diff options
Diffstat (limited to '')
-rw-r--r-- | utils/showmount/showmount.c | 323 |
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); +} + |