1 /* 2 * Copyright (c) 1990 Jan-Simon Pendry 3 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine 4 * Copyright (c) 1990, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Jan-Simon Pendry at Imperial College, London. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * from: @(#)amq.c 8.1 (Berkeley) 6/7/93 39 * $Id: amq.c,v 1.5 1997/01/15 23:43:46 millert Exp $ 40 */ 41 42 /* 43 * Automounter query tool 44 */ 45 46 #ifndef lint 47 char copyright[] = "\ 48 @(#)Copyright (c) 1990 Jan-Simon Pendry\n\ 49 @(#)Copyright (c) 1990 Imperial College of Science, Technology & Medicine\n\ 50 @(#)Copyright (c) 1990, 1993\n\ 51 The Regents of the University of California. All rights reserved.\n"; 52 #endif /* not lint */ 53 54 #ifndef lint 55 static char rcsid[] = "$Id: amq.c,v 1.5 1997/01/15 23:43:46 millert Exp $"; 56 static char sccsid[] = "@(#)amq.c 8.1 (Berkeley) 6/7/93"; 57 #endif /* not lint */ 58 59 #include "am.h" 60 #include "amq.h" 61 #include <stdio.h> 62 #include <fcntl.h> 63 #include <netdb.h> 64 65 static int privsock(); 66 67 char *progname; 68 static int flush_flag; 69 static int minfo_flag; 70 static int unmount_flag; 71 static int stats_flag; 72 static int getvers_flag; 73 static char *debug_opts; 74 static char *logfile; 75 static char *mount_map; 76 static char *xlog_optstr; 77 static char localhost[] = "localhost"; 78 static char *def_server = localhost; 79 80 extern int optind; 81 extern char *optarg; 82 83 static struct timeval tmo = { 10, 0 }; 84 #define TIMEOUT tmo 85 86 enum show_opt { Full, Stats, Calc, Short, ShowDone }; 87 88 /* 89 * If (e) is Calc then just calculate the sizes 90 * Otherwise display the mount node on stdout 91 */ 92 static void show_mti(mt, e, mwid, dwid, twid) 93 amq_mount_tree *mt; 94 enum show_opt e; 95 int *mwid; 96 int *dwid; 97 int *twid; 98 { 99 switch (e) { 100 case Calc: { 101 int mw = strlen(mt->mt_mountinfo); 102 int dw = strlen(mt->mt_directory); 103 int tw = strlen(mt->mt_type); 104 if (mw > *mwid) *mwid = mw; 105 if (dw > *dwid) *dwid = dw; 106 if (tw > *twid) *twid = tw; 107 } break; 108 109 case Full: { 110 struct tm *tp = localtime((time_t *) &mt->mt_mounttime); 111 printf("%-*.*s %-*.*s %-*.*s %s\n\t%-5d %-7d %-6d %-7d %-7d %-6d %02d/%02d/%02d %02d:%02d:%02d\n", 112 *dwid, *dwid, 113 *mt->mt_directory ? mt->mt_directory : "/", /* XXX */ 114 *twid, *twid, 115 mt->mt_type, 116 *mwid, *mwid, 117 mt->mt_mountinfo, 118 mt->mt_mountpoint, 119 120 mt->mt_mountuid, 121 mt->mt_getattr, 122 mt->mt_lookup, 123 mt->mt_readdir, 124 mt->mt_readlink, 125 mt->mt_statfs, 126 127 tp->tm_year > 99 ? tp->tm_year - 100 : tp->tm_year, 128 tp->tm_mon+1, tp->tm_mday, 129 tp->tm_hour, tp->tm_min, tp->tm_sec); 130 } break; 131 132 case Stats: { 133 struct tm *tp = localtime((time_t *) &mt->mt_mounttime); 134 printf("%-*.*s %-5d %-7d %-6d %-7d %-7d %-6d %02d/%02d/%02d %02d:%02d:%02d\n", 135 *dwid, *dwid, 136 *mt->mt_directory ? mt->mt_directory : "/", /* XXX */ 137 138 mt->mt_mountuid, 139 mt->mt_getattr, 140 mt->mt_lookup, 141 mt->mt_readdir, 142 mt->mt_readlink, 143 mt->mt_statfs, 144 145 tp->tm_year > 99 ? tp->tm_year - 100 : tp->tm_year, 146 tp->tm_mon+1, tp->tm_mday, 147 tp->tm_hour, tp->tm_min, tp->tm_sec); 148 } break; 149 150 case Short: { 151 printf("%-*.*s %-*.*s %-*.*s %s\n", 152 *dwid, *dwid, 153 *mt->mt_directory ? mt->mt_directory : "/", 154 *twid, *twid, 155 mt->mt_type, 156 *mwid, *mwid, 157 mt->mt_mountinfo, 158 mt->mt_mountpoint); 159 } break; 160 } 161 } 162 163 /* 164 * Display a mount tree. 165 */ 166 static void show_mt(mt, e, mwid, dwid, pwid) 167 amq_mount_tree *mt; 168 enum show_opt e; 169 int *mwid; 170 int *dwid; 171 int *pwid; 172 { 173 while (mt) { 174 show_mti(mt, e, mwid, dwid, pwid); 175 show_mt(mt->mt_next, e, mwid, dwid, pwid); 176 mt = mt->mt_child; 177 } 178 } 179 180 static void show_mi(ml, e, mwid, dwid, twid) 181 amq_mount_info_list *ml; 182 enum show_opt e; 183 int *mwid; 184 int *dwid; 185 int *twid; 186 { 187 int i; 188 switch (e) { 189 case Calc: { 190 for (i = 0; i < ml->amq_mount_info_list_len; i++) { 191 amq_mount_info *mi = &ml->amq_mount_info_list_val[i]; 192 int mw = strlen(mi->mi_mountinfo); 193 int dw = strlen(mi->mi_mountpt); 194 int tw = strlen(mi->mi_type); 195 if (mw > *mwid) *mwid = mw; 196 if (dw > *dwid) *dwid = dw; 197 if (tw > *twid) *twid = tw; 198 } 199 } break; 200 201 case Full: { 202 for (i = 0; i < ml->amq_mount_info_list_len; i++) { 203 amq_mount_info *mi = &ml->amq_mount_info_list_val[i]; 204 printf("%-*.*s %-*.*s %-*.*s %-3d %s is %s", 205 *mwid, *mwid, mi->mi_mountinfo, 206 *dwid, *dwid, mi->mi_mountpt, 207 *twid, *twid, mi->mi_type, 208 mi->mi_refc, mi->mi_fserver, 209 mi->mi_up > 0 ? "up" : 210 mi->mi_up < 0 ? "starting" : "down"); 211 if (mi->mi_error > 0) { 212 #ifdef HAS_STRERROR 213 printf(" (%s)", strerror(mi->mi_error)); 214 #else 215 extern char *sys_errlist[]; 216 extern int sys_nerr; 217 if (mi->mi_error < sys_nerr) 218 printf(" (%s)", sys_errlist[mi->mi_error]); 219 else 220 printf(" (Error %d)", mi->mi_error); 221 #endif 222 } else if (mi->mi_error < 0) { 223 fputs(" (in progress)", stdout); 224 } 225 fputc('\n', stdout); 226 } 227 } break; 228 } 229 } 230 231 /* 232 * Display general mount statistics 233 */ 234 static void show_ms(ms) 235 amq_mount_stats *ms; 236 { 237 printf("\ 238 requests stale mount mount unmount\n\ 239 deferred fhandles ok failed failed\n\ 240 %-9d %-9d %-9d %-9d %-9d\n", 241 ms->as_drops, ms->as_stale, ms->as_mok, ms->as_merr, ms->as_uerr); 242 } 243 244 static bool_t 245 xdr_pri_free(xdr_args, args_ptr) 246 xdrproc_t xdr_args; 247 caddr_t args_ptr; 248 { 249 XDR xdr; 250 xdr.x_op = XDR_FREE; 251 return ((*xdr_args)(&xdr, args_ptr)); 252 } 253 254 #ifdef hpux 255 #include <cluster.h> 256 static char *cluster_server() 257 { 258 struct cct_entry *cp; 259 260 if (cnodeid() == 0) { 261 /* 262 * Not clustered 263 */ 264 return def_server; 265 } 266 267 while (cp = getccent()) 268 if (cp->cnode_type == 'r') 269 return cp->cnode_name; 270 271 272 return def_server; 273 } 274 #endif /* hpux */ 275 276 /* 277 * MAIN 278 */ 279 main(argc, argv) 280 int argc; 281 char *argv[]; 282 { 283 int opt_ch; 284 int errs = 0; 285 char *server; 286 struct sockaddr_in server_addr; 287 288 /* In order to pass the Amd security check, we must use a priv port. */ 289 int s; 290 291 CLIENT *clnt; 292 struct hostent *hp; 293 int nodefault = 0; 294 295 /* 296 * Compute program name 297 */ 298 if (argv[0]) { 299 progname = strrchr(argv[0], '/'); 300 if (progname && progname[1]) 301 progname++; 302 else 303 progname = argv[0]; 304 } 305 if (!progname) 306 progname = "amq"; 307 308 /* 309 * Parse arguments 310 */ 311 while ((opt_ch = getopt(argc, argv, "fh:l:msuvx:D:M:")) != -1) 312 switch (opt_ch) { 313 case 'f': 314 flush_flag = 1; 315 nodefault = 1; 316 break; 317 318 case 'h': 319 def_server = optarg; 320 break; 321 322 case 'l': 323 logfile = optarg; 324 nodefault = 1; 325 break; 326 327 case 'm': 328 minfo_flag = 1; 329 nodefault = 1; 330 break; 331 332 case 's': 333 stats_flag = 1; 334 nodefault = 1; 335 break; 336 337 case 'u': 338 unmount_flag = 1; 339 nodefault = 1; 340 break; 341 342 case 'v': 343 getvers_flag = 1; 344 nodefault = 1; 345 break; 346 347 case 'x': 348 xlog_optstr = optarg; 349 nodefault = 1; 350 break; 351 352 case 'D': 353 debug_opts = optarg; 354 nodefault = 1; 355 break; 356 357 case 'M': 358 mount_map = optarg; 359 nodefault = 1; 360 break; 361 362 default: 363 errs = 1; 364 break; 365 } 366 367 if (optind == argc) { 368 if (unmount_flag) 369 errs = 1; 370 } 371 372 if (errs) { 373 show_usage: 374 fprintf(stderr, "\ 375 Usage: %s [-h host] [[-f] [-m] [-v] [-s]] | [[-u] directory ...]] |\n\ 376 \t[-l logfile|\"syslog\"] [-x log_flags] [-D dbg_opts] [-M mapent]\n", progname); 377 exit(1); 378 } 379 380 #ifdef hpux 381 /* 382 * Figure out root server of cluster 383 */ 384 if (def_server == localhost) 385 server = cluster_server(); 386 else 387 #endif /* hpux */ 388 server = def_server; 389 390 /* 391 * Get address of server 392 */ 393 if ((hp = gethostbyname(server)) == 0 && strcmp(server, localhost) != 0) { 394 fprintf(stderr, "%s: Can't get address of %s\n", progname, server); 395 exit(1); 396 } 397 bzero(&server_addr, sizeof server_addr); 398 server_addr.sin_family = AF_INET; 399 if (hp) { 400 bcopy((voidp) hp->h_addr, (voidp) &server_addr.sin_addr, 401 sizeof(server_addr.sin_addr)); 402 } else { 403 /* fake "localhost" */ 404 server_addr.sin_addr.s_addr = htonl(0x7f000001); 405 } 406 407 /* 408 * Create RPC endpoint 409 */ 410 s = privsock(SOCK_STREAM); 411 clnt = clnttcp_create(&server_addr, AMQ_PROGRAM, AMQ_VERSION, &s, 0, 0); 412 if (clnt == 0) { 413 close(s); 414 s = privsock(SOCK_DGRAM); 415 clnt = clntudp_create(&server_addr, AMQ_PROGRAM, AMQ_VERSION, TIMEOUT, &s); 416 } 417 if (clnt == 0) { 418 fprintf(stderr, "%s: ", progname); 419 clnt_pcreateerror(server); 420 exit(1); 421 } 422 423 /* 424 * Control debugging 425 */ 426 if (debug_opts) { 427 int *rc; 428 amq_setopt opt; 429 opt.as_opt = AMOPT_DEBUG; 430 opt.as_str = debug_opts; 431 rc = amqproc_setopt_1(&opt, clnt); 432 if (rc && *rc < 0) { 433 fprintf(stderr, "%s: daemon not compiled for debug", progname); 434 errs = 1; 435 } else if (!rc || *rc > 0) { 436 fprintf(stderr, "%s: debug setting for \"%s\" failed\n", progname, debug_opts); 437 errs = 1; 438 } 439 } 440 441 /* 442 * Control logging 443 */ 444 if (xlog_optstr) { 445 int *rc; 446 amq_setopt opt; 447 opt.as_opt = AMOPT_XLOG; 448 opt.as_str = xlog_optstr; 449 rc = amqproc_setopt_1(&opt, clnt); 450 if (!rc || *rc) { 451 fprintf(stderr, "%s: setting log level to \"%s\" failed\n", progname, xlog_optstr); 452 errs = 1; 453 } 454 } 455 456 /* 457 * Control log file 458 */ 459 if (logfile) { 460 int *rc; 461 amq_setopt opt; 462 opt.as_opt = AMOPT_LOGFILE; 463 opt.as_str = logfile; 464 rc = amqproc_setopt_1(&opt, clnt); 465 if (!rc || *rc) { 466 fprintf(stderr, "%s: setting logfile to \"%s\" failed\n", progname, logfile); 467 errs = 1; 468 } 469 } 470 471 /* 472 * Flush map cache 473 */ 474 if (flush_flag) { 475 int *rc; 476 amq_setopt opt; 477 opt.as_opt = AMOPT_FLUSHMAPC; 478 opt.as_str = ""; 479 rc = amqproc_setopt_1(&opt, clnt); 480 if (!rc || *rc) { 481 fprintf(stderr, "%s: amd on %s cannot flush the map cache\n", progname, server); 482 errs = 1; 483 } 484 } 485 486 /* 487 * Mount info 488 */ 489 if (minfo_flag) { 490 int dummy; 491 amq_mount_info_list *ml = amqproc_getmntfs_1(&dummy, clnt); 492 if (ml) { 493 int mwid = 0, dwid = 0, twid = 0; 494 show_mi(ml, Calc, &mwid, &dwid, &twid); 495 mwid++; dwid++; twid++; 496 show_mi(ml, Full, &mwid, &dwid, &twid); 497 498 } else { 499 fprintf(stderr, "%s: amd on %s cannot provide mount info\n", progname, server); 500 } 501 } 502 503 /* 504 * Mount map 505 */ 506 if (mount_map) { 507 int *rc; 508 do { 509 rc = amqproc_mount_1(&mount_map, clnt); 510 } while (rc && *rc < 0); 511 if (!rc || *rc > 0) { 512 if (rc) 513 errno = *rc; 514 else 515 errno = ETIMEDOUT; 516 fprintf(stderr, "%s: could not start new ", progname); 517 perror("autmount point"); 518 } 519 } 520 521 /* 522 * Get Version 523 */ 524 if (getvers_flag) { 525 amq_string *spp = amqproc_getvers_1((voidp) 0, clnt); 526 if (spp && *spp) { 527 printf("%s.\n", *spp); 528 free(*spp); 529 } else { 530 fprintf(stderr, "%s: failed to get version information\n", progname); 531 errs = 1; 532 } 533 } 534 535 /* 536 * Apply required operation to all remaining arguments 537 */ 538 if (optind < argc) { 539 do { 540 char *fs = argv[optind++]; 541 if (unmount_flag) { 542 /* 543 * Unmount request 544 */ 545 amqproc_umnt_1(&fs, clnt); 546 } else { 547 /* 548 * Stats request 549 */ 550 amq_mount_tree_p *mtp = amqproc_mnttree_1(&fs, clnt); 551 if (mtp) { 552 amq_mount_tree *mt = *mtp; 553 if (mt) { 554 int mwid = 0, dwid = 0, twid = 0; 555 show_mt(mt, Calc, &mwid, &dwid, &twid); 556 mwid++; dwid++, twid++; 557 printf("%-*.*s Uid Getattr Lookup RdDir RdLnk Statfs Mounted@\n", 558 dwid, dwid, "What"); 559 show_mt(mt, Stats, &mwid, &dwid, &twid); 560 } else { 561 fprintf(stderr, "%s: %s not automounted\n", progname, fs); 562 } 563 xdr_pri_free(xdr_amq_mount_tree_p, (caddr_t) mtp); 564 } else { 565 fprintf(stderr, "%s: ", progname); 566 clnt_perror(clnt, server); 567 errs = 1; 568 } 569 } 570 } while (optind < argc); 571 } else if (unmount_flag) { 572 goto show_usage; 573 } else if (stats_flag) { 574 amq_mount_stats *ms = amqproc_stats_1((voidp) 0, clnt); 575 if (ms) { 576 show_ms(ms); 577 } else { 578 fprintf(stderr, "%s: ", progname); 579 clnt_perror(clnt, server); 580 errs = 1; 581 } 582 } else if (!nodefault) { 583 amq_mount_tree_list *mlp = amqproc_export_1((voidp) 0, clnt); 584 if (mlp) { 585 enum show_opt e = Calc; 586 int mwid = 0, dwid = 0, pwid = 0; 587 while (e != ShowDone) { 588 int i; 589 for (i = 0; i < mlp->amq_mount_tree_list_len; i++) { 590 show_mt(mlp->amq_mount_tree_list_val[i], 591 e, &mwid, &dwid, &pwid); 592 } 593 mwid++; dwid++, pwid++; 594 if (e == Calc) e = Short; 595 else if (e == Short) e = ShowDone; 596 } 597 } else { 598 fprintf(stderr, "%s: ", progname); 599 clnt_perror(clnt, server); 600 errs = 1; 601 } 602 } 603 604 exit(errs); 605 } 606 607 /* 608 * udpresport creates a datagram socket and attempts to bind it to a 609 * secure port. 610 * returns: The bound socket, or -1 to indicate an error. 611 */ 612 static int inetresport(ty) 613 int ty; 614 { 615 int alport; 616 struct sockaddr_in addr; 617 int sock; 618 619 /* Use internet address family */ 620 addr.sin_family = AF_INET; 621 addr.sin_addr.s_addr = INADDR_ANY; 622 if ((sock = socket(AF_INET, ty, 0)) < 0) 623 return -1; 624 for (alport = IPPORT_RESERVED-1; alport > IPPORT_RESERVED/2 + 1; alport--) { 625 addr.sin_port = htons((u_short)alport); 626 if (bind(sock, (struct sockaddr *)&addr, sizeof (addr)) >= 0) 627 return sock; 628 if (errno != EADDRINUSE) { 629 close(sock); 630 return -1; 631 } 632 } 633 close(sock); 634 errno = EAGAIN; 635 return -1; 636 } 637 638 /* 639 * Privsock() calls inetresport() to attempt to bind a socket to a secure 640 * port. If inetresport() fails, privsock returns a magic socket number which 641 * indicates to RPC that it should make its own socket. 642 * returns: A privileged socket # or RPC_ANYSOCK. 643 */ 644 static int privsock(ty) 645 int ty; 646 { 647 int sock = inetresport(ty); 648 649 if (sock < 0) { 650 errno = 0; 651 /* Couldn't get a secure port, let RPC make an insecure one */ 652 sock = RPC_ANYSOCK; 653 } 654 return sock; 655 } 656 657 #ifdef DEBUG 658 xfree(f, l, p) 659 char *f, *l; 660 voidp p; 661 { 662 free(p); 663 } 664 #endif /* DEBUG */ 665