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 43static 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 73struct 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 80struct grouplist { 81 struct grouplist *gr_next; 82 char gr_name[RPCMNT_NAMELEN+1]; 83}; 84 85struct exportslist { 86 struct exportslist *ex_next; 87 struct grouplist *ex_groups; 88 char ex_dirp[RPCMNT_PATHLEN+1]; 89}; 90 91static struct mountlist *mntdump; 92static struct exportslist *exports; 93static int type = 0; 94 95static void print_dump(struct mountlist *); 96__dead static void usage(void); 97static int xdr_mntdump(XDR *, struct mountlist **); 98static int xdr_exports(XDR *, struct exportslist **); 99static 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 */ 109int 110main(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 239static int 240tcp_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 261static void 262mountlist_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 */ 274static int 275xdr_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 } 346next: 347 if (!xdr_bool(xdrsp, &bool_int)) 348 goto out; 349 } 350 return 1; 351out: 352 mountlist_free(*mlp); 353 return 0; 354} 355 356static void 357grouplist_free(struct grouplist *gp) 358{ 359 if (gp == NULL) 360 return; 361 grouplist_free(gp->gr_next); 362 free(gp); 363} 364 365static void 366exportslist_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 */ 378static int 379xdr_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; 418out: 419 exportslist_free(ep); 420 exportslist_free(*exp); 421 return 0; 422} 423 424static void 425usage(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 */ 435static void 436print_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