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