xref: /illumos-gate/usr/src/cmd/fs.d/nfs/showmount/showmount.c (revision b0bb0d63258be430b0e22afcb1581974bd7b568e)
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