xref: /titanic_54/usr/src/cmd/svc/svcadm/synch.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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 2004 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  * synchronous svcadm logic
31*7c478bd9Sstevel@tonic-gate  */
32*7c478bd9Sstevel@tonic-gate 
33*7c478bd9Sstevel@tonic-gate #include <locale.h>
34*7c478bd9Sstevel@tonic-gate #include <libintl.h>
35*7c478bd9Sstevel@tonic-gate #include <libscf.h>
36*7c478bd9Sstevel@tonic-gate #include <libscf_priv.h>
37*7c478bd9Sstevel@tonic-gate #include <libuutil.h>
38*7c478bd9Sstevel@tonic-gate #include <stddef.h>
39*7c478bd9Sstevel@tonic-gate #include <stdio.h>
40*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
41*7c478bd9Sstevel@tonic-gate #include <string.h>
42*7c478bd9Sstevel@tonic-gate #include <unistd.h>
43*7c478bd9Sstevel@tonic-gate #include <assert.h>
44*7c478bd9Sstevel@tonic-gate #include <errno.h>
45*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
46*7c478bd9Sstevel@tonic-gate 
47*7c478bd9Sstevel@tonic-gate 
48*7c478bd9Sstevel@tonic-gate /*
49*7c478bd9Sstevel@tonic-gate  * Definitions from svcadm.c.
50*7c478bd9Sstevel@tonic-gate  */
51*7c478bd9Sstevel@tonic-gate extern scf_handle_t *h;
52*7c478bd9Sstevel@tonic-gate extern ssize_t max_scf_fmri_sz;
53*7c478bd9Sstevel@tonic-gate 
54*7c478bd9Sstevel@tonic-gate extern void do_scfdie(int);
55*7c478bd9Sstevel@tonic-gate extern int inst_get_state(scf_instance_t *, char *, const char *,
56*7c478bd9Sstevel@tonic-gate     scf_propertygroup_t **);
57*7c478bd9Sstevel@tonic-gate extern ssize_t get_astring_prop(const scf_propertygroup_t *, const char *,
58*7c478bd9Sstevel@tonic-gate     scf_property_t *, scf_value_t *, char *, size_t);
59*7c478bd9Sstevel@tonic-gate extern int get_bool_prop(scf_propertygroup_t *, const char *, uint8_t *);
60*7c478bd9Sstevel@tonic-gate 
61*7c478bd9Sstevel@tonic-gate #define	scfdie()	do_scfdie(__LINE__)
62*7c478bd9Sstevel@tonic-gate 
63*7c478bd9Sstevel@tonic-gate int has_potential(scf_instance_t *, int);
64*7c478bd9Sstevel@tonic-gate 
65*7c478bd9Sstevel@tonic-gate /*
66*7c478bd9Sstevel@tonic-gate  * Determines if the specified instance is enabled, composing the
67*7c478bd9Sstevel@tonic-gate  * general and general_ovr property groups.  For simplicity, we map
68*7c478bd9Sstevel@tonic-gate  * most errors to "not enabled".
69*7c478bd9Sstevel@tonic-gate  */
70*7c478bd9Sstevel@tonic-gate int
71*7c478bd9Sstevel@tonic-gate is_enabled(scf_instance_t *inst)
72*7c478bd9Sstevel@tonic-gate {
73*7c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg;
74*7c478bd9Sstevel@tonic-gate 	uint8_t bp;
75*7c478bd9Sstevel@tonic-gate 
76*7c478bd9Sstevel@tonic-gate 	if ((pg = scf_pg_create(h)) == NULL)
77*7c478bd9Sstevel@tonic-gate 		scfdie();
78*7c478bd9Sstevel@tonic-gate 
79*7c478bd9Sstevel@tonic-gate 	if (scf_instance_get_pg(inst, SCF_PG_GENERAL_OVR, pg) == 0 &&
80*7c478bd9Sstevel@tonic-gate 	    get_bool_prop(pg, SCF_PROPERTY_ENABLED, &bp) == 0) {
81*7c478bd9Sstevel@tonic-gate 		scf_pg_destroy(pg);
82*7c478bd9Sstevel@tonic-gate 		return (bp);
83*7c478bd9Sstevel@tonic-gate 	}
84*7c478bd9Sstevel@tonic-gate 
85*7c478bd9Sstevel@tonic-gate 	if (scf_instance_get_pg(inst, SCF_PG_GENERAL, pg) == 0 &&
86*7c478bd9Sstevel@tonic-gate 	    get_bool_prop(pg, SCF_PROPERTY_ENABLED, &bp) == 0) {
87*7c478bd9Sstevel@tonic-gate 		scf_pg_destroy(pg);
88*7c478bd9Sstevel@tonic-gate 		return (bp);
89*7c478bd9Sstevel@tonic-gate 	}
90*7c478bd9Sstevel@tonic-gate 
91*7c478bd9Sstevel@tonic-gate 	scf_pg_destroy(pg);
92*7c478bd9Sstevel@tonic-gate 	return (B_FALSE);
93*7c478bd9Sstevel@tonic-gate }
94*7c478bd9Sstevel@tonic-gate 
95*7c478bd9Sstevel@tonic-gate /*
96*7c478bd9Sstevel@tonic-gate  * Reads an astring property from a property group.  If the named
97*7c478bd9Sstevel@tonic-gate  * property doesn't exist, returns NULL.  The result of a successful
98*7c478bd9Sstevel@tonic-gate  * call should be freed.
99*7c478bd9Sstevel@tonic-gate  */
100*7c478bd9Sstevel@tonic-gate static char *
101*7c478bd9Sstevel@tonic-gate read_astring_prop(scf_propertygroup_t *pg, scf_value_t *val,
102*7c478bd9Sstevel@tonic-gate     scf_property_t *prop, const char *name)
103*7c478bd9Sstevel@tonic-gate {
104*7c478bd9Sstevel@tonic-gate 	char *value;
105*7c478bd9Sstevel@tonic-gate 	size_t value_sz;
106*7c478bd9Sstevel@tonic-gate 
107*7c478bd9Sstevel@tonic-gate 	if (scf_pg_get_property(pg, name, prop) == -1) {
108*7c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
109*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
110*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
111*7c478bd9Sstevel@tonic-gate 			return (NULL);
112*7c478bd9Sstevel@tonic-gate 		default:
113*7c478bd9Sstevel@tonic-gate 			scfdie();
114*7c478bd9Sstevel@tonic-gate 		}
115*7c478bd9Sstevel@tonic-gate 	}
116*7c478bd9Sstevel@tonic-gate 
117*7c478bd9Sstevel@tonic-gate 	if (scf_property_get_value(prop, val) != 0) {
118*7c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
119*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
120*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
121*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_CONSTRAINT_VIOLATED:
122*7c478bd9Sstevel@tonic-gate 			return (NULL);
123*7c478bd9Sstevel@tonic-gate 		default:
124*7c478bd9Sstevel@tonic-gate 			scfdie();
125*7c478bd9Sstevel@tonic-gate 		}
126*7c478bd9Sstevel@tonic-gate 	}
127*7c478bd9Sstevel@tonic-gate 
128*7c478bd9Sstevel@tonic-gate 	value_sz = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
129*7c478bd9Sstevel@tonic-gate 	if ((value = malloc(value_sz)) == NULL)
130*7c478bd9Sstevel@tonic-gate 		scfdie();
131*7c478bd9Sstevel@tonic-gate 
132*7c478bd9Sstevel@tonic-gate 	if (scf_value_get_astring(val, value, value_sz) <= 0) {
133*7c478bd9Sstevel@tonic-gate 		free(value);
134*7c478bd9Sstevel@tonic-gate 		return (NULL);
135*7c478bd9Sstevel@tonic-gate 	}
136*7c478bd9Sstevel@tonic-gate 
137*7c478bd9Sstevel@tonic-gate 	return (value);
138*7c478bd9Sstevel@tonic-gate }
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate /*
141*7c478bd9Sstevel@tonic-gate  * Creates and returns an scf_iter for the values of the named
142*7c478bd9Sstevel@tonic-gate  * multi-value property.  Returns NULL on failure.
143*7c478bd9Sstevel@tonic-gate  */
144*7c478bd9Sstevel@tonic-gate static scf_iter_t *
145*7c478bd9Sstevel@tonic-gate prop_walk_init(scf_propertygroup_t *pg, const char *name)
146*7c478bd9Sstevel@tonic-gate {
147*7c478bd9Sstevel@tonic-gate 	scf_iter_t *iter;
148*7c478bd9Sstevel@tonic-gate 	scf_property_t *prop;
149*7c478bd9Sstevel@tonic-gate 
150*7c478bd9Sstevel@tonic-gate 	if ((iter = scf_iter_create(h)) == NULL ||
151*7c478bd9Sstevel@tonic-gate 	    (prop = scf_property_create(h)) == NULL)
152*7c478bd9Sstevel@tonic-gate 		scfdie();
153*7c478bd9Sstevel@tonic-gate 
154*7c478bd9Sstevel@tonic-gate 	if (scf_pg_get_property(pg, name, prop) != 0) {
155*7c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
156*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
157*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
158*7c478bd9Sstevel@tonic-gate 			goto error;
159*7c478bd9Sstevel@tonic-gate 		default:
160*7c478bd9Sstevel@tonic-gate 			scfdie();
161*7c478bd9Sstevel@tonic-gate 		}
162*7c478bd9Sstevel@tonic-gate 	}
163*7c478bd9Sstevel@tonic-gate 
164*7c478bd9Sstevel@tonic-gate 	if (scf_iter_property_values(iter, prop) != 0) {
165*7c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_DELETED)
166*7c478bd9Sstevel@tonic-gate 			scfdie();
167*7c478bd9Sstevel@tonic-gate 		goto error;
168*7c478bd9Sstevel@tonic-gate 	}
169*7c478bd9Sstevel@tonic-gate 
170*7c478bd9Sstevel@tonic-gate 	scf_property_destroy(prop);
171*7c478bd9Sstevel@tonic-gate 	return (iter);
172*7c478bd9Sstevel@tonic-gate error:
173*7c478bd9Sstevel@tonic-gate 	scf_property_destroy(prop);
174*7c478bd9Sstevel@tonic-gate 	scf_iter_destroy(iter);
175*7c478bd9Sstevel@tonic-gate 	return (NULL);
176*7c478bd9Sstevel@tonic-gate }
177*7c478bd9Sstevel@tonic-gate 
178*7c478bd9Sstevel@tonic-gate /*
179*7c478bd9Sstevel@tonic-gate  * Reads the next value from the multi-value property using the
180*7c478bd9Sstevel@tonic-gate  * scf_iter obtained by prop_walk_init, and places it in the buffer
181*7c478bd9Sstevel@tonic-gate  * pointed to by fmri.  Returns -1 on failure, 0 when done, and non-0
182*7c478bd9Sstevel@tonic-gate  * when returning a value.
183*7c478bd9Sstevel@tonic-gate  */
184*7c478bd9Sstevel@tonic-gate static int
185*7c478bd9Sstevel@tonic-gate prop_walk_step(scf_iter_t *iter, char *fmri, size_t len)
186*7c478bd9Sstevel@tonic-gate {
187*7c478bd9Sstevel@tonic-gate 	int r;
188*7c478bd9Sstevel@tonic-gate 	scf_value_t *val;
189*7c478bd9Sstevel@tonic-gate 
190*7c478bd9Sstevel@tonic-gate 	if ((val = scf_value_create(h)) == NULL)
191*7c478bd9Sstevel@tonic-gate 		scfdie();
192*7c478bd9Sstevel@tonic-gate 
193*7c478bd9Sstevel@tonic-gate 	r = scf_iter_next_value(iter, val);
194*7c478bd9Sstevel@tonic-gate 	if (r == 0)
195*7c478bd9Sstevel@tonic-gate 		goto out;
196*7c478bd9Sstevel@tonic-gate 	if (r == -1) {
197*7c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_DELETED)
198*7c478bd9Sstevel@tonic-gate 			scfdie();
199*7c478bd9Sstevel@tonic-gate 		goto out;
200*7c478bd9Sstevel@tonic-gate 	}
201*7c478bd9Sstevel@tonic-gate 	if (scf_value_get_astring(val, fmri, len) <= 0) {
202*7c478bd9Sstevel@tonic-gate 		r = -1;
203*7c478bd9Sstevel@tonic-gate 		goto out;
204*7c478bd9Sstevel@tonic-gate 	}
205*7c478bd9Sstevel@tonic-gate 
206*7c478bd9Sstevel@tonic-gate out:
207*7c478bd9Sstevel@tonic-gate 	scf_value_destroy(val);
208*7c478bd9Sstevel@tonic-gate 	return (r);
209*7c478bd9Sstevel@tonic-gate }
210*7c478bd9Sstevel@tonic-gate 
211*7c478bd9Sstevel@tonic-gate /*
212*7c478bd9Sstevel@tonic-gate  * Determines if a file dependency is satisfied, taking into account
213*7c478bd9Sstevel@tonic-gate  * whether it is an exclusion dependency or not.  If we can't access
214*7c478bd9Sstevel@tonic-gate  * the file, we err on the side of caution and assume the dependency
215*7c478bd9Sstevel@tonic-gate  * isn't satisfied.
216*7c478bd9Sstevel@tonic-gate  */
217*7c478bd9Sstevel@tonic-gate static int
218*7c478bd9Sstevel@tonic-gate file_has_potential(char *fmri, int exclude)
219*7c478bd9Sstevel@tonic-gate {
220*7c478bd9Sstevel@tonic-gate 	const char *path;
221*7c478bd9Sstevel@tonic-gate 	struct stat st;
222*7c478bd9Sstevel@tonic-gate 
223*7c478bd9Sstevel@tonic-gate 	int good = exclude ? B_FALSE : B_TRUE;
224*7c478bd9Sstevel@tonic-gate 
225*7c478bd9Sstevel@tonic-gate 	if (scf_parse_file_fmri(fmri, NULL, &path) != 0)
226*7c478bd9Sstevel@tonic-gate 		return (good);
227*7c478bd9Sstevel@tonic-gate 
228*7c478bd9Sstevel@tonic-gate 	if (stat(path, &st) == 0)
229*7c478bd9Sstevel@tonic-gate 		return (good);
230*7c478bd9Sstevel@tonic-gate 
231*7c478bd9Sstevel@tonic-gate 	if (errno == EACCES) {
232*7c478bd9Sstevel@tonic-gate 		uu_warn(gettext("Unable to access \"%s\".\n"), path);
233*7c478bd9Sstevel@tonic-gate 		return (B_FALSE);
234*7c478bd9Sstevel@tonic-gate 	}
235*7c478bd9Sstevel@tonic-gate 
236*7c478bd9Sstevel@tonic-gate 	return (!good);
237*7c478bd9Sstevel@tonic-gate }
238*7c478bd9Sstevel@tonic-gate 
239*7c478bd9Sstevel@tonic-gate /*
240*7c478bd9Sstevel@tonic-gate  * Determines if a dependency on a service instance is satisfiable.
241*7c478bd9Sstevel@tonic-gate  * Returns 0 if not, 1 if it is, or 2 if it is an optional or exclude
242*7c478bd9Sstevel@tonic-gate  * dependency and the service only "weakly" satisfies (i.e. is disabled
243*7c478bd9Sstevel@tonic-gate  * or is in maintenance state).
244*7c478bd9Sstevel@tonic-gate  */
245*7c478bd9Sstevel@tonic-gate static int
246*7c478bd9Sstevel@tonic-gate inst_has_potential(scf_instance_t *inst, int enabled, int optional, int exclude)
247*7c478bd9Sstevel@tonic-gate {
248*7c478bd9Sstevel@tonic-gate 	char state[MAX_SCF_STATE_STRING_SZ];
249*7c478bd9Sstevel@tonic-gate 
250*7c478bd9Sstevel@tonic-gate 	if (!enabled)
251*7c478bd9Sstevel@tonic-gate 		return ((optional || exclude) ? 2 : 0);
252*7c478bd9Sstevel@tonic-gate 
253*7c478bd9Sstevel@tonic-gate 	/*
254*7c478bd9Sstevel@tonic-gate 	 * Normally we would return a positive value on failure;
255*7c478bd9Sstevel@tonic-gate 	 * relying on startd to place the service in maintenance.  But
256*7c478bd9Sstevel@tonic-gate 	 * if we can't read a service's state, we have to assume it is
257*7c478bd9Sstevel@tonic-gate 	 * out to lunch.
258*7c478bd9Sstevel@tonic-gate 	 */
259*7c478bd9Sstevel@tonic-gate 	if (inst_get_state(inst, state, NULL, NULL) != 0)
260*7c478bd9Sstevel@tonic-gate 		return (0);
261*7c478bd9Sstevel@tonic-gate 
262*7c478bd9Sstevel@tonic-gate 	/*
263*7c478bd9Sstevel@tonic-gate 	 * Optional dependencies which are offline always have a possibility of
264*7c478bd9Sstevel@tonic-gate 	 * coming online.
265*7c478bd9Sstevel@tonic-gate 	 */
266*7c478bd9Sstevel@tonic-gate 	if (optional && strcmp(state, SCF_STATE_STRING_OFFLINE) == 0)
267*7c478bd9Sstevel@tonic-gate 		return (2);
268*7c478bd9Sstevel@tonic-gate 
269*7c478bd9Sstevel@tonic-gate 	if (strcmp(state, SCF_STATE_STRING_MAINT) == 0) {
270*7c478bd9Sstevel@tonic-gate 		/*
271*7c478bd9Sstevel@tonic-gate 		 * Enabled services in maintenance state satisfy
272*7c478bd9Sstevel@tonic-gate 		 * optional-all dependencies.
273*7c478bd9Sstevel@tonic-gate 		 */
274*7c478bd9Sstevel@tonic-gate 		return ((optional || exclude) ? 2 : 0);
275*7c478bd9Sstevel@tonic-gate 	}
276*7c478bd9Sstevel@tonic-gate 
277*7c478bd9Sstevel@tonic-gate 	/*
278*7c478bd9Sstevel@tonic-gate 	 * We're enabled and not in maintenance.
279*7c478bd9Sstevel@tonic-gate 	 */
280*7c478bd9Sstevel@tonic-gate 	if (exclude)
281*7c478bd9Sstevel@tonic-gate 		return (0);
282*7c478bd9Sstevel@tonic-gate 
283*7c478bd9Sstevel@tonic-gate 	if (strcmp(state, SCF_STATE_STRING_ONLINE) == 0 ||
284*7c478bd9Sstevel@tonic-gate 	    strcmp(state, SCF_STATE_STRING_DEGRADED) == 0)
285*7c478bd9Sstevel@tonic-gate 		return (1);
286*7c478bd9Sstevel@tonic-gate 
287*7c478bd9Sstevel@tonic-gate 	return (has_potential(inst, B_FALSE));
288*7c478bd9Sstevel@tonic-gate }
289*7c478bd9Sstevel@tonic-gate 
290*7c478bd9Sstevel@tonic-gate /*
291*7c478bd9Sstevel@tonic-gate  * Determines if a dependency on an fmri is satisfiable, handling the
292*7c478bd9Sstevel@tonic-gate  * separate cases for file, service, and instance fmris.  Returns false
293*7c478bd9Sstevel@tonic-gate  * if not, or true if it is.  Takes into account if the dependency is
294*7c478bd9Sstevel@tonic-gate  * an optional or exclusive one.
295*7c478bd9Sstevel@tonic-gate  */
296*7c478bd9Sstevel@tonic-gate static int
297*7c478bd9Sstevel@tonic-gate fmri_has_potential(char *fmri, int isfile, int optional, int exclude,
298*7c478bd9Sstevel@tonic-gate     int restarter)
299*7c478bd9Sstevel@tonic-gate {
300*7c478bd9Sstevel@tonic-gate 	scf_instance_t *inst;
301*7c478bd9Sstevel@tonic-gate 	scf_service_t *svc;
302*7c478bd9Sstevel@tonic-gate 	scf_iter_t *iter;
303*7c478bd9Sstevel@tonic-gate 	int good = exclude ? B_FALSE : B_TRUE;
304*7c478bd9Sstevel@tonic-gate 	int enabled;
305*7c478bd9Sstevel@tonic-gate 	int r, result;
306*7c478bd9Sstevel@tonic-gate 	int optbad;
307*7c478bd9Sstevel@tonic-gate 
308*7c478bd9Sstevel@tonic-gate 	assert(!optional || !exclude);
309*7c478bd9Sstevel@tonic-gate 
310*7c478bd9Sstevel@tonic-gate 	if (isfile)
311*7c478bd9Sstevel@tonic-gate 		return (file_has_potential(fmri, exclude));
312*7c478bd9Sstevel@tonic-gate 
313*7c478bd9Sstevel@tonic-gate 	if ((inst = scf_instance_create(h)) == NULL ||
314*7c478bd9Sstevel@tonic-gate 	    (svc = scf_service_create(h)) == NULL ||
315*7c478bd9Sstevel@tonic-gate 	    (iter = scf_iter_create(h)) == NULL)
316*7c478bd9Sstevel@tonic-gate 		scfdie();
317*7c478bd9Sstevel@tonic-gate 
318*7c478bd9Sstevel@tonic-gate 	if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL, NULL,
319*7c478bd9Sstevel@tonic-gate 	    SCF_DECODE_FMRI_EXACT) == 0) {
320*7c478bd9Sstevel@tonic-gate 		enabled = is_enabled(inst);
321*7c478bd9Sstevel@tonic-gate 		result =
322*7c478bd9Sstevel@tonic-gate 		    (inst_has_potential(inst, enabled, optional, exclude) != 0);
323*7c478bd9Sstevel@tonic-gate 		goto out;
324*7c478bd9Sstevel@tonic-gate 	}
325*7c478bd9Sstevel@tonic-gate 
326*7c478bd9Sstevel@tonic-gate 	if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL,
327*7c478bd9Sstevel@tonic-gate 	    SCF_DECODE_FMRI_EXACT) != 0) {
328*7c478bd9Sstevel@tonic-gate 		/*
329*7c478bd9Sstevel@tonic-gate 		 * If we are checking a restarter dependency, a bad
330*7c478bd9Sstevel@tonic-gate 		 * or nonexistent service will never be noticed.
331*7c478bd9Sstevel@tonic-gate 		 */
332*7c478bd9Sstevel@tonic-gate 		result = restarter ? B_FALSE : good;
333*7c478bd9Sstevel@tonic-gate 		goto out;
334*7c478bd9Sstevel@tonic-gate 	}
335*7c478bd9Sstevel@tonic-gate 
336*7c478bd9Sstevel@tonic-gate 	if (scf_iter_service_instances(iter, svc) != 0) {
337*7c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_DELETED)
338*7c478bd9Sstevel@tonic-gate 			scfdie();
339*7c478bd9Sstevel@tonic-gate 		result = good;
340*7c478bd9Sstevel@tonic-gate 		goto out;
341*7c478bd9Sstevel@tonic-gate 	}
342*7c478bd9Sstevel@tonic-gate 
343*7c478bd9Sstevel@tonic-gate 	optbad = 0;
344*7c478bd9Sstevel@tonic-gate 	for (;;) {
345*7c478bd9Sstevel@tonic-gate 		r = scf_iter_next_instance(iter, inst);
346*7c478bd9Sstevel@tonic-gate 		if (r == 0) {
347*7c478bd9Sstevel@tonic-gate 			result = exclude || (optional && !optbad);
348*7c478bd9Sstevel@tonic-gate 			goto out;
349*7c478bd9Sstevel@tonic-gate 		}
350*7c478bd9Sstevel@tonic-gate 		if (r == -1) {
351*7c478bd9Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_DELETED)
352*7c478bd9Sstevel@tonic-gate 				scfdie();
353*7c478bd9Sstevel@tonic-gate 			result = good;
354*7c478bd9Sstevel@tonic-gate 			goto out;
355*7c478bd9Sstevel@tonic-gate 		}
356*7c478bd9Sstevel@tonic-gate 
357*7c478bd9Sstevel@tonic-gate 		enabled = is_enabled(inst);
358*7c478bd9Sstevel@tonic-gate 		r = inst_has_potential(inst, enabled, optional, exclude);
359*7c478bd9Sstevel@tonic-gate 
360*7c478bd9Sstevel@tonic-gate 		/*
361*7c478bd9Sstevel@tonic-gate 		 * Exclusion dependencies over services map to
362*7c478bd9Sstevel@tonic-gate 		 * require-none for its instances.
363*7c478bd9Sstevel@tonic-gate 		 */
364*7c478bd9Sstevel@tonic-gate 		if (exclude)
365*7c478bd9Sstevel@tonic-gate 			r = (r == 0);
366*7c478bd9Sstevel@tonic-gate 
367*7c478bd9Sstevel@tonic-gate 		if (r == 1) {
368*7c478bd9Sstevel@tonic-gate 			/*
369*7c478bd9Sstevel@tonic-gate 			 * Remember, if this is an exclusion dependency
370*7c478bd9Sstevel@tonic-gate 			 * (which means we are here because there
371*7c478bd9Sstevel@tonic-gate 			 * exists an instance which wasn't satisfiable
372*7c478bd9Sstevel@tonic-gate 			 * in that regard), good means bad.
373*7c478bd9Sstevel@tonic-gate 			 */
374*7c478bd9Sstevel@tonic-gate 			result = good;
375*7c478bd9Sstevel@tonic-gate 			goto out;
376*7c478bd9Sstevel@tonic-gate 		}
377*7c478bd9Sstevel@tonic-gate 
378*7c478bd9Sstevel@tonic-gate 		if (optional && r == 0)
379*7c478bd9Sstevel@tonic-gate 			optbad = 1;
380*7c478bd9Sstevel@tonic-gate 	}
381*7c478bd9Sstevel@tonic-gate 
382*7c478bd9Sstevel@tonic-gate out:
383*7c478bd9Sstevel@tonic-gate 	scf_instance_destroy(inst);
384*7c478bd9Sstevel@tonic-gate 	scf_service_destroy(svc);
385*7c478bd9Sstevel@tonic-gate 	scf_iter_destroy(iter);
386*7c478bd9Sstevel@tonic-gate 	return (result);
387*7c478bd9Sstevel@tonic-gate }
388*7c478bd9Sstevel@tonic-gate 
389*7c478bd9Sstevel@tonic-gate static int
390*7c478bd9Sstevel@tonic-gate eval_require_any(scf_iter_t *iter, char *value, size_t value_sz, int isfile)
391*7c478bd9Sstevel@tonic-gate {
392*7c478bd9Sstevel@tonic-gate 	int r, empty = B_TRUE;
393*7c478bd9Sstevel@tonic-gate 
394*7c478bd9Sstevel@tonic-gate 	for (;;) {
395*7c478bd9Sstevel@tonic-gate 		/*
396*7c478bd9Sstevel@tonic-gate 		 * For reasons unknown, an empty require_any dependency
397*7c478bd9Sstevel@tonic-gate 		 * group is considered by startd to be satisfied.
398*7c478bd9Sstevel@tonic-gate 		 * This insanity fortunately doesn't extend to
399*7c478bd9Sstevel@tonic-gate 		 * dependencies on services with no instances.
400*7c478bd9Sstevel@tonic-gate 		 */
401*7c478bd9Sstevel@tonic-gate 		if ((r = prop_walk_step(iter, value, value_sz)) <= 0)
402*7c478bd9Sstevel@tonic-gate 			return ((r == 0 && empty) ? B_TRUE : r);
403*7c478bd9Sstevel@tonic-gate 		if (fmri_has_potential(value, isfile, B_FALSE, B_FALSE,
404*7c478bd9Sstevel@tonic-gate 		    B_FALSE))
405*7c478bd9Sstevel@tonic-gate 			return (1);
406*7c478bd9Sstevel@tonic-gate 		empty = B_FALSE;
407*7c478bd9Sstevel@tonic-gate 	}
408*7c478bd9Sstevel@tonic-gate }
409*7c478bd9Sstevel@tonic-gate 
410*7c478bd9Sstevel@tonic-gate static int
411*7c478bd9Sstevel@tonic-gate eval_all(scf_iter_t *iter, char *value, size_t value_sz,
412*7c478bd9Sstevel@tonic-gate     int isfile, int optional, int exclude)
413*7c478bd9Sstevel@tonic-gate {
414*7c478bd9Sstevel@tonic-gate 	int r;
415*7c478bd9Sstevel@tonic-gate 
416*7c478bd9Sstevel@tonic-gate 	for (;;) {
417*7c478bd9Sstevel@tonic-gate 		if ((r = prop_walk_step(iter, value, value_sz)) <= 0)
418*7c478bd9Sstevel@tonic-gate 			return ((r == 0) ? 1 : r);
419*7c478bd9Sstevel@tonic-gate 		if (!fmri_has_potential(value, isfile, optional, exclude,
420*7c478bd9Sstevel@tonic-gate 		    B_FALSE))
421*7c478bd9Sstevel@tonic-gate 			return (0);
422*7c478bd9Sstevel@tonic-gate 	}
423*7c478bd9Sstevel@tonic-gate }
424*7c478bd9Sstevel@tonic-gate 
425*7c478bd9Sstevel@tonic-gate static int
426*7c478bd9Sstevel@tonic-gate eval_require_all(scf_iter_t *iter, char *value, size_t value_sz, int isfile)
427*7c478bd9Sstevel@tonic-gate {
428*7c478bd9Sstevel@tonic-gate 	return (eval_all(iter, value, value_sz, isfile, B_FALSE, B_FALSE));
429*7c478bd9Sstevel@tonic-gate }
430*7c478bd9Sstevel@tonic-gate 
431*7c478bd9Sstevel@tonic-gate static int
432*7c478bd9Sstevel@tonic-gate eval_optional_all(scf_iter_t *iter, char *value, size_t value_sz, int isfile)
433*7c478bd9Sstevel@tonic-gate {
434*7c478bd9Sstevel@tonic-gate 	return (eval_all(iter, value, value_sz, isfile, B_TRUE, B_FALSE));
435*7c478bd9Sstevel@tonic-gate }
436*7c478bd9Sstevel@tonic-gate 
437*7c478bd9Sstevel@tonic-gate static int
438*7c478bd9Sstevel@tonic-gate eval_exclude_all(scf_iter_t *iter, char *value, size_t value_sz, int isfile)
439*7c478bd9Sstevel@tonic-gate {
440*7c478bd9Sstevel@tonic-gate 	return (eval_all(iter, value, value_sz, isfile, B_FALSE, B_TRUE));
441*7c478bd9Sstevel@tonic-gate }
442*7c478bd9Sstevel@tonic-gate 
443*7c478bd9Sstevel@tonic-gate /*
444*7c478bd9Sstevel@tonic-gate  * Examines the state and health of an instance's restarter and
445*7c478bd9Sstevel@tonic-gate  * dependencies, and determines the impact of both on the instance's
446*7c478bd9Sstevel@tonic-gate  * ability to be brought on line.  A true return value indicates that
447*7c478bd9Sstevel@tonic-gate  * instance appears to be a likely candidate for the online club.
448*7c478bd9Sstevel@tonic-gate  * False indicates that there is no hope for the instance.
449*7c478bd9Sstevel@tonic-gate  */
450*7c478bd9Sstevel@tonic-gate int
451*7c478bd9Sstevel@tonic-gate has_potential(scf_instance_t *inst, int restarter_only)
452*7c478bd9Sstevel@tonic-gate {
453*7c478bd9Sstevel@tonic-gate 	scf_snapshot_t *snap;
454*7c478bd9Sstevel@tonic-gate 	scf_iter_t *iter, *viter = NULL;
455*7c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg;
456*7c478bd9Sstevel@tonic-gate 	scf_property_t *prop;
457*7c478bd9Sstevel@tonic-gate 	scf_value_t *val;
458*7c478bd9Sstevel@tonic-gate 	char *type = NULL, *grouping = NULL;
459*7c478bd9Sstevel@tonic-gate 	char *value;
460*7c478bd9Sstevel@tonic-gate 	size_t value_sz;
461*7c478bd9Sstevel@tonic-gate 	int result = B_TRUE, r;
462*7c478bd9Sstevel@tonic-gate 	int isfile;
463*7c478bd9Sstevel@tonic-gate 
464*7c478bd9Sstevel@tonic-gate 	value_sz = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
465*7c478bd9Sstevel@tonic-gate 	if ((iter = scf_iter_create(h)) == NULL ||
466*7c478bd9Sstevel@tonic-gate 	    (snap = scf_snapshot_create(h)) == NULL ||
467*7c478bd9Sstevel@tonic-gate 	    (pg = scf_pg_create(h)) == NULL ||
468*7c478bd9Sstevel@tonic-gate 	    (val = scf_value_create(h)) == NULL ||
469*7c478bd9Sstevel@tonic-gate 	    (prop = scf_property_create(h)) == NULL ||
470*7c478bd9Sstevel@tonic-gate 	    (value = malloc(value_sz)) == NULL)
471*7c478bd9Sstevel@tonic-gate 		scfdie();
472*7c478bd9Sstevel@tonic-gate 
473*7c478bd9Sstevel@tonic-gate 	/*
474*7c478bd9Sstevel@tonic-gate 	 * First we check our restarter as an implicit dependency.
475*7c478bd9Sstevel@tonic-gate 	 */
476*7c478bd9Sstevel@tonic-gate 	if (scf_instance_get_pg_composed(inst, NULL, SCF_PG_GENERAL, pg) != 0)
477*7c478bd9Sstevel@tonic-gate 		scfdie();
478*7c478bd9Sstevel@tonic-gate 
479*7c478bd9Sstevel@tonic-gate 	r = get_astring_prop(pg, SCF_PROPERTY_RESTARTER, prop, val, value,
480*7c478bd9Sstevel@tonic-gate 	    value_sz);
481*7c478bd9Sstevel@tonic-gate 	if (r == -ENOENT) {
482*7c478bd9Sstevel@tonic-gate 		(void) strlcpy(value, SCF_SERVICE_STARTD, value_sz);
483*7c478bd9Sstevel@tonic-gate 	} else if (r < 0 || r > max_scf_fmri_sz) {
484*7c478bd9Sstevel@tonic-gate 		/*
485*7c478bd9Sstevel@tonic-gate 		 * Normally we would return true and let the restarter
486*7c478bd9Sstevel@tonic-gate 		 * tell our caller there is a problem by changing the
487*7c478bd9Sstevel@tonic-gate 		 * instance's state, but that's not going to happen if
488*7c478bd9Sstevel@tonic-gate 		 * the restarter is invalid.
489*7c478bd9Sstevel@tonic-gate 		 */
490*7c478bd9Sstevel@tonic-gate 		result = B_FALSE;
491*7c478bd9Sstevel@tonic-gate 		goto out;
492*7c478bd9Sstevel@tonic-gate 	}
493*7c478bd9Sstevel@tonic-gate 
494*7c478bd9Sstevel@tonic-gate 	if (!fmri_has_potential(value, B_FALSE, B_FALSE, B_FALSE, B_TRUE)) {
495*7c478bd9Sstevel@tonic-gate 		result = B_FALSE;
496*7c478bd9Sstevel@tonic-gate 		goto out;
497*7c478bd9Sstevel@tonic-gate 	}
498*7c478bd9Sstevel@tonic-gate 
499*7c478bd9Sstevel@tonic-gate 	if (restarter_only)
500*7c478bd9Sstevel@tonic-gate 		goto out;
501*7c478bd9Sstevel@tonic-gate 
502*7c478bd9Sstevel@tonic-gate 	/*
503*7c478bd9Sstevel@tonic-gate 	 * Now we check explicit dependencies.
504*7c478bd9Sstevel@tonic-gate 	 */
505*7c478bd9Sstevel@tonic-gate 	if (scf_instance_get_snapshot(inst, "running", snap) != 0) {
506*7c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND)
507*7c478bd9Sstevel@tonic-gate 			scfdie();
508*7c478bd9Sstevel@tonic-gate 		scf_snapshot_destroy(snap);
509*7c478bd9Sstevel@tonic-gate 		snap = NULL;
510*7c478bd9Sstevel@tonic-gate 	}
511*7c478bd9Sstevel@tonic-gate 
512*7c478bd9Sstevel@tonic-gate 	if (scf_iter_instance_pgs_typed_composed(iter, inst, snap,
513*7c478bd9Sstevel@tonic-gate 	    SCF_GROUP_DEPENDENCY) != 0) {
514*7c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_DELETED)
515*7c478bd9Sstevel@tonic-gate 			scfdie();
516*7c478bd9Sstevel@tonic-gate 		goto out;
517*7c478bd9Sstevel@tonic-gate 	}
518*7c478bd9Sstevel@tonic-gate 
519*7c478bd9Sstevel@tonic-gate 	for (;;) {
520*7c478bd9Sstevel@tonic-gate 		r = scf_iter_next_pg(iter, pg);
521*7c478bd9Sstevel@tonic-gate 		if (r == 0)
522*7c478bd9Sstevel@tonic-gate 			break;
523*7c478bd9Sstevel@tonic-gate 		if (r == -1) {
524*7c478bd9Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_DELETED)
525*7c478bd9Sstevel@tonic-gate 				scfdie();
526*7c478bd9Sstevel@tonic-gate 			goto out;
527*7c478bd9Sstevel@tonic-gate 		}
528*7c478bd9Sstevel@tonic-gate 
529*7c478bd9Sstevel@tonic-gate 		if ((grouping = read_astring_prop(pg, val, prop,
530*7c478bd9Sstevel@tonic-gate 		    SCF_PROPERTY_GROUPING)) == NULL)
531*7c478bd9Sstevel@tonic-gate 			goto out;
532*7c478bd9Sstevel@tonic-gate 
533*7c478bd9Sstevel@tonic-gate 		if ((type = read_astring_prop(pg, val, prop,
534*7c478bd9Sstevel@tonic-gate 		    SCF_PROPERTY_TYPE)) == NULL)
535*7c478bd9Sstevel@tonic-gate 			goto out;
536*7c478bd9Sstevel@tonic-gate 
537*7c478bd9Sstevel@tonic-gate 		if (strcmp(type, "path") == 0) {
538*7c478bd9Sstevel@tonic-gate 			isfile = B_TRUE;
539*7c478bd9Sstevel@tonic-gate 		} else if (strcmp(type, "service") == 0) {
540*7c478bd9Sstevel@tonic-gate 			isfile = B_FALSE;
541*7c478bd9Sstevel@tonic-gate 		} else {
542*7c478bd9Sstevel@tonic-gate 			free(type);
543*7c478bd9Sstevel@tonic-gate 			goto out;
544*7c478bd9Sstevel@tonic-gate 		}
545*7c478bd9Sstevel@tonic-gate 		free(type);
546*7c478bd9Sstevel@tonic-gate 
547*7c478bd9Sstevel@tonic-gate 		if ((viter = prop_walk_init(pg, SCF_PROPERTY_ENTITIES)) == NULL)
548*7c478bd9Sstevel@tonic-gate 			goto out;
549*7c478bd9Sstevel@tonic-gate 
550*7c478bd9Sstevel@tonic-gate 		if (strcmp(grouping, SCF_DEP_REQUIRE_ALL) == 0) {
551*7c478bd9Sstevel@tonic-gate 			r = eval_require_all(viter, value, value_sz, isfile);
552*7c478bd9Sstevel@tonic-gate 		} else if (strcmp(grouping, SCF_DEP_REQUIRE_ANY) == 0) {
553*7c478bd9Sstevel@tonic-gate 			r = eval_require_any(viter, value, value_sz, isfile);
554*7c478bd9Sstevel@tonic-gate 		} else if (strcmp(grouping, SCF_DEP_EXCLUDE_ALL) == 0) {
555*7c478bd9Sstevel@tonic-gate 			r = eval_exclude_all(viter, value, value_sz, isfile);
556*7c478bd9Sstevel@tonic-gate 		} else if (strcmp(grouping, SCF_DEP_OPTIONAL_ALL) == 0) {
557*7c478bd9Sstevel@tonic-gate 			r = eval_optional_all(viter, value, value_sz, isfile);
558*7c478bd9Sstevel@tonic-gate 		} else {
559*7c478bd9Sstevel@tonic-gate 			scf_iter_destroy(viter);
560*7c478bd9Sstevel@tonic-gate 			free(grouping);
561*7c478bd9Sstevel@tonic-gate 			grouping = NULL;
562*7c478bd9Sstevel@tonic-gate 			goto out;
563*7c478bd9Sstevel@tonic-gate 		}
564*7c478bd9Sstevel@tonic-gate 
565*7c478bd9Sstevel@tonic-gate 		scf_iter_destroy(viter);
566*7c478bd9Sstevel@tonic-gate 		free(grouping);
567*7c478bd9Sstevel@tonic-gate 		grouping = NULL;
568*7c478bd9Sstevel@tonic-gate 
569*7c478bd9Sstevel@tonic-gate 		if (r == 0) {
570*7c478bd9Sstevel@tonic-gate 			result = B_FALSE;
571*7c478bd9Sstevel@tonic-gate 			goto out;
572*7c478bd9Sstevel@tonic-gate 		} else if (r == -1) {
573*7c478bd9Sstevel@tonic-gate 			goto out;
574*7c478bd9Sstevel@tonic-gate 		}
575*7c478bd9Sstevel@tonic-gate 	}
576*7c478bd9Sstevel@tonic-gate 
577*7c478bd9Sstevel@tonic-gate out:
578*7c478bd9Sstevel@tonic-gate 	free(value);
579*7c478bd9Sstevel@tonic-gate 	scf_property_destroy(prop);
580*7c478bd9Sstevel@tonic-gate 	scf_value_destroy(val);
581*7c478bd9Sstevel@tonic-gate 	scf_pg_destroy(pg);
582*7c478bd9Sstevel@tonic-gate 	if (snap != NULL)
583*7c478bd9Sstevel@tonic-gate 		scf_snapshot_destroy(snap);
584*7c478bd9Sstevel@tonic-gate 	if (grouping != NULL)
585*7c478bd9Sstevel@tonic-gate 		free(grouping);
586*7c478bd9Sstevel@tonic-gate 	scf_iter_destroy(iter);
587*7c478bd9Sstevel@tonic-gate 	return (result);
588*7c478bd9Sstevel@tonic-gate }
589