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