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 <vfs/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 static void print_dump(struct mountlist *); 87 static void usage(void); 88 static int xdr_mntdump(XDR *, struct mountlist **); 89 static int xdr_exports(XDR *, struct exportslist **); 90 static enum clnt_stat tcp_callrpc(const char *, int, int, int, xdrproc_t, 91 char *, xdrproc_t, 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, nbytes; 108 enum clnt_stat estat; 109 char strvised[1024 * 4 + 1]; 110 111 while ((ch = getopt(argc, argv, "adEe3")) != -1) 112 switch (ch) { 113 case 'a': 114 if (type == 0) { 115 type = ALL; 116 rpcs |= DODUMP; 117 } else 118 usage(); 119 break; 120 case 'd': 121 if (type == 0) { 122 type = DIRS; 123 rpcs |= DODUMP; 124 } else 125 usage(); 126 break; 127 case 'E': 128 rpcs |= DOPARSABLEEXPORTS; 129 break; 130 case 'e': 131 rpcs |= DOEXPORTS; 132 break; 133 case '3': 134 mntvers = 3; 135 break; 136 case '?': 137 default: 138 usage(); 139 } 140 argc -= optind; 141 argv += optind; 142 143 if ((rpcs & DOPARSABLEEXPORTS) != 0) { 144 if ((rpcs & DOEXPORTS) != 0) 145 errx(1, "-E cannot be used with -e"); 146 if ((rpcs & DODUMP) != 0) 147 errx(1, "-E cannot be used with -a or -d"); 148 } 149 150 if (argc > 0) 151 host = *argv; 152 else 153 host = "localhost"; 154 155 if (rpcs == 0) 156 rpcs = DODUMP; 157 158 if (rpcs & DODUMP) 159 if ((estat = tcp_callrpc(host, RPCPROG_MNT, mntvers, 160 RPCMNT_DUMP, (xdrproc_t)xdr_void, NULL, 161 (xdrproc_t)xdr_mntdump, (char *)&mntdump)) != 0) { 162 clnt_perrno(estat); 163 errx(1, "can't do mountdump rpc"); 164 } 165 if (rpcs & (DOEXPORTS | DOPARSABLEEXPORTS)) 166 if ((estat = tcp_callrpc(host, RPCPROG_MNT, mntvers, 167 RPCMNT_EXPORT, (xdrproc_t)xdr_void, NULL, 168 (xdrproc_t)xdr_exports, (char *)&exports)) != 0) { 169 clnt_perrno(estat); 170 errx(1, "can't do exports rpc"); 171 } 172 173 /* Now just print out the results */ 174 if (rpcs & DODUMP) { 175 switch (type) { 176 case ALL: 177 printf("All mount points on %s:\n", host); 178 break; 179 case DIRS: 180 printf("Directories on %s:\n", host); 181 break; 182 default: 183 printf("Hosts on %s:\n", host); 184 break; 185 } 186 print_dump(mntdump); 187 } 188 if (rpcs & DOEXPORTS) { 189 printf("Exports list on %s:\n", host); 190 exp = exports; 191 while (exp) { 192 printf("%-35s", exp->ex_dirp); 193 grp = exp->ex_groups; 194 if (grp == NULL) { 195 printf("Everyone\n"); 196 } else { 197 while (grp) { 198 printf("%s ", grp->gr_name); 199 grp = grp->gr_next; 200 } 201 printf("\n"); 202 } 203 exp = exp->ex_next; 204 } 205 } 206 if (rpcs & DOPARSABLEEXPORTS) { 207 exp = exports; 208 while (exp) { 209 nbytes = strsnvis(strvised, sizeof(strvised), 210 exp->ex_dirp, VIS_GLOB | VIS_NL, "\"'$"); 211 if (nbytes == -1) 212 err(1, "strsnvis"); 213 printf("%s\n", strvised); 214 exp = exp->ex_next; 215 } 216 } 217 exit(0); 218 } 219 220 /* 221 * tcp_callrpc has the same interface as callrpc, but tries to 222 * use tcp as transport method in order to handle large replies. 223 */ 224 static enum clnt_stat 225 tcp_callrpc(const char *host, int prognum, int versnum, int procnum, 226 xdrproc_t inproc, char *in, xdrproc_t outproc, char *out) 227 { 228 CLIENT *client; 229 struct timeval timeout; 230 enum clnt_stat rval; 231 232 if ((client = clnt_create(host, prognum, versnum, "tcp")) == NULL && 233 (client = clnt_create(host, prognum, versnum, "udp")) == NULL) 234 return ((int) rpc_createerr.cf_stat); 235 236 timeout.tv_sec = 25; 237 timeout.tv_usec = 0; 238 rval = clnt_call(client, procnum, inproc, in, outproc, out, timeout); 239 clnt_destroy(client); 240 return rval; 241 } 242 243 /* 244 * Xdr routine for retrieving the mount dump list 245 */ 246 static int 247 xdr_mntdump(XDR *xdrsp, struct mountlist **mlp) 248 { 249 struct mountlist *mp; 250 struct mountlist *tp; 251 struct mountlist **otp = NULL; 252 int val, val2; 253 int bool; 254 char *strp; 255 256 *mlp = NULL; 257 if (!xdr_bool(xdrsp, &bool)) 258 return (0); 259 while (bool) { 260 mp = (struct mountlist *)malloc(sizeof(struct mountlist)); 261 if (mp == NULL) 262 return (0); 263 mp->ml_left = mp->ml_right = NULL; 264 strp = mp->ml_host; 265 if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) 266 return (0); 267 strp = mp->ml_dirp; 268 if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 269 return (0); 270 271 /* 272 * Build a binary tree on sorted order of either host or dirp. 273 * Drop any duplications. 274 */ 275 if (*mlp == NULL) { 276 *mlp = mp; 277 } else { 278 tp = *mlp; 279 while (tp) { 280 val = strcmp(mp->ml_host, tp->ml_host); 281 val2 = strcmp(mp->ml_dirp, tp->ml_dirp); 282 switch (type) { 283 case ALL: 284 if (val == 0) { 285 if (val2 == 0) { 286 free(mp); 287 goto next; 288 } 289 val = val2; 290 } 291 break; 292 case DIRS: 293 if (val2 == 0) { 294 free(mp); 295 goto next; 296 } 297 val = val2; 298 break; 299 default: 300 if (val == 0) { 301 free(mp); 302 goto next; 303 } 304 break; 305 } 306 if (val < 0) { 307 otp = &tp->ml_left; 308 tp = tp->ml_left; 309 } else { 310 otp = &tp->ml_right; 311 tp = tp->ml_right; 312 } 313 } 314 *otp = mp; 315 } 316 next: 317 if (!xdr_bool(xdrsp, &bool)) 318 return (0); 319 } 320 return (1); 321 } 322 323 /* 324 * Xdr routine to retrieve exports list 325 */ 326 static int 327 xdr_exports(XDR *xdrsp, struct exportslist **exp) 328 { 329 struct exportslist *ep; 330 struct grouplist *gp; 331 int bool, grpbool; 332 char *strp; 333 334 *exp = NULL; 335 if (!xdr_bool(xdrsp, &bool)) 336 return (0); 337 while (bool) { 338 ep = (struct exportslist *)malloc(sizeof(struct exportslist)); 339 if (ep == NULL) 340 return (0); 341 ep->ex_groups = NULL; 342 strp = ep->ex_dirp; 343 if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 344 return (0); 345 if (!xdr_bool(xdrsp, &grpbool)) 346 return (0); 347 while (grpbool) { 348 gp = (struct grouplist *)malloc(sizeof(struct grouplist)); 349 if (gp == NULL) 350 return (0); 351 strp = gp->gr_name; 352 if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) 353 return (0); 354 gp->gr_next = ep->ex_groups; 355 ep->ex_groups = gp; 356 if (!xdr_bool(xdrsp, &grpbool)) 357 return (0); 358 } 359 ep->ex_next = *exp; 360 *exp = ep; 361 if (!xdr_bool(xdrsp, &bool)) 362 return (0); 363 } 364 return (1); 365 } 366 367 static void 368 usage(void) 369 { 370 fprintf(stderr, "usage: showmount [-a | -d] [-e3] [host]\n"); 371 exit(1); 372 } 373 374 /* 375 * Print the binary tree in inorder so that output is sorted. 376 */ 377 static void 378 print_dump(struct mountlist *mp) 379 { 380 381 if (mp == NULL) 382 return; 383 if (mp->ml_left) 384 print_dump(mp->ml_left); 385 switch (type) { 386 case ALL: 387 printf("%s:%s\n", mp->ml_host, mp->ml_dirp); 388 break; 389 case DIRS: 390 printf("%s\n", mp->ml_dirp); 391 break; 392 default: 393 printf("%s\n", mp->ml_host); 394 break; 395 } 396 if (mp->ml_right) 397 print_dump(mp->ml_right); 398 } 399