showmount.c revision 87297
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 87297 2001-12-03 21:25:28Z dwmalone $";
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
9828068Scharniervoid print_dump __P((struct mountlist *));
9928068Scharnierstatic void usage __P((void));
10028068Scharnierint xdr_mntdump __P((XDR *, struct mountlist **));
10128068Scharnierint xdr_exports __P((XDR *, struct exportslist **));
10287297Sdwmaloneint tcp_callrpc __P((const char *host,
10329117Stegge		     int prognum, int versnum, int procnum,
10429117Stegge		     xdrproc_t inproc, char *in,
10529117Stegge		     xdrproc_t outproc, char *out));
10628068Scharnier
1071590Srgrimes/*
1081590Srgrimes * This command queries the NFS mount daemon for it's mount list and/or
1091590Srgrimes * it's exports list and prints them out.
1101590Srgrimes * See "NFS: Network File System Protocol Specification, RFC1094, Appendix A"
1119336Sdfr * and the "Network File System Protocol XXX.."
1121590Srgrimes * for detailed information on the protocol.
1131590Srgrimes */
11428068Scharnierint
1151590Srgrimesmain(argc, argv)
1161590Srgrimes	int argc;
1171590Srgrimes	char **argv;
1181590Srgrimes{
1191590Srgrimes	register struct exportslist *exp;
1201590Srgrimes	register struct grouplist *grp;
1219336Sdfr	register int rpcs = 0, mntvers = 1;
1221590Srgrimes	char ch;
12387297Sdwmalone	const char *host;
1241590Srgrimes	int estat;
1251590Srgrimes
12624360Simp	while ((ch = getopt(argc, argv, "ade3")) != -1)
1271590Srgrimes		switch((char)ch) {
1281590Srgrimes		case 'a':
1291590Srgrimes			if (type == 0) {
1301590Srgrimes				type = ALL;
1311590Srgrimes				rpcs |= DODUMP;
1321590Srgrimes			} else
1331590Srgrimes				usage();
1341590Srgrimes			break;
1351590Srgrimes		case 'd':
1361590Srgrimes			if (type == 0) {
1371590Srgrimes				type = DIRS;
1381590Srgrimes				rpcs |= DODUMP;
1391590Srgrimes			} else
1401590Srgrimes				usage();
1411590Srgrimes			break;
1421590Srgrimes		case 'e':
1431590Srgrimes			rpcs |= DOEXPORTS;
1441590Srgrimes			break;
1459336Sdfr		case '3':
1469336Sdfr			mntvers = 3;
1479336Sdfr			break;
1481590Srgrimes		case '?':
1491590Srgrimes		default:
1501590Srgrimes			usage();
1511590Srgrimes		}
1521590Srgrimes	argc -= optind;
1531590Srgrimes	argv += optind;
1541590Srgrimes
1551590Srgrimes	if (argc > 0)
1561590Srgrimes		host = *argv;
1571590Srgrimes	else
1581590Srgrimes		host = "localhost";
1591590Srgrimes
1601590Srgrimes	if (rpcs == 0)
1611590Srgrimes		rpcs = DODUMP;
1621590Srgrimes
1631590Srgrimes	if (rpcs & DODUMP)
16429117Stegge		if ((estat = tcp_callrpc(host, RPCPROG_MNT, mntvers,
1651590Srgrimes			RPCMNT_DUMP, xdr_void, (char *)0,
1661590Srgrimes			xdr_mntdump, (char *)&mntdump)) != 0) {
1671590Srgrimes			clnt_perrno(estat);
16828068Scharnier			errx(1, "can't do mountdump rpc");
1691590Srgrimes		}
1701590Srgrimes	if (rpcs & DOEXPORTS)
17129117Stegge		if ((estat = tcp_callrpc(host, RPCPROG_MNT, mntvers,
1721590Srgrimes			RPCMNT_EXPORT, xdr_void, (char *)0,
1731590Srgrimes			xdr_exports, (char *)&exports)) != 0) {
1741590Srgrimes			clnt_perrno(estat);
17528068Scharnier			errx(1, "can't do exports rpc");
1761590Srgrimes		}
1771590Srgrimes
1781590Srgrimes	/* Now just print out the results */
1791590Srgrimes	if (rpcs & DODUMP) {
1801590Srgrimes		switch (type) {
1811590Srgrimes		case ALL:
1821590Srgrimes			printf("All mount points on %s:\n", host);
1831590Srgrimes			break;
1841590Srgrimes		case DIRS:
1851590Srgrimes			printf("Directories on %s:\n", host);
1861590Srgrimes			break;
1871590Srgrimes		default:
1881590Srgrimes			printf("Hosts on %s:\n", host);
1891590Srgrimes			break;
1901590Srgrimes		};
1911590Srgrimes		print_dump(mntdump);
1921590Srgrimes	}
1931590Srgrimes	if (rpcs & DOEXPORTS) {
1941590Srgrimes		printf("Exports list on %s:\n", host);
1951590Srgrimes		exp = exports;
1961590Srgrimes		while (exp) {
1971590Srgrimes			printf("%-35s", exp->ex_dirp);
1981590Srgrimes			grp = exp->ex_groups;
1991590Srgrimes			if (grp == NULL) {
2001590Srgrimes				printf("Everyone\n");
2011590Srgrimes			} else {
2021590Srgrimes				while (grp) {
2031590Srgrimes					printf("%s ", grp->gr_name);
2041590Srgrimes					grp = grp->gr_next;
2051590Srgrimes				}
2061590Srgrimes				printf("\n");
2071590Srgrimes			}
2081590Srgrimes			exp = exp->ex_next;
2091590Srgrimes		}
2101590Srgrimes	}
21128068Scharnier	exit(0);
2121590Srgrimes}
2131590Srgrimes
2141590Srgrimes/*
21529117Stegge * tcp_callrpc has the same interface as callrpc, but tries to
21629117Stegge * use tcp as transport method in order to handle large replies.
21729117Stegge */
21829117Steggeint
21929117Steggetcp_callrpc(host, prognum, versnum, procnum, inproc, in, outproc, out)
22087297Sdwmalone	const char *host;
22129117Stegge	int prognum;
22229117Stegge	int versnum;
22329117Stegge	int procnum;
22429117Stegge	xdrproc_t inproc;
22529117Stegge	char *in;
22629117Stegge	xdrproc_t outproc;
22729117Stegge	char *out;
22829117Stegge{
22929117Stegge	CLIENT *client;
23029117Stegge	struct timeval timeout;
23129117Stegge	int rval;
23229117Stegge
23375239Siedowse	if ((client = clnt_create(host, prognum, versnum, "tcp")) == NULL &&
23475239Siedowse	    (client = clnt_create(host, prognum, versnum, "udp")) == NULL)
23529117Stegge		return ((int) rpc_createerr.cf_stat);
23629117Stegge
23729117Stegge	timeout.tv_sec = 25;
23829117Stegge	timeout.tv_usec = 0;
23929117Stegge	rval = (int) clnt_call(client, procnum,
24029117Stegge			       inproc, in,
24129117Stegge			       outproc, out,
24229117Stegge			       timeout);
24329117Stegge	clnt_destroy(client);
24429117Stegge 	return rval;
24529117Stegge}
24629117Stegge
24729117Stegge/*
2481590Srgrimes * Xdr routine for retrieving the mount dump list
2491590Srgrimes */
25028068Scharnierint
2511590Srgrimesxdr_mntdump(xdrsp, mlp)
2521590Srgrimes	XDR *xdrsp;
2531590Srgrimes	struct mountlist **mlp;
2541590Srgrimes{
2551590Srgrimes	register struct mountlist *mp;
2561590Srgrimes	register struct mountlist *tp;
2571590Srgrimes	register struct mountlist **otp;
2581590Srgrimes	int val, val2;
2591590Srgrimes	int bool;
2601590Srgrimes	char *strp;
2611590Srgrimes
2621590Srgrimes	*mlp = (struct mountlist *)0;
2631590Srgrimes	if (!xdr_bool(xdrsp, &bool))
2641590Srgrimes		return (0);
2651590Srgrimes	while (bool) {
2661590Srgrimes		mp = (struct mountlist *)malloc(sizeof(struct mountlist));
2671590Srgrimes		if (mp == NULL)
2681590Srgrimes			return (0);
2691590Srgrimes		mp->ml_left = mp->ml_right = (struct mountlist *)0;
2701590Srgrimes		strp = mp->ml_host;
2711590Srgrimes		if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN))
2721590Srgrimes			return (0);
2731590Srgrimes		strp = mp->ml_dirp;
2741590Srgrimes		if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
2751590Srgrimes			return (0);
2761590Srgrimes
2771590Srgrimes		/*
2781590Srgrimes		 * Build a binary tree on sorted order of either host or dirp.
2791590Srgrimes		 * Drop any duplications.
2801590Srgrimes		 */
2811590Srgrimes		if (*mlp == NULL) {
2821590Srgrimes			*mlp = mp;
2831590Srgrimes		} else {
2841590Srgrimes			tp = *mlp;
2851590Srgrimes			while (tp) {
2861590Srgrimes				val = strcmp(mp->ml_host, tp->ml_host);
2871590Srgrimes				val2 = strcmp(mp->ml_dirp, tp->ml_dirp);
2881590Srgrimes				switch (type) {
2891590Srgrimes				case ALL:
2901590Srgrimes					if (val == 0) {
2911590Srgrimes						if (val2 == 0) {
2921590Srgrimes							free((caddr_t)mp);
2931590Srgrimes							goto next;
2941590Srgrimes						}
2951590Srgrimes						val = val2;
2961590Srgrimes					}
2971590Srgrimes					break;
2981590Srgrimes				case DIRS:
2991590Srgrimes					if (val2 == 0) {
3001590Srgrimes						free((caddr_t)mp);
3011590Srgrimes						goto next;
3021590Srgrimes					}
3031590Srgrimes					val = val2;
3041590Srgrimes					break;
3051590Srgrimes				default:
3061590Srgrimes					if (val == 0) {
3071590Srgrimes						free((caddr_t)mp);
3081590Srgrimes						goto next;
3091590Srgrimes					}
3101590Srgrimes					break;
3111590Srgrimes				};
3121590Srgrimes				if (val < 0) {
3131590Srgrimes					otp = &tp->ml_left;
3141590Srgrimes					tp = tp->ml_left;
3151590Srgrimes				} else {
3161590Srgrimes					otp = &tp->ml_right;
3171590Srgrimes					tp = tp->ml_right;
3181590Srgrimes				}
3191590Srgrimes			}
3201590Srgrimes			*otp = mp;
3211590Srgrimes		}
3221590Srgrimesnext:
3231590Srgrimes		if (!xdr_bool(xdrsp, &bool))
3241590Srgrimes			return (0);
3251590Srgrimes	}
3261590Srgrimes	return (1);
3271590Srgrimes}
3281590Srgrimes
3291590Srgrimes/*
3301590Srgrimes * Xdr routine to retrieve exports list
3311590Srgrimes */
33228068Scharnierint
3331590Srgrimesxdr_exports(xdrsp, exp)
3341590Srgrimes	XDR *xdrsp;
3351590Srgrimes	struct exportslist **exp;
3361590Srgrimes{
3371590Srgrimes	register struct exportslist *ep;
3381590Srgrimes	register struct grouplist *gp;
3391590Srgrimes	int bool, grpbool;
3401590Srgrimes	char *strp;
3411590Srgrimes
3421590Srgrimes	*exp = (struct exportslist *)0;
3431590Srgrimes	if (!xdr_bool(xdrsp, &bool))
3441590Srgrimes		return (0);
3451590Srgrimes	while (bool) {
3461590Srgrimes		ep = (struct exportslist *)malloc(sizeof(struct exportslist));
3471590Srgrimes		if (ep == NULL)
3481590Srgrimes			return (0);
3491590Srgrimes		ep->ex_groups = (struct grouplist *)0;
3501590Srgrimes		strp = ep->ex_dirp;
3511590Srgrimes		if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
3521590Srgrimes			return (0);
3531590Srgrimes		if (!xdr_bool(xdrsp, &grpbool))
3541590Srgrimes			return (0);
3551590Srgrimes		while (grpbool) {
3561590Srgrimes			gp = (struct grouplist *)malloc(sizeof(struct grouplist));
3571590Srgrimes			if (gp == NULL)
3581590Srgrimes				return (0);
3591590Srgrimes			strp = gp->gr_name;
3601590Srgrimes			if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN))
3611590Srgrimes				return (0);
3621590Srgrimes			gp->gr_next = ep->ex_groups;
3631590Srgrimes			ep->ex_groups = gp;
3641590Srgrimes			if (!xdr_bool(xdrsp, &grpbool))
3651590Srgrimes				return (0);
3661590Srgrimes		}
3671590Srgrimes		ep->ex_next = *exp;
3681590Srgrimes		*exp = ep;
3691590Srgrimes		if (!xdr_bool(xdrsp, &bool))
3701590Srgrimes			return (0);
3711590Srgrimes	}
3721590Srgrimes	return (1);
3731590Srgrimes}
3741590Srgrimes
37528068Scharnierstatic void
3761590Srgrimesusage()
3771590Srgrimes{
37824825Sobrien	fprintf(stderr, "usage: showmount [-ade3] host\n");
3791590Srgrimes	exit(1);
3801590Srgrimes}
3811590Srgrimes
3821590Srgrimes/*
3831590Srgrimes * Print the binary tree in inorder so that output is sorted.
3841590Srgrimes */
38528068Scharniervoid
3861590Srgrimesprint_dump(mp)
3871590Srgrimes	struct mountlist *mp;
3881590Srgrimes{
3891590Srgrimes
3901590Srgrimes	if (mp == NULL)
3911590Srgrimes		return;
3921590Srgrimes	if (mp->ml_left)
3931590Srgrimes		print_dump(mp->ml_left);
3941590Srgrimes	switch (type) {
3951590Srgrimes	case ALL:
3961590Srgrimes		printf("%s:%s\n", mp->ml_host, mp->ml_dirp);
3971590Srgrimes		break;
3981590Srgrimes	case DIRS:
3991590Srgrimes		printf("%s\n", mp->ml_dirp);
4001590Srgrimes		break;
4011590Srgrimes	default:
4021590Srgrimes		printf("%s\n", mp->ml_host);
4031590Srgrimes		break;
4041590Srgrimes	};
4051590Srgrimes	if (mp->ml_right)
4061590Srgrimes		print_dump(mp->ml_right);
4071590Srgrimes}
408