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