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 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 #pragma ident "%Z%%M% %I% %E% SMI" 31 32 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <strings.h> 36 #include <fcntl.h> 37 #include <errno.h> 38 #include <sys/types.h> 39 #include <sys/stat.h> 40 #include <signal.h> 41 #include <unistd.h> 42 #include <sac.h> 43 #include "misc.h" 44 #include "structs.h" 45 #include "adm.h" 46 #include "extern.h" 47 48 49 /* 50 * functions 51 */ 52 53 char *pflags(); 54 char *getfield(); 55 void add_pm(); 56 void cleandirs(); 57 void rem_pm(); 58 void start_pm(); 59 void kill_pm(); 60 void enable_pm(); 61 void disable_pm(); 62 void list_pms(); 63 void read_db(); 64 void sendcmd(); 65 void checkresp(); 66 void single_print(); 67 void catch(); 68 void usage(); 69 70 # define START 0x1 /* -s seen */ 71 # define KILL 0x2 /* -k seen */ 72 # define ENABLE 0x4 /* -e seen */ 73 # define DISABLE 0x8 /* -d seen */ 74 # define PLIST 0x10 /* -l seen */ 75 # define LIST 0x20 /* -L seen */ 76 # define DBREAD 0x40 /* -x seen */ 77 # define CONFIG 0x80 /* -G seen */ 78 # define PCONFIG 0x100 /* -g seen */ 79 # define ADD 0x200 /* -a or other required options seen */ 80 # define REMOVE 0x400 /* -r seen */ 81 82 /* 83 * common error messages 84 */ 85 86 # define NOTPRIV "User not privileged for operation" 87 # define SACERR "Can not contact SAC" 88 # define BADINP "Embedded newlines not allowed" 89 90 91 int Saferrno; /* internal `errno' for exit */ 92 93 94 /* 95 * main - scan args for sacadm and call appropriate handling code 96 */ 97 98 int 99 main(int argc, 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 return (0); 397 } 398 399 400 /* 401 * usage - print out a usage message 402 * 403 * args: cmdname - the name command was invoked with 404 */ 405 406 void 407 usage(cmdname) 408 char *cmdname; 409 { 410 (void) fprintf(stderr, "Usage:\t%s -a -p pmtag -t type -c cmd -v ver [ -f dx ] [ -n count ]\n", cmdname); 411 (void) fprintf(stderr, "\t\t[ -y comment ] [ -z script]\n"); 412 (void) fprintf(stderr, "\t%s -r -p pmtag\n", cmdname); 413 (void) fprintf(stderr, "\t%s -s -p pmtag\n", cmdname); 414 (void) fprintf(stderr, "\t%s -k -p pmtag\n", cmdname); 415 (void) fprintf(stderr, "\t%s -e -p pmtag\n", cmdname); 416 (void) fprintf(stderr, "\t%s -d -p pmtag\n", cmdname); 417 (void) fprintf(stderr, "\t%s -l [ -p pmtag | -t type ]\n", cmdname); 418 (void) fprintf(stderr, "\t%s -L [ -p pmtag | -t type ]\n", cmdname); 419 (void) fprintf(stderr, "\t%s -g -p pmtag [ -z script ]\n", cmdname); 420 (void) fprintf(stderr, "\t%s -G [ -z script ]\n", cmdname); 421 (void) fprintf(stderr, "\t%s -x [ -p pmtag ]\n", cmdname); 422 Saferrno = E_BADARGS; 423 quit(); 424 } 425 426 427 /* 428 * add_pm - add a port monitor entry 429 * 430 * args: tag - port monitor's tag 431 * type - port monitor's type 432 * command - command string to invoke port monitor 433 * version - version number of port monitor's pmtab 434 * flags - port monitor flags 435 * count - restart count 436 * script - port monitor's configuration script 437 * comment - comment describing port monitor 438 */ 439 440 void 441 add_pm(tag, type, command, version, flags, count, script, comment) 442 char *tag; 443 char *type; 444 char *command; 445 int version; 446 long flags; 447 int count; 448 char *script; 449 char *comment; 450 { 451 FILE *fp; /* file pointer for _sactab */ 452 int fd; /* scratch file descriptor */ 453 struct stat statbuf; /* file status info */ 454 char buf[SIZE]; /* scratch buffer */ 455 char fname[SIZE]; /* scratch buffer for building names */ 456 register int i; /* scratch variable */ 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 (void) sprintf(buf, "rm -rf %s", fname); 492 if (system(buf) < 0) { 493 Saferrno = E_SYSERR; 494 (void) sprintf(buf, "could not remove files under <%s>", fname); 495 error(buf); 496 } 497 } 498 499 /* 500 * create the directory 501 */ 502 503 if (mkdir(fname, 0755) < 0) { 504 Saferrno = E_SYSERR; 505 (void) sprintf(buf, "could not create directory <%s>", fname); 506 cleandirs(tag); 507 error(buf); 508 } 509 } 510 511 /* 512 * put in the config script, if specified 513 */ 514 515 if (script) { 516 (void) sprintf(fname, "%s/_config", tag); 517 if (do_config(script, fname)) { 518 cleandirs(tag); 519 /* do_config put out any messages */ 520 quit(); 521 } 522 } 523 524 /* 525 * create the communications pipe, but first make sure that the 526 * permissions we specify are what we get 527 */ 528 529 (void) umask(0); 530 (void) sprintf(fname, "%s/%s/_pmpipe", HOME, tag); 531 if (mknod(fname, S_IFIFO | 0600, 0) < 0) { 532 Saferrno = E_SYSERR; 533 cleandirs(tag); 534 error("could not create communications pipe"); 535 } 536 537 /* 538 * create the _pid file 539 */ 540 541 (void) sprintf(fname, "%s/%s/_pid", HOME, tag); 542 if ((fd = creat(fname, 0644)) < 0) { 543 Saferrno = E_SYSERR; 544 cleandirs(tag); 545 error("could not create _pid file"); 546 } 547 (void) close(fd); 548 549 /* 550 * create the _pmtab file 551 */ 552 553 (void) sprintf(fname, "%s/%s/_pmtab", HOME, tag); 554 if ((fd = creat(fname, 0644)) < 0) { 555 Saferrno = E_SYSERR; 556 cleandirs(tag); 557 error("could not create _pmtab file"); 558 } 559 (void) sprintf(buf, "%s%d\n", VSTR, version); 560 if (write(fd, buf, (unsigned) strlen(buf)) != strlen(buf)) { 561 (void) close(fd); 562 (void) unlink(fname); 563 Saferrno = E_SYSERR; 564 cleandirs(tag); 565 error("error initializing _pmtab"); 566 } 567 (void) close(fd); 568 569 /* 570 * isolate the command name, but remember it since strtok() trashes it 571 */ 572 573 (void) strcpy(buf, command); 574 (void) strtok(command, " \t"); 575 576 /* 577 * check out the command - let addition succeed if it doesn't exist (assume 578 * it will be added later); fail anything else 579 */ 580 581 if (access(command, 0) == 0) { 582 if (stat(command, &statbuf) < 0) { 583 Saferrno = E_SYSERR; 584 (void) fprintf(stderr, "Could not stat <%s>\n", command); 585 cleandirs(tag); 586 quit(); 587 } 588 if (!(statbuf.st_mode & 0111)) { 589 Saferrno = E_BADARGS; 590 (void) fprintf(stderr, "%s not executable\n", command); 591 cleandirs(tag); 592 quit(); 593 } 594 if ((statbuf.st_mode & S_IFMT) != S_IFREG) { 595 Saferrno = E_BADARGS; 596 (void) fprintf(stderr, "%s not a regular file\n", command); 597 cleandirs(tag); 598 quit(); 599 } 600 } 601 else { 602 (void) fprintf(stderr, "warning - %s does not exist\n", command); 603 } 604 605 /* 606 * add the line 607 */ 608 609 fp = fopen(SACTAB, "a"); 610 if (fp == NULL) { 611 Saferrno = E_SYSERR; 612 cleandirs(tag); 613 error("Could not open _sactab"); 614 } 615 (void) fprintf(fp, "%s:%s:%s:%d:%s\t#%s\n", tag, type, 616 (flags ? pflags(flags, FALSE) : ""), count, buf, 617 (comment ? comment : "")); 618 (void) fclose(fp); 619 620 621 /* 622 * tell the SAC to read _sactab if its there (i.e. single user) 623 */ 624 625 if (sac_home()) 626 read_db(NULL); 627 return; 628 } 629 630 631 /* 632 * cleandirs - remove anything that might have been created (i.e. failed 633 * addition. Saferrno is set elsewhere; this is strictly an attempt 634 * to clean up what mess we've left, so don't check to see if the 635 * cleanup worked. 636 * 637 * args: tag - tag of port monitor whose trees should be removed 638 */ 639 640 void 641 cleandirs(tag) 642 char *tag; 643 { 644 char buf[SIZE]; /* scratch buffer */ 645 646 /* note: this removes the directory too, first zap /etc/saf/<tag> */ 647 (void) sprintf(buf, "rm -rf %s/%s", HOME, tag); 648 (void) system(buf); 649 650 /* now remove /var/saf/<tag> */ 651 (void) sprintf(buf, "%s/%s", ALTHOME, tag); 652 (void) rmdir(buf); 653 } 654 655 656 /* 657 * rem_pm - remove a port monitor 658 * 659 * args: tag - tag of port monitor to be removed 660 */ 661 662 void 663 rem_pm(tag) 664 char *tag; 665 { 666 FILE *fp; /* file pointer for _sactab */ 667 FILE *tfp; /* file pointer for temp file */ 668 int line; /* line number entry is on */ 669 char *tname; /* temp file name */ 670 char buf[SIZE]; /* scratch buffer */ 671 672 fp = fopen(SACTAB, "r"); 673 if (fp == NULL) { 674 Saferrno = E_SYSERR; 675 error("Could not open _sactab"); 676 } 677 if ((line = find_pm(fp, tag)) == 0) { 678 Saferrno = E_NOEXIST; 679 (void) sprintf(buf, "Invalid request, %s does not exist", tag); 680 error(buf); 681 } 682 tname = make_tempname("_sactab"); 683 tfp = open_temp(tname); 684 if (line != 1) { 685 if (copy_file(fp, tfp, 1, line - 1)) { 686 (void) unlink(tname); 687 Saferrno = E_SYSERR; 688 error("error accessing temp file"); 689 } 690 } 691 if (copy_file(fp, tfp, line + 1, -1)) { 692 (void) unlink(tname); 693 Saferrno = E_SYSERR; 694 error("error accessing temp file"); 695 } 696 (void) fclose(fp); 697 if (fclose(tfp) == EOF) { 698 (void) unlink(tname); 699 Saferrno = E_SYSERR; 700 error("error closing tempfile"); 701 } 702 /* note - replace only returns if successful */ 703 replace("_sactab", tname); 704 705 /* 706 * tell the SAC to read _sactab if its there (i.e. single user) 707 */ 708 709 if (sac_home()) 710 read_db(NULL); 711 return; 712 } 713 714 715 /* 716 * start_pm - start a particular port monitor 717 * 718 * args: tag - tag of port monitor to be started 719 */ 720 721 void 722 start_pm(tag) 723 char *tag; 724 { 725 struct admcmd cmd; /* command structure */ 726 register struct admcmd *ap = &cmd; /* and a pointer to it */ 727 728 ap->ac_mtype = AC_START; 729 (void) strcpy(ap->ac_tag, tag); 730 ap->ac_pid = getpid(); 731 sendcmd(ap, NULL, tag); 732 return; 733 } 734 735 736 /* 737 * kill_pm - stop a particular port monitor 738 * 739 * args: tag - tag of port monitor to be stopped 740 */ 741 742 void 743 kill_pm(tag) 744 char *tag; 745 { 746 struct admcmd cmd; /* command structure */ 747 register struct admcmd *ap = &cmd; /* and a pointer to it */ 748 749 ap->ac_mtype = AC_KILL; 750 (void) strcpy(ap->ac_tag, tag); 751 ap->ac_pid = getpid(); 752 sendcmd(ap, NULL, tag); 753 return; 754 } 755 756 757 /* 758 * enable_pm - enable a particular port monitor 759 * 760 * args: tag - tag of port monitor to be enabled 761 */ 762 763 void 764 enable_pm(tag) 765 char *tag; 766 { 767 struct admcmd cmd; /* command structure */ 768 register struct admcmd *ap = &cmd; /* and a pointer to it */ 769 770 ap->ac_mtype = AC_ENABLE; 771 (void) strcpy(ap->ac_tag, tag); 772 ap->ac_pid = getpid(); 773 sendcmd(ap, NULL, tag); 774 return; 775 } 776 777 778 /* 779 * disable_pm - disable a particular port monitor 780 * 781 * args: tag - tag of port monitor to be disabled 782 */ 783 784 void 785 disable_pm(tag) 786 char *tag; 787 { 788 struct admcmd cmd; /* command structure */ 789 register struct admcmd *ap = &cmd; /* and a pointer to it */ 790 791 ap->ac_mtype = AC_DISABLE; 792 (void) strcpy(ap->ac_tag, tag); 793 ap->ac_pid = getpid(); 794 sendcmd(ap, NULL, tag); 795 return; 796 } 797 798 799 /* 800 * read_db - tell SAC or a port monitor to read its administrative file. 801 * 802 * args: tag - tag of port monitor that should read its administrative 803 * file. If NULL, it means SAC should. 804 */ 805 806 void 807 read_db(tag) 808 char *tag; 809 { 810 struct admcmd cmd; /* command structure */ 811 register struct admcmd *ap = &cmd; /* and a pointer to it */ 812 813 ap->ac_mtype = (tag) ? AC_PMREAD : AC_SACREAD; 814 if (tag) 815 (void) strcpy(ap->ac_tag, tag); 816 ap->ac_pid = getpid(); 817 sendcmd(ap, NULL, tag); 818 return; 819 } 820 821 822 /* 823 * list_pms - request information about port monitors from SAC and output 824 * requested info 825 * 826 * args: pmtag - tag of port monitor to be listed (may be null) 827 * pmtype - type of port monitors to be listed (may be null) 828 * oflag - true if output should be easily parseable 829 */ 830 831 void 832 list_pms(pmtag, pmtype, oflag) 833 char *pmtag; 834 char *pmtype; 835 int oflag; 836 { 837 struct admcmd acmd; /* command structure */ 838 register struct admcmd *ap = &acmd; /* and a pointer to it */ 839 int nprint = 0; /* count # of PMs printed */ 840 char *p; /* scratch pointer */ 841 char *tag; /* returned tag */ 842 char *type; /* returned type */ 843 char *flags; /* returned flags */ 844 char *rsmax; /* returned restart count */ 845 char *state; /* returned state */ 846 char *cmd; /* returned command string */ 847 char *comment; /* returned comment string */ 848 849 /* 850 * if sac isn't there (single user), provide info direct from _sactab 851 * note: when this routine returns, the process exits, so there is no 852 * need to free up any memory 853 */ 854 855 p = NULL; 856 if (sac_home()) { 857 ap->ac_mtype = AC_STATUS; 858 ap->ac_tag[0] = '\0'; 859 ap->ac_pid = getpid(); 860 sendcmd(ap, &p, NULL); 861 } 862 else { 863 single_print(&p); 864 } 865 866 /* 867 * SAC sends back info in condensed form, we have to separate it out 868 * fields come in ':' separated, records are separated by newlines 869 */ 870 871 while (p && *p) { 872 tag = getfield(&p, ':'); /* PM tag */ 873 type = getfield(&p, ':'); /* PM type */ 874 flags = getfield(&p, ':'); /* flags */ 875 rsmax = getfield(&p, ':'); /* restart count */ 876 state = pstate((unchar) atoi(getfield(&p, ':'))); /* state in nice output format */ 877 cmd = getfield(&p, ':'); /* command */ 878 comment = getfield(&p, '\n'); /* comment */ 879 880 881 /* 882 * print out if no selectors specified, else check to see if 883 * a selector matched 884 */ 885 886 if ((!pmtag && !pmtype) || (pmtag && !strcmp(pmtag, tag)) || (pmtype && !strcmp(pmtype, type))) { 887 if (oflag) { 888 (void) printf("%s:%s:%s:%s:%s:%s#%s\n", tag, type, pflags(atol(flags), FALSE), 889 rsmax, state, cmd, comment); 890 } 891 else { 892 if (nprint == 0) { 893 (void) printf("PMTAG PMTYPE FLGS RCNT STATUS COMMAND\n"); 894 } 895 (void) printf("%-14s %-14s %-4s %-4s %-10s %s #%s\n", tag, type, pflags(atol(flags), TRUE), 896 rsmax, state, cmd, comment); 897 } 898 nprint++; 899 } 900 } 901 /* 902 * if we didn't find any valid ones, indicate an error (note: 1 and 903 * only 1 of the if statements should be true) 904 */ 905 if (nprint == 0) { 906 if (pmtype) 907 (void) fprintf(stderr, "Invalid request, %s does not exist\n", pmtype); 908 else if (pmtag) 909 (void) fprintf(stderr, "Invalid request, %s does not exist\n", pmtag); 910 else if (!pmtag && !pmtype) 911 (void) fprintf(stderr, "No port monitors defined\n"); 912 Saferrno = E_NOEXIST; 913 } 914 return; 915 } 916 917 918 /* 919 * getfield - retrieve and return a field from the sac "status" string (input 920 * argument is modified to point to next field as a side-effect) 921 * 922 * args: p - address of remaining portion of string 923 * sepchar - field terminator character 924 */ 925 926 char * 927 getfield(p, sepchar) 928 char **p; 929 char sepchar; 930 { 931 char *savep; /* for saving argument */ 932 933 savep = *p; 934 *p = strchr(*p, sepchar); 935 if (*p == NULL) { 936 Saferrno = E_SAFERR; 937 (void) fprintf(stderr, "Improper message from SAC\n"); 938 return(NULL); 939 } 940 **p = '\0'; 941 (*p)++; 942 return(savep); 943 } 944 945 946 /* 947 * single_print - print out _sactab if sac not at home (should only happen 948 * in single user mode 949 * 950 * args: p - address of pointer where formatted data should be 951 * placed (space allocated here) 952 */ 953 954 void 955 single_print(p) 956 char **p; 957 { 958 FILE *fp; /* file pointer for _sactab */ 959 struct stat statbuf; /* file status info */ 960 register char *tp1; /* scratch pointer */ 961 register char *tp2; /* scratch pointer */ 962 struct sactab stab; /* place to hold parsed info */ 963 register struct sactab *sp = &stab; /* and a pointer to it */ 964 char buf[SIZE]; /* scratch buffer */ 965 966 fp = fopen(SACTAB, "r"); 967 if (fp == NULL) { 968 Saferrno = E_SYSERR; 969 error("Could not open _sactab"); 970 } 971 if (fstat(fileno(fp), &statbuf) < 0) { 972 Saferrno = E_SYSERR; 973 error("could not stat _sactab"); 974 } 975 976 /* 977 * allocate space to build return string, twice file size should be more 978 * than enough (and make sure it's zero'ed out) 979 */ 980 981 tp1 = calloc(2 * statbuf.st_size, sizeof(char)); 982 if (tp1 == NULL) { 983 Saferrno = E_SYSERR; 984 error("could not allocate storage"); 985 } 986 987 /* 988 * read the file and build the string 989 */ 990 991 while (fgets(buf, SIZE, fp)) { 992 tp2 = trim(buf); 993 if (*tp2 == '\0') 994 continue; 995 parse(tp2, &stab); 996 (void) sprintf(buf, "%s:%s:%d:%d:%d:%s:%s\n", sp->sc_tag, sp->sc_type, 997 sp->sc_flags, sp->sc_rsmax, SSTATE, sp->sc_cmd, sp->sc_comment); 998 (void) strcat(tp1, buf); 999 free(sp->sc_cmd); 1000 free(sp->sc_comment); 1001 } 1002 if (!feof(fp)) { 1003 Saferrno = E_SYSERR; 1004 error("error reading _sactab"); 1005 } 1006 (void) fclose(fp); 1007 1008 /* 1009 * point at the just-built string 1010 */ 1011 1012 *p = tp1; 1013 return; 1014 } 1015 1016 1017 /* 1018 * openpipe - open up command pipe to SAC 1019 */ 1020 1021 int 1022 openpipe() 1023 { 1024 int fd; /* file descriptor associated with command pipe */ 1025 1026 fd = open(CMDPIPE, O_RDWR); 1027 if (fd < 0) { 1028 Saferrno = E_SYSERR; 1029 error(SACERR); 1030 } 1031 1032 /* 1033 * lock pipe to insure serial access, lock will disappear if process dies 1034 */ 1035 1036 if (lockf(fd, F_LOCK, 0) < 0) { 1037 Saferrno = E_SYSERR; 1038 error("unable to lock command pipe"); 1039 } 1040 return(fd); 1041 } 1042 1043 1044 /* 1045 * sendcmd - send a command to the SAC 1046 * 1047 * args: ap - pointer to command to send 1048 * info - pointer to return information from the SAC 1049 * tag - tag of port monitor to which the command applies (may 1050 * be NULL) 1051 */ 1052 1053 void 1054 sendcmd(ap, info, tag) 1055 struct admcmd *ap; 1056 char **info; 1057 char *tag; 1058 { 1059 int fd; /* file descriptor of command pipe */ 1060 1061 fd = openpipe(); 1062 if (write(fd, ap, sizeof(struct admcmd)) < 0) { 1063 Saferrno = E_SYSERR; 1064 error(SACERR); 1065 } 1066 checkresp(fd, info, tag); 1067 1068 /* 1069 * unlock the command pipe - not really necessary since we're about to close 1070 */ 1071 1072 (void) lockf(fd, F_ULOCK, 0); 1073 (void) close(fd); 1074 return; 1075 } 1076 1077 1078 /* 1079 * checkresp - check the SAC's response to our command 1080 * 1081 * args: fd - file descriptor of command pipe 1082 * info - pointer to return and info send along by SAC 1083 * tag - tag of port monitor that the command had been 1084 * for, only used for error reporting 1085 */ 1086 1087 void 1088 checkresp(fd, info, tag) 1089 int fd; 1090 char **info; 1091 char *tag; 1092 { 1093 struct admack ack; /* acknowledgment struct */ 1094 register struct admack *ak = &ack; /* and a pointer to it */ 1095 pid_t pid; /* my pid */ 1096 struct sigaction sigact; /* signal handler setup */ 1097 1098 /* 1099 * make sure this ack is meant for me, put an alarm around the read 1100 * so we don't hang out forever. 1101 */ 1102 1103 pid = getpid(); 1104 sigact.sa_flags = 0; 1105 sigact.sa_handler = catch; 1106 (void) sigemptyset(&sigact.sa_mask); 1107 (void) sigaddset(&sigact.sa_mask, SIGALRM); 1108 (void) sigaction(SIGALRM, &sigact, NULL); 1109 (void) alarm(10); 1110 do { 1111 if (read(fd, ak, sizeof(ack)) != sizeof(ack)) { 1112 Saferrno = E_SACNOTRUN; 1113 error(SACERR); 1114 } 1115 } while (pid != ak->ak_pid); 1116 (void) alarm(0); 1117 1118 /* 1119 * check out what happened 1120 */ 1121 1122 switch (ak->ak_resp) { 1123 case AK_ACK: 1124 /* everything was A-OK */ 1125 if (info && ak->ak_size) { 1126 /* there is return info and a place to put it */ 1127 if ((*info = malloc((unsigned) (ak->ak_size + 1))) == NULL) { 1128 Saferrno = E_SYSERR; 1129 error("could not allocate storage"); 1130 } 1131 if (read(fd, *info, (unsigned) ak->ak_size) != ak->ak_size) { 1132 Saferrno = E_SYSERR; 1133 error(SACERR); 1134 } 1135 /* make sure "string" is null-terminated */ 1136 (*info)[ak->ak_size] = '\0'; 1137 } 1138 return; 1139 /* something went wrong - see what */ 1140 case AK_PMRUN: 1141 Saferrno = E_PMRUN; 1142 (void) fprintf(stderr, "Port monitor, %s, is already running\n", tag); 1143 break; 1144 case AK_PMNOTRUN: 1145 Saferrno = E_PMNOTRUN; 1146 (void) fprintf(stderr, "Port monitor, %s, is not running\n", tag); 1147 break; 1148 case AK_NOPM: 1149 Saferrno = E_NOEXIST; 1150 (void) fprintf(stderr, "Invalid request, %s does not exist\n", tag); 1151 break; 1152 case AK_UNKNOWN: 1153 Saferrno = E_SAFERR; 1154 (void) fprintf(stderr, "Internal error - sent invalid command\n"); 1155 break; 1156 case AK_NOCONTACT: 1157 Saferrno = E_SAFERR; 1158 (void) fprintf(stderr, "Could not contact %s\n", tag); 1159 break; 1160 case AK_PMLOCK: 1161 Saferrno = E_SAFERR; 1162 (void) fprintf(stderr, "Could not start %s - _pid file locked\n", tag); 1163 break; 1164 case AK_RECOVER: 1165 Saferrno = E_RECOVER; 1166 (void) fprintf(stderr, "Port monitor, %s, is in recovery\n", tag); 1167 break; 1168 case AK_REQFAIL: 1169 Saferrno = E_SAFERR; 1170 (void) fprintf(stderr, "This request could not be completed - see sac log file for details\n"); 1171 break; 1172 default: 1173 Saferrno = E_SAFERR; 1174 (void) fprintf(stderr, "unknown response\n"); 1175 break; 1176 } 1177 } 1178 1179 1180 /* 1181 * catch - catcher for SIGALRM, don't need to do anything 1182 */ 1183 1184 void 1185 catch() 1186 { 1187 } 1188 1189 1190 /* 1191 * pflags - put port monitor flags into intelligible form for output 1192 * 1193 * args: flags - binary representation of flags 1194 * dflag - true if a "-" should be returned if no flags 1195 */ 1196 1197 char * 1198 pflags(flags, dflag) 1199 long flags; 1200 int dflag; 1201 { 1202 register int i; /* scratch counter */ 1203 static char buf[SIZE]; /* formatted flags */ 1204 1205 if (flags == 0) { 1206 if (dflag) 1207 return("-"); 1208 else 1209 return(""); 1210 } 1211 i = 0; 1212 if (flags & D_FLAG) { 1213 buf[i++] = 'd'; 1214 flags &= ~D_FLAG; 1215 } 1216 if (flags & X_FLAG) { 1217 buf[i++] = 'x'; 1218 flags &= ~X_FLAG; 1219 } 1220 if (flags) { 1221 (void) fprintf(stderr, "Bad information from SAC\n"); 1222 exit(1); 1223 } 1224 buf[i] = '\0'; 1225 return(buf); 1226 } 1227 1228 1229 /* 1230 * sac_home - returns true is sac has a lock on its logfile, false 1231 * otherwise (useful to avoid errors for administrative actions in 1232 * single user mode) 1233 */ 1234 1235 int 1236 sac_home() 1237 { 1238 int fd; /* fd to sac logfile */ 1239 1240 fd = open(LOGFILE, O_RDONLY); 1241 if (fd < 0) { 1242 fprintf(stderr, "warning - could not ascertain sac status\n"); 1243 return(FALSE); 1244 } 1245 if (lockf(fd, F_TEST, 0) < 0) { 1246 /* everything is ok */ 1247 (void) close(fd); 1248 return(TRUE); 1249 } 1250 else { 1251 /* no one home */ 1252 (void) close(fd); 1253 return(FALSE); 1254 } 1255 } 1256