1/*
2 * Copyright (c) 1989, 1993, 1995
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 4. Neither the name of the University nor the names of its contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#ifndef lint
34static const char copyright[] =
35"@(#) Copyright (c) 1989, 1993, 1995\n\
36	The Regents of the University of California.  All rights reserved.\n";
37#endif /* not lint */
38
39#ifndef lint
40#if 0
41static char sccsid[] = "@(#)showmount.c	8.3 (Berkeley) 3/29/95";
42#endif
43static const char rcsid[] =
44  "$FreeBSD: stable/10/usr.bin/showmount/showmount.c 308292 2016-11-04 14:06:21Z trasz $";
45#endif /* not lint */
46
47#include <sys/types.h>
48#include <sys/queue.h>
49#include <sys/file.h>
50#include <sys/socket.h>
51#include <sys/socketvar.h>
52
53#include <err.h>
54#include <netdb.h>
55#include <rpc/rpc.h>
56#include <rpc/pmap_clnt.h>
57#include <rpc/pmap_prot.h>
58#include <rpcsvc/mount.h>
59
60#include <stdio.h>
61#include <stdlib.h>
62#include <string.h>
63#include <unistd.h>
64#include <vis.h>
65
66/* Constant defs */
67#define	ALL	1
68#define	DIRS	2
69
70#define	DODUMP			0x1
71#define	DOEXPORTS		0x2
72#define	DOPARSABLEEXPORTS	0x4
73
74struct mountlist {
75	struct mountlist *ml_left;
76	struct mountlist *ml_right;
77	char	ml_host[MNTNAMLEN+1];
78	char	ml_dirp[MNTPATHLEN+1];
79};
80
81struct grouplist {
82	struct grouplist *gr_next;
83	char	gr_name[MNTNAMLEN+1];
84};
85
86struct exportslist {
87	struct exportslist *ex_next;
88	struct grouplist *ex_groups;
89	char	ex_dirp[MNTPATHLEN+1];
90};
91
92static struct mountlist *mntdump;
93static struct exportslist *exportslist;
94static int type = 0;
95
96void print_dump(struct mountlist *);
97static void usage(void);
98int xdr_mntdump(XDR *, struct mountlist **);
99int xdr_exportslist(XDR *, struct exportslist **);
100int tcp_callrpc(const char *host, int prognum, int versnum, int procnum,
101		xdrproc_t inproc, char *in, xdrproc_t outproc, char *out);
102
103/*
104 * This command queries the NFS mount daemon for it's mount list and/or
105 * it's exports list and prints them out.
106 * See "NFS: Network File System Protocol Specification, RFC1094, Appendix A"
107 * and the "Network File System Protocol XXX.."
108 * for detailed information on the protocol.
109 */
110int
111main(int argc, char **argv)
112{
113	char strvised[MNTPATHLEN * 4 + 1];
114	register struct exportslist *exp;
115	register struct grouplist *grp;
116	register int rpcs = 0, mntvers = 3;
117	const char *host;
118	int ch, estat, nbytes;
119
120	while ((ch = getopt(argc, argv, "adEe13")) != -1)
121		switch (ch) {
122		case 'a':
123			if (type == 0) {
124				type = ALL;
125				rpcs |= DODUMP;
126			} else
127				usage();
128			break;
129		case 'd':
130			if (type == 0) {
131				type = DIRS;
132				rpcs |= DODUMP;
133			} else
134				usage();
135			break;
136		case 'E':
137			rpcs |= DOPARSABLEEXPORTS;
138			break;
139		case 'e':
140			rpcs |= DOEXPORTS;
141			break;
142		case '1':
143			mntvers = 1;
144			break;
145		case '3':
146			mntvers = 3;
147			break;
148		case '?':
149		default:
150			usage();
151		}
152	argc -= optind;
153	argv += optind;
154
155	if ((rpcs & DOPARSABLEEXPORTS) != 0) {
156		if ((rpcs & DOEXPORTS) != 0)
157			errx(1, "-E cannot be used with -e");
158		if ((rpcs & DODUMP) != 0)
159			errx(1, "-E cannot be used with -a or -d");
160	}
161
162	if (argc > 0)
163		host = *argv;
164	else
165		host = "localhost";
166
167	if (rpcs == 0)
168		rpcs = DODUMP;
169
170	if (rpcs & DODUMP)
171		if ((estat = tcp_callrpc(host, MOUNTPROG, mntvers,
172			MOUNTPROC_DUMP, (xdrproc_t)xdr_void, (char *)0,
173			(xdrproc_t)xdr_mntdump, (char *)&mntdump)) != 0) {
174			clnt_perrno(estat);
175			errx(1, "can't do mountdump rpc");
176		}
177	if (rpcs & (DOEXPORTS | DOPARSABLEEXPORTS))
178		if ((estat = tcp_callrpc(host, MOUNTPROG, mntvers,
179			MOUNTPROC_EXPORT, (xdrproc_t)xdr_void, (char *)0,
180			(xdrproc_t)xdr_exportslist, (char *)&exportslist)) != 0) {
181			clnt_perrno(estat);
182			errx(1, "can't do exports rpc");
183		}
184
185	/* Now just print out the results */
186	if (rpcs & DODUMP) {
187		switch (type) {
188		case ALL:
189			printf("All mount points on %s:\n", host);
190			break;
191		case DIRS:
192			printf("Directories on %s:\n", host);
193			break;
194		default:
195			printf("Hosts on %s:\n", host);
196			break;
197		};
198		print_dump(mntdump);
199	}
200	if (rpcs & DOEXPORTS) {
201		printf("Exports list on %s:\n", host);
202		exp = exportslist;
203		while (exp) {
204			printf("%-34s ", exp->ex_dirp);
205			grp = exp->ex_groups;
206			if (grp == NULL) {
207				printf("Everyone\n");
208			} else {
209				while (grp) {
210					printf("%s ", grp->gr_name);
211					grp = grp->gr_next;
212				}
213				printf("\n");
214			}
215			exp = exp->ex_next;
216		}
217	}
218	if (rpcs & DOPARSABLEEXPORTS) {
219		exp = exportslist;
220		while (exp) {
221			nbytes = strsnvis(strvised, sizeof(strvised),
222			    exp->ex_dirp, VIS_GLOB | VIS_NL, "\"'$");
223			if (nbytes == -1)
224				err(1, "strsnvis");
225			printf("%s\n", strvised);
226			exp = exp->ex_next;
227		}
228	}
229	exit(0);
230}
231
232/*
233 * tcp_callrpc has the same interface as callrpc, but tries to
234 * use tcp as transport method in order to handle large replies.
235 */
236int
237tcp_callrpc(const char *host, int prognum, int versnum, int procnum,
238    xdrproc_t inproc, char *in, xdrproc_t outproc, char *out)
239{
240	CLIENT *client;
241	struct timeval timeout;
242	int rval;
243
244	if ((client = clnt_create(host, prognum, versnum, "tcp")) == NULL &&
245	    (client = clnt_create(host, prognum, versnum, "udp")) == NULL)
246		return ((int) rpc_createerr.cf_stat);
247
248	timeout.tv_sec = 25;
249	timeout.tv_usec = 0;
250	rval = (int) clnt_call(client, procnum,
251			       inproc, in,
252			       outproc, out,
253			       timeout);
254	clnt_destroy(client);
255 	return rval;
256}
257
258/*
259 * Xdr routine for retrieving the mount dump list
260 */
261int
262xdr_mntdump(XDR *xdrsp, struct mountlist **mlp)
263{
264	register struct mountlist *mp;
265	register struct mountlist *tp;
266	register struct mountlist **otp;
267	int val, val2;
268	int bool;
269	char *strp;
270
271	*mlp = (struct mountlist *)0;
272	if (!xdr_bool(xdrsp, &bool))
273		return (0);
274	while (bool) {
275		mp = (struct mountlist *)malloc(sizeof(struct mountlist));
276		if (mp == NULL)
277			return (0);
278		mp->ml_left = mp->ml_right = (struct mountlist *)0;
279		strp = mp->ml_host;
280		if (!xdr_string(xdrsp, &strp, MNTNAMLEN))
281			return (0);
282		strp = mp->ml_dirp;
283		if (!xdr_string(xdrsp, &strp, MNTPATHLEN))
284			return (0);
285
286		/*
287		 * Build a binary tree on sorted order of either host or dirp.
288		 * Drop any duplications.
289		 */
290		if (*mlp == NULL) {
291			*mlp = mp;
292		} else {
293			tp = *mlp;
294			while (tp) {
295				val = strcmp(mp->ml_host, tp->ml_host);
296				val2 = strcmp(mp->ml_dirp, tp->ml_dirp);
297				switch (type) {
298				case ALL:
299					if (val == 0) {
300						if (val2 == 0) {
301							free((caddr_t)mp);
302							goto next;
303						}
304						val = val2;
305					}
306					break;
307				case DIRS:
308					if (val2 == 0) {
309						free((caddr_t)mp);
310						goto next;
311					}
312					val = val2;
313					break;
314				default:
315					if (val == 0) {
316						free((caddr_t)mp);
317						goto next;
318					}
319					break;
320				};
321				if (val < 0) {
322					otp = &tp->ml_left;
323					tp = tp->ml_left;
324				} else {
325					otp = &tp->ml_right;
326					tp = tp->ml_right;
327				}
328			}
329			*otp = mp;
330		}
331next:
332		if (!xdr_bool(xdrsp, &bool))
333			return (0);
334	}
335	return (1);
336}
337
338/*
339 * Xdr routine to retrieve exports list
340 */
341int
342xdr_exportslist(XDR *xdrsp, struct exportslist **exp)
343{
344	register struct exportslist *ep;
345	register struct grouplist *gp;
346	int bool, grpbool;
347	char *strp;
348
349	*exp = (struct exportslist *)0;
350	if (!xdr_bool(xdrsp, &bool))
351		return (0);
352	while (bool) {
353		ep = (struct exportslist *)malloc(sizeof(struct exportslist));
354		if (ep == NULL)
355			return (0);
356		ep->ex_groups = (struct grouplist *)0;
357		strp = ep->ex_dirp;
358		if (!xdr_string(xdrsp, &strp, MNTPATHLEN))
359			return (0);
360		if (!xdr_bool(xdrsp, &grpbool))
361			return (0);
362		while (grpbool) {
363			gp = (struct grouplist *)malloc(sizeof(struct grouplist));
364			if (gp == NULL)
365				return (0);
366			strp = gp->gr_name;
367			if (!xdr_string(xdrsp, &strp, MNTNAMLEN))
368				return (0);
369			gp->gr_next = ep->ex_groups;
370			ep->ex_groups = gp;
371			if (!xdr_bool(xdrsp, &grpbool))
372				return (0);
373		}
374		ep->ex_next = *exp;
375		*exp = ep;
376		if (!xdr_bool(xdrsp, &bool))
377			return (0);
378	}
379	return (1);
380}
381
382static void
383usage(void)
384{
385	fprintf(stderr, "usage: showmount [-a | -d] [-e3] [host]\n");
386	exit(1);
387}
388
389/*
390 * Print the binary tree in inorder so that output is sorted.
391 */
392void
393print_dump(struct mountlist *mp)
394{
395
396	if (mp == NULL)
397		return;
398	if (mp->ml_left)
399		print_dump(mp->ml_left);
400	switch (type) {
401	case ALL:
402		printf("%s:%s\n", mp->ml_host, mp->ml_dirp);
403		break;
404	case DIRS:
405		printf("%s\n", mp->ml_dirp);
406		break;
407	default:
408		printf("%s\n", mp->ml_host);
409		break;
410	};
411	if (mp->ml_right)
412		print_dump(mp->ml_right);
413}
414