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