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