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