2 * Copyright (c) 1997-2014 Erez Zadok
3 * Copyright (c) 1990 Jan-Simon Pendry
4 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
5 * Copyright (c) 1990 The Regents of the University of California.
8 * This code is derived from software contributed to Berkeley by
9 * Jan-Simon Pendry at Imperial College, London.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * File: am-utils/amq/amq.c
41 * Automounter query tool
46 #endif /* HAVE_CONFIG_H */
51 static int flush_flag;
52 static int getpid_flag;
53 static int getpwd_flag;
54 static int getvers_flag;
55 static int minfo_flag;
56 static int mapinfo_flag;
57 static int quiet_flag;
58 static int stats_flag;
59 static int unmount_flag;
60 static int use_tcp_flag;
61 static int use_udp_flag;
62 static u_long amd_program_number = AMQ_PROGRAM;
63 static char *debug_opts;
64 static char *amq_logfile;
65 static char *xlog_optstr;
66 static char localhost[] = "localhost";
67 static char *def_server = localhost;
75 Full, Stats, Calc, Short, ShowDone
80 time_print(time_type tt)
82 time_t t = (time_t)(intptr_t)tt;
83 struct tm *tp = localtime(&t);
84 printf("%02d/%02d/%04d %02d:%02d:%02d",
85 tp->tm_mon + 1, tp->tm_mday,
86 tp->tm_year < 1900 ? tp->tm_year + 1900 : tp->tm_year,
87 tp->tm_hour, tp->tm_min, tp->tm_sec);
91 * If (e) is Calc then just calculate the sizes
92 * Otherwise display the mount node on stdout
95 show_mti(amq_mount_tree *mt, enum show_opt e, int *mwid, int *dwid, int *twid)
100 int mw = strlen(mt->mt_mountinfo);
101 int dw = strlen(mt->mt_directory);
102 int tw = strlen(mt->mt_type);
114 printf("%-*.*s %-*.*s %-*.*s %s\n\t%-5d %-7d %-6d %-7d %-7d %-6d",
116 *mt->mt_directory ? mt->mt_directory : "/", /* XXX */
129 time_print(mt->mt_mounttime);
136 printf("%-*.*s %-5d %-7d %-6d %-7d %-7d %-6d ",
138 *mt->mt_directory ? mt->mt_directory : "/", /* XXX */
146 time_print(mt->mt_mounttime);
153 printf("%-*.*s %-*.*s %-*.*s %s\n",
155 *mt->mt_directory ? mt->mt_directory : "/",
174 show_pwd(amq_mount_tree *mt, char *path, size_t l, int *flag)
179 len = strlen(mt->mt_mountpoint);
180 if (NSTREQ(path, mt->mt_mountpoint, len) &&
181 !STREQ(mt->mt_directory, mt->mt_mountpoint)) {
182 char buf[MAXPATHLEN+1]; /* must be same size as 'path' */
183 xstrlcpy(buf, mt->mt_directory, sizeof(buf));
184 xstrlcat(buf, &path[len], sizeof(buf));
185 xstrlcpy(path, buf, l);
188 show_pwd(mt->mt_next, path, l, flag);
195 * Display a mount tree.
198 show_mt(amq_mount_tree *mt, enum show_opt e, int *mwid, int *dwid, int *pwid)
201 show_mti(mt, e, mwid, dwid, pwid);
202 show_mt(mt->mt_next, e, mwid, dwid, pwid);
209 show_mi(amq_mount_info_list *ml, enum show_opt e, int *mwid, int *dwid, int *twid)
217 for (i = 0; i < ml->amq_mount_info_list_len; i++) {
218 amq_mount_info *mi = &ml->amq_mount_info_list_val[i];
219 int mw = strlen(mi->mi_mountinfo);
220 int dw = strlen(mi->mi_mountpt);
221 int tw = strlen(mi->mi_type);
234 for (i = 0; i < ml->amq_mount_info_list_len; i++) {
235 amq_mount_info *mi = &ml->amq_mount_info_list_val[i];
236 printf("%-*.*s %-*.*s %-*.*s %-3d %s is %s ",
237 *mwid, *mwid, mi->mi_mountinfo,
238 *dwid, *dwid, mi->mi_mountpt,
239 *twid, *twid, mi->mi_type,
240 mi->mi_refc, mi->mi_fserver,
241 mi->mi_up > 0 ? "up" :
242 mi->mi_up < 0 ? "starting" : "down");
243 if (mi->mi_error > 0) {
244 printf(" (%s)", strerror(mi->mi_error));
245 } else if (mi->mi_error < 0) {
246 fputs(" (in progress)", stdout);
259 show_map(amq_map_info *mi)
264 show_mapinfo(amq_map_info_list *ml, enum show_opt e, int *nwid, int *wwid)
272 for (i = 0; i < ml->amq_map_info_list_len; i++) {
273 amq_map_info *mi = &ml->amq_map_info_list_val[i];
274 int nw = strlen(mi->mi_name);
275 int ww = strlen(mi->mi_wildcard ? mi->mi_wildcard : "(null");
286 printf("%-*.*s %-*.*s %-8.8s %-7.7s %-7.7s %-7.7s %-s Modified\n",
287 *nwid, *nwid, "Name",
288 *wwid, *wwid, "Wild",
289 "Flags", "Refcnt", "Entries", "Reloads", "Stat");
290 for (i = 0; i < ml->amq_map_info_list_len; i++) {
291 amq_map_info *mi = &ml->amq_map_info_list_val[i];
292 printf("%-*.*s %*.*s %-8x %-7d %-7d %-7d %s ",
293 *nwid, *nwid, mi->mi_name,
294 *wwid, *wwid, mi->mi_wildcard,
295 mi->mi_flags, mi->mi_refc, mi->mi_nentries, mi->mi_reloads,
296 mi->mi_up == -1 ? "root" : (mi->mi_up ? " up" : "down"));
297 time_print(mi->mi_modify);
309 * Display general mount statistics
312 show_ms(amq_mount_stats *ms)
315 requests stale mount mount unmount\n\
316 deferred fhandles ok failed failed\n\
317 %-9d %-9d %-9d %-9d %-9d\n",
318 ms->as_drops, ms->as_stale, ms->as_mok, ms->as_merr, ms->as_uerr);
322 #if defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT)
326 struct cct_entry *cp;
328 if (cnodeid() == 0) {
334 while (cp = getccent())
335 if (cp->cnode_type == 'r')
336 return cp->cnode_name;
340 #endif /* defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT) */
344 print_umnt_error(amq_sync_umnt *rv, const char *fs)
347 switch (rv->au_etype) {
350 case AMQ_UMNT_FAILED:
351 printf("unmount failed: %s\n", strerror(rv->au_errno));
354 if (rv->au_errno == 0)
355 printf("%s is not mounted\n", fs);
357 printf("falling back to asynchronous unmount: %s\n",
358 strerror(rv->au_errno));
361 printf("pipe read error: %s\n", strerror(rv->au_errno));
363 case AMQ_UMNT_SERVER:
364 printf("amd server down\n");
366 case AMQ_UMNT_SIGNAL:
367 printf("got signal: %d\n", rv->au_signal);
370 * Omit default so the compiler can check for missing cases.
380 amu_sync_umnt_to_retval(amq_sync_umnt *rv)
382 switch (rv->au_etype) {
384 if (rv->au_errno == 0) {
386 * We allow this error so that things like:
387 * amq -uu /l/cd0d && eject cd0
388 * will work when /l/cd0d is not mounted.
389 * XXX - We still print an error message.
401 clnt_failed(CLIENT *clnt, char *server)
403 fprintf(stderr, "%s: ", am_get_progname());
404 clnt_perror(clnt, server);
413 main(int argc, char *argv[])
418 struct sockaddr_in server_addr;
423 char *progname = NULL;
426 * Compute program name
429 progname = strrchr(argv[0], '/');
430 if (progname && progname[1])
437 am_set_progname(progname);
442 while ((opt_ch = getopt(argc, argv, "Hfh:il:mqsuvx:D:pP:TUw")) != -1)
463 amq_logfile = optarg;
498 xlog_optstr = optarg;
508 amd_program_number = atoi(optarg);
528 if (optind == argc) {
535 Usage: %s [-fimpqsvwHTU] [-h hostname] [-l log_file|\"syslog\"]\n\
536 \t[-x log_options] [-D debug_options]\n\
537 \t[-P program_number] [[-u[u]] directory ...]\n",
544 /* set use_udp and use_tcp flags both to on if none are defined */
545 if (!use_tcp_flag && !use_udp_flag)
546 use_tcp_flag = use_udp_flag = 1;
548 #if defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT)
550 * Figure out root server of cluster
552 if (def_server == localhost)
553 server = cluster_server();
555 #endif /* defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT) */
559 * Get address of server
561 if ((hp = gethostbyname(server)) == 0 && !STREQ(server, localhost)) {
562 fprintf(stderr, "%s: Can't get address of %s\n",
563 am_get_progname(), server);
566 memset(&server_addr, 0, sizeof(server_addr));
567 /* as per POSIX, sin_len need not be set (used internally by kernel) */
568 server_addr.sin_family = AF_INET;
570 memmove((voidp) &server_addr.sin_addr, (voidp) hp->h_addr,
571 sizeof(server_addr.sin_addr));
573 /* fake "localhost" */
574 server_addr.sin_addr.s_addr = htonl(0x7f000001);
578 * Create RPC endpoint
580 tv.tv_sec = 5; /* 5 seconds for timeout or per retry */
583 if (use_tcp_flag) /* try tcp first */
584 clnt = clnt_create(server, amd_program_number, AMQ_VERSION, "tcp");
585 if (!clnt && use_udp_flag) { /* try udp next */
586 clnt = clnt_create(server, amd_program_number, AMQ_VERSION, "udp");
587 /* if ok, set timeout (valid for connectionless transports only) */
589 clnt_control(clnt, CLSET_RETRY_TIMEOUT, (char *) &tv);
592 fprintf(stderr, "%s: ", am_get_progname());
593 clnt_pcreateerror(server);
603 opt.as_opt = AMOPT_DEBUG;
604 opt.as_str = debug_opts;
605 rc = amqproc_setopt_1(&opt, clnt);
607 fprintf(stderr, "%s: daemon not compiled for debug\n",
610 } else if (!rc || *rc > 0) {
611 fprintf(stderr, "%s: debug setting for \"%s\" failed\n",
612 am_get_progname(), debug_opts);
623 opt.as_opt = AMOPT_XLOG;
624 opt.as_str = xlog_optstr;
625 rc = amqproc_setopt_1(&opt, clnt);
627 fprintf(stderr, "%s: setting log level to \"%s\" failed\n",
628 am_get_progname(), xlog_optstr);
639 opt.as_opt = AMOPT_LOGFILE;
640 opt.as_str = amq_logfile;
641 rc = amqproc_setopt_1(&opt, clnt);
643 fprintf(stderr, "%s: setting logfile to \"%s\" failed\n",
644 am_get_progname(), amq_logfile);
655 opt.as_opt = AMOPT_FLUSHMAPC;
657 rc = amqproc_setopt_1(&opt, clnt);
659 fprintf(stderr, "%s: amd on %s cannot flush the map cache\n",
660 am_get_progname(), server);
669 char path[MAXPATHLEN+1];
671 amq_mount_tree_list *mlp;
676 wd = getcwd(path, MAXPATHLEN+1);
678 fprintf(stderr, "%s: getcwd failed (%s)", am_get_progname(),
682 mlp = amqproc_export_1((voidp) 0, clnt);
683 for (i = 0; mlp && i < mlp->amq_mount_tree_list_len; i++) {
684 mt = mlp->amq_mount_tree_list_val[i];
687 show_pwd(mt, path, sizeof(path), &flag);
689 printf("%s\n", path);
702 amq_mount_info_list *ml = amqproc_getmntfs_1(&dummy, clnt);
704 int mwid = 0, dwid = 0, twid = 0;
705 show_mi(ml, Calc, &mwid, &dwid, &twid);
709 show_mi(ml, Full, &mwid, &dwid, &twid);
712 fprintf(stderr, "%s: amd on %s cannot provide mount info\n",
713 am_get_progname(), server);
723 amq_map_info_list *ml = amqproc_getmapinfo_1(&dummy, clnt);
725 int mwid = 0, wwid = 0;
726 show_mapinfo(ml, Calc, &mwid, &wwid);
730 show_mapinfo(ml, Full, &mwid, &wwid);
732 fprintf(stderr, "%s: amd on %s cannot provide map info\n",
733 am_get_progname(), server);
741 amq_string *spp = amqproc_getvers_1((voidp) 0, clnt);
746 fprintf(stderr, "%s: failed to get version information\n",
756 int *ip = amqproc_getpid_1((voidp) 0, clnt);
760 fprintf(stderr, "%s: failed to get PID of amd\n", am_get_progname());
766 * Apply required operation to all remaining arguments
770 char *fs = argv[optind++];
771 if (unmount_flag > 1) {
774 * Synchronous unmount request
776 sup = amqproc_sync_umnt_1(&fs, clnt);
779 print_umnt_error(sup, fs);
780 errs = amu_sync_umnt_to_retval(sup);
782 errs = clnt_failed(clnt, server);
784 } else if (unmount_flag) {
788 amqproc_umnt_1(&fs, clnt);
793 amq_mount_tree_p *mtp = amqproc_mnttree_1(&fs, clnt);
795 amq_mount_tree *mt = *mtp;
797 int mwid = 0, dwid = 0, twid = 0;
798 show_mt(mt, Calc, &mwid, &dwid, &twid);
801 printf("%-*.*s Uid Getattr Lookup RdDir RdLnk Statfs Mounted@\n",
803 show_mt(mt, Stats, &mwid, &dwid, &twid);
805 fprintf(stderr, "%s: %s not automounted\n", am_get_progname(), fs);
807 xdr_pri_free((XDRPROC_T_TYPE) xdr_amq_mount_tree_p, (caddr_t) mtp);
809 errs = clnt_failed(clnt, server);
812 } while (optind < argc);
814 } else if (unmount_flag) {
817 } else if (stats_flag) {
818 amq_mount_stats *ms = amqproc_stats_1((voidp) 0, clnt);
822 errs = clnt_failed(clnt, server);
825 } else if (!nodefault) {
826 amq_mount_tree_list *mlp = amqproc_export_1((voidp) 0, clnt);
828 enum show_opt e = Calc;
829 int mwid = 0, dwid = 0, pwid = 0;
831 while (e != ShowDone) {
833 for (i = 0; i < mlp->amq_mount_tree_list_len; i++) {
834 show_mt(mlp->amq_mount_tree_list_val[i],
835 e, &mwid, &dwid, &pwid);
846 errs = clnt_failed(clnt, server);
850 return errs; /* should never reach here */