]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/amd/amq/amq.c
MFC r308493, r308619: Update amd from am-utils 6.1.5 to 6.2.
[FreeBSD/stable/10.git] / contrib / amd / amq / amq.c
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
80 time_print(time_type tt)
81 {
82   time_t t = (time_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
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
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
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
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
259 show_map(amq_map_info *mi)
260 {
261 }
262
263 static void
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
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 *
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
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
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
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
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 }