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 * nfs dfmounts 42 */ 43 #include <stdio.h> 44 #include <stdlib.h> 45 #include <stdarg.h> 46 #include <string.h> 47 #include <rpc/rpc.h> 48 #include <rpc/rpcb_clnt.h> 49 #include <sys/socket.h> 50 #include <netdb.h> 51 #include <sys/time.h> 52 #include <sys/errno.h> 53 #include <nfs/nfs.h> 54 #include <rpcsvc/mount.h> 55 #include <locale.h> 56 #include <unistd.h> 57 #include <clnt_subr.h> 58 59 static int hflg; 60 61 static void pr_mounts(char *); 62 static void freemntlist(struct mountbody *); 63 static int sortpath(const void *, const void *); 64 static void usage(void); 65 66 int 67 main(int argc, char *argv[]) 68 { 69 70 char hostbuf[256]; 71 extern int optind; 72 int i, c; 73 74 (void) setlocale(LC_ALL, ""); 75 76 #if !defined(TEXT_DOMAIN) 77 #define TEXT_DOMAIN "SYS_TEST" 78 #endif 79 (void) textdomain(TEXT_DOMAIN); 80 81 while ((c = getopt(argc, argv, "h")) != EOF) { 82 switch (c) { 83 case 'h': 84 hflg++; 85 break; 86 default: 87 usage(); 88 exit(1); 89 } 90 } 91 92 if (optind < argc) { 93 for (i = optind; i < argc; i++) 94 pr_mounts(argv[i]); 95 } else { 96 if (gethostname(hostbuf, sizeof (hostbuf)) < 0) { 97 perror("nfs dfmounts: gethostname"); 98 exit(1); 99 } 100 pr_mounts(hostbuf); 101 } 102 103 return (0); 104 } 105 106 #define NTABLEENTRIES 2048 107 static struct mountbody *table[NTABLEENTRIES]; 108 static struct timeval rpc_totout_new = {15, 0}; 109 110 /* 111 * Print the filesystems on "host" that are currently mounted by a client. 112 */ 113 114 static void 115 pr_mounts(char *host) 116 { 117 CLIENT *cl; 118 struct mountbody *ml = NULL; 119 struct mountbody **tb, **endtb; 120 enum clnt_stat err; 121 char *lastpath; 122 char *lastclient; 123 int tail = 0; 124 struct timeval tout, rpc_totout_old; 125 126 (void) __rpc_control(CLCR_GET_RPCB_TIMEOUT, &rpc_totout_old); 127 (void) __rpc_control(CLCR_SET_RPCB_TIMEOUT, &rpc_totout_new); 128 129 cl = mountprog_client_create(host, &rpc_totout_old); 130 if (cl == NULL) { 131 return; 132 } 133 134 (void) __rpc_control(CLCR_SET_RPCB_TIMEOUT, &rpc_totout_old); 135 tout.tv_sec = 10; 136 tout.tv_usec = 0; 137 138 err = clnt_call(cl, MOUNTPROC_DUMP, xdr_void, 0, xdr_mountlist, 139 (caddr_t)&ml, tout); 140 if (err != 0) { 141 pr_err("%s\n", clnt_sperrno(err)); 142 clnt_destroy(cl); 143 return; 144 } 145 146 if (ml == NULL) 147 return; /* no mounts */ 148 149 if (!hflg) { 150 printf("%-8s %10s %-24s %s", 151 gettext("RESOURCE"), gettext("SERVER"), 152 gettext("PATHNAME"), gettext("CLIENTS")); 153 hflg++; 154 } 155 156 /* 157 * Create an array describing the mounts, so that we can sort them. 158 */ 159 tb = table; 160 for (; ml != NULL && tb < &table[NTABLEENTRIES]; ml = ml->ml_next) 161 *tb++ = ml; 162 if (ml != NULL && tb == &table[NTABLEENTRIES]) 163 pr_err(gettext("table overflow: only %d entries shown\n"), 164 NTABLEENTRIES); 165 endtb = tb; 166 qsort(table, endtb - table, sizeof (struct mountbody *), sortpath); 167 168 /* 169 * Print out the sorted array. Group entries for the same 170 * filesystem together, and ignore duplicate entries. 171 */ 172 lastpath = ""; 173 lastclient = ""; 174 for (tb = table; tb < endtb; tb++) { 175 if (*((*tb)->ml_directory) == '\0' || 176 *((*tb)->ml_hostname) == '\0') 177 continue; 178 if (strcmp(lastpath, (*tb)->ml_directory) == 0) { 179 if (strcmp(lastclient, (*tb)->ml_hostname) == 0) { 180 continue; /* ignore duplicate */ 181 } 182 } else { 183 printf("\n%-8s %10s %-24s ", 184 " -", host, (*tb)->ml_directory); 185 lastpath = (*tb)->ml_directory; 186 tail = 0; 187 } 188 if (tail++) 189 printf(","); 190 printf("%s", (*tb)->ml_hostname); 191 lastclient = (*tb)->ml_hostname; 192 } 193 printf("\n"); 194 195 freemntlist(ml); 196 clnt_destroy(cl); 197 } 198 199 static void 200 freemntlist(struct mountbody *ml) 201 { 202 struct mountbody *old; 203 204 while (ml) { 205 if (ml->ml_hostname) 206 free(ml->ml_hostname); 207 if (ml->ml_directory) 208 free(ml->ml_directory); 209 old = ml; 210 ml = ml->ml_next; 211 free(old); 212 } 213 } 214 215 /* 216 * Compare two structs for mounted filesystems. The primary sort key is 217 * the name of the exported filesystem. There is also a secondary sort on 218 * the name of the client, so that duplicate entries (same path and 219 * hostname) will sort together. 220 * 221 * Returns < 0 if the first entry sorts before the second entry, 0 if they 222 * sort the same, and > 0 if the first entry sorts after the second entry. 223 */ 224 225 static int 226 sortpath(const void *a, const void *b) 227 { 228 const struct mountbody **m1, **m2; 229 int result; 230 231 m1 = (const struct mountbody **)a; 232 m2 = (const struct mountbody **)b; 233 234 result = strcmp((*m1)->ml_directory, (*m2)->ml_directory); 235 if (result == 0) { 236 result = strcmp((*m1)->ml_hostname, (*m2)->ml_hostname); 237 } 238 239 return (result); 240 } 241 242 static void 243 usage(void) 244 { 245 (void) fprintf(stderr, gettext("Usage: dfmounts [-h] [host ...]\n")); 246 } 247 248 void 249 pr_err(char *fmt, ...) 250 { 251 va_list ap; 252 253 va_start(ap, fmt); 254 (void) fprintf(stderr, "nfs dfmounts: "); 255 (void) vfprintf(stderr, fmt, ap); 256 va_end(ap); 257 } 258