xref: /illumos-gate/usr/src/cmd/svc/svcadm/svcadm.c (revision 7c478bd95313f5f23a4c958a745db2134aa0324)
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  * svcadm - request adminstrative actions for service instances
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 
46*7c478bd9Sstevel@tonic-gate #ifndef TEXT_DOMAIN
47*7c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN	"SUNW_OST_OSCMD"
48*7c478bd9Sstevel@tonic-gate #endif /* TEXT_DOMAIN */
49*7c478bd9Sstevel@tonic-gate 
50*7c478bd9Sstevel@tonic-gate /* Must be a power of two */
51*7c478bd9Sstevel@tonic-gate #define	HT_BUCKETS	64
52*7c478bd9Sstevel@tonic-gate 
53*7c478bd9Sstevel@tonic-gate /*
54*7c478bd9Sstevel@tonic-gate  * Exit codes for enable and disable -s.
55*7c478bd9Sstevel@tonic-gate  */
56*7c478bd9Sstevel@tonic-gate #define	EXIT_SVC_FAILURE	3
57*7c478bd9Sstevel@tonic-gate #define	EXIT_DEP_FAILURE	4
58*7c478bd9Sstevel@tonic-gate 
59*7c478bd9Sstevel@tonic-gate /*
60*7c478bd9Sstevel@tonic-gate  * How long we will wait (in seconds) for a service to change state
61*7c478bd9Sstevel@tonic-gate  * before re-checking its dependencies.
62*7c478bd9Sstevel@tonic-gate  */
63*7c478bd9Sstevel@tonic-gate #define	WAIT_INTERVAL		3
64*7c478bd9Sstevel@tonic-gate 
65*7c478bd9Sstevel@tonic-gate #ifndef NDEBUG
66*7c478bd9Sstevel@tonic-gate #define	bad_error(func, err)	{					\
67*7c478bd9Sstevel@tonic-gate 	uu_warn("%s:%d: %s() failed with unexpected error %d.\n",	\
68*7c478bd9Sstevel@tonic-gate 	    __FILE__, __LINE__, (func), (err));				\
69*7c478bd9Sstevel@tonic-gate 	abort();							\
70*7c478bd9Sstevel@tonic-gate }
71*7c478bd9Sstevel@tonic-gate #else
72*7c478bd9Sstevel@tonic-gate #define	bad_error(func, err)	abort()
73*7c478bd9Sstevel@tonic-gate #endif
74*7c478bd9Sstevel@tonic-gate 
75*7c478bd9Sstevel@tonic-gate 
76*7c478bd9Sstevel@tonic-gate struct ht_elt {
77*7c478bd9Sstevel@tonic-gate 	struct ht_elt	*next;
78*7c478bd9Sstevel@tonic-gate 	boolean_t	active;
79*7c478bd9Sstevel@tonic-gate 	char		str[1];
80*7c478bd9Sstevel@tonic-gate };
81*7c478bd9Sstevel@tonic-gate 
82*7c478bd9Sstevel@tonic-gate 
83*7c478bd9Sstevel@tonic-gate scf_handle_t *h;
84*7c478bd9Sstevel@tonic-gate ssize_t max_scf_fmri_sz;
85*7c478bd9Sstevel@tonic-gate static const char *emsg_permission_denied;
86*7c478bd9Sstevel@tonic-gate static const char *emsg_nomem;
87*7c478bd9Sstevel@tonic-gate static const char *emsg_create_pg_perm_denied;
88*7c478bd9Sstevel@tonic-gate static const char *emsg_pg_perm_denied;
89*7c478bd9Sstevel@tonic-gate static const char *emsg_prop_perm_denied;
90*7c478bd9Sstevel@tonic-gate static const char *emsg_no_service;
91*7c478bd9Sstevel@tonic-gate 
92*7c478bd9Sstevel@tonic-gate static int exit_status = 0;
93*7c478bd9Sstevel@tonic-gate static int verbose = 0;
94*7c478bd9Sstevel@tonic-gate static char *scratch_fmri;
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate static struct ht_elt **visited;
97*7c478bd9Sstevel@tonic-gate 
98*7c478bd9Sstevel@tonic-gate /*
99*7c478bd9Sstevel@tonic-gate  * Visitors from synch.c, needed for enable -s and disable -s.
100*7c478bd9Sstevel@tonic-gate  */
101*7c478bd9Sstevel@tonic-gate extern int is_enabled(scf_instance_t *);
102*7c478bd9Sstevel@tonic-gate extern int has_potential(scf_instance_t *, int);
103*7c478bd9Sstevel@tonic-gate 
104*7c478bd9Sstevel@tonic-gate void
105*7c478bd9Sstevel@tonic-gate do_scfdie(int lineno)
106*7c478bd9Sstevel@tonic-gate {
107*7c478bd9Sstevel@tonic-gate 	scf_error_t err;
108*7c478bd9Sstevel@tonic-gate 
109*7c478bd9Sstevel@tonic-gate 	switch (err = scf_error()) {
110*7c478bd9Sstevel@tonic-gate 	case SCF_ERROR_CONNECTION_BROKEN:
111*7c478bd9Sstevel@tonic-gate 		uu_die(gettext("Connection to repository server broken.  "
112*7c478bd9Sstevel@tonic-gate 		    "Exiting.\n"));
113*7c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
114*7c478bd9Sstevel@tonic-gate 
115*7c478bd9Sstevel@tonic-gate 	case SCF_ERROR_BACKEND_READONLY:
116*7c478bd9Sstevel@tonic-gate 		uu_die(gettext("Repository is read-only.  Exiting.\n"));
117*7c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
118*7c478bd9Sstevel@tonic-gate 
119*7c478bd9Sstevel@tonic-gate 	default:
120*7c478bd9Sstevel@tonic-gate #ifdef NDEBUG
121*7c478bd9Sstevel@tonic-gate 		uu_die(gettext("Unexpected libscf error: %s.  Exiting.\n"),
122*7c478bd9Sstevel@tonic-gate 		    scf_strerror(err));
123*7c478bd9Sstevel@tonic-gate #else
124*7c478bd9Sstevel@tonic-gate 		uu_die("Unexpected libscf error on line %d: %s.\n", lineno,
125*7c478bd9Sstevel@tonic-gate 		    scf_strerror(err));
126*7c478bd9Sstevel@tonic-gate #endif
127*7c478bd9Sstevel@tonic-gate 	}
128*7c478bd9Sstevel@tonic-gate }
129*7c478bd9Sstevel@tonic-gate 
130*7c478bd9Sstevel@tonic-gate #define	scfdie()	do_scfdie(__LINE__)
131*7c478bd9Sstevel@tonic-gate 
132*7c478bd9Sstevel@tonic-gate static void
133*7c478bd9Sstevel@tonic-gate usage()
134*7c478bd9Sstevel@tonic-gate {
135*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(
136*7c478bd9Sstevel@tonic-gate 	"Usage: %1$s [-v] [cmd [args ... ]]\n\n"
137*7c478bd9Sstevel@tonic-gate 	"\t%1$s enable [-rst] <service> ...\t- enable and online service(s)\n"
138*7c478bd9Sstevel@tonic-gate 	"\t%1$s disable [-st] <service> ...\t- disable and offline service(s)\n"
139*7c478bd9Sstevel@tonic-gate 	"\t%1$s restart <service> ...\t\t- restart specified service(s)\n"
140*7c478bd9Sstevel@tonic-gate 	"\t%1$s refresh <service> ...\t\t- re-read service configuration\n"
141*7c478bd9Sstevel@tonic-gate 	"\t%1$s mark [-It] <state> <service> ...\t- set maintenance state\n"
142*7c478bd9Sstevel@tonic-gate 	"\t%1$s clear <service> ...\t\t- clear maintenance state\n"
143*7c478bd9Sstevel@tonic-gate 	"\t%1$s milestone [-d] <milestone>\t- advance to a service milestone\n"
144*7c478bd9Sstevel@tonic-gate 	"\n\t"
145*7c478bd9Sstevel@tonic-gate 	"Services can be specified using an FMRI, abbreviation, or fnmatch(5)\n"
146*7c478bd9Sstevel@tonic-gate 	"\tpattern, as shown in these examples for svc:/network/smtp:sendmail\n"
147*7c478bd9Sstevel@tonic-gate 	"\n"
148*7c478bd9Sstevel@tonic-gate 	"\t%1$s <cmd> svc:/network/smtp:sendmail\n"
149*7c478bd9Sstevel@tonic-gate 	"\t%1$s <cmd> network/smtp:sendmail\n"
150*7c478bd9Sstevel@tonic-gate 	"\t%1$s <cmd> network/*mail\n"
151*7c478bd9Sstevel@tonic-gate 	"\t%1$s <cmd> network/smtp\n"
152*7c478bd9Sstevel@tonic-gate 	"\t%1$s <cmd> smtp:sendmail\n"
153*7c478bd9Sstevel@tonic-gate 	"\t%1$s <cmd> smtp\n"
154*7c478bd9Sstevel@tonic-gate 	"\t%1$s <cmd> sendmail\n"), uu_getpname());
155*7c478bd9Sstevel@tonic-gate 
156*7c478bd9Sstevel@tonic-gate 	exit(UU_EXIT_USAGE);
157*7c478bd9Sstevel@tonic-gate }
158*7c478bd9Sstevel@tonic-gate 
159*7c478bd9Sstevel@tonic-gate 
160*7c478bd9Sstevel@tonic-gate /*
161*7c478bd9Sstevel@tonic-gate  * FMRI hash table for recursive enable.
162*7c478bd9Sstevel@tonic-gate  */
163*7c478bd9Sstevel@tonic-gate 
164*7c478bd9Sstevel@tonic-gate static uint32_t
165*7c478bd9Sstevel@tonic-gate hash_fmri(const char *str)
166*7c478bd9Sstevel@tonic-gate {
167*7c478bd9Sstevel@tonic-gate 	uint32_t h = 0, g;
168*7c478bd9Sstevel@tonic-gate 	const char *p;
169*7c478bd9Sstevel@tonic-gate 
170*7c478bd9Sstevel@tonic-gate 	/* Generic hash function from uts/common/os/modhash.c . */
171*7c478bd9Sstevel@tonic-gate 	for (p = str; *p != '\0'; ++p) {
172*7c478bd9Sstevel@tonic-gate 		h = (h << 4) + *p;
173*7c478bd9Sstevel@tonic-gate 		if ((g = (h & 0xf0000000)) != 0) {
174*7c478bd9Sstevel@tonic-gate 			h ^= (g >> 24);
175*7c478bd9Sstevel@tonic-gate 			h ^= g;
176*7c478bd9Sstevel@tonic-gate 		}
177*7c478bd9Sstevel@tonic-gate 	}
178*7c478bd9Sstevel@tonic-gate 
179*7c478bd9Sstevel@tonic-gate 	return (h);
180*7c478bd9Sstevel@tonic-gate }
181*7c478bd9Sstevel@tonic-gate 
182*7c478bd9Sstevel@tonic-gate /*
183*7c478bd9Sstevel@tonic-gate  * Return 1 if str has been visited, 0 if it has not, and -1 if memory could not
184*7c478bd9Sstevel@tonic-gate  * be allocated.
185*7c478bd9Sstevel@tonic-gate  */
186*7c478bd9Sstevel@tonic-gate static int
187*7c478bd9Sstevel@tonic-gate visited_find_or_add(const char *str, struct ht_elt **hep)
188*7c478bd9Sstevel@tonic-gate {
189*7c478bd9Sstevel@tonic-gate 	uint32_t h;
190*7c478bd9Sstevel@tonic-gate 	uint_t i;
191*7c478bd9Sstevel@tonic-gate 	struct ht_elt *he;
192*7c478bd9Sstevel@tonic-gate 
193*7c478bd9Sstevel@tonic-gate 	h = hash_fmri(str);
194*7c478bd9Sstevel@tonic-gate 	i = h & (HT_BUCKETS - 1);
195*7c478bd9Sstevel@tonic-gate 
196*7c478bd9Sstevel@tonic-gate 	for (he = visited[i]; he != NULL; he = he->next) {
197*7c478bd9Sstevel@tonic-gate 		if (strcmp(he->str, str) == 0) {
198*7c478bd9Sstevel@tonic-gate 			if (hep)
199*7c478bd9Sstevel@tonic-gate 				*hep = he;
200*7c478bd9Sstevel@tonic-gate 			return (1);
201*7c478bd9Sstevel@tonic-gate 		}
202*7c478bd9Sstevel@tonic-gate 	}
203*7c478bd9Sstevel@tonic-gate 
204*7c478bd9Sstevel@tonic-gate 	he = malloc(offsetof(struct ht_elt, str) + strlen(str) + 1);
205*7c478bd9Sstevel@tonic-gate 	if (he == NULL)
206*7c478bd9Sstevel@tonic-gate 		return (-1);
207*7c478bd9Sstevel@tonic-gate 
208*7c478bd9Sstevel@tonic-gate 	(void) strcpy(he->str, str);
209*7c478bd9Sstevel@tonic-gate 
210*7c478bd9Sstevel@tonic-gate 	he->next = visited[i];
211*7c478bd9Sstevel@tonic-gate 	visited[i] = he;
212*7c478bd9Sstevel@tonic-gate 
213*7c478bd9Sstevel@tonic-gate 	if (hep)
214*7c478bd9Sstevel@tonic-gate 		*hep = he;
215*7c478bd9Sstevel@tonic-gate 	return (0);
216*7c478bd9Sstevel@tonic-gate }
217*7c478bd9Sstevel@tonic-gate 
218*7c478bd9Sstevel@tonic-gate 
219*7c478bd9Sstevel@tonic-gate /*
220*7c478bd9Sstevel@tonic-gate  * Returns 0, ECANCELED if pg is deleted, ENOENT if propname doesn't exist,
221*7c478bd9Sstevel@tonic-gate  * EINVAL if the property is not of boolean type or has no values, and E2BIG
222*7c478bd9Sstevel@tonic-gate  * if it has more than one value.  *bp is set if 0 or E2BIG is returned.
223*7c478bd9Sstevel@tonic-gate  */
224*7c478bd9Sstevel@tonic-gate int
225*7c478bd9Sstevel@tonic-gate get_bool_prop(scf_propertygroup_t *pg, const char *propname, uint8_t *bp)
226*7c478bd9Sstevel@tonic-gate {
227*7c478bd9Sstevel@tonic-gate 	scf_property_t *prop;
228*7c478bd9Sstevel@tonic-gate 	scf_value_t *val;
229*7c478bd9Sstevel@tonic-gate 	int ret;
230*7c478bd9Sstevel@tonic-gate 
231*7c478bd9Sstevel@tonic-gate 	if ((prop = scf_property_create(h)) == NULL ||
232*7c478bd9Sstevel@tonic-gate 	    (val = scf_value_create(h)) == NULL)
233*7c478bd9Sstevel@tonic-gate 		scfdie();
234*7c478bd9Sstevel@tonic-gate 
235*7c478bd9Sstevel@tonic-gate 	if (scf_pg_get_property(pg, propname, prop) != 0) {
236*7c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
237*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
238*7c478bd9Sstevel@tonic-gate 			ret = ECANCELED;
239*7c478bd9Sstevel@tonic-gate 			goto out;
240*7c478bd9Sstevel@tonic-gate 
241*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
242*7c478bd9Sstevel@tonic-gate 			ret = ENOENT;
243*7c478bd9Sstevel@tonic-gate 			goto out;
244*7c478bd9Sstevel@tonic-gate 
245*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
246*7c478bd9Sstevel@tonic-gate 			assert(0);
247*7c478bd9Sstevel@tonic-gate 			abort();
248*7c478bd9Sstevel@tonic-gate 			/* NOTREACHED */
249*7c478bd9Sstevel@tonic-gate 
250*7c478bd9Sstevel@tonic-gate 		default:
251*7c478bd9Sstevel@tonic-gate 			scfdie();
252*7c478bd9Sstevel@tonic-gate 		}
253*7c478bd9Sstevel@tonic-gate 	}
254*7c478bd9Sstevel@tonic-gate 
255*7c478bd9Sstevel@tonic-gate 	if (scf_property_get_value(prop, val) == 0) {
256*7c478bd9Sstevel@tonic-gate 		ret = 0;
257*7c478bd9Sstevel@tonic-gate 	} else {
258*7c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
259*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
260*7c478bd9Sstevel@tonic-gate 			ret = ENOENT;
261*7c478bd9Sstevel@tonic-gate 			goto out;
262*7c478bd9Sstevel@tonic-gate 
263*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
264*7c478bd9Sstevel@tonic-gate 			ret = EINVAL;
265*7c478bd9Sstevel@tonic-gate 			goto out;
266*7c478bd9Sstevel@tonic-gate 
267*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_CONSTRAINT_VIOLATED:
268*7c478bd9Sstevel@tonic-gate 			ret = E2BIG;
269*7c478bd9Sstevel@tonic-gate 			break;
270*7c478bd9Sstevel@tonic-gate 
271*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
272*7c478bd9Sstevel@tonic-gate 			assert(0);
273*7c478bd9Sstevel@tonic-gate 			abort();
274*7c478bd9Sstevel@tonic-gate 			/* NOTREACHED */
275*7c478bd9Sstevel@tonic-gate 
276*7c478bd9Sstevel@tonic-gate 		default:
277*7c478bd9Sstevel@tonic-gate 			scfdie();
278*7c478bd9Sstevel@tonic-gate 		}
279*7c478bd9Sstevel@tonic-gate 	}
280*7c478bd9Sstevel@tonic-gate 
281*7c478bd9Sstevel@tonic-gate 	if (scf_value_get_boolean(val, bp) != 0) {
282*7c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_TYPE_MISMATCH)
283*7c478bd9Sstevel@tonic-gate 			scfdie();
284*7c478bd9Sstevel@tonic-gate 
285*7c478bd9Sstevel@tonic-gate 		ret = EINVAL;
286*7c478bd9Sstevel@tonic-gate 		goto out;
287*7c478bd9Sstevel@tonic-gate 	}
288*7c478bd9Sstevel@tonic-gate 
289*7c478bd9Sstevel@tonic-gate out:
290*7c478bd9Sstevel@tonic-gate 	scf_value_destroy(val);
291*7c478bd9Sstevel@tonic-gate 	scf_property_destroy(prop);
292*7c478bd9Sstevel@tonic-gate 	return (ret);
293*7c478bd9Sstevel@tonic-gate }
294*7c478bd9Sstevel@tonic-gate 
295*7c478bd9Sstevel@tonic-gate /*
296*7c478bd9Sstevel@tonic-gate  * Returns 0, EPERM, or EROFS.
297*7c478bd9Sstevel@tonic-gate  */
298*7c478bd9Sstevel@tonic-gate static int
299*7c478bd9Sstevel@tonic-gate set_bool_prop(scf_propertygroup_t *pg, const char *propname, boolean_t b)
300*7c478bd9Sstevel@tonic-gate {
301*7c478bd9Sstevel@tonic-gate 	scf_value_t *v;
302*7c478bd9Sstevel@tonic-gate 	scf_transaction_t *tx;
303*7c478bd9Sstevel@tonic-gate 	scf_transaction_entry_t *ent;
304*7c478bd9Sstevel@tonic-gate 	int ret = 0, r;
305*7c478bd9Sstevel@tonic-gate 
306*7c478bd9Sstevel@tonic-gate 	if ((tx = scf_transaction_create(h)) == NULL ||
307*7c478bd9Sstevel@tonic-gate 	    (ent = scf_entry_create(h)) == NULL ||
308*7c478bd9Sstevel@tonic-gate 	    (v = scf_value_create(h)) == NULL)
309*7c478bd9Sstevel@tonic-gate 		scfdie();
310*7c478bd9Sstevel@tonic-gate 
311*7c478bd9Sstevel@tonic-gate 	scf_value_set_boolean(v, b);
312*7c478bd9Sstevel@tonic-gate 
313*7c478bd9Sstevel@tonic-gate 	for (;;) {
314*7c478bd9Sstevel@tonic-gate 		if (scf_transaction_start(tx, pg) == -1) {
315*7c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
316*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
317*7c478bd9Sstevel@tonic-gate 				ret = EPERM;
318*7c478bd9Sstevel@tonic-gate 				goto out;
319*7c478bd9Sstevel@tonic-gate 
320*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_READONLY:
321*7c478bd9Sstevel@tonic-gate 				ret = EROFS;
322*7c478bd9Sstevel@tonic-gate 				goto out;
323*7c478bd9Sstevel@tonic-gate 
324*7c478bd9Sstevel@tonic-gate 			default:
325*7c478bd9Sstevel@tonic-gate 				scfdie();
326*7c478bd9Sstevel@tonic-gate 			}
327*7c478bd9Sstevel@tonic-gate 		}
328*7c478bd9Sstevel@tonic-gate 
329*7c478bd9Sstevel@tonic-gate 		if (scf_transaction_property_change_type(tx, ent, propname,
330*7c478bd9Sstevel@tonic-gate 		    SCF_TYPE_BOOLEAN) != 0) {
331*7c478bd9Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_NOT_FOUND)
332*7c478bd9Sstevel@tonic-gate 				scfdie();
333*7c478bd9Sstevel@tonic-gate 
334*7c478bd9Sstevel@tonic-gate 			if (scf_transaction_property_new(tx, ent, propname,
335*7c478bd9Sstevel@tonic-gate 			    SCF_TYPE_BOOLEAN) != 0)
336*7c478bd9Sstevel@tonic-gate 				scfdie();
337*7c478bd9Sstevel@tonic-gate 		}
338*7c478bd9Sstevel@tonic-gate 
339*7c478bd9Sstevel@tonic-gate 		r = scf_entry_add_value(ent, v);
340*7c478bd9Sstevel@tonic-gate 		assert(r == 0);
341*7c478bd9Sstevel@tonic-gate 
342*7c478bd9Sstevel@tonic-gate 		r = scf_transaction_commit(tx);
343*7c478bd9Sstevel@tonic-gate 		if (r == 1)
344*7c478bd9Sstevel@tonic-gate 			break;
345*7c478bd9Sstevel@tonic-gate 
346*7c478bd9Sstevel@tonic-gate 		scf_transaction_reset(tx);
347*7c478bd9Sstevel@tonic-gate 
348*7c478bd9Sstevel@tonic-gate 		if (r != 0) {
349*7c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
350*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
351*7c478bd9Sstevel@tonic-gate 				ret = EPERM;
352*7c478bd9Sstevel@tonic-gate 				goto out;
353*7c478bd9Sstevel@tonic-gate 
354*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_READONLY:
355*7c478bd9Sstevel@tonic-gate 				ret = EROFS;
356*7c478bd9Sstevel@tonic-gate 				goto out;
357*7c478bd9Sstevel@tonic-gate 
358*7c478bd9Sstevel@tonic-gate 			default:
359*7c478bd9Sstevel@tonic-gate 				scfdie();
360*7c478bd9Sstevel@tonic-gate 			}
361*7c478bd9Sstevel@tonic-gate 		}
362*7c478bd9Sstevel@tonic-gate 
363*7c478bd9Sstevel@tonic-gate 		if (scf_pg_update(pg) == -1)
364*7c478bd9Sstevel@tonic-gate 			scfdie();
365*7c478bd9Sstevel@tonic-gate 	}
366*7c478bd9Sstevel@tonic-gate 
367*7c478bd9Sstevel@tonic-gate out:
368*7c478bd9Sstevel@tonic-gate 	scf_transaction_destroy(tx);
369*7c478bd9Sstevel@tonic-gate 	scf_entry_destroy(ent);
370*7c478bd9Sstevel@tonic-gate 	scf_value_destroy(v);
371*7c478bd9Sstevel@tonic-gate 	return (ret);
372*7c478bd9Sstevel@tonic-gate }
373*7c478bd9Sstevel@tonic-gate 
374*7c478bd9Sstevel@tonic-gate /*
375*7c478bd9Sstevel@tonic-gate  * Gets the single astring value of the propname property of pg.  prop & v are
376*7c478bd9Sstevel@tonic-gate  * scratch space.  Returns the length of the string on success or
377*7c478bd9Sstevel@tonic-gate  *   -ENOENT - pg has no property named propname
378*7c478bd9Sstevel@tonic-gate  *   -E2BIG - property has no values or multiple values
379*7c478bd9Sstevel@tonic-gate  *   -EINVAL - property type is not compatible with astring
380*7c478bd9Sstevel@tonic-gate  */
381*7c478bd9Sstevel@tonic-gate ssize_t
382*7c478bd9Sstevel@tonic-gate get_astring_prop(const scf_propertygroup_t *pg, const char *propname,
383*7c478bd9Sstevel@tonic-gate     scf_property_t *prop, scf_value_t *v, char *buf, size_t bufsz)
384*7c478bd9Sstevel@tonic-gate {
385*7c478bd9Sstevel@tonic-gate 	ssize_t sz;
386*7c478bd9Sstevel@tonic-gate 
387*7c478bd9Sstevel@tonic-gate 	if (scf_pg_get_property(pg, propname, prop) != 0) {
388*7c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND)
389*7c478bd9Sstevel@tonic-gate 			scfdie();
390*7c478bd9Sstevel@tonic-gate 
391*7c478bd9Sstevel@tonic-gate 		return (-ENOENT);
392*7c478bd9Sstevel@tonic-gate 	}
393*7c478bd9Sstevel@tonic-gate 
394*7c478bd9Sstevel@tonic-gate 	if (scf_property_get_value(prop, v) != 0) {
395*7c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
396*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
397*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_CONSTRAINT_VIOLATED:
398*7c478bd9Sstevel@tonic-gate 			return (-E2BIG);
399*7c478bd9Sstevel@tonic-gate 
400*7c478bd9Sstevel@tonic-gate 		default:
401*7c478bd9Sstevel@tonic-gate 			scfdie();
402*7c478bd9Sstevel@tonic-gate 		}
403*7c478bd9Sstevel@tonic-gate 	}
404*7c478bd9Sstevel@tonic-gate 
405*7c478bd9Sstevel@tonic-gate 	sz = scf_value_get_astring(v, buf, bufsz);
406*7c478bd9Sstevel@tonic-gate 	if (sz < 0) {
407*7c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_TYPE_MISMATCH)
408*7c478bd9Sstevel@tonic-gate 			scfdie();
409*7c478bd9Sstevel@tonic-gate 
410*7c478bd9Sstevel@tonic-gate 		return (-EINVAL);
411*7c478bd9Sstevel@tonic-gate 	}
412*7c478bd9Sstevel@tonic-gate 
413*7c478bd9Sstevel@tonic-gate 	return (sz);
414*7c478bd9Sstevel@tonic-gate }
415*7c478bd9Sstevel@tonic-gate 
416*7c478bd9Sstevel@tonic-gate /*
417*7c478bd9Sstevel@tonic-gate  * Returns
418*7c478bd9Sstevel@tonic-gate  *   0 - success
419*7c478bd9Sstevel@tonic-gate  *   ECANCELED - pg was deleted
420*7c478bd9Sstevel@tonic-gate  *   EPERM - permission denied
421*7c478bd9Sstevel@tonic-gate  *   EACCES - access denied
422*7c478bd9Sstevel@tonic-gate  *   EROFS - readonly
423*7c478bd9Sstevel@tonic-gate  */
424*7c478bd9Sstevel@tonic-gate static int
425*7c478bd9Sstevel@tonic-gate delete_prop(scf_propertygroup_t *pg, const char *propname)
426*7c478bd9Sstevel@tonic-gate {
427*7c478bd9Sstevel@tonic-gate 	scf_transaction_t *tx;
428*7c478bd9Sstevel@tonic-gate 	scf_transaction_entry_t *ent;
429*7c478bd9Sstevel@tonic-gate 	int ret = 0, r;
430*7c478bd9Sstevel@tonic-gate 
431*7c478bd9Sstevel@tonic-gate 	if ((tx = scf_transaction_create(h)) == NULL ||
432*7c478bd9Sstevel@tonic-gate 	    (ent = scf_entry_create(h)) == NULL)
433*7c478bd9Sstevel@tonic-gate 		scfdie();
434*7c478bd9Sstevel@tonic-gate 
435*7c478bd9Sstevel@tonic-gate 	for (;;) {
436*7c478bd9Sstevel@tonic-gate 		if (scf_transaction_start(tx, pg) == -1) {
437*7c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
438*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_DELETED:
439*7c478bd9Sstevel@tonic-gate 				ret = ECANCELED;
440*7c478bd9Sstevel@tonic-gate 				goto out;
441*7c478bd9Sstevel@tonic-gate 
442*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
443*7c478bd9Sstevel@tonic-gate 				ret = EPERM;
444*7c478bd9Sstevel@tonic-gate 				goto out;
445*7c478bd9Sstevel@tonic-gate 
446*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_ACCESS:
447*7c478bd9Sstevel@tonic-gate 				ret = EACCES;
448*7c478bd9Sstevel@tonic-gate 				goto out;
449*7c478bd9Sstevel@tonic-gate 
450*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_READONLY:
451*7c478bd9Sstevel@tonic-gate 				ret = EROFS;
452*7c478bd9Sstevel@tonic-gate 				goto out;
453*7c478bd9Sstevel@tonic-gate 
454*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
455*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_HANDLE_MISMATCH:
456*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_BOUND:
457*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
458*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_IN_USE:
459*7c478bd9Sstevel@tonic-gate 			default:
460*7c478bd9Sstevel@tonic-gate 				scfdie();
461*7c478bd9Sstevel@tonic-gate 			}
462*7c478bd9Sstevel@tonic-gate 		}
463*7c478bd9Sstevel@tonic-gate 
464*7c478bd9Sstevel@tonic-gate 		if (scf_transaction_property_delete(tx, ent, propname) == -1)
465*7c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
466*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_DELETED:
467*7c478bd9Sstevel@tonic-gate 				ret = ECANCELED;
468*7c478bd9Sstevel@tonic-gate 				goto out;
469*7c478bd9Sstevel@tonic-gate 
470*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_FOUND:
471*7c478bd9Sstevel@tonic-gate 				ret = 0;
472*7c478bd9Sstevel@tonic-gate 				goto out;
473*7c478bd9Sstevel@tonic-gate 
474*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_HANDLE_MISMATCH:
475*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_BOUND:
476*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
477*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_INVALID_ARGUMENT:
478*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
479*7c478bd9Sstevel@tonic-gate 			default:
480*7c478bd9Sstevel@tonic-gate 				scfdie();
481*7c478bd9Sstevel@tonic-gate 			}
482*7c478bd9Sstevel@tonic-gate 
483*7c478bd9Sstevel@tonic-gate 		r = scf_transaction_commit(tx);
484*7c478bd9Sstevel@tonic-gate 		if (r == 1)
485*7c478bd9Sstevel@tonic-gate 			break;
486*7c478bd9Sstevel@tonic-gate 
487*7c478bd9Sstevel@tonic-gate 		scf_transaction_reset(tx);
488*7c478bd9Sstevel@tonic-gate 
489*7c478bd9Sstevel@tonic-gate 		if (r != 0) {
490*7c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
491*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_DELETED:
492*7c478bd9Sstevel@tonic-gate 				ret = ECANCELED;
493*7c478bd9Sstevel@tonic-gate 				goto out;
494*7c478bd9Sstevel@tonic-gate 
495*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
496*7c478bd9Sstevel@tonic-gate 				ret = EPERM;
497*7c478bd9Sstevel@tonic-gate 				goto out;
498*7c478bd9Sstevel@tonic-gate 
499*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_ACCESS:
500*7c478bd9Sstevel@tonic-gate 				ret = EACCES;
501*7c478bd9Sstevel@tonic-gate 				goto out;
502*7c478bd9Sstevel@tonic-gate 
503*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_READONLY:
504*7c478bd9Sstevel@tonic-gate 				ret = EROFS;
505*7c478bd9Sstevel@tonic-gate 				goto out;
506*7c478bd9Sstevel@tonic-gate 
507*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_INVALID_ARGUMENT:
508*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
509*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_BOUND:
510*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
511*7c478bd9Sstevel@tonic-gate 			default:
512*7c478bd9Sstevel@tonic-gate 				scfdie();
513*7c478bd9Sstevel@tonic-gate 			}
514*7c478bd9Sstevel@tonic-gate 		}
515*7c478bd9Sstevel@tonic-gate 
516*7c478bd9Sstevel@tonic-gate 		if (scf_pg_update(pg) == -1) {
517*7c478bd9Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_DELETED)
518*7c478bd9Sstevel@tonic-gate 				scfdie();
519*7c478bd9Sstevel@tonic-gate 
520*7c478bd9Sstevel@tonic-gate 			ret = ECANCELED;
521*7c478bd9Sstevel@tonic-gate 			goto out;
522*7c478bd9Sstevel@tonic-gate 		}
523*7c478bd9Sstevel@tonic-gate 	}
524*7c478bd9Sstevel@tonic-gate 
525*7c478bd9Sstevel@tonic-gate out:
526*7c478bd9Sstevel@tonic-gate 	scf_transaction_destroy(tx);
527*7c478bd9Sstevel@tonic-gate 	scf_entry_destroy(ent);
528*7c478bd9Sstevel@tonic-gate 	return (ret);
529*7c478bd9Sstevel@tonic-gate }
530*7c478bd9Sstevel@tonic-gate 
531*7c478bd9Sstevel@tonic-gate /*
532*7c478bd9Sstevel@tonic-gate  * Returns 0 or EPERM.
533*7c478bd9Sstevel@tonic-gate  */
534*7c478bd9Sstevel@tonic-gate static int
535*7c478bd9Sstevel@tonic-gate pg_get_or_add(scf_instance_t *inst, const char *pgname, const char *pgtype,
536*7c478bd9Sstevel@tonic-gate     uint32_t pgflags, scf_propertygroup_t *pg)
537*7c478bd9Sstevel@tonic-gate {
538*7c478bd9Sstevel@tonic-gate again:
539*7c478bd9Sstevel@tonic-gate 	if (scf_instance_get_pg(inst, pgname, pg) == 0)
540*7c478bd9Sstevel@tonic-gate 		return (0);
541*7c478bd9Sstevel@tonic-gate 
542*7c478bd9Sstevel@tonic-gate 	if (scf_error() != SCF_ERROR_NOT_FOUND)
543*7c478bd9Sstevel@tonic-gate 		scfdie();
544*7c478bd9Sstevel@tonic-gate 
545*7c478bd9Sstevel@tonic-gate 	if (scf_instance_add_pg(inst, pgname, pgtype, pgflags, pg) == 0)
546*7c478bd9Sstevel@tonic-gate 		return (0);
547*7c478bd9Sstevel@tonic-gate 
548*7c478bd9Sstevel@tonic-gate 	switch (scf_error()) {
549*7c478bd9Sstevel@tonic-gate 	case SCF_ERROR_EXISTS:
550*7c478bd9Sstevel@tonic-gate 		goto again;
551*7c478bd9Sstevel@tonic-gate 
552*7c478bd9Sstevel@tonic-gate 	case SCF_ERROR_PERMISSION_DENIED:
553*7c478bd9Sstevel@tonic-gate 		return (EPERM);
554*7c478bd9Sstevel@tonic-gate 
555*7c478bd9Sstevel@tonic-gate 	default:
556*7c478bd9Sstevel@tonic-gate 		scfdie();
557*7c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
558*7c478bd9Sstevel@tonic-gate 	}
559*7c478bd9Sstevel@tonic-gate }
560*7c478bd9Sstevel@tonic-gate 
561*7c478bd9Sstevel@tonic-gate /*
562*7c478bd9Sstevel@tonic-gate  * Enable or disable inst, per enable.  If temp is true, set
563*7c478bd9Sstevel@tonic-gate  * general_ovr/enabled.  Otherwise set general/enabled and delete
564*7c478bd9Sstevel@tonic-gate  * general_ovr/enabled if it exists (order is important here: we don't want the
565*7c478bd9Sstevel@tonic-gate  * enabled status to glitch).
566*7c478bd9Sstevel@tonic-gate  */
567*7c478bd9Sstevel@tonic-gate static void
568*7c478bd9Sstevel@tonic-gate set_inst_enabled(const char *fmri, scf_instance_t *inst, boolean_t temp,
569*7c478bd9Sstevel@tonic-gate     boolean_t enable)
570*7c478bd9Sstevel@tonic-gate {
571*7c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg;
572*7c478bd9Sstevel@tonic-gate 	uint8_t b;
573*7c478bd9Sstevel@tonic-gate 	const char *pgname = NULL;	/* For emsg_pg_perm_denied */
574*7c478bd9Sstevel@tonic-gate 	int r;
575*7c478bd9Sstevel@tonic-gate 
576*7c478bd9Sstevel@tonic-gate 	pg = scf_pg_create(h);
577*7c478bd9Sstevel@tonic-gate 	if (pg == NULL)
578*7c478bd9Sstevel@tonic-gate 		scfdie();
579*7c478bd9Sstevel@tonic-gate 
580*7c478bd9Sstevel@tonic-gate 	if (temp) {
581*7c478bd9Sstevel@tonic-gate 		/* Set general_ovr/enabled */
582*7c478bd9Sstevel@tonic-gate 		pgname = SCF_PG_GENERAL_OVR;
583*7c478bd9Sstevel@tonic-gate 		if (pg_get_or_add(inst, pgname, SCF_PG_GENERAL_OVR_TYPE,
584*7c478bd9Sstevel@tonic-gate 		    SCF_PG_GENERAL_OVR_FLAGS, pg) != 0)
585*7c478bd9Sstevel@tonic-gate 			goto eperm;
586*7c478bd9Sstevel@tonic-gate 
587*7c478bd9Sstevel@tonic-gate 		switch (set_bool_prop(pg, SCF_PROPERTY_ENABLED, enable) != 0) {
588*7c478bd9Sstevel@tonic-gate 		case 0:
589*7c478bd9Sstevel@tonic-gate 			break;
590*7c478bd9Sstevel@tonic-gate 
591*7c478bd9Sstevel@tonic-gate 		case EPERM:
592*7c478bd9Sstevel@tonic-gate 			goto eperm;
593*7c478bd9Sstevel@tonic-gate 
594*7c478bd9Sstevel@tonic-gate 		case EROFS:
595*7c478bd9Sstevel@tonic-gate 			/* Shouldn't happen, but it can. */
596*7c478bd9Sstevel@tonic-gate 			if (!verbose)
597*7c478bd9Sstevel@tonic-gate 				uu_warn(gettext("%s: Repository read-only.\n"),
598*7c478bd9Sstevel@tonic-gate 				    fmri);
599*7c478bd9Sstevel@tonic-gate 			else
600*7c478bd9Sstevel@tonic-gate 				uu_warn(gettext("%s: Could not set %s/%s "
601*7c478bd9Sstevel@tonic-gate 				    "(repository read-only).\n"), fmri,
602*7c478bd9Sstevel@tonic-gate 				    SCF_PG_GENERAL_OVR, SCF_PROPERTY_ENABLED);
603*7c478bd9Sstevel@tonic-gate 			goto out;
604*7c478bd9Sstevel@tonic-gate 
605*7c478bd9Sstevel@tonic-gate 		default:
606*7c478bd9Sstevel@tonic-gate 			assert(0);
607*7c478bd9Sstevel@tonic-gate 			abort();
608*7c478bd9Sstevel@tonic-gate 		}
609*7c478bd9Sstevel@tonic-gate 
610*7c478bd9Sstevel@tonic-gate 		if (verbose)
611*7c478bd9Sstevel@tonic-gate 			(void) printf(enable ?
612*7c478bd9Sstevel@tonic-gate 			    gettext("%s temporarily enabled.\n") :
613*7c478bd9Sstevel@tonic-gate 			    gettext("%s temporarily disabled.\n"), fmri);
614*7c478bd9Sstevel@tonic-gate 	} else {
615*7c478bd9Sstevel@tonic-gate again:
616*7c478bd9Sstevel@tonic-gate 		pgname = SCF_PG_GENERAL;
617*7c478bd9Sstevel@tonic-gate 		if (pg_get_or_add(inst, pgname, SCF_PG_GENERAL_TYPE,
618*7c478bd9Sstevel@tonic-gate 		    SCF_PG_GENERAL_FLAGS, pg) != 0)
619*7c478bd9Sstevel@tonic-gate 			goto eperm;
620*7c478bd9Sstevel@tonic-gate 
621*7c478bd9Sstevel@tonic-gate 		switch (set_bool_prop(pg, SCF_PROPERTY_ENABLED, enable)) {
622*7c478bd9Sstevel@tonic-gate 		case 0:
623*7c478bd9Sstevel@tonic-gate 			break;
624*7c478bd9Sstevel@tonic-gate 
625*7c478bd9Sstevel@tonic-gate 		case EPERM:
626*7c478bd9Sstevel@tonic-gate 			goto eperm;
627*7c478bd9Sstevel@tonic-gate 
628*7c478bd9Sstevel@tonic-gate 		case EROFS:
629*7c478bd9Sstevel@tonic-gate 			/*
630*7c478bd9Sstevel@tonic-gate 			 * If general/enabled is already set the way we want,
631*7c478bd9Sstevel@tonic-gate 			 * proceed.
632*7c478bd9Sstevel@tonic-gate 			 */
633*7c478bd9Sstevel@tonic-gate 			switch (get_bool_prop(pg, SCF_PROPERTY_ENABLED, &b)) {
634*7c478bd9Sstevel@tonic-gate 			case 0:
635*7c478bd9Sstevel@tonic-gate 				if ((b != 0) == (enable != B_FALSE))
636*7c478bd9Sstevel@tonic-gate 					break;
637*7c478bd9Sstevel@tonic-gate 				/* FALLTHROUGH */
638*7c478bd9Sstevel@tonic-gate 
639*7c478bd9Sstevel@tonic-gate 			case ENOENT:
640*7c478bd9Sstevel@tonic-gate 			case EINVAL:
641*7c478bd9Sstevel@tonic-gate 			case E2BIG:
642*7c478bd9Sstevel@tonic-gate 				if (!verbose)
643*7c478bd9Sstevel@tonic-gate 					uu_warn(gettext("%s: Repository "
644*7c478bd9Sstevel@tonic-gate 					    "read-only.\n"), fmri);
645*7c478bd9Sstevel@tonic-gate 				else
646*7c478bd9Sstevel@tonic-gate 					uu_warn(gettext("%s: Could not set "
647*7c478bd9Sstevel@tonic-gate 					    "%s/%s (repository read-only).\n"),
648*7c478bd9Sstevel@tonic-gate 					    fmri, SCF_PG_GENERAL,
649*7c478bd9Sstevel@tonic-gate 					    SCF_PROPERTY_ENABLED);
650*7c478bd9Sstevel@tonic-gate 				goto out;
651*7c478bd9Sstevel@tonic-gate 
652*7c478bd9Sstevel@tonic-gate 			case ECANCELED:
653*7c478bd9Sstevel@tonic-gate 				goto again;
654*7c478bd9Sstevel@tonic-gate 
655*7c478bd9Sstevel@tonic-gate 			default:
656*7c478bd9Sstevel@tonic-gate 				assert(0);
657*7c478bd9Sstevel@tonic-gate 				abort();
658*7c478bd9Sstevel@tonic-gate 			}
659*7c478bd9Sstevel@tonic-gate 			break;
660*7c478bd9Sstevel@tonic-gate 
661*7c478bd9Sstevel@tonic-gate 		default:
662*7c478bd9Sstevel@tonic-gate 			assert(0);
663*7c478bd9Sstevel@tonic-gate 			abort();
664*7c478bd9Sstevel@tonic-gate 		}
665*7c478bd9Sstevel@tonic-gate 
666*7c478bd9Sstevel@tonic-gate 		pgname = SCF_PG_GENERAL_OVR;
667*7c478bd9Sstevel@tonic-gate 		if (scf_instance_get_pg(inst, pgname, pg) == 0) {
668*7c478bd9Sstevel@tonic-gate 			r = delete_prop(pg, SCF_PROPERTY_ENABLED);
669*7c478bd9Sstevel@tonic-gate 			switch (r) {
670*7c478bd9Sstevel@tonic-gate 			case 0:
671*7c478bd9Sstevel@tonic-gate 				break;
672*7c478bd9Sstevel@tonic-gate 
673*7c478bd9Sstevel@tonic-gate 			case ECANCELED:
674*7c478bd9Sstevel@tonic-gate 				uu_warn(emsg_no_service, fmri);
675*7c478bd9Sstevel@tonic-gate 				goto out;
676*7c478bd9Sstevel@tonic-gate 
677*7c478bd9Sstevel@tonic-gate 			case EPERM:
678*7c478bd9Sstevel@tonic-gate 				goto eperm;
679*7c478bd9Sstevel@tonic-gate 
680*7c478bd9Sstevel@tonic-gate 			case EACCES:
681*7c478bd9Sstevel@tonic-gate 				uu_warn(gettext("Could not delete %s/%s "
682*7c478bd9Sstevel@tonic-gate 				    "property of %s: backend access denied.\n"),
683*7c478bd9Sstevel@tonic-gate 				    pgname, SCF_PROPERTY_ENABLED, fmri);
684*7c478bd9Sstevel@tonic-gate 				goto out;
685*7c478bd9Sstevel@tonic-gate 
686*7c478bd9Sstevel@tonic-gate 			case EROFS:
687*7c478bd9Sstevel@tonic-gate 				uu_warn(gettext("Could not delete %s/%s "
688*7c478bd9Sstevel@tonic-gate 				    "property of %s: backend is read-only.\n"),
689*7c478bd9Sstevel@tonic-gate 				    pgname, SCF_PROPERTY_ENABLED, fmri);
690*7c478bd9Sstevel@tonic-gate 				goto out;
691*7c478bd9Sstevel@tonic-gate 
692*7c478bd9Sstevel@tonic-gate 			default:
693*7c478bd9Sstevel@tonic-gate 				bad_error("delete_prop", r);
694*7c478bd9Sstevel@tonic-gate 			}
695*7c478bd9Sstevel@tonic-gate 		} else {
696*7c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
697*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_DELETED:
698*7c478bd9Sstevel@tonic-gate 				/* Print something? */
699*7c478bd9Sstevel@tonic-gate 
700*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_FOUND:
701*7c478bd9Sstevel@tonic-gate 				break;
702*7c478bd9Sstevel@tonic-gate 
703*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_HANDLE_MISMATCH:
704*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_INVALID_ARGUMENT:
705*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
706*7c478bd9Sstevel@tonic-gate 				assert(0);
707*7c478bd9Sstevel@tonic-gate 				abort();
708*7c478bd9Sstevel@tonic-gate 				/* NOTREACHED */
709*7c478bd9Sstevel@tonic-gate 
710*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
711*7c478bd9Sstevel@tonic-gate 			default:
712*7c478bd9Sstevel@tonic-gate 				scfdie();
713*7c478bd9Sstevel@tonic-gate 			}
714*7c478bd9Sstevel@tonic-gate 		}
715*7c478bd9Sstevel@tonic-gate 
716*7c478bd9Sstevel@tonic-gate 		if (verbose)
717*7c478bd9Sstevel@tonic-gate 			(void) printf(enable ?  gettext("%s enabled.\n") :
718*7c478bd9Sstevel@tonic-gate 			    gettext("%s disabled.\n"), fmri);
719*7c478bd9Sstevel@tonic-gate 	}
720*7c478bd9Sstevel@tonic-gate 
721*7c478bd9Sstevel@tonic-gate 	scf_pg_destroy(pg);
722*7c478bd9Sstevel@tonic-gate 	return;
723*7c478bd9Sstevel@tonic-gate 
724*7c478bd9Sstevel@tonic-gate eperm:
725*7c478bd9Sstevel@tonic-gate 	assert(pgname != NULL);
726*7c478bd9Sstevel@tonic-gate 	if (!verbose)
727*7c478bd9Sstevel@tonic-gate 		uu_warn(emsg_permission_denied, fmri);
728*7c478bd9Sstevel@tonic-gate 	else
729*7c478bd9Sstevel@tonic-gate 		uu_warn(emsg_pg_perm_denied, fmri, pgname);
730*7c478bd9Sstevel@tonic-gate 
731*7c478bd9Sstevel@tonic-gate out:
732*7c478bd9Sstevel@tonic-gate 	scf_pg_destroy(pg);
733*7c478bd9Sstevel@tonic-gate 	exit_status = 1;
734*7c478bd9Sstevel@tonic-gate }
735*7c478bd9Sstevel@tonic-gate 
736*7c478bd9Sstevel@tonic-gate /*
737*7c478bd9Sstevel@tonic-gate  * Set inst to the instance which corresponds to fmri.  If fmri identifies
738*7c478bd9Sstevel@tonic-gate  * a service with a single instance, get that instance.
739*7c478bd9Sstevel@tonic-gate  *
740*7c478bd9Sstevel@tonic-gate  * Fails with
741*7c478bd9Sstevel@tonic-gate  *   ENOTSUP - fmri has an unsupported scheme
742*7c478bd9Sstevel@tonic-gate  *   EINVAL - fmri is invalid
743*7c478bd9Sstevel@tonic-gate  *   ENOTDIR - fmri does not identify a service or instance
744*7c478bd9Sstevel@tonic-gate  *   ENOENT - could not locate instance
745*7c478bd9Sstevel@tonic-gate  *   E2BIG - fmri is a service with multiple instances (warning not printed)
746*7c478bd9Sstevel@tonic-gate  */
747*7c478bd9Sstevel@tonic-gate static int
748*7c478bd9Sstevel@tonic-gate get_inst_mult(const char *fmri, scf_instance_t *inst)
749*7c478bd9Sstevel@tonic-gate {
750*7c478bd9Sstevel@tonic-gate 	char *cfmri;
751*7c478bd9Sstevel@tonic-gate 	const char *svc_name, *inst_name, *pg_name;
752*7c478bd9Sstevel@tonic-gate 	scf_service_t *svc;
753*7c478bd9Sstevel@tonic-gate 	scf_instance_t *inst2;
754*7c478bd9Sstevel@tonic-gate 	scf_iter_t *iter;
755*7c478bd9Sstevel@tonic-gate 	int ret;
756*7c478bd9Sstevel@tonic-gate 
757*7c478bd9Sstevel@tonic-gate 	if (strncmp(fmri, "lrc:", sizeof ("lrc:") - 1) == 0) {
758*7c478bd9Sstevel@tonic-gate 		uu_warn(gettext("FMRI \"%s\" is a legacy service.\n"), fmri);
759*7c478bd9Sstevel@tonic-gate 		exit_status = 1;
760*7c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
761*7c478bd9Sstevel@tonic-gate 	}
762*7c478bd9Sstevel@tonic-gate 
763*7c478bd9Sstevel@tonic-gate 	cfmri = strdup(fmri);
764*7c478bd9Sstevel@tonic-gate 	if (cfmri == NULL)
765*7c478bd9Sstevel@tonic-gate 		uu_die(emsg_nomem);
766*7c478bd9Sstevel@tonic-gate 
767*7c478bd9Sstevel@tonic-gate 	if (scf_parse_svc_fmri(cfmri, NULL, &svc_name, &inst_name, &pg_name,
768*7c478bd9Sstevel@tonic-gate 	    NULL) != SCF_SUCCESS) {
769*7c478bd9Sstevel@tonic-gate 		free(cfmri);
770*7c478bd9Sstevel@tonic-gate 		uu_warn(gettext("FMRI \"%s\" is invalid.\n"), fmri);
771*7c478bd9Sstevel@tonic-gate 		exit_status = 1;
772*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
773*7c478bd9Sstevel@tonic-gate 	}
774*7c478bd9Sstevel@tonic-gate 
775*7c478bd9Sstevel@tonic-gate 	free(cfmri);
776*7c478bd9Sstevel@tonic-gate 
777*7c478bd9Sstevel@tonic-gate 	if (svc_name == NULL || pg_name != NULL) {
778*7c478bd9Sstevel@tonic-gate 		uu_warn(gettext(
779*7c478bd9Sstevel@tonic-gate 		    "FMRI \"%s\" does not designate a service or instance.\n"),
780*7c478bd9Sstevel@tonic-gate 		    fmri);
781*7c478bd9Sstevel@tonic-gate 		exit_status = 1;
782*7c478bd9Sstevel@tonic-gate 		return (ENOTDIR);
783*7c478bd9Sstevel@tonic-gate 	}
784*7c478bd9Sstevel@tonic-gate 
785*7c478bd9Sstevel@tonic-gate 	if (inst_name != NULL) {
786*7c478bd9Sstevel@tonic-gate 		if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
787*7c478bd9Sstevel@tonic-gate 		    NULL, SCF_DECODE_FMRI_EXACT) == 0)
788*7c478bd9Sstevel@tonic-gate 			return (0);
789*7c478bd9Sstevel@tonic-gate 
790*7c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND)
791*7c478bd9Sstevel@tonic-gate 			scfdie();
792*7c478bd9Sstevel@tonic-gate 
793*7c478bd9Sstevel@tonic-gate 		uu_warn(gettext("No such instance \"%s\".\n"), fmri);
794*7c478bd9Sstevel@tonic-gate 		exit_status = 1;
795*7c478bd9Sstevel@tonic-gate 
796*7c478bd9Sstevel@tonic-gate 		return (ENOENT);
797*7c478bd9Sstevel@tonic-gate 	}
798*7c478bd9Sstevel@tonic-gate 
799*7c478bd9Sstevel@tonic-gate 	if ((svc = scf_service_create(h)) == NULL ||
800*7c478bd9Sstevel@tonic-gate 	    (inst2 = scf_instance_create(h)) == NULL ||
801*7c478bd9Sstevel@tonic-gate 	    (iter = scf_iter_create(h)) == NULL)
802*7c478bd9Sstevel@tonic-gate 		scfdie();
803*7c478bd9Sstevel@tonic-gate 
804*7c478bd9Sstevel@tonic-gate 	if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL,
805*7c478bd9Sstevel@tonic-gate 	    SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
806*7c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND)
807*7c478bd9Sstevel@tonic-gate 			scfdie();
808*7c478bd9Sstevel@tonic-gate 
809*7c478bd9Sstevel@tonic-gate 		uu_warn(emsg_no_service, fmri);
810*7c478bd9Sstevel@tonic-gate 		exit_status = 1;
811*7c478bd9Sstevel@tonic-gate 
812*7c478bd9Sstevel@tonic-gate 		ret = ENOENT;
813*7c478bd9Sstevel@tonic-gate 		goto out;
814*7c478bd9Sstevel@tonic-gate 	}
815*7c478bd9Sstevel@tonic-gate 
816*7c478bd9Sstevel@tonic-gate 	/* If the service has only one child, use it. */
817*7c478bd9Sstevel@tonic-gate 	if (scf_iter_service_instances(iter, svc) != SCF_SUCCESS)
818*7c478bd9Sstevel@tonic-gate 		scfdie();
819*7c478bd9Sstevel@tonic-gate 
820*7c478bd9Sstevel@tonic-gate 	ret = scf_iter_next_instance(iter, inst);
821*7c478bd9Sstevel@tonic-gate 	if (ret < 0)
822*7c478bd9Sstevel@tonic-gate 		scfdie();
823*7c478bd9Sstevel@tonic-gate 	if (ret != 1) {
824*7c478bd9Sstevel@tonic-gate 		uu_warn(gettext("Service \"%s\" has no instances.\n"),
825*7c478bd9Sstevel@tonic-gate 		    fmri);
826*7c478bd9Sstevel@tonic-gate 		exit_status = 1;
827*7c478bd9Sstevel@tonic-gate 		ret = ENOENT;
828*7c478bd9Sstevel@tonic-gate 		goto out;
829*7c478bd9Sstevel@tonic-gate 	}
830*7c478bd9Sstevel@tonic-gate 
831*7c478bd9Sstevel@tonic-gate 	ret = scf_iter_next_instance(iter, inst2);
832*7c478bd9Sstevel@tonic-gate 	if (ret < 0)
833*7c478bd9Sstevel@tonic-gate 		scfdie();
834*7c478bd9Sstevel@tonic-gate 
835*7c478bd9Sstevel@tonic-gate 	if (ret != 0) {
836*7c478bd9Sstevel@tonic-gate 		ret = E2BIG;
837*7c478bd9Sstevel@tonic-gate 		goto out;
838*7c478bd9Sstevel@tonic-gate 	}
839*7c478bd9Sstevel@tonic-gate 
840*7c478bd9Sstevel@tonic-gate 	ret = 0;
841*7c478bd9Sstevel@tonic-gate 
842*7c478bd9Sstevel@tonic-gate out:
843*7c478bd9Sstevel@tonic-gate 	scf_iter_destroy(iter);
844*7c478bd9Sstevel@tonic-gate 	scf_instance_destroy(inst2);
845*7c478bd9Sstevel@tonic-gate 	scf_service_destroy(svc);
846*7c478bd9Sstevel@tonic-gate 	return (ret);
847*7c478bd9Sstevel@tonic-gate }
848*7c478bd9Sstevel@tonic-gate 
849*7c478bd9Sstevel@tonic-gate /*
850*7c478bd9Sstevel@tonic-gate  * Same as get_inst_mult(), but on E2BIG prints a warning and returns ENOENT.
851*7c478bd9Sstevel@tonic-gate  */
852*7c478bd9Sstevel@tonic-gate static int
853*7c478bd9Sstevel@tonic-gate get_inst(const char *fmri, scf_instance_t *inst)
854*7c478bd9Sstevel@tonic-gate {
855*7c478bd9Sstevel@tonic-gate 	int r;
856*7c478bd9Sstevel@tonic-gate 
857*7c478bd9Sstevel@tonic-gate 	r = get_inst_mult(fmri, inst);
858*7c478bd9Sstevel@tonic-gate 	if (r != E2BIG)
859*7c478bd9Sstevel@tonic-gate 		return (r);
860*7c478bd9Sstevel@tonic-gate 
861*7c478bd9Sstevel@tonic-gate 	uu_warn(gettext("operation on service %s is ambiguous; "
862*7c478bd9Sstevel@tonic-gate 	    "instance specification needed.\n"), fmri);
863*7c478bd9Sstevel@tonic-gate 	return (ENOENT);
864*7c478bd9Sstevel@tonic-gate }
865*7c478bd9Sstevel@tonic-gate 
866*7c478bd9Sstevel@tonic-gate static char *
867*7c478bd9Sstevel@tonic-gate inst_get_fmri(const scf_instance_t *inst)
868*7c478bd9Sstevel@tonic-gate {
869*7c478bd9Sstevel@tonic-gate 	ssize_t sz;
870*7c478bd9Sstevel@tonic-gate 
871*7c478bd9Sstevel@tonic-gate 	sz = scf_instance_to_fmri(inst, scratch_fmri, max_scf_fmri_sz);
872*7c478bd9Sstevel@tonic-gate 	if (sz < 0)
873*7c478bd9Sstevel@tonic-gate 		scfdie();
874*7c478bd9Sstevel@tonic-gate 	if (sz >= max_scf_fmri_sz)
875*7c478bd9Sstevel@tonic-gate 		uu_die(gettext("scf_instance_to_fmri() returned unexpectedly "
876*7c478bd9Sstevel@tonic-gate 		    "long value.\n"));
877*7c478bd9Sstevel@tonic-gate 
878*7c478bd9Sstevel@tonic-gate 	return (scratch_fmri);
879*7c478bd9Sstevel@tonic-gate }
880*7c478bd9Sstevel@tonic-gate 
881*7c478bd9Sstevel@tonic-gate static ssize_t
882*7c478bd9Sstevel@tonic-gate dep_get_astring(const char *fmri, const char *pgname,
883*7c478bd9Sstevel@tonic-gate     const scf_propertygroup_t *pg, const char *propname, scf_property_t *prop,
884*7c478bd9Sstevel@tonic-gate     scf_value_t *v, char *buf, size_t bufsz)
885*7c478bd9Sstevel@tonic-gate {
886*7c478bd9Sstevel@tonic-gate 	ssize_t sz;
887*7c478bd9Sstevel@tonic-gate 
888*7c478bd9Sstevel@tonic-gate 	sz = get_astring_prop(pg, propname, prop, v, buf, bufsz);
889*7c478bd9Sstevel@tonic-gate 	if (sz >= 0)
890*7c478bd9Sstevel@tonic-gate 		return (sz);
891*7c478bd9Sstevel@tonic-gate 
892*7c478bd9Sstevel@tonic-gate 	switch (-sz) {
893*7c478bd9Sstevel@tonic-gate 	case ENOENT:
894*7c478bd9Sstevel@tonic-gate 		uu_warn(gettext("\"%s\" is misconfigured (\"%s\" dependency "
895*7c478bd9Sstevel@tonic-gate 		    "lacks \"%s\" property.)\n"), fmri, pgname, propname);
896*7c478bd9Sstevel@tonic-gate 		return (-1);
897*7c478bd9Sstevel@tonic-gate 
898*7c478bd9Sstevel@tonic-gate 	case E2BIG:
899*7c478bd9Sstevel@tonic-gate 		uu_warn(gettext("\"%s\" is misconfigured (\"%s/%s\" property "
900*7c478bd9Sstevel@tonic-gate 		    "is not single-valued.)\n"), fmri, pgname, propname);
901*7c478bd9Sstevel@tonic-gate 		return (-1);
902*7c478bd9Sstevel@tonic-gate 
903*7c478bd9Sstevel@tonic-gate 	case EINVAL:
904*7c478bd9Sstevel@tonic-gate 		uu_warn(gettext("\"%s\" is misconfigured (\"%s/%s\" property "
905*7c478bd9Sstevel@tonic-gate 		    "is not of astring type.)\n"), fmri, pgname, propname);
906*7c478bd9Sstevel@tonic-gate 		return (-1);
907*7c478bd9Sstevel@tonic-gate 
908*7c478bd9Sstevel@tonic-gate 	default:
909*7c478bd9Sstevel@tonic-gate 		assert(0);
910*7c478bd9Sstevel@tonic-gate 		abort();
911*7c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
912*7c478bd9Sstevel@tonic-gate 	}
913*7c478bd9Sstevel@tonic-gate }
914*7c478bd9Sstevel@tonic-gate 
915*7c478bd9Sstevel@tonic-gate static boolean_t
916*7c478bd9Sstevel@tonic-gate multiple_instances(scf_iter_t *iter, scf_value_t *v, char *buf)
917*7c478bd9Sstevel@tonic-gate {
918*7c478bd9Sstevel@tonic-gate 	int count = 0, r;
919*7c478bd9Sstevel@tonic-gate 	boolean_t ret;
920*7c478bd9Sstevel@tonic-gate 	scf_instance_t *inst;
921*7c478bd9Sstevel@tonic-gate 
922*7c478bd9Sstevel@tonic-gate 	inst = scf_instance_create(h);
923*7c478bd9Sstevel@tonic-gate 	if (inst == NULL)
924*7c478bd9Sstevel@tonic-gate 		scfdie();
925*7c478bd9Sstevel@tonic-gate 
926*7c478bd9Sstevel@tonic-gate 	for (;;) {
927*7c478bd9Sstevel@tonic-gate 		r = scf_iter_next_value(iter, v);
928*7c478bd9Sstevel@tonic-gate 		if (r == 0) {
929*7c478bd9Sstevel@tonic-gate 			ret = B_FALSE;
930*7c478bd9Sstevel@tonic-gate 			goto out;
931*7c478bd9Sstevel@tonic-gate 		}
932*7c478bd9Sstevel@tonic-gate 		if (r != 1)
933*7c478bd9Sstevel@tonic-gate 			scfdie();
934*7c478bd9Sstevel@tonic-gate 
935*7c478bd9Sstevel@tonic-gate 		if (scf_value_get_astring(v, buf, max_scf_fmri_sz) < 0)
936*7c478bd9Sstevel@tonic-gate 			scfdie();
937*7c478bd9Sstevel@tonic-gate 
938*7c478bd9Sstevel@tonic-gate 		switch (get_inst_mult(buf, inst)) {
939*7c478bd9Sstevel@tonic-gate 		case 0:
940*7c478bd9Sstevel@tonic-gate 			++count;
941*7c478bd9Sstevel@tonic-gate 			if (count > 1) {
942*7c478bd9Sstevel@tonic-gate 				ret = B_TRUE;
943*7c478bd9Sstevel@tonic-gate 				goto out;
944*7c478bd9Sstevel@tonic-gate 			}
945*7c478bd9Sstevel@tonic-gate 			break;
946*7c478bd9Sstevel@tonic-gate 
947*7c478bd9Sstevel@tonic-gate 		case ENOTSUP:
948*7c478bd9Sstevel@tonic-gate 		case EINVAL:
949*7c478bd9Sstevel@tonic-gate 		case ENOTDIR:
950*7c478bd9Sstevel@tonic-gate 		case ENOENT:
951*7c478bd9Sstevel@tonic-gate 			continue;
952*7c478bd9Sstevel@tonic-gate 
953*7c478bd9Sstevel@tonic-gate 		case E2BIG:
954*7c478bd9Sstevel@tonic-gate 			ret = B_TRUE;
955*7c478bd9Sstevel@tonic-gate 			goto out;
956*7c478bd9Sstevel@tonic-gate 
957*7c478bd9Sstevel@tonic-gate 		default:
958*7c478bd9Sstevel@tonic-gate 			assert(0);
959*7c478bd9Sstevel@tonic-gate 			abort();
960*7c478bd9Sstevel@tonic-gate 		}
961*7c478bd9Sstevel@tonic-gate 	}
962*7c478bd9Sstevel@tonic-gate 
963*7c478bd9Sstevel@tonic-gate out:
964*7c478bd9Sstevel@tonic-gate 	scf_instance_destroy(inst);
965*7c478bd9Sstevel@tonic-gate 	return (ret);
966*7c478bd9Sstevel@tonic-gate }
967*7c478bd9Sstevel@tonic-gate 
968*7c478bd9Sstevel@tonic-gate /*
969*7c478bd9Sstevel@tonic-gate  * Enable the service or instance identified by fmri and its dependencies,
970*7c478bd9Sstevel@tonic-gate  * recursively.  Specifically, call get_inst(fmri), enable the result, and
971*7c478bd9Sstevel@tonic-gate  * recurse on its restarter and the dependencies.  To avoid duplication of
972*7c478bd9Sstevel@tonic-gate  * effort or looping around a dependency cycle, each FMRI is entered into the
973*7c478bd9Sstevel@tonic-gate  * "visited" hash table.  While recursing, the hash table entry is marked
974*7c478bd9Sstevel@tonic-gate  * "active", so that if we come upon it again, we know we've hit a cycle.
975*7c478bd9Sstevel@tonic-gate  * exclude_all and optional_all dependencies are ignored.  require_any
976*7c478bd9Sstevel@tonic-gate  * dependencies are followed only if they comprise a single service; otherwise
977*7c478bd9Sstevel@tonic-gate  * the user is warned.
978*7c478bd9Sstevel@tonic-gate  *
979*7c478bd9Sstevel@tonic-gate  * fmri must point to a writable max_scf_fmri_sz buffer.  Returns EINVAL if fmri
980*7c478bd9Sstevel@tonic-gate  * is invalid, E2BIG if fmri identifies a service with multiple instances, ELOOP
981*7c478bd9Sstevel@tonic-gate  * on cycle detection, or 0 on success.
982*7c478bd9Sstevel@tonic-gate  */
983*7c478bd9Sstevel@tonic-gate static int
984*7c478bd9Sstevel@tonic-gate enable_fmri_rec(char *fmri, boolean_t temp)
985*7c478bd9Sstevel@tonic-gate {
986*7c478bd9Sstevel@tonic-gate 	scf_instance_t *inst;
987*7c478bd9Sstevel@tonic-gate 	scf_snapshot_t *snap;
988*7c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg;
989*7c478bd9Sstevel@tonic-gate 	scf_property_t *prop;
990*7c478bd9Sstevel@tonic-gate 	scf_value_t *v;
991*7c478bd9Sstevel@tonic-gate 	scf_iter_t *pg_iter, *val_iter;
992*7c478bd9Sstevel@tonic-gate 	scf_type_t ty;
993*7c478bd9Sstevel@tonic-gate 	char *buf, *pgname;
994*7c478bd9Sstevel@tonic-gate 	ssize_t name_sz, len, sz;
995*7c478bd9Sstevel@tonic-gate 	int ret;
996*7c478bd9Sstevel@tonic-gate 	struct ht_elt *he;
997*7c478bd9Sstevel@tonic-gate 
998*7c478bd9Sstevel@tonic-gate 	len = scf_canonify_fmri(fmri, fmri, max_scf_fmri_sz);
999*7c478bd9Sstevel@tonic-gate 	if (len < 0) {
1000*7c478bd9Sstevel@tonic-gate 		assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT);
1001*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
1002*7c478bd9Sstevel@tonic-gate 	}
1003*7c478bd9Sstevel@tonic-gate 	assert(len < max_scf_fmri_sz);
1004*7c478bd9Sstevel@tonic-gate 
1005*7c478bd9Sstevel@tonic-gate 	switch (visited_find_or_add(fmri, &he)) {
1006*7c478bd9Sstevel@tonic-gate 	case 0:
1007*7c478bd9Sstevel@tonic-gate 		he->active = B_TRUE;
1008*7c478bd9Sstevel@tonic-gate 		break;
1009*7c478bd9Sstevel@tonic-gate 
1010*7c478bd9Sstevel@tonic-gate 	case 1:
1011*7c478bd9Sstevel@tonic-gate 		return (he->active ? ELOOP : 0);
1012*7c478bd9Sstevel@tonic-gate 
1013*7c478bd9Sstevel@tonic-gate 	case -1:
1014*7c478bd9Sstevel@tonic-gate 		uu_die(emsg_nomem);
1015*7c478bd9Sstevel@tonic-gate 
1016*7c478bd9Sstevel@tonic-gate 	default:
1017*7c478bd9Sstevel@tonic-gate 		assert(0);
1018*7c478bd9Sstevel@tonic-gate 		abort();
1019*7c478bd9Sstevel@tonic-gate 	}
1020*7c478bd9Sstevel@tonic-gate 
1021*7c478bd9Sstevel@tonic-gate 	inst = scf_instance_create(h);
1022*7c478bd9Sstevel@tonic-gate 	if (inst == NULL)
1023*7c478bd9Sstevel@tonic-gate 		scfdie();
1024*7c478bd9Sstevel@tonic-gate 
1025*7c478bd9Sstevel@tonic-gate 	switch (get_inst_mult(fmri, inst)) {
1026*7c478bd9Sstevel@tonic-gate 	case 0:
1027*7c478bd9Sstevel@tonic-gate 		break;
1028*7c478bd9Sstevel@tonic-gate 
1029*7c478bd9Sstevel@tonic-gate 	case E2BIG:
1030*7c478bd9Sstevel@tonic-gate 		he->active = B_FALSE;
1031*7c478bd9Sstevel@tonic-gate 		return (E2BIG);
1032*7c478bd9Sstevel@tonic-gate 
1033*7c478bd9Sstevel@tonic-gate 	default:
1034*7c478bd9Sstevel@tonic-gate 		he->active = B_FALSE;
1035*7c478bd9Sstevel@tonic-gate 		return (0);
1036*7c478bd9Sstevel@tonic-gate 	}
1037*7c478bd9Sstevel@tonic-gate 
1038*7c478bd9Sstevel@tonic-gate 	set_inst_enabled(fmri, inst, temp, B_TRUE);
1039*7c478bd9Sstevel@tonic-gate 
1040*7c478bd9Sstevel@tonic-gate 	if ((snap = scf_snapshot_create(h)) == NULL ||
1041*7c478bd9Sstevel@tonic-gate 	    (pg = scf_pg_create(h)) == NULL ||
1042*7c478bd9Sstevel@tonic-gate 	    (prop = scf_property_create(h)) == NULL ||
1043*7c478bd9Sstevel@tonic-gate 	    (v = scf_value_create(h)) == NULL ||
1044*7c478bd9Sstevel@tonic-gate 	    (pg_iter = scf_iter_create(h)) == NULL ||
1045*7c478bd9Sstevel@tonic-gate 	    (val_iter = scf_iter_create(h)) == NULL)
1046*7c478bd9Sstevel@tonic-gate 		scfdie();
1047*7c478bd9Sstevel@tonic-gate 
1048*7c478bd9Sstevel@tonic-gate 	buf = malloc(max_scf_fmri_sz);
1049*7c478bd9Sstevel@tonic-gate 	if (buf == NULL)
1050*7c478bd9Sstevel@tonic-gate 		uu_die(emsg_nomem);
1051*7c478bd9Sstevel@tonic-gate 
1052*7c478bd9Sstevel@tonic-gate 	name_sz = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH);
1053*7c478bd9Sstevel@tonic-gate 	if (name_sz < 0)
1054*7c478bd9Sstevel@tonic-gate 		scfdie();
1055*7c478bd9Sstevel@tonic-gate 	++name_sz;
1056*7c478bd9Sstevel@tonic-gate 	pgname = malloc(name_sz);
1057*7c478bd9Sstevel@tonic-gate 	if (pgname == NULL)
1058*7c478bd9Sstevel@tonic-gate 		uu_die(emsg_nomem);
1059*7c478bd9Sstevel@tonic-gate 
1060*7c478bd9Sstevel@tonic-gate 	if (scf_instance_get_snapshot(inst, "running", snap) != 0) {
1061*7c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND)
1062*7c478bd9Sstevel@tonic-gate 			scfdie();
1063*7c478bd9Sstevel@tonic-gate 
1064*7c478bd9Sstevel@tonic-gate 		scf_snapshot_destroy(snap);
1065*7c478bd9Sstevel@tonic-gate 		snap = NULL;
1066*7c478bd9Sstevel@tonic-gate 	}
1067*7c478bd9Sstevel@tonic-gate 
1068*7c478bd9Sstevel@tonic-gate 	/* Enable restarter */
1069*7c478bd9Sstevel@tonic-gate 	if (scf_instance_get_pg_composed(inst, snap, SCF_PG_GENERAL, pg) != 0) {
1070*7c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND)
1071*7c478bd9Sstevel@tonic-gate 			scfdie();
1072*7c478bd9Sstevel@tonic-gate 
1073*7c478bd9Sstevel@tonic-gate 		uu_warn(gettext("\"%s\" is misconfigured (lacks \"%s\" "
1074*7c478bd9Sstevel@tonic-gate 		    "property group).\n"), fmri, SCF_PG_GENERAL);
1075*7c478bd9Sstevel@tonic-gate 		ret = 0;
1076*7c478bd9Sstevel@tonic-gate 		goto out;
1077*7c478bd9Sstevel@tonic-gate 	}
1078*7c478bd9Sstevel@tonic-gate 
1079*7c478bd9Sstevel@tonic-gate 	sz = get_astring_prop(pg, SCF_PROPERTY_RESTARTER, prop, v, buf,
1080*7c478bd9Sstevel@tonic-gate 	    max_scf_fmri_sz);
1081*7c478bd9Sstevel@tonic-gate 	if (sz > max_scf_fmri_sz) {
1082*7c478bd9Sstevel@tonic-gate 		uu_warn(gettext("\"%s\" is misconfigured (the value of "
1083*7c478bd9Sstevel@tonic-gate 		    "\"%s/%s\" is too long).\n"), fmri, SCF_PG_GENERAL,
1084*7c478bd9Sstevel@tonic-gate 		    SCF_PROPERTY_RESTARTER);
1085*7c478bd9Sstevel@tonic-gate 		ret = 0;
1086*7c478bd9Sstevel@tonic-gate 		goto out;
1087*7c478bd9Sstevel@tonic-gate 	} else if (sz >= 0) {
1088*7c478bd9Sstevel@tonic-gate 		switch (enable_fmri_rec(buf, temp)) {
1089*7c478bd9Sstevel@tonic-gate 		case 0:
1090*7c478bd9Sstevel@tonic-gate 			break;
1091*7c478bd9Sstevel@tonic-gate 
1092*7c478bd9Sstevel@tonic-gate 		case EINVAL:
1093*7c478bd9Sstevel@tonic-gate 			uu_warn(gettext("Restarter FMRI for \"%s\" is "
1094*7c478bd9Sstevel@tonic-gate 			    "invalid.\n"), fmri);
1095*7c478bd9Sstevel@tonic-gate 			break;
1096*7c478bd9Sstevel@tonic-gate 
1097*7c478bd9Sstevel@tonic-gate 		case E2BIG:
1098*7c478bd9Sstevel@tonic-gate 			uu_warn(gettext("Restarter FMRI for \"%s\" identifies "
1099*7c478bd9Sstevel@tonic-gate 			    "a service with multiple instances.\n"), fmri);
1100*7c478bd9Sstevel@tonic-gate 			break;
1101*7c478bd9Sstevel@tonic-gate 
1102*7c478bd9Sstevel@tonic-gate 		case ELOOP:
1103*7c478bd9Sstevel@tonic-gate 			ret = ELOOP;
1104*7c478bd9Sstevel@tonic-gate 			goto out;
1105*7c478bd9Sstevel@tonic-gate 
1106*7c478bd9Sstevel@tonic-gate 		default:
1107*7c478bd9Sstevel@tonic-gate 			assert(0);
1108*7c478bd9Sstevel@tonic-gate 			abort();
1109*7c478bd9Sstevel@tonic-gate 		}
1110*7c478bd9Sstevel@tonic-gate 	} else if (sz < 0) {
1111*7c478bd9Sstevel@tonic-gate 		switch (-sz) {
1112*7c478bd9Sstevel@tonic-gate 		case ENOENT:
1113*7c478bd9Sstevel@tonic-gate 			break;
1114*7c478bd9Sstevel@tonic-gate 
1115*7c478bd9Sstevel@tonic-gate 		case E2BIG:
1116*7c478bd9Sstevel@tonic-gate 			uu_warn(gettext("\"%s\" is misconfigured (\"%s/%s\" "
1117*7c478bd9Sstevel@tonic-gate 			    "property is not single-valued).\n"), fmri,
1118*7c478bd9Sstevel@tonic-gate 			    SCF_PG_GENERAL, SCF_PROPERTY_RESTARTER);
1119*7c478bd9Sstevel@tonic-gate 			ret = 0;
1120*7c478bd9Sstevel@tonic-gate 			goto out;
1121*7c478bd9Sstevel@tonic-gate 
1122*7c478bd9Sstevel@tonic-gate 		case EINVAL:
1123*7c478bd9Sstevel@tonic-gate 			uu_warn(gettext("\"%s\" is misconfigured (\"%s/%s\" "
1124*7c478bd9Sstevel@tonic-gate 			    "property is not of astring type).\n"), fmri,
1125*7c478bd9Sstevel@tonic-gate 			    SCF_PG_GENERAL, SCF_PROPERTY_RESTARTER);
1126*7c478bd9Sstevel@tonic-gate 			ret = 0;
1127*7c478bd9Sstevel@tonic-gate 			goto out;
1128*7c478bd9Sstevel@tonic-gate 
1129*7c478bd9Sstevel@tonic-gate 		default:
1130*7c478bd9Sstevel@tonic-gate 			assert(0);
1131*7c478bd9Sstevel@tonic-gate 			abort();
1132*7c478bd9Sstevel@tonic-gate 		}
1133*7c478bd9Sstevel@tonic-gate 	}
1134*7c478bd9Sstevel@tonic-gate 
1135*7c478bd9Sstevel@tonic-gate 	if (scf_iter_instance_pgs_typed_composed(pg_iter, inst, snap,
1136*7c478bd9Sstevel@tonic-gate 	    SCF_GROUP_DEPENDENCY) == -1)
1137*7c478bd9Sstevel@tonic-gate 		scfdie();
1138*7c478bd9Sstevel@tonic-gate 
1139*7c478bd9Sstevel@tonic-gate 	while (scf_iter_next_pg(pg_iter, pg) > 0) {
1140*7c478bd9Sstevel@tonic-gate 		len = scf_pg_get_name(pg, pgname, name_sz);
1141*7c478bd9Sstevel@tonic-gate 		if (len < 0)
1142*7c478bd9Sstevel@tonic-gate 			scfdie();
1143*7c478bd9Sstevel@tonic-gate 		assert(len < name_sz);
1144*7c478bd9Sstevel@tonic-gate 
1145*7c478bd9Sstevel@tonic-gate 		if (dep_get_astring(fmri, pgname, pg, SCF_PROPERTY_TYPE, prop,
1146*7c478bd9Sstevel@tonic-gate 		    v, buf, max_scf_fmri_sz) < 0)
1147*7c478bd9Sstevel@tonic-gate 			continue;
1148*7c478bd9Sstevel@tonic-gate 
1149*7c478bd9Sstevel@tonic-gate 		if (strcmp(buf, "service") != 0)
1150*7c478bd9Sstevel@tonic-gate 			continue;
1151*7c478bd9Sstevel@tonic-gate 
1152*7c478bd9Sstevel@tonic-gate 		if (dep_get_astring(fmri, pgname, pg, SCF_PROPERTY_GROUPING,
1153*7c478bd9Sstevel@tonic-gate 		    prop, v, buf, max_scf_fmri_sz) < 0)
1154*7c478bd9Sstevel@tonic-gate 			continue;
1155*7c478bd9Sstevel@tonic-gate 
1156*7c478bd9Sstevel@tonic-gate 		if (strcmp(buf, SCF_DEP_EXCLUDE_ALL) == 0 ||
1157*7c478bd9Sstevel@tonic-gate 		    strcmp(buf, SCF_DEP_OPTIONAL_ALL) == 0)
1158*7c478bd9Sstevel@tonic-gate 			continue;
1159*7c478bd9Sstevel@tonic-gate 
1160*7c478bd9Sstevel@tonic-gate 		if (strcmp(buf, SCF_DEP_REQUIRE_ALL) != 0 &&
1161*7c478bd9Sstevel@tonic-gate 		    strcmp(buf, SCF_DEP_REQUIRE_ANY) != 0) {
1162*7c478bd9Sstevel@tonic-gate 			uu_warn(gettext("Dependency \"%s\" of \"%s\" has "
1163*7c478bd9Sstevel@tonic-gate 			    "unknown type \"%s\".\n"), pgname, fmri, buf);
1164*7c478bd9Sstevel@tonic-gate 			continue;
1165*7c478bd9Sstevel@tonic-gate 		}
1166*7c478bd9Sstevel@tonic-gate 
1167*7c478bd9Sstevel@tonic-gate 		if (scf_pg_get_property(pg, SCF_PROPERTY_ENTITIES, prop) ==
1168*7c478bd9Sstevel@tonic-gate 		    -1) {
1169*7c478bd9Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_NOT_FOUND)
1170*7c478bd9Sstevel@tonic-gate 				scfdie();
1171*7c478bd9Sstevel@tonic-gate 
1172*7c478bd9Sstevel@tonic-gate 			uu_warn(gettext("\"%s\" is misconfigured (\"%s\" "
1173*7c478bd9Sstevel@tonic-gate 			    "dependency lacks \"%s\" property.)\n"), fmri,
1174*7c478bd9Sstevel@tonic-gate 			    pgname, SCF_PROPERTY_ENTITIES);
1175*7c478bd9Sstevel@tonic-gate 			continue;
1176*7c478bd9Sstevel@tonic-gate 		}
1177*7c478bd9Sstevel@tonic-gate 
1178*7c478bd9Sstevel@tonic-gate 		if (scf_property_type(prop, &ty) != SCF_SUCCESS)
1179*7c478bd9Sstevel@tonic-gate 			scfdie();
1180*7c478bd9Sstevel@tonic-gate 
1181*7c478bd9Sstevel@tonic-gate 		if (ty != SCF_TYPE_FMRI) {
1182*7c478bd9Sstevel@tonic-gate 			uu_warn(gettext("\"%s\" is misconfigured (property "
1183*7c478bd9Sstevel@tonic-gate 			    "\"%s/%s\" is not of fmri type).\n"), fmri, pgname,
1184*7c478bd9Sstevel@tonic-gate 			    SCF_PROPERTY_ENTITIES);
1185*7c478bd9Sstevel@tonic-gate 			continue;
1186*7c478bd9Sstevel@tonic-gate 		}
1187*7c478bd9Sstevel@tonic-gate 
1188*7c478bd9Sstevel@tonic-gate 		if (scf_iter_property_values(val_iter, prop) == -1)
1189*7c478bd9Sstevel@tonic-gate 			scfdie();
1190*7c478bd9Sstevel@tonic-gate 
1191*7c478bd9Sstevel@tonic-gate 		if (strcmp(buf, SCF_DEP_REQUIRE_ANY) == 0) {
1192*7c478bd9Sstevel@tonic-gate 			if (multiple_instances(val_iter, v, buf)) {
1193*7c478bd9Sstevel@tonic-gate 				(void) printf(gettext("%s requires one of:\n"),
1194*7c478bd9Sstevel@tonic-gate 				    fmri);
1195*7c478bd9Sstevel@tonic-gate 
1196*7c478bd9Sstevel@tonic-gate 				if (scf_iter_property_values(val_iter, prop) !=
1197*7c478bd9Sstevel@tonic-gate 				    0)
1198*7c478bd9Sstevel@tonic-gate 					scfdie();
1199*7c478bd9Sstevel@tonic-gate 
1200*7c478bd9Sstevel@tonic-gate 				for (;;) {
1201*7c478bd9Sstevel@tonic-gate 					int r;
1202*7c478bd9Sstevel@tonic-gate 
1203*7c478bd9Sstevel@tonic-gate 					r = scf_iter_next_value(val_iter, v);
1204*7c478bd9Sstevel@tonic-gate 					if (r == 0)
1205*7c478bd9Sstevel@tonic-gate 						break;
1206*7c478bd9Sstevel@tonic-gate 					if (r != 1)
1207*7c478bd9Sstevel@tonic-gate 						scfdie();
1208*7c478bd9Sstevel@tonic-gate 
1209*7c478bd9Sstevel@tonic-gate 					if (scf_value_get_astring(v, buf,
1210*7c478bd9Sstevel@tonic-gate 					    max_scf_fmri_sz) < 0)
1211*7c478bd9Sstevel@tonic-gate 						scfdie();
1212*7c478bd9Sstevel@tonic-gate 
1213*7c478bd9Sstevel@tonic-gate 					(void) fputs("  ", stdout);
1214*7c478bd9Sstevel@tonic-gate 					(void) puts(buf);
1215*7c478bd9Sstevel@tonic-gate 				}
1216*7c478bd9Sstevel@tonic-gate 
1217*7c478bd9Sstevel@tonic-gate 				continue;
1218*7c478bd9Sstevel@tonic-gate 			}
1219*7c478bd9Sstevel@tonic-gate 
1220*7c478bd9Sstevel@tonic-gate 			/*
1221*7c478bd9Sstevel@tonic-gate 			 * Since there's only one instance, we can enable it.
1222*7c478bd9Sstevel@tonic-gate 			 * Reset val_iter and continue.
1223*7c478bd9Sstevel@tonic-gate 			 */
1224*7c478bd9Sstevel@tonic-gate 			if (scf_iter_property_values(val_iter, prop) != 0)
1225*7c478bd9Sstevel@tonic-gate 				scfdie();
1226*7c478bd9Sstevel@tonic-gate 		}
1227*7c478bd9Sstevel@tonic-gate 
1228*7c478bd9Sstevel@tonic-gate 		for (;;) {
1229*7c478bd9Sstevel@tonic-gate 			ret = scf_iter_next_value(val_iter, v);
1230*7c478bd9Sstevel@tonic-gate 			if (ret == 0)
1231*7c478bd9Sstevel@tonic-gate 				break;
1232*7c478bd9Sstevel@tonic-gate 			if (ret != 1)
1233*7c478bd9Sstevel@tonic-gate 				scfdie();
1234*7c478bd9Sstevel@tonic-gate 
1235*7c478bd9Sstevel@tonic-gate 			if (scf_value_get_astring(v, buf, max_scf_fmri_sz) ==
1236*7c478bd9Sstevel@tonic-gate 			    -1)
1237*7c478bd9Sstevel@tonic-gate 				scfdie();
1238*7c478bd9Sstevel@tonic-gate 
1239*7c478bd9Sstevel@tonic-gate 			switch (enable_fmri_rec(buf, temp)) {
1240*7c478bd9Sstevel@tonic-gate 			case 0:
1241*7c478bd9Sstevel@tonic-gate 				break;
1242*7c478bd9Sstevel@tonic-gate 
1243*7c478bd9Sstevel@tonic-gate 			case EINVAL:
1244*7c478bd9Sstevel@tonic-gate 				uu_warn(gettext("\"%s\" dependency of \"%s\" "
1245*7c478bd9Sstevel@tonic-gate 				    "has invalid FMRI \"%s\".\n"), pgname,
1246*7c478bd9Sstevel@tonic-gate 				    fmri, buf);
1247*7c478bd9Sstevel@tonic-gate 				break;
1248*7c478bd9Sstevel@tonic-gate 
1249*7c478bd9Sstevel@tonic-gate 			case E2BIG:
1250*7c478bd9Sstevel@tonic-gate 				uu_warn(gettext("%s depends on %s, which has "
1251*7c478bd9Sstevel@tonic-gate 				    "multiple instances.\n"), fmri, buf);
1252*7c478bd9Sstevel@tonic-gate 				break;
1253*7c478bd9Sstevel@tonic-gate 
1254*7c478bd9Sstevel@tonic-gate 			case ELOOP:
1255*7c478bd9Sstevel@tonic-gate 				ret = ELOOP;
1256*7c478bd9Sstevel@tonic-gate 				goto out;
1257*7c478bd9Sstevel@tonic-gate 
1258*7c478bd9Sstevel@tonic-gate 			default:
1259*7c478bd9Sstevel@tonic-gate 				assert(0);
1260*7c478bd9Sstevel@tonic-gate 				abort();
1261*7c478bd9Sstevel@tonic-gate 			}
1262*7c478bd9Sstevel@tonic-gate 		}
1263*7c478bd9Sstevel@tonic-gate 	}
1264*7c478bd9Sstevel@tonic-gate 
1265*7c478bd9Sstevel@tonic-gate 	ret = 0;
1266*7c478bd9Sstevel@tonic-gate 
1267*7c478bd9Sstevel@tonic-gate out:
1268*7c478bd9Sstevel@tonic-gate 	he->active = B_FALSE;
1269*7c478bd9Sstevel@tonic-gate 
1270*7c478bd9Sstevel@tonic-gate 	free(buf);
1271*7c478bd9Sstevel@tonic-gate 	free(pgname);
1272*7c478bd9Sstevel@tonic-gate 
1273*7c478bd9Sstevel@tonic-gate 	(void) scf_value_destroy(v);
1274*7c478bd9Sstevel@tonic-gate 	scf_property_destroy(prop);
1275*7c478bd9Sstevel@tonic-gate 	scf_pg_destroy(pg);
1276*7c478bd9Sstevel@tonic-gate 	scf_snapshot_destroy(snap);
1277*7c478bd9Sstevel@tonic-gate 	scf_iter_destroy(pg_iter);
1278*7c478bd9Sstevel@tonic-gate 	scf_iter_destroy(val_iter);
1279*7c478bd9Sstevel@tonic-gate 
1280*7c478bd9Sstevel@tonic-gate 	return (ret);
1281*7c478bd9Sstevel@tonic-gate }
1282*7c478bd9Sstevel@tonic-gate 
1283*7c478bd9Sstevel@tonic-gate /*
1284*7c478bd9Sstevel@tonic-gate  * fmri here is only used for verbose messages.
1285*7c478bd9Sstevel@tonic-gate  */
1286*7c478bd9Sstevel@tonic-gate static void
1287*7c478bd9Sstevel@tonic-gate set_inst_action(const char *fmri, const scf_instance_t *inst,
1288*7c478bd9Sstevel@tonic-gate     const char *action)
1289*7c478bd9Sstevel@tonic-gate {
1290*7c478bd9Sstevel@tonic-gate 	scf_transaction_t *tx;
1291*7c478bd9Sstevel@tonic-gate 	scf_transaction_entry_t *ent;
1292*7c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg;
1293*7c478bd9Sstevel@tonic-gate 	scf_property_t *prop;
1294*7c478bd9Sstevel@tonic-gate 	scf_value_t *v;
1295*7c478bd9Sstevel@tonic-gate 	int ret;
1296*7c478bd9Sstevel@tonic-gate 	int64_t t;
1297*7c478bd9Sstevel@tonic-gate 	hrtime_t timestamp;
1298*7c478bd9Sstevel@tonic-gate 
1299*7c478bd9Sstevel@tonic-gate 	const char * const scf_pg_restarter_actions = SCF_PG_RESTARTER_ACTIONS;
1300*7c478bd9Sstevel@tonic-gate 
1301*7c478bd9Sstevel@tonic-gate 	if ((pg = scf_pg_create(h)) == NULL ||
1302*7c478bd9Sstevel@tonic-gate 	    (prop = scf_property_create(h)) == NULL ||
1303*7c478bd9Sstevel@tonic-gate 	    (v = scf_value_create(h)) == NULL ||
1304*7c478bd9Sstevel@tonic-gate 	    (tx = scf_transaction_create(h)) == NULL ||
1305*7c478bd9Sstevel@tonic-gate 	    (ent = scf_entry_create(h)) == NULL)
1306*7c478bd9Sstevel@tonic-gate 		scfdie();
1307*7c478bd9Sstevel@tonic-gate 
1308*7c478bd9Sstevel@tonic-gate 	if (scf_instance_get_pg(inst, scf_pg_restarter_actions, pg) == -1) {
1309*7c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND)
1310*7c478bd9Sstevel@tonic-gate 			scfdie();
1311*7c478bd9Sstevel@tonic-gate 
1312*7c478bd9Sstevel@tonic-gate 		/* Try creating the restarter_actions property group. */
1313*7c478bd9Sstevel@tonic-gate 		if (scf_instance_add_pg(inst, scf_pg_restarter_actions,
1314*7c478bd9Sstevel@tonic-gate 		    SCF_PG_RESTARTER_ACTIONS_TYPE,
1315*7c478bd9Sstevel@tonic-gate 		    SCF_PG_RESTARTER_ACTIONS_FLAGS, pg) == -1) {
1316*7c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
1317*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_EXISTS:
1318*7c478bd9Sstevel@tonic-gate 				/* Someone must have added it. */
1319*7c478bd9Sstevel@tonic-gate 				break;
1320*7c478bd9Sstevel@tonic-gate 
1321*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
1322*7c478bd9Sstevel@tonic-gate 				if (!verbose)
1323*7c478bd9Sstevel@tonic-gate 					uu_warn(emsg_permission_denied, fmri);
1324*7c478bd9Sstevel@tonic-gate 				else
1325*7c478bd9Sstevel@tonic-gate 					uu_warn(emsg_create_pg_perm_denied,
1326*7c478bd9Sstevel@tonic-gate 					    fmri, scf_pg_restarter_actions);
1327*7c478bd9Sstevel@tonic-gate 				goto out;
1328*7c478bd9Sstevel@tonic-gate 
1329*7c478bd9Sstevel@tonic-gate 			default:
1330*7c478bd9Sstevel@tonic-gate 				scfdie();
1331*7c478bd9Sstevel@tonic-gate 			}
1332*7c478bd9Sstevel@tonic-gate 		}
1333*7c478bd9Sstevel@tonic-gate 	}
1334*7c478bd9Sstevel@tonic-gate 
1335*7c478bd9Sstevel@tonic-gate 	/*
1336*7c478bd9Sstevel@tonic-gate 	 * If we lose the transaction race and need to retry, there are 2
1337*7c478bd9Sstevel@tonic-gate 	 * potential other winners:
1338*7c478bd9Sstevel@tonic-gate 	 *	- another process setting actions
1339*7c478bd9Sstevel@tonic-gate 	 *	- the restarter marking the action complete
1340*7c478bd9Sstevel@tonic-gate 	 * Therefore, re-read the property every time through the loop before
1341*7c478bd9Sstevel@tonic-gate 	 * making any decisions based on their values.
1342*7c478bd9Sstevel@tonic-gate 	 */
1343*7c478bd9Sstevel@tonic-gate 	do {
1344*7c478bd9Sstevel@tonic-gate 		timestamp = gethrtime();
1345*7c478bd9Sstevel@tonic-gate 
1346*7c478bd9Sstevel@tonic-gate 		if (scf_transaction_start(tx, pg) == -1) {
1347*7c478bd9Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
1348*7c478bd9Sstevel@tonic-gate 				scfdie();
1349*7c478bd9Sstevel@tonic-gate 
1350*7c478bd9Sstevel@tonic-gate 			if (!verbose)
1351*7c478bd9Sstevel@tonic-gate 				uu_warn(emsg_permission_denied, fmri);
1352*7c478bd9Sstevel@tonic-gate 			else
1353*7c478bd9Sstevel@tonic-gate 				uu_warn(emsg_pg_perm_denied, fmri,
1354*7c478bd9Sstevel@tonic-gate 				    scf_pg_restarter_actions);
1355*7c478bd9Sstevel@tonic-gate 			goto out;
1356*7c478bd9Sstevel@tonic-gate 		}
1357*7c478bd9Sstevel@tonic-gate 
1358*7c478bd9Sstevel@tonic-gate 		if (scf_pg_get_property(pg, action, prop) == -1) {
1359*7c478bd9Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_NOT_FOUND)
1360*7c478bd9Sstevel@tonic-gate 				scfdie();
1361*7c478bd9Sstevel@tonic-gate 			if (scf_transaction_property_new(tx, ent,
1362*7c478bd9Sstevel@tonic-gate 			    action, SCF_TYPE_INTEGER) == -1)
1363*7c478bd9Sstevel@tonic-gate 				scfdie();
1364*7c478bd9Sstevel@tonic-gate 			goto action_set;
1365*7c478bd9Sstevel@tonic-gate 		} else {
1366*7c478bd9Sstevel@tonic-gate 			if (scf_transaction_property_change_type(tx, ent,
1367*7c478bd9Sstevel@tonic-gate 			    action, SCF_TYPE_INTEGER) == -1)
1368*7c478bd9Sstevel@tonic-gate 				scfdie();
1369*7c478bd9Sstevel@tonic-gate 		}
1370*7c478bd9Sstevel@tonic-gate 
1371*7c478bd9Sstevel@tonic-gate 		if (scf_property_get_value(prop, v) == -1) {
1372*7c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
1373*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONSTRAINT_VIOLATED:
1374*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_FOUND:
1375*7c478bd9Sstevel@tonic-gate 				/* Misconfigured, so set anyway. */
1376*7c478bd9Sstevel@tonic-gate 				goto action_set;
1377*7c478bd9Sstevel@tonic-gate 
1378*7c478bd9Sstevel@tonic-gate 			default:
1379*7c478bd9Sstevel@tonic-gate 				scfdie();
1380*7c478bd9Sstevel@tonic-gate 			}
1381*7c478bd9Sstevel@tonic-gate 		} else {
1382*7c478bd9Sstevel@tonic-gate 			if (scf_value_get_integer(v, &t) == -1) {
1383*7c478bd9Sstevel@tonic-gate 				assert(scf_error() == SCF_ERROR_TYPE_MISMATCH);
1384*7c478bd9Sstevel@tonic-gate 				goto action_set;
1385*7c478bd9Sstevel@tonic-gate 			}
1386*7c478bd9Sstevel@tonic-gate 			if (t > timestamp)
1387*7c478bd9Sstevel@tonic-gate 				break;
1388*7c478bd9Sstevel@tonic-gate 		}
1389*7c478bd9Sstevel@tonic-gate 
1390*7c478bd9Sstevel@tonic-gate action_set:
1391*7c478bd9Sstevel@tonic-gate 		scf_value_set_integer(v, timestamp);
1392*7c478bd9Sstevel@tonic-gate 		if (scf_entry_add_value(ent, v) == -1)
1393*7c478bd9Sstevel@tonic-gate 			scfdie();
1394*7c478bd9Sstevel@tonic-gate 
1395*7c478bd9Sstevel@tonic-gate 		ret = scf_transaction_commit(tx);
1396*7c478bd9Sstevel@tonic-gate 		if (ret == -1) {
1397*7c478bd9Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
1398*7c478bd9Sstevel@tonic-gate 				scfdie();
1399*7c478bd9Sstevel@tonic-gate 
1400*7c478bd9Sstevel@tonic-gate 			if (!verbose)
1401*7c478bd9Sstevel@tonic-gate 				uu_warn(emsg_permission_denied, fmri);
1402*7c478bd9Sstevel@tonic-gate 			else
1403*7c478bd9Sstevel@tonic-gate 				uu_warn(emsg_prop_perm_denied, fmri,
1404*7c478bd9Sstevel@tonic-gate 				    scf_pg_restarter_actions, action);
1405*7c478bd9Sstevel@tonic-gate 			scf_transaction_reset(tx);
1406*7c478bd9Sstevel@tonic-gate 			goto out;
1407*7c478bd9Sstevel@tonic-gate 		}
1408*7c478bd9Sstevel@tonic-gate 
1409*7c478bd9Sstevel@tonic-gate 		scf_transaction_reset(tx);
1410*7c478bd9Sstevel@tonic-gate 
1411*7c478bd9Sstevel@tonic-gate 		if (ret == 0) {
1412*7c478bd9Sstevel@tonic-gate 			if (scf_pg_update(pg) == -1)
1413*7c478bd9Sstevel@tonic-gate 				scfdie();
1414*7c478bd9Sstevel@tonic-gate 		}
1415*7c478bd9Sstevel@tonic-gate 	} while (ret == 0);
1416*7c478bd9Sstevel@tonic-gate 
1417*7c478bd9Sstevel@tonic-gate 	if (verbose)
1418*7c478bd9Sstevel@tonic-gate 		(void) printf(gettext("Action %s set for %s.\n"), action, fmri);
1419*7c478bd9Sstevel@tonic-gate 
1420*7c478bd9Sstevel@tonic-gate out:
1421*7c478bd9Sstevel@tonic-gate 	scf_value_destroy(v);
1422*7c478bd9Sstevel@tonic-gate 	scf_entry_destroy(ent);
1423*7c478bd9Sstevel@tonic-gate 	scf_transaction_destroy(tx);
1424*7c478bd9Sstevel@tonic-gate 	scf_property_destroy(prop);
1425*7c478bd9Sstevel@tonic-gate 	scf_pg_destroy(pg);
1426*7c478bd9Sstevel@tonic-gate }
1427*7c478bd9Sstevel@tonic-gate 
1428*7c478bd9Sstevel@tonic-gate /*
1429*7c478bd9Sstevel@tonic-gate  * Get the state of inst.  state should point to a buffer of
1430*7c478bd9Sstevel@tonic-gate  * MAX_SCF_STATE_STRING_SZ bytes.  Returns 0 on success or -1 if
1431*7c478bd9Sstevel@tonic-gate  *   no restarter property group
1432*7c478bd9Sstevel@tonic-gate  *   no state property
1433*7c478bd9Sstevel@tonic-gate  *   state property is misconfigured (wrong type, not single-valued)
1434*7c478bd9Sstevel@tonic-gate  *   state value is too long
1435*7c478bd9Sstevel@tonic-gate  * In these cases, fmri is used to print a warning.
1436*7c478bd9Sstevel@tonic-gate  *
1437*7c478bd9Sstevel@tonic-gate  * If pgp is non-NULL, a successful call to inst_get_state will store
1438*7c478bd9Sstevel@tonic-gate  * the SCF_PG_RESTARTER property group in *pgp, and the caller will be
1439*7c478bd9Sstevel@tonic-gate  * responsible for calling scf_pg_destroy on the property group.
1440*7c478bd9Sstevel@tonic-gate  */
1441*7c478bd9Sstevel@tonic-gate int
1442*7c478bd9Sstevel@tonic-gate inst_get_state(scf_instance_t *inst, char *state, const char *fmri,
1443*7c478bd9Sstevel@tonic-gate     scf_propertygroup_t **pgp)
1444*7c478bd9Sstevel@tonic-gate {
1445*7c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg;
1446*7c478bd9Sstevel@tonic-gate 	scf_property_t *prop;
1447*7c478bd9Sstevel@tonic-gate 	scf_value_t *val;
1448*7c478bd9Sstevel@tonic-gate 	int ret = -1;
1449*7c478bd9Sstevel@tonic-gate 	ssize_t szret;
1450*7c478bd9Sstevel@tonic-gate 
1451*7c478bd9Sstevel@tonic-gate 	if ((pg = scf_pg_create(h)) == NULL ||
1452*7c478bd9Sstevel@tonic-gate 	    (prop = scf_property_create(h)) == NULL ||
1453*7c478bd9Sstevel@tonic-gate 	    (val = scf_value_create(h)) == NULL)
1454*7c478bd9Sstevel@tonic-gate 		scfdie();
1455*7c478bd9Sstevel@tonic-gate 
1456*7c478bd9Sstevel@tonic-gate 	if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) {
1457*7c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND)
1458*7c478bd9Sstevel@tonic-gate 			scfdie();
1459*7c478bd9Sstevel@tonic-gate 
1460*7c478bd9Sstevel@tonic-gate 		uu_warn(gettext("%s is misconfigured (lacks \"%s\" property "
1461*7c478bd9Sstevel@tonic-gate 		    "group).\n"), fmri ? fmri : inst_get_fmri(inst),
1462*7c478bd9Sstevel@tonic-gate 		    SCF_PG_RESTARTER);
1463*7c478bd9Sstevel@tonic-gate 		goto out;
1464*7c478bd9Sstevel@tonic-gate 	}
1465*7c478bd9Sstevel@tonic-gate 
1466*7c478bd9Sstevel@tonic-gate 	szret = get_astring_prop(pg, SCF_PROPERTY_STATE, prop, val, state,
1467*7c478bd9Sstevel@tonic-gate 	    MAX_SCF_STATE_STRING_SZ);
1468*7c478bd9Sstevel@tonic-gate 	if (szret < 0) {
1469*7c478bd9Sstevel@tonic-gate 		switch (-szret) {
1470*7c478bd9Sstevel@tonic-gate 		case ENOENT:
1471*7c478bd9Sstevel@tonic-gate 			uu_warn(gettext("%s is misconfigured (\"%s\" property "
1472*7c478bd9Sstevel@tonic-gate 			    "group lacks \"%s\" property).\n"),
1473*7c478bd9Sstevel@tonic-gate 			    fmri ? fmri : inst_get_fmri(inst), SCF_PG_RESTARTER,
1474*7c478bd9Sstevel@tonic-gate 			    SCF_PROPERTY_STATE);
1475*7c478bd9Sstevel@tonic-gate 			goto out;
1476*7c478bd9Sstevel@tonic-gate 
1477*7c478bd9Sstevel@tonic-gate 		case E2BIG:
1478*7c478bd9Sstevel@tonic-gate 			uu_warn(gettext("%s is misconfigured (\"%s/%s\" "
1479*7c478bd9Sstevel@tonic-gate 			    "property is not single-valued).\n"),
1480*7c478bd9Sstevel@tonic-gate 			    fmri ? fmri : inst_get_fmri(inst), SCF_PG_RESTARTER,
1481*7c478bd9Sstevel@tonic-gate 			    SCF_PROPERTY_STATE);
1482*7c478bd9Sstevel@tonic-gate 			goto out;
1483*7c478bd9Sstevel@tonic-gate 
1484*7c478bd9Sstevel@tonic-gate 		case EINVAL:
1485*7c478bd9Sstevel@tonic-gate 			uu_warn(gettext("%s is misconfigured (\"%s/%s\" "
1486*7c478bd9Sstevel@tonic-gate 			    "property is not of type astring).\n"),
1487*7c478bd9Sstevel@tonic-gate 			    fmri ? fmri : inst_get_fmri(inst), SCF_PG_RESTARTER,
1488*7c478bd9Sstevel@tonic-gate 			    SCF_PROPERTY_STATE);
1489*7c478bd9Sstevel@tonic-gate 			goto out;
1490*7c478bd9Sstevel@tonic-gate 
1491*7c478bd9Sstevel@tonic-gate 		default:
1492*7c478bd9Sstevel@tonic-gate 			assert(0);
1493*7c478bd9Sstevel@tonic-gate 			abort();
1494*7c478bd9Sstevel@tonic-gate 		}
1495*7c478bd9Sstevel@tonic-gate 	}
1496*7c478bd9Sstevel@tonic-gate 	if (szret >= MAX_SCF_STATE_STRING_SZ) {
1497*7c478bd9Sstevel@tonic-gate 		uu_warn(gettext("%s is misconfigured (\"%s/%s\" property value "
1498*7c478bd9Sstevel@tonic-gate 		    "is too long).\n"), fmri ? fmri : inst_get_fmri(inst),
1499*7c478bd9Sstevel@tonic-gate 		    SCF_PG_RESTARTER, SCF_PROPERTY_STATE);
1500*7c478bd9Sstevel@tonic-gate 		goto out;
1501*7c478bd9Sstevel@tonic-gate 	}
1502*7c478bd9Sstevel@tonic-gate 
1503*7c478bd9Sstevel@tonic-gate 	ret = 0;
1504*7c478bd9Sstevel@tonic-gate 	if (pgp)
1505*7c478bd9Sstevel@tonic-gate 		*pgp = pg;
1506*7c478bd9Sstevel@tonic-gate 
1507*7c478bd9Sstevel@tonic-gate out:
1508*7c478bd9Sstevel@tonic-gate 	(void) scf_value_destroy(val);
1509*7c478bd9Sstevel@tonic-gate 	scf_property_destroy(prop);
1510*7c478bd9Sstevel@tonic-gate 	if (ret || pgp == NULL)
1511*7c478bd9Sstevel@tonic-gate 		scf_pg_destroy(pg);
1512*7c478bd9Sstevel@tonic-gate 	return (ret);
1513*7c478bd9Sstevel@tonic-gate }
1514*7c478bd9Sstevel@tonic-gate 
1515*7c478bd9Sstevel@tonic-gate static void
1516*7c478bd9Sstevel@tonic-gate set_astring_prop(const char *fmri, const char *pgname, const char *pgtype,
1517*7c478bd9Sstevel@tonic-gate     uint32_t pgflags, const char *propname, const char *str)
1518*7c478bd9Sstevel@tonic-gate {
1519*7c478bd9Sstevel@tonic-gate 	scf_instance_t *inst;
1520*7c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg;
1521*7c478bd9Sstevel@tonic-gate 	scf_property_t *prop;
1522*7c478bd9Sstevel@tonic-gate 	scf_value_t *val;
1523*7c478bd9Sstevel@tonic-gate 	scf_transaction_t *tx;
1524*7c478bd9Sstevel@tonic-gate 	scf_transaction_entry_t *txent;
1525*7c478bd9Sstevel@tonic-gate 	int ret;
1526*7c478bd9Sstevel@tonic-gate 
1527*7c478bd9Sstevel@tonic-gate 	inst = scf_instance_create(h);
1528*7c478bd9Sstevel@tonic-gate 	if (inst == NULL)
1529*7c478bd9Sstevel@tonic-gate 		scfdie();
1530*7c478bd9Sstevel@tonic-gate 
1531*7c478bd9Sstevel@tonic-gate 	if (get_inst(fmri, inst) != 0)
1532*7c478bd9Sstevel@tonic-gate 		return;
1533*7c478bd9Sstevel@tonic-gate 
1534*7c478bd9Sstevel@tonic-gate 	if ((pg = scf_pg_create(h)) == NULL ||
1535*7c478bd9Sstevel@tonic-gate 	    (prop = scf_property_create(h)) == NULL ||
1536*7c478bd9Sstevel@tonic-gate 	    (val = scf_value_create(h)) == NULL ||
1537*7c478bd9Sstevel@tonic-gate 	    (tx = scf_transaction_create(h)) == NULL ||
1538*7c478bd9Sstevel@tonic-gate 	    (txent = scf_entry_create(h)) == NULL)
1539*7c478bd9Sstevel@tonic-gate 		scfdie();
1540*7c478bd9Sstevel@tonic-gate 
1541*7c478bd9Sstevel@tonic-gate 	if (scf_instance_get_pg(inst, pgname, pg) != SCF_SUCCESS) {
1542*7c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND)
1543*7c478bd9Sstevel@tonic-gate 			scfdie();
1544*7c478bd9Sstevel@tonic-gate 
1545*7c478bd9Sstevel@tonic-gate 		if (scf_instance_add_pg(inst, pgname, pgtype, pgflags, pg) !=
1546*7c478bd9Sstevel@tonic-gate 		    SCF_SUCCESS) {
1547*7c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
1548*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_EXISTS:
1549*7c478bd9Sstevel@tonic-gate 				if (scf_instance_get_pg(inst, pgname, pg) !=
1550*7c478bd9Sstevel@tonic-gate 				    SCF_SUCCESS) {
1551*7c478bd9Sstevel@tonic-gate 					if (scf_error() != SCF_ERROR_NOT_FOUND)
1552*7c478bd9Sstevel@tonic-gate 						scfdie();
1553*7c478bd9Sstevel@tonic-gate 
1554*7c478bd9Sstevel@tonic-gate 					uu_warn(gettext("Repository write "
1555*7c478bd9Sstevel@tonic-gate 					    "contention.\n"));
1556*7c478bd9Sstevel@tonic-gate 					goto out;
1557*7c478bd9Sstevel@tonic-gate 				}
1558*7c478bd9Sstevel@tonic-gate 				break;
1559*7c478bd9Sstevel@tonic-gate 
1560*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
1561*7c478bd9Sstevel@tonic-gate 				if (!verbose)
1562*7c478bd9Sstevel@tonic-gate 					uu_warn(emsg_permission_denied, fmri);
1563*7c478bd9Sstevel@tonic-gate 				else
1564*7c478bd9Sstevel@tonic-gate 					uu_warn(emsg_create_pg_perm_denied,
1565*7c478bd9Sstevel@tonic-gate 					    fmri, pgname);
1566*7c478bd9Sstevel@tonic-gate 				goto out;
1567*7c478bd9Sstevel@tonic-gate 
1568*7c478bd9Sstevel@tonic-gate 			default:
1569*7c478bd9Sstevel@tonic-gate 				scfdie();
1570*7c478bd9Sstevel@tonic-gate 			}
1571*7c478bd9Sstevel@tonic-gate 		}
1572*7c478bd9Sstevel@tonic-gate 	}
1573*7c478bd9Sstevel@tonic-gate 
1574*7c478bd9Sstevel@tonic-gate 	do {
1575*7c478bd9Sstevel@tonic-gate 		if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
1576*7c478bd9Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
1577*7c478bd9Sstevel@tonic-gate 				scfdie();
1578*7c478bd9Sstevel@tonic-gate 
1579*7c478bd9Sstevel@tonic-gate 			if (!verbose)
1580*7c478bd9Sstevel@tonic-gate 				uu_warn(emsg_permission_denied, fmri);
1581*7c478bd9Sstevel@tonic-gate 			else
1582*7c478bd9Sstevel@tonic-gate 				uu_warn(emsg_pg_perm_denied, fmri, pgname);
1583*7c478bd9Sstevel@tonic-gate 			goto out;
1584*7c478bd9Sstevel@tonic-gate 		}
1585*7c478bd9Sstevel@tonic-gate 
1586*7c478bd9Sstevel@tonic-gate 		if (scf_transaction_property_change_type(tx, txent, propname,
1587*7c478bd9Sstevel@tonic-gate 		    SCF_TYPE_ASTRING) != 0) {
1588*7c478bd9Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_NOT_FOUND)
1589*7c478bd9Sstevel@tonic-gate 				scfdie();
1590*7c478bd9Sstevel@tonic-gate 
1591*7c478bd9Sstevel@tonic-gate 			if (scf_transaction_property_new(tx, txent, propname,
1592*7c478bd9Sstevel@tonic-gate 			    SCF_TYPE_ASTRING) != 0)
1593*7c478bd9Sstevel@tonic-gate 				scfdie();
1594*7c478bd9Sstevel@tonic-gate 		}
1595*7c478bd9Sstevel@tonic-gate 
1596*7c478bd9Sstevel@tonic-gate 		if (scf_value_set_astring(val, str) != SCF_SUCCESS)
1597*7c478bd9Sstevel@tonic-gate 			scfdie();
1598*7c478bd9Sstevel@tonic-gate 
1599*7c478bd9Sstevel@tonic-gate 		if (scf_entry_add_value(txent, val) != SCF_SUCCESS)
1600*7c478bd9Sstevel@tonic-gate 			scfdie();
1601*7c478bd9Sstevel@tonic-gate 
1602*7c478bd9Sstevel@tonic-gate 		ret = scf_transaction_commit(tx);
1603*7c478bd9Sstevel@tonic-gate 		if (ret == -1) {
1604*7c478bd9Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
1605*7c478bd9Sstevel@tonic-gate 				scfdie();
1606*7c478bd9Sstevel@tonic-gate 
1607*7c478bd9Sstevel@tonic-gate 			if (!verbose)
1608*7c478bd9Sstevel@tonic-gate 				uu_warn(emsg_permission_denied, fmri);
1609*7c478bd9Sstevel@tonic-gate 			else
1610*7c478bd9Sstevel@tonic-gate 				uu_warn(emsg_prop_perm_denied, fmri, pgname,
1611*7c478bd9Sstevel@tonic-gate 				    propname);
1612*7c478bd9Sstevel@tonic-gate 			goto out;
1613*7c478bd9Sstevel@tonic-gate 		}
1614*7c478bd9Sstevel@tonic-gate 
1615*7c478bd9Sstevel@tonic-gate 		if (ret == 0) {
1616*7c478bd9Sstevel@tonic-gate 			scf_transaction_reset(tx);
1617*7c478bd9Sstevel@tonic-gate 
1618*7c478bd9Sstevel@tonic-gate 			if (scf_pg_update(pg) != SCF_SUCCESS)
1619*7c478bd9Sstevel@tonic-gate 				scfdie();
1620*7c478bd9Sstevel@tonic-gate 		}
1621*7c478bd9Sstevel@tonic-gate 	} while (ret == 0);
1622*7c478bd9Sstevel@tonic-gate 
1623*7c478bd9Sstevel@tonic-gate out:
1624*7c478bd9Sstevel@tonic-gate 	scf_transaction_destroy(tx);
1625*7c478bd9Sstevel@tonic-gate 	scf_entry_destroy(txent);
1626*7c478bd9Sstevel@tonic-gate 	scf_value_destroy(val);
1627*7c478bd9Sstevel@tonic-gate 	scf_property_destroy(prop);
1628*7c478bd9Sstevel@tonic-gate 	scf_pg_destroy(pg);
1629*7c478bd9Sstevel@tonic-gate 	scf_instance_destroy(inst);
1630*7c478bd9Sstevel@tonic-gate }
1631*7c478bd9Sstevel@tonic-gate 
1632*7c478bd9Sstevel@tonic-gate 
1633*7c478bd9Sstevel@tonic-gate /*
1634*7c478bd9Sstevel@tonic-gate  * Flags to control enable and disable actions.
1635*7c478bd9Sstevel@tonic-gate  */
1636*7c478bd9Sstevel@tonic-gate #define	SET_ENABLED	0x1
1637*7c478bd9Sstevel@tonic-gate #define	SET_TEMPORARY	0x2
1638*7c478bd9Sstevel@tonic-gate #define	SET_RECURSIVE	0x4
1639*7c478bd9Sstevel@tonic-gate 
1640*7c478bd9Sstevel@tonic-gate static int
1641*7c478bd9Sstevel@tonic-gate set_fmri_enabled(void *data, scf_walkinfo_t *wip)
1642*7c478bd9Sstevel@tonic-gate {
1643*7c478bd9Sstevel@tonic-gate 	int flags = (int)data;
1644*7c478bd9Sstevel@tonic-gate 
1645*7c478bd9Sstevel@tonic-gate 	assert(wip->inst != NULL);
1646*7c478bd9Sstevel@tonic-gate 	assert(wip->pg == NULL);
1647*7c478bd9Sstevel@tonic-gate 
1648*7c478bd9Sstevel@tonic-gate 	if (flags & SET_RECURSIVE) {
1649*7c478bd9Sstevel@tonic-gate 		char *fmri_buf = malloc(max_scf_fmri_sz);
1650*7c478bd9Sstevel@tonic-gate 		if (fmri_buf == NULL)
1651*7c478bd9Sstevel@tonic-gate 			uu_die(emsg_nomem);
1652*7c478bd9Sstevel@tonic-gate 
1653*7c478bd9Sstevel@tonic-gate 		visited = calloc(HT_BUCKETS, sizeof (*visited));
1654*7c478bd9Sstevel@tonic-gate 		if (visited == NULL)
1655*7c478bd9Sstevel@tonic-gate 			uu_die(emsg_nomem);
1656*7c478bd9Sstevel@tonic-gate 
1657*7c478bd9Sstevel@tonic-gate 		/* scf_walk_fmri() guarantees that fmri isn't too long */
1658*7c478bd9Sstevel@tonic-gate 		assert(strlen(wip->fmri) <= max_scf_fmri_sz);
1659*7c478bd9Sstevel@tonic-gate 		(void) strlcpy(fmri_buf, wip->fmri, max_scf_fmri_sz);
1660*7c478bd9Sstevel@tonic-gate 
1661*7c478bd9Sstevel@tonic-gate 		switch (enable_fmri_rec(fmri_buf, (flags & SET_TEMPORARY))) {
1662*7c478bd9Sstevel@tonic-gate 		case E2BIG:
1663*7c478bd9Sstevel@tonic-gate 			uu_warn(gettext("operation on service %s is ambiguous; "
1664*7c478bd9Sstevel@tonic-gate 			    "instance specification needed.\n"), fmri_buf);
1665*7c478bd9Sstevel@tonic-gate 			break;
1666*7c478bd9Sstevel@tonic-gate 
1667*7c478bd9Sstevel@tonic-gate 		case ELOOP:
1668*7c478bd9Sstevel@tonic-gate 			uu_warn(gettext("%s: Dependency cycle detected.\n"),
1669*7c478bd9Sstevel@tonic-gate 			    fmri_buf);
1670*7c478bd9Sstevel@tonic-gate 		}
1671*7c478bd9Sstevel@tonic-gate 
1672*7c478bd9Sstevel@tonic-gate 		free(visited);
1673*7c478bd9Sstevel@tonic-gate 		free(fmri_buf);
1674*7c478bd9Sstevel@tonic-gate 
1675*7c478bd9Sstevel@tonic-gate 	} else {
1676*7c478bd9Sstevel@tonic-gate 		set_inst_enabled(wip->fmri, wip->inst,
1677*7c478bd9Sstevel@tonic-gate 		    (flags & SET_TEMPORARY) != 0, (flags & SET_ENABLED) != 0);
1678*7c478bd9Sstevel@tonic-gate 	}
1679*7c478bd9Sstevel@tonic-gate 
1680*7c478bd9Sstevel@tonic-gate 	return (0);
1681*7c478bd9Sstevel@tonic-gate }
1682*7c478bd9Sstevel@tonic-gate 
1683*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
1684*7c478bd9Sstevel@tonic-gate static int
1685*7c478bd9Sstevel@tonic-gate wait_fmri_enabled(void *data, scf_walkinfo_t *wip)
1686*7c478bd9Sstevel@tonic-gate {
1687*7c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg = NULL;
1688*7c478bd9Sstevel@tonic-gate 	char state[MAX_SCF_STATE_STRING_SZ];
1689*7c478bd9Sstevel@tonic-gate 
1690*7c478bd9Sstevel@tonic-gate 	assert(wip->inst != NULL);
1691*7c478bd9Sstevel@tonic-gate 	assert(wip->pg == NULL);
1692*7c478bd9Sstevel@tonic-gate 
1693*7c478bd9Sstevel@tonic-gate 	do {
1694*7c478bd9Sstevel@tonic-gate 		if (pg)
1695*7c478bd9Sstevel@tonic-gate 			scf_pg_destroy(pg);
1696*7c478bd9Sstevel@tonic-gate 		if (inst_get_state(wip->inst, state, wip->fmri, &pg) != 0) {
1697*7c478bd9Sstevel@tonic-gate 			exit_status = EXIT_SVC_FAILURE;
1698*7c478bd9Sstevel@tonic-gate 			return (0);
1699*7c478bd9Sstevel@tonic-gate 		}
1700*7c478bd9Sstevel@tonic-gate 
1701*7c478bd9Sstevel@tonic-gate 		if (strcmp(state, SCF_STATE_STRING_ONLINE) == 0 ||
1702*7c478bd9Sstevel@tonic-gate 		    strcmp(state, SCF_STATE_STRING_DEGRADED) == 0) {
1703*7c478bd9Sstevel@tonic-gate 			/*
1704*7c478bd9Sstevel@tonic-gate 			 * We're done.
1705*7c478bd9Sstevel@tonic-gate 			 */
1706*7c478bd9Sstevel@tonic-gate 			goto out;
1707*7c478bd9Sstevel@tonic-gate 		}
1708*7c478bd9Sstevel@tonic-gate 
1709*7c478bd9Sstevel@tonic-gate 		if (strcmp(state, SCF_STATE_STRING_MAINT) == 0) {
1710*7c478bd9Sstevel@tonic-gate 			/*
1711*7c478bd9Sstevel@tonic-gate 			 * The service is ill.
1712*7c478bd9Sstevel@tonic-gate 			 */
1713*7c478bd9Sstevel@tonic-gate 			uu_warn(gettext("Instance \"%s\" is in maintenance"
1714*7c478bd9Sstevel@tonic-gate 			    " state.\n"), wip->fmri);
1715*7c478bd9Sstevel@tonic-gate 			exit_status = EXIT_SVC_FAILURE;
1716*7c478bd9Sstevel@tonic-gate 			goto out;
1717*7c478bd9Sstevel@tonic-gate 		}
1718*7c478bd9Sstevel@tonic-gate 
1719*7c478bd9Sstevel@tonic-gate 		if (!is_enabled(wip->inst)) {
1720*7c478bd9Sstevel@tonic-gate 			/*
1721*7c478bd9Sstevel@tonic-gate 			 * Someone stepped in and disabled the service.
1722*7c478bd9Sstevel@tonic-gate 			 */
1723*7c478bd9Sstevel@tonic-gate 			uu_warn(gettext("Instance \"%s\" has been disabled"
1724*7c478bd9Sstevel@tonic-gate 			    " by another entity.\n"), wip->fmri);
1725*7c478bd9Sstevel@tonic-gate 			exit_status = EXIT_SVC_FAILURE;
1726*7c478bd9Sstevel@tonic-gate 			goto out;
1727*7c478bd9Sstevel@tonic-gate 		}
1728*7c478bd9Sstevel@tonic-gate 
1729*7c478bd9Sstevel@tonic-gate 		if (!has_potential(wip->inst, B_FALSE)) {
1730*7c478bd9Sstevel@tonic-gate 			/*
1731*7c478bd9Sstevel@tonic-gate 			 * Our dependencies aren't met.  We'll never
1732*7c478bd9Sstevel@tonic-gate 			 * amount to anything.
1733*7c478bd9Sstevel@tonic-gate 			 */
1734*7c478bd9Sstevel@tonic-gate 			uu_warn(gettext("Instance \"%s\" has unsatisfied"
1735*7c478bd9Sstevel@tonic-gate 			    " dependencies.\n"), wip->fmri);
1736*7c478bd9Sstevel@tonic-gate 			/*
1737*7c478bd9Sstevel@tonic-gate 			 * EXIT_SVC_FAILURE takes precedence over
1738*7c478bd9Sstevel@tonic-gate 			 * EXIT_DEP_FAILURE
1739*7c478bd9Sstevel@tonic-gate 			 */
1740*7c478bd9Sstevel@tonic-gate 			if (exit_status == 0)
1741*7c478bd9Sstevel@tonic-gate 				exit_status = EXIT_DEP_FAILURE;
1742*7c478bd9Sstevel@tonic-gate 			goto out;
1743*7c478bd9Sstevel@tonic-gate 		}
1744*7c478bd9Sstevel@tonic-gate 	} while (_scf_pg_wait(pg, WAIT_INTERVAL) >= 0);
1745*7c478bd9Sstevel@tonic-gate 	scfdie();
1746*7c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
1747*7c478bd9Sstevel@tonic-gate 
1748*7c478bd9Sstevel@tonic-gate out:
1749*7c478bd9Sstevel@tonic-gate 	scf_pg_destroy(pg);
1750*7c478bd9Sstevel@tonic-gate 	return (0);
1751*7c478bd9Sstevel@tonic-gate }
1752*7c478bd9Sstevel@tonic-gate 
1753*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
1754*7c478bd9Sstevel@tonic-gate static int
1755*7c478bd9Sstevel@tonic-gate wait_fmri_disabled(void *data, scf_walkinfo_t *wip)
1756*7c478bd9Sstevel@tonic-gate {
1757*7c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg = NULL;
1758*7c478bd9Sstevel@tonic-gate 	char state[MAX_SCF_STATE_STRING_SZ];
1759*7c478bd9Sstevel@tonic-gate 
1760*7c478bd9Sstevel@tonic-gate 	assert(wip->inst != NULL);
1761*7c478bd9Sstevel@tonic-gate 	assert(wip->pg == NULL);
1762*7c478bd9Sstevel@tonic-gate 
1763*7c478bd9Sstevel@tonic-gate 	do {
1764*7c478bd9Sstevel@tonic-gate 		if (pg)
1765*7c478bd9Sstevel@tonic-gate 			scf_pg_destroy(pg);
1766*7c478bd9Sstevel@tonic-gate 		if (inst_get_state(wip->inst, state, wip->fmri, &pg) != 0) {
1767*7c478bd9Sstevel@tonic-gate 			exit_status = EXIT_SVC_FAILURE;
1768*7c478bd9Sstevel@tonic-gate 			return (0);
1769*7c478bd9Sstevel@tonic-gate 		}
1770*7c478bd9Sstevel@tonic-gate 
1771*7c478bd9Sstevel@tonic-gate 		if (strcmp(state, SCF_STATE_STRING_DISABLED) == 0) {
1772*7c478bd9Sstevel@tonic-gate 			/*
1773*7c478bd9Sstevel@tonic-gate 			 * We're done.
1774*7c478bd9Sstevel@tonic-gate 			 */
1775*7c478bd9Sstevel@tonic-gate 			goto out;
1776*7c478bd9Sstevel@tonic-gate 		}
1777*7c478bd9Sstevel@tonic-gate 
1778*7c478bd9Sstevel@tonic-gate 		if (strcmp(state, SCF_STATE_STRING_MAINT) == 0) {
1779*7c478bd9Sstevel@tonic-gate 			/*
1780*7c478bd9Sstevel@tonic-gate 			 * The service is ill.
1781*7c478bd9Sstevel@tonic-gate 			 */
1782*7c478bd9Sstevel@tonic-gate 			uu_warn(gettext("Instance \"%s\" is in maintenance"
1783*7c478bd9Sstevel@tonic-gate 			    " state.\n"), wip->fmri);
1784*7c478bd9Sstevel@tonic-gate 			exit_status = EXIT_SVC_FAILURE;
1785*7c478bd9Sstevel@tonic-gate 			goto out;
1786*7c478bd9Sstevel@tonic-gate 		}
1787*7c478bd9Sstevel@tonic-gate 
1788*7c478bd9Sstevel@tonic-gate 		if (is_enabled(wip->inst)) {
1789*7c478bd9Sstevel@tonic-gate 			/*
1790*7c478bd9Sstevel@tonic-gate 			 * Someone stepped in and enabled the service.
1791*7c478bd9Sstevel@tonic-gate 			 */
1792*7c478bd9Sstevel@tonic-gate 			uu_warn(gettext("Instance \"%s\" has been enabled"
1793*7c478bd9Sstevel@tonic-gate 			    " by another entity.\n"), wip->fmri);
1794*7c478bd9Sstevel@tonic-gate 			exit_status = EXIT_SVC_FAILURE;
1795*7c478bd9Sstevel@tonic-gate 			goto out;
1796*7c478bd9Sstevel@tonic-gate 		}
1797*7c478bd9Sstevel@tonic-gate 
1798*7c478bd9Sstevel@tonic-gate 		if (!has_potential(wip->inst, B_TRUE)) {
1799*7c478bd9Sstevel@tonic-gate 			/*
1800*7c478bd9Sstevel@tonic-gate 			 * Our restarter is hopeless.
1801*7c478bd9Sstevel@tonic-gate 			 */
1802*7c478bd9Sstevel@tonic-gate 			uu_warn(gettext("Restarter for instance \"%s\" is"
1803*7c478bd9Sstevel@tonic-gate 			    " unavailable.\n"), wip->fmri);
1804*7c478bd9Sstevel@tonic-gate 			/*
1805*7c478bd9Sstevel@tonic-gate 			 * EXIT_SVC_FAILURE takes precedence over
1806*7c478bd9Sstevel@tonic-gate 			 * EXIT_DEP_FAILURE
1807*7c478bd9Sstevel@tonic-gate 			 */
1808*7c478bd9Sstevel@tonic-gate 			if (exit_status == 0)
1809*7c478bd9Sstevel@tonic-gate 				exit_status = EXIT_DEP_FAILURE;
1810*7c478bd9Sstevel@tonic-gate 			goto out;
1811*7c478bd9Sstevel@tonic-gate 		}
1812*7c478bd9Sstevel@tonic-gate 
1813*7c478bd9Sstevel@tonic-gate 	} while (_scf_pg_wait(pg, WAIT_INTERVAL) >= 0);
1814*7c478bd9Sstevel@tonic-gate 	scfdie();
1815*7c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
1816*7c478bd9Sstevel@tonic-gate 
1817*7c478bd9Sstevel@tonic-gate out:
1818*7c478bd9Sstevel@tonic-gate 	scf_pg_destroy(pg);
1819*7c478bd9Sstevel@tonic-gate 	return (0);
1820*7c478bd9Sstevel@tonic-gate }
1821*7c478bd9Sstevel@tonic-gate 
1822*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
1823*7c478bd9Sstevel@tonic-gate static int
1824*7c478bd9Sstevel@tonic-gate clear_instance(void *data, scf_walkinfo_t *wip)
1825*7c478bd9Sstevel@tonic-gate {
1826*7c478bd9Sstevel@tonic-gate 	char state[MAX_SCF_STATE_STRING_SZ];
1827*7c478bd9Sstevel@tonic-gate 
1828*7c478bd9Sstevel@tonic-gate 	assert(wip->inst != NULL);
1829*7c478bd9Sstevel@tonic-gate 	assert(wip->pg == NULL);
1830*7c478bd9Sstevel@tonic-gate 
1831*7c478bd9Sstevel@tonic-gate 	if (inst_get_state(wip->inst, state, wip->fmri, NULL) != 0)
1832*7c478bd9Sstevel@tonic-gate 		return (0);
1833*7c478bd9Sstevel@tonic-gate 
1834*7c478bd9Sstevel@tonic-gate 	if (strcmp(state, SCF_STATE_STRING_MAINT) == 0) {
1835*7c478bd9Sstevel@tonic-gate 		set_inst_action(wip->fmri, wip->inst, SCF_PROPERTY_MAINT_OFF);
1836*7c478bd9Sstevel@tonic-gate 	} else if (strcmp(state, SCF_STATE_STRING_DEGRADED) ==
1837*7c478bd9Sstevel@tonic-gate 	    0) {
1838*7c478bd9Sstevel@tonic-gate 		set_inst_action(wip->fmri, wip->inst, SCF_PROPERTY_RESTORE);
1839*7c478bd9Sstevel@tonic-gate 	} else {
1840*7c478bd9Sstevel@tonic-gate 		uu_warn(gettext("Instance \"%s\" is not in a "
1841*7c478bd9Sstevel@tonic-gate 		    "maintenance or degraded state.\n"), wip->fmri);
1842*7c478bd9Sstevel@tonic-gate 
1843*7c478bd9Sstevel@tonic-gate 		exit_status = 1;
1844*7c478bd9Sstevel@tonic-gate 	}
1845*7c478bd9Sstevel@tonic-gate 
1846*7c478bd9Sstevel@tonic-gate 	return (0);
1847*7c478bd9Sstevel@tonic-gate }
1848*7c478bd9Sstevel@tonic-gate 
1849*7c478bd9Sstevel@tonic-gate static int
1850*7c478bd9Sstevel@tonic-gate set_fmri_action(void *action, scf_walkinfo_t *wip)
1851*7c478bd9Sstevel@tonic-gate {
1852*7c478bd9Sstevel@tonic-gate 	assert(wip->inst != NULL && wip->pg == NULL);
1853*7c478bd9Sstevel@tonic-gate 
1854*7c478bd9Sstevel@tonic-gate 	set_inst_action(wip->fmri, wip->inst, action);
1855*7c478bd9Sstevel@tonic-gate 
1856*7c478bd9Sstevel@tonic-gate 	return (0);
1857*7c478bd9Sstevel@tonic-gate }
1858*7c478bd9Sstevel@tonic-gate 
1859*7c478bd9Sstevel@tonic-gate /*
1860*7c478bd9Sstevel@tonic-gate  * Flags to control 'mark' action.
1861*7c478bd9Sstevel@tonic-gate  */
1862*7c478bd9Sstevel@tonic-gate #define	MARK_IMMEDIATE	0x1
1863*7c478bd9Sstevel@tonic-gate #define	MARK_TEMPORARY	0x2
1864*7c478bd9Sstevel@tonic-gate 
1865*7c478bd9Sstevel@tonic-gate static int
1866*7c478bd9Sstevel@tonic-gate force_degraded(void *data, scf_walkinfo_t *wip)
1867*7c478bd9Sstevel@tonic-gate {
1868*7c478bd9Sstevel@tonic-gate 	int flags = (int)data;
1869*7c478bd9Sstevel@tonic-gate 	char state[MAX_SCF_STATE_STRING_SZ];
1870*7c478bd9Sstevel@tonic-gate 
1871*7c478bd9Sstevel@tonic-gate 	if (inst_get_state(wip->inst, state, wip->fmri, NULL) != 0) {
1872*7c478bd9Sstevel@tonic-gate 		exit_status = 1;
1873*7c478bd9Sstevel@tonic-gate 		return (0);
1874*7c478bd9Sstevel@tonic-gate 	}
1875*7c478bd9Sstevel@tonic-gate 
1876*7c478bd9Sstevel@tonic-gate 	if (strcmp(state, SCF_STATE_STRING_ONLINE) != 0) {
1877*7c478bd9Sstevel@tonic-gate 		uu_warn(gettext("Instance \"%s\" is not online.\n"), wip->fmri);
1878*7c478bd9Sstevel@tonic-gate 		exit_status = 1;
1879*7c478bd9Sstevel@tonic-gate 		return (0);
1880*7c478bd9Sstevel@tonic-gate 	}
1881*7c478bd9Sstevel@tonic-gate 
1882*7c478bd9Sstevel@tonic-gate 	set_inst_action(wip->fmri, wip->inst, (flags & MARK_IMMEDIATE) ?
1883*7c478bd9Sstevel@tonic-gate 	    SCF_PROPERTY_DEGRADE_IMMEDIATE : SCF_PROPERTY_DEGRADED);
1884*7c478bd9Sstevel@tonic-gate 
1885*7c478bd9Sstevel@tonic-gate 	return (0);
1886*7c478bd9Sstevel@tonic-gate }
1887*7c478bd9Sstevel@tonic-gate 
1888*7c478bd9Sstevel@tonic-gate static int
1889*7c478bd9Sstevel@tonic-gate force_maintenance(void *data, scf_walkinfo_t *wip)
1890*7c478bd9Sstevel@tonic-gate {
1891*7c478bd9Sstevel@tonic-gate 	int flags = (int)data;
1892*7c478bd9Sstevel@tonic-gate 	const char *prop;
1893*7c478bd9Sstevel@tonic-gate 
1894*7c478bd9Sstevel@tonic-gate 	if (flags & MARK_IMMEDIATE) {
1895*7c478bd9Sstevel@tonic-gate 		prop = (flags & MARK_TEMPORARY) ?
1896*7c478bd9Sstevel@tonic-gate 		    SCF_PROPERTY_MAINT_ON_IMMTEMP :
1897*7c478bd9Sstevel@tonic-gate 		    SCF_PROPERTY_MAINT_ON_IMMEDIATE;
1898*7c478bd9Sstevel@tonic-gate 	} else {
1899*7c478bd9Sstevel@tonic-gate 		prop = (flags & MARK_TEMPORARY) ?
1900*7c478bd9Sstevel@tonic-gate 		    SCF_PROPERTY_MAINT_ON_TEMPORARY :
1901*7c478bd9Sstevel@tonic-gate 		    SCF_PROPERTY_MAINT_ON;
1902*7c478bd9Sstevel@tonic-gate 	}
1903*7c478bd9Sstevel@tonic-gate 
1904*7c478bd9Sstevel@tonic-gate 	set_inst_action(wip->fmri, wip->inst, prop);
1905*7c478bd9Sstevel@tonic-gate 
1906*7c478bd9Sstevel@tonic-gate 	return (0);
1907*7c478bd9Sstevel@tonic-gate }
1908*7c478bd9Sstevel@tonic-gate 
1909*7c478bd9Sstevel@tonic-gate static void
1910*7c478bd9Sstevel@tonic-gate set_milestone(const char *fmri, boolean_t temporary)
1911*7c478bd9Sstevel@tonic-gate {
1912*7c478bd9Sstevel@tonic-gate 	scf_instance_t *inst;
1913*7c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg;
1914*7c478bd9Sstevel@tonic-gate 	int r;
1915*7c478bd9Sstevel@tonic-gate 
1916*7c478bd9Sstevel@tonic-gate 	if (temporary) {
1917*7c478bd9Sstevel@tonic-gate 		set_astring_prop(SCF_SERVICE_STARTD, SCF_PG_OPTIONS_OVR,
1918*7c478bd9Sstevel@tonic-gate 		    SCF_PG_OPTIONS_OVR_TYPE, SCF_PG_OPTIONS_OVR_FLAGS,
1919*7c478bd9Sstevel@tonic-gate 		    SCF_PROPERTY_MILESTONE, fmri);
1920*7c478bd9Sstevel@tonic-gate 		return;
1921*7c478bd9Sstevel@tonic-gate 	}
1922*7c478bd9Sstevel@tonic-gate 
1923*7c478bd9Sstevel@tonic-gate 	if ((inst = scf_instance_create(h)) == NULL ||
1924*7c478bd9Sstevel@tonic-gate 	    (pg = scf_pg_create(h)) == NULL)
1925*7c478bd9Sstevel@tonic-gate 		scfdie();
1926*7c478bd9Sstevel@tonic-gate 
1927*7c478bd9Sstevel@tonic-gate 	if (get_inst(SCF_SERVICE_STARTD, inst) != 0) {
1928*7c478bd9Sstevel@tonic-gate 		scf_instance_destroy(inst);
1929*7c478bd9Sstevel@tonic-gate 		return;
1930*7c478bd9Sstevel@tonic-gate 	}
1931*7c478bd9Sstevel@tonic-gate 
1932*7c478bd9Sstevel@tonic-gate 	/*
1933*7c478bd9Sstevel@tonic-gate 	 * Set the persistent milestone before deleting the override so we don't
1934*7c478bd9Sstevel@tonic-gate 	 * glitch.
1935*7c478bd9Sstevel@tonic-gate 	 */
1936*7c478bd9Sstevel@tonic-gate 	set_astring_prop(SCF_SERVICE_STARTD, SCF_PG_OPTIONS,
1937*7c478bd9Sstevel@tonic-gate 	    SCF_PG_OPTIONS_TYPE, SCF_PG_OPTIONS_FLAGS, SCF_PROPERTY_MILESTONE,
1938*7c478bd9Sstevel@tonic-gate 	    fmri);
1939*7c478bd9Sstevel@tonic-gate 
1940*7c478bd9Sstevel@tonic-gate 	if (scf_instance_get_pg(inst, SCF_PG_OPTIONS_OVR, pg) == 0) {
1941*7c478bd9Sstevel@tonic-gate 		r = delete_prop(pg, SCF_PROPERTY_MILESTONE);
1942*7c478bd9Sstevel@tonic-gate 		switch (r) {
1943*7c478bd9Sstevel@tonic-gate 		case 0:
1944*7c478bd9Sstevel@tonic-gate 			break;
1945*7c478bd9Sstevel@tonic-gate 
1946*7c478bd9Sstevel@tonic-gate 		case ECANCELED:
1947*7c478bd9Sstevel@tonic-gate 			uu_warn(emsg_no_service, fmri);
1948*7c478bd9Sstevel@tonic-gate 			exit_status = 1;
1949*7c478bd9Sstevel@tonic-gate 			goto out;
1950*7c478bd9Sstevel@tonic-gate 
1951*7c478bd9Sstevel@tonic-gate 		case EPERM:
1952*7c478bd9Sstevel@tonic-gate 			uu_warn(gettext("Could not delete %s/%s property of "
1953*7c478bd9Sstevel@tonic-gate 			    "%s: permission denied.\n"), SCF_PG_OPTIONS_OVR,
1954*7c478bd9Sstevel@tonic-gate 			    SCF_PROPERTY_MILESTONE, SCF_SERVICE_STARTD);
1955*7c478bd9Sstevel@tonic-gate 			exit_status = 1;
1956*7c478bd9Sstevel@tonic-gate 			goto out;
1957*7c478bd9Sstevel@tonic-gate 
1958*7c478bd9Sstevel@tonic-gate 		case EACCES:
1959*7c478bd9Sstevel@tonic-gate 			uu_warn(gettext("Could not delete %s/%s property of "
1960*7c478bd9Sstevel@tonic-gate 			    "%s: access denied.\n"), SCF_PG_OPTIONS_OVR,
1961*7c478bd9Sstevel@tonic-gate 			    SCF_PROPERTY_MILESTONE, SCF_SERVICE_STARTD);
1962*7c478bd9Sstevel@tonic-gate 			exit_status = 1;
1963*7c478bd9Sstevel@tonic-gate 			goto out;
1964*7c478bd9Sstevel@tonic-gate 
1965*7c478bd9Sstevel@tonic-gate 		case EROFS:
1966*7c478bd9Sstevel@tonic-gate 			uu_warn(gettext("Could not delete %s/%s property of "
1967*7c478bd9Sstevel@tonic-gate 			    "%s: backend read-only.\n"), SCF_PG_OPTIONS_OVR,
1968*7c478bd9Sstevel@tonic-gate 			    SCF_PROPERTY_MILESTONE, SCF_SERVICE_STARTD);
1969*7c478bd9Sstevel@tonic-gate 			exit_status = 1;
1970*7c478bd9Sstevel@tonic-gate 			goto out;
1971*7c478bd9Sstevel@tonic-gate 
1972*7c478bd9Sstevel@tonic-gate 		default:
1973*7c478bd9Sstevel@tonic-gate 			bad_error("delete_prop", r);
1974*7c478bd9Sstevel@tonic-gate 		}
1975*7c478bd9Sstevel@tonic-gate 	} else {
1976*7c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
1977*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
1978*7c478bd9Sstevel@tonic-gate 			break;
1979*7c478bd9Sstevel@tonic-gate 
1980*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
1981*7c478bd9Sstevel@tonic-gate 			uu_warn(emsg_no_service, fmri);
1982*7c478bd9Sstevel@tonic-gate 			exit_status = 1;
1983*7c478bd9Sstevel@tonic-gate 			goto out;
1984*7c478bd9Sstevel@tonic-gate 
1985*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_CONNECTION_BROKEN:
1986*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_HANDLE_MISMATCH:
1987*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_BOUND:
1988*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_INVALID_ARGUMENT:
1989*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
1990*7c478bd9Sstevel@tonic-gate 		default:
1991*7c478bd9Sstevel@tonic-gate 			scfdie();
1992*7c478bd9Sstevel@tonic-gate 		}
1993*7c478bd9Sstevel@tonic-gate 	}
1994*7c478bd9Sstevel@tonic-gate 
1995*7c478bd9Sstevel@tonic-gate out:
1996*7c478bd9Sstevel@tonic-gate 	scf_pg_destroy(pg);
1997*7c478bd9Sstevel@tonic-gate 	scf_instance_destroy(inst);
1998*7c478bd9Sstevel@tonic-gate }
1999*7c478bd9Sstevel@tonic-gate 
2000*7c478bd9Sstevel@tonic-gate static char const *milestones[] = {
2001*7c478bd9Sstevel@tonic-gate 	SCF_MILESTONE_SINGLE_USER,
2002*7c478bd9Sstevel@tonic-gate 	SCF_MILESTONE_MULTI_USER,
2003*7c478bd9Sstevel@tonic-gate 	SCF_MILESTONE_MULTI_USER_SERVER,
2004*7c478bd9Sstevel@tonic-gate 	NULL
2005*7c478bd9Sstevel@tonic-gate };
2006*7c478bd9Sstevel@tonic-gate 
2007*7c478bd9Sstevel@tonic-gate static void
2008*7c478bd9Sstevel@tonic-gate usage_milestone()
2009*7c478bd9Sstevel@tonic-gate {
2010*7c478bd9Sstevel@tonic-gate 	const char **ms;
2011*7c478bd9Sstevel@tonic-gate 
2012*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(
2013*7c478bd9Sstevel@tonic-gate 	"Usage: svcadm milestone [-d] <milestone>\n\n"
2014*7c478bd9Sstevel@tonic-gate 	"\t-d\tmake the specified milestone the default for system boot\n\n"
2015*7c478bd9Sstevel@tonic-gate 	"\tMilestones can be specified using an FMRI or abbreviation.\n"
2016*7c478bd9Sstevel@tonic-gate 	"\tThe major milestones are as follows:\n\n"
2017*7c478bd9Sstevel@tonic-gate 	"\tall\n"
2018*7c478bd9Sstevel@tonic-gate 	"\tnone\n"));
2019*7c478bd9Sstevel@tonic-gate 
2020*7c478bd9Sstevel@tonic-gate 	for (ms = milestones; *ms != NULL; ms++)
2021*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "\t%s\n", *ms);
2022*7c478bd9Sstevel@tonic-gate 
2023*7c478bd9Sstevel@tonic-gate 	exit(UU_EXIT_USAGE);
2024*7c478bd9Sstevel@tonic-gate }
2025*7c478bd9Sstevel@tonic-gate 
2026*7c478bd9Sstevel@tonic-gate static const char *
2027*7c478bd9Sstevel@tonic-gate validate_milestone(const char *milestone)
2028*7c478bd9Sstevel@tonic-gate {
2029*7c478bd9Sstevel@tonic-gate 	const char **ms;
2030*7c478bd9Sstevel@tonic-gate 	const char *tmp;
2031*7c478bd9Sstevel@tonic-gate 	size_t len;
2032*7c478bd9Sstevel@tonic-gate 
2033*7c478bd9Sstevel@tonic-gate 	if (strcmp(milestone, "all") == 0)
2034*7c478bd9Sstevel@tonic-gate 		return (milestone);
2035*7c478bd9Sstevel@tonic-gate 
2036*7c478bd9Sstevel@tonic-gate 	if (strcmp(milestone, "none") == 0)
2037*7c478bd9Sstevel@tonic-gate 		return (milestone);
2038*7c478bd9Sstevel@tonic-gate 
2039*7c478bd9Sstevel@tonic-gate 	/*
2040*7c478bd9Sstevel@tonic-gate 	 * Determine if this is a full or partial milestone
2041*7c478bd9Sstevel@tonic-gate 	 */
2042*7c478bd9Sstevel@tonic-gate 	for (ms = milestones; *ms != NULL; ms++) {
2043*7c478bd9Sstevel@tonic-gate 		if ((tmp = strstr(*ms, milestone)) != NULL) {
2044*7c478bd9Sstevel@tonic-gate 			len = strlen(milestone);
2045*7c478bd9Sstevel@tonic-gate 
2046*7c478bd9Sstevel@tonic-gate 			/*
2047*7c478bd9Sstevel@tonic-gate 			 * The beginning of the string must align with the start
2048*7c478bd9Sstevel@tonic-gate 			 * of a milestone fmri, or on the boundary between
2049*7c478bd9Sstevel@tonic-gate 			 * elements.  The end of the string must align with the
2050*7c478bd9Sstevel@tonic-gate 			 * end of the milestone, or at the instance boundary.
2051*7c478bd9Sstevel@tonic-gate 			 */
2052*7c478bd9Sstevel@tonic-gate 			if ((tmp == *ms || tmp[-1] == '/') &&
2053*7c478bd9Sstevel@tonic-gate 			    (tmp[len] == '\0' || tmp[len] == ':'))
2054*7c478bd9Sstevel@tonic-gate 				return (*ms);
2055*7c478bd9Sstevel@tonic-gate 		}
2056*7c478bd9Sstevel@tonic-gate 	}
2057*7c478bd9Sstevel@tonic-gate 
2058*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
2059*7c478bd9Sstevel@tonic-gate 	    gettext("\"%s\" is not a valid major milestone.\n"), milestone);
2060*7c478bd9Sstevel@tonic-gate 
2061*7c478bd9Sstevel@tonic-gate 	usage_milestone();
2062*7c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
2063*7c478bd9Sstevel@tonic-gate }
2064*7c478bd9Sstevel@tonic-gate 
2065*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2066*7c478bd9Sstevel@tonic-gate static void
2067*7c478bd9Sstevel@tonic-gate quiet(const char *fmt, ...)
2068*7c478bd9Sstevel@tonic-gate {
2069*7c478bd9Sstevel@tonic-gate 	/* Do nothing */
2070*7c478bd9Sstevel@tonic-gate }
2071*7c478bd9Sstevel@tonic-gate 
2072*7c478bd9Sstevel@tonic-gate int
2073*7c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
2074*7c478bd9Sstevel@tonic-gate {
2075*7c478bd9Sstevel@tonic-gate 	int o;
2076*7c478bd9Sstevel@tonic-gate 	int err;
2077*7c478bd9Sstevel@tonic-gate 
2078*7c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
2079*7c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
2080*7c478bd9Sstevel@tonic-gate 
2081*7c478bd9Sstevel@tonic-gate 	(void) uu_setpname(argv[0]);
2082*7c478bd9Sstevel@tonic-gate 
2083*7c478bd9Sstevel@tonic-gate 	if (argc < 2)
2084*7c478bd9Sstevel@tonic-gate 		usage();
2085*7c478bd9Sstevel@tonic-gate 
2086*7c478bd9Sstevel@tonic-gate 	max_scf_fmri_sz = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH);
2087*7c478bd9Sstevel@tonic-gate 	if (max_scf_fmri_sz < 0)
2088*7c478bd9Sstevel@tonic-gate 		scfdie();
2089*7c478bd9Sstevel@tonic-gate 	++max_scf_fmri_sz;
2090*7c478bd9Sstevel@tonic-gate 
2091*7c478bd9Sstevel@tonic-gate 	scratch_fmri = malloc(max_scf_fmri_sz);
2092*7c478bd9Sstevel@tonic-gate 	if (scratch_fmri == NULL)
2093*7c478bd9Sstevel@tonic-gate 		uu_die(emsg_nomem);
2094*7c478bd9Sstevel@tonic-gate 
2095*7c478bd9Sstevel@tonic-gate 	h = scf_handle_create(SCF_VERSION);
2096*7c478bd9Sstevel@tonic-gate 	if (h == NULL)
2097*7c478bd9Sstevel@tonic-gate 		scfdie();
2098*7c478bd9Sstevel@tonic-gate 
2099*7c478bd9Sstevel@tonic-gate 	if (scf_handle_bind(h) == -1)
2100*7c478bd9Sstevel@tonic-gate 		uu_die(gettext("Couldn't bind to svc.configd.\n"));
2101*7c478bd9Sstevel@tonic-gate 
2102*7c478bd9Sstevel@tonic-gate 	while ((o = getopt(argc, argv, "v")) != -1) {
2103*7c478bd9Sstevel@tonic-gate 		if (o == 'v')
2104*7c478bd9Sstevel@tonic-gate 			verbose = 1;
2105*7c478bd9Sstevel@tonic-gate 		else
2106*7c478bd9Sstevel@tonic-gate 			usage();
2107*7c478bd9Sstevel@tonic-gate 	}
2108*7c478bd9Sstevel@tonic-gate 
2109*7c478bd9Sstevel@tonic-gate 	if (optind >= argc)
2110*7c478bd9Sstevel@tonic-gate 		usage();
2111*7c478bd9Sstevel@tonic-gate 
2112*7c478bd9Sstevel@tonic-gate 	emsg_permission_denied = gettext("%s: Permission denied.\n");
2113*7c478bd9Sstevel@tonic-gate 	emsg_nomem = gettext("Out of memory.\n");
2114*7c478bd9Sstevel@tonic-gate 	emsg_create_pg_perm_denied = gettext("%s: Couldn't create \"%s\" "
2115*7c478bd9Sstevel@tonic-gate 	    "property group (permission denied).\n");
2116*7c478bd9Sstevel@tonic-gate 	emsg_pg_perm_denied = gettext("%s: Couldn't modify \"%s\" property "
2117*7c478bd9Sstevel@tonic-gate 	    "group (permission denied).\n");
2118*7c478bd9Sstevel@tonic-gate 	emsg_prop_perm_denied = gettext("%s: Couldn't modify \"%s/%s\" "
2119*7c478bd9Sstevel@tonic-gate 	    "property (permission denied).\n");
2120*7c478bd9Sstevel@tonic-gate 	emsg_no_service = gettext("No such service \"%s\".\n");
2121*7c478bd9Sstevel@tonic-gate 
2122*7c478bd9Sstevel@tonic-gate 	if (strcmp(argv[optind], "enable") == 0) {
2123*7c478bd9Sstevel@tonic-gate 		int flags = SET_ENABLED;
2124*7c478bd9Sstevel@tonic-gate 		int wait = 0;
2125*7c478bd9Sstevel@tonic-gate 		int error = 0;
2126*7c478bd9Sstevel@tonic-gate 
2127*7c478bd9Sstevel@tonic-gate 		++optind;
2128*7c478bd9Sstevel@tonic-gate 
2129*7c478bd9Sstevel@tonic-gate 		while ((o = getopt(argc, argv, "rst")) != -1) {
2130*7c478bd9Sstevel@tonic-gate 			if (o == 'r')
2131*7c478bd9Sstevel@tonic-gate 				flags |= SET_RECURSIVE;
2132*7c478bd9Sstevel@tonic-gate 			else if (o == 't')
2133*7c478bd9Sstevel@tonic-gate 				flags |= SET_TEMPORARY;
2134*7c478bd9Sstevel@tonic-gate 			else if (o == 's')
2135*7c478bd9Sstevel@tonic-gate 				wait = 1;
2136*7c478bd9Sstevel@tonic-gate 			else if (o == '?')
2137*7c478bd9Sstevel@tonic-gate 				usage();
2138*7c478bd9Sstevel@tonic-gate 			else {
2139*7c478bd9Sstevel@tonic-gate 				assert(0);
2140*7c478bd9Sstevel@tonic-gate 				abort();
2141*7c478bd9Sstevel@tonic-gate 			}
2142*7c478bd9Sstevel@tonic-gate 		}
2143*7c478bd9Sstevel@tonic-gate 		argc -= optind;
2144*7c478bd9Sstevel@tonic-gate 		argv += optind;
2145*7c478bd9Sstevel@tonic-gate 
2146*7c478bd9Sstevel@tonic-gate 		if (argc <= 0)
2147*7c478bd9Sstevel@tonic-gate 			usage();
2148*7c478bd9Sstevel@tonic-gate 
2149*7c478bd9Sstevel@tonic-gate 		/*
2150*7c478bd9Sstevel@tonic-gate 		 * We want to continue with -s processing if we had
2151*7c478bd9Sstevel@tonic-gate 		 * invalid options, but not if an enable failed.  We
2152*7c478bd9Sstevel@tonic-gate 		 * squelch output the second time we walk fmris; we saw
2153*7c478bd9Sstevel@tonic-gate 		 * the errors the first time.
2154*7c478bd9Sstevel@tonic-gate 		 */
2155*7c478bd9Sstevel@tonic-gate 		if ((err = scf_walk_fmri(h, argc, argv, 0, set_fmri_enabled,
2156*7c478bd9Sstevel@tonic-gate 		    (void *)flags, &error, uu_warn)) != 0) {
2157*7c478bd9Sstevel@tonic-gate 
2158*7c478bd9Sstevel@tonic-gate 			uu_warn(gettext("failed to iterate over "
2159*7c478bd9Sstevel@tonic-gate 			    "instances: %s\n"), scf_strerror(err));
2160*7c478bd9Sstevel@tonic-gate 			exit_status = UU_EXIT_FATAL;
2161*7c478bd9Sstevel@tonic-gate 
2162*7c478bd9Sstevel@tonic-gate 		} else if (wait && exit_status == 0 &&
2163*7c478bd9Sstevel@tonic-gate 		    (err = scf_walk_fmri(h, argc, argv, 0, wait_fmri_enabled,
2164*7c478bd9Sstevel@tonic-gate 		    (void *)flags, &error, quiet)) != 0) {
2165*7c478bd9Sstevel@tonic-gate 
2166*7c478bd9Sstevel@tonic-gate 			uu_warn(gettext("failed to iterate over "
2167*7c478bd9Sstevel@tonic-gate 			    "instances: %s\n"), scf_strerror(err));
2168*7c478bd9Sstevel@tonic-gate 			exit_status = UU_EXIT_FATAL;
2169*7c478bd9Sstevel@tonic-gate 		}
2170*7c478bd9Sstevel@tonic-gate 
2171*7c478bd9Sstevel@tonic-gate 		if (error > 0)
2172*7c478bd9Sstevel@tonic-gate 			exit_status = error;
2173*7c478bd9Sstevel@tonic-gate 
2174*7c478bd9Sstevel@tonic-gate 	} else if (strcmp(argv[optind], "disable") == 0) {
2175*7c478bd9Sstevel@tonic-gate 		int flags = 0;
2176*7c478bd9Sstevel@tonic-gate 		int wait = 0;
2177*7c478bd9Sstevel@tonic-gate 		int error = 0;
2178*7c478bd9Sstevel@tonic-gate 
2179*7c478bd9Sstevel@tonic-gate 		++optind;
2180*7c478bd9Sstevel@tonic-gate 
2181*7c478bd9Sstevel@tonic-gate 		while ((o = getopt(argc, argv, "st")) != -1) {
2182*7c478bd9Sstevel@tonic-gate 			if (o == 't')
2183*7c478bd9Sstevel@tonic-gate 				flags |= SET_TEMPORARY;
2184*7c478bd9Sstevel@tonic-gate 			else if (o == 's')
2185*7c478bd9Sstevel@tonic-gate 				wait = 1;
2186*7c478bd9Sstevel@tonic-gate 			else if (o == '?')
2187*7c478bd9Sstevel@tonic-gate 				usage();
2188*7c478bd9Sstevel@tonic-gate 			else {
2189*7c478bd9Sstevel@tonic-gate 				assert(0);
2190*7c478bd9Sstevel@tonic-gate 				abort();
2191*7c478bd9Sstevel@tonic-gate 			}
2192*7c478bd9Sstevel@tonic-gate 		}
2193*7c478bd9Sstevel@tonic-gate 		argc -= optind;
2194*7c478bd9Sstevel@tonic-gate 		argv += optind;
2195*7c478bd9Sstevel@tonic-gate 
2196*7c478bd9Sstevel@tonic-gate 		if (argc <= 0)
2197*7c478bd9Sstevel@tonic-gate 			usage();
2198*7c478bd9Sstevel@tonic-gate 
2199*7c478bd9Sstevel@tonic-gate 		/*
2200*7c478bd9Sstevel@tonic-gate 		 * We want to continue with -s processing if we had
2201*7c478bd9Sstevel@tonic-gate 		 * invalid options, but not if a disable failed.  We
2202*7c478bd9Sstevel@tonic-gate 		 * squelch output the second time we walk fmris; we saw
2203*7c478bd9Sstevel@tonic-gate 		 * the errors the first time.
2204*7c478bd9Sstevel@tonic-gate 		 */
2205*7c478bd9Sstevel@tonic-gate 		if ((err = scf_walk_fmri(h, argc, argv, 0, set_fmri_enabled,
2206*7c478bd9Sstevel@tonic-gate 		    (void *)flags, &exit_status, uu_warn)) != 0) {
2207*7c478bd9Sstevel@tonic-gate 
2208*7c478bd9Sstevel@tonic-gate 			uu_warn(gettext("failed to iterate over "
2209*7c478bd9Sstevel@tonic-gate 			    "instances: %s\n"), scf_strerror(err));
2210*7c478bd9Sstevel@tonic-gate 			exit_status = UU_EXIT_FATAL;
2211*7c478bd9Sstevel@tonic-gate 
2212*7c478bd9Sstevel@tonic-gate 		} else if (wait && exit_status == 0 &&
2213*7c478bd9Sstevel@tonic-gate 		    (err = scf_walk_fmri(h, argc, argv, 0, wait_fmri_disabled,
2214*7c478bd9Sstevel@tonic-gate 		    (void *)flags, &error, quiet)) != 0) {
2215*7c478bd9Sstevel@tonic-gate 
2216*7c478bd9Sstevel@tonic-gate 			uu_warn(gettext("failed to iterate over "
2217*7c478bd9Sstevel@tonic-gate 			    "instances: %s\n"), scf_strerror(err));
2218*7c478bd9Sstevel@tonic-gate 			exit_status = UU_EXIT_FATAL;
2219*7c478bd9Sstevel@tonic-gate 		}
2220*7c478bd9Sstevel@tonic-gate 
2221*7c478bd9Sstevel@tonic-gate 		if (error > 0)
2222*7c478bd9Sstevel@tonic-gate 			exit_status = error;
2223*7c478bd9Sstevel@tonic-gate 
2224*7c478bd9Sstevel@tonic-gate 	} else if (strcmp(argv[optind], "restart") == 0) {
2225*7c478bd9Sstevel@tonic-gate 		++optind;
2226*7c478bd9Sstevel@tonic-gate 
2227*7c478bd9Sstevel@tonic-gate 		if (optind >= argc)
2228*7c478bd9Sstevel@tonic-gate 			usage();
2229*7c478bd9Sstevel@tonic-gate 
2230*7c478bd9Sstevel@tonic-gate 		if ((err = scf_walk_fmri(h, argc - optind, argv + optind, 0,
2231*7c478bd9Sstevel@tonic-gate 		    set_fmri_action, (void *)SCF_PROPERTY_RESTART,
2232*7c478bd9Sstevel@tonic-gate 		    &exit_status, uu_warn)) != 0) {
2233*7c478bd9Sstevel@tonic-gate 			uu_warn(gettext("failed to iterate over "
2234*7c478bd9Sstevel@tonic-gate 			    "instances: %s\n"), scf_strerror(err));
2235*7c478bd9Sstevel@tonic-gate 			exit_status = UU_EXIT_FATAL;
2236*7c478bd9Sstevel@tonic-gate 		}
2237*7c478bd9Sstevel@tonic-gate 
2238*7c478bd9Sstevel@tonic-gate 	} else if (strcmp(argv[optind], "refresh") == 0) {
2239*7c478bd9Sstevel@tonic-gate 		++optind;
2240*7c478bd9Sstevel@tonic-gate 
2241*7c478bd9Sstevel@tonic-gate 		if (optind >= argc)
2242*7c478bd9Sstevel@tonic-gate 			usage();
2243*7c478bd9Sstevel@tonic-gate 
2244*7c478bd9Sstevel@tonic-gate 		if ((err = scf_walk_fmri(h, argc - optind, argv + optind, 0,
2245*7c478bd9Sstevel@tonic-gate 		    set_fmri_action, (void *)SCF_PROPERTY_REFRESH,
2246*7c478bd9Sstevel@tonic-gate 		    &exit_status, uu_warn)) != 0) {
2247*7c478bd9Sstevel@tonic-gate 			uu_warn(gettext("failed to iterate over "
2248*7c478bd9Sstevel@tonic-gate 			    "instances: %s\n"), scf_strerror(scf_error()));
2249*7c478bd9Sstevel@tonic-gate 			exit_status = UU_EXIT_FATAL;
2250*7c478bd9Sstevel@tonic-gate 		}
2251*7c478bd9Sstevel@tonic-gate 
2252*7c478bd9Sstevel@tonic-gate 	} else if (strcmp(argv[optind], "mark") == 0) {
2253*7c478bd9Sstevel@tonic-gate 		int flags = 0;
2254*7c478bd9Sstevel@tonic-gate 		scf_walk_callback callback;
2255*7c478bd9Sstevel@tonic-gate 
2256*7c478bd9Sstevel@tonic-gate 		++optind;
2257*7c478bd9Sstevel@tonic-gate 
2258*7c478bd9Sstevel@tonic-gate 		while ((o = getopt(argc, argv, "It")) != -1) {
2259*7c478bd9Sstevel@tonic-gate 			if (o == 'I')
2260*7c478bd9Sstevel@tonic-gate 				flags |= MARK_IMMEDIATE;
2261*7c478bd9Sstevel@tonic-gate 			else if (o == 't')
2262*7c478bd9Sstevel@tonic-gate 				flags |= MARK_TEMPORARY;
2263*7c478bd9Sstevel@tonic-gate 			else if (o == '?')
2264*7c478bd9Sstevel@tonic-gate 				usage();
2265*7c478bd9Sstevel@tonic-gate 			else {
2266*7c478bd9Sstevel@tonic-gate 				assert(0);
2267*7c478bd9Sstevel@tonic-gate 				abort();
2268*7c478bd9Sstevel@tonic-gate 			}
2269*7c478bd9Sstevel@tonic-gate 		}
2270*7c478bd9Sstevel@tonic-gate 
2271*7c478bd9Sstevel@tonic-gate 		if (argc - optind < 2)
2272*7c478bd9Sstevel@tonic-gate 			usage();
2273*7c478bd9Sstevel@tonic-gate 
2274*7c478bd9Sstevel@tonic-gate 		if (strcmp(argv[optind], "degraded") == 0) {
2275*7c478bd9Sstevel@tonic-gate 			if (flags & MARK_TEMPORARY)
2276*7c478bd9Sstevel@tonic-gate 				uu_xdie(UU_EXIT_USAGE, gettext("-t may not be "
2277*7c478bd9Sstevel@tonic-gate 				    "used with degraded.\n"));
2278*7c478bd9Sstevel@tonic-gate 			callback = force_degraded;
2279*7c478bd9Sstevel@tonic-gate 
2280*7c478bd9Sstevel@tonic-gate 		} else if (strcmp(argv[optind], "maintenance") == 0) {
2281*7c478bd9Sstevel@tonic-gate 			callback = force_maintenance;
2282*7c478bd9Sstevel@tonic-gate 		} else {
2283*7c478bd9Sstevel@tonic-gate 			usage();
2284*7c478bd9Sstevel@tonic-gate 		}
2285*7c478bd9Sstevel@tonic-gate 
2286*7c478bd9Sstevel@tonic-gate 		if ((err = scf_walk_fmri(h, argc - optind - 1,
2287*7c478bd9Sstevel@tonic-gate 		    argv + optind + 1, 0, callback, NULL, &exit_status,
2288*7c478bd9Sstevel@tonic-gate 		    uu_warn)) != 0) {
2289*7c478bd9Sstevel@tonic-gate 			uu_warn(gettext("failed to iterate over "
2290*7c478bd9Sstevel@tonic-gate 			    "instances: %s\n"),
2291*7c478bd9Sstevel@tonic-gate 			    scf_strerror(err));
2292*7c478bd9Sstevel@tonic-gate 			exit_status = UU_EXIT_FATAL;
2293*7c478bd9Sstevel@tonic-gate 		}
2294*7c478bd9Sstevel@tonic-gate 
2295*7c478bd9Sstevel@tonic-gate 	} else if (strcmp(argv[optind], "clear") == 0) {
2296*7c478bd9Sstevel@tonic-gate 		++optind;
2297*7c478bd9Sstevel@tonic-gate 
2298*7c478bd9Sstevel@tonic-gate 		if (optind >= argc)
2299*7c478bd9Sstevel@tonic-gate 			usage();
2300*7c478bd9Sstevel@tonic-gate 
2301*7c478bd9Sstevel@tonic-gate 		if ((err = scf_walk_fmri(h, argc - optind, argv + optind, 0,
2302*7c478bd9Sstevel@tonic-gate 		    clear_instance, NULL, &exit_status, uu_warn)) != 0) {
2303*7c478bd9Sstevel@tonic-gate 			uu_warn(gettext("failed to iterate over "
2304*7c478bd9Sstevel@tonic-gate 			    "instances: %s\n"), scf_strerror(err));
2305*7c478bd9Sstevel@tonic-gate 			exit_status = UU_EXIT_FATAL;
2306*7c478bd9Sstevel@tonic-gate 		}
2307*7c478bd9Sstevel@tonic-gate 
2308*7c478bd9Sstevel@tonic-gate 	} else if (strcmp(argv[optind], "milestone") == 0) {
2309*7c478bd9Sstevel@tonic-gate 		boolean_t temporary = B_TRUE;
2310*7c478bd9Sstevel@tonic-gate 		const char *milestone;
2311*7c478bd9Sstevel@tonic-gate 
2312*7c478bd9Sstevel@tonic-gate 		++optind;
2313*7c478bd9Sstevel@tonic-gate 
2314*7c478bd9Sstevel@tonic-gate 		while ((o = getopt(argc, argv, "d")) != -1) {
2315*7c478bd9Sstevel@tonic-gate 			if (o == 'd')
2316*7c478bd9Sstevel@tonic-gate 				temporary = B_FALSE;
2317*7c478bd9Sstevel@tonic-gate 			else if (o == '?')
2318*7c478bd9Sstevel@tonic-gate 				usage_milestone();
2319*7c478bd9Sstevel@tonic-gate 			else {
2320*7c478bd9Sstevel@tonic-gate 				assert(0);
2321*7c478bd9Sstevel@tonic-gate 				abort();
2322*7c478bd9Sstevel@tonic-gate 			}
2323*7c478bd9Sstevel@tonic-gate 		}
2324*7c478bd9Sstevel@tonic-gate 
2325*7c478bd9Sstevel@tonic-gate 		if (optind >= argc)
2326*7c478bd9Sstevel@tonic-gate 			usage_milestone();
2327*7c478bd9Sstevel@tonic-gate 
2328*7c478bd9Sstevel@tonic-gate 		milestone = validate_milestone(argv[optind]);
2329*7c478bd9Sstevel@tonic-gate 
2330*7c478bd9Sstevel@tonic-gate 		set_milestone(milestone, temporary);
2331*7c478bd9Sstevel@tonic-gate 	} else if (strcmp(argv[optind], "_smf_backup") == 0) {
2332*7c478bd9Sstevel@tonic-gate 		const char *reason = NULL;
2333*7c478bd9Sstevel@tonic-gate 
2334*7c478bd9Sstevel@tonic-gate 		++optind;
2335*7c478bd9Sstevel@tonic-gate 
2336*7c478bd9Sstevel@tonic-gate 		if (optind != argc - 1)
2337*7c478bd9Sstevel@tonic-gate 			usage();
2338*7c478bd9Sstevel@tonic-gate 
2339*7c478bd9Sstevel@tonic-gate 		if ((err = _scf_request_backup(h, argv[optind])) !=
2340*7c478bd9Sstevel@tonic-gate 		    SCF_SUCCESS) {
2341*7c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
2342*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_BOUND:
2343*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
2344*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_READONLY:
2345*7c478bd9Sstevel@tonic-gate 				scfdie();
2346*7c478bd9Sstevel@tonic-gate 				break;
2347*7c478bd9Sstevel@tonic-gate 
2348*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
2349*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_INVALID_ARGUMENT:
2350*7c478bd9Sstevel@tonic-gate 				reason = scf_strerror(scf_error());
2351*7c478bd9Sstevel@tonic-gate 				break;
2352*7c478bd9Sstevel@tonic-gate 
2353*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_INTERNAL:
2354*7c478bd9Sstevel@tonic-gate 				reason =
2355*7c478bd9Sstevel@tonic-gate 				    "unknown error (see console for details)";
2356*7c478bd9Sstevel@tonic-gate 				break;
2357*7c478bd9Sstevel@tonic-gate 			}
2358*7c478bd9Sstevel@tonic-gate 			uu_warn("failed to backup repository: %s\n", reason);
2359*7c478bd9Sstevel@tonic-gate 			exit_status = UU_EXIT_FATAL;
2360*7c478bd9Sstevel@tonic-gate 		}
2361*7c478bd9Sstevel@tonic-gate 	} else {
2362*7c478bd9Sstevel@tonic-gate 		usage();
2363*7c478bd9Sstevel@tonic-gate 	}
2364*7c478bd9Sstevel@tonic-gate 
2365*7c478bd9Sstevel@tonic-gate 	if (scf_handle_unbind(h) == -1)
2366*7c478bd9Sstevel@tonic-gate 		scfdie();
2367*7c478bd9Sstevel@tonic-gate 	scf_handle_destroy(h);
2368*7c478bd9Sstevel@tonic-gate 
2369*7c478bd9Sstevel@tonic-gate 	return (exit_status);
2370*7c478bd9Sstevel@tonic-gate }
2371