nfsidmap: Added Error Logging
[nfs-utils.git] / utils / showmount / showmount.c
1 /*
2  * showmount.c -- show mount information for an NFS server
3  * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
4  *
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)
8  * any later version.
9  *
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.
14  */
15
16 #ifdef HAVE_CONFIG_H
17 #include <config.h>
18 #endif
19
20 #include <stdio.h>
21 #include <rpc/rpc.h>
22 #include <rpc/pmap_prot.h>
23 #include <sys/socket.h>
24 #include <netinet/in.h>
25 #include <sys/time.h>
26 #include <string.h>
27 #include <sys/types.h>
28 #include <unistd.h>
29 #include <memory.h>
30 #include <stdlib.h>
31 #include <fcntl.h>
32
33 #include <netdb.h>
34 #include <arpa/inet.h>
35 #include <errno.h>
36 #include <getopt.h>
37 #include <mount.h>
38 #include <unistd.h>
39
40 #include "nfsrpc.h"
41
42 #define TIMEOUT_UDP     3
43 #define TOTAL_TIMEOUT   20
44
45 static char *   version = "showmount for " VERSION;
46 static char *   program_name;
47 static int      headers = 1;
48 static int      hflag = 0;
49 static int      aflag = 0;
50 static int      dflag = 0;
51 static int      eflag = 0;
52
53 static struct option longopts[] =
54 {
55         { "all", 0, 0, 'a' },
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' },
61         { NULL, 0, 0, 0 }
62 };
63
64 #define MAXHOSTLEN 256
65
66 static int dump_cmp(const void *pv, const void *qv)
67 {
68         const char **p = (const char **)pv;
69         const char **q = (const char **)qv;
70         return strcmp(*p, *q);
71 }
72
73 static void usage(FILE *fp, int n)
74 {
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");
78         exit(n);
79 }
80
81 static const char *mount_pgm_tbl[] = {
82         "showmount",
83         "mount",
84         "mountd",
85         NULL,
86 };
87
88 static const rpcvers_t mount_vers_tbl[] = {
89         MOUNTVERS_NFSV3,
90         MOUNTVERS_POSIX,
91         MOUNTVERS,
92 };
93 static const unsigned int max_vers_tblsz = 
94         (sizeof(mount_vers_tbl)/sizeof(mount_vers_tbl[0]));
95
96 /*
97  * Generate an RPC client handle connected to the mountd service
98  * at @hostname, or die trying.
99  *
100  * Supports both AF_INET and AF_INET6 server addresses.
101  */
102 static CLIENT *nfs_get_mount_client(const char *hostname, rpcvers_t vers)
103 {
104         rpcprog_t program = nfs_getrpcbyname(MOUNTPROG, mount_pgm_tbl);
105         CLIENT *client;
106
107         client = clnt_create(hostname, program, vers, "tcp");
108         if (client)
109                 return client;
110         client = clnt_create(hostname, program, vers, "udp");
111         if (client)
112                 return client;
113
114         clnt_pcreateerror("clnt_create");
115         exit(1);
116 }
117
118 int main(int argc, char **argv)
119 {
120         char hostname_buf[MAXHOSTLEN];
121         char *hostname;
122         enum clnt_stat clnt_stat;
123         struct timeval total_timeout;
124         int c;
125         CLIENT *mclient;
126         groups grouplist;
127         exports exportlist, exl;
128         mountlist dumplist;
129         mountlist list;
130         int i;
131         int n;
132         int maxlen;
133         int unsigned vers=0;
134         char **dumpv;
135
136         program_name = argv[0];
137         while ((c = getopt_long(argc, argv, "adehv", longopts, NULL)) != EOF) {
138                 switch (c) {
139                 case 'a':
140                         aflag = 1;
141                         break;
142                 case 'd':
143                         dflag = 1;
144                         break;
145                 case 'e':
146                         eflag = 1;
147                         break;
148                 case 'h':
149                         usage(stdout, 0);
150                         break;
151                 case 'v':
152                         printf("%s\n", version);
153                         exit(0);
154                 case 0:
155                         break;
156                 case '?':
157                 default:
158                         usage(stderr, 1);
159                         break;
160                 }
161         }
162         argc -= optind;
163         argv += optind;
164
165         switch (aflag + dflag + eflag) {
166         case 0:
167                 hflag = 1;
168                 break;
169         case 1:
170                 break;
171         default:
172                 fprintf(stderr, "%s: only one of -a, -d or -e is allowed\n",
173                         program_name);
174                 exit(1);
175                 break;
176         }
177
178         switch (argc) {
179         case 0:
180                 if (gethostname(hostname_buf, MAXHOSTLEN) < 0) {
181                         perror("getting hostname");
182                         exit(1);
183                 }
184                 hostname = hostname_buf;
185                 break;
186         case 1:
187                 hostname = argv[0];
188                 break;
189         default:
190                 fprintf(stderr, "%s: only one hostname is allowed\n",
191                         program_name);
192                 exit(1);
193                 break;
194         }
195
196         mclient = nfs_get_mount_client(hostname, mount_vers_tbl[vers]);
197         mclient->cl_auth = nfs_authsys_create();
198         if (mclient->cl_auth == NULL) {
199                 fprintf(stderr, "%s: unable to create RPC auth handle.\n",
200                                 program_name);
201                 clnt_destroy(mclient);
202                 exit(1);
203         }
204         total_timeout.tv_sec = TOTAL_TIMEOUT;
205         total_timeout.tv_usec = 0;
206
207 again:
208         if (eflag) {
209                 memset(&exportlist, '\0', sizeof(exportlist));
210
211                 clnt_stat = clnt_call(mclient, MOUNTPROC_EXPORT,
212                         (xdrproc_t) xdr_void, NULL,
213                         (xdrproc_t) xdr_exports, (caddr_t) &exportlist,
214                         total_timeout);
215                 if (clnt_stat == RPC_PROGVERSMISMATCH) {
216                         if (++vers <  max_vers_tblsz) {
217                                 (void)CLNT_CONTROL(mclient, CLSET_VERS, 
218                                         (void *)&mount_vers_tbl[vers]);
219                                 goto again;
220                                 }
221                 }
222                 if (clnt_stat != RPC_SUCCESS) {
223                         clnt_perror(mclient, "rpc mount export");
224                         clnt_destroy(mclient);
225                         exit(1);
226                 }
227                 if (headers)
228                         printf("Export list for %s:\n", hostname);
229                 maxlen = 0;
230                 for (exl = exportlist; exl; exl = exl->ex_next) {
231                         if ((n = strlen(exl->ex_dir)) > maxlen)
232                                 maxlen = n;
233                 }
234                 while (exportlist) {
235                         printf("%-*s ", maxlen, exportlist->ex_dir);
236                         grouplist = exportlist->ex_groups;
237                         if (grouplist)
238                                 while (grouplist) {
239                                         printf("%s%s", grouplist->gr_name,
240                                                 grouplist->gr_next ? "," : "");
241                                         grouplist = grouplist->gr_next;
242                                 }
243                         else
244                                 printf("(everyone)");
245                         printf("\n");
246                         exportlist = exportlist->ex_next;
247                 }
248                 clnt_destroy(mclient);
249                 exit(0);
250         }
251
252         memset(&dumplist, '\0', sizeof(dumplist));
253         clnt_stat = clnt_call(mclient, MOUNTPROC_DUMP,
254                 (xdrproc_t) xdr_void, NULL,
255                 (xdrproc_t) xdr_mountlist, (caddr_t) &dumplist,
256                 total_timeout);
257         if (clnt_stat == RPC_PROGVERSMISMATCH) {
258                 if (++vers <  max_vers_tblsz) {
259                         (void)CLNT_CONTROL(mclient, CLSET_VERS, 
260                                 (void *)&mount_vers_tbl[vers]);
261                         goto again;
262                 }
263         }
264         if (clnt_stat != RPC_SUCCESS) {
265                 clnt_perror(mclient, "rpc mount dump");
266                 clnt_destroy(mclient);
267                 exit(1);
268         }
269         clnt_destroy(mclient);
270
271         n = 0;
272         for (list = dumplist; list; list = list->ml_next)
273                 n++;
274         dumpv = (char **) calloc(n, sizeof (char *));
275         if (n && !dumpv) {
276                 fprintf(stderr, "%s: out of memory\n", program_name);
277                 exit(1);
278         }
279         i = 0;
280
281         if (hflag) {
282                 if (headers)
283                         printf("Hosts on %s:\n", hostname);
284                 while (dumplist) {
285                         dumpv[i++] = dumplist->ml_hostname;
286                         dumplist = dumplist->ml_next;
287                 }
288         }
289         else if (aflag) {
290                 if (headers)
291                         printf("All mount points on %s:\n", hostname);
292                 while (dumplist) {
293                         char *t;
294
295                         t=malloc(strlen(dumplist->ml_hostname)+strlen(dumplist->ml_directory)+2);
296                         if (!t)
297                         {
298                                 fprintf(stderr, "%s: out of memory\n", program_name);
299                                 exit(1);
300                         }
301                         sprintf(t, "%s:%s", dumplist->ml_hostname, dumplist->ml_directory);
302                         dumpv[i++] = t;
303                         dumplist = dumplist->ml_next;
304                 }
305         }
306         else if (dflag) {
307                 if (headers)
308                         printf("Directories on %s:\n", hostname);
309                 while (dumplist) {
310                         dumpv[i++] = dumplist->ml_directory;
311                         dumplist = dumplist->ml_next;
312                 }
313         }
314
315         qsort(dumpv, n, sizeof (char *), dump_cmp);
316         
317         for (i = 0; i < n; i++) {
318                 if (i == 0 || strcmp(dumpv[i], dumpv[i - 1]) != 0)
319                         printf("%s\n", dumpv[i]);
320         }
321         exit(0);
322 }
323