11590Srgrimes/* 228068Scharnier * Copyright (c) 1989, 1993, 1995 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * 51590Srgrimes * This code is derived from software contributed to Berkeley by 61590Srgrimes * Rick Macklem at The University of Guelph. 71590Srgrimes * 81590Srgrimes * Redistribution and use in source and binary forms, with or without 91590Srgrimes * modification, are permitted provided that the following conditions 101590Srgrimes * are met: 111590Srgrimes * 1. Redistributions of source code must retain the above copyright 121590Srgrimes * notice, this list of conditions and the following disclaimer. 131590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141590Srgrimes * notice, this list of conditions and the following disclaimer in the 151590Srgrimes * documentation and/or other materials provided with the distribution. 161590Srgrimes * 4. Neither the name of the University nor the names of its contributors 171590Srgrimes * may be used to endorse or promote products derived from this software 181590Srgrimes * without specific prior written permission. 191590Srgrimes * 201590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 211590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 221590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 231590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 241590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 251590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 261590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 271590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 281590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 291590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 301590Srgrimes * SUCH DAMAGE. 311590Srgrimes */ 321590Srgrimes 331590Srgrimes#ifndef lint 3428068Scharnierstatic const char copyright[] = 3528068Scharnier"@(#) Copyright (c) 1989, 1993, 1995\n\ 361590Srgrimes The Regents of the University of California. All rights reserved.\n"; 3778130Sdd#endif /* not lint */ 381590Srgrimes 391590Srgrimes#ifndef lint 4028068Scharnier#if 0 4128068Scharnierstatic char sccsid[] = "@(#)showmount.c 8.3 (Berkeley) 3/29/95"; 4228068Scharnier#endif 4328068Scharnierstatic const char rcsid[] = 4450477Speter "$FreeBSD$"; 4578130Sdd#endif /* not lint */ 461590Srgrimes 471590Srgrimes#include <sys/types.h> 4814542Sdg#include <sys/queue.h> 491590Srgrimes#include <sys/file.h> 501590Srgrimes#include <sys/socket.h> 511590Srgrimes#include <sys/socketvar.h> 5228068Scharnier 5328068Scharnier#include <err.h> 54200462Sdelphij#include <netdb.h> 551590Srgrimes#include <rpc/rpc.h> 561590Srgrimes#include <rpc/pmap_clnt.h> 571590Srgrimes#include <rpc/pmap_prot.h> 58194880Sdfr#include <rpcsvc/mount.h> 5928068Scharnier 601590Srgrimes#include <stdio.h> 6128068Scharnier#include <stdlib.h> 621590Srgrimes#include <string.h> 6328068Scharnier#include <unistd.h> 641590Srgrimes 651590Srgrimes/* Constant defs */ 661590Srgrimes#define ALL 1 671590Srgrimes#define DIRS 2 681590Srgrimes 691590Srgrimes#define DODUMP 0x1 701590Srgrimes#define DOEXPORTS 0x2 711590Srgrimes 721590Srgrimesstruct mountlist { 731590Srgrimes struct mountlist *ml_left; 741590Srgrimes struct mountlist *ml_right; 75194880Sdfr char ml_host[MNTNAMLEN+1]; 76194880Sdfr char ml_dirp[MNTPATHLEN+1]; 771590Srgrimes}; 781590Srgrimes 791590Srgrimesstruct grouplist { 801590Srgrimes struct grouplist *gr_next; 81194880Sdfr char gr_name[MNTNAMLEN+1]; 821590Srgrimes}; 831590Srgrimes 841590Srgrimesstruct exportslist { 851590Srgrimes struct exportslist *ex_next; 861590Srgrimes struct grouplist *ex_groups; 87194880Sdfr char ex_dirp[MNTPATHLEN+1]; 881590Srgrimes}; 891590Srgrimes 901590Srgrimesstatic struct mountlist *mntdump; 91194880Sdfrstatic struct exportslist *exportslist; 921590Srgrimesstatic int type = 0; 931590Srgrimes 9492922Simpvoid print_dump(struct mountlist *); 9592922Simpstatic void usage(void); 9692922Simpint xdr_mntdump(XDR *, struct mountlist **); 97194880Sdfrint xdr_exportslist(XDR *, struct exportslist **); 9892922Simpint tcp_callrpc(const char *host, int prognum, int versnum, int procnum, 9992922Simp xdrproc_t inproc, char *in, xdrproc_t outproc, char *out); 10028068Scharnier 1011590Srgrimes/* 1021590Srgrimes * This command queries the NFS mount daemon for it's mount list and/or 1031590Srgrimes * it's exports list and prints them out. 1041590Srgrimes * See "NFS: Network File System Protocol Specification, RFC1094, Appendix A" 1059336Sdfr * and the "Network File System Protocol XXX.." 1061590Srgrimes * for detailed information on the protocol. 1071590Srgrimes */ 10828068Scharnierint 109201382Sedmain(int argc, char **argv) 1101590Srgrimes{ 1111590Srgrimes register struct exportslist *exp; 1121590Srgrimes register struct grouplist *grp; 1139336Sdfr register int rpcs = 0, mntvers = 1; 11487297Sdwmalone const char *host; 115132660Sstefanf int ch, estat; 1161590Srgrimes 11724360Simp while ((ch = getopt(argc, argv, "ade3")) != -1) 118132660Sstefanf switch (ch) { 1191590Srgrimes case 'a': 1201590Srgrimes if (type == 0) { 1211590Srgrimes type = ALL; 1221590Srgrimes rpcs |= DODUMP; 1231590Srgrimes } else 1241590Srgrimes usage(); 1251590Srgrimes break; 1261590Srgrimes case 'd': 1271590Srgrimes if (type == 0) { 1281590Srgrimes type = DIRS; 1291590Srgrimes rpcs |= DODUMP; 1301590Srgrimes } else 1311590Srgrimes usage(); 1321590Srgrimes break; 1331590Srgrimes case 'e': 1341590Srgrimes rpcs |= DOEXPORTS; 1351590Srgrimes break; 1369336Sdfr case '3': 1379336Sdfr mntvers = 3; 1389336Sdfr break; 1391590Srgrimes case '?': 1401590Srgrimes default: 1411590Srgrimes usage(); 1421590Srgrimes } 1431590Srgrimes argc -= optind; 1441590Srgrimes argv += optind; 1451590Srgrimes 1461590Srgrimes if (argc > 0) 1471590Srgrimes host = *argv; 1481590Srgrimes else 1491590Srgrimes host = "localhost"; 1501590Srgrimes 1511590Srgrimes if (rpcs == 0) 1521590Srgrimes rpcs = DODUMP; 1531590Srgrimes 1541590Srgrimes if (rpcs & DODUMP) 155194880Sdfr if ((estat = tcp_callrpc(host, MOUNTPROG, mntvers, 156194880Sdfr MOUNTPROC_DUMP, (xdrproc_t)xdr_void, (char *)0, 157121546Speter (xdrproc_t)xdr_mntdump, (char *)&mntdump)) != 0) { 1581590Srgrimes clnt_perrno(estat); 15928068Scharnier errx(1, "can't do mountdump rpc"); 1601590Srgrimes } 1611590Srgrimes if (rpcs & DOEXPORTS) 162194880Sdfr if ((estat = tcp_callrpc(host, MOUNTPROG, mntvers, 163194880Sdfr MOUNTPROC_EXPORT, (xdrproc_t)xdr_void, (char *)0, 164194880Sdfr (xdrproc_t)xdr_exportslist, (char *)&exportslist)) != 0) { 1651590Srgrimes clnt_perrno(estat); 16628068Scharnier errx(1, "can't do exports rpc"); 1671590Srgrimes } 1681590Srgrimes 1691590Srgrimes /* Now just print out the results */ 1701590Srgrimes if (rpcs & DODUMP) { 1711590Srgrimes switch (type) { 1721590Srgrimes case ALL: 1731590Srgrimes printf("All mount points on %s:\n", host); 1741590Srgrimes break; 1751590Srgrimes case DIRS: 1761590Srgrimes printf("Directories on %s:\n", host); 1771590Srgrimes break; 1781590Srgrimes default: 1791590Srgrimes printf("Hosts on %s:\n", host); 1801590Srgrimes break; 1811590Srgrimes }; 1821590Srgrimes print_dump(mntdump); 1831590Srgrimes } 1841590Srgrimes if (rpcs & DOEXPORTS) { 1851590Srgrimes printf("Exports list on %s:\n", host); 186194880Sdfr exp = exportslist; 1871590Srgrimes while (exp) { 188222245Sru printf("%-34s ", exp->ex_dirp); 1891590Srgrimes grp = exp->ex_groups; 1901590Srgrimes if (grp == NULL) { 1911590Srgrimes printf("Everyone\n"); 1921590Srgrimes } else { 1931590Srgrimes while (grp) { 1941590Srgrimes printf("%s ", grp->gr_name); 1951590Srgrimes grp = grp->gr_next; 1961590Srgrimes } 1971590Srgrimes printf("\n"); 1981590Srgrimes } 1991590Srgrimes exp = exp->ex_next; 2001590Srgrimes } 2011590Srgrimes } 20228068Scharnier exit(0); 2031590Srgrimes} 2041590Srgrimes 2051590Srgrimes/* 20629117Stegge * tcp_callrpc has the same interface as callrpc, but tries to 20729117Stegge * use tcp as transport method in order to handle large replies. 20829117Stegge */ 20929117Steggeint 210201382Sedtcp_callrpc(const char *host, int prognum, int versnum, int procnum, 211201382Sed xdrproc_t inproc, char *in, xdrproc_t outproc, char *out) 21229117Stegge{ 21329117Stegge CLIENT *client; 21429117Stegge struct timeval timeout; 21529117Stegge int rval; 21629117Stegge 21775239Siedowse if ((client = clnt_create(host, prognum, versnum, "tcp")) == NULL && 21875239Siedowse (client = clnt_create(host, prognum, versnum, "udp")) == NULL) 21929117Stegge return ((int) rpc_createerr.cf_stat); 22029117Stegge 22129117Stegge timeout.tv_sec = 25; 22229117Stegge timeout.tv_usec = 0; 22329117Stegge rval = (int) clnt_call(client, procnum, 22429117Stegge inproc, in, 22529117Stegge outproc, out, 22629117Stegge timeout); 22729117Stegge clnt_destroy(client); 22829117Stegge return rval; 22929117Stegge} 23029117Stegge 23129117Stegge/* 2321590Srgrimes * Xdr routine for retrieving the mount dump list 2331590Srgrimes */ 23428068Scharnierint 235201382Sedxdr_mntdump(XDR *xdrsp, struct mountlist **mlp) 2361590Srgrimes{ 2371590Srgrimes register struct mountlist *mp; 2381590Srgrimes register struct mountlist *tp; 2391590Srgrimes register struct mountlist **otp; 2401590Srgrimes int val, val2; 2411590Srgrimes int bool; 2421590Srgrimes char *strp; 2431590Srgrimes 2441590Srgrimes *mlp = (struct mountlist *)0; 2451590Srgrimes if (!xdr_bool(xdrsp, &bool)) 2461590Srgrimes return (0); 2471590Srgrimes while (bool) { 2481590Srgrimes mp = (struct mountlist *)malloc(sizeof(struct mountlist)); 2491590Srgrimes if (mp == NULL) 2501590Srgrimes return (0); 2511590Srgrimes mp->ml_left = mp->ml_right = (struct mountlist *)0; 2521590Srgrimes strp = mp->ml_host; 253194880Sdfr if (!xdr_string(xdrsp, &strp, MNTNAMLEN)) 2541590Srgrimes return (0); 2551590Srgrimes strp = mp->ml_dirp; 256194880Sdfr if (!xdr_string(xdrsp, &strp, MNTPATHLEN)) 2571590Srgrimes return (0); 2581590Srgrimes 2591590Srgrimes /* 2601590Srgrimes * Build a binary tree on sorted order of either host or dirp. 2611590Srgrimes * Drop any duplications. 2621590Srgrimes */ 2631590Srgrimes if (*mlp == NULL) { 2641590Srgrimes *mlp = mp; 2651590Srgrimes } else { 2661590Srgrimes tp = *mlp; 2671590Srgrimes while (tp) { 2681590Srgrimes val = strcmp(mp->ml_host, tp->ml_host); 2691590Srgrimes val2 = strcmp(mp->ml_dirp, tp->ml_dirp); 2701590Srgrimes switch (type) { 2711590Srgrimes case ALL: 2721590Srgrimes if (val == 0) { 2731590Srgrimes if (val2 == 0) { 2741590Srgrimes free((caddr_t)mp); 2751590Srgrimes goto next; 2761590Srgrimes } 2771590Srgrimes val = val2; 2781590Srgrimes } 2791590Srgrimes break; 2801590Srgrimes case DIRS: 2811590Srgrimes if (val2 == 0) { 2821590Srgrimes free((caddr_t)mp); 2831590Srgrimes goto next; 2841590Srgrimes } 2851590Srgrimes val = val2; 2861590Srgrimes break; 2871590Srgrimes default: 2881590Srgrimes if (val == 0) { 2891590Srgrimes free((caddr_t)mp); 2901590Srgrimes goto next; 2911590Srgrimes } 2921590Srgrimes break; 2931590Srgrimes }; 2941590Srgrimes if (val < 0) { 2951590Srgrimes otp = &tp->ml_left; 2961590Srgrimes tp = tp->ml_left; 2971590Srgrimes } else { 2981590Srgrimes otp = &tp->ml_right; 2991590Srgrimes tp = tp->ml_right; 3001590Srgrimes } 3011590Srgrimes } 3021590Srgrimes *otp = mp; 3031590Srgrimes } 3041590Srgrimesnext: 3051590Srgrimes if (!xdr_bool(xdrsp, &bool)) 3061590Srgrimes return (0); 3071590Srgrimes } 3081590Srgrimes return (1); 3091590Srgrimes} 3101590Srgrimes 3111590Srgrimes/* 3121590Srgrimes * Xdr routine to retrieve exports list 3131590Srgrimes */ 31428068Scharnierint 315201382Sedxdr_exportslist(XDR *xdrsp, struct exportslist **exp) 3161590Srgrimes{ 3171590Srgrimes register struct exportslist *ep; 3181590Srgrimes register struct grouplist *gp; 3191590Srgrimes int bool, grpbool; 3201590Srgrimes char *strp; 3211590Srgrimes 3221590Srgrimes *exp = (struct exportslist *)0; 3231590Srgrimes if (!xdr_bool(xdrsp, &bool)) 3241590Srgrimes return (0); 3251590Srgrimes while (bool) { 3261590Srgrimes ep = (struct exportslist *)malloc(sizeof(struct exportslist)); 3271590Srgrimes if (ep == NULL) 3281590Srgrimes return (0); 3291590Srgrimes ep->ex_groups = (struct grouplist *)0; 3301590Srgrimes strp = ep->ex_dirp; 331194880Sdfr if (!xdr_string(xdrsp, &strp, MNTPATHLEN)) 3321590Srgrimes return (0); 3331590Srgrimes if (!xdr_bool(xdrsp, &grpbool)) 3341590Srgrimes return (0); 3351590Srgrimes while (grpbool) { 3361590Srgrimes gp = (struct grouplist *)malloc(sizeof(struct grouplist)); 3371590Srgrimes if (gp == NULL) 3381590Srgrimes return (0); 3391590Srgrimes strp = gp->gr_name; 340194880Sdfr if (!xdr_string(xdrsp, &strp, MNTNAMLEN)) 3411590Srgrimes return (0); 3421590Srgrimes gp->gr_next = ep->ex_groups; 3431590Srgrimes ep->ex_groups = gp; 3441590Srgrimes if (!xdr_bool(xdrsp, &grpbool)) 3451590Srgrimes return (0); 3461590Srgrimes } 3471590Srgrimes ep->ex_next = *exp; 3481590Srgrimes *exp = ep; 3491590Srgrimes if (!xdr_bool(xdrsp, &bool)) 3501590Srgrimes return (0); 3511590Srgrimes } 3521590Srgrimes return (1); 3531590Srgrimes} 3541590Srgrimes 35528068Scharnierstatic void 356201382Sedusage(void) 3571590Srgrimes{ 358146466Sru fprintf(stderr, "usage: showmount [-a | -d] [-e3] [host]\n"); 3591590Srgrimes exit(1); 3601590Srgrimes} 3611590Srgrimes 3621590Srgrimes/* 3631590Srgrimes * Print the binary tree in inorder so that output is sorted. 3641590Srgrimes */ 36528068Scharniervoid 366201382Sedprint_dump(struct mountlist *mp) 3671590Srgrimes{ 3681590Srgrimes 3691590Srgrimes if (mp == NULL) 3701590Srgrimes return; 3711590Srgrimes if (mp->ml_left) 3721590Srgrimes print_dump(mp->ml_left); 3731590Srgrimes switch (type) { 3741590Srgrimes case ALL: 3751590Srgrimes printf("%s:%s\n", mp->ml_host, mp->ml_dirp); 3761590Srgrimes break; 3771590Srgrimes case DIRS: 3781590Srgrimes printf("%s\n", mp->ml_dirp); 3791590Srgrimes break; 3801590Srgrimes default: 3811590Srgrimes printf("%s\n", mp->ml_host); 3821590Srgrimes break; 3831590Srgrimes }; 3841590Srgrimes if (mp->ml_right) 3851590Srgrimes print_dump(mp->ml_right); 3861590Srgrimes} 387