xref: /dragonfly/usr.bin/showmount/showmount.c (revision 8bf5b238)
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  * 3. 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  * @(#) Copyright (c) 1989, 1993, 1995 The Regents of the University of California.  All rights reserved.
33  * @(#)showmount.c	8.3 (Berkeley) 3/29/95
34  * $FreeBSD: src/usr.bin/showmount/showmount.c,v 1.16 2005/05/21 09:55:08 ru Exp $
35  */
36 
37 #include <sys/types.h>
38 #include <sys/queue.h>
39 #include <sys/file.h>
40 #include <sys/socket.h>
41 #include <sys/socketvar.h>
42 
43 #include <err.h>
44 #include <netdb.h>
45 #include <rpc/rpc.h>
46 #include <rpc/pmap_clnt.h>
47 #include <rpc/pmap_prot.h>
48 #include <nfs/rpcv2.h>
49 
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <unistd.h>
54 #include <vis.h>
55 
56 /* Constant defs */
57 #define	ALL	1
58 #define	DIRS	2
59 
60 #define	DODUMP		0x1
61 #define	DOEXPORTS	0x2
62 #define	DOPARSABLEEXPORTS	0x4
63 
64 struct mountlist {
65 	struct mountlist *ml_left;
66 	struct mountlist *ml_right;
67 	char	ml_host[RPCMNT_NAMELEN+1];
68 	char	ml_dirp[RPCMNT_PATHLEN+1];
69 };
70 
71 struct grouplist {
72 	struct grouplist *gr_next;
73 	char	gr_name[RPCMNT_NAMELEN+1];
74 };
75 
76 struct exportslist {
77 	struct exportslist *ex_next;
78 	struct grouplist *ex_groups;
79 	char	ex_dirp[RPCMNT_PATHLEN+1];
80 };
81 
82 static struct mountlist *mntdump;
83 static struct exportslist *exports;
84 static int type = 0;
85 
86 void print_dump(struct mountlist *);
87 static void usage(void);
88 int xdr_mntdump(XDR *, struct mountlist **);
89 int xdr_exports(XDR *, struct exportslist **);
90 int tcp_callrpc(const char *, int, int, int, xdrproc_t, char *, xdrproc_t,
91 		char *);
92 
93 /*
94  * This command queries the NFS mount daemon for it's mount list and/or
95  * it's exports list and prints them out.
96  * See "NFS: Network File System Protocol Specification, RFC1094, Appendix A"
97  * and the "Network File System Protocol XXX.."
98  * for detailed information on the protocol.
99  */
100 int
101 main(int argc, char **argv)
102 {
103 	struct exportslist *exp;
104 	struct grouplist *grp;
105 	int rpcs = 0, mntvers = 1;
106 	const char *host;
107 	int ch, estat, nbytes;
108 	char strvised[1024 * 4 + 1];
109 
110 	while ((ch = getopt(argc, argv, "adEe3")) != -1)
111 		switch (ch) {
112 		case 'a':
113 			if (type == 0) {
114 				type = ALL;
115 				rpcs |= DODUMP;
116 			} else
117 				usage();
118 			break;
119 		case 'd':
120 			if (type == 0) {
121 				type = DIRS;
122 				rpcs |= DODUMP;
123 			} else
124 				usage();
125 			break;
126 		case 'E':
127 			rpcs |= DOPARSABLEEXPORTS;
128 			break;
129 		case 'e':
130 			rpcs |= DOEXPORTS;
131 			break;
132 		case '3':
133 			mntvers = 3;
134 			break;
135 		case '?':
136 		default:
137 			usage();
138 		}
139 	argc -= optind;
140 	argv += optind;
141 
142 	if ((rpcs & DOPARSABLEEXPORTS) != 0) {
143 		if ((rpcs & DOEXPORTS) != 0)
144 			errx(1, "-E cannot be used with -e");
145 		if ((rpcs & DODUMP) != 0)
146 			errx(1, "-E cannot be used with -a or -d");
147 	}
148 
149 	if (argc > 0)
150 		host = *argv;
151 	else
152 		host = "localhost";
153 
154 	if (rpcs == 0)
155 		rpcs = DODUMP;
156 
157 	if (rpcs & DODUMP)
158 		if ((estat = tcp_callrpc(host, RPCPROG_MNT, mntvers,
159 			RPCMNT_DUMP, (xdrproc_t)xdr_void, NULL,
160 			(xdrproc_t)xdr_mntdump, (char *)&mntdump)) != 0) {
161 			clnt_perrno(estat);
162 			errx(1, "can't do mountdump rpc");
163 		}
164 	if (rpcs & (DOEXPORTS | DOPARSABLEEXPORTS))
165 		if ((estat = tcp_callrpc(host, RPCPROG_MNT, mntvers,
166 			RPCMNT_EXPORT, (xdrproc_t)xdr_void, NULL,
167 			(xdrproc_t)xdr_exports, (char *)&exports)) != 0) {
168 			clnt_perrno(estat);
169 			errx(1, "can't do exports rpc");
170 		}
171 
172 	/* Now just print out the results */
173 	if (rpcs & DODUMP) {
174 		switch (type) {
175 		case ALL:
176 			printf("All mount points on %s:\n", host);
177 			break;
178 		case DIRS:
179 			printf("Directories on %s:\n", host);
180 			break;
181 		default:
182 			printf("Hosts on %s:\n", host);
183 			break;
184 		}
185 		print_dump(mntdump);
186 	}
187 	if (rpcs & DOEXPORTS) {
188 		printf("Exports list on %s:\n", host);
189 		exp = exports;
190 		while (exp) {
191 			printf("%-35s", exp->ex_dirp);
192 			grp = exp->ex_groups;
193 			if (grp == NULL) {
194 				printf("Everyone\n");
195 			} else {
196 				while (grp) {
197 					printf("%s ", grp->gr_name);
198 					grp = grp->gr_next;
199 				}
200 				printf("\n");
201 			}
202 			exp = exp->ex_next;
203 		}
204 	}
205 	if (rpcs & DOPARSABLEEXPORTS) {
206 		exp = exports;
207 		while (exp) {
208 			nbytes = strsnvis(strvised, sizeof(strvised),
209 			    exp->ex_dirp, VIS_GLOB | VIS_NL, "\"'$");
210 			if (nbytes == -1)
211 				err(1, "strsnvis");
212 			printf("%s\n", strvised);
213 			exp = exp->ex_next;
214 		}
215 	}
216 	exit(0);
217 }
218 
219 /*
220  * tcp_callrpc has the same interface as callrpc, but tries to
221  * use tcp as transport method in order to handle large replies.
222  */
223 int
224 tcp_callrpc(const char *host, int prognum, int versnum, int procnum,
225 	    xdrproc_t inproc, char *in, xdrproc_t outproc, char *out)
226 {
227 	CLIENT *client;
228 	struct timeval timeout;
229 	int rval;
230 
231 	if ((client = clnt_create(host, prognum, versnum, "tcp")) == NULL &&
232 	    (client = clnt_create(host, prognum, versnum, "udp")) == NULL)
233 		return ((int) rpc_createerr.cf_stat);
234 
235 	timeout.tv_sec = 25;
236 	timeout.tv_usec = 0;
237 	rval = (int) clnt_call(client, procnum,
238 			       inproc, in,
239 			       outproc, out,
240 			       timeout);
241 	clnt_destroy(client);
242 	return rval;
243 }
244 
245 /*
246  * Xdr routine for retrieving the mount dump list
247  */
248 int
249 xdr_mntdump(XDR *xdrsp, struct mountlist **mlp)
250 {
251 	struct mountlist *mp;
252 	struct mountlist *tp;
253 	struct mountlist **otp = NULL;
254 	int val, val2;
255 	int bool;
256 	char *strp;
257 
258 	*mlp = NULL;
259 	if (!xdr_bool(xdrsp, &bool))
260 		return (0);
261 	while (bool) {
262 		mp = (struct mountlist *)malloc(sizeof(struct mountlist));
263 		if (mp == NULL)
264 			return (0);
265 		mp->ml_left = mp->ml_right = NULL;
266 		strp = mp->ml_host;
267 		if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN))
268 			return (0);
269 		strp = mp->ml_dirp;
270 		if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
271 			return (0);
272 
273 		/*
274 		 * Build a binary tree on sorted order of either host or dirp.
275 		 * Drop any duplications.
276 		 */
277 		if (*mlp == NULL) {
278 			*mlp = mp;
279 		} else {
280 			tp = *mlp;
281 			while (tp) {
282 				val = strcmp(mp->ml_host, tp->ml_host);
283 				val2 = strcmp(mp->ml_dirp, tp->ml_dirp);
284 				switch (type) {
285 				case ALL:
286 					if (val == 0) {
287 						if (val2 == 0) {
288 							free(mp);
289 							goto next;
290 						}
291 						val = val2;
292 					}
293 					break;
294 				case DIRS:
295 					if (val2 == 0) {
296 						free(mp);
297 						goto next;
298 					}
299 					val = val2;
300 					break;
301 				default:
302 					if (val == 0) {
303 						free(mp);
304 						goto next;
305 					}
306 					break;
307 				}
308 				if (val < 0) {
309 					otp = &tp->ml_left;
310 					tp = tp->ml_left;
311 				} else {
312 					otp = &tp->ml_right;
313 					tp = tp->ml_right;
314 				}
315 			}
316 			*otp = mp;
317 		}
318 next:
319 		if (!xdr_bool(xdrsp, &bool))
320 			return (0);
321 	}
322 	return (1);
323 }
324 
325 /*
326  * Xdr routine to retrieve exports list
327  */
328 int
329 xdr_exports(XDR *xdrsp, struct exportslist **exp)
330 {
331 	struct exportslist *ep;
332 	struct grouplist *gp;
333 	int bool, grpbool;
334 	char *strp;
335 
336 	*exp = NULL;
337 	if (!xdr_bool(xdrsp, &bool))
338 		return (0);
339 	while (bool) {
340 		ep = (struct exportslist *)malloc(sizeof(struct exportslist));
341 		if (ep == NULL)
342 			return (0);
343 		ep->ex_groups = NULL;
344 		strp = ep->ex_dirp;
345 		if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
346 			return (0);
347 		if (!xdr_bool(xdrsp, &grpbool))
348 			return (0);
349 		while (grpbool) {
350 			gp = (struct grouplist *)malloc(sizeof(struct grouplist));
351 			if (gp == NULL)
352 				return (0);
353 			strp = gp->gr_name;
354 			if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN))
355 				return (0);
356 			gp->gr_next = ep->ex_groups;
357 			ep->ex_groups = gp;
358 			if (!xdr_bool(xdrsp, &grpbool))
359 				return (0);
360 		}
361 		ep->ex_next = *exp;
362 		*exp = ep;
363 		if (!xdr_bool(xdrsp, &bool))
364 			return (0);
365 	}
366 	return (1);
367 }
368 
369 static void
370 usage(void)
371 {
372 	fprintf(stderr, "usage: showmount [-a | -d] [-e3] [host]\n");
373 	exit(1);
374 }
375 
376 /*
377  * Print the binary tree in inorder so that output is sorted.
378  */
379 void
380 print_dump(struct mountlist *mp)
381 {
382 
383 	if (mp == NULL)
384 		return;
385 	if (mp->ml_left)
386 		print_dump(mp->ml_left);
387 	switch (type) {
388 	case ALL:
389 		printf("%s:%s\n", mp->ml_host, mp->ml_dirp);
390 		break;
391 	case DIRS:
392 		printf("%s\n", mp->ml_dirp);
393 		break;
394 	default:
395 		printf("%s\n", mp->ml_host);
396 		break;
397 	}
398 	if (mp->ml_right)
399 		print_dump(mp->ml_right);
400 }
401