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