showmount.c revision 1160694128cd3980cc06abe31af529a887efd310
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* University Copyright- Copyright (c) 1982, 1986, 1988
* The Regents of the University of California
* All Rights Reserved
*
* University Acknowledgment- Portions of this document are derived from
* software developed by the University of California, Berkeley, and its
* contributors.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* showmount
*/
#include <stdio.h>
#include <stdarg.h>
#include <rpc/rpc.h>
#include <rpc/rpcb_clnt.h>
#include <sys/socket.h>
#include <netdb.h>
#include <sys/time.h>
#include <errno.h>
#include <nfs/nfs.h>
#include <rpcsvc/mount.h>
#include <locale.h>
int sorthost();
int sortpath();
void pr_err(char *, ...);
void printex();
void usage();
/*
* Dynamically-sized array of pointers to mountlist entries. Each element
* points into the linked list returned by the RPC call. We use an array
* so that we can conveniently sort the entries.
*/
static struct mountbody **table;
struct timeval rpc_totout_new = {15, 0};
int
main(int argc, char *argv[])
{
int aflg = 0, dflg = 0, eflg = 0;
int err;
struct mountbody *result_list = NULL;
struct mountbody *ml = NULL;
struct mountbody **tb; /* pointer into table */
char *host, hostbuf[256];
char *last;
CLIENT *cl;
extern int optind;
extern char *optarg;
int c;
struct timeval tout, rpc_totout_old;
int numentries;
(void) setlocale(LC_ALL, "");
#if !defined(TEXT_DOMAIN)
#define TEXT_DOMAIN "SYS_TEST"
#endif
(void) textdomain(TEXT_DOMAIN);
while ((c = getopt(argc, argv, "ade")) != EOF) {
switch (c) {
case 'a':
aflg++;
break;
case 'd':
dflg++;
break;
case 'e':
eflg++;
break;
default:
usage();
exit(1);
}
}
switch (argc - optind) {
case 0: /* no args */
if (gethostname(hostbuf, sizeof (hostbuf)) < 0) {
pr_err("gethostname: %s\n", strerror(errno));
exit(1);
}
host = hostbuf;
break;
case 1: /* one arg */
host = argv[optind];
break;
default: /* too many args */
usage();
exit(1);
}
__rpc_control(CLCR_GET_RPCB_TIMEOUT, &rpc_totout_old);
__rpc_control(CLCR_SET_RPCB_TIMEOUT, &rpc_totout_new);
/*
* First try circuit, then drop back to datagram if
* circuit is unavailable (an old version of mountd perhaps)
* Using circuit is preferred because it can handle
* arbitrarily long export lists.
*/
cl = clnt_create(host, MOUNTPROG, MOUNTVERS, "circuit_n");
if (cl == NULL) {
if (rpc_createerr.cf_stat == RPC_PROGNOTREGISTERED)
cl = clnt_create(host, MOUNTPROG, MOUNTVERS,
"datagram_n");
if (cl == NULL) {
pr_err("");
clnt_pcreateerror(host);
__rpc_control(CLCR_SET_RPCB_TIMEOUT, &rpc_totout_old);
exit(1);
}
}
__rpc_control(CLCR_SET_RPCB_TIMEOUT, &rpc_totout_old);
if (eflg) {
printex(cl, host);
if (aflg + dflg == 0) {
exit(0);
}
}
tout.tv_sec = 10;
tout.tv_usec = 0;
if (err = clnt_call(cl, MOUNTPROC_DUMP,
xdr_void, 0, xdr_mountlist,
(caddr_t)&result_list, tout)) {
pr_err("%s\n", clnt_sperrno(err));
exit(1);
}
/*
* Count the number of entries in the list. If the list is empty,
* quit now.
*/
numentries = 0;
for (ml = result_list; ml != NULL; ml = ml->ml_next)
numentries++;
if (numentries == 0)
exit(0);
/*
* Allocate memory for the array and initialize the array.
*/
table = (struct mountbody **)calloc(numentries,
sizeof (struct mountbody *));
if (table == NULL) {
pr_err(gettext("not enough memory for %d entries\n"),
numentries);
exit(1);
}
for (ml = result_list, tb = &table[0];
ml != NULL;
ml = ml->ml_next, tb++) {
*tb = ml;
}
/*
* Sort the entries and print the results.
*/
if (dflg)
qsort(table, numentries, sizeof (struct mountbody *), sortpath);
else
qsort(table, numentries, sizeof (struct mountbody *), sorthost);
if (aflg) {
for (tb = table; tb < table + numentries; tb++)
printf("%s:%s\n", (*tb)->ml_hostname,
(*tb)->ml_directory);
} else if (dflg) {
last = "";
for (tb = table; tb < table + numentries; tb++) {
if (strcmp(last, (*tb)->ml_directory))
printf("%s\n", (*tb)->ml_directory);
last = (*tb)->ml_directory;
}
} else {
last = "";
for (tb = table; tb < table + numentries; tb++) {
if (strcmp(last, (*tb)->ml_hostname))
printf("%s\n", (*tb)->ml_hostname);
last = (*tb)->ml_hostname;
}
}
return (0);
}
int
sorthost(a, b)
struct mountbody **a, **b;
{
return (strcmp((*a)->ml_hostname, (*b)->ml_hostname));
}
int
sortpath(a, b)
struct mountbody **a, **b;
{
return (strcmp((*a)->ml_directory, (*b)->ml_directory));
}
void
usage()
{
(void) fprintf(stderr,
gettext("Usage: showmount [-a] [-d] [-e] [host]\n"));
}
void
pr_err(char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
(void) fprintf(stderr, "showmount: ");
(void) vfprintf(stderr, fmt, ap);
va_end(ap);
}
void
printex(cl, host)
CLIENT *cl;
char *host;
{
struct exportnode *ex = NULL;
struct exportnode *e;
struct groupnode *gr;
enum clnt_stat err;
int max;
struct timeval tout;
tout.tv_sec = 10;
tout.tv_usec = 0;
if (err = clnt_call(cl, MOUNTPROC_EXPORT,
xdr_void, 0, xdr_exports, (caddr_t)&ex, tout)) {
pr_err("%s\n", clnt_sperrno(err));
exit(1);
}
if (ex == NULL) {
printf(gettext("no exported file systems for %s\n"), host);
} else {
printf(gettext("export list for %s:\n"), host);
}
max = 0;
for (e = ex; e != NULL; e = e->ex_next) {
if (strlen(e->ex_dir) > max) {
max = strlen(e->ex_dir);
}
}
while (ex) {
printf("%-*s ", max, ex->ex_dir);
gr = ex->ex_groups;
if (gr == NULL) {
printf(gettext("(everyone)"));
}
while (gr) {
printf("%s", gr->gr_name);
gr = gr->gr_next;
if (gr) {
printf(",");
}
}
printf("\n");
ex = ex->ex_next;
}
}