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