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