1 /*
2  * Copyright (c) 1989 The Regents of the University of California.
3  * 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 are permitted
9  * provided that the above copyright notice and this paragraph are
10  * duplicated in all such forms and that any documentation,
11  * advertising materials, and other materials related to such
12  * distribution and use acknowledge that the software was developed
13  * by the University of California, Berkeley.  The name of the
14  * University may not be used to endorse or promote products derived
15  * from this software without specific prior written permission.
16  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19  */
20 
21 #ifndef lint
22 char copyright[] =
23 "@(#) Copyright (c) 1989 Regents of the University of California.\n\
24  All rights reserved.\n";
25 #endif not lint
26 
27 #ifndef lint
28 static char sccsid[] = "@(#)showmount.c	6.3 (Berkeley) 05/15/90";
29 #endif not lint
30 
31 #include <sys/types.h>
32 #include <sys/file.h>
33 #include <sys/socket.h>
34 #include <sys/socketvar.h>
35 #include <netdb.h>
36 #include <rpc/rpc.h>
37 #include <rpc/pmap_clnt.h>
38 #include <rpc/pmap_prot.h>
39 #include <nfs/rpcv2.h>
40 #include <stdio.h>
41 #include <string.h>
42 
43 /* Constant defs */
44 #define	ALL	1
45 #define	DIRS	2
46 
47 #define	DODUMP		0x1
48 #define	DOEXPORTS	0x2
49 
50 struct mountlist {
51 	struct mountlist *ml_left;
52 	struct mountlist *ml_right;
53 	char	ml_host[RPCMNT_NAMELEN+1];
54 	char	ml_dirp[RPCMNT_PATHLEN+1];
55 };
56 
57 struct grouplist {
58 	struct grouplist *gr_next;
59 	char	gr_name[RPCMNT_NAMELEN+1];
60 };
61 
62 struct exportslist {
63 	struct exportslist *ex_next;
64 	struct grouplist *ex_groups;
65 	char	ex_dirp[RPCMNT_PATHLEN+1];
66 };
67 
68 static struct mountlist *mntdump;
69 static struct exportslist *exports;
70 static int type = 0;
71 int xdr_mntdump(), xdr_exports();
72 
73 /*
74  * This command queries the NFS mount daemon for it's mount list and/or
75  * it's exports list and prints them out.
76  * See "NFS: Network File System Protocol Specification, RFC1094, Appendix A"
77  * for detailed information on the protocol.
78  */
79 main(argc, argv)
80 	int argc;
81 	char **argv;
82 {
83 	register struct mountlist *mntp;
84 	register struct exportslist *exp;
85 	register struct grouplist *grp;
86 	extern char *optarg;
87 	extern int optind;
88 	register int rpcs = 0;
89 	char ch;
90 	char *host;
91 	int estat;
92 
93 	while ((ch = getopt(argc, argv, "ade")) != EOF)
94 		switch((char)ch) {
95 		case 'a':
96 			if (type == 0) {
97 				type = ALL;
98 				rpcs |= DODUMP;
99 			} else
100 				usage();
101 			break;
102 		case 'd':
103 			if (type == 0) {
104 				type = DIRS;
105 				rpcs |= DODUMP;
106 			} else
107 				usage();
108 			break;
109 		case 'e':
110 			rpcs |= DOEXPORTS;
111 			break;
112 		case '?':
113 		default:
114 			usage();
115 		}
116 	argc -= optind;
117 	argv += optind;
118 
119 	if (argc > 0)
120 		host = *argv;
121 	else
122 		host = "localhost";
123 
124 	if (rpcs == 0)
125 		rpcs = DODUMP;
126 
127 	if (rpcs & DODUMP)
128 		if ((estat = callrpc(host, RPCPROG_MNT, RPCMNT_VER1,
129 			RPCMNT_DUMP, xdr_void, (char *)0,
130 			xdr_mntdump, (char *)&mntdump)) != 0) {
131 			clnt_perrno(estat);
132 			fprintf(stderr, "Can't do Mountdump rpc\n");
133 			exit(1);
134 		}
135 	if (rpcs & DOEXPORTS)
136 		if ((estat = callrpc(host, RPCPROG_MNT, RPCMNT_VER1,
137 			RPCMNT_EXPORT, xdr_void, (char *)0,
138 			xdr_exports, (char *)&exports)) != 0) {
139 			clnt_perrno(estat);
140 			fprintf(stderr, "Can't do Exports rpc\n");
141 			exit(1);
142 		}
143 
144 	/* Now just print out the results */
145 	if (rpcs & DODUMP) {
146 		switch (type) {
147 		case ALL:
148 			printf("All mount points on %s:\n", host);
149 			break;
150 		case DIRS:
151 			printf("Directories on %s:\n", host);
152 			break;
153 		default:
154 			printf("Hosts on %s:\n", host);
155 			break;
156 		};
157 		print_dump(mntdump);
158 	}
159 	if (rpcs & DOEXPORTS) {
160 		printf("Exports list on %s:\n", host);
161 		exp = exports;
162 		while (exp) {
163 			printf("%-35s", exp->ex_dirp);
164 			grp = exp->ex_groups;
165 			if (grp == NULL) {
166 				printf("Everyone\n");
167 			} else {
168 				while (grp) {
169 					printf("%s ", grp->gr_name);
170 					grp = grp->gr_next;
171 				}
172 				printf("\n");
173 			}
174 			exp = exp->ex_next;
175 		}
176 	}
177 }
178 
179 /*
180  * Xdr routine for retrieving the mount dump list
181  */
182 xdr_mntdump(xdrsp, mlp)
183 	XDR *xdrsp;
184 	struct mountlist **mlp;
185 {
186 	register struct mountlist *mp;
187 	register struct mountlist *tp;
188 	register struct mountlist **otp;
189 	int val, val2;
190 	int bool;
191 	char *strp;
192 
193 	*mlp = (struct mountlist *)0;
194 	if (!xdr_bool(xdrsp, &bool))
195 		return (0);
196 	while (bool) {
197 		mp = (struct mountlist *)malloc(sizeof(struct mountlist));
198 		if (mp == NULL)
199 			return (0);
200 		mp->ml_left = mp->ml_right = (struct mountlist *)0;
201 		strp = mp->ml_host;
202 		if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN))
203 			return (0);
204 		strp = mp->ml_dirp;
205 		if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
206 			return (0);
207 
208 		/*
209 		 * Build a binary tree on sorted order of either host or dirp.
210 		 * Drop any duplications.
211 		 */
212 		if (*mlp == NULL) {
213 			*mlp = mp;
214 		} else {
215 			tp = *mlp;
216 			while (tp) {
217 				val = strcmp(mp->ml_host, tp->ml_host);
218 				val2 = strcmp(mp->ml_dirp, tp->ml_dirp);
219 				switch (type) {
220 				case ALL:
221 					if (val == 0) {
222 						if (val2 == 0) {
223 							free((caddr_t)mp);
224 							goto next;
225 						}
226 						val = val2;
227 					}
228 					break;
229 				case DIRS:
230 					if (val2 == 0) {
231 						free((caddr_t)mp);
232 						goto next;
233 					}
234 					val = val2;
235 					break;
236 				default:
237 					if (val == 0) {
238 						free((caddr_t)mp);
239 						goto next;
240 					}
241 					break;
242 				};
243 				if (val < 0) {
244 					otp = &tp->ml_left;
245 					tp = tp->ml_left;
246 				} else {
247 					otp = &tp->ml_right;
248 					tp = tp->ml_right;
249 				}
250 			}
251 			*otp = mp;
252 		}
253 next:
254 		if (!xdr_bool(xdrsp, &bool))
255 			return (0);
256 	}
257 	return (1);
258 }
259 
260 /*
261  * Xdr routine to retrieve exports list
262  */
263 xdr_exports(xdrsp, exp)
264 	XDR *xdrsp;
265 	struct exportslist **exp;
266 {
267 	register struct exportslist *ep;
268 	register struct grouplist *gp;
269 	int bool, grpbool;
270 	char *strp;
271 
272 	*exp = (struct exportslist *)0;
273 	if (!xdr_bool(xdrsp, &bool))
274 		return (0);
275 	while (bool) {
276 		ep = (struct exportslist *)malloc(sizeof(struct exportslist));
277 		if (ep == NULL)
278 			return (0);
279 		ep->ex_groups = (struct grouplist *)0;
280 		strp = ep->ex_dirp;
281 		if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
282 			return (0);
283 		if (!xdr_bool(xdrsp, &grpbool))
284 			return (0);
285 		while (grpbool) {
286 			gp = (struct grouplist *)malloc(sizeof(struct grouplist));
287 			if (gp == NULL)
288 				return (0);
289 			strp = gp->gr_name;
290 			if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN))
291 				return (0);
292 			gp->gr_next = ep->ex_groups;
293 			ep->ex_groups = gp;
294 			if (!xdr_bool(xdrsp, &grpbool))
295 				return (0);
296 		}
297 		ep->ex_next = *exp;
298 		*exp = ep;
299 		if (!xdr_bool(xdrsp, &bool))
300 			return (0);
301 	}
302 	return (1);
303 }
304 
305 static
306 usage()
307 {
308 	fprintf(stderr, "Usage: showmount [-ade] host\n");
309 	exit(1);
310 }
311 
312 /*
313  * Print the binary tree in inorder so that output is sorted.
314  */
315 print_dump(mp)
316 	struct mountlist *mp;
317 {
318 
319 	if (mp == NULL)
320 		return;
321 	if (mp->ml_left)
322 		print_dump(mp->ml_left);
323 	switch (type) {
324 	case ALL:
325 		printf("%s:%s\n", mp->ml_host, mp->ml_dirp);
326 		break;
327 	case DIRS:
328 		printf("%s\n", mp->ml_dirp);
329 		break;
330 	default:
331 		printf("%s\n", mp->ml_host);
332 		break;
333 	};
334 	if (mp->ml_right)
335 		print_dump(mp->ml_right);
336 }
337