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(1M): A daemon that is in charge of starting, stopping, and
51 * restarting services and instances.
52 * svc.configd(1M): 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(1M): A utility to add and remove services as well as change the
58 * properties associated with different services and instances.
59 * svcadm(1M): 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 <sys/proc.h>
207 #include <assert.h>
208 #include <errno.h>
209 #include <fcntl.h>
210 #include <ftw.h>
211 #include <libintl.h>
212 #include <libscf.h>
213 #include <libscf_priv.h>
214 #include <libuutil.h>
215 #include <locale.h>
216 #include <poll.h>
217 #include <pthread.h>
218 #include <signal.h>
219 #include <stdarg.h>
220 #include <stdlib.h>
221 #include <string.h>
222 #include <strings.h>
223 #include <unistd.h>
224
225 #include "startd.h"
226 #include "protocol.h"
227
228 extern int psecflags(idtype_t, id_t, psecflags_cmd_t, uint_t);
229
230 ssize_t max_scf_name_size;
231 ssize_t max_scf_fmri_size;
232 ssize_t max_scf_value_size;
233
234 mode_t fmask;
235 mode_t dmask;
236
237 graph_update_t *gu;
238 restarter_update_t *ru;
239
240 startd_state_t *st;
241
242 boolean_t booting_to_single_user = B_FALSE;
243
244 const char * const admin_actions[] = {
245 SCF_PROPERTY_DEGRADED,
246 SCF_PROPERTY_MAINT_OFF,
247 SCF_PROPERTY_MAINT_ON,
248 SCF_PROPERTY_MAINT_ON_IMMEDIATE,
249 SCF_PROPERTY_REFRESH,
250 SCF_PROPERTY_RESTART
251 };
252
253 const int admin_events[NACTIONS] = {
254 RESTARTER_EVENT_TYPE_ADMIN_DEGRADED,
255 RESTARTER_EVENT_TYPE_ADMIN_MAINT_OFF,
256 RESTARTER_EVENT_TYPE_ADMIN_MAINT_ON,
257 RESTARTER_EVENT_TYPE_ADMIN_MAINT_ON_IMMEDIATE,
258 RESTARTER_EVENT_TYPE_ADMIN_REFRESH,
259 RESTARTER_EVENT_TYPE_ADMIN_RESTART
260 };
261
262 const char * const instance_state_str[] = {
263 "none",
264 "uninitialized",
265 "maintenance",
266 "offline",
267 "disabled",
268 "online",
269 "degraded"
270 };
271
272 static int finished = 0;
273 static int opt_reconfig = 0;
274 static uint8_t prop_reconfig = 0;
275
276 #define INITIAL_REBIND_ATTEMPTS 5
277 #define INITIAL_REBIND_DELAY 3
278
279 pthread_mutexattr_t mutex_attrs;
280
281 #ifdef DEBUG
282 const char *
283 _umem_debug_init(void)
284 {
285 return ("default,verbose"); /* UMEM_DEBUG setting */
286 }
287
288 const char *
289 _umem_logging_init(void)
290 {
291 return ("fail,contents"); /* UMEM_LOGGING setting */
292 }
293 #endif
294
295 const char *
296 _umem_options_init(void)
297 {
298 /*
299 * To reduce our memory footprint, we set our UMEM_OPTIONS to indicate
300 * that we do not wish to have per-CPU magazines -- if svc.startd is so
301 * hot on CPU such that this becomes a scalability problem, there are
302 * likely deeper things amiss...
303 */
304 return ("nomagazines"); /* UMEM_OPTIONS setting */
305 }
306
307 /*
308 * startd_alloc_retry()
309 * Wrapper for allocation functions. Retries with a decaying time
310 * value on failure to allocate, and aborts startd if failure is
311 * persistent.
312 */
313 void *
314 startd_alloc_retry(void *f(size_t, int), size_t sz)
315 {
316 void *p;
317 uint_t try, msecs;
318
319 p = f(sz, UMEM_DEFAULT);
320 if (p != NULL || sz == 0)
321 return (p);
322
323 msecs = ALLOC_DELAY;
324
325 for (try = 0; p == NULL && try < ALLOC_RETRY; ++try) {
326 (void) poll(NULL, 0, msecs);
327 msecs *= ALLOC_DELAY_MULT;
328 p = f(sz, UMEM_DEFAULT);
329 if (p != NULL)
330 return (p);
331 }
332
333 uu_die("Insufficient memory.\n");
334 /* NOTREACHED */
335 }
336
337 void *
338 safe_realloc(void *p, size_t sz)
339 {
340 uint_t try, msecs;
341
342 p = realloc(p, sz);
343 if (p != NULL || sz == 0)
344 return (p);
345
346 msecs = ALLOC_DELAY;
347
348 for (try = 0; errno == EAGAIN && try < ALLOC_RETRY; ++try) {
349 (void) poll(NULL, 0, msecs);
350 p = realloc(p, sz);
351 if (p != NULL)
352 return (p);
353 msecs *= ALLOC_DELAY_MULT;
354 }
355
356 uu_die("Insufficient memory.\n");
357 /* NOTREACHED */
358 }
359
360 char *
361 safe_strdup(const char *s)
362 {
363 uint_t try, msecs;
364 char *d;
365
366 d = strdup(s);
367 if (d != NULL)
368 return (d);
369
370 msecs = ALLOC_DELAY;
371
372 for (try = 0;
373 (errno == EAGAIN || errno == ENOMEM) && try < ALLOC_RETRY;
374 ++try) {
375 (void) poll(NULL, 0, msecs);
376 d = strdup(s);
377 if (d != NULL)
378 return (d);
379 msecs *= ALLOC_DELAY_MULT;
380 }
381
382 uu_die("Insufficient memory.\n");
383 /* NOTREACHED */
384 }
385
386
387 void
388 startd_free(void *p, size_t sz)
389 {
390 umem_free(p, sz);
391 }
392
393 /*
394 * Creates a uu_list_pool_t with the same retry policy as startd_alloc().
395 * Only returns NULL for UU_ERROR_UNKNOWN_FLAG and UU_ERROR_NOT_SUPPORTED.
396 */
397 uu_list_pool_t *
398 startd_list_pool_create(const char *name, size_t e, size_t o,
399 uu_compare_fn_t *f, uint32_t flags)
400 {
401 uu_list_pool_t *pool;
402 uint_t try, msecs;
403
404 pool = uu_list_pool_create(name, e, o, f, flags);
405 if (pool != NULL)
406 return (pool);
407
408 msecs = ALLOC_DELAY;
409
410 for (try = 0; uu_error() == UU_ERROR_NO_MEMORY && try < ALLOC_RETRY;
411 ++try) {
412 (void) poll(NULL, 0, msecs);
413 pool = uu_list_pool_create(name, e, o, f, flags);
414 if (pool != NULL)
415 return (pool);
416 msecs *= ALLOC_DELAY_MULT;
417 }
418
419 if (try < ALLOC_RETRY)
420 return (NULL);
421
422 uu_die("Insufficient memory.\n");
423 /* NOTREACHED */
424 }
425
426 /*
427 * Creates a uu_list_t with the same retry policy as startd_alloc(). Only
428 * returns NULL for UU_ERROR_UNKNOWN_FLAG and UU_ERROR_NOT_SUPPORTED.
429 */
430 uu_list_t *
431 startd_list_create(uu_list_pool_t *pool, void *parent, uint32_t flags)
432 {
433 uu_list_t *list;
434 uint_t try, msecs;
435
436 list = uu_list_create(pool, parent, flags);
437 if (list != NULL)
438 return (list);
439
440 msecs = ALLOC_DELAY;
441
442 for (try = 0; uu_error() == UU_ERROR_NO_MEMORY && try < ALLOC_RETRY;
443 ++try) {
444 (void) poll(NULL, 0, msecs);
445 list = uu_list_create(pool, parent, flags);
446 if (list != NULL)
447 return (list);
448 msecs *= ALLOC_DELAY_MULT;
449 }
450
451 if (try < ALLOC_RETRY)
452 return (NULL);
453
454 uu_die("Insufficient memory.\n");
455 /* NOTREACHED */
456 }
457
458 pthread_t
459 startd_thread_create(void *(*func)(void *), void *ptr)
460 {
461 int err;
462 pthread_t tid;
463
464 err = pthread_create(&tid, NULL, func, ptr);
465 if (err != 0) {
466 assert(err == EAGAIN);
467 uu_die("Could not create thread.\n");
468 }
469
470 err = pthread_detach(tid);
471 assert(err == 0);
472
473 return (tid);
474 }
475
476 extern int info_events_all;
477
478 struct psf_desc {
479 char *name;
480 uint_t flag;
481 } procsec_flag_tbl[] = {
482 { "aslr", PROC_SEC_ASLR },
483 { NULL, NULL }
484 };
485
486 static void
487 init_secflags(scf_handle_t *hndl)
488 {
489 scf_property_t *prop;
490 scf_value_t *val;
491 struct psf_desc *psfd = NULL;
492 char *proc_sec_fmri = "svc:/system/process-security/"
493 ":properties/secflags";
494
495 for (psfd = procsec_flag_tbl; psfd->name != NULL; psfd++) {
496 char *pfmri;
497 uint8_t flag;
498
499 prop = safe_scf_property_create(hndl);
500 val = safe_scf_value_create(hndl);
501
502 if ((pfmri = uu_msprintf("%s/%s", proc_sec_fmri, psfd->name)) == NULL)
503 uu_die("Allocation failure\n");
504
505 if (scf_handle_decode_fmri(hndl, pfmri,
506 NULL, NULL, NULL, NULL, prop, NULL) != 0)
507 goto next;
508
509 if (scf_property_get_value(prop, val) != 0)
510 goto next;
511
512 (void) scf_value_get_boolean(val, &flag);
513
514 /*
515 * XXX: This will fail if the zone had PRIV_PROC_SECFLAGS
516 * removed.
517 *
518 * I'm not sure what we should do in that case -- I'd still
519 * like this to be settable based on a zonecfg setting, too.
520 *
521 * We only set things explicitly _on_ here, rather than
522 * explicitly _off_ such that a zone's settings do not
523 * permanently override those from the GZ.
524 *
525 * XXX: This might be a bit crap, we sorta want a tri-state
526 */
527 if (flag != 0) {
528 if (psecflags(P_PID, P_MYID,
529 PSECFLAGS_ENABLE, psfd->flag) != 0) {
530 uu_warn("couldn't set security flags: %s\n",
531 strerror(errno));
532 }
533 }
534 next:
535 uu_free(pfmri);
536 scf_value_destroy(val);
537 scf_property_destroy(prop);
538 }
539 }
540
541 static int
542 read_startd_config(void)
543 {
544 scf_handle_t *hndl;
545 scf_instance_t *inst;
546 scf_propertygroup_t *pg;
547 scf_property_t *prop;
548 scf_value_t *val;
549 scf_iter_t *iter, *piter;
550 instance_data_t idata;
551 char *buf, *vbuf;
552 char *startd_options_fmri = uu_msprintf("%s/:properties/options",
553 SCF_SERVICE_STARTD);
554 char *startd_reconfigure_fmri = uu_msprintf(
555 "%s/:properties/system/reconfigure", SCF_SERVICE_STARTD);
556 char *env_opts, *lasts, *cp;
557 int bind_fails = 0;
558 int ret = 0, r;
559 uint_t count = 0, msecs = ALLOC_DELAY;
560 size_t sz;
561 ctid_t ctid;
562 uint64_t uint64;
563
564 buf = startd_alloc(max_scf_fmri_size);
565
566 if (startd_options_fmri == NULL || startd_reconfigure_fmri == NULL)
567 uu_die("Allocation failure\n");
568
569 st->st_log_prefix = LOG_PREFIX_EARLY;
570
571 if ((st->st_log_file = getenv("STARTD_DEFAULT_LOG")) == NULL) {
572 st->st_log_file = startd_alloc(strlen(STARTD_DEFAULT_LOG) + 1);
573
574 (void) strcpy(st->st_log_file, STARTD_DEFAULT_LOG);
575 }
576
577 st->st_door_path = getenv("STARTD_ALT_DOOR");
578
579 /*
580 * Read "options" property group.
581 */
582 for (hndl = libscf_handle_create_bound(SCF_VERSION); hndl == NULL;
583 hndl = libscf_handle_create_bound(SCF_VERSION), bind_fails++) {
584 (void) sleep(INITIAL_REBIND_DELAY);
585
586 if (bind_fails > INITIAL_REBIND_ATTEMPTS) {
587 /*
588 * In the case that we can't bind to the repository
589 * (which should have been started), we need to allow
590 * the user into maintenance mode to determine what's
591 * failed.
592 */
593 log_framework(LOG_INFO, "Couldn't fetch "
594 "default settings: %s\n",
595 scf_strerror(scf_error()));
596
597 ret = -1;
598
599 goto noscfout;
600 }
601 }
602
603 idata.i_fmri = SCF_SERVICE_STARTD;
604 idata.i_state = RESTARTER_STATE_NONE;
605 idata.i_next_state = RESTARTER_STATE_NONE;
606 timestamp:
607 switch (r = _restarter_commit_states(hndl, &idata,
608 RESTARTER_STATE_ONLINE, RESTARTER_STATE_NONE,
609 restarter_get_str_short(restarter_str_insert_in_graph))) {
610 case 0:
611 break;
612
613 case ENOMEM:
614 ++count;
615 if (count < ALLOC_RETRY) {
616 (void) poll(NULL, 0, msecs);
617 msecs *= ALLOC_DELAY_MULT;
618 goto timestamp;
619 }
620
621 uu_die("Insufficient memory.\n");
622 /* NOTREACHED */
623
624 case ECONNABORTED:
625 libscf_handle_rebind(hndl);
626 goto timestamp;
627
628 case ENOENT:
629 case EPERM:
630 case EACCES:
631 case EROFS:
632 log_error(LOG_INFO, "Could set state of %s: %s.\n",
633 idata.i_fmri, strerror(r));
634 break;
635
636 case EINVAL:
637 default:
638 bad_error("_restarter_commit_states", r);
639 }
640
641 pg = safe_scf_pg_create(hndl);
642 prop = safe_scf_property_create(hndl);
643 val = safe_scf_value_create(hndl);
644 inst = safe_scf_instance_create(hndl);
645
646 /* set startd's restarter properties */
647 if (scf_handle_decode_fmri(hndl, SCF_SERVICE_STARTD, NULL, NULL, inst,
648 NULL, NULL, SCF_DECODE_FMRI_EXACT) == 0) {
649 (void) libscf_write_start_pid(inst, getpid());
650 ctid = proc_get_ctid();
651 if (ctid != -1) {
652 uint64 = (uint64_t)ctid;
653 (void) libscf_inst_set_count_prop(inst,
654 SCF_PG_RESTARTER, SCF_PG_RESTARTER_TYPE,
655 SCF_PG_RESTARTER_FLAGS, SCF_PROPERTY_CONTRACT,
656 uint64);
657 }
658 (void) libscf_note_method_log(inst, LOG_PREFIX_EARLY,
659 STARTD_DEFAULT_LOG);
660 (void) libscf_note_method_log(inst, LOG_PREFIX_NORMAL,
661 STARTD_DEFAULT_LOG);
662 }
663
664 /* Read reconfigure property for recovery. */
665 if (scf_handle_decode_fmri(hndl, startd_reconfigure_fmri, NULL, NULL,
666 NULL, NULL, prop, NULL) != -1 &&
667 scf_property_get_value(prop, val) == 0)
668 (void) scf_value_get_boolean(val, &prop_reconfig);
669
670 /*
671 * Set up the initial process secflags. We do this super early, and
672 * in svc.startd, so that it's inherited by as much stuff as possible
673 * upon boot.
674 */
675 init_secflags(hndl);
676
677 if (scf_handle_decode_fmri(hndl, startd_options_fmri, NULL, NULL, NULL,
678 pg, NULL, SCF_DECODE_FMRI_TRUNCATE) == -1) {
679 /*
680 * No configuration options defined.
681 */
682 if (scf_error() != SCF_ERROR_NOT_FOUND)
683 uu_warn("Couldn't read configuration from 'options' "
684 "group: %s\n", scf_strerror(scf_error()));
685 goto scfout;
686 }
687
688 /*
689 * If there is no "options" group defined, then our defaults are fine.
690 */
691 if (scf_pg_get_name(pg, NULL, 0) < 0)
692 goto scfout;
693
694 /* get info_events_all */
695 info_events_all = libscf_get_info_events_all(pg);
696
697 /* Iterate through. */
698 iter = safe_scf_iter_create(hndl);
699
700 (void) scf_iter_pg_properties(iter, pg);
701
702 piter = safe_scf_iter_create(hndl);
703 vbuf = startd_alloc(max_scf_value_size);
704
705 while ((scf_iter_next_property(iter, prop) == 1)) {
706 scf_type_t ty;
707
708 if (scf_property_get_name(prop, buf, max_scf_fmri_size) < 0)
709 continue;
710
711 if (strcmp(buf, "logging") != 0 &&
712 strcmp(buf, "boot_messages") != 0)
713 continue;
714
715 if (scf_property_type(prop, &ty) != 0) {
716 switch (scf_error()) {
717 case SCF_ERROR_CONNECTION_BROKEN:
718 default:
719 libscf_handle_rebind(hndl);
720 continue;
721
722 case SCF_ERROR_DELETED:
723 continue;
724
725 case SCF_ERROR_NOT_BOUND:
726 case SCF_ERROR_NOT_SET:
727 bad_error("scf_property_type", scf_error());
728 }
729 }
730
731 if (ty != SCF_TYPE_ASTRING) {
732 uu_warn("property \"options/%s\" is not of type "
733 "astring; ignored.\n", buf);
734 continue;
735 }
736
737 if (scf_property_get_value(prop, val) != 0) {
738 switch (scf_error()) {
739 case SCF_ERROR_CONNECTION_BROKEN:
740 default:
741 return (ECONNABORTED);
742
743 case SCF_ERROR_DELETED:
744 case SCF_ERROR_NOT_FOUND:
745 return (0);
746
747 case SCF_ERROR_CONSTRAINT_VIOLATED:
748 uu_warn("property \"options/%s\" has multiple "
749 "values; ignored.\n", buf);
750 continue;
751
752 case SCF_ERROR_PERMISSION_DENIED:
753 uu_warn("property \"options/%s\" cannot be "
754 "read because startd has insufficient "
755 "permission; ignored.\n", buf);
756 continue;
757
758 case SCF_ERROR_HANDLE_MISMATCH:
759 case SCF_ERROR_NOT_BOUND:
760 case SCF_ERROR_NOT_SET:
761 bad_error("scf_property_get_value",
762 scf_error());
763 }
764 }
765
766 if (scf_value_get_astring(val, vbuf, max_scf_value_size) < 0)
767 bad_error("scf_value_get_astring", scf_error());
768
769 if (strcmp("logging", buf) == 0) {
770 if (strcmp("verbose", vbuf) == 0) {
771 st->st_boot_flags = STARTD_BOOT_VERBOSE;
772 st->st_log_level_min = LOG_INFO;
773 } else if (strcmp("debug", vbuf) == 0) {
774 st->st_boot_flags = STARTD_BOOT_VERBOSE;
775 st->st_log_level_min = LOG_DEBUG;
776 } else if (strcmp("quiet", vbuf) == 0) {
777 st->st_log_level_min = LOG_NOTICE;
778 } else {
779 uu_warn("unknown options/logging "
780 "value '%s' ignored\n", vbuf);
781 }
782
783 } else if (strcmp("boot_messages", buf) == 0) {
784 if (strcmp("quiet", vbuf) == 0) {
785 st->st_boot_flags = STARTD_BOOT_QUIET;
786 } else if (strcmp("verbose", vbuf) == 0) {
787 st->st_boot_flags = STARTD_BOOT_VERBOSE;
788 } else {
789 log_framework(LOG_NOTICE, "unknown "
790 "options/boot_messages value '%s' "
791 "ignored\n", vbuf);
792 }
793
794 }
795 }
796
797 startd_free(vbuf, max_scf_value_size);
798 scf_iter_destroy(piter);
799
800 scf_iter_destroy(iter);
801
802 scfout:
803 scf_value_destroy(val);
804 scf_pg_destroy(pg);
805 scf_property_destroy(prop);
806 scf_instance_destroy(inst);
807 (void) scf_handle_unbind(hndl);
808 scf_handle_destroy(hndl);
809
810 noscfout:
811 startd_free(buf, max_scf_fmri_size);
812 uu_free(startd_options_fmri);
813 uu_free(startd_reconfigure_fmri);
814
815 if (booting_to_single_user) {
816 st->st_subgraph = startd_alloc(max_scf_fmri_size);
817 sz = strlcpy(st->st_subgraph, "milestone/single-user:default",
818 max_scf_fmri_size);
819 assert(sz < max_scf_fmri_size);
820 }
821
822 /*
823 * Options passed in as boot arguments override repository defaults.
824 */
825 env_opts = getenv("SMF_OPTIONS");
826 if (env_opts == NULL)
827 return (ret);
828
829 for (cp = strtok_r(env_opts, ",", &lasts); cp != NULL;
830 cp = strtok_r(NULL, ",", &lasts)) {
831 if (strcmp(cp, "debug") == 0) {
832 st->st_boot_flags = STARTD_BOOT_VERBOSE;
833 st->st_log_level_min = LOG_DEBUG;
834
835 /* -m debug should send messages to console */
836 st->st_log_flags =
837 st->st_log_flags | STARTD_LOG_TERMINAL;
838 } else if (strcmp(cp, "verbose") == 0) {
839 st->st_boot_flags = STARTD_BOOT_VERBOSE;
840 st->st_log_level_min = LOG_INFO;
841 } else if (strcmp(cp, "seed") == 0) {
842 uu_warn("SMF option \"%s\" unimplemented.\n", cp);
843 } else if (strcmp(cp, "quiet") == 0) {
844 st->st_log_level_min = LOG_NOTICE;
845 } else if (strncmp(cp, "milestone=",
846 sizeof ("milestone=") - 1) == 0) {
847 char *mp = cp + sizeof ("milestone=") - 1;
848
849 if (booting_to_single_user)
850 continue;
851
852 if (st->st_subgraph == NULL) {
853 st->st_subgraph =
854 startd_alloc(max_scf_fmri_size);
855 st->st_subgraph[0] = '\0';
856 }
857
858 if (mp[0] == '\0' || strcmp(mp, "all") == 0) {
859 (void) strcpy(st->st_subgraph, "all");
860 } else if (strcmp(mp, "su") == 0 ||
861 strcmp(mp, "single-user") == 0) {
862 (void) strcpy(st->st_subgraph,
863 "milestone/single-user:default");
864 } else if (strcmp(mp, "mu") == 0 ||
865 strcmp(mp, "multi-user") == 0) {
866 (void) strcpy(st->st_subgraph,
867 "milestone/multi-user:default");
868 } else if (strcmp(mp, "mus") == 0 ||
869 strcmp(mp, "multi-user-server") == 0) {
870 (void) strcpy(st->st_subgraph,
871 "milestone/multi-user-server:default");
872 } else if (strcmp(mp, "none") == 0) {
873 (void) strcpy(st->st_subgraph, "none");
874 } else {
875 log_framework(LOG_NOTICE,
876 "invalid milestone option value "
877 "'%s' ignored\n", mp);
878 }
879 } else {
880 uu_warn("Unknown SMF option \"%s\".\n", cp);
881 }
882 }
883
884 return (ret);
885 }
886
887 /*
888 * void set_boot_env()
889 *
890 * If -r was passed or /reconfigure exists, this is a reconfig
891 * reboot. We need to make sure that this information is given
892 * to the appropriate services the first time they're started
893 * by setting the system/reconfigure repository property,
894 * as well as pass the _INIT_RECONFIG variable on to the rcS
895 * start method so that legacy services can continue to use it.
896 *
897 * This function must never be called before contract_init(), as
898 * it sets st_initial. get_startd_config() sets prop_reconfig from
899 * pre-existing repository state.
900 */
901 static void
902 set_boot_env()
903 {
904 struct stat sb;
905 int r;
906
907 /*
908 * Check if property still is set -- indicates we didn't get
909 * far enough previously to unset it. Otherwise, if this isn't
910 * the first startup, don't re-process /reconfigure or the
911 * boot flag.
912 */
913 if (prop_reconfig != 1 && st->st_initial != 1)
914 return;
915
916 /* If /reconfigure exists, also set opt_reconfig. */
917 if (stat("/reconfigure", &sb) != -1)
918 opt_reconfig = 1;
919
920 /* Nothing to do. Just return. */
921 if (opt_reconfig == 0 && prop_reconfig == 0)
922 return;
923
924 /*
925 * Set startd's reconfigure property. This property is
926 * then cleared by successful completion of the single-user
927 * milestone.
928 */
929 if (prop_reconfig != 1) {
930 r = libscf_set_reconfig(1);
931 switch (r) {
932 case 0:
933 break;
934
935 case ENOENT:
936 case EPERM:
937 case EACCES:
938 case EROFS:
939 log_error(LOG_WARNING, "Could not set reconfiguration "
940 "property: %s\n", strerror(r));
941 break;
942
943 default:
944 bad_error("libscf_set_reconfig", r);
945 }
946 }
947 }
948
949 static void
950 startup(void)
951 {
952 ctid_t configd_ctid;
953 int err;
954
955 /*
956 * Initialize data structures.
957 */
958 gu = startd_zalloc(sizeof (graph_update_t));
959 ru = startd_zalloc(sizeof (restarter_update_t));
960
961 (void) pthread_cond_init(&st->st_load_cv, NULL);
962 (void) pthread_cond_init(&st->st_configd_live_cv, NULL);
963 (void) pthread_cond_init(&gu->gu_cv, NULL);
964 (void) pthread_cond_init(&gu->gu_freeze_cv, NULL);
965 (void) pthread_cond_init(&ru->restarter_update_cv, NULL);
966 (void) pthread_mutex_init(&st->st_load_lock, &mutex_attrs);
967 (void) pthread_mutex_init(&st->st_configd_live_lock, &mutex_attrs);
968 (void) pthread_mutex_init(&gu->gu_lock, &mutex_attrs);
969 (void) pthread_mutex_init(&gu->gu_freeze_lock, &mutex_attrs);
970 (void) pthread_mutex_init(&ru->restarter_update_lock, &mutex_attrs);
971
972 configd_ctid = contract_init();
973
974 if (configd_ctid != -1)
975 log_framework(LOG_DEBUG, "Existing configd contract %ld; not "
976 "starting svc.configd\n", configd_ctid);
977
978 /*
979 * Call utmpx_init() before creating the fork_configd() thread.
980 */
981 utmpx_init();
982
983 (void) startd_thread_create(fork_configd_thread, (void *)configd_ctid);
984
985 /*
986 * Await, if necessary, configd's initial arrival.
987 */
988 MUTEX_LOCK(&st->st_configd_live_lock);
989 while (!st->st_configd_lives) {
990 log_framework(LOG_DEBUG, "Awaiting cv signal on "
991 "configd_live_cv\n");
992 err = pthread_cond_wait(&st->st_configd_live_cv,
993 &st->st_configd_live_lock);
994 assert(err == 0);
995 }
996 MUTEX_UNLOCK(&st->st_configd_live_lock);
997
998 wait_init();
999
1000 if (read_startd_config())
1001 log_framework(LOG_INFO, "svc.configd unable to provide startd "
1002 "optional settings\n");
1003
1004 log_init();
1005 dict_init();
1006 timeout_init();
1007 restarter_protocol_init();
1008 restarter_init();
1009
1010 /*
1011 * svc.configd is started by fork_configd_thread so repository access is
1012 * available, run early manifest import before continuing with starting
1013 * graph engine and the rest of startd.
1014 */
1015 log_framework(LOG_DEBUG, "Calling fork_emi...\n");
1016 fork_emi();
1017
1018 graph_protocol_init();
1019 graph_init();
1020
1021 init_env();
1022
1023 set_boot_env();
1024 restarter_start();
1025 graph_engine_start();
1026 }
1027
1028 static void
1029 usage(const char *name)
1030 {
1031 uu_warn(gettext("usage: %s [-n]\n"), name);
1032 exit(UU_EXIT_USAGE);
1033 }
1034
1035 static int
1036 daemonize_start(void)
1037 {
1038 pid_t pid;
1039 int fd;
1040
1041 if ((pid = fork1()) < 0)
1042 return (-1);
1043
1044 if (pid != 0)
1045 exit(0);
1046
1047 (void) close(STDIN_FILENO);
1048
1049 if ((fd = open("/dev/null", O_RDONLY)) == -1) {
1050 uu_warn(gettext("can't connect stdin to /dev/null"));
1051 } else if (fd != STDIN_FILENO) {
1052 (void) dup2(fd, STDIN_FILENO);
1053 startd_close(fd);
1054 }
1055
1056 closefrom(3);
1057 (void) dup2(STDERR_FILENO, STDOUT_FILENO);
1058
1059 (void) setsid();
1060 (void) chdir("/");
1061
1062 /* Use default umask that init handed us, but 022 to create files. */
1063 dmask = umask(022);
1064 fmask = umask(dmask);
1065
1066 return (0);
1067 }
1068
1069 /*ARGSUSED*/
1070 static void
1071 die_handler(int sig, siginfo_t *info, void *data)
1072 {
1073 finished = 1;
1074 }
1075
1076 int
1077 main(int argc, char *argv[])
1078 {
1079 int opt;
1080 int daemonize = 1;
1081 struct sigaction act;
1082 sigset_t nullset;
1083 struct stat sb;
1084
1085 (void) uu_setpname(argv[0]);
1086
1087 st = startd_zalloc(sizeof (startd_state_t));
1088
1089 (void) pthread_mutexattr_init(&mutex_attrs);
1090 #ifndef NDEBUG
1091 (void) pthread_mutexattr_settype(&mutex_attrs,
1092 PTHREAD_MUTEX_ERRORCHECK);
1093 #endif
1094
1095 max_scf_name_size = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH);
1096 max_scf_value_size = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
1097 max_scf_fmri_size = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH);
1098
1099 if (max_scf_name_size == -1 || max_scf_value_size == -1 ||
1100 max_scf_value_size == -1)
1101 uu_die("Can't determine repository maximum lengths.\n");
1102
1103 max_scf_name_size++;
1104 max_scf_value_size++;
1105 max_scf_fmri_size++;
1106
1107 st->st_log_flags = STARTD_LOG_FILE | STARTD_LOG_SYSLOG;
1108 st->st_log_level_min = LOG_NOTICE;
1109
1110 while ((opt = getopt(argc, argv, "nrs")) != EOF) {
1111 switch (opt) {
1112 case 'n':
1113 daemonize = 0;
1114 break;
1115 case 'r': /* reconfiguration boot */
1116 opt_reconfig = 1;
1117 break;
1118 case 's': /* single-user mode */
1119 booting_to_single_user = B_TRUE;
1120 break;
1121 default:
1122 usage(argv[0]); /* exits */
1123 }
1124 }
1125
1126 if (optind != argc)
1127 usage(argv[0]);
1128
1129 (void) enable_extended_FILE_stdio(-1, -1);
1130
1131 if (daemonize)
1132 if (daemonize_start() < 0)
1133 uu_die("Can't daemonize\n");
1134
1135 log_init();
1136
1137 if (stat("/etc/svc/volatile/resetting", &sb) != -1) {
1138 log_framework(LOG_NOTICE, "Restarter quiesced.\n");
1139
1140 for (;;)
1141 (void) pause();
1142 }
1143
1144 act.sa_sigaction = &die_handler;
1145 (void) sigfillset(&act.sa_mask);
1146 act.sa_flags = SA_SIGINFO;
1147 (void) sigaction(SIGINT, &act, NULL);
1148 (void) sigaction(SIGTERM, &act, NULL);
1149
1150 startup();
1151
1152 (void) sigemptyset(&nullset);
1153 while (!finished) {
1154 log_framework(LOG_DEBUG, "Main thread paused\n");
1155 (void) sigsuspend(&nullset);
1156 }
1157
1158 (void) log_framework(LOG_DEBUG, "Restarter exiting.\n");
1159 return (0);
1160 }