1/* $NetBSD: showmount.c,v 1.19 2011/08/30 17:06:21 plunky 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 43static char sccsid[] = "@(#)showmount.c 8.3 (Berkeley) 3/29/95"; 44#endif 45__RCSID("$NetBSD: showmount.c,v 1.19 2011/08/30 17:06:21 plunky 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 70struct 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 77struct grouplist { 78 struct grouplist *gr_next; 79 char gr_name[RPCMNT_NAMELEN+1]; 80}; 81 82struct exportslist { 83 struct exportslist *ex_next; 84 struct grouplist *ex_groups; 85 char ex_dirp[RPCMNT_PATHLEN+1]; 86}; 87 88static struct mountlist *mntdump; 89static struct exportslist *exports; 90static int type = 0; 91 92static void print_dump(struct mountlist *); 93__dead static void usage(void); 94static int xdr_mntdump(XDR *, struct mountlist **); 95static int xdr_exports(XDR *, struct exportslist **); 96static 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 it's mount list and/or 101 * it's 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 */ 106int 107main(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, (char *)0, 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, (char *)0, 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 214static int 215tcp_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/* 237 * Xdr routine for retrieving the mount dump list 238 */ 239static int 240xdr_mntdump(XDR *xdrsp, struct mountlist **mlp) 241{ 242 struct mountlist *mp, **otp, *tp; 243 int bool_int, val, val2; 244 char *strp; 245 246 otp = NULL; 247 *mlp = (struct mountlist *)0; 248 if (!xdr_bool(xdrsp, &bool_int)) 249 return (0); 250 while (bool_int) { 251 mp = (struct mountlist *)malloc(sizeof(struct mountlist)); 252 if (mp == NULL) 253 return (0); 254 mp->ml_left = mp->ml_right = (struct mountlist *)0; 255 strp = mp->ml_host; 256 if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) 257 return (0); 258 strp = mp->ml_dirp; 259 if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 260 return (0); 261 262 /* 263 * Build a binary tree on sorted order of either host or dirp. 264 * Drop any duplications. 265 */ 266 if (*mlp == NULL) { 267 *mlp = mp; 268 } else { 269 tp = *mlp; 270 while (tp) { 271 val = strcmp(mp->ml_host, tp->ml_host); 272 val2 = strcmp(mp->ml_dirp, tp->ml_dirp); 273 switch (type) { 274 case ALL: 275 if (val == 0) { 276 if (val2 == 0) { 277 free((caddr_t)mp); 278 goto next; 279 } 280 val = val2; 281 } 282 break; 283 case DIRS: 284 if (val2 == 0) { 285 free((caddr_t)mp); 286 goto next; 287 } 288 val = val2; 289 break; 290 default: 291 if (val == 0) { 292 free((caddr_t)mp); 293 goto next; 294 } 295 break; 296 }; 297 if (val < 0) { 298 otp = &tp->ml_left; 299 tp = tp->ml_left; 300 } else { 301 otp = &tp->ml_right; 302 tp = tp->ml_right; 303 } 304 } 305 *otp = mp; 306 } 307next: 308 if (!xdr_bool(xdrsp, &bool_int)) 309 return (0); 310 } 311 return (1); 312} 313 314/* 315 * Xdr routine to retrieve exports list 316 */ 317static int 318xdr_exports(XDR *xdrsp, struct exportslist **exp) 319{ 320 struct exportslist *ep; 321 struct grouplist *gp; 322 int bool_int, grpbool; 323 char *strp; 324 325 *exp = (struct exportslist *)0; 326 if (!xdr_bool(xdrsp, &bool_int)) 327 return (0); 328 while (bool_int) { 329 ep = (struct exportslist *)malloc(sizeof(struct exportslist)); 330 if (ep == NULL) 331 return (0); 332 ep->ex_groups = (struct grouplist *)0; 333 strp = ep->ex_dirp; 334 if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 335 return (0); 336 if (!xdr_bool(xdrsp, &grpbool)) 337 return (0); 338 while (grpbool) { 339 gp = (struct grouplist *)malloc(sizeof(struct grouplist)); 340 if (gp == NULL) 341 return (0); 342 strp = gp->gr_name; 343 if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) 344 return (0); 345 gp->gr_next = ep->ex_groups; 346 ep->ex_groups = gp; 347 if (!xdr_bool(xdrsp, &grpbool)) 348 return (0); 349 } 350 ep->ex_next = *exp; 351 *exp = ep; 352 if (!xdr_bool(xdrsp, &bool_int)) 353 return (0); 354 } 355 return (1); 356} 357 358static void 359usage(void) 360{ 361 362 fprintf(stderr, "usage: showmount [-ade3] host\n"); 363 exit(1); 364} 365 366/* 367 * Print the binary tree in inorder so that output is sorted. 368 */ 369static void 370print_dump(struct mountlist *mp) 371{ 372 373 if (mp == NULL) 374 return; 375 if (mp->ml_left) 376 print_dump(mp->ml_left); 377 switch (type) { 378 case ALL: 379 printf("%s:%s\n", mp->ml_host, mp->ml_dirp); 380 break; 381 case DIRS: 382 printf("%s\n", mp->ml_dirp); 383 break; 384 default: 385 printf("%s\n", mp->ml_host); 386 break; 387 }; 388 if (mp->ml_right) 389 print_dump(mp->ml_right); 390} 391