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