1 /* $NetBSD: showmount.c,v 1.23 2018/01/09 03:31:15 christos 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.23 2018/01/09 03:31:15 christos 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 len; 118 int nbytes; 119 char strvised[1024 * 4 + 1]; 120 121 while ((ch = getopt(argc, argv, "adEe3")) != -1) 122 switch((char)ch) { 123 case 'a': 124 if (type == 0) { 125 type = ALL; 126 rpcs |= DODUMP; 127 } else 128 usage(); 129 break; 130 case 'd': 131 if (type == 0) { 132 type = DIRS; 133 rpcs |= DODUMP; 134 } else 135 usage(); 136 break; 137 case 'E': 138 rpcs |= DOPARSABLEEXPORTS; 139 break; 140 case 'e': 141 rpcs |= DOEXPORTS; 142 break; 143 case '3': 144 mntvers = 3; 145 break; 146 case '?': 147 default: 148 usage(); 149 } 150 argc -= optind; 151 argv += optind; 152 153 if ((rpcs & DOPARSABLEEXPORTS) != 0) { 154 if ((rpcs & DOEXPORTS) != 0) 155 errx(1, "-E cannot be used with -e"); 156 if ((rpcs & DODUMP) != 0) 157 errx(1, "-E cannot be used with -a or -d"); 158 } 159 160 if (argc > 0) 161 host = *argv; 162 else 163 host = "localhost"; 164 165 if (rpcs == 0) 166 rpcs = DODUMP; 167 168 if (rpcs & DODUMP) 169 if ((estat = tcp_callrpc(host, RPCPROG_MNT, mntvers, 170 RPCMNT_DUMP, (xdrproc_t)xdr_void, NULL, 171 (xdrproc_t)xdr_mntdump, (char *)&mntdump)) != 0) { 172 fprintf(stderr, "showmount: Can't do Mountdump rpc: "); 173 clnt_perrno(estat); 174 exit(1); 175 } 176 if (rpcs & (DOEXPORTS | DOPARSABLEEXPORTS)) 177 if ((estat = tcp_callrpc(host, RPCPROG_MNT, mntvers, 178 RPCMNT_EXPORT, (xdrproc_t)xdr_void, NULL, 179 (xdrproc_t)xdr_exports, (char *)&exports)) != 0) { 180 fprintf(stderr, "showmount: Can't do Exports rpc: "); 181 clnt_perrno(estat); 182 exit(1); 183 } 184 185 /* Now just print out the results */ 186 if (rpcs & DODUMP) { 187 switch (type) { 188 case ALL: 189 printf("All mount points on %s:\n", host); 190 break; 191 case DIRS: 192 printf("Directories on %s:\n", host); 193 break; 194 default: 195 printf("Hosts on %s:\n", host); 196 break; 197 }; 198 print_dump(mntdump); 199 } 200 if (rpcs & DOEXPORTS) { 201 printf("Exports list on %s:\n", host); 202 exp = exports; 203 while (exp) { 204 len = printf("%-35s", exp->ex_dirp); 205 if (len > 35) 206 printf("\t"); 207 grp = exp->ex_groups; 208 if (grp == NULL) { 209 printf("Everyone\n"); 210 } else { 211 while (grp) { 212 printf("%s ", grp->gr_name); 213 grp = grp->gr_next; 214 } 215 printf("\n"); 216 } 217 exp = exp->ex_next; 218 } 219 } 220 if (rpcs & DOPARSABLEEXPORTS) { 221 exp = exports; 222 while (exp) { 223 nbytes = strnvis(strvised, sizeof(strvised), 224 exp->ex_dirp, VIS_GLOB | VIS_NL); 225 if (nbytes == -1) 226 err(1, "strsnvis"); 227 printf("%s\n", strvised); 228 exp = exp->ex_next; 229 } 230 } 231 exit(0); 232 } 233 234 /* 235 * tcp_callrpc has the same interface as callrpc, but tries to 236 * use tcp as transport method in order to handle large replies. 237 */ 238 239 static int 240 tcp_callrpc(const char *host, int prognum, int versnum, int procnum, 241 xdrproc_t inproc, char *in, xdrproc_t outproc, char *out) 242 { 243 CLIENT *client; 244 struct timeval timeout; 245 int rval; 246 247 if ((client = clnt_create(host, prognum, versnum, "tcp")) == NULL && 248 (client = clnt_create(host, prognum, versnum, "udp")) == NULL) 249 return ((int) rpc_createerr.cf_stat); 250 251 timeout.tv_sec = 25; 252 timeout.tv_usec = 0; 253 rval = (int) clnt_call(client, procnum, 254 inproc, in, 255 outproc, out, 256 timeout); 257 clnt_destroy(client); 258 return rval; 259 } 260 261 static void 262 mountlist_free(struct mountlist *ml) 263 { 264 if (ml == NULL) 265 return; 266 mountlist_free(ml->ml_left); 267 mountlist_free(ml->ml_right); 268 free(ml); 269 } 270 271 /* 272 * Xdr routine for retrieving the mount dump list 273 */ 274 static int 275 xdr_mntdump(XDR *xdrsp, struct mountlist **mlp) 276 { 277 struct mountlist *mp, **otp, *tp; 278 int bool_int, val, val2; 279 char *strp; 280 281 otp = NULL; 282 *mlp = NULL; 283 if (!xdr_bool(xdrsp, &bool_int)) 284 return 0; 285 while (bool_int) { 286 mp = malloc(sizeof(*mp)); 287 if (mp == NULL) 288 goto out; 289 mp->ml_left = mp->ml_right = NULL; 290 strp = mp->ml_host; 291 if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) { 292 free(mp); 293 goto out; 294 } 295 strp = mp->ml_dirp; 296 if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) { 297 free(mp); 298 goto out; 299 } 300 301 /* 302 * Build a binary tree on sorted order of either host or dirp. 303 * Drop any duplications. 304 */ 305 if (*mlp == NULL) { 306 *mlp = mp; 307 } else { 308 tp = *mlp; 309 while (tp) { 310 val = strcmp(mp->ml_host, tp->ml_host); 311 val2 = strcmp(mp->ml_dirp, tp->ml_dirp); 312 switch (type) { 313 case ALL: 314 if (val == 0) { 315 if (val2 == 0) { 316 free(mp); 317 goto next; 318 } 319 val = val2; 320 } 321 break; 322 case DIRS: 323 if (val2 == 0) { 324 free(mp); 325 goto next; 326 } 327 val = val2; 328 break; 329 default: 330 if (val == 0) { 331 free(mp); 332 goto next; 333 } 334 break; 335 }; 336 if (val < 0) { 337 otp = &tp->ml_left; 338 tp = tp->ml_left; 339 } else { 340 otp = &tp->ml_right; 341 tp = tp->ml_right; 342 } 343 } 344 *otp = mp; 345 } 346 next: 347 if (!xdr_bool(xdrsp, &bool_int)) 348 goto out; 349 } 350 return 1; 351 out: 352 mountlist_free(*mlp); 353 return 0; 354 } 355 356 static void 357 grouplist_free(struct grouplist *gp) 358 { 359 if (gp == NULL) 360 return; 361 grouplist_free(gp->gr_next); 362 free(gp); 363 } 364 365 static void 366 exportslist_free(struct exportslist *ep) 367 { 368 if (ep == NULL) 369 return; 370 exportslist_free(ep->ex_next); 371 grouplist_free(ep->ex_groups); 372 free(ep); 373 } 374 375 /* 376 * Xdr routine to retrieve exports list 377 */ 378 static int 379 xdr_exports(XDR *xdrsp, struct exportslist **exp) 380 { 381 struct exportslist *ep = NULL; 382 struct grouplist *gp; 383 int bool_int, grpbool; 384 char *strp; 385 386 *exp = NULL; 387 if (!xdr_bool(xdrsp, &bool_int)) 388 return 0; 389 while (bool_int) { 390 ep = malloc(sizeof(*ep)); 391 if (ep == NULL) 392 goto out; 393 ep->ex_groups = NULL; 394 strp = ep->ex_dirp; 395 if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 396 goto out; 397 if (!xdr_bool(xdrsp, &grpbool)) 398 goto out; 399 while (grpbool) { 400 gp = malloc(sizeof(*gp)); 401 if (gp == NULL) 402 goto out; 403 gp->gr_next = ep->ex_groups; 404 ep->ex_groups = gp; 405 strp = gp->gr_name; 406 if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) 407 goto out; 408 if (!xdr_bool(xdrsp, &grpbool)) 409 goto out; 410 } 411 ep->ex_next = *exp; 412 *exp = ep; 413 ep = NULL; 414 if (!xdr_bool(xdrsp, &bool_int)) 415 goto out; 416 } 417 return 1; 418 out: 419 exportslist_free(ep); 420 exportslist_free(*exp); 421 return 0; 422 } 423 424 static void 425 usage(void) 426 { 427 428 fprintf(stderr, "usage: showmount [-ade3] host\n"); 429 exit(1); 430 } 431 432 /* 433 * Print the binary tree in inorder so that output is sorted. 434 */ 435 static void 436 print_dump(struct mountlist *mp) 437 { 438 439 if (mp == NULL) 440 return; 441 if (mp->ml_left) 442 print_dump(mp->ml_left); 443 switch (type) { 444 case ALL: 445 printf("%s:%s\n", mp->ml_host, mp->ml_dirp); 446 break; 447 case DIRS: 448 printf("%s\n", mp->ml_dirp); 449 break; 450 default: 451 printf("%s\n", mp->ml_host); 452 break; 453 }; 454 if (mp->ml_right) 455 print_dump(mp->ml_right); 456 } 457