1 /* $OpenBSD: showmount.c,v 1.24 2022/01/28 06:18:42 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 its mount list and/or
87 * its 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
main(int argc,char * argv[])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
xdr_mntdump(XDR * xdrsp,struct mountlist ** mlp)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
xdr_exports(XDR * xdrsp,struct exportslist ** exp)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
usage(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
print_dump(struct mountlist * mp)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