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