17c478bdstevel@tonic-gate/*
27c478bdstevel@tonic-gate * CDDL HEADER START
37c478bdstevel@tonic-gate *
47c478bdstevel@tonic-gate * The contents of this file are subject to the terms of the
53eae19dwesolows * Common Development and Distribution License (the "License").
63eae19dwesolows * You may not use this file except in compliance with the License.
77c478bdstevel@tonic-gate *
87c478bdstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bdstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bdstevel@tonic-gate * See the License for the specific language governing permissions
117c478bdstevel@tonic-gate * and limitations under the License.
127c478bdstevel@tonic-gate *
137c478bdstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bdstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bdstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bdstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bdstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bdstevel@tonic-gate *
197c478bdstevel@tonic-gate * CDDL HEADER END
207c478bdstevel@tonic-gate */
213eae19dwesolows
227c478bdstevel@tonic-gate/*
23eb1a346Truong Nguyen * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
247c478bdstevel@tonic-gate * Use is subject to license terms.
2554d0224Bryan Cantrill * Copyright (c) 2015, Joyent, Inc. All rights reserved.
267c478bdstevel@tonic-gate */
277c478bdstevel@tonic-gate
287c478bdstevel@tonic-gate/*
297c478bdstevel@tonic-gate * Service state explanation.  For select services, display a description, the
307c478bdstevel@tonic-gate * state, and possibly why the service is in that state, what's causing it to
317c478bdstevel@tonic-gate * be in that state, and what other services it is keeping offline (impact).
327c478bdstevel@tonic-gate *
337c478bdstevel@tonic-gate * Explaining states other than offline is easy.  For maintenance and
347c478bdstevel@tonic-gate * degraded, we just use the auxiliary state.  For offline, we must determine
357c478bdstevel@tonic-gate * which dependencies are unsatisfied and recurse.  If a causal service is not
367c478bdstevel@tonic-gate * offline, then a svcptr to it is added to the offline service's causes list.
377c478bdstevel@tonic-gate * If a causal service is offline, then we recurse to determine its causes and
387c478bdstevel@tonic-gate * merge them into the causes list of the service in question (see
397c478bdstevel@tonic-gate * add_causes()).  Note that by adding a self-pointing svcptr to the causes
407c478bdstevel@tonic-gate * lists of services which are not offline or are offline for unknown reasons,
417c478bdstevel@tonic-gate * we can always merge the unsatisfied dependency's causes into the
427c478bdstevel@tonic-gate * dependent's list.
437c478bdstevel@tonic-gate *
447c478bdstevel@tonic-gate * Computing an impact list is more involved because the dependencies in the
457c478bdstevel@tonic-gate * repository are unidirectional; it requires determining the causes of all
467c478bdstevel@tonic-gate * offline services.  For each unsatisfied dependency of an offline service,
477c478bdstevel@tonic-gate * a svcptr to the dependent is added to the dependency's impact_dependents
487c478bdstevel@tonic-gate * list (see add_causes()).  determine_impact() uses the lists to build an
497c478bdstevel@tonic-gate * impact list.  The direct dependency is used so that a path from the
507c478bdstevel@tonic-gate * affected service to the causal service can be constructed (see
517c478bdstevel@tonic-gate * print_dependency_reasons()).
527c478bdstevel@tonic-gate *
537c478bdstevel@tonic-gate * Because we always need at least impact counts, we always run
547c478bdstevel@tonic-gate * determine_causes() on all services.
557c478bdstevel@tonic-gate *
567c478bdstevel@tonic-gate * If no arguments are given, we must select the services which are causing
577c478bdstevel@tonic-gate * other services to be offline.  We do so by adding services which are not
587c478bdstevel@tonic-gate * running for any reason other than another service to the g_causes list in
597c478bdstevel@tonic-gate * determine_causes().
607c478bdstevel@tonic-gate *
617c478bdstevel@tonic-gate * Since all services must be examined, and their states may be consulted
627c478bdstevel@tonic-gate * a lot, it is important that we only read volatile data (like states) from
637c478bdstevel@tonic-gate * the repository once.  add_instance() reads data for an instance from the
647c478bdstevel@tonic-gate * repository into an inst_t and puts it into the "services" cache, which is
657c478bdstevel@tonic-gate * organized as a hash table of svc_t's, each of which has a list of inst_t's.
667c478bdstevel@tonic-gate */
677c478bdstevel@tonic-gate
687c478bdstevel@tonic-gate#include "svcs.h"
697c478bdstevel@tonic-gate
707c478bdstevel@tonic-gate#include <sys/stat.h>
717c478bdstevel@tonic-gate#include <sys/wait.h>
727c478bdstevel@tonic-gate
737c478bdstevel@tonic-gate#include <assert.h>
747c478bdstevel@tonic-gate#include <errno.h>
757c478bdstevel@tonic-gate#include <libintl.h>
767c478bdstevel@tonic-gate#include <libuutil.h>
777c478bdstevel@tonic-gate#include <libscf.h>
787c478bdstevel@tonic-gate#include <libscf_priv.h>
797c478bdstevel@tonic-gate#include <string.h>
807c478bdstevel@tonic-gate#include <stdio.h>
817c478bdstevel@tonic-gate#include <stdlib.h>
827c478bdstevel@tonic-gate#include <time.h>
837c478bdstevel@tonic-gate
847c478bdstevel@tonic-gate
857c478bdstevel@tonic-gate#define	DC_DISABLED	"SMF-8000-05"
867c478bdstevel@tonic-gate#define	DC_TEMPDISABLED	"SMF-8000-1S"
877c478bdstevel@tonic-gate#define	DC_RSTRINVALID	"SMF-8000-2A"
887c478bdstevel@tonic-gate#define	DC_RSTRABSENT	"SMF-8000-3P"
897c478bdstevel@tonic-gate#define	DC_UNINIT	"SMF-8000-4D"
907c478bdstevel@tonic-gate#define	DC_RSTRDEAD	"SMF-8000-5H"
917c478bdstevel@tonic-gate#define	DC_ADMINMAINT	"SMF-8000-63"
92eb1a346Truong Nguyen#define	DC_SVCREQMAINT	"SMF-8000-R4"
937c478bdstevel@tonic-gate#define	DC_REPTFAIL	"SMF-8000-7Y"
947c478bdstevel@tonic-gate#define	DC_METHFAIL	"SMF-8000-8Q"
957c478bdstevel@tonic-gate#define	DC_NONE		"SMF-8000-9C"
967c478bdstevel@tonic-gate#define	DC_UNKNOWN	"SMF-8000-AR"
977c478bdstevel@tonic-gate#define	DC_STARTING	"SMF-8000-C4"
987c478bdstevel@tonic-gate#define	DC_ADMINDEGR	"SMF-8000-DX"
997c478bdstevel@tonic-gate#define	DC_DEPABSENT	"SMF-8000-E2"
1007c478bdstevel@tonic-gate#define	DC_DEPRUNNING	"SMF-8000-FJ"
1017c478bdstevel@tonic-gate#define	DC_DEPOTHER	"SMF-8000-GE"
1027c478bdstevel@tonic-gate#define	DC_DEPCYCLE	"SMF-8000-HP"
1037c478bdstevel@tonic-gate#define	DC_INVALIDDEP	"SMF-8000-JA"
1047c478bdstevel@tonic-gate#define	DC_STARTFAIL	"SMF-8000-KS"
1057c478bdstevel@tonic-gate#define	DC_TOOQUICKLY	"SMF-8000-L5"
1067c478bdstevel@tonic-gate#define	DC_INVALIDSTATE	"SMF-8000-N3"
1077c478bdstevel@tonic-gate#define	DC_TRANSITION	"SMF-8000-PH"
1087c478bdstevel@tonic-gate
1097c478bdstevel@tonic-gate#define	DEFAULT_MAN_PATH	"/usr/share/man"
1107c478bdstevel@tonic-gate
111eb1a346Truong Nguyen#define	AUX_STATE_INVALID	"invalid_aux_state"
1127c478bdstevel@tonic-gate
1137c478bdstevel@tonic-gate#define	uu_list_append(lst, e)	uu_list_insert_before(lst, NULL, e)
1147c478bdstevel@tonic-gate
1157c478bdstevel@tonic-gate#define	bad_error(func, err)						\
11654d0224Bryan Cantrill	uu_panic("%s:%d: %s() failed with unknown error %d.\n",		\
11754d0224Bryan Cantrill	    __FILE__, __LINE__, func, err);
1187c478bdstevel@tonic-gate
1197c478bdstevel@tonic-gatetypedef struct {
1207c478bdstevel@tonic-gate	const char *svcname;
1217c478bdstevel@tonic-gate	const char *instname;
1227c478bdstevel@tonic-gate
1237c478bdstevel@tonic-gate	/* restarter pg properties */
1247c478bdstevel@tonic-gate	char state[MAX_SCF_STATE_STRING_SZ];
1257c478bdstevel@tonic-gate	char next_state[MAX_SCF_STATE_STRING_SZ];
1267c478bdstevel@tonic-gate	struct timeval stime;
1277c478bdstevel@tonic-gate	const char *aux_state;
128eb1a346Truong Nguyen	const char *aux_fmri;
1297c478bdstevel@tonic-gate	int64_t start_method_waitstatus;
1307c478bdstevel@tonic-gate
1312e1a947Liane Praza	uint8_t enabled;
1327c478bdstevel@tonic-gate	int temporary;
1337c478bdstevel@tonic-gate	const char *restarter;
1347c478bdstevel@tonic-gate	uu_list_t *dependencies;	/* list of dependency_group's */
1357c478bdstevel@tonic-gate
1367c478bdstevel@tonic-gate	int active;			/* In use?  (cycle detection) */
1377c478bdstevel@tonic-gate	int restarter_bad;
1387c478bdstevel@tonic-gate	const char *summary;
1397c478bdstevel@tonic-gate	uu_list_t *baddeps;		/* list of dependency's */
1407c478bdstevel@tonic-gate	uu_list_t *causes;		/* list of svcptrs */
1417c478bdstevel@tonic-gate	uu_list_t *impact_dependents;	/* list of svcptrs */
1427c478bdstevel@tonic-gate	uu_list_t *impact;		/* list of svcptrs */
1437c478bdstevel@tonic-gate
1447c478bdstevel@tonic-gate	uu_list_node_t node;
1457c478bdstevel@tonic-gate} inst_t;
1467c478bdstevel@tonic-gate
1477c478bdstevel@tonic-gatetypedef struct service {
1487c478bdstevel@tonic-gate	const char *svcname;
1497c478bdstevel@tonic-gate	uu_list_t *instances;
1507c478bdstevel@tonic-gate	struct service *next;
1517c478bdstevel@tonic-gate} svc_t;
1527c478bdstevel@tonic-gate
1537c478bdstevel@tonic-gatestruct svcptr {
1547c478bdstevel@tonic-gate	inst_t *svcp;
1557c478bdstevel@tonic-gate	inst_t *next_hop;
1567c478bdstevel@tonic-gate	uu_list_node_t node;
1577c478bdstevel@tonic-gate};
1587c478bdstevel@tonic-gate
1597c478bdstevel@tonic-gatestruct dependency_group {
1607c478bdstevel@tonic-gate	enum { DGG_REQALL, DGG_REQANY, DGG_OPTALL, DGG_EXCALL } grouping;
1617c478bdstevel@tonic-gate	const char *type;
1627c478bdstevel@tonic-gate	uu_list_t *entities;		/* List of struct dependency's */
1637c478bdstevel@tonic-gate	uu_list_node_t node;
1647c478bdstevel@tonic-gate};
1657c478bdstevel@tonic-gate
1667c478bdstevel@tonic-gatestruct dependency {
1677c478bdstevel@tonic-gate	const char *fmri;
1687c478bdstevel@tonic-gate	uu_list_node_t node;
1697c478bdstevel@tonic-gate};
1707c478bdstevel@tonic-gate
1717c478bdstevel@tonic-gate/* Hash table of service names -> svc_t's */
1727c478bdstevel@tonic-gate#define	SVC_HASH_NBUCKETS	256
1737c478bdstevel@tonic-gate#define	SVC_HASH_MASK		(SVC_HASH_NBUCKETS - 1)
1747c478bdstevel@tonic-gate
1757c478bdstevel@tonic-gatestatic svc_t **services;
1767c478bdstevel@tonic-gate
1777c478bdstevel@tonic-gatestatic uu_list_pool_t *insts, *svcptrs, *depgroups, *deps;
1787c478bdstevel@tonic-gatestatic uu_list_t *g_causes;		/* list of svcptrs */
1797c478bdstevel@tonic-gate
1807c478bdstevel@tonic-gatestatic scf_scope_t *g_local_scope;
1817c478bdstevel@tonic-gatestatic scf_service_t *g_svc;
1827c478bdstevel@tonic-gatestatic scf_instance_t *g_inst;
1837c478bdstevel@tonic-gatestatic scf_snapshot_t *g_snap;
1847c478bdstevel@tonic-gatestatic scf_propertygroup_t *g_pg;
1857c478bdstevel@tonic-gatestatic scf_property_t *g_prop;
1867c478bdstevel@tonic-gatestatic scf_value_t *g_val;
1877c478bdstevel@tonic-gatestatic scf_iter_t *g_iter, *g_viter;
1887c478bdstevel@tonic-gatestatic char *g_fmri, *g_value;
1897c478bdstevel@tonic-gatestatic size_t g_fmri_sz, g_value_sz;
190654b400Joshua M. Clulowstatic const char *g_msgbase = "http://illumos.org/msg/";
1917c478bdstevel@tonic-gate
1927c478bdstevel@tonic-gatestatic char *emsg_nomem;
1937c478bdstevel@tonic-gatestatic char *emsg_invalid_dep;
1947c478bdstevel@tonic-gate
1957c478bdstevel@tonic-gateextern scf_handle_t *h;
196048b027Bryan Cantrillextern char *g_zonename;
1977c478bdstevel@tonic-gate
1987c478bdstevel@tonic-gate/* ARGSUSED */
1997c478bdstevel@tonic-gatestatic int
2007c478bdstevel@tonic-gatesvcptr_compare(struct svcptr *a, struct svcptr *b, void *data)
2017c478bdstevel@tonic-gate{
2027c478bdstevel@tonic-gate	return (b->svcp - a->svcp);
2037c478bdstevel@tonic-gate}
2047c478bdstevel@tonic-gate
2057c478bdstevel@tonic-gatestatic uint32_t
2067c478bdstevel@tonic-gatehash_name(const char *name)
2077c478bdstevel@tonic-gate{
2087c478bdstevel@tonic-gate	uint32_t h = 0, g;
2097c478bdstevel@tonic-gate	const char *p;
2107c478bdstevel@tonic-gate
2117c478bdstevel@tonic-gate	for (p = name; *p != '\0'; ++p) {
2127c478bdstevel@tonic-gate		h = (h << 4) + *p;
2137c478bdstevel@tonic-gate		if ((g = (h & 0xf0000000)) != 0) {
2147c478bdstevel@tonic-gate			h ^= (g >> 24);
2157c478bdstevel@tonic-gate			h ^= g;
2167c478bdstevel@tonic-gate		}
2177c478bdstevel@tonic-gate	}
2187c478bdstevel@tonic-gate
2197c478bdstevel@tonic-gate	return (h);
2207c478bdstevel@tonic-gate}
2217c478bdstevel@tonic-gate
2227c478bdstevel@tonic-gatestatic void
2237c478bdstevel@tonic-gatex_init(void)
2247c478bdstevel@tonic-gate{
2257c478bdstevel@tonic-gate	emsg_nomem = gettext("Out of memory.\n");
2267c478bdstevel@tonic-gate	emsg_invalid_dep =
2277c478bdstevel@tonic-gate	    gettext("svc:/%s:%s has invalid dependency \"%s\".\n");
2287c478bdstevel@tonic-gate
2297c478bdstevel@tonic-gate	services = calloc(SVC_HASH_NBUCKETS, sizeof (*services));
2307c478bdstevel@tonic-gate	if (services == NULL)
2317c478bdstevel@tonic-gate		uu_die(emsg_nomem);
2327c478bdstevel@tonic-gate
2337c478bdstevel@tonic-gate	insts = uu_list_pool_create("insts", sizeof (inst_t),
2347c478bdstevel@tonic-gate	    offsetof(inst_t, node), NULL, UU_LIST_POOL_DEBUG);
2357c478bdstevel@tonic-gate	svcptrs = uu_list_pool_create("svcptrs", sizeof (struct svcptr),
2367c478bdstevel@tonic-gate	    offsetof(struct svcptr, node), (uu_compare_fn_t *)svcptr_compare,
2377c478bdstevel@tonic-gate	    UU_LIST_POOL_DEBUG);
2387c478bdstevel@tonic-gate	depgroups = uu_list_pool_create("depgroups",
2397c478bdstevel@tonic-gate	    sizeof (struct dependency_group),
2407c478bdstevel@tonic-gate	    offsetof(struct dependency_group, node), NULL, UU_LIST_POOL_DEBUG);
2417c478bdstevel@tonic-gate	deps = uu_list_pool_create("deps", sizeof (struct dependency),
2427c478bdstevel@tonic-gate	    offsetof(struct dependency, node), NULL, UU_LIST_POOL_DEBUG);
2437c478bdstevel@tonic-gate	g_causes = uu_list_create(svcptrs, NULL, UU_LIST_DEBUG);
2447c478bdstevel@tonic-gate	if (insts == NULL || svcptrs == NULL || depgroups == NULL ||
2457c478bdstevel@tonic-gate	    deps == NULL || g_causes == NULL)
2467c478bdstevel@tonic-gate		uu_die(emsg_nomem);
2477c478bdstevel@tonic-gate
2487c478bdstevel@tonic-gate	if ((g_local_scope = scf_scope_create(h)) == NULL ||
2497c478bdstevel@tonic-gate	    (g_svc = scf_service_create(h)) == NULL ||
2507c478bdstevel@tonic-gate	    (g_inst = scf_instance_create(h)) == NULL ||
2517c478bdstevel@tonic-gate	    (g_snap = scf_snapshot_create(h)) == NULL ||
2527c478bdstevel@tonic-gate	    (g_pg = scf_pg_create(h)) == NULL ||
2537c478bdstevel@tonic-gate	    (g_prop = scf_property_create(h)) == NULL ||
2547c478bdstevel@tonic-gate	    (g_val = scf_value_create(h)) == NULL ||
2557c478bdstevel@tonic-gate	    (g_iter = scf_iter_create(h)) == NULL ||
2567c478bdstevel@tonic-gate	    (g_viter = scf_iter_create(h)) == NULL)
2577c478bdstevel@tonic-gate		scfdie();
2587c478bdstevel@tonic-gate
2597c478bdstevel@tonic-gate	if (scf_handle_get_scope(h, SCF_SCOPE_LOCAL, g_local_scope) != 0)
2607c478bdstevel@tonic-gate		scfdie();
2617c478bdstevel@tonic-gate
2627c478bdstevel@tonic-gate	g_fmri_sz = max_scf_fmri_length + 1;
2637c478bdstevel@tonic-gate	g_fmri = safe_malloc(g_fmri_sz);
2647c478bdstevel@tonic-gate
2657c478bdstevel@tonic-gate	g_value_sz = max_scf_value_length + 1;
2667c478bdstevel@tonic-gate	g_value = safe_malloc(g_value_sz);
2677c478bdstevel@tonic-gate}
2687c478bdstevel@tonic-gate
2697c478bdstevel@tonic-gate/*
2707c478bdstevel@tonic-gate * Repository loading routines.
2717c478bdstevel@tonic-gate */
2727c478bdstevel@tonic-gate
2737c478bdstevel@tonic-gate/*
2747c478bdstevel@tonic-gate * Returns
2757c478bdstevel@tonic-gate *   0 - success
2767c478bdstevel@tonic-gate *   ECANCELED - inst was deleted
2777c478bdstevel@tonic-gate *   EINVAL - inst is invalid
2787c478bdstevel@tonic-gate */
2797c478bdstevel@tonic-gatestatic int
2807c478bdstevel@tonic-gateload_dependencies(inst_t *svcp, scf_instance_t *inst)
2817c478bdstevel@tonic-gate{
2827c478bdstevel@tonic-gate	scf_snapshot_t *snap;
2837c478bdstevel@tonic-gate	struct dependency_group *dg;
2847c478bdstevel@tonic-gate	struct dependency *d;
2857c478bdstevel@tonic-gate	int r;
2867c478bdstevel@tonic-gate
2877c478bdstevel@tonic-gate	assert(svcp->dependencies == NULL);
2887c478bdstevel@tonic-gate	svcp->dependencies = uu_list_create(depgroups, svcp, UU_LIST_DEBUG);
2897c478bdstevel@tonic-gate	if (svcp->dependencies == NULL)
2907c478bdstevel@tonic-gate		uu_die(emsg_nomem);
2917c478bdstevel@tonic-gate
2927c478bdstevel@tonic-gate	if (scf_instance_get_snapshot(inst, "running", g_snap) == 0) {
2937c478bdstevel@tonic-gate		snap = g_snap;
2947c478bdstevel@tonic-gate	} else {
2957c478bdstevel@tonic-gate		if (scf_error() != SCF_ERROR_NOT_FOUND)
2967c478bdstevel@tonic-gate			scfdie();
2977c478bdstevel@tonic-gate
2987c478bdstevel@tonic-gate		snap = NULL;
2997c478bdstevel@tonic-gate	}
3007c478bdstevel@tonic-gate
3017c478bdstevel@tonic-gate	if (scf_iter_instance_pgs_typed_composed(g_iter, inst, snap,
3027c478bdstevel@tonic-gate	    SCF_GROUP_DEPENDENCY) != 0) {
3037c478bdstevel@tonic-gate		if (scf_error() != SCF_ERROR_DELETED)
3047c478bdstevel@tonic-gate			scfdie();
3057c478bdstevel@tonic-gate		return (ECANCELED);
3067c478bdstevel@tonic-gate	}
3077c478bdstevel@tonic-gate
3087c478bdstevel@tonic-gate	for (;;) {
3097c478bdstevel@tonic-gate		r = scf_iter_next_pg(g_iter, g_pg);
3107c478bdstevel@tonic-gate		if (r == 0)
3117c478bdstevel@tonic-gate			break;
3127c478bdstevel@tonic-gate		if (r != 1) {
3137c478bdstevel@tonic-gate			if (scf_error() != SCF_ERROR_DELETED)
3147c478bdstevel@tonic-gate				scfdie();
3157c478bdstevel@tonic-gate			return (ECANCELED);
3167c478bdstevel@tonic-gate		}
3177c478bdstevel@tonic-gate
3187c478bdstevel@tonic-gate		dg = safe_malloc(sizeof (*dg));
3197c478bdstevel@tonic-gate		(void) memset(dg, 0, sizeof (*dg));
3207c478bdstevel@tonic-gate		dg->entities = uu_list_create(deps, dg, UU_LIST_DEBUG);
3217c478bdstevel@tonic-gate		if (dg->entities == NULL)
3227c478bdstevel@tonic-gate			uu_die(emsg_nomem);
3237c478bdstevel@tonic-gate
3247c478bdstevel@tonic-gate		if (pg_get_single_val(g_pg, SCF_PROPERTY_GROUPING,
3257c478bdstevel@tonic-gate		    SCF_TYPE_ASTRING, g_value, g_value_sz, 0) != 0)
3267c478bdstevel@tonic-gate			return (EINVAL);
3277c478bdstevel@tonic-gate
3287c478bdstevel@tonic-gate		if (strcmp(g_value, "require_all") == 0)
3297c478bdstevel@tonic-gate			dg->grouping = DGG_REQALL;
3307c478bdstevel@tonic-gate		else if (strcmp(g_value, "require_any") == 0)
3317c478bdstevel@tonic-gate			dg->grouping = DGG_REQANY;
3327c478bdstevel@tonic-gate		else if (strcmp(g_value, "optional_all") == 0)
3337c478bdstevel@tonic-gate			dg->grouping = DGG_OPTALL;
3347c478bdstevel@tonic-gate		else if (strcmp(g_value, "exclude_all") == 0)
3357c478bdstevel@tonic-gate			dg->grouping = DGG_EXCALL;
3367c478bdstevel@tonic-gate		else {
3377c478bdstevel@tonic-gate			(void) fprintf(stderr, gettext("svc:/%s:%s has "
3387c478bdstevel@tonic-gate			    "dependency with unknown type \"%s\".\n"),
3397c478bdstevel@tonic-gate			    svcp->svcname, svcp->instname, g_value);
3407c478bdstevel@tonic-gate			return (EINVAL);
3417c478bdstevel@tonic-gate		}
3427c478bdstevel@tonic-gate
3437c478bdstevel@tonic-gate		if (pg_get_single_val(g_pg, SCF_PROPERTY_TYPE, SCF_TYPE_ASTRING,
3447c478bdstevel@tonic-gate		    g_value, g_value_sz, 0) != 0)
3457c478bdstevel@tonic-gate			return (EINVAL);
3467c478bdstevel@tonic-gate		dg->type = safe_strdup(g_value);
3477c478bdstevel@tonic-gate
3487c478bdstevel@tonic-gate		if (scf_pg_get_property(g_pg, SCF_PROPERTY_ENTITIES, g_prop) !=
3497c478bdstevel@tonic-gate		    0) {
3507c478bdstevel@tonic-gate			switch (scf_error()) {
3517c478bdstevel@tonic-gate			case SCF_ERROR_NOT_FOUND:
3527c478bdstevel@tonic-gate				(void) fprintf(stderr, gettext("svc:/%s:%s has "
3537c478bdstevel@tonic-gate				    "dependency without an entities "
3547c478bdstevel@tonic-gate				    "property.\n"), svcp->svcname,
3557c478bdstevel@tonic-gate				    svcp->instname);
3567c478bdstevel@tonic-gate				return (EINVAL);
3577c478bdstevel@tonic-gate
3587c478bdstevel@tonic-gate			case SCF_ERROR_DELETED:
3597c478bdstevel@tonic-gate				return (ECANCELED);
3607c478bdstevel@tonic-gate
3617c478bdstevel@tonic-gate			default:
3627c478bdstevel@tonic-gate				scfdie();
3637c478bdstevel@tonic-gate			}
3647c478bdstevel@tonic-gate		}
3657c478bdstevel@tonic-gate
3667c478bdstevel@tonic-gate		if (scf_iter_property_values(g_viter, g_prop) != 0) {
3677c478bdstevel@tonic-gate			if (scf_error() != SCF_ERROR_DELETED)
3687c478bdstevel@tonic-gate				scfdie();
3697c478bdstevel@tonic-gate			return (ECANCELED);
3707c478bdstevel@tonic-gate		}
3717c478bdstevel@tonic-gate
3727c478bdstevel@tonic-gate		for (;;) {
3737c478bdstevel@tonic-gate			r = scf_iter_next_value(g_viter, g_val);
3747c478bdstevel@tonic-gate			if (r == 0)
3757c478bdstevel@tonic-gate				break;
3767c478bdstevel@tonic-gate			if (r != 1) {
3777c478bdstevel@tonic-gate				if (scf_error() != SCF_ERROR_DELETED)
3787c478bdstevel@tonic-gate					scfdie();
3797c478bdstevel@tonic-gate				return (ECANCELED);
3807c478bdstevel@tonic-gate			}
3817c478bdstevel@tonic-gate
3827c478bdstevel@tonic-gate			d = safe_malloc(sizeof (*d));
3837c478bdstevel@tonic-gate			d->fmri = safe_malloc(max_scf_fmri_length + 1);
3847c478bdstevel@tonic-gate
3857c478bdstevel@tonic-gate			if (scf_value_get_astring(g_val, (char *)d->fmri,
3867c478bdstevel@tonic-gate			    max_scf_fmri_length + 1) < 0)
3877c478bdstevel@tonic-gate				scfdie();
3887c478bdstevel@tonic-gate
3897c478bdstevel@tonic-gate			uu_list_node_init(d, &d->node, deps);
3907c478bdstevel@tonic-gate			(void) uu_list_append(dg->entities, d);
3917c478bdstevel@tonic-gate		}
3927c478bdstevel@tonic-gate
3937c478bdstevel@tonic-gate		uu_list_node_init(dg, &dg->node, depgroups);
3947c478bdstevel@tonic-gate		r = uu_list_append(svcp->dependencies, dg);
3957c478bdstevel@tonic-gate		assert(r == 0);
3967c478bdstevel@tonic-gate	}
3977c478bdstevel@tonic-gate
3987c478bdstevel@tonic-gate	return (0);
3997c478bdstevel@tonic-gate}
4007c478bdstevel@tonic-gate
4017c478bdstevel@tonic-gatestatic void
4027c478bdstevel@tonic-gateadd_instance(const char *svcname, const char *instname, scf_instance_t *inst)
4037c478bdstevel@tonic-gate{
4047c478bdstevel@tonic-gate	inst_t *instp;
4057c478bdstevel@tonic-gate	svc_t *svcp;
4067c478bdstevel@tonic-gate	int have_enabled = 0;
4072e1a947Liane Praza	uint8_t i;
4087c478bdstevel@tonic-gate	uint32_t h;
4092e1a947Liane Praza	int r;
4107c478bdstevel@tonic-gate
4117c478bdstevel@tonic-gate	h = hash_name(svcname) & SVC_HASH_MASK;
4127c478bdstevel@tonic-gate	for (svcp = services[h]; svcp != NULL; svcp = svcp->next) {
4137c478bdstevel@tonic-gate		if (strcmp(svcp->svcname, svcname) == 0)
4147c478bdstevel@tonic-gate			break;
4157c478bdstevel@tonic-gate	}
4167c478bdstevel@tonic-gate
4177c478bdstevel@tonic-gate	if (svcp == NULL) {
4187c478bdstevel@tonic-gate		svcp = safe_malloc(sizeof (*svcp));
4197c478bdstevel@tonic-gate		svcp->svcname = safe_strdup(svcname);
4207c478bdstevel@tonic-gate		svcp->instances = uu_list_create(insts, svcp, UU_LIST_DEBUG);
4217c478bdstevel@tonic-gate		if (svcp->instances == NULL)
4227c478bdstevel@tonic-gate			uu_die(emsg_nomem);
4237c478bdstevel@tonic-gate		svcp->next = services[h];
4247c478bdstevel@tonic-gate		services[h] = svcp;
4257c478bdstevel@tonic-gate	}
4267c478bdstevel@tonic-gate
4277c478bdstevel@tonic-gate	instp = safe_malloc(sizeof (*instp));
4287c478bdstevel@tonic-gate	(void) memset(instp, 0, sizeof (*instp));
4297c478bdstevel@tonic-gate	instp->svcname = svcp->svcname;
4307c478bdstevel@tonic-gate	instp->instname = safe_strdup(instname);
4317c478bdstevel@tonic-gate	instp->impact_dependents =
4327c478bdstevel@tonic-gate	    uu_list_create(svcptrs, instp, UU_LIST_DEBUG);
4337c478bdstevel@tonic-gate	if (instp->impact_dependents == NULL)
4347c478bdstevel@tonic-gate		uu_die(emsg_nomem);
4357c478bdstevel@tonic-gate
4367c478bdstevel@tonic-gate	if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, g_pg) != 0) {
4377c478bdstevel@tonic-gate		switch (scf_error()) {
4387c478bdstevel@tonic-gate		case SCF_ERROR_DELETED:
4397c478bdstevel@tonic-gate			return;
4407c478bdstevel@tonic-gate
4417c478bdstevel@tonic-gate		case SCF_ERROR_NOT_FOUND:
4427c478bdstevel@tonic-gate			(void) fprintf(stderr, gettext("svc:/%s:%s has no "
4437c478bdstevel@tonic-gate			    "\"%s\" property group; ignoring.\n"),
4447c478bdstevel@tonic-gate			    instp->svcname, instp->instname, SCF_PG_RESTARTER);
4457c478bdstevel@tonic-gate			return;
4467c478bdstevel@tonic-gate
4477c478bdstevel@tonic-gate		default:
4487c478bdstevel@tonic-gate			scfdie();
4497c478bdstevel@tonic-gate		}
4507c478bdstevel@tonic-gate	}
4517c478bdstevel@tonic-gate
4527c478bdstevel@tonic-gate	if (pg_get_single_val(g_pg, SCF_PROPERTY_STATE, SCF_TYPE_ASTRING,
4537c478bdstevel@tonic-gate	    (void *)instp->state, sizeof (instp->state), 0) != 0)
4547c478bdstevel@tonic-gate		return;
4557c478bdstevel@tonic-gate
4567c478bdstevel@tonic-gate	if (pg_get_single_val(g_pg, SCF_PROPERTY_NEXT_STATE, SCF_TYPE_ASTRING,
4577c478bdstevel@tonic-gate	    (void *)instp->next_state, sizeof (instp->next_state), 0) != 0)
4587c478bdstevel@tonic-gate		return;
4597c478bdstevel@tonic-gate
4607c478bdstevel@tonic-gate	if (pg_get_single_val(g_pg, SCF_PROPERTY_STATE_TIMESTAMP,
4617c478bdstevel@tonic-gate	    SCF_TYPE_TIME, &instp->stime, 0, 0) != 0)
4627c478bdstevel@tonic-gate		return;
4637c478bdstevel@tonic-gate
464eb1a346Truong Nguyen	/* restarter may not set aux_state, allow to continue in that case */
4657c478bdstevel@tonic-gate	if (pg_get_single_val(g_pg, SCF_PROPERTY_AUX_STATE, SCF_TYPE_ASTRING,
466eb1a346Truong Nguyen	    g_fmri, g_fmri_sz, 0) == 0)
467eb1a346Truong Nguyen		instp->aux_state = safe_strdup(g_fmri);
468eb1a346Truong Nguyen	else
469eb1a346Truong Nguyen		instp->aux_state = safe_strdup(AUX_STATE_INVALID);
4707c478bdstevel@tonic-gate
4717c478bdstevel@tonic-gate	(void) pg_get_single_val(g_pg, SCF_PROPERTY_START_METHOD_WAITSTATUS,
4727c478bdstevel@tonic-gate	    SCF_TYPE_INTEGER, &instp->start_method_waitstatus, 0, 0);
4737c478bdstevel@tonic-gate
474eb1a346Truong Nguyen	/* Get the optional auxiliary_fmri */
475eb1a346Truong Nguyen	if (pg_get_single_val(g_pg, SCF_PROPERTY_AUX_FMRI, SCF_TYPE_ASTRING,
476eb1a346Truong Nguyen	    g_fmri, g_fmri_sz, 0) == 0)
477eb1a346Truong Nguyen		instp->aux_fmri = safe_strdup(g_fmri);
478eb1a346Truong Nguyen
4797c478bdstevel@tonic-gate	if (scf_instance_get_pg(inst, SCF_PG_GENERAL_OVR, g_pg) == 0) {
4807c478bdstevel@tonic-gate		if (pg_get_single_val(g_pg, SCF_PROPERTY_ENABLED,
4817c478bdstevel@tonic-gate		    SCF_TYPE_BOOLEAN, &instp->enabled, 0, 0) == 0)
4827c478bdstevel@tonic-gate			have_enabled = 1;
4837c478bdstevel@tonic-gate	} else {
4847c478bdstevel@tonic-gate		switch (scf_error()) {
4857c478bdstevel@tonic-gate		case SCF_ERROR_NOT_FOUND:
4867c478bdstevel@tonic-gate			break;
4877c478bdstevel@tonic-gate
4887c478bdstevel@tonic-gate		case SCF_ERROR_DELETED:
4897c478bdstevel@tonic-gate			return;
4907c478bdstevel@tonic-gate
4917c478bdstevel@tonic-gate		default:
4927c478bdstevel@tonic-gate			scfdie();
4937c478bdstevel@tonic-gate		}
4947c478bdstevel@tonic-gate	}
4957c478bdstevel@tonic-gate
4967c478bdstevel@tonic-gate	if (scf_instance_get_pg_composed(inst, NULL, SCF_PG_GENERAL, g_pg) !=
4977c478bdstevel@tonic-gate	    0) {
4987c478bdstevel@tonic-gate		switch (scf_error()) {
4997c478bdstevel@tonic-gate		case SCF_ERROR_DELETED:
5007c478bdstevel@tonic-gate		case SCF_ERROR_NOT_FOUND:
5017c478bdstevel@tonic-gate			return;
5027c478bdstevel@tonic-gate
5037c478bdstevel@tonic-gate		default:
5047c478bdstevel@tonic-gate			scfdie();
5057c478bdstevel@tonic-gate		}
5067c478bdstevel@tonic-gate	}
5077c478bdstevel@tonic-gate
5087c478bdstevel@tonic-gate	if (pg_get_single_val(g_pg, SCF_PROPERTY_ENABLED, SCF_TYPE_BOOLEAN,
5097c478bdstevel@tonic-gate	    &i, 0, 0) != 0)
5107c478bdstevel@tonic-gate		return;
5117c478bdstevel@tonic-gate	if (!have_enabled) {
5127c478bdstevel@tonic-gate		instp->enabled = i;
5137c478bdstevel@tonic-gate		instp->temporary = 0;
5147c478bdstevel@tonic-gate	} else {
5157c478bdstevel@tonic-gate		instp->temporary = (instp->enabled != i);
5167c478bdstevel@tonic-gate	}
5177c478bdstevel@tonic-gate
5187c478bdstevel@tonic-gate	if (pg_get_single_val(g_pg, SCF_PROPERTY_RESTARTER, SCF_TYPE_ASTRING,
5197c478bdstevel@tonic-gate	    g_fmri, g_fmri_sz, 0) == 0)
5207c478bdstevel@tonic-gate		instp->restarter = safe_strdup(g_fmri);
5217c478bdstevel@tonic-gate	else
5227c478bdstevel@tonic-gate		instp->restarter = SCF_SERVICE_STARTD;
5237c478bdstevel@tonic-gate
5247c478bdstevel@tonic-gate	if (strcmp(instp->state, SCF_STATE_STRING_OFFLINE) == 0 &&
5257c478bdstevel@tonic-gate	    load_dependencies(instp, inst) != 0)
5267c478bdstevel@tonic-gate		return;
5277c478bdstevel@tonic-gate
5287c478bdstevel@tonic-gate	uu_list_node_init(instp, &instp->node, insts);
5292e1a947Liane Praza	r = uu_list_append(svcp->instances, instp);
5302e1a947Liane Praza	assert(r == 0);
5317c478bdstevel@tonic-gate}
5327c478bdstevel@tonic-gate
5337c478bdstevel@tonic-gatestatic void
5347c478bdstevel@tonic-gateload_services(void)
5357c478bdstevel@tonic-gate{
5367c478bdstevel@tonic-gate	scf_iter_t *siter, *iiter;
5377c478bdstevel@tonic-gate	int r;
5387c478bdstevel@tonic-gate	char *svcname, *instname;
5397c478bdstevel@tonic-gate
5407c478bdstevel@tonic-gate	if ((siter = scf_iter_create(h)) == NULL ||
5417c478bdstevel@tonic-gate	    (iiter = scf_iter_create(h)) == NULL)
5427c478bdstevel@tonic-gate		scfdie();
5437c478bdstevel@tonic-gate
5447c478bdstevel@tonic-gate	svcname = safe_malloc(max_scf_name_length + 1);
5457c478bdstevel@tonic-gate	instname = safe_malloc(max_scf_name_length + 1);
5467c478bdstevel@tonic-gate
5477c478bdstevel@tonic-gate	if (scf_iter_scope_services(siter, g_local_scope) != 0)
5487c478bdstevel@tonic-gate		scfdie();
5497c478bdstevel@tonic-gate
5507c478bdstevel@tonic-gate	for (;;) {
5517c478bdstevel@tonic-gate		r = scf_iter_next_service(siter, g_svc);
5527c478bdstevel@tonic-gate		if (r == 0)
5537c478bdstevel@tonic-gate			break;
5547c478bdstevel@tonic-gate		if (r != 1)
5557c478bdstevel@tonic-gate			scfdie();
5567c478bdstevel@tonic-gate
5577c478bdstevel@tonic-gate		if (scf_service_get_name(g_svc, svcname,
5587c478bdstevel@tonic-gate		    max_scf_name_length + 1) < 0) {
5597c478bdstevel@tonic-gate			if (scf_error() != SCF_ERROR_DELETED)
5607c478bdstevel@tonic-gate				scfdie();
5617c478bdstevel@tonic-gate			continue;
5627c478bdstevel@tonic-gate		}
5637c478bdstevel@tonic-gate
5647c478bdstevel@tonic-gate		if (scf_iter_service_instances(iiter, g_svc) != 0) {
5657c478bdstevel@tonic-gate			if (scf_error() != SCF_ERROR_DELETED)
5667c478bdstevel@tonic-gate				scfdie();
5677c478bdstevel@tonic-gate			continue;
5687c478bdstevel@tonic-gate		}
5697c478bdstevel@tonic-gate
5707c478bdstevel@tonic-gate		for (;;) {
5717c478bdstevel@tonic-gate			r = scf_iter_next_instance(iiter, g_inst);
5727c478bdstevel@tonic-gate			if (r == 0)
5737c478bdstevel@tonic-gate				break;
5747c478bdstevel@tonic-gate			if (r != 1) {
5757c478bdstevel@tonic-gate				if (scf_error() != SCF_ERROR_DELETED)
5767c478bdstevel@tonic-gate					scfdie();
5777c478bdstevel@tonic-gate				break;
5787c478bdstevel@tonic-gate			}
5797c478bdstevel@tonic-gate
5807c478bdstevel@tonic-gate			if (scf_instance_get_name(g_inst, instname,
5817c478bdstevel@tonic-gate			    max_scf_name_length + 1) < 0) {
5827c478bdstevel@tonic-gate				if (scf_error() != SCF_ERROR_DELETED)
5837c478bdstevel@tonic-gate					scfdie();
5847c478bdstevel@tonic-gate				continue;
5857c478bdstevel@tonic-gate			}
5867c478bdstevel@tonic-gate
5877c478bdstevel@tonic-gate			add_instance(svcname, instname, g_inst);
5887c478bdstevel@tonic-gate		}
5897c478bdstevel@tonic-gate	}
5907c478bdstevel@tonic-gate
5917c478bdstevel@tonic-gate	free(svcname);
5927c478bdstevel@tonic-gate	free(instname);
5937c478bdstevel@tonic-gate	scf_iter_destroy(siter);
5947c478bdstevel@tonic-gate	scf_iter_destroy(iiter);
5957c478bdstevel@tonic-gate}
5967c478bdstevel@tonic-gate
5977c478bdstevel@tonic-gate/*
5987c478bdstevel@tonic-gate * Dependency analysis routines.
5997c478bdstevel@tonic-gate */
6007c478bdstevel@tonic-gate
6017c478bdstevel@tonic-gatestatic void
6027c478bdstevel@tonic-gateadd_svcptr(uu_list_t *lst, inst_t *svcp)
6037c478bdstevel@tonic-gate{
6047c478bdstevel@tonic-gate	struct svcptr *spp;
6057c478bdstevel@tonic-gate	uu_list_index_t idx;
6067c478bdstevel@tonic-gate	int r;
6077c478bdstevel@tonic-gate
6087c478bdstevel@tonic-gate	spp = safe_malloc(sizeof (*spp));
6097c478bdstevel@tonic-gate	spp->svcp = svcp;
6107c478bdstevel@tonic-gate	spp->next_hop = NULL;
6117c478bdstevel@tonic-gate
6127c478bdstevel@tonic-gate	if (uu_list_find(lst, spp, NULL, &idx) != NULL) {
6137c478bdstevel@tonic-gate		free(spp);
6147c478bdstevel@tonic-gate		return;
6157c478bdstevel@tonic-gate	}
6167c478bdstevel@tonic-gate
6177c478bdstevel@tonic-gate	uu_list_node_init(spp, &spp->node, svcptrs);
6187c478bdstevel@tonic-gate	r = uu_list_append(lst, spp);
6197c478bdstevel@tonic-gate	assert(r == 0);
6207c478bdstevel@tonic-gate}
6217c478bdstevel@tonic-gate
6227c478bdstevel@tonic-gatestatic int determine_causes(inst_t *, void *);
6237c478bdstevel@tonic-gate
6247c478bdstevel@tonic-gate/*
6257c478bdstevel@tonic-gate * Determine the causes of src and add them to the causes list of dst.
6267c478bdstevel@tonic-gate * Returns ELOOP if src is active, and 0 otherwise.
6277c478bdstevel@tonic-gate */
6287c478bdstevel@tonic-gatestatic int
6297c478bdstevel@tonic-gateadd_causes(inst_t *dst, inst_t *src)
6307c478bdstevel@tonic-gate{
6317c478bdstevel@tonic-gate	struct svcptr *spp, *copy;
6327c478bdstevel@tonic-gate	uu_list_index_t idx;
6337c478bdstevel@tonic-gate
6347c478bdstevel@tonic-gate	if (determine_causes(src, (void *)1) != UU_WALK_NEXT) {
6357c478bdstevel@tonic-gate		/* Dependency cycle. */
6367c478bdstevel@tonic-gate		(void) fprintf(stderr, "  svc:/%s:%s\n", dst->svcname,
6377c478bdstevel@tonic-gate		    dst->instname);
6387c478bdstevel@tonic-gate		return (ELOOP);
6397c478bdstevel@tonic-gate	}
6407c478bdstevel@tonic-gate
6417c478bdstevel@tonic-gate	add_svcptr(src->impact_dependents, dst);
6427c478bdstevel@tonic-gate
6437c478bdstevel@tonic-gate	for (spp = uu_list_first(src->causes);
6447c478bdstevel@tonic-gate	    spp != NULL;
6457c478bdstevel@tonic-gate	    spp = uu_list_next(src->causes, spp)) {
6467c478bdstevel@tonic-gate		if (uu_list_find(dst->causes, spp, NULL, &idx) != NULL)
6477c478bdstevel@tonic-gate			continue;
6487c478bdstevel@tonic-gate
6497c478bdstevel@tonic-gate		copy = safe_malloc(sizeof (*copy));
6507c478bdstevel@tonic-gate		copy->svcp = spp->svcp;
6517c478bdstevel@tonic-gate		copy->next_hop = src;
6527c478bdstevel@tonic-gate		uu_list_node_init(copy, &copy->node, svcptrs);
6537c478bdstevel@tonic-gate		uu_list_insert(dst->causes, copy, idx);
6547c478bdstevel@tonic-gate
6557c478bdstevel@tonic-gate		add_svcptr(g_causes, spp->svcp);
6567c478bdstevel@tonic-gate	}
6577c478bdstevel@tonic-gate
6587c478bdstevel@tonic-gate	return (0);
6597c478bdstevel@tonic-gate}
6607c478bdstevel@tonic-gate
6617c478bdstevel@tonic-gatestatic int
6627c478bdstevel@tonic-gateinst_running(inst_t *ip)
6637c478bdstevel@tonic-gate{
6647c478bdstevel@tonic-gate	return (strcmp(ip->state, SCF_STATE_STRING_ONLINE) == 0 ||
6657c478bdstevel@tonic-gate	    strcmp(ip->state, SCF_STATE_STRING_DEGRADED) == 0);
6667c478bdstevel@tonic-gate}
6677c478bdstevel@tonic-gate
6687c478bdstevel@tonic-gatestatic int
6697c478bdstevel@tonic-gateinst_running_or_maint(inst_t *ip)
6707c478bdstevel@tonic-gate{
6717c478bdstevel@tonic-gate	return (inst_running(ip) ||
6727c478bdstevel@tonic-gate	    strcmp(ip->state, SCF_STATE_STRING_MAINT) == 0);
6737c478bdstevel@tonic-gate}
6747c478bdstevel@tonic-gate
6757c478bdstevel@tonic-gatestatic svc_t *
6767c478bdstevel@tonic-gateget_svc(const char *sn)
6777c478bdstevel@tonic-gate{
6787c478bdstevel@tonic-gate	uint32_t h;
6797c478bdstevel@tonic-gate	svc_t *svcp;
6807c478bdstevel@tonic-gate
6817c478bdstevel@tonic-gate	h = hash_name(sn) & SVC_HASH_MASK;
6827c478bdstevel@tonic-gate
6837c478bdstevel@tonic-gate	for (svcp = services[h]; svcp != NULL; svcp = svcp->next) {
6847c478bdstevel@tonic-gate		if (strcmp(svcp->svcname, sn) == 0)
6857c478bdstevel@tonic-gate			break;
6867c478bdstevel@tonic-gate	}
6877c478bdstevel@tonic-gate
6887c478bdstevel@tonic-gate	return (svcp);
6897c478bdstevel@tonic-gate}
6907c478bdstevel@tonic-gate
6917c478bdstevel@tonic-gate/* ARGSUSED */
6927c478bdstevel@tonic-gatestatic inst_t *
6937c478bdstevel@tonic-gateget_inst(svc_t *svcp, const char *in)
6947c478bdstevel@tonic-gate{
6957c478bdstevel@tonic-gate	inst_t *instp;
6967c478bdstevel@tonic-gate
6977c478bdstevel@tonic-gate	for (instp = uu_list_first(svcp->instances);
6987c478bdstevel@tonic-gate	    instp != NULL;
6997c478bdstevel@tonic-gate	    instp = uu_list_next(svcp->instances, instp)) {
7007c478bdstevel@tonic-gate		if (strcmp(instp->instname, in) == 0)
7017c478bdstevel@tonic-gate			return (instp);
7027c478bdstevel@tonic-gate	}
7037c478bdstevel@tonic-gate
7047c478bdstevel@tonic-gate	return (NULL);
7057c478bdstevel@tonic-gate}
7067c478bdstevel@tonic-gate
7077c478bdstevel@tonic-gatestatic int
7087c478bdstevel@tonic-gateget_fmri(const char *fmri, svc_t **spp, inst_t **ipp)
7097c478bdstevel@tonic-gate{
7107c478bdstevel@tonic-gate	const char *sn, *in;
7117c478bdstevel@tonic-gate	svc_t *sp;
7127c478bdstevel@tonic-gate	inst_t *ip;
7137c478bdstevel@tonic-gate
7147c478bdstevel@tonic-gate	if (strlcpy(g_fmri, fmri, g_fmri_sz) >= g_fmri_sz)
7157c478bdstevel@tonic-gate		return (EINVAL);
7167c478bdstevel@tonic-gate
7177c478bdstevel@tonic-gate	if (scf_parse_svc_fmri(g_fmri, NULL, &sn, &in, NULL, NULL) != 0)
7187c478bdstevel@tonic-gate		return (EINVAL);
7197c478bdstevel@tonic-gate
7207c478bdstevel@tonic-gate	if (sn == NULL)
7217c478bdstevel@tonic-gate		return (EINVAL);
7227c478bdstevel@tonic-gate
7237c478bdstevel@tonic-gate	sp = get_svc(sn);
7247c478bdstevel@tonic-gate	if (sp == NULL)
7257c478bdstevel@tonic-gate		return (ENOENT);
7267c478bdstevel@tonic-gate
7277c478bdstevel@tonic-gate	if (in != NULL) {
7287c478bdstevel@tonic-gate		ip = get_inst(sp, in);
7297c478bdstevel@tonic-gate		if (ip == NULL)
7307c478bdstevel@tonic-gate			return (ENOENT);
7317c478bdstevel@tonic-gate	}
7327c478bdstevel@tonic-gate
7337c478bdstevel@tonic-gate	if (spp != NULL)
7347c478bdstevel@tonic-gate		*spp = sp;
7357c478bdstevel@tonic-gate	if (ipp != NULL)
7367c478bdstevel@tonic-gate		*ipp = ((in == NULL) ? NULL : ip);
7377c478bdstevel@tonic-gate
7387c478bdstevel@tonic-gate	return (0);
7397c478bdstevel@tonic-gate}
7407c478bdstevel@tonic-gate
7417c478bdstevel@tonic-gatestatic int
7427c478bdstevel@tonic-gateprocess_reqall(inst_t *svcp, struct dependency_group *dg)
7437c478bdstevel@tonic-gate{
7447c478bdstevel@tonic-gate	uu_list_walk_t *walk;
7457c478bdstevel@tonic-gate	struct dependency *d;
7467c478bdstevel@tonic-gate	int r, svcrunning;
7477c478bdstevel@tonic-gate	svc_t *sp;
7487c478bdstevel@tonic-gate	inst_t *ip;
7497c478bdstevel@tonic-gate
7507c478bdstevel@tonic-gate	walk = uu_list_walk_start(dg->entities, UU_WALK_ROBUST);
7517c478bdstevel@tonic-gate	if (walk == NULL)
7527c478bdstevel@tonic-gate		uu_die(emsg_nomem);
7537c478bdstevel@tonic-gate
7547c478bdstevel@tonic-gate	while ((d = uu_list_walk_next(walk)) != NULL) {
7557c478bdstevel@tonic-gate		r = get_fmri(d->fmri, &sp, &ip);
7567c478bdstevel@tonic-gate		switch (r) {
7577c478bdstevel@tonic-gate		case EINVAL:
7587c478bdstevel@tonic-gate			/* LINTED */
7597c478bdstevel@tonic-gate			(void) fprintf(stderr, emsg_invalid_dep, svcp->svcname,
7607c478bdstevel@tonic-gate			    svcp->instname, d->fmri);
7617c478bdstevel@tonic-gate			continue;
7627c478bdstevel@tonic-gate
7637c478bdstevel@tonic-gate		case ENOENT:
7647c478bdstevel@tonic-gate			uu_list_remove(dg->entities, d);
7657c478bdstevel@tonic-gate			r = uu_list_append(svcp->baddeps, d);
7667c478bdstevel@tonic-gate			assert(r == 0);
7677c478bdstevel@tonic-gate			continue;
7687c478bdstevel@tonic-gate
7697c478bdstevel@tonic-gate		case 0:
7707c478bdstevel@tonic-gate			break;
7717c478bdstevel@tonic-gate
7727c478bdstevel@tonic-gate		default:
7737c478bdstevel@tonic-gate			bad_error("get_fmri", r);
7747c478bdstevel@tonic-gate		}
7757c478bdstevel@tonic-gate
7767c478bdstevel@tonic-gate		if (ip != NULL) {
7777c478bdstevel@tonic-gate			if (inst_running(ip))
7787c478bdstevel@tonic-gate				continue;
7797c478bdstevel@tonic-gate			r = add_causes(svcp, ip);
7807c478bdstevel@tonic-gate			if (r != 0) {
7817c478bdstevel@tonic-gate				assert(r == ELOOP);
7827c478bdstevel@tonic-gate				return (r);
7837c478bdstevel@tonic-gate			}
7847c478bdstevel@tonic-gate			continue;
7857c478bdstevel@tonic-gate		}
7867c478bdstevel@tonic-gate
7877c478bdstevel@tonic-gate		svcrunning = 0;
7887c478bdstevel@tonic-gate
7897c478bdstevel@tonic-gate		for (ip = uu_list_first(sp->instances);
7907c478bdstevel@tonic-gate		    ip != NULL;
7917c478bdstevel@tonic-gate		    ip = uu_list_next(sp->instances, ip)) {
7927c478bdstevel@tonic-gate			if (inst_running(ip))
7937c478bdstevel@tonic-gate				svcrunning = 1;
7947c478bdstevel@tonic-gate		}
7957c478bdstevel@tonic-gate
7967c478bdstevel@tonic-gate		if (!svcrunning) {
7977c478bdstevel@tonic-gate			for (ip = uu_list_first(sp->instances);
7987c478bdstevel@tonic-gate			    ip != NULL;
7997c478bdstevel@tonic-gate			    ip = uu_list_next(sp->instances, ip)) {
8007c478bdstevel@tonic-gate				r = add_causes(svcp, ip);
8017c478bdstevel@tonic-gate				if (r != 0) {
8027c478bdstevel@tonic-gate					assert(r == ELOOP);
8037c478bdstevel@tonic-gate					uu_list_walk_end(walk);
8047c478bdstevel@tonic-gate					return (r);
8057c478bdstevel@tonic-gate				}
8067c478bdstevel@tonic-gate			}
8077c478bdstevel@tonic-gate		}
8087c478bdstevel@tonic-gate	}
8097c478bdstevel@tonic-gate
8107c478bdstevel@tonic-gate	uu_list_walk_end(walk);
8117c478bdstevel@tonic-gate	return (0);
8127c478bdstevel@tonic-gate}
8137c478bdstevel@tonic-gate
8147c478bdstevel@tonic-gatestatic int
8157c478bdstevel@tonic-gateprocess_reqany(inst_t *svcp, struct dependency_group *dg)
8167c478bdstevel@tonic-gate{
8177c478bdstevel@tonic-gate	svc_t *sp;
8187c478bdstevel@tonic-gate	inst_t *ip;
8197c478bdstevel@tonic-gate	struct dependency *d;
8207c478bdstevel@tonic-gate	int r;
8217c478bdstevel@tonic-gate	uu_list_walk_t *walk;
8227c478bdstevel@tonic-gate
8237c478bdstevel@tonic-gate	for (d = uu_list_first(dg->entities);
8247c478bdstevel@tonic-gate	    d != NULL;
8257c478bdstevel@tonic-gate	    d = uu_list_next(dg->entities, d)) {
8267c478bdstevel@tonic-gate		r = get_fmri(d->fmri, &sp, &ip);
8277c478bdstevel@tonic-gate		switch (r) {
8287c478bdstevel@tonic-gate		case 0:
8297c478bdstevel@tonic-gate			break;
8307c478bdstevel@tonic-gate
8317c478bdstevel@tonic-gate		case EINVAL:
8327c478bdstevel@tonic-gate			/* LINTED */
8337c478bdstevel@tonic-gate			(void) fprintf(stderr, emsg_invalid_dep, svcp->svcname,
8347c478bdstevel@tonic-gate			    svcp->instname, d->fmri);
8357c478bdstevel@tonic-gate			continue;
8367c478bdstevel@tonic-gate
8377c478bdstevel@tonic-gate		case ENOENT:
8387c478bdstevel@tonic-gate			continue;
8397c478bdstevel@tonic-gate
8407c478bdstevel@tonic-gate		default:
8417c478bdstevel@tonic-gate			bad_error("eval_svc_dep", r);
8427c478bdstevel@tonic-gate		}
8437c478bdstevel@tonic-gate
8447c478bdstevel@tonic-gate		if (ip != NULL) {
8457c478bdstevel@tonic-gate			if (inst_running(ip))
8467c478bdstevel@tonic-gate				return (0);
8477c478bdstevel@tonic-gate			continue;
8487c478bdstevel@tonic-gate		}
8497c478bdstevel@tonic-gate
8507c478bdstevel@tonic-gate		for (ip = uu_list_first(sp->instances);
8517c478bdstevel@tonic-gate		    ip != NULL;
8527c478bdstevel@tonic-gate		    ip = uu_list_next(sp->instances, ip)) {
8537c478bdstevel@tonic-gate			if (inst_running(ip))
8547c478bdstevel@tonic-gate				return (0);
8557c478bdstevel@tonic-gate		}
8567c478bdstevel@tonic-gate	}
8577c478bdstevel@tonic-gate
8587c478bdstevel@tonic-gate	/*
8597c478bdstevel@tonic-gate	 * The dependency group is not satisfied.  Add all unsatisfied members
8607c478bdstevel@tonic-gate	 * to the cause list.
8617c478bdstevel@tonic-gate	 */
8627c478bdstevel@tonic-gate
8637c478bdstevel@tonic-gate	walk = uu_list_walk_start(dg->entities, UU_WALK_ROBUST);
8647c478bdstevel@tonic-gate	if (walk == NULL)
8657c478bdstevel@tonic-gate		uu_die(emsg_nomem);
8667c478bdstevel@tonic-gate
8677c478bdstevel@tonic-gate	while ((d = uu_list_walk_next(walk)) != NULL) {
8687c478bdstevel@tonic-gate		r = get_fmri(d->fmri, &sp, &ip);
8697c478bdstevel@tonic-gate		switch (r) {
8707c478bdstevel@tonic-gate		case 0:
8717c478bdstevel@tonic-gate			break;
8727c478bdstevel@tonic-gate
8737c478bdstevel@tonic-gate		case ENOENT:
8747c478bdstevel@tonic-gate			uu_list_remove(dg->entities, d);
8757c478bdstevel@tonic-gate			r = uu_list_append(svcp->baddeps, d);
8767c478bdstevel@tonic-gate			assert(r == 0);
8777c478bdstevel@tonic-gate			continue;
8787c478bdstevel@tonic-gate
8797c478bdstevel@tonic-gate		case EINVAL:
8807c478bdstevel@tonic-gate			/* Should have caught above. */
8817c478bdstevel@tonic-gate		default:
8827c478bdstevel@tonic-gate			bad_error("eval_svc_dep", r);
8837c478bdstevel@tonic-gate		}
8847c478bdstevel@tonic-gate
8857c478bdstevel@tonic-gate		if (ip != NULL) {
8867c478bdstevel@tonic-gate			if (inst_running(ip))
8877c478bdstevel@tonic-gate				continue;
8887c478bdstevel@tonic-gate			r = add_causes(svcp, ip);
8897c478bdstevel@tonic-gate			if (r != 0) {
8907c478bdstevel@tonic-gate				assert(r == ELOOP);
8917c478bdstevel@tonic-gate				return (r);
8927c478bdstevel@tonic-gate			}
8937c478bdstevel@tonic-gate			continue;
8947c478bdstevel@tonic-gate		}
8957c478bdstevel@tonic-gate
8967c478bdstevel@tonic-gate		for (ip = uu_list_first(sp->instances);
8977c478bdstevel@tonic-gate		    ip != NULL;
8987c478bdstevel@tonic-gate		    ip = uu_list_next(sp->instances, ip)) {
8997c478bdstevel@tonic-gate			if (inst_running(ip))
9007c478bdstevel@tonic-gate				continue;
9017c478bdstevel@tonic-gate			r = add_causes(svcp, ip);
9027c478bdstevel@tonic-gate			if (r != 0) {
9037c478bdstevel@tonic-gate				assert(r == ELOOP);
9047c478bdstevel@tonic-gate				return (r);
9057c478bdstevel@tonic-gate			}
9067c478bdstevel@tonic-gate		}
9077c478bdstevel@tonic-gate	}
9087c478bdstevel@tonic-gate
9097c478bdstevel@tonic-gate	return (0);
9107c478bdstevel@tonic-gate}
9117c478bdstevel@tonic-gate
9127c478bdstevel@tonic-gatestatic int
9137c478bdstevel@tonic-gateprocess_optall(inst_t *svcp, struct dependency_group *dg)
9147c478bdstevel@tonic-gate{
9157c478bdstevel@tonic-gate	uu_list_walk_t *walk;
9167c478bdstevel@tonic-gate	struct dependency *d;
9177c478bdstevel@tonic-gate	int r;
9187c478bdstevel@tonic-gate	inst_t *ip;
9197c478bdstevel@tonic-gate	svc_t *sp;
9207c478bdstevel@tonic-gate
9217c478bdstevel@tonic-gate	walk = uu_list_walk_start(dg->entities, UU_WALK_ROBUST);
9227c478bdstevel@tonic-gate	if (walk == NULL)
9237c478bdstevel@tonic-gate		uu_die(emsg_nomem);
9247c478bdstevel@tonic-gate
9257c478bdstevel@tonic-gate	while ((d = uu_list_walk_next(walk)) != NULL) {
9267c478bdstevel@tonic-gate		r = get_fmri(d->fmri, &sp, &ip);
9277c478bdstevel@tonic-gate
9287c478bdstevel@tonic-gate		switch (r) {
9297c478bdstevel@tonic-gate		case 0:
9307c478bdstevel@tonic-gate			break;
9317c478bdstevel@tonic-gate
9327c478bdstevel@tonic-gate		case EINVAL:
9337c478bdstevel@tonic-gate			/* LINTED */
9347c478bdstevel@tonic-gate			(void) fprintf(stderr, emsg_invalid_dep, svcp->svcname,
9357c478bdstevel@tonic-gate			    svcp->instname, d->fmri);
9367c478bdstevel@tonic-gate			continue;
9377c478bdstevel@tonic-gate
9387c478bdstevel@tonic-gate		case ENOENT:
9397c478bdstevel@tonic-gate			continue;
9407c478bdstevel@tonic-gate
9417c478bdstevel@tonic-gate		default:
9427c478bdstevel@tonic-gate			bad_error("get_fmri", r);
9437c478bdstevel@tonic-gate		}
9447c478bdstevel@tonic-gate
9457c478bdstevel@tonic-gate		if (ip != NULL) {
9462e1a947Liane Praza			if ((ip->enabled != 0) && !inst_running_or_maint(ip)) {
9477c478bdstevel@tonic-gate				r = add_causes(svcp, ip);
9487c478bdstevel@tonic-gate				if (r != 0) {
9497c478bdstevel@tonic-gate					assert(r == ELOOP);
9507c478bdstevel@tonic-gate					uu_list_walk_end(walk);
9517c478bdstevel@tonic-gate					return (r);
9527c478bdstevel@tonic-gate				}
9537c478bdstevel@tonic-gate			}
9547c478bdstevel@tonic-gate			continue;
9557c478bdstevel@tonic-gate		}
9567c478bdstevel@tonic-gate
9577c478bdstevel@tonic-gate		for (ip = uu_list_first(sp->instances);
9587c478bdstevel@tonic-gate		    ip != NULL;
9597c478bdstevel@tonic-gate		    ip = uu_list_next(sp->instances, ip)) {
9602e1a947Liane Praza			if ((ip->enabled != 0) && !inst_running_or_maint(ip)) {
9617c478bdstevel@tonic-gate				r = add_causes(svcp, ip);
9627c478bdstevel@tonic-gate				if (r != 0) {
9637c478bdstevel@tonic-gate					assert(r == ELOOP);
9647c478bdstevel@tonic-gate					uu_list_walk_end(walk);
9657c478bdstevel@tonic-gate					return (r);
9667c478bdstevel@tonic-gate				}
9677c478bdstevel@tonic-gate			}
9687c478bdstevel@tonic-gate		}
9697c478bdstevel@tonic-gate	}
9707c478bdstevel@tonic-gate
9717c478bdstevel@tonic-gate	uu_list_walk_end(walk);
9727c478bdstevel@tonic-gate	return (0);
9737c478bdstevel@tonic-gate}
9747c478bdstevel@tonic-gate
9757c478bdstevel@tonic-gatestatic int
9767c478bdstevel@tonic-gateprocess_excall(inst_t *svcp, struct dependency_group *dg)
9777c478bdstevel@tonic-gate{
9787c478bdstevel@tonic-gate	struct dependency *d;
9797c478bdstevel@tonic-gate	int r;
9807c478bdstevel@tonic-gate	svc_t *sp;
9817c478bdstevel@tonic-gate	inst_t *ip;
9827c478bdstevel@tonic-gate
9837c478bdstevel@tonic-gate	for (d = uu_list_first(dg->entities);
9847c478bdstevel@tonic-gate	    d != NULL;
9857c478bdstevel@tonic-gate	    d = uu_list_next(dg->entities, d)) {
9867c478bdstevel@tonic-gate		r = get_fmri(d->fmri, &sp, &ip);
9877c478bdstevel@tonic-gate
9887c478bdstevel@tonic-gate		switch (r) {
9897c478bdstevel@tonic-gate		case 0:
9907c478bdstevel@tonic-gate			break;
9917c478bdstevel@tonic-gate
9927c478bdstevel@tonic-gate		case EINVAL:
9937c478bdstevel@tonic-gate			/* LINTED */
9947c478bdstevel@tonic-gate			(void) fprintf(stderr, emsg_invalid_dep, svcp->svcname,
9957c478bdstevel@tonic-gate			    svcp->instname, d->fmri);
9967c478bdstevel@tonic-gate			continue;
9977c478bdstevel@tonic-gate
9987c478bdstevel@tonic-gate		case ENOENT:
9997c478bdstevel@tonic-gate			continue;
10007c478bdstevel@tonic-gate
10017c478bdstevel@tonic-gate		default:
10027c478bdstevel@tonic-gate			bad_error("eval_svc_dep", r);
10037c478bdstevel@tonic-gate		}
10047c478bdstevel@tonic-gate
10057c478bdstevel@tonic-gate		if (ip != NULL) {
10067c478bdstevel@tonic-gate			if (inst_running(ip)) {
10077c478bdstevel@tonic-gate				r = add_causes(svcp, ip);
10087c478bdstevel@tonic-gate				if (r != 0) {
10097c478bdstevel@tonic-gate					assert(r == ELOOP);
10107c478bdstevel@tonic-gate					return (r);
10117c478bdstevel@tonic-gate				}
10127c478bdstevel@tonic-gate			}
10137c478bdstevel@tonic-gate			continue;
10147c478bdstevel@tonic-gate		}
10157c478bdstevel@tonic-gate
10167c478bdstevel@tonic-gate		for (ip = uu_list_first(sp->instances);
10177c478bdstevel@tonic-gate		    ip != NULL;
10187c478bdstevel@tonic-gate		    ip = uu_list_next(sp->instances, ip)) {
10197c478bdstevel@tonic-gate			if (inst_running(ip)) {
10207c478bdstevel@tonic-gate				r = add_causes(svcp, ip);
10217c478bdstevel@tonic-gate				if (r != 0) {
10227c478bdstevel@tonic-gate					assert(r == ELOOP);
10237c478bdstevel@tonic-gate					return (r);
10247c478bdstevel@tonic-gate				}
10257c478bdstevel@tonic-gate			}
10267c478bdstevel@tonic-gate		}
10277c478bdstevel@tonic-gate	}
10287c478bdstevel@tonic-gate
10297c478bdstevel@tonic-gate	return (0);
10307c478bdstevel@tonic-gate}
10317c478bdstevel@tonic-gate
10327c478bdstevel@tonic-gatestatic int
10337c478bdstevel@tonic-gateprocess_svc_dg(inst_t *svcp, struct dependency_group *dg)
10347c478bdstevel@tonic-gate{
10357c478bdstevel@tonic-gate	switch (dg->grouping) {
10367c478bdstevel@tonic-gate	case DGG_REQALL:
10377c478bdstevel@tonic-gate		return (process_reqall(svcp, dg));
10387c478bdstevel@tonic-gate
10397c478bdstevel@tonic-gate	case DGG_REQANY:
10407c478bdstevel@tonic-gate		return (process_reqany(svcp, dg));
10417c478bdstevel@tonic-gate
10427c478bdstevel@tonic-gate	case DGG_OPTALL:
10437c478bdstevel@tonic-gate		return (process_optall(svcp, dg));
10447c478bdstevel@tonic-gate
10457c478bdstevel@tonic-gate	case DGG_EXCALL:
10467c478bdstevel@tonic-gate		return (process_excall(svcp, dg));
10477c478bdstevel@tonic-gate
10487c478bdstevel@tonic-gate	default:
10497c478bdstevel@tonic-gate#ifndef NDEBUG
10507c478bdstevel@tonic-gate		(void) fprintf(stderr,
10517c478bdstevel@tonic-gate		    "%s:%d: Unknown dependency grouping %d.\n", __FILE__,
10527c478bdstevel@tonic-gate		    __LINE__, dg->grouping);
10537c478bdstevel@tonic-gate#endif
10547c478bdstevel@tonic-gate		abort();
10557c478bdstevel@tonic-gate		/* NOTREACHED */
10567c478bdstevel@tonic-gate	}
10577c478bdstevel@tonic-gate}
10587c478bdstevel@tonic-gate
10597c478bdstevel@tonic-gate/*
10607c478bdstevel@tonic-gate * Returns
10617c478bdstevel@tonic-gate *   EINVAL - fmri is not a valid FMRI
10627c478bdstevel@tonic-gate *   0 - the file indicated by fmri is missing
10637c478bdstevel@tonic-gate *   1 - the file indicated by fmri is present
10647c478bdstevel@tonic-gate */
10657c478bdstevel@tonic-gatestatic int
10667c478bdstevel@tonic-gateeval_file_dep(const char *fmri)
10677c478bdstevel@tonic-gate{
10687c478bdstevel@tonic-gate	const char *path;
10697c478bdstevel@tonic-gate	struct stat st;
10707c478bdstevel@tonic-gate
10717c478bdstevel@tonic-gate	if (strncmp(fmri, "file:", sizeof ("file:") - 1) != 0)
10727c478bdstevel@tonic-gate		return (EINVAL);
10737c478bdstevel@tonic-gate
10747c478bdstevel@tonic-gate	path = fmri + (sizeof ("file:") - 1);
10757c478bdstevel@tonic-gate
10767c478bdstevel@tonic-gate	if (path[0] != '/')
10777c478bdstevel@tonic-gate		return (EINVAL);
10787c478bdstevel@tonic-gate
10797c478bdstevel@tonic-gate	if (path[1] == '/') {
10807c478bdstevel@tonic-gate		path += 2;
10817c478bdstevel@tonic-gate		if (strncmp(path, "localhost/", sizeof ("localhost/") - 1) == 0)
10827c478bdstevel@tonic-gate			path += sizeof ("localhost") - 1;
10837c478bdstevel@tonic-gate		else if (path[0] != '/')
10847c478bdstevel@tonic-gate			return (EINVAL);
10857c478bdstevel@tonic-gate	}
10867c478bdstevel@tonic-gate
10877c478bdstevel@tonic-gate	return (stat(path, &st) == 0 ? 1 : 0);
10887c478bdstevel@tonic-gate}
10897c478bdstevel@tonic-gate
10907c478bdstevel@tonic-gatestatic void
10917c478bdstevel@tonic-gateprocess_file_dg(inst_t *svcp, struct dependency_group *dg)
10927c478bdstevel@tonic-gate{
10937c478bdstevel@tonic-gate	uu_list_walk_t *walk;
10947c478bdstevel@tonic-gate	struct dependency *d, **deps;
10957c478bdstevel@tonic-gate	int r, i = 0, any_satisfied = 0;
10967c478bdstevel@tonic-gate
10977c478bdstevel@tonic-gate	if (dg->grouping == DGG_REQANY) {
10987c478bdstevel@tonic-gate		deps = calloc(uu_list_numnodes(dg->entities), sizeof (*deps));
10997c478bdstevel@tonic-gate		if (deps == NULL)
11007c478bdstevel@tonic-gate			uu_die(emsg_nomem);
11017c478bdstevel@tonic-gate	}
11027c478bdstevel@tonic-gate
11037c478bdstevel@tonic-gate	walk = uu_list_walk_start(dg->entities, UU_WALK_ROBUST);
11047c478bdstevel@tonic-gate	if (walk == NULL)
11057c478bdstevel@tonic-gate		uu_die(emsg_nomem);
11067c478bdstevel@tonic-gate
11077c478bdstevel@tonic-gate	while ((d = uu_list_walk_next(walk)) != NULL) {
11087c478bdstevel@tonic-gate		r = eval_file_dep(d->fmri);
11097c478bdstevel@tonic-gate		if (r == EINVAL) {
11107c478bdstevel@tonic-gate			/* LINTED */
11117c478bdstevel@tonic-gate			(void) fprintf(stderr, emsg_invalid_dep, svcp->svcname,
11127c478bdstevel@tonic-gate			    svcp->instname, d->fmri);
11137c478bdstevel@tonic-gate			continue;
11147c478bdstevel@tonic-gate		}
11157c478bdstevel@tonic-gate
11167c478bdstevel@tonic-gate		assert(r == 0 || r == 1);
11177c478bdstevel@tonic-gate
11187c478bdstevel@tonic-gate		switch (dg->grouping) {
11197c478bdstevel@tonic-gate		case DGG_REQALL:
11207c478bdstevel@tonic-gate		case DGG_OPTALL:
11217c478bdstevel@tonic-gate			if (r == 0) {
11227c478bdstevel@tonic-gate				uu_list_remove(dg->entities, d);
11237c478bdstevel@tonic-gate				r = uu_list_append(svcp->baddeps, d);
11247c478bdstevel@tonic-gate				assert(r == 0);
11257c478bdstevel@tonic-gate			}
11267c478bdstevel@tonic-gate			break;
11277c478bdstevel@tonic-gate
11287c478bdstevel@tonic-gate		case DGG_REQANY:
11297c478bdstevel@tonic-gate			if (r == 1)
11307c478bdstevel@tonic-gate				any_satisfied = 1;
11317c478bdstevel@tonic-gate			else
11327c478bdstevel@tonic-gate				deps[i++] = d;
11337c478bdstevel@tonic-gate			break;
11347c478bdstevel@tonic-gate
11357c478bdstevel@tonic-gate		case DGG_EXCALL:
11367c478bdstevel@tonic-gate			if (r == 1) {
11377c478bdstevel@tonic-gate				uu_list_remove(dg->entities, d);
11387c478bdstevel@tonic-gate				r = uu_list_append(svcp->baddeps, d);
11397c478bdstevel@tonic-gate				assert(r == 0);
11407c478bdstevel@tonic-gate			}
11417c478bdstevel@tonic-gate			break;
11427c478bdstevel@tonic-gate
11437c478bdstevel@tonic-gate		default:
11447c478bdstevel@tonic-gate#ifndef NDEBUG
11457c478bdstevel@tonic-gate			(void) fprintf(stderr, "%s:%d: Unknown grouping %d.\n",
11467c478bdstevel@tonic-gate			    __FILE__, __LINE__, dg->grouping);
11477c478bdstevel@tonic-gate#endif
11487c478bdstevel@tonic-gate			abort();
11497c478bdstevel@tonic-gate		}
11507c478bdstevel@tonic-gate	}
11517c478bdstevel@tonic-gate
11527c478bdstevel@tonic-gate	uu_list_walk_end(walk);
11537c478bdstevel@tonic-gate
11547c478bdstevel@tonic-gate	if (dg->grouping != DGG_REQANY)
11557c478bdstevel@tonic-gate		return;
11567c478bdstevel@tonic-gate
11577c478bdstevel@tonic-gate	if (!any_satisfied) {
1158d87bb7drm		while (--i >= 0) {
11597c478bdstevel@tonic-gate			uu_list_remove(dg->entities, deps[i]);
11607c478bdstevel@tonic-gate			r = uu_list_append(svcp->baddeps, deps[i]);
11617c478bdstevel@tonic-gate			assert(r == 0);
11627c478bdstevel@tonic-gate		}
11637c478bdstevel@tonic-gate	}
11647c478bdstevel@tonic-gate
11657c478bdstevel@tonic-gate	free(deps);
11667c478bdstevel@tonic-gate}
11677c478bdstevel@tonic-gate
11687c478bdstevel@tonic-gate/*
11697c478bdstevel@tonic-gate * Populate the causes list of svcp.  This function should not return with
11707c478bdstevel@tonic-gate * causes empty.
11717c478bdstevel@tonic-gate */
11727c478bdstevel@tonic-gatestatic int
11737c478bdstevel@tonic-gatedetermine_causes(inst_t *svcp, void *canfailp)
11747c478bdstevel@tonic-gate{
11757c478bdstevel@tonic-gate	struct dependency_group *dg;
11767c478bdstevel@tonic-gate	int r;
11777c478bdstevel@tonic-gate
11787c478bdstevel@tonic-gate	if (svcp->active) {
11797c478bdstevel@tonic-gate		(void) fprintf(stderr, gettext("Dependency cycle detected:\n"
11807c478bdstevel@tonic-gate		    "  svc:/%s:%s\n"), svcp->svcname, svcp->instname);
11817c478bdstevel@tonic-gate		return ((int)canfailp != 0 ? UU_WALK_ERROR : UU_WALK_NEXT);
11827c478bdstevel@tonic-gate	}
11837c478bdstevel@tonic-gate
11847c478bdstevel@tonic-gate	if (svcp->causes != NULL)
11857c478bdstevel@tonic-gate		return (UU_WALK_NEXT);
11867c478bdstevel@tonic-gate
11877c478bdstevel@tonic-gate	svcp->causes = uu_list_create(svcptrs, svcp, UU_LIST_DEBUG);
11887c478bdstevel@tonic-gate	svcp->baddeps = uu_list_create(deps, svcp, UU_LIST_DEBUG);
11897c478bdstevel@tonic-gate	if (svcp->causes == NULL || svcp->baddeps == NULL)
11907c478bdstevel@tonic-gate		uu_die(emsg_nomem);
11917c478bdstevel@tonic-gate
11927c478bdstevel@tonic-gate	if (inst_running(svcp) ||
11937c478bdstevel@tonic-gate	    strcmp(svcp->state, SCF_STATE_STRING_UNINIT) == 0) {
11947c478bdstevel@tonic-gate		/*
11957c478bdstevel@tonic-gate		 * If we're running, add a self-pointer in case we're
11967c478bdstevel@tonic-gate		 * excluding another service.
11977c478bdstevel@tonic-gate		 */
11987c478bdstevel@tonic-gate		add_svcptr(svcp->causes, svcp);
11997c478bdstevel@tonic-gate		return (UU_WALK_NEXT);
12007c478bdstevel@tonic-gate	}
12017c478bdstevel@tonic-gate
12027c478bdstevel@tonic-gate	if (strcmp(svcp->state, SCF_STATE_STRING_MAINT) == 0) {
12037c478bdstevel@tonic-gate		add_svcptr(svcp->causes, svcp);
12047c478bdstevel@tonic-gate		add_svcptr(g_causes, svcp);
12057c478bdstevel@tonic-gate		return (UU_WALK_NEXT);
12067c478bdstevel@tonic-gate	}
12077c478bdstevel@tonic-gate
12087c478bdstevel@tonic-gate	if (strcmp(svcp->state, SCF_STATE_STRING_DISABLED) == 0) {
12097c478bdstevel@tonic-gate		add_svcptr(svcp->causes, svcp);
12102e1a947Liane Praza		if (svcp->enabled != 0)
12117c478bdstevel@tonic-gate			add_svcptr(g_causes, svcp);
12127c478bdstevel@tonic-gate
12137c478bdstevel@tonic-gate		return (UU_WALK_NEXT);
12147c478bdstevel@tonic-gate	}
12157c478bdstevel@tonic-gate
12167c478bdstevel@tonic-gate	if (strcmp(svcp->state, SCF_STATE_STRING_OFFLINE) != 0) {
12177c478bdstevel@tonic-gate		(void) fprintf(stderr,
12187c478bdstevel@tonic-gate		    gettext("svc:/%s:%s has invalid state \"%s\".\n"),
12197c478bdstevel@tonic-gate		    svcp->svcname, svcp->instname, svcp->state);
12207c478bdstevel@tonic-gate		add_svcptr(svcp->causes, svcp);
12217c478bdstevel@tonic-gate		add_svcptr(g_causes, svcp);
12227c478bdstevel@tonic-gate		return (UU_WALK_NEXT);
12237c478bdstevel@tonic-gate	}
12247c478bdstevel@tonic-gate
12257c478bdstevel@tonic-gate	if (strcmp(svcp->next_state, SCF_STATE_STRING_NONE) != 0) {
12267c478bdstevel@tonic-gate		add_svcptr(svcp->causes, svcp);
12277c478bdstevel@tonic-gate		add_svcptr(g_causes, svcp);
12287c478bdstevel@tonic-gate		return (UU_WALK_NEXT);
12297c478bdstevel@tonic-gate	}
12307c478bdstevel@tonic-gate
12317c478bdstevel@tonic-gate	svcp->active = 1;
12327c478bdstevel@tonic-gate
12337c478bdstevel@tonic-gate	/*
12347c478bdstevel@tonic-gate	 * Dependency analysis can add elements to our baddeps list (absent
12357c478bdstevel@tonic-gate	 * dependency, unsatisfied file dependency), or to our cause list
12367c478bdstevel@tonic-gate	 * (unsatisfied dependency).
12377c478bdstevel@tonic-gate	 */
12387c478bdstevel@tonic-gate	for (dg = uu_list_first(svcp->dependencies);
12397c478bdstevel@tonic-gate	    dg != NULL;
12407c478bdstevel@tonic-gate	    dg = uu_list_next(svcp->dependencies, dg)) {
12417c478bdstevel@tonic-gate		if (strcmp(dg->type, "path") == 0) {
12427c478bdstevel@tonic-gate			process_file_dg(svcp, dg);
12437c478bdstevel@tonic-gate		} else if (strcmp(dg->type, "service") == 0) {
12447c478bdstevel@tonic-gate			int r;
12457c478bdstevel@tonic-gate
12467c478bdstevel@tonic-gate			r = process_svc_dg(svcp, dg);
12477c478bdstevel@tonic-gate			if (r != 0) {
12487c478bdstevel@tonic-gate				assert(r == ELOOP);
12497c478bdstevel@tonic-gate				svcp->active = 0;
12507c478bdstevel@tonic-gate				return ((int)canfailp != 0 ?
12517c478bdstevel@tonic-gate				    UU_WALK_ERROR : UU_WALK_NEXT);
12527c478bdstevel@tonic-gate			}
12537c478bdstevel@tonic-gate		} else {
12547c478bdstevel@tonic-gate			(void) fprintf(stderr, gettext("svc:/%s:%s has "
12557c478bdstevel@tonic-gate			    "dependency group with invalid type \"%s\".\n"),
12567c478bdstevel@tonic-gate			    svcp->svcname, svcp->instname, dg->type);
12577c478bdstevel@tonic-gate		}
12587c478bdstevel@tonic-gate	}
12597c478bdstevel@tonic-gate
12607c478bdstevel@tonic-gate	if (uu_list_numnodes(svcp->causes) == 0) {
12617c478bdstevel@tonic-gate		if (uu_list_numnodes(svcp->baddeps) > 0) {
12627c478bdstevel@tonic-gate			add_svcptr(g_causes, svcp);
12637c478bdstevel@tonic-gate			add_svcptr(svcp->causes, svcp);
12647c478bdstevel@tonic-gate		} else {
12657c478bdstevel@tonic-gate			inst_t *restarter;
12667c478bdstevel@tonic-gate
12677c478bdstevel@tonic-gate			r = get_fmri(svcp->restarter, NULL, &restarter);
12687c478bdstevel@tonic-gate			if (r == 0 && !inst_running(restarter)) {
12697c478bdstevel@tonic-gate				r = add_causes(svcp, restarter);
12707c478bdstevel@tonic-gate				if (r != 0) {
12717c478bdstevel@tonic-gate					assert(r == ELOOP);
12727c478bdstevel@tonic-gate					svcp->active = 0;
12737c478bdstevel@tonic-gate					return ((int)canfailp != 0 ?
12747c478bdstevel@tonic-gate					    UU_WALK_ERROR : UU_WALK_NEXT);
12757c478bdstevel@tonic-gate				}
12767c478bdstevel@tonic-gate			} else {
12777c478bdstevel@tonic-gate				svcp->restarter_bad = r;
12787c478bdstevel@tonic-gate				add_svcptr(svcp->causes, svcp);
12797c478bdstevel@tonic-gate				add_svcptr(g_causes, svcp);
12807c478bdstevel@tonic-gate			}
12817c478bdstevel@tonic-gate		}
12827c478bdstevel@tonic-gate	}
12837c478bdstevel@tonic-gate
12847c478bdstevel@tonic-gate	assert(uu_list_numnodes(svcp->causes) > 0);
12857c478bdstevel@tonic-gate
12867c478bdstevel@tonic-gate	svcp->active = 0;
12877c478bdstevel@tonic-gate	return (UU_WALK_NEXT);
12887c478bdstevel@tonic-gate}
12897c478bdstevel@tonic-gate
12907c478bdstevel@tonic-gatestatic void
12917c478bdstevel@tonic-gatedetermine_all_causes(void)
12927c478bdstevel@tonic-gate{
12937c478bdstevel@tonic-gate	svc_t *svcp;
12947c478bdstevel@tonic-gate	int i;
12957c478bdstevel@tonic-gate
12967c478bdstevel@tonic-gate	for (i = 0; i < SVC_HASH_NBUCKETS; ++i) {
12977c478bdstevel@tonic-gate		for (svcp = services[i]; svcp != NULL; svcp = svcp->next)
12987c478bdstevel@tonic-gate			(void) uu_list_walk(svcp->instances,
12997c478bdstevel@tonic-gate			    (uu_walk_fn_t *)determine_causes, 0, 0);
13007c478bdstevel@tonic-gate	}
13017c478bdstevel@tonic-gate}
13027c478bdstevel@tonic-gate
13037c478bdstevel@tonic-gate/*
13047c478bdstevel@tonic-gate * Returns
13057c478bdstevel@tonic-gate *   0 - success
13067c478bdstevel@tonic-gate *   ELOOP - dependency cycle detected
13077c478bdstevel@tonic-gate */
13087c478bdstevel@tonic-gatestatic int
13097c478bdstevel@tonic-gatedetermine_impact(inst_t *ip)
13107c478bdstevel@tonic-gate{
13117c478bdstevel@tonic-gate	struct svcptr *idsp, *spp, *copy;
13127c478bdstevel@tonic-gate	uu_list_index_t idx;
13137c478bdstevel@tonic-gate
13147c478bdstevel@tonic-gate	if (ip->active) {
13157c478bdstevel@tonic-gate		(void) fprintf(stderr, gettext("Dependency cycle detected:\n"
13167c478bdstevel@tonic-gate		    "  svc:/%s:%s\n"), ip->svcname, ip->instname);
13177c478bdstevel@tonic-gate		return (ELOOP);
13187c478bdstevel@tonic-gate	}
13197c478bdstevel@tonic-gate
13207c478bdstevel@tonic-gate	if (ip->impact != NULL)
13217c478bdstevel@tonic-gate		return (0);
13227c478bdstevel@tonic-gate
13237c478bdstevel@tonic-gate	ip->impact = uu_list_create(svcptrs, ip, UU_LIST_DEBUG);
13247c478bdstevel@tonic-gate	if (ip->impact == NULL)
13257c478bdstevel@tonic-gate		uu_die(emsg_nomem);
13267c478bdstevel@tonic-gate	ip->active = 1;
13277c478bdstevel@tonic-gate
13287c478bdstevel@tonic-gate	for (idsp = uu_list_first(ip->impact_dependents);
13297c478bdstevel@tonic-gate	    idsp != NULL;
13307c478bdstevel@tonic-gate	    idsp = uu_list_next(ip->impact_dependents, idsp)) {
13317c478bdstevel@tonic-gate		if (determine_impact(idsp->svcp) != 0) {
13327c478bdstevel@tonic-gate			(void) fprintf(stderr, "  svc:/%s:%s\n",
13337c478bdstevel@tonic-gate			    ip->svcname, ip->instname);
13347c478bdstevel@tonic-gate			return (ELOOP);
13357c478bdstevel@tonic-gate		}
13367c478bdstevel@tonic-gate
13377c478bdstevel@tonic-gate		add_svcptr(ip->impact, idsp->svcp);
13387c478bdstevel@tonic-gate
13397c478bdstevel@tonic-gate		for (spp = uu_list_first(idsp->svcp->impact);
13407c478bdstevel@tonic-gate		    spp != NULL;
13417c478bdstevel@tonic-gate		    spp = uu_list_next(idsp->svcp->impact, spp)) {
13427c478bdstevel@tonic-gate			if (uu_list_find(ip->impact, spp, NULL, &idx) != NULL)
13437c478bdstevel@tonic-gate				continue;
13447c478bdstevel@tonic-gate
13457c478bdstevel@tonic-gate			copy = safe_malloc(sizeof (*copy));
13467c478bdstevel@tonic-gate			copy->svcp = spp->svcp;
13477c478bdstevel@tonic-gate			copy->next_hop = NULL;
13487c478bdstevel@tonic-gate			uu_list_node_init(copy, &copy->node, svcptrs);
13497c478bdstevel@tonic-gate			uu_list_insert(ip->impact, copy, idx);
13507c478bdstevel@tonic-gate		}
13517c478bdstevel@tonic-gate	}
13527c478bdstevel@tonic-gate
13537c478bdstevel@tonic-gate	ip->active = 0;
13547c478bdstevel@tonic-gate	return (0);
13557c478bdstevel@tonic-gate}
13567c478bdstevel@tonic-gate
13577c478bdstevel@tonic-gate/*
13587c478bdstevel@tonic-gate * Printing routines.
13597c478bdstevel@tonic-gate */
13607c478bdstevel@tonic-gate
13617c478bdstevel@tonic-gatestatic void
13627c478bdstevel@tonic-gatecheck_msgbase(void)
13637c478bdstevel@tonic-gate{
13647c478bdstevel@tonic-gate	if (scf_handle_decode_fmri(h, SCF_SERVICE_STARTD, NULL, NULL, g_inst,
13657c478bdstevel@tonic-gate	    NULL, NULL, SCF_DECODE_FMRI_EXACT) != 0) {
13667c478bdstevel@tonic-gate		if (scf_error() != SCF_ERROR_NOT_FOUND)
13677c478bdstevel@tonic-gate			scfdie();
13687c478bdstevel@tonic-gate
13697c478bdstevel@tonic-gate		return;
13707c478bdstevel@tonic-gate	}
13717c478bdstevel@tonic-gate
13727c478bdstevel@tonic-gate	if (scf_instance_get_pg_composed(g_inst, NULL, "msg", g_pg) != 0) {
13737c478bdstevel@tonic-gate		switch (scf_error()) {
13747c478bdstevel@tonic-gate		case SCF_ERROR_NOT_FOUND:
13757c478bdstevel@tonic-gate		case SCF_ERROR_DELETED:
13767c478bdstevel@tonic-gate			return;
13777c478bdstevel@tonic-gate
13787c478bdstevel@tonic-gate		default:
13797c478bdstevel@tonic-gate			scfdie();
13807c478bdstevel@tonic-gate		}
13817c478bdstevel@tonic-gate	}
13827c478bdstevel@tonic-gate
13837c478bdstevel@tonic-gate	if (scf_pg_get_property(g_pg, "base", g_prop) != 0) {
13847c478bdstevel@tonic-gate		switch (scf_error()) {
13857c478bdstevel@tonic-gate		case SCF_ERROR_NOT_FOUND:
13867c478bdstevel@tonic-gate		case SCF_ERROR_DELETED:
13877c478bdstevel@tonic-gate			return;
13887c478bdstevel@tonic-gate
13897c478bdstevel@tonic-gate		default:
13907c478bdstevel@tonic-gate			scfdie();
13917c478bdstevel@tonic-gate		}
13927c478bdstevel@tonic-gate	}
13937c478bdstevel@tonic-gate
13947c478bdstevel@tonic-gate	if (scf_property_get_value(g_prop, g_val) != 0) {
13957c478bdstevel@tonic-gate		switch (scf_error()) {
13967c478bdstevel@tonic-gate		case SCF_ERROR_NOT_FOUND:
13977c478bdstevel@tonic-gate		case SCF_ERROR_CONSTRAINT_VIOLATED:
13983eae19dwesolows		case SCF_ERROR_PERMISSION_DENIED:
13997c478bdstevel@tonic-gate			g_msgbase = NULL;
14007c478bdstevel@tonic-gate			return;
14017c478bdstevel@tonic-gate
14027c478bdstevel@tonic-gate		case SCF_ERROR_DELETED:
14037c478bdstevel@tonic-gate			return;
14047c478bdstevel@tonic-gate
14057c478bdstevel@tonic-gate		default:
14067c478bdstevel@tonic-gate			scfdie();
14077c478bdstevel@tonic-gate		}
14087c478bdstevel@tonic-gate	}
14097c478bdstevel@tonic-gate
14107c478bdstevel@tonic-gate	if (scf_value_get_astring(g_val, g_value, g_value_sz) < 0) {
14117c478bdstevel@tonic-gate		if (scf_error() != SCF_ERROR_TYPE_MISMATCH)
14127c478bdstevel@tonic-gate			scfdie();
14137c478bdstevel@tonic-gate		return;
14147c478bdstevel@tonic-gate	}
14157c478bdstevel@tonic-gate
14167c478bdstevel@tonic-gate	g_msgbase = safe_strdup(g_value);
14177c478bdstevel@tonic-gate}
14187c478bdstevel@tonic-gate
14197c478bdstevel@tonic-gatestatic void
14207c478bdstevel@tonic-gatedetermine_summary(inst_t *ip)
14217c478bdstevel@tonic-gate{
14227c478bdstevel@tonic-gate	if (ip->summary != NULL)
14237c478bdstevel@tonic-gate		return;
14247c478bdstevel@tonic-gate
14257c478bdstevel@tonic-gate	if (inst_running(ip)) {
14267c478bdstevel@tonic-gate		ip->summary = gettext("is running.");
14277c478bdstevel@tonic-gate		return;
14287c478bdstevel@tonic-gate	}
14297c478bdstevel@tonic-gate
14307c478bdstevel@tonic-gate	if (strcmp(ip->state, SCF_STATE_STRING_UNINIT) == 0) {
14317c478bdstevel@tonic-gate		ip->summary = gettext("is uninitialized.");
14327c478bdstevel@tonic-gate	} else if (strcmp(ip->state, SCF_STATE_STRING_DISABLED) == 0) {
14337c478bdstevel@tonic-gate		if (!ip->temporary)
14347c478bdstevel@tonic-gate			ip->summary = gettext("is disabled.");
14357c478bdstevel@tonic-gate		else
14367c478bdstevel@tonic-gate			ip->summary = gettext("is temporarily disabled.");
14377c478bdstevel@tonic-gate	} else if (strcmp(ip->state, SCF_STATE_STRING_OFFLINE) == 0) {
14387c478bdstevel@tonic-gate		if (uu_list_numnodes(ip->baddeps) != 0)
14397c478bdstevel@tonic-gate			ip->summary = gettext("has missing dependencies.");
14407c478bdstevel@tonic-gate		else if (strcmp(ip->next_state, SCF_STATE_STRING_ONLINE) == 0)
14417c478bdstevel@tonic-gate			ip->summary = gettext("is starting.");
14427c478bdstevel@tonic-gate		else
14437c478bdstevel@tonic-gate			ip->summary = gettext("is offline.");
14447c478bdstevel@tonic-gate	} else if (strcmp(ip->state, SCF_STATE_STRING_MAINT) == 0) {
14457c478bdstevel@tonic-gate		if (strcmp(ip->aux_state, "administrative_request") == 0) {
14467c478bdstevel@tonic-gate			ip->summary = gettext("was taken down for maintenace "
14477c478bdstevel@tonic-gate			    "by an administrator.");
14487c478bdstevel@tonic-gate		} else if (strcmp(ip->aux_state, "dependency_cycle") == 0) {
14497c478bdstevel@tonic-gate			ip->summary = gettext("completed a dependency cycle.");
14507c478bdstevel@tonic-gate		} else if (strcmp(ip->aux_state, "fault_threshold_reached") ==
14517c478bdstevel@tonic-gate		    0) {
14527c478bdstevel@tonic-gate			ip->summary = gettext("is not running because "
14537c478bdstevel@tonic-gate			    "a method failed repeatedly.");
14547c478bdstevel@tonic-gate		} else if (strcmp(ip->aux_state, "invalid_dependency") == 0) {
14557c478bdstevel@tonic-gate			ip->summary = gettext("has an invalid dependency.");
14567c478bdstevel@tonic-gate		} else if (strcmp(ip->aux_state, "invalid_restarter") == 0) {
14577c478bdstevel@tonic-gate			ip->summary = gettext("has an invalid restarter.");
14587c478bdstevel@tonic-gate		} else if (strcmp(ip->aux_state, "method_failed") == 0) {
14597c478bdstevel@tonic-gate			ip->summary = gettext("is not running because "
14607c478bdstevel@tonic-gate			    "a method failed.");
14617c478bdstevel@tonic-gate		} else if (strcmp(ip->aux_state, "none") == 0) {
14627c478bdstevel@tonic-gate			ip->summary =
14637c478bdstevel@tonic-gate			    gettext("is not running for an unknown reason.");
14647c478bdstevel@tonic-gate		} else if (strcmp(ip->aux_state, "restarting_too_quickly") ==
14657c478bdstevel@tonic-gate		    0) {
14667c478bdstevel@tonic-gate			ip->summary = gettext("was restarting too quickly.");
14677c478bdstevel@tonic-gate		} else {
14687c478bdstevel@tonic-gate			ip->summary = gettext("requires maintenance.");
14697c478bdstevel@tonic-gate		}
14707c478bdstevel@tonic-gate	} else {
14717c478bdstevel@tonic-gate		ip->summary = gettext("is in an invalid state.");
14727c478bdstevel@tonic-gate	}
14737c478bdstevel@tonic-gate}
14747c478bdstevel@tonic-gate
14757c478bdstevel@tonic-gatestatic void
14767c478bdstevel@tonic-gateprint_method_failure(const inst_t *ip, const char **dcp)
14777c478bdstevel@tonic-gate{
14787c478bdstevel@tonic-gate	char buf[50];
14797c478bdstevel@tonic-gate	int stat = ip->start_method_waitstatus;
14807c478bdstevel@tonic-gate
14817c478bdstevel@tonic-gate	if (stat != 0) {
14827c478bdstevel@tonic-gate		if (WIFEXITED(stat)) {
14837c478bdstevel@tonic-gate			if (WEXITSTATUS(stat) == SMF_EXIT_ERR_CONFIG) {
14847c478bdstevel@tonic-gate				(void) strlcpy(buf, gettext(
14857c478bdstevel@tonic-gate				    "exited with $SMF_EXIT_ERR_CONFIG"),
14867c478bdstevel@tonic-gate				    sizeof (buf));
14877c478bdstevel@tonic-gate			} else if (WEXITSTATUS(stat) == SMF_EXIT_ERR_FATAL) {
14887c478bdstevel@tonic-gate				(void) strlcpy(buf, gettext(
14897c478bdstevel@tonic-gate				    "exited with $SMF_EXIT_ERR_FATAL"),
14907c478bdstevel@tonic-gate				    sizeof (buf));
14917c478bdstevel@tonic-gate			} else {
14927c478bdstevel@tonic-gate				(void) snprintf(buf, sizeof (buf),
14937c478bdstevel@tonic-gate				    gettext("exited with status %d"),
14947c478bdstevel@tonic-gate				    WEXITSTATUS(stat));
14957c478bdstevel@tonic-gate			}
14967c478bdstevel@tonic-gate		} else if (WIFSIGNALED(stat)) {
14977c478bdstevel@tonic-gate			if (WCOREDUMP(stat)) {
14987c478bdstevel@tonic-gate				if (strsignal(WTERMSIG(stat)) != NULL)
14997c478bdstevel@tonic-gate					(void) snprintf(buf, sizeof (buf),
15007c478bdstevel@tonic-gate					    gettext("dumped core on %s (%d)"),
15017c478bdstevel@tonic-gate					    strsignal(WTERMSIG(stat)),
15027c478bdstevel@tonic-gate					    WTERMSIG(stat));
15037c478bdstevel@tonic-gate				else
15047c478bdstevel@tonic-gate					(void) snprintf(buf, sizeof (buf),
15057c478bdstevel@tonic-gate					    gettext("dumped core signal %d"),
15067c478bdstevel@tonic-gate					    WTERMSIG(stat));
15077c478bdstevel@tonic-gate			} else {
15087c478bdstevel@tonic-gate				if (strsignal(WTERMSIG(stat)) != NULL) {
15097c478bdstevel@tonic-gate					(void) snprintf(buf, sizeof (buf),
15107c478bdstevel@tonic-gate					    gettext("died on %s (%d)"),
15117c478bdstevel@tonic-gate					    strsignal(WTERMSIG(stat)),
15127c478bdstevel@tonic-gate					    WTERMSIG(stat));
15137c478bdstevel@tonic-gate				} else {
15147c478bdstevel@tonic-gate					(void) snprintf(buf, sizeof (buf),
15157c478bdstevel@tonic-gate					    gettext("died on signal %d"),
15167c478bdstevel@tonic-gate					    WTERMSIG(stat));
15177c478bdstevel@tonic-gate				}
15187c478bdstevel@tonic-gate			}
15197c478bdstevel@tonic-gate		} else {
15207c478bdstevel@tonic-gate			goto fail;
15217c478bdstevel@tonic-gate		}
15227c478bdstevel@tonic-gate
15237c478bdstevel@tonic-gate		if (strcmp(ip->aux_state, "fault_threshold_reached") != 0)
15247c478bdstevel@tonic-gate			(void) printf(gettext("Reason: Start method %s.\n"),
15257c478bdstevel@tonic-gate			    buf);
15267c478bdstevel@tonic-gate		else
15277c478bdstevel@tonic-gate			(void) printf(gettext("Reason: "
15287c478bdstevel@tonic-gate			    "Start method failed repeatedly, last %s.\n"), buf);
15297c478bdstevel@tonic-gate		*dcp = DC_STARTFAIL;
15307c478bdstevel@tonic-gate	} else {
15317c478bdstevel@tonic-gatefail:
15327c478bdstevel@tonic-gate		if (strcmp(ip->aux_state, "fault_threshold_reached") == 0)
15337c478bdstevel@tonic-gate			(void) puts(gettext(
15347c478bdstevel@tonic-gate			    "Reason: Method failed repeatedly."));
15357c478bdstevel@tonic-gate		else
15367c478bdstevel@tonic-gate			(void) puts(gettext("Reason: Method failed."));
15377c478bdstevel@tonic-gate		*dcp = DC_METHFAIL;
15387c478bdstevel@tonic-gate	}
15397c478bdstevel@tonic-gate}
15407c478bdstevel@tonic-gate
15417c478bdstevel@tonic-gatestatic void
15427c478bdstevel@tonic-gateprint_dependency_reasons(const inst_t *svcp, int verbose)
15437c478bdstevel@tonic-gate{
15447c478bdstevel@tonic-gate	struct dependency *d;
15457c478bdstevel@tonic-gate	struct svcptr *spp;
15467c478bdstevel@tonic-gate	const char *dc;
15477c478bdstevel@tonic-gate
15487c478bdstevel@tonic-gate	/*
15497c478bdstevel@tonic-gate	 * If we couldn't determine why the service is offline, then baddeps
15507c478bdstevel@tonic-gate	 * will be empty and causes will have a pointer to self.
15517c478bdstevel@tonic-gate	 */
15527c478bdstevel@tonic-gate	if (uu_list_numnodes(svcp->baddeps) == 0 &&
15537c478bdstevel@tonic-gate	    uu_list_numnodes(svcp->causes) == 1) {
15547c478bdstevel@tonic-gate		spp = uu_list_first(svcp->causes);
15557c478bdstevel@tonic-gate		if (spp->svcp == svcp) {
15567c478bdstevel@tonic-gate			switch (svcp->restarter_bad) {
15577c478bdstevel@tonic-gate			case 0:
15587c478bdstevel@tonic-gate				(void) puts(gettext("Reason: Unknown."));
15597c478bdstevel@tonic-gate				dc = DC_UNKNOWN;
15607c478bdstevel@tonic-gate				break;
15617c478bdstevel@tonic-gate
15627c478bdstevel@tonic-gate			case EINVAL:
15637c478bdstevel@tonic-gate				(void) printf(gettext("Reason: "
15647c478bdstevel@tonic-gate				    "Restarter \"%s\" is invalid.\n"),
15657c478bdstevel@tonic-gate				    svcp->restarter);
15667c478bdstevel@tonic-gate				dc = DC_RSTRINVALID;
15677c478bdstevel@tonic-gate				break;
15687c478bdstevel@tonic-gate
15697c478bdstevel@tonic-gate			case ENOENT:
15707c478bdstevel@tonic-gate				(void) printf(gettext("Reason: "
15717c478bdstevel@tonic-gate				    "Restarter \"%s\" does not exist.\n"),
15727c478bdstevel@tonic-gate				    svcp->restarter);
15737c478bdstevel@tonic-gate				dc = DC_RSTRABSENT;
15747c478bdstevel@tonic-gate				break;
15757c478bdstevel@tonic-gate
15767c478bdstevel@tonic-gate			default:
15777c478bdstevel@tonic-gate#ifndef NDEBUG
15787c478bdstevel@tonic-gate				(void) fprintf(stderr, "%s:%d: Bad "
15797c478bdstevel@tonic-gate				    "restarter_bad value %d.  Aborting.\n",
15807c478bdstevel@tonic-gate				    __FILE__, __LINE__, svcp->restarter_bad);
15817c478bdstevel@tonic-gate#endif
15827c478bdstevel@tonic-gate				abort();
15837c478bdstevel@tonic-gate			}
15847c478bdstevel@tonic-gate
15857c478bdstevel@tonic-gate			if (g_msgbase)
15867c478bdstevel@tonic-gate				(void) printf(gettext("   See: %s%s\n"),
15877c478bdstevel@tonic-gate				    g_msgbase, dc);
15887c478bdstevel@tonic-gate			return;
15897c478bdstevel@tonic-gate		}
15907c478bdstevel@tonic-gate	}
15917c478bdstevel@tonic-gate
15927c478bdstevel@tonic-gate	for (d = uu_list_first(svcp->baddeps);
15937c478bdstevel@tonic-gate	    d != NULL;
15947c478bdstevel@tonic-gate	    d = uu_list_next(svcp->baddeps, d)) {
15957c478bdstevel@tonic-gate		(void) printf(gettext("Reason: Dependency %s is absent.\n"),
15967c478bdstevel@tonic-gate		    d->fmri);
15977c478bdstevel@tonic-gate		if (g_msgbase)
15987c478bdstevel@tonic-gate			(void) printf(gettext("   See: %s%s\n"), g_msgbase,
15997c478bdstevel@tonic-gate			    DC_DEPABSENT);
16007c478bdstevel@tonic-gate	}
16017c478bdstevel@tonic-gate
16027c478bdstevel@tonic-gate	for (spp = uu_list_first(svcp->causes);
16037c478bdstevel@tonic-gate	    spp != NULL && spp->svcp != svcp;
16047c478bdstevel@tonic-gate	    spp = uu_list_next(svcp->causes, spp)) {
16057c478bdstevel@tonic-gate		determine_summary(spp->svcp);
16067c478bdstevel@tonic-gate
16077c478bdstevel@tonic-gate		if (inst_running(spp->svcp)) {
16087c478bdstevel@tonic-gate			(void) printf(gettext("Reason: "
16097c478bdstevel@tonic-gate			    "Service svc:/%s:%s is running.\n"),
16107c478bdstevel@tonic-gate			    spp->svcp->svcname, spp->svcp->instname);
16117c478bdstevel@tonic-gate			dc = DC_DEPRUNNING;
16127c478bdstevel@tonic-gate		} else {
16137c478bdstevel@tonic-gate			if (snprintf(NULL, 0,
16147c478bdstevel@tonic-gate			    gettext("Reason: Service svc:/%s:%s %s"),
16157c478bdstevel@tonic-gate			    spp->svcp->svcname, spp->svcp->instname,
16167c478bdstevel@tonic-gate			    spp->svcp->summary) <= 80) {
16177c478bdstevel@tonic-gate				(void) printf(gettext(
16187c478bdstevel@tonic-gate				    "Reason: Service svc:/%s:%s %s\n"),
16197c478bdstevel@tonic-gate				    spp->svcp->svcname, spp->svcp->instname,
16207c478bdstevel@tonic-gate				    spp->svcp->summary);
16217c478bdstevel@tonic-gate			} else {
16227c478bdstevel@tonic-gate				(void) printf(gettext(
16237c478bdstevel@tonic-gate				    "Reason: Service svc:/%s:%s\n"
16247c478bdstevel@tonic-gate				    "        %s\n"), spp->svcp->svcname,
16257c478bdstevel@tonic-gate				    spp->svcp->instname, spp->svcp->summary);
16267c478bdstevel@tonic-gate			}
16277c478bdstevel@tonic-gate
16287c478bdstevel@tonic-gate			dc = DC_DEPOTHER;
16297c478bdstevel@tonic-gate		}
16307c478bdstevel@tonic-gate
16317c478bdstevel@tonic-gate		if (g_msgbase != NULL)
16327c478bdstevel@tonic-gate			(void) printf(gettext("   See: %s%s\n"), g_msgbase, dc);
16337c478bdstevel@tonic-gate
16347c478bdstevel@tonic-gate		if (verbose) {
16357c478bdstevel@tonic-gate			inst_t *pp;
16367c478bdstevel@tonic-gate			int indent;
16377c478bdstevel@tonic-gate
16387c478bdstevel@tonic-gate			(void) printf(gettext("  Path: svc:/%s:%s\n"),
16397c478bdstevel@tonic-gate			    svcp->svcname, svcp->instname);
16407c478bdstevel@tonic-gate
16417c478bdstevel@tonic-gate			indent = 1;
16427c478bdstevel@tonic-gate			for (pp = spp->next_hop; ; ) {
16437c478bdstevel@tonic-gate				struct svcptr *tmp;
16447c478bdstevel@tonic-gate
16457c478bdstevel@tonic-gate				(void) printf(gettext("%6s  %*ssvc:/%s:%s\n"),
16467c478bdstevel@tonic-gate				    "", indent++ * 2, "", pp->svcname,
16477c478bdstevel@tonic-gate				    pp->instname);
16487c478bdstevel@tonic-gate
16497c478bdstevel@tonic-gate				if (pp == spp->svcp)
16507c478bdstevel@tonic-gate					break;
16517c478bdstevel@tonic-gate
16527c478bdstevel@tonic-gate				/* set pp to next_hop of cause with same svcp */
16537c478bdstevel@tonic-gate				tmp = uu_list_find(pp->causes, spp, NULL, NULL);
16547c478bdstevel@tonic-gate				pp = tmp->next_hop;
16557c478bdstevel@tonic-gate			}
16567c478bdstevel@tonic-gate		}
16577c478bdstevel@tonic-gate	}
16587c478bdstevel@tonic-gate}
16597c478bdstevel@tonic-gate
16607c478bdstevel@tonic-gatestatic void
1661eb1a346Truong Nguyenprint_logs(scf_instance_t *inst)
1662eb1a346Truong Nguyen{
1663eb1a346Truong Nguyen	if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, g_pg) != 0)
1664eb1a346Truong Nguyen		return;
1665eb1a346Truong Nguyen
1666eb1a346Truong Nguyen	if (pg_get_single_val(g_pg, SCF_PROPERTY_ALT_LOGFILE,
1667eb1a346Truong Nguyen	    SCF_TYPE_ASTRING, (void *)g_value, g_value_sz, 0) == 0)
1668eb1a346Truong Nguyen		(void) printf(gettext("   See: %s\n"), g_value);
1669eb1a346Truong Nguyen
1670eb1a346Truong Nguyen	if (pg_get_single_val(g_pg, SCF_PROPERTY_LOGFILE,
1671eb1a346Truong Nguyen	    SCF_TYPE_ASTRING, (void *)g_value, g_value_sz, 0) == 0)
1672eb1a346Truong Nguyen		(void) printf(gettext("   See: %s\n"), g_value);
1673eb1a346Truong Nguyen}
1674eb1a346Truong Nguyen
1675eb1a346Truong Nguyenstatic void
1676eb1a346Truong Nguyenprint_aux_fmri_logs(const char *fmri)
1677eb1a346Truong Nguyen{
1678eb1a346Truong Nguyen	scf_instance_t *scf_inst = scf_instance_create(h);
1679eb1a346Truong Nguyen	if (scf_inst == NULL)
1680eb1a346Truong Nguyen		return;
1681eb1a346Truong Nguyen
1682eb1a346Truong Nguyen	if (scf_handle_decode_fmri(h, fmri, NULL, NULL, scf_inst,
1683eb1a346Truong Nguyen	    NULL, NULL, SCF_DECODE_FMRI_EXACT) == 0)
1684eb1a346Truong Nguyen		print_logs(scf_inst);
1685eb1a346Truong Nguyen
1686eb1a346Truong Nguyen	scf_instance_destroy(scf_inst);
1687eb1a346Truong Nguyen}
1688eb1a346Truong Nguyen
1689eb1a346Truong Nguyenstatic void
16907c478bdstevel@tonic-gateprint_reasons(const inst_t *svcp, int verbose)
16917c478bdstevel@tonic-gate{
16927c478bdstevel@tonic-gate	int r;
16937c478bdstevel@tonic-gate	const char *dc = NULL;
16947c478bdstevel@tonic-gate
16957c478bdstevel@tonic-gate	if (strcmp(svcp->state, SCF_STATE_STRING_ONLINE) == 0)
16967c478bdstevel@tonic-gate		return;
16977c478bdstevel@tonic-gate
16987c478bdstevel@tonic-gate	if (strcmp(svcp->state, SCF_STATE_STRING_UNINIT) == 0) {
16997c478bdstevel@tonic-gate		inst_t *rsp;
17007c478bdstevel@tonic-gate
17017c478bdstevel@tonic-gate		r = get_fmri(svcp->restarter, NULL, &rsp);
17027c478bdstevel@tonic-gate		switch (r) {
17037c478bdstevel@tonic-gate		case 0:
17047c478bdstevel@tonic-gate			if (rsp != NULL)
17057c478bdstevel@tonic-gate				break;
17067c478bdstevel@tonic-gate			/* FALLTHROUGH */
17077c478bdstevel@tonic-gate
17087c478bdstevel@tonic-gate		case EINVAL:
17097c478bdstevel@tonic-gate			(void) printf(gettext("Reason: "
17107c478bdstevel@tonic-gate			    "Restarter \"%s\" is invalid.\n"), svcp->restarter);
17117c478bdstevel@tonic-gate			dc = DC_RSTRINVALID;
17127c478bdstevel@tonic-gate			goto diagcode;
17137c478bdstevel@tonic-gate
17147c478bdstevel@tonic-gate		case ENOENT:
17157c478bdstevel@tonic-gate			(void) printf(gettext("Reason: "
17167c478bdstevel@tonic-gate			    "Restarter \"%s\" does not exist.\n"),
17177c478bdstevel@tonic-gate			    svcp->restarter);
17187c478bdstevel@tonic-gate			dc = DC_RSTRABSENT;
17197c478bdstevel@tonic-gate			goto diagcode;
17207c478bdstevel@tonic-gate
17217c478bdstevel@tonic-gate		default:
17227c478bdstevel@tonic-gate			bad_error("get_fmri", r);
17237c478bdstevel@tonic-gate		}
17247c478bdstevel@tonic-gate
17257c478bdstevel@tonic-gate		if (inst_running(rsp)) {
17267c478bdstevel@tonic-gate			(void) printf(gettext("Reason: Restarter %s "
17277c478bdstevel@tonic-gate			    "has not initialized service state.\n"),
17287c478bdstevel@tonic-gate			    svcp->restarter);
17297c478bdstevel@tonic-gate			dc = DC_UNINIT;
17307c478bdstevel@tonic-gate		} else {
17317c478bdstevel@tonic-gate			(void) printf(gettext(
17327c478bdstevel@tonic-gate			    "Reason: Restarter %s is not running.\n"),
17337c478bdstevel@tonic-gate			    svcp->restarter);
17347c478bdstevel@tonic-gate			dc = DC_RSTRDEAD;
17357c478bdstevel@tonic-gate		}
17367c478bdstevel@tonic-gate
17377c478bdstevel@tonic-gate	} else if (strcmp(svcp->state, SCF_STATE_STRING_DISABLED) == 0) {
17387c478bdstevel@tonic-gate		if (!svcp->temporary) {
17397c478bdstevel@tonic-gate			(void) puts(gettext(
17407c478bdstevel@tonic-gate			    "Reason: Disabled by an administrator."));
17417c478bdstevel@tonic-gate			dc = DC_DISABLED;
17427c478bdstevel@tonic-gate		} else {
17437c478bdstevel@tonic-gate			(void) puts(gettext("Reason: "
17447c478bdstevel@tonic-gate			    "Temporarily disabled by an administrator."));
17457c478bdstevel@tonic-gate			dc = DC_TEMPDISABLED;
17467c478bdstevel@tonic-gate		}
17477c478bdstevel@tonic-gate
17487c478bdstevel@tonic-gate	} else if (strcmp(svcp->state, SCF_STATE_STRING_MAINT) == 0) {
17497c478bdstevel@tonic-gate		if (strcmp(svcp->aux_state, "administrative_request") == 0) {
17507c478bdstevel@tonic-gate			(void) puts(gettext("Reason: "
17517c478bdstevel@tonic-gate			    "Maintenance requested by an administrator."));
17527c478bdstevel@tonic-gate			dc = DC_ADMINMAINT;
17537c478bdstevel@tonic-gate		} else if (strcmp(svcp->aux_state, "dependency_cycle") == 0) {
17547c478bdstevel@tonic-gate			(void) puts(gettext(
17557c478bdstevel@tonic-gate			    "Reason: Completes a dependency cycle."));
17567c478bdstevel@tonic-gate			dc = DC_DEPCYCLE;
17577c478bdstevel@tonic-gate		} else if (strcmp(svcp->aux_state, "fault_threshold_reached") ==
17587c478bdstevel@tonic-gate		    0) {
17597c478bdstevel@tonic-gate			print_method_failure(svcp, &dc);
1760eb1a346Truong Nguyen		} else if (strcmp(svcp->aux_state, "service_request") == 0) {
1761eb1a346Truong Nguyen			if (svcp->aux_fmri) {
1762eb1a346Truong Nguyen				(void) printf(gettext("Reason: Maintenance "
1763eb1a346Truong Nguyen				    "requested by \"%s\"\n"), svcp->aux_fmri);
1764eb1a346Truong Nguyen				print_aux_fmri_logs(svcp->aux_fmri);
1765eb1a346Truong Nguyen			} else {
1766eb1a346Truong Nguyen				(void) puts(gettext("Reason: Maintenance "
1767eb1a346Truong Nguyen				    "requested by another service."));
1768eb1a346Truong Nguyen			}
1769eb1a346Truong Nguyen			dc = DC_SVCREQMAINT;
17707c478bdstevel@tonic-gate		} else if (strcmp(svcp->aux_state, "invalid_dependency") == 0) {
17717c478bdstevel@tonic-gate			(void) puts(gettext("Reason: Has invalid dependency."));
17727c478bdstevel@tonic-gate			dc = DC_INVALIDDEP;
17737c478bdstevel@tonic-gate		} else if (strcmp(svcp->aux_state, "invalid_restarter") == 0) {
17747c478bdstevel@tonic-gate			(void) printf(gettext("Reason: Restarter \"%s\" is "
17757c478bdstevel@tonic-gate			    "invalid.\n"), svcp->restarter);
17767c478bdstevel@tonic-gate			dc = DC_RSTRINVALID;
17777c478bdstevel@tonic-gate		} else if (strcmp(svcp->aux_state, "method_failed") == 0) {
17787c478bdstevel@tonic-gate			print_method_failure(svcp, &dc);
17797c478bdstevel@tonic-gate		} else if (strcmp(svcp->aux_state, "restarting_too_quickly") ==
17807c478bdstevel@tonic-gate		    0) {
17817c478bdstevel@tonic-gate			(void) puts(gettext("Reason: Restarting too quickly."));
17827c478bdstevel@tonic-gate			dc = DC_TOOQUICKLY;
17837c478bdstevel@tonic-gate		} else if (strcmp(svcp->aux_state, "none") == 0) {
17847c478bdstevel@tonic-gate			(void) printf(gettext(
17857c478bdstevel@tonic-gate			    "Reason: Restarter %s gave no explanation.\n"),
17867c478bdstevel@tonic-gate			    svcp->restarter);
17877c478bdstevel@tonic-gate			dc = DC_NONE;
17887c478bdstevel@tonic-gate		} else {
17897c478bdstevel@tonic-gate			(void) puts(gettext("Reason: Unknown."));
17907c478bdstevel@tonic-gate			dc = DC_UNKNOWN;
17917c478bdstevel@tonic-gate		}
17927c478bdstevel@tonic-gate
17937c478bdstevel@tonic-gate	} else if (strcmp(svcp->state, SCF_STATE_STRING_OFFLINE) == 0) {
17947c478bdstevel@tonic-gate		if (strcmp(svcp->next_state, SCF_STATE_STRING_ONLINE) == 0) {
17957c478bdstevel@tonic-gate			(void) puts(gettext(
17967c478bdstevel@tonic-gate			    "Reason: Start method is running."));
17977c478bdstevel@tonic-gate			dc = DC_STARTING;
17987c478bdstevel@tonic-gate		} else if (strcmp(svcp->next_state, SCF_STATE_STRING_NONE) ==
17997c478bdstevel@tonic-gate		    0) {
18007c478bdstevel@tonic-gate			print_dependency_reasons(svcp, verbose);
18017c478bdstevel@tonic-gate			/* Function prints diagcodes. */
18027c478bdstevel@tonic-gate			return;
18037c478bdstevel@tonic-gate		} else {
18047c478bdstevel@tonic-gate			(void) printf(gettext(
18057c478bdstevel@tonic-gate			    "Reason: Transitioning to state %s.\n"),
18067c478bdstevel@tonic-gate			    svcp->next_state);
18077c478bdstevel@tonic-gate			dc = DC_TRANSITION;
18087c478bdstevel@tonic-gate		}
18097c478bdstevel@tonic-gate
18107c478bdstevel@tonic-gate	} else if (strcmp(svcp->state, SCF_STATE_STRING_DEGRADED) == 0) {
18117c478bdstevel@tonic-gate		(void) puts(gettext("Reason: Degraded by an administrator."));
18127c478bdstevel@tonic-gate		dc = DC_ADMINDEGR;
18137c478bdstevel@tonic-gate
18147c478bdstevel@tonic-gate	} else {
18157c478bdstevel@tonic-gate		(void) printf(gettext("Reason: Not in valid state (%s).\n"),
18167c478bdstevel@tonic-gate		    svcp->state);
18177c478bdstevel@tonic-gate		dc = DC_INVALIDSTATE;
18187c478bdstevel@tonic-gate	}
18197c478bdstevel@tonic-gate
18207c478bdstevel@tonic-gatediagcode:
18217c478bdstevel@tonic-gate	if (g_msgbase != NULL)
18227c478bdstevel@tonic-gate		(void) printf(gettext("   See: %s%s\n"), g_msgbase, dc);
18237c478bdstevel@tonic-gate}
18247c478bdstevel@tonic-gate
18257c478bdstevel@tonic-gatestatic void
18267c478bdstevel@tonic-gateprint_manpage(int verbose)
18277c478bdstevel@tonic-gate{
18287c478bdstevel@tonic-gate	static char *title = NULL;
18297c478bdstevel@tonic-gate	static char *section = NULL;
18307c478bdstevel@tonic-gate
18317c478bdstevel@tonic-gate	if (title == NULL) {
18327c478bdstevel@tonic-gate		title = safe_malloc(g_value_sz);
18337c478bdstevel@tonic-gate		section = safe_malloc(g_value_sz);
18347c478bdstevel@tonic-gate	}
18357c478bdstevel@tonic-gate
18367c478bdstevel@tonic-gate	if (pg_get_single_val(g_pg, SCF_PROPERTY_TM_TITLE, SCF_TYPE_ASTRING,
18377c478bdstevel@tonic-gate	    (void *)title, g_value_sz, 0) != 0)
18387c478bdstevel@tonic-gate		return;
18397c478bdstevel@tonic-gate
18407c478bdstevel@tonic-gate	if (pg_get_single_val(g_pg, SCF_PROPERTY_TM_SECTION,
18417c478bdstevel@tonic-gate	    SCF_TYPE_ASTRING, (void *)section, g_value_sz, 0) != 0)
18427c478bdstevel@tonic-gate		return;
18437c478bdstevel@tonic-gate
18447c478bdstevel@tonic-gate	if (!verbose) {
18457c478bdstevel@tonic-gate		(void) printf(gettext("   See: %s(%s)\n"), title, section);
18467c478bdstevel@tonic-gate		return;
18477c478bdstevel@tonic-gate	}
18487c478bdstevel@tonic-gate
18497c478bdstevel@tonic-gate	if (pg_get_single_val(g_pg, SCF_PROPERTY_TM_MANPATH, SCF_TYPE_ASTRING,
18507c478bdstevel@tonic-gate	    (void *)g_value, g_value_sz, 0) != 0)
18517c478bdstevel@tonic-gate		return;
18527c478bdstevel@tonic-gate
18537c478bdstevel@tonic-gate	if (strcmp(g_value, ":default") == 0) {
18547c478bdstevel@tonic-gate		assert(sizeof (DEFAULT_MAN_PATH) < g_value_sz);
18557c478bdstevel@tonic-gate		(void) strcpy(g_value, DEFAULT_MAN_PATH);
18567c478bdstevel@tonic-gate	}
18577c478bdstevel@tonic-gate
18587c478bdstevel@tonic-gate	(void) printf(gettext("   See: man -M %s -s %s %s\n"), g_value,
18597c478bdstevel@tonic-gate	    section, title);
18607c478bdstevel@tonic-gate}
18617c478bdstevel@tonic-gate
18627c478bdstevel@tonic-gatestatic void
18637c478bdstevel@tonic-gateprint_doclink()
18647c478bdstevel@tonic-gate{
18657c478bdstevel@tonic-gate	static char *uri = NULL;
18667c478bdstevel@tonic-gate
18677c478bdstevel@tonic-gate	if (uri == NULL) {
18687c478bdstevel@tonic-gate		uri = safe_malloc(g_value_sz);
18697c478bdstevel@tonic-gate	}
18707c478bdstevel@tonic-gate
18717c478bdstevel@tonic-gate	if (pg_get_single_val(g_pg, SCF_PROPERTY_TM_URI, SCF_TYPE_ASTRING,
18727c478bdstevel@tonic-gate	    (void *)uri, g_value_sz, 0) != 0)
18737c478bdstevel@tonic-gate		return;
18747c478bdstevel@tonic-gate
18757c478bdstevel@tonic-gate	(void) printf(gettext("   See: %s\n"), uri);
18767c478bdstevel@tonic-gate}
18777c478bdstevel@tonic-gate
18787c478bdstevel@tonic-gate
18797c478bdstevel@tonic-gate/*
18807c478bdstevel@tonic-gate * Returns
18817c478bdstevel@tonic-gate *   0 - success
18827c478bdstevel@tonic-gate *   1 - inst was deleted
18837c478bdstevel@tonic-gate */
18847c478bdstevel@tonic-gatestatic int
18857c478bdstevel@tonic-gateprint_docs(scf_instance_t *inst, int verbose)
18867c478bdstevel@tonic-gate{
18877c478bdstevel@tonic-gate	scf_snapshot_t *snap;
18887c478bdstevel@tonic-gate	int r;
18897c478bdstevel@tonic-gate
18907c478bdstevel@tonic-gate	if (scf_instance_get_snapshot(inst, "running", g_snap) != 0) {
18917c478bdstevel@tonic-gate		switch (scf_error()) {
18927c478bdstevel@tonic-gate		case SCF_ERROR_NOT_FOUND:
18937c478bdstevel@tonic-gate			break;
18947c478bdstevel@tonic-gate
18957c478bdstevel@tonic-gate		case SCF_ERROR_DELETED:
18967c478bdstevel@tonic-gate			return (1);
18977c478bdstevel@tonic-gate
18987c478bdstevel@tonic-gate		default:
18997c478bdstevel@tonic-gate			scfdie();
19007c478bdstevel@tonic-gate		}
19017c478bdstevel@tonic-gate
19027c478bdstevel@tonic-gate		snap = NULL;
19037c478bdstevel@tonic-gate	} else {
19047c478bdstevel@tonic-gate		snap = g_snap;
19057c478bdstevel@tonic-gate	}
19067c478bdstevel@tonic-gate
19077c478bdstevel@tonic-gate	if (scf_iter_instance_pgs_typed_composed(g_iter, inst, snap,
19087c478bdstevel@tonic-gate	    SCF_GROUP_TEMPLATE) != 0) {
19097c478bdstevel@tonic-gate		if (scf_error() != SCF_ERROR_DELETED)
19107c478bdstevel@tonic-gate			scfdie();
19117c478bdstevel@tonic-gate
19127c478bdstevel@tonic-gate		return (1);
19137c478bdstevel@tonic-gate	}
19147c478bdstevel@tonic-gate
19157c478bdstevel@tonic-gate	for (;;) {
19167c478bdstevel@tonic-gate		r = scf_iter_next_pg(g_iter, g_pg);
19177c478bdstevel@tonic-gate		if (r == 0)
19187c478bdstevel@tonic-gate			break;
19197c478bdstevel@tonic-gate		if (r != 1) {
19207c478bdstevel@tonic-gate			if (scf_error() != SCF_ERROR_DELETED)
19217c478bdstevel@tonic-gate				scfdie();
19227c478bdstevel@tonic-gate
19237c478bdstevel@tonic-gate			return (1);
19247c478bdstevel@tonic-gate		}
19257c478bdstevel@tonic-gate
19267c478bdstevel@tonic-gate		if (scf_pg_get_name(g_pg, g_fmri, g_fmri_sz) < 0) {
19277c478bdstevel@tonic-gate			if (scf_error() != SCF_ERROR_DELETED)
19287c478bdstevel@tonic-gate				scfdie();
19297c478bdstevel@tonic-gate
19307c478bdstevel@tonic-gate			continue;
19317c478bdstevel@tonic-gate		}
19327c478bdstevel@tonic-gate
19337c478bdstevel@tonic-gate		if (strncmp(g_fmri, SCF_PG_TM_MAN_PREFIX,
19347c478bdstevel@tonic-gate		    strlen(SCF_PG_TM_MAN_PREFIX)) == 0) {
19357c478bdstevel@tonic-gate			print_manpage(verbose);
19367c478bdstevel@tonic-gate			continue;
19377c478bdstevel@tonic-gate		}
19387c478bdstevel@tonic-gate
19397c478bdstevel@tonic-gate		if (strncmp(g_fmri, SCF_PG_TM_DOC_PREFIX,
19407c478bdstevel@tonic-gate		    strlen(SCF_PG_TM_DOC_PREFIX)) == 0) {
19417c478bdstevel@tonic-gate			print_doclink();
19427c478bdstevel@tonic-gate			continue;
19437c478bdstevel@tonic-gate		}
19447c478bdstevel@tonic-gate	}
19457c478bdstevel@tonic-gate	return (0);
19467c478bdstevel@tonic-gate}
19477c478bdstevel@tonic-gate
19487c478bdstevel@tonic-gatestatic int first = 1;
19497c478bdstevel@tonic-gate
19507c478bdstevel@tonic-gate/*
19517c478bdstevel@tonic-gate * Explain why the given service is in the state it's in.
19527c478bdstevel@tonic-gate */
19537c478bdstevel@tonic-gatestatic void
19547c478bdstevel@tonic-gateprint_service(inst_t *svcp, int verbose)
19557c478bdstevel@tonic-gate{
19567c478bdstevel@tonic-gate	struct svcptr *spp;
19577c478bdstevel@tonic-gate	time_t stime;
19587c478bdstevel@tonic-gate	char *timebuf;
19597c478bdstevel@tonic-gate	size_t tbsz;
19607c478bdstevel@tonic-gate	struct tm *tmp;
19617c478bdstevel@tonic-gate	int deleted = 0;
19627c478bdstevel@tonic-gate
19637c478bdstevel@tonic-gate	if (first)
19647c478bdstevel@tonic-gate		first = 0;
19657c478bdstevel@tonic-gate	else
19667c478bdstevel@tonic-gate		(void) putchar('\n');
19677c478bdstevel@tonic-gate
19687c478bdstevel@tonic-gate	(void) printf(gettext("svc:/%s:%s"), svcp->svcname, svcp->instname);
19697c478bdstevel@tonic-gate
19707c478bdstevel@tonic-gate	if (scf_scope_get_service(g_local_scope, svcp->svcname, g_svc) != 0) {
19717c478bdstevel@tonic-gate		if (scf_error() != SCF_ERROR_NOT_FOUND)
19727c478bdstevel@tonic-gate			scfdie();
19737c478bdstevel@tonic-gate		deleted = 1;
19747c478bdstevel@tonic-gate	} else if (scf_service_get_instance(g_svc, svcp->instname, g_inst) !=
19757c478bdstevel@tonic-gate	    0) {
19767c478bdstevel@tonic-gate		if (scf_error() != SCF_ERROR_NOT_FOUND)
19777c478bdstevel@tonic-gate			scfdie();
19787c478bdstevel@tonic-gate		deleted = 1;
19797c478bdstevel@tonic-gate	}
19807c478bdstevel@tonic-gate
19817c478bdstevel@tonic-gate	if (!deleted) {
19827c478bdstevel@tonic-gate		if (inst_get_single_val(g_inst, SCF_PG_TM_COMMON_NAME, locale,
19837c478bdstevel@tonic-gate		    SCF_TYPE_USTRING, g_value, g_value_sz, 0, 0, 1) == 0)
19847c478bdstevel@tonic-gate			/* EMPTY */;
19857c478bdstevel@tonic-gate		else if (inst_get_single_val(g_inst, SCF_PG_TM_COMMON_NAME, "C",
19867c478bdstevel@tonic-gate		    SCF_TYPE_USTRING, g_value, g_value_sz, 0, 0, 1) != 0)
19877c478bdstevel@tonic-gate			(void) strcpy(g_value, "?");
19887c478bdstevel@tonic-gate
19897c478bdstevel@tonic-gate		(void) printf(gettext(" (%s)\n"), g_value);
19907c478bdstevel@tonic-gate	} else {
19917c478bdstevel@tonic-gate		(void) putchar('\n');
19927c478bdstevel@tonic-gate	}
19937c478bdstevel@tonic-gate
1994048b027Bryan Cantrill	if (g_zonename != NULL)
1995048b027Bryan Cantrill		(void) printf(gettext("  Zone: %s\n"), g_zonename);
1996048b027Bryan Cantrill
19977c478bdstevel@tonic-gate	stime = svcp->stime.tv_sec;
19987c478bdstevel@tonic-gate	tmp = localtime(&stime);
19997c478bdstevel@tonic-gate
20007c478bdstevel@tonic-gate	for (tbsz = 50; ; tbsz *= 2) {
20017c478bdstevel@tonic-gate		timebuf = safe_malloc(tbsz);
20027c478bdstevel@tonic-gate		if (strftime(timebuf, tbsz, NULL, tmp) != 0)
20033eae19dwesolows			break;
20047c478bdstevel@tonic-gate		free(timebuf);
20057c478bdstevel@tonic-gate	}
20067c478bdstevel@tonic-gate
20077c478bdstevel@tonic-gate	(void) printf(gettext(" State: %s since %s\n"), svcp->state, timebuf);
20087c478bdstevel@tonic-gate
20097c478bdstevel@tonic-gate	free(timebuf);
20107c478bdstevel@tonic-gate
20117c478bdstevel@tonic-gate	/* Reasons */
20127c478bdstevel@tonic-gate	print_reasons(svcp, verbose);
20137c478bdstevel@tonic-gate
20147c478bdstevel@tonic-gate	if (!deleted)
20157c478bdstevel@tonic-gate		deleted = print_docs(g_inst, verbose);
20167c478bdstevel@tonic-gate	if (!deleted)
20177c478bdstevel@tonic-gate		print_logs(g_inst);
20187c478bdstevel@tonic-gate
20197c478bdstevel@tonic-gate	(void) determine_impact(svcp);
20207c478bdstevel@tonic-gate
20217c478bdstevel@tonic-gate	switch (uu_list_numnodes(svcp->impact)) {
20227c478bdstevel@tonic-gate	case 0:
20237c478bdstevel@tonic-gate		if (inst_running(svcp))
20247c478bdstevel@tonic-gate			(void) puts(gettext("Impact: None."));
20257c478bdstevel@tonic-gate		else
20267c478bdstevel@tonic-gate			(void) puts(gettext(
20277c478bdstevel@tonic-gate			    "Impact: This service is not running."));
20287c478bdstevel@tonic-gate		break;
20297c478bdstevel@tonic-gate
20307c478bdstevel@tonic-gate	case 1:
20317c478bdstevel@tonic-gate		if (!verbose)
20327c478bdstevel@tonic-gate			(void) puts(gettext("Impact: 1 dependent service "
20337c478bdstevel@tonic-gate			    "is not running.  (Use -v for list.)"));
20347c478bdstevel@tonic-gate		else
20357c478bdstevel@tonic-gate			(void) puts(gettext(
20367c478bdstevel@tonic-gate			    "Impact: 1 dependent service is not running:"));
20377c478bdstevel@tonic-gate		break;
20387c478bdstevel@tonic-gate
20397c478bdstevel@tonic-gate	default:
20407c478bdstevel@tonic-gate		if (!verbose)
20417c478bdstevel@tonic-gate			(void) printf(gettext("Impact: %d dependent services "
20427c478bdstevel@tonic-gate			    "are not running.  (Use -v for list.)\n"),
20437c478bdstevel@tonic-gate			    uu_list_numnodes(svcp->impact));
20447c478bdstevel@tonic-gate		else
20457c478bdstevel@tonic-gate			(void) printf(gettext(
20467c478bdstevel@tonic-gate			    "Impact: %d dependent services are not running:\n"),
20477c478bdstevel@tonic-gate			    uu_list_numnodes(svcp->impact));
20487c478bdstevel@tonic-gate	}
20497c478bdstevel@tonic-gate
20507c478bdstevel@tonic-gate	if (verbose) {
20517c478bdstevel@tonic-gate		for (spp = uu_list_first(svcp->impact);
20527c478bdstevel@tonic-gate		    spp != NULL;
20537c478bdstevel@tonic-gate		    spp = uu_list_next(svcp->impact, spp))
20547c478bdstevel@tonic-gate			(void) printf(gettext("        svc:/%s:%s\n"),
20557c478bdstevel@tonic-gate			    spp->svcp->svcname, spp->svcp->instname);
20567c478bdstevel@tonic-gate	}
20577c478bdstevel@tonic-gate}
20587c478bdstevel@tonic-gate
20597c478bdstevel@tonic-gate/*
20607c478bdstevel@tonic-gate * Top level routine.
20617c478bdstevel@tonic-gate */
20627c478bdstevel@tonic-gate
20637c478bdstevel@tonic-gatestatic int
20647c478bdstevel@tonic-gateimpact_compar(const void *a, const void *b)
20657c478bdstevel@tonic-gate{
20667c478bdstevel@tonic-gate	int n, m;
20677c478bdstevel@tonic-gate
20687c478bdstevel@tonic-gate	n = uu_list_numnodes((*(inst_t **)a)->impact);
20697c478bdstevel@tonic-gate	m = uu_list_numnodes((*(inst_t **)b)->impact);
20707c478bdstevel@tonic-gate
20717c478bdstevel@tonic-gate	return (m - n);
20727c478bdstevel@tonic-gate}
20737c478bdstevel@tonic-gate
20747c478bdstevel@tonic-gatestatic int
20757c478bdstevel@tonic-gateprint_service_cb(void *verbose, scf_walkinfo_t *wip)
20767c478bdstevel@tonic-gate{
20777c478bdstevel@tonic-gate	int r;
20787c478bdstevel@tonic-gate	inst_t *ip;
20797c478bdstevel@tonic-gate
20807c478bdstevel@tonic-gate	assert(wip->pg == NULL);
20817c478bdstevel@tonic-gate
20827c478bdstevel@tonic-gate	r = get_fmri(wip->fmri, NULL, &ip);
20837c478bdstevel@tonic-gate	assert(r != EINVAL);
20847c478bdstevel@tonic-gate	if (r == ENOENT)
20857c478bdstevel@tonic-gate		return (0);
20867c478bdstevel@tonic-gate
20877c478bdstevel@tonic-gate	assert(r == 0);
20887c478bdstevel@tonic-gate	assert(ip != NULL);
20897c478bdstevel@tonic-gate
20907c478bdstevel@tonic-gate	print_service(ip, (int)verbose);
20917c478bdstevel@tonic-gate
20927c478bdstevel@tonic-gate	return (0);
20937c478bdstevel@tonic-gate}
20947c478bdstevel@tonic-gate
20957c478bdstevel@tonic-gatevoid
20967c478bdstevel@tonic-gateexplain(int verbose, int argc, char **argv)
20977c478bdstevel@tonic-gate{
2098048b027Bryan Cantrill	/*
2099048b027Bryan Cantrill	 * Initialize globals.  If we have been called before (e.g., for a
2100048b027Bryan Cantrill	 * different zone), this will clobber the previous globals -- keeping
2101048b027Bryan Cantrill	 * with the proud svcs(1) tradition of not bothering to ever clean
2102048b027Bryan Cantrill	 * anything up.
2103048b027Bryan Cantrill	 */
21047c478bdstevel@tonic-gate	x_init();
21057c478bdstevel@tonic-gate
21067c478bdstevel@tonic-gate	/* Walk the graph and populate services with inst_t's */
21077c478bdstevel@tonic-gate	load_services();
21087c478bdstevel@tonic-gate
21097c478bdstevel@tonic-gate	/* Populate causes for services. */
21107c478bdstevel@tonic-gate	determine_all_causes();
21117c478bdstevel@tonic-gate
21127c478bdstevel@tonic-gate	if (argc > 0) {
21137c478bdstevel@tonic-gate		scf_error_t err;
21147c478bdstevel@tonic-gate
21157c478bdstevel@tonic-gate		check_msgbase();
21167c478bdstevel@tonic-gate
21177c478bdstevel@tonic-gate		/* Call print_service() for each operand. */
21187c478bdstevel@tonic-gate
21197c478bdstevel@tonic-gate		err = scf_walk_fmri(h, argc, argv, SCF_WALK_MULTIPLE,
21207c478bdstevel@tonic-gate		    print_service_cb, (void *)verbose, &exit_status, uu_warn);
21217c478bdstevel@tonic-gate		if (err != 0) {
21227c478bdstevel@tonic-gate			uu_warn(gettext(
21237c478bdstevel@tonic-gate			    "failed to iterate over instances: %s\n"),
21247c478bdstevel@tonic-gate			    scf_strerror(err));
21257c478bdstevel@tonic-gate			exit_status = UU_EXIT_FATAL;
21267c478bdstevel@tonic-gate		}
21277c478bdstevel@tonic-gate	} else {
21287c478bdstevel@tonic-gate		struct svcptr *spp;
21297c478bdstevel@tonic-gate		int n, i;
21307c478bdstevel@tonic-gate		inst_t **ary;
21317c478bdstevel@tonic-gate
21327c478bdstevel@tonic-gate		/* Sort g_causes. */
21337c478bdstevel@tonic-gate
21347c478bdstevel@tonic-gate		n = uu_list_numnodes(g_causes);
21357c478bdstevel@tonic-gate		if (n == 0)
21367c478bdstevel@tonic-gate			return;
21377c478bdstevel@tonic-gate
21387c478bdstevel@tonic-gate		check_msgbase();
21397c478bdstevel@tonic-gate
21407c478bdstevel@tonic-gate		ary = calloc(n, sizeof (*ary));
21417c478bdstevel@tonic-gate		if (ary == NULL)
21427c478bdstevel@tonic-gate			uu_die(emsg_nomem);
21437c478bdstevel@tonic-gate
21447c478bdstevel@tonic-gate		i = 0;
21457c478bdstevel@tonic-gate		for (spp = uu_list_first(g_causes);
21467c478bdstevel@tonic-gate		    spp != NULL;
21477c478bdstevel@tonic-gate		    spp = uu_list_next(g_causes, spp)) {
21487c478bdstevel@tonic-gate			(void) determine_impact(spp->svcp);
21497c478bdstevel@tonic-gate			ary[i++] = spp->svcp;
21507c478bdstevel@tonic-gate		}
21517c478bdstevel@tonic-gate
21527c478bdstevel@tonic-gate		qsort(ary, n, sizeof (*ary), impact_compar);
21537c478bdstevel@tonic-gate
21547c478bdstevel@tonic-gate		/* Call print_service() for each service. */
21557c478bdstevel@tonic-gate
21567c478bdstevel@tonic-gate		for (i = 0; i < n; ++i)
21577c478bdstevel@tonic-gate			print_service(ary[i], verbose);
21587c478bdstevel@tonic-gate	}
21597c478bdstevel@tonic-gate}
2160