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