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 (c) 2015, Syneto S.R.L. All rights reserved.
25 * Copyright 2016 Toomas Soome <tsoome@me.com>
29 * graph.c - master restarter graph engine
31 * The graph engine keeps a dependency graph of all service instances on the
32 * system, as recorded in the repository. It decides when services should
33 * be brought up or down based on service states and dependencies and sends
34 * commands to restarters to effect any changes. It also executes
35 * administrator commands sent by svcadm via the repository.
37 * The graph is stored in uu_list_t *dgraph and its vertices are
38 * graph_vertex_t's, each of which has a name and an integer id unique to
39 * its name (see dict.c). A vertex's type attribute designates the type
40 * of object it represents: GVT_INST for service instances, GVT_SVC for
41 * service objects (since service instances may depend on another service,
42 * rather than service instance), GVT_FILE for files (which services may
43 * depend on), and GVT_GROUP for dependencies on multiple objects. GVT_GROUP
44 * vertices are necessary because dependency lists may have particular
45 * grouping types (require any, require all, optional, or exclude) and
46 * event-propagation characteristics.
48 * The initial graph is built by libscf_populate_graph() invoking
49 * dgraph_add_instance() for each instance in the repository. The function
50 * adds a GVT_SVC vertex for the service if one does not already exist, adds
51 * a GVT_INST vertex named by the FMRI of the instance, and sets up the edges.
52 * The resulting web of vertices & edges associated with an instance's vertex
55 * - an edge from the GVT_SVC vertex for the instance's service
57 * - an edge to the GVT_INST vertex of the instance's resarter, if its
58 * restarter is not svc.startd
60 * - edges from other GVT_INST vertices if the instance is a restarter
62 * - for each dependency property group in the instance's "running"
63 * snapshot, an edge to a GVT_GROUP vertex named by the FMRI of the
64 * instance and the name of the property group
66 * - for each value of the "entities" property in each dependency property
67 * group, an edge from the corresponding GVT_GROUP vertex to a
68 * GVT_INST, GVT_SVC, or GVT_FILE vertex
70 * - edges from GVT_GROUP vertices for each dependent instance
72 * After the edges are set up the vertex's GV_CONFIGURED flag is set. If
73 * there are problems, or if a service is mentioned in a dependency but does
74 * not exist in the repository, the GV_CONFIGURED flag will be clear.
76 * The graph and all of its vertices are protected by the dgraph_lock mutex.
77 * See restarter.c for more information.
79 * The properties of an instance fall into two classes: immediate and
80 * snapshotted. Immediate properties should have an immediate effect when
81 * changed. Snapshotted properties should be read from a snapshot, so they
82 * only change when the snapshot changes. The immediate properties used by
83 * the graph engine are general/enabled, general/restarter, and the properties
84 * in the restarter_actions property group. Since they are immediate, they
85 * are not read out of a snapshot. The snapshotted properties used by the
86 * graph engine are those in the property groups with type "dependency" and
87 * are read out of the "running" snapshot. The "running" snapshot is created
88 * by the the graph engine as soon as possible, and it is updated, along with
89 * in-core copies of the data (dependency information for the graph engine) on
90 * receipt of the refresh command from svcadm. In addition, the graph engine
91 * updates the "start" snapshot from the "running" snapshot whenever a service
94 * When a DISABLE event is requested by the administrator, svc.startd shutdown
95 * the dependents first before shutting down the requested service.
96 * In graph_enable_by_vertex, we create a subtree that contains the dependent
97 * vertices by marking those vertices with the GV_TOOFFLINE flag. And we mark
98 * the vertex to disable with the GV_TODISABLE flag. Once the tree is created,
99 * we send the _ADMIN_DISABLE event to the leaves. The leaves will then
100 * transition from STATE_ONLINE/STATE_DEGRADED to STATE_OFFLINE/STATE_MAINT.
101 * In gt_enter_offline and gt_enter_maint if the vertex was in a subtree then
102 * we clear the GV_TOOFFLINE flag and walk the dependencies to offline the new
103 * exposed leaves. We do the same until we reach the last leaf (the one with
104 * the GV_TODISABLE flag). If the vertex to disable is also part of a larger
105 * subtree (eg. multiple DISABLE events on vertices in the same subtree) then
106 * once the first vertex is disabled (GV_TODISABLE flag is removed), we
107 * continue to propagate the offline event to the vertex's dependencies.
110 * SMF state transition notifications
112 * When an instance of a service managed by SMF changes state, svc.startd may
113 * publish a GPEC sysevent. All transitions to or from maintenance, a
114 * transition cause by a hardware error will generate an event.
115 * Other transitions will generate an event if there exist notification
116 * parameter for that transition. Notification parameters are stored in the
117 * SMF repository for the service/instance they refer to. System-wide
118 * notification parameters are stored in the global instance.
119 * svc.startd can be told to send events for all SMF state transitions despite
120 * of notification parameters by setting options/info_events_all to true in
123 * The set of transitions that generate events is cached in the
124 * dgraph_vertex_t gv_stn_tset for service/instance and in the global
125 * stn_global for the system-wide set. They are re-read when instances are
128 * The GPEC events published by svc.startd are consumed by fmd(1M). After
129 * processing these events, fmd(1M) publishes the processed events to
130 * notification agents. The notification agents read the notification
131 * parameters from the SMF repository through libscf(3LIB) interfaces and send
132 * the notification, or not, based on those parameters.
134 * Subscription and publishing to the GPEC channels is done with the
135 * libfmevent(3LIB) wrappers fmev_[r]publish_*() and
136 * fmev_shdl_(un)subscribe().
140 #include <sys/uadmin.h>
141 #include <sys/wait.h>
146 #include <fm/libfmevent.h>
148 #include <libscf_priv.h>
149 #include <librestart.h>
150 #include <libuutil.h>
160 #include <sys/statvfs.h>
161 #include <sys/uadmin.h>
168 #include "protocol.h"
171 #define MILESTONE_NONE ((graph_vertex_t *)1)
173 #define CONSOLE_LOGIN_FMRI "svc:/system/console-login:default"
174 #define FS_MINIMAL_FMRI "svc:/system/filesystem/minimal:default"
176 #define VERTEX_REMOVED 0 /* vertex has been freed */
177 #define VERTEX_INUSE 1 /* vertex is still in use */
179 #define IS_ENABLED(v) ((v)->gv_flags & (GV_ENABLED | GV_ENBLD_NOOVR))
182 * stn_global holds the tset for the system wide notification parameters.
183 * It is updated on refresh of svc:/system/svc/global:default
185 * There are two assumptions that relax the need for a mutex:
186 * 1. 32-bit value assignments are atomic
187 * 2. Its value is consumed only in one point at
188 * dgraph_state_transition_notify(). There are no test and set races.
190 * If either assumption is broken, we'll need a mutex to synchronize
191 * access to stn_global
195 * info_events_all holds a flag to override notification parameters and send
196 * Information events for all state transitions.
197 * same about the need of a mutex here.
202 * Services in these states are not considered 'down' by the
203 * milestone/shutdown code.
205 #define up_state(state) ((state) == RESTARTER_STATE_ONLINE || \
206 (state) == RESTARTER_STATE_DEGRADED || \
207 (state) == RESTARTER_STATE_OFFLINE)
209 #define is_depgrp_bypassed(v) ((v->gv_type == GVT_GROUP) && \
210 ((v->gv_depgroup == DEPGRP_EXCLUDE_ALL) || \
211 (v->gv_depgroup == DEPGRP_OPTIONAL_ALL) || \
212 (v->gv_restart < RERR_RESTART)))
214 static uu_list_pool_t
*graph_edge_pool
, *graph_vertex_pool
;
215 static uu_list_t
*dgraph
;
216 static pthread_mutex_t dgraph_lock
;
219 * milestone indicates the current subgraph. When NULL, it is the entire
220 * graph. When MILESTONE_NONE, it is the empty graph. Otherwise, it is all
221 * services on which the target vertex depends.
223 static graph_vertex_t
*milestone
= NULL
;
224 static boolean_t initial_milestone_set
= B_FALSE
;
225 static pthread_cond_t initial_milestone_cv
= PTHREAD_COND_INITIALIZER
;
227 /* protected by dgraph_lock */
228 static boolean_t sulogin_thread_running
= B_FALSE
;
229 static boolean_t sulogin_running
= B_FALSE
;
230 static boolean_t console_login_ready
= B_FALSE
;
232 /* Number of services to come down to complete milestone transition. */
233 static uint_t non_subgraph_svcs
;
236 * These variables indicate what should be done when we reach the milestone
237 * target milestone, i.e., when non_subgraph_svcs == 0. They are acted upon in
238 * dgraph_set_instance_state().
240 static int halting
= -1;
241 static boolean_t go_single_user_mode
= B_FALSE
;
242 static boolean_t go_to_level1
= B_FALSE
;
245 * Tracks when we started halting.
247 static time_t halting_time
= 0;
250 * This tracks the legacy runlevel to ensure we signal init and manage
251 * utmpx entries correctly.
253 static char current_runlevel
= '\0';
255 /* Number of single user threads currently running */
256 static pthread_mutex_t single_user_thread_lock
;
257 static int single_user_thread_count
= 0;
259 /* Statistics for dependency cycle-checking */
260 static u_longlong_t dep_inserts
= 0;
261 static u_longlong_t dep_cycle_ns
= 0;
262 static u_longlong_t dep_insert_ns
= 0;
265 static const char * const emsg_invalid_restarter
=
266 "Transitioning %s to maintenance, restarter FMRI %s is invalid "
267 "(see 'svcs -xv' for details).\n";
268 static const char * const console_login_fmri
= CONSOLE_LOGIN_FMRI
;
269 static const char * const single_user_fmri
= SCF_MILESTONE_SINGLE_USER
;
270 static const char * const multi_user_fmri
= SCF_MILESTONE_MULTI_USER
;
271 static const char * const multi_user_svr_fmri
= SCF_MILESTONE_MULTI_USER_SERVER
;
275 * These services define the system being "up". If none of them can come
276 * online, then we will run sulogin on the console. Note that the install ones
277 * are for the miniroot and when installing CDs after the first. can_come_up()
278 * does the decision making, and an sulogin_thread() runs sulogin, which can be
279 * started by dgraph_set_instance_state() or single_user_thread().
281 * NOTE: can_come_up() relies on SCF_MILESTONE_SINGLE_USER being the first
282 * entry, which is only used when booting_to_single_user (boot -s) is set.
283 * This is because when doing a "boot -s", sulogin is started from specials.c
284 * after milestone/single-user comes online, for backwards compatibility.
285 * In this case, SCF_MILESTONE_SINGLE_USER needs to be part of up_svcs
286 * to ensure sulogin will be spawned if milestone/single-user cannot be reached.
288 static const char * const up_svcs
[] = {
289 SCF_MILESTONE_SINGLE_USER
,
291 "svc:/system/install-setup:default",
292 "svc:/system/install:default",
296 /* This array must have an element for each non-NULL element of up_svcs[]. */
297 static graph_vertex_t
*up_svcs_p
[] = { NULL
, NULL
, NULL
, NULL
};
299 /* These are for seed repository magic. See can_come_up(). */
300 static const char * const manifest_import
= SCF_INSTANCE_MI
;
301 static graph_vertex_t
*manifest_import_p
= NULL
;
304 static char target_milestone_as_runlevel(void);
305 static void graph_runlevel_changed(char rl
, int online
);
306 static int dgraph_set_milestone(const char *, scf_handle_t
*, boolean_t
);
307 static boolean_t
should_be_in_subgraph(graph_vertex_t
*v
);
308 static int mark_subtree(graph_edge_t
*, void *);
309 static boolean_t
insubtree_dependents_down(graph_vertex_t
*);
312 * graph_vertex_compare()
313 * This function can compare either int *id or * graph_vertex_t *gv
314 * values, as the vertex id is always the first element of a
315 * graph_vertex structure.
319 graph_vertex_compare(const void *lc_arg
, const void *rc_arg
, void *private)
321 int lc_id
= ((const graph_vertex_t
*)lc_arg
)->gv_id
;
322 int rc_id
= *(int *)rc_arg
;
334 graph_edge_pool
= startd_list_pool_create("graph_edges",
335 sizeof (graph_edge_t
), offsetof(graph_edge_t
, ge_link
), NULL
,
337 assert(graph_edge_pool
!= NULL
);
339 graph_vertex_pool
= startd_list_pool_create("graph_vertices",
340 sizeof (graph_vertex_t
), offsetof(graph_vertex_t
, gv_link
),
341 graph_vertex_compare
, UU_LIST_POOL_DEBUG
);
342 assert(graph_vertex_pool
!= NULL
);
344 (void) pthread_mutex_init(&dgraph_lock
, &mutex_attrs
);
345 (void) pthread_mutex_init(&single_user_thread_lock
, &mutex_attrs
);
346 dgraph
= startd_list_create(graph_vertex_pool
, NULL
, UU_LIST_SORTED
);
347 assert(dgraph
!= NULL
);
350 current_runlevel
= utmpx_get_runlevel();
352 log_framework(LOG_DEBUG
, "Initialized graph\n");
355 static graph_vertex_t
*
356 vertex_get_by_name(const char *name
)
360 assert(MUTEX_HELD(&dgraph_lock
));
362 id
= dict_lookup_byname(name
);
366 return (uu_list_find(dgraph
, &id
, NULL
, NULL
));
369 static graph_vertex_t
*
370 vertex_get_by_id(int id
)
372 assert(MUTEX_HELD(&dgraph_lock
));
377 return (uu_list_find(dgraph
, &id
, NULL
, NULL
));
381 * Creates a new vertex with the given name, adds it to the graph, and returns
382 * a pointer to it. The graph lock must be held by this thread on entry.
384 static graph_vertex_t
*
385 graph_add_vertex(const char *name
)
392 assert(MUTEX_HELD(&dgraph_lock
));
394 id
= dict_insert(name
);
396 v
= startd_zalloc(sizeof (*v
));
400 v
->gv_name
= startd_alloc(strlen(name
) + 1);
401 (void) strcpy(v
->gv_name
, name
);
403 v
->gv_dependencies
= startd_list_create(graph_edge_pool
, v
, 0);
404 v
->gv_dependents
= startd_list_create(graph_edge_pool
, v
, 0);
406 p
= uu_list_find(dgraph
, &id
, NULL
, &idx
);
409 uu_list_node_init(v
, &v
->gv_link
, graph_vertex_pool
);
410 uu_list_insert(dgraph
, v
, idx
);
416 * Removes v from the graph and frees it. The graph should be locked by this
417 * thread, and v should have no edges associated with it.
420 graph_remove_vertex(graph_vertex_t
*v
)
422 assert(MUTEX_HELD(&dgraph_lock
));
424 assert(uu_list_numnodes(v
->gv_dependencies
) == 0);
425 assert(uu_list_numnodes(v
->gv_dependents
) == 0);
426 assert(v
->gv_refs
== 0);
428 startd_free(v
->gv_name
, strlen(v
->gv_name
) + 1);
429 uu_list_destroy(v
->gv_dependencies
);
430 uu_list_destroy(v
->gv_dependents
);
431 uu_list_remove(dgraph
, v
);
433 startd_free(v
, sizeof (graph_vertex_t
));
437 graph_add_edge(graph_vertex_t
*fv
, graph_vertex_t
*tv
)
439 graph_edge_t
*e
, *re
;
442 assert(MUTEX_HELD(&dgraph_lock
));
444 e
= startd_alloc(sizeof (graph_edge_t
));
445 re
= startd_alloc(sizeof (graph_edge_t
));
453 uu_list_node_init(e
, &e
->ge_link
, graph_edge_pool
);
454 r
= uu_list_insert_before(fv
->gv_dependencies
, NULL
, e
);
457 uu_list_node_init(re
, &re
->ge_link
, graph_edge_pool
);
458 r
= uu_list_insert_before(tv
->gv_dependents
, NULL
, re
);
463 graph_remove_edge(graph_vertex_t
*v
, graph_vertex_t
*dv
)
467 for (e
= uu_list_first(v
->gv_dependencies
);
469 e
= uu_list_next(v
->gv_dependencies
, e
)) {
470 if (e
->ge_vertex
== dv
) {
471 uu_list_remove(v
->gv_dependencies
, e
);
472 startd_free(e
, sizeof (graph_edge_t
));
477 for (e
= uu_list_first(dv
->gv_dependents
);
479 e
= uu_list_next(dv
->gv_dependents
, e
)) {
480 if (e
->ge_vertex
== v
) {
481 uu_list_remove(dv
->gv_dependents
, e
);
482 startd_free(e
, sizeof (graph_edge_t
));
489 remove_inst_vertex(graph_vertex_t
*v
)
495 assert(MUTEX_HELD(&dgraph_lock
));
496 assert(uu_list_numnodes(v
->gv_dependents
) == 1);
497 assert(uu_list_numnodes(v
->gv_dependencies
) == 0);
498 assert(v
->gv_refs
== 0);
499 assert((v
->gv_flags
& GV_CONFIGURED
) == 0);
501 e
= uu_list_first(v
->gv_dependents
);
503 graph_remove_edge(sv
, v
);
505 for (i
= 0; up_svcs
[i
] != NULL
; ++i
) {
506 if (up_svcs_p
[i
] == v
)
510 if (manifest_import_p
== v
)
511 manifest_import_p
= NULL
;
513 graph_remove_vertex(v
);
515 if (uu_list_numnodes(sv
->gv_dependencies
) == 0 &&
516 uu_list_numnodes(sv
->gv_dependents
) == 0 &&
518 graph_remove_vertex(sv
);
522 graph_walk_dependents(graph_vertex_t
*v
, void (*func
)(graph_vertex_t
*, void *),
527 for (e
= uu_list_first(v
->gv_dependents
);
529 e
= uu_list_next(v
->gv_dependents
, e
))
530 func(e
->ge_vertex
, arg
);
534 graph_walk_dependencies(graph_vertex_t
*v
,
535 void (*func
)(graph_vertex_t
*, void *), void *arg
)
539 assert(MUTEX_HELD(&dgraph_lock
));
541 for (e
= uu_list_first(v
->gv_dependencies
);
543 e
= uu_list_next(v
->gv_dependencies
, e
)) {
545 func(e
->ge_vertex
, arg
);
550 * Generic graph walking function.
552 * Given a vertex, this function will walk either dependencies
553 * (WALK_DEPENDENCIES) or dependents (WALK_DEPENDENTS) of a vertex recursively
554 * for the entire graph. It will avoid cycles and never visit the same vertex
557 * We avoid traversing exclusion dependencies, because they are allowed to
558 * create cycles in the graph. When propagating satisfiability, there is no
559 * need to walk exclusion dependencies because exclude_all_satisfied() doesn't
560 * test for satisfiability.
562 * The walker takes two callbacks. The first is called before examining the
563 * dependents of each vertex. The second is called on each vertex after
564 * examining its dependents. This allows is_path_to() to construct a path only
565 * after the target vertex has been found.
572 typedef int (*graph_walk_cb_t
)(graph_vertex_t
*, void *);
574 typedef struct graph_walk_info
{
575 graph_walk_dir_t gi_dir
;
576 uchar_t
*gi_visited
; /* vertex bitmap */
577 int (*gi_pre
)(graph_vertex_t
*, void *);
578 void (*gi_post
)(graph_vertex_t
*, void *);
579 void *gi_arg
; /* callback arg */
580 int gi_ret
; /* return value */
584 graph_walk_recurse(graph_edge_t
*e
, graph_walk_info_t
*gip
)
588 graph_vertex_t
*v
= e
->ge_vertex
;
593 b
= 1 << (v
->gv_id
% 8);
596 * Check to see if we've visited this vertex already.
598 if (gip
->gi_visited
[i
] & b
)
599 return (UU_WALK_NEXT
);
601 gip
->gi_visited
[i
] |= b
;
604 * Don't follow exclusions.
606 if (v
->gv_type
== GVT_GROUP
&& v
->gv_depgroup
== DEPGRP_EXCLUDE_ALL
)
607 return (UU_WALK_NEXT
);
610 * Call pre-visit callback. If this doesn't terminate the walk,
613 if ((gip
->gi_ret
= gip
->gi_pre(v
, gip
->gi_arg
)) == UU_WALK_NEXT
) {
615 * Recurse using appropriate list.
617 if (gip
->gi_dir
== WALK_DEPENDENTS
)
618 list
= v
->gv_dependents
;
620 list
= v
->gv_dependencies
;
622 r
= uu_list_walk(list
, (uu_walk_fn_t
*)graph_walk_recurse
,
628 * Callbacks must return either UU_WALK_NEXT or UU_WALK_DONE.
630 assert(gip
->gi_ret
== UU_WALK_NEXT
|| gip
->gi_ret
== UU_WALK_DONE
);
633 * If given a post-callback, call the function for every vertex.
635 if (gip
->gi_post
!= NULL
)
636 (void) gip
->gi_post(v
, gip
->gi_arg
);
639 * Preserve the callback's return value. If the callback returns
640 * UU_WALK_DONE, then we propagate that to the caller in order to
641 * terminate the walk.
643 return (gip
->gi_ret
);
647 graph_walk(graph_vertex_t
*v
, graph_walk_dir_t dir
,
648 int (*pre
)(graph_vertex_t
*, void *),
649 void (*post
)(graph_vertex_t
*, void *), void *arg
)
651 graph_walk_info_t gi
;
653 size_t sz
= dictionary
->dict_new_id
/ 8 + 1;
655 gi
.gi_visited
= startd_zalloc(sz
);
663 * Fake up an edge for the first iteration
666 (void) graph_walk_recurse(&fake
, &gi
);
668 startd_free(gi
.gi_visited
, sz
);
671 typedef struct child_search
{
672 int id
; /* id of vertex to look for */
673 uint_t depth
; /* recursion depth */
675 * While the vertex is not found, path is NULL. After the search, if
676 * the vertex was found then path should point to a -1-terminated
677 * array of vertex id's which constitute the path to the vertex.
683 child_pre(graph_vertex_t
*v
, void *arg
)
685 child_search_t
*cs
= arg
;
689 if (v
->gv_id
== cs
->id
) {
690 cs
->path
= startd_alloc((cs
->depth
+ 1) * sizeof (int));
691 cs
->path
[cs
->depth
] = -1;
692 return (UU_WALK_DONE
);
695 return (UU_WALK_NEXT
);
699 child_post(graph_vertex_t
*v
, void *arg
)
701 child_search_t
*cs
= arg
;
705 if (cs
->path
!= NULL
)
706 cs
->path
[cs
->depth
] = v
->gv_id
;
710 * Look for a path from from to to. If one exists, returns a pointer to
711 * a NULL-terminated array of pointers to the vertices along the path. If
712 * there is no path, returns NULL.
715 is_path_to(graph_vertex_t
*from
, graph_vertex_t
*to
)
723 graph_walk(from
, WALK_DEPENDENCIES
, child_pre
, child_post
, &cs
);
729 * Given an array of int's as returned by is_path_to, allocates a string of
730 * their names joined by newlines. Returns the size of the allocated buffer
731 * in *sz and frees path.
734 path_to_str(int *path
, char **cpp
, size_t *sz
)
738 size_t allocd
, new_allocd
;
741 assert(MUTEX_HELD(&dgraph_lock
));
742 assert(path
[0] != -1);
745 *cpp
= startd_alloc(1);
748 for (i
= 0; path
[i
] != -1; ++i
) {
751 v
= vertex_get_by_id(path
[i
]);
755 else if (v
->gv_type
== GVT_INST
|| v
->gv_type
== GVT_SVC
)
759 new_allocd
= allocd
+ strlen(name
) + 1;
760 new = startd_alloc(new_allocd
);
761 (void) strcpy(new, *cpp
);
762 (void) strcat(new, name
);
763 (void) strcat(new, "\n");
765 startd_free(*cpp
, allocd
);
772 startd_free(path
, sizeof (int) * (i
+ 1));
779 * This function along with run_sulogin() implements an exclusion relationship
780 * between system/console-login and sulogin. run_sulogin() will fail if
781 * system/console-login is online, and the graph engine should call
782 * graph_clogin_start() to bring system/console-login online, which defers the
783 * start if sulogin is running.
786 graph_clogin_start(graph_vertex_t
*v
)
788 assert(MUTEX_HELD(&dgraph_lock
));
791 console_login_ready
= B_TRUE
;
793 vertex_send_event(v
, RESTARTER_EVENT_TYPE_START
);
797 graph_su_start(graph_vertex_t
*v
)
800 * /etc/inittab used to have the initial /sbin/rcS as a 'sysinit'
801 * entry with a runlevel of 'S', before jumping to the final
802 * target runlevel (as set in initdefault). We mimic that legacy
805 utmpx_set_runlevel('S', '0', B_FALSE
);
806 vertex_send_event(v
, RESTARTER_EVENT_TYPE_START
);
810 graph_post_su_online(void)
812 graph_runlevel_changed('S', 1);
816 graph_post_su_disable(void)
818 graph_runlevel_changed('S', 0);
822 graph_post_mu_online(void)
824 graph_runlevel_changed('2', 1);
828 graph_post_mu_disable(void)
830 graph_runlevel_changed('2', 0);
834 graph_post_mus_online(void)
836 graph_runlevel_changed('3', 1);
840 graph_post_mus_disable(void)
842 graph_runlevel_changed('3', 0);
845 static struct special_vertex_info
{
847 void (*start_f
)(graph_vertex_t
*);
848 void (*post_online_f
)(void);
849 void (*post_disable_f
)(void);
850 } special_vertices
[] = {
851 { CONSOLE_LOGIN_FMRI
, graph_clogin_start
, NULL
, NULL
},
852 { SCF_MILESTONE_SINGLE_USER
, graph_su_start
,
853 graph_post_su_online
, graph_post_su_disable
},
854 { SCF_MILESTONE_MULTI_USER
, NULL
,
855 graph_post_mu_online
, graph_post_mu_disable
},
856 { SCF_MILESTONE_MULTI_USER_SERVER
, NULL
,
857 graph_post_mus_online
, graph_post_mus_disable
},
863 vertex_send_event(graph_vertex_t
*v
, restarter_event_type_t e
)
866 case RESTARTER_EVENT_TYPE_ADD_INSTANCE
:
867 assert(v
->gv_state
== RESTARTER_STATE_UNINIT
);
869 MUTEX_LOCK(&st
->st_load_lock
);
870 st
->st_load_instances
++;
871 MUTEX_UNLOCK(&st
->st_load_lock
);
874 case RESTARTER_EVENT_TYPE_ENABLE
:
875 log_framework(LOG_DEBUG
, "Enabling %s.\n", v
->gv_name
);
876 assert(v
->gv_state
== RESTARTER_STATE_UNINIT
||
877 v
->gv_state
== RESTARTER_STATE_DISABLED
||
878 v
->gv_state
== RESTARTER_STATE_MAINT
);
881 case RESTARTER_EVENT_TYPE_DISABLE
:
882 case RESTARTER_EVENT_TYPE_ADMIN_DISABLE
:
883 log_framework(LOG_DEBUG
, "Disabling %s.\n", v
->gv_name
);
884 assert(v
->gv_state
!= RESTARTER_STATE_DISABLED
);
887 case RESTARTER_EVENT_TYPE_STOP_RESET
:
888 case RESTARTER_EVENT_TYPE_STOP
:
889 log_framework(LOG_DEBUG
, "Stopping %s.\n", v
->gv_name
);
890 assert(v
->gv_state
== RESTARTER_STATE_DEGRADED
||
891 v
->gv_state
== RESTARTER_STATE_ONLINE
);
894 case RESTARTER_EVENT_TYPE_START
:
895 log_framework(LOG_DEBUG
, "Starting %s.\n", v
->gv_name
);
896 assert(v
->gv_state
== RESTARTER_STATE_OFFLINE
);
899 case RESTARTER_EVENT_TYPE_REMOVE_INSTANCE
:
900 case RESTARTER_EVENT_TYPE_ADMIN_DEGRADED
:
901 case RESTARTER_EVENT_TYPE_ADMIN_REFRESH
:
902 case RESTARTER_EVENT_TYPE_ADMIN_RESTART
:
903 case RESTARTER_EVENT_TYPE_ADMIN_MAINT_OFF
:
904 case RESTARTER_EVENT_TYPE_ADMIN_MAINT_ON
:
905 case RESTARTER_EVENT_TYPE_ADMIN_MAINT_ON_IMMEDIATE
:
906 case RESTARTER_EVENT_TYPE_DEPENDENCY_CYCLE
:
907 case RESTARTER_EVENT_TYPE_INVALID_DEPENDENCY
:
912 uu_warn("%s:%d: Bad event %d.\n", __FILE__
, __LINE__
, e
);
917 restarter_protocol_send_event(v
->gv_name
, v
->gv_restarter_channel
, e
,
922 graph_unset_restarter(graph_vertex_t
*v
)
924 assert(MUTEX_HELD(&dgraph_lock
));
925 assert(v
->gv_flags
& GV_CONFIGURED
);
927 vertex_send_event(v
, RESTARTER_EVENT_TYPE_REMOVE_INSTANCE
);
929 if (v
->gv_restarter_id
!= -1) {
932 rv
= vertex_get_by_id(v
->gv_restarter_id
);
933 graph_remove_edge(v
, rv
);
936 v
->gv_restarter_id
= -1;
937 v
->gv_restarter_channel
= NULL
;
941 * Return VERTEX_REMOVED when the vertex passed in argument is deleted from the
942 * dgraph otherwise return VERTEX_INUSE.
945 free_if_unrefed(graph_vertex_t
*v
)
947 assert(MUTEX_HELD(&dgraph_lock
));
950 return (VERTEX_INUSE
);
952 if (v
->gv_type
== GVT_SVC
&&
953 uu_list_numnodes(v
->gv_dependents
) == 0 &&
954 uu_list_numnodes(v
->gv_dependencies
) == 0) {
955 graph_remove_vertex(v
);
956 return (VERTEX_REMOVED
);
957 } else if (v
->gv_type
== GVT_INST
&&
958 (v
->gv_flags
& GV_CONFIGURED
) == 0 &&
959 uu_list_numnodes(v
->gv_dependents
) == 1 &&
960 uu_list_numnodes(v
->gv_dependencies
) == 0) {
961 remove_inst_vertex(v
);
962 return (VERTEX_REMOVED
);
965 return (VERTEX_INUSE
);
969 delete_depgroup(graph_vertex_t
*v
)
974 assert(MUTEX_HELD(&dgraph_lock
));
975 assert(v
->gv_type
== GVT_GROUP
);
976 assert(uu_list_numnodes(v
->gv_dependents
) == 0);
978 while ((e
= uu_list_first(v
->gv_dependencies
)) != NULL
) {
981 graph_remove_edge(v
, dv
);
983 switch (dv
->gv_type
) {
984 case GVT_INST
: /* instance dependency */
985 case GVT_SVC
: /* service dependency */
986 (void) free_if_unrefed(dv
);
989 case GVT_FILE
: /* file dependency */
990 assert(uu_list_numnodes(dv
->gv_dependencies
) == 0);
991 if (uu_list_numnodes(dv
->gv_dependents
) == 0)
992 graph_remove_vertex(dv
);
997 uu_warn("%s:%d: Unexpected node type %d", __FILE__
,
998 __LINE__
, dv
->gv_type
);
1004 graph_remove_vertex(v
);
1008 delete_instance_deps_cb(graph_edge_t
*e
, void **ptrs
)
1010 graph_vertex_t
*v
= ptrs
[0];
1011 boolean_t delete_restarter_dep
= (boolean_t
)ptrs
[1];
1017 * We have four possibilities here:
1018 * - GVT_INST: restarter
1019 * - GVT_GROUP - GVT_INST: instance dependency
1020 * - GVT_GROUP - GVT_SVC - GV_INST: service dependency
1021 * - GVT_GROUP - GVT_FILE: file dependency
1023 switch (dv
->gv_type
) {
1024 case GVT_INST
: /* restarter */
1025 assert(dv
->gv_id
== v
->gv_restarter_id
);
1026 if (delete_restarter_dep
)
1027 graph_remove_edge(v
, dv
);
1030 case GVT_GROUP
: /* pg dependency */
1031 graph_remove_edge(v
, dv
);
1032 delete_depgroup(dv
);
1036 /* These are currently not direct dependencies */
1040 uu_warn("%s:%d: Bad vertex type %d.\n", __FILE__
, __LINE__
,
1046 return (UU_WALK_NEXT
);
1050 delete_instance_dependencies(graph_vertex_t
*v
, boolean_t delete_restarter_dep
)
1055 assert(MUTEX_HELD(&dgraph_lock
));
1056 assert(v
->gv_type
== GVT_INST
);
1059 ptrs
[1] = (void *)delete_restarter_dep
;
1061 r
= uu_list_walk(v
->gv_dependencies
,
1062 (uu_walk_fn_t
*)delete_instance_deps_cb
, &ptrs
, UU_WALK_ROBUST
);
1067 * int graph_insert_vertex_unconfigured()
1068 * Insert a vertex without sending any restarter events. If the vertex
1069 * already exists or creation is successful, return a pointer to it in *vp.
1071 * If type is not GVT_GROUP, dt can remain unset.
1073 * Returns 0, EEXIST, or EINVAL if the arguments are invalid (i.e., fmri
1074 * doesn't agree with type, or type doesn't agree with dt).
1077 graph_insert_vertex_unconfigured(const char *fmri
, gv_type_t type
,
1078 depgroup_type_t dt
, restarter_error_t rt
, graph_vertex_t
**vp
)
1083 assert(MUTEX_HELD(&dgraph_lock
));
1088 if (strncmp(fmri
, "svc:", sizeof ("svc:") - 1) != 0)
1093 if (strncmp(fmri
, "file:", sizeof ("file:") - 1) != 0)
1098 if (dt
<= 0 || rt
< 0)
1104 uu_warn("%s:%d: Unknown type %d.\n", __FILE__
, __LINE__
, type
);
1109 *vp
= vertex_get_by_name(fmri
);
1113 *vp
= graph_add_vertex(fmri
);
1115 (*vp
)->gv_type
= type
;
1116 (*vp
)->gv_depgroup
= dt
;
1117 (*vp
)->gv_restart
= rt
;
1119 (*vp
)->gv_flags
= 0;
1120 (*vp
)->gv_state
= RESTARTER_STATE_NONE
;
1122 for (i
= 0; special_vertices
[i
].name
!= NULL
; ++i
) {
1123 if (strcmp(fmri
, special_vertices
[i
].name
) == 0) {
1124 (*vp
)->gv_start_f
= special_vertices
[i
].start_f
;
1125 (*vp
)->gv_post_online_f
=
1126 special_vertices
[i
].post_online_f
;
1127 (*vp
)->gv_post_disable_f
=
1128 special_vertices
[i
].post_disable_f
;
1133 (*vp
)->gv_restarter_id
= -1;
1134 (*vp
)->gv_restarter_channel
= 0;
1136 if (type
== GVT_INST
) {
1140 sfmri
= inst_fmri_to_svc_fmri(fmri
);
1141 sv
= vertex_get_by_name(sfmri
);
1143 r
= graph_insert_vertex_unconfigured(sfmri
, GVT_SVC
, 0,
1147 startd_free(sfmri
, max_scf_fmri_size
);
1149 graph_add_edge(sv
, *vp
);
1153 * If this vertex is in the subgraph, mark it as so, for both
1154 * GVT_INST and GVT_SERVICE verteces.
1155 * A GVT_SERVICE vertex can only be in the subgraph if another instance
1156 * depends on it, in which case it's already been added to the graph
1157 * and marked as in the subgraph (by refresh_vertex()). If a
1158 * GVT_SERVICE vertex was freshly added (by the code above), it means
1159 * that it has no dependents, and cannot be in the subgraph.
1160 * Regardless of this, we still check that gv_flags includes
1161 * GV_INSUBGRAPH in the event that future behavior causes the above
1162 * code to add a GVT_SERVICE vertex which should be in the subgraph.
1165 (*vp
)->gv_flags
|= (should_be_in_subgraph(*vp
)? GV_INSUBGRAPH
: 0);
1171 * Returns 0 on success or ELOOP if the dependency would create a cycle.
1174 graph_insert_dependency(graph_vertex_t
*fv
, graph_vertex_t
*tv
, int **pathp
)
1178 assert(MUTEX_HELD(&dgraph_lock
));
1180 /* cycle detection */
1183 /* Don't follow exclusions. */
1184 if (!(fv
->gv_type
== GVT_GROUP
&&
1185 fv
->gv_depgroup
== DEPGRP_EXCLUDE_ALL
)) {
1186 *pathp
= is_path_to(tv
, fv
);
1191 dep_cycle_ns
+= gethrtime() - now
;
1195 graph_add_edge(fv
, tv
);
1197 dep_insert_ns
+= gethrtime() - now
;
1199 /* Check if the dependency adds the "to" vertex to the subgraph */
1200 tv
->gv_flags
|= (should_be_in_subgraph(tv
) ? GV_INSUBGRAPH
: 0);
1206 inst_running(graph_vertex_t
*v
)
1208 assert(v
->gv_type
== GVT_INST
);
1210 if (v
->gv_state
== RESTARTER_STATE_ONLINE
||
1211 v
->gv_state
== RESTARTER_STATE_DEGRADED
)
1218 * The dependency evaluation functions return
1219 * 1 - dependency satisfied
1220 * 0 - dependency unsatisfied
1221 * -1 - dependency unsatisfiable (without administrator intervention)
1223 * The functions also take a boolean satbility argument. When true, the
1224 * functions may recurse in order to determine satisfiability.
1226 static int require_any_satisfied(graph_vertex_t
*, boolean_t
);
1227 static int dependency_satisfied(graph_vertex_t
*, boolean_t
);
1230 * A require_all dependency is unsatisfied if any elements are unsatisfied. It
1231 * is unsatisfiable if any elements are unsatisfiable.
1234 require_all_satisfied(graph_vertex_t
*groupv
, boolean_t satbility
)
1238 boolean_t any_unsatisfied
;
1240 if (uu_list_numnodes(groupv
->gv_dependencies
) == 0)
1243 any_unsatisfied
= B_FALSE
;
1245 for (edge
= uu_list_first(groupv
->gv_dependencies
);
1247 edge
= uu_list_next(groupv
->gv_dependencies
, edge
)) {
1248 i
= dependency_satisfied(edge
->ge_vertex
, satbility
);
1252 log_framework2(LOG_DEBUG
, DEBUG_DEPENDENCIES
,
1253 "require_all(%s): %s is unsatisfi%s.\n", groupv
->gv_name
,
1254 edge
->ge_vertex
->gv_name
, i
== 0 ? "ed" : "able");
1262 any_unsatisfied
= B_TRUE
;
1265 return (any_unsatisfied
? 0 : 1);
1269 * A require_any dependency is satisfied if any element is satisfied. It is
1270 * satisfiable if any element is satisfiable.
1273 require_any_satisfied(graph_vertex_t
*groupv
, boolean_t satbility
)
1277 boolean_t satisfiable
;
1279 if (uu_list_numnodes(groupv
->gv_dependencies
) == 0)
1282 satisfiable
= B_FALSE
;
1284 for (edge
= uu_list_first(groupv
->gv_dependencies
);
1286 edge
= uu_list_next(groupv
->gv_dependencies
, edge
)) {
1287 s
= dependency_satisfied(edge
->ge_vertex
, satbility
);
1292 log_framework2(LOG_DEBUG
, DEBUG_DEPENDENCIES
,
1293 "require_any(%s): %s is unsatisfi%s.\n",
1294 groupv
->gv_name
, edge
->ge_vertex
->gv_name
,
1295 s
== 0 ? "ed" : "able");
1297 if (satbility
&& s
== 0)
1298 satisfiable
= B_TRUE
;
1301 return (!satbility
|| satisfiable
? 0 : -1);
1305 * An optional_all dependency only considers elements which are configured,
1306 * enabled, and not in maintenance. If any are unsatisfied, then the dependency
1309 * Offline dependencies which are waiting for a dependency to come online are
1310 * unsatisfied. Offline dependences which cannot possibly come online
1311 * (unsatisfiable) are always considered satisfied.
1314 optional_all_satisfied(graph_vertex_t
*groupv
, boolean_t satbility
)
1318 boolean_t any_qualified
;
1319 boolean_t any_unsatisfied
;
1322 any_qualified
= B_FALSE
;
1323 any_unsatisfied
= B_FALSE
;
1325 for (edge
= uu_list_first(groupv
->gv_dependencies
);
1327 edge
= uu_list_next(groupv
->gv_dependencies
, edge
)) {
1328 v
= edge
->ge_vertex
;
1330 switch (v
->gv_type
) {
1332 /* Skip missing or disabled instances */
1333 if ((v
->gv_flags
& (GV_CONFIGURED
| GV_ENABLED
)) !=
1334 (GV_CONFIGURED
| GV_ENABLED
))
1337 if (v
->gv_state
== RESTARTER_STATE_MAINT
)
1340 if (v
->gv_flags
& GV_TOOFFLINE
)
1343 any_qualified
= B_TRUE
;
1344 if (v
->gv_state
== RESTARTER_STATE_OFFLINE
) {
1346 * For offline dependencies, treat unsatisfiable
1349 i
= dependency_satisfied(v
, B_TRUE
);
1352 } else if (v
->gv_state
== RESTARTER_STATE_DISABLED
) {
1354 * The service is enabled, but hasn't
1355 * transitioned out of disabled yet. Treat it
1356 * as unsatisfied (not unsatisfiable).
1360 i
= dependency_satisfied(v
, satbility
);
1365 any_qualified
= B_TRUE
;
1366 i
= dependency_satisfied(v
, satbility
);
1371 boolean_t svc_any_qualified
;
1372 boolean_t svc_satisfied
;
1373 boolean_t svc_satisfiable
;
1377 svc_any_qualified
= B_FALSE
;
1378 svc_satisfied
= B_FALSE
;
1379 svc_satisfiable
= B_FALSE
;
1381 for (e2
= uu_list_first(v
->gv_dependencies
);
1383 e2
= uu_list_next(v
->gv_dependencies
, e2
)) {
1385 assert(v2
->gv_type
== GVT_INST
);
1388 (GV_CONFIGURED
| GV_ENABLED
)) !=
1389 (GV_CONFIGURED
| GV_ENABLED
))
1392 if (v2
->gv_state
== RESTARTER_STATE_MAINT
)
1395 if (v2
->gv_flags
& GV_TOOFFLINE
)
1398 svc_any_qualified
= B_TRUE
;
1400 if (v2
->gv_state
== RESTARTER_STATE_OFFLINE
) {
1402 * For offline dependencies, treat
1403 * unsatisfiable as satisfied.
1405 i
= dependency_satisfied(v2
, B_TRUE
);
1408 } else if (v2
->gv_state
==
1409 RESTARTER_STATE_DISABLED
) {
1412 i
= dependency_satisfied(v2
, satbility
);
1416 svc_satisfied
= B_TRUE
;
1420 svc_satisfiable
= B_TRUE
;
1423 if (!svc_any_qualified
)
1425 any_qualified
= B_TRUE
;
1426 if (svc_satisfied
) {
1428 } else if (svc_satisfiable
) {
1439 uu_warn("%s:%d: Unexpected vertex type %d.\n", __FILE__
,
1440 __LINE__
, v
->gv_type
);
1448 log_framework2(LOG_DEBUG
, DEBUG_DEPENDENCIES
,
1449 "optional_all(%s): %s is unsatisfi%s.\n", groupv
->gv_name
,
1450 v
->gv_name
, i
== 0 ? "ed" : "able");
1456 any_unsatisfied
= B_TRUE
;
1462 return (any_unsatisfied
? 0 : 1);
1466 * An exclude_all dependency is unsatisfied if any non-service element is
1467 * satisfied or any service instance which is configured, enabled, and not in
1468 * maintenance is satisfied. Usually when unsatisfied, it is also
1471 #define LOG_EXCLUDE(u, v) \
1472 log_framework2(LOG_DEBUG, DEBUG_DEPENDENCIES, \
1473 "exclude_all(%s): %s is satisfied.\n", \
1474 (u)->gv_name, (v)->gv_name)
1478 exclude_all_satisfied(graph_vertex_t
*groupv
, boolean_t satbility
)
1480 graph_edge_t
*edge
, *e2
;
1481 graph_vertex_t
*v
, *v2
;
1483 for (edge
= uu_list_first(groupv
->gv_dependencies
);
1485 edge
= uu_list_next(groupv
->gv_dependencies
, edge
)) {
1486 v
= edge
->ge_vertex
;
1488 switch (v
->gv_type
) {
1490 if ((v
->gv_flags
& GV_CONFIGURED
) == 0)
1493 switch (v
->gv_state
) {
1494 case RESTARTER_STATE_ONLINE
:
1495 case RESTARTER_STATE_DEGRADED
:
1496 LOG_EXCLUDE(groupv
, v
);
1497 return (v
->gv_flags
& GV_ENABLED
? -1 : 0);
1499 case RESTARTER_STATE_OFFLINE
:
1500 case RESTARTER_STATE_UNINIT
:
1501 LOG_EXCLUDE(groupv
, v
);
1504 case RESTARTER_STATE_DISABLED
:
1505 case RESTARTER_STATE_MAINT
:
1510 uu_warn("%s:%d: Unexpected vertex state %d.\n",
1511 __FILE__
, __LINE__
, v
->gv_state
);
1523 LOG_EXCLUDE(groupv
, v
);
1529 uu_warn("%s:%d: Unexpected vertex type %d.\n", __FILE__
,
1530 __LINE__
, v
->gv_type
);
1535 /* v represents a service */
1536 if (uu_list_numnodes(v
->gv_dependencies
) == 0)
1539 for (e2
= uu_list_first(v
->gv_dependencies
);
1541 e2
= uu_list_next(v
->gv_dependencies
, e2
)) {
1543 assert(v2
->gv_type
== GVT_INST
);
1545 if ((v2
->gv_flags
& GV_CONFIGURED
) == 0)
1548 switch (v2
->gv_state
) {
1549 case RESTARTER_STATE_ONLINE
:
1550 case RESTARTER_STATE_DEGRADED
:
1551 LOG_EXCLUDE(groupv
, v2
);
1552 return (v2
->gv_flags
& GV_ENABLED
? -1 : 0);
1554 case RESTARTER_STATE_OFFLINE
:
1555 case RESTARTER_STATE_UNINIT
:
1556 LOG_EXCLUDE(groupv
, v2
);
1559 case RESTARTER_STATE_DISABLED
:
1560 case RESTARTER_STATE_MAINT
:
1565 uu_warn("%s:%d: Unexpected vertex type %d.\n",
1566 __FILE__
, __LINE__
, v2
->gv_type
);
1577 * int instance_satisfied()
1578 * Determine if all the dependencies are satisfied for the supplied instance
1579 * vertex. Return 1 if they are, 0 if they aren't, and -1 if they won't be
1580 * without administrator intervention.
1583 instance_satisfied(graph_vertex_t
*v
, boolean_t satbility
)
1585 assert(v
->gv_type
== GVT_INST
);
1586 assert(!inst_running(v
));
1588 return (require_all_satisfied(v
, satbility
));
1592 * Decide whether v can satisfy a dependency. v can either be a child of
1593 * a group vertex, or of an instance vertex.
1596 dependency_satisfied(graph_vertex_t
*v
, boolean_t satbility
)
1598 switch (v
->gv_type
) {
1600 if ((v
->gv_flags
& GV_CONFIGURED
) == 0) {
1601 if (v
->gv_flags
& GV_DEATHROW
) {
1603 * A dependency on an instance with GV_DEATHROW
1604 * flag is always considered as satisfied.
1612 * Any vertex with the GV_TOOFFLINE flag set is guaranteed
1613 * to have its dependencies unsatisfiable.
1615 if (v
->gv_flags
& GV_TOOFFLINE
)
1618 switch (v
->gv_state
) {
1619 case RESTARTER_STATE_ONLINE
:
1620 case RESTARTER_STATE_DEGRADED
:
1623 case RESTARTER_STATE_OFFLINE
:
1626 return (instance_satisfied(v
, satbility
) != -1 ?
1629 case RESTARTER_STATE_DISABLED
:
1630 case RESTARTER_STATE_MAINT
:
1633 case RESTARTER_STATE_UNINIT
:
1638 uu_warn("%s:%d: Unexpected vertex state %d.\n",
1639 __FILE__
, __LINE__
, v
->gv_state
);
1646 if (uu_list_numnodes(v
->gv_dependencies
) == 0)
1648 return (require_any_satisfied(v
, satbility
));
1651 /* i.e., we assume files will not be automatically generated */
1652 return (file_ready(v
) ? 1 : -1);
1659 uu_warn("%s:%d: Unexpected node type %d.\n", __FILE__
, __LINE__
,
1666 switch (v
->gv_depgroup
) {
1667 case DEPGRP_REQUIRE_ANY
:
1668 return (require_any_satisfied(v
, satbility
));
1670 case DEPGRP_REQUIRE_ALL
:
1671 return (require_all_satisfied(v
, satbility
));
1673 case DEPGRP_OPTIONAL_ALL
:
1674 return (optional_all_satisfied(v
, satbility
));
1676 case DEPGRP_EXCLUDE_ALL
:
1677 return (exclude_all_satisfied(v
, satbility
));
1681 uu_warn("%s:%d: Unknown dependency grouping %d.\n", __FILE__
,
1682 __LINE__
, v
->gv_depgroup
);
1689 graph_start_if_satisfied(graph_vertex_t
*v
)
1691 if (v
->gv_state
== RESTARTER_STATE_OFFLINE
&&
1692 instance_satisfied(v
, B_FALSE
) == 1) {
1693 if (v
->gv_start_f
== NULL
)
1694 vertex_send_event(v
, RESTARTER_EVENT_TYPE_START
);
1701 * propagate_satbility()
1703 * This function is used when the given vertex changes state in such a way that
1704 * one of its dependents may become unsatisfiable. This happens when an
1705 * instance transitions between offline -> online, or from !running ->
1706 * maintenance, as well as when an instance is removed from the graph.
1708 * We have to walk all the dependents, since optional_all dependencies several
1709 * levels up could become (un)satisfied, instead of unsatisfiable. For example,
1711 * +-----+ optional_all +-----+ require_all +-----+
1712 * | A |--------------->| B |-------------->| C |
1713 * +-----+ +-----+ +-----+
1715 * offline -> maintenance
1717 * If C goes into maintenance, it's not enough simply to check B. Because A has
1718 * an optional dependency, what was previously an unsatisfiable situation is now
1719 * satisfied (B will never come online, even though its state hasn't changed).
1721 * Note that it's not necessary to continue examining dependents after reaching
1722 * an optional_all dependency. It's not possible for an optional_all dependency
1723 * to change satisfiability without also coming online, in which case we get a
1724 * start event and propagation continues naturally. However, it does no harm to
1725 * continue propagating satisfiability (as it is a relatively rare event), and
1726 * keeps the walker code simple and generic.
1730 satbility_cb(graph_vertex_t
*v
, void *arg
)
1732 if (v
->gv_type
== GVT_INST
)
1733 graph_start_if_satisfied(v
);
1735 return (UU_WALK_NEXT
);
1739 propagate_satbility(graph_vertex_t
*v
)
1741 graph_walk(v
, WALK_DEPENDENTS
, satbility_cb
, NULL
, NULL
);
1744 static void propagate_stop(graph_vertex_t
*, void *);
1748 propagate_start(graph_vertex_t
*v
, void *arg
)
1750 switch (v
->gv_type
) {
1752 graph_start_if_satisfied(v
);
1756 if (v
->gv_depgroup
== DEPGRP_EXCLUDE_ALL
) {
1757 graph_walk_dependents(v
, propagate_stop
,
1758 (void *)RERR_RESTART
);
1764 graph_walk_dependents(v
, propagate_start
, NULL
);
1769 uu_warn("%s:%d: propagate_start() encountered GVT_FILE.\n",
1770 __FILE__
, __LINE__
);
1777 uu_warn("%s:%d: Unknown vertex type %d.\n", __FILE__
, __LINE__
,
1785 propagate_stop(graph_vertex_t
*v
, void *arg
)
1788 graph_vertex_t
*svc
;
1789 restarter_error_t err
= (restarter_error_t
)arg
;
1791 switch (v
->gv_type
) {
1794 if (err
> RERR_NONE
&& inst_running(v
)) {
1795 if (err
== RERR_RESTART
|| err
== RERR_REFRESH
) {
1796 vertex_send_event(v
,
1797 RESTARTER_EVENT_TYPE_STOP_RESET
);
1799 vertex_send_event(v
, RESTARTER_EVENT_TYPE_STOP
);
1805 graph_walk_dependents(v
, propagate_stop
, arg
);
1810 uu_warn("%s:%d: propagate_stop() encountered GVT_FILE.\n",
1811 __FILE__
, __LINE__
);
1817 if (v
->gv_depgroup
== DEPGRP_EXCLUDE_ALL
) {
1818 graph_walk_dependents(v
, propagate_start
, NULL
);
1822 if (err
== RERR_NONE
|| err
> v
->gv_restart
)
1825 assert(uu_list_numnodes(v
->gv_dependents
) == 1);
1826 e
= uu_list_first(v
->gv_dependents
);
1829 if (inst_running(svc
)) {
1830 if (err
== RERR_RESTART
|| err
== RERR_REFRESH
) {
1831 vertex_send_event(svc
,
1832 RESTARTER_EVENT_TYPE_STOP_RESET
);
1834 vertex_send_event(svc
,
1835 RESTARTER_EVENT_TYPE_STOP
);
1842 uu_warn("%s:%d: Unknown vertex type %d.\n", __FILE__
, __LINE__
,
1850 offline_vertex(graph_vertex_t
*v
)
1852 scf_handle_t
*h
= libscf_handle_create_bound_loop();
1853 scf_instance_t
*scf_inst
= safe_scf_instance_create(h
);
1854 scf_propertygroup_t
*pg
= safe_scf_pg_create(h
);
1855 restarter_instance_state_t state
, next_state
;
1858 assert(v
->gv_type
== GVT_INST
);
1860 if (scf_inst
== NULL
)
1861 bad_error("safe_scf_instance_create", scf_error());
1863 bad_error("safe_scf_pg_create", scf_error());
1865 /* if the vertex is already going offline, return */
1867 if (scf_handle_decode_fmri(h
, v
->gv_name
, NULL
, NULL
, scf_inst
, NULL
,
1868 NULL
, SCF_DECODE_FMRI_EXACT
) != 0) {
1869 switch (scf_error()) {
1870 case SCF_ERROR_CONNECTION_BROKEN
:
1871 libscf_handle_rebind(h
);
1874 case SCF_ERROR_NOT_FOUND
:
1876 scf_instance_destroy(scf_inst
);
1877 (void) scf_handle_unbind(h
);
1878 scf_handle_destroy(h
);
1881 uu_die("Can't decode FMRI %s: %s\n", v
->gv_name
,
1882 scf_strerror(scf_error()));
1885 r
= scf_instance_get_pg(scf_inst
, SCF_PG_RESTARTER
, pg
);
1887 switch (scf_error()) {
1888 case SCF_ERROR_CONNECTION_BROKEN
:
1889 libscf_handle_rebind(h
);
1892 case SCF_ERROR_NOT_SET
:
1893 case SCF_ERROR_NOT_FOUND
:
1895 scf_instance_destroy(scf_inst
);
1896 (void) scf_handle_unbind(h
);
1897 scf_handle_destroy(h
);
1901 bad_error("scf_instance_get_pg", scf_error());
1904 r
= libscf_read_states(pg
, &state
, &next_state
);
1905 if (r
== 0 && (next_state
== RESTARTER_STATE_OFFLINE
||
1906 next_state
== RESTARTER_STATE_DISABLED
)) {
1907 log_framework(LOG_DEBUG
,
1908 "%s: instance is already going down.\n",
1911 scf_instance_destroy(scf_inst
);
1912 (void) scf_handle_unbind(h
);
1913 scf_handle_destroy(h
);
1919 scf_instance_destroy(scf_inst
);
1920 (void) scf_handle_unbind(h
);
1921 scf_handle_destroy(h
);
1923 vertex_send_event(v
, RESTARTER_EVENT_TYPE_STOP_RESET
);
1927 * void graph_enable_by_vertex()
1928 * If admin is non-zero, this is an administrative request for change
1929 * of the enabled property. Thus, send the ADMIN_DISABLE rather than
1930 * a plain DISABLE restarter event.
1933 graph_enable_by_vertex(graph_vertex_t
*vertex
, int enable
, int admin
)
1938 assert(MUTEX_HELD(&dgraph_lock
));
1939 assert((vertex
->gv_flags
& GV_CONFIGURED
));
1941 vertex
->gv_flags
= (vertex
->gv_flags
& ~GV_ENABLED
) |
1942 (enable
? GV_ENABLED
: 0);
1945 if (vertex
->gv_state
!= RESTARTER_STATE_OFFLINE
&&
1946 vertex
->gv_state
!= RESTARTER_STATE_DEGRADED
&&
1947 vertex
->gv_state
!= RESTARTER_STATE_ONLINE
) {
1949 * In case the vertex was notified to go down,
1950 * but now can return online, clear the _TOOFFLINE
1951 * and _TODISABLE flags.
1953 vertex
->gv_flags
&= ~GV_TOOFFLINE
;
1954 vertex
->gv_flags
&= ~GV_TODISABLE
;
1956 vertex_send_event(vertex
, RESTARTER_EVENT_TYPE_ENABLE
);
1960 * Wait for state update from restarter before sending _START or
1967 if (vertex
->gv_state
== RESTARTER_STATE_DISABLED
)
1971 vertex_send_event(vertex
, RESTARTER_EVENT_TYPE_DISABLE
);
1974 * Wait for state update from restarter before sending _START or
1982 * If it is a DISABLE event requested by the administrator then we are
1983 * offlining the dependents first.
1987 * Set GV_TOOFFLINE for the services we are offlining. We cannot
1988 * clear the GV_TOOFFLINE bits from all the services because
1989 * other DISABLE events might be handled at the same time.
1991 vertex
->gv_flags
|= GV_TOOFFLINE
;
1993 /* remember which vertex to disable... */
1994 vertex
->gv_flags
|= GV_TODISABLE
;
1996 log_framework(LOG_DEBUG
, "Marking in-subtree vertices before "
1997 "disabling %s.\n", vertex
->gv_name
);
1999 /* set GV_TOOFFLINE for its dependents */
2000 r
= uu_list_walk(vertex
->gv_dependents
, (uu_walk_fn_t
*)mark_subtree
,
2004 /* disable the instance now if there is nothing else to offline */
2005 if (insubtree_dependents_down(vertex
) == B_TRUE
) {
2006 vertex_send_event(vertex
, RESTARTER_EVENT_TYPE_ADMIN_DISABLE
);
2011 * This loop is similar to the one used for the graph reversal shutdown
2012 * and could be improved in term of performance for the subtree reversal
2015 for (v
= uu_list_first(dgraph
); v
!= NULL
;
2016 v
= uu_list_next(dgraph
, v
)) {
2017 /* skip the vertex we are disabling for now */
2021 if (v
->gv_type
!= GVT_INST
||
2022 (v
->gv_flags
& GV_CONFIGURED
) == 0 ||
2023 (v
->gv_flags
& GV_ENABLED
) == 0 ||
2024 (v
->gv_flags
& GV_TOOFFLINE
) == 0)
2027 if ((v
->gv_state
!= RESTARTER_STATE_ONLINE
) &&
2028 (v
->gv_state
!= RESTARTER_STATE_DEGRADED
)) {
2029 /* continue if there is nothing to offline */
2034 * Instances which are up need to come down before we're
2035 * done, but we can only offline the leaves here. An
2036 * instance is a leaf when all its dependents are down.
2038 if (insubtree_dependents_down(v
) == B_TRUE
) {
2039 log_framework(LOG_DEBUG
, "Offlining in-subtree "
2040 "instance %s for %s.\n",
2041 v
->gv_name
, vertex
->gv_name
);
2047 static int configure_vertex(graph_vertex_t
*, scf_instance_t
*);
2050 * Set the restarter for v to fmri_arg. That is, make sure a vertex for
2051 * fmri_arg exists, make v depend on it, and send _ADD_INSTANCE for v. If
2052 * v is already configured and fmri_arg indicates the current restarter, do
2053 * nothing. If v is configured and fmri_arg is a new restarter, delete v's
2054 * dependency on the restarter, send _REMOVE_INSTANCE for v, and set the new
2055 * restarter. Returns 0 on success, EINVAL if the FMRI is invalid,
2056 * ECONNABORTED if the repository connection is broken, and ELOOP
2057 * if the dependency would create a cycle. In the last case, *pathp will
2058 * point to a -1-terminated array of ids which compose the path from v to
2062 graph_change_restarter(graph_vertex_t
*v
, const char *fmri_arg
, scf_handle_t
*h
,
2065 char *restarter_fmri
= NULL
;
2070 assert(MUTEX_HELD(&dgraph_lock
));
2072 if (fmri_arg
[0] != '\0') {
2073 err
= fmri_canonify(fmri_arg
, &restarter_fmri
, B_TRUE
);
2075 assert(err
== EINVAL
);
2080 if (restarter_fmri
== NULL
||
2081 strcmp(restarter_fmri
, SCF_SERVICE_STARTD
) == 0) {
2082 if (v
->gv_flags
& GV_CONFIGURED
) {
2083 if (v
->gv_restarter_id
== -1) {
2084 if (restarter_fmri
!= NULL
)
2085 startd_free(restarter_fmri
,
2090 graph_unset_restarter(v
);
2093 /* Master restarter, nothing to do. */
2094 v
->gv_restarter_id
= -1;
2095 v
->gv_restarter_channel
= NULL
;
2096 vertex_send_event(v
, RESTARTER_EVENT_TYPE_ADD_INSTANCE
);
2100 if (v
->gv_flags
& GV_CONFIGURED
) {
2101 id
= dict_lookup_byname(restarter_fmri
);
2102 if (id
!= -1 && v
->gv_restarter_id
== id
) {
2103 startd_free(restarter_fmri
, max_scf_fmri_size
);
2107 graph_unset_restarter(v
);
2110 err
= graph_insert_vertex_unconfigured(restarter_fmri
, GVT_INST
, 0,
2112 startd_free(restarter_fmri
, max_scf_fmri_size
);
2113 assert(err
== 0 || err
== EEXIST
);
2115 if (rv
->gv_delegate_initialized
== 0) {
2116 if ((rv
->gv_delegate_channel
= restarter_protocol_init_delegate(
2117 rv
->gv_name
)) == NULL
)
2119 rv
->gv_delegate_initialized
= 1;
2121 v
->gv_restarter_id
= rv
->gv_id
;
2122 v
->gv_restarter_channel
= rv
->gv_delegate_channel
;
2124 err
= graph_insert_dependency(v
, rv
, pathp
);
2126 assert(err
== ELOOP
);
2130 vertex_send_event(v
, RESTARTER_EVENT_TYPE_ADD_INSTANCE
);
2132 if (!(rv
->gv_flags
& GV_CONFIGURED
)) {
2133 scf_instance_t
*inst
;
2135 err
= libscf_fmri_get_instance(h
, rv
->gv_name
, &inst
);
2138 err
= configure_vertex(rv
, inst
);
2139 scf_instance_destroy(inst
);
2146 return (ECONNABORTED
);
2149 bad_error("configure_vertex", err
);
2154 return (ECONNABORTED
);
2161 * The fmri doesn't specify an instance - translate
2168 bad_error("libscf_fmri_get_instance", err
);
2177 * Add all of the instances of the service named by fmri to the graph.
2180 * ENOENT - service indicated by fmri does not exist
2182 * In both cases *reboundp will be B_TRUE if the handle was rebound, or B_FALSE
2186 add_service(const char *fmri
, scf_handle_t
*h
, boolean_t
*reboundp
)
2189 scf_instance_t
*inst
;
2194 *reboundp
= B_FALSE
;
2196 svc
= safe_scf_service_create(h
);
2197 inst
= safe_scf_instance_create(h
);
2198 iter
= safe_scf_iter_create(h
);
2199 inst_fmri
= startd_alloc(max_scf_fmri_size
);
2202 if (scf_handle_decode_fmri(h
, fmri
, NULL
, svc
, NULL
, NULL
, NULL
,
2203 SCF_DECODE_FMRI_EXACT
) != 0) {
2204 switch (scf_error()) {
2205 case SCF_ERROR_CONNECTION_BROKEN
:
2207 libscf_handle_rebind(h
);
2211 case SCF_ERROR_NOT_FOUND
:
2215 case SCF_ERROR_INVALID_ARGUMENT
:
2216 case SCF_ERROR_CONSTRAINT_VIOLATED
:
2217 case SCF_ERROR_NOT_BOUND
:
2218 case SCF_ERROR_HANDLE_MISMATCH
:
2219 bad_error("scf_handle_decode_fmri", scf_error());
2223 if (scf_iter_service_instances(iter
, svc
) != 0) {
2224 switch (scf_error()) {
2225 case SCF_ERROR_CONNECTION_BROKEN
:
2227 libscf_handle_rebind(h
);
2231 case SCF_ERROR_DELETED
:
2235 case SCF_ERROR_HANDLE_MISMATCH
:
2236 case SCF_ERROR_NOT_BOUND
:
2237 case SCF_ERROR_NOT_SET
:
2238 bad_error("scf_iter_service_instances", scf_error());
2243 r
= scf_iter_next_instance(iter
, inst
);
2247 switch (scf_error()) {
2248 case SCF_ERROR_CONNECTION_BROKEN
:
2250 libscf_handle_rebind(h
);
2254 case SCF_ERROR_DELETED
:
2258 case SCF_ERROR_HANDLE_MISMATCH
:
2259 case SCF_ERROR_NOT_BOUND
:
2260 case SCF_ERROR_NOT_SET
:
2261 case SCF_ERROR_INVALID_ARGUMENT
:
2262 bad_error("scf_iter_next_instance",
2267 if (scf_instance_to_fmri(inst
, inst_fmri
, max_scf_fmri_size
) <
2269 switch (scf_error()) {
2270 case SCF_ERROR_CONNECTION_BROKEN
:
2271 libscf_handle_rebind(h
);
2275 case SCF_ERROR_DELETED
:
2278 case SCF_ERROR_NOT_BOUND
:
2279 case SCF_ERROR_NOT_SET
:
2280 bad_error("scf_instance_to_fmri", scf_error());
2284 r
= dgraph_add_instance(inst_fmri
, inst
, B_FALSE
);
2294 libscf_handle_rebind(h
);
2300 bad_error("dgraph_add_instance", r
);
2307 startd_free(inst_fmri
, max_scf_fmri_size
);
2308 scf_iter_destroy(iter
);
2309 scf_instance_destroy(inst
);
2310 scf_service_destroy(svc
);
2314 struct depfmri_info
{
2315 graph_vertex_t
*v
; /* GVT_GROUP vertex */
2316 gv_type_t type
; /* type of dependency */
2317 const char *inst_fmri
; /* FMRI of parental GVT_INST vert. */
2318 const char *pg_name
; /* Name of dependency pg */
2320 int err
; /* return error code */
2321 int **pathp
; /* return circular dependency path */
2325 * Find or create a vertex for fmri and make info->v depend on it.
2330 * On failure, sets info->err to
2331 * EINVAL - fmri is invalid
2332 * fmri does not match info->type
2333 * ELOOP - Adding the dependency creates a circular dependency. *info->pathp
2334 * will point to an array of the ids of the members of the cycle.
2335 * ECONNABORTED - repository connection was broken
2336 * ECONNRESET - succeeded, but repository connection was reset
2339 process_dependency_fmri(const char *fmri
, struct depfmri_info
*info
)
2342 graph_vertex_t
*depgroup_v
, *v
;
2343 char *fmri_copy
, *cfmri
;
2344 size_t fmri_copy_sz
;
2345 const char *scope
, *service
, *instance
, *pg
;
2346 scf_instance_t
*inst
;
2349 assert(MUTEX_HELD(&dgraph_lock
));
2351 /* Get or create vertex for FMRI */
2352 depgroup_v
= info
->v
;
2354 if (strncmp(fmri
, "file:", sizeof ("file:") - 1) == 0) {
2355 if (info
->type
!= GVT_FILE
) {
2356 log_framework(LOG_NOTICE
,
2357 "FMRI \"%s\" is not allowed for the \"%s\" "
2358 "dependency's type of instance %s.\n", fmri
,
2359 info
->pg_name
, info
->inst_fmri
);
2360 return (info
->err
= EINVAL
);
2363 err
= graph_insert_vertex_unconfigured(fmri
, info
->type
, 0,
2370 assert(v
->gv_type
== GVT_FILE
);
2373 case EINVAL
: /* prevented above */
2375 bad_error("graph_insert_vertex_unconfigured", err
);
2378 if (info
->type
!= GVT_INST
) {
2379 log_framework(LOG_NOTICE
,
2380 "FMRI \"%s\" is not allowed for the \"%s\" "
2381 "dependency's type of instance %s.\n", fmri
,
2382 info
->pg_name
, info
->inst_fmri
);
2383 return (info
->err
= EINVAL
);
2387 * We must canonify fmri & add a vertex for it.
2389 fmri_copy_sz
= strlen(fmri
) + 1;
2390 fmri_copy
= startd_alloc(fmri_copy_sz
);
2391 (void) strcpy(fmri_copy
, fmri
);
2393 /* Determine if the FMRI is a property group or instance */
2394 if (scf_parse_svc_fmri(fmri_copy
, &scope
, &service
,
2395 &instance
, &pg
, NULL
) != 0) {
2396 startd_free(fmri_copy
, fmri_copy_sz
);
2397 log_framework(LOG_NOTICE
,
2398 "Dependency \"%s\" of %s has invalid FMRI "
2399 "\"%s\".\n", info
->pg_name
, info
->inst_fmri
,
2401 return (info
->err
= EINVAL
);
2404 if (service
== NULL
|| pg
!= NULL
) {
2405 startd_free(fmri_copy
, fmri_copy_sz
);
2406 log_framework(LOG_NOTICE
,
2407 "Dependency \"%s\" of %s does not designate a "
2408 "service or instance.\n", info
->pg_name
,
2410 return (info
->err
= EINVAL
);
2413 if (scope
== NULL
|| strcmp(scope
, SCF_SCOPE_LOCAL
) == 0) {
2414 cfmri
= uu_msprintf("svc:/%s%s%s",
2415 service
, instance
? ":" : "", instance
? instance
:
2418 cfmri
= uu_msprintf("svc://%s/%s%s%s",
2419 scope
, service
, instance
? ":" : "", instance
?
2423 startd_free(fmri_copy
, fmri_copy_sz
);
2425 err
= graph_insert_vertex_unconfigured(cfmri
, instance
?
2426 GVT_INST
: GVT_SVC
, instance
? 0 : DEPGRP_REQUIRE_ANY
,
2435 if (instance
!= NULL
)
2436 assert(v
->gv_type
== GVT_INST
);
2438 assert(v
->gv_type
== GVT_SVC
);
2442 bad_error("graph_insert_vertex_unconfigured", err
);
2446 /* Add dependency from depgroup_v to new vertex */
2447 info
->err
= graph_insert_dependency(depgroup_v
, v
, info
->pathp
);
2448 switch (info
->err
) {
2456 bad_error("graph_insert_dependency", info
->err
);
2459 /* This must be after we insert the dependency, to avoid looping. */
2460 switch (v
->gv_type
) {
2462 if ((v
->gv_flags
& GV_CONFIGURED
) != 0)
2465 inst
= safe_scf_instance_create(info
->h
);
2470 err
= libscf_lookup_instance(v
->gv_name
, inst
);
2473 err
= configure_vertex(v
, inst
);
2480 libscf_handle_rebind(info
->h
);
2485 bad_error("configure_vertex", err
);
2493 libscf_handle_rebind(info
->h
);
2500 bad_error("libscf_fmri_get_instance", err
);
2503 scf_instance_destroy(inst
);
2506 return (info
->err
= ECONNRESET
);
2510 (void) add_service(v
->gv_name
, info
->h
, &rebound
);
2512 return (info
->err
= ECONNRESET
);
2519 graph_vertex_t
*v
; /* GVT_INST vertex */
2520 int err
; /* return error */
2521 int **pathp
; /* return circular dependency path */
2525 * Make info->v depend on a new GVT_GROUP node for this property group,
2526 * and then call process_dependency_fmri() for the values of the entity
2527 * property. Return 0 on success, or if something goes wrong return nonzero
2528 * and set info->err to ECONNABORTED, EINVAL, or the error code returned by
2529 * process_dependency_fmri().
2532 process_dependency_pg(scf_propertygroup_t
*pg
, struct deppg_info
*info
)
2535 depgroup_type_t deptype
;
2536 restarter_error_t rerr
;
2537 struct depfmri_info linfo
;
2538 char *fmri
, *pg_name
;
2540 graph_vertex_t
*depgrp
;
2541 scf_property_t
*prop
;
2547 assert(MUTEX_HELD(&dgraph_lock
));
2549 h
= scf_pg_handle(pg
);
2551 pg_name
= startd_alloc(max_scf_name_size
);
2553 len
= scf_pg_get_name(pg
, pg_name
, max_scf_name_size
);
2555 startd_free(pg_name
, max_scf_name_size
);
2556 switch (scf_error()) {
2557 case SCF_ERROR_CONNECTION_BROKEN
:
2559 return (info
->err
= ECONNABORTED
);
2561 case SCF_ERROR_DELETED
:
2562 return (info
->err
= 0);
2564 case SCF_ERROR_NOT_SET
:
2565 bad_error("scf_pg_get_name", scf_error());
2570 * Skip over empty dependency groups. Since dependency property
2571 * groups are updated atomically, they are either empty or
2574 empty
= depgroup_empty(h
, pg
);
2577 "Error reading dependency group \"%s\" of %s: %s\n",
2578 pg_name
, info
->v
->gv_name
, scf_strerror(scf_error()));
2579 startd_free(pg_name
, max_scf_name_size
);
2580 return (info
->err
= EINVAL
);
2582 } else if (empty
== 1) {
2583 log_framework(LOG_DEBUG
,
2584 "Ignoring empty dependency group \"%s\" of %s\n",
2585 pg_name
, info
->v
->gv_name
);
2586 startd_free(pg_name
, max_scf_name_size
);
2587 return (info
->err
= 0);
2590 fmri_sz
= strlen(info
->v
->gv_name
) + 1 + len
+ 1;
2591 fmri
= startd_alloc(fmri_sz
);
2593 (void) snprintf(fmri
, fmri_sz
, "%s>%s", info
->v
->gv_name
,
2596 /* Validate the pg before modifying the graph */
2597 deptype
= depgroup_read_grouping(h
, pg
);
2598 if (deptype
== DEPGRP_UNSUPPORTED
) {
2600 "Dependency \"%s\" of %s has an unknown grouping value.\n",
2601 pg_name
, info
->v
->gv_name
);
2602 startd_free(fmri
, fmri_sz
);
2603 startd_free(pg_name
, max_scf_name_size
);
2604 return (info
->err
= EINVAL
);
2607 rerr
= depgroup_read_restart(h
, pg
);
2608 if (rerr
== RERR_UNSUPPORTED
) {
2610 "Dependency \"%s\" of %s has an unknown restart_on value."
2611 "\n", pg_name
, info
->v
->gv_name
);
2612 startd_free(fmri
, fmri_sz
);
2613 startd_free(pg_name
, max_scf_name_size
);
2614 return (info
->err
= EINVAL
);
2617 prop
= safe_scf_property_create(h
);
2619 if (scf_pg_get_property(pg
, SCF_PROPERTY_ENTITIES
, prop
) != 0) {
2620 scferr
= scf_error();
2621 scf_property_destroy(prop
);
2622 if (scferr
== SCF_ERROR_DELETED
) {
2623 startd_free(fmri
, fmri_sz
);
2624 startd_free(pg_name
, max_scf_name_size
);
2625 return (info
->err
= 0);
2626 } else if (scferr
!= SCF_ERROR_NOT_FOUND
) {
2627 startd_free(fmri
, fmri_sz
);
2628 startd_free(pg_name
, max_scf_name_size
);
2629 return (info
->err
= ECONNABORTED
);
2633 "Dependency \"%s\" of %s is missing a \"%s\" property.\n",
2634 pg_name
, info
->v
->gv_name
, SCF_PROPERTY_ENTITIES
);
2636 startd_free(fmri
, fmri_sz
);
2637 startd_free(pg_name
, max_scf_name_size
);
2639 return (info
->err
= EINVAL
);
2642 /* Create depgroup vertex for pg */
2643 err
= graph_insert_vertex_unconfigured(fmri
, GVT_GROUP
, deptype
,
2646 startd_free(fmri
, fmri_sz
);
2648 /* Add dependency from inst vertex to new vertex */
2649 err
= graph_insert_dependency(info
->v
, depgrp
, info
->pathp
);
2650 /* ELOOP can't happen because this should be a new vertex */
2654 linfo
.type
= depgroup_read_scheme(h
, pg
);
2655 linfo
.inst_fmri
= info
->v
->gv_name
;
2656 linfo
.pg_name
= pg_name
;
2659 linfo
.pathp
= info
->pathp
;
2660 err
= walk_property_astrings(prop
, (callback_t
)process_dependency_fmri
,
2663 scf_property_destroy(prop
);
2664 startd_free(pg_name
, max_scf_name_size
);
2669 return (info
->err
= linfo
.err
);
2673 return (info
->err
= err
);
2676 return (info
->err
= 0);
2679 return (info
->err
= ECONNABORTED
);
2682 bad_error("walk_property_astrings", err
);
2688 * Build the dependency info for v from the repository. Returns 0 on success,
2689 * ECONNABORTED on repository disconnection, EINVAL if the repository
2690 * configuration is invalid, and ELOOP if a dependency would cause a cycle.
2691 * In the last case, *pathp will point to a -1-terminated array of ids which
2692 * constitute the rest of the dependency cycle.
2695 set_dependencies(graph_vertex_t
*v
, scf_instance_t
*inst
, int **pathp
)
2697 struct deppg_info info
;
2699 uint_t old_configured
;
2701 assert(MUTEX_HELD(&dgraph_lock
));
2704 * Mark the vertex as configured during dependency insertion to avoid
2705 * dependency cycles (which can appear in the graph if one of the
2706 * vertices is an exclusion-group).
2708 old_configured
= v
->gv_flags
& GV_CONFIGURED
;
2709 v
->gv_flags
|= GV_CONFIGURED
;
2715 err
= walk_dependency_pgs(inst
, (callback_t
)process_dependency_pg
,
2718 if (!old_configured
)
2719 v
->gv_flags
&= ~GV_CONFIGURED
;
2727 return (ECONNABORTED
);
2730 /* Should get delete event, so return 0. */
2734 bad_error("walk_dependency_pgs", err
);
2741 handle_cycle(const char *fmri
, int *path
)
2746 assert(MUTEX_HELD(&dgraph_lock
));
2748 path_to_str(path
, (char **)&cp
, &sz
);
2750 log_error(LOG_ERR
, "Transitioning %s to maintenance "
2751 "because it completes a dependency cycle (see svcs -xv for "
2752 "details):\n%s", fmri
? fmri
: "?", cp
);
2754 startd_free((void *)cp
, sz
);
2758 * Increment the vertex's reference count to prevent the vertex removal
2762 vertex_ref(graph_vertex_t
*v
)
2764 assert(MUTEX_HELD(&dgraph_lock
));
2770 * Decrement the vertex's reference count and remove the vertex from
2771 * the dgraph when possible.
2773 * Return VERTEX_REMOVED when the vertex has been removed otherwise
2774 * return VERTEX_INUSE.
2777 vertex_unref(graph_vertex_t
*v
)
2779 assert(MUTEX_HELD(&dgraph_lock
));
2780 assert(v
->gv_refs
> 0);
2784 return (free_if_unrefed(v
));
2788 * When run on the dependencies of a vertex, populates list with
2789 * graph_edge_t's which point to the service vertices or the instance
2790 * vertices (no GVT_GROUP nodes) on which the vertex depends.
2792 * Increment the vertex's reference count once the vertex is inserted
2793 * in the list. The vertex won't be able to be deleted from the dgraph
2794 * while it is referenced.
2797 append_svcs_or_insts(graph_edge_t
*e
, uu_list_t
*list
)
2799 graph_vertex_t
*v
= e
->ge_vertex
;
2803 switch (v
->gv_type
) {
2809 r
= uu_list_walk(v
->gv_dependencies
,
2810 (uu_walk_fn_t
*)append_svcs_or_insts
, list
, 0);
2812 return (UU_WALK_NEXT
);
2815 return (UU_WALK_NEXT
);
2819 uu_warn("%s:%d: Unexpected vertex type %d.\n", __FILE__
,
2820 __LINE__
, v
->gv_type
);
2825 new = startd_alloc(sizeof (*new));
2827 uu_list_node_init(new, &new->ge_link
, graph_edge_pool
);
2828 r
= uu_list_insert_before(list
, NULL
, new);
2832 * Because we are inserting the vertex in a list, we don't want
2833 * the vertex to be freed while the list is in use. In order to
2834 * achieve that, increment the vertex's reference count.
2838 return (UU_WALK_NEXT
);
2842 should_be_in_subgraph(graph_vertex_t
*v
)
2850 * v is in the subgraph if any of its dependents are in the subgraph.
2851 * Except for EXCLUDE_ALL dependents. And OPTIONAL dependents only
2852 * count if we're enabled.
2854 for (e
= uu_list_first(v
->gv_dependents
);
2856 e
= uu_list_next(v
->gv_dependents
, e
)) {
2857 graph_vertex_t
*dv
= e
->ge_vertex
;
2859 if (!(dv
->gv_flags
& GV_INSUBGRAPH
))
2863 * Don't include instances that are optional and disabled.
2865 if (v
->gv_type
== GVT_INST
&& dv
->gv_type
== GVT_SVC
) {
2870 for (ee
= uu_list_first(dv
->gv_dependents
);
2872 ee
= uu_list_next(dv
->gv_dependents
, ee
)) {
2874 graph_vertex_t
*ddv
= e
->ge_vertex
;
2876 if (ddv
->gv_type
== GVT_GROUP
&&
2877 ddv
->gv_depgroup
== DEPGRP_EXCLUDE_ALL
)
2880 if (ddv
->gv_type
== GVT_GROUP
&&
2881 ddv
->gv_depgroup
== DEPGRP_OPTIONAL_ALL
&&
2882 !(v
->gv_flags
& GV_ENBLD_NOOVR
))
2890 if (v
->gv_type
== GVT_INST
&&
2891 dv
->gv_type
== GVT_GROUP
&&
2892 dv
->gv_depgroup
== DEPGRP_OPTIONAL_ALL
&&
2893 !(v
->gv_flags
& GV_ENBLD_NOOVR
))
2896 /* Don't include excluded services and instances */
2897 if (dv
->gv_type
== GVT_GROUP
&&
2898 dv
->gv_depgroup
== DEPGRP_EXCLUDE_ALL
)
2908 * Ensures that GV_INSUBGRAPH is set properly for v and its descendents. If
2909 * any bits change, manipulate the repository appropriately. Returns 0 or
2913 eval_subgraph(graph_vertex_t
*v
, scf_handle_t
*h
)
2915 boolean_t old
= (v
->gv_flags
& GV_INSUBGRAPH
) != 0;
2918 scf_instance_t
*inst
;
2921 assert(milestone
!= NULL
&& milestone
!= MILESTONE_NONE
);
2923 new = should_be_in_subgraph(v
);
2928 log_framework(LOG_DEBUG
, new ? "Adding %s to the subgraph.\n" :
2929 "Removing %s from the subgraph.\n", v
->gv_name
);
2931 v
->gv_flags
= (v
->gv_flags
& ~GV_INSUBGRAPH
) |
2932 (new ? GV_INSUBGRAPH
: 0);
2934 if (v
->gv_type
== GVT_INST
&& (v
->gv_flags
& GV_CONFIGURED
)) {
2938 err
= libscf_fmri_get_instance(h
, v
->gv_name
, &inst
);
2942 libscf_handle_rebind(h
);
2952 bad_error("libscf_fmri_get_instance", err
);
2958 err
= libscf_delete_enable_ovr(inst
);
2959 f
= "libscf_delete_enable_ovr";
2961 err
= libscf_set_enable_ovr(inst
, 0);
2962 f
= "libscf_set_enable_ovr";
2964 scf_instance_destroy(inst
);
2971 libscf_handle_rebind(h
);
2973 * We must continue so the graph is updated,
2974 * but we must return ECONNABORTED so any
2975 * libscf state held by any callers is reset.
2982 log_error(LOG_WARNING
,
2983 "Could not set %s/%s for %s: %s.\n",
2984 SCF_PG_GENERAL_OVR
, SCF_PROPERTY_ENABLED
,
2985 v
->gv_name
, strerror(err
));
2994 for (e
= uu_list_first(v
->gv_dependencies
);
2996 e
= uu_list_next(v
->gv_dependencies
, e
)) {
2997 r
= eval_subgraph(e
->ge_vertex
, h
);
2999 assert(r
== ECONNABORTED
);
3008 * Delete the (property group) dependencies of v & create new ones based on
3009 * inst. If doing so would create a cycle, log a message and put the instance
3010 * into maintenance. Update GV_INSUBGRAPH flags as necessary. Returns 0 or
3014 refresh_vertex(graph_vertex_t
*v
, scf_instance_t
*inst
)
3020 scf_handle_t
*h
= scf_instance_handle(inst
);
3021 uu_list_t
*old_deps
;
3026 assert(MUTEX_HELD(&dgraph_lock
));
3027 assert(v
->gv_type
== GVT_INST
);
3029 log_framework(LOG_DEBUG
, "Graph engine: Refreshing %s.\n", v
->gv_name
);
3031 if (milestone
> MILESTONE_NONE
) {
3033 * In case some of v's dependencies are being deleted we must
3034 * make a list of them now for GV_INSUBGRAPH-flag evaluation
3035 * after the new dependencies are in place.
3037 old_deps
= startd_list_create(graph_edge_pool
, NULL
, 0);
3039 err
= uu_list_walk(v
->gv_dependencies
,
3040 (uu_walk_fn_t
*)append_svcs_or_insts
, old_deps
, 0);
3044 delete_instance_dependencies(v
, B_FALSE
);
3046 err
= set_dependencies(v
, inst
, &path
);
3057 r
= libscf_instance_get_fmri(inst
, &fmri
);
3071 bad_error("libscf_instance_get_fmri", r
);
3074 if (err
== EINVAL
) {
3075 log_error(LOG_ERR
, "Transitioning %s "
3076 "to maintenance due to misconfiguration.\n",
3078 vertex_send_event(v
,
3079 RESTARTER_EVENT_TYPE_INVALID_DEPENDENCY
);
3081 handle_cycle(fmri
, path
);
3082 vertex_send_event(v
,
3083 RESTARTER_EVENT_TYPE_DEPENDENCY_CYCLE
);
3085 startd_free(fmri
, max_scf_fmri_size
);
3090 bad_error("set_dependencies", err
);
3093 if (milestone
> MILESTONE_NONE
) {
3094 boolean_t aborted
= B_FALSE
;
3096 for (e
= uu_list_first(old_deps
);
3098 e
= uu_list_next(old_deps
, e
)) {
3101 if (vertex_unref(vv
) == VERTEX_INUSE
&&
3102 eval_subgraph(vv
, h
) == ECONNABORTED
)
3106 for (e
= uu_list_first(v
->gv_dependencies
);
3108 e
= uu_list_next(v
->gv_dependencies
, e
)) {
3109 if (eval_subgraph(e
->ge_vertex
, h
) ==
3120 graph_start_if_satisfied(v
);
3125 if (milestone
> MILESTONE_NONE
) {
3126 void *cookie
= NULL
;
3128 while ((e
= uu_list_teardown(old_deps
, &cookie
)) != NULL
)
3129 startd_free(e
, sizeof (*e
));
3131 uu_list_destroy(old_deps
);
3138 * Set up v according to inst. That is, make sure it depends on its
3139 * restarter and set up its dependencies. Send the ADD_INSTANCE command to
3140 * the restarter, and send ENABLE or DISABLE as appropriate.
3142 * Returns 0 on success, ECONNABORTED on repository disconnection, or
3143 * ECANCELED if inst is deleted.
3146 configure_vertex(graph_vertex_t
*v
, scf_instance_t
*inst
)
3149 scf_propertygroup_t
*pg
;
3150 scf_snapshot_t
*snap
;
3151 char *restarter_fmri
= startd_alloc(max_scf_value_size
);
3152 int enabled
, enabled_ovr
;
3158 restarter_fmri
[0] = '\0';
3160 assert(MUTEX_HELD(&dgraph_lock
));
3161 assert(v
->gv_type
== GVT_INST
);
3162 assert((v
->gv_flags
& GV_CONFIGURED
) == 0);
3164 /* GV_INSUBGRAPH should already be set properly. */
3165 assert(should_be_in_subgraph(v
) ==
3166 ((v
->gv_flags
& GV_INSUBGRAPH
) != 0));
3169 * If the instance fmri is in the deathrow list then set the
3170 * GV_DEATHROW flag on the vertex and create and set to true the
3171 * SCF_PROPERTY_DEATHROW boolean property in the non-persistent
3172 * repository for this instance fmri.
3174 if ((v
->gv_flags
& GV_DEATHROW
) ||
3175 (is_fmri_in_deathrow(v
->gv_name
) == B_TRUE
)) {
3176 if ((v
->gv_flags
& GV_DEATHROW
) == 0) {
3178 * Set flag GV_DEATHROW, create and set to true
3179 * the SCF_PROPERTY_DEATHROW property in the
3180 * non-persistent repository for this instance fmri.
3182 v
->gv_flags
|= GV_DEATHROW
;
3184 switch (err
= libscf_set_deathrow(inst
, 1)) {
3190 startd_free(restarter_fmri
, max_scf_value_size
);
3194 log_error(LOG_WARNING
, "Could not set %s/%s "
3195 "for deathrow %s: %s.\n",
3196 SCF_PG_DEATHROW
, SCF_PROPERTY_DEATHROW
,
3197 v
->gv_name
, strerror(err
));
3201 uu_die("Permission denied.\n");
3205 bad_error("libscf_set_deathrow", err
);
3207 log_framework(LOG_DEBUG
, "Deathrow, graph set %s.\n",
3210 startd_free(restarter_fmri
, max_scf_value_size
);
3214 h
= scf_instance_handle(inst
);
3217 * Using a temporary deathrow boolean property, set through
3218 * libscf_set_deathrow(), only for fmris on deathrow, is necessary
3219 * because deathrow_fini() may already have been called, and in case
3220 * of a refresh, GV_DEATHROW may need to be set again.
3221 * libscf_get_deathrow() sets deathrow to 1 only if this instance
3222 * has a temporary boolean property named 'deathrow' valued true
3223 * in a property group 'deathrow', -1 or 0 in all other cases.
3225 err
= libscf_get_deathrow(h
, inst
, &deathrow
);
3232 startd_free(restarter_fmri
, max_scf_value_size
);
3236 bad_error("libscf_get_deathrow", err
);
3239 if (deathrow
== 1) {
3240 v
->gv_flags
|= GV_DEATHROW
;
3241 startd_free(restarter_fmri
, max_scf_value_size
);
3245 log_framework(LOG_DEBUG
, "Graph adding %s.\n", v
->gv_name
);
3248 * If the instance does not have a restarter property group,
3249 * initialize its state to uninitialized/none, in case the restarter
3252 pg
= safe_scf_pg_create(h
);
3254 if (scf_instance_get_pg(inst
, SCF_PG_RESTARTER
, pg
) != 0) {
3255 instance_data_t idata
;
3256 uint_t count
= 0, msecs
= ALLOC_DELAY
;
3258 switch (scf_error()) {
3259 case SCF_ERROR_NOT_FOUND
:
3262 case SCF_ERROR_CONNECTION_BROKEN
:
3265 startd_free(restarter_fmri
, max_scf_value_size
);
3266 return (ECONNABORTED
);
3268 case SCF_ERROR_DELETED
:
3270 startd_free(restarter_fmri
, max_scf_value_size
);
3273 case SCF_ERROR_NOT_SET
:
3274 bad_error("scf_instance_get_pg", scf_error());
3277 switch (err
= libscf_instance_get_fmri(inst
,
3278 (char **)&idata
.i_fmri
)) {
3285 startd_free(restarter_fmri
, max_scf_value_size
);
3289 bad_error("libscf_instance_get_fmri", err
);
3292 idata
.i_state
= RESTARTER_STATE_NONE
;
3293 idata
.i_next_state
= RESTARTER_STATE_NONE
;
3296 switch (err
= _restarter_commit_states(h
, &idata
,
3297 RESTARTER_STATE_UNINIT
, RESTARTER_STATE_NONE
,
3298 restarter_get_str_short(restarter_str_insert_in_graph
))) {
3304 if (count
< ALLOC_RETRY
) {
3305 (void) poll(NULL
, 0, msecs
);
3306 msecs
*= ALLOC_DELAY_MULT
;
3310 uu_die("Insufficient memory.\n");
3314 startd_free((void *)idata
.i_fmri
, max_scf_fmri_size
);
3316 startd_free(restarter_fmri
, max_scf_value_size
);
3317 return (ECONNABORTED
);
3320 startd_free((void *)idata
.i_fmri
, max_scf_fmri_size
);
3322 startd_free(restarter_fmri
, max_scf_value_size
);
3328 log_error(LOG_NOTICE
, "Could not initialize state for "
3329 "%s: %s.\n", idata
.i_fmri
, strerror(err
));
3334 bad_error("_restarter_commit_states", err
);
3337 startd_free((void *)idata
.i_fmri
, max_scf_fmri_size
);
3342 if (milestone
!= NULL
) {
3344 * Make sure the enable-override is set properly before we
3345 * read whether we should be enabled.
3347 if (milestone
== MILESTONE_NONE
||
3348 !(v
->gv_flags
& GV_INSUBGRAPH
)) {
3350 * This might seem unjustified after the milestone
3351 * transition has completed (non_subgraph_svcs == 0),
3352 * but it's important because when we boot to
3353 * a milestone, we set the milestone before populating
3354 * the graph, and all of the new non-subgraph services
3355 * need to be disabled here.
3357 switch (err
= libscf_set_enable_ovr(inst
, 0)) {
3363 startd_free(restarter_fmri
, max_scf_value_size
);
3367 log_error(LOG_WARNING
,
3368 "Could not set %s/%s for %s: %s.\n",
3369 SCF_PG_GENERAL_OVR
, SCF_PROPERTY_ENABLED
,
3370 v
->gv_name
, strerror(err
));
3374 uu_die("Permission denied.\n");
3378 bad_error("libscf_set_enable_ovr", err
);
3381 assert(v
->gv_flags
& GV_INSUBGRAPH
);
3382 switch (err
= libscf_delete_enable_ovr(inst
)) {
3388 startd_free(restarter_fmri
, max_scf_value_size
);
3392 uu_die("Permission denied.\n");
3396 bad_error("libscf_delete_enable_ovr", err
);
3401 err
= libscf_get_basic_instance_data(h
, inst
, v
->gv_name
, &enabled
,
3402 &enabled_ovr
, &restarter_fmri
);
3409 startd_free(restarter_fmri
, max_scf_value_size
);
3413 log_framework(LOG_DEBUG
,
3414 "Ignoring %s because it has no general property group.\n",
3416 startd_free(restarter_fmri
, max_scf_value_size
);
3420 bad_error("libscf_get_basic_instance_data", err
);
3423 if ((tset
= libscf_get_stn_tset(inst
)) == -1) {
3424 log_framework(LOG_WARNING
,
3425 "Failed to get notification parameters for %s: %s\n",
3426 v
->gv_name
, scf_strerror(scf_error()));
3429 v
->gv_stn_tset
= tset
;
3431 if (strcmp(v
->gv_name
, SCF_INSTANCE_GLOBAL
) == 0)
3432 stn_global
= v
->gv_stn_tset
;
3434 if (enabled
== -1) {
3435 startd_free(restarter_fmri
, max_scf_value_size
);
3439 v
->gv_flags
= (v
->gv_flags
& ~GV_ENBLD_NOOVR
) |
3440 (enabled
? GV_ENBLD_NOOVR
: 0);
3442 if (enabled_ovr
!= -1)
3443 enabled
= enabled_ovr
;
3445 v
->gv_state
= RESTARTER_STATE_UNINIT
;
3447 snap
= libscf_get_or_make_running_snapshot(inst
, v
->gv_name
, B_TRUE
);
3448 scf_snapshot_destroy(snap
);
3450 /* Set up the restarter. (Sends _ADD_INSTANCE on success.) */
3451 err
= graph_change_restarter(v
, restarter_fmri
, h
, &path
);
3453 instance_data_t idata
;
3454 uint_t count
= 0, msecs
= ALLOC_DELAY
;
3455 restarter_str_t reason
;
3457 if (err
== ECONNABORTED
) {
3458 startd_free(restarter_fmri
, max_scf_value_size
);
3462 assert(err
== EINVAL
|| err
== ELOOP
);
3464 if (err
== EINVAL
) {
3465 log_framework(LOG_ERR
, emsg_invalid_restarter
,
3466 v
->gv_name
, restarter_fmri
);
3467 reason
= restarter_str_invalid_restarter
;
3469 handle_cycle(v
->gv_name
, path
);
3470 reason
= restarter_str_dependency_cycle
;
3473 startd_free(restarter_fmri
, max_scf_value_size
);
3476 * We didn't register the instance with the restarter, so we
3477 * must set maintenance mode ourselves.
3479 err
= libscf_instance_get_fmri(inst
, (char **)&idata
.i_fmri
);
3481 assert(err
== ECONNABORTED
|| err
== ECANCELED
);
3485 idata
.i_state
= RESTARTER_STATE_NONE
;
3486 idata
.i_next_state
= RESTARTER_STATE_NONE
;
3489 switch (err
= _restarter_commit_states(h
, &idata
,
3490 RESTARTER_STATE_MAINT
, RESTARTER_STATE_NONE
,
3491 restarter_get_str_short(reason
))) {
3497 if (count
< ALLOC_RETRY
) {
3498 (void) poll(NULL
, 0, msecs
);
3499 msecs
*= ALLOC_DELAY_MULT
;
3503 uu_die("Insufficient memory.\n");
3507 startd_free((void *)idata
.i_fmri
, max_scf_fmri_size
);
3508 return (ECONNABORTED
);
3511 startd_free((void *)idata
.i_fmri
, max_scf_fmri_size
);
3517 log_error(LOG_NOTICE
, "Could not initialize state for "
3518 "%s: %s.\n", idata
.i_fmri
, strerror(err
));
3523 bad_error("_restarter_commit_states", err
);
3526 startd_free((void *)idata
.i_fmri
, max_scf_fmri_size
);
3528 v
->gv_state
= RESTARTER_STATE_MAINT
;
3532 startd_free(restarter_fmri
, max_scf_value_size
);
3534 /* Add all the other dependencies. */
3535 err
= refresh_vertex(v
, inst
);
3537 assert(err
== ECONNABORTED
);
3542 v
->gv_flags
|= GV_CONFIGURED
;
3544 graph_enable_by_vertex(v
, enabled
, 0);
3551 kill_user_procs(void)
3553 (void) fputs("svc.startd: Killing user processes.\n", stdout
);
3556 * Despite its name, killall's role is to get select user processes--
3557 * basically those representing terminal-based logins-- to die. Victims
3558 * are located by killall in the utmp database. Since these are most
3559 * often shell based logins, and many shells mask SIGTERM (but are
3560 * responsive to SIGHUP) we first HUP and then shortly thereafter
3563 (void) fork_with_timeout("/usr/sbin/killall HUP", 1, 5);
3564 (void) fork_with_timeout("/usr/sbin/killall KILL", 1, 5);
3567 * Note the selection of user id's 0, 1 and 15, subsequently
3568 * inverted by -v. 15 is reserved for dladmd. Yes, this is a
3569 * kludge-- a better policy is needed.
3571 * Note that fork_with_timeout will only wait out the 1 second
3572 * "grace time" if pkill actually returns 0. So if there are
3573 * no matches, this will run to completion much more quickly.
3575 (void) fork_with_timeout("/usr/bin/pkill -TERM -v -u 0,1,15", 1, 5);
3576 (void) fork_with_timeout("/usr/bin/pkill -KILL -v -u 0,1,15", 1, 5);
3582 const char * const resetting
= "/etc/svc/volatile/resetting";
3587 char down_buf
[256], time_buf
[256];
3594 fd
= creat(resetting
, 0777);
3598 uu_warn("Could not create \"%s\"", resetting
);
3600 /* Kill dhcpagent if we're not using nfs for root */
3601 if ((statvfs("/", &vfs
) == 0) &&
3602 (strncmp(vfs
.f_basetype
, "nfs", sizeof ("nfs") - 1) != 0))
3603 fork_with_timeout("/usr/bin/pkill -x -u 0 dhcpagent", 0, 5);
3606 * Call sync(2) now, before we kill off user processes. This takes
3607 * advantage of the several seconds of pause we have before the
3608 * killalls are done. Time we can make good use of to get pages
3609 * moving out to disk.
3611 * Inside non-global zones, we don't bother, and it's better not to
3612 * anyway, since sync(2) can have system-wide impact.
3614 if (getzoneid() == 0)
3620 * Note that this must come after the killing of user procs, since
3621 * killall relies on utmpx, and this command affects the contents of
3624 if (access("/usr/lib/acct/closewtmp", X_OK
) == 0)
3625 fork_with_timeout("/usr/lib/acct/closewtmp", 0, 5);
3628 * For patches which may be installed as the system is shutting
3629 * down, we need to ensure, one more time, that the boot archive
3630 * really is up to date.
3632 if (getzoneid() == 0 && access("/usr/sbin/bootadm", X_OK
) == 0)
3633 fork_with_timeout("/usr/sbin/bootadm -ea update_all", 0, 3600);
3636 * Right now, fast reboot is supported only on i386.
3637 * scf_is_fastboot_default() should take care of it.
3638 * If somehow we got there on unsupported platform -
3639 * print warning and fall back to regular reboot.
3641 if (halting
== AD_FASTREBOOT
) {
3643 if (be_get_boot_args(&fbarg
, BE_ENTRY_DEFAULT
) == 0) {
3644 mdep
= (uintptr_t)fbarg
;
3647 * Failed to read BE info, fall back to normal reboot
3650 uu_warn("Failed to get fast reboot arguments.\n"
3651 "Falling back to regular reboot.\n");
3655 uu_warn("Fast reboot configured, but not supported by "
3660 fork_with_timeout("/sbin/umountall -l", 0, 5);
3661 fork_with_timeout("/sbin/umount /tmp /var/adm /var/run /var "
3662 ">/dev/null 2>&1", 0, 5);
3665 * Try to get to consistency for whatever UFS filesystems are left.
3666 * This is pretty expensive, so we save it for the end in the hopes of
3667 * minimizing what it must do. The other option would be to start in
3668 * parallel with the killall's, but lockfs tends to throw out much more
3669 * than is needed, and so subsequent commands (like umountall) take a
3670 * long time to get going again.
3672 * Inside of zones, we don't bother, since we're not about to terminate
3673 * the whole OS instance.
3675 * On systems using only ZFS, this call to lockfs -fa is a no-op.
3677 if (getzoneid() == 0) {
3678 if (access("/usr/sbin/lockfs", X_OK
) == 0)
3679 fork_with_timeout("/usr/sbin/lockfs -fa", 0, 30);
3681 sync(); /* once more, with feeling */
3684 fork_with_timeout("/sbin/umount /usr >/dev/null 2>&1", 0, 5);
3687 * Construct and emit the last words from userland:
3688 * "<timestamp> The system is down. Shutdown took <N> seconds."
3690 * Normally we'd use syslog, but with /var and other things
3691 * potentially gone, try to minimize the external dependencies.
3694 (void) localtime_r(&now
, &nowtm
);
3696 if (strftime(down_buf
, sizeof (down_buf
),
3697 "%b %e %T The system is down.", &nowtm
) == 0) {
3698 (void) strlcpy(down_buf
, "The system is down.",
3702 if (halting_time
!= 0 && halting_time
<= now
) {
3703 (void) snprintf(time_buf
, sizeof (time_buf
),
3704 " Shutdown took %lu seconds.", now
- halting_time
);
3708 (void) printf("%s%s\n", down_buf
, time_buf
);
3710 (void) uadmin(A_SHUTDOWN
, halting
, mdep
);
3711 uu_warn("uadmin() failed");
3714 if (halting
== AD_FASTREBOOT
)
3718 if (remove(resetting
) != 0 && errno
!= ENOENT
)
3719 uu_warn("Could not remove \"%s\"", resetting
);
3723 * If any of the up_svcs[] are online or satisfiable, return true. If they are
3724 * all missing, disabled, in maintenance, or unsatisfiable, return false.
3731 assert(MUTEX_HELD(&dgraph_lock
));
3734 * If we are booting to single user (boot -s),
3735 * SCF_MILESTONE_SINGLE_USER is needed to come up because startd
3736 * spawns sulogin after single-user is online (see specials.c).
3738 i
= (booting_to_single_user
? 0 : 1);
3740 for (; up_svcs
[i
] != NULL
; ++i
) {
3741 if (up_svcs_p
[i
] == NULL
) {
3742 up_svcs_p
[i
] = vertex_get_by_name(up_svcs
[i
]);
3744 if (up_svcs_p
[i
] == NULL
)
3749 * Ignore unconfigured services (the ones that have been
3750 * mentioned in a dependency from other services, but do
3751 * not exist in the repository). Services which exist
3752 * in the repository but don't have general/enabled
3753 * property will be also ignored.
3755 if (!(up_svcs_p
[i
]->gv_flags
& GV_CONFIGURED
))
3758 switch (up_svcs_p
[i
]->gv_state
) {
3759 case RESTARTER_STATE_ONLINE
:
3760 case RESTARTER_STATE_DEGRADED
:
3762 * Deactivate verbose boot once a login service has been
3765 st
->st_log_login_reached
= 1;
3767 case RESTARTER_STATE_UNINIT
:
3770 case RESTARTER_STATE_OFFLINE
:
3771 if (instance_satisfied(up_svcs_p
[i
], B_TRUE
) != -1)
3773 log_framework(LOG_DEBUG
,
3774 "can_come_up(): %s is unsatisfiable.\n",
3775 up_svcs_p
[i
]->gv_name
);
3778 case RESTARTER_STATE_DISABLED
:
3779 case RESTARTER_STATE_MAINT
:
3780 log_framework(LOG_DEBUG
,
3781 "can_come_up(): %s is in state %s.\n",
3782 up_svcs_p
[i
]->gv_name
,
3783 instance_state_str
[up_svcs_p
[i
]->gv_state
]);
3788 uu_warn("%s:%d: Unexpected vertex state %d.\n",
3789 __FILE__
, __LINE__
, up_svcs_p
[i
]->gv_state
);
3796 * In the seed repository, console-login is unsatisfiable because
3797 * services are missing. To behave correctly in that case we don't want
3798 * to return false until manifest-import is online.
3801 if (manifest_import_p
== NULL
) {
3802 manifest_import_p
= vertex_get_by_name(manifest_import
);
3804 if (manifest_import_p
== NULL
)
3808 switch (manifest_import_p
->gv_state
) {
3809 case RESTARTER_STATE_ONLINE
:
3810 case RESTARTER_STATE_DEGRADED
:
3811 case RESTARTER_STATE_DISABLED
:
3812 case RESTARTER_STATE_MAINT
:
3815 case RESTARTER_STATE_OFFLINE
:
3816 if (instance_satisfied(manifest_import_p
, B_TRUE
) == -1)
3820 case RESTARTER_STATE_UNINIT
:
3828 * Runs sulogin. Returns
3830 * EALREADY - sulogin is already running
3831 * EBUSY - console-login is running
3834 run_sulogin(const char *msg
)
3838 assert(MUTEX_HELD(&dgraph_lock
));
3840 if (sulogin_running
)
3843 v
= vertex_get_by_name(console_login_fmri
);
3844 if (v
!= NULL
&& inst_running(v
))
3847 sulogin_running
= B_TRUE
;
3849 MUTEX_UNLOCK(&dgraph_lock
);
3851 fork_sulogin(B_FALSE
, msg
);
3853 MUTEX_LOCK(&dgraph_lock
);
3855 sulogin_running
= B_FALSE
;
3857 if (console_login_ready
) {
3858 v
= vertex_get_by_name(console_login_fmri
);
3860 if (v
!= NULL
&& v
->gv_state
== RESTARTER_STATE_OFFLINE
) {
3861 if (v
->gv_start_f
== NULL
)
3862 vertex_send_event(v
,
3863 RESTARTER_EVENT_TYPE_START
);
3868 console_login_ready
= B_FALSE
;
3875 * The sulogin thread runs sulogin while can_come_up() is false. run_sulogin()
3876 * keeps sulogin from stepping on console-login's toes.
3880 sulogin_thread(void *unused
)
3882 MUTEX_LOCK(&dgraph_lock
);
3884 assert(sulogin_thread_running
);
3887 (void) run_sulogin("Console login service(s) cannot run\n");
3888 } while (!can_come_up());
3890 sulogin_thread_running
= B_FALSE
;
3891 MUTEX_UNLOCK(&dgraph_lock
);
3898 single_user_thread(void *unused
)
3902 scf_instance_t
*inst
;
3903 scf_property_t
*prop
;
3909 MUTEX_LOCK(&single_user_thread_lock
);
3910 single_user_thread_count
++;
3912 if (!booting_to_single_user
)
3915 if (go_single_user_mode
|| booting_to_single_user
) {
3916 msg
= "SINGLE USER MODE\n";
3918 assert(go_to_level1
);
3920 fork_rc_script('1', "start", B_TRUE
);
3922 uu_warn("The system is ready for administration.\n");
3927 MUTEX_UNLOCK(&single_user_thread_lock
);
3930 MUTEX_LOCK(&dgraph_lock
);
3931 r
= run_sulogin(msg
);
3932 MUTEX_UNLOCK(&dgraph_lock
);
3936 assert(r
== EALREADY
|| r
== EBUSY
);
3943 MUTEX_LOCK(&single_user_thread_lock
);
3946 * If another single user thread has started, let it finish changing
3949 if (single_user_thread_count
> 1) {
3950 single_user_thread_count
--;
3951 MUTEX_UNLOCK(&single_user_thread_lock
);
3955 h
= libscf_handle_create_bound_loop();
3956 inst
= scf_instance_create(h
);
3957 prop
= safe_scf_property_create(h
);
3958 val
= safe_scf_value_create(h
);
3959 buf
= startd_alloc(max_scf_fmri_size
);
3962 if (scf_handle_decode_fmri(h
, SCF_SERVICE_STARTD
, NULL
, NULL
, inst
,
3963 NULL
, NULL
, SCF_DECODE_FMRI_EXACT
) != 0) {
3964 switch (scf_error()) {
3965 case SCF_ERROR_NOT_FOUND
:
3966 r
= libscf_create_self(h
);
3969 assert(r
== ECONNABORTED
);
3972 case SCF_ERROR_CONNECTION_BROKEN
:
3973 libscf_handle_rebind(h
);
3976 case SCF_ERROR_INVALID_ARGUMENT
:
3977 case SCF_ERROR_CONSTRAINT_VIOLATED
:
3978 case SCF_ERROR_NOT_BOUND
:
3979 case SCF_ERROR_HANDLE_MISMATCH
:
3981 bad_error("scf_handle_decode_fmri", scf_error());
3985 MUTEX_LOCK(&dgraph_lock
);
3987 r
= scf_instance_delete_prop(inst
, SCF_PG_OPTIONS_OVR
,
3988 SCF_PROPERTY_MILESTONE
);
3995 MUTEX_UNLOCK(&dgraph_lock
);
3996 libscf_handle_rebind(h
);
4002 log_error(LOG_WARNING
, "Could not clear temporary milestone: "
4003 "%s.\n", strerror(r
));
4007 bad_error("scf_instance_delete_prop", r
);
4010 MUTEX_UNLOCK(&dgraph_lock
);
4012 r
= libscf_get_milestone(inst
, prop
, val
, buf
, max_scf_fmri_size
);
4017 (void) strcpy(buf
, "all");
4021 uu_warn("Returning to milestone %s.\n", buf
);
4025 libscf_handle_rebind(h
);
4029 bad_error("libscf_get_milestone", r
);
4032 r
= dgraph_set_milestone(buf
, h
, B_FALSE
);
4042 bad_error("dgraph_set_milestone", r
);
4046 * See graph_runlevel_changed().
4048 MUTEX_LOCK(&dgraph_lock
);
4049 utmpx_set_runlevel(target_milestone_as_runlevel(), 'S', B_TRUE
);
4050 MUTEX_UNLOCK(&dgraph_lock
);
4052 startd_free(buf
, max_scf_fmri_size
);
4053 scf_value_destroy(val
);
4054 scf_property_destroy(prop
);
4055 scf_instance_destroy(inst
);
4056 scf_handle_destroy(h
);
4059 * We'll give ourselves 3 seconds to respond to all of the enablings
4060 * that setting the milestone should have created before checking
4061 * whether to run sulogin.
4067 MUTEX_LOCK(&dgraph_lock
);
4069 * Clearing these variables will allow the sulogin thread to run. We
4070 * check here in case there aren't any more state updates anytime soon.
4072 go_to_level1
= go_single_user_mode
= booting_to_single_user
= B_FALSE
;
4073 if (!sulogin_thread_running
&& !can_come_up()) {
4074 (void) startd_thread_create(sulogin_thread
, NULL
);
4075 sulogin_thread_running
= B_TRUE
;
4077 MUTEX_UNLOCK(&dgraph_lock
);
4078 single_user_thread_count
--;
4079 MUTEX_UNLOCK(&single_user_thread_lock
);
4085 * Dependency graph operations API. These are handle-independent thread-safe
4086 * graph manipulation functions which are the entry points for the event
4091 * If a configured vertex exists for inst_fmri, return EEXIST. If no vertex
4092 * exists for inst_fmri, add one. Then fetch the restarter from inst, make
4093 * this vertex dependent on it, and send _ADD_INSTANCE to the restarter.
4094 * Fetch whether the instance should be enabled from inst and send _ENABLE or
4095 * _DISABLE as appropriate. Finally rummage through inst's dependency
4096 * property groups and add vertices and edges as appropriate. If anything
4097 * goes wrong after sending _ADD_INSTANCE, send _ADMIN_MAINT_ON to put the
4098 * instance in maintenance. Don't send _START or _STOP until we get a state
4099 * update in case we're being restarted and the service is already running.
4101 * To support booting to a milestone, we must also make sure all dependencies
4102 * encountered are configured, if they exist in the repository.
4104 * Returns 0 on success, ECONNABORTED on repository disconnection, EINVAL if
4105 * inst_fmri is an invalid (or not canonical) FMRI, ECANCELED if inst is
4106 * deleted, or EEXIST if a configured vertex for inst_fmri already exists.
4109 dgraph_add_instance(const char *inst_fmri
, scf_instance_t
*inst
,
4110 boolean_t lock_graph
)
4115 if (strcmp(inst_fmri
, SCF_SERVICE_STARTD
) == 0)
4118 /* Check for a vertex for inst_fmri. */
4120 MUTEX_LOCK(&dgraph_lock
);
4122 assert(MUTEX_HELD(&dgraph_lock
));
4125 v
= vertex_get_by_name(inst_fmri
);
4128 assert(v
->gv_type
== GVT_INST
);
4130 if (v
->gv_flags
& GV_CONFIGURED
) {
4132 MUTEX_UNLOCK(&dgraph_lock
);
4136 /* Add the vertex. */
4137 err
= graph_insert_vertex_unconfigured(inst_fmri
, GVT_INST
, 0,
4140 assert(err
== EINVAL
);
4142 MUTEX_UNLOCK(&dgraph_lock
);
4147 err
= configure_vertex(v
, inst
);
4150 MUTEX_UNLOCK(&dgraph_lock
);
4156 * Locate the vertex for this property group's instance. If it doesn't exist
4157 * or is unconfigured, call dgraph_add_instance() & return. Otherwise fetch
4158 * the restarter for the instance, and if it has changed, send
4159 * _REMOVE_INSTANCE to the old restarter, remove the dependency, make sure the
4160 * new restarter has a vertex, add a new dependency, and send _ADD_INSTANCE to
4161 * the new restarter. Then fetch whether the instance should be enabled, and
4162 * if it is different from what we had, or if we changed the restarter, send
4163 * the appropriate _ENABLE or _DISABLE command.
4165 * Returns 0 on success, ENOTSUP if the pg's parent is not an instance,
4166 * ECONNABORTED on repository disconnection, ECANCELED if the instance is
4167 * deleted, or -1 if the instance's general property group is deleted or if
4168 * its enabled property is misconfigured.
4171 dgraph_update_general(scf_propertygroup_t
*pg
)
4174 scf_instance_t
*inst
;
4176 char *restarter_fmri
;
4179 int enabled
, enabled_ovr
;
4182 /* Find the vertex for this service */
4183 h
= scf_pg_handle(pg
);
4185 inst
= safe_scf_instance_create(h
);
4187 if (scf_pg_get_parent_instance(pg
, inst
) != 0) {
4188 switch (scf_error()) {
4189 case SCF_ERROR_CONSTRAINT_VIOLATED
:
4192 case SCF_ERROR_CONNECTION_BROKEN
:
4194 return (ECONNABORTED
);
4196 case SCF_ERROR_DELETED
:
4199 case SCF_ERROR_NOT_SET
:
4200 bad_error("scf_pg_get_parent_instance", scf_error());
4204 err
= libscf_instance_get_fmri(inst
, &fmri
);
4210 scf_instance_destroy(inst
);
4211 return (ECONNABORTED
);
4214 scf_instance_destroy(inst
);
4218 bad_error("libscf_instance_get_fmri", err
);
4221 log_framework(LOG_DEBUG
,
4222 "Graph engine: Reloading general properties for %s.\n", fmri
);
4224 MUTEX_LOCK(&dgraph_lock
);
4226 v
= vertex_get_by_name(fmri
);
4227 if (v
== NULL
|| !(v
->gv_flags
& GV_CONFIGURED
)) {
4228 /* Will get the up-to-date properties. */
4229 MUTEX_UNLOCK(&dgraph_lock
);
4230 err
= dgraph_add_instance(fmri
, inst
, B_TRUE
);
4231 startd_free(fmri
, max_scf_fmri_size
);
4232 scf_instance_destroy(inst
);
4233 return (err
== ECANCELED
? 0 : err
);
4236 /* Read enabled & restarter from repository. */
4237 restarter_fmri
= startd_alloc(max_scf_value_size
);
4238 err
= libscf_get_basic_instance_data(h
, inst
, v
->gv_name
, &enabled
,
4239 &enabled_ovr
, &restarter_fmri
);
4240 if (err
!= 0 || enabled
== -1) {
4241 MUTEX_UNLOCK(&dgraph_lock
);
4242 scf_instance_destroy(inst
);
4243 startd_free(fmri
, max_scf_fmri_size
);
4248 startd_free(restarter_fmri
, max_scf_value_size
);
4253 startd_free(restarter_fmri
, max_scf_value_size
);
4257 bad_error("libscf_get_basic_instance_data", err
);
4261 oldflags
= v
->gv_flags
;
4262 v
->gv_flags
= (v
->gv_flags
& ~GV_ENBLD_NOOVR
) |
4263 (enabled
? GV_ENBLD_NOOVR
: 0);
4265 if (enabled_ovr
!= -1)
4266 enabled
= enabled_ovr
;
4269 * If GV_ENBLD_NOOVR has changed, then we need to re-evaluate the
4272 if (milestone
> MILESTONE_NONE
&& v
->gv_flags
!= oldflags
)
4273 (void) eval_subgraph(v
, h
);
4275 scf_instance_destroy(inst
);
4277 /* Ignore restarter change for now. */
4279 startd_free(restarter_fmri
, max_scf_value_size
);
4280 startd_free(fmri
, max_scf_fmri_size
);
4283 * Always send _ENABLE or _DISABLE. We could avoid this if the
4284 * restarter didn't change and the enabled value didn't change, but
4285 * that's not easy to check and improbable anyway, so we'll just do
4288 graph_enable_by_vertex(v
, enabled
, 1);
4290 MUTEX_UNLOCK(&dgraph_lock
);
4296 * Delete all of the property group dependencies of v, update inst's running
4297 * snapshot, and add the dependencies in the new snapshot. If any of the new
4298 * dependencies would create a cycle, send _ADMIN_MAINT_ON. Otherwise
4299 * reevaluate v's dependencies, send _START or _STOP as appropriate, and do
4300 * the same for v's dependents.
4304 * ECONNABORTED - repository connection broken
4305 * ECANCELED - inst was deleted
4306 * EINVAL - inst is invalid (e.g., missing general/enabled)
4307 * -1 - libscf_snapshots_refresh() failed
4310 dgraph_refresh_instance(graph_vertex_t
*v
, scf_instance_t
*inst
)
4316 assert(MUTEX_HELD(&dgraph_lock
));
4317 assert(v
->gv_type
== GVT_INST
);
4319 /* Only refresh services with valid general/enabled properties. */
4320 r
= libscf_get_basic_instance_data(scf_instance_handle(inst
), inst
,
4321 v
->gv_name
, &enabled
, NULL
, NULL
);
4331 log_framework(LOG_DEBUG
,
4332 "Ignoring %s because it has no general property group.\n",
4337 bad_error("libscf_get_basic_instance_data", r
);
4340 if ((tset
= libscf_get_stn_tset(inst
)) == -1) {
4341 log_framework(LOG_WARNING
,
4342 "Failed to get notification parameters for %s: %s\n",
4343 v
->gv_name
, scf_strerror(scf_error()));
4346 v
->gv_stn_tset
= tset
;
4347 if (strcmp(v
->gv_name
, SCF_INSTANCE_GLOBAL
) == 0)
4353 r
= libscf_snapshots_refresh(inst
, v
->gv_name
);
4356 bad_error("libscf_snapshots_refresh", r
);
4362 r
= refresh_vertex(v
, inst
);
4363 if (r
!= 0 && r
!= ECONNABORTED
)
4364 bad_error("refresh_vertex", r
);
4369 * Returns true only if none of this service's dependents are 'up' -- online
4370 * or degraded (offline is considered down in this situation). This function
4371 * is somehow similar to is_nonsubgraph_leaf() but works on subtrees.
4374 insubtree_dependents_down(graph_vertex_t
*v
)
4379 assert(MUTEX_HELD(&dgraph_lock
));
4381 for (e
= uu_list_first(v
->gv_dependents
); e
!= NULL
;
4382 e
= uu_list_next(v
->gv_dependents
, e
)) {
4384 if (vv
->gv_type
== GVT_INST
) {
4385 if ((vv
->gv_flags
& GV_CONFIGURED
) == 0)
4388 if ((vv
->gv_flags
& GV_TOOFFLINE
) == 0)
4391 if ((vv
->gv_state
== RESTARTER_STATE_ONLINE
) ||
4392 (vv
->gv_state
== RESTARTER_STATE_DEGRADED
))
4396 * Skip all excluded and optional_all dependencies
4397 * and decide whether to offline the service based
4398 * on restart_on attribute.
4400 if (is_depgrp_bypassed(vv
))
4404 * For dependency groups or service vertices, keep
4405 * traversing to see if instances are running.
4407 if (insubtree_dependents_down(vv
) == B_FALSE
)
4416 * Returns true only if none of this service's dependents are 'up' -- online,
4417 * degraded, or offline.
4420 is_nonsubgraph_leaf(graph_vertex_t
*v
)
4425 assert(MUTEX_HELD(&dgraph_lock
));
4427 for (e
= uu_list_first(v
->gv_dependents
);
4429 e
= uu_list_next(v
->gv_dependents
, e
)) {
4432 if (vv
->gv_type
== GVT_INST
) {
4433 if ((vv
->gv_flags
& GV_CONFIGURED
) == 0)
4436 if (vv
->gv_flags
& GV_INSUBGRAPH
)
4439 if (up_state(vv
->gv_state
))
4443 * For dependency group or service vertices, keep
4444 * traversing to see if instances are running.
4446 * We should skip exclude_all dependencies otherwise
4447 * the vertex will never be considered as a leaf
4448 * if the dependent is offline. The main reason for
4449 * this is that disable_nonsubgraph_leaves() skips
4450 * exclusion dependencies.
4452 if (vv
->gv_type
== GVT_GROUP
&&
4453 vv
->gv_depgroup
== DEPGRP_EXCLUDE_ALL
)
4456 if (!is_nonsubgraph_leaf(vv
))
4465 * Disable v temporarily. Attempt to do this by setting its enabled override
4466 * property in the repository. If that fails, send a _DISABLE command.
4467 * Returns 0 on success and ECONNABORTED if the repository connection is
4471 disable_service_temporarily(graph_vertex_t
*v
, scf_handle_t
*h
)
4473 const char * const emsg
= "Could not temporarily disable %s because "
4474 "%s. Will stop service anyways. Repository status for the "
4475 "service may be inaccurate.\n";
4476 const char * const emsg_cbroken
=
4477 "the repository connection was broken";
4479 scf_instance_t
*inst
;
4482 inst
= scf_instance_create(h
);
4486 (void) snprintf(buf
, sizeof (buf
),
4487 "scf_instance_create() failed (%s)",
4488 scf_strerror(scf_error()));
4489 log_error(LOG_WARNING
, emsg
, v
->gv_name
, buf
);
4491 graph_enable_by_vertex(v
, 0, 0);
4495 r
= scf_handle_decode_fmri(h
, v
->gv_name
, NULL
, NULL
, inst
,
4496 NULL
, NULL
, SCF_DECODE_FMRI_EXACT
);
4498 switch (scf_error()) {
4499 case SCF_ERROR_CONNECTION_BROKEN
:
4500 log_error(LOG_WARNING
, emsg
, v
->gv_name
, emsg_cbroken
);
4501 graph_enable_by_vertex(v
, 0, 0);
4502 return (ECONNABORTED
);
4504 case SCF_ERROR_NOT_FOUND
:
4507 case SCF_ERROR_HANDLE_MISMATCH
:
4508 case SCF_ERROR_INVALID_ARGUMENT
:
4509 case SCF_ERROR_CONSTRAINT_VIOLATED
:
4510 case SCF_ERROR_NOT_BOUND
:
4512 bad_error("scf_handle_decode_fmri",
4517 r
= libscf_set_enable_ovr(inst
, 0);
4520 scf_instance_destroy(inst
);
4524 scf_instance_destroy(inst
);
4528 log_error(LOG_WARNING
, emsg
, v
->gv_name
, emsg_cbroken
);
4529 graph_enable_by_vertex(v
, 0, 0);
4530 return (ECONNABORTED
);
4533 log_error(LOG_WARNING
, emsg
, v
->gv_name
,
4534 "the repository denied permission");
4535 graph_enable_by_vertex(v
, 0, 0);
4539 log_error(LOG_WARNING
, emsg
, v
->gv_name
,
4540 "the repository is read-only");
4541 graph_enable_by_vertex(v
, 0, 0);
4545 bad_error("libscf_set_enable_ovr", r
);
4551 * Of the transitive instance dependencies of v, offline those which are
4552 * in the subtree and which are leaves (i.e., have no dependents which are
4556 offline_subtree_leaves(graph_vertex_t
*v
, void *arg
)
4558 assert(MUTEX_HELD(&dgraph_lock
));
4560 /* If v isn't an instance, recurse on its dependencies. */
4561 if (v
->gv_type
!= GVT_INST
) {
4562 graph_walk_dependencies(v
, offline_subtree_leaves
, arg
);
4567 * If v is not in the subtree, so should all of its dependencies,
4570 if ((v
->gv_flags
& GV_TOOFFLINE
) == 0)
4573 /* If v isn't a leaf because it's already down, recurse. */
4574 if (!up_state(v
->gv_state
)) {
4575 graph_walk_dependencies(v
, offline_subtree_leaves
, arg
);
4579 /* if v is a leaf, offline it or disable it if it's the last one */
4580 if (insubtree_dependents_down(v
) == B_TRUE
) {
4581 if (v
->gv_flags
& GV_TODISABLE
)
4582 vertex_send_event(v
,
4583 RESTARTER_EVENT_TYPE_ADMIN_DISABLE
);
4590 graph_offline_subtree_leaves(graph_vertex_t
*v
, void *h
)
4592 graph_walk_dependencies(v
, offline_subtree_leaves
, (void *)h
);
4597 * Of the transitive instance dependencies of v, disable those which are not
4598 * in the subgraph and which are leaves (i.e., have no dependents which are
4602 disable_nonsubgraph_leaves(graph_vertex_t
*v
, void *arg
)
4604 assert(MUTEX_HELD(&dgraph_lock
));
4607 * We must skip exclusion dependencies because they are allowed to
4608 * complete dependency cycles. This is correct because A's exclusion
4609 * dependency on B doesn't bear on the order in which they should be
4610 * stopped. Indeed, the exclusion dependency should guarantee that
4611 * they are never online at the same time.
4613 if (v
->gv_type
== GVT_GROUP
&& v
->gv_depgroup
== DEPGRP_EXCLUDE_ALL
)
4616 /* If v isn't an instance, recurse on its dependencies. */
4617 if (v
->gv_type
!= GVT_INST
)
4620 if ((v
->gv_flags
& GV_CONFIGURED
) == 0)
4622 * Unconfigured instances should have no dependencies, but in
4623 * case they ever get them,
4628 * If v is in the subgraph, so should all of its dependencies, so do
4631 if (v
->gv_flags
& GV_INSUBGRAPH
)
4634 /* If v isn't a leaf because it's already down, recurse. */
4635 if (!up_state(v
->gv_state
))
4638 /* If v is disabled but not down yet, be patient. */
4639 if ((v
->gv_flags
& GV_ENABLED
) == 0)
4642 /* If v is a leaf, disable it. */
4643 if (is_nonsubgraph_leaf(v
))
4644 (void) disable_service_temporarily(v
, (scf_handle_t
*)arg
);
4649 graph_walk_dependencies(v
, disable_nonsubgraph_leaves
, arg
);
4653 stn_restarter_state(restarter_instance_state_t rstate
)
4655 static const struct statemap
{
4656 restarter_instance_state_t restarter_state
;
4659 { RESTARTER_STATE_UNINIT
, SCF_STATE_UNINIT
},
4660 { RESTARTER_STATE_MAINT
, SCF_STATE_MAINT
},
4661 { RESTARTER_STATE_OFFLINE
, SCF_STATE_OFFLINE
},
4662 { RESTARTER_STATE_DISABLED
, SCF_STATE_DISABLED
},
4663 { RESTARTER_STATE_ONLINE
, SCF_STATE_ONLINE
},
4664 { RESTARTER_STATE_DEGRADED
, SCF_STATE_DEGRADED
}
4669 for (i
= 0; i
< sizeof (map
) / sizeof (map
[0]); i
++) {
4670 if (rstate
== map
[i
].restarter_state
)
4671 return (map
[i
].scf_state
);
4678 * State transition counters
4679 * Not incremented atomically - indicative only
4681 static uint64_t stev_ct_maint
;
4682 static uint64_t stev_ct_hwerr
;
4683 static uint64_t stev_ct_service
;
4684 static uint64_t stev_ct_global
;
4685 static uint64_t stev_ct_noprefs
;
4686 static uint64_t stev_ct_from_uninit
;
4687 static uint64_t stev_ct_bad_state
;
4688 static uint64_t stev_ct_ovr_prefs
;
4691 dgraph_state_transition_notify(graph_vertex_t
*v
,
4692 restarter_instance_state_t old_state
, restarter_str_t reason
)
4694 restarter_instance_state_t new_state
= v
->gv_state
;
4695 int stn_transition
, maint
;
4698 fmev_pri_t pri
= FMEV_LOPRI
;
4701 if ((from
= stn_restarter_state(old_state
)) == -1 ||
4702 (to
= stn_restarter_state(new_state
)) == -1) {
4703 stev_ct_bad_state
++;
4707 stn_transition
= from
<< 16 | to
;
4709 maint
= (to
== SCF_STATE_MAINT
|| from
== SCF_STATE_MAINT
);
4713 * All transitions to/from maintenance state must raise
4719 } else if (reason
== restarter_str_ct_ev_hwerr
) {
4721 * All transitions caused by hardware fault must raise
4727 } else if (stn_transition
& v
->gv_stn_tset
) {
4729 * Specifically enabled event.
4733 } else if (from
== SCF_STATE_UNINIT
) {
4735 * Only raise these if specifically selected above.
4737 stev_ct_from_uninit
++;
4738 } else if (stn_transition
& stn_global
&&
4739 (IS_ENABLED(v
) == 1 || to
== SCF_STATE_DISABLED
)) {
4746 if (info_events_all
) {
4747 stev_ct_ovr_prefs
++;
4753 if (nvlist_alloc(&attr
, NV_UNIQUE_NAME
, 0) != 0 ||
4754 nvlist_add_string(attr
, "fmri", v
->gv_name
) != 0 ||
4755 nvlist_add_uint32(attr
, "reason-version",
4756 restarter_str_version()) || nvlist_add_string(attr
, "reason-short",
4757 restarter_get_str_short(reason
)) != 0 ||
4758 nvlist_add_string(attr
, "reason-long",
4759 restarter_get_str_long(reason
)) != 0 ||
4760 nvlist_add_int32(attr
, "transition", stn_transition
) != 0) {
4761 log_framework(LOG_WARNING
,
4762 "FMEV: %s could not create nvlist for transition "
4763 "event: %s\n", v
->gv_name
, strerror(errno
));
4768 if (fmev_rspublish_nvl(FMEV_RULESET_SMF
, "state-transition",
4769 instance_state_str
[new_state
], pri
, attr
) != FMEV_SUCCESS
) {
4770 log_framework(LOG_DEBUG
,
4771 "FMEV: %s failed to publish transition event: %s\n",
4772 v
->gv_name
, fmev_strerror(fmev_errno
));
4778 * Find the vertex for inst_name. If it doesn't exist, return ENOENT.
4779 * Otherwise set its state to state. If the instance has entered a state
4780 * which requires automatic action, take it (Uninitialized: do
4781 * dgraph_refresh_instance() without the snapshot update. Disabled: if the
4782 * instance should be enabled, send _ENABLE. Offline: if the instance should
4783 * be disabled, send _DISABLE, and if its dependencies are satisfied, send
4784 * _START. Online, Degraded: if the instance wasn't running, update its start
4785 * snapshot. Maintenance: no action.)
4787 * Also fails with ECONNABORTED, or EINVAL if state is invalid.
4790 dgraph_set_instance_state(scf_handle_t
*h
, const char *inst_name
,
4791 protocol_states_t
*states
)
4795 restarter_instance_state_t old_state
;
4796 restarter_instance_state_t state
= states
->ps_state
;
4797 restarter_error_t serr
= states
->ps_err
;
4799 MUTEX_LOCK(&dgraph_lock
);
4801 v
= vertex_get_by_name(inst_name
);
4803 MUTEX_UNLOCK(&dgraph_lock
);
4807 assert(v
->gv_type
== GVT_INST
);
4810 case RESTARTER_STATE_UNINIT
:
4811 case RESTARTER_STATE_DISABLED
:
4812 case RESTARTER_STATE_OFFLINE
:
4813 case RESTARTER_STATE_ONLINE
:
4814 case RESTARTER_STATE_DEGRADED
:
4815 case RESTARTER_STATE_MAINT
:
4819 MUTEX_UNLOCK(&dgraph_lock
);
4823 log_framework(LOG_DEBUG
, "Graph noting %s %s -> %s.\n", v
->gv_name
,
4824 instance_state_str
[v
->gv_state
], instance_state_str
[state
]);
4826 old_state
= v
->gv_state
;
4827 v
->gv_state
= state
;
4829 v
->gv_reason
= states
->ps_reason
;
4830 err
= gt_transition(h
, v
, serr
, old_state
);
4831 if (err
== 0 && v
->gv_state
!= old_state
) {
4832 dgraph_state_transition_notify(v
, old_state
, states
->ps_reason
);
4835 MUTEX_UNLOCK(&dgraph_lock
);
4840 * Handle state changes during milestone shutdown. See
4841 * dgraph_set_milestone(). If the repository connection is broken,
4842 * ECONNABORTED will be returned, though a _DISABLE command will be sent for
4843 * the vertex anyway.
4846 vertex_subgraph_dependencies_shutdown(scf_handle_t
*h
, graph_vertex_t
*v
,
4847 restarter_instance_state_t old_state
)
4852 assert(v
->gv_type
== GVT_INST
);
4854 /* Don't care if we're not going to a milestone. */
4855 if (milestone
== NULL
)
4858 /* Don't care if we already finished coming down. */
4859 if (non_subgraph_svcs
== 0)
4862 /* Don't care if the service is in the subgraph. */
4863 if (v
->gv_flags
& GV_INSUBGRAPH
)
4867 * Update non_subgraph_svcs. It is the number of non-subgraph
4868 * services which are in online, degraded, or offline.
4871 was_up
= up_state(old_state
);
4872 now_up
= up_state(v
->gv_state
);
4874 if (!was_up
&& now_up
) {
4875 ++non_subgraph_svcs
;
4876 } else if (was_up
&& !now_up
) {
4877 --non_subgraph_svcs
;
4879 if (non_subgraph_svcs
== 0) {
4880 if (halting
!= -1) {
4882 } else if (go_single_user_mode
|| go_to_level1
) {
4883 (void) startd_thread_create(single_user_thread
,
4890 /* If this service is a leaf, it should be disabled. */
4891 if ((v
->gv_flags
& GV_ENABLED
) && is_nonsubgraph_leaf(v
)) {
4894 r
= disable_service_temporarily(v
, h
);
4904 bad_error("disable_service_temporarily", r
);
4909 * If the service just came down, propagate the disable to the newly
4912 if (was_up
&& !now_up
)
4913 graph_walk_dependencies(v
, disable_nonsubgraph_leaves
,
4920 * Decide whether to start up an sulogin thread after a service is
4921 * finished changing state. Only need to do the full can_come_up()
4922 * evaluation if an instance is changing state, we're not halfway through
4923 * loading the thread, and we aren't shutting down or going to the single
4927 graph_transition_sulogin(restarter_instance_state_t state
,
4928 restarter_instance_state_t old_state
)
4930 assert(MUTEX_HELD(&dgraph_lock
));
4932 if (state
!= old_state
&& st
->st_load_complete
&&
4933 !go_single_user_mode
&& !go_to_level1
&&
4935 if (!sulogin_thread_running
&& !can_come_up()) {
4936 (void) startd_thread_create(sulogin_thread
, NULL
);
4937 sulogin_thread_running
= B_TRUE
;
4943 * Propagate a start, stop event, or a satisfiability event.
4945 * PROPAGATE_START and PROPAGATE_STOP simply propagate the transition event
4946 * to direct dependents. PROPAGATE_SAT propagates a start then walks the
4947 * full dependent graph to check for newly satisfied nodes. This is
4948 * necessary for cases when non-direct dependents may be effected but direct
4949 * dependents may not (e.g. for optional_all evaluations, see the
4950 * propagate_satbility() comments).
4952 * PROPAGATE_SAT should be used whenever a non-running service moves into
4953 * a state which can satisfy optional dependencies, like disabled or
4957 graph_transition_propagate(graph_vertex_t
*v
, propagate_event_t type
,
4958 restarter_error_t rerr
)
4960 if (type
== PROPAGATE_STOP
) {
4961 graph_walk_dependents(v
, propagate_stop
, (void *)rerr
);
4962 } else if (type
== PROPAGATE_START
|| type
== PROPAGATE_SAT
) {
4963 graph_walk_dependents(v
, propagate_start
, NULL
);
4965 if (type
== PROPAGATE_SAT
)
4966 propagate_satbility(v
);
4969 uu_warn("%s:%d: Unexpected type value %d.\n", __FILE__
,
4977 * If a vertex for fmri exists and it is enabled, send _DISABLE to the
4978 * restarter. If it is running, send _STOP. Send _REMOVE_INSTANCE. Delete
4979 * all property group dependencies, and the dependency on the restarter,
4980 * disposing of vertices as appropriate. If other vertices depend on this
4981 * one, mark it unconfigured and return. Otherwise remove the vertex. Always
4985 dgraph_remove_instance(const char *fmri
, scf_handle_t
*h
)
4989 uu_list_t
*old_deps
;
4992 log_framework(LOG_DEBUG
, "Graph engine: Removing %s.\n", fmri
);
4994 MUTEX_LOCK(&dgraph_lock
);
4996 v
= vertex_get_by_name(fmri
);
4998 MUTEX_UNLOCK(&dgraph_lock
);
5002 /* Send restarter delete event. */
5003 if (v
->gv_flags
& GV_CONFIGURED
)
5004 graph_unset_restarter(v
);
5006 if (milestone
> MILESTONE_NONE
) {
5008 * Make a list of v's current dependencies so we can
5009 * reevaluate their GV_INSUBGRAPH flags after the dependencies
5012 old_deps
= startd_list_create(graph_edge_pool
, NULL
, 0);
5014 err
= uu_list_walk(v
->gv_dependencies
,
5015 (uu_walk_fn_t
*)append_svcs_or_insts
, old_deps
, 0);
5019 delete_instance_dependencies(v
, B_TRUE
);
5022 * Deleting an instance can both satisfy and unsatisfy dependencies,
5023 * depending on their type. First propagate the stop as a RERR_RESTART
5024 * event -- deletion isn't a fault, just a normal stop. This gives
5025 * dependent services the chance to do a clean shutdown. Then, mark
5026 * the service as unconfigured and propagate the start event for the
5027 * optional_all dependencies that might have become satisfied.
5029 graph_walk_dependents(v
, propagate_stop
, (void *)RERR_RESTART
);
5031 v
->gv_flags
&= ~GV_CONFIGURED
;
5032 v
->gv_flags
&= ~GV_DEATHROW
;
5034 graph_walk_dependents(v
, propagate_start
, NULL
);
5035 propagate_satbility(v
);
5038 * If there are no (non-service) dependents, the vertex can be
5039 * completely removed.
5041 if (v
!= milestone
&& v
->gv_refs
== 0 &&
5042 uu_list_numnodes(v
->gv_dependents
) == 1)
5043 remove_inst_vertex(v
);
5045 if (milestone
> MILESTONE_NONE
) {
5046 void *cookie
= NULL
;
5048 while ((e
= uu_list_teardown(old_deps
, &cookie
)) != NULL
) {
5051 if (vertex_unref(v
) == VERTEX_INUSE
)
5052 while (eval_subgraph(v
, h
) == ECONNABORTED
)
5053 libscf_handle_rebind(h
);
5055 startd_free(e
, sizeof (*e
));
5058 uu_list_destroy(old_deps
);
5061 MUTEX_UNLOCK(&dgraph_lock
);
5067 * Return the eventual (maybe current) milestone in the form of a
5071 target_milestone_as_runlevel()
5073 assert(MUTEX_HELD(&dgraph_lock
));
5075 if (milestone
== NULL
)
5077 else if (milestone
== MILESTONE_NONE
)
5080 if (strcmp(milestone
->gv_name
, multi_user_fmri
) == 0)
5082 else if (strcmp(milestone
->gv_name
, single_user_fmri
) == 0)
5084 else if (strcmp(milestone
->gv_name
, multi_user_svr_fmri
) == 0)
5088 (void) fprintf(stderr
, "%s:%d: Unknown milestone name \"%s\".\n",
5089 __FILE__
, __LINE__
, milestone
->gv_name
);
5111 signal_init(char rl
)
5116 assert(MUTEX_HELD(&dgraph_lock
));
5118 if (zone_getattr(getzoneid(), ZONE_ATTR_INITPID
, &init_pid
,
5119 sizeof (init_pid
)) != sizeof (init_pid
)) {
5120 log_error(LOG_NOTICE
, "Could not get pid to signal init.\n");
5124 for (i
= 0; init_sigs
[i
].rl
!= 0; ++i
)
5125 if (init_sigs
[i
].rl
== rl
)
5128 if (init_sigs
[i
].rl
!= 0) {
5129 if (kill(init_pid
, init_sigs
[i
].sig
) != 0) {
5133 log_error(LOG_NOTICE
, "Could not signal init: "
5134 "%s.\n", strerror(errno
));
5139 bad_error("kill", errno
);
5146 * This is called when one of the major milestones changes state, or when
5147 * init is signalled and tells us it was told to change runlevel. We wait
5148 * to reach the milestone because this allows /etc/inittab entries to retain
5149 * some boot ordering: historically, entries could place themselves before/after
5150 * the running of /sbin/rcX scripts but we can no longer make the
5151 * distinction because the /sbin/rcX scripts no longer exist as punctuation
5152 * marks in /etc/inittab.
5154 * Also, we only trigger an update when we reach the eventual target
5155 * milestone: without this, an /etc/inittab entry marked only for
5156 * runlevel 2 would be executed for runlevel 3, which is not how
5157 * /etc/inittab entries work.
5159 * If we're single user coming online, then we set utmpx to the target
5160 * runlevel so that legacy scripts can work as expected.
5163 graph_runlevel_changed(char rl
, int online
)
5167 assert(MUTEX_HELD(&dgraph_lock
));
5169 trl
= target_milestone_as_runlevel();
5173 current_runlevel
= trl
;
5175 } else if (rl
== 'S') {
5177 * At boot, set the entry early for the benefit of the
5178 * legacy init scripts.
5180 utmpx_set_runlevel(trl
, 'S', B_FALSE
);
5183 if (rl
== '3' && trl
== '2') {
5184 current_runlevel
= trl
;
5186 } else if (rl
== '2' && trl
== 'S') {
5187 current_runlevel
= trl
;
5194 * Move to a backwards-compatible runlevel by executing the appropriate
5195 * /etc/rc?.d/K* scripts and/or setting the milestone.
5199 * ECONNRESET - success, but handle was reset
5200 * ECONNABORTED - repository connection broken
5201 * ECANCELED - pg was deleted
5204 dgraph_set_runlevel(scf_propertygroup_t
*pg
, scf_property_t
*prop
)
5209 const char *ms
= NULL
; /* what to commit as options/milestone */
5210 boolean_t rebound
= B_FALSE
;
5213 const char * const stop
= "stop";
5215 r
= libscf_extract_runlevel(prop
, &rl
);
5226 log_error(LOG_WARNING
, "runlevel property is misconfigured; "
5228 /* delete the bad property */
5232 bad_error("libscf_extract_runlevel", r
);
5244 * These cases cause a milestone change, so
5245 * graph_runlevel_changed() will eventually deal with
5259 log_framework(LOG_NOTICE
, "Unknown runlevel '%c'.\n", rl
);
5264 h
= scf_pg_handle(pg
);
5266 MUTEX_LOCK(&dgraph_lock
);
5269 * Since this triggers no milestone changes, force it by hand.
5271 if (current_runlevel
== '4' && rl
== '3')
5275 * 1. If we are here after an "init X":
5278 * init/lscf_set_runlevel()
5279 * process_pg_event()
5280 * dgraph_set_runlevel()
5282 * then we haven't passed through graph_runlevel_changed() yet,
5283 * therefore 'current_runlevel' has not changed for sure but 'rl' has.
5284 * In consequence, if 'rl' is lower than 'current_runlevel', we change
5285 * the system runlevel and execute the appropriate /etc/rc?.d/K* scripts
5288 * 2. On the other hand, if we are here after a "svcadm milestone":
5290 * svcadm milestone X
5291 * dgraph_set_milestone()
5292 * handle_graph_update_event()
5293 * dgraph_set_instance_state()
5294 * graph_post_X_[online|offline]()
5295 * graph_runlevel_changed()
5297 * init/lscf_set_runlevel()
5298 * process_pg_event()
5299 * dgraph_set_runlevel()
5301 * then we already passed through graph_runlevel_changed() (by the way
5302 * of dgraph_set_milestone()) and 'current_runlevel' may have changed
5303 * and already be equal to 'rl' so we are going to return immediately
5304 * from dgraph_set_runlevel() without changing the system runlevel and
5305 * without executing the /etc/rc?.d/K* scripts.
5307 if (rl
== current_runlevel
) {
5312 log_framework(LOG_DEBUG
, "Changing to runlevel '%c'.\n", rl
);
5315 * Make sure stop rc scripts see the new settings via who -r.
5317 utmpx_set_runlevel(rl
, current_runlevel
, B_TRUE
);
5320 * Some run levels don't have a direct correspondence to any
5321 * milestones, so we have to signal init directly.
5324 current_runlevel
= rl
;
5330 uu_warn("The system is coming down for administration. "
5332 fork_rc_script(rl
, stop
, B_FALSE
);
5333 ms
= single_user_fmri
;
5334 go_single_user_mode
= B_TRUE
;
5338 halting_time
= time(NULL
);
5339 fork_rc_script(rl
, stop
, B_TRUE
);
5344 halting_time
= time(NULL
);
5345 fork_rc_script(rl
, stop
, B_TRUE
);
5346 halting
= AD_POWEROFF
;
5350 halting_time
= time(NULL
);
5351 fork_rc_script(rl
, stop
, B_TRUE
);
5352 if (scf_is_fastboot_default() && getzoneid() == GLOBAL_ZONEID
)
5353 halting
= AD_FASTREBOOT
;
5358 uu_warn("The system is coming down. Please wait.\n");
5362 * We can't wait until all services are offline since this
5363 * thread is responsible for taking them offline. Instead we
5364 * set halting to the second argument for uadmin() and call
5365 * do_uadmin() from dgraph_set_instance_state() when
5371 if (current_runlevel
!= 'S') {
5372 uu_warn("Changing to state 1.\n");
5373 fork_rc_script(rl
, stop
, B_FALSE
);
5375 uu_warn("The system is coming up for administration. "
5378 ms
= single_user_fmri
;
5379 go_to_level1
= B_TRUE
;
5383 if (current_runlevel
== '3' || current_runlevel
== '4')
5384 fork_rc_script(rl
, stop
, B_FALSE
);
5385 ms
= multi_user_fmri
;
5395 (void) fprintf(stderr
, "%s:%d: Uncaught case %d ('%c').\n",
5396 __FILE__
, __LINE__
, rl
, rl
);
5402 MUTEX_UNLOCK(&dgraph_lock
);
5405 switch (r
= libscf_clear_runlevel(pg
, ms
)) {
5410 libscf_handle_rebind(h
);
5420 log_error(LOG_NOTICE
, "Could not delete \"%s/%s\" property: "
5421 "%s.\n", SCF_PG_OPTIONS
, "runlevel", strerror(r
));
5425 bad_error("libscf_clear_runlevel", r
);
5428 return (rebound
? ECONNRESET
: 0);
5432 * mark_subtree walks the dependents and add the GV_TOOFFLINE flag
5433 * to the instances that are supposed to go offline during an
5434 * administrative disable operation.
5437 mark_subtree(graph_edge_t
*e
, void *arg
)
5444 /* If it's already in the subgraph, skip. */
5445 if (v
->gv_flags
& GV_TOOFFLINE
)
5446 return (UU_WALK_NEXT
);
5448 switch (v
->gv_type
) {
5450 /* If the instance is already disabled, skip it. */
5451 if (!(v
->gv_flags
& GV_ENABLED
))
5452 return (UU_WALK_NEXT
);
5454 v
->gv_flags
|= GV_TOOFFLINE
;
5455 log_framework(LOG_DEBUG
, "%s added to subtree\n", v
->gv_name
);
5459 * Skip all excluded and optional_all dependencies and decide
5460 * whether to offline the service based on restart_on attribute.
5462 if (is_depgrp_bypassed(v
))
5463 return (UU_WALK_NEXT
);
5467 r
= uu_list_walk(v
->gv_dependents
, (uu_walk_fn_t
*)mark_subtree
, arg
,
5470 return (UU_WALK_NEXT
);
5474 mark_subgraph(graph_edge_t
*e
, void *arg
)
5478 int optional
= (int)arg
;
5482 /* If it's already in the subgraph, skip. */
5483 if (v
->gv_flags
& GV_INSUBGRAPH
)
5484 return (UU_WALK_NEXT
);
5487 * Keep track if walk has entered an optional dependency group
5489 if (v
->gv_type
== GVT_GROUP
&& v
->gv_depgroup
== DEPGRP_OPTIONAL_ALL
) {
5493 * Quit if we are in an optional dependency group and the instance
5496 if (optional
&& (v
->gv_type
== GVT_INST
) &&
5497 (!(v
->gv_flags
& GV_ENBLD_NOOVR
)))
5498 return (UU_WALK_NEXT
);
5500 v
->gv_flags
|= GV_INSUBGRAPH
;
5502 /* Skip all excluded dependencies. */
5503 if (v
->gv_type
== GVT_GROUP
&& v
->gv_depgroup
== DEPGRP_EXCLUDE_ALL
)
5504 return (UU_WALK_NEXT
);
5506 r
= uu_list_walk(v
->gv_dependencies
, (uu_walk_fn_t
*)mark_subgraph
,
5507 (void *)optional
, 0);
5509 return (UU_WALK_NEXT
);
5513 * Bring down all services which are not dependencies of fmri. The
5514 * dependencies of fmri (direct & indirect) will constitute the "subgraph",
5515 * and will have the GV_INSUBGRAPH flag set. The rest must be brought down,
5516 * which means the state is "disabled", "maintenance", or "uninitialized". We
5517 * could consider "offline" to be down, and refrain from sending start
5518 * commands for such services, but that's not strictly necessary, so we'll
5519 * decline to intrude on the state machine. It would probably confuse users
5522 * The services should be brought down in reverse-dependency order, so we
5523 * can't do it all at once here. We initiate by override-disabling the leaves
5524 * of the dependency tree -- those services which are up but have no
5525 * dependents which are up. When they come down,
5526 * vertex_subgraph_dependencies_shutdown() will override-disable the newly
5527 * exposed leaves. Perseverance will ensure completion.
5529 * Sometimes we need to take action when the transition is complete, like
5530 * start sulogin or halt the system. To tell when we're done, we initialize
5531 * non_subgraph_svcs here to be the number of services which need to come
5532 * down. As each does, we decrement the counter. When it hits zero, we take
5533 * the appropriate action. See vertex_subgraph_dependencies_shutdown().
5535 * In case we're coming up, we also remove any enable-overrides for the
5536 * services which are dependencies of fmri.
5538 * If norepository is true, the function will not change the repository.
5540 * The decision to change the system run level in accordance with the milestone
5541 * is taken in dgraph_set_runlevel().
5545 * ECONNRESET - success, but handle was rebound
5546 * EINVAL - fmri is invalid (error is logged)
5547 * EALREADY - the milestone is already set to fmri
5548 * ENOENT - a configured vertex does not exist for fmri (an error is logged)
5551 dgraph_set_milestone(const char *fmri
, scf_handle_t
*h
, boolean_t norepository
)
5553 const char *cfmri
, *fs
;
5554 graph_vertex_t
*nm
, *v
;
5556 scf_instance_t
*inst
;
5557 boolean_t isall
, isnone
, rebound
= B_FALSE
;
5560 isall
= (strcmp(fmri
, "all") == 0);
5561 isnone
= (strcmp(fmri
, "none") == 0);
5563 if (!isall
&& !isnone
) {
5564 if (fmri_canonify(fmri
, (char **)&cfmri
, B_FALSE
) == EINVAL
)
5567 if (strcmp(cfmri
, single_user_fmri
) != 0 &&
5568 strcmp(cfmri
, multi_user_fmri
) != 0 &&
5569 strcmp(cfmri
, multi_user_svr_fmri
) != 0) {
5570 startd_free((void *)cfmri
, max_scf_fmri_size
);
5572 log_framework(LOG_WARNING
,
5573 "Rejecting request for invalid milestone \"%s\".\n",
5579 inst
= safe_scf_instance_create(h
);
5581 MUTEX_LOCK(&dgraph_lock
);
5583 if (milestone
== NULL
) {
5585 log_framework(LOG_DEBUG
,
5586 "Milestone already set to all.\n");
5590 } else if (milestone
== MILESTONE_NONE
) {
5592 log_framework(LOG_DEBUG
,
5593 "Milestone already set to none.\n");
5598 if (!isall
&& !isnone
&&
5599 strcmp(cfmri
, milestone
->gv_name
) == 0) {
5600 log_framework(LOG_DEBUG
,
5601 "Milestone already set to %s.\n", cfmri
);
5607 if (!isall
&& !isnone
) {
5608 nm
= vertex_get_by_name(cfmri
);
5609 if (nm
== NULL
|| !(nm
->gv_flags
& GV_CONFIGURED
)) {
5610 log_framework(LOG_WARNING
, "Cannot set milestone to %s "
5611 "because no such service exists.\n", cfmri
);
5617 log_framework(LOG_DEBUG
, "Changing milestone to %s.\n", fmri
);
5620 * Set milestone, removing the old one if this was the last reference.
5622 if (milestone
> MILESTONE_NONE
)
5623 (void) vertex_unref(milestone
);
5628 milestone
= MILESTONE_NONE
;
5631 /* milestone should count as a reference */
5632 vertex_ref(milestone
);
5635 /* Clear all GV_INSUBGRAPH bits. */
5636 for (v
= uu_list_first(dgraph
); v
!= NULL
; v
= uu_list_next(dgraph
, v
))
5637 v
->gv_flags
&= ~GV_INSUBGRAPH
;
5639 if (!isall
&& !isnone
) {
5640 /* Set GV_INSUBGRAPH for milestone & descendents. */
5641 milestone
->gv_flags
|= GV_INSUBGRAPH
;
5643 r
= uu_list_walk(milestone
->gv_dependencies
,
5644 (uu_walk_fn_t
*)mark_subgraph
, NULL
, 0);
5648 /* Un-override services in the subgraph & override-disable the rest. */
5652 non_subgraph_svcs
= 0;
5653 for (v
= uu_list_first(dgraph
);
5655 v
= uu_list_next(dgraph
, v
)) {
5656 if (v
->gv_type
!= GVT_INST
||
5657 (v
->gv_flags
& GV_CONFIGURED
) == 0)
5661 r
= scf_handle_decode_fmri(h
, v
->gv_name
, NULL
, NULL
, inst
,
5662 NULL
, NULL
, SCF_DECODE_FMRI_EXACT
);
5664 switch (scf_error()) {
5665 case SCF_ERROR_CONNECTION_BROKEN
:
5667 libscf_handle_rebind(h
);
5671 case SCF_ERROR_NOT_FOUND
:
5674 case SCF_ERROR_HANDLE_MISMATCH
:
5675 case SCF_ERROR_INVALID_ARGUMENT
:
5676 case SCF_ERROR_CONSTRAINT_VIOLATED
:
5677 case SCF_ERROR_NOT_BOUND
:
5678 bad_error("scf_handle_decode_fmri",
5683 if (isall
|| (v
->gv_flags
& GV_INSUBGRAPH
)) {
5684 r
= libscf_delete_enable_ovr(inst
);
5685 fs
= "libscf_delete_enable_ovr";
5687 assert(isnone
|| (v
->gv_flags
& GV_INSUBGRAPH
) == 0);
5690 * Services which are up need to come down before
5691 * we're done, but we can only disable the leaves
5695 if (up_state(v
->gv_state
))
5696 ++non_subgraph_svcs
;
5698 /* If it's already disabled, don't bother. */
5699 if ((v
->gv_flags
& GV_ENABLED
) == 0)
5702 if (!is_nonsubgraph_leaf(v
))
5705 r
= libscf_set_enable_ovr(inst
, 0);
5706 fs
= "libscf_set_enable_ovr";
5714 libscf_handle_rebind(h
);
5720 log_error(LOG_WARNING
,
5721 "Could not set %s/%s for %s: %s.\n",
5722 SCF_PG_GENERAL_OVR
, SCF_PROPERTY_ENABLED
,
5723 v
->gv_name
, strerror(r
));
5731 if (halting
!= -1) {
5732 if (non_subgraph_svcs
> 1)
5733 uu_warn("%d system services are now being stopped.\n",
5735 else if (non_subgraph_svcs
== 1)
5736 uu_warn("One system service is now being stopped.\n");
5737 else if (non_subgraph_svcs
== 0)
5741 ret
= rebound
? ECONNRESET
: 0;
5744 MUTEX_UNLOCK(&dgraph_lock
);
5745 if (!isall
&& !isnone
)
5746 startd_free((void *)cfmri
, max_scf_fmri_size
);
5747 scf_instance_destroy(inst
);
5753 * Returns 0, ECONNABORTED, or EINVAL.
5756 handle_graph_update_event(scf_handle_t
*h
, graph_protocol_event_t
*e
)
5760 switch (e
->gpe_type
) {
5761 case GRAPH_UPDATE_RELOAD_GRAPH
:
5762 log_error(LOG_WARNING
,
5763 "graph_event: reload graph unimplemented\n");
5766 case GRAPH_UPDATE_STATE_CHANGE
: {
5767 protocol_states_t
*states
= e
->gpe_data
;
5769 switch (r
= dgraph_set_instance_state(h
, e
->gpe_inst
, states
)) {
5775 return (ECONNABORTED
);
5780 (void) fprintf(stderr
, "dgraph_set_instance_state() "
5781 "failed with unexpected error %d at %s:%d.\n", r
,
5782 __FILE__
, __LINE__
);
5787 startd_free(states
, sizeof (protocol_states_t
));
5792 log_error(LOG_WARNING
,
5793 "graph_event_loop received an unknown event: %d\n",
5802 * graph_event_thread()
5803 * Wait for state changes from the restarters.
5807 graph_event_thread(void *unused
)
5812 h
= libscf_handle_create_bound_loop();
5816 graph_protocol_event_t
*e
;
5818 MUTEX_LOCK(&gu
->gu_lock
);
5820 while (gu
->gu_wakeup
== 0)
5821 (void) pthread_cond_wait(&gu
->gu_cv
, &gu
->gu_lock
);
5825 while ((e
= graph_event_dequeue()) != NULL
) {
5826 MUTEX_LOCK(&e
->gpe_lock
);
5827 MUTEX_UNLOCK(&gu
->gu_lock
);
5829 while ((err
= handle_graph_update_event(h
, e
)) ==
5831 libscf_handle_rebind(h
);
5834 graph_event_release(e
);
5836 graph_event_requeue(e
);
5838 MUTEX_LOCK(&gu
->gu_lock
);
5841 MUTEX_UNLOCK(&gu
->gu_lock
);
5845 * Unreachable for now -- there's currently no graceful cleanup
5848 MUTEX_UNLOCK(&gu
->gu_lock
);
5849 scf_handle_destroy(h
);
5854 set_initial_milestone(scf_handle_t
*h
)
5856 scf_instance_t
*inst
;
5861 inst
= safe_scf_instance_create(h
);
5862 fmri
= startd_alloc(max_scf_fmri_size
);
5865 * If -m milestone= was specified, we want to set options_ovr/milestone
5866 * to it. Otherwise we want to read what the milestone should be set
5867 * to. Either way we need our inst.
5870 if (scf_handle_decode_fmri(h
, SCF_SERVICE_STARTD
, NULL
, NULL
, inst
,
5871 NULL
, NULL
, SCF_DECODE_FMRI_EXACT
) != 0) {
5872 switch (scf_error()) {
5873 case SCF_ERROR_CONNECTION_BROKEN
:
5874 libscf_handle_rebind(h
);
5877 case SCF_ERROR_NOT_FOUND
:
5878 if (st
->st_subgraph
!= NULL
&&
5879 st
->st_subgraph
[0] != '\0') {
5880 sz
= strlcpy(fmri
, st
->st_subgraph
,
5882 assert(sz
< max_scf_fmri_size
);
5888 case SCF_ERROR_INVALID_ARGUMENT
:
5889 case SCF_ERROR_CONSTRAINT_VIOLATED
:
5890 case SCF_ERROR_HANDLE_MISMATCH
:
5892 bad_error("scf_handle_decode_fmri", scf_error());
5895 if (st
->st_subgraph
!= NULL
&& st
->st_subgraph
[0] != '\0') {
5896 scf_propertygroup_t
*pg
;
5898 pg
= safe_scf_pg_create(h
);
5900 sz
= strlcpy(fmri
, st
->st_subgraph
, max_scf_fmri_size
);
5901 assert(sz
< max_scf_fmri_size
);
5903 r
= libscf_inst_get_or_add_pg(inst
, SCF_PG_OPTIONS_OVR
,
5904 SCF_PG_OPTIONS_OVR_TYPE
, SCF_PG_OPTIONS_OVR_FLAGS
,
5911 libscf_handle_rebind(h
);
5917 log_error(LOG_WARNING
, "Could not set %s/%s: "
5918 "%s.\n", SCF_PG_OPTIONS_OVR
,
5919 SCF_PROPERTY_MILESTONE
, strerror(r
));
5923 sz
= strlcpy(fmri
, st
->st_subgraph
,
5925 assert(sz
< max_scf_fmri_size
);
5929 bad_error("libscf_inst_get_or_add_pg", r
);
5932 r
= libscf_clear_runlevel(pg
, fmri
);
5938 libscf_handle_rebind(h
);
5944 log_error(LOG_WARNING
, "Could not set %s/%s: "
5945 "%s.\n", SCF_PG_OPTIONS_OVR
,
5946 SCF_PROPERTY_MILESTONE
, strerror(r
));
5950 sz
= strlcpy(fmri
, st
->st_subgraph
,
5952 assert(sz
< max_scf_fmri_size
);
5956 bad_error("libscf_clear_runlevel", r
);
5961 scf_property_t
*prop
;
5964 prop
= safe_scf_property_create(h
);
5965 val
= safe_scf_value_create(h
);
5967 r
= libscf_get_milestone(inst
, prop
, val
, fmri
,
5974 libscf_handle_rebind(h
);
5978 log_error(LOG_WARNING
, "Milestone property is "
5979 "misconfigured. Defaulting to \"all\".\n");
5988 bad_error("libscf_get_milestone", r
);
5991 scf_value_destroy(val
);
5992 scf_property_destroy(prop
);
5996 if (fmri
[0] == '\0' || strcmp(fmri
, "all") == 0)
5999 if (strcmp(fmri
, "none") != 0) {
6001 if (scf_handle_decode_fmri(h
, fmri
, NULL
, NULL
, inst
, NULL
,
6002 NULL
, SCF_DECODE_FMRI_EXACT
) != 0) {
6003 switch (scf_error()) {
6004 case SCF_ERROR_INVALID_ARGUMENT
:
6005 log_error(LOG_WARNING
,
6006 "Requested milestone \"%s\" is invalid. "
6007 "Reverting to \"all\".\n", fmri
);
6010 case SCF_ERROR_CONSTRAINT_VIOLATED
:
6011 log_error(LOG_WARNING
, "Requested milestone "
6012 "\"%s\" does not specify an instance. "
6013 "Reverting to \"all\".\n", fmri
);
6016 case SCF_ERROR_CONNECTION_BROKEN
:
6017 libscf_handle_rebind(h
);
6020 case SCF_ERROR_NOT_FOUND
:
6021 log_error(LOG_WARNING
, "Requested milestone "
6022 "\"%s\" not in repository. Reverting to "
6023 "\"all\".\n", fmri
);
6026 case SCF_ERROR_HANDLE_MISMATCH
:
6028 bad_error("scf_handle_decode_fmri",
6033 r
= fmri_canonify(fmri
, &cfmri
, B_FALSE
);
6036 r
= dgraph_add_instance(cfmri
, inst
, B_TRUE
);
6037 startd_free(cfmri
, max_scf_fmri_size
);
6046 log_error(LOG_WARNING
,
6047 "Requested milestone \"%s\" is invalid. "
6048 "Reverting to \"all\".\n", fmri
);
6052 log_error(LOG_WARNING
,
6053 "Requested milestone \"%s\" not "
6054 "in repository. Reverting to \"all\".\n",
6060 bad_error("dgraph_add_instance", r
);
6064 log_console(LOG_INFO
, "Booting to milestone \"%s\".\n", fmri
);
6066 r
= dgraph_set_milestone(fmri
, h
, B_FALSE
);
6076 bad_error("dgraph_set_milestone", r
);
6080 startd_free(fmri
, max_scf_fmri_size
);
6081 scf_instance_destroy(inst
);
6085 set_restart_milestone(scf_handle_t
*h
)
6087 scf_instance_t
*inst
;
6088 scf_property_t
*prop
;
6093 inst
= safe_scf_instance_create(h
);
6096 if (scf_handle_decode_fmri(h
, SCF_SERVICE_STARTD
, NULL
, NULL
,
6097 inst
, NULL
, NULL
, SCF_DECODE_FMRI_EXACT
) != 0) {
6098 switch (scf_error()) {
6099 case SCF_ERROR_CONNECTION_BROKEN
:
6100 libscf_handle_rebind(h
);
6103 case SCF_ERROR_NOT_FOUND
:
6106 case SCF_ERROR_INVALID_ARGUMENT
:
6107 case SCF_ERROR_CONSTRAINT_VIOLATED
:
6108 case SCF_ERROR_HANDLE_MISMATCH
:
6110 bad_error("scf_handle_decode_fmri", scf_error());
6113 scf_instance_destroy(inst
);
6117 prop
= safe_scf_property_create(h
);
6118 val
= safe_scf_value_create(h
);
6119 fmri
= startd_alloc(max_scf_fmri_size
);
6121 r
= libscf_get_milestone(inst
, prop
, val
, fmri
, max_scf_fmri_size
);
6127 libscf_handle_rebind(h
);
6136 bad_error("libscf_get_milestone", r
);
6139 r
= dgraph_set_milestone(fmri
, h
, B_TRUE
);
6149 bad_error("dgraph_set_milestone", r
);
6153 startd_free(fmri
, max_scf_fmri_size
);
6154 scf_value_destroy(val
);
6155 scf_property_destroy(prop
);
6156 scf_instance_destroy(inst
);
6160 * void *graph_thread(void *)
6162 * Graph management thread.
6166 graph_thread(void *arg
)
6171 h
= libscf_handle_create_bound_loop();
6174 set_initial_milestone(h
);
6176 MUTEX_LOCK(&dgraph_lock
);
6177 initial_milestone_set
= B_TRUE
;
6178 err
= pthread_cond_broadcast(&initial_milestone_cv
);
6180 MUTEX_UNLOCK(&dgraph_lock
);
6182 libscf_populate_graph(h
);
6184 if (!st
->st_initial
)
6185 set_restart_milestone(h
);
6187 MUTEX_LOCK(&st
->st_load_lock
);
6188 st
->st_load_complete
= 1;
6189 (void) pthread_cond_broadcast(&st
->st_load_cv
);
6190 MUTEX_UNLOCK(&st
->st_load_lock
);
6192 MUTEX_LOCK(&dgraph_lock
);
6194 * Now that we've set st_load_complete we need to check can_come_up()
6195 * since if we booted to a milestone, then there won't be any more
6198 if (!go_single_user_mode
&& !go_to_level1
&&
6200 if (!sulogin_thread_running
&& !can_come_up()) {
6201 (void) startd_thread_create(sulogin_thread
, NULL
);
6202 sulogin_thread_running
= B_TRUE
;
6205 MUTEX_UNLOCK(&dgraph_lock
);
6207 (void) pthread_mutex_lock(&gu
->gu_freeze_lock
);
6211 (void) pthread_cond_wait(&gu
->gu_freeze_cv
,
6212 &gu
->gu_freeze_lock
);
6216 * Unreachable for now -- there's currently no graceful cleanup
6219 (void) pthread_mutex_unlock(&gu
->gu_freeze_lock
);
6220 scf_handle_destroy(h
);
6228 * Given an array of timestamps 'a' with 'num' elements, find the
6229 * lowest non-zero timestamp and return its index. If there are no
6230 * non-zero elements, return -1.
6233 next_action(hrtime_t
*a
, int num
)
6236 int i
= 0, smallest
= -1;
6238 for (i
= 0; i
< num
; i
++) {
6242 } else if (a
[i
] != 0 && a
[i
] < t
) {
6255 * void process_actions()
6256 * Process actions requested by the administrator. Possibilities include:
6257 * refresh, restart, maintenance mode off, maintenance mode on,
6258 * maintenance mode immediate, and degraded.
6260 * The set of pending actions is represented in the repository as a
6261 * per-instance property group, with each action being a single property
6262 * in that group. This property group is converted to an array, with each
6263 * action type having an array slot. The actions in the array at the
6264 * time process_actions() is called are acted on in the order of the
6265 * timestamp (which is the value stored in the slot). A value of zero
6266 * indicates that there is no pending action of the type associated with
6267 * a particular slot.
6269 * Sending an action event multiple times before the restarter has a
6270 * chance to process that action will force it to be run at the last
6271 * timestamp where it appears in the ordering.
6273 * Turning maintenance mode on trumps all other actions.
6275 * Returns 0 or ECONNABORTED.
6278 process_actions(scf_handle_t
*h
, scf_propertygroup_t
*pg
, scf_instance_t
*inst
)
6280 scf_property_t
*prop
= NULL
;
6281 scf_value_t
*val
= NULL
;
6283 graph_vertex_t
*vertex
;
6286 hrtime_t action_ts
[NACTIONS
];
6289 r
= libscf_instance_get_fmri(inst
, &inst_name
);
6295 return (ECONNABORTED
);
6301 bad_error("libscf_instance_get_fmri", r
);
6304 MUTEX_LOCK(&dgraph_lock
);
6306 vertex
= vertex_get_by_name(inst_name
);
6307 if (vertex
== NULL
) {
6308 MUTEX_UNLOCK(&dgraph_lock
);
6309 log_framework(LOG_DEBUG
, "%s: Can't find graph vertex. "
6310 "The instance must have been removed.\n", inst_name
);
6311 startd_free(inst_name
, max_scf_fmri_size
);
6315 prop
= safe_scf_property_create(h
);
6316 val
= safe_scf_value_create(h
);
6318 for (i
= 0; i
< NACTIONS
; i
++) {
6319 if (scf_pg_get_property(pg
, admin_actions
[i
], prop
) != 0) {
6320 switch (scf_error()) {
6321 case SCF_ERROR_CONNECTION_BROKEN
:
6326 case SCF_ERROR_DELETED
:
6329 case SCF_ERROR_NOT_FOUND
:
6333 case SCF_ERROR_HANDLE_MISMATCH
:
6334 case SCF_ERROR_INVALID_ARGUMENT
:
6335 case SCF_ERROR_NOT_SET
:
6336 bad_error("scf_pg_get_property", scf_error());
6340 if (scf_property_type(prop
, &type
) != 0) {
6341 switch (scf_error()) {
6342 case SCF_ERROR_CONNECTION_BROKEN
:
6347 case SCF_ERROR_DELETED
:
6351 case SCF_ERROR_NOT_SET
:
6352 bad_error("scf_property_type", scf_error());
6356 if (type
!= SCF_TYPE_INTEGER
) {
6361 if (scf_property_get_value(prop
, val
) != 0) {
6362 switch (scf_error()) {
6363 case SCF_ERROR_CONNECTION_BROKEN
:
6368 case SCF_ERROR_DELETED
:
6371 case SCF_ERROR_NOT_FOUND
:
6372 case SCF_ERROR_CONSTRAINT_VIOLATED
:
6376 case SCF_ERROR_NOT_SET
:
6377 case SCF_ERROR_PERMISSION_DENIED
:
6378 bad_error("scf_property_get_value",
6383 r
= scf_value_get_integer(val
, &action_ts
[i
]);
6387 a
= ADMIN_EVENT_MAINT_ON_IMMEDIATE
;
6388 if (action_ts
[ADMIN_EVENT_MAINT_ON_IMMEDIATE
] ||
6389 action_ts
[ADMIN_EVENT_MAINT_ON
]) {
6390 a
= action_ts
[ADMIN_EVENT_MAINT_ON_IMMEDIATE
] ?
6391 ADMIN_EVENT_MAINT_ON_IMMEDIATE
: ADMIN_EVENT_MAINT_ON
;
6393 vertex_send_event(vertex
, admin_events
[a
]);
6394 r
= libscf_unset_action(h
, pg
, a
, action_ts
[a
]);
6405 uu_die("Insufficient privilege.\n");
6409 bad_error("libscf_unset_action", r
);
6413 while ((a
= next_action(action_ts
, NACTIONS
)) != -1) {
6414 log_framework(LOG_DEBUG
,
6415 "Graph: processing %s action for %s.\n", admin_actions
[a
],
6418 if (a
== ADMIN_EVENT_REFRESH
) {
6419 r
= dgraph_refresh_instance(vertex
, inst
);
6428 /* pg & inst are reset now, so just return. */
6433 bad_error("dgraph_refresh_instance", r
);
6437 vertex_send_event(vertex
, admin_events
[a
]);
6439 r
= libscf_unset_action(h
, pg
, a
, action_ts
[a
]);
6450 uu_die("Insufficient privilege.\n");
6454 bad_error("libscf_unset_action", r
);
6461 MUTEX_UNLOCK(&dgraph_lock
);
6463 scf_property_destroy(prop
);
6464 scf_value_destroy(val
);
6465 startd_free(inst_name
, max_scf_fmri_size
);
6470 * inst and pg_name are scratch space, and are unset on entry.
6473 * ECONNRESET - success, but repository handle rebound
6474 * ECONNABORTED - repository connection broken
6477 process_pg_event(scf_handle_t
*h
, scf_propertygroup_t
*pg
, scf_instance_t
*inst
,
6481 scf_property_t
*prop
;
6484 boolean_t rebound
= B_FALSE
, rebind_inst
= B_FALSE
;
6486 if (scf_pg_get_name(pg
, pg_name
, max_scf_value_size
) < 0) {
6487 switch (scf_error()) {
6488 case SCF_ERROR_CONNECTION_BROKEN
:
6490 return (ECONNABORTED
);
6492 case SCF_ERROR_DELETED
:
6495 case SCF_ERROR_NOT_SET
:
6496 bad_error("scf_pg_get_name", scf_error());
6500 if (strcmp(pg_name
, SCF_PG_GENERAL
) == 0 ||
6501 strcmp(pg_name
, SCF_PG_GENERAL_OVR
) == 0) {
6502 r
= dgraph_update_general(pg
);
6510 return (ECONNABORTED
);
6513 /* Error should have been logged. */
6517 bad_error("dgraph_update_general", r
);
6519 } else if (strcmp(pg_name
, SCF_PG_RESTARTER_ACTIONS
) == 0) {
6520 if (scf_pg_get_parent_instance(pg
, inst
) != 0) {
6521 switch (scf_error()) {
6522 case SCF_ERROR_CONNECTION_BROKEN
:
6523 return (ECONNABORTED
);
6525 case SCF_ERROR_DELETED
:
6526 case SCF_ERROR_CONSTRAINT_VIOLATED
:
6527 /* Ignore commands on services. */
6530 case SCF_ERROR_NOT_BOUND
:
6531 case SCF_ERROR_HANDLE_MISMATCH
:
6532 case SCF_ERROR_NOT_SET
:
6534 bad_error("scf_pg_get_parent_instance",
6539 return (process_actions(h
, pg
, inst
));
6542 if (strcmp(pg_name
, SCF_PG_OPTIONS
) != 0 &&
6543 strcmp(pg_name
, SCF_PG_OPTIONS_OVR
) != 0)
6547 * We only care about the options[_ovr] property groups of our own
6548 * instance, so get the fmri and compare. Plus, once we know it's
6549 * correct, if the repository connection is broken we know exactly what
6550 * property group we were operating on, and can look it up again.
6552 if (scf_pg_get_parent_instance(pg
, inst
) != 0) {
6553 switch (scf_error()) {
6554 case SCF_ERROR_CONNECTION_BROKEN
:
6555 return (ECONNABORTED
);
6557 case SCF_ERROR_DELETED
:
6558 case SCF_ERROR_CONSTRAINT_VIOLATED
:
6561 case SCF_ERROR_HANDLE_MISMATCH
:
6562 case SCF_ERROR_NOT_BOUND
:
6563 case SCF_ERROR_NOT_SET
:
6565 bad_error("scf_pg_get_parent_instance",
6570 switch (r
= libscf_instance_get_fmri(inst
, &fmri
)) {
6575 return (ECONNABORTED
);
6581 bad_error("libscf_instance_get_fmri", r
);
6584 if (strcmp(fmri
, SCF_SERVICE_STARTD
) != 0) {
6585 startd_free(fmri
, max_scf_fmri_size
);
6590 * update the information events flag
6592 if (strcmp(pg_name
, SCF_PG_OPTIONS
) == 0)
6593 info_events_all
= libscf_get_info_events_all(pg
);
6595 prop
= safe_scf_property_create(h
);
6596 val
= safe_scf_value_create(h
);
6598 if (strcmp(pg_name
, SCF_PG_OPTIONS_OVR
) == 0) {
6599 /* See if we need to set the runlevel. */
6603 libscf_handle_rebind(h
);
6606 r
= libscf_lookup_instance(SCF_SERVICE_STARTD
, inst
);
6619 bad_error("libscf_lookup_instance", r
);
6622 if (scf_instance_get_pg(inst
, pg_name
, pg
) != 0) {
6623 switch (scf_error()) {
6624 case SCF_ERROR_DELETED
:
6625 case SCF_ERROR_NOT_FOUND
:
6628 case SCF_ERROR_CONNECTION_BROKEN
:
6631 case SCF_ERROR_HANDLE_MISMATCH
:
6632 case SCF_ERROR_NOT_BOUND
:
6633 case SCF_ERROR_NOT_SET
:
6634 case SCF_ERROR_INVALID_ARGUMENT
:
6636 bad_error("scf_instance_get_pg",
6642 if (scf_pg_get_property(pg
, "runlevel", prop
) == 0) {
6643 r
= dgraph_set_runlevel(pg
, prop
);
6647 rebind_inst
= B_TRUE
;
6660 bad_error("dgraph_set_runlevel", r
);
6663 switch (scf_error()) {
6664 case SCF_ERROR_CONNECTION_BROKEN
:
6668 case SCF_ERROR_DELETED
:
6671 case SCF_ERROR_NOT_FOUND
:
6674 case SCF_ERROR_INVALID_ARGUMENT
:
6675 case SCF_ERROR_HANDLE_MISMATCH
:
6676 case SCF_ERROR_NOT_BOUND
:
6677 case SCF_ERROR_NOT_SET
:
6678 bad_error("scf_pg_get_property", scf_error());
6685 r
= libscf_lookup_instance(SCF_SERVICE_STARTD
, inst
);
6691 libscf_handle_rebind(h
);
6700 bad_error("libscf_lookup_instance", r
);
6704 r
= libscf_get_milestone(inst
, prop
, val
, fmri
, max_scf_fmri_size
);
6710 libscf_handle_rebind(h
);
6715 log_error(LOG_NOTICE
,
6716 "%s/%s property of %s is misconfigured.\n", pg_name
,
6717 SCF_PROPERTY_MILESTONE
, SCF_SERVICE_STARTD
);
6722 (void) strcpy(fmri
, "all");
6726 bad_error("libscf_get_milestone", r
);
6729 r
= dgraph_set_milestone(fmri
, h
, B_FALSE
);
6737 log_error(LOG_WARNING
, "Milestone %s is invalid.\n", fmri
);
6741 log_error(LOG_WARNING
, "Milestone %s does not exist.\n", fmri
);
6745 bad_error("dgraph_set_milestone", r
);
6749 startd_free(fmri
, max_scf_fmri_size
);
6750 scf_value_destroy(val
);
6751 scf_property_destroy(prop
);
6753 return (rebound
? ECONNRESET
: 0);
6757 * process_delete() deletes an instance from the dgraph if 'fmri' is an
6758 * instance fmri or if 'fmri' matches the 'general' property group of an
6759 * instance (or the 'general/enabled' property).
6761 * 'fmri' may be overwritten and cannot be trusted on return by the caller.
6764 process_delete(char *fmri
, scf_handle_t
*h
)
6766 char *lfmri
, *end_inst_fmri
;
6767 const char *inst_name
= NULL
;
6768 const char *pg_name
= NULL
;
6769 const char *prop_name
= NULL
;
6771 lfmri
= safe_strdup(fmri
);
6773 /* Determine if the FMRI is a property group or instance */
6774 if (scf_parse_svc_fmri(lfmri
, NULL
, NULL
, &inst_name
, &pg_name
,
6775 &prop_name
) != SCF_SUCCESS
) {
6776 log_error(LOG_WARNING
,
6777 "Received invalid FMRI \"%s\" from repository server.\n",
6779 } else if (inst_name
!= NULL
&& pg_name
== NULL
) {
6780 (void) dgraph_remove_instance(fmri
, h
);
6781 } else if (inst_name
!= NULL
&& pg_name
!= NULL
) {
6783 * If we're deleting the 'general' property group or
6784 * 'general/enabled' property then the whole instance
6785 * must be removed from the dgraph.
6787 if (strcmp(pg_name
, SCF_PG_GENERAL
) != 0) {
6792 if (prop_name
!= NULL
&&
6793 strcmp(prop_name
, SCF_PROPERTY_ENABLED
) != 0) {
6799 * Because the instance has already been deleted from the
6800 * repository, we cannot use any scf_ functions to retrieve
6801 * the instance FMRI however we can easily reconstruct it
6804 end_inst_fmri
= strstr(fmri
, SCF_FMRI_PROPERTYGRP_PREFIX
);
6805 if (end_inst_fmri
== NULL
)
6806 bad_error("process_delete", 0);
6808 end_inst_fmri
[0] = '\0';
6810 (void) dgraph_remove_instance(fmri
, h
);
6818 repository_event_thread(void *unused
)
6821 scf_propertygroup_t
*pg
;
6822 scf_instance_t
*inst
;
6823 char *fmri
= startd_alloc(max_scf_fmri_size
);
6824 char *pg_name
= startd_alloc(max_scf_value_size
);
6827 h
= libscf_handle_create_bound_loop();
6829 pg
= safe_scf_pg_create(h
);
6830 inst
= safe_scf_instance_create(h
);
6833 if (_scf_notify_add_pgtype(h
, SCF_GROUP_FRAMEWORK
) != SCF_SUCCESS
) {
6834 if (scf_error() == SCF_ERROR_CONNECTION_BROKEN
) {
6835 libscf_handle_rebind(h
);
6837 log_error(LOG_WARNING
,
6838 "Couldn't set up repository notification "
6839 "for property group type %s: %s\n",
6840 SCF_GROUP_FRAMEWORK
, scf_strerror(scf_error()));
6852 /* Note: fmri is only set on delete events. */
6853 res
= _scf_notify_wait(pg
, fmri
, max_scf_fmri_size
);
6855 libscf_handle_rebind(h
);
6857 } else if (res
== 0) {
6859 * property group modified. inst and pg_name are
6860 * pre-allocated scratch space.
6862 if (scf_pg_update(pg
) < 0) {
6863 switch (scf_error()) {
6864 case SCF_ERROR_DELETED
:
6867 case SCF_ERROR_CONNECTION_BROKEN
:
6868 log_error(LOG_WARNING
,
6869 "Lost repository event due to "
6870 "disconnection.\n");
6871 libscf_handle_rebind(h
);
6874 case SCF_ERROR_NOT_BOUND
:
6875 case SCF_ERROR_NOT_SET
:
6877 bad_error("scf_pg_update", scf_error());
6881 r
= process_pg_event(h
, pg
, inst
, pg_name
);
6887 log_error(LOG_WARNING
, "Lost repository event "
6888 "due to disconnection.\n");
6889 libscf_handle_rebind(h
);
6896 bad_error("process_pg_event", r
);
6900 * Service, instance, or pg deleted.
6901 * Don't trust fmri on return.
6903 process_delete(fmri
, h
);
6912 graph_engine_start()
6916 (void) startd_thread_create(graph_thread
, NULL
);
6918 MUTEX_LOCK(&dgraph_lock
);
6919 while (!initial_milestone_set
) {
6920 err
= pthread_cond_wait(&initial_milestone_cv
, &dgraph_lock
);
6923 MUTEX_UNLOCK(&dgraph_lock
);
6925 (void) startd_thread_create(repository_event_thread
, NULL
);
6926 (void) startd_thread_create(graph_event_thread
, NULL
);