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.
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.
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]
23 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2015, Joyent, Inc.
28 * startd.c - the master restarter
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
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.
45 * Overview of the SMF Architecture
47 * There are a few different components that make up SMF and are responsible
48 * for different pieces of functionality that are used:
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
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
64 * The following block diagram explains how these components communicate:
66 * The SMF Block Diagram
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 +---------+ +--------+
75 * door_call(3C)| | door_call(3C)
78 * +----------+ +--------+ +--------+ +----------+
79 * | | | | | | | svccfg |
80 * | startd |<--->| libscf | | libscf |<---->| svcadm |
81 * | | | (3LIB) | | (3LIB) | | svcs |
82 * +----------+ +--------+ +--------+ +----------+
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 * +-------------------------------------------------------------------+
95 * Chatting with Configd and Sharing Repository Information
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.
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.
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.
120 * The Events of svc.startd
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().
136 * Threads/Functions Queues Threads/Functions
139 * +----------------+ +-------+ +-------------+
140 * --->| graph_protocol | graph_event | graph | graph_event_ | graph_event |
141 * --->| _send_event() |------------>| event |----------------->| _thread |
142 * +----------------+ _enqueue() | queue | dequeue() +-------------+
144 * _scf_notify_wait() vertex_send_event()|
146 * | +------------------+ +--------------------+
147 * +->| repository_event | vertex_send_event() | restarter_protocol |
148 * | _thread |----------------------------->| _send_event() |
149 * +------------------+ +--------------------+
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() +--------------+ +--------------------+
167 * ||+--------------->
168 * |+---------------->
169 * +----------------->
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.
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.
189 * External references
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
199 #include <stdio_ext.h>
200 #include <sys/mnttab.h> /* uses FILE * without including stdio.h */
202 #include <sys/mount.h>
203 #include <sys/stat.h>
204 #include <sys/types.h>
205 #include <sys/wait.h>
212 #include <libscf_priv.h>
213 #include <libuutil.h>
225 #include "protocol.h"
227 ssize_t max_scf_name_size
;
228 ssize_t max_scf_fmri_size
;
229 ssize_t max_scf_value_size
;
235 restarter_update_t
*ru
;
239 boolean_t booting_to_single_user
= B_FALSE
;
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
,
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
259 const char * const instance_state_str
[] = {
269 static int finished
= 0;
270 static int opt_reconfig
= 0;
271 static uint8_t prop_reconfig
= 0;
273 #define INITIAL_REBIND_ATTEMPTS 5
274 #define INITIAL_REBIND_DELAY 3
276 pthread_mutexattr_t mutex_attrs
;
280 _umem_debug_init(void)
282 return ("default,verbose"); /* UMEM_DEBUG setting */
286 _umem_logging_init(void)
288 return ("fail,contents"); /* UMEM_LOGGING setting */
293 _umem_options_init(void)
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...
301 return ("nomagazines"); /* UMEM_OPTIONS setting */
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
311 startd_alloc_retry(void *f(size_t, int), size_t sz
)
316 p
= f(sz
, UMEM_DEFAULT
);
317 if (p
!= NULL
|| sz
== 0)
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
);
330 uu_die("Insufficient memory.\n");
335 safe_realloc(void *p
, size_t sz
)
340 if (p
!= NULL
|| sz
== 0)
345 for (try = 0; errno
== EAGAIN
&& try < ALLOC_RETRY
; ++try) {
346 (void) poll(NULL
, 0, msecs
);
350 msecs
*= ALLOC_DELAY_MULT
;
353 uu_die("Insufficient memory.\n");
358 safe_strdup(const char *s
)
370 (errno
== EAGAIN
|| errno
== ENOMEM
) && try < ALLOC_RETRY
;
372 (void) poll(NULL
, 0, msecs
);
376 msecs
*= ALLOC_DELAY_MULT
;
379 uu_die("Insufficient memory.\n");
385 startd_free(void *p
, size_t sz
)
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.
395 startd_list_pool_create(const char *name
, size_t e
, size_t o
,
396 uu_compare_fn_t
*f
, uint32_t flags
)
398 uu_list_pool_t
*pool
;
401 pool
= uu_list_pool_create(name
, e
, o
, f
, flags
);
407 for (try = 0; uu_error() == UU_ERROR_NO_MEMORY
&& try < ALLOC_RETRY
;
409 (void) poll(NULL
, 0, msecs
);
410 pool
= uu_list_pool_create(name
, e
, o
, f
, flags
);
413 msecs
*= ALLOC_DELAY_MULT
;
416 if (try < ALLOC_RETRY
)
419 uu_die("Insufficient memory.\n");
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.
428 startd_list_create(uu_list_pool_t
*pool
, void *parent
, uint32_t flags
)
433 list
= uu_list_create(pool
, parent
, flags
);
439 for (try = 0; uu_error() == UU_ERROR_NO_MEMORY
&& try < ALLOC_RETRY
;
441 (void) poll(NULL
, 0, msecs
);
442 list
= uu_list_create(pool
, parent
, flags
);
445 msecs
*= ALLOC_DELAY_MULT
;
448 if (try < ALLOC_RETRY
)
451 uu_die("Insufficient memory.\n");
456 startd_thread_create(void *(*func
)(void *), void *ptr
)
461 err
= pthread_create(&tid
, NULL
, func
, ptr
);
463 assert(err
== EAGAIN
);
464 uu_die("Could not create thread.\n");
467 err
= pthread_detach(tid
);
473 extern int info_events_all
;
476 read_startd_config(void)
479 scf_instance_t
*inst
;
480 scf_propertygroup_t
*pg
;
481 scf_property_t
*prop
;
483 scf_iter_t
*iter
, *piter
;
484 instance_data_t idata
;
486 char *startd_options_fmri
= uu_msprintf("%s/:properties/options",
488 char *startd_reconfigure_fmri
= uu_msprintf(
489 "%s/:properties/system/reconfigure", SCF_SERVICE_STARTD
);
490 char *env_opts
, *lasts
, *cp
;
493 uint_t count
= 0, msecs
= ALLOC_DELAY
;
498 buf
= startd_alloc(max_scf_fmri_size
);
500 if (startd_options_fmri
== NULL
|| startd_reconfigure_fmri
== NULL
)
501 uu_die("Allocation failure\n");
503 st
->st_log_prefix
= LOG_PREFIX_EARLY
;
505 if ((st
->st_log_file
= getenv("STARTD_DEFAULT_LOG")) == NULL
) {
506 st
->st_log_file
= startd_alloc(strlen(STARTD_DEFAULT_LOG
) + 1);
508 (void) strcpy(st
->st_log_file
, STARTD_DEFAULT_LOG
);
511 st
->st_door_path
= getenv("STARTD_ALT_DOOR");
514 * Read "options" property group.
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
);
520 if (bind_fails
> INITIAL_REBIND_ATTEMPTS
) {
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
527 log_framework(LOG_INFO
, "Couldn't fetch "
528 "default settings: %s\n",
529 scf_strerror(scf_error()));
537 idata
.i_fmri
= SCF_SERVICE_STARTD
;
538 idata
.i_state
= RESTARTER_STATE_NONE
;
539 idata
.i_next_state
= RESTARTER_STATE_NONE
;
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
))) {
549 if (count
< ALLOC_RETRY
) {
550 (void) poll(NULL
, 0, msecs
);
551 msecs
*= ALLOC_DELAY_MULT
;
555 uu_die("Insufficient memory.\n");
559 libscf_handle_rebind(hndl
);
566 log_error(LOG_INFO
, "Could set state of %s: %s.\n",
567 idata
.i_fmri
, strerror(r
));
572 bad_error("_restarter_commit_states", r
);
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
);
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();
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
,
592 (void) libscf_note_method_log(inst
, LOG_PREFIX_EARLY
,
594 (void) libscf_note_method_log(inst
, LOG_PREFIX_NORMAL
,
598 /* Read reconfigure property for recovery. */
599 if (scf_handle_decode_fmri(hndl
, startd_reconfigure_fmri
, NULL
, NULL
,
600 NULL
, NULL
, prop
, NULL
) != -1 &&
601 scf_property_get_value(prop
, val
) == 0)
602 (void) scf_value_get_boolean(val
, &prop_reconfig
);
604 if (scf_handle_decode_fmri(hndl
, startd_options_fmri
, NULL
, NULL
, NULL
,
605 pg
, NULL
, SCF_DECODE_FMRI_TRUNCATE
) == -1) {
607 * No configuration options defined.
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()));
616 * If there is no "options" group defined, then our defaults are fine.
618 if (scf_pg_get_name(pg
, NULL
, 0) < 0)
621 /* get info_events_all */
622 info_events_all
= libscf_get_info_events_all(pg
);
624 /* Iterate through. */
625 iter
= safe_scf_iter_create(hndl
);
627 (void) scf_iter_pg_properties(iter
, pg
);
629 piter
= safe_scf_iter_create(hndl
);
630 vbuf
= startd_alloc(max_scf_value_size
);
632 while ((scf_iter_next_property(iter
, prop
) == 1)) {
635 if (scf_property_get_name(prop
, buf
, max_scf_fmri_size
) < 0)
638 if (strcmp(buf
, "logging") != 0 &&
639 strcmp(buf
, "boot_messages") != 0)
642 if (scf_property_type(prop
, &ty
) != 0) {
643 switch (scf_error()) {
644 case SCF_ERROR_CONNECTION_BROKEN
:
646 libscf_handle_rebind(hndl
);
649 case SCF_ERROR_DELETED
:
652 case SCF_ERROR_NOT_BOUND
:
653 case SCF_ERROR_NOT_SET
:
654 bad_error("scf_property_type", scf_error());
658 if (ty
!= SCF_TYPE_ASTRING
) {
659 uu_warn("property \"options/%s\" is not of type "
660 "astring; ignored.\n", buf
);
664 if (scf_property_get_value(prop
, val
) != 0) {
665 switch (scf_error()) {
666 case SCF_ERROR_CONNECTION_BROKEN
:
668 return (ECONNABORTED
);
670 case SCF_ERROR_DELETED
:
671 case SCF_ERROR_NOT_FOUND
:
674 case SCF_ERROR_CONSTRAINT_VIOLATED
:
675 uu_warn("property \"options/%s\" has multiple "
676 "values; ignored.\n", buf
);
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
);
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",
693 if (scf_value_get_astring(val
, vbuf
, max_scf_value_size
) < 0)
694 bad_error("scf_value_get_astring", scf_error());
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
;
706 uu_warn("unknown options/logging "
707 "value '%s' ignored\n", vbuf
);
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
;
716 log_framework(LOG_NOTICE
, "unknown "
717 "options/boot_messages value '%s' "
724 startd_free(vbuf
, max_scf_value_size
);
725 scf_iter_destroy(piter
);
727 scf_iter_destroy(iter
);
730 scf_value_destroy(val
);
732 scf_property_destroy(prop
);
733 scf_instance_destroy(inst
);
734 (void) scf_handle_unbind(hndl
);
735 scf_handle_destroy(hndl
);
738 startd_free(buf
, max_scf_fmri_size
);
739 uu_free(startd_options_fmri
);
740 uu_free(startd_reconfigure_fmri
);
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",
746 assert(sz
< max_scf_fmri_size
);
750 * Options passed in as boot arguments override repository defaults.
752 env_opts
= getenv("SMF_OPTIONS");
753 if (env_opts
== NULL
)
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
;
762 /* -m debug should send messages to console */
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;
776 if (booting_to_single_user
)
779 if (st
->st_subgraph
== NULL
) {
781 startd_alloc(max_scf_fmri_size
);
782 st
->st_subgraph
[0] = '\0';
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");
802 log_framework(LOG_NOTICE
,
803 "invalid milestone option value "
804 "'%s' ignored\n", mp
);
807 uu_warn("Unknown SMF option \"%s\".\n", cp
);
815 * void set_boot_env()
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.
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.
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
840 if (prop_reconfig
!= 1 && st
->st_initial
!= 1)
843 /* If /reconfigure exists, also set opt_reconfig. */
844 if (stat("/reconfigure", &sb
) != -1)
847 /* Nothing to do. Just return. */
848 if (opt_reconfig
== 0 && prop_reconfig
== 0)
852 * Set startd's reconfigure property. This property is
853 * then cleared by successful completion of the single-user
856 if (prop_reconfig
!= 1) {
857 r
= libscf_set_reconfig(1);
866 log_error(LOG_WARNING
, "Could not set reconfiguration "
867 "property: %s\n", strerror(r
));
871 bad_error("libscf_set_reconfig", r
);
883 * Initialize data structures.
885 gu
= startd_zalloc(sizeof (graph_update_t
));
886 ru
= startd_zalloc(sizeof (restarter_update_t
));
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
);
899 configd_ctid
= contract_init();
901 if (configd_ctid
!= -1)
902 log_framework(LOG_DEBUG
, "Existing configd contract %ld; not "
903 "starting svc.configd\n", configd_ctid
);
906 * Call utmpx_init() before creating the fork_configd() thread.
910 (void) startd_thread_create(fork_configd_thread
, (void *)configd_ctid
);
913 * Await, if necessary, configd's initial arrival.
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
);
923 MUTEX_UNLOCK(&st
->st_configd_live_lock
);
927 if (read_startd_config())
928 log_framework(LOG_INFO
, "svc.configd unable to provide startd "
929 "optional settings\n");
934 restarter_protocol_init();
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.
942 log_framework(LOG_DEBUG
, "Calling fork_emi...\n");
945 graph_protocol_init();
952 graph_engine_start();
956 usage(const char *name
)
958 uu_warn(gettext("usage: %s [-n]\n"), name
);
963 daemonize_start(void)
968 if ((pid
= fork1()) < 0)
974 (void) close(STDIN_FILENO
);
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
);
984 (void) dup2(STDERR_FILENO
, STDOUT_FILENO
);
989 /* Use default umask that init handed us, but 022 to create files. */
991 fmask
= umask(dmask
);
998 die_handler(int sig
, siginfo_t
*info
, void *data
)
1004 main(int argc
, char *argv
[])
1008 struct sigaction act
;
1012 (void) uu_setpname(argv
[0]);
1014 st
= startd_zalloc(sizeof (startd_state_t
));
1016 (void) pthread_mutexattr_init(&mutex_attrs
);
1018 (void) pthread_mutexattr_settype(&mutex_attrs
,
1019 PTHREAD_MUTEX_ERRORCHECK
);
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
);
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");
1030 max_scf_name_size
++;
1031 max_scf_value_size
++;
1032 max_scf_fmri_size
++;
1034 st
->st_log_flags
= STARTD_LOG_FILE
| STARTD_LOG_SYSLOG
;
1035 st
->st_log_level_min
= LOG_NOTICE
;
1037 while ((opt
= getopt(argc
, argv
, "nrs")) != EOF
) {
1042 case 'r': /* reconfiguration boot */
1045 case 's': /* single-user mode */
1046 booting_to_single_user
= B_TRUE
;
1049 usage(argv
[0]); /* exits */
1056 (void) enable_extended_FILE_stdio(-1, -1);
1059 if (daemonize_start() < 0)
1060 uu_die("Can't daemonize\n");
1064 if (stat("/etc/svc/volatile/resetting", &sb
) != -1) {
1065 log_framework(LOG_NOTICE
, "Restarter quiesced.\n");
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
);
1079 (void) sigemptyset(&nullset
);
1081 log_framework(LOG_DEBUG
, "Main thread paused\n");
1082 (void) sigsuspend(&nullset
);
1085 (void) log_framework(LOG_DEBUG
, "Restarter exiting.\n");