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