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