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