1 /*
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.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * Jan-Simon Pendry at Imperial College, London.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
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.
22 *
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
33 * SUCH DAMAGE.
34 *
35 *
36 * File: am-utils/amq/amq.c
37 *
38 */
39
40 /*
41 * Automounter query tool
42 */
43
44 #ifdef HAVE_CONFIG_H
45 # include <config.h>
46 #endif /* HAVE_CONFIG_H */
47 #include <am_defs.h>
48 #include <amq.h>
49
50 /* locals */
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;
68
69 /* externals */
70 extern int optind;
71 extern char *optarg;
72
73 /* structures */
74 enum show_opt {
75 Full, Stats, Calc, Short, ShowDone
76 };
77
78
79 static void
time_print(time_type tt)80 time_print(time_type tt)
81 {
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);
88 }
89
90 /*
91 * If (e) is Calc then just calculate the sizes
92 * Otherwise display the mount node on stdout
93 */
94 static void
show_mti(amq_mount_tree * mt,enum show_opt e,int * mwid,int * dwid,int * twid)95 show_mti(amq_mount_tree *mt, enum show_opt e, int *mwid, int *dwid, int *twid)
96 {
97 switch (e) {
98 case Calc:
99 {
100 int mw = strlen(mt->mt_mountinfo);
101 int dw = strlen(mt->mt_directory);
102 int tw = strlen(mt->mt_type);
103 if (mw > *mwid)
104 *mwid = mw;
105 if (dw > *dwid)
106 *dwid = dw;
107 if (tw > *twid)
108 *twid = tw;
109 }
110 break;
111
112 case Full:
113 {
114 printf("%-*.*s %-*.*s %-*.*s %s\n\t%-5d %-7d %-6d %-7d %-7d %-6d",
115 *dwid, *dwid,
116 *mt->mt_directory ? mt->mt_directory : "/", /* XXX */
117 *twid, *twid,
118 mt->mt_type,
119 *mwid, *mwid,
120 mt->mt_mountinfo,
121 mt->mt_mountpoint,
122
123 mt->mt_mountuid,
124 mt->mt_getattr,
125 mt->mt_lookup,
126 mt->mt_readdir,
127 mt->mt_readlink,
128 mt->mt_statfs);
129 time_print(mt->mt_mounttime);
130 printf("\n");
131 }
132 break;
133
134 case Stats:
135 {
136 printf("%-*.*s %-5d %-7d %-6d %-7d %-7d %-6d ",
137 *dwid, *dwid,
138 *mt->mt_directory ? mt->mt_directory : "/", /* XXX */
139
140 mt->mt_mountuid,
141 mt->mt_getattr,
142 mt->mt_lookup,
143 mt->mt_readdir,
144 mt->mt_readlink,
145 mt->mt_statfs);
146 time_print(mt->mt_mounttime);
147 printf("\n");
148 }
149 break;
150
151 case Short:
152 {
153 printf("%-*.*s %-*.*s %-*.*s %s\n",
154 *dwid, *dwid,
155 *mt->mt_directory ? mt->mt_directory : "/",
156 *twid, *twid,
157 mt->mt_type,
158 *mwid, *mwid,
159 mt->mt_mountinfo,
160 mt->mt_mountpoint);
161 }
162 break;
163
164 default:
165 break;
166 }
167 }
168
169
170 /*
171 * Display a pwd data
172 */
173 static void
show_pwd(amq_mount_tree * mt,char * path,size_t l,int * flag)174 show_pwd(amq_mount_tree *mt, char *path, size_t l, int *flag)
175 {
176 int len;
177
178 while (mt) {
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);
186 *flag = 1;
187 }
188 show_pwd(mt->mt_next, path, l, flag);
189 mt = mt->mt_child;
190 }
191 }
192
193
194 /*
195 * Display a mount tree.
196 */
197 static void
show_mt(amq_mount_tree * mt,enum show_opt e,int * mwid,int * dwid,int * pwid)198 show_mt(amq_mount_tree *mt, enum show_opt e, int *mwid, int *dwid, int *pwid)
199 {
200 while (mt) {
201 show_mti(mt, e, mwid, dwid, pwid);
202 show_mt(mt->mt_next, e, mwid, dwid, pwid);
203 mt = mt->mt_child;
204 }
205 }
206
207
208 static void
show_mi(amq_mount_info_list * ml,enum show_opt e,int * mwid,int * dwid,int * twid)209 show_mi(amq_mount_info_list *ml, enum show_opt e, int *mwid, int *dwid, int *twid)
210 {
211 u_int i;
212
213 switch (e) {
214
215 case Calc:
216 {
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);
222 if (mw > *mwid)
223 *mwid = mw;
224 if (dw > *dwid)
225 *dwid = dw;
226 if (tw > *twid)
227 *twid = tw;
228 }
229 }
230 break;
231
232 case Full:
233 {
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);
247 }
248 fputc('\n', stdout);
249 }
250 }
251 break;
252
253 default:
254 break;
255 }
256 }
257
258 static void
show_map(amq_map_info * mi)259 show_map(amq_map_info *mi)
260 {
261 }
262
263 static void
show_mapinfo(amq_map_info_list * ml,enum show_opt e,int * nwid,int * wwid)264 show_mapinfo(amq_map_info_list *ml, enum show_opt e, int *nwid, int *wwid)
265 {
266 u_int i;
267
268 switch (e) {
269
270 case Calc:
271 {
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");
276 if (nw > *nwid)
277 *nwid = nw;
278 if (ww > *wwid)
279 *wwid = ww;
280 }
281 }
282 break;
283
284 case Full:
285 {
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);
298 fputc('\n', stdout);
299 }
300 }
301 break;
302
303 default:
304 break;
305 }
306 }
307
308 /*
309 * Display general mount statistics
310 */
311 static void
show_ms(amq_mount_stats * ms)312 show_ms(amq_mount_stats *ms)
313 {
314 printf("\
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);
319 }
320
321
322 #if defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT)
323 static char *
cluster_server(void)324 cluster_server(void)
325 {
326 struct cct_entry *cp;
327
328 if (cnodeid() == 0) {
329 /*
330 * Not clustered
331 */
332 return def_server;
333 }
334 while (cp = getccent())
335 if (cp->cnode_type == 'r')
336 return cp->cnode_name;
337
338 return def_server;
339 }
340 #endif /* defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT) */
341
342
343 static void
print_umnt_error(amq_sync_umnt * rv,const char * fs)344 print_umnt_error(amq_sync_umnt *rv, const char *fs)
345 {
346
347 switch (rv->au_etype) {
348 case AMQ_UMNT_OK:
349 break;
350 case AMQ_UMNT_FAILED:
351 printf("unmount failed: %s\n", strerror(rv->au_errno));
352 break;
353 case AMQ_UMNT_FORK:
354 if (rv->au_errno == 0)
355 printf("%s is not mounted\n", fs);
356 else
357 printf("falling back to asynchronous unmount: %s\n",
358 strerror(rv->au_errno));
359 break;
360 case AMQ_UMNT_READ:
361 printf("pipe read error: %s\n", strerror(rv->au_errno));
362 break;
363 case AMQ_UMNT_SERVER:
364 printf("amd server down\n");
365 break;
366 case AMQ_UMNT_SIGNAL:
367 printf("got signal: %d\n", rv->au_signal);
368 break;
369 /*
370 * Omit default so the compiler can check for missing cases.
371 *
372 default:
373 break;
374 */
375 }
376 }
377
378
379 static int
amu_sync_umnt_to_retval(amq_sync_umnt * rv)380 amu_sync_umnt_to_retval(amq_sync_umnt *rv)
381 {
382 switch (rv->au_etype) {
383 case AMQ_UMNT_FORK:
384 if (rv->au_errno == 0) {
385 /*
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.
390 */
391 return 0;
392 }
393 /*FALLTHROUGH*/
394 default:
395 return rv->au_etype;
396 }
397 }
398
399
400 static int
clnt_failed(CLIENT * clnt,char * server)401 clnt_failed(CLIENT *clnt, char *server)
402 {
403 fprintf(stderr, "%s: ", am_get_progname());
404 clnt_perror(clnt, server);
405 return 1;
406 }
407
408
409 /*
410 * MAIN
411 */
412 int
main(int argc,char * argv[])413 main(int argc, char *argv[])
414 {
415 int opt_ch;
416 int errs = 0;
417 char *server;
418 struct sockaddr_in server_addr;
419 CLIENT *clnt = NULL;
420 struct hostent *hp;
421 int nodefault = 0;
422 struct timeval tv;
423 char *progname = NULL;
424
425 /*
426 * Compute program name
427 */
428 if (argv[0]) {
429 progname = strrchr(argv[0], '/');
430 if (progname && progname[1])
431 progname++;
432 else
433 progname = argv[0];
434 }
435 if (!progname)
436 progname = "amq";
437 am_set_progname(progname);
438
439 /*
440 * Parse arguments
441 */
442 while ((opt_ch = getopt(argc, argv, "Hfh:il:mqsuvx:D:pP:TUw")) != -1)
443 switch (opt_ch) {
444 case 'H':
445 goto show_usage;
446 break;
447
448 case 'f':
449 flush_flag = 1;
450 nodefault = 1;
451 break;
452
453 case 'h':
454 def_server = optarg;
455 break;
456
457 case 'i':
458 mapinfo_flag = 1;
459 nodefault = 1;
460 break;
461
462 case 'l':
463 amq_logfile = optarg;
464 nodefault = 1;
465 break;
466
467 case 'm':
468 minfo_flag = 1;
469 nodefault = 1;
470 break;
471
472 case 'p':
473 getpid_flag = 1;
474 nodefault = 1;
475 break;
476
477 case 'q':
478 quiet_flag = 1;
479 nodefault = 1;
480 break;
481
482 case 's':
483 stats_flag = 1;
484 nodefault = 1;
485 break;
486
487 case 'u':
488 unmount_flag++;
489 nodefault = 1;
490 break;
491
492 case 'v':
493 getvers_flag = 1;
494 nodefault = 1;
495 break;
496
497 case 'x':
498 xlog_optstr = optarg;
499 nodefault = 1;
500 break;
501
502 case 'D':
503 debug_opts = optarg;
504 nodefault = 1;
505 break;
506
507 case 'P':
508 amd_program_number = atoi(optarg);
509 break;
510
511 case 'T':
512 use_tcp_flag = 1;
513 break;
514
515 case 'U':
516 use_udp_flag = 1;
517 break;
518
519 case 'w':
520 getpwd_flag = 1;
521 break;
522
523 default:
524 errs = 1;
525 break;
526 }
527
528 if (optind == argc) {
529 if (unmount_flag)
530 errs = 1;
531 }
532 if (errs) {
533 show_usage:
534 fprintf(stderr, "\
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",
538 am_get_progname()
539 );
540 exit(1);
541 }
542
543
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;
547
548 #if defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT)
549 /*
550 * Figure out root server of cluster
551 */
552 if (def_server == localhost)
553 server = cluster_server();
554 else
555 #endif /* defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT) */
556 server = def_server;
557
558 /*
559 * Get address of server
560 */
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);
564 exit(1);
565 }
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;
569 if (hp) {
570 memmove((voidp) &server_addr.sin_addr, (voidp) hp->h_addr,
571 sizeof(server_addr.sin_addr));
572 } else {
573 /* fake "localhost" */
574 server_addr.sin_addr.s_addr = htonl(0x7f000001);
575 }
576
577 /*
578 * Create RPC endpoint
579 */
580 tv.tv_sec = 5; /* 5 seconds for timeout or per retry */
581 tv.tv_usec = 0;
582
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) */
588 if (clnt)
589 clnt_control(clnt, CLSET_RETRY_TIMEOUT, (char *) &tv);
590 }
591 if (!clnt) {
592 fprintf(stderr, "%s: ", am_get_progname());
593 clnt_pcreateerror(server);
594 exit(1);
595 }
596
597 /*
598 * Control debugging
599 */
600 if (debug_opts) {
601 int *rc;
602 amq_setopt opt;
603 opt.as_opt = AMOPT_DEBUG;
604 opt.as_str = debug_opts;
605 rc = amqproc_setopt_1(&opt, clnt);
606 if (rc && *rc < 0) {
607 fprintf(stderr, "%s: daemon not compiled for debug\n",
608 am_get_progname());
609 errs = 1;
610 } else if (!rc || *rc > 0) {
611 fprintf(stderr, "%s: debug setting for \"%s\" failed\n",
612 am_get_progname(), debug_opts);
613 errs = 1;
614 }
615 }
616
617 /*
618 * Control logging
619 */
620 if (xlog_optstr) {
621 int *rc;
622 amq_setopt opt;
623 opt.as_opt = AMOPT_XLOG;
624 opt.as_str = xlog_optstr;
625 rc = amqproc_setopt_1(&opt, clnt);
626 if (!rc || *rc) {
627 fprintf(stderr, "%s: setting log level to \"%s\" failed\n",
628 am_get_progname(), xlog_optstr);
629 errs = 1;
630 }
631 }
632
633 /*
634 * Control log file
635 */
636 if (amq_logfile) {
637 int *rc;
638 amq_setopt opt;
639 opt.as_opt = AMOPT_LOGFILE;
640 opt.as_str = amq_logfile;
641 rc = amqproc_setopt_1(&opt, clnt);
642 if (!rc || *rc) {
643 fprintf(stderr, "%s: setting logfile to \"%s\" failed\n",
644 am_get_progname(), amq_logfile);
645 errs = 1;
646 }
647 }
648
649 /*
650 * Flush map cache
651 */
652 if (flush_flag) {
653 int *rc;
654 amq_setopt opt;
655 opt.as_opt = AMOPT_FLUSHMAPC;
656 opt.as_str = "";
657 rc = amqproc_setopt_1(&opt, clnt);
658 if (!rc || *rc) {
659 fprintf(stderr, "%s: amd on %s cannot flush the map cache\n",
660 am_get_progname(), server);
661 errs = 1;
662 }
663 }
664
665 /*
666 * getpwd info
667 */
668 if (getpwd_flag) {
669 char path[MAXPATHLEN+1];
670 char *wd;
671 amq_mount_tree_list *mlp;
672 amq_mount_tree_p mt;
673 u_int i;
674 int flag;
675
676 wd = getcwd(path, MAXPATHLEN+1);
677 if (!wd) {
678 fprintf(stderr, "%s: getcwd failed (%s)", am_get_progname(),
679 strerror(errno));
680 exit(1);
681 }
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];
685 while (1) {
686 flag = 0;
687 show_pwd(mt, path, sizeof(path), &flag);
688 if (!flag) {
689 printf("%s\n", path);
690 break;
691 }
692 }
693 }
694 exit(0);
695 }
696
697 /*
698 * Mount info
699 */
700 if (minfo_flag) {
701 int dummy;
702 amq_mount_info_list *ml = amqproc_getmntfs_1(&dummy, clnt);
703 if (ml) {
704 int mwid = 0, dwid = 0, twid = 0;
705 show_mi(ml, Calc, &mwid, &dwid, &twid);
706 mwid++;
707 dwid++;
708 twid++;
709 show_mi(ml, Full, &mwid, &dwid, &twid);
710
711 } else {
712 fprintf(stderr, "%s: amd on %s cannot provide mount info\n",
713 am_get_progname(), server);
714 }
715 }
716
717
718 /*
719 * Map
720 */
721 if (mapinfo_flag) {
722 int dummy;
723 amq_map_info_list *ml = amqproc_getmapinfo_1(&dummy, clnt);
724 if (ml) {
725 int mwid = 0, wwid = 0;
726 show_mapinfo(ml, Calc, &mwid, &wwid);
727 mwid++;
728 if (wwid)
729 wwid++;
730 show_mapinfo(ml, Full, &mwid, &wwid);
731 } else {
732 fprintf(stderr, "%s: amd on %s cannot provide map info\n",
733 am_get_progname(), server);
734 }
735 }
736
737 /*
738 * Get Version
739 */
740 if (getvers_flag) {
741 amq_string *spp = amqproc_getvers_1((voidp) 0, clnt);
742 if (spp && *spp) {
743 fputs(*spp, stdout);
744 XFREE(*spp);
745 } else {
746 fprintf(stderr, "%s: failed to get version information\n",
747 am_get_progname());
748 errs = 1;
749 }
750 }
751
752 /*
753 * Get PID of amd
754 */
755 if (getpid_flag) {
756 int *ip = amqproc_getpid_1((voidp) 0, clnt);
757 if (ip && *ip) {
758 printf("%d\n", *ip);
759 } else {
760 fprintf(stderr, "%s: failed to get PID of amd\n", am_get_progname());
761 errs = 1;
762 }
763 }
764
765 /*
766 * Apply required operation to all remaining arguments
767 */
768 if (optind < argc) {
769 do {
770 char *fs = argv[optind++];
771 if (unmount_flag > 1) {
772 amq_sync_umnt *sup;
773 /*
774 * Synchronous unmount request
775 */
776 sup = amqproc_sync_umnt_1(&fs, clnt);
777 if (sup) {
778 if (quiet_flag == 0)
779 print_umnt_error(sup, fs);
780 errs = amu_sync_umnt_to_retval(sup);
781 } else {
782 errs = clnt_failed(clnt, server);
783 }
784 } else if (unmount_flag) {
785 /*
786 * Unmount request
787 */
788 amqproc_umnt_1(&fs, clnt);
789 } else {
790 /*
791 * Stats request
792 */
793 amq_mount_tree_p *mtp = amqproc_mnttree_1(&fs, clnt);
794 if (mtp) {
795 amq_mount_tree *mt = *mtp;
796 if (mt) {
797 int mwid = 0, dwid = 0, twid = 0;
798 show_mt(mt, Calc, &mwid, &dwid, &twid);
799 mwid++;
800 dwid++, twid++;
801 printf("%-*.*s Uid Getattr Lookup RdDir RdLnk Statfs Mounted@\n",
802 dwid, dwid, "What");
803 show_mt(mt, Stats, &mwid, &dwid, &twid);
804 } else {
805 fprintf(stderr, "%s: %s not automounted\n", am_get_progname(), fs);
806 }
807 xdr_pri_free((XDRPROC_T_TYPE) xdr_amq_mount_tree_p, (caddr_t) mtp);
808 } else {
809 errs = clnt_failed(clnt, server);
810 }
811 }
812 } while (optind < argc);
813
814 } else if (unmount_flag) {
815 goto show_usage;
816
817 } else if (stats_flag) {
818 amq_mount_stats *ms = amqproc_stats_1((voidp) 0, clnt);
819 if (ms) {
820 show_ms(ms);
821 } else {
822 errs = clnt_failed(clnt, server);
823 }
824
825 } else if (!nodefault) {
826 amq_mount_tree_list *mlp = amqproc_export_1((voidp) 0, clnt);
827 if (mlp) {
828 enum show_opt e = Calc;
829 int mwid = 0, dwid = 0, pwid = 0;
830
831 while (e != ShowDone) {
832 u_int i;
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);
836 }
837 mwid++;
838 dwid++, pwid++;
839 if (e == Calc)
840 e = Short;
841 else if (e == Short)
842 e = ShowDone;
843 }
844
845 } else {
846 errs = clnt_failed(clnt, server);
847 }
848 }
849 exit(errs);
850 return errs; /* should never reach here */
851 }
852