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