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