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