1 /* 2 * Copyright (c) 1989, 1993, 1995 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Rick Macklem at The University of Guelph. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * @(#) Copyright (c) 1989, 1993, 1995 The Regents of the University of California. All rights reserved. 33 * @(#)showmount.c 8.3 (Berkeley) 3/29/95 34 * $FreeBSD: src/usr.bin/showmount/showmount.c,v 1.16 2005/05/21 09:55:08 ru Exp $ 35 */ 36 37 #include <sys/types.h> 38 #include <sys/queue.h> 39 #include <sys/file.h> 40 #include <sys/socket.h> 41 #include <sys/socketvar.h> 42 43 #include <err.h> 44 #include <netdb.h> 45 #include <rpc/rpc.h> 46 #include <rpc/pmap_clnt.h> 47 #include <rpc/pmap_prot.h> 48 #include <nfs/rpcv2.h> 49 50 #include <stdio.h> 51 #include <stdlib.h> 52 #include <string.h> 53 #include <unistd.h> 54 #include <vis.h> 55 56 /* Constant defs */ 57 #define ALL 1 58 #define DIRS 2 59 60 #define DODUMP 0x1 61 #define DOEXPORTS 0x2 62 #define DOPARSABLEEXPORTS 0x4 63 64 struct mountlist { 65 struct mountlist *ml_left; 66 struct mountlist *ml_right; 67 char ml_host[RPCMNT_NAMELEN+1]; 68 char ml_dirp[RPCMNT_PATHLEN+1]; 69 }; 70 71 struct grouplist { 72 struct grouplist *gr_next; 73 char gr_name[RPCMNT_NAMELEN+1]; 74 }; 75 76 struct exportslist { 77 struct exportslist *ex_next; 78 struct grouplist *ex_groups; 79 char ex_dirp[RPCMNT_PATHLEN+1]; 80 }; 81 82 static struct mountlist *mntdump; 83 static struct exportslist *exports; 84 static int type = 0; 85 86 void print_dump(struct mountlist *); 87 static void usage(void); 88 int xdr_mntdump(XDR *, struct mountlist **); 89 int xdr_exports(XDR *, struct exportslist **); 90 int tcp_callrpc(const char *, int, int, int, xdrproc_t, char *, xdrproc_t, 91 char *); 92 93 /* 94 * This command queries the NFS mount daemon for it's mount list and/or 95 * it's exports list and prints them out. 96 * See "NFS: Network File System Protocol Specification, RFC1094, Appendix A" 97 * and the "Network File System Protocol XXX.." 98 * for detailed information on the protocol. 99 */ 100 int 101 main(int argc, char **argv) 102 { 103 struct exportslist *exp; 104 struct grouplist *grp; 105 int rpcs = 0, mntvers = 1; 106 const char *host; 107 int ch, estat, nbytes; 108 char strvised[1024 * 4 + 1]; 109 110 while ((ch = getopt(argc, argv, "adEe3")) != -1) 111 switch (ch) { 112 case 'a': 113 if (type == 0) { 114 type = ALL; 115 rpcs |= DODUMP; 116 } else 117 usage(); 118 break; 119 case 'd': 120 if (type == 0) { 121 type = DIRS; 122 rpcs |= DODUMP; 123 } else 124 usage(); 125 break; 126 case 'E': 127 rpcs |= DOPARSABLEEXPORTS; 128 break; 129 case 'e': 130 rpcs |= DOEXPORTS; 131 break; 132 case '3': 133 mntvers = 3; 134 break; 135 case '?': 136 default: 137 usage(); 138 } 139 argc -= optind; 140 argv += optind; 141 142 if ((rpcs & DOPARSABLEEXPORTS) != 0) { 143 if ((rpcs & DOEXPORTS) != 0) 144 errx(1, "-E cannot be used with -e"); 145 if ((rpcs & DODUMP) != 0) 146 errx(1, "-E cannot be used with -a or -d"); 147 } 148 149 if (argc > 0) 150 host = *argv; 151 else 152 host = "localhost"; 153 154 if (rpcs == 0) 155 rpcs = DODUMP; 156 157 if (rpcs & DODUMP) 158 if ((estat = tcp_callrpc(host, RPCPROG_MNT, mntvers, 159 RPCMNT_DUMP, (xdrproc_t)xdr_void, NULL, 160 (xdrproc_t)xdr_mntdump, (char *)&mntdump)) != 0) { 161 clnt_perrno(estat); 162 errx(1, "can't do mountdump rpc"); 163 } 164 if (rpcs & (DOEXPORTS | DOPARSABLEEXPORTS)) 165 if ((estat = tcp_callrpc(host, RPCPROG_MNT, mntvers, 166 RPCMNT_EXPORT, (xdrproc_t)xdr_void, NULL, 167 (xdrproc_t)xdr_exports, (char *)&exports)) != 0) { 168 clnt_perrno(estat); 169 errx(1, "can't do exports rpc"); 170 } 171 172 /* Now just print out the results */ 173 if (rpcs & DODUMP) { 174 switch (type) { 175 case ALL: 176 printf("All mount points on %s:\n", host); 177 break; 178 case DIRS: 179 printf("Directories on %s:\n", host); 180 break; 181 default: 182 printf("Hosts on %s:\n", host); 183 break; 184 } 185 print_dump(mntdump); 186 } 187 if (rpcs & DOEXPORTS) { 188 printf("Exports list on %s:\n", host); 189 exp = exports; 190 while (exp) { 191 printf("%-35s", exp->ex_dirp); 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 if (rpcs & DOPARSABLEEXPORTS) { 206 exp = exports; 207 while (exp) { 208 nbytes = strsnvis(strvised, sizeof(strvised), 209 exp->ex_dirp, VIS_GLOB | VIS_NL, "\"'$"); 210 if (nbytes == -1) 211 err(1, "strsnvis"); 212 printf("%s\n", strvised); 213 exp = exp->ex_next; 214 } 215 } 216 exit(0); 217 } 218 219 /* 220 * tcp_callrpc has the same interface as callrpc, but tries to 221 * use tcp as transport method in order to handle large replies. 222 */ 223 int 224 tcp_callrpc(const char *host, int prognum, int versnum, int procnum, 225 xdrproc_t inproc, char *in, xdrproc_t outproc, char *out) 226 { 227 CLIENT *client; 228 struct timeval timeout; 229 int rval; 230 231 if ((client = clnt_create(host, prognum, versnum, "tcp")) == NULL && 232 (client = clnt_create(host, prognum, versnum, "udp")) == NULL) 233 return ((int) rpc_createerr.cf_stat); 234 235 timeout.tv_sec = 25; 236 timeout.tv_usec = 0; 237 rval = (int) clnt_call(client, procnum, 238 inproc, in, 239 outproc, out, 240 timeout); 241 clnt_destroy(client); 242 return rval; 243 } 244 245 /* 246 * Xdr routine for retrieving the mount dump list 247 */ 248 int 249 xdr_mntdump(XDR *xdrsp, struct mountlist **mlp) 250 { 251 struct mountlist *mp; 252 struct mountlist *tp; 253 struct mountlist **otp = NULL; 254 int val, val2; 255 int bool; 256 char *strp; 257 258 *mlp = NULL; 259 if (!xdr_bool(xdrsp, &bool)) 260 return (0); 261 while (bool) { 262 mp = (struct mountlist *)malloc(sizeof(struct mountlist)); 263 if (mp == NULL) 264 return (0); 265 mp->ml_left = mp->ml_right = NULL; 266 strp = mp->ml_host; 267 if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) 268 return (0); 269 strp = mp->ml_dirp; 270 if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 271 return (0); 272 273 /* 274 * Build a binary tree on sorted order of either host or dirp. 275 * Drop any duplications. 276 */ 277 if (*mlp == NULL) { 278 *mlp = mp; 279 } else { 280 tp = *mlp; 281 while (tp) { 282 val = strcmp(mp->ml_host, tp->ml_host); 283 val2 = strcmp(mp->ml_dirp, tp->ml_dirp); 284 switch (type) { 285 case ALL: 286 if (val == 0) { 287 if (val2 == 0) { 288 free(mp); 289 goto next; 290 } 291 val = val2; 292 } 293 break; 294 case DIRS: 295 if (val2 == 0) { 296 free(mp); 297 goto next; 298 } 299 val = val2; 300 break; 301 default: 302 if (val == 0) { 303 free(mp); 304 goto next; 305 } 306 break; 307 } 308 if (val < 0) { 309 otp = &tp->ml_left; 310 tp = tp->ml_left; 311 } else { 312 otp = &tp->ml_right; 313 tp = tp->ml_right; 314 } 315 } 316 *otp = mp; 317 } 318 next: 319 if (!xdr_bool(xdrsp, &bool)) 320 return (0); 321 } 322 return (1); 323 } 324 325 /* 326 * Xdr routine to retrieve exports list 327 */ 328 int 329 xdr_exports(XDR *xdrsp, struct exportslist **exp) 330 { 331 struct exportslist *ep; 332 struct grouplist *gp; 333 int bool, grpbool; 334 char *strp; 335 336 *exp = NULL; 337 if (!xdr_bool(xdrsp, &bool)) 338 return (0); 339 while (bool) { 340 ep = (struct exportslist *)malloc(sizeof(struct exportslist)); 341 if (ep == NULL) 342 return (0); 343 ep->ex_groups = NULL; 344 strp = ep->ex_dirp; 345 if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 346 return (0); 347 if (!xdr_bool(xdrsp, &grpbool)) 348 return (0); 349 while (grpbool) { 350 gp = (struct grouplist *)malloc(sizeof(struct grouplist)); 351 if (gp == NULL) 352 return (0); 353 strp = gp->gr_name; 354 if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) 355 return (0); 356 gp->gr_next = ep->ex_groups; 357 ep->ex_groups = gp; 358 if (!xdr_bool(xdrsp, &grpbool)) 359 return (0); 360 } 361 ep->ex_next = *exp; 362 *exp = ep; 363 if (!xdr_bool(xdrsp, &bool)) 364 return (0); 365 } 366 return (1); 367 } 368 369 static void 370 usage(void) 371 { 372 fprintf(stderr, "usage: showmount [-a | -d] [-e3] [host]\n"); 373 exit(1); 374 } 375 376 /* 377 * Print the binary tree in inorder so that output is sorted. 378 */ 379 void 380 print_dump(struct mountlist *mp) 381 { 382 383 if (mp == NULL) 384 return; 385 if (mp->ml_left) 386 print_dump(mp->ml_left); 387 switch (type) { 388 case ALL: 389 printf("%s:%s\n", mp->ml_host, mp->ml_dirp); 390 break; 391 case DIRS: 392 printf("%s\n", mp->ml_dirp); 393 break; 394 default: 395 printf("%s\n", mp->ml_host); 396 break; 397 } 398 if (mp->ml_right) 399 print_dump(mp->ml_right); 400 } 401