xref: /illumos-gate/usr/src/cmd/saf/sac.c (revision 30699046)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
23c6eba0f3SToomas Soome /*	  All Rights Reserved	*/
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate /*
2634e48580Sdp  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
2734e48580Sdp  * Use is subject to license terms.
287c478bd9Sstevel@tonic-gate  */
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate #include <stdio.h>
3134e48580Sdp #include <stdlib.h>
327c478bd9Sstevel@tonic-gate #include <fcntl.h>
337c478bd9Sstevel@tonic-gate #include <ctype.h>
347c478bd9Sstevel@tonic-gate #include <signal.h>
3534e48580Sdp #include <strings.h>
367c478bd9Sstevel@tonic-gate #include <errno.h>
377c478bd9Sstevel@tonic-gate #include <sys/types.h>
387c478bd9Sstevel@tonic-gate #include <sys/stat.h>
397c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
407c478bd9Sstevel@tonic-gate #include <sys/wait.h>
417c478bd9Sstevel@tonic-gate #include <unistd.h>
427c478bd9Sstevel@tonic-gate #include <utmpx.h>
437c478bd9Sstevel@tonic-gate #include <memory.h>
447c478bd9Sstevel@tonic-gate #include "msgs.h"
457c478bd9Sstevel@tonic-gate #include "extern.h"
467c478bd9Sstevel@tonic-gate #include <sac.h>
477c478bd9Sstevel@tonic-gate #include "misc.h"
487c478bd9Sstevel@tonic-gate #include "structs.h"
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate #include <security/pam_appl.h>
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate #define	RESP	1		/* pollfail via no response to sanity poll */
537c478bd9Sstevel@tonic-gate #define	DEATH	2		/* pollfail via child death */
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate /* signal whose dispositions will be changed */
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate static struct sigaction	Sigpoll;	/* SIGPOLL */
587c478bd9Sstevel@tonic-gate static struct sigaction	Sigcld;		/* SIGCLD */
597c478bd9Sstevel@tonic-gate static struct sigaction	Sigalrm;	/* SIGALRM */
607c478bd9Sstevel@tonic-gate static sigset_t Origmask;		/* original signal mask */
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate void usage(void);
637c478bd9Sstevel@tonic-gate void initialize(void);
647c478bd9Sstevel@tonic-gate void startpms(void);
657c478bd9Sstevel@tonic-gate void readutmpx(void);
667c478bd9Sstevel@tonic-gate int startpm(struct sactab *);
677c478bd9Sstevel@tonic-gate void cleanutx(struct sactab *);
687c478bd9Sstevel@tonic-gate void account(struct sactab *, pid_t);
697c478bd9Sstevel@tonic-gate void startit(struct sactab *);
707c478bd9Sstevel@tonic-gate char **mkargv(struct sactab *);
71*30699046SRichard Lowe void pollpms(int);
727c478bd9Sstevel@tonic-gate void reap(int);
737c478bd9Sstevel@tonic-gate void pollfail(struct sactab *, int);
747c478bd9Sstevel@tonic-gate void readpipe(void);
75c6eba0f3SToomas Soome int validstate(uchar_t);
767c478bd9Sstevel@tonic-gate int mk_cmd_pipe(void);
777c478bd9Sstevel@tonic-gate void startpoll(void);
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate /*
827c478bd9Sstevel@tonic-gate  * main - scan args for sac, initialize everything, and wait for commands
837c478bd9Sstevel@tonic-gate  *	  from sacadm via the command pipe
847c478bd9Sstevel@tonic-gate  */
857c478bd9Sstevel@tonic-gate 
8634e48580Sdp int
main(int argc,char * argv[])877c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
887c478bd9Sstevel@tonic-gate {
897c478bd9Sstevel@tonic-gate 	int c;	/* place to hold options */
907c478bd9Sstevel@tonic-gate 	struct sigaction sigact;	/* for signal handling */
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate 	(void) sigprocmask(SIG_SETMASK, NULL, &Origmask);
937c478bd9Sstevel@tonic-gate 	if (argc == 1)
947c478bd9Sstevel@tonic-gate 		usage();
957c478bd9Sstevel@tonic-gate 	(void) setpgrp();
967c478bd9Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "t:")) != -1) {
977c478bd9Sstevel@tonic-gate 		switch (c) {
987c478bd9Sstevel@tonic-gate 		case 't':
997c478bd9Sstevel@tonic-gate 			if (Stime != 0)
1007c478bd9Sstevel@tonic-gate 				usage();
1017c478bd9Sstevel@tonic-gate 			Stime = atoi(optarg);
1027c478bd9Sstevel@tonic-gate 			if (Stime <= 0)
1037c478bd9Sstevel@tonic-gate 				usage();
1047c478bd9Sstevel@tonic-gate 			break;
1057c478bd9Sstevel@tonic-gate 		case '?':
1067c478bd9Sstevel@tonic-gate 			usage();
1077c478bd9Sstevel@tonic-gate 		}
1087c478bd9Sstevel@tonic-gate 	}
1097c478bd9Sstevel@tonic-gate 	if (optind < argc)
1107c478bd9Sstevel@tonic-gate 		usage();
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate 	initialize();
1137c478bd9Sstevel@tonic-gate 	sigact.sa_flags = 0;
1147c478bd9Sstevel@tonic-gate 	sigact.sa_handler = pollpms;
1157c478bd9Sstevel@tonic-gate 	(void) sigemptyset(&sigact.sa_mask);
1167c478bd9Sstevel@tonic-gate 	(void) sigaddset(&sigact.sa_mask, SIGALRM);
1177c478bd9Sstevel@tonic-gate 	(void) sigaction(SIGALRM, &sigact, &Sigalrm);
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate /*
1207c478bd9Sstevel@tonic-gate  * minimize time spent in STARTING or UNKNOWN, pollpms() sets alarm
1217c478bd9Sstevel@tonic-gate  */
1227c478bd9Sstevel@tonic-gate 
123*30699046SRichard Lowe 	pollpms(SIGALRM);
1247c478bd9Sstevel@tonic-gate 	for (;;)
1257c478bd9Sstevel@tonic-gate 		readpipe();
1267c478bd9Sstevel@tonic-gate }
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate /*
1307c478bd9Sstevel@tonic-gate  * usage - output a usage message on the console
1317c478bd9Sstevel@tonic-gate  */
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate void
usage()1347c478bd9Sstevel@tonic-gate usage()
1357c478bd9Sstevel@tonic-gate {
1367c478bd9Sstevel@tonic-gate 	FILE *fp;	/* scratch file pointer */
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate 	fp = fopen("/dev/console", "w");
1397c478bd9Sstevel@tonic-gate 	if (fp)
1407c478bd9Sstevel@tonic-gate 		(void) fprintf(fp, "SAC: Usage: sac -t sanity_interval\n");
1417c478bd9Sstevel@tonic-gate 	exit(1);
1427c478bd9Sstevel@tonic-gate }
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate /*
1467c478bd9Sstevel@tonic-gate  * initialize - initialization stuff
1477c478bd9Sstevel@tonic-gate  */
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate void
initialize()1517c478bd9Sstevel@tonic-gate initialize()
1527c478bd9Sstevel@tonic-gate {
1537c478bd9Sstevel@tonic-gate 	int ret;			/* return code from doconfig() */
1547c478bd9Sstevel@tonic-gate 	struct sigaction sigact;	/* for signal handling */
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate 	openlog();
1577c478bd9Sstevel@tonic-gate 	log("*** SAC starting ***");
1587c478bd9Sstevel@tonic-gate #ifdef DEBUG
1597c478bd9Sstevel@tonic-gate 	opendebug();
1607c478bd9Sstevel@tonic-gate 	log("Debugging turned on");
1617c478bd9Sstevel@tonic-gate #endif
1627c478bd9Sstevel@tonic-gate 	if (chdir(HOME) < 0)
1637c478bd9Sstevel@tonic-gate 		error(E_CHDIR, EXIT);
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate /*
1667c478bd9Sstevel@tonic-gate  * pass an invalid fd, shouldn't be doing pushes and pops in this per-system
1677c478bd9Sstevel@tonic-gate  * configuration script (_sysconfig)
1687c478bd9Sstevel@tonic-gate  */
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate 	if ((ret = doconfig(-1, SYSCONFIG, 0)) != 0) {
1717c478bd9Sstevel@tonic-gate 		if (ret == -1)
1727c478bd9Sstevel@tonic-gate 			error(E_SYSCONF, EXIT);
1737c478bd9Sstevel@tonic-gate 		else {
1747c478bd9Sstevel@tonic-gate 			(void) sprintf(Scratch,
175c6eba0f3SToomas Soome 			    "Error in _sysconfig: line %d", ret);
1767c478bd9Sstevel@tonic-gate 			log(Scratch);
1777c478bd9Sstevel@tonic-gate 			error(E_BADSYSCONF, EXIT);
1787c478bd9Sstevel@tonic-gate 		}
1797c478bd9Sstevel@tonic-gate 	}
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 	sigact.sa_flags = 0;
1827c478bd9Sstevel@tonic-gate 	sigact.sa_handler = reap;
1837c478bd9Sstevel@tonic-gate 	(void) sigemptyset(&sigact.sa_mask);
1847c478bd9Sstevel@tonic-gate 	(void) sigaddset(&sigact.sa_mask, SIGCLD);
1857c478bd9Sstevel@tonic-gate 	(void) sigaction(SIGCLD, &sigact, &Sigcld);
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate /*
1887c478bd9Sstevel@tonic-gate  * establish pipe for PMS to communicate with sac
1897c478bd9Sstevel@tonic-gate  */
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate 	if (access("_sacpipe", 0) != 0) {
1927c478bd9Sstevel@tonic-gate 		/* not there, create one */
1937c478bd9Sstevel@tonic-gate 		(void) umask(0);
1947c478bd9Sstevel@tonic-gate 		if (mknod("_sacpipe", S_IFIFO | 0600, 0) < 0)
1957c478bd9Sstevel@tonic-gate 			error(E_NOPIPE, EXIT);
1967c478bd9Sstevel@tonic-gate 	}
1977c478bd9Sstevel@tonic-gate 	Sfd = open("_sacpipe", O_RDWR);
1987c478bd9Sstevel@tonic-gate 	if (Sfd < 0)
1997c478bd9Sstevel@tonic-gate 		error(E_NOPIPE, EXIT);
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate /*
2027c478bd9Sstevel@tonic-gate  * establish pipe for sacadm to communicate with sac
2037c478bd9Sstevel@tonic-gate  */
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 	Cfd = mk_cmd_pipe();
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate /*
2087c478bd9Sstevel@tonic-gate  * read in _sactab, but don't start port monitors as a by-product
2097c478bd9Sstevel@tonic-gate  * since we may be in recovery - start them explicitly instead
2107c478bd9Sstevel@tonic-gate  */
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 	read_table(FALSE);
2137c478bd9Sstevel@tonic-gate 	startpoll();
2147c478bd9Sstevel@tonic-gate 	startpms();
2157c478bd9Sstevel@tonic-gate }
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate /*
2197c478bd9Sstevel@tonic-gate  * startpms - start initial set of port monitors
2207c478bd9Sstevel@tonic-gate  */
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate void
startpms()2247c478bd9Sstevel@tonic-gate startpms()
2257c478bd9Sstevel@tonic-gate {
2267c478bd9Sstevel@tonic-gate 	struct sactab *sp;	/* working pointer */
2277c478bd9Sstevel@tonic-gate 	int rflag;			/* recovery flag */
2287c478bd9Sstevel@tonic-gate 	pid_t checklock();
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate /*
2317c478bd9Sstevel@tonic-gate  * check to see if we're really a recovering SAC (if any port monitors hold
2327c478bd9Sstevel@tonic-gate  * locks, assume that we're in recovery), if so, start differently
2337c478bd9Sstevel@tonic-gate  */
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 	rflag = 0;
2367c478bd9Sstevel@tonic-gate 	for (sp = Sactab; sp; sp = sp->sc_next) {
2377c478bd9Sstevel@tonic-gate 		if (checklock(sp)) {
2387c478bd9Sstevel@tonic-gate 			rflag = 1;
2397c478bd9Sstevel@tonic-gate 			sp->sc_sstate = sp->sc_pstate = UNKNOWN;
2407c478bd9Sstevel@tonic-gate 			sp->sc_ok = 1;
2417c478bd9Sstevel@tonic-gate 			sp->sc_exit = 0;
2427c478bd9Sstevel@tonic-gate 			(void) sprintf(Scratch, "%s/_pmpipe", sp->sc_tag);
2437c478bd9Sstevel@tonic-gate 			sp->sc_fd = open(Scratch, O_RDWR);
2447c478bd9Sstevel@tonic-gate 			if (sp->sc_fd < 0) {
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate /*
2477c478bd9Sstevel@tonic-gate  * if we get into here, we're in deep trouble.  PM seems to be running
2487c478bd9Sstevel@tonic-gate  * and we're trying to recover, but we can't talk to it.  Unfortunately,
2497c478bd9Sstevel@tonic-gate  * there's not much that can be done other than to try and restore a
2507c478bd9Sstevel@tonic-gate  * sane state.  By setting sp->sc_ok to 0, this will look like a poll failure
2517c478bd9Sstevel@tonic-gate  * and if sp->rs_rsmax > 0, PM will be restarted.
2527c478bd9Sstevel@tonic-gate  */
2537c478bd9Sstevel@tonic-gate 
254c6eba0f3SToomas Soome 				(void) sprintf(Scratch, "Could not open "
255c6eba0f3SToomas Soome 				    "_pmpipe for port monitor <%s>",
256c6eba0f3SToomas Soome 				    sp->sc_tag);
2577c478bd9Sstevel@tonic-gate 				log(Scratch);
2587c478bd9Sstevel@tonic-gate 				(void) sendsig(sp, SIGTERM);
2597c478bd9Sstevel@tonic-gate 				sp->sc_ok = 0;
2607c478bd9Sstevel@tonic-gate 			}
2617c478bd9Sstevel@tonic-gate 		}
2627c478bd9Sstevel@tonic-gate 	}
2637c478bd9Sstevel@tonic-gate 	if (rflag) {
2647c478bd9Sstevel@tonic-gate 		readutmpx();
2657c478bd9Sstevel@tonic-gate 		log("SAC in recovery");
2667c478bd9Sstevel@tonic-gate 		return;
2677c478bd9Sstevel@tonic-gate 	}
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate /*
2707c478bd9Sstevel@tonic-gate  * normal startup
2717c478bd9Sstevel@tonic-gate  */
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate 	for (sp = Sactab; sp; sp = sp->sc_next) {
2747c478bd9Sstevel@tonic-gate 		if (sp->sc_flags & X_FLAG) {
2757c478bd9Sstevel@tonic-gate 			/* System Administator specified don't start */
2767c478bd9Sstevel@tonic-gate 			continue;
2777c478bd9Sstevel@tonic-gate 		}
2787c478bd9Sstevel@tonic-gate 		(void) startpm(sp);
2797c478bd9Sstevel@tonic-gate 	}
2807c478bd9Sstevel@tonic-gate }
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate /*
2847c478bd9Sstevel@tonic-gate  * readutmpx - read the utmpx file to find out the ids of running port
2857c478bd9Sstevel@tonic-gate  *		monitors (only called during a recover start up).  Note:
2867c478bd9Sstevel@tonic-gate  *		after a sac failure, init will inherit all of the port
2877c478bd9Sstevel@tonic-gate  *		monitors and should get the SIGCLD's if they die (and
2887c478bd9Sstevel@tonic-gate  *		will clean up).  This is mainly for stuck processes,
2897c478bd9Sstevel@tonic-gate  *		although init would get the SIGCLD when the stuckie gets
2907c478bd9Sstevel@tonic-gate  *		killed, it doesn't hurt to have the sac check.  This is
2917c478bd9Sstevel@tonic-gate  *		only done once.
2927c478bd9Sstevel@tonic-gate  *
2937c478bd9Sstevel@tonic-gate  */
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate void
readutmpx()2977c478bd9Sstevel@tonic-gate readutmpx()
2987c478bd9Sstevel@tonic-gate {
2997c478bd9Sstevel@tonic-gate 	struct sactab *sp;	/* working pointer */
3007c478bd9Sstevel@tonic-gate 	struct sactab *savesp;	/* rembered port monitor match */
3017c478bd9Sstevel@tonic-gate 	struct utmpx *uxp;	/* working pointer */
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate 	setutxent();
3047c478bd9Sstevel@tonic-gate 	while (uxp = getutxent()) {
3057c478bd9Sstevel@tonic-gate 		/* we're only interested in login processes */
3067c478bd9Sstevel@tonic-gate 		if (uxp->ut_type != LOGIN_PROCESS)
3077c478bd9Sstevel@tonic-gate 			continue;
3087c478bd9Sstevel@tonic-gate 		if (uxp->ut_user[sizeof (uxp->ut_user) - 1] == '\0') {
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate /*
3117c478bd9Sstevel@tonic-gate  * possible port monitor and name is short enough to do a normal compare
3127c478bd9Sstevel@tonic-gate  */
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate 			sp = findpm(uxp->ut_user);
3157c478bd9Sstevel@tonic-gate 			if (sp && (sp->sc_sstate == UNKNOWN)) {
3167c478bd9Sstevel@tonic-gate 				/* found one */
3177c478bd9Sstevel@tonic-gate 				(void) memcpy(sp->sc_utid, uxp->ut_id, IDLEN);
3187c478bd9Sstevel@tonic-gate 				sp->sc_pid = uxp->ut_pid;
3197c478bd9Sstevel@tonic-gate 			}
3207c478bd9Sstevel@tonic-gate 		} else {
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate /*
3237c478bd9Sstevel@tonic-gate  * possible port monitor name, but it could have been truncated.  If
3247c478bd9Sstevel@tonic-gate  * a match is found on a unique prefix, then it should be the correct
3257c478bd9Sstevel@tonic-gate  * entry.  If an ambiguity is found, ignore the entry, init will clean
3267c478bd9Sstevel@tonic-gate  * up the entry if it dies.
3277c478bd9Sstevel@tonic-gate  */
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate 			savesp = NULL;
3307c478bd9Sstevel@tonic-gate 			for (sp = Sactab; sp; sp = sp->sc_next) {
3317c478bd9Sstevel@tonic-gate 				if (strncmp(uxp->ut_user, sp->sc_tag,
3327c478bd9Sstevel@tonic-gate 				    sizeof (uxp->ut_user)) == 0) {
3337c478bd9Sstevel@tonic-gate 					if (savesp) {
3347c478bd9Sstevel@tonic-gate 						/* already found a match */
3357c478bd9Sstevel@tonic-gate 						savesp = NULL;
3367c478bd9Sstevel@tonic-gate 						(void) sprintf(Scratch,
337c6eba0f3SToomas Soome 						    "ambiguous utmpx entry "
338c6eba0f3SToomas Soome 						    "<%.8s>", sp->sc_tag);
3397c478bd9Sstevel@tonic-gate 						log(Scratch);
3407c478bd9Sstevel@tonic-gate 						break;
3417c478bd9Sstevel@tonic-gate 					} else {
3427c478bd9Sstevel@tonic-gate 						savesp = sp;
3437c478bd9Sstevel@tonic-gate 					}
3447c478bd9Sstevel@tonic-gate 				}
3457c478bd9Sstevel@tonic-gate 			}
3467c478bd9Sstevel@tonic-gate 			if (savesp && (savesp->sc_sstate == UNKNOWN)) {
3477c478bd9Sstevel@tonic-gate 				/* found it */
3487c478bd9Sstevel@tonic-gate 				(void) memcpy(savesp->sc_utid, uxp->ut_id,
349c6eba0f3SToomas Soome 				    IDLEN);
3507c478bd9Sstevel@tonic-gate 				savesp->sc_pid = uxp->ut_pid;
3517c478bd9Sstevel@tonic-gate 			}
3527c478bd9Sstevel@tonic-gate 		}
3537c478bd9Sstevel@tonic-gate 	}
3547c478bd9Sstevel@tonic-gate 	endutxent();
3557c478bd9Sstevel@tonic-gate }
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate /*
3597c478bd9Sstevel@tonic-gate  * startpm - start a particular PM, return code:
3607c478bd9Sstevel@tonic-gate  *		-1: _pid file locked
3617c478bd9Sstevel@tonic-gate  *		-2: any other reason
3627c478bd9Sstevel@tonic-gate  *
3637c478bd9Sstevel@tonic-gate  *	args:	sp - pointer to sac's port monitor information for
3647c478bd9Sstevel@tonic-gate  *		     designated port monitor
3657c478bd9Sstevel@tonic-gate  */
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate int
startpm(struct sactab * sp)3687c478bd9Sstevel@tonic-gate startpm(struct sactab *sp)
3697c478bd9Sstevel@tonic-gate {
3707c478bd9Sstevel@tonic-gate 	sigset_t cset;		/* for signal handling */
3717c478bd9Sstevel@tonic-gate 	sigset_t tset;		/* for signal handling */
3727c478bd9Sstevel@tonic-gate 	pid_t pid;		/* pid of new port monitor */
3737c478bd9Sstevel@tonic-gate 	pid_t checklock();
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate #ifdef DEBUG
3767c478bd9Sstevel@tonic-gate 	debug("in startpm");
3777c478bd9Sstevel@tonic-gate #endif
3787c478bd9Sstevel@tonic-gate 	if (checklock(sp)) {
3797c478bd9Sstevel@tonic-gate 		(void) sprintf(Scratch,
380c6eba0f3SToomas Soome 		    "could not start <%s> - _pid file locked", sp->sc_tag);
3817c478bd9Sstevel@tonic-gate 		log(Scratch);
3827c478bd9Sstevel@tonic-gate 		return (-1);
3837c478bd9Sstevel@tonic-gate 	}
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 	(void) sprintf(Scratch, "%s/_pmpipe", sp->sc_tag);
3867c478bd9Sstevel@tonic-gate 	if (access(Scratch, 0) != 0) {
3877c478bd9Sstevel@tonic-gate 		/* not there, create one */
3887c478bd9Sstevel@tonic-gate 		(void) umask(0);
3897c478bd9Sstevel@tonic-gate 		if (mknod(Scratch, S_IFIFO | 0600, 0) < 0) {
390c6eba0f3SToomas Soome 			(void) sprintf(Scratch, "Could not create _pmpipe "
391c6eba0f3SToomas Soome 			    "for port monitor <%s>, errno is %d",
392c6eba0f3SToomas Soome 			    sp->sc_tag, errno);
3937c478bd9Sstevel@tonic-gate 			log(Scratch);
3947c478bd9Sstevel@tonic-gate 			return (-2);
3957c478bd9Sstevel@tonic-gate 		}
3967c478bd9Sstevel@tonic-gate 	}
3977c478bd9Sstevel@tonic-gate 	sp->sc_fd = open(Scratch, O_RDWR);
3987c478bd9Sstevel@tonic-gate 	if (sp->sc_fd < 0) {
399c6eba0f3SToomas Soome 		(void) sprintf(Scratch, "Could not open _pmpipe for port "
400c6eba0f3SToomas Soome 		    "monitor <%s>, errno is %d", sp->sc_tag, errno);
4017c478bd9Sstevel@tonic-gate 		log(Scratch);
4027c478bd9Sstevel@tonic-gate 		return (-2);
4037c478bd9Sstevel@tonic-gate 	}
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate 	/* in case child dies too quickly */
4067c478bd9Sstevel@tonic-gate 	(void) sigprocmask(SIG_SETMASK, NULL, &cset);
4077c478bd9Sstevel@tonic-gate 	tset = cset;
4087c478bd9Sstevel@tonic-gate 	(void) sigaddset(&tset, SIGCLD);
4097c478bd9Sstevel@tonic-gate 	(void) sigprocmask(SIG_SETMASK, &tset, NULL);
4107c478bd9Sstevel@tonic-gate 	if ((pid = fork()) < 0) {
4117c478bd9Sstevel@tonic-gate 		(void) sprintf(Scratch,
412c6eba0f3SToomas Soome 		    "Could not fork port monitor <%s>", sp->sc_tag);
4137c478bd9Sstevel@tonic-gate 		log(Scratch);
4147c478bd9Sstevel@tonic-gate 		return (-2);
4157c478bd9Sstevel@tonic-gate 	} else if (!pid) {
4167c478bd9Sstevel@tonic-gate 		startit(sp);
4177c478bd9Sstevel@tonic-gate 		/* no return */
4187c478bd9Sstevel@tonic-gate 	}
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate /*
4217c478bd9Sstevel@tonic-gate  * clean up old utmpx if its there
4227c478bd9Sstevel@tonic-gate  */
4237c478bd9Sstevel@tonic-gate 
4247c478bd9Sstevel@tonic-gate 	cleanutx(sp);
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate /*
4277c478bd9Sstevel@tonic-gate  * create a utmpx entry and set initial states
4287c478bd9Sstevel@tonic-gate  */
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate 	account(sp, pid);
4317c478bd9Sstevel@tonic-gate 	sp->sc_pstate = STARTING;
4327c478bd9Sstevel@tonic-gate 	if (sp->sc_lstate == NOTRUNNING)
4337c478bd9Sstevel@tonic-gate 		sp->sc_sstate = (sp->sc_flags & D_FLAG) ? DISABLED : ENABLED;
4347c478bd9Sstevel@tonic-gate 	else
4357c478bd9Sstevel@tonic-gate 		sp->sc_sstate = sp->sc_lstate;
4367c478bd9Sstevel@tonic-gate 	sp->sc_ok = 1;
4377c478bd9Sstevel@tonic-gate 	sp->sc_exit = 0;
4387c478bd9Sstevel@tonic-gate 	sp->sc_pid = pid;
4397c478bd9Sstevel@tonic-gate 	/* ok to take signals now that the table is up-to-table */
4407c478bd9Sstevel@tonic-gate 	(void) sigprocmask(SIG_SETMASK, &cset, NULL);
4417c478bd9Sstevel@tonic-gate 	return (0);
4427c478bd9Sstevel@tonic-gate }
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate /*
4467c478bd9Sstevel@tonic-gate  * cleanutx - clean out a utmpx record for a port monitor
4477c478bd9Sstevel@tonic-gate  *
4487c478bd9Sstevel@tonic-gate  *	args:	sp - pointer to sac's port monitor information for
4497c478bd9Sstevel@tonic-gate  *		     designated port monitor
4507c478bd9Sstevel@tonic-gate  */
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate void
cleanutx(struct sactab * sp)4547c478bd9Sstevel@tonic-gate cleanutx(struct sactab *sp)
4557c478bd9Sstevel@tonic-gate {
4567c478bd9Sstevel@tonic-gate 	int i;			 /* scratch variable */
4577c478bd9Sstevel@tonic-gate 	int zerocheck;		  /* scratch variable */
4587c478bd9Sstevel@tonic-gate 	char buf[SIZE];		 /* scratch buffer */
4597c478bd9Sstevel@tonic-gate 	pam_handle_t *pamh;		/* PAM auth descriptor */
4607c478bd9Sstevel@tonic-gate 	struct utmpx ut;
4617c478bd9Sstevel@tonic-gate 	struct utmpx *up;
4627c478bd9Sstevel@tonic-gate 	int pid;
4637c478bd9Sstevel@tonic-gate 	char user[sizeof (up->ut_user) + 1];
4647c478bd9Sstevel@tonic-gate 	char ttyn[sizeof (up->ut_line) + 1];
4657c478bd9Sstevel@tonic-gate 	char rhost[sizeof (up->ut_host) + 1];
4667c478bd9Sstevel@tonic-gate /*
4677c478bd9Sstevel@tonic-gate  * check to see if there is a utmpx entry to clean up (indicated by a non
4687c478bd9Sstevel@tonic-gate  * zero utmpx id
4697c478bd9Sstevel@tonic-gate  */
4707c478bd9Sstevel@tonic-gate 	zerocheck = 0;
4717c478bd9Sstevel@tonic-gate 	for (i = 0; i < IDLEN; ++i) {
4727c478bd9Sstevel@tonic-gate 		zerocheck += sp->sc_utid[i];
4737c478bd9Sstevel@tonic-gate 	}
4747c478bd9Sstevel@tonic-gate 	if (zerocheck == 0)
4757c478bd9Sstevel@tonic-gate 		return;
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate 	pid = sp->sc_pid;
4787c478bd9Sstevel@tonic-gate 	setutxent();
4797c478bd9Sstevel@tonic-gate 	while (up = getutxent()) {
4807c478bd9Sstevel@tonic-gate 		if (up->ut_pid == pid) {
4817c478bd9Sstevel@tonic-gate 			if (up->ut_type == DEAD_PROCESS) {
4827c478bd9Sstevel@tonic-gate 				/*
4837c478bd9Sstevel@tonic-gate 				 * Cleaned up elsewhere.
4847c478bd9Sstevel@tonic-gate 				 */
4857c478bd9Sstevel@tonic-gate 				break;
4867c478bd9Sstevel@tonic-gate 			}
4877c478bd9Sstevel@tonic-gate 			strncpy(user, up->ut_user, sizeof (up->ut_user));
4887c478bd9Sstevel@tonic-gate 			user[sizeof (up->ut_user)] = '\0';
4897c478bd9Sstevel@tonic-gate 			strncpy(ttyn, up->ut_line, sizeof (up->ut_line));
4907c478bd9Sstevel@tonic-gate 			ttyn[sizeof (up->ut_line)] = '\0';
4917c478bd9Sstevel@tonic-gate 			strncpy(rhost, up->ut_host, sizeof (up->ut_host));
4927c478bd9Sstevel@tonic-gate 			rhost[sizeof (up->ut_host)] = '\0';
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate 			if ((pam_start("sac", user, NULL, &pamh)) ==
495c6eba0f3SToomas Soome 			    PAM_SUCCESS) {
4967c478bd9Sstevel@tonic-gate 				(void) pam_set_item(pamh, PAM_TTY, ttyn);
4977c478bd9Sstevel@tonic-gate 				(void) pam_set_item(pamh, PAM_RHOST, rhost);
4987c478bd9Sstevel@tonic-gate 				(void) pam_close_session(pamh, 0);
4997c478bd9Sstevel@tonic-gate 				pam_end(pamh, PAM_SUCCESS);
5007c478bd9Sstevel@tonic-gate 			}
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate 			up->ut_type = DEAD_PROCESS;
5037c478bd9Sstevel@tonic-gate 			up->ut_exit.e_termination = WTERMSIG(sp->sc_exit);
5047c478bd9Sstevel@tonic-gate 			up->ut_exit.e_exit = WEXITSTATUS(sp->sc_exit);
505c6eba0f3SToomas Soome 			(void) memcpy(up->ut_id, sp->sc_utid,
506c6eba0f3SToomas Soome 			    sizeof (up->ut_id));
5077c478bd9Sstevel@tonic-gate 			(void) time(&up->ut_tv.tv_sec);
5087c478bd9Sstevel@tonic-gate 			if (modutx(up) == NULL) {
5097c478bd9Sstevel@tonic-gate 				/*
5107c478bd9Sstevel@tonic-gate 				 * Since modutx failed we'll
5117c478bd9Sstevel@tonic-gate 				 * write out the new entry
5127c478bd9Sstevel@tonic-gate 				 * ourselves.
5137c478bd9Sstevel@tonic-gate 				 */
5147c478bd9Sstevel@tonic-gate 				(void) pututxline(up);
5157c478bd9Sstevel@tonic-gate 				updwtmpx("wtmpx", up);
5167c478bd9Sstevel@tonic-gate 			}
5177c478bd9Sstevel@tonic-gate 			break;
5187c478bd9Sstevel@tonic-gate 		}
5197c478bd9Sstevel@tonic-gate 	}
5207c478bd9Sstevel@tonic-gate 	endutxent();
5217c478bd9Sstevel@tonic-gate }
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate /*
5247c478bd9Sstevel@tonic-gate  * account - create a utmp record for a port monitor
5257c478bd9Sstevel@tonic-gate  *
5267c478bd9Sstevel@tonic-gate  *	args:	pid - process id of port monitor
5277c478bd9Sstevel@tonic-gate  */
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate 
5307c478bd9Sstevel@tonic-gate void
account(struct sactab * sp,pid_t pid)5317c478bd9Sstevel@tonic-gate account(struct sactab *sp, pid_t pid)
5327c478bd9Sstevel@tonic-gate {
5337c478bd9Sstevel@tonic-gate 	struct utmpx utmpx;			/* prototype utmpx entry */
5347c478bd9Sstevel@tonic-gate 	struct utmpx *up = &utmpx;		/* and a pointer to it */
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate 	(void) memset(up, '\0', sizeof (utmpx));
5377c478bd9Sstevel@tonic-gate 	(void) strncpy(up->ut_user, sp->sc_tag, sizeof (up->ut_user));
5387c478bd9Sstevel@tonic-gate 	up->ut_pid = pid;
5397c478bd9Sstevel@tonic-gate 	up->ut_type = LOGIN_PROCESS;
5407c478bd9Sstevel@tonic-gate 	up->ut_id[0] = 'P';
5417c478bd9Sstevel@tonic-gate 	up->ut_id[1] = 'M';
5427c478bd9Sstevel@tonic-gate 	up->ut_id[2] = SC_WILDC;
5437c478bd9Sstevel@tonic-gate 	up->ut_id[3] = SC_WILDC;
5447c478bd9Sstevel@tonic-gate 	(void) time(&up->ut_xtime);
5457c478bd9Sstevel@tonic-gate 	if (makeutx(up) == NULL) {
5467c478bd9Sstevel@tonic-gate 		log("Could not create utmpx entry");
5477c478bd9Sstevel@tonic-gate 		(void) memset(sp->sc_utid, '\0', IDLEN);
5487c478bd9Sstevel@tonic-gate 	} else {
5497c478bd9Sstevel@tonic-gate 		(void) memcpy(sp->sc_utid, up->ut_id, IDLEN);
5507c478bd9Sstevel@tonic-gate 	}
5517c478bd9Sstevel@tonic-gate }
5527c478bd9Sstevel@tonic-gate 
5537c478bd9Sstevel@tonic-gate 
5547c478bd9Sstevel@tonic-gate /*
5557c478bd9Sstevel@tonic-gate  * startit - finish starting a particular port monitor, establish environment,
5567c478bd9Sstevel@tonic-gate  *		etc. (Note: this is the child at this point)
5577c478bd9Sstevel@tonic-gate  *
5587c478bd9Sstevel@tonic-gate  *	args:	sp - pointer to sac's port monitor information for
5597c478bd9Sstevel@tonic-gate  *		     designated port monitor
5607c478bd9Sstevel@tonic-gate  */
5617c478bd9Sstevel@tonic-gate 
5627c478bd9Sstevel@tonic-gate 
5637c478bd9Sstevel@tonic-gate void
startit(struct sactab * sp)5647c478bd9Sstevel@tonic-gate startit(struct sactab *sp)
5657c478bd9Sstevel@tonic-gate {
5667c478bd9Sstevel@tonic-gate 	static char istate[SIZE];	/* place to put ISTATE env var. */
5677c478bd9Sstevel@tonic-gate 	static char pmtag[SIZE];	/* place to put PMTAG env var. */
5687c478bd9Sstevel@tonic-gate 	char **argvp;			/* arglist for PM */
5697c478bd9Sstevel@tonic-gate 	int i;				/* loop control variable */
5707c478bd9Sstevel@tonic-gate 	long ndesc;			/* # of file descriptors configured */
5717c478bd9Sstevel@tonic-gate 	int ret;			/* return value from doconfig */
5727c478bd9Sstevel@tonic-gate 	sigset_t cset;			/* for signal handling */
5737c478bd9Sstevel@tonic-gate 	sigset_t tset;			/* for signal handling */
5747c478bd9Sstevel@tonic-gate 
5757c478bd9Sstevel@tonic-gate /*
5767c478bd9Sstevel@tonic-gate  * establish the home directory
5777c478bd9Sstevel@tonic-gate  */
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate 	if (chdir(sp->sc_tag) < 0) {
5807c478bd9Sstevel@tonic-gate 		(void) sprintf(Scratch,
581c6eba0f3SToomas Soome 		    "Cannot chdir to <%s/%s>, port monitor not started",
582c6eba0f3SToomas Soome 		    HOME, sp->sc_tag);
5837c478bd9Sstevel@tonic-gate 		log(Scratch);
5847c478bd9Sstevel@tonic-gate 		exit(1);
5857c478bd9Sstevel@tonic-gate 	}
5867c478bd9Sstevel@tonic-gate 
5877c478bd9Sstevel@tonic-gate /*
5887c478bd9Sstevel@tonic-gate  * interpret the configuration script, pass an invalid fd, shouldn't be
5897c478bd9Sstevel@tonic-gate  * doing pushes and pops in this script
5907c478bd9Sstevel@tonic-gate  */
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate 	(void) sigprocmask(SIG_SETMASK, NULL, &cset);
5937c478bd9Sstevel@tonic-gate 	tset = cset;
5947c478bd9Sstevel@tonic-gate 	(void) sigaddset(&tset, SIGCLD);
5957c478bd9Sstevel@tonic-gate 	(void) sigprocmask(SIG_SETMASK, &tset, NULL);
5967c478bd9Sstevel@tonic-gate 	if ((ret = doconfig(-1, "_config", 0)) != 0) {
5977c478bd9Sstevel@tonic-gate 		if (ret == -1) {
5987c478bd9Sstevel@tonic-gate 			(void) sprintf(Scratch,
599c6eba0f3SToomas Soome 			    "system error in _config script for <%s>",
600c6eba0f3SToomas Soome 			    sp->sc_tag);
6017c478bd9Sstevel@tonic-gate 			log(Scratch);
6027c478bd9Sstevel@tonic-gate 			exit(1);
6037c478bd9Sstevel@tonic-gate 		} else {
6047c478bd9Sstevel@tonic-gate 			(void) sprintf(Scratch,
605c6eba0f3SToomas Soome 			    "Error in _config script for <%s>: line %d",
606c6eba0f3SToomas Soome 			    sp->sc_tag, ret);
6077c478bd9Sstevel@tonic-gate 			log(Scratch);
6087c478bd9Sstevel@tonic-gate 			exit(1);
6097c478bd9Sstevel@tonic-gate 		}
6107c478bd9Sstevel@tonic-gate 	}
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate /*
6137c478bd9Sstevel@tonic-gate  * add the promised environment variables
6147c478bd9Sstevel@tonic-gate  */
6157c478bd9Sstevel@tonic-gate 
6167c478bd9Sstevel@tonic-gate 	if (sp->sc_lstate == NOTRUNNING)
6177c478bd9Sstevel@tonic-gate 		(void) sprintf(istate, "ISTATE=%s",
618c6eba0f3SToomas Soome 		    (sp->sc_flags & D_FLAG) ? "disabled" : "enabled");
6197c478bd9Sstevel@tonic-gate 	else
6207c478bd9Sstevel@tonic-gate 		(void) sprintf(istate, "ISTATE=%s",
621c6eba0f3SToomas Soome 		    (sp->sc_lstate == DISABLED) ? "disabled" : "enabled");
6227c478bd9Sstevel@tonic-gate 	if (putenv(istate)) {
6237c478bd9Sstevel@tonic-gate 		(void) sprintf(Scratch,
624c6eba0f3SToomas Soome 		    "can't expand port monitor <%s> environment",
625c6eba0f3SToomas Soome 		    sp->sc_tag);
6267c478bd9Sstevel@tonic-gate 		log(Scratch);
6277c478bd9Sstevel@tonic-gate 		exit(1);
6287c478bd9Sstevel@tonic-gate 	}
6297c478bd9Sstevel@tonic-gate 	(void) sprintf(pmtag, "PMTAG=%s", sp->sc_tag);
6307c478bd9Sstevel@tonic-gate 	if (putenv(pmtag)) {
6317c478bd9Sstevel@tonic-gate 		(void) sprintf(Scratch,
632c6eba0f3SToomas Soome 		    "can't expand port monitor <%s> environment",
633c6eba0f3SToomas Soome 		    sp->sc_tag);
6347c478bd9Sstevel@tonic-gate 		log(Scratch);
6357c478bd9Sstevel@tonic-gate 		exit(1);
6367c478bd9Sstevel@tonic-gate 	}
6377c478bd9Sstevel@tonic-gate 
6387c478bd9Sstevel@tonic-gate /*
6397c478bd9Sstevel@tonic-gate  * build an argv
6407c478bd9Sstevel@tonic-gate  */
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate 	argvp = mkargv(sp);
6437c478bd9Sstevel@tonic-gate 
6447c478bd9Sstevel@tonic-gate 	(void) sprintf(Scratch, "starting port monitor <%s>", sp->sc_tag);
6457c478bd9Sstevel@tonic-gate 	log(Scratch);
6467c478bd9Sstevel@tonic-gate 	ndesc = ulimit(4, 0L);
6477c478bd9Sstevel@tonic-gate 	for (i = 0; i < ndesc; i++)
6487c478bd9Sstevel@tonic-gate 		(void) fcntl(i, F_SETFD, 1);
6497c478bd9Sstevel@tonic-gate 	/* restore orignal handlers and mask */
6507c478bd9Sstevel@tonic-gate 	(void) sigaction(SIGPOLL, &Sigpoll, NULL);
6517c478bd9Sstevel@tonic-gate 	(void) sigaction(SIGCLD, &Sigcld, NULL);
6527c478bd9Sstevel@tonic-gate 	(void) sigaction(SIGALRM, &Sigalrm, NULL);
6537c478bd9Sstevel@tonic-gate 	(void) sigprocmask(SIG_SETMASK, &Origmask, NULL);
6547c478bd9Sstevel@tonic-gate 	(void) execve(argvp[0], argvp, environ);
6557c478bd9Sstevel@tonic-gate 	(void) sprintf(Scratch, "exec of port monitor <%s> failed", sp->sc_tag);
6567c478bd9Sstevel@tonic-gate 	log(Scratch);
6577c478bd9Sstevel@tonic-gate 	exit(1);
6587c478bd9Sstevel@tonic-gate }
6597c478bd9Sstevel@tonic-gate 
6607c478bd9Sstevel@tonic-gate 
6617c478bd9Sstevel@tonic-gate /*
6627c478bd9Sstevel@tonic-gate  * mkargv - Given a pointer to a struct sactab, construct argv
6637c478bd9Sstevel@tonic-gate  *		for an exec system call.
6647c478bd9Sstevel@tonic-gate  *
6657c478bd9Sstevel@tonic-gate  *	args:	sp - pointer to sac's port monitor information for
6667c478bd9Sstevel@tonic-gate  *		     designated port montior
6677c478bd9Sstevel@tonic-gate  */
6687c478bd9Sstevel@tonic-gate 
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate #define	NARGS	50	/* max # of args */
6717c478bd9Sstevel@tonic-gate 
6727c478bd9Sstevel@tonic-gate static char *newargv[NARGS];	/* place for argv list */
6737c478bd9Sstevel@tonic-gate static char *delim = " \t'\"";	/* delimiter list */
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate char **
mkargv(struct sactab * sp)6767c478bd9Sstevel@tonic-gate mkargv(struct sactab *sp)
6777c478bd9Sstevel@tonic-gate {
6787c478bd9Sstevel@tonic-gate 	char **argvp = newargv;			/* scratch pointer */
6797c478bd9Sstevel@tonic-gate 	char *p = sp->sc_cmd;			/* working pointer */
6807c478bd9Sstevel@tonic-gate 	char delch;				/* delimiter seen */
6817c478bd9Sstevel@tonic-gate 	char *savep;				/* scratch pointer */
6827c478bd9Sstevel@tonic-gate 	char *tp;				/* scratch pointer */
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate 	*argvp = 0;
6857c478bd9Sstevel@tonic-gate 	savep = p;
6867c478bd9Sstevel@tonic-gate 	while (p && *p) {
6877c478bd9Sstevel@tonic-gate 		if (p = strpbrk(p, delim)) {
6887c478bd9Sstevel@tonic-gate 			switch (*p) {
6897c478bd9Sstevel@tonic-gate 			case ' ':
6907c478bd9Sstevel@tonic-gate 			case '\t':
6917c478bd9Sstevel@tonic-gate 				/* "normal" cases */
6927c478bd9Sstevel@tonic-gate 				*p++ = '\0';
6937c478bd9Sstevel@tonic-gate 				*argvp++ = savep;
6947c478bd9Sstevel@tonic-gate 				/* zap trailing white space */
6957c478bd9Sstevel@tonic-gate 				while (isspace(*p))
6967c478bd9Sstevel@tonic-gate 					p++;
6977c478bd9Sstevel@tonic-gate 				savep = p;
6987c478bd9Sstevel@tonic-gate 				break;
6997c478bd9Sstevel@tonic-gate 			case '"':
7007c478bd9Sstevel@tonic-gate 			case '\'':
7017c478bd9Sstevel@tonic-gate 				/* found a string */
7027c478bd9Sstevel@tonic-gate 				delch = *p; /* remember the delimiter */
7037c478bd9Sstevel@tonic-gate 				savep = ++p;
7047c478bd9Sstevel@tonic-gate 
7057c478bd9Sstevel@tonic-gate /*
7067c478bd9Sstevel@tonic-gate  * We work the string in place, embedded instances of the string delimiter,
7077c478bd9Sstevel@tonic-gate  * i.e. \" must have the '\' removed.  Since we'd have to do a compare to
7087c478bd9Sstevel@tonic-gate  * decide if a copy were needed, it's less work to just do the copy, even
7097c478bd9Sstevel@tonic-gate  * though it is most likely unnecessary.
7107c478bd9Sstevel@tonic-gate  */
7117c478bd9Sstevel@tonic-gate 
7127c478bd9Sstevel@tonic-gate 				tp = p;
7137c478bd9Sstevel@tonic-gate 				for (;;) {
7147c478bd9Sstevel@tonic-gate 					if (*p == '\0') {
7157c478bd9Sstevel@tonic-gate 						(void) sprintf(Scratch,
716c6eba0f3SToomas Soome 						    "invalid command line, "
717c6eba0f3SToomas Soome 						    "non-terminated string for "
718c6eba0f3SToomas Soome 						    "port monitor %s",
719c6eba0f3SToomas Soome 						    sp->sc_tag);
7207c478bd9Sstevel@tonic-gate 						log(Scratch);
7217c478bd9Sstevel@tonic-gate 						exit(1);
7227c478bd9Sstevel@tonic-gate 					}
7237c478bd9Sstevel@tonic-gate 					if (*p == delch) {
7247c478bd9Sstevel@tonic-gate 						if (*(tp - 1) == '\\') {
7257c478bd9Sstevel@tonic-gate 							/* \delim */
7267c478bd9Sstevel@tonic-gate 							*(tp - 1) = *p;
7277c478bd9Sstevel@tonic-gate 							p++;
7287c478bd9Sstevel@tonic-gate 						} else { /* end of string */
7297c478bd9Sstevel@tonic-gate 							*tp = 0;
7307c478bd9Sstevel@tonic-gate 							*argvp++ = savep;
7317c478bd9Sstevel@tonic-gate 							p++;
7327c478bd9Sstevel@tonic-gate 						/* zap trailing white space */
7337c478bd9Sstevel@tonic-gate 							while (isspace(*p))
7347c478bd9Sstevel@tonic-gate 								p++;
7357c478bd9Sstevel@tonic-gate 							savep = p;
7367c478bd9Sstevel@tonic-gate 							break;
7377c478bd9Sstevel@tonic-gate 						}
7387c478bd9Sstevel@tonic-gate 					} else {
7397c478bd9Sstevel@tonic-gate 						*tp++ = *p++;
7407c478bd9Sstevel@tonic-gate 					}
7417c478bd9Sstevel@tonic-gate 				}
7427c478bd9Sstevel@tonic-gate 				break;
7437c478bd9Sstevel@tonic-gate 			default:
7447c478bd9Sstevel@tonic-gate 				log("Internal error in parse routine");
7457c478bd9Sstevel@tonic-gate 				exit(1);
7467c478bd9Sstevel@tonic-gate 			}
7477c478bd9Sstevel@tonic-gate 		}
7487c478bd9Sstevel@tonic-gate 		else
7497c478bd9Sstevel@tonic-gate 			*argvp++ = savep;
7507c478bd9Sstevel@tonic-gate 	}
7517c478bd9Sstevel@tonic-gate 	*argvp = 0;
7527c478bd9Sstevel@tonic-gate 	return (newargv);
7537c478bd9Sstevel@tonic-gate }
7547c478bd9Sstevel@tonic-gate 
7557c478bd9Sstevel@tonic-gate 
7567c478bd9Sstevel@tonic-gate /*
7577c478bd9Sstevel@tonic-gate  * pollpms - send out sanity polls, if sc_sstate and sc_pstate are
7587c478bd9Sstevel@tonic-gate  *	the same (everyone agrees on the state) or if SAC thinks PM
7597c478bd9Sstevel@tonic-gate  *	should be stopping, send out a status message;
7607c478bd9Sstevel@tonic-gate  *	otherwise, send out a message indicating the state the SAC
7617c478bd9Sstevel@tonic-gate  *	thinks the PM should be entering
7627c478bd9Sstevel@tonic-gate  */
7637c478bd9Sstevel@tonic-gate 
7647c478bd9Sstevel@tonic-gate void
pollpms(int signal __unused)765*30699046SRichard Lowe pollpms(int signal __unused)
7667c478bd9Sstevel@tonic-gate {
7677c478bd9Sstevel@tonic-gate 	struct sactab *sp;	/* working pointer */
7687c478bd9Sstevel@tonic-gate 	struct sacmsg sacmsg;		/* message to send to PM */
7697c478bd9Sstevel@tonic-gate 
7707c478bd9Sstevel@tonic-gate #ifdef DEBUG
7717c478bd9Sstevel@tonic-gate 	debug("alarm went off");
7727c478bd9Sstevel@tonic-gate #endif
7737c478bd9Sstevel@tonic-gate 	for (sp = Sactab; sp; sp = sp->sc_next) {
7747c478bd9Sstevel@tonic-gate 		if (sp->sc_pstate == NOTRUNNING || sp->sc_pstate == FAILED) {
7757c478bd9Sstevel@tonic-gate 			/* don't bother if no one is home */
7767c478bd9Sstevel@tonic-gate 			continue;
7777c478bd9Sstevel@tonic-gate 		}
7787c478bd9Sstevel@tonic-gate 		if (sp->sc_ok == 0) {
7797c478bd9Sstevel@tonic-gate 			/* PM has stopped responding */
7807c478bd9Sstevel@tonic-gate 			pollfail(sp, RESP);
7817c478bd9Sstevel@tonic-gate 			continue;
7827c478bd9Sstevel@tonic-gate 		}
7837c478bd9Sstevel@tonic-gate 
7847c478bd9Sstevel@tonic-gate /*
7857c478bd9Sstevel@tonic-gate  * note - if we're in recovery, a SC_STATUS message is sent
7867c478bd9Sstevel@tonic-gate  * (sc_sstate = UNKNOWN and sc_pstate = UNKNOWN)
7877c478bd9Sstevel@tonic-gate  */
7887c478bd9Sstevel@tonic-gate 
7897c478bd9Sstevel@tonic-gate 		if (sp->sc_sstate == sp->sc_pstate) {
7907c478bd9Sstevel@tonic-gate 			sacmsg.sc_type = SC_STATUS;
7917c478bd9Sstevel@tonic-gate 			sacmsg.sc_size = 0;
7927c478bd9Sstevel@tonic-gate 		} else {
7937c478bd9Sstevel@tonic-gate 			switch (sp->sc_sstate) {
7947c478bd9Sstevel@tonic-gate 			case ENABLED:
7957c478bd9Sstevel@tonic-gate 				sacmsg.sc_type = SC_ENABLE;
7967c478bd9Sstevel@tonic-gate 				sacmsg.sc_size = 0;
7977c478bd9Sstevel@tonic-gate 				break;
7987c478bd9Sstevel@tonic-gate 			case DISABLED:
7997c478bd9Sstevel@tonic-gate 				sacmsg.sc_type = SC_DISABLE;
8007c478bd9Sstevel@tonic-gate 				sacmsg.sc_size = 0;
8017c478bd9Sstevel@tonic-gate 				break;
8027c478bd9Sstevel@tonic-gate 			case STARTING:
8037c478bd9Sstevel@tonic-gate 			case STOPPING:
8047c478bd9Sstevel@tonic-gate 			case NOTRUNNING:
8057c478bd9Sstevel@tonic-gate 			case FAILED:
8067c478bd9Sstevel@tonic-gate 			case UNKNOWN:
8077c478bd9Sstevel@tonic-gate 				/*
8087c478bd9Sstevel@tonic-gate 				 * if NOTRUNNING or FAILED, PM will probably
8097c478bd9Sstevel@tonic-gate 				 * not respond to poll, that's how we detect
8107c478bd9Sstevel@tonic-gate 				 * that it's gone
8117c478bd9Sstevel@tonic-gate 				 */
8127c478bd9Sstevel@tonic-gate 				sacmsg.sc_type = SC_STATUS;
8137c478bd9Sstevel@tonic-gate 				sacmsg.sc_size = 0;
8147c478bd9Sstevel@tonic-gate 				break;
8157c478bd9Sstevel@tonic-gate 			default:
8167c478bd9Sstevel@tonic-gate 				error(E_BADSTATE, EXIT);
8177c478bd9Sstevel@tonic-gate 			}
8187c478bd9Sstevel@tonic-gate 		}
8197c478bd9Sstevel@tonic-gate 
8207c478bd9Sstevel@tonic-gate 		/* send the message */
8217c478bd9Sstevel@tonic-gate 		sendpmmsg(sp, &sacmsg);
8227c478bd9Sstevel@tonic-gate 		sp->sc_ok = 0;
8237c478bd9Sstevel@tonic-gate 	}
8247c478bd9Sstevel@tonic-gate 	(void) alarm(Stime);
8257c478bd9Sstevel@tonic-gate }
8267c478bd9Sstevel@tonic-gate 
8277c478bd9Sstevel@tonic-gate 
8287c478bd9Sstevel@tonic-gate /*
8297c478bd9Sstevel@tonic-gate  * reap - clean up dead children, equivalent to a "fast" poll failure
8307c478bd9Sstevel@tonic-gate  *
8317c478bd9Sstevel@tonic-gate  *	args:	signo - signal #
8327c478bd9Sstevel@tonic-gate  */
8337c478bd9Sstevel@tonic-gate 
8347c478bd9Sstevel@tonic-gate void
reap(int signo)8357c478bd9Sstevel@tonic-gate reap(int signo)
8367c478bd9Sstevel@tonic-gate {
8377c478bd9Sstevel@tonic-gate 	struct sactab *sp;		/* working pointer */
8387c478bd9Sstevel@tonic-gate 	pid_t pid;			/* returned pid from wait */
8397c478bd9Sstevel@tonic-gate 	int status;			/* returned status from wait */
8407c478bd9Sstevel@tonic-gate 
8417c478bd9Sstevel@tonic-gate 	pid = wait(&status);
8427c478bd9Sstevel@tonic-gate 	for (sp = Sactab; sp; sp = sp->sc_next) {
8437c478bd9Sstevel@tonic-gate 		if (sp->sc_pid == pid)
8447c478bd9Sstevel@tonic-gate 			break;
8457c478bd9Sstevel@tonic-gate 	}
8467c478bd9Sstevel@tonic-gate 	if (sp == NULL) {
8477c478bd9Sstevel@tonic-gate 		/* not from a port monitor we know about */
8487c478bd9Sstevel@tonic-gate 		return;
8497c478bd9Sstevel@tonic-gate 	}
8507c478bd9Sstevel@tonic-gate 	sp->sc_exit = status;
8517c478bd9Sstevel@tonic-gate 	/* only call pollfail for "stuck" and stopping processes */
8527c478bd9Sstevel@tonic-gate 	if (sp->sc_pstate != NOTRUNNING && sp->sc_pstate != FAILED)
8537c478bd9Sstevel@tonic-gate 		pollfail(sp, DEATH);
8547c478bd9Sstevel@tonic-gate }
8557c478bd9Sstevel@tonic-gate 
8567c478bd9Sstevel@tonic-gate 
8577c478bd9Sstevel@tonic-gate /*
8587c478bd9Sstevel@tonic-gate  * pollfail - handle the case where a PM stops responding to a sanity poll
8597c478bd9Sstevel@tonic-gate  *
8607c478bd9Sstevel@tonic-gate  *	args:	sp - pointer to sac's port monitor information for
8617c478bd9Sstevel@tonic-gate  *		     designated port monitor
8627c478bd9Sstevel@tonic-gate  *		reason - RESP or DEATH (indicates why pollfail called)
8637c478bd9Sstevel@tonic-gate  */
8647c478bd9Sstevel@tonic-gate 
8657c478bd9Sstevel@tonic-gate 
8667c478bd9Sstevel@tonic-gate void
pollfail(struct sactab * sp,int reason)8677c478bd9Sstevel@tonic-gate pollfail(struct sactab *sp, int reason)
8687c478bd9Sstevel@tonic-gate {
8697c478bd9Sstevel@tonic-gate 	char buf[SIZE];			/* scratch buffer */
8707c478bd9Sstevel@tonic-gate 	sigset_t cset;			/* for signal handling */
8717c478bd9Sstevel@tonic-gate 	sigset_t tset;			/* for signal handling */
8727c478bd9Sstevel@tonic-gate 
8737c478bd9Sstevel@tonic-gate #ifdef DEBUG
8747c478bd9Sstevel@tonic-gate 	debug("in pollfail");
8757c478bd9Sstevel@tonic-gate #endif
8767c478bd9Sstevel@tonic-gate 
8777c478bd9Sstevel@tonic-gate /* first, remove the utmpx entry and clean up any links */
8787c478bd9Sstevel@tonic-gate 
8797c478bd9Sstevel@tonic-gate 	cleanutx(sp);
8807c478bd9Sstevel@tonic-gate 
8817c478bd9Sstevel@tonic-gate 	if (sp->sc_pstate == STOPPING) {
8827c478bd9Sstevel@tonic-gate 		(void) sprintf(buf, "<%s> has stopped", sp->sc_tag);
8837c478bd9Sstevel@tonic-gate 		log(buf);
8847c478bd9Sstevel@tonic-gate 		sp->sc_pstate = NOTRUNNING;
8857c478bd9Sstevel@tonic-gate 		sp->sc_lstate = NOTRUNNING;
8867c478bd9Sstevel@tonic-gate 		(void) close(sp->sc_fd);
8877c478bd9Sstevel@tonic-gate 	} else {
8887c478bd9Sstevel@tonic-gate 
8897c478bd9Sstevel@tonic-gate /*
8907c478bd9Sstevel@tonic-gate  * PM in trouble - if it's still there, try to put it out of its misery
8917c478bd9Sstevel@tonic-gate  * We play with SIGCLD here to that after SIGKILL is sent, the catcher
8927c478bd9Sstevel@tonic-gate  * routine reap() is not called until we're ready (note: when a catcher
8937c478bd9Sstevel@tonic-gate  * is established for SIGCLD and any zombies are present, the signal is
8947c478bd9Sstevel@tonic-gate  * immediately received)
8957c478bd9Sstevel@tonic-gate  */
8967c478bd9Sstevel@tonic-gate 
8977c478bd9Sstevel@tonic-gate 		(void) sigprocmask(SIG_SETMASK, NULL, &cset);
8987c478bd9Sstevel@tonic-gate 		tset = cset;
8997c478bd9Sstevel@tonic-gate 		(void) sigaddset(&tset, SIGCLD);
9007c478bd9Sstevel@tonic-gate 		(void) sigprocmask(SIG_SETMASK, &tset, NULL);
9017c478bd9Sstevel@tonic-gate 		(void) sendsig(sp, SIGKILL);
9027c478bd9Sstevel@tonic-gate 		if (sp->sc_rscnt < sp->sc_rsmax) {
9037c478bd9Sstevel@tonic-gate 			/* try to restart it */
9047c478bd9Sstevel@tonic-gate 			if (reason == RESP)
905c6eba0f3SToomas Soome 				(void) sprintf(buf, "<%s> stopped responding "
906c6eba0f3SToomas Soome 				    "to sanity polls - trying to restart",
907c6eba0f3SToomas Soome 				    sp->sc_tag);
9087c478bd9Sstevel@tonic-gate 			else
9097c478bd9Sstevel@tonic-gate 				(void) sprintf(buf,
910c6eba0f3SToomas Soome 				    "<%s> has died - trying to restart",
911c6eba0f3SToomas Soome 				    sp->sc_tag);
9127c478bd9Sstevel@tonic-gate 			log(buf);
9137c478bd9Sstevel@tonic-gate 			sp->sc_rscnt++;
9147c478bd9Sstevel@tonic-gate 			(void) close(sp->sc_fd);
9157c478bd9Sstevel@tonic-gate 			(void) startpm(sp);
9167c478bd9Sstevel@tonic-gate 		} else {
9177c478bd9Sstevel@tonic-gate 			sp->sc_sstate = sp->sc_pstate = FAILED;
9187c478bd9Sstevel@tonic-gate 			(void) close(sp->sc_fd);
9197c478bd9Sstevel@tonic-gate 			(void) sprintf(buf, "<%s> has FAILED", sp->sc_tag);
9207c478bd9Sstevel@tonic-gate 			log(buf);
9217c478bd9Sstevel@tonic-gate 		}
9227c478bd9Sstevel@tonic-gate 	}
9237c478bd9Sstevel@tonic-gate 	(void) sigprocmask(SIG_SETMASK, &cset, NULL);
9247c478bd9Sstevel@tonic-gate }
9257c478bd9Sstevel@tonic-gate 
9267c478bd9Sstevel@tonic-gate 
9277c478bd9Sstevel@tonic-gate /*
9287c478bd9Sstevel@tonic-gate  * readpipe - read messages from _sacpipe
9297c478bd9Sstevel@tonic-gate  */
9307c478bd9Sstevel@tonic-gate 
9317c478bd9Sstevel@tonic-gate 
9327c478bd9Sstevel@tonic-gate void
readpipe()9337c478bd9Sstevel@tonic-gate readpipe()
9347c478bd9Sstevel@tonic-gate {
9357c478bd9Sstevel@tonic-gate 	struct pmmsg pmmsg;			/* incoming message */
9367c478bd9Sstevel@tonic-gate 	struct pmmsg *pp = &pmmsg;		/* and a pointer to it */
9377c478bd9Sstevel@tonic-gate 	struct sactab *sp;			/* working pointer */
9387c478bd9Sstevel@tonic-gate 	int ret;				/* return value from read */
9397c478bd9Sstevel@tonic-gate 
9407c478bd9Sstevel@tonic-gate /*
9417c478bd9Sstevel@tonic-gate  * This routine's main purpose is to maintain the state associated with
9427c478bd9Sstevel@tonic-gate  * each of the known port monitors.  Because it may be confusing, following
9437c478bd9Sstevel@tonic-gate  * is a brief discussion of what is happening.  Three different views of
9447c478bd9Sstevel@tonic-gate  * a port monitor's state exist: sc_sstate, sc_pstate, and sc_lstate.
9457c478bd9Sstevel@tonic-gate  * sc_sstate is the state in which the sac has been instructed to place
9467c478bd9Sstevel@tonic-gate  * a port monitor.  sc_lstate is essentially a shadow of this field, however,
9477c478bd9Sstevel@tonic-gate  * it will only take on the values ENABLED, DISABLED, and NOTRUNNING.
9487c478bd9Sstevel@tonic-gate  * sc_lstate is used if a port monitor dies to restart it in the state in
9497c478bd9Sstevel@tonic-gate  * which it was last running.  sc_pstate is the last state that the port
9507c478bd9Sstevel@tonic-gate  * monitor reported itself in.  Note that if the administrator specifies
9517c478bd9Sstevel@tonic-gate  * a state change, there is a window where sc_sstate and sc_pstate will
9527c478bd9Sstevel@tonic-gate  * be different (until the port monitor enacts and acknowledges the change).
9537c478bd9Sstevel@tonic-gate  *
9547c478bd9Sstevel@tonic-gate  * These states interact with the polling loop to determine which message
9557c478bd9Sstevel@tonic-gate  * should be sent to a port monitor.  If the states agree, an SC_STATUS
9567c478bd9Sstevel@tonic-gate  * is sent.  If they disagree, the appropriate message to put the port
9577c478bd9Sstevel@tonic-gate  * monitor in the correct state is sent (SC_ENABLE or SC_DISABLE).  sc_pstate
9587c478bd9Sstevel@tonic-gate  * is the state that is reported back to an AC_STATUS request.  Finally,
9597c478bd9Sstevel@tonic-gate  * when in recovery (sc_sstate and sc_pstate both = UNKNOWN), the sac will
9607c478bd9Sstevel@tonic-gate  * take the port monitor's reported state as the true state.  This is the
9617c478bd9Sstevel@tonic-gate  * only instance in which a port monitor can cause sc_sstate to change.
9627c478bd9Sstevel@tonic-gate  */
9637c478bd9Sstevel@tonic-gate 
9647c478bd9Sstevel@tonic-gate 	for (;;) {
9657c478bd9Sstevel@tonic-gate 		if (read(Sfd, pp, sizeof (pmmsg)) < 0) {
9667c478bd9Sstevel@tonic-gate 			if (errno != EINTR)
9677c478bd9Sstevel@tonic-gate 				error(E_BADREAD, EXIT);
9687c478bd9Sstevel@tonic-gate 			continue;
9697c478bd9Sstevel@tonic-gate 		}
9707c478bd9Sstevel@tonic-gate 
9717c478bd9Sstevel@tonic-gate 		while (pp->pm_size) {
9727c478bd9Sstevel@tonic-gate 
9737c478bd9Sstevel@tonic-gate /*
9747c478bd9Sstevel@tonic-gate  * there's data after the header, unfortunately, we don't understand
9757c478bd9Sstevel@tonic-gate  * any of it because only class 1 (no data) messages are defined.  Just
9767c478bd9Sstevel@tonic-gate  * flush it
9777c478bd9Sstevel@tonic-gate  */
9787c478bd9Sstevel@tonic-gate 
979c6eba0f3SToomas Soome 			ret = read(Sfd, Scratch, (pp->pm_size > SIZE) ?
980c6eba0f3SToomas Soome 			    (unsigned)SIZE : (unsigned)pp->pm_size);
9817c478bd9Sstevel@tonic-gate 			if (ret < 0) {
9827c478bd9Sstevel@tonic-gate 				if (errno != EINTR)
9837c478bd9Sstevel@tonic-gate 					error(E_BADREAD, EXIT);
9847c478bd9Sstevel@tonic-gate 				continue;
9857c478bd9Sstevel@tonic-gate 			}
9867c478bd9Sstevel@tonic-gate 			else
9877c478bd9Sstevel@tonic-gate 				pp->pm_size -= ret;
9887c478bd9Sstevel@tonic-gate 		}
9897c478bd9Sstevel@tonic-gate 
9907c478bd9Sstevel@tonic-gate 		sp = findpm(pp->pm_tag);
9917c478bd9Sstevel@tonic-gate 		if (sp == NULL) {
9927c478bd9Sstevel@tonic-gate 			log("message from unknown process");
9937c478bd9Sstevel@tonic-gate 			continue;
9947c478bd9Sstevel@tonic-gate 		}
9957c478bd9Sstevel@tonic-gate 		switch (pp->pm_type) {
9967c478bd9Sstevel@tonic-gate 		case PM_UNKNOWN:
9977c478bd9Sstevel@tonic-gate 			(void) sprintf(Scratch,
998c6eba0f3SToomas Soome 			    "port monitor <%s> didn't recognize message",
999c6eba0f3SToomas Soome 			    sp->sc_tag);
10007c478bd9Sstevel@tonic-gate 			log(Scratch);
10017c478bd9Sstevel@tonic-gate 			/* fall through */
10027c478bd9Sstevel@tonic-gate 		case PM_STATUS:
10037c478bd9Sstevel@tonic-gate 			/*
10047c478bd9Sstevel@tonic-gate 			 * paranoia check, if port monitor reports garbage
10057c478bd9Sstevel@tonic-gate 			 * state, pretend it said UNKNOWN
10067c478bd9Sstevel@tonic-gate 			 */
10077c478bd9Sstevel@tonic-gate 			if (!validstate(pp->pm_state)) {
10087c478bd9Sstevel@tonic-gate 				pp->pm_state = UNKNOWN;
1009c6eba0f3SToomas Soome 				(void) sprintf(Scratch, "port monitor <%s> "
1010c6eba0f3SToomas Soome 				    "reporting invalid state", sp->sc_tag);
10117c478bd9Sstevel@tonic-gate 				log(Scratch);
10127c478bd9Sstevel@tonic-gate 			}
10137c478bd9Sstevel@tonic-gate 			if (sp->sc_sstate == sp->sc_pstate) {
10147c478bd9Sstevel@tonic-gate 				/* everyone agrees on the current state */
10157c478bd9Sstevel@tonic-gate 				if (sp->sc_sstate == UNKNOWN) {
10167c478bd9Sstevel@tonic-gate 					/* special case for recovery */
10177c478bd9Sstevel@tonic-gate 					sp->sc_sstate = pp->pm_state;
10187c478bd9Sstevel@tonic-gate 					sp->sc_pstate = pp->pm_state;
10197c478bd9Sstevel@tonic-gate 					if (pp->pm_state == ENABLED ||
1020c6eba0f3SToomas Soome 					    pp->pm_state == DISABLED)
10217c478bd9Sstevel@tonic-gate 					/* sc_lstate NOTRUNNING by default */
10227c478bd9Sstevel@tonic-gate 						sp->sc_lstate = pp->pm_state;
10237c478bd9Sstevel@tonic-gate 				}
10247c478bd9Sstevel@tonic-gate 				if (pp->pm_state != sp->sc_pstate) {
10257c478bd9Sstevel@tonic-gate 					/*
10267c478bd9Sstevel@tonic-gate 					 * something isn't right here, PM
10277c478bd9Sstevel@tonic-gate 					 * changed state without orders, try
10287c478bd9Sstevel@tonic-gate 					 * to restore to correct state
10297c478bd9Sstevel@tonic-gate 					 */
10307c478bd9Sstevel@tonic-gate 					sp->sc_pstate = pp->pm_state;
10317c478bd9Sstevel@tonic-gate 				}
10327c478bd9Sstevel@tonic-gate 			} else if (sp->sc_sstate == pp->pm_state) {
10337c478bd9Sstevel@tonic-gate 				/* PM changed to state requested */
1034c6eba0f3SToomas Soome 				(void) sprintf(Scratch, "port monitor <%s> "
1035c6eba0f3SToomas Soome 				    "changed state from %s to %s",
1036c6eba0f3SToomas Soome 				    sp->sc_tag, pstate(sp->sc_pstate),
1037c6eba0f3SToomas Soome 				    pstate(pp->pm_state));
10387c478bd9Sstevel@tonic-gate 				log(Scratch);
10397c478bd9Sstevel@tonic-gate 				sp->sc_pstate = pp->pm_state;
10407c478bd9Sstevel@tonic-gate 			} else if (sp->sc_pstate != pp->pm_state) {
10417c478bd9Sstevel@tonic-gate 				/*
10427c478bd9Sstevel@tonic-gate 				 * something isn't right here, PM isn't
10437c478bd9Sstevel@tonic-gate 				 * in the state it was, nor is it in the
10447c478bd9Sstevel@tonic-gate 				 * state we just tried to put it in, try
10457c478bd9Sstevel@tonic-gate 				 * to restore to correct state if we should
10467c478bd9Sstevel@tonic-gate 				 */
10477c478bd9Sstevel@tonic-gate 				if (sp->sc_pstate != STOPPING)
10487c478bd9Sstevel@tonic-gate 					sp->sc_pstate = pp->pm_state;
10497c478bd9Sstevel@tonic-gate 			}
10507c478bd9Sstevel@tonic-gate 			break;
10517c478bd9Sstevel@tonic-gate 		default:
1052c6eba0f3SToomas Soome 			(void) sprintf(Scratch, "port monitor <%s> sent an "
1053c6eba0f3SToomas Soome 			    "invalid message - ignoring it", sp->sc_tag);
10547c478bd9Sstevel@tonic-gate 			log(Scratch);
10557c478bd9Sstevel@tonic-gate 			break;
10567c478bd9Sstevel@tonic-gate 		}
10577c478bd9Sstevel@tonic-gate 		/* no matter what, PM did answer the poll */
10587c478bd9Sstevel@tonic-gate 		sp->sc_ok = 1;
10597c478bd9Sstevel@tonic-gate 		/* Note the messages it understands */
10607c478bd9Sstevel@tonic-gate 		sp->sc_maxclass = pp->pm_maxclass;
10617c478bd9Sstevel@tonic-gate 	}
10627c478bd9Sstevel@tonic-gate }
10637c478bd9Sstevel@tonic-gate 
10647c478bd9Sstevel@tonic-gate 
10657c478bd9Sstevel@tonic-gate /*
10667c478bd9Sstevel@tonic-gate  * validstate - determine if arg s a valid return state from a port monitor
10677c478bd9Sstevel@tonic-gate  *	return 1 if ok, 0 otherwise
10687c478bd9Sstevel@tonic-gate  *
10697c478bd9Sstevel@tonic-gate  *	args:	state - state to be verified
10707c478bd9Sstevel@tonic-gate  */
10717c478bd9Sstevel@tonic-gate int
validstate(uchar_t state)1072c6eba0f3SToomas Soome validstate(uchar_t state)
10737c478bd9Sstevel@tonic-gate {
10747c478bd9Sstevel@tonic-gate 	switch (state) {
10757c478bd9Sstevel@tonic-gate 	case PM_ENABLED:
10767c478bd9Sstevel@tonic-gate 	case PM_DISABLED:
10777c478bd9Sstevel@tonic-gate 	case PM_STARTING:
10787c478bd9Sstevel@tonic-gate 	case PM_STOPPING:
10797c478bd9Sstevel@tonic-gate 		return (1);
10807c478bd9Sstevel@tonic-gate 	default:
10817c478bd9Sstevel@tonic-gate 		return (0);
10827c478bd9Sstevel@tonic-gate 	}
10837c478bd9Sstevel@tonic-gate }
10847c478bd9Sstevel@tonic-gate 
10857c478bd9Sstevel@tonic-gate 
10867c478bd9Sstevel@tonic-gate /*
10877c478bd9Sstevel@tonic-gate  * mk_cmd_pipe - create the command pipe used by sacadm
10887c478bd9Sstevel@tonic-gate  */
10897c478bd9Sstevel@tonic-gate 
10907c478bd9Sstevel@tonic-gate int
mk_cmd_pipe()10917c478bd9Sstevel@tonic-gate mk_cmd_pipe()
10927c478bd9Sstevel@tonic-gate {
10937c478bd9Sstevel@tonic-gate 	int fds[2];			/* pipe endpoints */
10947c478bd9Sstevel@tonic-gate 	int fd;				/* scratch file descriptor */
10957c478bd9Sstevel@tonic-gate 
10967c478bd9Sstevel@tonic-gate 	/* make sure there is a file here to mount on */
10977c478bd9Sstevel@tonic-gate 	(void) unlink(CMDPIPE);
10987c478bd9Sstevel@tonic-gate 	fd = open(CMDPIPE, O_RDWR | O_CREAT, 0600);
10997c478bd9Sstevel@tonic-gate 	if (fd < 0)
11007c478bd9Sstevel@tonic-gate 		error(E_CMDPIPE, EXIT);
11017c478bd9Sstevel@tonic-gate 	close(fd);
11027c478bd9Sstevel@tonic-gate 	if (pipe(fds) < 0)
11037c478bd9Sstevel@tonic-gate 		error(E_PIPE, EXIT);
11047c478bd9Sstevel@tonic-gate 	if (fattach(fds[0], CMDPIPE) < 0)
11057c478bd9Sstevel@tonic-gate 		error(E_FATTACH, EXIT);
11067c478bd9Sstevel@tonic-gate 	return (fds[1]);
11077c478bd9Sstevel@tonic-gate }
11087c478bd9Sstevel@tonic-gate 
11097c478bd9Sstevel@tonic-gate 
11107c478bd9Sstevel@tonic-gate /*
11117c478bd9Sstevel@tonic-gate  * startpoll - enable polling on command pipe by setting up to catch SIGPOLL
11127c478bd9Sstevel@tonic-gate  */
11137c478bd9Sstevel@tonic-gate 
11147c478bd9Sstevel@tonic-gate 
11157c478bd9Sstevel@tonic-gate void
startpoll()11167c478bd9Sstevel@tonic-gate startpoll()
11177c478bd9Sstevel@tonic-gate {
11187c478bd9Sstevel@tonic-gate 	struct sigaction sigact;	/* for signal handling */
11197c478bd9Sstevel@tonic-gate 
11207c478bd9Sstevel@tonic-gate 	if (ioctl(Cfd, I_SETSIG, S_INPUT) < 0)
11217c478bd9Sstevel@tonic-gate 		error(E_SETSIG, EXIT);
11227c478bd9Sstevel@tonic-gate 	sigact.sa_flags = 0;
11237c478bd9Sstevel@tonic-gate 	sigact.sa_handler = sigpoll;
11247c478bd9Sstevel@tonic-gate 	(void) sigemptyset(&sigact.sa_mask);
11257c478bd9Sstevel@tonic-gate 	(void) sigaddset(&sigact.sa_mask, SIGPOLL);
11267c478bd9Sstevel@tonic-gate 	(void) sigaction(SIGPOLL, &sigact, &Sigpoll);
11277c478bd9Sstevel@tonic-gate }
1128