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 2018 Joyent, Inc.
25 * Copyright (c) 2015, Syneto S.R.L. All rights reserved.
26 * Copyright 2016 Toomas Soome <tsoome@me.com>
27 * Copyright 2016 RackTop Systems.
31 * graph.c - master restarter graph engine
33 * The graph engine keeps a dependency graph of all service instances on the
34 * system, as recorded in the repository. It decides when services should
35 * be brought up or down based on service states and dependencies and sends
36 * commands to restarters to effect any changes. It also executes
37 * administrator commands sent by svcadm via the repository.
39 * The graph is stored in uu_list_t *dgraph and its vertices are
40 * graph_vertex_t's, each of which has a name and an integer id unique to
41 * its name (see dict.c). A vertex's type attribute designates the type
42 * of object it represents: GVT_INST for service instances, GVT_SVC for
43 * service objects (since service instances may depend on another service,
44 * rather than service instance), GVT_FILE for files (which services may
45 * depend on), and GVT_GROUP for dependencies on multiple objects. GVT_GROUP
46 * vertices are necessary because dependency lists may have particular
47 * grouping types (require any, require all, optional, or exclude) and
48 * event-propagation characteristics.
50 * The initial graph is built by libscf_populate_graph() invoking
51 * dgraph_add_instance() for each instance in the repository. The function
52 * adds a GVT_SVC vertex for the service if one does not already exist, adds
53 * a GVT_INST vertex named by the FMRI of the instance, and sets up the edges.
54 * The resulting web of vertices & edges associated with an instance's vertex
57 * - an edge from the GVT_SVC vertex for the instance's service
59 * - an edge to the GVT_INST vertex of the instance's resarter, if its
60 * restarter is not svc.startd
62 * - edges from other GVT_INST vertices if the instance is a restarter
64 * - for each dependency property group in the instance's "running"
65 * snapshot, an edge to a GVT_GROUP vertex named by the FMRI of the
66 * instance and the name of the property group
68 * - for each value of the "entities" property in each dependency property
69 * group, an edge from the corresponding GVT_GROUP vertex to a
70 * GVT_INST, GVT_SVC, or GVT_FILE vertex
72 * - edges from GVT_GROUP vertices for each dependent instance
74 * After the edges are set up the vertex's GV_CONFIGURED flag is set. If
75 * there are problems, or if a service is mentioned in a dependency but does
76 * not exist in the repository, the GV_CONFIGURED flag will be clear.
78 * The graph and all of its vertices are protected by the dgraph_lock mutex.
79 * See restarter.c for more information.
81 * The properties of an instance fall into two classes: immediate and
82 * snapshotted. Immediate properties should have an immediate effect when
83 * changed. Snapshotted properties should be read from a snapshot, so they
84 * only change when the snapshot changes. The immediate properties used by
85 * the graph engine are general/enabled, general/restarter, and the properties
86 * in the restarter_actions property group. Since they are immediate, they
87 * are not read out of a snapshot. The snapshotted properties used by the
88 * graph engine are those in the property groups with type "dependency" and
89 * are read out of the "running" snapshot. The "running" snapshot is created
90 * by the the graph engine as soon as possible, and it is updated, along with
91 * in-core copies of the data (dependency information for the graph engine) on
92 * receipt of the refresh command from svcadm. In addition, the graph engine
93 * updates the "start" snapshot from the "running" snapshot whenever a service
96 * When a DISABLE event is requested by the administrator, svc.startd shutdown
97 * the dependents first before shutting down the requested service.
98 * In graph_enable_by_vertex, we create a subtree that contains the dependent
99 * vertices by marking those vertices with the GV_TOOFFLINE flag. And we mark
100 * the vertex to disable with the GV_TODISABLE flag. Once the tree is created,
101 * we send the _ADMIN_DISABLE event to the leaves. The leaves will then
102 * transition from STATE_ONLINE/STATE_DEGRADED to STATE_OFFLINE/STATE_MAINT.
103 * In gt_enter_offline and gt_enter_maint if the vertex was in a subtree then
104 * we clear the GV_TOOFFLINE flag and walk the dependencies to offline the new
105 * exposed leaves. We do the same until we reach the last leaf (the one with
106 * the GV_TODISABLE flag). If the vertex to disable is also part of a larger
107 * subtree (eg. multiple DISABLE events on vertices in the same subtree) then
108 * once the first vertex is disabled (GV_TODISABLE flag is removed), we
109 * continue to propagate the offline event to the vertex's dependencies.
112 * SMF state transition notifications
114 * When an instance of a service managed by SMF changes state, svc.startd may
115 * publish a GPEC sysevent. All transitions to or from maintenance, a
116 * transition cause by a hardware error will generate an event.
117 * Other transitions will generate an event if there exist notification
118 * parameter for that transition. Notification parameters are stored in the
119 * SMF repository for the service/instance they refer to. System-wide
120 * notification parameters are stored in the global instance.
121 * svc.startd can be told to send events for all SMF state transitions despite
122 * of notification parameters by setting options/info_events_all to true in
125 * The set of transitions that generate events is cached in the
126 * dgraph_vertex_t gv_stn_tset for service/instance and in the global
127 * stn_global for the system-wide set. They are re-read when instances are
130 * The GPEC events published by svc.startd are consumed by fmd(1M). After
131 * processing these events, fmd(1M) publishes the processed events to
132 * notification agents. The notification agents read the notification
133 * parameters from the SMF repository through libscf(3LIB) interfaces and send
134 * the notification, or not, based on those parameters.
136 * Subscription and publishing to the GPEC channels is done with the
137 * libfmevent(3LIB) wrappers fmev_[r]publish_*() and
138 * fmev_shdl_(un)subscribe().
142 #include <sys/uadmin.h>
143 #include <sys/wait.h>
148 #include <fm/libfmevent.h>
150 #include <libscf_priv.h>
151 #include <librestart.h>
152 #include <libuutil.h>
162 #include <sys/statvfs.h>
163 #include <sys/uadmin.h>
170 #include "protocol.h"
173 #define MILESTONE_NONE ((graph_vertex_t *)1)
175 #define CONSOLE_LOGIN_FMRI "svc:/system/console-login:default"
176 #define FS_MINIMAL_FMRI "svc:/system/filesystem/minimal:default"
178 #define VERTEX_REMOVED 0 /* vertex has been freed */
179 #define VERTEX_INUSE 1 /* vertex is still in use */
181 #define IS_ENABLED(v) ((v)->gv_flags & (GV_ENABLED | GV_ENBLD_NOOVR))
184 * stn_global holds the tset for the system wide notification parameters.
185 * It is updated on refresh of svc:/system/svc/global:default
187 * There are two assumptions that relax the need for a mutex:
188 * 1. 32-bit value assignments are atomic
189 * 2. Its value is consumed only in one point at
190 * dgraph_state_transition_notify(). There are no test and set races.
192 * If either assumption is broken, we'll need a mutex to synchronize
193 * access to stn_global
197 * info_events_all holds a flag to override notification parameters and send
198 * Information events for all state transitions.
199 * same about the need of a mutex here.
204 * Services in these states are not considered 'down' by the
205 * milestone/shutdown code.
207 #define up_state(state) ((state) == RESTARTER_STATE_ONLINE || \
208 (state) == RESTARTER_STATE_DEGRADED || \
209 (state) == RESTARTER_STATE_OFFLINE)
211 #define is_depgrp_bypassed(v) ((v->gv_type == GVT_GROUP) && \
212 ((v->gv_depgroup == DEPGRP_EXCLUDE_ALL) || \
213 (v->gv_restart < RERR_RESTART)))
215 #define is_inst_bypassed(v) ((v->gv_type == GVT_INST) && \
216 ((v->gv_flags & GV_TODISABLE) || \
217 (v->gv_flags & GV_TOOFFLINE)))
219 static uu_list_pool_t
*graph_edge_pool
, *graph_vertex_pool
;
220 static uu_list_t
*dgraph
;
221 static pthread_mutex_t dgraph_lock
;
224 * milestone indicates the current subgraph. When NULL, it is the entire
225 * graph. When MILESTONE_NONE, it is the empty graph. Otherwise, it is all
226 * services on which the target vertex depends.
228 static graph_vertex_t
*milestone
= NULL
;
229 static boolean_t initial_milestone_set
= B_FALSE
;
230 static pthread_cond_t initial_milestone_cv
= PTHREAD_COND_INITIALIZER
;
232 /* protected by dgraph_lock */
233 static boolean_t sulogin_thread_running
= B_FALSE
;
234 static boolean_t sulogin_running
= B_FALSE
;
235 static boolean_t console_login_ready
= B_FALSE
;
237 /* Number of services to come down to complete milestone transition. */
238 static uint_t non_subgraph_svcs
;
241 * These variables indicate what should be done when we reach the milestone
242 * target milestone, i.e., when non_subgraph_svcs == 0. They are acted upon in
243 * dgraph_set_instance_state().
245 static int halting
= -1;
246 static boolean_t go_single_user_mode
= B_FALSE
;
247 static boolean_t go_to_level1
= B_FALSE
;
250 * Tracks when we started halting.
252 static time_t halting_time
= 0;
255 * This tracks the legacy runlevel to ensure we signal init and manage
256 * utmpx entries correctly.
258 static char current_runlevel
= '\0';
260 /* Number of single user threads currently running */
261 static pthread_mutex_t single_user_thread_lock
;
262 static int single_user_thread_count
= 0;
264 /* Statistics for dependency cycle-checking */
265 static u_longlong_t dep_inserts
= 0;
266 static u_longlong_t dep_cycle_ns
= 0;
267 static u_longlong_t dep_insert_ns
= 0;
270 static const char * const emsg_invalid_restarter
=
271 "Transitioning %s to maintenance, restarter FMRI %s is invalid "
272 "(see 'svcs -xv' for details).\n";
273 static const char * const console_login_fmri
= CONSOLE_LOGIN_FMRI
;
274 static const char * const single_user_fmri
= SCF_MILESTONE_SINGLE_USER
;
275 static const char * const multi_user_fmri
= SCF_MILESTONE_MULTI_USER
;
276 static const char * const multi_user_svr_fmri
= SCF_MILESTONE_MULTI_USER_SERVER
;
280 * These services define the system being "up". If none of them can come
281 * online, then we will run sulogin on the console. Note that the install ones
282 * are for the miniroot and when installing CDs after the first. can_come_up()
283 * does the decision making, and an sulogin_thread() runs sulogin, which can be
284 * started by dgraph_set_instance_state() or single_user_thread().
286 * NOTE: can_come_up() relies on SCF_MILESTONE_SINGLE_USER being the first
287 * entry, which is only used when booting_to_single_user (boot -s) is set.
288 * This is because when doing a "boot -s", sulogin is started from specials.c
289 * after milestone/single-user comes online, for backwards compatibility.
290 * In this case, SCF_MILESTONE_SINGLE_USER needs to be part of up_svcs
291 * to ensure sulogin will be spawned if milestone/single-user cannot be reached.
293 static const char * const up_svcs
[] = {
294 SCF_MILESTONE_SINGLE_USER
,
296 "svc:/system/install-setup:default",
297 "svc:/system/install:default",
301 /* This array must have an element for each non-NULL element of up_svcs[]. */
302 static graph_vertex_t
*up_svcs_p
[] = { NULL
, NULL
, NULL
, NULL
};
304 /* These are for seed repository magic. See can_come_up(). */
305 static const char * const manifest_import
= SCF_INSTANCE_MI
;
306 static graph_vertex_t
*manifest_import_p
= NULL
;
309 static char target_milestone_as_runlevel(void);
310 static void graph_runlevel_changed(char rl
, int online
);
311 static int dgraph_set_milestone(const char *, scf_handle_t
*, boolean_t
);
312 static boolean_t
should_be_in_subgraph(graph_vertex_t
*v
);
313 static int mark_subtree(graph_edge_t
*, void *);
314 static boolean_t
insubtree_dependents_down(graph_vertex_t
*);
317 * graph_vertex_compare()
318 * This function can compare either int *id or * graph_vertex_t *gv
319 * values, as the vertex id is always the first element of a
320 * graph_vertex structure.
324 graph_vertex_compare(const void *lc_arg
, const void *rc_arg
, void *private)
326 int lc_id
= ((const graph_vertex_t
*)lc_arg
)->gv_id
;
327 int rc_id
= *(int *)rc_arg
;
339 graph_edge_pool
= startd_list_pool_create("graph_edges",
340 sizeof (graph_edge_t
), offsetof(graph_edge_t
, ge_link
), NULL
,
342 assert(graph_edge_pool
!= NULL
);
344 graph_vertex_pool
= startd_list_pool_create("graph_vertices",
345 sizeof (graph_vertex_t
), offsetof(graph_vertex_t
, gv_link
),
346 graph_vertex_compare
, UU_LIST_POOL_DEBUG
);
347 assert(graph_vertex_pool
!= NULL
);
349 (void) pthread_mutex_init(&dgraph_lock
, &mutex_attrs
);
350 (void) pthread_mutex_init(&single_user_thread_lock
, &mutex_attrs
);
351 dgraph
= startd_list_create(graph_vertex_pool
, NULL
, UU_LIST_SORTED
);
352 assert(dgraph
!= NULL
);
355 current_runlevel
= utmpx_get_runlevel();
357 log_framework(LOG_DEBUG
, "Initialized graph\n");
360 static graph_vertex_t
*
361 vertex_get_by_name(const char *name
)
365 assert(MUTEX_HELD(&dgraph_lock
));
367 id
= dict_lookup_byname(name
);
371 return (uu_list_find(dgraph
, &id
, NULL
, NULL
));
374 static graph_vertex_t
*
375 vertex_get_by_id(int id
)
377 assert(MUTEX_HELD(&dgraph_lock
));
382 return (uu_list_find(dgraph
, &id
, NULL
, NULL
));
386 * Creates a new vertex with the given name, adds it to the graph, and returns
387 * a pointer to it. The graph lock must be held by this thread on entry.
389 static graph_vertex_t
*
390 graph_add_vertex(const char *name
)
397 assert(MUTEX_HELD(&dgraph_lock
));
399 id
= dict_insert(name
);
401 v
= startd_zalloc(sizeof (*v
));
405 v
->gv_name
= startd_alloc(strlen(name
) + 1);
406 (void) strcpy(v
->gv_name
, name
);
408 v
->gv_dependencies
= startd_list_create(graph_edge_pool
, v
, 0);
409 v
->gv_dependents
= startd_list_create(graph_edge_pool
, v
, 0);
411 p
= uu_list_find(dgraph
, &id
, NULL
, &idx
);
414 uu_list_node_init(v
, &v
->gv_link
, graph_vertex_pool
);
415 uu_list_insert(dgraph
, v
, idx
);
421 * Removes v from the graph and frees it. The graph should be locked by this
422 * thread, and v should have no edges associated with it.
425 graph_remove_vertex(graph_vertex_t
*v
)
427 assert(MUTEX_HELD(&dgraph_lock
));
429 assert(uu_list_numnodes(v
->gv_dependencies
) == 0);
430 assert(uu_list_numnodes(v
->gv_dependents
) == 0);
431 assert(v
->gv_refs
== 0);
433 startd_free(v
->gv_name
, strlen(v
->gv_name
) + 1);
434 uu_list_destroy(v
->gv_dependencies
);
435 uu_list_destroy(v
->gv_dependents
);
436 uu_list_remove(dgraph
, v
);
438 startd_free(v
, sizeof (graph_vertex_t
));
442 graph_add_edge(graph_vertex_t
*fv
, graph_vertex_t
*tv
)
444 graph_edge_t
*e
, *re
;
447 assert(MUTEX_HELD(&dgraph_lock
));
449 e
= startd_alloc(sizeof (graph_edge_t
));
450 re
= startd_alloc(sizeof (graph_edge_t
));
458 uu_list_node_init(e
, &e
->ge_link
, graph_edge_pool
);
459 r
= uu_list_insert_before(fv
->gv_dependencies
, NULL
, e
);
462 uu_list_node_init(re
, &re
->ge_link
, graph_edge_pool
);
463 r
= uu_list_insert_before(tv
->gv_dependents
, NULL
, re
);
468 graph_remove_edge(graph_vertex_t
*v
, graph_vertex_t
*dv
)
472 for (e
= uu_list_first(v
->gv_dependencies
);
474 e
= uu_list_next(v
->gv_dependencies
, e
)) {
475 if (e
->ge_vertex
== dv
) {
476 uu_list_remove(v
->gv_dependencies
, e
);
477 startd_free(e
, sizeof (graph_edge_t
));
482 for (e
= uu_list_first(dv
->gv_dependents
);
484 e
= uu_list_next(dv
->gv_dependents
, e
)) {
485 if (e
->ge_vertex
== v
) {
486 uu_list_remove(dv
->gv_dependents
, e
);
487 startd_free(e
, sizeof (graph_edge_t
));
494 remove_inst_vertex(graph_vertex_t
*v
)
500 assert(MUTEX_HELD(&dgraph_lock
));
501 assert(uu_list_numnodes(v
->gv_dependents
) == 1);
502 assert(uu_list_numnodes(v
->gv_dependencies
) == 0);
503 assert(v
->gv_refs
== 0);
504 assert((v
->gv_flags
& GV_CONFIGURED
) == 0);
506 e
= uu_list_first(v
->gv_dependents
);
508 graph_remove_edge(sv
, v
);
510 for (i
= 0; up_svcs
[i
] != NULL
; ++i
) {
511 if (up_svcs_p
[i
] == v
)
515 if (manifest_import_p
== v
)
516 manifest_import_p
= NULL
;
518 graph_remove_vertex(v
);
520 if (uu_list_numnodes(sv
->gv_dependencies
) == 0 &&
521 uu_list_numnodes(sv
->gv_dependents
) == 0 &&
523 graph_remove_vertex(sv
);
527 graph_walk_dependents(graph_vertex_t
*v
, void (*func
)(graph_vertex_t
*, void *),
532 for (e
= uu_list_first(v
->gv_dependents
);
534 e
= uu_list_next(v
->gv_dependents
, e
))
535 func(e
->ge_vertex
, arg
);
539 graph_walk_dependencies(graph_vertex_t
*v
,
540 void (*func
)(graph_vertex_t
*, void *), void *arg
)
544 assert(MUTEX_HELD(&dgraph_lock
));
546 for (e
= uu_list_first(v
->gv_dependencies
);
548 e
= uu_list_next(v
->gv_dependencies
, e
)) {
550 func(e
->ge_vertex
, arg
);
555 * Generic graph walking function.
557 * Given a vertex, this function will walk either dependencies
558 * (WALK_DEPENDENCIES) or dependents (WALK_DEPENDENTS) of a vertex recursively
559 * for the entire graph. It will avoid cycles and never visit the same vertex
562 * We avoid traversing exclusion dependencies, because they are allowed to
563 * create cycles in the graph. When propagating satisfiability, there is no
564 * need to walk exclusion dependencies because exclude_all_satisfied() doesn't
565 * test for satisfiability.
567 * The walker takes two callbacks. The first is called before examining the
568 * dependents of each vertex. The second is called on each vertex after
569 * examining its dependents. This allows is_path_to() to construct a path only
570 * after the target vertex has been found.
577 typedef int (*graph_walk_cb_t
)(graph_vertex_t
*, void *);
579 typedef struct graph_walk_info
{
580 graph_walk_dir_t gi_dir
;
581 uchar_t
*gi_visited
; /* vertex bitmap */
582 int (*gi_pre
)(graph_vertex_t
*, void *);
583 void (*gi_post
)(graph_vertex_t
*, void *);
584 void *gi_arg
; /* callback arg */
585 int gi_ret
; /* return value */
589 graph_walk_recurse(graph_edge_t
*e
, graph_walk_info_t
*gip
)
593 graph_vertex_t
*v
= e
->ge_vertex
;
598 b
= 1 << (v
->gv_id
% 8);
601 * Check to see if we've visited this vertex already.
603 if (gip
->gi_visited
[i
] & b
)
604 return (UU_WALK_NEXT
);
606 gip
->gi_visited
[i
] |= b
;
609 * Don't follow exclusions.
611 if (v
->gv_type
== GVT_GROUP
&& v
->gv_depgroup
== DEPGRP_EXCLUDE_ALL
)
612 return (UU_WALK_NEXT
);
615 * Call pre-visit callback. If this doesn't terminate the walk,
618 if ((gip
->gi_ret
= gip
->gi_pre(v
, gip
->gi_arg
)) == UU_WALK_NEXT
) {
620 * Recurse using appropriate list.
622 if (gip
->gi_dir
== WALK_DEPENDENTS
)
623 list
= v
->gv_dependents
;
625 list
= v
->gv_dependencies
;
627 r
= uu_list_walk(list
, (uu_walk_fn_t
*)graph_walk_recurse
,
633 * Callbacks must return either UU_WALK_NEXT or UU_WALK_DONE.
635 assert(gip
->gi_ret
== UU_WALK_NEXT
|| gip
->gi_ret
== UU_WALK_DONE
);
638 * If given a post-callback, call the function for every vertex.
640 if (gip
->gi_post
!= NULL
)
641 (void) gip
->gi_post(v
, gip
->gi_arg
);
644 * Preserve the callback's return value. If the callback returns
645 * UU_WALK_DONE, then we propagate that to the caller in order to
646 * terminate the walk.
648 return (gip
->gi_ret
);
652 graph_walk(graph_vertex_t
*v
, graph_walk_dir_t dir
,
653 int (*pre
)(graph_vertex_t
*, void *),
654 void (*post
)(graph_vertex_t
*, void *), void *arg
)
656 graph_walk_info_t gi
;
658 size_t sz
= dictionary
->dict_new_id
/ 8 + 1;
660 gi
.gi_visited
= startd_zalloc(sz
);
668 * Fake up an edge for the first iteration
671 (void) graph_walk_recurse(&fake
, &gi
);
673 startd_free(gi
.gi_visited
, sz
);
676 typedef struct child_search
{
677 int id
; /* id of vertex to look for */
678 uint_t depth
; /* recursion depth */
680 * While the vertex is not found, path is NULL. After the search, if
681 * the vertex was found then path should point to a -1-terminated
682 * array of vertex id's which constitute the path to the vertex.
688 child_pre(graph_vertex_t
*v
, void *arg
)
690 child_search_t
*cs
= arg
;
694 if (v
->gv_id
== cs
->id
) {
695 cs
->path
= startd_alloc((cs
->depth
+ 1) * sizeof (int));
696 cs
->path
[cs
->depth
] = -1;
697 return (UU_WALK_DONE
);
700 return (UU_WALK_NEXT
);
704 child_post(graph_vertex_t
*v
, void *arg
)
706 child_search_t
*cs
= arg
;
710 if (cs
->path
!= NULL
)
711 cs
->path
[cs
->depth
] = v
->gv_id
;
715 * Look for a path from from to to. If one exists, returns a pointer to
716 * a NULL-terminated array of pointers to the vertices along the path. If
717 * there is no path, returns NULL.
720 is_path_to(graph_vertex_t
*from
, graph_vertex_t
*to
)
728 graph_walk(from
, WALK_DEPENDENCIES
, child_pre
, child_post
, &cs
);
734 * Given an array of int's as returned by is_path_to, allocates a string of
735 * their names joined by newlines. Returns the size of the allocated buffer
736 * in *sz and frees path.
739 path_to_str(int *path
, char **cpp
, size_t *sz
)
743 size_t allocd
, new_allocd
;
746 assert(MUTEX_HELD(&dgraph_lock
));
747 assert(path
[0] != -1);
750 *cpp
= startd_alloc(1);
753 for (i
= 0; path
[i
] != -1; ++i
) {
756 v
= vertex_get_by_id(path
[i
]);
760 else if (v
->gv_type
== GVT_INST
|| v
->gv_type
== GVT_SVC
)
764 new_allocd
= allocd
+ strlen(name
) + 1;
765 new = startd_alloc(new_allocd
);
766 (void) strcpy(new, *cpp
);
767 (void) strcat(new, name
);
768 (void) strcat(new, "\n");
770 startd_free(*cpp
, allocd
);
777 startd_free(path
, sizeof (int) * (i
+ 1));
784 * This function along with run_sulogin() implements an exclusion relationship
785 * between system/console-login and sulogin. run_sulogin() will fail if
786 * system/console-login is online, and the graph engine should call
787 * graph_clogin_start() to bring system/console-login online, which defers the
788 * start if sulogin is running.
791 graph_clogin_start(graph_vertex_t
*v
)
793 assert(MUTEX_HELD(&dgraph_lock
));
796 console_login_ready
= B_TRUE
;
798 vertex_send_event(v
, RESTARTER_EVENT_TYPE_START
);
802 graph_su_start(graph_vertex_t
*v
)
805 * /etc/inittab used to have the initial /sbin/rcS as a 'sysinit'
806 * entry with a runlevel of 'S', before jumping to the final
807 * target runlevel (as set in initdefault). We mimic that legacy
810 utmpx_set_runlevel('S', '0', B_FALSE
);
811 vertex_send_event(v
, RESTARTER_EVENT_TYPE_START
);
815 graph_post_su_online(void)
817 graph_runlevel_changed('S', 1);
821 graph_post_su_disable(void)
823 graph_runlevel_changed('S', 0);
827 graph_post_mu_online(void)
829 graph_runlevel_changed('2', 1);
833 graph_post_mu_disable(void)
835 graph_runlevel_changed('2', 0);
839 graph_post_mus_online(void)
841 graph_runlevel_changed('3', 1);
845 graph_post_mus_disable(void)
847 graph_runlevel_changed('3', 0);
850 static struct special_vertex_info
{
852 void (*start_f
)(graph_vertex_t
*);
853 void (*post_online_f
)(void);
854 void (*post_disable_f
)(void);
855 } special_vertices
[] = {
856 { CONSOLE_LOGIN_FMRI
, graph_clogin_start
, NULL
, NULL
},
857 { SCF_MILESTONE_SINGLE_USER
, graph_su_start
,
858 graph_post_su_online
, graph_post_su_disable
},
859 { SCF_MILESTONE_MULTI_USER
, NULL
,
860 graph_post_mu_online
, graph_post_mu_disable
},
861 { SCF_MILESTONE_MULTI_USER_SERVER
, NULL
,
862 graph_post_mus_online
, graph_post_mus_disable
},
868 vertex_send_event(graph_vertex_t
*v
, restarter_event_type_t e
)
871 case RESTARTER_EVENT_TYPE_ADD_INSTANCE
:
872 assert(v
->gv_state
== RESTARTER_STATE_UNINIT
);
874 MUTEX_LOCK(&st
->st_load_lock
);
875 st
->st_load_instances
++;
876 MUTEX_UNLOCK(&st
->st_load_lock
);
879 case RESTARTER_EVENT_TYPE_ENABLE
:
880 log_framework(LOG_DEBUG
, "Enabling %s.\n", v
->gv_name
);
881 assert(v
->gv_state
== RESTARTER_STATE_UNINIT
||
882 v
->gv_state
== RESTARTER_STATE_DISABLED
||
883 v
->gv_state
== RESTARTER_STATE_MAINT
);
886 case RESTARTER_EVENT_TYPE_DISABLE
:
887 case RESTARTER_EVENT_TYPE_ADMIN_DISABLE
:
888 log_framework(LOG_DEBUG
, "Disabling %s.\n", v
->gv_name
);
889 assert(v
->gv_state
!= RESTARTER_STATE_DISABLED
);
892 case RESTARTER_EVENT_TYPE_STOP_RESET
:
893 case RESTARTER_EVENT_TYPE_STOP
:
894 log_framework(LOG_DEBUG
, "Stopping %s.\n", v
->gv_name
);
895 assert(v
->gv_state
== RESTARTER_STATE_DEGRADED
||
896 v
->gv_state
== RESTARTER_STATE_ONLINE
);
899 case RESTARTER_EVENT_TYPE_START
:
900 log_framework(LOG_DEBUG
, "Starting %s.\n", v
->gv_name
);
901 assert(v
->gv_state
== RESTARTER_STATE_OFFLINE
);
904 case RESTARTER_EVENT_TYPE_REMOVE_INSTANCE
:
905 case RESTARTER_EVENT_TYPE_ADMIN_DEGRADED
:
906 case RESTARTER_EVENT_TYPE_ADMIN_REFRESH
:
907 case RESTARTER_EVENT_TYPE_ADMIN_RESTART
:
908 case RESTARTER_EVENT_TYPE_ADMIN_MAINT_OFF
:
909 case RESTARTER_EVENT_TYPE_ADMIN_MAINT_ON
:
910 case RESTARTER_EVENT_TYPE_ADMIN_MAINT_ON_IMMEDIATE
:
911 case RESTARTER_EVENT_TYPE_DEPENDENCY_CYCLE
:
912 case RESTARTER_EVENT_TYPE_INVALID_DEPENDENCY
:
917 uu_warn("%s:%d: Bad event %d.\n", __FILE__
, __LINE__
, e
);
922 restarter_protocol_send_event(v
->gv_name
, v
->gv_restarter_channel
, e
,
927 graph_unset_restarter(graph_vertex_t
*v
)
929 assert(MUTEX_HELD(&dgraph_lock
));
930 assert(v
->gv_flags
& GV_CONFIGURED
);
932 vertex_send_event(v
, RESTARTER_EVENT_TYPE_REMOVE_INSTANCE
);
934 if (v
->gv_restarter_id
!= -1) {
937 rv
= vertex_get_by_id(v
->gv_restarter_id
);
938 graph_remove_edge(v
, rv
);
941 v
->gv_restarter_id
= -1;
942 v
->gv_restarter_channel
= NULL
;
946 * Return VERTEX_REMOVED when the vertex passed in argument is deleted from the
947 * dgraph otherwise return VERTEX_INUSE.
950 free_if_unrefed(graph_vertex_t
*v
)
952 assert(MUTEX_HELD(&dgraph_lock
));
955 return (VERTEX_INUSE
);
957 if (v
->gv_type
== GVT_SVC
&&
958 uu_list_numnodes(v
->gv_dependents
) == 0 &&
959 uu_list_numnodes(v
->gv_dependencies
) == 0) {
960 graph_remove_vertex(v
);
961 return (VERTEX_REMOVED
);
962 } else if (v
->gv_type
== GVT_INST
&&
963 (v
->gv_flags
& GV_CONFIGURED
) == 0 &&
964 uu_list_numnodes(v
->gv_dependents
) == 1 &&
965 uu_list_numnodes(v
->gv_dependencies
) == 0) {
966 remove_inst_vertex(v
);
967 return (VERTEX_REMOVED
);
970 return (VERTEX_INUSE
);
974 delete_depgroup(graph_vertex_t
*v
)
979 assert(MUTEX_HELD(&dgraph_lock
));
980 assert(v
->gv_type
== GVT_GROUP
);
981 assert(uu_list_numnodes(v
->gv_dependents
) == 0);
983 while ((e
= uu_list_first(v
->gv_dependencies
)) != NULL
) {
986 graph_remove_edge(v
, dv
);
988 switch (dv
->gv_type
) {
989 case GVT_INST
: /* instance dependency */
990 case GVT_SVC
: /* service dependency */
991 (void) free_if_unrefed(dv
);
994 case GVT_FILE
: /* file dependency */
995 assert(uu_list_numnodes(dv
->gv_dependencies
) == 0);
996 if (uu_list_numnodes(dv
->gv_dependents
) == 0)
997 graph_remove_vertex(dv
);
1002 uu_warn("%s:%d: Unexpected node type %d", __FILE__
,
1003 __LINE__
, dv
->gv_type
);
1009 graph_remove_vertex(v
);
1013 delete_instance_deps_cb(graph_edge_t
*e
, void **ptrs
)
1015 graph_vertex_t
*v
= ptrs
[0];
1016 boolean_t delete_restarter_dep
= (boolean_t
)ptrs
[1];
1022 * We have four possibilities here:
1023 * - GVT_INST: restarter
1024 * - GVT_GROUP - GVT_INST: instance dependency
1025 * - GVT_GROUP - GVT_SVC - GV_INST: service dependency
1026 * - GVT_GROUP - GVT_FILE: file dependency
1028 switch (dv
->gv_type
) {
1029 case GVT_INST
: /* restarter */
1030 assert(dv
->gv_id
== v
->gv_restarter_id
);
1031 if (delete_restarter_dep
)
1032 graph_remove_edge(v
, dv
);
1035 case GVT_GROUP
: /* pg dependency */
1036 graph_remove_edge(v
, dv
);
1037 delete_depgroup(dv
);
1041 /* These are currently not direct dependencies */
1045 uu_warn("%s:%d: Bad vertex type %d.\n", __FILE__
, __LINE__
,
1051 return (UU_WALK_NEXT
);
1055 delete_instance_dependencies(graph_vertex_t
*v
, boolean_t delete_restarter_dep
)
1060 assert(MUTEX_HELD(&dgraph_lock
));
1061 assert(v
->gv_type
== GVT_INST
);
1064 ptrs
[1] = (void *)delete_restarter_dep
;
1066 r
= uu_list_walk(v
->gv_dependencies
,
1067 (uu_walk_fn_t
*)delete_instance_deps_cb
, &ptrs
, UU_WALK_ROBUST
);
1072 * int graph_insert_vertex_unconfigured()
1073 * Insert a vertex without sending any restarter events. If the vertex
1074 * already exists or creation is successful, return a pointer to it in *vp.
1076 * If type is not GVT_GROUP, dt can remain unset.
1078 * Returns 0, EEXIST, or EINVAL if the arguments are invalid (i.e., fmri
1079 * doesn't agree with type, or type doesn't agree with dt).
1082 graph_insert_vertex_unconfigured(const char *fmri
, gv_type_t type
,
1083 depgroup_type_t dt
, restarter_error_t rt
, graph_vertex_t
**vp
)
1088 assert(MUTEX_HELD(&dgraph_lock
));
1093 if (strncmp(fmri
, "svc:", sizeof ("svc:") - 1) != 0)
1098 if (strncmp(fmri
, "file:", sizeof ("file:") - 1) != 0)
1103 if (dt
<= 0 || rt
< 0)
1109 uu_warn("%s:%d: Unknown type %d.\n", __FILE__
, __LINE__
, type
);
1114 *vp
= vertex_get_by_name(fmri
);
1118 *vp
= graph_add_vertex(fmri
);
1120 (*vp
)->gv_type
= type
;
1121 (*vp
)->gv_depgroup
= dt
;
1122 (*vp
)->gv_restart
= rt
;
1124 (*vp
)->gv_flags
= 0;
1125 (*vp
)->gv_state
= RESTARTER_STATE_NONE
;
1127 for (i
= 0; special_vertices
[i
].name
!= NULL
; ++i
) {
1128 if (strcmp(fmri
, special_vertices
[i
].name
) == 0) {
1129 (*vp
)->gv_start_f
= special_vertices
[i
].start_f
;
1130 (*vp
)->gv_post_online_f
=
1131 special_vertices
[i
].post_online_f
;
1132 (*vp
)->gv_post_disable_f
=
1133 special_vertices
[i
].post_disable_f
;
1138 (*vp
)->gv_restarter_id
= -1;
1139 (*vp
)->gv_restarter_channel
= 0;
1141 if (type
== GVT_INST
) {
1145 sfmri
= inst_fmri_to_svc_fmri(fmri
);
1146 sv
= vertex_get_by_name(sfmri
);
1148 r
= graph_insert_vertex_unconfigured(sfmri
, GVT_SVC
, 0,
1152 startd_free(sfmri
, max_scf_fmri_size
);
1154 graph_add_edge(sv
, *vp
);
1158 * If this vertex is in the subgraph, mark it as so, for both
1159 * GVT_INST and GVT_SERVICE verteces.
1160 * A GVT_SERVICE vertex can only be in the subgraph if another instance
1161 * depends on it, in which case it's already been added to the graph
1162 * and marked as in the subgraph (by refresh_vertex()). If a
1163 * GVT_SERVICE vertex was freshly added (by the code above), it means
1164 * that it has no dependents, and cannot be in the subgraph.
1165 * Regardless of this, we still check that gv_flags includes
1166 * GV_INSUBGRAPH in the event that future behavior causes the above
1167 * code to add a GVT_SERVICE vertex which should be in the subgraph.
1170 (*vp
)->gv_flags
|= (should_be_in_subgraph(*vp
)? GV_INSUBGRAPH
: 0);
1176 * Returns 0 on success or ELOOP if the dependency would create a cycle.
1179 graph_insert_dependency(graph_vertex_t
*fv
, graph_vertex_t
*tv
, int **pathp
)
1183 assert(MUTEX_HELD(&dgraph_lock
));
1185 /* cycle detection */
1188 /* Don't follow exclusions. */
1189 if (!(fv
->gv_type
== GVT_GROUP
&&
1190 fv
->gv_depgroup
== DEPGRP_EXCLUDE_ALL
)) {
1191 *pathp
= is_path_to(tv
, fv
);
1196 dep_cycle_ns
+= gethrtime() - now
;
1200 graph_add_edge(fv
, tv
);
1202 dep_insert_ns
+= gethrtime() - now
;
1204 /* Check if the dependency adds the "to" vertex to the subgraph */
1205 tv
->gv_flags
|= (should_be_in_subgraph(tv
) ? GV_INSUBGRAPH
: 0);
1211 inst_running(graph_vertex_t
*v
)
1213 assert(v
->gv_type
== GVT_INST
);
1215 if (v
->gv_state
== RESTARTER_STATE_ONLINE
||
1216 v
->gv_state
== RESTARTER_STATE_DEGRADED
)
1223 * The dependency evaluation functions return
1224 * 1 - dependency satisfied
1225 * 0 - dependency unsatisfied
1226 * -1 - dependency unsatisfiable (without administrator intervention)
1228 * The functions also take a boolean satbility argument. When true, the
1229 * functions may recurse in order to determine satisfiability.
1231 static int require_any_satisfied(graph_vertex_t
*, boolean_t
);
1232 static int dependency_satisfied(graph_vertex_t
*, boolean_t
);
1235 * A require_all dependency is unsatisfied if any elements are unsatisfied. It
1236 * is unsatisfiable if any elements are unsatisfiable.
1239 require_all_satisfied(graph_vertex_t
*groupv
, boolean_t satbility
)
1243 boolean_t any_unsatisfied
;
1245 if (uu_list_numnodes(groupv
->gv_dependencies
) == 0)
1248 any_unsatisfied
= B_FALSE
;
1250 for (edge
= uu_list_first(groupv
->gv_dependencies
);
1252 edge
= uu_list_next(groupv
->gv_dependencies
, edge
)) {
1253 i
= dependency_satisfied(edge
->ge_vertex
, satbility
);
1257 log_framework2(LOG_DEBUG
, DEBUG_DEPENDENCIES
,
1258 "require_all(%s): %s is unsatisfi%s.\n", groupv
->gv_name
,
1259 edge
->ge_vertex
->gv_name
, i
== 0 ? "ed" : "able");
1267 any_unsatisfied
= B_TRUE
;
1270 return (any_unsatisfied
? 0 : 1);
1274 * A require_any dependency is satisfied if any element is satisfied. It is
1275 * satisfiable if any element is satisfiable.
1278 require_any_satisfied(graph_vertex_t
*groupv
, boolean_t satbility
)
1282 boolean_t satisfiable
;
1284 if (uu_list_numnodes(groupv
->gv_dependencies
) == 0)
1287 satisfiable
= B_FALSE
;
1289 for (edge
= uu_list_first(groupv
->gv_dependencies
);
1291 edge
= uu_list_next(groupv
->gv_dependencies
, edge
)) {
1292 s
= dependency_satisfied(edge
->ge_vertex
, satbility
);
1297 log_framework2(LOG_DEBUG
, DEBUG_DEPENDENCIES
,
1298 "require_any(%s): %s is unsatisfi%s.\n",
1299 groupv
->gv_name
, edge
->ge_vertex
->gv_name
,
1300 s
== 0 ? "ed" : "able");
1302 if (satbility
&& s
== 0)
1303 satisfiable
= B_TRUE
;
1306 return ((!satbility
|| satisfiable
) ? 0 : -1);
1310 * An optional_all dependency only considers elements which are configured,
1311 * enabled, and not in maintenance. If any are unsatisfied, then the dependency
1314 * Offline dependencies which are waiting for a dependency to come online are
1315 * unsatisfied. Offline dependences which cannot possibly come online
1316 * (unsatisfiable) are always considered satisfied.
1319 optional_all_satisfied(graph_vertex_t
*groupv
, boolean_t satbility
)
1323 boolean_t any_qualified
;
1324 boolean_t any_unsatisfied
;
1327 any_qualified
= B_FALSE
;
1328 any_unsatisfied
= B_FALSE
;
1330 for (edge
= uu_list_first(groupv
->gv_dependencies
);
1332 edge
= uu_list_next(groupv
->gv_dependencies
, edge
)) {
1333 v
= edge
->ge_vertex
;
1335 switch (v
->gv_type
) {
1337 /* Skip missing instances */
1338 if ((v
->gv_flags
& GV_CONFIGURED
) == 0)
1341 if (v
->gv_state
== RESTARTER_STATE_MAINT
)
1344 any_qualified
= B_TRUE
;
1345 if (v
->gv_state
== RESTARTER_STATE_OFFLINE
||
1346 v
->gv_state
== RESTARTER_STATE_DISABLED
) {
1348 * For offline/disabled dependencies,
1349 * treat unsatisfiable as satisfied.
1351 i
= dependency_satisfied(v
, B_TRUE
);
1355 i
= dependency_satisfied(v
, satbility
);
1360 any_qualified
= B_TRUE
;
1361 i
= dependency_satisfied(v
, satbility
);
1366 any_qualified
= B_TRUE
;
1367 i
= optional_all_satisfied(v
, satbility
);
1375 uu_warn("%s:%d: Unexpected vertex type %d.\n", __FILE__
,
1376 __LINE__
, v
->gv_type
);
1384 log_framework2(LOG_DEBUG
, DEBUG_DEPENDENCIES
,
1385 "optional_all(%s): %s is unsatisfi%s.\n", groupv
->gv_name
,
1386 v
->gv_name
, i
== 0 ? "ed" : "able");
1392 any_unsatisfied
= B_TRUE
;
1398 return (any_unsatisfied
? 0 : 1);
1402 * An exclude_all dependency is unsatisfied if any non-service element is
1403 * satisfied or any service instance which is configured, enabled, and not in
1404 * maintenance is satisfied. Usually when unsatisfied, it is also
1407 #define LOG_EXCLUDE(u, v) \
1408 log_framework2(LOG_DEBUG, DEBUG_DEPENDENCIES, \
1409 "exclude_all(%s): %s is satisfied.\n", \
1410 (u)->gv_name, (v)->gv_name)
1414 exclude_all_satisfied(graph_vertex_t
*groupv
, boolean_t satbility
)
1416 graph_edge_t
*edge
, *e2
;
1417 graph_vertex_t
*v
, *v2
;
1419 for (edge
= uu_list_first(groupv
->gv_dependencies
);
1421 edge
= uu_list_next(groupv
->gv_dependencies
, edge
)) {
1422 v
= edge
->ge_vertex
;
1424 switch (v
->gv_type
) {
1426 if ((v
->gv_flags
& GV_CONFIGURED
) == 0)
1429 switch (v
->gv_state
) {
1430 case RESTARTER_STATE_ONLINE
:
1431 case RESTARTER_STATE_DEGRADED
:
1432 LOG_EXCLUDE(groupv
, v
);
1433 return (v
->gv_flags
& GV_ENABLED
? -1 : 0);
1435 case RESTARTER_STATE_OFFLINE
:
1436 case RESTARTER_STATE_UNINIT
:
1437 LOG_EXCLUDE(groupv
, v
);
1440 case RESTARTER_STATE_DISABLED
:
1441 case RESTARTER_STATE_MAINT
:
1446 uu_warn("%s:%d: Unexpected vertex state %d.\n",
1447 __FILE__
, __LINE__
, v
->gv_state
);
1459 LOG_EXCLUDE(groupv
, v
);
1465 uu_warn("%s:%d: Unexpected vertex type %d.\n", __FILE__
,
1466 __LINE__
, v
->gv_type
);
1471 /* v represents a service */
1472 if (uu_list_numnodes(v
->gv_dependencies
) == 0)
1475 for (e2
= uu_list_first(v
->gv_dependencies
);
1477 e2
= uu_list_next(v
->gv_dependencies
, e2
)) {
1479 assert(v2
->gv_type
== GVT_INST
);
1481 if ((v2
->gv_flags
& GV_CONFIGURED
) == 0)
1484 switch (v2
->gv_state
) {
1485 case RESTARTER_STATE_ONLINE
:
1486 case RESTARTER_STATE_DEGRADED
:
1487 LOG_EXCLUDE(groupv
, v2
);
1488 return (v2
->gv_flags
& GV_ENABLED
? -1 : 0);
1490 case RESTARTER_STATE_OFFLINE
:
1491 case RESTARTER_STATE_UNINIT
:
1492 LOG_EXCLUDE(groupv
, v2
);
1495 case RESTARTER_STATE_DISABLED
:
1496 case RESTARTER_STATE_MAINT
:
1501 uu_warn("%s:%d: Unexpected vertex type %d.\n",
1502 __FILE__
, __LINE__
, v2
->gv_type
);
1513 * int instance_satisfied()
1514 * Determine if all the dependencies are satisfied for the supplied instance
1515 * vertex. Return 1 if they are, 0 if they aren't, and -1 if they won't be
1516 * without administrator intervention.
1519 instance_satisfied(graph_vertex_t
*v
, boolean_t satbility
)
1521 assert(v
->gv_type
== GVT_INST
);
1522 assert(!inst_running(v
));
1524 return (require_all_satisfied(v
, satbility
));
1528 * Decide whether v can satisfy a dependency. v can either be a child of
1529 * a group vertex, or of an instance vertex.
1532 dependency_satisfied(graph_vertex_t
*v
, boolean_t satbility
)
1534 switch (v
->gv_type
) {
1536 if ((v
->gv_flags
& GV_CONFIGURED
) == 0) {
1537 if (v
->gv_flags
& GV_DEATHROW
) {
1539 * A dependency on an instance with GV_DEATHROW
1540 * flag is always considered as satisfied.
1548 * Vertices may be transitioning so we try to figure out if
1549 * the end state is likely to satisfy the dependency instead
1550 * of assuming the dependency is unsatisfied/unsatisfiable.
1552 * Support for optional_all dependencies depends on us getting
1553 * this right because unsatisfiable dependencies are treated
1554 * as being satisfied.
1556 switch (v
->gv_state
) {
1557 case RESTARTER_STATE_ONLINE
:
1558 case RESTARTER_STATE_DEGRADED
:
1559 if (v
->gv_flags
& GV_TODISABLE
)
1561 if (v
->gv_flags
& GV_TOOFFLINE
)
1565 case RESTARTER_STATE_OFFLINE
:
1566 if (!satbility
|| v
->gv_flags
& GV_TODISABLE
)
1567 return (satbility
? -1 : 0);
1568 return (instance_satisfied(v
, satbility
) != -1 ?
1571 case RESTARTER_STATE_DISABLED
:
1572 if (!satbility
|| !(v
->gv_flags
& GV_ENABLED
))
1573 return (satbility
? -1 : 0);
1574 return (instance_satisfied(v
, satbility
) != -1 ?
1577 case RESTARTER_STATE_MAINT
:
1580 case RESTARTER_STATE_UNINIT
:
1585 uu_warn("%s:%d: Unexpected vertex state %d.\n",
1586 __FILE__
, __LINE__
, v
->gv_state
);
1593 if (uu_list_numnodes(v
->gv_dependencies
) == 0)
1595 return (require_any_satisfied(v
, satbility
));
1598 /* i.e., we assume files will not be automatically generated */
1599 return (file_ready(v
) ? 1 : -1);
1606 uu_warn("%s:%d: Unexpected node type %d.\n", __FILE__
, __LINE__
,
1613 switch (v
->gv_depgroup
) {
1614 case DEPGRP_REQUIRE_ANY
:
1615 return (require_any_satisfied(v
, satbility
));
1617 case DEPGRP_REQUIRE_ALL
:
1618 return (require_all_satisfied(v
, satbility
));
1620 case DEPGRP_OPTIONAL_ALL
:
1621 return (optional_all_satisfied(v
, satbility
));
1623 case DEPGRP_EXCLUDE_ALL
:
1624 return (exclude_all_satisfied(v
, satbility
));
1628 uu_warn("%s:%d: Unknown dependency grouping %d.\n", __FILE__
,
1629 __LINE__
, v
->gv_depgroup
);
1636 graph_start_if_satisfied(graph_vertex_t
*v
)
1638 if (v
->gv_state
== RESTARTER_STATE_OFFLINE
&&
1639 instance_satisfied(v
, B_FALSE
) == 1) {
1640 if (v
->gv_start_f
== NULL
)
1641 vertex_send_event(v
, RESTARTER_EVENT_TYPE_START
);
1648 * propagate_satbility()
1650 * This function is used when the given vertex changes state in such a way that
1651 * one of its dependents may become unsatisfiable. This happens when an
1652 * instance transitions between offline -> online, or from !running ->
1653 * maintenance, as well as when an instance is removed from the graph.
1655 * We have to walk all the dependents, since optional_all dependencies several
1656 * levels up could become (un)satisfied, instead of unsatisfiable. For example,
1658 * +-----+ optional_all +-----+ require_all +-----+
1659 * | A |--------------->| B |-------------->| C |
1660 * +-----+ +-----+ +-----+
1662 * offline -> maintenance
1664 * If C goes into maintenance, it's not enough simply to check B. Because A has
1665 * an optional dependency, what was previously an unsatisfiable situation is now
1666 * satisfied (B will never come online, even though its state hasn't changed).
1668 * Note that it's not necessary to continue examining dependents after reaching
1669 * an optional_all dependency. It's not possible for an optional_all dependency
1670 * to change satisfiability without also coming online, in which case we get a
1671 * start event and propagation continues naturally. However, it does no harm to
1672 * continue propagating satisfiability (as it is a relatively rare event), and
1673 * keeps the walker code simple and generic.
1677 satbility_cb(graph_vertex_t
*v
, void *arg
)
1679 if (is_inst_bypassed(v
))
1680 return (UU_WALK_NEXT
);
1682 if (v
->gv_type
== GVT_INST
)
1683 graph_start_if_satisfied(v
);
1685 return (UU_WALK_NEXT
);
1689 propagate_satbility(graph_vertex_t
*v
)
1691 graph_walk(v
, WALK_DEPENDENTS
, satbility_cb
, NULL
, NULL
);
1694 static void propagate_stop(graph_vertex_t
*, void *);
1699 * This function is used to propagate a start event to the dependents of the
1700 * given vertex. Any dependents that are offline but have their dependencies
1701 * satisfied are started. Any dependents that are online and have restart_on
1702 * set to "restart" or "refresh" are restarted because their dependencies have
1703 * just changed. This only happens with optional_all dependencies.
1706 propagate_start(graph_vertex_t
*v
, void *arg
)
1708 restarter_error_t err
= (restarter_error_t
)arg
;
1710 if (is_inst_bypassed(v
))
1713 switch (v
->gv_type
) {
1716 if (inst_running(v
)) {
1717 if (err
== RERR_RESTART
|| err
== RERR_REFRESH
) {
1718 vertex_send_event(v
,
1719 RESTARTER_EVENT_TYPE_STOP_RESET
);
1722 graph_start_if_satisfied(v
);
1727 if (v
->gv_depgroup
== DEPGRP_EXCLUDE_ALL
) {
1728 graph_walk_dependents(v
, propagate_stop
,
1729 (void *)RERR_RESTART
);
1732 err
= v
->gv_restart
;
1736 graph_walk_dependents(v
, propagate_start
, (void *)err
);
1741 uu_warn("%s:%d: propagate_start() encountered GVT_FILE.\n",
1742 __FILE__
, __LINE__
);
1749 uu_warn("%s:%d: Unknown vertex type %d.\n", __FILE__
, __LINE__
,
1759 * This function is used to propagate a stop event to the dependents of the
1760 * given vertex. Any dependents that are online (or in degraded state) with
1761 * the restart_on property set to "restart" or "refresh" will be stopped as
1762 * their dependencies have just changed, propagate_start() will start them
1763 * again once their dependencies have been re-satisfied.
1766 propagate_stop(graph_vertex_t
*v
, void *arg
)
1768 restarter_error_t err
= (restarter_error_t
)arg
;
1770 if (is_inst_bypassed(v
))
1773 switch (v
->gv_type
) {
1776 if (err
> RERR_NONE
&& inst_running(v
)) {
1777 if (err
== RERR_RESTART
|| err
== RERR_REFRESH
) {
1778 vertex_send_event(v
,
1779 RESTARTER_EVENT_TYPE_STOP_RESET
);
1781 vertex_send_event(v
, RESTARTER_EVENT_TYPE_STOP
);
1787 graph_walk_dependents(v
, propagate_stop
, arg
);
1792 uu_warn("%s:%d: propagate_stop() encountered GVT_FILE.\n",
1793 __FILE__
, __LINE__
);
1799 if (v
->gv_depgroup
== DEPGRP_EXCLUDE_ALL
) {
1800 graph_walk_dependents(v
, propagate_start
,
1805 if (err
== RERR_NONE
|| err
> v
->gv_restart
)
1808 graph_walk_dependents(v
, propagate_stop
, arg
);
1813 uu_warn("%s:%d: Unknown vertex type %d.\n", __FILE__
, __LINE__
,
1821 offline_vertex(graph_vertex_t
*v
)
1823 scf_handle_t
*h
= libscf_handle_create_bound_loop();
1824 scf_instance_t
*scf_inst
= safe_scf_instance_create(h
);
1825 scf_propertygroup_t
*pg
= safe_scf_pg_create(h
);
1826 restarter_instance_state_t state
, next_state
;
1829 assert(v
->gv_type
== GVT_INST
);
1831 if (scf_inst
== NULL
)
1832 bad_error("safe_scf_instance_create", scf_error());
1834 bad_error("safe_scf_pg_create", scf_error());
1836 /* if the vertex is already going offline, return */
1838 if (scf_handle_decode_fmri(h
, v
->gv_name
, NULL
, NULL
, scf_inst
, NULL
,
1839 NULL
, SCF_DECODE_FMRI_EXACT
) != 0) {
1840 switch (scf_error()) {
1841 case SCF_ERROR_CONNECTION_BROKEN
:
1842 libscf_handle_rebind(h
);
1845 case SCF_ERROR_NOT_FOUND
:
1847 scf_instance_destroy(scf_inst
);
1848 (void) scf_handle_unbind(h
);
1849 scf_handle_destroy(h
);
1852 uu_die("Can't decode FMRI %s: %s\n", v
->gv_name
,
1853 scf_strerror(scf_error()));
1856 r
= scf_instance_get_pg(scf_inst
, SCF_PG_RESTARTER
, pg
);
1858 switch (scf_error()) {
1859 case SCF_ERROR_CONNECTION_BROKEN
:
1860 libscf_handle_rebind(h
);
1863 case SCF_ERROR_NOT_SET
:
1864 case SCF_ERROR_NOT_FOUND
:
1866 scf_instance_destroy(scf_inst
);
1867 (void) scf_handle_unbind(h
);
1868 scf_handle_destroy(h
);
1872 bad_error("scf_instance_get_pg", scf_error());
1875 r
= libscf_read_states(pg
, &state
, &next_state
);
1876 if (r
== 0 && (next_state
== RESTARTER_STATE_OFFLINE
||
1877 next_state
== RESTARTER_STATE_DISABLED
)) {
1878 log_framework(LOG_DEBUG
,
1879 "%s: instance is already going down.\n",
1882 scf_instance_destroy(scf_inst
);
1883 (void) scf_handle_unbind(h
);
1884 scf_handle_destroy(h
);
1890 scf_instance_destroy(scf_inst
);
1891 (void) scf_handle_unbind(h
);
1892 scf_handle_destroy(h
);
1894 vertex_send_event(v
, RESTARTER_EVENT_TYPE_STOP_RESET
);
1898 * void graph_enable_by_vertex()
1899 * If admin is non-zero, this is an administrative request for change
1900 * of the enabled property. Thus, send the ADMIN_DISABLE rather than
1901 * a plain DISABLE restarter event.
1904 graph_enable_by_vertex(graph_vertex_t
*vertex
, int enable
, int admin
)
1909 assert(MUTEX_HELD(&dgraph_lock
));
1910 assert((vertex
->gv_flags
& GV_CONFIGURED
));
1912 vertex
->gv_flags
= (vertex
->gv_flags
& ~GV_ENABLED
) |
1913 (enable
? GV_ENABLED
: 0);
1916 if (vertex
->gv_state
!= RESTARTER_STATE_OFFLINE
&&
1917 vertex
->gv_state
!= RESTARTER_STATE_DEGRADED
&&
1918 vertex
->gv_state
!= RESTARTER_STATE_ONLINE
) {
1920 * In case the vertex was notified to go down,
1921 * but now can return online, clear the _TOOFFLINE
1922 * and _TODISABLE flags.
1924 vertex
->gv_flags
&= ~GV_TOOFFLINE
;
1925 vertex
->gv_flags
&= ~GV_TODISABLE
;
1927 vertex_send_event(vertex
, RESTARTER_EVENT_TYPE_ENABLE
);
1931 * Wait for state update from restarter before sending _START or
1938 if (vertex
->gv_state
== RESTARTER_STATE_DISABLED
)
1942 vertex_send_event(vertex
, RESTARTER_EVENT_TYPE_DISABLE
);
1945 * Wait for state update from restarter before sending _START or
1953 * If it is a DISABLE event requested by the administrator then we are
1954 * offlining the dependents first.
1958 * Set GV_TOOFFLINE for the services we are offlining. We cannot
1959 * clear the GV_TOOFFLINE bits from all the services because
1960 * other DISABLE events might be handled at the same time.
1962 vertex
->gv_flags
|= GV_TOOFFLINE
;
1964 /* remember which vertex to disable... */
1965 vertex
->gv_flags
|= GV_TODISABLE
;
1967 log_framework(LOG_DEBUG
, "Marking in-subtree vertices before "
1968 "disabling %s.\n", vertex
->gv_name
);
1970 /* set GV_TOOFFLINE for its dependents */
1971 r
= uu_list_walk(vertex
->gv_dependents
, (uu_walk_fn_t
*)mark_subtree
,
1975 /* disable the instance now if there is nothing else to offline */
1976 if (insubtree_dependents_down(vertex
) == B_TRUE
) {
1977 vertex_send_event(vertex
, RESTARTER_EVENT_TYPE_ADMIN_DISABLE
);
1982 * This loop is similar to the one used for the graph reversal shutdown
1983 * and could be improved in term of performance for the subtree reversal
1986 for (v
= uu_list_first(dgraph
); v
!= NULL
;
1987 v
= uu_list_next(dgraph
, v
)) {
1988 /* skip the vertex we are disabling for now */
1992 if (v
->gv_type
!= GVT_INST
||
1993 (v
->gv_flags
& GV_CONFIGURED
) == 0 ||
1994 (v
->gv_flags
& GV_ENABLED
) == 0 ||
1995 (v
->gv_flags
& GV_TOOFFLINE
) == 0)
1998 if ((v
->gv_state
!= RESTARTER_STATE_ONLINE
) &&
1999 (v
->gv_state
!= RESTARTER_STATE_DEGRADED
)) {
2000 /* continue if there is nothing to offline */
2005 * Instances which are up need to come down before we're
2006 * done, but we can only offline the leaves here. An
2007 * instance is a leaf when all its dependents are down.
2009 if (insubtree_dependents_down(v
) == B_TRUE
) {
2010 log_framework(LOG_DEBUG
, "Offlining in-subtree "
2011 "instance %s for %s.\n",
2012 v
->gv_name
, vertex
->gv_name
);
2018 static int configure_vertex(graph_vertex_t
*, scf_instance_t
*);
2021 * Set the restarter for v to fmri_arg. That is, make sure a vertex for
2022 * fmri_arg exists, make v depend on it, and send _ADD_INSTANCE for v. If
2023 * v is already configured and fmri_arg indicates the current restarter, do
2024 * nothing. If v is configured and fmri_arg is a new restarter, delete v's
2025 * dependency on the restarter, send _REMOVE_INSTANCE for v, and set the new
2026 * restarter. Returns 0 on success, EINVAL if the FMRI is invalid,
2027 * ECONNABORTED if the repository connection is broken, and ELOOP
2028 * if the dependency would create a cycle. In the last case, *pathp will
2029 * point to a -1-terminated array of ids which compose the path from v to
2033 graph_change_restarter(graph_vertex_t
*v
, const char *fmri_arg
, scf_handle_t
*h
,
2036 char *restarter_fmri
= NULL
;
2041 assert(MUTEX_HELD(&dgraph_lock
));
2043 if (fmri_arg
[0] != '\0') {
2044 err
= fmri_canonify(fmri_arg
, &restarter_fmri
, B_TRUE
);
2046 assert(err
== EINVAL
);
2051 if (restarter_fmri
== NULL
||
2052 strcmp(restarter_fmri
, SCF_SERVICE_STARTD
) == 0) {
2053 if (v
->gv_flags
& GV_CONFIGURED
) {
2054 if (v
->gv_restarter_id
== -1) {
2055 if (restarter_fmri
!= NULL
)
2056 startd_free(restarter_fmri
,
2061 graph_unset_restarter(v
);
2064 /* Master restarter, nothing to do. */
2065 v
->gv_restarter_id
= -1;
2066 v
->gv_restarter_channel
= NULL
;
2067 vertex_send_event(v
, RESTARTER_EVENT_TYPE_ADD_INSTANCE
);
2071 if (v
->gv_flags
& GV_CONFIGURED
) {
2072 id
= dict_lookup_byname(restarter_fmri
);
2073 if (id
!= -1 && v
->gv_restarter_id
== id
) {
2074 startd_free(restarter_fmri
, max_scf_fmri_size
);
2078 graph_unset_restarter(v
);
2081 err
= graph_insert_vertex_unconfigured(restarter_fmri
, GVT_INST
, 0,
2083 startd_free(restarter_fmri
, max_scf_fmri_size
);
2084 assert(err
== 0 || err
== EEXIST
);
2086 if (rv
->gv_delegate_initialized
== 0) {
2087 if ((rv
->gv_delegate_channel
= restarter_protocol_init_delegate(
2088 rv
->gv_name
)) == NULL
)
2090 rv
->gv_delegate_initialized
= 1;
2092 v
->gv_restarter_id
= rv
->gv_id
;
2093 v
->gv_restarter_channel
= rv
->gv_delegate_channel
;
2095 err
= graph_insert_dependency(v
, rv
, pathp
);
2097 assert(err
== ELOOP
);
2101 vertex_send_event(v
, RESTARTER_EVENT_TYPE_ADD_INSTANCE
);
2103 if (!(rv
->gv_flags
& GV_CONFIGURED
)) {
2104 scf_instance_t
*inst
;
2106 err
= libscf_fmri_get_instance(h
, rv
->gv_name
, &inst
);
2109 err
= configure_vertex(rv
, inst
);
2110 scf_instance_destroy(inst
);
2117 return (ECONNABORTED
);
2120 bad_error("configure_vertex", err
);
2125 return (ECONNABORTED
);
2132 * The fmri doesn't specify an instance - translate
2139 bad_error("libscf_fmri_get_instance", err
);
2148 * Add all of the instances of the service named by fmri to the graph.
2151 * ENOENT - service indicated by fmri does not exist
2153 * In both cases *reboundp will be B_TRUE if the handle was rebound, or B_FALSE
2157 add_service(const char *fmri
, scf_handle_t
*h
, boolean_t
*reboundp
)
2160 scf_instance_t
*inst
;
2165 *reboundp
= B_FALSE
;
2167 svc
= safe_scf_service_create(h
);
2168 inst
= safe_scf_instance_create(h
);
2169 iter
= safe_scf_iter_create(h
);
2170 inst_fmri
= startd_alloc(max_scf_fmri_size
);
2173 if (scf_handle_decode_fmri(h
, fmri
, NULL
, svc
, NULL
, NULL
, NULL
,
2174 SCF_DECODE_FMRI_EXACT
) != 0) {
2175 switch (scf_error()) {
2176 case SCF_ERROR_CONNECTION_BROKEN
:
2178 libscf_handle_rebind(h
);
2182 case SCF_ERROR_NOT_FOUND
:
2186 case SCF_ERROR_INVALID_ARGUMENT
:
2187 case SCF_ERROR_CONSTRAINT_VIOLATED
:
2188 case SCF_ERROR_NOT_BOUND
:
2189 case SCF_ERROR_HANDLE_MISMATCH
:
2190 bad_error("scf_handle_decode_fmri", scf_error());
2194 if (scf_iter_service_instances(iter
, svc
) != 0) {
2195 switch (scf_error()) {
2196 case SCF_ERROR_CONNECTION_BROKEN
:
2198 libscf_handle_rebind(h
);
2202 case SCF_ERROR_DELETED
:
2206 case SCF_ERROR_HANDLE_MISMATCH
:
2207 case SCF_ERROR_NOT_BOUND
:
2208 case SCF_ERROR_NOT_SET
:
2209 bad_error("scf_iter_service_instances", scf_error());
2214 r
= scf_iter_next_instance(iter
, inst
);
2218 switch (scf_error()) {
2219 case SCF_ERROR_CONNECTION_BROKEN
:
2221 libscf_handle_rebind(h
);
2225 case SCF_ERROR_DELETED
:
2229 case SCF_ERROR_HANDLE_MISMATCH
:
2230 case SCF_ERROR_NOT_BOUND
:
2231 case SCF_ERROR_NOT_SET
:
2232 case SCF_ERROR_INVALID_ARGUMENT
:
2233 bad_error("scf_iter_next_instance",
2238 if (scf_instance_to_fmri(inst
, inst_fmri
, max_scf_fmri_size
) <
2240 switch (scf_error()) {
2241 case SCF_ERROR_CONNECTION_BROKEN
:
2242 libscf_handle_rebind(h
);
2246 case SCF_ERROR_DELETED
:
2249 case SCF_ERROR_NOT_BOUND
:
2250 case SCF_ERROR_NOT_SET
:
2251 bad_error("scf_instance_to_fmri", scf_error());
2255 r
= dgraph_add_instance(inst_fmri
, inst
, B_FALSE
);
2265 libscf_handle_rebind(h
);
2271 bad_error("dgraph_add_instance", r
);
2278 startd_free(inst_fmri
, max_scf_fmri_size
);
2279 scf_iter_destroy(iter
);
2280 scf_instance_destroy(inst
);
2281 scf_service_destroy(svc
);
2285 struct depfmri_info
{
2286 graph_vertex_t
*v
; /* GVT_GROUP vertex */
2287 gv_type_t type
; /* type of dependency */
2288 const char *inst_fmri
; /* FMRI of parental GVT_INST vert. */
2289 const char *pg_name
; /* Name of dependency pg */
2291 int err
; /* return error code */
2292 int **pathp
; /* return circular dependency path */
2296 * Find or create a vertex for fmri and make info->v depend on it.
2301 * On failure, sets info->err to
2302 * EINVAL - fmri is invalid
2303 * fmri does not match info->type
2304 * ELOOP - Adding the dependency creates a circular dependency. *info->pathp
2305 * will point to an array of the ids of the members of the cycle.
2306 * ECONNABORTED - repository connection was broken
2307 * ECONNRESET - succeeded, but repository connection was reset
2310 process_dependency_fmri(const char *fmri
, struct depfmri_info
*info
)
2313 graph_vertex_t
*depgroup_v
, *v
;
2314 char *fmri_copy
, *cfmri
;
2315 size_t fmri_copy_sz
;
2316 const char *scope
, *service
, *instance
, *pg
;
2317 scf_instance_t
*inst
;
2320 assert(MUTEX_HELD(&dgraph_lock
));
2322 /* Get or create vertex for FMRI */
2323 depgroup_v
= info
->v
;
2325 if (strncmp(fmri
, "file:", sizeof ("file:") - 1) == 0) {
2326 if (info
->type
!= GVT_FILE
) {
2327 log_framework(LOG_NOTICE
,
2328 "FMRI \"%s\" is not allowed for the \"%s\" "
2329 "dependency's type of instance %s.\n", fmri
,
2330 info
->pg_name
, info
->inst_fmri
);
2331 return (info
->err
= EINVAL
);
2334 err
= graph_insert_vertex_unconfigured(fmri
, info
->type
, 0,
2341 assert(v
->gv_type
== GVT_FILE
);
2344 case EINVAL
: /* prevented above */
2346 bad_error("graph_insert_vertex_unconfigured", err
);
2349 if (info
->type
!= GVT_INST
) {
2350 log_framework(LOG_NOTICE
,
2351 "FMRI \"%s\" is not allowed for the \"%s\" "
2352 "dependency's type of instance %s.\n", fmri
,
2353 info
->pg_name
, info
->inst_fmri
);
2354 return (info
->err
= EINVAL
);
2358 * We must canonify fmri & add a vertex for it.
2360 fmri_copy_sz
= strlen(fmri
) + 1;
2361 fmri_copy
= startd_alloc(fmri_copy_sz
);
2362 (void) strcpy(fmri_copy
, fmri
);
2364 /* Determine if the FMRI is a property group or instance */
2365 if (scf_parse_svc_fmri(fmri_copy
, &scope
, &service
,
2366 &instance
, &pg
, NULL
) != 0) {
2367 startd_free(fmri_copy
, fmri_copy_sz
);
2368 log_framework(LOG_NOTICE
,
2369 "Dependency \"%s\" of %s has invalid FMRI "
2370 "\"%s\".\n", info
->pg_name
, info
->inst_fmri
,
2372 return (info
->err
= EINVAL
);
2375 if (service
== NULL
|| pg
!= NULL
) {
2376 startd_free(fmri_copy
, fmri_copy_sz
);
2377 log_framework(LOG_NOTICE
,
2378 "Dependency \"%s\" of %s does not designate a "
2379 "service or instance.\n", info
->pg_name
,
2381 return (info
->err
= EINVAL
);
2384 if (scope
== NULL
|| strcmp(scope
, SCF_SCOPE_LOCAL
) == 0) {
2385 cfmri
= uu_msprintf("svc:/%s%s%s",
2386 service
, instance
? ":" : "", instance
? instance
:
2389 cfmri
= uu_msprintf("svc://%s/%s%s%s",
2390 scope
, service
, instance
? ":" : "", instance
?
2394 startd_free(fmri_copy
, fmri_copy_sz
);
2396 err
= graph_insert_vertex_unconfigured(cfmri
, instance
?
2397 GVT_INST
: GVT_SVC
, instance
? 0 : DEPGRP_REQUIRE_ANY
,
2406 if (instance
!= NULL
)
2407 assert(v
->gv_type
== GVT_INST
);
2409 assert(v
->gv_type
== GVT_SVC
);
2413 bad_error("graph_insert_vertex_unconfigured", err
);
2417 /* Add dependency from depgroup_v to new vertex */
2418 info
->err
= graph_insert_dependency(depgroup_v
, v
, info
->pathp
);
2419 switch (info
->err
) {
2427 bad_error("graph_insert_dependency", info
->err
);
2430 /* This must be after we insert the dependency, to avoid looping. */
2431 switch (v
->gv_type
) {
2433 if ((v
->gv_flags
& GV_CONFIGURED
) != 0)
2436 inst
= safe_scf_instance_create(info
->h
);
2441 err
= libscf_lookup_instance(v
->gv_name
, inst
);
2444 err
= configure_vertex(v
, inst
);
2451 libscf_handle_rebind(info
->h
);
2456 bad_error("configure_vertex", err
);
2464 libscf_handle_rebind(info
->h
);
2471 bad_error("libscf_fmri_get_instance", err
);
2474 scf_instance_destroy(inst
);
2477 return (info
->err
= ECONNRESET
);
2481 (void) add_service(v
->gv_name
, info
->h
, &rebound
);
2483 return (info
->err
= ECONNRESET
);
2490 graph_vertex_t
*v
; /* GVT_INST vertex */
2491 int err
; /* return error */
2492 int **pathp
; /* return circular dependency path */
2496 * Make info->v depend on a new GVT_GROUP node for this property group,
2497 * and then call process_dependency_fmri() for the values of the entity
2498 * property. Return 0 on success, or if something goes wrong return nonzero
2499 * and set info->err to ECONNABORTED, EINVAL, or the error code returned by
2500 * process_dependency_fmri().
2503 process_dependency_pg(scf_propertygroup_t
*pg
, struct deppg_info
*info
)
2506 depgroup_type_t deptype
;
2507 restarter_error_t rerr
;
2508 struct depfmri_info linfo
;
2509 char *fmri
, *pg_name
;
2511 graph_vertex_t
*depgrp
;
2512 scf_property_t
*prop
;
2518 assert(MUTEX_HELD(&dgraph_lock
));
2520 h
= scf_pg_handle(pg
);
2522 pg_name
= startd_alloc(max_scf_name_size
);
2524 len
= scf_pg_get_name(pg
, pg_name
, max_scf_name_size
);
2526 startd_free(pg_name
, max_scf_name_size
);
2527 switch (scf_error()) {
2528 case SCF_ERROR_CONNECTION_BROKEN
:
2530 return (info
->err
= ECONNABORTED
);
2532 case SCF_ERROR_DELETED
:
2533 return (info
->err
= 0);
2535 case SCF_ERROR_NOT_SET
:
2536 bad_error("scf_pg_get_name", scf_error());
2541 * Skip over empty dependency groups. Since dependency property
2542 * groups are updated atomically, they are either empty or
2545 empty
= depgroup_empty(h
, pg
);
2548 "Error reading dependency group \"%s\" of %s: %s\n",
2549 pg_name
, info
->v
->gv_name
, scf_strerror(scf_error()));
2550 startd_free(pg_name
, max_scf_name_size
);
2551 return (info
->err
= EINVAL
);
2553 } else if (empty
== 1) {
2554 log_framework(LOG_DEBUG
,
2555 "Ignoring empty dependency group \"%s\" of %s\n",
2556 pg_name
, info
->v
->gv_name
);
2557 startd_free(pg_name
, max_scf_name_size
);
2558 return (info
->err
= 0);
2561 fmri_sz
= strlen(info
->v
->gv_name
) + 1 + len
+ 1;
2562 fmri
= startd_alloc(fmri_sz
);
2564 (void) snprintf(fmri
, fmri_sz
, "%s>%s", info
->v
->gv_name
,
2567 /* Validate the pg before modifying the graph */
2568 deptype
= depgroup_read_grouping(h
, pg
);
2569 if (deptype
== DEPGRP_UNSUPPORTED
) {
2571 "Dependency \"%s\" of %s has an unknown grouping value.\n",
2572 pg_name
, info
->v
->gv_name
);
2573 startd_free(fmri
, fmri_sz
);
2574 startd_free(pg_name
, max_scf_name_size
);
2575 return (info
->err
= EINVAL
);
2578 rerr
= depgroup_read_restart(h
, pg
);
2579 if (rerr
== RERR_UNSUPPORTED
) {
2581 "Dependency \"%s\" of %s has an unknown restart_on value."
2582 "\n", pg_name
, info
->v
->gv_name
);
2583 startd_free(fmri
, fmri_sz
);
2584 startd_free(pg_name
, max_scf_name_size
);
2585 return (info
->err
= EINVAL
);
2588 prop
= safe_scf_property_create(h
);
2590 if (scf_pg_get_property(pg
, SCF_PROPERTY_ENTITIES
, prop
) != 0) {
2591 scferr
= scf_error();
2592 scf_property_destroy(prop
);
2593 if (scferr
== SCF_ERROR_DELETED
) {
2594 startd_free(fmri
, fmri_sz
);
2595 startd_free(pg_name
, max_scf_name_size
);
2596 return (info
->err
= 0);
2597 } else if (scferr
!= SCF_ERROR_NOT_FOUND
) {
2598 startd_free(fmri
, fmri_sz
);
2599 startd_free(pg_name
, max_scf_name_size
);
2600 return (info
->err
= ECONNABORTED
);
2604 "Dependency \"%s\" of %s is missing a \"%s\" property.\n",
2605 pg_name
, info
->v
->gv_name
, SCF_PROPERTY_ENTITIES
);
2607 startd_free(fmri
, fmri_sz
);
2608 startd_free(pg_name
, max_scf_name_size
);
2610 return (info
->err
= EINVAL
);
2613 /* Create depgroup vertex for pg */
2614 err
= graph_insert_vertex_unconfigured(fmri
, GVT_GROUP
, deptype
,
2617 startd_free(fmri
, fmri_sz
);
2619 /* Add dependency from inst vertex to new vertex */
2620 err
= graph_insert_dependency(info
->v
, depgrp
, info
->pathp
);
2621 /* ELOOP can't happen because this should be a new vertex */
2625 linfo
.type
= depgroup_read_scheme(h
, pg
);
2626 linfo
.inst_fmri
= info
->v
->gv_name
;
2627 linfo
.pg_name
= pg_name
;
2630 linfo
.pathp
= info
->pathp
;
2631 err
= walk_property_astrings(prop
, (callback_t
)process_dependency_fmri
,
2634 scf_property_destroy(prop
);
2635 startd_free(pg_name
, max_scf_name_size
);
2640 return (info
->err
= linfo
.err
);
2644 return (info
->err
= err
);
2647 return (info
->err
= 0);
2650 return (info
->err
= ECONNABORTED
);
2653 bad_error("walk_property_astrings", err
);
2659 * Build the dependency info for v from the repository. Returns 0 on success,
2660 * ECONNABORTED on repository disconnection, EINVAL if the repository
2661 * configuration is invalid, and ELOOP if a dependency would cause a cycle.
2662 * In the last case, *pathp will point to a -1-terminated array of ids which
2663 * constitute the rest of the dependency cycle.
2666 set_dependencies(graph_vertex_t
*v
, scf_instance_t
*inst
, int **pathp
)
2668 struct deppg_info info
;
2670 uint_t old_configured
;
2672 assert(MUTEX_HELD(&dgraph_lock
));
2675 * Mark the vertex as configured during dependency insertion to avoid
2676 * dependency cycles (which can appear in the graph if one of the
2677 * vertices is an exclusion-group).
2679 old_configured
= v
->gv_flags
& GV_CONFIGURED
;
2680 v
->gv_flags
|= GV_CONFIGURED
;
2686 err
= walk_dependency_pgs(inst
, (callback_t
)process_dependency_pg
,
2689 if (!old_configured
)
2690 v
->gv_flags
&= ~GV_CONFIGURED
;
2698 return (ECONNABORTED
);
2701 /* Should get delete event, so return 0. */
2705 bad_error("walk_dependency_pgs", err
);
2712 handle_cycle(const char *fmri
, int *path
)
2717 assert(MUTEX_HELD(&dgraph_lock
));
2719 path_to_str(path
, (char **)&cp
, &sz
);
2721 log_error(LOG_ERR
, "Transitioning %s to maintenance "
2722 "because it completes a dependency cycle (see svcs -xv for "
2723 "details):\n%s", fmri
? fmri
: "?", cp
);
2725 startd_free((void *)cp
, sz
);
2729 * Increment the vertex's reference count to prevent the vertex removal
2733 vertex_ref(graph_vertex_t
*v
)
2735 assert(MUTEX_HELD(&dgraph_lock
));
2741 * Decrement the vertex's reference count and remove the vertex from
2742 * the dgraph when possible.
2744 * Return VERTEX_REMOVED when the vertex has been removed otherwise
2745 * return VERTEX_INUSE.
2748 vertex_unref(graph_vertex_t
*v
)
2750 assert(MUTEX_HELD(&dgraph_lock
));
2751 assert(v
->gv_refs
> 0);
2755 return (free_if_unrefed(v
));
2759 * When run on the dependencies of a vertex, populates list with
2760 * graph_edge_t's which point to the service vertices or the instance
2761 * vertices (no GVT_GROUP nodes) on which the vertex depends.
2763 * Increment the vertex's reference count once the vertex is inserted
2764 * in the list. The vertex won't be able to be deleted from the dgraph
2765 * while it is referenced.
2768 append_svcs_or_insts(graph_edge_t
*e
, uu_list_t
*list
)
2770 graph_vertex_t
*v
= e
->ge_vertex
;
2774 switch (v
->gv_type
) {
2780 r
= uu_list_walk(v
->gv_dependencies
,
2781 (uu_walk_fn_t
*)append_svcs_or_insts
, list
, 0);
2783 return (UU_WALK_NEXT
);
2786 return (UU_WALK_NEXT
);
2790 uu_warn("%s:%d: Unexpected vertex type %d.\n", __FILE__
,
2791 __LINE__
, v
->gv_type
);
2796 new = startd_alloc(sizeof (*new));
2798 uu_list_node_init(new, &new->ge_link
, graph_edge_pool
);
2799 r
= uu_list_insert_before(list
, NULL
, new);
2803 * Because we are inserting the vertex in a list, we don't want
2804 * the vertex to be freed while the list is in use. In order to
2805 * achieve that, increment the vertex's reference count.
2809 return (UU_WALK_NEXT
);
2813 should_be_in_subgraph(graph_vertex_t
*v
)
2821 * v is in the subgraph if any of its dependents are in the subgraph.
2822 * Except for EXCLUDE_ALL dependents. And OPTIONAL dependents only
2823 * count if we're enabled.
2825 for (e
= uu_list_first(v
->gv_dependents
);
2827 e
= uu_list_next(v
->gv_dependents
, e
)) {
2828 graph_vertex_t
*dv
= e
->ge_vertex
;
2830 if (!(dv
->gv_flags
& GV_INSUBGRAPH
))
2834 * Don't include instances that are optional and disabled.
2836 if (v
->gv_type
== GVT_INST
&& dv
->gv_type
== GVT_SVC
) {
2841 for (ee
= uu_list_first(dv
->gv_dependents
);
2843 ee
= uu_list_next(dv
->gv_dependents
, ee
)) {
2845 graph_vertex_t
*ddv
= e
->ge_vertex
;
2847 if (ddv
->gv_type
== GVT_GROUP
&&
2848 ddv
->gv_depgroup
== DEPGRP_EXCLUDE_ALL
)
2851 if (ddv
->gv_type
== GVT_GROUP
&&
2852 ddv
->gv_depgroup
== DEPGRP_OPTIONAL_ALL
&&
2853 !(v
->gv_flags
& GV_ENBLD_NOOVR
))
2861 if (v
->gv_type
== GVT_INST
&&
2862 dv
->gv_type
== GVT_GROUP
&&
2863 dv
->gv_depgroup
== DEPGRP_OPTIONAL_ALL
&&
2864 !(v
->gv_flags
& GV_ENBLD_NOOVR
))
2867 /* Don't include excluded services and instances */
2868 if (dv
->gv_type
== GVT_GROUP
&&
2869 dv
->gv_depgroup
== DEPGRP_EXCLUDE_ALL
)
2879 * Ensures that GV_INSUBGRAPH is set properly for v and its descendents. If
2880 * any bits change, manipulate the repository appropriately. Returns 0 or
2884 eval_subgraph(graph_vertex_t
*v
, scf_handle_t
*h
)
2886 boolean_t old
= (v
->gv_flags
& GV_INSUBGRAPH
) != 0;
2889 scf_instance_t
*inst
;
2892 assert(milestone
!= NULL
&& milestone
!= MILESTONE_NONE
);
2894 new = should_be_in_subgraph(v
);
2899 log_framework(LOG_DEBUG
, new ? "Adding %s to the subgraph.\n" :
2900 "Removing %s from the subgraph.\n", v
->gv_name
);
2902 v
->gv_flags
= (v
->gv_flags
& ~GV_INSUBGRAPH
) |
2903 (new ? GV_INSUBGRAPH
: 0);
2905 if (v
->gv_type
== GVT_INST
&& (v
->gv_flags
& GV_CONFIGURED
)) {
2909 err
= libscf_fmri_get_instance(h
, v
->gv_name
, &inst
);
2913 libscf_handle_rebind(h
);
2923 bad_error("libscf_fmri_get_instance", err
);
2929 err
= libscf_delete_enable_ovr(inst
);
2930 f
= "libscf_delete_enable_ovr";
2932 err
= libscf_set_enable_ovr(inst
, 0);
2933 f
= "libscf_set_enable_ovr";
2935 scf_instance_destroy(inst
);
2942 libscf_handle_rebind(h
);
2944 * We must continue so the graph is updated,
2945 * but we must return ECONNABORTED so any
2946 * libscf state held by any callers is reset.
2953 log_error(LOG_WARNING
,
2954 "Could not set %s/%s for %s: %s.\n",
2955 SCF_PG_GENERAL_OVR
, SCF_PROPERTY_ENABLED
,
2956 v
->gv_name
, strerror(err
));
2965 for (e
= uu_list_first(v
->gv_dependencies
);
2967 e
= uu_list_next(v
->gv_dependencies
, e
)) {
2968 r
= eval_subgraph(e
->ge_vertex
, h
);
2970 assert(r
== ECONNABORTED
);
2979 * Delete the (property group) dependencies of v & create new ones based on
2980 * inst. If doing so would create a cycle, log a message and put the instance
2981 * into maintenance. Update GV_INSUBGRAPH flags as necessary. Returns 0 or
2985 refresh_vertex(graph_vertex_t
*v
, scf_instance_t
*inst
)
2991 scf_handle_t
*h
= scf_instance_handle(inst
);
2992 uu_list_t
*old_deps
;
2997 assert(MUTEX_HELD(&dgraph_lock
));
2998 assert(v
->gv_type
== GVT_INST
);
3000 log_framework(LOG_DEBUG
, "Graph engine: Refreshing %s.\n", v
->gv_name
);
3002 if (milestone
> MILESTONE_NONE
) {
3004 * In case some of v's dependencies are being deleted we must
3005 * make a list of them now for GV_INSUBGRAPH-flag evaluation
3006 * after the new dependencies are in place.
3008 old_deps
= startd_list_create(graph_edge_pool
, NULL
, 0);
3010 err
= uu_list_walk(v
->gv_dependencies
,
3011 (uu_walk_fn_t
*)append_svcs_or_insts
, old_deps
, 0);
3015 delete_instance_dependencies(v
, B_FALSE
);
3017 err
= set_dependencies(v
, inst
, &path
);
3028 r
= libscf_instance_get_fmri(inst
, &fmri
);
3042 bad_error("libscf_instance_get_fmri", r
);
3045 if (err
== EINVAL
) {
3046 log_error(LOG_ERR
, "Transitioning %s "
3047 "to maintenance due to misconfiguration.\n",
3049 vertex_send_event(v
,
3050 RESTARTER_EVENT_TYPE_INVALID_DEPENDENCY
);
3052 handle_cycle(fmri
, path
);
3053 vertex_send_event(v
,
3054 RESTARTER_EVENT_TYPE_DEPENDENCY_CYCLE
);
3056 startd_free(fmri
, max_scf_fmri_size
);
3061 bad_error("set_dependencies", err
);
3064 if (milestone
> MILESTONE_NONE
) {
3065 boolean_t aborted
= B_FALSE
;
3067 for (e
= uu_list_first(old_deps
);
3069 e
= uu_list_next(old_deps
, e
)) {
3072 if (vertex_unref(vv
) == VERTEX_INUSE
&&
3073 eval_subgraph(vv
, h
) == ECONNABORTED
)
3077 for (e
= uu_list_first(v
->gv_dependencies
);
3079 e
= uu_list_next(v
->gv_dependencies
, e
)) {
3080 if (eval_subgraph(e
->ge_vertex
, h
) ==
3091 graph_start_if_satisfied(v
);
3096 if (milestone
> MILESTONE_NONE
) {
3097 void *cookie
= NULL
;
3099 while ((e
= uu_list_teardown(old_deps
, &cookie
)) != NULL
)
3100 startd_free(e
, sizeof (*e
));
3102 uu_list_destroy(old_deps
);
3109 * Set up v according to inst. That is, make sure it depends on its
3110 * restarter and set up its dependencies. Send the ADD_INSTANCE command to
3111 * the restarter, and send ENABLE or DISABLE as appropriate.
3113 * Returns 0 on success, ECONNABORTED on repository disconnection, or
3114 * ECANCELED if inst is deleted.
3117 configure_vertex(graph_vertex_t
*v
, scf_instance_t
*inst
)
3120 scf_propertygroup_t
*pg
;
3121 scf_snapshot_t
*snap
;
3122 char *restarter_fmri
= startd_alloc(max_scf_value_size
);
3123 int enabled
, enabled_ovr
;
3129 restarter_fmri
[0] = '\0';
3131 assert(MUTEX_HELD(&dgraph_lock
));
3132 assert(v
->gv_type
== GVT_INST
);
3133 assert((v
->gv_flags
& GV_CONFIGURED
) == 0);
3135 /* GV_INSUBGRAPH should already be set properly. */
3136 assert(should_be_in_subgraph(v
) ==
3137 ((v
->gv_flags
& GV_INSUBGRAPH
) != 0));
3140 * If the instance fmri is in the deathrow list then set the
3141 * GV_DEATHROW flag on the vertex and create and set to true the
3142 * SCF_PROPERTY_DEATHROW boolean property in the non-persistent
3143 * repository for this instance fmri.
3145 if ((v
->gv_flags
& GV_DEATHROW
) ||
3146 (is_fmri_in_deathrow(v
->gv_name
) == B_TRUE
)) {
3147 if ((v
->gv_flags
& GV_DEATHROW
) == 0) {
3149 * Set flag GV_DEATHROW, create and set to true
3150 * the SCF_PROPERTY_DEATHROW property in the
3151 * non-persistent repository for this instance fmri.
3153 v
->gv_flags
|= GV_DEATHROW
;
3155 switch (err
= libscf_set_deathrow(inst
, 1)) {
3161 startd_free(restarter_fmri
, max_scf_value_size
);
3165 log_error(LOG_WARNING
, "Could not set %s/%s "
3166 "for deathrow %s: %s.\n",
3167 SCF_PG_DEATHROW
, SCF_PROPERTY_DEATHROW
,
3168 v
->gv_name
, strerror(err
));
3172 uu_die("Permission denied.\n");
3176 bad_error("libscf_set_deathrow", err
);
3178 log_framework(LOG_DEBUG
, "Deathrow, graph set %s.\n",
3181 startd_free(restarter_fmri
, max_scf_value_size
);
3185 h
= scf_instance_handle(inst
);
3188 * Using a temporary deathrow boolean property, set through
3189 * libscf_set_deathrow(), only for fmris on deathrow, is necessary
3190 * because deathrow_fini() may already have been called, and in case
3191 * of a refresh, GV_DEATHROW may need to be set again.
3192 * libscf_get_deathrow() sets deathrow to 1 only if this instance
3193 * has a temporary boolean property named 'deathrow' valued true
3194 * in a property group 'deathrow', -1 or 0 in all other cases.
3196 err
= libscf_get_deathrow(h
, inst
, &deathrow
);
3203 startd_free(restarter_fmri
, max_scf_value_size
);
3207 bad_error("libscf_get_deathrow", err
);
3210 if (deathrow
== 1) {
3211 v
->gv_flags
|= GV_DEATHROW
;
3212 startd_free(restarter_fmri
, max_scf_value_size
);
3216 log_framework(LOG_DEBUG
, "Graph adding %s.\n", v
->gv_name
);
3219 * If the instance does not have a restarter property group,
3220 * initialize its state to uninitialized/none, in case the restarter
3223 pg
= safe_scf_pg_create(h
);
3225 if (scf_instance_get_pg(inst
, SCF_PG_RESTARTER
, pg
) != 0) {
3226 instance_data_t idata
;
3227 uint_t count
= 0, msecs
= ALLOC_DELAY
;
3229 switch (scf_error()) {
3230 case SCF_ERROR_NOT_FOUND
:
3233 case SCF_ERROR_CONNECTION_BROKEN
:
3236 startd_free(restarter_fmri
, max_scf_value_size
);
3237 return (ECONNABORTED
);
3239 case SCF_ERROR_DELETED
:
3241 startd_free(restarter_fmri
, max_scf_value_size
);
3244 case SCF_ERROR_NOT_SET
:
3245 bad_error("scf_instance_get_pg", scf_error());
3248 switch (err
= libscf_instance_get_fmri(inst
,
3249 (char **)&idata
.i_fmri
)) {
3256 startd_free(restarter_fmri
, max_scf_value_size
);
3260 bad_error("libscf_instance_get_fmri", err
);
3263 idata
.i_state
= RESTARTER_STATE_NONE
;
3264 idata
.i_next_state
= RESTARTER_STATE_NONE
;
3267 switch (err
= _restarter_commit_states(h
, &idata
,
3268 RESTARTER_STATE_UNINIT
, RESTARTER_STATE_NONE
,
3269 restarter_get_str_short(restarter_str_insert_in_graph
))) {
3275 if (count
< ALLOC_RETRY
) {
3276 (void) poll(NULL
, 0, msecs
);
3277 msecs
*= ALLOC_DELAY_MULT
;
3281 uu_die("Insufficient memory.\n");
3285 startd_free((void *)idata
.i_fmri
, max_scf_fmri_size
);
3287 startd_free(restarter_fmri
, max_scf_value_size
);
3288 return (ECONNABORTED
);
3291 startd_free((void *)idata
.i_fmri
, max_scf_fmri_size
);
3293 startd_free(restarter_fmri
, max_scf_value_size
);
3299 log_error(LOG_NOTICE
, "Could not initialize state for "
3300 "%s: %s.\n", idata
.i_fmri
, strerror(err
));
3305 bad_error("_restarter_commit_states", err
);
3308 startd_free((void *)idata
.i_fmri
, max_scf_fmri_size
);
3313 if (milestone
!= NULL
) {
3315 * Make sure the enable-override is set properly before we
3316 * read whether we should be enabled.
3318 if (milestone
== MILESTONE_NONE
||
3319 !(v
->gv_flags
& GV_INSUBGRAPH
)) {
3321 * This might seem unjustified after the milestone
3322 * transition has completed (non_subgraph_svcs == 0),
3323 * but it's important because when we boot to
3324 * a milestone, we set the milestone before populating
3325 * the graph, and all of the new non-subgraph services
3326 * need to be disabled here.
3328 switch (err
= libscf_set_enable_ovr(inst
, 0)) {
3334 startd_free(restarter_fmri
, max_scf_value_size
);
3338 log_error(LOG_WARNING
,
3339 "Could not set %s/%s for %s: %s.\n",
3340 SCF_PG_GENERAL_OVR
, SCF_PROPERTY_ENABLED
,
3341 v
->gv_name
, strerror(err
));
3345 uu_die("Permission denied.\n");
3349 bad_error("libscf_set_enable_ovr", err
);
3352 assert(v
->gv_flags
& GV_INSUBGRAPH
);
3353 switch (err
= libscf_delete_enable_ovr(inst
)) {
3359 startd_free(restarter_fmri
, max_scf_value_size
);
3363 uu_die("Permission denied.\n");
3367 bad_error("libscf_delete_enable_ovr", err
);
3372 err
= libscf_get_basic_instance_data(h
, inst
, v
->gv_name
, &enabled
,
3373 &enabled_ovr
, &restarter_fmri
);
3380 startd_free(restarter_fmri
, max_scf_value_size
);
3384 log_framework(LOG_DEBUG
,
3385 "Ignoring %s because it has no general property group.\n",
3387 startd_free(restarter_fmri
, max_scf_value_size
);
3391 bad_error("libscf_get_basic_instance_data", err
);
3394 if ((tset
= libscf_get_stn_tset(inst
)) == -1) {
3395 log_framework(LOG_WARNING
,
3396 "Failed to get notification parameters for %s: %s\n",
3397 v
->gv_name
, scf_strerror(scf_error()));
3400 v
->gv_stn_tset
= tset
;
3402 if (strcmp(v
->gv_name
, SCF_INSTANCE_GLOBAL
) == 0)
3403 stn_global
= v
->gv_stn_tset
;
3405 if (enabled
== -1) {
3406 startd_free(restarter_fmri
, max_scf_value_size
);
3410 v
->gv_flags
= (v
->gv_flags
& ~GV_ENBLD_NOOVR
) |
3411 (enabled
? GV_ENBLD_NOOVR
: 0);
3413 if (enabled_ovr
!= -1)
3414 enabled
= enabled_ovr
;
3416 v
->gv_state
= RESTARTER_STATE_UNINIT
;
3418 snap
= libscf_get_or_make_running_snapshot(inst
, v
->gv_name
, B_TRUE
);
3419 scf_snapshot_destroy(snap
);
3421 /* Set up the restarter. (Sends _ADD_INSTANCE on success.) */
3422 err
= graph_change_restarter(v
, restarter_fmri
, h
, &path
);
3424 instance_data_t idata
;
3425 uint_t count
= 0, msecs
= ALLOC_DELAY
;
3426 restarter_str_t reason
;
3428 if (err
== ECONNABORTED
) {
3429 startd_free(restarter_fmri
, max_scf_value_size
);
3433 assert(err
== EINVAL
|| err
== ELOOP
);
3435 if (err
== EINVAL
) {
3436 log_framework(LOG_ERR
, emsg_invalid_restarter
,
3437 v
->gv_name
, restarter_fmri
);
3438 reason
= restarter_str_invalid_restarter
;
3440 handle_cycle(v
->gv_name
, path
);
3441 reason
= restarter_str_dependency_cycle
;
3444 startd_free(restarter_fmri
, max_scf_value_size
);
3447 * We didn't register the instance with the restarter, so we
3448 * must set maintenance mode ourselves.
3450 err
= libscf_instance_get_fmri(inst
, (char **)&idata
.i_fmri
);
3452 assert(err
== ECONNABORTED
|| err
== ECANCELED
);
3456 idata
.i_state
= RESTARTER_STATE_NONE
;
3457 idata
.i_next_state
= RESTARTER_STATE_NONE
;
3460 switch (err
= _restarter_commit_states(h
, &idata
,
3461 RESTARTER_STATE_MAINT
, RESTARTER_STATE_NONE
,
3462 restarter_get_str_short(reason
))) {
3468 if (count
< ALLOC_RETRY
) {
3469 (void) poll(NULL
, 0, msecs
);
3470 msecs
*= ALLOC_DELAY_MULT
;
3474 uu_die("Insufficient memory.\n");
3478 startd_free((void *)idata
.i_fmri
, max_scf_fmri_size
);
3479 return (ECONNABORTED
);
3482 startd_free((void *)idata
.i_fmri
, max_scf_fmri_size
);
3488 log_error(LOG_NOTICE
, "Could not initialize state for "
3489 "%s: %s.\n", idata
.i_fmri
, strerror(err
));
3494 bad_error("_restarter_commit_states", err
);
3497 startd_free((void *)idata
.i_fmri
, max_scf_fmri_size
);
3499 v
->gv_state
= RESTARTER_STATE_MAINT
;
3503 startd_free(restarter_fmri
, max_scf_value_size
);
3505 /* Add all the other dependencies. */
3506 err
= refresh_vertex(v
, inst
);
3508 assert(err
== ECONNABORTED
);
3513 v
->gv_flags
|= GV_CONFIGURED
;
3515 graph_enable_by_vertex(v
, enabled
, 0);
3522 kill_user_procs(void)
3524 (void) fputs("svc.startd: Killing user processes.\n", stdout
);
3527 * Despite its name, killall's role is to get select user processes--
3528 * basically those representing terminal-based logins-- to die. Victims
3529 * are located by killall in the utmp database. Since these are most
3530 * often shell based logins, and many shells mask SIGTERM (but are
3531 * responsive to SIGHUP) we first HUP and then shortly thereafter
3534 (void) fork_with_timeout("/usr/sbin/killall HUP", 1, 5);
3535 (void) fork_with_timeout("/usr/sbin/killall KILL", 1, 5);
3538 * Note the selection of user id's 0, 1 and 15, subsequently
3539 * inverted by -v. 15 is reserved for dladmd. Yes, this is a
3540 * kludge-- a better policy is needed.
3542 * Note that fork_with_timeout will only wait out the 1 second
3543 * "grace time" if pkill actually returns 0. So if there are
3544 * no matches, this will run to completion much more quickly.
3546 (void) fork_with_timeout("/usr/bin/pkill -TERM -v -u 0,1,15", 1, 5);
3547 (void) fork_with_timeout("/usr/bin/pkill -KILL -v -u 0,1,15", 1, 5);
3553 const char * const resetting
= "/etc/svc/volatile/resetting";
3558 char down_buf
[256], time_buf
[256];
3565 fd
= creat(resetting
, 0777);
3569 uu_warn("Could not create \"%s\"", resetting
);
3571 /* Kill dhcpagent if we're not using nfs for root */
3572 if ((statvfs("/", &vfs
) == 0) &&
3573 (strncmp(vfs
.f_basetype
, "nfs", sizeof ("nfs") - 1) != 0))
3574 fork_with_timeout("/usr/bin/pkill -x -u 0 dhcpagent", 0, 5);
3577 * Call sync(2) now, before we kill off user processes. This takes
3578 * advantage of the several seconds of pause we have before the
3579 * killalls are done. Time we can make good use of to get pages
3580 * moving out to disk.
3582 * Inside non-global zones, we don't bother, and it's better not to
3583 * anyway, since sync(2) can have system-wide impact.
3585 if (getzoneid() == 0)
3591 * Note that this must come after the killing of user procs, since
3592 * killall relies on utmpx, and this command affects the contents of
3595 if (access("/usr/lib/acct/closewtmp", X_OK
) == 0)
3596 fork_with_timeout("/usr/lib/acct/closewtmp", 0, 5);
3599 * For patches which may be installed as the system is shutting
3600 * down, we need to ensure, one more time, that the boot archive
3601 * really is up to date.
3603 if (getzoneid() == 0 && access("/usr/sbin/bootadm", X_OK
) == 0)
3604 fork_with_timeout("/usr/sbin/bootadm -ea update_all", 0, 3600);
3607 * Right now, fast reboot is supported only on i386.
3608 * scf_is_fastboot_default() should take care of it.
3609 * If somehow we got there on unsupported platform -
3610 * print warning and fall back to regular reboot.
3612 if (halting
== AD_FASTREBOOT
) {
3614 if (be_get_boot_args(&fbarg
, BE_ENTRY_DEFAULT
) == 0) {
3615 mdep
= (uintptr_t)fbarg
;
3618 * Failed to read BE info, fall back to normal reboot
3621 uu_warn("Failed to get fast reboot arguments.\n"
3622 "Falling back to regular reboot.\n");
3626 uu_warn("Fast reboot configured, but not supported by "
3631 fork_with_timeout("/sbin/umountall -l", 0, 5);
3632 fork_with_timeout("/sbin/umount /tmp /var/adm /var/run /var "
3633 ">/dev/null 2>&1", 0, 5);
3636 * Try to get to consistency for whatever UFS filesystems are left.
3637 * This is pretty expensive, so we save it for the end in the hopes of
3638 * minimizing what it must do. The other option would be to start in
3639 * parallel with the killall's, but lockfs tends to throw out much more
3640 * than is needed, and so subsequent commands (like umountall) take a
3641 * long time to get going again.
3643 * Inside of zones, we don't bother, since we're not about to terminate
3644 * the whole OS instance.
3646 * On systems using only ZFS, this call to lockfs -fa is a no-op.
3648 if (getzoneid() == 0) {
3649 if (access("/usr/sbin/lockfs", X_OK
) == 0)
3650 fork_with_timeout("/usr/sbin/lockfs -fa", 0, 30);
3652 sync(); /* once more, with feeling */
3655 fork_with_timeout("/sbin/umount /usr >/dev/null 2>&1", 0, 5);
3658 * Construct and emit the last words from userland:
3659 * "<timestamp> The system is down. Shutdown took <N> seconds."
3661 * Normally we'd use syslog, but with /var and other things
3662 * potentially gone, try to minimize the external dependencies.
3665 (void) localtime_r(&now
, &nowtm
);
3667 if (strftime(down_buf
, sizeof (down_buf
),
3668 "%b %e %T The system is down.", &nowtm
) == 0) {
3669 (void) strlcpy(down_buf
, "The system is down.",
3673 if (halting_time
!= 0 && halting_time
<= now
) {
3674 (void) snprintf(time_buf
, sizeof (time_buf
),
3675 " Shutdown took %lu seconds.", now
- halting_time
);
3679 (void) printf("%s%s\n", down_buf
, time_buf
);
3681 (void) uadmin(A_SHUTDOWN
, halting
, mdep
);
3682 uu_warn("uadmin() failed");
3685 if (halting
== AD_FASTREBOOT
)
3689 if (remove(resetting
) != 0 && errno
!= ENOENT
)
3690 uu_warn("Could not remove \"%s\"", resetting
);
3694 * If any of the up_svcs[] are online or satisfiable, return true. If they are
3695 * all missing, disabled, in maintenance, or unsatisfiable, return false.
3702 assert(MUTEX_HELD(&dgraph_lock
));
3705 * If we are booting to single user (boot -s),
3706 * SCF_MILESTONE_SINGLE_USER is needed to come up because startd
3707 * spawns sulogin after single-user is online (see specials.c).
3709 i
= (booting_to_single_user
? 0 : 1);
3711 for (; up_svcs
[i
] != NULL
; ++i
) {
3712 if (up_svcs_p
[i
] == NULL
) {
3713 up_svcs_p
[i
] = vertex_get_by_name(up_svcs
[i
]);
3715 if (up_svcs_p
[i
] == NULL
)
3720 * Ignore unconfigured services (the ones that have been
3721 * mentioned in a dependency from other services, but do
3722 * not exist in the repository). Services which exist
3723 * in the repository but don't have general/enabled
3724 * property will be also ignored.
3726 if (!(up_svcs_p
[i
]->gv_flags
& GV_CONFIGURED
))
3729 switch (up_svcs_p
[i
]->gv_state
) {
3730 case RESTARTER_STATE_ONLINE
:
3731 case RESTARTER_STATE_DEGRADED
:
3733 * Deactivate verbose boot once a login service has been
3736 st
->st_log_login_reached
= 1;
3738 case RESTARTER_STATE_UNINIT
:
3741 case RESTARTER_STATE_OFFLINE
:
3742 if (instance_satisfied(up_svcs_p
[i
], B_TRUE
) != -1)
3744 log_framework(LOG_DEBUG
,
3745 "can_come_up(): %s is unsatisfiable.\n",
3746 up_svcs_p
[i
]->gv_name
);
3749 case RESTARTER_STATE_DISABLED
:
3750 case RESTARTER_STATE_MAINT
:
3751 log_framework(LOG_DEBUG
,
3752 "can_come_up(): %s is in state %s.\n",
3753 up_svcs_p
[i
]->gv_name
,
3754 instance_state_str
[up_svcs_p
[i
]->gv_state
]);
3759 uu_warn("%s:%d: Unexpected vertex state %d.\n",
3760 __FILE__
, __LINE__
, up_svcs_p
[i
]->gv_state
);
3767 * In the seed repository, console-login is unsatisfiable because
3768 * services are missing. To behave correctly in that case we don't want
3769 * to return false until manifest-import is online.
3772 if (manifest_import_p
== NULL
) {
3773 manifest_import_p
= vertex_get_by_name(manifest_import
);
3775 if (manifest_import_p
== NULL
)
3779 switch (manifest_import_p
->gv_state
) {
3780 case RESTARTER_STATE_ONLINE
:
3781 case RESTARTER_STATE_DEGRADED
:
3782 case RESTARTER_STATE_DISABLED
:
3783 case RESTARTER_STATE_MAINT
:
3786 case RESTARTER_STATE_OFFLINE
:
3787 if (instance_satisfied(manifest_import_p
, B_TRUE
) == -1)
3791 case RESTARTER_STATE_UNINIT
:
3799 * Runs sulogin. Returns
3801 * EALREADY - sulogin is already running
3802 * EBUSY - console-login is running
3805 run_sulogin(const char *msg
)
3809 assert(MUTEX_HELD(&dgraph_lock
));
3811 if (sulogin_running
)
3814 v
= vertex_get_by_name(console_login_fmri
);
3815 if (v
!= NULL
&& inst_running(v
))
3818 sulogin_running
= B_TRUE
;
3820 MUTEX_UNLOCK(&dgraph_lock
);
3822 fork_sulogin(B_FALSE
, msg
);
3824 MUTEX_LOCK(&dgraph_lock
);
3826 sulogin_running
= B_FALSE
;
3828 if (console_login_ready
) {
3829 v
= vertex_get_by_name(console_login_fmri
);
3831 if (v
!= NULL
&& v
->gv_state
== RESTARTER_STATE_OFFLINE
) {
3832 if (v
->gv_start_f
== NULL
)
3833 vertex_send_event(v
,
3834 RESTARTER_EVENT_TYPE_START
);
3839 console_login_ready
= B_FALSE
;
3846 * The sulogin thread runs sulogin while can_come_up() is false. run_sulogin()
3847 * keeps sulogin from stepping on console-login's toes.
3851 sulogin_thread(void *unused
)
3853 (void) pthread_setname_np(pthread_self(), "sulogin");
3855 MUTEX_LOCK(&dgraph_lock
);
3857 assert(sulogin_thread_running
);
3860 (void) run_sulogin("Console login service(s) cannot run\n");
3861 } while (!can_come_up());
3863 sulogin_thread_running
= B_FALSE
;
3864 MUTEX_UNLOCK(&dgraph_lock
);
3871 single_user_thread(void *unused
)
3875 scf_instance_t
*inst
;
3876 scf_property_t
*prop
;
3882 (void) pthread_setname_np(pthread_self(), "single_user");
3884 MUTEX_LOCK(&single_user_thread_lock
);
3885 single_user_thread_count
++;
3887 if (!booting_to_single_user
)
3890 if (go_single_user_mode
|| booting_to_single_user
) {
3891 msg
= "SINGLE USER MODE\n";
3893 assert(go_to_level1
);
3895 fork_rc_script('1', "start", B_TRUE
);
3897 uu_warn("The system is ready for administration.\n");
3902 MUTEX_UNLOCK(&single_user_thread_lock
);
3905 MUTEX_LOCK(&dgraph_lock
);
3906 r
= run_sulogin(msg
);
3907 MUTEX_UNLOCK(&dgraph_lock
);
3911 assert(r
== EALREADY
|| r
== EBUSY
);
3918 MUTEX_LOCK(&single_user_thread_lock
);
3921 * If another single user thread has started, let it finish changing
3924 if (single_user_thread_count
> 1) {
3925 single_user_thread_count
--;
3926 MUTEX_UNLOCK(&single_user_thread_lock
);
3930 h
= libscf_handle_create_bound_loop();
3931 inst
= scf_instance_create(h
);
3932 prop
= safe_scf_property_create(h
);
3933 val
= safe_scf_value_create(h
);
3934 buf
= startd_alloc(max_scf_fmri_size
);
3937 if (scf_handle_decode_fmri(h
, SCF_SERVICE_STARTD
, NULL
, NULL
, inst
,
3938 NULL
, NULL
, SCF_DECODE_FMRI_EXACT
) != 0) {
3939 switch (scf_error()) {
3940 case SCF_ERROR_NOT_FOUND
:
3941 r
= libscf_create_self(h
);
3944 assert(r
== ECONNABORTED
);
3947 case SCF_ERROR_CONNECTION_BROKEN
:
3948 libscf_handle_rebind(h
);
3951 case SCF_ERROR_INVALID_ARGUMENT
:
3952 case SCF_ERROR_CONSTRAINT_VIOLATED
:
3953 case SCF_ERROR_NOT_BOUND
:
3954 case SCF_ERROR_HANDLE_MISMATCH
:
3956 bad_error("scf_handle_decode_fmri", scf_error());
3960 MUTEX_LOCK(&dgraph_lock
);
3962 r
= scf_instance_delete_prop(inst
, SCF_PG_OPTIONS_OVR
,
3963 SCF_PROPERTY_MILESTONE
);
3970 MUTEX_UNLOCK(&dgraph_lock
);
3971 libscf_handle_rebind(h
);
3977 log_error(LOG_WARNING
, "Could not clear temporary milestone: "
3978 "%s.\n", strerror(r
));
3982 bad_error("scf_instance_delete_prop", r
);
3985 MUTEX_UNLOCK(&dgraph_lock
);
3987 r
= libscf_get_milestone(inst
, prop
, val
, buf
, max_scf_fmri_size
);
3992 (void) strcpy(buf
, "all");
3996 uu_warn("Returning to milestone %s.\n", buf
);
4000 libscf_handle_rebind(h
);
4004 bad_error("libscf_get_milestone", r
);
4007 r
= dgraph_set_milestone(buf
, h
, B_FALSE
);
4017 bad_error("dgraph_set_milestone", r
);
4021 * See graph_runlevel_changed().
4023 MUTEX_LOCK(&dgraph_lock
);
4024 utmpx_set_runlevel(target_milestone_as_runlevel(), 'S', B_TRUE
);
4025 MUTEX_UNLOCK(&dgraph_lock
);
4027 startd_free(buf
, max_scf_fmri_size
);
4028 scf_value_destroy(val
);
4029 scf_property_destroy(prop
);
4030 scf_instance_destroy(inst
);
4031 scf_handle_destroy(h
);
4034 * We'll give ourselves 3 seconds to respond to all of the enablings
4035 * that setting the milestone should have created before checking
4036 * whether to run sulogin.
4042 MUTEX_LOCK(&dgraph_lock
);
4044 * Clearing these variables will allow the sulogin thread to run. We
4045 * check here in case there aren't any more state updates anytime soon.
4047 go_to_level1
= go_single_user_mode
= booting_to_single_user
= B_FALSE
;
4048 if (!sulogin_thread_running
&& !can_come_up()) {
4049 (void) startd_thread_create(sulogin_thread
, NULL
);
4050 sulogin_thread_running
= B_TRUE
;
4052 MUTEX_UNLOCK(&dgraph_lock
);
4053 single_user_thread_count
--;
4054 MUTEX_UNLOCK(&single_user_thread_lock
);
4060 * Dependency graph operations API. These are handle-independent thread-safe
4061 * graph manipulation functions which are the entry points for the event
4066 * If a configured vertex exists for inst_fmri, return EEXIST. If no vertex
4067 * exists for inst_fmri, add one. Then fetch the restarter from inst, make
4068 * this vertex dependent on it, and send _ADD_INSTANCE to the restarter.
4069 * Fetch whether the instance should be enabled from inst and send _ENABLE or
4070 * _DISABLE as appropriate. Finally rummage through inst's dependency
4071 * property groups and add vertices and edges as appropriate. If anything
4072 * goes wrong after sending _ADD_INSTANCE, send _ADMIN_MAINT_ON to put the
4073 * instance in maintenance. Don't send _START or _STOP until we get a state
4074 * update in case we're being restarted and the service is already running.
4076 * To support booting to a milestone, we must also make sure all dependencies
4077 * encountered are configured, if they exist in the repository.
4079 * Returns 0 on success, ECONNABORTED on repository disconnection, EINVAL if
4080 * inst_fmri is an invalid (or not canonical) FMRI, ECANCELED if inst is
4081 * deleted, or EEXIST if a configured vertex for inst_fmri already exists.
4084 dgraph_add_instance(const char *inst_fmri
, scf_instance_t
*inst
,
4085 boolean_t lock_graph
)
4090 if (strcmp(inst_fmri
, SCF_SERVICE_STARTD
) == 0)
4093 /* Check for a vertex for inst_fmri. */
4095 MUTEX_LOCK(&dgraph_lock
);
4097 assert(MUTEX_HELD(&dgraph_lock
));
4100 v
= vertex_get_by_name(inst_fmri
);
4103 assert(v
->gv_type
== GVT_INST
);
4105 if (v
->gv_flags
& GV_CONFIGURED
) {
4107 MUTEX_UNLOCK(&dgraph_lock
);
4111 /* Add the vertex. */
4112 err
= graph_insert_vertex_unconfigured(inst_fmri
, GVT_INST
, 0,
4115 assert(err
== EINVAL
);
4117 MUTEX_UNLOCK(&dgraph_lock
);
4122 err
= configure_vertex(v
, inst
);
4125 MUTEX_UNLOCK(&dgraph_lock
);
4131 * Locate the vertex for this property group's instance. If it doesn't exist
4132 * or is unconfigured, call dgraph_add_instance() & return. Otherwise fetch
4133 * the restarter for the instance, and if it has changed, send
4134 * _REMOVE_INSTANCE to the old restarter, remove the dependency, make sure the
4135 * new restarter has a vertex, add a new dependency, and send _ADD_INSTANCE to
4136 * the new restarter. Then fetch whether the instance should be enabled, and
4137 * if it is different from what we had, or if we changed the restarter, send
4138 * the appropriate _ENABLE or _DISABLE command.
4140 * Returns 0 on success, ENOTSUP if the pg's parent is not an instance,
4141 * ECONNABORTED on repository disconnection, ECANCELED if the instance is
4142 * deleted, or -1 if the instance's general property group is deleted or if
4143 * its enabled property is misconfigured.
4146 dgraph_update_general(scf_propertygroup_t
*pg
)
4149 scf_instance_t
*inst
;
4151 char *restarter_fmri
;
4154 int enabled
, enabled_ovr
;
4157 /* Find the vertex for this service */
4158 h
= scf_pg_handle(pg
);
4160 inst
= safe_scf_instance_create(h
);
4162 if (scf_pg_get_parent_instance(pg
, inst
) != 0) {
4163 switch (scf_error()) {
4164 case SCF_ERROR_CONSTRAINT_VIOLATED
:
4167 case SCF_ERROR_CONNECTION_BROKEN
:
4169 return (ECONNABORTED
);
4171 case SCF_ERROR_DELETED
:
4174 case SCF_ERROR_NOT_SET
:
4175 bad_error("scf_pg_get_parent_instance", scf_error());
4179 err
= libscf_instance_get_fmri(inst
, &fmri
);
4185 scf_instance_destroy(inst
);
4186 return (ECONNABORTED
);
4189 scf_instance_destroy(inst
);
4193 bad_error("libscf_instance_get_fmri", err
);
4196 log_framework(LOG_DEBUG
,
4197 "Graph engine: Reloading general properties for %s.\n", fmri
);
4199 MUTEX_LOCK(&dgraph_lock
);
4201 v
= vertex_get_by_name(fmri
);
4202 if (v
== NULL
|| !(v
->gv_flags
& GV_CONFIGURED
)) {
4203 /* Will get the up-to-date properties. */
4204 MUTEX_UNLOCK(&dgraph_lock
);
4205 err
= dgraph_add_instance(fmri
, inst
, B_TRUE
);
4206 startd_free(fmri
, max_scf_fmri_size
);
4207 scf_instance_destroy(inst
);
4208 return (err
== ECANCELED
? 0 : err
);
4211 /* Read enabled & restarter from repository. */
4212 restarter_fmri
= startd_alloc(max_scf_value_size
);
4213 err
= libscf_get_basic_instance_data(h
, inst
, v
->gv_name
, &enabled
,
4214 &enabled_ovr
, &restarter_fmri
);
4215 if (err
!= 0 || enabled
== -1) {
4216 MUTEX_UNLOCK(&dgraph_lock
);
4217 scf_instance_destroy(inst
);
4218 startd_free(fmri
, max_scf_fmri_size
);
4223 startd_free(restarter_fmri
, max_scf_value_size
);
4228 startd_free(restarter_fmri
, max_scf_value_size
);
4232 bad_error("libscf_get_basic_instance_data", err
);
4236 oldflags
= v
->gv_flags
;
4237 v
->gv_flags
= (v
->gv_flags
& ~GV_ENBLD_NOOVR
) |
4238 (enabled
? GV_ENBLD_NOOVR
: 0);
4240 if (enabled_ovr
!= -1)
4241 enabled
= enabled_ovr
;
4244 * If GV_ENBLD_NOOVR has changed, then we need to re-evaluate the
4247 if (milestone
> MILESTONE_NONE
&& v
->gv_flags
!= oldflags
)
4248 (void) eval_subgraph(v
, h
);
4250 scf_instance_destroy(inst
);
4252 /* Ignore restarter change for now. */
4254 startd_free(restarter_fmri
, max_scf_value_size
);
4255 startd_free(fmri
, max_scf_fmri_size
);
4258 * Always send _ENABLE or _DISABLE. We could avoid this if the
4259 * restarter didn't change and the enabled value didn't change, but
4260 * that's not easy to check and improbable anyway, so we'll just do
4263 graph_enable_by_vertex(v
, enabled
, 1);
4265 MUTEX_UNLOCK(&dgraph_lock
);
4271 * Delete all of the property group dependencies of v, update inst's running
4272 * snapshot, and add the dependencies in the new snapshot. If any of the new
4273 * dependencies would create a cycle, send _ADMIN_MAINT_ON. Otherwise
4274 * reevaluate v's dependencies, send _START or _STOP as appropriate, and do
4275 * the same for v's dependents.
4279 * ECONNABORTED - repository connection broken
4280 * ECANCELED - inst was deleted
4281 * EINVAL - inst is invalid (e.g., missing general/enabled)
4282 * -1 - libscf_snapshots_refresh() failed
4285 dgraph_refresh_instance(graph_vertex_t
*v
, scf_instance_t
*inst
)
4291 assert(MUTEX_HELD(&dgraph_lock
));
4292 assert(v
->gv_type
== GVT_INST
);
4294 /* Only refresh services with valid general/enabled properties. */
4295 r
= libscf_get_basic_instance_data(scf_instance_handle(inst
), inst
,
4296 v
->gv_name
, &enabled
, NULL
, NULL
);
4306 log_framework(LOG_DEBUG
,
4307 "Ignoring %s because it has no general property group.\n",
4312 bad_error("libscf_get_basic_instance_data", r
);
4315 if ((tset
= libscf_get_stn_tset(inst
)) == -1) {
4316 log_framework(LOG_WARNING
,
4317 "Failed to get notification parameters for %s: %s\n",
4318 v
->gv_name
, scf_strerror(scf_error()));
4321 v
->gv_stn_tset
= tset
;
4322 if (strcmp(v
->gv_name
, SCF_INSTANCE_GLOBAL
) == 0)
4328 r
= libscf_snapshots_refresh(inst
, v
->gv_name
);
4331 bad_error("libscf_snapshots_refresh", r
);
4337 r
= refresh_vertex(v
, inst
);
4338 if (r
!= 0 && r
!= ECONNABORTED
)
4339 bad_error("refresh_vertex", r
);
4344 * Returns true only if none of this service's dependents are 'up' -- online
4345 * or degraded (offline is considered down in this situation). This function
4346 * is somehow similar to is_nonsubgraph_leaf() but works on subtrees.
4349 insubtree_dependents_down(graph_vertex_t
*v
)
4354 assert(MUTEX_HELD(&dgraph_lock
));
4356 for (e
= uu_list_first(v
->gv_dependents
); e
!= NULL
;
4357 e
= uu_list_next(v
->gv_dependents
, e
)) {
4359 if (vv
->gv_type
== GVT_INST
) {
4360 if ((vv
->gv_flags
& GV_CONFIGURED
) == 0)
4363 if ((vv
->gv_flags
& GV_TOOFFLINE
) == 0)
4366 if ((vv
->gv_state
== RESTARTER_STATE_ONLINE
) ||
4367 (vv
->gv_state
== RESTARTER_STATE_DEGRADED
))
4371 * Skip all excluded dependents and decide whether
4372 * to offline the service based on the restart_on
4375 if (is_depgrp_bypassed(vv
))
4379 * For dependency groups or service vertices, keep
4380 * traversing to see if instances are running.
4382 if (insubtree_dependents_down(vv
) == B_FALSE
)
4391 * Returns true only if none of this service's dependents are 'up' -- online,
4392 * degraded, or offline.
4395 is_nonsubgraph_leaf(graph_vertex_t
*v
)
4400 assert(MUTEX_HELD(&dgraph_lock
));
4402 for (e
= uu_list_first(v
->gv_dependents
);
4404 e
= uu_list_next(v
->gv_dependents
, e
)) {
4407 if (vv
->gv_type
== GVT_INST
) {
4408 if ((vv
->gv_flags
& GV_CONFIGURED
) == 0)
4411 if (vv
->gv_flags
& GV_INSUBGRAPH
)
4414 if (up_state(vv
->gv_state
))
4418 * For dependency group or service vertices, keep
4419 * traversing to see if instances are running.
4421 * We should skip exclude_all dependencies otherwise
4422 * the vertex will never be considered as a leaf
4423 * if the dependent is offline. The main reason for
4424 * this is that disable_nonsubgraph_leaves() skips
4425 * exclusion dependencies.
4427 if (vv
->gv_type
== GVT_GROUP
&&
4428 vv
->gv_depgroup
== DEPGRP_EXCLUDE_ALL
)
4431 if (!is_nonsubgraph_leaf(vv
))
4440 * Disable v temporarily. Attempt to do this by setting its enabled override
4441 * property in the repository. If that fails, send a _DISABLE command.
4442 * Returns 0 on success and ECONNABORTED if the repository connection is
4446 disable_service_temporarily(graph_vertex_t
*v
, scf_handle_t
*h
)
4448 const char * const emsg
= "Could not temporarily disable %s because "
4449 "%s. Will stop service anyways. Repository status for the "
4450 "service may be inaccurate.\n";
4451 const char * const emsg_cbroken
=
4452 "the repository connection was broken";
4454 scf_instance_t
*inst
;
4457 inst
= scf_instance_create(h
);
4461 (void) snprintf(buf
, sizeof (buf
),
4462 "scf_instance_create() failed (%s)",
4463 scf_strerror(scf_error()));
4464 log_error(LOG_WARNING
, emsg
, v
->gv_name
, buf
);
4466 graph_enable_by_vertex(v
, 0, 0);
4470 r
= scf_handle_decode_fmri(h
, v
->gv_name
, NULL
, NULL
, inst
,
4471 NULL
, NULL
, SCF_DECODE_FMRI_EXACT
);
4473 switch (scf_error()) {
4474 case SCF_ERROR_CONNECTION_BROKEN
:
4475 log_error(LOG_WARNING
, emsg
, v
->gv_name
, emsg_cbroken
);
4476 graph_enable_by_vertex(v
, 0, 0);
4477 return (ECONNABORTED
);
4479 case SCF_ERROR_NOT_FOUND
:
4482 case SCF_ERROR_HANDLE_MISMATCH
:
4483 case SCF_ERROR_INVALID_ARGUMENT
:
4484 case SCF_ERROR_CONSTRAINT_VIOLATED
:
4485 case SCF_ERROR_NOT_BOUND
:
4487 bad_error("scf_handle_decode_fmri",
4492 r
= libscf_set_enable_ovr(inst
, 0);
4495 scf_instance_destroy(inst
);
4499 scf_instance_destroy(inst
);
4503 log_error(LOG_WARNING
, emsg
, v
->gv_name
, emsg_cbroken
);
4504 graph_enable_by_vertex(v
, 0, 0);
4505 return (ECONNABORTED
);
4508 log_error(LOG_WARNING
, emsg
, v
->gv_name
,
4509 "the repository denied permission");
4510 graph_enable_by_vertex(v
, 0, 0);
4514 log_error(LOG_WARNING
, emsg
, v
->gv_name
,
4515 "the repository is read-only");
4516 graph_enable_by_vertex(v
, 0, 0);
4520 bad_error("libscf_set_enable_ovr", r
);
4526 * Of the transitive instance dependencies of v, offline those which are
4527 * in the subtree and which are leaves (i.e., have no dependents which are
4531 offline_subtree_leaves(graph_vertex_t
*v
, void *arg
)
4533 assert(MUTEX_HELD(&dgraph_lock
));
4535 /* If v isn't an instance, recurse on its dependencies. */
4536 if (v
->gv_type
!= GVT_INST
) {
4537 graph_walk_dependencies(v
, offline_subtree_leaves
, arg
);
4542 * If v is not in the subtree, so should all of its dependencies,
4545 if ((v
->gv_flags
& GV_TOOFFLINE
) == 0)
4548 /* If v isn't a leaf because it's already down, recurse. */
4549 if (!up_state(v
->gv_state
)) {
4550 graph_walk_dependencies(v
, offline_subtree_leaves
, arg
);
4554 /* if v is a leaf, offline it or disable it if it's the last one */
4555 if (insubtree_dependents_down(v
) == B_TRUE
) {
4556 if (v
->gv_flags
& GV_TODISABLE
)
4557 vertex_send_event(v
,
4558 RESTARTER_EVENT_TYPE_ADMIN_DISABLE
);
4565 graph_offline_subtree_leaves(graph_vertex_t
*v
, void *h
)
4567 graph_walk_dependencies(v
, offline_subtree_leaves
, (void *)h
);
4572 * Of the transitive instance dependencies of v, disable those which are not
4573 * in the subgraph and which are leaves (i.e., have no dependents which are
4577 disable_nonsubgraph_leaves(graph_vertex_t
*v
, void *arg
)
4579 assert(MUTEX_HELD(&dgraph_lock
));
4582 * We must skip exclusion dependencies because they are allowed to
4583 * complete dependency cycles. This is correct because A's exclusion
4584 * dependency on B doesn't bear on the order in which they should be
4585 * stopped. Indeed, the exclusion dependency should guarantee that
4586 * they are never online at the same time.
4588 if (v
->gv_type
== GVT_GROUP
&& v
->gv_depgroup
== DEPGRP_EXCLUDE_ALL
)
4591 /* If v isn't an instance, recurse on its dependencies. */
4592 if (v
->gv_type
!= GVT_INST
)
4595 if ((v
->gv_flags
& GV_CONFIGURED
) == 0)
4597 * Unconfigured instances should have no dependencies, but in
4598 * case they ever get them,
4603 * If v is in the subgraph, so should all of its dependencies, so do
4606 if (v
->gv_flags
& GV_INSUBGRAPH
)
4609 /* If v isn't a leaf because it's already down, recurse. */
4610 if (!up_state(v
->gv_state
))
4613 /* If v is disabled but not down yet, be patient. */
4614 if ((v
->gv_flags
& GV_ENABLED
) == 0)
4617 /* If v is a leaf, disable it. */
4618 if (is_nonsubgraph_leaf(v
))
4619 (void) disable_service_temporarily(v
, (scf_handle_t
*)arg
);
4624 graph_walk_dependencies(v
, disable_nonsubgraph_leaves
, arg
);
4628 stn_restarter_state(restarter_instance_state_t rstate
)
4630 static const struct statemap
{
4631 restarter_instance_state_t restarter_state
;
4634 { RESTARTER_STATE_UNINIT
, SCF_STATE_UNINIT
},
4635 { RESTARTER_STATE_MAINT
, SCF_STATE_MAINT
},
4636 { RESTARTER_STATE_OFFLINE
, SCF_STATE_OFFLINE
},
4637 { RESTARTER_STATE_DISABLED
, SCF_STATE_DISABLED
},
4638 { RESTARTER_STATE_ONLINE
, SCF_STATE_ONLINE
},
4639 { RESTARTER_STATE_DEGRADED
, SCF_STATE_DEGRADED
}
4644 for (i
= 0; i
< sizeof (map
) / sizeof (map
[0]); i
++) {
4645 if (rstate
== map
[i
].restarter_state
)
4646 return (map
[i
].scf_state
);
4653 * State transition counters
4654 * Not incremented atomically - indicative only
4656 static uint64_t stev_ct_maint
;
4657 static uint64_t stev_ct_hwerr
;
4658 static uint64_t stev_ct_service
;
4659 static uint64_t stev_ct_global
;
4660 static uint64_t stev_ct_noprefs
;
4661 static uint64_t stev_ct_from_uninit
;
4662 static uint64_t stev_ct_bad_state
;
4663 static uint64_t stev_ct_ovr_prefs
;
4666 dgraph_state_transition_notify(graph_vertex_t
*v
,
4667 restarter_instance_state_t old_state
, restarter_str_t reason
)
4669 restarter_instance_state_t new_state
= v
->gv_state
;
4670 int stn_transition
, maint
;
4673 fmev_pri_t pri
= FMEV_LOPRI
;
4676 if ((from
= stn_restarter_state(old_state
)) == -1 ||
4677 (to
= stn_restarter_state(new_state
)) == -1) {
4678 stev_ct_bad_state
++;
4682 stn_transition
= from
<< 16 | to
;
4684 maint
= (to
== SCF_STATE_MAINT
|| from
== SCF_STATE_MAINT
);
4688 * All transitions to/from maintenance state must raise
4694 } else if (reason
== restarter_str_ct_ev_hwerr
) {
4696 * All transitions caused by hardware fault must raise
4702 } else if (stn_transition
& v
->gv_stn_tset
) {
4704 * Specifically enabled event.
4708 } else if (from
== SCF_STATE_UNINIT
) {
4710 * Only raise these if specifically selected above.
4712 stev_ct_from_uninit
++;
4713 } else if (stn_transition
& stn_global
&&
4714 (IS_ENABLED(v
) == 1 || to
== SCF_STATE_DISABLED
)) {
4721 if (info_events_all
) {
4722 stev_ct_ovr_prefs
++;
4728 if (nvlist_alloc(&attr
, NV_UNIQUE_NAME
, 0) != 0 ||
4729 nvlist_add_string(attr
, "fmri", v
->gv_name
) != 0 ||
4730 nvlist_add_uint32(attr
, "reason-version",
4731 restarter_str_version()) || nvlist_add_string(attr
, "reason-short",
4732 restarter_get_str_short(reason
)) != 0 ||
4733 nvlist_add_string(attr
, "reason-long",
4734 restarter_get_str_long(reason
)) != 0 ||
4735 nvlist_add_int32(attr
, "transition", stn_transition
) != 0) {
4736 log_framework(LOG_WARNING
,
4737 "FMEV: %s could not create nvlist for transition "
4738 "event: %s\n", v
->gv_name
, strerror(errno
));
4743 if (fmev_rspublish_nvl(FMEV_RULESET_SMF
, "state-transition",
4744 instance_state_str
[new_state
], pri
, attr
) != FMEV_SUCCESS
) {
4745 log_framework(LOG_DEBUG
,
4746 "FMEV: %s failed to publish transition event: %s\n",
4747 v
->gv_name
, fmev_strerror(fmev_errno
));
4753 * Find the vertex for inst_name. If it doesn't exist, return ENOENT.
4754 * Otherwise set its state to state. If the instance has entered a state
4755 * which requires automatic action, take it (Uninitialized: do
4756 * dgraph_refresh_instance() without the snapshot update. Disabled: if the
4757 * instance should be enabled, send _ENABLE. Offline: if the instance should
4758 * be disabled, send _DISABLE, and if its dependencies are satisfied, send
4759 * _START. Online, Degraded: if the instance wasn't running, update its start
4760 * snapshot. Maintenance: no action.)
4762 * Also fails with ECONNABORTED, or EINVAL if state is invalid.
4765 dgraph_set_instance_state(scf_handle_t
*h
, const char *inst_name
,
4766 protocol_states_t
*states
)
4770 restarter_instance_state_t old_state
;
4771 restarter_instance_state_t state
= states
->ps_state
;
4772 restarter_error_t serr
= states
->ps_err
;
4774 MUTEX_LOCK(&dgraph_lock
);
4776 v
= vertex_get_by_name(inst_name
);
4778 MUTEX_UNLOCK(&dgraph_lock
);
4782 assert(v
->gv_type
== GVT_INST
);
4785 case RESTARTER_STATE_UNINIT
:
4786 case RESTARTER_STATE_DISABLED
:
4787 case RESTARTER_STATE_OFFLINE
:
4788 case RESTARTER_STATE_ONLINE
:
4789 case RESTARTER_STATE_DEGRADED
:
4790 case RESTARTER_STATE_MAINT
:
4794 MUTEX_UNLOCK(&dgraph_lock
);
4798 log_framework(LOG_DEBUG
, "Graph noting %s %s -> %s.\n", v
->gv_name
,
4799 instance_state_str
[v
->gv_state
], instance_state_str
[state
]);
4801 old_state
= v
->gv_state
;
4802 v
->gv_state
= state
;
4804 v
->gv_reason
= states
->ps_reason
;
4805 err
= gt_transition(h
, v
, serr
, old_state
);
4806 if (err
== 0 && v
->gv_state
!= old_state
) {
4807 dgraph_state_transition_notify(v
, old_state
, states
->ps_reason
);
4810 MUTEX_UNLOCK(&dgraph_lock
);
4815 * Handle state changes during milestone shutdown. See
4816 * dgraph_set_milestone(). If the repository connection is broken,
4817 * ECONNABORTED will be returned, though a _DISABLE command will be sent for
4818 * the vertex anyway.
4821 vertex_subgraph_dependencies_shutdown(scf_handle_t
*h
, graph_vertex_t
*v
,
4822 restarter_instance_state_t old_state
)
4827 assert(v
->gv_type
== GVT_INST
);
4829 /* Don't care if we're not going to a milestone. */
4830 if (milestone
== NULL
)
4833 /* Don't care if we already finished coming down. */
4834 if (non_subgraph_svcs
== 0)
4837 /* Don't care if the service is in the subgraph. */
4838 if (v
->gv_flags
& GV_INSUBGRAPH
)
4842 * Update non_subgraph_svcs. It is the number of non-subgraph
4843 * services which are in online, degraded, or offline.
4846 was_up
= up_state(old_state
);
4847 now_up
= up_state(v
->gv_state
);
4849 if (!was_up
&& now_up
) {
4850 ++non_subgraph_svcs
;
4851 } else if (was_up
&& !now_up
) {
4852 --non_subgraph_svcs
;
4854 if (non_subgraph_svcs
== 0) {
4855 if (halting
!= -1) {
4857 } else if (go_single_user_mode
|| go_to_level1
) {
4858 (void) startd_thread_create(single_user_thread
,
4865 /* If this service is a leaf, it should be disabled. */
4866 if ((v
->gv_flags
& GV_ENABLED
) && is_nonsubgraph_leaf(v
)) {
4869 r
= disable_service_temporarily(v
, h
);
4879 bad_error("disable_service_temporarily", r
);
4884 * If the service just came down, propagate the disable to the newly
4887 if (was_up
&& !now_up
)
4888 graph_walk_dependencies(v
, disable_nonsubgraph_leaves
,
4895 * Decide whether to start up an sulogin thread after a service is
4896 * finished changing state. Only need to do the full can_come_up()
4897 * evaluation if an instance is changing state, we're not halfway through
4898 * loading the thread, and we aren't shutting down or going to the single
4902 graph_transition_sulogin(restarter_instance_state_t state
,
4903 restarter_instance_state_t old_state
)
4905 assert(MUTEX_HELD(&dgraph_lock
));
4907 if (state
!= old_state
&& st
->st_load_complete
&&
4908 !go_single_user_mode
&& !go_to_level1
&&
4910 if (!sulogin_thread_running
&& !can_come_up()) {
4911 (void) startd_thread_create(sulogin_thread
, NULL
);
4912 sulogin_thread_running
= B_TRUE
;
4918 * Propagate a start, stop event, or a satisfiability event.
4920 * PROPAGATE_START and PROPAGATE_STOP simply propagate the transition event
4921 * to direct dependents. PROPAGATE_SAT propagates a start then walks the
4922 * full dependent graph to check for newly satisfied nodes. This is
4923 * necessary for cases when non-direct dependents may be effected but direct
4924 * dependents may not (e.g. for optional_all evaluations, see the
4925 * propagate_satbility() comments).
4927 * PROPAGATE_SAT should be used whenever a non-running service moves into
4928 * a state which can satisfy optional dependencies, like disabled or
4932 graph_transition_propagate(graph_vertex_t
*v
, propagate_event_t type
,
4933 restarter_error_t rerr
)
4935 if (type
== PROPAGATE_STOP
) {
4936 graph_walk_dependents(v
, propagate_stop
, (void *)rerr
);
4937 } else if (type
== PROPAGATE_START
|| type
== PROPAGATE_SAT
) {
4938 graph_walk_dependents(v
, propagate_start
, (void *)RERR_NONE
);
4940 if (type
== PROPAGATE_SAT
)
4941 propagate_satbility(v
);
4944 uu_warn("%s:%d: Unexpected type value %d.\n", __FILE__
,
4952 * If a vertex for fmri exists and it is enabled, send _DISABLE to the
4953 * restarter. If it is running, send _STOP. Send _REMOVE_INSTANCE. Delete
4954 * all property group dependencies, and the dependency on the restarter,
4955 * disposing of vertices as appropriate. If other vertices depend on this
4956 * one, mark it unconfigured and return. Otherwise remove the vertex. Always
4960 dgraph_remove_instance(const char *fmri
, scf_handle_t
*h
)
4964 uu_list_t
*old_deps
;
4967 log_framework(LOG_DEBUG
, "Graph engine: Removing %s.\n", fmri
);
4969 MUTEX_LOCK(&dgraph_lock
);
4971 v
= vertex_get_by_name(fmri
);
4973 MUTEX_UNLOCK(&dgraph_lock
);
4977 /* Send restarter delete event. */
4978 if (v
->gv_flags
& GV_CONFIGURED
)
4979 graph_unset_restarter(v
);
4981 if (milestone
> MILESTONE_NONE
) {
4983 * Make a list of v's current dependencies so we can
4984 * reevaluate their GV_INSUBGRAPH flags after the dependencies
4987 old_deps
= startd_list_create(graph_edge_pool
, NULL
, 0);
4989 err
= uu_list_walk(v
->gv_dependencies
,
4990 (uu_walk_fn_t
*)append_svcs_or_insts
, old_deps
, 0);
4994 delete_instance_dependencies(v
, B_TRUE
);
4997 * Deleting an instance can both satisfy and unsatisfy dependencies,
4998 * depending on their type. First propagate the stop as a RERR_RESTART
4999 * event -- deletion isn't a fault, just a normal stop. This gives
5000 * dependent services the chance to do a clean shutdown. Then, mark
5001 * the service as unconfigured and propagate the start event for the
5002 * optional_all dependencies that might have become satisfied.
5004 graph_walk_dependents(v
, propagate_stop
, (void *)RERR_RESTART
);
5006 v
->gv_flags
&= ~GV_CONFIGURED
;
5007 v
->gv_flags
&= ~GV_DEATHROW
;
5009 graph_walk_dependents(v
, propagate_start
, (void *)RERR_NONE
);
5010 propagate_satbility(v
);
5013 * If there are no (non-service) dependents, the vertex can be
5014 * completely removed.
5016 if (v
!= milestone
&& v
->gv_refs
== 0 &&
5017 uu_list_numnodes(v
->gv_dependents
) == 1)
5018 remove_inst_vertex(v
);
5020 if (milestone
> MILESTONE_NONE
) {
5021 void *cookie
= NULL
;
5023 while ((e
= uu_list_teardown(old_deps
, &cookie
)) != NULL
) {
5026 if (vertex_unref(v
) == VERTEX_INUSE
)
5027 while (eval_subgraph(v
, h
) == ECONNABORTED
)
5028 libscf_handle_rebind(h
);
5030 startd_free(e
, sizeof (*e
));
5033 uu_list_destroy(old_deps
);
5036 MUTEX_UNLOCK(&dgraph_lock
);
5042 * Return the eventual (maybe current) milestone in the form of a
5046 target_milestone_as_runlevel()
5048 assert(MUTEX_HELD(&dgraph_lock
));
5050 if (milestone
== NULL
)
5052 else if (milestone
== MILESTONE_NONE
)
5055 if (strcmp(milestone
->gv_name
, multi_user_fmri
) == 0)
5057 else if (strcmp(milestone
->gv_name
, single_user_fmri
) == 0)
5059 else if (strcmp(milestone
->gv_name
, multi_user_svr_fmri
) == 0)
5063 (void) fprintf(stderr
, "%s:%d: Unknown milestone name \"%s\".\n",
5064 __FILE__
, __LINE__
, milestone
->gv_name
);
5086 signal_init(char rl
)
5091 assert(MUTEX_HELD(&dgraph_lock
));
5093 if (zone_getattr(getzoneid(), ZONE_ATTR_INITPID
, &init_pid
,
5094 sizeof (init_pid
)) != sizeof (init_pid
)) {
5095 log_error(LOG_NOTICE
, "Could not get pid to signal init.\n");
5099 for (i
= 0; init_sigs
[i
].rl
!= 0; ++i
)
5100 if (init_sigs
[i
].rl
== rl
)
5103 if (init_sigs
[i
].rl
!= 0) {
5104 if (kill(init_pid
, init_sigs
[i
].sig
) != 0) {
5108 log_error(LOG_NOTICE
, "Could not signal init: "
5109 "%s.\n", strerror(errno
));
5114 bad_error("kill", errno
);
5121 * This is called when one of the major milestones changes state, or when
5122 * init is signalled and tells us it was told to change runlevel. We wait
5123 * to reach the milestone because this allows /etc/inittab entries to retain
5124 * some boot ordering: historically, entries could place themselves before/after
5125 * the running of /sbin/rcX scripts but we can no longer make the
5126 * distinction because the /sbin/rcX scripts no longer exist as punctuation
5127 * marks in /etc/inittab.
5129 * Also, we only trigger an update when we reach the eventual target
5130 * milestone: without this, an /etc/inittab entry marked only for
5131 * runlevel 2 would be executed for runlevel 3, which is not how
5132 * /etc/inittab entries work.
5134 * If we're single user coming online, then we set utmpx to the target
5135 * runlevel so that legacy scripts can work as expected.
5138 graph_runlevel_changed(char rl
, int online
)
5142 assert(MUTEX_HELD(&dgraph_lock
));
5144 trl
= target_milestone_as_runlevel();
5148 current_runlevel
= trl
;
5150 } else if (rl
== 'S') {
5152 * At boot, set the entry early for the benefit of the
5153 * legacy init scripts.
5155 utmpx_set_runlevel(trl
, 'S', B_FALSE
);
5158 if (rl
== '3' && trl
== '2') {
5159 current_runlevel
= trl
;
5161 } else if (rl
== '2' && trl
== 'S') {
5162 current_runlevel
= trl
;
5169 * Move to a backwards-compatible runlevel by executing the appropriate
5170 * /etc/rc?.d/K* scripts and/or setting the milestone.
5174 * ECONNRESET - success, but handle was reset
5175 * ECONNABORTED - repository connection broken
5176 * ECANCELED - pg was deleted
5179 dgraph_set_runlevel(scf_propertygroup_t
*pg
, scf_property_t
*prop
)
5184 const char *ms
= NULL
; /* what to commit as options/milestone */
5185 boolean_t rebound
= B_FALSE
;
5188 const char * const stop
= "stop";
5190 r
= libscf_extract_runlevel(prop
, &rl
);
5201 log_error(LOG_WARNING
, "runlevel property is misconfigured; "
5203 /* delete the bad property */
5207 bad_error("libscf_extract_runlevel", r
);
5219 * These cases cause a milestone change, so
5220 * graph_runlevel_changed() will eventually deal with
5234 log_framework(LOG_NOTICE
, "Unknown runlevel '%c'.\n", rl
);
5239 h
= scf_pg_handle(pg
);
5241 MUTEX_LOCK(&dgraph_lock
);
5244 * Since this triggers no milestone changes, force it by hand.
5246 if (current_runlevel
== '4' && rl
== '3')
5250 * 1. If we are here after an "init X":
5253 * init/lscf_set_runlevel()
5254 * process_pg_event()
5255 * dgraph_set_runlevel()
5257 * then we haven't passed through graph_runlevel_changed() yet,
5258 * therefore 'current_runlevel' has not changed for sure but 'rl' has.
5259 * In consequence, if 'rl' is lower than 'current_runlevel', we change
5260 * the system runlevel and execute the appropriate /etc/rc?.d/K* scripts
5263 * 2. On the other hand, if we are here after a "svcadm milestone":
5265 * svcadm milestone X
5266 * dgraph_set_milestone()
5267 * handle_graph_update_event()
5268 * dgraph_set_instance_state()
5269 * graph_post_X_[online|offline]()
5270 * graph_runlevel_changed()
5272 * init/lscf_set_runlevel()
5273 * process_pg_event()
5274 * dgraph_set_runlevel()
5276 * then we already passed through graph_runlevel_changed() (by the way
5277 * of dgraph_set_milestone()) and 'current_runlevel' may have changed
5278 * and already be equal to 'rl' so we are going to return immediately
5279 * from dgraph_set_runlevel() without changing the system runlevel and
5280 * without executing the /etc/rc?.d/K* scripts.
5282 if (rl
== current_runlevel
) {
5287 log_framework(LOG_DEBUG
, "Changing to runlevel '%c'.\n", rl
);
5290 * Make sure stop rc scripts see the new settings via who -r.
5292 utmpx_set_runlevel(rl
, current_runlevel
, B_TRUE
);
5295 * Some run levels don't have a direct correspondence to any
5296 * milestones, so we have to signal init directly.
5299 current_runlevel
= rl
;
5305 uu_warn("The system is coming down for administration. "
5307 fork_rc_script(rl
, stop
, B_FALSE
);
5308 ms
= single_user_fmri
;
5309 go_single_user_mode
= B_TRUE
;
5313 halting_time
= time(NULL
);
5314 fork_rc_script(rl
, stop
, B_TRUE
);
5319 halting_time
= time(NULL
);
5320 fork_rc_script(rl
, stop
, B_TRUE
);
5321 halting
= AD_POWEROFF
;
5325 halting_time
= time(NULL
);
5326 fork_rc_script(rl
, stop
, B_TRUE
);
5327 if (scf_is_fastboot_default() && getzoneid() == GLOBAL_ZONEID
)
5328 halting
= AD_FASTREBOOT
;
5333 uu_warn("The system is coming down. Please wait.\n");
5337 * We can't wait until all services are offline since this
5338 * thread is responsible for taking them offline. Instead we
5339 * set halting to the second argument for uadmin() and call
5340 * do_uadmin() from dgraph_set_instance_state() when
5346 if (current_runlevel
!= 'S') {
5347 uu_warn("Changing to state 1.\n");
5348 fork_rc_script(rl
, stop
, B_FALSE
);
5350 uu_warn("The system is coming up for administration. "
5353 ms
= single_user_fmri
;
5354 go_to_level1
= B_TRUE
;
5358 if (current_runlevel
== '3' || current_runlevel
== '4')
5359 fork_rc_script(rl
, stop
, B_FALSE
);
5360 ms
= multi_user_fmri
;
5370 (void) fprintf(stderr
, "%s:%d: Uncaught case %d ('%c').\n",
5371 __FILE__
, __LINE__
, rl
, rl
);
5377 MUTEX_UNLOCK(&dgraph_lock
);
5380 switch (r
= libscf_clear_runlevel(pg
, ms
)) {
5385 libscf_handle_rebind(h
);
5395 log_error(LOG_NOTICE
, "Could not delete \"%s/%s\" property: "
5396 "%s.\n", SCF_PG_OPTIONS
, "runlevel", strerror(r
));
5400 bad_error("libscf_clear_runlevel", r
);
5403 return (rebound
? ECONNRESET
: 0);
5407 * mark_subtree walks the dependents and add the GV_TOOFFLINE flag
5408 * to the instances that are supposed to go offline during an
5409 * administrative disable operation.
5412 mark_subtree(graph_edge_t
*e
, void *arg
)
5419 /* If it's already in the subgraph, skip. */
5420 if (v
->gv_flags
& GV_TOOFFLINE
)
5421 return (UU_WALK_NEXT
);
5423 switch (v
->gv_type
) {
5425 /* If the instance is already offline, skip it. */
5426 if (!inst_running(v
))
5427 return (UU_WALK_NEXT
);
5429 v
->gv_flags
|= GV_TOOFFLINE
;
5430 log_framework(LOG_DEBUG
, "%s added to subtree\n", v
->gv_name
);
5434 * Skip all excluded dependents and decide whether to offline
5435 * the service based on the restart_on attribute.
5437 if (is_depgrp_bypassed(v
))
5438 return (UU_WALK_NEXT
);
5442 r
= uu_list_walk(v
->gv_dependents
, (uu_walk_fn_t
*)mark_subtree
, arg
,
5445 return (UU_WALK_NEXT
);
5449 mark_subgraph(graph_edge_t
*e
, void *arg
)
5453 int optional
= (int)arg
;
5457 /* If it's already in the subgraph, skip. */
5458 if (v
->gv_flags
& GV_INSUBGRAPH
)
5459 return (UU_WALK_NEXT
);
5462 * Keep track if walk has entered an optional dependency group
5464 if (v
->gv_type
== GVT_GROUP
&& v
->gv_depgroup
== DEPGRP_OPTIONAL_ALL
) {
5468 * Quit if we are in an optional dependency group and the instance
5471 if (optional
&& (v
->gv_type
== GVT_INST
) &&
5472 (!(v
->gv_flags
& GV_ENBLD_NOOVR
)))
5473 return (UU_WALK_NEXT
);
5475 v
->gv_flags
|= GV_INSUBGRAPH
;
5477 /* Skip all excluded dependencies. */
5478 if (v
->gv_type
== GVT_GROUP
&& v
->gv_depgroup
== DEPGRP_EXCLUDE_ALL
)
5479 return (UU_WALK_NEXT
);
5481 r
= uu_list_walk(v
->gv_dependencies
, (uu_walk_fn_t
*)mark_subgraph
,
5482 (void *)optional
, 0);
5484 return (UU_WALK_NEXT
);
5488 * Bring down all services which are not dependencies of fmri. The
5489 * dependencies of fmri (direct & indirect) will constitute the "subgraph",
5490 * and will have the GV_INSUBGRAPH flag set. The rest must be brought down,
5491 * which means the state is "disabled", "maintenance", or "uninitialized". We
5492 * could consider "offline" to be down, and refrain from sending start
5493 * commands for such services, but that's not strictly necessary, so we'll
5494 * decline to intrude on the state machine. It would probably confuse users
5497 * The services should be brought down in reverse-dependency order, so we
5498 * can't do it all at once here. We initiate by override-disabling the leaves
5499 * of the dependency tree -- those services which are up but have no
5500 * dependents which are up. When they come down,
5501 * vertex_subgraph_dependencies_shutdown() will override-disable the newly
5502 * exposed leaves. Perseverance will ensure completion.
5504 * Sometimes we need to take action when the transition is complete, like
5505 * start sulogin or halt the system. To tell when we're done, we initialize
5506 * non_subgraph_svcs here to be the number of services which need to come
5507 * down. As each does, we decrement the counter. When it hits zero, we take
5508 * the appropriate action. See vertex_subgraph_dependencies_shutdown().
5510 * In case we're coming up, we also remove any enable-overrides for the
5511 * services which are dependencies of fmri.
5513 * If norepository is true, the function will not change the repository.
5515 * The decision to change the system run level in accordance with the milestone
5516 * is taken in dgraph_set_runlevel().
5520 * ECONNRESET - success, but handle was rebound
5521 * EINVAL - fmri is invalid (error is logged)
5522 * EALREADY - the milestone is already set to fmri
5523 * ENOENT - a configured vertex does not exist for fmri (an error is logged)
5526 dgraph_set_milestone(const char *fmri
, scf_handle_t
*h
, boolean_t norepository
)
5528 const char *cfmri
, *fs
;
5529 graph_vertex_t
*nm
, *v
;
5531 scf_instance_t
*inst
;
5532 boolean_t isall
, isnone
, rebound
= B_FALSE
;
5535 isall
= (strcmp(fmri
, "all") == 0);
5536 isnone
= (strcmp(fmri
, "none") == 0);
5538 if (!isall
&& !isnone
) {
5539 if (fmri_canonify(fmri
, (char **)&cfmri
, B_FALSE
) == EINVAL
)
5542 if (strcmp(cfmri
, single_user_fmri
) != 0 &&
5543 strcmp(cfmri
, multi_user_fmri
) != 0 &&
5544 strcmp(cfmri
, multi_user_svr_fmri
) != 0) {
5545 startd_free((void *)cfmri
, max_scf_fmri_size
);
5547 log_framework(LOG_WARNING
,
5548 "Rejecting request for invalid milestone \"%s\".\n",
5554 inst
= safe_scf_instance_create(h
);
5556 MUTEX_LOCK(&dgraph_lock
);
5558 if (milestone
== NULL
) {
5560 log_framework(LOG_DEBUG
,
5561 "Milestone already set to all.\n");
5565 } else if (milestone
== MILESTONE_NONE
) {
5567 log_framework(LOG_DEBUG
,
5568 "Milestone already set to none.\n");
5573 if (!isall
&& !isnone
&&
5574 strcmp(cfmri
, milestone
->gv_name
) == 0) {
5575 log_framework(LOG_DEBUG
,
5576 "Milestone already set to %s.\n", cfmri
);
5582 if (!isall
&& !isnone
) {
5583 nm
= vertex_get_by_name(cfmri
);
5584 if (nm
== NULL
|| !(nm
->gv_flags
& GV_CONFIGURED
)) {
5585 log_framework(LOG_WARNING
, "Cannot set milestone to %s "
5586 "because no such service exists.\n", cfmri
);
5592 log_framework(LOG_DEBUG
, "Changing milestone to %s.\n", fmri
);
5595 * Set milestone, removing the old one if this was the last reference.
5597 if (milestone
> MILESTONE_NONE
)
5598 (void) vertex_unref(milestone
);
5603 milestone
= MILESTONE_NONE
;
5606 /* milestone should count as a reference */
5607 vertex_ref(milestone
);
5610 /* Clear all GV_INSUBGRAPH bits. */
5611 for (v
= uu_list_first(dgraph
); v
!= NULL
; v
= uu_list_next(dgraph
, v
))
5612 v
->gv_flags
&= ~GV_INSUBGRAPH
;
5614 if (!isall
&& !isnone
) {
5615 /* Set GV_INSUBGRAPH for milestone & descendents. */
5616 milestone
->gv_flags
|= GV_INSUBGRAPH
;
5618 r
= uu_list_walk(milestone
->gv_dependencies
,
5619 (uu_walk_fn_t
*)mark_subgraph
, NULL
, 0);
5623 /* Un-override services in the subgraph & override-disable the rest. */
5627 non_subgraph_svcs
= 0;
5628 for (v
= uu_list_first(dgraph
);
5630 v
= uu_list_next(dgraph
, v
)) {
5631 if (v
->gv_type
!= GVT_INST
||
5632 (v
->gv_flags
& GV_CONFIGURED
) == 0)
5636 r
= scf_handle_decode_fmri(h
, v
->gv_name
, NULL
, NULL
, inst
,
5637 NULL
, NULL
, SCF_DECODE_FMRI_EXACT
);
5639 switch (scf_error()) {
5640 case SCF_ERROR_CONNECTION_BROKEN
:
5642 libscf_handle_rebind(h
);
5646 case SCF_ERROR_NOT_FOUND
:
5649 case SCF_ERROR_HANDLE_MISMATCH
:
5650 case SCF_ERROR_INVALID_ARGUMENT
:
5651 case SCF_ERROR_CONSTRAINT_VIOLATED
:
5652 case SCF_ERROR_NOT_BOUND
:
5653 bad_error("scf_handle_decode_fmri",
5658 if (isall
|| (v
->gv_flags
& GV_INSUBGRAPH
)) {
5659 r
= libscf_delete_enable_ovr(inst
);
5660 fs
= "libscf_delete_enable_ovr";
5662 assert(isnone
|| (v
->gv_flags
& GV_INSUBGRAPH
) == 0);
5665 * Services which are up need to come down before
5666 * we're done, but we can only disable the leaves
5670 if (up_state(v
->gv_state
))
5671 ++non_subgraph_svcs
;
5673 /* If it's already disabled, don't bother. */
5674 if ((v
->gv_flags
& GV_ENABLED
) == 0)
5677 if (!is_nonsubgraph_leaf(v
))
5680 r
= libscf_set_enable_ovr(inst
, 0);
5681 fs
= "libscf_set_enable_ovr";
5689 libscf_handle_rebind(h
);
5695 log_error(LOG_WARNING
,
5696 "Could not set %s/%s for %s: %s.\n",
5697 SCF_PG_GENERAL_OVR
, SCF_PROPERTY_ENABLED
,
5698 v
->gv_name
, strerror(r
));
5706 if (halting
!= -1) {
5707 if (non_subgraph_svcs
> 1)
5708 uu_warn("%d system services are now being stopped.\n",
5710 else if (non_subgraph_svcs
== 1)
5711 uu_warn("One system service is now being stopped.\n");
5712 else if (non_subgraph_svcs
== 0)
5716 ret
= rebound
? ECONNRESET
: 0;
5719 MUTEX_UNLOCK(&dgraph_lock
);
5720 if (!isall
&& !isnone
)
5721 startd_free((void *)cfmri
, max_scf_fmri_size
);
5722 scf_instance_destroy(inst
);
5728 * Returns 0, ECONNABORTED, or EINVAL.
5731 handle_graph_update_event(scf_handle_t
*h
, graph_protocol_event_t
*e
)
5735 switch (e
->gpe_type
) {
5736 case GRAPH_UPDATE_RELOAD_GRAPH
:
5737 log_error(LOG_WARNING
,
5738 "graph_event: reload graph unimplemented\n");
5741 case GRAPH_UPDATE_STATE_CHANGE
: {
5742 protocol_states_t
*states
= e
->gpe_data
;
5744 switch (r
= dgraph_set_instance_state(h
, e
->gpe_inst
, states
)) {
5750 return (ECONNABORTED
);
5755 (void) fprintf(stderr
, "dgraph_set_instance_state() "
5756 "failed with unexpected error %d at %s:%d.\n", r
,
5757 __FILE__
, __LINE__
);
5762 startd_free(states
, sizeof (protocol_states_t
));
5767 log_error(LOG_WARNING
,
5768 "graph_event_loop received an unknown event: %d\n",
5777 * graph_event_thread()
5778 * Wait for state changes from the restarters.
5782 graph_event_thread(void *unused
)
5787 (void) pthread_setname_np(pthread_self(), "graph_event");
5789 h
= libscf_handle_create_bound_loop();
5793 graph_protocol_event_t
*e
;
5795 MUTEX_LOCK(&gu
->gu_lock
);
5797 while (gu
->gu_wakeup
== 0)
5798 (void) pthread_cond_wait(&gu
->gu_cv
, &gu
->gu_lock
);
5802 while ((e
= graph_event_dequeue()) != NULL
) {
5803 MUTEX_LOCK(&e
->gpe_lock
);
5804 MUTEX_UNLOCK(&gu
->gu_lock
);
5806 while ((err
= handle_graph_update_event(h
, e
)) ==
5808 libscf_handle_rebind(h
);
5811 graph_event_release(e
);
5813 graph_event_requeue(e
);
5815 MUTEX_LOCK(&gu
->gu_lock
);
5818 MUTEX_UNLOCK(&gu
->gu_lock
);
5822 * Unreachable for now -- there's currently no graceful cleanup
5825 MUTEX_UNLOCK(&gu
->gu_lock
);
5826 scf_handle_destroy(h
);
5831 set_initial_milestone(scf_handle_t
*h
)
5833 scf_instance_t
*inst
;
5838 inst
= safe_scf_instance_create(h
);
5839 fmri
= startd_alloc(max_scf_fmri_size
);
5842 * If -m milestone= was specified, we want to set options_ovr/milestone
5843 * to it. Otherwise we want to read what the milestone should be set
5844 * to. Either way we need our inst.
5847 if (scf_handle_decode_fmri(h
, SCF_SERVICE_STARTD
, NULL
, NULL
, inst
,
5848 NULL
, NULL
, SCF_DECODE_FMRI_EXACT
) != 0) {
5849 switch (scf_error()) {
5850 case SCF_ERROR_CONNECTION_BROKEN
:
5851 libscf_handle_rebind(h
);
5854 case SCF_ERROR_NOT_FOUND
:
5855 if (st
->st_subgraph
!= NULL
&&
5856 st
->st_subgraph
[0] != '\0') {
5857 sz
= strlcpy(fmri
, st
->st_subgraph
,
5859 assert(sz
< max_scf_fmri_size
);
5865 case SCF_ERROR_INVALID_ARGUMENT
:
5866 case SCF_ERROR_CONSTRAINT_VIOLATED
:
5867 case SCF_ERROR_HANDLE_MISMATCH
:
5869 bad_error("scf_handle_decode_fmri", scf_error());
5872 if (st
->st_subgraph
!= NULL
&& st
->st_subgraph
[0] != '\0') {
5873 scf_propertygroup_t
*pg
;
5875 pg
= safe_scf_pg_create(h
);
5877 sz
= strlcpy(fmri
, st
->st_subgraph
, max_scf_fmri_size
);
5878 assert(sz
< max_scf_fmri_size
);
5880 r
= libscf_inst_get_or_add_pg(inst
, SCF_PG_OPTIONS_OVR
,
5881 SCF_PG_OPTIONS_OVR_TYPE
, SCF_PG_OPTIONS_OVR_FLAGS
,
5888 libscf_handle_rebind(h
);
5894 log_error(LOG_WARNING
, "Could not set %s/%s: "
5895 "%s.\n", SCF_PG_OPTIONS_OVR
,
5896 SCF_PROPERTY_MILESTONE
, strerror(r
));
5900 sz
= strlcpy(fmri
, st
->st_subgraph
,
5902 assert(sz
< max_scf_fmri_size
);
5906 bad_error("libscf_inst_get_or_add_pg", r
);
5909 r
= libscf_clear_runlevel(pg
, fmri
);
5915 libscf_handle_rebind(h
);
5921 log_error(LOG_WARNING
, "Could not set %s/%s: "
5922 "%s.\n", SCF_PG_OPTIONS_OVR
,
5923 SCF_PROPERTY_MILESTONE
, strerror(r
));
5927 sz
= strlcpy(fmri
, st
->st_subgraph
,
5929 assert(sz
< max_scf_fmri_size
);
5933 bad_error("libscf_clear_runlevel", r
);
5938 scf_property_t
*prop
;
5941 prop
= safe_scf_property_create(h
);
5942 val
= safe_scf_value_create(h
);
5944 r
= libscf_get_milestone(inst
, prop
, val
, fmri
,
5951 libscf_handle_rebind(h
);
5955 log_error(LOG_WARNING
, "Milestone property is "
5956 "misconfigured. Defaulting to \"all\".\n");
5965 bad_error("libscf_get_milestone", r
);
5968 scf_value_destroy(val
);
5969 scf_property_destroy(prop
);
5973 if (fmri
[0] == '\0' || strcmp(fmri
, "all") == 0)
5976 if (strcmp(fmri
, "none") != 0) {
5978 if (scf_handle_decode_fmri(h
, fmri
, NULL
, NULL
, inst
, NULL
,
5979 NULL
, SCF_DECODE_FMRI_EXACT
) != 0) {
5980 switch (scf_error()) {
5981 case SCF_ERROR_INVALID_ARGUMENT
:
5982 log_error(LOG_WARNING
,
5983 "Requested milestone \"%s\" is invalid. "
5984 "Reverting to \"all\".\n", fmri
);
5987 case SCF_ERROR_CONSTRAINT_VIOLATED
:
5988 log_error(LOG_WARNING
, "Requested milestone "
5989 "\"%s\" does not specify an instance. "
5990 "Reverting to \"all\".\n", fmri
);
5993 case SCF_ERROR_CONNECTION_BROKEN
:
5994 libscf_handle_rebind(h
);
5997 case SCF_ERROR_NOT_FOUND
:
5998 log_error(LOG_WARNING
, "Requested milestone "
5999 "\"%s\" not in repository. Reverting to "
6000 "\"all\".\n", fmri
);
6003 case SCF_ERROR_HANDLE_MISMATCH
:
6005 bad_error("scf_handle_decode_fmri",
6010 r
= fmri_canonify(fmri
, &cfmri
, B_FALSE
);
6013 r
= dgraph_add_instance(cfmri
, inst
, B_TRUE
);
6014 startd_free(cfmri
, max_scf_fmri_size
);
6023 log_error(LOG_WARNING
,
6024 "Requested milestone \"%s\" is invalid. "
6025 "Reverting to \"all\".\n", fmri
);
6029 log_error(LOG_WARNING
,
6030 "Requested milestone \"%s\" not "
6031 "in repository. Reverting to \"all\".\n",
6037 bad_error("dgraph_add_instance", r
);
6041 log_console(LOG_INFO
, "Booting to milestone \"%s\".\n", fmri
);
6043 r
= dgraph_set_milestone(fmri
, h
, B_FALSE
);
6053 bad_error("dgraph_set_milestone", r
);
6057 startd_free(fmri
, max_scf_fmri_size
);
6058 scf_instance_destroy(inst
);
6062 set_restart_milestone(scf_handle_t
*h
)
6064 scf_instance_t
*inst
;
6065 scf_property_t
*prop
;
6070 inst
= safe_scf_instance_create(h
);
6073 if (scf_handle_decode_fmri(h
, SCF_SERVICE_STARTD
, NULL
, NULL
,
6074 inst
, NULL
, NULL
, SCF_DECODE_FMRI_EXACT
) != 0) {
6075 switch (scf_error()) {
6076 case SCF_ERROR_CONNECTION_BROKEN
:
6077 libscf_handle_rebind(h
);
6080 case SCF_ERROR_NOT_FOUND
:
6083 case SCF_ERROR_INVALID_ARGUMENT
:
6084 case SCF_ERROR_CONSTRAINT_VIOLATED
:
6085 case SCF_ERROR_HANDLE_MISMATCH
:
6087 bad_error("scf_handle_decode_fmri", scf_error());
6090 scf_instance_destroy(inst
);
6094 prop
= safe_scf_property_create(h
);
6095 val
= safe_scf_value_create(h
);
6096 fmri
= startd_alloc(max_scf_fmri_size
);
6098 r
= libscf_get_milestone(inst
, prop
, val
, fmri
, max_scf_fmri_size
);
6104 libscf_handle_rebind(h
);
6113 bad_error("libscf_get_milestone", r
);
6116 r
= dgraph_set_milestone(fmri
, h
, B_TRUE
);
6126 bad_error("dgraph_set_milestone", r
);
6130 startd_free(fmri
, max_scf_fmri_size
);
6131 scf_value_destroy(val
);
6132 scf_property_destroy(prop
);
6133 scf_instance_destroy(inst
);
6137 * void *graph_thread(void *)
6139 * Graph management thread.
6143 graph_thread(void *arg
)
6148 (void) pthread_setname_np(pthread_self(), "graph");
6150 h
= libscf_handle_create_bound_loop();
6153 set_initial_milestone(h
);
6155 MUTEX_LOCK(&dgraph_lock
);
6156 initial_milestone_set
= B_TRUE
;
6157 err
= pthread_cond_broadcast(&initial_milestone_cv
);
6159 MUTEX_UNLOCK(&dgraph_lock
);
6161 libscf_populate_graph(h
);
6163 if (!st
->st_initial
)
6164 set_restart_milestone(h
);
6166 MUTEX_LOCK(&st
->st_load_lock
);
6167 st
->st_load_complete
= 1;
6168 (void) pthread_cond_broadcast(&st
->st_load_cv
);
6169 MUTEX_UNLOCK(&st
->st_load_lock
);
6171 MUTEX_LOCK(&dgraph_lock
);
6173 * Now that we've set st_load_complete we need to check can_come_up()
6174 * since if we booted to a milestone, then there won't be any more
6177 if (!go_single_user_mode
&& !go_to_level1
&&
6179 if (!sulogin_thread_running
&& !can_come_up()) {
6180 (void) startd_thread_create(sulogin_thread
, NULL
);
6181 sulogin_thread_running
= B_TRUE
;
6184 MUTEX_UNLOCK(&dgraph_lock
);
6186 (void) pthread_mutex_lock(&gu
->gu_freeze_lock
);
6190 (void) pthread_cond_wait(&gu
->gu_freeze_cv
,
6191 &gu
->gu_freeze_lock
);
6195 * Unreachable for now -- there's currently no graceful cleanup
6198 (void) pthread_mutex_unlock(&gu
->gu_freeze_lock
);
6199 scf_handle_destroy(h
);
6207 * Given an array of timestamps 'a' with 'num' elements, find the
6208 * lowest non-zero timestamp and return its index. If there are no
6209 * non-zero elements, return -1.
6212 next_action(hrtime_t
*a
, int num
)
6215 int i
= 0, smallest
= -1;
6217 for (i
= 0; i
< num
; i
++) {
6221 } else if (a
[i
] != 0 && a
[i
] < t
) {
6234 * void process_actions()
6235 * Process actions requested by the administrator. Possibilities include:
6236 * refresh, restart, maintenance mode off, maintenance mode on,
6237 * maintenance mode immediate, and degraded.
6239 * The set of pending actions is represented in the repository as a
6240 * per-instance property group, with each action being a single property
6241 * in that group. This property group is converted to an array, with each
6242 * action type having an array slot. The actions in the array at the
6243 * time process_actions() is called are acted on in the order of the
6244 * timestamp (which is the value stored in the slot). A value of zero
6245 * indicates that there is no pending action of the type associated with
6246 * a particular slot.
6248 * Sending an action event multiple times before the restarter has a
6249 * chance to process that action will force it to be run at the last
6250 * timestamp where it appears in the ordering.
6252 * Turning maintenance mode on trumps all other actions.
6254 * Returns 0 or ECONNABORTED.
6257 process_actions(scf_handle_t
*h
, scf_propertygroup_t
*pg
, scf_instance_t
*inst
)
6259 scf_property_t
*prop
= NULL
;
6260 scf_value_t
*val
= NULL
;
6262 graph_vertex_t
*vertex
;
6265 hrtime_t action_ts
[NACTIONS
];
6268 r
= libscf_instance_get_fmri(inst
, &inst_name
);
6274 return (ECONNABORTED
);
6280 bad_error("libscf_instance_get_fmri", r
);
6283 MUTEX_LOCK(&dgraph_lock
);
6285 vertex
= vertex_get_by_name(inst_name
);
6286 if (vertex
== NULL
) {
6287 MUTEX_UNLOCK(&dgraph_lock
);
6288 log_framework(LOG_DEBUG
, "%s: Can't find graph vertex. "
6289 "The instance must have been removed.\n", inst_name
);
6290 startd_free(inst_name
, max_scf_fmri_size
);
6294 prop
= safe_scf_property_create(h
);
6295 val
= safe_scf_value_create(h
);
6297 for (i
= 0; i
< NACTIONS
; i
++) {
6298 if (scf_pg_get_property(pg
, admin_actions
[i
], prop
) != 0) {
6299 switch (scf_error()) {
6300 case SCF_ERROR_CONNECTION_BROKEN
:
6305 case SCF_ERROR_DELETED
:
6308 case SCF_ERROR_NOT_FOUND
:
6312 case SCF_ERROR_HANDLE_MISMATCH
:
6313 case SCF_ERROR_INVALID_ARGUMENT
:
6314 case SCF_ERROR_NOT_SET
:
6315 bad_error("scf_pg_get_property", scf_error());
6319 if (scf_property_type(prop
, &type
) != 0) {
6320 switch (scf_error()) {
6321 case SCF_ERROR_CONNECTION_BROKEN
:
6326 case SCF_ERROR_DELETED
:
6330 case SCF_ERROR_NOT_SET
:
6331 bad_error("scf_property_type", scf_error());
6335 if (type
!= SCF_TYPE_INTEGER
) {
6340 if (scf_property_get_value(prop
, val
) != 0) {
6341 switch (scf_error()) {
6342 case SCF_ERROR_CONNECTION_BROKEN
:
6347 case SCF_ERROR_DELETED
:
6350 case SCF_ERROR_NOT_FOUND
:
6351 case SCF_ERROR_CONSTRAINT_VIOLATED
:
6355 case SCF_ERROR_NOT_SET
:
6356 case SCF_ERROR_PERMISSION_DENIED
:
6357 bad_error("scf_property_get_value",
6362 r
= scf_value_get_integer(val
, &action_ts
[i
]);
6366 a
= ADMIN_EVENT_MAINT_ON_IMMEDIATE
;
6367 if (action_ts
[ADMIN_EVENT_MAINT_ON_IMMEDIATE
] ||
6368 action_ts
[ADMIN_EVENT_MAINT_ON
]) {
6369 a
= action_ts
[ADMIN_EVENT_MAINT_ON_IMMEDIATE
] ?
6370 ADMIN_EVENT_MAINT_ON_IMMEDIATE
: ADMIN_EVENT_MAINT_ON
;
6372 vertex_send_event(vertex
, admin_events
[a
]);
6373 r
= libscf_unset_action(h
, pg
, a
, action_ts
[a
]);
6384 uu_die("Insufficient privilege.\n");
6388 bad_error("libscf_unset_action", r
);
6392 while ((a
= next_action(action_ts
, NACTIONS
)) != -1) {
6393 log_framework(LOG_DEBUG
,
6394 "Graph: processing %s action for %s.\n", admin_actions
[a
],
6397 if (a
== ADMIN_EVENT_REFRESH
) {
6398 r
= dgraph_refresh_instance(vertex
, inst
);
6407 /* pg & inst are reset now, so just return. */
6412 bad_error("dgraph_refresh_instance", r
);
6416 vertex_send_event(vertex
, admin_events
[a
]);
6418 r
= libscf_unset_action(h
, pg
, a
, action_ts
[a
]);
6429 uu_die("Insufficient privilege.\n");
6433 bad_error("libscf_unset_action", r
);
6440 MUTEX_UNLOCK(&dgraph_lock
);
6442 scf_property_destroy(prop
);
6443 scf_value_destroy(val
);
6444 startd_free(inst_name
, max_scf_fmri_size
);
6449 * inst and pg_name are scratch space, and are unset on entry.
6452 * ECONNRESET - success, but repository handle rebound
6453 * ECONNABORTED - repository connection broken
6456 process_pg_event(scf_handle_t
*h
, scf_propertygroup_t
*pg
, scf_instance_t
*inst
,
6460 scf_property_t
*prop
;
6463 boolean_t rebound
= B_FALSE
, rebind_inst
= B_FALSE
;
6465 if (scf_pg_get_name(pg
, pg_name
, max_scf_value_size
) < 0) {
6466 switch (scf_error()) {
6467 case SCF_ERROR_CONNECTION_BROKEN
:
6469 return (ECONNABORTED
);
6471 case SCF_ERROR_DELETED
:
6474 case SCF_ERROR_NOT_SET
:
6475 bad_error("scf_pg_get_name", scf_error());
6479 if (strcmp(pg_name
, SCF_PG_GENERAL
) == 0 ||
6480 strcmp(pg_name
, SCF_PG_GENERAL_OVR
) == 0) {
6481 r
= dgraph_update_general(pg
);
6489 return (ECONNABORTED
);
6492 /* Error should have been logged. */
6496 bad_error("dgraph_update_general", r
);
6498 } else if (strcmp(pg_name
, SCF_PG_RESTARTER_ACTIONS
) == 0) {
6499 if (scf_pg_get_parent_instance(pg
, inst
) != 0) {
6500 switch (scf_error()) {
6501 case SCF_ERROR_CONNECTION_BROKEN
:
6502 return (ECONNABORTED
);
6504 case SCF_ERROR_DELETED
:
6505 case SCF_ERROR_CONSTRAINT_VIOLATED
:
6506 /* Ignore commands on services. */
6509 case SCF_ERROR_NOT_BOUND
:
6510 case SCF_ERROR_HANDLE_MISMATCH
:
6511 case SCF_ERROR_NOT_SET
:
6513 bad_error("scf_pg_get_parent_instance",
6518 return (process_actions(h
, pg
, inst
));
6521 if (strcmp(pg_name
, SCF_PG_OPTIONS
) != 0 &&
6522 strcmp(pg_name
, SCF_PG_OPTIONS_OVR
) != 0)
6526 * We only care about the options[_ovr] property groups of our own
6527 * instance, so get the fmri and compare. Plus, once we know it's
6528 * correct, if the repository connection is broken we know exactly what
6529 * property group we were operating on, and can look it up again.
6531 if (scf_pg_get_parent_instance(pg
, inst
) != 0) {
6532 switch (scf_error()) {
6533 case SCF_ERROR_CONNECTION_BROKEN
:
6534 return (ECONNABORTED
);
6536 case SCF_ERROR_DELETED
:
6537 case SCF_ERROR_CONSTRAINT_VIOLATED
:
6540 case SCF_ERROR_HANDLE_MISMATCH
:
6541 case SCF_ERROR_NOT_BOUND
:
6542 case SCF_ERROR_NOT_SET
:
6544 bad_error("scf_pg_get_parent_instance",
6549 switch (r
= libscf_instance_get_fmri(inst
, &fmri
)) {
6554 return (ECONNABORTED
);
6560 bad_error("libscf_instance_get_fmri", r
);
6563 if (strcmp(fmri
, SCF_SERVICE_STARTD
) != 0) {
6564 startd_free(fmri
, max_scf_fmri_size
);
6569 * update the information events flag
6571 if (strcmp(pg_name
, SCF_PG_OPTIONS
) == 0)
6572 info_events_all
= libscf_get_info_events_all(pg
);
6574 prop
= safe_scf_property_create(h
);
6575 val
= safe_scf_value_create(h
);
6577 if (strcmp(pg_name
, SCF_PG_OPTIONS_OVR
) == 0) {
6578 /* See if we need to set the runlevel. */
6582 libscf_handle_rebind(h
);
6585 r
= libscf_lookup_instance(SCF_SERVICE_STARTD
, inst
);
6598 bad_error("libscf_lookup_instance", r
);
6601 if (scf_instance_get_pg(inst
, pg_name
, pg
) != 0) {
6602 switch (scf_error()) {
6603 case SCF_ERROR_DELETED
:
6604 case SCF_ERROR_NOT_FOUND
:
6607 case SCF_ERROR_CONNECTION_BROKEN
:
6610 case SCF_ERROR_HANDLE_MISMATCH
:
6611 case SCF_ERROR_NOT_BOUND
:
6612 case SCF_ERROR_NOT_SET
:
6613 case SCF_ERROR_INVALID_ARGUMENT
:
6615 bad_error("scf_instance_get_pg",
6621 if (scf_pg_get_property(pg
, "runlevel", prop
) == 0) {
6622 r
= dgraph_set_runlevel(pg
, prop
);
6626 rebind_inst
= B_TRUE
;
6639 bad_error("dgraph_set_runlevel", r
);
6642 switch (scf_error()) {
6643 case SCF_ERROR_CONNECTION_BROKEN
:
6647 case SCF_ERROR_DELETED
:
6650 case SCF_ERROR_NOT_FOUND
:
6653 case SCF_ERROR_INVALID_ARGUMENT
:
6654 case SCF_ERROR_HANDLE_MISMATCH
:
6655 case SCF_ERROR_NOT_BOUND
:
6656 case SCF_ERROR_NOT_SET
:
6657 bad_error("scf_pg_get_property", scf_error());
6664 r
= libscf_lookup_instance(SCF_SERVICE_STARTD
, inst
);
6670 libscf_handle_rebind(h
);
6679 bad_error("libscf_lookup_instance", r
);
6683 r
= libscf_get_milestone(inst
, prop
, val
, fmri
, max_scf_fmri_size
);
6689 libscf_handle_rebind(h
);
6694 log_error(LOG_NOTICE
,
6695 "%s/%s property of %s is misconfigured.\n", pg_name
,
6696 SCF_PROPERTY_MILESTONE
, SCF_SERVICE_STARTD
);
6701 (void) strcpy(fmri
, "all");
6705 bad_error("libscf_get_milestone", r
);
6708 r
= dgraph_set_milestone(fmri
, h
, B_FALSE
);
6716 log_error(LOG_WARNING
, "Milestone %s is invalid.\n", fmri
);
6720 log_error(LOG_WARNING
, "Milestone %s does not exist.\n", fmri
);
6724 bad_error("dgraph_set_milestone", r
);
6728 startd_free(fmri
, max_scf_fmri_size
);
6729 scf_value_destroy(val
);
6730 scf_property_destroy(prop
);
6732 return (rebound
? ECONNRESET
: 0);
6736 * process_delete() deletes an instance from the dgraph if 'fmri' is an
6737 * instance fmri or if 'fmri' matches the 'general' property group of an
6738 * instance (or the 'general/enabled' property).
6740 * 'fmri' may be overwritten and cannot be trusted on return by the caller.
6743 process_delete(char *fmri
, scf_handle_t
*h
)
6745 char *lfmri
, *end_inst_fmri
;
6746 const char *inst_name
= NULL
;
6747 const char *pg_name
= NULL
;
6748 const char *prop_name
= NULL
;
6750 lfmri
= safe_strdup(fmri
);
6752 /* Determine if the FMRI is a property group or instance */
6753 if (scf_parse_svc_fmri(lfmri
, NULL
, NULL
, &inst_name
, &pg_name
,
6754 &prop_name
) != SCF_SUCCESS
) {
6755 log_error(LOG_WARNING
,
6756 "Received invalid FMRI \"%s\" from repository server.\n",
6758 } else if (inst_name
!= NULL
&& pg_name
== NULL
) {
6759 (void) dgraph_remove_instance(fmri
, h
);
6760 } else if (inst_name
!= NULL
&& pg_name
!= NULL
) {
6762 * If we're deleting the 'general' property group or
6763 * 'general/enabled' property then the whole instance
6764 * must be removed from the dgraph.
6766 if (strcmp(pg_name
, SCF_PG_GENERAL
) != 0) {
6771 if (prop_name
!= NULL
&&
6772 strcmp(prop_name
, SCF_PROPERTY_ENABLED
) != 0) {
6778 * Because the instance has already been deleted from the
6779 * repository, we cannot use any scf_ functions to retrieve
6780 * the instance FMRI however we can easily reconstruct it
6783 end_inst_fmri
= strstr(fmri
, SCF_FMRI_PROPERTYGRP_PREFIX
);
6784 if (end_inst_fmri
== NULL
)
6785 bad_error("process_delete", 0);
6787 end_inst_fmri
[0] = '\0';
6789 (void) dgraph_remove_instance(fmri
, h
);
6797 repository_event_thread(void *unused
)
6800 scf_propertygroup_t
*pg
;
6801 scf_instance_t
*inst
;
6802 char *fmri
= startd_alloc(max_scf_fmri_size
);
6803 char *pg_name
= startd_alloc(max_scf_value_size
);
6806 (void) pthread_setname_np(pthread_self(), "repository_event");
6808 h
= libscf_handle_create_bound_loop();
6810 pg
= safe_scf_pg_create(h
);
6811 inst
= safe_scf_instance_create(h
);
6814 if (_scf_notify_add_pgtype(h
, SCF_GROUP_FRAMEWORK
) != SCF_SUCCESS
) {
6815 if (scf_error() == SCF_ERROR_CONNECTION_BROKEN
) {
6816 libscf_handle_rebind(h
);
6818 log_error(LOG_WARNING
,
6819 "Couldn't set up repository notification "
6820 "for property group type %s: %s\n",
6821 SCF_GROUP_FRAMEWORK
, scf_strerror(scf_error()));
6833 /* Note: fmri is only set on delete events. */
6834 res
= _scf_notify_wait(pg
, fmri
, max_scf_fmri_size
);
6836 libscf_handle_rebind(h
);
6838 } else if (res
== 0) {
6840 * property group modified. inst and pg_name are
6841 * pre-allocated scratch space.
6843 if (scf_pg_update(pg
) < 0) {
6844 switch (scf_error()) {
6845 case SCF_ERROR_DELETED
:
6848 case SCF_ERROR_CONNECTION_BROKEN
:
6849 log_error(LOG_WARNING
,
6850 "Lost repository event due to "
6851 "disconnection.\n");
6852 libscf_handle_rebind(h
);
6855 case SCF_ERROR_NOT_BOUND
:
6856 case SCF_ERROR_NOT_SET
:
6858 bad_error("scf_pg_update", scf_error());
6862 r
= process_pg_event(h
, pg
, inst
, pg_name
);
6868 log_error(LOG_WARNING
, "Lost repository event "
6869 "due to disconnection.\n");
6870 libscf_handle_rebind(h
);
6877 bad_error("process_pg_event", r
);
6881 * Service, instance, or pg deleted.
6882 * Don't trust fmri on return.
6884 process_delete(fmri
, h
);
6893 graph_engine_start()
6897 (void) startd_thread_create(graph_thread
, NULL
);
6899 MUTEX_LOCK(&dgraph_lock
);
6900 while (!initial_milestone_set
) {
6901 err
= pthread_cond_wait(&initial_milestone_cv
, &dgraph_lock
);
6904 MUTEX_UNLOCK(&dgraph_lock
);
6906 (void) startd_thread_create(repository_event_thread
, NULL
);
6907 (void) startd_thread_create(graph_event_thread
, NULL
);