xref: /illumos-gate/usr/src/cmd/svc/svcs/explain.c (revision 8fff7887)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
53eae19d9Swesolows  * Common Development and Distribution License (the "License").
63eae19d9Swesolows  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
213eae19d9Swesolows 
227c478bd9Sstevel@tonic-gate /*
23eb1a3463STruong Nguyen  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*8fff7887SJohn Levon  * Copyright 2020 Joyent, Inc.
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate /*
297c478bd9Sstevel@tonic-gate  * Service state explanation.  For select services, display a description, the
307c478bd9Sstevel@tonic-gate  * state, and possibly why the service is in that state, what's causing it to
317c478bd9Sstevel@tonic-gate  * be in that state, and what other services it is keeping offline (impact).
327c478bd9Sstevel@tonic-gate  *
337c478bd9Sstevel@tonic-gate  * Explaining states other than offline is easy.  For maintenance and
347c478bd9Sstevel@tonic-gate  * degraded, we just use the auxiliary state.  For offline, we must determine
357c478bd9Sstevel@tonic-gate  * which dependencies are unsatisfied and recurse.  If a causal service is not
367c478bd9Sstevel@tonic-gate  * offline, then a svcptr to it is added to the offline service's causes list.
377c478bd9Sstevel@tonic-gate  * If a causal service is offline, then we recurse to determine its causes and
387c478bd9Sstevel@tonic-gate  * merge them into the causes list of the service in question (see
397c478bd9Sstevel@tonic-gate  * add_causes()).  Note that by adding a self-pointing svcptr to the causes
407c478bd9Sstevel@tonic-gate  * lists of services which are not offline or are offline for unknown reasons,
417c478bd9Sstevel@tonic-gate  * we can always merge the unsatisfied dependency's causes into the
427c478bd9Sstevel@tonic-gate  * dependent's list.
437c478bd9Sstevel@tonic-gate  *
447c478bd9Sstevel@tonic-gate  * Computing an impact list is more involved because the dependencies in the
457c478bd9Sstevel@tonic-gate  * repository are unidirectional; it requires determining the causes of all
467c478bd9Sstevel@tonic-gate  * offline services.  For each unsatisfied dependency of an offline service,
477c478bd9Sstevel@tonic-gate  * a svcptr to the dependent is added to the dependency's impact_dependents
487c478bd9Sstevel@tonic-gate  * list (see add_causes()).  determine_impact() uses the lists to build an
497c478bd9Sstevel@tonic-gate  * impact list.  The direct dependency is used so that a path from the
507c478bd9Sstevel@tonic-gate  * affected service to the causal service can be constructed (see
517c478bd9Sstevel@tonic-gate  * print_dependency_reasons()).
527c478bd9Sstevel@tonic-gate  *
537c478bd9Sstevel@tonic-gate  * Because we always need at least impact counts, we always run
547c478bd9Sstevel@tonic-gate  * determine_causes() on all services.
557c478bd9Sstevel@tonic-gate  *
567c478bd9Sstevel@tonic-gate  * If no arguments are given, we must select the services which are causing
577c478bd9Sstevel@tonic-gate  * other services to be offline.  We do so by adding services which are not
587c478bd9Sstevel@tonic-gate  * running for any reason other than another service to the g_causes list in
597c478bd9Sstevel@tonic-gate  * determine_causes().
607c478bd9Sstevel@tonic-gate  *
617c478bd9Sstevel@tonic-gate  * Since all services must be examined, and their states may be consulted
627c478bd9Sstevel@tonic-gate  * a lot, it is important that we only read volatile data (like states) from
637c478bd9Sstevel@tonic-gate  * the repository once.  add_instance() reads data for an instance from the
647c478bd9Sstevel@tonic-gate  * repository into an inst_t and puts it into the "services" cache, which is
657c478bd9Sstevel@tonic-gate  * organized as a hash table of svc_t's, each of which has a list of inst_t's.
667c478bd9Sstevel@tonic-gate  */
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate #include "svcs.h"
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate #include <sys/stat.h>
717c478bd9Sstevel@tonic-gate #include <sys/wait.h>
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate #include <assert.h>
747c478bd9Sstevel@tonic-gate #include <errno.h>
757c478bd9Sstevel@tonic-gate #include <libintl.h>
767c478bd9Sstevel@tonic-gate #include <libuutil.h>
777c478bd9Sstevel@tonic-gate #include <libscf.h>
787c478bd9Sstevel@tonic-gate #include <libscf_priv.h>
797c478bd9Sstevel@tonic-gate #include <string.h>
807c478bd9Sstevel@tonic-gate #include <stdio.h>
817c478bd9Sstevel@tonic-gate #include <stdlib.h>
827c478bd9Sstevel@tonic-gate #include <time.h>
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate #define	DC_DISABLED	"SMF-8000-05"
867c478bd9Sstevel@tonic-gate #define	DC_TEMPDISABLED	"SMF-8000-1S"
877c478bd9Sstevel@tonic-gate #define	DC_RSTRINVALID	"SMF-8000-2A"
887c478bd9Sstevel@tonic-gate #define	DC_RSTRABSENT	"SMF-8000-3P"
897c478bd9Sstevel@tonic-gate #define	DC_UNINIT	"SMF-8000-4D"
907c478bd9Sstevel@tonic-gate #define	DC_RSTRDEAD	"SMF-8000-5H"
917c478bd9Sstevel@tonic-gate #define	DC_ADMINMAINT	"SMF-8000-63"
92eb1a3463STruong Nguyen #define	DC_SVCREQMAINT	"SMF-8000-R4"
937c478bd9Sstevel@tonic-gate #define	DC_REPTFAIL	"SMF-8000-7Y"
947c478bd9Sstevel@tonic-gate #define	DC_METHFAIL	"SMF-8000-8Q"
957c478bd9Sstevel@tonic-gate #define	DC_NONE		"SMF-8000-9C"
967c478bd9Sstevel@tonic-gate #define	DC_UNKNOWN	"SMF-8000-AR"
977c478bd9Sstevel@tonic-gate #define	DC_STARTING	"SMF-8000-C4"
987c478bd9Sstevel@tonic-gate #define	DC_ADMINDEGR	"SMF-8000-DX"
997c478bd9Sstevel@tonic-gate #define	DC_DEPABSENT	"SMF-8000-E2"
1007c478bd9Sstevel@tonic-gate #define	DC_DEPRUNNING	"SMF-8000-FJ"
1017c478bd9Sstevel@tonic-gate #define	DC_DEPOTHER	"SMF-8000-GE"
1027c478bd9Sstevel@tonic-gate #define	DC_DEPCYCLE	"SMF-8000-HP"
1037c478bd9Sstevel@tonic-gate #define	DC_INVALIDDEP	"SMF-8000-JA"
1047c478bd9Sstevel@tonic-gate #define	DC_STARTFAIL	"SMF-8000-KS"
1057c478bd9Sstevel@tonic-gate #define	DC_TOOQUICKLY	"SMF-8000-L5"
1067c478bd9Sstevel@tonic-gate #define	DC_INVALIDSTATE	"SMF-8000-N3"
1077c478bd9Sstevel@tonic-gate #define	DC_TRANSITION	"SMF-8000-PH"
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate #define	DEFAULT_MAN_PATH	"/usr/share/man"
1107c478bd9Sstevel@tonic-gate 
111eb1a3463STruong Nguyen #define	AUX_STATE_INVALID	"invalid_aux_state"
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate #define	uu_list_append(lst, e)	uu_list_insert_before(lst, NULL, e)
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate #define	bad_error(func, err)						\
11654d02241SBryan Cantrill 	uu_panic("%s:%d: %s() failed with unknown error %d.\n",		\
11754d02241SBryan Cantrill 	    __FILE__, __LINE__, func, err);
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate typedef struct {
1207c478bd9Sstevel@tonic-gate 	const char *svcname;
1217c478bd9Sstevel@tonic-gate 	const char *instname;
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate 	/* restarter pg properties */
1247c478bd9Sstevel@tonic-gate 	char state[MAX_SCF_STATE_STRING_SZ];
1257c478bd9Sstevel@tonic-gate 	char next_state[MAX_SCF_STATE_STRING_SZ];
1267c478bd9Sstevel@tonic-gate 	struct timeval stime;
1277c478bd9Sstevel@tonic-gate 	const char *aux_state;
128eb1a3463STruong Nguyen 	const char *aux_fmri;
1297c478bd9Sstevel@tonic-gate 	int64_t start_method_waitstatus;
1307c478bd9Sstevel@tonic-gate 
1312e1a9474SLiane Praza 	uint8_t enabled;
1327c478bd9Sstevel@tonic-gate 	int temporary;
1337c478bd9Sstevel@tonic-gate 	const char *restarter;
1347c478bd9Sstevel@tonic-gate 	uu_list_t *dependencies;	/* list of dependency_group's */
1357c478bd9Sstevel@tonic-gate 
136*8fff7887SJohn Levon 	char comment[SCF_COMMENT_MAX_LENGTH];
137*8fff7887SJohn Levon 
1387c478bd9Sstevel@tonic-gate 	int active;			/* In use?  (cycle detection) */
1397c478bd9Sstevel@tonic-gate 	int restarter_bad;
1407c478bd9Sstevel@tonic-gate 	const char *summary;
1417c478bd9Sstevel@tonic-gate 	uu_list_t *baddeps;		/* list of dependency's */
1427c478bd9Sstevel@tonic-gate 	uu_list_t *causes;		/* list of svcptrs */
1437c478bd9Sstevel@tonic-gate 	uu_list_t *impact_dependents;	/* list of svcptrs */
1447c478bd9Sstevel@tonic-gate 	uu_list_t *impact;		/* list of svcptrs */
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate 	uu_list_node_t node;
1477c478bd9Sstevel@tonic-gate } inst_t;
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate typedef struct service {
1507c478bd9Sstevel@tonic-gate 	const char *svcname;
1517c478bd9Sstevel@tonic-gate 	uu_list_t *instances;
1527c478bd9Sstevel@tonic-gate 	struct service *next;
1537c478bd9Sstevel@tonic-gate } svc_t;
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate struct svcptr {
1567c478bd9Sstevel@tonic-gate 	inst_t *svcp;
1577c478bd9Sstevel@tonic-gate 	inst_t *next_hop;
1587c478bd9Sstevel@tonic-gate 	uu_list_node_t node;
1597c478bd9Sstevel@tonic-gate };
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate struct dependency_group {
1627c478bd9Sstevel@tonic-gate 	enum { DGG_REQALL, DGG_REQANY, DGG_OPTALL, DGG_EXCALL } grouping;
1637c478bd9Sstevel@tonic-gate 	const char *type;
1647c478bd9Sstevel@tonic-gate 	uu_list_t *entities;		/* List of struct dependency's */
1657c478bd9Sstevel@tonic-gate 	uu_list_node_t node;
1667c478bd9Sstevel@tonic-gate };
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate struct dependency {
1697c478bd9Sstevel@tonic-gate 	const char *fmri;
1707c478bd9Sstevel@tonic-gate 	uu_list_node_t node;
1717c478bd9Sstevel@tonic-gate };
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate /* Hash table of service names -> svc_t's */
1747c478bd9Sstevel@tonic-gate #define	SVC_HASH_NBUCKETS	256
1757c478bd9Sstevel@tonic-gate #define	SVC_HASH_MASK		(SVC_HASH_NBUCKETS - 1)
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate static svc_t **services;
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate static uu_list_pool_t *insts, *svcptrs, *depgroups, *deps;
1807c478bd9Sstevel@tonic-gate static uu_list_t *g_causes;		/* list of svcptrs */
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate static scf_scope_t *g_local_scope;
1837c478bd9Sstevel@tonic-gate static scf_service_t *g_svc;
1847c478bd9Sstevel@tonic-gate static scf_instance_t *g_inst;
1857c478bd9Sstevel@tonic-gate static scf_snapshot_t *g_snap;
1867c478bd9Sstevel@tonic-gate static scf_propertygroup_t *g_pg;
1877c478bd9Sstevel@tonic-gate static scf_property_t *g_prop;
1887c478bd9Sstevel@tonic-gate static scf_value_t *g_val;
1897c478bd9Sstevel@tonic-gate static scf_iter_t *g_iter, *g_viter;
1907c478bd9Sstevel@tonic-gate static char *g_fmri, *g_value;
1917c478bd9Sstevel@tonic-gate static size_t g_fmri_sz, g_value_sz;
192654b400cSJoshua M. Clulow static const char *g_msgbase = "http://illumos.org/msg/";
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate static char *emsg_nomem;
1957c478bd9Sstevel@tonic-gate static char *emsg_invalid_dep;
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate extern scf_handle_t *h;
198048b0279SBryan Cantrill extern char *g_zonename;
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate /* ARGSUSED */
2017c478bd9Sstevel@tonic-gate static int
svcptr_compare(struct svcptr * a,struct svcptr * b,void * data)2027c478bd9Sstevel@tonic-gate svcptr_compare(struct svcptr *a, struct svcptr *b, void *data)
2037c478bd9Sstevel@tonic-gate {
2047c478bd9Sstevel@tonic-gate 	return (b->svcp - a->svcp);
2057c478bd9Sstevel@tonic-gate }
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate static uint32_t
hash_name(const char * name)2087c478bd9Sstevel@tonic-gate hash_name(const char *name)
2097c478bd9Sstevel@tonic-gate {
2107c478bd9Sstevel@tonic-gate 	uint32_t h = 0, g;
2117c478bd9Sstevel@tonic-gate 	const char *p;
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate 	for (p = name; *p != '\0'; ++p) {
2147c478bd9Sstevel@tonic-gate 		h = (h << 4) + *p;
2157c478bd9Sstevel@tonic-gate 		if ((g = (h & 0xf0000000)) != 0) {
2167c478bd9Sstevel@tonic-gate 			h ^= (g >> 24);
2177c478bd9Sstevel@tonic-gate 			h ^= g;
2187c478bd9Sstevel@tonic-gate 		}
2197c478bd9Sstevel@tonic-gate 	}
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate 	return (h);
2227c478bd9Sstevel@tonic-gate }
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate static void
x_init(void)2257c478bd9Sstevel@tonic-gate x_init(void)
2267c478bd9Sstevel@tonic-gate {
2277c478bd9Sstevel@tonic-gate 	emsg_nomem = gettext("Out of memory.\n");
2287c478bd9Sstevel@tonic-gate 	emsg_invalid_dep =
2297c478bd9Sstevel@tonic-gate 	    gettext("svc:/%s:%s has invalid dependency \"%s\".\n");
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate 	services = calloc(SVC_HASH_NBUCKETS, sizeof (*services));
2327c478bd9Sstevel@tonic-gate 	if (services == NULL)
2337c478bd9Sstevel@tonic-gate 		uu_die(emsg_nomem);
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 	insts = uu_list_pool_create("insts", sizeof (inst_t),
2367c478bd9Sstevel@tonic-gate 	    offsetof(inst_t, node), NULL, UU_LIST_POOL_DEBUG);
2377c478bd9Sstevel@tonic-gate 	svcptrs = uu_list_pool_create("svcptrs", sizeof (struct svcptr),
2387c478bd9Sstevel@tonic-gate 	    offsetof(struct svcptr, node), (uu_compare_fn_t *)svcptr_compare,
2397c478bd9Sstevel@tonic-gate 	    UU_LIST_POOL_DEBUG);
2407c478bd9Sstevel@tonic-gate 	depgroups = uu_list_pool_create("depgroups",
2417c478bd9Sstevel@tonic-gate 	    sizeof (struct dependency_group),
2427c478bd9Sstevel@tonic-gate 	    offsetof(struct dependency_group, node), NULL, UU_LIST_POOL_DEBUG);
2437c478bd9Sstevel@tonic-gate 	deps = uu_list_pool_create("deps", sizeof (struct dependency),
2447c478bd9Sstevel@tonic-gate 	    offsetof(struct dependency, node), NULL, UU_LIST_POOL_DEBUG);
2457c478bd9Sstevel@tonic-gate 	g_causes = uu_list_create(svcptrs, NULL, UU_LIST_DEBUG);
2467c478bd9Sstevel@tonic-gate 	if (insts == NULL || svcptrs == NULL || depgroups == NULL ||
2477c478bd9Sstevel@tonic-gate 	    deps == NULL || g_causes == NULL)
2487c478bd9Sstevel@tonic-gate 		uu_die(emsg_nomem);
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate 	if ((g_local_scope = scf_scope_create(h)) == NULL ||
2517c478bd9Sstevel@tonic-gate 	    (g_svc = scf_service_create(h)) == NULL ||
2527c478bd9Sstevel@tonic-gate 	    (g_inst = scf_instance_create(h)) == NULL ||
2537c478bd9Sstevel@tonic-gate 	    (g_snap = scf_snapshot_create(h)) == NULL ||
2547c478bd9Sstevel@tonic-gate 	    (g_pg = scf_pg_create(h)) == NULL ||
2557c478bd9Sstevel@tonic-gate 	    (g_prop = scf_property_create(h)) == NULL ||
2567c478bd9Sstevel@tonic-gate 	    (g_val = scf_value_create(h)) == NULL ||
2577c478bd9Sstevel@tonic-gate 	    (g_iter = scf_iter_create(h)) == NULL ||
2587c478bd9Sstevel@tonic-gate 	    (g_viter = scf_iter_create(h)) == NULL)
2597c478bd9Sstevel@tonic-gate 		scfdie();
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate 	if (scf_handle_get_scope(h, SCF_SCOPE_LOCAL, g_local_scope) != 0)
2627c478bd9Sstevel@tonic-gate 		scfdie();
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate 	g_fmri_sz = max_scf_fmri_length + 1;
2657c478bd9Sstevel@tonic-gate 	g_fmri = safe_malloc(g_fmri_sz);
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate 	g_value_sz = max_scf_value_length + 1;
2687c478bd9Sstevel@tonic-gate 	g_value = safe_malloc(g_value_sz);
2697c478bd9Sstevel@tonic-gate }
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate /*
2727c478bd9Sstevel@tonic-gate  * Repository loading routines.
2737c478bd9Sstevel@tonic-gate  */
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate /*
2767c478bd9Sstevel@tonic-gate  * Returns
2777c478bd9Sstevel@tonic-gate  *   0 - success
2787c478bd9Sstevel@tonic-gate  *   ECANCELED - inst was deleted
2797c478bd9Sstevel@tonic-gate  *   EINVAL - inst is invalid
2807c478bd9Sstevel@tonic-gate  */
2817c478bd9Sstevel@tonic-gate static int
load_dependencies(inst_t * svcp,scf_instance_t * inst)2827c478bd9Sstevel@tonic-gate load_dependencies(inst_t *svcp, scf_instance_t *inst)
2837c478bd9Sstevel@tonic-gate {
2847c478bd9Sstevel@tonic-gate 	scf_snapshot_t *snap;
2857c478bd9Sstevel@tonic-gate 	struct dependency_group *dg;
2867c478bd9Sstevel@tonic-gate 	struct dependency *d;
2877c478bd9Sstevel@tonic-gate 	int r;
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate 	assert(svcp->dependencies == NULL);
2907c478bd9Sstevel@tonic-gate 	svcp->dependencies = uu_list_create(depgroups, svcp, UU_LIST_DEBUG);
2917c478bd9Sstevel@tonic-gate 	if (svcp->dependencies == NULL)
2927c478bd9Sstevel@tonic-gate 		uu_die(emsg_nomem);
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate 	if (scf_instance_get_snapshot(inst, "running", g_snap) == 0) {
2957c478bd9Sstevel@tonic-gate 		snap = g_snap;
2967c478bd9Sstevel@tonic-gate 	} else {
2977c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND)
2987c478bd9Sstevel@tonic-gate 			scfdie();
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate 		snap = NULL;
3017c478bd9Sstevel@tonic-gate 	}
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate 	if (scf_iter_instance_pgs_typed_composed(g_iter, inst, snap,
3047c478bd9Sstevel@tonic-gate 	    SCF_GROUP_DEPENDENCY) != 0) {
3057c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_DELETED)
3067c478bd9Sstevel@tonic-gate 			scfdie();
3077c478bd9Sstevel@tonic-gate 		return (ECANCELED);
3087c478bd9Sstevel@tonic-gate 	}
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate 	for (;;) {
3117c478bd9Sstevel@tonic-gate 		r = scf_iter_next_pg(g_iter, g_pg);
3127c478bd9Sstevel@tonic-gate 		if (r == 0)
3137c478bd9Sstevel@tonic-gate 			break;
3147c478bd9Sstevel@tonic-gate 		if (r != 1) {
3157c478bd9Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_DELETED)
3167c478bd9Sstevel@tonic-gate 				scfdie();
3177c478bd9Sstevel@tonic-gate 			return (ECANCELED);
3187c478bd9Sstevel@tonic-gate 		}
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate 		dg = safe_malloc(sizeof (*dg));
3217c478bd9Sstevel@tonic-gate 		(void) memset(dg, 0, sizeof (*dg));
3227c478bd9Sstevel@tonic-gate 		dg->entities = uu_list_create(deps, dg, UU_LIST_DEBUG);
3237c478bd9Sstevel@tonic-gate 		if (dg->entities == NULL)
3247c478bd9Sstevel@tonic-gate 			uu_die(emsg_nomem);
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate 		if (pg_get_single_val(g_pg, SCF_PROPERTY_GROUPING,
3277c478bd9Sstevel@tonic-gate 		    SCF_TYPE_ASTRING, g_value, g_value_sz, 0) != 0)
3287c478bd9Sstevel@tonic-gate 			return (EINVAL);
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate 		if (strcmp(g_value, "require_all") == 0)
3317c478bd9Sstevel@tonic-gate 			dg->grouping = DGG_REQALL;
3327c478bd9Sstevel@tonic-gate 		else if (strcmp(g_value, "require_any") == 0)
3337c478bd9Sstevel@tonic-gate 			dg->grouping = DGG_REQANY;
3347c478bd9Sstevel@tonic-gate 		else if (strcmp(g_value, "optional_all") == 0)
3357c478bd9Sstevel@tonic-gate 			dg->grouping = DGG_OPTALL;
3367c478bd9Sstevel@tonic-gate 		else if (strcmp(g_value, "exclude_all") == 0)
3377c478bd9Sstevel@tonic-gate 			dg->grouping = DGG_EXCALL;
3387c478bd9Sstevel@tonic-gate 		else {
3397c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("svc:/%s:%s has "
3407c478bd9Sstevel@tonic-gate 			    "dependency with unknown type \"%s\".\n"),
3417c478bd9Sstevel@tonic-gate 			    svcp->svcname, svcp->instname, g_value);
3427c478bd9Sstevel@tonic-gate 			return (EINVAL);
3437c478bd9Sstevel@tonic-gate 		}
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate 		if (pg_get_single_val(g_pg, SCF_PROPERTY_TYPE, SCF_TYPE_ASTRING,
3467c478bd9Sstevel@tonic-gate 		    g_value, g_value_sz, 0) != 0)
3477c478bd9Sstevel@tonic-gate 			return (EINVAL);
3487c478bd9Sstevel@tonic-gate 		dg->type = safe_strdup(g_value);
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 		if (scf_pg_get_property(g_pg, SCF_PROPERTY_ENTITIES, g_prop) !=
3517c478bd9Sstevel@tonic-gate 		    0) {
3527c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
3537c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_FOUND:
3547c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext("svc:/%s:%s has "
3557c478bd9Sstevel@tonic-gate 				    "dependency without an entities "
3567c478bd9Sstevel@tonic-gate 				    "property.\n"), svcp->svcname,
3577c478bd9Sstevel@tonic-gate 				    svcp->instname);
3587c478bd9Sstevel@tonic-gate 				return (EINVAL);
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate 			case SCF_ERROR_DELETED:
3617c478bd9Sstevel@tonic-gate 				return (ECANCELED);
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 			default:
3647c478bd9Sstevel@tonic-gate 				scfdie();
3657c478bd9Sstevel@tonic-gate 			}
3667c478bd9Sstevel@tonic-gate 		}
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate 		if (scf_iter_property_values(g_viter, g_prop) != 0) {
3697c478bd9Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_DELETED)
3707c478bd9Sstevel@tonic-gate 				scfdie();
3717c478bd9Sstevel@tonic-gate 			return (ECANCELED);
3727c478bd9Sstevel@tonic-gate 		}
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate 		for (;;) {
3757c478bd9Sstevel@tonic-gate 			r = scf_iter_next_value(g_viter, g_val);
3767c478bd9Sstevel@tonic-gate 			if (r == 0)
3777c478bd9Sstevel@tonic-gate 				break;
3787c478bd9Sstevel@tonic-gate 			if (r != 1) {
3797c478bd9Sstevel@tonic-gate 				if (scf_error() != SCF_ERROR_DELETED)
3807c478bd9Sstevel@tonic-gate 					scfdie();
3817c478bd9Sstevel@tonic-gate 				return (ECANCELED);
3827c478bd9Sstevel@tonic-gate 			}
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate 			d = safe_malloc(sizeof (*d));
3857c478bd9Sstevel@tonic-gate 			d->fmri = safe_malloc(max_scf_fmri_length + 1);
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate 			if (scf_value_get_astring(g_val, (char *)d->fmri,
3887c478bd9Sstevel@tonic-gate 			    max_scf_fmri_length + 1) < 0)
3897c478bd9Sstevel@tonic-gate 				scfdie();
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate 			uu_list_node_init(d, &d->node, deps);
3927c478bd9Sstevel@tonic-gate 			(void) uu_list_append(dg->entities, d);
3937c478bd9Sstevel@tonic-gate 		}
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 		uu_list_node_init(dg, &dg->node, depgroups);
3967c478bd9Sstevel@tonic-gate 		r = uu_list_append(svcp->dependencies, dg);
3977c478bd9Sstevel@tonic-gate 		assert(r == 0);
3987c478bd9Sstevel@tonic-gate 	}
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 	return (0);
4017c478bd9Sstevel@tonic-gate }
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate static void
add_instance(const char * svcname,const char * instname,scf_instance_t * inst)4047c478bd9Sstevel@tonic-gate add_instance(const char *svcname, const char *instname, scf_instance_t *inst)
4057c478bd9Sstevel@tonic-gate {
4067c478bd9Sstevel@tonic-gate 	inst_t *instp;
4077c478bd9Sstevel@tonic-gate 	svc_t *svcp;
408*8fff7887SJohn Levon 	int ovr_set = 0;
4092e1a9474SLiane Praza 	uint8_t i;
4107c478bd9Sstevel@tonic-gate 	uint32_t h;
4112e1a9474SLiane Praza 	int r;
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate 	h = hash_name(svcname) & SVC_HASH_MASK;
4147c478bd9Sstevel@tonic-gate 	for (svcp = services[h]; svcp != NULL; svcp = svcp->next) {
4157c478bd9Sstevel@tonic-gate 		if (strcmp(svcp->svcname, svcname) == 0)
4167c478bd9Sstevel@tonic-gate 			break;
4177c478bd9Sstevel@tonic-gate 	}
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate 	if (svcp == NULL) {
4207c478bd9Sstevel@tonic-gate 		svcp = safe_malloc(sizeof (*svcp));
4217c478bd9Sstevel@tonic-gate 		svcp->svcname = safe_strdup(svcname);
4227c478bd9Sstevel@tonic-gate 		svcp->instances = uu_list_create(insts, svcp, UU_LIST_DEBUG);
4237c478bd9Sstevel@tonic-gate 		if (svcp->instances == NULL)
4247c478bd9Sstevel@tonic-gate 			uu_die(emsg_nomem);
4257c478bd9Sstevel@tonic-gate 		svcp->next = services[h];
4267c478bd9Sstevel@tonic-gate 		services[h] = svcp;
4277c478bd9Sstevel@tonic-gate 	}
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate 	instp = safe_malloc(sizeof (*instp));
4307c478bd9Sstevel@tonic-gate 	(void) memset(instp, 0, sizeof (*instp));
4317c478bd9Sstevel@tonic-gate 	instp->svcname = svcp->svcname;
4327c478bd9Sstevel@tonic-gate 	instp->instname = safe_strdup(instname);
4337c478bd9Sstevel@tonic-gate 	instp->impact_dependents =
4347c478bd9Sstevel@tonic-gate 	    uu_list_create(svcptrs, instp, UU_LIST_DEBUG);
4357c478bd9Sstevel@tonic-gate 	if (instp->impact_dependents == NULL)
4367c478bd9Sstevel@tonic-gate 		uu_die(emsg_nomem);
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate 	if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, g_pg) != 0) {
4397c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
4407c478bd9Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
4417c478bd9Sstevel@tonic-gate 			return;
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
4447c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("svc:/%s:%s has no "
4457c478bd9Sstevel@tonic-gate 			    "\"%s\" property group; ignoring.\n"),
4467c478bd9Sstevel@tonic-gate 			    instp->svcname, instp->instname, SCF_PG_RESTARTER);
4477c478bd9Sstevel@tonic-gate 			return;
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate 		default:
4507c478bd9Sstevel@tonic-gate 			scfdie();
4517c478bd9Sstevel@tonic-gate 		}
4527c478bd9Sstevel@tonic-gate 	}
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate 	if (pg_get_single_val(g_pg, SCF_PROPERTY_STATE, SCF_TYPE_ASTRING,
4557c478bd9Sstevel@tonic-gate 	    (void *)instp->state, sizeof (instp->state), 0) != 0)
4567c478bd9Sstevel@tonic-gate 		return;
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate 	if (pg_get_single_val(g_pg, SCF_PROPERTY_NEXT_STATE, SCF_TYPE_ASTRING,
4597c478bd9Sstevel@tonic-gate 	    (void *)instp->next_state, sizeof (instp->next_state), 0) != 0)
4607c478bd9Sstevel@tonic-gate 		return;
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate 	if (pg_get_single_val(g_pg, SCF_PROPERTY_STATE_TIMESTAMP,
4637c478bd9Sstevel@tonic-gate 	    SCF_TYPE_TIME, &instp->stime, 0, 0) != 0)
4647c478bd9Sstevel@tonic-gate 		return;
4657c478bd9Sstevel@tonic-gate 
466eb1a3463STruong Nguyen 	/* restarter may not set aux_state, allow to continue in that case */
4677c478bd9Sstevel@tonic-gate 	if (pg_get_single_val(g_pg, SCF_PROPERTY_AUX_STATE, SCF_TYPE_ASTRING,
468eb1a3463STruong Nguyen 	    g_fmri, g_fmri_sz, 0) == 0)
469eb1a3463STruong Nguyen 		instp->aux_state = safe_strdup(g_fmri);
470eb1a3463STruong Nguyen 	else
471eb1a3463STruong Nguyen 		instp->aux_state = safe_strdup(AUX_STATE_INVALID);
4727c478bd9Sstevel@tonic-gate 
4737c478bd9Sstevel@tonic-gate 	(void) pg_get_single_val(g_pg, SCF_PROPERTY_START_METHOD_WAITSTATUS,
4747c478bd9Sstevel@tonic-gate 	    SCF_TYPE_INTEGER, &instp->start_method_waitstatus, 0, 0);
4757c478bd9Sstevel@tonic-gate 
476eb1a3463STruong Nguyen 	/* Get the optional auxiliary_fmri */
477eb1a3463STruong Nguyen 	if (pg_get_single_val(g_pg, SCF_PROPERTY_AUX_FMRI, SCF_TYPE_ASTRING,
478eb1a3463STruong Nguyen 	    g_fmri, g_fmri_sz, 0) == 0)
479eb1a3463STruong Nguyen 		instp->aux_fmri = safe_strdup(g_fmri);
480eb1a3463STruong Nguyen 
4817c478bd9Sstevel@tonic-gate 	if (scf_instance_get_pg(inst, SCF_PG_GENERAL_OVR, g_pg) == 0) {
4827c478bd9Sstevel@tonic-gate 		if (pg_get_single_val(g_pg, SCF_PROPERTY_ENABLED,
4837c478bd9Sstevel@tonic-gate 		    SCF_TYPE_BOOLEAN, &instp->enabled, 0, 0) == 0)
484*8fff7887SJohn Levon 			ovr_set = 1;
485*8fff7887SJohn Levon 		(void) pg_get_single_val(g_pg, SCF_PROPERTY_COMMENT,
486*8fff7887SJohn Levon 		    SCF_TYPE_ASTRING, instp->comment,
487*8fff7887SJohn Levon 		    sizeof (instp->comment), EMPTY_OK);
4887c478bd9Sstevel@tonic-gate 	} else {
4897c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
4907c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
4917c478bd9Sstevel@tonic-gate 			break;
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
4947c478bd9Sstevel@tonic-gate 			return;
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate 		default:
4977c478bd9Sstevel@tonic-gate 			scfdie();
4987c478bd9Sstevel@tonic-gate 		}
4997c478bd9Sstevel@tonic-gate 	}
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate 	if (scf_instance_get_pg_composed(inst, NULL, SCF_PG_GENERAL, g_pg) !=
5027c478bd9Sstevel@tonic-gate 	    0) {
5037c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
5047c478bd9Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
5057c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
5067c478bd9Sstevel@tonic-gate 			return;
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate 		default:
5097c478bd9Sstevel@tonic-gate 			scfdie();
5107c478bd9Sstevel@tonic-gate 		}
5117c478bd9Sstevel@tonic-gate 	}
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate 	if (pg_get_single_val(g_pg, SCF_PROPERTY_ENABLED, SCF_TYPE_BOOLEAN,
5147c478bd9Sstevel@tonic-gate 	    &i, 0, 0) != 0)
5157c478bd9Sstevel@tonic-gate 		return;
516*8fff7887SJohn Levon 
517*8fff7887SJohn Levon 	if (ovr_set) {
518*8fff7887SJohn Levon 		instp->temporary = (instp->enabled != i);
519*8fff7887SJohn Levon 	} else {
5207c478bd9Sstevel@tonic-gate 		instp->enabled = i;
5217c478bd9Sstevel@tonic-gate 		instp->temporary = 0;
522*8fff7887SJohn Levon 	}
523*8fff7887SJohn Levon 
524*8fff7887SJohn Levon 	if (!instp->temporary) {
525*8fff7887SJohn Levon 		(void) pg_get_single_val(g_pg, SCF_PROPERTY_COMMENT,
526*8fff7887SJohn Levon 		    SCF_TYPE_ASTRING, instp->comment,
527*8fff7887SJohn Levon 		    sizeof (instp->comment), EMPTY_OK);
5287c478bd9Sstevel@tonic-gate 	}
5297c478bd9Sstevel@tonic-gate 
5307c478bd9Sstevel@tonic-gate 	if (pg_get_single_val(g_pg, SCF_PROPERTY_RESTARTER, SCF_TYPE_ASTRING,
5317c478bd9Sstevel@tonic-gate 	    g_fmri, g_fmri_sz, 0) == 0)
5327c478bd9Sstevel@tonic-gate 		instp->restarter = safe_strdup(g_fmri);
5337c478bd9Sstevel@tonic-gate 	else
5347c478bd9Sstevel@tonic-gate 		instp->restarter = SCF_SERVICE_STARTD;
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate 	if (strcmp(instp->state, SCF_STATE_STRING_OFFLINE) == 0 &&
5377c478bd9Sstevel@tonic-gate 	    load_dependencies(instp, inst) != 0)
5387c478bd9Sstevel@tonic-gate 		return;
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate 	uu_list_node_init(instp, &instp->node, insts);
5412e1a9474SLiane Praza 	r = uu_list_append(svcp->instances, instp);
5422e1a9474SLiane Praza 	assert(r == 0);
5437c478bd9Sstevel@tonic-gate }
5447c478bd9Sstevel@tonic-gate 
5457c478bd9Sstevel@tonic-gate static void
load_services(void)5467c478bd9Sstevel@tonic-gate load_services(void)
5477c478bd9Sstevel@tonic-gate {
5487c478bd9Sstevel@tonic-gate 	scf_iter_t *siter, *iiter;
5497c478bd9Sstevel@tonic-gate 	int r;
5507c478bd9Sstevel@tonic-gate 	char *svcname, *instname;
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate 	if ((siter = scf_iter_create(h)) == NULL ||
5537c478bd9Sstevel@tonic-gate 	    (iiter = scf_iter_create(h)) == NULL)
5547c478bd9Sstevel@tonic-gate 		scfdie();
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate 	svcname = safe_malloc(max_scf_name_length + 1);
5577c478bd9Sstevel@tonic-gate 	instname = safe_malloc(max_scf_name_length + 1);
5587c478bd9Sstevel@tonic-gate 
5597c478bd9Sstevel@tonic-gate 	if (scf_iter_scope_services(siter, g_local_scope) != 0)
5607c478bd9Sstevel@tonic-gate 		scfdie();
5617c478bd9Sstevel@tonic-gate 
5627c478bd9Sstevel@tonic-gate 	for (;;) {
5637c478bd9Sstevel@tonic-gate 		r = scf_iter_next_service(siter, g_svc);
5647c478bd9Sstevel@tonic-gate 		if (r == 0)
5657c478bd9Sstevel@tonic-gate 			break;
5667c478bd9Sstevel@tonic-gate 		if (r != 1)
5677c478bd9Sstevel@tonic-gate 			scfdie();
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate 		if (scf_service_get_name(g_svc, svcname,
5707c478bd9Sstevel@tonic-gate 		    max_scf_name_length + 1) < 0) {
5717c478bd9Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_DELETED)
5727c478bd9Sstevel@tonic-gate 				scfdie();
5737c478bd9Sstevel@tonic-gate 			continue;
5747c478bd9Sstevel@tonic-gate 		}
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate 		if (scf_iter_service_instances(iiter, g_svc) != 0) {
5777c478bd9Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_DELETED)
5787c478bd9Sstevel@tonic-gate 				scfdie();
5797c478bd9Sstevel@tonic-gate 			continue;
5807c478bd9Sstevel@tonic-gate 		}
5817c478bd9Sstevel@tonic-gate 
5827c478bd9Sstevel@tonic-gate 		for (;;) {
5837c478bd9Sstevel@tonic-gate 			r = scf_iter_next_instance(iiter, g_inst);
5847c478bd9Sstevel@tonic-gate 			if (r == 0)
5857c478bd9Sstevel@tonic-gate 				break;
5867c478bd9Sstevel@tonic-gate 			if (r != 1) {
5877c478bd9Sstevel@tonic-gate 				if (scf_error() != SCF_ERROR_DELETED)
5887c478bd9Sstevel@tonic-gate 					scfdie();
5897c478bd9Sstevel@tonic-gate 				break;
5907c478bd9Sstevel@tonic-gate 			}
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate 			if (scf_instance_get_name(g_inst, instname,
5937c478bd9Sstevel@tonic-gate 			    max_scf_name_length + 1) < 0) {
5947c478bd9Sstevel@tonic-gate 				if (scf_error() != SCF_ERROR_DELETED)
5957c478bd9Sstevel@tonic-gate 					scfdie();
5967c478bd9Sstevel@tonic-gate 				continue;
5977c478bd9Sstevel@tonic-gate 			}
5987c478bd9Sstevel@tonic-gate 
5997c478bd9Sstevel@tonic-gate 			add_instance(svcname, instname, g_inst);
6007c478bd9Sstevel@tonic-gate 		}
6017c478bd9Sstevel@tonic-gate 	}
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate 	free(svcname);
6047c478bd9Sstevel@tonic-gate 	free(instname);
6057c478bd9Sstevel@tonic-gate 	scf_iter_destroy(siter);
6067c478bd9Sstevel@tonic-gate 	scf_iter_destroy(iiter);
6077c478bd9Sstevel@tonic-gate }
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate /*
6107c478bd9Sstevel@tonic-gate  * Dependency analysis routines.
6117c478bd9Sstevel@tonic-gate  */
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate static void
add_svcptr(uu_list_t * lst,inst_t * svcp)6147c478bd9Sstevel@tonic-gate add_svcptr(uu_list_t *lst, inst_t *svcp)
6157c478bd9Sstevel@tonic-gate {
6167c478bd9Sstevel@tonic-gate 	struct svcptr *spp;
6177c478bd9Sstevel@tonic-gate 	uu_list_index_t idx;
6187c478bd9Sstevel@tonic-gate 	int r;
6197c478bd9Sstevel@tonic-gate 
6207c478bd9Sstevel@tonic-gate 	spp = safe_malloc(sizeof (*spp));
6217c478bd9Sstevel@tonic-gate 	spp->svcp = svcp;
6227c478bd9Sstevel@tonic-gate 	spp->next_hop = NULL;
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate 	if (uu_list_find(lst, spp, NULL, &idx) != NULL) {
6257c478bd9Sstevel@tonic-gate 		free(spp);
6267c478bd9Sstevel@tonic-gate 		return;
6277c478bd9Sstevel@tonic-gate 	}
6287c478bd9Sstevel@tonic-gate 
6297c478bd9Sstevel@tonic-gate 	uu_list_node_init(spp, &spp->node, svcptrs);
6307c478bd9Sstevel@tonic-gate 	r = uu_list_append(lst, spp);
6317c478bd9Sstevel@tonic-gate 	assert(r == 0);
6327c478bd9Sstevel@tonic-gate }
6337c478bd9Sstevel@tonic-gate 
6347c478bd9Sstevel@tonic-gate static int determine_causes(inst_t *, void *);
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate /*
6377c478bd9Sstevel@tonic-gate  * Determine the causes of src and add them to the causes list of dst.
6387c478bd9Sstevel@tonic-gate  * Returns ELOOP if src is active, and 0 otherwise.
6397c478bd9Sstevel@tonic-gate  */
6407c478bd9Sstevel@tonic-gate static int
add_causes(inst_t * dst,inst_t * src)6417c478bd9Sstevel@tonic-gate add_causes(inst_t *dst, inst_t *src)
6427c478bd9Sstevel@tonic-gate {
6437c478bd9Sstevel@tonic-gate 	struct svcptr *spp, *copy;
6447c478bd9Sstevel@tonic-gate 	uu_list_index_t idx;
6457c478bd9Sstevel@tonic-gate 
6467c478bd9Sstevel@tonic-gate 	if (determine_causes(src, (void *)1) != UU_WALK_NEXT) {
6477c478bd9Sstevel@tonic-gate 		/* Dependency cycle. */
6487c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "  svc:/%s:%s\n", dst->svcname,
6497c478bd9Sstevel@tonic-gate 		    dst->instname);
6507c478bd9Sstevel@tonic-gate 		return (ELOOP);
6517c478bd9Sstevel@tonic-gate 	}
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate 	add_svcptr(src->impact_dependents, dst);
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate 	for (spp = uu_list_first(src->causes);
6567c478bd9Sstevel@tonic-gate 	    spp != NULL;
6577c478bd9Sstevel@tonic-gate 	    spp = uu_list_next(src->causes, spp)) {
6587c478bd9Sstevel@tonic-gate 		if (uu_list_find(dst->causes, spp, NULL, &idx) != NULL)
6597c478bd9Sstevel@tonic-gate 			continue;
6607c478bd9Sstevel@tonic-gate 
6617c478bd9Sstevel@tonic-gate 		copy = safe_malloc(sizeof (*copy));
6627c478bd9Sstevel@tonic-gate 		copy->svcp = spp->svcp;
6637c478bd9Sstevel@tonic-gate 		copy->next_hop = src;
6647c478bd9Sstevel@tonic-gate 		uu_list_node_init(copy, &copy->node, svcptrs);
6657c478bd9Sstevel@tonic-gate 		uu_list_insert(dst->causes, copy, idx);
6667c478bd9Sstevel@tonic-gate 
6677c478bd9Sstevel@tonic-gate 		add_svcptr(g_causes, spp->svcp);
6687c478bd9Sstevel@tonic-gate 	}
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate 	return (0);
6717c478bd9Sstevel@tonic-gate }
6727c478bd9Sstevel@tonic-gate 
6737c478bd9Sstevel@tonic-gate static int
inst_running(inst_t * ip)6747c478bd9Sstevel@tonic-gate inst_running(inst_t *ip)
6757c478bd9Sstevel@tonic-gate {
6767c478bd9Sstevel@tonic-gate 	return (strcmp(ip->state, SCF_STATE_STRING_ONLINE) == 0 ||
6777c478bd9Sstevel@tonic-gate 	    strcmp(ip->state, SCF_STATE_STRING_DEGRADED) == 0);
6787c478bd9Sstevel@tonic-gate }
6797c478bd9Sstevel@tonic-gate 
6807c478bd9Sstevel@tonic-gate static int
inst_running_or_maint(inst_t * ip)6817c478bd9Sstevel@tonic-gate inst_running_or_maint(inst_t *ip)
6827c478bd9Sstevel@tonic-gate {
6837c478bd9Sstevel@tonic-gate 	return (inst_running(ip) ||
6847c478bd9Sstevel@tonic-gate 	    strcmp(ip->state, SCF_STATE_STRING_MAINT) == 0);
6857c478bd9Sstevel@tonic-gate }
6867c478bd9Sstevel@tonic-gate 
6877c478bd9Sstevel@tonic-gate static svc_t *
get_svc(const char * sn)6887c478bd9Sstevel@tonic-gate get_svc(const char *sn)
6897c478bd9Sstevel@tonic-gate {
6907c478bd9Sstevel@tonic-gate 	uint32_t h;
6917c478bd9Sstevel@tonic-gate 	svc_t *svcp;
6927c478bd9Sstevel@tonic-gate 
6937c478bd9Sstevel@tonic-gate 	h = hash_name(sn) & SVC_HASH_MASK;
6947c478bd9Sstevel@tonic-gate 
6957c478bd9Sstevel@tonic-gate 	for (svcp = services[h]; svcp != NULL; svcp = svcp->next) {
6967c478bd9Sstevel@tonic-gate 		if (strcmp(svcp->svcname, sn) == 0)
6977c478bd9Sstevel@tonic-gate 			break;
6987c478bd9Sstevel@tonic-gate 	}
6997c478bd9Sstevel@tonic-gate 
7007c478bd9Sstevel@tonic-gate 	return (svcp);
7017c478bd9Sstevel@tonic-gate }
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate /* ARGSUSED */
7047c478bd9Sstevel@tonic-gate static inst_t *
get_inst(svc_t * svcp,const char * in)7057c478bd9Sstevel@tonic-gate get_inst(svc_t *svcp, const char *in)
7067c478bd9Sstevel@tonic-gate {
7077c478bd9Sstevel@tonic-gate 	inst_t *instp;
7087c478bd9Sstevel@tonic-gate 
7097c478bd9Sstevel@tonic-gate 	for (instp = uu_list_first(svcp->instances);
7107c478bd9Sstevel@tonic-gate 	    instp != NULL;
7117c478bd9Sstevel@tonic-gate 	    instp = uu_list_next(svcp->instances, instp)) {
7127c478bd9Sstevel@tonic-gate 		if (strcmp(instp->instname, in) == 0)
7137c478bd9Sstevel@tonic-gate 			return (instp);
7147c478bd9Sstevel@tonic-gate 	}
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate 	return (NULL);
7177c478bd9Sstevel@tonic-gate }
7187c478bd9Sstevel@tonic-gate 
7197c478bd9Sstevel@tonic-gate static int
get_fmri(const char * fmri,svc_t ** spp,inst_t ** ipp)7207c478bd9Sstevel@tonic-gate get_fmri(const char *fmri, svc_t **spp, inst_t **ipp)
7217c478bd9Sstevel@tonic-gate {
7227c478bd9Sstevel@tonic-gate 	const char *sn, *in;
7237c478bd9Sstevel@tonic-gate 	svc_t *sp;
7247c478bd9Sstevel@tonic-gate 	inst_t *ip;
7257c478bd9Sstevel@tonic-gate 
7267c478bd9Sstevel@tonic-gate 	if (strlcpy(g_fmri, fmri, g_fmri_sz) >= g_fmri_sz)
7277c478bd9Sstevel@tonic-gate 		return (EINVAL);
7287c478bd9Sstevel@tonic-gate 
7297c478bd9Sstevel@tonic-gate 	if (scf_parse_svc_fmri(g_fmri, NULL, &sn, &in, NULL, NULL) != 0)
7307c478bd9Sstevel@tonic-gate 		return (EINVAL);
7317c478bd9Sstevel@tonic-gate 
7327c478bd9Sstevel@tonic-gate 	if (sn == NULL)
7337c478bd9Sstevel@tonic-gate 		return (EINVAL);
7347c478bd9Sstevel@tonic-gate 
7357c478bd9Sstevel@tonic-gate 	sp = get_svc(sn);
7367c478bd9Sstevel@tonic-gate 	if (sp == NULL)
7377c478bd9Sstevel@tonic-gate 		return (ENOENT);
7387c478bd9Sstevel@tonic-gate 
7397c478bd9Sstevel@tonic-gate 	if (in != NULL) {
7407c478bd9Sstevel@tonic-gate 		ip = get_inst(sp, in);
7417c478bd9Sstevel@tonic-gate 		if (ip == NULL)
7427c478bd9Sstevel@tonic-gate 			return (ENOENT);
7437c478bd9Sstevel@tonic-gate 	}
7447c478bd9Sstevel@tonic-gate 
7457c478bd9Sstevel@tonic-gate 	if (spp != NULL)
7467c478bd9Sstevel@tonic-gate 		*spp = sp;
7477c478bd9Sstevel@tonic-gate 	if (ipp != NULL)
7487c478bd9Sstevel@tonic-gate 		*ipp = ((in == NULL) ? NULL : ip);
7497c478bd9Sstevel@tonic-gate 
7507c478bd9Sstevel@tonic-gate 	return (0);
7517c478bd9Sstevel@tonic-gate }
7527c478bd9Sstevel@tonic-gate 
7537c478bd9Sstevel@tonic-gate static int
process_reqall(inst_t * svcp,struct dependency_group * dg)7547c478bd9Sstevel@tonic-gate process_reqall(inst_t *svcp, struct dependency_group *dg)
7557c478bd9Sstevel@tonic-gate {
7567c478bd9Sstevel@tonic-gate 	uu_list_walk_t *walk;
7577c478bd9Sstevel@tonic-gate 	struct dependency *d;
7587c478bd9Sstevel@tonic-gate 	int r, svcrunning;
7597c478bd9Sstevel@tonic-gate 	svc_t *sp;
7607c478bd9Sstevel@tonic-gate 	inst_t *ip;
7617c478bd9Sstevel@tonic-gate 
7627c478bd9Sstevel@tonic-gate 	walk = uu_list_walk_start(dg->entities, UU_WALK_ROBUST);
7637c478bd9Sstevel@tonic-gate 	if (walk == NULL)
7647c478bd9Sstevel@tonic-gate 		uu_die(emsg_nomem);
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate 	while ((d = uu_list_walk_next(walk)) != NULL) {
7677c478bd9Sstevel@tonic-gate 		r = get_fmri(d->fmri, &sp, &ip);
7687c478bd9Sstevel@tonic-gate 		switch (r) {
7697c478bd9Sstevel@tonic-gate 		case EINVAL:
7707c478bd9Sstevel@tonic-gate 			/* LINTED */
7717c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, emsg_invalid_dep, svcp->svcname,
7727c478bd9Sstevel@tonic-gate 			    svcp->instname, d->fmri);
7737c478bd9Sstevel@tonic-gate 			continue;
7747c478bd9Sstevel@tonic-gate 
7757c478bd9Sstevel@tonic-gate 		case ENOENT:
7767c478bd9Sstevel@tonic-gate 			uu_list_remove(dg->entities, d);
7777c478bd9Sstevel@tonic-gate 			r = uu_list_append(svcp->baddeps, d);
7787c478bd9Sstevel@tonic-gate 			assert(r == 0);
7797c478bd9Sstevel@tonic-gate 			continue;
7807c478bd9Sstevel@tonic-gate 
7817c478bd9Sstevel@tonic-gate 		case 0:
7827c478bd9Sstevel@tonic-gate 			break;
7837c478bd9Sstevel@tonic-gate 
7847c478bd9Sstevel@tonic-gate 		default:
7857c478bd9Sstevel@tonic-gate 			bad_error("get_fmri", r);
7867c478bd9Sstevel@tonic-gate 		}
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate 		if (ip != NULL) {
7897c478bd9Sstevel@tonic-gate 			if (inst_running(ip))
7907c478bd9Sstevel@tonic-gate 				continue;
7917c478bd9Sstevel@tonic-gate 			r = add_causes(svcp, ip);
7927c478bd9Sstevel@tonic-gate 			if (r != 0) {
7937c478bd9Sstevel@tonic-gate 				assert(r == ELOOP);
7947c478bd9Sstevel@tonic-gate 				return (r);
7957c478bd9Sstevel@tonic-gate 			}
7967c478bd9Sstevel@tonic-gate 			continue;
7977c478bd9Sstevel@tonic-gate 		}
7987c478bd9Sstevel@tonic-gate 
7997c478bd9Sstevel@tonic-gate 		svcrunning = 0;
8007c478bd9Sstevel@tonic-gate 
8017c478bd9Sstevel@tonic-gate 		for (ip = uu_list_first(sp->instances);
8027c478bd9Sstevel@tonic-gate 		    ip != NULL;
8037c478bd9Sstevel@tonic-gate 		    ip = uu_list_next(sp->instances, ip)) {
8047c478bd9Sstevel@tonic-gate 			if (inst_running(ip))
8057c478bd9Sstevel@tonic-gate 				svcrunning = 1;
8067c478bd9Sstevel@tonic-gate 		}
8077c478bd9Sstevel@tonic-gate 
8087c478bd9Sstevel@tonic-gate 		if (!svcrunning) {
8097c478bd9Sstevel@tonic-gate 			for (ip = uu_list_first(sp->instances);
8107c478bd9Sstevel@tonic-gate 			    ip != NULL;
8117c478bd9Sstevel@tonic-gate 			    ip = uu_list_next(sp->instances, ip)) {
8127c478bd9Sstevel@tonic-gate 				r = add_causes(svcp, ip);
8137c478bd9Sstevel@tonic-gate 				if (r != 0) {
8147c478bd9Sstevel@tonic-gate 					assert(r == ELOOP);
8157c478bd9Sstevel@tonic-gate 					uu_list_walk_end(walk);
8167c478bd9Sstevel@tonic-gate 					return (r);
8177c478bd9Sstevel@tonic-gate 				}
8187c478bd9Sstevel@tonic-gate 			}
8197c478bd9Sstevel@tonic-gate 		}
8207c478bd9Sstevel@tonic-gate 	}
8217c478bd9Sstevel@tonic-gate 
8227c478bd9Sstevel@tonic-gate 	uu_list_walk_end(walk);
8237c478bd9Sstevel@tonic-gate 	return (0);
8247c478bd9Sstevel@tonic-gate }
8257c478bd9Sstevel@tonic-gate 
8267c478bd9Sstevel@tonic-gate static int
process_reqany(inst_t * svcp,struct dependency_group * dg)8277c478bd9Sstevel@tonic-gate process_reqany(inst_t *svcp, struct dependency_group *dg)
8287c478bd9Sstevel@tonic-gate {
8297c478bd9Sstevel@tonic-gate 	svc_t *sp;
8307c478bd9Sstevel@tonic-gate 	inst_t *ip;
8317c478bd9Sstevel@tonic-gate 	struct dependency *d;
8327c478bd9Sstevel@tonic-gate 	int r;
8337c478bd9Sstevel@tonic-gate 	uu_list_walk_t *walk;
8347c478bd9Sstevel@tonic-gate 
8357c478bd9Sstevel@tonic-gate 	for (d = uu_list_first(dg->entities);
8367c478bd9Sstevel@tonic-gate 	    d != NULL;
8377c478bd9Sstevel@tonic-gate 	    d = uu_list_next(dg->entities, d)) {
8387c478bd9Sstevel@tonic-gate 		r = get_fmri(d->fmri, &sp, &ip);
8397c478bd9Sstevel@tonic-gate 		switch (r) {
8407c478bd9Sstevel@tonic-gate 		case 0:
8417c478bd9Sstevel@tonic-gate 			break;
8427c478bd9Sstevel@tonic-gate 
8437c478bd9Sstevel@tonic-gate 		case EINVAL:
8447c478bd9Sstevel@tonic-gate 			/* LINTED */
8457c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, emsg_invalid_dep, svcp->svcname,
8467c478bd9Sstevel@tonic-gate 			    svcp->instname, d->fmri);
8477c478bd9Sstevel@tonic-gate 			continue;
8487c478bd9Sstevel@tonic-gate 
8497c478bd9Sstevel@tonic-gate 		case ENOENT:
8507c478bd9Sstevel@tonic-gate 			continue;
8517c478bd9Sstevel@tonic-gate 
8527c478bd9Sstevel@tonic-gate 		default:
8537c478bd9Sstevel@tonic-gate 			bad_error("eval_svc_dep", r);
8547c478bd9Sstevel@tonic-gate 		}
8557c478bd9Sstevel@tonic-gate 
8567c478bd9Sstevel@tonic-gate 		if (ip != NULL) {
8577c478bd9Sstevel@tonic-gate 			if (inst_running(ip))
8587c478bd9Sstevel@tonic-gate 				return (0);
8597c478bd9Sstevel@tonic-gate 			continue;
8607c478bd9Sstevel@tonic-gate 		}
8617c478bd9Sstevel@tonic-gate 
8627c478bd9Sstevel@tonic-gate 		for (ip = uu_list_first(sp->instances);
8637c478bd9Sstevel@tonic-gate 		    ip != NULL;
8647c478bd9Sstevel@tonic-gate 		    ip = uu_list_next(sp->instances, ip)) {
8657c478bd9Sstevel@tonic-gate 			if (inst_running(ip))
8667c478bd9Sstevel@tonic-gate 				return (0);
8677c478bd9Sstevel@tonic-gate 		}
8687c478bd9Sstevel@tonic-gate 	}
8697c478bd9Sstevel@tonic-gate 
8707c478bd9Sstevel@tonic-gate 	/*
8717c478bd9Sstevel@tonic-gate 	 * The dependency group is not satisfied.  Add all unsatisfied members
8727c478bd9Sstevel@tonic-gate 	 * to the cause list.
8737c478bd9Sstevel@tonic-gate 	 */
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate 	walk = uu_list_walk_start(dg->entities, UU_WALK_ROBUST);
8767c478bd9Sstevel@tonic-gate 	if (walk == NULL)
8777c478bd9Sstevel@tonic-gate 		uu_die(emsg_nomem);
8787c478bd9Sstevel@tonic-gate 
8797c478bd9Sstevel@tonic-gate 	while ((d = uu_list_walk_next(walk)) != NULL) {
8807c478bd9Sstevel@tonic-gate 		r = get_fmri(d->fmri, &sp, &ip);
8817c478bd9Sstevel@tonic-gate 		switch (r) {
8827c478bd9Sstevel@tonic-gate 		case 0:
8837c478bd9Sstevel@tonic-gate 			break;
8847c478bd9Sstevel@tonic-gate 
8857c478bd9Sstevel@tonic-gate 		case ENOENT:
8867c478bd9Sstevel@tonic-gate 			uu_list_remove(dg->entities, d);
8877c478bd9Sstevel@tonic-gate 			r = uu_list_append(svcp->baddeps, d);
8887c478bd9Sstevel@tonic-gate 			assert(r == 0);
8897c478bd9Sstevel@tonic-gate 			continue;
8907c478bd9Sstevel@tonic-gate 
8917c478bd9Sstevel@tonic-gate 		case EINVAL:
8927c478bd9Sstevel@tonic-gate 			/* Should have caught above. */
8937c478bd9Sstevel@tonic-gate 		default:
8947c478bd9Sstevel@tonic-gate 			bad_error("eval_svc_dep", r);
8957c478bd9Sstevel@tonic-gate 		}
8967c478bd9Sstevel@tonic-gate 
8977c478bd9Sstevel@tonic-gate 		if (ip != NULL) {
8987c478bd9Sstevel@tonic-gate 			if (inst_running(ip))
8997c478bd9Sstevel@tonic-gate 				continue;
9007c478bd9Sstevel@tonic-gate 			r = add_causes(svcp, ip);
9017c478bd9Sstevel@tonic-gate 			if (r != 0) {
9027c478bd9Sstevel@tonic-gate 				assert(r == ELOOP);
9037c478bd9Sstevel@tonic-gate 				return (r);
9047c478bd9Sstevel@tonic-gate 			}
9057c478bd9Sstevel@tonic-gate 			continue;
9067c478bd9Sstevel@tonic-gate 		}
9077c478bd9Sstevel@tonic-gate 
9087c478bd9Sstevel@tonic-gate 		for (ip = uu_list_first(sp->instances);
9097c478bd9Sstevel@tonic-gate 		    ip != NULL;
9107c478bd9Sstevel@tonic-gate 		    ip = uu_list_next(sp->instances, ip)) {
9117c478bd9Sstevel@tonic-gate 			if (inst_running(ip))
9127c478bd9Sstevel@tonic-gate 				continue;
9137c478bd9Sstevel@tonic-gate 			r = add_causes(svcp, ip);
9147c478bd9Sstevel@tonic-gate 			if (r != 0) {
9157c478bd9Sstevel@tonic-gate 				assert(r == ELOOP);
9167c478bd9Sstevel@tonic-gate 				return (r);
9177c478bd9Sstevel@tonic-gate 			}
9187c478bd9Sstevel@tonic-gate 		}
9197c478bd9Sstevel@tonic-gate 	}
9207c478bd9Sstevel@tonic-gate 
9217c478bd9Sstevel@tonic-gate 	return (0);
9227c478bd9Sstevel@tonic-gate }
9237c478bd9Sstevel@tonic-gate 
9247c478bd9Sstevel@tonic-gate static int
process_optall(inst_t * svcp,struct dependency_group * dg)9257c478bd9Sstevel@tonic-gate process_optall(inst_t *svcp, struct dependency_group *dg)
9267c478bd9Sstevel@tonic-gate {
9277c478bd9Sstevel@tonic-gate 	uu_list_walk_t *walk;
9287c478bd9Sstevel@tonic-gate 	struct dependency *d;
9297c478bd9Sstevel@tonic-gate 	int r;
9307c478bd9Sstevel@tonic-gate 	inst_t *ip;
9317c478bd9Sstevel@tonic-gate 	svc_t *sp;
9327c478bd9Sstevel@tonic-gate 
9337c478bd9Sstevel@tonic-gate 	walk = uu_list_walk_start(dg->entities, UU_WALK_ROBUST);
9347c478bd9Sstevel@tonic-gate 	if (walk == NULL)
9357c478bd9Sstevel@tonic-gate 		uu_die(emsg_nomem);
9367c478bd9Sstevel@tonic-gate 
9377c478bd9Sstevel@tonic-gate 	while ((d = uu_list_walk_next(walk)) != NULL) {
9387c478bd9Sstevel@tonic-gate 		r = get_fmri(d->fmri, &sp, &ip);
9397c478bd9Sstevel@tonic-gate 
9407c478bd9Sstevel@tonic-gate 		switch (r) {
9417c478bd9Sstevel@tonic-gate 		case 0:
9427c478bd9Sstevel@tonic-gate 			break;
9437c478bd9Sstevel@tonic-gate 
9447c478bd9Sstevel@tonic-gate 		case EINVAL:
9457c478bd9Sstevel@tonic-gate 			/* LINTED */
9467c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, emsg_invalid_dep, svcp->svcname,
9477c478bd9Sstevel@tonic-gate 			    svcp->instname, d->fmri);
9487c478bd9Sstevel@tonic-gate 			continue;
9497c478bd9Sstevel@tonic-gate 
9507c478bd9Sstevel@tonic-gate 		case ENOENT:
9517c478bd9Sstevel@tonic-gate 			continue;
9527c478bd9Sstevel@tonic-gate 
9537c478bd9Sstevel@tonic-gate 		default:
9547c478bd9Sstevel@tonic-gate 			bad_error("get_fmri", r);
9557c478bd9Sstevel@tonic-gate 		}
9567c478bd9Sstevel@tonic-gate 
9577c478bd9Sstevel@tonic-gate 		if (ip != NULL) {
9582e1a9474SLiane Praza 			if ((ip->enabled != 0) && !inst_running_or_maint(ip)) {
9597c478bd9Sstevel@tonic-gate 				r = add_causes(svcp, ip);
9607c478bd9Sstevel@tonic-gate 				if (r != 0) {
9617c478bd9Sstevel@tonic-gate 					assert(r == ELOOP);
9627c478bd9Sstevel@tonic-gate 					uu_list_walk_end(walk);
9637c478bd9Sstevel@tonic-gate 					return (r);
9647c478bd9Sstevel@tonic-gate 				}
9657c478bd9Sstevel@tonic-gate 			}
9667c478bd9Sstevel@tonic-gate 			continue;
9677c478bd9Sstevel@tonic-gate 		}
9687c478bd9Sstevel@tonic-gate 
9697c478bd9Sstevel@tonic-gate 		for (ip = uu_list_first(sp->instances);
9707c478bd9Sstevel@tonic-gate 		    ip != NULL;
9717c478bd9Sstevel@tonic-gate 		    ip = uu_list_next(sp->instances, ip)) {
9722e1a9474SLiane Praza 			if ((ip->enabled != 0) && !inst_running_or_maint(ip)) {
9737c478bd9Sstevel@tonic-gate 				r = add_causes(svcp, ip);
9747c478bd9Sstevel@tonic-gate 				if (r != 0) {
9757c478bd9Sstevel@tonic-gate 					assert(r == ELOOP);
9767c478bd9Sstevel@tonic-gate 					uu_list_walk_end(walk);
9777c478bd9Sstevel@tonic-gate 					return (r);
9787c478bd9Sstevel@tonic-gate 				}
9797c478bd9Sstevel@tonic-gate 			}
9807c478bd9Sstevel@tonic-gate 		}
9817c478bd9Sstevel@tonic-gate 	}
9827c478bd9Sstevel@tonic-gate 
9837c478bd9Sstevel@tonic-gate 	uu_list_walk_end(walk);
9847c478bd9Sstevel@tonic-gate 	return (0);
9857c478bd9Sstevel@tonic-gate }
9867c478bd9Sstevel@tonic-gate 
9877c478bd9Sstevel@tonic-gate static int
process_excall(inst_t * svcp,struct dependency_group * dg)9887c478bd9Sstevel@tonic-gate process_excall(inst_t *svcp, struct dependency_group *dg)
9897c478bd9Sstevel@tonic-gate {
9907c478bd9Sstevel@tonic-gate 	struct dependency *d;
9917c478bd9Sstevel@tonic-gate 	int r;
9927c478bd9Sstevel@tonic-gate 	svc_t *sp;
9937c478bd9Sstevel@tonic-gate 	inst_t *ip;
9947c478bd9Sstevel@tonic-gate 
9957c478bd9Sstevel@tonic-gate 	for (d = uu_list_first(dg->entities);
9967c478bd9Sstevel@tonic-gate 	    d != NULL;
9977c478bd9Sstevel@tonic-gate 	    d = uu_list_next(dg->entities, d)) {
9987c478bd9Sstevel@tonic-gate 		r = get_fmri(d->fmri, &sp, &ip);
9997c478bd9Sstevel@tonic-gate 
10007c478bd9Sstevel@tonic-gate 		switch (r) {
10017c478bd9Sstevel@tonic-gate 		case 0:
10027c478bd9Sstevel@tonic-gate 			break;
10037c478bd9Sstevel@tonic-gate 
10047c478bd9Sstevel@tonic-gate 		case EINVAL:
10057c478bd9Sstevel@tonic-gate 			/* LINTED */
10067c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, emsg_invalid_dep, svcp->svcname,
10077c478bd9Sstevel@tonic-gate 			    svcp->instname, d->fmri);
10087c478bd9Sstevel@tonic-gate 			continue;
10097c478bd9Sstevel@tonic-gate 
10107c478bd9Sstevel@tonic-gate 		case ENOENT:
10117c478bd9Sstevel@tonic-gate 			continue;
10127c478bd9Sstevel@tonic-gate 
10137c478bd9Sstevel@tonic-gate 		default:
10147c478bd9Sstevel@tonic-gate 			bad_error("eval_svc_dep", r);
10157c478bd9Sstevel@tonic-gate 		}
10167c478bd9Sstevel@tonic-gate 
10177c478bd9Sstevel@tonic-gate 		if (ip != NULL) {
10187c478bd9Sstevel@tonic-gate 			if (inst_running(ip)) {
10197c478bd9Sstevel@tonic-gate 				r = add_causes(svcp, ip);
10207c478bd9Sstevel@tonic-gate 				if (r != 0) {
10217c478bd9Sstevel@tonic-gate 					assert(r == ELOOP);
10227c478bd9Sstevel@tonic-gate 					return (r);
10237c478bd9Sstevel@tonic-gate 				}
10247c478bd9Sstevel@tonic-gate 			}
10257c478bd9Sstevel@tonic-gate 			continue;
10267c478bd9Sstevel@tonic-gate 		}
10277c478bd9Sstevel@tonic-gate 
10287c478bd9Sstevel@tonic-gate 		for (ip = uu_list_first(sp->instances);
10297c478bd9Sstevel@tonic-gate 		    ip != NULL;
10307c478bd9Sstevel@tonic-gate 		    ip = uu_list_next(sp->instances, ip)) {
10317c478bd9Sstevel@tonic-gate 			if (inst_running(ip)) {
10327c478bd9Sstevel@tonic-gate 				r = add_causes(svcp, ip);
10337c478bd9Sstevel@tonic-gate 				if (r != 0) {
10347c478bd9Sstevel@tonic-gate 					assert(r == ELOOP);
10357c478bd9Sstevel@tonic-gate 					return (r);
10367c478bd9Sstevel@tonic-gate 				}
10377c478bd9Sstevel@tonic-gate 			}
10387c478bd9Sstevel@tonic-gate 		}
10397c478bd9Sstevel@tonic-gate 	}
10407c478bd9Sstevel@tonic-gate 
10417c478bd9Sstevel@tonic-gate 	return (0);
10427c478bd9Sstevel@tonic-gate }
10437c478bd9Sstevel@tonic-gate 
10447c478bd9Sstevel@tonic-gate static int
process_svc_dg(inst_t * svcp,struct dependency_group * dg)10457c478bd9Sstevel@tonic-gate process_svc_dg(inst_t *svcp, struct dependency_group *dg)
10467c478bd9Sstevel@tonic-gate {
10477c478bd9Sstevel@tonic-gate 	switch (dg->grouping) {
10487c478bd9Sstevel@tonic-gate 	case DGG_REQALL:
10497c478bd9Sstevel@tonic-gate 		return (process_reqall(svcp, dg));
10507c478bd9Sstevel@tonic-gate 
10517c478bd9Sstevel@tonic-gate 	case DGG_REQANY:
10527c478bd9Sstevel@tonic-gate 		return (process_reqany(svcp, dg));
10537c478bd9Sstevel@tonic-gate 
10547c478bd9Sstevel@tonic-gate 	case DGG_OPTALL:
10557c478bd9Sstevel@tonic-gate 		return (process_optall(svcp, dg));
10567c478bd9Sstevel@tonic-gate 
10577c478bd9Sstevel@tonic-gate 	case DGG_EXCALL:
10587c478bd9Sstevel@tonic-gate 		return (process_excall(svcp, dg));
10597c478bd9Sstevel@tonic-gate 
10607c478bd9Sstevel@tonic-gate 	default:
10617c478bd9Sstevel@tonic-gate #ifndef NDEBUG
10627c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
10637c478bd9Sstevel@tonic-gate 		    "%s:%d: Unknown dependency grouping %d.\n", __FILE__,
10647c478bd9Sstevel@tonic-gate 		    __LINE__, dg->grouping);
10657c478bd9Sstevel@tonic-gate #endif
10667c478bd9Sstevel@tonic-gate 		abort();
10677c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
10687c478bd9Sstevel@tonic-gate 	}
10697c478bd9Sstevel@tonic-gate }
10707c478bd9Sstevel@tonic-gate 
10717c478bd9Sstevel@tonic-gate /*
10727c478bd9Sstevel@tonic-gate  * Returns
10737c478bd9Sstevel@tonic-gate  *   EINVAL - fmri is not a valid FMRI
10747c478bd9Sstevel@tonic-gate  *   0 - the file indicated by fmri is missing
10757c478bd9Sstevel@tonic-gate  *   1 - the file indicated by fmri is present
10767c478bd9Sstevel@tonic-gate  */
10777c478bd9Sstevel@tonic-gate static int
eval_file_dep(const char * fmri)10787c478bd9Sstevel@tonic-gate eval_file_dep(const char *fmri)
10797c478bd9Sstevel@tonic-gate {
10807c478bd9Sstevel@tonic-gate 	const char *path;
10817c478bd9Sstevel@tonic-gate 	struct stat st;
10827c478bd9Sstevel@tonic-gate 
10837c478bd9Sstevel@tonic-gate 	if (strncmp(fmri, "file:", sizeof ("file:") - 1) != 0)
10847c478bd9Sstevel@tonic-gate 		return (EINVAL);
10857c478bd9Sstevel@tonic-gate 
10867c478bd9Sstevel@tonic-gate 	path = fmri + (sizeof ("file:") - 1);
10877c478bd9Sstevel@tonic-gate 
10887c478bd9Sstevel@tonic-gate 	if (path[0] != '/')
10897c478bd9Sstevel@tonic-gate 		return (EINVAL);
10907c478bd9Sstevel@tonic-gate 
10917c478bd9Sstevel@tonic-gate 	if (path[1] == '/') {
10927c478bd9Sstevel@tonic-gate 		path += 2;
10937c478bd9Sstevel@tonic-gate 		if (strncmp(path, "localhost/", sizeof ("localhost/") - 1) == 0)
10947c478bd9Sstevel@tonic-gate 			path += sizeof ("localhost") - 1;
10957c478bd9Sstevel@tonic-gate 		else if (path[0] != '/')
10967c478bd9Sstevel@tonic-gate 			return (EINVAL);
10977c478bd9Sstevel@tonic-gate 	}
10987c478bd9Sstevel@tonic-gate 
10997c478bd9Sstevel@tonic-gate 	return (stat(path, &st) == 0 ? 1 : 0);
11007c478bd9Sstevel@tonic-gate }
11017c478bd9Sstevel@tonic-gate 
11027c478bd9Sstevel@tonic-gate static void
process_file_dg(inst_t * svcp,struct dependency_group * dg)11037c478bd9Sstevel@tonic-gate process_file_dg(inst_t *svcp, struct dependency_group *dg)
11047c478bd9Sstevel@tonic-gate {
11057c478bd9Sstevel@tonic-gate 	uu_list_walk_t *walk;
11067c478bd9Sstevel@tonic-gate 	struct dependency *d, **deps;
11077c478bd9Sstevel@tonic-gate 	int r, i = 0, any_satisfied = 0;
11087c478bd9Sstevel@tonic-gate 
11097c478bd9Sstevel@tonic-gate 	if (dg->grouping == DGG_REQANY) {
11107c478bd9Sstevel@tonic-gate 		deps = calloc(uu_list_numnodes(dg->entities), sizeof (*deps));
11117c478bd9Sstevel@tonic-gate 		if (deps == NULL)
11127c478bd9Sstevel@tonic-gate 			uu_die(emsg_nomem);
11137c478bd9Sstevel@tonic-gate 	}
11147c478bd9Sstevel@tonic-gate 
11157c478bd9Sstevel@tonic-gate 	walk = uu_list_walk_start(dg->entities, UU_WALK_ROBUST);
11167c478bd9Sstevel@tonic-gate 	if (walk == NULL)
11177c478bd9Sstevel@tonic-gate 		uu_die(emsg_nomem);
11187c478bd9Sstevel@tonic-gate 
11197c478bd9Sstevel@tonic-gate 	while ((d = uu_list_walk_next(walk)) != NULL) {
11207c478bd9Sstevel@tonic-gate 		r = eval_file_dep(d->fmri);
11217c478bd9Sstevel@tonic-gate 		if (r == EINVAL) {
11227c478bd9Sstevel@tonic-gate 			/* LINTED */
11237c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, emsg_invalid_dep, svcp->svcname,
11247c478bd9Sstevel@tonic-gate 			    svcp->instname, d->fmri);
11257c478bd9Sstevel@tonic-gate 			continue;
11267c478bd9Sstevel@tonic-gate 		}
11277c478bd9Sstevel@tonic-gate 
11287c478bd9Sstevel@tonic-gate 		assert(r == 0 || r == 1);
11297c478bd9Sstevel@tonic-gate 
11307c478bd9Sstevel@tonic-gate 		switch (dg->grouping) {
11317c478bd9Sstevel@tonic-gate 		case DGG_REQALL:
11327c478bd9Sstevel@tonic-gate 		case DGG_OPTALL:
11337c478bd9Sstevel@tonic-gate 			if (r == 0) {
11347c478bd9Sstevel@tonic-gate 				uu_list_remove(dg->entities, d);
11357c478bd9Sstevel@tonic-gate 				r = uu_list_append(svcp->baddeps, d);
11367c478bd9Sstevel@tonic-gate 				assert(r == 0);
11377c478bd9Sstevel@tonic-gate 			}
11387c478bd9Sstevel@tonic-gate 			break;
11397c478bd9Sstevel@tonic-gate 
11407c478bd9Sstevel@tonic-gate 		case DGG_REQANY:
11417c478bd9Sstevel@tonic-gate 			if (r == 1)
11427c478bd9Sstevel@tonic-gate 				any_satisfied = 1;
11437c478bd9Sstevel@tonic-gate 			else
11447c478bd9Sstevel@tonic-gate 				deps[i++] = d;
11457c478bd9Sstevel@tonic-gate 			break;
11467c478bd9Sstevel@tonic-gate 
11477c478bd9Sstevel@tonic-gate 		case DGG_EXCALL:
11487c478bd9Sstevel@tonic-gate 			if (r == 1) {
11497c478bd9Sstevel@tonic-gate 				uu_list_remove(dg->entities, d);
11507c478bd9Sstevel@tonic-gate 				r = uu_list_append(svcp->baddeps, d);
11517c478bd9Sstevel@tonic-gate 				assert(r == 0);
11527c478bd9Sstevel@tonic-gate 			}
11537c478bd9Sstevel@tonic-gate 			break;
11547c478bd9Sstevel@tonic-gate