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