1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2015, Syneto S.R.L. All rights reserved.
25 * Copyright 2016 Toomas Soome <tsoome@me.com>
26 * Copyright 2016 RackTop Systems.
27 */
28
29 /*
30 * graph.c - master restarter graph engine
31 *
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.
37 *
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.
48 *
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
54 * includes
55 *
56 * - an edge from the GVT_SVC vertex for the instance's service
57 *
58 * - an edge to the GVT_INST vertex of the instance's resarter, if its
59 * restarter is not svc.startd
60 *
61 * - edges from other GVT_INST vertices if the instance is a restarter
62 *
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
66 *
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
70 *
71 * - edges from GVT_GROUP vertices for each dependent instance
72 *
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.
76 *
77 * The graph and all of its vertices are protected by the dgraph_lock mutex.
78 * See restarter.c for more information.
79 *
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
93 * comes online.
94 *
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.
109 *
110 *
111 * SMF state transition notifications
112 *
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
122 * restarter:default
123 *
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
127 * refreshed.
128 *
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.
134 *
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().
138 *
139 */
140
141 #include <sys/uadmin.h>
142 #include <sys/wait.h>
143
144 #include <assert.h>
145 #include <errno.h>
146 #include <fcntl.h>
147 #include <fm/libfmevent.h>
148 #include <libscf.h>
149 #include <libscf_priv.h>
150 #include <librestart.h>
151 #include <libuutil.h>
152 #include <locale.h>
153 #include <poll.h>
154 #include <pthread.h>
155 #include <signal.h>
156 #include <stddef.h>
157 #include <stdio.h>
158 #include <stdlib.h>
159 #include <string.h>
160 #include <strings.h>
161 #include <sys/statvfs.h>
162 #include <sys/uadmin.h>
163 #include <zone.h>
164 #if defined(__x86)
165 #include <libbe.h>
166 #endif /* __x86 */
167
168 #include "startd.h"
169 #include "protocol.h"
170
171
172 #define MILESTONE_NONE ((graph_vertex_t *)1)
173
174 #define CONSOLE_LOGIN_FMRI "svc:/system/console-login:default"
175 #define FS_MINIMAL_FMRI "svc:/system/filesystem/minimal:default"
176
177 #define VERTEX_REMOVED 0 /* vertex has been freed */
178 #define VERTEX_INUSE 1 /* vertex is still in use */
179
180 #define IS_ENABLED(v) ((v)->gv_flags & (GV_ENABLED | GV_ENBLD_NOOVR))
181
182 /*
183 * stn_global holds the tset for the system wide notification parameters.
184 * It is updated on refresh of svc:/system/svc/global:default
185 *
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.
190 *
191 * If either assumption is broken, we'll need a mutex to synchronize
192 * access to stn_global
193 */
194 int32_t stn_global;
195 /*
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.
199 */
200 int info_events_all;
201
202 /*
203 * Services in these states are not considered 'down' by the
204 * milestone/shutdown code.
205 */
206 #define up_state(state) ((state) == RESTARTER_STATE_ONLINE || \
207 (state) == RESTARTER_STATE_DEGRADED || \
208 (state) == RESTARTER_STATE_OFFLINE)
209
210 #define is_depgrp_bypassed(v) ((v->gv_type == GVT_GROUP) && \
211 ((v->gv_depgroup == DEPGRP_EXCLUDE_ALL) || \
212 (v->gv_restart < RERR_RESTART)))
213
214 static uu_list_pool_t *graph_edge_pool, *graph_vertex_pool;
215 static uu_list_t *dgraph;
216 static pthread_mutex_t dgraph_lock;
217
218 /*
219 * milestone indicates the current subgraph. When NULL, it is the entire
220 * graph. When MILESTONE_NONE, it is the empty graph. Otherwise, it is all
221 * services on which the target vertex depends.
222 */
223 static graph_vertex_t *milestone = NULL;
224 static boolean_t initial_milestone_set = B_FALSE;
225 static pthread_cond_t initial_milestone_cv = PTHREAD_COND_INITIALIZER;
226
227 /* protected by dgraph_lock */
228 static boolean_t sulogin_thread_running = B_FALSE;
229 static boolean_t sulogin_running = B_FALSE;
230 static boolean_t console_login_ready = B_FALSE;
231
232 /* Number of services to come down to complete milestone transition. */
233 static uint_t non_subgraph_svcs;
234
235 /*
236 * These variables indicate what should be done when we reach the milestone
237 * target milestone, i.e., when non_subgraph_svcs == 0. They are acted upon in
238 * dgraph_set_instance_state().
239 */
240 static int halting = -1;
241 static boolean_t go_single_user_mode = B_FALSE;
242 static boolean_t go_to_level1 = B_FALSE;
243
244 /*
245 * Tracks when we started halting.
246 */
247 static time_t halting_time = 0;
248
249 /*
250 * This tracks the legacy runlevel to ensure we signal init and manage
251 * utmpx entries correctly.
252 */
253 static char current_runlevel = '\0';
254
255 /* Number of single user threads currently running */
256 static pthread_mutex_t single_user_thread_lock;
257 static int single_user_thread_count = 0;
258
259 /* Statistics for dependency cycle-checking */
260 static u_longlong_t dep_inserts = 0;
261 static u_longlong_t dep_cycle_ns = 0;
262 static u_longlong_t dep_insert_ns = 0;
263
264
265 static const char * const emsg_invalid_restarter =
266 "Transitioning %s to maintenance, restarter FMRI %s is invalid "
267 "(see 'svcs -xv' for details).\n";
268 static const char * const console_login_fmri = CONSOLE_LOGIN_FMRI;
269 static const char * const single_user_fmri = SCF_MILESTONE_SINGLE_USER;
270 static const char * const multi_user_fmri = SCF_MILESTONE_MULTI_USER;
271 static const char * const multi_user_svr_fmri = SCF_MILESTONE_MULTI_USER_SERVER;
272
273
274 /*
275 * These services define the system being "up". If none of them can come
276 * online, then we will run sulogin on the console. Note that the install ones
277 * are for the miniroot and when installing CDs after the first. can_come_up()
278 * does the decision making, and an sulogin_thread() runs sulogin, which can be
279 * started by dgraph_set_instance_state() or single_user_thread().
280 *
281 * NOTE: can_come_up() relies on SCF_MILESTONE_SINGLE_USER being the first
282 * entry, which is only used when booting_to_single_user (boot -s) is set.
283 * This is because when doing a "boot -s", sulogin is started from specials.c
284 * after milestone/single-user comes online, for backwards compatibility.
285 * In this case, SCF_MILESTONE_SINGLE_USER needs to be part of up_svcs
286 * to ensure sulogin will be spawned if milestone/single-user cannot be reached.
287 */
288 static const char * const up_svcs[] = {
289 SCF_MILESTONE_SINGLE_USER,
290 CONSOLE_LOGIN_FMRI,
291 "svc:/system/install-setup:default",
292 "svc:/system/install:default",
293 NULL
294 };
295
296 /* This array must have an element for each non-NULL element of up_svcs[]. */
297 static graph_vertex_t *up_svcs_p[] = { NULL, NULL, NULL, NULL };
298
299 /* These are for seed repository magic. See can_come_up(). */
300 static const char * const manifest_import = SCF_INSTANCE_MI;
301 static graph_vertex_t *manifest_import_p = NULL;
302
303
304 static char target_milestone_as_runlevel(void);
305 static void graph_runlevel_changed(char rl, int online);
306 static int dgraph_set_milestone(const char *, scf_handle_t *, boolean_t);
307 static boolean_t should_be_in_subgraph(graph_vertex_t *v);
308 static int mark_subtree(graph_edge_t *, void *);
309 static boolean_t insubtree_dependents_down(graph_vertex_t *);
310
311 /*
312 * graph_vertex_compare()
313 * This function can compare either int *id or * graph_vertex_t *gv
314 * values, as the vertex id is always the first element of a
315 * graph_vertex structure.
316 */
317 /* ARGSUSED */
318 static int
319 graph_vertex_compare(const void *lc_arg, const void *rc_arg, void *private)
320 {
321 int lc_id = ((const graph_vertex_t *)lc_arg)->gv_id;
322 int rc_id = *(int *)rc_arg;
323
324 if (lc_id > rc_id)
325 return (1);
326 if (lc_id < rc_id)
327 return (-1);
328 return (0);
329 }
330
331 void
332 graph_init()
333 {
334 graph_edge_pool = startd_list_pool_create("graph_edges",
335 sizeof (graph_edge_t), offsetof(graph_edge_t, ge_link), NULL,
336 UU_LIST_POOL_DEBUG);
337 assert(graph_edge_pool != NULL);
338
339 graph_vertex_pool = startd_list_pool_create("graph_vertices",
340 sizeof (graph_vertex_t), offsetof(graph_vertex_t, gv_link),
341 graph_vertex_compare, UU_LIST_POOL_DEBUG);
342 assert(graph_vertex_pool != NULL);
343
344 (void) pthread_mutex_init(&dgraph_lock, &mutex_attrs);
345 (void) pthread_mutex_init(&single_user_thread_lock, &mutex_attrs);
346 dgraph = startd_list_create(graph_vertex_pool, NULL, UU_LIST_SORTED);
347 assert(dgraph != NULL);
348
349 if (!st->st_initial)
350 current_runlevel = utmpx_get_runlevel();
351
352 log_framework(LOG_DEBUG, "Initialized graph\n");
353 }
354
355 static graph_vertex_t *
356 vertex_get_by_name(const char *name)
357 {
358 int id;
359
360 assert(MUTEX_HELD(&dgraph_lock));
361
362 id = dict_lookup_byname(name);
363 if (id == -1)
364 return (NULL);
365
366 return (uu_list_find(dgraph, &id, NULL, NULL));
367 }
368
369 static graph_vertex_t *
370 vertex_get_by_id(int id)
371 {
372 assert(MUTEX_HELD(&dgraph_lock));
373
374 if (id == -1)
375 return (NULL);
376
377 return (uu_list_find(dgraph, &id, NULL, NULL));
378 }
379
380 /*
381 * Creates a new vertex with the given name, adds it to the graph, and returns
382 * a pointer to it. The graph lock must be held by this thread on entry.
383 */
384 static graph_vertex_t *
385 graph_add_vertex(const char *name)
386 {
387 int id;
388 graph_vertex_t *v;
389 void *p;
390 uu_list_index_t idx;
391
392 assert(MUTEX_HELD(&dgraph_lock));
393
394 id = dict_insert(name);
395
396 v = startd_zalloc(sizeof (*v));
397
398 v->gv_id = id;
399
400 v->gv_name = startd_alloc(strlen(name) + 1);
401 (void) strcpy(v->gv_name, name);
402
403 v->gv_dependencies = startd_list_create(graph_edge_pool, v, 0);
404 v->gv_dependents = startd_list_create(graph_edge_pool, v, 0);
405
406 p = uu_list_find(dgraph, &id, NULL, &idx);
407 assert(p == NULL);
408
409 uu_list_node_init(v, &v->gv_link, graph_vertex_pool);
410 uu_list_insert(dgraph, v, idx);
411
412 return (v);
413 }
414
415 /*
416 * Removes v from the graph and frees it. The graph should be locked by this
417 * thread, and v should have no edges associated with it.
418 */
419 static void
420 graph_remove_vertex(graph_vertex_t *v)
421 {
422 assert(MUTEX_HELD(&dgraph_lock));
423
424 assert(uu_list_numnodes(v->gv_dependencies) == 0);
425 assert(uu_list_numnodes(v->gv_dependents) == 0);
426 assert(v->gv_refs == 0);
427
428 startd_free(v->gv_name, strlen(v->gv_name) + 1);
429 uu_list_destroy(v->gv_dependencies);
430 uu_list_destroy(v->gv_dependents);
431 uu_list_remove(dgraph, v);
432
433 startd_free(v, sizeof (graph_vertex_t));
434 }
435
436 static void
437 graph_add_edge(graph_vertex_t *fv, graph_vertex_t *tv)
438 {
439 graph_edge_t *e, *re;
440 int r;
441
442 assert(MUTEX_HELD(&dgraph_lock));
443
444 e = startd_alloc(sizeof (graph_edge_t));
445 re = startd_alloc(sizeof (graph_edge_t));
446
447 e->ge_parent = fv;
448 e->ge_vertex = tv;
449
450 re->ge_parent = tv;
451 re->ge_vertex = fv;
452
453 uu_list_node_init(e, &e->ge_link, graph_edge_pool);
454 r = uu_list_insert_before(fv->gv_dependencies, NULL, e);
455 assert(r == 0);
456
457 uu_list_node_init(re, &re->ge_link, graph_edge_pool);
458 r = uu_list_insert_before(tv->gv_dependents, NULL, re);
459 assert(r == 0);
460 }
461
462 static void
463 graph_remove_edge(graph_vertex_t *v, graph_vertex_t *dv)
464 {
465 graph_edge_t *e;
466
467 for (e = uu_list_first(v->gv_dependencies);
468 e != NULL;
469 e = uu_list_next(v->gv_dependencies, e)) {
470 if (e->ge_vertex == dv) {
471 uu_list_remove(v->gv_dependencies, e);
472 startd_free(e, sizeof (graph_edge_t));
473 break;
474 }
475 }
476
477 for (e = uu_list_first(dv->gv_dependents);
478 e != NULL;
479 e = uu_list_next(dv->gv_dependents, e)) {
480 if (e->ge_vertex == v) {
481 uu_list_remove(dv->gv_dependents, e);
482 startd_free(e, sizeof (graph_edge_t));
483 break;
484 }
485 }
486 }
487
488 static void
489 remove_inst_vertex(graph_vertex_t *v)
490 {
491 graph_edge_t *e;
492 graph_vertex_t *sv;
493 int i;
494
495 assert(MUTEX_HELD(&dgraph_lock));
496 assert(uu_list_numnodes(v->gv_dependents) == 1);
497 assert(uu_list_numnodes(v->gv_dependencies) == 0);
498 assert(v->gv_refs == 0);
499 assert((v->gv_flags & GV_CONFIGURED) == 0);
500
501 e = uu_list_first(v->gv_dependents);
502 sv = e->ge_vertex;
503 graph_remove_edge(sv, v);
504
505 for (i = 0; up_svcs[i] != NULL; ++i) {
506 if (up_svcs_p[i] == v)
507 up_svcs_p[i] = NULL;
508 }
509
510 if (manifest_import_p == v)
511 manifest_import_p = NULL;
512
513 graph_remove_vertex(v);
514
515 if (uu_list_numnodes(sv->gv_dependencies) == 0 &&
516 uu_list_numnodes(sv->gv_dependents) == 0 &&
517 sv->gv_refs == 0)
518 graph_remove_vertex(sv);
519 }
520
521 static void
522 graph_walk_dependents(graph_vertex_t *v, void (*func)(graph_vertex_t *, void *),
523 void *arg)
524 {
525 graph_edge_t *e;
526
527 for (e = uu_list_first(v->gv_dependents);
528 e != NULL;
529 e = uu_list_next(v->gv_dependents, e))
530 func(e->ge_vertex, arg);
531 }
532
533 static void
534 graph_walk_dependencies(graph_vertex_t *v,
535 void (*func)(graph_vertex_t *, void *), void *arg)
536 {
537 graph_edge_t *e;
538
539 assert(MUTEX_HELD(&dgraph_lock));
540
541 for (e = uu_list_first(v->gv_dependencies);
542 e != NULL;
543 e = uu_list_next(v->gv_dependencies, e)) {
544
545 func(e->ge_vertex, arg);
546 }
547 }
548
549 /*
550 * Generic graph walking function.
551 *
552 * Given a vertex, this function will walk either dependencies
553 * (WALK_DEPENDENCIES) or dependents (WALK_DEPENDENTS) of a vertex recursively
554 * for the entire graph. It will avoid cycles and never visit the same vertex
555 * twice.
556 *
557 * We avoid traversing exclusion dependencies, because they are allowed to
558 * create cycles in the graph. When propagating satisfiability, there is no
559 * need to walk exclusion dependencies because exclude_all_satisfied() doesn't
560 * test for satisfiability.
561 *
562 * The walker takes two callbacks. The first is called before examining the
563 * dependents of each vertex. The second is called on each vertex after
564 * examining its dependents. This allows is_path_to() to construct a path only
565 * after the target vertex has been found.
566 */
567 typedef enum {
568 WALK_DEPENDENTS,
569 WALK_DEPENDENCIES
570 } graph_walk_dir_t;
571
572 typedef int (*graph_walk_cb_t)(graph_vertex_t *, void *);
573
574 typedef struct graph_walk_info {
575 graph_walk_dir_t gi_dir;
576 uchar_t *gi_visited; /* vertex bitmap */
577 int (*gi_pre)(graph_vertex_t *, void *);
578 void (*gi_post)(graph_vertex_t *, void *);
579 void *gi_arg; /* callback arg */
580 int gi_ret; /* return value */
581 } graph_walk_info_t;
582
583 static int
584 graph_walk_recurse(graph_edge_t *e, graph_walk_info_t *gip)
585 {
586 uu_list_t *list;
587 int r;
588 graph_vertex_t *v = e->ge_vertex;
589 int i;
590 uint_t b;
591
592 i = v->gv_id / 8;
593 b = 1 << (v->gv_id % 8);
594
595 /*
596 * Check to see if we've visited this vertex already.
597 */
598 if (gip->gi_visited[i] & b)
599 return (UU_WALK_NEXT);
600
601 gip->gi_visited[i] |= b;
602
603 /*
604 * Don't follow exclusions.
605 */
606 if (v->gv_type == GVT_GROUP && v->gv_depgroup == DEPGRP_EXCLUDE_ALL)
607 return (UU_WALK_NEXT);
608
609 /*
610 * Call pre-visit callback. If this doesn't terminate the walk,
611 * continue search.
612 */
613 if ((gip->gi_ret = gip->gi_pre(v, gip->gi_arg)) == UU_WALK_NEXT) {
614 /*
615 * Recurse using appropriate list.
616 */
617 if (gip->gi_dir == WALK_DEPENDENTS)
618 list = v->gv_dependents;
619 else
620 list = v->gv_dependencies;
621
622 r = uu_list_walk(list, (uu_walk_fn_t *)graph_walk_recurse,
623 gip, 0);
624 assert(r == 0);
625 }
626
627 /*
628 * Callbacks must return either UU_WALK_NEXT or UU_WALK_DONE.
629 */
630 assert(gip->gi_ret == UU_WALK_NEXT || gip->gi_ret == UU_WALK_DONE);
631
632 /*
633 * If given a post-callback, call the function for every vertex.
634 */
635 if (gip->gi_post != NULL)
636 (void) gip->gi_post(v, gip->gi_arg);
637
638 /*
639 * Preserve the callback's return value. If the callback returns
640 * UU_WALK_DONE, then we propagate that to the caller in order to
641 * terminate the walk.
642 */
643 return (gip->gi_ret);
644 }
645
646 static void
647 graph_walk(graph_vertex_t *v, graph_walk_dir_t dir,
648 int (*pre)(graph_vertex_t *, void *),
649 void (*post)(graph_vertex_t *, void *), void *arg)
650 {
651 graph_walk_info_t gi;
652 graph_edge_t fake;
653 size_t sz = dictionary->dict_new_id / 8 + 1;
654
655 gi.gi_visited = startd_zalloc(sz);
656 gi.gi_pre = pre;
657 gi.gi_post = post;
658 gi.gi_arg = arg;
659 gi.gi_dir = dir;
660 gi.gi_ret = 0;
661
662 /*
663 * Fake up an edge for the first iteration
664 */
665 fake.ge_vertex = v;
666 (void) graph_walk_recurse(&fake, &gi);
667
668 startd_free(gi.gi_visited, sz);
669 }
670
671 typedef struct child_search {
672 int id; /* id of vertex to look for */
673 uint_t depth; /* recursion depth */
674 /*
675 * While the vertex is not found, path is NULL. After the search, if
676 * the vertex was found then path should point to a -1-terminated
677 * array of vertex id's which constitute the path to the vertex.
678 */
679 int *path;
680 } child_search_t;
681
682 static int
683 child_pre(graph_vertex_t *v, void *arg)
684 {
685 child_search_t *cs = arg;
686
687 cs->depth++;
688
689 if (v->gv_id == cs->id) {
690 cs->path = startd_alloc((cs->depth + 1) * sizeof (int));
691 cs->path[cs->depth] = -1;
692 return (UU_WALK_DONE);
693 }
694
695 return (UU_WALK_NEXT);
696 }
697
698 static void
699 child_post(graph_vertex_t *v, void *arg)
700 {
701 child_search_t *cs = arg;
702
703 cs->depth--;
704
705 if (cs->path != NULL)
706 cs->path[cs->depth] = v->gv_id;
707 }
708
709 /*
710 * Look for a path from from to to. If one exists, returns a pointer to
711 * a NULL-terminated array of pointers to the vertices along the path. If
712 * there is no path, returns NULL.
713 */
714 static int *
715 is_path_to(graph_vertex_t *from, graph_vertex_t *to)
716 {
717 child_search_t cs;
718
719 cs.id = to->gv_id;
720 cs.depth = 0;
721 cs.path = NULL;
722
723 graph_walk(from, WALK_DEPENDENCIES, child_pre, child_post, &cs);
724
725 return (cs.path);
726 }
727
728 /*
729 * Given an array of int's as returned by is_path_to, allocates a string of
730 * their names joined by newlines. Returns the size of the allocated buffer
731 * in *sz and frees path.
732 */
733 static void
734 path_to_str(int *path, char **cpp, size_t *sz)
735 {
736 int i;
737 graph_vertex_t *v;
738 size_t allocd, new_allocd;
739 char *new, *name;
740
741 assert(MUTEX_HELD(&dgraph_lock));
742 assert(path[0] != -1);
743
744 allocd = 1;
745 *cpp = startd_alloc(1);
746 (*cpp)[0] = '\0';
747
748 for (i = 0; path[i] != -1; ++i) {
749 name = NULL;
750
751 v = vertex_get_by_id(path[i]);
752
753 if (v == NULL)
754 name = "<deleted>";
755 else if (v->gv_type == GVT_INST || v->gv_type == GVT_SVC)
756 name = v->gv_name;
757
758 if (name != NULL) {
759 new_allocd = allocd + strlen(name) + 1;
760 new = startd_alloc(new_allocd);
761 (void) strcpy(new, *cpp);
762 (void) strcat(new, name);
763 (void) strcat(new, "\n");
764
765 startd_free(*cpp, allocd);
766
767 *cpp = new;
768 allocd = new_allocd;
769 }
770 }
771
772 startd_free(path, sizeof (int) * (i + 1));
773
774 *sz = allocd;
775 }
776
777
778 /*
779 * This function along with run_sulogin() implements an exclusion relationship
780 * between system/console-login and sulogin. run_sulogin() will fail if
781 * system/console-login is online, and the graph engine should call
782 * graph_clogin_start() to bring system/console-login online, which defers the
783 * start if sulogin is running.
784 */
785 static void
786 graph_clogin_start(graph_vertex_t *v)
787 {
788 assert(MUTEX_HELD(&dgraph_lock));
789
790 if (sulogin_running)
791 console_login_ready = B_TRUE;
792 else
793 vertex_send_event(v, RESTARTER_EVENT_TYPE_START);
794 }
795
796 static void
797 graph_su_start(graph_vertex_t *v)
798 {
799 /*
800 * /etc/inittab used to have the initial /sbin/rcS as a 'sysinit'
801 * entry with a runlevel of 'S', before jumping to the final
802 * target runlevel (as set in initdefault). We mimic that legacy
803 * behavior here.
804 */
805 utmpx_set_runlevel('S', '0', B_FALSE);
806 vertex_send_event(v, RESTARTER_EVENT_TYPE_START);
807 }
808
809 static void
810 graph_post_su_online(void)
811 {
812 graph_runlevel_changed('S', 1);
813 }
814
815 static void
816 graph_post_su_disable(void)
817 {
818 graph_runlevel_changed('S', 0);
819 }
820
821 static void
822 graph_post_mu_online(void)
823 {
824 graph_runlevel_changed('2', 1);
825 }
826
827 static void
828 graph_post_mu_disable(void)
829 {
830 graph_runlevel_changed('2', 0);
831 }
832
833 static void
834 graph_post_mus_online(void)
835 {
836 graph_runlevel_changed('3', 1);
837 }
838
839 static void
840 graph_post_mus_disable(void)
841 {
842 graph_runlevel_changed('3', 0);
843 }
844
845 static struct special_vertex_info {
846 const char *name;
847 void (*start_f)(graph_vertex_t *);
848 void (*post_online_f)(void);
849 void (*post_disable_f)(void);
850 } special_vertices[] = {
851 { CONSOLE_LOGIN_FMRI, graph_clogin_start, NULL, NULL },
852 { SCF_MILESTONE_SINGLE_USER, graph_su_start,
853 graph_post_su_online, graph_post_su_disable },
854 { SCF_MILESTONE_MULTI_USER, NULL,
855 graph_post_mu_online, graph_post_mu_disable },
856 { SCF_MILESTONE_MULTI_USER_SERVER, NULL,
857 graph_post_mus_online, graph_post_mus_disable },
858 { NULL },
859 };
860
861
862 void
863 vertex_send_event(graph_vertex_t *v, restarter_event_type_t e)
864 {
865 switch (e) {
866 case RESTARTER_EVENT_TYPE_ADD_INSTANCE:
867 assert(v->gv_state == RESTARTER_STATE_UNINIT);
868
869 MUTEX_LOCK(&st->st_load_lock);
870 st->st_load_instances++;
871 MUTEX_UNLOCK(&st->st_load_lock);
872 break;
873
874 case RESTARTER_EVENT_TYPE_ENABLE:
875 log_framework(LOG_DEBUG, "Enabling %s.\n", v->gv_name);
876 assert(v->gv_state == RESTARTER_STATE_UNINIT ||
877 v->gv_state == RESTARTER_STATE_DISABLED ||
878 v->gv_state == RESTARTER_STATE_MAINT);
879 break;
880
881 case RESTARTER_EVENT_TYPE_DISABLE:
882 case RESTARTER_EVENT_TYPE_ADMIN_DISABLE:
883 log_framework(LOG_DEBUG, "Disabling %s.\n", v->gv_name);
884 assert(v->gv_state != RESTARTER_STATE_DISABLED);
885 break;
886
887 case RESTARTER_EVENT_TYPE_STOP_RESET:
888 case RESTARTER_EVENT_TYPE_STOP:
889 log_framework(LOG_DEBUG, "Stopping %s.\n", v->gv_name);
890 assert(v->gv_state == RESTARTER_STATE_DEGRADED ||
891 v->gv_state == RESTARTER_STATE_ONLINE);
892 break;
893
894 case RESTARTER_EVENT_TYPE_START:
895 log_framework(LOG_DEBUG, "Starting %s.\n", v->gv_name);
896 assert(v->gv_state == RESTARTER_STATE_OFFLINE);
897 break;
898
899 case RESTARTER_EVENT_TYPE_REMOVE_INSTANCE:
900 case RESTARTER_EVENT_TYPE_ADMIN_DEGRADED:
901 case RESTARTER_EVENT_TYPE_ADMIN_REFRESH:
902 case RESTARTER_EVENT_TYPE_ADMIN_RESTART:
903 case RESTARTER_EVENT_TYPE_ADMIN_MAINT_OFF:
904 case RESTARTER_EVENT_TYPE_ADMIN_MAINT_ON:
905 case RESTARTER_EVENT_TYPE_ADMIN_MAINT_ON_IMMEDIATE:
906 case RESTARTER_EVENT_TYPE_DEPENDENCY_CYCLE:
907 case RESTARTER_EVENT_TYPE_INVALID_DEPENDENCY:
908 break;
909
910 default:
911 #ifndef NDEBUG
912 uu_warn("%s:%d: Bad event %d.\n", __FILE__, __LINE__, e);
913 #endif
914 abort();
915 }
916
917 restarter_protocol_send_event(v->gv_name, v->gv_restarter_channel, e,
918 v->gv_reason);
919 }
920
921 static void
922 graph_unset_restarter(graph_vertex_t *v)
923 {
924 assert(MUTEX_HELD(&dgraph_lock));
925 assert(v->gv_flags & GV_CONFIGURED);
926
927 vertex_send_event(v, RESTARTER_EVENT_TYPE_REMOVE_INSTANCE);
928
929 if (v->gv_restarter_id != -1) {
930 graph_vertex_t *rv;
931
932 rv = vertex_get_by_id(v->gv_restarter_id);
933 graph_remove_edge(v, rv);
934 }
935
936 v->gv_restarter_id = -1;
937 v->gv_restarter_channel = NULL;
938 }
939
940 /*
941 * Return VERTEX_REMOVED when the vertex passed in argument is deleted from the
942 * dgraph otherwise return VERTEX_INUSE.
943 */
944 static int
945 free_if_unrefed(graph_vertex_t *v)
946 {
947 assert(MUTEX_HELD(&dgraph_lock));
948
949 if (v->gv_refs > 0)
950 return (VERTEX_INUSE);
951
952 if (v->gv_type == GVT_SVC &&
953 uu_list_numnodes(v->gv_dependents) == 0 &&
954 uu_list_numnodes(v->gv_dependencies) == 0) {
955 graph_remove_vertex(v);
956 return (VERTEX_REMOVED);
957 } else if (v->gv_type == GVT_INST &&
958 (v->gv_flags & GV_CONFIGURED) == 0 &&
959 uu_list_numnodes(v->gv_dependents) == 1 &&
960 uu_list_numnodes(v->gv_dependencies) == 0) {
961 remove_inst_vertex(v);
962 return (VERTEX_REMOVED);
963 }
964
965 return (VERTEX_INUSE);
966 }
967
968 static void
969 delete_depgroup(graph_vertex_t *v)
970 {
971 graph_edge_t *e;
972 graph_vertex_t *dv;
973
974 assert(MUTEX_HELD(&dgraph_lock));
975 assert(v->gv_type == GVT_GROUP);
976 assert(uu_list_numnodes(v->gv_dependents) == 0);
977
978 while ((e = uu_list_first(v->gv_dependencies)) != NULL) {
979 dv = e->ge_vertex;
980
981 graph_remove_edge(v, dv);
982
983 switch (dv->gv_type) {
984 case GVT_INST: /* instance dependency */
985 case GVT_SVC: /* service dependency */
986 (void) free_if_unrefed(dv);
987 break;
988
989 case GVT_FILE: /* file dependency */
990 assert(uu_list_numnodes(dv->gv_dependencies) == 0);
991 if (uu_list_numnodes(dv->gv_dependents) == 0)
992 graph_remove_vertex(dv);
993 break;
994
995 default:
996 #ifndef NDEBUG
997 uu_warn("%s:%d: Unexpected node type %d", __FILE__,
998 __LINE__, dv->gv_type);
999 #endif
1000 abort();
1001 }
1002 }
1003
1004 graph_remove_vertex(v);
1005 }
1006
1007 static int
1008 delete_instance_deps_cb(graph_edge_t *e, void **ptrs)
1009 {
1010 graph_vertex_t *v = ptrs[0];
1011 boolean_t delete_restarter_dep = (boolean_t)ptrs[1];
1012 graph_vertex_t *dv;
1013
1014 dv = e->ge_vertex;
1015
1016 /*
1017 * We have four possibilities here:
1018 * - GVT_INST: restarter
1019 * - GVT_GROUP - GVT_INST: instance dependency
1020 * - GVT_GROUP - GVT_SVC - GV_INST: service dependency
1021 * - GVT_GROUP - GVT_FILE: file dependency
1022 */
1023 switch (dv->gv_type) {
1024 case GVT_INST: /* restarter */
1025 assert(dv->gv_id == v->gv_restarter_id);
1026 if (delete_restarter_dep)
1027 graph_remove_edge(v, dv);
1028 break;
1029
1030 case GVT_GROUP: /* pg dependency */
1031 graph_remove_edge(v, dv);
1032 delete_depgroup(dv);
1033 break;
1034
1035 case GVT_FILE:
1036 /* These are currently not direct dependencies */
1037
1038 default:
1039 #ifndef NDEBUG
1040 uu_warn("%s:%d: Bad vertex type %d.\n", __FILE__, __LINE__,
1041 dv->gv_type);
1042 #endif
1043 abort();
1044 }
1045
1046 return (UU_WALK_NEXT);
1047 }
1048
1049 static void
1050 delete_instance_dependencies(graph_vertex_t *v, boolean_t delete_restarter_dep)
1051 {
1052 void *ptrs[2];
1053 int r;
1054
1055 assert(MUTEX_HELD(&dgraph_lock));
1056 assert(v->gv_type == GVT_INST);
1057
1058 ptrs[0] = v;
1059 ptrs[1] = (void *)delete_restarter_dep;
1060
1061 r = uu_list_walk(v->gv_dependencies,
1062 (uu_walk_fn_t *)delete_instance_deps_cb, &ptrs, UU_WALK_ROBUST);
1063 assert(r == 0);
1064 }
1065
1066 /*
1067 * int graph_insert_vertex_unconfigured()
1068 * Insert a vertex without sending any restarter events. If the vertex
1069 * already exists or creation is successful, return a pointer to it in *vp.
1070 *
1071 * If type is not GVT_GROUP, dt can remain unset.
1072 *
1073 * Returns 0, EEXIST, or EINVAL if the arguments are invalid (i.e., fmri
1074 * doesn't agree with type, or type doesn't agree with dt).
1075 */
1076 static int
1077 graph_insert_vertex_unconfigured(const char *fmri, gv_type_t type,
1078 depgroup_type_t dt, restarter_error_t rt, graph_vertex_t **vp)
1079 {
1080 int r;
1081 int i;
1082
1083 assert(MUTEX_HELD(&dgraph_lock));
1084
1085 switch (type) {
1086 case GVT_SVC:
1087 case GVT_INST:
1088 if (strncmp(fmri, "svc:", sizeof ("svc:") - 1) != 0)
1089 return (EINVAL);
1090 break;
1091
1092 case GVT_FILE:
1093 if (strncmp(fmri, "file:", sizeof ("file:") - 1) != 0)
1094 return (EINVAL);
1095 break;
1096
1097 case GVT_GROUP:
1098 if (dt <= 0 || rt < 0)
1099 return (EINVAL);
1100 break;
1101
1102 default:
1103 #ifndef NDEBUG
1104 uu_warn("%s:%d: Unknown type %d.\n", __FILE__, __LINE__, type);
1105 #endif
1106 abort();
1107 }
1108
1109 *vp = vertex_get_by_name(fmri);
1110 if (*vp != NULL)
1111 return (EEXIST);
1112
1113 *vp = graph_add_vertex(fmri);
1114
1115 (*vp)->gv_type = type;
1116 (*vp)->gv_depgroup = dt;
1117 (*vp)->gv_restart = rt;
1118
1119 (*vp)->gv_flags = 0;
1120 (*vp)->gv_state = RESTARTER_STATE_NONE;
1121
1122 for (i = 0; special_vertices[i].name != NULL; ++i) {
1123 if (strcmp(fmri, special_vertices[i].name) == 0) {
1124 (*vp)->gv_start_f = special_vertices[i].start_f;
1125 (*vp)->gv_post_online_f =
1126 special_vertices[i].post_online_f;
1127 (*vp)->gv_post_disable_f =
1128 special_vertices[i].post_disable_f;
1129 break;
1130 }
1131 }
1132
1133 (*vp)->gv_restarter_id = -1;
1134 (*vp)->gv_restarter_channel = 0;
1135
1136 if (type == GVT_INST) {
1137 char *sfmri;
1138 graph_vertex_t *sv;
1139
1140 sfmri = inst_fmri_to_svc_fmri(fmri);
1141 sv = vertex_get_by_name(sfmri);
1142 if (sv == NULL) {
1143 r = graph_insert_vertex_unconfigured(sfmri, GVT_SVC, 0,
1144 0, &sv);
1145 assert(r == 0);
1146 }
1147 startd_free(sfmri, max_scf_fmri_size);
1148
1149 graph_add_edge(sv, *vp);
1150 }
1151
1152 /*
1153 * If this vertex is in the subgraph, mark it as so, for both
1154 * GVT_INST and GVT_SERVICE verteces.
1155 * A GVT_SERVICE vertex can only be in the subgraph if another instance
1156 * depends on it, in which case it's already been added to the graph
1157 * and marked as in the subgraph (by refresh_vertex()). If a
1158 * GVT_SERVICE vertex was freshly added (by the code above), it means
1159 * that it has no dependents, and cannot be in the subgraph.
1160 * Regardless of this, we still check that gv_flags includes
1161 * GV_INSUBGRAPH in the event that future behavior causes the above
1162 * code to add a GVT_SERVICE vertex which should be in the subgraph.
1163 */
1164
1165 (*vp)->gv_flags |= (should_be_in_subgraph(*vp)? GV_INSUBGRAPH : 0);
1166
1167 return (0);
1168 }
1169
1170 /*
1171 * Returns 0 on success or ELOOP if the dependency would create a cycle.
1172 */
1173 static int
1174 graph_insert_dependency(graph_vertex_t *fv, graph_vertex_t *tv, int **pathp)
1175 {
1176 hrtime_t now;
1177
1178 assert(MUTEX_HELD(&dgraph_lock));
1179
1180 /* cycle detection */
1181 now = gethrtime();
1182
1183 /* Don't follow exclusions. */
1184 if (!(fv->gv_type == GVT_GROUP &&
1185 fv->gv_depgroup == DEPGRP_EXCLUDE_ALL)) {
1186 *pathp = is_path_to(tv, fv);
1187 if (*pathp)
1188 return (ELOOP);
1189 }
1190
1191 dep_cycle_ns += gethrtime() - now;
1192 ++dep_inserts;
1193 now = gethrtime();
1194
1195 graph_add_edge(fv, tv);
1196
1197 dep_insert_ns += gethrtime() - now;
1198
1199 /* Check if the dependency adds the "to" vertex to the subgraph */
1200 tv->gv_flags |= (should_be_in_subgraph(tv) ? GV_INSUBGRAPH : 0);
1201
1202 return (0);
1203 }
1204
1205 static int
1206 inst_running(graph_vertex_t *v)
1207 {
1208 assert(v->gv_type == GVT_INST);
1209
1210 if (v->gv_state == RESTARTER_STATE_ONLINE ||
1211 v->gv_state == RESTARTER_STATE_DEGRADED)
1212 return (1);
1213
1214 return (0);
1215 }
1216
1217 /*
1218 * The dependency evaluation functions return
1219 * 1 - dependency satisfied
1220 * 0 - dependency unsatisfied
1221 * -1 - dependency unsatisfiable (without administrator intervention)
1222 *
1223 * The functions also take a boolean satbility argument. When true, the
1224 * functions may recurse in order to determine satisfiability.
1225 */
1226 static int require_any_satisfied(graph_vertex_t *, boolean_t);
1227 static int dependency_satisfied(graph_vertex_t *, boolean_t);
1228
1229 /*
1230 * A require_all dependency is unsatisfied if any elements are unsatisfied. It
1231 * is unsatisfiable if any elements are unsatisfiable.
1232 */
1233 static int
1234 require_all_satisfied(graph_vertex_t *groupv, boolean_t satbility)
1235 {
1236 graph_edge_t *edge;
1237 int i;
1238 boolean_t any_unsatisfied;
1239
1240 if (uu_list_numnodes(groupv->gv_dependencies) == 0)
1241 return (1);
1242
1243 any_unsatisfied = B_FALSE;
1244
1245 for (edge = uu_list_first(groupv->gv_dependencies);
1246 edge != NULL;
1247 edge = uu_list_next(groupv->gv_dependencies, edge)) {
1248 i = dependency_satisfied(edge->ge_vertex, satbility);
1249 if (i == 1)
1250 continue;
1251
1252 log_framework2(LOG_DEBUG, DEBUG_DEPENDENCIES,
1253 "require_all(%s): %s is unsatisfi%s.\n", groupv->gv_name,
1254 edge->ge_vertex->gv_name, i == 0 ? "ed" : "able");
1255
1256 if (!satbility)
1257 return (0);
1258
1259 if (i == -1)
1260 return (-1);
1261
1262 any_unsatisfied = B_TRUE;
1263 }
1264
1265 return (any_unsatisfied ? 0 : 1);
1266 }
1267
1268 /*
1269 * A require_any dependency is satisfied if any element is satisfied. It is
1270 * satisfiable if any element is satisfiable.
1271 */
1272 static int
1273 require_any_satisfied(graph_vertex_t *groupv, boolean_t satbility)
1274 {
1275 graph_edge_t *edge;
1276 int s;
1277 boolean_t satisfiable;
1278
1279 if (uu_list_numnodes(groupv->gv_dependencies) == 0)
1280 return (1);
1281
1282 satisfiable = B_FALSE;
1283
1284 for (edge = uu_list_first(groupv->gv_dependencies);
1285 edge != NULL;
1286 edge = uu_list_next(groupv->gv_dependencies, edge)) {
1287 s = dependency_satisfied(edge->ge_vertex, satbility);
1288
1289 if (s == 1)
1290 return (1);
1291
1292 log_framework2(LOG_DEBUG, DEBUG_DEPENDENCIES,
1293 "require_any(%s): %s is unsatisfi%s.\n",
1294 groupv->gv_name, edge->ge_vertex->gv_name,
1295 s == 0 ? "ed" : "able");
1296
1297 if (satbility && s == 0)
1298 satisfiable = B_TRUE;
1299 }
1300
1301 return (!satbility || satisfiable ? 0 : -1);
1302 }
1303
1304 /*
1305 * An optional_all dependency only considers elements which are configured,
1306 * enabled, and not in maintenance. If any are unsatisfied, then the dependency
1307 * is unsatisfied.
1308 *
1309 * Offline dependencies which are waiting for a dependency to come online are
1310 * unsatisfied. Offline dependences which cannot possibly come online
1311 * (unsatisfiable) are always considered satisfied.
1312 */
1313 static int
1314 optional_all_satisfied(graph_vertex_t *groupv, boolean_t satbility)
1315 {
1316 graph_edge_t *edge;
1317 graph_vertex_t *v;
1318 boolean_t any_qualified;
1319 boolean_t any_unsatisfied;
1320 int i;
1321
1322 any_qualified = B_FALSE;
1323 any_unsatisfied = B_FALSE;
1324
1325 for (edge = uu_list_first(groupv->gv_dependencies);
1326 edge != NULL;
1327 edge = uu_list_next(groupv->gv_dependencies, edge)) {
1328 v = edge->ge_vertex;
1329
1330 switch (v->gv_type) {
1331 case GVT_INST:
1332 /* Skip missing instances */
1333 if ((v->gv_flags & GV_CONFIGURED) == 0)
1334 continue;
1335
1336 if (v->gv_state == RESTARTER_STATE_MAINT)
1337 continue;
1338
1339 any_qualified = B_TRUE;
1340 if (v->gv_state == RESTARTER_STATE_OFFLINE) {
1341 /*
1342 * For offline dependencies, treat unsatisfiable
1343 * as satisfied.
1344 */
1345 i = dependency_satisfied(v, B_TRUE);
1346 if (i == -1)
1347 i = 1;
1348 } else if (v->gv_state == RESTARTER_STATE_DISABLED) {
1349 /*
1350 * If the instance is transitioning out of
1351 * disabled the dependency is temporarily
1352 * unsatisfied (not unsatisfiable).
1353 */
1354 i = v->gv_flags & GV_ENABLED ? 0 : 1;
1355 } else {
1356 i = dependency_satisfied(v, satbility);
1357 }
1358 break;
1359
1360 case GVT_FILE:
1361 any_qualified = B_TRUE;
1362 i = dependency_satisfied(v, satbility);
1363
1364 break;
1365
1366 case GVT_SVC: {
1367 any_qualified = B_TRUE;
1368 i = optional_all_satisfied(v, satbility);
1369
1370 break;
1371 }
1372
1373 case GVT_GROUP:
1374 default:
1375 #ifndef NDEBUG
1376 uu_warn("%s:%d: Unexpected vertex type %d.\n", __FILE__,
1377 __LINE__, v->gv_type);
1378 #endif
1379 abort();
1380 }
1381
1382 if (i == 1)
1383 continue;
1384
1385 log_framework2(LOG_DEBUG, DEBUG_DEPENDENCIES,
1386 "optional_all(%s): %s is unsatisfi%s.\n", groupv->gv_name,
1387 v->gv_name, i == 0 ? "ed" : "able");
1388
1389 if (!satbility)
1390 return (0);
1391 if (i == -1)
1392 return (-1);
1393 any_unsatisfied = B_TRUE;
1394 }
1395
1396 if (!any_qualified)
1397 return (1);
1398
1399 return (any_unsatisfied ? 0 : 1);
1400 }
1401
1402 /*
1403 * An exclude_all dependency is unsatisfied if any non-service element is
1404 * satisfied or any service instance which is configured, enabled, and not in
1405 * maintenance is satisfied. Usually when unsatisfied, it is also
1406 * unsatisfiable.
1407 */
1408 #define LOG_EXCLUDE(u, v) \
1409 log_framework2(LOG_DEBUG, DEBUG_DEPENDENCIES, \
1410 "exclude_all(%s): %s is satisfied.\n", \
1411 (u)->gv_name, (v)->gv_name)
1412
1413 /* ARGSUSED */
1414 static int
1415 exclude_all_satisfied(graph_vertex_t *groupv, boolean_t satbility)
1416 {
1417 graph_edge_t *edge, *e2;
1418 graph_vertex_t *v, *v2;
1419
1420 for (edge = uu_list_first(groupv->gv_dependencies);
1421 edge != NULL;
1422 edge = uu_list_next(groupv->gv_dependencies, edge)) {
1423 v = edge->ge_vertex;
1424
1425 switch (v->gv_type) {
1426 case GVT_INST:
1427 if ((v->gv_flags & GV_CONFIGURED) == 0)
1428 continue;
1429
1430 switch (v->gv_state) {
1431 case RESTARTER_STATE_ONLINE:
1432 case RESTARTER_STATE_DEGRADED:
1433 LOG_EXCLUDE(groupv, v);
1434 return (v->gv_flags & GV_ENABLED ? -1 : 0);
1435
1436 case RESTARTER_STATE_OFFLINE:
1437 case RESTARTER_STATE_UNINIT:
1438 LOG_EXCLUDE(groupv, v);
1439 return (0);
1440
1441 case RESTARTER_STATE_DISABLED:
1442 case RESTARTER_STATE_MAINT:
1443 continue;
1444
1445 default:
1446 #ifndef NDEBUG
1447 uu_warn("%s:%d: Unexpected vertex state %d.\n",
1448 __FILE__, __LINE__, v->gv_state);
1449 #endif
1450 abort();
1451 }
1452 /* NOTREACHED */
1453
1454 case GVT_SVC:
1455 break;
1456
1457 case GVT_FILE:
1458 if (!file_ready(v))
1459 continue;
1460 LOG_EXCLUDE(groupv, v);
1461 return (-1);
1462
1463 case GVT_GROUP:
1464 default:
1465 #ifndef NDEBUG
1466 uu_warn("%s:%d: Unexpected vertex type %d.\n", __FILE__,
1467 __LINE__, v->gv_type);
1468 #endif
1469 abort();
1470 }
1471
1472 /* v represents a service */
1473 if (uu_list_numnodes(v->gv_dependencies) == 0)
1474 continue;
1475
1476 for (e2 = uu_list_first(v->gv_dependencies);
1477 e2 != NULL;
1478 e2 = uu_list_next(v->gv_dependencies, e2)) {
1479 v2 = e2->ge_vertex;
1480 assert(v2->gv_type == GVT_INST);
1481
1482 if ((v2->gv_flags & GV_CONFIGURED) == 0)
1483 continue;
1484
1485 switch (v2->gv_state) {
1486 case RESTARTER_STATE_ONLINE:
1487 case RESTARTER_STATE_DEGRADED:
1488 LOG_EXCLUDE(groupv, v2);
1489 return (v2->gv_flags & GV_ENABLED ? -1 : 0);
1490
1491 case RESTARTER_STATE_OFFLINE:
1492 case RESTARTER_STATE_UNINIT:
1493 LOG_EXCLUDE(groupv, v2);
1494 return (0);
1495
1496 case RESTARTER_STATE_DISABLED:
1497 case RESTARTER_STATE_MAINT:
1498 continue;
1499
1500 default:
1501 #ifndef NDEBUG
1502 uu_warn("%s:%d: Unexpected vertex type %d.\n",
1503 __FILE__, __LINE__, v2->gv_type);
1504 #endif
1505 abort();
1506 }
1507 }
1508 }
1509
1510 return (1);
1511 }
1512
1513 /*
1514 * int instance_satisfied()
1515 * Determine if all the dependencies are satisfied for the supplied instance
1516 * vertex. Return 1 if they are, 0 if they aren't, and -1 if they won't be
1517 * without administrator intervention.
1518 */
1519 static int
1520 instance_satisfied(graph_vertex_t *v, boolean_t satbility)
1521 {
1522 assert(v->gv_type == GVT_INST);
1523 assert(!inst_running(v));
1524
1525 return (require_all_satisfied(v, satbility));
1526 }
1527
1528 /*
1529 * Decide whether v can satisfy a dependency. v can either be a child of
1530 * a group vertex, or of an instance vertex.
1531 */
1532 static int
1533 dependency_satisfied(graph_vertex_t *v, boolean_t satbility)
1534 {
1535 switch (v->gv_type) {
1536 case GVT_INST:
1537 if ((v->gv_flags & GV_CONFIGURED) == 0) {
1538 if (v->gv_flags & GV_DEATHROW) {
1539 /*
1540 * A dependency on an instance with GV_DEATHROW
1541 * flag is always considered as satisfied.
1542 */
1543 return (1);
1544 }
1545 return (-1);
1546 }
1547
1548 /*
1549 * Any vertex with the GV_TODISABLE flag set is guaranteed
1550 * to have its dependencies unsatisfiable. Any vertex with
1551 * GV_TOOFFLINE may be satisfied after it transitions.
1552 */
1553 if (v->gv_flags & GV_TODISABLE)
1554 return (-1);
1555 if (v->gv_flags & GV_TOOFFLINE)
1556 return (0);
1557
1558 switch (v->gv_state) {
1559 case RESTARTER_STATE_ONLINE:
1560 case RESTARTER_STATE_DEGRADED:
1561 return (1);
1562
1563 case RESTARTER_STATE_OFFLINE:
1564 if (!satbility)
1565 return (0);
1566 return (instance_satisfied(v, satbility) != -1 ?
1567 0 : -1);
1568
1569 case RESTARTER_STATE_DISABLED:
1570 case RESTARTER_STATE_MAINT:
1571 return (-1);
1572
1573 case RESTARTER_STATE_UNINIT:
1574 return (0);
1575
1576 default:
1577 #ifndef NDEBUG
1578 uu_warn("%s:%d: Unexpected vertex state %d.\n",
1579 __FILE__, __LINE__, v->gv_state);
1580 #endif
1581 abort();
1582 /* NOTREACHED */
1583 }
1584
1585 case GVT_SVC:
1586 if (uu_list_numnodes(v->gv_dependencies) == 0)
1587 return (-1);
1588 return (require_any_satisfied(v, satbility));
1589
1590 case GVT_FILE:
1591 /* i.e., we assume files will not be automatically generated */
1592 return (file_ready(v) ? 1 : -1);
1593
1594 case GVT_GROUP:
1595 break;
1596
1597 default:
1598 #ifndef NDEBUG
1599 uu_warn("%s:%d: Unexpected node type %d.\n", __FILE__, __LINE__,
1600 v->gv_type);
1601 #endif
1602 abort();
1603 /* NOTREACHED */
1604 }
1605
1606 switch (v->gv_depgroup) {
1607 case DEPGRP_REQUIRE_ANY:
1608 return (require_any_satisfied(v, satbility));
1609
1610 case DEPGRP_REQUIRE_ALL:
1611 return (require_all_satisfied(v, satbility));
1612
1613 case DEPGRP_OPTIONAL_ALL:
1614 return (optional_all_satisfied(v, satbility));
1615
1616 case DEPGRP_EXCLUDE_ALL:
1617 return (exclude_all_satisfied(v, satbility));
1618
1619 default:
1620 #ifndef NDEBUG
1621 uu_warn("%s:%d: Unknown dependency grouping %d.\n", __FILE__,
1622 __LINE__, v->gv_depgroup);
1623 #endif
1624 abort();
1625 }
1626 }
1627
1628 void
1629 graph_start_if_satisfied(graph_vertex_t *v)
1630 {
1631 if (v->gv_state == RESTARTER_STATE_OFFLINE &&
1632 instance_satisfied(v, B_FALSE) == 1) {
1633 if (v->gv_start_f == NULL)
1634 vertex_send_event(v, RESTARTER_EVENT_TYPE_START);
1635 else
1636 v->gv_start_f(v);
1637 }
1638 }
1639
1640 /*
1641 * propagate_satbility()
1642 *
1643 * This function is used when the given vertex changes state in such a way that
1644 * one of its dependents may become unsatisfiable. This happens when an
1645 * instance transitions between offline -> online, or from !running ->
1646 * maintenance, as well as when an instance is removed from the graph.
1647 *
1648 * We have to walk all the dependents, since optional_all dependencies several
1649 * levels up could become (un)satisfied, instead of unsatisfiable. For example,
1650 *
1651 * +-----+ optional_all +-----+ require_all +-----+
1652 * | A |--------------->| B |-------------->| C |
1653 * +-----+ +-----+ +-----+
1654 *
1655 * offline -> maintenance
1656 *
1657 * If C goes into maintenance, it's not enough simply to check B. Because A has
1658 * an optional dependency, what was previously an unsatisfiable situation is now
1659 * satisfied (B will never come online, even though its state hasn't changed).
1660 *
1661 * Note that it's not necessary to continue examining dependents after reaching
1662 * an optional_all dependency. It's not possible for an optional_all dependency
1663 * to change satisfiability without also coming online, in which case we get a
1664 * start event and propagation continues naturally. However, it does no harm to
1665 * continue propagating satisfiability (as it is a relatively rare event), and
1666 * keeps the walker code simple and generic.
1667 */
1668 /*ARGSUSED*/
1669 static int
1670 satbility_cb(graph_vertex_t *v, void *arg)
1671 {
1672 if (v->gv_flags & GV_TOOFFLINE)
1673 return (UU_WALK_NEXT);
1674
1675 if (v->gv_type == GVT_INST)
1676 graph_start_if_satisfied(v);
1677
1678 return (UU_WALK_NEXT);
1679 }
1680
1681 static void
1682 propagate_satbility(graph_vertex_t *v)
1683 {
1684 graph_walk(v, WALK_DEPENDENTS, satbility_cb, NULL, NULL);
1685 }
1686
1687 static void propagate_stop(graph_vertex_t *, void *);
1688
1689 /*
1690 * propagate_start()
1691 *
1692 * This function is used to propagate a start event to the dependents of the
1693 * given vertex. Any dependents that are offline but have their dependencies
1694 * satisfied are started. Any dependents that are online and have restart_on
1695 * set to "restart" or "refresh" are restarted because their dependencies have
1696 * just changed. This only happens with optional_all dependencies.
1697 */
1698 static void
1699 propagate_start(graph_vertex_t *v, void *arg)
1700 {
1701 restarter_error_t err = (restarter_error_t)arg;
1702
1703 if (v->gv_flags & GV_TOOFFLINE)
1704 return;
1705
1706 switch (v->gv_type) {
1707 case GVT_INST:
1708 /* Restarter */
1709 if (inst_running(v)) {
1710 if (err == RERR_RESTART || err == RERR_REFRESH) {
1711 vertex_send_event(v,
1712 RESTARTER_EVENT_TYPE_STOP_RESET);
1713 }
1714 } else {
1715 graph_start_if_satisfied(v);
1716 }
1717 break;
1718
1719 case GVT_GROUP:
1720 if (v->gv_depgroup == DEPGRP_EXCLUDE_ALL) {
1721 graph_walk_dependents(v, propagate_stop,
1722 (void *)RERR_RESTART);
1723 break;
1724 }
1725 err = v->gv_restart;
1726 /* FALLTHROUGH */
1727
1728 case GVT_SVC:
1729 graph_walk_dependents(v, propagate_start, (void *)err);
1730 break;
1731
1732 case GVT_FILE:
1733 #ifndef NDEBUG
1734 uu_warn("%s:%d: propagate_start() encountered GVT_FILE.\n",
1735 __FILE__, __LINE__);
1736 #endif
1737 abort();
1738 /* NOTREACHED */
1739
1740 default:
1741 #ifndef NDEBUG
1742 uu_warn("%s:%d: Unknown vertex type %d.\n", __FILE__, __LINE__,
1743 v->gv_type);
1744 #endif
1745 abort();
1746 }
1747 }
1748
1749 /*
1750 * propagate_stop()
1751 *
1752 * This function is used to propagate a stop event to the dependents of the
1753 * given vertex. Any dependents that are online (or in degraded state) with
1754 * the restart_on property set to "restart" or "refresh" will be stopped as
1755 * their dependencies have just changed, propagate_start() will start them
1756 * again once their dependencies have been re-satisfied.
1757 */
1758 static void
1759 propagate_stop(graph_vertex_t *v, void *arg)
1760 {
1761 restarter_error_t err = (restarter_error_t)arg;
1762
1763 if (v->gv_flags & GV_TOOFFLINE)
1764 return;
1765
1766 switch (v->gv_type) {
1767 case GVT_INST:
1768 /* Restarter */
1769 if (err > RERR_NONE && inst_running(v)) {
1770 if (err == RERR_RESTART || err == RERR_REFRESH) {
1771 vertex_send_event(v,
1772 RESTARTER_EVENT_TYPE_STOP_RESET);
1773 } else {
1774 vertex_send_event(v, RESTARTER_EVENT_TYPE_STOP);
1775 }
1776 }
1777 break;
1778
1779 case GVT_SVC:
1780 graph_walk_dependents(v, propagate_stop, arg);
1781 break;
1782
1783 case GVT_FILE:
1784 #ifndef NDEBUG
1785 uu_warn("%s:%d: propagate_stop() encountered GVT_FILE.\n",
1786 __FILE__, __LINE__);
1787 #endif
1788 abort();
1789 /* NOTREACHED */
1790
1791 case GVT_GROUP:
1792 if (v->gv_depgroup == DEPGRP_EXCLUDE_ALL) {
1793 graph_walk_dependents(v, propagate_start, NULL);
1794 break;
1795 }
1796
1797 if (err == RERR_NONE || err > v->gv_restart)
1798 break;
1799
1800 graph_walk_dependents(v, propagate_stop, arg);
1801 break;
1802
1803 default:
1804 #ifndef NDEBUG
1805 uu_warn("%s:%d: Unknown vertex type %d.\n", __FILE__, __LINE__,
1806 v->gv_type);
1807 #endif
1808 abort();
1809 }
1810 }
1811
1812 void
1813 offline_vertex(graph_vertex_t *v)
1814 {
1815 scf_handle_t *h = libscf_handle_create_bound_loop();
1816 scf_instance_t *scf_inst = safe_scf_instance_create(h);
1817 scf_propertygroup_t *pg = safe_scf_pg_create(h);
1818 restarter_instance_state_t state, next_state;
1819 int r;
1820
1821 assert(v->gv_type == GVT_INST);
1822
1823 if (scf_inst == NULL)
1824 bad_error("safe_scf_instance_create", scf_error());
1825 if (pg == NULL)
1826 bad_error("safe_scf_pg_create", scf_error());
1827
1828 /* if the vertex is already going offline, return */
1829 rep_retry:
1830 if (scf_handle_decode_fmri(h, v->gv_name, NULL, NULL, scf_inst, NULL,
1831 NULL, SCF_DECODE_FMRI_EXACT) != 0) {
1832 switch (scf_error()) {
1833 case SCF_ERROR_CONNECTION_BROKEN:
1834 libscf_handle_rebind(h);
1835 goto rep_retry;
1836
1837 case SCF_ERROR_NOT_FOUND:
1838 scf_pg_destroy(pg);
1839 scf_instance_destroy(scf_inst);
1840 (void) scf_handle_unbind(h);
1841 scf_handle_destroy(h);
1842 return;
1843 }
1844 uu_die("Can't decode FMRI %s: %s\n", v->gv_name,
1845 scf_strerror(scf_error()));
1846 }
1847
1848 r = scf_instance_get_pg(scf_inst, SCF_PG_RESTARTER, pg);
1849 if (r != 0) {
1850 switch (scf_error()) {
1851 case SCF_ERROR_CONNECTION_BROKEN:
1852 libscf_handle_rebind(h);
1853 goto rep_retry;
1854
1855 case SCF_ERROR_NOT_SET:
1856 case SCF_ERROR_NOT_FOUND:
1857 scf_pg_destroy(pg);
1858 scf_instance_destroy(scf_inst);
1859 (void) scf_handle_unbind(h);
1860 scf_handle_destroy(h);
1861 return;
1862
1863 default:
1864 bad_error("scf_instance_get_pg", scf_error());
1865 }
1866 } else {
1867 r = libscf_read_states(pg, &state, &next_state);
1868 if (r == 0 && (next_state == RESTARTER_STATE_OFFLINE ||
1869 next_state == RESTARTER_STATE_DISABLED)) {
1870 log_framework(LOG_DEBUG,
1871 "%s: instance is already going down.\n",
1872 v->gv_name);
1873 scf_pg_destroy(pg);
1874 scf_instance_destroy(scf_inst);
1875 (void) scf_handle_unbind(h);
1876 scf_handle_destroy(h);
1877 return;
1878 }
1879 }
1880
1881 scf_pg_destroy(pg);
1882 scf_instance_destroy(scf_inst);
1883 (void) scf_handle_unbind(h);
1884 scf_handle_destroy(h);
1885
1886 vertex_send_event(v, RESTARTER_EVENT_TYPE_STOP_RESET);
1887 }
1888
1889 /*
1890 * void graph_enable_by_vertex()
1891 * If admin is non-zero, this is an administrative request for change
1892 * of the enabled property. Thus, send the ADMIN_DISABLE rather than
1893 * a plain DISABLE restarter event.
1894 */
1895 void
1896 graph_enable_by_vertex(graph_vertex_t *vertex, int enable, int admin)
1897 {
1898 graph_vertex_t *v;
1899 int r;
1900
1901 assert(MUTEX_HELD(&dgraph_lock));
1902 assert((vertex->gv_flags & GV_CONFIGURED));
1903
1904 vertex->gv_flags = (vertex->gv_flags & ~GV_ENABLED) |
1905 (enable ? GV_ENABLED : 0);
1906
1907 if (enable) {
1908 if (vertex->gv_state != RESTARTER_STATE_OFFLINE &&
1909 vertex->gv_state != RESTARTER_STATE_DEGRADED &&
1910 vertex->gv_state != RESTARTER_STATE_ONLINE) {
1911 /*
1912 * In case the vertex was notified to go down,
1913 * but now can return online, clear the _TOOFFLINE
1914 * and _TODISABLE flags.
1915 */
1916 vertex->gv_flags &= ~GV_TOOFFLINE;
1917 vertex->gv_flags &= ~GV_TODISABLE;
1918
1919 vertex_send_event(vertex, RESTARTER_EVENT_TYPE_ENABLE);
1920 }
1921
1922 /*
1923 * Wait for state update from restarter before sending _START or
1924 * _STOP.
1925 */
1926
1927 return;
1928 }
1929
1930 if (vertex->gv_state == RESTARTER_STATE_DISABLED)
1931 return;
1932
1933 if (!admin) {
1934 vertex_send_event(vertex, RESTARTER_EVENT_TYPE_DISABLE);
1935
1936 /*
1937 * Wait for state update from restarter before sending _START or
1938 * _STOP.
1939 */
1940
1941 return;
1942 }
1943
1944 /*
1945 * If it is a DISABLE event requested by the administrator then we are
1946 * offlining the dependents first.
1947 */
1948
1949 /*
1950 * Set GV_TOOFFLINE for the services we are offlining. We cannot
1951 * clear the GV_TOOFFLINE bits from all the services because
1952 * other DISABLE events might be handled at the same time.
1953 */
1954 vertex->gv_flags |= GV_TOOFFLINE;
1955
1956 /* remember which vertex to disable... */
1957 vertex->gv_flags |= GV_TODISABLE;
1958
1959 log_framework(LOG_DEBUG, "Marking in-subtree vertices before "
1960 "disabling %s.\n", vertex->gv_name);
1961
1962 /* set GV_TOOFFLINE for its dependents */
1963 r = uu_list_walk(vertex->gv_dependents, (uu_walk_fn_t *)mark_subtree,
1964 NULL, 0);
1965 assert(r == 0);
1966
1967 /* disable the instance now if there is nothing else to offline */
1968 if (insubtree_dependents_down(vertex) == B_TRUE) {
1969 vertex_send_event(vertex, RESTARTER_EVENT_TYPE_ADMIN_DISABLE);
1970 return;
1971 }
1972
1973 /*
1974 * This loop is similar to the one used for the graph reversal shutdown
1975 * and could be improved in term of performance for the subtree reversal
1976 * disable case.
1977 */
1978 for (v = uu_list_first(dgraph); v != NULL;
1979 v = uu_list_next(dgraph, v)) {
1980 /* skip the vertex we are disabling for now */
1981 if (v == vertex)
1982 continue;
1983
1984 if (v->gv_type != GVT_INST ||
1985 (v->gv_flags & GV_CONFIGURED) == 0 ||
1986 (v->gv_flags & GV_ENABLED) == 0 ||
1987 (v->gv_flags & GV_TOOFFLINE) == 0)
1988 continue;
1989
1990 if ((v->gv_state != RESTARTER_STATE_ONLINE) &&
1991 (v->gv_state != RESTARTER_STATE_DEGRADED)) {
1992 /* continue if there is nothing to offline */
1993 continue;
1994 }
1995
1996 /*
1997 * Instances which are up need to come down before we're
1998 * done, but we can only offline the leaves here. An
1999 * instance is a leaf when all its dependents are down.
2000 */
2001 if (insubtree_dependents_down(v) == B_TRUE) {
2002 log_framework(LOG_DEBUG, "Offlining in-subtree "
2003 "instance %s for %s.\n",
2004 v->gv_name, vertex->gv_name);
2005 offline_vertex(v);
2006 }
2007 }
2008 }
2009
2010 static int configure_vertex(graph_vertex_t *, scf_instance_t *);
2011
2012 /*
2013 * Set the restarter for v to fmri_arg. That is, make sure a vertex for
2014 * fmri_arg exists, make v depend on it, and send _ADD_INSTANCE for v. If
2015 * v is already configured and fmri_arg indicates the current restarter, do
2016 * nothing. If v is configured and fmri_arg is a new restarter, delete v's
2017 * dependency on the restarter, send _REMOVE_INSTANCE for v, and set the new
2018 * restarter. Returns 0 on success, EINVAL if the FMRI is invalid,
2019 * ECONNABORTED if the repository connection is broken, and ELOOP
2020 * if the dependency would create a cycle. In the last case, *pathp will
2021 * point to a -1-terminated array of ids which compose the path from v to
2022 * restarter_fmri.
2023 */
2024 int
2025 graph_change_restarter(graph_vertex_t *v, const char *fmri_arg, scf_handle_t *h,
2026 int **pathp)
2027 {
2028 char *restarter_fmri = NULL;
2029 graph_vertex_t *rv;
2030 int err;
2031 int id;
2032
2033 assert(MUTEX_HELD(&dgraph_lock));
2034
2035 if (fmri_arg[0] != '\0') {
2036 err = fmri_canonify(fmri_arg, &restarter_fmri, B_TRUE);
2037 if (err != 0) {
2038 assert(err == EINVAL);
2039 return (err);
2040 }
2041 }
2042
2043 if (restarter_fmri == NULL ||
2044 strcmp(restarter_fmri, SCF_SERVICE_STARTD) == 0) {
2045 if (v->gv_flags & GV_CONFIGURED) {
2046 if (v->gv_restarter_id == -1) {
2047 if (restarter_fmri != NULL)
2048 startd_free(restarter_fmri,
2049 max_scf_fmri_size);
2050 return (0);
2051 }
2052
2053 graph_unset_restarter(v);
2054 }
2055
2056 /* Master restarter, nothing to do. */
2057 v->gv_restarter_id = -1;
2058 v->gv_restarter_channel = NULL;
2059 vertex_send_event(v, RESTARTER_EVENT_TYPE_ADD_INSTANCE);
2060 return (0);
2061 }
2062
2063 if (v->gv_flags & GV_CONFIGURED) {
2064 id = dict_lookup_byname(restarter_fmri);
2065 if (id != -1 && v->gv_restarter_id == id) {
2066 startd_free(restarter_fmri, max_scf_fmri_size);
2067 return (0);
2068 }
2069
2070 graph_unset_restarter(v);
2071 }
2072
2073 err = graph_insert_vertex_unconfigured(restarter_fmri, GVT_INST, 0,
2074 RERR_NONE, &rv);
2075 startd_free(restarter_fmri, max_scf_fmri_size);
2076 assert(err == 0 || err == EEXIST);
2077
2078 if (rv->gv_delegate_initialized == 0) {
2079 if ((rv->gv_delegate_channel = restarter_protocol_init_delegate(
2080 rv->gv_name)) == NULL)
2081 return (EINVAL);
2082 rv->gv_delegate_initialized = 1;
2083 }
2084 v->gv_restarter_id = rv->gv_id;
2085 v->gv_restarter_channel = rv->gv_delegate_channel;
2086
2087 err = graph_insert_dependency(v, rv, pathp);
2088 if (err != 0) {
2089 assert(err == ELOOP);
2090 return (ELOOP);
2091 }
2092
2093 vertex_send_event(v, RESTARTER_EVENT_TYPE_ADD_INSTANCE);
2094
2095 if (!(rv->gv_flags & GV_CONFIGURED)) {
2096 scf_instance_t *inst;
2097
2098 err = libscf_fmri_get_instance(h, rv->gv_name, &inst);
2099 switch (err) {
2100 case 0:
2101 err = configure_vertex(rv, inst);
2102 scf_instance_destroy(inst);
2103 switch (err) {
2104 case 0:
2105 case ECANCELED:
2106 break;
2107
2108 case ECONNABORTED:
2109 return (ECONNABORTED);
2110
2111 default:
2112 bad_error("configure_vertex", err);
2113 }
2114 break;
2115
2116 case ECONNABORTED:
2117 return (ECONNABORTED);
2118
2119 case ENOENT:
2120 break;
2121
2122 case ENOTSUP:
2123 /*
2124 * The fmri doesn't specify an instance - translate
2125 * to EINVAL.
2126 */
2127 return (EINVAL);
2128
2129 case EINVAL:
2130 default:
2131 bad_error("libscf_fmri_get_instance", err);
2132 }
2133 }
2134
2135 return (0);
2136 }
2137
2138
2139 /*
2140 * Add all of the instances of the service named by fmri to the graph.
2141 * Returns
2142 * 0 - success
2143 * ENOENT - service indicated by fmri does not exist
2144 *
2145 * In both cases *reboundp will be B_TRUE if the handle was rebound, or B_FALSE
2146 * otherwise.
2147 */
2148 static int
2149 add_service(const char *fmri, scf_handle_t *h, boolean_t *reboundp)
2150 {
2151 scf_service_t *svc;
2152 scf_instance_t *inst;
2153 scf_iter_t *iter;
2154 char *inst_fmri;
2155 int ret, r;
2156
2157 *reboundp = B_FALSE;
2158
2159 svc = safe_scf_service_create(h);
2160 inst = safe_scf_instance_create(h);
2161 iter = safe_scf_iter_create(h);
2162 inst_fmri = startd_alloc(max_scf_fmri_size);
2163
2164 rebound:
2165 if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL,
2166 SCF_DECODE_FMRI_EXACT) != 0) {
2167 switch (scf_error()) {
2168 case SCF_ERROR_CONNECTION_BROKEN:
2169 default:
2170 libscf_handle_rebind(h);
2171 *reboundp = B_TRUE;
2172 goto rebound;
2173
2174 case SCF_ERROR_NOT_FOUND:
2175 ret = ENOENT;
2176 goto out;
2177
2178 case SCF_ERROR_INVALID_ARGUMENT:
2179 case SCF_ERROR_CONSTRAINT_VIOLATED:
2180 case SCF_ERROR_NOT_BOUND:
2181 case SCF_ERROR_HANDLE_MISMATCH:
2182 bad_error("scf_handle_decode_fmri", scf_error());
2183 }
2184 }
2185
2186 if (scf_iter_service_instances(iter, svc) != 0) {
2187 switch (scf_error()) {
2188 case SCF_ERROR_CONNECTION_BROKEN:
2189 default:
2190 libscf_handle_rebind(h);
2191 *reboundp = B_TRUE;
2192 goto rebound;
2193
2194 case SCF_ERROR_DELETED:
2195 ret = ENOENT;
2196 goto out;
2197
2198 case SCF_ERROR_HANDLE_MISMATCH:
2199 case SCF_ERROR_NOT_BOUND:
2200 case SCF_ERROR_NOT_SET:
2201 bad_error("scf_iter_service_instances", scf_error());
2202 }
2203 }
2204
2205 for (;;) {
2206 r = scf_iter_next_instance(iter, inst);
2207 if (r == 0)
2208 break;
2209 if (r != 1) {
2210 switch (scf_error()) {
2211 case SCF_ERROR_CONNECTION_BROKEN:
2212 default:
2213 libscf_handle_rebind(h);
2214 *reboundp = B_TRUE;
2215 goto rebound;
2216
2217 case SCF_ERROR_DELETED:
2218 ret = ENOENT;
2219 goto out;
2220
2221 case SCF_ERROR_HANDLE_MISMATCH:
2222 case SCF_ERROR_NOT_BOUND:
2223 case SCF_ERROR_NOT_SET:
2224 case SCF_ERROR_INVALID_ARGUMENT:
2225 bad_error("scf_iter_next_instance",
2226 scf_error());
2227 }
2228 }
2229
2230 if (scf_instance_to_fmri(inst, inst_fmri, max_scf_fmri_size) <
2231 0) {
2232 switch (scf_error()) {
2233 case SCF_ERROR_CONNECTION_BROKEN:
2234 libscf_handle_rebind(h);
2235 *reboundp = B_TRUE;
2236 goto rebound;
2237
2238 case SCF_ERROR_DELETED:
2239 continue;
2240
2241 case SCF_ERROR_NOT_BOUND:
2242 case SCF_ERROR_NOT_SET:
2243 bad_error("scf_instance_to_fmri", scf_error());
2244 }
2245 }
2246
2247 r = dgraph_add_instance(inst_fmri, inst, B_FALSE);
2248 switch (r) {
2249 case 0:
2250 case ECANCELED:
2251 break;
2252
2253 case EEXIST:
2254 continue;
2255
2256 case ECONNABORTED:
2257 libscf_handle_rebind(h);
2258 *reboundp = B_TRUE;
2259 goto rebound;
2260
2261 case EINVAL:
2262 default:
2263 bad_error("dgraph_add_instance", r);
2264 }
2265 }
2266
2267 ret = 0;
2268
2269 out:
2270 startd_free(inst_fmri, max_scf_fmri_size);
2271 scf_iter_destroy(iter);
2272 scf_instance_destroy(inst);
2273 scf_service_destroy(svc);
2274 return (ret);
2275 }
2276
2277 struct depfmri_info {
2278 graph_vertex_t *v; /* GVT_GROUP vertex */
2279 gv_type_t type; /* type of dependency */
2280 const char *inst_fmri; /* FMRI of parental GVT_INST vert. */
2281 const char *pg_name; /* Name of dependency pg */
2282 scf_handle_t *h;
2283 int err; /* return error code */
2284 int **pathp; /* return circular dependency path */
2285 };
2286
2287 /*
2288 * Find or create a vertex for fmri and make info->v depend on it.
2289 * Returns
2290 * 0 - success
2291 * nonzero - failure
2292 *
2293 * On failure, sets info->err to
2294 * EINVAL - fmri is invalid
2295 * fmri does not match info->type
2296 * ELOOP - Adding the dependency creates a circular dependency. *info->pathp
2297 * will point to an array of the ids of the members of the cycle.
2298 * ECONNABORTED - repository connection was broken
2299 * ECONNRESET - succeeded, but repository connection was reset
2300 */
2301 static int
2302 process_dependency_fmri(const char *fmri, struct depfmri_info *info)
2303 {
2304 int err;
2305 graph_vertex_t *depgroup_v, *v;
2306 char *fmri_copy, *cfmri;
2307 size_t fmri_copy_sz;
2308 const char *scope, *service, *instance, *pg;
2309 scf_instance_t *inst;
2310 boolean_t rebound;
2311
2312 assert(MUTEX_HELD(&dgraph_lock));
2313
2314 /* Get or create vertex for FMRI */
2315 depgroup_v = info->v;
2316
2317 if (strncmp(fmri, "file:", sizeof ("file:") - 1) == 0) {
2318 if (info->type != GVT_FILE) {
2319 log_framework(LOG_NOTICE,
2320 "FMRI \"%s\" is not allowed for the \"%s\" "
2321 "dependency's type of instance %s.\n", fmri,
2322 info->pg_name, info->inst_fmri);
2323 return (info->err = EINVAL);
2324 }
2325
2326 err = graph_insert_vertex_unconfigured(fmri, info->type, 0,
2327 RERR_NONE, &v);
2328 switch (err) {
2329 case 0:
2330 break;
2331
2332 case EEXIST:
2333 assert(v->gv_type == GVT_FILE);
2334 break;
2335
2336 case EINVAL: /* prevented above */
2337 default:
2338 bad_error("graph_insert_vertex_unconfigured", err);
2339 }
2340 } else {
2341 if (info->type != GVT_INST) {
2342 log_framework(LOG_NOTICE,
2343 "FMRI \"%s\" is not allowed for the \"%s\" "
2344 "dependency's type of instance %s.\n", fmri,
2345 info->pg_name, info->inst_fmri);
2346 return (info->err = EINVAL);
2347 }
2348
2349 /*
2350 * We must canonify fmri & add a vertex for it.
2351 */
2352 fmri_copy_sz = strlen(fmri) + 1;
2353 fmri_copy = startd_alloc(fmri_copy_sz);
2354 (void) strcpy(fmri_copy, fmri);
2355
2356 /* Determine if the FMRI is a property group or instance */
2357 if (scf_parse_svc_fmri(fmri_copy, &scope, &service,
2358 &instance, &pg, NULL) != 0) {
2359 startd_free(fmri_copy, fmri_copy_sz);
2360 log_framework(LOG_NOTICE,
2361 "Dependency \"%s\" of %s has invalid FMRI "
2362 "\"%s\".\n", info->pg_name, info->inst_fmri,
2363 fmri);
2364 return (info->err = EINVAL);
2365 }
2366
2367 if (service == NULL || pg != NULL) {
2368 startd_free(fmri_copy, fmri_copy_sz);
2369 log_framework(LOG_NOTICE,
2370 "Dependency \"%s\" of %s does not designate a "
2371 "service or instance.\n", info->pg_name,
2372 info->inst_fmri);
2373 return (info->err = EINVAL);
2374 }
2375
2376 if (scope == NULL || strcmp(scope, SCF_SCOPE_LOCAL) == 0) {
2377 cfmri = uu_msprintf("svc:/%s%s%s",
2378 service, instance ? ":" : "", instance ? instance :
2379 "");
2380 } else {
2381 cfmri = uu_msprintf("svc://%s/%s%s%s",
2382 scope, service, instance ? ":" : "", instance ?
2383 instance : "");
2384 }
2385
2386 startd_free(fmri_copy, fmri_copy_sz);
2387
2388 err = graph_insert_vertex_unconfigured(cfmri, instance ?
2389 GVT_INST : GVT_SVC, instance ? 0 : DEPGRP_REQUIRE_ANY,
2390 RERR_NONE, &v);
2391 uu_free(cfmri);
2392 switch (err) {
2393 case 0:
2394 break;
2395
2396 case EEXIST:
2397 /* Verify v. */
2398 if (instance != NULL)
2399 assert(v->gv_type == GVT_INST);
2400 else
2401 assert(v->gv_type == GVT_SVC);
2402 break;
2403
2404 default:
2405 bad_error("graph_insert_vertex_unconfigured", err);
2406 }
2407 }
2408
2409 /* Add dependency from depgroup_v to new vertex */
2410 info->err = graph_insert_dependency(depgroup_v, v, info->pathp);
2411 switch (info->err) {
2412 case 0:
2413 break;
2414
2415 case ELOOP:
2416 return (ELOOP);
2417
2418 default:
2419 bad_error("graph_insert_dependency", info->err);
2420 }
2421
2422 /* This must be after we insert the dependency, to avoid looping. */
2423 switch (v->gv_type) {
2424 case GVT_INST:
2425 if ((v->gv_flags & GV_CONFIGURED) != 0)
2426 break;
2427
2428 inst = safe_scf_instance_create(info->h);
2429
2430 rebound = B_FALSE;
2431
2432 rebound:
2433 err = libscf_lookup_instance(v->gv_name, inst);
2434 switch (err) {
2435 case 0:
2436 err = configure_vertex(v, inst);
2437 switch (err) {
2438 case 0:
2439 case ECANCELED:
2440 break;
2441
2442 case ECONNABORTED:
2443 libscf_handle_rebind(info->h);
2444 rebound = B_TRUE;
2445 goto rebound;
2446
2447 default:
2448 bad_error("configure_vertex", err);
2449 }
2450 break;
2451
2452 case ENOENT:
2453 break;
2454
2455 case ECONNABORTED:
2456 libscf_handle_rebind(info->h);
2457 rebound = B_TRUE;
2458 goto rebound;
2459
2460 case EINVAL:
2461 case ENOTSUP:
2462 default:
2463 bad_error("libscf_fmri_get_instance", err);
2464 }
2465
2466 scf_instance_destroy(inst);
2467
2468 if (rebound)
2469 return (info->err = ECONNRESET);
2470 break;
2471
2472 case GVT_SVC:
2473 (void) add_service(v->gv_name, info->h, &rebound);
2474 if (rebound)
2475 return (info->err = ECONNRESET);
2476 }
2477
2478 return (0);
2479 }
2480
2481 struct deppg_info {
2482 graph_vertex_t *v; /* GVT_INST vertex */
2483 int err; /* return error */
2484 int **pathp; /* return circular dependency path */
2485 };
2486
2487 /*
2488 * Make info->v depend on a new GVT_GROUP node for this property group,
2489 * and then call process_dependency_fmri() for the values of the entity
2490 * property. Return 0 on success, or if something goes wrong return nonzero
2491 * and set info->err to ECONNABORTED, EINVAL, or the error code returned by
2492 * process_dependency_fmri().
2493 */
2494 static int
2495 process_dependency_pg(scf_propertygroup_t *pg, struct deppg_info *info)
2496 {
2497 scf_handle_t *h;
2498 depgroup_type_t deptype;
2499 restarter_error_t rerr;
2500 struct depfmri_info linfo;
2501 char *fmri, *pg_name;
2502 size_t fmri_sz;
2503 graph_vertex_t *depgrp;
2504 scf_property_t *prop;
2505 int err;
2506 int empty;
2507 scf_error_t scferr;
2508 ssize_t len;
2509
2510 assert(MUTEX_HELD(&dgraph_lock));
2511
2512 h = scf_pg_handle(pg);
2513
2514 pg_name = startd_alloc(max_scf_name_size);
2515
2516 len = scf_pg_get_name(pg, pg_name, max_scf_name_size);
2517 if (len < 0) {
2518 startd_free(pg_name, max_scf_name_size);
2519 switch (scf_error()) {
2520 case SCF_ERROR_CONNECTION_BROKEN:
2521 default:
2522 return (info->err = ECONNABORTED);
2523
2524 case SCF_ERROR_DELETED:
2525 return (info->err = 0);
2526
2527 case SCF_ERROR_NOT_SET:
2528 bad_error("scf_pg_get_name", scf_error());
2529 }
2530 }
2531
2532 /*
2533 * Skip over empty dependency groups. Since dependency property
2534 * groups are updated atomically, they are either empty or
2535 * fully populated.
2536 */
2537 empty = depgroup_empty(h, pg);
2538 if (empty < 0) {
2539 log_error(LOG_INFO,
2540 "Error reading dependency group \"%s\" of %s: %s\n",
2541 pg_name, info->v->gv_name, scf_strerror(scf_error()));
2542 startd_free(pg_name, max_scf_name_size);
2543 return (info->err = EINVAL);
2544
2545 } else if (empty == 1) {
2546 log_framework(LOG_DEBUG,
2547 "Ignoring empty dependency group \"%s\" of %s\n",
2548 pg_name, info->v->gv_name);
2549 startd_free(pg_name, max_scf_name_size);
2550 return (info->err = 0);
2551 }
2552
2553 fmri_sz = strlen(info->v->gv_name) + 1 + len + 1;
2554 fmri = startd_alloc(fmri_sz);
2555
2556 (void) snprintf(fmri, fmri_sz, "%s>%s", info->v->gv_name,
2557 pg_name);
2558
2559 /* Validate the pg before modifying the graph */
2560 deptype = depgroup_read_grouping(h, pg);
2561 if (deptype == DEPGRP_UNSUPPORTED) {
2562 log_error(LOG_INFO,
2563 "Dependency \"%s\" of %s has an unknown grouping value.\n",
2564 pg_name, info->v->gv_name);
2565 startd_free(fmri, fmri_sz);
2566 startd_free(pg_name, max_scf_name_size);
2567 return (info->err = EINVAL);
2568 }
2569
2570 rerr = depgroup_read_restart(h, pg);
2571 if (rerr == RERR_UNSUPPORTED) {
2572 log_error(LOG_INFO,
2573 "Dependency \"%s\" of %s has an unknown restart_on value."
2574 "\n", pg_name, info->v->gv_name);
2575 startd_free(fmri, fmri_sz);
2576 startd_free(pg_name, max_scf_name_size);
2577 return (info->err = EINVAL);
2578 }
2579
2580 prop = safe_scf_property_create(h);
2581
2582 if (scf_pg_get_property(pg, SCF_PROPERTY_ENTITIES, prop) != 0) {
2583 scferr = scf_error();
2584 scf_property_destroy(prop);
2585 if (scferr == SCF_ERROR_DELETED) {
2586 startd_free(fmri, fmri_sz);
2587 startd_free(pg_name, max_scf_name_size);
2588 return (info->err = 0);
2589 } else if (scferr != SCF_ERROR_NOT_FOUND) {
2590 startd_free(fmri, fmri_sz);
2591 startd_free(pg_name, max_scf_name_size);
2592 return (info->err = ECONNABORTED);
2593 }
2594
2595 log_error(LOG_INFO,
2596 "Dependency \"%s\" of %s is missing a \"%s\" property.\n",
2597 pg_name, info->v->gv_name, SCF_PROPERTY_ENTITIES);
2598
2599 startd_free(fmri, fmri_sz);
2600 startd_free(pg_name, max_scf_name_size);
2601
2602 return (info->err = EINVAL);
2603 }
2604
2605 /* Create depgroup vertex for pg */
2606 err = graph_insert_vertex_unconfigured(fmri, GVT_GROUP, deptype,
2607 rerr, &depgrp);
2608 assert(err == 0);
2609 startd_free(fmri, fmri_sz);
2610
2611 /* Add dependency from inst vertex to new vertex */
2612 err = graph_insert_dependency(info->v, depgrp, info->pathp);
2613 /* ELOOP can't happen because this should be a new vertex */
2614 assert(err == 0);
2615
2616 linfo.v = depgrp;
2617 linfo.type = depgroup_read_scheme(h, pg);
2618 linfo.inst_fmri = info->v->gv_name;
2619 linfo.pg_name = pg_name;
2620 linfo.h = h;
2621 linfo.err = 0;
2622 linfo.pathp = info->pathp;
2623 err = walk_property_astrings(prop, (callback_t)process_dependency_fmri,
2624 &linfo);
2625
2626 scf_property_destroy(prop);
2627 startd_free(pg_name, max_scf_name_size);
2628
2629 switch (err) {
2630 case 0:
2631 case EINTR:
2632 return (info->err = linfo.err);
2633
2634 case ECONNABORTED:
2635 case EINVAL:
2636 return (info->err = err);
2637
2638 case ECANCELED:
2639 return (info->err = 0);
2640
2641 case ECONNRESET:
2642 return (info->err = ECONNABORTED);
2643
2644 default:
2645 bad_error("walk_property_astrings", err);
2646 /* NOTREACHED */
2647 }
2648 }
2649
2650 /*
2651 * Build the dependency info for v from the repository. Returns 0 on success,
2652 * ECONNABORTED on repository disconnection, EINVAL if the repository
2653 * configuration is invalid, and ELOOP if a dependency would cause a cycle.
2654 * In the last case, *pathp will point to a -1-terminated array of ids which
2655 * constitute the rest of the dependency cycle.
2656 */
2657 static int
2658 set_dependencies(graph_vertex_t *v, scf_instance_t *inst, int **pathp)
2659 {
2660 struct deppg_info info;
2661 int err;
2662 uint_t old_configured;
2663
2664 assert(MUTEX_HELD(&dgraph_lock));
2665
2666 /*
2667 * Mark the vertex as configured during dependency insertion to avoid
2668 * dependency cycles (which can appear in the graph if one of the
2669 * vertices is an exclusion-group).
2670 */
2671 old_configured = v->gv_flags & GV_CONFIGURED;
2672 v->gv_flags |= GV_CONFIGURED;
2673
2674 info.err = 0;
2675 info.v = v;
2676 info.pathp = pathp;
2677
2678 err = walk_dependency_pgs(inst, (callback_t)process_dependency_pg,
2679 &info);
2680
2681 if (!old_configured)
2682 v->gv_flags &= ~GV_CONFIGURED;
2683
2684 switch (err) {
2685 case 0:
2686 case EINTR:
2687 return (info.err);
2688
2689 case ECONNABORTED:
2690 return (ECONNABORTED);
2691
2692 case ECANCELED:
2693 /* Should get delete event, so return 0. */
2694 return (0);
2695
2696 default:
2697 bad_error("walk_dependency_pgs", err);
2698 /* NOTREACHED */
2699 }
2700 }
2701
2702
2703 static void
2704 handle_cycle(const char *fmri, int *path)
2705 {
2706 const char *cp;
2707 size_t sz;
2708
2709 assert(MUTEX_HELD(&dgraph_lock));
2710
2711 path_to_str(path, (char **)&cp, &sz);
2712
2713 log_error(LOG_ERR, "Transitioning %s to maintenance "
2714 "because it completes a dependency cycle (see svcs -xv for "
2715 "details):\n%s", fmri ? fmri : "?", cp);
2716
2717 startd_free((void *)cp, sz);
2718 }
2719
2720 /*
2721 * Increment the vertex's reference count to prevent the vertex removal
2722 * from the dgraph.
2723 */
2724 static void
2725 vertex_ref(graph_vertex_t *v)
2726 {
2727 assert(MUTEX_HELD(&dgraph_lock));
2728
2729 v->gv_refs++;
2730 }
2731
2732 /*
2733 * Decrement the vertex's reference count and remove the vertex from
2734 * the dgraph when possible.
2735 *
2736 * Return VERTEX_REMOVED when the vertex has been removed otherwise
2737 * return VERTEX_INUSE.
2738 */
2739 static int
2740 vertex_unref(graph_vertex_t *v)
2741 {
2742 assert(MUTEX_HELD(&dgraph_lock));
2743 assert(v->gv_refs > 0);
2744
2745 v->gv_refs--;
2746
2747 return (free_if_unrefed(v));
2748 }
2749
2750 /*
2751 * When run on the dependencies of a vertex, populates list with
2752 * graph_edge_t's which point to the service vertices or the instance
2753 * vertices (no GVT_GROUP nodes) on which the vertex depends.
2754 *
2755 * Increment the vertex's reference count once the vertex is inserted
2756 * in the list. The vertex won't be able to be deleted from the dgraph
2757 * while it is referenced.
2758 */
2759 static int
2760 append_svcs_or_insts(graph_edge_t *e, uu_list_t *list)
2761 {
2762 graph_vertex_t *v = e->ge_vertex;
2763 graph_edge_t *new;
2764 int r;
2765
2766 switch (v->gv_type) {
2767 case GVT_INST:
2768 case GVT_SVC:
2769 break;
2770
2771 case GVT_GROUP:
2772 r = uu_list_walk(v->gv_dependencies,
2773 (uu_walk_fn_t *)append_svcs_or_insts, list, 0);
2774 assert(r == 0);
2775 return (UU_WALK_NEXT);
2776
2777 case GVT_FILE:
2778 return (UU_WALK_NEXT);
2779
2780 default:
2781 #ifndef NDEBUG
2782 uu_warn("%s:%d: Unexpected vertex type %d.\n", __FILE__,
2783 __LINE__, v->gv_type);
2784 #endif
2785 abort();
2786 }
2787
2788 new = startd_alloc(sizeof (*new));
2789 new->ge_vertex = v;
2790 uu_list_node_init(new, &new->ge_link, graph_edge_pool);
2791 r = uu_list_insert_before(list, NULL, new);
2792 assert(r == 0);
2793
2794 /*
2795 * Because we are inserting the vertex in a list, we don't want
2796 * the vertex to be freed while the list is in use. In order to
2797 * achieve that, increment the vertex's reference count.
2798 */
2799 vertex_ref(v);
2800
2801 return (UU_WALK_NEXT);
2802 }
2803
2804 static boolean_t
2805 should_be_in_subgraph(graph_vertex_t *v)
2806 {
2807 graph_edge_t *e;
2808
2809 if (v == milestone)
2810 return (B_TRUE);
2811
2812 /*
2813 * v is in the subgraph if any of its dependents are in the subgraph.
2814 * Except for EXCLUDE_ALL dependents. And OPTIONAL dependents only
2815 * count if we're enabled.
2816 */
2817 for (e = uu_list_first(v->gv_dependents);
2818 e != NULL;
2819 e = uu_list_next(v->gv_dependents, e)) {
2820 graph_vertex_t *dv = e->ge_vertex;
2821
2822 if (!(dv->gv_flags & GV_INSUBGRAPH))
2823 continue;
2824
2825 /*
2826 * Don't include instances that are optional and disabled.
2827 */
2828 if (v->gv_type == GVT_INST && dv->gv_type == GVT_SVC) {
2829
2830 int in = 0;
2831 graph_edge_t *ee;
2832
2833 for (ee = uu_list_first(dv->gv_dependents);
2834 ee != NULL;
2835 ee = uu_list_next(dv->gv_dependents, ee)) {
2836
2837 graph_vertex_t *ddv = e->ge_vertex;
2838
2839 if (ddv->gv_type == GVT_GROUP &&
2840 ddv->gv_depgroup == DEPGRP_EXCLUDE_ALL)
2841 continue;
2842
2843 if (ddv->gv_type == GVT_GROUP &&
2844 ddv->gv_depgroup == DEPGRP_OPTIONAL_ALL &&
2845 !(v->gv_flags & GV_ENBLD_NOOVR))
2846 continue;
2847
2848 in = 1;
2849 }
2850 if (!in)
2851 continue;
2852 }
2853 if (v->gv_type == GVT_INST &&
2854 dv->gv_type == GVT_GROUP &&
2855 dv->gv_depgroup == DEPGRP_OPTIONAL_ALL &&
2856 !(v->gv_flags & GV_ENBLD_NOOVR))
2857 continue;
2858
2859 /* Don't include excluded services and instances */
2860 if (dv->gv_type == GVT_GROUP &&
2861 dv->gv_depgroup == DEPGRP_EXCLUDE_ALL)
2862 continue;
2863
2864 return (B_TRUE);
2865 }
2866
2867 return (B_FALSE);
2868 }
2869
2870 /*
2871 * Ensures that GV_INSUBGRAPH is set properly for v and its descendents. If
2872 * any bits change, manipulate the repository appropriately. Returns 0 or
2873 * ECONNABORTED.
2874 */
2875 static int
2876 eval_subgraph(graph_vertex_t *v, scf_handle_t *h)
2877 {
2878 boolean_t old = (v->gv_flags & GV_INSUBGRAPH) != 0;
2879 boolean_t new;
2880 graph_edge_t *e;
2881 scf_instance_t *inst;
2882 int ret = 0, r;
2883
2884 assert(milestone != NULL && milestone != MILESTONE_NONE);
2885
2886 new = should_be_in_subgraph(v);
2887
2888 if (new == old)
2889 return (0);
2890
2891 log_framework(LOG_DEBUG, new ? "Adding %s to the subgraph.\n" :
2892 "Removing %s from the subgraph.\n", v->gv_name);
2893
2894 v->gv_flags = (v->gv_flags & ~GV_INSUBGRAPH) |
2895 (new ? GV_INSUBGRAPH : 0);
2896
2897 if (v->gv_type == GVT_INST && (v->gv_flags & GV_CONFIGURED)) {
2898 int err;
2899
2900 get_inst:
2901 err = libscf_fmri_get_instance(h, v->gv_name, &inst);
2902 if (err != 0) {
2903 switch (err) {
2904 case ECONNABORTED:
2905 libscf_handle_rebind(h);
2906 ret = ECONNABORTED;
2907 goto get_inst;
2908
2909 case ENOENT:
2910 break;
2911
2912 case EINVAL:
2913 case ENOTSUP:
2914 default:
2915 bad_error("libscf_fmri_get_instance", err);
2916 }
2917 } else {
2918 const char *f;
2919
2920 if (new) {
2921 err = libscf_delete_enable_ovr(inst);
2922 f = "libscf_delete_enable_ovr";
2923 } else {
2924 err = libscf_set_enable_ovr(inst, 0);
2925 f = "libscf_set_enable_ovr";
2926 }
2927 scf_instance_destroy(inst);
2928 switch (err) {
2929 case 0:
2930 case ECANCELED:
2931 break;
2932
2933 case ECONNABORTED:
2934 libscf_handle_rebind(h);
2935 /*
2936 * We must continue so the graph is updated,
2937 * but we must return ECONNABORTED so any
2938 * libscf state held by any callers is reset.
2939 */
2940 ret = ECONNABORTED;
2941 goto get_inst;
2942
2943 case EROFS:
2944 case EPERM:
2945 log_error(LOG_WARNING,
2946 "Could not set %s/%s for %s: %s.\n",
2947 SCF_PG_GENERAL_OVR, SCF_PROPERTY_ENABLED,
2948 v->gv_name, strerror(err));
2949 break;
2950
2951 default:
2952 bad_error(f, err);
2953 }
2954 }
2955 }
2956
2957 for (e = uu_list_first(v->gv_dependencies);
2958 e != NULL;
2959 e = uu_list_next(v->gv_dependencies, e)) {
2960 r = eval_subgraph(e->ge_vertex, h);
2961 if (r != 0) {
2962 assert(r == ECONNABORTED);
2963 ret = ECONNABORTED;
2964 }
2965 }
2966
2967 return (ret);
2968 }
2969
2970 /*
2971 * Delete the (property group) dependencies of v & create new ones based on
2972 * inst. If doing so would create a cycle, log a message and put the instance
2973 * into maintenance. Update GV_INSUBGRAPH flags as necessary. Returns 0 or
2974 * ECONNABORTED.
2975 */
2976 int
2977 refresh_vertex(graph_vertex_t *v, scf_instance_t *inst)
2978 {
2979 int err;
2980 int *path;
2981 char *fmri;
2982 int r;
2983 scf_handle_t *h = scf_instance_handle(inst);
2984 uu_list_t *old_deps;
2985 int ret = 0;
2986 graph_edge_t *e;
2987 graph_vertex_t *vv;
2988
2989 assert(MUTEX_HELD(&dgraph_lock));
2990 assert(v->gv_type == GVT_INST);
2991
2992 log_framework(LOG_DEBUG, "Graph engine: Refreshing %s.\n", v->gv_name);
2993
2994 if (milestone > MILESTONE_NONE) {
2995 /*
2996 * In case some of v's dependencies are being deleted we must
2997 * make a list of them now for GV_INSUBGRAPH-flag evaluation
2998 * after the new dependencies are in place.
2999 */
3000 old_deps = startd_list_create(graph_edge_pool, NULL, 0);
3001
3002 err = uu_list_walk(v->gv_dependencies,
3003 (uu_walk_fn_t *)append_svcs_or_insts, old_deps, 0);
3004 assert(err == 0);
3005 }
3006
3007 delete_instance_dependencies(v, B_FALSE);
3008
3009 err = set_dependencies(v, inst, &path);
3010 switch (err) {
3011 case 0:
3012 break;
3013
3014 case ECONNABORTED:
3015 ret = err;
3016 goto out;
3017
3018 case EINVAL:
3019 case ELOOP:
3020 r = libscf_instance_get_fmri(inst, &fmri);
3021 switch (r) {
3022 case 0:
3023 break;
3024
3025 case ECONNABORTED:
3026 ret = ECONNABORTED;
3027 goto out;
3028
3029 case ECANCELED:
3030 ret = 0;
3031 goto out;
3032
3033 default:
3034 bad_error("libscf_instance_get_fmri", r);
3035 }
3036
3037 if (err == EINVAL) {
3038 log_error(LOG_ERR, "Transitioning %s "
3039 "to maintenance due to misconfiguration.\n",
3040 fmri ? fmri : "?");
3041 vertex_send_event(v,
3042 RESTARTER_EVENT_TYPE_INVALID_DEPENDENCY);
3043 } else {
3044 handle_cycle(fmri, path);
3045 vertex_send_event(v,
3046 RESTARTER_EVENT_TYPE_DEPENDENCY_CYCLE);
3047 }
3048 startd_free(fmri, max_scf_fmri_size);
3049 ret = 0;
3050 goto out;
3051
3052 default:
3053 bad_error("set_dependencies", err);
3054 }
3055
3056 if (milestone > MILESTONE_NONE) {
3057 boolean_t aborted = B_FALSE;
3058
3059 for (e = uu_list_first(old_deps);
3060 e != NULL;
3061 e = uu_list_next(old_deps, e)) {
3062 vv = e->ge_vertex;
3063
3064 if (vertex_unref(vv) == VERTEX_INUSE &&
3065 eval_subgraph(vv, h) == ECONNABORTED)
3066 aborted = B_TRUE;
3067 }
3068
3069 for (e = uu_list_first(v->gv_dependencies);
3070 e != NULL;
3071 e = uu_list_next(v->gv_dependencies, e)) {
3072 if (eval_subgraph(e->ge_vertex, h) ==
3073 ECONNABORTED)
3074 aborted = B_TRUE;
3075 }
3076
3077 if (aborted) {
3078 ret = ECONNABORTED;
3079 goto out;
3080 }
3081 }
3082
3083 graph_start_if_satisfied(v);
3084
3085 ret = 0;
3086
3087 out:
3088 if (milestone > MILESTONE_NONE) {
3089 void *cookie = NULL;
3090
3091 while ((e = uu_list_teardown(old_deps, &cookie)) != NULL)
3092 startd_free(e, sizeof (*e));
3093
3094 uu_list_destroy(old_deps);
3095 }
3096
3097 return (ret);
3098 }
3099
3100 /*
3101 * Set up v according to inst. That is, make sure it depends on its
3102 * restarter and set up its dependencies. Send the ADD_INSTANCE command to
3103 * the restarter, and send ENABLE or DISABLE as appropriate.
3104 *
3105 * Returns 0 on success, ECONNABORTED on repository disconnection, or
3106 * ECANCELED if inst is deleted.
3107 */
3108 static int
3109 configure_vertex(graph_vertex_t *v, scf_instance_t *inst)
3110 {
3111 scf_handle_t *h;
3112 scf_propertygroup_t *pg;
3113 scf_snapshot_t *snap;
3114 char *restarter_fmri = startd_alloc(max_scf_value_size);
3115 int enabled, enabled_ovr;
3116 int err;
3117 int *path;
3118 int deathrow;
3119 int32_t tset;
3120
3121 restarter_fmri[0] = '\0';
3122
3123 assert(MUTEX_HELD(&dgraph_lock));
3124 assert(v->gv_type == GVT_INST);
3125 assert((v->gv_flags & GV_CONFIGURED) == 0);
3126
3127 /* GV_INSUBGRAPH should already be set properly. */
3128 assert(should_be_in_subgraph(v) ==
3129 ((v->gv_flags & GV_INSUBGRAPH) != 0));
3130
3131 /*
3132 * If the instance fmri is in the deathrow list then set the
3133 * GV_DEATHROW flag on the vertex and create and set to true the
3134 * SCF_PROPERTY_DEATHROW boolean property in the non-persistent
3135 * repository for this instance fmri.
3136 */
3137 if ((v->gv_flags & GV_DEATHROW) ||
3138 (is_fmri_in_deathrow(v->gv_name) == B_TRUE)) {
3139 if ((v->gv_flags & GV_DEATHROW) == 0) {
3140 /*
3141 * Set flag GV_DEATHROW, create and set to true
3142 * the SCF_PROPERTY_DEATHROW property in the
3143 * non-persistent repository for this instance fmri.
3144 */
3145 v->gv_flags |= GV_DEATHROW;
3146
3147 switch (err = libscf_set_deathrow(inst, 1)) {
3148 case 0:
3149 break;
3150
3151 case ECONNABORTED:
3152 case ECANCELED:
3153 startd_free(restarter_fmri, max_scf_value_size);
3154 return (err);
3155
3156 case EROFS:
3157 log_error(LOG_WARNING, "Could not set %s/%s "
3158 "for deathrow %s: %s.\n",
3159 SCF_PG_DEATHROW, SCF_PROPERTY_DEATHROW,
3160 v->gv_name, strerror(err));
3161 break;
3162
3163 case EPERM:
3164 uu_die("Permission denied.\n");
3165 /* NOTREACHED */
3166
3167 default:
3168 bad_error("libscf_set_deathrow", err);
3169 }
3170 log_framework(LOG_DEBUG, "Deathrow, graph set %s.\n",
3171 v->gv_name);
3172 }
3173 startd_free(restarter_fmri, max_scf_value_size);
3174 return (0);
3175 }
3176
3177 h = scf_instance_handle(inst);
3178
3179 /*
3180 * Using a temporary deathrow boolean property, set through
3181 * libscf_set_deathrow(), only for fmris on deathrow, is necessary
3182 * because deathrow_fini() may already have been called, and in case
3183 * of a refresh, GV_DEATHROW may need to be set again.
3184 * libscf_get_deathrow() sets deathrow to 1 only if this instance
3185 * has a temporary boolean property named 'deathrow' valued true
3186 * in a property group 'deathrow', -1 or 0 in all other cases.
3187 */
3188 err = libscf_get_deathrow(h, inst, &deathrow);
3189 switch (err) {
3190 case 0:
3191 break;
3192
3193 case ECONNABORTED:
3194 case ECANCELED:
3195 startd_free(restarter_fmri, max_scf_value_size);
3196 return (err);
3197
3198 default:
3199 bad_error("libscf_get_deathrow", err);
3200 }
3201
3202 if (deathrow == 1) {
3203 v->gv_flags |= GV_DEATHROW;
3204 startd_free(restarter_fmri, max_scf_value_size);
3205 return (0);
3206 }
3207
3208 log_framework(LOG_DEBUG, "Graph adding %s.\n", v->gv_name);
3209
3210 /*
3211 * If the instance does not have a restarter property group,
3212 * initialize its state to uninitialized/none, in case the restarter
3213 * is not enabled.
3214 */
3215 pg = safe_scf_pg_create(h);
3216
3217 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != 0) {
3218 instance_data_t idata;
3219 uint_t count = 0, msecs = ALLOC_DELAY;
3220
3221 switch (scf_error()) {
3222 case SCF_ERROR_NOT_FOUND:
3223 break;
3224
3225 case SCF_ERROR_CONNECTION_BROKEN:
3226 default:
3227 scf_pg_destroy(pg);
3228 startd_free(restarter_fmri, max_scf_value_size);
3229 return (ECONNABORTED);
3230
3231 case SCF_ERROR_DELETED:
3232 scf_pg_destroy(pg);
3233 startd_free(restarter_fmri, max_scf_value_size);
3234 return (ECANCELED);
3235
3236 case SCF_ERROR_NOT_SET:
3237 bad_error("scf_instance_get_pg", scf_error());
3238 }
3239
3240 switch (err = libscf_instance_get_fmri(inst,
3241 (char **)&idata.i_fmri)) {
3242 case 0:
3243 break;
3244
3245 case ECONNABORTED:
3246 case ECANCELED:
3247 scf_pg_destroy(pg);
3248 startd_free(restarter_fmri, max_scf_value_size);
3249 return (err);
3250
3251 default:
3252 bad_error("libscf_instance_get_fmri", err);
3253 }
3254
3255 idata.i_state = RESTARTER_STATE_NONE;
3256 idata.i_next_state = RESTARTER_STATE_NONE;
3257
3258 init_state:
3259 switch (err = _restarter_commit_states(h, &idata,
3260 RESTARTER_STATE_UNINIT, RESTARTER_STATE_NONE,
3261 restarter_get_str_short(restarter_str_insert_in_graph))) {
3262 case 0:
3263 break;
3264
3265 case ENOMEM:
3266 ++count;
3267 if (count < ALLOC_RETRY) {
3268 (void) poll(NULL, 0, msecs);
3269 msecs *= ALLOC_DELAY_MULT;
3270 goto init_state;
3271 }
3272
3273 uu_die("Insufficient memory.\n");
3274 /* NOTREACHED */
3275
3276 case ECONNABORTED:
3277 startd_free((void *)idata.i_fmri, max_scf_fmri_size);
3278 scf_pg_destroy(pg);
3279 startd_free(restarter_fmri, max_scf_value_size);
3280 return (ECONNABORTED);
3281
3282 case ENOENT:
3283 startd_free((void *)idata.i_fmri, max_scf_fmri_size);
3284 scf_pg_destroy(pg);
3285 startd_free(restarter_fmri, max_scf_value_size);
3286 return (ECANCELED);
3287
3288 case EPERM:
3289 case EACCES:
3290 case EROFS:
3291 log_error(LOG_NOTICE, "Could not initialize state for "
3292 "%s: %s.\n", idata.i_fmri, strerror(err));
3293 break;
3294
3295 case EINVAL:
3296 default:
3297 bad_error("_restarter_commit_states", err);
3298 }
3299
3300 startd_free((void *)idata.i_fmri, max_scf_fmri_size);
3301 }
3302
3303 scf_pg_destroy(pg);
3304
3305 if (milestone != NULL) {
3306 /*
3307 * Make sure the enable-override is set properly before we
3308 * read whether we should be enabled.
3309 */
3310 if (milestone == MILESTONE_NONE ||
3311 !(v->gv_flags & GV_INSUBGRAPH)) {
3312 /*
3313 * This might seem unjustified after the milestone
3314 * transition has completed (non_subgraph_svcs == 0),
3315 * but it's important because when we boot to
3316 * a milestone, we set the milestone before populating
3317 * the graph, and all of the new non-subgraph services
3318 * need to be disabled here.
3319 */
3320 switch (err = libscf_set_enable_ovr(inst, 0)) {
3321 case 0:
3322 break;
3323
3324 case ECONNABORTED:
3325 case ECANCELED:
3326 startd_free(restarter_fmri, max_scf_value_size);
3327 return (err);
3328
3329 case EROFS:
3330 log_error(LOG_WARNING,
3331 "Could not set %s/%s for %s: %s.\n",
3332 SCF_PG_GENERAL_OVR, SCF_PROPERTY_ENABLED,
3333 v->gv_name, strerror(err));
3334 break;
3335
3336 case EPERM:
3337 uu_die("Permission denied.\n");
3338 /* NOTREACHED */
3339
3340 default:
3341 bad_error("libscf_set_enable_ovr", err);
3342 }
3343 } else {
3344 assert(v->gv_flags & GV_INSUBGRAPH);
3345 switch (err = libscf_delete_enable_ovr(inst)) {
3346 case 0:
3347 break;
3348
3349 case ECONNABORTED:
3350 case ECANCELED:
3351 startd_free(restarter_fmri, max_scf_value_size);
3352 return (err);
3353
3354 case EPERM:
3355 uu_die("Permission denied.\n");
3356 /* NOTREACHED */
3357
3358 default:
3359 bad_error("libscf_delete_enable_ovr", err);
3360 }
3361 }
3362 }
3363
3364 err = libscf_get_basic_instance_data(h, inst, v->gv_name, &enabled,
3365 &enabled_ovr, &restarter_fmri);
3366 switch (err) {
3367 case 0:
3368 break;
3369
3370 case ECONNABORTED:
3371 case ECANCELED:
3372 startd_free(restarter_fmri, max_scf_value_size);
3373 return (err);
3374
3375 case ENOENT:
3376 log_framework(LOG_DEBUG,
3377 "Ignoring %s because it has no general property group.\n",
3378 v->gv_name);
3379 startd_free(restarter_fmri, max_scf_value_size);
3380 return (0);
3381
3382 default:
3383 bad_error("libscf_get_basic_instance_data", err);
3384 }
3385
3386 if ((tset = libscf_get_stn_tset(inst)) == -1) {
3387 log_framework(LOG_WARNING,
3388 "Failed to get notification parameters for %s: %s\n",
3389 v->gv_name, scf_strerror(scf_error()));
3390 v->gv_stn_tset = 0;
3391 } else {
3392 v->gv_stn_tset = tset;
3393 }
3394 if (strcmp(v->gv_name, SCF_INSTANCE_GLOBAL) == 0)
3395 stn_global = v->gv_stn_tset;
3396
3397 if (enabled == -1) {
3398 startd_free(restarter_fmri, max_scf_value_size);
3399 return (0);
3400 }
3401
3402 v->gv_flags = (v->gv_flags & ~GV_ENBLD_NOOVR) |
3403 (enabled ? GV_ENBLD_NOOVR : 0);
3404
3405 if (enabled_ovr != -1)
3406 enabled = enabled_ovr;
3407
3408 v->gv_state = RESTARTER_STATE_UNINIT;
3409
3410 snap = libscf_get_or_make_running_snapshot(inst, v->gv_name, B_TRUE);
3411 scf_snapshot_destroy(snap);
3412
3413 /* Set up the restarter. (Sends _ADD_INSTANCE on success.) */
3414 err = graph_change_restarter(v, restarter_fmri, h, &path);
3415 if (err != 0) {
3416 instance_data_t idata;
3417 uint_t count = 0, msecs = ALLOC_DELAY;
3418 restarter_str_t reason;
3419
3420 if (err == ECONNABORTED) {
3421 startd_free(restarter_fmri, max_scf_value_size);
3422 return (err);
3423 }
3424
3425 assert(err == EINVAL || err == ELOOP);
3426
3427 if (err == EINVAL) {
3428 log_framework(LOG_ERR, emsg_invalid_restarter,
3429 v->gv_name, restarter_fmri);
3430 reason = restarter_str_invalid_restarter;
3431 } else {
3432 handle_cycle(v->gv_name, path);
3433 reason = restarter_str_dependency_cycle;
3434 }
3435
3436 startd_free(restarter_fmri, max_scf_value_size);
3437
3438 /*
3439 * We didn't register the instance with the restarter, so we
3440 * must set maintenance mode ourselves.
3441 */
3442 err = libscf_instance_get_fmri(inst, (char **)&idata.i_fmri);
3443 if (err != 0) {
3444 assert(err == ECONNABORTED || err == ECANCELED);
3445 return (err);
3446 }
3447
3448 idata.i_state = RESTARTER_STATE_NONE;
3449 idata.i_next_state = RESTARTER_STATE_NONE;
3450
3451 set_maint:
3452 switch (err = _restarter_commit_states(h, &idata,
3453 RESTARTER_STATE_MAINT, RESTARTER_STATE_NONE,
3454 restarter_get_str_short(reason))) {
3455 case 0:
3456 break;
3457
3458 case ENOMEM:
3459 ++count;
3460 if (count < ALLOC_RETRY) {
3461 (void) poll(NULL, 0, msecs);
3462 msecs *= ALLOC_DELAY_MULT;
3463 goto set_maint;
3464 }
3465
3466 uu_die("Insufficient memory.\n");
3467 /* NOTREACHED */
3468
3469 case ECONNABORTED:
3470 startd_free((void *)idata.i_fmri, max_scf_fmri_size);
3471 return (ECONNABORTED);
3472
3473 case ENOENT:
3474 startd_free((void *)idata.i_fmri, max_scf_fmri_size);
3475 return (ECANCELED);
3476
3477 case EPERM:
3478 case EACCES:
3479 case EROFS:
3480 log_error(LOG_NOTICE, "Could not initialize state for "
3481 "%s: %s.\n", idata.i_fmri, strerror(err));
3482 break;
3483
3484 case EINVAL:
3485 default:
3486 bad_error("_restarter_commit_states", err);
3487 }
3488
3489 startd_free((void *)idata.i_fmri, max_scf_fmri_size);
3490
3491 v->gv_state = RESTARTER_STATE_MAINT;
3492
3493 goto out;
3494 }
3495 startd_free(restarter_fmri, max_scf_value_size);
3496
3497 /* Add all the other dependencies. */
3498 err = refresh_vertex(v, inst);
3499 if (err != 0) {
3500 assert(err == ECONNABORTED);
3501 return (err);
3502 }
3503
3504 out:
3505 v->gv_flags |= GV_CONFIGURED;
3506
3507 graph_enable_by_vertex(v, enabled, 0);
3508
3509 return (0);
3510 }
3511
3512
3513 static void
3514 kill_user_procs(void)
3515 {
3516 (void) fputs("svc.startd: Killing user processes.\n", stdout);
3517
3518 /*
3519 * Despite its name, killall's role is to get select user processes--
3520 * basically those representing terminal-based logins-- to die. Victims
3521 * are located by killall in the utmp database. Since these are most
3522 * often shell based logins, and many shells mask SIGTERM (but are
3523 * responsive to SIGHUP) we first HUP and then shortly thereafter
3524 * kill -9.
3525 */
3526 (void) fork_with_timeout("/usr/sbin/killall HUP", 1, 5);
3527 (void) fork_with_timeout("/usr/sbin/killall KILL", 1, 5);
3528
3529 /*
3530 * Note the selection of user id's 0, 1 and 15, subsequently
3531 * inverted by -v. 15 is reserved for dladmd. Yes, this is a
3532 * kludge-- a better policy is needed.
3533 *
3534 * Note that fork_with_timeout will only wait out the 1 second
3535 * "grace time" if pkill actually returns 0. So if there are
3536 * no matches, this will run to completion much more quickly.
3537 */
3538 (void) fork_with_timeout("/usr/bin/pkill -TERM -v -u 0,1,15", 1, 5);
3539 (void) fork_with_timeout("/usr/bin/pkill -KILL -v -u 0,1,15", 1, 5);
3540 }
3541
3542 static void
3543 do_uadmin(void)
3544 {
3545 const char * const resetting = "/etc/svc/volatile/resetting";
3546 int fd;
3547 struct statvfs vfs;
3548 time_t now;
3549 struct tm nowtm;
3550 char down_buf[256], time_buf[256];
3551 uintptr_t mdep;
3552 #if defined(__x86)
3553 char *fbarg = NULL;
3554 #endif /* __x86 */
3555
3556 mdep = NULL;
3557 fd = creat(resetting, 0777);
3558 if (fd >= 0)
3559 startd_close(fd);
3560 else
3561 uu_warn("Could not create \"%s\"", resetting);
3562
3563 /* Kill dhcpagent if we're not using nfs for root */
3564 if ((statvfs("/", &vfs) == 0) &&
3565 (strncmp(vfs.f_basetype, "nfs", sizeof ("nfs") - 1) != 0))
3566 fork_with_timeout("/usr/bin/pkill -x -u 0 dhcpagent", 0, 5);
3567
3568 /*
3569 * Call sync(2) now, before we kill off user processes. This takes
3570 * advantage of the several seconds of pause we have before the
3571 * killalls are done. Time we can make good use of to get pages
3572 * moving out to disk.
3573 *
3574 * Inside non-global zones, we don't bother, and it's better not to
3575 * anyway, since sync(2) can have system-wide impact.
3576 */
3577 if (getzoneid() == 0)
3578 sync();
3579
3580 kill_user_procs();
3581
3582 /*
3583 * Note that this must come after the killing of user procs, since
3584 * killall relies on utmpx, and this command affects the contents of
3585 * said file.
3586 */
3587 if (access("/usr/lib/acct/closewtmp", X_OK) == 0)
3588 fork_with_timeout("/usr/lib/acct/closewtmp", 0, 5);
3589
3590 /*
3591 * For patches which may be installed as the system is shutting
3592 * down, we need to ensure, one more time, that the boot archive
3593 * really is up to date.
3594 */
3595 if (getzoneid() == 0 && access("/usr/sbin/bootadm", X_OK) == 0)
3596 fork_with_timeout("/usr/sbin/bootadm -ea update_all", 0, 3600);
3597
3598 /*
3599 * Right now, fast reboot is supported only on i386.
3600 * scf_is_fastboot_default() should take care of it.
3601 * If somehow we got there on unsupported platform -
3602 * print warning and fall back to regular reboot.
3603 */
3604 if (halting == AD_FASTREBOOT) {
3605 #if defined(__x86)
3606 if (be_get_boot_args(&fbarg, BE_ENTRY_DEFAULT) == 0) {
3607 mdep = (uintptr_t)fbarg;
3608 } else {
3609 /*
3610 * Failed to read BE info, fall back to normal reboot
3611 */
3612 halting = AD_BOOT;
3613 uu_warn("Failed to get fast reboot arguments.\n"
3614 "Falling back to regular reboot.\n");
3615 }
3616 #else /* __x86 */
3617 halting = AD_BOOT;
3618 uu_warn("Fast reboot configured, but not supported by "
3619 "this ISA\n");
3620 #endif /* __x86 */
3621 }
3622
3623 fork_with_timeout("/sbin/umountall -l", 0, 5);
3624 fork_with_timeout("/sbin/umount /tmp /var/adm /var/run /var "
3625 ">/dev/null 2>&1", 0, 5);
3626
3627 /*
3628 * Try to get to consistency for whatever UFS filesystems are left.
3629 * This is pretty expensive, so we save it for the end in the hopes of
3630 * minimizing what it must do. The other option would be to start in
3631 * parallel with the killall's, but lockfs tends to throw out much more
3632 * than is needed, and so subsequent commands (like umountall) take a
3633 * long time to get going again.
3634 *
3635 * Inside of zones, we don't bother, since we're not about to terminate
3636 * the whole OS instance.
3637 *
3638 * On systems using only ZFS, this call to lockfs -fa is a no-op.
3639 */
3640 if (getzoneid() == 0) {
3641 if (access("/usr/sbin/lockfs", X_OK) == 0)
3642 fork_with_timeout("/usr/sbin/lockfs -fa", 0, 30);
3643
3644 sync(); /* once more, with feeling */
3645 }
3646
3647 fork_with_timeout("/sbin/umount /usr >/dev/null 2>&1", 0, 5);
3648
3649 /*
3650 * Construct and emit the last words from userland:
3651 * "<timestamp> The system is down. Shutdown took <N> seconds."
3652 *
3653 * Normally we'd use syslog, but with /var and other things
3654 * potentially gone, try to minimize the external dependencies.
3655 */
3656 now = time(NULL);
3657 (void) localtime_r(&now, &nowtm);
3658
3659 if (strftime(down_buf, sizeof (down_buf),
3660 "%b %e %T The system is down.", &nowtm) == 0) {
3661 (void) strlcpy(down_buf, "The system is down.",
3662 sizeof (down_buf));
3663 }
3664
3665 if (halting_time != 0 && halting_time <= now) {
3666 (void) snprintf(time_buf, sizeof (time_buf),
3667 " Shutdown took %lu seconds.", now - halting_time);
3668 } else {
3669 time_buf[0] = '\0';
3670 }
3671 (void) printf("%s%s\n", down_buf, time_buf);
3672
3673 (void) uadmin(A_SHUTDOWN, halting, mdep);
3674 uu_warn("uadmin() failed");
3675
3676 #if defined(__x86)
3677 if (halting == AD_FASTREBOOT)
3678 free(fbarg);
3679 #endif /* __x86 */
3680
3681 if (remove(resetting) != 0 && errno != ENOENT)
3682 uu_warn("Could not remove \"%s\"", resetting);
3683 }
3684
3685 /*
3686 * If any of the up_svcs[] are online or satisfiable, return true. If they are
3687 * all missing, disabled, in maintenance, or unsatisfiable, return false.
3688 */
3689 boolean_t
3690 can_come_up(void)
3691 {
3692 int i;
3693
3694 assert(MUTEX_HELD(&dgraph_lock));
3695
3696 /*
3697 * If we are booting to single user (boot -s),
3698 * SCF_MILESTONE_SINGLE_USER is needed to come up because startd
3699 * spawns sulogin after single-user is online (see specials.c).
3700 */
3701 i = (booting_to_single_user ? 0 : 1);
3702
3703 for (; up_svcs[i] != NULL; ++i) {
3704 if (up_svcs_p[i] == NULL) {
3705 up_svcs_p[i] = vertex_get_by_name(up_svcs[i]);
3706
3707 if (up_svcs_p[i] == NULL)
3708 continue;
3709 }
3710
3711 /*
3712 * Ignore unconfigured services (the ones that have been
3713 * mentioned in a dependency from other services, but do
3714 * not exist in the repository). Services which exist
3715 * in the repository but don't have general/enabled
3716 * property will be also ignored.
3717 */
3718 if (!(up_svcs_p[i]->gv_flags & GV_CONFIGURED))
3719 continue;
3720
3721 switch (up_svcs_p[i]->gv_state) {
3722 case RESTARTER_STATE_ONLINE:
3723 case RESTARTER_STATE_DEGRADED:
3724 /*
3725 * Deactivate verbose boot once a login service has been
3726 * reached.
3727 */
3728 st->st_log_login_reached = 1;
3729 /*FALLTHROUGH*/
3730 case RESTARTER_STATE_UNINIT:
3731 return (B_TRUE);
3732
3733 case RESTARTER_STATE_OFFLINE:
3734 if (instance_satisfied(up_svcs_p[i], B_TRUE) != -1)
3735 return (B_TRUE);
3736 log_framework(LOG_DEBUG,
3737 "can_come_up(): %s is unsatisfiable.\n",
3738 up_svcs_p[i]->gv_name);
3739 continue;
3740
3741 case RESTARTER_STATE_DISABLED:
3742 case RESTARTER_STATE_MAINT:
3743 log_framework(LOG_DEBUG,
3744 "can_come_up(): %s is in state %s.\n",
3745 up_svcs_p[i]->gv_name,
3746 instance_state_str[up_svcs_p[i]->gv_state]);
3747 continue;
3748
3749 default:
3750 #ifndef NDEBUG
3751 uu_warn("%s:%d: Unexpected vertex state %d.\n",
3752 __FILE__, __LINE__, up_svcs_p[i]->gv_state);
3753 #endif
3754 abort();
3755 }
3756 }
3757
3758 /*
3759 * In the seed repository, console-login is unsatisfiable because
3760 * services are missing. To behave correctly in that case we don't want
3761 * to return false until manifest-import is online.
3762 */
3763
3764 if (manifest_import_p == NULL) {
3765 manifest_import_p = vertex_get_by_name(manifest_import);
3766
3767 if (manifest_import_p == NULL)
3768 return (B_FALSE);
3769 }
3770
3771 switch (manifest_import_p->gv_state) {
3772 case RESTARTER_STATE_ONLINE:
3773 case RESTARTER_STATE_DEGRADED:
3774 case RESTARTER_STATE_DISABLED:
3775 case RESTARTER_STATE_MAINT:
3776 break;
3777
3778 case RESTARTER_STATE_OFFLINE:
3779 if (instance_satisfied(manifest_import_p, B_TRUE) == -1)
3780 break;
3781 /* FALLTHROUGH */
3782
3783 case RESTARTER_STATE_UNINIT:
3784 return (B_TRUE);
3785 }
3786
3787 return (B_FALSE);
3788 }
3789
3790 /*
3791 * Runs sulogin. Returns
3792 * 0 - success
3793 * EALREADY - sulogin is already running
3794 * EBUSY - console-login is running
3795 */
3796 static int
3797 run_sulogin(const char *msg)
3798 {
3799 graph_vertex_t *v;
3800
3801 assert(MUTEX_HELD(&dgraph_lock));
3802
3803 if (sulogin_running)
3804 return (EALREADY);
3805
3806 v = vertex_get_by_name(console_login_fmri);
3807 if (v != NULL && inst_running(v))
3808 return (EBUSY);
3809
3810 sulogin_running = B_TRUE;
3811
3812 MUTEX_UNLOCK(&dgraph_lock);
3813
3814 fork_sulogin(B_FALSE, msg);
3815
3816 MUTEX_LOCK(&dgraph_lock);
3817
3818 sulogin_running = B_FALSE;
3819
3820 if (console_login_ready) {
3821 v = vertex_get_by_name(console_login_fmri);
3822
3823 if (v != NULL && v->gv_state == RESTARTER_STATE_OFFLINE) {
3824 if (v->gv_start_f == NULL)
3825 vertex_send_event(v,
3826 RESTARTER_EVENT_TYPE_START);
3827 else
3828 v->gv_start_f(v);
3829 }
3830
3831 console_login_ready = B_FALSE;
3832 }
3833
3834 return (0);
3835 }
3836
3837 /*
3838 * The sulogin thread runs sulogin while can_come_up() is false. run_sulogin()
3839 * keeps sulogin from stepping on console-login's toes.
3840 */
3841 /* ARGSUSED */
3842 static void *
3843 sulogin_thread(void *unused)
3844 {
3845 MUTEX_LOCK(&dgraph_lock);
3846
3847 assert(sulogin_thread_running);
3848
3849 do {
3850 (void) run_sulogin("Console login service(s) cannot run\n");
3851 } while (!can_come_up());
3852
3853 sulogin_thread_running = B_FALSE;
3854 MUTEX_UNLOCK(&dgraph_lock);
3855
3856 return (NULL);
3857 }
3858
3859 /* ARGSUSED */
3860 void *
3861 single_user_thread(void *unused)
3862 {
3863 uint_t left;
3864 scf_handle_t *h;
3865 scf_instance_t *inst;
3866 scf_property_t *prop;
3867 scf_value_t *val;
3868 const char *msg;
3869 char *buf;
3870 int r;
3871
3872 MUTEX_LOCK(&single_user_thread_lock);
3873 single_user_thread_count++;
3874
3875 if (!booting_to_single_user)
3876 kill_user_procs();
3877
3878 if (go_single_user_mode || booting_to_single_user) {
3879 msg = "SINGLE USER MODE\n";
3880 } else {
3881 assert(go_to_level1);
3882
3883 fork_rc_script('1', "start", B_TRUE);
3884
3885 uu_warn("The system is ready for administration.\n");
3886
3887 msg = "";
3888 }
3889
3890 MUTEX_UNLOCK(&single_user_thread_lock);
3891
3892 for (;;) {
3893 MUTEX_LOCK(&dgraph_lock);
3894 r = run_sulogin(msg);
3895 MUTEX_UNLOCK(&dgraph_lock);
3896 if (r == 0)
3897 break;
3898
3899 assert(r == EALREADY || r == EBUSY);
3900
3901 left = 3;
3902 while (left > 0)
3903 left = sleep(left);
3904 }
3905
3906 MUTEX_LOCK(&single_user_thread_lock);
3907
3908 /*
3909 * If another single user thread has started, let it finish changing
3910 * the run level.
3911 */
3912 if (single_user_thread_count > 1) {
3913 single_user_thread_count--;
3914 MUTEX_UNLOCK(&single_user_thread_lock);
3915 return (NULL);
3916 }
3917
3918 h = libscf_handle_create_bound_loop();
3919 inst = scf_instance_create(h);
3920 prop = safe_scf_property_create(h);
3921 val = safe_scf_value_create(h);
3922 buf = startd_alloc(max_scf_fmri_size);
3923
3924 lookup:
3925 if (scf_handle_decode_fmri(h, SCF_SERVICE_STARTD, NULL, NULL, inst,
3926 NULL, NULL, SCF_DECODE_FMRI_EXACT) != 0) {
3927 switch (scf_error()) {
3928 case SCF_ERROR_NOT_FOUND:
3929 r = libscf_create_self(h);
3930 if (r == 0)
3931 goto lookup;
3932 assert(r == ECONNABORTED);
3933 /* FALLTHROUGH */
3934
3935 case SCF_ERROR_CONNECTION_BROKEN:
3936 libscf_handle_rebind(h);
3937 goto lookup;
3938
3939 case SCF_ERROR_INVALID_ARGUMENT:
3940 case SCF_ERROR_CONSTRAINT_VIOLATED:
3941 case SCF_ERROR_NOT_BOUND:
3942 case SCF_ERROR_HANDLE_MISMATCH:
3943 default:
3944 bad_error("scf_handle_decode_fmri", scf_error());
3945 }
3946 }
3947
3948 MUTEX_LOCK(&dgraph_lock);
3949
3950 r = scf_instance_delete_prop(inst, SCF_PG_OPTIONS_OVR,
3951 SCF_PROPERTY_MILESTONE);
3952 switch (r) {
3953 case 0:
3954 case ECANCELED:
3955 break;
3956
3957 case ECONNABORTED:
3958 MUTEX_UNLOCK(&dgraph_lock);
3959 libscf_handle_rebind(h);
3960 goto lookup;
3961
3962 case EPERM:
3963 case EACCES:
3964 case EROFS:
3965 log_error(LOG_WARNING, "Could not clear temporary milestone: "
3966 "%s.\n", strerror(r));
3967 break;
3968
3969 default:
3970 bad_error("scf_instance_delete_prop", r);
3971 }
3972
3973 MUTEX_UNLOCK(&dgraph_lock);
3974
3975 r = libscf_get_milestone(inst, prop, val, buf, max_scf_fmri_size);
3976 switch (r) {
3977 case ECANCELED:
3978 case ENOENT:
3979 case EINVAL:
3980 (void) strcpy(buf, "all");
3981 /* FALLTHROUGH */
3982
3983 case 0:
3984 uu_warn("Returning to milestone %s.\n", buf);
3985 break;
3986
3987 case ECONNABORTED:
3988 libscf_handle_rebind(h);
3989 goto lookup;
3990
3991 default:
3992 bad_error("libscf_get_milestone", r);
3993 }
3994
3995 r = dgraph_set_milestone(buf, h, B_FALSE);
3996 switch (r) {
3997 case 0:
3998 case ECONNRESET:
3999 case EALREADY:
4000 case EINVAL:
4001 case ENOENT:
4002 break;
4003
4004 default:
4005 bad_error("dgraph_set_milestone", r);
4006 }
4007
4008 /*
4009 * See graph_runlevel_changed().
4010 */
4011 MUTEX_LOCK(&dgraph_lock);
4012 utmpx_set_runlevel(target_milestone_as_runlevel(), 'S', B_TRUE);
4013 MUTEX_UNLOCK(&dgraph_lock);
4014
4015 startd_free(buf, max_scf_fmri_size);
4016 scf_value_destroy(val);
4017 scf_property_destroy(prop);
4018 scf_instance_destroy(inst);
4019 scf_handle_destroy(h);
4020
4021 /*
4022 * We'll give ourselves 3 seconds to respond to all of the enablings
4023 * that setting the milestone should have created before checking
4024 * whether to run sulogin.
4025 */
4026 left = 3;
4027 while (left > 0)
4028 left = sleep(left);
4029
4030 MUTEX_LOCK(&dgraph_lock);
4031 /*
4032 * Clearing these variables will allow the sulogin thread to run. We
4033 * check here in case there aren't any more state updates anytime soon.
4034 */
4035 go_to_level1 = go_single_user_mode = booting_to_single_user = B_FALSE;
4036 if (!sulogin_thread_running && !can_come_up()) {
4037 (void) startd_thread_create(sulogin_thread, NULL);
4038 sulogin_thread_running = B_TRUE;
4039 }
4040 MUTEX_UNLOCK(&dgraph_lock);
4041 single_user_thread_count--;
4042 MUTEX_UNLOCK(&single_user_thread_lock);
4043 return (NULL);
4044 }
4045
4046
4047 /*
4048 * Dependency graph operations API. These are handle-independent thread-safe
4049 * graph manipulation functions which are the entry points for the event
4050 * threads below.
4051 */
4052
4053 /*
4054 * If a configured vertex exists for inst_fmri, return EEXIST. If no vertex
4055 * exists for inst_fmri, add one. Then fetch the restarter from inst, make
4056 * this vertex dependent on it, and send _ADD_INSTANCE to the restarter.
4057 * Fetch whether the instance should be enabled from inst and send _ENABLE or
4058 * _DISABLE as appropriate. Finally rummage through inst's dependency
4059 * property groups and add vertices and edges as appropriate. If anything
4060 * goes wrong after sending _ADD_INSTANCE, send _ADMIN_MAINT_ON to put the
4061 * instance in maintenance. Don't send _START or _STOP until we get a state
4062 * update in case we're being restarted and the service is already running.
4063 *
4064 * To support booting to a milestone, we must also make sure all dependencies
4065 * encountered are configured, if they exist in the repository.
4066 *
4067 * Returns 0 on success, ECONNABORTED on repository disconnection, EINVAL if
4068 * inst_fmri is an invalid (or not canonical) FMRI, ECANCELED if inst is
4069 * deleted, or EEXIST if a configured vertex for inst_fmri already exists.
4070 */
4071 int
4072 dgraph_add_instance(const char *inst_fmri, scf_instance_t *inst,
4073 boolean_t lock_graph)
4074 {
4075 graph_vertex_t *v;
4076 int err;
4077
4078 if (strcmp(inst_fmri, SCF_SERVICE_STARTD) == 0)
4079 return (0);
4080
4081 /* Check for a vertex for inst_fmri. */
4082 if (lock_graph) {
4083 MUTEX_LOCK(&dgraph_lock);
4084 } else {
4085 assert(MUTEX_HELD(&dgraph_lock));
4086 }
4087
4088 v = vertex_get_by_name(inst_fmri);
4089
4090 if (v != NULL) {
4091 assert(v->gv_type == GVT_INST);
4092
4093 if (v->gv_flags & GV_CONFIGURED) {
4094 if (lock_graph)
4095 MUTEX_UNLOCK(&dgraph_lock);
4096 return (EEXIST);
4097 }
4098 } else {
4099 /* Add the vertex. */
4100 err = graph_insert_vertex_unconfigured(inst_fmri, GVT_INST, 0,
4101 RERR_NONE, &v);
4102 if (err != 0) {
4103 assert(err == EINVAL);
4104 if (lock_graph)
4105 MUTEX_UNLOCK(&dgraph_lock);
4106 return (EINVAL);
4107 }
4108 }
4109
4110 err = configure_vertex(v, inst);
4111
4112 if (lock_graph)
4113 MUTEX_UNLOCK(&dgraph_lock);
4114
4115 return (err);
4116 }
4117
4118 /*
4119 * Locate the vertex for this property group's instance. If it doesn't exist
4120 * or is unconfigured, call dgraph_add_instance() & return. Otherwise fetch
4121 * the restarter for the instance, and if it has changed, send
4122 * _REMOVE_INSTANCE to the old restarter, remove the dependency, make sure the
4123 * new restarter has a vertex, add a new dependency, and send _ADD_INSTANCE to
4124 * the new restarter. Then fetch whether the instance should be enabled, and
4125 * if it is different from what we had, or if we changed the restarter, send
4126 * the appropriate _ENABLE or _DISABLE command.
4127 *
4128 * Returns 0 on success, ENOTSUP if the pg's parent is not an instance,
4129 * ECONNABORTED on repository disconnection, ECANCELED if the instance is
4130 * deleted, or -1 if the instance's general property group is deleted or if
4131 * its enabled property is misconfigured.
4132 */
4133 static int
4134 dgraph_update_general(scf_propertygroup_t *pg)
4135 {
4136 scf_handle_t *h;
4137 scf_instance_t *inst;
4138 char *fmri;
4139 char *restarter_fmri;
4140 graph_vertex_t *v;
4141 int err;
4142 int enabled, enabled_ovr;
4143 int oldflags;
4144
4145 /* Find the vertex for this service */
4146 h = scf_pg_handle(pg);
4147
4148 inst = safe_scf_instance_create(h);
4149
4150 if (scf_pg_get_parent_instance(pg, inst) != 0) {
4151 switch (scf_error()) {
4152 case SCF_ERROR_CONSTRAINT_VIOLATED:
4153 return (ENOTSUP);
4154
4155 case SCF_ERROR_CONNECTION_BROKEN:
4156 default:
4157 return (ECONNABORTED);
4158
4159 case SCF_ERROR_DELETED:
4160 return (0);
4161
4162 case SCF_ERROR_NOT_SET:
4163 bad_error("scf_pg_get_parent_instance", scf_error());
4164 }
4165 }
4166
4167 err = libscf_instance_get_fmri(inst, &fmri);
4168 switch (err) {
4169 case 0:
4170 break;
4171
4172 case ECONNABORTED:
4173 scf_instance_destroy(inst);
4174 return (ECONNABORTED);
4175
4176 case ECANCELED:
4177 scf_instance_destroy(inst);
4178 return (0);
4179
4180 default:
4181 bad_error("libscf_instance_get_fmri", err);
4182 }
4183
4184 log_framework(LOG_DEBUG,
4185 "Graph engine: Reloading general properties for %s.\n", fmri);
4186
4187 MUTEX_LOCK(&dgraph_lock);
4188
4189 v = vertex_get_by_name(fmri);
4190 if (v == NULL || !(v->gv_flags & GV_CONFIGURED)) {
4191 /* Will get the up-to-date properties. */
4192 MUTEX_UNLOCK(&dgraph_lock);
4193 err = dgraph_add_instance(fmri, inst, B_TRUE);
4194 startd_free(fmri, max_scf_fmri_size);
4195 scf_instance_destroy(inst);
4196 return (err == ECANCELED ? 0 : err);
4197 }
4198
4199 /* Read enabled & restarter from repository. */
4200 restarter_fmri = startd_alloc(max_scf_value_size);
4201 err = libscf_get_basic_instance_data(h, inst, v->gv_name, &enabled,
4202 &enabled_ovr, &restarter_fmri);
4203 if (err != 0 || enabled == -1) {
4204 MUTEX_UNLOCK(&dgraph_lock);
4205 scf_instance_destroy(inst);
4206 startd_free(fmri, max_scf_fmri_size);
4207
4208 switch (err) {
4209 case ENOENT:
4210 case 0:
4211 startd_free(restarter_fmri, max_scf_value_size);
4212 return (-1);
4213
4214 case ECONNABORTED:
4215 case ECANCELED:
4216 startd_free(restarter_fmri, max_scf_value_size);
4217 return (err);
4218
4219 default:
4220 bad_error("libscf_get_basic_instance_data", err);
4221 }
4222 }
4223
4224 oldflags = v->gv_flags;
4225 v->gv_flags = (v->gv_flags & ~GV_ENBLD_NOOVR) |
4226 (enabled ? GV_ENBLD_NOOVR : 0);
4227
4228 if (enabled_ovr != -1)
4229 enabled = enabled_ovr;
4230
4231 /*
4232 * If GV_ENBLD_NOOVR has changed, then we need to re-evaluate the
4233 * subgraph.
4234 */
4235 if (milestone > MILESTONE_NONE && v->gv_flags != oldflags)
4236 (void) eval_subgraph(v, h);
4237
4238 scf_instance_destroy(inst);
4239
4240 /* Ignore restarter change for now. */
4241
4242 startd_free(restarter_fmri, max_scf_value_size);
4243 startd_free(fmri, max_scf_fmri_size);
4244
4245 /*
4246 * Always send _ENABLE or _DISABLE. We could avoid this if the
4247 * restarter didn't change and the enabled value didn't change, but
4248 * that's not easy to check and improbable anyway, so we'll just do
4249 * this.
4250 */
4251 graph_enable_by_vertex(v, enabled, 1);
4252
4253 MUTEX_UNLOCK(&dgraph_lock);
4254
4255 return (0);
4256 }
4257
4258 /*
4259 * Delete all of the property group dependencies of v, update inst's running
4260 * snapshot, and add the dependencies in the new snapshot. If any of the new
4261 * dependencies would create a cycle, send _ADMIN_MAINT_ON. Otherwise
4262 * reevaluate v's dependencies, send _START or _STOP as appropriate, and do
4263 * the same for v's dependents.
4264 *
4265 * Returns
4266 * 0 - success
4267 * ECONNABORTED - repository connection broken
4268 * ECANCELED - inst was deleted
4269 * EINVAL - inst is invalid (e.g., missing general/enabled)
4270 * -1 - libscf_snapshots_refresh() failed
4271 */
4272 static int
4273 dgraph_refresh_instance(graph_vertex_t *v, scf_instance_t *inst)
4274 {
4275 int r;
4276 int enabled;
4277 int32_t tset;
4278
4279 assert(MUTEX_HELD(&dgraph_lock));
4280 assert(v->gv_type == GVT_INST);
4281
4282 /* Only refresh services with valid general/enabled properties. */
4283 r = libscf_get_basic_instance_data(scf_instance_handle(inst), inst,
4284 v->gv_name, &enabled, NULL, NULL);
4285 switch (r) {
4286 case 0:
4287 break;
4288
4289 case ECONNABORTED:
4290 case ECANCELED:
4291 return (r);
4292
4293 case ENOENT:
4294 log_framework(LOG_DEBUG,
4295 "Ignoring %s because it has no general property group.\n",
4296 v->gv_name);
4297 return (EINVAL);
4298
4299 default:
4300 bad_error("libscf_get_basic_instance_data", r);
4301 }
4302
4303 if ((tset = libscf_get_stn_tset(inst)) == -1) {
4304 log_framework(LOG_WARNING,
4305 "Failed to get notification parameters for %s: %s\n",
4306 v->gv_name, scf_strerror(scf_error()));
4307 tset = 0;
4308 }
4309 v->gv_stn_tset = tset;
4310 if (strcmp(v->gv_name, SCF_INSTANCE_GLOBAL) == 0)
4311 stn_global = tset;
4312
4313 if (enabled == -1)
4314 return (EINVAL);
4315
4316 r = libscf_snapshots_refresh(inst, v->gv_name);
4317 if (r != 0) {
4318 if (r != -1)
4319 bad_error("libscf_snapshots_refresh", r);
4320
4321 /* error logged */
4322 return (r);
4323 }
4324
4325 r = refresh_vertex(v, inst);
4326 if (r != 0 && r != ECONNABORTED)
4327 bad_error("refresh_vertex", r);
4328 return (r);
4329 }
4330
4331 /*
4332 * Returns true only if none of this service's dependents are 'up' -- online
4333 * or degraded (offline is considered down in this situation). This function
4334 * is somehow similar to is_nonsubgraph_leaf() but works on subtrees.
4335 */
4336 static boolean_t
4337 insubtree_dependents_down(graph_vertex_t *v)
4338 {
4339 graph_vertex_t *vv;
4340 graph_edge_t *e;
4341
4342 assert(MUTEX_HELD(&dgraph_lock));
4343
4344 for (e = uu_list_first(v->gv_dependents); e != NULL;
4345 e = uu_list_next(v->gv_dependents, e)) {
4346 vv = e->ge_vertex;
4347 if (vv->gv_type == GVT_INST) {
4348 if ((vv->gv_flags & GV_CONFIGURED) == 0)
4349 continue;
4350
4351 if ((vv->gv_flags & GV_TOOFFLINE) == 0)
4352 continue;
4353
4354 if ((vv->gv_state == RESTARTER_STATE_ONLINE) ||
4355 (vv->gv_state == RESTARTER_STATE_DEGRADED))
4356 return (B_FALSE);
4357 } else {
4358 /*
4359 * Skip all excluded dependents and decide whether
4360 * to offline the service based on the restart_on
4361 * on attribute.
4362 */
4363 if (is_depgrp_bypassed(vv))
4364 continue;
4365
4366 /*
4367 * For dependency groups or service vertices, keep
4368 * traversing to see if instances are running.
4369 */
4370 if (insubtree_dependents_down(vv) == B_FALSE)
4371 return (B_FALSE);
4372 }
4373 }
4374
4375 return (B_TRUE);
4376 }
4377
4378 /*
4379 * Returns true only if none of this service's dependents are 'up' -- online,
4380 * degraded, or offline.
4381 */
4382 static int
4383 is_nonsubgraph_leaf(graph_vertex_t *v)
4384 {
4385 graph_vertex_t *vv;
4386 graph_edge_t *e;
4387
4388 assert(MUTEX_HELD(&dgraph_lock));
4389
4390 for (e = uu_list_first(v->gv_dependents);
4391 e != NULL;
4392 e = uu_list_next(v->gv_dependents, e)) {
4393
4394 vv = e->ge_vertex;
4395 if (vv->gv_type == GVT_INST) {
4396 if ((vv->gv_flags & GV_CONFIGURED) == 0)
4397 continue;
4398
4399 if (vv->gv_flags & GV_INSUBGRAPH)
4400 continue;
4401
4402 if (up_state(vv->gv_state))
4403 return (0);
4404 } else {
4405 /*
4406 * For dependency group or service vertices, keep
4407 * traversing to see if instances are running.
4408 *
4409 * We should skip exclude_all dependencies otherwise
4410 * the vertex will never be considered as a leaf
4411 * if the dependent is offline. The main reason for
4412 * this is that disable_nonsubgraph_leaves() skips
4413 * exclusion dependencies.
4414 */
4415 if (vv->gv_type == GVT_GROUP &&
4416 vv->gv_depgroup == DEPGRP_EXCLUDE_ALL)
4417 continue;
4418
4419 if (!is_nonsubgraph_leaf(vv))
4420 return (0);
4421 }
4422 }
4423
4424 return (1);
4425 }
4426
4427 /*
4428 * Disable v temporarily. Attempt to do this by setting its enabled override
4429 * property in the repository. If that fails, send a _DISABLE command.
4430 * Returns 0 on success and ECONNABORTED if the repository connection is
4431 * broken.
4432 */
4433 static int
4434 disable_service_temporarily(graph_vertex_t *v, scf_handle_t *h)
4435 {
4436 const char * const emsg = "Could not temporarily disable %s because "
4437 "%s. Will stop service anyways. Repository status for the "
4438 "service may be inaccurate.\n";
4439 const char * const emsg_cbroken =
4440 "the repository connection was broken";
4441
4442 scf_instance_t *inst;
4443 int r;
4444
4445 inst = scf_instance_create(h);
4446 if (inst == NULL) {
4447 char buf[100];
4448
4449 (void) snprintf(buf, sizeof (buf),
4450 "scf_instance_create() failed (%s)",
4451 scf_strerror(scf_error()));
4452 log_error(LOG_WARNING, emsg, v->gv_name, buf);
4453
4454 graph_enable_by_vertex(v, 0, 0);
4455 return (0);
4456 }
4457
4458 r = scf_handle_decode_fmri(h, v->gv_name, NULL, NULL, inst,
4459 NULL, NULL, SCF_DECODE_FMRI_EXACT);
4460 if (r != 0) {
4461 switch (scf_error()) {
4462 case SCF_ERROR_CONNECTION_BROKEN:
4463 log_error(LOG_WARNING, emsg, v->gv_name, emsg_cbroken);
4464 graph_enable_by_vertex(v, 0, 0);
4465 return (ECONNABORTED);
4466
4467 case SCF_ERROR_NOT_FOUND:
4468 return (0);
4469
4470 case SCF_ERROR_HANDLE_MISMATCH:
4471 case SCF_ERROR_INVALID_ARGUMENT:
4472 case SCF_ERROR_CONSTRAINT_VIOLATED:
4473 case SCF_ERROR_NOT_BOUND:
4474 default:
4475 bad_error("scf_handle_decode_fmri",
4476 scf_error());
4477 }
4478 }
4479
4480 r = libscf_set_enable_ovr(inst, 0);
4481 switch (r) {
4482 case 0:
4483 scf_instance_destroy(inst);
4484 return (0);
4485
4486 case ECANCELED:
4487 scf_instance_destroy(inst);
4488 return (0);
4489
4490 case ECONNABORTED:
4491 log_error(LOG_WARNING, emsg, v->gv_name, emsg_cbroken);
4492 graph_enable_by_vertex(v, 0, 0);
4493 return (ECONNABORTED);
4494
4495 case EPERM:
4496 log_error(LOG_WARNING, emsg, v->gv_name,
4497 "the repository denied permission");
4498 graph_enable_by_vertex(v, 0, 0);
4499 return (0);
4500
4501 case EROFS:
4502 log_error(LOG_WARNING, emsg, v->gv_name,
4503 "the repository is read-only");
4504 graph_enable_by_vertex(v, 0, 0);
4505 return (0);
4506
4507 default:
4508 bad_error("libscf_set_enable_ovr", r);
4509 /* NOTREACHED */
4510 }
4511 }
4512
4513 /*
4514 * Of the transitive instance dependencies of v, offline those which are
4515 * in the subtree and which are leaves (i.e., have no dependents which are
4516 * "up").
4517 */
4518 void
4519 offline_subtree_leaves(graph_vertex_t *v, void *arg)
4520 {
4521 assert(MUTEX_HELD(&dgraph_lock));
4522
4523 /* If v isn't an instance, recurse on its dependencies. */
4524 if (v->gv_type != GVT_INST) {
4525 graph_walk_dependencies(v, offline_subtree_leaves, arg);
4526 return;
4527 }
4528
4529 /*
4530 * If v is not in the subtree, so should all of its dependencies,
4531 * so do nothing.
4532 */
4533 if ((v->gv_flags & GV_TOOFFLINE) == 0)
4534 return;
4535
4536 /* If v isn't a leaf because it's already down, recurse. */
4537 if (!up_state(v->gv_state)) {
4538 graph_walk_dependencies(v, offline_subtree_leaves, arg);
4539 return;
4540 }
4541
4542 /* if v is a leaf, offline it or disable it if it's the last one */
4543 if (insubtree_dependents_down(v) == B_TRUE) {
4544 if (v->gv_flags & GV_TODISABLE)
4545 vertex_send_event(v,
4546 RESTARTER_EVENT_TYPE_ADMIN_DISABLE);
4547 else
4548 offline_vertex(v);
4549 }
4550 }
4551
4552 void
4553 graph_offline_subtree_leaves(graph_vertex_t *v, void *h)
4554 {
4555 graph_walk_dependencies(v, offline_subtree_leaves, (void *)h);
4556 }
4557
4558
4559 /*
4560 * Of the transitive instance dependencies of v, disable those which are not
4561 * in the subgraph and which are leaves (i.e., have no dependents which are
4562 * "up").
4563 */
4564 static void
4565 disable_nonsubgraph_leaves(graph_vertex_t *v, void *arg)
4566 {
4567 assert(MUTEX_HELD(&dgraph_lock));
4568
4569 /*
4570 * We must skip exclusion dependencies because they are allowed to
4571 * complete dependency cycles. This is correct because A's exclusion
4572 * dependency on B doesn't bear on the order in which they should be
4573 * stopped. Indeed, the exclusion dependency should guarantee that
4574 * they are never online at the same time.
4575 */
4576 if (v->gv_type == GVT_GROUP && v->gv_depgroup == DEPGRP_EXCLUDE_ALL)
4577 return;
4578
4579 /* If v isn't an instance, recurse on its dependencies. */
4580 if (v->gv_type != GVT_INST)
4581 goto recurse;
4582
4583 if ((v->gv_flags & GV_CONFIGURED) == 0)
4584 /*
4585 * Unconfigured instances should have no dependencies, but in
4586 * case they ever get them,
4587 */
4588 goto recurse;
4589
4590 /*
4591 * If v is in the subgraph, so should all of its dependencies, so do
4592 * nothing.
4593 */
4594 if (v->gv_flags & GV_INSUBGRAPH)
4595 return;
4596
4597 /* If v isn't a leaf because it's already down, recurse. */
4598 if (!up_state(v->gv_state))
4599 goto recurse;
4600
4601 /* If v is disabled but not down yet, be patient. */
4602 if ((v->gv_flags & GV_ENABLED) == 0)
4603 return;
4604
4605 /* If v is a leaf, disable it. */
4606 if (is_nonsubgraph_leaf(v))
4607 (void) disable_service_temporarily(v, (scf_handle_t *)arg);
4608
4609 return;
4610
4611 recurse:
4612 graph_walk_dependencies(v, disable_nonsubgraph_leaves, arg);
4613 }
4614
4615 static int
4616 stn_restarter_state(restarter_instance_state_t rstate)
4617 {
4618 static const struct statemap {
4619 restarter_instance_state_t restarter_state;
4620 int scf_state;
4621 } map[] = {
4622 { RESTARTER_STATE_UNINIT, SCF_STATE_UNINIT },
4623 { RESTARTER_STATE_MAINT, SCF_STATE_MAINT },
4624 { RESTARTER_STATE_OFFLINE, SCF_STATE_OFFLINE },
4625 { RESTARTER_STATE_DISABLED, SCF_STATE_DISABLED },
4626 { RESTARTER_STATE_ONLINE, SCF_STATE_ONLINE },
4627 { RESTARTER_STATE_DEGRADED, SCF_STATE_DEGRADED }
4628 };
4629
4630 int i;
4631
4632 for (i = 0; i < sizeof (map) / sizeof (map[0]); i++) {
4633 if (rstate == map[i].restarter_state)
4634 return (map[i].scf_state);
4635 }
4636
4637 return (-1);
4638 }
4639
4640 /*
4641 * State transition counters
4642 * Not incremented atomically - indicative only
4643 */
4644 static uint64_t stev_ct_maint;
4645 static uint64_t stev_ct_hwerr;
4646 static uint64_t stev_ct_service;
4647 static uint64_t stev_ct_global;
4648 static uint64_t stev_ct_noprefs;
4649 static uint64_t stev_ct_from_uninit;
4650 static uint64_t stev_ct_bad_state;
4651 static uint64_t stev_ct_ovr_prefs;
4652
4653 static void
4654 dgraph_state_transition_notify(graph_vertex_t *v,
4655 restarter_instance_state_t old_state, restarter_str_t reason)
4656 {
4657 restarter_instance_state_t new_state = v->gv_state;
4658 int stn_transition, maint;
4659 int from, to;
4660 nvlist_t *attr;
4661 fmev_pri_t pri = FMEV_LOPRI;
4662 int raise = 0;
4663
4664 if ((from = stn_restarter_state(old_state)) == -1 ||
4665 (to = stn_restarter_state(new_state)) == -1) {
4666 stev_ct_bad_state++;
4667 return;
4668 }
4669
4670 stn_transition = from << 16 | to;
4671
4672 maint = (to == SCF_STATE_MAINT || from == SCF_STATE_MAINT);
4673
4674 if (maint) {
4675 /*
4676 * All transitions to/from maintenance state must raise
4677 * an event.
4678 */
4679 raise++;
4680 pri = FMEV_HIPRI;
4681 stev_ct_maint++;
4682 } else if (reason == restarter_str_ct_ev_hwerr) {
4683 /*
4684 * All transitions caused by hardware fault must raise
4685 * an event
4686 */
4687 raise++;
4688 pri = FMEV_HIPRI;
4689 stev_ct_hwerr++;
4690 } else if (stn_transition & v->gv_stn_tset) {
4691 /*
4692 * Specifically enabled event.
4693 */
4694 raise++;
4695 stev_ct_service++;
4696 } else if (from == SCF_STATE_UNINIT) {
4697 /*
4698 * Only raise these if specifically selected above.
4699 */
4700 stev_ct_from_uninit++;
4701 } else if (stn_transition & stn_global &&
4702 (IS_ENABLED(v) == 1 || to == SCF_STATE_DISABLED)) {
4703 raise++;
4704 stev_ct_global++;
4705 } else {
4706 stev_ct_noprefs++;
4707 }
4708
4709 if (info_events_all) {
4710 stev_ct_ovr_prefs++;
4711 raise++;
4712 }
4713 if (!raise)
4714 return;
4715
4716 if (nvlist_alloc(&attr, NV_UNIQUE_NAME, 0) != 0 ||
4717 nvlist_add_string(attr, "fmri", v->gv_name) != 0 ||
4718 nvlist_add_uint32(attr, "reason-version",
4719 restarter_str_version()) || nvlist_add_string(attr, "reason-short",
4720 restarter_get_str_short(reason)) != 0 ||
4721 nvlist_add_string(attr, "reason-long",
4722 restarter_get_str_long(reason)) != 0 ||
4723 nvlist_add_int32(attr, "transition", stn_transition) != 0) {
4724 log_framework(LOG_WARNING,
4725 "FMEV: %s could not create nvlist for transition "
4726 "event: %s\n", v->gv_name, strerror(errno));
4727 nvlist_free(attr);
4728 return;
4729 }
4730
4731 if (fmev_rspublish_nvl(FMEV_RULESET_SMF, "state-transition",
4732 instance_state_str[new_state], pri, attr) != FMEV_SUCCESS) {
4733 log_framework(LOG_DEBUG,
4734 "FMEV: %s failed to publish transition event: %s\n",
4735 v->gv_name, fmev_strerror(fmev_errno));
4736 nvlist_free(attr);
4737 }
4738 }
4739
4740 /*
4741 * Find the vertex for inst_name. If it doesn't exist, return ENOENT.
4742 * Otherwise set its state to state. If the instance has entered a state
4743 * which requires automatic action, take it (Uninitialized: do
4744 * dgraph_refresh_instance() without the snapshot update. Disabled: if the
4745 * instance should be enabled, send _ENABLE. Offline: if the instance should
4746 * be disabled, send _DISABLE, and if its dependencies are satisfied, send
4747 * _START. Online, Degraded: if the instance wasn't running, update its start
4748 * snapshot. Maintenance: no action.)
4749 *
4750 * Also fails with ECONNABORTED, or EINVAL if state is invalid.
4751 */
4752 static int
4753 dgraph_set_instance_state(scf_handle_t *h, const char *inst_name,
4754 protocol_states_t *states)
4755 {
4756 graph_vertex_t *v;
4757 int err = 0;
4758 restarter_instance_state_t old_state;
4759 restarter_instance_state_t state = states->ps_state;
4760 restarter_error_t serr = states->ps_err;
4761
4762 MUTEX_LOCK(&dgraph_lock);
4763
4764 v = vertex_get_by_name(inst_name);
4765 if (v == NULL) {
4766 MUTEX_UNLOCK(&dgraph_lock);
4767 return (ENOENT);
4768 }
4769
4770 assert(v->gv_type == GVT_INST);
4771
4772 switch (state) {
4773 case RESTARTER_STATE_UNINIT:
4774 case RESTARTER_STATE_DISABLED:
4775 case RESTARTER_STATE_OFFLINE:
4776 case RESTARTER_STATE_ONLINE:
4777 case RESTARTER_STATE_DEGRADED:
4778 case RESTARTER_STATE_MAINT:
4779 break;
4780
4781 default:
4782 MUTEX_UNLOCK(&dgraph_lock);
4783 return (EINVAL);
4784 }
4785
4786 log_framework(LOG_DEBUG, "Graph noting %s %s -> %s.\n", v->gv_name,
4787 instance_state_str[v->gv_state], instance_state_str[state]);
4788
4789 old_state = v->gv_state;
4790 v->gv_state = state;
4791
4792 v->gv_reason = states->ps_reason;
4793 err = gt_transition(h, v, serr, old_state);
4794 if (err == 0 && v->gv_state != old_state) {
4795 dgraph_state_transition_notify(v, old_state, states->ps_reason);
4796 }
4797
4798 MUTEX_UNLOCK(&dgraph_lock);
4799 return (err);
4800 }
4801
4802 /*
4803 * Handle state changes during milestone shutdown. See
4804 * dgraph_set_milestone(). If the repository connection is broken,
4805 * ECONNABORTED will be returned, though a _DISABLE command will be sent for
4806 * the vertex anyway.
4807 */
4808 int
4809 vertex_subgraph_dependencies_shutdown(scf_handle_t *h, graph_vertex_t *v,
4810 restarter_instance_state_t old_state)
4811 {
4812 int was_up, now_up;
4813 int ret = 0;
4814
4815 assert(v->gv_type == GVT_INST);
4816
4817 /* Don't care if we're not going to a milestone. */
4818 if (milestone == NULL)
4819 return (0);
4820
4821 /* Don't care if we already finished coming down. */
4822 if (non_subgraph_svcs == 0)
4823 return (0);
4824
4825 /* Don't care if the service is in the subgraph. */
4826 if (v->gv_flags & GV_INSUBGRAPH)
4827 return (0);
4828
4829 /*
4830 * Update non_subgraph_svcs. It is the number of non-subgraph
4831 * services which are in online, degraded, or offline.
4832 */
4833
4834 was_up = up_state(old_state);
4835 now_up = up_state(v->gv_state);
4836
4837 if (!was_up && now_up) {
4838 ++non_subgraph_svcs;
4839 } else if (was_up && !now_up) {
4840 --non_subgraph_svcs;
4841
4842 if (non_subgraph_svcs == 0) {
4843 if (halting != -1) {
4844 do_uadmin();
4845 } else if (go_single_user_mode || go_to_level1) {
4846 (void) startd_thread_create(single_user_thread,
4847 NULL);
4848 }
4849 return (0);
4850 }
4851 }
4852
4853 /* If this service is a leaf, it should be disabled. */
4854 if ((v->gv_flags & GV_ENABLED) && is_nonsubgraph_leaf(v)) {
4855 int r;
4856
4857 r = disable_service_temporarily(v, h);
4858 switch (r) {
4859 case 0:
4860 break;
4861
4862 case ECONNABORTED:
4863 ret = ECONNABORTED;
4864 break;
4865
4866 default:
4867 bad_error("disable_service_temporarily", r);
4868 }
4869 }
4870
4871 /*
4872 * If the service just came down, propagate the disable to the newly
4873 * exposed leaves.
4874 */
4875 if (was_up && !now_up)
4876 graph_walk_dependencies(v, disable_nonsubgraph_leaves,
4877 (void *)h);
4878
4879 return (ret);
4880 }
4881
4882 /*
4883 * Decide whether to start up an sulogin thread after a service is
4884 * finished changing state. Only need to do the full can_come_up()
4885 * evaluation if an instance is changing state, we're not halfway through
4886 * loading the thread, and we aren't shutting down or going to the single
4887 * user milestone.
4888 */
4889 void
4890 graph_transition_sulogin(restarter_instance_state_t state,
4891 restarter_instance_state_t old_state)
4892 {
4893 assert(MUTEX_HELD(&dgraph_lock));
4894
4895 if (state != old_state && st->st_load_complete &&
4896 !go_single_user_mode && !go_to_level1 &&
4897 halting == -1) {
4898 if (!sulogin_thread_running && !can_come_up()) {
4899 (void) startd_thread_create(sulogin_thread, NULL);
4900 sulogin_thread_running = B_TRUE;
4901 }
4902 }
4903 }
4904
4905 /*
4906 * Propagate a start, stop event, or a satisfiability event.
4907 *
4908 * PROPAGATE_START and PROPAGATE_STOP simply propagate the transition event
4909 * to direct dependents. PROPAGATE_SAT propagates a start then walks the
4910 * full dependent graph to check for newly satisfied nodes. This is
4911 * necessary for cases when non-direct dependents may be effected but direct
4912 * dependents may not (e.g. for optional_all evaluations, see the
4913 * propagate_satbility() comments).
4914 *
4915 * PROPAGATE_SAT should be used whenever a non-running service moves into
4916 * a state which can satisfy optional dependencies, like disabled or
4917 * maintenance.
4918 */
4919 void
4920 graph_transition_propagate(graph_vertex_t *v, propagate_event_t type,
4921 restarter_error_t rerr)
4922 {
4923 if (type == PROPAGATE_STOP) {
4924 graph_walk_dependents(v, propagate_stop, (void *)rerr);
4925 } else if (type == PROPAGATE_START || type == PROPAGATE_SAT) {
4926 graph_walk_dependents(v, propagate_start, (void *)RERR_NONE);
4927
4928 if (type == PROPAGATE_SAT)
4929 propagate_satbility(v);
4930 } else {
4931 #ifndef NDEBUG
4932 uu_warn("%s:%d: Unexpected type value %d.\n", __FILE__,
4933 __LINE__, type);
4934 #endif
4935 abort();
4936 }
4937 }
4938
4939 /*
4940 * If a vertex for fmri exists and it is enabled, send _DISABLE to the
4941 * restarter. If it is running, send _STOP. Send _REMOVE_INSTANCE. Delete
4942 * all property group dependencies, and the dependency on the restarter,
4943 * disposing of vertices as appropriate. If other vertices depend on this
4944 * one, mark it unconfigured and return. Otherwise remove the vertex. Always
4945 * returns 0.
4946 */
4947 static int
4948 dgraph_remove_instance(const char *fmri, scf_handle_t *h)
4949 {
4950 graph_vertex_t *v;
4951 graph_edge_t *e;
4952 uu_list_t *old_deps;
4953 int err;
4954
4955 log_framework(LOG_DEBUG, "Graph engine: Removing %s.\n", fmri);
4956
4957 MUTEX_LOCK(&dgraph_lock);
4958
4959 v = vertex_get_by_name(fmri);
4960 if (v == NULL) {
4961 MUTEX_UNLOCK(&dgraph_lock);
4962 return (0);
4963 }
4964
4965 /* Send restarter delete event. */
4966 if (v->gv_flags & GV_CONFIGURED)
4967 graph_unset_restarter(v);
4968
4969 if (milestone > MILESTONE_NONE) {
4970 /*
4971 * Make a list of v's current dependencies so we can
4972 * reevaluate their GV_INSUBGRAPH flags after the dependencies
4973 * are removed.
4974 */
4975 old_deps = startd_list_create(graph_edge_pool, NULL, 0);
4976
4977 err = uu_list_walk(v->gv_dependencies,
4978 (uu_walk_fn_t *)append_svcs_or_insts, old_deps, 0);
4979 assert(err == 0);
4980 }
4981
4982 delete_instance_dependencies(v, B_TRUE);
4983
4984 /*
4985 * Deleting an instance can both satisfy and unsatisfy dependencies,
4986 * depending on their type. First propagate the stop as a RERR_RESTART
4987 * event -- deletion isn't a fault, just a normal stop. This gives
4988 * dependent services the chance to do a clean shutdown. Then, mark
4989 * the service as unconfigured and propagate the start event for the
4990 * optional_all dependencies that might have become satisfied.
4991 */
4992 graph_walk_dependents(v, propagate_stop, (void *)RERR_RESTART);
4993
4994 v->gv_flags &= ~GV_CONFIGURED;
4995 v->gv_flags &= ~GV_DEATHROW;
4996
4997 graph_walk_dependents(v, propagate_start, (void *)RERR_NONE);
4998 propagate_satbility(v);
4999
5000 /*
5001 * If there are no (non-service) dependents, the vertex can be
5002 * completely removed.
5003 */
5004 if (v != milestone && v->gv_refs == 0 &&
5005 uu_list_numnodes(v->gv_dependents) == 1)
5006 remove_inst_vertex(v);
5007
5008 if (milestone > MILESTONE_NONE) {
5009 void *cookie = NULL;
5010
5011 while ((e = uu_list_teardown(old_deps, &cookie)) != NULL) {
5012 v = e->ge_vertex;
5013
5014 if (vertex_unref(v) == VERTEX_INUSE)
5015 while (eval_subgraph(v, h) == ECONNABORTED)
5016 libscf_handle_rebind(h);
5017
5018 startd_free(e, sizeof (*e));
5019 }
5020
5021 uu_list_destroy(old_deps);
5022 }
5023
5024 MUTEX_UNLOCK(&dgraph_lock);
5025
5026 return (0);
5027 }
5028
5029 /*
5030 * Return the eventual (maybe current) milestone in the form of a
5031 * legacy runlevel.
5032 */
5033 static char
5034 target_milestone_as_runlevel()
5035 {
5036 assert(MUTEX_HELD(&dgraph_lock));
5037
5038 if (milestone == NULL)
5039 return ('3');
5040 else if (milestone == MILESTONE_NONE)
5041 return ('0');
5042
5043 if (strcmp(milestone->gv_name, multi_user_fmri) == 0)
5044 return ('2');
5045 else if (strcmp(milestone->gv_name, single_user_fmri) == 0)
5046 return ('S');
5047 else if (strcmp(milestone->gv_name, multi_user_svr_fmri) == 0)
5048 return ('3');
5049
5050 #ifndef NDEBUG
5051 (void) fprintf(stderr, "%s:%d: Unknown milestone name \"%s\".\n",
5052 __FILE__, __LINE__, milestone->gv_name);
5053 #endif
5054 abort();
5055 /* NOTREACHED */
5056 }
5057
5058 static struct {
5059 char rl;
5060 int sig;
5061 } init_sigs[] = {
5062 { 'S', SIGBUS },
5063 { '0', SIGINT },
5064 { '1', SIGQUIT },
5065 { '2', SIGILL },
5066 { '3', SIGTRAP },
5067 { '4', SIGIOT },
5068 { '5', SIGEMT },
5069 { '6', SIGFPE },
5070 { 0, 0 }
5071 };
5072
5073 static void
5074 signal_init(char rl)
5075 {
5076 pid_t init_pid;
5077 int i;
5078
5079 assert(MUTEX_HELD(&dgraph_lock));
5080
5081 if (zone_getattr(getzoneid(), ZONE_ATTR_INITPID, &init_pid,
5082 sizeof (init_pid)) != sizeof (init_pid)) {
5083 log_error(LOG_NOTICE, "Could not get pid to signal init.\n");
5084 return;
5085 }
5086
5087 for (i = 0; init_sigs[i].rl != 0; ++i)
5088 if (init_sigs[i].rl == rl)
5089 break;
5090
5091 if (init_sigs[i].rl != 0) {
5092 if (kill(init_pid, init_sigs[i].sig) != 0) {
5093 switch (errno) {
5094 case EPERM:
5095 case ESRCH:
5096 log_error(LOG_NOTICE, "Could not signal init: "
5097 "%s.\n", strerror(errno));
5098 break;
5099
5100 case EINVAL:
5101 default:
5102 bad_error("kill", errno);
5103 }
5104 }
5105 }
5106 }
5107
5108 /*
5109 * This is called when one of the major milestones changes state, or when
5110 * init is signalled and tells us it was told to change runlevel. We wait
5111 * to reach the milestone because this allows /etc/inittab entries to retain
5112 * some boot ordering: historically, entries could place themselves before/after
5113 * the running of /sbin/rcX scripts but we can no longer make the
5114 * distinction because the /sbin/rcX scripts no longer exist as punctuation
5115 * marks in /etc/inittab.
5116 *
5117 * Also, we only trigger an update when we reach the eventual target
5118 * milestone: without this, an /etc/inittab entry marked only for
5119 * runlevel 2 would be executed for runlevel 3, which is not how
5120 * /etc/inittab entries work.
5121 *
5122 * If we're single user coming online, then we set utmpx to the target
5123 * runlevel so that legacy scripts can work as expected.
5124 */
5125 static void
5126 graph_runlevel_changed(char rl, int online)
5127 {
5128 char trl;
5129
5130 assert(MUTEX_HELD(&dgraph_lock));
5131
5132 trl = target_milestone_as_runlevel();
5133
5134 if (online) {
5135 if (rl == trl) {
5136 current_runlevel = trl;
5137 signal_init(trl);
5138 } else if (rl == 'S') {
5139 /*
5140 * At boot, set the entry early for the benefit of the
5141 * legacy init scripts.
5142 */
5143 utmpx_set_runlevel(trl, 'S', B_FALSE);
5144 }
5145 } else {
5146 if (rl == '3' && trl == '2') {
5147 current_runlevel = trl;
5148 signal_init(trl);
5149 } else if (rl == '2' && trl == 'S') {
5150 current_runlevel = trl;
5151 signal_init(trl);
5152 }
5153 }
5154 }
5155
5156 /*
5157 * Move to a backwards-compatible runlevel by executing the appropriate
5158 * /etc/rc?.d/K* scripts and/or setting the milestone.
5159 *
5160 * Returns
5161 * 0 - success
5162 * ECONNRESET - success, but handle was reset
5163 * ECONNABORTED - repository connection broken
5164 * ECANCELED - pg was deleted
5165 */
5166 static int
5167 dgraph_set_runlevel(scf_propertygroup_t *pg, scf_property_t *prop)
5168 {
5169 char rl;
5170 scf_handle_t *h;
5171 int r;
5172 const char *ms = NULL; /* what to commit as options/milestone */
5173 boolean_t rebound = B_FALSE;
5174 int mark_rl = 0;
5175
5176 const char * const stop = "stop";
5177
5178 r = libscf_extract_runlevel(prop, &rl);
5179 switch (r) {
5180 case 0:
5181 break;
5182
5183 case ECONNABORTED:
5184 case ECANCELED:
5185 return (r);
5186
5187 case EINVAL:
5188 case ENOENT:
5189 log_error(LOG_WARNING, "runlevel property is misconfigured; "
5190 "ignoring.\n");
5191 /* delete the bad property */
5192 goto nolock_out;
5193
5194 default:
5195 bad_error("libscf_extract_runlevel", r);
5196 }
5197
5198 switch (rl) {
5199 case 's':
5200 rl = 'S';
5201 /* FALLTHROUGH */
5202
5203 case 'S':
5204 case '2':
5205 case '3':
5206 /*
5207 * These cases cause a milestone change, so
5208 * graph_runlevel_changed() will eventually deal with
5209 * signalling init.
5210 */
5211 break;
5212
5213 case '0':
5214 case '1':
5215 case '4':
5216 case '5':
5217 case '6':
5218 mark_rl = 1;
5219 break;
5220
5221 default:
5222 log_framework(LOG_NOTICE, "Unknown runlevel '%c'.\n", rl);
5223 ms = NULL;
5224 goto nolock_out;
5225 }
5226
5227 h = scf_pg_handle(pg);
5228
5229 MUTEX_LOCK(&dgraph_lock);
5230
5231 /*
5232 * Since this triggers no milestone changes, force it by hand.
5233 */
5234 if (current_runlevel == '4' && rl == '3')
5235 mark_rl = 1;
5236
5237 /*
5238 * 1. If we are here after an "init X":
5239 *
5240 * init X
5241 * init/lscf_set_runlevel()
5242 * process_pg_event()
5243 * dgraph_set_runlevel()
5244 *
5245 * then we haven't passed through graph_runlevel_changed() yet,
5246 * therefore 'current_runlevel' has not changed for sure but 'rl' has.
5247 * In consequence, if 'rl' is lower than 'current_runlevel', we change
5248 * the system runlevel and execute the appropriate /etc/rc?.d/K* scripts
5249 * past this test.
5250 *
5251 * 2. On the other hand, if we are here after a "svcadm milestone":
5252 *
5253 * svcadm milestone X
5254 * dgraph_set_milestone()
5255 * handle_graph_update_event()
5256 * dgraph_set_instance_state()
5257 * graph_post_X_[online|offline]()
5258 * graph_runlevel_changed()
5259 * signal_init()
5260 * init/lscf_set_runlevel()
5261 * process_pg_event()
5262 * dgraph_set_runlevel()
5263 *
5264 * then we already passed through graph_runlevel_changed() (by the way
5265 * of dgraph_set_milestone()) and 'current_runlevel' may have changed
5266 * and already be equal to 'rl' so we are going to return immediately
5267 * from dgraph_set_runlevel() without changing the system runlevel and
5268 * without executing the /etc/rc?.d/K* scripts.
5269 */
5270 if (rl == current_runlevel) {
5271 ms = NULL;
5272 goto out;
5273 }
5274
5275 log_framework(LOG_DEBUG, "Changing to runlevel '%c'.\n", rl);
5276
5277 /*
5278 * Make sure stop rc scripts see the new settings via who -r.
5279 */
5280 utmpx_set_runlevel(rl, current_runlevel, B_TRUE);
5281
5282 /*
5283 * Some run levels don't have a direct correspondence to any
5284 * milestones, so we have to signal init directly.
5285 */
5286 if (mark_rl) {
5287 current_runlevel = rl;
5288 signal_init(rl);
5289 }
5290
5291 switch (rl) {
5292 case 'S':
5293 uu_warn("The system is coming down for administration. "
5294 "Please wait.\n");
5295 fork_rc_script(rl, stop, B_FALSE);
5296 ms = single_user_fmri;
5297 go_single_user_mode = B_TRUE;
5298 break;
5299
5300 case '0':
5301 halting_time = time(NULL);
5302 fork_rc_script(rl, stop, B_TRUE);
5303 halting = AD_HALT;
5304 goto uadmin;
5305
5306 case '5':
5307 halting_time = time(NULL);
5308 fork_rc_script(rl, stop, B_TRUE);
5309 halting = AD_POWEROFF;
5310 goto uadmin;
5311
5312 case '6':
5313 halting_time = time(NULL);
5314 fork_rc_script(rl, stop, B_TRUE);
5315 if (scf_is_fastboot_default() && getzoneid() == GLOBAL_ZONEID)
5316 halting = AD_FASTREBOOT;
5317 else
5318 halting = AD_BOOT;
5319
5320 uadmin:
5321 uu_warn("The system is coming down. Please wait.\n");
5322 ms = "none";
5323
5324 /*
5325 * We can't wait until all services are offline since this
5326 * thread is responsible for taking them offline. Instead we
5327 * set halting to the second argument for uadmin() and call
5328 * do_uadmin() from dgraph_set_instance_state() when
5329 * appropriate.
5330 */
5331 break;
5332
5333 case '1':
5334 if (current_runlevel != 'S') {
5335 uu_warn("Changing to state 1.\n");
5336 fork_rc_script(rl, stop, B_FALSE);
5337 } else {
5338 uu_warn("The system is coming up for administration. "
5339 "Please wait.\n");
5340 }
5341 ms = single_user_fmri;
5342 go_to_level1 = B_TRUE;
5343 break;
5344
5345 case '2':
5346 if (current_runlevel == '3' || current_runlevel == '4')
5347 fork_rc_script(rl, stop, B_FALSE);
5348 ms = multi_user_fmri;
5349 break;
5350
5351 case '3':
5352 case '4':
5353 ms = "all";
5354 break;
5355
5356 default:
5357 #ifndef NDEBUG
5358 (void) fprintf(stderr, "%s:%d: Uncaught case %d ('%c').\n",
5359 __FILE__, __LINE__, rl, rl);
5360 #endif
5361 abort();
5362 }
5363
5364 out:
5365 MUTEX_UNLOCK(&dgraph_lock);
5366
5367 nolock_out:
5368 switch (r = libscf_clear_runlevel(pg, ms)) {
5369 case 0:
5370 break;
5371
5372 case ECONNABORTED:
5373 libscf_handle_rebind(h);
5374 rebound = B_TRUE;
5375 goto nolock_out;
5376
5377 case ECANCELED:
5378 break;
5379
5380 case EPERM:
5381 case EACCES:
5382 case EROFS:
5383 log_error(LOG_NOTICE, "Could not delete \"%s/%s\" property: "
5384 "%s.\n", SCF_PG_OPTIONS, "runlevel", strerror(r));
5385 break;
5386
5387 default:
5388 bad_error("libscf_clear_runlevel", r);
5389 }
5390
5391 return (rebound ? ECONNRESET : 0);
5392 }
5393
5394 /*
5395 * mark_subtree walks the dependents and add the GV_TOOFFLINE flag
5396 * to the instances that are supposed to go offline during an
5397 * administrative disable operation.
5398 */
5399 static int
5400 mark_subtree(graph_edge_t *e, void *arg)
5401 {
5402 graph_vertex_t *v;
5403 int r;
5404
5405 v = e->ge_vertex;
5406
5407 /* If it's already in the subgraph, skip. */
5408 if (v->gv_flags & GV_TOOFFLINE)
5409 return (UU_WALK_NEXT);
5410
5411 switch (v->gv_type) {
5412 case GVT_INST:
5413 /* If the instance is already disabled, skip it. */
5414 if (!(v->gv_flags & GV_ENABLED))
5415 return (UU_WALK_NEXT);
5416
5417 v->gv_flags |= GV_TOOFFLINE;
5418 log_framework(LOG_DEBUG, "%s added to subtree\n", v->gv_name);
5419 break;
5420 case GVT_GROUP:
5421 /*
5422 * Skip all excluded dependents and decide whether to offline
5423 * the service based on the restart_on attribute.
5424 */
5425 if (is_depgrp_bypassed(v))
5426 return (UU_WALK_NEXT);
5427 break;
5428 }
5429
5430 r = uu_list_walk(v->gv_dependents, (uu_walk_fn_t *)mark_subtree, arg,
5431 0);
5432 assert(r == 0);
5433 return (UU_WALK_NEXT);
5434 }
5435
5436 static int
5437 mark_subgraph(graph_edge_t *e, void *arg)
5438 {
5439 graph_vertex_t *v;
5440 int r;
5441 int optional = (int)arg;
5442
5443 v = e->ge_vertex;
5444
5445 /* If it's already in the subgraph, skip. */
5446 if (v->gv_flags & GV_INSUBGRAPH)
5447 return (UU_WALK_NEXT);
5448
5449 /*
5450 * Keep track if walk has entered an optional dependency group
5451 */
5452 if (v->gv_type == GVT_GROUP && v->gv_depgroup == DEPGRP_OPTIONAL_ALL) {
5453 optional = 1;
5454 }
5455 /*
5456 * Quit if we are in an optional dependency group and the instance
5457 * is disabled
5458 */
5459 if (optional && (v->gv_type == GVT_INST) &&
5460 (!(v->gv_flags & GV_ENBLD_NOOVR)))
5461 return (UU_WALK_NEXT);
5462
5463 v->gv_flags |= GV_INSUBGRAPH;
5464
5465 /* Skip all excluded dependencies. */
5466 if (v->gv_type == GVT_GROUP && v->gv_depgroup == DEPGRP_EXCLUDE_ALL)
5467 return (UU_WALK_NEXT);
5468
5469 r = uu_list_walk(v->gv_dependencies, (uu_walk_fn_t *)mark_subgraph,
5470 (void *)optional, 0);
5471 assert(r == 0);
5472 return (UU_WALK_NEXT);
5473 }
5474
5475 /*
5476 * Bring down all services which are not dependencies of fmri. The
5477 * dependencies of fmri (direct & indirect) will constitute the "subgraph",
5478 * and will have the GV_INSUBGRAPH flag set. The rest must be brought down,
5479 * which means the state is "disabled", "maintenance", or "uninitialized". We
5480 * could consider "offline" to be down, and refrain from sending start
5481 * commands for such services, but that's not strictly necessary, so we'll
5482 * decline to intrude on the state machine. It would probably confuse users
5483 * anyway.
5484 *
5485 * The services should be brought down in reverse-dependency order, so we
5486 * can't do it all at once here. We initiate by override-disabling the leaves
5487 * of the dependency tree -- those services which are up but have no
5488 * dependents which are up. When they come down,
5489 * vertex_subgraph_dependencies_shutdown() will override-disable the newly
5490 * exposed leaves. Perseverance will ensure completion.
5491 *
5492 * Sometimes we need to take action when the transition is complete, like
5493 * start sulogin or halt the system. To tell when we're done, we initialize
5494 * non_subgraph_svcs here to be the number of services which need to come
5495 * down. As each does, we decrement the counter. When it hits zero, we take
5496 * the appropriate action. See vertex_subgraph_dependencies_shutdown().
5497 *
5498 * In case we're coming up, we also remove any enable-overrides for the
5499 * services which are dependencies of fmri.
5500 *
5501 * If norepository is true, the function will not change the repository.
5502 *
5503 * The decision to change the system run level in accordance with the milestone
5504 * is taken in dgraph_set_runlevel().
5505 *
5506 * Returns
5507 * 0 - success
5508 * ECONNRESET - success, but handle was rebound
5509 * EINVAL - fmri is invalid (error is logged)
5510 * EALREADY - the milestone is already set to fmri
5511 * ENOENT - a configured vertex does not exist for fmri (an error is logged)
5512 */
5513 static int
5514 dgraph_set_milestone(const char *fmri, scf_handle_t *h, boolean_t norepository)
5515 {
5516 const char *cfmri, *fs;
5517 graph_vertex_t *nm, *v;
5518 int ret = 0, r;
5519 scf_instance_t *inst;
5520 boolean_t isall, isnone, rebound = B_FALSE;
5521
5522 /* Validate fmri */
5523 isall = (strcmp(fmri, "all") == 0);
5524 isnone = (strcmp(fmri, "none") == 0);
5525
5526 if (!isall && !isnone) {
5527 if (fmri_canonify(fmri, (char **)&cfmri, B_FALSE) == EINVAL)
5528 goto reject;
5529
5530 if (strcmp(cfmri, single_user_fmri) != 0 &&
5531 strcmp(cfmri, multi_user_fmri) != 0 &&
5532 strcmp(cfmri, multi_user_svr_fmri) != 0) {
5533 startd_free((void *)cfmri, max_scf_fmri_size);
5534 reject:
5535 log_framework(LOG_WARNING,
5536 "Rejecting request for invalid milestone \"%s\".\n",
5537 fmri);
5538 return (EINVAL);
5539 }
5540 }
5541
5542 inst = safe_scf_instance_create(h);
5543
5544 MUTEX_LOCK(&dgraph_lock);
5545
5546 if (milestone == NULL) {
5547 if (isall) {
5548 log_framework(LOG_DEBUG,
5549 "Milestone already set to all.\n");
5550 ret = EALREADY;
5551 goto out;
5552 }
5553 } else if (milestone == MILESTONE_NONE) {
5554 if (isnone) {
5555 log_framework(LOG_DEBUG,
5556 "Milestone already set to none.\n");
5557 ret = EALREADY;
5558 goto out;
5559 }
5560 } else {
5561 if (!isall && !isnone &&
5562 strcmp(cfmri, milestone->gv_name) == 0) {
5563 log_framework(LOG_DEBUG,
5564 "Milestone already set to %s.\n", cfmri);
5565 ret = EALREADY;
5566 goto out;
5567 }
5568 }
5569
5570 if (!isall && !isnone) {
5571 nm = vertex_get_by_name(cfmri);
5572 if (nm == NULL || !(nm->gv_flags & GV_CONFIGURED)) {
5573 log_framework(LOG_WARNING, "Cannot set milestone to %s "
5574 "because no such service exists.\n", cfmri);
5575 ret = ENOENT;
5576 goto out;
5577 }
5578 }
5579
5580 log_framework(LOG_DEBUG, "Changing milestone to %s.\n", fmri);
5581
5582 /*
5583 * Set milestone, removing the old one if this was the last reference.
5584 */
5585 if (milestone > MILESTONE_NONE)
5586 (void) vertex_unref(milestone);
5587
5588 if (isall)
5589 milestone = NULL;
5590 else if (isnone)
5591 milestone = MILESTONE_NONE;
5592 else {
5593 milestone = nm;
5594 /* milestone should count as a reference */
5595 vertex_ref(milestone);
5596 }
5597
5598 /* Clear all GV_INSUBGRAPH bits. */
5599 for (v = uu_list_first(dgraph); v != NULL; v = uu_list_next(dgraph, v))
5600 v->gv_flags &= ~GV_INSUBGRAPH;
5601
5602 if (!isall && !isnone) {
5603 /* Set GV_INSUBGRAPH for milestone & descendents. */
5604 milestone->gv_flags |= GV_INSUBGRAPH;
5605
5606 r = uu_list_walk(milestone->gv_dependencies,
5607 (uu_walk_fn_t *)mark_subgraph, NULL, 0);
5608 assert(r == 0);
5609 }
5610
5611 /* Un-override services in the subgraph & override-disable the rest. */
5612 if (norepository)
5613 goto out;
5614
5615 non_subgraph_svcs = 0;
5616 for (v = uu_list_first(dgraph);
5617 v != NULL;
5618 v = uu_list_next(dgraph, v)) {
5619 if (v->gv_type != GVT_INST ||
5620 (v->gv_flags & GV_CONFIGURED) == 0)
5621 continue;
5622
5623 again:
5624 r = scf_handle_decode_fmri(h, v->gv_name, NULL, NULL, inst,
5625 NULL, NULL, SCF_DECODE_FMRI_EXACT);
5626 if (r != 0) {
5627 switch (scf_error()) {
5628 case SCF_ERROR_CONNECTION_BROKEN:
5629 default:
5630 libscf_handle_rebind(h);
5631 rebound = B_TRUE;
5632 goto again;
5633
5634 case SCF_ERROR_NOT_FOUND:
5635 continue;
5636
5637 case SCF_ERROR_HANDLE_MISMATCH:
5638 case SCF_ERROR_INVALID_ARGUMENT:
5639 case SCF_ERROR_CONSTRAINT_VIOLATED:
5640 case SCF_ERROR_NOT_BOUND:
5641 bad_error("scf_handle_decode_fmri",
5642 scf_error());
5643 }
5644 }
5645
5646 if (isall || (v->gv_flags & GV_INSUBGRAPH)) {
5647 r = libscf_delete_enable_ovr(inst);
5648 fs = "libscf_delete_enable_ovr";
5649 } else {
5650 assert(isnone || (v->gv_flags & GV_INSUBGRAPH) == 0);
5651
5652 /*
5653 * Services which are up need to come down before
5654 * we're done, but we can only disable the leaves
5655 * here.
5656 */
5657
5658 if (up_state(v->gv_state))
5659 ++non_subgraph_svcs;
5660
5661 /* If it's already disabled, don't bother. */
5662 if ((v->gv_flags & GV_ENABLED) == 0)
5663 continue;
5664
5665 if (!is_nonsubgraph_leaf(v))
5666 continue;
5667
5668 r = libscf_set_enable_ovr(inst, 0);
5669 fs = "libscf_set_enable_ovr";
5670 }
5671 switch (r) {
5672 case 0:
5673 case ECANCELED:
5674 break;
5675
5676 case ECONNABORTED:
5677 libscf_handle_rebind(h);
5678 rebound = B_TRUE;
5679 goto again;
5680
5681 case EPERM:
5682 case EROFS:
5683 log_error(LOG_WARNING,
5684 "Could not set %s/%s for %s: %s.\n",
5685 SCF_PG_GENERAL_OVR, SCF_PROPERTY_ENABLED,
5686 v->gv_name, strerror(r));
5687 break;
5688
5689 default:
5690 bad_error(fs, r);
5691 }
5692 }
5693
5694 if (halting != -1) {
5695 if (non_subgraph_svcs > 1)
5696 uu_warn("%d system services are now being stopped.\n",
5697 non_subgraph_svcs);
5698 else if (non_subgraph_svcs == 1)
5699 uu_warn("One system service is now being stopped.\n");
5700 else if (non_subgraph_svcs == 0)
5701 do_uadmin();
5702 }
5703
5704 ret = rebound ? ECONNRESET : 0;
5705
5706 out:
5707 MUTEX_UNLOCK(&dgraph_lock);
5708 if (!isall && !isnone)
5709 startd_free((void *)cfmri, max_scf_fmri_size);
5710 scf_instance_destroy(inst);
5711 return (ret);
5712 }
5713
5714
5715 /*
5716 * Returns 0, ECONNABORTED, or EINVAL.
5717 */
5718 static int
5719 handle_graph_update_event(scf_handle_t *h, graph_protocol_event_t *e)
5720 {
5721 int r;
5722
5723 switch (e->gpe_type) {
5724 case GRAPH_UPDATE_RELOAD_GRAPH:
5725 log_error(LOG_WARNING,
5726 "graph_event: reload graph unimplemented\n");
5727 break;
5728
5729 case GRAPH_UPDATE_STATE_CHANGE: {
5730 protocol_states_t *states = e->gpe_data;
5731
5732 switch (r = dgraph_set_instance_state(h, e->gpe_inst, states)) {
5733 case 0:
5734 case ENOENT:
5735 break;
5736
5737 case ECONNABORTED:
5738 return (ECONNABORTED);
5739
5740 case EINVAL:
5741 default:
5742 #ifndef NDEBUG
5743 (void) fprintf(stderr, "dgraph_set_instance_state() "
5744 "failed with unexpected error %d at %s:%d.\n", r,
5745 __FILE__, __LINE__);
5746 #endif
5747 abort();
5748 }
5749
5750 startd_free(states, sizeof (protocol_states_t));
5751 break;
5752 }
5753
5754 default:
5755 log_error(LOG_WARNING,
5756 "graph_event_loop received an unknown event: %d\n",
5757 e->gpe_type);
5758 break;
5759 }
5760
5761 return (0);
5762 }
5763
5764 /*
5765 * graph_event_thread()
5766 * Wait for state changes from the restarters.
5767 */
5768 /*ARGSUSED*/
5769 void *
5770 graph_event_thread(void *unused)
5771 {
5772 scf_handle_t *h;
5773 int err;
5774
5775 h = libscf_handle_create_bound_loop();
5776
5777 /*CONSTCOND*/
5778 while (1) {
5779 graph_protocol_event_t *e;
5780
5781 MUTEX_LOCK(&gu->gu_lock);
5782
5783 while (gu->gu_wakeup == 0)
5784 (void) pthread_cond_wait(&gu->gu_cv, &gu->gu_lock);
5785
5786 gu->gu_wakeup = 0;
5787
5788 while ((e = graph_event_dequeue()) != NULL) {
5789 MUTEX_LOCK(&e->gpe_lock);
5790 MUTEX_UNLOCK(&gu->gu_lock);
5791
5792 while ((err = handle_graph_update_event(h, e)) ==
5793 ECONNABORTED)
5794 libscf_handle_rebind(h);
5795
5796 if (err == 0)
5797 graph_event_release(e);
5798 else
5799 graph_event_requeue(e);
5800
5801 MUTEX_LOCK(&gu->gu_lock);
5802 }
5803
5804 MUTEX_UNLOCK(&gu->gu_lock);
5805 }
5806
5807 /*
5808 * Unreachable for now -- there's currently no graceful cleanup
5809 * called on exit().
5810 */
5811 MUTEX_UNLOCK(&gu->gu_lock);
5812 scf_handle_destroy(h);
5813 return (NULL);
5814 }
5815
5816 static void
5817 set_initial_milestone(scf_handle_t *h)
5818 {
5819 scf_instance_t *inst;
5820 char *fmri, *cfmri;
5821 size_t sz;
5822 int r;
5823
5824 inst = safe_scf_instance_create(h);
5825 fmri = startd_alloc(max_scf_fmri_size);
5826
5827 /*
5828 * If -m milestone= was specified, we want to set options_ovr/milestone
5829 * to it. Otherwise we want to read what the milestone should be set
5830 * to. Either way we need our inst.
5831 */
5832 get_self:
5833 if (scf_handle_decode_fmri(h, SCF_SERVICE_STARTD, NULL, NULL, inst,
5834 NULL, NULL, SCF_DECODE_FMRI_EXACT) != 0) {
5835 switch (scf_error()) {
5836 case SCF_ERROR_CONNECTION_BROKEN:
5837 libscf_handle_rebind(h);
5838 goto get_self;
5839
5840 case SCF_ERROR_NOT_FOUND:
5841 if (st->st_subgraph != NULL &&
5842 st->st_subgraph[0] != '\0') {
5843 sz = strlcpy(fmri, st->st_subgraph,
5844 max_scf_fmri_size);
5845 assert(sz < max_scf_fmri_size);
5846 } else {
5847 fmri[0] = '\0';
5848 }
5849 break;
5850
5851 case SCF_ERROR_INVALID_ARGUMENT:
5852 case SCF_ERROR_CONSTRAINT_VIOLATED:
5853 case SCF_ERROR_HANDLE_MISMATCH:
5854 default:
5855 bad_error("scf_handle_decode_fmri", scf_error());
5856 }
5857 } else {
5858 if (st->st_subgraph != NULL && st->st_subgraph[0] != '\0') {
5859 scf_propertygroup_t *pg;
5860
5861 pg = safe_scf_pg_create(h);
5862
5863 sz = strlcpy(fmri, st->st_subgraph, max_scf_fmri_size);
5864 assert(sz < max_scf_fmri_size);
5865
5866 r = libscf_inst_get_or_add_pg(inst, SCF_PG_OPTIONS_OVR,
5867 SCF_PG_OPTIONS_OVR_TYPE, SCF_PG_OPTIONS_OVR_FLAGS,
5868 pg);
5869 switch (r) {
5870 case 0:
5871 break;
5872
5873 case ECONNABORTED:
5874 libscf_handle_rebind(h);
5875 goto get_self;
5876
5877 case EPERM:
5878 case EACCES:
5879 case EROFS:
5880 log_error(LOG_WARNING, "Could not set %s/%s: "
5881 "%s.\n", SCF_PG_OPTIONS_OVR,
5882 SCF_PROPERTY_MILESTONE, strerror(r));
5883 /* FALLTHROUGH */
5884
5885 case ECANCELED:
5886 sz = strlcpy(fmri, st->st_subgraph,
5887 max_scf_fmri_size);
5888 assert(sz < max_scf_fmri_size);
5889 break;
5890
5891 default:
5892 bad_error("libscf_inst_get_or_add_pg", r);
5893 }
5894
5895 r = libscf_clear_runlevel(pg, fmri);
5896 switch (r) {
5897 case 0:
5898 break;
5899
5900 case ECONNABORTED:
5901 libscf_handle_rebind(h);
5902 goto get_self;
5903
5904 case EPERM:
5905 case EACCES:
5906 case EROFS:
5907 log_error(LOG_WARNING, "Could not set %s/%s: "
5908 "%s.\n", SCF_PG_OPTIONS_OVR,
5909 SCF_PROPERTY_MILESTONE, strerror(r));
5910 /* FALLTHROUGH */
5911
5912 case ECANCELED:
5913 sz = strlcpy(fmri, st->st_subgraph,
5914 max_scf_fmri_size);
5915 assert(sz < max_scf_fmri_size);
5916 break;
5917
5918 default:
5919 bad_error("libscf_clear_runlevel", r);
5920 }
5921
5922 scf_pg_destroy(pg);
5923 } else {
5924 scf_property_t *prop;
5925 scf_value_t *val;
5926
5927 prop = safe_scf_property_create(h);
5928 val = safe_scf_value_create(h);
5929
5930 r = libscf_get_milestone(inst, prop, val, fmri,
5931 max_scf_fmri_size);
5932 switch (r) {
5933 case 0:
5934 break;
5935
5936 case ECONNABORTED:
5937 libscf_handle_rebind(h);
5938 goto get_self;
5939
5940 case EINVAL:
5941 log_error(LOG_WARNING, "Milestone property is "
5942 "misconfigured. Defaulting to \"all\".\n");
5943 /* FALLTHROUGH */
5944
5945 case ECANCELED:
5946 case ENOENT:
5947 fmri[0] = '\0';
5948 break;
5949
5950 default:
5951 bad_error("libscf_get_milestone", r);
5952 }
5953
5954 scf_value_destroy(val);
5955 scf_property_destroy(prop);
5956 }
5957 }
5958
5959 if (fmri[0] == '\0' || strcmp(fmri, "all") == 0)
5960 goto out;
5961
5962 if (strcmp(fmri, "none") != 0) {
5963 retry:
5964 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
5965 NULL, SCF_DECODE_FMRI_EXACT) != 0) {
5966 switch (scf_error()) {
5967 case SCF_ERROR_INVALID_ARGUMENT:
5968 log_error(LOG_WARNING,
5969 "Requested milestone \"%s\" is invalid. "
5970 "Reverting to \"all\".\n", fmri);
5971 goto out;
5972
5973 case SCF_ERROR_CONSTRAINT_VIOLATED:
5974 log_error(LOG_WARNING, "Requested milestone "
5975 "\"%s\" does not specify an instance. "
5976 "Reverting to \"all\".\n", fmri);
5977 goto out;
5978
5979 case SCF_ERROR_CONNECTION_BROKEN:
5980 libscf_handle_rebind(h);
5981 goto retry;
5982
5983 case SCF_ERROR_NOT_FOUND:
5984 log_error(LOG_WARNING, "Requested milestone "
5985 "\"%s\" not in repository. Reverting to "
5986 "\"all\".\n", fmri);
5987 goto out;
5988
5989 case SCF_ERROR_HANDLE_MISMATCH:
5990 default:
5991 bad_error("scf_handle_decode_fmri",
5992 scf_error());
5993 }
5994 }
5995
5996 r = fmri_canonify(fmri, &cfmri, B_FALSE);
5997 assert(r == 0);
5998
5999 r = dgraph_add_instance(cfmri, inst, B_TRUE);
6000 startd_free(cfmri, max_scf_fmri_size);
6001 switch (r) {
6002 case 0:
6003 break;
6004
6005 case ECONNABORTED:
6006 goto retry;
6007
6008 case EINVAL:
6009 log_error(LOG_WARNING,
6010 "Requested milestone \"%s\" is invalid. "
6011 "Reverting to \"all\".\n", fmri);
6012 goto out;
6013
6014 case ECANCELED:
6015 log_error(LOG_WARNING,
6016 "Requested milestone \"%s\" not "
6017 "in repository. Reverting to \"all\".\n",
6018 fmri);
6019 goto out;
6020
6021 case EEXIST:
6022 default:
6023 bad_error("dgraph_add_instance", r);
6024 }
6025 }
6026
6027 log_console(LOG_INFO, "Booting to milestone \"%s\".\n", fmri);
6028
6029 r = dgraph_set_milestone(fmri, h, B_FALSE);
6030 switch (r) {
6031 case 0:
6032 case ECONNRESET:
6033 case EALREADY:
6034 break;
6035
6036 case EINVAL:
6037 case ENOENT:
6038 default:
6039 bad_error("dgraph_set_milestone", r);
6040 }
6041
6042 out:
6043 startd_free(fmri, max_scf_fmri_size);
6044 scf_instance_destroy(inst);
6045 }
6046
6047 void
6048 set_restart_milestone(scf_handle_t *h)
6049 {
6050 scf_instance_t *inst;
6051 scf_property_t *prop;
6052 scf_value_t *val;
6053 char *fmri;
6054 int r;
6055
6056 inst = safe_scf_instance_create(h);
6057
6058 get_self:
6059 if (scf_handle_decode_fmri(h, SCF_SERVICE_STARTD, NULL, NULL,
6060 inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != 0) {
6061 switch (scf_error()) {
6062 case SCF_ERROR_CONNECTION_BROKEN:
6063 libscf_handle_rebind(h);
6064 goto get_self;
6065
6066 case SCF_ERROR_NOT_FOUND:
6067 break;
6068
6069 case SCF_ERROR_INVALID_ARGUMENT:
6070 case SCF_ERROR_CONSTRAINT_VIOLATED:
6071 case SCF_ERROR_HANDLE_MISMATCH:
6072 default:
6073 bad_error("scf_handle_decode_fmri", scf_error());
6074 }
6075
6076 scf_instance_destroy(inst);
6077 return;
6078 }
6079
6080 prop = safe_scf_property_create(h);
6081 val = safe_scf_value_create(h);
6082 fmri = startd_alloc(max_scf_fmri_size);
6083
6084 r = libscf_get_milestone(inst, prop, val, fmri, max_scf_fmri_size);
6085 switch (r) {
6086 case 0:
6087 break;
6088
6089 case ECONNABORTED:
6090 libscf_handle_rebind(h);
6091 goto get_self;
6092
6093 case ECANCELED:
6094 case ENOENT:
6095 case EINVAL:
6096 goto out;
6097
6098 default:
6099 bad_error("libscf_get_milestone", r);
6100 }
6101
6102 r = dgraph_set_milestone(fmri, h, B_TRUE);
6103 switch (r) {
6104 case 0:
6105 case ECONNRESET:
6106 case EALREADY:
6107 case EINVAL:
6108 case ENOENT:
6109 break;
6110
6111 default:
6112 bad_error("dgraph_set_milestone", r);
6113 }
6114
6115 out:
6116 startd_free(fmri, max_scf_fmri_size);
6117 scf_value_destroy(val);
6118 scf_property_destroy(prop);
6119 scf_instance_destroy(inst);
6120 }
6121
6122 /*
6123 * void *graph_thread(void *)
6124 *
6125 * Graph management thread.
6126 */
6127 /*ARGSUSED*/
6128 void *
6129 graph_thread(void *arg)
6130 {
6131 scf_handle_t *h;
6132 int err;
6133
6134 h = libscf_handle_create_bound_loop();
6135
6136 if (st->st_initial)
6137 set_initial_milestone(h);
6138
6139 MUTEX_LOCK(&dgraph_lock);
6140 initial_milestone_set = B_TRUE;
6141 err = pthread_cond_broadcast(&initial_milestone_cv);
6142 assert(err == 0);
6143 MUTEX_UNLOCK(&dgraph_lock);
6144
6145 libscf_populate_graph(h);
6146
6147 if (!st->st_initial)
6148 set_restart_milestone(h);
6149
6150 MUTEX_LOCK(&st->st_load_lock);
6151 st->st_load_complete = 1;
6152 (void) pthread_cond_broadcast(&st->st_load_cv);
6153 MUTEX_UNLOCK(&st->st_load_lock);
6154
6155 MUTEX_LOCK(&dgraph_lock);
6156 /*
6157 * Now that we've set st_load_complete we need to check can_come_up()
6158 * since if we booted to a milestone, then there won't be any more
6159 * state updates.
6160 */
6161 if (!go_single_user_mode && !go_to_level1 &&
6162 halting == -1) {
6163 if (!sulogin_thread_running && !can_come_up()) {
6164 (void) startd_thread_create(sulogin_thread, NULL);
6165 sulogin_thread_running = B_TRUE;
6166 }
6167 }
6168 MUTEX_UNLOCK(&dgraph_lock);
6169
6170 (void) pthread_mutex_lock(&gu->gu_freeze_lock);
6171
6172 /*CONSTCOND*/
6173 while (1) {
6174 (void) pthread_cond_wait(&gu->gu_freeze_cv,
6175 &gu->gu_freeze_lock);
6176 }
6177
6178 /*
6179 * Unreachable for now -- there's currently no graceful cleanup
6180 * called on exit().
6181 */
6182 (void) pthread_mutex_unlock(&gu->gu_freeze_lock);
6183 scf_handle_destroy(h);
6184
6185 return (NULL);
6186 }
6187
6188
6189 /*
6190 * int next_action()
6191 * Given an array of timestamps 'a' with 'num' elements, find the
6192 * lowest non-zero timestamp and return its index. If there are no
6193 * non-zero elements, return -1.
6194 */
6195 static int
6196 next_action(hrtime_t *a, int num)
6197 {
6198 hrtime_t t = 0;
6199 int i = 0, smallest = -1;
6200
6201 for (i = 0; i < num; i++) {
6202 if (t == 0) {
6203 t = a[i];
6204 smallest = i;
6205 } else if (a[i] != 0 && a[i] < t) {
6206 t = a[i];
6207 smallest = i;
6208 }
6209 }
6210
6211 if (t == 0)
6212 return (-1);
6213 else
6214 return (smallest);
6215 }
6216
6217 /*
6218 * void process_actions()
6219 * Process actions requested by the administrator. Possibilities include:
6220 * refresh, restart, maintenance mode off, maintenance mode on,
6221 * maintenance mode immediate, and degraded.
6222 *
6223 * The set of pending actions is represented in the repository as a
6224 * per-instance property group, with each action being a single property
6225 * in that group. This property group is converted to an array, with each
6226 * action type having an array slot. The actions in the array at the
6227 * time process_actions() is called are acted on in the order of the
6228 * timestamp (which is the value stored in the slot). A value of zero
6229 * indicates that there is no pending action of the type associated with
6230 * a particular slot.
6231 *
6232 * Sending an action event multiple times before the restarter has a
6233 * chance to process that action will force it to be run at the last
6234 * timestamp where it appears in the ordering.
6235 *
6236 * Turning maintenance mode on trumps all other actions.
6237 *
6238 * Returns 0 or ECONNABORTED.
6239 */
6240 static int
6241 process_actions(scf_handle_t *h, scf_propertygroup_t *pg, scf_instance_t *inst)
6242 {
6243 scf_property_t *prop = NULL;
6244 scf_value_t *val = NULL;
6245 scf_type_t type;
6246 graph_vertex_t *vertex;
6247 admin_action_t a;
6248 int i, ret = 0, r;
6249 hrtime_t action_ts[NACTIONS];
6250 char *inst_name;
6251
6252 r = libscf_instance_get_fmri(inst, &inst_name);
6253 switch (r) {
6254 case 0:
6255 break;
6256
6257 case ECONNABORTED:
6258 return (ECONNABORTED);
6259
6260 case ECANCELED:
6261 return (0);
6262
6263 default:
6264 bad_error("libscf_instance_get_fmri", r);
6265 }
6266
6267 MUTEX_LOCK(&dgraph_lock);
6268
6269 vertex = vertex_get_by_name(inst_name);
6270 if (vertex == NULL) {
6271 MUTEX_UNLOCK(&dgraph_lock);
6272 log_framework(LOG_DEBUG, "%s: Can't find graph vertex. "
6273 "The instance must have been removed.\n", inst_name);
6274 startd_free(inst_name, max_scf_fmri_size);
6275 return (0);
6276 }
6277
6278 prop = safe_scf_property_create(h);
6279 val = safe_scf_value_create(h);
6280
6281 for (i = 0; i < NACTIONS; i++) {
6282 if (scf_pg_get_property(pg, admin_actions[i], prop) != 0) {
6283 switch (scf_error()) {
6284 case SCF_ERROR_CONNECTION_BROKEN:
6285 default:
6286 ret = ECONNABORTED;
6287 goto out;
6288
6289 case SCF_ERROR_DELETED:
6290 goto out;
6291
6292 case SCF_ERROR_NOT_FOUND:
6293 action_ts[i] = 0;
6294 continue;
6295
6296 case SCF_ERROR_HANDLE_MISMATCH:
6297 case SCF_ERROR_INVALID_ARGUMENT:
6298 case SCF_ERROR_NOT_SET:
6299 bad_error("scf_pg_get_property", scf_error());
6300 }
6301 }
6302
6303 if (scf_property_type(prop, &type) != 0) {
6304 switch (scf_error()) {
6305 case SCF_ERROR_CONNECTION_BROKEN:
6306 default:
6307 ret = ECONNABORTED;
6308 goto out;
6309
6310 case SCF_ERROR_DELETED:
6311 action_ts[i] = 0;
6312 continue;
6313
6314 case SCF_ERROR_NOT_SET:
6315 bad_error("scf_property_type", scf_error());
6316 }
6317 }
6318
6319 if (type != SCF_TYPE_INTEGER) {
6320 action_ts[i] = 0;
6321 continue;
6322 }
6323
6324 if (scf_property_get_value(prop, val) != 0) {
6325 switch (scf_error()) {
6326 case SCF_ERROR_CONNECTION_BROKEN:
6327 default:
6328 ret = ECONNABORTED;
6329 goto out;
6330
6331 case SCF_ERROR_DELETED:
6332 goto out;
6333
6334 case SCF_ERROR_NOT_FOUND:
6335 case SCF_ERROR_CONSTRAINT_VIOLATED:
6336 action_ts[i] = 0;
6337 continue;
6338
6339 case SCF_ERROR_NOT_SET:
6340 case SCF_ERROR_PERMISSION_DENIED:
6341 bad_error("scf_property_get_value",
6342 scf_error());
6343 }
6344 }
6345
6346 r = scf_value_get_integer(val, &action_ts[i]);
6347 assert(r == 0);
6348 }
6349
6350 a = ADMIN_EVENT_MAINT_ON_IMMEDIATE;
6351 if (action_ts[ADMIN_EVENT_MAINT_ON_IMMEDIATE] ||
6352 action_ts[ADMIN_EVENT_MAINT_ON]) {
6353 a = action_ts[ADMIN_EVENT_MAINT_ON_IMMEDIATE] ?
6354 ADMIN_EVENT_MAINT_ON_IMMEDIATE : ADMIN_EVENT_MAINT_ON;
6355
6356 vertex_send_event(vertex, admin_events[a]);
6357 r = libscf_unset_action(h, pg, a, action_ts[a]);
6358 switch (r) {
6359 case 0:
6360 case EACCES:
6361 break;
6362
6363 case ECONNABORTED:
6364 ret = ECONNABORTED;
6365 goto out;
6366
6367 case EPERM:
6368 uu_die("Insufficient privilege.\n");
6369 /* NOTREACHED */
6370
6371 default:
6372 bad_error("libscf_unset_action", r);
6373 }
6374 }
6375
6376 while ((a = next_action(action_ts, NACTIONS)) != -1) {
6377 log_framework(LOG_DEBUG,
6378 "Graph: processing %s action for %s.\n", admin_actions[a],
6379 inst_name);
6380
6381 if (a == ADMIN_EVENT_REFRESH) {
6382 r = dgraph_refresh_instance(vertex, inst);
6383 switch (r) {
6384 case 0:
6385 case ECANCELED:
6386 case EINVAL:
6387 case -1:
6388 break;
6389
6390 case ECONNABORTED:
6391 /* pg & inst are reset now, so just return. */
6392 ret = ECONNABORTED;
6393 goto out;
6394
6395 default:
6396 bad_error("dgraph_refresh_instance", r);
6397 }
6398 }
6399
6400 vertex_send_event(vertex, admin_events[a]);
6401
6402 r = libscf_unset_action(h, pg, a, action_ts[a]);
6403 switch (r) {
6404 case 0:
6405 case EACCES:
6406 break;
6407
6408 case ECONNABORTED:
6409 ret = ECONNABORTED;
6410 goto out;
6411
6412 case EPERM:
6413 uu_die("Insufficient privilege.\n");
6414 /* NOTREACHED */
6415
6416 default:
6417 bad_error("libscf_unset_action", r);
6418 }
6419
6420 action_ts[a] = 0;
6421 }
6422
6423 out:
6424 MUTEX_UNLOCK(&dgraph_lock);
6425
6426 scf_property_destroy(prop);
6427 scf_value_destroy(val);
6428 startd_free(inst_name, max_scf_fmri_size);
6429 return (ret);
6430 }
6431
6432 /*
6433 * inst and pg_name are scratch space, and are unset on entry.
6434 * Returns
6435 * 0 - success
6436 * ECONNRESET - success, but repository handle rebound
6437 * ECONNABORTED - repository connection broken
6438 */
6439 static int
6440 process_pg_event(scf_handle_t *h, scf_propertygroup_t *pg, scf_instance_t *inst,
6441 char *pg_name)
6442 {
6443 int r;
6444 scf_property_t *prop;
6445 scf_value_t *val;
6446 char *fmri;
6447 boolean_t rebound = B_FALSE, rebind_inst = B_FALSE;
6448
6449 if (scf_pg_get_name(pg, pg_name, max_scf_value_size) < 0) {
6450 switch (scf_error()) {
6451 case SCF_ERROR_CONNECTION_BROKEN:
6452 default:
6453 return (ECONNABORTED);
6454
6455 case SCF_ERROR_DELETED:
6456 return (0);
6457
6458 case SCF_ERROR_NOT_SET:
6459 bad_error("scf_pg_get_name", scf_error());
6460 }
6461 }
6462
6463 if (strcmp(pg_name, SCF_PG_GENERAL) == 0 ||
6464 strcmp(pg_name, SCF_PG_GENERAL_OVR) == 0) {
6465 r = dgraph_update_general(pg);
6466 switch (r) {
6467 case 0:
6468 case ENOTSUP:
6469 case ECANCELED:
6470 return (0);
6471
6472 case ECONNABORTED:
6473 return (ECONNABORTED);
6474
6475 case -1:
6476 /* Error should have been logged. */
6477 return (0);
6478
6479 default:
6480 bad_error("dgraph_update_general", r);
6481 }
6482 } else if (strcmp(pg_name, SCF_PG_RESTARTER_ACTIONS) == 0) {
6483 if (scf_pg_get_parent_instance(pg, inst) != 0) {
6484 switch (scf_error()) {
6485 case SCF_ERROR_CONNECTION_BROKEN:
6486 return (ECONNABORTED);
6487
6488 case SCF_ERROR_DELETED:
6489 case SCF_ERROR_CONSTRAINT_VIOLATED:
6490 /* Ignore commands on services. */
6491 return (0);
6492
6493 case SCF_ERROR_NOT_BOUND:
6494 case SCF_ERROR_HANDLE_MISMATCH:
6495 case SCF_ERROR_NOT_SET:
6496 default:
6497 bad_error("scf_pg_get_parent_instance",
6498 scf_error());
6499 }
6500 }
6501
6502 return (process_actions(h, pg, inst));
6503 }
6504
6505 if (strcmp(pg_name, SCF_PG_OPTIONS) != 0 &&
6506 strcmp(pg_name, SCF_PG_OPTIONS_OVR) != 0)
6507 return (0);
6508
6509 /*
6510 * We only care about the options[_ovr] property groups of our own
6511 * instance, so get the fmri and compare. Plus, once we know it's
6512 * correct, if the repository connection is broken we know exactly what
6513 * property group we were operating on, and can look it up again.
6514 */
6515 if (scf_pg_get_parent_instance(pg, inst) != 0) {
6516 switch (scf_error()) {
6517 case SCF_ERROR_CONNECTION_BROKEN:
6518 return (ECONNABORTED);
6519
6520 case SCF_ERROR_DELETED:
6521 case SCF_ERROR_CONSTRAINT_VIOLATED:
6522 return (0);
6523
6524 case SCF_ERROR_HANDLE_MISMATCH:
6525 case SCF_ERROR_NOT_BOUND:
6526 case SCF_ERROR_NOT_SET:
6527 default:
6528 bad_error("scf_pg_get_parent_instance",
6529 scf_error());
6530 }
6531 }
6532
6533 switch (r = libscf_instance_get_fmri(inst, &fmri)) {
6534 case 0:
6535 break;
6536
6537 case ECONNABORTED:
6538 return (ECONNABORTED);
6539
6540 case ECANCELED:
6541 return (0);
6542
6543 default:
6544 bad_error("libscf_instance_get_fmri", r);
6545 }
6546
6547 if (strcmp(fmri, SCF_SERVICE_STARTD) != 0) {
6548 startd_free(fmri, max_scf_fmri_size);
6549 return (0);
6550 }
6551
6552 /*
6553 * update the information events flag
6554 */
6555 if (strcmp(pg_name, SCF_PG_OPTIONS) == 0)
6556 info_events_all = libscf_get_info_events_all(pg);
6557
6558 prop = safe_scf_property_create(h);
6559 val = safe_scf_value_create(h);
6560
6561 if (strcmp(pg_name, SCF_PG_OPTIONS_OVR) == 0) {
6562 /* See if we need to set the runlevel. */
6563 /* CONSTCOND */
6564 if (0) {
6565 rebind_pg:
6566 libscf_handle_rebind(h);
6567 rebound = B_TRUE;
6568
6569 r = libscf_lookup_instance(SCF_SERVICE_STARTD, inst);
6570 switch (r) {
6571 case 0:
6572 break;
6573
6574 case ECONNABORTED:
6575 goto rebind_pg;
6576
6577 case ENOENT:
6578 goto out;
6579
6580 case EINVAL:
6581 case ENOTSUP:
6582 bad_error("libscf_lookup_instance", r);
6583 }
6584
6585 if (scf_instance_get_pg(inst, pg_name, pg) != 0) {
6586 switch (scf_error()) {
6587 case SCF_ERROR_DELETED:
6588 case SCF_ERROR_NOT_FOUND:
6589 goto out;
6590
6591 case SCF_ERROR_CONNECTION_BROKEN:
6592 goto rebind_pg;
6593
6594 case SCF_ERROR_HANDLE_MISMATCH:
6595 case SCF_ERROR_NOT_BOUND:
6596 case SCF_ERROR_NOT_SET:
6597 case SCF_ERROR_INVALID_ARGUMENT:
6598 default:
6599 bad_error("scf_instance_get_pg",
6600 scf_error());
6601 }
6602 }
6603 }
6604
6605 if (scf_pg_get_property(pg, "runlevel", prop) == 0) {
6606 r = dgraph_set_runlevel(pg, prop);
6607 switch (r) {
6608 case ECONNRESET:
6609 rebound = B_TRUE;
6610 rebind_inst = B_TRUE;
6611 /* FALLTHROUGH */
6612
6613 case 0:
6614 break;
6615
6616 case ECONNABORTED:
6617 goto rebind_pg;
6618
6619 case ECANCELED:
6620 goto out;
6621
6622 default:
6623 bad_error("dgraph_set_runlevel", r);
6624 }
6625 } else {
6626 switch (scf_error()) {
6627 case SCF_ERROR_CONNECTION_BROKEN:
6628 default:
6629 goto rebind_pg;
6630
6631 case SCF_ERROR_DELETED:
6632 goto out;
6633
6634 case SCF_ERROR_NOT_FOUND:
6635 break;
6636
6637 case SCF_ERROR_INVALID_ARGUMENT:
6638 case SCF_ERROR_HANDLE_MISMATCH:
6639 case SCF_ERROR_NOT_BOUND:
6640 case SCF_ERROR_NOT_SET:
6641 bad_error("scf_pg_get_property", scf_error());
6642 }
6643 }
6644 }
6645
6646 if (rebind_inst) {
6647 lookup_inst:
6648 r = libscf_lookup_instance(SCF_SERVICE_STARTD, inst);
6649 switch (r) {
6650 case 0:
6651 break;
6652
6653 case ECONNABORTED:
6654 libscf_handle_rebind(h);
6655 rebound = B_TRUE;
6656 goto lookup_inst;
6657
6658 case ENOENT:
6659 goto out;
6660
6661 case EINVAL:
6662 case ENOTSUP:
6663 bad_error("libscf_lookup_instance", r);
6664 }
6665 }
6666
6667 r = libscf_get_milestone(inst, prop, val, fmri, max_scf_fmri_size);
6668 switch (r) {
6669 case 0:
6670 break;
6671
6672 case ECONNABORTED:
6673 libscf_handle_rebind(h);
6674 rebound = B_TRUE;
6675 goto lookup_inst;
6676
6677 case EINVAL:
6678 log_error(LOG_NOTICE,
6679 "%s/%s property of %s is misconfigured.\n", pg_name,
6680 SCF_PROPERTY_MILESTONE, SCF_SERVICE_STARTD);
6681 /* FALLTHROUGH */
6682
6683 case ECANCELED:
6684 case ENOENT:
6685 (void) strcpy(fmri, "all");
6686 break;
6687
6688 default:
6689 bad_error("libscf_get_milestone", r);
6690 }
6691
6692 r = dgraph_set_milestone(fmri, h, B_FALSE);
6693 switch (r) {
6694 case 0:
6695 case ECONNRESET:
6696 case EALREADY:
6697 break;
6698
6699 case EINVAL:
6700 log_error(LOG_WARNING, "Milestone %s is invalid.\n", fmri);
6701 break;
6702
6703 case ENOENT:
6704 log_error(LOG_WARNING, "Milestone %s does not exist.\n", fmri);
6705 break;
6706
6707 default:
6708 bad_error("dgraph_set_milestone", r);
6709 }
6710
6711 out:
6712 startd_free(fmri, max_scf_fmri_size);
6713 scf_value_destroy(val);
6714 scf_property_destroy(prop);
6715
6716 return (rebound ? ECONNRESET : 0);
6717 }
6718
6719 /*
6720 * process_delete() deletes an instance from the dgraph if 'fmri' is an
6721 * instance fmri or if 'fmri' matches the 'general' property group of an
6722 * instance (or the 'general/enabled' property).
6723 *
6724 * 'fmri' may be overwritten and cannot be trusted on return by the caller.
6725 */
6726 static void
6727 process_delete(char *fmri, scf_handle_t *h)
6728 {
6729 char *lfmri, *end_inst_fmri;
6730 const char *inst_name = NULL;
6731 const char *pg_name = NULL;
6732 const char *prop_name = NULL;
6733
6734 lfmri = safe_strdup(fmri);
6735
6736 /* Determine if the FMRI is a property group or instance */
6737 if (scf_parse_svc_fmri(lfmri, NULL, NULL, &inst_name, &pg_name,
6738 &prop_name) != SCF_SUCCESS) {
6739 log_error(LOG_WARNING,
6740 "Received invalid FMRI \"%s\" from repository server.\n",
6741 fmri);
6742 } else if (inst_name != NULL && pg_name == NULL) {
6743 (void) dgraph_remove_instance(fmri, h);
6744 } else if (inst_name != NULL && pg_name != NULL) {
6745 /*
6746 * If we're deleting the 'general' property group or
6747 * 'general/enabled' property then the whole instance
6748 * must be removed from the dgraph.
6749 */
6750 if (strcmp(pg_name, SCF_PG_GENERAL) != 0) {
6751 free(lfmri);
6752 return;
6753 }
6754
6755 if (prop_name != NULL &&
6756 strcmp(prop_name, SCF_PROPERTY_ENABLED) != 0) {
6757 free(lfmri);
6758 return;
6759 }
6760
6761 /*
6762 * Because the instance has already been deleted from the
6763 * repository, we cannot use any scf_ functions to retrieve
6764 * the instance FMRI however we can easily reconstruct it
6765 * manually.
6766 */
6767 end_inst_fmri = strstr(fmri, SCF_FMRI_PROPERTYGRP_PREFIX);
6768 if (end_inst_fmri == NULL)
6769 bad_error("process_delete", 0);
6770
6771 end_inst_fmri[0] = '\0';
6772
6773 (void) dgraph_remove_instance(fmri, h);
6774 }
6775
6776 free(lfmri);
6777 }
6778
6779 /*ARGSUSED*/
6780 void *
6781 repository_event_thread(void *unused)
6782 {
6783 scf_handle_t *h;
6784 scf_propertygroup_t *pg;
6785 scf_instance_t *inst;
6786 char *fmri = startd_alloc(max_scf_fmri_size);
6787 char *pg_name = startd_alloc(max_scf_value_size);
6788 int r;
6789
6790 h = libscf_handle_create_bound_loop();
6791
6792 pg = safe_scf_pg_create(h);
6793 inst = safe_scf_instance_create(h);
6794
6795 retry:
6796 if (_scf_notify_add_pgtype(h, SCF_GROUP_FRAMEWORK) != SCF_SUCCESS) {
6797 if (scf_error() == SCF_ERROR_CONNECTION_BROKEN) {
6798 libscf_handle_rebind(h);
6799 } else {
6800 log_error(LOG_WARNING,
6801 "Couldn't set up repository notification "
6802 "for property group type %s: %s\n",
6803 SCF_GROUP_FRAMEWORK, scf_strerror(scf_error()));
6804
6805 (void) sleep(1);
6806 }
6807
6808 goto retry;
6809 }
6810
6811 /*CONSTCOND*/
6812 while (1) {
6813 ssize_t res;
6814
6815 /* Note: fmri is only set on delete events. */
6816 res = _scf_notify_wait(pg, fmri, max_scf_fmri_size);
6817 if (res < 0) {
6818 libscf_handle_rebind(h);
6819 goto retry;
6820 } else if (res == 0) {
6821 /*
6822 * property group modified. inst and pg_name are
6823 * pre-allocated scratch space.
6824 */
6825 if (scf_pg_update(pg) < 0) {
6826 switch (scf_error()) {
6827 case SCF_ERROR_DELETED:
6828 continue;
6829
6830 case SCF_ERROR_CONNECTION_BROKEN:
6831 log_error(LOG_WARNING,
6832 "Lost repository event due to "
6833 "disconnection.\n");
6834 libscf_handle_rebind(h);
6835 goto retry;
6836
6837 case SCF_ERROR_NOT_BOUND:
6838 case SCF_ERROR_NOT_SET:
6839 default:
6840 bad_error("scf_pg_update", scf_error());
6841 }
6842 }
6843
6844 r = process_pg_event(h, pg, inst, pg_name);
6845 switch (r) {
6846 case 0:
6847 break;
6848
6849 case ECONNABORTED:
6850 log_error(LOG_WARNING, "Lost repository event "
6851 "due to disconnection.\n");
6852 libscf_handle_rebind(h);
6853 /* FALLTHROUGH */
6854
6855 case ECONNRESET:
6856 goto retry;
6857
6858 default:
6859 bad_error("process_pg_event", r);
6860 }
6861 } else {
6862 /*
6863 * Service, instance, or pg deleted.
6864 * Don't trust fmri on return.
6865 */
6866 process_delete(fmri, h);
6867 }
6868 }
6869
6870 /*NOTREACHED*/
6871 return (NULL);
6872 }
6873
6874 void
6875 graph_engine_start()
6876 {
6877 int err;
6878
6879 (void) startd_thread_create(graph_thread, NULL);
6880
6881 MUTEX_LOCK(&dgraph_lock);
6882 while (!initial_milestone_set) {
6883 err = pthread_cond_wait(&initial_milestone_cv, &dgraph_lock);
6884 assert(err == 0);
6885 }
6886 MUTEX_UNLOCK(&dgraph_lock);
6887
6888 (void) startd_thread_create(repository_event_thread, NULL);
6889 (void) startd_thread_create(graph_event_thread, NULL);
6890 }