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