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