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