1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright (c) 1999 by Sun Microsystems, Inc. 24 * All rights reserved. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 31 #pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.15*/ 32 33 34 # include <stdio.h> 35 # include <fcntl.h> 36 # include <errno.h> 37 # include <sys/types.h> 38 # include <sys/stat.h> 39 # include <signal.h> 40 # include <unistd.h> 41 # include <sac.h> 42 # include "misc.h" 43 # include "structs.h" 44 # include "adm.h" 45 # include "extern.h" 46 47 48 /* 49 * functions 50 */ 51 52 char *pflags(); 53 char *getfield(); 54 void add_pm(); 55 void cleandirs(); 56 void rem_pm(); 57 void start_pm(); 58 void kill_pm(); 59 void enable_pm(); 60 void disable_pm(); 61 void list_pms(); 62 void read_db(); 63 void sendcmd(); 64 void checkresp(); 65 void single_print(); 66 void catch(); 67 void usage(); 68 69 # define START 0x1 /* -s seen */ 70 # define KILL 0x2 /* -k seen */ 71 # define ENABLE 0x4 /* -e seen */ 72 # define DISABLE 0x8 /* -d seen */ 73 # define PLIST 0x10 /* -l seen */ 74 # define LIST 0x20 /* -L seen */ 75 # define DBREAD 0x40 /* -x seen */ 76 # define CONFIG 0x80 /* -G seen */ 77 # define PCONFIG 0x100 /* -g seen */ 78 # define ADD 0x200 /* -a or other required options seen */ 79 # define REMOVE 0x400 /* -r seen */ 80 81 /* 82 * common error messages 83 */ 84 85 # define NOTPRIV "User not privileged for operation" 86 # define SACERR "Can not contact SAC" 87 # define BADINP "Embedded newlines not allowed" 88 89 90 int Saferrno; /* internal `errno' for exit */ 91 92 93 /* 94 * main - scan args for sacadm and call appropriate handling code 95 */ 96 97 main(argc, argv) 98 int argc; 99 char *argv[]; 100 { 101 int c; /* option letter */ 102 uid_t uid; /* invoker's real uid */ 103 int ret; /* return code from check_version */ 104 int flag = 0; /* flag to record requested operations */ 105 int errflg = 0; /* error indicator */ 106 int version = -1; /* argument to -v */ 107 int count = 0; /* argument to -n */ 108 int badcnt = 0; /* count of bad args to -f */ 109 int sawaflag = 0; /* true if actually saw -a */ 110 int conflag = 0; /* true if output should be in condensed form */ 111 long flags = 0; /* arguments to -f */ 112 FILE *fp; /* scratch file pointer */ 113 char *pmtag = NULL; /* argument to -p */ 114 char *type = NULL; /* argument to -t */ 115 char *script = NULL; /* argument to -z */ 116 char *command = NULL; /* argument to -c */ 117 char *comment = " "; /* argument to -y */ 118 char badargs[BADFARGSIZE]; /* place to hold bad args to -f */ 119 char buf[SIZE]; /* scratch buffer */ 120 register char *p; /* scratch pointer */ 121 122 if (argc == 1) 123 usage(argv[0]); 124 while ((c = getopt(argc, argv, "ac:def:GgkLln:p:rst:v:xy:z:")) != -1) { 125 switch (c) { 126 case 'a': 127 flag |= ADD; 128 sawaflag = 1; 129 break; 130 case 'c': 131 flag |= ADD; 132 if (strchr(optarg, '\n')) { 133 Saferrno = E_BADARGS; 134 error(BADINP); 135 } 136 command = optarg; 137 if (*command != '/') { 138 Saferrno = E_BADARGS; 139 error("command must be a full pathname"); 140 } 141 break; 142 case 'd': 143 flag |= DISABLE; 144 break; 145 case 'e': 146 flag |= ENABLE; 147 break; 148 case 'f': 149 flag |= ADD; 150 while (*optarg) { 151 switch (*optarg++) { 152 case 'd': 153 flags |= D_FLAG; 154 break; 155 case 'x': 156 flags |= X_FLAG; 157 break; 158 default: 159 if (badcnt < (BADFARGSIZE -1)) 160 badargs[badcnt++] = *(optarg - 1); 161 break; 162 } 163 } 164 /* null terminate just in case anything is there */ 165 badargs[badcnt] = '\0'; 166 break; 167 case 'G': 168 flag |= CONFIG; 169 break; 170 case 'g': 171 flag |= PCONFIG; 172 break; 173 case 'k': 174 flag |= KILL; 175 break; 176 case 'L': 177 flag |= LIST; 178 break; 179 case 'l': 180 flag |= PLIST; 181 break; 182 case 'n': 183 flag |= ADD; 184 count = atoi(optarg); 185 if (count < 0) { 186 Saferrno = E_BADARGS; 187 error("restart count can not be negative"); 188 } 189 break; 190 case 'p': 191 pmtag = optarg; 192 if (strchr(optarg, '\n')) { 193 Saferrno = E_BADARGS; 194 error(BADINP); 195 } 196 if (strlen(pmtag) > PMTAGSIZE) { 197 pmtag[PMTAGSIZE] = '\0'; 198 (void) fprintf(stderr, "tag too long, truncated to <%s>\n", pmtag); 199 } 200 for (p = pmtag; *p; p++) { 201 if (!isalnum(*p)) { 202 Saferrno = E_BADARGS; 203 error("port monitor tag must be alphanumeric"); 204 } 205 } 206 break; 207 case 'r': 208 flag |= REMOVE; 209 break; 210 case 's': 211 flag |= START; 212 break; 213 case 't': 214 type = optarg; 215 if (strchr(optarg, '\n')) { 216 Saferrno = E_BADARGS; 217 error(BADINP); 218 } 219 if (strlen(type) > PMTYPESIZE) { 220 type[PMTYPESIZE] = '\0'; 221 (void) fprintf(stderr, "type too long, truncated to <%s>\n", type); 222 } 223 for (p = type; *p; p++) { 224 if (!isalnum(*p)) { 225 Saferrno = E_BADARGS; 226 error("port monitor type must be alphanumeric"); 227 } 228 } 229 break; 230 case 'v': 231 flag |= ADD; 232 version = atoi(optarg); 233 if (version < 0) { 234 Saferrno = E_BADARGS; 235 error("version number can not be negative"); 236 } 237 break; 238 case 'x': 239 flag |= DBREAD; 240 break; 241 case 'y': 242 flag |= ADD; 243 if (strchr(optarg, '\n')) { 244 Saferrno = E_BADARGS; 245 error(BADINP); 246 } 247 comment = optarg; 248 break; 249 case 'z': 250 if (strchr(optarg, '\n')) { 251 Saferrno = E_BADARGS; 252 error(BADINP); 253 } 254 script = optarg; 255 break; 256 case '?': 257 errflg++; 258 } 259 } 260 if (errflg || (optind < argc)) 261 usage(argv[0]); 262 263 if (badcnt) { 264 /* bad flags were given to -f */ 265 Saferrno = E_BADARGS; 266 (void) sprintf(buf, 267 "Invalid request, %s are not valid arguments for \"-f\"", 268 badargs); 269 error(buf); 270 } 271 272 if ((ret = check_version(VERSION, SACTAB)) == 1) { 273 Saferrno = E_SAFERR; 274 error("_sactab version number is incorrect"); 275 } 276 else if (ret == 2) { 277 (void) sprintf(buf, "could not open %s", SACTAB); 278 Saferrno = E_SYSERR; 279 error(buf); 280 } 281 else if (ret == 3) { 282 (void) sprintf(buf, "%s file is corrupt", SACTAB); 283 Saferrno = E_SAFERR; 284 error(buf); 285 } 286 uid = getuid(); 287 switch (flag) { 288 case ADD: 289 if (uid) { 290 Saferrno = E_NOPRIV; 291 error(NOTPRIV); 292 } 293 if (!sawaflag || !pmtag || !type || !command || (version < 0)) 294 usage(argv[0]); 295 add_pm(pmtag, type, command, version, flags, count, script, comment); 296 break; 297 case REMOVE: 298 if (uid) { 299 Saferrno = E_NOPRIV; 300 error(NOTPRIV); 301 } 302 if (!pmtag || type || script) 303 usage(argv[0]); 304 rem_pm(pmtag); 305 break; 306 case START: 307 if (uid) { 308 Saferrno = E_NOPRIV; 309 error(NOTPRIV); 310 } 311 if (!pmtag || type || script) 312 usage(argv[0]); 313 start_pm(pmtag); 314 break; 315 case KILL: 316 if (uid) { 317 Saferrno = E_NOPRIV; 318 error(NOTPRIV); 319 } 320 if (!pmtag || type || script) 321 usage(argv[0]); 322 kill_pm(pmtag); 323 break; 324 case ENABLE: 325 if (uid) { 326 Saferrno = E_NOPRIV; 327 error(NOTPRIV); 328 } 329 if (!pmtag || type || script) 330 usage(argv[0]); 331 enable_pm(pmtag); 332 break; 333 case DISABLE: 334 if (uid) { 335 Saferrno = E_NOPRIV; 336 error(NOTPRIV); 337 } 338 if (!pmtag || type || script) 339 usage(argv[0]); 340 disable_pm(pmtag); 341 break; 342 case LIST: 343 conflag = 1; 344 /* fall through */ 345 case PLIST: 346 if ((pmtag && type) || script) 347 usage(argv[0]); 348 list_pms(pmtag, type, conflag); 349 break; 350 case DBREAD: 351 if (uid) { 352 Saferrno = E_NOPRIV; 353 error(NOTPRIV); 354 } 355 if (type || script) 356 usage(argv[0]); 357 read_db(pmtag); 358 break; 359 case CONFIG: 360 if (script && uid) { 361 Saferrno = E_NOPRIV; 362 error(NOTPRIV); 363 } 364 if (type || pmtag) 365 usage(argv[0]); 366 (void) do_config(script, "_sysconfig"); 367 break; 368 case PCONFIG: 369 if (script && uid) { 370 Saferrno = E_NOPRIV; 371 error(NOTPRIV); 372 } 373 if (!pmtag || type) 374 usage(argv[0]); 375 fp = fopen(SACTAB, "r"); 376 if (fp == NULL) { 377 Saferrno = E_SYSERR; 378 error("Could not open _sactab"); 379 } 380 if (!find_pm(fp, pmtag)) { 381 Saferrno = E_NOEXIST; 382 (void) sprintf(buf, "Invalid request, %s does not exist", pmtag); 383 error(buf); 384 } 385 (void) fclose(fp); 386 (void) sprintf(buf, "%s/_config", pmtag); 387 (void) do_config(script, buf); 388 break; 389 default: 390 /* we only get here if more than one flag bit was set */ 391 usage(argv[0]); 392 /* NOTREACHED */ 393 } 394 quit(); 395 /* NOTREACHED */ 396 } 397 398 399 /* 400 * usage - print out a usage message 401 * 402 * args: cmdname - the name command was invoked with 403 */ 404 405 void 406 usage(cmdname) 407 char *cmdname; 408 { 409 (void) fprintf(stderr, "Usage:\t%s -a -p pmtag -t type -c cmd -v ver [ -f dx ] [ -n count ]\n", cmdname); 410 (void) fprintf(stderr, "\t\t[ -y comment ] [ -z script]\n"); 411 (void) fprintf(stderr, "\t%s -r -p pmtag\n", cmdname); 412 (void) fprintf(stderr, "\t%s -s -p pmtag\n", cmdname); 413 (void) fprintf(stderr, "\t%s -k -p pmtag\n", cmdname); 414 (void) fprintf(stderr, "\t%s -e -p pmtag\n", cmdname); 415 (void) fprintf(stderr, "\t%s -d -p pmtag\n", cmdname); 416 (void) fprintf(stderr, "\t%s -l [ -p pmtag | -t type ]\n", cmdname); 417 (void) fprintf(stderr, "\t%s -L [ -p pmtag | -t type ]\n", cmdname); 418 (void) fprintf(stderr, "\t%s -g -p pmtag [ -z script ]\n", cmdname); 419 (void) fprintf(stderr, "\t%s -G [ -z script ]\n", cmdname); 420 (void) fprintf(stderr, "\t%s -x [ -p pmtag ]\n", cmdname); 421 Saferrno = E_BADARGS; 422 quit(); 423 } 424 425 426 /* 427 * add_pm - add a port monitor entry 428 * 429 * args: tag - port monitor's tag 430 * type - port monitor's type 431 * command - command string to invoke port monitor 432 * version - version number of port monitor's pmtab 433 * flags - port monitor flags 434 * count - restart count 435 * script - port monitor's configuration script 436 * comment - comment describing port monitor 437 */ 438 439 void 440 add_pm(tag, type, command, version, flags, count, script, comment) 441 char *tag; 442 char *type; 443 char *command; 444 int version; 445 long flags; 446 int count; 447 char *script; 448 char *comment; 449 { 450 FILE *fp; /* file pointer for _sactab */ 451 int fd; /* scratch file descriptor */ 452 struct stat statbuf; /* file status info */ 453 char buf[SIZE]; /* scratch buffer */ 454 char fname[SIZE]; /* scratch buffer for building names */ 455 register int i; /* scratch variable */ 456 457 fp = fopen(SACTAB, "r"); 458 if (fp == NULL) { 459 Saferrno = E_SYSERR; 460 error("Could not open _sactab"); 461 } 462 if (find_pm(fp, tag)) { 463 Saferrno = E_DUP; 464 (void) sprintf(buf, "Invalid request, %s already exists", tag); 465 error(buf); 466 } 467 (void) fclose(fp); 468 469 /* 470 * create the directories for it if needed and put in initial files 471 * (/etc/saf and /var/saf) 472 */ 473 474 for (i = 0; i < 2; i++) { 475 /* i == 0 do /etc/saf i == 1 do /var/saf */ 476 (void) sprintf(fname, "%s/%s", (i == 0 ) ? HOME : ALTHOME, tag); 477 if (access(fname, 0) == 0) { 478 /* something is there, find out what it is */ 479 if (stat(fname, &statbuf) < 0) { 480 Saferrno = E_SYSERR; 481 (void) sprintf(buf, "could not stat <%s>", fname); 482 error(buf); 483 } 484 if ((statbuf.st_mode & S_IFMT) != S_IFDIR) { 485 Saferrno = E_SYSERR; 486 (void) sprintf(buf, "<%s> exists and is not a directory", fname); 487 error(buf); 488 } 489 /* note: this removes the directory too */ 490 (void) sprintf(buf, "rm -rf %s", fname); 491 if (system(buf) < 0) { 492 Saferrno = E_SYSERR; 493 (void) sprintf(buf, "could not remove files under <%s>", fname); 494 error(buf); 495 } 496 } 497 498 /* 499 * create the directory 500 */ 501 502 if (mkdir(fname, 0755) < 0) { 503 Saferrno = E_SYSERR; 504 (void) sprintf(buf, "could not create directory <%s>", fname); 505 cleandirs(tag); 506 error(buf); 507 } 508 } 509 510 /* 511 * put in the config script, if specified 512 */ 513 514 if (script) { 515 (void) sprintf(fname, "%s/_config", tag); 516 if (do_config(script, fname)) { 517 cleandirs(tag); 518 /* do_config put out any messages */ 519 quit(); 520 } 521 } 522 523 /* 524 * create the communications pipe, but first make sure that the 525 * permissions we specify are what we get 526 */ 527 528 (void) umask(0); 529 (void) sprintf(fname, "%s/%s/_pmpipe", HOME, tag); 530 if (mknod(fname, S_IFIFO | 0600, 0) < 0) { 531 Saferrno = E_SYSERR; 532 cleandirs(tag); 533 error("could not create communications pipe"); 534 } 535 536 /* 537 * create the _pid file 538 */ 539 540 (void) sprintf(fname, "%s/%s/_pid", HOME, tag); 541 if ((fd = creat(fname, 0644)) < 0) { 542 Saferrno = E_SYSERR; 543 cleandirs(tag); 544 error("could not create _pid file"); 545 } 546 (void) close(fd); 547 548 /* 549 * create the _pmtab file 550 */ 551 552 (void) sprintf(fname, "%s/%s/_pmtab", HOME, tag); 553 if ((fd = creat(fname, 0644)) < 0) { 554 Saferrno = E_SYSERR; 555 cleandirs(tag); 556 error("could not create _pmtab file"); 557 } 558 (void) sprintf(buf, "%s%d\n", VSTR, version); 559 if (write(fd, buf, (unsigned) strlen(buf)) != strlen(buf)) { 560 (void) close(fd); 561 (void) unlink(fname); 562 Saferrno = E_SYSERR; 563 cleandirs(tag); 564 error("error initializing _pmtab"); 565 } 566 (void) close(fd); 567 568 /* 569 * isolate the command name, but remember it since strtok() trashes it 570 */ 571 572 (void) strcpy(buf, command); 573 (void) strtok(command, " \t"); 574 575 /* 576 * check out the command - let addition succeed if it doesn't exist (assume 577 * it will be added later); fail anything else 578 */ 579 580 if (access(command, 0) == 0) { 581 if (stat(command, &statbuf) < 0) { 582 Saferrno = E_SYSERR; 583 (void) fprintf(stderr, "Could not stat <%s>\n", command); 584 cleandirs(tag); 585 quit(); 586 } 587 if (!(statbuf.st_mode & 0111)) { 588 Saferrno = E_BADARGS; 589 (void) fprintf(stderr, "%s not executable\n", command); 590 cleandirs(tag); 591 quit(); 592 } 593 if ((statbuf.st_mode & S_IFMT) != S_IFREG) { 594 Saferrno = E_BADARGS; 595 (void) fprintf(stderr, "%s not a regular file\n", command); 596 cleandirs(tag); 597 quit(); 598 } 599 } 600 else { 601 (void) fprintf(stderr, "warning - %s does not exist\n", command); 602 } 603 604 /* 605 * add the line 606 */ 607 608 fp = fopen(SACTAB, "a"); 609 if (fp == NULL) { 610 Saferrno = E_SYSERR; 611 cleandirs(tag); 612 error("Could not open _sactab"); 613 } 614 (void) fprintf(fp, "%s:%s:%s:%d:%s\t#%s\n", tag, type, 615 (flags ? pflags(flags, FALSE) : ""), count, buf, 616 (comment ? comment : "")); 617 (void) fclose(fp); 618 619 620 /* 621 * tell the SAC to read _sactab if its there (i.e. single user) 622 */ 623 624 if (sac_home()) 625 read_db(NULL); 626 return; 627 } 628 629 630 /* 631 * cleandirs - remove anything that might have been created (i.e. failed 632 * addition. Saferrno is set elsewhere; this is strictly an attempt 633 * to clean up what mess we've left, so don't check to see if the 634 * cleanup worked. 635 * 636 * args: tag - tag of port monitor whose trees should be removed 637 */ 638 639 void 640 cleandirs(tag) 641 char *tag; 642 { 643 char buf[SIZE]; /* scratch buffer */ 644 645 /* note: this removes the directory too, first zap /etc/saf/<tag> */ 646 (void) sprintf(buf, "rm -rf %s/%s", HOME, tag); 647 (void) system(buf); 648 649 /* now remove /var/saf/<tag> */ 650 (void) sprintf(buf, "%s/%s", ALTHOME, tag); 651 (void) rmdir(buf); 652 } 653 654 655 /* 656 * rem_pm - remove a port monitor 657 * 658 * args: tag - tag of port monitor to be removed 659 */ 660 661 void 662 rem_pm(tag) 663 char *tag; 664 { 665 FILE *fp; /* file pointer for _sactab */ 666 FILE *tfp; /* file pointer for temp file */ 667 int line; /* line number entry is on */ 668 char *tname; /* temp file name */ 669 char buf[SIZE]; /* scratch buffer */ 670 671 fp = fopen(SACTAB, "r"); 672 if (fp == NULL) { 673 Saferrno = E_SYSERR; 674 error("Could not open _sactab"); 675 } 676 if ((line = find_pm(fp, tag)) == 0) { 677 Saferrno = E_NOEXIST; 678 (void) sprintf(buf, "Invalid request, %s does not exist", tag); 679 error(buf); 680 } 681 tname = make_tempname("_sactab"); 682 tfp = open_temp(tname); 683 if (line != 1) { 684 if (copy_file(fp, tfp, 1, line - 1)) { 685 (void) unlink(tname); 686 Saferrno = E_SYSERR; 687 error("error accessing temp file"); 688 } 689 } 690 if (copy_file(fp, tfp, line + 1, -1)) { 691 (void) unlink(tname); 692 Saferrno = E_SYSERR; 693 error("error accessing temp file"); 694 } 695 (void) fclose(fp); 696 if (fclose(tfp) == EOF) { 697 (void) unlink(tname); 698 Saferrno = E_SYSERR; 699 error("error closing tempfile"); 700 } 701 /* note - replace only returns if successful */ 702 replace("_sactab", tname); 703 704 /* 705 * tell the SAC to read _sactab if its there (i.e. single user) 706 */ 707 708 if (sac_home()) 709 read_db(NULL); 710 return; 711 } 712 713 714 /* 715 * start_pm - start a particular port monitor 716 * 717 * args: tag - tag of port monitor to be started 718 */ 719 720 void 721 start_pm(tag) 722 char *tag; 723 { 724 struct admcmd cmd; /* command structure */ 725 register struct admcmd *ap = &cmd; /* and a pointer to it */ 726 727 ap->ac_mtype = AC_START; 728 (void) strcpy(ap->ac_tag, tag); 729 ap->ac_pid = getpid(); 730 sendcmd(ap, NULL, tag); 731 return; 732 } 733 734 735 /* 736 * kill_pm - stop a particular port monitor 737 * 738 * args: tag - tag of port monitor to be stopped 739 */ 740 741 void 742 kill_pm(tag) 743 char *tag; 744 { 745 struct admcmd cmd; /* command structure */ 746 register struct admcmd *ap = &cmd; /* and a pointer to it */ 747 748 ap->ac_mtype = AC_KILL; 749 (void) strcpy(ap->ac_tag, tag); 750 ap->ac_pid = getpid(); 751 sendcmd(ap, NULL, tag); 752 return; 753 } 754 755 756 /* 757 * enable_pm - enable a particular port monitor 758 * 759 * args: tag - tag of port monitor to be enabled 760 */ 761 762 void 763 enable_pm(tag) 764 char *tag; 765 { 766 struct admcmd cmd; /* command structure */ 767 register struct admcmd *ap = &cmd; /* and a pointer to it */ 768 769 ap->ac_mtype = AC_ENABLE; 770 (void) strcpy(ap->ac_tag, tag); 771 ap->ac_pid = getpid(); 772 sendcmd(ap, NULL, tag); 773 return; 774 } 775 776 777 /* 778 * disable_pm - disable a particular port monitor 779 * 780 * args: tag - tag of port monitor to be disabled 781 */ 782 783 void 784 disable_pm(tag) 785 char *tag; 786 { 787 struct admcmd cmd; /* command structure */ 788 register struct admcmd *ap = &cmd; /* and a pointer to it */ 789 790 ap->ac_mtype = AC_DISABLE; 791 (void) strcpy(ap->ac_tag, tag); 792 ap->ac_pid = getpid(); 793 sendcmd(ap, NULL, tag); 794 return; 795 } 796 797 798 /* 799 * read_db - tell SAC or a port monitor to read its administrative file. 800 * 801 * args: tag - tag of port monitor that should read its administrative 802 * file. If NULL, it means SAC should. 803 */ 804 805 void 806 read_db(tag) 807 char *tag; 808 { 809 struct admcmd cmd; /* command structure */ 810 register struct admcmd *ap = &cmd; /* and a pointer to it */ 811 812 ap->ac_mtype = (tag) ? AC_PMREAD : AC_SACREAD; 813 if (tag) 814 (void) strcpy(ap->ac_tag, tag); 815 ap->ac_pid = getpid(); 816 sendcmd(ap, NULL, tag); 817 return; 818 } 819 820 821 /* 822 * list_pms - request information about port monitors from SAC and output 823 * requested info 824 * 825 * args: pmtag - tag of port monitor to be listed (may be null) 826 * pmtype - type of port monitors to be listed (may be null) 827 * oflag - true if output should be easily parseable 828 */ 829 830 void 831 list_pms(pmtag, pmtype, oflag) 832 char *pmtag; 833 char *pmtype; 834 int oflag; 835 { 836 struct admcmd acmd; /* command structure */ 837 register struct admcmd *ap = &acmd; /* and a pointer to it */ 838 int nprint = 0; /* count # of PMs printed */ 839 char *p; /* scratch pointer */ 840 char *tag; /* returned tag */ 841 char *type; /* returned type */ 842 char *flags; /* returned flags */ 843 char *rsmax; /* returned restart count */ 844 char *state; /* returned state */ 845 char *cmd; /* returned command string */ 846 char *comment; /* returned comment string */ 847 848 /* 849 * if sac isn't there (single user), provide info direct from _sactab 850 * note: when this routine returns, the process exits, so there is no 851 * need to free up any memory 852 */ 853 854 p = NULL; 855 if (sac_home()) { 856 ap->ac_mtype = AC_STATUS; 857 ap->ac_tag[0] = '\0'; 858 ap->ac_pid = getpid(); 859 sendcmd(ap, &p, NULL); 860 } 861 else { 862 single_print(&p); 863 } 864 865 /* 866 * SAC sends back info in condensed form, we have to separate it out 867 * fields come in ':' separated, records are separated by newlines 868 */ 869 870 while (p && *p) { 871 tag = getfield(&p, ':'); /* PM tag */ 872 type = getfield(&p, ':'); /* PM type */ 873 flags = getfield(&p, ':'); /* flags */ 874 rsmax = getfield(&p, ':'); /* restart count */ 875 state = pstate((unchar) atoi(getfield(&p, ':'))); /* state in nice output format */ 876 cmd = getfield(&p, ':'); /* command */ 877 comment = getfield(&p, '\n'); /* comment */ 878 879 880 /* 881 * print out if no selectors specified, else check to see if 882 * a selector matched 883 */ 884 885 if ((!pmtag && !pmtype) || (pmtag && !strcmp(pmtag, tag)) || (pmtype && !strcmp(pmtype, type))) { 886 if (oflag) { 887 (void) printf("%s:%s:%s:%s:%s:%s#%s\n", tag, type, pflags(atol(flags), FALSE), 888 rsmax, state, cmd, comment); 889 } 890 else { 891 if (nprint == 0) { 892 (void) printf("PMTAG PMTYPE FLGS RCNT STATUS COMMAND\n"); 893 } 894 (void) printf("%-14s %-14s %-4s %-4s %-10s %s #%s\n", tag, type, pflags(atol(flags), TRUE), 895 rsmax, state, cmd, comment); 896 } 897 nprint++; 898 } 899 } 900 /* 901 * if we didn't find any valid ones, indicate an error (note: 1 and 902 * only 1 of the if statements should be true) 903 */ 904 if (nprint == 0) { 905 if (pmtype) 906 (void) fprintf(stderr, "Invalid request, %s does not exist\n", pmtype); 907 else if (pmtag) 908 (void) fprintf(stderr, "Invalid request, %s does not exist\n", pmtag); 909 else if (!pmtag && !pmtype) 910 (void) fprintf(stderr, "No port monitors defined\n"); 911 Saferrno = E_NOEXIST; 912 } 913 return; 914 } 915 916 917 /* 918 * getfield - retrieve and return a field from the sac "status" string (input 919 * argument is modified to point to next field as a side-effect) 920 * 921 * args: p - address of remaining portion of string 922 * sepchar - field terminator character 923 */ 924 925 char * 926 getfield(p, sepchar) 927 char **p; 928 char sepchar; 929 { 930 char *savep; /* for saving argument */ 931 932 savep = *p; 933 *p = strchr(*p, sepchar); 934 if (*p == NULL) { 935 Saferrno = E_SAFERR; 936 (void) fprintf(stderr, "Improper message from SAC\n"); 937 return(NULL); 938 } 939 **p = '\0'; 940 (*p)++; 941 return(savep); 942 } 943 944 945 /* 946 * single_print - print out _sactab if sac not at home (should only happen 947 * in single user mode 948 * 949 * args: p - address of pointer where formatted data should be 950 * placed (space allocated here) 951 */ 952 953 void 954 single_print(p) 955 char **p; 956 { 957 FILE *fp; /* file pointer for _sactab */ 958 struct stat statbuf; /* file status info */ 959 register char *tp1; /* scratch pointer */ 960 register char *tp2; /* scratch pointer */ 961 struct sactab stab; /* place to hold parsed info */ 962 register struct sactab *sp = &stab; /* and a pointer to it */ 963 char buf[SIZE]; /* scratch buffer */ 964 965 fp = fopen(SACTAB, "r"); 966 if (fp == NULL) { 967 Saferrno = E_SYSERR; 968 error("Could not open _sactab"); 969 } 970 if (fstat(fileno(fp), &statbuf) < 0) { 971 Saferrno = E_SYSERR; 972 error("could not stat _sactab"); 973 } 974 975 /* 976 * allocate space to build return string, twice file size should be more 977 * than enough (and make sure it's zero'ed out) 978 */ 979 980 tp1 = calloc(2 * statbuf.st_size, sizeof(char)); 981 if (tp1 == NULL) { 982 Saferrno = E_SYSERR; 983 error("could not allocate storage"); 984 } 985 986 /* 987 * read the file and build the string 988 */ 989 990 while (fgets(buf, SIZE, fp)) { 991 tp2 = trim(buf); 992 if (*tp2 == '\0') 993 continue; 994 parse(tp2, &stab); 995 (void) sprintf(buf, "%s:%s:%d:%d:%d:%s:%s\n", sp->sc_tag, sp->sc_type, 996 sp->sc_flags, sp->sc_rsmax, SSTATE, sp->sc_cmd, sp->sc_comment); 997 (void) strcat(tp1, buf); 998 free(sp->sc_cmd); 999 free(sp->sc_comment); 1000 } 1001 if (!feof(fp)) { 1002 Saferrno = E_SYSERR; 1003 error("error reading _sactab"); 1004 } 1005 (void) fclose(fp); 1006 1007 /* 1008 * point at the just-built string 1009 */ 1010 1011 *p = tp1; 1012 return; 1013 } 1014 1015 1016 /* 1017 * openpipe - open up command pipe to SAC 1018 */ 1019 1020 openpipe() 1021 { 1022 int fd; /* file descriptor associated with command pipe */ 1023 1024 fd = open(CMDPIPE, O_RDWR); 1025 if (fd < 0) { 1026 Saferrno = E_SYSERR; 1027 error(SACERR); 1028 } 1029 1030 /* 1031 * lock pipe to insure serial access, lock will disappear if process dies 1032 */ 1033 1034 if (lockf(fd, F_LOCK, 0) < 0) { 1035 Saferrno = E_SYSERR; 1036 error("unable to lock command pipe"); 1037 } 1038 return(fd); 1039 } 1040 1041 1042 /* 1043 * sendcmd - send a command to the SAC 1044 * 1045 * args: ap - pointer to command to send 1046 * info - pointer to return information from the SAC 1047 * tag - tag of port monitor to which the command applies (may 1048 * be NULL) 1049 */ 1050 1051 void 1052 sendcmd(ap, info, tag) 1053 struct admcmd *ap; 1054 char **info; 1055 char *tag; 1056 { 1057 int fd; /* file descriptor of command pipe */ 1058 1059 fd = openpipe(); 1060 if (write(fd, ap, sizeof(struct admcmd)) < 0) { 1061 Saferrno = E_SYSERR; 1062 error(SACERR); 1063 } 1064 checkresp(fd, info, tag); 1065 1066 /* 1067 * unlock the command pipe - not really necessary since we're about to close 1068 */ 1069 1070 (void) lockf(fd, F_ULOCK, 0); 1071 (void) close(fd); 1072 return; 1073 } 1074 1075 1076 /* 1077 * checkresp - check the SAC's response to our command 1078 * 1079 * args: fd - file descriptor of command pipe 1080 * info - pointer to return and info send along by SAC 1081 * tag - tag of port monitor that the command had been 1082 * for, only used for error reporting 1083 */ 1084 1085 void 1086 checkresp(fd, info, tag) 1087 int fd; 1088 char **info; 1089 char *tag; 1090 { 1091 struct admack ack; /* acknowledgment struct */ 1092 register struct admack *ak = &ack; /* and a pointer to it */ 1093 pid_t pid; /* my pid */ 1094 struct sigaction sigact; /* signal handler setup */ 1095 1096 /* 1097 * make sure this ack is meant for me, put an alarm around the read 1098 * so we don't hang out forever. 1099 */ 1100 1101 pid = getpid(); 1102 sigact.sa_flags = 0; 1103 sigact.sa_handler = catch; 1104 (void) sigemptyset(&sigact.sa_mask); 1105 (void) sigaddset(&sigact.sa_mask, SIGALRM); 1106 (void) sigaction(SIGALRM, &sigact, NULL); 1107 (void) alarm(10); 1108 do { 1109 if (read(fd, ak, sizeof(ack)) != sizeof(ack)) { 1110 Saferrno = E_SACNOTRUN; 1111 error(SACERR); 1112 } 1113 } while (pid != ak->ak_pid); 1114 (void) alarm(0); 1115 1116 /* 1117 * check out what happened 1118 */ 1119 1120 switch (ak->ak_resp) { 1121 case AK_ACK: 1122 /* everything was A-OK */ 1123 if (info && ak->ak_size) { 1124 /* there is return info and a place to put it */ 1125 if ((*info = malloc((unsigned) (ak->ak_size + 1))) == NULL) { 1126 Saferrno = E_SYSERR; 1127 error("could not allocate storage"); 1128 } 1129 if (read(fd, *info, (unsigned) ak->ak_size) != ak->ak_size) { 1130 Saferrno = E_SYSERR; 1131 error(SACERR); 1132 } 1133 /* make sure "string" is null-terminated */ 1134 (*info)[ak->ak_size] = '\0'; 1135 } 1136 return; 1137 /* something went wrong - see what */ 1138 case AK_PMRUN: 1139 Saferrno = E_PMRUN; 1140 (void) fprintf(stderr, "Port monitor, %s, is already running\n", tag); 1141 break; 1142 case AK_PMNOTRUN: 1143 Saferrno = E_PMNOTRUN; 1144 (void) fprintf(stderr, "Port monitor, %s, is not running\n", tag); 1145 break; 1146 case AK_NOPM: 1147 Saferrno = E_NOEXIST; 1148 (void) fprintf(stderr, "Invalid request, %s does not exist\n", tag); 1149 break; 1150 case AK_UNKNOWN: 1151 Saferrno = E_SAFERR; 1152 (void) fprintf(stderr, "Internal error - sent invalid command\n"); 1153 break; 1154 case AK_NOCONTACT: 1155 Saferrno = E_SAFERR; 1156 (void) fprintf(stderr, "Could not contact %s\n", tag); 1157 break; 1158 case AK_PMLOCK: 1159 Saferrno = E_SAFERR; 1160 (void) fprintf(stderr, "Could not start %s - _pid file locked\n", tag); 1161 break; 1162 case AK_RECOVER: 1163 Saferrno = E_RECOVER; 1164 (void) fprintf(stderr, "Port monitor, %s, is in recovery\n", tag); 1165 break; 1166 case AK_REQFAIL: 1167 Saferrno = E_SAFERR; 1168 (void) fprintf(stderr, "This request could not be completed - see sac log file for details\n"); 1169 break; 1170 default: 1171 Saferrno = E_SAFERR; 1172 (void) fprintf(stderr, "unknown response\n"); 1173 break; 1174 } 1175 } 1176 1177 1178 /* 1179 * catch - catcher for SIGALRM, don't need to do anything 1180 */ 1181 1182 void 1183 catch() 1184 { 1185 } 1186 1187 1188 /* 1189 * pflags - put port monitor flags into intelligible form for output 1190 * 1191 * args: flags - binary representation of flags 1192 * dflag - true if a "-" should be returned if no flags 1193 */ 1194 1195 char * 1196 pflags(flags, dflag) 1197 long flags; 1198 int dflag; 1199 { 1200 register int i; /* scratch counter */ 1201 static char buf[SIZE]; /* formatted flags */ 1202 1203 if (flags == 0) { 1204 if (dflag) 1205 return("-"); 1206 else 1207 return(""); 1208 } 1209 i = 0; 1210 if (flags & D_FLAG) { 1211 buf[i++] = 'd'; 1212 flags &= ~D_FLAG; 1213 } 1214 if (flags & X_FLAG) { 1215 buf[i++] = 'x'; 1216 flags &= ~X_FLAG; 1217 } 1218 if (flags) { 1219 (void) fprintf(stderr, "Bad information from SAC\n"); 1220 exit(1); 1221 } 1222 buf[i] = '\0'; 1223 return(buf); 1224 } 1225 1226 1227 /* 1228 * sac_home - returns true is sac has a lock on its logfile, false 1229 * otherwise (useful to avoid errors for administrative actions in 1230 * single user mode) 1231 */ 1232 1233 sac_home() 1234 { 1235 int fd; /* fd to sac logfile */ 1236 1237 fd = open(LOGFILE, O_RDONLY); 1238 if (fd < 0) { 1239 fprintf(stderr, "warning - could not ascertain sac status\n"); 1240 return(FALSE); 1241 } 1242 if (lockf(fd, F_TEST, 0) < 0) { 1243 /* everything is ok */ 1244 (void) close(fd); 1245 return(TRUE); 1246 } 1247 else { 1248 /* no one home */ 1249 (void) close(fd); 1250 return(FALSE); 1251 } 1252 } 1253