xref: /illumos-gate/usr/src/cmd/svc/svcs/explain.c (revision 7c478bd9)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate /*
30*7c478bd9Sstevel@tonic-gate  * Service state explanation.  For select services, display a description, the
31*7c478bd9Sstevel@tonic-gate  * state, and possibly why the service is in that state, what's causing it to
32*7c478bd9Sstevel@tonic-gate  * be in that state, and what other services it is keeping offline (impact).
33*7c478bd9Sstevel@tonic-gate  *
34*7c478bd9Sstevel@tonic-gate  * Explaining states other than offline is easy.  For maintenance and
35*7c478bd9Sstevel@tonic-gate  * degraded, we just use the auxiliary state.  For offline, we must determine
36*7c478bd9Sstevel@tonic-gate  * which dependencies are unsatisfied and recurse.  If a causal service is not
37*7c478bd9Sstevel@tonic-gate  * offline, then a svcptr to it is added to the offline service's causes list.
38*7c478bd9Sstevel@tonic-gate  * If a causal service is offline, then we recurse to determine its causes and
39*7c478bd9Sstevel@tonic-gate  * merge them into the causes list of the service in question (see
40*7c478bd9Sstevel@tonic-gate  * add_causes()).  Note that by adding a self-pointing svcptr to the causes
41*7c478bd9Sstevel@tonic-gate  * lists of services which are not offline or are offline for unknown reasons,
42*7c478bd9Sstevel@tonic-gate  * we can always merge the unsatisfied dependency's causes into the
43*7c478bd9Sstevel@tonic-gate  * dependent's list.
44*7c478bd9Sstevel@tonic-gate  *
45*7c478bd9Sstevel@tonic-gate  * Computing an impact list is more involved because the dependencies in the
46*7c478bd9Sstevel@tonic-gate  * repository are unidirectional; it requires determining the causes of all
47*7c478bd9Sstevel@tonic-gate  * offline services.  For each unsatisfied dependency of an offline service,
48*7c478bd9Sstevel@tonic-gate  * a svcptr to the dependent is added to the dependency's impact_dependents
49*7c478bd9Sstevel@tonic-gate  * list (see add_causes()).  determine_impact() uses the lists to build an
50*7c478bd9Sstevel@tonic-gate  * impact list.  The direct dependency is used so that a path from the
51*7c478bd9Sstevel@tonic-gate  * affected service to the causal service can be constructed (see
52*7c478bd9Sstevel@tonic-gate  * print_dependency_reasons()).
53*7c478bd9Sstevel@tonic-gate  *
54*7c478bd9Sstevel@tonic-gate  * Because we always need at least impact counts, we always run
55*7c478bd9Sstevel@tonic-gate  * determine_causes() on all services.
56*7c478bd9Sstevel@tonic-gate  *
57*7c478bd9Sstevel@tonic-gate  * If no arguments are given, we must select the services which are causing
58*7c478bd9Sstevel@tonic-gate  * other services to be offline.  We do so by adding services which are not
59*7c478bd9Sstevel@tonic-gate  * running for any reason other than another service to the g_causes list in
60*7c478bd9Sstevel@tonic-gate  * determine_causes().
61*7c478bd9Sstevel@tonic-gate  *
62*7c478bd9Sstevel@tonic-gate  * Since all services must be examined, and their states may be consulted
63*7c478bd9Sstevel@tonic-gate  * a lot, it is important that we only read volatile data (like states) from
64*7c478bd9Sstevel@tonic-gate  * the repository once.  add_instance() reads data for an instance from the
65*7c478bd9Sstevel@tonic-gate  * repository into an inst_t and puts it into the "services" cache, which is
66*7c478bd9Sstevel@tonic-gate  * organized as a hash table of svc_t's, each of which has a list of inst_t's.
67*7c478bd9Sstevel@tonic-gate  */
68*7c478bd9Sstevel@tonic-gate 
69*7c478bd9Sstevel@tonic-gate #include "svcs.h"
70*7c478bd9Sstevel@tonic-gate 
71*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
72*7c478bd9Sstevel@tonic-gate #include <sys/wait.h>
73*7c478bd9Sstevel@tonic-gate 
74*7c478bd9Sstevel@tonic-gate #include <assert.h>
75*7c478bd9Sstevel@tonic-gate #include <errno.h>
76*7c478bd9Sstevel@tonic-gate #include <libintl.h>
77*7c478bd9Sstevel@tonic-gate #include <libuutil.h>
78*7c478bd9Sstevel@tonic-gate #include <libscf.h>
79*7c478bd9Sstevel@tonic-gate #include <libscf_priv.h>
80*7c478bd9Sstevel@tonic-gate #include <string.h>
81*7c478bd9Sstevel@tonic-gate #include <stdio.h>
82*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
83*7c478bd9Sstevel@tonic-gate #include <time.h>
84*7c478bd9Sstevel@tonic-gate 
85*7c478bd9Sstevel@tonic-gate 
86*7c478bd9Sstevel@tonic-gate #define	DC_DISABLED	"SMF-8000-05"
87*7c478bd9Sstevel@tonic-gate #define	DC_TEMPDISABLED	"SMF-8000-1S"
88*7c478bd9Sstevel@tonic-gate #define	DC_RSTRINVALID	"SMF-8000-2A"
89*7c478bd9Sstevel@tonic-gate #define	DC_RSTRABSENT	"SMF-8000-3P"
90*7c478bd9Sstevel@tonic-gate #define	DC_UNINIT	"SMF-8000-4D"
91*7c478bd9Sstevel@tonic-gate #define	DC_RSTRDEAD	"SMF-8000-5H"
92*7c478bd9Sstevel@tonic-gate #define	DC_ADMINMAINT	"SMF-8000-63"
93*7c478bd9Sstevel@tonic-gate #define	DC_REPTFAIL	"SMF-8000-7Y"
94*7c478bd9Sstevel@tonic-gate #define	DC_METHFAIL	"SMF-8000-8Q"
95*7c478bd9Sstevel@tonic-gate #define	DC_NONE		"SMF-8000-9C"
96*7c478bd9Sstevel@tonic-gate #define	DC_UNKNOWN	"SMF-8000-AR"
97*7c478bd9Sstevel@tonic-gate #define	DC_STARTING	"SMF-8000-C4"
98*7c478bd9Sstevel@tonic-gate #define	DC_ADMINDEGR	"SMF-8000-DX"
99*7c478bd9Sstevel@tonic-gate #define	DC_DEPABSENT	"SMF-8000-E2"
100*7c478bd9Sstevel@tonic-gate #define	DC_DEPRUNNING	"SMF-8000-FJ"
101*7c478bd9Sstevel@tonic-gate #define	DC_DEPOTHER	"SMF-8000-GE"
102*7c478bd9Sstevel@tonic-gate #define	DC_DEPCYCLE	"SMF-8000-HP"
103*7c478bd9Sstevel@tonic-gate #define	DC_INVALIDDEP	"SMF-8000-JA"
104*7c478bd9Sstevel@tonic-gate #define	DC_STARTFAIL	"SMF-8000-KS"
105*7c478bd9Sstevel@tonic-gate #define	DC_TOOQUICKLY	"SMF-8000-L5"
106*7c478bd9Sstevel@tonic-gate #define	DC_INVALIDSTATE	"SMF-8000-N3"
107*7c478bd9Sstevel@tonic-gate #define	DC_TRANSITION	"SMF-8000-PH"
108*7c478bd9Sstevel@tonic-gate 
109*7c478bd9Sstevel@tonic-gate #define	DEFAULT_MAN_PATH	"/usr/share/man"
110*7c478bd9Sstevel@tonic-gate 
111*7c478bd9Sstevel@tonic-gate 
112*7c478bd9Sstevel@tonic-gate #define	uu_list_append(lst, e)	uu_list_insert_before(lst, NULL, e)
113*7c478bd9Sstevel@tonic-gate 
114*7c478bd9Sstevel@tonic-gate #ifdef NDEBUG
115*7c478bd9Sstevel@tonic-gate #define	bad_error(func, err)	abort()
116*7c478bd9Sstevel@tonic-gate #else
117*7c478bd9Sstevel@tonic-gate #define	bad_error(func, err)						\
118*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "%s:%d: %s() failed with unknown error %d.\n", \
119*7c478bd9Sstevel@tonic-gate 	    __FILE__, __LINE__, func, err);				\
120*7c478bd9Sstevel@tonic-gate 	abort();
121*7c478bd9Sstevel@tonic-gate #endif
122*7c478bd9Sstevel@tonic-gate 
123*7c478bd9Sstevel@tonic-gate 
124*7c478bd9Sstevel@tonic-gate typedef struct {
125*7c478bd9Sstevel@tonic-gate 	const char *svcname;
126*7c478bd9Sstevel@tonic-gate 	const char *instname;
127*7c478bd9Sstevel@tonic-gate 
128*7c478bd9Sstevel@tonic-gate 	/* restarter pg properties */
129*7c478bd9Sstevel@tonic-gate 	char state[MAX_SCF_STATE_STRING_SZ];
130*7c478bd9Sstevel@tonic-gate 	char next_state[MAX_SCF_STATE_STRING_SZ];
131*7c478bd9Sstevel@tonic-gate 	struct timeval stime;
132*7c478bd9Sstevel@tonic-gate 	const char *aux_state;
133*7c478bd9Sstevel@tonic-gate 	int64_t start_method_waitstatus;
134*7c478bd9Sstevel@tonic-gate 
135*7c478bd9Sstevel@tonic-gate 	int enabled;
136*7c478bd9Sstevel@tonic-gate 	int temporary;
137*7c478bd9Sstevel@tonic-gate 	const char *restarter;
138*7c478bd9Sstevel@tonic-gate 	uu_list_t *dependencies;	/* list of dependency_group's */
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate 	int active;			/* In use?  (cycle detection) */
141*7c478bd9Sstevel@tonic-gate 	int restarter_bad;
142*7c478bd9Sstevel@tonic-gate 	const char *summary;
143*7c478bd9Sstevel@tonic-gate 	uu_list_t *baddeps;		/* list of dependency's */
144*7c478bd9Sstevel@tonic-gate 	uu_list_t *causes;		/* list of svcptrs */
145*7c478bd9Sstevel@tonic-gate 	uu_list_t *impact_dependents;	/* list of svcptrs */
146*7c478bd9Sstevel@tonic-gate 	uu_list_t *impact;		/* list of svcptrs */
147*7c478bd9Sstevel@tonic-gate 
148*7c478bd9Sstevel@tonic-gate 	uu_list_node_t node;
149*7c478bd9Sstevel@tonic-gate } inst_t;
150*7c478bd9Sstevel@tonic-gate 
151*7c478bd9Sstevel@tonic-gate typedef struct service {
152*7c478bd9Sstevel@tonic-gate 	const char *svcname;
153*7c478bd9Sstevel@tonic-gate 	uu_list_t *instances;
154*7c478bd9Sstevel@tonic-gate 	struct service *next;
155*7c478bd9Sstevel@tonic-gate } svc_t;
156*7c478bd9Sstevel@tonic-gate 
157*7c478bd9Sstevel@tonic-gate struct svcptr {
158*7c478bd9Sstevel@tonic-gate 	inst_t *svcp;
159*7c478bd9Sstevel@tonic-gate 	inst_t *next_hop;
160*7c478bd9Sstevel@tonic-gate 	uu_list_node_t node;
161*7c478bd9Sstevel@tonic-gate };
162*7c478bd9Sstevel@tonic-gate 
163*7c478bd9Sstevel@tonic-gate struct dependency_group {
164*7c478bd9Sstevel@tonic-gate 	enum { DGG_REQALL, DGG_REQANY, DGG_OPTALL, DGG_EXCALL } grouping;
165*7c478bd9Sstevel@tonic-gate 	const char *type;
166*7c478bd9Sstevel@tonic-gate 	uu_list_t *entities;		/* List of struct dependency's */
167*7c478bd9Sstevel@tonic-gate 	uu_list_node_t node;
168*7c478bd9Sstevel@tonic-gate };
169*7c478bd9Sstevel@tonic-gate 
170*7c478bd9Sstevel@tonic-gate struct dependency {
171*7c478bd9Sstevel@tonic-gate 	const char *fmri;
172*7c478bd9Sstevel@tonic-gate 	uu_list_node_t node;
173*7c478bd9Sstevel@tonic-gate };
174*7c478bd9Sstevel@tonic-gate 
175*7c478bd9Sstevel@tonic-gate /* Hash table of service names -> svc_t's */
176*7c478bd9Sstevel@tonic-gate #define	SVC_HASH_NBUCKETS	256
177*7c478bd9Sstevel@tonic-gate #define	SVC_HASH_MASK		(SVC_HASH_NBUCKETS - 1)
178*7c478bd9Sstevel@tonic-gate 
179*7c478bd9Sstevel@tonic-gate static svc_t **services;
180*7c478bd9Sstevel@tonic-gate 
181*7c478bd9Sstevel@tonic-gate static uu_list_pool_t *insts, *svcptrs, *depgroups, *deps;
182*7c478bd9Sstevel@tonic-gate static uu_list_t *g_causes;		/* list of svcptrs */
183*7c478bd9Sstevel@tonic-gate 
184*7c478bd9Sstevel@tonic-gate static scf_scope_t *g_local_scope;
185*7c478bd9Sstevel@tonic-gate static scf_service_t *g_svc;
186*7c478bd9Sstevel@tonic-gate static scf_instance_t *g_inst;
187*7c478bd9Sstevel@tonic-gate static scf_snapshot_t *g_snap;
188*7c478bd9Sstevel@tonic-gate static scf_propertygroup_t *g_pg;
189*7c478bd9Sstevel@tonic-gate static scf_property_t *g_prop;
190*7c478bd9Sstevel@tonic-gate static scf_value_t *g_val;
191*7c478bd9Sstevel@tonic-gate static scf_iter_t *g_iter, *g_viter;
192*7c478bd9Sstevel@tonic-gate static char *g_fmri, *g_value;
193*7c478bd9Sstevel@tonic-gate static size_t g_fmri_sz, g_value_sz;
194*7c478bd9Sstevel@tonic-gate static const char *g_msgbase = "http://sun.com/msg/";
195*7c478bd9Sstevel@tonic-gate 
196*7c478bd9Sstevel@tonic-gate static char *emsg_nomem;
197*7c478bd9Sstevel@tonic-gate static char *emsg_invalid_dep;
198*7c478bd9Sstevel@tonic-gate 
199*7c478bd9Sstevel@tonic-gate extern scf_handle_t *h;
200*7c478bd9Sstevel@tonic-gate 
201*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
202*7c478bd9Sstevel@tonic-gate static int
203*7c478bd9Sstevel@tonic-gate svcptr_compare(struct svcptr *a, struct svcptr *b, void *data)
204*7c478bd9Sstevel@tonic-gate {
205*7c478bd9Sstevel@tonic-gate 	return (b->svcp - a->svcp);
206*7c478bd9Sstevel@tonic-gate }
207*7c478bd9Sstevel@tonic-gate 
208*7c478bd9Sstevel@tonic-gate static uint32_t
209*7c478bd9Sstevel@tonic-gate hash_name(const char *name)
210*7c478bd9Sstevel@tonic-gate {
211*7c478bd9Sstevel@tonic-gate 	uint32_t h = 0, g;
212*7c478bd9Sstevel@tonic-gate 	const char *p;
213*7c478bd9Sstevel@tonic-gate 
214*7c478bd9Sstevel@tonic-gate 	for (p = name; *p != '\0'; ++p) {
215*7c478bd9Sstevel@tonic-gate 		h = (h << 4) + *p;
216*7c478bd9Sstevel@tonic-gate 		if ((g = (h & 0xf0000000)) != 0) {
217*7c478bd9Sstevel@tonic-gate 			h ^= (g >> 24);
218*7c478bd9Sstevel@tonic-gate 			h ^= g;
219*7c478bd9Sstevel@tonic-gate 		}
220*7c478bd9Sstevel@tonic-gate 	}
221*7c478bd9Sstevel@tonic-gate 
222*7c478bd9Sstevel@tonic-gate 	return (h);
223*7c478bd9Sstevel@tonic-gate }
224*7c478bd9Sstevel@tonic-gate 
225*7c478bd9Sstevel@tonic-gate 
226*7c478bd9Sstevel@tonic-gate static void
227*7c478bd9Sstevel@tonic-gate x_init(void)
228*7c478bd9Sstevel@tonic-gate {
229*7c478bd9Sstevel@tonic-gate 	emsg_nomem = gettext("Out of memory.\n");
230*7c478bd9Sstevel@tonic-gate 	emsg_invalid_dep =
231*7c478bd9Sstevel@tonic-gate 	    gettext("svc:/%s:%s has invalid dependency \"%s\".\n");
232*7c478bd9Sstevel@tonic-gate 
233*7c478bd9Sstevel@tonic-gate 	services = calloc(SVC_HASH_NBUCKETS, sizeof (*services));
234*7c478bd9Sstevel@tonic-gate 	if (services == NULL)
235*7c478bd9Sstevel@tonic-gate 		uu_die(emsg_nomem);
236*7c478bd9Sstevel@tonic-gate 
237*7c478bd9Sstevel@tonic-gate 	insts = uu_list_pool_create("insts", sizeof (inst_t),
238*7c478bd9Sstevel@tonic-gate 	    offsetof(inst_t, node), NULL, UU_LIST_POOL_DEBUG);
239*7c478bd9Sstevel@tonic-gate 	svcptrs = uu_list_pool_create("svcptrs", sizeof (struct svcptr),
240*7c478bd9Sstevel@tonic-gate 	    offsetof(struct svcptr, node), (uu_compare_fn_t *)svcptr_compare,
241*7c478bd9Sstevel@tonic-gate 	    UU_LIST_POOL_DEBUG);
242*7c478bd9Sstevel@tonic-gate 	depgroups = uu_list_pool_create("depgroups",
243*7c478bd9Sstevel@tonic-gate 	    sizeof (struct dependency_group),
244*7c478bd9Sstevel@tonic-gate 	    offsetof(struct dependency_group, node), NULL, UU_LIST_POOL_DEBUG);
245*7c478bd9Sstevel@tonic-gate 	deps = uu_list_pool_create("deps", sizeof (struct dependency),
246*7c478bd9Sstevel@tonic-gate 	    offsetof(struct dependency, node), NULL, UU_LIST_POOL_DEBUG);
247*7c478bd9Sstevel@tonic-gate 	g_causes = uu_list_create(svcptrs, NULL, UU_LIST_DEBUG);
248*7c478bd9Sstevel@tonic-gate 	if (insts == NULL || svcptrs == NULL || depgroups == NULL ||
249*7c478bd9Sstevel@tonic-gate 	    deps == NULL || g_causes == NULL)
250*7c478bd9Sstevel@tonic-gate 		uu_die(emsg_nomem);
251*7c478bd9Sstevel@tonic-gate 
252*7c478bd9Sstevel@tonic-gate 	if ((g_local_scope = scf_scope_create(h)) == NULL ||
253*7c478bd9Sstevel@tonic-gate 	    (g_svc = scf_service_create(h)) == NULL ||
254*7c478bd9Sstevel@tonic-gate 	    (g_inst = scf_instance_create(h)) == NULL ||
255*7c478bd9Sstevel@tonic-gate 	    (g_snap = scf_snapshot_create(h)) == NULL ||
256*7c478bd9Sstevel@tonic-gate 	    (g_pg = scf_pg_create(h)) == NULL ||
257*7c478bd9Sstevel@tonic-gate 	    (g_prop = scf_property_create(h)) == NULL ||
258*7c478bd9Sstevel@tonic-gate 	    (g_val = scf_value_create(h)) == NULL ||
259*7c478bd9Sstevel@tonic-gate 	    (g_iter = scf_iter_create(h)) == NULL ||
260*7c478bd9Sstevel@tonic-gate 	    (g_viter = scf_iter_create(h)) == NULL)
261*7c478bd9Sstevel@tonic-gate 		scfdie();
262*7c478bd9Sstevel@tonic-gate 
263*7c478bd9Sstevel@tonic-gate 	if (scf_handle_get_scope(h, SCF_SCOPE_LOCAL, g_local_scope) != 0)
264*7c478bd9Sstevel@tonic-gate 		scfdie();
265*7c478bd9Sstevel@tonic-gate 
266*7c478bd9Sstevel@tonic-gate 	g_fmri_sz = max_scf_fmri_length + 1;
267*7c478bd9Sstevel@tonic-gate 	g_fmri = safe_malloc(g_fmri_sz);
268*7c478bd9Sstevel@tonic-gate 
269*7c478bd9Sstevel@tonic-gate 	g_value_sz = max_scf_value_length + 1;
270*7c478bd9Sstevel@tonic-gate 	g_value = safe_malloc(g_value_sz);
271*7c478bd9Sstevel@tonic-gate }
272*7c478bd9Sstevel@tonic-gate 
273*7c478bd9Sstevel@tonic-gate /*
274*7c478bd9Sstevel@tonic-gate  * Repository loading routines.
275*7c478bd9Sstevel@tonic-gate  */
276*7c478bd9Sstevel@tonic-gate 
277*7c478bd9Sstevel@tonic-gate /*
278*7c478bd9Sstevel@tonic-gate  * Returns
279*7c478bd9Sstevel@tonic-gate  *   0 - success
280*7c478bd9Sstevel@tonic-gate  *   ECANCELED - inst was deleted
281*7c478bd9Sstevel@tonic-gate  *   EINVAL - inst is invalid
282*7c478bd9Sstevel@tonic-gate  */
283*7c478bd9Sstevel@tonic-gate static int
284*7c478bd9Sstevel@tonic-gate load_dependencies(inst_t *svcp, scf_instance_t *inst)
285*7c478bd9Sstevel@tonic-gate {
286*7c478bd9Sstevel@tonic-gate 	scf_snapshot_t *snap;
287*7c478bd9Sstevel@tonic-gate 	struct dependency_group *dg;
288*7c478bd9Sstevel@tonic-gate 	struct dependency *d;
289*7c478bd9Sstevel@tonic-gate 	int r;
290*7c478bd9Sstevel@tonic-gate 
291*7c478bd9Sstevel@tonic-gate 	assert(svcp->dependencies == NULL);
292*7c478bd9Sstevel@tonic-gate 	svcp->dependencies = uu_list_create(depgroups, svcp, UU_LIST_DEBUG);
293*7c478bd9Sstevel@tonic-gate 	if (svcp->dependencies == NULL)
294*7c478bd9Sstevel@tonic-gate 		uu_die(emsg_nomem);
295*7c478bd9Sstevel@tonic-gate 
296*7c478bd9Sstevel@tonic-gate 	if (scf_instance_get_snapshot(inst, "running", g_snap) == 0) {
297*7c478bd9Sstevel@tonic-gate 		snap = g_snap;
298*7c478bd9Sstevel@tonic-gate 	} else {
299*7c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND)
300*7c478bd9Sstevel@tonic-gate 			scfdie();
301*7c478bd9Sstevel@tonic-gate 
302*7c478bd9Sstevel@tonic-gate 		snap = NULL;
303*7c478bd9Sstevel@tonic-gate 	}
304*7c478bd9Sstevel@tonic-gate 
305*7c478bd9Sstevel@tonic-gate 	if (scf_iter_instance_pgs_typed_composed(g_iter, inst, snap,
306*7c478bd9Sstevel@tonic-gate 	    SCF_GROUP_DEPENDENCY) != 0) {
307*7c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_DELETED)
308*7c478bd9Sstevel@tonic-gate 			scfdie();
309*7c478bd9Sstevel@tonic-gate 		return (ECANCELED);
310*7c478bd9Sstevel@tonic-gate 	}
311*7c478bd9Sstevel@tonic-gate 
312*7c478bd9Sstevel@tonic-gate 	for (;;) {
313*7c478bd9Sstevel@tonic-gate 		r = scf_iter_next_pg(g_iter, g_pg);
314*7c478bd9Sstevel@tonic-gate 		if (r == 0)
315*7c478bd9Sstevel@tonic-gate 			break;
316*7c478bd9Sstevel@tonic-gate 		if (r != 1) {
317*7c478bd9Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_DELETED)
318*7c478bd9Sstevel@tonic-gate 				scfdie();
319*7c478bd9Sstevel@tonic-gate 			return (ECANCELED);
320*7c478bd9Sstevel@tonic-gate 		}
321*7c478bd9Sstevel@tonic-gate 
322*7c478bd9Sstevel@tonic-gate 		dg = safe_malloc(sizeof (*dg));
323*7c478bd9Sstevel@tonic-gate 		(void) memset(dg, 0, sizeof (*dg));
324*7c478bd9Sstevel@tonic-gate 		dg->entities = uu_list_create(deps, dg, UU_LIST_DEBUG);
325*7c478bd9Sstevel@tonic-gate 		if (dg->entities == NULL)
326*7c478bd9Sstevel@tonic-gate 			uu_die(emsg_nomem);
327*7c478bd9Sstevel@tonic-gate 
328*7c478bd9Sstevel@tonic-gate 		if (pg_get_single_val(g_pg, SCF_PROPERTY_GROUPING,
329*7c478bd9Sstevel@tonic-gate 		    SCF_TYPE_ASTRING, g_value, g_value_sz, 0) != 0)
330*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
331*7c478bd9Sstevel@tonic-gate 
332*7c478bd9Sstevel@tonic-gate 		if (strcmp(g_value, "require_all") == 0)
333*7c478bd9Sstevel@tonic-gate 			dg->grouping = DGG_REQALL;
334*7c478bd9Sstevel@tonic-gate 		else if (strcmp(g_value, "require_any") == 0)
335*7c478bd9Sstevel@tonic-gate 			dg->grouping = DGG_REQANY;
336*7c478bd9Sstevel@tonic-gate 		else if (strcmp(g_value, "optional_all") == 0)
337*7c478bd9Sstevel@tonic-gate 			dg->grouping = DGG_OPTALL;
338*7c478bd9Sstevel@tonic-gate 		else if (strcmp(g_value, "exclude_all") == 0)
339*7c478bd9Sstevel@tonic-gate 			dg->grouping = DGG_EXCALL;
340*7c478bd9Sstevel@tonic-gate 		else {
341*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("svc:/%s:%s has "
342*7c478bd9Sstevel@tonic-gate 			    "dependency with unknown type \"%s\".\n"),
343*7c478bd9Sstevel@tonic-gate 			    svcp->svcname, svcp->instname, g_value);
344*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
345*7c478bd9Sstevel@tonic-gate 		}
346*7c478bd9Sstevel@tonic-gate 
347*7c478bd9Sstevel@tonic-gate 		if (pg_get_single_val(g_pg, SCF_PROPERTY_TYPE, SCF_TYPE_ASTRING,
348*7c478bd9Sstevel@tonic-gate 		    g_value, g_value_sz, 0) != 0)
349*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
350*7c478bd9Sstevel@tonic-gate 		dg->type = safe_strdup(g_value);
351*7c478bd9Sstevel@tonic-gate 
352*7c478bd9Sstevel@tonic-gate 		if (scf_pg_get_property(g_pg, SCF_PROPERTY_ENTITIES, g_prop) !=
353*7c478bd9Sstevel@tonic-gate 		    0) {
354*7c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
355*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_FOUND:
356*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext("svc:/%s:%s has "
357*7c478bd9Sstevel@tonic-gate 				    "dependency without an entities "
358*7c478bd9Sstevel@tonic-gate 				    "property.\n"), svcp->svcname,
359*7c478bd9Sstevel@tonic-gate 				    svcp->instname);
360*7c478bd9Sstevel@tonic-gate 				return (EINVAL);
361*7c478bd9Sstevel@tonic-gate 
362*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_DELETED:
363*7c478bd9Sstevel@tonic-gate 				return (ECANCELED);
364*7c478bd9Sstevel@tonic-gate 
365*7c478bd9Sstevel@tonic-gate 			default:
366*7c478bd9Sstevel@tonic-gate 				scfdie();
367*7c478bd9Sstevel@tonic-gate 			}
368*7c478bd9Sstevel@tonic-gate 		}
369*7c478bd9Sstevel@tonic-gate 
370*7c478bd9Sstevel@tonic-gate 		if (scf_iter_property_values(g_viter, g_prop) != 0) {
371*7c478bd9Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_DELETED)
372*7c478bd9Sstevel@tonic-gate 				scfdie();
373*7c478bd9Sstevel@tonic-gate 			return (ECANCELED);
374*7c478bd9Sstevel@tonic-gate 		}
375*7c478bd9Sstevel@tonic-gate 
376*7c478bd9Sstevel@tonic-gate 		for (;;) {
377*7c478bd9Sstevel@tonic-gate 			r = scf_iter_next_value(g_viter, g_val);
378*7c478bd9Sstevel@tonic-gate 			if (r == 0)
379*7c478bd9Sstevel@tonic-gate 				break;
380*7c478bd9Sstevel@tonic-gate 			if (r != 1) {
381*7c478bd9Sstevel@tonic-gate 				if (scf_error() != SCF_ERROR_DELETED)
382*7c478bd9Sstevel@tonic-gate 					scfdie();
383*7c478bd9Sstevel@tonic-gate 				return (ECANCELED);
384*7c478bd9Sstevel@tonic-gate 			}
385*7c478bd9Sstevel@tonic-gate 
386*7c478bd9Sstevel@tonic-gate 			d = safe_malloc(sizeof (*d));
387*7c478bd9Sstevel@tonic-gate 			d->fmri = safe_malloc(max_scf_fmri_length + 1);
388*7c478bd9Sstevel@tonic-gate 
389*7c478bd9Sstevel@tonic-gate 			if (scf_value_get_astring(g_val, (char *)d->fmri,
390*7c478bd9Sstevel@tonic-gate 			    max_scf_fmri_length + 1) < 0)
391*7c478bd9Sstevel@tonic-gate 				scfdie();
392*7c478bd9Sstevel@tonic-gate 
393*7c478bd9Sstevel@tonic-gate 			uu_list_node_init(d, &d->node, deps);
394*7c478bd9Sstevel@tonic-gate 			(void) uu_list_append(dg->entities, d);
395*7c478bd9Sstevel@tonic-gate 		}
396*7c478bd9Sstevel@tonic-gate 
397*7c478bd9Sstevel@tonic-gate 		uu_list_node_init(dg, &dg->node, depgroups);
398*7c478bd9Sstevel@tonic-gate 		r = uu_list_append(svcp->dependencies, dg);
399*7c478bd9Sstevel@tonic-gate 		assert(r == 0);
400*7c478bd9Sstevel@tonic-gate 	}
401*7c478bd9Sstevel@tonic-gate 
402*7c478bd9Sstevel@tonic-gate 	return (0);
403*7c478bd9Sstevel@tonic-gate }
404*7c478bd9Sstevel@tonic-gate 
405*7c478bd9Sstevel@tonic-gate static void
406*7c478bd9Sstevel@tonic-gate add_instance(const char *svcname, const char *instname, scf_instance_t *inst)
407*7c478bd9Sstevel@tonic-gate {
408*7c478bd9Sstevel@tonic-gate 	inst_t *instp;
409*7c478bd9Sstevel@tonic-gate 	svc_t *svcp;
410*7c478bd9Sstevel@tonic-gate 	int have_enabled = 0;
411*7c478bd9Sstevel@tonic-gate 	int i;
412*7c478bd9Sstevel@tonic-gate 	uint32_t h;
413*7c478bd9Sstevel@tonic-gate 
414*7c478bd9Sstevel@tonic-gate 	h = hash_name(svcname) & SVC_HASH_MASK;
415*7c478bd9Sstevel@tonic-gate 	for (svcp = services[h]; svcp != NULL; svcp = svcp->next) {
416*7c478bd9Sstevel@tonic-gate 		if (strcmp(svcp->svcname, svcname) == 0)
417*7c478bd9Sstevel@tonic-gate 			break;
418*7c478bd9Sstevel@tonic-gate 	}
419*7c478bd9Sstevel@tonic-gate 
420*7c478bd9Sstevel@tonic-gate 	if (svcp == NULL) {
421*7c478bd9Sstevel@tonic-gate 		svcp = safe_malloc(sizeof (*svcp));
422*7c478bd9Sstevel@tonic-gate 		svcp->svcname = safe_strdup(svcname);
423*7c478bd9Sstevel@tonic-gate 		svcp->instances = uu_list_create(insts, svcp, UU_LIST_DEBUG);
424*7c478bd9Sstevel@tonic-gate 		if (svcp->instances == NULL)
425*7c478bd9Sstevel@tonic-gate 			uu_die(emsg_nomem);
426*7c478bd9Sstevel@tonic-gate 		svcp->next = services[h];
427*7c478bd9Sstevel@tonic-gate 		services[h] = svcp;
428*7c478bd9Sstevel@tonic-gate 	}
429*7c478bd9Sstevel@tonic-gate 
430*7c478bd9Sstevel@tonic-gate 	instp = safe_malloc(sizeof (*instp));
431*7c478bd9Sstevel@tonic-gate 	(void) memset(instp, 0, sizeof (*instp));
432*7c478bd9Sstevel@tonic-gate 	instp->svcname = svcp->svcname;
433*7c478bd9Sstevel@tonic-gate 	instp->instname = safe_strdup(instname);
434*7c478bd9Sstevel@tonic-gate 	instp->impact_dependents =
435*7c478bd9Sstevel@tonic-gate 	    uu_list_create(svcptrs, instp, UU_LIST_DEBUG);
436*7c478bd9Sstevel@tonic-gate 	if (instp->impact_dependents == NULL)
437*7c478bd9Sstevel@tonic-gate 		uu_die(emsg_nomem);
438*7c478bd9Sstevel@tonic-gate 
439*7c478bd9Sstevel@tonic-gate 	if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, g_pg) != 0) {
440*7c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
441*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
442*7c478bd9Sstevel@tonic-gate 			return;
443*7c478bd9Sstevel@tonic-gate 
444*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
445*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("svc:/%s:%s has no "
446*7c478bd9Sstevel@tonic-gate 			    "\"%s\" property group; ignoring.\n"),
447*7c478bd9Sstevel@tonic-gate 			    instp->svcname, instp->instname, SCF_PG_RESTARTER);
448*7c478bd9Sstevel@tonic-gate 			return;
449*7c478bd9Sstevel@tonic-gate 
450*7c478bd9Sstevel@tonic-gate 		default:
451*7c478bd9Sstevel@tonic-gate 			scfdie();
452*7c478bd9Sstevel@tonic-gate 		}
453*7c478bd9Sstevel@tonic-gate 	}
454*7c478bd9Sstevel@tonic-gate 
455*7c478bd9Sstevel@tonic-gate 	if (pg_get_single_val(g_pg, SCF_PROPERTY_STATE, SCF_TYPE_ASTRING,
456*7c478bd9Sstevel@tonic-gate 	    (void *)instp->state, sizeof (instp->state), 0) != 0)
457*7c478bd9Sstevel@tonic-gate 		return;
458*7c478bd9Sstevel@tonic-gate 
459*7c478bd9Sstevel@tonic-gate 	if (pg_get_single_val(g_pg, SCF_PROPERTY_NEXT_STATE, SCF_TYPE_ASTRING,
460*7c478bd9Sstevel@tonic-gate 	    (void *)instp->next_state, sizeof (instp->next_state), 0) != 0)
461*7c478bd9Sstevel@tonic-gate 		return;
462*7c478bd9Sstevel@tonic-gate 
463*7c478bd9Sstevel@tonic-gate 	if (pg_get_single_val(g_pg, SCF_PROPERTY_STATE_TIMESTAMP,
464*7c478bd9Sstevel@tonic-gate 	    SCF_TYPE_TIME, &instp->stime, 0, 0) != 0)
465*7c478bd9Sstevel@tonic-gate 		return;
466*7c478bd9Sstevel@tonic-gate 
467*7c478bd9Sstevel@tonic-gate 	if (pg_get_single_val(g_pg, SCF_PROPERTY_AUX_STATE, SCF_TYPE_ASTRING,
468*7c478bd9Sstevel@tonic-gate 	    g_fmri, g_fmri_sz, 0) != 0)
469*7c478bd9Sstevel@tonic-gate 		return;
470*7c478bd9Sstevel@tonic-gate 	instp->aux_state = safe_strdup(g_fmri);
471*7c478bd9Sstevel@tonic-gate 
472*7c478bd9Sstevel@tonic-gate 	(void) pg_get_single_val(g_pg, SCF_PROPERTY_START_METHOD_WAITSTATUS,
473*7c478bd9Sstevel@tonic-gate 	    SCF_TYPE_INTEGER, &instp->start_method_waitstatus, 0, 0);
474*7c478bd9Sstevel@tonic-gate 
475*7c478bd9Sstevel@tonic-gate 	if (scf_instance_get_pg(inst, SCF_PG_GENERAL_OVR, g_pg) == 0) {
476*7c478bd9Sstevel@tonic-gate 		if (pg_get_single_val(g_pg, SCF_PROPERTY_ENABLED,
477*7c478bd9Sstevel@tonic-gate 		    SCF_TYPE_BOOLEAN, &instp->enabled, 0, 0) == 0)
478*7c478bd9Sstevel@tonic-gate 			have_enabled = 1;
479*7c478bd9Sstevel@tonic-gate 	} else {
480*7c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
481*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
482*7c478bd9Sstevel@tonic-gate 			break;
483*7c478bd9Sstevel@tonic-gate 
484*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
485*7c478bd9Sstevel@tonic-gate 			return;
486*7c478bd9Sstevel@tonic-gate 
487*7c478bd9Sstevel@tonic-gate 		default:
488*7c478bd9Sstevel@tonic-gate 			scfdie();
489*7c478bd9Sstevel@tonic-gate 		}
490*7c478bd9Sstevel@tonic-gate 	}
491*7c478bd9Sstevel@tonic-gate 
492*7c478bd9Sstevel@tonic-gate 	if (scf_instance_get_pg_composed(inst, NULL, SCF_PG_GENERAL, g_pg) !=
493*7c478bd9Sstevel@tonic-gate 	    0) {
494*7c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
495*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
496*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
497*7c478bd9Sstevel@tonic-gate 			return;
498*7c478bd9Sstevel@tonic-gate 
499*7c478bd9Sstevel@tonic-gate 		default:
500*7c478bd9Sstevel@tonic-gate 			scfdie();
501*7c478bd9Sstevel@tonic-gate 		}
502*7c478bd9Sstevel@tonic-gate 	}
503*7c478bd9Sstevel@tonic-gate 
504*7c478bd9Sstevel@tonic-gate 	if (pg_get_single_val(g_pg, SCF_PROPERTY_ENABLED, SCF_TYPE_BOOLEAN,
505*7c478bd9Sstevel@tonic-gate 	    &i, 0, 0) != 0)
506*7c478bd9Sstevel@tonic-gate 		return;
507*7c478bd9Sstevel@tonic-gate 	if (!have_enabled) {
508*7c478bd9Sstevel@tonic-gate 		instp->enabled = i;
509*7c478bd9Sstevel@tonic-gate 		instp->temporary = 0;
510*7c478bd9Sstevel@tonic-gate 	} else {
511*7c478bd9Sstevel@tonic-gate 		instp->temporary = (instp->enabled != i);
512*7c478bd9Sstevel@tonic-gate 	}
513*7c478bd9Sstevel@tonic-gate 
514*7c478bd9Sstevel@tonic-gate 	if (pg_get_single_val(g_pg, SCF_PROPERTY_RESTARTER, SCF_TYPE_ASTRING,
515*7c478bd9Sstevel@tonic-gate 	    g_fmri, g_fmri_sz, 0) == 0)
516*7c478bd9Sstevel@tonic-gate 		instp->restarter = safe_strdup(g_fmri);
517*7c478bd9Sstevel@tonic-gate 	else
518*7c478bd9Sstevel@tonic-gate 		instp->restarter = SCF_SERVICE_STARTD;
519*7c478bd9Sstevel@tonic-gate 
520*7c478bd9Sstevel@tonic-gate 	if (strcmp(instp->state, SCF_STATE_STRING_OFFLINE) == 0 &&
521*7c478bd9Sstevel@tonic-gate 	    load_dependencies(instp, inst) != 0)
522*7c478bd9Sstevel@tonic-gate 		return;
523*7c478bd9Sstevel@tonic-gate 
524*7c478bd9Sstevel@tonic-gate 	uu_list_node_init(instp, &instp->node, insts);
525*7c478bd9Sstevel@tonic-gate 	i = uu_list_append(svcp->instances, instp);
526*7c478bd9Sstevel@tonic-gate 	assert(i == 0);
527*7c478bd9Sstevel@tonic-gate }
528*7c478bd9Sstevel@tonic-gate 
529*7c478bd9Sstevel@tonic-gate static void
530*7c478bd9Sstevel@tonic-gate load_services(void)
531*7c478bd9Sstevel@tonic-gate {
532*7c478bd9Sstevel@tonic-gate 	scf_iter_t *siter, *iiter;
533*7c478bd9Sstevel@tonic-gate 	int r;
534*7c478bd9Sstevel@tonic-gate 	char *svcname, *instname;
535*7c478bd9Sstevel@tonic-gate 
536*7c478bd9Sstevel@tonic-gate 	if ((siter = scf_iter_create(h)) == NULL ||
537*7c478bd9Sstevel@tonic-gate 	    (iiter = scf_iter_create(h)) == NULL)
538*7c478bd9Sstevel@tonic-gate 		scfdie();
539*7c478bd9Sstevel@tonic-gate 
540*7c478bd9Sstevel@tonic-gate 	svcname = safe_malloc(max_scf_name_length + 1);
541*7c478bd9Sstevel@tonic-gate 	instname = safe_malloc(max_scf_name_length + 1);
542*7c478bd9Sstevel@tonic-gate 
543*7c478bd9Sstevel@tonic-gate 	if (scf_iter_scope_services(siter, g_local_scope) != 0)
544*7c478bd9Sstevel@tonic-gate 		scfdie();
545*7c478bd9Sstevel@tonic-gate 
546*7c478bd9Sstevel@tonic-gate 	for (;;) {
547*7c478bd9Sstevel@tonic-gate 		r = scf_iter_next_service(siter, g_svc);
548*7c478bd9Sstevel@tonic-gate 		if (r == 0)
549*7c478bd9Sstevel@tonic-gate 			break;
550*7c478bd9Sstevel@tonic-gate 		if (r != 1)
551*7c478bd9Sstevel@tonic-gate 			scfdie();
552*7c478bd9Sstevel@tonic-gate 
553*7c478bd9Sstevel@tonic-gate 		if (scf_service_get_name(g_svc, svcname,
554*7c478bd9Sstevel@tonic-gate 		    max_scf_name_length + 1) < 0) {
555*7c478bd9Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_DELETED)
556*7c478bd9Sstevel@tonic-gate 				scfdie();
557*7c478bd9Sstevel@tonic-gate 			continue;
558*7c478bd9Sstevel@tonic-gate 		}
559*7c478bd9Sstevel@tonic-gate 
560*7c478bd9Sstevel@tonic-gate 		if (scf_iter_service_instances(iiter, g_svc) != 0) {
561*7c478bd9Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_DELETED)
562*7c478bd9Sstevel@tonic-gate 				scfdie();
563*7c478bd9Sstevel@tonic-gate 			continue;
564*7c478bd9Sstevel@tonic-gate 		}
565*7c478bd9Sstevel@tonic-gate 
566*7c478bd9Sstevel@tonic-gate 		for (;;) {
567*7c478bd9Sstevel@tonic-gate 			r = scf_iter_next_instance(iiter, g_inst);
568*7c478bd9Sstevel@tonic-gate 			if (r == 0)
569*7c478bd9Sstevel@tonic-gate 				break;
570*7c478bd9Sstevel@tonic-gate 			if (r != 1) {
571*7c478bd9Sstevel@tonic-gate 				if (scf_error() != SCF_ERROR_DELETED)
572*7c478bd9Sstevel@tonic-gate 					scfdie();
573*7c478bd9Sstevel@tonic-gate 				break;
574*7c478bd9Sstevel@tonic-gate 			}
575*7c478bd9Sstevel@tonic-gate 
576*7c478bd9Sstevel@tonic-gate 			if (scf_instance_get_name(g_inst, instname,
577*7c478bd9Sstevel@tonic-gate 			    max_scf_name_length + 1) < 0) {
578*7c478bd9Sstevel@tonic-gate 				if (scf_error() != SCF_ERROR_DELETED)
579*7c478bd9Sstevel@tonic-gate 					scfdie();
580*7c478bd9Sstevel@tonic-gate 				continue;
581*7c478bd9Sstevel@tonic-gate 			}
582*7c478bd9Sstevel@tonic-gate 
583*7c478bd9Sstevel@tonic-gate 			add_instance(svcname, instname, g_inst);
584*7c478bd9Sstevel@tonic-gate 		}
585*7c478bd9Sstevel@tonic-gate 	}
586*7c478bd9Sstevel@tonic-gate 
587*7c478bd9Sstevel@tonic-gate 	free(svcname);
588*7c478bd9Sstevel@tonic-gate 	free(instname);
589*7c478bd9Sstevel@tonic-gate 	scf_iter_destroy(siter);
590*7c478bd9Sstevel@tonic-gate 	scf_iter_destroy(iiter);
591*7c478bd9Sstevel@tonic-gate }
592*7c478bd9Sstevel@tonic-gate 
593*7c478bd9Sstevel@tonic-gate /*
594*7c478bd9Sstevel@tonic-gate  * Dependency analysis routines.
595*7c478bd9Sstevel@tonic-gate  */
596*7c478bd9Sstevel@tonic-gate 
597*7c478bd9Sstevel@tonic-gate static void
598*7c478bd9Sstevel@tonic-gate add_svcptr(uu_list_t *lst, inst_t *svcp)
599*7c478bd9Sstevel@tonic-gate {
600*7c478bd9Sstevel@tonic-gate 	struct svcptr *spp;
601*7c478bd9Sstevel@tonic-gate 	uu_list_index_t idx;
602*7c478bd9Sstevel@tonic-gate 	int r;
603*7c478bd9Sstevel@tonic-gate 
604*7c478bd9Sstevel@tonic-gate 	spp = safe_malloc(sizeof (*spp));
605*7c478bd9Sstevel@tonic-gate 	spp->svcp = svcp;
606*7c478bd9Sstevel@tonic-gate 	spp->next_hop = NULL;
607*7c478bd9Sstevel@tonic-gate 
608*7c478bd9Sstevel@tonic-gate 	if (uu_list_find(lst, spp, NULL, &idx) != NULL) {
609*7c478bd9Sstevel@tonic-gate 		free(spp);
610*7c478bd9Sstevel@tonic-gate 		return;
611*7c478bd9Sstevel@tonic-gate 	}
612*7c478bd9Sstevel@tonic-gate 
613*7c478bd9Sstevel@tonic-gate 	uu_list_node_init(spp, &spp->node, svcptrs);
614*7c478bd9Sstevel@tonic-gate 	r = uu_list_append(lst, spp);
615*7c478bd9Sstevel@tonic-gate 	assert(r == 0);
616*7c478bd9Sstevel@tonic-gate }
617*7c478bd9Sstevel@tonic-gate 
618*7c478bd9Sstevel@tonic-gate static int determine_causes(inst_t *, void *);
619*7c478bd9Sstevel@tonic-gate 
620*7c478bd9Sstevel@tonic-gate /*
621*7c478bd9Sstevel@tonic-gate  * Determine the causes of src and add them to the causes list of dst.
622*7c478bd9Sstevel@tonic-gate  * Returns ELOOP if src is active, and 0 otherwise.
623*7c478bd9Sstevel@tonic-gate  */
624*7c478bd9Sstevel@tonic-gate static int
625*7c478bd9Sstevel@tonic-gate add_causes(inst_t *dst, inst_t *src)
626*7c478bd9Sstevel@tonic-gate {
627*7c478bd9Sstevel@tonic-gate 	struct svcptr *spp, *copy;
628*7c478bd9Sstevel@tonic-gate 	uu_list_index_t idx;
629*7c478bd9Sstevel@tonic-gate 
630*7c478bd9Sstevel@tonic-gate 	if (determine_causes(src, (void *)1) != UU_WALK_NEXT) {
631*7c478bd9Sstevel@tonic-gate 		/* Dependency cycle. */
632*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "  svc:/%s:%s\n", dst->svcname,
633*7c478bd9Sstevel@tonic-gate 		    dst->instname);
634*7c478bd9Sstevel@tonic-gate 		return (ELOOP);
635*7c478bd9Sstevel@tonic-gate 	}
636*7c478bd9Sstevel@tonic-gate 
637*7c478bd9Sstevel@tonic-gate 	add_svcptr(src->impact_dependents, dst);
638*7c478bd9Sstevel@tonic-gate 
639*7c478bd9Sstevel@tonic-gate 	for (spp = uu_list_first(src->causes);
640*7c478bd9Sstevel@tonic-gate 	    spp != NULL;
641*7c478bd9Sstevel@tonic-gate 	    spp = uu_list_next(src->causes, spp)) {
642*7c478bd9Sstevel@tonic-gate 		if (uu_list_find(dst->causes, spp, NULL, &idx) != NULL)
643*7c478bd9Sstevel@tonic-gate 			continue;
644*7c478bd9Sstevel@tonic-gate 
645*7c478bd9Sstevel@tonic-gate 		copy = safe_malloc(sizeof (*copy));
646*7c478bd9Sstevel@tonic-gate 		copy->svcp = spp->svcp;
647*7c478bd9Sstevel@tonic-gate 		copy->next_hop = src;
648*7c478bd9Sstevel@tonic-gate 		uu_list_node_init(copy, &copy->node, svcptrs);
649*7c478bd9Sstevel@tonic-gate 		uu_list_insert(dst->causes, copy, idx);
650*7c478bd9Sstevel@tonic-gate 
651*7c478bd9Sstevel@tonic-gate 		add_svcptr(g_causes, spp->svcp);
652*7c478bd9Sstevel@tonic-gate 	}
653*7c478bd9Sstevel@tonic-gate 
654*7c478bd9Sstevel@tonic-gate 	return (0);
655*7c478bd9Sstevel@tonic-gate }
656*7c478bd9Sstevel@tonic-gate 
657*7c478bd9Sstevel@tonic-gate static int
658*7c478bd9Sstevel@tonic-gate inst_running(inst_t *ip)
659*7c478bd9Sstevel@tonic-gate {
660*7c478bd9Sstevel@tonic-gate 	return (strcmp(ip->state, SCF_STATE_STRING_ONLINE) == 0 ||
661*7c478bd9Sstevel@tonic-gate 	    strcmp(ip->state, SCF_STATE_STRING_DEGRADED) == 0);
662*7c478bd9Sstevel@tonic-gate }
663*7c478bd9Sstevel@tonic-gate 
664*7c478bd9Sstevel@tonic-gate static int
665*7c478bd9Sstevel@tonic-gate inst_running_or_maint(inst_t *ip)
666*7c478bd9Sstevel@tonic-gate {
667*7c478bd9Sstevel@tonic-gate 	return (inst_running(ip) ||
668*7c478bd9Sstevel@tonic-gate 	    strcmp(ip->state, SCF_STATE_STRING_MAINT) == 0);
669*7c478bd9Sstevel@tonic-gate }
670*7c478bd9Sstevel@tonic-gate 
671*7c478bd9Sstevel@tonic-gate static svc_t *
672*7c478bd9Sstevel@tonic-gate get_svc(const char *sn)
673*7c478bd9Sstevel@tonic-gate {
674*7c478bd9Sstevel@tonic-gate 	uint32_t h;
675*7c478bd9Sstevel@tonic-gate 	svc_t *svcp;
676*7c478bd9Sstevel@tonic-gate 
677*7c478bd9Sstevel@tonic-gate 	h = hash_name(sn) & SVC_HASH_MASK;
678*7c478bd9Sstevel@tonic-gate 
679*7c478bd9Sstevel@tonic-gate 	for (svcp = services[h]; svcp != NULL; svcp = svcp->next) {
680*7c478bd9Sstevel@tonic-gate 		if (strcmp(svcp->svcname, sn) == 0)
681*7c478bd9Sstevel@tonic-gate 			break;
682*7c478bd9Sstevel@tonic-gate 	}
683*7c478bd9Sstevel@tonic-gate 
684*7c478bd9Sstevel@tonic-gate 	return (svcp);
685*7c478bd9Sstevel@tonic-gate }
686*7c478bd9Sstevel@tonic-gate 
687*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
688*7c478bd9Sstevel@tonic-gate static inst_t *
689*7c478bd9Sstevel@tonic-gate get_inst(svc_t *svcp, const char *in)
690*7c478bd9Sstevel@tonic-gate {
691*7c478bd9Sstevel@tonic-gate 	inst_t *instp;
692*7c478bd9Sstevel@tonic-gate 
693*7c478bd9Sstevel@tonic-gate 	for (instp = uu_list_first(svcp->instances);
694*7c478bd9Sstevel@tonic-gate 	    instp != NULL;
695*7c478bd9Sstevel@tonic-gate 	    instp = uu_list_next(svcp->instances, instp)) {
696*7c478bd9Sstevel@tonic-gate 		if (strcmp(instp->instname, in) == 0)
697*7c478bd9Sstevel@tonic-gate 			return (instp);
698*7c478bd9Sstevel@tonic-gate 	}
699*7c478bd9Sstevel@tonic-gate 
700*7c478bd9Sstevel@tonic-gate 	return (NULL);
701*7c478bd9Sstevel@tonic-gate }
702*7c478bd9Sstevel@tonic-gate 
703*7c478bd9Sstevel@tonic-gate static int
704*7c478bd9Sstevel@tonic-gate get_fmri(const char *fmri, svc_t **spp, inst_t **ipp)
705*7c478bd9Sstevel@tonic-gate {
706*7c478bd9Sstevel@tonic-gate 	const char *sn, *in;
707*7c478bd9Sstevel@tonic-gate 	svc_t *sp;
708*7c478bd9Sstevel@tonic-gate 	inst_t *ip;
709*7c478bd9Sstevel@tonic-gate 
710*7c478bd9Sstevel@tonic-gate 	if (strlcpy(g_fmri, fmri, g_fmri_sz) >= g_fmri_sz)
711*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
712*7c478bd9Sstevel@tonic-gate 
713*7c478bd9Sstevel@tonic-gate 	if (scf_parse_svc_fmri(g_fmri, NULL, &sn, &in, NULL, NULL) != 0)
714*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
715*7c478bd9Sstevel@tonic-gate 
716*7c478bd9Sstevel@tonic-gate 	if (sn == NULL)
717*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
718*7c478bd9Sstevel@tonic-gate 
719*7c478bd9Sstevel@tonic-gate 	sp = get_svc(sn);
720*7c478bd9Sstevel@tonic-gate 	if (sp == NULL)
721*7c478bd9Sstevel@tonic-gate 		return (ENOENT);
722*7c478bd9Sstevel@tonic-gate 
723*7c478bd9Sstevel@tonic-gate 	if (in != NULL) {
724*7c478bd9Sstevel@tonic-gate 		ip = get_inst(sp, in);
725*7c478bd9Sstevel@tonic-gate 		if (ip == NULL)
726*7c478bd9Sstevel@tonic-gate 			return (ENOENT);
727*7c478bd9Sstevel@tonic-gate 	}
728*7c478bd9Sstevel@tonic-gate 
729*7c478bd9Sstevel@tonic-gate 	if (spp != NULL)
730*7c478bd9Sstevel@tonic-gate 		*spp = sp;
731*7c478bd9Sstevel@tonic-gate 	if (ipp != NULL)
732*7c478bd9Sstevel@tonic-gate 		*ipp = ((in == NULL) ? NULL : ip);
733*7c478bd9Sstevel@tonic-gate 
734*7c478bd9Sstevel@tonic-gate 	return (0);
735*7c478bd9Sstevel@tonic-gate }
736*7c478bd9Sstevel@tonic-gate 
737*7c478bd9Sstevel@tonic-gate static int
738*7c478bd9Sstevel@tonic-gate process_reqall(inst_t *svcp, struct dependency_group *dg)
739*7c478bd9Sstevel@tonic-gate {
740*7c478bd9Sstevel@tonic-gate 	uu_list_walk_t *walk;
741*7c478bd9Sstevel@tonic-gate 	struct dependency *d;
742*7c478bd9Sstevel@tonic-gate 	int r, svcrunning;
743*7c478bd9Sstevel@tonic-gate 	svc_t *sp;
744*7c478bd9Sstevel@tonic-gate 	inst_t *ip;
745*7c478bd9Sstevel@tonic-gate 
746*7c478bd9Sstevel@tonic-gate 	walk = uu_list_walk_start(dg->entities, UU_WALK_ROBUST);
747*7c478bd9Sstevel@tonic-gate 	if (walk == NULL)
748*7c478bd9Sstevel@tonic-gate 		uu_die(emsg_nomem);
749*7c478bd9Sstevel@tonic-gate 
750*7c478bd9Sstevel@tonic-gate 	while ((d = uu_list_walk_next(walk)) != NULL) {
751*7c478bd9Sstevel@tonic-gate 		r = get_fmri(d->fmri, &sp, &ip);
752*7c478bd9Sstevel@tonic-gate 		switch (r) {
753*7c478bd9Sstevel@tonic-gate 		case EINVAL:
754*7c478bd9Sstevel@tonic-gate 			/* LINTED */
755*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, emsg_invalid_dep, svcp->svcname,
756*7c478bd9Sstevel@tonic-gate 			    svcp->instname, d->fmri);
757*7c478bd9Sstevel@tonic-gate 			continue;
758*7c478bd9Sstevel@tonic-gate 
759*7c478bd9Sstevel@tonic-gate 		case ENOENT:
760*7c478bd9Sstevel@tonic-gate 			uu_list_remove(dg->entities, d);
761*7c478bd9Sstevel@tonic-gate 			r = uu_list_append(svcp->baddeps, d);
762*7c478bd9Sstevel@tonic-gate 			assert(r == 0);
763*7c478bd9Sstevel@tonic-gate 			continue;
764*7c478bd9Sstevel@tonic-gate 
765*7c478bd9Sstevel@tonic-gate 		case 0:
766*7c478bd9Sstevel@tonic-gate 			break;
767*7c478bd9Sstevel@tonic-gate 
768*7c478bd9Sstevel@tonic-gate 		default:
769*7c478bd9Sstevel@tonic-gate 			bad_error("get_fmri", r);
770*7c478bd9Sstevel@tonic-gate 		}
771*7c478bd9Sstevel@tonic-gate 
772*7c478bd9Sstevel@tonic-gate 		if (ip != NULL) {
773*7c478bd9Sstevel@tonic-gate 			if (inst_running(ip))
774*7c478bd9Sstevel@tonic-gate 				continue;
775*7c478bd9Sstevel@tonic-gate 			r = add_causes(svcp, ip);
776*7c478bd9Sstevel@tonic-gate 			if (r != 0) {
777*7c478bd9Sstevel@tonic-gate 				assert(r == ELOOP);
778*7c478bd9Sstevel@tonic-gate 				return (r);
779*7c478bd9Sstevel@tonic-gate 			}
780*7c478bd9Sstevel@tonic-gate 			continue;
781*7c478bd9Sstevel@tonic-gate 		}
782*7c478bd9Sstevel@tonic-gate 
783*7c478bd9Sstevel@tonic-gate 		svcrunning = 0;
784*7c478bd9Sstevel@tonic-gate 
785*7c478bd9Sstevel@tonic-gate 		for (ip = uu_list_first(sp->instances);
786*7c478bd9Sstevel@tonic-gate 		    ip != NULL;
787*7c478bd9Sstevel@tonic-gate 		    ip = uu_list_next(sp->instances, ip)) {
788*7c478bd9Sstevel@tonic-gate 			if (inst_running(ip))
789*7c478bd9Sstevel@tonic-gate 				svcrunning = 1;
790*7c478bd9Sstevel@tonic-gate 		}
791*7c478bd9Sstevel@tonic-gate 
792*7c478bd9Sstevel@tonic-gate 		if (!svcrunning) {
793*7c478bd9Sstevel@tonic-gate 			for (ip = uu_list_first(sp->instances);
794*7c478bd9Sstevel@tonic-gate 			    ip != NULL;
795*7c478bd9Sstevel@tonic-gate 			    ip = uu_list_next(sp->instances, ip)) {
796*7c478bd9Sstevel@tonic-gate 				r = add_causes(svcp, ip);
797*7c478bd9Sstevel@tonic-gate 				if (r != 0) {
798*7c478bd9Sstevel@tonic-gate 					assert(r == ELOOP);
799*7c478bd9Sstevel@tonic-gate 					uu_list_walk_end(walk);
800*7c478bd9Sstevel@tonic-gate 					return (r);
801*7c478bd9Sstevel@tonic-gate 				}
802*7c478bd9Sstevel@tonic-gate 			}
803*7c478bd9Sstevel@tonic-gate 		}
804*7c478bd9Sstevel@tonic-gate 	}
805*7c478bd9Sstevel@tonic-gate 
806*7c478bd9Sstevel@tonic-gate 	uu_list_walk_end(walk);
807*7c478bd9Sstevel@tonic-gate 	return (0);
808*7c478bd9Sstevel@tonic-gate }
809*7c478bd9Sstevel@tonic-gate 
810*7c478bd9Sstevel@tonic-gate static int
811*7c478bd9Sstevel@tonic-gate process_reqany(inst_t *svcp, struct dependency_group *dg)
812*7c478bd9Sstevel@tonic-gate {
813*7c478bd9Sstevel@tonic-gate 	svc_t *sp;
814*7c478bd9Sstevel@tonic-gate 	inst_t *ip;
815*7c478bd9Sstevel@tonic-gate 	struct dependency *d;
816*7c478bd9Sstevel@tonic-gate 	int r;
817*7c478bd9Sstevel@tonic-gate 	uu_list_walk_t *walk;
818*7c478bd9Sstevel@tonic-gate 
819*7c478bd9Sstevel@tonic-gate 	for (d = uu_list_first(dg->entities);
820*7c478bd9Sstevel@tonic-gate 	    d != NULL;
821*7c478bd9Sstevel@tonic-gate 	    d = uu_list_next(dg->entities, d)) {
822*7c478bd9Sstevel@tonic-gate 		r = get_fmri(d->fmri, &sp, &ip);
823*7c478bd9Sstevel@tonic-gate 		switch (r) {
824*7c478bd9Sstevel@tonic-gate 		case 0:
825*7c478bd9Sstevel@tonic-gate 			break;
826*7c478bd9Sstevel@tonic-gate 
827*7c478bd9Sstevel@tonic-gate 		case EINVAL:
828*7c478bd9Sstevel@tonic-gate 			/* LINTED */
829*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, emsg_invalid_dep, svcp->svcname,
830*7c478bd9Sstevel@tonic-gate 			    svcp->instname, d->fmri);
831*7c478bd9Sstevel@tonic-gate 			continue;
832*7c478bd9Sstevel@tonic-gate 
833*7c478bd9Sstevel@tonic-gate 		case ENOENT:
834*7c478bd9Sstevel@tonic-gate 			continue;
835*7c478bd9Sstevel@tonic-gate 
836*7c478bd9Sstevel@tonic-gate 		default:
837*7c478bd9Sstevel@tonic-gate 			bad_error("eval_svc_dep", r);
838*7c478bd9Sstevel@tonic-gate 		}
839*7c478bd9Sstevel@tonic-gate 
840*7c478bd9Sstevel@tonic-gate 		if (ip != NULL) {
841*7c478bd9Sstevel@tonic-gate 			if (inst_running(ip))
842*7c478bd9Sstevel@tonic-gate 				return (0);
843*7c478bd9Sstevel@tonic-gate 			continue;
844*7c478bd9Sstevel@tonic-gate 		}
845*7c478bd9Sstevel@tonic-gate 
846*7c478bd9Sstevel@tonic-gate 		for (ip = uu_list_first(sp->instances);
847*7c478bd9Sstevel@tonic-gate 		    ip != NULL;
848*7c478bd9Sstevel@tonic-gate 		    ip = uu_list_next(sp->instances, ip)) {
849*7c478bd9Sstevel@tonic-gate 			if (inst_running(ip))
850*7c478bd9Sstevel@tonic-gate 				return (0);
851*7c478bd9Sstevel@tonic-gate 		}
852*7c478bd9Sstevel@tonic-gate 	}
853*7c478bd9Sstevel@tonic-gate 
854*7c478bd9Sstevel@tonic-gate 	/*
855*7c478bd9Sstevel@tonic-gate 	 * The dependency group is not satisfied.  Add all unsatisfied members
856*7c478bd9Sstevel@tonic-gate 	 * to the cause list.
857*7c478bd9Sstevel@tonic-gate 	 */
858*7c478bd9Sstevel@tonic-gate 
859*7c478bd9Sstevel@tonic-gate 	walk = uu_list_walk_start(dg->entities, UU_WALK_ROBUST);
860*7c478bd9Sstevel@tonic-gate 	if (walk == NULL)
861*7c478bd9Sstevel@tonic-gate 		uu_die(emsg_nomem);
862*7c478bd9Sstevel@tonic-gate 
863*7c478bd9Sstevel@tonic-gate 	while ((d = uu_list_walk_next(walk)) != NULL) {
864*7c478bd9Sstevel@tonic-gate 		r = get_fmri(d->fmri, &sp, &ip);
865*7c478bd9Sstevel@tonic-gate 		switch (r) {
866*7c478bd9Sstevel@tonic-gate 		case 0:
867*7c478bd9Sstevel@tonic-gate 			break;
868*7c478bd9Sstevel@tonic-gate 
869*7c478bd9Sstevel@tonic-gate 		case ENOENT:
870*7c478bd9Sstevel@tonic-gate 			uu_list_remove(dg->entities, d);
871*7c478bd9Sstevel@tonic-gate 			r = uu_list_append(svcp->baddeps, d);
872*7c478bd9Sstevel@tonic-gate 			assert(r == 0);
873*7c478bd9Sstevel@tonic-gate 			continue;
874*7c478bd9Sstevel@tonic-gate 
875*7c478bd9Sstevel@tonic-gate 		case EINVAL:
876*7c478bd9Sstevel@tonic-gate 			/* Should have caught above. */
877*7c478bd9Sstevel@tonic-gate 		default:
878*7c478bd9Sstevel@tonic-gate 			bad_error("eval_svc_dep", r);
879*7c478bd9Sstevel@tonic-gate 		}
880*7c478bd9Sstevel@tonic-gate 
881*7c478bd9Sstevel@tonic-gate 		if (ip != NULL) {
882*7c478bd9Sstevel@tonic-gate 			if (inst_running(ip))
883*7c478bd9Sstevel@tonic-gate 				continue;
884*7c478bd9Sstevel@tonic-gate 			r = add_causes(svcp, ip);
885*7c478bd9Sstevel@tonic-gate 			if (r != 0) {
886*7c478bd9Sstevel@tonic-gate 				assert(r == ELOOP);
887*7c478bd9Sstevel@tonic-gate 				return (r);
888*7c478bd9Sstevel@tonic-gate 			}
889*7c478bd9Sstevel@tonic-gate 			continue;
890*7c478bd9Sstevel@tonic-gate 		}
891*7c478bd9Sstevel@tonic-gate 
892*7c478bd9Sstevel@tonic-gate 		for (ip = uu_list_first(sp->instances);
893*7c478bd9Sstevel@tonic-gate 		    ip != NULL;
894*7c478bd9Sstevel@tonic-gate 		    ip = uu_list_next(sp->instances, ip)) {
895*7c478bd9Sstevel@tonic-gate 			if (inst_running(ip))
896*7c478bd9Sstevel@tonic-gate 				continue;
897*7c478bd9Sstevel@tonic-gate 			r = add_causes(svcp, ip);
898*7c478bd9Sstevel@tonic-gate 			if (r != 0) {
899*7c478bd9Sstevel@tonic-gate 				assert(r == ELOOP);
900*7c478bd9Sstevel@tonic-gate 				return (r);
901*7c478bd9Sstevel@tonic-gate 			}
902*7c478bd9Sstevel@tonic-gate 		}
903*7c478bd9Sstevel@tonic-gate 	}
904*7c478bd9Sstevel@tonic-gate 
905*7c478bd9Sstevel@tonic-gate 	return (0);
906*7c478bd9Sstevel@tonic-gate }
907*7c478bd9Sstevel@tonic-gate 
908*7c478bd9Sstevel@tonic-gate static int
909*7c478bd9Sstevel@tonic-gate process_optall(inst_t *svcp, struct dependency_group *dg)
910*7c478bd9Sstevel@tonic-gate {
911*7c478bd9Sstevel@tonic-gate 	uu_list_walk_t *walk;
912*7c478bd9Sstevel@tonic-gate 	struct dependency *d;
913*7c478bd9Sstevel@tonic-gate 	int r;
914*7c478bd9Sstevel@tonic-gate 	inst_t *ip;
915*7c478bd9Sstevel@tonic-gate 	svc_t *sp;
916*7c478bd9Sstevel@tonic-gate 
917*7c478bd9Sstevel@tonic-gate 	walk = uu_list_walk_start(dg->entities, UU_WALK_ROBUST);
918*7c478bd9Sstevel@tonic-gate 	if (walk == NULL)
919*7c478bd9Sstevel@tonic-gate 		uu_die(emsg_nomem);
920*7c478bd9Sstevel@tonic-gate 
921*7c478bd9Sstevel@tonic-gate 	while ((d = uu_list_walk_next(walk)) != NULL) {
922*7c478bd9Sstevel@tonic-gate 		r = get_fmri(d->fmri, &sp, &ip);
923*7c478bd9Sstevel@tonic-gate 
924*7c478bd9Sstevel@tonic-gate 		switch (r) {
925*7c478bd9Sstevel@tonic-gate 		case 0:
926*7c478bd9Sstevel@tonic-gate 			break;
927*7c478bd9Sstevel@tonic-gate 
928*7c478bd9Sstevel@tonic-gate 		case EINVAL:
929*7c478bd9Sstevel@tonic-gate 			/* LINTED */
930*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, emsg_invalid_dep, svcp->svcname,
931*7c478bd9Sstevel@tonic-gate 			    svcp->instname, d->fmri);
932*7c478bd9Sstevel@tonic-gate 			continue;
933*7c478bd9Sstevel@tonic-gate 
934*7c478bd9Sstevel@tonic-gate 		case ENOENT:
935*7c478bd9Sstevel@tonic-gate 			continue;
936*7c478bd9Sstevel@tonic-gate 
937*7c478bd9Sstevel@tonic-gate 		default:
938*7c478bd9Sstevel@tonic-gate 			bad_error("get_fmri", r);
939*7c478bd9Sstevel@tonic-gate 		}
940*7c478bd9Sstevel@tonic-gate 
941*7c478bd9Sstevel@tonic-gate 		if (ip != NULL) {
942*7c478bd9Sstevel@tonic-gate 			if (ip->enabled && !inst_running_or_maint(ip)) {
943*7c478bd9Sstevel@tonic-gate 				r = add_causes(svcp, ip);
944*7c478bd9Sstevel@tonic-gate 				if (r != 0) {
945*7c478bd9Sstevel@tonic-gate 					assert(r == ELOOP);
946*7c478bd9Sstevel@tonic-gate 					uu_list_walk_end(walk);
947*7c478bd9Sstevel@tonic-gate 					return (r);
948*7c478bd9Sstevel@tonic-gate 				}
949*7c478bd9Sstevel@tonic-gate 			}
950*7c478bd9Sstevel@tonic-gate 			continue;
951*7c478bd9Sstevel@tonic-gate 		}
952*7c478bd9Sstevel@tonic-gate 
953*7c478bd9Sstevel@tonic-gate 		for (ip = uu_list_first(sp->instances);
954*7c478bd9Sstevel@tonic-gate 		    ip != NULL;
955*7c478bd9Sstevel@tonic-gate 		    ip = uu_list_next(sp->instances, ip)) {
956*7c478bd9Sstevel@tonic-gate 			if (ip->enabled && !inst_running_or_maint(ip)) {
957*7c478bd9Sstevel@tonic-gate 				r = add_causes(svcp, ip);
958*7c478bd9Sstevel@tonic-gate 				if (r != 0) {
959*7c478bd9Sstevel@tonic-gate 					assert(r == ELOOP);
960*7c478bd9Sstevel@tonic-gate 					uu_list_walk_end(walk);
961*7c478bd9Sstevel@tonic-gate 					return (r);
962*7c478bd9Sstevel@tonic-gate 				}
963*7c478bd9Sstevel@tonic-gate 			}
964*7c478bd9Sstevel@tonic-gate 		}
965*7c478bd9Sstevel@tonic-gate 	}
966*7c478bd9Sstevel@tonic-gate 
967*7c478bd9Sstevel@tonic-gate 	uu_list_walk_end(walk);
968*7c478bd9Sstevel@tonic-gate 	return (0);
969*7c478bd9Sstevel@tonic-gate }
970*7c478bd9Sstevel@tonic-gate 
971*7c478bd9Sstevel@tonic-gate static int
972*7c478bd9Sstevel@tonic-gate process_excall(inst_t *svcp, struct dependency_group *dg)
973*7c478bd9Sstevel@tonic-gate {
974*7c478bd9Sstevel@tonic-gate 	struct dependency *d;
975*7c478bd9Sstevel@tonic-gate 	int r;
976*7c478bd9Sstevel@tonic-gate 	svc_t *sp;
977*7c478bd9Sstevel@tonic-gate 	inst_t *ip;
978*7c478bd9Sstevel@tonic-gate 
979*7c478bd9Sstevel@tonic-gate 	for (d = uu_list_first(dg->entities);
980*7c478bd9Sstevel@tonic-gate 	    d != NULL;
981*7c478bd9Sstevel@tonic-gate 	    d = uu_list_next(dg->entities, d)) {
982*7c478bd9Sstevel@tonic-gate 		r = get_fmri(d->fmri, &sp, &ip);
983*7c478bd9Sstevel@tonic-gate 
984*7c478bd9Sstevel@tonic-gate 		switch (r) {
985*7c478bd9Sstevel@tonic-gate 		case 0:
986*7c478bd9Sstevel@tonic-gate 			break;
987*7c478bd9Sstevel@tonic-gate 
988*7c478bd9Sstevel@tonic-gate 		case EINVAL:
989*7c478bd9Sstevel@tonic-gate 			/* LINTED */
990*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, emsg_invalid_dep, svcp->svcname,
991*7c478bd9Sstevel@tonic-gate 			    svcp->instname, d->fmri);
992*7c478bd9Sstevel@tonic-gate 			continue;
993*7c478bd9Sstevel@tonic-gate 
994*7c478bd9Sstevel@tonic-gate 		case ENOENT:
995*7c478bd9Sstevel@tonic-gate 			continue;
996*7c478bd9Sstevel@tonic-gate 
997*7c478bd9Sstevel@tonic-gate 		default:
998*7c478bd9Sstevel@tonic-gate 			bad_error("eval_svc_dep", r);
999*7c478bd9Sstevel@tonic-gate 		}
1000*7c478bd9Sstevel@tonic-gate 
1001*7c478bd9Sstevel@tonic-gate 		if (ip != NULL) {
1002*7c478bd9Sstevel@tonic-gate 			if (inst_running(ip)) {
1003*7c478bd9Sstevel@tonic-gate 				r = add_causes(svcp, ip);
1004*7c478bd9Sstevel@tonic-gate 				if (r != 0) {
1005*7c478bd9Sstevel@tonic-gate 					assert(r == ELOOP);
1006*7c478bd9Sstevel@tonic-gate 					return (r);
1007*7c478bd9Sstevel@tonic-gate 				}
1008*7c478bd9Sstevel@tonic-gate 			}
1009*7c478bd9Sstevel@tonic-gate 			continue;
1010*7c478bd9Sstevel@tonic-gate 		}
1011*7c478bd9Sstevel@tonic-gate 
1012*7c478bd9Sstevel@tonic-gate 		for (ip = uu_list_first(sp->instances);
1013*7c478bd9Sstevel@tonic-gate 		    ip != NULL;
1014*7c478bd9Sstevel@tonic-gate 		    ip = uu_list_next(sp->instances, ip)) {
1015*7c478bd9Sstevel@tonic-gate 			if (inst_running(ip)) {
1016*7c478bd9Sstevel@tonic-gate 				r = add_causes(svcp, ip);
1017*7c478bd9Sstevel@tonic-gate 				if (r != 0) {
1018*7c478bd9Sstevel@tonic-gate 					assert(r == ELOOP);
1019*7c478bd9Sstevel@tonic-gate 					return (r);
1020*7c478bd9Sstevel@tonic-gate 				}
1021*7c478bd9Sstevel@tonic-gate 			}
1022*7c478bd9Sstevel@tonic-gate 		}
1023*7c478bd9Sstevel@tonic-gate 	}
1024*7c478bd9Sstevel@tonic-gate 
1025*7c478bd9Sstevel@tonic-gate 	return (0);
1026*7c478bd9Sstevel@tonic-gate }
1027*7c478bd9Sstevel@tonic-gate 
1028*7c478bd9Sstevel@tonic-gate static int
1029*7c478bd9Sstevel@tonic-gate process_svc_dg(inst_t *svcp, struct dependency_group *dg)
1030*7c478bd9Sstevel@tonic-gate {
1031*7c478bd9Sstevel@tonic-gate 	switch (dg->grouping) {
1032*7c478bd9Sstevel@tonic-gate 	case DGG_REQALL:
1033*7c478bd9Sstevel@tonic-gate 		return (process_reqall(svcp, dg));
1034*7c478bd9Sstevel@tonic-gate 
1035*7c478bd9Sstevel@tonic-gate 	case DGG_REQANY:
1036*7c478bd9Sstevel@tonic-gate 		return (process_reqany(svcp, dg));
1037*7c478bd9Sstevel@tonic-gate 
1038*7c478bd9Sstevel@tonic-gate 	case DGG_OPTALL:
1039*7c478bd9Sstevel@tonic-gate 		return (process_optall(svcp, dg));
1040*7c478bd9Sstevel@tonic-gate 
1041*7c478bd9Sstevel@tonic-gate 	case DGG_EXCALL:
1042*7c478bd9Sstevel@tonic-gate 		return (process_excall(svcp, dg));
1043*7c478bd9Sstevel@tonic-gate 
1044*7c478bd9Sstevel@tonic-gate 	default:
1045*7c478bd9Sstevel@tonic-gate #ifndef NDEBUG
1046*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
1047*7c478bd9Sstevel@tonic-gate 		    "%s:%d: Unknown dependency grouping %d.\n", __FILE__,
1048*7c478bd9Sstevel@tonic-gate 		    __LINE__, dg->grouping);
1049*7c478bd9Sstevel@tonic-gate #endif
1050*7c478bd9Sstevel@tonic-gate 		abort();
1051*7c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
1052*7c478bd9Sstevel@tonic-gate 	}
1053*7c478bd9Sstevel@tonic-gate }
1054*7c478bd9Sstevel@tonic-gate 
1055*7c478bd9Sstevel@tonic-gate /*
1056*7c478bd9Sstevel@tonic-gate  * Returns
1057*7c478bd9Sstevel@tonic-gate  *   EINVAL - fmri is not a valid FMRI
1058*7c478bd9Sstevel@tonic-gate  *   0 - the file indicated by fmri is missing
1059*7c478bd9Sstevel@tonic-gate  *   1 - the file indicated by fmri is present
1060*7c478bd9Sstevel@tonic-gate  */
1061*7c478bd9Sstevel@tonic-gate static int
1062*7c478bd9Sstevel@tonic-gate eval_file_dep(const char *fmri)
1063*7c478bd9Sstevel@tonic-gate {
1064*7c478bd9Sstevel@tonic-gate 	const char *path;
1065*7c478bd9Sstevel@tonic-gate 	struct stat st;
1066*7c478bd9Sstevel@tonic-gate 
1067*7c478bd9Sstevel@tonic-gate 	if (strncmp(fmri, "file:", sizeof ("file:") - 1) != 0)
1068*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
1069*7c478bd9Sstevel@tonic-gate 
1070*7c478bd9Sstevel@tonic-gate 	path = fmri + (sizeof ("file:") - 1);
1071*7c478bd9Sstevel@tonic-gate 
1072*7c478bd9Sstevel@tonic-gate 	if (path[0] != '/')
1073*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
1074*7c478bd9Sstevel@tonic-gate 
1075*7c478bd9Sstevel@tonic-gate 	if (path[1] == '/') {
1076*7c478bd9Sstevel@tonic-gate 		path += 2;
1077*7c478bd9Sstevel@tonic-gate 		if (strncmp(path, "localhost/", sizeof ("localhost/") - 1) == 0)
1078*7c478bd9Sstevel@tonic-gate 			path += sizeof ("localhost") - 1;
1079*7c478bd9Sstevel@tonic-gate 		else if (path[0] != '/')
1080*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
1081*7c478bd9Sstevel@tonic-gate 	}
1082*7c478bd9Sstevel@tonic-gate 
1083*7c478bd9Sstevel@tonic-gate 	return (stat(path, &st) == 0 ? 1 : 0);
1084*7c478bd9Sstevel@tonic-gate }
1085*7c478bd9Sstevel@tonic-gate 
1086*7c478bd9Sstevel@tonic-gate static void
1087*7c478bd9Sstevel@tonic-gate process_file_dg(inst_t *svcp, struct dependency_group *dg)
1088*7c478bd9Sstevel@tonic-gate {
1089*7c478bd9Sstevel@tonic-gate 	uu_list_walk_t *walk;
1090*7c478bd9Sstevel@tonic-gate 	struct dependency *d, **deps;
1091*7c478bd9Sstevel@tonic-gate 	int r, i = 0, any_satisfied = 0;
1092*7c478bd9Sstevel@tonic-gate 
1093*7c478bd9Sstevel@tonic-gate 	if (dg->grouping == DGG_REQANY) {
1094*7c478bd9Sstevel@tonic-gate 		deps = calloc(uu_list_numnodes(dg->entities), sizeof (*deps));
1095*7c478bd9Sstevel@tonic-gate 		if (deps == NULL)
1096*7c478bd9Sstevel@tonic-gate 			uu_die(emsg_nomem);
1097*7c478bd9Sstevel@tonic-gate 	}
1098*7c478bd9Sstevel@tonic-gate 
1099*7c478bd9Sstevel@tonic-gate 	walk = uu_list_walk_start(dg->entities, UU_WALK_ROBUST);
1100*7c478bd9Sstevel@tonic-gate 	if (walk == NULL)
1101*7c478bd9Sstevel@tonic-gate 		uu_die(emsg_nomem);
1102*7c478bd9Sstevel@tonic-gate 
1103*7c478bd9Sstevel@tonic-gate 	while ((d = uu_list_walk_next(walk)) != NULL) {
1104*7c478bd9Sstevel@tonic-gate 		r = eval_file_dep(d->fmri);
1105*7c478bd9Sstevel@tonic-gate 		if (r == EINVAL) {
1106*7c478bd9Sstevel@tonic-gate 			/* LINTED */
1107*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, emsg_invalid_dep, svcp->svcname,
1108*7c478bd9Sstevel@tonic-gate 			    svcp->instname, d->fmri);
1109*7c478bd9Sstevel@tonic-gate 			continue;
1110*7c478bd9Sstevel@tonic-gate 		}
1111*7c478bd9Sstevel@tonic-gate 
1112*7c478bd9Sstevel@tonic-gate 		assert(r == 0 || r == 1);
1113*7c478bd9Sstevel@tonic-gate 
1114*7c478bd9Sstevel@tonic-gate 		switch (dg->grouping) {
1115*7c478bd9Sstevel@tonic-gate 		case DGG_REQALL:
1116*7c478bd9Sstevel@tonic-gate 		case DGG_OPTALL:
1117*7c478bd9Sstevel@tonic-gate 			if (r == 0) {
1118*7c478bd9Sstevel@tonic-gate 				uu_list_remove(dg->entities, d);
1119*7c478bd9Sstevel@tonic-gate 				r = uu_list_append(svcp->baddeps, d);
1120*7c478bd9Sstevel@tonic-gate 				assert(r == 0);
1121*7c478bd9Sstevel@tonic-gate 			}
1122*7c478bd9Sstevel@tonic-gate 			break;
1123*7c478bd9Sstevel@tonic-gate 
1124*7c478bd9Sstevel@tonic-gate 		case DGG_REQANY:
1125*7c478bd9Sstevel@tonic-gate 			if (r == 1)
1126*7c478bd9Sstevel@tonic-gate 				any_satisfied = 1;
1127*7c478bd9Sstevel@tonic-gate 			else
1128*7c478bd9Sstevel@tonic-gate 				deps[i++] = d;
1129*7c478bd9Sstevel@tonic-gate 			break;
1130*7c478bd9Sstevel@tonic-gate 
1131*7c478bd9Sstevel@tonic-gate 		case DGG_EXCALL:
1132*7c478bd9Sstevel@tonic-gate 			if (r == 1) {
1133*7c478bd9Sstevel@tonic-gate 				uu_list_remove(dg->entities, d);
1134*7c478bd9Sstevel@tonic-gate 				r = uu_list_append(svcp->baddeps, d);
1135*7c478bd9Sstevel@tonic-gate 				assert(r == 0);
1136*7c478bd9Sstevel@tonic-gate 			}
1137*7c478bd9Sstevel@tonic-gate 			break;
1138*7c478bd9Sstevel@tonic-gate 
1139*7c478bd9Sstevel@tonic-gate 		default:
1140*7c478bd9Sstevel@tonic-gate #ifndef NDEBUG
1141*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s:%d: Unknown grouping %d.\n",
1142*7c478bd9Sstevel@tonic-gate 			    __FILE__, __LINE__, dg->grouping);
1143*7c478bd9Sstevel@tonic-gate #endif
1144*7c478bd9Sstevel@tonic-gate 			abort();
1145*7c478bd9Sstevel@tonic-gate 		}
1146*7c478bd9Sstevel@tonic-gate 	}
1147*7c478bd9Sstevel@tonic-gate 
1148*7c478bd9Sstevel@tonic-gate 	uu_list_walk_end(walk);
1149*7c478bd9Sstevel@tonic-gate 
1150*7c478bd9Sstevel@tonic-gate 	if (dg->grouping != DGG_REQANY)
1151*7c478bd9Sstevel@tonic-gate 		return;
1152*7c478bd9Sstevel@tonic-gate 
1153*7c478bd9Sstevel@tonic-gate 	if (!any_satisfied) {
1154*7c478bd9Sstevel@tonic-gate 		for (; i >= 0; --i) {
1155*7c478bd9Sstevel@tonic-gate 			uu_list_remove(dg->entities, deps[i]);
1156*7c478bd9Sstevel@tonic-gate 			r = uu_list_append(svcp->baddeps, deps[i]);
1157*7c478bd9Sstevel@tonic-gate 			assert(r == 0);
1158*7c478bd9Sstevel@tonic-gate 		}
1159*7c478bd9Sstevel@tonic-gate 	}
1160*7c478bd9Sstevel@tonic-gate 
1161*7c478bd9Sstevel@tonic-gate 	free(deps);
1162*7c478bd9Sstevel@tonic-gate }
1163*7c478bd9Sstevel@tonic-gate 
1164*7c478bd9Sstevel@tonic-gate /*
1165*7c478bd9Sstevel@tonic-gate  * Populate the causes list of svcp.  This function should not return with
1166*7c478bd9Sstevel@tonic-gate  * causes empty.
1167*7c478bd9Sstevel@tonic-gate  */
1168*7c478bd9Sstevel@tonic-gate static int
1169*7c478bd9Sstevel@tonic-gate determine_causes(inst_t *svcp, void *canfailp)
1170*7c478bd9Sstevel@tonic-gate {
1171*7c478bd9Sstevel@tonic-gate 	struct dependency_group *dg;
1172*7c478bd9Sstevel@tonic-gate 	int r;
1173*7c478bd9Sstevel@tonic-gate 
1174*7c478bd9Sstevel@tonic-gate 	if (svcp->active) {
1175*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Dependency cycle detected:\n"
1176*7c478bd9Sstevel@tonic-gate 		    "  svc:/%s:%s\n"), svcp->svcname, svcp->instname);
1177*7c478bd9Sstevel@tonic-gate 		return ((int)canfailp != 0 ? UU_WALK_ERROR : UU_WALK_NEXT);
1178*7c478bd9Sstevel@tonic-gate 	}
1179*7c478bd9Sstevel@tonic-gate 
1180*7c478bd9Sstevel@tonic-gate 	if (svcp->causes != NULL)
1181*7c478bd9Sstevel@tonic-gate 		return (UU_WALK_NEXT);
1182*7c478bd9Sstevel@tonic-gate 
1183*7c478bd9Sstevel@tonic-gate 	svcp->causes = uu_list_create(svcptrs, svcp, UU_LIST_DEBUG);
1184*7c478bd9Sstevel@tonic-gate 	svcp->baddeps = uu_list_create(deps, svcp, UU_LIST_DEBUG);
1185*7c478bd9Sstevel@tonic-gate 	if (svcp->causes == NULL || svcp->baddeps == NULL)
1186*7c478bd9Sstevel@tonic-gate 		uu_die(emsg_nomem);
1187*7c478bd9Sstevel@tonic-gate 
1188*7c478bd9Sstevel@tonic-gate 	if (inst_running(svcp) ||
1189*7c478bd9Sstevel@tonic-gate 	    strcmp(svcp->state, SCF_STATE_STRING_UNINIT) == 0) {
1190*7c478bd9Sstevel@tonic-gate 		/*
1191*7c478bd9Sstevel@tonic-gate 		 * If we're running, add a self-pointer in case we're
1192*7c478bd9Sstevel@tonic-gate 		 * excluding another service.
1193*7c478bd9Sstevel@tonic-gate 		 */
1194*7c478bd9Sstevel@tonic-gate 		add_svcptr(svcp->causes, svcp);
1195*7c478bd9Sstevel@tonic-gate 		return (UU_WALK_NEXT);
1196*7c478bd9Sstevel@tonic-gate 	}
1197*7c478bd9Sstevel@tonic-gate 
1198*7c478bd9Sstevel@tonic-gate 	if (strcmp(svcp->state, SCF_STATE_STRING_MAINT) == 0) {
1199*7c478bd9Sstevel@tonic-gate 		add_svcptr(svcp->causes, svcp);
1200*7c478bd9Sstevel@tonic-gate 		add_svcptr(g_causes, svcp);
1201*7c478bd9Sstevel@tonic-gate 		return (UU_WALK_NEXT);
1202*7c478bd9Sstevel@tonic-gate 	}
1203*7c478bd9Sstevel@tonic-gate 
1204*7c478bd9Sstevel@tonic-gate 	if (strcmp(svcp->state, SCF_STATE_STRING_DISABLED) == 0) {
1205*7c478bd9Sstevel@tonic-gate 		add_svcptr(svcp->causes, svcp);
1206*7c478bd9Sstevel@tonic-gate 		if (svcp->enabled)
1207*7c478bd9Sstevel@tonic-gate 			add_svcptr(g_causes, svcp);
1208*7c478bd9Sstevel@tonic-gate 
1209*7c478bd9Sstevel@tonic-gate 		return (UU_WALK_NEXT);
1210*7c478bd9Sstevel@tonic-gate 	}
1211*7c478bd9Sstevel@tonic-gate 
1212*7c478bd9Sstevel@tonic-gate 	if (strcmp(svcp->state, SCF_STATE_STRING_OFFLINE) != 0) {
1213*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
1214*7c478bd9Sstevel@tonic-gate 		    gettext("svc:/%s:%s has invalid state \"%s\".\n"),
1215*7c478bd9Sstevel@tonic-gate 		    svcp->svcname, svcp->instname, svcp->state);
1216*7c478bd9Sstevel@tonic-gate 		add_svcptr(svcp->causes, svcp);
1217*7c478bd9Sstevel@tonic-gate 		add_svcptr(g_causes, svcp);
1218*7c478bd9Sstevel@tonic-gate 		return (UU_WALK_NEXT);
1219*7c478bd9Sstevel@tonic-gate 	}
1220*7c478bd9Sstevel@tonic-gate 
1221*7c478bd9Sstevel@tonic-gate 	if (strcmp(svcp->next_state, SCF_STATE_STRING_NONE) != 0) {
1222*7c478bd9Sstevel@tonic-gate 		add_svcptr(svcp->causes, svcp);
1223*7c478bd9Sstevel@tonic-gate 		add_svcptr(g_causes, svcp);
1224*7c478bd9Sstevel@tonic-gate 		return (UU_WALK_NEXT);
1225*7c478bd9Sstevel@tonic-gate 	}
1226*7c478bd9Sstevel@tonic-gate 
1227*7c478bd9Sstevel@tonic-gate 	svcp->active = 1;
1228*7c478bd9Sstevel@tonic-gate 
1229*7c478bd9Sstevel@tonic-gate 	/*
1230*7c478bd9Sstevel@tonic-gate 	 * Dependency analysis can add elements to our baddeps list (absent
1231*7c478bd9Sstevel@tonic-gate 	 * dependency, unsatisfied file dependency), or to our cause list
1232*7c478bd9Sstevel@tonic-gate 	 * (unsatisfied dependency).
1233*7c478bd9Sstevel@tonic-gate 	 */
1234*7c478bd9Sstevel@tonic-gate 	for (dg = uu_list_first(svcp->dependencies);
1235*7c478bd9Sstevel@tonic-gate 	    dg != NULL;
1236*7c478bd9Sstevel@tonic-gate 	    dg = uu_list_next(svcp->dependencies, dg)) {
1237*7c478bd9Sstevel@tonic-gate 		if (strcmp(dg->type, "path") == 0) {
1238*7c478bd9Sstevel@tonic-gate 			process_file_dg(svcp, dg);
1239*7c478bd9Sstevel@tonic-gate 		} else if (strcmp(dg->type, "service") == 0) {
1240*7c478bd9Sstevel@tonic-gate 			int r;
1241*7c478bd9Sstevel@tonic-gate 
1242*7c478bd9Sstevel@tonic-gate 			r = process_svc_dg(svcp, dg);
1243*7c478bd9Sstevel@tonic-gate 			if (r != 0) {
1244*7c478bd9Sstevel@tonic-gate 				assert(r == ELOOP);
1245*7c478bd9Sstevel@tonic-gate 				svcp->active = 0;
1246*7c478bd9Sstevel@tonic-gate 				return ((int)canfailp != 0 ?
1247*7c478bd9Sstevel@tonic-gate 				    UU_WALK_ERROR : UU_WALK_NEXT);
1248*7c478bd9Sstevel@tonic-gate 			}
1249*7c478bd9Sstevel@tonic-gate 		} else {
1250*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("svc:/%s:%s has "
1251*7c478bd9Sstevel@tonic-gate 			    "dependency group with invalid type \"%s\".\n"),
1252*7c478bd9Sstevel@tonic-gate 			    svcp->svcname, svcp->instname, dg->type);
1253*7c478bd9Sstevel@tonic-gate 		}
1254*7c478bd9Sstevel@tonic-gate 	}
1255*7c478bd9Sstevel@tonic-gate 
1256*7c478bd9Sstevel@tonic-gate 	if (uu_list_numnodes(svcp->causes) == 0) {
1257*7c478bd9Sstevel@tonic-gate 		if (uu_list_numnodes(svcp->baddeps) > 0) {
1258*7c478bd9Sstevel@tonic-gate 			add_svcptr(g_causes, svcp);
1259*7c478bd9Sstevel@tonic-gate 			add_svcptr(svcp->causes, svcp);
1260*7c478bd9Sstevel@tonic-gate 		} else {
1261*7c478bd9Sstevel@tonic-gate 			inst_t *restarter;
1262*7c478bd9Sstevel@tonic-gate 
1263*7c478bd9Sstevel@tonic-gate 			r = get_fmri(svcp->restarter, NULL, &restarter);
1264*7c478bd9Sstevel@tonic-gate 			if (r == 0 && !inst_running(restarter)) {
1265*7c478bd9Sstevel@tonic-gate 				r = add_causes(svcp, restarter);
1266*7c478bd9Sstevel@tonic-gate 				if (r != 0) {
1267*7c478bd9Sstevel@tonic-gate 					assert(r == ELOOP);
1268*7c478bd9Sstevel@tonic-gate 					svcp->active = 0;
1269*7c478bd9Sstevel@tonic-gate 					return ((int)canfailp != 0 ?
1270*7c478bd9Sstevel@tonic-gate 					    UU_WALK_ERROR : UU_WALK_NEXT);
1271*7c478bd9Sstevel@tonic-gate 				}
1272*7c478bd9Sstevel@tonic-gate 			} else {
1273*7c478bd9Sstevel@tonic-gate 				svcp->restarter_bad = r;
1274*7c478bd9Sstevel@tonic-gate 				add_svcptr(svcp->causes, svcp);
1275*7c478bd9Sstevel@tonic-gate 				add_svcptr(g_causes, svcp);
1276*7c478bd9Sstevel@tonic-gate 			}
1277*7c478bd9Sstevel@tonic-gate 		}
1278*7c478bd9Sstevel@tonic-gate 	}
1279*7c478bd9Sstevel@tonic-gate 
1280*7c478bd9Sstevel@tonic-gate 	assert(uu_list_numnodes(svcp->causes) > 0);
1281*7c478bd9Sstevel@tonic-gate 
1282*7c478bd9Sstevel@tonic-gate 	svcp->active = 0;
1283*7c478bd9Sstevel@tonic-gate 	return (UU_WALK_NEXT);
1284*7c478bd9Sstevel@tonic-gate }
1285*7c478bd9Sstevel@tonic-gate 
1286*7c478bd9Sstevel@tonic-gate static void
1287*7c478bd9Sstevel@tonic-gate determine_all_causes(void)
1288*7c478bd9Sstevel@tonic-gate {
1289*7c478bd9Sstevel@tonic-gate 	svc_t *svcp;
1290*7c478bd9Sstevel@tonic-gate 	int i;
1291*7c478bd9Sstevel@tonic-gate 
1292*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < SVC_HASH_NBUCKETS; ++i) {
1293*7c478bd9Sstevel@tonic-gate 		for (svcp = services[i]; svcp != NULL; svcp = svcp->next)
1294*7c478bd9Sstevel@tonic-gate 			(void) uu_list_walk(svcp->instances,
1295*7c478bd9Sstevel@tonic-gate 			    (uu_walk_fn_t *)determine_causes, 0, 0);
1296*7c478bd9Sstevel@tonic-gate 	}
1297*7c478bd9Sstevel@tonic-gate }
1298*7c478bd9Sstevel@tonic-gate 
1299*7c478bd9Sstevel@tonic-gate /*
1300*7c478bd9Sstevel@tonic-gate  * Returns
1301*7c478bd9Sstevel@tonic-gate  *   0 - success
1302*7c478bd9Sstevel@tonic-gate  *   ELOOP - dependency cycle detected
1303*7c478bd9Sstevel@tonic-gate  */
1304*7c478bd9Sstevel@tonic-gate static int
1305*7c478bd9Sstevel@tonic-gate determine_impact(inst_t *ip)
1306*7c478bd9Sstevel@tonic-gate {
1307*7c478bd9Sstevel@tonic-gate 	struct svcptr *idsp, *spp, *copy;
1308*7c478bd9Sstevel@tonic-gate 	uu_list_index_t idx;
1309*7c478bd9Sstevel@tonic-gate 
1310*7c478bd9Sstevel@tonic-gate 	if (ip->active) {
1311*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Dependency cycle detected:\n"
1312*7c478bd9Sstevel@tonic-gate 		    "  svc:/%s:%s\n"), ip->svcname, ip->instname);
1313*7c478bd9Sstevel@tonic-gate 		return (ELOOP);
1314*7c478bd9Sstevel@tonic-gate 	}
1315*7c478bd9Sstevel@tonic-gate 
1316*7c478bd9Sstevel@tonic-gate 	if (ip->impact != NULL)
1317*7c478bd9Sstevel@tonic-gate 		return (0);
1318*7c478bd9Sstevel@tonic-gate 
1319*7c478bd9Sstevel@tonic-gate 	ip->impact = uu_list_create(svcptrs, ip, UU_LIST_DEBUG);
1320*7c478bd9Sstevel@tonic-gate 	if (ip->impact == NULL)
1321*7c478bd9Sstevel@tonic-gate 		uu_die(emsg_nomem);
1322*7c478bd9Sstevel@tonic-gate 	ip->active = 1;
1323*7c478bd9Sstevel@tonic-gate 
1324*7c478bd9Sstevel@tonic-gate 	for (idsp = uu_list_first(ip->impact_dependents);
1325*7c478bd9Sstevel@tonic-gate 	    idsp != NULL;
1326*7c478bd9Sstevel@tonic-gate 	    idsp = uu_list_next(ip->impact_dependents, idsp)) {
1327*7c478bd9Sstevel@tonic-gate 		if (determine_impact(idsp->svcp) != 0) {
1328*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "  svc:/%s:%s\n",
1329*7c478bd9Sstevel@tonic-gate 			    ip->svcname, ip->instname);
1330*7c478bd9Sstevel@tonic-gate 			return (ELOOP);
1331*7c478bd9Sstevel@tonic-gate 		}
1332*7c478bd9Sstevel@tonic-gate 
1333*7c478bd9Sstevel@tonic-gate 		add_svcptr(ip->impact, idsp->svcp);
1334*7c478bd9Sstevel@tonic-gate 
1335*7c478bd9Sstevel@tonic-gate 		for (spp = uu_list_first(idsp->svcp->impact);
1336*7c478bd9Sstevel@tonic-gate 		    spp != NULL;
1337*7c478bd9Sstevel@tonic-gate 		    spp = uu_list_next(idsp->svcp->impact, spp)) {
1338*7c478bd9Sstevel@tonic-gate 			if (uu_list_find(ip->impact, spp, NULL, &idx) != NULL)
1339*7c478bd9Sstevel@tonic-gate 				continue;
1340*7c478bd9Sstevel@tonic-gate 
1341*7c478bd9Sstevel@tonic-gate 			copy = safe_malloc(sizeof (*copy));
1342*7c478bd9Sstevel@tonic-gate 			copy->svcp = spp->svcp;
1343*7c478bd9Sstevel@tonic-gate 			copy->next_hop = NULL;
1344*7c478bd9Sstevel@tonic-gate 			uu_list_node_init(copy, &copy->node, svcptrs);
1345*7c478bd9Sstevel@tonic-gate 			uu_list_insert(ip->impact, copy, idx);
1346*7c478bd9Sstevel@tonic-gate 		}
1347*7c478bd9Sstevel@tonic-gate 	}
1348*7c478bd9Sstevel@tonic-gate 
1349*7c478bd9Sstevel@tonic-gate 	ip->active = 0;
1350*7c478bd9Sstevel@tonic-gate 	return (0);
1351*7c478bd9Sstevel@tonic-gate }
1352*7c478bd9Sstevel@tonic-gate 
1353*7c478bd9Sstevel@tonic-gate /*
1354*7c478bd9Sstevel@tonic-gate  * Printing routines.
1355*7c478bd9Sstevel@tonic-gate  */
1356*7c478bd9Sstevel@tonic-gate 
1357*7c478bd9Sstevel@tonic-gate static void
1358*7c478bd9Sstevel@tonic-gate check_msgbase(void)
1359*7c478bd9Sstevel@tonic-gate {
1360*7c478bd9Sstevel@tonic-gate 	if (scf_handle_decode_fmri(h, SCF_SERVICE_STARTD, NULL, NULL, g_inst,
1361*7c478bd9Sstevel@tonic-gate 	    NULL, NULL, SCF_DECODE_FMRI_EXACT) != 0) {
1362*7c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND)
1363*7c478bd9Sstevel@tonic-gate 			scfdie();
1364*7c478bd9Sstevel@tonic-gate 
1365*7c478bd9Sstevel@tonic-gate 		return;
1366*7c478bd9Sstevel@tonic-gate 	}
1367*7c478bd9Sstevel@tonic-gate 
1368*7c478bd9Sstevel@tonic-gate 	if (scf_instance_get_pg_composed(g_inst, NULL, "msg", g_pg) != 0) {
1369*7c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
1370*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
1371*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
1372*7c478bd9Sstevel@tonic-gate 			return;
1373*7c478bd9Sstevel@tonic-gate 
1374*7c478bd9Sstevel@tonic-gate 		default:
1375*7c478bd9Sstevel@tonic-gate 			scfdie();
1376*7c478bd9Sstevel@tonic-gate 		}
1377*7c478bd9Sstevel@tonic-gate 	}
1378*7c478bd9Sstevel@tonic-gate 
1379*7c478bd9Sstevel@tonic-gate 	if (scf_pg_get_property(g_pg, "base", g_prop) != 0) {
1380*7c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
1381*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
1382*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
1383*7c478bd9Sstevel@tonic-gate 			return;
1384*7c478bd9Sstevel@tonic-gate 
1385*7c478bd9Sstevel@tonic-gate 		default:
1386*7c478bd9Sstevel@tonic-gate 			scfdie();
1387*7c478bd9Sstevel@tonic-gate 		}
1388*7c478bd9Sstevel@tonic-gate 	}
1389*7c478bd9Sstevel@tonic-gate 
1390*7c478bd9Sstevel@tonic-gate 	if (scf_property_get_value(g_prop, g_val) != 0) {
1391*7c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
1392*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
1393*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_CONSTRAINT_VIOLATED:
1394*7c478bd9Sstevel@tonic-gate 			g_msgbase = NULL;
1395*7c478bd9Sstevel@tonic-gate 			return;
1396*7c478bd9Sstevel@tonic-gate 
1397*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
1398*7c478bd9Sstevel@tonic-gate 			return;
1399*7c478bd9Sstevel@tonic-gate 
1400*7c478bd9Sstevel@tonic-gate 		default:
1401*7c478bd9Sstevel@tonic-gate 			scfdie();
1402*7c478bd9Sstevel@tonic-gate 		}
1403*7c478bd9Sstevel@tonic-gate 	}
1404*7c478bd9Sstevel@tonic-gate 
1405*7c478bd9Sstevel@tonic-gate 	if (scf_value_get_astring(g_val, g_value, g_value_sz) < 0) {
1406*7c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_TYPE_MISMATCH)
1407*7c478bd9Sstevel@tonic-gate 			scfdie();
1408*7c478bd9Sstevel@tonic-gate 		return;
1409*7c478bd9Sstevel@tonic-gate 	}
1410*7c478bd9Sstevel@tonic-gate 
1411*7c478bd9Sstevel@tonic-gate 	g_msgbase = safe_strdup(g_value);
1412*7c478bd9Sstevel@tonic-gate }
1413*7c478bd9Sstevel@tonic-gate 
1414*7c478bd9Sstevel@tonic-gate static void
1415*7c478bd9Sstevel@tonic-gate determine_summary(inst_t *ip)
1416*7c478bd9Sstevel@tonic-gate {
1417*7c478bd9Sstevel@tonic-gate 	if (ip->summary != NULL)
1418*7c478bd9Sstevel@tonic-gate 		return;
1419*7c478bd9Sstevel@tonic-gate 
1420*7c478bd9Sstevel@tonic-gate 	if (inst_running(ip)) {
1421*7c478bd9Sstevel@tonic-gate 		ip->summary = gettext("is running.");
1422*7c478bd9Sstevel@tonic-gate 		return;
1423*7c478bd9Sstevel@tonic-gate 	}
1424*7c478bd9Sstevel@tonic-gate 
1425*7c478bd9Sstevel@tonic-gate 	if (strcmp(ip->state, SCF_STATE_STRING_UNINIT) == 0) {
1426*7c478bd9Sstevel@tonic-gate 		ip->summary = gettext("is uninitialized.");
1427*7c478bd9Sstevel@tonic-gate 	} else if (strcmp(ip->state, SCF_STATE_STRING_DISABLED) == 0) {
1428*7c478bd9Sstevel@tonic-gate 		if (!ip->temporary)
1429*7c478bd9Sstevel@tonic-gate 			ip->summary = gettext("is disabled.");
1430*7c478bd9Sstevel@tonic-gate 		else
1431*7c478bd9Sstevel@tonic-gate 			ip->summary = gettext("is temporarily disabled.");
1432*7c478bd9Sstevel@tonic-gate 	} else if (strcmp(ip->state, SCF_STATE_STRING_OFFLINE) == 0) {
1433*7c478bd9Sstevel@tonic-gate 		if (uu_list_numnodes(ip->baddeps) != 0)
1434*7c478bd9Sstevel@tonic-gate 			ip->summary = gettext("has missing dependencies.");
1435*7c478bd9Sstevel@tonic-gate 		else if (strcmp(ip->next_state, SCF_STATE_STRING_ONLINE) == 0)
1436*7c478bd9Sstevel@tonic-gate 			ip->summary = gettext("is starting.");
1437*7c478bd9Sstevel@tonic-gate 		else
1438*7c478bd9Sstevel@tonic-gate 			ip->summary = gettext("is offline.");
1439*7c478bd9Sstevel@tonic-gate 	} else if (strcmp(ip->state, SCF_STATE_STRING_MAINT) == 0) {
1440*7c478bd9Sstevel@tonic-gate 		if (strcmp(ip->aux_state, "administrative_request") == 0) {
1441*7c478bd9Sstevel@tonic-gate 			ip->summary = gettext("was taken down for maintenace "
1442*7c478bd9Sstevel@tonic-gate 			    "by an administrator.");
1443*7c478bd9Sstevel@tonic-gate 		} else if (strcmp(ip->aux_state, "dependency_cycle") == 0) {
1444*7c478bd9Sstevel@tonic-gate 			ip->summary = gettext("completed a dependency cycle.");
1445*7c478bd9Sstevel@tonic-gate 		} else if (strcmp(ip->aux_state, "fault_threshold_reached") ==
1446*7c478bd9Sstevel@tonic-gate 		    0) {
1447*7c478bd9Sstevel@tonic-gate 			ip->summary = gettext("is not running because "
1448*7c478bd9Sstevel@tonic-gate 			    "a method failed repeatedly.");
1449*7c478bd9Sstevel@tonic-gate 		} else if (strcmp(ip->aux_state, "invalid_dependency") == 0) {
1450*7c478bd9Sstevel@tonic-gate 			ip->summary = gettext("has an invalid dependency.");
1451*7c478bd9Sstevel@tonic-gate 		} else if (strcmp(ip->aux_state, "invalid_restarter") == 0) {
1452*7c478bd9Sstevel@tonic-gate 			ip->summary = gettext("has an invalid restarter.");
1453*7c478bd9Sstevel@tonic-gate 		} else if (strcmp(ip->aux_state, "method_failed") == 0) {
1454*7c478bd9Sstevel@tonic-gate 			ip->summary = gettext("is not running because "
1455*7c478bd9Sstevel@tonic-gate 			    "a method failed.");
1456*7c478bd9Sstevel@tonic-gate 		} else if (strcmp(ip->aux_state, "none") == 0) {
1457*7c478bd9Sstevel@tonic-gate 			ip->summary =
1458*7c478bd9Sstevel@tonic-gate 			    gettext("is not running for an unknown reason.");
1459*7c478bd9Sstevel@tonic-gate 		} else if (strcmp(ip->aux_state, "restarting_too_quickly") ==
1460*7c478bd9Sstevel@tonic-gate 		    0) {
1461*7c478bd9Sstevel@tonic-gate 			ip->summary = gettext("was restarting too quickly.");
1462*7c478bd9Sstevel@tonic-gate 		} else {
1463*7c478bd9Sstevel@tonic-gate 			ip->summary = gettext("requires maintenance.");
1464*7c478bd9Sstevel@tonic-gate 		}
1465*7c478bd9Sstevel@tonic-gate 	} else {
1466*7c478bd9Sstevel@tonic-gate 		ip->summary = gettext("is in an invalid state.");
1467*7c478bd9Sstevel@tonic-gate 	}
1468*7c478bd9Sstevel@tonic-gate }
1469*7c478bd9Sstevel@tonic-gate 
1470*7c478bd9Sstevel@tonic-gate static void
1471*7c478bd9Sstevel@tonic-gate print_method_failure(const inst_t *ip, const char **dcp)
1472*7c478bd9Sstevel@tonic-gate {
1473*7c478bd9Sstevel@tonic-gate 	char buf[50];
1474*7c478bd9Sstevel@tonic-gate 	int stat = ip->start_method_waitstatus;
1475*7c478bd9Sstevel@tonic-gate 
1476*7c478bd9Sstevel@tonic-gate 	if (stat != 0) {
1477*7c478bd9Sstevel@tonic-gate 		if (WIFEXITED(stat)) {
1478*7c478bd9Sstevel@tonic-gate 			if (WEXITSTATUS(stat) == SMF_EXIT_ERR_CONFIG) {
1479*7c478bd9Sstevel@tonic-gate 				(void) strlcpy(buf, gettext(
1480*7c478bd9Sstevel@tonic-gate 				    "exited with $SMF_EXIT_ERR_CONFIG"),
1481*7c478bd9Sstevel@tonic-gate 				    sizeof (buf));
1482*7c478bd9Sstevel@tonic-gate 			} else if (WEXITSTATUS(stat) == SMF_EXIT_ERR_FATAL) {
1483*7c478bd9Sstevel@tonic-gate 				(void) strlcpy(buf, gettext(
1484*7c478bd9Sstevel@tonic-gate 				    "exited with $SMF_EXIT_ERR_FATAL"),
1485*7c478bd9Sstevel@tonic-gate 				    sizeof (buf));
1486*7c478bd9Sstevel@tonic-gate 			} else {
1487*7c478bd9Sstevel@tonic-gate 				(void) snprintf(buf, sizeof (buf),
1488*7c478bd9Sstevel@tonic-gate 				    gettext("exited with status %d"),
1489*7c478bd9Sstevel@tonic-gate 				    WEXITSTATUS(stat));
1490*7c478bd9Sstevel@tonic-gate 			}
1491*7c478bd9Sstevel@tonic-gate 		} else if (WIFSIGNALED(stat)) {
1492*7c478bd9Sstevel@tonic-gate 			if (WCOREDUMP(stat)) {
1493*7c478bd9Sstevel@tonic-gate 				if (strsignal(WTERMSIG(stat)) != NULL)
1494*7c478bd9Sstevel@tonic-gate 					(void) snprintf(buf, sizeof (buf),
1495*7c478bd9Sstevel@tonic-gate 					    gettext("dumped core on %s (%d)"),
1496*7c478bd9Sstevel@tonic-gate 					    strsignal(WTERMSIG(stat)),
1497*7c478bd9Sstevel@tonic-gate 					    WTERMSIG(stat));
1498*7c478bd9Sstevel@tonic-gate 				else
1499*7c478bd9Sstevel@tonic-gate 					(void) snprintf(buf, sizeof (buf),
1500*7c478bd9Sstevel@tonic-gate 					    gettext("dumped core signal %d"),
1501*7c478bd9Sstevel@tonic-gate 					    WTERMSIG(stat));
1502*7c478bd9Sstevel@tonic-gate 			} else {
1503*7c478bd9Sstevel@tonic-gate 				if (strsignal(WTERMSIG(stat)) != NULL) {
1504*7c478bd9Sstevel@tonic-gate 					(void) snprintf(buf, sizeof (buf),
1505*7c478bd9Sstevel@tonic-gate 					    gettext("died on %s (%d)"),
1506*7c478bd9Sstevel@tonic-gate 					    strsignal(WTERMSIG(stat)),
1507*7c478bd9Sstevel@tonic-gate 					    WTERMSIG(stat));
1508*7c478bd9Sstevel@tonic-gate 				} else {
1509*7c478bd9Sstevel@tonic-gate 					(void) snprintf(buf, sizeof (buf),
1510*7c478bd9Sstevel@tonic-gate 					    gettext("died on signal %d"),
1511*7c478bd9Sstevel@tonic-gate 					    WTERMSIG(stat));
1512*7c478bd9Sstevel@tonic-gate 				}
1513*7c478bd9Sstevel@tonic-gate 			}
1514*7c478bd9Sstevel@tonic-gate 		} else {
1515*7c478bd9Sstevel@tonic-gate 			goto fail;
1516*7c478bd9Sstevel@tonic-gate 		}
1517*7c478bd9Sstevel@tonic-gate 
1518*7c478bd9Sstevel@tonic-gate 		if (strcmp(ip->aux_state, "fault_threshold_reached") != 0)
1519*7c478bd9Sstevel@tonic-gate 			(void) printf(gettext("Reason: Start method %s.\n"),
1520*7c478bd9Sstevel@tonic-gate 			    buf);
1521*7c478bd9Sstevel@tonic-gate 		else
1522*7c478bd9Sstevel@tonic-gate 			(void) printf(gettext("Reason: "
1523*7c478bd9Sstevel@tonic-gate 			    "Start method failed repeatedly, last %s.\n"), buf);
1524*7c478bd9Sstevel@tonic-gate 		*dcp = DC_STARTFAIL;
1525*7c478bd9Sstevel@tonic-gate 	} else {
1526*7c478bd9Sstevel@tonic-gate fail:
1527*7c478bd9Sstevel@tonic-gate 		if (strcmp(ip->aux_state, "fault_threshold_reached") == 0)
1528*7c478bd9Sstevel@tonic-gate 			(void) puts(gettext(
1529*7c478bd9Sstevel@tonic-gate 			    "Reason: Method failed repeatedly."));
1530*7c478bd9Sstevel@tonic-gate 		else
1531*7c478bd9Sstevel@tonic-gate 			(void) puts(gettext("Reason: Method failed."));
1532*7c478bd9Sstevel@tonic-gate 		*dcp = DC_METHFAIL;
1533*7c478bd9Sstevel@tonic-gate 	}
1534*7c478bd9Sstevel@tonic-gate }
1535*7c478bd9Sstevel@tonic-gate 
1536*7c478bd9Sstevel@tonic-gate static void
1537*7c478bd9Sstevel@tonic-gate print_dependency_reasons(const inst_t *svcp, int verbose)
1538*7c478bd9Sstevel@tonic-gate {
1539*7c478bd9Sstevel@tonic-gate 	struct dependency *d;
1540*7c478bd9Sstevel@tonic-gate 	struct svcptr *spp;
1541*7c478bd9Sstevel@tonic-gate 	const char *dc;
1542*7c478bd9Sstevel@tonic-gate 
1543*7c478bd9Sstevel@tonic-gate 	/*
1544*7c478bd9Sstevel@tonic-gate 	 * If we couldn't determine why the service is offline, then baddeps
1545*7c478bd9Sstevel@tonic-gate 	 * will be empty and causes will have a pointer to self.
1546*7c478bd9Sstevel@tonic-gate 	 */
1547*7c478bd9Sstevel@tonic-gate 	if (uu_list_numnodes(svcp->baddeps) == 0 &&
1548*7c478bd9Sstevel@tonic-gate 	    uu_list_numnodes(svcp->causes) == 1) {
1549*7c478bd9Sstevel@tonic-gate 		spp = uu_list_first(svcp->causes);
1550*7c478bd9Sstevel@tonic-gate 		if (spp->svcp == svcp) {
1551*7c478bd9Sstevel@tonic-gate 			switch (svcp->restarter_bad) {
1552*7c478bd9Sstevel@tonic-gate 			case 0:
1553*7c478bd9Sstevel@tonic-gate 				(void) puts(gettext("Reason: Unknown."));
1554*7c478bd9Sstevel@tonic-gate 				dc = DC_UNKNOWN;
1555*7c478bd9Sstevel@tonic-gate 				break;
1556*7c478bd9Sstevel@tonic-gate 
1557*7c478bd9Sstevel@tonic-gate 			case EINVAL:
1558*7c478bd9Sstevel@tonic-gate 				(void) printf(gettext("Reason: "
1559*7c478bd9Sstevel@tonic-gate 				    "Restarter \"%s\" is invalid.\n"),
1560*7c478bd9Sstevel@tonic-gate 				    svcp->restarter);
1561*7c478bd9Sstevel@tonic-gate 				dc = DC_RSTRINVALID;
1562*7c478bd9Sstevel@tonic-gate 				break;
1563*7c478bd9Sstevel@tonic-gate 
1564*7c478bd9Sstevel@tonic-gate 			case ENOENT:
1565*7c478bd9Sstevel@tonic-gate 				(void) printf(gettext("Reason: "
1566*7c478bd9Sstevel@tonic-gate 				    "Restarter \"%s\" does not exist.\n"),
1567*7c478bd9Sstevel@tonic-gate 				    svcp->restarter);
1568*7c478bd9Sstevel@tonic-gate 				dc = DC_RSTRABSENT;
1569*7c478bd9Sstevel@tonic-gate 				break;
1570*7c478bd9Sstevel@tonic-gate 
1571*7c478bd9Sstevel@tonic-gate 			default:
1572*7c478bd9Sstevel@tonic-gate #ifndef NDEBUG
1573*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, "%s:%d: Bad "
1574*7c478bd9Sstevel@tonic-gate 				    "restarter_bad value %d.  Aborting.\n",
1575*7c478bd9Sstevel@tonic-gate 				    __FILE__, __LINE__, svcp->restarter_bad);
1576*7c478bd9Sstevel@tonic-gate #endif
1577*7c478bd9Sstevel@tonic-gate 				abort();
1578*7c478bd9Sstevel@tonic-gate 			}
1579*7c478bd9Sstevel@tonic-gate 
1580*7c478bd9Sstevel@tonic-gate 			if (g_msgbase)
1581*7c478bd9Sstevel@tonic-gate 				(void) printf(gettext("   See: %s%s\n"),
1582*7c478bd9Sstevel@tonic-gate 				    g_msgbase, dc);
1583*7c478bd9Sstevel@tonic-gate 			return;
1584*7c478bd9Sstevel@tonic-gate 		}
1585*7c478bd9Sstevel@tonic-gate 	}
1586*7c478bd9Sstevel@tonic-gate 
1587*7c478bd9Sstevel@tonic-gate 	for (d = uu_list_first(svcp->baddeps);
1588*7c478bd9Sstevel@tonic-gate 	    d != NULL;
1589*7c478bd9Sstevel@tonic-gate 	    d = uu_list_next(svcp->baddeps, d)) {
1590*7c478bd9Sstevel@tonic-gate 		(void) printf(gettext("Reason: Dependency %s is absent.\n"),
1591*7c478bd9Sstevel@tonic-gate 		    d->fmri);
1592*7c478bd9Sstevel@tonic-gate 		if (g_msgbase)
1593*7c478bd9Sstevel@tonic-gate 			(void) printf(gettext("   See: %s%s\n"), g_msgbase,
1594*7c478bd9Sstevel@tonic-gate 			    DC_DEPABSENT);
1595*7c478bd9Sstevel@tonic-gate 	}
1596*7c478bd9Sstevel@tonic-gate 
1597*7c478bd9Sstevel@tonic-gate 	for (spp = uu_list_first(svcp->causes);
1598*7c478bd9Sstevel@tonic-gate 	    spp != NULL && spp->svcp != svcp;
1599*7c478bd9Sstevel@tonic-gate 	    spp = uu_list_next(svcp->causes, spp)) {
1600*7c478bd9Sstevel@tonic-gate 		determine_summary(spp->svcp);
1601*7c478bd9Sstevel@tonic-gate 
1602*7c478bd9Sstevel@tonic-gate 		if (inst_running(spp->svcp)) {
1603*7c478bd9Sstevel@tonic-gate 			(void) printf(gettext("Reason: "
1604*7c478bd9Sstevel@tonic-gate 			    "Service svc:/%s:%s is running.\n"),
1605*7c478bd9Sstevel@tonic-gate 			    spp->svcp->svcname, spp->svcp->instname);
1606*7c478bd9Sstevel@tonic-gate 			dc = DC_DEPRUNNING;
1607*7c478bd9Sstevel@tonic-gate 		} else {
1608*7c478bd9Sstevel@tonic-gate 			if (snprintf(NULL, 0,
1609*7c478bd9Sstevel@tonic-gate 			    gettext("Reason: Service svc:/%s:%s %s"),
1610*7c478bd9Sstevel@tonic-gate 			    spp->svcp->svcname, spp->svcp->instname,
1611*7c478bd9Sstevel@tonic-gate 			    spp->svcp->summary) <= 80) {
1612*7c478bd9Sstevel@tonic-gate 				(void) printf(gettext(
1613*7c478bd9Sstevel@tonic-gate 				    "Reason: Service svc:/%s:%s %s\n"),
1614*7c478bd9Sstevel@tonic-gate 				    spp->svcp->svcname, spp->svcp->instname,
1615*7c478bd9Sstevel@tonic-gate 				    spp->svcp->summary);
1616*7c478bd9Sstevel@tonic-gate 			} else {
1617*7c478bd9Sstevel@tonic-gate 				(void) printf(gettext(
1618*7c478bd9Sstevel@tonic-gate 				    "Reason: Service svc:/%s:%s\n"
1619*7c478bd9Sstevel@tonic-gate 				    "        %s\n"), spp->svcp->svcname,
1620*7c478bd9Sstevel@tonic-gate 				    spp->svcp->instname, spp->svcp->summary);
1621*7c478bd9Sstevel@tonic-gate 			}
1622*7c478bd9Sstevel@tonic-gate 
1623*7c478bd9Sstevel@tonic-gate 			dc = DC_DEPOTHER;
1624*7c478bd9Sstevel@tonic-gate 		}
1625*7c478bd9Sstevel@tonic-gate 
1626*7c478bd9Sstevel@tonic-gate 		if (g_msgbase != NULL)
1627*7c478bd9Sstevel@tonic-gate 			(void) printf(gettext("   See: %s%s\n"), g_msgbase, dc);
1628*7c478bd9Sstevel@tonic-gate 
1629*7c478bd9Sstevel@tonic-gate 		if (verbose) {
1630*7c478bd9Sstevel@tonic-gate 			inst_t *pp;
1631*7c478bd9Sstevel@tonic-gate 			int indent;
1632*7c478bd9Sstevel@tonic-gate 
1633*7c478bd9Sstevel@tonic-gate 			(void) printf(gettext("  Path: svc:/%s:%s\n"),
1634*7c478bd9Sstevel@tonic-gate 			    svcp->svcname, svcp->instname);
1635*7c478bd9Sstevel@tonic-gate 
1636*7c478bd9Sstevel@tonic-gate 			indent = 1;
1637*7c478bd9Sstevel@tonic-gate 			for (pp = spp->next_hop; ; ) {
1638*7c478bd9Sstevel@tonic-gate 				struct svcptr *tmp;
1639*7c478bd9Sstevel@tonic-gate 
1640*7c478bd9Sstevel@tonic-gate 				(void) printf(gettext("%6s  %*ssvc:/%s:%s\n"),
1641*7c478bd9Sstevel@tonic-gate 				    "", indent++ * 2, "", pp->svcname,
1642*7c478bd9Sstevel@tonic-gate 				    pp->instname);
1643*7c478bd9Sstevel@tonic-gate 
1644*7c478bd9Sstevel@tonic-gate 				if (pp == spp->svcp)
1645*7c478bd9Sstevel@tonic-gate 					break;
1646*7c478bd9Sstevel@tonic-gate 
1647*7c478bd9Sstevel@tonic-gate 				/* set pp to next_hop of cause with same svcp */
1648*7c478bd9Sstevel@tonic-gate 				tmp = uu_list_find(pp->causes, spp, NULL, NULL);
1649*7c478bd9Sstevel@tonic-gate 				pp = tmp->next_hop;
1650*7c478bd9Sstevel@tonic-gate 			}
1651*7c478bd9Sstevel@tonic-gate 		}
1652*7c478bd9Sstevel@tonic-gate 	}
1653*7c478bd9Sstevel@tonic-gate }
1654*7c478bd9Sstevel@tonic-gate 
1655*7c478bd9Sstevel@tonic-gate static void
1656*7c478bd9Sstevel@tonic-gate print_reasons(const inst_t *svcp, int verbose)
1657*7c478bd9Sstevel@tonic-gate {
1658*7c478bd9Sstevel@tonic-gate 	int r;
1659*7c478bd9Sstevel@tonic-gate 	const char *dc = NULL;
1660*7c478bd9Sstevel@tonic-gate 
1661*7c478bd9Sstevel@tonic-gate 	if (strcmp(svcp->state, SCF_STATE_STRING_ONLINE) == 0)
1662*7c478bd9Sstevel@tonic-gate 		return;
1663*7c478bd9Sstevel@tonic-gate 
1664*7c478bd9Sstevel@tonic-gate 	if (strcmp(svcp->state, SCF_STATE_STRING_UNINIT) == 0) {
1665*7c478bd9Sstevel@tonic-gate 		inst_t *rsp;
1666*7c478bd9Sstevel@tonic-gate 
1667*7c478bd9Sstevel@tonic-gate 		r = get_fmri(svcp->restarter, NULL, &rsp);
1668*7c478bd9Sstevel@tonic-gate 		switch (r) {
1669*7c478bd9Sstevel@tonic-gate 		case 0:
1670*7c478bd9Sstevel@tonic-gate 			if (rsp != NULL)
1671*7c478bd9Sstevel@tonic-gate 				break;
1672*7c478bd9Sstevel@tonic-gate 			/* FALLTHROUGH */
1673*7c478bd9Sstevel@tonic-gate 
1674*7c478bd9Sstevel@tonic-gate 		case EINVAL:
1675*7c478bd9Sstevel@tonic-gate 			(void) printf(gettext("Reason: "
1676*7c478bd9Sstevel@tonic-gate 			    "Restarter \"%s\" is invalid.\n"), svcp->restarter);
1677*7c478bd9Sstevel@tonic-gate 			dc = DC_RSTRINVALID;
1678*7c478bd9Sstevel@tonic-gate 			goto diagcode;
1679*7c478bd9Sstevel@tonic-gate 
1680*7c478bd9Sstevel@tonic-gate 		case ENOENT:
1681*7c478bd9Sstevel@tonic-gate 			(void) printf(gettext("Reason: "
1682*7c478bd9Sstevel@tonic-gate 			    "Restarter \"%s\" does not exist.\n"),
1683*7c478bd9Sstevel@tonic-gate 			    svcp->restarter);
1684*7c478bd9Sstevel@tonic-gate 			dc = DC_RSTRABSENT;
1685*7c478bd9Sstevel@tonic-gate 			goto diagcode;
1686*7c478bd9Sstevel@tonic-gate 
1687*7c478bd9Sstevel@tonic-gate 		default:
1688*7c478bd9Sstevel@tonic-gate 			bad_error("get_fmri", r);
1689*7c478bd9Sstevel@tonic-gate 		}
1690*7c478bd9Sstevel@tonic-gate 
1691*7c478bd9Sstevel@tonic-gate 		if (inst_running(rsp)) {
1692*7c478bd9Sstevel@tonic-gate 			(void) printf(gettext("Reason: Restarter %s "
1693*7c478bd9Sstevel@tonic-gate 			    "has not initialized service state.\n"),
1694*7c478bd9Sstevel@tonic-gate 			    svcp->restarter);
1695*7c478bd9Sstevel@tonic-gate 			dc = DC_UNINIT;
1696*7c478bd9Sstevel@tonic-gate 		} else {
1697*7c478bd9Sstevel@tonic-gate 			(void) printf(gettext(
1698*7c478bd9Sstevel@tonic-gate 			    "Reason: Restarter %s is not running.\n"),
1699*7c478bd9Sstevel@tonic-gate 			    svcp->restarter);
1700*7c478bd9Sstevel@tonic-gate 			dc = DC_RSTRDEAD;
1701*7c478bd9Sstevel@tonic-gate 		}
1702*7c478bd9Sstevel@tonic-gate 
1703*7c478bd9Sstevel@tonic-gate 	} else if (strcmp(svcp->state, SCF_STATE_STRING_DISABLED) == 0) {
1704*7c478bd9Sstevel@tonic-gate 		if (!svcp->temporary) {
1705*7c478bd9Sstevel@tonic-gate 			(void) puts(gettext(
1706*7c478bd9Sstevel@tonic-gate 			    "Reason: Disabled by an administrator."));
1707*7c478bd9Sstevel@tonic-gate 			dc = DC_DISABLED;
1708*7c478bd9Sstevel@tonic-gate 		} else {
1709*7c478bd9Sstevel@tonic-gate 			(void) puts(gettext("Reason: "
1710*7c478bd9Sstevel@tonic-gate 			    "Temporarily disabled by an administrator."));
1711*7c478bd9Sstevel@tonic-gate 			dc = DC_TEMPDISABLED;
1712*7c478bd9Sstevel@tonic-gate 		}
1713*7c478bd9Sstevel@tonic-gate 
1714*7c478bd9Sstevel@tonic-gate 	} else if (strcmp(svcp->state, SCF_STATE_STRING_MAINT) == 0) {
1715*7c478bd9Sstevel@tonic-gate 		if (strcmp(svcp->aux_state, "administrative_request") == 0) {
1716*7c478bd9Sstevel@tonic-gate 			(void) puts(gettext("Reason: "
1717*7c478bd9Sstevel@tonic-gate 			    "Maintenance requested by an administrator."));
1718*7c478bd9Sstevel@tonic-gate 			dc = DC_ADMINMAINT;
1719*7c478bd9Sstevel@tonic-gate 		} else if (strcmp(svcp->aux_state, "dependency_cycle") == 0) {
1720*7c478bd9Sstevel@tonic-gate 			(void) puts(gettext(
1721*7c478bd9Sstevel@tonic-gate 			    "Reason: Completes a dependency cycle."));
1722*7c478bd9Sstevel@tonic-gate 			dc = DC_DEPCYCLE;
1723*7c478bd9Sstevel@tonic-gate 		} else if (strcmp(svcp->aux_state, "fault_threshold_reached") ==
1724*7c478bd9Sstevel@tonic-gate 		    0) {
1725*7c478bd9Sstevel@tonic-gate 			print_method_failure(svcp, &dc);
1726*7c478bd9Sstevel@tonic-gate 		} else if (strcmp(svcp->aux_state, "invalid_dependency") == 0) {
1727*7c478bd9Sstevel@tonic-gate 			(void) puts(gettext("Reason: Has invalid dependency."));
1728*7c478bd9Sstevel@tonic-gate 			dc = DC_INVALIDDEP;
1729*7c478bd9Sstevel@tonic-gate 		} else if (strcmp(svcp->aux_state, "invalid_restarter") == 0) {
1730*7c478bd9Sstevel@tonic-gate 			(void) printf(gettext("Reason: Restarter \"%s\" is "
1731*7c478bd9Sstevel@tonic-gate 			    "invalid.\n"), svcp->restarter);
1732*7c478bd9Sstevel@tonic-gate 			dc = DC_RSTRINVALID;
1733*7c478bd9Sstevel@tonic-gate 		} else if (strcmp(svcp->aux_state, "method_failed") == 0) {
1734*7c478bd9Sstevel@tonic-gate 			print_method_failure(svcp, &dc);
1735*7c478bd9Sstevel@tonic-gate 		} else if (strcmp(svcp->aux_state, "restarting_too_quickly") ==
1736*7c478bd9Sstevel@tonic-gate 		    0) {
1737*7c478bd9Sstevel@tonic-gate 			(void) puts(gettext("Reason: Restarting too quickly."));
1738*7c478bd9Sstevel@tonic-gate 			dc = DC_TOOQUICKLY;
1739*7c478bd9Sstevel@tonic-gate 		} else if (strcmp(svcp->aux_state, "none") == 0) {
1740*7c478bd9Sstevel@tonic-gate 			(void) printf(gettext(
1741*7c478bd9Sstevel@tonic-gate 			    "Reason: Restarter %s gave no explanation.\n"),
1742*7c478bd9Sstevel@tonic-gate 			    svcp->restarter);
1743*7c478bd9Sstevel@tonic-gate 			dc = DC_NONE;
1744*7c478bd9Sstevel@tonic-gate 		} else {
1745*7c478bd9Sstevel@tonic-gate 			(void) puts(gettext("Reason: Unknown."));
1746*7c478bd9Sstevel@tonic-gate 			dc = DC_UNKNOWN;
1747*7c478bd9Sstevel@tonic-gate 		}
1748*7c478bd9Sstevel@tonic-gate 
1749*7c478bd9Sstevel@tonic-gate 	} else if (strcmp(svcp->state, SCF_STATE_STRING_OFFLINE) == 0) {
1750*7c478bd9Sstevel@tonic-gate 		if (strcmp(svcp->next_state, SCF_STATE_STRING_ONLINE) == 0) {
1751*7c478bd9Sstevel@tonic-gate 			(void) puts(gettext(
1752*7c478bd9Sstevel@tonic-gate 			    "Reason: Start method is running."));
1753*7c478bd9Sstevel@tonic-gate 			dc = DC_STARTING;
1754*7c478bd9Sstevel@tonic-gate 		} else if (strcmp(svcp->next_state, SCF_STATE_STRING_NONE) ==
1755*7c478bd9Sstevel@tonic-gate 		    0) {
1756*7c478bd9Sstevel@tonic-gate 			print_dependency_reasons(svcp, verbose);
1757*7c478bd9Sstevel@tonic-gate 			/* Function prints diagcodes. */
1758*7c478bd9Sstevel@tonic-gate 			return;
1759*7c478bd9Sstevel@tonic-gate 		} else {
1760*7c478bd9Sstevel@tonic-gate 			(void) printf(gettext(
1761*7c478bd9Sstevel@tonic-gate 			    "Reason: Transitioning to state %s.\n"),
1762*7c478bd9Sstevel@tonic-gate 			    svcp->next_state);
1763*7c478bd9Sstevel@tonic-gate 			dc = DC_TRANSITION;
1764*7c478bd9Sstevel@tonic-gate 		}
1765*7c478bd9Sstevel@tonic-gate 
1766*7c478bd9Sstevel@tonic-gate 	} else if (strcmp(svcp->state, SCF_STATE_STRING_DEGRADED) == 0) {
1767*7c478bd9Sstevel@tonic-gate 		(void) puts(gettext("Reason: Degraded by an administrator."));
1768*7c478bd9Sstevel@tonic-gate 		dc = DC_ADMINDEGR;
1769*7c478bd9Sstevel@tonic-gate 
1770*7c478bd9Sstevel@tonic-gate 	} else {
1771*7c478bd9Sstevel@tonic-gate 		(void) printf(gettext("Reason: Not in valid state (%s).\n"),
1772*7c478bd9Sstevel@tonic-gate 		    svcp->state);
1773*7c478bd9Sstevel@tonic-gate 		dc = DC_INVALIDSTATE;
1774*7c478bd9Sstevel@tonic-gate 	}
1775*7c478bd9Sstevel@tonic-gate 
1776*7c478bd9Sstevel@tonic-gate diagcode:
1777*7c478bd9Sstevel@tonic-gate 	if (g_msgbase != NULL)
1778*7c478bd9Sstevel@tonic-gate 		(void) printf(gettext("   See: %s%s\n"), g_msgbase, dc);
1779*7c478bd9Sstevel@tonic-gate }
1780*7c478bd9Sstevel@tonic-gate 
1781*7c478bd9Sstevel@tonic-gate static void
1782*7c478bd9Sstevel@tonic-gate print_manpage(int verbose)
1783*7c478bd9Sstevel@tonic-gate {
1784*7c478bd9Sstevel@tonic-gate 	static char *title = NULL;
1785*7c478bd9Sstevel@tonic-gate 	static char *section = NULL;
1786*7c478bd9Sstevel@tonic-gate 
1787*7c478bd9Sstevel@tonic-gate 	if (title == NULL) {
1788*7c478bd9Sstevel@tonic-gate 		title = safe_malloc(g_value_sz);
1789*7c478bd9Sstevel@tonic-gate 		section = safe_malloc(g_value_sz);
1790*7c478bd9Sstevel@tonic-gate 	}
1791*7c478bd9Sstevel@tonic-gate 
1792*7c478bd9Sstevel@tonic-gate 	if (pg_get_single_val(g_pg, SCF_PROPERTY_TM_TITLE, SCF_TYPE_ASTRING,
1793*7c478bd9Sstevel@tonic-gate 	    (void *)title, g_value_sz, 0) != 0)
1794*7c478bd9Sstevel@tonic-gate 		return;
1795*7c478bd9Sstevel@tonic-gate 
1796*7c478bd9Sstevel@tonic-gate 	if (pg_get_single_val(g_pg, SCF_PROPERTY_TM_SECTION,
1797*7c478bd9Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, (void *)section, g_value_sz, 0) != 0)
1798*7c478bd9Sstevel@tonic-gate 		return;
1799*7c478bd9Sstevel@tonic-gate 
1800*7c478bd9Sstevel@tonic-gate 	if (!verbose) {
1801*7c478bd9Sstevel@tonic-gate 		(void) printf(gettext("   See: %s(%s)\n"), title, section);
1802*7c478bd9Sstevel@tonic-gate 		return;
1803*7c478bd9Sstevel@tonic-gate 	}
1804*7c478bd9Sstevel@tonic-gate 
1805*7c478bd9Sstevel@tonic-gate 	if (pg_get_single_val(g_pg, SCF_PROPERTY_TM_MANPATH, SCF_TYPE_ASTRING,
1806*7c478bd9Sstevel@tonic-gate 	    (void *)g_value, g_value_sz, 0) != 0)
1807*7c478bd9Sstevel@tonic-gate 		return;
1808*7c478bd9Sstevel@tonic-gate 
1809*7c478bd9Sstevel@tonic-gate 	if (strcmp(g_value, ":default") == 0) {
1810*7c478bd9Sstevel@tonic-gate 		assert(sizeof (DEFAULT_MAN_PATH) < g_value_sz);
1811*7c478bd9Sstevel@tonic-gate 		(void) strcpy(g_value, DEFAULT_MAN_PATH);
1812*7c478bd9Sstevel@tonic-gate 	}
1813*7c478bd9Sstevel@tonic-gate 
1814*7c478bd9Sstevel@tonic-gate 	(void) printf(gettext("   See: man -M %s -s %s %s\n"), g_value,
1815*7c478bd9Sstevel@tonic-gate 	    section, title);
1816*7c478bd9Sstevel@tonic-gate }
1817*7c478bd9Sstevel@tonic-gate 
1818*7c478bd9Sstevel@tonic-gate static void
1819*7c478bd9Sstevel@tonic-gate print_doclink()
1820*7c478bd9Sstevel@tonic-gate {
1821*7c478bd9Sstevel@tonic-gate 	static char *uri = NULL;
1822*7c478bd9Sstevel@tonic-gate 
1823*7c478bd9Sstevel@tonic-gate 	if (uri == NULL) {
1824*7c478bd9Sstevel@tonic-gate 		uri = safe_malloc(g_value_sz);
1825*7c478bd9Sstevel@tonic-gate 	}
1826*7c478bd9Sstevel@tonic-gate 
1827*7c478bd9Sstevel@tonic-gate 	if (pg_get_single_val(g_pg, SCF_PROPERTY_TM_URI, SCF_TYPE_ASTRING,
1828*7c478bd9Sstevel@tonic-gate 	    (void *)uri, g_value_sz, 0) != 0)
1829*7c478bd9Sstevel@tonic-gate 		return;
1830*7c478bd9Sstevel@tonic-gate 
1831*7c478bd9Sstevel@tonic-gate 	(void) printf(gettext("   See: %s\n"), uri);
1832*7c478bd9Sstevel@tonic-gate }
1833*7c478bd9Sstevel@tonic-gate 
1834*7c478bd9Sstevel@tonic-gate 
1835*7c478bd9Sstevel@tonic-gate /*
1836*7c478bd9Sstevel@tonic-gate  * Returns
1837*7c478bd9Sstevel@tonic-gate  *   0 - success
1838*7c478bd9Sstevel@tonic-gate  *   1 - inst was deleted
1839*7c478bd9Sstevel@tonic-gate  */
1840*7c478bd9Sstevel@tonic-gate static int
1841*7c478bd9Sstevel@tonic-gate print_docs(scf_instance_t *inst, int verbose)
1842*7c478bd9Sstevel@tonic-gate {
1843*7c478bd9Sstevel@tonic-gate 	scf_snapshot_t *snap;
1844*7c478bd9Sstevel@tonic-gate 	int r;
1845*7c478bd9Sstevel@tonic-gate 
1846*7c478bd9Sstevel@tonic-gate 	if (scf_instance_get_snapshot(inst, "running", g_snap) != 0) {
1847*7c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
1848*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
1849*7c478bd9Sstevel@tonic-gate 			break;
1850*7c478bd9Sstevel@tonic-gate 
1851*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
1852*7c478bd9Sstevel@tonic-gate 			return (1);
1853*7c478bd9Sstevel@tonic-gate 
1854*7c478bd9Sstevel@tonic-gate 		default:
1855*7c478bd9Sstevel@tonic-gate 			scfdie();
1856*7c478bd9Sstevel@tonic-gate 		}
1857*7c478bd9Sstevel@tonic-gate 
1858*7c478bd9Sstevel@tonic-gate 		snap = NULL;
1859*7c478bd9Sstevel@tonic-gate 	} else {
1860*7c478bd9Sstevel@tonic-gate 		snap = g_snap;
1861*7c478bd9Sstevel@tonic-gate 	}
1862*7c478bd9Sstevel@tonic-gate 
1863*7c478bd9Sstevel@tonic-gate 	if (scf_iter_instance_pgs_typed_composed(g_iter, inst, snap,
1864*7c478bd9Sstevel@tonic-gate 	    SCF_GROUP_TEMPLATE) != 0) {
1865*7c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_DELETED)
1866*7c478bd9Sstevel@tonic-gate 			scfdie();
1867*7c478bd9Sstevel@tonic-gate 
1868*7c478bd9Sstevel@tonic-gate 		return (1);
1869*7c478bd9Sstevel@tonic-gate 	}
1870*7c478bd9Sstevel@tonic-gate 
1871*7c478bd9Sstevel@tonic-gate 	for (;;) {
1872*7c478bd9Sstevel@tonic-gate 		r = scf_iter_next_pg(g_iter, g_pg);
1873*7c478bd9Sstevel@tonic-gate 		if (r == 0)
1874*7c478bd9Sstevel@tonic-gate 			break;
1875*7c478bd9Sstevel@tonic-gate 		if (r != 1) {
1876*7c478bd9Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_DELETED)
1877*7c478bd9Sstevel@tonic-gate 				scfdie();
1878*7c478bd9Sstevel@tonic-gate 
1879*7c478bd9Sstevel@tonic-gate 			return (1);
1880*7c478bd9Sstevel@tonic-gate 		}
1881*7c478bd9Sstevel@tonic-gate 
1882*7c478bd9Sstevel@tonic-gate 		if (scf_pg_get_name(g_pg, g_fmri, g_fmri_sz) < 0) {
1883*7c478bd9Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_DELETED)
1884*7c478bd9Sstevel@tonic-gate 				scfdie();
1885*7c478bd9Sstevel@tonic-gate 
1886*7c478bd9Sstevel@tonic-gate 			continue;
1887*7c478bd9Sstevel@tonic-gate 		}
1888*7c478bd9Sstevel@tonic-gate 
1889*7c478bd9Sstevel@tonic-gate 		if (strncmp(g_fmri, SCF_PG_TM_MAN_PREFIX,
1890*7c478bd9Sstevel@tonic-gate 		    strlen(SCF_PG_TM_MAN_PREFIX)) == 0) {
1891*7c478bd9Sstevel@tonic-gate 			print_manpage(verbose);
1892*7c478bd9Sstevel@tonic-gate 			continue;
1893*7c478bd9Sstevel@tonic-gate 		}
1894*7c478bd9Sstevel@tonic-gate 
1895*7c478bd9Sstevel@tonic-gate 		if (strncmp(g_fmri, SCF_PG_TM_DOC_PREFIX,
1896*7c478bd9Sstevel@tonic-gate 		    strlen(SCF_PG_TM_DOC_PREFIX)) == 0) {
1897*7c478bd9Sstevel@tonic-gate 			print_doclink();
1898*7c478bd9Sstevel@tonic-gate 			continue;
1899*7c478bd9Sstevel@tonic-gate 		}
1900*7c478bd9Sstevel@tonic-gate 	}
1901*7c478bd9Sstevel@tonic-gate 	return (0);
1902*7c478bd9Sstevel@tonic-gate }
1903*7c478bd9Sstevel@tonic-gate 
1904*7c478bd9Sstevel@tonic-gate static void
1905*7c478bd9Sstevel@tonic-gate print_logs(scf_instance_t *inst)
1906*7c478bd9Sstevel@tonic-gate {
1907*7c478bd9Sstevel@tonic-gate 	if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, g_pg) != 0)
1908*7c478bd9Sstevel@tonic-gate 		return;
1909*7c478bd9Sstevel@tonic-gate 
1910*7c478bd9Sstevel@tonic-gate 	if (pg_get_single_val(g_pg, SCF_PROPERTY_ALT_LOGFILE,
1911*7c478bd9Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, (void *)g_value, g_value_sz, 0) == 0)
1912*7c478bd9Sstevel@tonic-gate 		(void) printf(gettext("   See: %s\n"), g_value);
1913*7c478bd9Sstevel@tonic-gate 
1914*7c478bd9Sstevel@tonic-gate 	if (pg_get_single_val(g_pg, SCF_PROPERTY_LOGFILE,
1915*7c478bd9Sstevel@tonic-gate 	    SCF_TYPE_ASTRING, (void *)g_value, g_value_sz, 0) == 0)
1916*7c478bd9Sstevel@tonic-gate 		(void) printf(gettext("   See: %s\n"), g_value);
1917*7c478bd9Sstevel@tonic-gate }
1918*7c478bd9Sstevel@tonic-gate 
1919*7c478bd9Sstevel@tonic-gate static int first = 1;
1920*7c478bd9Sstevel@tonic-gate 
1921*7c478bd9Sstevel@tonic-gate /*
1922*7c478bd9Sstevel@tonic-gate  * Explain why the given service is in the state it's in.
1923*7c478bd9Sstevel@tonic-gate  */
1924*7c478bd9Sstevel@tonic-gate static void
1925*7c478bd9Sstevel@tonic-gate print_service(inst_t *svcp, int verbose)
1926*7c478bd9Sstevel@tonic-gate {
1927*7c478bd9Sstevel@tonic-gate 	struct svcptr *spp;
1928*7c478bd9Sstevel@tonic-gate 	time_t stime;
1929*7c478bd9Sstevel@tonic-gate 	char *timebuf;
1930*7c478bd9Sstevel@tonic-gate 	size_t tbsz;
1931*7c478bd9Sstevel@tonic-gate 	struct tm *tmp;
1932*7c478bd9Sstevel@tonic-gate 	int deleted = 0;
1933*7c478bd9Sstevel@tonic-gate 
1934*7c478bd9Sstevel@tonic-gate 	if (first)
1935*7c478bd9Sstevel@tonic-gate 		first = 0;
1936*7c478bd9Sstevel@tonic-gate 	else
1937*7c478bd9Sstevel@tonic-gate 		(void) putchar('\n');
1938*7c478bd9Sstevel@tonic-gate 
1939*7c478bd9Sstevel@tonic-gate 	(void) printf(gettext("svc:/%s:%s"), svcp->svcname, svcp->instname);
1940*7c478bd9Sstevel@tonic-gate 
1941*7c478bd9Sstevel@tonic-gate 	if (scf_scope_get_service(g_local_scope, svcp->svcname, g_svc) != 0) {
1942*7c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND)
1943*7c478bd9Sstevel@tonic-gate 			scfdie();
1944*7c478bd9Sstevel@tonic-gate 		deleted = 1;
1945*7c478bd9Sstevel@tonic-gate 	} else if (scf_service_get_instance(g_svc, svcp->instname, g_inst) !=
1946*7c478bd9Sstevel@tonic-gate 	    0) {
1947*7c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND)
1948*7c478bd9Sstevel@tonic-gate 			scfdie();
1949*7c478bd9Sstevel@tonic-gate 		deleted = 1;
1950*7c478bd9Sstevel@tonic-gate 	}
1951*7c478bd9Sstevel@tonic-gate 
1952*7c478bd9Sstevel@tonic-gate 	if (!deleted) {
1953*7c478bd9Sstevel@tonic-gate 		if (inst_get_single_val(g_inst, SCF_PG_TM_COMMON_NAME, locale,
1954*7c478bd9Sstevel@tonic-gate 		    SCF_TYPE_USTRING, g_value, g_value_sz, 0, 0, 1) == 0)
1955*7c478bd9Sstevel@tonic-gate 			/* EMPTY */;
1956*7c478bd9Sstevel@tonic-gate 		else if (inst_get_single_val(g_inst, SCF_PG_TM_COMMON_NAME, "C",
1957*7c478bd9Sstevel@tonic-gate 		    SCF_TYPE_USTRING, g_value, g_value_sz, 0, 0, 1) != 0)
1958*7c478bd9Sstevel@tonic-gate 			(void) strcpy(g_value, "?");
1959*7c478bd9Sstevel@tonic-gate 
1960*7c478bd9Sstevel@tonic-gate 		(void) printf(gettext(" (%s)\n"), g_value);
1961*7c478bd9Sstevel@tonic-gate 	} else {
1962*7c478bd9Sstevel@tonic-gate 		(void) putchar('\n');
1963*7c478bd9Sstevel@tonic-gate 	}
1964*7c478bd9Sstevel@tonic-gate 
1965*7c478bd9Sstevel@tonic-gate 	stime = svcp->stime.tv_sec;
1966*7c478bd9Sstevel@tonic-gate 	tmp = localtime(&stime);
1967*7c478bd9Sstevel@tonic-gate 
1968*7c478bd9Sstevel@tonic-gate 	for (tbsz = 50; ; tbsz *= 2) {
1969*7c478bd9Sstevel@tonic-gate 		timebuf = safe_malloc(tbsz);
1970*7c478bd9Sstevel@tonic-gate 		if (strftime(timebuf, tbsz, NULL, tmp) != 0)
1971*7c478bd9Sstevel@tonic-gate 		    break;
1972*7c478bd9Sstevel@tonic-gate 		free(timebuf);
1973*7c478bd9Sstevel@tonic-gate 	}
1974*7c478bd9Sstevel@tonic-gate 
1975*7c478bd9Sstevel@tonic-gate 	(void) printf(gettext(" State: %s since %s\n"), svcp->state, timebuf);
1976*7c478bd9Sstevel@tonic-gate 
1977*7c478bd9Sstevel@tonic-gate 	free(timebuf);
1978*7c478bd9Sstevel@tonic-gate 
1979*7c478bd9Sstevel@tonic-gate 	/* Reasons */
1980*7c478bd9Sstevel@tonic-gate 	print_reasons(svcp, verbose);
1981*7c478bd9Sstevel@tonic-gate 
1982*7c478bd9Sstevel@tonic-gate 	if (!deleted)
1983*7c478bd9Sstevel@tonic-gate 		deleted = print_docs(g_inst, verbose);
1984*7c478bd9Sstevel@tonic-gate 	if (!deleted)
1985*7c478bd9Sstevel@tonic-gate 		print_logs(g_inst);
1986*7c478bd9Sstevel@tonic-gate 
1987*7c478bd9Sstevel@tonic-gate 	(void) determine_impact(svcp);
1988*7c478bd9Sstevel@tonic-gate 
1989*7c478bd9Sstevel@tonic-gate 	switch (uu_list_numnodes(svcp->impact)) {
1990*7c478bd9Sstevel@tonic-gate 	case 0:
1991*7c478bd9Sstevel@tonic-gate 		if (inst_running(svcp))
1992*7c478bd9Sstevel@tonic-gate 			(void) puts(gettext("Impact: None."));
1993*7c478bd9Sstevel@tonic-gate 		else
1994*7c478bd9Sstevel@tonic-gate 			(void) puts(gettext(
1995*7c478bd9Sstevel@tonic-gate 			    "Impact: This service is not running."));
1996*7c478bd9Sstevel@tonic-gate 		break;
1997*7c478bd9Sstevel@tonic-gate 
1998*7c478bd9Sstevel@tonic-gate 	case 1:
1999*7c478bd9Sstevel@tonic-gate 		if (!verbose)
2000*7c478bd9Sstevel@tonic-gate 			(void) puts(gettext("Impact: 1 dependent service "
2001*7c478bd9Sstevel@tonic-gate 			    "is not running.  (Use -v for list.)"));
2002*7c478bd9Sstevel@tonic-gate 		else
2003*7c478bd9Sstevel@tonic-gate 			(void) puts(gettext(
2004*7c478bd9Sstevel@tonic-gate 			    "Impact: 1 dependent service is not running:"));
2005*7c478bd9Sstevel@tonic-gate 		break;
2006*7c478bd9Sstevel@tonic-gate 
2007*7c478bd9Sstevel@tonic-gate 	default:
2008*7c478bd9Sstevel@tonic-gate 		if (!verbose)
2009*7c478bd9Sstevel@tonic-gate 			(void) printf(gettext("Impact: %d dependent services "
2010*7c478bd9Sstevel@tonic-gate 			    "are not running.  (Use -v for list.)\n"),
2011*7c478bd9Sstevel@tonic-gate 			    uu_list_numnodes(svcp->impact));
2012*7c478bd9Sstevel@tonic-gate 		else
2013*7c478bd9Sstevel@tonic-gate 			(void) printf(gettext(
2014*7c478bd9Sstevel@tonic-gate 			    "Impact: %d dependent services are not running:\n"),
2015*7c478bd9Sstevel@tonic-gate 			    uu_list_numnodes(svcp->impact));
2016*7c478bd9Sstevel@tonic-gate 	}
2017*7c478bd9Sstevel@tonic-gate 
2018*7c478bd9Sstevel@tonic-gate 	if (verbose) {
2019*7c478bd9Sstevel@tonic-gate 		for (spp = uu_list_first(svcp->impact);
2020*7c478bd9Sstevel@tonic-gate 		    spp != NULL;
2021*7c478bd9Sstevel@tonic-gate 		    spp = uu_list_next(svcp->impact, spp))
2022*7c478bd9Sstevel@tonic-gate 			(void) printf(gettext("        svc:/%s:%s\n"),
2023*7c478bd9Sstevel@tonic-gate 			    spp->svcp->svcname, spp->svcp->instname);
2024*7c478bd9Sstevel@tonic-gate 	}
2025*7c478bd9Sstevel@tonic-gate }
2026*7c478bd9Sstevel@tonic-gate 
2027*7c478bd9Sstevel@tonic-gate /*
2028*7c478bd9Sstevel@tonic-gate  * Top level routine.
2029*7c478bd9Sstevel@tonic-gate  */
2030*7c478bd9Sstevel@tonic-gate 
2031*7c478bd9Sstevel@tonic-gate static int
2032*7c478bd9Sstevel@tonic-gate impact_compar(const void *a, const void *b)
2033*7c478bd9Sstevel@tonic-gate {
2034*7c478bd9Sstevel@tonic-gate 	int n, m;
2035*7c478bd9Sstevel@tonic-gate 
2036*7c478bd9Sstevel@tonic-gate 	n = uu_list_numnodes((*(inst_t **)a)->impact);
2037*7c478bd9Sstevel@tonic-gate 	m = uu_list_numnodes((*(inst_t **)b)->impact);
2038*7c478bd9Sstevel@tonic-gate 
2039*7c478bd9Sstevel@tonic-gate 	return (m - n);
2040*7c478bd9Sstevel@tonic-gate }
2041*7c478bd9Sstevel@tonic-gate 
2042*7c478bd9Sstevel@tonic-gate static int
2043*7c478bd9Sstevel@tonic-gate print_service_cb(void *verbose, scf_walkinfo_t *wip)
2044*7c478bd9Sstevel@tonic-gate {
2045*7c478bd9Sstevel@tonic-gate 	int r;
2046*7c478bd9Sstevel@tonic-gate 	inst_t *ip;
2047*7c478bd9Sstevel@tonic-gate 
2048*7c478bd9Sstevel@tonic-gate 	assert(wip->pg == NULL);
2049*7c478bd9Sstevel@tonic-gate 
2050*7c478bd9Sstevel@tonic-gate 	r = get_fmri(wip->fmri, NULL, &ip);
2051*7c478bd9Sstevel@tonic-gate 	assert(r != EINVAL);
2052*7c478bd9Sstevel@tonic-gate 	if (r == ENOENT)
2053*7c478bd9Sstevel@tonic-gate 		return (0);
2054*7c478bd9Sstevel@tonic-gate 
2055*7c478bd9Sstevel@tonic-gate 	assert(r == 0);
2056*7c478bd9Sstevel@tonic-gate 	assert(ip != NULL);
2057*7c478bd9Sstevel@tonic-gate 
2058*7c478bd9Sstevel@tonic-gate 	print_service(ip, (int)verbose);
2059*7c478bd9Sstevel@tonic-gate 
2060*7c478bd9Sstevel@tonic-gate 	return (0);
2061*7c478bd9Sstevel@tonic-gate }
2062*7c478bd9Sstevel@tonic-gate 
2063*7c478bd9Sstevel@tonic-gate void
2064*7c478bd9Sstevel@tonic-gate explain(int verbose, int argc, char **argv)
2065*7c478bd9Sstevel@tonic-gate {
2066*7c478bd9Sstevel@tonic-gate 	/* Initialize globals. */
2067*7c478bd9Sstevel@tonic-gate 	x_init();
2068*7c478bd9Sstevel@tonic-gate 
2069*7c478bd9Sstevel@tonic-gate 	/* Walk the graph and populate services with inst_t's */
2070*7c478bd9Sstevel@tonic-gate 	load_services();
2071*7c478bd9Sstevel@tonic-gate 
2072*7c478bd9Sstevel@tonic-gate 	/* Populate causes for services. */
2073*7c478bd9Sstevel@tonic-gate 	determine_all_causes();
2074*7c478bd9Sstevel@tonic-gate 
2075*7c478bd9Sstevel@tonic-gate 	if (argc > 0) {
2076*7c478bd9Sstevel@tonic-gate 		scf_error_t err;
2077*7c478bd9Sstevel@tonic-gate 
2078*7c478bd9Sstevel@tonic-gate 		check_msgbase();
2079*7c478bd9Sstevel@tonic-gate 
2080*7c478bd9Sstevel@tonic-gate 		/* Call print_service() for each operand. */
2081*7c478bd9Sstevel@tonic-gate 
2082*7c478bd9Sstevel@tonic-gate 		err = scf_walk_fmri(h, argc, argv, SCF_WALK_MULTIPLE,
2083*7c478bd9Sstevel@tonic-gate 		    print_service_cb, (void *)verbose, &exit_status, uu_warn);
2084*7c478bd9Sstevel@tonic-gate 		if (err != 0) {
2085*7c478bd9Sstevel@tonic-gate 			uu_warn(gettext(
2086*7c478bd9Sstevel@tonic-gate 			    "failed to iterate over instances: %s\n"),
2087*7c478bd9Sstevel@tonic-gate 			    scf_strerror(err));
2088*7c478bd9Sstevel@tonic-gate 			exit_status = UU_EXIT_FATAL;
2089*7c478bd9Sstevel@tonic-gate 		}
2090*7c478bd9Sstevel@tonic-gate 	} else {
2091*7c478bd9Sstevel@tonic-gate 		struct svcptr *spp;
2092*7c478bd9Sstevel@tonic-gate 		int n, i;
2093*7c478bd9Sstevel@tonic-gate 		inst_t **ary;
2094*7c478bd9Sstevel@tonic-gate 
2095*7c478bd9Sstevel@tonic-gate 		/* Sort g_causes. */
2096*7c478bd9Sstevel@tonic-gate 
2097*7c478bd9Sstevel@tonic-gate 		n = uu_list_numnodes(g_causes);
2098*7c478bd9Sstevel@tonic-gate 		if (n == 0)
2099*7c478bd9Sstevel@tonic-gate 			return;
2100*7c478bd9Sstevel@tonic-gate 
2101*7c478bd9Sstevel@tonic-gate 		check_msgbase();
2102*7c478bd9Sstevel@tonic-gate 
2103*7c478bd9Sstevel@tonic-gate 		ary = calloc(n, sizeof (*ary));
2104*7c478bd9Sstevel@tonic-gate 		if (ary == NULL)
2105*7c478bd9Sstevel@tonic-gate 			uu_die(emsg_nomem);
2106*7c478bd9Sstevel@tonic-gate 
2107*7c478bd9Sstevel@tonic-gate 		i = 0;
2108*7c478bd9Sstevel@tonic-gate 		for (spp = uu_list_first(g_causes);
2109*7c478bd9Sstevel@tonic-gate 		    spp != NULL;
2110*7c478bd9Sstevel@tonic-gate 		    spp = uu_list_next(g_causes, spp)) {
2111*7c478bd9Sstevel@tonic-gate 			(void) determine_impact(spp->svcp);
2112*7c478bd9Sstevel@tonic-gate 			ary[i++] = spp->svcp;
2113*7c478bd9Sstevel@tonic-gate 		}
2114*7c478bd9Sstevel@tonic-gate 
2115*7c478bd9Sstevel@tonic-gate 		qsort(ary, n, sizeof (*ary), impact_compar);
2116*7c478bd9Sstevel@tonic-gate 
2117*7c478bd9Sstevel@tonic-gate 		/* Call print_service() for each service. */
2118*7c478bd9Sstevel@tonic-gate 
2119*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < n; ++i)
2120*7c478bd9Sstevel@tonic-gate 			print_service(ary[i], verbose);
2121*7c478bd9Sstevel@tonic-gate 	}
2122*7c478bd9Sstevel@tonic-gate }
2123