1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * University Copyright- Copyright (c) 1982, 1986, 1988 32 * The Regents of the University of California 33 * All Rights Reserved 34 * 35 * University Acknowledgment- Portions of this document are derived from 36 * software developed by the University of California, Berkeley, and its 37 * contributors. 38 */ 39 40 /* 41 * showmount 42 */ 43 #include <stdio.h> 44 #include <stdarg.h> 45 #include <rpc/rpc.h> 46 #include <rpc/rpcb_clnt.h> 47 #include <sys/socket.h> 48 #include <netdb.h> 49 #include <sys/time.h> 50 #include <errno.h> 51 #include <nfs/nfs.h> 52 #include <rpcsvc/mount.h> 53 #include <locale.h> 54 55 int sorthost(); 56 int sortpath(); 57 void pr_err(char *, ...); 58 void printex(); 59 void usage(); 60 61 /* 62 * Dynamically-sized array of pointers to mountlist entries. Each element 63 * points into the linked list returned by the RPC call. We use an array 64 * so that we can conveniently sort the entries. 65 */ 66 static struct mountbody **table; 67 68 struct timeval rpc_totout_new = {15, 0}; 69 70 int 71 main(int argc, char *argv[]) 72 { 73 int aflg = 0, dflg = 0, eflg = 0; 74 int err; 75 struct mountbody *result_list = NULL; 76 struct mountbody *ml = NULL; 77 struct mountbody **tb; /* pointer into table */ 78 char *host, hostbuf[256]; 79 char *last; 80 CLIENT *cl; 81 extern int optind; 82 extern char *optarg; 83 int c; 84 struct timeval tout, rpc_totout_old; 85 int numentries; 86 (void) setlocale(LC_ALL, ""); 87 88 #if !defined(TEXT_DOMAIN) 89 #define TEXT_DOMAIN "SYS_TEST" 90 #endif 91 (void) textdomain(TEXT_DOMAIN); 92 93 while ((c = getopt(argc, argv, "ade")) != EOF) { 94 switch (c) { 95 case 'a': 96 aflg++; 97 break; 98 case 'd': 99 dflg++; 100 break; 101 case 'e': 102 eflg++; 103 break; 104 default: 105 usage(); 106 exit(1); 107 } 108 } 109 110 switch (argc - optind) { 111 case 0: /* no args */ 112 if (gethostname(hostbuf, sizeof (hostbuf)) < 0) { 113 pr_err("gethostname: %s\n", strerror(errno)); 114 exit(1); 115 } 116 host = hostbuf; 117 break; 118 case 1: /* one arg */ 119 host = argv[optind]; 120 break; 121 default: /* too many args */ 122 usage(); 123 exit(1); 124 } 125 126 __rpc_control(CLCR_GET_RPCB_TIMEOUT, &rpc_totout_old); 127 __rpc_control(CLCR_SET_RPCB_TIMEOUT, &rpc_totout_new); 128 129 /* 130 * First try circuit, then drop back to datagram if 131 * circuit is unavailable (an old version of mountd perhaps) 132 * Using circuit is preferred because it can handle 133 * arbitrarily long export lists. 134 */ 135 cl = clnt_create(host, MOUNTPROG, MOUNTVERS, "circuit_n"); 136 if (cl == NULL) { 137 if (rpc_createerr.cf_stat == RPC_PROGNOTREGISTERED) 138 cl = clnt_create(host, MOUNTPROG, MOUNTVERS, 139 "datagram_n"); 140 if (cl == NULL) { 141 pr_err(""); 142 clnt_pcreateerror(host); 143 __rpc_control(CLCR_SET_RPCB_TIMEOUT, &rpc_totout_old); 144 exit(1); 145 } 146 } 147 148 __rpc_control(CLCR_SET_RPCB_TIMEOUT, &rpc_totout_old); 149 150 if (eflg) { 151 printex(cl, host); 152 if (aflg + dflg == 0) { 153 exit(0); 154 } 155 } 156 157 tout.tv_sec = 10; 158 tout.tv_usec = 0; 159 160 if (err = clnt_call(cl, MOUNTPROC_DUMP, 161 xdr_void, 0, xdr_mountlist, 162 (caddr_t)&result_list, tout)) { 163 pr_err("%s\n", clnt_sperrno(err)); 164 exit(1); 165 } 166 167 /* 168 * Count the number of entries in the list. If the list is empty, 169 * quit now. 170 */ 171 numentries = 0; 172 for (ml = result_list; ml != NULL; ml = ml->ml_next) 173 numentries++; 174 if (numentries == 0) 175 exit(0); 176 177 /* 178 * Allocate memory for the array and initialize the array. 179 */ 180 181 table = (struct mountbody **)calloc(numentries, 182 sizeof (struct mountbody *)); 183 if (table == NULL) { 184 pr_err(gettext("not enough memory for %d entries\n"), 185 numentries); 186 exit(1); 187 } 188 for (ml = result_list, tb = &table[0]; 189 ml != NULL; 190 ml = ml->ml_next, tb++) { 191 *tb = ml; 192 } 193 194 /* 195 * Sort the entries and print the results. 196 */ 197 198 if (dflg) 199 qsort(table, numentries, sizeof (struct mountbody *), sortpath); 200 else 201 qsort(table, numentries, sizeof (struct mountbody *), sorthost); 202 if (aflg) { 203 for (tb = table; tb < table + numentries; tb++) 204 printf("%s:%s\n", (*tb)->ml_hostname, 205 (*tb)->ml_directory); 206 } else if (dflg) { 207 last = ""; 208 for (tb = table; tb < table + numentries; tb++) { 209 if (strcmp(last, (*tb)->ml_directory)) 210 printf("%s\n", (*tb)->ml_directory); 211 last = (*tb)->ml_directory; 212 } 213 } else { 214 last = ""; 215 for (tb = table; tb < table + numentries; tb++) { 216 if (strcmp(last, (*tb)->ml_hostname)) 217 printf("%s\n", (*tb)->ml_hostname); 218 last = (*tb)->ml_hostname; 219 } 220 } 221 return (0); 222 } 223 224 int 225 sorthost(a, b) 226 struct mountbody **a, **b; 227 { 228 return (strcmp((*a)->ml_hostname, (*b)->ml_hostname)); 229 } 230 231 int 232 sortpath(a, b) 233 struct mountbody **a, **b; 234 { 235 return (strcmp((*a)->ml_directory, (*b)->ml_directory)); 236 } 237 238 void 239 usage() 240 { 241 (void) fprintf(stderr, 242 gettext("Usage: showmount [-a] [-d] [-e] [host]\n")); 243 } 244 245 void 246 pr_err(char *fmt, ...) 247 { 248 va_list ap; 249 250 va_start(ap, fmt); 251 (void) fprintf(stderr, "showmount: "); 252 (void) vfprintf(stderr, fmt, ap); 253 va_end(ap); 254 } 255 256 void 257 printex(cl, host) 258 CLIENT *cl; 259 char *host; 260 { 261 struct exportnode *ex = NULL; 262 struct exportnode *e; 263 struct groupnode *gr; 264 enum clnt_stat err; 265 int max; 266 struct timeval tout; 267 268 tout.tv_sec = 10; 269 tout.tv_usec = 0; 270 271 if (err = clnt_call(cl, MOUNTPROC_EXPORT, 272 xdr_void, 0, xdr_exports, (caddr_t)&ex, tout)) { 273 pr_err("%s\n", clnt_sperrno(err)); 274 exit(1); 275 } 276 277 if (ex == NULL) { 278 printf(gettext("no exported file systems for %s\n"), host); 279 } else { 280 printf(gettext("export list for %s:\n"), host); 281 } 282 max = 0; 283 for (e = ex; e != NULL; e = e->ex_next) { 284 if (strlen(e->ex_dir) > max) { 285 max = strlen(e->ex_dir); 286 } 287 } 288 while (ex) { 289 printf("%-*s ", max, ex->ex_dir); 290 gr = ex->ex_groups; 291 if (gr == NULL) { 292 printf(gettext("(everyone)")); 293 } 294 while (gr) { 295 printf("%s", gr->gr_name); 296 gr = gr->gr_next; 297 if (gr) { 298 printf(","); 299 } 300 } 301 printf("\n"); 302 ex = ex->ex_next; 303 } 304 } 305