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