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