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
main(int argc,char * argv[])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
usage()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
initialize()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
startpms()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
readutmpx()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
startpm(struct sactab * sp)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
cleanutx(struct sactab * sp)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
account(struct sactab * sp,pid_t pid)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
startit(struct sactab * sp)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 **
mkargv(struct sactab * sp)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
pollpms(int signal __unused)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
reap(int signo)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
pollfail(struct sactab * sp,int reason)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
readpipe()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
validstate(uchar_t state)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
mk_cmd_pipe()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
startpoll()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