summaryrefslogtreecommitdiffstats
path: root/utils/showmount/showmount.c
diff options
context:
space:
mode:
Diffstat (limited to 'utils/showmount/showmount.c')
-rw-r--r--utils/showmount/showmount.c323
1 files changed, 323 insertions, 0 deletions
diff --git a/utils/showmount/showmount.c b/utils/showmount/showmount.c
new file mode 100644
index 0000000..394f528
--- /dev/null
+++ b/utils/showmount/showmount.c
@@ -0,0 +1,323 @@
+/*
+ * showmount.c -- show mount information for an NFS server
+ * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <rpc/rpc.h>
+#include <rpc/pmap_prot.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/time.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <memory.h>
+#include <stdlib.h>
+#include <fcntl.h>
+
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <getopt.h>
+#include <mount.h>
+#include <unistd.h>
+
+#include "nfsrpc.h"
+
+#define TIMEOUT_UDP 3
+#define TOTAL_TIMEOUT 20
+
+static char * version = "showmount for " VERSION;
+static char * program_name;
+static int headers = 1;
+static int hflag = 0;
+static int aflag = 0;
+static int dflag = 0;
+static int eflag = 0;
+
+static struct option longopts[] =
+{
+ { "all", 0, 0, 'a' },
+ { "directories", 0, 0, 'd' },
+ { "exports", 0, 0, 'e' },
+ { "no-headers", 0, &headers, 0 },
+ { "version", 0, 0, 'v' },
+ { "help", 0, 0, 'h' },
+ { NULL, 0, 0, 0 }
+};
+
+#define MAXHOSTLEN 256
+
+static int dump_cmp(const void *pv, const void *qv)
+{
+ const char **p = (const char **)pv;
+ const char **q = (const char **)qv;
+ return strcmp(*p, *q);
+}
+
+static void usage(FILE *fp, int n)
+{
+ fprintf(fp, "Usage: %s [-adehv]\n", program_name);
+ fprintf(fp, " [--all] [--directories] [--exports]\n");
+ fprintf(fp, " [--no-headers] [--help] [--version] [host]\n");
+ exit(n);
+}
+
+static const char *mount_pgm_tbl[] = {
+ "showmount",
+ "mount",
+ "mountd",
+ NULL,
+};
+
+static const rpcvers_t mount_vers_tbl[] = {
+ MOUNTVERS_NFSV3,
+ MOUNTVERS_POSIX,
+ MOUNTVERS,
+};
+static const unsigned int max_vers_tblsz =
+ (sizeof(mount_vers_tbl)/sizeof(mount_vers_tbl[0]));
+
+/*
+ * Generate an RPC client handle connected to the mountd service
+ * at @hostname, or die trying.
+ *
+ * Supports both AF_INET and AF_INET6 server addresses.
+ */
+static CLIENT *nfs_get_mount_client(const char *hostname, rpcvers_t vers)
+{
+ rpcprog_t program = nfs_getrpcbyname(MOUNTPROG, mount_pgm_tbl);
+ CLIENT *client;
+
+ client = clnt_create(hostname, program, vers, "tcp");
+ if (client)
+ return client;
+ client = clnt_create(hostname, program, vers, "udp");
+ if (client)
+ return client;
+
+ clnt_pcreateerror("clnt_create");
+ exit(1);
+}
+
+int main(int argc, char **argv)
+{
+ char hostname_buf[MAXHOSTLEN];
+ char *hostname;
+ enum clnt_stat clnt_stat;
+ struct timeval total_timeout;
+ int c;
+ CLIENT *mclient;
+ groups grouplist;
+ exports exportlist, exl;
+ mountlist dumplist;
+ mountlist list;
+ int i;
+ int n;
+ int maxlen;
+ int unsigned vers=0;
+ char **dumpv;
+
+ program_name = argv[0];
+ while ((c = getopt_long(argc, argv, "adehv", longopts, NULL)) != EOF) {
+ switch (c) {
+ case 'a':
+ aflag = 1;
+ break;
+ case 'd':
+ dflag = 1;
+ break;
+ case 'e':
+ eflag = 1;
+ break;
+ case 'h':
+ usage(stdout, 0);
+ break;
+ case 'v':
+ printf("%s\n", version);
+ exit(0);
+ case 0:
+ break;
+ case '?':
+ default:
+ usage(stderr, 1);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ switch (aflag + dflag + eflag) {
+ case 0:
+ hflag = 1;
+ break;
+ case 1:
+ break;
+ default:
+ fprintf(stderr, "%s: only one of -a, -d or -e is allowed\n",
+ program_name);
+ exit(1);
+ break;
+ }
+
+ switch (argc) {
+ case 0:
+ if (gethostname(hostname_buf, MAXHOSTLEN) < 0) {
+ perror("getting hostname");
+ exit(1);
+ }
+ hostname = hostname_buf;
+ break;
+ case 1:
+ hostname = argv[0];
+ break;
+ default:
+ fprintf(stderr, "%s: only one hostname is allowed\n",
+ program_name);
+ exit(1);
+ break;
+ }
+
+ mclient = nfs_get_mount_client(hostname, mount_vers_tbl[vers]);
+ mclient->cl_auth = nfs_authsys_create();
+ if (mclient->cl_auth == NULL) {
+ fprintf(stderr, "%s: unable to create RPC auth handle.\n",
+ program_name);
+ clnt_destroy(mclient);
+ exit(1);
+ }
+ total_timeout.tv_sec = TOTAL_TIMEOUT;
+ total_timeout.tv_usec = 0;
+
+again:
+ if (eflag) {
+ memset(&exportlist, '\0', sizeof(exportlist));
+
+ clnt_stat = clnt_call(mclient, MOUNTPROC_EXPORT,
+ (xdrproc_t) xdr_void, NULL,
+ (xdrproc_t) xdr_exports, (caddr_t) &exportlist,
+ total_timeout);
+ if (clnt_stat == RPC_PROGVERSMISMATCH) {
+ if (++vers < max_vers_tblsz) {
+ (void)CLNT_CONTROL(mclient, CLSET_VERS,
+ (void *)&mount_vers_tbl[vers]);
+ goto again;
+ }
+ }
+ if (clnt_stat != RPC_SUCCESS) {
+ clnt_perror(mclient, "rpc mount export");
+ clnt_destroy(mclient);
+ exit(1);
+ }
+ if (headers)
+ printf("Export list for %s:\n", hostname);
+ maxlen = 0;
+ for (exl = exportlist; exl; exl = exl->ex_next) {
+ if ((n = strlen(exl->ex_dir)) > maxlen)
+ maxlen = n;
+ }
+ while (exportlist) {
+ printf("%-*s ", maxlen, exportlist->ex_dir);
+ grouplist = exportlist->ex_groups;
+ if (grouplist)
+ while (grouplist) {
+ printf("%s%s", grouplist->gr_name,
+ grouplist->gr_next ? "," : "");
+ grouplist = grouplist->gr_next;
+ }
+ else
+ printf("(everyone)");
+ printf("\n");
+ exportlist = exportlist->ex_next;
+ }
+ clnt_destroy(mclient);
+ exit(0);
+ }
+
+ memset(&dumplist, '\0', sizeof(dumplist));
+ clnt_stat = clnt_call(mclient, MOUNTPROC_DUMP,
+ (xdrproc_t) xdr_void, NULL,
+ (xdrproc_t) xdr_mountlist, (caddr_t) &dumplist,
+ total_timeout);
+ if (clnt_stat == RPC_PROGVERSMISMATCH) {
+ if (++vers < max_vers_tblsz) {
+ (void)CLNT_CONTROL(mclient, CLSET_VERS,
+ (void *)&mount_vers_tbl[vers]);
+ goto again;
+ }
+ }
+ if (clnt_stat != RPC_SUCCESS) {
+ clnt_perror(mclient, "rpc mount dump");
+ clnt_destroy(mclient);
+ exit(1);
+ }
+ clnt_destroy(mclient);
+
+ n = 0;
+ for (list = dumplist; list; list = list->ml_next)
+ n++;
+ dumpv = (char **) calloc(n, sizeof (char *));
+ if (n && !dumpv) {
+ fprintf(stderr, "%s: out of memory\n", program_name);
+ exit(1);
+ }
+ i = 0;
+
+ if (hflag) {
+ if (headers)
+ printf("Hosts on %s:\n", hostname);
+ while (dumplist) {
+ dumpv[i++] = dumplist->ml_hostname;
+ dumplist = dumplist->ml_next;
+ }
+ }
+ else if (aflag) {
+ if (headers)
+ printf("All mount points on %s:\n", hostname);
+ while (dumplist) {
+ char *t;
+
+ t=malloc(strlen(dumplist->ml_hostname)+strlen(dumplist->ml_directory)+2);
+ if (!t)
+ {
+ fprintf(stderr, "%s: out of memory\n", program_name);
+ exit(1);
+ }
+ sprintf(t, "%s:%s", dumplist->ml_hostname, dumplist->ml_directory);
+ dumpv[i++] = t;
+ dumplist = dumplist->ml_next;
+ }
+ }
+ else if (dflag) {
+ if (headers)
+ printf("Directories on %s:\n", hostname);
+ while (dumplist) {
+ dumpv[i++] = dumplist->ml_directory;
+ dumplist = dumplist->ml_next;
+ }
+ }
+
+ qsort(dumpv, n, sizeof (char *), dump_cmp);
+
+ for (i = 0; i < n; i++) {
+ if (i == 0 || strcmp(dumpv[i], dumpv[i - 1]) != 0)
+ printf("%s\n", dumpv[i]);
+ }
+ exit(0);
+}
+