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