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