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