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: stable/10/usr.bin/showmount/showmount.c 308292 2016-11-04 14:06:21Z trasz $"; 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> 64308292Strasz#include <vis.h> 651590Srgrimes 661590Srgrimes/* Constant defs */ 671590Srgrimes#define ALL 1 681590Srgrimes#define DIRS 2 691590Srgrimes 70308292Strasz#define DODUMP 0x1 71308292Strasz#define DOEXPORTS 0x2 72308292Strasz#define DOPARSABLEEXPORTS 0x4 731590Srgrimes 741590Srgrimesstruct mountlist { 751590Srgrimes struct mountlist *ml_left; 761590Srgrimes struct mountlist *ml_right; 77194880Sdfr char ml_host[MNTNAMLEN+1]; 78194880Sdfr char ml_dirp[MNTPATHLEN+1]; 791590Srgrimes}; 801590Srgrimes 811590Srgrimesstruct grouplist { 821590Srgrimes struct grouplist *gr_next; 83194880Sdfr char gr_name[MNTNAMLEN+1]; 841590Srgrimes}; 851590Srgrimes 861590Srgrimesstruct exportslist { 871590Srgrimes struct exportslist *ex_next; 881590Srgrimes struct grouplist *ex_groups; 89194880Sdfr char ex_dirp[MNTPATHLEN+1]; 901590Srgrimes}; 911590Srgrimes 921590Srgrimesstatic struct mountlist *mntdump; 93194880Sdfrstatic struct exportslist *exportslist; 941590Srgrimesstatic int type = 0; 951590Srgrimes 9692922Simpvoid print_dump(struct mountlist *); 9792922Simpstatic void usage(void); 9892922Simpint xdr_mntdump(XDR *, struct mountlist **); 99194880Sdfrint xdr_exportslist(XDR *, struct exportslist **); 10092922Simpint tcp_callrpc(const char *host, int prognum, int versnum, int procnum, 10192922Simp xdrproc_t inproc, char *in, xdrproc_t outproc, char *out); 10228068Scharnier 1031590Srgrimes/* 1041590Srgrimes * This command queries the NFS mount daemon for it's mount list and/or 1051590Srgrimes * it's exports list and prints them out. 1061590Srgrimes * See "NFS: Network File System Protocol Specification, RFC1094, Appendix A" 1079336Sdfr * and the "Network File System Protocol XXX.." 1081590Srgrimes * for detailed information on the protocol. 1091590Srgrimes */ 11028068Scharnierint 111201382Sedmain(int argc, char **argv) 1121590Srgrimes{ 113308292Strasz char strvised[MNTPATHLEN * 4 + 1]; 1141590Srgrimes register struct exportslist *exp; 1151590Srgrimes register struct grouplist *grp; 116270258Speter register int rpcs = 0, mntvers = 3; 11787297Sdwmalone const char *host; 118308292Strasz int ch, estat, nbytes; 1191590Srgrimes 120308292Strasz while ((ch = getopt(argc, argv, "adEe13")) != -1) 121132660Sstefanf switch (ch) { 1221590Srgrimes case 'a': 1231590Srgrimes if (type == 0) { 1241590Srgrimes type = ALL; 1251590Srgrimes rpcs |= DODUMP; 1261590Srgrimes } else 1271590Srgrimes usage(); 1281590Srgrimes break; 1291590Srgrimes case 'd': 1301590Srgrimes if (type == 0) { 1311590Srgrimes type = DIRS; 1321590Srgrimes rpcs |= DODUMP; 1331590Srgrimes } else 1341590Srgrimes usage(); 1351590Srgrimes break; 136308292Strasz case 'E': 137308292Strasz rpcs |= DOPARSABLEEXPORTS; 138308292Strasz break; 1391590Srgrimes case 'e': 1401590Srgrimes rpcs |= DOEXPORTS; 1411590Srgrimes break; 142270258Speter case '1': 143270258Speter mntvers = 1; 144270258Speter break; 1459336Sdfr case '3': 1469336Sdfr mntvers = 3; 1479336Sdfr break; 1481590Srgrimes case '?': 1491590Srgrimes default: 1501590Srgrimes usage(); 1511590Srgrimes } 1521590Srgrimes argc -= optind; 1531590Srgrimes argv += optind; 1541590Srgrimes 155308292Strasz if ((rpcs & DOPARSABLEEXPORTS) != 0) { 156308292Strasz if ((rpcs & DOEXPORTS) != 0) 157308292Strasz errx(1, "-E cannot be used with -e"); 158308292Strasz if ((rpcs & DODUMP) != 0) 159308292Strasz errx(1, "-E cannot be used with -a or -d"); 160308292Strasz } 161308292Strasz 1621590Srgrimes if (argc > 0) 1631590Srgrimes host = *argv; 1641590Srgrimes else 1651590Srgrimes host = "localhost"; 1661590Srgrimes 1671590Srgrimes if (rpcs == 0) 1681590Srgrimes rpcs = DODUMP; 1691590Srgrimes 1701590Srgrimes if (rpcs & DODUMP) 171194880Sdfr if ((estat = tcp_callrpc(host, MOUNTPROG, mntvers, 172194880Sdfr MOUNTPROC_DUMP, (xdrproc_t)xdr_void, (char *)0, 173121546Speter (xdrproc_t)xdr_mntdump, (char *)&mntdump)) != 0) { 1741590Srgrimes clnt_perrno(estat); 17528068Scharnier errx(1, "can't do mountdump rpc"); 1761590Srgrimes } 177308292Strasz if (rpcs & (DOEXPORTS | DOPARSABLEEXPORTS)) 178194880Sdfr if ((estat = tcp_callrpc(host, MOUNTPROG, mntvers, 179194880Sdfr MOUNTPROC_EXPORT, (xdrproc_t)xdr_void, (char *)0, 180194880Sdfr (xdrproc_t)xdr_exportslist, (char *)&exportslist)) != 0) { 1811590Srgrimes clnt_perrno(estat); 18228068Scharnier errx(1, "can't do exports rpc"); 1831590Srgrimes } 1841590Srgrimes 1851590Srgrimes /* Now just print out the results */ 1861590Srgrimes if (rpcs & DODUMP) { 1871590Srgrimes switch (type) { 1881590Srgrimes case ALL: 1891590Srgrimes printf("All mount points on %s:\n", host); 1901590Srgrimes break; 1911590Srgrimes case DIRS: 1921590Srgrimes printf("Directories on %s:\n", host); 1931590Srgrimes break; 1941590Srgrimes default: 1951590Srgrimes printf("Hosts on %s:\n", host); 1961590Srgrimes break; 1971590Srgrimes }; 1981590Srgrimes print_dump(mntdump); 1991590Srgrimes } 2001590Srgrimes if (rpcs & DOEXPORTS) { 2011590Srgrimes printf("Exports list on %s:\n", host); 202194880Sdfr exp = exportslist; 2031590Srgrimes while (exp) { 204222245Sru printf("%-34s ", exp->ex_dirp); 2051590Srgrimes grp = exp->ex_groups; 2061590Srgrimes if (grp == NULL) { 2071590Srgrimes printf("Everyone\n"); 2081590Srgrimes } else { 2091590Srgrimes while (grp) { 2101590Srgrimes printf("%s ", grp->gr_name); 2111590Srgrimes grp = grp->gr_next; 2121590Srgrimes } 2131590Srgrimes printf("\n"); 2141590Srgrimes } 2151590Srgrimes exp = exp->ex_next; 2161590Srgrimes } 2171590Srgrimes } 218308292Strasz if (rpcs & DOPARSABLEEXPORTS) { 219308292Strasz exp = exportslist; 220308292Strasz while (exp) { 221308292Strasz nbytes = strsnvis(strvised, sizeof(strvised), 222308292Strasz exp->ex_dirp, VIS_GLOB | VIS_NL, "\"'$"); 223308292Strasz if (nbytes == -1) 224308292Strasz err(1, "strsnvis"); 225308292Strasz printf("%s\n", strvised); 226308292Strasz exp = exp->ex_next; 227308292Strasz } 228308292Strasz } 22928068Scharnier exit(0); 2301590Srgrimes} 2311590Srgrimes 2321590Srgrimes/* 23329117Stegge * tcp_callrpc has the same interface as callrpc, but tries to 23429117Stegge * use tcp as transport method in order to handle large replies. 23529117Stegge */ 23629117Steggeint 237201382Sedtcp_callrpc(const char *host, int prognum, int versnum, int procnum, 238201382Sed xdrproc_t inproc, char *in, xdrproc_t outproc, char *out) 23929117Stegge{ 24029117Stegge CLIENT *client; 24129117Stegge struct timeval timeout; 24229117Stegge int rval; 24329117Stegge 24475239Siedowse if ((client = clnt_create(host, prognum, versnum, "tcp")) == NULL && 24575239Siedowse (client = clnt_create(host, prognum, versnum, "udp")) == NULL) 24629117Stegge return ((int) rpc_createerr.cf_stat); 24729117Stegge 24829117Stegge timeout.tv_sec = 25; 24929117Stegge timeout.tv_usec = 0; 25029117Stegge rval = (int) clnt_call(client, procnum, 25129117Stegge inproc, in, 25229117Stegge outproc, out, 25329117Stegge timeout); 25429117Stegge clnt_destroy(client); 25529117Stegge return rval; 25629117Stegge} 25729117Stegge 25829117Stegge/* 2591590Srgrimes * Xdr routine for retrieving the mount dump list 2601590Srgrimes */ 26128068Scharnierint 262201382Sedxdr_mntdump(XDR *xdrsp, struct mountlist **mlp) 2631590Srgrimes{ 2641590Srgrimes register struct mountlist *mp; 2651590Srgrimes register struct mountlist *tp; 2661590Srgrimes register struct mountlist **otp; 2671590Srgrimes int val, val2; 2681590Srgrimes int bool; 2691590Srgrimes char *strp; 2701590Srgrimes 2711590Srgrimes *mlp = (struct mountlist *)0; 2721590Srgrimes if (!xdr_bool(xdrsp, &bool)) 2731590Srgrimes return (0); 2741590Srgrimes while (bool) { 2751590Srgrimes mp = (struct mountlist *)malloc(sizeof(struct mountlist)); 2761590Srgrimes if (mp == NULL) 2771590Srgrimes return (0); 2781590Srgrimes mp->ml_left = mp->ml_right = (struct mountlist *)0; 2791590Srgrimes strp = mp->ml_host; 280194880Sdfr if (!xdr_string(xdrsp, &strp, MNTNAMLEN)) 2811590Srgrimes return (0); 2821590Srgrimes strp = mp->ml_dirp; 283194880Sdfr if (!xdr_string(xdrsp, &strp, MNTPATHLEN)) 2841590Srgrimes return (0); 2851590Srgrimes 2861590Srgrimes /* 2871590Srgrimes * Build a binary tree on sorted order of either host or dirp. 2881590Srgrimes * Drop any duplications. 2891590Srgrimes */ 2901590Srgrimes if (*mlp == NULL) { 2911590Srgrimes *mlp = mp; 2921590Srgrimes } else { 2931590Srgrimes tp = *mlp; 2941590Srgrimes while (tp) { 2951590Srgrimes val = strcmp(mp->ml_host, tp->ml_host); 2961590Srgrimes val2 = strcmp(mp->ml_dirp, tp->ml_dirp); 2971590Srgrimes switch (type) { 2981590Srgrimes case ALL: 2991590Srgrimes if (val == 0) { 3001590Srgrimes if (val2 == 0) { 3011590Srgrimes free((caddr_t)mp); 3021590Srgrimes goto next; 3031590Srgrimes } 3041590Srgrimes val = val2; 3051590Srgrimes } 3061590Srgrimes break; 3071590Srgrimes case DIRS: 3081590Srgrimes if (val2 == 0) { 3091590Srgrimes free((caddr_t)mp); 3101590Srgrimes goto next; 3111590Srgrimes } 3121590Srgrimes val = val2; 3131590Srgrimes break; 3141590Srgrimes default: 3151590Srgrimes if (val == 0) { 3161590Srgrimes free((caddr_t)mp); 3171590Srgrimes goto next; 3181590Srgrimes } 3191590Srgrimes break; 3201590Srgrimes }; 3211590Srgrimes if (val < 0) { 3221590Srgrimes otp = &tp->ml_left; 3231590Srgrimes tp = tp->ml_left; 3241590Srgrimes } else { 3251590Srgrimes otp = &tp->ml_right; 3261590Srgrimes tp = tp->ml_right; 3271590Srgrimes } 3281590Srgrimes } 3291590Srgrimes *otp = mp; 3301590Srgrimes } 3311590Srgrimesnext: 3321590Srgrimes if (!xdr_bool(xdrsp, &bool)) 3331590Srgrimes return (0); 3341590Srgrimes } 3351590Srgrimes return (1); 3361590Srgrimes} 3371590Srgrimes 3381590Srgrimes/* 3391590Srgrimes * Xdr routine to retrieve exports list 3401590Srgrimes */ 34128068Scharnierint 342201382Sedxdr_exportslist(XDR *xdrsp, struct exportslist **exp) 3431590Srgrimes{ 3441590Srgrimes register struct exportslist *ep; 3451590Srgrimes register struct grouplist *gp; 3461590Srgrimes int bool, grpbool; 3471590Srgrimes char *strp; 3481590Srgrimes 3491590Srgrimes *exp = (struct exportslist *)0; 3501590Srgrimes if (!xdr_bool(xdrsp, &bool)) 3511590Srgrimes return (0); 3521590Srgrimes while (bool) { 3531590Srgrimes ep = (struct exportslist *)malloc(sizeof(struct exportslist)); 3541590Srgrimes if (ep == NULL) 3551590Srgrimes return (0); 3561590Srgrimes ep->ex_groups = (struct grouplist *)0; 3571590Srgrimes strp = ep->ex_dirp; 358194880Sdfr if (!xdr_string(xdrsp, &strp, MNTPATHLEN)) 3591590Srgrimes return (0); 3601590Srgrimes if (!xdr_bool(xdrsp, &grpbool)) 3611590Srgrimes return (0); 3621590Srgrimes while (grpbool) { 3631590Srgrimes gp = (struct grouplist *)malloc(sizeof(struct grouplist)); 3641590Srgrimes if (gp == NULL) 3651590Srgrimes return (0); 3661590Srgrimes strp = gp->gr_name; 367194880Sdfr if (!xdr_string(xdrsp, &strp, MNTNAMLEN)) 3681590Srgrimes return (0); 3691590Srgrimes gp->gr_next = ep->ex_groups; 3701590Srgrimes ep->ex_groups = gp; 3711590Srgrimes if (!xdr_bool(xdrsp, &grpbool)) 3721590Srgrimes return (0); 3731590Srgrimes } 3741590Srgrimes ep->ex_next = *exp; 3751590Srgrimes *exp = ep; 3761590Srgrimes if (!xdr_bool(xdrsp, &bool)) 3771590Srgrimes return (0); 3781590Srgrimes } 3791590Srgrimes return (1); 3801590Srgrimes} 3811590Srgrimes 38228068Scharnierstatic void 383201382Sedusage(void) 3841590Srgrimes{ 385146466Sru fprintf(stderr, "usage: showmount [-a | -d] [-e3] [host]\n"); 3861590Srgrimes exit(1); 3871590Srgrimes} 3881590Srgrimes 3891590Srgrimes/* 3901590Srgrimes * Print the binary tree in inorder so that output is sorted. 3911590Srgrimes */ 39228068Scharniervoid 393201382Sedprint_dump(struct mountlist *mp) 3941590Srgrimes{ 3951590Srgrimes 3961590Srgrimes if (mp == NULL) 3971590Srgrimes return; 3981590Srgrimes if (mp->ml_left) 3991590Srgrimes print_dump(mp->ml_left); 4001590Srgrimes switch (type) { 4011590Srgrimes case ALL: 4021590Srgrimes printf("%s:%s\n", mp->ml_host, mp->ml_dirp); 4031590Srgrimes break; 4041590Srgrimes case DIRS: 4051590Srgrimes printf("%s\n", mp->ml_dirp); 4061590Srgrimes break; 4071590Srgrimes default: 4081590Srgrimes printf("%s\n", mp->ml_host); 4091590Srgrimes break; 4101590Srgrimes }; 4111590Srgrimes if (mp->ml_right) 4121590Srgrimes print_dump(mp->ml_right); 4131590Srgrimes} 414