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