xref: /illumos-gate/usr/src/cmd/svc/startd/startd.c (revision c3a558e7)
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 2010 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
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 const char *
148 _umem_debug_init(void)
149 {
150 	return ("default,verbose");	/* UMEM_DEBUG setting */
151 }
152 
153 const char *
154 _umem_logging_init(void)
155 {
156 	return ("fail,contents");	/* UMEM_LOGGING setting */
157 }
158 
159 /*
160  * startd_alloc_retry()
161  *   Wrapper for allocation functions.  Retries with a decaying time
162  *   value on failure to allocate, and aborts startd if failure is
163  *   persistent.
164  */
165 void *
166 startd_alloc_retry(void *f(size_t, int), size_t sz)
167 {
168 	void *p;
169 	uint_t try, msecs;
170 
171 	p = f(sz, UMEM_DEFAULT);
172 	if (p != NULL || sz == 0)
173 		return (p);
174 
175 	msecs = ALLOC_DELAY;
176 
177 	for (try = 0; p == NULL && try < ALLOC_RETRY; ++try) {
178 		(void) poll(NULL, 0, msecs);
179 		msecs *= ALLOC_DELAY_MULT;
180 		p = f(sz, UMEM_DEFAULT);
181 		if (p != NULL)
182 			return (p);
183 	}
184 
185 	uu_die("Insufficient memory.\n");
186 	/* NOTREACHED */
187 }
188 
189 void *
190 safe_realloc(void *p, size_t sz)
191 {
192 	uint_t try, msecs;
193 
194 	p = realloc(p, sz);
195 	if (p != NULL || sz == 0)
196 		return (p);
197 
198 	msecs = ALLOC_DELAY;
199 
200 	for (try = 0; errno == EAGAIN && try < ALLOC_RETRY; ++try) {
201 		(void) poll(NULL, 0, msecs);
202 		p = realloc(p, sz);
203 		if (p != NULL)
204 			return (p);
205 		msecs *= ALLOC_DELAY_MULT;
206 	}
207 
208 	uu_die("Insufficient memory.\n");
209 	/* NOTREACHED */
210 }
211 
212 char *
213 safe_strdup(const char *s)
214 {
215 	uint_t try, msecs;
216 	char *d;
217 
218 	d = strdup(s);
219 	if (d != NULL)
220 		return (d);
221 
222 	msecs = ALLOC_DELAY;
223 
224 	for (try = 0;
225 	    (errno == EAGAIN || errno == ENOMEM) && try < ALLOC_RETRY;
226 	    ++try) {
227 		(void) poll(NULL, 0, msecs);
228 		d = strdup(s);
229 		if (d != NULL)
230 			return (d);
231 		msecs *= ALLOC_DELAY_MULT;
232 	}
233 
234 	uu_die("Insufficient memory.\n");
235 	/* NOTREACHED */
236 }
237 
238 
239 void
240 startd_free(void *p, size_t sz)
241 {
242 	umem_free(p, sz);
243 }
244 
245 /*
246  * Creates a uu_list_pool_t with the same retry policy as startd_alloc().
247  * Only returns NULL for UU_ERROR_UNKNOWN_FLAG and UU_ERROR_NOT_SUPPORTED.
248  */
249 uu_list_pool_t *
250 startd_list_pool_create(const char *name, size_t e, size_t o,
251     uu_compare_fn_t *f, uint32_t flags)
252 {
253 	uu_list_pool_t *pool;
254 	uint_t try, msecs;
255 
256 	pool = uu_list_pool_create(name, e, o, f, flags);
257 	if (pool != NULL)
258 		return (pool);
259 
260 	msecs = ALLOC_DELAY;
261 
262 	for (try = 0; uu_error() == UU_ERROR_NO_MEMORY && try < ALLOC_RETRY;
263 	    ++try) {
264 		(void) poll(NULL, 0, msecs);
265 		pool = uu_list_pool_create(name, e, o, f, flags);
266 		if (pool != NULL)
267 			return (pool);
268 		msecs *= ALLOC_DELAY_MULT;
269 	}
270 
271 	if (try < ALLOC_RETRY)
272 		return (NULL);
273 
274 	uu_die("Insufficient memory.\n");
275 	/* NOTREACHED */
276 }
277 
278 /*
279  * Creates a uu_list_t with the same retry policy as startd_alloc().  Only
280  * returns NULL for UU_ERROR_UNKNOWN_FLAG and UU_ERROR_NOT_SUPPORTED.
281  */
282 uu_list_t *
283 startd_list_create(uu_list_pool_t *pool, void *parent, uint32_t flags)
284 {
285 	uu_list_t *list;
286 	uint_t try, msecs;
287 
288 	list = uu_list_create(pool, parent, flags);
289 	if (list != NULL)
290 		return (list);
291 
292 	msecs = ALLOC_DELAY;
293 
294 	for (try = 0; uu_error() == UU_ERROR_NO_MEMORY && try < ALLOC_RETRY;
295 	    ++try) {
296 		(void) poll(NULL, 0, msecs);
297 		list = uu_list_create(pool, parent, flags);
298 		if (list != NULL)
299 			return (list);
300 		msecs *= ALLOC_DELAY_MULT;
301 	}
302 
303 	if (try < ALLOC_RETRY)
304 		return (NULL);
305 
306 	uu_die("Insufficient memory.\n");
307 	/* NOTREACHED */
308 }
309 
310 pthread_t
311 startd_thread_create(void *(*func)(void *), void *ptr)
312 {
313 	int err;
314 	pthread_t tid;
315 
316 	err = pthread_create(&tid, NULL, func, ptr);
317 	if (err != 0) {
318 		assert(err == EAGAIN);
319 		uu_die("Could not create thread.\n");
320 	}
321 
322 	err = pthread_detach(tid);
323 	assert(err == 0);
324 
325 	return (tid);
326 }
327 
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, NULL)) {
397 	case 0:
398 		break;
399 
400 	case ENOMEM:
401 		++count;
402 		if (count < ALLOC_RETRY) {
403 			(void) poll(NULL, 0, msecs);
404 			msecs *= ALLOC_DELAY_MULT;
405 			goto timestamp;
406 		}
407 
408 		uu_die("Insufficient memory.\n");
409 		/* NOTREACHED */
410 
411 	case ECONNABORTED:
412 		libscf_handle_rebind(hndl);
413 		goto timestamp;
414 
415 	case ENOENT:
416 	case EPERM:
417 	case EACCES:
418 	case EROFS:
419 		log_error(LOG_INFO, "Could set state of %s: %s.\n",
420 		    idata.i_fmri, strerror(r));
421 		break;
422 
423 	case EINVAL:
424 	default:
425 		bad_error("_restarter_commit_states", r);
426 	}
427 
428 	pg = safe_scf_pg_create(hndl);
429 	prop = safe_scf_property_create(hndl);
430 	val = safe_scf_value_create(hndl);
431 	inst = safe_scf_instance_create(hndl);
432 
433 	/* set startd's restarter properties */
434 	if (scf_handle_decode_fmri(hndl, SCF_SERVICE_STARTD, NULL, NULL, inst,
435 	    NULL, NULL, SCF_DECODE_FMRI_EXACT) == 0) {
436 		(void) libscf_write_start_pid(inst, getpid());
437 		ctid = proc_get_ctid();
438 		if (ctid != -1) {
439 			uint64 = (uint64_t)ctid;
440 			(void) libscf_inst_set_count_prop(inst,
441 			    SCF_PG_RESTARTER, SCF_PG_RESTARTER_TYPE,
442 			    SCF_PG_RESTARTER_FLAGS, SCF_PROPERTY_CONTRACT,
443 			    uint64);
444 		}
445 		(void) libscf_note_method_log(inst, LOG_PREFIX_EARLY,
446 		    STARTD_DEFAULT_LOG);
447 		(void) libscf_note_method_log(inst, LOG_PREFIX_NORMAL,
448 		    STARTD_DEFAULT_LOG);
449 	}
450 
451 	/* Read reconfigure property for recovery. */
452 	if (scf_handle_decode_fmri(hndl, startd_reconfigure_fmri, NULL, NULL,
453 	    NULL, NULL, prop, NULL) != -1 &&
454 	    scf_property_get_value(prop, val) == 0)
455 		(void) scf_value_get_boolean(val, &prop_reconfig);
456 
457 	if (scf_handle_decode_fmri(hndl, startd_options_fmri, NULL, NULL, NULL,
458 	    pg, NULL, SCF_DECODE_FMRI_TRUNCATE) == -1) {
459 		/*
460 		 * No configuration options defined.
461 		 */
462 		if (scf_error() != SCF_ERROR_NOT_FOUND)
463 			uu_warn("Couldn't read configuration from 'options' "
464 			    "group: %s\n", scf_strerror(scf_error()));
465 		goto scfout;
466 	}
467 
468 	/*
469 	 * If there is no "options" group defined, then our defaults are fine.
470 	 */
471 	if (scf_pg_get_name(pg, NULL, 0) < 0)
472 		goto scfout;
473 
474 	/* Iterate through. */
475 	iter = safe_scf_iter_create(hndl);
476 
477 	(void) scf_iter_pg_properties(iter, pg);
478 
479 	piter = safe_scf_iter_create(hndl);
480 	vbuf = startd_alloc(max_scf_value_size);
481 
482 	while ((scf_iter_next_property(iter, prop) == 1)) {
483 		scf_type_t ty;
484 
485 		if (scf_property_get_name(prop, buf, max_scf_fmri_size) < 0)
486 			continue;
487 
488 		if (strcmp(buf, "logging") != 0 &&
489 		    strcmp(buf, "boot_messages") != 0)
490 			continue;
491 
492 		if (scf_property_type(prop, &ty) != 0) {
493 			switch (scf_error()) {
494 			case SCF_ERROR_CONNECTION_BROKEN:
495 			default:
496 				libscf_handle_rebind(hndl);
497 				continue;
498 
499 			case SCF_ERROR_DELETED:
500 				continue;
501 
502 			case SCF_ERROR_NOT_BOUND:
503 			case SCF_ERROR_NOT_SET:
504 				bad_error("scf_property_type", scf_error());
505 			}
506 		}
507 
508 		if (ty != SCF_TYPE_ASTRING) {
509 			uu_warn("property \"options/%s\" is not of type "
510 			    "astring; ignored.\n", buf);
511 			continue;
512 		}
513 
514 		if (scf_property_get_value(prop, val) != 0) {
515 			switch (scf_error()) {
516 			case SCF_ERROR_CONNECTION_BROKEN:
517 			default:
518 				return (ECONNABORTED);
519 
520 			case SCF_ERROR_DELETED:
521 			case SCF_ERROR_NOT_FOUND:
522 				return (0);
523 
524 			case SCF_ERROR_CONSTRAINT_VIOLATED:
525 				uu_warn("property \"options/%s\" has multiple "
526 				    "values; ignored.\n", buf);
527 				continue;
528 
529 			case SCF_ERROR_PERMISSION_DENIED:
530 				uu_warn("property \"options/%s\" cannot be "
531 				    "read because startd has insufficient "
532 				    "permission; ignored.\n", buf);
533 				continue;
534 
535 			case SCF_ERROR_HANDLE_MISMATCH:
536 			case SCF_ERROR_NOT_BOUND:
537 			case SCF_ERROR_NOT_SET:
538 				bad_error("scf_property_get_value",
539 				    scf_error());
540 			}
541 		}
542 
543 		if (scf_value_get_astring(val, vbuf, max_scf_value_size) < 0)
544 			bad_error("scf_value_get_astring", scf_error());
545 
546 		if (strcmp("logging", buf) == 0) {
547 			if (strcmp("verbose", vbuf) == 0) {
548 				st->st_boot_flags = STARTD_BOOT_VERBOSE;
549 				st->st_log_level_min = LOG_INFO;
550 			} else if (strcmp("debug", vbuf) == 0) {
551 				st->st_boot_flags = STARTD_BOOT_VERBOSE;
552 				st->st_log_level_min = LOG_DEBUG;
553 			} else if (strcmp("quiet", vbuf) == 0) {
554 				st->st_log_level_min = LOG_NOTICE;
555 			} else {
556 				uu_warn("unknown options/logging "
557 				    "value '%s' ignored\n", vbuf);
558 			}
559 
560 		} else if (strcmp("boot_messages", buf) == 0) {
561 			if (strcmp("quiet", vbuf) == 0) {
562 				st->st_boot_flags = STARTD_BOOT_QUIET;
563 			} else if (strcmp("verbose", vbuf) == 0) {
564 				st->st_boot_flags = STARTD_BOOT_VERBOSE;
565 			} else {
566 				log_framework(LOG_NOTICE, "unknown "
567 				    "options/boot_messages value '%s' "
568 				    "ignored\n", vbuf);
569 			}
570 
571 		}
572 	}
573 
574 	startd_free(vbuf, max_scf_value_size);
575 	scf_iter_destroy(piter);
576 
577 	scf_iter_destroy(iter);
578 
579 scfout:
580 	scf_value_destroy(val);
581 	scf_pg_destroy(pg);
582 	scf_property_destroy(prop);
583 	scf_instance_destroy(inst);
584 	(void) scf_handle_unbind(hndl);
585 	scf_handle_destroy(hndl);
586 
587 noscfout:
588 	startd_free(buf, max_scf_fmri_size);
589 	uu_free(startd_options_fmri);
590 	uu_free(startd_reconfigure_fmri);
591 
592 	if (booting_to_single_user) {
593 		st->st_subgraph = startd_alloc(max_scf_fmri_size);
594 		sz = strlcpy(st->st_subgraph, "milestone/single-user:default",
595 		    max_scf_fmri_size);
596 		assert(sz < max_scf_fmri_size);
597 	}
598 
599 	/*
600 	 * Options passed in as boot arguments override repository defaults.
601 	 */
602 	env_opts = getenv("SMF_OPTIONS");
603 	if (env_opts == NULL)
604 		return (ret);
605 
606 	for (cp = strtok_r(env_opts, ",", &lasts); cp != NULL;
607 	    cp = strtok_r(NULL, ",", &lasts)) {
608 		if (strcmp(cp, "debug") == 0) {
609 			st->st_boot_flags = STARTD_BOOT_VERBOSE;
610 			st->st_log_level_min = LOG_DEBUG;
611 
612 			/* -m debug should send messages to console */
613 			st->st_log_flags =
614 			    st->st_log_flags | STARTD_LOG_TERMINAL;
615 		} else if (strcmp(cp, "verbose") == 0) {
616 			st->st_boot_flags = STARTD_BOOT_VERBOSE;
617 			st->st_log_level_min = LOG_INFO;
618 		} else if (strcmp(cp, "seed") == 0) {
619 			uu_warn("SMF option \"%s\" unimplemented.\n", cp);
620 		} else if (strcmp(cp, "quiet") == 0) {
621 			st->st_log_level_min = LOG_NOTICE;
622 		} else if (strncmp(cp, "milestone=",
623 		    sizeof ("milestone=") - 1) == 0) {
624 			char *mp = cp + sizeof ("milestone=") - 1;
625 
626 			if (booting_to_single_user)
627 				continue;
628 
629 			if (st->st_subgraph == NULL) {
630 				st->st_subgraph =
631 				    startd_alloc(max_scf_fmri_size);
632 				st->st_subgraph[0] = '\0';
633 			}
634 
635 			if (mp[0] == '\0' || strcmp(mp, "all") == 0) {
636 				(void) strcpy(st->st_subgraph, "all");
637 			} else if (strcmp(mp, "su") == 0 ||
638 			    strcmp(mp, "single-user") == 0) {
639 				(void) strcpy(st->st_subgraph,
640 				    "milestone/single-user:default");
641 			} else if (strcmp(mp, "mu") == 0 ||
642 			    strcmp(mp, "multi-user") == 0) {
643 				(void) strcpy(st->st_subgraph,
644 				    "milestone/multi-user:default");
645 			} else if (strcmp(mp, "mus") == 0 ||
646 			    strcmp(mp, "multi-user-server") == 0) {
647 				(void) strcpy(st->st_subgraph,
648 				    "milestone/multi-user-server:default");
649 			} else if (strcmp(mp, "none") == 0) {
650 				(void) strcpy(st->st_subgraph, "none");
651 			} else {
652 				log_framework(LOG_NOTICE,
653 				    "invalid milestone option value "
654 				    "'%s' ignored\n", mp);
655 			}
656 		} else {
657 			uu_warn("Unknown SMF option \"%s\".\n", cp);
658 		}
659 	}
660 
661 	return (ret);
662 }
663 
664 /*
665  * void set_boot_env()
666  *
667  * If -r was passed or /reconfigure exists, this is a reconfig
668  * reboot.  We need to make sure that this information is given
669  * to the appropriate services the first time they're started
670  * by setting the system/reconfigure repository property,
671  * as well as pass the _INIT_RECONFIG variable on to the rcS
672  * start method so that legacy services can continue to use it.
673  *
674  * This function must never be called before contract_init(), as
675  * it sets st_initial.  get_startd_config() sets prop_reconfig from
676  * pre-existing repository state.
677  */
678 static void
679 set_boot_env()
680 {
681 	struct stat sb;
682 	int r;
683 
684 	/*
685 	 * Check if property still is set -- indicates we didn't get
686 	 * far enough previously to unset it.  Otherwise, if this isn't
687 	 * the first startup, don't re-process /reconfigure or the
688 	 * boot flag.
689 	 */
690 	if (prop_reconfig != 1 && st->st_initial != 1)
691 		return;
692 
693 	/* If /reconfigure exists, also set opt_reconfig. */
694 	if (stat("/reconfigure", &sb) != -1)
695 		opt_reconfig = 1;
696 
697 	/* Nothing to do.  Just return. */
698 	if (opt_reconfig == 0 && prop_reconfig == 0)
699 		return;
700 
701 	/*
702 	 * Set startd's reconfigure property.  This property is
703 	 * then cleared by successful completion of the single-user
704 	 * milestone.
705 	 */
706 	if (prop_reconfig != 1) {
707 		r = libscf_set_reconfig(1);
708 		switch (r) {
709 		case 0:
710 			break;
711 
712 		case ENOENT:
713 		case EPERM:
714 		case EACCES:
715 		case EROFS:
716 			log_error(LOG_WARNING, "Could not set reconfiguration "
717 			    "property: %s\n", strerror(r));
718 			break;
719 
720 		default:
721 			bad_error("libscf_set_reconfig", r);
722 		}
723 	}
724 }
725 
726 static void
727 startup(void)
728 {
729 	ctid_t configd_ctid;
730 	int err;
731 
732 	/*
733 	 * Initialize data structures.
734 	 */
735 	gu = startd_zalloc(sizeof (graph_update_t));
736 	ru = startd_zalloc(sizeof (restarter_update_t));
737 
738 	(void) pthread_cond_init(&st->st_load_cv, NULL);
739 	(void) pthread_cond_init(&st->st_configd_live_cv, NULL);
740 	(void) pthread_cond_init(&gu->gu_cv, NULL);
741 	(void) pthread_cond_init(&gu->gu_freeze_cv, NULL);
742 	(void) pthread_cond_init(&ru->restarter_update_cv, NULL);
743 	(void) pthread_mutex_init(&st->st_load_lock, &mutex_attrs);
744 	(void) pthread_mutex_init(&st->st_configd_live_lock, &mutex_attrs);
745 	(void) pthread_mutex_init(&gu->gu_lock, &mutex_attrs);
746 	(void) pthread_mutex_init(&gu->gu_freeze_lock, &mutex_attrs);
747 	(void) pthread_mutex_init(&ru->restarter_update_lock, &mutex_attrs);
748 
749 	configd_ctid = contract_init();
750 
751 	if (configd_ctid != -1)
752 		log_framework(LOG_DEBUG, "Existing configd contract %ld; not "
753 		    "starting svc.configd\n", configd_ctid);
754 
755 	(void) startd_thread_create(fork_configd_thread, (void *)configd_ctid);
756 
757 	/*
758 	 * Await, if necessary, configd's initial arrival.
759 	 */
760 	MUTEX_LOCK(&st->st_configd_live_lock);
761 	while (!st->st_configd_lives) {
762 		log_framework(LOG_DEBUG, "Awaiting cv signal on "
763 		    "configd_live_cv\n");
764 		err = pthread_cond_wait(&st->st_configd_live_cv,
765 		    &st->st_configd_live_lock);
766 		assert(err == 0);
767 	}
768 	MUTEX_UNLOCK(&st->st_configd_live_lock);
769 
770 	utmpx_init();
771 	wait_init();
772 
773 	if (read_startd_config())
774 		log_framework(LOG_INFO, "svc.configd unable to provide startd "
775 		    "optional settings\n");
776 
777 	log_init();
778 	dict_init();
779 	timeout_init();
780 	restarter_protocol_init();
781 	restarter_init();
782 
783 	/*
784 	 * svc.configd is started by fork_configd_thread so repository access is
785 	 * available, run early manifest import before continuing with starting
786 	 * graph engine and the rest of startd.
787 	 */
788 	log_framework(LOG_DEBUG, "Calling fork_emi...\n");
789 	fork_emi();
790 
791 	graph_protocol_init();
792 	graph_init();
793 
794 	init_env();
795 
796 	set_boot_env();
797 	restarter_start();
798 	graph_engine_start();
799 }
800 
801 static void
802 usage(const char *name)
803 {
804 	uu_warn(gettext("usage: %s [-n]\n"), name);
805 	exit(UU_EXIT_USAGE);
806 }
807 
808 static int
809 daemonize_start(void)
810 {
811 	pid_t pid;
812 	int fd;
813 
814 	if ((pid = fork1()) < 0)
815 		return (-1);
816 
817 	if (pid != 0)
818 		exit(0);
819 
820 	(void) close(STDIN_FILENO);
821 
822 	if ((fd = open("/dev/null", O_RDONLY)) == -1) {
823 		uu_warn(gettext("can't connect stdin to /dev/null"));
824 	} else if (fd != STDIN_FILENO) {
825 		(void) dup2(fd, STDIN_FILENO);
826 		startd_close(fd);
827 	}
828 
829 	closefrom(3);
830 	(void) dup2(STDERR_FILENO, STDOUT_FILENO);
831 
832 	(void) setsid();
833 	(void) chdir("/");
834 
835 	/* Use default umask that init handed us, but 022 to create files. */
836 	dmask = umask(022);
837 	fmask = umask(dmask);
838 
839 	return (0);
840 }
841 
842 /*ARGSUSED*/
843 static void
844 die_handler(int sig, siginfo_t *info, void *data)
845 {
846 	finished = 1;
847 }
848 
849 int
850 main(int argc, char *argv[])
851 {
852 	int opt;
853 	int daemonize = 1;
854 	struct sigaction act;
855 	sigset_t nullset;
856 	struct stat sb;
857 
858 	(void) uu_setpname(argv[0]);
859 
860 	st = startd_zalloc(sizeof (startd_state_t));
861 
862 	(void) pthread_mutexattr_init(&mutex_attrs);
863 #ifndef	NDEBUG
864 	(void) pthread_mutexattr_settype(&mutex_attrs,
865 	    PTHREAD_MUTEX_ERRORCHECK);
866 #endif
867 
868 	max_scf_name_size = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH);
869 	max_scf_value_size = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
870 	max_scf_fmri_size = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH);
871 
872 	if (max_scf_name_size == -1 || max_scf_value_size == -1 ||
873 	    max_scf_value_size == -1)
874 		uu_die("Can't determine repository maximum lengths.\n");
875 
876 	max_scf_name_size++;
877 	max_scf_value_size++;
878 	max_scf_fmri_size++;
879 
880 	st->st_log_flags = STARTD_LOG_FILE | STARTD_LOG_SYSLOG;
881 	st->st_log_level_min = LOG_NOTICE;
882 
883 	while ((opt = getopt(argc, argv, "nrs")) != EOF) {
884 		switch (opt) {
885 		case 'n':
886 			daemonize = 0;
887 			break;
888 		case 'r':			/* reconfiguration boot */
889 			opt_reconfig = 1;
890 			break;
891 		case 's':			/* single-user mode */
892 			booting_to_single_user = B_TRUE;
893 			break;
894 		default:
895 			usage(argv[0]);		/* exits */
896 		}
897 	}
898 
899 	if (optind != argc)
900 		usage(argv[0]);
901 
902 	(void) enable_extended_FILE_stdio(-1, -1);
903 
904 	if (daemonize)
905 		if (daemonize_start() < 0)
906 			uu_die("Can't daemonize\n");
907 
908 	log_init();
909 
910 	if (stat("/etc/svc/volatile/resetting", &sb) != -1) {
911 		log_framework(LOG_NOTICE, "Restarter quiesced.\n");
912 
913 		for (;;)
914 			(void) pause();
915 	}
916 
917 	act.sa_sigaction = &die_handler;
918 	(void) sigfillset(&act.sa_mask);
919 	act.sa_flags = SA_SIGINFO;
920 	(void) sigaction(SIGINT, &act, NULL);
921 	(void) sigaction(SIGTERM, &act, NULL);
922 
923 	startup();
924 
925 	(void) sigemptyset(&nullset);
926 	while (!finished) {
927 		log_framework(LOG_DEBUG, "Main thread paused\n");
928 		(void) sigsuspend(&nullset);
929 	}
930 
931 	(void) log_framework(LOG_DEBUG, "Restarter exiting.\n");
932 	return (0);
933 }
934