Home | History | Annotate | Line # | Download | only in showmount
      1 /*	$NetBSD: showmount.c,v 1.25 2025/06/05 08:08:41 bad Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1989, 1993, 1995
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * This code is derived from software contributed to Berkeley by
      8  * Rick Macklem at The University of Guelph.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. Neither the name of the University nor the names of its contributors
     19  *    may be used to endorse or promote products derived from this software
     20  *    without specific prior written permission.
     21  *
     22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     32  * SUCH DAMAGE.
     33  */
     34 
     35 #include <sys/cdefs.h>
     36 #ifndef lint
     37 __COPYRIGHT("@(#) Copyright (c) 1989, 1993, 1995\
     38  The Regents of the University of California.  All rights reserved.");
     39 #endif /* not lint */
     40 
     41 #ifndef lint
     42 #if 0
     43 static char sccsid[] = "@(#)showmount.c	8.3 (Berkeley) 3/29/95";
     44 #endif
     45 __RCSID("$NetBSD: showmount.c,v 1.25 2025/06/05 08:08:41 bad Exp $");
     46 #endif /* not lint */
     47 
     48 #include <sys/types.h>
     49 #include <sys/file.h>
     50 #include <sys/socket.h>
     51 
     52 #include <netdb.h>
     53 #include <rpc/rpc.h>
     54 #include <rpc/pmap_clnt.h>
     55 #include <rpc/pmap_prot.h>
     56 #include <nfs/rpcv2.h>
     57 
     58 #include <stdio.h>
     59 #include <stdlib.h>
     60 #include <string.h>
     61 #include <unistd.h>
     62 #include <err.h>
     63 #include <vis.h>
     64 
     65 /* Constant defs */
     66 #define	ALL	1
     67 #define	DIRS	2
     68 
     69 #define	DODUMP		0x1
     70 #define	DOEXPORTS	0x2
     71 #define	DOPARSABLEEXPORTS	0x4
     72 
     73 struct mountlist {
     74 	struct mountlist *ml_left;
     75 	struct mountlist *ml_right;
     76 	char	ml_host[RPCMNT_NAMELEN+1];
     77 	char	ml_dirp[RPCMNT_PATHLEN+1];
     78 };
     79 
     80 struct grouplist {
     81 	struct grouplist *gr_next;
     82 	char	gr_name[RPCMNT_NAMELEN+1];
     83 };
     84 
     85 struct exportslist {
     86 	struct exportslist *ex_next;
     87 	struct grouplist *ex_groups;
     88 	char	ex_dirp[RPCMNT_PATHLEN+1];
     89 };
     90 
     91 static struct mountlist *mntdump;
     92 static struct exportslist *exports;
     93 static int type = 0;
     94 
     95 static void	print_dump(struct mountlist *);
     96 __dead static void	usage(void);
     97 static int	xdr_mntdump(XDR *, struct mountlist **);
     98 static int	xdr_exports(XDR *, struct exportslist **);
     99 static int	tcp_callrpc(const char *host, int prognum, int versnum,
    100     int procnum, xdrproc_t inproc, char *in, xdrproc_t outproc, char *out);
    101 
    102 /*
    103  * This command queries the NFS mount daemon for its mount list and/or
    104  * its exports list and prints them out.
    105  * See "NFS: Network File System Protocol Specification, RFC1094, Appendix A"
    106  * and the "Network File System Protocol XXX.."
    107  * for detailed information on the protocol.
    108  */
    109 int
    110 main(int argc, char **argv)
    111 {
    112 	struct exportslist *exp;
    113 	struct grouplist *grp;
    114 	int estat, rpcs = 0, mntvers = 1;
    115 	const char *host;
    116 	int ch;
    117 	int nbytes;
    118 	char strvised[1024 * 4 + 1];
    119 
    120 	while ((ch = getopt(argc, argv, "adEe3")) != -1)
    121 		switch((char)ch) {
    122 		case 'a':
    123 			if (type == 0) {
    124 				type = ALL;
    125 				rpcs |= DODUMP;
    126 			} else
    127 				usage();
    128 			break;
    129 		case 'd':
    130 			if (type == 0) {
    131 				type = DIRS;
    132 				rpcs |= DODUMP;
    133 			} else
    134 				usage();
    135 			break;
    136 		case 'E':
    137 			rpcs |= DOPARSABLEEXPORTS;
    138 			break;
    139 		case 'e':
    140 			rpcs |= DOEXPORTS;
    141 			break;
    142 		case '3':
    143 			mntvers = 3;
    144 			break;
    145 		case '?':
    146 		default:
    147 			usage();
    148 		}
    149 	argc -= optind;
    150 	argv += optind;
    151 
    152 	if ((rpcs & DOPARSABLEEXPORTS) != 0) {
    153 		if ((rpcs & DOEXPORTS) != 0)
    154 			errx(1, "-E cannot be used with -e");
    155 		if ((rpcs & DODUMP) != 0)
    156 			errx(1, "-E cannot be used with -a or -d");
    157 	}
    158 
    159 	if (argc > 0)
    160 		host = *argv;
    161 	else
    162 		host = "localhost";
    163 
    164 	if (rpcs == 0)
    165 		rpcs = DODUMP;
    166 
    167 	if (rpcs & DODUMP)
    168 		if ((estat = tcp_callrpc(host, RPCPROG_MNT, mntvers,
    169 			 RPCMNT_DUMP, (xdrproc_t)xdr_void, NULL,
    170 			 (xdrproc_t)xdr_mntdump, (char *)&mntdump)) != 0) {
    171 			fprintf(stderr, "showmount: Can't do Mountdump rpc: ");
    172 			clnt_perrno(estat);
    173 			exit(1);
    174 		}
    175 	if (rpcs & (DOEXPORTS | DOPARSABLEEXPORTS))
    176 		if ((estat = tcp_callrpc(host, RPCPROG_MNT, mntvers,
    177 			 RPCMNT_EXPORT, (xdrproc_t)xdr_void, NULL,
    178 			 (xdrproc_t)xdr_exports, (char *)&exports)) != 0) {
    179 			fprintf(stderr, "showmount: Can't do Exports rpc: ");
    180 			clnt_perrno(estat);
    181 			exit(1);
    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 		printf("Exports list on %s:\n", host);
    201 		exp = exports;
    202 		while (exp) {
    203 			printf("%-34s ", exp->ex_dirp);
    204 			grp = exp->ex_groups;
    205 			if (grp == NULL) {
    206 				printf("Everyone\n");
    207 			} else {
    208 				while (grp) {
    209 					printf("%s ", grp->gr_name);
    210 					grp = grp->gr_next;
    211 				}
    212 				printf("\n");
    213 			}
    214 			exp = exp->ex_next;
    215 		}
    216 	}
    217 	if (rpcs & DOPARSABLEEXPORTS) {
    218 		exp = exports;
    219 		while (exp) {
    220 			nbytes = strnvis(strvised, sizeof(strvised),
    221 			    exp->ex_dirp, VIS_GLOB | VIS_NL);
    222 			if (nbytes == -1)
    223 				err(1, "strsnvis");
    224 			printf("%s\n", strvised);
    225 			exp = exp->ex_next;
    226 		}
    227 	}
    228 	exit(0);
    229 }
    230 
    231 /*
    232  * tcp_callrpc has the same interface as callrpc, but tries to
    233  * use tcp as transport method in order to handle large replies.
    234  */
    235 
    236 static int
    237 tcp_callrpc(const char *host, int prognum, int versnum, int procnum,
    238     xdrproc_t inproc, char *in, xdrproc_t outproc, char *out)
    239 {
    240 	CLIENT *client;
    241 	struct timeval timeout;
    242 	int rval;
    243 
    244 	if ((client = clnt_create(host, prognum, versnum, "tcp")) == NULL &&
    245 	    (client = clnt_create(host, prognum, versnum, "udp")) == NULL)
    246 		return ((int) rpc_createerr.cf_stat);
    247 
    248 	timeout.tv_sec = 25;
    249 	timeout.tv_usec = 0;
    250 	rval = (int) clnt_call(client, procnum,
    251 			       inproc, in,
    252 			       outproc, out,
    253 			       timeout);
    254 	clnt_destroy(client);
    255  	return rval;
    256 }
    257 
    258 static void
    259 mountlist_free(struct mountlist *ml)
    260 {
    261 	if (ml == NULL)
    262 		return;
    263 	mountlist_free(ml->ml_left);
    264 	mountlist_free(ml->ml_right);
    265 	free(ml);
    266 }
    267 
    268 /*
    269  * Xdr routine for retrieving the mount dump list
    270  */
    271 static int
    272 xdr_mntdump(XDR *xdrsp, struct mountlist **mlp)
    273 {
    274 	struct mountlist *mp, **otp, *tp;
    275 	int bool_int, val, val2;
    276 	char *strp;
    277 
    278 	otp = NULL;
    279 	*mlp = NULL;
    280 	if (!xdr_bool(xdrsp, &bool_int))
    281 		return 0;
    282 	while (bool_int) {
    283 		mp = malloc(sizeof(*mp));
    284 		if (mp == NULL)
    285 			goto out;
    286 		mp->ml_left = mp->ml_right = NULL;
    287 		strp = mp->ml_host;
    288 		if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) {
    289 			free(mp);
    290 			goto out;
    291 		}
    292 		strp = mp->ml_dirp;
    293 		if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) {
    294 			free(mp);
    295 			goto out;
    296 		}
    297 
    298 		/*
    299 		 * Build a binary tree on sorted order of either host or dirp.
    300 		 * Drop any duplications.
    301 		 */
    302 		if (*mlp == NULL) {
    303 			*mlp = mp;
    304 		} else {
    305 			tp = *mlp;
    306 			while (tp) {
    307 				val = strcmp(mp->ml_host, tp->ml_host);
    308 				val2 = strcmp(mp->ml_dirp, tp->ml_dirp);
    309 				switch (type) {
    310 				case ALL:
    311 					if (val == 0) {
    312 						if (val2 == 0) {
    313 							free(mp);
    314 							goto next;
    315 						}
    316 						val = val2;
    317 					}
    318 					break;
    319 				case DIRS:
    320 					if (val2 == 0) {
    321 						free(mp);
    322 						goto next;
    323 					}
    324 					val = val2;
    325 					break;
    326 				default:
    327 					if (val == 0) {
    328 						free(mp);
    329 						goto next;
    330 					}
    331 					break;
    332 				};
    333 				if (val < 0) {
    334 					otp = &tp->ml_left;
    335 					tp = tp->ml_left;
    336 				} else {
    337 					otp = &tp->ml_right;
    338 					tp = tp->ml_right;
    339 				}
    340 			}
    341 			*otp = mp;
    342 		}
    343 next:
    344 		if (!xdr_bool(xdrsp, &bool_int))
    345 			goto out;
    346 	}
    347 	return 1;
    348 out:
    349 	mountlist_free(*mlp);
    350 	return 0;
    351 }
    352 
    353 static void
    354 grouplist_free(struct grouplist *gp)
    355 {
    356 	if (gp == NULL)
    357 		return;
    358 	grouplist_free(gp->gr_next);
    359 	free(gp);
    360 }
    361 
    362 static void
    363 exportslist_free(struct exportslist *ep)
    364 {
    365 	if (ep == NULL)
    366 		return;
    367 	exportslist_free(ep->ex_next);
    368 	grouplist_free(ep->ex_groups);
    369 	free(ep);
    370 }
    371 
    372 /*
    373  * Xdr routine to retrieve exports list
    374  */
    375 static int
    376 xdr_exports(XDR *xdrsp, struct exportslist **exp)
    377 {
    378 	struct exportslist *ep = NULL;
    379 	struct grouplist *gp;
    380 	int bool_int, grpbool;
    381 	char *strp;
    382 
    383 	*exp = NULL;
    384 	if (!xdr_bool(xdrsp, &bool_int))
    385 		return 0;
    386 	while (bool_int) {
    387 		ep = malloc(sizeof(*ep));
    388 		if (ep == NULL)
    389 			goto out;
    390 		ep->ex_groups = NULL;
    391 		strp = ep->ex_dirp;
    392 		if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
    393 			goto out;
    394 		if (!xdr_bool(xdrsp, &grpbool))
    395 			goto out;
    396 		while (grpbool) {
    397 			gp = malloc(sizeof(*gp));
    398 			if (gp == NULL)
    399 				goto out;
    400 			gp->gr_next = ep->ex_groups;
    401 			ep->ex_groups = gp;
    402 			strp = gp->gr_name;
    403 			if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN))
    404 				goto out;
    405 			if (!xdr_bool(xdrsp, &grpbool))
    406 				goto out;
    407 		}
    408 		ep->ex_next = *exp;
    409 		*exp = ep;
    410 		ep = NULL;
    411 		if (!xdr_bool(xdrsp, &bool_int))
    412 			goto out;
    413 	}
    414 	return 1;
    415 out:
    416 	exportslist_free(ep);
    417 	exportslist_free(*exp);
    418 	return 0;
    419 }
    420 
    421 static void
    422 usage(void)
    423 {
    424 
    425 	fprintf(stderr, "usage: showmount [-ade3] host\n");
    426 	exit(1);
    427 }
    428 
    429 /*
    430  * Print the binary tree in inorder so that output is sorted.
    431  */
    432 static void
    433 print_dump(struct mountlist *mp)
    434 {
    435 
    436 	if (mp == NULL)
    437 		return;
    438 	if (mp->ml_left)
    439 		print_dump(mp->ml_left);
    440 	switch (type) {
    441 	case ALL:
    442 		printf("%s:%s\n", mp->ml_host, mp->ml_dirp);
    443 		break;
    444 	case DIRS:
    445 		printf("%s\n", mp->ml_dirp);
    446 		break;
    447 	default:
    448 		printf("%s\n", mp->ml_host);
    449 		break;
    450 	};
    451 	if (mp->ml_right)
    452 		print_dump(mp->ml_right);
    453 }
    454