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