1*b985414bSchristos /* $NetBSD: showmount.c,v 1.23 2018/01/09 03:31:15 christos Exp $ */
20ac05e52Sjtc
361f28255Scgd /*
43f2b3b5aSjtc * Copyright (c) 1989, 1993, 1995
50ac05e52Sjtc * The Regents of the University of California. All rights reserved.
661f28255Scgd *
761f28255Scgd * This code is derived from software contributed to Berkeley by
861f28255Scgd * Rick Macklem at The University of Guelph.
961f28255Scgd *
1061f28255Scgd * Redistribution and use in source and binary forms, with or without
1161f28255Scgd * modification, are permitted provided that the following conditions
1261f28255Scgd * are met:
1361f28255Scgd * 1. Redistributions of source code must retain the above copyright
1461f28255Scgd * notice, this list of conditions and the following disclaimer.
1561f28255Scgd * 2. Redistributions in binary form must reproduce the above copyright
1661f28255Scgd * notice, this list of conditions and the following disclaimer in the
1761f28255Scgd * documentation and/or other materials provided with the distribution.
1889aaa1bbSagc * 3. Neither the name of the University nor the names of its contributors
1961f28255Scgd * may be used to endorse or promote products derived from this software
2061f28255Scgd * without specific prior written permission.
2161f28255Scgd *
2261f28255Scgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2361f28255Scgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2461f28255Scgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2561f28255Scgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2661f28255Scgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2761f28255Scgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2861f28255Scgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2961f28255Scgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3061f28255Scgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3161f28255Scgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3261f28255Scgd * SUCH DAMAGE.
3361f28255Scgd */
3461f28255Scgd
35cfd8831aSlukem #include <sys/cdefs.h>
3661f28255Scgd #ifndef lint
3798e5374cSlukem __COPYRIGHT("@(#) Copyright (c) 1989, 1993, 1995\
3898e5374cSlukem The Regents of the University of California. All rights reserved.");
39d594ce93Scgd #endif /* not lint */
4061f28255Scgd
4161f28255Scgd #ifndef lint
420ac05e52Sjtc #if 0
433f2b3b5aSjtc static char sccsid[] = "@(#)showmount.c 8.3 (Berkeley) 3/29/95";
440ac05e52Sjtc #endif
45*b985414bSchristos __RCSID("$NetBSD: showmount.c,v 1.23 2018/01/09 03:31:15 christos Exp $");
46d594ce93Scgd #endif /* not lint */
4761f28255Scgd
4861f28255Scgd #include <sys/types.h>
4961f28255Scgd #include <sys/file.h>
5061f28255Scgd #include <sys/socket.h>
513f2b3b5aSjtc
5261f28255Scgd #include <netdb.h>
5361f28255Scgd #include <rpc/rpc.h>
5461f28255Scgd #include <rpc/pmap_clnt.h>
5561f28255Scgd #include <rpc/pmap_prot.h>
5661f28255Scgd #include <nfs/rpcv2.h>
573f2b3b5aSjtc
5861f28255Scgd #include <stdio.h>
59424af298Scgd #include <stdlib.h>
6061f28255Scgd #include <string.h>
613f2b3b5aSjtc #include <unistd.h>
62*b985414bSchristos #include <err.h>
63*b985414bSchristos #include <vis.h>
6461f28255Scgd
6561f28255Scgd /* Constant defs */
6661f28255Scgd #define ALL 1
6761f28255Scgd #define DIRS 2
6861f28255Scgd
6961f28255Scgd #define DODUMP 0x1
7061f28255Scgd #define DOEXPORTS 0x2
71*b985414bSchristos #define DOPARSABLEEXPORTS 0x4
7261f28255Scgd
7361f28255Scgd struct mountlist {
7461f28255Scgd struct mountlist *ml_left;
7561f28255Scgd struct mountlist *ml_right;
7661f28255Scgd char ml_host[RPCMNT_NAMELEN+1];
7761f28255Scgd char ml_dirp[RPCMNT_PATHLEN+1];
7861f28255Scgd };
7961f28255Scgd
8061f28255Scgd struct grouplist {
8161f28255Scgd struct grouplist *gr_next;
8261f28255Scgd char gr_name[RPCMNT_NAMELEN+1];
8361f28255Scgd };
8461f28255Scgd
8561f28255Scgd struct exportslist {
8661f28255Scgd struct exportslist *ex_next;
8761f28255Scgd struct grouplist *ex_groups;
8861f28255Scgd char ex_dirp[RPCMNT_PATHLEN+1];
8961f28255Scgd };
9061f28255Scgd
9161f28255Scgd static struct mountlist *mntdump;
9261f28255Scgd static struct exportslist *exports;
9361f28255Scgd static int type = 0;
943f2b3b5aSjtc
95b480aed3Sjoerg static void print_dump(struct mountlist *);
96b480aed3Sjoerg __dead static void usage(void);
97b480aed3Sjoerg static int xdr_mntdump(XDR *, struct mountlist **);
98b480aed3Sjoerg static int xdr_exports(XDR *, struct exportslist **);
99b480aed3Sjoerg static int tcp_callrpc(const char *host, int prognum, int versnum,
100b480aed3Sjoerg int procnum, xdrproc_t inproc, char *in, xdrproc_t outproc, char *out);
10161f28255Scgd
10261f28255Scgd /*
103f0a7346dSsnj * This command queries the NFS mount daemon for its mount list and/or
104f0a7346dSsnj * its exports list and prints them out.
10561f28255Scgd * See "NFS: Network File System Protocol Specification, RFC1094, Appendix A"
1063f2b3b5aSjtc * and the "Network File System Protocol XXX.."
10761f28255Scgd * for detailed information on the protocol.
10861f28255Scgd */
1093f2b3b5aSjtc int
main(int argc,char ** argv)110b04eff35Srpaulo main(int argc, char **argv)
11161f28255Scgd {
1123f2b3b5aSjtc struct exportslist *exp;
1133f2b3b5aSjtc struct grouplist *grp;
1143f2b3b5aSjtc int estat, rpcs = 0, mntvers = 1;
115a2958081Slukem const char *host;
116f8fcb56bSmark int ch;
117e6333204Smsaitoh int len;
118*b985414bSchristos int nbytes;
119*b985414bSchristos char strvised[1024 * 4 + 1];
12061f28255Scgd
121*b985414bSchristos while ((ch = getopt(argc, argv, "adEe3")) != -1)
12261f28255Scgd switch((char)ch) {
12361f28255Scgd case 'a':
12461f28255Scgd if (type == 0) {
12561f28255Scgd type = ALL;
12661f28255Scgd rpcs |= DODUMP;
12761f28255Scgd } else
12861f28255Scgd usage();
12961f28255Scgd break;
13061f28255Scgd case 'd':
13161f28255Scgd if (type == 0) {
13261f28255Scgd type = DIRS;
13361f28255Scgd rpcs |= DODUMP;
13461f28255Scgd } else
13561f28255Scgd usage();
13661f28255Scgd break;
137*b985414bSchristos case 'E':
138*b985414bSchristos rpcs |= DOPARSABLEEXPORTS;
139*b985414bSchristos break;
14061f28255Scgd case 'e':
14161f28255Scgd rpcs |= DOEXPORTS;
14261f28255Scgd break;
1433f2b3b5aSjtc case '3':
1443f2b3b5aSjtc mntvers = 3;
1453f2b3b5aSjtc break;
14661f28255Scgd case '?':
14761f28255Scgd default:
14861f28255Scgd usage();
14961f28255Scgd }
15061f28255Scgd argc -= optind;
15161f28255Scgd argv += optind;
15261f28255Scgd
153*b985414bSchristos if ((rpcs & DOPARSABLEEXPORTS) != 0) {
154*b985414bSchristos if ((rpcs & DOEXPORTS) != 0)
155*b985414bSchristos errx(1, "-E cannot be used with -e");
156*b985414bSchristos if ((rpcs & DODUMP) != 0)
157*b985414bSchristos errx(1, "-E cannot be used with -a or -d");
158*b985414bSchristos }
159*b985414bSchristos
16061f28255Scgd if (argc > 0)
16161f28255Scgd host = *argv;
16261f28255Scgd else
16361f28255Scgd host = "localhost";
16461f28255Scgd
16561f28255Scgd if (rpcs == 0)
16661f28255Scgd rpcs = DODUMP;
16761f28255Scgd
16861f28255Scgd if (rpcs & DODUMP)
169de443fd9Smycroft if ((estat = tcp_callrpc(host, RPCPROG_MNT, mntvers,
170ed70d746Schristos RPCMNT_DUMP, (xdrproc_t)xdr_void, NULL,
17187d4f607Splunky (xdrproc_t)xdr_mntdump, (char *)&mntdump)) != 0) {
172d0ec1c6bScgd fprintf(stderr, "showmount: Can't do Mountdump rpc: ");
17361f28255Scgd clnt_perrno(estat);
17461f28255Scgd exit(1);
17561f28255Scgd }
176*b985414bSchristos if (rpcs & (DOEXPORTS | DOPARSABLEEXPORTS))
177de443fd9Smycroft if ((estat = tcp_callrpc(host, RPCPROG_MNT, mntvers,
178ed70d746Schristos RPCMNT_EXPORT, (xdrproc_t)xdr_void, NULL,
17987d4f607Splunky (xdrproc_t)xdr_exports, (char *)&exports)) != 0) {
180d0ec1c6bScgd fprintf(stderr, "showmount: Can't do Exports rpc: ");
18161f28255Scgd clnt_perrno(estat);
18261f28255Scgd exit(1);
18361f28255Scgd }
18461f28255Scgd
18561f28255Scgd /* Now just print out the results */
18661f28255Scgd if (rpcs & DODUMP) {
18761f28255Scgd switch (type) {
18861f28255Scgd case ALL:
18961f28255Scgd printf("All mount points on %s:\n", host);
19061f28255Scgd break;
19161f28255Scgd case DIRS:
19261f28255Scgd printf("Directories on %s:\n", host);
19361f28255Scgd break;
19461f28255Scgd default:
19561f28255Scgd printf("Hosts on %s:\n", host);
19661f28255Scgd break;
19761f28255Scgd };
19861f28255Scgd print_dump(mntdump);
19961f28255Scgd }
20061f28255Scgd if (rpcs & DOEXPORTS) {
20161f28255Scgd printf("Exports list on %s:\n", host);
20261f28255Scgd exp = exports;
20361f28255Scgd while (exp) {
204e6333204Smsaitoh len = printf("%-35s", exp->ex_dirp);
205e6333204Smsaitoh if (len > 35)
206e6333204Smsaitoh printf("\t");
20761f28255Scgd grp = exp->ex_groups;
20861f28255Scgd if (grp == NULL) {
20961f28255Scgd printf("Everyone\n");
21061f28255Scgd } else {
21161f28255Scgd while (grp) {
21261f28255Scgd printf("%s ", grp->gr_name);
21361f28255Scgd grp = grp->gr_next;
21461f28255Scgd }
21561f28255Scgd printf("\n");
21661f28255Scgd }
21761f28255Scgd exp = exp->ex_next;
21861f28255Scgd }
21961f28255Scgd }
220*b985414bSchristos if (rpcs & DOPARSABLEEXPORTS) {
221*b985414bSchristos exp = exports;
222*b985414bSchristos while (exp) {
223*b985414bSchristos nbytes = strnvis(strvised, sizeof(strvised),
224*b985414bSchristos exp->ex_dirp, VIS_GLOB | VIS_NL);
225*b985414bSchristos if (nbytes == -1)
226*b985414bSchristos err(1, "strsnvis");
227*b985414bSchristos printf("%s\n", strvised);
228*b985414bSchristos exp = exp->ex_next;
229*b985414bSchristos }
230*b985414bSchristos }
2313f2b3b5aSjtc exit(0);
23261f28255Scgd }
23361f28255Scgd
23461f28255Scgd /*
235de443fd9Smycroft * tcp_callrpc has the same interface as callrpc, but tries to
236de443fd9Smycroft * use tcp as transport method in order to handle large replies.
237de443fd9Smycroft */
238de443fd9Smycroft
239b480aed3Sjoerg static int
tcp_callrpc(const char * host,int prognum,int versnum,int procnum,xdrproc_t inproc,char * in,xdrproc_t outproc,char * out)240b04eff35Srpaulo tcp_callrpc(const char *host, int prognum, int versnum, int procnum,
241b04eff35Srpaulo xdrproc_t inproc, char *in, xdrproc_t outproc, char *out)
242de443fd9Smycroft {
243de443fd9Smycroft CLIENT *client;
244de443fd9Smycroft struct timeval timeout;
245de443fd9Smycroft int rval;
246de443fd9Smycroft
247ff2bab1cSrpaulo if ((client = clnt_create(host, prognum, versnum, "tcp")) == NULL &&
248ff2bab1cSrpaulo (client = clnt_create(host, prognum, versnum, "udp")) == NULL)
249de443fd9Smycroft return ((int) rpc_createerr.cf_stat);
250de443fd9Smycroft
251de443fd9Smycroft timeout.tv_sec = 25;
252de443fd9Smycroft timeout.tv_usec = 0;
253de443fd9Smycroft rval = (int) clnt_call(client, procnum,
254de443fd9Smycroft inproc, in,
255de443fd9Smycroft outproc, out,
256de443fd9Smycroft timeout);
257de443fd9Smycroft clnt_destroy(client);
258de443fd9Smycroft return rval;
259de443fd9Smycroft }
260de443fd9Smycroft
261ed70d746Schristos static void
mountlist_free(struct mountlist * ml)262ed70d746Schristos mountlist_free(struct mountlist *ml)
263ed70d746Schristos {
264ed70d746Schristos if (ml == NULL)
265ed70d746Schristos return;
266ed70d746Schristos mountlist_free(ml->ml_left);
267ed70d746Schristos mountlist_free(ml->ml_right);
268ed70d746Schristos free(ml);
269ed70d746Schristos }
270ed70d746Schristos
271de443fd9Smycroft /*
27261f28255Scgd * Xdr routine for retrieving the mount dump list
27361f28255Scgd */
274b480aed3Sjoerg static int
xdr_mntdump(XDR * xdrsp,struct mountlist ** mlp)275b04eff35Srpaulo xdr_mntdump(XDR *xdrsp, struct mountlist **mlp)
27661f28255Scgd {
2773f2b3b5aSjtc struct mountlist *mp, **otp, *tp;
278336c1525Smbalmer int bool_int, val, val2;
27961f28255Scgd char *strp;
28061f28255Scgd
281cfd8831aSlukem otp = NULL;
282ed70d746Schristos *mlp = NULL;
283336c1525Smbalmer if (!xdr_bool(xdrsp, &bool_int))
284ed70d746Schristos return 0;
285336c1525Smbalmer while (bool_int) {
286ed70d746Schristos mp = malloc(sizeof(*mp));
28761f28255Scgd if (mp == NULL)
288ed70d746Schristos goto out;
289ed70d746Schristos mp->ml_left = mp->ml_right = NULL;
29061f28255Scgd strp = mp->ml_host;
291ed70d746Schristos if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) {
292ed70d746Schristos free(mp);
293ed70d746Schristos goto out;
294ed70d746Schristos }
29561f28255Scgd strp = mp->ml_dirp;
296ed70d746Schristos if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) {
297ed70d746Schristos free(mp);
298ed70d746Schristos goto out;
299ed70d746Schristos }
30061f28255Scgd
30161f28255Scgd /*
30261f28255Scgd * Build a binary tree on sorted order of either host or dirp.
30361f28255Scgd * Drop any duplications.
30461f28255Scgd */
30561f28255Scgd if (*mlp == NULL) {
30661f28255Scgd *mlp = mp;
30761f28255Scgd } else {
30861f28255Scgd tp = *mlp;
30961f28255Scgd while (tp) {
31061f28255Scgd val = strcmp(mp->ml_host, tp->ml_host);
31161f28255Scgd val2 = strcmp(mp->ml_dirp, tp->ml_dirp);
31261f28255Scgd switch (type) {
31361f28255Scgd case ALL:
31461f28255Scgd if (val == 0) {
31561f28255Scgd if (val2 == 0) {
316ed70d746Schristos free(mp);
31761f28255Scgd goto next;
31861f28255Scgd }
31961f28255Scgd val = val2;
32061f28255Scgd }
32161f28255Scgd break;
32261f28255Scgd case DIRS:
32361f28255Scgd if (val2 == 0) {
324ed70d746Schristos free(mp);
32561f28255Scgd goto next;
32661f28255Scgd }
32761f28255Scgd val = val2;
32861f28255Scgd break;
32961f28255Scgd default:
33061f28255Scgd if (val == 0) {
331ed70d746Schristos free(mp);
33261f28255Scgd goto next;
33361f28255Scgd }
33461f28255Scgd break;
33561f28255Scgd };
33661f28255Scgd if (val < 0) {
33761f28255Scgd otp = &tp->ml_left;
33861f28255Scgd tp = tp->ml_left;
33961f28255Scgd } else {
34061f28255Scgd otp = &tp->ml_right;
34161f28255Scgd tp = tp->ml_right;
34261f28255Scgd }
34361f28255Scgd }
34461f28255Scgd *otp = mp;
34561f28255Scgd }
34661f28255Scgd next:
347336c1525Smbalmer if (!xdr_bool(xdrsp, &bool_int))
348ed70d746Schristos goto out;
34961f28255Scgd }
350ed70d746Schristos return 1;
351ed70d746Schristos out:
352ed70d746Schristos mountlist_free(*mlp);
353ed70d746Schristos return 0;
354ed70d746Schristos }
355ed70d746Schristos
356ed70d746Schristos static void
grouplist_free(struct grouplist * gp)357ed70d746Schristos grouplist_free(struct grouplist *gp)
358ed70d746Schristos {
359ed70d746Schristos if (gp == NULL)
360ed70d746Schristos return;
361ed70d746Schristos grouplist_free(gp->gr_next);
362ed70d746Schristos free(gp);
363ed70d746Schristos }
364ed70d746Schristos
365ed70d746Schristos static void
exportslist_free(struct exportslist * ep)366ed70d746Schristos exportslist_free(struct exportslist *ep)
367ed70d746Schristos {
368ed70d746Schristos if (ep == NULL)
369ed70d746Schristos return;
370ed70d746Schristos exportslist_free(ep->ex_next);
371ed70d746Schristos grouplist_free(ep->ex_groups);
372ed70d746Schristos free(ep);
37361f28255Scgd }
37461f28255Scgd
37561f28255Scgd /*
37661f28255Scgd * Xdr routine to retrieve exports list
37761f28255Scgd */
378b480aed3Sjoerg static int
xdr_exports(XDR * xdrsp,struct exportslist ** exp)379b04eff35Srpaulo xdr_exports(XDR *xdrsp, struct exportslist **exp)
38061f28255Scgd {
381ed70d746Schristos struct exportslist *ep = NULL;
3823f2b3b5aSjtc struct grouplist *gp;
383336c1525Smbalmer int bool_int, grpbool;
38461f28255Scgd char *strp;
38561f28255Scgd
386ed70d746Schristos *exp = NULL;
387336c1525Smbalmer if (!xdr_bool(xdrsp, &bool_int))
388ed70d746Schristos return 0;
389336c1525Smbalmer while (bool_int) {
390ed70d746Schristos ep = malloc(sizeof(*ep));
39161f28255Scgd if (ep == NULL)
392ed70d746Schristos goto out;
393ed70d746Schristos ep->ex_groups = NULL;
39461f28255Scgd strp = ep->ex_dirp;
39561f28255Scgd if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
396ed70d746Schristos goto out;
39761f28255Scgd if (!xdr_bool(xdrsp, &grpbool))
398ed70d746Schristos goto out;
39961f28255Scgd while (grpbool) {
400ed70d746Schristos gp = malloc(sizeof(*gp));
40161f28255Scgd if (gp == NULL)
402ed70d746Schristos goto out;
40361f28255Scgd gp->gr_next = ep->ex_groups;
40461f28255Scgd ep->ex_groups = gp;
405ed70d746Schristos strp = gp->gr_name;
406ed70d746Schristos if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN))
407ed70d746Schristos goto out;
40861f28255Scgd if (!xdr_bool(xdrsp, &grpbool))
409ed70d746Schristos goto out;
41061f28255Scgd }
41161f28255Scgd ep->ex_next = *exp;
41261f28255Scgd *exp = ep;
413ed70d746Schristos ep = NULL;
414336c1525Smbalmer if (!xdr_bool(xdrsp, &bool_int))
415ed70d746Schristos goto out;
41661f28255Scgd }
417ed70d746Schristos return 1;
418ed70d746Schristos out:
419ed70d746Schristos exportslist_free(ep);
420ed70d746Schristos exportslist_free(*exp);
421ed70d746Schristos return 0;
42261f28255Scgd }
42361f28255Scgd
424b480aed3Sjoerg static void
usage(void)425b480aed3Sjoerg usage(void)
42661f28255Scgd {
4273f2b3b5aSjtc
428d0ec1c6bScgd fprintf(stderr, "usage: showmount [-ade3] host\n");
42961f28255Scgd exit(1);
43061f28255Scgd }
43161f28255Scgd
43261f28255Scgd /*
43361f28255Scgd * Print the binary tree in inorder so that output is sorted.
43461f28255Scgd */
435b480aed3Sjoerg static void
print_dump(struct mountlist * mp)436b04eff35Srpaulo print_dump(struct mountlist *mp)
43761f28255Scgd {
43861f28255Scgd
43961f28255Scgd if (mp == NULL)
44061f28255Scgd return;
44161f28255Scgd if (mp->ml_left)
44261f28255Scgd print_dump(mp->ml_left);
44361f28255Scgd switch (type) {
44461f28255Scgd case ALL:
44561f28255Scgd printf("%s:%s\n", mp->ml_host, mp->ml_dirp);
44661f28255Scgd break;
44761f28255Scgd case DIRS:
44861f28255Scgd printf("%s\n", mp->ml_dirp);
44961f28255Scgd break;
45061f28255Scgd default:
45161f28255Scgd printf("%s\n", mp->ml_host);
45261f28255Scgd break;
45361f28255Scgd };
45461f28255Scgd if (mp->ml_right)
45561f28255Scgd print_dump(mp->ml_right);
45661f28255Scgd }
457