summaryrefslogtreecommitdiffstats
path: root/usr.sbin/amd/amq/amq.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/amd/amq/amq.c')
-rw-r--r--usr.sbin/amd/amq/amq.c666
1 files changed, 666 insertions, 0 deletions
diff --git a/usr.sbin/amd/amq/amq.c b/usr.sbin/amd/amq/amq.c
new file mode 100644
index 0000000..d3749bc
--- /dev/null
+++ b/usr.sbin/amd/amq/amq.c
@@ -0,0 +1,666 @@
+/*
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)amq.c 8.1 (Berkeley) 6/7/93
+ *
+ * $Id: amq.c,v 5.2.2.1 1992/02/09 15:09:16 jsp beta $
+ *
+ */
+
+/*
+ * Automounter query tool
+ */
+
+#ifndef lint
+char copyright[] = "\
+@(#)Copyright (c) 1990 Jan-Simon Pendry\n\
+@(#)Copyright (c) 1990 Imperial College of Science, Technology & Medicine\n\
+@(#)Copyright (c) 1990, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char rcsid[] = "$Id: amq.c,v 5.2.2.1 1992/02/09 15:09:16 jsp beta $";
+static char sccsid[] = "@(#)amq.c 8.1 (Berkeley) 6/7/93";
+#endif /* not lint */
+
+#include "am.h"
+#include "amq.h"
+#include <stdio.h>
+#include <fcntl.h>
+#include <netdb.h>
+
+static int privsock();
+
+char *progname;
+static int flush_flag;
+static int minfo_flag;
+static int unmount_flag;
+static int stats_flag;
+static int getvers_flag;
+static char *debug_opts;
+static char *logfile;
+static char *mount_map;
+static char *xlog_optstr;
+static char localhost[] = "localhost";
+static char *def_server = localhost;
+
+extern int optind;
+extern char *optarg;
+
+static struct timeval tmo = { 10, 0 };
+#define TIMEOUT tmo
+
+enum show_opt { Full, Stats, Calc, Short, ShowDone };
+
+/*
+ * If (e) is Calc then just calculate the sizes
+ * Otherwise display the mount node on stdout
+ */
+static void show_mti(mt, e, mwid, dwid, twid)
+amq_mount_tree *mt;
+enum show_opt e;
+int *mwid;
+int *dwid;
+int *twid;
+{
+ switch (e) {
+ case Calc: {
+ int mw = strlen(mt->mt_mountinfo);
+ int dw = strlen(mt->mt_directory);
+ int tw = strlen(mt->mt_type);
+ if (mw > *mwid) *mwid = mw;
+ if (dw > *dwid) *dwid = dw;
+ if (tw > *twid) *twid = tw;
+ } break;
+
+ case Full: {
+ struct tm *tp = localtime((time_t *) &mt->mt_mounttime);
+printf("%-*.*s %-*.*s %-*.*s %s\n\t%-5d %-7d %-6d %-7d %-7d %-6d %02d/%02d/%02d %02d:%02d:%02d\n",
+ *dwid, *dwid,
+ *mt->mt_directory ? mt->mt_directory : "/", /* XXX */
+ *twid, *twid,
+ mt->mt_type,
+ *mwid, *mwid,
+ mt->mt_mountinfo,
+ mt->mt_mountpoint,
+
+ mt->mt_mountuid,
+ mt->mt_getattr,
+ mt->mt_lookup,
+ mt->mt_readdir,
+ mt->mt_readlink,
+ mt->mt_statfs,
+
+ tp->tm_year > 99 ? tp->tm_year - 100 : tp->tm_year,
+ tp->tm_mon+1, tp->tm_mday,
+ tp->tm_hour, tp->tm_min, tp->tm_sec);
+ } break;
+
+ case Stats: {
+ struct tm *tp = localtime((time_t *) &mt->mt_mounttime);
+printf("%-*.*s %-5d %-7d %-6d %-7d %-7d %-6d %02d/%02d/%02d %02d:%02d:%02d\n",
+ *dwid, *dwid,
+ *mt->mt_directory ? mt->mt_directory : "/", /* XXX */
+
+ mt->mt_mountuid,
+ mt->mt_getattr,
+ mt->mt_lookup,
+ mt->mt_readdir,
+ mt->mt_readlink,
+ mt->mt_statfs,
+
+ tp->tm_year > 99 ? tp->tm_year - 100 : tp->tm_year,
+ tp->tm_mon+1, tp->tm_mday,
+ tp->tm_hour, tp->tm_min, tp->tm_sec);
+ } break;
+
+ case Short: {
+ printf("%-*.*s %-*.*s %-*.*s %s\n",
+ *dwid, *dwid,
+ *mt->mt_directory ? mt->mt_directory : "/",
+ *twid, *twid,
+ mt->mt_type,
+ *mwid, *mwid,
+ mt->mt_mountinfo,
+ mt->mt_mountpoint);
+ } break;
+ }
+}
+
+/*
+ * Display a mount tree.
+ */
+static void show_mt(mt, e, mwid, dwid, pwid)
+amq_mount_tree *mt;
+enum show_opt e;
+int *mwid;
+int *dwid;
+int *pwid;
+{
+ while (mt) {
+ show_mti(mt, e, mwid, dwid, pwid);
+ show_mt(mt->mt_next, e, mwid, dwid, pwid);
+ mt = mt->mt_child;
+ }
+}
+
+static void show_mi(ml, e, mwid, dwid, twid)
+amq_mount_info_list *ml;
+enum show_opt e;
+int *mwid;
+int *dwid;
+int *twid;
+{
+ int i;
+ switch (e) {
+ case Calc: {
+ for (i = 0; i < ml->amq_mount_info_list_len; i++) {
+ amq_mount_info *mi = &ml->amq_mount_info_list_val[i];
+ int mw = strlen(mi->mi_mountinfo);
+ int dw = strlen(mi->mi_mountpt);
+ int tw = strlen(mi->mi_type);
+ if (mw > *mwid) *mwid = mw;
+ if (dw > *dwid) *dwid = dw;
+ if (tw > *twid) *twid = tw;
+ }
+ } break;
+
+ case Full: {
+ for (i = 0; i < ml->amq_mount_info_list_len; i++) {
+ amq_mount_info *mi = &ml->amq_mount_info_list_val[i];
+ printf("%-*.*s %-*.*s %-*.*s %-3d %s is %s",
+ *mwid, *mwid, mi->mi_mountinfo,
+ *dwid, *dwid, mi->mi_mountpt,
+ *twid, *twid, mi->mi_type,
+ mi->mi_refc, mi->mi_fserver,
+ mi->mi_up > 0 ? "up" :
+ mi->mi_up < 0 ? "starting" : "down");
+ if (mi->mi_error > 0) {
+#ifdef HAS_STRERROR
+ printf(" (%s)", strerror(mi->mi_error));
+#else
+ extern char *sys_errlist[];
+ extern int sys_nerr;
+ if (mi->mi_error < sys_nerr)
+ printf(" (%s)", sys_errlist[mi->mi_error]);
+ else
+ printf(" (Error %d)", mi->mi_error);
+#endif
+ } else if (mi->mi_error < 0) {
+ fputs(" (in progress)", stdout);
+ }
+ fputc('\n', stdout);
+ }
+ } break;
+ }
+}
+
+/*
+ * Display general mount statistics
+ */
+static void show_ms(ms)
+amq_mount_stats *ms;
+{
+ printf("\
+requests stale mount mount unmount\n\
+deferred fhandles ok failed failed\n\
+%-9d %-9d %-9d %-9d %-9d\n",
+ ms->as_drops, ms->as_stale, ms->as_mok, ms->as_merr, ms->as_uerr);
+}
+
+static bool_t
+xdr_pri_free(xdr_args, args_ptr)
+xdrproc_t xdr_args;
+caddr_t args_ptr;
+{
+ XDR xdr;
+ xdr.x_op = XDR_FREE;
+ return ((*xdr_args)(&xdr, args_ptr));
+}
+
+#ifdef hpux
+#include <cluster.h>
+static char *cluster_server()
+{
+ struct cct_entry *cp;
+
+ if (cnodeid() == 0) {
+ /*
+ * Not clustered
+ */
+ return def_server;
+ }
+
+ while (cp = getccent())
+ if (cp->cnode_type == 'r')
+ return cp->cnode_name;
+
+
+ return def_server;
+}
+#endif /* hpux */
+
+/*
+ * MAIN
+ */
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ int opt_ch;
+ int errs = 0;
+ char *server;
+ struct sockaddr_in server_addr;
+
+ /* In order to pass the Amd security check, we must use a priv port. */
+ int s;
+
+ CLIENT *clnt;
+ struct hostent *hp;
+ int nodefault = 0;
+
+ /*
+ * Compute program name
+ */
+ if (argv[0]) {
+ progname = strrchr(argv[0], '/');
+ if (progname && progname[1])
+ progname++;
+ else
+ progname = argv[0];
+ }
+ if (!progname)
+ progname = "amq";
+
+ /*
+ * Parse arguments
+ */
+ while ((opt_ch = getopt(argc, argv, "fh:l:msuvx:D:M:")) != EOF)
+ switch (opt_ch) {
+ case 'f':
+ flush_flag = 1;
+ nodefault = 1;
+ break;
+
+ case 'h':
+ def_server = optarg;
+ break;
+
+ case 'l':
+ logfile = optarg;
+ nodefault = 1;
+ break;
+
+ case 'm':
+ minfo_flag = 1;
+ nodefault = 1;
+ break;
+
+ case 's':
+ stats_flag = 1;
+ nodefault = 1;
+ break;
+
+ case 'u':
+ unmount_flag = 1;
+ nodefault = 1;
+ break;
+
+ case 'v':
+ getvers_flag = 1;
+ nodefault = 1;
+ break;
+
+ case 'x':
+ xlog_optstr = optarg;
+ nodefault = 1;
+ break;
+
+ case 'D':
+ debug_opts = optarg;
+ nodefault = 1;
+ break;
+
+ case 'M':
+ mount_map = optarg;
+ nodefault = 1;
+ break;
+
+ default:
+ errs = 1;
+ break;
+ }
+
+ if (optind == argc) {
+ if (unmount_flag)
+ errs = 1;
+ }
+
+ if (errs) {
+show_usage:
+ fprintf(stderr, "\
+Usage: %s [-h host] [[-f] [-m] [-v] [-s]] | [[-u] directory ...]] |\n\
+\t[-l logfile|\"syslog\"] [-x log_flags] [-D dbg_opts] [-M mapent]\n", progname);
+ exit(1);
+ }
+
+#ifdef hpux
+ /*
+ * Figure out root server of cluster
+ */
+ if (def_server == localhost)
+ server = cluster_server();
+ else
+#endif /* hpux */
+ server = def_server;
+
+ /*
+ * Get address of server
+ */
+ if ((hp = gethostbyname(server)) == 0 && strcmp(server, localhost) != 0) {
+ fprintf(stderr, "%s: Can't get address of %s\n", progname, server);
+ exit(1);
+ }
+ bzero(&server_addr, sizeof server_addr);
+ server_addr.sin_family = AF_INET;
+ if (hp) {
+ bcopy((voidp) hp->h_addr, (voidp) &server_addr.sin_addr,
+ sizeof(server_addr.sin_addr));
+ } else {
+ /* fake "localhost" */
+ server_addr.sin_addr.s_addr = htonl(0x7f000001);
+ }
+
+ /*
+ * Create RPC endpoint
+ */
+ s = privsock(SOCK_STREAM);
+ clnt = clnttcp_create(&server_addr, AMQ_PROGRAM, AMQ_VERSION, &s, 0, 0);
+ if (clnt == 0) {
+ close(s);
+ s = privsock(SOCK_DGRAM);
+ clnt = clntudp_create(&server_addr, AMQ_PROGRAM, AMQ_VERSION, TIMEOUT, &s);
+ }
+ if (clnt == 0) {
+ fprintf(stderr, "%s: ", progname);
+ clnt_pcreateerror(server);
+ exit(1);
+ }
+
+ /*
+ * Control debugging
+ */
+ if (debug_opts) {
+ int *rc;
+ amq_setopt opt;
+ opt.as_opt = AMOPT_DEBUG;
+ opt.as_str = debug_opts;
+ rc = amqproc_setopt_1(&opt, clnt);
+ if (rc && *rc < 0) {
+ fprintf(stderr, "%s: daemon not compiled for debug", progname);
+ errs = 1;
+ } else if (!rc || *rc > 0) {
+ fprintf(stderr, "%s: debug setting for \"%s\" failed\n", progname, debug_opts);
+ errs = 1;
+ }
+ }
+
+ /*
+ * Control logging
+ */
+ if (xlog_optstr) {
+ int *rc;
+ amq_setopt opt;
+ opt.as_opt = AMOPT_XLOG;
+ opt.as_str = xlog_optstr;
+ rc = amqproc_setopt_1(&opt, clnt);
+ if (!rc || *rc) {
+ fprintf(stderr, "%s: setting log level to \"%s\" failed\n", progname, xlog_optstr);
+ errs = 1;
+ }
+ }
+
+ /*
+ * Control log file
+ */
+ if (logfile) {
+ int *rc;
+ amq_setopt opt;
+ opt.as_opt = AMOPT_LOGFILE;
+ opt.as_str = logfile;
+ rc = amqproc_setopt_1(&opt, clnt);
+ if (!rc || *rc) {
+ fprintf(stderr, "%s: setting logfile to \"%s\" failed\n", progname, logfile);
+ errs = 1;
+ }
+ }
+
+ /*
+ * Flush map cache
+ */
+ if (flush_flag) {
+ int *rc;
+ amq_setopt opt;
+ opt.as_opt = AMOPT_FLUSHMAPC;
+ opt.as_str = "";
+ rc = amqproc_setopt_1(&opt, clnt);
+ if (!rc || *rc) {
+ fprintf(stderr, "%s: amd on %s cannot flush the map cache\n", progname, server);
+ errs = 1;
+ }
+ }
+
+ /*
+ * Mount info
+ */
+ if (minfo_flag) {
+ int dummy;
+ amq_mount_info_list *ml = amqproc_getmntfs_1(&dummy, clnt);
+ if (ml) {
+ int mwid = 0, dwid = 0, twid = 0;
+ show_mi(ml, Calc, &mwid, &dwid, &twid);
+ mwid++; dwid++; twid++;
+ show_mi(ml, Full, &mwid, &dwid, &twid);
+
+ } else {
+ fprintf(stderr, "%s: amd on %s cannot provide mount info\n", progname, server);
+ }
+ }
+
+ /*
+ * Mount map
+ */
+ if (mount_map) {
+ int *rc;
+ do {
+ rc = amqproc_mount_1(&mount_map, clnt);
+ } while (rc && *rc < 0);
+ if (!rc || *rc > 0) {
+ if (rc)
+ errno = *rc;
+ else
+ errno = ETIMEDOUT;
+ fprintf(stderr, "%s: could not start new ", progname);
+ perror("autmount point");
+ }
+ }
+
+ /*
+ * Get Version
+ */
+ if (getvers_flag) {
+ amq_string *spp = amqproc_getvers_1((voidp) 0, clnt);
+ if (spp && *spp) {
+ printf("%s.\n", *spp);
+ free(*spp);
+ } else {
+ fprintf(stderr, "%s: failed to get version information\n", progname);
+ errs = 1;
+ }
+ }
+
+ /*
+ * Apply required operation to all remaining arguments
+ */
+ if (optind < argc) {
+ do {
+ char *fs = argv[optind++];
+ if (unmount_flag) {
+ /*
+ * Unmount request
+ */
+ amqproc_umnt_1(&fs, clnt);
+ } else {
+ /*
+ * Stats request
+ */
+ amq_mount_tree_p *mtp = amqproc_mnttree_1(&fs, clnt);
+ if (mtp) {
+ amq_mount_tree *mt = *mtp;
+ if (mt) {
+ int mwid = 0, dwid = 0, twid = 0;
+ show_mt(mt, Calc, &mwid, &dwid, &twid);
+ mwid++; dwid++, twid++;
+ printf("%-*.*s Uid Getattr Lookup RdDir RdLnk Statfs Mounted@\n",
+ dwid, dwid, "What");
+ show_mt(mt, Stats, &mwid, &dwid, &twid);
+ } else {
+ fprintf(stderr, "%s: %s not automounted\n", progname, fs);
+ }
+ xdr_pri_free(xdr_amq_mount_tree_p, (caddr_t) mtp);
+ } else {
+ fprintf(stderr, "%s: ", progname);
+ clnt_perror(clnt, server);
+ errs = 1;
+ }
+ }
+ } while (optind < argc);
+ } else if (unmount_flag) {
+ goto show_usage;
+ } else if (stats_flag) {
+ amq_mount_stats *ms = amqproc_stats_1((voidp) 0, clnt);
+ if (ms) {
+ show_ms(ms);
+ } else {
+ fprintf(stderr, "%s: ", progname);
+ clnt_perror(clnt, server);
+ errs = 1;
+ }
+ } else if (!nodefault) {
+ amq_mount_tree_list *mlp = amqproc_export_1((voidp) 0, clnt);
+ if (mlp) {
+ enum show_opt e = Calc;
+ int mwid = 0, dwid = 0, pwid = 0;
+ while (e != ShowDone) {
+ int i;
+ for (i = 0; i < mlp->amq_mount_tree_list_len; i++) {
+ show_mt(mlp->amq_mount_tree_list_val[i],
+ e, &mwid, &dwid, &pwid);
+ }
+ mwid++; dwid++, pwid++;
+ if (e == Calc) e = Short;
+ else if (e == Short) e = ShowDone;
+ }
+ } else {
+ fprintf(stderr, "%s: ", progname);
+ clnt_perror(clnt, server);
+ errs = 1;
+ }
+ }
+
+ exit(errs);
+}
+
+/*
+ * udpresport creates a datagram socket and attempts to bind it to a
+ * secure port.
+ * returns: The bound socket, or -1 to indicate an error.
+ */
+static int inetresport(ty)
+int ty;
+{
+ int alport;
+ struct sockaddr_in addr;
+ int sock;
+
+ /* Use internet address family */
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = INADDR_ANY;
+ if ((sock = socket(AF_INET, ty, 0)) < 0)
+ return -1;
+ for (alport = IPPORT_RESERVED-1; alport > IPPORT_RESERVED/2 + 1; alport--) {
+ addr.sin_port = htons((u_short)alport);
+ if (bind(sock, (struct sockaddr *)&addr, sizeof (addr)) >= 0)
+ return sock;
+ if (errno != EADDRINUSE) {
+ close(sock);
+ return -1;
+ }
+ }
+ close(sock);
+ errno = EAGAIN;
+ return -1;
+}
+
+/*
+ * Privsock() calls inetresport() to attempt to bind a socket to a secure
+ * port. If inetresport() fails, privsock returns a magic socket number which
+ * indicates to RPC that it should make its own socket.
+ * returns: A privileged socket # or RPC_ANYSOCK.
+ */
+static int privsock(ty)
+int ty;
+{
+ int sock = inetresport(ty);
+
+ if (sock < 0) {
+ errno = 0;
+ /* Couldn't get a secure port, let RPC make an insecure one */
+ sock = RPC_ANYSOCK;
+ }
+ return sock;
+}
+
+#ifdef DEBUG
+xfree(f, l, p)
+char *f, *l;
+voidp p;
+{
+ free(p);
+}
+#endif /* DEBUG */
OpenPOWER on IntegriCloud