xref: /illumos-gate/usr/src/cmd/init/init.c (revision 39cc040ff7c0c62aae858381f21d0567dd60042e)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
505b96de2Smjnelson  * Common Development and Distribution License (the "License").
605b96de2Smjnelson  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
2105b96de2Smjnelson 
227c478bd9Sstevel@tonic-gate /*
230a1278f2SGary Mills  * Copyright (c) 2013 Gary Mills
240a1278f2SGary Mills  *
25861a9162SJohn Beck  * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
297c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate /*
327c478bd9Sstevel@tonic-gate  * University Copyright- Copyright (c) 1982, 1986, 1988
337c478bd9Sstevel@tonic-gate  * The Regents of the University of California
347c478bd9Sstevel@tonic-gate  * All Rights Reserved
357c478bd9Sstevel@tonic-gate  *
367c478bd9Sstevel@tonic-gate  * University Acknowledgment- Portions of this document are derived from
377c478bd9Sstevel@tonic-gate  * software developed by the University of California, Berkeley, and its
387c478bd9Sstevel@tonic-gate  * contributors.
397c478bd9Sstevel@tonic-gate  */
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate /*
427c478bd9Sstevel@tonic-gate  * init(1M) is the general process spawning program.  Its primary job is to
437c478bd9Sstevel@tonic-gate  * start and restart svc.startd for smf(5).  For backwards-compatibility it also
447c478bd9Sstevel@tonic-gate  * spawns and respawns processes according to /etc/inittab and the current
457c478bd9Sstevel@tonic-gate  * run-level.  It reads /etc/default/inittab for general configuration.
467c478bd9Sstevel@tonic-gate  *
477c478bd9Sstevel@tonic-gate  * To change run-levels the system administrator runs init from the command
487c478bd9Sstevel@tonic-gate  * line with a level name.  init signals svc.startd via libscf and directs the
497c478bd9Sstevel@tonic-gate  * zone's init (pid 1 in the global zone) what to do by sending it a signal;
507c478bd9Sstevel@tonic-gate  * these signal numbers are commonly refered to in the code as 'states'.  Valid
517c478bd9Sstevel@tonic-gate  * run-levels are [sS0123456].  Additionally, init can be given directives
527c478bd9Sstevel@tonic-gate  * [qQabc], which indicate actions to be taken pertaining to /etc/inittab.
537c478bd9Sstevel@tonic-gate  *
547c478bd9Sstevel@tonic-gate  * When init processes inittab entries, it finds processes that are to be
557c478bd9Sstevel@tonic-gate  * spawned at various run-levels.  inittab contains the set of the levels for
567c478bd9Sstevel@tonic-gate  * which each inittab entry is valid.
577c478bd9Sstevel@tonic-gate  *
587c478bd9Sstevel@tonic-gate  * State File and Restartability
597c478bd9Sstevel@tonic-gate  *   Premature exit by init(1M) is handled as a special case by the kernel:
607c478bd9Sstevel@tonic-gate  *   init(1M) will be immediately re-executed, retaining its original PID.  (PID
617c478bd9Sstevel@tonic-gate  *   1 in the global zone.)  To track the processes it has previously spawned,
627c478bd9Sstevel@tonic-gate  *   as well as other mutable state, init(1M) regularly updates a state file
637c478bd9Sstevel@tonic-gate  *   such that its subsequent invocations have knowledge of its various
647c478bd9Sstevel@tonic-gate  *   dependent processes and duties.
657c478bd9Sstevel@tonic-gate  *
667c478bd9Sstevel@tonic-gate  * Process Contracts
677c478bd9Sstevel@tonic-gate  *   We start svc.startd(1M) in a contract and transfer inherited contracts when
687c478bd9Sstevel@tonic-gate  *   restarting it.  Everything else is started using the legacy contract
697c478bd9Sstevel@tonic-gate  *   template, and the created contracts are abandoned when they become empty.
707c478bd9Sstevel@tonic-gate  *
717c478bd9Sstevel@tonic-gate  * utmpx Entry Handling
727c478bd9Sstevel@tonic-gate  *   Because init(1M) no longer governs the startup process, its knowledge of
737c478bd9Sstevel@tonic-gate  *   when utmpx becomes writable is indirect.  However, spawned processes
747c478bd9Sstevel@tonic-gate  *   expect to be constructed with valid utmpx entries.  As a result, attempts
757c478bd9Sstevel@tonic-gate  *   to write normal entries will be retried until successful.
767c478bd9Sstevel@tonic-gate  *
777c478bd9Sstevel@tonic-gate  * Maintenance Mode
787c478bd9Sstevel@tonic-gate  *   In certain failure scenarios, init(1M) will enter a maintenance mode, in
797c478bd9Sstevel@tonic-gate  *   which it invokes sulogin(1M) to allow the operator an opportunity to
807c478bd9Sstevel@tonic-gate  *   repair the system.  Normally, this operation is performed as a
817c478bd9Sstevel@tonic-gate  *   fork(2)-exec(2)-waitpid(3C) sequence with the parent waiting for repair or
827c478bd9Sstevel@tonic-gate  *   diagnosis to be completed.  In the cases that fork(2) requests themselves
837c478bd9Sstevel@tonic-gate  *   fail, init(1M) will directly execute sulogin(1M), and allow the kernel to
847c478bd9Sstevel@tonic-gate  *   restart init(1M) on exit from the operator session.
857c478bd9Sstevel@tonic-gate  *
867c478bd9Sstevel@tonic-gate  *   One scenario where init(1M) enters its maintenance mode is when
877c478bd9Sstevel@tonic-gate  *   svc.startd(1M) begins to fail rapidly, defined as when the average time
887c478bd9Sstevel@tonic-gate  *   between recent failures drops below a given threshold.
897c478bd9Sstevel@tonic-gate  */
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate #include <sys/contract/process.h>
927c478bd9Sstevel@tonic-gate #include <sys/ctfs.h>
937c478bd9Sstevel@tonic-gate #include <sys/stat.h>
947c478bd9Sstevel@tonic-gate #include <sys/statvfs.h>
957c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
967c478bd9Sstevel@tonic-gate #include <sys/systeminfo.h>
977c478bd9Sstevel@tonic-gate #include <sys/time.h>
987c478bd9Sstevel@tonic-gate #include <sys/termios.h>
997c478bd9Sstevel@tonic-gate #include <sys/tty.h>
1007c478bd9Sstevel@tonic-gate #include <sys/types.h>
1017c478bd9Sstevel@tonic-gate #include <sys/utsname.h>
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate #include <bsm/adt_event.h>
1047c478bd9Sstevel@tonic-gate #include <bsm/libbsm.h>
1057c478bd9Sstevel@tonic-gate #include <security/pam_appl.h>
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate #include <assert.h>
1087c478bd9Sstevel@tonic-gate #include <ctype.h>
1097c478bd9Sstevel@tonic-gate #include <dirent.h>
1107c478bd9Sstevel@tonic-gate #include <errno.h>
1117c478bd9Sstevel@tonic-gate #include <fcntl.h>
1127c478bd9Sstevel@tonic-gate #include <libcontract.h>
1137c478bd9Sstevel@tonic-gate #include <libcontract_priv.h>
1147c478bd9Sstevel@tonic-gate #include <libintl.h>
1157c478bd9Sstevel@tonic-gate #include <libscf.h>
1167c478bd9Sstevel@tonic-gate #include <libscf_priv.h>
1177c478bd9Sstevel@tonic-gate #include <poll.h>
1187c478bd9Sstevel@tonic-gate #include <procfs.h>
1197c478bd9Sstevel@tonic-gate #include <signal.h>
1207c478bd9Sstevel@tonic-gate #include <stdarg.h>
1217c478bd9Sstevel@tonic-gate #include <stdio.h>
1227c478bd9Sstevel@tonic-gate #include <stdio_ext.h>
1237c478bd9Sstevel@tonic-gate #include <stdlib.h>
1247c478bd9Sstevel@tonic-gate #include <string.h>
1257c478bd9Sstevel@tonic-gate #include <strings.h>
1267c478bd9Sstevel@tonic-gate #include <syslog.h>
1277c478bd9Sstevel@tonic-gate #include <time.h>
1287c478bd9Sstevel@tonic-gate #include <ulimit.h>
1297c478bd9Sstevel@tonic-gate #include <unistd.h>
1307c478bd9Sstevel@tonic-gate #include <utmpx.h>
1317c478bd9Sstevel@tonic-gate #include <wait.h>
1327c478bd9Sstevel@tonic-gate #include <zone.h>
1337c478bd9Sstevel@tonic-gate #include <ucontext.h>
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate #undef	sleep
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate #define	fioctl(p, sptr, cmd)	ioctl(fileno(p), sptr, cmd)
1387c478bd9Sstevel@tonic-gate #define	min(a, b)		(((a) < (b)) ? (a) : (b))
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate #define	TRUE	1
1417c478bd9Sstevel@tonic-gate #define	FALSE	0
1427c478bd9Sstevel@tonic-gate #define	FAILURE	-1
1437c478bd9Sstevel@tonic-gate 
1440a1278f2SGary Mills #define	UT_USER_SZ	32	/* Size of a utmpx ut_user field */
1457c478bd9Sstevel@tonic-gate #define	UT_LINE_SZ	32	/* Size of a utmpx ut_line field */
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate /*
1487c478bd9Sstevel@tonic-gate  * SLEEPTIME	The number of seconds "init" sleeps between wakeups if
1497c478bd9Sstevel@tonic-gate  *		nothing else requires this "init" wakeup.
1507c478bd9Sstevel@tonic-gate  */
1517c478bd9Sstevel@tonic-gate #define	SLEEPTIME	(5 * 60)
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate /*
1547c478bd9Sstevel@tonic-gate  * MAXCMDL	The maximum length of a command string in inittab.
1557c478bd9Sstevel@tonic-gate  */
1567c478bd9Sstevel@tonic-gate #define	MAXCMDL	512
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate /*
1597c478bd9Sstevel@tonic-gate  * EXEC		The length of the prefix string added to all comamnds
1607c478bd9Sstevel@tonic-gate  *		found in inittab.
1617c478bd9Sstevel@tonic-gate  */
1627c478bd9Sstevel@tonic-gate #define	EXEC	(sizeof ("exec ") - 1)
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate /*
1657c478bd9Sstevel@tonic-gate  * TWARN	The amount of time between warning signal, SIGTERM,
1667c478bd9Sstevel@tonic-gate  *		and the fatal kill signal, SIGKILL.
1677c478bd9Sstevel@tonic-gate  */
1687c478bd9Sstevel@tonic-gate #define	TWARN	5
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate #define	id_eq(x, y)	((x[0] == y[0] && x[1] == y[1] && x[2] == y[2] &&\
1717c478bd9Sstevel@tonic-gate 			x[3] == y[3]) ? TRUE : FALSE)
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate /*
1747c478bd9Sstevel@tonic-gate  * The kernel's default umask is 022 these days; since some processes inherit
1757c478bd9Sstevel@tonic-gate  * their umask from init, init will set it from CMASK in /etc/default/init.
1767c478bd9Sstevel@tonic-gate  * init gets the default umask from the kernel, it sets it to 022 whenever
1777c478bd9Sstevel@tonic-gate  * it wants to create a file and reverts to CMASK afterwards.
1787c478bd9Sstevel@tonic-gate  */
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate static int cmask;
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate /*
1837c478bd9Sstevel@tonic-gate  * The following definitions, concluding with the 'lvls' array, provide a
1847c478bd9Sstevel@tonic-gate  * common mapping between level-name (like 'S'), signal number (state),
1857c478bd9Sstevel@tonic-gate  * run-level mask, and specific properties associated with a run-level.
1867c478bd9Sstevel@tonic-gate  * This array should be accessed using the routines lvlname_to_state(),
1877c478bd9Sstevel@tonic-gate  * lvlname_to_mask(), state_to_mask(), and state_to_flags().
1887c478bd9Sstevel@tonic-gate  */
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate /*
1917c478bd9Sstevel@tonic-gate  * Correspondence of signals to init actions.
1927c478bd9Sstevel@tonic-gate  */
1937c478bd9Sstevel@tonic-gate #define	LVLQ		SIGHUP
1947c478bd9Sstevel@tonic-gate #define	LVL0		SIGINT
1957c478bd9Sstevel@tonic-gate #define	LVL1		SIGQUIT
1967c478bd9Sstevel@tonic-gate #define	LVL2		SIGILL
1977c478bd9Sstevel@tonic-gate #define	LVL3		SIGTRAP
1987c478bd9Sstevel@tonic-gate #define	LVL4		SIGIOT
1997c478bd9Sstevel@tonic-gate #define	LVL5		SIGEMT
2007c478bd9Sstevel@tonic-gate #define	LVL6		SIGFPE
2017c478bd9Sstevel@tonic-gate #define	SINGLE_USER	SIGBUS
2027c478bd9Sstevel@tonic-gate #define	LVLa		SIGSEGV
2037c478bd9Sstevel@tonic-gate #define	LVLb		SIGSYS
2047c478bd9Sstevel@tonic-gate #define	LVLc		SIGPIPE
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate /*
2077c478bd9Sstevel@tonic-gate  * Bit Mask for each level.  Used to determine legal levels.
2087c478bd9Sstevel@tonic-gate  */
2097c478bd9Sstevel@tonic-gate #define	MASK0	0x0001
2107c478bd9Sstevel@tonic-gate #define	MASK1	0x0002
2117c478bd9Sstevel@tonic-gate #define	MASK2	0x0004
2127c478bd9Sstevel@tonic-gate #define	MASK3	0x0008
2137c478bd9Sstevel@tonic-gate #define	MASK4	0x0010
2147c478bd9Sstevel@tonic-gate #define	MASK5	0x0020
2157c478bd9Sstevel@tonic-gate #define	MASK6	0x0040
2167c478bd9Sstevel@tonic-gate #define	MASKSU	0x0080
2177c478bd9Sstevel@tonic-gate #define	MASKa	0x0100
2187c478bd9Sstevel@tonic-gate #define	MASKb	0x0200
2197c478bd9Sstevel@tonic-gate #define	MASKc	0x0400
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate #define	MASK_NUMERIC (MASK0 | MASK1 | MASK2 | MASK3 | MASK4 | MASK5 | MASK6)
2227c478bd9Sstevel@tonic-gate #define	MASK_abc (MASKa | MASKb | MASKc)
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate /*
2257c478bd9Sstevel@tonic-gate  * Flags to indicate properties of various states.
2267c478bd9Sstevel@tonic-gate  */
2277c478bd9Sstevel@tonic-gate #define	LSEL_RUNLEVEL	0x0001	/* runlevels you can transition to */
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate typedef struct lvl {
2307c478bd9Sstevel@tonic-gate 	int	lvl_state;
2317c478bd9Sstevel@tonic-gate 	int	lvl_mask;
2327c478bd9Sstevel@tonic-gate 	char	lvl_name;
2337c478bd9Sstevel@tonic-gate 	int	lvl_flags;
2347c478bd9Sstevel@tonic-gate } lvl_t;
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate static lvl_t lvls[] = {
2377c478bd9Sstevel@tonic-gate 	{ LVLQ,		0,	'Q', 0					},
2387c478bd9Sstevel@tonic-gate 	{ LVLQ,		0,	'q', 0					},
2396d59ee37Spaulson 	{ LVL0,		MASK0,	'0', LSEL_RUNLEVEL			},
2406d59ee37Spaulson 	{ LVL1, 	MASK1,	'1', LSEL_RUNLEVEL			},
2417c478bd9Sstevel@tonic-gate 	{ LVL2, 	MASK2,	'2', LSEL_RUNLEVEL			},
2427c478bd9Sstevel@tonic-gate 	{ LVL3, 	MASK3,	'3', LSEL_RUNLEVEL			},
2437c478bd9Sstevel@tonic-gate 	{ LVL4, 	MASK4,	'4', LSEL_RUNLEVEL			},
2446d59ee37Spaulson 	{ LVL5, 	MASK5,	'5', LSEL_RUNLEVEL			},
2456d59ee37Spaulson 	{ LVL6, 	MASK6, 	'6', LSEL_RUNLEVEL			},
2466d59ee37Spaulson 	{ SINGLE_USER, 	MASKSU, 'S', LSEL_RUNLEVEL			},
2476d59ee37Spaulson 	{ SINGLE_USER, 	MASKSU, 's', LSEL_RUNLEVEL			},
2487c478bd9Sstevel@tonic-gate 	{ LVLa,		MASKa,	'a', 0					},
2497c478bd9Sstevel@tonic-gate 	{ LVLb,		MASKb,	'b', 0					},
2507c478bd9Sstevel@tonic-gate 	{ LVLc,		MASKc,	'c', 0					}
2517c478bd9Sstevel@tonic-gate };
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate #define	LVL_NELEMS (sizeof (lvls) / sizeof (lvl_t))
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate /*
2567c478bd9Sstevel@tonic-gate  * Legal action field values.
2577c478bd9Sstevel@tonic-gate  */
2587c478bd9Sstevel@tonic-gate #define	OFF		0	/* Kill process if on, else ignore */
2597c478bd9Sstevel@tonic-gate #define	RESPAWN		1	/* Continuously restart process when it dies */
2607c478bd9Sstevel@tonic-gate #define	ONDEMAND	RESPAWN	/* Respawn for a, b, c type processes */
2617c478bd9Sstevel@tonic-gate #define	ONCE		2	/* Start process, do not respawn when dead */
2627c478bd9Sstevel@tonic-gate #define	WAIT		3	/* Perform once and wait to complete */
2637c478bd9Sstevel@tonic-gate #define	BOOT		4	/* Start at boot time only */
2647c478bd9Sstevel@tonic-gate #define	BOOTWAIT	5	/* Start at boot time and wait to complete */
2657c478bd9Sstevel@tonic-gate #define	POWERFAIL	6	/* Start on powerfail */
2667c478bd9Sstevel@tonic-gate #define	POWERWAIT	7	/* Start and wait for complete on powerfail */
2677c478bd9Sstevel@tonic-gate #define	INITDEFAULT	8	/* Default level "init" should start at */
2687c478bd9Sstevel@tonic-gate #define	SYSINIT		9	/* Actions performed before init speaks */
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate #define	M_OFF		0001
2717c478bd9Sstevel@tonic-gate #define	M_RESPAWN	0002
2727c478bd9Sstevel@tonic-gate #define	M_ONDEMAND	M_RESPAWN
2737c478bd9Sstevel@tonic-gate #define	M_ONCE		0004
2747c478bd9Sstevel@tonic-gate #define	M_WAIT		0010
2757c478bd9Sstevel@tonic-gate #define	M_BOOT		0020
2767c478bd9Sstevel@tonic-gate #define	M_BOOTWAIT	0040
2777c478bd9Sstevel@tonic-gate #define	M_PF		0100
2787c478bd9Sstevel@tonic-gate #define	M_PWAIT		0200
2797c478bd9Sstevel@tonic-gate #define	M_INITDEFAULT	0400
2807c478bd9Sstevel@tonic-gate #define	M_SYSINIT	01000
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate /* States for the inittab parser in getcmd(). */
2837c478bd9Sstevel@tonic-gate #define	ID	1
2847c478bd9Sstevel@tonic-gate #define	LEVELS	2
2857c478bd9Sstevel@tonic-gate #define	ACTION	3
2867c478bd9Sstevel@tonic-gate #define	COMMAND	4
2877c478bd9Sstevel@tonic-gate #define	COMMENT	5
2887c478bd9Sstevel@tonic-gate 
2897b209c2cSacruz /*
2907b209c2cSacruz  * inittab entry id constants
2917b209c2cSacruz  */
2927b209c2cSacruz #define	INITTAB_ENTRY_ID_SIZE 4
2937b209c2cSacruz #define	INITTAB_ENTRY_ID_STR_FORMAT "%.4s"	/* if INITTAB_ENTRY_ID_SIZE */
2947b209c2cSacruz 						/* changes, this should */
2957b209c2cSacruz 						/* change accordingly */
2967b209c2cSacruz 
2977c478bd9Sstevel@tonic-gate /*
2987c478bd9Sstevel@tonic-gate  * Init can be in any of three main states, "normal" mode where it is
2997c478bd9Sstevel@tonic-gate  * processing entries for the lines file in a normal fashion, "boot" mode,
3007c478bd9Sstevel@tonic-gate  * where it is only interested in the boot actions, and "powerfail" mode,
3017c478bd9Sstevel@tonic-gate  * where it is only interested in powerfail related actions. The following
3027c478bd9Sstevel@tonic-gate  * masks declare the legal actions for each mode.
3037c478bd9Sstevel@tonic-gate  */
3047c478bd9Sstevel@tonic-gate #define	NORMAL_MODES	(M_OFF | M_RESPAWN | M_ONCE | M_WAIT)
3057c478bd9Sstevel@tonic-gate #define	BOOT_MODES	(M_BOOT | M_BOOTWAIT)
3067c478bd9Sstevel@tonic-gate #define	PF_MODES	(M_PF | M_PWAIT)
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate struct PROC_TABLE {
3097b209c2cSacruz 	char	p_id[INITTAB_ENTRY_ID_SIZE];	/* Four letter unique id of */
3107b209c2cSacruz 						/* process */
3117c478bd9Sstevel@tonic-gate 	pid_t	p_pid;		/* Process id */
3127c478bd9Sstevel@tonic-gate 	short	p_count;	/* How many respawns of this command in */
3137c478bd9Sstevel@tonic-gate 				/*   the current series */
3147c478bd9Sstevel@tonic-gate 	long	p_time;		/* Start time for a series of respawns */
3157c478bd9Sstevel@tonic-gate 	short	p_flags;
3167c478bd9Sstevel@tonic-gate 	short	p_exit;		/* Exit status of a process which died */
3177c478bd9Sstevel@tonic-gate };
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate /*
3207c478bd9Sstevel@tonic-gate  * Flags for the "p_flags" word of a PROC_TABLE entry:
3217c478bd9Sstevel@tonic-gate  *
3227c478bd9Sstevel@tonic-gate  *	OCCUPIED	This slot in init's proc table is in use.
3237c478bd9Sstevel@tonic-gate  *
3247c478bd9Sstevel@tonic-gate  *	LIVING		Process is alive.
3257c478bd9Sstevel@tonic-gate  *
3267c478bd9Sstevel@tonic-gate  *	NOCLEANUP	efork() is not allowed to cleanup this entry even
3277c478bd9Sstevel@tonic-gate  *			if process is dead.
3287c478bd9Sstevel@tonic-gate  *
3297c478bd9Sstevel@tonic-gate  *	NAMED		This process has a name, i.e. came from inittab.
3307c478bd9Sstevel@tonic-gate  *
3317c478bd9Sstevel@tonic-gate  *	DEMANDREQUEST	Process started by a "telinit [abc]" command.  Processes
3327c478bd9Sstevel@tonic-gate  *			formed this way are respawnable and immune to level
3337c478bd9Sstevel@tonic-gate  *			changes as long as their entry exists in inittab.
3347c478bd9Sstevel@tonic-gate  *
3357c478bd9Sstevel@tonic-gate  *	TOUCHED		Flag used by remv() to determine whether it has looked
3367c478bd9Sstevel@tonic-gate  *			at an entry while checking for processes to be killed.
3377c478bd9Sstevel@tonic-gate  *
3387c478bd9Sstevel@tonic-gate  *	WARNED		Flag used by remv() to mark processes that have been
3397c478bd9Sstevel@tonic-gate  *			sent the SIGTERM signal.  If they don't die in 5
3407c478bd9Sstevel@tonic-gate  *			seconds, they are sent the SIGKILL signal.
3417c478bd9Sstevel@tonic-gate  *
3427c478bd9Sstevel@tonic-gate  *	KILLED		Flag used by remv() to mark procs that have been sent
3437c478bd9Sstevel@tonic-gate  *			the SIGTERM and SIGKILL signals.
3447c478bd9Sstevel@tonic-gate  *
3457c478bd9Sstevel@tonic-gate  *	PF_MASK		Bitwise or of legal flags, for sanity checking.
3467c478bd9Sstevel@tonic-gate  */
3477c478bd9Sstevel@tonic-gate #define	OCCUPIED	01
3487c478bd9Sstevel@tonic-gate #define	LIVING		02
3497c478bd9Sstevel@tonic-gate #define	NOCLEANUP	04
3507c478bd9Sstevel@tonic-gate #define	NAMED		010
3517c478bd9Sstevel@tonic-gate #define	DEMANDREQUEST	020
3527c478bd9Sstevel@tonic-gate #define	TOUCHED		040
3537c478bd9Sstevel@tonic-gate #define	WARNED		0100
3547c478bd9Sstevel@tonic-gate #define	KILLED		0200
3557c478bd9Sstevel@tonic-gate #define	PF_MASK		0377
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate /*
3587c478bd9Sstevel@tonic-gate  * Respawn limits for processes that are to be respawned:
3597c478bd9Sstevel@tonic-gate  *
3607c478bd9Sstevel@tonic-gate  *	SPAWN_INTERVAL	The number of seconds over which "init" will try to
3617c478bd9Sstevel@tonic-gate  *			respawn a process SPAWN_LIMIT times before it gets mad.
3627c478bd9Sstevel@tonic-gate  *
3637c478bd9Sstevel@tonic-gate  *	SPAWN_LIMIT	The number of respawns "init" will attempt in
3647c478bd9Sstevel@tonic-gate  *			SPAWN_INTERVAL seconds before it generates an
3657c478bd9Sstevel@tonic-gate  *			error message and inhibits further tries for
3667c478bd9Sstevel@tonic-gate  *			INHIBIT seconds.
3677c478bd9Sstevel@tonic-gate  *
3687c478bd9Sstevel@tonic-gate  *	INHIBIT		The number of seconds "init" ignores an entry it had
3697c478bd9Sstevel@tonic-gate  *			trouble spawning unless a "telinit Q" is received.
3707c478bd9Sstevel@tonic-gate  */
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate #define	SPAWN_INTERVAL	(2*60)
3737c478bd9Sstevel@tonic-gate #define	SPAWN_LIMIT	10
3747c478bd9Sstevel@tonic-gate #define	INHIBIT		(5*60)
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate /*
3777c478bd9Sstevel@tonic-gate  * The maximum number of decimal digits for an id_t.  (ceil(log10 (max_id)))
3787c478bd9Sstevel@tonic-gate  */
3797c478bd9Sstevel@tonic-gate #define	ID_MAX_STR_LEN	10
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate #define	NULLPROC	((struct PROC_TABLE *)(0))
3827c478bd9Sstevel@tonic-gate #define	NO_ROOM		((struct PROC_TABLE *)(FAILURE))
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate struct CMD_LINE {
3857b209c2cSacruz 	char c_id[INITTAB_ENTRY_ID_SIZE];	/* Four letter unique id of */
3867b209c2cSacruz 						/* process to be affected by */
3877b209c2cSacruz 						/* action */
3887c478bd9Sstevel@tonic-gate 	short c_levels;	/* Mask of legal levels for process */
3897c478bd9Sstevel@tonic-gate 	short c_action;	/* Mask for type of action required */
3907c478bd9Sstevel@tonic-gate 	char *c_command; /* Pointer to init command */
3917c478bd9Sstevel@tonic-gate };
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate struct	pidrec {
3947c478bd9Sstevel@tonic-gate 	int	pd_type;	/* Command type */
3957c478bd9Sstevel@tonic-gate 	pid_t	pd_pid;		/* pid to add or remove */
3967c478bd9Sstevel@tonic-gate };
3977c478bd9Sstevel@tonic-gate 
3987c478bd9Sstevel@tonic-gate /*
3997c478bd9Sstevel@tonic-gate  * pd_type's
4007c478bd9Sstevel@tonic-gate  */
4017c478bd9Sstevel@tonic-gate #define	ADDPID	1
4027c478bd9Sstevel@tonic-gate #define	REMPID	2
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate static struct	pidlist {
4057c478bd9Sstevel@tonic-gate 	pid_t	pl_pid;		/* pid to watch for */
4067c478bd9Sstevel@tonic-gate 	int	pl_dflag;	/* Flag indicating SIGCLD from this pid */
4077c478bd9Sstevel@tonic-gate 	short	pl_exit;	/* Exit status of proc */
4087c478bd9Sstevel@tonic-gate 	struct	pidlist	*pl_next; /* Next in list */
4097c478bd9Sstevel@tonic-gate } *Plhead, *Plfree;
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate /*
4127c478bd9Sstevel@tonic-gate  * The following structure contains a set of modes for /dev/syscon
413*39cc040fSToomas Soome  * and should match the default contents of /etc/ioctl.syscon.
4147c478bd9Sstevel@tonic-gate  */
4157c478bd9Sstevel@tonic-gate static struct termios	dflt_termios = {
416*39cc040fSToomas Soome 	.c_iflag = BRKINT|ICRNL|IXON|IMAXBEL,
417*39cc040fSToomas Soome 	.c_oflag = OPOST|ONLCR|TAB3,
418*39cc040fSToomas Soome 	.c_cflag = CS8|CREAD|B9600,
419*39cc040fSToomas Soome 	.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK|ECHOCTL|ECHOKE|IEXTEN,
420*39cc040fSToomas Soome 	.c_cc = { CINTR, CQUIT, CERASE, CKILL, CEOF, 0, 0, 0,
421*39cc040fSToomas Soome 	    CSTART, CSTOP, CSWTCH, CDSUSP, CRPRNT, CFLUSH, CWERASE, CLNEXT,
422*39cc040fSToomas Soome 	    CSTATUS, CERASE2, 0
423*39cc040fSToomas Soome 	}
4247c478bd9Sstevel@tonic-gate };
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate static struct termios	stored_syscon_termios;
4277c478bd9Sstevel@tonic-gate static int		write_ioctl = 0;	/* Rewrite /etc/ioctl.syscon */
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate static union WAKEUP {
4307c478bd9Sstevel@tonic-gate 	struct WAKEFLAGS {
4317c478bd9Sstevel@tonic-gate 		unsigned w_usersignal : 1;	/* User sent signal to "init" */
4327c478bd9Sstevel@tonic-gate 		unsigned w_childdeath : 1;	/* An "init" child died */
4337c478bd9Sstevel@tonic-gate 		unsigned w_powerhit : 1;	/* OS experienced powerfail */
4347c478bd9Sstevel@tonic-gate 	}	w_flags;
4357c478bd9Sstevel@tonic-gate 	int w_mask;
4367c478bd9Sstevel@tonic-gate } wakeup;
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate struct init_state {
4407c478bd9Sstevel@tonic-gate 	int			ist_runlevel;
4417c478bd9Sstevel@tonic-gate 	int			ist_num_proc;
4427c478bd9Sstevel@tonic-gate 	int			ist_utmpx_ok;
4437c478bd9Sstevel@tonic-gate 	struct PROC_TABLE	ist_proc_table[1];
4447c478bd9Sstevel@tonic-gate };
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate #define	cur_state	(g_state->ist_runlevel)
4477c478bd9Sstevel@tonic-gate #define	num_proc	(g_state->ist_num_proc)
4487c478bd9Sstevel@tonic-gate #define	proc_table	(g_state->ist_proc_table)
4497c478bd9Sstevel@tonic-gate #define	utmpx_ok	(g_state->ist_utmpx_ok)
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate /* Contract cookies. */
4527c478bd9Sstevel@tonic-gate #define	ORDINARY_COOKIE		0
4537c478bd9Sstevel@tonic-gate #define	STARTD_COOKIE		1
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate #ifndef NDEBUG
4577c478bd9Sstevel@tonic-gate #define	bad_error(func, err)	{					\
4587c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "%s:%d: %s() failed with unexpected "	\
4597c478bd9Sstevel@tonic-gate 	    "error %d.  Aborting.\n", __FILE__, __LINE__, (func), (err)); \
4607c478bd9Sstevel@tonic-gate 	abort();							\
4617c478bd9Sstevel@tonic-gate }
4627c478bd9Sstevel@tonic-gate #else
4637c478bd9Sstevel@tonic-gate #define	bad_error(func, err)	abort()
4647c478bd9Sstevel@tonic-gate #endif
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate /*
4687c478bd9Sstevel@tonic-gate  * Useful file and device names.
4697c478bd9Sstevel@tonic-gate  */
4707c478bd9Sstevel@tonic-gate static char *CONSOLE	  = "/dev/console";	/* Real system console */
47192ba7109Seschrock static char *INITPIPE_DIR = "/var/run";
47292ba7109Seschrock static char *INITPIPE	  = "/var/run/initpipe";
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate #define	INIT_STATE_DIR "/etc/svc/volatile"
4757c478bd9Sstevel@tonic-gate static const char * const init_state_file = INIT_STATE_DIR "/init.state";
4767c478bd9Sstevel@tonic-gate static const char * const init_next_state_file =
4777c478bd9Sstevel@tonic-gate 	INIT_STATE_DIR "/init-next.state";
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate static const int init_num_proc = 20;	/* Initial size of process table. */
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate static char *UTMPX	 = UTMPX_FILE;		/* Snapshot record file */
4827c478bd9Sstevel@tonic-gate static char *WTMPX	 = WTMPX_FILE;		/* Long term record file */
4837c478bd9Sstevel@tonic-gate static char *INITTAB	 = "/etc/inittab";	/* Script file for "init" */
4847c478bd9Sstevel@tonic-gate static char *SYSTTY	 = "/dev/systty";	/* System Console */
4857c478bd9Sstevel@tonic-gate static char *SYSCON	 = "/dev/syscon";	/* Virtual System console */
4867c478bd9Sstevel@tonic-gate static char *IOCTLSYSCON = "/etc/ioctl.syscon";	/* Last syscon modes */
4877c478bd9Sstevel@tonic-gate static char *ENVFILE	 = "/etc/default/init";	/* Default env. */
4887c478bd9Sstevel@tonic-gate static char *SU	= "/etc/sulogin";	/* Super-user program for single user */
4897c478bd9Sstevel@tonic-gate static char *SH	= "/sbin/sh";		/* Standard shell */
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate /*
4927c478bd9Sstevel@tonic-gate  * Default Path.  /sbin is included in path only during sysinit phase
4937c478bd9Sstevel@tonic-gate  */
4947c478bd9Sstevel@tonic-gate #define	DEF_PATH	"PATH=/usr/sbin:/usr/bin"
4957c478bd9Sstevel@tonic-gate #define	INIT_PATH	"PATH=/sbin:/usr/sbin:/usr/bin"
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate static int	prior_state;
4987c478bd9Sstevel@tonic-gate static int	prev_state;	/* State "init" was in last time it woke */
4997c478bd9Sstevel@tonic-gate static int	new_state;	/* State user wants "init" to go to. */
50092ba7109Seschrock static int	lvlq_received;	/* Explicit request to examine state */
5017c478bd9Sstevel@tonic-gate static int	op_modes = BOOT_MODES; /* Current state of "init" */
5027c478bd9Sstevel@tonic-gate static int	Gchild = 0;	/* Flag to indicate "godchild" died, set in */
5037c478bd9Sstevel@tonic-gate 				/*   childeath() and cleared in cleanaux() */
5047c478bd9Sstevel@tonic-gate static int	Pfd = -1;	/* fd to receive pids thru */
5057c478bd9Sstevel@tonic-gate static unsigned int	spawncnt, pausecnt;
5067c478bd9Sstevel@tonic-gate static int	rsflag;		/* Set if a respawn has taken place */
5077c478bd9Sstevel@tonic-gate static volatile int time_up;	/* Flag set to TRUE by the alarm interrupt */
5087c478bd9Sstevel@tonic-gate 				/* routine each time an alarm interrupt */
5097c478bd9Sstevel@tonic-gate 				/* takes place. */
5107c478bd9Sstevel@tonic-gate static int	sflg = 0;	/* Set if we were booted -s to single user */
5117c478bd9Sstevel@tonic-gate static int	rflg = 0;	/* Set if booted -r, reconfigure devices */
5127c478bd9Sstevel@tonic-gate static int	bflg = 0;	/* Set if booted -b, don't run rc scripts */
5137c478bd9Sstevel@tonic-gate static pid_t	init_pid;	/* PID of "one true" init for current zone */
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate static struct init_state *g_state = NULL;
5167c478bd9Sstevel@tonic-gate static size_t	g_state_sz;
5177c478bd9Sstevel@tonic-gate static int	booting = 1;	/* Set while we're booting. */
5187c478bd9Sstevel@tonic-gate 
5197c478bd9Sstevel@tonic-gate /*
5207c478bd9Sstevel@tonic-gate  * Array for default global environment.
5217c478bd9Sstevel@tonic-gate  */
5227c478bd9Sstevel@tonic-gate #define	MAXENVENT	24	/* Max number of default env variables + 1 */
5237c478bd9Sstevel@tonic-gate 				/* init can use three itself, so this leaves */
5247c478bd9Sstevel@tonic-gate 				/* 20 for the administrator in ENVFILE. */
5257c478bd9Sstevel@tonic-gate static char	*glob_envp[MAXENVENT];	/* Array of environment strings */
5267c478bd9Sstevel@tonic-gate static int	glob_envn;		/* Number of environment strings */
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate static struct pollfd	poll_fds[1];
5307c478bd9Sstevel@tonic-gate static int		poll_nfds = 0;	/* poll_fds is uninitialized */
5317c478bd9Sstevel@tonic-gate 
5327b209c2cSacruz /*
5337b209c2cSacruz  * Contracts constants
5347b209c2cSacruz  */
5357b209c2cSacruz #define	SVC_INIT_PREFIX "init:/"
5367b209c2cSacruz #define	SVC_AUX_SIZE (INITTAB_ENTRY_ID_SIZE + 1)
5377b209c2cSacruz #define	SVC_FMRI_SIZE (sizeof (SVC_INIT_PREFIX) + INITTAB_ENTRY_ID_SIZE)
5387b209c2cSacruz 
5397c478bd9Sstevel@tonic-gate static int	legacy_tmpl = -1;	/* fd for legacy contract template */
5407c478bd9Sstevel@tonic-gate static int	startd_tmpl = -1;	/* fd for svc.startd's template */
5417b209c2cSacruz static char	startd_svc_aux[SVC_AUX_SIZE];
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate static char	startd_cline[256] = "";	/* svc.startd's command line */
5447c478bd9Sstevel@tonic-gate static int	do_restart_startd = 1;	/* Whether to restart svc.startd. */
5457c478bd9Sstevel@tonic-gate static char	*smf_options = NULL;	/* Options to give to startd. */
5467c478bd9Sstevel@tonic-gate static int	smf_debug = 0;		/* Messages for debugging smf(5) */
5477c478bd9Sstevel@tonic-gate static time_t	init_boot_time;		/* Substitute for kernel boot time. */
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate #define	NSTARTD_FAILURE_TIMES	3		/* trigger after 3 failures */
5507c478bd9Sstevel@tonic-gate #define	STARTD_FAILURE_RATE_NS	5000000000LL	/* 1 failure/5 seconds */
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate static hrtime_t	startd_failure_time[NSTARTD_FAILURE_TIMES];
5537c478bd9Sstevel@tonic-gate static uint_t	startd_failure_index;
5547c478bd9Sstevel@tonic-gate 
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate static char	*prog_name(char *);
5577c478bd9Sstevel@tonic-gate static int	state_to_mask(int);
5587c478bd9Sstevel@tonic-gate static int	lvlname_to_mask(char, int *);
5597c478bd9Sstevel@tonic-gate static void	lscf_set_runlevel(char);
5607c478bd9Sstevel@tonic-gate static int	state_to_flags(int);
5617c478bd9Sstevel@tonic-gate static char	state_to_name(int);
5627c478bd9Sstevel@tonic-gate static int	lvlname_to_state(char);
5637c478bd9Sstevel@tonic-gate static int	getcmd(struct CMD_LINE *, char *);
5647c478bd9Sstevel@tonic-gate static int	realcon();
5657c478bd9Sstevel@tonic-gate static int	spawn_processes();
5667c478bd9Sstevel@tonic-gate static int	get_ioctl_syscon();
5677c478bd9Sstevel@tonic-gate static int	account(short, struct PROC_TABLE *, char *);
5687c478bd9Sstevel@tonic-gate static void	alarmclk();
5697c478bd9Sstevel@tonic-gate static void	childeath(int);
5707c478bd9Sstevel@tonic-gate static void	cleanaux();
5717c478bd9Sstevel@tonic-gate static void	clearent(pid_t, short);
5727c478bd9Sstevel@tonic-gate static void	console(boolean_t, char *, ...);
5737c478bd9Sstevel@tonic-gate static void	init_signals(void);
5747c478bd9Sstevel@tonic-gate static void	setup_pipe();
5757c478bd9Sstevel@tonic-gate static void	killproc(pid_t);
5767c478bd9Sstevel@tonic-gate static void	init_env();
5777c478bd9Sstevel@tonic-gate static void	boot_init();
5787c478bd9Sstevel@tonic-gate static void	powerfail();
5797c478bd9Sstevel@tonic-gate static void	remv();
5807c478bd9Sstevel@tonic-gate static void	write_ioctl_syscon();
5817c478bd9Sstevel@tonic-gate static void	spawn(struct PROC_TABLE *, struct CMD_LINE *);
5827c478bd9Sstevel@tonic-gate static void	setimer(int);
5837c478bd9Sstevel@tonic-gate static void	siglvl(int, siginfo_t *, ucontext_t *);
5847c478bd9Sstevel@tonic-gate static void	sigpoll(int);
5857c478bd9Sstevel@tonic-gate static void	enter_maintenance(void);
5867c478bd9Sstevel@tonic-gate static void	timer(int);
5877c478bd9Sstevel@tonic-gate static void	userinit(int, char **);
5887c478bd9Sstevel@tonic-gate static void	notify_pam_dead(struct utmpx *);
5897c478bd9Sstevel@tonic-gate static long	waitproc(struct PROC_TABLE *);
5907c478bd9Sstevel@tonic-gate static struct PROC_TABLE *efork(int, struct PROC_TABLE *, int);
5917c478bd9Sstevel@tonic-gate static struct PROC_TABLE *findpslot(struct CMD_LINE *);
5927c478bd9Sstevel@tonic-gate static void	increase_proc_table_size();
5937c478bd9Sstevel@tonic-gate static void	st_init();
5947c478bd9Sstevel@tonic-gate static void	st_write();
5957c478bd9Sstevel@tonic-gate static void	contracts_init();
5967c478bd9Sstevel@tonic-gate static void	contract_event(struct pollfd *);
5977c478bd9Sstevel@tonic-gate static int	startd_run(const char *, int, ctid_t);
5987c478bd9Sstevel@tonic-gate static void	startd_record_failure();
5997c478bd9Sstevel@tonic-gate static int	startd_failure_rate_critical();
6007c478bd9Sstevel@tonic-gate static char	*audit_boot_msg();
6017c478bd9Sstevel@tonic-gate static int	audit_put_record(int, int, char *);
6027c478bd9Sstevel@tonic-gate static void	update_boot_archive(int new_state);
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate int
6057c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
6067c478bd9Sstevel@tonic-gate {
6077c478bd9Sstevel@tonic-gate 	int	chg_lvl_flag = FALSE, print_banner = FALSE;
6087c478bd9Sstevel@tonic-gate 	int	may_need_audit = 1;
6097c478bd9Sstevel@tonic-gate 	int	c;
6107c478bd9Sstevel@tonic-gate 	char	*msg;
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate 	/* Get a timestamp for use as boot time, if needed. */
6137c478bd9Sstevel@tonic-gate 	(void) time(&init_boot_time);
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate 	/* Get the default umask */
6167c478bd9Sstevel@tonic-gate 	cmask = umask(022);
6177c478bd9Sstevel@tonic-gate 	(void) umask(cmask);
6187c478bd9Sstevel@tonic-gate 
6197c478bd9Sstevel@tonic-gate 	/* Parse the arguments to init. Check for single user */
6207c478bd9Sstevel@tonic-gate 	opterr = 0;
6217c478bd9Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "brsm:")) != EOF) {
6227c478bd9Sstevel@tonic-gate 		switch (c) {
6237c478bd9Sstevel@tonic-gate 		case 'b':
6247c478bd9Sstevel@tonic-gate 			rflg = 0;
6257c478bd9Sstevel@tonic-gate 			bflg = 1;
6267c478bd9Sstevel@tonic-gate 			if (!sflg)
6277c478bd9Sstevel@tonic-gate 				sflg++;
6287c478bd9Sstevel@tonic-gate 			break;
6297c478bd9Sstevel@tonic-gate 		case 'r':
6307c478bd9Sstevel@tonic-gate 			bflg = 0;
6317c478bd9Sstevel@tonic-gate 			rflg++;
6327c478bd9Sstevel@tonic-gate 			break;
6337c478bd9Sstevel@tonic-gate 		case 's':
6347c478bd9Sstevel@tonic-gate 			if (!bflg)
6357c478bd9Sstevel@tonic-gate 				sflg++;
6367c478bd9Sstevel@tonic-gate 			break;
6377c478bd9Sstevel@tonic-gate 		case 'm':
6387c478bd9Sstevel@tonic-gate 			smf_options = optarg;
6397c478bd9Sstevel@tonic-gate 			smf_debug = (strstr(smf_options, "debug") != NULL);
6407c478bd9Sstevel@tonic-gate 			break;
6417c478bd9Sstevel@tonic-gate 		}
6427c478bd9Sstevel@tonic-gate 	}
6437c478bd9Sstevel@tonic-gate 
6447c478bd9Sstevel@tonic-gate 	/*
6457c478bd9Sstevel@tonic-gate 	 * Determine if we are the main init, or a user invoked init, whose job
6467c478bd9Sstevel@tonic-gate 	 * it is to inform init to change levels or perform some other action.
6477c478bd9Sstevel@tonic-gate 	 */
6487c478bd9Sstevel@tonic-gate 	if (zone_getattr(getzoneid(), ZONE_ATTR_INITPID, &init_pid,
6497c478bd9Sstevel@tonic-gate 	    sizeof (init_pid)) != sizeof (init_pid)) {
6507c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "could not get pid for init\n");
6517c478bd9Sstevel@tonic-gate 		return (1);
6527c478bd9Sstevel@tonic-gate 	}
6537c478bd9Sstevel@tonic-gate 
6547c478bd9Sstevel@tonic-gate 	/*
6557c478bd9Sstevel@tonic-gate 	 * If this PID is not the same as the "true" init for the zone, then we
6567c478bd9Sstevel@tonic-gate 	 * must be in 'user' mode.
6577c478bd9Sstevel@tonic-gate 	 */
6587c478bd9Sstevel@tonic-gate 	if (getpid() != init_pid) {
6597c478bd9Sstevel@tonic-gate 		userinit(argc, argv);
6607c478bd9Sstevel@tonic-gate 	}
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate 	if (getzoneid() != GLOBAL_ZONEID) {
6637c478bd9Sstevel@tonic-gate 		print_banner = TRUE;
6647c478bd9Sstevel@tonic-gate 	}
6657c478bd9Sstevel@tonic-gate 
6667c478bd9Sstevel@tonic-gate 	/*
6677c478bd9Sstevel@tonic-gate 	 * Initialize state (and set "booting").
6687c478bd9Sstevel@tonic-gate 	 */
6697c478bd9Sstevel@tonic-gate 	st_init();
6707c478bd9Sstevel@tonic-gate 
6717c478bd9Sstevel@tonic-gate 	if (booting && print_banner) {
6727c478bd9Sstevel@tonic-gate 		struct utsname un;
6737c478bd9Sstevel@tonic-gate 		char buf[BUFSIZ], *isa;
6747c478bd9Sstevel@tonic-gate 		long ret;
6757c478bd9Sstevel@tonic-gate 		int bits = 32;
6767c478bd9Sstevel@tonic-gate 
6777c478bd9Sstevel@tonic-gate 		/*
6787c478bd9Sstevel@tonic-gate 		 * We want to print the boot banner as soon as
6797c478bd9Sstevel@tonic-gate 		 * possible.  In the global zone, the kernel does it,
6807c478bd9Sstevel@tonic-gate 		 * but we do not have that luxury in non-global zones,
6817c478bd9Sstevel@tonic-gate 		 * so we will print it here.
6827c478bd9Sstevel@tonic-gate 		 */
6837c478bd9Sstevel@tonic-gate 		(void) uname(&un);
6847c478bd9Sstevel@tonic-gate 		ret = sysinfo(SI_ISALIST, buf, sizeof (buf));
6857c478bd9Sstevel@tonic-gate 		if (ret != -1L && ret <= sizeof (buf)) {
6867c478bd9Sstevel@tonic-gate 			for (isa = strtok(buf, " "); isa;
6877c478bd9Sstevel@tonic-gate 			    isa = strtok(NULL, " ")) {
6887c478bd9Sstevel@tonic-gate 				if (strcmp(isa, "sparcv9") == 0 ||
6897c478bd9Sstevel@tonic-gate 				    strcmp(isa, "amd64") == 0) {
6907c478bd9Sstevel@tonic-gate 					bits = 64;
6917c478bd9Sstevel@tonic-gate 					break;
6927c478bd9Sstevel@tonic-gate 				}
6937c478bd9Sstevel@tonic-gate 			}
6947c478bd9Sstevel@tonic-gate 		}
6957c478bd9Sstevel@tonic-gate 
6967c478bd9Sstevel@tonic-gate 		console(B_FALSE,
6977c478bd9Sstevel@tonic-gate 		    "\n\n%s Release %s Version %s %d-bit\r\n",
6987c478bd9Sstevel@tonic-gate 		    un.sysname, un.release, un.version, bits);
6997c478bd9Sstevel@tonic-gate 		console(B_FALSE,
700861a9162SJohn Beck 		    "Copyright (c) 1983, 2010, Oracle and/or its affiliates."
7017c478bd9Sstevel@tonic-gate 		    " All rights reserved.\r\n");
7027c478bd9Sstevel@tonic-gate 	}
7037c478bd9Sstevel@tonic-gate 
7047c478bd9Sstevel@tonic-gate 	/*
7057c478bd9Sstevel@tonic-gate 	 * Get the ioctl settings for /dev/syscon from /etc/ioctl.syscon
7067c478bd9Sstevel@tonic-gate 	 * so that it can be brought up in the state it was in when the
7077c478bd9Sstevel@tonic-gate 	 * system went down; or set to defaults if ioctl.syscon isn't
7087c478bd9Sstevel@tonic-gate 	 * valid.
7097c478bd9Sstevel@tonic-gate 	 *
7107c478bd9Sstevel@tonic-gate 	 * This needs to be done even if we're restarting so reset_modes()
7117c478bd9Sstevel@tonic-gate 	 * will work in case we need to go down to single user mode.
7127c478bd9Sstevel@tonic-gate 	 */
7137c478bd9Sstevel@tonic-gate 	write_ioctl = get_ioctl_syscon();
7147c478bd9Sstevel@tonic-gate 
7157c478bd9Sstevel@tonic-gate 	/*
7167c478bd9Sstevel@tonic-gate 	 * Set up all signals to be caught or ignored as appropriate.
7177c478bd9Sstevel@tonic-gate 	 */
7187c478bd9Sstevel@tonic-gate 	init_signals();
7197c478bd9Sstevel@tonic-gate 
7207c478bd9Sstevel@tonic-gate 	/* Load glob_envp from ENVFILE. */
7217c478bd9Sstevel@tonic-gate 	init_env();
7227c478bd9Sstevel@tonic-gate 
7237c478bd9Sstevel@tonic-gate 	contracts_init();
7247c478bd9Sstevel@tonic-gate 
7257c478bd9Sstevel@tonic-gate 	if (!booting) {
7267c478bd9Sstevel@tonic-gate 		/* cur_state should have been read in. */
7277c478bd9Sstevel@tonic-gate 
7287c478bd9Sstevel@tonic-gate 		op_modes = NORMAL_MODES;
7297c478bd9Sstevel@tonic-gate 
7307c478bd9Sstevel@tonic-gate 		/* Rewrite the ioctl file if it was bad. */
7317c478bd9Sstevel@tonic-gate 		if (write_ioctl)
7327c478bd9Sstevel@tonic-gate 			write_ioctl_syscon();
7337c478bd9Sstevel@tonic-gate 	} else {
7347c478bd9Sstevel@tonic-gate 		/*
7357c478bd9Sstevel@tonic-gate 		 * It's fine to boot up with state as zero, because
7367c478bd9Sstevel@tonic-gate 		 * startd will later tell us the real state.
7377c478bd9Sstevel@tonic-gate 		 */
7387c478bd9Sstevel@tonic-gate 		cur_state = 0;
7397c478bd9Sstevel@tonic-gate 		op_modes = BOOT_MODES;
7407c478bd9Sstevel@tonic-gate 
7417c478bd9Sstevel@tonic-gate 		boot_init();
7427c478bd9Sstevel@tonic-gate 	}
7437c478bd9Sstevel@tonic-gate 
7447c478bd9Sstevel@tonic-gate 	prev_state = prior_state = cur_state;
7457c478bd9Sstevel@tonic-gate 
74692ba7109Seschrock 	setup_pipe();
74792ba7109Seschrock 
7487c478bd9Sstevel@tonic-gate 	/*
7497c478bd9Sstevel@tonic-gate 	 * Here is the beginning of the main process loop.
7507c478bd9Sstevel@tonic-gate 	 */
7517c478bd9Sstevel@tonic-gate 	for (;;) {
75292ba7109Seschrock 		if (lvlq_received) {
7537c478bd9Sstevel@tonic-gate 			setup_pipe();
75492ba7109Seschrock 			lvlq_received = B_FALSE;
75592ba7109Seschrock 		}
7567c478bd9Sstevel@tonic-gate 
7577c478bd9Sstevel@tonic-gate 		/*
7587c478bd9Sstevel@tonic-gate 		 * Clean up any accounting records for dead "godchildren".
7597c478bd9Sstevel@tonic-gate 		 */
7607c478bd9Sstevel@tonic-gate 		if (Gchild)
7617c478bd9Sstevel@tonic-gate 			cleanaux();
7627c478bd9Sstevel@tonic-gate 
7637c478bd9Sstevel@tonic-gate 		/*
7647c478bd9Sstevel@tonic-gate 		 * If in "normal" mode, check all living processes and initiate
7657c478bd9Sstevel@tonic-gate 		 * kill sequence on those that should not be there anymore.
7667c478bd9Sstevel@tonic-gate 		 */
7677c478bd9Sstevel@tonic-gate 		if (op_modes == NORMAL_MODES && cur_state != LVLa &&
7687c478bd9Sstevel@tonic-gate 		    cur_state != LVLb && cur_state != LVLc)
7697c478bd9Sstevel@tonic-gate 			remv();
7707c478bd9Sstevel@tonic-gate 
7717c478bd9Sstevel@tonic-gate 		/*
7727c478bd9Sstevel@tonic-gate 		 * If a change in run levels is the reason we awoke, now do
7737c478bd9Sstevel@tonic-gate 		 * the accounting to report the change in the utmp file.
7747c478bd9Sstevel@tonic-gate 		 * Also report the change on the system console.
7757c478bd9Sstevel@tonic-gate 		 */
7767c478bd9Sstevel@tonic-gate 		if (chg_lvl_flag) {
7777c478bd9Sstevel@tonic-gate 			chg_lvl_flag = FALSE;
7787c478bd9Sstevel@tonic-gate 
7797c478bd9Sstevel@tonic-gate 			if (state_to_flags(cur_state) & LSEL_RUNLEVEL) {
7807c478bd9Sstevel@tonic-gate 				char rl = state_to_name(cur_state);
7817c478bd9Sstevel@tonic-gate 
7827c478bd9Sstevel@tonic-gate 				if (rl != -1)
7837c478bd9Sstevel@tonic-gate 					lscf_set_runlevel(rl);
7847c478bd9Sstevel@tonic-gate 			}
7857c478bd9Sstevel@tonic-gate 
7867c478bd9Sstevel@tonic-gate 			may_need_audit = 1;
7877c478bd9Sstevel@tonic-gate 		}
7887c478bd9Sstevel@tonic-gate 
7897c478bd9Sstevel@tonic-gate 		/*
7907c478bd9Sstevel@tonic-gate 		 * Scan the inittab file and spawn and respawn processes that
7917c478bd9Sstevel@tonic-gate 		 * should be alive in the current state. If inittab does not
7927c478bd9Sstevel@tonic-gate 		 * exist default to  single user mode.
7937c478bd9Sstevel@tonic-gate 		 */
7947c478bd9Sstevel@tonic-gate 		if (spawn_processes() == FAILURE) {
7957c478bd9Sstevel@tonic-gate 			prior_state = prev_state;
7967c478bd9Sstevel@tonic-gate 			cur_state = SINGLE_USER;
7977c478bd9Sstevel@tonic-gate 		}
7987c478bd9Sstevel@tonic-gate 
7997c478bd9Sstevel@tonic-gate 		/* If any respawns occurred, take note. */
8007c478bd9Sstevel@tonic-gate 		if (rsflag) {
8017c478bd9Sstevel@tonic-gate 			rsflag = 0;
8027c478bd9Sstevel@tonic-gate 			spawncnt++;
8037c478bd9Sstevel@tonic-gate 		}
8047c478bd9Sstevel@tonic-gate 
8057c478bd9Sstevel@tonic-gate 		/*
8067c478bd9Sstevel@tonic-gate 		 * If a powerfail signal was received during the last
8077c478bd9Sstevel@tonic-gate 		 * sequence, set mode to powerfail.  When spawn_processes() is
8087c478bd9Sstevel@tonic-gate 		 * entered the first thing it does is to check "powerhit".  If
8097c478bd9Sstevel@tonic-gate 		 * it is in PF_MODES then it clears "powerhit" and does
8107c478bd9Sstevel@tonic-gate 		 * a powerfail sequence.  If it is not in PF_MODES, then it
8117c478bd9Sstevel@tonic-gate 		 * puts itself in PF_MODES and then clears "powerhit".  Should
8127c478bd9Sstevel@tonic-gate 		 * "powerhit" get set again while spawn_processes() is working
8137c478bd9Sstevel@tonic-gate 		 * on a powerfail sequence, the following code  will see that
8147c478bd9Sstevel@tonic-gate 		 * spawn_processes() tries to execute the powerfail sequence
8157c478bd9Sstevel@tonic-gate 		 * again.  This guarantees that the powerfail sequence will be
8167c478bd9Sstevel@tonic-gate 		 * successfully completed before further processing takes
8177c478bd9Sstevel@tonic-gate 		 * place.
8187c478bd9Sstevel@tonic-gate 		 */
8197c478bd9Sstevel@tonic-gate 		if (wakeup.w_flags.w_powerhit) {
8207c478bd9Sstevel@tonic-gate 			op_modes = PF_MODES;
8217c478bd9Sstevel@tonic-gate 			/*
8227c478bd9Sstevel@tonic-gate 			 * Make sure that cur_state != prev_state so that
8237c478bd9Sstevel@tonic-gate 			 * ONCE and WAIT types work.
8247c478bd9Sstevel@tonic-gate 			 */
8257c478bd9Sstevel@tonic-gate 			prev_state = 0;
8267c478bd9Sstevel@tonic-gate 		} else if (op_modes != NORMAL_MODES) {
8277c478bd9Sstevel@tonic-gate 			/*
8287c478bd9Sstevel@tonic-gate 			 * If spawn_processes() was not just called while in
8297c478bd9Sstevel@tonic-gate 			 * normal mode, we set the mode to normal and it will
8307c478bd9Sstevel@tonic-gate 			 * be called again to check normal modes.  If we have
8317c478bd9Sstevel@tonic-gate 			 * just finished a powerfail sequence with prev_state
8327c478bd9Sstevel@tonic-gate 			 * equal to zero, we set prev_state equal to cur_state
8337c478bd9Sstevel@tonic-gate 			 * before the next pass through.
8347c478bd9Sstevel@tonic-gate 			 */
8357c478bd9Sstevel@tonic-gate 			if (op_modes == PF_MODES)
8367c478bd9Sstevel@tonic-gate 				prev_state = cur_state;
8377c478bd9Sstevel@tonic-gate 			op_modes = NORMAL_MODES;
8387c478bd9Sstevel@tonic-gate 		} else if (cur_state == LVLa || cur_state == LVLb ||
8397c478bd9Sstevel@tonic-gate 		    cur_state == LVLc) {
8407c478bd9Sstevel@tonic-gate 			/*
8417c478bd9Sstevel@tonic-gate 			 * If it was a change of levels that awakened us and the
8427c478bd9Sstevel@tonic-gate 			 * new level is one of the demand levels then reset
8437c478bd9Sstevel@tonic-gate 			 * cur_state to the previous state and do another scan
8447c478bd9Sstevel@tonic-gate 			 * to take care of the usual respawn actions.
8457c478bd9Sstevel@tonic-gate 			 */
8467c478bd9Sstevel@tonic-gate 			cur_state = prior_state;
8477c478bd9Sstevel@tonic-gate 			prior_state = prev_state;
8487c478bd9Sstevel@tonic-gate 			prev_state = cur_state;
8497c478bd9Sstevel@tonic-gate 		} else {
8507c478bd9Sstevel@tonic-gate 			prev_state = cur_state;
8517c478bd9Sstevel@tonic-gate 
8527c478bd9Sstevel@tonic-gate 			if (wakeup.w_mask == 0) {
8537c478bd9Sstevel@tonic-gate 				int ret;
8547c478bd9Sstevel@tonic-gate 
8557c478bd9Sstevel@tonic-gate 				if (may_need_audit && (cur_state == LVL3)) {
8567c478bd9Sstevel@tonic-gate 					msg = audit_boot_msg();
8577c478bd9Sstevel@tonic-gate 
8587c478bd9Sstevel@tonic-gate 					may_need_audit = 0;
8597c478bd9Sstevel@tonic-gate 					(void) audit_put_record(ADT_SUCCESS,
8607c478bd9Sstevel@tonic-gate 					    ADT_SUCCESS, msg);
8617c478bd9Sstevel@tonic-gate 					free(msg);
8627c478bd9Sstevel@tonic-gate 				}
8637c478bd9Sstevel@tonic-gate 
8647c478bd9Sstevel@tonic-gate 				/*
8657c478bd9Sstevel@tonic-gate 				 * "init" is finished with all actions for
8667c478bd9Sstevel@tonic-gate 				 * the current wakeup.
8677c478bd9Sstevel@tonic-gate 				 */
8687c478bd9Sstevel@tonic-gate 				ret = poll(poll_fds, poll_nfds,
8697c478bd9Sstevel@tonic-gate 				    SLEEPTIME * MILLISEC);
8707c478bd9Sstevel@tonic-gate 				pausecnt++;
8717c478bd9Sstevel@tonic-gate 				if (ret > 0)
8727c478bd9Sstevel@tonic-gate 					contract_event(&poll_fds[0]);
8737c478bd9Sstevel@tonic-gate 				else if (ret < 0 && errno != EINTR)
8747c478bd9Sstevel@tonic-gate 					console(B_TRUE, "poll() error: %s\n",
8757c478bd9Sstevel@tonic-gate 					    strerror(errno));
8767c478bd9Sstevel@tonic-gate 			}
8777c478bd9Sstevel@tonic-gate 
8787c478bd9Sstevel@tonic-gate 			if (wakeup.w_flags.w_usersignal) {
8797c478bd9Sstevel@tonic-gate 				/*
8807c478bd9Sstevel@tonic-gate 				 * Install the new level.  This could be a real
8817c478bd9Sstevel@tonic-gate 				 * change in levels  or a telinit [Q|a|b|c] or
8827c478bd9Sstevel@tonic-gate 				 * just a telinit to the same level at which
8837c478bd9Sstevel@tonic-gate 				 * we are running.
8847c478bd9Sstevel@tonic-gate 				 */
8857c478bd9Sstevel@tonic-gate 				if (new_state != cur_state) {
8867c478bd9Sstevel@tonic-gate 					if (new_state == LVLa ||
8877c478bd9Sstevel@tonic-gate 					    new_state == LVLb ||
8887c478bd9Sstevel@tonic-gate 					    new_state == LVLc) {
8897c478bd9Sstevel@tonic-gate 						prev_state = prior_state;
8907c478bd9Sstevel@tonic-gate 						prior_state = cur_state;
8917c478bd9Sstevel@tonic-gate 						cur_state = new_state;
8927c478bd9Sstevel@tonic-gate 					} else {
8937c478bd9Sstevel@tonic-gate 						prev_state = cur_state;
8947c478bd9Sstevel@tonic-gate 						if (cur_state >= 0)
8957c478bd9Sstevel@tonic-gate 							prior_state = cur_state;
8967c478bd9Sstevel@tonic-gate 						cur_state = new_state;
8977c478bd9Sstevel@tonic-gate 						chg_lvl_flag = TRUE;
8987c478bd9Sstevel@tonic-gate 					}
8997c478bd9Sstevel@tonic-gate 				}
9007c478bd9Sstevel@tonic-gate 
9017c478bd9Sstevel@tonic-gate 				new_state = 0;
9027c478bd9Sstevel@tonic-gate 			}
9037c478bd9Sstevel@tonic-gate 
9047c478bd9Sstevel@tonic-gate 			if (wakeup.w_flags.w_powerhit)
9057c478bd9Sstevel@tonic-gate 				op_modes = PF_MODES;
9067c478bd9Sstevel@tonic-gate 
9077c478bd9Sstevel@tonic-gate 			/*
9087c478bd9Sstevel@tonic-gate 			 * Clear all wakeup reasons.
9097c478bd9Sstevel@tonic-gate 			 */
9107c478bd9Sstevel@tonic-gate 			wakeup.w_mask = 0;
9117c478bd9Sstevel@tonic-gate 		}
9127c478bd9Sstevel@tonic-gate 	}
9137c478bd9Sstevel@tonic-gate 
9147c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
9157c478bd9Sstevel@tonic-gate }
9167c478bd9Sstevel@tonic-gate 
9177c478bd9Sstevel@tonic-gate static void
9187c478bd9Sstevel@tonic-gate update_boot_archive(int new_state)
9197c478bd9Sstevel@tonic-gate {
9207c478bd9Sstevel@tonic-gate 	if (new_state != LVL0 && new_state != LVL5 && new_state != LVL6)
9217c478bd9Sstevel@tonic-gate 		return;
9227c478bd9Sstevel@tonic-gate 
9237c478bd9Sstevel@tonic-gate 	if (getzoneid() != GLOBAL_ZONEID)
9247c478bd9Sstevel@tonic-gate 		return;
9257c478bd9Sstevel@tonic-gate 
92648847494SEnrico Perla - Sun Microsystems 	(void) system("/sbin/bootadm -ea update_all");
9277c478bd9Sstevel@tonic-gate }
9287c478bd9Sstevel@tonic-gate 
9297c478bd9Sstevel@tonic-gate /*
9307c478bd9Sstevel@tonic-gate  * void enter_maintenance()
9317c478bd9Sstevel@tonic-gate  *   A simple invocation of sulogin(1M), with no baggage, in the case that we
9327c478bd9Sstevel@tonic-gate  *   are unable to activate svc.startd(1M).  We fork; the child runs sulogin;
9337c478bd9Sstevel@tonic-gate  *   we wait for it to exit.
9347c478bd9Sstevel@tonic-gate  */
9357c478bd9Sstevel@tonic-gate static void
9367c478bd9Sstevel@tonic-gate enter_maintenance()
9377c478bd9Sstevel@tonic-gate {
9387c478bd9Sstevel@tonic-gate 	struct PROC_TABLE	*su_process;
9397c478bd9Sstevel@tonic-gate 
9407c478bd9Sstevel@tonic-gate 	console(B_FALSE, "Requesting maintenance mode\n"
9417c478bd9Sstevel@tonic-gate 	    "(See /lib/svc/share/README for additional information.)\n");
942c39ec064SRoger A. Faulkner 	(void) sighold(SIGCLD);
9437c478bd9Sstevel@tonic-gate 	while ((su_process = efork(M_OFF, NULLPROC, NOCLEANUP)) == NO_ROOM)
9447c478bd9Sstevel@tonic-gate 		(void) pause();
945c39ec064SRoger A. Faulkner 	(void) sigrelse(SIGCLD);
9467c478bd9Sstevel@tonic-gate 	if (su_process == NULLPROC) {
9477c478bd9Sstevel@tonic-gate 		int fd;
9487c478bd9Sstevel@tonic-gate 
9497c478bd9Sstevel@tonic-gate 		(void) fclose(stdin);
9507c478bd9Sstevel@tonic-gate 		(void) fclose(stdout);
9517c478bd9Sstevel@tonic-gate 		(void) fclose(stderr);
9527c478bd9Sstevel@tonic-gate 		closefrom(0);
9537c478bd9Sstevel@tonic-gate 
9547c478bd9Sstevel@tonic-gate 		fd = open(SYSCON, O_RDWR | O_NOCTTY);
9557c478bd9Sstevel@tonic-gate 		if (fd >= 0) {
9567c478bd9Sstevel@tonic-gate 			(void) dup2(fd, 1);
9577c478bd9Sstevel@tonic-gate 			(void) dup2(fd, 2);
9587c478bd9Sstevel@tonic-gate 		} else {
9597c478bd9Sstevel@tonic-gate 			/*
9607c478bd9Sstevel@tonic-gate 			 * Need to issue an error message somewhere.
9617c478bd9Sstevel@tonic-gate 			 */
9627c478bd9Sstevel@tonic-gate 			syslog(LOG_CRIT, "init[%d]: cannot open %s; %s\n",
9637c478bd9Sstevel@tonic-gate 			    getpid(), SYSCON, strerror(errno));
9647c478bd9Sstevel@tonic-gate 		}
9657c478bd9Sstevel@tonic-gate 
9667c478bd9Sstevel@tonic-gate 		/*
9677c478bd9Sstevel@tonic-gate 		 * Execute the "su" program.
9687c478bd9Sstevel@tonic-gate 		 */
9697c478bd9Sstevel@tonic-gate 		(void) execle(SU, SU, "-", (char *)0, glob_envp);
9707c478bd9Sstevel@tonic-gate 		console(B_TRUE, "execle of %s failed: %s\n", SU,
9717c478bd9Sstevel@tonic-gate 		    strerror(errno));
9727c478bd9Sstevel@tonic-gate 		timer(5);
9737c478bd9Sstevel@tonic-gate 		exit(1);
9747c478bd9Sstevel@tonic-gate 	}
9757c478bd9Sstevel@tonic-gate 
9767c478bd9Sstevel@tonic-gate 	/*
9777c478bd9Sstevel@tonic-gate 	 * If we are the parent, wait around for the child to die
9787c478bd9Sstevel@tonic-gate 	 * or for "init" to be signaled to change levels.
9797c478bd9Sstevel@tonic-gate 	 */
9807c478bd9Sstevel@tonic-gate 	while (waitproc(su_process) == FAILURE) {
9817c478bd9Sstevel@tonic-gate 		/*
9827c478bd9Sstevel@tonic-gate 		 * All other reasons for waking are ignored when in
9837c478bd9Sstevel@tonic-gate 		 * single-user mode.  The only child we are interested
9847c478bd9Sstevel@tonic-gate 		 * in is being waited for explicitly by waitproc().
9857c478bd9Sstevel@tonic-gate 		 */
9867c478bd9Sstevel@tonic-gate 		wakeup.w_mask = 0;
9877c478bd9Sstevel@tonic-gate 	}
9887c478bd9Sstevel@tonic-gate }
9897c478bd9Sstevel@tonic-gate 
9907c478bd9Sstevel@tonic-gate /*
9917c478bd9Sstevel@tonic-gate  * remv() scans through "proc_table" and performs cleanup.  If
9927c478bd9Sstevel@tonic-gate  * there is a process in the table, which shouldn't be here at
9937c478bd9Sstevel@tonic-gate  * the current run level, then remv() kills the process.
9947c478bd9Sstevel@tonic-gate  */
9957c478bd9Sstevel@tonic-gate static void
9967c478bd9Sstevel@tonic-gate remv()
9977c478bd9Sstevel@tonic-gate {
9987c478bd9Sstevel@tonic-gate 	struct PROC_TABLE	*process;
9997c478bd9Sstevel@tonic-gate 	struct CMD_LINE		cmd;
10007c478bd9Sstevel@tonic-gate 	char			cmd_string[MAXCMDL];
10017c478bd9Sstevel@tonic-gate 	int			change_level;
10027c478bd9Sstevel@tonic-gate 
10037c478bd9Sstevel@tonic-gate 	change_level = (cur_state != prev_state ? TRUE : FALSE);
10047c478bd9Sstevel@tonic-gate 
10057c478bd9Sstevel@tonic-gate 	/*
10067c478bd9Sstevel@tonic-gate 	 * Clear the TOUCHED flag on all entries so that when we have
10077c478bd9Sstevel@tonic-gate 	 * finished scanning inittab, we will be able to tell if we
10087c478bd9Sstevel@tonic-gate 	 * have any processes for which there is no entry in inittab.
10097c478bd9Sstevel@tonic-gate 	 */
10107c478bd9Sstevel@tonic-gate 	for (process = proc_table;
10117c478bd9Sstevel@tonic-gate 	    (process < proc_table + num_proc); process++) {
10127c478bd9Sstevel@tonic-gate 		process->p_flags &= ~TOUCHED;
10137c478bd9Sstevel@tonic-gate 	}
10147c478bd9Sstevel@tonic-gate 
10157c478bd9Sstevel@tonic-gate 	/*
10167c478bd9Sstevel@tonic-gate 	 * Scan all inittab entries.
10177c478bd9Sstevel@tonic-gate 	 */
10187c478bd9Sstevel@tonic-gate 	while (getcmd(&cmd, &cmd_string[0]) == TRUE) {
10197c478bd9Sstevel@tonic-gate 		/* Scan for process which goes with this entry in inittab. */
10207c478bd9Sstevel@tonic-gate 		for (process = proc_table;
10217c478bd9Sstevel@tonic-gate 		    (process < proc_table + num_proc); process++) {
10227c478bd9Sstevel@tonic-gate 			if ((process->p_flags & OCCUPIED) == 0 ||
10237c478bd9Sstevel@tonic-gate 			    !id_eq(process->p_id, cmd.c_id))
10247c478bd9Sstevel@tonic-gate 				continue;
10257c478bd9Sstevel@tonic-gate 
10267c478bd9Sstevel@tonic-gate 			/*
10277c478bd9Sstevel@tonic-gate 			 * This slot contains the process we are looking for.
10287c478bd9Sstevel@tonic-gate 			 */
10297c478bd9Sstevel@tonic-gate 
10307c478bd9Sstevel@tonic-gate 			/*
10317c478bd9Sstevel@tonic-gate 			 * Is the cur_state SINGLE_USER or is this process
10327c478bd9Sstevel@tonic-gate 			 * marked as "off" or was this proc started by some
10337c478bd9Sstevel@tonic-gate 			 * mechanism other than LVL{a|b|c} and the current level
10347c478bd9Sstevel@tonic-gate 			 * does not support this process?
10357c478bd9Sstevel@tonic-gate 			 */
10367c478bd9Sstevel@tonic-gate 			if (cur_state == SINGLE_USER ||
10377c478bd9Sstevel@tonic-gate 			    cmd.c_action == M_OFF ||
10387c478bd9Sstevel@tonic-gate 			    ((cmd.c_levels & state_to_mask(cur_state)) == 0 &&
10397c478bd9Sstevel@tonic-gate 			    (process->p_flags & DEMANDREQUEST) == 0)) {
10407c478bd9Sstevel@tonic-gate 				if (process->p_flags & LIVING) {
10417c478bd9Sstevel@tonic-gate 					/*
10427c478bd9Sstevel@tonic-gate 					 * Touch this entry so we know we have
10437c478bd9Sstevel@tonic-gate 					 * treated it.  Note that procs which
10447c478bd9Sstevel@tonic-gate 					 * are already dead at this point and
10457c478bd9Sstevel@tonic-gate 					 * should not be restarted are left
10467c478bd9Sstevel@tonic-gate 					 * untouched.  This causes their slot to
10477c478bd9Sstevel@tonic-gate 					 * be freed later after dead accounting
10487c478bd9Sstevel@tonic-gate 					 * is done.
10497c478bd9Sstevel@tonic-gate 					 */
10507c478bd9Sstevel@tonic-gate 					process->p_flags |= TOUCHED;
10517c478bd9Sstevel@tonic-gate 
10527c478bd9Sstevel@tonic-gate 					if ((process->p_flags & KILLED) == 0) {
10537c478bd9Sstevel@tonic-gate 						if (change_level) {
10547c478bd9Sstevel@tonic-gate 							process->p_flags
10557c478bd9Sstevel@tonic-gate 							    |= WARNED;
10567c478bd9Sstevel@tonic-gate 							(void) kill(
10577c478bd9Sstevel@tonic-gate 							    process->p_pid,
10587c478bd9Sstevel@tonic-gate 							    SIGTERM);
10597c478bd9Sstevel@tonic-gate 						} else {
10607c478bd9Sstevel@tonic-gate 							/*
10617c478bd9Sstevel@tonic-gate 							 * Fork a killing proc
10627c478bd9Sstevel@tonic-gate 							 * so "init" can
10637c478bd9Sstevel@tonic-gate 							 * continue without
10647c478bd9Sstevel@tonic-gate 							 * having to pause for
10657c478bd9Sstevel@tonic-gate 							 * TWARN seconds.
10667c478bd9Sstevel@tonic-gate 							 */
10677c478bd9Sstevel@tonic-gate 							killproc(
10687c478bd9Sstevel@tonic-gate 							    process->p_pid);
10697c478bd9Sstevel@tonic-gate 						}
10707c478bd9Sstevel@tonic-gate 						process->p_flags |= KILLED;
10717c478bd9Sstevel@tonic-gate 					}
10727c478bd9Sstevel@tonic-gate 				}
10737c478bd9Sstevel@tonic-gate 			} else {
10747c478bd9Sstevel@tonic-gate 				/*
10757c478bd9Sstevel@tonic-gate 				 * Process can exist at current level.  If it is
10767c478bd9Sstevel@tonic-gate 				 * still alive or a DEMANDREQUEST we touch it so
10777c478bd9Sstevel@tonic-gate 				 * it will be left alone.  Otherwise we leave it
10787c478bd9Sstevel@tonic-gate 				 * untouched so it will be accounted for and
10797c478bd9Sstevel@tonic-gate 				 * cleaned up later in remv().  Dead
10807c478bd9Sstevel@tonic-gate 				 * DEMANDREQUESTs will be accounted but not
10817c478bd9Sstevel@tonic-gate 				 * freed.
10827c478bd9Sstevel@tonic-gate 				 */
10837c478bd9Sstevel@tonic-gate 				if (process->p_flags &
10847c478bd9Sstevel@tonic-gate 				    (LIVING|NOCLEANUP|DEMANDREQUEST))
10857c478bd9Sstevel@tonic-gate 					process->p_flags |= TOUCHED;
10867c478bd9Sstevel@tonic-gate 			}
10877c478bd9Sstevel@tonic-gate 
10887c478bd9Sstevel@tonic-gate 			break;
10897c478bd9Sstevel@tonic-gate 		}
10907c478bd9Sstevel@tonic-gate 	}
10917c478bd9Sstevel@tonic-gate 
10927c478bd9Sstevel@tonic-gate 	st_write();
10937c478bd9Sstevel@tonic-gate 
10947c478bd9Sstevel@tonic-gate 	/*
10957c478bd9Sstevel@tonic-gate 	 * If this was a change of levels call, scan through the
10967c478bd9Sstevel@tonic-gate 	 * process table for processes that were warned to die.  If any
10977c478bd9Sstevel@tonic-gate 	 * are found that haven't left yet, sleep for TWARN seconds and
10987c478bd9Sstevel@tonic-gate 	 * then send final terminations to any that haven't died yet.
10997c478bd9Sstevel@tonic-gate 	 */
11007c478bd9Sstevel@tonic-gate 	if (change_level) {
11017c478bd9Sstevel@tonic-gate 
11027c478bd9Sstevel@tonic-gate 		/*
11037c478bd9Sstevel@tonic-gate 		 * Set the alarm for TWARN seconds on the assumption
11047c478bd9Sstevel@tonic-gate 		 * that there will be some that need to be waited for.
11057c478bd9Sstevel@tonic-gate 		 * This won't harm anything except we are guaranteed to
11067c478bd9Sstevel@tonic-gate 		 * wakeup in TWARN seconds whether we need to or not.
11077c478bd9Sstevel@tonic-gate 		 */
11087c478bd9Sstevel@tonic-gate 		setimer(TWARN);
11097c478bd9Sstevel@tonic-gate 
11107c478bd9Sstevel@tonic-gate 		/*
11117c478bd9Sstevel@tonic-gate 		 * Scan for processes which should be dying.  We hope they
11127c478bd9Sstevel@tonic-gate 		 * will die without having to be sent a SIGKILL signal.
11137c478bd9Sstevel@tonic-gate 		 */
11147c478bd9Sstevel@tonic-gate 		for (process = proc_table;
11157c478bd9Sstevel@tonic-gate 		    (process < proc_table + num_proc); process++) {
11167c478bd9Sstevel@tonic-gate 			/*
11177c478bd9Sstevel@tonic-gate 			 * If this process should die, hasn't yet, and the
11187c478bd9Sstevel@tonic-gate 			 * TWARN time hasn't expired yet, wait for process
11197c478bd9Sstevel@tonic-gate 			 * to die or for timer to expire.
11207c478bd9Sstevel@tonic-gate 			 */
11217c478bd9Sstevel@tonic-gate 			while (time_up == FALSE &&
11227c478bd9Sstevel@tonic-gate 			    (process->p_flags & (WARNED|LIVING|OCCUPIED)) ==
11237c478bd9Sstevel@tonic-gate 			    (WARNED|LIVING|OCCUPIED))
11247c478bd9Sstevel@tonic-gate 				(void) pause();
11257c478bd9Sstevel@tonic-gate 
11267c478bd9Sstevel@tonic-gate 			if (time_up == TRUE)
11277c478bd9Sstevel@tonic-gate 				break;
11287c478bd9Sstevel@tonic-gate 		}
11297c478bd9Sstevel@tonic-gate 
11307c478bd9Sstevel@tonic-gate 		/*
11317c478bd9Sstevel@tonic-gate 		 * If we reached the end of the table without the timer
11327c478bd9Sstevel@tonic-gate 		 * expiring, then there are no procs which will have to be
11337c478bd9Sstevel@tonic-gate 		 * sent the SIGKILL signal.  If the timer has expired, then
11347c478bd9Sstevel@tonic-gate 		 * it is necessary to scan the table again and send signals
11357c478bd9Sstevel@tonic-gate 		 * to all processes which aren't going away nicely.
11367c478bd9Sstevel@tonic-gate 		 */
11377c478bd9Sstevel@tonic-gate 		if (time_up == TRUE) {
11387c478bd9Sstevel@tonic-gate 			for (process = proc_table;
11397c478bd9Sstevel@tonic-gate 			    (process < proc_table + num_proc); process++) {
11407c478bd9Sstevel@tonic-gate 				if ((process->p_flags &
11417c478bd9Sstevel@tonic-gate 				    (WARNED|LIVING|OCCUPIED)) ==
11427c478bd9Sstevel@tonic-gate 				    (WARNED|LIVING|OCCUPIED))
11437c478bd9Sstevel@tonic-gate 					(void) kill(process->p_pid, SIGKILL);
11447c478bd9Sstevel@tonic-gate 			}
11457c478bd9Sstevel@tonic-gate 		}
11467c478bd9Sstevel@tonic-gate 		setimer(0);
11477c478bd9Sstevel@tonic-gate 	}
11487c478bd9Sstevel@tonic-gate 
11497c478bd9Sstevel@tonic-gate 	/*
11507c478bd9Sstevel@tonic-gate 	 * Rescan the proc_table for two kinds of entry, those marked LIVING,
11517c478bd9Sstevel@tonic-gate 	 * NAMED, which don't have an entry in inittab (haven't been TOUCHED
11527c478bd9Sstevel@tonic-gate 	 * by the above scanning), and haven't been sent kill signals, and
11537c478bd9Sstevel@tonic-gate 	 * those entries marked not LIVING, NAMED.  The former procs are killed.
11547c478bd9Sstevel@tonic-gate 	 * The latter have DEAD_PROCESS accounting done and the slot cleared.
11557c478bd9Sstevel@tonic-gate 	 */
11567c478bd9Sstevel@tonic-gate 	for (process = proc_table;
11577c478bd9Sstevel@tonic-gate 	    (process < proc_table + num_proc); process++) {
11587c478bd9Sstevel@tonic-gate 		if ((process->p_flags & (LIVING|NAMED|TOUCHED|KILLED|OCCUPIED))
11597c478bd9Sstevel@tonic-gate 		    == (LIVING|NAMED|OCCUPIED)) {
11607c478bd9Sstevel@tonic-gate 			killproc(process->p_pid);
11617c478bd9Sstevel@tonic-gate 			process->p_flags |= KILLED;
11627c478bd9Sstevel@tonic-gate 		} else if ((process->p_flags & (LIVING|NAMED|OCCUPIED)) ==
11637c478bd9Sstevel@tonic-gate 		    (NAMED|OCCUPIED)) {
11647c478bd9Sstevel@tonic-gate 			(void) account(DEAD_PROCESS, process, NULL);
11657c478bd9Sstevel@tonic-gate 			/*
11667c478bd9Sstevel@tonic-gate 			 * If this named proc hasn't been TOUCHED, then free the
11677c478bd9Sstevel@tonic-gate 			 * space. It has either died of it's own accord, but
11687c478bd9Sstevel@tonic-gate 			 * isn't respawnable or it was killed because it
11697c478bd9Sstevel@tonic-gate 			 * shouldn't exist at this level.
11707c478bd9Sstevel@tonic-gate 			 */
11717c478bd9Sstevel@tonic-gate 			if ((process->p_flags & TOUCHED) == 0)
11727c478bd9Sstevel@tonic-gate 				process->p_flags = 0;
11737c478bd9Sstevel@tonic-gate 		}
11747c478bd9Sstevel@tonic-gate 	}
11757c478bd9Sstevel@tonic-gate 
11767c478bd9Sstevel@tonic-gate 	st_write();
11777c478bd9Sstevel@tonic-gate }
11787c478bd9Sstevel@tonic-gate 
11797c478bd9Sstevel@tonic-gate /*
11807c478bd9Sstevel@tonic-gate  * Extract the svc.startd command line and whether to restart it from its
11817c478bd9Sstevel@tonic-gate  * inittab entry.
11827c478bd9Sstevel@tonic-gate  */
11837c478bd9Sstevel@tonic-gate /*ARGSUSED*/
11847c478bd9Sstevel@tonic-gate static void
11857c478bd9Sstevel@tonic-gate process_startd_line(struct CMD_LINE *cmd, char *cmd_string)
11867c478bd9Sstevel@tonic-gate {
11877c478bd9Sstevel@tonic-gate 	size_t sz;
11887c478bd9Sstevel@tonic-gate 
11897c478bd9Sstevel@tonic-gate 	/* Save the command line. */
11907c478bd9Sstevel@tonic-gate 	if (sflg || rflg) {
11917c478bd9Sstevel@tonic-gate 		/* Also append -r or -s. */
11927c478bd9Sstevel@tonic-gate 		(void) strlcpy(startd_cline, cmd_string, sizeof (startd_cline));
11937c478bd9Sstevel@tonic-gate 		(void) strlcat(startd_cline, " -", sizeof (startd_cline));
11947c478bd9Sstevel@tonic-gate 		if (sflg)
11957c478bd9Sstevel@tonic-gate 			sz = strlcat(startd_cline, "s", sizeof (startd_cline));
11967c478bd9Sstevel@tonic-gate 		if (rflg)
11977c478bd9Sstevel@tonic-gate 			sz = strlcat(startd_cline, "r", sizeof (startd_cline));
11987c478bd9Sstevel@tonic-gate 	} else {
11997c478bd9Sstevel@tonic-gate 		sz = strlcpy(startd_cline, cmd_string, sizeof (startd_cline));
12007c478bd9Sstevel@tonic-gate 	}
12017c478bd9Sstevel@tonic-gate 
12027c478bd9Sstevel@tonic-gate 	if (sz >= sizeof (startd_cline)) {
12037c478bd9Sstevel@tonic-gate 		console(B_TRUE,
12047c478bd9Sstevel@tonic-gate 		    "svc.startd command line too long.  Ignoring.\n");
12057c478bd9Sstevel@tonic-gate 		startd_cline[0] = '\0';
12067c478bd9Sstevel@tonic-gate 		return;
12077c478bd9Sstevel@tonic-gate 	}
12087c478bd9Sstevel@tonic-gate }
12097c478bd9Sstevel@tonic-gate 
12107c478bd9Sstevel@tonic-gate /*
12117c478bd9Sstevel@tonic-gate  * spawn_processes() scans inittab for entries which should be run at this
12127c478bd9Sstevel@tonic-gate  * mode.  Processes which should be running but are not, are started.
12137c478bd9Sstevel@tonic-gate  */
12147c478bd9Sstevel@tonic-gate static int
12157c478bd9Sstevel@tonic-gate spawn_processes()
12167c478bd9Sstevel@tonic-gate {
12177c478bd9Sstevel@tonic-gate 	struct PROC_TABLE		*pp;
12187c478bd9Sstevel@tonic-gate 	struct CMD_LINE			cmd;
12197c478bd9Sstevel@tonic-gate 	char				cmd_string[MAXCMDL];
12207c478bd9Sstevel@tonic-gate 	short				lvl_mask;
12217c478bd9Sstevel@tonic-gate 	int				status;
12227c478bd9Sstevel@tonic-gate 
12237c478bd9Sstevel@tonic-gate 	/*
12247c478bd9Sstevel@tonic-gate 	 * First check the "powerhit" flag.  If it is set, make sure the modes
12257c478bd9Sstevel@tonic-gate 	 * are PF_MODES and clear the "powerhit" flag.  Avoid the possible race
12267c478bd9Sstevel@tonic-gate 	 * on the "powerhit" flag by disallowing a new powerfail interrupt
12277c478bd9Sstevel@tonic-gate 	 * between the test of the powerhit flag and the clearing of it.
12287c478bd9Sstevel@tonic-gate 	 */
12297c478bd9Sstevel@tonic-gate 	if (wakeup.w_flags.w_powerhit) {
12307c478bd9Sstevel@tonic-gate 		wakeup.w_flags.w_powerhit = 0;
12317c478bd9Sstevel@tonic-gate 		op_modes = PF_MODES;
12327c478bd9Sstevel@tonic-gate 	}
12337c478bd9Sstevel@tonic-gate 	lvl_mask = state_to_mask(cur_state);
12347c478bd9Sstevel@tonic-gate 
12357c478bd9Sstevel@tonic-gate 	/*
12367c478bd9Sstevel@tonic-gate 	 * Scan through all the entries in inittab.
12377c478bd9Sstevel@tonic-gate 	 */
12387c478bd9Sstevel@tonic-gate 	while ((status = getcmd(&cmd, &cmd_string[0])) == TRUE) {
12397c478bd9Sstevel@tonic-gate 		if (id_eq(cmd.c_id, "smf")) {
12407c478bd9Sstevel@tonic-gate 			process_startd_line(&cmd, cmd_string);
12417c478bd9Sstevel@tonic-gate 			continue;
12427c478bd9Sstevel@tonic-gate 		}
12437c478bd9Sstevel@tonic-gate 
12447c478bd9Sstevel@tonic-gate retry_for_proc_slot:
12457c478bd9Sstevel@tonic-gate 
12467c478bd9Sstevel@tonic-gate 		/*
12477c478bd9Sstevel@tonic-gate 		 * Find out if there is a process slot for this entry already.
12487c478bd9Sstevel@tonic-gate 		 */
12497c478bd9Sstevel@tonic-gate 		if ((pp = findpslot(&cmd)) == NULLPROC) {
12507c478bd9Sstevel@tonic-gate 			/*
12517c478bd9Sstevel@tonic-gate 			 * we've run out of proc table entries
12527c478bd9Sstevel@tonic-gate 			 * increase proc_table.
12537c478bd9Sstevel@tonic-gate 			 */
12547c478bd9Sstevel@tonic-gate 			increase_proc_table_size();
12557c478bd9Sstevel@tonic-gate 
12567c478bd9Sstevel@tonic-gate 			/*
12577c478bd9Sstevel@tonic-gate 			 * Retry now as we have an empty proc slot.
12587c478bd9Sstevel@tonic-gate 			 * In case increase_proc_table_size() fails,
12597c478bd9Sstevel@tonic-gate 			 * we will keep retrying.
12607c478bd9Sstevel@tonic-gate 			 */
12617c478bd9Sstevel@tonic-gate 			goto retry_for_proc_slot;
12627c478bd9Sstevel@tonic-gate 		}
12637c478bd9Sstevel@tonic-gate 
12647c478bd9Sstevel@tonic-gate 		/*
12657c478bd9Sstevel@tonic-gate 		 * If there is an entry, and it is marked as DEMANDREQUEST,
12667c478bd9Sstevel@tonic-gate 		 * one of the levels a, b, or c is in its levels mask, and
12677c478bd9Sstevel@tonic-gate 		 * the action field is ONDEMAND and ONDEMAND is a permissable
12687c478bd9Sstevel@tonic-gate 		 * mode, and the process is dead, then respawn it.
12697c478bd9Sstevel@tonic-gate 		 */
12707c478bd9Sstevel@tonic-gate 		if (((pp->p_flags & (LIVING|DEMANDREQUEST)) == DEMANDREQUEST) &&
12717c478bd9Sstevel@tonic-gate 		    (cmd.c_levels & MASK_abc) &&
12727c478bd9Sstevel@tonic-gate 		    (cmd.c_action & op_modes) == M_ONDEMAND) {
12737c478bd9Sstevel@tonic-gate 			spawn(pp, &cmd);
12747c478bd9Sstevel@tonic-gate 			continue;
12757c478bd9Sstevel@tonic-gate 		}
12767c478bd9Sstevel@tonic-gate 
12777c478bd9Sstevel@tonic-gate 		/*
12787c478bd9Sstevel@tonic-gate 		 * If the action is not an action we are interested in,
12797c478bd9Sstevel@tonic-gate 		 * skip the entry.
12807c478bd9Sstevel@tonic-gate 		 */
12817c478bd9Sstevel@tonic-gate 		if ((cmd.c_action & op_modes) == 0 || pp->p_flags & LIVING ||
12827c478bd9Sstevel@tonic-gate 		    (cmd.c_levels & lvl_mask) == 0)
12837c478bd9Sstevel@tonic-gate 			continue;
12847c478bd9Sstevel@tonic-gate 
12857c478bd9Sstevel@tonic-gate 		/*
12867c478bd9Sstevel@tonic-gate 		 * If the modes are the normal modes (ONCE, WAIT, RESPAWN, OFF,
12877c478bd9Sstevel@tonic-gate 		 * ONDEMAND) and the action field is either OFF or the action
12887c478bd9Sstevel@tonic-gate 		 * field is ONCE or WAIT and the current level is the same as
12897c478bd9Sstevel@tonic-gate 		 * the last level, then skip this entry.  ONCE and WAIT only
12907c478bd9Sstevel@tonic-gate 		 * get run when the level changes.
12917c478bd9Sstevel@tonic-gate 		 */
12927c478bd9Sstevel@tonic-gate 		if (op_modes == NORMAL_MODES &&
12937c478bd9Sstevel@tonic-gate 		    (cmd.c_action == M_OFF ||
129448847494SEnrico Perla - Sun Microsystems 		    (cmd.c_action & (M_ONCE|M_WAIT)) &&
129548847494SEnrico Perla - Sun Microsystems 		    cur_state == prev_state))
12967c478bd9Sstevel@tonic-gate 			continue;
12977c478bd9Sstevel@tonic-gate 
12987c478bd9Sstevel@tonic-gate 		/*
12997c478bd9Sstevel@tonic-gate 		 * At this point we are interested in performing the action for
13007c478bd9Sstevel@tonic-gate 		 * this entry.  Actions fall into two categories, spinning off
13017c478bd9Sstevel@tonic-gate 		 * a process and not waiting, and spinning off a process and
13027c478bd9Sstevel@tonic-gate 		 * waiting for it to die.  If the action is ONCE, RESPAWN,
13037c478bd9Sstevel@tonic-gate 		 * ONDEMAND, POWERFAIL, or BOOT we don't wait for the process
13047c478bd9Sstevel@tonic-gate 		 * to die, for all other actions we do wait.
13057c478bd9Sstevel@tonic-gate 		 */
13067c478bd9Sstevel@tonic-gate 		if (cmd.c_action & (M_ONCE | M_RESPAWN | M_PF | M_BOOT)) {
13077c478bd9Sstevel@tonic-gate 			spawn(pp, &cmd);
13087c478bd9Sstevel@tonic-gate 
13097c478bd9Sstevel@tonic-gate 		} else {
13107c478bd9Sstevel@tonic-gate 			spawn(pp, &cmd);
131148847494SEnrico Perla - Sun Microsystems 			while (waitproc(pp) == FAILURE)
131248847494SEnrico Perla - Sun Microsystems 				;
13137c478bd9Sstevel@tonic-gate 			(void) account(DEAD_PROCESS, pp, NULL);
13147c478bd9Sstevel@tonic-gate 			pp->p_flags = 0;
13157c478bd9Sstevel@tonic-gate 		}
13167c478bd9Sstevel@tonic-gate 	}
13177c478bd9Sstevel@tonic-gate 	return (status);
13187c478bd9Sstevel@tonic-gate }
13197c478bd9Sstevel@tonic-gate 
13207c478bd9Sstevel@tonic-gate /*
13217c478bd9Sstevel@tonic-gate  * spawn() spawns a shell, inserts the information about the process
13227c478bd9Sstevel@tonic-gate  * process into the proc_table, and does the startup accounting.
13237c478bd9Sstevel@tonic-gate  */
13247c478bd9Sstevel@tonic-gate static void
13257c478bd9Sstevel@tonic-gate spawn(struct PROC_TABLE *process, struct CMD_LINE *cmd)
13267c478bd9Sstevel@tonic-gate {
13277c478bd9Sstevel@tonic-gate 	int		i;
13287c478bd9Sstevel@tonic-gate 	int		modes, maxfiles;
13297c478bd9Sstevel@tonic-gate 	time_t		now;
13307c478bd9Sstevel@tonic-gate 	struct PROC_TABLE tmproc, *oprocess;
13317c478bd9Sstevel@tonic-gate 
13327c478bd9Sstevel@tonic-gate 	/*
13337c478bd9Sstevel@tonic-gate 	 * The modes to be sent to efork() are 0 unless we are
13347c478bd9Sstevel@tonic-gate 	 * spawning a LVLa, LVLb, or LVLc entry or we will be
13357c478bd9Sstevel@tonic-gate 	 * waiting for the death of the child before continuing.
13367c478bd9Sstevel@tonic-gate 	 */
13377c478bd9Sstevel@tonic-gate 	modes = NAMED;
13387c478bd9Sstevel@tonic-gate 	if (process->p_flags & DEMANDREQUEST || cur_state == LVLa ||
13397c478bd9Sstevel@tonic-gate 	    cur_state == LVLb || cur_state == LVLc)
13407c478bd9Sstevel@tonic-gate 		modes |= DEMANDREQUEST;
13417c478bd9Sstevel@tonic-gate 	if ((cmd->c_action & (M_SYSINIT | M_WAIT | M_BOOTWAIT | M_PWAIT)) != 0)
13427c478bd9Sstevel@tonic-gate 		modes |= NOCLEANUP;
13437c478bd9Sstevel@tonic-gate 
13447c478bd9Sstevel@tonic-gate 	/*
13457c478bd9Sstevel@tonic-gate 	 * If this is a respawnable process, check the threshold
13467c478bd9Sstevel@tonic-gate 	 * information to avoid excessive respawns.
13477c478bd9Sstevel@tonic-gate 	 */
13487c478bd9Sstevel@tonic-gate 	if (cmd->c_action & M_RESPAWN) {
13497c478bd9Sstevel@tonic-gate 		/*
13507c478bd9Sstevel@tonic-gate 		 * Add NOCLEANUP to all respawnable commands so that the
13517c478bd9Sstevel@tonic-gate 		 * information about the frequency of respawns isn't lost.
13527c478bd9Sstevel@tonic-gate 		 */
13537c478bd9Sstevel@tonic-gate 		modes |= NOCLEANUP;
13547c478bd9Sstevel@tonic-gate 		(void) time(&now);
13557c478bd9Sstevel@tonic-gate 
13567c478bd9Sstevel@tonic-gate 		/*
13577c478bd9Sstevel@tonic-gate 		 * If no time is assigned, then this is the first time
13587c478bd9Sstevel@tonic-gate 		 * this command is being processed in this series.  Assign
13597c478bd9Sstevel@tonic-gate 		 * the current time.
13607c478bd9Sstevel@tonic-gate 		 */
13617c478bd9Sstevel@tonic-gate 		if (process->p_time == 0L)
13627c478bd9Sstevel@tonic-gate 			process->p_time = now;
13637c478bd9Sstevel@tonic-gate 
13647c478bd9Sstevel@tonic-gate 		if (process->p_count++ == SPAWN_LIMIT) {
13657c478bd9Sstevel@tonic-gate 
13667c478bd9Sstevel@tonic-gate 			if ((now - process->p_time) < SPAWN_INTERVAL) {
13677c478bd9Sstevel@tonic-gate 				/*
13687c478bd9Sstevel@tonic-gate 				 * Process is respawning too rapidly.  Print
13697c478bd9Sstevel@tonic-gate 				 * message and refuse to respawn it for now.
13707c478bd9Sstevel@tonic-gate 				 */
13717c478bd9Sstevel@tonic-gate 				console(B_TRUE, "Command is respawning too "
13727c478bd9Sstevel@tonic-gate 				    "rapidly. Check for possible errors.\n"
13737c478bd9Sstevel@tonic-gate 				    "id:%4s \"%s\"\n",
13747c478bd9Sstevel@tonic-gate 				    &cmd->c_id[0], &cmd->c_command[EXEC]);
13757c478bd9Sstevel@tonic-gate 				return;
13767c478bd9Sstevel@tonic-gate 			}
13777c478bd9Sstevel@tonic-gate 			process->p_time = now;
13787c478bd9Sstevel@tonic-gate 			process->p_count = 0;
13797c478bd9Sstevel@tonic-gate 
13807c478bd9Sstevel@tonic-gate 		} else if (process->p_count > SPAWN_LIMIT) {
13817c478bd9Sstevel@tonic-gate 			/*
13827c478bd9Sstevel@tonic-gate 			 * If process has been respawning too rapidly and
13837c478bd9Sstevel@tonic-gate 			 * the inhibit time limit hasn't expired yet, we
13847c478bd9Sstevel@tonic-gate 			 * refuse to respawn.
13857c478bd9Sstevel@tonic-gate 			 */
13867c478bd9Sstevel@tonic-gate 			if (now - process->p_time < SPAWN_INTERVAL + INHIBIT)
13877c478bd9Sstevel@tonic-gate 				return;
13887c478bd9Sstevel@tonic-gate 			process->p_time = now;
13897c478bd9Sstevel@tonic-gate 			process->p_count = 0;
13907c478bd9Sstevel@tonic-gate 		}
13917c478bd9Sstevel@tonic-gate 		rsflag = TRUE;
13927c478bd9Sstevel@tonic-gate 	}
13937c478bd9Sstevel@tonic-gate 
13947c478bd9Sstevel@tonic-gate 	/*
13957c478bd9Sstevel@tonic-gate 	 * Spawn a child process to execute this command.
13967c478bd9Sstevel@tonic-gate 	 */
1397c39ec064SRoger A. Faulkner 	(void) sighold(SIGCLD);
13987c478bd9Sstevel@tonic-gate 	oprocess = process;
13997c478bd9Sstevel@tonic-gate 	while ((process = efork(cmd->c_action, oprocess, modes)) == NO_ROOM)
14007c478bd9Sstevel@tonic-gate 		(void) pause();
14017c478bd9Sstevel@tonic-gate 
14027c478bd9Sstevel@tonic-gate 	if (process == NULLPROC) {
14037c478bd9Sstevel@tonic-gate 
14047c478bd9Sstevel@tonic-gate 		/*
14057c478bd9Sstevel@tonic-gate 		 * We are the child.  We must make sure we get a different
14067c478bd9Sstevel@tonic-gate 		 * file pointer for our references to utmpx.  Otherwise our
14077c478bd9Sstevel@tonic-gate 		 * seeks and reads will compete with those of the parent.
14087c478bd9Sstevel@tonic-gate 		 */
14097c478bd9Sstevel@tonic-gate 		endutxent();
14107c478bd9Sstevel@tonic-gate 
14117c478bd9Sstevel@tonic-gate 		/*
14127c478bd9Sstevel@tonic-gate 		 * Perform the accounting for the beginning of a process.
14137c478bd9Sstevel@tonic-gate 		 * Note that all processes are initially "INIT_PROCESS"es.
14147c478bd9Sstevel@tonic-gate 		 */
14157c478bd9Sstevel@tonic-gate 		tmproc.p_id[0] = cmd->c_id[0];
14167c478bd9Sstevel@tonic-gate 		tmproc.p_id[1] = cmd->c_id[1];
14177c478bd9Sstevel@tonic-gate 		tmproc.p_id[2] = cmd->c_id[2];
14187c478bd9Sstevel@tonic-gate 		tmproc.p_id[3] = cmd->c_id[3];
14197c478bd9Sstevel@tonic-gate 		tmproc.p_pid = getpid();
14207c478bd9Sstevel@tonic-gate 		tmproc.p_exit = 0;
14217c478bd9Sstevel@tonic-gate 		(void) account(INIT_PROCESS, &tmproc,
14227c478bd9Sstevel@tonic-gate 		    prog_name(&cmd->c_command[EXEC]));
14237c478bd9Sstevel@tonic-gate 		maxfiles = ulimit(UL_GDESLIM, 0);
14247c478bd9Sstevel@tonic-gate 		for (i = 0; i < maxfiles; i++)
14257c478bd9Sstevel@tonic-gate 			(void) fcntl(i, F_SETFD, FD_CLOEXEC);
14267c478bd9Sstevel@tonic-gate 
14277c478bd9Sstevel@tonic-gate 		/*
14287c478bd9Sstevel@tonic-gate 		 * Now exec a shell with the -c option and the command
14297c478bd9Sstevel@tonic-gate 		 * from inittab.
14307c478bd9Sstevel@tonic-gate 		 */
14317c478bd9Sstevel@tonic-gate 		(void) execle(SH, "INITSH", "-c", cmd->c_command, (char *)0,
14327c478bd9Sstevel@tonic-gate 		    glob_envp);
14337c478bd9Sstevel@tonic-gate 		console(B_TRUE, "Command\n\"%s\"\n failed to execute.  errno "
14347c478bd9Sstevel@tonic-gate 		    "= %d (exec of shell failed)\n", cmd->c_command, errno);
14357c478bd9Sstevel@tonic-gate 
14367c478bd9Sstevel@tonic-gate 		/*
14377c478bd9Sstevel@tonic-gate 		 * Don't come back so quickly that "init" doesn't have a
14387c478bd9Sstevel@tonic-gate 		 * chance to finish putting this child in "proc_table".
14397c478bd9Sstevel@tonic-gate 		 */
14407c478bd9Sstevel@tonic-gate 		timer(20);
14417c478bd9Sstevel@tonic-gate 		exit(1);
14427c478bd9Sstevel@tonic-gate 
14437c478bd9Sstevel@tonic-gate 	}
14447c478bd9Sstevel@tonic-gate 
14457c478bd9Sstevel@tonic-gate 	/*
14467c478bd9Sstevel@tonic-gate 	 * We are the parent.  Insert the necessary
14477c478bd9Sstevel@tonic-gate 	 * information in the proc_table.
14487c478bd9Sstevel@tonic-gate 	 */
14497c478bd9Sstevel@tonic-gate 	process->p_id[0] = cmd->c_id[0];
14507c478bd9Sstevel@tonic-gate 	process->p_id[1] = cmd->c_id[1];
14517c478bd9Sstevel@tonic-gate 	process->p_id[2] = cmd->c_id[2];
14527c478bd9Sstevel@tonic-gate 	process->p_id[3] = cmd->c_id[3];
14537c478bd9Sstevel@tonic-gate 
14547c478bd9Sstevel@tonic-gate 	st_write();
14557c478bd9Sstevel@tonic-gate 
1456c39ec064SRoger A. Faulkner 	(void) sigrelse(SIGCLD);
14577c478bd9Sstevel@tonic-gate }
14587c478bd9Sstevel@tonic-gate 
14597c478bd9Sstevel@tonic-gate /*
14607c478bd9Sstevel@tonic-gate  * findpslot() finds the old slot in the process table for the
14617c478bd9Sstevel@tonic-gate  * command with the same id, or it finds an empty slot.
14627c478bd9Sstevel@tonic-gate  */
14637c478bd9Sstevel@tonic-gate static struct PROC_TABLE *
14647c478bd9Sstevel@tonic-gate findpslot(struct CMD_LINE *cmd)
14657c478bd9Sstevel@tonic-gate {
14667c478bd9Sstevel@tonic-gate 	struct PROC_TABLE	*process;
14677c478bd9Sstevel@tonic-gate 	struct PROC_TABLE	*empty = NULLPROC;
14687c478bd9Sstevel@tonic-gate 
14697c478bd9Sstevel@tonic-gate 	for (process = proc_table;
14707c478bd9Sstevel@tonic-gate 	    (process < proc_table + num_proc); process++) {
14717c478bd9Sstevel@tonic-gate 		if (process->p_flags & OCCUPIED &&
14727c478bd9Sstevel@tonic-gate 		    id_eq(process->p_id, cmd->c_id))
14737c478bd9Sstevel@tonic-gate 			break;
14747c478bd9Sstevel@tonic-gate 
14757c478bd9Sstevel@tonic-gate 		/*
14767c478bd9Sstevel@tonic-gate 		 * If the entry is totally empty and "empty" is still 0,
14777c478bd9Sstevel@tonic-gate 		 * remember where this hole is and make sure the slot is
14787c478bd9Sstevel@tonic-gate 		 * zeroed out.
14797c478bd9Sstevel@tonic-gate 		 */
14807c478bd9Sstevel@tonic-gate 		if (empty == NULLPROC && (process->p_flags & OCCUPIED) == 0) {
14817c478bd9Sstevel@tonic-gate 			empty = process;
14827c478bd9Sstevel@tonic-gate 			process->p_id[0] = '\0';
14837c478bd9Sstevel@tonic-gate 			process->p_id[1] = '\0';
14847c478bd9Sstevel@tonic-gate 			process->p_id[2] = '\0';
14857c478bd9Sstevel@tonic-gate 			process->p_id[3] = '\0';
14867c478bd9Sstevel@tonic-gate 			process->p_pid = 0;
14877c478bd9Sstevel@tonic-gate 			process->p_time = 0L;
14887c478bd9Sstevel@tonic-gate 			process->p_count = 0;
14897c478bd9Sstevel@tonic-gate 			process->p_flags = 0;
14907c478bd9Sstevel@tonic-gate 			process->p_exit = 0;
14917c478bd9Sstevel@tonic-gate 		}
14927c478bd9Sstevel@tonic-gate 	}
14937c478bd9Sstevel@tonic-gate 
14947c478bd9Sstevel@tonic-gate 	/*
14957c478bd9Sstevel@tonic-gate 	 * If there is no entry for this slot, then there should be an
14967c478bd9Sstevel@tonic-gate 	 * empty slot.  If there is no empty slot, then we've run out
14977c478bd9Sstevel@tonic-gate 	 * of proc_table space.  If the latter is true, empty will be
14987c478bd9Sstevel@tonic-gate 	 * NULL and the caller will have to complain.
14997c478bd9Sstevel@tonic-gate 	 */
15007c478bd9Sstevel@tonic-gate 	if (process == (proc_table + num_proc))
15017c478bd9Sstevel@tonic-gate 		process = empty;
15027c478bd9Sstevel@tonic-gate 
15037c478bd9Sstevel@tonic-gate 	return (process);
15047c478bd9Sstevel@tonic-gate }
15057c478bd9Sstevel@tonic-gate 
15067c478bd9Sstevel@tonic-gate /*
15077c478bd9Sstevel@tonic-gate  * getcmd() parses lines from inittab.  Each time it finds a command line
15087c478bd9Sstevel@tonic-gate  * it will return TRUE as well as fill the passed CMD_LINE structure and
15097c478bd9Sstevel@tonic-gate  * the shell command string.  When the end of inittab is reached, FALSE
15107c478bd9Sstevel@tonic-gate  * is returned inittab is automatically opened if it is not currently open
15117c478bd9Sstevel@tonic-gate  * and is closed when the end of the file is reached.
15127c478bd9Sstevel@tonic-gate  */
15137c478bd9Sstevel@tonic-gate static FILE *fp_inittab = NULL;
15147c478bd9Sstevel@tonic-gate 
15157c478bd9Sstevel@tonic-gate static int
15167c478bd9Sstevel@tonic-gate getcmd(struct CMD_LINE *cmd, char *shcmd)
15177c478bd9Sstevel@tonic-gate {
15187c478bd9Sstevel@tonic-gate 	char	*ptr;
15197c478bd9Sstevel@tonic-gate 	int	c, lastc, state;
15207c478bd9Sstevel@tonic-gate 	char 	*ptr1;
15217c478bd9Sstevel@tonic-gate 	int	answer, i, proceed;
15227c478bd9Sstevel@tonic-gate 	struct	stat	sbuf;
15237c478bd9Sstevel@tonic-gate 	static char *actions[] = {
15247c478bd9Sstevel@tonic-gate 		"off", "respawn", "ondemand", "once", "wait", "boot",
15257c478bd9Sstevel@tonic-gate 		"bootwait", "powerfail", "powerwait", "initdefault",
15267c478bd9Sstevel@tonic-gate 		"sysinit",
15277c478bd9Sstevel@tonic-gate 	};
15287c478bd9Sstevel@tonic-gate 	static short act_masks[] = {
15297c478bd9Sstevel@tonic-gate 		M_OFF, M_RESPAWN, M_ONDEMAND, M_ONCE, M_WAIT, M_BOOT,
15307c478bd9Sstevel@tonic-gate 		M_BOOTWAIT, M_PF, M_PWAIT, M_INITDEFAULT, M_SYSINIT,
15317c478bd9Sstevel@tonic-gate 	};
15327c478bd9Sstevel@tonic-gate 	/*
15337c478bd9Sstevel@tonic-gate 	 * Only these actions will be allowed for entries which
15347c478bd9Sstevel@tonic-gate 	 * are specified for single-user mode.
15357c478bd9Sstevel@tonic-gate 	 */
15367c478bd9Sstevel@tonic-gate 	short su_acts = M_INITDEFAULT | M_PF | M_PWAIT | M_WAIT;
15377c478bd9Sstevel@tonic-gate 
15387c478bd9Sstevel@tonic-gate 	if (fp_inittab == NULL) {
15397c478bd9Sstevel@tonic-gate 		/*
15407c478bd9Sstevel@tonic-gate 		 * Before attempting to open inittab we stat it to make
15417c478bd9Sstevel@tonic-gate 		 * sure it currently exists and is not empty.  We try
15427c478bd9Sstevel@tonic-gate 		 * several times because someone may have temporarily
15437c478bd9Sstevel@tonic-gate 		 * unlinked or truncated the file.
15447c478bd9Sstevel@tonic-gate 		 */
15457c478bd9Sstevel@tonic-gate 		for (i = 0; i < 3; i++) {
15467c478bd9Sstevel@tonic-gate 			if (stat(INITTAB, &sbuf) == -1) {
15477c478bd9Sstevel@tonic-gate 				if (i == 2) {
15487c478bd9Sstevel@tonic-gate 					console(B_TRUE,
15497c478bd9Sstevel@tonic-gate 					    "Cannot stat %s, errno: %d\n",
15507c478bd9Sstevel@tonic-gate 					    INITTAB, errno);
15517c478bd9Sstevel@tonic-gate 					return (FAILURE);
15527c478bd9Sstevel@tonic-gate 				} else {
15537c478bd9Sstevel@tonic-gate 					timer(3);
15547c478bd9Sstevel@tonic-gate 				}
15557c478bd9Sstevel@tonic-gate 			} else if (sbuf.st_size < 10) {
15567c478bd9Sstevel@tonic-gate 				if (i == 2) {
15577c478bd9Sstevel@tonic-gate 					console(B_TRUE,
15587c478bd9Sstevel@tonic-gate 					    "%s truncated or corrupted\n",
15597c478bd9Sstevel@tonic-gate 					    INITTAB);
15607c478bd9Sstevel@tonic-gate 					return (FAILURE);
15617c478bd9Sstevel@tonic-gate 				} else {
15627c478bd9Sstevel@tonic-gate 					timer(3);
15637c478bd9Sstevel@tonic-gate 				}
15647c478bd9Sstevel@tonic-gate 			} else {
15657c478bd9Sstevel@tonic-gate 				break;
15667c478bd9Sstevel@tonic-gate 			}
15677c478bd9Sstevel@tonic-gate 		}
15687c478bd9Sstevel@tonic-gate 
15697c478bd9Sstevel@tonic-gate 		/*
15707c478bd9Sstevel@tonic-gate 		 * If unable to open inittab, print error message and
15717c478bd9Sstevel@tonic-gate 		 * return FAILURE to caller.
15727c478bd9Sstevel@tonic-gate 		 */
15737c478bd9Sstevel@tonic-gate 		if ((fp_inittab = fopen(INITTAB, "r")) == NULL) {
15747c478bd9Sstevel@tonic-gate 			console(B_TRUE, "Cannot open %s errno: %d\n", INITTAB,
15757c478bd9Sstevel@tonic-gate 			    errno);
15767c478bd9Sstevel@tonic-gate 			return (FAILURE);
15777c478bd9Sstevel@tonic-gate 		}
15787c478bd9Sstevel@tonic-gate 	}
15797c478bd9Sstevel@tonic-gate 
15807c478bd9Sstevel@tonic-gate 	/*
15817c478bd9Sstevel@tonic-gate 	 * Keep getting commands from inittab until you find a
15827c478bd9Sstevel@tonic-gate 	 * good one or run out of file.
15837c478bd9Sstevel@tonic-gate 	 */
15847c478bd9Sstevel@tonic-gate 	for (answer = FALSE; answer == FALSE; ) {
15857c478bd9Sstevel@tonic-gate 		/*
15867c478bd9Sstevel@tonic-gate 		 * Zero out the cmd itself before trying next line.
15877c478bd9Sstevel@tonic-gate 		 */
15887c478bd9Sstevel@tonic-gate 		bzero(cmd, sizeof (struct CMD_LINE));
15897c478bd9Sstevel@tonic-gate 
15907c478bd9Sstevel@tonic-gate 		/*
15917c478bd9Sstevel@tonic-gate 		 * Read in lines of inittab, parsing at colons, until a line is
15927c478bd9Sstevel@tonic-gate 		 * read in which doesn't end with a backslash.  Do not start if
15937c478bd9Sstevel@tonic-gate 		 * the first character read is an EOF.  Note that this means
15947c478bd9Sstevel@tonic-gate 		 * that lines which don't end in a newline are still processed,
15957c478bd9Sstevel@tonic-gate 		 * since the "for" will terminate normally once started,
15967c478bd9Sstevel@tonic-gate 		 * regardless of whether line terminates with a newline or EOF.
15977c478bd9Sstevel@tonic-gate 		 */
15987c478bd9Sstevel@tonic-gate 		state = FAILURE;
15997c478bd9Sstevel@tonic-gate 		if ((c = fgetc(fp_inittab)) == EOF) {
16007c478bd9Sstevel@tonic-gate 			answer = FALSE;
16017c478bd9Sstevel@tonic-gate 			(void) fclose(fp_inittab);
16027c478bd9Sstevel@tonic-gate 			fp_inittab = NULL;
16037c478bd9Sstevel@tonic-gate 			break;
16047c478bd9Sstevel@tonic-gate 		}
16057c478bd9Sstevel@tonic-gate 
16067c478bd9Sstevel@tonic-gate 		for (proceed = TRUE, ptr = shcmd, state = ID, lastc = '\0';
16077c478bd9Sstevel@tonic-gate 		    proceed && c != EOF;
16087c478bd9Sstevel@tonic-gate 		    lastc = c, c = fgetc(fp_inittab)) {
16090a1278f2SGary Mills 			/* If we're not in the FAILURE state and haven't */
16100a1278f2SGary Mills 			/* yet reached the shell command field, process	 */
16110a1278f2SGary Mills 			/* the line, otherwise just look for a real end	 */
16120a1278f2SGary Mills 			/* of line.					 */
16130a1278f2SGary Mills 			if (state != FAILURE && state != COMMAND) {
16147c478bd9Sstevel@tonic-gate 			/*
16157c478bd9Sstevel@tonic-gate 			 * Squeeze out spaces and tabs.
16167c478bd9Sstevel@tonic-gate 			 */
16177c478bd9Sstevel@tonic-gate 			if (c == ' ' || c == '\t')
16187c478bd9Sstevel@tonic-gate 				continue;
16197c478bd9Sstevel@tonic-gate 
16207c478bd9Sstevel@tonic-gate 			/*
16217c478bd9Sstevel@tonic-gate 			 * Ignore characters in a comment, except for the \n.
16227c478bd9Sstevel@tonic-gate 			 */
16237c478bd9Sstevel@tonic-gate 			if (state == COMMENT) {
16247c478bd9Sstevel@tonic-gate 				if (c == '\n') {
16257c478bd9Sstevel@tonic-gate 					lastc = ' ';
16267c478bd9Sstevel@tonic-gate 					break;
16277c478bd9Sstevel@tonic-gate 				} else {
16287c478bd9Sstevel@tonic-gate 					continue;
16297c478bd9Sstevel@tonic-gate 				}
16307c478bd9Sstevel@tonic-gate 			}
16317c478bd9Sstevel@tonic-gate 
16327c478bd9Sstevel@tonic-gate 			/*
16337c478bd9Sstevel@tonic-gate 			 * Detect comments (lines whose first non-whitespace
16347c478bd9Sstevel@tonic-gate 			 * character is '#') by checking that we're at the
16357c478bd9Sstevel@tonic-gate 			 * beginning of a line, have seen a '#', and haven't
16367c478bd9Sstevel@tonic-gate 			 * yet accumulated any characters.
16377c478bd9Sstevel@tonic-gate 			 */
16387c478bd9Sstevel@tonic-gate 			if (state == ID && c == '#' && ptr == shcmd) {
16397c478bd9Sstevel@tonic-gate 				state = COMMENT;
16407c478bd9Sstevel@tonic-gate 				continue;
16417c478bd9Sstevel@tonic-gate 			}
16427c478bd9Sstevel@tonic-gate 
16437c478bd9Sstevel@tonic-gate 			/*
16447c478bd9Sstevel@tonic-gate 			 * If the character is a ':', then check the
16457c478bd9Sstevel@tonic-gate 			 * previous field for correctness and advance
16467c478bd9Sstevel@tonic-gate 			 * to the next field.
16477c478bd9Sstevel@tonic-gate 			 */
16487c478bd9Sstevel@tonic-gate 			if (c == ':') {
16490a1278f2SGary Mills 				switch (state) {
16507c478bd9Sstevel@tonic-gate 
16510a1278f2SGary Mills 				case ID :
16527c478bd9Sstevel@tonic-gate 				/*
16537c478bd9Sstevel@tonic-gate 				 * Check to see that there are only
16547c478bd9Sstevel@tonic-gate 				 * 1 to 4 characters for the id.
16557c478bd9Sstevel@tonic-gate 				 */
16567c478bd9Sstevel@tonic-gate 				if ((i = ptr - shcmd) < 1 || i > 4) {
16577c478bd9Sstevel@tonic-gate 					state = FAILURE;
16587c478bd9Sstevel@tonic-gate 				} else {
16597c478bd9Sstevel@tonic-gate 					bcopy(shcmd, &cmd->c_id[0], i);
16607c478bd9Sstevel@tonic-gate 					ptr = shcmd;
16617c478bd9Sstevel@tonic-gate 					state = LEVELS;
16627c478bd9Sstevel@tonic-gate 				}
16637c478bd9Sstevel@tonic-gate 				break;
16647c478bd9Sstevel@tonic-gate 
16650a1278f2SGary Mills 				case LEVELS :
16667c478bd9Sstevel@tonic-gate 				/*
16677c478bd9Sstevel@tonic-gate 				 * Build a mask for all the levels for
16687c478bd9Sstevel@tonic-gate 				 * which this command will be legal.
16697c478bd9Sstevel@tonic-gate 				 */
16707c478bd9Sstevel@tonic-gate 				for (cmd->c_levels = 0, ptr1 = shcmd;
16717c478bd9Sstevel@tonic-gate 				    ptr1 < ptr; ptr1++) {
16727c478bd9Sstevel@tonic-gate 					int mask;
16737c478bd9Sstevel@tonic-gate 					if (lvlname_to_mask(*ptr1,
16747c478bd9Sstevel@tonic-gate 					    &mask) == -1) {
16757c478bd9Sstevel@tonic-gate 						state = FAILURE;
16767c478bd9Sstevel@tonic-gate 						break;
16777c478bd9Sstevel@tonic-gate 					}
16787c478bd9Sstevel@tonic-gate 					cmd->c_levels |= mask;
16797c478bd9Sstevel@tonic-gate 				}
16807c478bd9Sstevel@tonic-gate 				if (state != FAILURE) {
16817c478bd9Sstevel@tonic-gate 					state = ACTION;
16827c478bd9Sstevel@tonic-gate 					ptr = shcmd;	/* Reset the buffer */
16837c478bd9Sstevel@tonic-gate 				}
16847c478bd9Sstevel@tonic-gate 				break;
16857c478bd9Sstevel@tonic-gate 
16860a1278f2SGary Mills 				case ACTION :
16877c478bd9Sstevel@tonic-gate 				/*
16887c478bd9Sstevel@tonic-gate 				 * Null terminate the string in shcmd buffer and
16897c478bd9Sstevel@tonic-gate 				 * then try to match against legal actions.  If
16907c478bd9Sstevel@tonic-gate 				 * the field is of length 0, then the default of
16917c478bd9Sstevel@tonic-gate 				 * "RESPAWN" is used if the id is numeric,
16927c478bd9Sstevel@tonic-gate 				 * otherwise the default is "OFF".
16937c478bd9Sstevel@tonic-gate 				 */
16947c478bd9Sstevel@tonic-gate 				if (ptr == shcmd) {
16957c478bd9Sstevel@tonic-gate 					if (isdigit(cmd->c_id[0]) &&
16967c478bd9Sstevel@tonic-gate 					    (cmd->c_id[1] == '\0' ||
16970a1278f2SGary Mills 					    isdigit(cmd->c_id[1])) &&
16987c478bd9Sstevel@tonic-gate 					    (cmd->c_id[2] == '\0' ||
16990a1278f2SGary Mills 					    isdigit(cmd->c_id[2])) &&
17007c478bd9Sstevel@tonic-gate 					    (cmd->c_id[3] == '\0' ||
17010a1278f2SGary Mills 					    isdigit(cmd->c_id[3])))
17020a1278f2SGary Mills 						cmd->c_action = M_RESPAWN;
17037c478bd9Sstevel@tonic-gate 					else
17040a1278f2SGary Mills 						cmd->c_action = M_OFF;
17057c478bd9Sstevel@tonic-gate 				} else {
17060a1278f2SGary Mills 					for (cmd->c_action = 0, i = 0,
17070a1278f2SGary Mills 					    *ptr = '\0';
17080a1278f2SGary Mills 					    i <
17090a1278f2SGary Mills 					    sizeof (actions)/sizeof (char *);
17100a1278f2SGary Mills 					    i++) {
17117c478bd9Sstevel@tonic-gate 					if (strcmp(shcmd, actions[i]) == 0) {
17120a1278f2SGary Mills 						if ((cmd->c_levels & MASKSU) &&
17130a1278f2SGary Mills 						    !(act_masks[i] & su_acts))
17140a1278f2SGary Mills 							cmd->c_action = 0;
17150a1278f2SGary Mills 						else
17160a1278f2SGary Mills 							cmd->c_action =
17170a1278f2SGary Mills 							    act_masks[i];
17180a1278f2SGary Mills 						break;
17190a1278f2SGary Mills 					}
17207c478bd9Sstevel@tonic-gate 					}
17217c478bd9Sstevel@tonic-gate 				}
17227c478bd9Sstevel@tonic-gate 
17237c478bd9Sstevel@tonic-gate 				/*
17247c478bd9Sstevel@tonic-gate 				 * If the action didn't match any legal action,
17257c478bd9Sstevel@tonic-gate 				 * set state to FAILURE.
17267c478bd9Sstevel@tonic-gate 				 */
17277c478bd9Sstevel@tonic-gate 				if (cmd->c_action == 0) {
17287c478bd9Sstevel@tonic-gate 					state = FAILURE;
17297c478bd9Sstevel@tonic-gate 				} else {
17307c478bd9Sstevel@tonic-gate 					state = COMMAND;
17317c478bd9Sstevel@tonic-gate 					(void) strcpy(shcmd, "exec ");
17327c478bd9Sstevel@tonic-gate 				}
17337c478bd9Sstevel@tonic-gate 				ptr = shcmd + EXEC;
17347c478bd9Sstevel@tonic-gate 				break;
17350a1278f2SGary Mills 				}
17360a1278f2SGary Mills 				continue;
17377c478bd9Sstevel@tonic-gate 			}
17380a1278f2SGary Mills 		}
17390a1278f2SGary Mills 
17400a1278f2SGary Mills 		/* If the character is a '\n', then this is the end of a */
17410a1278f2SGary Mills 		/* line.  If the '\n' wasn't preceded by a backslash, */
17420a1278f2SGary Mills 		/* it is also the end of an inittab command.  If it was */
17430a1278f2SGary Mills 		/* preceded by a backslash then the next line is a */
17440a1278f2SGary Mills 		/* continuation.  Note that the continuation '\n' falls */
17450a1278f2SGary Mills 		/* through and is treated like other characters and is */
17460a1278f2SGary Mills 		/* stored in the shell command line. */
17470a1278f2SGary Mills 		if (c == '\n' && lastc != '\\') {
17480a1278f2SGary Mills 			proceed = FALSE;
17490a1278f2SGary Mills 			*ptr = '\0';
17500a1278f2SGary Mills 			break;
17510a1278f2SGary Mills 		}
17527c478bd9Sstevel@tonic-gate 
17530a1278f2SGary Mills 		/* For all other characters just stuff them into the */
17540a1278f2SGary Mills 		/* command as long as there aren't too many of them. */
17550a1278f2SGary Mills 		/* Make sure there is room for a terminating '\0' also. */
17560a1278f2SGary Mills 		if (ptr >= shcmd + MAXCMDL - 1)
17577c478bd9Sstevel@tonic-gate 			state = FAILURE;
17580a1278f2SGary Mills 		else
17597c478bd9Sstevel@tonic-gate 			*ptr++ = (char)c;
17607c478bd9Sstevel@tonic-gate 
17610a1278f2SGary Mills 		/* If the character we just stored was a quoted	*/
17620a1278f2SGary Mills 		/* backslash, then change "c" to '\0', so that this	*/
17630a1278f2SGary Mills 		/* backslash will not cause a subsequent '\n' to appear */
17640a1278f2SGary Mills 		/* quoted.  In otherwords '\' '\' '\n' is the real end */
17650a1278f2SGary Mills 		/* of a command, while '\' '\n' is a continuation. */
17660a1278f2SGary Mills 		if (c == '\\' && lastc == '\\')
17677c478bd9Sstevel@tonic-gate 			c = '\0';
17687c478bd9Sstevel@tonic-gate 		}
17697c478bd9Sstevel@tonic-gate 
17707c478bd9Sstevel@tonic-gate 		/*
17717c478bd9Sstevel@tonic-gate 		 * Make sure all the fields are properly specified
17727c478bd9Sstevel@tonic-gate 		 * for a good command line.
17737c478bd9Sstevel@tonic-gate 		 */
17747c478bd9Sstevel@tonic-gate 		if (state == COMMAND) {
17757c478bd9Sstevel@tonic-gate 			answer = TRUE;
17767c478bd9Sstevel@tonic-gate 			cmd->c_command = shcmd;
17777c478bd9Sstevel@tonic-gate 
17787c478bd9Sstevel@tonic-gate 			/*
17797c478bd9Sstevel@tonic-gate 			 * If no default level was supplied, insert
17807c478bd9Sstevel@tonic-gate 			 * all numerical levels.
17817c478bd9Sstevel@tonic-gate 			 */
17827c478bd9Sstevel@tonic-gate 			if (cmd->c_levels == 0)
17837c478bd9Sstevel@tonic-gate 				cmd->c_levels = MASK_NUMERIC;
17847c478bd9Sstevel@tonic-gate 
17857c478bd9Sstevel@tonic-gate 			/*
17867c478bd9Sstevel@tonic-gate 			 * If no action has been supplied, declare this
17877c478bd9Sstevel@tonic-gate 			 * entry to be OFF.
17887c478bd9Sstevel@tonic-gate 			 */
17897c478bd9Sstevel@tonic-gate 			if (cmd->c_action == 0)
17907c478bd9Sstevel@tonic-gate 				cmd->c_action = M_OFF;
17917c478bd9Sstevel@tonic-gate 
17927c478bd9Sstevel@tonic-gate 			/*
17937c478bd9Sstevel@tonic-gate 			 * If no shell command has been supplied, make sure
17947c478bd9Sstevel@tonic-gate 			 * there is a null string in the command field.
17957c478bd9Sstevel@tonic-gate 			 */
17967c478bd9Sstevel@tonic-gate 			if (ptr == shcmd + EXEC)
17977c478bd9Sstevel@tonic-gate 				*shcmd = '\0';
17987c478bd9Sstevel@tonic-gate 		} else
17997c478bd9Sstevel@tonic-gate 			answer = FALSE;
18007c478bd9Sstevel@tonic-gate 
18017c478bd9Sstevel@tonic-gate 		/*
18027c478bd9Sstevel@tonic-gate 		 * If we have reached the end of inittab, then close it
18037c478bd9Sstevel@tonic-gate 		 * and quit trying to find a good command line.
18047c478bd9Sstevel@tonic-gate 		 */
18057c478bd9Sstevel@tonic-gate 		if (c == EOF) {
18067c478bd9Sstevel@tonic-gate 			(void) fclose(fp_inittab);
18077c478bd9Sstevel@tonic-gate 			fp_inittab = NULL;
18087c478bd9Sstevel@tonic-gate 			break;
18097c478bd9Sstevel@tonic-gate 		}
18107c478bd9Sstevel@tonic-gate 	}
18117c478bd9Sstevel@tonic-gate 	return (answer);
18127c478bd9Sstevel@tonic-gate }
18137c478bd9Sstevel@tonic-gate 
18147c478bd9Sstevel@tonic-gate /*
18157c478bd9Sstevel@tonic-gate  * lvlname_to_state(): convert the character name of a state to its level
18167c478bd9Sstevel@tonic-gate  * (its corresponding signal number).
18177c478bd9Sstevel@tonic-gate  */
18187c478bd9Sstevel@tonic-gate static int
18197c478bd9Sstevel@tonic-gate lvlname_to_state(char name)
18207c478bd9Sstevel@tonic-gate {
18217c478bd9Sstevel@tonic-gate 	int i;
18227c478bd9Sstevel@tonic-gate 	for (i = 0; i < LVL_NELEMS; i++) {
18237c478bd9Sstevel@tonic-gate 		if (lvls[i].lvl_name == name)
18247c478bd9Sstevel@tonic-gate 			return (lvls[i].lvl_state);
18257c478bd9Sstevel@tonic-gate 	}
18267c478bd9Sstevel@tonic-gate 	return (-1);
18277c478bd9Sstevel@tonic-gate }
18287c478bd9Sstevel@tonic-gate 
18297c478bd9Sstevel@tonic-gate /*
18307c478bd9Sstevel@tonic-gate  * state_to_name(): convert the level to the character name.
18317c478bd9Sstevel@tonic-gate  */
18327c478bd9Sstevel@tonic-gate static char
18337c478bd9Sstevel@tonic-gate state_to_name(int state)
18347c478bd9Sstevel@tonic-gate {
18357c478bd9Sstevel@tonic-gate 	int i;
18367c478bd9Sstevel@tonic-gate 	for (i = 0; i < LVL_NELEMS; i++) {
18377c478bd9Sstevel@tonic-gate 		if (lvls[i].lvl_state == state)
18387c478bd9Sstevel@tonic-gate 			return (lvls[i].lvl_name);
18397c478bd9Sstevel@tonic-gate 	}
18407c478bd9Sstevel@tonic-gate 	return (-1);
18417c478bd9Sstevel@tonic-gate }
18427c478bd9Sstevel@tonic-gate 
18437c478bd9Sstevel@tonic-gate /*
18447c478bd9Sstevel@tonic-gate  * state_to_mask(): return the mask corresponding to a signal number
18457c478bd9Sstevel@tonic-gate  */
18467c478bd9Sstevel@tonic-gate static int
18477c478bd9Sstevel@tonic-gate state_to_mask(int state)
18487c478bd9Sstevel@tonic-gate {
18497c478bd9Sstevel@tonic-gate 	int i;
18507c478bd9Sstevel@tonic-gate 	for (i = 0; i < LVL_NELEMS; i++) {
18517c478bd9Sstevel@tonic-gate 		if (lvls[i].lvl_state == state)
18527c478bd9Sstevel@tonic-gate 			return (lvls[i].lvl_mask);
18537c478bd9Sstevel@tonic-gate 	}
18547c478bd9Sstevel@tonic-gate 	return (0);	/* return 0, since that represents an empty mask */
18557c478bd9Sstevel@tonic-gate }
18567c478bd9Sstevel@tonic-gate 
18577c478bd9Sstevel@tonic-gate /*
18587c478bd9Sstevel@tonic-gate  * lvlname_to_mask(): return the mask corresponding to a levels character name
18597c478bd9Sstevel@tonic-gate  */
18607c478bd9Sstevel@tonic-gate static int
18617c478bd9Sstevel@tonic-gate lvlname_to_mask(char name, int *mask)
18627c478bd9Sstevel@tonic-gate {
18637c478bd9Sstevel@tonic-gate 	int i;
18647c478bd9Sstevel@tonic-gate 	for (i = 0; i < LVL_NELEMS; i++) {
18657c478bd9Sstevel@tonic-gate 		if (lvls[i].lvl_name == name) {
18667c478bd9Sstevel@tonic-gate 			*mask = lvls[i].lvl_mask;
18677c478bd9Sstevel@tonic-gate 			return (0);
18687c478bd9Sstevel@tonic-gate 		}
18697c478bd9Sstevel@tonic-gate 	}
18707c478bd9Sstevel@tonic-gate 	return (-1);
18717c478bd9Sstevel@tonic-gate }
18727c478bd9Sstevel@tonic-gate 
18737c478bd9Sstevel@tonic-gate /*
18747c478bd9Sstevel@tonic-gate  * state_to_flags(): return the flags corresponding to a runlevel.  These
18757c478bd9Sstevel@tonic-gate  * indicate properties of that runlevel.
18767c478bd9Sstevel@tonic-gate  */
18777c478bd9Sstevel@tonic-gate static int
18787c478bd9Sstevel@tonic-gate state_to_flags(int state)
18797c478bd9Sstevel@tonic-gate {
18807c478bd9Sstevel@tonic-gate 	int i;
18817c478bd9Sstevel@tonic-gate 	for (i = 0; i < LVL_NELEMS; i++) {
18827c478bd9Sstevel@tonic-gate 		if (lvls[i].lvl_state == state)
18837c478bd9Sstevel@tonic-gate 			return (lvls[i].lvl_flags);
18847c478bd9Sstevel@tonic-gate 	}
18857c478bd9Sstevel@tonic-gate 	return (0);
18867c478bd9Sstevel@tonic-gate }
18877c478bd9Sstevel@tonic-gate 
18887c478bd9Sstevel@tonic-gate /*
18897c478bd9Sstevel@tonic-gate  * killproc() creates a child which kills the process specified by pid.
18907c478bd9Sstevel@tonic-gate  */
18917c478bd9Sstevel@tonic-gate void
18927c478bd9Sstevel@tonic-gate killproc(pid_t pid)
18937c478bd9Sstevel@tonic-gate {
18947c478bd9Sstevel@tonic-gate 	struct PROC_TABLE	*process;
18957c478bd9Sstevel@tonic-gate 
1896c39ec064SRoger A. Faulkner 	(void) sighold(SIGCLD);
18977c478bd9Sstevel@tonic-gate 	while ((process = efork(M_OFF, NULLPROC, 0)) == NO_ROOM)
18987c478bd9Sstevel@tonic-gate 		(void) pause();
1899c39ec064SRoger A. Faulkner 	(void) sigrelse(SIGCLD);
19007c478bd9Sstevel@tonic-gate 
19017c478bd9Sstevel@tonic-gate 	if (process == NULLPROC) {
19027c478bd9Sstevel@tonic-gate 		/*
19037c478bd9Sstevel@tonic-gate 		 * efork() sets all signal handlers to the default, so reset
19047c478bd9Sstevel@tonic-gate 		 * the ALRM handler to make timer() work as expected.
19057c478bd9Sstevel@tonic-gate 		 */
19067c478bd9Sstevel@tonic-gate 		(void) sigset(SIGALRM, alarmclk);
19077c478bd9Sstevel@tonic-gate 
19087c478bd9Sstevel@tonic-gate 		/*
19097c478bd9Sstevel@tonic-gate 		 * We are the child.  Try to terminate the process nicely
19107c478bd9Sstevel@tonic-gate 		 * first using SIGTERM and if it refuses to die in TWARN
19117c478bd9Sstevel@tonic-gate 		 * seconds kill it with SIGKILL.
19127c478bd9Sstevel@tonic-gate 		 */
19137c478bd9Sstevel@tonic-gate 		(void) kill(pid, SIGTERM);
19147c478bd9Sstevel@tonic-gate 		(void) timer(TWARN);
19157c478bd9Sstevel@tonic-gate 		(void) kill(pid, SIGKILL);
19167c478bd9Sstevel@tonic-gate 		(void) exit(0);
19177c478bd9Sstevel@tonic-gate 	}
19187c478bd9Sstevel@tonic-gate }
19197c478bd9Sstevel@tonic-gate 
19207c478bd9Sstevel@tonic-gate /*
19217c478bd9Sstevel@tonic-gate  * Set up the default environment for all procs to be forked from init.
19227c478bd9Sstevel@tonic-gate  * Read the values from the /etc/default/init file, except for PATH.  If
19237c478bd9Sstevel@tonic-gate  * there's not enough room in the environment array, the environment
19247c478bd9Sstevel@tonic-gate  * lines that don't fit are silently discarded.
19257c478bd9Sstevel@tonic-gate  */
19267c478bd9Sstevel@tonic-gate void
19277c478bd9Sstevel@tonic-gate init_env()
19287c478bd9Sstevel@tonic-gate {
19297c478bd9Sstevel@tonic-gate 	char	line[MAXCMDL];
19307c478bd9Sstevel@tonic-gate 	FILE	*fp;
19317c478bd9Sstevel@tonic-gate 	int	inquotes, length, wslength;
19327c478bd9Sstevel@tonic-gate 	char	*tokp, *cp1, *cp2;
19337c478bd9Sstevel@tonic-gate 
19347c478bd9Sstevel@tonic-gate 	glob_envp[0] = malloc((unsigned)(strlen(DEF_PATH)+2));
19357c478bd9Sstevel@tonic-gate 	(void) strcpy(glob_envp[0], DEF_PATH);
19367c478bd9Sstevel@tonic-gate 	glob_envn = 1;
19377c478bd9Sstevel@tonic-gate 
19387c478bd9Sstevel@tonic-gate 	if (rflg) {
19397c478bd9Sstevel@tonic-gate 		glob_envp[1] =
194048847494SEnrico Perla - Sun Microsystems 		    malloc((unsigned)(strlen("_DVFS_RECONFIG=YES")+2));
19417c478bd9Sstevel@tonic-gate 		(void) strcpy(glob_envp[1], "_DVFS_RECONFIG=YES");
19427c478bd9Sstevel@tonic-gate 		++glob_envn;
19437c478bd9Sstevel@tonic-gate 	} else if (bflg == 1) {
19447c478bd9Sstevel@tonic-gate 		glob_envp[1] =
194548847494SEnrico Perla - Sun Microsystems 		    malloc((unsigned)(strlen("RB_NOBOOTRC=YES")+2));
19467c478bd9Sstevel@tonic-gate 		(void) strcpy(glob_envp[1], "RB_NOBOOTRC=YES");
19477c478bd9Sstevel@tonic-gate 		++glob_envn;
19487c478bd9Sstevel@tonic-gate 	}
19497c478bd9Sstevel@tonic-gate 
19507c478bd9Sstevel@tonic-gate 	if ((fp = fopen(ENVFILE, "r")) == NULL) {
19517c478bd9Sstevel@tonic-gate 		console(B_TRUE,
19527c478bd9Sstevel@tonic-gate 		    "Cannot open %s. Environment not initialized.\n",
19537c478bd9Sstevel@tonic-gate 		    ENVFILE);
19547c478bd9Sstevel@tonic-gate 	} else {
19557c478bd9Sstevel@tonic-gate 		while (fgets(line, MAXCMDL - 1, fp) != NULL &&
19567c478bd9Sstevel@tonic-gate 		    glob_envn < MAXENVENT - 2) {
19577c478bd9Sstevel@tonic-gate 			/*
19587c478bd9Sstevel@tonic-gate 			 * Toss newline
19597c478bd9Sstevel@tonic-gate 			 */
19607c478bd9Sstevel@tonic-gate 			length = strlen(line);
19617c478bd9Sstevel@tonic-gate 			if (line[length - 1] == '\n')
19627c478bd9Sstevel@tonic-gate 				line[length - 1] = '\0';
19637c478bd9Sstevel@tonic-gate 
19647c478bd9Sstevel@tonic-gate 			/*
19657c478bd9Sstevel@tonic-gate 			 * Ignore blank or comment lines.
19667c478bd9Sstevel@tonic-gate 			 */
19677c478bd9Sstevel@tonic-gate 			if (line[0] == '#' || line[0] == '\0' ||
19687c478bd9Sstevel@tonic-gate 			    (wslength = strspn(line, " \t\n")) ==
19697c478bd9Sstevel@tonic-gate 			    strlen(line) ||
19707c478bd9Sstevel@tonic-gate 			    strchr(line, '#') == line + wslength)
19717c478bd9Sstevel@tonic-gate 				continue;
19727c478bd9Sstevel@tonic-gate 
19737c478bd9Sstevel@tonic-gate 			/*
19747c478bd9Sstevel@tonic-gate 			 * First make a pass through the line and change
19757c478bd9Sstevel@tonic-gate 			 * any non-quoted semi-colons to blanks so they
19767c478bd9Sstevel@tonic-gate 			 * will be treated as token separators below.
19777c478bd9Sstevel@tonic-gate 			 */
19787c478bd9Sstevel@tonic-gate 			inquotes = 0;
19797c478bd9Sstevel@tonic-gate 			for (cp1 = line; *cp1 != '\0'; cp1++) {
19807c478bd9Sstevel@tonic-gate 				if (*cp1 == '"') {
19817c478bd9Sstevel@tonic-gate 					if (inquotes == 0)
19827c478bd9Sstevel@tonic-gate 						inquotes = 1;
19837c478bd9Sstevel@tonic-gate 					else
19847c478bd9Sstevel@tonic-gate 						inquotes = 0;
19857c478bd9Sstevel@tonic-gate 				} else if (*cp1 == ';') {
19867c478bd9Sstevel@tonic-gate 					if (inquotes == 0)
19877c478bd9Sstevel@tonic-gate 						*cp1 = ' ';
19887c478bd9Sstevel@tonic-gate 				}
19897c478bd9Sstevel@tonic-gate 			}
19907c478bd9Sstevel@tonic-gate 
19917c478bd9Sstevel@tonic-gate 			/*
19927c478bd9Sstevel@tonic-gate 			 * Tokens within the line are separated by blanks
19937c478bd9Sstevel@tonic-gate 			 *  and tabs.  For each token in the line which
19947c478bd9Sstevel@tonic-gate 			 * contains a '=' we strip out any quotes and then
19957c478bd9Sstevel@tonic-gate 			 * stick the token in the environment array.
19967c478bd9Sstevel@tonic-gate 			 */
19977c478bd9Sstevel@tonic-gate 			if ((tokp = strtok(line, " \t")) == NULL)
19987c478bd9Sstevel@tonic-gate 				continue;
19997c478bd9Sstevel@tonic-gate 			do {
20007c478bd9Sstevel@tonic-gate 				if (strchr(tokp, '=') == NULL)
20017c478bd9Sstevel@tonic-gate 					continue;
20027c478bd9Sstevel@tonic-gate 				length = strlen(tokp);
20037c478bd9Sstevel@tonic-gate 				while ((cp1 = strpbrk(tokp, "\"\'")) != NULL) {
20047c478bd9Sstevel@tonic-gate 					for (cp2 = cp1;
20057c478bd9Sstevel@tonic-gate 					    cp2 < &tokp[length]; cp2++)
20067c478bd9Sstevel@tonic-gate 						*cp2 = *(cp2 + 1);
20077c478bd9Sstevel@tonic-gate 					length--;
20087c478bd9Sstevel@tonic-gate 				}
20097c478bd9Sstevel@tonic-gate 
20107c478bd9Sstevel@tonic-gate 				if (strncmp(tokp, "CMASK=",
20117c478bd9Sstevel@tonic-gate 				    sizeof ("CMASK=") - 1) == 0) {
20127c478bd9Sstevel@tonic-gate 					long t;
20137c478bd9Sstevel@tonic-gate 
20147c478bd9Sstevel@tonic-gate 					/* We know there's an = */
20157c478bd9Sstevel@tonic-gate 					t = strtol(strchr(tokp, '=') + 1, NULL,
20167c478bd9Sstevel@tonic-gate 					    8);
20177c478bd9Sstevel@tonic-gate 
20187c478bd9Sstevel@tonic-gate 					/* Sanity */
20197c478bd9Sstevel@tonic-gate 					if (t <= 077 && t >= 0)
20207c478bd9Sstevel@tonic-gate 						cmask = (int)t;
20217c478bd9Sstevel@tonic-gate 					(void) umask(cmask);
20227c478bd9Sstevel@tonic-gate 					continue;
20237c478bd9Sstevel@tonic-gate 				}
20247c478bd9Sstevel@tonic-gate 				glob_envp[glob_envn] =
20257c478bd9Sstevel@tonic-gate 				    malloc((unsigned)(length + 1));
20267c478bd9Sstevel@tonic-gate 				(void) strcpy(glob_envp[glob_envn], tokp);
20277c478bd9Sstevel@tonic-gate 				if (++glob_envn >= MAXENVENT - 1)
20287c478bd9Sstevel@tonic-gate 					break;
20297c478bd9Sstevel@tonic-gate 			} while ((tokp = strtok(NULL, " \t")) != NULL);
20307c478bd9Sstevel@tonic-gate 		}
20317c478bd9Sstevel@tonic-gate 
20327c478bd9Sstevel@tonic-gate 		/*
20337c478bd9Sstevel@tonic-gate 		 * Append a null pointer to the environment array
20347c478bd9Sstevel@tonic-gate 		 * to mark its end.
20357c478bd9Sstevel@tonic-gate 		 */
20367c478bd9Sstevel@tonic-gate 		glob_envp[glob_envn] = NULL;
20377c478bd9Sstevel@tonic-gate 		(void) fclose(fp);
20387c478bd9Sstevel@tonic-gate 	}
20397c478bd9Sstevel@tonic-gate }
20407c478bd9Sstevel@tonic-gate 
20417c478bd9Sstevel@tonic-gate /*
20427c478bd9Sstevel@tonic-gate  * boot_init(): Do initialization things that should be done at boot.
20437c478bd9Sstevel@tonic-gate  */
20447c478bd9Sstevel@tonic-gate void
20457c478bd9Sstevel@tonic-gate boot_init()
20467c478bd9Sstevel@tonic-gate {
20477c478bd9Sstevel@tonic-gate 	int i;
20487c478bd9Sstevel@tonic-gate 	struct PROC_TABLE *process, *oprocess;
20497c478bd9Sstevel@tonic-gate 	struct CMD_LINE	cmd;
20507c478bd9Sstevel@tonic-gate 	char	line[MAXCMDL];
20517b209c2cSacruz 	char	svc_aux[SVC_AUX_SIZE];
20527b209c2cSacruz 	char	init_svc_fmri[SVC_FMRI_SIZE];
20537c478bd9Sstevel@tonic-gate 	char *old_path;
20547c478bd9Sstevel@tonic-gate 	int maxfiles;
20557c478bd9Sstevel@tonic-gate 
20567c478bd9Sstevel@tonic-gate 	/* Use INIT_PATH for sysinit cmds */
20577c478bd9Sstevel@tonic-gate 	old_path = glob_envp[0];
20587c478bd9Sstevel@tonic-gate 	glob_envp[0] = malloc((unsigned)(strlen(INIT_PATH)+2));
20597c478bd9Sstevel@tonic-gate 	(void) strcpy(glob_envp[0], INIT_PATH);
20607c478bd9Sstevel@tonic-gate 
20617c478bd9Sstevel@tonic-gate 	/*
20627c478bd9Sstevel@tonic-gate 	 * Scan inittab(4) and process the special svc.startd entry, initdefault
20637c478bd9Sstevel@tonic-gate 	 * and sysinit entries.
20647c478bd9Sstevel@tonic-gate 	 */
20657c478bd9Sstevel@tonic-gate 	while (getcmd(&cmd, &line[0]) == TRUE) {
20667b209c2cSacruz 		if (startd_tmpl >= 0 && id_eq(cmd.c_id, "smf")) {
20677c478bd9Sstevel@tonic-gate 			process_startd_line(&cmd, line);
20687b209c2cSacruz 			(void) snprintf(startd_svc_aux, SVC_AUX_SIZE,
20697b209c2cSacruz 			    INITTAB_ENTRY_ID_STR_FORMAT, cmd.c_id);
20707b209c2cSacruz 		} else if (cmd.c_action == M_INITDEFAULT) {
20717c478bd9Sstevel@tonic-gate 			/*
20727c478bd9Sstevel@tonic-gate 			 * initdefault is no longer meaningful, as the SMF
20737c478bd9Sstevel@tonic-gate 			 * milestone controls what (legacy) run level we
20747c478bd9Sstevel@tonic-gate 			 * boot to.
20757c478bd9Sstevel@tonic-gate 			 */
20767c478bd9Sstevel@tonic-gate 			console(B_TRUE,
20777c478bd9Sstevel@tonic-gate 			    "Ignoring legacy \"initdefault\" entry.\n");
20787c478bd9Sstevel@tonic-gate 		} else if (cmd.c_action == M_SYSINIT) {
20797c478bd9Sstevel@tonic-gate 			/*
20807c478bd9Sstevel@tonic-gate 			 * Execute the "sysinit" entry and wait for it to
20817c478bd9Sstevel@tonic-gate 			 * complete.  No bookkeeping is performed on these
20827c478bd9Sstevel@tonic-gate 			 * entries because we avoid writing to the file system
20837c478bd9Sstevel@tonic-gate 			 * until after there has been an chance to check it.
20847c478bd9Sstevel@tonic-gate 			 */
20857c478bd9Sstevel@tonic-gate 			if (process = findpslot(&cmd)) {
2086c39ec064SRoger A. Faulkner 				(void) sighold(SIGCLD);
20877b209c2cSacruz 				(void) snprintf(svc_aux, SVC_AUX_SIZE,
20887b209c2cSacruz 				    INITTAB_ENTRY_ID_STR_FORMAT, cmd.c_id);
20897b209c2cSacruz 				(void) snprintf(init_svc_fmri, SVC_FMRI_SIZE,
20907b209c2cSacruz 				    SVC_INIT_PREFIX INITTAB_ENTRY_ID_STR_FORMAT,
20917b209c2cSacruz 				    cmd.c_id);
20927b209c2cSacruz 				if (legacy_tmpl >= 0) {
20937b209c2cSacruz 					(void) ct_pr_tmpl_set_svc_fmri(
20947b209c2cSacruz 					    legacy_tmpl, init_svc_fmri);
20957b209c2cSacruz 					(void) ct_pr_tmpl_set_svc_aux(
20967b209c2cSacruz 					    legacy_tmpl, svc_aux);
20977b209c2cSacruz 				}
20987c478bd9Sstevel@tonic-gate 
20997c478bd9Sstevel@tonic-gate 				for (oprocess = process;
21007c478bd9Sstevel@tonic-gate 				    (process = efork(M_OFF, oprocess,
21017c478bd9Sstevel@tonic-gate 				    (NAMED|NOCLEANUP))) == NO_ROOM;
21027c478bd9Sstevel@tonic-gate 				    /* CSTYLED */)
21037c478bd9Sstevel@tonic-gate 					;
2104c39ec064SRoger A. Faulkner 				(void) sigrelse(SIGCLD);
21057c478bd9Sstevel@tonic-gate 
21067c478bd9Sstevel@tonic-gate 				if (process == NULLPROC) {
21077c478bd9Sstevel@tonic-gate 					maxfiles = ulimit(UL_GDESLIM, 0);
21087c478bd9Sstevel@tonic-gate 
21097c478bd9Sstevel@tonic-gate 					for (i = 0; i < maxfiles; i++)
21107c478bd9Sstevel@tonic-gate 						(void) fcntl(i, F_SETFD,
21117c478bd9Sstevel@tonic-gate 						    FD_CLOEXEC);
21127c478bd9Sstevel@tonic-gate 					(void) execle(SH, "INITSH", "-c",
21137c478bd9Sstevel@tonic-gate 					    cmd.c_command,
21147c478bd9Sstevel@tonic-gate 					    (char *)0, glob_envp);
21157c478bd9Sstevel@tonic-gate 					console(B_TRUE,
21167c478bd9Sstevel@tonic-gate "Command\n\"%s\"\n failed to execute.  errno = %d (exec of shell failed)\n",
211748847494SEnrico Perla - Sun Microsystems 					    cmd.c_command, errno);
21187c478bd9Sstevel@tonic-gate 					exit(1);
21190a1278f2SGary Mills 				} else
21200a1278f2SGary Mills 					while (waitproc(process) == FAILURE)
21210a1278f2SGary Mills 						;
21227c478bd9Sstevel@tonic-gate 				process->p_flags = 0;
21237c478bd9Sstevel@tonic-gate 				st_write();
21247c478bd9Sstevel@tonic-gate 			}
21257c478bd9Sstevel@tonic-gate 		}
21267c478bd9Sstevel@tonic-gate 	}
21277c478bd9Sstevel@tonic-gate 
21287c478bd9Sstevel@tonic-gate 	/* Restore the path. */
21297c478bd9Sstevel@tonic-gate 	free(glob_envp[0]);
21307c478bd9Sstevel@tonic-gate 	glob_envp[0] = old_path;
21317c478bd9Sstevel@tonic-gate 
21327c478bd9Sstevel@tonic-gate 	/*
21337c478bd9Sstevel@tonic-gate 	 * This will enable st_write() to complain about init_state_file.
21347c478bd9Sstevel@tonic-gate 	 */
21357c478bd9Sstevel@tonic-gate 	booting = 0;
21367c478bd9Sstevel@tonic-gate 
21377c478bd9Sstevel@tonic-gate 	/*
21387c478bd9Sstevel@tonic-gate 	 * If the /etc/ioctl.syscon didn't exist or had invalid contents write
21397c478bd9Sstevel@tonic-gate 	 * out a correct version.
21407c478bd9Sstevel@tonic-gate 	 */
21417c478bd9Sstevel@tonic-gate 	if (write_ioctl)
21427c478bd9Sstevel@tonic-gate 		write_ioctl_syscon();
21437c478bd9Sstevel@tonic-gate 
21447c478bd9Sstevel@tonic-gate 	/*
21457c478bd9Sstevel@tonic-gate 	 * Start svc.startd(1M), which does most of the work.
21467c478bd9Sstevel@tonic-gate 	 */
21477c478bd9Sstevel@tonic-gate 	if (startd_cline[0] != '\0' && startd_tmpl >= 0) {
21487c478bd9Sstevel@tonic-gate 		/* Start svc.startd. */
21497c478bd9Sstevel@tonic-gate 		if (startd_run(startd_cline, startd_tmpl, 0) == -1)
21507c478bd9Sstevel@tonic-gate 			cur_state = SINGLE_USER;
21517c478bd9Sstevel@tonic-gate 	} else {
21527c478bd9Sstevel@tonic-gate 		console(B_TRUE, "Absent svc.startd entry or bad "
21537c478bd9Sstevel@tonic-gate 		    "contract template.  Not starting svc.startd.\n");
21547c478bd9Sstevel@tonic-gate 		enter_maintenance();
21557c478bd9Sstevel@tonic-gate 	}
21567c478bd9Sstevel@tonic-gate }
21577c478bd9Sstevel@tonic-gate 
21587c478bd9Sstevel@tonic-gate /*
21597c478bd9Sstevel@tonic-gate  * init_signals(): Initialize all signals to either be caught or ignored.
21607c478bd9Sstevel@tonic-gate  */
21617c478bd9Sstevel@tonic-gate void
21627c478bd9Sstevel@tonic-gate init_signals(void)
21637c478bd9Sstevel@tonic-gate {
21647c478bd9Sstevel@tonic-gate 	struct sigaction act;
21657c478bd9Sstevel@tonic-gate 	int i;
21667c478bd9Sstevel@tonic-gate 
21677c478bd9Sstevel@tonic-gate 	/*
21687c478bd9Sstevel@tonic-gate 	 * Start by ignoring all signals, then selectively re-enable some.
21697c478bd9Sstevel@tonic-gate 	 * The SIG_IGN disposition will only affect asynchronous signals:
21707c478bd9Sstevel@tonic-gate 	 * any signal that we trigger synchronously that doesn't end up
21717c478bd9Sstevel@tonic-gate 	 * being handled by siglvl() will be forcibly delivered by the kernel.
21727c478bd9Sstevel@tonic-gate 	 */
21737c478bd9Sstevel@tonic-gate 	for (i = SIGHUP; i <= SIGRTMAX; i++)
21747c478bd9Sstevel@tonic-gate 		(void) sigset(i, SIG_IGN);
21757c478bd9Sstevel@tonic-gate 
21767c478bd9Sstevel@tonic-gate 	/*
21777c478bd9Sstevel@tonic-gate 	 * Handle all level-changing signals using siglvl() and set sa_mask so
21787c478bd9Sstevel@tonic-gate 	 * that all level-changing signals are blocked while in siglvl().
21797c478bd9Sstevel@tonic-gate 	 */
21807c478bd9Sstevel@tonic-gate 	act.sa_handler = siglvl;
21817c478bd9Sstevel@tonic-gate 	act.sa_flags = SA_SIGINFO;
21827c478bd9Sstevel@tonic-gate 	(void) sigemptyset(&act.sa_mask);
21837c478bd9Sstevel@tonic-gate 
21847c478bd9Sstevel@tonic-gate 	(void) sigaddset(&act.sa_mask, LVLQ);
21857c478bd9Sstevel@tonic-gate 	(void) sigaddset(&act.sa_mask, LVL0);
21867c478bd9Sstevel@tonic-gate 	(void) sigaddset(&act.sa_mask, LVL1);
21877c478bd9Sstevel@tonic-gate 	(void) sigaddset(&act.sa_mask, LVL2);
21887c478bd9Sstevel@tonic-gate 	(void) sigaddset(&act.sa_mask, LVL3);
21897c478bd9Sstevel@tonic-gate 	(void) sigaddset(&act.sa_mask, LVL4);
21907c478bd9Sstevel@tonic-gate 	(void) sigaddset(&act.sa_mask, LVL5);
21917c478bd9Sstevel@tonic-gate 	(void) sigaddset(&act.sa_mask, LVL6);
21927c478bd9Sstevel@tonic-gate 	(void) sigaddset(&act.sa_mask, SINGLE_USER);
21937c478bd9Sstevel@tonic-gate 	(void) sigaddset(&act.sa_mask, LVLa);
21947c478bd9Sstevel@tonic-gate 	(void) sigaddset(&act.sa_mask, LVLb);
21957c478bd9Sstevel@tonic-gate 	(void) sigaddset(&act.sa_mask, LVLc);
21967c478bd9Sstevel@tonic-gate 
21977c478bd9Sstevel@tonic-gate 	(void) sigaction(LVLQ, &act, NULL);
21987c478bd9Sstevel@tonic-gate 	(void) sigaction(LVL0, &act, NULL);
21997c478bd9Sstevel@tonic-gate 	(void) sigaction(LVL1, &act, NULL);
22007c478bd9Sstevel@tonic-gate 	(void) sigaction(LVL2, &act, NULL);
22017c478bd9Sstevel@tonic-gate 	(void) sigaction(LVL3, &act, NULL);
22027c478bd9Sstevel@tonic-gate 	(void) sigaction(LVL4, &act, NULL);
22037c478bd9Sstevel@tonic-gate 	(void) sigaction(LVL5, &act, NULL);
22047c478bd9Sstevel@tonic-gate 	(void) sigaction(LVL6, &act, NULL);
22057c478bd9Sstevel@tonic-gate 	(void) sigaction(SINGLE_USER, &act, NULL);
22067c478bd9Sstevel@tonic-gate 	(void) sigaction(LVLa, &act, NULL);
22077c478bd9Sstevel@tonic-gate 	(void) sigaction(LVLb, &act, NULL);
22087c478bd9Sstevel@tonic-gate 	(void) sigaction(LVLc, &act, NULL);
22097c478bd9Sstevel@tonic-gate 
22107c478bd9Sstevel@tonic-gate 	(void) sigset(SIGALRM, alarmclk);
22117c478bd9Sstevel@tonic-gate 	alarmclk();
22127c478bd9Sstevel@tonic-gate 
22137c478bd9Sstevel@tonic-gate 	(void) sigset(SIGCLD, childeath);
22147c478bd9Sstevel@tonic-gate 	(void) sigset(SIGPWR, powerfail);
22157c478bd9Sstevel@tonic-gate }
22167c478bd9Sstevel@tonic-gate 
22177c478bd9Sstevel@tonic-gate /*
22187c478bd9Sstevel@tonic-gate  * Set up pipe for "godchildren". If the file exists and is a pipe just open
22197c478bd9Sstevel@tonic-gate  * it. Else, if the file system is r/w create it.  Otherwise, defer its
222092ba7109Seschrock  * creation and open until after /var/run has been mounted.  This function is
222192ba7109Seschrock  * only called on startup and when explicitly requested via LVLQ.
22227c478bd9Sstevel@tonic-gate  */
22237c478bd9Sstevel@tonic-gate void
22247c478bd9Sstevel@tonic-gate setup_pipe()
22257c478bd9Sstevel@tonic-gate {
22267c478bd9Sstevel@tonic-gate 	struct stat stat_buf;
22277c478bd9Sstevel@tonic-gate 	struct statvfs statvfs_buf;
2228dd965b2fSnakanon 	struct sigaction act;
22297c478bd9Sstevel@tonic-gate 
223092ba7109Seschrock 	/*
223192ba7109Seschrock 	 * Always close the previous pipe descriptor as the mounted filesystems
223292ba7109Seschrock 	 * may have changed.
223392ba7109Seschrock 	 */
223492ba7109Seschrock 	if (Pfd >= 0)
223592ba7109Seschrock 		(void) close(Pfd);
223692ba7109Seschrock 
22377c478bd9Sstevel@tonic-gate 	if ((stat(INITPIPE, &stat_buf) == 0) &&
22387c478bd9Sstevel@tonic-gate 	    ((stat_buf.st_mode & (S_IFMT|S_IRUSR)) == (S_IFIFO|S_IRUSR)))
22397c478bd9Sstevel@tonic-gate 		Pfd = open(INITPIPE, O_RDWR | O_NDELAY);
22407c478bd9Sstevel@tonic-gate 	else
22417c478bd9Sstevel@tonic-gate 		if ((statvfs(INITPIPE_DIR, &statvfs_buf) == 0) &&
22427c478bd9Sstevel@tonic-gate 		    ((statvfs_buf.f_flag & ST_RDONLY) == 0)) {
22437c478bd9Sstevel@tonic-gate 			(void) unlink(INITPIPE);
22447c478bd9Sstevel@tonic-gate 			(void) mknod(INITPIPE, S_IFIFO | 0600, 0);
22457c478bd9Sstevel@tonic-gate 			Pfd = open(INITPIPE, O_RDWR | O_NDELAY);
22467c478bd9Sstevel@tonic-gate 		}
22477c478bd9Sstevel@tonic-gate 
22487c478bd9Sstevel@tonic-gate 	if (Pfd >= 0) {
22497c478bd9Sstevel@tonic-gate 		(void) ioctl(Pfd, I_SETSIG, S_INPUT);
22507c478bd9Sstevel@tonic-gate 		/*
22517c478bd9Sstevel@tonic-gate 		 * Read pipe in message discard mode.
22527c478bd9Sstevel@tonic-gate 		 */
22537c478bd9Sstevel@tonic-gate 		(void) ioctl(Pfd, I_SRDOPT, RMSGD);
2254dd965b2fSnakanon 
2255dd965b2fSnakanon 		act.sa_handler = sigpoll;
2256dd965b2fSnakanon 		act.sa_flags = 0;
2257dd965b2fSnakanon 		(void) sigemptyset(&act.sa_mask);
2258dd965b2fSnakanon 		(void) sigaddset(&act.sa_mask, SIGCLD);
2259dd965b2fSnakanon 		(void) sigaction(SIGPOLL, &act, NULL);
22607c478bd9Sstevel@tonic-gate 	}
22617c478bd9Sstevel@tonic-gate }
22627c478bd9Sstevel@tonic-gate 
22637c478bd9Sstevel@tonic-gate /*
22647c478bd9Sstevel@tonic-gate  * siglvl - handle an asynchronous signal from init(1M) telling us that we
22657c478bd9Sstevel@tonic-gate  * should change the current run level.  We set new_state accordingly.
22667c478bd9Sstevel@tonic-gate  */
22677c478bd9Sstevel@tonic-gate void
22687c478bd9Sstevel@tonic-gate siglvl(int sig, siginfo_t *sip, ucontext_t *ucp)
22697c478bd9Sstevel@tonic-gate {
22707c478bd9Sstevel@tonic-gate 	struct PROC_TABLE *process;
22717c478bd9Sstevel@tonic-gate 	struct sigaction act;
22727c478bd9Sstevel@tonic-gate 
22737c478bd9Sstevel@tonic-gate 	/*
22747c478bd9Sstevel@tonic-gate 	 * If the signal was from the kernel (rather than init(1M)) then init
22757c478bd9Sstevel@tonic-gate 	 * itself tripped the signal.  That is, we might have a bug and tripped
22767c478bd9Sstevel@tonic-gate 	 * a real SIGSEGV instead of receiving it as an alias for SIGLVLa.  In
22777c478bd9Sstevel@tonic-gate 	 * such a case we reset the disposition to SIG_DFL, block all signals
22787c478bd9Sstevel@tonic-gate 	 * in uc_mask but the current one, and return to the interrupted ucp
22797c478bd9Sstevel@tonic-gate 	 * to effect an appropriate death.  The kernel will then restart us.
22807c478bd9Sstevel@tonic-gate 	 *
22817c478bd9Sstevel@tonic-gate 	 * The one exception to SI_FROMKERNEL() is SIGFPE (a.k.a. LVL6), which
22827c478bd9Sstevel@tonic-gate 	 * the kernel can send us when it wants to effect an orderly reboot.
22837c478bd9Sstevel@tonic-gate 	 * For this case we must also verify si_code is zero, rather than a
22847c478bd9Sstevel@tonic-gate 	 * code such as FPE_INTDIV which a bug might have triggered.
22857c478bd9Sstevel@tonic-gate 	 */
22867c478bd9Sstevel@tonic-gate 	if (sip != NULL && SI_FROMKERNEL(sip) &&
22877c478bd9Sstevel@tonic-gate 	    (sig != SIGFPE || sip->si_code == 0)) {
22887c478bd9Sstevel@tonic-gate 
22897c478bd9Sstevel@tonic-gate 		(void) sigemptyset(&act.sa_mask);
22907c478bd9Sstevel@tonic-gate 		act.sa_handler = SIG_DFL;
22917c478bd9Sstevel@tonic-gate 		act.sa_flags = 0;
22927c478bd9Sstevel@tonic-gate 		(void) sigaction(sig, &act, NULL);
22937c478bd9Sstevel@tonic-gate 
22947c478bd9Sstevel@tonic-gate 		(void) sigfillset(&ucp->uc_sigmask);
22957c478bd9Sstevel@tonic-gate 		(void) sigdelset(&ucp->uc_sigmask, sig);
22967c478bd9Sstevel@tonic-gate 		ucp->uc_flags |= UC_SIGMASK;
22977c478bd9Sstevel@tonic-gate 
22987c478bd9Sstevel@tonic-gate 		(void) setcontext(ucp);
22997c478bd9Sstevel@tonic-gate 	}
23007c478bd9Sstevel@tonic-gate 
23017c478bd9Sstevel@tonic-gate 	/*
23027c478bd9Sstevel@tonic-gate 	 * If the signal received is a LVLQ signal, do not really
23037c478bd9Sstevel@tonic-gate 	 * change levels, just restate the current level.  If the
23047c478bd9Sstevel@tonic-gate 	 * signal is not a LVLQ, set the new level to the signal
23057c478bd9Sstevel@tonic-gate 	 * received.
23067c478bd9Sstevel@tonic-gate 	 */
230792ba7109Seschrock 	if (sig == LVLQ) {
23087c478bd9Sstevel@tonic-gate 		new_state = cur_state;
230992ba7109Seschrock 		lvlq_received = B_TRUE;
231092ba7109Seschrock 	} else {
23117c478bd9Sstevel@tonic-gate 		new_state = sig;
231292ba7109Seschrock 	}
23137c478bd9Sstevel@tonic-gate 
23147c478bd9Sstevel@tonic-gate 	/*
23157c478bd9Sstevel@tonic-gate 	 * Clear all times and repeat counts in the process table
23167c478bd9Sstevel@tonic-gate 	 * since either the level is changing or the user has editted
23177c478bd9Sstevel@tonic-gate 	 * the inittab file and wants us to look at it again.
23187c478bd9Sstevel@tonic-gate 	 * If the user has fixed a typo, we don't want residual timing
23197c478bd9Sstevel@tonic-gate 	 * data preventing the fixed command line from executing.
23207c478bd9Sstevel@tonic-gate 	 */
23217c478bd9Sstevel@tonic-gate 	for (process = proc_table;
232248847494SEnrico Perla - Sun Microsystems 	    (process < proc_table + num_proc); process++) {
23237c478bd9Sstevel@tonic-gate 		process->p_time = 0L;
23247c478bd9Sstevel@tonic-gate 		process->p_count = 0;
23257c478bd9Sstevel@tonic-gate 	}
23267c478bd9Sstevel@tonic-gate 
23277c478bd9Sstevel@tonic-gate 	/*
23287c478bd9Sstevel@tonic-gate 	 * Set the flag to indicate that a "user signal" was received.
23297c478bd9Sstevel@tonic-gate 	 */
23307c478bd9Sstevel@tonic-gate 	wakeup.w_flags.w_usersignal = 1;
23317c478bd9Sstevel@tonic-gate }
23327c478bd9Sstevel@tonic-gate 
23337c478bd9Sstevel@tonic-gate 
23347c478bd9Sstevel@tonic-gate /*
23357c478bd9Sstevel@tonic-gate  * alarmclk
23367c478bd9Sstevel@tonic-gate  */
23377c478bd9Sstevel@tonic-gate static void
23387c478bd9Sstevel@tonic-gate alarmclk()
23397c478bd9Sstevel@tonic-gate {
23407c478bd9Sstevel@tonic-gate 	time_up = TRUE;
23417c478bd9Sstevel@tonic-gate }
23427c478bd9Sstevel@tonic-gate 
23437c478bd9Sstevel@tonic-gate /*
23447c478bd9Sstevel@tonic-gate  * childeath_single():
23457c478bd9Sstevel@tonic-gate  *
23467c478bd9Sstevel@tonic-gate  * This used to be the SIGCLD handler and it was set with signal()
23477c478bd9Sstevel@tonic-gate  * (as opposed to sigset()).  When a child exited we'd come to the
23487c478bd9Sstevel@tonic-gate  * handler, wait for the child, and reenable the handler with
23497c478bd9Sstevel@tonic-gate  * signal() just before returning.  The implementation of signal()
23507c478bd9Sstevel@tonic-gate  * checks with waitid() for waitable children and sends a SIGCLD
23517c478bd9Sstevel@tonic-gate  * if there are some.  If children are exiting faster than the
23527c478bd9Sstevel@tonic-gate  * handler can run we keep sending signals and the handler never
23537c478bd9Sstevel@tonic-gate  * gets to return and eventually the stack runs out and init dies.
23547c478bd9Sstevel@tonic-gate  * To prevent that we set the handler with sigset() so the handler
23557c478bd9Sstevel@tonic-gate  * doesn't need to be reset, and in childeath() (see below) we
23567c478bd9Sstevel@tonic-gate  * call childeath_single() as long as there are children to be
23577c478bd9Sstevel@tonic-gate  * waited for.  If a child exits while init is in the handler a
23587c478bd9Sstevel@tonic-gate  * SIGCLD will be pending and delivered on return from the handler.
23597c478bd9Sstevel@tonic-gate  * If the child was already waited for the handler will have nothing
23607c478bd9Sstevel@tonic-gate  * to do and return, otherwise the child will be waited for.
23617c478bd9Sstevel@tonic-gate  */
23627c478bd9Sstevel@tonic-gate static void
2363c39ec064SRoger A. Faulkner childeath_single(pid_t pid, int status)
23647c478bd9Sstevel@tonic-gate {
23657c478bd9Sstevel@tonic-gate 	struct PROC_TABLE	*process;
23667c478bd9Sstevel@tonic-gate 	struct pidlist		*pp;
23677c478bd9Sstevel@tonic-gate 
23687c478bd9Sstevel@tonic-gate 	/*
2369c39ec064SRoger A. Faulkner 	 * Scan the process table to see if we are interested in this process.
23707c478bd9Sstevel@tonic-gate 	 */
23717c478bd9Sstevel@tonic-gate 	for (process = proc_table;
237248847494SEnrico Perla - Sun Microsystems 	    (process < proc_table + num_proc); process++) {
23737c478bd9Sstevel@tonic-gate 		if ((process->p_flags & (LIVING|OCCUPIED)) ==
23747c478bd9Sstevel@tonic-gate 		    (LIVING|OCCUPIED) && process->p_pid == pid) {
23757c478bd9Sstevel@tonic-gate 
23767c478bd9Sstevel@tonic-gate 			/*
23777c478bd9Sstevel@tonic-gate 			 * Mark this process as having died and store the exit
23787c478bd9Sstevel@tonic-gate 			 * status.  Also set the wakeup flag for a dead child
23797c478bd9Sstevel@tonic-gate 			 * and break out of the loop.
23807c478bd9Sstevel@tonic-gate 			 */
23817c478bd9Sstevel@tonic-gate 			process->p_flags &= ~LIVING;
23827c478bd9Sstevel@tonic-gate 			process->p_exit = (short)status;
23837c478bd9Sstevel@tonic-gate 			wakeup.w_flags.w_childdeath = 1;
23847c478bd9Sstevel@tonic-gate 
23857c478bd9Sstevel@tonic-gate 			return;
23867c478bd9Sstevel@tonic-gate 		}
23877c478bd9Sstevel@tonic-gate 	}
23887c478bd9Sstevel@tonic-gate 
23897c478bd9Sstevel@tonic-gate 	/*
23907c478bd9Sstevel@tonic-gate 	 * No process was found above, look through auxiliary list.
23917c478bd9Sstevel@tonic-gate 	 */
23927c478bd9Sstevel@tonic-gate 	(void) sighold(SIGPOLL);
23937c478bd9Sstevel@tonic-gate 	pp = Plhead;
23947c478bd9Sstevel@tonic-gate 	while (pp) {
23957c478bd9Sstevel@tonic-gate 		if (pid > pp->pl_pid) {
23967c478bd9Sstevel@tonic-gate 			/*
23977c478bd9Sstevel@tonic-gate 			 * Keep on looking.
23987c478bd9Sstevel@tonic-gate 			 */
23997c478bd9Sstevel@tonic-gate 			pp = pp->pl_next;
24007c478bd9Sstevel@tonic-gate 			continue;
24017c478bd9Sstevel@tonic-gate 		} else if (pid < pp->pl_pid) {
24027c478bd9Sstevel@tonic-gate 			/*
24037c478bd9Sstevel@tonic-gate 			 * Not in the list.
24047c478bd9Sstevel@tonic-gate 			 */
24057c478bd9Sstevel@tonic-gate 			break;
24067c478bd9Sstevel@tonic-gate 		} else {
24077c478bd9Sstevel@tonic-gate 			/*
24087c478bd9Sstevel@tonic-gate 			 * This is a dead "godchild".
24097c478bd9Sstevel@tonic-gate 			 */
24107c478bd9Sstevel@tonic-gate 			pp->pl_dflag = 1;
24117c478bd9Sstevel@tonic-gate 			pp->pl_exit = (short)status;
24127c478bd9Sstevel@tonic-gate 			wakeup.w_flags.w_childdeath = 1;
24137c478bd9Sstevel@tonic-gate 			Gchild = 1;	/* Notice to call cleanaux(). */
24147c478bd9Sstevel@tonic-gate 			break;
24157c478bd9Sstevel@tonic-gate 		}
24167c478bd9Sstevel@tonic-gate 	}
24177c478bd9Sstevel@tonic-gate 
24187c478bd9Sstevel@tonic-gate 	(void) sigrelse(SIGPOLL);
24197c478bd9Sstevel@tonic-gate }
24207c478bd9Sstevel@tonic-gate 
24217c478bd9Sstevel@tonic-gate /* ARGSUSED */
24227c478bd9Sstevel@tonic-gate static void
24237c478bd9Sstevel@tonic-gate childeath(int signo)
24247c478bd9Sstevel@tonic-gate {
2425c39ec064SRoger A. Faulkner 	pid_t pid;
2426c39ec064SRoger A. Faulkner 	int status;
24277c478bd9Sstevel@tonic-gate 
2428c39ec064SRoger A. Faulkner 	while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
2429c39ec064SRoger A. Faulkner 		childeath_single(pid, status);
24307c478bd9Sstevel@tonic-gate }
24317c478bd9Sstevel@tonic-gate 
24327c478bd9Sstevel@tonic-gate static void
24337c478bd9Sstevel@tonic-gate powerfail()
24347c478bd9Sstevel@tonic-gate {
24357c478bd9Sstevel@tonic-gate 	(void) nice(-19);
24367c478bd9Sstevel@tonic-gate 	wakeup.w_flags.w_powerhit = 1;
24377c478bd9Sstevel@tonic-gate }
24387c478bd9Sstevel@tonic-gate 
24397c478bd9Sstevel@tonic-gate /*
24407c478bd9Sstevel@tonic-gate  * efork() forks a child and the parent inserts the process in its table
24417c478bd9Sstevel@tonic-gate  * of processes that are directly a result of forks that it has performed.
24427c478bd9Sstevel@tonic-gate  * The child just changes the "global" with the process id for this process
24437c478bd9Sstevel@tonic-gate  * to it's new value.
24447c478bd9Sstevel@tonic-gate  * If efork() is called with a pointer into the proc_table it uses that slot,
24457c478bd9Sstevel@tonic-gate  * otherwise it searches for a free slot.  Regardless of how it was called,
24467c478bd9Sstevel@tonic-gate  * it returns the pointer to the proc_table entry
24477c478bd9Sstevel@tonic-gate  *
2448c39ec064SRoger A. Faulkner  * The SIGCLD signal is blocked (held) before calling efork()
2449c39ec064SRoger A. Faulkner  * and is unblocked (released) after efork() returns.
24507c478bd9Sstevel@tonic-gate  *
24517c478bd9Sstevel@tonic-gate  * Ideally, this should be rewritten to use modern signal semantics.
24527c478bd9Sstevel@tonic-gate  */
24537c478bd9Sstevel@tonic-gate static struct PROC_TABLE *
24547c478bd9Sstevel@tonic-gate efork(int action, struct PROC_TABLE *process, int modes)
24557c478bd9Sstevel@tonic-gate {
24567c478bd9Sstevel@tonic-gate 	pid_t	childpid;
24577c478bd9Sstevel@tonic-gate 	struct PROC_TABLE *proc;
24587c478bd9Sstevel@tonic-gate 	int		i;
24597c478bd9Sstevel@tonic-gate 	/*
24607c478bd9Sstevel@tonic-gate 	 * Freshen up the proc_table, removing any entries for dead processes
24617c478bd9Sstevel@tonic-gate 	 * that don't have NOCLEANUP set.  Perform the necessary accounting.
24627c478bd9Sstevel@tonic-gate 	 */
24637c478bd9Sstevel@tonic-gate 	for (proc = proc_table; (proc < proc_table + num_proc); proc++) {
24647c478bd9Sstevel@tonic-gate 		if ((proc->p_flags & (OCCUPIED|LIVING|NOCLEANUP)) ==
24657c478bd9Sstevel@tonic-gate 		    (OCCUPIED)) {
24667c478bd9Sstevel@tonic-gate 			/*
24677c478bd9Sstevel@tonic-gate 			 * Is this a named process?
24687c478bd9Sstevel@tonic-gate 			 * If so, do the necessary bookkeeping.
24697c478bd9Sstevel@tonic-gate 			 */
24707c478bd9Sstevel@tonic-gate 			if (proc->p_flags & NAMED)
24717c478bd9Sstevel@tonic-gate 				(void) account(DEAD_PROCESS, proc, NULL);
24727c478bd9Sstevel@tonic-gate 
24737c478bd9Sstevel@tonic-gate 			/*
24747c478bd9Sstevel@tonic-gate 			 * Free this entry for new usage.
24757c478bd9Sstevel@tonic-gate 			 */
24767c478bd9Sstevel@tonic-gate 			proc->p_flags = 0;
24777c478bd9Sstevel@tonic-gate 		}
24787c478bd9Sstevel@tonic-gate 	}
24797c478bd9Sstevel@tonic-gate 
24807c478bd9Sstevel@tonic-gate 	while ((childpid = fork()) == FAILURE) {
24817c478bd9Sstevel@tonic-gate 		/*
24827c478bd9Sstevel@tonic-gate 		 * Shorten the alarm timer in case someone else's child dies
24837c478bd9Sstevel@tonic-gate 		 * and free up a slot in the process table.
24847c478bd9Sstevel@tonic-gate 		 */
24857c478bd9Sstevel@tonic-gate 		setimer(5);
24867c478bd9Sstevel@tonic-gate 
24877c478bd9Sstevel@tonic-gate 		/*
2488c39ec064SRoger A. Faulkner 		 * Wait for some children to die.  Since efork()
2489c39ec064SRoger A. Faulkner 		 * is always called with SIGCLD blocked, unblock
2490c39ec064SRoger A. Faulkner 		 * it here so that child death signals can come in.
24917c478bd9Sstevel@tonic-gate 		 */
2492c39ec064SRoger A. Faulkner 		(void) sigrelse(SIGCLD);
24937c478bd9Sstevel@tonic-gate 		(void) pause();
2494c39ec064SRoger A. Faulkner 		(void) sighold(SIGCLD);
24957c478bd9Sstevel@tonic-gate 		setimer(0);
24967c478bd9Sstevel@tonic-gate 	}
24977c478bd9Sstevel@tonic-gate 
24987c478bd9Sstevel@tonic-gate 	if (childpid != 0) {
24997c478bd9Sstevel@tonic-gate 
25007c478bd9Sstevel@tonic-gate 		if (process == NULLPROC) {
25017c478bd9Sstevel@tonic-gate 			/*
25027c478bd9Sstevel@tonic-gate 			 * No proc table pointer specified so search
25037c478bd9Sstevel@tonic-gate 			 * for a free slot.
25047c478bd9Sstevel@tonic-gate 			 */
25057c478bd9Sstevel@tonic-gate 			for (process = proc_table;  process->p_flags != 0 &&
250648847494SEnrico Perla - Sun Microsystems 			    (process < proc_table + num_proc); process++)
25077c478bd9Sstevel@tonic-gate 					;
25087c478bd9Sstevel@tonic-gate 
25097c478bd9Sstevel@tonic-gate 			if (process == (proc_table + num_proc)) {
25107c478bd9Sstevel@tonic-gate 				int old_proc_table_size = num_proc;
25117c478bd9Sstevel@tonic-gate 
25127c478bd9Sstevel@tonic-gate 				/* Increase the process table size */
25137c478bd9Sstevel@tonic-gate 				increase_proc_table_size();
25147c478bd9Sstevel@tonic-gate 				if (old_proc_table_size == num_proc) {
25157c478bd9Sstevel@tonic-gate 					/* didn't grow: memory failure */
25167c478bd9Sstevel@tonic-gate 					return (NO_ROOM);
25177c478bd9Sstevel@tonic-gate 				} else {
25187c478bd9Sstevel@tonic-gate 					process =
25197c478bd9Sstevel@tonic-gate 					    proc_table + old_proc_table_size;
25207c478bd9Sstevel@tonic-gate 				}
25217c478bd9Sstevel@tonic-gate 			}
25227c478bd9Sstevel@tonic-gate 
25237c478bd9Sstevel@tonic-gate 			process->p_time = 0L;
25247c478bd9Sstevel@tonic-gate 			process->p_count = 0;
25257c478bd9Sstevel@tonic-gate 		}
25267c478bd9Sstevel@tonic-gate 		process->p_id[0] = '\0';
25277c478bd9Sstevel@tonic-gate 		process->p_id[1] = '\0';
25287c478bd9Sstevel@tonic-gate 		process->p_id[2] = '\0';
25297c478bd9Sstevel@tonic-gate 		process->p_id[3] = '\0';
25307c478bd9Sstevel@tonic-gate 		process->p_pid = childpid;
25317c478bd9Sstevel@tonic-gate 		process->p_flags = (LIVING | OCCUPIED | modes);
25327c478bd9Sstevel@tonic-gate 		process->p_exit = 0;
25337c478bd9Sstevel@tonic-gate 
25347c478bd9Sstevel@tonic-gate 		st_write();
25357c478bd9Sstevel@tonic-gate 	} else {
25367c478bd9Sstevel@tonic-gate 		if ((action & (M_WAIT | M_BOOTWAIT)) == 0)
25377c478bd9Sstevel@tonic-gate 			(void) setpgrp();
25387c478bd9Sstevel@tonic-gate 
25397c478bd9Sstevel@tonic-gate 		process = NULLPROC;
25407c478bd9Sstevel@tonic-gate 
25417c478bd9Sstevel@tonic-gate 		/*
25427c478bd9Sstevel@tonic-gate 		 * Reset all signals to the system defaults.
25437c478bd9Sstevel@tonic-gate 		 */
25447c478bd9Sstevel@tonic-gate 		for (i = SIGHUP; i <= SIGRTMAX; i++)
25457c478bd9Sstevel@tonic-gate 			(void) sigset(i, SIG_DFL);
25467c478bd9Sstevel@tonic-gate 
25477c478bd9Sstevel@tonic-gate 		/*
25487c478bd9Sstevel@tonic-gate 		 * POSIX B.2.2.2 advises that init should set SIGTTOU,
25497c478bd9Sstevel@tonic-gate 		 * SIGTTIN, and SIGTSTP to SIG_IGN.
25507c478bd9Sstevel@tonic-gate 		 *
25517c478bd9Sstevel@tonic-gate 		 * Make sure that SIGXCPU and SIGXFSZ also remain ignored,
25527c478bd9Sstevel@tonic-gate 		 * for backward compatibility.
25537c478bd9Sstevel@tonic-gate 		 */
25547c478bd9Sstevel@tonic-gate 		(void) sigset(SIGTTIN, SIG_IGN);
25557c478bd9Sstevel@tonic-gate 		(void) sigset(SIGTTOU, SIG_IGN);
25567c478bd9Sstevel@tonic-gate 		(void) sigset(SIGTSTP, SIG_IGN);
25577c478bd9Sstevel@tonic-gate 		(void) sigset(SIGXCPU, SIG_IGN);
25587c478bd9Sstevel@tonic-gate 		(void) sigset(SIGXFSZ, SIG_IGN);
25597c478bd9Sstevel@tonic-gate 	}
25607c478bd9Sstevel@tonic-gate 	return (process);
25617c478bd9Sstevel@tonic-gate }
25627c478bd9Sstevel@tonic-gate 
25637c478bd9Sstevel@tonic-gate 
25647c478bd9Sstevel@tonic-gate /*
25657c478bd9Sstevel@tonic-gate  * waitproc() waits for a specified process to die.  For this function to
25667c478bd9Sstevel@tonic-gate  * work, the specified process must already in the proc_table.  waitproc()
25677c478bd9Sstevel@tonic-gate  * returns the exit status of the specified process when it dies.
25687c478bd9Sstevel@tonic-gate  */
25697c478bd9Sstevel@tonic-gate static long
25707c478bd9Sstevel@tonic-gate waitproc(struct PROC_TABLE *process)
25717c478bd9Sstevel@tonic-gate {
25727c478bd9Sstevel@tonic-gate 	int		answer;
25737c478bd9Sstevel@tonic-gate 	sigset_t	oldmask, newmask, zeromask;
25747c478bd9Sstevel@tonic-gate 
25757c478bd9Sstevel@tonic-gate 	(void) sigemptyset(&zeromask);
25767c478bd9Sstevel@tonic-gate 	(void) sigemptyset(&newmask);
25777c478bd9Sstevel@tonic-gate 
25787c478bd9Sstevel@tonic-gate 	(void) sigaddset(&newmask, SIGCLD);
25797c478bd9Sstevel@tonic-gate 
25807c478bd9Sstevel@tonic-gate 	/* Block SIGCLD and save the current signal mask */
25817c478bd9Sstevel@tonic-gate 	if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)
25827c478bd9Sstevel@tonic-gate 		perror("SIG_BLOCK error");
25837c478bd9Sstevel@tonic-gate 
25847c478bd9Sstevel@tonic-gate 	/*
25857c478bd9Sstevel@tonic-gate 	 * Wait around until the process dies.
25867c478bd9Sstevel@tonic-gate 	 */
25877c478bd9Sstevel@tonic-gate 	if (process->p_flags & LIVING)
25887c478bd9Sstevel@tonic-gate 		(void) sigsuspend(&zeromask);
25897c478bd9Sstevel@tonic-gate 
25907c478bd9Sstevel@tonic-gate 	/* Reset signal mask to unblock SIGCLD */
25917c478bd9Sstevel@tonic-gate 	if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
25927c478bd9Sstevel@tonic-gate 		perror("SIG_SETMASK error");
25937c478bd9Sstevel@tonic-gate 
25947c478bd9Sstevel@tonic-gate 	if (process->p_flags & LIVING)
25957c478bd9Sstevel@tonic-gate 		return (FAILURE);
25967c478bd9Sstevel@tonic-gate 
25977c478bd9Sstevel@tonic-gate 	/*
25987c478bd9Sstevel@tonic-gate 	 * Make sure to only return 16 bits so that answer will always
25997c478bd9Sstevel@tonic-gate 	 * be positive whenever the process of interest really died.
26007c478bd9Sstevel@tonic-gate 	 */
26017c478bd9Sstevel@tonic-gate 	answer = (process->p_exit & 0xffff);
26027c478bd9Sstevel@tonic-gate 
26037c478bd9Sstevel@tonic-gate 	/*
26047c478bd9Sstevel@tonic-gate 	 * Free the slot in the proc_table.
26057c478bd9Sstevel@tonic-gate 	 */
26067c478bd9Sstevel@tonic-gate 	process->p_flags = 0;
26077c478bd9Sstevel@tonic-gate 	return (answer);
26087c478bd9Sstevel@tonic-gate }
26097c478bd9Sstevel@tonic-gate 
26107c478bd9Sstevel@tonic-gate /*
26117c478bd9Sstevel@tonic-gate  * notify_pam_dead(): calls into the PAM framework to close the given session.
26127c478bd9Sstevel@tonic-gate  */
26137c478bd9Sstevel@tonic-gate static void
26147c478bd9Sstevel@tonic-gate notify_pam_dead(struct utmpx *up)
26157c478bd9Sstevel@tonic-gate {
26167c478bd9Sstevel@tonic-gate 	pam_handle_t *pamh;
26177c478bd9Sstevel@tonic-gate 	char user[sizeof (up->ut_user) + 1];
26187c478bd9Sstevel@tonic-gate 	char ttyn[sizeof (up->ut_line) + 1];
26197c478bd9Sstevel@tonic-gate 	char host[sizeof (up->ut_host) + 1];
26207c478bd9Sstevel@tonic-gate 
26217c478bd9Sstevel@tonic-gate 	/*
26227c478bd9Sstevel@tonic-gate 	 * PAM does not take care of updating utmpx/wtmpx.
26237c478bd9Sstevel@tonic-gate 	 */
26247c478bd9Sstevel@tonic-gate 	(void) snprintf(user, sizeof (user), "%s", up->ut_user);
26257c478bd9Sstevel@tonic-gate 	(void) snprintf(ttyn, sizeof (ttyn), "%s", up->ut_line);
26267c478bd9Sstevel@tonic-gate 	(void) snprintf(host, sizeof (host), "%s", up->ut_host);
26277c478bd9Sstevel@tonic-gate 
26287c478bd9Sstevel@tonic-gate 	if (pam_start("init", user, NULL, &pamh) == PAM_SUCCESS)  {
26297c478bd9Sstevel@tonic-gate 		(void) pam_set_item(pamh, PAM_TTY, ttyn);
26307c478bd9Sstevel@tonic-gate 		(void) pam_set_item(pamh, PAM_RHOST, host);
26317c478bd9Sstevel@tonic-gate 		(void) pam_close_session(pamh, 0);
26327c478bd9Sstevel@tonic-gate 		(void) pam_end(pamh, PAM_SUCCESS);
26337c478bd9Sstevel@tonic-gate 	}
26347c478bd9Sstevel@tonic-gate }
26357c478bd9Sstevel@tonic-gate 
26367c478bd9Sstevel@tonic-gate /*
26377c478bd9Sstevel@tonic-gate  * Check you can access utmpx (As / may be read-only and
26387c478bd9Sstevel@tonic-gate  * /var may not be mounted yet).
26397c478bd9Sstevel@tonic-gate  */
26407c478bd9Sstevel@tonic-gate static int
26417c478bd9Sstevel@tonic-gate access_utmpx(void)
26427c478bd9Sstevel@tonic-gate {
26437c478bd9Sstevel@tonic-gate 	do {
26447c478bd9Sstevel@tonic-gate 		utmpx_ok = (access(UTMPX, R_OK|W_OK) == 0);
26457c478bd9Sstevel@tonic-gate 	} while (!utmpx_ok && errno == EINTR);
26467c478bd9Sstevel@tonic-gate 
26477c478bd9Sstevel@tonic-gate 	return (utmpx_ok);
26487c478bd9Sstevel@tonic-gate }
26497c478bd9Sstevel@tonic-gate 
26507c478bd9Sstevel@tonic-gate /*
26517c478bd9Sstevel@tonic-gate  * account() updates entries in utmpx and appends new entries to the end of
26527c478bd9Sstevel@tonic-gate  * wtmpx (assuming they exist).  The program argument indicates the name of
26537c478bd9Sstevel@tonic-gate  * program if INIT_PROCESS, otherwise should be NULL.
26547c478bd9Sstevel@tonic-gate  *
26557c478bd9Sstevel@tonic-gate  * account() only blocks for INIT_PROCESS requests.
26567c478bd9Sstevel@tonic-gate  *
26577c478bd9Sstevel@tonic-gate  * Returns non-zero if write failed.
26587c478bd9Sstevel@tonic-gate  */
26597c478bd9Sstevel@tonic-gate static int
26607c478bd9Sstevel@tonic-gate account(short state, struct PROC_TABLE *process, char *program)
26617c478bd9Sstevel@tonic-gate {
26627c478bd9Sstevel@tonic-gate 	struct utmpx utmpbuf, *u, *oldu;
26637c478bd9Sstevel@tonic-gate 	int tmplen;
26647c478bd9Sstevel@tonic-gate 	char fail_buf[UT_LINE_SZ];
26657c478bd9Sstevel@tonic-gate 	sigset_t block, unblock;
26667c478bd9Sstevel@tonic-gate 
26677c478bd9Sstevel@tonic-gate 	if (!utmpx_ok && !access_utmpx()) {
26687c478bd9Sstevel@tonic-gate 		return (-1);
26697c478bd9Sstevel@tonic-gate 	}
26707c478bd9Sstevel@tonic-gate 
26717c478bd9Sstevel@tonic-gate 	/*
26727c478bd9Sstevel@tonic-gate 	 * Set up the prototype for the utmp structure we want to write.
26737c478bd9Sstevel@tonic-gate 	 */
26747c478bd9Sstevel@tonic-gate 	u = &utmpbuf;
26757c478bd9Sstevel@tonic-gate 	(void) memset(u, 0, sizeof (struct utmpx));
26767c478bd9Sstevel@tonic-gate 
26777c478bd9Sstevel@tonic-gate 	/*
26787c478bd9Sstevel@tonic-gate 	 * Fill in the various fields of the utmp structure.
26797c478bd9Sstevel@tonic-gate 	 */
26807c478bd9Sstevel@tonic-gate 	u->ut_id[0] = process->p_id[0];
26817c478bd9Sstevel@tonic-gate 	u->ut_id[1] = process->p_id[1];
26827c478bd9Sstevel@tonic-gate 	u->ut_id[2] = process->p_id[2];
26837c478bd9Sstevel@tonic-gate 	u->ut_id[3] = process->p_id[3];
26847c478bd9Sstevel@tonic-gate 	u->ut_pid = process->p_pid;
26857c478bd9Sstevel@tonic-gate 
26867c478bd9Sstevel@tonic-gate 	/*
26877c478bd9Sstevel@tonic-gate 	 * Fill the "ut_exit" structure.
26887c478bd9Sstevel@tonic-gate 	 */
26897c478bd9Sstevel@tonic-gate 	u->ut_exit.e_termination = WTERMSIG(process->p_exit);
26907c478bd9Sstevel@tonic-gate 	u->ut_exit.e_exit = WEXITSTATUS(process->p_exit);
26917c478bd9Sstevel@tonic-gate 	u->ut_type = state;
26927c478bd9Sstevel@tonic-gate 
26937c478bd9Sstevel@tonic-gate 	(void) time(&u->ut_tv.tv_sec);
26947c478bd9Sstevel@tonic-gate 
26957c478bd9Sstevel@tonic-gate 	/*
26967c478bd9Sstevel@tonic-gate 	 * Block signals for utmp update.
26977c478bd9Sstevel@tonic-gate 	 */
26987c478bd9Sstevel@tonic-gate 	(void) sigfillset(&block);
26997c478bd9Sstevel@tonic-gate 	(void) sigprocmask(SIG_BLOCK, &block, &unblock);
27007c478bd9Sstevel@tonic-gate 
27017c478bd9Sstevel@tonic-gate 	/*
27027c478bd9Sstevel@tonic-gate 	 * See if there already is such an entry in the "utmpx" file.
27037c478bd9Sstevel@tonic-gate 	 */
27047c478bd9Sstevel@tonic-gate 	setutxent();	/* Start at beginning of utmpx file. */
27057c478bd9Sstevel@tonic-gate 
27067c478bd9Sstevel@tonic-gate 	if ((oldu = getutxid(u)) != NULL) {
27077c478bd9Sstevel@tonic-gate 		/*
27087c478bd9Sstevel@tonic-gate 		 * Copy in the old "user", "line" and "host" fields
27097c478bd9Sstevel@tonic-gate 		 * to our new structure.
27107c478bd9Sstevel@tonic-gate 		 */
27117c478bd9Sstevel@tonic-gate 		bcopy(oldu->ut_user, u->ut_user, sizeof (u->ut_user));
27127c478bd9Sstevel@tonic-gate 		bcopy(oldu->ut_line, u->ut_line, sizeof (u->ut_line));
27137c478bd9Sstevel@tonic-gate 		bcopy(oldu->ut_host, u->ut_host, sizeof (u->ut_host));
27147c478bd9Sstevel@tonic-gate 		u->ut_syslen = (tmplen = strlen(u->ut_host)) ?
271548847494SEnrico Perla - Sun Microsystems 		    min(tmplen + 1, sizeof (u->ut_host)) : 0;
27167c478bd9Sstevel@tonic-gate 
27177c478bd9Sstevel@tonic-gate 		if (oldu->ut_type == USER_PROCESS && state == DEAD_PROCESS) {
27187c478bd9Sstevel@tonic-gate 			notify_pam_dead(oldu);
27197c478bd9Sstevel@tonic-gate 		}
27207c478bd9Sstevel@tonic-gate 	}
27217c478bd9Sstevel@tonic-gate 
27227c478bd9Sstevel@tonic-gate 	/*
27237c478bd9Sstevel@tonic-gate 	 * Perform special accounting. Insert the special string into the
27247c478bd9Sstevel@tonic-gate 	 * ut_line array. For INIT_PROCESSes put in the name of the
27257c478bd9Sstevel@tonic-gate 	 * program in the "ut_user" field.
27267c478bd9Sstevel@tonic-gate 	 */
27277c478bd9Sstevel@tonic-gate 	switch (state) {
27287c478bd9Sstevel@tonic-gate 	case INIT_PROCESS:
27297c478bd9Sstevel@tonic-gate 		(void) strncpy(u->ut_user, program, sizeof (u->ut_user));
27307c478bd9Sstevel@tonic-gate 		(void) strcpy(fail_buf, "INIT_PROCESS");
27317c478bd9Sstevel@tonic-gate 		break;
27327c478bd9Sstevel@tonic-gate 
27337c478bd9Sstevel@tonic-gate 	default:
27347c478bd9Sstevel@tonic-gate 		(void) strlcpy(fail_buf, u->ut_id, sizeof (u->ut_id) + 1);
27357c478bd9Sstevel@tonic-gate 		break;
27367c478bd9Sstevel@tonic-gate 	}
27377c478bd9Sstevel@tonic-gate 
27387c478bd9Sstevel@tonic-gate 	/*
27397c478bd9Sstevel@tonic-gate 	 * Write out the updated entry to utmpx file.
27407c478bd9Sstevel@tonic-gate 	 */
27417c478bd9Sstevel@tonic-gate 	if (pututxline(u) == NULL) {
27427c478bd9Sstevel@tonic-gate 		console(B_TRUE, "Failed write of utmpx entry: \"%s\": %s\n",
27437c478bd9Sstevel@tonic-gate 		    fail_buf, strerror(errno));
27447c478bd9Sstevel@tonic-gate 		endutxent();
27457c478bd9Sstevel@tonic-gate 		(void) sigprocmask(SIG_SETMASK, &unblock, NULL);
27467c478bd9Sstevel@tonic-gate 		return (-1);
27477c478bd9Sstevel@tonic-gate 	}
27487c478bd9Sstevel@tonic-gate 
27497c478bd9Sstevel@tonic-gate 	/*
27507c478bd9Sstevel@tonic-gate 	 * If we're able to write to utmpx, then attempt to add to the
27517c478bd9Sstevel@tonic-gate 	 * end of the wtmpx file.
27527c478bd9Sstevel@tonic-gate 	 */
27537c478bd9Sstevel@tonic-gate 	updwtmpx(WTMPX, u);
27547c478bd9Sstevel@tonic-gate 
27557c478bd9Sstevel@tonic-gate 	endutxent();
27567c478bd9Sstevel@tonic-gate 
27577c478bd9Sstevel@tonic-gate 	(void) sigprocmask(SIG_SETMASK, &unblock, NULL);
27587c478bd9Sstevel@tonic-gate 
27597c478bd9Sstevel@tonic-gate 	return (0);
27607c478bd9Sstevel@tonic-gate }
27617c478bd9Sstevel@tonic-gate 
27627c478bd9Sstevel@tonic-gate static void
27637c478bd9Sstevel@tonic-gate clearent(pid_t pid, short status)
27647c478bd9Sstevel@tonic-gate {
27657c478bd9Sstevel@tonic-gate 	struct utmpx *up;
27667c478bd9Sstevel@tonic-gate 	sigset_t block, unblock;
27677c478bd9Sstevel@tonic-gate 
27687c478bd9Sstevel@tonic-gate 	/*
27697c478bd9Sstevel@tonic-gate 	 * Block signals for utmp update.
27707c478bd9Sstevel@tonic-gate 	 */
27717c478bd9Sstevel@tonic-gate 	(void) sigfillset(&block);
27727c478bd9Sstevel@tonic-gate 	(void) sigprocmask(SIG_BLOCK, &block, &unblock);
27737c478bd9Sstevel@tonic-gate 
27747c478bd9Sstevel@tonic-gate 	/*
27757c478bd9Sstevel@tonic-gate 	 * No error checking for now.
27767c478bd9Sstevel@tonic-gate 	 */
27777c478bd9Sstevel@tonic-gate 
27787c478bd9Sstevel@tonic-gate 	setutxent();
27797c478bd9Sstevel@tonic-gate 	while (up = getutxent()) {
27807c478bd9Sstevel@tonic-gate 		if (up->ut_pid == pid) {
27817c478bd9Sstevel@tonic-gate 			if (up->ut_type == DEAD_PROCESS) {
27827c478bd9Sstevel@tonic-gate 				/*
27837c478bd9Sstevel@tonic-gate 				 * Cleaned up elsewhere.
27847c478bd9Sstevel@tonic-gate 				 */
27857c478bd9Sstevel@tonic-gate 				continue;
27867c478bd9Sstevel@tonic-gate 			}
27877c478bd9Sstevel@tonic-gate 
27887c478bd9Sstevel@tonic-gate 			notify_pam_dead(up);
27897c478bd9Sstevel@tonic-gate 
27907c478bd9Sstevel@tonic-gate 			up->ut_type = DEAD_PROCESS;
27917c478bd9Sstevel@tonic-gate 			up->ut_exit.e_termination = WTERMSIG(status);
27927c478bd9Sstevel@tonic-gate 			up->ut_exit.e_exit = WEXITSTATUS(status);
27937c478bd9Sstevel@tonic-gate 			(void) time(&up->ut_tv.tv_sec);
27947c478bd9Sstevel@tonic-gate 
27957c478bd9Sstevel@tonic-gate 			(void) pututxline(up);
27967c478bd9Sstevel@tonic-gate 			/*
27977c478bd9Sstevel@tonic-gate 			 * Now attempt to add to the end of the
27987c478bd9Sstevel@tonic-gate 			 * wtmp and wtmpx files.  Do not create
27997c478bd9Sstevel@tonic-gate 			 * if they don't already exist.
28007c478bd9Sstevel@tonic-gate 			 */
28017c478bd9Sstevel@tonic-gate 			updwtmpx(WTMPX, up);
28027c478bd9Sstevel@tonic-gate 
28037c478bd9Sstevel@tonic-gate 			break;
28047c478bd9Sstevel@tonic-gate 		}
28057c478bd9Sstevel@tonic-gate 	}
28067c478bd9Sstevel@tonic-gate 
28077c478bd9Sstevel@tonic-gate 	endutxent();
28087c478bd9Sstevel@tonic-gate 	(void) sigprocmask(SIG_SETMASK, &unblock, NULL);
28097c478bd9Sstevel@tonic-gate }
28107c478bd9Sstevel@tonic-gate 
28117c478bd9Sstevel@tonic-gate /*
28127c478bd9Sstevel@tonic-gate  * prog_name() searches for the word or unix path name and
28137c478bd9Sstevel@tonic-gate  * returns a pointer to the last element of the pathname.
28147c478bd9Sstevel@tonic-gate  */
28157c478bd9Sstevel@tonic-gate static char *
28167c478bd9Sstevel@tonic-gate prog_name(char *string)
28177c478bd9Sstevel@tonic-gate {
28187c478bd9Sstevel@tonic-gate 	char	*ptr, *ptr2;
28190a1278f2SGary Mills 	static char word[UT_USER_SZ + 1];
28207c478bd9Sstevel@tonic-gate 
28217c478bd9Sstevel@tonic-gate 	/*
28227c478bd9Sstevel@tonic-gate 	 * Search for the first word skipping leading spaces and tabs.
28237c478bd9Sstevel@tonic-gate 	 */
28247c478bd9Sstevel@tonic-gate 	while (*string == ' ' || *string == '\t')
28257c478bd9Sstevel@tonic-gate 		string++;
28267c478bd9Sstevel@tonic-gate 
28277c478bd9Sstevel@tonic-gate 	/*
28287c478bd9Sstevel@tonic-gate 	 * If the first non-space non-tab character is not one allowed in
28297c478bd9Sstevel@tonic-gate 	 * a word, return a pointer to a null string, otherwise parse the
28307c478bd9Sstevel@tonic-gate 	 * pathname.
28317c478bd9Sstevel@tonic-gate 	 */
28327c478bd9Sstevel@tonic-gate 	if (*string != '.' && *string != '/' && *string != '_' &&
28337c478bd9Sstevel@tonic-gate 	    (*string < 'a' || *string > 'z') &&
28347c478bd9Sstevel@tonic-gate 	    (*string < 'A' || * string > 'Z') &&
28357c478bd9Sstevel@tonic-gate 	    (*string < '0' || *string > '9'))
28367c478bd9Sstevel@tonic-gate 		return ("");
28377c478bd9Sstevel@tonic-gate 
28387c478bd9Sstevel@tonic-gate 	/*
28397c478bd9Sstevel@tonic-gate 	 * Parse the pathname looking forward for '/', ' ', '\t', '\n' or
28407c478bd9Sstevel@tonic-gate 	 * '\0'.  Each time a '/' is found, move "ptr" to one past the
28417c478bd9Sstevel@tonic-gate 	 * '/', thus when a ' ', '\t', '\n', or '\0' is found, "ptr" will
28427c478bd9Sstevel@tonic-gate 	 * point to the last element of the pathname.
28437c478bd9Sstevel@tonic-gate 	 */
2844c39ec064SRoger A. Faulkner 	for (ptr = string; *string != ' ' && *string != '\t' &&
284548847494SEnrico Perla - Sun Microsystems 	    *string != '\n' && *string != '\0'; string++) {
28467c478bd9Sstevel@tonic-gate 		if (*string == '/')
28477c478bd9Sstevel@tonic-gate 			ptr = string+1;
28487c478bd9Sstevel@tonic-gate 	}
28497c478bd9Sstevel@tonic-gate 
28507c478bd9Sstevel@tonic-gate 	/*
28517c478bd9Sstevel@tonic-gate 	 * Copy out up to the size of the "ut_user" array into "word",
28527c478bd9Sstevel@tonic-gate 	 * null terminate it and return a pointer to it.
28537c478bd9Sstevel@tonic-gate 	 */
28540a1278f2SGary Mills 	for (ptr2 = &word[0]; ptr2 < &word[UT_USER_SZ] &&
28557c478bd9Sstevel@tonic-gate 	    ptr < string; /* CSTYLED */)
28567c478bd9Sstevel@tonic-gate 		*ptr2++ = *ptr++;
28577c478bd9Sstevel@tonic-gate 
28587c478bd9Sstevel@tonic-gate 	*ptr2 = '\0';
28597c478bd9Sstevel@tonic-gate 	return (&word[0]);
28607c478bd9Sstevel@tonic-gate }
28617c478bd9Sstevel@tonic-gate 
28627c478bd9Sstevel@tonic-gate 
28637c478bd9Sstevel@tonic-gate /*
28647c478bd9Sstevel@tonic-gate  * realcon() returns a nonzero value if there is a character device
28657c478bd9Sstevel@tonic-gate  * associated with SYSCON that has the same device number as CONSOLE.
28667c478bd9Sstevel@tonic-gate  */
28677c478bd9Sstevel@tonic-gate static int
28687c478bd9Sstevel@tonic-gate realcon()
28697c478bd9Sstevel@tonic-gate {
28707c478bd9Sstevel@tonic-gate 	struct stat sconbuf, conbuf;
28717c478bd9Sstevel@tonic-gate 
28727c478bd9Sstevel@tonic-gate 	if (stat(SYSCON, &sconbuf) != -1 &&
28737c478bd9Sstevel@tonic-gate 	    stat(CONSOLE, &conbuf) != -1 &&
28744bc0a2efScasper 	    S_ISCHR(sconbuf.st_mode) &&
28754bc0a2efScasper 	    S_ISCHR(conbuf.st_mode) &&
28767c478bd9Sstevel@tonic-gate 	    sconbuf.st_rdev == conbuf.st_rdev) {
28777c478bd9Sstevel@tonic-gate 		return (1);
28787c478bd9Sstevel@tonic-gate 	} else {
28797c478bd9Sstevel@tonic-gate 		return (0);
28807c478bd9Sstevel@tonic-gate 	}
28817c478bd9Sstevel@tonic-gate }
28827c478bd9Sstevel@tonic-gate 
28837c478bd9Sstevel@tonic-gate 
28847c478bd9Sstevel@tonic-gate /*
28857c478bd9Sstevel@tonic-gate  * get_ioctl_syscon() retrieves the SYSCON settings from the IOCTLSYSCON file.
28867c478bd9Sstevel@tonic-gate  * Returns true if the IOCTLSYSCON file needs to be written (with
28877c478bd9Sstevel@tonic-gate  * write_ioctl_syscon() below)
28887c478bd9Sstevel@tonic-gate  */
28897c478bd9Sstevel@tonic-gate static int
28907c478bd9Sstevel@tonic-gate get_ioctl_syscon()
28917c478bd9Sstevel@tonic-gate {
28927c478bd9Sstevel@tonic-gate 	FILE	*fp;
28937c478bd9Sstevel@tonic-gate 	unsigned int	iflags, oflags, cflags, lflags, ldisc, cc[18];
28947c478bd9Sstevel@tonic-gate 	int		i, valid_format = 0;
28957c478bd9Sstevel@tonic-gate 
28967c478bd9Sstevel@tonic-gate 	/*
28977c478bd9Sstevel@tonic-gate 	 * Read in the previous modes for SYSCON from IOCTLSYSCON.
28987c478bd9Sstevel@tonic-gate 	 */
28997c478bd9Sstevel@tonic-gate 	if ((fp = fopen(IOCTLSYSCON, "r")) == NULL) {
29007c478bd9Sstevel@tonic-gate 		stored_syscon_termios = dflt_termios;
29017c478bd9Sstevel@tonic-gate 		console(B_TRUE,
29027c478bd9Sstevel@tonic-gate 		    "warning:%s does not exist, default settings assumed\n",
29037c478bd9Sstevel@tonic-gate 		    IOCTLSYSCON);
29047c478bd9Sstevel@tonic-gate 	} else {
29057c478bd9Sstevel@tonic-gate 
29060a1278f2SGary Mills 		i = fscanf(fp,
29077c478bd9Sstevel@tonic-gate 	    "%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x",
29080a1278f2SGary Mills 		    &iflags, &oflags, &cflags, &lflags,
29090a1278f2SGary Mills 		    &cc[0], &cc[1], &cc[2], &cc[3], &cc[4], &cc[5], &cc[6],
29100a1278f2SGary Mills 		    &cc[7], &cc[8], &cc[9], &cc[10], &cc[11], &cc[12], &cc[13],
29110a1278f2SGary Mills 		    &cc[14], &cc[15], &cc[16], &cc[17]);
29120a1278f2SGary Mills 
29130a1278f2SGary Mills 		if (i == 22) {
29140a1278f2SGary Mills 			stored_syscon_termios.c_iflag = iflags;
29150a1278f2SGary Mills 			stored_syscon_termios.c_oflag = oflags;
29160a1278f2SGary Mills 			stored_syscon_termios.c_cflag = cflags;
29170a1278f2SGary Mills 			stored_syscon_termios.c_lflag = lflags;
29180a1278f2SGary Mills 			for (i = 0; i < 18; i++)
29190a1278f2SGary Mills 				stored_syscon_termios.c_cc[i] = (char)cc[i];
29200a1278f2SGary Mills 			valid_format = 1;
29210a1278f2SGary Mills 		} else if (i == 13) {
29227c478bd9Sstevel@tonic-gate 		rewind(fp);
29237c478bd9Sstevel@tonic-gate 		i = fscanf(fp, "%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x",
29247c478bd9Sstevel@tonic-gate 		    &iflags, &oflags, &cflags, &lflags, &ldisc, &cc[0], &cc[1],
29257c478bd9Sstevel@tonic-gate 		    &cc[2], &cc[3], &cc[4], &cc[5], &cc[6], &cc[7]);
29267c478bd9Sstevel@tonic-gate 
29277c478bd9Sstevel@tonic-gate 		/*
29287c478bd9Sstevel@tonic-gate 		 * If the file is formatted properly, use the values to
29297c478bd9Sstevel@tonic-gate 		 * initialize the console terminal condition.
29307c478bd9Sstevel@tonic-gate 		 */
29317c478bd9Sstevel@tonic-gate 		stored_syscon_termios.c_iflag = (ushort_t)iflags;
29327c478bd9Sstevel@tonic-gate 		stored_syscon_termios.c_oflag = (ushort_t)oflags;
29337c478bd9Sstevel@tonic-gate 		stored_syscon_termios.c_cflag = (ushort_t)cflags;
29347c478bd9Sstevel@tonic-gate 		stored_syscon_termios.c_lflag = (ushort_t)lflags;
29357c478bd9Sstevel@tonic-gate 		for (i = 0; i < 8; i++)
29367c478bd9Sstevel@tonic-gate 			stored_syscon_termios.c_cc[i] = (char)cc[i];
29377c478bd9Sstevel@tonic-gate 		valid_format = 1;
29380a1278f2SGary Mills 		}
29390a1278f2SGary Mills 		(void) fclose(fp);
29407c478bd9Sstevel@tonic-gate 
29410a1278f2SGary Mills 		/* If the file is badly formatted, use the default settings. */
29420a1278f2SGary Mills 		if (!valid_format)
29430a1278f2SGary Mills 			stored_syscon_termios = dflt_termios;
29447c478bd9Sstevel@tonic-gate 	}
29457c478bd9Sstevel@tonic-gate 
29467c478bd9Sstevel@tonic-gate 	/* If the file had a bad format, rewrite it later. */
29477c478bd9Sstevel@tonic-gate 	return (!valid_format);
29487c478bd9Sstevel@tonic-gate }
29497c478bd9Sstevel@tonic-gate 
29507c478bd9Sstevel@tonic-gate 
29517c478bd9Sstevel@tonic-gate static void
29527c478bd9Sstevel@tonic-gate write_ioctl_syscon()
29537c478bd9Sstevel@tonic-gate {
29547c478bd9Sstevel@tonic-gate 	FILE *fp;
29557c478bd9Sstevel@tonic-gate 	int i;
29567c478bd9Sstevel@tonic-gate 
29577c478bd9Sstevel@tonic-gate 	(void) unlink(SYSCON);
29587c478bd9Sstevel@tonic-gate 	(void) link(SYSTTY, SYSCON);
29597c478bd9Sstevel@tonic-gate 	(void) umask(022);
29607c478bd9Sstevel@tonic-gate 	fp = fopen(IOCTLSYSCON, "w");
29617c478bd9Sstevel@tonic-gate 
29627c478bd9Sstevel@tonic-gate 	(void) fprintf(fp, "%x:%x:%x:%x:0", stored_syscon_termios.c_iflag,
29637c478bd9Sstevel@tonic-gate 	    stored_syscon_termios.c_oflag, stored_syscon_termios.c_cflag,
29647c478bd9Sstevel@tonic-gate 	    stored_syscon_termios.c_lflag);
29657c478bd9Sstevel@tonic-gate 	for (i = 0; i < 8; ++i)
29667c478bd9Sstevel@tonic-gate 		(void) fprintf(fp, ":%x", stored_syscon_termios.c_cc[i]);
29677c478bd9Sstevel@tonic-gate 	(void) putc('\n', fp);
29687c478bd9Sstevel@tonic-gate 
29697c478bd9Sstevel@tonic-gate 	(void) fflush(fp);
29707c478bd9Sstevel@tonic-gate 	(void) fsync(fileno(fp));
29717c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
29727c478bd9Sstevel@tonic-gate 	(void) umask(cmask);
29737c478bd9Sstevel@tonic-gate }
29747c478bd9Sstevel@tonic-gate 
29757c478bd9Sstevel@tonic-gate 
29767c478bd9Sstevel@tonic-gate /*
29777c478bd9Sstevel@tonic-gate  * void console(boolean_t, char *, ...)
29787c478bd9Sstevel@tonic-gate  *   Outputs the requested message to the system console.  Note that the number
29797c478bd9Sstevel@tonic-gate  *   of arguments passed to console() should be determined by the print format.
29807c478bd9Sstevel@tonic-gate  *
29817c478bd9Sstevel@tonic-gate  *   The "prefix" parameter indicates whether or not "INIT: " should precede the
29827c478bd9Sstevel@tonic-gate  *   message.
29837c478bd9Sstevel@tonic-gate  *
29847c478bd9Sstevel@tonic-gate  *   To make sure we write to the console in a sane fashion, we use the modes
29857c478bd9Sstevel@tonic-gate  *   we keep in stored_syscon_termios (which we read out of /etc/ioctl.syscon).
29867c478bd9Sstevel@tonic-gate  *   Afterwards we restore whatever modes were already there.
29877c478bd9Sstevel@tonic-gate  */
29887c478bd9Sstevel@tonic-gate /* PRINTFLIKE2 */
29897c478bd9Sstevel@tonic-gate static void
29907c478bd9Sstevel@tonic-gate console(boolean_t prefix, char *format, ...)
29917c478bd9Sstevel@tonic-gate {
29927c478bd9Sstevel@tonic-gate 	char	outbuf[BUFSIZ];
29937c478bd9Sstevel@tonic-gate 	va_list	args;
29947c478bd9Sstevel@tonic-gate 	int fd, getret;
29957c478bd9Sstevel@tonic-gate 	struct termios old_syscon_termios;
29967c478bd9Sstevel@tonic-gate 	FILE *f;
29977c478bd9Sstevel@tonic-gate 
29987c478bd9Sstevel@tonic-gate 	/*
29997c478bd9Sstevel@tonic-gate 	 * We open SYSCON anew each time in case it has changed (see
30007c478bd9Sstevel@tonic-gate 	 * userinit()).
30017c478bd9Sstevel@tonic-gate 	 */
30027c478bd9Sstevel@tonic-gate 	if ((fd = open(SYSCON, O_RDWR | O_NOCTTY)) < 0 ||
30037c478bd9Sstevel@tonic-gate 	    (f = fdopen(fd, "r+")) == NULL) {
30047c478bd9Sstevel@tonic-gate 		if (prefix)
30057c478bd9Sstevel@tonic-gate 			syslog(LOG_WARNING, "INIT: ");
30067c478bd9Sstevel@tonic-gate 		va_start(args, format);
30077c478bd9Sstevel@tonic-gate 		vsyslog(LOG_WARNING, format, args);
30087c478bd9Sstevel@tonic-gate 		va_end(args);
30097c478bd9Sstevel@tonic-gate 		if (fd >= 0)
30107c478bd9Sstevel@tonic-gate 			(void) close(fd);
30117c478bd9Sstevel@tonic-gate 		return;
30127c478bd9Sstevel@tonic-gate 	}
30137c478bd9Sstevel@tonic-gate 	setbuf(f, &outbuf[0]);
30147c478bd9Sstevel@tonic-gate 
30157c478bd9Sstevel@tonic-gate 	getret = tcgetattr(fd, &old_syscon_termios);
30167c478bd9Sstevel@tonic-gate 	old_syscon_termios.c_cflag &= ~HUPCL;
30177c478bd9Sstevel@tonic-gate 	if (realcon())
30187c478bd9Sstevel@tonic-gate 		/* Don't overwrite cflag of real console. */
30197c478bd9Sstevel@tonic-gate 		stored_syscon_termios.c_cflag = old_syscon_termios.c_cflag;
30207c478bd9Sstevel@tonic-gate 
30217c478bd9Sstevel@tonic-gate 	stored_syscon_termios.c_cflag &= ~HUPCL;
30227c478bd9Sstevel@tonic-gate 
30237c478bd9Sstevel@tonic-gate 	(void) tcsetattr(fd, TCSANOW, &stored_syscon_termios);
30247c478bd9Sstevel@tonic-gate 
30257c478bd9Sstevel@tonic-gate 	if (prefix)
30267c478bd9Sstevel@tonic-gate 		(void) fprintf(f, "\nINIT: ");
30277c478bd9Sstevel@tonic-gate 	va_start(args, format);
30287c478bd9Sstevel@tonic-gate 	(void) vfprintf(f, format, args);
30297c478bd9Sstevel@tonic-gate 	va_end(args);
30307c478bd9Sstevel@tonic-gate 
30317c478bd9Sstevel@tonic-gate 	if (getret == 0)
30327c478bd9Sstevel@tonic-gate 		(void) tcsetattr(fd, TCSADRAIN, &old_syscon_termios);
30337c478bd9Sstevel@tonic-gate 
30347c478bd9Sstevel@tonic-gate 	(void) fclose(f);
30357c478bd9Sstevel@tonic-gate }
30367c478bd9Sstevel@tonic-gate 
30377c478bd9Sstevel@tonic-gate /*
30387c478bd9Sstevel@tonic-gate  * timer() is a substitute for sleep() which uses alarm() and pause().
30397c478bd9Sstevel@tonic-gate  */
30407c478bd9Sstevel@tonic-gate static void
30417c478bd9Sstevel@tonic-gate timer(int waitime)
30427c478bd9Sstevel@tonic-gate {
30437c478bd9Sstevel@tonic-gate 	setimer(waitime);
30447c478bd9Sstevel@tonic-gate 	while (time_up == FALSE)
30457c478bd9Sstevel@tonic-gate 		(void) pause();
30467c478bd9Sstevel@tonic-gate }
30477c478bd9Sstevel@tonic-gate 
30487c478bd9Sstevel@tonic-gate static void
30497c478bd9Sstevel@tonic-gate setimer(int timelimit)
30507c478bd9Sstevel@tonic-gate {
30517c478bd9Sstevel@tonic-gate 	alarmclk();
30527c478bd9Sstevel@tonic-gate 	(void) alarm(timelimit);
30537c478bd9Sstevel@tonic-gate 	time_up = (timelimit ? FALSE : TRUE);
30547c478bd9Sstevel@tonic-gate }
30557c478bd9Sstevel@tonic-gate 
30567c478bd9Sstevel@tonic-gate /*
30577c478bd9Sstevel@tonic-gate  * Fails with
30587c478bd9Sstevel@tonic-gate  *   ENOMEM - out of memory
30597c478bd9Sstevel@tonic-gate  *   ECONNABORTED - repository connection broken
30607c478bd9Sstevel@tonic-gate  *   EPERM - permission denied
30617c478bd9Sstevel@tonic-gate  *   EACCES - backend access denied
30627c478bd9Sstevel@tonic-gate  *   EROFS - backend readonly
30637c478bd9Sstevel@tonic-gate  */
30647c478bd9Sstevel@tonic-gate static int
30657c478bd9Sstevel@tonic-gate get_or_add_startd(scf_instance_t *inst)
30667c478bd9Sstevel@tonic-gate {
30677c478bd9Sstevel@tonic-gate 	scf_handle_t *h;
30687c478bd9Sstevel@tonic-gate 	scf_scope_t *scope = NULL;
30697c478bd9Sstevel@tonic-gate 	scf_service_t *svc = NULL;
30707c478bd9Sstevel@tonic-gate 	int ret = 0;
30717c478bd9Sstevel@tonic-gate 
30727c478bd9Sstevel@tonic-gate 	h = scf_instance_handle(inst);
30737c478bd9Sstevel@tonic-gate 
30747c478bd9Sstevel@tonic-gate 	if (scf_handle_decode_fmri(h, SCF_SERVICE_STARTD, NULL, NULL, inst,
30757c478bd9Sstevel@tonic-gate 	    NULL, NULL, SCF_DECODE_FMRI_EXACT) == 0)
30767c478bd9Sstevel@tonic-gate 		return (0);
30777c478bd9Sstevel@tonic-gate 
30787c478bd9Sstevel@tonic-gate 	switch (scf_error()) {
30797c478bd9Sstevel@tonic-gate 	case SCF_ERROR_CONNECTION_BROKEN:
30807c478bd9Sstevel@tonic-gate 		return (ECONNABORTED);
30817c478bd9Sstevel@tonic-gate 
30827c478bd9Sstevel@tonic-gate 	case SCF_ERROR_NOT_FOUND:
30837c478bd9Sstevel@tonic-gate 		break;
30847c478bd9Sstevel@tonic-gate 
30857c478bd9Sstevel@tonic-gate 	case SCF_ERROR_HANDLE_MISMATCH:
30867c478bd9Sstevel@tonic-gate 	case SCF_ERROR_INVALID_ARGUMENT:
30877c478bd9Sstevel@tonic-gate 	case SCF_ERROR_CONSTRAINT_VIOLATED:
30887c478bd9Sstevel@tonic-gate 	default:
30897c478bd9Sstevel@tonic-gate 		bad_error("scf_handle_decode_fmri", scf_error());
30907c478bd9Sstevel@tonic-gate 	}
30917c478bd9Sstevel@tonic-gate 
30927c478bd9Sstevel@tonic-gate 	/* Make sure we're right, since we're adding piece-by-piece. */
30937c478bd9Sstevel@tonic-gate 	assert(strcmp(SCF_SERVICE_STARTD,
30947c478bd9Sstevel@tonic-gate 	    "svc:/system/svc/restarter:default") == 0);
30957c478bd9Sstevel@tonic-gate 
30967c478bd9Sstevel@tonic-gate 	if ((scope = scf_scope_create(h)) == NULL ||
30977c478bd9Sstevel@tonic-gate 	    (svc = scf_service_create(h)) == NULL) {
30987c478bd9Sstevel@tonic-gate 		ret = ENOMEM;
30997c478bd9Sstevel@tonic-gate 		goto out;
31007c478bd9Sstevel@tonic-gate 	}
31017c478bd9Sstevel@tonic-gate 
31027c478bd9Sstevel@tonic-gate get_scope:
31037c478bd9Sstevel@tonic-gate 	if (scf_handle_get_scope(h, SCF_SCOPE_LOCAL, scope) != 0) {
31047c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
31057c478bd9Sstevel@tonic-gate 		case SCF_ERROR_CONNECTION_BROKEN:
31067c478bd9Sstevel@tonic-gate 			ret = ECONNABORTED;
31077c478bd9Sstevel@tonic-gate 			goto out;
31087c478bd9Sstevel@tonic-gate 
31097c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
31107c478bd9Sstevel@tonic-gate 			(void) fputs(gettext(
31117c478bd9Sstevel@tonic-gate 			    "smf(5) repository missing local scope.\n"),
31127c478bd9Sstevel@tonic-gate 			    stderr);
31137c478bd9Sstevel@tonic-gate 			exit(1);
31147c478bd9Sstevel@tonic-gate 			/* NOTREACHED */
31157c478bd9Sstevel@tonic-gate 
31167c478bd9Sstevel@tonic-gate 		case SCF_ERROR_HANDLE_MISMATCH:
31177c478bd9Sstevel@tonic-gate 		case SCF_ERROR_INVALID_ARGUMENT:
31187c478bd9Sstevel@tonic-gate 		default:
31197c478bd9Sstevel@tonic-gate 			bad_error("scf_handle_get_scope", scf_error());
31207c478bd9Sstevel@tonic-gate 		}
31217c478bd9Sstevel@tonic-gate 	}
31227c478bd9Sstevel@tonic-gate 
31237c478bd9Sstevel@tonic-gate get_svc:
31247c478bd9Sstevel@tonic-gate 	if (scf_scope_get_service(scope, "system/svc/restarter", svc) != 0) {
31257c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
31267c478bd9Sstevel@tonic-gate 		case SCF_ERROR_CONNECTION_BROKEN:
31277c478bd9Sstevel@tonic-gate 			ret = ECONNABORTED;
31287c478bd9Sstevel@tonic-gate 			goto out;
31297c478bd9Sstevel@tonic-gate 
31307c478bd9Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
31317c478bd9Sstevel@tonic-gate 			goto get_scope;
31327c478bd9Sstevel@tonic-gate 
31337c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
31347c478bd9Sstevel@tonic-gate 			break;
31357c478bd9Sstevel@tonic-gate 
31367c478bd9Sstevel@tonic-gate 		case SCF_ERROR_HANDLE_MISMATCH:
31377c478bd9Sstevel@tonic-gate 		case SCF_ERROR_INVALID_ARGUMENT:
31387c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
31397c478bd9Sstevel@tonic-gate 		default:
31407c478bd9Sstevel@tonic-gate 			bad_error("scf_scope_get_service", scf_error());
31417c478bd9Sstevel@tonic-gate 		}
31427c478bd9Sstevel@tonic-gate 
31437c478bd9Sstevel@tonic-gate add_svc:
31447c478bd9Sstevel@tonic-gate 		if (scf_scope_add_service(scope, "system/svc/restarter", svc) !=
31457c478bd9Sstevel@tonic-gate 		    0) {
31467c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
31477c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
31487c478bd9Sstevel@tonic-gate 				ret = ECONNABORTED;
31497c478bd9Sstevel@tonic-gate 				goto out;
31507c478bd9Sstevel@tonic-gate 
31517c478bd9Sstevel@tonic-gate 			case SCF_ERROR_EXISTS:
31527c478bd9Sstevel@tonic-gate 				goto get_svc;
31537c478bd9Sstevel@tonic-gate 
31547c478bd9Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
31557c478bd9Sstevel@tonic-gate 				ret = EPERM;
31567c478bd9Sstevel@tonic-gate 				goto out;
31577c478bd9Sstevel@tonic-gate 
31587c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_ACCESS:
31597c478bd9Sstevel@tonic-gate 				ret = EACCES;
31607c478bd9Sstevel@tonic-gate 				goto out;
31617c478bd9Sstevel@tonic-gate 
31627c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_READONLY:
31637c478bd9Sstevel@tonic-gate 				ret = EROFS;
31647c478bd9Sstevel@tonic-gate 				goto out;
31657c478bd9Sstevel@tonic-gate 
31667c478bd9Sstevel@tonic-gate 			case SCF_ERROR_HANDLE_MISMATCH:
31677c478bd9Sstevel@tonic-gate 			case SCF_ERROR_INVALID_ARGUMENT:
31687c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
31697c478bd9Sstevel@tonic-gate 			default:
31707c478bd9Sstevel@tonic-gate 				bad_error("scf_scope_add_service", scf_error());
31717c478bd9Sstevel@tonic-gate 			}
31727c478bd9Sstevel@tonic-gate 		}
31737c478bd9Sstevel@tonic-gate 	}
31747c478bd9Sstevel@tonic-gate 
31757c478bd9Sstevel@tonic-gate get_inst:
31767c478bd9Sstevel@tonic-gate 	if (scf_service_get_instance(svc, "default", inst) != 0) {
31777c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
31787c478bd9Sstevel@tonic-gate 		case SCF_ERROR_CONNECTION_BROKEN:
31797c478bd9Sstevel@tonic-gate 			ret = ECONNABORTED;
31807c478bd9Sstevel@tonic-gate 			goto out;
31817c478bd9Sstevel@tonic-gate 
31827c478bd9Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
31837c478bd9Sstevel@tonic-gate 			goto add_svc;
31847c478bd9Sstevel@tonic-gate 
31857c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
31867c478bd9Sstevel@tonic-gate 			break;
31877c478bd9Sstevel@tonic-gate 
31887c478bd9Sstevel@tonic-gate 		case SCF_ERROR_HANDLE_MISMATCH:
31897c478bd9Sstevel@tonic-gate 		case SCF_ERROR_INVALID_ARGUMENT:
31907c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
31917c478bd9Sstevel@tonic-gate 		default:
31927c478bd9Sstevel@tonic-gate 			bad_error("scf_service_get_instance", scf_error());
31937c478bd9Sstevel@tonic-gate 		}
31947c478bd9Sstevel@tonic-gate 
31957c478bd9Sstevel@tonic-gate 		if (scf_service_add_instance(svc, "default", inst) !=
31967c478bd9Sstevel@tonic-gate 		    0) {
31977c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
31987c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
31997c478bd9Sstevel@tonic-gate 				ret = ECONNABORTED;
32007c478bd9Sstevel@tonic-gate 				goto out;
32017c478bd9Sstevel@tonic-gate 
32027c478bd9Sstevel@tonic-gate 			case SCF_ERROR_DELETED:
32037c478bd9Sstevel@tonic-gate 				goto add_svc;
32047c478bd9Sstevel@tonic-gate 
32057c478bd9Sstevel@tonic-gate 			case SCF_ERROR_EXISTS:
32067c478bd9Sstevel@tonic-gate 				goto get_inst;
32077c478bd9Sstevel@tonic-gate 
32087c478bd9Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
32097c478bd9Sstevel@tonic-gate 				ret = EPERM;
32107c478bd9Sstevel@tonic-gate 				goto out;
32117c478bd9Sstevel@tonic-gate 
32127c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_ACCESS:
32137c478bd9Sstevel@tonic-gate 				ret = EACCES;
32147c478bd9Sstevel@tonic-gate 				goto out;
32157c478bd9Sstevel@tonic-gate 
32167c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_READONLY:
32177c478bd9Sstevel@tonic-gate 				ret = EROFS;
32187c478bd9Sstevel@tonic-gate 				goto out;
32197c478bd9Sstevel@tonic-gate 
32207c478bd9Sstevel@tonic-gate 			case SCF_ERROR_HANDLE_MISMATCH:
32217c478bd9Sstevel@tonic-gate 			case SCF_ERROR_INVALID_ARGUMENT:
32227c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
32237c478bd9Sstevel@tonic-gate 			default:
32247c478bd9Sstevel@tonic-gate 				bad_error("scf_service_add_instance",
32257c478bd9Sstevel@tonic-gate 				    scf_error());
32267c478bd9Sstevel@tonic-gate 			}
32277c478bd9Sstevel@tonic-gate 		}
32287c478bd9Sstevel@tonic-gate 	}
32297c478bd9Sstevel@tonic-gate 
32307c478bd9Sstevel@tonic-gate 	ret = 0;
32317c478bd9Sstevel@tonic-gate 
32327c478bd9Sstevel@tonic-gate out:
32337c478bd9Sstevel@tonic-gate 	scf_service_destroy(svc);
32347c478bd9Sstevel@tonic-gate 	scf_scope_destroy(scope);
32357c478bd9Sstevel@tonic-gate 	return (ret);
32367c478bd9Sstevel@tonic-gate }
32377c478bd9Sstevel@tonic-gate 
32387c478bd9Sstevel@tonic-gate /*
32397c478bd9Sstevel@tonic-gate  * Fails with
32407c478bd9Sstevel@tonic-gate  *   ECONNABORTED - repository connection broken
32417c478bd9Sstevel@tonic-gate  *   ECANCELED - the transaction's property group was deleted
32427c478bd9Sstevel@tonic-gate  */
32437c478bd9Sstevel@tonic-gate static int
32447c478bd9Sstevel@tonic-gate transaction_add_set(scf_transaction_t *tx, scf_transaction_entry_t *ent,
32457c478bd9Sstevel@tonic-gate     const char *pname, scf_type_t type)
32467c478bd9Sstevel@tonic-gate {
32477c478bd9Sstevel@tonic-gate change_type:
32487c478bd9Sstevel@tonic-gate 	if (scf_transaction_property_change_type(tx, ent, pname, type) == 0)
32497c478bd9Sstevel@tonic-gate 		return (0);
32507c478bd9Sstevel@tonic-gate 
32517c478bd9Sstevel@tonic-gate 	switch (scf_error()) {
32527c478bd9Sstevel@tonic-gate 	case SCF_ERROR_CONNECTION_BROKEN:
32537c478bd9Sstevel@tonic-gate 		return (ECONNABORTED);
32547c478bd9Sstevel@tonic-gate 
32557c478bd9Sstevel@tonic-gate 	case SCF_ERROR_DELETED:
32567c478bd9Sstevel@tonic-gate 		return (ECANCELED);
32577c478bd9Sstevel@tonic-gate 
32587c478bd9Sstevel@tonic-gate 	case SCF_ERROR_NOT_FOUND:
32597c478bd9Sstevel@tonic-gate 		goto new;
32607c478bd9Sstevel@tonic-gate 
32617c478bd9Sstevel@tonic-gate 	case SCF_ERROR_HANDLE_MISMATCH:
32627c478bd9Sstevel@tonic-gate 	case SCF_ERROR_INVALID_ARGUMENT:
32637c478bd9Sstevel@tonic-gate 	case SCF_ERROR_NOT_BOUND:
32647c478bd9Sstevel@tonic-gate 	case SCF_ERROR_NOT_SET:
32657c478bd9Sstevel@tonic-gate 	default:
32667c478bd9Sstevel@tonic-gate 		bad_error("scf_transaction_property_change_type", scf_error());
32677c478bd9Sstevel@tonic-gate 	}
32687c478bd9Sstevel@tonic-gate 
32697c478bd9Sstevel@tonic-gate new:
32707c478bd9Sstevel@tonic-gate 	if (scf_transaction_property_new(tx, ent, pname, type) == 0)
32717c478bd9Sstevel@tonic-gate 		return (0);
32727c478bd9Sstevel@tonic-gate 
32737c478bd9Sstevel@tonic-gate 	switch (scf_error()) {
32747c478bd9Sstevel@tonic-gate 	case SCF_ERROR_CONNECTION_BROKEN:
32757c478bd9Sstevel@tonic-gate 		return (ECONNABORTED);
32767c478bd9Sstevel@tonic-gate 
32777c478bd9Sstevel@tonic-gate 	case SCF_ERROR_DELETED:
32787c478bd9Sstevel@tonic-gate 		return (ECANCELED);
32797c478bd9Sstevel@tonic-gate 
32807c478bd9Sstevel@tonic-gate 	case SCF_ERROR_EXISTS:
32817c478bd9Sstevel@tonic-gate 		goto change_type;
32827c478bd9Sstevel@tonic-gate 
32837c478bd9Sstevel@tonic-gate 	case SCF_ERROR_HANDLE_MISMATCH:
32847c478bd9Sstevel@tonic-gate 	case SCF_ERROR_INVALID_ARGUMENT:
32857c478bd9Sstevel@tonic-gate 	case SCF_ERROR_NOT_BOUND:
32867c478bd9Sstevel@tonic-gate 	case SCF_ERROR_NOT_SET:
32877c478bd9Sstevel@tonic-gate 	default:
32887c478bd9Sstevel@tonic-gate 		bad_error("scf_transaction_property_new", scf_error());
32897c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
32907c478bd9Sstevel@tonic-gate 	}
32917c478bd9Sstevel@tonic-gate }
32927c478bd9Sstevel@tonic-gate 
32937c478bd9Sstevel@tonic-gate static void
32947c478bd9Sstevel@tonic-gate scferr(void)
32957c478bd9Sstevel@tonic-gate {
32967c478bd9Sstevel@tonic-gate 	switch (scf_error()) {
32977c478bd9Sstevel@tonic-gate 	case SCF_ERROR_NO_MEMORY:
32987c478bd9Sstevel@tonic-gate 		console(B_TRUE, gettext("Out of memory.\n"));
32997c478bd9Sstevel@tonic-gate 		break;
33007c478bd9Sstevel@tonic-gate 
33017c478bd9Sstevel@tonic-gate 	case SCF_ERROR_CONNECTION_BROKEN:
33027c478bd9Sstevel@tonic-gate 		console(B_TRUE, gettext(
33037c478bd9Sstevel@tonic-gate 		    "Connection to smf(5) repository server broken.\n"));
33047c478bd9Sstevel@tonic-gate 		break;
33057c478bd9Sstevel@tonic-gate 
33067c478bd9Sstevel@tonic-gate 	case SCF_ERROR_NO_RESOURCES:
33077c478bd9Sstevel@tonic-gate 		console(B_TRUE, gettext(
33087c478bd9Sstevel@tonic-gate 		    "smf(5) repository server is out of memory.\n"));
33097c478bd9Sstevel@tonic-gate 		break;
33107c478bd9Sstevel@tonic-gate 
33117c478bd9Sstevel@tonic-gate 	case SCF_ERROR_PERMISSION_DENIED:
33127c478bd9Sstevel@tonic-gate 		console(B_TRUE, gettext("Insufficient privileges.\n"));
33137c478bd9Sstevel@tonic-gate 		break;
33147c478bd9Sstevel@tonic-gate 
33157c478bd9Sstevel@tonic-gate 	default:
33167c478bd9Sstevel@tonic-gate 		console(B_TRUE, gettext("libscf error: %s\n"),
33177c478bd9Sstevel@tonic-gate 		    scf_strerror(scf_error()));
33187c478bd9Sstevel@tonic-gate 	}
33197c478bd9Sstevel@tonic-gate }
33207c478bd9Sstevel@tonic-gate 
33217c478bd9Sstevel@tonic-gate static void
33227c478bd9Sstevel@tonic-gate lscf_set_runlevel(char rl)
33237c478bd9Sstevel@tonic-gate {
33247c478bd9Sstevel@tonic-gate 	scf_handle_t *h;
33257c478bd9Sstevel@tonic-gate 	scf_instance_t *inst = NULL;
33267c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg = NULL;
33277c478bd9Sstevel@tonic-gate 	scf_transaction_t *tx = NULL;
33287c478bd9Sstevel@tonic-gate 	scf_transaction_entry_t *ent = NULL;
33297c478bd9Sstevel@tonic-gate 	scf_value_t *val = NULL;
33307c478bd9Sstevel@tonic-gate 	char buf[2];
33317c478bd9Sstevel@tonic-gate 	int r;
33327c478bd9Sstevel@tonic-gate 
33337c478bd9Sstevel@tonic-gate 	h = scf_handle_create(SCF_VERSION);
33347c478bd9Sstevel@tonic-gate 	if (h == NULL) {
33357c478bd9Sstevel@tonic-gate 		scferr();
33367c478bd9Sstevel@tonic-gate 		return;
33377c478bd9Sstevel@tonic-gate 	}
33387c478bd9Sstevel@tonic-gate 
33397c478bd9Sstevel@tonic-gate 	if (scf_handle_bind(h) != 0) {
33407c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
33417c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NO_SERVER:
33427c478bd9Sstevel@tonic-gate 			console(B_TRUE,
33437c478bd9Sstevel@tonic-gate 			    gettext("smf(5) repository server not running.\n"));
33447c478bd9Sstevel@tonic-gate 			goto bail;
33457c478bd9Sstevel@tonic-gate 
33467c478bd9Sstevel@tonic-gate 		default:
33477c478bd9Sstevel@tonic-gate 			scferr();
33487c478bd9Sstevel@tonic-gate 			goto bail;
33497c478bd9Sstevel@tonic-gate 		}
33507c478bd9Sstevel@tonic-gate 	}
33517c478bd9Sstevel@tonic-gate 
33527c478bd9Sstevel@tonic-gate 	if ((inst = scf_instance_create(h)) == NULL ||
33537c478bd9Sstevel@tonic-gate 	    (pg = scf_pg_create(h)) == NULL ||
33547c478bd9Sstevel@tonic-gate 	    (val = scf_value_create(h)) == NULL ||
33557c478bd9Sstevel@tonic-gate 	    (tx = scf_transaction_create(h)) == NULL ||
33567c478bd9Sstevel@tonic-gate 	    (ent = scf_entry_create(h)) == NULL) {
33577c478bd9Sstevel@tonic-gate 		scferr();
33587c478bd9Sstevel@tonic-gate 		goto bail;
33597c478bd9Sstevel@tonic-gate 	}
33607c478bd9Sstevel@tonic-gate 
33617c478bd9Sstevel@tonic-gate get_inst:
33627c478bd9Sstevel@tonic-gate 	r = get_or_add_startd(inst);
33637c478bd9Sstevel@tonic-gate 	switch (r) {
33647c478bd9Sstevel@tonic-gate 	case 0:
33657c478bd9Sstevel@tonic-gate 		break;
33667c478bd9Sstevel@tonic-gate 
33677c478bd9Sstevel@tonic-gate 	case ENOMEM:
33687c478bd9Sstevel@tonic-gate 	case ECONNABORTED:
33697c478bd9Sstevel@tonic-gate 	case EPERM:
33707c478bd9Sstevel@tonic-gate 	case EACCES:
33717c478bd9Sstevel@tonic-gate 	case EROFS:
33727c478bd9Sstevel@tonic-gate 		scferr();
33737c478bd9Sstevel@tonic-gate 		goto bail;
33747c478bd9Sstevel@tonic-gate 	default:
33757c478bd9Sstevel@tonic-gate 		bad_error("get_or_add_startd", r);
33767c478bd9Sstevel@tonic-gate 	}
33777c478bd9Sstevel@tonic-gate 
33787c478bd9Sstevel@tonic-gate get_pg:
33797c478bd9Sstevel@tonic-gate 	if (scf_instance_get_pg(inst, SCF_PG_OPTIONS_OVR, pg) != 0) {
33807c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
33817c478bd9Sstevel@tonic-gate 		case SCF_ERROR_CONNECTION_BROKEN:
33827c478bd9Sstevel@tonic-gate 			scferr();
33837c478bd9Sstevel@tonic-gate 			goto bail;
33847c478bd9Sstevel@tonic-gate 
33857c478bd9Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
33867c478bd9Sstevel@tonic-gate 			goto get_inst;
33877c478bd9Sstevel@tonic-gate 
33887c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
33897c478bd9Sstevel@tonic-gate 			break;
33907c478bd9Sstevel@tonic-gate 
33917c478bd9Sstevel@tonic-gate 		case SCF_ERROR_HANDLE_MISMATCH:
33927c478bd9Sstevel@tonic-gate 		case SCF_ERROR_INVALID_ARGUMENT:
33937c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
33947c478bd9Sstevel@tonic-gate 		default:
33957c478bd9Sstevel@tonic-gate 			bad_error("scf_instance_get_pg", scf_error());
33967c478bd9Sstevel@tonic-gate 		}
33977c478bd9Sstevel@tonic-gate 
33987c478bd9Sstevel@tonic-gate add_pg:
33997c478bd9Sstevel@tonic-gate 		if (scf_instance_add_pg(inst, SCF_PG_OPTIONS_OVR,
34007c478bd9Sstevel@tonic-gate 		    SCF_PG_OPTIONS_OVR_TYPE, SCF_PG_OPTIONS_OVR_FLAGS, pg) !=
34017c478bd9Sstevel@tonic-gate 		    0) {
34027c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
34037c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
34047c478bd9Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
34057c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_ACCESS:
34067c478bd9Sstevel@tonic-gate 				scferr();
34077c478bd9Sstevel@tonic-gate 				goto bail;
34087c478bd9Sstevel@tonic-gate 
34097c478bd9Sstevel@tonic-gate 			case SCF_ERROR_DELETED:
34107c478bd9Sstevel@tonic-gate 				goto get_inst;
34117c478bd9Sstevel@tonic-gate 
34127c478bd9Sstevel@tonic-gate 			case SCF_ERROR_EXISTS:
34137c478bd9Sstevel@tonic-gate 				goto get_pg;
34147c478bd9Sstevel@tonic-gate 
34157c478bd9Sstevel@tonic-gate 			case SCF_ERROR_HANDLE_MISMATCH:
34167c478bd9Sstevel@tonic-gate 			case SCF_ERROR_INVALID_ARGUMENT:
34177c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
34187c478bd9Sstevel@tonic-gate 			default:
34197c478bd9Sstevel@tonic-gate 				bad_error("scf_instance_add_pg", scf_error());
34207c478bd9Sstevel@tonic-gate 			}
34217c478bd9Sstevel@tonic-gate 		}
34227c478bd9Sstevel@tonic-gate 	}
34237c478bd9Sstevel@tonic-gate 
34247c478bd9Sstevel@tonic-gate 	buf[0] = rl;
34257c478bd9Sstevel@tonic-gate 	buf[1] = '\0';
34267c478bd9Sstevel@tonic-gate 	r = scf_value_set_astring(val, buf);
34277c478bd9Sstevel@tonic-gate 	assert(r == 0);
34287c478bd9Sstevel@tonic-gate 
34297c478bd9Sstevel@tonic-gate 	for (;;) {
34307c478bd9Sstevel@tonic-gate 		if (scf_transaction_start(tx, pg) != 0) {
34317c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
34327c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
34337c478bd9Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
34347c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_ACCESS:
34357c478bd9Sstevel@tonic-gate 				scferr();
34367c478bd9Sstevel@tonic-gate 				goto bail;
34377c478bd9Sstevel@tonic-gate 
34387c478bd9Sstevel@tonic-gate 			case SCF_ERROR_DELETED:
34397c478bd9Sstevel@tonic-gate 				goto add_pg;
34407c478bd9Sstevel@tonic-gate 
34417c478bd9Sstevel@tonic-gate 			case SCF_ERROR_HANDLE_MISMATCH:
34427c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_BOUND:
34437c478bd9Sstevel@tonic-gate 			case SCF_ERROR_IN_USE:
34447c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
34457c478bd9Sstevel@tonic-gate 			default:
34467c478bd9Sstevel@tonic-gate 				bad_error("scf_transaction_start", scf_error());
34477c478bd9Sstevel@tonic-gate 			}
34487c478bd9Sstevel@tonic-gate 		}
34497c478bd9Sstevel@tonic-gate 
34507c478bd9Sstevel@tonic-gate 		r = transaction_add_set(tx, ent, "runlevel", SCF_TYPE_ASTRING);
34517c478bd9Sstevel@tonic-gate 		switch (r) {
34527c478bd9Sstevel@tonic-gate 		case 0:
34537c478bd9Sstevel@tonic-gate 			break;
34547c478bd9Sstevel@tonic-gate 
34557c478bd9Sstevel@tonic-gate 		case ECONNABORTED:
34567c478bd9Sstevel@tonic-gate 			scferr();
34577c478bd9Sstevel@tonic-gate 			goto bail;
34587c478bd9Sstevel@tonic-gate 
34597c478bd9Sstevel@tonic-gate 		case ECANCELED:
34607c478bd9Sstevel@tonic-gate 			scf_transaction_reset(tx);
34617c478bd9Sstevel@tonic-gate 			goto add_pg;
34627c478bd9Sstevel@tonic-gate 
34637c478bd9Sstevel@tonic-gate 		default:
34647c478bd9Sstevel@tonic-gate 			bad_error("transaction_add_set", r);
34657c478bd9Sstevel@tonic-gate 		}
34667c478bd9Sstevel@tonic-gate 
34677c478bd9Sstevel@tonic-gate 		r = scf_entry_add_value(ent, val);
34687c478bd9Sstevel@tonic-gate 		assert(r == 0);
34697c478bd9Sstevel@tonic-gate 
34707c478bd9Sstevel@tonic-gate 		r = scf_transaction_commit(tx);
34717c478bd9Sstevel@tonic-gate 		if (r == 1)
34727c478bd9Sstevel@tonic-gate 			break;
34737c478bd9Sstevel@tonic-gate 
34747c478bd9Sstevel@tonic-gate 		if (r != 0) {
34757c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
34767c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
34777c478bd9Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
34787c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_ACCESS:
34797c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_READONLY:
34807c478bd9Sstevel@tonic-gate 				scferr();
34817c478bd9Sstevel@tonic-gate 				goto bail;
34827c478bd9Sstevel@tonic-gate 
34837c478bd9Sstevel@tonic-gate 			case SCF_ERROR_DELETED:
34847c478bd9Sstevel@tonic-gate 				scf_transaction_reset(tx);
34857c478bd9Sstevel@tonic-gate 				goto add_pg;
34867c478bd9Sstevel@tonic-gate 
34877c478bd9Sstevel@tonic-gate 			case SCF_ERROR_INVALID_ARGUMENT:
34887c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_BOUND:
34897c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
34907c478bd9Sstevel@tonic-gate 			default:
34917c478bd9Sstevel@tonic-gate 				bad_error("scf_transaction_commit",
34927c478bd9Sstevel@tonic-gate 				    scf_error());
34937c478bd9Sstevel@tonic-gate 			}
34947c478bd9Sstevel@tonic-gate 		}
34957c478bd9Sstevel@tonic-gate 
34967c478bd9Sstevel@tonic-gate 		scf_transaction_reset(tx);
34977c478bd9Sstevel@tonic-gate 		(void) scf_pg_update(pg);
34987c478bd9Sstevel@tonic-gate 	}
34997c478bd9Sstevel@tonic-gate 
35007c478bd9Sstevel@tonic-gate bail:
35017c478bd9Sstevel@tonic-gate 	scf_transaction_destroy(tx);
35027c478bd9Sstevel@tonic-gate 	scf_entry_destroy(ent);
35037c478bd9Sstevel@tonic-gate 	scf_value_destroy(val);
35047c478bd9Sstevel@tonic-gate 	scf_pg_destroy(pg);
35057c478bd9Sstevel@tonic-gate 	scf_instance_destroy(inst);
35067c478bd9Sstevel@tonic-gate 
35077c478bd9Sstevel@tonic-gate 	(void) scf_handle_unbind(h);
35087c478bd9Sstevel@tonic-gate 	scf_handle_destroy(h);
35097c478bd9Sstevel@tonic-gate }
35107c478bd9Sstevel@tonic-gate 
35117c478bd9Sstevel@tonic-gate /*
35127c478bd9Sstevel@tonic-gate  * Function to handle requests from users to main init running as process 1.
35137c478bd9Sstevel@tonic-gate  */
35147c478bd9Sstevel@tonic-gate static void
35157c478bd9Sstevel@tonic-gate userinit(int argc, char **argv)
35167c478bd9Sstevel@tonic-gate {
35177c478bd9Sstevel@tonic-gate 	FILE	*fp;
35187c478bd9Sstevel@tonic-gate 	char	*ln;
35197c478bd9Sstevel@tonic-gate 	int	init_signal;
35207c478bd9Sstevel@tonic-gate 	struct stat	sconbuf, conbuf;
35217c478bd9Sstevel@tonic-gate 	const char *usage_msg = "Usage: init [0123456SsQqabc]\n";
35227c478bd9Sstevel@tonic-gate 
35237c478bd9Sstevel@tonic-gate 	/*
35247c478bd9Sstevel@tonic-gate 	 * We are a user invoked init.  Is there an argument and is it
35257c478bd9Sstevel@tonic-gate 	 * a single character?  If not, print usage message and quit.
35267c478bd9Sstevel@tonic-gate 	 */
35277c478bd9Sstevel@tonic-gate 	if (argc != 2 || argv[1][1] != '\0') {
35287c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, usage_msg);
35297c478bd9Sstevel@tonic-gate 		exit(0);
35307c478bd9Sstevel@tonic-gate 	}
35317c478bd9Sstevel@tonic-gate 
35327c478bd9Sstevel@tonic-gate 	if ((init_signal = lvlname_to_state((char)argv[1][0])) == -1) {
35337c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, usage_msg);
35347c478bd9Sstevel@tonic-gate 		(void) audit_put_record(ADT_FAILURE, ADT_FAIL_VALUE_BAD_CMD,
35357c478bd9Sstevel@tonic-gate 		    argv[1]);
35367c478bd9Sstevel@tonic-gate 		exit(1);
35377c478bd9Sstevel@tonic-gate 	}
35387c478bd9Sstevel@tonic-gate 
35397c478bd9Sstevel@tonic-gate 	if (init_signal == SINGLE_USER) {
35407c478bd9Sstevel@tonic-gate 		/*
35417c478bd9Sstevel@tonic-gate 		 * Make sure this process is talking to a legal tty line
35427c478bd9Sstevel@tonic-gate 		 * and that /dev/syscon is linked to this line.
35437c478bd9Sstevel@tonic-gate 		 */
35447c478bd9Sstevel@tonic-gate 		ln = ttyname(0);	/* Get the name of tty */
35457c478bd9Sstevel@tonic-gate 		if (ln == NULL) {
35467c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
35477c478bd9Sstevel@tonic-gate 			    "Standard input not a tty line\n");
35487c478bd9Sstevel@tonic-gate 			(void) audit_put_record(ADT_FAILURE,
35497c478bd9Sstevel@tonic-gate 			    ADT_FAIL_VALUE_BAD_TTY, argv[1]);
35507c478bd9Sstevel@tonic-gate 			exit(1);
35517c478bd9Sstevel@tonic-gate 		}
3552c2a7bee5Svikram 
3553c2a7bee5Svikram 		if ((stat(ln, &sconbuf) != -1) &&
3554c2a7bee5Svikram 		    (stat(SYSCON, &conbuf) == -1 ||
3555c2a7bee5Svikram 		    sconbuf.st_rdev != conbuf.st_rdev)) {
35567c478bd9Sstevel@tonic-gate 			/*
3557c2a7bee5Svikram 			 * /dev/syscon needs to change.
35587c478bd9Sstevel@tonic-gate 			 * Unlink /dev/syscon and relink it to the current line.
35597c478bd9Sstevel@tonic-gate 			 */
3560c2a7bee5Svikram 			if (lstat(SYSCON, &conbuf) != -1 &&
3561c2a7bee5Svikram 			    unlink(SYSCON) == FAILURE) {
35627c478bd9Sstevel@tonic-gate 				perror("Can't unlink /dev/syscon");
35637c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
35647c478bd9Sstevel@tonic-gate 				    "Run command on the system console.\n");
35657c478bd9Sstevel@tonic-gate 				(void) audit_put_record(ADT_FAILURE,
35667c478bd9Sstevel@tonic-gate 				    ADT_FAIL_VALUE_PROGRAM, argv[1]);
35677c478bd9Sstevel@tonic-gate 				exit(1);
35687c478bd9Sstevel@tonic-gate 			}
3569c2a7bee5Svikram 			if (symlink(ln, SYSCON) == FAILURE) {
35707c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
3571c2a7bee5Svikram 				    "Can't symlink /dev/syscon to %s: %s", ln,
35727c478bd9Sstevel@tonic-gate 				    strerror(errno));
35737c478bd9Sstevel@tonic-gate 
35747c478bd9Sstevel@tonic-gate 				/* Try to leave a syscon */
35757c478bd9Sstevel@tonic-gate 				(void) link(SYSTTY, SYSCON);
35767c478bd9Sstevel@tonic-gate 				(void) audit_put_record(ADT_FAILURE,
35777c478bd9Sstevel@tonic-gate 				    ADT_FAIL_VALUE_PROGRAM, argv[1]);
35787c478bd9Sstevel@tonic-gate 				exit(1);
35797c478bd9Sstevel@tonic-gate 			}
35807c478bd9Sstevel@tonic-gate 
35817c478bd9Sstevel@tonic-gate 			/*
35827c478bd9Sstevel@tonic-gate 			 * Try to leave a message on system console saying where
35837c478bd9Sstevel@tonic-gate 			 * /dev/syscon is currently connected.
35847c478bd9Sstevel@tonic-gate 			 */
35857c478bd9Sstevel@tonic-gate 			if ((fp = fopen(SYSTTY, "r+")) != NULL) {
35867c478bd9Sstevel@tonic-gate 				(void) fprintf(fp,
35877c478bd9Sstevel@tonic-gate 				    "\n****	SYSCON CHANGED TO %s	****\n",
35887c478bd9Sstevel@tonic-gate 				    ln);
35897c478bd9Sstevel@tonic-gate 				(void) fclose(fp);
35907c478bd9Sstevel@tonic-gate 			}
35917c478bd9Sstevel@tonic-gate 		}
35927c478bd9Sstevel@tonic-gate 	}
35937c478bd9Sstevel@tonic-gate 
35947c478bd9Sstevel@tonic-gate 	update_boot_archive(init_signal);
35957c478bd9Sstevel@tonic-gate 
35966d59ee37Spaulson 	(void) audit_put_record(ADT_SUCCESS, ADT_SUCCESS, argv[1]);
35977c478bd9Sstevel@tonic-gate 
35987c478bd9Sstevel@tonic-gate 	/*
35997c478bd9Sstevel@tonic-gate 	 * Signal init; init will take care of telling svc.startd.
36007c478bd9Sstevel@tonic-gate 	 */
36017c478bd9Sstevel@tonic-gate 	if (kill(init_pid, init_signal) == FAILURE) {
36027c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "Must be super-user\n");
36037c478bd9Sstevel@tonic-gate 		(void) audit_put_record(ADT_FAILURE,
36047c478bd9Sstevel@tonic-gate 		    ADT_FAIL_VALUE_AUTH, argv[1]);
36057c478bd9Sstevel@tonic-gate 		exit(1);
36067c478bd9Sstevel@tonic-gate 	}
36077c478bd9Sstevel@tonic-gate 
36087c478bd9Sstevel@tonic-gate 	exit(0);
36097c478bd9Sstevel@tonic-gate }
36107c478bd9Sstevel@tonic-gate 
36117c478bd9Sstevel@tonic-gate 
36127c478bd9Sstevel@tonic-gate #define	DELTA	25	/* Number of pidlist elements to allocate at a time */
36137c478bd9Sstevel@tonic-gate 
36147c478bd9Sstevel@tonic-gate /* ARGSUSED */
36157c478bd9Sstevel@tonic-gate void
36167c478bd9Sstevel@tonic-gate sigpoll(int n)
36177c478bd9Sstevel@tonic-gate {
36187c478bd9Sstevel@tonic-gate 	struct pidrec prec;
36197c478bd9Sstevel@tonic-gate 	struct pidrec *p = &prec;
36207c478bd9Sstevel@tonic-gate 	struct pidlist *plp;
36217c478bd9Sstevel@tonic-gate 	struct pidlist *tp, *savetp;
36227c478bd9Sstevel@tonic-gate 	int i;
36237c478bd9Sstevel@tonic-gate 
36247c478bd9Sstevel@tonic-gate 	if (Pfd < 0) {
36257c478bd9Sstevel@tonic-gate 		return;
36267c478bd9Sstevel@tonic-gate 	}
3627dd965b2fSnakanon 
36287c478bd9Sstevel@tonic-gate 	for (;;) {
36297c478bd9Sstevel@tonic-gate 		/*
36307c478bd9Sstevel@tonic-gate 		 * Important Note: Either read will really fail (in which case
36317c478bd9Sstevel@tonic-gate 		 * return is all we can do) or will get EAGAIN (Pfd was opened
36327c478bd9Sstevel@tonic-gate 		 * O_NDELAY), in which case we also want to return.
36337c478bd9Sstevel@tonic-gate 		 * Always return from here!
36347c478bd9Sstevel@tonic-gate 		 */
36357c478bd9Sstevel@tonic-gate 		if (read(Pfd, p, sizeof (struct pidrec)) !=
36367c478bd9Sstevel@tonic-gate 						sizeof (struct pidrec)) {
36377c478bd9Sstevel@tonic-gate 			return;
36387c478bd9Sstevel@tonic-gate 		}
36397c478bd9Sstevel@tonic-gate 		switch (p->pd_type) {
36407c478bd9Sstevel@tonic-gate 
36417c478bd9Sstevel@tonic-gate 		case ADDPID:
36427c478bd9Sstevel@tonic-gate 			/*
36437c478bd9Sstevel@tonic-gate 			 * New "godchild", add to list.
36447c478bd9Sstevel@tonic-gate 			 */
36457c478bd9Sstevel@tonic-gate 			if (Plfree == NULL) {
36467c478bd9Sstevel@tonic-gate 				plp = (struct pidlist *)calloc(DELTA,
36477c478bd9Sstevel@tonic-gate 				    sizeof (struct pidlist));
36487c478bd9Sstevel@tonic-gate 				if (plp == NULL) {
36497c478bd9Sstevel@tonic-gate 					/* Can't save pid */
36507c478bd9Sstevel@tonic-gate 					break;
36517c478bd9Sstevel@tonic-gate 				}
36527c478bd9Sstevel@tonic-gate 				/*
36537c478bd9Sstevel@tonic-gate 				 * Point at 2nd record allocated, we'll use plp.
36547c478bd9Sstevel@tonic-gate 				 */
36557c478bd9Sstevel@tonic-gate 				tp = plp + 1;
36567c478bd9Sstevel@tonic-gate 				/*
36577c478bd9Sstevel@tonic-gate 				 * Link them into a chain.
36587c478bd9Sstevel@tonic-gate 				 */
36597c478bd9Sstevel@tonic-gate 				Plfree = tp;
36607c478bd9Sstevel@tonic-gate 				for (i = 0; i < DELTA - 2; i++) {
36617c478bd9Sstevel@tonic-gate 					tp->pl_next = tp + 1;
36627c478bd9Sstevel@tonic-gate 					tp++;
36637c478bd9Sstevel@tonic-gate 				}
36647c478bd9Sstevel@tonic-gate 			} else {
36657c478bd9Sstevel@tonic-gate 				plp = Plfree;
36667c478bd9Sstevel@tonic-gate 				Plfree = plp->pl_next;
36677c478bd9Sstevel@tonic-gate 			}
36687c478bd9Sstevel@tonic-gate 			plp->pl_pid = p->pd_pid;
36697c478bd9Sstevel@tonic-gate 			plp->pl_dflag = 0;
36707c478bd9Sstevel@tonic-gate 			plp->pl_next = NULL;
36717c478bd9Sstevel@tonic-gate 			/*
36727c478bd9Sstevel@tonic-gate 			 * Note - pid list is kept in increasing order of pids.
36737c478bd9Sstevel@tonic-gate 			 */
36747c478bd9Sstevel@tonic-gate 			if (Plhead == NULL) {
36757c478bd9Sstevel@tonic-gate 				Plhead = plp;
36767c478bd9Sstevel@tonic-gate 				/* Back up to read next record */
36777c478bd9Sstevel@tonic-gate 				break;
36787c478bd9Sstevel@tonic-gate 			} else {
36797c478bd9Sstevel@tonic-gate 				savetp = tp = Plhead;
36807c478bd9Sstevel@tonic-gate 				while (tp) {
36817c478bd9Sstevel@tonic-gate 					if (plp->pl_pid > tp->pl_pid) {
36827c478bd9Sstevel@tonic-gate 						savetp = tp;
36837c478bd9Sstevel@tonic-gate 						tp = tp->pl_next;
36847c478bd9Sstevel@tonic-gate 						continue;
36857c478bd9Sstevel@tonic-gate 					} else if (plp->pl_pid < tp->pl_pid) {
36867c478bd9Sstevel@tonic-gate 						if (tp == Plhead) {
36877c478bd9Sstevel@tonic-gate 							plp->pl_next = Plhead;
36887c478bd9Sstevel@tonic-gate 							Plhead = plp;
36897c478bd9Sstevel@tonic-gate 						} else {
36907c478bd9Sstevel@tonic-gate 							plp->pl_next =
36917c478bd9Sstevel@tonic-gate 							    savetp->pl_next;
36927c478bd9Sstevel@tonic-gate 							savetp->pl_next = plp;
36937c478bd9Sstevel@tonic-gate 						}
36947c478bd9Sstevel@tonic-gate 						break;
36957c478bd9Sstevel@tonic-gate 					} else {
36967c478bd9Sstevel@tonic-gate 						/* Already in list! */
36977c478bd9Sstevel@tonic-gate 						plp->pl_next = Plfree;
36987c478bd9Sstevel@tonic-gate 						Plfree = plp;
36997c478bd9Sstevel@tonic-gate 						break;
37007c478bd9Sstevel@tonic-gate 					}
37017c478bd9Sstevel@tonic-gate 				}
37027c478bd9Sstevel@tonic-gate 				if (tp == NULL) {
37037c478bd9Sstevel@tonic-gate 					/* Add to end of list */
37047c478bd9Sstevel@tonic-gate 					savetp->pl_next = plp;
37057c478bd9Sstevel@tonic-gate 				}
37067c478bd9Sstevel@tonic-gate 			}
37077c478bd9Sstevel@tonic-gate 			/* Back up to read next record. */
37087c478bd9Sstevel@tonic-gate 			break;
37097c478bd9Sstevel@tonic-gate 
37107c478bd9Sstevel@tonic-gate 		case REMPID:
37117c478bd9Sstevel@tonic-gate 			/*
37127c478bd9Sstevel@tonic-gate 			 * This one was handled by someone else,
37137c478bd9Sstevel@tonic-gate 			 * purge it from the list.
37147c478bd9Sstevel@tonic-gate 			 */
37157c478bd9Sstevel@tonic-gate 			if (Plhead == NULL) {
37167c478bd9Sstevel@tonic-gate 				/* Back up to read next record. */
37177c478bd9Sstevel@tonic-gate 				break;
37187c478bd9Sstevel@tonic-gate 			}
37197c478bd9Sstevel@tonic-gate 			savetp = tp = Plhead;
37207c478bd9Sstevel@tonic-gate 			while (tp) {
37217c478bd9Sstevel@tonic-gate 				if (p->pd_pid > tp->pl_pid) {
37227c478bd9Sstevel@tonic-gate 					/* Keep on looking. */
37237c478bd9Sstevel@tonic-gate 					savetp = tp;
37247c478bd9Sstevel@tonic-gate 					tp = tp->pl_next;
37257c478bd9Sstevel@tonic-gate 					continue;
37267c478bd9Sstevel@tonic-gate 				} else if (p->pd_pid < tp->pl_pid) {
37277c478bd9Sstevel@tonic-gate 					/* Not in list. */
37287c478bd9Sstevel@tonic-gate 					break;
37297c478bd9Sstevel@tonic-gate 				} else {
37307c478bd9Sstevel@tonic-gate 					/* Found it. */
37317c478bd9Sstevel@tonic-gate 					if (tp == Plhead)
37327c478bd9Sstevel@tonic-gate 						Plhead = tp->pl_next;
37337c478bd9Sstevel@tonic-gate 					else
37347c478bd9Sstevel@tonic-gate 						savetp->pl_next = tp->pl_next;
37357c478bd9Sstevel@tonic-gate 					tp->pl_next = Plfree;
37367c478bd9Sstevel@tonic-gate 					Plfree = tp;
37377c478bd9Sstevel@tonic-gate 					break;
37387c478bd9Sstevel@tonic-gate 				}
37397c478bd9Sstevel@tonic-gate 			}
37407c478bd9Sstevel@tonic-gate 			/* Back up to read next record. */
37417c478bd9Sstevel@tonic-gate 			break;
37427c478bd9Sstevel@tonic-gate 		default:
37437c478bd9Sstevel@tonic-gate 			console(B_TRUE, "Bad message on initpipe\n");
37447c478bd9Sstevel@tonic-gate 			break;
37457c478bd9Sstevel@tonic-gate 		}
37467c478bd9Sstevel@tonic-gate 	}
37477c478bd9Sstevel@tonic-gate }
37487c478bd9Sstevel@tonic-gate 
37497c478bd9Sstevel@tonic-gate 
37507c478bd9Sstevel@tonic-gate static void
37517c478bd9Sstevel@tonic-gate cleanaux()
37527c478bd9Sstevel@tonic-gate {
37537c478bd9Sstevel@tonic-gate 	struct pidlist *savep, *p;
37547c478bd9Sstevel@tonic-gate 	pid_t	pid;
37557c478bd9Sstevel@tonic-gate 	short	status;
37567c478bd9Sstevel@tonic-gate 
3757c39ec064SRoger A. Faulkner 	(void) sighold(SIGCLD);
37587c478bd9Sstevel@tonic-gate 	Gchild = 0;	/* Note - Safe to do this here since no SIGCLDs */
37597c478bd9Sstevel@tonic-gate 	(void) sighold(SIGPOLL);
37607c478bd9Sstevel@tonic-gate 	savep = p = Plhead;
37617c478bd9Sstevel@tonic-gate 	while (p) {
37627c478bd9Sstevel@tonic-gate 		if (p->pl_dflag) {
37637c478bd9Sstevel@tonic-gate 			/*
37647c478bd9Sstevel@tonic-gate 			 * Found an entry to delete,
37657c478bd9Sstevel@tonic-gate 			 * remove it from list first.
37667c478bd9Sstevel@tonic-gate 			 */
37677c478bd9Sstevel@tonic-gate 			pid = p->pl_pid;
37687c478bd9Sstevel@tonic-gate 			status = p->pl_exit;
37697c478bd9Sstevel@tonic-gate 			if (p == Plhead) {
37707c478bd9Sstevel@tonic-gate 				Plhead = p->pl_next;
37717c478bd9Sstevel@tonic-gate 				p->pl_next = Plfree;
37727c478bd9Sstevel@tonic-gate 				Plfree = p;
37737c478bd9Sstevel@tonic-gate 				savep = p = Plhead;
37747c478bd9Sstevel@tonic-gate 			} else {
37757c478bd9Sstevel@tonic-gate 				savep->pl_next = p->pl_next;
37767c478bd9Sstevel@tonic-gate 				p->pl_next = Plfree;
37777c478bd9Sstevel@tonic-gate 				Plfree = p;
37787c478bd9Sstevel@tonic-gate 				p = savep->pl_next;
37797c478bd9Sstevel@tonic-gate 			}
37807c478bd9Sstevel@tonic-gate 			clearent(pid, status);
37817c478bd9Sstevel@tonic-gate 			continue;
37827c478bd9Sstevel@tonic-gate 		}
37837c478bd9Sstevel@tonic-gate 		savep = p;
37847c478bd9Sstevel@tonic-gate 		p = p->pl_next;
37857c478bd9Sstevel@tonic-gate 	}
37867c478bd9Sstevel@tonic-gate 	(void) sigrelse(SIGPOLL);
3787c39ec064SRoger A. Faulkner 	(void) sigrelse(SIGCLD);
37887c478bd9Sstevel@tonic-gate }
37897c478bd9Sstevel@tonic-gate 
37907c478bd9Sstevel@tonic-gate 
37917c478bd9Sstevel@tonic-gate /*
37927c478bd9Sstevel@tonic-gate  * /etc/inittab has more entries and we have run out of room in the proc_table
37937c478bd9Sstevel@tonic-gate  * array. Double the size of proc_table to accomodate the extra entries.
37947c478bd9Sstevel@tonic-gate  */
37957c478bd9Sstevel@tonic-gate static void
37967c478bd9Sstevel@tonic-gate increase_proc_table_size()
37977c478bd9Sstevel@tonic-gate {
37987c478bd9Sstevel@tonic-gate 	sigset_t block, unblock;
37997c478bd9Sstevel@tonic-gate 	void *ptr;
38007c478bd9Sstevel@tonic-gate 	size_t delta = num_proc * sizeof (struct PROC_TABLE);
38017c478bd9Sstevel@tonic-gate 
38027c478bd9Sstevel@tonic-gate 
38037c478bd9Sstevel@tonic-gate 	/*
38047c478bd9Sstevel@tonic-gate 	 * Block signals for realloc.
38057c478bd9Sstevel@tonic-gate 	 */
38067c478bd9Sstevel@tonic-gate 	(void) sigfillset(&block);
38077c478bd9Sstevel@tonic-gate 	(void) sigprocmask(SIG_BLOCK, &block, &unblock);
38087c478bd9Sstevel@tonic-gate 
38097c478bd9Sstevel@tonic-gate 
38107c478bd9Sstevel@tonic-gate 	/*
38117c478bd9Sstevel@tonic-gate 	 * On failure we just return because callers of this function check
38127c478bd9Sstevel@tonic-gate 	 * for failure.
38137c478bd9Sstevel@tonic-gate 	 */
38147c478bd9Sstevel@tonic-gate 	do
38157c478bd9Sstevel@tonic-gate 		ptr = realloc(g_state, g_state_sz + delta);
38160a1278f2SGary Mills 	while (ptr == NULL && errno == EAGAIN)
38170a1278f2SGary Mills 		;
38187c478bd9Sstevel@tonic-gate 
38197c478bd9Sstevel@tonic-gate 	if (ptr != NULL) {
38207c478bd9Sstevel@tonic-gate 		/* ensure that the new part is initialized to zero */
38217c478bd9Sstevel@tonic-gate 		bzero((caddr_t)ptr + g_state_sz, delta);
38227c478bd9Sstevel@tonic-gate 
38237c478bd9Sstevel@tonic-gate 		g_state = ptr;
38247c478bd9Sstevel@tonic-gate 		g_state_sz += delta;
38257c478bd9Sstevel@tonic-gate 		num_proc <<= 1;
38267c478bd9Sstevel@tonic-gate 	}
38277c478bd9Sstevel@tonic-gate 
38287c478bd9Sstevel@tonic-gate 
38297c478bd9Sstevel@tonic-gate 	/* unblock our signals before returning */
38307c478bd9Sstevel@tonic-gate 	(void) sigprocmask(SIG_SETMASK, &unblock, NULL);
38317c478bd9Sstevel@tonic-gate }
38327c478bd9Sstevel@tonic-gate 
38337c478bd9Sstevel@tonic-gate 
38347c478bd9Sstevel@tonic-gate 
38357c478bd9Sstevel@tonic-gate /*
38367c478bd9Sstevel@tonic-gate  * Sanity check g_state.
38377c478bd9Sstevel@tonic-gate  */
38387c478bd9Sstevel@tonic-gate static int
38397c478bd9Sstevel@tonic-gate st_sane()
38407c478bd9Sstevel@tonic-gate {
38417c478bd9Sstevel@tonic-gate 	int i;
38427c478bd9Sstevel@tonic-gate 	struct PROC_TABLE *ptp;
38437c478bd9Sstevel@tonic-gate 
38447c478bd9Sstevel@tonic-gate 
38457c478bd9Sstevel@tonic-gate 	/* Note: cur_state is encoded as a signal number */
38467c478bd9Sstevel@tonic-gate 	if (cur_state < 1 || cur_state == 9 || cur_state > 13)
38477c478bd9Sstevel@tonic-gate 		return (0);
38487c478bd9Sstevel@tonic-gate 
38497c478bd9Sstevel@tonic-gate 	/* Check num_proc */
38507c478bd9Sstevel@tonic-gate 	if (g_state_sz != sizeof (struct init_state) + (num_proc - 1) *
38517c478bd9Sstevel@tonic-gate 	    sizeof (struct PROC_TABLE))
38527c478bd9Sstevel@tonic-gate 		return (0);
38537c478bd9Sstevel@tonic-gate 
38547c478bd9Sstevel@tonic-gate 	/* Check proc_table */
38557c478bd9Sstevel@tonic-gate 	for (i = 0, ptp = proc_table; i < num_proc; ++i, ++ptp) {
38567c478bd9Sstevel@tonic-gate 		/* skip unoccupied entries */
38577c478bd9Sstevel@tonic-gate 		if (!(ptp->p_flags & OCCUPIED))
38587c478bd9Sstevel@tonic-gate 			continue;
38597c478bd9Sstevel@tonic-gate 
38607c478bd9Sstevel@tonic-gate 		/* p_flags has no bits outside of PF_MASK */
38617c478bd9Sstevel@tonic-gate 		if (ptp->p_flags & ~(PF_MASK))
38627c478bd9Sstevel@tonic-gate 			return (0);
38637c478bd9Sstevel@tonic-gate 
38647c478bd9Sstevel@tonic-gate 		/* 5 <= pid <= MAXPID */
38657c478bd9Sstevel@tonic-gate 		if (ptp->p_pid < 5 || ptp->p_pid > MAXPID)
38667c478bd9Sstevel@tonic-gate 			return (0);
38677c478bd9Sstevel@tonic-gate 
38687c478bd9Sstevel@tonic-gate 		/* p_count >= 0 */
38697c478bd9Sstevel@tonic-gate 		if (ptp->p_count < 0)
38707c478bd9Sstevel@tonic-gate 			return (0);
38717c478bd9Sstevel@tonic-gate 
38727c478bd9Sstevel@tonic-gate 		/* p_time >= 0 */
38737c478bd9Sstevel@tonic-gate 		if (ptp->p_time < 0)
38747c478bd9Sstevel@tonic-gate 			return (0);
38757c478bd9Sstevel@tonic-gate 	}
38767c478bd9Sstevel@tonic-gate 
38777c478bd9Sstevel@tonic-gate 	return (1);
38787c478bd9Sstevel@tonic-gate }
38797c478bd9Sstevel@tonic-gate 
38807c478bd9Sstevel@tonic-gate /*
38817c478bd9Sstevel@tonic-gate  * Initialize our state.
38827c478bd9Sstevel@tonic-gate  *
38837c478bd9Sstevel@tonic-gate  * If the system just booted, then init_state_file, which is located on an
38847c478bd9Sstevel@tonic-gate  * everpresent tmpfs filesystem, should not exist.
38857c478bd9Sstevel@tonic-gate  *
38867c478bd9Sstevel@tonic-gate  * If we were restarted, then init_state_file should exist, in
38877c478bd9Sstevel@tonic-gate  * which case we'll read it in, sanity check it, and use it.
38887c478bd9Sstevel@tonic-gate  *
38897c478bd9Sstevel@tonic-gate  * Note: You can't call console() until proc_table is ready.
38907c478bd9Sstevel@tonic-gate  */
38917c478bd9Sstevel@tonic-gate void
38927c478bd9Sstevel@tonic-gate st_init()
38937c478bd9Sstevel@tonic-gate {
38947c478bd9Sstevel@tonic-gate 	struct stat stb;
38957c478bd9Sstevel@tonic-gate 	int ret, st_fd, insane = 0;
38967c478bd9Sstevel@tonic-gate 	size_t to_be_read;
38977c478bd9Sstevel@tonic-gate 	char *ptr;
38987c478bd9Sstevel@tonic-gate 
38997c478bd9Sstevel@tonic-gate 
39007c478bd9Sstevel@tonic-gate 	booting = 1;
39017c478bd9Sstevel@tonic-gate 
39027c478bd9Sstevel@tonic-gate 	do {
39037c478bd9Sstevel@tonic-gate 		/*
39047c478bd9Sstevel@tonic-gate 		 * If we can exclusively create the file, then we're the
39057c478bd9Sstevel@tonic-gate 		 * initial invocation of init(1M).
39067c478bd9Sstevel@tonic-gate 		 */
39077c478bd9Sstevel@tonic-gate 		st_fd = open(init_state_file, O_RDWR | O_CREAT | O_EXCL,
39087c478bd9Sstevel@tonic-gate 		    S_IRUSR | S_IWUSR);
39097c478bd9Sstevel@tonic-gate 	} while (st_fd == -1 && errno == EINTR);
39107c478bd9Sstevel@tonic-gate 	if (st_fd != -1)
39117c478bd9Sstevel@tonic-gate 		goto new_state;
39127c478bd9Sstevel@tonic-gate 
39137c478bd9Sstevel@tonic-gate 	booting = 0;
39147c478bd9Sstevel@tonic-gate 
39157c478bd9Sstevel@tonic-gate 	do {
39167c478bd9Sstevel@tonic-gate 		st_fd = open(init_state_file, O_RDWR, S_IRUSR | S_IWUSR);
39177c478bd9Sstevel@tonic-gate 	} while (st_fd == -1 && errno == EINTR);
39187c478bd9Sstevel@tonic-gate 	if (st_fd == -1)
39197c478bd9Sstevel@tonic-gate 		goto new_state;
39207c478bd9Sstevel@tonic-gate 
39217c478bd9Sstevel@tonic-gate 	/* Get the size of the file. */
39227c478bd9Sstevel@tonic-gate 	do
39237c478bd9Sstevel@tonic-gate 		ret = fstat(st_fd, &stb);
39240a1278f2SGary Mills 	while (ret == -1 && errno == EINTR)
39250a1278f2SGary Mills 		;
39267c478bd9Sstevel@tonic-gate 	if (ret == -1)
39277c478bd9Sstevel@tonic-gate 		goto new_state;
39287c478bd9Sstevel@tonic-gate 
39297c478bd9Sstevel@tonic-gate 	do
39307c478bd9Sstevel@tonic-gate 		g_state = malloc(stb.st_size);
39310a1278f2SGary Mills 	while (g_state == NULL && errno == EAGAIN)
39320a1278f2SGary Mills 		;
39337c478bd9Sstevel@tonic-gate 	if (g_state == NULL)
39347c478bd9Sstevel@tonic-gate 		goto new_state;
39357c478bd9Sstevel@tonic-gate 
39367c478bd9Sstevel@tonic-gate 	to_be_read = stb.st_size;
39377c478bd9Sstevel@tonic-gate 	ptr = (char *)g_state;
39387c478bd9Sstevel@tonic-gate 	while (to_be_read > 0) {
39397c478bd9Sstevel@tonic-gate 		ssize_t read_ret;
39407c478bd9Sstevel@tonic-gate 
39417c478bd9Sstevel@tonic-gate 		read_ret = read(st_fd, ptr, to_be_read);
39427c478bd9Sstevel@tonic-gate 		if (read_ret < 0) {
39437c478bd9Sstevel@tonic-gate 			if (errno == EINTR)
39447c478bd9Sstevel@tonic-gate 				continue;
39457c478bd9Sstevel@tonic-gate 
39467c478bd9Sstevel@tonic-gate 			goto new_state;
39477c478bd9Sstevel@tonic-gate 		}
39487c478bd9Sstevel@tonic-gate 
39497c478bd9Sstevel@tonic-gate 		to_be_read -= read_ret;
39507c478bd9Sstevel@tonic-gate 		ptr += read_ret;
39517c478bd9Sstevel@tonic-gate 	}
39527c478bd9Sstevel@tonic-gate 
39537c478bd9Sstevel@tonic-gate 	(void) close(st_fd);
39547c478bd9Sstevel@tonic-gate 
39557c478bd9Sstevel@tonic-gate 	g_state_sz = stb.st_size;
39567c478bd9Sstevel@tonic-gate 
39577c478bd9Sstevel@tonic-gate 	if (st_sane()) {
39587c478bd9Sstevel@tonic-gate 		console(B_TRUE, "Restarting.\n");
39597c478bd9Sstevel@tonic-gate 		return;
39607c478bd9Sstevel@tonic-gate 	}
39617c478bd9Sstevel@tonic-gate 
39627c478bd9Sstevel@tonic-gate 	insane = 1;
39637c478bd9Sstevel@tonic-gate 
39647c478bd9Sstevel@tonic-gate new_state:
39657c478bd9Sstevel@tonic-gate 	if (st_fd >= 0)
39667c478bd9Sstevel@tonic-gate 		(void) close(st_fd);
39677c478bd9Sstevel@tonic-gate 	else
39687c478bd9Sstevel@tonic-gate 		(void) unlink(init_state_file);
39697c478bd9Sstevel@tonic-gate 
39707c478bd9Sstevel@tonic-gate 	if (g_state != NULL)
39717c478bd9Sstevel@tonic-gate 		free(g_state);
39727c478bd9Sstevel@tonic-gate 
39737c478bd9Sstevel@tonic-gate 	/* Something went wrong, so allocate new state. */
39747c478bd9Sstevel@tonic-gate 	g_state_sz = sizeof (struct init_state) +
39757c478bd9Sstevel@tonic-gate 	    ((init_num_proc - 1) * sizeof (struct PROC_TABLE));
39767c478bd9Sstevel@tonic-gate 	do
39777c478bd9Sstevel@tonic-gate 		g_state = calloc(1, g_state_sz);
39780a1278f2SGary Mills 	while (g_state == NULL && errno == EAGAIN)
39790a1278f2SGary Mills 		;
39807c478bd9Sstevel@tonic-gate 	if (g_state == NULL) {
39817c478bd9Sstevel@tonic-gate 		/* Fatal error! */
39827c478bd9Sstevel@tonic-gate 		exit(errno);
39837c478bd9Sstevel@tonic-gate 	}
39847c478bd9Sstevel@tonic-gate 
39857c478bd9Sstevel@tonic-gate 	g_state->ist_runlevel = -1;
39867c478bd9Sstevel@tonic-gate 	num_proc = init_num_proc;
39877c478bd9Sstevel@tonic-gate 
39887c478bd9Sstevel@tonic-gate 	if (!booting) {
39897c478bd9Sstevel@tonic-gate 		console(B_TRUE, "Restarting.\n");
39907c478bd9Sstevel@tonic-gate 
39917c478bd9Sstevel@tonic-gate 		/* Overwrite the bad state file. */
39927c478bd9Sstevel@tonic-gate 		st_write();
39937c478bd9Sstevel@tonic-gate 
39947c478bd9Sstevel@tonic-gate 		if (!insane) {
39957c478bd9Sstevel@tonic-gate 			console(B_TRUE,
39967c478bd9Sstevel@tonic-gate 			    "Error accessing persistent state file `%s'.  "
39977c478bd9Sstevel@tonic-gate 			    "Ignored.\n", init_state_file);
39987c478bd9Sstevel@tonic-gate 		} else {
39997c478bd9Sstevel@tonic-gate 			console(B_TRUE,
40007c478bd9Sstevel@tonic-gate 			    "Persistent state file `%s' is invalid and was "
40017c478bd9Sstevel@tonic-gate 			    "ignored.\n", init_state_file);
40027c478bd9Sstevel@tonic-gate 		}
40037c478bd9Sstevel@tonic-gate 	}
40047c478bd9Sstevel@tonic-gate }
40057c478bd9Sstevel@tonic-gate 
40067c478bd9Sstevel@tonic-gate /*
40077c478bd9Sstevel@tonic-gate  * Write g_state out to the state file.
40087c478bd9Sstevel@tonic-gate  */
40097c478bd9Sstevel@tonic-gate void
40107c478bd9Sstevel@tonic-gate st_write()
40117c478bd9Sstevel@tonic-gate {
40127c478bd9Sstevel@tonic-gate 	static int complained = 0;
40137c478bd9Sstevel@tonic-gate 
40147c478bd9Sstevel@tonic-gate 	int st_fd;
40157c478bd9Sstevel@tonic-gate 	char *cp;
40167c478bd9Sstevel@tonic-gate 	size_t sz;
40177c478bd9Sstevel@tonic-gate 	ssize_t ret;
40187c478bd9Sstevel@tonic-gate 
40197c478bd9Sstevel@tonic-gate 
40207c478bd9Sstevel@tonic-gate 	do {
40217c478bd9Sstevel@tonic-gate 		st_fd = open(init_next_state_file,
40227c478bd9Sstevel@tonic-gate 		    O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
40237c478bd9Sstevel@tonic-gate 	} while (st_fd < 0 && errno == EINTR);
40247c478bd9Sstevel@tonic-gate 	if (st_fd < 0)
40257c478bd9Sstevel@tonic-gate 		goto err;
40267c478bd9Sstevel@tonic-gate 
40277c478bd9Sstevel@tonic-gate 	cp = (char *)g_state;
40287c478bd9Sstevel@tonic-gate 	sz = g_state_sz;
40297c478bd9Sstevel@tonic-gate 	while (sz > 0) {
40307c478bd9Sstevel@tonic-gate 		ret = write(st_fd, cp, sz);
40317c478bd9Sstevel@tonic-gate 		if (ret < 0) {
40327c478bd9Sstevel@tonic-gate 			if (errno == EINTR)
40337c478bd9Sstevel@tonic-gate 				continue;
40347c478bd9Sstevel@tonic-gate 
40357c478bd9Sstevel@tonic-gate 			goto err;
40367c478bd9Sstevel@tonic-gate 		}
40377c478bd9Sstevel@tonic-gate 
40387c478bd9Sstevel@tonic-gate 		sz -= ret;
40397c478bd9Sstevel@tonic-gate 		cp += ret;
40407c478bd9Sstevel@tonic-gate 	}
40417c478bd9Sstevel@tonic-gate 
40427c478bd9Sstevel@tonic-gate 	(void) close(st_fd);
40437c478bd9Sstevel@tonic-gate 	st_fd = -1;
40447c478bd9Sstevel@tonic-gate 	if (rename(init_next_state_file, init_state_file)) {
40457c478bd9Sstevel@tonic-gate 		(void) unlink(init_next_state_file);
40467c478bd9Sstevel@tonic-gate 		goto err;
40477c478bd9Sstevel@tonic-gate 	}
40487c478bd9Sstevel@tonic-gate 	complained = 0;
40497c478bd9Sstevel@tonic-gate 
40507c478bd9Sstevel@tonic-gate 	return;
40517c478bd9Sstevel@tonic-gate 
40527c478bd9Sstevel@tonic-gate err:
40537c478bd9Sstevel@tonic-gate 	if (st_fd >= 0)
40547c478bd9Sstevel@tonic-gate 		(void) close(st_fd);
40557c478bd9Sstevel@tonic-gate 
40567c478bd9Sstevel@tonic-gate 	if (!booting && !complained) {
40577c478bd9Sstevel@tonic-gate 		/*
40587c478bd9Sstevel@tonic-gate 		 * Only complain after the filesystem should have come up.
40597c478bd9Sstevel@tonic-gate 		 * And only do it once so we don't loop between console()
40607c478bd9Sstevel@tonic-gate 		 * & efork().
40617c478bd9Sstevel@tonic-gate 		 */
40627c478bd9Sstevel@tonic-gate 		complained = 1;
40637c478bd9Sstevel@tonic-gate 		if (st_fd)
40647c478bd9Sstevel@tonic-gate 			console(B_TRUE, "Couldn't write persistent state "
40657c478bd9Sstevel@tonic-gate 			    "file `%s'.\n", init_state_file);
40667c478bd9Sstevel@tonic-gate 		else
40677c478bd9Sstevel@tonic-gate 			console(B_TRUE, "Couldn't move persistent state "
40687c478bd9Sstevel@tonic-gate 			    "file `%s' to `%s'.\n", init_next_state_file,
40697c478bd9Sstevel@tonic-gate 			    init_state_file);
40707c478bd9Sstevel@tonic-gate 	}
40717c478bd9Sstevel@tonic-gate }
40727c478bd9Sstevel@tonic-gate 
40737c478bd9Sstevel@tonic-gate /*
40747c478bd9Sstevel@tonic-gate  * Create a contract with these parameters.
40757c478bd9Sstevel@tonic-gate  */
40767c478bd9Sstevel@tonic-gate static int
40777c478bd9Sstevel@tonic-gate contract_make_template(uint_t info, uint_t critical, uint_t fatal,
40787c478bd9Sstevel@tonic-gate     uint64_t cookie)
40797c478bd9Sstevel@tonic-gate {
40807c478bd9Sstevel@tonic-gate 	int fd, err;
40817c478bd9Sstevel@tonic-gate 
40827c478bd9Sstevel@tonic-gate 	char *ioctl_tset_emsg =
40837c478bd9Sstevel@tonic-gate 	    "Couldn't set \"%s\" contract template parameter: %s.\n";
40847c478bd9Sstevel@tonic-gate 
40857c478bd9Sstevel@tonic-gate 	do
40867c478bd9Sstevel@tonic-gate 		fd = open64(CTFS_ROOT "/process/template", O_RDWR);
40870a1278f2SGary Mills 	while (fd < 0 && errno == EINTR)
40880a1278f2SGary Mills 		;
40897c478bd9Sstevel@tonic-gate 	if (fd < 0) {
40907c478bd9Sstevel@tonic-gate 		console(B_TRUE, "Couldn't create process template: %s.\n",
40917c478bd9Sstevel@tonic-gate 		    strerror(errno));
40927c478bd9Sstevel@tonic-gate 		return (-1);
40937c478bd9Sstevel@tonic-gate 	}
40947c478bd9Sstevel@tonic-gate 
40957c478bd9Sstevel@tonic-gate 	if (err = ct_pr_tmpl_set_param(fd, CT_PR_INHERIT | CT_PR_REGENT))
40967c478bd9Sstevel@tonic-gate 		console(B_TRUE, "Contract set template inherit, regent "
40977b209c2cSacruz 		    "failed: %s.\n", strerror(err));
40987c478bd9Sstevel@tonic-gate 
40997c478bd9Sstevel@tonic-gate 	/*
41007c478bd9Sstevel@tonic-gate 	 * These errors result in a misconfigured template, which is better
41017c478bd9Sstevel@tonic-gate 	 * than no template at all, so warn but don't abort.
41027c478bd9Sstevel@tonic-gate 	 */
41037c478bd9Sstevel@tonic-gate 	if (err = ct_tmpl_set_informative(fd, info))
41047c478bd9Sstevel@tonic-gate 		console(B_TRUE, ioctl_tset_emsg, "informative", strerror(err));
41057c478bd9Sstevel@tonic-gate 
41067c478bd9Sstevel@tonic-gate 	if (err = ct_tmpl_set_critical(fd, critical))
41077c478bd9Sstevel@tonic-gate 		console(B_TRUE, ioctl_tset_emsg, "critical", strerror(err));
41087c478bd9Sstevel@tonic-gate 
41097c478bd9Sstevel@tonic-gate 	if (err = ct_pr_tmpl_set_fatal(fd, fatal))
41107c478bd9Sstevel@tonic-gate 		console(B_TRUE, ioctl_tset_emsg, "fatal", strerror(err));
41117c478bd9Sstevel@tonic-gate 
41127c478bd9Sstevel@tonic-gate 	if (err = ct_tmpl_set_cookie(fd, cookie))
41137c478bd9Sstevel@tonic-gate 		console(B_TRUE, ioctl_tset_emsg, "cookie", strerror(err));
41147c478bd9Sstevel@tonic-gate 
41157c478bd9Sstevel@tonic-gate 	(void) fcntl(fd, F_SETFD, FD_CLOEXEC);
41167c478bd9Sstevel@tonic-gate 
41177c478bd9Sstevel@tonic-gate 	return (fd);
41187c478bd9Sstevel@tonic-gate }
41197c478bd9Sstevel@tonic-gate 
41207c478bd9Sstevel@tonic-gate /*
41217c478bd9Sstevel@tonic-gate  * Create the templates and open an event file descriptor.  We use dup2(2) to
41227c478bd9Sstevel@tonic-gate  * get these descriptors away from the stdin/stdout/stderr group.
41237c478bd9Sstevel@tonic-gate  */
41247c478bd9Sstevel@tonic-gate static void
41257c478bd9Sstevel@tonic-gate contracts_init()
41267c478bd9Sstevel@tonic-gate {
41277c478bd9Sstevel@tonic-gate 	int err, fd;
41287c478bd9Sstevel@tonic-gate 
41297c478bd9Sstevel@tonic-gate 	/*
41307c478bd9Sstevel@tonic-gate 	 * Create & configure a legacy template.  We only want empty events so
41317c478bd9Sstevel@tonic-gate 	 * we know when to abandon them.
41327c478bd9Sstevel@tonic-gate 	 */
41337c478bd9Sstevel@tonic-gate 	legacy_tmpl = contract_make_template(0, CT_PR_EV_EMPTY, CT_PR_EV_HWERR,
41347c478bd9Sstevel@tonic-gate 	    ORDINARY_COOKIE);
41357c478bd9Sstevel@tonic-gate 	if (legacy_tmpl >= 0) {
41367c478bd9Sstevel@tonic-gate 		err = ct_tmpl_activate(legacy_tmpl);
41377c478bd9Sstevel@tonic-gate 		if (err != 0) {
41387c478bd9Sstevel@tonic-gate 			(void) close(legacy_tmpl);
41397c478bd9Sstevel@tonic-gate 			legacy_tmpl = -1;
41407c478bd9Sstevel@tonic-gate 			console(B_TRUE,
41417c478bd9Sstevel@tonic-gate 			    "Couldn't activate legacy template (%s); "
41427c478bd9Sstevel@tonic-gate 			    "legacy services will be in init's contract.\n",
41437c478bd9Sstevel@tonic-gate 			    strerror(err));
41447c478bd9Sstevel@tonic-gate 		}
41457c478bd9Sstevel@tonic-gate 	} else
41467c478bd9Sstevel@tonic-gate 		console(B_TRUE,
41477c478bd9Sstevel@tonic-gate 		    "Legacy services will be in init's contract.\n");
41487c478bd9Sstevel@tonic-gate 
41497c478bd9Sstevel@tonic-gate 	if (dup2(legacy_tmpl, 255) == -1) {
41507c478bd9Sstevel@tonic-gate 		console(B_TRUE, "Could not duplicate legacy template: %s.\n",
41517c478bd9Sstevel@tonic-gate 		    strerror(errno));
41527c478bd9Sstevel@tonic-gate 	} else {
41537c478bd9Sstevel@tonic-gate 		(void) close(legacy_tmpl);
41547c478bd9Sstevel@tonic-gate 		legacy_tmpl = 255;
41557c478bd9Sstevel@tonic-gate 	}
41567c478bd9Sstevel@tonic-gate 
41577c478bd9Sstevel@tonic-gate 	(void) fcntl(legacy_tmpl, F_SETFD, FD_CLOEXEC);
41587c478bd9Sstevel@tonic-gate 
41597c478bd9Sstevel@tonic-gate 	startd_tmpl = contract_make_template(0, CT_PR_EV_EMPTY,
41607c478bd9Sstevel@tonic-gate 	    CT_PR_EV_HWERR | CT_PR_EV_SIGNAL | CT_PR_EV_CORE, STARTD_COOKIE);
41617c478bd9Sstevel@tonic-gate 
41627c478bd9Sstevel@tonic-gate 	if (dup2(startd_tmpl, 254) == -1) {
41637c478bd9Sstevel@tonic-gate 		console(B_TRUE, "Could not duplicate startd template: %s.\n",
41647c478bd9Sstevel@tonic-gate 		    strerror(errno));
41657c478bd9Sstevel@tonic-gate 	} else {
41667c478bd9Sstevel@tonic-gate 		(void) close(startd_tmpl);
41677c478bd9Sstevel@tonic-gate 		startd_tmpl = 254;
41687c478bd9Sstevel@tonic-gate 	}
41697c478bd9Sstevel@tonic-gate 
41707c478bd9Sstevel@tonic-gate 	(void) fcntl(startd_tmpl, F_SETFD, FD_CLOEXEC);
41717c478bd9Sstevel@tonic-gate 
41727c478bd9Sstevel@tonic-gate 	if (legacy_tmpl < 0 && startd_tmpl < 0) {
41737c478bd9Sstevel@tonic-gate 		/* The creation errors have already been reported. */
41747c478bd9Sstevel@tonic-gate 		console(B_TRUE,
41757c478bd9Sstevel@tonic-gate 		    "Ignoring contract events.  Core smf(5) services will not "
41767c478bd9Sstevel@tonic-gate 		    "be restarted.\n");
41777c478bd9Sstevel@tonic-gate 		return;
41787c478bd9Sstevel@tonic-gate 	}
41797c478bd9Sstevel@tonic-gate 
41807c478bd9Sstevel@tonic-gate 	/*
41817c478bd9Sstevel@tonic-gate 	 * Open an event endpoint.
41827c478bd9Sstevel@tonic-gate 	 */
41837c478bd9Sstevel@tonic-gate 	do
41847c478bd9Sstevel@tonic-gate 		fd = open64(CTFS_ROOT "/process/pbundle", O_RDONLY);
41850a1278f2SGary Mills 	while (fd < 0 && errno == EINTR)
41860a1278f2SGary Mills 		;
41877c478bd9Sstevel@tonic-gate 	if (fd < 0) {
41887c478bd9Sstevel@tonic-gate 		console(B_TRUE,
41897c478bd9Sstevel@tonic-gate 		    "Couldn't open process pbundle: %s.  Core smf(5) services "
41907c478bd9Sstevel@tonic-gate 		    "will not be restarted.\n", strerror(errno));
41917c478bd9Sstevel@tonic-gate 		return;
41927c478bd9Sstevel@tonic-gate 	}
41937c478bd9Sstevel@tonic-gate 
41947c478bd9Sstevel@tonic-gate 	if (dup2(fd, 253) == -1) {
41957c478bd9Sstevel@tonic-gate 		console(B_TRUE, "Could not duplicate process bundle: %s.\n",
41967c478bd9Sstevel@tonic-gate 		    strerror(errno));
41977c478bd9Sstevel@tonic-gate 	} else {
41987c478bd9Sstevel@tonic-gate 		(void) close(fd);
41997c478bd9Sstevel@tonic-gate 		fd = 253;
42007c478bd9Sstevel@tonic-gate 	}
42017c478bd9Sstevel@tonic-gate 
42027c478bd9Sstevel@tonic-gate 	(void) fcntl(fd, F_SETFD, FD_CLOEXEC);
42037c478bd9Sstevel@tonic-gate 
42047c478bd9Sstevel@tonic-gate 	/* Reset in case we've been restarted. */
42057c478bd9Sstevel@tonic-gate 	(void) ct_event_reset(fd);
42067c478bd9Sstevel@tonic-gate 
42077c478bd9Sstevel@tonic-gate 	poll_fds[0].fd = fd;
42087c478bd9Sstevel@tonic-gate 	poll_fds[0].events = POLLIN;
42097c478bd9Sstevel@tonic-gate 	poll_nfds = 1;
42107c478bd9Sstevel@tonic-gate }
42117c478bd9Sstevel@tonic-gate 
42127c478bd9Sstevel@tonic-gate static int
42137c478bd9Sstevel@tonic-gate contract_getfile(ctid_t id, const char *name, int oflag)
42147c478bd9Sstevel@tonic-gate {
42157c478bd9Sstevel@tonic-gate 	int fd;
42167c478bd9Sstevel@tonic-gate 
42177c478bd9Sstevel@tonic-gate 	do
42187c478bd9Sstevel@tonic-gate 		fd = contract_open(id, "process", name, oflag);
42190a1278f2SGary Mills 	while (fd < 0 && errno == EINTR)
42200a1278f2SGary Mills 		;
42217c478bd9Sstevel@tonic-gate 
42227c478bd9Sstevel@tonic-gate 	if (fd < 0)
42237c478bd9Sstevel@tonic-gate 		console(B_TRUE, "Couldn't open %s for contract %ld: %s.\n",
42247c478bd9Sstevel@tonic-gate 		    name, id, strerror(errno));
42257c478bd9Sstevel@tonic-gate 
42267c478bd9Sstevel@tonic-gate 	return (fd);
42277c478bd9Sstevel@tonic-gate }
42287c478bd9Sstevel@tonic-gate 
42297c478bd9Sstevel@tonic-gate static int
42307c478bd9Sstevel@tonic-gate contract_cookie(ctid_t id, uint64_t *cp)
42317c478bd9Sstevel@tonic-gate {
42327c478bd9Sstevel@tonic-gate 	int fd, err;
42337c478bd9Sstevel@tonic-gate 	ct_stathdl_t sh;
42347c478bd9Sstevel@tonic-gate 
42357c478bd9Sstevel@tonic-gate 	fd = contract_getfile(id, "status", O_RDONLY);
42367c478bd9Sstevel@tonic-gate 	if (fd < 0)
42377c478bd9Sstevel@tonic-gate 		return (-1);
42387c478bd9Sstevel@tonic-gate 
42397c478bd9Sstevel@tonic-gate 	err = ct_status_read(fd, CTD_COMMON, &sh);
42407c478bd9Sstevel@tonic-gate 	if (err != 0) {
42417c478bd9Sstevel@tonic-gate 		console(B_TRUE, "Couldn't read status of contract %ld: %s.\n",
42427c478bd9Sstevel@tonic-gate 		    id, strerror(err));
42437c478bd9Sstevel@tonic-gate 		(void) close(fd);
42447c478bd9Sstevel@tonic-gate 		return (-1);
42457c478bd9Sstevel@tonic-gate 	}
42467c478bd9Sstevel@tonic-gate 
42477c478bd9Sstevel@tonic-gate 	(void) close(fd);
42487c478bd9Sstevel@tonic-gate 
42497c478bd9Sstevel@tonic-gate 	*cp = ct_status_get_cookie(sh);
42507c478bd9Sstevel@tonic-gate 
42517c478bd9Sstevel@tonic-gate 	ct_status_free(sh);
42527c478bd9Sstevel@tonic-gate 	return (0);
42537c478bd9Sstevel@tonic-gate }
42547c478bd9Sstevel@tonic-gate 
42557c478bd9Sstevel@tonic-gate static void
42567c478bd9Sstevel@tonic-gate contract_ack(ct_evthdl_t e)
42577c478bd9Sstevel@tonic-gate {
42587c478bd9Sstevel@tonic-gate 	int fd;
42597c478bd9Sstevel@tonic-gate 
42607c478bd9Sstevel@tonic-gate 	if (ct_event_get_flags(e) & CTE_INFO)
42617c478bd9Sstevel@tonic-gate 		return;
42627c478bd9Sstevel@tonic-gate 
42637c478bd9Sstevel@tonic-gate 	fd = contract_getfile(ct_event_get_ctid(e), "ctl", O_WRONLY);
42647c478bd9Sstevel@tonic-gate 	if (fd < 0)
42657c478bd9Sstevel@tonic-gate 		return;
42667c478bd9Sstevel@tonic-gate 
42677c478bd9Sstevel@tonic-gate 	(void) ct_ctl_ack(fd, ct_event_get_evid(e));
42687c478bd9Sstevel@tonic-gate 	(void) close(fd);
42697c478bd9Sstevel@tonic-gate }
42707c478bd9Sstevel@tonic-gate 
42717c478bd9Sstevel@tonic-gate /*
42727c478bd9Sstevel@tonic-gate  * Process a contract event.
42737c478bd9Sstevel@tonic-gate  */
42747c478bd9Sstevel@tonic-gate static void
42757c478bd9Sstevel@tonic-gate contract_event(struct pollfd *poll)
42767c478bd9Sstevel@tonic-gate {
42777c478bd9Sstevel@tonic-gate 	ct_evthdl_t e;
42787c478bd9Sstevel@tonic-gate 	int err;
42797c478bd9Sstevel@tonic-gate 	ctid_t ctid;
42807c478bd9Sstevel@tonic-gate 
42817c478bd9Sstevel@tonic-gate 	if (!(poll->revents & POLLIN)) {
42827c478bd9Sstevel@tonic-gate 		if (poll->revents & POLLERR)
42837c478bd9Sstevel@tonic-gate 			console(B_TRUE,
42847c478bd9Sstevel@tonic-gate 			    "Unknown poll error on my process contract "
42857c478bd9Sstevel@tonic-gate 			    "pbundle.\n");
42867c478bd9Sstevel@tonic-gate 		return;
42877c478bd9Sstevel@tonic-gate 	}
42887c478bd9Sstevel@tonic-gate 
42897c478bd9Sstevel@tonic-gate 	err = ct_event_read(poll->fd, &e);
42907c478bd9Sstevel@tonic-gate 	if (err != 0) {
42917c478bd9Sstevel@tonic-gate 		console(B_TRUE, "Error retrieving contract event: %s.\n",
42927c478bd9Sstevel@tonic-gate 		    strerror(err));
42937c478bd9Sstevel@tonic-gate 		return;
42947c478bd9Sstevel@tonic-gate 	}
42957c478bd9Sstevel@tonic-gate 
42967c478bd9Sstevel@tonic-gate 	ctid = ct_event_get_ctid(e);
42977c478bd9Sstevel@tonic-gate 
42987c478bd9Sstevel@tonic-gate 	if (ct_event_get_type(e) == CT_PR_EV_EMPTY) {
42997c478bd9Sstevel@tonic-gate 		uint64_t cookie;
43007c478bd9Sstevel@tonic-gate 		int ret, abandon = 1;
43017c478bd9Sstevel@tonic-gate 
43027c478bd9Sstevel@tonic-gate 		/* If it's svc.startd, restart it.  Else, abandon. */
43037c478bd9Sstevel@tonic-gate 		ret = contract_cookie(ctid, &cookie);
43047c478bd9Sstevel@tonic-gate 
43057c478bd9Sstevel@tonic-gate 		if (ret == 0) {
43067c478bd9Sstevel@tonic-gate 			if (cookie == STARTD_COOKIE &&
43077c478bd9Sstevel@tonic-gate 			    do_restart_startd) {
43087c478bd9Sstevel@tonic-gate 				if (smf_debug)
43097c478bd9Sstevel@tonic-gate 					console(B_TRUE, "Restarting "
43107c478bd9Sstevel@tonic-gate 					    "svc.startd.\n");
43117c478bd9Sstevel@tonic-gate 
43127c478bd9Sstevel@tonic-gate 				/*
43137c478bd9Sstevel@tonic-gate 				 * Account for the failure.  If the failure rate
43147c478bd9Sstevel@tonic-gate 				 * exceeds a threshold, then drop to maintenance
43157c478bd9Sstevel@tonic-gate 				 * mode.
43167c478bd9Sstevel@tonic-gate 				 */
43177c478bd9Sstevel@tonic-gate 				startd_record_failure();
43187c478bd9Sstevel@tonic-gate 				if (startd_failure_rate_critical())
43197c478bd9Sstevel@tonic-gate 					enter_maintenance();
43207c478bd9Sstevel@tonic-gate 
43217c478bd9Sstevel@tonic-gate 				if (startd_tmpl < 0)
43227c478bd9Sstevel@tonic-gate 					console(B_TRUE,
43237c478bd9Sstevel@tonic-gate 					    "Restarting svc.startd in "
43247c478bd9Sstevel@tonic-gate 					    "improper contract (bad "
43257c478bd9Sstevel@tonic-gate 					    "template).\n");
43267c478bd9Sstevel@tonic-gate 
43277c478bd9Sstevel@tonic-gate 				(void) startd_run(startd_cline, startd_tmpl,
43287c478bd9Sstevel@tonic-gate 				    ctid);
43297c478bd9Sstevel@tonic-gate 
43307c478bd9Sstevel@tonic-gate 				abandon = 0;
43317c478bd9Sstevel@tonic-gate 			}
43327c478bd9Sstevel@tonic-gate 		}
43337c478bd9Sstevel@tonic-gate 
43347c478bd9Sstevel@tonic-gate 		if (abandon && (err = contract_abandon_id(ctid))) {
43357c478bd9Sstevel@tonic-gate 			console(B_TRUE, "Couldn't abandon contract %ld: %s.\n",
43367c478bd9Sstevel@tonic-gate 			    ctid, strerror(err));
43377c478bd9Sstevel@tonic-gate 		}
43387c478bd9Sstevel@tonic-gate 
43397c478bd9Sstevel@tonic-gate 		/*
43407c478bd9Sstevel@tonic-gate 		 * No need to acknowledge the event since either way the
43417c478bd9Sstevel@tonic-gate 		 * originating contract should be abandoned.
43427c478bd9Sstevel@tonic-gate 		 */
43437c478bd9Sstevel@tonic-gate 	} else {
43447c478bd9Sstevel@tonic-gate 		console(B_TRUE,
43457c478bd9Sstevel@tonic-gate 		    "Received contract event of unexpected type %d from "
43467c478bd9Sstevel@tonic-gate 		    "contract %ld.\n", ct_event_get_type(e), ctid);
43477c478bd9Sstevel@tonic-gate 
43487c478bd9Sstevel@tonic-gate 		if ((ct_event_get_flags(e) & (CTE_INFO | CTE_ACK)) == 0)
43497c478bd9Sstevel@tonic-gate 			/* Allow unexpected critical events to be released. */
43507c478bd9Sstevel@tonic-gate 			contract_ack(e);
43517c478bd9Sstevel@tonic-gate 	}
43527c478bd9Sstevel@tonic-gate 
43537c478bd9Sstevel@tonic-gate 	ct_event_free(e);
43547c478bd9Sstevel@tonic-gate }
43557c478bd9Sstevel@tonic-gate 
43567c478bd9Sstevel@tonic-gate /*
43577c478bd9Sstevel@tonic-gate  * svc.startd(1M) Management
43587c478bd9Sstevel@tonic-gate  */
43597c478bd9Sstevel@tonic-gate 
43607c478bd9Sstevel@tonic-gate /*
43617c478bd9Sstevel@tonic-gate  * (Re)start svc.startd(1M).  old_ctid should be the contract ID of the old
43627c478bd9Sstevel@tonic-gate  * contract, or 0 if we're starting it for the first time.  If wait is true
43637c478bd9Sstevel@tonic-gate  * we'll wait for and return the exit value of the child.
43647c478bd9Sstevel@tonic-gate  */
43657c478bd9Sstevel@tonic-gate static int
43667c478bd9Sstevel@tonic-gate startd_run(const char *cline, int tmpl, ctid_t old_ctid)
43677c478bd9Sstevel@tonic-gate {
43687c478bd9Sstevel@tonic-gate 	int err, i, ret, did_activate;
43697c478bd9Sstevel@tonic-gate 	pid_t pid;
43707c478bd9Sstevel@tonic-gate 	struct stat sb;
43717c478bd9Sstevel@tonic-gate 
43727c478bd9Sstevel@tonic-gate 	if (cline[0] == '\0')
43737c478bd9Sstevel@tonic-gate 		return (-1);
43747c478bd9Sstevel@tonic-gate 
43757c478bd9Sstevel@tonic-gate 	/*
43767c478bd9Sstevel@tonic-gate 	 * Don't restart startd if the system is rebooting or shutting down.
43777c478bd9Sstevel@tonic-gate 	 */
43787c478bd9Sstevel@tonic-gate 	do {
43797c478bd9Sstevel@tonic-gate 		ret = stat("/etc/svc/volatile/resetting", &sb);
43807c478bd9Sstevel@tonic-gate 	} while (ret == -1 && errno == EINTR);
43817c478bd9Sstevel@tonic-gate 
43827c478bd9Sstevel@tonic-gate 	if (ret == 0) {
43837c478bd9Sstevel@tonic-gate 		if (smf_debug)
43847c478bd9Sstevel@tonic-gate 			console(B_TRUE, "Quiescing for reboot.\n");
43857c478bd9Sstevel@tonic-gate 		(void) pause();
43867c478bd9Sstevel@tonic-gate 		return (-1);
43877c478bd9Sstevel@tonic-gate 	}
43887c478bd9Sstevel@tonic-gate 
43897c478bd9Sstevel@tonic-gate 	err = ct_pr_tmpl_set_transfer(tmpl, old_ctid);
43907c478bd9Sstevel@tonic-gate 	if (err == EINVAL) {
43917c478bd9Sstevel@tonic-gate 		console(B_TRUE, "Remake startd_tmpl; reattempt transfer.\n");
43927c478bd9Sstevel@tonic-gate 		tmpl = startd_tmpl = contract_make_template(0, CT_PR_EV_EMPTY,
43937c478bd9Sstevel@tonic-gate 		    CT_PR_EV_HWERR, STARTD_COOKIE);
43947c478bd9Sstevel@tonic-gate 
43957c478bd9Sstevel@tonic-gate 		err = ct_pr_tmpl_set_transfer(tmpl, old_ctid);
43967c478bd9Sstevel@tonic-gate 	}
43977c478bd9Sstevel@tonic-gate 	if (err != 0) {
43987c478bd9Sstevel@tonic-gate 		console(B_TRUE,
43997c478bd9Sstevel@tonic-gate 		    "Couldn't set transfer parameter of contract template: "
44007c478bd9Sstevel@tonic-gate 		    "%s.\n", strerror(err));
44017c478bd9Sstevel@tonic-gate 	}
44027c478bd9Sstevel@tonic-gate 
44037b209c2cSacruz 	if ((err = ct_pr_tmpl_set_svc_fmri(startd_tmpl,
44047b209c2cSacruz 	    SCF_SERVICE_STARTD)) != 0)
44057b209c2cSacruz 		console(B_TRUE,
44067b209c2cSacruz 		    "Can not set svc_fmri in contract template: %s\n",
44077b209c2cSacruz 		    strerror(err));
44087b209c2cSacruz 	if ((err = ct_pr_tmpl_set_svc_aux(startd_tmpl,
44097b209c2cSacruz 	    startd_svc_aux)) != 0)
44107b209c2cSacruz 		console(B_TRUE,
44117b209c2cSacruz 		    "Can not set svc_aux in contract template: %s\n",
44127b209c2cSacruz 		    strerror(err));
44137c478bd9Sstevel@tonic-gate 	did_activate = !(ct_tmpl_activate(tmpl));
44147c478bd9Sstevel@tonic-gate 	if (!did_activate)
44157c478bd9Sstevel@tonic-gate 		console(B_TRUE,
44167c478bd9Sstevel@tonic-gate 		    "Template activation failed; not starting \"%s\" in "
44177c478bd9Sstevel@tonic-gate 		    "proper contract.\n", cline);
44187c478bd9Sstevel@tonic-gate 
4419c39ec064SRoger A. Faulkner 	/* Hold SIGCLD so we can wait if necessary. */
4420c39ec064SRoger A. Faulkner 	(void) sighold(SIGCLD);
44217c478bd9Sstevel@tonic-gate 
44227c478bd9Sstevel@tonic-gate 	while ((pid = fork()) < 0) {
44237c478bd9Sstevel@tonic-gate 		if (errno == EPERM) {
44247c478bd9Sstevel@tonic-gate 			console(B_TRUE, "Insufficient permission to fork.\n");
44257c478bd9Sstevel@tonic-gate 
44267c478bd9Sstevel@tonic-gate 			/* Now that's a doozy. */
44277c478bd9Sstevel@tonic-gate 			exit(1);
44287c478bd9Sstevel@tonic-gate 		}
44297c478bd9Sstevel@tonic-gate 
44307c478bd9Sstevel@tonic-gate 		console(B_TRUE,
44317c478bd9Sstevel@tonic-gate 		    "fork() for svc.startd failed: %s.  Will retry in 1 "
44327c478bd9Sstevel@tonic-gate 		    "second...\n", strerror(errno));
44337c478bd9Sstevel@tonic-gate 
44347c478bd9Sstevel@tonic-gate 		(void) sleep(1);
44357c478bd9Sstevel@tonic-gate 
44367c478bd9Sstevel@tonic-gate 		/* Eventually give up? */
44377c478bd9Sstevel@tonic-gate 	}
44387c478bd9Sstevel@tonic-gate 
44397c478bd9Sstevel@tonic-gate 	if (pid == 0) {
44407c478bd9Sstevel@tonic-gate 		/* child */
44417c478bd9Sstevel@tonic-gate 
44427c478bd9Sstevel@tonic-gate 		/* See the comment in efork() */
44437c478bd9Sstevel@tonic-gate 		for (i = SIGHUP; i <= SIGRTMAX; ++i) {
44447c478bd9Sstevel@tonic-gate 			if (i == SIGTTOU || i == SIGTTIN || i == SIGTSTP)
44457c478bd9Sstevel@tonic-gate 				(void) sigset(i, SIG_IGN);
44467c478bd9Sstevel@tonic-gate 			else
44477c478bd9Sstevel@tonic-gate 				(void) sigset(i, SIG_DFL);
44487c478bd9Sstevel@tonic-gate 		}
44497c478bd9Sstevel@tonic-gate 
44507c478bd9Sstevel@tonic-gate 		if (smf_options != NULL) {
44517c478bd9Sstevel@tonic-gate 			/* Put smf_options in the environment. */
44527c478bd9Sstevel@tonic-gate 			glob_envp[glob_envn] =
44537c478bd9Sstevel@tonic-gate 			    malloc(sizeof ("SMF_OPTIONS=") - 1 +
445448847494SEnrico Perla - Sun Microsystems 			    strlen(smf_options) + 1);
44557c478bd9Sstevel@tonic-gate 
44567c478bd9Sstevel@tonic-gate 			if (glob_envp[glob_envn] != NULL) {
44577c478bd9Sstevel@tonic-gate 				/* LINTED */
44587c478bd9Sstevel@tonic-gate 				(void) sprintf(glob_envp[glob_envn],
44597c478bd9Sstevel@tonic-gate 				    "SMF_OPTIONS=%s", smf_options);
44607c478bd9Sstevel@tonic-gate 				glob_envp[glob_envn+1] = NULL;
44617c478bd9Sstevel@tonic-gate 			} else {
44627c478bd9Sstevel@tonic-gate 				console(B_TRUE,
44637c478bd9Sstevel@tonic-gate 				    "Could not set SMF_OPTIONS (%s).\n",
44647c478bd9Sstevel@tonic-gate 				    strerror(errno));
44657c478bd9Sstevel@tonic-gate 			}
44667c478bd9Sstevel@tonic-gate 		}
44677c478bd9Sstevel@tonic-gate 
44687c478bd9Sstevel@tonic-gate 		if (smf_debug)
44697c478bd9Sstevel@tonic-gate 			console(B_TRUE, "Executing svc.startd\n");
44707c478bd9Sstevel@tonic-gate 
44717c478bd9Sstevel@tonic-gate 		(void) execle(SH, "INITSH", "-c", cline, NULL, glob_envp);
44727c478bd9Sstevel@tonic-gate 
44737c478bd9Sstevel@tonic-gate 		console(B_TRUE, "Could not exec \"%s\" (%s).\n", SH,
44747c478bd9Sstevel@tonic-gate 		    strerror(errno));
44757c478bd9Sstevel@tonic-gate 
44767c478bd9Sstevel@tonic-gate 		exit(1);
44777c478bd9Sstevel@tonic-gate 	}
44787c478bd9Sstevel@tonic-gate 
44797c478bd9Sstevel@tonic-gate 	/* parent */
44807c478bd9Sstevel@tonic-gate 
44817c478bd9Sstevel@tonic-gate 	if (did_activate) {
44827c478bd9Sstevel@tonic-gate 		if (legacy_tmpl < 0 || ct_tmpl_activate(legacy_tmpl) != 0)
44837c478bd9Sstevel@tonic-gate 			(void) ct_tmpl_clear(tmpl);
44847c478bd9Sstevel@tonic-gate 	}
44857c478bd9Sstevel@tonic-gate 
44867c478bd9Sstevel@tonic-gate 	/* Clear the old_ctid reference so the kernel can reclaim it. */
44877c478bd9Sstevel@tonic-gate 	if (old_ctid != 0)
44887c478bd9Sstevel@tonic-gate 		(void) ct_pr_tmpl_set_transfer(tmpl, 0);
44897c478bd9Sstevel@tonic-gate 
4490c39ec064SRoger A. Faulkner 	(void) sigrelse(SIGCLD);
44917c478bd9Sstevel@tonic-gate 
44927c478bd9Sstevel@tonic-gate 	return (0);
44937c478bd9Sstevel@tonic-gate }
44947c478bd9Sstevel@tonic-gate 
44957c478bd9Sstevel@tonic-gate /*
44967c478bd9Sstevel@tonic-gate  * void startd_record_failure(void)
44977c478bd9Sstevel@tonic-gate  *   Place the current time in our circular array of svc.startd failures.
44987c478bd9Sstevel@tonic-gate  */
44997c478bd9Sstevel@tonic-gate void
45007c478bd9Sstevel@tonic-gate startd_record_failure()
45017c478bd9Sstevel@tonic-gate {
45027c478bd9Sstevel@tonic-gate 	int index = startd_failure_index++ % NSTARTD_FAILURE_TIMES;
45037c478bd9Sstevel@tonic-gate 
45047c478bd9Sstevel@tonic-gate 	startd_failure_time[index] = gethrtime();
45057c478bd9Sstevel@tonic-gate }
45067c478bd9Sstevel@tonic-gate 
45077c478bd9Sstevel@tonic-gate /*
45087c478bd9Sstevel@tonic-gate  * int startd_failure_rate_critical(void)
45097c478bd9Sstevel@tonic-gate  *   Return true if the average failure interval is less than the permitted
45107c478bd9Sstevel@tonic-gate  *   interval.  Implicit success if insufficient measurements for an average
45117c478bd9Sstevel@tonic-gate  *   exist.
45127c478bd9Sstevel@tonic-gate  */
45137c478bd9Sstevel@tonic-gate int
45147c478bd9Sstevel@tonic-gate startd_failure_rate_critical()
45157c478bd9Sstevel@tonic-gate {
45167c478bd9Sstevel@tonic-gate 	int n = startd_failure_index;
45177c478bd9Sstevel@tonic-gate 	hrtime_t avg_ns = 0;
45187c478bd9Sstevel@tonic-gate 
45197c478bd9Sstevel@tonic-gate 	if (startd_failure_index < NSTARTD_FAILURE_TIMES)
45207c478bd9Sstevel@tonic-gate 		return (0);
45217c478bd9Sstevel@tonic-gate 
45227c478bd9Sstevel@tonic-gate 	avg_ns =
45237c478bd9Sstevel@tonic-gate 	    (startd_failure_time[(n - 1) % NSTARTD_FAILURE_TIMES] -
45247c478bd9Sstevel@tonic-gate 	    startd_failure_time[n % NSTARTD_FAILURE_TIMES]) /
45257c478bd9Sstevel@tonic-gate 	    NSTARTD_FAILURE_TIMES;
45267c478bd9Sstevel@tonic-gate 
45277c478bd9Sstevel@tonic-gate 	return (avg_ns < STARTD_FAILURE_RATE_NS);
45287c478bd9Sstevel@tonic-gate }
45297c478bd9Sstevel@tonic-gate 
45307c478bd9Sstevel@tonic-gate /*
45317c478bd9Sstevel@tonic-gate  * returns string that must be free'd
45327c478bd9Sstevel@tonic-gate  */
45337c478bd9Sstevel@tonic-gate 
45347c478bd9Sstevel@tonic-gate static char
45357c478bd9Sstevel@tonic-gate *audit_boot_msg()
45367c478bd9Sstevel@tonic-gate {
45377c478bd9Sstevel@tonic-gate 	char		*b, *p;
45387c478bd9Sstevel@tonic-gate 	char		desc[] = "booted";
45397c478bd9Sstevel@tonic-gate 	zoneid_t	zid = getzoneid();
45407c478bd9Sstevel@tonic-gate 
45417c478bd9Sstevel@tonic-gate 	b = malloc(sizeof (desc) + MAXNAMELEN + 3);
45427c478bd9Sstevel@tonic-gate 	if (b == NULL)
45437c478bd9Sstevel@tonic-gate 		return (b);
45447c478bd9Sstevel@tonic-gate 
45457c478bd9Sstevel@tonic-gate 	p = b;
45467c478bd9Sstevel@tonic-gate 	p += strlcpy(p, desc, sizeof (desc));
45477c478bd9Sstevel@tonic-gate 	if (zid != GLOBAL_ZONEID) {
45487c478bd9Sstevel@tonic-gate 		p += strlcpy(p, ": ", 3);
45497c478bd9Sstevel@tonic-gate 		(void) getzonenamebyid(zid, p, MAXNAMELEN);
45507c478bd9Sstevel@tonic-gate 	}
45517c478bd9Sstevel@tonic-gate 	return (b);
45527c478bd9Sstevel@tonic-gate }
45537c478bd9Sstevel@tonic-gate 
45547c478bd9Sstevel@tonic-gate /*
45557c478bd9Sstevel@tonic-gate  * Generate AUE_init_solaris audit record.  Return 1 if
45567c478bd9Sstevel@tonic-gate  * auditing is enabled in case the caller cares.
45577c478bd9Sstevel@tonic-gate  *
45587c478bd9Sstevel@tonic-gate  * In the case of userint() or a local zone invocation of
45597c478bd9Sstevel@tonic-gate  * one_true_init, the process initially contains the audit
45607c478bd9Sstevel@tonic-gate  * characteristics of the process that invoked init.  The first pass
45617c478bd9Sstevel@tonic-gate  * through here uses those characteristics then for the case of
45627c478bd9Sstevel@tonic-gate  * one_true_init in a local zone, clears them so subsequent system
45637c478bd9Sstevel@tonic-gate  * state changes won't be attributed to the person who booted the
45647c478bd9Sstevel@tonic-gate  * zone.
45657c478bd9Sstevel@tonic-gate  */
45667c478bd9Sstevel@tonic-gate static int
45677c478bd9Sstevel@tonic-gate audit_put_record(int pass_fail, int status, char *msg)
45687c478bd9Sstevel@tonic-gate {
45697c478bd9Sstevel@tonic-gate 	adt_session_data_t	*ah;
45707c478bd9Sstevel@tonic-gate 	adt_event_data_t	*event;
45717c478bd9Sstevel@tonic-gate 
45727c478bd9Sstevel@tonic-gate 	if (!adt_audit_enabled())
45737c478bd9Sstevel@tonic-gate 		return (0);
45747c478bd9Sstevel@tonic-gate 
45757c478bd9Sstevel@tonic-gate 	/*
45767c478bd9Sstevel@tonic-gate 	 * the PROC_DATA picks up the context to tell whether this is
45777c478bd9Sstevel@tonic-gate 	 * an attributed record (auid = -2 is unattributed)
45787c478bd9Sstevel@tonic-gate 	 */
45797c478bd9Sstevel@tonic-gate 	if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA)) {
45807c478bd9Sstevel@tonic-gate 		console(B_TRUE, "audit failure:  %s\n", strerror(errno));
45817c478bd9Sstevel@tonic-gate 		return (1);
45827c478bd9Sstevel@tonic-gate 	}
45837c478bd9Sstevel@tonic-gate 	event = adt_alloc_event(ah, ADT_init_solaris);
45847c478bd9Sstevel@tonic-gate 	if (event == NULL) {
45857c478bd9Sstevel@tonic-gate 		console(B_TRUE, "audit failure:  %s\n", strerror(errno));
45867c478bd9Sstevel@tonic-gate 		(void) adt_end_session(ah);
45877c478bd9Sstevel@tonic-gate 		return (1);
45887c478bd9Sstevel@tonic-gate 	}
45897c478bd9Sstevel@tonic-gate 	event->adt_init_solaris.info = msg;	/* NULL is ok here */
45907c478bd9Sstevel@tonic-gate 
45917c478bd9Sstevel@tonic-gate 	if (adt_put_event(event, pass_fail, status)) {
45927c478bd9Sstevel@tonic-gate 		console(B_TRUE, "audit failure:  %s\n", strerror(errno));
45937c478bd9Sstevel@tonic-gate 		(void) adt_end_session(ah);
45947c478bd9Sstevel@tonic-gate 		return (1);
45957c478bd9Sstevel@tonic-gate 	}
45967c478bd9Sstevel@tonic-gate 	adt_free_event(event);
45977c478bd9Sstevel@tonic-gate 
45987c478bd9Sstevel@tonic-gate 	(void) adt_end_session(ah);
45997c478bd9Sstevel@tonic-gate 
46007c478bd9Sstevel@tonic-gate 	return (1);
46017c478bd9Sstevel@tonic-gate }
4602