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