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>
26 * Copyright 2016 RackTop Systems.
30 * graph.c - master restarter graph engine
32 * The graph engine keeps a dependency graph of all service instances on the
33 * system, as recorded in the repository. It decides when services should
34 * be brought up or down based on service states and dependencies and sends
35 * commands to restarters to effect any changes. It also executes
36 * administrator commands sent by svcadm via the repository.
38 * The graph is stored in uu_list_t *dgraph and its vertices are
39 * graph_vertex_t's, each of which has a name and an integer id unique to
40 * its name (see dict.c). A vertex's type attribute designates the type
41 * of object it represents: GVT_INST for service instances, GVT_SVC for
42 * service objects (since service instances may depend on another service,
43 * rather than service instance), GVT_FILE for files (which services may
44 * depend on), and GVT_GROUP for dependencies on multiple objects. GVT_GROUP
45 * vertices are necessary because dependency lists may have particular
46 * grouping types (require any, require all, optional, or exclude) and
47 * event-propagation characteristics.
49 * The initial graph is built by libscf_populate_graph() invoking
50 * dgraph_add_instance() for each instance in the repository. The function
51 * adds a GVT_SVC vertex for the service if one does not already exist, adds
52 * a GVT_INST vertex named by the FMRI of the instance, and sets up the edges.
53 * The resulting web of vertices & edges associated with an instance's vertex
56 * - an edge from the GVT_SVC vertex for the instance's service
58 * - an edge to the GVT_INST vertex of the instance's resarter, if its
59 * restarter is not svc.startd
61 * - edges from other GVT_INST vertices if the instance is a restarter
63 * - for each dependency property group in the instance's "running"
64 * snapshot, an edge to a GVT_GROUP vertex named by the FMRI of the
65 * instance and the name of the property group
67 * - for each value of the "entities" property in each dependency property
68 * group, an edge from the corresponding GVT_GROUP vertex to a
69 * GVT_INST, GVT_SVC, or GVT_FILE vertex
71 * - edges from GVT_GROUP vertices for each dependent instance
73 * After the edges are set up the vertex's GV_CONFIGURED flag is set. If
74 * there are problems, or if a service is mentioned in a dependency but does
75 * not exist in the repository, the GV_CONFIGURED flag will be clear.
77 * The graph and all of its vertices are protected by the dgraph_lock mutex.
78 * See restarter.c for more information.
80 * The properties of an instance fall into two classes: immediate and
81 * snapshotted. Immediate properties should have an immediate effect when
82 * changed. Snapshotted properties should be read from a snapshot, so they
83 * only change when the snapshot changes. The immediate properties used by
84 * the graph engine are general/enabled, general/restarter, and the properties
85 * in the restarter_actions property group. Since they are immediate, they
86 * are not read out of a snapshot. The snapshotted properties used by the
87 * graph engine are those in the property groups with type "dependency" and
88 * are read out of the "running" snapshot. The "running" snapshot is created
89 * by the the graph engine as soon as possible, and it is updated, along with
90 * in-core copies of the data (dependency information for the graph engine) on
91 * receipt of the refresh command from svcadm. In addition, the graph engine
92 * updates the "start" snapshot from the "running" snapshot whenever a service
95 * When a DISABLE event is requested by the administrator, svc.startd shutdown
96 * the dependents first before shutting down the requested service.
97 * In graph_enable_by_vertex, we create a subtree that contains the dependent
98 * vertices by marking those vertices with the GV_TOOFFLINE flag. And we mark
99 * the vertex to disable with the GV_TODISABLE flag. Once the tree is created,
100 * we send the _ADMIN_DISABLE event to the leaves. The leaves will then
101 * transition from STATE_ONLINE/STATE_DEGRADED to STATE_OFFLINE/STATE_MAINT.
102 * In gt_enter_offline and gt_enter_maint if the vertex was in a subtree then
103 * we clear the GV_TOOFFLINE flag and walk the dependencies to offline the new
104 * exposed leaves. We do the same until we reach the last leaf (the one with
105 * the GV_TODISABLE flag). If the vertex to disable is also part of a larger
106 * subtree (eg. multiple DISABLE events on vertices in the same subtree) then
107 * once the first vertex is disabled (GV_TODISABLE flag is removed), we
108 * continue to propagate the offline event to the vertex's dependencies.
111 * SMF state transition notifications
113 * When an instance of a service managed by SMF changes state, svc.startd may
114 * publish a GPEC sysevent. All transitions to or from maintenance, a
115 * transition cause by a hardware error will generate an event.
116 * Other transitions will generate an event if there exist notification
117 * parameter for that transition. Notification parameters are stored in the
118 * SMF repository for the service/instance they refer to. System-wide
119 * notification parameters are stored in the global instance.
120 * svc.startd can be told to send events for all SMF state transitions despite
121 * of notification parameters by setting options/info_events_all to true in
124 * The set of transitions that generate events is cached in the
125 * dgraph_vertex_t gv_stn_tset for service/instance and in the global
126 * stn_global for the system-wide set. They are re-read when instances are
129 * The GPEC events published by svc.startd are consumed by fmd(1M). After
130 * processing these events, fmd(1M) publishes the processed events to
131 * notification agents. The notification agents read the notification
132 * parameters from the SMF repository through libscf(3LIB) interfaces and send
133 * the notification, or not, based on those parameters.
135 * Subscription and publishing to the GPEC channels is done with the
136 * libfmevent(3LIB) wrappers fmev_[r]publish_*() and
137 * fmev_shdl_(un)subscribe().
141 #include <sys/uadmin.h>
142 #include <sys/wait.h>
147 #include <fm/libfmevent.h>
149 #include <libscf_priv.h>
150 #include <librestart.h>
151 #include <libuutil.h>
161 #include <sys/statvfs.h>
162 #include <sys/uadmin.h>
169 #include "protocol.h"
172 #define MILESTONE_NONE ((graph_vertex_t *)1)
174 #define CONSOLE_LOGIN_FMRI "svc:/system/console-login:default"
175 #define FS_MINIMAL_FMRI "svc:/system/filesystem/minimal:default"
177 #define VERTEX_REMOVED 0 /* vertex has been freed */
178 #define VERTEX_INUSE 1 /* vertex is still in use */
180 #define IS_ENABLED(v) ((v)->gv_flags & (GV_ENABLED | GV_ENBLD_NOOVR))
183 * stn_global holds the tset for the system wide notification parameters.
184 * It is updated on refresh of svc:/system/svc/global:default
186 * There are two assumptions that relax the need for a mutex:
187 * 1. 32-bit value assignments are atomic
188 * 2. Its value is consumed only in one point at
189 * dgraph_state_transition_notify(). There are no test and set races.
191 * If either assumption is broken, we'll need a mutex to synchronize
192 * access to stn_global
196 * info_events_all holds a flag to override notification parameters and send
197 * Information events for all state transitions.
198 * same about the need of a mutex here.
203 * Services in these states are not considered 'down' by the
204 * milestone/shutdown code.
206 #define up_state(state) ((state) == RESTARTER_STATE_ONLINE || \
207 (state) == RESTARTER_STATE_DEGRADED || \
208 (state) == RESTARTER_STATE_OFFLINE)
210 #define is_depgrp_bypassed(v) ((v->gv_type == GVT_GROUP) && \
211 ((v->gv_depgroup == DEPGRP_EXCLUDE_ALL) || \
212 (v->gv_restart < RERR_RESTART)))
214 #define is_inst_bypassed(v) ((v->gv_type == GVT_INST) && \
215 ((v->gv_flags & GV_TODISABLE) || \
216 (v->gv_flags & GV_TOOFFLINE)))
218 static uu_list_pool_t
*graph_edge_pool
, *graph_vertex_pool
;
219 static uu_list_t
*dgraph
;
220 static pthread_mutex_t dgraph_lock
;
223 * milestone indicates the current subgraph. When NULL, it is the entire
224 * graph. When MILESTONE_NONE, it is the empty graph. Otherwise, it is all
225 * services on which the target vertex depends.
227 static graph_vertex_t
*milestone
= NULL
;
228 static boolean_t initial_milestone_set
= B_FALSE
;
229 static pthread_cond_t initial_milestone_cv
= PTHREAD_COND_INITIALIZER
;
231 /* protected by dgraph_lock */
232 static boolean_t sulogin_thread_running
= B_FALSE
;
233 static boolean_t sulogin_running
= B_FALSE
;
234 static boolean_t console_login_ready
= B_FALSE
;
236 /* Number of services to come down to complete milestone transition. */
237 static uint_t non_subgraph_svcs
;
240 * These variables indicate what should be done when we reach the milestone
241 * target milestone, i.e., when non_subgraph_svcs == 0. They are acted upon in
242 * dgraph_set_instance_state().
244 static int halting
= -1;
245 static boolean_t go_single_user_mode
= B_FALSE
;
246 static boolean_t go_to_level1
= B_FALSE
;
249 * Tracks when we started halting.
251 static time_t halting_time
= 0;
254 * This tracks the legacy runlevel to ensure we signal init and manage
255 * utmpx entries correctly.
257 static char current_runlevel
= '\0';
259 /* Number of single user threads currently running */
260 static pthread_mutex_t single_user_thread_lock
;
261 static int single_user_thread_count
= 0;
263 /* Statistics for dependency cycle-checking */
264 static u_longlong_t dep_inserts
= 0;
265 static u_longlong_t dep_cycle_ns
= 0;
266 static u_longlong_t dep_insert_ns
= 0;
269 static const char * const emsg_invalid_restarter
=
270 "Transitioning %s to maintenance, restarter FMRI %s is invalid "
271 "(see 'svcs -xv' for details).\n";
272 static const char * const console_login_fmri
= CONSOLE_LOGIN_FMRI
;
273 static const char * const single_user_fmri
= SCF_MILESTONE_SINGLE_USER
;
274 static const char * const multi_user_fmri
= SCF_MILESTONE_MULTI_USER
;
275 static const char * const multi_user_svr_fmri
= SCF_MILESTONE_MULTI_USER_SERVER
;
279 * These services define the system being "up". If none of them can come
280 * online, then we will run sulogin on the console. Note that the install ones
281 * are for the miniroot and when installing CDs after the first. can_come_up()
282 * does the decision making, and an sulogin_thread() runs sulogin, which can be
283 * started by dgraph_set_instance_state() or single_user_thread().
285 * NOTE: can_come_up() relies on SCF_MILESTONE_SINGLE_USER being the first
286 * entry, which is only used when booting_to_single_user (boot -s) is set.
287 * This is because when doing a "boot -s", sulogin is started from specials.c
288 * after milestone/single-user comes online, for backwards compatibility.
289 * In this case, SCF_MILESTONE_SINGLE_USER needs to be part of up_svcs
290 * to ensure sulogin will be spawned if milestone/single-user cannot be reached.
292 static const char * const up_svcs
[] = {
293 SCF_MILESTONE_SINGLE_USER
,
295 "svc:/system/install-setup:default",
296 "svc:/system/install:default",
300 /* This array must have an element for each non-NULL element of up_svcs[]. */
301 static graph_vertex_t
*up_svcs_p
[] = { NULL
, NULL
, NULL
, NULL
};
303 /* These are for seed repository magic. See can_come_up(). */
304 static const char * const manifest_import
= SCF_INSTANCE_MI
;
305 static graph_vertex_t
*manifest_import_p
= NULL
;
308 static char target_milestone_as_runlevel(void);
309 static void graph_runlevel_changed(char rl
, int online
);
310 static int dgraph_set_milestone(const char *, scf_handle_t
*, boolean_t
);
311 static boolean_t
should_be_in_subgraph(graph_vertex_t
*v
);
312 static int mark_subtree(graph_edge_t
*, void *);
313 static boolean_t
insubtree_dependents_down(graph_vertex_t
*);
316 * graph_vertex_compare()
317 * This function can compare either int *id or * graph_vertex_t *gv
318 * values, as the vertex id is always the first element of a
319 * graph_vertex structure.
323 graph_vertex_compare(const void *lc_arg
, const void *rc_arg
, void *private)
325 int lc_id
= ((const graph_vertex_t
*)lc_arg
)->gv_id
;
326 int rc_id
= *(int *)rc_arg
;
338 graph_edge_pool
= startd_list_pool_create("graph_edges",
339 sizeof (graph_edge_t
), offsetof(graph_edge_t
, ge_link
), NULL
,
341 assert(graph_edge_pool
!= NULL
);
343 graph_vertex_pool
= startd_list_pool_create("graph_vertices",
344 sizeof (graph_vertex_t
), offsetof(graph_vertex_t
, gv_link
),
345 graph_vertex_compare
, UU_LIST_POOL_DEBUG
);
346 assert(graph_vertex_pool
!= NULL
);
348 (void) pthread_mutex_init(&dgraph_lock
, &mutex_attrs
);
349 (void) pthread_mutex_init(&single_user_thread_lock
, &mutex_attrs
);
350 dgraph
= startd_list_create(graph_vertex_pool
, NULL
, UU_LIST_SORTED
);
351 assert(dgraph
!= NULL
);
354 current_runlevel
= utmpx_get_runlevel();
356 log_framework(LOG_DEBUG
, "Initialized graph\n");
359 static graph_vertex_t
*
360 vertex_get_by_name(const char *name
)
364 assert(MUTEX_HELD(&dgraph_lock
));
366 id
= dict_lookup_byname(name
);
370 return (uu_list_find(dgraph
, &id
, NULL
, NULL
));
373 static graph_vertex_t
*
374 vertex_get_by_id(int id
)
376 assert(MUTEX_HELD(&dgraph_lock
));
381 return (uu_list_find(dgraph
, &id
, NULL
, NULL
));
385 * Creates a new vertex with the given name, adds it to the graph, and returns
386 * a pointer to it. The graph lock must be held by this thread on entry.
388 static graph_vertex_t
*
389 graph_add_vertex(const char *name
)
396 assert(MUTEX_HELD(&dgraph_lock
));
398 id
= dict_insert(name
);
400 v
= startd_zalloc(sizeof (*v
));
404 v
->gv_name
= startd_alloc(strlen(name
) + 1);
405 (void) strcpy(v
->gv_name
, name
);
407 v
->gv_dependencies
= startd_list_create(graph_edge_pool
, v
, 0);
408 v
->gv_dependents
= startd_list_create(graph_edge_pool
, v
, 0);
410 p
= uu_list_find(dgraph
, &id
, NULL
, &idx
);
413 uu_list_node_init(v
, &v
->gv_link
, graph_vertex_pool
);
414 uu_list_insert(dgraph
, v
, idx
);
420 * Removes v from the graph and frees it. The graph should be locked by this
421 * thread, and v should have no edges associated with it.
424 graph_remove_vertex(graph_vertex_t
*v
)
426 assert(MUTEX_HELD(&dgraph_lock
));
428 assert(uu_list_numnodes(v
->gv_dependencies
) == 0);
429 assert(uu_list_numnodes(v
->gv_dependents
) == 0);
430 assert(v
->gv_refs
== 0);
432 startd_free(v
->gv_name
, strlen(v
->gv_name
) + 1);
433 uu_list_destroy(v
->gv_dependencies
);
434 uu_list_destroy(v
->gv_dependents
);
435 uu_list_remove(dgraph
, v
);
437 startd_free(v
, sizeof (graph_vertex_t
));
441 graph_add_edge(graph_vertex_t
*fv
, graph_vertex_t
*tv
)
443 graph_edge_t
*e
, *re
;
446 assert(MUTEX_HELD(&dgraph_lock
));
448 e
= startd_alloc(sizeof (graph_edge_t
));
449 re
= startd_alloc(sizeof (graph_edge_t
));
457 uu_list_node_init(e
, &e
->ge_link
, graph_edge_pool
);
458 r
= uu_list_insert_before(fv
->gv_dependencies
, NULL
, e
);
461 uu_list_node_init(re
, &re
->ge_link
, graph_edge_pool
);
462 r
= uu_list_insert_before(tv
->gv_dependents
, NULL
, re
);
467 graph_remove_edge(graph_vertex_t
*v
, graph_vertex_t
*dv
)
471 for (e
= uu_list_first(v
->gv_dependencies
);
473 e
= uu_list_next(v
->gv_dependencies
, e
)) {
474 if (e
->ge_vertex
== dv
) {
475 uu_list_remove(v
->gv_dependencies
, e
);
476 startd_free(e
, sizeof (graph_edge_t
));
481 for (e
= uu_list_first(dv
->gv_dependents
);
483 e
= uu_list_next(dv
->gv_dependents
, e
)) {
484 if (e
->ge_vertex
== v
) {
485 uu_list_remove(dv
->gv_dependents
, e
);
486 startd_free(e
, sizeof (graph_edge_t
));
493 remove_inst_vertex(graph_vertex_t
*v
)
499 assert(MUTEX_HELD(&dgraph_lock
));
500 assert(uu_list_numnodes(v
->gv_dependents
) == 1);
501 assert(uu_list_numnodes(v
->gv_dependencies
) == 0);
502 assert(v
->gv_refs
== 0);
503 assert((v
->gv_flags
& GV_CONFIGURED
) == 0);
505 e
= uu_list_first(v
->gv_dependents
);
507 graph_remove_edge(sv
, v
);
509 for (i
= 0; up_svcs
[i
] != NULL
; ++i
) {
510 if (up_svcs_p
[i
] == v
)
514 if (manifest_import_p
== v
)
515 manifest_import_p
= NULL
;
517 graph_remove_vertex(v
);
519 if (uu_list_numnodes(sv
->gv_dependencies
) == 0 &&
520 uu_list_numnodes(sv
->gv_dependents
) == 0 &&
522 graph_remove_vertex(sv
);
526 graph_walk_dependents(graph_vertex_t
*v
, void (*func
)(graph_vertex_t
*, void *),
531 for (e
= uu_list_first(v
->gv_dependents
);
533 e
= uu_list_next(v
->gv_dependents
, e
))
534 func(e
->ge_vertex
, arg
);
538 graph_walk_dependencies(graph_vertex_t
*v
,
539 void (*func
)(graph_vertex_t
*, void *), void *arg
)
543 assert(MUTEX_HELD(&dgraph_lock
));
545 for (e
= uu_list_first(v
->gv_dependencies
);
547 e
= uu_list_next(v
->gv_dependencies
, e
)) {
549 func(e
->ge_vertex
, arg
);
554 * Generic graph walking function.
556 * Given a vertex, this function will walk either dependencies
557 * (WALK_DEPENDENCIES) or dependents (WALK_DEPENDENTS) of a vertex recursively
558 * for the entire graph. It will avoid cycles and never visit the same vertex
561 * We avoid traversing exclusion dependencies, because they are allowed to
562 * create cycles in the graph. When propagating satisfiability, there is no
563 * need to walk exclusion dependencies because exclude_all_satisfied() doesn't
564 * test for satisfiability.
566 * The walker takes two callbacks. The first is called before examining the
567 * dependents of each vertex. The second is called on each vertex after
568 * examining its dependents. This allows is_path_to() to construct a path only
569 * after the target vertex has been found.
576 typedef int (*graph_walk_cb_t
)(graph_vertex_t
*, void *);
578 typedef struct graph_walk_info
{
579 graph_walk_dir_t gi_dir
;
580 uchar_t
*gi_visited
; /* vertex bitmap */
581 int (*gi_pre
)(graph_vertex_t
*, void *);
582 void (*gi_post
)(graph_vertex_t
*, void *);
583 void *gi_arg
; /* callback arg */
584 int gi_ret
; /* return value */
588 graph_walk_recurse(graph_edge_t
*e
, graph_walk_info_t
*gip
)
592 graph_vertex_t
*v
= e
->ge_vertex
;
597 b
= 1 << (v
->gv_id
% 8);
600 * Check to see if we've visited this vertex already.
602 if (gip
->gi_visited
[i
] & b
)
603 return (UU_WALK_NEXT
);
605 gip
->gi_visited
[i
] |= b
;
608 * Don't follow exclusions.
610 if (v
->gv_type
== GVT_GROUP
&& v
->gv_depgroup
== DEPGRP_EXCLUDE_ALL
)
611 return (UU_WALK_NEXT
);
614 * Call pre-visit callback. If this doesn't terminate the walk,
617 if ((gip
->gi_ret
= gip
->gi_pre(v
, gip
->gi_arg
)) == UU_WALK_NEXT
) {
619 * Recurse using appropriate list.
621 if (gip
->gi_dir
== WALK_DEPENDENTS
)
622 list
= v
->gv_dependents
;
624 list
= v
->gv_dependencies
;
626 r
= uu_list_walk(list
, (uu_walk_fn_t
*)graph_walk_recurse
,
632 * Callbacks must return either UU_WALK_NEXT or UU_WALK_DONE.
634 assert(gip
->gi_ret
== UU_WALK_NEXT
|| gip
->gi_ret
== UU_WALK_DONE
);
637 * If given a post-callback, call the function for every vertex.
639 if (gip
->gi_post
!= NULL
)
640 (void) gip
->gi_post(v
, gip
->gi_arg
);
643 * Preserve the callback's return value. If the callback returns
644 * UU_WALK_DONE, then we propagate that to the caller in order to
645 * terminate the walk.
647 return (gip
->gi_ret
);
651 graph_walk(graph_vertex_t
*v
, graph_walk_dir_t dir
,
652 int (*pre
)(graph_vertex_t
*, void *),
653 void (*post
)(graph_vertex_t
*, void *), void *arg
)
655 graph_walk_info_t gi
;
657 size_t sz
= dictionary
->dict_new_id
/ 8 + 1;
659 gi
.gi_visited
= startd_zalloc(sz
);
667 * Fake up an edge for the first iteration
670 (void) graph_walk_recurse(&fake
, &gi
);
672 startd_free(gi
.gi_visited
, sz
);
675 typedef struct child_search
{
676 int id
; /* id of vertex to look for */
677 uint_t depth
; /* recursion depth */
679 * While the vertex is not found, path is NULL. After the search, if
680 * the vertex was found then path should point to a -1-terminated
681 * array of vertex id's which constitute the path to the vertex.
687 child_pre(graph_vertex_t
*v
, void *arg
)
689 child_search_t
*cs
= arg
;
693 if (v
->gv_id
== cs
->id
) {
694 cs
->path
= startd_alloc((cs
->depth
+ 1) * sizeof (int));
695 cs
->path
[cs
->depth
] = -1;
696 return (UU_WALK_DONE
);
699 return (UU_WALK_NEXT
);
703 child_post(graph_vertex_t
*v
, void *arg
)
705 child_search_t
*cs
= arg
;
709 if (cs
->path
!= NULL
)
710 cs
->path
[cs
->depth
] = v
->gv_id
;
714 * Look for a path from from to to. If one exists, returns a pointer to
715 * a NULL-terminated array of pointers to the vertices along the path. If
716 * there is no path, returns NULL.
719 is_path_to(graph_vertex_t
*from
, graph_vertex_t
*to
)
727 graph_walk(from
, WALK_DEPENDENCIES
, child_pre
, child_post
, &cs
);
733 * Given an array of int's as returned by is_path_to, allocates a string of
734 * their names joined by newlines. Returns the size of the allocated buffer
735 * in *sz and frees path.
738 path_to_str(int *path
, char **cpp
, size_t *sz
)
742 size_t allocd
, new_allocd
;
745 assert(MUTEX_HELD(&dgraph_lock
));
746 assert(path
[0] != -1);
749 *cpp
= startd_alloc(1);
752 for (i
= 0; path
[i
] != -1; ++i
) {
755 v
= vertex_get_by_id(path
[i
]);
759 else if (v
->gv_type
== GVT_INST
|| v
->gv_type
== GVT_SVC
)
763 new_allocd
= allocd
+ strlen(name
) + 1;
764 new = startd_alloc(new_allocd
);
765 (void) strcpy(new, *cpp
);
766 (void) strcat(new, name
);
767 (void) strcat(new, "\n");
769 startd_free(*cpp
, allocd
);
776 startd_free(path
, sizeof (int) * (i
+ 1));
783 * This function along with run_sulogin() implements an exclusion relationship
784 * between system/console-login and sulogin. run_sulogin() will fail if
785 * system/console-login is online, and the graph engine should call
786 * graph_clogin_start() to bring system/console-login online, which defers the
787 * start if sulogin is running.
790 graph_clogin_start(graph_vertex_t
*v
)
792 assert(MUTEX_HELD(&dgraph_lock
));
795 console_login_ready
= B_TRUE
;
797 vertex_send_event(v
, RESTARTER_EVENT_TYPE_START
);
801 graph_su_start(graph_vertex_t
*v
)
804 * /etc/inittab used to have the initial /sbin/rcS as a 'sysinit'
805 * entry with a runlevel of 'S', before jumping to the final
806 * target runlevel (as set in initdefault). We mimic that legacy
809 utmpx_set_runlevel('S', '0', B_FALSE
);
810 vertex_send_event(v
, RESTARTER_EVENT_TYPE_START
);
814 graph_post_su_online(void)
816 graph_runlevel_changed('S', 1);
820 graph_post_su_disable(void)
822 graph_runlevel_changed('S', 0);
826 graph_post_mu_online(void)
828 graph_runlevel_changed('2', 1);
832 graph_post_mu_disable(void)
834 graph_runlevel_changed('2', 0);
838 graph_post_mus_online(void)
840 graph_runlevel_changed('3', 1);
844 graph_post_mus_disable(void)
846 graph_runlevel_changed('3', 0);
849 static struct special_vertex_info
{
851 void (*start_f
)(graph_vertex_t
*);
852 void (*post_online_f
)(void);
853 void (*post_disable_f
)(void);
854 } special_vertices
[] = {
855 { CONSOLE_LOGIN_FMRI
, graph_clogin_start
, NULL
, NULL
},
856 { SCF_MILESTONE_SINGLE_USER
, graph_su_start
,
857 graph_post_su_online
, graph_post_su_disable
},
858 { SCF_MILESTONE_MULTI_USER
, NULL
,
859 graph_post_mu_online
, graph_post_mu_disable
},
860 { SCF_MILESTONE_MULTI_USER_SERVER
, NULL
,
861 graph_post_mus_online
, graph_post_mus_disable
},
867 vertex_send_event(graph_vertex_t
*v
, restarter_event_type_t e
)
870 case RESTARTER_EVENT_TYPE_ADD_INSTANCE
:
871 assert(v
->gv_state
== RESTARTER_STATE_UNINIT
);
873 MUTEX_LOCK(&st
->st_load_lock
);
874 st
->st_load_instances
++;
875 MUTEX_UNLOCK(&st
->st_load_lock
);
878 case RESTARTER_EVENT_TYPE_ENABLE
:
879 log_framework(LOG_DEBUG
, "Enabling %s.\n", v
->gv_name
);
880 assert(v
->gv_state
== RESTARTER_STATE_UNINIT
||
881 v
->gv_state
== RESTARTER_STATE_DISABLED
||
882 v
->gv_state
== RESTARTER_STATE_MAINT
);
885 case RESTARTER_EVENT_TYPE_DISABLE
:
886 case RESTARTER_EVENT_TYPE_ADMIN_DISABLE
:
887 log_framework(LOG_DEBUG
, "Disabling %s.\n", v
->gv_name
);
888 assert(v
->gv_state
!= RESTARTER_STATE_DISABLED
);
891 case RESTARTER_EVENT_TYPE_STOP_RESET
:
892 case RESTARTER_EVENT_TYPE_STOP
:
893 log_framework(LOG_DEBUG
, "Stopping %s.\n", v
->gv_name
);
894 assert(v
->gv_state
== RESTARTER_STATE_DEGRADED
||
895 v
->gv_state
== RESTARTER_STATE_ONLINE
);
898 case RESTARTER_EVENT_TYPE_START
:
899 log_framework(LOG_DEBUG
, "Starting %s.\n", v
->gv_name
);
900 assert(v
->gv_state
== RESTARTER_STATE_OFFLINE
);
903 case RESTARTER_EVENT_TYPE_REMOVE_INSTANCE
:
904 case RESTARTER_EVENT_TYPE_ADMIN_DEGRADED
:
905 case RESTARTER_EVENT_TYPE_ADMIN_REFRESH
:
906 case RESTARTER_EVENT_TYPE_ADMIN_RESTART
:
907 case RESTARTER_EVENT_TYPE_ADMIN_MAINT_OFF
:
908 case RESTARTER_EVENT_TYPE_ADMIN_MAINT_ON
:
909 case RESTARTER_EVENT_TYPE_ADMIN_MAINT_ON_IMMEDIATE
:
910 case RESTARTER_EVENT_TYPE_DEPENDENCY_CYCLE
:
911 case RESTARTER_EVENT_TYPE_INVALID_DEPENDENCY
:
916 uu_warn("%s:%d: Bad event %d.\n", __FILE__
, __LINE__
, e
);
921 restarter_protocol_send_event(v
->gv_name
, v
->gv_restarter_channel
, e
,
926 graph_unset_restarter(graph_vertex_t
*v
)
928 assert(MUTEX_HELD(&dgraph_lock
));
929 assert(v
->gv_flags
& GV_CONFIGURED
);
931 vertex_send_event(v
, RESTARTER_EVENT_TYPE_REMOVE_INSTANCE
);
933 if (v
->gv_restarter_id
!= -1) {
936 rv
= vertex_get_by_id(v
->gv_restarter_id
);
937 graph_remove_edge(v
, rv
);
940 v
->gv_restarter_id
= -1;
941 v
->gv_restarter_channel
= NULL
;
945 * Return VERTEX_REMOVED when the vertex passed in argument is deleted from the
946 * dgraph otherwise return VERTEX_INUSE.
949 free_if_unrefed(graph_vertex_t
*v
)
951 assert(MUTEX_HELD(&dgraph_lock
));
954 return (VERTEX_INUSE
);
956 if (v
->gv_type
== GVT_SVC
&&
957 uu_list_numnodes(v
->gv_dependents
) == 0 &&
958 uu_list_numnodes(v
->gv_dependencies
) == 0) {
959 graph_remove_vertex(v
);
960 return (VERTEX_REMOVED
);
961 } else if (v
->gv_type
== GVT_INST
&&
962 (v
->gv_flags
& GV_CONFIGURED
) == 0 &&
963 uu_list_numnodes(v
->gv_dependents
) == 1 &&
964 uu_list_numnodes(v
->gv_dependencies
) == 0) {
965 remove_inst_vertex(v
);
966 return (VERTEX_REMOVED
);
969 return (VERTEX_INUSE
);
973 delete_depgroup(graph_vertex_t
*v
)
978 assert(MUTEX_HELD(&dgraph_lock
));
979 assert(v
->gv_type
== GVT_GROUP
);
980 assert(uu_list_numnodes(v
->gv_dependents
) == 0);
982 while ((e
= uu_list_first(v
->gv_dependencies
)) != NULL
) {
985 graph_remove_edge(v
, dv
);
987 switch (dv
->gv_type
) {
988 case GVT_INST
: /* instance dependency */
989 case GVT_SVC
: /* service dependency */
990 (void) free_if_unrefed(dv
);
993 case GVT_FILE
: /* file dependency */
994 assert(uu_list_numnodes(dv
->gv_dependencies
) == 0);
995 if (uu_list_numnodes(dv
->gv_dependents
) == 0)
996 graph_remove_vertex(dv
);
1001 uu_warn("%s:%d: Unexpected node type %d", __FILE__
,
1002 __LINE__
, dv
->gv_type
);
1008 graph_remove_vertex(v
);
1012 delete_instance_deps_cb(graph_edge_t
*e
, void **ptrs
)
1014 graph_vertex_t
*v
= ptrs
[0];
1015 boolean_t delete_restarter_dep
= (boolean_t
)ptrs
[1];
1021 * We have four possibilities here:
1022 * - GVT_INST: restarter
1023 * - GVT_GROUP - GVT_INST: instance dependency
1024 * - GVT_GROUP - GVT_SVC - GV_INST: service dependency
1025 * - GVT_GROUP - GVT_FILE: file dependency
1027 switch (dv
->gv_type
) {
1028 case GVT_INST
: /* restarter */
1029 assert(dv
->gv_id
== v
->gv_restarter_id
);
1030 if (delete_restarter_dep
)
1031 graph_remove_edge(v
, dv
);
1034 case GVT_GROUP
: /* pg dependency */
1035 graph_remove_edge(v
, dv
);
1036 delete_depgroup(dv
);
1040 /* These are currently not direct dependencies */
1044 uu_warn("%s:%d: Bad vertex type %d.\n", __FILE__
, __LINE__
,
1050 return (UU_WALK_NEXT
);
1054 delete_instance_dependencies(graph_vertex_t
*v
, boolean_t delete_restarter_dep
)
1059 assert(MUTEX_HELD(&dgraph_lock
));
1060 assert(v
->gv_type
== GVT_INST
);
1063 ptrs
[1] = (void *)delete_restarter_dep
;
1065 r
= uu_list_walk(v
->gv_dependencies
,
1066 (uu_walk_fn_t
*)delete_instance_deps_cb
, &ptrs
, UU_WALK_ROBUST
);
1071 * int graph_insert_vertex_unconfigured()
1072 * Insert a vertex without sending any restarter events. If the vertex
1073 * already exists or creation is successful, return a pointer to it in *vp.
1075 * If type is not GVT_GROUP, dt can remain unset.
1077 * Returns 0, EEXIST, or EINVAL if the arguments are invalid (i.e., fmri
1078 * doesn't agree with type, or type doesn't agree with dt).
1081 graph_insert_vertex_unconfigured(const char *fmri
, gv_type_t type
,
1082 depgroup_type_t dt
, restarter_error_t rt
, graph_vertex_t
**vp
)
1087 assert(MUTEX_HELD(&dgraph_lock
));
1092 if (strncmp(fmri
, "svc:", sizeof ("svc:") - 1) != 0)
1097 if (strncmp(fmri
, "file:", sizeof ("file:") - 1) != 0)
1102 if (dt
<= 0 || rt
< 0)
1108 uu_warn("%s:%d: Unknown type %d.\n", __FILE__
, __LINE__
, type
);
1113 *vp
= vertex_get_by_name(fmri
);
1117 *vp
= graph_add_vertex(fmri
);
1119 (*vp
)->gv_type
= type
;
1120 (*vp
)->gv_depgroup
= dt
;
1121 (*vp
)->gv_restart
= rt
;
1123 (*vp
)->gv_flags
= 0;
1124 (*vp
)->gv_state
= RESTARTER_STATE_NONE
;
1126 for (i
= 0; special_vertices
[i
].name
!= NULL
; ++i
) {
1127 if (strcmp(fmri
, special_vertices
[i
].name
) == 0) {
1128 (*vp
)->gv_start_f
= special_vertices
[i
].start_f
;
1129 (*vp
)->gv_post_online_f
=
1130 special_vertices
[i
].post_online_f
;
1131 (*vp
)->gv_post_disable_f
=
1132 special_vertices
[i
].post_disable_f
;
1137 (*vp
)->gv_restarter_id
= -1;
1138 (*vp
)->gv_restarter_channel
= 0;
1140 if (type
== GVT_INST
) {
1144 sfmri
= inst_fmri_to_svc_fmri(fmri
);
1145 sv
= vertex_get_by_name(sfmri
);
1147 r
= graph_insert_vertex_unconfigured(sfmri
, GVT_SVC
, 0,
1151 startd_free(sfmri
, max_scf_fmri_size
);
1153 graph_add_edge(sv
, *vp
);
1157 * If this vertex is in the subgraph, mark it as so, for both
1158 * GVT_INST and GVT_SERVICE verteces.
1159 * A GVT_SERVICE vertex can only be in the subgraph if another instance
1160 * depends on it, in which case it's already been added to the graph
1161 * and marked as in the subgraph (by refresh_vertex()). If a
1162 * GVT_SERVICE vertex was freshly added (by the code above), it means
1163 * that it has no dependents, and cannot be in the subgraph.
1164 * Regardless of this, we still check that gv_flags includes
1165 * GV_INSUBGRAPH in the event that future behavior causes the above
1166 * code to add a GVT_SERVICE vertex which should be in the subgraph.
1169 (*vp
)->gv_flags
|= (should_be_in_subgraph(*vp
)? GV_INSUBGRAPH
: 0);
1175 * Returns 0 on success or ELOOP if the dependency would create a cycle.
1178 graph_insert_dependency(graph_vertex_t
*fv
, graph_vertex_t
*tv
, int **pathp
)
1182 assert(MUTEX_HELD(&dgraph_lock
));
1184 /* cycle detection */
1187 /* Don't follow exclusions. */
1188 if (!(fv
->gv_type
== GVT_GROUP
&&
1189 fv
->gv_depgroup
== DEPGRP_EXCLUDE_ALL
)) {
1190 *pathp
= is_path_to(tv
, fv
);
1195 dep_cycle_ns
+= gethrtime() - now
;
1199 graph_add_edge(fv
, tv
);
1201 dep_insert_ns
+= gethrtime() - now
;
1203 /* Check if the dependency adds the "to" vertex to the subgraph */
1204 tv
->gv_flags
|= (should_be_in_subgraph(tv
) ? GV_INSUBGRAPH
: 0);
1210 inst_running(graph_vertex_t
*v
)
1212 assert(v
->gv_type
== GVT_INST
);
1214 if (v
->gv_state
== RESTARTER_STATE_ONLINE
||
1215 v
->gv_state
== RESTARTER_STATE_DEGRADED
)
1222 * The dependency evaluation functions return
1223 * 1 - dependency satisfied
1224 * 0 - dependency unsatisfied
1225 * -1 - dependency unsatisfiable (without administrator intervention)
1227 * The functions also take a boolean satbility argument. When true, the
1228 * functions may recurse in order to determine satisfiability.
1230 static int require_any_satisfied(graph_vertex_t
*, boolean_t
);
1231 static int dependency_satisfied(graph_vertex_t
*, boolean_t
);
1234 * A require_all dependency is unsatisfied if any elements are unsatisfied. It
1235 * is unsatisfiable if any elements are unsatisfiable.
1238 require_all_satisfied(graph_vertex_t
*groupv
, boolean_t satbility
)
1242 boolean_t any_unsatisfied
;
1244 if (uu_list_numnodes(groupv
->gv_dependencies
) == 0)
1247 any_unsatisfied
= B_FALSE
;
1249 for (edge
= uu_list_first(groupv
->gv_dependencies
);
1251 edge
= uu_list_next(groupv
->gv_dependencies
, edge
)) {
1252 i
= dependency_satisfied(edge
->ge_vertex
, satbility
);
1256 log_framework2(LOG_DEBUG
, DEBUG_DEPENDENCIES
,
1257 "require_all(%s): %s is unsatisfi%s.\n", groupv
->gv_name
,
1258 edge
->ge_vertex
->gv_name
, i
== 0 ? "ed" : "able");
1266 any_unsatisfied
= B_TRUE
;
1269 return (any_unsatisfied
? 0 : 1);
1273 * A require_any dependency is satisfied if any element is satisfied. It is
1274 * satisfiable if any element is satisfiable.
1277 require_any_satisfied(graph_vertex_t
*groupv
, boolean_t satbility
)
1281 boolean_t satisfiable
;
1283 if (uu_list_numnodes(groupv
->gv_dependencies
) == 0)
1286 satisfiable
= B_FALSE
;
1288 for (edge
= uu_list_first(groupv
->gv_dependencies
);
1290 edge
= uu_list_next(groupv
->gv_dependencies
, edge
)) {
1291 s
= dependency_satisfied(edge
->ge_vertex
, satbility
);
1296 log_framework2(LOG_DEBUG
, DEBUG_DEPENDENCIES
,
1297 "require_any(%s): %s is unsatisfi%s.\n",
1298 groupv
->gv_name
, edge
->ge_vertex
->gv_name
,
1299 s
== 0 ? "ed" : "able");
1301 if (satbility
&& s
== 0)
1302 satisfiable
= B_TRUE
;
1305 return ((!satbility
|| satisfiable
) ? 0 : -1);
1309 * An optional_all dependency only considers elements which are configured,
1310 * enabled, and not in maintenance. If any are unsatisfied, then the dependency
1313 * Offline dependencies which are waiting for a dependency to come online are
1314 * unsatisfied. Offline dependences which cannot possibly come online
1315 * (unsatisfiable) are always considered satisfied.
1318 optional_all_satisfied(graph_vertex_t
*groupv
, boolean_t satbility
)
1322 boolean_t any_qualified
;
1323 boolean_t any_unsatisfied
;
1326 any_qualified
= B_FALSE
;
1327 any_unsatisfied
= B_FALSE
;
1329 for (edge
= uu_list_first(groupv
->gv_dependencies
);
1331 edge
= uu_list_next(groupv
->gv_dependencies
, edge
)) {
1332 v
= edge
->ge_vertex
;
1334 switch (v
->gv_type
) {
1336 /* Skip missing instances */
1337 if ((v
->gv_flags
& GV_CONFIGURED
) == 0)
1340 if (v
->gv_state
== RESTARTER_STATE_MAINT
)
1343 any_qualified
= B_TRUE
;
1344 if (v
->gv_state
== RESTARTER_STATE_OFFLINE
||
1345 v
->gv_state
== RESTARTER_STATE_DISABLED
) {
1347 * For offline/disabled dependencies,
1348 * treat unsatisfiable as satisfied.
1350 i
= dependency_satisfied(v
, B_TRUE
);
1354 i
= dependency_satisfied(v
, satbility
);
1359 any_qualified
= B_TRUE
;
1360 i
= dependency_satisfied(v
, satbility
);
1365 any_qualified
= B_TRUE
;
1366 i
= optional_all_satisfied(v
, satbility
);
1374 uu_warn("%s:%d: Unexpected vertex type %d.\n", __FILE__
,
1375 __LINE__
, v
->gv_type
);
1383 log_framework2(LOG_DEBUG
, DEBUG_DEPENDENCIES
,
1384 "optional_all(%s): %s is unsatisfi%s.\n", groupv
->gv_name
,
1385 v
->gv_name
, i
== 0 ? "ed" : "able");
1391 any_unsatisfied
= B_TRUE
;
1397 return (any_unsatisfied
? 0 : 1);
1401 * An exclude_all dependency is unsatisfied if any non-service element is
1402 * satisfied or any service instance which is configured, enabled, and not in
1403 * maintenance is satisfied. Usually when unsatisfied, it is also
1406 #define LOG_EXCLUDE(u, v) \
1407 log_framework2(LOG_DEBUG, DEBUG_DEPENDENCIES, \
1408 "exclude_all(%s): %s is satisfied.\n", \
1409 (u)->gv_name, (v)->gv_name)
1413 exclude_all_satisfied(graph_vertex_t
*groupv
, boolean_t satbility
)
1415 graph_edge_t
*edge
, *e2
;
1416 graph_vertex_t
*v
, *v2
;
1418 for (edge
= uu_list_first(groupv
->gv_dependencies
);
1420 edge
= uu_list_next(groupv
->gv_dependencies
, edge
)) {
1421 v
= edge
->ge_vertex
;
1423 switch (v
->gv_type
) {
1425 if ((v
->gv_flags
& GV_CONFIGURED
) == 0)
1428 switch (v
->gv_state
) {
1429 case RESTARTER_STATE_ONLINE
:
1430 case RESTARTER_STATE_DEGRADED
:
1431 LOG_EXCLUDE(groupv
, v
);
1432 return (v
->gv_flags
& GV_ENABLED
? -1 : 0);
1434 case RESTARTER_STATE_OFFLINE
:
1435 case RESTARTER_STATE_UNINIT
:
1436 LOG_EXCLUDE(groupv
, v
);
1439 case RESTARTER_STATE_DISABLED
:
1440 case RESTARTER_STATE_MAINT
:
1445 uu_warn("%s:%d: Unexpected vertex state %d.\n",
1446 __FILE__
, __LINE__
, v
->gv_state
);
1458 LOG_EXCLUDE(groupv
, v
);
1464 uu_warn("%s:%d: Unexpected vertex type %d.\n", __FILE__
,
1465 __LINE__
, v
->gv_type
);
1470 /* v represents a service */
1471 if (uu_list_numnodes(v
->gv_dependencies
) == 0)
1474 for (e2
= uu_list_first(v
->gv_dependencies
);
1476 e2
= uu_list_next(v
->gv_dependencies
, e2
)) {
1478 assert(v2
->gv_type
== GVT_INST
);
1480 if ((v2
->gv_flags
& GV_CONFIGURED
) == 0)
1483 switch (v2
->gv_state
) {
1484 case RESTARTER_STATE_ONLINE
:
1485 case RESTARTER_STATE_DEGRADED
:
1486 LOG_EXCLUDE(groupv
, v2
);
1487 return (v2
->gv_flags
& GV_ENABLED
? -1 : 0);
1489 case RESTARTER_STATE_OFFLINE
:
1490 case RESTARTER_STATE_UNINIT
:
1491 LOG_EXCLUDE(groupv
, v2
);
1494 case RESTARTER_STATE_DISABLED
:
1495 case RESTARTER_STATE_MAINT
:
1500 uu_warn("%s:%d: Unexpected vertex type %d.\n",
1501 __FILE__
, __LINE__
, v2
->gv_type
);
1512 * int instance_satisfied()
1513 * Determine if all the dependencies are satisfied for the supplied instance
1514 * vertex. Return 1 if they are, 0 if they aren't, and -1 if they won't be
1515 * without administrator intervention.
1518 instance_satisfied(graph_vertex_t
*v
, boolean_t satbility
)
1520 assert(v
->gv_type
== GVT_INST
);
1521 assert(!inst_running(v
));
1523 return (require_all_satisfied(v
, satbility
));
1527 * Decide whether v can satisfy a dependency. v can either be a child of
1528 * a group vertex, or of an instance vertex.
1531 dependency_satisfied(graph_vertex_t
*v
, boolean_t satbility
)
1533 switch (v
->gv_type
) {
1535 if ((v
->gv_flags
& GV_CONFIGURED
) == 0) {
1536 if (v
->gv_flags
& GV_DEATHROW
) {
1538 * A dependency on an instance with GV_DEATHROW
1539 * flag is always considered as satisfied.
1547 * Vertices may be transitioning so we try to figure out if
1548 * the end state is likely to satisfy the dependency instead
1549 * of assuming the dependency is unsatisfied/unsatisfiable.
1551 * Support for optional_all dependencies depends on us getting
1552 * this right because unsatisfiable dependencies are treated
1553 * as being satisfied.
1555 switch (v
->gv_state
) {
1556 case RESTARTER_STATE_ONLINE
:
1557 case RESTARTER_STATE_DEGRADED
:
1558 if (v
->gv_flags
& GV_TODISABLE
)
1560 if (v
->gv_flags
& GV_TOOFFLINE
)
1564 case RESTARTER_STATE_OFFLINE
:
1565 if (!satbility
|| v
->gv_flags
& GV_TODISABLE
)
1566 return (satbility
? -1 : 0);
1567 return (instance_satisfied(v
, satbility
) != -1 ?
1570 case RESTARTER_STATE_DISABLED
:
1571 if (!satbility
|| !(v
->gv_flags
& GV_ENABLED
))
1572 return (satbility
? -1 : 0);
1573 return (instance_satisfied(v
, satbility
) != -1 ?
1576 case RESTARTER_STATE_MAINT
:
1579 case RESTARTER_STATE_UNINIT
:
1584 uu_warn("%s:%d: Unexpected vertex state %d.\n",
1585 __FILE__
, __LINE__
, v
->gv_state
);
1592 if (uu_list_numnodes(v
->gv_dependencies
) == 0)
1594 return (require_any_satisfied(v
, satbility
));
1597 /* i.e., we assume files will not be automatically generated */
1598 return (file_ready(v
) ? 1 : -1);
1605 uu_warn("%s:%d: Unexpected node type %d.\n", __FILE__
, __LINE__
,
1612 switch (v
->gv_depgroup
) {
1613 case DEPGRP_REQUIRE_ANY
:
1614 return (require_any_satisfied(v
, satbility
));
1616 case DEPGRP_REQUIRE_ALL
:
1617 return (require_all_satisfied(v
, satbility
));
1619 case DEPGRP_OPTIONAL_ALL
:
1620 return (optional_all_satisfied(v
, satbility
));
1622 case DEPGRP_EXCLUDE_ALL
:
1623 return (exclude_all_satisfied(v
, satbility
));
1627 uu_warn("%s:%d: Unknown dependency grouping %d.\n", __FILE__
,
1628 __LINE__
, v
->gv_depgroup
);
1635 graph_start_if_satisfied(graph_vertex_t
*v
)
1637 if (v
->gv_state
== RESTARTER_STATE_OFFLINE
&&
1638 instance_satisfied(v
, B_FALSE
) == 1) {
1639 if (v
->gv_start_f
== NULL
)
1640 vertex_send_event(v
, RESTARTER_EVENT_TYPE_START
);
1647 * propagate_satbility()
1649 * This function is used when the given vertex changes state in such a way that
1650 * one of its dependents may become unsatisfiable. This happens when an
1651 * instance transitions between offline -> online, or from !running ->
1652 * maintenance, as well as when an instance is removed from the graph.
1654 * We have to walk all the dependents, since optional_all dependencies several
1655 * levels up could become (un)satisfied, instead of unsatisfiable. For example,
1657 * +-----+ optional_all +-----+ require_all +-----+
1658 * | A |--------------->| B |-------------->| C |
1659 * +-----+ +-----+ +-----+
1661 * offline -> maintenance
1663 * If C goes into maintenance, it's not enough simply to check B. Because A has
1664 * an optional dependency, what was previously an unsatisfiable situation is now
1665 * satisfied (B will never come online, even though its state hasn't changed).
1667 * Note that it's not necessary to continue examining dependents after reaching
1668 * an optional_all dependency. It's not possible for an optional_all dependency
1669 * to change satisfiability without also coming online, in which case we get a
1670 * start event and propagation continues naturally. However, it does no harm to
1671 * continue propagating satisfiability (as it is a relatively rare event), and
1672 * keeps the walker code simple and generic.
1676 satbility_cb(graph_vertex_t
*v
, void *arg
)
1678 if (is_inst_bypassed(v
))
1679 return (UU_WALK_NEXT
);
1681 if (v
->gv_type
== GVT_INST
)
1682 graph_start_if_satisfied(v
);
1684 return (UU_WALK_NEXT
);
1688 propagate_satbility(graph_vertex_t
*v
)
1690 graph_walk(v
, WALK_DEPENDENTS
, satbility_cb
, NULL
, NULL
);
1693 static void propagate_stop(graph_vertex_t
*, void *);
1698 * This function is used to propagate a start event to the dependents of the
1699 * given vertex. Any dependents that are offline but have their dependencies
1700 * satisfied are started. Any dependents that are online and have restart_on
1701 * set to "restart" or "refresh" are restarted because their dependencies have
1702 * just changed. This only happens with optional_all dependencies.
1705 propagate_start(graph_vertex_t
*v
, void *arg
)
1707 restarter_error_t err
= (restarter_error_t
)arg
;
1709 if (is_inst_bypassed(v
))
1712 switch (v
->gv_type
) {
1715 if (inst_running(v
)) {
1716 if (err
== RERR_RESTART
|| err
== RERR_REFRESH
) {
1717 vertex_send_event(v
,
1718 RESTARTER_EVENT_TYPE_STOP_RESET
);
1721 graph_start_if_satisfied(v
);
1726 if (v
->gv_depgroup
== DEPGRP_EXCLUDE_ALL
) {
1727 graph_walk_dependents(v
, propagate_stop
,
1728 (void *)RERR_RESTART
);
1731 err
= v
->gv_restart
;
1735 graph_walk_dependents(v
, propagate_start
, (void *)err
);
1740 uu_warn("%s:%d: propagate_start() encountered GVT_FILE.\n",
1741 __FILE__
, __LINE__
);
1748 uu_warn("%s:%d: Unknown vertex type %d.\n", __FILE__
, __LINE__
,
1758 * This function is used to propagate a stop event to the dependents of the
1759 * given vertex. Any dependents that are online (or in degraded state) with
1760 * the restart_on property set to "restart" or "refresh" will be stopped as
1761 * their dependencies have just changed, propagate_start() will start them
1762 * again once their dependencies have been re-satisfied.
1765 propagate_stop(graph_vertex_t
*v
, void *arg
)
1767 restarter_error_t err
= (restarter_error_t
)arg
;
1769 if (is_inst_bypassed(v
))
1772 switch (v
->gv_type
) {
1775 if (err
> RERR_NONE
&& inst_running(v
)) {
1776 if (err
== RERR_RESTART
|| err
== RERR_REFRESH
) {
1777 vertex_send_event(v
,
1778 RESTARTER_EVENT_TYPE_STOP_RESET
);
1780 vertex_send_event(v
, RESTARTER_EVENT_TYPE_STOP
);
1786 graph_walk_dependents(v
, propagate_stop
, arg
);
1791 uu_warn("%s:%d: propagate_stop() encountered GVT_FILE.\n",
1792 __FILE__
, __LINE__
);
1798 if (v
->gv_depgroup
== DEPGRP_EXCLUDE_ALL
) {
1799 graph_walk_dependents(v
, propagate_start
,
1804 if (err
== RERR_NONE
|| err
> v
->gv_restart
)
1807 graph_walk_dependents(v
, propagate_stop
, arg
);
1812 uu_warn("%s:%d: Unknown vertex type %d.\n", __FILE__
, __LINE__
,
1820 offline_vertex(graph_vertex_t
*v
)
1822 scf_handle_t
*h
= libscf_handle_create_bound_loop();
1823 scf_instance_t
*scf_inst
= safe_scf_instance_create(h
);
1824 scf_propertygroup_t
*pg
= safe_scf_pg_create(h
);
1825 restarter_instance_state_t state
, next_state
;
1828 assert(v
->gv_type
== GVT_INST
);
1830 if (scf_inst
== NULL
)
1831 bad_error("safe_scf_instance_create", scf_error());
1833 bad_error("safe_scf_pg_create", scf_error());
1835 /* if the vertex is already going offline, return */
1837 if (scf_handle_decode_fmri(h
, v
->gv_name
, NULL
, NULL
, scf_inst
, NULL
,
1838 NULL
, SCF_DECODE_FMRI_EXACT
) != 0) {
1839 switch (scf_error()) {
1840 case SCF_ERROR_CONNECTION_BROKEN
:
1841 libscf_handle_rebind(h
);
1844 case SCF_ERROR_NOT_FOUND
:
1846 scf_instance_destroy(scf_inst
);
1847 (void) scf_handle_unbind(h
);
1848 scf_handle_destroy(h
);
1851 uu_die("Can't decode FMRI %s: %s\n", v
->gv_name
,
1852 scf_strerror(scf_error()));
1855 r
= scf_instance_get_pg(scf_inst
, SCF_PG_RESTARTER
, pg
);
1857 switch (scf_error()) {
1858 case SCF_ERROR_CONNECTION_BROKEN
:
1859 libscf_handle_rebind(h
);
1862 case SCF_ERROR_NOT_SET
:
1863 case SCF_ERROR_NOT_FOUND
:
1865 scf_instance_destroy(scf_inst
);
1866 (void) scf_handle_unbind(h
);
1867 scf_handle_destroy(h
);
1871 bad_error("scf_instance_get_pg", scf_error());
1874 r
= libscf_read_states(pg
, &state
, &next_state
);
1875 if (r
== 0 && (next_state
== RESTARTER_STATE_OFFLINE
||
1876 next_state
== RESTARTER_STATE_DISABLED
)) {
1877 log_framework(LOG_DEBUG
,
1878 "%s: instance is already going down.\n",
1881 scf_instance_destroy(scf_inst
);
1882 (void) scf_handle_unbind(h
);
1883 scf_handle_destroy(h
);
1889 scf_instance_destroy(scf_inst
);
1890 (void) scf_handle_unbind(h
);
1891 scf_handle_destroy(h
);
1893 vertex_send_event(v
, RESTARTER_EVENT_TYPE_STOP_RESET
);
1897 * void graph_enable_by_vertex()
1898 * If admin is non-zero, this is an administrative request for change
1899 * of the enabled property. Thus, send the ADMIN_DISABLE rather than
1900 * a plain DISABLE restarter event.
1903 graph_enable_by_vertex(graph_vertex_t
*vertex
, int enable
, int admin
)
1908 assert(MUTEX_HELD(&dgraph_lock
));
1909 assert((vertex
->gv_flags
& GV_CONFIGURED
));
1911 vertex
->gv_flags
= (vertex
->gv_flags
& ~GV_ENABLED
) |
1912 (enable
? GV_ENABLED
: 0);
1915 if (vertex
->gv_state
!= RESTARTER_STATE_OFFLINE
&&
1916 vertex
->gv_state
!= RESTARTER_STATE_DEGRADED
&&
1917 vertex
->gv_state
!= RESTARTER_STATE_ONLINE
) {
1919 * In case the vertex was notified to go down,
1920 * but now can return online, clear the _TOOFFLINE
1921 * and _TODISABLE flags.
1923 vertex
->gv_flags
&= ~GV_TOOFFLINE
;
1924 vertex
->gv_flags
&= ~GV_TODISABLE
;
1926 vertex_send_event(vertex
, RESTARTER_EVENT_TYPE_ENABLE
);
1930 * Wait for state update from restarter before sending _START or
1937 if (vertex
->gv_state
== RESTARTER_STATE_DISABLED
)
1941 vertex_send_event(vertex
, RESTARTER_EVENT_TYPE_DISABLE
);
1944 * Wait for state update from restarter before sending _START or
1952 * If it is a DISABLE event requested by the administrator then we are
1953 * offlining the dependents first.
1957 * Set GV_TOOFFLINE for the services we are offlining. We cannot
1958 * clear the GV_TOOFFLINE bits from all the services because
1959 * other DISABLE events might be handled at the same time.
1961 vertex
->gv_flags
|= GV_TOOFFLINE
;
1963 /* remember which vertex to disable... */
1964 vertex
->gv_flags
|= GV_TODISABLE
;
1966 log_framework(LOG_DEBUG
, "Marking in-subtree vertices before "
1967 "disabling %s.\n", vertex
->gv_name
);
1969 /* set GV_TOOFFLINE for its dependents */
1970 r
= uu_list_walk(vertex
->gv_dependents
, (uu_walk_fn_t
*)mark_subtree
,
1974 /* disable the instance now if there is nothing else to offline */
1975 if (insubtree_dependents_down(vertex
) == B_TRUE
) {
1976 vertex_send_event(vertex
, RESTARTER_EVENT_TYPE_ADMIN_DISABLE
);
1981 * This loop is similar to the one used for the graph reversal shutdown
1982 * and could be improved in term of performance for the subtree reversal
1985 for (v
= uu_list_first(dgraph
); v
!= NULL
;
1986 v
= uu_list_next(dgraph
, v
)) {
1987 /* skip the vertex we are disabling for now */
1991 if (v
->gv_type
!= GVT_INST
||
1992 (v
->gv_flags
& GV_CONFIGURED
) == 0 ||
1993 (v
->gv_flags
& GV_ENABLED
) == 0 ||
1994 (v
->gv_flags
& GV_TOOFFLINE
) == 0)
1997 if ((v
->gv_state
!= RESTARTER_STATE_ONLINE
) &&
1998 (v
->gv_state
!= RESTARTER_STATE_DEGRADED
)) {
1999 /* continue if there is nothing to offline */
2004 * Instances which are up need to come down before we're
2005 * done, but we can only offline the leaves here. An
2006 * instance is a leaf when all its dependents are down.
2008 if (insubtree_dependents_down(v
) == B_TRUE
) {
2009 log_framework(LOG_DEBUG
, "Offlining in-subtree "
2010 "instance %s for %s.\n",
2011 v
->gv_name
, vertex
->gv_name
);
2017 static int configure_vertex(graph_vertex_t
*, scf_instance_t
*);
2020 * Set the restarter for v to fmri_arg. That is, make sure a vertex for
2021 * fmri_arg exists, make v depend on it, and send _ADD_INSTANCE for v. If
2022 * v is already configured and fmri_arg indicates the current restarter, do
2023 * nothing. If v is configured and fmri_arg is a new restarter, delete v's
2024 * dependency on the restarter, send _REMOVE_INSTANCE for v, and set the new
2025 * restarter. Returns 0 on success, EINVAL if the FMRI is invalid,
2026 * ECONNABORTED if the repository connection is broken, and ELOOP
2027 * if the dependency would create a cycle. In the last case, *pathp will
2028 * point to a -1-terminated array of ids which compose the path from v to
2032 graph_change_restarter(graph_vertex_t
*v
, const char *fmri_arg
, scf_handle_t
*h
,
2035 char *restarter_fmri
= NULL
;
2040 assert(MUTEX_HELD(&dgraph_lock
));
2042 if (fmri_arg
[0] != '\0') {
2043 err
= fmri_canonify(fmri_arg
, &restarter_fmri
, B_TRUE
);
2045 assert(err
== EINVAL
);
2050 if (restarter_fmri
== NULL
||
2051 strcmp(restarter_fmri
, SCF_SERVICE_STARTD
) == 0) {
2052 if (v
->gv_flags
& GV_CONFIGURED
) {
2053 if (v
->gv_restarter_id
== -1) {
2054 if (restarter_fmri
!= NULL
)
2055 startd_free(restarter_fmri
,
2060 graph_unset_restarter(v
);
2063 /* Master restarter, nothing to do. */
2064 v
->gv_restarter_id
= -1;
2065 v
->gv_restarter_channel
= NULL
;
2066 vertex_send_event(v
, RESTARTER_EVENT_TYPE_ADD_INSTANCE
);
2070 if (v
->gv_flags
& GV_CONFIGURED
) {
2071 id
= dict_lookup_byname(restarter_fmri
);
2072 if (id
!= -1 && v
->gv_restarter_id
== id
) {
2073 startd_free(restarter_fmri
, max_scf_fmri_size
);
2077 graph_unset_restarter(v
);
2080 err
= graph_insert_vertex_unconfigured(restarter_fmri
, GVT_INST
, 0,
2082 startd_free(restarter_fmri
, max_scf_fmri_size
);
2083 assert(err
== 0 || err
== EEXIST
);
2085 if (rv
->gv_delegate_initialized
== 0) {
2086 if ((rv
->gv_delegate_channel
= restarter_protocol_init_delegate(
2087 rv
->gv_name
)) == NULL
)
2089 rv
->gv_delegate_initialized
= 1;
2091 v
->gv_restarter_id
= rv
->gv_id
;
2092 v
->gv_restarter_channel
= rv
->gv_delegate_channel
;
2094 err
= graph_insert_dependency(v
, rv
, pathp
);
2096 assert(err
== ELOOP
);
2100 vertex_send_event(v
, RESTARTER_EVENT_TYPE_ADD_INSTANCE
);
2102 if (!(rv
->gv_flags
& GV_CONFIGURED
)) {
2103 scf_instance_t
*inst
;
2105 err
= libscf_fmri_get_instance(h
, rv
->gv_name
, &inst
);
2108 err
= configure_vertex(rv
, inst
);
2109 scf_instance_destroy(inst
);
2116 return (ECONNABORTED
);
2119 bad_error("configure_vertex", err
);
2124 return (ECONNABORTED
);
2131 * The fmri doesn't specify an instance - translate
2138 bad_error("libscf_fmri_get_instance", err
);
2147 * Add all of the instances of the service named by fmri to the graph.
2150 * ENOENT - service indicated by fmri does not exist
2152 * In both cases *reboundp will be B_TRUE if the handle was rebound, or B_FALSE
2156 add_service(const char *fmri
, scf_handle_t
*h
, boolean_t
*reboundp
)
2159 scf_instance_t
*inst
;
2164 *reboundp
= B_FALSE
;
2166 svc
= safe_scf_service_create(h
);
2167 inst
= safe_scf_instance_create(h
);
2168 iter
= safe_scf_iter_create(h
);
2169 inst_fmri
= startd_alloc(max_scf_fmri_size
);
2172 if (scf_handle_decode_fmri(h
, fmri
, NULL
, svc
, NULL
, NULL
, NULL
,
2173 SCF_DECODE_FMRI_EXACT
) != 0) {
2174 switch (scf_error()) {
2175 case SCF_ERROR_CONNECTION_BROKEN
:
2177 libscf_handle_rebind(h
);
2181 case SCF_ERROR_NOT_FOUND
:
2185 case SCF_ERROR_INVALID_ARGUMENT
:
2186 case SCF_ERROR_CONSTRAINT_VIOLATED
:
2187 case SCF_ERROR_NOT_BOUND
:
2188 case SCF_ERROR_HANDLE_MISMATCH
:
2189 bad_error("scf_handle_decode_fmri", scf_error());
2193 if (scf_iter_service_instances(iter
, svc
) != 0) {
2194 switch (scf_error()) {
2195 case SCF_ERROR_CONNECTION_BROKEN
:
2197 libscf_handle_rebind(h
);
2201 case SCF_ERROR_DELETED
:
2205 case SCF_ERROR_HANDLE_MISMATCH
:
2206 case SCF_ERROR_NOT_BOUND
:
2207 case SCF_ERROR_NOT_SET
:
2208 bad_error("scf_iter_service_instances", scf_error());
2213 r
= scf_iter_next_instance(iter
, inst
);
2217 switch (scf_error()) {
2218 case SCF_ERROR_CONNECTION_BROKEN
:
2220 libscf_handle_rebind(h
);
2224 case SCF_ERROR_DELETED
:
2228 case SCF_ERROR_HANDLE_MISMATCH
:
2229 case SCF_ERROR_NOT_BOUND
:
2230 case SCF_ERROR_NOT_SET
:
2231 case SCF_ERROR_INVALID_ARGUMENT
:
2232 bad_error("scf_iter_next_instance",
2237 if (scf_instance_to_fmri(inst
, inst_fmri
, max_scf_fmri_size
) <
2239 switch (scf_error()) {
2240 case SCF_ERROR_CONNECTION_BROKEN
:
2241 libscf_handle_rebind(h
);
2245 case SCF_ERROR_DELETED
:
2248 case SCF_ERROR_NOT_BOUND
:
2249 case SCF_ERROR_NOT_SET
:
2250 bad_error("scf_instance_to_fmri", scf_error());
2254 r
= dgraph_add_instance(inst_fmri
, inst
, B_FALSE
);
2264 libscf_handle_rebind(h
);
2270 bad_error("dgraph_add_instance", r
);
2277 startd_free(inst_fmri
, max_scf_fmri_size
);
2278 scf_iter_destroy(iter
);
2279 scf_instance_destroy(inst
);
2280 scf_service_destroy(svc
);
2284 struct depfmri_info
{
2285 graph_vertex_t
*v
; /* GVT_GROUP vertex */
2286 gv_type_t type
; /* type of dependency */
2287 const char *inst_fmri
; /* FMRI of parental GVT_INST vert. */
2288 const char *pg_name
; /* Name of dependency pg */
2290 int err
; /* return error code */
2291 int **pathp
; /* return circular dependency path */
2295 * Find or create a vertex for fmri and make info->v depend on it.
2300 * On failure, sets info->err to
2301 * EINVAL - fmri is invalid
2302 * fmri does not match info->type
2303 * ELOOP - Adding the dependency creates a circular dependency. *info->pathp
2304 * will point to an array of the ids of the members of the cycle.
2305 * ECONNABORTED - repository connection was broken
2306 * ECONNRESET - succeeded, but repository connection was reset
2309 process_dependency_fmri(const char *fmri
, struct depfmri_info
*info
)
2312 graph_vertex_t
*depgroup_v
, *v
;
2313 char *fmri_copy
, *cfmri
;
2314 size_t fmri_copy_sz
;
2315 const char *scope
, *service
, *instance
, *pg
;
2316 scf_instance_t
*inst
;
2319 assert(MUTEX_HELD(&dgraph_lock
));
2321 /* Get or create vertex for FMRI */
2322 depgroup_v
= info
->v
;
2324 if (strncmp(fmri
, "file:", sizeof ("file:") - 1) == 0) {
2325 if (info
->type
!= GVT_FILE
) {
2326 log_framework(LOG_NOTICE
,
2327 "FMRI \"%s\" is not allowed for the \"%s\" "
2328 "dependency's type of instance %s.\n", fmri
,
2329 info
->pg_name
, info
->inst_fmri
);
2330 return (info
->err
= EINVAL
);
2333 err
= graph_insert_vertex_unconfigured(fmri
, info
->type
, 0,
2340 assert(v
->gv_type
== GVT_FILE
);
2343 case EINVAL
: /* prevented above */
2345 bad_error("graph_insert_vertex_unconfigured", err
);
2348 if (info
->type
!= GVT_INST
) {
2349 log_framework(LOG_NOTICE
,
2350 "FMRI \"%s\" is not allowed for the \"%s\" "
2351 "dependency's type of instance %s.\n", fmri
,
2352 info
->pg_name
, info
->inst_fmri
);
2353 return (info
->err
= EINVAL
);
2357 * We must canonify fmri & add a vertex for it.
2359 fmri_copy_sz
= strlen(fmri
) + 1;
2360 fmri_copy
= startd_alloc(fmri_copy_sz
);
2361 (void) strcpy(fmri_copy
, fmri
);
2363 /* Determine if the FMRI is a property group or instance */
2364 if (scf_parse_svc_fmri(fmri_copy
, &scope
, &service
,
2365 &instance
, &pg
, NULL
) != 0) {
2366 startd_free(fmri_copy
, fmri_copy_sz
);
2367 log_framework(LOG_NOTICE
,
2368 "Dependency \"%s\" of %s has invalid FMRI "
2369 "\"%s\".\n", info
->pg_name
, info
->inst_fmri
,
2371 return (info
->err
= EINVAL
);
2374 if (service
== NULL
|| pg
!= NULL
) {
2375 startd_free(fmri_copy
, fmri_copy_sz
);
2376 log_framework(LOG_NOTICE
,
2377 "Dependency \"%s\" of %s does not designate a "
2378 "service or instance.\n", info
->pg_name
,
2380 return (info
->err
= EINVAL
);
2383 if (scope
== NULL
|| strcmp(scope
, SCF_SCOPE_LOCAL
) == 0) {
2384 cfmri
= uu_msprintf("svc:/%s%s%s",
2385 service
, instance
? ":" : "", instance
? instance
:
2388 cfmri
= uu_msprintf("svc://%s/%s%s%s",
2389 scope
, service
, instance
? ":" : "", instance
?
2393 startd_free(fmri_copy
, fmri_copy_sz
);
2395 err
= graph_insert_vertex_unconfigured(cfmri
, instance
?
2396 GVT_INST
: GVT_SVC
, instance
? 0 : DEPGRP_REQUIRE_ANY
,
2405 if (instance
!= NULL
)
2406 assert(v
->gv_type
== GVT_INST
);
2408 assert(v
->gv_type
== GVT_SVC
);
2412 bad_error("graph_insert_vertex_unconfigured", err
);
2416 /* Add dependency from depgroup_v to new vertex */
2417 info
->err
= graph_insert_dependency(depgroup_v
, v
, info
->pathp
);
2418 switch (info
->err
) {
2426 bad_error("graph_insert_dependency", info
->err
);
2429 /* This must be after we insert the dependency, to avoid looping. */
2430 switch (v
->gv_type
) {
2432 if ((v
->gv_flags
& GV_CONFIGURED
) != 0)
2435 inst
= safe_scf_instance_create(info
->h
);
2440 err
= libscf_lookup_instance(v
->gv_name
, inst
);
2443 err
= configure_vertex(v
, inst
);
2450 libscf_handle_rebind(info
->h
);
2455 bad_error("configure_vertex", err
);
2463 libscf_handle_rebind(info
->h
);
2470 bad_error("libscf_fmri_get_instance", err
);
2473 scf_instance_destroy(inst
);
2476 return (info
->err
= ECONNRESET
);
2480 (void) add_service(v
->gv_name
, info
->h
, &rebound
);
2482 return (info
->err
= ECONNRESET
);
2489 graph_vertex_t
*v
; /* GVT_INST vertex */
2490 int err
; /* return error */
2491 int **pathp
; /* return circular dependency path */
2495 * Make info->v depend on a new GVT_GROUP node for this property group,
2496 * and then call process_dependency_fmri() for the values of the entity
2497 * property. Return 0 on success, or if something goes wrong return nonzero
2498 * and set info->err to ECONNABORTED, EINVAL, or the error code returned by
2499 * process_dependency_fmri().
2502 process_dependency_pg(scf_propertygroup_t
*pg
, struct deppg_info
*info
)
2505 depgroup_type_t deptype
;
2506 restarter_error_t rerr
;
2507 struct depfmri_info linfo
;
2508 char *fmri
, *pg_name
;
2510 graph_vertex_t
*depgrp
;
2511 scf_property_t
*prop
;
2517 assert(MUTEX_HELD(&dgraph_lock
));
2519 h
= scf_pg_handle(pg
);
2521 pg_name
= startd_alloc(max_scf_name_size
);
2523 len
= scf_pg_get_name(pg
, pg_name
, max_scf_name_size
);
2525 startd_free(pg_name
, max_scf_name_size
);
2526 switch (scf_error()) {
2527 case SCF_ERROR_CONNECTION_BROKEN
:
2529 return (info
->err
= ECONNABORTED
);
2531 case SCF_ERROR_DELETED
:
2532 return (info
->err
= 0);
2534 case SCF_ERROR_NOT_SET
:
2535 bad_error("scf_pg_get_name", scf_error());
2540 * Skip over empty dependency groups. Since dependency property
2541 * groups are updated atomically, they are either empty or
2544 empty
= depgroup_empty(h
, pg
);
2547 "Error reading dependency group \"%s\" of %s: %s\n",
2548 pg_name
, info
->v
->gv_name
, scf_strerror(scf_error()));
2549 startd_free(pg_name
, max_scf_name_size
);
2550 return (info
->err
= EINVAL
);
2552 } else if (empty
== 1) {
2553 log_framework(LOG_DEBUG
,
2554 "Ignoring empty dependency group \"%s\" of %s\n",
2555 pg_name
, info
->v
->gv_name
);
2556 startd_free(pg_name
, max_scf_name_size
);
2557 return (info
->err
= 0);
2560 fmri_sz
= strlen(info
->v
->gv_name
) + 1 + len
+ 1;
2561 fmri
= startd_alloc(fmri_sz
);
2563 (void) snprintf(fmri
, fmri_sz
, "%s>%s", info
->v
->gv_name
,
2566 /* Validate the pg before modifying the graph */
2567 deptype
= depgroup_read_grouping(h
, pg
);
2568 if (deptype
== DEPGRP_UNSUPPORTED
) {
2570 "Dependency \"%s\" of %s has an unknown grouping value.\n",
2571 pg_name
, info
->v
->gv_name
);
2572 startd_free(fmri
, fmri_sz
);
2573 startd_free(pg_name
, max_scf_name_size
);
2574 return (info
->err
= EINVAL
);
2577 rerr
= depgroup_read_restart(h
, pg
);
2578 if (rerr
== RERR_UNSUPPORTED
) {
2580 "Dependency \"%s\" of %s has an unknown restart_on value."
2581 "\n", pg_name
, info
->v
->gv_name
);
2582 startd_free(fmri
, fmri_sz
);
2583 startd_free(pg_name
, max_scf_name_size
);
2584 return (info
->err
= EINVAL
);
2587 prop
= safe_scf_property_create(h
);
2589 if (scf_pg_get_property(pg
, SCF_PROPERTY_ENTITIES
, prop
) != 0) {
2590 scferr
= scf_error();
2591 scf_property_destroy(prop
);
2592 if (scferr
== SCF_ERROR_DELETED
) {
2593 startd_free(fmri
, fmri_sz
);
2594 startd_free(pg_name
, max_scf_name_size
);
2595 return (info
->err
= 0);
2596 } else if (scferr
!= SCF_ERROR_NOT_FOUND
) {
2597 startd_free(fmri
, fmri_sz
);
2598 startd_free(pg_name
, max_scf_name_size
);
2599 return (info
->err
= ECONNABORTED
);
2603 "Dependency \"%s\" of %s is missing a \"%s\" property.\n",
2604 pg_name
, info
->v
->gv_name
, SCF_PROPERTY_ENTITIES
);
2606 startd_free(fmri
, fmri_sz
);
2607 startd_free(pg_name
, max_scf_name_size
);
2609 return (info
->err
= EINVAL
);
2612 /* Create depgroup vertex for pg */
2613 err
= graph_insert_vertex_unconfigured(fmri
, GVT_GROUP
, deptype
,
2616 startd_free(fmri
, fmri_sz
);
2618 /* Add dependency from inst vertex to new vertex */
2619 err
= graph_insert_dependency(info
->v
, depgrp
, info
->pathp
);
2620 /* ELOOP can't happen because this should be a new vertex */
2624 linfo
.type
= depgroup_read_scheme(h
, pg
);
2625 linfo
.inst_fmri
= info
->v
->gv_name
;
2626 linfo
.pg_name
= pg_name
;
2629 linfo
.pathp
= info
->pathp
;
2630 err
= walk_property_astrings(prop
, (callback_t
)process_dependency_fmri
,
2633 scf_property_destroy(prop
);
2634 startd_free(pg_name
, max_scf_name_size
);
2639 return (info
->err
= linfo
.err
);
2643 return (info
->err
= err
);
2646 return (info
->err
= 0);
2649 return (info
->err
= ECONNABORTED
);
2652 bad_error("walk_property_astrings", err
);
2658 * Build the dependency info for v from the repository. Returns 0 on success,
2659 * ECONNABORTED on repository disconnection, EINVAL if the repository
2660 * configuration is invalid, and ELOOP if a dependency would cause a cycle.
2661 * In the last case, *pathp will point to a -1-terminated array of ids which
2662 * constitute the rest of the dependency cycle.
2665 set_dependencies(graph_vertex_t
*v
, scf_instance_t
*inst
, int **pathp
)
2667 struct deppg_info info
;
2669 uint_t old_configured
;
2671 assert(MUTEX_HELD(&dgraph_lock
));
2674 * Mark the vertex as configured during dependency insertion to avoid
2675 * dependency cycles (which can appear in the graph if one of the
2676 * vertices is an exclusion-group).
2678 old_configured
= v
->gv_flags
& GV_CONFIGURED
;
2679 v
->gv_flags
|= GV_CONFIGURED
;
2685 err
= walk_dependency_pgs(inst
, (callback_t
)process_dependency_pg
,
2688 if (!old_configured
)
2689 v
->gv_flags
&= ~GV_CONFIGURED
;
2697 return (ECONNABORTED
);
2700 /* Should get delete event, so return 0. */
2704 bad_error("walk_dependency_pgs", err
);
2711 handle_cycle(const char *fmri
, int *path
)
2716 assert(MUTEX_HELD(&dgraph_lock
));
2718 path_to_str(path
, (char **)&cp
, &sz
);
2720 log_error(LOG_ERR
, "Transitioning %s to maintenance "
2721 "because it completes a dependency cycle (see svcs -xv for "
2722 "details):\n%s", fmri
? fmri
: "?", cp
);
2724 startd_free((void *)cp
, sz
);
2728 * Increment the vertex's reference count to prevent the vertex removal
2732 vertex_ref(graph_vertex_t
*v
)
2734 assert(MUTEX_HELD(&dgraph_lock
));
2740 * Decrement the vertex's reference count and remove the vertex from
2741 * the dgraph when possible.
2743 * Return VERTEX_REMOVED when the vertex has been removed otherwise
2744 * return VERTEX_INUSE.
2747 vertex_unref(graph_vertex_t
*v
)
2749 assert(MUTEX_HELD(&dgraph_lock
));
2750 assert(v
->gv_refs
> 0);
2754 return (free_if_unrefed(v
));
2758 * When run on the dependencies of a vertex, populates list with
2759 * graph_edge_t's which point to the service vertices or the instance
2760 * vertices (no GVT_GROUP nodes) on which the vertex depends.
2762 * Increment the vertex's reference count once the vertex is inserted
2763 * in the list. The vertex won't be able to be deleted from the dgraph
2764 * while it is referenced.
2767 append_svcs_or_insts(graph_edge_t
*e
, uu_list_t
*list
)
2769 graph_vertex_t
*v
= e
->ge_vertex
;
2773 switch (v
->gv_type
) {
2779 r
= uu_list_walk(v
->gv_dependencies
,
2780 (uu_walk_fn_t
*)append_svcs_or_insts
, list
, 0);
2782 return (UU_WALK_NEXT
);
2785 return (UU_WALK_NEXT
);
2789 uu_warn("%s:%d: Unexpected vertex type %d.\n", __FILE__
,
2790 __LINE__
, v
->gv_type
);
2795 new = startd_alloc(sizeof (*new));
2797 uu_list_node_init(new, &new->ge_link
, graph_edge_pool
);
2798 r
= uu_list_insert_before(list
, NULL
, new);
2802 * Because we are inserting the vertex in a list, we don't want
2803 * the vertex to be freed while the list is in use. In order to
2804 * achieve that, increment the vertex's reference count.
2808 return (UU_WALK_NEXT
);
2812 should_be_in_subgraph(graph_vertex_t
*v
)
2820 * v is in the subgraph if any of its dependents are in the subgraph.
2821 * Except for EXCLUDE_ALL dependents. And OPTIONAL dependents only
2822 * count if we're enabled.
2824 for (e
= uu_list_first(v
->gv_dependents
);
2826 e
= uu_list_next(v
->gv_dependents
, e
)) {
2827 graph_vertex_t
*dv
= e
->ge_vertex
;
2829 if (!(dv
->gv_flags
& GV_INSUBGRAPH
))
2833 * Don't include instances that are optional and disabled.
2835 if (v
->gv_type
== GVT_INST
&& dv
->gv_type
== GVT_SVC
) {
2840 for (ee
= uu_list_first(dv
->gv_dependents
);
2842 ee
= uu_list_next(dv
->gv_dependents
, ee
)) {
2844 graph_vertex_t
*ddv
= e
->ge_vertex
;
2846 if (ddv
->gv_type
== GVT_GROUP
&&
2847 ddv
->gv_depgroup
== DEPGRP_EXCLUDE_ALL
)
2850 if (ddv
->gv_type
== GVT_GROUP
&&
2851 ddv
->gv_depgroup
== DEPGRP_OPTIONAL_ALL
&&
2852 !(v
->gv_flags
& GV_ENBLD_NOOVR
))
2860 if (v
->gv_type
== GVT_INST
&&
2861 dv
->gv_type
== GVT_GROUP
&&
2862 dv
->gv_depgroup
== DEPGRP_OPTIONAL_ALL
&&
2863 !(v
->gv_flags
& GV_ENBLD_NOOVR
))
2866 /* Don't include excluded services and instances */
2867 if (dv
->gv_type
== GVT_GROUP
&&
2868 dv
->gv_depgroup
== DEPGRP_EXCLUDE_ALL
)
2878 * Ensures that GV_INSUBGRAPH is set properly for v and its descendents. If
2879 * any bits change, manipulate the repository appropriately. Returns 0 or
2883 eval_subgraph(graph_vertex_t
*v
, scf_handle_t
*h
)
2885 boolean_t old
= (v
->gv_flags
& GV_INSUBGRAPH
) != 0;
2888 scf_instance_t
*inst
;
2891 assert(milestone
!= NULL
&& milestone
!= MILESTONE_NONE
);
2893 new = should_be_in_subgraph(v
);
2898 log_framework(LOG_DEBUG
, new ? "Adding %s to the subgraph.\n" :
2899 "Removing %s from the subgraph.\n", v
->gv_name
);
2901 v
->gv_flags
= (v
->gv_flags
& ~GV_INSUBGRAPH
) |
2902 (new ? GV_INSUBGRAPH
: 0);
2904 if (v
->gv_type
== GVT_INST
&& (v
->gv_flags
& GV_CONFIGURED
)) {
2908 err
= libscf_fmri_get_instance(h
, v
->gv_name
, &inst
);
2912 libscf_handle_rebind(h
);
2922 bad_error("libscf_fmri_get_instance", err
);
2928 err
= libscf_delete_enable_ovr(inst
);
2929 f
= "libscf_delete_enable_ovr";
2931 err
= libscf_set_enable_ovr(inst
, 0);
2932 f
= "libscf_set_enable_ovr";
2934 scf_instance_destroy(inst
);
2941 libscf_handle_rebind(h
);
2943 * We must continue so the graph is updated,
2944 * but we must return ECONNABORTED so any
2945 * libscf state held by any callers is reset.
2952 log_error(LOG_WARNING
,
2953 "Could not set %s/%s for %s: %s.\n",
2954 SCF_PG_GENERAL_OVR
, SCF_PROPERTY_ENABLED
,
2955 v
->gv_name
, strerror(err
));
2964 for (e
= uu_list_first(v
->gv_dependencies
);
2966 e
= uu_list_next(v
->gv_dependencies
, e
)) {
2967 r
= eval_subgraph(e
->ge_vertex
, h
);
2969 assert(r
== ECONNABORTED
);
2978 * Delete the (property group) dependencies of v & create new ones based on
2979 * inst. If doing so would create a cycle, log a message and put the instance
2980 * into maintenance. Update GV_INSUBGRAPH flags as necessary. Returns 0 or
2984 refresh_vertex(graph_vertex_t
*v
, scf_instance_t
*inst
)
2990 scf_handle_t
*h
= scf_instance_handle(inst
);
2991 uu_list_t
*old_deps
;
2996 assert(MUTEX_HELD(&dgraph_lock
));
2997 assert(v
->gv_type
== GVT_INST
);
2999 log_framework(LOG_DEBUG
, "Graph engine: Refreshing %s.\n", v
->gv_name
);
3001 if (milestone
> MILESTONE_NONE
) {
3003 * In case some of v's dependencies are being deleted we must
3004 * make a list of them now for GV_INSUBGRAPH-flag evaluation
3005 * after the new dependencies are in place.
3007 old_deps
= startd_list_create(graph_edge_pool
, NULL
, 0);
3009 err
= uu_list_walk(v
->gv_dependencies
,
3010 (uu_walk_fn_t
*)append_svcs_or_insts
, old_deps
, 0);
3014 delete_instance_dependencies(v
, B_FALSE
);
3016 err
= set_dependencies(v
, inst
, &path
);
3027 r
= libscf_instance_get_fmri(inst
, &fmri
);
3041 bad_error("libscf_instance_get_fmri", r
);
3044 if (err
== EINVAL
) {
3045 log_error(LOG_ERR
, "Transitioning %s "
3046 "to maintenance due to misconfiguration.\n",
3048 vertex_send_event(v
,
3049 RESTARTER_EVENT_TYPE_INVALID_DEPENDENCY
);
3051 handle_cycle(fmri
, path
);
3052 vertex_send_event(v
,
3053 RESTARTER_EVENT_TYPE_DEPENDENCY_CYCLE
);
3055 startd_free(fmri
, max_scf_fmri_size
);
3060 bad_error("set_dependencies", err
);
3063 if (milestone
> MILESTONE_NONE
) {
3064 boolean_t aborted
= B_FALSE
;
3066 for (e
= uu_list_first(old_deps
);
3068 e
= uu_list_next(old_deps
, e
)) {
3071 if (vertex_unref(vv
) == VERTEX_INUSE
&&
3072 eval_subgraph(vv
, h
) == ECONNABORTED
)
3076 for (e
= uu_list_first(v
->gv_dependencies
);
3078 e
= uu_list_next(v
->gv_dependencies
, e
)) {
3079 if (eval_subgraph(e
->ge_vertex
, h
) ==
3090 graph_start_if_satisfied(v
);
3095 if (milestone
> MILESTONE_NONE
) {
3096 void *cookie
= NULL
;
3098 while ((e
= uu_list_teardown(old_deps
, &cookie
)) != NULL
)
3099 startd_free(e
, sizeof (*e
));
3101 uu_list_destroy(old_deps
);
3108 * Set up v according to inst. That is, make sure it depends on its
3109 * restarter and set up its dependencies. Send the ADD_INSTANCE command to
3110 * the restarter, and send ENABLE or DISABLE as appropriate.
3112 * Returns 0 on success, ECONNABORTED on repository disconnection, or
3113 * ECANCELED if inst is deleted.
3116 configure_vertex(graph_vertex_t
*v
, scf_instance_t
*inst
)
3119 scf_propertygroup_t
*pg
;
3120 scf_snapshot_t
*snap
;
3121 char *restarter_fmri
= startd_alloc(max_scf_value_size
);
3122 int enabled
, enabled_ovr
;
3128 restarter_fmri
[0] = '\0';
3130 assert(MUTEX_HELD(&dgraph_lock
));
3131 assert(v
->gv_type
== GVT_INST
);
3132 assert((v
->gv_flags
& GV_CONFIGURED
) == 0);
3134 /* GV_INSUBGRAPH should already be set properly. */
3135 assert(should_be_in_subgraph(v
) ==
3136 ((v
->gv_flags
& GV_INSUBGRAPH
) != 0));
3139 * If the instance fmri is in the deathrow list then set the
3140 * GV_DEATHROW flag on the vertex and create and set to true the
3141 * SCF_PROPERTY_DEATHROW boolean property in the non-persistent
3142 * repository for this instance fmri.
3144 if ((v
->gv_flags
& GV_DEATHROW
) ||
3145 (is_fmri_in_deathrow(v
->gv_name
) == B_TRUE
)) {
3146 if ((v
->gv_flags
& GV_DEATHROW
) == 0) {
3148 * Set flag GV_DEATHROW, create and set to true
3149 * the SCF_PROPERTY_DEATHROW property in the
3150 * non-persistent repository for this instance fmri.
3152 v
->gv_flags
|= GV_DEATHROW
;
3154 switch (err
= libscf_set_deathrow(inst
, 1)) {
3160 startd_free(restarter_fmri
, max_scf_value_size
);
3164 log_error(LOG_WARNING
, "Could not set %s/%s "
3165 "for deathrow %s: %s.\n",
3166 SCF_PG_DEATHROW
, SCF_PROPERTY_DEATHROW
,
3167 v
->gv_name
, strerror(err
));
3171 uu_die("Permission denied.\n");
3175 bad_error("libscf_set_deathrow", err
);
3177 log_framework(LOG_DEBUG
, "Deathrow, graph set %s.\n",
3180 startd_free(restarter_fmri
, max_scf_value_size
);
3184 h
= scf_instance_handle(inst
);
3187 * Using a temporary deathrow boolean property, set through
3188 * libscf_set_deathrow(), only for fmris on deathrow, is necessary
3189 * because deathrow_fini() may already have been called, and in case
3190 * of a refresh, GV_DEATHROW may need to be set again.
3191 * libscf_get_deathrow() sets deathrow to 1 only if this instance
3192 * has a temporary boolean property named 'deathrow' valued true
3193 * in a property group 'deathrow', -1 or 0 in all other cases.
3195 err
= libscf_get_deathrow(h
, inst
, &deathrow
);
3202 startd_free(restarter_fmri
, max_scf_value_size
);
3206 bad_error("libscf_get_deathrow", err
);
3209 if (deathrow
== 1) {
3210 v
->gv_flags
|= GV_DEATHROW
;
3211 startd_free(restarter_fmri
, max_scf_value_size
);
3215 log_framework(LOG_DEBUG
, "Graph adding %s.\n", v
->gv_name
);
3218 * If the instance does not have a restarter property group,
3219 * initialize its state to uninitialized/none, in case the restarter
3222 pg
= safe_scf_pg_create(h
);
3224 if (scf_instance_get_pg(inst
, SCF_PG_RESTARTER
, pg
) != 0) {
3225 instance_data_t idata
;
3226 uint_t count
= 0, msecs
= ALLOC_DELAY
;
3228 switch (scf_error()) {
3229 case SCF_ERROR_NOT_FOUND
:
3232 case SCF_ERROR_CONNECTION_BROKEN
:
3235 startd_free(restarter_fmri
, max_scf_value_size
);
3236 return (ECONNABORTED
);
3238 case SCF_ERROR_DELETED
:
3240 startd_free(restarter_fmri
, max_scf_value_size
);
3243 case SCF_ERROR_NOT_SET
:
3244 bad_error("scf_instance_get_pg", scf_error());
3247 switch (err
= libscf_instance_get_fmri(inst
,
3248 (char **)&idata
.i_fmri
)) {
3255 startd_free(restarter_fmri
, max_scf_value_size
);
3259 bad_error("libscf_instance_get_fmri", err
);
3262 idata
.i_state
= RESTARTER_STATE_NONE
;
3263 idata
.i_next_state
= RESTARTER_STATE_NONE
;
3266 switch (err
= _restarter_commit_states(h
, &idata
,
3267 RESTARTER_STATE_UNINIT
, RESTARTER_STATE_NONE
,
3268 restarter_get_str_short(restarter_str_insert_in_graph
))) {
3274 if (count
< ALLOC_RETRY
) {
3275 (void) poll(NULL
, 0, msecs
);
3276 msecs
*= ALLOC_DELAY_MULT
;
3280 uu_die("Insufficient memory.\n");
3284 startd_free((void *)idata
.i_fmri
, max_scf_fmri_size
);
3286 startd_free(restarter_fmri
, max_scf_value_size
);
3287 return (ECONNABORTED
);
3290 startd_free((void *)idata
.i_fmri
, max_scf_fmri_size
);
3292 startd_free(restarter_fmri
, max_scf_value_size
);
3298 log_error(LOG_NOTICE
, "Could not initialize state for "
3299 "%s: %s.\n", idata
.i_fmri
, strerror(err
));
3304 bad_error("_restarter_commit_states", err
);
3307 startd_free((void *)idata
.i_fmri
, max_scf_fmri_size
);
3312 if (milestone
!= NULL
) {
3314 * Make sure the enable-override is set properly before we
3315 * read whether we should be enabled.
3317 if (milestone
== MILESTONE_NONE
||
3318 !(v
->gv_flags
& GV_INSUBGRAPH
)) {
3320 * This might seem unjustified after the milestone
3321 * transition has completed (non_subgraph_svcs == 0),
3322 * but it's important because when we boot to
3323 * a milestone, we set the milestone before populating
3324 * the graph, and all of the new non-subgraph services
3325 * need to be disabled here.
3327 switch (err
= libscf_set_enable_ovr(inst
, 0)) {
3333 startd_free(restarter_fmri
, max_scf_value_size
);
3337 log_error(LOG_WARNING
,
3338 "Could not set %s/%s for %s: %s.\n",
3339 SCF_PG_GENERAL_OVR
, SCF_PROPERTY_ENABLED
,
3340 v
->gv_name
, strerror(err
));
3344 uu_die("Permission denied.\n");
3348 bad_error("libscf_set_enable_ovr", err
);
3351 assert(v
->gv_flags
& GV_INSUBGRAPH
);
3352 switch (err
= libscf_delete_enable_ovr(inst
)) {
3358 startd_free(restarter_fmri
, max_scf_value_size
);
3362 uu_die("Permission denied.\n");
3366 bad_error("libscf_delete_enable_ovr", err
);
3371 err
= libscf_get_basic_instance_data(h
, inst
, v
->gv_name
, &enabled
,
3372 &enabled_ovr
, &restarter_fmri
);
3379 startd_free(restarter_fmri
, max_scf_value_size
);
3383 log_framework(LOG_DEBUG
,
3384 "Ignoring %s because it has no general property group.\n",
3386 startd_free(restarter_fmri
, max_scf_value_size
);
3390 bad_error("libscf_get_basic_instance_data", err
);
3393 if ((tset
= libscf_get_stn_tset(inst
)) == -1) {
3394 log_framework(LOG_WARNING
,
3395 "Failed to get notification parameters for %s: %s\n",
3396 v
->gv_name
, scf_strerror(scf_error()));
3399 v
->gv_stn_tset
= tset
;
3401 if (strcmp(v
->gv_name
, SCF_INSTANCE_GLOBAL
) == 0)
3402 stn_global
= v
->gv_stn_tset
;
3404 if (enabled
== -1) {
3405 startd_free(restarter_fmri
, max_scf_value_size
);
3409 v
->gv_flags
= (v
->gv_flags
& ~GV_ENBLD_NOOVR
) |
3410 (enabled
? GV_ENBLD_NOOVR
: 0);
3412 if (enabled_ovr
!= -1)
3413 enabled
= enabled_ovr
;
3415 v
->gv_state
= RESTARTER_STATE_UNINIT
;
3417 snap
= libscf_get_or_make_running_snapshot(inst
, v
->gv_name
, B_TRUE
);
3418 scf_snapshot_destroy(snap
);
3420 /* Set up the restarter. (Sends _ADD_INSTANCE on success.) */
3421 err
= graph_change_restarter(v
, restarter_fmri
, h
, &path
);
3423 instance_data_t idata
;
3424 uint_t count
= 0, msecs
= ALLOC_DELAY
;
3425 restarter_str_t reason
;
3427 if (err
== ECONNABORTED
) {
3428 startd_free(restarter_fmri
, max_scf_value_size
);
3432 assert(err
== EINVAL
|| err
== ELOOP
);
3434 if (err
== EINVAL
) {
3435 log_framework(LOG_ERR
, emsg_invalid_restarter
,
3436 v
->gv_name
, restarter_fmri
);
3437 reason
= restarter_str_invalid_restarter
;
3439 handle_cycle(v
->gv_name
, path
);
3440 reason
= restarter_str_dependency_cycle
;
3443 startd_free(restarter_fmri
, max_scf_value_size
);
3446 * We didn't register the instance with the restarter, so we
3447 * must set maintenance mode ourselves.
3449 err
= libscf_instance_get_fmri(inst
, (char **)&idata
.i_fmri
);
3451 assert(err
== ECONNABORTED
|| err
== ECANCELED
);
3455 idata
.i_state
= RESTARTER_STATE_NONE
;
3456 idata
.i_next_state
= RESTARTER_STATE_NONE
;
3459 switch (err
= _restarter_commit_states(h
, &idata
,
3460 RESTARTER_STATE_MAINT
, RESTARTER_STATE_NONE
,
3461 restarter_get_str_short(reason
))) {
3467 if (count
< ALLOC_RETRY
) {
3468 (void) poll(NULL
, 0, msecs
);
3469 msecs
*= ALLOC_DELAY_MULT
;
3473 uu_die("Insufficient memory.\n");
3477 startd_free((void *)idata
.i_fmri
, max_scf_fmri_size
);
3478 return (ECONNABORTED
);
3481 startd_free((void *)idata
.i_fmri
, max_scf_fmri_size
);
3487 log_error(LOG_NOTICE
, "Could not initialize state for "
3488 "%s: %s.\n", idata
.i_fmri
, strerror(err
));
3493 bad_error("_restarter_commit_states", err
);
3496 startd_free((void *)idata
.i_fmri
, max_scf_fmri_size
);
3498 v
->gv_state
= RESTARTER_STATE_MAINT
;
3502 startd_free(restarter_fmri
, max_scf_value_size
);
3504 /* Add all the other dependencies. */
3505 err
= refresh_vertex(v
, inst
);
3507 assert(err
== ECONNABORTED
);
3512 v
->gv_flags
|= GV_CONFIGURED
;
3514 graph_enable_by_vertex(v
, enabled
, 0);
3521 kill_user_procs(void)
3523 (void) fputs("svc.startd: Killing user processes.\n", stdout
);
3526 * Despite its name, killall's role is to get select user processes--
3527 * basically those representing terminal-based logins-- to die. Victims
3528 * are located by killall in the utmp database. Since these are most
3529 * often shell based logins, and many shells mask SIGTERM (but are
3530 * responsive to SIGHUP) we first HUP and then shortly thereafter
3533 (void) fork_with_timeout("/usr/sbin/killall HUP", 1, 5);
3534 (void) fork_with_timeout("/usr/sbin/killall KILL", 1, 5);
3537 * Note the selection of user id's 0, 1 and 15, subsequently
3538 * inverted by -v. 15 is reserved for dladmd. Yes, this is a
3539 * kludge-- a better policy is needed.
3541 * Note that fork_with_timeout will only wait out the 1 second
3542 * "grace time" if pkill actually returns 0. So if there are
3543 * no matches, this will run to completion much more quickly.
3545 (void) fork_with_timeout("/usr/bin/pkill -TERM -v -u 0,1,15", 1, 5);
3546 (void) fork_with_timeout("/usr/bin/pkill -KILL -v -u 0,1,15", 1, 5);
3552 const char * const resetting
= "/etc/svc/volatile/resetting";
3557 char down_buf
[256], time_buf
[256];
3564 fd
= creat(resetting
, 0777);
3568 uu_warn("Could not create \"%s\"", resetting
);
3570 /* Kill dhcpagent if we're not using nfs for root */
3571 if ((statvfs("/", &vfs
) == 0) &&
3572 (strncmp(vfs
.f_basetype
, "nfs", sizeof ("nfs") - 1) != 0))
3573 fork_with_timeout("/usr/bin/pkill -x -u 0 dhcpagent", 0, 5);
3576 * Call sync(2) now, before we kill off user processes. This takes
3577 * advantage of the several seconds of pause we have before the
3578 * killalls are done. Time we can make good use of to get pages
3579 * moving out to disk.
3581 * Inside non-global zones, we don't bother, and it's better not to
3582 * anyway, since sync(2) can have system-wide impact.
3584 if (getzoneid() == 0)
3590 * Note that this must come after the killing of user procs, since
3591 * killall relies on utmpx, and this command affects the contents of
3594 if (access("/usr/lib/acct/closewtmp", X_OK
) == 0)
3595 fork_with_timeout("/usr/lib/acct/closewtmp", 0, 5);
3598 * For patches which may be installed as the system is shutting
3599 * down, we need to ensure, one more time, that the boot archive
3600 * really is up to date.
3602 if (getzoneid() == 0 && access("/usr/sbin/bootadm", X_OK
) == 0)
3603 fork_with_timeout("/usr/sbin/bootadm -ea update_all", 0, 3600);
3606 * Right now, fast reboot is supported only on i386.
3607 * scf_is_fastboot_default() should take care of it.
3608 * If somehow we got there on unsupported platform -
3609 * print warning and fall back to regular reboot.
3611 if (halting
== AD_FASTREBOOT
) {
3613 if (be_get_boot_args(&fbarg
, BE_ENTRY_DEFAULT
) == 0) {
3614 mdep
= (uintptr_t)fbarg
;
3617 * Failed to read BE info, fall back to normal reboot
3620 uu_warn("Failed to get fast reboot arguments.\n"
3621 "Falling back to regular reboot.\n");
3625 uu_warn("Fast reboot configured, but not supported by "
3630 fork_with_timeout("/sbin/umountall -l", 0, 5);
3631 fork_with_timeout("/sbin/umount /tmp /var/adm /var/run /var "
3632 ">/dev/null 2>&1", 0, 5);
3635 * Try to get to consistency for whatever UFS filesystems are left.
3636 * This is pretty expensive, so we save it for the end in the hopes of
3637 * minimizing what it must do. The other option would be to start in
3638 * parallel with the killall's, but lockfs tends to throw out much more
3639 * than is needed, and so subsequent commands (like umountall) take a
3640 * long time to get going again.
3642 * Inside of zones, we don't bother, since we're not about to terminate
3643 * the whole OS instance.
3645 * On systems using only ZFS, this call to lockfs -fa is a no-op.
3647 if (getzoneid() == 0) {
3648 if (access("/usr/sbin/lockfs", X_OK
) == 0)
3649 fork_with_timeout("/usr/sbin/lockfs -fa", 0, 30);
3651 sync(); /* once more, with feeling */
3654 fork_with_timeout("/sbin/umount /usr >/dev/null 2>&1", 0, 5);
3657 * Construct and emit the last words from userland:
3658 * "<timestamp> The system is down. Shutdown took <N> seconds."
3660 * Normally we'd use syslog, but with /var and other things
3661 * potentially gone, try to minimize the external dependencies.
3664 (void) localtime_r(&now
, &nowtm
);
3666 if (strftime(down_buf
, sizeof (down_buf
),
3667 "%b %e %T The system is down.", &nowtm
) == 0) {
3668 (void) strlcpy(down_buf
, "The system is down.",
3672 if (halting_time
!= 0 && halting_time
<= now
) {
3673 (void) snprintf(time_buf
, sizeof (time_buf
),
3674 " Shutdown took %lu seconds.", now
- halting_time
);
3678 (void) printf("%s%s\n", down_buf
, time_buf
);
3680 (void) uadmin(A_SHUTDOWN
, halting
, mdep
);
3681 uu_warn("uadmin() failed");
3684 if (halting
== AD_FASTREBOOT
)
3688 if (remove(resetting
) != 0 && errno
!= ENOENT
)
3689 uu_warn("Could not remove \"%s\"", resetting
);
3693 * If any of the up_svcs[] are online or satisfiable, return true. If they are
3694 * all missing, disabled, in maintenance, or unsatisfiable, return false.
3701 assert(MUTEX_HELD(&dgraph_lock
));
3704 * If we are booting to single user (boot -s),
3705 * SCF_MILESTONE_SINGLE_USER is needed to come up because startd
3706 * spawns sulogin after single-user is online (see specials.c).
3708 i
= (booting_to_single_user
? 0 : 1);
3710 for (; up_svcs
[i
] != NULL
; ++i
) {
3711 if (up_svcs_p
[i
] == NULL
) {
3712 up_svcs_p
[i
] = vertex_get_by_name(up_svcs
[i
]);
3714 if (up_svcs_p
[i
] == NULL
)
3719 * Ignore unconfigured services (the ones that have been
3720 * mentioned in a dependency from other services, but do
3721 * not exist in the repository). Services which exist
3722 * in the repository but don't have general/enabled
3723 * property will be also ignored.
3725 if (!(up_svcs_p
[i
]->gv_flags
& GV_CONFIGURED
))
3728 switch (up_svcs_p
[i
]->gv_state
) {
3729 case RESTARTER_STATE_ONLINE
:
3730 case RESTARTER_STATE_DEGRADED
:
3732 * Deactivate verbose boot once a login service has been
3735 st
->st_log_login_reached
= 1;
3737 case RESTARTER_STATE_UNINIT
:
3740 case RESTARTER_STATE_OFFLINE
:
3741 if (instance_satisfied(up_svcs_p
[i
], B_TRUE
) != -1)
3743 log_framework(LOG_DEBUG
,
3744 "can_come_up(): %s is unsatisfiable.\n",
3745 up_svcs_p
[i
]->gv_name
);
3748 case RESTARTER_STATE_DISABLED
:
3749 case RESTARTER_STATE_MAINT
:
3750 log_framework(LOG_DEBUG
,
3751 "can_come_up(): %s is in state %s.\n",
3752 up_svcs_p
[i
]->gv_name
,
3753 instance_state_str
[up_svcs_p
[i
]->gv_state
]);
3758 uu_warn("%s:%d: Unexpected vertex state %d.\n",
3759 __FILE__
, __LINE__
, up_svcs_p
[i
]->gv_state
);
3766 * In the seed repository, console-login is unsatisfiable because
3767 * services are missing. To behave correctly in that case we don't want
3768 * to return false until manifest-import is online.
3771 if (manifest_import_p
== NULL
) {
3772 manifest_import_p
= vertex_get_by_name(manifest_import
);
3774 if (manifest_import_p
== NULL
)
3778 switch (manifest_import_p
->gv_state
) {
3779 case RESTARTER_STATE_ONLINE
:
3780 case RESTARTER_STATE_DEGRADED
:
3781 case RESTARTER_STATE_DISABLED
:
3782 case RESTARTER_STATE_MAINT
:
3785 case RESTARTER_STATE_OFFLINE
:
3786 if (instance_satisfied(manifest_import_p
, B_TRUE
) == -1)
3790 case RESTARTER_STATE_UNINIT
:
3798 * Runs sulogin. Returns
3800 * EALREADY - sulogin is already running
3801 * EBUSY - console-login is running
3804 run_sulogin(const char *msg
)
3808 assert(MUTEX_HELD(&dgraph_lock
));
3810 if (sulogin_running
)
3813 v
= vertex_get_by_name(console_login_fmri
);
3814 if (v
!= NULL
&& inst_running(v
))
3817 sulogin_running
= B_TRUE
;
3819 MUTEX_UNLOCK(&dgraph_lock
);
3821 fork_sulogin(B_FALSE
, msg
);
3823 MUTEX_LOCK(&dgraph_lock
);
3825 sulogin_running
= B_FALSE
;
3827 if (console_login_ready
) {
3828 v
= vertex_get_by_name(console_login_fmri
);
3830 if (v
!= NULL
&& v
->gv_state
== RESTARTER_STATE_OFFLINE
) {
3831 if (v
->gv_start_f
== NULL
)
3832 vertex_send_event(v
,
3833 RESTARTER_EVENT_TYPE_START
);
3838 console_login_ready
= B_FALSE
;
3845 * The sulogin thread runs sulogin while can_come_up() is false. run_sulogin()
3846 * keeps sulogin from stepping on console-login's toes.
3850 sulogin_thread(void *unused
)
3852 MUTEX_LOCK(&dgraph_lock
);
3854 assert(sulogin_thread_running
);
3857 (void) run_sulogin("Console login service(s) cannot run\n");
3858 } while (!can_come_up());
3860 sulogin_thread_running
= B_FALSE
;
3861 MUTEX_UNLOCK(&dgraph_lock
);
3868 single_user_thread(void *unused
)
3872 scf_instance_t
*inst
;
3873 scf_property_t
*prop
;
3879 MUTEX_LOCK(&single_user_thread_lock
);
3880 single_user_thread_count
++;
3882 if (!booting_to_single_user
)
3885 if (go_single_user_mode
|| booting_to_single_user
) {
3886 msg
= "SINGLE USER MODE\n";
3888 assert(go_to_level1
);
3890 fork_rc_script('1', "start", B_TRUE
);
3892 uu_warn("The system is ready for administration.\n");
3897 MUTEX_UNLOCK(&single_user_thread_lock
);
3900 MUTEX_LOCK(&dgraph_lock
);
3901 r
= run_sulogin(msg
);
3902 MUTEX_UNLOCK(&dgraph_lock
);
3906 assert(r
== EALREADY
|| r
== EBUSY
);
3913 MUTEX_LOCK(&single_user_thread_lock
);
3916 * If another single user thread has started, let it finish changing
3919 if (single_user_thread_count
> 1) {
3920 single_user_thread_count
--;
3921 MUTEX_UNLOCK(&single_user_thread_lock
);
3925 h
= libscf_handle_create_bound_loop();
3926 inst
= scf_instance_create(h
);
3927 prop
= safe_scf_property_create(h
);
3928 val
= safe_scf_value_create(h
);
3929 buf
= startd_alloc(max_scf_fmri_size
);
3932 if (scf_handle_decode_fmri(h
, SCF_SERVICE_STARTD
, NULL
, NULL
, inst
,
3933 NULL
, NULL
, SCF_DECODE_FMRI_EXACT
) != 0) {
3934 switch (scf_error()) {
3935 case SCF_ERROR_NOT_FOUND
:
3936 r
= libscf_create_self(h
);
3939 assert(r
== ECONNABORTED
);
3942 case SCF_ERROR_CONNECTION_BROKEN
:
3943 libscf_handle_rebind(h
);
3946 case SCF_ERROR_INVALID_ARGUMENT
:
3947 case SCF_ERROR_CONSTRAINT_VIOLATED
:
3948 case SCF_ERROR_NOT_BOUND
:
3949 case SCF_ERROR_HANDLE_MISMATCH
:
3951 bad_error("scf_handle_decode_fmri", scf_error());
3955 MUTEX_LOCK(&dgraph_lock
);
3957 r
= scf_instance_delete_prop(inst
, SCF_PG_OPTIONS_OVR
,
3958 SCF_PROPERTY_MILESTONE
);
3965 MUTEX_UNLOCK(&dgraph_lock
);
3966 libscf_handle_rebind(h
);
3972 log_error(LOG_WARNING
, "Could not clear temporary milestone: "
3973 "%s.\n", strerror(r
));
3977 bad_error("scf_instance_delete_prop", r
);
3980 MUTEX_UNLOCK(&dgraph_lock
);
3982 r
= libscf_get_milestone(inst
, prop
, val
, buf
, max_scf_fmri_size
);
3987 (void) strcpy(buf
, "all");
3991 uu_warn("Returning to milestone %s.\n", buf
);
3995 libscf_handle_rebind(h
);
3999 bad_error("libscf_get_milestone", r
);
4002 r
= dgraph_set_milestone(buf
, h
, B_FALSE
);
4012 bad_error("dgraph_set_milestone", r
);
4016 * See graph_runlevel_changed().
4018 MUTEX_LOCK(&dgraph_lock
);
4019 utmpx_set_runlevel(target_milestone_as_runlevel(), 'S', B_TRUE
);
4020 MUTEX_UNLOCK(&dgraph_lock
);
4022 startd_free(buf
, max_scf_fmri_size
);
4023 scf_value_destroy(val
);
4024 scf_property_destroy(prop
);
4025 scf_instance_destroy(inst
);
4026 scf_handle_destroy(h
);
4029 * We'll give ourselves 3 seconds to respond to all of the enablings
4030 * that setting the milestone should have created before checking
4031 * whether to run sulogin.
4037 MUTEX_LOCK(&dgraph_lock
);
4039 * Clearing these variables will allow the sulogin thread to run. We
4040 * check here in case there aren't any more state updates anytime soon.
4042 go_to_level1
= go_single_user_mode
= booting_to_single_user
= B_FALSE
;
4043 if (!sulogin_thread_running
&& !can_come_up()) {
4044 (void) startd_thread_create(sulogin_thread
, NULL
);
4045 sulogin_thread_running
= B_TRUE
;
4047 MUTEX_UNLOCK(&dgraph_lock
);
4048 single_user_thread_count
--;
4049 MUTEX_UNLOCK(&single_user_thread_lock
);
4055 * Dependency graph operations API. These are handle-independent thread-safe
4056 * graph manipulation functions which are the entry points for the event
4061 * If a configured vertex exists for inst_fmri, return EEXIST. If no vertex
4062 * exists for inst_fmri, add one. Then fetch the restarter from inst, make
4063 * this vertex dependent on it, and send _ADD_INSTANCE to the restarter.
4064 * Fetch whether the instance should be enabled from inst and send _ENABLE or
4065 * _DISABLE as appropriate. Finally rummage through inst's dependency
4066 * property groups and add vertices and edges as appropriate. If anything
4067 * goes wrong after sending _ADD_INSTANCE, send _ADMIN_MAINT_ON to put the
4068 * instance in maintenance. Don't send _START or _STOP until we get a state
4069 * update in case we're being restarted and the service is already running.
4071 * To support booting to a milestone, we must also make sure all dependencies
4072 * encountered are configured, if they exist in the repository.
4074 * Returns 0 on success, ECONNABORTED on repository disconnection, EINVAL if
4075 * inst_fmri is an invalid (or not canonical) FMRI, ECANCELED if inst is
4076 * deleted, or EEXIST if a configured vertex for inst_fmri already exists.
4079 dgraph_add_instance(const char *inst_fmri
, scf_instance_t
*inst
,
4080 boolean_t lock_graph
)
4085 if (strcmp(inst_fmri
, SCF_SERVICE_STARTD
) == 0)
4088 /* Check for a vertex for inst_fmri. */
4090 MUTEX_LOCK(&dgraph_lock
);
4092 assert(MUTEX_HELD(&dgraph_lock
));
4095 v
= vertex_get_by_name(inst_fmri
);
4098 assert(v
->gv_type
== GVT_INST
);
4100 if (v
->gv_flags
& GV_CONFIGURED
) {
4102 MUTEX_UNLOCK(&dgraph_lock
);
4106 /* Add the vertex. */
4107 err
= graph_insert_vertex_unconfigured(inst_fmri
, GVT_INST
, 0,
4110 assert(err
== EINVAL
);
4112 MUTEX_UNLOCK(&dgraph_lock
);
4117 err
= configure_vertex(v
, inst
);
4120 MUTEX_UNLOCK(&dgraph_lock
);
4126 * Locate the vertex for this property group's instance. If it doesn't exist
4127 * or is unconfigured, call dgraph_add_instance() & return. Otherwise fetch
4128 * the restarter for the instance, and if it has changed, send
4129 * _REMOVE_INSTANCE to the old restarter, remove the dependency, make sure the
4130 * new restarter has a vertex, add a new dependency, and send _ADD_INSTANCE to
4131 * the new restarter. Then fetch whether the instance should be enabled, and
4132 * if it is different from what we had, or if we changed the restarter, send
4133 * the appropriate _ENABLE or _DISABLE command.
4135 * Returns 0 on success, ENOTSUP if the pg's parent is not an instance,
4136 * ECONNABORTED on repository disconnection, ECANCELED if the instance is
4137 * deleted, or -1 if the instance's general property group is deleted or if
4138 * its enabled property is misconfigured.
4141 dgraph_update_general(scf_propertygroup_t
*pg
)
4144 scf_instance_t
*inst
;
4146 char *restarter_fmri
;
4149 int enabled
, enabled_ovr
;
4152 /* Find the vertex for this service */
4153 h
= scf_pg_handle(pg
);
4155 inst
= safe_scf_instance_create(h
);
4157 if (scf_pg_get_parent_instance(pg
, inst
) != 0) {
4158 switch (scf_error()) {
4159 case SCF_ERROR_CONSTRAINT_VIOLATED
:
4162 case SCF_ERROR_CONNECTION_BROKEN
:
4164 return (ECONNABORTED
);
4166 case SCF_ERROR_DELETED
:
4169 case SCF_ERROR_NOT_SET
:
4170 bad_error("scf_pg_get_parent_instance", scf_error());
4174 err
= libscf_instance_get_fmri(inst
, &fmri
);
4180 scf_instance_destroy(inst
);
4181 return (ECONNABORTED
);
4184 scf_instance_destroy(inst
);
4188 bad_error("libscf_instance_get_fmri", err
);
4191 log_framework(LOG_DEBUG
,
4192 "Graph engine: Reloading general properties for %s.\n", fmri
);
4194 MUTEX_LOCK(&dgraph_lock
);
4196 v
= vertex_get_by_name(fmri
);
4197 if (v
== NULL
|| !(v
->gv_flags
& GV_CONFIGURED
)) {
4198 /* Will get the up-to-date properties. */
4199 MUTEX_UNLOCK(&dgraph_lock
);
4200 err
= dgraph_add_instance(fmri
, inst
, B_TRUE
);
4201 startd_free(fmri
, max_scf_fmri_size
);
4202 scf_instance_destroy(inst
);
4203 return (err
== ECANCELED
? 0 : err
);
4206 /* Read enabled & restarter from repository. */
4207 restarter_fmri
= startd_alloc(max_scf_value_size
);
4208 err
= libscf_get_basic_instance_data(h
, inst
, v
->gv_name
, &enabled
,
4209 &enabled_ovr
, &restarter_fmri
);
4210 if (err
!= 0 || enabled
== -1) {
4211 MUTEX_UNLOCK(&dgraph_lock
);
4212 scf_instance_destroy(inst
);
4213 startd_free(fmri
, max_scf_fmri_size
);
4218 startd_free(restarter_fmri
, max_scf_value_size
);
4223 startd_free(restarter_fmri
, max_scf_value_size
);
4227 bad_error("libscf_get_basic_instance_data", err
);
4231 oldflags
= v
->gv_flags
;
4232 v
->gv_flags
= (v
->gv_flags
& ~GV_ENBLD_NOOVR
) |
4233 (enabled
? GV_ENBLD_NOOVR
: 0);
4235 if (enabled_ovr
!= -1)
4236 enabled
= enabled_ovr
;
4239 * If GV_ENBLD_NOOVR has changed, then we need to re-evaluate the
4242 if (milestone
> MILESTONE_NONE
&& v
->gv_flags
!= oldflags
)
4243 (void) eval_subgraph(v
, h
);
4245 scf_instance_destroy(inst
);
4247 /* Ignore restarter change for now. */
4249 startd_free(restarter_fmri
, max_scf_value_size
);
4250 startd_free(fmri
, max_scf_fmri_size
);
4253 * Always send _ENABLE or _DISABLE. We could avoid this if the
4254 * restarter didn't change and the enabled value didn't change, but
4255 * that's not easy to check and improbable anyway, so we'll just do
4258 graph_enable_by_vertex(v
, enabled
, 1);
4260 MUTEX_UNLOCK(&dgraph_lock
);
4266 * Delete all of the property group dependencies of v, update inst's running
4267 * snapshot, and add the dependencies in the new snapshot. If any of the new
4268 * dependencies would create a cycle, send _ADMIN_MAINT_ON. Otherwise
4269 * reevaluate v's dependencies, send _START or _STOP as appropriate, and do
4270 * the same for v's dependents.
4274 * ECONNABORTED - repository connection broken
4275 * ECANCELED - inst was deleted
4276 * EINVAL - inst is invalid (e.g., missing general/enabled)
4277 * -1 - libscf_snapshots_refresh() failed
4280 dgraph_refresh_instance(graph_vertex_t
*v
, scf_instance_t
*inst
)
4286 assert(MUTEX_HELD(&dgraph_lock
));
4287 assert(v
->gv_type
== GVT_INST
);
4289 /* Only refresh services with valid general/enabled properties. */
4290 r
= libscf_get_basic_instance_data(scf_instance_handle(inst
), inst
,
4291 v
->gv_name
, &enabled
, NULL
, NULL
);
4301 log_framework(LOG_DEBUG
,
4302 "Ignoring %s because it has no general property group.\n",
4307 bad_error("libscf_get_basic_instance_data", r
);
4310 if ((tset
= libscf_get_stn_tset(inst
)) == -1) {
4311 log_framework(LOG_WARNING
,
4312 "Failed to get notification parameters for %s: %s\n",
4313 v
->gv_name
, scf_strerror(scf_error()));
4316 v
->gv_stn_tset
= tset
;
4317 if (strcmp(v
->gv_name
, SCF_INSTANCE_GLOBAL
) == 0)
4323 r
= libscf_snapshots_refresh(inst
, v
->gv_name
);
4326 bad_error("libscf_snapshots_refresh", r
);
4332 r
= refresh_vertex(v
, inst
);
4333 if (r
!= 0 && r
!= ECONNABORTED
)
4334 bad_error("refresh_vertex", r
);
4339 * Returns true only if none of this service's dependents are 'up' -- online
4340 * or degraded (offline is considered down in this situation). This function
4341 * is somehow similar to is_nonsubgraph_leaf() but works on subtrees.
4344 insubtree_dependents_down(graph_vertex_t
*v
)
4349 assert(MUTEX_HELD(&dgraph_lock
));
4351 for (e
= uu_list_first(v
->gv_dependents
); e
!= NULL
;
4352 e
= uu_list_next(v
->gv_dependents
, e
)) {
4354 if (vv
->gv_type
== GVT_INST
) {
4355 if ((vv
->gv_flags
& GV_CONFIGURED
) == 0)
4358 if ((vv
->gv_flags
& GV_TOOFFLINE
) == 0)
4361 if ((vv
->gv_state
== RESTARTER_STATE_ONLINE
) ||
4362 (vv
->gv_state
== RESTARTER_STATE_DEGRADED
))
4366 * Skip all excluded dependents and decide whether
4367 * to offline the service based on the restart_on
4370 if (is_depgrp_bypassed(vv
))
4374 * For dependency groups or service vertices, keep
4375 * traversing to see if instances are running.
4377 if (insubtree_dependents_down(vv
) == B_FALSE
)
4386 * Returns true only if none of this service's dependents are 'up' -- online,
4387 * degraded, or offline.
4390 is_nonsubgraph_leaf(graph_vertex_t
*v
)
4395 assert(MUTEX_HELD(&dgraph_lock
));
4397 for (e
= uu_list_first(v
->gv_dependents
);
4399 e
= uu_list_next(v
->gv_dependents
, e
)) {
4402 if (vv
->gv_type
== GVT_INST
) {
4403 if ((vv
->gv_flags
& GV_CONFIGURED
) == 0)
4406 if (vv
->gv_flags
& GV_INSUBGRAPH
)
4409 if (up_state(vv
->gv_state
))
4413 * For dependency group or service vertices, keep
4414 * traversing to see if instances are running.
4416 * We should skip exclude_all dependencies otherwise
4417 * the vertex will never be considered as a leaf
4418 * if the dependent is offline. The main reason for
4419 * this is that disable_nonsubgraph_leaves() skips
4420 * exclusion dependencies.
4422 if (vv
->gv_type
== GVT_GROUP
&&
4423 vv
->gv_depgroup
== DEPGRP_EXCLUDE_ALL
)
4426 if (!is_nonsubgraph_leaf(vv
))
4435 * Disable v temporarily. Attempt to do this by setting its enabled override
4436 * property in the repository. If that fails, send a _DISABLE command.
4437 * Returns 0 on success and ECONNABORTED if the repository connection is
4441 disable_service_temporarily(graph_vertex_t
*v
, scf_handle_t
*h
)
4443 const char * const emsg
= "Could not temporarily disable %s because "
4444 "%s. Will stop service anyways. Repository status for the "
4445 "service may be inaccurate.\n";
4446 const char * const emsg_cbroken
=
4447 "the repository connection was broken";
4449 scf_instance_t
*inst
;
4452 inst
= scf_instance_create(h
);
4456 (void) snprintf(buf
, sizeof (buf
),
4457 "scf_instance_create() failed (%s)",
4458 scf_strerror(scf_error()));
4459 log_error(LOG_WARNING
, emsg
, v
->gv_name
, buf
);
4461 graph_enable_by_vertex(v
, 0, 0);
4465 r
= scf_handle_decode_fmri(h
, v
->gv_name
, NULL
, NULL
, inst
,
4466 NULL
, NULL
, SCF_DECODE_FMRI_EXACT
);
4468 switch (scf_error()) {
4469 case SCF_ERROR_CONNECTION_BROKEN
:
4470 log_error(LOG_WARNING
, emsg
, v
->gv_name
, emsg_cbroken
);
4471 graph_enable_by_vertex(v
, 0, 0);
4472 return (ECONNABORTED
);
4474 case SCF_ERROR_NOT_FOUND
:
4477 case SCF_ERROR_HANDLE_MISMATCH
:
4478 case SCF_ERROR_INVALID_ARGUMENT
:
4479 case SCF_ERROR_CONSTRAINT_VIOLATED
:
4480 case SCF_ERROR_NOT_BOUND
:
4482 bad_error("scf_handle_decode_fmri",
4487 r
= libscf_set_enable_ovr(inst
, 0);
4490 scf_instance_destroy(inst
);
4494 scf_instance_destroy(inst
);
4498 log_error(LOG_WARNING
, emsg
, v
->gv_name
, emsg_cbroken
);
4499 graph_enable_by_vertex(v
, 0, 0);
4500 return (ECONNABORTED
);
4503 log_error(LOG_WARNING
, emsg
, v
->gv_name
,
4504 "the repository denied permission");
4505 graph_enable_by_vertex(v
, 0, 0);
4509 log_error(LOG_WARNING
, emsg
, v
->gv_name
,
4510 "the repository is read-only");
4511 graph_enable_by_vertex(v
, 0, 0);
4515 bad_error("libscf_set_enable_ovr", r
);
4521 * Of the transitive instance dependencies of v, offline those which are
4522 * in the subtree and which are leaves (i.e., have no dependents which are
4526 offline_subtree_leaves(graph_vertex_t
*v
, void *arg
)
4528 assert(MUTEX_HELD(&dgraph_lock
));
4530 /* If v isn't an instance, recurse on its dependencies. */
4531 if (v
->gv_type
!= GVT_INST
) {
4532 graph_walk_dependencies(v
, offline_subtree_leaves
, arg
);
4537 * If v is not in the subtree, so should all of its dependencies,
4540 if ((v
->gv_flags
& GV_TOOFFLINE
) == 0)
4543 /* If v isn't a leaf because it's already down, recurse. */
4544 if (!up_state(v
->gv_state
)) {
4545 graph_walk_dependencies(v
, offline_subtree_leaves
, arg
);
4549 /* if v is a leaf, offline it or disable it if it's the last one */
4550 if (insubtree_dependents_down(v
) == B_TRUE
) {
4551 if (v
->gv_flags
& GV_TODISABLE
)
4552 vertex_send_event(v
,
4553 RESTARTER_EVENT_TYPE_ADMIN_DISABLE
);
4560 graph_offline_subtree_leaves(graph_vertex_t
*v
, void *h
)
4562 graph_walk_dependencies(v
, offline_subtree_leaves
, (void *)h
);
4567 * Of the transitive instance dependencies of v, disable those which are not
4568 * in the subgraph and which are leaves (i.e., have no dependents which are
4572 disable_nonsubgraph_leaves(graph_vertex_t
*v
, void *arg
)
4574 assert(MUTEX_HELD(&dgraph_lock
));
4577 * We must skip exclusion dependencies because they are allowed to
4578 * complete dependency cycles. This is correct because A's exclusion
4579 * dependency on B doesn't bear on the order in which they should be
4580 * stopped. Indeed, the exclusion dependency should guarantee that
4581 * they are never online at the same time.
4583 if (v
->gv_type
== GVT_GROUP
&& v
->gv_depgroup
== DEPGRP_EXCLUDE_ALL
)
4586 /* If v isn't an instance, recurse on its dependencies. */
4587 if (v
->gv_type
!= GVT_INST
)
4590 if ((v
->gv_flags
& GV_CONFIGURED
) == 0)
4592 * Unconfigured instances should have no dependencies, but in
4593 * case they ever get them,
4598 * If v is in the subgraph, so should all of its dependencies, so do
4601 if (v
->gv_flags
& GV_INSUBGRAPH
)
4604 /* If v isn't a leaf because it's already down, recurse. */
4605 if (!up_state(v
->gv_state
))
4608 /* If v is disabled but not down yet, be patient. */
4609 if ((v
->gv_flags
& GV_ENABLED
) == 0)
4612 /* If v is a leaf, disable it. */
4613 if (is_nonsubgraph_leaf(v
))
4614 (void) disable_service_temporarily(v
, (scf_handle_t
*)arg
);
4619 graph_walk_dependencies(v
, disable_nonsubgraph_leaves
, arg
);
4623 stn_restarter_state(restarter_instance_state_t rstate
)
4625 static const struct statemap
{
4626 restarter_instance_state_t restarter_state
;
4629 { RESTARTER_STATE_UNINIT
, SCF_STATE_UNINIT
},
4630 { RESTARTER_STATE_MAINT
, SCF_STATE_MAINT
},
4631 { RESTARTER_STATE_OFFLINE
, SCF_STATE_OFFLINE
},
4632 { RESTARTER_STATE_DISABLED
, SCF_STATE_DISABLED
},
4633 { RESTARTER_STATE_ONLINE
, SCF_STATE_ONLINE
},
4634 { RESTARTER_STATE_DEGRADED
, SCF_STATE_DEGRADED
}
4639 for (i
= 0; i
< sizeof (map
) / sizeof (map
[0]); i
++) {
4640 if (rstate
== map
[i
].restarter_state
)
4641 return (map
[i
].scf_state
);
4648 * State transition counters
4649 * Not incremented atomically - indicative only
4651 static uint64_t stev_ct_maint
;
4652 static uint64_t stev_ct_hwerr
;
4653 static uint64_t stev_ct_service
;
4654 static uint64_t stev_ct_global
;
4655 static uint64_t stev_ct_noprefs
;
4656 static uint64_t stev_ct_from_uninit
;
4657 static uint64_t stev_ct_bad_state
;
4658 static uint64_t stev_ct_ovr_prefs
;
4661 dgraph_state_transition_notify(graph_vertex_t
*v
,
4662 restarter_instance_state_t old_state
, restarter_str_t reason
)
4664 restarter_instance_state_t new_state
= v
->gv_state
;
4665 int stn_transition
, maint
;
4668 fmev_pri_t pri
= FMEV_LOPRI
;
4671 if ((from
= stn_restarter_state(old_state
)) == -1 ||
4672 (to
= stn_restarter_state(new_state
)) == -1) {
4673 stev_ct_bad_state
++;
4677 stn_transition
= from
<< 16 | to
;
4679 maint
= (to
== SCF_STATE_MAINT
|| from
== SCF_STATE_MAINT
);
4683 * All transitions to/from maintenance state must raise
4689 } else if (reason
== restarter_str_ct_ev_hwerr
) {
4691 * All transitions caused by hardware fault must raise
4697 } else if (stn_transition
& v
->gv_stn_tset
) {
4699 * Specifically enabled event.
4703 } else if (from
== SCF_STATE_UNINIT
) {
4705 * Only raise these if specifically selected above.
4707 stev_ct_from_uninit
++;
4708 } else if (stn_transition
& stn_global
&&
4709 (IS_ENABLED(v
) == 1 || to
== SCF_STATE_DISABLED
)) {
4716 if (info_events_all
) {
4717 stev_ct_ovr_prefs
++;
4723 if (nvlist_alloc(&attr
, NV_UNIQUE_NAME
, 0) != 0 ||
4724 nvlist_add_string(attr
, "fmri", v
->gv_name
) != 0 ||
4725 nvlist_add_uint32(attr
, "reason-version",
4726 restarter_str_version()) || nvlist_add_string(attr
, "reason-short",
4727 restarter_get_str_short(reason
)) != 0 ||
4728 nvlist_add_string(attr
, "reason-long",
4729 restarter_get_str_long(reason
)) != 0 ||
4730 nvlist_add_int32(attr
, "transition", stn_transition
) != 0) {
4731 log_framework(LOG_WARNING
,
4732 "FMEV: %s could not create nvlist for transition "
4733 "event: %s\n", v
->gv_name
, strerror(errno
));
4738 if (fmev_rspublish_nvl(FMEV_RULESET_SMF
, "state-transition",
4739 instance_state_str
[new_state
], pri
, attr
) != FMEV_SUCCESS
) {
4740 log_framework(LOG_DEBUG
,
4741 "FMEV: %s failed to publish transition event: %s\n",
4742 v
->gv_name
, fmev_strerror(fmev_errno
));
4748 * Find the vertex for inst_name. If it doesn't exist, return ENOENT.
4749 * Otherwise set its state to state. If the instance has entered a state
4750 * which requires automatic action, take it (Uninitialized: do
4751 * dgraph_refresh_instance() without the snapshot update. Disabled: if the
4752 * instance should be enabled, send _ENABLE. Offline: if the instance should
4753 * be disabled, send _DISABLE, and if its dependencies are satisfied, send
4754 * _START. Online, Degraded: if the instance wasn't running, update its start
4755 * snapshot. Maintenance: no action.)
4757 * Also fails with ECONNABORTED, or EINVAL if state is invalid.
4760 dgraph_set_instance_state(scf_handle_t
*h
, const char *inst_name
,
4761 protocol_states_t
*states
)
4765 restarter_instance_state_t old_state
;
4766 restarter_instance_state_t state
= states
->ps_state
;
4767 restarter_error_t serr
= states
->ps_err
;
4769 MUTEX_LOCK(&dgraph_lock
);
4771 v
= vertex_get_by_name(inst_name
);
4773 MUTEX_UNLOCK(&dgraph_lock
);
4777 assert(v
->gv_type
== GVT_INST
);
4780 case RESTARTER_STATE_UNINIT
:
4781 case RESTARTER_STATE_DISABLED
:
4782 case RESTARTER_STATE_OFFLINE
:
4783 case RESTARTER_STATE_ONLINE
:
4784 case RESTARTER_STATE_DEGRADED
:
4785 case RESTARTER_STATE_MAINT
:
4789 MUTEX_UNLOCK(&dgraph_lock
);
4793 log_framework(LOG_DEBUG
, "Graph noting %s %s -> %s.\n", v
->gv_name
,
4794 instance_state_str
[v
->gv_state
], instance_state_str
[state
]);
4796 old_state
= v
->gv_state
;
4797 v
->gv_state
= state
;
4799 v
->gv_reason
= states
->ps_reason
;
4800 err
= gt_transition(h
, v
, serr
, old_state
);
4801 if (err
== 0 && v
->gv_state
!= old_state
) {
4802 dgraph_state_transition_notify(v
, old_state
, states
->ps_reason
);
4805 MUTEX_UNLOCK(&dgraph_lock
);
4810 * Handle state changes during milestone shutdown. See
4811 * dgraph_set_milestone(). If the repository connection is broken,
4812 * ECONNABORTED will be returned, though a _DISABLE command will be sent for
4813 * the vertex anyway.
4816 vertex_subgraph_dependencies_shutdown(scf_handle_t
*h
, graph_vertex_t
*v
,
4817 restarter_instance_state_t old_state
)
4822 assert(v
->gv_type
== GVT_INST
);
4824 /* Don't care if we're not going to a milestone. */
4825 if (milestone
== NULL
)
4828 /* Don't care if we already finished coming down. */
4829 if (non_subgraph_svcs
== 0)
4832 /* Don't care if the service is in the subgraph. */
4833 if (v
->gv_flags
& GV_INSUBGRAPH
)
4837 * Update non_subgraph_svcs. It is the number of non-subgraph
4838 * services which are in online, degraded, or offline.
4841 was_up
= up_state(old_state
);
4842 now_up
= up_state(v
->gv_state
);
4844 if (!was_up
&& now_up
) {
4845 ++non_subgraph_svcs
;
4846 } else if (was_up
&& !now_up
) {
4847 --non_subgraph_svcs
;
4849 if (non_subgraph_svcs
== 0) {
4850 if (halting
!= -1) {
4852 } else if (go_single_user_mode
|| go_to_level1
) {
4853 (void) startd_thread_create(single_user_thread
,
4860 /* If this service is a leaf, it should be disabled. */
4861 if ((v
->gv_flags
& GV_ENABLED
) && is_nonsubgraph_leaf(v
)) {
4864 r
= disable_service_temporarily(v
, h
);
4874 bad_error("disable_service_temporarily", r
);
4879 * If the service just came down, propagate the disable to the newly
4882 if (was_up
&& !now_up
)
4883 graph_walk_dependencies(v
, disable_nonsubgraph_leaves
,
4890 * Decide whether to start up an sulogin thread after a service is
4891 * finished changing state. Only need to do the full can_come_up()
4892 * evaluation if an instance is changing state, we're not halfway through
4893 * loading the thread, and we aren't shutting down or going to the single
4897 graph_transition_sulogin(restarter_instance_state_t state
,
4898 restarter_instance_state_t old_state
)
4900 assert(MUTEX_HELD(&dgraph_lock
));
4902 if (state
!= old_state
&& st
->st_load_complete
&&
4903 !go_single_user_mode
&& !go_to_level1
&&
4905 if (!sulogin_thread_running
&& !can_come_up()) {
4906 (void) startd_thread_create(sulogin_thread
, NULL
);
4907 sulogin_thread_running
= B_TRUE
;
4913 * Propagate a start, stop event, or a satisfiability event.
4915 * PROPAGATE_START and PROPAGATE_STOP simply propagate the transition event
4916 * to direct dependents. PROPAGATE_SAT propagates a start then walks the
4917 * full dependent graph to check for newly satisfied nodes. This is
4918 * necessary for cases when non-direct dependents may be effected but direct
4919 * dependents may not (e.g. for optional_all evaluations, see the
4920 * propagate_satbility() comments).
4922 * PROPAGATE_SAT should be used whenever a non-running service moves into
4923 * a state which can satisfy optional dependencies, like disabled or
4927 graph_transition_propagate(graph_vertex_t
*v
, propagate_event_t type
,
4928 restarter_error_t rerr
)
4930 if (type
== PROPAGATE_STOP
) {
4931 graph_walk_dependents(v
, propagate_stop
, (void *)rerr
);
4932 } else if (type
== PROPAGATE_START
|| type
== PROPAGATE_SAT
) {
4933 graph_walk_dependents(v
, propagate_start
, (void *)RERR_NONE
);
4935 if (type
== PROPAGATE_SAT
)
4936 propagate_satbility(v
);
4939 uu_warn("%s:%d: Unexpected type value %d.\n", __FILE__
,
4947 * If a vertex for fmri exists and it is enabled, send _DISABLE to the
4948 * restarter. If it is running, send _STOP. Send _REMOVE_INSTANCE. Delete
4949 * all property group dependencies, and the dependency on the restarter,
4950 * disposing of vertices as appropriate. If other vertices depend on this
4951 * one, mark it unconfigured and return. Otherwise remove the vertex. Always
4955 dgraph_remove_instance(const char *fmri
, scf_handle_t
*h
)
4959 uu_list_t
*old_deps
;
4962 log_framework(LOG_DEBUG
, "Graph engine: Removing %s.\n", fmri
);
4964 MUTEX_LOCK(&dgraph_lock
);
4966 v
= vertex_get_by_name(fmri
);
4968 MUTEX_UNLOCK(&dgraph_lock
);
4972 /* Send restarter delete event. */
4973 if (v
->gv_flags
& GV_CONFIGURED
)
4974 graph_unset_restarter(v
);
4976 if (milestone
> MILESTONE_NONE
) {
4978 * Make a list of v's current dependencies so we can
4979 * reevaluate their GV_INSUBGRAPH flags after the dependencies
4982 old_deps
= startd_list_create(graph_edge_pool
, NULL
, 0);
4984 err
= uu_list_walk(v
->gv_dependencies
,
4985 (uu_walk_fn_t
*)append_svcs_or_insts
, old_deps
, 0);
4989 delete_instance_dependencies(v
, B_TRUE
);
4992 * Deleting an instance can both satisfy and unsatisfy dependencies,
4993 * depending on their type. First propagate the stop as a RERR_RESTART
4994 * event -- deletion isn't a fault, just a normal stop. This gives
4995 * dependent services the chance to do a clean shutdown. Then, mark
4996 * the service as unconfigured and propagate the start event for the
4997 * optional_all dependencies that might have become satisfied.
4999 graph_walk_dependents(v
, propagate_stop
, (void *)RERR_RESTART
);
5001 v
->gv_flags
&= ~GV_CONFIGURED
;
5002 v
->gv_flags
&= ~GV_DEATHROW
;
5004 graph_walk_dependents(v
, propagate_start
, (void *)RERR_NONE
);
5005 propagate_satbility(v
);
5008 * If there are no (non-service) dependents, the vertex can be
5009 * completely removed.
5011 if (v
!= milestone
&& v
->gv_refs
== 0 &&
5012 uu_list_numnodes(v
->gv_dependents
) == 1)
5013 remove_inst_vertex(v
);
5015 if (milestone
> MILESTONE_NONE
) {
5016 void *cookie
= NULL
;
5018 while ((e
= uu_list_teardown(old_deps
, &cookie
)) != NULL
) {
5021 if (vertex_unref(v
) == VERTEX_INUSE
)
5022 while (eval_subgraph(v
, h
) == ECONNABORTED
)
5023 libscf_handle_rebind(h
);
5025 startd_free(e
, sizeof (*e
));
5028 uu_list_destroy(old_deps
);
5031 MUTEX_UNLOCK(&dgraph_lock
);
5037 * Return the eventual (maybe current) milestone in the form of a
5041 target_milestone_as_runlevel()
5043 assert(MUTEX_HELD(&dgraph_lock
));
5045 if (milestone
== NULL
)
5047 else if (milestone
== MILESTONE_NONE
)
5050 if (strcmp(milestone
->gv_name
, multi_user_fmri
) == 0)
5052 else if (strcmp(milestone
->gv_name
, single_user_fmri
) == 0)
5054 else if (strcmp(milestone
->gv_name
, multi_user_svr_fmri
) == 0)
5058 (void) fprintf(stderr
, "%s:%d: Unknown milestone name \"%s\".\n",
5059 __FILE__
, __LINE__
, milestone
->gv_name
);
5081 signal_init(char rl
)
5086 assert(MUTEX_HELD(&dgraph_lock
));
5088 if (zone_getattr(getzoneid(), ZONE_ATTR_INITPID
, &init_pid
,
5089 sizeof (init_pid
)) != sizeof (init_pid
)) {
5090 log_error(LOG_NOTICE
, "Could not get pid to signal init.\n");
5094 for (i
= 0; init_sigs
[i
].rl
!= 0; ++i
)
5095 if (init_sigs
[i
].rl
== rl
)
5098 if (init_sigs
[i
].rl
!= 0) {
5099 if (kill(init_pid
, init_sigs
[i
].sig
) != 0) {
5103 log_error(LOG_NOTICE
, "Could not signal init: "
5104 "%s.\n", strerror(errno
));
5109 bad_error("kill", errno
);
5116 * This is called when one of the major milestones changes state, or when
5117 * init is signalled and tells us it was told to change runlevel. We wait
5118 * to reach the milestone because this allows /etc/inittab entries to retain
5119 * some boot ordering: historically, entries could place themselves before/after
5120 * the running of /sbin/rcX scripts but we can no longer make the
5121 * distinction because the /sbin/rcX scripts no longer exist as punctuation
5122 * marks in /etc/inittab.
5124 * Also, we only trigger an update when we reach the eventual target
5125 * milestone: without this, an /etc/inittab entry marked only for
5126 * runlevel 2 would be executed for runlevel 3, which is not how
5127 * /etc/inittab entries work.
5129 * If we're single user coming online, then we set utmpx to the target
5130 * runlevel so that legacy scripts can work as expected.
5133 graph_runlevel_changed(char rl
, int online
)
5137 assert(MUTEX_HELD(&dgraph_lock
));
5139 trl
= target_milestone_as_runlevel();
5143 current_runlevel
= trl
;
5145 } else if (rl
== 'S') {
5147 * At boot, set the entry early for the benefit of the
5148 * legacy init scripts.
5150 utmpx_set_runlevel(trl
, 'S', B_FALSE
);
5153 if (rl
== '3' && trl
== '2') {
5154 current_runlevel
= trl
;
5156 } else if (rl
== '2' && trl
== 'S') {
5157 current_runlevel
= trl
;
5164 * Move to a backwards-compatible runlevel by executing the appropriate
5165 * /etc/rc?.d/K* scripts and/or setting the milestone.
5169 * ECONNRESET - success, but handle was reset
5170 * ECONNABORTED - repository connection broken
5171 * ECANCELED - pg was deleted
5174 dgraph_set_runlevel(scf_propertygroup_t
*pg
, scf_property_t
*prop
)
5179 const char *ms
= NULL
; /* what to commit as options/milestone */
5180 boolean_t rebound
= B_FALSE
;
5183 const char * const stop
= "stop";
5185 r
= libscf_extract_runlevel(prop
, &rl
);
5196 log_error(LOG_WARNING
, "runlevel property is misconfigured; "
5198 /* delete the bad property */
5202 bad_error("libscf_extract_runlevel", r
);
5214 * These cases cause a milestone change, so
5215 * graph_runlevel_changed() will eventually deal with
5229 log_framework(LOG_NOTICE
, "Unknown runlevel '%c'.\n", rl
);
5234 h
= scf_pg_handle(pg
);
5236 MUTEX_LOCK(&dgraph_lock
);
5239 * Since this triggers no milestone changes, force it by hand.
5241 if (current_runlevel
== '4' && rl
== '3')
5245 * 1. If we are here after an "init X":
5248 * init/lscf_set_runlevel()
5249 * process_pg_event()
5250 * dgraph_set_runlevel()
5252 * then we haven't passed through graph_runlevel_changed() yet,
5253 * therefore 'current_runlevel' has not changed for sure but 'rl' has.
5254 * In consequence, if 'rl' is lower than 'current_runlevel', we change
5255 * the system runlevel and execute the appropriate /etc/rc?.d/K* scripts
5258 * 2. On the other hand, if we are here after a "svcadm milestone":
5260 * svcadm milestone X
5261 * dgraph_set_milestone()
5262 * handle_graph_update_event()
5263 * dgraph_set_instance_state()
5264 * graph_post_X_[online|offline]()
5265 * graph_runlevel_changed()
5267 * init/lscf_set_runlevel()
5268 * process_pg_event()
5269 * dgraph_set_runlevel()
5271 * then we already passed through graph_runlevel_changed() (by the way
5272 * of dgraph_set_milestone()) and 'current_runlevel' may have changed
5273 * and already be equal to 'rl' so we are going to return immediately
5274 * from dgraph_set_runlevel() without changing the system runlevel and
5275 * without executing the /etc/rc?.d/K* scripts.
5277 if (rl
== current_runlevel
) {
5282 log_framework(LOG_DEBUG
, "Changing to runlevel '%c'.\n", rl
);
5285 * Make sure stop rc scripts see the new settings via who -r.
5287 utmpx_set_runlevel(rl
, current_runlevel
, B_TRUE
);
5290 * Some run levels don't have a direct correspondence to any
5291 * milestones, so we have to signal init directly.
5294 current_runlevel
= rl
;
5300 uu_warn("The system is coming down for administration. "
5302 fork_rc_script(rl
, stop
, B_FALSE
);
5303 ms
= single_user_fmri
;
5304 go_single_user_mode
= B_TRUE
;
5308 halting_time
= time(NULL
);
5309 fork_rc_script(rl
, stop
, B_TRUE
);
5314 halting_time
= time(NULL
);
5315 fork_rc_script(rl
, stop
, B_TRUE
);
5316 halting
= AD_POWEROFF
;
5320 halting_time
= time(NULL
);
5321 fork_rc_script(rl
, stop
, B_TRUE
);
5322 if (scf_is_fastboot_default() && getzoneid() == GLOBAL_ZONEID
)
5323 halting
= AD_FASTREBOOT
;
5328 uu_warn("The system is coming down. Please wait.\n");
5332 * We can't wait until all services are offline since this
5333 * thread is responsible for taking them offline. Instead we
5334 * set halting to the second argument for uadmin() and call
5335 * do_uadmin() from dgraph_set_instance_state() when
5341 if (current_runlevel
!= 'S') {
5342 uu_warn("Changing to state 1.\n");
5343 fork_rc_script(rl
, stop
, B_FALSE
);
5345 uu_warn("The system is coming up for administration. "
5348 ms
= single_user_fmri
;
5349 go_to_level1
= B_TRUE
;
5353 if (current_runlevel
== '3' || current_runlevel
== '4')
5354 fork_rc_script(rl
, stop
, B_FALSE
);
5355 ms
= multi_user_fmri
;
5365 (void) fprintf(stderr
, "%s:%d: Uncaught case %d ('%c').\n",
5366 __FILE__
, __LINE__
, rl
, rl
);
5372 MUTEX_UNLOCK(&dgraph_lock
);
5375 switch (r
= libscf_clear_runlevel(pg
, ms
)) {
5380 libscf_handle_rebind(h
);
5390 log_error(LOG_NOTICE
, "Could not delete \"%s/%s\" property: "
5391 "%s.\n", SCF_PG_OPTIONS
, "runlevel", strerror(r
));
5395 bad_error("libscf_clear_runlevel", r
);
5398 return (rebound
? ECONNRESET
: 0);
5402 * mark_subtree walks the dependents and add the GV_TOOFFLINE flag
5403 * to the instances that are supposed to go offline during an
5404 * administrative disable operation.
5407 mark_subtree(graph_edge_t
*e
, void *arg
)
5414 /* If it's already in the subgraph, skip. */
5415 if (v
->gv_flags
& GV_TOOFFLINE
)
5416 return (UU_WALK_NEXT
);
5418 switch (v
->gv_type
) {
5420 /* If the instance is already offline, skip it. */
5421 if (!inst_running(v
))
5422 return (UU_WALK_NEXT
);
5424 v
->gv_flags
|= GV_TOOFFLINE
;
5425 log_framework(LOG_DEBUG
, "%s added to subtree\n", v
->gv_name
);
5429 * Skip all excluded dependents and decide whether to offline
5430 * the service based on the restart_on attribute.
5432 if (is_depgrp_bypassed(v
))
5433 return (UU_WALK_NEXT
);
5437 r
= uu_list_walk(v
->gv_dependents
, (uu_walk_fn_t
*)mark_subtree
, arg
,
5440 return (UU_WALK_NEXT
);
5444 mark_subgraph(graph_edge_t
*e
, void *arg
)
5448 int optional
= (int)arg
;
5452 /* If it's already in the subgraph, skip. */
5453 if (v
->gv_flags
& GV_INSUBGRAPH
)
5454 return (UU_WALK_NEXT
);
5457 * Keep track if walk has entered an optional dependency group
5459 if (v
->gv_type
== GVT_GROUP
&& v
->gv_depgroup
== DEPGRP_OPTIONAL_ALL
) {
5463 * Quit if we are in an optional dependency group and the instance
5466 if (optional
&& (v
->gv_type
== GVT_INST
) &&
5467 (!(v
->gv_flags
& GV_ENBLD_NOOVR
)))
5468 return (UU_WALK_NEXT
);
5470 v
->gv_flags
|= GV_INSUBGRAPH
;
5472 /* Skip all excluded dependencies. */
5473 if (v
->gv_type
== GVT_GROUP
&& v
->gv_depgroup
== DEPGRP_EXCLUDE_ALL
)
5474 return (UU_WALK_NEXT
);
5476 r
= uu_list_walk(v
->gv_dependencies
, (uu_walk_fn_t
*)mark_subgraph
,
5477 (void *)optional
, 0);
5479 return (UU_WALK_NEXT
);
5483 * Bring down all services which are not dependencies of fmri. The
5484 * dependencies of fmri (direct & indirect) will constitute the "subgraph",
5485 * and will have the GV_INSUBGRAPH flag set. The rest must be brought down,
5486 * which means the state is "disabled", "maintenance", or "uninitialized". We
5487 * could consider "offline" to be down, and refrain from sending start
5488 * commands for such services, but that's not strictly necessary, so we'll
5489 * decline to intrude on the state machine. It would probably confuse users
5492 * The services should be brought down in reverse-dependency order, so we
5493 * can't do it all at once here. We initiate by override-disabling the leaves
5494 * of the dependency tree -- those services which are up but have no
5495 * dependents which are up. When they come down,
5496 * vertex_subgraph_dependencies_shutdown() will override-disable the newly
5497 * exposed leaves. Perseverance will ensure completion.
5499 * Sometimes we need to take action when the transition is complete, like
5500 * start sulogin or halt the system. To tell when we're done, we initialize
5501 * non_subgraph_svcs here to be the number of services which need to come
5502 * down. As each does, we decrement the counter. When it hits zero, we take
5503 * the appropriate action. See vertex_subgraph_dependencies_shutdown().
5505 * In case we're coming up, we also remove any enable-overrides for the
5506 * services which are dependencies of fmri.
5508 * If norepository is true, the function will not change the repository.
5510 * The decision to change the system run level in accordance with the milestone
5511 * is taken in dgraph_set_runlevel().
5515 * ECONNRESET - success, but handle was rebound
5516 * EINVAL - fmri is invalid (error is logged)
5517 * EALREADY - the milestone is already set to fmri
5518 * ENOENT - a configured vertex does not exist for fmri (an error is logged)
5521 dgraph_set_milestone(const char *fmri
, scf_handle_t
*h
, boolean_t norepository
)
5523 const char *cfmri
, *fs
;
5524 graph_vertex_t
*nm
, *v
;
5526 scf_instance_t
*inst
;
5527 boolean_t isall
, isnone
, rebound
= B_FALSE
;
5530 isall
= (strcmp(fmri
, "all") == 0);
5531 isnone
= (strcmp(fmri
, "none") == 0);
5533 if (!isall
&& !isnone
) {
5534 if (fmri_canonify(fmri
, (char **)&cfmri
, B_FALSE
) == EINVAL
)
5537 if (strcmp(cfmri
, single_user_fmri
) != 0 &&
5538 strcmp(cfmri
, multi_user_fmri
) != 0 &&
5539 strcmp(cfmri
, multi_user_svr_fmri
) != 0) {
5540 startd_free((void *)cfmri
, max_scf_fmri_size
);
5542 log_framework(LOG_WARNING
,
5543 "Rejecting request for invalid milestone \"%s\".\n",
5549 inst
= safe_scf_instance_create(h
);
5551 MUTEX_LOCK(&dgraph_lock
);
5553 if (milestone
== NULL
) {
5555 log_framework(LOG_DEBUG
,
5556 "Milestone already set to all.\n");
5560 } else if (milestone
== MILESTONE_NONE
) {
5562 log_framework(LOG_DEBUG
,
5563 "Milestone already set to none.\n");
5568 if (!isall
&& !isnone
&&
5569 strcmp(cfmri
, milestone
->gv_name
) == 0) {
5570 log_framework(LOG_DEBUG
,
5571 "Milestone already set to %s.\n", cfmri
);
5577 if (!isall
&& !isnone
) {
5578 nm
= vertex_get_by_name(cfmri
);
5579 if (nm
== NULL
|| !(nm
->gv_flags
& GV_CONFIGURED
)) {
5580 log_framework(LOG_WARNING
, "Cannot set milestone to %s "
5581 "because no such service exists.\n", cfmri
);
5587 log_framework(LOG_DEBUG
, "Changing milestone to %s.\n", fmri
);
5590 * Set milestone, removing the old one if this was the last reference.
5592 if (milestone
> MILESTONE_NONE
)
5593 (void) vertex_unref(milestone
);
5598 milestone
= MILESTONE_NONE
;
5601 /* milestone should count as a reference */
5602 vertex_ref(milestone
);
5605 /* Clear all GV_INSUBGRAPH bits. */
5606 for (v
= uu_list_first(dgraph
); v
!= NULL
; v
= uu_list_next(dgraph
, v
))
5607 v
->gv_flags
&= ~GV_INSUBGRAPH
;
5609 if (!isall
&& !isnone
) {
5610 /* Set GV_INSUBGRAPH for milestone & descendents. */
5611 milestone
->gv_flags
|= GV_INSUBGRAPH
;
5613 r
= uu_list_walk(milestone
->gv_dependencies
,
5614 (uu_walk_fn_t
*)mark_subgraph
, NULL
, 0);
5618 /* Un-override services in the subgraph & override-disable the rest. */
5622 non_subgraph_svcs
= 0;
5623 for (v
= uu_list_first(dgraph
);
5625 v
= uu_list_next(dgraph
, v
)) {
5626 if (v
->gv_type
!= GVT_INST
||
5627 (v
->gv_flags
& GV_CONFIGURED
) == 0)
5631 r
= scf_handle_decode_fmri(h
, v
->gv_name
, NULL
, NULL
, inst
,
5632 NULL
, NULL
, SCF_DECODE_FMRI_EXACT
);
5634 switch (scf_error()) {
5635 case SCF_ERROR_CONNECTION_BROKEN
:
5637 libscf_handle_rebind(h
);
5641 case SCF_ERROR_NOT_FOUND
:
5644 case SCF_ERROR_HANDLE_MISMATCH
:
5645 case SCF_ERROR_INVALID_ARGUMENT
:
5646 case SCF_ERROR_CONSTRAINT_VIOLATED
:
5647 case SCF_ERROR_NOT_BOUND
:
5648 bad_error("scf_handle_decode_fmri",
5653 if (isall
|| (v
->gv_flags
& GV_INSUBGRAPH
)) {
5654 r
= libscf_delete_enable_ovr(inst
);
5655 fs
= "libscf_delete_enable_ovr";
5657 assert(isnone
|| (v
->gv_flags
& GV_INSUBGRAPH
) == 0);
5660 * Services which are up need to come down before
5661 * we're done, but we can only disable the leaves
5665 if (up_state(v
->gv_state
))
5666 ++non_subgraph_svcs
;
5668 /* If it's already disabled, don't bother. */
5669 if ((v
->gv_flags
& GV_ENABLED
) == 0)
5672 if (!is_nonsubgraph_leaf(v
))
5675 r
= libscf_set_enable_ovr(inst
, 0);
5676 fs
= "libscf_set_enable_ovr";
5684 libscf_handle_rebind(h
);
5690 log_error(LOG_WARNING
,
5691 "Could not set %s/%s for %s: %s.\n",
5692 SCF_PG_GENERAL_OVR
, SCF_PROPERTY_ENABLED
,
5693 v
->gv_name
, strerror(r
));
5701 if (halting
!= -1) {
5702 if (non_subgraph_svcs
> 1)
5703 uu_warn("%d system services are now being stopped.\n",
5705 else if (non_subgraph_svcs
== 1)
5706 uu_warn("One system service is now being stopped.\n");
5707 else if (non_subgraph_svcs
== 0)
5711 ret
= rebound
? ECONNRESET
: 0;
5714 MUTEX_UNLOCK(&dgraph_lock
);
5715 if (!isall
&& !isnone
)
5716 startd_free((void *)cfmri
, max_scf_fmri_size
);
5717 scf_instance_destroy(inst
);
5723 * Returns 0, ECONNABORTED, or EINVAL.
5726 handle_graph_update_event(scf_handle_t
*h
, graph_protocol_event_t
*e
)
5730 switch (e
->gpe_type
) {
5731 case GRAPH_UPDATE_RELOAD_GRAPH
:
5732 log_error(LOG_WARNING
,
5733 "graph_event: reload graph unimplemented\n");
5736 case GRAPH_UPDATE_STATE_CHANGE
: {
5737 protocol_states_t
*states
= e
->gpe_data
;
5739 switch (r
= dgraph_set_instance_state(h
, e
->gpe_inst
, states
)) {
5745 return (ECONNABORTED
);
5750 (void) fprintf(stderr
, "dgraph_set_instance_state() "
5751 "failed with unexpected error %d at %s:%d.\n", r
,
5752 __FILE__
, __LINE__
);
5757 startd_free(states
, sizeof (protocol_states_t
));
5762 log_error(LOG_WARNING
,
5763 "graph_event_loop received an unknown event: %d\n",
5772 * graph_event_thread()
5773 * Wait for state changes from the restarters.
5777 graph_event_thread(void *unused
)
5782 h
= libscf_handle_create_bound_loop();
5786 graph_protocol_event_t
*e
;
5788 MUTEX_LOCK(&gu
->gu_lock
);
5790 while (gu
->gu_wakeup
== 0)
5791 (void) pthread_cond_wait(&gu
->gu_cv
, &gu
->gu_lock
);
5795 while ((e
= graph_event_dequeue()) != NULL
) {
5796 MUTEX_LOCK(&e
->gpe_lock
);
5797 MUTEX_UNLOCK(&gu
->gu_lock
);
5799 while ((err
= handle_graph_update_event(h
, e
)) ==
5801 libscf_handle_rebind(h
);
5804 graph_event_release(e
);
5806 graph_event_requeue(e
);
5808 MUTEX_LOCK(&gu
->gu_lock
);
5811 MUTEX_UNLOCK(&gu
->gu_lock
);
5815 * Unreachable for now -- there's currently no graceful cleanup
5818 MUTEX_UNLOCK(&gu
->gu_lock
);
5819 scf_handle_destroy(h
);
5824 set_initial_milestone(scf_handle_t
*h
)
5826 scf_instance_t
*inst
;
5831 inst
= safe_scf_instance_create(h
);
5832 fmri
= startd_alloc(max_scf_fmri_size
);
5835 * If -m milestone= was specified, we want to set options_ovr/milestone
5836 * to it. Otherwise we want to read what the milestone should be set
5837 * to. Either way we need our inst.
5840 if (scf_handle_decode_fmri(h
, SCF_SERVICE_STARTD
, NULL
, NULL
, inst
,
5841 NULL
, NULL
, SCF_DECODE_FMRI_EXACT
) != 0) {
5842 switch (scf_error()) {
5843 case SCF_ERROR_CONNECTION_BROKEN
:
5844 libscf_handle_rebind(h
);
5847 case SCF_ERROR_NOT_FOUND
:
5848 if (st
->st_subgraph
!= NULL
&&
5849 st
->st_subgraph
[0] != '\0') {
5850 sz
= strlcpy(fmri
, st
->st_subgraph
,
5852 assert(sz
< max_scf_fmri_size
);
5858 case SCF_ERROR_INVALID_ARGUMENT
:
5859 case SCF_ERROR_CONSTRAINT_VIOLATED
:
5860 case SCF_ERROR_HANDLE_MISMATCH
:
5862 bad_error("scf_handle_decode_fmri", scf_error());
5865 if (st
->st_subgraph
!= NULL
&& st
->st_subgraph
[0] != '\0') {
5866 scf_propertygroup_t
*pg
;
5868 pg
= safe_scf_pg_create(h
);
5870 sz
= strlcpy(fmri
, st
->st_subgraph
, max_scf_fmri_size
);
5871 assert(sz
< max_scf_fmri_size
);
5873 r
= libscf_inst_get_or_add_pg(inst
, SCF_PG_OPTIONS_OVR
,
5874 SCF_PG_OPTIONS_OVR_TYPE
, SCF_PG_OPTIONS_OVR_FLAGS
,
5881 libscf_handle_rebind(h
);
5887 log_error(LOG_WARNING
, "Could not set %s/%s: "
5888 "%s.\n", SCF_PG_OPTIONS_OVR
,
5889 SCF_PROPERTY_MILESTONE
, strerror(r
));
5893 sz
= strlcpy(fmri
, st
->st_subgraph
,
5895 assert(sz
< max_scf_fmri_size
);
5899 bad_error("libscf_inst_get_or_add_pg", r
);
5902 r
= libscf_clear_runlevel(pg
, fmri
);
5908 libscf_handle_rebind(h
);
5914 log_error(LOG_WARNING
, "Could not set %s/%s: "
5915 "%s.\n", SCF_PG_OPTIONS_OVR
,
5916 SCF_PROPERTY_MILESTONE
, strerror(r
));
5920 sz
= strlcpy(fmri
, st
->st_subgraph
,
5922 assert(sz
< max_scf_fmri_size
);
5926 bad_error("libscf_clear_runlevel", r
);
5931 scf_property_t
*prop
;
5934 prop
= safe_scf_property_create(h
);
5935 val
= safe_scf_value_create(h
);
5937 r
= libscf_get_milestone(inst
, prop
, val
, fmri
,
5944 libscf_handle_rebind(h
);
5948 log_error(LOG_WARNING
, "Milestone property is "
5949 "misconfigured. Defaulting to \"all\".\n");
5958 bad_error("libscf_get_milestone", r
);
5961 scf_value_destroy(val
);
5962 scf_property_destroy(prop
);
5966 if (fmri
[0] == '\0' || strcmp(fmri
, "all") == 0)
5969 if (strcmp(fmri
, "none") != 0) {
5971 if (scf_handle_decode_fmri(h
, fmri
, NULL
, NULL
, inst
, NULL
,
5972 NULL
, SCF_DECODE_FMRI_EXACT
) != 0) {
5973 switch (scf_error()) {
5974 case SCF_ERROR_INVALID_ARGUMENT
:
5975 log_error(LOG_WARNING
,
5976 "Requested milestone \"%s\" is invalid. "
5977 "Reverting to \"all\".\n", fmri
);
5980 case SCF_ERROR_CONSTRAINT_VIOLATED
:
5981 log_error(LOG_WARNING
, "Requested milestone "
5982 "\"%s\" does not specify an instance. "
5983 "Reverting to \"all\".\n", fmri
);
5986 case SCF_ERROR_CONNECTION_BROKEN
:
5987 libscf_handle_rebind(h
);
5990 case SCF_ERROR_NOT_FOUND
:
5991 log_error(LOG_WARNING
, "Requested milestone "
5992 "\"%s\" not in repository. Reverting to "
5993 "\"all\".\n", fmri
);
5996 case SCF_ERROR_HANDLE_MISMATCH
:
5998 bad_error("scf_handle_decode_fmri",
6003 r
= fmri_canonify(fmri
, &cfmri
, B_FALSE
);
6006 r
= dgraph_add_instance(cfmri
, inst
, B_TRUE
);
6007 startd_free(cfmri
, max_scf_fmri_size
);
6016 log_error(LOG_WARNING
,
6017 "Requested milestone \"%s\" is invalid. "
6018 "Reverting to \"all\".\n", fmri
);
6022 log_error(LOG_WARNING
,
6023 "Requested milestone \"%s\" not "
6024 "in repository. Reverting to \"all\".\n",
6030 bad_error("dgraph_add_instance", r
);
6034 log_console(LOG_INFO
, "Booting to milestone \"%s\".\n", fmri
);
6036 r
= dgraph_set_milestone(fmri
, h
, B_FALSE
);
6046 bad_error("dgraph_set_milestone", r
);
6050 startd_free(fmri
, max_scf_fmri_size
);
6051 scf_instance_destroy(inst
);
6055 set_restart_milestone(scf_handle_t
*h
)
6057 scf_instance_t
*inst
;
6058 scf_property_t
*prop
;
6063 inst
= safe_scf_instance_create(h
);
6066 if (scf_handle_decode_fmri(h
, SCF_SERVICE_STARTD
, NULL
, NULL
,
6067 inst
, NULL
, NULL
, SCF_DECODE_FMRI_EXACT
) != 0) {
6068 switch (scf_error()) {
6069 case SCF_ERROR_CONNECTION_BROKEN
:
6070 libscf_handle_rebind(h
);
6073 case SCF_ERROR_NOT_FOUND
:
6076 case SCF_ERROR_INVALID_ARGUMENT
:
6077 case SCF_ERROR_CONSTRAINT_VIOLATED
:
6078 case SCF_ERROR_HANDLE_MISMATCH
:
6080 bad_error("scf_handle_decode_fmri", scf_error());
6083 scf_instance_destroy(inst
);
6087 prop
= safe_scf_property_create(h
);
6088 val
= safe_scf_value_create(h
);
6089 fmri
= startd_alloc(max_scf_fmri_size
);
6091 r
= libscf_get_milestone(inst
, prop
, val
, fmri
, max_scf_fmri_size
);
6097 libscf_handle_rebind(h
);
6106 bad_error("libscf_get_milestone", r
);
6109 r
= dgraph_set_milestone(fmri
, h
, B_TRUE
);
6119 bad_error("dgraph_set_milestone", r
);
6123 startd_free(fmri
, max_scf_fmri_size
);
6124 scf_value_destroy(val
);
6125 scf_property_destroy(prop
);
6126 scf_instance_destroy(inst
);
6130 * void *graph_thread(void *)
6132 * Graph management thread.
6136 graph_thread(void *arg
)
6141 h
= libscf_handle_create_bound_loop();
6144 set_initial_milestone(h
);
6146 MUTEX_LOCK(&dgraph_lock
);
6147 initial_milestone_set
= B_TRUE
;
6148 err
= pthread_cond_broadcast(&initial_milestone_cv
);
6150 MUTEX_UNLOCK(&dgraph_lock
);
6152 libscf_populate_graph(h
);
6154 if (!st
->st_initial
)
6155 set_restart_milestone(h
);
6157 MUTEX_LOCK(&st
->st_load_lock
);
6158 st
->st_load_complete
= 1;
6159 (void) pthread_cond_broadcast(&st
->st_load_cv
);
6160 MUTEX_UNLOCK(&st
->st_load_lock
);
6162 MUTEX_LOCK(&dgraph_lock
);
6164 * Now that we've set st_load_complete we need to check can_come_up()
6165 * since if we booted to a milestone, then there won't be any more
6168 if (!go_single_user_mode
&& !go_to_level1
&&
6170 if (!sulogin_thread_running
&& !can_come_up()) {
6171 (void) startd_thread_create(sulogin_thread
, NULL
);
6172 sulogin_thread_running
= B_TRUE
;
6175 MUTEX_UNLOCK(&dgraph_lock
);
6177 (void) pthread_mutex_lock(&gu
->gu_freeze_lock
);
6181 (void) pthread_cond_wait(&gu
->gu_freeze_cv
,
6182 &gu
->gu_freeze_lock
);
6186 * Unreachable for now -- there's currently no graceful cleanup
6189 (void) pthread_mutex_unlock(&gu
->gu_freeze_lock
);
6190 scf_handle_destroy(h
);
6198 * Given an array of timestamps 'a' with 'num' elements, find the
6199 * lowest non-zero timestamp and return its index. If there are no
6200 * non-zero elements, return -1.
6203 next_action(hrtime_t
*a
, int num
)
6206 int i
= 0, smallest
= -1;
6208 for (i
= 0; i
< num
; i
++) {
6212 } else if (a
[i
] != 0 && a
[i
] < t
) {
6225 * void process_actions()
6226 * Process actions requested by the administrator. Possibilities include:
6227 * refresh, restart, maintenance mode off, maintenance mode on,
6228 * maintenance mode immediate, and degraded.
6230 * The set of pending actions is represented in the repository as a
6231 * per-instance property group, with each action being a single property
6232 * in that group. This property group is converted to an array, with each
6233 * action type having an array slot. The actions in the array at the
6234 * time process_actions() is called are acted on in the order of the
6235 * timestamp (which is the value stored in the slot). A value of zero
6236 * indicates that there is no pending action of the type associated with
6237 * a particular slot.
6239 * Sending an action event multiple times before the restarter has a
6240 * chance to process that action will force it to be run at the last
6241 * timestamp where it appears in the ordering.
6243 * Turning maintenance mode on trumps all other actions.
6245 * Returns 0 or ECONNABORTED.
6248 process_actions(scf_handle_t
*h
, scf_propertygroup_t
*pg
, scf_instance_t
*inst
)
6250 scf_property_t
*prop
= NULL
;
6251 scf_value_t
*val
= NULL
;
6253 graph_vertex_t
*vertex
;
6256 hrtime_t action_ts
[NACTIONS
];
6259 r
= libscf_instance_get_fmri(inst
, &inst_name
);
6265 return (ECONNABORTED
);
6271 bad_error("libscf_instance_get_fmri", r
);
6274 MUTEX_LOCK(&dgraph_lock
);
6276 vertex
= vertex_get_by_name(inst_name
);
6277 if (vertex
== NULL
) {
6278 MUTEX_UNLOCK(&dgraph_lock
);
6279 log_framework(LOG_DEBUG
, "%s: Can't find graph vertex. "
6280 "The instance must have been removed.\n", inst_name
);
6281 startd_free(inst_name
, max_scf_fmri_size
);
6285 prop
= safe_scf_property_create(h
);
6286 val
= safe_scf_value_create(h
);
6288 for (i
= 0; i
< NACTIONS
; i
++) {
6289 if (scf_pg_get_property(pg
, admin_actions
[i
], prop
) != 0) {
6290 switch (scf_error()) {
6291 case SCF_ERROR_CONNECTION_BROKEN
:
6296 case SCF_ERROR_DELETED
:
6299 case SCF_ERROR_NOT_FOUND
:
6303 case SCF_ERROR_HANDLE_MISMATCH
:
6304 case SCF_ERROR_INVALID_ARGUMENT
:
6305 case SCF_ERROR_NOT_SET
:
6306 bad_error("scf_pg_get_property", scf_error());
6310 if (scf_property_type(prop
, &type
) != 0) {
6311 switch (scf_error()) {
6312 case SCF_ERROR_CONNECTION_BROKEN
:
6317 case SCF_ERROR_DELETED
:
6321 case SCF_ERROR_NOT_SET
:
6322 bad_error("scf_property_type", scf_error());
6326 if (type
!= SCF_TYPE_INTEGER
) {
6331 if (scf_property_get_value(prop
, val
) != 0) {
6332 switch (scf_error()) {
6333 case SCF_ERROR_CONNECTION_BROKEN
:
6338 case SCF_ERROR_DELETED
:
6341 case SCF_ERROR_NOT_FOUND
:
6342 case SCF_ERROR_CONSTRAINT_VIOLATED
:
6346 case SCF_ERROR_NOT_SET
:
6347 case SCF_ERROR_PERMISSION_DENIED
:
6348 bad_error("scf_property_get_value",
6353 r
= scf_value_get_integer(val
, &action_ts
[i
]);
6357 a
= ADMIN_EVENT_MAINT_ON_IMMEDIATE
;
6358 if (action_ts
[ADMIN_EVENT_MAINT_ON_IMMEDIATE
] ||
6359 action_ts
[ADMIN_EVENT_MAINT_ON
]) {
6360 a
= action_ts
[ADMIN_EVENT_MAINT_ON_IMMEDIATE
] ?
6361 ADMIN_EVENT_MAINT_ON_IMMEDIATE
: ADMIN_EVENT_MAINT_ON
;
6363 vertex_send_event(vertex
, admin_events
[a
]);
6364 r
= libscf_unset_action(h
, pg
, a
, action_ts
[a
]);
6375 uu_die("Insufficient privilege.\n");
6379 bad_error("libscf_unset_action", r
);
6383 while ((a
= next_action(action_ts
, NACTIONS
)) != -1) {
6384 log_framework(LOG_DEBUG
,
6385 "Graph: processing %s action for %s.\n", admin_actions
[a
],
6388 if (a
== ADMIN_EVENT_REFRESH
) {
6389 r
= dgraph_refresh_instance(vertex
, inst
);
6398 /* pg & inst are reset now, so just return. */
6403 bad_error("dgraph_refresh_instance", r
);
6407 vertex_send_event(vertex
, admin_events
[a
]);
6409 r
= libscf_unset_action(h
, pg
, a
, action_ts
[a
]);
6420 uu_die("Insufficient privilege.\n");
6424 bad_error("libscf_unset_action", r
);
6431 MUTEX_UNLOCK(&dgraph_lock
);
6433 scf_property_destroy(prop
);
6434 scf_value_destroy(val
);
6435 startd_free(inst_name
, max_scf_fmri_size
);
6440 * inst and pg_name are scratch space, and are unset on entry.
6443 * ECONNRESET - success, but repository handle rebound
6444 * ECONNABORTED - repository connection broken
6447 process_pg_event(scf_handle_t
*h
, scf_propertygroup_t
*pg
, scf_instance_t
*inst
,
6451 scf_property_t
*prop
;
6454 boolean_t rebound
= B_FALSE
, rebind_inst
= B_FALSE
;
6456 if (scf_pg_get_name(pg
, pg_name
, max_scf_value_size
) < 0) {
6457 switch (scf_error()) {
6458 case SCF_ERROR_CONNECTION_BROKEN
:
6460 return (ECONNABORTED
);
6462 case SCF_ERROR_DELETED
:
6465 case SCF_ERROR_NOT_SET
:
6466 bad_error("scf_pg_get_name", scf_error());
6470 if (strcmp(pg_name
, SCF_PG_GENERAL
) == 0 ||
6471 strcmp(pg_name
, SCF_PG_GENERAL_OVR
) == 0) {
6472 r
= dgraph_update_general(pg
);
6480 return (ECONNABORTED
);
6483 /* Error should have been logged. */
6487 bad_error("dgraph_update_general", r
);
6489 } else if (strcmp(pg_name
, SCF_PG_RESTARTER_ACTIONS
) == 0) {
6490 if (scf_pg_get_parent_instance(pg
, inst
) != 0) {
6491 switch (scf_error()) {
6492 case SCF_ERROR_CONNECTION_BROKEN
:
6493 return (ECONNABORTED
);
6495 case SCF_ERROR_DELETED
:
6496 case SCF_ERROR_CONSTRAINT_VIOLATED
:
6497 /* Ignore commands on services. */
6500 case SCF_ERROR_NOT_BOUND
:
6501 case SCF_ERROR_HANDLE_MISMATCH
:
6502 case SCF_ERROR_NOT_SET
:
6504 bad_error("scf_pg_get_parent_instance",
6509 return (process_actions(h
, pg
, inst
));
6512 if (strcmp(pg_name
, SCF_PG_OPTIONS
) != 0 &&
6513 strcmp(pg_name
, SCF_PG_OPTIONS_OVR
) != 0)
6517 * We only care about the options[_ovr] property groups of our own
6518 * instance, so get the fmri and compare. Plus, once we know it's
6519 * correct, if the repository connection is broken we know exactly what
6520 * property group we were operating on, and can look it up again.
6522 if (scf_pg_get_parent_instance(pg
, inst
) != 0) {
6523 switch (scf_error()) {
6524 case SCF_ERROR_CONNECTION_BROKEN
:
6525 return (ECONNABORTED
);
6527 case SCF_ERROR_DELETED
:
6528 case SCF_ERROR_CONSTRAINT_VIOLATED
:
6531 case SCF_ERROR_HANDLE_MISMATCH
:
6532 case SCF_ERROR_NOT_BOUND
:
6533 case SCF_ERROR_NOT_SET
:
6535 bad_error("scf_pg_get_parent_instance",
6540 switch (r
= libscf_instance_get_fmri(inst
, &fmri
)) {
6545 return (ECONNABORTED
);
6551 bad_error("libscf_instance_get_fmri", r
);
6554 if (strcmp(fmri
, SCF_SERVICE_STARTD
) != 0) {
6555 startd_free(fmri
, max_scf_fmri_size
);
6560 * update the information events flag
6562 if (strcmp(pg_name
, SCF_PG_OPTIONS
) == 0)
6563 info_events_all
= libscf_get_info_events_all(pg
);
6565 prop
= safe_scf_property_create(h
);
6566 val
= safe_scf_value_create(h
);
6568 if (strcmp(pg_name
, SCF_PG_OPTIONS_OVR
) == 0) {
6569 /* See if we need to set the runlevel. */
6573 libscf_handle_rebind(h
);
6576 r
= libscf_lookup_instance(SCF_SERVICE_STARTD
, inst
);
6589 bad_error("libscf_lookup_instance", r
);
6592 if (scf_instance_get_pg(inst
, pg_name
, pg
) != 0) {
6593 switch (scf_error()) {
6594 case SCF_ERROR_DELETED
:
6595 case SCF_ERROR_NOT_FOUND
:
6598 case SCF_ERROR_CONNECTION_BROKEN
:
6601 case SCF_ERROR_HANDLE_MISMATCH
:
6602 case SCF_ERROR_NOT_BOUND
:
6603 case SCF_ERROR_NOT_SET
:
6604 case SCF_ERROR_INVALID_ARGUMENT
:
6606 bad_error("scf_instance_get_pg",
6612 if (scf_pg_get_property(pg
, "runlevel", prop
) == 0) {
6613 r
= dgraph_set_runlevel(pg
, prop
);
6617 rebind_inst
= B_TRUE
;
6630 bad_error("dgraph_set_runlevel", r
);
6633 switch (scf_error()) {
6634 case SCF_ERROR_CONNECTION_BROKEN
:
6638 case SCF_ERROR_DELETED
:
6641 case SCF_ERROR_NOT_FOUND
:
6644 case SCF_ERROR_INVALID_ARGUMENT
:
6645 case SCF_ERROR_HANDLE_MISMATCH
:
6646 case SCF_ERROR_NOT_BOUND
:
6647 case SCF_ERROR_NOT_SET
:
6648 bad_error("scf_pg_get_property", scf_error());
6655 r
= libscf_lookup_instance(SCF_SERVICE_STARTD
, inst
);
6661 libscf_handle_rebind(h
);
6670 bad_error("libscf_lookup_instance", r
);
6674 r
= libscf_get_milestone(inst
, prop
, val
, fmri
, max_scf_fmri_size
);
6680 libscf_handle_rebind(h
);
6685 log_error(LOG_NOTICE
,
6686 "%s/%s property of %s is misconfigured.\n", pg_name
,
6687 SCF_PROPERTY_MILESTONE
, SCF_SERVICE_STARTD
);
6692 (void) strcpy(fmri
, "all");
6696 bad_error("libscf_get_milestone", r
);
6699 r
= dgraph_set_milestone(fmri
, h
, B_FALSE
);
6707 log_error(LOG_WARNING
, "Milestone %s is invalid.\n", fmri
);
6711 log_error(LOG_WARNING
, "Milestone %s does not exist.\n", fmri
);
6715 bad_error("dgraph_set_milestone", r
);
6719 startd_free(fmri
, max_scf_fmri_size
);
6720 scf_value_destroy(val
);
6721 scf_property_destroy(prop
);
6723 return (rebound
? ECONNRESET
: 0);
6727 * process_delete() deletes an instance from the dgraph if 'fmri' is an
6728 * instance fmri or if 'fmri' matches the 'general' property group of an
6729 * instance (or the 'general/enabled' property).
6731 * 'fmri' may be overwritten and cannot be trusted on return by the caller.
6734 process_delete(char *fmri
, scf_handle_t
*h
)
6736 char *lfmri
, *end_inst_fmri
;
6737 const char *inst_name
= NULL
;
6738 const char *pg_name
= NULL
;
6739 const char *prop_name
= NULL
;
6741 lfmri
= safe_strdup(fmri
);
6743 /* Determine if the FMRI is a property group or instance */
6744 if (scf_parse_svc_fmri(lfmri
, NULL
, NULL
, &inst_name
, &pg_name
,
6745 &prop_name
) != SCF_SUCCESS
) {
6746 log_error(LOG_WARNING
,
6747 "Received invalid FMRI \"%s\" from repository server.\n",
6749 } else if (inst_name
!= NULL
&& pg_name
== NULL
) {
6750 (void) dgraph_remove_instance(fmri
, h
);
6751 } else if (inst_name
!= NULL
&& pg_name
!= NULL
) {
6753 * If we're deleting the 'general' property group or
6754 * 'general/enabled' property then the whole instance
6755 * must be removed from the dgraph.
6757 if (strcmp(pg_name
, SCF_PG_GENERAL
) != 0) {
6762 if (prop_name
!= NULL
&&
6763 strcmp(prop_name
, SCF_PROPERTY_ENABLED
) != 0) {
6769 * Because the instance has already been deleted from the
6770 * repository, we cannot use any scf_ functions to retrieve
6771 * the instance FMRI however we can easily reconstruct it
6774 end_inst_fmri
= strstr(fmri
, SCF_FMRI_PROPERTYGRP_PREFIX
);
6775 if (end_inst_fmri
== NULL
)
6776 bad_error("process_delete", 0);
6778 end_inst_fmri
[0] = '\0';
6780 (void) dgraph_remove_instance(fmri
, h
);
6788 repository_event_thread(void *unused
)
6791 scf_propertygroup_t
*pg
;
6792 scf_instance_t
*inst
;
6793 char *fmri
= startd_alloc(max_scf_fmri_size
);
6794 char *pg_name
= startd_alloc(max_scf_value_size
);
6797 h
= libscf_handle_create_bound_loop();
6799 pg
= safe_scf_pg_create(h
);
6800 inst
= safe_scf_instance_create(h
);
6803 if (_scf_notify_add_pgtype(h
, SCF_GROUP_FRAMEWORK
) != SCF_SUCCESS
) {
6804 if (scf_error() == SCF_ERROR_CONNECTION_BROKEN
) {
6805 libscf_handle_rebind(h
);
6807 log_error(LOG_WARNING
,
6808 "Couldn't set up repository notification "
6809 "for property group type %s: %s\n",
6810 SCF_GROUP_FRAMEWORK
, scf_strerror(scf_error()));
6822 /* Note: fmri is only set on delete events. */
6823 res
= _scf_notify_wait(pg
, fmri
, max_scf_fmri_size
);
6825 libscf_handle_rebind(h
);
6827 } else if (res
== 0) {
6829 * property group modified. inst and pg_name are
6830 * pre-allocated scratch space.
6832 if (scf_pg_update(pg
) < 0) {
6833 switch (scf_error()) {
6834 case SCF_ERROR_DELETED
:
6837 case SCF_ERROR_CONNECTION_BROKEN
:
6838 log_error(LOG_WARNING
,
6839 "Lost repository event due to "
6840 "disconnection.\n");
6841 libscf_handle_rebind(h
);
6844 case SCF_ERROR_NOT_BOUND
:
6845 case SCF_ERROR_NOT_SET
:
6847 bad_error("scf_pg_update", scf_error());
6851 r
= process_pg_event(h
, pg
, inst
, pg_name
);
6857 log_error(LOG_WARNING
, "Lost repository event "
6858 "due to disconnection.\n");
6859 libscf_handle_rebind(h
);
6866 bad_error("process_pg_event", r
);
6870 * Service, instance, or pg deleted.
6871 * Don't trust fmri on return.
6873 process_delete(fmri
, h
);
6882 graph_engine_start()
6886 (void) startd_thread_create(graph_thread
, NULL
);
6888 MUTEX_LOCK(&dgraph_lock
);
6889 while (!initial_milestone_set
) {
6890 err
= pthread_cond_wait(&initial_milestone_cv
, &dgraph_lock
);
6893 MUTEX_UNLOCK(&dgraph_lock
);
6895 (void) startd_thread_create(repository_event_thread
, NULL
);
6896 (void) startd_thread_create(graph_event_thread
, NULL
);