showmount.c revision 121546
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 * 3. All advertising materials mentioning features or use of this software 171590Srgrimes * must display the following acknowledgement: 181590Srgrimes * This product includes software developed by the University of 191590Srgrimes * California, Berkeley and its contributors. 201590Srgrimes * 4. Neither the name of the University nor the names of its contributors 211590Srgrimes * may be used to endorse or promote products derived from this software 221590Srgrimes * without specific prior written permission. 231590Srgrimes * 241590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 251590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 261590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 271590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 281590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 291590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 301590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 311590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 321590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 331590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 341590Srgrimes * SUCH DAMAGE. 351590Srgrimes */ 361590Srgrimes 371590Srgrimes#ifndef lint 3828068Scharnierstatic const char copyright[] = 3928068Scharnier"@(#) Copyright (c) 1989, 1993, 1995\n\ 401590Srgrimes The Regents of the University of California. All rights reserved.\n"; 4178130Sdd#endif /* not lint */ 421590Srgrimes 431590Srgrimes#ifndef lint 4428068Scharnier#if 0 4528068Scharnierstatic char sccsid[] = "@(#)showmount.c 8.3 (Berkeley) 3/29/95"; 4628068Scharnier#endif 4728068Scharnierstatic const char rcsid[] = 4850477Speter "$FreeBSD: head/usr.bin/showmount/showmount.c 121546 2003-10-26 04:58:44Z peter $"; 4978130Sdd#endif /* not lint */ 501590Srgrimes 511590Srgrimes#include <sys/types.h> 5214542Sdg#include <sys/queue.h> 531590Srgrimes#include <sys/file.h> 541590Srgrimes#include <sys/socket.h> 551590Srgrimes#include <sys/socketvar.h> 5628068Scharnier 5728068Scharnier#include <err.h> 581590Srgrimes#include <netdb.h> 591590Srgrimes#include <rpc/rpc.h> 601590Srgrimes#include <rpc/pmap_clnt.h> 611590Srgrimes#include <rpc/pmap_prot.h> 621590Srgrimes#include <nfs/rpcv2.h> 6328068Scharnier 641590Srgrimes#include <stdio.h> 6528068Scharnier#include <stdlib.h> 661590Srgrimes#include <string.h> 6728068Scharnier#include <unistd.h> 681590Srgrimes 691590Srgrimes/* Constant defs */ 701590Srgrimes#define ALL 1 711590Srgrimes#define DIRS 2 721590Srgrimes 731590Srgrimes#define DODUMP 0x1 741590Srgrimes#define DOEXPORTS 0x2 751590Srgrimes 761590Srgrimesstruct mountlist { 771590Srgrimes struct mountlist *ml_left; 781590Srgrimes struct mountlist *ml_right; 791590Srgrimes char ml_host[RPCMNT_NAMELEN+1]; 801590Srgrimes char ml_dirp[RPCMNT_PATHLEN+1]; 811590Srgrimes}; 821590Srgrimes 831590Srgrimesstruct grouplist { 841590Srgrimes struct grouplist *gr_next; 851590Srgrimes char gr_name[RPCMNT_NAMELEN+1]; 861590Srgrimes}; 871590Srgrimes 881590Srgrimesstruct exportslist { 891590Srgrimes struct exportslist *ex_next; 901590Srgrimes struct grouplist *ex_groups; 911590Srgrimes char ex_dirp[RPCMNT_PATHLEN+1]; 921590Srgrimes}; 931590Srgrimes 941590Srgrimesstatic struct mountlist *mntdump; 951590Srgrimesstatic struct exportslist *exports; 961590Srgrimesstatic int type = 0; 971590Srgrimes 9892922Simpvoid print_dump(struct mountlist *); 9992922Simpstatic void usage(void); 10092922Simpint xdr_mntdump(XDR *, struct mountlist **); 10192922Simpint xdr_exports(XDR *, struct exportslist **); 10292922Simpint tcp_callrpc(const char *host, int prognum, int versnum, int procnum, 10392922Simp xdrproc_t inproc, char *in, xdrproc_t outproc, char *out); 10428068Scharnier 1051590Srgrimes/* 1061590Srgrimes * This command queries the NFS mount daemon for it's mount list and/or 1071590Srgrimes * it's exports list and prints them out. 1081590Srgrimes * See "NFS: Network File System Protocol Specification, RFC1094, Appendix A" 1099336Sdfr * and the "Network File System Protocol XXX.." 1101590Srgrimes * for detailed information on the protocol. 1111590Srgrimes */ 11228068Scharnierint 1131590Srgrimesmain(argc, argv) 1141590Srgrimes int argc; 1151590Srgrimes char **argv; 1161590Srgrimes{ 1171590Srgrimes register struct exportslist *exp; 1181590Srgrimes register struct grouplist *grp; 1199336Sdfr register int rpcs = 0, mntvers = 1; 1201590Srgrimes char ch; 12187297Sdwmalone const char *host; 1221590Srgrimes int estat; 1231590Srgrimes 12424360Simp while ((ch = getopt(argc, argv, "ade3")) != -1) 1251590Srgrimes switch((char)ch) { 1261590Srgrimes case 'a': 1271590Srgrimes if (type == 0) { 1281590Srgrimes type = ALL; 1291590Srgrimes rpcs |= DODUMP; 1301590Srgrimes } else 1311590Srgrimes usage(); 1321590Srgrimes break; 1331590Srgrimes case 'd': 1341590Srgrimes if (type == 0) { 1351590Srgrimes type = DIRS; 1361590Srgrimes rpcs |= DODUMP; 1371590Srgrimes } else 1381590Srgrimes usage(); 1391590Srgrimes break; 1401590Srgrimes case 'e': 1411590Srgrimes rpcs |= DOEXPORTS; 1421590Srgrimes break; 1439336Sdfr case '3': 1449336Sdfr mntvers = 3; 1459336Sdfr break; 1461590Srgrimes case '?': 1471590Srgrimes default: 1481590Srgrimes usage(); 1491590Srgrimes } 1501590Srgrimes argc -= optind; 1511590Srgrimes argv += optind; 1521590Srgrimes 1531590Srgrimes if (argc > 0) 1541590Srgrimes host = *argv; 1551590Srgrimes else 1561590Srgrimes host = "localhost"; 1571590Srgrimes 1581590Srgrimes if (rpcs == 0) 1591590Srgrimes rpcs = DODUMP; 1601590Srgrimes 1611590Srgrimes if (rpcs & DODUMP) 16229117Stegge if ((estat = tcp_callrpc(host, RPCPROG_MNT, mntvers, 163121546Speter RPCMNT_DUMP, (xdrproc_t)xdr_void, (char *)0, 164121546Speter (xdrproc_t)xdr_mntdump, (char *)&mntdump)) != 0) { 1651590Srgrimes clnt_perrno(estat); 16628068Scharnier errx(1, "can't do mountdump rpc"); 1671590Srgrimes } 1681590Srgrimes if (rpcs & DOEXPORTS) 16929117Stegge if ((estat = tcp_callrpc(host, RPCPROG_MNT, mntvers, 170121546Speter RPCMNT_EXPORT, (xdrproc_t)xdr_void, (char *)0, 171121546Speter (xdrproc_t)xdr_exports, (char *)&exports)) != 0) { 1721590Srgrimes clnt_perrno(estat); 17328068Scharnier errx(1, "can't do exports rpc"); 1741590Srgrimes } 1751590Srgrimes 1761590Srgrimes /* Now just print out the results */ 1771590Srgrimes if (rpcs & DODUMP) { 1781590Srgrimes switch (type) { 1791590Srgrimes case ALL: 1801590Srgrimes printf("All mount points on %s:\n", host); 1811590Srgrimes break; 1821590Srgrimes case DIRS: 1831590Srgrimes printf("Directories on %s:\n", host); 1841590Srgrimes break; 1851590Srgrimes default: 1861590Srgrimes printf("Hosts on %s:\n", host); 1871590Srgrimes break; 1881590Srgrimes }; 1891590Srgrimes print_dump(mntdump); 1901590Srgrimes } 1911590Srgrimes if (rpcs & DOEXPORTS) { 1921590Srgrimes printf("Exports list on %s:\n", host); 1931590Srgrimes exp = exports; 1941590Srgrimes while (exp) { 1951590Srgrimes printf("%-35s", exp->ex_dirp); 1961590Srgrimes grp = exp->ex_groups; 1971590Srgrimes if (grp == NULL) { 1981590Srgrimes printf("Everyone\n"); 1991590Srgrimes } else { 2001590Srgrimes while (grp) { 2011590Srgrimes printf("%s ", grp->gr_name); 2021590Srgrimes grp = grp->gr_next; 2031590Srgrimes } 2041590Srgrimes printf("\n"); 2051590Srgrimes } 2061590Srgrimes exp = exp->ex_next; 2071590Srgrimes } 2081590Srgrimes } 20928068Scharnier exit(0); 2101590Srgrimes} 2111590Srgrimes 2121590Srgrimes/* 21329117Stegge * tcp_callrpc has the same interface as callrpc, but tries to 21429117Stegge * use tcp as transport method in order to handle large replies. 21529117Stegge */ 21629117Steggeint 21729117Steggetcp_callrpc(host, prognum, versnum, procnum, inproc, in, outproc, out) 21887297Sdwmalone const char *host; 21929117Stegge int prognum; 22029117Stegge int versnum; 22129117Stegge int procnum; 22229117Stegge xdrproc_t inproc; 22329117Stegge char *in; 22429117Stegge xdrproc_t outproc; 22529117Stegge char *out; 22629117Stegge{ 22729117Stegge CLIENT *client; 22829117Stegge struct timeval timeout; 22929117Stegge int rval; 23029117Stegge 23175239Siedowse if ((client = clnt_create(host, prognum, versnum, "tcp")) == NULL && 23275239Siedowse (client = clnt_create(host, prognum, versnum, "udp")) == NULL) 23329117Stegge return ((int) rpc_createerr.cf_stat); 23429117Stegge 23529117Stegge timeout.tv_sec = 25; 23629117Stegge timeout.tv_usec = 0; 23729117Stegge rval = (int) clnt_call(client, procnum, 23829117Stegge inproc, in, 23929117Stegge outproc, out, 24029117Stegge timeout); 24129117Stegge clnt_destroy(client); 24229117Stegge return rval; 24329117Stegge} 24429117Stegge 24529117Stegge/* 2461590Srgrimes * Xdr routine for retrieving the mount dump list 2471590Srgrimes */ 24828068Scharnierint 2491590Srgrimesxdr_mntdump(xdrsp, mlp) 2501590Srgrimes XDR *xdrsp; 2511590Srgrimes struct mountlist **mlp; 2521590Srgrimes{ 2531590Srgrimes register struct mountlist *mp; 2541590Srgrimes register struct mountlist *tp; 2551590Srgrimes register struct mountlist **otp; 2561590Srgrimes int val, val2; 2571590Srgrimes int bool; 2581590Srgrimes char *strp; 2591590Srgrimes 2601590Srgrimes *mlp = (struct mountlist *)0; 2611590Srgrimes if (!xdr_bool(xdrsp, &bool)) 2621590Srgrimes return (0); 2631590Srgrimes while (bool) { 2641590Srgrimes mp = (struct mountlist *)malloc(sizeof(struct mountlist)); 2651590Srgrimes if (mp == NULL) 2661590Srgrimes return (0); 2671590Srgrimes mp->ml_left = mp->ml_right = (struct mountlist *)0; 2681590Srgrimes strp = mp->ml_host; 2691590Srgrimes if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) 2701590Srgrimes return (0); 2711590Srgrimes strp = mp->ml_dirp; 2721590Srgrimes if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 2731590Srgrimes return (0); 2741590Srgrimes 2751590Srgrimes /* 2761590Srgrimes * Build a binary tree on sorted order of either host or dirp. 2771590Srgrimes * Drop any duplications. 2781590Srgrimes */ 2791590Srgrimes if (*mlp == NULL) { 2801590Srgrimes *mlp = mp; 2811590Srgrimes } else { 2821590Srgrimes tp = *mlp; 2831590Srgrimes while (tp) { 2841590Srgrimes val = strcmp(mp->ml_host, tp->ml_host); 2851590Srgrimes val2 = strcmp(mp->ml_dirp, tp->ml_dirp); 2861590Srgrimes switch (type) { 2871590Srgrimes case ALL: 2881590Srgrimes if (val == 0) { 2891590Srgrimes if (val2 == 0) { 2901590Srgrimes free((caddr_t)mp); 2911590Srgrimes goto next; 2921590Srgrimes } 2931590Srgrimes val = val2; 2941590Srgrimes } 2951590Srgrimes break; 2961590Srgrimes case DIRS: 2971590Srgrimes if (val2 == 0) { 2981590Srgrimes free((caddr_t)mp); 2991590Srgrimes goto next; 3001590Srgrimes } 3011590Srgrimes val = val2; 3021590Srgrimes break; 3031590Srgrimes default: 3041590Srgrimes if (val == 0) { 3051590Srgrimes free((caddr_t)mp); 3061590Srgrimes goto next; 3071590Srgrimes } 3081590Srgrimes break; 3091590Srgrimes }; 3101590Srgrimes if (val < 0) { 3111590Srgrimes otp = &tp->ml_left; 3121590Srgrimes tp = tp->ml_left; 3131590Srgrimes } else { 3141590Srgrimes otp = &tp->ml_right; 3151590Srgrimes tp = tp->ml_right; 3161590Srgrimes } 3171590Srgrimes } 3181590Srgrimes *otp = mp; 3191590Srgrimes } 3201590Srgrimesnext: 3211590Srgrimes if (!xdr_bool(xdrsp, &bool)) 3221590Srgrimes return (0); 3231590Srgrimes } 3241590Srgrimes return (1); 3251590Srgrimes} 3261590Srgrimes 3271590Srgrimes/* 3281590Srgrimes * Xdr routine to retrieve exports list 3291590Srgrimes */ 33028068Scharnierint 3311590Srgrimesxdr_exports(xdrsp, exp) 3321590Srgrimes XDR *xdrsp; 3331590Srgrimes struct exportslist **exp; 3341590Srgrimes{ 3351590Srgrimes register struct exportslist *ep; 3361590Srgrimes register struct grouplist *gp; 3371590Srgrimes int bool, grpbool; 3381590Srgrimes char *strp; 3391590Srgrimes 3401590Srgrimes *exp = (struct exportslist *)0; 3411590Srgrimes if (!xdr_bool(xdrsp, &bool)) 3421590Srgrimes return (0); 3431590Srgrimes while (bool) { 3441590Srgrimes ep = (struct exportslist *)malloc(sizeof(struct exportslist)); 3451590Srgrimes if (ep == NULL) 3461590Srgrimes return (0); 3471590Srgrimes ep->ex_groups = (struct grouplist *)0; 3481590Srgrimes strp = ep->ex_dirp; 3491590Srgrimes if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 3501590Srgrimes return (0); 3511590Srgrimes if (!xdr_bool(xdrsp, &grpbool)) 3521590Srgrimes return (0); 3531590Srgrimes while (grpbool) { 3541590Srgrimes gp = (struct grouplist *)malloc(sizeof(struct grouplist)); 3551590Srgrimes if (gp == NULL) 3561590Srgrimes return (0); 3571590Srgrimes strp = gp->gr_name; 3581590Srgrimes if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) 3591590Srgrimes return (0); 3601590Srgrimes gp->gr_next = ep->ex_groups; 3611590Srgrimes ep->ex_groups = gp; 3621590Srgrimes if (!xdr_bool(xdrsp, &grpbool)) 3631590Srgrimes return (0); 3641590Srgrimes } 3651590Srgrimes ep->ex_next = *exp; 3661590Srgrimes *exp = ep; 3671590Srgrimes if (!xdr_bool(xdrsp, &bool)) 3681590Srgrimes return (0); 3691590Srgrimes } 3701590Srgrimes return (1); 3711590Srgrimes} 3721590Srgrimes 37328068Scharnierstatic void 3741590Srgrimesusage() 3751590Srgrimes{ 376104966Sjmallett fprintf(stderr, "usage: showmount [-a | -d] [-e3] host\n"); 3771590Srgrimes exit(1); 3781590Srgrimes} 3791590Srgrimes 3801590Srgrimes/* 3811590Srgrimes * Print the binary tree in inorder so that output is sorted. 3821590Srgrimes */ 38328068Scharniervoid 3841590Srgrimesprint_dump(mp) 3851590Srgrimes struct mountlist *mp; 3861590Srgrimes{ 3871590Srgrimes 3881590Srgrimes if (mp == NULL) 3891590Srgrimes return; 3901590Srgrimes if (mp->ml_left) 3911590Srgrimes print_dump(mp->ml_left); 3921590Srgrimes switch (type) { 3931590Srgrimes case ALL: 3941590Srgrimes printf("%s:%s\n", mp->ml_host, mp->ml_dirp); 3951590Srgrimes break; 3961590Srgrimes case DIRS: 3971590Srgrimes printf("%s\n", mp->ml_dirp); 3981590Srgrimes break; 3991590Srgrimes default: 4001590Srgrimes printf("%s\n", mp->ml_host); 4011590Srgrimes break; 4021590Srgrimes }; 4031590Srgrimes if (mp->ml_right) 4041590Srgrimes print_dump(mp->ml_right); 4051590Srgrimes} 406