xref: /illumos-gate/usr/src/cmd/init/init.c (revision 7c478bd9)
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 /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28*7c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
29*7c478bd9Sstevel@tonic-gate 
30*7c478bd9Sstevel@tonic-gate /*
31*7c478bd9Sstevel@tonic-gate  * University Copyright- Copyright (c) 1982, 1986, 1988
32*7c478bd9Sstevel@tonic-gate  * The Regents of the University of California
33*7c478bd9Sstevel@tonic-gate  * All Rights Reserved
34*7c478bd9Sstevel@tonic-gate  *
35*7c478bd9Sstevel@tonic-gate  * University Acknowledgment- Portions of this document are derived from
36*7c478bd9Sstevel@tonic-gate  * software developed by the University of California, Berkeley, and its
37*7c478bd9Sstevel@tonic-gate  * contributors.
38*7c478bd9Sstevel@tonic-gate  */
39*7c478bd9Sstevel@tonic-gate 
40*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
41*7c478bd9Sstevel@tonic-gate 
42*7c478bd9Sstevel@tonic-gate /*
43*7c478bd9Sstevel@tonic-gate  * init(1M) is the general process spawning program.  Its primary job is to
44*7c478bd9Sstevel@tonic-gate  * start and restart svc.startd for smf(5).  For backwards-compatibility it also
45*7c478bd9Sstevel@tonic-gate  * spawns and respawns processes according to /etc/inittab and the current
46*7c478bd9Sstevel@tonic-gate  * run-level.  It reads /etc/default/inittab for general configuration.
47*7c478bd9Sstevel@tonic-gate  *
48*7c478bd9Sstevel@tonic-gate  * To change run-levels the system administrator runs init from the command
49*7c478bd9Sstevel@tonic-gate  * line with a level name.  init signals svc.startd via libscf and directs the
50*7c478bd9Sstevel@tonic-gate  * zone's init (pid 1 in the global zone) what to do by sending it a signal;
51*7c478bd9Sstevel@tonic-gate  * these signal numbers are commonly refered to in the code as 'states'.  Valid
52*7c478bd9Sstevel@tonic-gate  * run-levels are [sS0123456].  Additionally, init can be given directives
53*7c478bd9Sstevel@tonic-gate  * [qQabc], which indicate actions to be taken pertaining to /etc/inittab.
54*7c478bd9Sstevel@tonic-gate  *
55*7c478bd9Sstevel@tonic-gate  * When init processes inittab entries, it finds processes that are to be
56*7c478bd9Sstevel@tonic-gate  * spawned at various run-levels.  inittab contains the set of the levels for
57*7c478bd9Sstevel@tonic-gate  * which each inittab entry is valid.
58*7c478bd9Sstevel@tonic-gate  *
59*7c478bd9Sstevel@tonic-gate  * State File and Restartability
60*7c478bd9Sstevel@tonic-gate  *   Premature exit by init(1M) is handled as a special case by the kernel:
61*7c478bd9Sstevel@tonic-gate  *   init(1M) will be immediately re-executed, retaining its original PID.  (PID
62*7c478bd9Sstevel@tonic-gate  *   1 in the global zone.)  To track the processes it has previously spawned,
63*7c478bd9Sstevel@tonic-gate  *   as well as other mutable state, init(1M) regularly updates a state file
64*7c478bd9Sstevel@tonic-gate  *   such that its subsequent invocations have knowledge of its various
65*7c478bd9Sstevel@tonic-gate  *   dependent processes and duties.
66*7c478bd9Sstevel@tonic-gate  *
67*7c478bd9Sstevel@tonic-gate  * Process Contracts
68*7c478bd9Sstevel@tonic-gate  *   We start svc.startd(1M) in a contract and transfer inherited contracts when
69*7c478bd9Sstevel@tonic-gate  *   restarting it.  Everything else is started using the legacy contract
70*7c478bd9Sstevel@tonic-gate  *   template, and the created contracts are abandoned when they become empty.
71*7c478bd9Sstevel@tonic-gate  *
72*7c478bd9Sstevel@tonic-gate  * utmpx Entry Handling
73*7c478bd9Sstevel@tonic-gate  *   Because init(1M) no longer governs the startup process, its knowledge of
74*7c478bd9Sstevel@tonic-gate  *   when utmpx becomes writable is indirect.  However, spawned processes
75*7c478bd9Sstevel@tonic-gate  *   expect to be constructed with valid utmpx entries.  As a result, attempts
76*7c478bd9Sstevel@tonic-gate  *   to write normal entries will be retried until successful.
77*7c478bd9Sstevel@tonic-gate  *
78*7c478bd9Sstevel@tonic-gate  * Maintenance Mode
79*7c478bd9Sstevel@tonic-gate  *   In certain failure scenarios, init(1M) will enter a maintenance mode, in
80*7c478bd9Sstevel@tonic-gate  *   which it invokes sulogin(1M) to allow the operator an opportunity to
81*7c478bd9Sstevel@tonic-gate  *   repair the system.  Normally, this operation is performed as a
82*7c478bd9Sstevel@tonic-gate  *   fork(2)-exec(2)-waitpid(3C) sequence with the parent waiting for repair or
83*7c478bd9Sstevel@tonic-gate  *   diagnosis to be completed.  In the cases that fork(2) requests themselves
84*7c478bd9Sstevel@tonic-gate  *   fail, init(1M) will directly execute sulogin(1M), and allow the kernel to
85*7c478bd9Sstevel@tonic-gate  *   restart init(1M) on exit from the operator session.
86*7c478bd9Sstevel@tonic-gate  *
87*7c478bd9Sstevel@tonic-gate  *   One scenario where init(1M) enters its maintenance mode is when
88*7c478bd9Sstevel@tonic-gate  *   svc.startd(1M) begins to fail rapidly, defined as when the average time
89*7c478bd9Sstevel@tonic-gate  *   between recent failures drops below a given threshold.
90*7c478bd9Sstevel@tonic-gate  */
91*7c478bd9Sstevel@tonic-gate 
92*7c478bd9Sstevel@tonic-gate #include <sys/contract/process.h>
93*7c478bd9Sstevel@tonic-gate #include <sys/ctfs.h>
94*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
95*7c478bd9Sstevel@tonic-gate #include <sys/statvfs.h>
96*7c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
97*7c478bd9Sstevel@tonic-gate #include <sys/systeminfo.h>
98*7c478bd9Sstevel@tonic-gate #include <sys/time.h>
99*7c478bd9Sstevel@tonic-gate #include <sys/termios.h>
100*7c478bd9Sstevel@tonic-gate #include <sys/tty.h>
101*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
102*7c478bd9Sstevel@tonic-gate #include <sys/utsname.h>
103*7c478bd9Sstevel@tonic-gate 
104*7c478bd9Sstevel@tonic-gate #include <bsm/adt_event.h>
105*7c478bd9Sstevel@tonic-gate #include <bsm/libbsm.h>
106*7c478bd9Sstevel@tonic-gate #include <security/pam_appl.h>
107*7c478bd9Sstevel@tonic-gate 
108*7c478bd9Sstevel@tonic-gate #include <assert.h>
109*7c478bd9Sstevel@tonic-gate #include <ctype.h>
110*7c478bd9Sstevel@tonic-gate #include <dirent.h>
111*7c478bd9Sstevel@tonic-gate #include <errno.h>
112*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
113*7c478bd9Sstevel@tonic-gate #include <libcontract.h>
114*7c478bd9Sstevel@tonic-gate #include <libcontract_priv.h>
115*7c478bd9Sstevel@tonic-gate #include <libintl.h>
116*7c478bd9Sstevel@tonic-gate #include <libscf.h>
117*7c478bd9Sstevel@tonic-gate #include <libscf_priv.h>
118*7c478bd9Sstevel@tonic-gate #include <poll.h>
119*7c478bd9Sstevel@tonic-gate #include <procfs.h>
120*7c478bd9Sstevel@tonic-gate #include <signal.h>
121*7c478bd9Sstevel@tonic-gate #include <stdarg.h>
122*7c478bd9Sstevel@tonic-gate #include <stdio.h>
123*7c478bd9Sstevel@tonic-gate #include <stdio_ext.h>
124*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
125*7c478bd9Sstevel@tonic-gate #include <string.h>
126*7c478bd9Sstevel@tonic-gate #include <strings.h>
127*7c478bd9Sstevel@tonic-gate #include <syslog.h>
128*7c478bd9Sstevel@tonic-gate #include <time.h>
129*7c478bd9Sstevel@tonic-gate #include <ulimit.h>
130*7c478bd9Sstevel@tonic-gate #include <unistd.h>
131*7c478bd9Sstevel@tonic-gate #include <utmpx.h>
132*7c478bd9Sstevel@tonic-gate #include <wait.h>
133*7c478bd9Sstevel@tonic-gate #include <zone.h>
134*7c478bd9Sstevel@tonic-gate #include <ucontext.h>
135*7c478bd9Sstevel@tonic-gate 
136*7c478bd9Sstevel@tonic-gate #undef	sleep
137*7c478bd9Sstevel@tonic-gate 
138*7c478bd9Sstevel@tonic-gate #define	fioctl(p, sptr, cmd)	ioctl(fileno(p), sptr, cmd)
139*7c478bd9Sstevel@tonic-gate #define	min(a, b)		(((a) < (b)) ? (a) : (b))
140*7c478bd9Sstevel@tonic-gate 
141*7c478bd9Sstevel@tonic-gate #define	TRUE	1
142*7c478bd9Sstevel@tonic-gate #define	FALSE	0
143*7c478bd9Sstevel@tonic-gate #define	FAILURE	-1
144*7c478bd9Sstevel@tonic-gate 
145*7c478bd9Sstevel@tonic-gate #define	UT_LINE_SZ	32	/* Size of a utmpx ut_line field */
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate /*
148*7c478bd9Sstevel@tonic-gate  * SLEEPTIME	The number of seconds "init" sleeps between wakeups if
149*7c478bd9Sstevel@tonic-gate  *		nothing else requires this "init" wakeup.
150*7c478bd9Sstevel@tonic-gate  */
151*7c478bd9Sstevel@tonic-gate #define	SLEEPTIME	(5 * 60)
152*7c478bd9Sstevel@tonic-gate 
153*7c478bd9Sstevel@tonic-gate /*
154*7c478bd9Sstevel@tonic-gate  * MAXCMDL	The maximum length of a command string in inittab.
155*7c478bd9Sstevel@tonic-gate  */
156*7c478bd9Sstevel@tonic-gate #define	MAXCMDL	512
157*7c478bd9Sstevel@tonic-gate 
158*7c478bd9Sstevel@tonic-gate /*
159*7c478bd9Sstevel@tonic-gate  * EXEC		The length of the prefix string added to all comamnds
160*7c478bd9Sstevel@tonic-gate  *		found in inittab.
161*7c478bd9Sstevel@tonic-gate  */
162*7c478bd9Sstevel@tonic-gate #define	EXEC	(sizeof ("exec ") - 1)
163*7c478bd9Sstevel@tonic-gate 
164*7c478bd9Sstevel@tonic-gate /*
165*7c478bd9Sstevel@tonic-gate  * TWARN	The amount of time between warning signal, SIGTERM,
166*7c478bd9Sstevel@tonic-gate  *		and the fatal kill signal, SIGKILL.
167*7c478bd9Sstevel@tonic-gate  */
168*7c478bd9Sstevel@tonic-gate #define	TWARN	5
169*7c478bd9Sstevel@tonic-gate 
170*7c478bd9Sstevel@tonic-gate #define	id_eq(x, y)	((x[0] == y[0] && x[1] == y[1] && x[2] == y[2] &&\
171*7c478bd9Sstevel@tonic-gate 			x[3] == y[3]) ? TRUE : FALSE)
172*7c478bd9Sstevel@tonic-gate 
173*7c478bd9Sstevel@tonic-gate /*
174*7c478bd9Sstevel@tonic-gate  * The kernel's default umask is 022 these days; since some processes inherit
175*7c478bd9Sstevel@tonic-gate  * their umask from init, init will set it from CMASK in /etc/default/init.
176*7c478bd9Sstevel@tonic-gate  * init gets the default umask from the kernel, it sets it to 022 whenever
177*7c478bd9Sstevel@tonic-gate  * it wants to create a file and reverts to CMASK afterwards.
178*7c478bd9Sstevel@tonic-gate  */
179*7c478bd9Sstevel@tonic-gate 
180*7c478bd9Sstevel@tonic-gate static int cmask;
181*7c478bd9Sstevel@tonic-gate 
182*7c478bd9Sstevel@tonic-gate /*
183*7c478bd9Sstevel@tonic-gate  * The following definitions, concluding with the 'lvls' array, provide a
184*7c478bd9Sstevel@tonic-gate  * common mapping between level-name (like 'S'), signal number (state),
185*7c478bd9Sstevel@tonic-gate  * run-level mask, and specific properties associated with a run-level.
186*7c478bd9Sstevel@tonic-gate  * This array should be accessed using the routines lvlname_to_state(),
187*7c478bd9Sstevel@tonic-gate  * lvlname_to_mask(), state_to_mask(), and state_to_flags().
188*7c478bd9Sstevel@tonic-gate  */
189*7c478bd9Sstevel@tonic-gate 
190*7c478bd9Sstevel@tonic-gate /*
191*7c478bd9Sstevel@tonic-gate  * Correspondence of signals to init actions.
192*7c478bd9Sstevel@tonic-gate  */
193*7c478bd9Sstevel@tonic-gate #define	LVLQ		SIGHUP
194*7c478bd9Sstevel@tonic-gate #define	LVL0		SIGINT
195*7c478bd9Sstevel@tonic-gate #define	LVL1		SIGQUIT
196*7c478bd9Sstevel@tonic-gate #define	LVL2		SIGILL
197*7c478bd9Sstevel@tonic-gate #define	LVL3		SIGTRAP
198*7c478bd9Sstevel@tonic-gate #define	LVL4		SIGIOT
199*7c478bd9Sstevel@tonic-gate #define	LVL5		SIGEMT
200*7c478bd9Sstevel@tonic-gate #define	LVL6		SIGFPE
201*7c478bd9Sstevel@tonic-gate #define	SINGLE_USER	SIGBUS
202*7c478bd9Sstevel@tonic-gate #define	LVLa		SIGSEGV
203*7c478bd9Sstevel@tonic-gate #define	LVLb		SIGSYS
204*7c478bd9Sstevel@tonic-gate #define	LVLc		SIGPIPE
205*7c478bd9Sstevel@tonic-gate 
206*7c478bd9Sstevel@tonic-gate /*
207*7c478bd9Sstevel@tonic-gate  * Bit Mask for each level.  Used to determine legal levels.
208*7c478bd9Sstevel@tonic-gate  */
209*7c478bd9Sstevel@tonic-gate #define	MASK0	0x0001
210*7c478bd9Sstevel@tonic-gate #define	MASK1	0x0002
211*7c478bd9Sstevel@tonic-gate #define	MASK2	0x0004
212*7c478bd9Sstevel@tonic-gate #define	MASK3	0x0008
213*7c478bd9Sstevel@tonic-gate #define	MASK4	0x0010
214*7c478bd9Sstevel@tonic-gate #define	MASK5	0x0020
215*7c478bd9Sstevel@tonic-gate #define	MASK6	0x0040
216*7c478bd9Sstevel@tonic-gate #define	MASKSU	0x0080
217*7c478bd9Sstevel@tonic-gate #define	MASKa	0x0100
218*7c478bd9Sstevel@tonic-gate #define	MASKb	0x0200
219*7c478bd9Sstevel@tonic-gate #define	MASKc	0x0400
220*7c478bd9Sstevel@tonic-gate 
221*7c478bd9Sstevel@tonic-gate #define	MASK_NUMERIC (MASK0 | MASK1 | MASK2 | MASK3 | MASK4 | MASK5 | MASK6)
222*7c478bd9Sstevel@tonic-gate #define	MASK_abc (MASKa | MASKb | MASKc)
223*7c478bd9Sstevel@tonic-gate 
224*7c478bd9Sstevel@tonic-gate /*
225*7c478bd9Sstevel@tonic-gate  * Flags to indicate properties of various states.
226*7c478bd9Sstevel@tonic-gate  */
227*7c478bd9Sstevel@tonic-gate #define	LSEL_RUNLEVEL	0x0001	/* runlevels you can transition to */
228*7c478bd9Sstevel@tonic-gate #define	LSEL_NOAUDIT	0x0002	/* levels with auditing disabled */
229*7c478bd9Sstevel@tonic-gate 
230*7c478bd9Sstevel@tonic-gate typedef struct lvl {
231*7c478bd9Sstevel@tonic-gate 	int	lvl_state;
232*7c478bd9Sstevel@tonic-gate 	int	lvl_mask;
233*7c478bd9Sstevel@tonic-gate 	char	lvl_name;
234*7c478bd9Sstevel@tonic-gate 	int	lvl_flags;
235*7c478bd9Sstevel@tonic-gate } lvl_t;
236*7c478bd9Sstevel@tonic-gate 
237*7c478bd9Sstevel@tonic-gate static lvl_t lvls[] = {
238*7c478bd9Sstevel@tonic-gate 	{ LVLQ,		0,	'Q', 0					},
239*7c478bd9Sstevel@tonic-gate 	{ LVLQ,		0,	'q', 0					},
240*7c478bd9Sstevel@tonic-gate 	{ LVL0,		MASK0,	'0', LSEL_RUNLEVEL | LSEL_NOAUDIT	},
241*7c478bd9Sstevel@tonic-gate 	{ LVL1, 	MASK1,	'1', LSEL_RUNLEVEL | LSEL_NOAUDIT	},
242*7c478bd9Sstevel@tonic-gate 	{ LVL2, 	MASK2,	'2', LSEL_RUNLEVEL			},
243*7c478bd9Sstevel@tonic-gate 	{ LVL3, 	MASK3,	'3', LSEL_RUNLEVEL			},
244*7c478bd9Sstevel@tonic-gate 	{ LVL4, 	MASK4,	'4', LSEL_RUNLEVEL			},
245*7c478bd9Sstevel@tonic-gate 	{ LVL5, 	MASK5,	'5', LSEL_RUNLEVEL | LSEL_NOAUDIT	},
246*7c478bd9Sstevel@tonic-gate 	{ LVL6, 	MASK6, 	'6', LSEL_RUNLEVEL | LSEL_NOAUDIT	},
247*7c478bd9Sstevel@tonic-gate 	{ SINGLE_USER, 	MASKSU, 'S', LSEL_RUNLEVEL | LSEL_NOAUDIT	},
248*7c478bd9Sstevel@tonic-gate 	{ SINGLE_USER, 	MASKSU, 's', LSEL_RUNLEVEL | LSEL_NOAUDIT	},
249*7c478bd9Sstevel@tonic-gate 	{ LVLa,		MASKa,	'a', 0					},
250*7c478bd9Sstevel@tonic-gate 	{ LVLb,		MASKb,	'b', 0					},
251*7c478bd9Sstevel@tonic-gate 	{ LVLc,		MASKc,	'c', 0					}
252*7c478bd9Sstevel@tonic-gate };
253*7c478bd9Sstevel@tonic-gate 
254*7c478bd9Sstevel@tonic-gate #define	LVL_NELEMS (sizeof (lvls) / sizeof (lvl_t))
255*7c478bd9Sstevel@tonic-gate 
256*7c478bd9Sstevel@tonic-gate /*
257*7c478bd9Sstevel@tonic-gate  * Legal action field values.
258*7c478bd9Sstevel@tonic-gate  */
259*7c478bd9Sstevel@tonic-gate #define	OFF		0	/* Kill process if on, else ignore */
260*7c478bd9Sstevel@tonic-gate #define	RESPAWN		1	/* Continuously restart process when it dies */
261*7c478bd9Sstevel@tonic-gate #define	ONDEMAND	RESPAWN	/* Respawn for a, b, c type processes */
262*7c478bd9Sstevel@tonic-gate #define	ONCE		2	/* Start process, do not respawn when dead */
263*7c478bd9Sstevel@tonic-gate #define	WAIT		3	/* Perform once and wait to complete */
264*7c478bd9Sstevel@tonic-gate #define	BOOT		4	/* Start at boot time only */
265*7c478bd9Sstevel@tonic-gate #define	BOOTWAIT	5	/* Start at boot time and wait to complete */
266*7c478bd9Sstevel@tonic-gate #define	POWERFAIL	6	/* Start on powerfail */
267*7c478bd9Sstevel@tonic-gate #define	POWERWAIT	7	/* Start and wait for complete on powerfail */
268*7c478bd9Sstevel@tonic-gate #define	INITDEFAULT	8	/* Default level "init" should start at */
269*7c478bd9Sstevel@tonic-gate #define	SYSINIT		9	/* Actions performed before init speaks */
270*7c478bd9Sstevel@tonic-gate 
271*7c478bd9Sstevel@tonic-gate #define	M_OFF		0001
272*7c478bd9Sstevel@tonic-gate #define	M_RESPAWN	0002
273*7c478bd9Sstevel@tonic-gate #define	M_ONDEMAND	M_RESPAWN
274*7c478bd9Sstevel@tonic-gate #define	M_ONCE		0004
275*7c478bd9Sstevel@tonic-gate #define	M_WAIT		0010
276*7c478bd9Sstevel@tonic-gate #define	M_BOOT		0020
277*7c478bd9Sstevel@tonic-gate #define	M_BOOTWAIT	0040
278*7c478bd9Sstevel@tonic-gate #define	M_PF		0100
279*7c478bd9Sstevel@tonic-gate #define	M_PWAIT		0200
280*7c478bd9Sstevel@tonic-gate #define	M_INITDEFAULT	0400
281*7c478bd9Sstevel@tonic-gate #define	M_SYSINIT	01000
282*7c478bd9Sstevel@tonic-gate 
283*7c478bd9Sstevel@tonic-gate /* States for the inittab parser in getcmd(). */
284*7c478bd9Sstevel@tonic-gate #define	ID	1
285*7c478bd9Sstevel@tonic-gate #define	LEVELS	2
286*7c478bd9Sstevel@tonic-gate #define	ACTION	3
287*7c478bd9Sstevel@tonic-gate #define	COMMAND	4
288*7c478bd9Sstevel@tonic-gate #define	COMMENT	5
289*7c478bd9Sstevel@tonic-gate 
290*7c478bd9Sstevel@tonic-gate /*
291*7c478bd9Sstevel@tonic-gate  * Init can be in any of three main states, "normal" mode where it is
292*7c478bd9Sstevel@tonic-gate  * processing entries for the lines file in a normal fashion, "boot" mode,
293*7c478bd9Sstevel@tonic-gate  * where it is only interested in the boot actions, and "powerfail" mode,
294*7c478bd9Sstevel@tonic-gate  * where it is only interested in powerfail related actions. The following
295*7c478bd9Sstevel@tonic-gate  * masks declare the legal actions for each mode.
296*7c478bd9Sstevel@tonic-gate  */
297*7c478bd9Sstevel@tonic-gate #define	NORMAL_MODES	(M_OFF | M_RESPAWN | M_ONCE | M_WAIT)
298*7c478bd9Sstevel@tonic-gate #define	BOOT_MODES	(M_BOOT | M_BOOTWAIT)
299*7c478bd9Sstevel@tonic-gate #define	PF_MODES	(M_PF | M_PWAIT)
300*7c478bd9Sstevel@tonic-gate 
301*7c478bd9Sstevel@tonic-gate struct PROC_TABLE {
302*7c478bd9Sstevel@tonic-gate 	char	p_id[4];	/* Four letter unique id of process */
303*7c478bd9Sstevel@tonic-gate 	pid_t	p_pid;		/* Process id */
304*7c478bd9Sstevel@tonic-gate 	short	p_count;	/* How many respawns of this command in */
305*7c478bd9Sstevel@tonic-gate 				/*   the current series */
306*7c478bd9Sstevel@tonic-gate 	long	p_time;		/* Start time for a series of respawns */
307*7c478bd9Sstevel@tonic-gate 	short	p_flags;
308*7c478bd9Sstevel@tonic-gate 	short	p_exit;		/* Exit status of a process which died */
309*7c478bd9Sstevel@tonic-gate };
310*7c478bd9Sstevel@tonic-gate 
311*7c478bd9Sstevel@tonic-gate /*
312*7c478bd9Sstevel@tonic-gate  * Flags for the "p_flags" word of a PROC_TABLE entry:
313*7c478bd9Sstevel@tonic-gate  *
314*7c478bd9Sstevel@tonic-gate  *	OCCUPIED	This slot in init's proc table is in use.
315*7c478bd9Sstevel@tonic-gate  *
316*7c478bd9Sstevel@tonic-gate  *	LIVING		Process is alive.
317*7c478bd9Sstevel@tonic-gate  *
318*7c478bd9Sstevel@tonic-gate  *	NOCLEANUP	efork() is not allowed to cleanup this entry even
319*7c478bd9Sstevel@tonic-gate  *			if process is dead.
320*7c478bd9Sstevel@tonic-gate  *
321*7c478bd9Sstevel@tonic-gate  *	NAMED		This process has a name, i.e. came from inittab.
322*7c478bd9Sstevel@tonic-gate  *
323*7c478bd9Sstevel@tonic-gate  *	DEMANDREQUEST	Process started by a "telinit [abc]" command.  Processes
324*7c478bd9Sstevel@tonic-gate  *			formed this way are respawnable and immune to level
325*7c478bd9Sstevel@tonic-gate  *			changes as long as their entry exists in inittab.
326*7c478bd9Sstevel@tonic-gate  *
327*7c478bd9Sstevel@tonic-gate  *	TOUCHED		Flag used by remv() to determine whether it has looked
328*7c478bd9Sstevel@tonic-gate  *			at an entry while checking for processes to be killed.
329*7c478bd9Sstevel@tonic-gate  *
330*7c478bd9Sstevel@tonic-gate  *	WARNED		Flag used by remv() to mark processes that have been
331*7c478bd9Sstevel@tonic-gate  *			sent the SIGTERM signal.  If they don't die in 5
332*7c478bd9Sstevel@tonic-gate  *			seconds, they are sent the SIGKILL signal.
333*7c478bd9Sstevel@tonic-gate  *
334*7c478bd9Sstevel@tonic-gate  *	KILLED		Flag used by remv() to mark procs that have been sent
335*7c478bd9Sstevel@tonic-gate  *			the SIGTERM and SIGKILL signals.
336*7c478bd9Sstevel@tonic-gate  *
337*7c478bd9Sstevel@tonic-gate  *	PF_MASK		Bitwise or of legal flags, for sanity checking.
338*7c478bd9Sstevel@tonic-gate  */
339*7c478bd9Sstevel@tonic-gate #define	OCCUPIED	01
340*7c478bd9Sstevel@tonic-gate #define	LIVING		02
341*7c478bd9Sstevel@tonic-gate #define	NOCLEANUP	04
342*7c478bd9Sstevel@tonic-gate #define	NAMED		010
343*7c478bd9Sstevel@tonic-gate #define	DEMANDREQUEST	020
344*7c478bd9Sstevel@tonic-gate #define	TOUCHED		040
345*7c478bd9Sstevel@tonic-gate #define	WARNED		0100
346*7c478bd9Sstevel@tonic-gate #define	KILLED		0200
347*7c478bd9Sstevel@tonic-gate #define	PF_MASK		0377
348*7c478bd9Sstevel@tonic-gate 
349*7c478bd9Sstevel@tonic-gate /*
350*7c478bd9Sstevel@tonic-gate  * Respawn limits for processes that are to be respawned:
351*7c478bd9Sstevel@tonic-gate  *
352*7c478bd9Sstevel@tonic-gate  *	SPAWN_INTERVAL	The number of seconds over which "init" will try to
353*7c478bd9Sstevel@tonic-gate  *			respawn a process SPAWN_LIMIT times before it gets mad.
354*7c478bd9Sstevel@tonic-gate  *
355*7c478bd9Sstevel@tonic-gate  *	SPAWN_LIMIT	The number of respawns "init" will attempt in
356*7c478bd9Sstevel@tonic-gate  *			SPAWN_INTERVAL seconds before it generates an
357*7c478bd9Sstevel@tonic-gate  *			error message and inhibits further tries for
358*7c478bd9Sstevel@tonic-gate  *			INHIBIT seconds.
359*7c478bd9Sstevel@tonic-gate  *
360*7c478bd9Sstevel@tonic-gate  *	INHIBIT		The number of seconds "init" ignores an entry it had
361*7c478bd9Sstevel@tonic-gate  *			trouble spawning unless a "telinit Q" is received.
362*7c478bd9Sstevel@tonic-gate  */
363*7c478bd9Sstevel@tonic-gate 
364*7c478bd9Sstevel@tonic-gate #define	SPAWN_INTERVAL	(2*60)
365*7c478bd9Sstevel@tonic-gate #define	SPAWN_LIMIT	10
366*7c478bd9Sstevel@tonic-gate #define	INHIBIT		(5*60)
367*7c478bd9Sstevel@tonic-gate 
368*7c478bd9Sstevel@tonic-gate /*
369*7c478bd9Sstevel@tonic-gate  * The maximum number of decimal digits for an id_t.  (ceil(log10 (max_id)))
370*7c478bd9Sstevel@tonic-gate  */
371*7c478bd9Sstevel@tonic-gate #define	ID_MAX_STR_LEN	10
372*7c478bd9Sstevel@tonic-gate 
373*7c478bd9Sstevel@tonic-gate #define	NULLPROC	((struct PROC_TABLE *)(0))
374*7c478bd9Sstevel@tonic-gate #define	NO_ROOM		((struct PROC_TABLE *)(FAILURE))
375*7c478bd9Sstevel@tonic-gate 
376*7c478bd9Sstevel@tonic-gate struct CMD_LINE {
377*7c478bd9Sstevel@tonic-gate 	char c_id[4];	/* Four letter unique id of process to be */
378*7c478bd9Sstevel@tonic-gate 			/*   affected by action */
379*7c478bd9Sstevel@tonic-gate 	short c_levels;	/* Mask of legal levels for process */
380*7c478bd9Sstevel@tonic-gate 	short c_action;	/* Mask for type of action required */
381*7c478bd9Sstevel@tonic-gate 	char *c_command; /* Pointer to init command */
382*7c478bd9Sstevel@tonic-gate };
383*7c478bd9Sstevel@tonic-gate 
384*7c478bd9Sstevel@tonic-gate struct	pidrec {
385*7c478bd9Sstevel@tonic-gate 	int	pd_type;	/* Command type */
386*7c478bd9Sstevel@tonic-gate 	pid_t	pd_pid;		/* pid to add or remove */
387*7c478bd9Sstevel@tonic-gate };
388*7c478bd9Sstevel@tonic-gate 
389*7c478bd9Sstevel@tonic-gate /*
390*7c478bd9Sstevel@tonic-gate  * pd_type's
391*7c478bd9Sstevel@tonic-gate  */
392*7c478bd9Sstevel@tonic-gate #define	ADDPID	1
393*7c478bd9Sstevel@tonic-gate #define	REMPID	2
394*7c478bd9Sstevel@tonic-gate 
395*7c478bd9Sstevel@tonic-gate static struct	pidlist {
396*7c478bd9Sstevel@tonic-gate 	pid_t	pl_pid;		/* pid to watch for */
397*7c478bd9Sstevel@tonic-gate 	int	pl_dflag;	/* Flag indicating SIGCLD from this pid */
398*7c478bd9Sstevel@tonic-gate 	short	pl_exit;	/* Exit status of proc */
399*7c478bd9Sstevel@tonic-gate 	struct	pidlist	*pl_next; /* Next in list */
400*7c478bd9Sstevel@tonic-gate } *Plhead, *Plfree;
401*7c478bd9Sstevel@tonic-gate 
402*7c478bd9Sstevel@tonic-gate /*
403*7c478bd9Sstevel@tonic-gate  * The following structure contains a set of modes for /dev/syscon
404*7c478bd9Sstevel@tonic-gate  * and should match the default contents of /etc/ioctl.syscon.
405*7c478bd9Sstevel@tonic-gate  */
406*7c478bd9Sstevel@tonic-gate static struct termios	dflt_termios = {
407*7c478bd9Sstevel@tonic-gate 	BRKINT|ICRNL|IXON|IMAXBEL,			/* iflag */
408*7c478bd9Sstevel@tonic-gate 	OPOST|ONLCR|TAB3,				/* oflag */
409*7c478bd9Sstevel@tonic-gate 	CS8|CREAD|B9600,				/* cflag */
410*7c478bd9Sstevel@tonic-gate 	ISIG|ICANON|ECHO|ECHOE|ECHOK|ECHOCTL|ECHOKE|IEXTEN, /* lflag */
411*7c478bd9Sstevel@tonic-gate 	CINTR, CQUIT, CERASE, CKILL, CEOF, 0, 0, 0,
412*7c478bd9Sstevel@tonic-gate 	0, 0, 0, 0, 0, 0, 0, 0,
413*7c478bd9Sstevel@tonic-gate 	0, 0, 0
414*7c478bd9Sstevel@tonic-gate };
415*7c478bd9Sstevel@tonic-gate 
416*7c478bd9Sstevel@tonic-gate static struct termios	stored_syscon_termios;
417*7c478bd9Sstevel@tonic-gate static int		write_ioctl = 0;	/* Rewrite /etc/ioctl.syscon */
418*7c478bd9Sstevel@tonic-gate 
419*7c478bd9Sstevel@tonic-gate static union WAKEUP {
420*7c478bd9Sstevel@tonic-gate 	struct WAKEFLAGS {
421*7c478bd9Sstevel@tonic-gate 		unsigned w_usersignal : 1;	/* User sent signal to "init" */
422*7c478bd9Sstevel@tonic-gate 		unsigned w_childdeath : 1;	/* An "init" child died */
423*7c478bd9Sstevel@tonic-gate 		unsigned w_powerhit : 1;	/* OS experienced powerfail */
424*7c478bd9Sstevel@tonic-gate 	}	w_flags;
425*7c478bd9Sstevel@tonic-gate 	int w_mask;
426*7c478bd9Sstevel@tonic-gate } wakeup;
427*7c478bd9Sstevel@tonic-gate 
428*7c478bd9Sstevel@tonic-gate 
429*7c478bd9Sstevel@tonic-gate struct init_state {
430*7c478bd9Sstevel@tonic-gate 	int			ist_runlevel;
431*7c478bd9Sstevel@tonic-gate 	int			ist_num_proc;
432*7c478bd9Sstevel@tonic-gate 	int			ist_utmpx_ok;
433*7c478bd9Sstevel@tonic-gate 	struct PROC_TABLE	ist_proc_table[1];
434*7c478bd9Sstevel@tonic-gate };
435*7c478bd9Sstevel@tonic-gate 
436*7c478bd9Sstevel@tonic-gate #define	cur_state	(g_state->ist_runlevel)
437*7c478bd9Sstevel@tonic-gate #define	num_proc	(g_state->ist_num_proc)
438*7c478bd9Sstevel@tonic-gate #define	proc_table	(g_state->ist_proc_table)
439*7c478bd9Sstevel@tonic-gate #define	utmpx_ok	(g_state->ist_utmpx_ok)
440*7c478bd9Sstevel@tonic-gate 
441*7c478bd9Sstevel@tonic-gate /* Contract cookies. */
442*7c478bd9Sstevel@tonic-gate #define	ORDINARY_COOKIE		0
443*7c478bd9Sstevel@tonic-gate #define	STARTD_COOKIE		1
444*7c478bd9Sstevel@tonic-gate 
445*7c478bd9Sstevel@tonic-gate 
446*7c478bd9Sstevel@tonic-gate #ifndef NDEBUG
447*7c478bd9Sstevel@tonic-gate #define	bad_error(func, err)	{					\
448*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "%s:%d: %s() failed with unexpected "	\
449*7c478bd9Sstevel@tonic-gate 	    "error %d.  Aborting.\n", __FILE__, __LINE__, (func), (err)); \
450*7c478bd9Sstevel@tonic-gate 	abort();							\
451*7c478bd9Sstevel@tonic-gate }
452*7c478bd9Sstevel@tonic-gate #else
453*7c478bd9Sstevel@tonic-gate #define	bad_error(func, err)	abort()
454*7c478bd9Sstevel@tonic-gate #endif
455*7c478bd9Sstevel@tonic-gate 
456*7c478bd9Sstevel@tonic-gate 
457*7c478bd9Sstevel@tonic-gate /*
458*7c478bd9Sstevel@tonic-gate  * Useful file and device names.
459*7c478bd9Sstevel@tonic-gate  */
460*7c478bd9Sstevel@tonic-gate static char *CONSOLE	  = "/dev/console";	/* Real system console */
461*7c478bd9Sstevel@tonic-gate static char *INITPIPE_DIR = "/etc";
462*7c478bd9Sstevel@tonic-gate static char *INITPIPE	  = "/etc/initpipe";
463*7c478bd9Sstevel@tonic-gate 
464*7c478bd9Sstevel@tonic-gate #define	INIT_STATE_DIR "/etc/svc/volatile"
465*7c478bd9Sstevel@tonic-gate static const char * const init_state_file = INIT_STATE_DIR "/init.state";
466*7c478bd9Sstevel@tonic-gate static const char * const init_next_state_file =
467*7c478bd9Sstevel@tonic-gate 	INIT_STATE_DIR "/init-next.state";
468*7c478bd9Sstevel@tonic-gate 
469*7c478bd9Sstevel@tonic-gate static const int init_num_proc = 20;	/* Initial size of process table. */
470*7c478bd9Sstevel@tonic-gate 
471*7c478bd9Sstevel@tonic-gate static char *UTMPX	 = UTMPX_FILE;		/* Snapshot record file */
472*7c478bd9Sstevel@tonic-gate static char *WTMPX	 = WTMPX_FILE;		/* Long term record file */
473*7c478bd9Sstevel@tonic-gate static char *INITTAB	 = "/etc/inittab";	/* Script file for "init" */
474*7c478bd9Sstevel@tonic-gate static char *SYSTTY	 = "/dev/systty";	/* System Console */
475*7c478bd9Sstevel@tonic-gate static char *SYSCON	 = "/dev/syscon";	/* Virtual System console */
476*7c478bd9Sstevel@tonic-gate static char *IOCTLSYSCON = "/etc/ioctl.syscon";	/* Last syscon modes */
477*7c478bd9Sstevel@tonic-gate static char *ENVFILE	 = "/etc/default/init";	/* Default env. */
478*7c478bd9Sstevel@tonic-gate static char *SU	= "/etc/sulogin";	/* Super-user program for single user */
479*7c478bd9Sstevel@tonic-gate static char *SH	= "/sbin/sh";		/* Standard shell */
480*7c478bd9Sstevel@tonic-gate 
481*7c478bd9Sstevel@tonic-gate /*
482*7c478bd9Sstevel@tonic-gate  * Default Path.  /sbin is included in path only during sysinit phase
483*7c478bd9Sstevel@tonic-gate  */
484*7c478bd9Sstevel@tonic-gate #define	DEF_PATH	"PATH=/usr/sbin:/usr/bin"
485*7c478bd9Sstevel@tonic-gate #define	INIT_PATH	"PATH=/sbin:/usr/sbin:/usr/bin"
486*7c478bd9Sstevel@tonic-gate 
487*7c478bd9Sstevel@tonic-gate static int	prior_state;
488*7c478bd9Sstevel@tonic-gate static int	prev_state;	/* State "init" was in last time it woke */
489*7c478bd9Sstevel@tonic-gate static int	new_state;	/* State user wants "init" to go to. */
490*7c478bd9Sstevel@tonic-gate static int	op_modes = BOOT_MODES; /* Current state of "init" */
491*7c478bd9Sstevel@tonic-gate static int	Gchild = 0;	/* Flag to indicate "godchild" died, set in */
492*7c478bd9Sstevel@tonic-gate 				/*   childeath() and cleared in cleanaux() */
493*7c478bd9Sstevel@tonic-gate static int	Pfd = -1;	/* fd to receive pids thru */
494*7c478bd9Sstevel@tonic-gate static unsigned int	spawncnt, pausecnt;
495*7c478bd9Sstevel@tonic-gate static int	rsflag;		/* Set if a respawn has taken place */
496*7c478bd9Sstevel@tonic-gate static volatile int time_up;	/* Flag set to TRUE by the alarm interrupt */
497*7c478bd9Sstevel@tonic-gate 				/* routine each time an alarm interrupt */
498*7c478bd9Sstevel@tonic-gate 				/* takes place. */
499*7c478bd9Sstevel@tonic-gate static int	sflg = 0;	/* Set if we were booted -s to single user */
500*7c478bd9Sstevel@tonic-gate static int	rflg = 0;	/* Set if booted -r, reconfigure devices */
501*7c478bd9Sstevel@tonic-gate static int	bflg = 0;	/* Set if booted -b, don't run rc scripts */
502*7c478bd9Sstevel@tonic-gate static pid_t	init_pid;	/* PID of "one true" init for current zone */
503*7c478bd9Sstevel@tonic-gate 
504*7c478bd9Sstevel@tonic-gate static struct init_state *g_state = NULL;
505*7c478bd9Sstevel@tonic-gate static size_t	g_state_sz;
506*7c478bd9Sstevel@tonic-gate static int	booting = 1;	/* Set while we're booting. */
507*7c478bd9Sstevel@tonic-gate 
508*7c478bd9Sstevel@tonic-gate /*
509*7c478bd9Sstevel@tonic-gate  * Array for default global environment.
510*7c478bd9Sstevel@tonic-gate  */
511*7c478bd9Sstevel@tonic-gate #define	MAXENVENT	24	/* Max number of default env variables + 1 */
512*7c478bd9Sstevel@tonic-gate 				/* init can use three itself, so this leaves */
513*7c478bd9Sstevel@tonic-gate 				/* 20 for the administrator in ENVFILE. */
514*7c478bd9Sstevel@tonic-gate static char	*glob_envp[MAXENVENT];	/* Array of environment strings */
515*7c478bd9Sstevel@tonic-gate static int	glob_envn;		/* Number of environment strings */
516*7c478bd9Sstevel@tonic-gate 
517*7c478bd9Sstevel@tonic-gate 
518*7c478bd9Sstevel@tonic-gate static struct pollfd	poll_fds[1];
519*7c478bd9Sstevel@tonic-gate static int		poll_nfds = 0;	/* poll_fds is uninitialized */
520*7c478bd9Sstevel@tonic-gate 
521*7c478bd9Sstevel@tonic-gate static int	legacy_tmpl = -1;	/* fd for legacy contract template */
522*7c478bd9Sstevel@tonic-gate static int	startd_tmpl = -1;	/* fd for svc.startd's template */
523*7c478bd9Sstevel@tonic-gate 
524*7c478bd9Sstevel@tonic-gate static char	startd_cline[256] = "";	/* svc.startd's command line */
525*7c478bd9Sstevel@tonic-gate static int	do_restart_startd = 1;	/* Whether to restart svc.startd. */
526*7c478bd9Sstevel@tonic-gate static char	*smf_options = NULL;	/* Options to give to startd. */
527*7c478bd9Sstevel@tonic-gate static int	smf_debug = 0;		/* Messages for debugging smf(5) */
528*7c478bd9Sstevel@tonic-gate static time_t	init_boot_time;		/* Substitute for kernel boot time. */
529*7c478bd9Sstevel@tonic-gate 
530*7c478bd9Sstevel@tonic-gate #define	NSTARTD_FAILURE_TIMES	3		/* trigger after 3 failures */
531*7c478bd9Sstevel@tonic-gate #define	STARTD_FAILURE_RATE_NS	5000000000LL	/* 1 failure/5 seconds */
532*7c478bd9Sstevel@tonic-gate 
533*7c478bd9Sstevel@tonic-gate static hrtime_t	startd_failure_time[NSTARTD_FAILURE_TIMES];
534*7c478bd9Sstevel@tonic-gate static uint_t	startd_failure_index;
535*7c478bd9Sstevel@tonic-gate 
536*7c478bd9Sstevel@tonic-gate 
537*7c478bd9Sstevel@tonic-gate static char	*prog_name(char *);
538*7c478bd9Sstevel@tonic-gate static int	state_to_mask(int);
539*7c478bd9Sstevel@tonic-gate static int	lvlname_to_mask(char, int *);
540*7c478bd9Sstevel@tonic-gate static void	lscf_set_runlevel(char);
541*7c478bd9Sstevel@tonic-gate static int	state_to_flags(int);
542*7c478bd9Sstevel@tonic-gate static char	state_to_name(int);
543*7c478bd9Sstevel@tonic-gate static int	lvlname_to_state(char);
544*7c478bd9Sstevel@tonic-gate static int	getcmd(struct CMD_LINE *, char *);
545*7c478bd9Sstevel@tonic-gate static int	realcon();
546*7c478bd9Sstevel@tonic-gate static int	spawn_processes();
547*7c478bd9Sstevel@tonic-gate static int	get_ioctl_syscon();
548*7c478bd9Sstevel@tonic-gate static int	account(short, struct PROC_TABLE *, char *);
549*7c478bd9Sstevel@tonic-gate static void	alarmclk();
550*7c478bd9Sstevel@tonic-gate static void	childeath(int);
551*7c478bd9Sstevel@tonic-gate static void	cleanaux();
552*7c478bd9Sstevel@tonic-gate static void	clearent(pid_t, short);
553*7c478bd9Sstevel@tonic-gate static void	console(boolean_t, char *, ...);
554*7c478bd9Sstevel@tonic-gate static void	init_signals(void);
555*7c478bd9Sstevel@tonic-gate static void	setup_pipe();
556*7c478bd9Sstevel@tonic-gate static void	killproc(pid_t);
557*7c478bd9Sstevel@tonic-gate static void	init_env();
558*7c478bd9Sstevel@tonic-gate static void	boot_init();
559*7c478bd9Sstevel@tonic-gate static void	powerfail();
560*7c478bd9Sstevel@tonic-gate static void	remv();
561*7c478bd9Sstevel@tonic-gate static void	write_ioctl_syscon();
562*7c478bd9Sstevel@tonic-gate static void	spawn(struct PROC_TABLE *, struct CMD_LINE *);
563*7c478bd9Sstevel@tonic-gate static void	setimer(int);
564*7c478bd9Sstevel@tonic-gate static void	siglvl(int, siginfo_t *, ucontext_t *);
565*7c478bd9Sstevel@tonic-gate static void	sigpoll(int);
566*7c478bd9Sstevel@tonic-gate static void	enter_maintenance(void);
567*7c478bd9Sstevel@tonic-gate static void	timer(int);
568*7c478bd9Sstevel@tonic-gate static void	userinit(int, char **);
569*7c478bd9Sstevel@tonic-gate static void	notify_pam_dead(struct utmpx *);
570*7c478bd9Sstevel@tonic-gate static long	waitproc(struct PROC_TABLE *);
571*7c478bd9Sstevel@tonic-gate static struct PROC_TABLE *efork(int, struct PROC_TABLE *, int);
572*7c478bd9Sstevel@tonic-gate static struct PROC_TABLE *findpslot(struct CMD_LINE *);
573*7c478bd9Sstevel@tonic-gate static void	increase_proc_table_size();
574*7c478bd9Sstevel@tonic-gate static void	st_init();
575*7c478bd9Sstevel@tonic-gate static void	st_write();
576*7c478bd9Sstevel@tonic-gate static void	contracts_init();
577*7c478bd9Sstevel@tonic-gate static void	contract_event(struct pollfd *);
578*7c478bd9Sstevel@tonic-gate static int	startd_run(const char *, int, ctid_t);
579*7c478bd9Sstevel@tonic-gate static void	startd_record_failure();
580*7c478bd9Sstevel@tonic-gate static int	startd_failure_rate_critical();
581*7c478bd9Sstevel@tonic-gate static char	*audit_boot_msg();
582*7c478bd9Sstevel@tonic-gate static int	audit_put_record(int, int, char *);
583*7c478bd9Sstevel@tonic-gate static void	update_boot_archive(int new_state);
584*7c478bd9Sstevel@tonic-gate 
585*7c478bd9Sstevel@tonic-gate int
586*7c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
587*7c478bd9Sstevel@tonic-gate {
588*7c478bd9Sstevel@tonic-gate 	int	chg_lvl_flag = FALSE, print_banner = FALSE;
589*7c478bd9Sstevel@tonic-gate 	int	may_need_audit = 1;
590*7c478bd9Sstevel@tonic-gate 	int	c;
591*7c478bd9Sstevel@tonic-gate 	char	*msg;
592*7c478bd9Sstevel@tonic-gate 
593*7c478bd9Sstevel@tonic-gate 	/* Get a timestamp for use as boot time, if needed. */
594*7c478bd9Sstevel@tonic-gate 	(void) time(&init_boot_time);
595*7c478bd9Sstevel@tonic-gate 
596*7c478bd9Sstevel@tonic-gate 	/* Get the default umask */
597*7c478bd9Sstevel@tonic-gate 	cmask = umask(022);
598*7c478bd9Sstevel@tonic-gate 	(void) umask(cmask);
599*7c478bd9Sstevel@tonic-gate 
600*7c478bd9Sstevel@tonic-gate 	/* Parse the arguments to init. Check for single user */
601*7c478bd9Sstevel@tonic-gate 	opterr = 0;
602*7c478bd9Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "brsm:")) != EOF) {
603*7c478bd9Sstevel@tonic-gate 		switch (c) {
604*7c478bd9Sstevel@tonic-gate 		case 'b':
605*7c478bd9Sstevel@tonic-gate 			rflg = 0;
606*7c478bd9Sstevel@tonic-gate 			bflg = 1;
607*7c478bd9Sstevel@tonic-gate 			if (!sflg)
608*7c478bd9Sstevel@tonic-gate 				sflg++;
609*7c478bd9Sstevel@tonic-gate 			break;
610*7c478bd9Sstevel@tonic-gate 		case 'r':
611*7c478bd9Sstevel@tonic-gate 			bflg = 0;
612*7c478bd9Sstevel@tonic-gate 			rflg++;
613*7c478bd9Sstevel@tonic-gate 			break;
614*7c478bd9Sstevel@tonic-gate 		case 's':
615*7c478bd9Sstevel@tonic-gate 			if (!bflg)
616*7c478bd9Sstevel@tonic-gate 				sflg++;
617*7c478bd9Sstevel@tonic-gate 			break;
618*7c478bd9Sstevel@tonic-gate 		case 'm':
619*7c478bd9Sstevel@tonic-gate 			smf_options = optarg;
620*7c478bd9Sstevel@tonic-gate 			smf_debug = (strstr(smf_options, "debug") != NULL);
621*7c478bd9Sstevel@tonic-gate 			break;
622*7c478bd9Sstevel@tonic-gate 		}
623*7c478bd9Sstevel@tonic-gate 	}
624*7c478bd9Sstevel@tonic-gate 
625*7c478bd9Sstevel@tonic-gate 	/*
626*7c478bd9Sstevel@tonic-gate 	 * Determine if we are the main init, or a user invoked init, whose job
627*7c478bd9Sstevel@tonic-gate 	 * it is to inform init to change levels or perform some other action.
628*7c478bd9Sstevel@tonic-gate 	 */
629*7c478bd9Sstevel@tonic-gate 	if (zone_getattr(getzoneid(), ZONE_ATTR_INITPID, &init_pid,
630*7c478bd9Sstevel@tonic-gate 	    sizeof (init_pid)) != sizeof (init_pid)) {
631*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "could not get pid for init\n");
632*7c478bd9Sstevel@tonic-gate 		return (1);
633*7c478bd9Sstevel@tonic-gate 	}
634*7c478bd9Sstevel@tonic-gate 
635*7c478bd9Sstevel@tonic-gate 	/*
636*7c478bd9Sstevel@tonic-gate 	 * If this PID is not the same as the "true" init for the zone, then we
637*7c478bd9Sstevel@tonic-gate 	 * must be in 'user' mode.
638*7c478bd9Sstevel@tonic-gate 	 */
639*7c478bd9Sstevel@tonic-gate 	if (getpid() != init_pid) {
640*7c478bd9Sstevel@tonic-gate 		userinit(argc, argv);
641*7c478bd9Sstevel@tonic-gate 	}
642*7c478bd9Sstevel@tonic-gate 
643*7c478bd9Sstevel@tonic-gate 	if (getzoneid() != GLOBAL_ZONEID) {
644*7c478bd9Sstevel@tonic-gate 		print_banner = TRUE;
645*7c478bd9Sstevel@tonic-gate 	}
646*7c478bd9Sstevel@tonic-gate 
647*7c478bd9Sstevel@tonic-gate 	/*
648*7c478bd9Sstevel@tonic-gate 	 * Initialize state (and set "booting").
649*7c478bd9Sstevel@tonic-gate 	 */
650*7c478bd9Sstevel@tonic-gate 	st_init();
651*7c478bd9Sstevel@tonic-gate 
652*7c478bd9Sstevel@tonic-gate 	if (booting && print_banner) {
653*7c478bd9Sstevel@tonic-gate 		struct utsname un;
654*7c478bd9Sstevel@tonic-gate 		char buf[BUFSIZ], *isa;
655*7c478bd9Sstevel@tonic-gate 		long ret;
656*7c478bd9Sstevel@tonic-gate 		int bits = 32;
657*7c478bd9Sstevel@tonic-gate 
658*7c478bd9Sstevel@tonic-gate 		/*
659*7c478bd9Sstevel@tonic-gate 		 * We want to print the boot banner as soon as
660*7c478bd9Sstevel@tonic-gate 		 * possible.  In the global zone, the kernel does it,
661*7c478bd9Sstevel@tonic-gate 		 * but we do not have that luxury in non-global zones,
662*7c478bd9Sstevel@tonic-gate 		 * so we will print it here.
663*7c478bd9Sstevel@tonic-gate 		 */
664*7c478bd9Sstevel@tonic-gate 		(void) uname(&un);
665*7c478bd9Sstevel@tonic-gate 		ret = sysinfo(SI_ISALIST, buf, sizeof (buf));
666*7c478bd9Sstevel@tonic-gate 		if (ret != -1L && ret <= sizeof (buf)) {
667*7c478bd9Sstevel@tonic-gate 			for (isa = strtok(buf, " "); isa;
668*7c478bd9Sstevel@tonic-gate 			    isa = strtok(NULL, " ")) {
669*7c478bd9Sstevel@tonic-gate 				if (strcmp(isa, "sparcv9") == 0 ||
670*7c478bd9Sstevel@tonic-gate 				    strcmp(isa, "amd64") == 0) {
671*7c478bd9Sstevel@tonic-gate 					bits = 64;
672*7c478bd9Sstevel@tonic-gate 					break;
673*7c478bd9Sstevel@tonic-gate 				}
674*7c478bd9Sstevel@tonic-gate 			}
675*7c478bd9Sstevel@tonic-gate 		}
676*7c478bd9Sstevel@tonic-gate 
677*7c478bd9Sstevel@tonic-gate 		console(B_FALSE,
678*7c478bd9Sstevel@tonic-gate 		    "\n\n%s Release %s Version %s %d-bit\r\n",
679*7c478bd9Sstevel@tonic-gate 		    un.sysname, un.release, un.version, bits);
680*7c478bd9Sstevel@tonic-gate 		console(B_FALSE,
681*7c478bd9Sstevel@tonic-gate 		    "Copyright 1983-2005 Sun Microsystems, Inc. "
682*7c478bd9Sstevel@tonic-gate 		    " All rights reserved.\r\n");
683*7c478bd9Sstevel@tonic-gate 		console(B_FALSE,
684*7c478bd9Sstevel@tonic-gate 		    "Use is subject to license terms.\r\n");
685*7c478bd9Sstevel@tonic-gate 	}
686*7c478bd9Sstevel@tonic-gate 
687*7c478bd9Sstevel@tonic-gate 	/*
688*7c478bd9Sstevel@tonic-gate 	 * Get the ioctl settings for /dev/syscon from /etc/ioctl.syscon
689*7c478bd9Sstevel@tonic-gate 	 * so that it can be brought up in the state it was in when the
690*7c478bd9Sstevel@tonic-gate 	 * system went down; or set to defaults if ioctl.syscon isn't
691*7c478bd9Sstevel@tonic-gate 	 * valid.
692*7c478bd9Sstevel@tonic-gate 	 *
693*7c478bd9Sstevel@tonic-gate 	 * This needs to be done even if we're restarting so reset_modes()
694*7c478bd9Sstevel@tonic-gate 	 * will work in case we need to go down to single user mode.
695*7c478bd9Sstevel@tonic-gate 	 */
696*7c478bd9Sstevel@tonic-gate 	write_ioctl = get_ioctl_syscon();
697*7c478bd9Sstevel@tonic-gate 
698*7c478bd9Sstevel@tonic-gate 	/*
699*7c478bd9Sstevel@tonic-gate 	 * Set up all signals to be caught or ignored as appropriate.
700*7c478bd9Sstevel@tonic-gate 	 */
701*7c478bd9Sstevel@tonic-gate 	init_signals();
702*7c478bd9Sstevel@tonic-gate 
703*7c478bd9Sstevel@tonic-gate 	/* Load glob_envp from ENVFILE. */
704*7c478bd9Sstevel@tonic-gate 	init_env();
705*7c478bd9Sstevel@tonic-gate 
706*7c478bd9Sstevel@tonic-gate 	contracts_init();
707*7c478bd9Sstevel@tonic-gate 
708*7c478bd9Sstevel@tonic-gate 	if (!booting) {
709*7c478bd9Sstevel@tonic-gate 		/* cur_state should have been read in. */
710*7c478bd9Sstevel@tonic-gate 
711*7c478bd9Sstevel@tonic-gate 		op_modes = NORMAL_MODES;
712*7c478bd9Sstevel@tonic-gate 
713*7c478bd9Sstevel@tonic-gate 		/* Rewrite the ioctl file if it was bad. */
714*7c478bd9Sstevel@tonic-gate 		if (write_ioctl)
715*7c478bd9Sstevel@tonic-gate 			write_ioctl_syscon();
716*7c478bd9Sstevel@tonic-gate 	} else {
717*7c478bd9Sstevel@tonic-gate 		/*
718*7c478bd9Sstevel@tonic-gate 		 * It's fine to boot up with state as zero, because
719*7c478bd9Sstevel@tonic-gate 		 * startd will later tell us the real state.
720*7c478bd9Sstevel@tonic-gate 		 */
721*7c478bd9Sstevel@tonic-gate 		cur_state = 0;
722*7c478bd9Sstevel@tonic-gate 		op_modes = BOOT_MODES;
723*7c478bd9Sstevel@tonic-gate 
724*7c478bd9Sstevel@tonic-gate 		boot_init();
725*7c478bd9Sstevel@tonic-gate 	}
726*7c478bd9Sstevel@tonic-gate 
727*7c478bd9Sstevel@tonic-gate 	prev_state = prior_state = cur_state;
728*7c478bd9Sstevel@tonic-gate 
729*7c478bd9Sstevel@tonic-gate 	/*
730*7c478bd9Sstevel@tonic-gate 	 * Here is the beginning of the main process loop.
731*7c478bd9Sstevel@tonic-gate 	 */
732*7c478bd9Sstevel@tonic-gate 	for (;;) {
733*7c478bd9Sstevel@tonic-gate 		if (Pfd < 0)
734*7c478bd9Sstevel@tonic-gate 			setup_pipe();
735*7c478bd9Sstevel@tonic-gate 
736*7c478bd9Sstevel@tonic-gate 		/*
737*7c478bd9Sstevel@tonic-gate 		 * Clean up any accounting records for dead "godchildren".
738*7c478bd9Sstevel@tonic-gate 		 */
739*7c478bd9Sstevel@tonic-gate 		if (Gchild)
740*7c478bd9Sstevel@tonic-gate 			cleanaux();
741*7c478bd9Sstevel@tonic-gate 
742*7c478bd9Sstevel@tonic-gate 		/*
743*7c478bd9Sstevel@tonic-gate 		 * If in "normal" mode, check all living processes and initiate
744*7c478bd9Sstevel@tonic-gate 		 * kill sequence on those that should not be there anymore.
745*7c478bd9Sstevel@tonic-gate 		 */
746*7c478bd9Sstevel@tonic-gate 		if (op_modes == NORMAL_MODES && cur_state != LVLa &&
747*7c478bd9Sstevel@tonic-gate 		    cur_state != LVLb && cur_state != LVLc)
748*7c478bd9Sstevel@tonic-gate 			remv();
749*7c478bd9Sstevel@tonic-gate 
750*7c478bd9Sstevel@tonic-gate 		/*
751*7c478bd9Sstevel@tonic-gate 		 * If a change in run levels is the reason we awoke, now do
752*7c478bd9Sstevel@tonic-gate 		 * the accounting to report the change in the utmp file.
753*7c478bd9Sstevel@tonic-gate 		 * Also report the change on the system console.
754*7c478bd9Sstevel@tonic-gate 		 */
755*7c478bd9Sstevel@tonic-gate 		if (chg_lvl_flag) {
756*7c478bd9Sstevel@tonic-gate 			chg_lvl_flag = FALSE;
757*7c478bd9Sstevel@tonic-gate 
758*7c478bd9Sstevel@tonic-gate 			if (state_to_flags(cur_state) & LSEL_RUNLEVEL) {
759*7c478bd9Sstevel@tonic-gate 				char rl = state_to_name(cur_state);
760*7c478bd9Sstevel@tonic-gate 
761*7c478bd9Sstevel@tonic-gate 				if (rl != -1)
762*7c478bd9Sstevel@tonic-gate 					lscf_set_runlevel(rl);
763*7c478bd9Sstevel@tonic-gate 			}
764*7c478bd9Sstevel@tonic-gate 
765*7c478bd9Sstevel@tonic-gate 			may_need_audit = 1;
766*7c478bd9Sstevel@tonic-gate 		}
767*7c478bd9Sstevel@tonic-gate 
768*7c478bd9Sstevel@tonic-gate 		/*
769*7c478bd9Sstevel@tonic-gate 		 * Scan the inittab file and spawn and respawn processes that
770*7c478bd9Sstevel@tonic-gate 		 * should be alive in the current state. If inittab does not
771*7c478bd9Sstevel@tonic-gate 		 * exist default to  single user mode.
772*7c478bd9Sstevel@tonic-gate 		 */
773*7c478bd9Sstevel@tonic-gate 		if (spawn_processes() == FAILURE) {
774*7c478bd9Sstevel@tonic-gate 			prior_state = prev_state;
775*7c478bd9Sstevel@tonic-gate 			cur_state = SINGLE_USER;
776*7c478bd9Sstevel@tonic-gate 		}
777*7c478bd9Sstevel@tonic-gate 
778*7c478bd9Sstevel@tonic-gate 		/* If any respawns occurred, take note. */
779*7c478bd9Sstevel@tonic-gate 		if (rsflag) {
780*7c478bd9Sstevel@tonic-gate 			rsflag = 0;
781*7c478bd9Sstevel@tonic-gate 			spawncnt++;
782*7c478bd9Sstevel@tonic-gate 		}
783*7c478bd9Sstevel@tonic-gate 
784*7c478bd9Sstevel@tonic-gate 		/*
785*7c478bd9Sstevel@tonic-gate 		 * If a powerfail signal was received during the last
786*7c478bd9Sstevel@tonic-gate 		 * sequence, set mode to powerfail.  When spawn_processes() is
787*7c478bd9Sstevel@tonic-gate 		 * entered the first thing it does is to check "powerhit".  If
788*7c478bd9Sstevel@tonic-gate 		 * it is in PF_MODES then it clears "powerhit" and does
789*7c478bd9Sstevel@tonic-gate 		 * a powerfail sequence.  If it is not in PF_MODES, then it
790*7c478bd9Sstevel@tonic-gate 		 * puts itself in PF_MODES and then clears "powerhit".  Should
791*7c478bd9Sstevel@tonic-gate 		 * "powerhit" get set again while spawn_processes() is working
792*7c478bd9Sstevel@tonic-gate 		 * on a powerfail sequence, the following code  will see that
793*7c478bd9Sstevel@tonic-gate 		 * spawn_processes() tries to execute the powerfail sequence
794*7c478bd9Sstevel@tonic-gate 		 * again.  This guarantees that the powerfail sequence will be
795*7c478bd9Sstevel@tonic-gate 		 * successfully completed before further processing takes
796*7c478bd9Sstevel@tonic-gate 		 * place.
797*7c478bd9Sstevel@tonic-gate 		 */
798*7c478bd9Sstevel@tonic-gate 		if (wakeup.w_flags.w_powerhit) {
799*7c478bd9Sstevel@tonic-gate 			op_modes = PF_MODES;
800*7c478bd9Sstevel@tonic-gate 			/*
801*7c478bd9Sstevel@tonic-gate 			 * Make sure that cur_state != prev_state so that
802*7c478bd9Sstevel@tonic-gate 			 * ONCE and WAIT types work.
803*7c478bd9Sstevel@tonic-gate 			 */
804*7c478bd9Sstevel@tonic-gate 			prev_state = 0;
805*7c478bd9Sstevel@tonic-gate 		} else if (op_modes != NORMAL_MODES) {
806*7c478bd9Sstevel@tonic-gate 			/*
807*7c478bd9Sstevel@tonic-gate 			 * If spawn_processes() was not just called while in
808*7c478bd9Sstevel@tonic-gate 			 * normal mode, we set the mode to normal and it will
809*7c478bd9Sstevel@tonic-gate 			 * be called again to check normal modes.  If we have
810*7c478bd9Sstevel@tonic-gate 			 * just finished a powerfail sequence with prev_state
811*7c478bd9Sstevel@tonic-gate 			 * equal to zero, we set prev_state equal to cur_state
812*7c478bd9Sstevel@tonic-gate 			 * before the next pass through.
813*7c478bd9Sstevel@tonic-gate 			 */
814*7c478bd9Sstevel@tonic-gate 			if (op_modes == PF_MODES)
815*7c478bd9Sstevel@tonic-gate 				prev_state = cur_state;
816*7c478bd9Sstevel@tonic-gate 			op_modes = NORMAL_MODES;
817*7c478bd9Sstevel@tonic-gate 		} else if (cur_state == LVLa || cur_state == LVLb ||
818*7c478bd9Sstevel@tonic-gate 		    cur_state == LVLc) {
819*7c478bd9Sstevel@tonic-gate 			/*
820*7c478bd9Sstevel@tonic-gate 			 * If it was a change of levels that awakened us and the
821*7c478bd9Sstevel@tonic-gate 			 * new level is one of the demand levels then reset
822*7c478bd9Sstevel@tonic-gate 			 * cur_state to the previous state and do another scan
823*7c478bd9Sstevel@tonic-gate 			 * to take care of the usual respawn actions.
824*7c478bd9Sstevel@tonic-gate 			 */
825*7c478bd9Sstevel@tonic-gate 			cur_state = prior_state;
826*7c478bd9Sstevel@tonic-gate 			prior_state = prev_state;
827*7c478bd9Sstevel@tonic-gate 			prev_state = cur_state;
828*7c478bd9Sstevel@tonic-gate 		} else {
829*7c478bd9Sstevel@tonic-gate 			prev_state = cur_state;
830*7c478bd9Sstevel@tonic-gate 
831*7c478bd9Sstevel@tonic-gate 			if (wakeup.w_mask == 0) {
832*7c478bd9Sstevel@tonic-gate 				int ret;
833*7c478bd9Sstevel@tonic-gate 
834*7c478bd9Sstevel@tonic-gate 				if (may_need_audit && (cur_state == LVL3)) {
835*7c478bd9Sstevel@tonic-gate 					msg = audit_boot_msg();
836*7c478bd9Sstevel@tonic-gate 
837*7c478bd9Sstevel@tonic-gate 					may_need_audit = 0;
838*7c478bd9Sstevel@tonic-gate 					(void) audit_put_record(ADT_SUCCESS,
839*7c478bd9Sstevel@tonic-gate 					    ADT_SUCCESS, msg);
840*7c478bd9Sstevel@tonic-gate 					free(msg);
841*7c478bd9Sstevel@tonic-gate 				}
842*7c478bd9Sstevel@tonic-gate 
843*7c478bd9Sstevel@tonic-gate 				/*
844*7c478bd9Sstevel@tonic-gate 				 * "init" is finished with all actions for
845*7c478bd9Sstevel@tonic-gate 				 * the current wakeup.
846*7c478bd9Sstevel@tonic-gate 				 */
847*7c478bd9Sstevel@tonic-gate 				ret = poll(poll_fds, poll_nfds,
848*7c478bd9Sstevel@tonic-gate 				    SLEEPTIME * MILLISEC);
849*7c478bd9Sstevel@tonic-gate 				pausecnt++;
850*7c478bd9Sstevel@tonic-gate 				if (ret > 0)
851*7c478bd9Sstevel@tonic-gate 					contract_event(&poll_fds[0]);
852*7c478bd9Sstevel@tonic-gate 				else if (ret < 0 && errno != EINTR)
853*7c478bd9Sstevel@tonic-gate 					console(B_TRUE, "poll() error: %s\n",
854*7c478bd9Sstevel@tonic-gate 					    strerror(errno));
855*7c478bd9Sstevel@tonic-gate 			}
856*7c478bd9Sstevel@tonic-gate 
857*7c478bd9Sstevel@tonic-gate 			if (wakeup.w_flags.w_usersignal) {
858*7c478bd9Sstevel@tonic-gate 				/*
859*7c478bd9Sstevel@tonic-gate 				 * Install the new level.  This could be a real
860*7c478bd9Sstevel@tonic-gate 				 * change in levels  or a telinit [Q|a|b|c] or
861*7c478bd9Sstevel@tonic-gate 				 * just a telinit to the same level at which
862*7c478bd9Sstevel@tonic-gate 				 * we are running.
863*7c478bd9Sstevel@tonic-gate 				 */
864*7c478bd9Sstevel@tonic-gate 				if (new_state != cur_state) {
865*7c478bd9Sstevel@tonic-gate 					if (new_state == LVLa ||
866*7c478bd9Sstevel@tonic-gate 					    new_state == LVLb ||
867*7c478bd9Sstevel@tonic-gate 					    new_state == LVLc) {
868*7c478bd9Sstevel@tonic-gate 						prev_state = prior_state;
869*7c478bd9Sstevel@tonic-gate 						prior_state = cur_state;
870*7c478bd9Sstevel@tonic-gate 						cur_state = new_state;
871*7c478bd9Sstevel@tonic-gate 					} else {
872*7c478bd9Sstevel@tonic-gate 						prev_state = cur_state;
873*7c478bd9Sstevel@tonic-gate 						if (cur_state >= 0)
874*7c478bd9Sstevel@tonic-gate 							prior_state = cur_state;
875*7c478bd9Sstevel@tonic-gate 						cur_state = new_state;
876*7c478bd9Sstevel@tonic-gate 						chg_lvl_flag = TRUE;
877*7c478bd9Sstevel@tonic-gate 					}
878*7c478bd9Sstevel@tonic-gate 				}
879*7c478bd9Sstevel@tonic-gate 
880*7c478bd9Sstevel@tonic-gate 				new_state = 0;
881*7c478bd9Sstevel@tonic-gate 			}
882*7c478bd9Sstevel@tonic-gate 
883*7c478bd9Sstevel@tonic-gate 			if (wakeup.w_flags.w_powerhit)
884*7c478bd9Sstevel@tonic-gate 				op_modes = PF_MODES;
885*7c478bd9Sstevel@tonic-gate 
886*7c478bd9Sstevel@tonic-gate 			/*
887*7c478bd9Sstevel@tonic-gate 			 * Clear all wakeup reasons.
888*7c478bd9Sstevel@tonic-gate 			 */
889*7c478bd9Sstevel@tonic-gate 			wakeup.w_mask = 0;
890*7c478bd9Sstevel@tonic-gate 		}
891*7c478bd9Sstevel@tonic-gate 	}
892*7c478bd9Sstevel@tonic-gate 
893*7c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
894*7c478bd9Sstevel@tonic-gate }
895*7c478bd9Sstevel@tonic-gate 
896*7c478bd9Sstevel@tonic-gate static void
897*7c478bd9Sstevel@tonic-gate update_boot_archive(int new_state)
898*7c478bd9Sstevel@tonic-gate {
899*7c478bd9Sstevel@tonic-gate 	if (new_state != LVL0 && new_state != LVL5 && new_state != LVL6)
900*7c478bd9Sstevel@tonic-gate 		return;
901*7c478bd9Sstevel@tonic-gate 
902*7c478bd9Sstevel@tonic-gate 	if (getzoneid() != GLOBAL_ZONEID)
903*7c478bd9Sstevel@tonic-gate 		return;
904*7c478bd9Sstevel@tonic-gate 
905*7c478bd9Sstevel@tonic-gate 	(void) system("/sbin/bootadm -a update_all");
906*7c478bd9Sstevel@tonic-gate }
907*7c478bd9Sstevel@tonic-gate 
908*7c478bd9Sstevel@tonic-gate /*
909*7c478bd9Sstevel@tonic-gate  * void enter_maintenance()
910*7c478bd9Sstevel@tonic-gate  *   A simple invocation of sulogin(1M), with no baggage, in the case that we
911*7c478bd9Sstevel@tonic-gate  *   are unable to activate svc.startd(1M).  We fork; the child runs sulogin;
912*7c478bd9Sstevel@tonic-gate  *   we wait for it to exit.
913*7c478bd9Sstevel@tonic-gate  */
914*7c478bd9Sstevel@tonic-gate static void
915*7c478bd9Sstevel@tonic-gate enter_maintenance()
916*7c478bd9Sstevel@tonic-gate {
917*7c478bd9Sstevel@tonic-gate 	struct PROC_TABLE	*su_process;
918*7c478bd9Sstevel@tonic-gate 
919*7c478bd9Sstevel@tonic-gate 	console(B_FALSE, "Requesting maintenance mode\n"
920*7c478bd9Sstevel@tonic-gate 	    "(See /lib/svc/share/README for additional information.)\n");
921*7c478bd9Sstevel@tonic-gate 	(void) sigset(SIGCLD, SIG_DFL);
922*7c478bd9Sstevel@tonic-gate 	while ((su_process = efork(M_OFF, NULLPROC, NOCLEANUP)) == NO_ROOM)
923*7c478bd9Sstevel@tonic-gate 		(void) pause();
924*7c478bd9Sstevel@tonic-gate 	(void) sigset(SIGCLD, childeath);
925*7c478bd9Sstevel@tonic-gate 	if (su_process == NULLPROC) {
926*7c478bd9Sstevel@tonic-gate 		int fd;
927*7c478bd9Sstevel@tonic-gate 
928*7c478bd9Sstevel@tonic-gate 		(void) fclose(stdin);
929*7c478bd9Sstevel@tonic-gate 		(void) fclose(stdout);
930*7c478bd9Sstevel@tonic-gate 		(void) fclose(stderr);
931*7c478bd9Sstevel@tonic-gate 		closefrom(0);
932*7c478bd9Sstevel@tonic-gate 
933*7c478bd9Sstevel@tonic-gate 		fd = open(SYSCON, O_RDWR | O_NOCTTY);
934*7c478bd9Sstevel@tonic-gate 		if (fd >= 0) {
935*7c478bd9Sstevel@tonic-gate 			(void) dup2(fd, 1);
936*7c478bd9Sstevel@tonic-gate 			(void) dup2(fd, 2);
937*7c478bd9Sstevel@tonic-gate 		} else {
938*7c478bd9Sstevel@tonic-gate 			/*
939*7c478bd9Sstevel@tonic-gate 			 * Need to issue an error message somewhere.
940*7c478bd9Sstevel@tonic-gate 			 */
941*7c478bd9Sstevel@tonic-gate 			syslog(LOG_CRIT, "init[%d]: cannot open %s; %s\n",
942*7c478bd9Sstevel@tonic-gate 			    getpid(), SYSCON, strerror(errno));
943*7c478bd9Sstevel@tonic-gate 		}
944*7c478bd9Sstevel@tonic-gate 
945*7c478bd9Sstevel@tonic-gate 		/*
946*7c478bd9Sstevel@tonic-gate 		 * Execute the "su" program.
947*7c478bd9Sstevel@tonic-gate 		 */
948*7c478bd9Sstevel@tonic-gate 		(void) execle(SU, SU, "-", (char *)0, glob_envp);
949*7c478bd9Sstevel@tonic-gate 		console(B_TRUE, "execle of %s failed: %s\n", SU,
950*7c478bd9Sstevel@tonic-gate 		    strerror(errno));
951*7c478bd9Sstevel@tonic-gate 		timer(5);
952*7c478bd9Sstevel@tonic-gate 		exit(1);
953*7c478bd9Sstevel@tonic-gate 	}
954*7c478bd9Sstevel@tonic-gate 
955*7c478bd9Sstevel@tonic-gate 	/*
956*7c478bd9Sstevel@tonic-gate 	 * If we are the parent, wait around for the child to die
957*7c478bd9Sstevel@tonic-gate 	 * or for "init" to be signaled to change levels.
958*7c478bd9Sstevel@tonic-gate 	 */
959*7c478bd9Sstevel@tonic-gate 	while (waitproc(su_process) == FAILURE) {
960*7c478bd9Sstevel@tonic-gate 		/*
961*7c478bd9Sstevel@tonic-gate 		 * All other reasons for waking are ignored when in
962*7c478bd9Sstevel@tonic-gate 		 * single-user mode.  The only child we are interested
963*7c478bd9Sstevel@tonic-gate 		 * in is being waited for explicitly by waitproc().
964*7c478bd9Sstevel@tonic-gate 		 */
965*7c478bd9Sstevel@tonic-gate 		wakeup.w_mask = 0;
966*7c478bd9Sstevel@tonic-gate 	}
967*7c478bd9Sstevel@tonic-gate }
968*7c478bd9Sstevel@tonic-gate 
969*7c478bd9Sstevel@tonic-gate /*
970*7c478bd9Sstevel@tonic-gate  * remv() scans through "proc_table" and performs cleanup.  If
971*7c478bd9Sstevel@tonic-gate  * there is a process in the table, which shouldn't be here at
972*7c478bd9Sstevel@tonic-gate  * the current run level, then remv() kills the process.
973*7c478bd9Sstevel@tonic-gate  */
974*7c478bd9Sstevel@tonic-gate static void
975*7c478bd9Sstevel@tonic-gate remv()
976*7c478bd9Sstevel@tonic-gate {
977*7c478bd9Sstevel@tonic-gate 	struct PROC_TABLE	*process;
978*7c478bd9Sstevel@tonic-gate 	struct CMD_LINE		cmd;
979*7c478bd9Sstevel@tonic-gate 	char			cmd_string[MAXCMDL];
980*7c478bd9Sstevel@tonic-gate 	int			change_level;
981*7c478bd9Sstevel@tonic-gate 
982*7c478bd9Sstevel@tonic-gate 	change_level = (cur_state != prev_state ? TRUE : FALSE);
983*7c478bd9Sstevel@tonic-gate 
984*7c478bd9Sstevel@tonic-gate 	/*
985*7c478bd9Sstevel@tonic-gate 	 * Clear the TOUCHED flag on all entries so that when we have
986*7c478bd9Sstevel@tonic-gate 	 * finished scanning inittab, we will be able to tell if we
987*7c478bd9Sstevel@tonic-gate 	 * have any processes for which there is no entry in inittab.
988*7c478bd9Sstevel@tonic-gate 	 */
989*7c478bd9Sstevel@tonic-gate 	for (process = proc_table;
990*7c478bd9Sstevel@tonic-gate 	    (process < proc_table + num_proc); process++) {
991*7c478bd9Sstevel@tonic-gate 		process->p_flags &= ~TOUCHED;
992*7c478bd9Sstevel@tonic-gate 	}
993*7c478bd9Sstevel@tonic-gate 
994*7c478bd9Sstevel@tonic-gate 	/*
995*7c478bd9Sstevel@tonic-gate 	 * Scan all inittab entries.
996*7c478bd9Sstevel@tonic-gate 	 */
997*7c478bd9Sstevel@tonic-gate 	while (getcmd(&cmd, &cmd_string[0]) == TRUE) {
998*7c478bd9Sstevel@tonic-gate 		/* Scan for process which goes with this entry in inittab. */
999*7c478bd9Sstevel@tonic-gate 		for (process = proc_table;
1000*7c478bd9Sstevel@tonic-gate 		    (process < proc_table + num_proc); process++) {
1001*7c478bd9Sstevel@tonic-gate 			if ((process->p_flags & OCCUPIED) == 0 ||
1002*7c478bd9Sstevel@tonic-gate 			    !id_eq(process->p_id, cmd.c_id))
1003*7c478bd9Sstevel@tonic-gate 				continue;
1004*7c478bd9Sstevel@tonic-gate 
1005*7c478bd9Sstevel@tonic-gate 			/*
1006*7c478bd9Sstevel@tonic-gate 			 * This slot contains the process we are looking for.
1007*7c478bd9Sstevel@tonic-gate 			 */
1008*7c478bd9Sstevel@tonic-gate 
1009*7c478bd9Sstevel@tonic-gate 			/*
1010*7c478bd9Sstevel@tonic-gate 			 * Is the cur_state SINGLE_USER or is this process
1011*7c478bd9Sstevel@tonic-gate 			 * marked as "off" or was this proc started by some
1012*7c478bd9Sstevel@tonic-gate 			 * mechanism other than LVL{a|b|c} and the current level
1013*7c478bd9Sstevel@tonic-gate 			 * does not support this process?
1014*7c478bd9Sstevel@tonic-gate 			 */
1015*7c478bd9Sstevel@tonic-gate 			if (cur_state == SINGLE_USER ||
1016*7c478bd9Sstevel@tonic-gate 			    cmd.c_action == M_OFF ||
1017*7c478bd9Sstevel@tonic-gate 			    ((cmd.c_levels & state_to_mask(cur_state)) == 0 &&
1018*7c478bd9Sstevel@tonic-gate 			    (process->p_flags & DEMANDREQUEST) == 0)) {
1019*7c478bd9Sstevel@tonic-gate 				if (process->p_flags & LIVING) {
1020*7c478bd9Sstevel@tonic-gate 					/*
1021*7c478bd9Sstevel@tonic-gate 					 * Touch this entry so we know we have
1022*7c478bd9Sstevel@tonic-gate 					 * treated it.  Note that procs which
1023*7c478bd9Sstevel@tonic-gate 					 * are already dead at this point and
1024*7c478bd9Sstevel@tonic-gate 					 * should not be restarted are left
1025*7c478bd9Sstevel@tonic-gate 					 * untouched.  This causes their slot to
1026*7c478bd9Sstevel@tonic-gate 					 * be freed later after dead accounting
1027*7c478bd9Sstevel@tonic-gate 					 * is done.
1028*7c478bd9Sstevel@tonic-gate 					 */
1029*7c478bd9Sstevel@tonic-gate 					process->p_flags |= TOUCHED;
1030*7c478bd9Sstevel@tonic-gate 
1031*7c478bd9Sstevel@tonic-gate 					if ((process->p_flags & KILLED) == 0) {
1032*7c478bd9Sstevel@tonic-gate 						if (change_level) {
1033*7c478bd9Sstevel@tonic-gate 							process->p_flags
1034*7c478bd9Sstevel@tonic-gate 							    |= WARNED;
1035*7c478bd9Sstevel@tonic-gate 							(void) kill(
1036*7c478bd9Sstevel@tonic-gate 							    process->p_pid,
1037*7c478bd9Sstevel@tonic-gate 							    SIGTERM);
1038*7c478bd9Sstevel@tonic-gate 						} else {
1039*7c478bd9Sstevel@tonic-gate 							/*
1040*7c478bd9Sstevel@tonic-gate 							 * Fork a killing proc
1041*7c478bd9Sstevel@tonic-gate 							 * so "init" can
1042*7c478bd9Sstevel@tonic-gate 							 * continue without
1043*7c478bd9Sstevel@tonic-gate 							 * having to pause for
1044*7c478bd9Sstevel@tonic-gate 							 * TWARN seconds.
1045*7c478bd9Sstevel@tonic-gate 							 */
1046*7c478bd9Sstevel@tonic-gate 							killproc(
1047*7c478bd9Sstevel@tonic-gate 							    process->p_pid);
1048*7c478bd9Sstevel@tonic-gate 						}
1049*7c478bd9Sstevel@tonic-gate 						process->p_flags |= KILLED;
1050*7c478bd9Sstevel@tonic-gate 					}
1051*7c478bd9Sstevel@tonic-gate 				}
1052*7c478bd9Sstevel@tonic-gate 			} else {
1053*7c478bd9Sstevel@tonic-gate 				/*
1054*7c478bd9Sstevel@tonic-gate 				 * Process can exist at current level.  If it is
1055*7c478bd9Sstevel@tonic-gate 				 * still alive or a DEMANDREQUEST we touch it so
1056*7c478bd9Sstevel@tonic-gate 				 * it will be left alone.  Otherwise we leave it
1057*7c478bd9Sstevel@tonic-gate 				 * untouched so it will be accounted for and
1058*7c478bd9Sstevel@tonic-gate 				 * cleaned up later in remv().  Dead
1059*7c478bd9Sstevel@tonic-gate 				 * DEMANDREQUESTs will be accounted but not
1060*7c478bd9Sstevel@tonic-gate 				 * freed.
1061*7c478bd9Sstevel@tonic-gate 				 */
1062*7c478bd9Sstevel@tonic-gate 				if (process->p_flags &
1063*7c478bd9Sstevel@tonic-gate 				    (LIVING|NOCLEANUP|DEMANDREQUEST))
1064*7c478bd9Sstevel@tonic-gate 					process->p_flags |= TOUCHED;
1065*7c478bd9Sstevel@tonic-gate 			}
1066*7c478bd9Sstevel@tonic-gate 
1067*7c478bd9Sstevel@tonic-gate 			break;
1068*7c478bd9Sstevel@tonic-gate 		}
1069*7c478bd9Sstevel@tonic-gate 	}
1070*7c478bd9Sstevel@tonic-gate 
1071*7c478bd9Sstevel@tonic-gate 	st_write();
1072*7c478bd9Sstevel@tonic-gate 
1073*7c478bd9Sstevel@tonic-gate 	/*
1074*7c478bd9Sstevel@tonic-gate 	 * If this was a change of levels call, scan through the
1075*7c478bd9Sstevel@tonic-gate 	 * process table for processes that were warned to die.  If any
1076*7c478bd9Sstevel@tonic-gate 	 * are found that haven't left yet, sleep for TWARN seconds and
1077*7c478bd9Sstevel@tonic-gate 	 * then send final terminations to any that haven't died yet.
1078*7c478bd9Sstevel@tonic-gate 	 */
1079*7c478bd9Sstevel@tonic-gate 	if (change_level) {
1080*7c478bd9Sstevel@tonic-gate 
1081*7c478bd9Sstevel@tonic-gate 		/*
1082*7c478bd9Sstevel@tonic-gate 		 * Set the alarm for TWARN seconds on the assumption
1083*7c478bd9Sstevel@tonic-gate 		 * that there will be some that need to be waited for.
1084*7c478bd9Sstevel@tonic-gate 		 * This won't harm anything except we are guaranteed to
1085*7c478bd9Sstevel@tonic-gate 		 * wakeup in TWARN seconds whether we need to or not.
1086*7c478bd9Sstevel@tonic-gate 		 */
1087*7c478bd9Sstevel@tonic-gate 		setimer(TWARN);
1088*7c478bd9Sstevel@tonic-gate 
1089*7c478bd9Sstevel@tonic-gate 		/*
1090*7c478bd9Sstevel@tonic-gate 		 * Scan for processes which should be dying.  We hope they
1091*7c478bd9Sstevel@tonic-gate 		 * will die without having to be sent a SIGKILL signal.
1092*7c478bd9Sstevel@tonic-gate 		 */
1093*7c478bd9Sstevel@tonic-gate 		for (process = proc_table;
1094*7c478bd9Sstevel@tonic-gate 		    (process < proc_table + num_proc); process++) {
1095*7c478bd9Sstevel@tonic-gate 			/*
1096*7c478bd9Sstevel@tonic-gate 			 * If this process should die, hasn't yet, and the
1097*7c478bd9Sstevel@tonic-gate 			 * TWARN time hasn't expired yet, wait for process
1098*7c478bd9Sstevel@tonic-gate 			 * to die or for timer to expire.
1099*7c478bd9Sstevel@tonic-gate 			 */
1100*7c478bd9Sstevel@tonic-gate 			while (time_up == FALSE &&
1101*7c478bd9Sstevel@tonic-gate 			    (process->p_flags & (WARNED|LIVING|OCCUPIED)) ==
1102*7c478bd9Sstevel@tonic-gate 			    (WARNED|LIVING|OCCUPIED))
1103*7c478bd9Sstevel@tonic-gate 				(void) pause();
1104*7c478bd9Sstevel@tonic-gate 
1105*7c478bd9Sstevel@tonic-gate 			if (time_up == TRUE)
1106*7c478bd9Sstevel@tonic-gate 				break;
1107*7c478bd9Sstevel@tonic-gate 		}
1108*7c478bd9Sstevel@tonic-gate 
1109*7c478bd9Sstevel@tonic-gate 		/*
1110*7c478bd9Sstevel@tonic-gate 		 * If we reached the end of the table without the timer
1111*7c478bd9Sstevel@tonic-gate 		 * expiring, then there are no procs which will have to be
1112*7c478bd9Sstevel@tonic-gate 		 * sent the SIGKILL signal.  If the timer has expired, then
1113*7c478bd9Sstevel@tonic-gate 		 * it is necessary to scan the table again and send signals
1114*7c478bd9Sstevel@tonic-gate 		 * to all processes which aren't going away nicely.
1115*7c478bd9Sstevel@tonic-gate 		 */
1116*7c478bd9Sstevel@tonic-gate 		if (time_up == TRUE) {
1117*7c478bd9Sstevel@tonic-gate 			for (process = proc_table;
1118*7c478bd9Sstevel@tonic-gate 			    (process < proc_table + num_proc); process++) {
1119*7c478bd9Sstevel@tonic-gate 				if ((process->p_flags &
1120*7c478bd9Sstevel@tonic-gate 				    (WARNED|LIVING|OCCUPIED)) ==
1121*7c478bd9Sstevel@tonic-gate 				    (WARNED|LIVING|OCCUPIED))
1122*7c478bd9Sstevel@tonic-gate 					(void) kill(process->p_pid, SIGKILL);
1123*7c478bd9Sstevel@tonic-gate 			}
1124*7c478bd9Sstevel@tonic-gate 		}
1125*7c478bd9Sstevel@tonic-gate 		setimer(0);
1126*7c478bd9Sstevel@tonic-gate 	}
1127*7c478bd9Sstevel@tonic-gate 
1128*7c478bd9Sstevel@tonic-gate 	/*
1129*7c478bd9Sstevel@tonic-gate 	 * Rescan the proc_table for two kinds of entry, those marked LIVING,
1130*7c478bd9Sstevel@tonic-gate 	 * NAMED, which don't have an entry in inittab (haven't been TOUCHED
1131*7c478bd9Sstevel@tonic-gate 	 * by the above scanning), and haven't been sent kill signals, and
1132*7c478bd9Sstevel@tonic-gate 	 * those entries marked not LIVING, NAMED.  The former procs are killed.
1133*7c478bd9Sstevel@tonic-gate 	 * The latter have DEAD_PROCESS accounting done and the slot cleared.
1134*7c478bd9Sstevel@tonic-gate 	 */
1135*7c478bd9Sstevel@tonic-gate 	for (process = proc_table;
1136*7c478bd9Sstevel@tonic-gate 	    (process < proc_table + num_proc); process++) {
1137*7c478bd9Sstevel@tonic-gate 		if ((process->p_flags & (LIVING|NAMED|TOUCHED|KILLED|OCCUPIED))
1138*7c478bd9Sstevel@tonic-gate 		    == (LIVING|NAMED|OCCUPIED)) {
1139*7c478bd9Sstevel@tonic-gate 			killproc(process->p_pid);
1140*7c478bd9Sstevel@tonic-gate 			process->p_flags |= KILLED;
1141*7c478bd9Sstevel@tonic-gate 		} else if ((process->p_flags & (LIVING|NAMED|OCCUPIED)) ==
1142*7c478bd9Sstevel@tonic-gate 		    (NAMED|OCCUPIED)) {
1143*7c478bd9Sstevel@tonic-gate 			(void) account(DEAD_PROCESS, process, NULL);
1144*7c478bd9Sstevel@tonic-gate 			/*
1145*7c478bd9Sstevel@tonic-gate 			 * If this named proc hasn't been TOUCHED, then free the
1146*7c478bd9Sstevel@tonic-gate 			 * space. It has either died of it's own accord, but
1147*7c478bd9Sstevel@tonic-gate 			 * isn't respawnable or it was killed because it
1148*7c478bd9Sstevel@tonic-gate 			 * shouldn't exist at this level.
1149*7c478bd9Sstevel@tonic-gate 			 */
1150*7c478bd9Sstevel@tonic-gate 			if ((process->p_flags & TOUCHED) == 0)
1151*7c478bd9Sstevel@tonic-gate 				process->p_flags = 0;
1152*7c478bd9Sstevel@tonic-gate 		}
1153*7c478bd9Sstevel@tonic-gate 	}
1154*7c478bd9Sstevel@tonic-gate 
1155*7c478bd9Sstevel@tonic-gate 	st_write();
1156*7c478bd9Sstevel@tonic-gate }
1157*7c478bd9Sstevel@tonic-gate 
1158*7c478bd9Sstevel@tonic-gate /*
1159*7c478bd9Sstevel@tonic-gate  * Extract the svc.startd command line and whether to restart it from its
1160*7c478bd9Sstevel@tonic-gate  * inittab entry.
1161*7c478bd9Sstevel@tonic-gate  */
1162*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1163*7c478bd9Sstevel@tonic-gate static void
1164*7c478bd9Sstevel@tonic-gate process_startd_line(struct CMD_LINE *cmd, char *cmd_string)
1165*7c478bd9Sstevel@tonic-gate {
1166*7c478bd9Sstevel@tonic-gate 	size_t sz;
1167*7c478bd9Sstevel@tonic-gate 
1168*7c478bd9Sstevel@tonic-gate 	/* Save the command line. */
1169*7c478bd9Sstevel@tonic-gate 	if (sflg || rflg) {
1170*7c478bd9Sstevel@tonic-gate 		/* Also append -r or -s. */
1171*7c478bd9Sstevel@tonic-gate 		(void) strlcpy(startd_cline, cmd_string, sizeof (startd_cline));
1172*7c478bd9Sstevel@tonic-gate 		(void) strlcat(startd_cline, " -", sizeof (startd_cline));
1173*7c478bd9Sstevel@tonic-gate 		if (sflg)
1174*7c478bd9Sstevel@tonic-gate 			sz = strlcat(startd_cline, "s", sizeof (startd_cline));
1175*7c478bd9Sstevel@tonic-gate 		if (rflg)
1176*7c478bd9Sstevel@tonic-gate 			sz = strlcat(startd_cline, "r", sizeof (startd_cline));
1177*7c478bd9Sstevel@tonic-gate 	} else {
1178*7c478bd9Sstevel@tonic-gate 		sz = strlcpy(startd_cline, cmd_string, sizeof (startd_cline));
1179*7c478bd9Sstevel@tonic-gate 	}
1180*7c478bd9Sstevel@tonic-gate 
1181*7c478bd9Sstevel@tonic-gate 	if (sz >= sizeof (startd_cline)) {
1182*7c478bd9Sstevel@tonic-gate 		console(B_TRUE,
1183*7c478bd9Sstevel@tonic-gate 		    "svc.startd command line too long.  Ignoring.\n");
1184*7c478bd9Sstevel@tonic-gate 		startd_cline[0] = '\0';
1185*7c478bd9Sstevel@tonic-gate 		return;
1186*7c478bd9Sstevel@tonic-gate 	}
1187*7c478bd9Sstevel@tonic-gate }
1188*7c478bd9Sstevel@tonic-gate 
1189*7c478bd9Sstevel@tonic-gate /*
1190*7c478bd9Sstevel@tonic-gate  * spawn_processes() scans inittab for entries which should be run at this
1191*7c478bd9Sstevel@tonic-gate  * mode.  Processes which should be running but are not, are started.
1192*7c478bd9Sstevel@tonic-gate  */
1193*7c478bd9Sstevel@tonic-gate static int
1194*7c478bd9Sstevel@tonic-gate spawn_processes()
1195*7c478bd9Sstevel@tonic-gate {
1196*7c478bd9Sstevel@tonic-gate 	struct PROC_TABLE		*pp;
1197*7c478bd9Sstevel@tonic-gate 	struct CMD_LINE			cmd;
1198*7c478bd9Sstevel@tonic-gate 	char				cmd_string[MAXCMDL];
1199*7c478bd9Sstevel@tonic-gate 	short				lvl_mask;
1200*7c478bd9Sstevel@tonic-gate 	int				status;
1201*7c478bd9Sstevel@tonic-gate 
1202*7c478bd9Sstevel@tonic-gate 	/*
1203*7c478bd9Sstevel@tonic-gate 	 * First check the "powerhit" flag.  If it is set, make sure the modes
1204*7c478bd9Sstevel@tonic-gate 	 * are PF_MODES and clear the "powerhit" flag.  Avoid the possible race
1205*7c478bd9Sstevel@tonic-gate 	 * on the "powerhit" flag by disallowing a new powerfail interrupt
1206*7c478bd9Sstevel@tonic-gate 	 * between the test of the powerhit flag and the clearing of it.
1207*7c478bd9Sstevel@tonic-gate 	 */
1208*7c478bd9Sstevel@tonic-gate 	if (wakeup.w_flags.w_powerhit) {
1209*7c478bd9Sstevel@tonic-gate 		wakeup.w_flags.w_powerhit = 0;
1210*7c478bd9Sstevel@tonic-gate 		op_modes = PF_MODES;
1211*7c478bd9Sstevel@tonic-gate 	}
1212*7c478bd9Sstevel@tonic-gate 	lvl_mask = state_to_mask(cur_state);
1213*7c478bd9Sstevel@tonic-gate 
1214*7c478bd9Sstevel@tonic-gate 	/*
1215*7c478bd9Sstevel@tonic-gate 	 * Scan through all the entries in inittab.
1216*7c478bd9Sstevel@tonic-gate 	 */
1217*7c478bd9Sstevel@tonic-gate 	while ((status = getcmd(&cmd, &cmd_string[0])) == TRUE) {
1218*7c478bd9Sstevel@tonic-gate 		if (id_eq(cmd.c_id, "smf")) {
1219*7c478bd9Sstevel@tonic-gate 			process_startd_line(&cmd, cmd_string);
1220*7c478bd9Sstevel@tonic-gate 			continue;
1221*7c478bd9Sstevel@tonic-gate 		}
1222*7c478bd9Sstevel@tonic-gate 
1223*7c478bd9Sstevel@tonic-gate retry_for_proc_slot:
1224*7c478bd9Sstevel@tonic-gate 
1225*7c478bd9Sstevel@tonic-gate 		/*
1226*7c478bd9Sstevel@tonic-gate 		 * Find out if there is a process slot for this entry already.
1227*7c478bd9Sstevel@tonic-gate 		 */
1228*7c478bd9Sstevel@tonic-gate 		if ((pp = findpslot(&cmd)) == NULLPROC) {
1229*7c478bd9Sstevel@tonic-gate 			/*
1230*7c478bd9Sstevel@tonic-gate 			 * we've run out of proc table entries
1231*7c478bd9Sstevel@tonic-gate 			 * increase proc_table.
1232*7c478bd9Sstevel@tonic-gate 			 */
1233*7c478bd9Sstevel@tonic-gate 			increase_proc_table_size();
1234*7c478bd9Sstevel@tonic-gate 
1235*7c478bd9Sstevel@tonic-gate 			/*
1236*7c478bd9Sstevel@tonic-gate 			 * Retry now as we have an empty proc slot.
1237*7c478bd9Sstevel@tonic-gate 			 * In case increase_proc_table_size() fails,
1238*7c478bd9Sstevel@tonic-gate 			 * we will keep retrying.
1239*7c478bd9Sstevel@tonic-gate 			 */
1240*7c478bd9Sstevel@tonic-gate 			goto retry_for_proc_slot;
1241*7c478bd9Sstevel@tonic-gate 		}
1242*7c478bd9Sstevel@tonic-gate 
1243*7c478bd9Sstevel@tonic-gate 		/*
1244*7c478bd9Sstevel@tonic-gate 		 * If there is an entry, and it is marked as DEMANDREQUEST,
1245*7c478bd9Sstevel@tonic-gate 		 * one of the levels a, b, or c is in its levels mask, and
1246*7c478bd9Sstevel@tonic-gate 		 * the action field is ONDEMAND and ONDEMAND is a permissable
1247*7c478bd9Sstevel@tonic-gate 		 * mode, and the process is dead, then respawn it.
1248*7c478bd9Sstevel@tonic-gate 		 */
1249*7c478bd9Sstevel@tonic-gate 		if (((pp->p_flags & (LIVING|DEMANDREQUEST)) == DEMANDREQUEST) &&
1250*7c478bd9Sstevel@tonic-gate 		    (cmd.c_levels & MASK_abc) &&
1251*7c478bd9Sstevel@tonic-gate 		    (cmd.c_action & op_modes) == M_ONDEMAND) {
1252*7c478bd9Sstevel@tonic-gate 			spawn(pp, &cmd);
1253*7c478bd9Sstevel@tonic-gate 			continue;
1254*7c478bd9Sstevel@tonic-gate 		}
1255*7c478bd9Sstevel@tonic-gate 
1256*7c478bd9Sstevel@tonic-gate 		/*
1257*7c478bd9Sstevel@tonic-gate 		 * If the action is not an action we are interested in,
1258*7c478bd9Sstevel@tonic-gate 		 * skip the entry.
1259*7c478bd9Sstevel@tonic-gate 		 */
1260*7c478bd9Sstevel@tonic-gate 		if ((cmd.c_action & op_modes) == 0 || pp->p_flags & LIVING ||
1261*7c478bd9Sstevel@tonic-gate 		    (cmd.c_levels & lvl_mask) == 0)
1262*7c478bd9Sstevel@tonic-gate 			continue;
1263*7c478bd9Sstevel@tonic-gate 
1264*7c478bd9Sstevel@tonic-gate 		/*
1265*7c478bd9Sstevel@tonic-gate 		 * If the modes are the normal modes (ONCE, WAIT, RESPAWN, OFF,
1266*7c478bd9Sstevel@tonic-gate 		 * ONDEMAND) and the action field is either OFF or the action
1267*7c478bd9Sstevel@tonic-gate 		 * field is ONCE or WAIT and the current level is the same as
1268*7c478bd9Sstevel@tonic-gate 		 * the last level, then skip this entry.  ONCE and WAIT only
1269*7c478bd9Sstevel@tonic-gate 		 * get run when the level changes.
1270*7c478bd9Sstevel@tonic-gate 		 */
1271*7c478bd9Sstevel@tonic-gate 		if (op_modes == NORMAL_MODES &&
1272*7c478bd9Sstevel@tonic-gate 		    (cmd.c_action == M_OFF ||
1273*7c478bd9Sstevel@tonic-gate 			(cmd.c_action & (M_ONCE|M_WAIT)) &&
1274*7c478bd9Sstevel@tonic-gate 			cur_state == prev_state))
1275*7c478bd9Sstevel@tonic-gate 			continue;
1276*7c478bd9Sstevel@tonic-gate 
1277*7c478bd9Sstevel@tonic-gate 		/*
1278*7c478bd9Sstevel@tonic-gate 		 * At this point we are interested in performing the action for
1279*7c478bd9Sstevel@tonic-gate 		 * this entry.  Actions fall into two categories, spinning off
1280*7c478bd9Sstevel@tonic-gate 		 * a process and not waiting, and spinning off a process and
1281*7c478bd9Sstevel@tonic-gate 		 * waiting for it to die.  If the action is ONCE, RESPAWN,
1282*7c478bd9Sstevel@tonic-gate 		 * ONDEMAND, POWERFAIL, or BOOT we don't wait for the process
1283*7c478bd9Sstevel@tonic-gate 		 * to die, for all other actions we do wait.
1284*7c478bd9Sstevel@tonic-gate 		 */
1285*7c478bd9Sstevel@tonic-gate 		if (cmd.c_action & (M_ONCE | M_RESPAWN | M_PF | M_BOOT)) {
1286*7c478bd9Sstevel@tonic-gate 			spawn(pp, &cmd);
1287*7c478bd9Sstevel@tonic-gate 
1288*7c478bd9Sstevel@tonic-gate 		} else {
1289*7c478bd9Sstevel@tonic-gate 			spawn(pp, &cmd);
1290*7c478bd9Sstevel@tonic-gate 			while (waitproc(pp) == FAILURE);
1291*7c478bd9Sstevel@tonic-gate 			(void) account(DEAD_PROCESS, pp, NULL);
1292*7c478bd9Sstevel@tonic-gate 			pp->p_flags = 0;
1293*7c478bd9Sstevel@tonic-gate 		}
1294*7c478bd9Sstevel@tonic-gate 	}
1295*7c478bd9Sstevel@tonic-gate 	return (status);
1296*7c478bd9Sstevel@tonic-gate }
1297*7c478bd9Sstevel@tonic-gate 
1298*7c478bd9Sstevel@tonic-gate /*
1299*7c478bd9Sstevel@tonic-gate  * spawn() spawns a shell, inserts the information about the process
1300*7c478bd9Sstevel@tonic-gate  * process into the proc_table, and does the startup accounting.
1301*7c478bd9Sstevel@tonic-gate  */
1302*7c478bd9Sstevel@tonic-gate static void
1303*7c478bd9Sstevel@tonic-gate spawn(struct PROC_TABLE *process, struct CMD_LINE *cmd)
1304*7c478bd9Sstevel@tonic-gate {
1305*7c478bd9Sstevel@tonic-gate 	int		i;
1306*7c478bd9Sstevel@tonic-gate 	int		modes, maxfiles;
1307*7c478bd9Sstevel@tonic-gate 	time_t		now;
1308*7c478bd9Sstevel@tonic-gate 	struct PROC_TABLE tmproc, *oprocess;
1309*7c478bd9Sstevel@tonic-gate 
1310*7c478bd9Sstevel@tonic-gate 	/*
1311*7c478bd9Sstevel@tonic-gate 	 * The modes to be sent to efork() are 0 unless we are
1312*7c478bd9Sstevel@tonic-gate 	 * spawning a LVLa, LVLb, or LVLc entry or we will be
1313*7c478bd9Sstevel@tonic-gate 	 * waiting for the death of the child before continuing.
1314*7c478bd9Sstevel@tonic-gate 	 */
1315*7c478bd9Sstevel@tonic-gate 	modes = NAMED;
1316*7c478bd9Sstevel@tonic-gate 	if (process->p_flags & DEMANDREQUEST || cur_state == LVLa ||
1317*7c478bd9Sstevel@tonic-gate 	    cur_state == LVLb || cur_state == LVLc)
1318*7c478bd9Sstevel@tonic-gate 		modes |= DEMANDREQUEST;
1319*7c478bd9Sstevel@tonic-gate 	if ((cmd->c_action & (M_SYSINIT | M_WAIT | M_BOOTWAIT | M_PWAIT)) != 0)
1320*7c478bd9Sstevel@tonic-gate 		modes |= NOCLEANUP;
1321*7c478bd9Sstevel@tonic-gate 
1322*7c478bd9Sstevel@tonic-gate 	/*
1323*7c478bd9Sstevel@tonic-gate 	 * If this is a respawnable process, check the threshold
1324*7c478bd9Sstevel@tonic-gate 	 * information to avoid excessive respawns.
1325*7c478bd9Sstevel@tonic-gate 	 */
1326*7c478bd9Sstevel@tonic-gate 	if (cmd->c_action & M_RESPAWN) {
1327*7c478bd9Sstevel@tonic-gate 		/*
1328*7c478bd9Sstevel@tonic-gate 		 * Add NOCLEANUP to all respawnable commands so that the
1329*7c478bd9Sstevel@tonic-gate 		 * information about the frequency of respawns isn't lost.
1330*7c478bd9Sstevel@tonic-gate 		 */
1331*7c478bd9Sstevel@tonic-gate 		modes |= NOCLEANUP;
1332*7c478bd9Sstevel@tonic-gate 		(void) time(&now);
1333*7c478bd9Sstevel@tonic-gate 
1334*7c478bd9Sstevel@tonic-gate 		/*
1335*7c478bd9Sstevel@tonic-gate 		 * If no time is assigned, then this is the first time
1336*7c478bd9Sstevel@tonic-gate 		 * this command is being processed in this series.  Assign
1337*7c478bd9Sstevel@tonic-gate 		 * the current time.
1338*7c478bd9Sstevel@tonic-gate 		 */
1339*7c478bd9Sstevel@tonic-gate 		if (process->p_time == 0L)
1340*7c478bd9Sstevel@tonic-gate 			process->p_time = now;
1341*7c478bd9Sstevel@tonic-gate 
1342*7c478bd9Sstevel@tonic-gate 		if (process->p_count++ == SPAWN_LIMIT) {
1343*7c478bd9Sstevel@tonic-gate 
1344*7c478bd9Sstevel@tonic-gate 			if ((now - process->p_time) < SPAWN_INTERVAL) {
1345*7c478bd9Sstevel@tonic-gate 				/*
1346*7c478bd9Sstevel@tonic-gate 				 * Process is respawning too rapidly.  Print
1347*7c478bd9Sstevel@tonic-gate 				 * message and refuse to respawn it for now.
1348*7c478bd9Sstevel@tonic-gate 				 */
1349*7c478bd9Sstevel@tonic-gate 				console(B_TRUE, "Command is respawning too "
1350*7c478bd9Sstevel@tonic-gate 				    "rapidly. Check for possible errors.\n"
1351*7c478bd9Sstevel@tonic-gate 				    "id:%4s \"%s\"\n",
1352*7c478bd9Sstevel@tonic-gate 				    &cmd->c_id[0], &cmd->c_command[EXEC]);
1353*7c478bd9Sstevel@tonic-gate 				return;
1354*7c478bd9Sstevel@tonic-gate 			}
1355*7c478bd9Sstevel@tonic-gate 			process->p_time = now;
1356*7c478bd9Sstevel@tonic-gate 			process->p_count = 0;
1357*7c478bd9Sstevel@tonic-gate 
1358*7c478bd9Sstevel@tonic-gate 		} else if (process->p_count > SPAWN_LIMIT) {
1359*7c478bd9Sstevel@tonic-gate 			/*
1360*7c478bd9Sstevel@tonic-gate 			 * If process has been respawning too rapidly and
1361*7c478bd9Sstevel@tonic-gate 			 * the inhibit time limit hasn't expired yet, we
1362*7c478bd9Sstevel@tonic-gate 			 * refuse to respawn.
1363*7c478bd9Sstevel@tonic-gate 			 */
1364*7c478bd9Sstevel@tonic-gate 			if (now - process->p_time < SPAWN_INTERVAL + INHIBIT)
1365*7c478bd9Sstevel@tonic-gate 				return;
1366*7c478bd9Sstevel@tonic-gate 			process->p_time = now;
1367*7c478bd9Sstevel@tonic-gate 			process->p_count = 0;
1368*7c478bd9Sstevel@tonic-gate 		}
1369*7c478bd9Sstevel@tonic-gate 		rsflag = TRUE;
1370*7c478bd9Sstevel@tonic-gate 	}
1371*7c478bd9Sstevel@tonic-gate 
1372*7c478bd9Sstevel@tonic-gate 	/*
1373*7c478bd9Sstevel@tonic-gate 	 * Spawn a child process to execute this command.
1374*7c478bd9Sstevel@tonic-gate 	 */
1375*7c478bd9Sstevel@tonic-gate 	(void) sigset(SIGCLD, SIG_DFL);
1376*7c478bd9Sstevel@tonic-gate 	oprocess = process;
1377*7c478bd9Sstevel@tonic-gate 	while ((process = efork(cmd->c_action, oprocess, modes)) == NO_ROOM)
1378*7c478bd9Sstevel@tonic-gate 		(void) pause();
1379*7c478bd9Sstevel@tonic-gate 
1380*7c478bd9Sstevel@tonic-gate 	if (process == NULLPROC) {
1381*7c478bd9Sstevel@tonic-gate 
1382*7c478bd9Sstevel@tonic-gate 		/*
1383*7c478bd9Sstevel@tonic-gate 		 * We are the child.  We must make sure we get a different
1384*7c478bd9Sstevel@tonic-gate 		 * file pointer for our references to utmpx.  Otherwise our
1385*7c478bd9Sstevel@tonic-gate 		 * seeks and reads will compete with those of the parent.
1386*7c478bd9Sstevel@tonic-gate 		 */
1387*7c478bd9Sstevel@tonic-gate 		endutxent();
1388*7c478bd9Sstevel@tonic-gate 
1389*7c478bd9Sstevel@tonic-gate 		/*
1390*7c478bd9Sstevel@tonic-gate 		 * Perform the accounting for the beginning of a process.
1391*7c478bd9Sstevel@tonic-gate 		 * Note that all processes are initially "INIT_PROCESS"es.
1392*7c478bd9Sstevel@tonic-gate 		 */
1393*7c478bd9Sstevel@tonic-gate 		tmproc.p_id[0] = cmd->c_id[0];
1394*7c478bd9Sstevel@tonic-gate 		tmproc.p_id[1] = cmd->c_id[1];
1395*7c478bd9Sstevel@tonic-gate 		tmproc.p_id[2] = cmd->c_id[2];
1396*7c478bd9Sstevel@tonic-gate 		tmproc.p_id[3] = cmd->c_id[3];
1397*7c478bd9Sstevel@tonic-gate 		tmproc.p_pid = getpid();
1398*7c478bd9Sstevel@tonic-gate 		tmproc.p_exit = 0;
1399*7c478bd9Sstevel@tonic-gate 		(void) account(INIT_PROCESS, &tmproc,
1400*7c478bd9Sstevel@tonic-gate 		    prog_name(&cmd->c_command[EXEC]));
1401*7c478bd9Sstevel@tonic-gate 		maxfiles = ulimit(UL_GDESLIM, 0);
1402*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < maxfiles; i++)
1403*7c478bd9Sstevel@tonic-gate 			(void) fcntl(i, F_SETFD, FD_CLOEXEC);
1404*7c478bd9Sstevel@tonic-gate 
1405*7c478bd9Sstevel@tonic-gate 		/*
1406*7c478bd9Sstevel@tonic-gate 		 * Now exec a shell with the -c option and the command
1407*7c478bd9Sstevel@tonic-gate 		 * from inittab.
1408*7c478bd9Sstevel@tonic-gate 		 */
1409*7c478bd9Sstevel@tonic-gate 		(void) execle(SH, "INITSH", "-c", cmd->c_command, (char *)0,
1410*7c478bd9Sstevel@tonic-gate 		    glob_envp);
1411*7c478bd9Sstevel@tonic-gate 		console(B_TRUE, "Command\n\"%s\"\n failed to execute.  errno "
1412*7c478bd9Sstevel@tonic-gate 		    "= %d (exec of shell failed)\n", cmd->c_command, errno);
1413*7c478bd9Sstevel@tonic-gate 
1414*7c478bd9Sstevel@tonic-gate 		/*
1415*7c478bd9Sstevel@tonic-gate 		 * Don't come back so quickly that "init" doesn't have a
1416*7c478bd9Sstevel@tonic-gate 		 * chance to finish putting this child in "proc_table".
1417*7c478bd9Sstevel@tonic-gate 		 */
1418*7c478bd9Sstevel@tonic-gate 		timer(20);
1419*7c478bd9Sstevel@tonic-gate 		exit(1);
1420*7c478bd9Sstevel@tonic-gate 
1421*7c478bd9Sstevel@tonic-gate 	}
1422*7c478bd9Sstevel@tonic-gate 
1423*7c478bd9Sstevel@tonic-gate 	/*
1424*7c478bd9Sstevel@tonic-gate 	 * We are the parent.  Insert the necessary
1425*7c478bd9Sstevel@tonic-gate 	 * information in the proc_table.
1426*7c478bd9Sstevel@tonic-gate 	 */
1427*7c478bd9Sstevel@tonic-gate 	process->p_id[0] = cmd->c_id[0];
1428*7c478bd9Sstevel@tonic-gate 	process->p_id[1] = cmd->c_id[1];
1429*7c478bd9Sstevel@tonic-gate 	process->p_id[2] = cmd->c_id[2];
1430*7c478bd9Sstevel@tonic-gate 	process->p_id[3] = cmd->c_id[3];
1431*7c478bd9Sstevel@tonic-gate 
1432*7c478bd9Sstevel@tonic-gate 	st_write();
1433*7c478bd9Sstevel@tonic-gate 
1434*7c478bd9Sstevel@tonic-gate 	(void) sigset(SIGCLD, childeath);
1435*7c478bd9Sstevel@tonic-gate }
1436*7c478bd9Sstevel@tonic-gate 
1437*7c478bd9Sstevel@tonic-gate /*
1438*7c478bd9Sstevel@tonic-gate  * findpslot() finds the old slot in the process table for the
1439*7c478bd9Sstevel@tonic-gate  * command with the same id, or it finds an empty slot.
1440*7c478bd9Sstevel@tonic-gate  */
1441*7c478bd9Sstevel@tonic-gate static struct PROC_TABLE *
1442*7c478bd9Sstevel@tonic-gate findpslot(struct CMD_LINE *cmd)
1443*7c478bd9Sstevel@tonic-gate {
1444*7c478bd9Sstevel@tonic-gate 	struct PROC_TABLE	*process;
1445*7c478bd9Sstevel@tonic-gate 	struct PROC_TABLE	*empty = NULLPROC;
1446*7c478bd9Sstevel@tonic-gate 
1447*7c478bd9Sstevel@tonic-gate 	for (process = proc_table;
1448*7c478bd9Sstevel@tonic-gate 	    (process < proc_table + num_proc); process++) {
1449*7c478bd9Sstevel@tonic-gate 		if (process->p_flags & OCCUPIED &&
1450*7c478bd9Sstevel@tonic-gate 		    id_eq(process->p_id, cmd->c_id))
1451*7c478bd9Sstevel@tonic-gate 			break;
1452*7c478bd9Sstevel@tonic-gate 
1453*7c478bd9Sstevel@tonic-gate 		/*
1454*7c478bd9Sstevel@tonic-gate 		 * If the entry is totally empty and "empty" is still 0,
1455*7c478bd9Sstevel@tonic-gate 		 * remember where this hole is and make sure the slot is
1456*7c478bd9Sstevel@tonic-gate 		 * zeroed out.
1457*7c478bd9Sstevel@tonic-gate 		 */
1458*7c478bd9Sstevel@tonic-gate 		if (empty == NULLPROC && (process->p_flags & OCCUPIED) == 0) {
1459*7c478bd9Sstevel@tonic-gate 			empty = process;
1460*7c478bd9Sstevel@tonic-gate 			process->p_id[0] = '\0';
1461*7c478bd9Sstevel@tonic-gate 			process->p_id[1] = '\0';
1462*7c478bd9Sstevel@tonic-gate 			process->p_id[2] = '\0';
1463*7c478bd9Sstevel@tonic-gate 			process->p_id[3] = '\0';
1464*7c478bd9Sstevel@tonic-gate 			process->p_pid = 0;
1465*7c478bd9Sstevel@tonic-gate 			process->p_time = 0L;
1466*7c478bd9Sstevel@tonic-gate 			process->p_count = 0;
1467*7c478bd9Sstevel@tonic-gate 			process->p_flags = 0;
1468*7c478bd9Sstevel@tonic-gate 			process->p_exit = 0;
1469*7c478bd9Sstevel@tonic-gate 		}
1470*7c478bd9Sstevel@tonic-gate 	}
1471*7c478bd9Sstevel@tonic-gate 
1472*7c478bd9Sstevel@tonic-gate 	/*
1473*7c478bd9Sstevel@tonic-gate 	 * If there is no entry for this slot, then there should be an
1474*7c478bd9Sstevel@tonic-gate 	 * empty slot.  If there is no empty slot, then we've run out
1475*7c478bd9Sstevel@tonic-gate 	 * of proc_table space.  If the latter is true, empty will be
1476*7c478bd9Sstevel@tonic-gate 	 * NULL and the caller will have to complain.
1477*7c478bd9Sstevel@tonic-gate 	 */
1478*7c478bd9Sstevel@tonic-gate 	if (process == (proc_table + num_proc))
1479*7c478bd9Sstevel@tonic-gate 		process = empty;
1480*7c478bd9Sstevel@tonic-gate 
1481*7c478bd9Sstevel@tonic-gate 	return (process);
1482*7c478bd9Sstevel@tonic-gate }
1483*7c478bd9Sstevel@tonic-gate 
1484*7c478bd9Sstevel@tonic-gate /*
1485*7c478bd9Sstevel@tonic-gate  * getcmd() parses lines from inittab.  Each time it finds a command line
1486*7c478bd9Sstevel@tonic-gate  * it will return TRUE as well as fill the passed CMD_LINE structure and
1487*7c478bd9Sstevel@tonic-gate  * the shell command string.  When the end of inittab is reached, FALSE
1488*7c478bd9Sstevel@tonic-gate  * is returned inittab is automatically opened if it is not currently open
1489*7c478bd9Sstevel@tonic-gate  * and is closed when the end of the file is reached.
1490*7c478bd9Sstevel@tonic-gate  */
1491*7c478bd9Sstevel@tonic-gate static FILE *fp_inittab = NULL;
1492*7c478bd9Sstevel@tonic-gate 
1493*7c478bd9Sstevel@tonic-gate static int
1494*7c478bd9Sstevel@tonic-gate getcmd(struct CMD_LINE *cmd, char *shcmd)
1495*7c478bd9Sstevel@tonic-gate {
1496*7c478bd9Sstevel@tonic-gate 	char	*ptr;
1497*7c478bd9Sstevel@tonic-gate 	int	c, lastc, state;
1498*7c478bd9Sstevel@tonic-gate 	char 	*ptr1;
1499*7c478bd9Sstevel@tonic-gate 	int	answer, i, proceed;
1500*7c478bd9Sstevel@tonic-gate 	struct	stat	sbuf;
1501*7c478bd9Sstevel@tonic-gate 	static char *actions[] = {
1502*7c478bd9Sstevel@tonic-gate 		"off", "respawn", "ondemand", "once", "wait", "boot",
1503*7c478bd9Sstevel@tonic-gate 		"bootwait", "powerfail", "powerwait", "initdefault",
1504*7c478bd9Sstevel@tonic-gate 		"sysinit",
1505*7c478bd9Sstevel@tonic-gate 	};
1506*7c478bd9Sstevel@tonic-gate 	static short act_masks[] = {
1507*7c478bd9Sstevel@tonic-gate 		M_OFF, M_RESPAWN, M_ONDEMAND, M_ONCE, M_WAIT, M_BOOT,
1508*7c478bd9Sstevel@tonic-gate 		M_BOOTWAIT, M_PF, M_PWAIT, M_INITDEFAULT, M_SYSINIT,
1509*7c478bd9Sstevel@tonic-gate 	};
1510*7c478bd9Sstevel@tonic-gate 	/*
1511*7c478bd9Sstevel@tonic-gate 	 * Only these actions will be allowed for entries which
1512*7c478bd9Sstevel@tonic-gate 	 * are specified for single-user mode.
1513*7c478bd9Sstevel@tonic-gate 	 */
1514*7c478bd9Sstevel@tonic-gate 	short su_acts = M_INITDEFAULT | M_PF | M_PWAIT | M_WAIT;
1515*7c478bd9Sstevel@tonic-gate 
1516*7c478bd9Sstevel@tonic-gate 	if (fp_inittab == NULL) {
1517*7c478bd9Sstevel@tonic-gate 		/*
1518*7c478bd9Sstevel@tonic-gate 		 * Before attempting to open inittab we stat it to make
1519*7c478bd9Sstevel@tonic-gate 		 * sure it currently exists and is not empty.  We try
1520*7c478bd9Sstevel@tonic-gate 		 * several times because someone may have temporarily
1521*7c478bd9Sstevel@tonic-gate 		 * unlinked or truncated the file.
1522*7c478bd9Sstevel@tonic-gate 		 */
1523*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < 3; i++) {
1524*7c478bd9Sstevel@tonic-gate 			if (stat(INITTAB, &sbuf) == -1) {
1525*7c478bd9Sstevel@tonic-gate 				if (i == 2) {
1526*7c478bd9Sstevel@tonic-gate 					console(B_TRUE,
1527*7c478bd9Sstevel@tonic-gate 					    "Cannot stat %s, errno: %d\n",
1528*7c478bd9Sstevel@tonic-gate 					    INITTAB, errno);
1529*7c478bd9Sstevel@tonic-gate 					return (FAILURE);
1530*7c478bd9Sstevel@tonic-gate 				} else {
1531*7c478bd9Sstevel@tonic-gate 					timer(3);
1532*7c478bd9Sstevel@tonic-gate 				}
1533*7c478bd9Sstevel@tonic-gate 			} else if (sbuf.st_size < 10) {
1534*7c478bd9Sstevel@tonic-gate 				if (i == 2) {
1535*7c478bd9Sstevel@tonic-gate 					console(B_TRUE,
1536*7c478bd9Sstevel@tonic-gate 					    "%s truncated or corrupted\n",
1537*7c478bd9Sstevel@tonic-gate 					    INITTAB);
1538*7c478bd9Sstevel@tonic-gate 					return (FAILURE);
1539*7c478bd9Sstevel@tonic-gate 				} else {
1540*7c478bd9Sstevel@tonic-gate 					timer(3);
1541*7c478bd9Sstevel@tonic-gate 				}
1542*7c478bd9Sstevel@tonic-gate 			} else {
1543*7c478bd9Sstevel@tonic-gate 				break;
1544*7c478bd9Sstevel@tonic-gate 			}
1545*7c478bd9Sstevel@tonic-gate 		}
1546*7c478bd9Sstevel@tonic-gate 
1547*7c478bd9Sstevel@tonic-gate 		/*
1548*7c478bd9Sstevel@tonic-gate 		 * If unable to open inittab, print error message and
1549*7c478bd9Sstevel@tonic-gate 		 * return FAILURE to caller.
1550*7c478bd9Sstevel@tonic-gate 		 */
1551*7c478bd9Sstevel@tonic-gate 		if ((fp_inittab = fopen(INITTAB, "r")) == NULL) {
1552*7c478bd9Sstevel@tonic-gate 			console(B_TRUE, "Cannot open %s errno: %d\n", INITTAB,
1553*7c478bd9Sstevel@tonic-gate 			    errno);
1554*7c478bd9Sstevel@tonic-gate 			return (FAILURE);
1555*7c478bd9Sstevel@tonic-gate 		}
1556*7c478bd9Sstevel@tonic-gate 	}
1557*7c478bd9Sstevel@tonic-gate 
1558*7c478bd9Sstevel@tonic-gate 	/*
1559*7c478bd9Sstevel@tonic-gate 	 * Keep getting commands from inittab until you find a
1560*7c478bd9Sstevel@tonic-gate 	 * good one or run out of file.
1561*7c478bd9Sstevel@tonic-gate 	 */
1562*7c478bd9Sstevel@tonic-gate 	for (answer = FALSE; answer == FALSE; ) {
1563*7c478bd9Sstevel@tonic-gate 		/*
1564*7c478bd9Sstevel@tonic-gate 		 * Zero out the cmd itself before trying next line.
1565*7c478bd9Sstevel@tonic-gate 		 */
1566*7c478bd9Sstevel@tonic-gate 		bzero(cmd, sizeof (struct CMD_LINE));
1567*7c478bd9Sstevel@tonic-gate 
1568*7c478bd9Sstevel@tonic-gate 		/*
1569*7c478bd9Sstevel@tonic-gate 		 * Read in lines of inittab, parsing at colons, until a line is
1570*7c478bd9Sstevel@tonic-gate 		 * read in which doesn't end with a backslash.  Do not start if
1571*7c478bd9Sstevel@tonic-gate 		 * the first character read is an EOF.  Note that this means
1572*7c478bd9Sstevel@tonic-gate 		 * that lines which don't end in a newline are still processed,
1573*7c478bd9Sstevel@tonic-gate 		 * since the "for" will terminate normally once started,
1574*7c478bd9Sstevel@tonic-gate 		 * regardless of whether line terminates with a newline or EOF.
1575*7c478bd9Sstevel@tonic-gate 		 */
1576*7c478bd9Sstevel@tonic-gate 		state = FAILURE;
1577*7c478bd9Sstevel@tonic-gate 		if ((c = fgetc(fp_inittab)) == EOF) {
1578*7c478bd9Sstevel@tonic-gate 			answer = FALSE;
1579*7c478bd9Sstevel@tonic-gate 			(void) fclose(fp_inittab);
1580*7c478bd9Sstevel@tonic-gate 			fp_inittab = NULL;
1581*7c478bd9Sstevel@tonic-gate 			break;
1582*7c478bd9Sstevel@tonic-gate 		}
1583*7c478bd9Sstevel@tonic-gate 
1584*7c478bd9Sstevel@tonic-gate 		for (proceed = TRUE, ptr = shcmd, state = ID, lastc = '\0';
1585*7c478bd9Sstevel@tonic-gate 		    proceed && c != EOF;
1586*7c478bd9Sstevel@tonic-gate 		    lastc = c, c = fgetc(fp_inittab)) {
1587*7c478bd9Sstevel@tonic-gate 		    /* If we're not in the FAILURE state and haven't	*/
1588*7c478bd9Sstevel@tonic-gate 		    /* yet reached the shell command field, process	*/
1589*7c478bd9Sstevel@tonic-gate 		    /* the line, otherwise just look for a real end	*/
1590*7c478bd9Sstevel@tonic-gate 		    /* of line.						*/
1591*7c478bd9Sstevel@tonic-gate 		    if (state != FAILURE && state != COMMAND) {
1592*7c478bd9Sstevel@tonic-gate 			/*
1593*7c478bd9Sstevel@tonic-gate 			 * Squeeze out spaces and tabs.
1594*7c478bd9Sstevel@tonic-gate 			 */
1595*7c478bd9Sstevel@tonic-gate 			if (c == ' ' || c == '\t')
1596*7c478bd9Sstevel@tonic-gate 				continue;
1597*7c478bd9Sstevel@tonic-gate 
1598*7c478bd9Sstevel@tonic-gate 			/*
1599*7c478bd9Sstevel@tonic-gate 			 * Ignore characters in a comment, except for the \n.
1600*7c478bd9Sstevel@tonic-gate 			 */
1601*7c478bd9Sstevel@tonic-gate 			if (state == COMMENT) {
1602*7c478bd9Sstevel@tonic-gate 				if (c == '\n') {
1603*7c478bd9Sstevel@tonic-gate 					lastc = ' ';
1604*7c478bd9Sstevel@tonic-gate 					break;
1605*7c478bd9Sstevel@tonic-gate 				} else {
1606*7c478bd9Sstevel@tonic-gate 					continue;
1607*7c478bd9Sstevel@tonic-gate 				}
1608*7c478bd9Sstevel@tonic-gate 			}
1609*7c478bd9Sstevel@tonic-gate 
1610*7c478bd9Sstevel@tonic-gate 			/*
1611*7c478bd9Sstevel@tonic-gate 			 * Detect comments (lines whose first non-whitespace
1612*7c478bd9Sstevel@tonic-gate 			 * character is '#') by checking that we're at the
1613*7c478bd9Sstevel@tonic-gate 			 * beginning of a line, have seen a '#', and haven't
1614*7c478bd9Sstevel@tonic-gate 			 * yet accumulated any characters.
1615*7c478bd9Sstevel@tonic-gate 			 */
1616*7c478bd9Sstevel@tonic-gate 			if (state == ID && c == '#' && ptr == shcmd) {
1617*7c478bd9Sstevel@tonic-gate 				state = COMMENT;
1618*7c478bd9Sstevel@tonic-gate 				continue;
1619*7c478bd9Sstevel@tonic-gate 			}
1620*7c478bd9Sstevel@tonic-gate 
1621*7c478bd9Sstevel@tonic-gate 			/*
1622*7c478bd9Sstevel@tonic-gate 			 * If the character is a ':', then check the
1623*7c478bd9Sstevel@tonic-gate 			 * previous field for correctness and advance
1624*7c478bd9Sstevel@tonic-gate 			 * to the next field.
1625*7c478bd9Sstevel@tonic-gate 			 */
1626*7c478bd9Sstevel@tonic-gate 			if (c == ':') {
1627*7c478bd9Sstevel@tonic-gate 			    switch (state) {
1628*7c478bd9Sstevel@tonic-gate 
1629*7c478bd9Sstevel@tonic-gate 			    case ID :
1630*7c478bd9Sstevel@tonic-gate 				/*
1631*7c478bd9Sstevel@tonic-gate 				 * Check to see that there are only
1632*7c478bd9Sstevel@tonic-gate 				 * 1 to 4 characters for the id.
1633*7c478bd9Sstevel@tonic-gate 				 */
1634*7c478bd9Sstevel@tonic-gate 				if ((i = ptr - shcmd) < 1 || i > 4) {
1635*7c478bd9Sstevel@tonic-gate 					state = FAILURE;
1636*7c478bd9Sstevel@tonic-gate 				} else {
1637*7c478bd9Sstevel@tonic-gate 					bcopy(shcmd, &cmd->c_id[0], i);
1638*7c478bd9Sstevel@tonic-gate 					ptr = shcmd;
1639*7c478bd9Sstevel@tonic-gate 					state = LEVELS;
1640*7c478bd9Sstevel@tonic-gate 				}
1641*7c478bd9Sstevel@tonic-gate 				break;
1642*7c478bd9Sstevel@tonic-gate 
1643*7c478bd9Sstevel@tonic-gate 			    case LEVELS :
1644*7c478bd9Sstevel@tonic-gate 				/*
1645*7c478bd9Sstevel@tonic-gate 				 * Build a mask for all the levels for
1646*7c478bd9Sstevel@tonic-gate 				 * which this command will be legal.
1647*7c478bd9Sstevel@tonic-gate 				 */
1648*7c478bd9Sstevel@tonic-gate 				for (cmd->c_levels = 0, ptr1 = shcmd;
1649*7c478bd9Sstevel@tonic-gate 				    ptr1 < ptr; ptr1++) {
1650*7c478bd9Sstevel@tonic-gate 					int mask;
1651*7c478bd9Sstevel@tonic-gate 					if (lvlname_to_mask(*ptr1,
1652*7c478bd9Sstevel@tonic-gate 					    &mask) == -1) {
1653*7c478bd9Sstevel@tonic-gate 						state = FAILURE;
1654*7c478bd9Sstevel@tonic-gate 						break;
1655*7c478bd9Sstevel@tonic-gate 					}
1656*7c478bd9Sstevel@tonic-gate 					cmd->c_levels |= mask;
1657*7c478bd9Sstevel@tonic-gate 				}
1658*7c478bd9Sstevel@tonic-gate 				if (state != FAILURE) {
1659*7c478bd9Sstevel@tonic-gate 					state = ACTION;
1660*7c478bd9Sstevel@tonic-gate 					ptr = shcmd;	/* Reset the buffer */
1661*7c478bd9Sstevel@tonic-gate 				}
1662*7c478bd9Sstevel@tonic-gate 				break;
1663*7c478bd9Sstevel@tonic-gate 
1664*7c478bd9Sstevel@tonic-gate 			    case ACTION :
1665*7c478bd9Sstevel@tonic-gate 				/*
1666*7c478bd9Sstevel@tonic-gate 				 * Null terminate the string in shcmd buffer and
1667*7c478bd9Sstevel@tonic-gate 				 * then try to match against legal actions.  If
1668*7c478bd9Sstevel@tonic-gate 				 * the field is of length 0, then the default of
1669*7c478bd9Sstevel@tonic-gate 				 * "RESPAWN" is used if the id is numeric,
1670*7c478bd9Sstevel@tonic-gate 				 * otherwise the default is "OFF".
1671*7c478bd9Sstevel@tonic-gate 				 */
1672*7c478bd9Sstevel@tonic-gate 				if (ptr == shcmd) {
1673*7c478bd9Sstevel@tonic-gate 					if (isdigit(cmd->c_id[0]) &&
1674*7c478bd9Sstevel@tonic-gate 					    (cmd->c_id[1] == '\0' ||
1675*7c478bd9Sstevel@tonic-gate 						isdigit(cmd->c_id[1])) &&
1676*7c478bd9Sstevel@tonic-gate 					    (cmd->c_id[2] == '\0' ||
1677*7c478bd9Sstevel@tonic-gate 						isdigit(cmd->c_id[2])) &&
1678*7c478bd9Sstevel@tonic-gate 					    (cmd->c_id[3] == '\0' ||
1679*7c478bd9Sstevel@tonic-gate 						isdigit(cmd->c_id[3])))
1680*7c478bd9Sstevel@tonic-gate 						    cmd->c_action = M_RESPAWN;
1681*7c478bd9Sstevel@tonic-gate 					else
1682*7c478bd9Sstevel@tonic-gate 						    cmd->c_action = M_OFF;
1683*7c478bd9Sstevel@tonic-gate 				} else {
1684*7c478bd9Sstevel@tonic-gate 				    for (cmd->c_action = 0, i = 0, *ptr = '\0';
1685*7c478bd9Sstevel@tonic-gate 				    i < sizeof (actions)/sizeof (char *);
1686*7c478bd9Sstevel@tonic-gate 				    i++) {
1687*7c478bd9Sstevel@tonic-gate 					if (strcmp(shcmd, actions[i]) == 0) {
1688*7c478bd9Sstevel@tonic-gate 					    if ((cmd->c_levels & MASKSU) &&
1689*7c478bd9Sstevel@tonic-gate 						!(act_masks[i] & su_acts))
1690*7c478bd9Sstevel@tonic-gate 						    cmd->c_action = 0;
1691*7c478bd9Sstevel@tonic-gate 					    else
1692*7c478bd9Sstevel@tonic-gate 						cmd->c_action = act_masks[i];
1693*7c478bd9Sstevel@tonic-gate 					    break;
1694*7c478bd9Sstevel@tonic-gate 					}
1695*7c478bd9Sstevel@tonic-gate 				    }
1696*7c478bd9Sstevel@tonic-gate 				}
1697*7c478bd9Sstevel@tonic-gate 
1698*7c478bd9Sstevel@tonic-gate 				/*
1699*7c478bd9Sstevel@tonic-gate 				 * If the action didn't match any legal action,
1700*7c478bd9Sstevel@tonic-gate 				 * set state to FAILURE.
1701*7c478bd9Sstevel@tonic-gate 				 */
1702*7c478bd9Sstevel@tonic-gate 				if (cmd->c_action == 0) {
1703*7c478bd9Sstevel@tonic-gate 					state = FAILURE;
1704*7c478bd9Sstevel@tonic-gate 				} else {
1705*7c478bd9Sstevel@tonic-gate 					state = COMMAND;
1706*7c478bd9Sstevel@tonic-gate 					(void) strcpy(shcmd, "exec ");
1707*7c478bd9Sstevel@tonic-gate 				}
1708*7c478bd9Sstevel@tonic-gate 				ptr = shcmd + EXEC;
1709*7c478bd9Sstevel@tonic-gate 				break;
1710*7c478bd9Sstevel@tonic-gate 			    }
1711*7c478bd9Sstevel@tonic-gate 			    continue;
1712*7c478bd9Sstevel@tonic-gate 			}
1713*7c478bd9Sstevel@tonic-gate 		    }
1714*7c478bd9Sstevel@tonic-gate 
1715*7c478bd9Sstevel@tonic-gate 		    /* If the character is a '\n', then this is the end of a */
1716*7c478bd9Sstevel@tonic-gate 		    /* line.  If the '\n' wasn't preceded by a backslash, */
1717*7c478bd9Sstevel@tonic-gate 		    /* it is also the end of an inittab command.  If it was */
1718*7c478bd9Sstevel@tonic-gate 		    /* preceded by a backslash then the next line is a */
1719*7c478bd9Sstevel@tonic-gate 		    /* continuation.  Note that the continuation '\n' falls */
1720*7c478bd9Sstevel@tonic-gate 		    /* through and is treated like other characters and is */
1721*7c478bd9Sstevel@tonic-gate 		    /* stored in the shell command line. */
1722*7c478bd9Sstevel@tonic-gate 		    if (c == '\n' && lastc != '\\') {
1723*7c478bd9Sstevel@tonic-gate 				proceed = FALSE;
1724*7c478bd9Sstevel@tonic-gate 				*ptr = '\0';
1725*7c478bd9Sstevel@tonic-gate 				break;
1726*7c478bd9Sstevel@tonic-gate 		    }
1727*7c478bd9Sstevel@tonic-gate 
1728*7c478bd9Sstevel@tonic-gate 		    /* For all other characters just stuff them into the */
1729*7c478bd9Sstevel@tonic-gate 		    /* command as long as there aren't too many of them. */
1730*7c478bd9Sstevel@tonic-gate 		    /* Make sure there is room for a terminating '\0' also. */
1731*7c478bd9Sstevel@tonic-gate 		    if (ptr >= shcmd + MAXCMDL - 1)
1732*7c478bd9Sstevel@tonic-gate 			state = FAILURE;
1733*7c478bd9Sstevel@tonic-gate 		    else
1734*7c478bd9Sstevel@tonic-gate 			*ptr++ = (char)c;
1735*7c478bd9Sstevel@tonic-gate 
1736*7c478bd9Sstevel@tonic-gate 		    /* If the character we just stored was a quoted	*/
1737*7c478bd9Sstevel@tonic-gate 		    /* backslash, then change "c" to '\0', so that this	*/
1738*7c478bd9Sstevel@tonic-gate 		    /* backslash will not cause a subsequent '\n' to appear */
1739*7c478bd9Sstevel@tonic-gate 		    /* quoted.  In otherwords '\' '\' '\n' is the real end */
1740*7c478bd9Sstevel@tonic-gate 		    /* of a command, while '\' '\n' is a continuation. */
1741*7c478bd9Sstevel@tonic-gate 		    if (c == '\\' && lastc == '\\')
1742*7c478bd9Sstevel@tonic-gate 			c = '\0';
1743*7c478bd9Sstevel@tonic-gate 		}
1744*7c478bd9Sstevel@tonic-gate 
1745*7c478bd9Sstevel@tonic-gate 		/*
1746*7c478bd9Sstevel@tonic-gate 		 * Make sure all the fields are properly specified
1747*7c478bd9Sstevel@tonic-gate 		 * for a good command line.
1748*7c478bd9Sstevel@tonic-gate 		 */
1749*7c478bd9Sstevel@tonic-gate 		if (state == COMMAND) {
1750*7c478bd9Sstevel@tonic-gate 			answer = TRUE;
1751*7c478bd9Sstevel@tonic-gate 			cmd->c_command = shcmd;
1752*7c478bd9Sstevel@tonic-gate 
1753*7c478bd9Sstevel@tonic-gate 			/*
1754*7c478bd9Sstevel@tonic-gate 			 * If no default level was supplied, insert
1755*7c478bd9Sstevel@tonic-gate 			 * all numerical levels.
1756*7c478bd9Sstevel@tonic-gate 			 */
1757*7c478bd9Sstevel@tonic-gate 			if (cmd->c_levels == 0)
1758*7c478bd9Sstevel@tonic-gate 				cmd->c_levels = MASK_NUMERIC;
1759*7c478bd9Sstevel@tonic-gate 
1760*7c478bd9Sstevel@tonic-gate 			/*
1761*7c478bd9Sstevel@tonic-gate 			 * If no action has been supplied, declare this
1762*7c478bd9Sstevel@tonic-gate 			 * entry to be OFF.
1763*7c478bd9Sstevel@tonic-gate 			 */
1764*7c478bd9Sstevel@tonic-gate 			if (cmd->c_action == 0)
1765*7c478bd9Sstevel@tonic-gate 				cmd->c_action = M_OFF;
1766*7c478bd9Sstevel@tonic-gate 
1767*7c478bd9Sstevel@tonic-gate 			/*
1768*7c478bd9Sstevel@tonic-gate 			 * If no shell command has been supplied, make sure
1769*7c478bd9Sstevel@tonic-gate 			 * there is a null string in the command field.
1770*7c478bd9Sstevel@tonic-gate 			 */
1771*7c478bd9Sstevel@tonic-gate 			if (ptr == shcmd + EXEC)
1772*7c478bd9Sstevel@tonic-gate 				*shcmd = '\0';
1773*7c478bd9Sstevel@tonic-gate 		} else
1774*7c478bd9Sstevel@tonic-gate 			answer = FALSE;
1775*7c478bd9Sstevel@tonic-gate 
1776*7c478bd9Sstevel@tonic-gate 		/*
1777*7c478bd9Sstevel@tonic-gate 		 * If we have reached the end of inittab, then close it
1778*7c478bd9Sstevel@tonic-gate 		 * and quit trying to find a good command line.
1779*7c478bd9Sstevel@tonic-gate 		 */
1780*7c478bd9Sstevel@tonic-gate 		if (c == EOF) {
1781*7c478bd9Sstevel@tonic-gate 			(void) fclose(fp_inittab);
1782*7c478bd9Sstevel@tonic-gate 			fp_inittab = NULL;
1783*7c478bd9Sstevel@tonic-gate 			break;
1784*7c478bd9Sstevel@tonic-gate 		}
1785*7c478bd9Sstevel@tonic-gate 	}
1786*7c478bd9Sstevel@tonic-gate 	return (answer);
1787*7c478bd9Sstevel@tonic-gate }
1788*7c478bd9Sstevel@tonic-gate 
1789*7c478bd9Sstevel@tonic-gate /*
1790*7c478bd9Sstevel@tonic-gate  * lvlname_to_state(): convert the character name of a state to its level
1791*7c478bd9Sstevel@tonic-gate  * (its corresponding signal number).
1792*7c478bd9Sstevel@tonic-gate  */
1793*7c478bd9Sstevel@tonic-gate static int
1794*7c478bd9Sstevel@tonic-gate lvlname_to_state(char name)
1795*7c478bd9Sstevel@tonic-gate {
1796*7c478bd9Sstevel@tonic-gate 	int i;
1797*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < LVL_NELEMS; i++) {
1798*7c478bd9Sstevel@tonic-gate 		if (lvls[i].lvl_name == name)
1799*7c478bd9Sstevel@tonic-gate 			return (lvls[i].lvl_state);
1800*7c478bd9Sstevel@tonic-gate 	}
1801*7c478bd9Sstevel@tonic-gate 	return (-1);
1802*7c478bd9Sstevel@tonic-gate }
1803*7c478bd9Sstevel@tonic-gate 
1804*7c478bd9Sstevel@tonic-gate /*
1805*7c478bd9Sstevel@tonic-gate  * state_to_name(): convert the level to the character name.
1806*7c478bd9Sstevel@tonic-gate  */
1807*7c478bd9Sstevel@tonic-gate static char
1808*7c478bd9Sstevel@tonic-gate state_to_name(int state)
1809*7c478bd9Sstevel@tonic-gate {
1810*7c478bd9Sstevel@tonic-gate 	int i;
1811*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < LVL_NELEMS; i++) {
1812*7c478bd9Sstevel@tonic-gate 		if (lvls[i].lvl_state == state)
1813*7c478bd9Sstevel@tonic-gate 			return (lvls[i].lvl_name);
1814*7c478bd9Sstevel@tonic-gate 	}
1815*7c478bd9Sstevel@tonic-gate 	return (-1);
1816*7c478bd9Sstevel@tonic-gate }
1817*7c478bd9Sstevel@tonic-gate 
1818*7c478bd9Sstevel@tonic-gate /*
1819*7c478bd9Sstevel@tonic-gate  * state_to_mask(): return the mask corresponding to a signal number
1820*7c478bd9Sstevel@tonic-gate  */
1821*7c478bd9Sstevel@tonic-gate static int
1822*7c478bd9Sstevel@tonic-gate state_to_mask(int state)
1823*7c478bd9Sstevel@tonic-gate {
1824*7c478bd9Sstevel@tonic-gate 	int i;
1825*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < LVL_NELEMS; i++) {
1826*7c478bd9Sstevel@tonic-gate 		if (lvls[i].lvl_state == state)
1827*7c478bd9Sstevel@tonic-gate 			return (lvls[i].lvl_mask);
1828*7c478bd9Sstevel@tonic-gate 	}
1829*7c478bd9Sstevel@tonic-gate 	return (0);	/* return 0, since that represents an empty mask */
1830*7c478bd9Sstevel@tonic-gate }
1831*7c478bd9Sstevel@tonic-gate 
1832*7c478bd9Sstevel@tonic-gate /*
1833*7c478bd9Sstevel@tonic-gate  * lvlname_to_mask(): return the mask corresponding to a levels character name
1834*7c478bd9Sstevel@tonic-gate  */
1835*7c478bd9Sstevel@tonic-gate static int
1836*7c478bd9Sstevel@tonic-gate lvlname_to_mask(char name, int *mask)
1837*7c478bd9Sstevel@tonic-gate {
1838*7c478bd9Sstevel@tonic-gate 	int i;
1839*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < LVL_NELEMS; i++) {
1840*7c478bd9Sstevel@tonic-gate 		if (lvls[i].lvl_name == name) {
1841*7c478bd9Sstevel@tonic-gate 			*mask = lvls[i].lvl_mask;
1842*7c478bd9Sstevel@tonic-gate 			return (0);
1843*7c478bd9Sstevel@tonic-gate 		}
1844*7c478bd9Sstevel@tonic-gate 	}
1845*7c478bd9Sstevel@tonic-gate 	return (-1);
1846*7c478bd9Sstevel@tonic-gate }
1847*7c478bd9Sstevel@tonic-gate 
1848*7c478bd9Sstevel@tonic-gate /*
1849*7c478bd9Sstevel@tonic-gate  * state_to_flags(): return the flags corresponding to a runlevel.  These
1850*7c478bd9Sstevel@tonic-gate  * indicate properties of that runlevel.
1851*7c478bd9Sstevel@tonic-gate  */
1852*7c478bd9Sstevel@tonic-gate static int
1853*7c478bd9Sstevel@tonic-gate state_to_flags(int state)
1854*7c478bd9Sstevel@tonic-gate {
1855*7c478bd9Sstevel@tonic-gate 	int i;
1856*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < LVL_NELEMS; i++) {
1857*7c478bd9Sstevel@tonic-gate 		if (lvls[i].lvl_state == state)
1858*7c478bd9Sstevel@tonic-gate 			return (lvls[i].lvl_flags);
1859*7c478bd9Sstevel@tonic-gate 	}
1860*7c478bd9Sstevel@tonic-gate 	return (0);
1861*7c478bd9Sstevel@tonic-gate }
1862*7c478bd9Sstevel@tonic-gate 
1863*7c478bd9Sstevel@tonic-gate /*
1864*7c478bd9Sstevel@tonic-gate  * killproc() creates a child which kills the process specified by pid.
1865*7c478bd9Sstevel@tonic-gate  */
1866*7c478bd9Sstevel@tonic-gate void
1867*7c478bd9Sstevel@tonic-gate killproc(pid_t pid)
1868*7c478bd9Sstevel@tonic-gate {
1869*7c478bd9Sstevel@tonic-gate 	struct PROC_TABLE	*process;
1870*7c478bd9Sstevel@tonic-gate 
1871*7c478bd9Sstevel@tonic-gate 	(void) sigset(SIGCLD, SIG_DFL);
1872*7c478bd9Sstevel@tonic-gate 	while ((process = efork(M_OFF, NULLPROC, 0)) == NO_ROOM)
1873*7c478bd9Sstevel@tonic-gate 		(void) pause();
1874*7c478bd9Sstevel@tonic-gate 	(void) sigset(SIGCLD, childeath);
1875*7c478bd9Sstevel@tonic-gate 
1876*7c478bd9Sstevel@tonic-gate 	if (process == NULLPROC) {
1877*7c478bd9Sstevel@tonic-gate 		/*
1878*7c478bd9Sstevel@tonic-gate 		 * efork() sets all signal handlers to the default, so reset
1879*7c478bd9Sstevel@tonic-gate 		 * the ALRM handler to make timer() work as expected.
1880*7c478bd9Sstevel@tonic-gate 		 */
1881*7c478bd9Sstevel@tonic-gate 		(void) sigset(SIGALRM, alarmclk);
1882*7c478bd9Sstevel@tonic-gate 
1883*7c478bd9Sstevel@tonic-gate 		/*
1884*7c478bd9Sstevel@tonic-gate 		 * We are the child.  Try to terminate the process nicely
1885*7c478bd9Sstevel@tonic-gate 		 * first using SIGTERM and if it refuses to die in TWARN
1886*7c478bd9Sstevel@tonic-gate 		 * seconds kill it with SIGKILL.
1887*7c478bd9Sstevel@tonic-gate 		 */
1888*7c478bd9Sstevel@tonic-gate 		(void) kill(pid, SIGTERM);
1889*7c478bd9Sstevel@tonic-gate 		(void) timer(TWARN);
1890*7c478bd9Sstevel@tonic-gate 		(void) kill(pid, SIGKILL);
1891*7c478bd9Sstevel@tonic-gate 		(void) exit(0);
1892*7c478bd9Sstevel@tonic-gate 	}
1893*7c478bd9Sstevel@tonic-gate }
1894*7c478bd9Sstevel@tonic-gate 
1895*7c478bd9Sstevel@tonic-gate /*
1896*7c478bd9Sstevel@tonic-gate  * Set up the default environment for all procs to be forked from init.
1897*7c478bd9Sstevel@tonic-gate  * Read the values from the /etc/default/init file, except for PATH.  If
1898*7c478bd9Sstevel@tonic-gate  * there's not enough room in the environment array, the environment
1899*7c478bd9Sstevel@tonic-gate  * lines that don't fit are silently discarded.
1900*7c478bd9Sstevel@tonic-gate  */
1901*7c478bd9Sstevel@tonic-gate void
1902*7c478bd9Sstevel@tonic-gate init_env()
1903*7c478bd9Sstevel@tonic-gate {
1904*7c478bd9Sstevel@tonic-gate 	char	line[MAXCMDL];
1905*7c478bd9Sstevel@tonic-gate 	FILE	*fp;
1906*7c478bd9Sstevel@tonic-gate 	int	inquotes, length, wslength;
1907*7c478bd9Sstevel@tonic-gate 	char	*tokp, *cp1, *cp2;
1908*7c478bd9Sstevel@tonic-gate 
1909*7c478bd9Sstevel@tonic-gate 	glob_envp[0] = malloc((unsigned)(strlen(DEF_PATH)+2));
1910*7c478bd9Sstevel@tonic-gate 	(void) strcpy(glob_envp[0], DEF_PATH);
1911*7c478bd9Sstevel@tonic-gate 	glob_envn = 1;
1912*7c478bd9Sstevel@tonic-gate 
1913*7c478bd9Sstevel@tonic-gate 	if (rflg) {
1914*7c478bd9Sstevel@tonic-gate 		glob_envp[1] =
1915*7c478bd9Sstevel@tonic-gate 			malloc((unsigned)(strlen("_DVFS_RECONFIG=YES")+2));
1916*7c478bd9Sstevel@tonic-gate 		(void) strcpy(glob_envp[1], "_DVFS_RECONFIG=YES");
1917*7c478bd9Sstevel@tonic-gate 		++glob_envn;
1918*7c478bd9Sstevel@tonic-gate 	} else if (bflg == 1) {
1919*7c478bd9Sstevel@tonic-gate 		glob_envp[1] =
1920*7c478bd9Sstevel@tonic-gate 			malloc((unsigned)(strlen("RB_NOBOOTRC=YES")+2));
1921*7c478bd9Sstevel@tonic-gate 		(void) strcpy(glob_envp[1], "RB_NOBOOTRC=YES");
1922*7c478bd9Sstevel@tonic-gate 		++glob_envn;
1923*7c478bd9Sstevel@tonic-gate 	}
1924*7c478bd9Sstevel@tonic-gate 
1925*7c478bd9Sstevel@tonic-gate 	if ((fp = fopen(ENVFILE, "r")) == NULL) {
1926*7c478bd9Sstevel@tonic-gate 		console(B_TRUE,
1927*7c478bd9Sstevel@tonic-gate 		    "Cannot open %s. Environment not initialized.\n",
1928*7c478bd9Sstevel@tonic-gate 		    ENVFILE);
1929*7c478bd9Sstevel@tonic-gate 	} else {
1930*7c478bd9Sstevel@tonic-gate 		while (fgets(line, MAXCMDL - 1, fp) != NULL &&
1931*7c478bd9Sstevel@tonic-gate 		    glob_envn < MAXENVENT - 2) {
1932*7c478bd9Sstevel@tonic-gate 			/*
1933*7c478bd9Sstevel@tonic-gate 			 * Toss newline
1934*7c478bd9Sstevel@tonic-gate 			 */
1935*7c478bd9Sstevel@tonic-gate 			length = strlen(line);
1936*7c478bd9Sstevel@tonic-gate 			if (line[length - 1] == '\n')
1937*7c478bd9Sstevel@tonic-gate 				line[length - 1] = '\0';
1938*7c478bd9Sstevel@tonic-gate 
1939*7c478bd9Sstevel@tonic-gate 			/*
1940*7c478bd9Sstevel@tonic-gate 			 * Ignore blank or comment lines.
1941*7c478bd9Sstevel@tonic-gate 			 */
1942*7c478bd9Sstevel@tonic-gate 			if (line[0] == '#' || line[0] == '\0' ||
1943*7c478bd9Sstevel@tonic-gate 			    (wslength = strspn(line, " \t\n")) ==
1944*7c478bd9Sstevel@tonic-gate 			    strlen(line) ||
1945*7c478bd9Sstevel@tonic-gate 			    strchr(line, '#') == line + wslength)
1946*7c478bd9Sstevel@tonic-gate 				continue;
1947*7c478bd9Sstevel@tonic-gate 
1948*7c478bd9Sstevel@tonic-gate 			/*
1949*7c478bd9Sstevel@tonic-gate 			 * First make a pass through the line and change
1950*7c478bd9Sstevel@tonic-gate 			 * any non-quoted semi-colons to blanks so they
1951*7c478bd9Sstevel@tonic-gate 			 * will be treated as token separators below.
1952*7c478bd9Sstevel@tonic-gate 			 */
1953*7c478bd9Sstevel@tonic-gate 			inquotes = 0;
1954*7c478bd9Sstevel@tonic-gate 			for (cp1 = line; *cp1 != '\0'; cp1++) {
1955*7c478bd9Sstevel@tonic-gate 				if (*cp1 == '"') {
1956*7c478bd9Sstevel@tonic-gate 					if (inquotes == 0)
1957*7c478bd9Sstevel@tonic-gate 						inquotes = 1;
1958*7c478bd9Sstevel@tonic-gate 					else
1959*7c478bd9Sstevel@tonic-gate 						inquotes = 0;
1960*7c478bd9Sstevel@tonic-gate 				} else if (*cp1 == ';') {
1961*7c478bd9Sstevel@tonic-gate 					if (inquotes == 0)
1962*7c478bd9Sstevel@tonic-gate 						*cp1 = ' ';
1963*7c478bd9Sstevel@tonic-gate 				}
1964*7c478bd9Sstevel@tonic-gate 			}
1965*7c478bd9Sstevel@tonic-gate 
1966*7c478bd9Sstevel@tonic-gate 			/*
1967*7c478bd9Sstevel@tonic-gate 			 * Tokens within the line are separated by blanks
1968*7c478bd9Sstevel@tonic-gate 			 *  and tabs.  For each token in the line which
1969*7c478bd9Sstevel@tonic-gate 			 * contains a '=' we strip out any quotes and then
1970*7c478bd9Sstevel@tonic-gate 			 * stick the token in the environment array.
1971*7c478bd9Sstevel@tonic-gate 			 */
1972*7c478bd9Sstevel@tonic-gate 			if ((tokp = strtok(line, " \t")) == NULL)
1973*7c478bd9Sstevel@tonic-gate 				continue;
1974*7c478bd9Sstevel@tonic-gate 			do {
1975*7c478bd9Sstevel@tonic-gate 				if (strchr(tokp, '=') == NULL)
1976*7c478bd9Sstevel@tonic-gate 					continue;
1977*7c478bd9Sstevel@tonic-gate 				length = strlen(tokp);
1978*7c478bd9Sstevel@tonic-gate 				while ((cp1 = strpbrk(tokp, "\"\'")) != NULL) {
1979*7c478bd9Sstevel@tonic-gate 					for (cp2 = cp1;
1980*7c478bd9Sstevel@tonic-gate 					    cp2 < &tokp[length]; cp2++)
1981*7c478bd9Sstevel@tonic-gate 						*cp2 = *(cp2 + 1);
1982*7c478bd9Sstevel@tonic-gate 					length--;
1983*7c478bd9Sstevel@tonic-gate 				}
1984*7c478bd9Sstevel@tonic-gate 
1985*7c478bd9Sstevel@tonic-gate 				if (strncmp(tokp, "CMASK=",
1986*7c478bd9Sstevel@tonic-gate 				    sizeof ("CMASK=") - 1) == 0) {
1987*7c478bd9Sstevel@tonic-gate 					long t;
1988*7c478bd9Sstevel@tonic-gate 
1989*7c478bd9Sstevel@tonic-gate 					/* We know there's an = */
1990*7c478bd9Sstevel@tonic-gate 					t = strtol(strchr(tokp, '=') + 1, NULL,
1991*7c478bd9Sstevel@tonic-gate 					    8);
1992*7c478bd9Sstevel@tonic-gate 
1993*7c478bd9Sstevel@tonic-gate 					/* Sanity */
1994*7c478bd9Sstevel@tonic-gate 					if (t <= 077 && t >= 0)
1995*7c478bd9Sstevel@tonic-gate 						cmask = (int)t;
1996*7c478bd9Sstevel@tonic-gate 					(void) umask(cmask);
1997*7c478bd9Sstevel@tonic-gate 					continue;
1998*7c478bd9Sstevel@tonic-gate 				}
1999*7c478bd9Sstevel@tonic-gate 				glob_envp[glob_envn] =
2000*7c478bd9Sstevel@tonic-gate 				    malloc((unsigned)(length + 1));
2001*7c478bd9Sstevel@tonic-gate 				(void) strcpy(glob_envp[glob_envn], tokp);
2002*7c478bd9Sstevel@tonic-gate 				if (++glob_envn >= MAXENVENT - 1)
2003*7c478bd9Sstevel@tonic-gate 					break;
2004*7c478bd9Sstevel@tonic-gate 			} while ((tokp = strtok(NULL, " \t")) != NULL);
2005*7c478bd9Sstevel@tonic-gate 		}
2006*7c478bd9Sstevel@tonic-gate 
2007*7c478bd9Sstevel@tonic-gate 		/*
2008*7c478bd9Sstevel@tonic-gate 		 * Append a null pointer to the environment array
2009*7c478bd9Sstevel@tonic-gate 		 * to mark its end.
2010*7c478bd9Sstevel@tonic-gate 		 */
2011*7c478bd9Sstevel@tonic-gate 		glob_envp[glob_envn] = NULL;
2012*7c478bd9Sstevel@tonic-gate 		(void) fclose(fp);
2013*7c478bd9Sstevel@tonic-gate 	}
2014*7c478bd9Sstevel@tonic-gate }
2015*7c478bd9Sstevel@tonic-gate 
2016*7c478bd9Sstevel@tonic-gate /*
2017*7c478bd9Sstevel@tonic-gate  * boot_init(): Do initialization things that should be done at boot.
2018*7c478bd9Sstevel@tonic-gate  */
2019*7c478bd9Sstevel@tonic-gate void
2020*7c478bd9Sstevel@tonic-gate boot_init()
2021*7c478bd9Sstevel@tonic-gate {
2022*7c478bd9Sstevel@tonic-gate 	int i;
2023*7c478bd9Sstevel@tonic-gate 	struct PROC_TABLE *process, *oprocess;
2024*7c478bd9Sstevel@tonic-gate 	struct CMD_LINE	cmd;
2025*7c478bd9Sstevel@tonic-gate 	char	line[MAXCMDL];
2026*7c478bd9Sstevel@tonic-gate 	char *old_path;
2027*7c478bd9Sstevel@tonic-gate 	int maxfiles;
2028*7c478bd9Sstevel@tonic-gate 
2029*7c478bd9Sstevel@tonic-gate 	/* Use INIT_PATH for sysinit cmds */
2030*7c478bd9Sstevel@tonic-gate 	old_path = glob_envp[0];
2031*7c478bd9Sstevel@tonic-gate 	glob_envp[0] = malloc((unsigned)(strlen(INIT_PATH)+2));
2032*7c478bd9Sstevel@tonic-gate 	(void) strcpy(glob_envp[0], INIT_PATH);
2033*7c478bd9Sstevel@tonic-gate 
2034*7c478bd9Sstevel@tonic-gate 	/*
2035*7c478bd9Sstevel@tonic-gate 	 * Scan inittab(4) and process the special svc.startd entry, initdefault
2036*7c478bd9Sstevel@tonic-gate 	 * and sysinit entries.
2037*7c478bd9Sstevel@tonic-gate 	 */
2038*7c478bd9Sstevel@tonic-gate 	while (getcmd(&cmd, &line[0]) == TRUE) {
2039*7c478bd9Sstevel@tonic-gate 		if (startd_tmpl >= 0 && id_eq(cmd.c_id, "smf"))
2040*7c478bd9Sstevel@tonic-gate 			process_startd_line(&cmd, line);
2041*7c478bd9Sstevel@tonic-gate 		else if (cmd.c_action == M_INITDEFAULT) {
2042*7c478bd9Sstevel@tonic-gate 			/*
2043*7c478bd9Sstevel@tonic-gate 			 * initdefault is no longer meaningful, as the SMF
2044*7c478bd9Sstevel@tonic-gate 			 * milestone controls what (legacy) run level we
2045*7c478bd9Sstevel@tonic-gate 			 * boot to.
2046*7c478bd9Sstevel@tonic-gate 			 */
2047*7c478bd9Sstevel@tonic-gate 			console(B_TRUE,
2048*7c478bd9Sstevel@tonic-gate 			    "Ignoring legacy \"initdefault\" entry.\n");
2049*7c478bd9Sstevel@tonic-gate 		} else if (cmd.c_action == M_SYSINIT) {
2050*7c478bd9Sstevel@tonic-gate 			/*
2051*7c478bd9Sstevel@tonic-gate 			 * Execute the "sysinit" entry and wait for it to
2052*7c478bd9Sstevel@tonic-gate 			 * complete.  No bookkeeping is performed on these
2053*7c478bd9Sstevel@tonic-gate 			 * entries because we avoid writing to the file system
2054*7c478bd9Sstevel@tonic-gate 			 * until after there has been an chance to check it.
2055*7c478bd9Sstevel@tonic-gate 			 */
2056*7c478bd9Sstevel@tonic-gate 			if (process = findpslot(&cmd)) {
2057*7c478bd9Sstevel@tonic-gate 				(void) sigset(SIGCLD, SIG_DFL);
2058*7c478bd9Sstevel@tonic-gate 
2059*7c478bd9Sstevel@tonic-gate 				for (oprocess = process;
2060*7c478bd9Sstevel@tonic-gate 				    (process = efork(M_OFF, oprocess,
2061*7c478bd9Sstevel@tonic-gate 				    (NAMED|NOCLEANUP))) == NO_ROOM;
2062*7c478bd9Sstevel@tonic-gate 				    /* CSTYLED */)
2063*7c478bd9Sstevel@tonic-gate 					;
2064*7c478bd9Sstevel@tonic-gate 				(void) sigset(SIGCLD, childeath);
2065*7c478bd9Sstevel@tonic-gate 
2066*7c478bd9Sstevel@tonic-gate 				if (process == NULLPROC) {
2067*7c478bd9Sstevel@tonic-gate 					maxfiles = ulimit(UL_GDESLIM, 0);
2068*7c478bd9Sstevel@tonic-gate 
2069*7c478bd9Sstevel@tonic-gate 					for (i = 0; i < maxfiles; i++)
2070*7c478bd9Sstevel@tonic-gate 						(void) fcntl(i, F_SETFD,
2071*7c478bd9Sstevel@tonic-gate 						    FD_CLOEXEC);
2072*7c478bd9Sstevel@tonic-gate 					(void) execle(SH, "INITSH", "-c",
2073*7c478bd9Sstevel@tonic-gate 					    cmd.c_command,
2074*7c478bd9Sstevel@tonic-gate 					    (char *)0, glob_envp);
2075*7c478bd9Sstevel@tonic-gate 					console(B_TRUE,
2076*7c478bd9Sstevel@tonic-gate "Command\n\"%s\"\n failed to execute.  errno = %d (exec of shell failed)\n",
2077*7c478bd9Sstevel@tonic-gate 						cmd.c_command, errno);
2078*7c478bd9Sstevel@tonic-gate 					exit(1);
2079*7c478bd9Sstevel@tonic-gate 				} else while (waitproc(process) == FAILURE);
2080*7c478bd9Sstevel@tonic-gate 				process->p_flags = 0;
2081*7c478bd9Sstevel@tonic-gate 				st_write();
2082*7c478bd9Sstevel@tonic-gate 			}
2083*7c478bd9Sstevel@tonic-gate 		}
2084*7c478bd9Sstevel@tonic-gate 	}
2085*7c478bd9Sstevel@tonic-gate 
2086*7c478bd9Sstevel@tonic-gate 	/* Restore the path. */
2087*7c478bd9Sstevel@tonic-gate 	free(glob_envp[0]);
2088*7c478bd9Sstevel@tonic-gate 	glob_envp[0] = old_path;
2089*7c478bd9Sstevel@tonic-gate 
2090*7c478bd9Sstevel@tonic-gate 	/*
2091*7c478bd9Sstevel@tonic-gate 	 * This will enable st_write() to complain about init_state_file.
2092*7c478bd9Sstevel@tonic-gate 	 */
2093*7c478bd9Sstevel@tonic-gate 	booting = 0;
2094*7c478bd9Sstevel@tonic-gate 
2095*7c478bd9Sstevel@tonic-gate 	/*
2096*7c478bd9Sstevel@tonic-gate 	 * If the /etc/ioctl.syscon didn't exist or had invalid contents write
2097*7c478bd9Sstevel@tonic-gate 	 * out a correct version.
2098*7c478bd9Sstevel@tonic-gate 	 */
2099*7c478bd9Sstevel@tonic-gate 	if (write_ioctl)
2100*7c478bd9Sstevel@tonic-gate 		write_ioctl_syscon();
2101*7c478bd9Sstevel@tonic-gate 
2102*7c478bd9Sstevel@tonic-gate 	/*
2103*7c478bd9Sstevel@tonic-gate 	 * Start svc.startd(1M), which does most of the work.
2104*7c478bd9Sstevel@tonic-gate 	 */
2105*7c478bd9Sstevel@tonic-gate 	if (startd_cline[0] != '\0' && startd_tmpl >= 0) {
2106*7c478bd9Sstevel@tonic-gate 		/* Start svc.startd. */
2107*7c478bd9Sstevel@tonic-gate 		if (startd_run(startd_cline, startd_tmpl, 0) == -1)
2108*7c478bd9Sstevel@tonic-gate 			cur_state = SINGLE_USER;
2109*7c478bd9Sstevel@tonic-gate 	} else {
2110*7c478bd9Sstevel@tonic-gate 		console(B_TRUE, "Absent svc.startd entry or bad "
2111*7c478bd9Sstevel@tonic-gate 		    "contract template.  Not starting svc.startd.\n");
2112*7c478bd9Sstevel@tonic-gate 		enter_maintenance();
2113*7c478bd9Sstevel@tonic-gate 	}
2114*7c478bd9Sstevel@tonic-gate }
2115*7c478bd9Sstevel@tonic-gate 
2116*7c478bd9Sstevel@tonic-gate /*
2117*7c478bd9Sstevel@tonic-gate  * init_signals(): Initialize all signals to either be caught or ignored.
2118*7c478bd9Sstevel@tonic-gate  */
2119*7c478bd9Sstevel@tonic-gate void
2120*7c478bd9Sstevel@tonic-gate init_signals(void)
2121*7c478bd9Sstevel@tonic-gate {
2122*7c478bd9Sstevel@tonic-gate 	struct sigaction act;
2123*7c478bd9Sstevel@tonic-gate 	int i;
2124*7c478bd9Sstevel@tonic-gate 
2125*7c478bd9Sstevel@tonic-gate 	/*
2126*7c478bd9Sstevel@tonic-gate 	 * Start by ignoring all signals, then selectively re-enable some.
2127*7c478bd9Sstevel@tonic-gate 	 * The SIG_IGN disposition will only affect asynchronous signals:
2128*7c478bd9Sstevel@tonic-gate 	 * any signal that we trigger synchronously that doesn't end up
2129*7c478bd9Sstevel@tonic-gate 	 * being handled by siglvl() will be forcibly delivered by the kernel.
2130*7c478bd9Sstevel@tonic-gate 	 */
2131*7c478bd9Sstevel@tonic-gate 	for (i = SIGHUP; i <= SIGRTMAX; i++)
2132*7c478bd9Sstevel@tonic-gate 		(void) sigset(i, SIG_IGN);
2133*7c478bd9Sstevel@tonic-gate 
2134*7c478bd9Sstevel@tonic-gate 	/*
2135*7c478bd9Sstevel@tonic-gate 	 * Handle all level-changing signals using siglvl() and set sa_mask so
2136*7c478bd9Sstevel@tonic-gate 	 * that all level-changing signals are blocked while in siglvl().
2137*7c478bd9Sstevel@tonic-gate 	 */
2138*7c478bd9Sstevel@tonic-gate 	act.sa_handler = siglvl;
2139*7c478bd9Sstevel@tonic-gate 	act.sa_flags = SA_SIGINFO;
2140*7c478bd9Sstevel@tonic-gate 	(void) sigemptyset(&act.sa_mask);
2141*7c478bd9Sstevel@tonic-gate 
2142*7c478bd9Sstevel@tonic-gate 	(void) sigaddset(&act.sa_mask, LVLQ);
2143*7c478bd9Sstevel@tonic-gate 	(void) sigaddset(&act.sa_mask, LVL0);
2144*7c478bd9Sstevel@tonic-gate 	(void) sigaddset(&act.sa_mask, LVL1);
2145*7c478bd9Sstevel@tonic-gate 	(void) sigaddset(&act.sa_mask, LVL2);
2146*7c478bd9Sstevel@tonic-gate 	(void) sigaddset(&act.sa_mask, LVL3);
2147*7c478bd9Sstevel@tonic-gate 	(void) sigaddset(&act.sa_mask, LVL4);
2148*7c478bd9Sstevel@tonic-gate 	(void) sigaddset(&act.sa_mask, LVL5);
2149*7c478bd9Sstevel@tonic-gate 	(void) sigaddset(&act.sa_mask, LVL6);
2150*7c478bd9Sstevel@tonic-gate 	(void) sigaddset(&act.sa_mask, SINGLE_USER);
2151*7c478bd9Sstevel@tonic-gate 	(void) sigaddset(&act.sa_mask, LVLa);
2152*7c478bd9Sstevel@tonic-gate 	(void) sigaddset(&act.sa_mask, LVLb);
2153*7c478bd9Sstevel@tonic-gate 	(void) sigaddset(&act.sa_mask, LVLc);
2154*7c478bd9Sstevel@tonic-gate 
2155*7c478bd9Sstevel@tonic-gate 	(void) sigaction(LVLQ, &act, NULL);
2156*7c478bd9Sstevel@tonic-gate 	(void) sigaction(LVL0, &act, NULL);
2157*7c478bd9Sstevel@tonic-gate 	(void) sigaction(LVL1, &act, NULL);
2158*7c478bd9Sstevel@tonic-gate 	(void) sigaction(LVL2, &act, NULL);
2159*7c478bd9Sstevel@tonic-gate 	(void) sigaction(LVL3, &act, NULL);
2160*7c478bd9Sstevel@tonic-gate 	(void) sigaction(LVL4, &act, NULL);
2161*7c478bd9Sstevel@tonic-gate 	(void) sigaction(LVL5, &act, NULL);
2162*7c478bd9Sstevel@tonic-gate 	(void) sigaction(LVL6, &act, NULL);
2163*7c478bd9Sstevel@tonic-gate 	(void) sigaction(SINGLE_USER, &act, NULL);
2164*7c478bd9Sstevel@tonic-gate 	(void) sigaction(LVLa, &act, NULL);
2165*7c478bd9Sstevel@tonic-gate 	(void) sigaction(LVLb, &act, NULL);
2166*7c478bd9Sstevel@tonic-gate 	(void) sigaction(LVLc, &act, NULL);
2167*7c478bd9Sstevel@tonic-gate 
2168*7c478bd9Sstevel@tonic-gate 	(void) sigset(SIGALRM, alarmclk);
2169*7c478bd9Sstevel@tonic-gate 	alarmclk();
2170*7c478bd9Sstevel@tonic-gate 
2171*7c478bd9Sstevel@tonic-gate 	(void) sigset(SIGCLD, childeath);
2172*7c478bd9Sstevel@tonic-gate 	(void) sigset(SIGPWR, powerfail);
2173*7c478bd9Sstevel@tonic-gate }
2174*7c478bd9Sstevel@tonic-gate 
2175*7c478bd9Sstevel@tonic-gate /*
2176*7c478bd9Sstevel@tonic-gate  * Set up pipe for "godchildren". If the file exists and is a pipe just open
2177*7c478bd9Sstevel@tonic-gate  * it. Else, if the file system is r/w create it.  Otherwise, defer its
2178*7c478bd9Sstevel@tonic-gate  * creation and open until after the sysinit functions have had a chance to
2179*7c478bd9Sstevel@tonic-gate  * make the root read/write.
2180*7c478bd9Sstevel@tonic-gate  */
2181*7c478bd9Sstevel@tonic-gate void
2182*7c478bd9Sstevel@tonic-gate setup_pipe()
2183*7c478bd9Sstevel@tonic-gate {
2184*7c478bd9Sstevel@tonic-gate 	struct stat stat_buf;
2185*7c478bd9Sstevel@tonic-gate 	struct statvfs statvfs_buf;
2186*7c478bd9Sstevel@tonic-gate 
2187*7c478bd9Sstevel@tonic-gate 	if ((stat(INITPIPE, &stat_buf) == 0) &&
2188*7c478bd9Sstevel@tonic-gate 	    ((stat_buf.st_mode & (S_IFMT|S_IRUSR)) == (S_IFIFO|S_IRUSR)))
2189*7c478bd9Sstevel@tonic-gate 		Pfd = open(INITPIPE, O_RDWR | O_NDELAY);
2190*7c478bd9Sstevel@tonic-gate 	else
2191*7c478bd9Sstevel@tonic-gate 		if ((statvfs(INITPIPE_DIR, &statvfs_buf) == 0) &&
2192*7c478bd9Sstevel@tonic-gate 		    ((statvfs_buf.f_flag & ST_RDONLY) == 0)) {
2193*7c478bd9Sstevel@tonic-gate 			(void) unlink(INITPIPE);
2194*7c478bd9Sstevel@tonic-gate 			(void) mknod(INITPIPE, S_IFIFO | 0600, 0);
2195*7c478bd9Sstevel@tonic-gate 			Pfd = open(INITPIPE, O_RDWR | O_NDELAY);
2196*7c478bd9Sstevel@tonic-gate 		}
2197*7c478bd9Sstevel@tonic-gate 
2198*7c478bd9Sstevel@tonic-gate 	if (Pfd >= 0) {
2199*7c478bd9Sstevel@tonic-gate 		(void) ioctl(Pfd, I_SETSIG, S_INPUT);
2200*7c478bd9Sstevel@tonic-gate 		/*
2201*7c478bd9Sstevel@tonic-gate 		 * Read pipe in message discard mode.
2202*7c478bd9Sstevel@tonic-gate 		 */
2203*7c478bd9Sstevel@tonic-gate 		(void) ioctl(Pfd, I_SRDOPT, RMSGD);
2204*7c478bd9Sstevel@tonic-gate 		(void) sigset(SIGPOLL, sigpoll);
2205*7c478bd9Sstevel@tonic-gate 	}
2206*7c478bd9Sstevel@tonic-gate }
2207*7c478bd9Sstevel@tonic-gate 
2208*7c478bd9Sstevel@tonic-gate /*
2209*7c478bd9Sstevel@tonic-gate  * siglvl - handle an asynchronous signal from init(1M) telling us that we
2210*7c478bd9Sstevel@tonic-gate  * should change the current run level.  We set new_state accordingly.
2211*7c478bd9Sstevel@tonic-gate  */
2212*7c478bd9Sstevel@tonic-gate void
2213*7c478bd9Sstevel@tonic-gate siglvl(int sig, siginfo_t *sip, ucontext_t *ucp)
2214*7c478bd9Sstevel@tonic-gate {
2215*7c478bd9Sstevel@tonic-gate 	struct PROC_TABLE *process;
2216*7c478bd9Sstevel@tonic-gate 	struct sigaction act;
2217*7c478bd9Sstevel@tonic-gate 
2218*7c478bd9Sstevel@tonic-gate 	/*
2219*7c478bd9Sstevel@tonic-gate 	 * If the signal was from the kernel (rather than init(1M)) then init
2220*7c478bd9Sstevel@tonic-gate 	 * itself tripped the signal.  That is, we might have a bug and tripped
2221*7c478bd9Sstevel@tonic-gate 	 * a real SIGSEGV instead of receiving it as an alias for SIGLVLa.  In
2222*7c478bd9Sstevel@tonic-gate 	 * such a case we reset the disposition to SIG_DFL, block all signals
2223*7c478bd9Sstevel@tonic-gate 	 * in uc_mask but the current one, and return to the interrupted ucp
2224*7c478bd9Sstevel@tonic-gate 	 * to effect an appropriate death.  The kernel will then restart us.
2225*7c478bd9Sstevel@tonic-gate 	 *
2226*7c478bd9Sstevel@tonic-gate 	 * The one exception to SI_FROMKERNEL() is SIGFPE (a.k.a. LVL6), which
2227*7c478bd9Sstevel@tonic-gate 	 * the kernel can send us when it wants to effect an orderly reboot.
2228*7c478bd9Sstevel@tonic-gate 	 * For this case we must also verify si_code is zero, rather than a
2229*7c478bd9Sstevel@tonic-gate 	 * code such as FPE_INTDIV which a bug might have triggered.
2230*7c478bd9Sstevel@tonic-gate 	 */
2231*7c478bd9Sstevel@tonic-gate 	if (sip != NULL && SI_FROMKERNEL(sip) &&
2232*7c478bd9Sstevel@tonic-gate 	    (sig != SIGFPE || sip->si_code == 0)) {
2233*7c478bd9Sstevel@tonic-gate 
2234*7c478bd9Sstevel@tonic-gate 		(void) sigemptyset(&act.sa_mask);
2235*7c478bd9Sstevel@tonic-gate 		act.sa_handler = SIG_DFL;
2236*7c478bd9Sstevel@tonic-gate 		act.sa_flags = 0;
2237*7c478bd9Sstevel@tonic-gate 		(void) sigaction(sig, &act, NULL);
2238*7c478bd9Sstevel@tonic-gate 
2239*7c478bd9Sstevel@tonic-gate 		(void) sigfillset(&ucp->uc_sigmask);
2240*7c478bd9Sstevel@tonic-gate 		(void) sigdelset(&ucp->uc_sigmask, sig);
2241*7c478bd9Sstevel@tonic-gate 		ucp->uc_flags |= UC_SIGMASK;
2242*7c478bd9Sstevel@tonic-gate 
2243*7c478bd9Sstevel@tonic-gate 		(void) setcontext(ucp);
2244*7c478bd9Sstevel@tonic-gate 	}
2245*7c478bd9Sstevel@tonic-gate 
2246*7c478bd9Sstevel@tonic-gate 	/*
2247*7c478bd9Sstevel@tonic-gate 	 * If the signal received is a LVLQ signal, do not really
2248*7c478bd9Sstevel@tonic-gate 	 * change levels, just restate the current level.  If the
2249*7c478bd9Sstevel@tonic-gate 	 * signal is not a LVLQ, set the new level to the signal
2250*7c478bd9Sstevel@tonic-gate 	 * received.
2251*7c478bd9Sstevel@tonic-gate 	 */
2252*7c478bd9Sstevel@tonic-gate 	if (sig == LVLQ)
2253*7c478bd9Sstevel@tonic-gate 		new_state = cur_state;
2254*7c478bd9Sstevel@tonic-gate 	else
2255*7c478bd9Sstevel@tonic-gate 		new_state = sig;
2256*7c478bd9Sstevel@tonic-gate 
2257*7c478bd9Sstevel@tonic-gate 	/*
2258*7c478bd9Sstevel@tonic-gate 	 * Clear all times and repeat counts in the process table
2259*7c478bd9Sstevel@tonic-gate 	 * since either the level is changing or the user has editted
2260*7c478bd9Sstevel@tonic-gate 	 * the inittab file and wants us to look at it again.
2261*7c478bd9Sstevel@tonic-gate 	 * If the user has fixed a typo, we don't want residual timing
2262*7c478bd9Sstevel@tonic-gate 	 * data preventing the fixed command line from executing.
2263*7c478bd9Sstevel@tonic-gate 	 */
2264*7c478bd9Sstevel@tonic-gate 	for (process = proc_table;
2265*7c478bd9Sstevel@tonic-gate 		(process < proc_table + num_proc); process++) {
2266*7c478bd9Sstevel@tonic-gate 		process->p_time = 0L;
2267*7c478bd9Sstevel@tonic-gate 		process->p_count = 0;
2268*7c478bd9Sstevel@tonic-gate 	}
2269*7c478bd9Sstevel@tonic-gate 
2270*7c478bd9Sstevel@tonic-gate 	/*
2271*7c478bd9Sstevel@tonic-gate 	 * Set the flag to indicate that a "user signal" was received.
2272*7c478bd9Sstevel@tonic-gate 	 */
2273*7c478bd9Sstevel@tonic-gate 	wakeup.w_flags.w_usersignal = 1;
2274*7c478bd9Sstevel@tonic-gate }
2275*7c478bd9Sstevel@tonic-gate 
2276*7c478bd9Sstevel@tonic-gate 
2277*7c478bd9Sstevel@tonic-gate /*
2278*7c478bd9Sstevel@tonic-gate  * alarmclk
2279*7c478bd9Sstevel@tonic-gate  */
2280*7c478bd9Sstevel@tonic-gate static void
2281*7c478bd9Sstevel@tonic-gate alarmclk()
2282*7c478bd9Sstevel@tonic-gate {
2283*7c478bd9Sstevel@tonic-gate 	time_up = TRUE;
2284*7c478bd9Sstevel@tonic-gate }
2285*7c478bd9Sstevel@tonic-gate 
2286*7c478bd9Sstevel@tonic-gate /*
2287*7c478bd9Sstevel@tonic-gate  * childeath_single():
2288*7c478bd9Sstevel@tonic-gate  *
2289*7c478bd9Sstevel@tonic-gate  * This used to be the SIGCLD handler and it was set with signal()
2290*7c478bd9Sstevel@tonic-gate  * (as opposed to sigset()).  When a child exited we'd come to the
2291*7c478bd9Sstevel@tonic-gate  * handler, wait for the child, and reenable the handler with
2292*7c478bd9Sstevel@tonic-gate  * signal() just before returning.  The implementation of signal()
2293*7c478bd9Sstevel@tonic-gate  * checks with waitid() for waitable children and sends a SIGCLD
2294*7c478bd9Sstevel@tonic-gate  * if there are some.  If children are exiting faster than the
2295*7c478bd9Sstevel@tonic-gate  * handler can run we keep sending signals and the handler never
2296*7c478bd9Sstevel@tonic-gate  * gets to return and eventually the stack runs out and init dies.
2297*7c478bd9Sstevel@tonic-gate  * To prevent that we set the handler with sigset() so the handler
2298*7c478bd9Sstevel@tonic-gate  * doesn't need to be reset, and in childeath() (see below) we
2299*7c478bd9Sstevel@tonic-gate  * call childeath_single() as long as there are children to be
2300*7c478bd9Sstevel@tonic-gate  * waited for.  If a child exits while init is in the handler a
2301*7c478bd9Sstevel@tonic-gate  * SIGCLD will be pending and delivered on return from the handler.
2302*7c478bd9Sstevel@tonic-gate  * If the child was already waited for the handler will have nothing
2303*7c478bd9Sstevel@tonic-gate  * to do and return, otherwise the child will be waited for.
2304*7c478bd9Sstevel@tonic-gate  */
2305*7c478bd9Sstevel@tonic-gate static void
2306*7c478bd9Sstevel@tonic-gate childeath_single()
2307*7c478bd9Sstevel@tonic-gate {
2308*7c478bd9Sstevel@tonic-gate 	struct PROC_TABLE	*process;
2309*7c478bd9Sstevel@tonic-gate 	struct pidlist		*pp;
2310*7c478bd9Sstevel@tonic-gate 	pid_t			pid;
2311*7c478bd9Sstevel@tonic-gate 	int			status;
2312*7c478bd9Sstevel@tonic-gate 
2313*7c478bd9Sstevel@tonic-gate 	/*
2314*7c478bd9Sstevel@tonic-gate 	 * Perform wait to get the process id of the child that died and
2315*7c478bd9Sstevel@tonic-gate 	 * then scan the process table to see if we are interested in
2316*7c478bd9Sstevel@tonic-gate 	 * this process. NOTE: if a super-user sends the SIGCLD signal
2317*7c478bd9Sstevel@tonic-gate 	 * to init, the following wait will not immediately return and
2318*7c478bd9Sstevel@tonic-gate 	 * init will be inoperative until one of its child really does die.
2319*7c478bd9Sstevel@tonic-gate 	 */
2320*7c478bd9Sstevel@tonic-gate 	pid = wait(&status);
2321*7c478bd9Sstevel@tonic-gate 
2322*7c478bd9Sstevel@tonic-gate 	for (process = proc_table;
2323*7c478bd9Sstevel@tonic-gate 		(process < proc_table + num_proc); process++) {
2324*7c478bd9Sstevel@tonic-gate 		if ((process->p_flags & (LIVING|OCCUPIED)) ==
2325*7c478bd9Sstevel@tonic-gate 		    (LIVING|OCCUPIED) && process->p_pid == pid) {
2326*7c478bd9Sstevel@tonic-gate 
2327*7c478bd9Sstevel@tonic-gate 			/*
2328*7c478bd9Sstevel@tonic-gate 			 * Mark this process as having died and store the exit
2329*7c478bd9Sstevel@tonic-gate 			 * status.  Also set the wakeup flag for a dead child
2330*7c478bd9Sstevel@tonic-gate 			 * and break out of the loop.
2331*7c478bd9Sstevel@tonic-gate 			 */
2332*7c478bd9Sstevel@tonic-gate 			process->p_flags &= ~LIVING;
2333*7c478bd9Sstevel@tonic-gate 			process->p_exit = (short)status;
2334*7c478bd9Sstevel@tonic-gate 			wakeup.w_flags.w_childdeath = 1;
2335*7c478bd9Sstevel@tonic-gate 
2336*7c478bd9Sstevel@tonic-gate 			return;
2337*7c478bd9Sstevel@tonic-gate 		}
2338*7c478bd9Sstevel@tonic-gate 	}
2339*7c478bd9Sstevel@tonic-gate 
2340*7c478bd9Sstevel@tonic-gate 	/*
2341*7c478bd9Sstevel@tonic-gate 	 * No process was found above, look through auxiliary list.
2342*7c478bd9Sstevel@tonic-gate 	 */
2343*7c478bd9Sstevel@tonic-gate 	(void) sighold(SIGPOLL);
2344*7c478bd9Sstevel@tonic-gate 	pp = Plhead;
2345*7c478bd9Sstevel@tonic-gate 	while (pp) {
2346*7c478bd9Sstevel@tonic-gate 		if (pid > pp->pl_pid) {
2347*7c478bd9Sstevel@tonic-gate 			/*
2348*7c478bd9Sstevel@tonic-gate 			 * Keep on looking.
2349*7c478bd9Sstevel@tonic-gate 			 */
2350*7c478bd9Sstevel@tonic-gate 			pp = pp->pl_next;
2351*7c478bd9Sstevel@tonic-gate 			continue;
2352*7c478bd9Sstevel@tonic-gate 		} else if (pid < pp->pl_pid) {
2353*7c478bd9Sstevel@tonic-gate 			/*
2354*7c478bd9Sstevel@tonic-gate 			 * Not in the list.
2355*7c478bd9Sstevel@tonic-gate 			 */
2356*7c478bd9Sstevel@tonic-gate 			break;
2357*7c478bd9Sstevel@tonic-gate 		} else {
2358*7c478bd9Sstevel@tonic-gate 			/*
2359*7c478bd9Sstevel@tonic-gate 			 * This is a dead "godchild".
2360*7c478bd9Sstevel@tonic-gate 			 */
2361*7c478bd9Sstevel@tonic-gate 			pp->pl_dflag = 1;
2362*7c478bd9Sstevel@tonic-gate 			pp->pl_exit = (short)status;
2363*7c478bd9Sstevel@tonic-gate 			wakeup.w_flags.w_childdeath = 1;
2364*7c478bd9Sstevel@tonic-gate 			Gchild = 1;	/* Notice to call cleanaux(). */
2365*7c478bd9Sstevel@tonic-gate 			break;
2366*7c478bd9Sstevel@tonic-gate 		}
2367*7c478bd9Sstevel@tonic-gate 	}
2368*7c478bd9Sstevel@tonic-gate 
2369*7c478bd9Sstevel@tonic-gate 	(void) sigrelse(SIGPOLL);
2370*7c478bd9Sstevel@tonic-gate }
2371*7c478bd9Sstevel@tonic-gate 
2372*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
2373*7c478bd9Sstevel@tonic-gate static void
2374*7c478bd9Sstevel@tonic-gate childeath(int signo)
2375*7c478bd9Sstevel@tonic-gate {
2376*7c478bd9Sstevel@tonic-gate 	siginfo_t info;
2377*7c478bd9Sstevel@tonic-gate 
2378*7c478bd9Sstevel@tonic-gate 	while ((waitid(P_ALL, (id_t)0, &info, WEXITED|WNOHANG|WNOWAIT) == 0) &&
2379*7c478bd9Sstevel@tonic-gate 	    info.si_pid != 0)
2380*7c478bd9Sstevel@tonic-gate 		childeath_single();
2381*7c478bd9Sstevel@tonic-gate }
2382*7c478bd9Sstevel@tonic-gate 
2383*7c478bd9Sstevel@tonic-gate static void
2384*7c478bd9Sstevel@tonic-gate powerfail()
2385*7c478bd9Sstevel@tonic-gate {
2386*7c478bd9Sstevel@tonic-gate 	(void) nice(-19);
2387*7c478bd9Sstevel@tonic-gate 	wakeup.w_flags.w_powerhit = 1;
2388*7c478bd9Sstevel@tonic-gate }
2389*7c478bd9Sstevel@tonic-gate 
2390*7c478bd9Sstevel@tonic-gate /*
2391*7c478bd9Sstevel@tonic-gate  * efork() forks a child and the parent inserts the process in its table
2392*7c478bd9Sstevel@tonic-gate  * of processes that are directly a result of forks that it has performed.
2393*7c478bd9Sstevel@tonic-gate  * The child just changes the "global" with the process id for this process
2394*7c478bd9Sstevel@tonic-gate  * to it's new value.
2395*7c478bd9Sstevel@tonic-gate  * If efork() is called with a pointer into the proc_table it uses that slot,
2396*7c478bd9Sstevel@tonic-gate  * otherwise it searches for a free slot.  Regardless of how it was called,
2397*7c478bd9Sstevel@tonic-gate  * it returns the pointer to the proc_table entry
2398*7c478bd9Sstevel@tonic-gate  *
2399*7c478bd9Sstevel@tonic-gate  * The SIGCLD handler is set to default (SIG_DFL) before calling efork().
2400*7c478bd9Sstevel@tonic-gate  * This relies on the somewhat obscure SVR2 SIGCLD/SIG_DFL semantic
2401*7c478bd9Sstevel@tonic-gate  * implied by the use of signal(3c).  While the meaning of SIG_DFL for
2402*7c478bd9Sstevel@tonic-gate  * SIGCLD is nominally to ignore the signal, once the signal disposition
2403*7c478bd9Sstevel@tonic-gate  * is set to childeath(), the kernel will post a SIGCLD if a child
2404*7c478bd9Sstevel@tonic-gate  * exited during the period the disposition was SIG_DFL.  It acts more
2405*7c478bd9Sstevel@tonic-gate  * like a signal block.
2406*7c478bd9Sstevel@tonic-gate  *
2407*7c478bd9Sstevel@tonic-gate  * Ideally, this should be rewritten to use modern signal semantics.
2408*7c478bd9Sstevel@tonic-gate  */
2409*7c478bd9Sstevel@tonic-gate static struct PROC_TABLE *
2410*7c478bd9Sstevel@tonic-gate efork(int action, struct PROC_TABLE *process, int modes)
2411*7c478bd9Sstevel@tonic-gate {
2412*7c478bd9Sstevel@tonic-gate 	pid_t	childpid;
2413*7c478bd9Sstevel@tonic-gate 	struct PROC_TABLE *proc;
2414*7c478bd9Sstevel@tonic-gate 	int		i;
2415*7c478bd9Sstevel@tonic-gate 	void (*oldroutine)();
2416*7c478bd9Sstevel@tonic-gate 	/*
2417*7c478bd9Sstevel@tonic-gate 	 * Freshen up the proc_table, removing any entries for dead processes
2418*7c478bd9Sstevel@tonic-gate 	 * that don't have NOCLEANUP set.  Perform the necessary accounting.
2419*7c478bd9Sstevel@tonic-gate 	 */
2420*7c478bd9Sstevel@tonic-gate 	for (proc = proc_table; (proc < proc_table + num_proc); proc++) {
2421*7c478bd9Sstevel@tonic-gate 		if ((proc->p_flags & (OCCUPIED|LIVING|NOCLEANUP)) ==
2422*7c478bd9Sstevel@tonic-gate 		    (OCCUPIED)) {
2423*7c478bd9Sstevel@tonic-gate 			/*
2424*7c478bd9Sstevel@tonic-gate 			 * Is this a named process?
2425*7c478bd9Sstevel@tonic-gate 			 * If so, do the necessary bookkeeping.
2426*7c478bd9Sstevel@tonic-gate 			 */
2427*7c478bd9Sstevel@tonic-gate 			if (proc->p_flags & NAMED)
2428*7c478bd9Sstevel@tonic-gate 				(void) account(DEAD_PROCESS, proc, NULL);
2429*7c478bd9Sstevel@tonic-gate 
2430*7c478bd9Sstevel@tonic-gate 			/*
2431*7c478bd9Sstevel@tonic-gate 			 * Free this entry for new usage.
2432*7c478bd9Sstevel@tonic-gate 			 */
2433*7c478bd9Sstevel@tonic-gate 			proc->p_flags = 0;
2434*7c478bd9Sstevel@tonic-gate 		}
2435*7c478bd9Sstevel@tonic-gate 	}
2436*7c478bd9Sstevel@tonic-gate 
2437*7c478bd9Sstevel@tonic-gate 	while ((childpid = fork()) == FAILURE) {
2438*7c478bd9Sstevel@tonic-gate 		/*
2439*7c478bd9Sstevel@tonic-gate 		 * Shorten the alarm timer in case someone else's child dies
2440*7c478bd9Sstevel@tonic-gate 		 * and free up a slot in the process table.
2441*7c478bd9Sstevel@tonic-gate 		 */
2442*7c478bd9Sstevel@tonic-gate 		setimer(5);
2443*7c478bd9Sstevel@tonic-gate 
2444*7c478bd9Sstevel@tonic-gate 		/*
2445*7c478bd9Sstevel@tonic-gate 		 * Wait for some children to die.  Since efork() is normally
2446*7c478bd9Sstevel@tonic-gate 		 * called with SIGCLD in the default state, reset it to catch
2447*7c478bd9Sstevel@tonic-gate 		 * so that child death signals can come in.
2448*7c478bd9Sstevel@tonic-gate 		 */
2449*7c478bd9Sstevel@tonic-gate 		oldroutine = sigset(SIGCLD, childeath);
2450*7c478bd9Sstevel@tonic-gate 		(void) pause();
2451*7c478bd9Sstevel@tonic-gate 		(void) sigset(SIGCLD, oldroutine);
2452*7c478bd9Sstevel@tonic-gate 		setimer(0);
2453*7c478bd9Sstevel@tonic-gate 	}
2454*7c478bd9Sstevel@tonic-gate 
2455*7c478bd9Sstevel@tonic-gate 	if (childpid != 0) {
2456*7c478bd9Sstevel@tonic-gate 
2457*7c478bd9Sstevel@tonic-gate 		if (process == NULLPROC) {
2458*7c478bd9Sstevel@tonic-gate 			/*
2459*7c478bd9Sstevel@tonic-gate 			 * No proc table pointer specified so search
2460*7c478bd9Sstevel@tonic-gate 			 * for a free slot.
2461*7c478bd9Sstevel@tonic-gate 			 */
2462*7c478bd9Sstevel@tonic-gate 			for (process = proc_table;  process->p_flags != 0 &&
2463*7c478bd9Sstevel@tonic-gate 				(process < proc_table + num_proc); process++)
2464*7c478bd9Sstevel@tonic-gate 					;
2465*7c478bd9Sstevel@tonic-gate 
2466*7c478bd9Sstevel@tonic-gate 			if (process == (proc_table + num_proc)) {
2467*7c478bd9Sstevel@tonic-gate 				int old_proc_table_size = num_proc;
2468*7c478bd9Sstevel@tonic-gate 
2469*7c478bd9Sstevel@tonic-gate 				/* Increase the process table size */
2470*7c478bd9Sstevel@tonic-gate 				increase_proc_table_size();
2471*7c478bd9Sstevel@tonic-gate 				if (old_proc_table_size == num_proc) {
2472*7c478bd9Sstevel@tonic-gate 					/* didn't grow: memory failure */
2473*7c478bd9Sstevel@tonic-gate 					return (NO_ROOM);
2474*7c478bd9Sstevel@tonic-gate 				} else {
2475*7c478bd9Sstevel@tonic-gate 					process =
2476*7c478bd9Sstevel@tonic-gate 					    proc_table + old_proc_table_size;
2477*7c478bd9Sstevel@tonic-gate 				}
2478*7c478bd9Sstevel@tonic-gate 			}
2479*7c478bd9Sstevel@tonic-gate 
2480*7c478bd9Sstevel@tonic-gate 			process->p_time = 0L;
2481*7c478bd9Sstevel@tonic-gate 			process->p_count = 0;
2482*7c478bd9Sstevel@tonic-gate 		}
2483*7c478bd9Sstevel@tonic-gate 		process->p_id[0] = '\0';
2484*7c478bd9Sstevel@tonic-gate 		process->p_id[1] = '\0';
2485*7c478bd9Sstevel@tonic-gate 		process->p_id[2] = '\0';
2486*7c478bd9Sstevel@tonic-gate 		process->p_id[3] = '\0';
2487*7c478bd9Sstevel@tonic-gate 		process->p_pid = childpid;
2488*7c478bd9Sstevel@tonic-gate 		process->p_flags = (LIVING | OCCUPIED | modes);
2489*7c478bd9Sstevel@tonic-gate 		process->p_exit = 0;
2490*7c478bd9Sstevel@tonic-gate 
2491*7c478bd9Sstevel@tonic-gate 		st_write();
2492*7c478bd9Sstevel@tonic-gate 	} else {
2493*7c478bd9Sstevel@tonic-gate 		if ((action & (M_WAIT | M_BOOTWAIT)) == 0)
2494*7c478bd9Sstevel@tonic-gate 			(void) setpgrp();
2495*7c478bd9Sstevel@tonic-gate 
2496*7c478bd9Sstevel@tonic-gate 		process = NULLPROC;
2497*7c478bd9Sstevel@tonic-gate 
2498*7c478bd9Sstevel@tonic-gate 		/*
2499*7c478bd9Sstevel@tonic-gate 		 * Reset all signals to the system defaults.
2500*7c478bd9Sstevel@tonic-gate 		 */
2501*7c478bd9Sstevel@tonic-gate 		for (i = SIGHUP; i <= SIGRTMAX; i++)
2502*7c478bd9Sstevel@tonic-gate 			(void) sigset(i, SIG_DFL);
2503*7c478bd9Sstevel@tonic-gate 
2504*7c478bd9Sstevel@tonic-gate 		/*
2505*7c478bd9Sstevel@tonic-gate 		 * POSIX B.2.2.2 advises that init should set SIGTTOU,
2506*7c478bd9Sstevel@tonic-gate 		 * SIGTTIN, and SIGTSTP to SIG_IGN.
2507*7c478bd9Sstevel@tonic-gate 		 *
2508*7c478bd9Sstevel@tonic-gate 		 * Make sure that SIGXCPU and SIGXFSZ also remain ignored,
2509*7c478bd9Sstevel@tonic-gate 		 * for backward compatibility.
2510*7c478bd9Sstevel@tonic-gate 		 */
2511*7c478bd9Sstevel@tonic-gate 		(void) sigset(SIGTTIN, SIG_IGN);
2512*7c478bd9Sstevel@tonic-gate 		(void) sigset(SIGTTOU, SIG_IGN);
2513*7c478bd9Sstevel@tonic-gate 		(void) sigset(SIGTSTP, SIG_IGN);
2514*7c478bd9Sstevel@tonic-gate 		(void) sigset(SIGXCPU, SIG_IGN);
2515*7c478bd9Sstevel@tonic-gate 		(void) sigset(SIGXFSZ, SIG_IGN);
2516*7c478bd9Sstevel@tonic-gate 	}
2517*7c478bd9Sstevel@tonic-gate 	return (process);
2518*7c478bd9Sstevel@tonic-gate }
2519*7c478bd9Sstevel@tonic-gate 
2520*7c478bd9Sstevel@tonic-gate 
2521*7c478bd9Sstevel@tonic-gate /*
2522*7c478bd9Sstevel@tonic-gate  * waitproc() waits for a specified process to die.  For this function to
2523*7c478bd9Sstevel@tonic-gate  * work, the specified process must already in the proc_table.  waitproc()
2524*7c478bd9Sstevel@tonic-gate  * returns the exit status of the specified process when it dies.
2525*7c478bd9Sstevel@tonic-gate  */
2526*7c478bd9Sstevel@tonic-gate static long
2527*7c478bd9Sstevel@tonic-gate waitproc(struct PROC_TABLE *process)
2528*7c478bd9Sstevel@tonic-gate {
2529*7c478bd9Sstevel@tonic-gate 	int		answer;
2530*7c478bd9Sstevel@tonic-gate 	sigset_t	oldmask, newmask, zeromask;
2531*7c478bd9Sstevel@tonic-gate 
2532*7c478bd9Sstevel@tonic-gate 	(void) sigemptyset(&zeromask);
2533*7c478bd9Sstevel@tonic-gate 	(void) sigemptyset(&newmask);
2534*7c478bd9Sstevel@tonic-gate 
2535*7c478bd9Sstevel@tonic-gate 	(void) sigaddset(&newmask, SIGCLD);
2536*7c478bd9Sstevel@tonic-gate 
2537*7c478bd9Sstevel@tonic-gate 	/* Block SIGCLD and save the current signal mask */
2538*7c478bd9Sstevel@tonic-gate 	if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)
2539*7c478bd9Sstevel@tonic-gate 		perror("SIG_BLOCK error");
2540*7c478bd9Sstevel@tonic-gate 
2541*7c478bd9Sstevel@tonic-gate 	/*
2542*7c478bd9Sstevel@tonic-gate 	 * Wait around until the process dies.
2543*7c478bd9Sstevel@tonic-gate 	 */
2544*7c478bd9Sstevel@tonic-gate 	if (process->p_flags & LIVING)
2545*7c478bd9Sstevel@tonic-gate 		(void) sigsuspend(&zeromask);
2546*7c478bd9Sstevel@tonic-gate 
2547*7c478bd9Sstevel@tonic-gate 	/* Reset signal mask to unblock SIGCLD */
2548*7c478bd9Sstevel@tonic-gate 	if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
2549*7c478bd9Sstevel@tonic-gate 		perror("SIG_SETMASK error");
2550*7c478bd9Sstevel@tonic-gate 
2551*7c478bd9Sstevel@tonic-gate 	if (process->p_flags & LIVING)
2552*7c478bd9Sstevel@tonic-gate 		return (FAILURE);
2553*7c478bd9Sstevel@tonic-gate 
2554*7c478bd9Sstevel@tonic-gate 	/*
2555*7c478bd9Sstevel@tonic-gate 	 * Make sure to only return 16 bits so that answer will always
2556*7c478bd9Sstevel@tonic-gate 	 * be positive whenever the process of interest really died.
2557*7c478bd9Sstevel@tonic-gate 	 */
2558*7c478bd9Sstevel@tonic-gate 	answer = (process->p_exit & 0xffff);
2559*7c478bd9Sstevel@tonic-gate 
2560*7c478bd9Sstevel@tonic-gate 	/*
2561*7c478bd9Sstevel@tonic-gate 	 * Free the slot in the proc_table.
2562*7c478bd9Sstevel@tonic-gate 	 */
2563*7c478bd9Sstevel@tonic-gate 	process->p_flags = 0;
2564*7c478bd9Sstevel@tonic-gate 	return (answer);
2565*7c478bd9Sstevel@tonic-gate }
2566*7c478bd9Sstevel@tonic-gate 
2567*7c478bd9Sstevel@tonic-gate /*
2568*7c478bd9Sstevel@tonic-gate  * notify_pam_dead(): calls into the PAM framework to close the given session.
2569*7c478bd9Sstevel@tonic-gate  */
2570*7c478bd9Sstevel@tonic-gate static void
2571*7c478bd9Sstevel@tonic-gate notify_pam_dead(struct utmpx *up)
2572*7c478bd9Sstevel@tonic-gate {
2573*7c478bd9Sstevel@tonic-gate 	pam_handle_t *pamh;
2574*7c478bd9Sstevel@tonic-gate 	char user[sizeof (up->ut_user) + 1];
2575*7c478bd9Sstevel@tonic-gate 	char ttyn[sizeof (up->ut_line) + 1];
2576*7c478bd9Sstevel@tonic-gate 	char host[sizeof (up->ut_host) + 1];
2577*7c478bd9Sstevel@tonic-gate 
2578*7c478bd9Sstevel@tonic-gate 	/*
2579*7c478bd9Sstevel@tonic-gate 	 * PAM does not take care of updating utmpx/wtmpx.
2580*7c478bd9Sstevel@tonic-gate 	 */
2581*7c478bd9Sstevel@tonic-gate 	(void) snprintf(user, sizeof (user), "%s", up->ut_user);
2582*7c478bd9Sstevel@tonic-gate 	(void) snprintf(ttyn, sizeof (ttyn), "%s", up->ut_line);
2583*7c478bd9Sstevel@tonic-gate 	(void) snprintf(host, sizeof (host), "%s", up->ut_host);
2584*7c478bd9Sstevel@tonic-gate 
2585*7c478bd9Sstevel@tonic-gate 	if (pam_start("init", user, NULL, &pamh) == PAM_SUCCESS)  {
2586*7c478bd9Sstevel@tonic-gate 		(void) pam_set_item(pamh, PAM_TTY, ttyn);
2587*7c478bd9Sstevel@tonic-gate 		(void) pam_set_item(pamh, PAM_RHOST, host);
2588*7c478bd9Sstevel@tonic-gate 		(void) pam_close_session(pamh, 0);
2589*7c478bd9Sstevel@tonic-gate 		(void) pam_end(pamh, PAM_SUCCESS);
2590*7c478bd9Sstevel@tonic-gate 	}
2591*7c478bd9Sstevel@tonic-gate }
2592*7c478bd9Sstevel@tonic-gate 
2593*7c478bd9Sstevel@tonic-gate /*
2594*7c478bd9Sstevel@tonic-gate  * Check you can access utmpx (As / may be read-only and
2595*7c478bd9Sstevel@tonic-gate  * /var may not be mounted yet).
2596*7c478bd9Sstevel@tonic-gate  */
2597*7c478bd9Sstevel@tonic-gate static int
2598*7c478bd9Sstevel@tonic-gate access_utmpx(void)
2599*7c478bd9Sstevel@tonic-gate {
2600*7c478bd9Sstevel@tonic-gate 	do {
2601*7c478bd9Sstevel@tonic-gate 		utmpx_ok = (access(UTMPX, R_OK|W_OK) == 0);
2602*7c478bd9Sstevel@tonic-gate 	} while (!utmpx_ok && errno == EINTR);
2603*7c478bd9Sstevel@tonic-gate 
2604*7c478bd9Sstevel@tonic-gate 	return (utmpx_ok);
2605*7c478bd9Sstevel@tonic-gate }
2606*7c478bd9Sstevel@tonic-gate 
2607*7c478bd9Sstevel@tonic-gate /*
2608*7c478bd9Sstevel@tonic-gate  * account() updates entries in utmpx and appends new entries to the end of
2609*7c478bd9Sstevel@tonic-gate  * wtmpx (assuming they exist).  The program argument indicates the name of
2610*7c478bd9Sstevel@tonic-gate  * program if INIT_PROCESS, otherwise should be NULL.
2611*7c478bd9Sstevel@tonic-gate  *
2612*7c478bd9Sstevel@tonic-gate  * account() only blocks for INIT_PROCESS requests.
2613*7c478bd9Sstevel@tonic-gate  *
2614*7c478bd9Sstevel@tonic-gate  * Returns non-zero if write failed.
2615*7c478bd9Sstevel@tonic-gate  */
2616*7c478bd9Sstevel@tonic-gate static int
2617*7c478bd9Sstevel@tonic-gate account(short state, struct PROC_TABLE *process, char *program)
2618*7c478bd9Sstevel@tonic-gate {
2619*7c478bd9Sstevel@tonic-gate 	struct utmpx utmpbuf, *u, *oldu;
2620*7c478bd9Sstevel@tonic-gate 	int tmplen;
2621*7c478bd9Sstevel@tonic-gate 	char fail_buf[UT_LINE_SZ];
2622*7c478bd9Sstevel@tonic-gate 	sigset_t block, unblock;
2623*7c478bd9Sstevel@tonic-gate 
2624*7c478bd9Sstevel@tonic-gate 	if (!utmpx_ok && !access_utmpx()) {
2625*7c478bd9Sstevel@tonic-gate 		return (-1);
2626*7c478bd9Sstevel@tonic-gate 	}
2627*7c478bd9Sstevel@tonic-gate 
2628*7c478bd9Sstevel@tonic-gate 	/*
2629*7c478bd9Sstevel@tonic-gate 	 * Set up the prototype for the utmp structure we want to write.
2630*7c478bd9Sstevel@tonic-gate 	 */
2631*7c478bd9Sstevel@tonic-gate 	u = &utmpbuf;
2632*7c478bd9Sstevel@tonic-gate 	(void) memset(u, 0, sizeof (struct utmpx));
2633*7c478bd9Sstevel@tonic-gate 
2634*7c478bd9Sstevel@tonic-gate 	/*
2635*7c478bd9Sstevel@tonic-gate 	 * Fill in the various fields of the utmp structure.
2636*7c478bd9Sstevel@tonic-gate 	 */
2637*7c478bd9Sstevel@tonic-gate 	u->ut_id[0] = process->p_id[0];
2638*7c478bd9Sstevel@tonic-gate 	u->ut_id[1] = process->p_id[1];
2639*7c478bd9Sstevel@tonic-gate 	u->ut_id[2] = process->p_id[2];
2640*7c478bd9Sstevel@tonic-gate 	u->ut_id[3] = process->p_id[3];
2641*7c478bd9Sstevel@tonic-gate 	u->ut_pid = process->p_pid;
2642*7c478bd9Sstevel@tonic-gate 
2643*7c478bd9Sstevel@tonic-gate 	/*
2644*7c478bd9Sstevel@tonic-gate 	 * Fill the "ut_exit" structure.
2645*7c478bd9Sstevel@tonic-gate 	 */
2646*7c478bd9Sstevel@tonic-gate 	u->ut_exit.e_termination = WTERMSIG(process->p_exit);
2647*7c478bd9Sstevel@tonic-gate 	u->ut_exit.e_exit = WEXITSTATUS(process->p_exit);
2648*7c478bd9Sstevel@tonic-gate 	u->ut_type = state;
2649*7c478bd9Sstevel@tonic-gate 
2650*7c478bd9Sstevel@tonic-gate 	(void) time(&u->ut_tv.tv_sec);
2651*7c478bd9Sstevel@tonic-gate 
2652*7c478bd9Sstevel@tonic-gate 	/*
2653*7c478bd9Sstevel@tonic-gate 	 * Block signals for utmp update.
2654*7c478bd9Sstevel@tonic-gate 	 */
2655*7c478bd9Sstevel@tonic-gate 	(void) sigfillset(&block);
2656*7c478bd9Sstevel@tonic-gate 	(void) sigprocmask(SIG_BLOCK, &block, &unblock);
2657*7c478bd9Sstevel@tonic-gate 
2658*7c478bd9Sstevel@tonic-gate 	/*
2659*7c478bd9Sstevel@tonic-gate 	 * See if there already is such an entry in the "utmpx" file.
2660*7c478bd9Sstevel@tonic-gate 	 */
2661*7c478bd9Sstevel@tonic-gate 	setutxent();	/* Start at beginning of utmpx file. */
2662*7c478bd9Sstevel@tonic-gate 
2663*7c478bd9Sstevel@tonic-gate 	if ((oldu = getutxid(u)) != NULL) {
2664*7c478bd9Sstevel@tonic-gate 		/*
2665*7c478bd9Sstevel@tonic-gate 		 * Copy in the old "user", "line" and "host" fields
2666*7c478bd9Sstevel@tonic-gate 		 * to our new structure.
2667*7c478bd9Sstevel@tonic-gate 		 */
2668*7c478bd9Sstevel@tonic-gate 		bcopy(oldu->ut_user, u->ut_user, sizeof (u->ut_user));
2669*7c478bd9Sstevel@tonic-gate 		bcopy(oldu->ut_line, u->ut_line, sizeof (u->ut_line));
2670*7c478bd9Sstevel@tonic-gate 		bcopy(oldu->ut_host, u->ut_host, sizeof (u->ut_host));
2671*7c478bd9Sstevel@tonic-gate 		u->ut_syslen = (tmplen = strlen(u->ut_host)) ?
2672*7c478bd9Sstevel@tonic-gate 			min(tmplen + 1, sizeof (u->ut_host)) : 0;
2673*7c478bd9Sstevel@tonic-gate 
2674*7c478bd9Sstevel@tonic-gate 		if (oldu->ut_type == USER_PROCESS && state == DEAD_PROCESS) {
2675*7c478bd9Sstevel@tonic-gate 			notify_pam_dead(oldu);
2676*7c478bd9Sstevel@tonic-gate 		}
2677*7c478bd9Sstevel@tonic-gate 	}
2678*7c478bd9Sstevel@tonic-gate 
2679*7c478bd9Sstevel@tonic-gate 	/*
2680*7c478bd9Sstevel@tonic-gate 	 * Perform special accounting. Insert the special string into the
2681*7c478bd9Sstevel@tonic-gate 	 * ut_line array. For INIT_PROCESSes put in the name of the
2682*7c478bd9Sstevel@tonic-gate 	 * program in the "ut_user" field.
2683*7c478bd9Sstevel@tonic-gate 	 */
2684*7c478bd9Sstevel@tonic-gate 	switch (state) {
2685*7c478bd9Sstevel@tonic-gate 	case INIT_PROCESS:
2686*7c478bd9Sstevel@tonic-gate 		(void) strncpy(u->ut_user, program, sizeof (u->ut_user));
2687*7c478bd9Sstevel@tonic-gate 		(void) strcpy(fail_buf, "INIT_PROCESS");
2688*7c478bd9Sstevel@tonic-gate 		break;
2689*7c478bd9Sstevel@tonic-gate 
2690*7c478bd9Sstevel@tonic-gate 	default:
2691*7c478bd9Sstevel@tonic-gate 		(void) strlcpy(fail_buf, u->ut_id, sizeof (u->ut_id) + 1);
2692*7c478bd9Sstevel@tonic-gate 		break;
2693*7c478bd9Sstevel@tonic-gate 	}
2694*7c478bd9Sstevel@tonic-gate 
2695*7c478bd9Sstevel@tonic-gate 	/*
2696*7c478bd9Sstevel@tonic-gate 	 * Write out the updated entry to utmpx file.
2697*7c478bd9Sstevel@tonic-gate 	 */
2698*7c478bd9Sstevel@tonic-gate 	if (pututxline(u) == NULL) {
2699*7c478bd9Sstevel@tonic-gate 		console(B_TRUE, "Failed write of utmpx entry: \"%s\": %s\n",
2700*7c478bd9Sstevel@tonic-gate 		    fail_buf, strerror(errno));
2701*7c478bd9Sstevel@tonic-gate 		endutxent();
2702*7c478bd9Sstevel@tonic-gate 		(void) sigprocmask(SIG_SETMASK, &unblock, NULL);
2703*7c478bd9Sstevel@tonic-gate 		return (-1);
2704*7c478bd9Sstevel@tonic-gate 	}
2705*7c478bd9Sstevel@tonic-gate 
2706*7c478bd9Sstevel@tonic-gate 	/*
2707*7c478bd9Sstevel@tonic-gate 	 * If we're able to write to utmpx, then attempt to add to the
2708*7c478bd9Sstevel@tonic-gate 	 * end of the wtmpx file.
2709*7c478bd9Sstevel@tonic-gate 	 */
2710*7c478bd9Sstevel@tonic-gate 	updwtmpx(WTMPX, u);
2711*7c478bd9Sstevel@tonic-gate 
2712*7c478bd9Sstevel@tonic-gate 	endutxent();
2713*7c478bd9Sstevel@tonic-gate 
2714*7c478bd9Sstevel@tonic-gate 	(void) sigprocmask(SIG_SETMASK, &unblock, NULL);
2715*7c478bd9Sstevel@tonic-gate 
2716*7c478bd9Sstevel@tonic-gate 	return (0);
2717*7c478bd9Sstevel@tonic-gate }
2718*7c478bd9Sstevel@tonic-gate 
2719*7c478bd9Sstevel@tonic-gate static void
2720*7c478bd9Sstevel@tonic-gate clearent(pid_t pid, short status)
2721*7c478bd9Sstevel@tonic-gate {
2722*7c478bd9Sstevel@tonic-gate 	struct utmpx *up;
2723*7c478bd9Sstevel@tonic-gate 	sigset_t block, unblock;
2724*7c478bd9Sstevel@tonic-gate 
2725*7c478bd9Sstevel@tonic-gate 	/*
2726*7c478bd9Sstevel@tonic-gate 	 * Block signals for utmp update.
2727*7c478bd9Sstevel@tonic-gate 	 */
2728*7c478bd9Sstevel@tonic-gate 	(void) sigfillset(&block);
2729*7c478bd9Sstevel@tonic-gate 	(void) sigprocmask(SIG_BLOCK, &block, &unblock);
2730*7c478bd9Sstevel@tonic-gate 
2731*7c478bd9Sstevel@tonic-gate 	/*
2732*7c478bd9Sstevel@tonic-gate 	 * No error checking for now.
2733*7c478bd9Sstevel@tonic-gate 	 */
2734*7c478bd9Sstevel@tonic-gate 
2735*7c478bd9Sstevel@tonic-gate 	setutxent();
2736*7c478bd9Sstevel@tonic-gate 	while (up = getutxent()) {
2737*7c478bd9Sstevel@tonic-gate 		if (up->ut_pid == pid) {
2738*7c478bd9Sstevel@tonic-gate 			if (up->ut_type == DEAD_PROCESS) {
2739*7c478bd9Sstevel@tonic-gate 				/*
2740*7c478bd9Sstevel@tonic-gate 				 * Cleaned up elsewhere.
2741*7c478bd9Sstevel@tonic-gate 				 */
2742*7c478bd9Sstevel@tonic-gate 				continue;
2743*7c478bd9Sstevel@tonic-gate 			}
2744*7c478bd9Sstevel@tonic-gate 
2745*7c478bd9Sstevel@tonic-gate 			notify_pam_dead(up);
2746*7c478bd9Sstevel@tonic-gate 
2747*7c478bd9Sstevel@tonic-gate 			up->ut_type = DEAD_PROCESS;
2748*7c478bd9Sstevel@tonic-gate 			up->ut_exit.e_termination = WTERMSIG(status);
2749*7c478bd9Sstevel@tonic-gate 			up->ut_exit.e_exit = WEXITSTATUS(status);
2750*7c478bd9Sstevel@tonic-gate 			(void) time(&up->ut_tv.tv_sec);
2751*7c478bd9Sstevel@tonic-gate 
2752*7c478bd9Sstevel@tonic-gate 			(void) pututxline(up);
2753*7c478bd9Sstevel@tonic-gate 			/*
2754*7c478bd9Sstevel@tonic-gate 			 * Now attempt to add to the end of the
2755*7c478bd9Sstevel@tonic-gate 			 * wtmp and wtmpx files.  Do not create
2756*7c478bd9Sstevel@tonic-gate 			 * if they don't already exist.
2757*7c478bd9Sstevel@tonic-gate 			 */
2758*7c478bd9Sstevel@tonic-gate 			updwtmpx(WTMPX, up);
2759*7c478bd9Sstevel@tonic-gate 
2760*7c478bd9Sstevel@tonic-gate 			break;
2761*7c478bd9Sstevel@tonic-gate 		}
2762*7c478bd9Sstevel@tonic-gate 	}
2763*7c478bd9Sstevel@tonic-gate 
2764*7c478bd9Sstevel@tonic-gate 	endutxent();
2765*7c478bd9Sstevel@tonic-gate 	(void) sigprocmask(SIG_SETMASK, &unblock, NULL);
2766*7c478bd9Sstevel@tonic-gate }
2767*7c478bd9Sstevel@tonic-gate 
2768*7c478bd9Sstevel@tonic-gate /*
2769*7c478bd9Sstevel@tonic-gate  * prog_name() searches for the word or unix path name and
2770*7c478bd9Sstevel@tonic-gate  * returns a pointer to the last element of the pathname.
2771*7c478bd9Sstevel@tonic-gate  */
2772*7c478bd9Sstevel@tonic-gate static char *
2773*7c478bd9Sstevel@tonic-gate prog_name(char *string)
2774*7c478bd9Sstevel@tonic-gate {
2775*7c478bd9Sstevel@tonic-gate 	char	*ptr, *ptr2;
2776*7c478bd9Sstevel@tonic-gate 	/* XXX - utmp - fix name length */
2777*7c478bd9Sstevel@tonic-gate 	static char word[_POSIX_LOGIN_NAME_MAX];
2778*7c478bd9Sstevel@tonic-gate 
2779*7c478bd9Sstevel@tonic-gate 	/*
2780*7c478bd9Sstevel@tonic-gate 	 * Search for the first word skipping leading spaces and tabs.
2781*7c478bd9Sstevel@tonic-gate 	 */
2782*7c478bd9Sstevel@tonic-gate 	while (*string == ' ' || *string == '\t')
2783*7c478bd9Sstevel@tonic-gate 		string++;
2784*7c478bd9Sstevel@tonic-gate 
2785*7c478bd9Sstevel@tonic-gate 	/*
2786*7c478bd9Sstevel@tonic-gate 	 * If the first non-space non-tab character is not one allowed in
2787*7c478bd9Sstevel@tonic-gate 	 * a word, return a pointer to a null string, otherwise parse the
2788*7c478bd9Sstevel@tonic-gate 	 * pathname.
2789*7c478bd9Sstevel@tonic-gate 	 */
2790*7c478bd9Sstevel@tonic-gate 	if (*string != '.' && *string != '/' && *string != '_' &&
2791*7c478bd9Sstevel@tonic-gate 	    (*string < 'a' || *string > 'z') &&
2792*7c478bd9Sstevel@tonic-gate 	    (*string < 'A' || * string > 'Z') &&
2793*7c478bd9Sstevel@tonic-gate 	    (*string < '0' || *string > '9'))
2794*7c478bd9Sstevel@tonic-gate 		return ("");
2795*7c478bd9Sstevel@tonic-gate 
2796*7c478bd9Sstevel@tonic-gate 	/*
2797*7c478bd9Sstevel@tonic-gate 	 * Parse the pathname looking forward for '/', ' ', '\t', '\n' or
2798*7c478bd9Sstevel@tonic-gate 	 * '\0'.  Each time a '/' is found, move "ptr" to one past the
2799*7c478bd9Sstevel@tonic-gate 	 * '/', thus when a ' ', '\t', '\n', or '\0' is found, "ptr" will
2800*7c478bd9Sstevel@tonic-gate 	 * point to the last element of the pathname.
2801*7c478bd9Sstevel@tonic-gate 	 */
2802*7c478bd9Sstevel@tonic-gate 	for (ptr = string;
2803*7c478bd9Sstevel@tonic-gate 		*string != ' ' && *string != '\t' && *string != '\n' &&
2804*7c478bd9Sstevel@tonic-gate 							*string != '\0';
2805*7c478bd9Sstevel@tonic-gate 		string++) {
2806*7c478bd9Sstevel@tonic-gate 		if (*string == '/')
2807*7c478bd9Sstevel@tonic-gate 			ptr = string+1;
2808*7c478bd9Sstevel@tonic-gate 	}
2809*7c478bd9Sstevel@tonic-gate 
2810*7c478bd9Sstevel@tonic-gate 	/*
2811*7c478bd9Sstevel@tonic-gate 	 * Copy out up to the size of the "ut_user" array into "word",
2812*7c478bd9Sstevel@tonic-gate 	 * null terminate it and return a pointer to it.
2813*7c478bd9Sstevel@tonic-gate 	 */
2814*7c478bd9Sstevel@tonic-gate 	/* XXX - utmp - fix name length */
2815*7c478bd9Sstevel@tonic-gate 	for (ptr2 = &word[0]; ptr2 < &word[_POSIX_LOGIN_NAME_MAX - 1] &&
2816*7c478bd9Sstevel@tonic-gate 	    ptr < string; /* CSTYLED */)
2817*7c478bd9Sstevel@tonic-gate 		*ptr2++ = *ptr++;
2818*7c478bd9Sstevel@tonic-gate 
2819*7c478bd9Sstevel@tonic-gate 	*ptr2 = '\0';
2820*7c478bd9Sstevel@tonic-gate 	return (&word[0]);
2821*7c478bd9Sstevel@tonic-gate }
2822*7c478bd9Sstevel@tonic-gate 
2823*7c478bd9Sstevel@tonic-gate 
2824*7c478bd9Sstevel@tonic-gate /*
2825*7c478bd9Sstevel@tonic-gate  * realcon() returns a nonzero value if there is a character device
2826*7c478bd9Sstevel@tonic-gate  * associated with SYSCON that has the same device number as CONSOLE.
2827*7c478bd9Sstevel@tonic-gate  */
2828*7c478bd9Sstevel@tonic-gate static int
2829*7c478bd9Sstevel@tonic-gate realcon()
2830*7c478bd9Sstevel@tonic-gate {
2831*7c478bd9Sstevel@tonic-gate 	struct stat sconbuf, conbuf;
2832*7c478bd9Sstevel@tonic-gate 
2833*7c478bd9Sstevel@tonic-gate 	if (stat(SYSCON, &sconbuf) != -1 &&
2834*7c478bd9Sstevel@tonic-gate 	    stat(CONSOLE, &conbuf) != -1 &&
2835*7c478bd9Sstevel@tonic-gate 	    sconbuf.st_mode & S_IFCHR &&
2836*7c478bd9Sstevel@tonic-gate 	    conbuf.st_mode & S_IFCHR &&
2837*7c478bd9Sstevel@tonic-gate 	    sconbuf.st_rdev == conbuf.st_rdev) {
2838*7c478bd9Sstevel@tonic-gate 		return (1);
2839*7c478bd9Sstevel@tonic-gate 	} else {
2840*7c478bd9Sstevel@tonic-gate 		return (0);
2841*7c478bd9Sstevel@tonic-gate 	}
2842*7c478bd9Sstevel@tonic-gate }
2843*7c478bd9Sstevel@tonic-gate 
2844*7c478bd9Sstevel@tonic-gate 
2845*7c478bd9Sstevel@tonic-gate /*
2846*7c478bd9Sstevel@tonic-gate  * get_ioctl_syscon() retrieves the SYSCON settings from the IOCTLSYSCON file.
2847*7c478bd9Sstevel@tonic-gate  * Returns true if the IOCTLSYSCON file needs to be written (with
2848*7c478bd9Sstevel@tonic-gate  * write_ioctl_syscon() below)
2849*7c478bd9Sstevel@tonic-gate  */
2850*7c478bd9Sstevel@tonic-gate static int
2851*7c478bd9Sstevel@tonic-gate get_ioctl_syscon()
2852*7c478bd9Sstevel@tonic-gate {
2853*7c478bd9Sstevel@tonic-gate 	FILE	*fp;
2854*7c478bd9Sstevel@tonic-gate 	unsigned int	iflags, oflags, cflags, lflags, ldisc, cc[18];
2855*7c478bd9Sstevel@tonic-gate 	int		i, valid_format = 0;
2856*7c478bd9Sstevel@tonic-gate 
2857*7c478bd9Sstevel@tonic-gate 	/*
2858*7c478bd9Sstevel@tonic-gate 	 * Read in the previous modes for SYSCON from IOCTLSYSCON.
2859*7c478bd9Sstevel@tonic-gate 	 */
2860*7c478bd9Sstevel@tonic-gate 	if ((fp = fopen(IOCTLSYSCON, "r")) == NULL) {
2861*7c478bd9Sstevel@tonic-gate 		stored_syscon_termios = dflt_termios;
2862*7c478bd9Sstevel@tonic-gate 		console(B_TRUE,
2863*7c478bd9Sstevel@tonic-gate 		    "warning:%s does not exist, default settings assumed\n",
2864*7c478bd9Sstevel@tonic-gate 		    IOCTLSYSCON);
2865*7c478bd9Sstevel@tonic-gate 	} else {
2866*7c478bd9Sstevel@tonic-gate 
2867*7c478bd9Sstevel@tonic-gate 	    i = fscanf(fp,
2868*7c478bd9Sstevel@tonic-gate 	    "%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x",
2869*7c478bd9Sstevel@tonic-gate 		&iflags, &oflags, &cflags, &lflags,
2870*7c478bd9Sstevel@tonic-gate 		&cc[0], &cc[1], &cc[2], &cc[3], &cc[4], &cc[5], &cc[6],
2871*7c478bd9Sstevel@tonic-gate 		&cc[7], &cc[8], &cc[9], &cc[10], &cc[11], &cc[12], &cc[13],
2872*7c478bd9Sstevel@tonic-gate 		&cc[14], &cc[15], &cc[16], &cc[17]);
2873*7c478bd9Sstevel@tonic-gate 
2874*7c478bd9Sstevel@tonic-gate 	    if (i == 22) {
2875*7c478bd9Sstevel@tonic-gate 		stored_syscon_termios.c_iflag = iflags;
2876*7c478bd9Sstevel@tonic-gate 		stored_syscon_termios.c_oflag = oflags;
2877*7c478bd9Sstevel@tonic-gate 		stored_syscon_termios.c_cflag = cflags;
2878*7c478bd9Sstevel@tonic-gate 		stored_syscon_termios.c_lflag = lflags;
2879*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < 18; i++)
2880*7c478bd9Sstevel@tonic-gate 			stored_syscon_termios.c_cc[i] = (char)cc[i];
2881*7c478bd9Sstevel@tonic-gate 		valid_format = 1;
2882*7c478bd9Sstevel@tonic-gate 	    } else if (i == 13) {
2883*7c478bd9Sstevel@tonic-gate 		rewind(fp);
2884*7c478bd9Sstevel@tonic-gate 		i = fscanf(fp, "%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x",
2885*7c478bd9Sstevel@tonic-gate 		    &iflags, &oflags, &cflags, &lflags, &ldisc, &cc[0], &cc[1],
2886*7c478bd9Sstevel@tonic-gate 		    &cc[2], &cc[3], &cc[4], &cc[5], &cc[6], &cc[7]);
2887*7c478bd9Sstevel@tonic-gate 
2888*7c478bd9Sstevel@tonic-gate 		/*
2889*7c478bd9Sstevel@tonic-gate 		 * If the file is formatted properly, use the values to
2890*7c478bd9Sstevel@tonic-gate 		 * initialize the console terminal condition.
2891*7c478bd9Sstevel@tonic-gate 		 */
2892*7c478bd9Sstevel@tonic-gate 		stored_syscon_termios.c_iflag = (ushort_t)iflags;
2893*7c478bd9Sstevel@tonic-gate 		stored_syscon_termios.c_oflag = (ushort_t)oflags;
2894*7c478bd9Sstevel@tonic-gate 		stored_syscon_termios.c_cflag = (ushort_t)cflags;
2895*7c478bd9Sstevel@tonic-gate 		stored_syscon_termios.c_lflag = (ushort_t)lflags;
2896*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < 8; i++)
2897*7c478bd9Sstevel@tonic-gate 			stored_syscon_termios.c_cc[i] = (char)cc[i];
2898*7c478bd9Sstevel@tonic-gate 		valid_format = 1;
2899*7c478bd9Sstevel@tonic-gate 	    }
2900*7c478bd9Sstevel@tonic-gate 	    (void) fclose(fp);
2901*7c478bd9Sstevel@tonic-gate 
2902*7c478bd9Sstevel@tonic-gate 	    /* If the file is badly formatted, use the default settings. */
2903*7c478bd9Sstevel@tonic-gate 	    if (!valid_format)
2904*7c478bd9Sstevel@tonic-gate 		stored_syscon_termios = dflt_termios;
2905*7c478bd9Sstevel@tonic-gate 	}
2906*7c478bd9Sstevel@tonic-gate 
2907*7c478bd9Sstevel@tonic-gate 	/* If the file had a bad format, rewrite it later. */
2908*7c478bd9Sstevel@tonic-gate 	return (!valid_format);
2909*7c478bd9Sstevel@tonic-gate }
2910*7c478bd9Sstevel@tonic-gate 
2911*7c478bd9Sstevel@tonic-gate 
2912*7c478bd9Sstevel@tonic-gate static void
2913*7c478bd9Sstevel@tonic-gate write_ioctl_syscon()
2914*7c478bd9Sstevel@tonic-gate {
2915*7c478bd9Sstevel@tonic-gate 	FILE *fp;
2916*7c478bd9Sstevel@tonic-gate 	int i;
2917*7c478bd9Sstevel@tonic-gate 
2918*7c478bd9Sstevel@tonic-gate 	(void) unlink(SYSCON);
2919*7c478bd9Sstevel@tonic-gate 	(void) link(SYSTTY, SYSCON);
2920*7c478bd9Sstevel@tonic-gate 	(void) umask(022);
2921*7c478bd9Sstevel@tonic-gate 	fp = fopen(IOCTLSYSCON, "w");
2922*7c478bd9Sstevel@tonic-gate 
2923*7c478bd9Sstevel@tonic-gate 	(void) fprintf(fp, "%x:%x:%x:%x:0", stored_syscon_termios.c_iflag,
2924*7c478bd9Sstevel@tonic-gate 	    stored_syscon_termios.c_oflag, stored_syscon_termios.c_cflag,
2925*7c478bd9Sstevel@tonic-gate 	    stored_syscon_termios.c_lflag);
2926*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < 8; ++i)
2927*7c478bd9Sstevel@tonic-gate 		(void) fprintf(fp, ":%x", stored_syscon_termios.c_cc[i]);
2928*7c478bd9Sstevel@tonic-gate 	(void) putc('\n', fp);
2929*7c478bd9Sstevel@tonic-gate 
2930*7c478bd9Sstevel@tonic-gate 	(void) fflush(fp);
2931*7c478bd9Sstevel@tonic-gate 	(void) fsync(fileno(fp));
2932*7c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
2933*7c478bd9Sstevel@tonic-gate 	(void) umask(cmask);
2934*7c478bd9Sstevel@tonic-gate }
2935*7c478bd9Sstevel@tonic-gate 
2936*7c478bd9Sstevel@tonic-gate 
2937*7c478bd9Sstevel@tonic-gate /*
2938*7c478bd9Sstevel@tonic-gate  * void console(boolean_t, char *, ...)
2939*7c478bd9Sstevel@tonic-gate  *   Outputs the requested message to the system console.  Note that the number
2940*7c478bd9Sstevel@tonic-gate  *   of arguments passed to console() should be determined by the print format.
2941*7c478bd9Sstevel@tonic-gate  *
2942*7c478bd9Sstevel@tonic-gate  *   The "prefix" parameter indicates whether or not "INIT: " should precede the
2943*7c478bd9Sstevel@tonic-gate  *   message.
2944*7c478bd9Sstevel@tonic-gate  *
2945*7c478bd9Sstevel@tonic-gate  *   To make sure we write to the console in a sane fashion, we use the modes
2946*7c478bd9Sstevel@tonic-gate  *   we keep in stored_syscon_termios (which we read out of /etc/ioctl.syscon).
2947*7c478bd9Sstevel@tonic-gate  *   Afterwards we restore whatever modes were already there.
2948*7c478bd9Sstevel@tonic-gate  */
2949*7c478bd9Sstevel@tonic-gate /* PRINTFLIKE2 */
2950*7c478bd9Sstevel@tonic-gate static void
2951*7c478bd9Sstevel@tonic-gate console(boolean_t prefix, char *format, ...)
2952*7c478bd9Sstevel@tonic-gate {
2953*7c478bd9Sstevel@tonic-gate 	char	outbuf[BUFSIZ];
2954*7c478bd9Sstevel@tonic-gate 	va_list	args;
2955*7c478bd9Sstevel@tonic-gate 	int fd, getret;
2956*7c478bd9Sstevel@tonic-gate 	struct termios old_syscon_termios;
2957*7c478bd9Sstevel@tonic-gate 	FILE *f;
2958*7c478bd9Sstevel@tonic-gate 
2959*7c478bd9Sstevel@tonic-gate 	/*
2960*7c478bd9Sstevel@tonic-gate 	 * We open SYSCON anew each time in case it has changed (see
2961*7c478bd9Sstevel@tonic-gate 	 * userinit()).
2962*7c478bd9Sstevel@tonic-gate 	 */
2963*7c478bd9Sstevel@tonic-gate 	if ((fd = open(SYSCON, O_RDWR | O_NOCTTY)) < 0 ||
2964*7c478bd9Sstevel@tonic-gate 	    (f = fdopen(fd, "r+")) == NULL) {
2965*7c478bd9Sstevel@tonic-gate 		if (prefix)
2966*7c478bd9Sstevel@tonic-gate 			syslog(LOG_WARNING, "INIT: ");
2967*7c478bd9Sstevel@tonic-gate 		va_start(args, format);
2968*7c478bd9Sstevel@tonic-gate 		vsyslog(LOG_WARNING, format, args);
2969*7c478bd9Sstevel@tonic-gate 		va_end(args);
2970*7c478bd9Sstevel@tonic-gate 		if (fd >= 0)
2971*7c478bd9Sstevel@tonic-gate 			(void) close(fd);
2972*7c478bd9Sstevel@tonic-gate 		return;
2973*7c478bd9Sstevel@tonic-gate 	}
2974*7c478bd9Sstevel@tonic-gate 	setbuf(f, &outbuf[0]);
2975*7c478bd9Sstevel@tonic-gate 
2976*7c478bd9Sstevel@tonic-gate 	getret = tcgetattr(fd, &old_syscon_termios);
2977*7c478bd9Sstevel@tonic-gate 	old_syscon_termios.c_cflag &= ~HUPCL;
2978*7c478bd9Sstevel@tonic-gate 	if (realcon())
2979*7c478bd9Sstevel@tonic-gate 		/* Don't overwrite cflag of real console. */
2980*7c478bd9Sstevel@tonic-gate 		stored_syscon_termios.c_cflag = old_syscon_termios.c_cflag;
2981*7c478bd9Sstevel@tonic-gate 
2982*7c478bd9Sstevel@tonic-gate 	stored_syscon_termios.c_cflag &= ~HUPCL;
2983*7c478bd9Sstevel@tonic-gate 
2984*7c478bd9Sstevel@tonic-gate 	(void) tcsetattr(fd, TCSANOW, &stored_syscon_termios);
2985*7c478bd9Sstevel@tonic-gate 
2986*7c478bd9Sstevel@tonic-gate 	if (prefix)
2987*7c478bd9Sstevel@tonic-gate 		(void) fprintf(f, "\nINIT: ");
2988*7c478bd9Sstevel@tonic-gate 	va_start(args, format);
2989*7c478bd9Sstevel@tonic-gate 	(void) vfprintf(f, format, args);
2990*7c478bd9Sstevel@tonic-gate 	va_end(args);
2991*7c478bd9Sstevel@tonic-gate 
2992*7c478bd9Sstevel@tonic-gate 	if (getret == 0)
2993*7c478bd9Sstevel@tonic-gate 		(void) tcsetattr(fd, TCSADRAIN, &old_syscon_termios);
2994*7c478bd9Sstevel@tonic-gate 
2995*7c478bd9Sstevel@tonic-gate 	(void) fclose(f);
2996*7c478bd9Sstevel@tonic-gate }
2997*7c478bd9Sstevel@tonic-gate 
2998*7c478bd9Sstevel@tonic-gate /*
2999*7c478bd9Sstevel@tonic-gate  * timer() is a substitute for sleep() which uses alarm() and pause().
3000*7c478bd9Sstevel@tonic-gate  */
3001*7c478bd9Sstevel@tonic-gate static void
3002*7c478bd9Sstevel@tonic-gate timer(int waitime)
3003*7c478bd9Sstevel@tonic-gate {
3004*7c478bd9Sstevel@tonic-gate 	setimer(waitime);
3005*7c478bd9Sstevel@tonic-gate 	while (time_up == FALSE)
3006*7c478bd9Sstevel@tonic-gate 		(void) pause();
3007*7c478bd9Sstevel@tonic-gate }
3008*7c478bd9Sstevel@tonic-gate 
3009*7c478bd9Sstevel@tonic-gate static void
3010*7c478bd9Sstevel@tonic-gate setimer(int timelimit)
3011*7c478bd9Sstevel@tonic-gate {
3012*7c478bd9Sstevel@tonic-gate 	alarmclk();
3013*7c478bd9Sstevel@tonic-gate 	(void) alarm(timelimit);
3014*7c478bd9Sstevel@tonic-gate 	time_up = (timelimit ? FALSE : TRUE);
3015*7c478bd9Sstevel@tonic-gate }
3016*7c478bd9Sstevel@tonic-gate 
3017*7c478bd9Sstevel@tonic-gate /*
3018*7c478bd9Sstevel@tonic-gate  * Fails with
3019*7c478bd9Sstevel@tonic-gate  *   ENOMEM - out of memory
3020*7c478bd9Sstevel@tonic-gate  *   ECONNABORTED - repository connection broken
3021*7c478bd9Sstevel@tonic-gate  *   EPERM - permission denied
3022*7c478bd9Sstevel@tonic-gate  *   EACCES - backend access denied
3023*7c478bd9Sstevel@tonic-gate  *   EROFS - backend readonly
3024*7c478bd9Sstevel@tonic-gate  */
3025*7c478bd9Sstevel@tonic-gate static int
3026*7c478bd9Sstevel@tonic-gate get_or_add_startd(scf_instance_t *inst)
3027*7c478bd9Sstevel@tonic-gate {
3028*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h;
3029*7c478bd9Sstevel@tonic-gate 	scf_scope_t *scope = NULL;
3030*7c478bd9Sstevel@tonic-gate 	scf_service_t *svc = NULL;
3031*7c478bd9Sstevel@tonic-gate 	int ret = 0;
3032*7c478bd9Sstevel@tonic-gate 
3033*7c478bd9Sstevel@tonic-gate 	h = scf_instance_handle(inst);
3034*7c478bd9Sstevel@tonic-gate 
3035*7c478bd9Sstevel@tonic-gate 	if (scf_handle_decode_fmri(h, SCF_SERVICE_STARTD, NULL, NULL, inst,
3036*7c478bd9Sstevel@tonic-gate 	    NULL, NULL, SCF_DECODE_FMRI_EXACT) == 0)
3037*7c478bd9Sstevel@tonic-gate 		return (0);
3038*7c478bd9Sstevel@tonic-gate 
3039*7c478bd9Sstevel@tonic-gate 	switch (scf_error()) {
3040*7c478bd9Sstevel@tonic-gate 	case SCF_ERROR_CONNECTION_BROKEN:
3041*7c478bd9Sstevel@tonic-gate 		return (ECONNABORTED);
3042*7c478bd9Sstevel@tonic-gate 
3043*7c478bd9Sstevel@tonic-gate 	case SCF_ERROR_NOT_FOUND:
3044*7c478bd9Sstevel@tonic-gate 		break;
3045*7c478bd9Sstevel@tonic-gate 
3046*7c478bd9Sstevel@tonic-gate 	case SCF_ERROR_HANDLE_MISMATCH:
3047*7c478bd9Sstevel@tonic-gate 	case SCF_ERROR_INVALID_ARGUMENT:
3048*7c478bd9Sstevel@tonic-gate 	case SCF_ERROR_CONSTRAINT_VIOLATED:
3049*7c478bd9Sstevel@tonic-gate 	default:
3050*7c478bd9Sstevel@tonic-gate 		bad_error("scf_handle_decode_fmri", scf_error());
3051*7c478bd9Sstevel@tonic-gate 	}
3052*7c478bd9Sstevel@tonic-gate 
3053*7c478bd9Sstevel@tonic-gate 	/* Make sure we're right, since we're adding piece-by-piece. */
3054*7c478bd9Sstevel@tonic-gate 	assert(strcmp(SCF_SERVICE_STARTD,
3055*7c478bd9Sstevel@tonic-gate 	    "svc:/system/svc/restarter:default") == 0);
3056*7c478bd9Sstevel@tonic-gate 
3057*7c478bd9Sstevel@tonic-gate 	if ((scope = scf_scope_create(h)) == NULL ||
3058*7c478bd9Sstevel@tonic-gate 	    (svc = scf_service_create(h)) == NULL) {
3059*7c478bd9Sstevel@tonic-gate 		ret = ENOMEM;
3060*7c478bd9Sstevel@tonic-gate 		goto out;
3061*7c478bd9Sstevel@tonic-gate 	}
3062*7c478bd9Sstevel@tonic-gate 
3063*7c478bd9Sstevel@tonic-gate get_scope:
3064*7c478bd9Sstevel@tonic-gate 	if (scf_handle_get_scope(h, SCF_SCOPE_LOCAL, scope) != 0) {
3065*7c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
3066*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_CONNECTION_BROKEN:
3067*7c478bd9Sstevel@tonic-gate 			ret = ECONNABORTED;
3068*7c478bd9Sstevel@tonic-gate 			goto out;
3069*7c478bd9Sstevel@tonic-gate 
3070*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
3071*7c478bd9Sstevel@tonic-gate 			(void) fputs(gettext(
3072*7c478bd9Sstevel@tonic-gate 			    "smf(5) repository missing local scope.\n"),
3073*7c478bd9Sstevel@tonic-gate 			    stderr);
3074*7c478bd9Sstevel@tonic-gate 			exit(1);
3075*7c478bd9Sstevel@tonic-gate 			/* NOTREACHED */
3076*7c478bd9Sstevel@tonic-gate 
3077*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_HANDLE_MISMATCH:
3078*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_INVALID_ARGUMENT:
3079*7c478bd9Sstevel@tonic-gate 		default:
3080*7c478bd9Sstevel@tonic-gate 			bad_error("scf_handle_get_scope", scf_error());
3081*7c478bd9Sstevel@tonic-gate 		}
3082*7c478bd9Sstevel@tonic-gate 	}
3083*7c478bd9Sstevel@tonic-gate 
3084*7c478bd9Sstevel@tonic-gate get_svc:
3085*7c478bd9Sstevel@tonic-gate 	if (scf_scope_get_service(scope, "system/svc/restarter", svc) != 0) {
3086*7c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
3087*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_CONNECTION_BROKEN:
3088*7c478bd9Sstevel@tonic-gate 			ret = ECONNABORTED;
3089*7c478bd9Sstevel@tonic-gate 			goto out;
3090*7c478bd9Sstevel@tonic-gate 
3091*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
3092*7c478bd9Sstevel@tonic-gate 			goto get_scope;
3093*7c478bd9Sstevel@tonic-gate 
3094*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
3095*7c478bd9Sstevel@tonic-gate 			break;
3096*7c478bd9Sstevel@tonic-gate 
3097*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_HANDLE_MISMATCH:
3098*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_INVALID_ARGUMENT:
3099*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
3100*7c478bd9Sstevel@tonic-gate 		default:
3101*7c478bd9Sstevel@tonic-gate 			bad_error("scf_scope_get_service", scf_error());
3102*7c478bd9Sstevel@tonic-gate 		}
3103*7c478bd9Sstevel@tonic-gate 
3104*7c478bd9Sstevel@tonic-gate add_svc:
3105*7c478bd9Sstevel@tonic-gate 		if (scf_scope_add_service(scope, "system/svc/restarter", svc) !=
3106*7c478bd9Sstevel@tonic-gate 		    0) {
3107*7c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
3108*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
3109*7c478bd9Sstevel@tonic-gate 				ret = ECONNABORTED;
3110*7c478bd9Sstevel@tonic-gate 				goto out;
3111*7c478bd9Sstevel@tonic-gate 
3112*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_EXISTS:
3113*7c478bd9Sstevel@tonic-gate 				goto get_svc;
3114*7c478bd9Sstevel@tonic-gate 
3115*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
3116*7c478bd9Sstevel@tonic-gate 				ret = EPERM;
3117*7c478bd9Sstevel@tonic-gate 				goto out;
3118*7c478bd9Sstevel@tonic-gate 
3119*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_ACCESS:
3120*7c478bd9Sstevel@tonic-gate 				ret = EACCES;
3121*7c478bd9Sstevel@tonic-gate 				goto out;
3122*7c478bd9Sstevel@tonic-gate 
3123*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_READONLY:
3124*7c478bd9Sstevel@tonic-gate 				ret = EROFS;
3125*7c478bd9Sstevel@tonic-gate 				goto out;
3126*7c478bd9Sstevel@tonic-gate 
3127*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_HANDLE_MISMATCH:
3128*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_INVALID_ARGUMENT:
3129*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
3130*7c478bd9Sstevel@tonic-gate 			default:
3131*7c478bd9Sstevel@tonic-gate 				bad_error("scf_scope_add_service", scf_error());
3132*7c478bd9Sstevel@tonic-gate 			}
3133*7c478bd9Sstevel@tonic-gate 		}
3134*7c478bd9Sstevel@tonic-gate 	}
3135*7c478bd9Sstevel@tonic-gate 
3136*7c478bd9Sstevel@tonic-gate get_inst:
3137*7c478bd9Sstevel@tonic-gate 	if (scf_service_get_instance(svc, "default", inst) != 0) {
3138*7c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
3139*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_CONNECTION_BROKEN:
3140*7c478bd9Sstevel@tonic-gate 			ret = ECONNABORTED;
3141*7c478bd9Sstevel@tonic-gate 			goto out;
3142*7c478bd9Sstevel@tonic-gate 
3143*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
3144*7c478bd9Sstevel@tonic-gate 			goto add_svc;
3145*7c478bd9Sstevel@tonic-gate 
3146*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
3147*7c478bd9Sstevel@tonic-gate 			break;
3148*7c478bd9Sstevel@tonic-gate 
3149*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_HANDLE_MISMATCH:
3150*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_INVALID_ARGUMENT:
3151*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
3152*7c478bd9Sstevel@tonic-gate 		default:
3153*7c478bd9Sstevel@tonic-gate 			bad_error("scf_service_get_instance", scf_error());
3154*7c478bd9Sstevel@tonic-gate 		}
3155*7c478bd9Sstevel@tonic-gate 
3156*7c478bd9Sstevel@tonic-gate 		if (scf_service_add_instance(svc, "default", inst) !=
3157*7c478bd9Sstevel@tonic-gate 		    0) {
3158*7c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
3159*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
3160*7c478bd9Sstevel@tonic-gate 				ret = ECONNABORTED;
3161*7c478bd9Sstevel@tonic-gate 				goto out;
3162*7c478bd9Sstevel@tonic-gate 
3163*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_DELETED:
3164*7c478bd9Sstevel@tonic-gate 				goto add_svc;
3165*7c478bd9Sstevel@tonic-gate 
3166*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_EXISTS:
3167*7c478bd9Sstevel@tonic-gate 				goto get_inst;
3168*7c478bd9Sstevel@tonic-gate 
3169*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
3170*7c478bd9Sstevel@tonic-gate 				ret = EPERM;
3171*7c478bd9Sstevel@tonic-gate 				goto out;
3172*7c478bd9Sstevel@tonic-gate 
3173*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_ACCESS:
3174*7c478bd9Sstevel@tonic-gate 				ret = EACCES;
3175*7c478bd9Sstevel@tonic-gate 				goto out;
3176*7c478bd9Sstevel@tonic-gate 
3177*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_READONLY:
3178*7c478bd9Sstevel@tonic-gate 				ret = EROFS;
3179*7c478bd9Sstevel@tonic-gate 				goto out;
3180*7c478bd9Sstevel@tonic-gate 
3181*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_HANDLE_MISMATCH:
3182*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_INVALID_ARGUMENT:
3183*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
3184*7c478bd9Sstevel@tonic-gate 			default:
3185*7c478bd9Sstevel@tonic-gate 				bad_error("scf_service_add_instance",
3186*7c478bd9Sstevel@tonic-gate 				    scf_error());
3187*7c478bd9Sstevel@tonic-gate 			}
3188*7c478bd9Sstevel@tonic-gate 		}
3189*7c478bd9Sstevel@tonic-gate 	}
3190*7c478bd9Sstevel@tonic-gate 
3191*7c478bd9Sstevel@tonic-gate 	ret = 0;
3192*7c478bd9Sstevel@tonic-gate 
3193*7c478bd9Sstevel@tonic-gate out:
3194*7c478bd9Sstevel@tonic-gate 	scf_service_destroy(svc);
3195*7c478bd9Sstevel@tonic-gate 	scf_scope_destroy(scope);
3196*7c478bd9Sstevel@tonic-gate 	return (ret);
3197*7c478bd9Sstevel@tonic-gate }
3198*7c478bd9Sstevel@tonic-gate 
3199*7c478bd9Sstevel@tonic-gate /*
3200*7c478bd9Sstevel@tonic-gate  * Fails with
3201*7c478bd9Sstevel@tonic-gate  *   ECONNABORTED - repository connection broken
3202*7c478bd9Sstevel@tonic-gate  *   ECANCELED - the transaction's property group was deleted
3203*7c478bd9Sstevel@tonic-gate  */
3204*7c478bd9Sstevel@tonic-gate static int
3205*7c478bd9Sstevel@tonic-gate transaction_add_set(scf_transaction_t *tx, scf_transaction_entry_t *ent,
3206*7c478bd9Sstevel@tonic-gate     const char *pname, scf_type_t type)
3207*7c478bd9Sstevel@tonic-gate {
3208*7c478bd9Sstevel@tonic-gate change_type:
3209*7c478bd9Sstevel@tonic-gate 	if (scf_transaction_property_change_type(tx, ent, pname, type) == 0)
3210*7c478bd9Sstevel@tonic-gate 		return (0);
3211*7c478bd9Sstevel@tonic-gate 
3212*7c478bd9Sstevel@tonic-gate 	switch (scf_error()) {
3213*7c478bd9Sstevel@tonic-gate 	case SCF_ERROR_CONNECTION_BROKEN:
3214*7c478bd9Sstevel@tonic-gate 		return (ECONNABORTED);
3215*7c478bd9Sstevel@tonic-gate 
3216*7c478bd9Sstevel@tonic-gate 	case SCF_ERROR_DELETED:
3217*7c478bd9Sstevel@tonic-gate 		return (ECANCELED);
3218*7c478bd9Sstevel@tonic-gate 
3219*7c478bd9Sstevel@tonic-gate 	case SCF_ERROR_NOT_FOUND:
3220*7c478bd9Sstevel@tonic-gate 		goto new;
3221*7c478bd9Sstevel@tonic-gate 
3222*7c478bd9Sstevel@tonic-gate 	case SCF_ERROR_HANDLE_MISMATCH:
3223*7c478bd9Sstevel@tonic-gate 	case SCF_ERROR_INVALID_ARGUMENT:
3224*7c478bd9Sstevel@tonic-gate 	case SCF_ERROR_NOT_BOUND:
3225*7c478bd9Sstevel@tonic-gate 	case SCF_ERROR_NOT_SET:
3226*7c478bd9Sstevel@tonic-gate 	default:
3227*7c478bd9Sstevel@tonic-gate 		bad_error("scf_transaction_property_change_type", scf_error());
3228*7c478bd9Sstevel@tonic-gate 	}
3229*7c478bd9Sstevel@tonic-gate 
3230*7c478bd9Sstevel@tonic-gate new:
3231*7c478bd9Sstevel@tonic-gate 	if (scf_transaction_property_new(tx, ent, pname, type) == 0)
3232*7c478bd9Sstevel@tonic-gate 		return (0);
3233*7c478bd9Sstevel@tonic-gate 
3234*7c478bd9Sstevel@tonic-gate 	switch (scf_error()) {
3235*7c478bd9Sstevel@tonic-gate 	case SCF_ERROR_CONNECTION_BROKEN:
3236*7c478bd9Sstevel@tonic-gate 		return (ECONNABORTED);
3237*7c478bd9Sstevel@tonic-gate 
3238*7c478bd9Sstevel@tonic-gate 	case SCF_ERROR_DELETED:
3239*7c478bd9Sstevel@tonic-gate 		return (ECANCELED);
3240*7c478bd9Sstevel@tonic-gate 
3241*7c478bd9Sstevel@tonic-gate 	case SCF_ERROR_EXISTS:
3242*7c478bd9Sstevel@tonic-gate 		goto change_type;
3243*7c478bd9Sstevel@tonic-gate 
3244*7c478bd9Sstevel@tonic-gate 	case SCF_ERROR_HANDLE_MISMATCH:
3245*7c478bd9Sstevel@tonic-gate 	case SCF_ERROR_INVALID_ARGUMENT:
3246*7c478bd9Sstevel@tonic-gate 	case SCF_ERROR_NOT_BOUND:
3247*7c478bd9Sstevel@tonic-gate 	case SCF_ERROR_NOT_SET:
3248*7c478bd9Sstevel@tonic-gate 	default:
3249*7c478bd9Sstevel@tonic-gate 		bad_error("scf_transaction_property_new", scf_error());
3250*7c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
3251*7c478bd9Sstevel@tonic-gate 	}
3252*7c478bd9Sstevel@tonic-gate }
3253*7c478bd9Sstevel@tonic-gate 
3254*7c478bd9Sstevel@tonic-gate static void
3255*7c478bd9Sstevel@tonic-gate scferr(void)
3256*7c478bd9Sstevel@tonic-gate {
3257*7c478bd9Sstevel@tonic-gate 	switch (scf_error()) {
3258*7c478bd9Sstevel@tonic-gate 	case SCF_ERROR_NO_MEMORY:
3259*7c478bd9Sstevel@tonic-gate 		console(B_TRUE, gettext("Out of memory.\n"));
3260*7c478bd9Sstevel@tonic-gate 		break;
3261*7c478bd9Sstevel@tonic-gate 
3262*7c478bd9Sstevel@tonic-gate 	case SCF_ERROR_CONNECTION_BROKEN:
3263*7c478bd9Sstevel@tonic-gate 		console(B_TRUE, gettext(
3264*7c478bd9Sstevel@tonic-gate 		    "Connection to smf(5) repository server broken.\n"));
3265*7c478bd9Sstevel@tonic-gate 		break;
3266*7c478bd9Sstevel@tonic-gate 
3267*7c478bd9Sstevel@tonic-gate 	case SCF_ERROR_NO_RESOURCES:
3268*7c478bd9Sstevel@tonic-gate 		console(B_TRUE, gettext(
3269*7c478bd9Sstevel@tonic-gate 		    "smf(5) repository server is out of memory.\n"));
3270*7c478bd9Sstevel@tonic-gate 		break;
3271*7c478bd9Sstevel@tonic-gate 
3272*7c478bd9Sstevel@tonic-gate 	case SCF_ERROR_PERMISSION_DENIED:
3273*7c478bd9Sstevel@tonic-gate 		console(B_TRUE, gettext("Insufficient privileges.\n"));
3274*7c478bd9Sstevel@tonic-gate 		break;
3275*7c478bd9Sstevel@tonic-gate 
3276*7c478bd9Sstevel@tonic-gate 	default:
3277*7c478bd9Sstevel@tonic-gate 		console(B_TRUE, gettext("libscf error: %s\n"),
3278*7c478bd9Sstevel@tonic-gate 		    scf_strerror(scf_error()));
3279*7c478bd9Sstevel@tonic-gate 	}
3280*7c478bd9Sstevel@tonic-gate }
3281*7c478bd9Sstevel@tonic-gate 
3282*7c478bd9Sstevel@tonic-gate static void
3283*7c478bd9Sstevel@tonic-gate lscf_set_runlevel(char rl)
3284*7c478bd9Sstevel@tonic-gate {
3285*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h;
3286*7c478bd9Sstevel@tonic-gate 	scf_instance_t *inst = NULL;
3287*7c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg = NULL;
3288*7c478bd9Sstevel@tonic-gate 	scf_transaction_t *tx = NULL;
3289*7c478bd9Sstevel@tonic-gate 	scf_transaction_entry_t *ent = NULL;
3290*7c478bd9Sstevel@tonic-gate 	scf_value_t *val = NULL;
3291*7c478bd9Sstevel@tonic-gate 	char buf[2];
3292*7c478bd9Sstevel@tonic-gate 	int r;
3293*7c478bd9Sstevel@tonic-gate 
3294*7c478bd9Sstevel@tonic-gate 	h = scf_handle_create(SCF_VERSION);
3295*7c478bd9Sstevel@tonic-gate 	if (h == NULL) {
3296*7c478bd9Sstevel@tonic-gate 		scferr();
3297*7c478bd9Sstevel@tonic-gate 		return;
3298*7c478bd9Sstevel@tonic-gate 	}
3299*7c478bd9Sstevel@tonic-gate 
3300*7c478bd9Sstevel@tonic-gate 	if (scf_handle_bind(h) != 0) {
3301*7c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
3302*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NO_SERVER:
3303*7c478bd9Sstevel@tonic-gate 			console(B_TRUE,
3304*7c478bd9Sstevel@tonic-gate 			    gettext("smf(5) repository server not running.\n"));
3305*7c478bd9Sstevel@tonic-gate 			goto bail;
3306*7c478bd9Sstevel@tonic-gate 
3307*7c478bd9Sstevel@tonic-gate 		default:
3308*7c478bd9Sstevel@tonic-gate 			scferr();
3309*7c478bd9Sstevel@tonic-gate 			goto bail;
3310*7c478bd9Sstevel@tonic-gate 		}
3311*7c478bd9Sstevel@tonic-gate 	}
3312*7c478bd9Sstevel@tonic-gate 
3313*7c478bd9Sstevel@tonic-gate 	if ((inst = scf_instance_create(h)) == NULL ||
3314*7c478bd9Sstevel@tonic-gate 	    (pg = scf_pg_create(h)) == NULL ||
3315*7c478bd9Sstevel@tonic-gate 	    (val = scf_value_create(h)) == NULL ||
3316*7c478bd9Sstevel@tonic-gate 	    (tx = scf_transaction_create(h)) == NULL ||
3317*7c478bd9Sstevel@tonic-gate 	    (ent = scf_entry_create(h)) == NULL) {
3318*7c478bd9Sstevel@tonic-gate 		scferr();
3319*7c478bd9Sstevel@tonic-gate 		goto bail;
3320*7c478bd9Sstevel@tonic-gate 	}
3321*7c478bd9Sstevel@tonic-gate 
3322*7c478bd9Sstevel@tonic-gate get_inst:
3323*7c478bd9Sstevel@tonic-gate 	r = get_or_add_startd(inst);
3324*7c478bd9Sstevel@tonic-gate 	switch (r) {
3325*7c478bd9Sstevel@tonic-gate 	case 0:
3326*7c478bd9Sstevel@tonic-gate 		break;
3327*7c478bd9Sstevel@tonic-gate 
3328*7c478bd9Sstevel@tonic-gate 	case ENOMEM:
3329*7c478bd9Sstevel@tonic-gate 	case ECONNABORTED:
3330*7c478bd9Sstevel@tonic-gate 	case EPERM:
3331*7c478bd9Sstevel@tonic-gate 	case EACCES:
3332*7c478bd9Sstevel@tonic-gate 	case EROFS:
3333*7c478bd9Sstevel@tonic-gate 		scferr();
3334*7c478bd9Sstevel@tonic-gate 		goto bail;
3335*7c478bd9Sstevel@tonic-gate 	default:
3336*7c478bd9Sstevel@tonic-gate 		bad_error("get_or_add_startd", r);
3337*7c478bd9Sstevel@tonic-gate 	}
3338*7c478bd9Sstevel@tonic-gate 
3339*7c478bd9Sstevel@tonic-gate get_pg:
3340*7c478bd9Sstevel@tonic-gate 	if (scf_instance_get_pg(inst, SCF_PG_OPTIONS_OVR, pg) != 0) {
3341*7c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
3342*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_CONNECTION_BROKEN:
3343*7c478bd9Sstevel@tonic-gate 			scferr();
3344*7c478bd9Sstevel@tonic-gate 			goto bail;
3345*7c478bd9Sstevel@tonic-gate 
3346*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
3347*7c478bd9Sstevel@tonic-gate 			goto get_inst;
3348*7c478bd9Sstevel@tonic-gate 
3349*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
3350*7c478bd9Sstevel@tonic-gate 			break;
3351*7c478bd9Sstevel@tonic-gate 
3352*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_HANDLE_MISMATCH:
3353*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_INVALID_ARGUMENT:
3354*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
3355*7c478bd9Sstevel@tonic-gate 		default:
3356*7c478bd9Sstevel@tonic-gate 			bad_error("scf_instance_get_pg", scf_error());
3357*7c478bd9Sstevel@tonic-gate 		}
3358*7c478bd9Sstevel@tonic-gate 
3359*7c478bd9Sstevel@tonic-gate add_pg:
3360*7c478bd9Sstevel@tonic-gate 		if (scf_instance_add_pg(inst, SCF_PG_OPTIONS_OVR,
3361*7c478bd9Sstevel@tonic-gate 		    SCF_PG_OPTIONS_OVR_TYPE, SCF_PG_OPTIONS_OVR_FLAGS, pg) !=
3362*7c478bd9Sstevel@tonic-gate 		    0) {
3363*7c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
3364*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
3365*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
3366*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_ACCESS:
3367*7c478bd9Sstevel@tonic-gate 				scferr();
3368*7c478bd9Sstevel@tonic-gate 				goto bail;
3369*7c478bd9Sstevel@tonic-gate 
3370*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_DELETED:
3371*7c478bd9Sstevel@tonic-gate 				goto get_inst;
3372*7c478bd9Sstevel@tonic-gate 
3373*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_EXISTS:
3374*7c478bd9Sstevel@tonic-gate 				goto get_pg;
3375*7c478bd9Sstevel@tonic-gate 
3376*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_HANDLE_MISMATCH:
3377*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_INVALID_ARGUMENT:
3378*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
3379*7c478bd9Sstevel@tonic-gate 			default:
3380*7c478bd9Sstevel@tonic-gate 				bad_error("scf_instance_add_pg", scf_error());
3381*7c478bd9Sstevel@tonic-gate 			}
3382*7c478bd9Sstevel@tonic-gate 		}
3383*7c478bd9Sstevel@tonic-gate 	}
3384*7c478bd9Sstevel@tonic-gate 
3385*7c478bd9Sstevel@tonic-gate 	buf[0] = rl;
3386*7c478bd9Sstevel@tonic-gate 	buf[1] = '\0';
3387*7c478bd9Sstevel@tonic-gate 	r = scf_value_set_astring(val, buf);
3388*7c478bd9Sstevel@tonic-gate 	assert(r == 0);
3389*7c478bd9Sstevel@tonic-gate 
3390*7c478bd9Sstevel@tonic-gate 	for (;;) {
3391*7c478bd9Sstevel@tonic-gate 		if (scf_transaction_start(tx, pg) != 0) {
3392*7c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
3393*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
3394*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
3395*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_ACCESS:
3396*7c478bd9Sstevel@tonic-gate 				scferr();
3397*7c478bd9Sstevel@tonic-gate 				goto bail;
3398*7c478bd9Sstevel@tonic-gate 
3399*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_DELETED:
3400*7c478bd9Sstevel@tonic-gate 				goto add_pg;
3401*7c478bd9Sstevel@tonic-gate 
3402*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_HANDLE_MISMATCH:
3403*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_BOUND:
3404*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_IN_USE:
3405*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
3406*7c478bd9Sstevel@tonic-gate 			default:
3407*7c478bd9Sstevel@tonic-gate 				bad_error("scf_transaction_start", scf_error());
3408*7c478bd9Sstevel@tonic-gate 			}
3409*7c478bd9Sstevel@tonic-gate 		}
3410*7c478bd9Sstevel@tonic-gate 
3411*7c478bd9Sstevel@tonic-gate 		r = transaction_add_set(tx, ent, "runlevel", SCF_TYPE_ASTRING);
3412*7c478bd9Sstevel@tonic-gate 		switch (r) {
3413*7c478bd9Sstevel@tonic-gate 		case 0:
3414*7c478bd9Sstevel@tonic-gate 			break;
3415*7c478bd9Sstevel@tonic-gate 
3416*7c478bd9Sstevel@tonic-gate 		case ECONNABORTED:
3417*7c478bd9Sstevel@tonic-gate 			scferr();
3418*7c478bd9Sstevel@tonic-gate 			goto bail;
3419*7c478bd9Sstevel@tonic-gate 
3420*7c478bd9Sstevel@tonic-gate 		case ECANCELED:
3421*7c478bd9Sstevel@tonic-gate 			scf_transaction_reset(tx);
3422*7c478bd9Sstevel@tonic-gate 			goto add_pg;
3423*7c478bd9Sstevel@tonic-gate 
3424*7c478bd9Sstevel@tonic-gate 		default:
3425*7c478bd9Sstevel@tonic-gate 			bad_error("transaction_add_set", r);
3426*7c478bd9Sstevel@tonic-gate 		}
3427*7c478bd9Sstevel@tonic-gate 
3428*7c478bd9Sstevel@tonic-gate 		r = scf_entry_add_value(ent, val);
3429*7c478bd9Sstevel@tonic-gate 		assert(r == 0);
3430*7c478bd9Sstevel@tonic-gate 
3431*7c478bd9Sstevel@tonic-gate 		r = scf_transaction_commit(tx);
3432*7c478bd9Sstevel@tonic-gate 		if (r == 1)
3433*7c478bd9Sstevel@tonic-gate 			break;
3434*7c478bd9Sstevel@tonic-gate 
3435*7c478bd9Sstevel@tonic-gate 		if (r != 0) {
3436*7c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
3437*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
3438*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
3439*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_ACCESS:
3440*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_READONLY:
3441*7c478bd9Sstevel@tonic-gate 				scferr();
3442*7c478bd9Sstevel@tonic-gate 				goto bail;
3443*7c478bd9Sstevel@tonic-gate 
3444*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_DELETED:
3445*7c478bd9Sstevel@tonic-gate 				scf_transaction_reset(tx);
3446*7c478bd9Sstevel@tonic-gate 				goto add_pg;
3447*7c478bd9Sstevel@tonic-gate 
3448*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_INVALID_ARGUMENT:
3449*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_BOUND:
3450*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
3451*7c478bd9Sstevel@tonic-gate 			default:
3452*7c478bd9Sstevel@tonic-gate 				bad_error("scf_transaction_commit",
3453*7c478bd9Sstevel@tonic-gate 				    scf_error());
3454*7c478bd9Sstevel@tonic-gate 			}
3455*7c478bd9Sstevel@tonic-gate 		}
3456*7c478bd9Sstevel@tonic-gate 
3457*7c478bd9Sstevel@tonic-gate 		scf_transaction_reset(tx);
3458*7c478bd9Sstevel@tonic-gate 		(void) scf_pg_update(pg);
3459*7c478bd9Sstevel@tonic-gate 	}
3460*7c478bd9Sstevel@tonic-gate 
3461*7c478bd9Sstevel@tonic-gate bail:
3462*7c478bd9Sstevel@tonic-gate 	scf_transaction_destroy(tx);
3463*7c478bd9Sstevel@tonic-gate 	scf_entry_destroy(ent);
3464*7c478bd9Sstevel@tonic-gate 	scf_value_destroy(val);
3465*7c478bd9Sstevel@tonic-gate 	scf_pg_destroy(pg);
3466*7c478bd9Sstevel@tonic-gate 	scf_instance_destroy(inst);
3467*7c478bd9Sstevel@tonic-gate 
3468*7c478bd9Sstevel@tonic-gate 	(void) scf_handle_unbind(h);
3469*7c478bd9Sstevel@tonic-gate 	scf_handle_destroy(h);
3470*7c478bd9Sstevel@tonic-gate }
3471*7c478bd9Sstevel@tonic-gate 
3472*7c478bd9Sstevel@tonic-gate /*
3473*7c478bd9Sstevel@tonic-gate  * Function to handle requests from users to main init running as process 1.
3474*7c478bd9Sstevel@tonic-gate  */
3475*7c478bd9Sstevel@tonic-gate static void
3476*7c478bd9Sstevel@tonic-gate userinit(int argc, char **argv)
3477*7c478bd9Sstevel@tonic-gate {
3478*7c478bd9Sstevel@tonic-gate 	FILE	*fp;
3479*7c478bd9Sstevel@tonic-gate 	char	*ln;
3480*7c478bd9Sstevel@tonic-gate 	int	init_signal;
3481*7c478bd9Sstevel@tonic-gate 	struct stat	sconbuf, conbuf;
3482*7c478bd9Sstevel@tonic-gate 	int turnoff = 0;
3483*7c478bd9Sstevel@tonic-gate 	const char *usage_msg = "Usage: init [0123456SsQqabc]\n";
3484*7c478bd9Sstevel@tonic-gate 
3485*7c478bd9Sstevel@tonic-gate 	/*
3486*7c478bd9Sstevel@tonic-gate 	 * We are a user invoked init.  Is there an argument and is it
3487*7c478bd9Sstevel@tonic-gate 	 * a single character?  If not, print usage message and quit.
3488*7c478bd9Sstevel@tonic-gate 	 */
3489*7c478bd9Sstevel@tonic-gate 	if (argc != 2 || argv[1][1] != '\0') {
3490*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, usage_msg);
3491*7c478bd9Sstevel@tonic-gate 		exit(0);
3492*7c478bd9Sstevel@tonic-gate 	}
3493*7c478bd9Sstevel@tonic-gate 
3494*7c478bd9Sstevel@tonic-gate 	if ((init_signal = lvlname_to_state((char)argv[1][0])) == -1) {
3495*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, usage_msg);
3496*7c478bd9Sstevel@tonic-gate 		(void) audit_put_record(ADT_FAILURE, ADT_FAIL_VALUE_BAD_CMD,
3497*7c478bd9Sstevel@tonic-gate 		    argv[1]);
3498*7c478bd9Sstevel@tonic-gate 		exit(1);
3499*7c478bd9Sstevel@tonic-gate 	}
3500*7c478bd9Sstevel@tonic-gate 
3501*7c478bd9Sstevel@tonic-gate 	turnoff = LSEL_NOAUDIT & state_to_flags(init_signal);
3502*7c478bd9Sstevel@tonic-gate 
3503*7c478bd9Sstevel@tonic-gate 	if (init_signal == SINGLE_USER) {
3504*7c478bd9Sstevel@tonic-gate 		/*
3505*7c478bd9Sstevel@tonic-gate 		 * Make sure this process is talking to a legal tty line
3506*7c478bd9Sstevel@tonic-gate 		 * and that /dev/syscon is linked to this line.
3507*7c478bd9Sstevel@tonic-gate 		 */
3508*7c478bd9Sstevel@tonic-gate 		ln = ttyname(0);	/* Get the name of tty */
3509*7c478bd9Sstevel@tonic-gate 		if (ln == NULL) {
3510*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
3511*7c478bd9Sstevel@tonic-gate 			    "Standard input not a tty line\n");
3512*7c478bd9Sstevel@tonic-gate 			(void) audit_put_record(ADT_FAILURE,
3513*7c478bd9Sstevel@tonic-gate 			    ADT_FAIL_VALUE_BAD_TTY, argv[1]);
3514*7c478bd9Sstevel@tonic-gate 			exit(1);
3515*7c478bd9Sstevel@tonic-gate 		}
3516*7c478bd9Sstevel@tonic-gate 		if (stat(ln, &sconbuf) != -1 &&
3517*7c478bd9Sstevel@tonic-gate 		    stat(SYSCON, &conbuf) != -1 &&
3518*7c478bd9Sstevel@tonic-gate 		    sconbuf.st_rdev != conbuf.st_rdev &&
3519*7c478bd9Sstevel@tonic-gate 		    sconbuf.st_ino != conbuf.st_ino) {
3520*7c478bd9Sstevel@tonic-gate 			/*
3521*7c478bd9Sstevel@tonic-gate 			 * Unlink /dev/syscon and relink it to the current line.
3522*7c478bd9Sstevel@tonic-gate 			 */
3523*7c478bd9Sstevel@tonic-gate 			if (unlink(SYSCON) == FAILURE) {
3524*7c478bd9Sstevel@tonic-gate 				perror("Can't unlink /dev/syscon");
3525*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
3526*7c478bd9Sstevel@tonic-gate 				    "Run command on the system console.\n");
3527*7c478bd9Sstevel@tonic-gate 				(void) audit_put_record(ADT_FAILURE,
3528*7c478bd9Sstevel@tonic-gate 				    ADT_FAIL_VALUE_PROGRAM, argv[1]);
3529*7c478bd9Sstevel@tonic-gate 				exit(1);
3530*7c478bd9Sstevel@tonic-gate 			}
3531*7c478bd9Sstevel@tonic-gate 			if (link(ln, SYSCON) == FAILURE) {
3532*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
3533*7c478bd9Sstevel@tonic-gate 				    "Can't link /dev/syscon to %s: %s", ln,
3534*7c478bd9Sstevel@tonic-gate 				    strerror(errno));
3535*7c478bd9Sstevel@tonic-gate 
3536*7c478bd9Sstevel@tonic-gate 				/* Try to leave a syscon */
3537*7c478bd9Sstevel@tonic-gate 				(void) link(SYSTTY, SYSCON);
3538*7c478bd9Sstevel@tonic-gate 				(void) audit_put_record(ADT_FAILURE,
3539*7c478bd9Sstevel@tonic-gate 				    ADT_FAIL_VALUE_PROGRAM, argv[1]);
3540*7c478bd9Sstevel@tonic-gate 				exit(1);
3541*7c478bd9Sstevel@tonic-gate 			}
3542*7c478bd9Sstevel@tonic-gate 
3543*7c478bd9Sstevel@tonic-gate 			/*
3544*7c478bd9Sstevel@tonic-gate 			 * Try to leave a message on system console saying where
3545*7c478bd9Sstevel@tonic-gate 			 * /dev/syscon is currently connected.
3546*7c478bd9Sstevel@tonic-gate 			 */
3547*7c478bd9Sstevel@tonic-gate 			if ((fp = fopen(SYSTTY, "r+")) != NULL) {
3548*7c478bd9Sstevel@tonic-gate 				(void) fprintf(fp,
3549*7c478bd9Sstevel@tonic-gate 				    "\n****	SYSCON CHANGED TO %s	****\n",
3550*7c478bd9Sstevel@tonic-gate 				    ln);
3551*7c478bd9Sstevel@tonic-gate 				(void) fclose(fp);
3552*7c478bd9Sstevel@tonic-gate 			}
3553*7c478bd9Sstevel@tonic-gate 		}
3554*7c478bd9Sstevel@tonic-gate 	}
3555*7c478bd9Sstevel@tonic-gate 
3556*7c478bd9Sstevel@tonic-gate 	update_boot_archive(init_signal);
3557*7c478bd9Sstevel@tonic-gate 
3558*7c478bd9Sstevel@tonic-gate 	if (audit_put_record(ADT_SUCCESS, ADT_SUCCESS, argv[1]) &&
3559*7c478bd9Sstevel@tonic-gate 	    turnoff) {
3560*7c478bd9Sstevel@tonic-gate 		/* turn off audit daemon and try to flush audit queue */
3561*7c478bd9Sstevel@tonic-gate 
3562*7c478bd9Sstevel@tonic-gate 		if (system("/usr/sbin/audit -t")) {
3563*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: can't turn off auditd\n",
3564*7c478bd9Sstevel@tonic-gate 				argv[0]);
3565*7c478bd9Sstevel@tonic-gate 		} else {
3566*7c478bd9Sstevel@tonic-gate 			(void) sleep(5);
3567*7c478bd9Sstevel@tonic-gate 		}
3568*7c478bd9Sstevel@tonic-gate 	}
3569*7c478bd9Sstevel@tonic-gate 
3570*7c478bd9Sstevel@tonic-gate 	/*
3571*7c478bd9Sstevel@tonic-gate 	 * Signal init; init will take care of telling svc.startd.
3572*7c478bd9Sstevel@tonic-gate 	 */
3573*7c478bd9Sstevel@tonic-gate 	if (kill(init_pid, init_signal) == FAILURE) {
3574*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "Must be super-user\n");
3575*7c478bd9Sstevel@tonic-gate 		(void) audit_put_record(ADT_FAILURE,
3576*7c478bd9Sstevel@tonic-gate 		    ADT_FAIL_VALUE_AUTH, argv[1]);
3577*7c478bd9Sstevel@tonic-gate 		exit(1);
3578*7c478bd9Sstevel@tonic-gate 	}
3579*7c478bd9Sstevel@tonic-gate 
3580*7c478bd9Sstevel@tonic-gate 	exit(0);
3581*7c478bd9Sstevel@tonic-gate }
3582*7c478bd9Sstevel@tonic-gate 
3583*7c478bd9Sstevel@tonic-gate 
3584*7c478bd9Sstevel@tonic-gate #define	DELTA	25	/* Number of pidlist elements to allocate at a time */
3585*7c478bd9Sstevel@tonic-gate 
3586*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
3587*7c478bd9Sstevel@tonic-gate void
3588*7c478bd9Sstevel@tonic-gate sigpoll(int n)
3589*7c478bd9Sstevel@tonic-gate {
3590*7c478bd9Sstevel@tonic-gate 	struct pidrec prec;
3591*7c478bd9Sstevel@tonic-gate 	struct pidrec *p = &prec;
3592*7c478bd9Sstevel@tonic-gate 	struct pidlist *plp;
3593*7c478bd9Sstevel@tonic-gate 	struct pidlist *tp, *savetp;
3594*7c478bd9Sstevel@tonic-gate 	int i;
3595*7c478bd9Sstevel@tonic-gate 
3596*7c478bd9Sstevel@tonic-gate 	if (Pfd < 0) {
3597*7c478bd9Sstevel@tonic-gate 		return;
3598*7c478bd9Sstevel@tonic-gate 	}
3599*7c478bd9Sstevel@tonic-gate 	(void) sigset(SIGCLD, SIG_DFL);
3600*7c478bd9Sstevel@tonic-gate 	for (;;) {
3601*7c478bd9Sstevel@tonic-gate 		/*
3602*7c478bd9Sstevel@tonic-gate 		 * Important Note: Either read will really fail (in which case
3603*7c478bd9Sstevel@tonic-gate 		 * return is all we can do) or will get EAGAIN (Pfd was opened
3604*7c478bd9Sstevel@tonic-gate 		 * O_NDELAY), in which case we also want to return.
3605*7c478bd9Sstevel@tonic-gate 		 * Always return from here!
3606*7c478bd9Sstevel@tonic-gate 		 */
3607*7c478bd9Sstevel@tonic-gate 		if (read(Pfd, p, sizeof (struct pidrec)) !=
3608*7c478bd9Sstevel@tonic-gate 						sizeof (struct pidrec)) {
3609*7c478bd9Sstevel@tonic-gate 			(void) sigset(SIGCLD, childeath);
3610*7c478bd9Sstevel@tonic-gate 			return;
3611*7c478bd9Sstevel@tonic-gate 		}
3612*7c478bd9Sstevel@tonic-gate 		switch (p->pd_type) {
3613*7c478bd9Sstevel@tonic-gate 
3614*7c478bd9Sstevel@tonic-gate 		case ADDPID:
3615*7c478bd9Sstevel@tonic-gate 			/*
3616*7c478bd9Sstevel@tonic-gate 			 * New "godchild", add to list.
3617*7c478bd9Sstevel@tonic-gate 			 */
3618*7c478bd9Sstevel@tonic-gate 			if (Plfree == NULL) {
3619*7c478bd9Sstevel@tonic-gate 				plp = (struct pidlist *)calloc(DELTA,
3620*7c478bd9Sstevel@tonic-gate 				    sizeof (struct pidlist));
3621*7c478bd9Sstevel@tonic-gate 				if (plp == NULL) {
3622*7c478bd9Sstevel@tonic-gate 					/* Can't save pid */
3623*7c478bd9Sstevel@tonic-gate 					break;
3624*7c478bd9Sstevel@tonic-gate 				}
3625*7c478bd9Sstevel@tonic-gate 				/*
3626*7c478bd9Sstevel@tonic-gate 				 * Point at 2nd record allocated, we'll use plp.
3627*7c478bd9Sstevel@tonic-gate 				 */
3628*7c478bd9Sstevel@tonic-gate 				tp = plp + 1;
3629*7c478bd9Sstevel@tonic-gate 				/*
3630*7c478bd9Sstevel@tonic-gate 				 * Link them into a chain.
3631*7c478bd9Sstevel@tonic-gate 				 */
3632*7c478bd9Sstevel@tonic-gate 				Plfree = tp;
3633*7c478bd9Sstevel@tonic-gate 				for (i = 0; i < DELTA - 2; i++) {
3634*7c478bd9Sstevel@tonic-gate 					tp->pl_next = tp + 1;
3635*7c478bd9Sstevel@tonic-gate 					tp++;
3636*7c478bd9Sstevel@tonic-gate 				}
3637*7c478bd9Sstevel@tonic-gate 			} else {
3638*7c478bd9Sstevel@tonic-gate 				plp = Plfree;
3639*7c478bd9Sstevel@tonic-gate 				Plfree = plp->pl_next;
3640*7c478bd9Sstevel@tonic-gate 			}
3641*7c478bd9Sstevel@tonic-gate 			plp->pl_pid = p->pd_pid;
3642*7c478bd9Sstevel@tonic-gate 			plp->pl_dflag = 0;
3643*7c478bd9Sstevel@tonic-gate 			plp->pl_next = NULL;
3644*7c478bd9Sstevel@tonic-gate 			/*
3645*7c478bd9Sstevel@tonic-gate 			 * Note - pid list is kept in increasing order of pids.
3646*7c478bd9Sstevel@tonic-gate 			 */
3647*7c478bd9Sstevel@tonic-gate 			if (Plhead == NULL) {
3648*7c478bd9Sstevel@tonic-gate 				Plhead = plp;
3649*7c478bd9Sstevel@tonic-gate 				/* Back up to read next record */
3650*7c478bd9Sstevel@tonic-gate 				break;
3651*7c478bd9Sstevel@tonic-gate 			} else {
3652*7c478bd9Sstevel@tonic-gate 				savetp = tp = Plhead;
3653*7c478bd9Sstevel@tonic-gate 				while (tp) {
3654*7c478bd9Sstevel@tonic-gate 					if (plp->pl_pid > tp->pl_pid) {
3655*7c478bd9Sstevel@tonic-gate 						savetp = tp;
3656*7c478bd9Sstevel@tonic-gate 						tp = tp->pl_next;
3657*7c478bd9Sstevel@tonic-gate 						continue;
3658*7c478bd9Sstevel@tonic-gate 					} else if (plp->pl_pid < tp->pl_pid) {
3659*7c478bd9Sstevel@tonic-gate 						if (tp == Plhead) {
3660*7c478bd9Sstevel@tonic-gate 							plp->pl_next = Plhead;
3661*7c478bd9Sstevel@tonic-gate 							Plhead = plp;
3662*7c478bd9Sstevel@tonic-gate 						} else {
3663*7c478bd9Sstevel@tonic-gate 							plp->pl_next =
3664*7c478bd9Sstevel@tonic-gate 							    savetp->pl_next;
3665*7c478bd9Sstevel@tonic-gate 							savetp->pl_next = plp;
3666*7c478bd9Sstevel@tonic-gate 						}
3667*7c478bd9Sstevel@tonic-gate 						break;
3668*7c478bd9Sstevel@tonic-gate 					} else {
3669*7c478bd9Sstevel@tonic-gate 						/* Already in list! */
3670*7c478bd9Sstevel@tonic-gate 						plp->pl_next = Plfree;
3671*7c478bd9Sstevel@tonic-gate 						Plfree = plp;
3672*7c478bd9Sstevel@tonic-gate 						break;
3673*7c478bd9Sstevel@tonic-gate 					}
3674*7c478bd9Sstevel@tonic-gate 				}
3675*7c478bd9Sstevel@tonic-gate 				if (tp == NULL) {
3676*7c478bd9Sstevel@tonic-gate 					/* Add to end of list */
3677*7c478bd9Sstevel@tonic-gate 					savetp->pl_next = plp;
3678*7c478bd9Sstevel@tonic-gate 				}
3679*7c478bd9Sstevel@tonic-gate 			}
3680*7c478bd9Sstevel@tonic-gate 			/* Back up to read next record. */
3681*7c478bd9Sstevel@tonic-gate 			break;
3682*7c478bd9Sstevel@tonic-gate 
3683*7c478bd9Sstevel@tonic-gate 		case REMPID:
3684*7c478bd9Sstevel@tonic-gate 			/*
3685*7c478bd9Sstevel@tonic-gate 			 * This one was handled by someone else,
3686*7c478bd9Sstevel@tonic-gate 			 * purge it from the list.
3687*7c478bd9Sstevel@tonic-gate 			 */
3688*7c478bd9Sstevel@tonic-gate 			if (Plhead == NULL) {
3689*7c478bd9Sstevel@tonic-gate 				/* Back up to read next record. */
3690*7c478bd9Sstevel@tonic-gate 				break;
3691*7c478bd9Sstevel@tonic-gate 			}
3692*7c478bd9Sstevel@tonic-gate 			savetp = tp = Plhead;
3693*7c478bd9Sstevel@tonic-gate 			while (tp) {
3694*7c478bd9Sstevel@tonic-gate 				if (p->pd_pid > tp->pl_pid) {
3695*7c478bd9Sstevel@tonic-gate 					/* Keep on looking. */
3696*7c478bd9Sstevel@tonic-gate 					savetp = tp;
3697*7c478bd9Sstevel@tonic-gate 					tp = tp->pl_next;
3698*7c478bd9Sstevel@tonic-gate 					continue;
3699*7c478bd9Sstevel@tonic-gate 				} else if (p->pd_pid < tp->pl_pid) {
3700*7c478bd9Sstevel@tonic-gate 					/* Not in list. */
3701*7c478bd9Sstevel@tonic-gate 					break;
3702*7c478bd9Sstevel@tonic-gate 				} else {
3703*7c478bd9Sstevel@tonic-gate 					/* Found it. */
3704*7c478bd9Sstevel@tonic-gate 					if (tp == Plhead)
3705*7c478bd9Sstevel@tonic-gate 						Plhead = tp->pl_next;
3706*7c478bd9Sstevel@tonic-gate 					else
3707*7c478bd9Sstevel@tonic-gate 						savetp->pl_next = tp->pl_next;
3708*7c478bd9Sstevel@tonic-gate 					tp->pl_next = Plfree;
3709*7c478bd9Sstevel@tonic-gate 					Plfree = tp;
3710*7c478bd9Sstevel@tonic-gate 					break;
3711*7c478bd9Sstevel@tonic-gate 				}
3712*7c478bd9Sstevel@tonic-gate 			}
3713*7c478bd9Sstevel@tonic-gate 			/* Back up to read next record. */
3714*7c478bd9Sstevel@tonic-gate 			break;
3715*7c478bd9Sstevel@tonic-gate 		default:
3716*7c478bd9Sstevel@tonic-gate 			console(B_TRUE, "Bad message on initpipe\n");
3717*7c478bd9Sstevel@tonic-gate 			break;
3718*7c478bd9Sstevel@tonic-gate 		}
3719*7c478bd9Sstevel@tonic-gate 	}
3720*7c478bd9Sstevel@tonic-gate }
3721*7c478bd9Sstevel@tonic-gate 
3722*7c478bd9Sstevel@tonic-gate 
3723*7c478bd9Sstevel@tonic-gate static void
3724*7c478bd9Sstevel@tonic-gate cleanaux()
3725*7c478bd9Sstevel@tonic-gate {
3726*7c478bd9Sstevel@tonic-gate 	struct pidlist *savep, *p;
3727*7c478bd9Sstevel@tonic-gate 	pid_t	pid;
3728*7c478bd9Sstevel@tonic-gate 	short	status;
3729*7c478bd9Sstevel@tonic-gate 
3730*7c478bd9Sstevel@tonic-gate 	(void) sigset(SIGCLD, SIG_DFL);
3731*7c478bd9Sstevel@tonic-gate 	Gchild = 0;	/* Note - Safe to do this here since no SIGCLDs */
3732*7c478bd9Sstevel@tonic-gate 	(void) sighold(SIGPOLL);
3733*7c478bd9Sstevel@tonic-gate 	savep = p = Plhead;
3734*7c478bd9Sstevel@tonic-gate 	while (p) {
3735*7c478bd9Sstevel@tonic-gate 		if (p->pl_dflag) {
3736*7c478bd9Sstevel@tonic-gate 			/*
3737*7c478bd9Sstevel@tonic-gate 			 * Found an entry to delete,
3738*7c478bd9Sstevel@tonic-gate 			 * remove it from list first.
3739*7c478bd9Sstevel@tonic-gate 			 */
3740*7c478bd9Sstevel@tonic-gate 			pid = p->pl_pid;
3741*7c478bd9Sstevel@tonic-gate 			status = p->pl_exit;
3742*7c478bd9Sstevel@tonic-gate 			if (p == Plhead) {
3743*7c478bd9Sstevel@tonic-gate 				Plhead = p->pl_next;
3744*7c478bd9Sstevel@tonic-gate 				p->pl_next = Plfree;
3745*7c478bd9Sstevel@tonic-gate 				Plfree = p;
3746*7c478bd9Sstevel@tonic-gate 				savep = p = Plhead;
3747*7c478bd9Sstevel@tonic-gate 			} else {
3748*7c478bd9Sstevel@tonic-gate 				savep->pl_next = p->pl_next;
3749*7c478bd9Sstevel@tonic-gate 				p->pl_next = Plfree;
3750*7c478bd9Sstevel@tonic-gate 				Plfree = p;
3751*7c478bd9Sstevel@tonic-gate 				p = savep->pl_next;
3752*7c478bd9Sstevel@tonic-gate 			}
3753*7c478bd9Sstevel@tonic-gate 			clearent(pid, status);
3754*7c478bd9Sstevel@tonic-gate 			continue;
3755*7c478bd9Sstevel@tonic-gate 		}
3756*7c478bd9Sstevel@tonic-gate 		savep = p;
3757*7c478bd9Sstevel@tonic-gate 		p = p->pl_next;
3758*7c478bd9Sstevel@tonic-gate 	}
3759*7c478bd9Sstevel@tonic-gate 	(void) sigrelse(SIGPOLL);
3760*7c478bd9Sstevel@tonic-gate 	(void) sigset(SIGCLD, childeath);
3761*7c478bd9Sstevel@tonic-gate }
3762*7c478bd9Sstevel@tonic-gate 
3763*7c478bd9Sstevel@tonic-gate 
3764*7c478bd9Sstevel@tonic-gate /*
3765*7c478bd9Sstevel@tonic-gate  * /etc/inittab has more entries and we have run out of room in the proc_table
3766*7c478bd9Sstevel@tonic-gate  * array. Double the size of proc_table to accomodate the extra entries.
3767*7c478bd9Sstevel@tonic-gate  */
3768*7c478bd9Sstevel@tonic-gate static void
3769*7c478bd9Sstevel@tonic-gate increase_proc_table_size()
3770*7c478bd9Sstevel@tonic-gate {
3771*7c478bd9Sstevel@tonic-gate 	sigset_t block, unblock;
3772*7c478bd9Sstevel@tonic-gate 	void *ptr;
3773*7c478bd9Sstevel@tonic-gate 	size_t delta = num_proc * sizeof (struct PROC_TABLE);
3774*7c478bd9Sstevel@tonic-gate 
3775*7c478bd9Sstevel@tonic-gate 
3776*7c478bd9Sstevel@tonic-gate 	/*
3777*7c478bd9Sstevel@tonic-gate 	 * Block signals for realloc.
3778*7c478bd9Sstevel@tonic-gate 	 */
3779*7c478bd9Sstevel@tonic-gate 	(void) sigfillset(&block);
3780*7c478bd9Sstevel@tonic-gate 	(void) sigprocmask(SIG_BLOCK, &block, &unblock);
3781*7c478bd9Sstevel@tonic-gate 
3782*7c478bd9Sstevel@tonic-gate 
3783*7c478bd9Sstevel@tonic-gate 	/*
3784*7c478bd9Sstevel@tonic-gate 	 * On failure we just return because callers of this function check
3785*7c478bd9Sstevel@tonic-gate 	 * for failure.
3786*7c478bd9Sstevel@tonic-gate 	 */
3787*7c478bd9Sstevel@tonic-gate 	do
3788*7c478bd9Sstevel@tonic-gate 		ptr = realloc(g_state, g_state_sz + delta);
3789*7c478bd9Sstevel@tonic-gate 	while (ptr == NULL && errno == EAGAIN);
3790*7c478bd9Sstevel@tonic-gate 
3791*7c478bd9Sstevel@tonic-gate 	if (ptr != NULL) {
3792*7c478bd9Sstevel@tonic-gate 		/* ensure that the new part is initialized to zero */
3793*7c478bd9Sstevel@tonic-gate 		bzero((caddr_t)ptr + g_state_sz, delta);
3794*7c478bd9Sstevel@tonic-gate 
3795*7c478bd9Sstevel@tonic-gate 		g_state = ptr;
3796*7c478bd9Sstevel@tonic-gate 		g_state_sz += delta;
3797*7c478bd9Sstevel@tonic-gate 		num_proc <<= 1;
3798*7c478bd9Sstevel@tonic-gate 	}
3799*7c478bd9Sstevel@tonic-gate 
3800*7c478bd9Sstevel@tonic-gate 
3801*7c478bd9Sstevel@tonic-gate 	/* unblock our signals before returning */
3802*7c478bd9Sstevel@tonic-gate 	(void) sigprocmask(SIG_SETMASK, &unblock, NULL);
3803*7c478bd9Sstevel@tonic-gate }
3804*7c478bd9Sstevel@tonic-gate 
3805*7c478bd9Sstevel@tonic-gate 
3806*7c478bd9Sstevel@tonic-gate 
3807*7c478bd9Sstevel@tonic-gate /*
3808*7c478bd9Sstevel@tonic-gate  * Sanity check g_state.
3809*7c478bd9Sstevel@tonic-gate  */
3810*7c478bd9Sstevel@tonic-gate static int
3811*7c478bd9Sstevel@tonic-gate st_sane()
3812*7c478bd9Sstevel@tonic-gate {
3813*7c478bd9Sstevel@tonic-gate 	int i;
3814*7c478bd9Sstevel@tonic-gate 	struct PROC_TABLE *ptp;
3815*7c478bd9Sstevel@tonic-gate 
3816*7c478bd9Sstevel@tonic-gate 
3817*7c478bd9Sstevel@tonic-gate 	/* Note: cur_state is encoded as a signal number */
3818*7c478bd9Sstevel@tonic-gate 	if (cur_state < 1 || cur_state == 9 || cur_state > 13)
3819*7c478bd9Sstevel@tonic-gate 		return (0);
3820*7c478bd9Sstevel@tonic-gate 
3821*7c478bd9Sstevel@tonic-gate 	/* Check num_proc */
3822*7c478bd9Sstevel@tonic-gate 	if (g_state_sz != sizeof (struct init_state) + (num_proc - 1) *
3823*7c478bd9Sstevel@tonic-gate 	    sizeof (struct PROC_TABLE))
3824*7c478bd9Sstevel@tonic-gate 		return (0);
3825*7c478bd9Sstevel@tonic-gate 
3826*7c478bd9Sstevel@tonic-gate 	/* Check proc_table */
3827*7c478bd9Sstevel@tonic-gate 	for (i = 0, ptp = proc_table; i < num_proc; ++i, ++ptp) {
3828*7c478bd9Sstevel@tonic-gate 		/* skip unoccupied entries */
3829*7c478bd9Sstevel@tonic-gate 		if (!(ptp->p_flags & OCCUPIED))
3830*7c478bd9Sstevel@tonic-gate 			continue;
3831*7c478bd9Sstevel@tonic-gate 
3832*7c478bd9Sstevel@tonic-gate 		/* p_flags has no bits outside of PF_MASK */
3833*7c478bd9Sstevel@tonic-gate 		if (ptp->p_flags & ~(PF_MASK))
3834*7c478bd9Sstevel@tonic-gate 			return (0);
3835*7c478bd9Sstevel@tonic-gate 
3836*7c478bd9Sstevel@tonic-gate 		/* 5 <= pid <= MAXPID */
3837*7c478bd9Sstevel@tonic-gate 		if (ptp->p_pid < 5 || ptp->p_pid > MAXPID)
3838*7c478bd9Sstevel@tonic-gate 			return (0);
3839*7c478bd9Sstevel@tonic-gate 
3840*7c478bd9Sstevel@tonic-gate 		/* p_count >= 0 */
3841*7c478bd9Sstevel@tonic-gate 		if (ptp->p_count < 0)
3842*7c478bd9Sstevel@tonic-gate 			return (0);
3843*7c478bd9Sstevel@tonic-gate 
3844*7c478bd9Sstevel@tonic-gate 		/* p_time >= 0 */
3845*7c478bd9Sstevel@tonic-gate 		if (ptp->p_time < 0)
3846*7c478bd9Sstevel@tonic-gate 			return (0);
3847*7c478bd9Sstevel@tonic-gate 	}
3848*7c478bd9Sstevel@tonic-gate 
3849*7c478bd9Sstevel@tonic-gate 	return (1);
3850*7c478bd9Sstevel@tonic-gate }
3851*7c478bd9Sstevel@tonic-gate 
3852*7c478bd9Sstevel@tonic-gate /*
3853*7c478bd9Sstevel@tonic-gate  * Initialize our state.
3854*7c478bd9Sstevel@tonic-gate  *
3855*7c478bd9Sstevel@tonic-gate  * If the system just booted, then init_state_file, which is located on an
3856*7c478bd9Sstevel@tonic-gate  * everpresent tmpfs filesystem, should not exist.
3857*7c478bd9Sstevel@tonic-gate  *
3858*7c478bd9Sstevel@tonic-gate  * If we were restarted, then init_state_file should exist, in
3859*7c478bd9Sstevel@tonic-gate  * which case we'll read it in, sanity check it, and use it.
3860*7c478bd9Sstevel@tonic-gate  *
3861*7c478bd9Sstevel@tonic-gate  * Note: You can't call console() until proc_table is ready.
3862*7c478bd9Sstevel@tonic-gate  */
3863*7c478bd9Sstevel@tonic-gate void
3864*7c478bd9Sstevel@tonic-gate st_init()
3865*7c478bd9Sstevel@tonic-gate {
3866*7c478bd9Sstevel@tonic-gate 	struct stat stb;
3867*7c478bd9Sstevel@tonic-gate 	int ret, st_fd, insane = 0;
3868*7c478bd9Sstevel@tonic-gate 	size_t to_be_read;
3869*7c478bd9Sstevel@tonic-gate 	char *ptr;
3870*7c478bd9Sstevel@tonic-gate 
3871*7c478bd9Sstevel@tonic-gate 
3872*7c478bd9Sstevel@tonic-gate 	booting = 1;
3873*7c478bd9Sstevel@tonic-gate 
3874*7c478bd9Sstevel@tonic-gate 	do {
3875*7c478bd9Sstevel@tonic-gate 		/*
3876*7c478bd9Sstevel@tonic-gate 		 * If we can exclusively create the file, then we're the
3877*7c478bd9Sstevel@tonic-gate 		 * initial invocation of init(1M).
3878*7c478bd9Sstevel@tonic-gate 		 */
3879*7c478bd9Sstevel@tonic-gate 		st_fd = open(init_state_file, O_RDWR | O_CREAT | O_EXCL,
3880*7c478bd9Sstevel@tonic-gate 		    S_IRUSR | S_IWUSR);
3881*7c478bd9Sstevel@tonic-gate 	} while (st_fd == -1 && errno == EINTR);
3882*7c478bd9Sstevel@tonic-gate 	if (st_fd != -1)
3883*7c478bd9Sstevel@tonic-gate 		goto new_state;
3884*7c478bd9Sstevel@tonic-gate 
3885*7c478bd9Sstevel@tonic-gate 	booting = 0;
3886*7c478bd9Sstevel@tonic-gate 
3887*7c478bd9Sstevel@tonic-gate 	do {
3888*7c478bd9Sstevel@tonic-gate 		st_fd = open(init_state_file, O_RDWR, S_IRUSR | S_IWUSR);
3889*7c478bd9Sstevel@tonic-gate 	} while (st_fd == -1 && errno == EINTR);
3890*7c478bd9Sstevel@tonic-gate 	if (st_fd == -1)
3891*7c478bd9Sstevel@tonic-gate 		goto new_state;
3892*7c478bd9Sstevel@tonic-gate 
3893*7c478bd9Sstevel@tonic-gate 	/* Get the size of the file. */
3894*7c478bd9Sstevel@tonic-gate 	do
3895*7c478bd9Sstevel@tonic-gate 		ret = fstat(st_fd, &stb);
3896*7c478bd9Sstevel@tonic-gate 	while (ret == -1 && errno == EINTR);
3897*7c478bd9Sstevel@tonic-gate 	if (ret == -1)
3898*7c478bd9Sstevel@tonic-gate 		goto new_state;
3899*7c478bd9Sstevel@tonic-gate 
3900*7c478bd9Sstevel@tonic-gate 	do
3901*7c478bd9Sstevel@tonic-gate 		g_state = malloc(stb.st_size);
3902*7c478bd9Sstevel@tonic-gate 	while (g_state == NULL && errno == EAGAIN);
3903*7c478bd9Sstevel@tonic-gate 	if (g_state == NULL)
3904*7c478bd9Sstevel@tonic-gate 		goto new_state;
3905*7c478bd9Sstevel@tonic-gate 
3906*7c478bd9Sstevel@tonic-gate 	to_be_read = stb.st_size;
3907*7c478bd9Sstevel@tonic-gate 	ptr = (char *)g_state;
3908*7c478bd9Sstevel@tonic-gate 	while (to_be_read > 0) {
3909*7c478bd9Sstevel@tonic-gate 		ssize_t read_ret;
3910*7c478bd9Sstevel@tonic-gate 
3911*7c478bd9Sstevel@tonic-gate 		read_ret = read(st_fd, ptr, to_be_read);
3912*7c478bd9Sstevel@tonic-gate 		if (read_ret < 0) {
3913*7c478bd9Sstevel@tonic-gate 			if (errno == EINTR)
3914*7c478bd9Sstevel@tonic-gate 				continue;
3915*7c478bd9Sstevel@tonic-gate 
3916*7c478bd9Sstevel@tonic-gate 			goto new_state;
3917*7c478bd9Sstevel@tonic-gate 		}
3918*7c478bd9Sstevel@tonic-gate 
3919*7c478bd9Sstevel@tonic-gate 		to_be_read -= read_ret;
3920*7c478bd9Sstevel@tonic-gate 		ptr += read_ret;
3921*7c478bd9Sstevel@tonic-gate 	}
3922*7c478bd9Sstevel@tonic-gate 
3923*7c478bd9Sstevel@tonic-gate 	(void) close(st_fd);
3924*7c478bd9Sstevel@tonic-gate 
3925*7c478bd9Sstevel@tonic-gate 	g_state_sz = stb.st_size;
3926*7c478bd9Sstevel@tonic-gate 
3927*7c478bd9Sstevel@tonic-gate 	if (st_sane()) {
3928*7c478bd9Sstevel@tonic-gate 		console(B_TRUE, "Restarting.\n");
3929*7c478bd9Sstevel@tonic-gate 		return;
3930*7c478bd9Sstevel@tonic-gate 	}
3931*7c478bd9Sstevel@tonic-gate 
3932*7c478bd9Sstevel@tonic-gate 	insane = 1;
3933*7c478bd9Sstevel@tonic-gate 
3934*7c478bd9Sstevel@tonic-gate new_state:
3935*7c478bd9Sstevel@tonic-gate 	if (st_fd >= 0)
3936*7c478bd9Sstevel@tonic-gate 		(void) close(st_fd);
3937*7c478bd9Sstevel@tonic-gate 	else
3938*7c478bd9Sstevel@tonic-gate 		(void) unlink(init_state_file);
3939*7c478bd9Sstevel@tonic-gate 
3940*7c478bd9Sstevel@tonic-gate 	if (g_state != NULL)
3941*7c478bd9Sstevel@tonic-gate 		free(g_state);
3942*7c478bd9Sstevel@tonic-gate 
3943*7c478bd9Sstevel@tonic-gate 	/* Something went wrong, so allocate new state. */
3944*7c478bd9Sstevel@tonic-gate 	g_state_sz = sizeof (struct init_state) +
3945*7c478bd9Sstevel@tonic-gate 	    ((init_num_proc - 1) * sizeof (struct PROC_TABLE));
3946*7c478bd9Sstevel@tonic-gate 	do
3947*7c478bd9Sstevel@tonic-gate 		g_state = calloc(1, g_state_sz);
3948*7c478bd9Sstevel@tonic-gate 	while (g_state == NULL && errno == EAGAIN);
3949*7c478bd9Sstevel@tonic-gate 	if (g_state == NULL) {
3950*7c478bd9Sstevel@tonic-gate 		/* Fatal error! */
3951*7c478bd9Sstevel@tonic-gate 		exit(errno);
3952*7c478bd9Sstevel@tonic-gate 	}
3953*7c478bd9Sstevel@tonic-gate 
3954*7c478bd9Sstevel@tonic-gate 	g_state->ist_runlevel = -1;
3955*7c478bd9Sstevel@tonic-gate 	num_proc = init_num_proc;
3956*7c478bd9Sstevel@tonic-gate 
3957*7c478bd9Sstevel@tonic-gate 	if (!booting) {
3958*7c478bd9Sstevel@tonic-gate 		console(B_TRUE, "Restarting.\n");
3959*7c478bd9Sstevel@tonic-gate 
3960*7c478bd9Sstevel@tonic-gate 		/* Overwrite the bad state file. */
3961*7c478bd9Sstevel@tonic-gate 		st_write();
3962*7c478bd9Sstevel@tonic-gate 
3963*7c478bd9Sstevel@tonic-gate 		if (!insane) {
3964*7c478bd9Sstevel@tonic-gate 			console(B_TRUE,
3965*7c478bd9Sstevel@tonic-gate 			    "Error accessing persistent state file `%s'.  "
3966*7c478bd9Sstevel@tonic-gate 			    "Ignored.\n", init_state_file);
3967*7c478bd9Sstevel@tonic-gate 		} else {
3968*7c478bd9Sstevel@tonic-gate 			console(B_TRUE,
3969*7c478bd9Sstevel@tonic-gate 			    "Persistent state file `%s' is invalid and was "
3970*7c478bd9Sstevel@tonic-gate 			    "ignored.\n", init_state_file);
3971*7c478bd9Sstevel@tonic-gate 		}
3972*7c478bd9Sstevel@tonic-gate 	}
3973*7c478bd9Sstevel@tonic-gate }
3974*7c478bd9Sstevel@tonic-gate 
3975*7c478bd9Sstevel@tonic-gate /*
3976*7c478bd9Sstevel@tonic-gate  * Write g_state out to the state file.
3977*7c478bd9Sstevel@tonic-gate  */
3978*7c478bd9Sstevel@tonic-gate void
3979*7c478bd9Sstevel@tonic-gate st_write()
3980*7c478bd9Sstevel@tonic-gate {
3981*7c478bd9Sstevel@tonic-gate 	static int complained = 0;
3982*7c478bd9Sstevel@tonic-gate 
3983*7c478bd9Sstevel@tonic-gate 	int st_fd;
3984*7c478bd9Sstevel@tonic-gate 	char *cp;
3985*7c478bd9Sstevel@tonic-gate 	size_t sz;
3986*7c478bd9Sstevel@tonic-gate 	ssize_t ret;
3987*7c478bd9Sstevel@tonic-gate 
3988*7c478bd9Sstevel@tonic-gate 
3989*7c478bd9Sstevel@tonic-gate 	do {
3990*7c478bd9Sstevel@tonic-gate 		st_fd = open(init_next_state_file,
3991*7c478bd9Sstevel@tonic-gate 		    O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
3992*7c478bd9Sstevel@tonic-gate 	} while (st_fd < 0 && errno == EINTR);
3993*7c478bd9Sstevel@tonic-gate 	if (st_fd < 0)
3994*7c478bd9Sstevel@tonic-gate 		goto err;
3995*7c478bd9Sstevel@tonic-gate 
3996*7c478bd9Sstevel@tonic-gate 	cp = (char *)g_state;
3997*7c478bd9Sstevel@tonic-gate 	sz = g_state_sz;
3998*7c478bd9Sstevel@tonic-gate 	while (sz > 0) {
3999*7c478bd9Sstevel@tonic-gate 		ret = write(st_fd, cp, sz);
4000*7c478bd9Sstevel@tonic-gate 		if (ret < 0) {
4001*7c478bd9Sstevel@tonic-gate 			if (errno == EINTR)
4002*7c478bd9Sstevel@tonic-gate 				continue;
4003*7c478bd9Sstevel@tonic-gate 
4004*7c478bd9Sstevel@tonic-gate 			goto err;
4005*7c478bd9Sstevel@tonic-gate 		}
4006*7c478bd9Sstevel@tonic-gate 
4007*7c478bd9Sstevel@tonic-gate 		sz -= ret;
4008*7c478bd9Sstevel@tonic-gate 		cp += ret;
4009*7c478bd9Sstevel@tonic-gate 	}
4010*7c478bd9Sstevel@tonic-gate 
4011*7c478bd9Sstevel@tonic-gate 	(void) close(st_fd);
4012*7c478bd9Sstevel@tonic-gate 	st_fd = -1;
4013*7c478bd9Sstevel@tonic-gate 	if (rename(init_next_state_file, init_state_file)) {
4014*7c478bd9Sstevel@tonic-gate 		(void) unlink(init_next_state_file);
4015*7c478bd9Sstevel@tonic-gate 		goto err;
4016*7c478bd9Sstevel@tonic-gate 	}
4017*7c478bd9Sstevel@tonic-gate 	complained = 0;
4018*7c478bd9Sstevel@tonic-gate 
4019*7c478bd9Sstevel@tonic-gate 	return;
4020*7c478bd9Sstevel@tonic-gate 
4021*7c478bd9Sstevel@tonic-gate err:
4022*7c478bd9Sstevel@tonic-gate 	if (st_fd >= 0)
4023*7c478bd9Sstevel@tonic-gate 		(void) close(st_fd);
4024*7c478bd9Sstevel@tonic-gate 
4025*7c478bd9Sstevel@tonic-gate 	if (!booting && !complained) {
4026*7c478bd9Sstevel@tonic-gate 		/*
4027*7c478bd9Sstevel@tonic-gate 		 * Only complain after the filesystem should have come up.
4028*7c478bd9Sstevel@tonic-gate 		 * And only do it once so we don't loop between console()
4029*7c478bd9Sstevel@tonic-gate 		 * & efork().
4030*7c478bd9Sstevel@tonic-gate 		 */
4031*7c478bd9Sstevel@tonic-gate 		complained = 1;
4032*7c478bd9Sstevel@tonic-gate 		if (st_fd)
4033*7c478bd9Sstevel@tonic-gate 			console(B_TRUE, "Couldn't write persistent state "
4034*7c478bd9Sstevel@tonic-gate 			    "file `%s'.\n", init_state_file);
4035*7c478bd9Sstevel@tonic-gate 		else
4036*7c478bd9Sstevel@tonic-gate 			console(B_TRUE, "Couldn't move persistent state "
4037*7c478bd9Sstevel@tonic-gate 			    "file `%s' to `%s'.\n", init_next_state_file,
4038*7c478bd9Sstevel@tonic-gate 			    init_state_file);
4039*7c478bd9Sstevel@tonic-gate 	}
4040*7c478bd9Sstevel@tonic-gate }
4041*7c478bd9Sstevel@tonic-gate 
4042*7c478bd9Sstevel@tonic-gate /*
4043*7c478bd9Sstevel@tonic-gate  * Create a contract with these parameters.
4044*7c478bd9Sstevel@tonic-gate  */
4045*7c478bd9Sstevel@tonic-gate static int
4046*7c478bd9Sstevel@tonic-gate contract_make_template(uint_t info, uint_t critical, uint_t fatal,
4047*7c478bd9Sstevel@tonic-gate     uint64_t cookie)
4048*7c478bd9Sstevel@tonic-gate {
4049*7c478bd9Sstevel@tonic-gate 	int fd, err;
4050*7c478bd9Sstevel@tonic-gate 
4051*7c478bd9Sstevel@tonic-gate 	char *ioctl_tset_emsg =
4052*7c478bd9Sstevel@tonic-gate 	    "Couldn't set \"%s\" contract template parameter: %s.\n";
4053*7c478bd9Sstevel@tonic-gate 
4054*7c478bd9Sstevel@tonic-gate 	do
4055*7c478bd9Sstevel@tonic-gate 		fd = open64(CTFS_ROOT "/process/template", O_RDWR);
4056*7c478bd9Sstevel@tonic-gate 	while (fd < 0 && errno == EINTR);
4057*7c478bd9Sstevel@tonic-gate 	if (fd < 0) {
4058*7c478bd9Sstevel@tonic-gate 		console(B_TRUE, "Couldn't create process template: %s.\n",
4059*7c478bd9Sstevel@tonic-gate 		    strerror(errno));
4060*7c478bd9Sstevel@tonic-gate 		return (-1);
4061*7c478bd9Sstevel@tonic-gate 	}
4062*7c478bd9Sstevel@tonic-gate 
4063*7c478bd9Sstevel@tonic-gate 	if (err = ct_pr_tmpl_set_param(fd, CT_PR_INHERIT | CT_PR_REGENT))
4064*7c478bd9Sstevel@tonic-gate 		console(B_TRUE, "Contract set template inherit, regent "
4065*7c478bd9Sstevel@tonic-gate 		    "failed.\n");
4066*7c478bd9Sstevel@tonic-gate 
4067*7c478bd9Sstevel@tonic-gate 	/*
4068*7c478bd9Sstevel@tonic-gate 	 * These errors result in a misconfigured template, which is better
4069*7c478bd9Sstevel@tonic-gate 	 * than no template at all, so warn but don't abort.
4070*7c478bd9Sstevel@tonic-gate 	 */
4071*7c478bd9Sstevel@tonic-gate 	if (err = ct_tmpl_set_informative(fd, info))
4072*7c478bd9Sstevel@tonic-gate 		console(B_TRUE, ioctl_tset_emsg, "informative", strerror(err));
4073*7c478bd9Sstevel@tonic-gate 
4074*7c478bd9Sstevel@tonic-gate 	if (err = ct_tmpl_set_critical(fd, critical))
4075*7c478bd9Sstevel@tonic-gate 		console(B_TRUE, ioctl_tset_emsg, "critical", strerror(err));
4076*7c478bd9Sstevel@tonic-gate 
4077*7c478bd9Sstevel@tonic-gate 	if (err = ct_pr_tmpl_set_fatal(fd, fatal))
4078*7c478bd9Sstevel@tonic-gate 		console(B_TRUE, ioctl_tset_emsg, "fatal", strerror(err));
4079*7c478bd9Sstevel@tonic-gate 
4080*7c478bd9Sstevel@tonic-gate 	if (err = ct_tmpl_set_cookie(fd, cookie))
4081*7c478bd9Sstevel@tonic-gate 		console(B_TRUE, ioctl_tset_emsg, "cookie", strerror(err));
4082*7c478bd9Sstevel@tonic-gate 
4083*7c478bd9Sstevel@tonic-gate 	(void) fcntl(fd, F_SETFD, FD_CLOEXEC);
4084*7c478bd9Sstevel@tonic-gate 
4085*7c478bd9Sstevel@tonic-gate 	return (fd);
4086*7c478bd9Sstevel@tonic-gate }
4087*7c478bd9Sstevel@tonic-gate 
4088*7c478bd9Sstevel@tonic-gate /*
4089*7c478bd9Sstevel@tonic-gate  * Create the templates and open an event file descriptor.  We use dup2(2) to
4090*7c478bd9Sstevel@tonic-gate  * get these descriptors away from the stdin/stdout/stderr group.
4091*7c478bd9Sstevel@tonic-gate  */
4092*7c478bd9Sstevel@tonic-gate static void
4093*7c478bd9Sstevel@tonic-gate contracts_init()
4094*7c478bd9Sstevel@tonic-gate {
4095*7c478bd9Sstevel@tonic-gate 	int err, fd;
4096*7c478bd9Sstevel@tonic-gate 
4097*7c478bd9Sstevel@tonic-gate 	/*
4098*7c478bd9Sstevel@tonic-gate 	 * Create & configure a legacy template.  We only want empty events so
4099*7c478bd9Sstevel@tonic-gate 	 * we know when to abandon them.
4100*7c478bd9Sstevel@tonic-gate 	 */
4101*7c478bd9Sstevel@tonic-gate 	legacy_tmpl = contract_make_template(0, CT_PR_EV_EMPTY, CT_PR_EV_HWERR,
4102*7c478bd9Sstevel@tonic-gate 	    ORDINARY_COOKIE);
4103*7c478bd9Sstevel@tonic-gate 	if (legacy_tmpl >= 0) {
4104*7c478bd9Sstevel@tonic-gate 		err = ct_tmpl_activate(legacy_tmpl);
4105*7c478bd9Sstevel@tonic-gate 		if (err != 0) {
4106*7c478bd9Sstevel@tonic-gate 			(void) close(legacy_tmpl);
4107*7c478bd9Sstevel@tonic-gate 			legacy_tmpl = -1;
4108*7c478bd9Sstevel@tonic-gate 			console(B_TRUE,
4109*7c478bd9Sstevel@tonic-gate 			    "Couldn't activate legacy template (%s); "
4110*7c478bd9Sstevel@tonic-gate 			    "legacy services will be in init's contract.\n",
4111*7c478bd9Sstevel@tonic-gate 			    strerror(err));
4112*7c478bd9Sstevel@tonic-gate 		}
4113*7c478bd9Sstevel@tonic-gate 	} else
4114*7c478bd9Sstevel@tonic-gate 		console(B_TRUE,
4115*7c478bd9Sstevel@tonic-gate 		    "Legacy services will be in init's contract.\n");
4116*7c478bd9Sstevel@tonic-gate 
4117*7c478bd9Sstevel@tonic-gate 	if (dup2(legacy_tmpl, 255) == -1) {
4118*7c478bd9Sstevel@tonic-gate 		console(B_TRUE, "Could not duplicate legacy template: %s.\n",
4119*7c478bd9Sstevel@tonic-gate 		    strerror(errno));
4120*7c478bd9Sstevel@tonic-gate 	} else {
4121*7c478bd9Sstevel@tonic-gate 		(void) close(legacy_tmpl);
4122*7c478bd9Sstevel@tonic-gate 		legacy_tmpl = 255;
4123*7c478bd9Sstevel@tonic-gate 	}
4124*7c478bd9Sstevel@tonic-gate 
4125*7c478bd9Sstevel@tonic-gate 	(void) fcntl(legacy_tmpl, F_SETFD, FD_CLOEXEC);
4126*7c478bd9Sstevel@tonic-gate 
4127*7c478bd9Sstevel@tonic-gate 	startd_tmpl = contract_make_template(0, CT_PR_EV_EMPTY,
4128*7c478bd9Sstevel@tonic-gate 	    CT_PR_EV_HWERR | CT_PR_EV_SIGNAL | CT_PR_EV_CORE, STARTD_COOKIE);
4129*7c478bd9Sstevel@tonic-gate 
4130*7c478bd9Sstevel@tonic-gate 	if (dup2(startd_tmpl, 254) == -1) {
4131*7c478bd9Sstevel@tonic-gate 		console(B_TRUE, "Could not duplicate startd template: %s.\n",
4132*7c478bd9Sstevel@tonic-gate 		    strerror(errno));
4133*7c478bd9Sstevel@tonic-gate 	} else {
4134*7c478bd9Sstevel@tonic-gate 		(void) close(startd_tmpl);
4135*7c478bd9Sstevel@tonic-gate 		startd_tmpl = 254;
4136*7c478bd9Sstevel@tonic-gate 	}
4137*7c478bd9Sstevel@tonic-gate 
4138*7c478bd9Sstevel@tonic-gate 	(void) fcntl(startd_tmpl, F_SETFD, FD_CLOEXEC);
4139*7c478bd9Sstevel@tonic-gate 
4140*7c478bd9Sstevel@tonic-gate 	if (legacy_tmpl < 0 && startd_tmpl < 0) {
4141*7c478bd9Sstevel@tonic-gate 		/* The creation errors have already been reported. */
4142*7c478bd9Sstevel@tonic-gate 		console(B_TRUE,
4143*7c478bd9Sstevel@tonic-gate 		    "Ignoring contract events.  Core smf(5) services will not "
4144*7c478bd9Sstevel@tonic-gate 		    "be restarted.\n");
4145*7c478bd9Sstevel@tonic-gate 		return;
4146*7c478bd9Sstevel@tonic-gate 	}
4147*7c478bd9Sstevel@tonic-gate 
4148*7c478bd9Sstevel@tonic-gate 	/*
4149*7c478bd9Sstevel@tonic-gate 	 * Open an event endpoint.
4150*7c478bd9Sstevel@tonic-gate 	 */
4151*7c478bd9Sstevel@tonic-gate 	do
4152*7c478bd9Sstevel@tonic-gate 		fd = open64(CTFS_ROOT "/process/pbundle", O_RDONLY);
4153*7c478bd9Sstevel@tonic-gate 	while (fd < 0 && errno == EINTR);
4154*7c478bd9Sstevel@tonic-gate 	if (fd < 0) {
4155*7c478bd9Sstevel@tonic-gate 		console(B_TRUE,
4156*7c478bd9Sstevel@tonic-gate 		    "Couldn't open process pbundle: %s.  Core smf(5) services "
4157*7c478bd9Sstevel@tonic-gate 		    "will not be restarted.\n", strerror(errno));
4158*7c478bd9Sstevel@tonic-gate 		return;
4159*7c478bd9Sstevel@tonic-gate 	}
4160*7c478bd9Sstevel@tonic-gate 
4161*7c478bd9Sstevel@tonic-gate 	if (dup2(fd, 253) == -1) {
4162*7c478bd9Sstevel@tonic-gate 		console(B_TRUE, "Could not duplicate process bundle: %s.\n",
4163*7c478bd9Sstevel@tonic-gate 		    strerror(errno));
4164*7c478bd9Sstevel@tonic-gate 	} else {
4165*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
4166*7c478bd9Sstevel@tonic-gate 		fd = 253;
4167*7c478bd9Sstevel@tonic-gate 	}
4168*7c478bd9Sstevel@tonic-gate 
4169*7c478bd9Sstevel@tonic-gate 	(void) fcntl(fd, F_SETFD, FD_CLOEXEC);
4170*7c478bd9Sstevel@tonic-gate 
4171*7c478bd9Sstevel@tonic-gate 	/* Reset in case we've been restarted. */
4172*7c478bd9Sstevel@tonic-gate 	(void) ct_event_reset(fd);
4173*7c478bd9Sstevel@tonic-gate 
4174*7c478bd9Sstevel@tonic-gate 	poll_fds[0].fd = fd;
4175*7c478bd9Sstevel@tonic-gate 	poll_fds[0].events = POLLIN;
4176*7c478bd9Sstevel@tonic-gate 	poll_nfds = 1;
4177*7c478bd9Sstevel@tonic-gate }
4178*7c478bd9Sstevel@tonic-gate 
4179*7c478bd9Sstevel@tonic-gate static int
4180*7c478bd9Sstevel@tonic-gate contract_getfile(ctid_t id, const char *name, int oflag)
4181*7c478bd9Sstevel@tonic-gate {
4182*7c478bd9Sstevel@tonic-gate 	int fd;
4183*7c478bd9Sstevel@tonic-gate 
4184*7c478bd9Sstevel@tonic-gate 	do
4185*7c478bd9Sstevel@tonic-gate 		fd = contract_open(id, "process", name, oflag);
4186*7c478bd9Sstevel@tonic-gate 	while (fd < 0 && errno == EINTR);
4187*7c478bd9Sstevel@tonic-gate 
4188*7c478bd9Sstevel@tonic-gate 	if (fd < 0)
4189*7c478bd9Sstevel@tonic-gate 		console(B_TRUE, "Couldn't open %s for contract %ld: %s.\n",
4190*7c478bd9Sstevel@tonic-gate 		    name, id, strerror(errno));
4191*7c478bd9Sstevel@tonic-gate 
4192*7c478bd9Sstevel@tonic-gate 	return (fd);
4193*7c478bd9Sstevel@tonic-gate }
4194*7c478bd9Sstevel@tonic-gate 
4195*7c478bd9Sstevel@tonic-gate static int
4196*7c478bd9Sstevel@tonic-gate contract_cookie(ctid_t id, uint64_t *cp)
4197*7c478bd9Sstevel@tonic-gate {
4198*7c478bd9Sstevel@tonic-gate 	int fd, err;
4199*7c478bd9Sstevel@tonic-gate 	ct_stathdl_t sh;
4200*7c478bd9Sstevel@tonic-gate 
4201*7c478bd9Sstevel@tonic-gate 	fd = contract_getfile(id, "status", O_RDONLY);
4202*7c478bd9Sstevel@tonic-gate 	if (fd < 0)
4203*7c478bd9Sstevel@tonic-gate 		return (-1);
4204*7c478bd9Sstevel@tonic-gate 
4205*7c478bd9Sstevel@tonic-gate 	err = ct_status_read(fd, CTD_COMMON, &sh);
4206*7c478bd9Sstevel@tonic-gate 	if (err != 0) {
4207*7c478bd9Sstevel@tonic-gate 		console(B_TRUE, "Couldn't read status of contract %ld: %s.\n",
4208*7c478bd9Sstevel@tonic-gate 		    id, strerror(err));
4209*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
4210*7c478bd9Sstevel@tonic-gate 		return (-1);
4211*7c478bd9Sstevel@tonic-gate 	}
4212*7c478bd9Sstevel@tonic-gate 
4213*7c478bd9Sstevel@tonic-gate 	(void) close(fd);
4214*7c478bd9Sstevel@tonic-gate 
4215*7c478bd9Sstevel@tonic-gate 	*cp = ct_status_get_cookie(sh);
4216*7c478bd9Sstevel@tonic-gate 
4217*7c478bd9Sstevel@tonic-gate 	ct_status_free(sh);
4218*7c478bd9Sstevel@tonic-gate 	return (0);
4219*7c478bd9Sstevel@tonic-gate }
4220*7c478bd9Sstevel@tonic-gate 
4221*7c478bd9Sstevel@tonic-gate static void
4222*7c478bd9Sstevel@tonic-gate contract_ack(ct_evthdl_t e)
4223*7c478bd9Sstevel@tonic-gate {
4224*7c478bd9Sstevel@tonic-gate 	int fd;
4225*7c478bd9Sstevel@tonic-gate 
4226*7c478bd9Sstevel@tonic-gate 	if (ct_event_get_flags(e) & CTE_INFO)
4227*7c478bd9Sstevel@tonic-gate 		return;
4228*7c478bd9Sstevel@tonic-gate 
4229*7c478bd9Sstevel@tonic-gate 	fd = contract_getfile(ct_event_get_ctid(e), "ctl", O_WRONLY);
4230*7c478bd9Sstevel@tonic-gate 	if (fd < 0)
4231*7c478bd9Sstevel@tonic-gate 		return;
4232*7c478bd9Sstevel@tonic-gate 
4233*7c478bd9Sstevel@tonic-gate 	(void) ct_ctl_ack(fd, ct_event_get_evid(e));
4234*7c478bd9Sstevel@tonic-gate 	(void) close(fd);
4235*7c478bd9Sstevel@tonic-gate }
4236*7c478bd9Sstevel@tonic-gate 
4237*7c478bd9Sstevel@tonic-gate /*
4238*7c478bd9Sstevel@tonic-gate  * Process a contract event.
4239*7c478bd9Sstevel@tonic-gate  */
4240*7c478bd9Sstevel@tonic-gate static void
4241*7c478bd9Sstevel@tonic-gate contract_event(struct pollfd *poll)
4242*7c478bd9Sstevel@tonic-gate {
4243*7c478bd9Sstevel@tonic-gate 	ct_evthdl_t e;
4244*7c478bd9Sstevel@tonic-gate 	int err;
4245*7c478bd9Sstevel@tonic-gate 	ctid_t ctid;
4246*7c478bd9Sstevel@tonic-gate 
4247*7c478bd9Sstevel@tonic-gate 	if (!(poll->revents & POLLIN)) {
4248*7c478bd9Sstevel@tonic-gate 		if (poll->revents & POLLERR)
4249*7c478bd9Sstevel@tonic-gate 			console(B_TRUE,
4250*7c478bd9Sstevel@tonic-gate 			    "Unknown poll error on my process contract "
4251*7c478bd9Sstevel@tonic-gate 			    "pbundle.\n");
4252*7c478bd9Sstevel@tonic-gate 		return;
4253*7c478bd9Sstevel@tonic-gate 	}
4254*7c478bd9Sstevel@tonic-gate 
4255*7c478bd9Sstevel@tonic-gate 	err = ct_event_read(poll->fd, &e);
4256*7c478bd9Sstevel@tonic-gate 	if (err != 0) {
4257*7c478bd9Sstevel@tonic-gate 		console(B_TRUE, "Error retrieving contract event: %s.\n",
4258*7c478bd9Sstevel@tonic-gate 		    strerror(err));
4259*7c478bd9Sstevel@tonic-gate 		return;
4260*7c478bd9Sstevel@tonic-gate 	}
4261*7c478bd9Sstevel@tonic-gate 
4262*7c478bd9Sstevel@tonic-gate 	ctid = ct_event_get_ctid(e);
4263*7c478bd9Sstevel@tonic-gate 
4264*7c478bd9Sstevel@tonic-gate 	if (ct_event_get_type(e) == CT_PR_EV_EMPTY) {
4265*7c478bd9Sstevel@tonic-gate 		uint64_t cookie;
4266*7c478bd9Sstevel@tonic-gate 		int ret, abandon = 1;
4267*7c478bd9Sstevel@tonic-gate 
4268*7c478bd9Sstevel@tonic-gate 		/* If it's svc.startd, restart it.  Else, abandon. */
4269*7c478bd9Sstevel@tonic-gate 		ret = contract_cookie(ctid, &cookie);
4270*7c478bd9Sstevel@tonic-gate 
4271*7c478bd9Sstevel@tonic-gate 		if (ret == 0) {
4272*7c478bd9Sstevel@tonic-gate 			if (cookie == STARTD_COOKIE &&
4273*7c478bd9Sstevel@tonic-gate 			    do_restart_startd) {
4274*7c478bd9Sstevel@tonic-gate 				if (smf_debug)
4275*7c478bd9Sstevel@tonic-gate 					console(B_TRUE, "Restarting "
4276*7c478bd9Sstevel@tonic-gate 					    "svc.startd.\n");
4277*7c478bd9Sstevel@tonic-gate 
4278*7c478bd9Sstevel@tonic-gate 				/*
4279*7c478bd9Sstevel@tonic-gate 				 * Account for the failure.  If the failure rate
4280*7c478bd9Sstevel@tonic-gate 				 * exceeds a threshold, then drop to maintenance
4281*7c478bd9Sstevel@tonic-gate 				 * mode.
4282*7c478bd9Sstevel@tonic-gate 				 */
4283*7c478bd9Sstevel@tonic-gate 				startd_record_failure();
4284*7c478bd9Sstevel@tonic-gate 				if (startd_failure_rate_critical())
4285*7c478bd9Sstevel@tonic-gate 					enter_maintenance();
4286*7c478bd9Sstevel@tonic-gate 
4287*7c478bd9Sstevel@tonic-gate 				if (startd_tmpl < 0)
4288*7c478bd9Sstevel@tonic-gate 					console(B_TRUE,
4289*7c478bd9Sstevel@tonic-gate 					    "Restarting svc.startd in "
4290*7c478bd9Sstevel@tonic-gate 					    "improper contract (bad "
4291*7c478bd9Sstevel@tonic-gate 					    "template).\n");
4292*7c478bd9Sstevel@tonic-gate 
4293*7c478bd9Sstevel@tonic-gate 				(void) startd_run(startd_cline, startd_tmpl,
4294*7c478bd9Sstevel@tonic-gate 				    ctid);
4295*7c478bd9Sstevel@tonic-gate 
4296*7c478bd9Sstevel@tonic-gate 				abandon = 0;
4297*7c478bd9Sstevel@tonic-gate 			}
4298*7c478bd9Sstevel@tonic-gate 		}
4299*7c478bd9Sstevel@tonic-gate 
4300*7c478bd9Sstevel@tonic-gate 		if (abandon && (err = contract_abandon_id(ctid))) {
4301*7c478bd9Sstevel@tonic-gate 			console(B_TRUE, "Couldn't abandon contract %ld: %s.\n",
4302*7c478bd9Sstevel@tonic-gate 			    ctid, strerror(err));
4303*7c478bd9Sstevel@tonic-gate 		}
4304*7c478bd9Sstevel@tonic-gate 
4305*7c478bd9Sstevel@tonic-gate 		/*
4306*7c478bd9Sstevel@tonic-gate 		 * No need to acknowledge the event since either way the
4307*7c478bd9Sstevel@tonic-gate 		 * originating contract should be abandoned.
4308*7c478bd9Sstevel@tonic-gate 		 */
4309*7c478bd9Sstevel@tonic-gate 	} else {
4310*7c478bd9Sstevel@tonic-gate 		console(B_TRUE,
4311*7c478bd9Sstevel@tonic-gate 		    "Received contract event of unexpected type %d from "
4312*7c478bd9Sstevel@tonic-gate 		    "contract %ld.\n", ct_event_get_type(e), ctid);
4313*7c478bd9Sstevel@tonic-gate 
4314*7c478bd9Sstevel@tonic-gate 		if ((ct_event_get_flags(e) & (CTE_INFO | CTE_ACK)) == 0)
4315*7c478bd9Sstevel@tonic-gate 			/* Allow unexpected critical events to be released. */
4316*7c478bd9Sstevel@tonic-gate 			contract_ack(e);
4317*7c478bd9Sstevel@tonic-gate 	}
4318*7c478bd9Sstevel@tonic-gate 
4319*7c478bd9Sstevel@tonic-gate 	ct_event_free(e);
4320*7c478bd9Sstevel@tonic-gate }
4321*7c478bd9Sstevel@tonic-gate 
4322*7c478bd9Sstevel@tonic-gate /*
4323*7c478bd9Sstevel@tonic-gate  * svc.startd(1M) Management
4324*7c478bd9Sstevel@tonic-gate  */
4325*7c478bd9Sstevel@tonic-gate 
4326*7c478bd9Sstevel@tonic-gate /*
4327*7c478bd9Sstevel@tonic-gate  * (Re)start svc.startd(1M).  old_ctid should be the contract ID of the old
4328*7c478bd9Sstevel@tonic-gate  * contract, or 0 if we're starting it for the first time.  If wait is true
4329*7c478bd9Sstevel@tonic-gate  * we'll wait for and return the exit value of the child.
4330*7c478bd9Sstevel@tonic-gate  */
4331*7c478bd9Sstevel@tonic-gate static int
4332*7c478bd9Sstevel@tonic-gate startd_run(const char *cline, int tmpl, ctid_t old_ctid)
4333*7c478bd9Sstevel@tonic-gate {
4334*7c478bd9Sstevel@tonic-gate 	int err, i, ret, did_activate;
4335*7c478bd9Sstevel@tonic-gate 	pid_t pid;
4336*7c478bd9Sstevel@tonic-gate 	struct stat sb;
4337*7c478bd9Sstevel@tonic-gate 
4338*7c478bd9Sstevel@tonic-gate 	if (cline[0] == '\0')
4339*7c478bd9Sstevel@tonic-gate 		return (-1);
4340*7c478bd9Sstevel@tonic-gate 
4341*7c478bd9Sstevel@tonic-gate 	/*
4342*7c478bd9Sstevel@tonic-gate 	 * Don't restart startd if the system is rebooting or shutting down.
4343*7c478bd9Sstevel@tonic-gate 	 */
4344*7c478bd9Sstevel@tonic-gate 	do {
4345*7c478bd9Sstevel@tonic-gate 		ret = stat("/etc/svc/volatile/resetting", &sb);
4346*7c478bd9Sstevel@tonic-gate 	} while (ret == -1 && errno == EINTR);
4347*7c478bd9Sstevel@tonic-gate 
4348*7c478bd9Sstevel@tonic-gate 	if (ret == 0) {
4349*7c478bd9Sstevel@tonic-gate 		if (smf_debug)
4350*7c478bd9Sstevel@tonic-gate 			console(B_TRUE, "Quiescing for reboot.\n");
4351*7c478bd9Sstevel@tonic-gate 		(void) pause();
4352*7c478bd9Sstevel@tonic-gate 		return (-1);
4353*7c478bd9Sstevel@tonic-gate 	}
4354*7c478bd9Sstevel@tonic-gate 
4355*7c478bd9Sstevel@tonic-gate 	err = ct_pr_tmpl_set_transfer(tmpl, old_ctid);
4356*7c478bd9Sstevel@tonic-gate 	if (err == EINVAL) {
4357*7c478bd9Sstevel@tonic-gate 		console(B_TRUE, "Remake startd_tmpl; reattempt transfer.\n");
4358*7c478bd9Sstevel@tonic-gate 		tmpl = startd_tmpl = contract_make_template(0, CT_PR_EV_EMPTY,
4359*7c478bd9Sstevel@tonic-gate 		    CT_PR_EV_HWERR, STARTD_COOKIE);
4360*7c478bd9Sstevel@tonic-gate 
4361*7c478bd9Sstevel@tonic-gate 		err = ct_pr_tmpl_set_transfer(tmpl, old_ctid);
4362*7c478bd9Sstevel@tonic-gate 	}
4363*7c478bd9Sstevel@tonic-gate 	if (err != 0) {
4364*7c478bd9Sstevel@tonic-gate 		console(B_TRUE,
4365*7c478bd9Sstevel@tonic-gate 		    "Couldn't set transfer parameter of contract template: "
4366*7c478bd9Sstevel@tonic-gate 		    "%s.\n", strerror(err));
4367*7c478bd9Sstevel@tonic-gate 	}
4368*7c478bd9Sstevel@tonic-gate 
4369*7c478bd9Sstevel@tonic-gate 	did_activate = !(ct_tmpl_activate(tmpl));
4370*7c478bd9Sstevel@tonic-gate 	if (!did_activate)
4371*7c478bd9Sstevel@tonic-gate 		console(B_TRUE,
4372*7c478bd9Sstevel@tonic-gate 		    "Template activation failed; not starting \"%s\" in "
4373*7c478bd9Sstevel@tonic-gate 		    "proper contract.\n", cline);
4374*7c478bd9Sstevel@tonic-gate 
4375*7c478bd9Sstevel@tonic-gate 	/* Hold SIGCHLD so we can wait if necessary. */
4376*7c478bd9Sstevel@tonic-gate 	(void) sighold(SIGCHLD);
4377*7c478bd9Sstevel@tonic-gate 
4378*7c478bd9Sstevel@tonic-gate 	while ((pid = fork()) < 0) {
4379*7c478bd9Sstevel@tonic-gate 		if (errno == EPERM) {
4380*7c478bd9Sstevel@tonic-gate 			console(B_TRUE, "Insufficient permission to fork.\n");
4381*7c478bd9Sstevel@tonic-gate 
4382*7c478bd9Sstevel@tonic-gate 			/* Now that's a doozy. */
4383*7c478bd9Sstevel@tonic-gate 			exit(1);
4384*7c478bd9Sstevel@tonic-gate 		}
4385*7c478bd9Sstevel@tonic-gate 
4386*7c478bd9Sstevel@tonic-gate 		console(B_TRUE,
4387*7c478bd9Sstevel@tonic-gate 		    "fork() for svc.startd failed: %s.  Will retry in 1 "
4388*7c478bd9Sstevel@tonic-gate 		    "second...\n", strerror(errno));
4389*7c478bd9Sstevel@tonic-gate 
4390*7c478bd9Sstevel@tonic-gate 		(void) sleep(1);
4391*7c478bd9Sstevel@tonic-gate 
4392*7c478bd9Sstevel@tonic-gate 		/* Eventually give up? */
4393*7c478bd9Sstevel@tonic-gate 	}
4394*7c478bd9Sstevel@tonic-gate 
4395*7c478bd9Sstevel@tonic-gate 	if (pid == 0) {
4396*7c478bd9Sstevel@tonic-gate 		/* child */
4397*7c478bd9Sstevel@tonic-gate 
4398*7c478bd9Sstevel@tonic-gate 		/* See the comment in efork() */
4399*7c478bd9Sstevel@tonic-gate 		for (i = SIGHUP; i <= SIGRTMAX; ++i) {
4400*7c478bd9Sstevel@tonic-gate 			if (i == SIGTTOU || i == SIGTTIN || i == SIGTSTP)
4401*7c478bd9Sstevel@tonic-gate 				(void) sigset(i, SIG_IGN);
4402*7c478bd9Sstevel@tonic-gate 			else
4403*7c478bd9Sstevel@tonic-gate 				(void) sigset(i, SIG_DFL);
4404*7c478bd9Sstevel@tonic-gate 		}
4405*7c478bd9Sstevel@tonic-gate 
4406*7c478bd9Sstevel@tonic-gate 		if (smf_options != NULL) {
4407*7c478bd9Sstevel@tonic-gate 			/* Put smf_options in the environment. */
4408*7c478bd9Sstevel@tonic-gate 			glob_envp[glob_envn] =
4409*7c478bd9Sstevel@tonic-gate 			    malloc(sizeof ("SMF_OPTIONS=") - 1 +
4410*7c478bd9Sstevel@tonic-gate 				strlen(smf_options) + 1);
4411*7c478bd9Sstevel@tonic-gate 
4412*7c478bd9Sstevel@tonic-gate 			if (glob_envp[glob_envn] != NULL) {
4413*7c478bd9Sstevel@tonic-gate 				/* LINTED */
4414*7c478bd9Sstevel@tonic-gate 				(void) sprintf(glob_envp[glob_envn],
4415*7c478bd9Sstevel@tonic-gate 				    "SMF_OPTIONS=%s", smf_options);
4416*7c478bd9Sstevel@tonic-gate 				glob_envp[glob_envn+1] = NULL;
4417*7c478bd9Sstevel@tonic-gate 			} else {
4418*7c478bd9Sstevel@tonic-gate 				console(B_TRUE,
4419*7c478bd9Sstevel@tonic-gate 				    "Could not set SMF_OPTIONS (%s).\n",
4420*7c478bd9Sstevel@tonic-gate 				    strerror(errno));
4421*7c478bd9Sstevel@tonic-gate 			}
4422*7c478bd9Sstevel@tonic-gate 		}
4423*7c478bd9Sstevel@tonic-gate 
4424*7c478bd9Sstevel@tonic-gate 		if (smf_debug)
4425*7c478bd9Sstevel@tonic-gate 			console(B_TRUE, "Executing svc.startd\n");
4426*7c478bd9Sstevel@tonic-gate 
4427*7c478bd9Sstevel@tonic-gate 		(void) execle(SH, "INITSH", "-c", cline, NULL, glob_envp);
4428*7c478bd9Sstevel@tonic-gate 
4429*7c478bd9Sstevel@tonic-gate 		console(B_TRUE, "Could not exec \"%s\" (%s).\n", SH,
4430*7c478bd9Sstevel@tonic-gate 		    strerror(errno));
4431*7c478bd9Sstevel@tonic-gate 
4432*7c478bd9Sstevel@tonic-gate 		exit(1);
4433*7c478bd9Sstevel@tonic-gate 	}
4434*7c478bd9Sstevel@tonic-gate 
4435*7c478bd9Sstevel@tonic-gate 	/* parent */
4436*7c478bd9Sstevel@tonic-gate 
4437*7c478bd9Sstevel@tonic-gate 	if (did_activate) {
4438*7c478bd9Sstevel@tonic-gate 		if (legacy_tmpl < 0 || ct_tmpl_activate(legacy_tmpl) != 0)
4439*7c478bd9Sstevel@tonic-gate 			(void) ct_tmpl_clear(tmpl);
4440*7c478bd9Sstevel@tonic-gate 	}
4441*7c478bd9Sstevel@tonic-gate 
4442*7c478bd9Sstevel@tonic-gate 	/* Clear the old_ctid reference so the kernel can reclaim it. */
4443*7c478bd9Sstevel@tonic-gate 	if (old_ctid != 0)
4444*7c478bd9Sstevel@tonic-gate 		(void) ct_pr_tmpl_set_transfer(tmpl, 0);
4445*7c478bd9Sstevel@tonic-gate 
4446*7c478bd9Sstevel@tonic-gate 	(void) sigrelse(SIGCHLD);
4447*7c478bd9Sstevel@tonic-gate 
4448*7c478bd9Sstevel@tonic-gate 	return (0);
4449*7c478bd9Sstevel@tonic-gate }
4450*7c478bd9Sstevel@tonic-gate 
4451*7c478bd9Sstevel@tonic-gate /*
4452*7c478bd9Sstevel@tonic-gate  * void startd_record_failure(void)
4453*7c478bd9Sstevel@tonic-gate  *   Place the current time in our circular array of svc.startd failures.
4454*7c478bd9Sstevel@tonic-gate  */
4455*7c478bd9Sstevel@tonic-gate void
4456*7c478bd9Sstevel@tonic-gate startd_record_failure()
4457*7c478bd9Sstevel@tonic-gate {
4458*7c478bd9Sstevel@tonic-gate 	int index = startd_failure_index++ % NSTARTD_FAILURE_TIMES;
4459*7c478bd9Sstevel@tonic-gate 
4460*7c478bd9Sstevel@tonic-gate 	startd_failure_time[index] = gethrtime();
4461*7c478bd9Sstevel@tonic-gate }
4462*7c478bd9Sstevel@tonic-gate 
4463*7c478bd9Sstevel@tonic-gate /*
4464*7c478bd9Sstevel@tonic-gate  * int startd_failure_rate_critical(void)
4465*7c478bd9Sstevel@tonic-gate  *   Return true if the average failure interval is less than the permitted
4466*7c478bd9Sstevel@tonic-gate  *   interval.  Implicit success if insufficient measurements for an average
4467*7c478bd9Sstevel@tonic-gate  *   exist.
4468*7c478bd9Sstevel@tonic-gate  */
4469*7c478bd9Sstevel@tonic-gate int
4470*7c478bd9Sstevel@tonic-gate startd_failure_rate_critical()
4471*7c478bd9Sstevel@tonic-gate {
4472*7c478bd9Sstevel@tonic-gate 	int n = startd_failure_index;
4473*7c478bd9Sstevel@tonic-gate 	hrtime_t avg_ns = 0;
4474*7c478bd9Sstevel@tonic-gate 
4475*7c478bd9Sstevel@tonic-gate 	if (startd_failure_index < NSTARTD_FAILURE_TIMES)
4476*7c478bd9Sstevel@tonic-gate 		return (0);
4477*7c478bd9Sstevel@tonic-gate 
4478*7c478bd9Sstevel@tonic-gate 	avg_ns =
4479*7c478bd9Sstevel@tonic-gate 	    (startd_failure_time[(n - 1) % NSTARTD_FAILURE_TIMES] -
4480*7c478bd9Sstevel@tonic-gate 	    startd_failure_time[n % NSTARTD_FAILURE_TIMES]) /
4481*7c478bd9Sstevel@tonic-gate 	    NSTARTD_FAILURE_TIMES;
4482*7c478bd9Sstevel@tonic-gate 
4483*7c478bd9Sstevel@tonic-gate 	return (avg_ns < STARTD_FAILURE_RATE_NS);
4484*7c478bd9Sstevel@tonic-gate }
4485*7c478bd9Sstevel@tonic-gate 
4486*7c478bd9Sstevel@tonic-gate /*
4487*7c478bd9Sstevel@tonic-gate  * returns string that must be free'd
4488*7c478bd9Sstevel@tonic-gate  */
4489*7c478bd9Sstevel@tonic-gate 
4490*7c478bd9Sstevel@tonic-gate static char
4491*7c478bd9Sstevel@tonic-gate *audit_boot_msg()
4492*7c478bd9Sstevel@tonic-gate {
4493*7c478bd9Sstevel@tonic-gate 	char		*b, *p;
4494*7c478bd9Sstevel@tonic-gate 	char		desc[] = "booted";
4495*7c478bd9Sstevel@tonic-gate 	zoneid_t	zid = getzoneid();
4496*7c478bd9Sstevel@tonic-gate 
4497*7c478bd9Sstevel@tonic-gate 	b = malloc(sizeof (desc) + MAXNAMELEN + 3);
4498*7c478bd9Sstevel@tonic-gate 	if (b == NULL)
4499*7c478bd9Sstevel@tonic-gate 		return (b);
4500*7c478bd9Sstevel@tonic-gate 
4501*7c478bd9Sstevel@tonic-gate 	p = b;
4502*7c478bd9Sstevel@tonic-gate 	p += strlcpy(p, desc, sizeof (desc));
4503*7c478bd9Sstevel@tonic-gate 	if (zid != GLOBAL_ZONEID) {
4504*7c478bd9Sstevel@tonic-gate 		p += strlcpy(p, ": ", 3);
4505*7c478bd9Sstevel@tonic-gate 		(void) getzonenamebyid(zid, p, MAXNAMELEN);
4506*7c478bd9Sstevel@tonic-gate 	}
4507*7c478bd9Sstevel@tonic-gate 	return (b);
4508*7c478bd9Sstevel@tonic-gate }
4509*7c478bd9Sstevel@tonic-gate 
4510*7c478bd9Sstevel@tonic-gate /*
4511*7c478bd9Sstevel@tonic-gate  * Generate AUE_init_solaris audit record.  Return 1 if
4512*7c478bd9Sstevel@tonic-gate  * auditing is enabled in case the caller cares.
4513*7c478bd9Sstevel@tonic-gate  *
4514*7c478bd9Sstevel@tonic-gate  * In the case of userint() or a local zone invocation of
4515*7c478bd9Sstevel@tonic-gate  * one_true_init, the process initially contains the audit
4516*7c478bd9Sstevel@tonic-gate  * characteristics of the process that invoked init.  The first pass
4517*7c478bd9Sstevel@tonic-gate  * through here uses those characteristics then for the case of
4518*7c478bd9Sstevel@tonic-gate  * one_true_init in a local zone, clears them so subsequent system
4519*7c478bd9Sstevel@tonic-gate  * state changes won't be attributed to the person who booted the
4520*7c478bd9Sstevel@tonic-gate  * zone.
4521*7c478bd9Sstevel@tonic-gate  */
4522*7c478bd9Sstevel@tonic-gate static int
4523*7c478bd9Sstevel@tonic-gate audit_put_record(int pass_fail, int status, char *msg)
4524*7c478bd9Sstevel@tonic-gate {
4525*7c478bd9Sstevel@tonic-gate 	adt_session_data_t	*ah;
4526*7c478bd9Sstevel@tonic-gate 	adt_event_data_t	*event;
4527*7c478bd9Sstevel@tonic-gate 
4528*7c478bd9Sstevel@tonic-gate 	if (!adt_audit_enabled())
4529*7c478bd9Sstevel@tonic-gate 		return (0);
4530*7c478bd9Sstevel@tonic-gate 
4531*7c478bd9Sstevel@tonic-gate 	/*
4532*7c478bd9Sstevel@tonic-gate 	 * the PROC_DATA picks up the context to tell whether this is
4533*7c478bd9Sstevel@tonic-gate 	 * an attributed record (auid = -2 is unattributed)
4534*7c478bd9Sstevel@tonic-gate 	 */
4535*7c478bd9Sstevel@tonic-gate 	if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA)) {
4536*7c478bd9Sstevel@tonic-gate 		console(B_TRUE, "audit failure:  %s\n", strerror(errno));
4537*7c478bd9Sstevel@tonic-gate 		return (1);
4538*7c478bd9Sstevel@tonic-gate 	}
4539*7c478bd9Sstevel@tonic-gate 	event = adt_alloc_event(ah, ADT_init_solaris);
4540*7c478bd9Sstevel@tonic-gate 	if (event == NULL) {
4541*7c478bd9Sstevel@tonic-gate 		console(B_TRUE, "audit failure:  %s\n", strerror(errno));
4542*7c478bd9Sstevel@tonic-gate 		(void) adt_end_session(ah);
4543*7c478bd9Sstevel@tonic-gate 		return (1);
4544*7c478bd9Sstevel@tonic-gate 	}
4545*7c478bd9Sstevel@tonic-gate 	event->adt_init_solaris.info = msg;	/* NULL is ok here */
4546*7c478bd9Sstevel@tonic-gate 
4547*7c478bd9Sstevel@tonic-gate 	if (adt_put_event(event, pass_fail, status)) {
4548*7c478bd9Sstevel@tonic-gate 		console(B_TRUE, "audit failure:  %s\n", strerror(errno));
4549*7c478bd9Sstevel@tonic-gate 		(void) adt_end_session(ah);
4550*7c478bd9Sstevel@tonic-gate 		return (1);
4551*7c478bd9Sstevel@tonic-gate 	}
4552*7c478bd9Sstevel@tonic-gate 	adt_free_event(event);
4553*7c478bd9Sstevel@tonic-gate 
4554*7c478bd9Sstevel@tonic-gate 	(void) adt_end_session(ah);
4555*7c478bd9Sstevel@tonic-gate 
4556*7c478bd9Sstevel@tonic-gate 	return (1);
4557*7c478bd9Sstevel@tonic-gate }
4558