1 /* $NetBSD: showmount.c,v 1.22 2016/01/26 16:23:27 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.22 2016/01/26 16:23:27 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 63 /* Constant defs */ 64 #define ALL 1 65 #define DIRS 2 66 67 #define DODUMP 0x1 68 #define DOEXPORTS 0x2 69 70 struct mountlist { 71 struct mountlist *ml_left; 72 struct mountlist *ml_right; 73 char ml_host[RPCMNT_NAMELEN+1]; 74 char ml_dirp[RPCMNT_PATHLEN+1]; 75 }; 76 77 struct grouplist { 78 struct grouplist *gr_next; 79 char gr_name[RPCMNT_NAMELEN+1]; 80 }; 81 82 struct exportslist { 83 struct exportslist *ex_next; 84 struct grouplist *ex_groups; 85 char ex_dirp[RPCMNT_PATHLEN+1]; 86 }; 87 88 static struct mountlist *mntdump; 89 static struct exportslist *exports; 90 static int type = 0; 91 92 static void print_dump(struct mountlist *); 93 __dead static void usage(void); 94 static int xdr_mntdump(XDR *, struct mountlist **); 95 static int xdr_exports(XDR *, struct exportslist **); 96 static int tcp_callrpc(const char *host, int prognum, int versnum, 97 int procnum, xdrproc_t inproc, char *in, xdrproc_t outproc, char *out); 98 99 /* 100 * This command queries the NFS mount daemon for its mount list and/or 101 * its exports list and prints them out. 102 * See "NFS: Network File System Protocol Specification, RFC1094, Appendix A" 103 * and the "Network File System Protocol XXX.." 104 * for detailed information on the protocol. 105 */ 106 int 107 main(int argc, char **argv) 108 { 109 struct exportslist *exp; 110 struct grouplist *grp; 111 int estat, rpcs = 0, mntvers = 1; 112 const char *host; 113 int ch; 114 int len; 115 116 while ((ch = getopt(argc, argv, "ade3")) != -1) 117 switch((char)ch) { 118 case 'a': 119 if (type == 0) { 120 type = ALL; 121 rpcs |= DODUMP; 122 } else 123 usage(); 124 break; 125 case 'd': 126 if (type == 0) { 127 type = DIRS; 128 rpcs |= DODUMP; 129 } else 130 usage(); 131 break; 132 case 'e': 133 rpcs |= DOEXPORTS; 134 break; 135 case '3': 136 mntvers = 3; 137 break; 138 case '?': 139 default: 140 usage(); 141 } 142 argc -= optind; 143 argv += optind; 144 145 if (argc > 0) 146 host = *argv; 147 else 148 host = "localhost"; 149 150 if (rpcs == 0) 151 rpcs = DODUMP; 152 153 if (rpcs & DODUMP) 154 if ((estat = tcp_callrpc(host, RPCPROG_MNT, mntvers, 155 RPCMNT_DUMP, (xdrproc_t)xdr_void, NULL, 156 (xdrproc_t)xdr_mntdump, (char *)&mntdump)) != 0) { 157 fprintf(stderr, "showmount: Can't do Mountdump rpc: "); 158 clnt_perrno(estat); 159 exit(1); 160 } 161 if (rpcs & DOEXPORTS) 162 if ((estat = tcp_callrpc(host, RPCPROG_MNT, mntvers, 163 RPCMNT_EXPORT, (xdrproc_t)xdr_void, NULL, 164 (xdrproc_t)xdr_exports, (char *)&exports)) != 0) { 165 fprintf(stderr, "showmount: Can't do Exports rpc: "); 166 clnt_perrno(estat); 167 exit(1); 168 } 169 170 /* Now just print out the results */ 171 if (rpcs & DODUMP) { 172 switch (type) { 173 case ALL: 174 printf("All mount points on %s:\n", host); 175 break; 176 case DIRS: 177 printf("Directories on %s:\n", host); 178 break; 179 default: 180 printf("Hosts on %s:\n", host); 181 break; 182 }; 183 print_dump(mntdump); 184 } 185 if (rpcs & DOEXPORTS) { 186 printf("Exports list on %s:\n", host); 187 exp = exports; 188 while (exp) { 189 len = printf("%-35s", exp->ex_dirp); 190 if (len > 35) 191 printf("\t"); 192 grp = exp->ex_groups; 193 if (grp == NULL) { 194 printf("Everyone\n"); 195 } else { 196 while (grp) { 197 printf("%s ", grp->gr_name); 198 grp = grp->gr_next; 199 } 200 printf("\n"); 201 } 202 exp = exp->ex_next; 203 } 204 } 205 206 exit(0); 207 } 208 209 /* 210 * tcp_callrpc has the same interface as callrpc, but tries to 211 * use tcp as transport method in order to handle large replies. 212 */ 213 214 static int 215 tcp_callrpc(const char *host, int prognum, int versnum, int procnum, 216 xdrproc_t inproc, char *in, xdrproc_t outproc, char *out) 217 { 218 CLIENT *client; 219 struct timeval timeout; 220 int rval; 221 222 if ((client = clnt_create(host, prognum, versnum, "tcp")) == NULL && 223 (client = clnt_create(host, prognum, versnum, "udp")) == NULL) 224 return ((int) rpc_createerr.cf_stat); 225 226 timeout.tv_sec = 25; 227 timeout.tv_usec = 0; 228 rval = (int) clnt_call(client, procnum, 229 inproc, in, 230 outproc, out, 231 timeout); 232 clnt_destroy(client); 233 return rval; 234 } 235 236 static void 237 mountlist_free(struct mountlist *ml) 238 { 239 if (ml == NULL) 240 return; 241 mountlist_free(ml->ml_left); 242 mountlist_free(ml->ml_right); 243 free(ml); 244 } 245 246 /* 247 * Xdr routine for retrieving the mount dump list 248 */ 249 static int 250 xdr_mntdump(XDR *xdrsp, struct mountlist **mlp) 251 { 252 struct mountlist *mp, **otp, *tp; 253 int bool_int, val, val2; 254 char *strp; 255 256 otp = NULL; 257 *mlp = NULL; 258 if (!xdr_bool(xdrsp, &bool_int)) 259 return 0; 260 while (bool_int) { 261 mp = malloc(sizeof(*mp)); 262 if (mp == NULL) 263 goto out; 264 mp->ml_left = mp->ml_right = NULL; 265 strp = mp->ml_host; 266 if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) { 267 free(mp); 268 goto out; 269 } 270 strp = mp->ml_dirp; 271 if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) { 272 free(mp); 273 goto out; 274 } 275 276 /* 277 * Build a binary tree on sorted order of either host or dirp. 278 * Drop any duplications. 279 */ 280 if (*mlp == NULL) { 281 *mlp = mp; 282 } else { 283 tp = *mlp; 284 while (tp) { 285 val = strcmp(mp->ml_host, tp->ml_host); 286 val2 = strcmp(mp->ml_dirp, tp->ml_dirp); 287 switch (type) { 288 case ALL: 289 if (val == 0) { 290 if (val2 == 0) { 291 free(mp); 292 goto next; 293 } 294 val = val2; 295 } 296 break; 297 case DIRS: 298 if (val2 == 0) { 299 free(mp); 300 goto next; 301 } 302 val = val2; 303 break; 304 default: 305 if (val == 0) { 306 free(mp); 307 goto next; 308 } 309 break; 310 }; 311 if (val < 0) { 312 otp = &tp->ml_left; 313 tp = tp->ml_left; 314 } else { 315 otp = &tp->ml_right; 316 tp = tp->ml_right; 317 } 318 } 319 *otp = mp; 320 } 321 next: 322 if (!xdr_bool(xdrsp, &bool_int)) 323 goto out; 324 } 325 return 1; 326 out: 327 mountlist_free(*mlp); 328 return 0; 329 } 330 331 static void 332 grouplist_free(struct grouplist *gp) 333 { 334 if (gp == NULL) 335 return; 336 grouplist_free(gp->gr_next); 337 free(gp); 338 } 339 340 static void 341 exportslist_free(struct exportslist *ep) 342 { 343 if (ep == NULL) 344 return; 345 exportslist_free(ep->ex_next); 346 grouplist_free(ep->ex_groups); 347 free(ep); 348 } 349 350 /* 351 * Xdr routine to retrieve exports list 352 */ 353 static int 354 xdr_exports(XDR *xdrsp, struct exportslist **exp) 355 { 356 struct exportslist *ep = NULL; 357 struct grouplist *gp; 358 int bool_int, grpbool; 359 char *strp; 360 361 *exp = NULL; 362 if (!xdr_bool(xdrsp, &bool_int)) 363 return 0; 364 while (bool_int) { 365 ep = malloc(sizeof(*ep)); 366 if (ep == NULL) 367 goto out; 368 ep->ex_groups = NULL; 369 strp = ep->ex_dirp; 370 if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 371 goto out; 372 if (!xdr_bool(xdrsp, &grpbool)) 373 goto out; 374 while (grpbool) { 375 gp = malloc(sizeof(*gp)); 376 if (gp == NULL) 377 goto out; 378 gp->gr_next = ep->ex_groups; 379 ep->ex_groups = gp; 380 strp = gp->gr_name; 381 if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) 382 goto out; 383 if (!xdr_bool(xdrsp, &grpbool)) 384 goto out; 385 } 386 ep->ex_next = *exp; 387 *exp = ep; 388 ep = NULL; 389 if (!xdr_bool(xdrsp, &bool_int)) 390 goto out; 391 } 392 return 1; 393 out: 394 exportslist_free(ep); 395 exportslist_free(*exp); 396 return 0; 397 } 398 399 static void 400 usage(void) 401 { 402 403 fprintf(stderr, "usage: showmount [-ade3] host\n"); 404 exit(1); 405 } 406 407 /* 408 * Print the binary tree in inorder so that output is sorted. 409 */ 410 static void 411 print_dump(struct mountlist *mp) 412 { 413 414 if (mp == NULL) 415 return; 416 if (mp->ml_left) 417 print_dump(mp->ml_left); 418 switch (type) { 419 case ALL: 420 printf("%s:%s\n", mp->ml_host, mp->ml_dirp); 421 break; 422 case DIRS: 423 printf("%s\n", mp->ml_dirp); 424 break; 425 default: 426 printf("%s\n", mp->ml_host); 427 break; 428 }; 429 if (mp->ml_right) 430 print_dump(mp->ml_right); 431 } 432