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