amq.c revision 82801
1/* 2 * Copyright (c) 1997-2001 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. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgment: 21 * This product includes software developed by the University of 22 * California, Berkeley and its contributors. 23 * 4. Neither the name of the University nor the names of its contributors 24 * may be used to endorse or promote products derived from this software 25 * without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37 * SUCH DAMAGE. 38 * 39 * %W% (Berkeley) %G% 40 * 41 * $Id: amq.c,v 1.7.2.5 2001/01/12 22:43:43 ro Exp $ 42 * $FreeBSD: head/contrib/amd/amq/amq.c 82801 2001-09-02 18:22:46Z obrien $ 43 * 44 */ 45 46/* 47 * Automounter query tool 48 */ 49 50#ifndef lint 51char copyright[] = "\ 52@(#)Copyright (c) 1997-2001 Erez Zadok\n\ 53@(#)Copyright (c) 1990 Jan-Simon Pendry\n\ 54@(#)Copyright (c) 1990 Imperial College of Science, Technology & Medicine\n\ 55@(#)Copyright (c) 1990 The Regents of the University of California.\n\ 56@(#)All rights reserved.\n"; 57#if __GNUC__ < 2 58static char rcsid[] = "$Id: amq.c,v 1.7.2.5 2001/01/12 22:43:43 ro Exp $"; 59static char sccsid[] = "%W% (Berkeley) %G%"; 60#endif /* __GNUC__ < 2 */ 61#endif /* not lint */ 62 63#ifdef HAVE_CONFIG_H 64# include <config.h> 65#endif /* HAVE_CONFIG_H */ 66#include <am_defs.h> 67#include <amq.h> 68 69/* locals */ 70static int flush_flag; 71static int minfo_flag; 72static int getpid_flag; 73static int unmount_flag; 74static int stats_flag; 75static int getvers_flag; 76static int amd_program_number = AMQ_PROGRAM; 77static int use_tcp_flag, use_udp_flag; 78static int getpwd_flag; 79static char *debug_opts; 80static char *amq_logfile; 81static char *xlog_optstr; 82static char localhost[] = "localhost"; 83static char *def_server = localhost; 84 85/* externals */ 86extern int optind; 87extern char *optarg; 88 89/* structures */ 90enum show_opt { 91 Full, Stats, Calc, Short, ShowDone 92}; 93 94 95/* 96 * If (e) is Calc then just calculate the sizes 97 * Otherwise display the mount node on stdout 98 */ 99static void 100show_mti(amq_mount_tree *mt, enum show_opt e, int *mwid, int *dwid, int *twid) 101{ 102 switch (e) { 103 case Calc: 104 { 105 int mw = strlen(mt->mt_mountinfo); 106 int dw = strlen(mt->mt_directory); 107 int tw = strlen(mt->mt_type); 108 if (mw > *mwid) 109 *mwid = mw; 110 if (dw > *dwid) 111 *dwid = dw; 112 if (tw > *twid) 113 *twid = tw; 114 } 115 break; 116 117 case Full: 118 { 119 struct tm *tp = localtime((time_t *) &mt->mt_mounttime); 120 printf("%-*.*s %-*.*s %-*.*s %s\n\t%-5d %-7d %-6d %-7d %-7d %-6d %02d/%02d/%02d %02d:%02d:%02d\n", 121 *dwid, *dwid, 122 *mt->mt_directory ? mt->mt_directory : "/", /* XXX */ 123 *twid, *twid, 124 mt->mt_type, 125 *mwid, *mwid, 126 mt->mt_mountinfo, 127 mt->mt_mountpoint, 128 129 mt->mt_mountuid, 130 mt->mt_getattr, 131 mt->mt_lookup, 132 mt->mt_readdir, 133 mt->mt_readlink, 134 mt->mt_statfs, 135 136 tp->tm_year > 99 ? tp->tm_year - 100 : tp->tm_year, 137 tp->tm_mon + 1, tp->tm_mday, 138 tp->tm_hour, tp->tm_min, tp->tm_sec); 139 } 140 break; 141 142 case Stats: 143 { 144 struct tm *tp = localtime((time_t *) &mt->mt_mounttime); 145 printf("%-*.*s %-5d %-7d %-6d %-7d %-7d %-6d %02d/%02d/%02d %02d:%02d:%02d\n", 146 *dwid, *dwid, 147 *mt->mt_directory ? mt->mt_directory : "/", /* XXX */ 148 149 mt->mt_mountuid, 150 mt->mt_getattr, 151 mt->mt_lookup, 152 mt->mt_readdir, 153 mt->mt_readlink, 154 mt->mt_statfs, 155 156 tp->tm_year > 99 ? tp->tm_year - 100 : tp->tm_year, 157 tp->tm_mon + 1, tp->tm_mday, 158 tp->tm_hour, tp->tm_min, tp->tm_sec); 159 } 160 break; 161 162 case Short: 163 { 164 printf("%-*.*s %-*.*s %-*.*s %s\n", 165 *dwid, *dwid, 166 *mt->mt_directory ? mt->mt_directory : "/", 167 *twid, *twid, 168 mt->mt_type, 169 *mwid, *mwid, 170 mt->mt_mountinfo, 171 mt->mt_mountpoint); 172 } 173 break; 174 175 default: 176 break; 177 } 178} 179 180 181/* 182 * Display a pwd data 183 */ 184static void 185show_pwd(amq_mount_tree *mt, char *path, int *flag) 186{ 187 int len; 188 189 while (mt) { 190 len = strlen(mt->mt_mountpoint); 191 if (NSTREQ(path, mt->mt_mountpoint, len) && 192 !STREQ(mt->mt_directory, mt->mt_mountpoint)) { 193 char buf[MAXPATHLEN+1]; 194 strcpy(buf, mt->mt_directory); 195 strcat(buf, &path[len]); 196 strcpy(path, buf); 197 *flag = 1; 198 } 199 show_pwd(mt->mt_next, path, flag); 200 mt = mt->mt_child; 201 } 202} 203 204 205/* 206 * Display a mount tree. 207 */ 208static void 209show_mt(amq_mount_tree *mt, enum show_opt e, int *mwid, int *dwid, int *pwid) 210{ 211 while (mt) { 212 show_mti(mt, e, mwid, dwid, pwid); 213 show_mt(mt->mt_next, e, mwid, dwid, pwid); 214 mt = mt->mt_child; 215 } 216} 217 218 219static void 220show_mi(amq_mount_info_list *ml, enum show_opt e, int *mwid, int *dwid, int *twid) 221{ 222 int i; 223 224 switch (e) { 225 226 case Calc: 227 { 228 for (i = 0; i < ml->amq_mount_info_list_len; i++) { 229 amq_mount_info *mi = &ml->amq_mount_info_list_val[i]; 230 int mw = strlen(mi->mi_mountinfo); 231 int dw = strlen(mi->mi_mountpt); 232 int tw = strlen(mi->mi_type); 233 if (mw > *mwid) 234 *mwid = mw; 235 if (dw > *dwid) 236 *dwid = dw; 237 if (tw > *twid) 238 *twid = tw; 239 } 240 } 241 break; 242 243 case Full: 244 { 245 for (i = 0; i < ml->amq_mount_info_list_len; i++) { 246 amq_mount_info *mi = &ml->amq_mount_info_list_val[i]; 247 printf("%-*.*s %-*.*s %-*.*s %-3d %s is %s", 248 *mwid, *mwid, mi->mi_mountinfo, 249 *dwid, *dwid, mi->mi_mountpt, 250 *twid, *twid, mi->mi_type, 251 mi->mi_refc, mi->mi_fserver, 252 mi->mi_up > 0 ? "up" : 253 mi->mi_up < 0 ? "starting" : "down"); 254 if (mi->mi_error > 0) { 255 extern int sys_nerr; 256 if (mi->mi_error < sys_nerr) 257#ifdef HAVE_STRERROR 258 printf(" (%s)", strerror(mi->mi_error)); 259#else /* not HAVE_STRERROR */ 260 printf(" (%s)", sys_errlist[mi->mi_error]); 261#endif /* not HAVE_STRERROR */ 262 else 263 printf(" (Error %d)", mi->mi_error); 264 } else if (mi->mi_error < 0) { 265 fputs(" (in progress)", stdout); 266 } 267 fputc('\n', stdout); 268 } 269 } 270 break; 271 272 default: 273 break; 274 } 275} 276 277 278/* 279 * Display general mount statistics 280 */ 281static void 282show_ms(amq_mount_stats *ms) 283{ 284 printf("\ 285requests stale mount mount unmount\n\ 286deferred fhandles ok failed failed\n\ 287%-9d %-9d %-9d %-9d %-9d\n", 288 ms->as_drops, ms->as_stale, ms->as_mok, ms->as_merr, ms->as_uerr); 289} 290 291 292#if defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT) 293static char * 294cluster_server(void) 295{ 296 struct cct_entry *cp; 297 298 if (cnodeid() == 0) { 299 /* 300 * Not clustered 301 */ 302 return def_server; 303 } 304 while (cp = getccent()) 305 if (cp->cnode_type == 'r') 306 return cp->cnode_name; 307 308 return def_server; 309} 310#endif /* defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT) */ 311 312 313/* 314 * MAIN 315 */ 316int 317main(int argc, char *argv[]) 318{ 319 int opt_ch; 320 int errs = 0; 321 char *server; 322 struct sockaddr_in server_addr; 323 CLIENT *clnt = NULL; 324 struct hostent *hp; 325 int nodefault = 0; 326 struct timeval tv; 327 char *progname = NULL; 328 329 /* 330 * Compute program name 331 */ 332 if (argv[0]) { 333 progname = strrchr(argv[0], '/'); 334 if (progname && progname[1]) 335 progname++; 336 else 337 progname = argv[0]; 338 } 339 if (!progname) 340 progname = "amq"; 341 am_set_progname(progname); 342 343 /* 344 * Parse arguments 345 */ 346 while ((opt_ch = getopt(argc, argv, "Hfh:l:msuvx:D:pP:TUw")) != -1) 347 switch (opt_ch) { 348 case 'H': 349 goto show_usage; 350 break; 351 352 case 'f': 353 flush_flag = 1; 354 nodefault = 1; 355 break; 356 357 case 'h': 358 def_server = optarg; 359 break; 360 361 case 'l': 362 amq_logfile = optarg; 363 nodefault = 1; 364 break; 365 366 case 'm': 367 minfo_flag = 1; 368 nodefault = 1; 369 break; 370 371 case 'p': 372 getpid_flag = 1; 373 nodefault = 1; 374 break; 375 376 case 's': 377 stats_flag = 1; 378 nodefault = 1; 379 break; 380 381 case 'u': 382 unmount_flag = 1; 383 nodefault = 1; 384 break; 385 386 case 'v': 387 getvers_flag = 1; 388 nodefault = 1; 389 break; 390 391 case 'x': 392 xlog_optstr = optarg; 393 nodefault = 1; 394 break; 395 396 case 'D': 397 debug_opts = optarg; 398 nodefault = 1; 399 break; 400 401 case 'P': 402 amd_program_number = atoi(optarg); 403 break; 404 405 case 'T': 406 use_tcp_flag = 1; 407 break; 408 409 case 'U': 410 use_udp_flag = 1; 411 break; 412 413 case 'w': 414 getpwd_flag = 1; 415 break; 416 417 default: 418 errs = 1; 419 break; 420 } 421 422 if (optind == argc) { 423 if (unmount_flag) 424 errs = 1; 425 } 426 if (errs) { 427 show_usage: 428 fprintf(stderr, "\ 429Usage: %s [-fmpsvwHTU] [-h hostname] [-l log_file|\"syslog\"]\n\ 430\t[-x log_options] [-D debug_options]\n\ 431\t[-P program_number] [[-u] directory ...]\n", 432 am_get_progname() 433 ); 434 exit(1); 435 } 436 437 438 /* set use_udp and use_tcp flags both to on if none are defined */ 439 if (!use_tcp_flag && !use_udp_flag) 440 use_tcp_flag = use_udp_flag = 1; 441 442#if defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT) 443 /* 444 * Figure out root server of cluster 445 */ 446 if (def_server == localhost) 447 server = cluster_server(); 448 else 449#endif /* defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT) */ 450 server = def_server; 451 452 /* 453 * Get address of server 454 */ 455 if ((hp = gethostbyname(server)) == 0 && !STREQ(server, localhost)) { 456 fprintf(stderr, "%s: Can't get address of %s\n", 457 am_get_progname(), server); 458 exit(1); 459 } 460 memset(&server_addr, 0, sizeof server_addr); 461 server_addr.sin_family = AF_INET; 462 if (hp) { 463 memmove((voidp) &server_addr.sin_addr, (voidp) hp->h_addr, 464 sizeof(server_addr.sin_addr)); 465 } else { 466 /* fake "localhost" */ 467 server_addr.sin_addr.s_addr = htonl(0x7f000001); 468 } 469 470 /* 471 * Create RPC endpoint 472 */ 473 tv.tv_sec = 5; /* 5 seconds for timeout or per retry */ 474 tv.tv_usec = 0; 475 476 if (use_tcp_flag) /* try tcp first */ 477 clnt = clnt_create(server, amd_program_number, AMQ_VERSION, "tcp"); 478 if (!clnt && use_udp_flag) { /* try udp next */ 479 clnt = clnt_create(server, amd_program_number, AMQ_VERSION, "udp"); 480 /* if ok, set timeout (valid for connectionless transports only) */ 481 if (clnt) 482 clnt_control(clnt, CLSET_RETRY_TIMEOUT, (char *) &tv); 483 } 484 if (!clnt) { 485 fprintf(stderr, "%s: ", am_get_progname()); 486 clnt_pcreateerror(server); 487 exit(1); 488 } 489 490 /* 491 * Control debugging 492 */ 493 if (debug_opts) { 494 int *rc; 495 amq_setopt opt; 496 opt.as_opt = AMOPT_DEBUG; 497 opt.as_str = debug_opts; 498 rc = amqproc_setopt_1(&opt, clnt); 499 if (rc && *rc < 0) { 500 fprintf(stderr, "%s: daemon not compiled for debug\n", 501 am_get_progname()); 502 errs = 1; 503 } else if (!rc || *rc > 0) { 504 fprintf(stderr, "%s: debug setting for \"%s\" failed\n", 505 am_get_progname(), debug_opts); 506 errs = 1; 507 } 508 } 509 510 /* 511 * Control logging 512 */ 513 if (xlog_optstr) { 514 int *rc; 515 amq_setopt opt; 516 opt.as_opt = AMOPT_XLOG; 517 opt.as_str = xlog_optstr; 518 rc = amqproc_setopt_1(&opt, clnt); 519 if (!rc || *rc) { 520 fprintf(stderr, "%s: setting log level to \"%s\" failed\n", 521 am_get_progname(), xlog_optstr); 522 errs = 1; 523 } 524 } 525 526 /* 527 * Control log file 528 */ 529 if (amq_logfile) { 530 int *rc; 531 amq_setopt opt; 532 opt.as_opt = AMOPT_LOGFILE; 533 opt.as_str = amq_logfile; 534 rc = amqproc_setopt_1(&opt, clnt); 535 if (!rc || *rc) { 536 fprintf(stderr, "%s: setting logfile to \"%s\" failed\n", 537 am_get_progname(), amq_logfile); 538 errs = 1; 539 } 540 } 541 542 /* 543 * Flush map cache 544 */ 545 if (flush_flag) { 546 int *rc; 547 amq_setopt opt; 548 opt.as_opt = AMOPT_FLUSHMAPC; 549 opt.as_str = ""; 550 rc = amqproc_setopt_1(&opt, clnt); 551 if (!rc || *rc) { 552 fprintf(stderr, "%s: amd on %s cannot flush the map cache\n", 553 am_get_progname(), server); 554 errs = 1; 555 } 556 } 557 558 /* 559 * getpwd info 560 */ 561 if (getpwd_flag) { 562 char path[MAXPATHLEN+1]; 563 char *wd = getcwd(path, MAXPATHLEN+1); 564 amq_mount_tree_list *mlp = amqproc_export_1((voidp) 0, clnt); 565 amq_mount_tree_p mt; 566 int i, flag; 567 568 if (!wd) { 569 perror("getcwd"); 570 exit(1); 571 } 572 for (i = 0; mlp && i < mlp->amq_mount_tree_list_len; i++) { 573 mt = mlp->amq_mount_tree_list_val[i]; 574 while (1) { 575 flag = 0; 576 show_pwd(mt, path, &flag); 577 if (!flag) { 578 printf("%s\n", path); 579 break; 580 } 581 } 582 } 583 exit(0); 584 } 585 586 /* 587 * Mount info 588 */ 589 if (minfo_flag) { 590 int dummy; 591 amq_mount_info_list *ml = amqproc_getmntfs_1(&dummy, clnt); 592 if (ml) { 593 int mwid = 0, dwid = 0, twid = 0; 594 show_mi(ml, Calc, &mwid, &dwid, &twid); 595 mwid++; 596 dwid++; 597 twid++; 598 show_mi(ml, Full, &mwid, &dwid, &twid); 599 600 } else { 601 fprintf(stderr, "%s: amd on %s cannot provide mount info\n", 602 am_get_progname(), server); 603 } 604 } 605 606 /* 607 * Get Version 608 */ 609 if (getvers_flag) { 610 amq_string *spp = amqproc_getvers_1((voidp) 0, clnt); 611 if (spp && *spp) { 612 fputs(*spp, stdout); 613 XFREE(*spp); 614 } else { 615 fprintf(stderr, "%s: failed to get version information\n", 616 am_get_progname()); 617 errs = 1; 618 } 619 } 620 621 /* 622 * Get PID of amd 623 */ 624 if (getpid_flag) { 625 int *ip = amqproc_getpid_1((voidp) 0, clnt); 626 if (ip && *ip) { 627 printf("%d\n", *ip); 628 } else { 629 fprintf(stderr, "%s: failed to get PID of amd\n", am_get_progname()); 630 errs = 1; 631 } 632 } 633 634 /* 635 * Apply required operation to all remaining arguments 636 */ 637 if (optind < argc) { 638 do { 639 char *fs = argv[optind++]; 640 if (unmount_flag) { 641 /* 642 * Unmount request 643 */ 644 amqproc_umnt_1(&fs, clnt); 645 } else { 646 /* 647 * Stats request 648 */ 649 amq_mount_tree_p *mtp = amqproc_mnttree_1(&fs, clnt); 650 if (mtp) { 651 amq_mount_tree *mt = *mtp; 652 if (mt) { 653 int mwid = 0, dwid = 0, twid = 0; 654 show_mt(mt, Calc, &mwid, &dwid, &twid); 655 mwid++; 656 dwid++, twid++; 657 printf("%-*.*s Uid Getattr Lookup RdDir RdLnk Statfs Mounted@\n", 658 dwid, dwid, "What"); 659 show_mt(mt, Stats, &mwid, &dwid, &twid); 660 } else { 661 fprintf(stderr, "%s: %s not automounted\n", am_get_progname(), fs); 662 } 663 xdr_pri_free((XDRPROC_T_TYPE) xdr_amq_mount_tree_p, (caddr_t) mtp); 664 } else { 665 fprintf(stderr, "%s: ", am_get_progname()); 666 clnt_perror(clnt, server); 667 errs = 1; 668 } 669 } 670 } while (optind < argc); 671 672 } else if (unmount_flag) { 673 goto show_usage; 674 675 } else if (stats_flag) { 676 amq_mount_stats *ms = amqproc_stats_1((voidp) 0, clnt); 677 if (ms) { 678 show_ms(ms); 679 } else { 680 fprintf(stderr, "%s: ", am_get_progname()); 681 clnt_perror(clnt, server); 682 errs = 1; 683 } 684 685 } else if (!nodefault) { 686 amq_mount_tree_list *mlp = amqproc_export_1((voidp) 0, clnt); 687 if (mlp) { 688 enum show_opt e = Calc; 689 int mwid = 0, dwid = 0, pwid = 0; 690 while (e != ShowDone) { 691 int i; 692 for (i = 0; i < mlp->amq_mount_tree_list_len; i++) { 693 show_mt(mlp->amq_mount_tree_list_val[i], 694 e, &mwid, &dwid, &pwid); 695 } 696 mwid++; 697 dwid++, pwid++; 698 if (e == Calc) 699 e = Short; 700 else if (e == Short) 701 e = ShowDone; 702 } 703 704 } else { 705 fprintf(stderr, "%s: ", am_get_progname()); 706 clnt_perror(clnt, server); 707 errs = 1; 708 } 709 } 710 exit(errs); 711 return errs; /* should never reach here */ 712} 713