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