xref: /illumos-gate/usr/src/cmd/svc/startd/startd.c (revision c7c6ab2a4af23be725dea6dacf112b0b9f3fe26f)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 /*
27  * startd.c - the master restarter
28  *
29  * svc.startd comprises two halves.  The graph engine is based in graph.c and
30  * maintains the service dependency graph based on the information in the
31  * repository.  For each service it also tracks the current state and the
32  * restarter responsible for the service.  Based on the graph, events from the
33  * repository (mostly administrative requests from svcadm), and messages from
34  * the restarters, the graph engine makes decisions about how the services
35  * should be manipulated and sends commands to the appropriate restarters.
36  * Communication between the graph engine and the restarters is embodied in
37  * protocol.c.
38  *
39  * The second half of svc.startd is the restarter for services managed by
40  * svc.startd and is primarily contained in restarter.c.  It responds to graph
41  * engine commands by executing methods, updating the repository, and sending
42  * feedback (mostly state updates) to the graph engine.
43  *
44  * Error handling
45  *
46  * In general, when svc.startd runs out of memory it reattempts a few times,
47  * sleeping inbetween, before giving up and exiting (see startd_alloc_retry()).
48  * When a repository connection is broken (libscf calls fail with
49  * SCF_ERROR_CONNECTION_BROKEN, librestart and internal functions return
50  * ECONNABORTED), svc.startd calls libscf_rebind_handle(), which coordinates
51  * with the svc.configd-restarting thread, fork_configd_thread(), via
52  * st->st_configd_live_cv, and rebinds the repository handle.  Doing so resets
53  * all libscf state associated with that handle, so functions which do this
54  * should communicate the event to their callers (usually by returning
55  * ECONNRESET) so they may reset their state appropriately.
56  *
57  * External references
58  *
59  * svc.configd generates special security audit events for changes to some
60  * restarter related properties.  See the special_props_list array in
61  * usr/src/cmd/svc/configd/rc_node.c for the properties that cause these audit
62  * events.  If you change the semantics of these propereties within startd, you
63  * will probably need to update rc_node.c
64  */
65 
66 #include <stdio.h>
67 #include <stdio_ext.h>
68 #include <sys/mnttab.h>		/* uses FILE * without including stdio.h */
69 #include <alloca.h>
70 #include <sys/mount.h>
71 #include <sys/stat.h>
72 #include <sys/types.h>
73 #include <sys/wait.h>
74 #include <assert.h>
75 #include <errno.h>
76 #include <fcntl.h>
77 #include <ftw.h>
78 #include <libintl.h>
79 #include <libscf.h>
80 #include <libscf_priv.h>
81 #include <libuutil.h>
82 #include <locale.h>
83 #include <poll.h>
84 #include <pthread.h>
85 #include <signal.h>
86 #include <stdarg.h>
87 #include <stdlib.h>
88 #include <string.h>
89 #include <strings.h>
90 #include <unistd.h>
91 
92 #include "startd.h"
93 #include "protocol.h"
94 
95 ssize_t max_scf_name_size;
96 ssize_t max_scf_fmri_size;
97 ssize_t max_scf_value_size;
98 
99 mode_t fmask;
100 mode_t dmask;
101 
102 graph_update_t *gu;
103 restarter_update_t *ru;
104 
105 startd_state_t *st;
106 
107 boolean_t booting_to_single_user = B_FALSE;
108 
109 const char * const admin_actions[] = {
110     SCF_PROPERTY_DEGRADED,
111     SCF_PROPERTY_MAINT_OFF,
112     SCF_PROPERTY_MAINT_ON,
113     SCF_PROPERTY_MAINT_ON_IMMEDIATE,
114     SCF_PROPERTY_REFRESH,
115     SCF_PROPERTY_RESTART
116 };
117 
118 const int admin_events[NACTIONS] = {
119     RESTARTER_EVENT_TYPE_ADMIN_DEGRADED,
120     RESTARTER_EVENT_TYPE_ADMIN_MAINT_OFF,
121     RESTARTER_EVENT_TYPE_ADMIN_MAINT_ON,
122     RESTARTER_EVENT_TYPE_ADMIN_MAINT_ON_IMMEDIATE,
123     RESTARTER_EVENT_TYPE_ADMIN_REFRESH,
124     RESTARTER_EVENT_TYPE_ADMIN_RESTART
125 };
126 
127 const char * const instance_state_str[] = {
128 	"none",
129 	"uninitialized",
130 	"maintenance",
131 	"offline",
132 	"disabled",
133 	"online",
134 	"degraded"
135 };
136 
137 static int finished = 0;
138 static int opt_reconfig = 0;
139 static uint8_t prop_reconfig = 0;
140 
141 #define	INITIAL_REBIND_ATTEMPTS	5
142 #define	INITIAL_REBIND_DELAY	3
143 
144 pthread_mutexattr_t mutex_attrs;
145 
146 const char *
147 _umem_debug_init(void)
148 {
149 	return ("default,verbose");	/* UMEM_DEBUG setting */
150 }
151 
152 const char *
153 _umem_logging_init(void)
154 {
155 	return ("fail,contents");	/* UMEM_LOGGING setting */
156 }
157 
158 /*
159  * startd_alloc_retry()
160  *   Wrapper for allocation functions.  Retries with a decaying time
161  *   value on failure to allocate, and aborts startd if failure is
162  *   persistent.
163  */
164 void *
165 startd_alloc_retry(void *f(size_t, int), size_t sz)
166 {
167 	void *p;
168 	uint_t try, msecs;
169 
170 	p = f(sz, UMEM_DEFAULT);
171 	if (p != NULL || sz == 0)
172 		return (p);
173 
174 	msecs = ALLOC_DELAY;
175 
176 	for (try = 0; p == NULL && try < ALLOC_RETRY; ++try) {
177 		(void) poll(NULL, 0, msecs);
178 		msecs *= ALLOC_DELAY_MULT;
179 		p = f(sz, UMEM_DEFAULT);
180 		if (p != NULL)
181 			return (p);
182 	}
183 
184 	uu_die("Insufficient memory.\n");
185 	/* NOTREACHED */
186 }
187 
188 void *
189 safe_realloc(void *p, size_t sz)
190 {
191 	uint_t try, msecs;
192 
193 	p = realloc(p, sz);
194 	if (p != NULL || sz == 0)
195 		return (p);
196 
197 	msecs = ALLOC_DELAY;
198 
199 	for (try = 0; errno == EAGAIN && try < ALLOC_RETRY; ++try) {
200 		(void) poll(NULL, 0, msecs);
201 		p = realloc(p, sz);
202 		if (p != NULL)
203 			return (p);
204 		msecs *= ALLOC_DELAY_MULT;
205 	}
206 
207 	uu_die("Insufficient memory.\n");
208 	/* NOTREACHED */
209 }
210 
211 char *
212 safe_strdup(const char *s)
213 {
214 	uint_t try, msecs;
215 	char *d;
216 
217 	d = strdup(s);
218 	if (d != NULL)
219 		return (d);
220 
221 	msecs = ALLOC_DELAY;
222 
223 	for (try = 0;
224 	    (errno == EAGAIN || errno == ENOMEM) && try < ALLOC_RETRY;
225 	    ++try) {
226 		(void) poll(NULL, 0, msecs);
227 		d = strdup(s);
228 		if (d != NULL)
229 			return (d);
230 		msecs *= ALLOC_DELAY_MULT;
231 	}
232 
233 	uu_die("Insufficient memory.\n");
234 	/* NOTREACHED */
235 }
236 
237 
238 void
239 startd_free(void *p, size_t sz)
240 {
241 	umem_free(p, sz);
242 }
243 
244 /*
245  * Creates a uu_list_pool_t with the same retry policy as startd_alloc().
246  * Only returns NULL for UU_ERROR_UNKNOWN_FLAG and UU_ERROR_NOT_SUPPORTED.
247  */
248 uu_list_pool_t *
249 startd_list_pool_create(const char *name, size_t e, size_t o,
250     uu_compare_fn_t *f, uint32_t flags)
251 {
252 	uu_list_pool_t *pool;
253 	uint_t try, msecs;
254 
255 	pool = uu_list_pool_create(name, e, o, f, flags);
256 	if (pool != NULL)
257 		return (pool);
258 
259 	msecs = ALLOC_DELAY;
260 
261 	for (try = 0; uu_error() == UU_ERROR_NO_MEMORY && try < ALLOC_RETRY;
262 	    ++try) {
263 		(void) poll(NULL, 0, msecs);
264 		pool = uu_list_pool_create(name, e, o, f, flags);
265 		if (pool != NULL)
266 			return (pool);
267 		msecs *= ALLOC_DELAY_MULT;
268 	}
269 
270 	if (try < ALLOC_RETRY)
271 		return (NULL);
272 
273 	uu_die("Insufficient memory.\n");
274 	/* NOTREACHED */
275 }
276 
277 /*
278  * Creates a uu_list_t with the same retry policy as startd_alloc().  Only
279  * returns NULL for UU_ERROR_UNKNOWN_FLAG and UU_ERROR_NOT_SUPPORTED.
280  */
281 uu_list_t *
282 startd_list_create(uu_list_pool_t *pool, void *parent, uint32_t flags)
283 {
284 	uu_list_t *list;
285 	uint_t try, msecs;
286 
287 	list = uu_list_create(pool, parent, flags);
288 	if (list != NULL)
289 		return (list);
290 
291 	msecs = ALLOC_DELAY;
292 
293 	for (try = 0; uu_error() == UU_ERROR_NO_MEMORY && try < ALLOC_RETRY;
294 	    ++try) {
295 		(void) poll(NULL, 0, msecs);
296 		list = uu_list_create(pool, parent, flags);
297 		if (list != NULL)
298 			return (list);
299 		msecs *= ALLOC_DELAY_MULT;
300 	}
301 
302 	if (try < ALLOC_RETRY)
303 		return (NULL);
304 
305 	uu_die("Insufficient memory.\n");
306 	/* NOTREACHED */
307 }
308 
309 pthread_t
310 startd_thread_create(void *(*func)(void *), void *ptr)
311 {
312 	int err;
313 	pthread_t tid;
314 
315 	err = pthread_create(&tid, NULL, func, ptr);
316 	if (err != 0) {
317 		assert(err == EAGAIN);
318 		uu_die("Could not create thread.\n");
319 	}
320 
321 	err = pthread_detach(tid);
322 	assert(err == 0);
323 
324 	return (tid);
325 }
326 
327 extern int info_events_all;
328 
329 static int
330 read_startd_config(void)
331 {
332 	scf_handle_t *hndl;
333 	scf_instance_t *inst;
334 	scf_propertygroup_t *pg;
335 	scf_property_t *prop;
336 	scf_value_t *val;
337 	scf_iter_t *iter, *piter;
338 	instance_data_t idata;
339 	char *buf, *vbuf;
340 	char *startd_options_fmri = uu_msprintf("%s/:properties/options",
341 	    SCF_SERVICE_STARTD);
342 	char *startd_reconfigure_fmri = uu_msprintf(
343 	    "%s/:properties/system/reconfigure", SCF_SERVICE_STARTD);
344 	char *env_opts, *lasts, *cp;
345 	int bind_fails = 0;
346 	int ret = 0, r;
347 	uint_t count = 0, msecs = ALLOC_DELAY;
348 	size_t sz;
349 	ctid_t ctid;
350 	uint64_t uint64;
351 
352 	buf = startd_alloc(max_scf_fmri_size);
353 
354 	if (startd_options_fmri == NULL || startd_reconfigure_fmri == NULL)
355 		uu_die("Allocation failure\n");
356 
357 	st->st_log_prefix = LOG_PREFIX_EARLY;
358 
359 	if ((st->st_log_file = getenv("STARTD_DEFAULT_LOG")) == NULL) {
360 		st->st_log_file = startd_alloc(strlen(STARTD_DEFAULT_LOG) + 1);
361 
362 		(void) strcpy(st->st_log_file, STARTD_DEFAULT_LOG);
363 	}
364 
365 	st->st_door_path = getenv("STARTD_ALT_DOOR");
366 
367 	/*
368 	 * Read "options" property group.
369 	 */
370 	for (hndl = libscf_handle_create_bound(SCF_VERSION); hndl == NULL;
371 	    hndl = libscf_handle_create_bound(SCF_VERSION), bind_fails++) {
372 		(void) sleep(INITIAL_REBIND_DELAY);
373 
374 		if (bind_fails > INITIAL_REBIND_ATTEMPTS) {
375 			/*
376 			 * In the case that we can't bind to the repository
377 			 * (which should have been started), we need to allow
378 			 * the user into maintenance mode to determine what's
379 			 * failed.
380 			 */
381 			log_framework(LOG_INFO, "Couldn't fetch "
382 			    "default settings: %s\n",
383 			    scf_strerror(scf_error()));
384 
385 			ret = -1;
386 
387 			goto noscfout;
388 		}
389 	}
390 
391 	idata.i_fmri = SCF_SERVICE_STARTD;
392 	idata.i_state = RESTARTER_STATE_NONE;
393 	idata.i_next_state = RESTARTER_STATE_NONE;
394 timestamp:
395 	switch (r = _restarter_commit_states(hndl, &idata,
396 	    RESTARTER_STATE_ONLINE, RESTARTER_STATE_NONE,
397 	    restarter_get_str_short(restarter_str_insert_in_graph))) {
398 	case 0:
399 		break;
400 
401 	case ENOMEM:
402 		++count;
403 		if (count < ALLOC_RETRY) {
404 			(void) poll(NULL, 0, msecs);
405 			msecs *= ALLOC_DELAY_MULT;
406 			goto timestamp;
407 		}
408 
409 		uu_die("Insufficient memory.\n");
410 		/* NOTREACHED */
411 
412 	case ECONNABORTED:
413 		libscf_handle_rebind(hndl);
414 		goto timestamp;
415 
416 	case ENOENT:
417 	case EPERM:
418 	case EACCES:
419 	case EROFS:
420 		log_error(LOG_INFO, "Could set state of %s: %s.\n",
421 		    idata.i_fmri, strerror(r));
422 		break;
423 
424 	case EINVAL:
425 	default:
426 		bad_error("_restarter_commit_states", r);
427 	}
428 
429 	pg = safe_scf_pg_create(hndl);
430 	prop = safe_scf_property_create(hndl);
431 	val = safe_scf_value_create(hndl);
432 	inst = safe_scf_instance_create(hndl);
433 
434 	/* set startd's restarter properties */
435 	if (scf_handle_decode_fmri(hndl, SCF_SERVICE_STARTD, NULL, NULL, inst,
436 	    NULL, NULL, SCF_DECODE_FMRI_EXACT) == 0) {
437 		(void) libscf_write_start_pid(inst, getpid());
438 		ctid = proc_get_ctid();
439 		if (ctid != -1) {
440 			uint64 = (uint64_t)ctid;
441 			(void) libscf_inst_set_count_prop(inst,
442 			    SCF_PG_RESTARTER, SCF_PG_RESTARTER_TYPE,
443 			    SCF_PG_RESTARTER_FLAGS, SCF_PROPERTY_CONTRACT,
444 			    uint64);
445 		}
446 		(void) libscf_note_method_log(inst, LOG_PREFIX_EARLY,
447 		    STARTD_DEFAULT_LOG);
448 		(void) libscf_note_method_log(inst, LOG_PREFIX_NORMAL,
449 		    STARTD_DEFAULT_LOG);
450 	}
451 
452 	/* Read reconfigure property for recovery. */
453 	if (scf_handle_decode_fmri(hndl, startd_reconfigure_fmri, NULL, NULL,
454 	    NULL, NULL, prop, NULL) != -1 &&
455 	    scf_property_get_value(prop, val) == 0)
456 		(void) scf_value_get_boolean(val, &prop_reconfig);
457 
458 	if (scf_handle_decode_fmri(hndl, startd_options_fmri, NULL, NULL, NULL,
459 	    pg, NULL, SCF_DECODE_FMRI_TRUNCATE) == -1) {
460 		/*
461 		 * No configuration options defined.
462 		 */
463 		if (scf_error() != SCF_ERROR_NOT_FOUND)
464 			uu_warn("Couldn't read configuration from 'options' "
465 			    "group: %s\n", scf_strerror(scf_error()));
466 		goto scfout;
467 	}
468 
469 	/*
470 	 * If there is no "options" group defined, then our defaults are fine.
471 	 */
472 	if (scf_pg_get_name(pg, NULL, 0) < 0)
473 		goto scfout;
474 
475 	/* get info_events_all */
476 	info_events_all = libscf_get_info_events_all(pg);
477 
478 	/* Iterate through. */
479 	iter = safe_scf_iter_create(hndl);
480 
481 	(void) scf_iter_pg_properties(iter, pg);
482 
483 	piter = safe_scf_iter_create(hndl);
484 	vbuf = startd_alloc(max_scf_value_size);
485 
486 	while ((scf_iter_next_property(iter, prop) == 1)) {
487 		scf_type_t ty;
488 
489 		if (scf_property_get_name(prop, buf, max_scf_fmri_size) < 0)
490 			continue;
491 
492 		if (strcmp(buf, "logging") != 0 &&
493 		    strcmp(buf, "boot_messages") != 0)
494 			continue;
495 
496 		if (scf_property_type(prop, &ty) != 0) {
497 			switch (scf_error()) {
498 			case SCF_ERROR_CONNECTION_BROKEN:
499 			default:
500 				libscf_handle_rebind(hndl);
501 				continue;
502 
503 			case SCF_ERROR_DELETED:
504 				continue;
505 
506 			case SCF_ERROR_NOT_BOUND:
507 			case SCF_ERROR_NOT_SET:
508 				bad_error("scf_property_type", scf_error());
509 			}
510 		}
511 
512 		if (ty != SCF_TYPE_ASTRING) {
513 			uu_warn("property \"options/%s\" is not of type "
514 			    "astring; ignored.\n", buf);
515 			continue;
516 		}
517 
518 		if (scf_property_get_value(prop, val) != 0) {
519 			switch (scf_error()) {
520 			case SCF_ERROR_CONNECTION_BROKEN:
521 			default:
522 				return (ECONNABORTED);
523 
524 			case SCF_ERROR_DELETED:
525 			case SCF_ERROR_NOT_FOUND:
526 				return (0);
527 
528 			case SCF_ERROR_CONSTRAINT_VIOLATED:
529 				uu_warn("property \"options/%s\" has multiple "
530 				    "values; ignored.\n", buf);
531 				continue;
532 
533 			case SCF_ERROR_PERMISSION_DENIED:
534 				uu_warn("property \"options/%s\" cannot be "
535 				    "read because startd has insufficient "
536 				    "permission; ignored.\n", buf);
537 				continue;
538 
539 			case SCF_ERROR_HANDLE_MISMATCH:
540 			case SCF_ERROR_NOT_BOUND:
541 			case SCF_ERROR_NOT_SET:
542 				bad_error("scf_property_get_value",
543 				    scf_error());
544 			}
545 		}
546 
547 		if (scf_value_get_astring(val, vbuf, max_scf_value_size) < 0)
548 			bad_error("scf_value_get_astring", scf_error());
549 
550 		if (strcmp("logging", buf) == 0) {
551 			if (strcmp("verbose", vbuf) == 0) {
552 				st->st_boot_flags = STARTD_BOOT_VERBOSE;
553 				st->st_log_level_min = LOG_INFO;
554 			} else if (strcmp("debug", vbuf) == 0) {
555 				st->st_boot_flags = STARTD_BOOT_VERBOSE;
556 				st->st_log_level_min = LOG_DEBUG;
557 			} else if (strcmp("quiet", vbuf) == 0) {
558 				st->st_log_level_min = LOG_NOTICE;
559 			} else {
560 				uu_warn("unknown options/logging "
561 				    "value '%s' ignored\n", vbuf);
562 			}
563 
564 		} else if (strcmp("boot_messages", buf) == 0) {
565 			if (strcmp("quiet", vbuf) == 0) {
566 				st->st_boot_flags = STARTD_BOOT_QUIET;
567 			} else if (strcmp("verbose", vbuf) == 0) {
568 				st->st_boot_flags = STARTD_BOOT_VERBOSE;
569 			} else {
570 				log_framework(LOG_NOTICE, "unknown "
571 				    "options/boot_messages value '%s' "
572 				    "ignored\n", vbuf);
573 			}
574 
575 		}
576 	}
577 
578 	startd_free(vbuf, max_scf_value_size);
579 	scf_iter_destroy(piter);
580 
581 	scf_iter_destroy(iter);
582 
583 scfout:
584 	scf_value_destroy(val);
585 	scf_pg_destroy(pg);
586 	scf_property_destroy(prop);
587 	scf_instance_destroy(inst);
588 	(void) scf_handle_unbind(hndl);
589 	scf_handle_destroy(hndl);
590 
591 noscfout:
592 	startd_free(buf, max_scf_fmri_size);
593 	uu_free(startd_options_fmri);
594 	uu_free(startd_reconfigure_fmri);
595 
596 	if (booting_to_single_user) {
597 		st->st_subgraph = startd_alloc(max_scf_fmri_size);
598 		sz = strlcpy(st->st_subgraph, "milestone/single-user:default",
599 		    max_scf_fmri_size);
600 		assert(sz < max_scf_fmri_size);
601 	}
602 
603 	/*
604 	 * Options passed in as boot arguments override repository defaults.
605 	 */
606 	env_opts = getenv("SMF_OPTIONS");
607 	if (env_opts == NULL)
608 		return (ret);
609 
610 	for (cp = strtok_r(env_opts, ",", &lasts); cp != NULL;
611 	    cp = strtok_r(NULL, ",", &lasts)) {
612 		if (strcmp(cp, "debug") == 0) {
613 			st->st_boot_flags = STARTD_BOOT_VERBOSE;
614 			st->st_log_level_min = LOG_DEBUG;
615 
616 			/* -m debug should send messages to console */
617 			st->st_log_flags =
618 			    st->st_log_flags | STARTD_LOG_TERMINAL;
619 		} else if (strcmp(cp, "verbose") == 0) {
620 			st->st_boot_flags = STARTD_BOOT_VERBOSE;
621 			st->st_log_level_min = LOG_INFO;
622 		} else if (strcmp(cp, "seed") == 0) {
623 			uu_warn("SMF option \"%s\" unimplemented.\n", cp);
624 		} else if (strcmp(cp, "quiet") == 0) {
625 			st->st_log_level_min = LOG_NOTICE;
626 		} else if (strncmp(cp, "milestone=",
627 		    sizeof ("milestone=") - 1) == 0) {
628 			char *mp = cp + sizeof ("milestone=") - 1;
629 
630 			if (booting_to_single_user)
631 				continue;
632 
633 			if (st->st_subgraph == NULL) {
634 				st->st_subgraph =
635 				    startd_alloc(max_scf_fmri_size);
636 				st->st_subgraph[0] = '\0';
637 			}
638 
639 			if (mp[0] == '\0' || strcmp(mp, "all") == 0) {
640 				(void) strcpy(st->st_subgraph, "all");
641 			} else if (strcmp(mp, "su") == 0 ||
642 			    strcmp(mp, "single-user") == 0) {
643 				(void) strcpy(st->st_subgraph,
644 				    "milestone/single-user:default");
645 			} else if (strcmp(mp, "mu") == 0 ||
646 			    strcmp(mp, "multi-user") == 0) {
647 				(void) strcpy(st->st_subgraph,
648 				    "milestone/multi-user:default");
649 			} else if (strcmp(mp, "mus") == 0 ||
650 			    strcmp(mp, "multi-user-server") == 0) {
651 				(void) strcpy(st->st_subgraph,
652 				    "milestone/multi-user-server:default");
653 			} else if (strcmp(mp, "none") == 0) {
654 				(void) strcpy(st->st_subgraph, "none");
655 			} else {
656 				log_framework(LOG_NOTICE,
657 				    "invalid milestone option value "
658 				    "'%s' ignored\n", mp);
659 			}
660 		} else {
661 			uu_warn("Unknown SMF option \"%s\".\n", cp);
662 		}
663 	}
664 
665 	return (ret);
666 }
667 
668 /*
669  * void set_boot_env()
670  *
671  * If -r was passed or /reconfigure exists, this is a reconfig
672  * reboot.  We need to make sure that this information is given
673  * to the appropriate services the first time they're started
674  * by setting the system/reconfigure repository property,
675  * as well as pass the _INIT_RECONFIG variable on to the rcS
676  * start method so that legacy services can continue to use it.
677  *
678  * This function must never be called before contract_init(), as
679  * it sets st_initial.  get_startd_config() sets prop_reconfig from
680  * pre-existing repository state.
681  */
682 static void
683 set_boot_env()
684 {
685 	struct stat sb;
686 	int r;
687 
688 	/*
689 	 * Check if property still is set -- indicates we didn't get
690 	 * far enough previously to unset it.  Otherwise, if this isn't
691 	 * the first startup, don't re-process /reconfigure or the
692 	 * boot flag.
693 	 */
694 	if (prop_reconfig != 1 && st->st_initial != 1)
695 		return;
696 
697 	/* If /reconfigure exists, also set opt_reconfig. */
698 	if (stat("/reconfigure", &sb) != -1)
699 		opt_reconfig = 1;
700 
701 	/* Nothing to do.  Just return. */
702 	if (opt_reconfig == 0 && prop_reconfig == 0)
703 		return;
704 
705 	/*
706 	 * Set startd's reconfigure property.  This property is
707 	 * then cleared by successful completion of the single-user
708 	 * milestone.
709 	 */
710 	if (prop_reconfig != 1) {
711 		r = libscf_set_reconfig(1);
712 		switch (r) {
713 		case 0:
714 			break;
715 
716 		case ENOENT:
717 		case EPERM:
718 		case EACCES:
719 		case EROFS:
720 			log_error(LOG_WARNING, "Could not set reconfiguration "
721 			    "property: %s\n", strerror(r));
722 			break;
723 
724 		default:
725 			bad_error("libscf_set_reconfig", r);
726 		}
727 	}
728 }
729 
730 static void
731 startup(void)
732 {
733 	ctid_t configd_ctid;
734 	int err;
735 
736 	/*
737 	 * Initialize data structures.
738 	 */
739 	gu = startd_zalloc(sizeof (graph_update_t));
740 	ru = startd_zalloc(sizeof (restarter_update_t));
741 
742 	(void) pthread_cond_init(&st->st_load_cv, NULL);
743 	(void) pthread_cond_init(&st->st_configd_live_cv, NULL);
744 	(void) pthread_cond_init(&gu->gu_cv, NULL);
745 	(void) pthread_cond_init(&gu->gu_freeze_cv, NULL);
746 	(void) pthread_cond_init(&ru->restarter_update_cv, NULL);
747 	(void) pthread_mutex_init(&st->st_load_lock, &mutex_attrs);
748 	(void) pthread_mutex_init(&st->st_configd_live_lock, &mutex_attrs);
749 	(void) pthread_mutex_init(&gu->gu_lock, &mutex_attrs);
750 	(void) pthread_mutex_init(&gu->gu_freeze_lock, &mutex_attrs);
751 	(void) pthread_mutex_init(&ru->restarter_update_lock, &mutex_attrs);
752 
753 	configd_ctid = contract_init();
754 
755 	if (configd_ctid != -1)
756 		log_framework(LOG_DEBUG, "Existing configd contract %ld; not "
757 		    "starting svc.configd\n", configd_ctid);
758 
759 	(void) startd_thread_create(fork_configd_thread, (void *)configd_ctid);
760 
761 	/*
762 	 * Await, if necessary, configd's initial arrival.
763 	 */
764 	MUTEX_LOCK(&st->st_configd_live_lock);
765 	while (!st->st_configd_lives) {
766 		log_framework(LOG_DEBUG, "Awaiting cv signal on "
767 		    "configd_live_cv\n");
768 		err = pthread_cond_wait(&st->st_configd_live_cv,
769 		    &st->st_configd_live_lock);
770 		assert(err == 0);
771 	}
772 	MUTEX_UNLOCK(&st->st_configd_live_lock);
773 
774 	utmpx_init();
775 	wait_init();
776 
777 	if (read_startd_config())
778 		log_framework(LOG_INFO, "svc.configd unable to provide startd "
779 		    "optional settings\n");
780 
781 	log_init();
782 	dict_init();
783 	timeout_init();
784 	restarter_protocol_init();
785 	restarter_init();
786 
787 	/*
788 	 * svc.configd is started by fork_configd_thread so repository access is
789 	 * available, run early manifest import before continuing with starting
790 	 * graph engine and the rest of startd.
791 	 */
792 	log_framework(LOG_DEBUG, "Calling fork_emi...\n");
793 	fork_emi();
794 
795 	graph_protocol_init();
796 	graph_init();
797 
798 	init_env();
799 
800 	set_boot_env();
801 	restarter_start();
802 	graph_engine_start();
803 }
804 
805 static void
806 usage(const char *name)
807 {
808 	uu_warn(gettext("usage: %s [-n]\n"), name);
809 	exit(UU_EXIT_USAGE);
810 }
811 
812 static int
813 daemonize_start(void)
814 {
815 	pid_t pid;
816 	int fd;
817 
818 	if ((pid = fork1()) < 0)
819 		return (-1);
820 
821 	if (pid != 0)
822 		exit(0);
823 
824 	(void) close(STDIN_FILENO);
825 
826 	if ((fd = open("/dev/null", O_RDONLY)) == -1) {
827 		uu_warn(gettext("can't connect stdin to /dev/null"));
828 	} else if (fd != STDIN_FILENO) {
829 		(void) dup2(fd, STDIN_FILENO);
830 		startd_close(fd);
831 	}
832 
833 	closefrom(3);
834 	(void) dup2(STDERR_FILENO, STDOUT_FILENO);
835 
836 	(void) setsid();
837 	(void) chdir("/");
838 
839 	/* Use default umask that init handed us, but 022 to create files. */
840 	dmask = umask(022);
841 	fmask = umask(dmask);
842 
843 	return (0);
844 }
845 
846 /*ARGSUSED*/
847 static void
848 die_handler(int sig, siginfo_t *info, void *data)
849 {
850 	finished = 1;
851 }
852 
853 int
854 main(int argc, char *argv[])
855 {
856 	int opt;
857 	int daemonize = 1;
858 	struct sigaction act;
859 	sigset_t nullset;
860 	struct stat sb;
861 
862 	(void) uu_setpname(argv[0]);
863 
864 	st = startd_zalloc(sizeof (startd_state_t));
865 
866 	(void) pthread_mutexattr_init(&mutex_attrs);
867 #ifndef	NDEBUG
868 	(void) pthread_mutexattr_settype(&mutex_attrs,
869 	    PTHREAD_MUTEX_ERRORCHECK);
870 #endif
871 
872 	max_scf_name_size = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH);
873 	max_scf_value_size = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
874 	max_scf_fmri_size = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH);
875 
876 	if (max_scf_name_size == -1 || max_scf_value_size == -1 ||
877 	    max_scf_value_size == -1)
878 		uu_die("Can't determine repository maximum lengths.\n");
879 
880 	max_scf_name_size++;
881 	max_scf_value_size++;
882 	max_scf_fmri_size++;
883 
884 	st->st_log_flags = STARTD_LOG_FILE | STARTD_LOG_SYSLOG;
885 	st->st_log_level_min = LOG_NOTICE;
886 
887 	while ((opt = getopt(argc, argv, "nrs")) != EOF) {
888 		switch (opt) {
889 		case 'n':
890 			daemonize = 0;
891 			break;
892 		case 'r':			/* reconfiguration boot */
893 			opt_reconfig = 1;
894 			break;
895 		case 's':			/* single-user mode */
896 			booting_to_single_user = B_TRUE;
897 			break;
898 		default:
899 			usage(argv[0]);		/* exits */
900 		}
901 	}
902 
903 	if (optind != argc)
904 		usage(argv[0]);
905 
906 	(void) enable_extended_FILE_stdio(-1, -1);
907 
908 	if (daemonize)
909 		if (daemonize_start() < 0)
910 			uu_die("Can't daemonize\n");
911 
912 	log_init();
913 
914 	if (stat("/etc/svc/volatile/resetting", &sb) != -1) {
915 		log_framework(LOG_NOTICE, "Restarter quiesced.\n");
916 
917 		for (;;)
918 			(void) pause();
919 	}
920 
921 	act.sa_sigaction = &die_handler;
922 	(void) sigfillset(&act.sa_mask);
923 	act.sa_flags = SA_SIGINFO;
924 	(void) sigaction(SIGINT, &act, NULL);
925 	(void) sigaction(SIGTERM, &act, NULL);
926 
927 	startup();
928 
929 	(void) sigemptyset(&nullset);
930 	while (!finished) {
931 		log_framework(LOG_DEBUG, "Main thread paused\n");
932 		(void) sigsuspend(&nullset);
933 	}
934 
935 	(void) log_framework(LOG_DEBUG, "Restarter exiting.\n");
936 	return (0);
937 }
938