2 * showmount.c -- show mount information for an NFS server
3 * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
22 #include <rpc/pmap_prot.h>
23 #include <sys/socket.h>
24 #include <netinet/in.h>
27 #include <sys/types.h>
34 #include <arpa/inet.h>
43 #define TOTAL_TIMEOUT 20
45 static char * version = "showmount for " VERSION;
46 static char * program_name;
47 static int headers = 1;
53 static struct option longopts[] =
56 { "directories", 0, 0, 'd' },
57 { "exports", 0, 0, 'e' },
58 { "no-headers", 0, &headers, 0 },
59 { "version", 0, 0, 'v' },
60 { "help", 0, 0, 'h' },
64 #define MAXHOSTLEN 256
66 static int dump_cmp(const void *pv, const void *qv)
68 const char **p = (const char **)pv;
69 const char **q = (const char **)qv;
70 return strcmp(*p, *q);
73 static void usage(FILE *fp, int n)
75 fprintf(fp, "Usage: %s [-adehv]\n", program_name);
76 fprintf(fp, " [--all] [--directories] [--exports]\n");
77 fprintf(fp, " [--no-headers] [--help] [--version] [host]\n");
81 #ifdef HAVE_CLNT_CREATE
83 static const char *nfs_sm_pgmtbl[] = {
91 * Generate an RPC client handle connected to the mountd service
92 * at @hostname, or die trying.
94 * Supports both AF_INET and AF_INET6 server addresses.
96 static CLIENT *nfs_get_mount_client(const char *hostname)
98 rpcprog_t program = nfs_getrpcbyname(MOUNTPROG, nfs_sm_pgmtbl);
101 client = clnt_create(hostname, program, MOUNTVERS, "tcp");
105 client = clnt_create(hostname, program, MOUNTVERS, "udp");
109 clnt_pcreateerror("clnt_create");
113 #else /* HAVE_CLNT_CREATE */
116 * Perform a non-blocking connect on the socket fd.
118 * tout contains the timeout. It will be modified to contain the time
119 * remaining (i.e. time provided - time elasped).
121 * Returns zero on success; otherwise, -1 is returned and errno is set
122 * to reflect the nature of the error.
124 static int connect_nb(int fd, struct sockaddr_in *addr, struct timeval *tout)
130 flags = fcntl(fd, F_GETFL, 0);
134 ret = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
139 * From here on subsequent sys calls could change errno so
140 * we set ret = -errno to capture it in case we decide to
143 len = sizeof(struct sockaddr);
144 ret = connect(fd, (struct sockaddr *)addr, len);
145 if (ret < 0 && errno != EINPROGRESS) {
157 ret = select(fd + 1, NULL, &rset, NULL, tout);
165 if (FD_ISSET(fd, &rset)) {
169 status = getsockopt(fd, SOL_SOCKET, SO_ERROR, &ret, &len);
175 /* Oops - something wrong with connect */
183 fcntl(fd, F_SETFL, flags);
188 * Generate an RPC client handle connected to the mountd service
189 * at @hostname, or die trying.
191 * Supports only AF_INET server addresses.
193 static CLIENT *nfs_get_mount_client(const char *hostname)
196 struct sockaddr_in server_addr;
197 struct timeval pertry_timeout;
198 CLIENT *mclient = NULL;
201 if (inet_aton(hostname, &server_addr.sin_addr)) {
202 server_addr.sin_family = AF_INET;
205 if ((hp = gethostbyname(hostname)) == NULL) {
206 fprintf(stderr, "%s: can't get address for %s\n",
207 program_name, hostname);
210 server_addr.sin_family = AF_INET;
211 memcpy(&server_addr.sin_addr, hp->h_addr, hp->h_length);
214 msock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
216 if (nfs_getport_ping((struct sockaddr *)&server_addr,
217 sizeof(server_addr), MOUNTPROG,
218 MOUNTVERS, IPPROTO_TCP)) {
219 ret = connect_nb(msock, &server_addr, 0);
221 mclient = clnttcp_create(&server_addr,
222 MOUNTPROG, MOUNTVERS, &msock,
231 if (nfs_getport_ping((struct sockaddr *)&server_addr,
232 sizeof(server_addr), MOUNTPROG,
233 MOUNTVERS, IPPROTO_UDP)) {
234 clnt_pcreateerror("showmount");
238 pertry_timeout.tv_sec = TIMEOUT_UDP;
239 pertry_timeout.tv_usec = 0;
240 if ((mclient = clntudp_create(&server_addr,
241 MOUNTPROG, MOUNTVERS, pertry_timeout, &msock)) == NULL) {
242 clnt_pcreateerror("mount clntudp_create");
250 #endif /* HAVE_CLNT_CREATE */
252 int main(int argc, char **argv)
254 char hostname_buf[MAXHOSTLEN];
256 enum clnt_stat clnt_stat;
257 struct timeval total_timeout;
261 exports exportlist, exl;
269 program_name = argv[0];
270 while ((c = getopt_long(argc, argv, "adehv", longopts, NULL)) != EOF) {
285 printf("%s\n", version);
298 switch (aflag + dflag + eflag) {
305 fprintf(stderr, "%s: only one of -a, -d or -e is allowed\n",
313 if (gethostname(hostname_buf, MAXHOSTLEN) < 0) {
314 perror("getting hostname");
317 hostname = hostname_buf;
323 fprintf(stderr, "%s: only one hostname is allowed\n",
329 mclient = nfs_get_mount_client(hostname);
330 mclient->cl_auth = authunix_create_default();
331 total_timeout.tv_sec = TOTAL_TIMEOUT;
332 total_timeout.tv_usec = 0;
335 memset(&exportlist, '\0', sizeof(exportlist));
337 clnt_stat = clnt_call(mclient, MOUNTPROC_EXPORT,
338 (xdrproc_t) xdr_void, NULL,
339 (xdrproc_t) xdr_exports, (caddr_t) &exportlist,
341 if (clnt_stat != RPC_SUCCESS) {
342 clnt_perror(mclient, "rpc mount export");
343 clnt_destroy(mclient);
347 printf("Export list for %s:\n", hostname);
349 for (exl = exportlist; exl; exl = exl->ex_next) {
350 if ((n = strlen(exl->ex_dir)) > maxlen)
354 printf("%-*s ", maxlen, exportlist->ex_dir);
355 grouplist = exportlist->ex_groups;
358 printf("%s%s", grouplist->gr_name,
359 grouplist->gr_next ? "," : "");
360 grouplist = grouplist->gr_next;
363 printf("(everyone)");
365 exportlist = exportlist->ex_next;
367 clnt_destroy(mclient);
371 memset(&dumplist, '\0', sizeof(dumplist));
372 clnt_stat = clnt_call(mclient, MOUNTPROC_DUMP,
373 (xdrproc_t) xdr_void, NULL,
374 (xdrproc_t) xdr_mountlist, (caddr_t) &dumplist,
376 if (clnt_stat != RPC_SUCCESS) {
377 clnt_perror(mclient, "rpc mount dump");
378 clnt_destroy(mclient);
381 clnt_destroy(mclient);
384 for (list = dumplist; list; list = list->ml_next)
386 dumpv = (char **) calloc(n, sizeof (char *));
388 fprintf(stderr, "%s: out of memory\n", program_name);
395 printf("Hosts on %s:\n", hostname);
397 dumpv[i++] = dumplist->ml_hostname;
398 dumplist = dumplist->ml_next;
403 printf("All mount points on %s:\n", hostname);
407 t=malloc(strlen(dumplist->ml_hostname)+strlen(dumplist->ml_directory)+2);
410 fprintf(stderr, "%s: out of memory\n", program_name);
413 sprintf(t, "%s:%s", dumplist->ml_hostname, dumplist->ml_directory);
415 dumplist = dumplist->ml_next;
420 printf("Directories on %s:\n", hostname);
422 dumpv[i++] = dumplist->ml_directory;
423 dumplist = dumplist->ml_next;
427 qsort(dumpv, n, sizeof (char *), dump_cmp);
429 for (i = 0; i < n; i++) {
430 if (i == 0 || strcmp(dumpv[i], dumpv[i - 1]) != 0)
431 printf("%s\n", dumpv[i]);