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