1/* $NetBSD: amq.c,v 1.4 2022/08/23 07:42:28 christos Exp $ */ 2 3/* 4 * Copyright (c) 1997-2014 Erez Zadok 5 * Copyright (c) 1990 Jan-Simon Pendry 6 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine 7 * Copyright (c) 1990 The Regents of the University of California. 8 * All rights reserved. 9 * 10 * This code is derived from software contributed to Berkeley by 11 * Jan-Simon Pendry at Imperial College, London. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 3. Neither the name of the University nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 * 37 * 38 * File: am-utils/amq/amq.c 39 * 40 */ 41 42/* 43 * Automounter query tool 44 */ 45 46#ifdef HAVE_CONFIG_H 47# include <config.h> 48#endif /* HAVE_CONFIG_H */ 49#include <am_defs.h> 50#include <amq.h> 51 52/* locals */ 53static int flush_flag; 54static int getpid_flag; 55static int getpwd_flag; 56static int getvers_flag; 57static int minfo_flag; 58static int mapinfo_flag; 59static int quiet_flag; 60static int stats_flag; 61static int unmount_flag; 62static int use_tcp_flag; 63static int use_udp_flag; 64static u_long amd_program_number = AMQ_PROGRAM; 65static char *debug_opts; 66static char *amq_logfile; 67static char *xlog_optstr; 68static char localhost[] = "localhost"; 69static char *def_server = localhost; 70 71/* externals */ 72extern int optind; 73extern char *optarg; 74 75/* structures */ 76enum show_opt { 77 Full, Stats, Calc, Short, ShowDone 78}; 79 80 81static void 82time_print(time_type tt) 83{ 84 time_t t = (time_t)tt; 85 struct tm *tp = localtime(&t); 86 printf("%02d/%02d/%04d %02d:%02d:%02d", 87 tp->tm_mon + 1, tp->tm_mday, 88 tp->tm_year < 1900 ? tp->tm_year + 1900 : tp->tm_year, 89 tp->tm_hour, tp->tm_min, tp->tm_sec); 90} 91 92/* 93 * If (e) is Calc then just calculate the sizes 94 * Otherwise display the mount node on stdout 95 */ 96static void 97show_mti(amq_mount_tree *mt, enum show_opt e, int *mwid, int *dwid, int *twid) 98{ 99 switch (e) { 100 case Calc: 101 { 102 int mw = strlen(mt->mt_mountinfo); 103 int dw = strlen(mt->mt_directory); 104 int tw = strlen(mt->mt_type); 105 if (mw > *mwid) 106 *mwid = mw; 107 if (dw > *dwid) 108 *dwid = dw; 109 if (tw > *twid) 110 *twid = tw; 111 } 112 break; 113 114 case Full: 115 { 116 printf("%-*.*s %-*.*s %-*.*s %s\n\t%-5d %-7d %-6d %-7d %-7d %-6d", 117 *dwid, *dwid, 118 *mt->mt_directory ? mt->mt_directory : "/", /* XXX */ 119 *twid, *twid, 120 mt->mt_type, 121 *mwid, *mwid, 122 mt->mt_mountinfo, 123 mt->mt_mountpoint, 124 125 mt->mt_mountuid, 126 mt->mt_getattr, 127 mt->mt_lookup, 128 mt->mt_readdir, 129 mt->mt_readlink, 130 mt->mt_statfs); 131 time_print(mt->mt_mounttime); 132 printf("\n"); 133 } 134 break; 135 136 case Stats: 137 { 138 printf("%-*.*s %-5d %-7d %-6d %-7d %-7d %-6d ", 139 *dwid, *dwid, 140 *mt->mt_directory ? mt->mt_directory : "/", /* XXX */ 141 142 mt->mt_mountuid, 143 mt->mt_getattr, 144 mt->mt_lookup, 145 mt->mt_readdir, 146 mt->mt_readlink, 147 mt->mt_statfs); 148 time_print(mt->mt_mounttime); 149 printf("\n"); 150 } 151 break; 152 153 case Short: 154 { 155 printf("%-*.*s %-*.*s %-*.*s %s\n", 156 *dwid, *dwid, 157 *mt->mt_directory ? mt->mt_directory : "/", 158 *twid, *twid, 159 mt->mt_type, 160 *mwid, *mwid, 161 mt->mt_mountinfo, 162 mt->mt_mountpoint); 163 } 164 break; 165 166 default: 167 break; 168 } 169} 170 171 172/* 173 * Display a pwd data 174 */ 175static void 176show_pwd(amq_mount_tree *mt, char *path, size_t l, int *flag) 177{ 178 int len; 179 180 while (mt) { 181 len = strlen(mt->mt_mountpoint); 182 if (NSTREQ(path, mt->mt_mountpoint, len) && 183 !STREQ(mt->mt_directory, mt->mt_mountpoint)) { 184 char buf[MAXPATHLEN+1]; /* must be same size as 'path' */ 185 xstrlcpy(buf, mt->mt_directory, sizeof(buf)); 186 xstrlcat(buf, &path[len], sizeof(buf)); 187 xstrlcpy(path, buf, l); 188 *flag = 1; 189 } 190 show_pwd(mt->mt_next, path, l, flag); 191 mt = mt->mt_child; 192 } 193} 194 195 196/* 197 * Display a mount tree. 198 */ 199static void 200show_mt(amq_mount_tree *mt, enum show_opt e, int *mwid, int *dwid, int *pwid) 201{ 202 while (mt) { 203 show_mti(mt, e, mwid, dwid, pwid); 204 show_mt(mt->mt_next, e, mwid, dwid, pwid); 205 mt = mt->mt_child; 206 } 207} 208 209 210static void 211show_mi(amq_mount_info_list *ml, enum show_opt e, int *mwid, int *dwid, int *twid) 212{ 213 u_int i; 214 215 switch (e) { 216 217 case Calc: 218 { 219 for (i = 0; i < ml->amq_mount_info_list_len; i++) { 220 amq_mount_info *mi = &ml->amq_mount_info_list_val[i]; 221 int mw = strlen(mi->mi_mountinfo); 222 int dw = strlen(mi->mi_mountpt); 223 int tw = strlen(mi->mi_type); 224 if (mw > *mwid) 225 *mwid = mw; 226 if (dw > *dwid) 227 *dwid = dw; 228 if (tw > *twid) 229 *twid = tw; 230 } 231 } 232 break; 233 234 case Full: 235 { 236 for (i = 0; i < ml->amq_mount_info_list_len; i++) { 237 amq_mount_info *mi = &ml->amq_mount_info_list_val[i]; 238 printf("%-*.*s %-*.*s %-*.*s %-3d %s is %s ", 239 *mwid, *mwid, mi->mi_mountinfo, 240 *dwid, *dwid, mi->mi_mountpt, 241 *twid, *twid, mi->mi_type, 242 mi->mi_refc, mi->mi_fserver, 243 mi->mi_up > 0 ? "up" : 244 mi->mi_up < 0 ? "starting" : "down"); 245 if (mi->mi_error > 0) { 246 printf(" (%s)", strerror(mi->mi_error)); 247 } else if (mi->mi_error < 0) { 248 fputs(" (in progress)", stdout); 249 } 250 fputc('\n', stdout); 251 } 252 } 253 break; 254 255 default: 256 break; 257 } 258} 259 260static void 261show_mapinfo(amq_map_info_list *ml, enum show_opt e, int *nwid, int *wwid) 262{ 263 u_int i; 264 265 switch (e) { 266 267 case Calc: 268 { 269 for (i = 0; i < ml->amq_map_info_list_len; i++) { 270 amq_map_info *mi = &ml->amq_map_info_list_val[i]; 271 int nw = strlen(mi->mi_name); 272 int ww = strlen(mi->mi_wildcard ? mi->mi_wildcard : "(null"); 273 if (nw > *nwid) 274 *nwid = nw; 275 if (ww > *wwid) 276 *wwid = ww; 277 } 278 } 279 break; 280 281 case Full: 282 { 283 printf("%-*.*s %-*.*s %-8.8s %-7.7s %-7.7s %-7.7s %-s Modified\n", 284 *nwid, *nwid, "Name", 285 *wwid, *wwid, "Wild", 286 "Flags", "Refcnt", "Entries", "Reloads", "Stat"); 287 for (i = 0; i < ml->amq_map_info_list_len; i++) { 288 amq_map_info *mi = &ml->amq_map_info_list_val[i]; 289 printf("%-*.*s %*.*s %-8x %-7d %-7d %-7d %s ", 290 *nwid, *nwid, mi->mi_name, 291 *wwid, *wwid, mi->mi_wildcard, 292 mi->mi_flags, mi->mi_refc, mi->mi_nentries, mi->mi_reloads, 293 mi->mi_up == -1 ? "root" : (mi->mi_up ? " up" : "down")); 294 time_print(mi->mi_modify); 295 fputc('\n', stdout); 296 } 297 } 298 break; 299 300 default: 301 break; 302 } 303} 304 305/* 306 * Display general mount statistics 307 */ 308static void 309show_ms(amq_mount_stats *ms) 310{ 311 printf("\ 312requests stale mount mount unmount\n\ 313deferred fhandles ok failed failed\n\ 314%-9d %-9d %-9d %-9d %-9d\n", 315 ms->as_drops, ms->as_stale, ms->as_mok, ms->as_merr, ms->as_uerr); 316} 317 318 319#if defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT) 320static char * 321cluster_server(void) 322{ 323 struct cct_entry *cp; 324 325 if (cnodeid() == 0) { 326 /* 327 * Not clustered 328 */ 329 return def_server; 330 } 331 while (cp = getccent()) 332 if (cp->cnode_type == 'r') 333 return cp->cnode_name; 334 335 return def_server; 336} 337#endif /* defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT) */ 338 339 340static void 341print_umnt_error(amq_sync_umnt *rv, const char *fs) 342{ 343 344 switch (rv->au_etype) { 345 case AMQ_UMNT_OK: 346 break; 347 case AMQ_UMNT_FAILED: 348 printf("unmount failed: %s\n", strerror(rv->au_errno)); 349 break; 350 case AMQ_UMNT_FORK: 351 if (rv->au_errno == 0) 352 printf("%s is not mounted\n", fs); 353 else 354 printf("falling back to asynchronous unmount: %s\n", 355 strerror(rv->au_errno)); 356 break; 357 case AMQ_UMNT_READ: 358 printf("pipe read error: %s\n", strerror(rv->au_errno)); 359 break; 360 case AMQ_UMNT_SERVER: 361 printf("amd server down\n"); 362 break; 363 case AMQ_UMNT_SIGNAL: 364 printf("got signal: %d\n", rv->au_signal); 365 break; 366 /* 367 * Omit default so the compiler can check for missing cases. 368 * 369 default: 370 break; 371 */ 372 } 373} 374 375 376static int 377amu_sync_umnt_to_retval(amq_sync_umnt *rv) 378{ 379 switch (rv->au_etype) { 380 case AMQ_UMNT_FORK: 381 if (rv->au_errno == 0) { 382 /* 383 * We allow this error so that things like: 384 * amq -uu /l/cd0d && eject cd0 385 * will work when /l/cd0d is not mounted. 386 * XXX - We still print an error message. 387 */ 388 return 0; 389 } 390 /*FALLTHROUGH*/ 391 default: 392 return rv->au_etype; 393 } 394} 395 396 397static int 398clnt_failed(CLIENT *clnt, char *server) 399{ 400 fprintf(stderr, "%s: ", am_get_progname()); 401 clnt_perror(clnt, server); 402 return 1; 403} 404 405 406/* 407 * MAIN 408 */ 409int 410main(int argc, char *argv[]) 411{ 412 int opt_ch; 413 int errs = 0; 414 char *server; 415 struct sockaddr_in server_addr; 416 CLIENT *clnt = NULL; 417 struct hostent *hp; 418 int nodefault = 0; 419 struct timeval tv; 420 char *progname = NULL; 421 422 /* 423 * Compute program name 424 */ 425 if (argv[0]) { 426 progname = strrchr(argv[0], '/'); 427 if (progname && progname[1]) 428 progname++; 429 else 430 progname = argv[0]; 431 } 432 if (!progname) 433 progname = "amq"; 434 am_set_progname(progname); 435 436 /* 437 * Parse arguments 438 */ 439 while ((opt_ch = getopt(argc, argv, "Hfh:il:mqsuvx:D:pP:TUw")) != -1) 440 switch (opt_ch) { 441 case 'H': 442 goto show_usage; 443 break; 444 445 case 'f': 446 flush_flag = 1; 447 nodefault = 1; 448 break; 449 450 case 'h': 451 def_server = optarg; 452 break; 453 454 case 'i': 455 mapinfo_flag = 1; 456 nodefault = 1; 457 break; 458 459 case 'l': 460 amq_logfile = optarg; 461 nodefault = 1; 462 break; 463 464 case 'm': 465 minfo_flag = 1; 466 nodefault = 1; 467 break; 468 469 case 'p': 470 getpid_flag = 1; 471 nodefault = 1; 472 break; 473 474 case 'q': 475 quiet_flag = 1; 476 nodefault = 1; 477 break; 478 479 case 's': 480 stats_flag = 1; 481 nodefault = 1; 482 break; 483 484 case 'u': 485 unmount_flag++; 486 nodefault = 1; 487 break; 488 489 case 'v': 490 getvers_flag = 1; 491 nodefault = 1; 492 break; 493 494 case 'x': 495 xlog_optstr = optarg; 496 nodefault = 1; 497 break; 498 499 case 'D': 500 debug_opts = optarg; 501 nodefault = 1; 502 break; 503 504 case 'P': 505 amd_program_number = atoi(optarg); 506 break; 507 508 case 'T': 509 use_tcp_flag = 1; 510 break; 511 512 case 'U': 513 use_udp_flag = 1; 514 break; 515 516 case 'w': 517 getpwd_flag = 1; 518 break; 519 520 default: 521 errs = 1; 522 break; 523 } 524 525 if (optind == argc) { 526 if (unmount_flag) 527 errs = 1; 528 } 529 if (errs) { 530 show_usage: 531 fprintf(stderr, "\ 532Usage: %s [-fimpqsvwHTU] [-h hostname] [-l log_file|\"syslog\"]\n\ 533\t[-x log_options] [-D debug_options]\n\ 534\t[-P program_number] [[-u[u]] directory ...]\n", 535 am_get_progname() 536 ); 537 exit(1); 538 } 539 540 541 /* set use_udp and use_tcp flags both to on if none are defined */ 542 if (!use_tcp_flag && !use_udp_flag) 543 use_tcp_flag = use_udp_flag = 1; 544 545#if defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT) 546 /* 547 * Figure out root server of cluster 548 */ 549 if (def_server == localhost) 550 server = cluster_server(); 551 else 552#endif /* defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT) */ 553 server = def_server; 554 555 /* 556 * Get address of server 557 */ 558 if ((hp = gethostbyname(server)) == 0 && !STREQ(server, localhost)) { 559 fprintf(stderr, "%s: Can't get address of %s\n", 560 am_get_progname(), server); 561 exit(1); 562 } 563 memset(&server_addr, 0, sizeof(server_addr)); 564 /* as per POSIX, sin_len need not be set (used internally by kernel) */ 565 server_addr.sin_family = AF_INET; 566 if (hp) { 567 memmove((voidp) &server_addr.sin_addr, (voidp) hp->h_addr, 568 sizeof(server_addr.sin_addr)); 569 } else { 570 /* fake "localhost" */ 571 server_addr.sin_addr.s_addr = htonl(0x7f000001); 572 } 573 574 /* 575 * Create RPC endpoint 576 */ 577 tv.tv_sec = 5; /* 5 seconds for timeout or per retry */ 578 tv.tv_usec = 0; 579 580 if (use_tcp_flag) /* try tcp first */ 581 clnt = clnt_create(server, amd_program_number, AMQ_VERSION, "tcp"); 582 if (!clnt && use_udp_flag) { /* try udp next */ 583 clnt = clnt_create(server, amd_program_number, AMQ_VERSION, "udp"); 584 /* if ok, set timeout (valid for connectionless transports only) */ 585 if (clnt) 586 clnt_control(clnt, CLSET_RETRY_TIMEOUT, (char *) &tv); 587 } 588 if (!clnt) { 589 fprintf(stderr, "%s: ", am_get_progname()); 590 clnt_pcreateerror(server); 591 exit(1); 592 } 593 594 /* 595 * Control debugging 596 */ 597 if (debug_opts) { 598 int *rc; 599 amq_setopt opt; 600 opt.as_opt = AMOPT_DEBUG; 601 opt.as_str = debug_opts; 602 rc = amqproc_setopt_1(&opt, clnt); 603 if (rc && *rc < 0) { 604 fprintf(stderr, "%s: daemon not compiled for debug\n", 605 am_get_progname()); 606 errs = 1; 607 } else if (!rc || *rc > 0) { 608 fprintf(stderr, "%s: debug setting for \"%s\" failed\n", 609 am_get_progname(), debug_opts); 610 errs = 1; 611 } 612 } 613 614 /* 615 * Control logging 616 */ 617 if (xlog_optstr) { 618 int *rc; 619 amq_setopt opt; 620 opt.as_opt = AMOPT_XLOG; 621 opt.as_str = xlog_optstr; 622 rc = amqproc_setopt_1(&opt, clnt); 623 if (!rc || *rc) { 624 fprintf(stderr, "%s: setting log level to \"%s\" failed\n", 625 am_get_progname(), xlog_optstr); 626 errs = 1; 627 } 628 } 629 630 /* 631 * Control log file 632 */ 633 if (amq_logfile) { 634 int *rc; 635 amq_setopt opt; 636 opt.as_opt = AMOPT_LOGFILE; 637 opt.as_str = amq_logfile; 638 rc = amqproc_setopt_1(&opt, clnt); 639 if (!rc || *rc) { 640 fprintf(stderr, "%s: setting logfile to \"%s\" failed\n", 641 am_get_progname(), amq_logfile); 642 errs = 1; 643 } 644 } 645 646 /* 647 * Flush map cache 648 */ 649 if (flush_flag) { 650 int *rc; 651 amq_setopt opt; 652 opt.as_opt = AMOPT_FLUSHMAPC; 653 opt.as_str = ""; 654 rc = amqproc_setopt_1(&opt, clnt); 655 if (!rc || *rc) { 656 fprintf(stderr, "%s: amd on %s cannot flush the map cache\n", 657 am_get_progname(), server); 658 errs = 1; 659 } 660 } 661 662 /* 663 * getpwd info 664 */ 665 if (getpwd_flag) { 666 char path[MAXPATHLEN+1]; 667 char *wd; 668 amq_mount_tree_list *mlp; 669 amq_mount_tree_p mt; 670 u_int i; 671 int flag; 672 673 wd = getcwd(path, MAXPATHLEN+1); 674 if (!wd) { 675 fprintf(stderr, "%s: getcwd failed (%s)", am_get_progname(), 676 strerror(errno)); 677 exit(1); 678 } 679 mlp = amqproc_export_1((voidp) 0, clnt); 680 for (i = 0; mlp && i < mlp->amq_mount_tree_list_len; i++) { 681 mt = mlp->amq_mount_tree_list_val[i]; 682 while (1) { 683 flag = 0; 684 show_pwd(mt, path, sizeof(path), &flag); 685 if (!flag) { 686 printf("%s\n", path); 687 break; 688 } 689 } 690 } 691 exit(0); 692 } 693 694 /* 695 * Mount info 696 */ 697 if (minfo_flag) { 698 int dummy; 699 amq_mount_info_list *ml = amqproc_getmntfs_1(&dummy, clnt); 700 if (ml) { 701 int mwid = 0, dwid = 0, twid = 0; 702 show_mi(ml, Calc, &mwid, &dwid, &twid); 703 mwid++; 704 dwid++; 705 twid++; 706 show_mi(ml, Full, &mwid, &dwid, &twid); 707 708 } else { 709 fprintf(stderr, "%s: amd on %s cannot provide mount info\n", 710 am_get_progname(), server); 711 } 712 } 713 714 715 /* 716 * Map 717 */ 718 if (mapinfo_flag) { 719 int dummy; 720 amq_map_info_list *ml = amqproc_getmapinfo_1(&dummy, clnt); 721 if (ml) { 722 int mwid = 0, wwid = 0; 723 show_mapinfo(ml, Calc, &mwid, &wwid); 724 mwid++; 725 if (wwid) 726 wwid++; 727 show_mapinfo(ml, Full, &mwid, &wwid); 728 } else { 729 fprintf(stderr, "%s: amd on %s cannot provide map info\n", 730 am_get_progname(), server); 731 } 732 } 733 734 /* 735 * Get Version 736 */ 737 if (getvers_flag) { 738 amq_string *spp = amqproc_getvers_1((voidp) 0, clnt); 739 if (spp && *spp) { 740 fputs(*spp, stdout); 741 XFREE(*spp); 742 } else { 743 fprintf(stderr, "%s: failed to get version information\n", 744 am_get_progname()); 745 errs = 1; 746 } 747 } 748 749 /* 750 * Get PID of amd 751 */ 752 if (getpid_flag) { 753 int *ip = amqproc_getpid_1((voidp) 0, clnt); 754 if (ip && *ip) { 755 printf("%d\n", *ip); 756 } else { 757 fprintf(stderr, "%s: failed to get PID of amd\n", am_get_progname()); 758 errs = 1; 759 } 760 } 761 762 /* 763 * Apply required operation to all remaining arguments 764 */ 765 if (optind < argc) { 766 do { 767 char *fs = argv[optind++]; 768 if (unmount_flag > 1) { 769 amq_sync_umnt *sup; 770 /* 771 * Synchronous unmount request 772 */ 773 sup = amqproc_sync_umnt_1(&fs, clnt); 774 if (sup) { 775 if (quiet_flag == 0) 776 print_umnt_error(sup, fs); 777 errs = amu_sync_umnt_to_retval(sup); 778 } else { 779 errs = clnt_failed(clnt, server); 780 } 781 } else if (unmount_flag) { 782 /* 783 * Unmount request 784 */ 785 amqproc_umnt_1(&fs, clnt); 786 } else { 787 /* 788 * Stats request 789 */ 790 amq_mount_tree_p *mtp = amqproc_mnttree_1(&fs, clnt); 791 if (mtp) { 792 amq_mount_tree *mt = *mtp; 793 if (mt) { 794 int mwid = 0, dwid = 0, twid = 0; 795 show_mt(mt, Calc, &mwid, &dwid, &twid); 796 mwid++; 797 dwid++, twid++; 798 printf("%-*.*s Uid Getattr Lookup RdDir RdLnk Statfs Mounted@\n", 799 dwid, dwid, "What"); 800 show_mt(mt, Stats, &mwid, &dwid, &twid); 801 } else { 802 fprintf(stderr, "%s: %s not automounted\n", am_get_progname(), fs); 803 } 804 xdr_pri_free((XDRPROC_T_TYPE) xdr_amq_mount_tree_p, (caddr_t) mtp); 805 } else { 806 errs = clnt_failed(clnt, server); 807 } 808 } 809 } while (optind < argc); 810 811 } else if (unmount_flag) { 812 goto show_usage; 813 814 } else if (stats_flag) { 815 amq_mount_stats *ms = amqproc_stats_1((voidp) 0, clnt); 816 if (ms) { 817 show_ms(ms); 818 } else { 819 errs = clnt_failed(clnt, server); 820 } 821 822 } else if (!nodefault) { 823 amq_mount_tree_list *mlp = amqproc_export_1((voidp) 0, clnt); 824 if (mlp) { 825 enum show_opt e = Calc; 826 int mwid = 0, dwid = 0, pwid = 0; 827 828 while (e != ShowDone) { 829 u_int i; 830 for (i = 0; i < mlp->amq_mount_tree_list_len; i++) { 831 show_mt(mlp->amq_mount_tree_list_val[i], 832 e, &mwid, &dwid, &pwid); 833 } 834 mwid++; 835 dwid++, pwid++; 836 if (e == Calc) 837 e = Short; 838 else if (e == Short) 839 e = ShowDone; 840 } 841 842 } else { 843 errs = clnt_failed(clnt, server); 844 } 845 } 846 exit(errs); 847 return errs; /* should never reach here */ 848} 849