init.c revision 05fc5e5bf1bd330914669ff21940f37885c2b20a
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * CDDL HEADER START
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * The contents of this file are subject to the terms of the
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Common Development and Distribution License (the "License").
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * You may not use this file except in compliance with the License.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * See the License for the specific language governing permissions
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * and limitations under the License.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * When distributing Covered Code, include this CDDL HEADER in each
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * If applicable, add the following below this CDDL HEADER, with the
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * fields enclosed by brackets "[]" replaced with your own identifying
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * information: Portions Copyright [yyyy] [name of copyright owner]
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * CDDL HEADER END
d618d68dcf9c6c8f2c1e2fbbd4de1de0cf30150ePriya Krishnan * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
57ff5e7e2f79bd09ccd01cdeba02f38fdde17a80Jeff Biseda * Use is subject to license terms.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap/* All Rights Reserved */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * University Copyright- Copyright (c) 1982, 1986, 1988
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * The Regents of the University of California
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * All Rights Reserved
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * University Acknowledgment- Portions of this document are derived from
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * software developed by the University of California, Berkeley, and its
30e7468f8f41aa30ada067b2c1d5d284046514daPeter Dunlap * contributors.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * init(1M) is the general process spawning program. Its primary job is to
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * start and restart svc.startd for smf(5). For backwards-compatibility it also
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * spawns and respawns processes according to /etc/inittab and the current
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * run-level. It reads /etc/default/inittab for general configuration.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * To change run-levels the system administrator runs init from the command
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * line with a level name. init signals svc.startd via libscf and directs the
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * zone's init (pid 1 in the global zone) what to do by sending it a signal;
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * these signal numbers are commonly refered to in the code as 'states'. Valid
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * run-levels are [sS0123456]. Additionally, init can be given directives
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * [qQabc], which indicate actions to be taken pertaining to /etc/inittab.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * When init processes inittab entries, it finds processes that are to be
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * spawned at various run-levels. inittab contains the set of the levels for
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * which each inittab entry is valid.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * State File and Restartability
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Premature exit by init(1M) is handled as a special case by the kernel:
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * init(1M) will be immediately re-executed, retaining its original PID. (PID
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * 1 in the global zone.) To track the processes it has previously spawned,
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * as well as other mutable state, init(1M) regularly updates a state file
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * such that its subsequent invocations have knowledge of its various
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * dependent processes and duties.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Process Contracts
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * We start svc.startd(1M) in a contract and transfer inherited contracts when
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * restarting it. Everything else is started using the legacy contract
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * template, and the created contracts are abandoned when they become empty.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * utmpx Entry Handling
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Because init(1M) no longer governs the startup process, its knowledge of
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * when utmpx becomes writable is indirect. However, spawned processes
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * expect to be constructed with valid utmpx entries. As a result, attempts
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * to write normal entries will be retried until successful.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Maintenance Mode
e42a0851889d583925aa3bd2d9bd139189031cb0peter dunlap * In certain failure scenarios, init(1M) will enter a maintenance mode, in
e42a0851889d583925aa3bd2d9bd139189031cb0peter dunlap * which it invokes sulogin(1M) to allow the operator an opportunity to
e42a0851889d583925aa3bd2d9bd139189031cb0peter dunlap * repair the system. Normally, this operation is performed as a
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States * fork(2)-exec(2)-waitpid(3C) sequence with the parent waiting for repair or
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States * diagnosis to be completed. In the cases that fork(2) requests themselves
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States * fail, init(1M) will directly execute sulogin(1M), and allow the kernel to
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States * restart init(1M) on exit from the operator session.
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States *
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States * One scenario where init(1M) enters its maintenance mode is when
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States * svc.startd(1M) begins to fail rapidly, defined as when the average time
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States * between recent failures drops below a given threshold.
30e7468f8f41aa30ada067b2c1d5d284046514daPeter Dunlap#define fioctl(p, sptr, cmd) ioctl(fileno(p), sptr, cmd)
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap#define min(a, b) (((a) < (b)) ? (a) : (b))
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap#define UT_LINE_SZ 32 /* Size of a utmpx ut_line field */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * SLEEPTIME The number of seconds "init" sleeps between wakeups if
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * nothing else requires this "init" wakeup.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * MAXCMDL The maximum length of a command string in inittab.
1050fd6d7cf8ededf1816f2b4d8e5d047410260cJames Moore * EXEC The length of the prefix string added to all comamnds
1050fd6d7cf8ededf1816f2b4d8e5d047410260cJames Moore * found in inittab.
1050fd6d7cf8ededf1816f2b4d8e5d047410260cJames Moore * TWARN The amount of time between warning signal, SIGTERM,
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * and the fatal kill signal, SIGKILL.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap#define id_eq(x, y) ((x[0] == y[0] && x[1] == y[1] && x[2] == y[2] &&\
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * The kernel's default umask is 022 these days; since some processes inherit
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * their umask from init, init will set it from CMASK in /etc/default/init.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * init gets the default umask from the kernel, it sets it to 022 whenever
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * it wants to create a file and reverts to CMASK afterwards.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * The following definitions, concluding with the 'lvls' array, provide a
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * common mapping between level-name (like 'S'), signal number (state),
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * run-level mask, and specific properties associated with a run-level.
30e7468f8f41aa30ada067b2c1d5d284046514daPeter Dunlap * This array should be accessed using the routines lvlname_to_state(),
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * lvlname_to_mask(), state_to_mask(), and state_to_flags().
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Correspondence of signals to init actions.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Bit Mask for each level. Used to determine legal levels.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap#define MASK_NUMERIC (MASK0 | MASK1 | MASK2 | MASK3 | MASK4 | MASK5 | MASK6)
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Flags to indicate properties of various states.
30e7468f8f41aa30ada067b2c1d5d284046514daPeter Dunlap#define LSEL_RUNLEVEL 0x0001 /* runlevels you can transition to */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlaptypedef struct lvl {
92adbba74606fdfb5f11be2a6497e53ff2224507Peter Cudhea - Sun Microsystems - Burlington, MA United States int lvl_flags;
92adbba74606fdfb5f11be2a6497e53ff2224507Peter Cudhea - Sun Microsystems - Burlington, MA United States} lvl_t;
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap#define LVL_NELEMS (sizeof (lvls) / sizeof (lvl_t))
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Legal action field values.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap#define OFF 0 /* Kill process if on, else ignore */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap#define RESPAWN 1 /* Continuously restart process when it dies */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap#define ONDEMAND RESPAWN /* Respawn for a, b, c type processes */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap#define ONCE 2 /* Start process, do not respawn when dead */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap#define WAIT 3 /* Perform once and wait to complete */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap#define BOOTWAIT 5 /* Start at boot time and wait to complete */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap#define POWERWAIT 7 /* Start and wait for complete on powerfail */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap#define INITDEFAULT 8 /* Default level "init" should start at */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap#define SYSINIT 9 /* Actions performed before init speaks */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap/* States for the inittab parser in getcmd(). */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * inittab entry id constants
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap#define INITTAB_ENTRY_ID_STR_FORMAT "%.4s" /* if INITTAB_ENTRY_ID_SIZE */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap /* changes, this should */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap /* change accordingly */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Init can be in any of three main states, "normal" mode where it is
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * processing entries for the lines file in a normal fashion, "boot" mode,
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * where it is only interested in the boot actions, and "powerfail" mode,
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * where it is only interested in powerfail related actions. The following
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * masks declare the legal actions for each mode.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap#define NORMAL_MODES (M_OFF | M_RESPAWN | M_ONCE | M_WAIT)
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap char p_id[INITTAB_ENTRY_ID_SIZE]; /* Four letter unique id of */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap /* process */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap short p_count; /* How many respawns of this command in */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap /* the current series */
30e7468f8f41aa30ada067b2c1d5d284046514daPeter Dunlap long p_time; /* Start time for a series of respawns */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap short p_exit; /* Exit status of a process which died */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Flags for the "p_flags" word of a PROC_TABLE entry:
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * OCCUPIED This slot in init's proc table is in use.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * LIVING Process is alive.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * NOCLEANUP efork() is not allowed to cleanup this entry even
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * if process is dead.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * NAMED This process has a name, i.e. came from inittab.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * DEMANDREQUEST Process started by a "telinit [abc]" command. Processes
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * formed this way are respawnable and immune to level
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * changes as long as their entry exists in inittab.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * TOUCHED Flag used by remv() to determine whether it has looked
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * at an entry while checking for processes to be killed.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * WARNED Flag used by remv() to mark processes that have been
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * sent the SIGTERM signal. If they don't die in 5
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * seconds, they are sent the SIGKILL signal.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * KILLED Flag used by remv() to mark procs that have been sent
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * the SIGTERM and SIGKILL signals.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * PF_MASK Bitwise or of legal flags, for sanity checking.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Respawn limits for processes that are to be respawned:
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * SPAWN_INTERVAL The number of seconds over which "init" will try to
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * respawn a process SPAWN_LIMIT times before it gets mad.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * SPAWN_LIMIT The number of respawns "init" will attempt in
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * SPAWN_INTERVAL seconds before it generates an
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * error message and inhibits further tries for
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * INHIBIT seconds.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * INHIBIT The number of seconds "init" ignores an entry it had
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * trouble spawning unless a "telinit Q" is received.
e42a0851889d583925aa3bd2d9bd139189031cb0peter dunlap * The maximum number of decimal digits for an id_t. (ceil(log10 (max_id)))
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States#define ID_MAX_STR_LEN 10
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States#define NULLPROC ((struct PROC_TABLE *)(0))
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap#define NO_ROOM ((struct PROC_TABLE *)(FAILURE))
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap char c_id[INITTAB_ENTRY_ID_SIZE]; /* Four letter unique id of */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap /* process to be affected by */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap /* action */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap short c_levels; /* Mask of legal levels for process */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap short c_action; /* Mask for type of action required */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic struct pidlist {
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap int pl_dflag; /* Flag indicating SIGCLD from this pid */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * The following structure contains a set of modes for /dev/syscon
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * and should match the default contents of /etc/ioctl.syscon.
30e7468f8f41aa30ada067b2c1d5d284046514daPeter Dunlap ISIG|ICANON|ECHO|ECHOE|ECHOK|ECHOCTL|ECHOKE|IEXTEN, /* lflag */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap 0, 0, 0, 0, 0, 0, 0, 0,
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic int write_ioctl = 0; /* Rewrite /etc/ioctl.syscon */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic union WAKEUP {
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap unsigned w_usersignal : 1; /* User sent signal to "init" */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap unsigned w_childdeath : 1; /* An "init" child died */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap unsigned w_powerhit : 1; /* OS experienced powerfail */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap/* Contract cookies. */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap (void) fprintf(stderr, "%s:%d: %s() failed with unexpected " \
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap "error %d. Aborting.\n", __FILE__, __LINE__, (func), (err)); \
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Useful file and device names.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic char *CONSOLE = "/dev/console"; /* Real system console */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic const char * const init_state_file = INIT_STATE_DIR "/init.state";
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic const char * const init_next_state_file =
5f7d09c6770c7413ed11bfa981c6d50666ca0f4dPeter Cudhea - Sun Microsystems - Burlington, MA United States INIT_STATE_DIR "/init-next.state";
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic const int init_num_proc = 20; /* Initial size of process table. */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic char *UTMPX = UTMPX_FILE; /* Snapshot record file */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic char *WTMPX = WTMPX_FILE; /* Long term record file */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic char *INITTAB = "/etc/inittab"; /* Script file for "init" */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic char *SYSTTY = "/dev/systty"; /* System Console */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic char *SYSCON = "/dev/syscon"; /* Virtual System console */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic char *IOCTLSYSCON = "/etc/ioctl.syscon"; /* Last syscon modes */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic char *ENVFILE = "/etc/default/init"; /* Default env. */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic char *SU = "/etc/sulogin"; /* Super-user program for single user */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic char *SH = "/sbin/sh"; /* Standard shell */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Default Path. /sbin is included in path only during sysinit phase
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap#define INIT_PATH "PATH=/sbin:/usr/sbin:/usr/bin"
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic int prev_state; /* State "init" was in last time it woke */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic int new_state; /* State user wants "init" to go to. */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic int lvlq_received; /* Explicit request to examine state */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic int op_modes = BOOT_MODES; /* Current state of "init" */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic int Gchild = 0; /* Flag to indicate "godchild" died, set in */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap /* childeath() and cleared in cleanaux() */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic int Pfd = -1; /* fd to receive pids thru */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic int rsflag; /* Set if a respawn has taken place */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic volatile int time_up; /* Flag set to TRUE by the alarm interrupt */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap /* routine each time an alarm interrupt */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap /* takes place. */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic int sflg = 0; /* Set if we were booted -s to single user */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic int rflg = 0; /* Set if booted -r, reconfigure devices */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic int bflg = 0; /* Set if booted -b, don't run rc scripts */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic pid_t init_pid; /* PID of "one true" init for current zone */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic int booting = 1; /* Set while we're booting. */
e42a0851889d583925aa3bd2d9bd139189031cb0peter dunlap * Array for default global environment.
e42a0851889d583925aa3bd2d9bd139189031cb0peter dunlap#define MAXENVENT 24 /* Max number of default env variables + 1 */
e42a0851889d583925aa3bd2d9bd139189031cb0peter dunlap /* init can use three itself, so this leaves */
e42a0851889d583925aa3bd2d9bd139189031cb0peter dunlap /* 20 for the administrator in ENVFILE. */
e42a0851889d583925aa3bd2d9bd139189031cb0peter dunlapstatic char *glob_envp[MAXENVENT]; /* Array of environment strings */
e42a0851889d583925aa3bd2d9bd139189031cb0peter dunlapstatic int glob_envn; /* Number of environment strings */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic int poll_nfds = 0; /* poll_fds is uninitialized */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Contracts constants
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap#define SVC_AUX_SIZE (INITTAB_ENTRY_ID_SIZE + 1)
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap#define SVC_FMRI_SIZE (sizeof (SVC_INIT_PREFIX) + INITTAB_ENTRY_ID_SIZE)
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic int legacy_tmpl = -1; /* fd for legacy contract template */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic int startd_tmpl = -1; /* fd for svc.startd's template */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic char startd_cline[256] = ""; /* svc.startd's command line */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic int do_restart_startd = 1; /* Whether to restart svc.startd. */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic char *smf_options = NULL; /* Options to give to startd. */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic int smf_debug = 0; /* Messages for debugging smf(5) */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic time_t init_boot_time; /* Substitute for kernel boot time. */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap#define NSTARTD_FAILURE_TIMES 3 /* trigger after 3 failures */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap#define STARTD_FAILURE_RATE_NS 5000000000LL /* 1 failure/5 seconds */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic hrtime_t startd_failure_time[NSTARTD_FAILURE_TIMES];
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic char *prog_name(char *);
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United Statesstatic int state_to_mask(int);
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United Statesstatic int lvlname_to_mask(char, int *);
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic void lscf_set_runlevel(char);
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic int state_to_flags(int);
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic char state_to_name(int);
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic int lvlname_to_state(char);
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic int account(short, struct PROC_TABLE *, char *);
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic void alarmclk();
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic void childeath(int);
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic void cleanaux();
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic void init_signals(void);
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic void init_env();
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United Statesstatic void boot_init();
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic void remv();
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic void spawn(struct PROC_TABLE *, struct CMD_LINE *);
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic void setimer(int);
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic void siglvl(int, siginfo_t *, ucontext_t *);
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic void sigpoll(int);
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United Statesstatic void enter_maintenance(void);
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United Statesstatic void timer(int);
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United Statesstatic void userinit(int, char **);
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United Statesstatic struct PROC_TABLE *efork(int, struct PROC_TABLE *, int);
30e7468f8f41aa30ada067b2c1d5d284046514daPeter Dunlapstatic struct PROC_TABLE *findpslot(struct CMD_LINE *);
30e7468f8f41aa30ada067b2c1d5d284046514daPeter Dunlapstatic void st_init();
30e7468f8f41aa30ada067b2c1d5d284046514daPeter Dunlapstatic void st_write();
30e7468f8f41aa30ada067b2c1d5d284046514daPeter Dunlapstatic int startd_run(const char *, int, ctid_t);
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic int audit_put_record(int, int, char *);
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap int chg_lvl_flag = FALSE, print_banner = FALSE;
47715e7fd18d93fbdad6de94604baaa63665f0fbPriya Krishnan /* Get a timestamp for use as boot time, if needed. */
47715e7fd18d93fbdad6de94604baaa63665f0fbPriya Krishnan /* Get the default umask */
47715e7fd18d93fbdad6de94604baaa63665f0fbPriya Krishnan /* Parse the arguments to init. Check for single user */
47715e7fd18d93fbdad6de94604baaa63665f0fbPriya Krishnan while ((c = getopt(argc, argv, "brsm:")) != EOF) {
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States if (!sflg)
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap smf_debug = (strstr(smf_options, "debug") != NULL);
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Determine if we are the main init, or a user invoked init, whose job
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * it is to inform init to change levels or perform some other action.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap if (zone_getattr(getzoneid(), ZONE_ATTR_INITPID, &init_pid,
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap (void) fprintf(stderr, "could not get pid for init\n");
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * If this PID is not the same as the "true" init for the zone, then we
d618d68dcf9c6c8f2c1e2fbbd4de1de0cf30150ePriya Krishnan * must be in 'user' mode.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Initialize state (and set "booting").
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * We want to print the boot banner as soon as
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * possible. In the global zone, the kernel does it,
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * but we do not have that luxury in non-global zones,
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * so we will print it here.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap "\n\n%s Release %s Version %s %d-bit\r\n",
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap "Copyright 1983-2009 Sun Microsystems, Inc. "
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap " All rights reserved.\r\n");
92adbba74606fdfb5f11be2a6497e53ff2224507Peter Cudhea - Sun Microsystems - Burlington, MA United States console(B_FALSE,
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap "Use is subject to license terms.\r\n");
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Get the ioctl settings for /dev/syscon from /etc/ioctl.syscon
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * so that it can be brought up in the state it was in when the
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * system went down; or set to defaults if ioctl.syscon isn't
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * This needs to be done even if we're restarting so reset_modes()
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * will work in case we need to go down to single user mode.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Set up all signals to be caught or ignored as appropriate.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap /* Load glob_envp from ENVFILE. */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap /* cur_state should have been read in. */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap /* Rewrite the ioctl file if it was bad. */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * It's fine to boot up with state as zero, because
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * startd will later tell us the real state.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Here is the beginning of the main process loop.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Clean up any accounting records for dead "godchildren".
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * If in "normal" mode, check all living processes and initiate
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * kill sequence on those that should not be there anymore.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap if (op_modes == NORMAL_MODES && cur_state != LVLa &&
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * If a change in run levels is the reason we awoke, now do
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * the accounting to report the change in the utmp file.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Also report the change on the system console.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap if (state_to_flags(cur_state) & LSEL_RUNLEVEL) {
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Scan the inittab file and spawn and respawn processes that
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * should be alive in the current state. If inittab does not
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * exist default to single user mode.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap /* If any respawns occurred, take note. */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * If a powerfail signal was received during the last
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * sequence, set mode to powerfail. When spawn_processes() is
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * entered the first thing it does is to check "powerhit". If
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * it is in PF_MODES then it clears "powerhit" and does
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * a powerfail sequence. If it is not in PF_MODES, then it
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * puts itself in PF_MODES and then clears "powerhit". Should
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * "powerhit" get set again while spawn_processes() is working
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * on a powerfail sequence, the following code will see that
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * spawn_processes() tries to execute the powerfail sequence
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * again. This guarantees that the powerfail sequence will be
92adbba74606fdfb5f11be2a6497e53ff2224507Peter Cudhea - Sun Microsystems - Burlington, MA United States * successfully completed before further processing takes
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Make sure that cur_state != prev_state so that
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * ONCE and WAIT types work.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * If spawn_processes() was not just called while in
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * normal mode, we set the mode to normal and it will
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * be called again to check normal modes. If we have
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * just finished a powerfail sequence with prev_state
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * equal to zero, we set prev_state equal to cur_state
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * before the next pass through.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap } else if (cur_state == LVLa || cur_state == LVLb ||
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * If it was a change of levels that awakened us and the
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * new level is one of the demand levels then reset
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * cur_state to the previous state and do another scan
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * to take care of the usual respawn actions.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * "init" is finished with all actions for
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * the current wakeup.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Install the new level. This could be a real
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * change in levels or a telinit [Q|a|b|c] or
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * just a telinit to the same level at which
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * we are running.
92adbba74606fdfb5f11be2a6497e53ff2224507Peter Cudhea - Sun Microsystems - Burlington, MA United States cur_state = new_state;
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Clear all wakeup reasons.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap /*NOTREACHED*/
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap if (new_state != LVL0 && new_state != LVL5 && new_state != LVL6)
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * void enter_maintenance()
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * A simple invocation of sulogin(1M), with no baggage, in the case that we
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * are unable to activate svc.startd(1M). We fork; the child runs sulogin;
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * we wait for it to exit.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap console(B_FALSE, "Requesting maintenance mode\n"
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap "(See /lib/svc/share/README for additional information.)\n");
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap while ((su_process = efork(M_OFF, NULLPROC, NOCLEANUP)) == NO_ROOM)
92adbba74606fdfb5f11be2a6497e53ff2224507Peter Cudhea - Sun Microsystems - Burlington, MA United States closefrom(0);
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Need to issue an error message somewhere.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap syslog(LOG_CRIT, "init[%d]: cannot open %s; %s\n",
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Execute the "su" program.
e42a0851889d583925aa3bd2d9bd139189031cb0peter dunlap (void) execle(SU, SU, "-", (char *)0, glob_envp);
e42a0851889d583925aa3bd2d9bd139189031cb0peter dunlap console(B_TRUE, "execle of %s failed: %s\n", SU,
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States timer(5);
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States exit(1);
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States }
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States /*
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States * If we are the parent, wait around for the child to die
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States * or for "init" to be signaled to change levels.
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States */
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States while (waitproc(su_process) == FAILURE) {
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States /*
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States * All other reasons for waking are ignored when in
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States * single-user mode. The only child we are interested
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States * in is being waited for explicitly by waitproc().
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States */
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States wakeup.w_mask = 0;
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States }
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States}
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States/*
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States * remv() scans through "proc_table" and performs cleanup. If
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States * there is a process in the table, which shouldn't be here at
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States * the current run level, then remv() kills the process.
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States */
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United Statesstatic void
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United Statesremv()
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States{
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States struct PROC_TABLE *process;
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States struct CMD_LINE cmd;
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States char cmd_string[MAXCMDL];
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States int change_level;
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States change_level = (cur_state != prev_state ? TRUE : FALSE);
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States /*
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States * Clear the TOUCHED flag on all entries so that when we have
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States * finished scanning inittab, we will be able to tell if we
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States * have any processes for which there is no entry in inittab.
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States */
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States for (process = proc_table;
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States (process < proc_table + num_proc); process++) {
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States process->p_flags &= ~TOUCHED;
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States /*
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States * Scan all inittab entries.
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap /* Scan for process which goes with this entry in inittab. */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap (process < proc_table + num_proc); process++) {
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * This slot contains the process we are looking for.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Is the cur_state SINGLE_USER or is this process
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * marked as "off" or was this proc started by some
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * mechanism other than LVL{a|b|c} and the current level
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * does not support this process?
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap ((cmd.c_levels & state_to_mask(cur_state)) == 0 &&
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Touch this entry so we know we have
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * treated it. Note that procs which
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * are already dead at this point and
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * should not be restarted are left
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * untouched. This causes their slot to
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * be freed later after dead accounting
92adbba74606fdfb5f11be2a6497e53ff2224507Peter Cudhea - Sun Microsystems - Burlington, MA United States if ((process->p_flags & KILLED) == 0) {
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Fork a killing proc
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * so "init" can
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * continue without
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * having to pause for
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * TWARN seconds.
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States process->p_flags |= KILLED;
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States }
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States }
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States } else {
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States /*
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States * Process can exist at current level. If it is
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * still alive or a DEMANDREQUEST we touch it so
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * it will be left alone. Otherwise we leave it
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * untouched so it will be accounted for and
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * cleaned up later in remv(). Dead
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * DEMANDREQUESTs will be accounted but not
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * If this was a change of levels call, scan through the
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * process table for processes that were warned to die. If any
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * are found that haven't left yet, sleep for TWARN seconds and
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * then send final terminations to any that haven't died yet.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Set the alarm for TWARN seconds on the assumption
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * that there will be some that need to be waited for.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * This won't harm anything except we are guaranteed to
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * wakeup in TWARN seconds whether we need to or not.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Scan for processes which should be dying. We hope they
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * will die without having to be sent a SIGKILL signal.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap (process < proc_table + num_proc); process++) {
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * If this process should die, hasn't yet, and the
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * TWARN time hasn't expired yet, wait for process
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * to die or for timer to expire.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap (process->p_flags & (WARNED|LIVING|OCCUPIED)) ==
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * If we reached the end of the table without the timer
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * expiring, then there are no procs which will have to be
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * sent the SIGKILL signal. If the timer has expired, then
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * it is necessary to scan the table again and send signals
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * to all processes which aren't going away nicely.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap (process < proc_table + num_proc); process++) {
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Rescan the proc_table for two kinds of entry, those marked LIVING,
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * NAMED, which don't have an entry in inittab (haven't been TOUCHED
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * by the above scanning), and haven't been sent kill signals, and
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * those entries marked not LIVING, NAMED. The former procs are killed.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * The latter have DEAD_PROCESS accounting done and the slot cleared.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap (process < proc_table + num_proc); process++) {
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap if ((process->p_flags & (LIVING|NAMED|TOUCHED|KILLED|OCCUPIED))
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap } else if ((process->p_flags & (LIVING|NAMED|OCCUPIED)) ==
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * If this named proc hasn't been TOUCHED, then free the
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * space. It has either died of it's own accord, but
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * isn't respawnable or it was killed because it
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * shouldn't exist at this level.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Extract the svc.startd command line and whether to restart it from its
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * inittab entry.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapprocess_startd_line(struct CMD_LINE *cmd, char *cmd_string)
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap /* Save the command line. */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap /* Also append -r or -s. */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap (void) strlcpy(startd_cline, cmd_string, sizeof (startd_cline));
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap (void) strlcat(startd_cline, " -", sizeof (startd_cline));
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap sz = strlcat(startd_cline, "s", sizeof (startd_cline));
5f7d09c6770c7413ed11bfa981c6d50666ca0f4dPeter Cudhea - Sun Microsystems - Burlington, MA United States if (rflg)
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap sz = strlcat(startd_cline, "r", sizeof (startd_cline));
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap sz = strlcpy(startd_cline, cmd_string, sizeof (startd_cline));
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap "svc.startd command line too long. Ignoring.\n");
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * spawn_processes() scans inittab for entries which should be run at this
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * mode. Processes which should be running but are not, are started.
92adbba74606fdfb5f11be2a6497e53ff2224507Peter Cudhea - Sun Microsystems - Burlington, MA United States struct PROC_TABLE *pp;
92adbba74606fdfb5f11be2a6497e53ff2224507Peter Cudhea - Sun Microsystems - Burlington, MA United States struct CMD_LINE cmd;
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * First check the "powerhit" flag. If it is set, make sure the modes
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * are PF_MODES and clear the "powerhit" flag. Avoid the possible race
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * on the "powerhit" flag by disallowing a new powerfail interrupt
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * between the test of the powerhit flag and the clearing of it.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Scan through all the entries in inittab.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap while ((status = getcmd(&cmd, &cmd_string[0])) == TRUE) {
e42a0851889d583925aa3bd2d9bd139189031cb0peter dunlap * Find out if there is a process slot for this entry already.
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States /*
e42a0851889d583925aa3bd2d9bd139189031cb0peter dunlap * we've run out of proc table entries
e42a0851889d583925aa3bd2d9bd139189031cb0peter dunlap * increase proc_table.
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States /*
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States * Retry now as we have an empty proc slot.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * In case increase_proc_table_size() fails,
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * we will keep retrying.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * If there is an entry, and it is marked as DEMANDREQUEST,
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * one of the levels a, b, or c is in its levels mask, and
30e7468f8f41aa30ada067b2c1d5d284046514daPeter Dunlap * the action field is ONDEMAND and ONDEMAND is a permissable
30e7468f8f41aa30ada067b2c1d5d284046514daPeter Dunlap * mode, and the process is dead, then respawn it.
30e7468f8f41aa30ada067b2c1d5d284046514daPeter Dunlap if (((pp->p_flags & (LIVING|DEMANDREQUEST)) == DEMANDREQUEST) &&
30e7468f8f41aa30ada067b2c1d5d284046514daPeter Dunlap * If the action is not an action we are interested in,
30e7468f8f41aa30ada067b2c1d5d284046514daPeter Dunlap * skip the entry.
30e7468f8f41aa30ada067b2c1d5d284046514daPeter Dunlap if ((cmd.c_action & op_modes) == 0 || pp->p_flags & LIVING ||
30e7468f8f41aa30ada067b2c1d5d284046514daPeter Dunlap * If the modes are the normal modes (ONCE, WAIT, RESPAWN, OFF,
30e7468f8f41aa30ada067b2c1d5d284046514daPeter Dunlap * ONDEMAND) and the action field is either OFF or the action
30e7468f8f41aa30ada067b2c1d5d284046514daPeter Dunlap * field is ONCE or WAIT and the current level is the same as
30e7468f8f41aa30ada067b2c1d5d284046514daPeter Dunlap * the last level, then skip this entry. ONCE and WAIT only
30e7468f8f41aa30ada067b2c1d5d284046514daPeter Dunlap * get run when the level changes.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * At this point we are interested in performing the action for
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * this entry. Actions fall into two categories, spinning off
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * a process and not waiting, and spinning off a process and
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * waiting for it to die. If the action is ONCE, RESPAWN,
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * ONDEMAND, POWERFAIL, or BOOT we don't wait for the process
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * to die, for all other actions we do wait.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap if (cmd.c_action & (M_ONCE | M_RESPAWN | M_PF | M_BOOT)) {
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * spawn() spawns a shell, inserts the information about the process
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States * process into the proc_table, and does the startup accounting.
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States */
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United Statesstatic void
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United Statesspawn(struct PROC_TABLE *process, struct CMD_LINE *cmd)
e97fb1537da57d70dafde456e25bbd6bcc839475Peter Cudhea - Sun Microsystems - Burlington, MA United States{
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * The modes to be sent to efork() are 0 unless we are
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * spawning a LVLa, LVLb, or LVLc entry or we will be
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * waiting for the death of the child before continuing.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap if (process->p_flags & DEMANDREQUEST || cur_state == LVLa ||
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap if ((cmd->c_action & (M_SYSINIT | M_WAIT | M_BOOTWAIT | M_PWAIT)) != 0)
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * If this is a respawnable process, check the threshold
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * information to avoid excessive respawns.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Add NOCLEANUP to all respawnable commands so that the
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * information about the frequency of respawns isn't lost.
e42a0851889d583925aa3bd2d9bd139189031cb0peter dunlap * If no time is assigned, then this is the first time
e42a0851889d583925aa3bd2d9bd139189031cb0peter dunlap * this command is being processed in this series. Assign
e42a0851889d583925aa3bd2d9bd139189031cb0peter dunlap * the current time.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap if ((now - process->p_time) < SPAWN_INTERVAL) {
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Process is respawning too rapidly. Print
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * message and refuse to respawn it for now.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap "rapidly. Check for possible errors.\n"
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap "id:%4s \"%s\"\n",
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * If process has been respawning too rapidly and
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * the inhibit time limit hasn't expired yet, we
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * refuse to respawn.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap if (now - process->p_time < SPAWN_INTERVAL + INHIBIT)
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Spawn a child process to execute this command.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap while ((process = efork(cmd->c_action, oprocess, modes)) == NO_ROOM)
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * We are the child. We must make sure we get a different
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * file pointer for our references to utmpx. Otherwise our
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * seeks and reads will compete with those of the parent.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Perform the accounting for the beginning of a process.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Note that all processes are initially "INIT_PROCESS"es.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap for (i = 0; i < maxfiles; i++)
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Now exec a shell with the -c option and the command
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * from inittab.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap (void) execle(SH, "INITSH", "-c", cmd->c_command, (char *)0,
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap console(B_TRUE, "Command\n\"%s\"\n failed to execute. errno "
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap "= %d (exec of shell failed)\n", cmd->c_command, errno);
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Don't come back so quickly that "init" doesn't have a
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * chance to finish putting this child in "proc_table".
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * We are the parent. Insert the necessary
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * information in the proc_table.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * findpslot() finds the old slot in the process table for the
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * command with the same id, or it finds an empty slot.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlapstatic struct PROC_TABLE *
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap (process < proc_table + num_proc); process++) {
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * If the entry is totally empty and "empty" is still 0,
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * remember where this hole is and make sure the slot is
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * zeroed out.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap if (empty == NULLPROC && (process->p_flags & OCCUPIED) == 0) {
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * If there is no entry for this slot, then there should be an
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * empty slot. If there is no empty slot, then we've run out
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * of proc_table space. If the latter is true, empty will be
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * NULL and the caller will have to complain.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * getcmd() parses lines from inittab. Each time it finds a command line
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * it will return TRUE as well as fill the passed CMD_LINE structure and
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * the shell command string. When the end of inittab is reached, FALSE
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * is returned inittab is automatically opened if it is not currently open
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * and is closed when the end of the file is reached.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap static char *actions[] = {
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap "off", "respawn", "ondemand", "once", "wait", "boot",
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap "bootwait", "powerfail", "powerwait", "initdefault",
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap static short act_masks[] = {
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap M_OFF, M_RESPAWN, M_ONDEMAND, M_ONCE, M_WAIT, M_BOOT,
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap M_BOOTWAIT, M_PF, M_PWAIT, M_INITDEFAULT, M_SYSINIT,
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Only these actions will be allowed for entries which
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * are specified for single-user mode.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap short su_acts = M_INITDEFAULT | M_PF | M_PWAIT | M_WAIT;
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Before attempting to open inittab we stat it to make
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * sure it currently exists and is not empty. We try
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * several times because someone may have temporarily
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * unlinked or truncated the file.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap for (i = 0; i < 3; i++) {
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap if (i == 2) {
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap "Cannot stat %s, errno: %d\n",
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap if (i == 2) {
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap "%s truncated or corrupted\n",
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * If unable to open inittab, print error message and
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * return FAILURE to caller.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap if ((fp_inittab = fopen(INITTAB, "r")) == NULL) {
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap console(B_TRUE, "Cannot open %s errno: %d\n", INITTAB,
5f7d09c6770c7413ed11bfa981c6d50666ca0f4dPeter Cudhea - Sun Microsystems - Burlington, MA United States * Keep getting commands from inittab until you find a
30e7468f8f41aa30ada067b2c1d5d284046514daPeter Dunlap * good one or run out of file.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Zero out the cmd itself before trying next line.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Read in lines of inittab, parsing at colons, until a line is
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * read in which doesn't end with a backslash. Do not start if
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * the first character read is an EOF. Note that this means
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * that lines which don't end in a newline are still processed,
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * since the "for" will terminate normally once started,
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * regardless of whether line terminates with a newline or EOF.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap for (proceed = TRUE, ptr = shcmd, state = ID, lastc = '\0';
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap /* If we're not in the FAILURE state and haven't */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap /* yet reached the shell command field, process */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap /* the line, otherwise just look for a real end */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap /* of line. */
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Squeeze out spaces and tabs.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Ignore characters in a comment, except for the \n.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap if (c == '\n') {
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Detect comments (lines whose first non-whitespace
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * character is '#') by checking that we're at the
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * beginning of a line, have seen a '#', and haven't
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * yet accumulated any characters.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * If the character is a ':', then check the
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * previous field for correctness and advance
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * to the next field.
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap if (c == ':') {
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * Check to see that there are only
a6d42e7d71324c5193c3b94d57d96ba2925d52e1Peter Dunlap * 1 to 4 characters for the id.
case LEVELS :
int mask;
case ACTION :
i < sizeof (actions)/sizeof (char *);
*ptr++ = (char)c;
if (c == EOF) {
return (answer);
for (i = 0; i < LVL_NELEMS; i++) {
for (i = 0; i < LVL_NELEMS; i++) {
for (i = 0; i < LVL_NELEMS; i++) {
for (i = 0; i < LVL_NELEMS; i++) {
for (i = 0; i < LVL_NELEMS; i++) {
(void) pause();
(void) exit(0);
init_env()
if (rflg) {
++glob_envn;
++glob_envn;
ENVFILE);
inquotes = 0;
if (inquotes == 0)
inquotes = 0;
if (inquotes == 0)
length--;
cmask = (int)t;
char *old_path;
int maxfiles;
* Scan inittab(4) and process the special svc.startd entry, initdefault
if (legacy_tmpl >= 0) {
(void) ct_pr_tmpl_set_svc_fmri(
(void) ct_pr_tmpl_set_svc_aux(
for (i = 0; i < maxfiles; i++)
(char *)0, glob_envp);
st_write();
booting = 0;
* If the /etc/ioctl.syscon didn't exist or had invalid contents write
if (write_ioctl)
* Start svc.startd(1M), which does most of the work.
/* Start svc.startd. */
"contract template. Not starting svc.startd.\n");
init_signals(void)
alarmclk();
if (Pfd >= 0)
if (Pfd >= 0) {
alarmclk()
int status;
while (pp) {
static struct PROC_TABLE *
void (*oldroutine)();
(OCCUPIED)) {
(void) pause();
setimer(0);
if (childpid != 0) {
return (NO_ROOM);
process =
st_write();
(void) setpgrp();
return (process);
int answer;
return (FAILURE);
return (answer);
access_utmpx(void)
return (utmpx_ok);
int tmplen;
u = &utmpbuf;
switch (state) {
case INIT_PROCESS:
endutxent();
endutxent();
setutxent();
endutxent();
string++;
string++) {
return (&word[0]);
realcon()
int i, valid_format = 0;
if (!valid_format)
return (!valid_format);
* we keep in stored_syscon_termios (which we read out of /etc/ioctl.syscon).
FILE *f;
if (prefix)
if (fd >= 0)
if (realcon())
if (prefix)
if (getret == 0)
(void) fclose(f);
(void) pause();
alarmclk();
scf_handle_t *h;
int ret = 0;
switch (scf_error()) {
return (ECONNABORTED);
case SCF_ERROR_NOT_FOUND:
goto out;
switch (scf_error()) {
goto out;
case SCF_ERROR_NOT_FOUND:
stderr);
switch (scf_error()) {
goto out;
case SCF_ERROR_DELETED:
goto get_scope;
case SCF_ERROR_NOT_FOUND:
case SCF_ERROR_NOT_SET:
switch (scf_error()) {
goto out;
case SCF_ERROR_EXISTS:
goto get_svc;
goto out;
case SCF_ERROR_BACKEND_ACCESS:
goto out;
goto out;
case SCF_ERROR_NOT_SET:
switch (scf_error()) {
goto out;
case SCF_ERROR_DELETED:
goto add_svc;
case SCF_ERROR_NOT_FOUND:
case SCF_ERROR_NOT_SET:
switch (scf_error()) {
goto out;
case SCF_ERROR_DELETED:
goto add_svc;
case SCF_ERROR_EXISTS:
goto get_inst;
goto out;
case SCF_ERROR_BACKEND_ACCESS:
goto out;
goto out;
case SCF_ERROR_NOT_SET:
scf_error());
ret = 0;
out:
return (ret);
switch (scf_error()) {
return (ECONNABORTED);
case SCF_ERROR_DELETED:
return (ECANCELED);
case SCF_ERROR_NOT_FOUND:
goto new;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
new:
switch (scf_error()) {
return (ECONNABORTED);
case SCF_ERROR_DELETED:
return (ECANCELED);
case SCF_ERROR_EXISTS:
goto change_type;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
scferr(void)
switch (scf_error()) {
case SCF_ERROR_NO_MEMORY:
case SCF_ERROR_NO_RESOURCES:
scf_handle_t *h;
if (h == NULL) {
scferr();
if (scf_handle_bind(h) != 0) {
switch (scf_error()) {
case SCF_ERROR_NO_SERVER:
goto bail;
scferr();
goto bail;
scferr();
goto bail;
case ENOMEM:
case ECONNABORTED:
case EPERM:
case EACCES:
case EROFS:
scferr();
goto bail;
switch (scf_error()) {
scferr();
goto bail;
case SCF_ERROR_DELETED:
goto get_inst;
case SCF_ERROR_NOT_FOUND:
case SCF_ERROR_NOT_SET:
switch (scf_error()) {
case SCF_ERROR_BACKEND_ACCESS:
scferr();
goto bail;
case SCF_ERROR_DELETED:
goto get_inst;
case SCF_ERROR_EXISTS:
goto get_pg;
case SCF_ERROR_NOT_SET:
assert(r == 0);
switch (scf_error()) {
case SCF_ERROR_BACKEND_ACCESS:
scferr();
goto bail;
case SCF_ERROR_DELETED:
goto add_pg;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_IN_USE:
case SCF_ERROR_NOT_SET:
case ECONNABORTED:
scferr();
goto bail;
case ECANCELED:
goto add_pg;
assert(r == 0);
switch (scf_error()) {
case SCF_ERROR_BACKEND_ACCESS:
scferr();
goto bail;
case SCF_ERROR_DELETED:
goto add_pg;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
scf_error());
bail:
(void) scf_handle_unbind(h);
char *ln;
int init_signal;
exit(0);
ln);
* Signal init; init will take care of telling svc.startd.
exit(0);
sigpoll(int n)
if (Pfd < 0) {
sizeof (struct pidrec)) {
switch (p->pd_type) {
case ADDPID:
sizeof (struct pidlist));
tp++;
while (tp) {
case REMPID:
while (tp) {
cleanaux()
short status;
if (p->pl_dflag) {
if (p == Plhead) {
Plfree = p;
Plfree = p;
savep = p;
p = p->pl_next;
void *ptr;
st_sane()
sizeof (struct PROC_TABLE))
st_init()
char *ptr;
goto new_state;
booting = 0;
goto new_state;
goto new_state;
goto new_state;
while (to_be_read > 0) {
if (read_ret < 0) {
goto new_state;
if (st_sane()) {
if (st_fd >= 0)
if (!booting) {
st_write();
if (!insane) {
st_write()
static int complained = 0;
int st_fd;
char *cp;
if (st_fd < 0)
goto err;
while (sz > 0) {
if (ret < 0) {
goto err;
goto err;
complained = 0;
err:
if (st_fd >= 0)
if (st_fd)
char *ioctl_tset_emsg =
if (fd < 0) {
return (fd);
if (legacy_tmpl >= 0) {
if (err != 0) {
if (fd < 0) {
int fd;
if (fd < 0)
return (fd);
if (fd < 0)
if (err != 0) {
int fd;
if (fd < 0)
ct_evthdl_t e;
int err;
if (err != 0) {
/* If it's svc.startd, restart it. Else, abandon. */
if (ret == 0) {
if (smf_debug)
"svc.startd.\n");
if (startd_failure_rate_critical())
if (startd_tmpl < 0)
"Restarting svc.startd in "
ctid);
abandon = 0;
contract_ack(e);
ct_event_free(e);
* svc.startd(1M) Management
* (Re)start svc.startd(1M). old_ctid should be the contract ID of the old
if (ret == 0) {
if (smf_debug)
(void) pause();
if (err != 0) {
SCF_SERVICE_STARTD)) != 0)
startd_svc_aux)) != 0)
if (!did_activate)
"fork() for svc.startd failed: %s. Will retry in 1 "
if (pid == 0) {
if (smf_debug)
if (did_activate) {
if (old_ctid != 0)
* Place the current time in our circular array of svc.startd failures.
int n = startd_failure_index;
avg_ns =
if (b == NULL)
if (!adt_audit_enabled())