1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 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/types.h> 36 #include <sys/queue.h> 37 #include <sys/file.h> 38 #include <sys/socket.h> 39 #include <sys/socketvar.h> 40 41 #include <err.h> 42 #include <getopt.h> 43 #include <netdb.h> 44 #include <rpc/rpc.h> 45 #include <rpc/pmap_clnt.h> 46 #include <rpc/pmap_prot.h> 47 #include <rpcsvc/mount.h> 48 49 #include <stdio.h> 50 #include <stdlib.h> 51 #include <string.h> 52 #include <unistd.h> 53 #include <vis.h> 54 55 /* Constant defs */ 56 #define ALL 1 57 #define DIRS 2 58 59 #define DODUMP 0x1 60 #define DOEXPORTS 0x2 61 #define DOPARSABLEEXPORTS 0x4 62 63 struct mountlist { 64 struct mountlist *ml_left; 65 struct mountlist *ml_right; 66 char ml_host[MNTNAMLEN+1]; 67 char ml_dirp[MNTPATHLEN+1]; 68 }; 69 70 struct grouplist { 71 struct grouplist *gr_next; 72 char gr_name[MNTNAMLEN+1]; 73 }; 74 75 struct exportslist { 76 struct exportslist *ex_next; 77 struct grouplist *ex_groups; 78 char ex_dirp[MNTPATHLEN+1]; 79 }; 80 81 static struct mountlist *mntdump; 82 static struct exportslist *exportslist; 83 static int type = 0; 84 85 void print_dump(struct mountlist *); 86 static void usage(void) __dead2; 87 int xdr_mntdump(XDR *, struct mountlist **); 88 int xdr_exportslist(XDR *, struct exportslist **); 89 int tcp_callrpc(const char *host, int prognum, int versnum, int procnum, 90 xdrproc_t inproc, char *in, xdrproc_t outproc, char *out); 91 92 static const struct option long_opts[] = { 93 { "all", no_argument, NULL, 'a' }, 94 { "directories", no_argument, NULL, 'd' }, 95 { "exports-script", no_argument, NULL, 'E' }, 96 { "exports", no_argument, NULL, 'e' }, 97 { NULL, 0, NULL, 0 }, 98 }; 99 100 /* 101 * This command queries the NFS mount daemon for it's mount list and/or 102 * it's exports list and prints them out. 103 * See "NFS: Network File System Protocol Specification, RFC1094, Appendix A" 104 * and the "Network File System Protocol XXX.." 105 * for detailed information on the protocol. 106 */ 107 int 108 main(int argc, char **argv) 109 { 110 char strvised[MNTPATHLEN * 4 + 1]; 111 register struct exportslist *exp; 112 register struct grouplist *grp; 113 register int rpcs = 0, mntvers = 3; 114 const char *host; 115 int ch, estat, nbytes; 116 117 while ((ch = getopt_long(argc, argv, "+adEe13", long_opts, NULL)) != -1) 118 switch (ch) { 119 case 'a': 120 if (type == 0) { 121 type = ALL; 122 rpcs |= DODUMP; 123 } else 124 usage(); 125 break; 126 case 'd': 127 if (type == 0) { 128 type = DIRS; 129 rpcs |= DODUMP; 130 } else 131 usage(); 132 break; 133 case 'E': 134 rpcs |= DOPARSABLEEXPORTS; 135 break; 136 case 'e': 137 rpcs |= DOEXPORTS; 138 break; 139 case '1': 140 mntvers = 1; 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, MOUNTPROG, mntvers, 169 MOUNTPROC_DUMP, (xdrproc_t)xdr_void, (char *)0, 170 (xdrproc_t)xdr_mntdump, (char *)&mntdump)) != 0) { 171 clnt_perrno(estat); 172 errx(1, "can't do mountdump rpc"); 173 } 174 if (rpcs & (DOEXPORTS | DOPARSABLEEXPORTS)) 175 if ((estat = tcp_callrpc(host, MOUNTPROG, mntvers, 176 MOUNTPROC_EXPORT, (xdrproc_t)xdr_void, (char *)0, 177 (xdrproc_t)xdr_exportslist, (char *)&exportslist)) != 0) { 178 clnt_perrno(estat); 179 errx(1, "can't do exports rpc"); 180 } 181 182 /* Now just print out the results */ 183 if (rpcs & DODUMP) { 184 switch (type) { 185 case ALL: 186 printf("All mount points on %s:\n", host); 187 break; 188 case DIRS: 189 printf("Directories on %s:\n", host); 190 break; 191 default: 192 printf("Hosts on %s:\n", host); 193 break; 194 } 195 print_dump(mntdump); 196 } 197 if (rpcs & DOEXPORTS) { 198 printf("Exports list on %s:\n", host); 199 exp = exportslist; 200 while (exp) { 201 printf("%-34s ", exp->ex_dirp); 202 grp = exp->ex_groups; 203 if (grp == NULL) { 204 printf("Everyone\n"); 205 } else { 206 while (grp) { 207 printf("%s ", grp->gr_name); 208 grp = grp->gr_next; 209 } 210 printf("\n"); 211 } 212 exp = exp->ex_next; 213 } 214 } 215 if (rpcs & DOPARSABLEEXPORTS) { 216 exp = exportslist; 217 while (exp) { 218 nbytes = strsnvis(strvised, sizeof(strvised), 219 exp->ex_dirp, VIS_GLOB | VIS_NL, "\"'$"); 220 if (nbytes == -1) 221 err(1, "strsnvis"); 222 printf("%s\n", strvised); 223 exp = exp->ex_next; 224 } 225 } 226 exit(0); 227 } 228 229 /* 230 * tcp_callrpc has the same interface as callrpc, but tries to 231 * use tcp as transport method in order to handle large replies. 232 */ 233 int 234 tcp_callrpc(const char *host, int prognum, int versnum, int procnum, 235 xdrproc_t inproc, char *in, xdrproc_t outproc, char *out) 236 { 237 CLIENT *client; 238 struct timeval timeout; 239 int rval; 240 241 if ((client = clnt_create(host, prognum, versnum, "tcp")) == NULL && 242 (client = clnt_create(host, prognum, versnum, "udp")) == NULL) 243 return ((int) rpc_createerr.cf_stat); 244 245 timeout.tv_sec = 25; 246 timeout.tv_usec = 0; 247 rval = (int) clnt_call(client, procnum, 248 inproc, in, 249 outproc, out, 250 timeout); 251 clnt_destroy(client); 252 return rval; 253 } 254 255 /* 256 * Xdr routine for retrieving the mount dump list 257 */ 258 int 259 xdr_mntdump(XDR *xdrsp, struct mountlist **mlp) 260 { 261 register struct mountlist *mp; 262 register struct mountlist *tp; 263 register struct mountlist **otp; 264 int val, val2; 265 int bool; 266 char *strp; 267 268 *mlp = (struct mountlist *)0; 269 if (!xdr_bool(xdrsp, &bool)) 270 return (0); 271 while (bool) { 272 mp = (struct mountlist *)malloc(sizeof(struct mountlist)); 273 if (mp == NULL) 274 return (0); 275 mp->ml_left = mp->ml_right = (struct mountlist *)0; 276 strp = mp->ml_host; 277 if (!xdr_string(xdrsp, &strp, MNTNAMLEN)) { 278 free(mp); 279 return (0); 280 } 281 strp = mp->ml_dirp; 282 if (!xdr_string(xdrsp, &strp, MNTPATHLEN)) { 283 free(mp); 284 return (0); 285 } 286 287 /* 288 * Build a binary tree on sorted order of either host or dirp. 289 * Drop any duplications. 290 */ 291 if (*mlp == NULL) { 292 *mlp = mp; 293 } else { 294 tp = *mlp; 295 while (tp) { 296 val = strcmp(mp->ml_host, tp->ml_host); 297 val2 = strcmp(mp->ml_dirp, tp->ml_dirp); 298 switch (type) { 299 case ALL: 300 if (val == 0) { 301 if (val2 == 0) { 302 free((caddr_t)mp); 303 goto next; 304 } 305 val = val2; 306 } 307 break; 308 case DIRS: 309 if (val2 == 0) { 310 free((caddr_t)mp); 311 goto next; 312 } 313 val = val2; 314 break; 315 default: 316 if (val == 0) { 317 free((caddr_t)mp); 318 goto next; 319 } 320 break; 321 } 322 if (val < 0) { 323 otp = &tp->ml_left; 324 tp = tp->ml_left; 325 } else { 326 otp = &tp->ml_right; 327 tp = tp->ml_right; 328 } 329 } 330 *otp = mp; 331 } 332 next: 333 if (!xdr_bool(xdrsp, &bool)) 334 return (0); 335 } 336 return (1); 337 } 338 339 /* 340 * Xdr routine to retrieve exports list 341 */ 342 int 343 xdr_exportslist(XDR *xdrsp, struct exportslist **exp) 344 { 345 register struct exportslist *ep; 346 register struct grouplist *gp; 347 int bool, grpbool; 348 char *strp; 349 350 *exp = (struct exportslist *)0; 351 if (!xdr_bool(xdrsp, &bool)) 352 return (0); 353 while (bool) { 354 ep = (struct exportslist *)malloc(sizeof(struct exportslist)); 355 if (ep == NULL) 356 return (0); 357 ep->ex_groups = (struct grouplist *)0; 358 strp = ep->ex_dirp; 359 if (!xdr_string(xdrsp, &strp, MNTPATHLEN)) 360 return (0); 361 if (!xdr_bool(xdrsp, &grpbool)) 362 return (0); 363 while (grpbool) { 364 gp = (struct grouplist *)malloc(sizeof(struct grouplist)); 365 if (gp == NULL) 366 return (0); 367 strp = gp->gr_name; 368 if (!xdr_string(xdrsp, &strp, MNTNAMLEN)) 369 return (0); 370 gp->gr_next = ep->ex_groups; 371 ep->ex_groups = gp; 372 if (!xdr_bool(xdrsp, &grpbool)) 373 return (0); 374 } 375 ep->ex_next = *exp; 376 *exp = ep; 377 if (!xdr_bool(xdrsp, &bool)) 378 return (0); 379 } 380 return (1); 381 } 382 383 static void 384 usage(void) 385 { 386 fprintf(stderr, "usage: showmount [-a | -d] [-e3] [host]\n"); 387 exit(1); 388 } 389 390 /* 391 * Print the binary tree in inorder so that output is sorted. 392 */ 393 void 394 print_dump(struct mountlist *mp) 395 { 396 397 if (mp == NULL) 398 return; 399 if (mp->ml_left) 400 print_dump(mp->ml_left); 401 switch (type) { 402 case ALL: 403 printf("%s:%s\n", mp->ml_host, mp->ml_dirp); 404 break; 405 case DIRS: 406 printf("%s\n", mp->ml_dirp); 407 break; 408 default: 409 printf("%s\n", mp->ml_host); 410 break; 411 } 412 if (mp->ml_right) 413 print_dump(mp->ml_right); 414 } 415