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