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