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
58struct 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
65struct grouplist {
66	struct grouplist *gr_next;
67	char	gr_name[RPCMNT_NAMELEN+1];
68};
69
70struct exportslist {
71	struct exportslist *ex_next;
72	struct grouplist *ex_groups;
73	char	ex_dirp[RPCMNT_PATHLEN+1];
74};
75
76static struct mountlist *mntdump;
77static struct exportslist *exports;
78static int type = 0;
79
80void	print_dump(struct mountlist *);
81void	usage(void);
82int	xdr_mntdump(XDR *, struct mountlist **);
83int	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 */
92int
93main(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 */
230int
231xdr_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		}
297next:
298		if (!xdr_bool(xdrsp, &bool))
299			return (0);
300	}
301	return (1);
302}
303
304/*
305 * Xdr routine to retrieve exports list
306 */
307int
308xdr_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
348void
349usage(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 */
359void
360print_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