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 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 23 /* All Rights Reserved */ 24 25 /* 26 * Copyright (c) 1998 by Sun Microsystems, Inc. 27 * All rights reserved. 28 */ 29 30 #pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.14 */ 31 32 #include <stdio.h> 33 #include <fcntl.h> 34 #include <ctype.h> 35 #include <signal.h> 36 #include <errno.h> 37 #include <sys/types.h> 38 #include <sys/stat.h> 39 #include <sys/stropts.h> 40 #include <sys/wait.h> 41 #include <unistd.h> 42 #include <utmpx.h> 43 #include <memory.h> 44 #include "msgs.h" 45 #include "extern.h" 46 #include <sac.h> 47 #include "misc.h" 48 #include "structs.h" 49 50 #include <security/pam_appl.h> 51 52 #define RESP 1 /* pollfail via no response to sanity poll */ 53 #define DEATH 2 /* pollfail via child death */ 54 55 /* signal whose dispositions will be changed */ 56 57 static struct sigaction Sigpoll; /* SIGPOLL */ 58 static struct sigaction Sigcld; /* SIGCLD */ 59 static struct sigaction Sigalrm; /* SIGALRM */ 60 static sigset_t Origmask; /* original signal mask */ 61 62 void usage(void); 63 void initialize(void); 64 void startpms(void); 65 void readutmpx(void); 66 int startpm(struct sactab *); 67 void cleanutx(struct sactab *); 68 void account(struct sactab *, pid_t); 69 void startit(struct sactab *); 70 char **mkargv(struct sactab *); 71 void pollpms(void); 72 void reap(int); 73 void pollfail(struct sactab *, int); 74 void readpipe(void); 75 int validstate(unchar); 76 int mk_cmd_pipe(void); 77 void startpoll(void); 78 79 80 81 /* 82 * main - scan args for sac, initialize everything, and wait for commands 83 * from sacadm via the command pipe 84 */ 85 86 main(int argc, char *argv[]) 87 { 88 int c; /* place to hold options */ 89 struct sigaction sigact; /* for signal handling */ 90 91 (void) sigprocmask(SIG_SETMASK, NULL, &Origmask); 92 if (argc == 1) 93 usage(); 94 (void) setpgrp(); 95 while ((c = getopt(argc, argv, "t:")) != -1) { 96 switch (c) { 97 case 't': 98 if (Stime != 0) 99 usage(); 100 Stime = atoi(optarg); 101 if (Stime <= 0) 102 usage(); 103 break; 104 case '?': 105 usage(); 106 } 107 } 108 if (optind < argc) 109 usage(); 110 111 initialize(); 112 sigact.sa_flags = 0; 113 sigact.sa_handler = pollpms; 114 (void) sigemptyset(&sigact.sa_mask); 115 (void) sigaddset(&sigact.sa_mask, SIGALRM); 116 (void) sigaction(SIGALRM, &sigact, &Sigalrm); 117 118 /* 119 * minimize time spent in STARTING or UNKNOWN, pollpms() sets alarm 120 */ 121 122 pollpms(); 123 for (;;) 124 readpipe(); 125 } 126 127 128 /* 129 * usage - output a usage message on the console 130 */ 131 132 void 133 usage() 134 { 135 FILE *fp; /* scratch file pointer */ 136 137 fp = fopen("/dev/console", "w"); 138 if (fp) 139 (void) fprintf(fp, "SAC: Usage: sac -t sanity_interval\n"); 140 exit(1); 141 } 142 143 144 /* 145 * initialize - initialization stuff 146 */ 147 148 149 void 150 initialize() 151 { 152 int ret; /* return code from doconfig() */ 153 struct sigaction sigact; /* for signal handling */ 154 155 openlog(); 156 log("*** SAC starting ***"); 157 #ifdef DEBUG 158 opendebug(); 159 log("Debugging turned on"); 160 #endif 161 if (chdir(HOME) < 0) 162 error(E_CHDIR, EXIT); 163 164 /* 165 * pass an invalid fd, shouldn't be doing pushes and pops in this per-system 166 * configuration script (_sysconfig) 167 */ 168 169 if ((ret = doconfig(-1, SYSCONFIG, 0)) != 0) { 170 if (ret == -1) 171 error(E_SYSCONF, EXIT); 172 else { 173 (void) sprintf(Scratch, 174 "Error in _sysconfig: line %d", ret); 175 log(Scratch); 176 error(E_BADSYSCONF, EXIT); 177 } 178 } 179 180 sigact.sa_flags = 0; 181 sigact.sa_handler = reap; 182 (void) sigemptyset(&sigact.sa_mask); 183 (void) sigaddset(&sigact.sa_mask, SIGCLD); 184 (void) sigaction(SIGCLD, &sigact, &Sigcld); 185 186 /* 187 * establish pipe for PMS to communicate with sac 188 */ 189 190 if (access("_sacpipe", 0) != 0) { 191 /* not there, create one */ 192 (void) umask(0); 193 if (mknod("_sacpipe", S_IFIFO | 0600, 0) < 0) 194 error(E_NOPIPE, EXIT); 195 } 196 Sfd = open("_sacpipe", O_RDWR); 197 if (Sfd < 0) 198 error(E_NOPIPE, EXIT); 199 200 /* 201 * establish pipe for sacadm to communicate with sac 202 */ 203 204 Cfd = mk_cmd_pipe(); 205 206 /* 207 * read in _sactab, but don't start port monitors as a by-product 208 * since we may be in recovery - start them explicitly instead 209 */ 210 211 read_table(FALSE); 212 startpoll(); 213 startpms(); 214 } 215 216 217 /* 218 * startpms - start initial set of port monitors 219 */ 220 221 222 void 223 startpms() 224 { 225 struct sactab *sp; /* working pointer */ 226 int rflag; /* recovery flag */ 227 pid_t checklock(); 228 229 /* 230 * check to see if we're really a recovering SAC (if any port monitors hold 231 * locks, assume that we're in recovery), if so, start differently 232 */ 233 234 rflag = 0; 235 for (sp = Sactab; sp; sp = sp->sc_next) { 236 if (checklock(sp)) { 237 rflag = 1; 238 sp->sc_sstate = sp->sc_pstate = UNKNOWN; 239 sp->sc_ok = 1; 240 sp->sc_exit = 0; 241 (void) sprintf(Scratch, "%s/_pmpipe", sp->sc_tag); 242 sp->sc_fd = open(Scratch, O_RDWR); 243 if (sp->sc_fd < 0) { 244 245 /* 246 * if we get into here, we're in deep trouble. PM seems to be running 247 * and we're trying to recover, but we can't talk to it. Unfortunately, 248 * there's not much that can be done other than to try and restore a 249 * sane state. By setting sp->sc_ok to 0, this will look like a poll failure 250 * and if sp->rs_rsmax > 0, PM will be restarted. 251 */ 252 253 (void) sprintf(Scratch, 254 "Could not open _pmpipe for port monitor <%s>", 255 sp->sc_tag); 256 log(Scratch); 257 (void) sendsig(sp, SIGTERM); 258 sp->sc_ok = 0; 259 } 260 } 261 } 262 if (rflag) { 263 readutmpx(); 264 log("SAC in recovery"); 265 return; 266 } 267 268 /* 269 * normal startup 270 */ 271 272 for (sp = Sactab; sp; sp = sp->sc_next) { 273 if (sp->sc_flags & X_FLAG) { 274 /* System Administator specified don't start */ 275 continue; 276 } 277 (void) startpm(sp); 278 } 279 } 280 281 282 /* 283 * readutmpx - read the utmpx file to find out the ids of running port 284 * monitors (only called during a recover start up). Note: 285 * after a sac failure, init will inherit all of the port 286 * monitors and should get the SIGCLD's if they die (and 287 * will clean up). This is mainly for stuck processes, 288 * although init would get the SIGCLD when the stuckie gets 289 * killed, it doesn't hurt to have the sac check. This is 290 * only done once. 291 * 292 */ 293 294 295 void 296 readutmpx() 297 { 298 struct sactab *sp; /* working pointer */ 299 struct sactab *savesp; /* rembered port monitor match */ 300 struct utmpx *uxp; /* working pointer */ 301 302 setutxent(); 303 while (uxp = getutxent()) { 304 /* we're only interested in login processes */ 305 if (uxp->ut_type != LOGIN_PROCESS) 306 continue; 307 if (uxp->ut_user[sizeof (uxp->ut_user) - 1] == '\0') { 308 309 /* 310 * possible port monitor and name is short enough to do a normal compare 311 */ 312 313 sp = findpm(uxp->ut_user); 314 if (sp && (sp->sc_sstate == UNKNOWN)) { 315 /* found one */ 316 (void) memcpy(sp->sc_utid, uxp->ut_id, IDLEN); 317 sp->sc_pid = uxp->ut_pid; 318 } 319 } else { 320 321 /* 322 * possible port monitor name, but it could have been truncated. If 323 * a match is found on a unique prefix, then it should be the correct 324 * entry. If an ambiguity is found, ignore the entry, init will clean 325 * up the entry if it dies. 326 */ 327 328 savesp = NULL; 329 for (sp = Sactab; sp; sp = sp->sc_next) { 330 if (strncmp(uxp->ut_user, sp->sc_tag, 331 sizeof (uxp->ut_user)) == 0) { 332 if (savesp) { 333 /* already found a match */ 334 savesp = NULL; 335 (void) sprintf(Scratch, 336 "ambiguous utmpx entry <%.8s>", 337 sp->sc_tag); 338 log(Scratch); 339 break; 340 } else { 341 savesp = sp; 342 } 343 } 344 } 345 if (savesp && (savesp->sc_sstate == UNKNOWN)) { 346 /* found it */ 347 (void) memcpy(savesp->sc_utid, uxp->ut_id, 348 IDLEN); 349 savesp->sc_pid = uxp->ut_pid; 350 } 351 } 352 } 353 endutxent(); 354 } 355 356 357 /* 358 * startpm - start a particular PM, return code: 359 * -1: _pid file locked 360 * -2: any other reason 361 * 362 * args: sp - pointer to sac's port monitor information for 363 * designated port monitor 364 */ 365 366 int 367 startpm(struct sactab *sp) 368 { 369 sigset_t cset; /* for signal handling */ 370 sigset_t tset; /* for signal handling */ 371 pid_t pid; /* pid of new port monitor */ 372 pid_t checklock(); 373 374 #ifdef DEBUG 375 debug("in startpm"); 376 #endif 377 if (checklock(sp)) { 378 (void) sprintf(Scratch, 379 "could not start <%s> - _pid file locked", sp->sc_tag); 380 log(Scratch); 381 return (-1); 382 } 383 384 (void) sprintf(Scratch, "%s/_pmpipe", sp->sc_tag); 385 if (access(Scratch, 0) != 0) { 386 /* not there, create one */ 387 (void) umask(0); 388 if (mknod(Scratch, S_IFIFO | 0600, 0) < 0) { 389 (void) sprintf(Scratch, 390 "Could not create _pmpipe for port monitor <%s>, errno is %d", 391 sp->sc_tag, errno); 392 log(Scratch); 393 return (-2); 394 } 395 } 396 sp->sc_fd = open(Scratch, O_RDWR); 397 if (sp->sc_fd < 0) { 398 (void) sprintf(Scratch, 399 "Could not open _pmpipe for port monitor <%s>, errno is %d", 400 sp->sc_tag, errno); 401 log(Scratch); 402 return (-2); 403 } 404 405 /* in case child dies too quickly */ 406 (void) sigprocmask(SIG_SETMASK, NULL, &cset); 407 tset = cset; 408 (void) sigaddset(&tset, SIGCLD); 409 (void) sigprocmask(SIG_SETMASK, &tset, NULL); 410 if ((pid = fork()) < 0) { 411 (void) sprintf(Scratch, 412 "Could not fork port monitor <%s>", sp->sc_tag); 413 log(Scratch); 414 return (-2); 415 } else if (!pid) { 416 startit(sp); 417 /* no return */ 418 } 419 420 /* 421 * clean up old utmpx if its there 422 */ 423 424 cleanutx(sp); 425 426 /* 427 * create a utmpx entry and set initial states 428 */ 429 430 account(sp, pid); 431 sp->sc_pstate = STARTING; 432 if (sp->sc_lstate == NOTRUNNING) 433 sp->sc_sstate = (sp->sc_flags & D_FLAG) ? DISABLED : ENABLED; 434 else 435 sp->sc_sstate = sp->sc_lstate; 436 sp->sc_ok = 1; 437 sp->sc_exit = 0; 438 sp->sc_pid = pid; 439 /* ok to take signals now that the table is up-to-table */ 440 (void) sigprocmask(SIG_SETMASK, &cset, NULL); 441 return (0); 442 } 443 444 445 /* 446 * cleanutx - clean out a utmpx record for a port monitor 447 * 448 * args: sp - pointer to sac's port monitor information for 449 * designated port monitor 450 */ 451 452 453 void 454 cleanutx(struct sactab *sp) 455 { 456 int i; /* scratch variable */ 457 int zerocheck; /* scratch variable */ 458 char buf[SIZE]; /* scratch buffer */ 459 pam_handle_t *pamh; /* PAM auth descriptor */ 460 struct utmpx ut; 461 struct utmpx *up; 462 int pid; 463 char user[sizeof (up->ut_user) + 1]; 464 char ttyn[sizeof (up->ut_line) + 1]; 465 char rhost[sizeof (up->ut_host) + 1]; 466 /* 467 * check to see if there is a utmpx entry to clean up (indicated by a non 468 * zero utmpx id 469 */ 470 zerocheck = 0; 471 for (i = 0; i < IDLEN; ++i) { 472 zerocheck += sp->sc_utid[i]; 473 } 474 if (zerocheck == 0) 475 return; 476 477 pid = sp->sc_pid; 478 setutxent(); 479 while (up = getutxent()) { 480 if (up->ut_pid == pid) { 481 if (up->ut_type == DEAD_PROCESS) { 482 /* 483 * Cleaned up elsewhere. 484 */ 485 break; 486 } 487 strncpy(user, up->ut_user, sizeof (up->ut_user)); 488 user[sizeof (up->ut_user)] = '\0'; 489 strncpy(ttyn, up->ut_line, sizeof (up->ut_line)); 490 ttyn[sizeof (up->ut_line)] = '\0'; 491 strncpy(rhost, up->ut_host, sizeof (up->ut_host)); 492 rhost[sizeof (up->ut_host)] = '\0'; 493 494 if ((pam_start("sac", user, NULL, &pamh)) == 495 PAM_SUCCESS) { 496 (void) pam_set_item(pamh, PAM_TTY, ttyn); 497 (void) pam_set_item(pamh, PAM_RHOST, rhost); 498 (void) pam_close_session(pamh, 0); 499 pam_end(pamh, PAM_SUCCESS); 500 } 501 502 up->ut_type = DEAD_PROCESS; 503 up->ut_exit.e_termination = WTERMSIG(sp->sc_exit); 504 up->ut_exit.e_exit = WEXITSTATUS(sp->sc_exit); 505 if (sp->sc_utid != NULL) 506 (void) memcpy(up->ut_id, sp->sc_utid, 507 sizeof (up->ut_id)); 508 (void) time(&up->ut_tv.tv_sec); 509 if (modutx(up) == NULL) { 510 /* 511 * Since modutx failed we'll 512 * write out the new entry 513 * ourselves. 514 */ 515 (void) pututxline(up); 516 updwtmpx("wtmpx", up); 517 } 518 break; 519 } 520 } 521 endutxent(); 522 } 523 524 /* 525 * account - create a utmp record for a port monitor 526 * 527 * args: pid - process id of port monitor 528 */ 529 530 531 void 532 account(struct sactab *sp, pid_t pid) 533 { 534 struct utmpx utmpx; /* prototype utmpx entry */ 535 struct utmpx *up = &utmpx; /* and a pointer to it */ 536 537 (void) memset(up, '\0', sizeof (utmpx)); 538 (void) strncpy(up->ut_user, sp->sc_tag, sizeof (up->ut_user)); 539 up->ut_pid = pid; 540 up->ut_type = LOGIN_PROCESS; 541 up->ut_id[0] = 'P'; 542 up->ut_id[1] = 'M'; 543 up->ut_id[2] = SC_WILDC; 544 up->ut_id[3] = SC_WILDC; 545 (void) time(&up->ut_xtime); 546 if (makeutx(up) == NULL) { 547 log("Could not create utmpx entry"); 548 (void) memset(sp->sc_utid, '\0', IDLEN); 549 } else { 550 (void) memcpy(sp->sc_utid, up->ut_id, IDLEN); 551 } 552 } 553 554 555 /* 556 * startit - finish starting a particular port monitor, establish environment, 557 * etc. (Note: this is the child at this point) 558 * 559 * args: sp - pointer to sac's port monitor information for 560 * designated port monitor 561 */ 562 563 564 void 565 startit(struct sactab *sp) 566 { 567 static char istate[SIZE]; /* place to put ISTATE env var. */ 568 static char pmtag[SIZE]; /* place to put PMTAG env var. */ 569 char **argvp; /* arglist for PM */ 570 int i; /* loop control variable */ 571 long ndesc; /* # of file descriptors configured */ 572 int ret; /* return value from doconfig */ 573 sigset_t cset; /* for signal handling */ 574 sigset_t tset; /* for signal handling */ 575 576 /* 577 * establish the home directory 578 */ 579 580 if (chdir(sp->sc_tag) < 0) { 581 (void) sprintf(Scratch, 582 "Cannot chdir to <%s/%s>, port monitor not started", 583 HOME, sp->sc_tag); 584 log(Scratch); 585 exit(1); 586 } 587 588 /* 589 * interpret the configuration script, pass an invalid fd, shouldn't be 590 * doing pushes and pops in this script 591 */ 592 593 (void) sigprocmask(SIG_SETMASK, NULL, &cset); 594 tset = cset; 595 (void) sigaddset(&tset, SIGCLD); 596 (void) sigprocmask(SIG_SETMASK, &tset, NULL); 597 if ((ret = doconfig(-1, "_config", 0)) != 0) { 598 if (ret == -1) { 599 (void) sprintf(Scratch, 600 "system error in _config script for <%s>", 601 sp->sc_tag); 602 log(Scratch); 603 exit(1); 604 } else { 605 (void) sprintf(Scratch, 606 "Error in _config script for <%s>: line %d", 607 sp->sc_tag, ret); 608 log(Scratch); 609 exit(1); 610 } 611 } 612 613 /* 614 * add the promised environment variables 615 */ 616 617 if (sp->sc_lstate == NOTRUNNING) 618 (void) sprintf(istate, "ISTATE=%s", 619 (sp->sc_flags & D_FLAG) ? "disabled" : "enabled"); 620 else 621 (void) sprintf(istate, "ISTATE=%s", 622 (sp->sc_lstate == DISABLED) ? "disabled" : "enabled"); 623 if (putenv(istate)) { 624 (void) sprintf(Scratch, 625 "can't expand port monitor <%s> environment", 626 sp->sc_tag); 627 log(Scratch); 628 exit(1); 629 } 630 (void) sprintf(pmtag, "PMTAG=%s", sp->sc_tag); 631 if (putenv(pmtag)) { 632 (void) sprintf(Scratch, 633 "can't expand port monitor <%s> environment", 634 sp->sc_tag); 635 log(Scratch); 636 exit(1); 637 } 638 639 /* 640 * build an argv 641 */ 642 643 argvp = mkargv(sp); 644 645 (void) sprintf(Scratch, "starting port monitor <%s>", sp->sc_tag); 646 log(Scratch); 647 ndesc = ulimit(4, 0L); 648 for (i = 0; i < ndesc; i++) 649 (void) fcntl(i, F_SETFD, 1); 650 /* restore orignal handlers and mask */ 651 (void) sigaction(SIGPOLL, &Sigpoll, NULL); 652 (void) sigaction(SIGCLD, &Sigcld, NULL); 653 (void) sigaction(SIGALRM, &Sigalrm, NULL); 654 (void) sigprocmask(SIG_SETMASK, &Origmask, NULL); 655 (void) execve(argvp[0], argvp, environ); 656 (void) sprintf(Scratch, "exec of port monitor <%s> failed", sp->sc_tag); 657 log(Scratch); 658 exit(1); 659 } 660 661 662 /* 663 * mkargv - Given a pointer to a struct sactab, construct argv 664 * for an exec system call. 665 * 666 * args: sp - pointer to sac's port monitor information for 667 * designated port montior 668 */ 669 670 671 #define NARGS 50 /* max # of args */ 672 673 static char *newargv[NARGS]; /* place for argv list */ 674 static char *delim = " \t'\""; /* delimiter list */ 675 676 char ** 677 mkargv(struct sactab *sp) 678 { 679 char **argvp = newargv; /* scratch pointer */ 680 char *p = sp->sc_cmd; /* working pointer */ 681 char delch; /* delimiter seen */ 682 char *savep; /* scratch pointer */ 683 char *tp; /* scratch pointer */ 684 685 *argvp = 0; 686 savep = p; 687 while (p && *p) { 688 if (p = strpbrk(p, delim)) { 689 switch (*p) { 690 case ' ': 691 case '\t': 692 /* "normal" cases */ 693 *p++ = '\0'; 694 *argvp++ = savep; 695 /* zap trailing white space */ 696 while (isspace(*p)) 697 p++; 698 savep = p; 699 break; 700 case '"': 701 case '\'': 702 /* found a string */ 703 delch = *p; /* remember the delimiter */ 704 savep = ++p; 705 706 /* 707 * We work the string in place, embedded instances of the string delimiter, 708 * i.e. \" must have the '\' removed. Since we'd have to do a compare to 709 * decide if a copy were needed, it's less work to just do the copy, even 710 * though it is most likely unnecessary. 711 */ 712 713 tp = p; 714 for (;;) { 715 if (*p == '\0') { 716 (void) sprintf(Scratch, 717 "invalid command line, non-terminated string for port monitor %s", 718 sp->sc_tag); 719 log(Scratch); 720 exit(1); 721 } 722 if (*p == delch) { 723 if (*(tp - 1) == '\\') { 724 /* \delim */ 725 *(tp - 1) = *p; 726 p++; 727 } else { /* end of string */ 728 *tp = 0; 729 *argvp++ = savep; 730 p++; 731 /* zap trailing white space */ 732 while (isspace(*p)) 733 p++; 734 savep = p; 735 break; 736 } 737 } else { 738 *tp++ = *p++; 739 } 740 } 741 break; 742 default: 743 log("Internal error in parse routine"); 744 exit(1); 745 } 746 } 747 else 748 *argvp++ = savep; 749 } 750 *argvp = 0; 751 return (newargv); 752 } 753 754 755 /* 756 * pollpms - send out sanity polls, if sc_sstate and sc_pstate are 757 * the same (everyone agrees on the state) or if SAC thinks PM 758 * should be stopping, send out a status message; 759 * otherwise, send out a message indicating the state the SAC 760 * thinks the PM should be entering 761 */ 762 763 void 764 pollpms() 765 { 766 struct sactab *sp; /* working pointer */ 767 struct sacmsg sacmsg; /* message to send to PM */ 768 769 #ifdef DEBUG 770 debug("alarm went off"); 771 #endif 772 for (sp = Sactab; sp; sp = sp->sc_next) { 773 if (sp->sc_pstate == NOTRUNNING || sp->sc_pstate == FAILED) { 774 /* don't bother if no one is home */ 775 continue; 776 } 777 if (sp->sc_ok == 0) { 778 /* PM has stopped responding */ 779 pollfail(sp, RESP); 780 continue; 781 } 782 783 /* 784 * note - if we're in recovery, a SC_STATUS message is sent 785 * (sc_sstate = UNKNOWN and sc_pstate = UNKNOWN) 786 */ 787 788 if (sp->sc_sstate == sp->sc_pstate) { 789 sacmsg.sc_type = SC_STATUS; 790 sacmsg.sc_size = 0; 791 } else { 792 switch (sp->sc_sstate) { 793 case ENABLED: 794 sacmsg.sc_type = SC_ENABLE; 795 sacmsg.sc_size = 0; 796 break; 797 case DISABLED: 798 sacmsg.sc_type = SC_DISABLE; 799 sacmsg.sc_size = 0; 800 break; 801 case STARTING: 802 case STOPPING: 803 case NOTRUNNING: 804 case FAILED: 805 case UNKNOWN: 806 /* 807 * if NOTRUNNING or FAILED, PM will probably 808 * not respond to poll, that's how we detect 809 * that it's gone 810 */ 811 sacmsg.sc_type = SC_STATUS; 812 sacmsg.sc_size = 0; 813 break; 814 default: 815 error(E_BADSTATE, EXIT); 816 } 817 } 818 819 /* send the message */ 820 sendpmmsg(sp, &sacmsg); 821 sp->sc_ok = 0; 822 } 823 (void) alarm(Stime); 824 } 825 826 827 /* 828 * reap - clean up dead children, equivalent to a "fast" poll failure 829 * 830 * args: signo - signal # 831 */ 832 833 void 834 reap(int signo) 835 { 836 struct sactab *sp; /* working pointer */ 837 pid_t pid; /* returned pid from wait */ 838 int status; /* returned status from wait */ 839 840 pid = wait(&status); 841 for (sp = Sactab; sp; sp = sp->sc_next) { 842 if (sp->sc_pid == pid) 843 break; 844 } 845 if (sp == NULL) { 846 /* not from a port monitor we know about */ 847 return; 848 } 849 sp->sc_exit = status; 850 /* only call pollfail for "stuck" and stopping processes */ 851 if (sp->sc_pstate != NOTRUNNING && sp->sc_pstate != FAILED) 852 pollfail(sp, DEATH); 853 } 854 855 856 /* 857 * pollfail - handle the case where a PM stops responding to a sanity poll 858 * 859 * args: sp - pointer to sac's port monitor information for 860 * designated port monitor 861 * reason - RESP or DEATH (indicates why pollfail called) 862 */ 863 864 865 void 866 pollfail(struct sactab *sp, int reason) 867 { 868 char buf[SIZE]; /* scratch buffer */ 869 sigset_t cset; /* for signal handling */ 870 sigset_t tset; /* for signal handling */ 871 872 #ifdef DEBUG 873 debug("in pollfail"); 874 #endif 875 876 /* first, remove the utmpx entry and clean up any links */ 877 878 cleanutx(sp); 879 880 if (sp->sc_pstate == STOPPING) { 881 (void) sprintf(buf, "<%s> has stopped", sp->sc_tag); 882 log(buf); 883 sp->sc_pstate = NOTRUNNING; 884 sp->sc_lstate = NOTRUNNING; 885 (void) close(sp->sc_fd); 886 } else { 887 888 /* 889 * PM in trouble - if it's still there, try to put it out of its misery 890 * We play with SIGCLD here to that after SIGKILL is sent, the catcher 891 * routine reap() is not called until we're ready (note: when a catcher 892 * is established for SIGCLD and any zombies are present, the signal is 893 * immediately received) 894 */ 895 896 (void) sigprocmask(SIG_SETMASK, NULL, &cset); 897 tset = cset; 898 (void) sigaddset(&tset, SIGCLD); 899 (void) sigprocmask(SIG_SETMASK, &tset, NULL); 900 (void) sendsig(sp, SIGKILL); 901 if (sp->sc_rscnt < sp->sc_rsmax) { 902 /* try to restart it */ 903 if (reason == RESP) 904 (void) sprintf(buf, 905 "<%s> stopped responding to sanity polls - trying to restart", 906 sp->sc_tag); 907 else 908 (void) sprintf(buf, 909 "<%s> has died - trying to restart", 910 sp->sc_tag); 911 log(buf); 912 sp->sc_rscnt++; 913 (void) close(sp->sc_fd); 914 (void) startpm(sp); 915 } else { 916 sp->sc_sstate = sp->sc_pstate = FAILED; 917 (void) close(sp->sc_fd); 918 (void) sprintf(buf, "<%s> has FAILED", sp->sc_tag); 919 log(buf); 920 } 921 } 922 (void) sigprocmask(SIG_SETMASK, &cset, NULL); 923 } 924 925 926 /* 927 * readpipe - read messages from _sacpipe 928 */ 929 930 931 void 932 readpipe() 933 { 934 struct pmmsg pmmsg; /* incoming message */ 935 struct pmmsg *pp = &pmmsg; /* and a pointer to it */ 936 struct sactab *sp; /* working pointer */ 937 int ret; /* return value from read */ 938 939 /* 940 * This routine's main purpose is to maintain the state associated with 941 * each of the known port monitors. Because it may be confusing, following 942 * is a brief discussion of what is happening. Three different views of 943 * a port monitor's state exist: sc_sstate, sc_pstate, and sc_lstate. 944 * sc_sstate is the state in which the sac has been instructed to place 945 * a port monitor. sc_lstate is essentially a shadow of this field, however, 946 * it will only take on the values ENABLED, DISABLED, and NOTRUNNING. 947 * sc_lstate is used if a port monitor dies to restart it in the state in 948 * which it was last running. sc_pstate is the last state that the port 949 * monitor reported itself in. Note that if the administrator specifies 950 * a state change, there is a window where sc_sstate and sc_pstate will 951 * be different (until the port monitor enacts and acknowledges the change). 952 * 953 * These states interact with the polling loop to determine which message 954 * should be sent to a port monitor. If the states agree, an SC_STATUS 955 * is sent. If they disagree, the appropriate message to put the port 956 * monitor in the correct state is sent (SC_ENABLE or SC_DISABLE). sc_pstate 957 * is the state that is reported back to an AC_STATUS request. Finally, 958 * when in recovery (sc_sstate and sc_pstate both = UNKNOWN), the sac will 959 * take the port monitor's reported state as the true state. This is the 960 * only instance in which a port monitor can cause sc_sstate to change. 961 */ 962 963 for (;;) { 964 if (read(Sfd, pp, sizeof (pmmsg)) < 0) { 965 if (errno != EINTR) 966 error(E_BADREAD, EXIT); 967 continue; 968 } 969 970 while (pp->pm_size) { 971 972 /* 973 * there's data after the header, unfortunately, we don't understand 974 * any of it because only class 1 (no data) messages are defined. Just 975 * flush it 976 */ 977 978 ret = read(Sfd, Scratch, 979 (pp->pm_size > SIZE) ? (unsigned) SIZE : 980 (unsigned) pp->pm_size); 981 if (ret < 0) { 982 if (errno != EINTR) 983 error(E_BADREAD, EXIT); 984 continue; 985 } 986 else 987 pp->pm_size -= ret; 988 } 989 990 sp = findpm(pp->pm_tag); 991 if (sp == NULL) { 992 log("message from unknown process"); 993 continue; 994 } 995 switch (pp->pm_type) { 996 case PM_UNKNOWN: 997 (void) sprintf(Scratch, 998 "port monitor <%s> didn't recognize message", 999 sp->sc_tag); 1000 log(Scratch); 1001 /* fall through */ 1002 case PM_STATUS: 1003 /* 1004 * paranoia check, if port monitor reports garbage 1005 * state, pretend it said UNKNOWN 1006 */ 1007 if (!validstate(pp->pm_state)) { 1008 pp->pm_state = UNKNOWN; 1009 (void) sprintf(Scratch, 1010 "port monitor <%s> reporting invalid state", 1011 sp->sc_tag); 1012 log(Scratch); 1013 } 1014 if (sp->sc_sstate == sp->sc_pstate) { 1015 /* everyone agrees on the current state */ 1016 if (sp->sc_sstate == UNKNOWN) { 1017 /* special case for recovery */ 1018 sp->sc_sstate = pp->pm_state; 1019 sp->sc_pstate = pp->pm_state; 1020 if (pp->pm_state == ENABLED || 1021 pp->pm_state == DISABLED) 1022 /* sc_lstate NOTRUNNING by default */ 1023 sp->sc_lstate = pp->pm_state; 1024 } 1025 if (pp->pm_state != sp->sc_pstate) { 1026 /* 1027 * something isn't right here, PM 1028 * changed state without orders, try 1029 * to restore to correct state 1030 */ 1031 sp->sc_pstate = pp->pm_state; 1032 } 1033 } else if (sp->sc_sstate == pp->pm_state) { 1034 /* PM changed to state requested */ 1035 (void) sprintf(Scratch, 1036 "port monitor <%s> changed state from %s to %s", 1037 sp->sc_tag, pstate(sp->sc_pstate), 1038 pstate(pp->pm_state)); 1039 log(Scratch); 1040 sp->sc_pstate = pp->pm_state; 1041 } else if (sp->sc_pstate != pp->pm_state) { 1042 /* 1043 * something isn't right here, PM isn't 1044 * in the state it was, nor is it in the 1045 * state we just tried to put it in, try 1046 * to restore to correct state if we should 1047 */ 1048 if (sp->sc_pstate != STOPPING) 1049 sp->sc_pstate = pp->pm_state; 1050 } 1051 break; 1052 default: 1053 (void) sprintf(Scratch, 1054 "port monitor <%s> sent an invalid message - ignoring it", 1055 sp->sc_tag); 1056 log(Scratch); 1057 break; 1058 } 1059 /* no matter what, PM did answer the poll */ 1060 sp->sc_ok = 1; 1061 /* Note the messages it understands */ 1062 sp->sc_maxclass = pp->pm_maxclass; 1063 } 1064 } 1065 1066 1067 /* 1068 * validstate - determine if arg s a valid return state from a port monitor 1069 * return 1 if ok, 0 otherwise 1070 * 1071 * args: state - state to be verified 1072 */ 1073 int 1074 validstate(unchar state) 1075 { 1076 switch (state) { 1077 case PM_ENABLED: 1078 case PM_DISABLED: 1079 case PM_STARTING: 1080 case PM_STOPPING: 1081 return (1); 1082 default: 1083 return (0); 1084 } 1085 } 1086 1087 1088 /* 1089 * mk_cmd_pipe - create the command pipe used by sacadm 1090 */ 1091 1092 int 1093 mk_cmd_pipe() 1094 { 1095 int fds[2]; /* pipe endpoints */ 1096 int fd; /* scratch file descriptor */ 1097 1098 /* make sure there is a file here to mount on */ 1099 (void) unlink(CMDPIPE); 1100 fd = open(CMDPIPE, O_RDWR | O_CREAT, 0600); 1101 if (fd < 0) 1102 error(E_CMDPIPE, EXIT); 1103 close(fd); 1104 if (pipe(fds) < 0) 1105 error(E_PIPE, EXIT); 1106 if (fattach(fds[0], CMDPIPE) < 0) 1107 error(E_FATTACH, EXIT); 1108 return (fds[1]); 1109 } 1110 1111 1112 /* 1113 * startpoll - enable polling on command pipe by setting up to catch SIGPOLL 1114 */ 1115 1116 1117 void 1118 startpoll() 1119 { 1120 struct sigaction sigact; /* for signal handling */ 1121 1122 if (ioctl(Cfd, I_SETSIG, S_INPUT) < 0) 1123 error(E_SETSIG, EXIT); 1124 sigact.sa_flags = 0; 1125 sigact.sa_handler = sigpoll; 1126 (void) sigemptyset(&sigact.sa_mask); 1127 (void) sigaddset(&sigact.sa_mask, SIGPOLL); 1128 (void) sigaction(SIGPOLL, &sigact, &Sigpoll); 1129 } 1130