xref: /onnv-gate/usr/src/cmd/svc/svcadm/svcadm.c (revision 471:fb6202c3da23)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
23*471Shg115875  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate  * svcadm - request adminstrative actions for service instances
310Sstevel@tonic-gate  */
320Sstevel@tonic-gate 
330Sstevel@tonic-gate #include <locale.h>
340Sstevel@tonic-gate #include <libintl.h>
350Sstevel@tonic-gate #include <libscf.h>
360Sstevel@tonic-gate #include <libscf_priv.h>
370Sstevel@tonic-gate #include <libuutil.h>
380Sstevel@tonic-gate #include <stddef.h>
390Sstevel@tonic-gate #include <stdio.h>
400Sstevel@tonic-gate #include <stdlib.h>
410Sstevel@tonic-gate #include <string.h>
420Sstevel@tonic-gate #include <unistd.h>
430Sstevel@tonic-gate #include <assert.h>
440Sstevel@tonic-gate #include <errno.h>
450Sstevel@tonic-gate 
460Sstevel@tonic-gate #ifndef TEXT_DOMAIN
470Sstevel@tonic-gate #define	TEXT_DOMAIN	"SUNW_OST_OSCMD"
480Sstevel@tonic-gate #endif /* TEXT_DOMAIN */
490Sstevel@tonic-gate 
500Sstevel@tonic-gate /* Must be a power of two */
510Sstevel@tonic-gate #define	HT_BUCKETS	64
520Sstevel@tonic-gate 
530Sstevel@tonic-gate /*
540Sstevel@tonic-gate  * Exit codes for enable and disable -s.
550Sstevel@tonic-gate  */
560Sstevel@tonic-gate #define	EXIT_SVC_FAILURE	3
570Sstevel@tonic-gate #define	EXIT_DEP_FAILURE	4
580Sstevel@tonic-gate 
590Sstevel@tonic-gate /*
600Sstevel@tonic-gate  * How long we will wait (in seconds) for a service to change state
610Sstevel@tonic-gate  * before re-checking its dependencies.
620Sstevel@tonic-gate  */
630Sstevel@tonic-gate #define	WAIT_INTERVAL		3
640Sstevel@tonic-gate 
650Sstevel@tonic-gate #ifndef NDEBUG
660Sstevel@tonic-gate #define	bad_error(func, err)	{					\
670Sstevel@tonic-gate 	uu_warn("%s:%d: %s() failed with unexpected error %d.\n",	\
680Sstevel@tonic-gate 	    __FILE__, __LINE__, (func), (err));				\
690Sstevel@tonic-gate 	abort();							\
700Sstevel@tonic-gate }
710Sstevel@tonic-gate #else
720Sstevel@tonic-gate #define	bad_error(func, err)	abort()
730Sstevel@tonic-gate #endif
740Sstevel@tonic-gate 
750Sstevel@tonic-gate 
760Sstevel@tonic-gate struct ht_elt {
770Sstevel@tonic-gate 	struct ht_elt	*next;
780Sstevel@tonic-gate 	boolean_t	active;
790Sstevel@tonic-gate 	char		str[1];
800Sstevel@tonic-gate };
810Sstevel@tonic-gate 
820Sstevel@tonic-gate 
830Sstevel@tonic-gate scf_handle_t *h;
840Sstevel@tonic-gate ssize_t max_scf_fmri_sz;
850Sstevel@tonic-gate static const char *emsg_permission_denied;
860Sstevel@tonic-gate static const char *emsg_nomem;
870Sstevel@tonic-gate static const char *emsg_create_pg_perm_denied;
880Sstevel@tonic-gate static const char *emsg_pg_perm_denied;
890Sstevel@tonic-gate static const char *emsg_prop_perm_denied;
900Sstevel@tonic-gate static const char *emsg_no_service;
910Sstevel@tonic-gate 
920Sstevel@tonic-gate static int exit_status = 0;
930Sstevel@tonic-gate static int verbose = 0;
940Sstevel@tonic-gate static char *scratch_fmri;
950Sstevel@tonic-gate 
960Sstevel@tonic-gate static struct ht_elt **visited;
970Sstevel@tonic-gate 
98*471Shg115875 void do_scfdie(int lineno) __NORETURN;
99*471Shg115875 static void usage_milestone(void) __NORETURN;
100*471Shg115875 
1010Sstevel@tonic-gate /*
1020Sstevel@tonic-gate  * Visitors from synch.c, needed for enable -s and disable -s.
1030Sstevel@tonic-gate  */
1040Sstevel@tonic-gate extern int is_enabled(scf_instance_t *);
1050Sstevel@tonic-gate extern int has_potential(scf_instance_t *, int);
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate void
1080Sstevel@tonic-gate do_scfdie(int lineno)
1090Sstevel@tonic-gate {
1100Sstevel@tonic-gate 	scf_error_t err;
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate 	switch (err = scf_error()) {
1130Sstevel@tonic-gate 	case SCF_ERROR_CONNECTION_BROKEN:
1140Sstevel@tonic-gate 		uu_die(gettext("Connection to repository server broken.  "
1150Sstevel@tonic-gate 		    "Exiting.\n"));
1160Sstevel@tonic-gate 		/* NOTREACHED */
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate 	case SCF_ERROR_BACKEND_READONLY:
1190Sstevel@tonic-gate 		uu_die(gettext("Repository is read-only.  Exiting.\n"));
1200Sstevel@tonic-gate 		/* NOTREACHED */
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate 	default:
1230Sstevel@tonic-gate #ifdef NDEBUG
1240Sstevel@tonic-gate 		uu_die(gettext("Unexpected libscf error: %s.  Exiting.\n"),
1250Sstevel@tonic-gate 		    scf_strerror(err));
1260Sstevel@tonic-gate #else
1270Sstevel@tonic-gate 		uu_die("Unexpected libscf error on line %d: %s.\n", lineno,
1280Sstevel@tonic-gate 		    scf_strerror(err));
1290Sstevel@tonic-gate #endif
1300Sstevel@tonic-gate 	}
1310Sstevel@tonic-gate }
1320Sstevel@tonic-gate 
1330Sstevel@tonic-gate #define	scfdie()	do_scfdie(__LINE__)
1340Sstevel@tonic-gate 
1350Sstevel@tonic-gate static void
1360Sstevel@tonic-gate usage()
1370Sstevel@tonic-gate {
1380Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(
1390Sstevel@tonic-gate 	"Usage: %1$s [-v] [cmd [args ... ]]\n\n"
1400Sstevel@tonic-gate 	"\t%1$s enable [-rst] <service> ...\t- enable and online service(s)\n"
1410Sstevel@tonic-gate 	"\t%1$s disable [-st] <service> ...\t- disable and offline service(s)\n"
1420Sstevel@tonic-gate 	"\t%1$s restart <service> ...\t\t- restart specified service(s)\n"
1430Sstevel@tonic-gate 	"\t%1$s refresh <service> ...\t\t- re-read service configuration\n"
1440Sstevel@tonic-gate 	"\t%1$s mark [-It] <state> <service> ...\t- set maintenance state\n"
1450Sstevel@tonic-gate 	"\t%1$s clear <service> ...\t\t- clear maintenance state\n"
1460Sstevel@tonic-gate 	"\t%1$s milestone [-d] <milestone>\t- advance to a service milestone\n"
1470Sstevel@tonic-gate 	"\n\t"
1480Sstevel@tonic-gate 	"Services can be specified using an FMRI, abbreviation, or fnmatch(5)\n"
1490Sstevel@tonic-gate 	"\tpattern, as shown in these examples for svc:/network/smtp:sendmail\n"
1500Sstevel@tonic-gate 	"\n"
1510Sstevel@tonic-gate 	"\t%1$s <cmd> svc:/network/smtp:sendmail\n"
1520Sstevel@tonic-gate 	"\t%1$s <cmd> network/smtp:sendmail\n"
1530Sstevel@tonic-gate 	"\t%1$s <cmd> network/*mail\n"
1540Sstevel@tonic-gate 	"\t%1$s <cmd> network/smtp\n"
1550Sstevel@tonic-gate 	"\t%1$s <cmd> smtp:sendmail\n"
1560Sstevel@tonic-gate 	"\t%1$s <cmd> smtp\n"
1570Sstevel@tonic-gate 	"\t%1$s <cmd> sendmail\n"), uu_getpname());
1580Sstevel@tonic-gate 
1590Sstevel@tonic-gate 	exit(UU_EXIT_USAGE);
1600Sstevel@tonic-gate }
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate /*
1640Sstevel@tonic-gate  * FMRI hash table for recursive enable.
1650Sstevel@tonic-gate  */
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate static uint32_t
1680Sstevel@tonic-gate hash_fmri(const char *str)
1690Sstevel@tonic-gate {
1700Sstevel@tonic-gate 	uint32_t h = 0, g;
1710Sstevel@tonic-gate 	const char *p;
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate 	/* Generic hash function from uts/common/os/modhash.c . */
1740Sstevel@tonic-gate 	for (p = str; *p != '\0'; ++p) {
1750Sstevel@tonic-gate 		h = (h << 4) + *p;
1760Sstevel@tonic-gate 		if ((g = (h & 0xf0000000)) != 0) {
1770Sstevel@tonic-gate 			h ^= (g >> 24);
1780Sstevel@tonic-gate 			h ^= g;
1790Sstevel@tonic-gate 		}
1800Sstevel@tonic-gate 	}
1810Sstevel@tonic-gate 
1820Sstevel@tonic-gate 	return (h);
1830Sstevel@tonic-gate }
1840Sstevel@tonic-gate 
1850Sstevel@tonic-gate /*
1860Sstevel@tonic-gate  * Return 1 if str has been visited, 0 if it has not, and -1 if memory could not
1870Sstevel@tonic-gate  * be allocated.
1880Sstevel@tonic-gate  */
1890Sstevel@tonic-gate static int
1900Sstevel@tonic-gate visited_find_or_add(const char *str, struct ht_elt **hep)
1910Sstevel@tonic-gate {
1920Sstevel@tonic-gate 	uint32_t h;
1930Sstevel@tonic-gate 	uint_t i;
1940Sstevel@tonic-gate 	struct ht_elt *he;
1950Sstevel@tonic-gate 
1960Sstevel@tonic-gate 	h = hash_fmri(str);
1970Sstevel@tonic-gate 	i = h & (HT_BUCKETS - 1);
1980Sstevel@tonic-gate 
1990Sstevel@tonic-gate 	for (he = visited[i]; he != NULL; he = he->next) {
2000Sstevel@tonic-gate 		if (strcmp(he->str, str) == 0) {
2010Sstevel@tonic-gate 			if (hep)
2020Sstevel@tonic-gate 				*hep = he;
2030Sstevel@tonic-gate 			return (1);
2040Sstevel@tonic-gate 		}
2050Sstevel@tonic-gate 	}
2060Sstevel@tonic-gate 
2070Sstevel@tonic-gate 	he = malloc(offsetof(struct ht_elt, str) + strlen(str) + 1);
2080Sstevel@tonic-gate 	if (he == NULL)
2090Sstevel@tonic-gate 		return (-1);
2100Sstevel@tonic-gate 
2110Sstevel@tonic-gate 	(void) strcpy(he->str, str);
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate 	he->next = visited[i];
2140Sstevel@tonic-gate 	visited[i] = he;
2150Sstevel@tonic-gate 
2160Sstevel@tonic-gate 	if (hep)
2170Sstevel@tonic-gate 		*hep = he;
2180Sstevel@tonic-gate 	return (0);
2190Sstevel@tonic-gate }
2200Sstevel@tonic-gate 
2210Sstevel@tonic-gate 
2220Sstevel@tonic-gate /*
2230Sstevel@tonic-gate  * Returns 0, ECANCELED if pg is deleted, ENOENT if propname doesn't exist,
2240Sstevel@tonic-gate  * EINVAL if the property is not of boolean type or has no values, and E2BIG
2250Sstevel@tonic-gate  * if it has more than one value.  *bp is set if 0 or E2BIG is returned.
2260Sstevel@tonic-gate  */
2270Sstevel@tonic-gate int
2280Sstevel@tonic-gate get_bool_prop(scf_propertygroup_t *pg, const char *propname, uint8_t *bp)
2290Sstevel@tonic-gate {
2300Sstevel@tonic-gate 	scf_property_t *prop;
2310Sstevel@tonic-gate 	scf_value_t *val;
2320Sstevel@tonic-gate 	int ret;
2330Sstevel@tonic-gate 
2340Sstevel@tonic-gate 	if ((prop = scf_property_create(h)) == NULL ||
2350Sstevel@tonic-gate 	    (val = scf_value_create(h)) == NULL)
2360Sstevel@tonic-gate 		scfdie();
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate 	if (scf_pg_get_property(pg, propname, prop) != 0) {
2390Sstevel@tonic-gate 		switch (scf_error()) {
2400Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
2410Sstevel@tonic-gate 			ret = ECANCELED;
2420Sstevel@tonic-gate 			goto out;
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
2450Sstevel@tonic-gate 			ret = ENOENT;
2460Sstevel@tonic-gate 			goto out;
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
2490Sstevel@tonic-gate 			assert(0);
2500Sstevel@tonic-gate 			abort();
2510Sstevel@tonic-gate 			/* NOTREACHED */
2520Sstevel@tonic-gate 
2530Sstevel@tonic-gate 		default:
2540Sstevel@tonic-gate 			scfdie();
2550Sstevel@tonic-gate 		}
2560Sstevel@tonic-gate 	}
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate 	if (scf_property_get_value(prop, val) == 0) {
2590Sstevel@tonic-gate 		ret = 0;
2600Sstevel@tonic-gate 	} else {
2610Sstevel@tonic-gate 		switch (scf_error()) {
2620Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
2630Sstevel@tonic-gate 			ret = ENOENT;
2640Sstevel@tonic-gate 			goto out;
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
2670Sstevel@tonic-gate 			ret = EINVAL;
2680Sstevel@tonic-gate 			goto out;
2690Sstevel@tonic-gate 
2700Sstevel@tonic-gate 		case SCF_ERROR_CONSTRAINT_VIOLATED:
2710Sstevel@tonic-gate 			ret = E2BIG;
2720Sstevel@tonic-gate 			break;
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
2750Sstevel@tonic-gate 			assert(0);
2760Sstevel@tonic-gate 			abort();
2770Sstevel@tonic-gate 			/* NOTREACHED */
2780Sstevel@tonic-gate 
2790Sstevel@tonic-gate 		default:
2800Sstevel@tonic-gate 			scfdie();
2810Sstevel@tonic-gate 		}
2820Sstevel@tonic-gate 	}
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate 	if (scf_value_get_boolean(val, bp) != 0) {
2850Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_TYPE_MISMATCH)
2860Sstevel@tonic-gate 			scfdie();
2870Sstevel@tonic-gate 
2880Sstevel@tonic-gate 		ret = EINVAL;
2890Sstevel@tonic-gate 		goto out;
2900Sstevel@tonic-gate 	}
2910Sstevel@tonic-gate 
2920Sstevel@tonic-gate out:
2930Sstevel@tonic-gate 	scf_value_destroy(val);
2940Sstevel@tonic-gate 	scf_property_destroy(prop);
2950Sstevel@tonic-gate 	return (ret);
2960Sstevel@tonic-gate }
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate /*
2990Sstevel@tonic-gate  * Returns 0, EPERM, or EROFS.
3000Sstevel@tonic-gate  */
3010Sstevel@tonic-gate static int
3020Sstevel@tonic-gate set_bool_prop(scf_propertygroup_t *pg, const char *propname, boolean_t b)
3030Sstevel@tonic-gate {
3040Sstevel@tonic-gate 	scf_value_t *v;
3050Sstevel@tonic-gate 	scf_transaction_t *tx;
3060Sstevel@tonic-gate 	scf_transaction_entry_t *ent;
3070Sstevel@tonic-gate 	int ret = 0, r;
3080Sstevel@tonic-gate 
3090Sstevel@tonic-gate 	if ((tx = scf_transaction_create(h)) == NULL ||
3100Sstevel@tonic-gate 	    (ent = scf_entry_create(h)) == NULL ||
3110Sstevel@tonic-gate 	    (v = scf_value_create(h)) == NULL)
3120Sstevel@tonic-gate 		scfdie();
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate 	scf_value_set_boolean(v, b);
3150Sstevel@tonic-gate 
3160Sstevel@tonic-gate 	for (;;) {
3170Sstevel@tonic-gate 		if (scf_transaction_start(tx, pg) == -1) {
3180Sstevel@tonic-gate 			switch (scf_error()) {
3190Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
3200Sstevel@tonic-gate 				ret = EPERM;
3210Sstevel@tonic-gate 				goto out;
3220Sstevel@tonic-gate 
3230Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_READONLY:
3240Sstevel@tonic-gate 				ret = EROFS;
3250Sstevel@tonic-gate 				goto out;
3260Sstevel@tonic-gate 
3270Sstevel@tonic-gate 			default:
3280Sstevel@tonic-gate 				scfdie();
3290Sstevel@tonic-gate 			}
3300Sstevel@tonic-gate 		}
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate 		if (scf_transaction_property_change_type(tx, ent, propname,
3330Sstevel@tonic-gate 		    SCF_TYPE_BOOLEAN) != 0) {
3340Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_NOT_FOUND)
3350Sstevel@tonic-gate 				scfdie();
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate 			if (scf_transaction_property_new(tx, ent, propname,
3380Sstevel@tonic-gate 			    SCF_TYPE_BOOLEAN) != 0)
3390Sstevel@tonic-gate 				scfdie();
3400Sstevel@tonic-gate 		}
3410Sstevel@tonic-gate 
3420Sstevel@tonic-gate 		r = scf_entry_add_value(ent, v);
3430Sstevel@tonic-gate 		assert(r == 0);
3440Sstevel@tonic-gate 
3450Sstevel@tonic-gate 		r = scf_transaction_commit(tx);
3460Sstevel@tonic-gate 		if (r == 1)
3470Sstevel@tonic-gate 			break;
3480Sstevel@tonic-gate 
3490Sstevel@tonic-gate 		scf_transaction_reset(tx);
3500Sstevel@tonic-gate 
3510Sstevel@tonic-gate 		if (r != 0) {
3520Sstevel@tonic-gate 			switch (scf_error()) {
3530Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
3540Sstevel@tonic-gate 				ret = EPERM;
3550Sstevel@tonic-gate 				goto out;
3560Sstevel@tonic-gate 
3570Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_READONLY:
3580Sstevel@tonic-gate 				ret = EROFS;
3590Sstevel@tonic-gate 				goto out;
3600Sstevel@tonic-gate 
3610Sstevel@tonic-gate 			default:
3620Sstevel@tonic-gate 				scfdie();
3630Sstevel@tonic-gate 			}
3640Sstevel@tonic-gate 		}
3650Sstevel@tonic-gate 
3660Sstevel@tonic-gate 		if (scf_pg_update(pg) == -1)
3670Sstevel@tonic-gate 			scfdie();
3680Sstevel@tonic-gate 	}
3690Sstevel@tonic-gate 
3700Sstevel@tonic-gate out:
3710Sstevel@tonic-gate 	scf_transaction_destroy(tx);
3720Sstevel@tonic-gate 	scf_entry_destroy(ent);
3730Sstevel@tonic-gate 	scf_value_destroy(v);
3740Sstevel@tonic-gate 	return (ret);
3750Sstevel@tonic-gate }
3760Sstevel@tonic-gate 
3770Sstevel@tonic-gate /*
3780Sstevel@tonic-gate  * Gets the single astring value of the propname property of pg.  prop & v are
3790Sstevel@tonic-gate  * scratch space.  Returns the length of the string on success or
3800Sstevel@tonic-gate  *   -ENOENT - pg has no property named propname
3810Sstevel@tonic-gate  *   -E2BIG - property has no values or multiple values
3820Sstevel@tonic-gate  *   -EINVAL - property type is not compatible with astring
3830Sstevel@tonic-gate  */
3840Sstevel@tonic-gate ssize_t
3850Sstevel@tonic-gate get_astring_prop(const scf_propertygroup_t *pg, const char *propname,
3860Sstevel@tonic-gate     scf_property_t *prop, scf_value_t *v, char *buf, size_t bufsz)
3870Sstevel@tonic-gate {
3880Sstevel@tonic-gate 	ssize_t sz;
3890Sstevel@tonic-gate 
3900Sstevel@tonic-gate 	if (scf_pg_get_property(pg, propname, prop) != 0) {
3910Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND)
3920Sstevel@tonic-gate 			scfdie();
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate 		return (-ENOENT);
3950Sstevel@tonic-gate 	}
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate 	if (scf_property_get_value(prop, v) != 0) {
3980Sstevel@tonic-gate 		switch (scf_error()) {
3990Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
4000Sstevel@tonic-gate 		case SCF_ERROR_CONSTRAINT_VIOLATED:
4010Sstevel@tonic-gate 			return (-E2BIG);
4020Sstevel@tonic-gate 
4030Sstevel@tonic-gate 		default:
4040Sstevel@tonic-gate 			scfdie();
4050Sstevel@tonic-gate 		}
4060Sstevel@tonic-gate 	}
4070Sstevel@tonic-gate 
4080Sstevel@tonic-gate 	sz = scf_value_get_astring(v, buf, bufsz);
4090Sstevel@tonic-gate 	if (sz < 0) {
4100Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_TYPE_MISMATCH)
4110Sstevel@tonic-gate 			scfdie();
4120Sstevel@tonic-gate 
4130Sstevel@tonic-gate 		return (-EINVAL);
4140Sstevel@tonic-gate 	}
4150Sstevel@tonic-gate 
4160Sstevel@tonic-gate 	return (sz);
4170Sstevel@tonic-gate }
4180Sstevel@tonic-gate 
4190Sstevel@tonic-gate /*
4200Sstevel@tonic-gate  * Returns
4210Sstevel@tonic-gate  *   0 - success
4220Sstevel@tonic-gate  *   ECANCELED - pg was deleted
4230Sstevel@tonic-gate  *   EPERM - permission denied
4240Sstevel@tonic-gate  *   EACCES - access denied
4250Sstevel@tonic-gate  *   EROFS - readonly
4260Sstevel@tonic-gate  */
4270Sstevel@tonic-gate static int
4280Sstevel@tonic-gate delete_prop(scf_propertygroup_t *pg, const char *propname)
4290Sstevel@tonic-gate {
4300Sstevel@tonic-gate 	scf_transaction_t *tx;
4310Sstevel@tonic-gate 	scf_transaction_entry_t *ent;
4320Sstevel@tonic-gate 	int ret = 0, r;
4330Sstevel@tonic-gate 
4340Sstevel@tonic-gate 	if ((tx = scf_transaction_create(h)) == NULL ||
4350Sstevel@tonic-gate 	    (ent = scf_entry_create(h)) == NULL)
4360Sstevel@tonic-gate 		scfdie();
4370Sstevel@tonic-gate 
4380Sstevel@tonic-gate 	for (;;) {
4390Sstevel@tonic-gate 		if (scf_transaction_start(tx, pg) == -1) {
4400Sstevel@tonic-gate 			switch (scf_error()) {
4410Sstevel@tonic-gate 			case SCF_ERROR_DELETED:
4420Sstevel@tonic-gate 				ret = ECANCELED;
4430Sstevel@tonic-gate 				goto out;
4440Sstevel@tonic-gate 
4450Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
4460Sstevel@tonic-gate 				ret = EPERM;
4470Sstevel@tonic-gate 				goto out;
4480Sstevel@tonic-gate 
4490Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_ACCESS:
4500Sstevel@tonic-gate 				ret = EACCES;
4510Sstevel@tonic-gate 				goto out;
4520Sstevel@tonic-gate 
4530Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_READONLY:
4540Sstevel@tonic-gate 				ret = EROFS;
4550Sstevel@tonic-gate 				goto out;
4560Sstevel@tonic-gate 
4570Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
4580Sstevel@tonic-gate 			case SCF_ERROR_HANDLE_MISMATCH:
4590Sstevel@tonic-gate 			case SCF_ERROR_NOT_BOUND:
4600Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
4610Sstevel@tonic-gate 			case SCF_ERROR_IN_USE:
4620Sstevel@tonic-gate 			default:
4630Sstevel@tonic-gate 				scfdie();
4640Sstevel@tonic-gate 			}
4650Sstevel@tonic-gate 		}
4660Sstevel@tonic-gate 
4670Sstevel@tonic-gate 		if (scf_transaction_property_delete(tx, ent, propname) == -1)
4680Sstevel@tonic-gate 			switch (scf_error()) {
4690Sstevel@tonic-gate 			case SCF_ERROR_DELETED:
4700Sstevel@tonic-gate 				ret = ECANCELED;
4710Sstevel@tonic-gate 				goto out;
4720Sstevel@tonic-gate 
4730Sstevel@tonic-gate 			case SCF_ERROR_NOT_FOUND:
4740Sstevel@tonic-gate 				ret = 0;
4750Sstevel@tonic-gate 				goto out;
4760Sstevel@tonic-gate 
4770Sstevel@tonic-gate 			case SCF_ERROR_HANDLE_MISMATCH:
4780Sstevel@tonic-gate 			case SCF_ERROR_NOT_BOUND:
4790Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
4800Sstevel@tonic-gate 			case SCF_ERROR_INVALID_ARGUMENT:
4810Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
4820Sstevel@tonic-gate 			default:
4830Sstevel@tonic-gate 				scfdie();
4840Sstevel@tonic-gate 			}
4850Sstevel@tonic-gate 
4860Sstevel@tonic-gate 		r = scf_transaction_commit(tx);
4870Sstevel@tonic-gate 		if (r == 1)
4880Sstevel@tonic-gate 			break;
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate 		scf_transaction_reset(tx);
4910Sstevel@tonic-gate 
4920Sstevel@tonic-gate 		if (r != 0) {
4930Sstevel@tonic-gate 			switch (scf_error()) {
4940Sstevel@tonic-gate 			case SCF_ERROR_DELETED:
4950Sstevel@tonic-gate 				ret = ECANCELED;
4960Sstevel@tonic-gate 				goto out;
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
4990Sstevel@tonic-gate 				ret = EPERM;
5000Sstevel@tonic-gate 				goto out;
5010Sstevel@tonic-gate 
5020Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_ACCESS:
5030Sstevel@tonic-gate 				ret = EACCES;
5040Sstevel@tonic-gate 				goto out;
5050Sstevel@tonic-gate 
5060Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_READONLY:
5070Sstevel@tonic-gate 				ret = EROFS;
5080Sstevel@tonic-gate 				goto out;
5090Sstevel@tonic-gate 
5100Sstevel@tonic-gate 			case SCF_ERROR_INVALID_ARGUMENT:
5110Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
5120Sstevel@tonic-gate 			case SCF_ERROR_NOT_BOUND:
5130Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
5140Sstevel@tonic-gate 			default:
5150Sstevel@tonic-gate 				scfdie();
5160Sstevel@tonic-gate 			}
5170Sstevel@tonic-gate 		}
5180Sstevel@tonic-gate 
5190Sstevel@tonic-gate 		if (scf_pg_update(pg) == -1) {
5200Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_DELETED)
5210Sstevel@tonic-gate 				scfdie();
5220Sstevel@tonic-gate 
5230Sstevel@tonic-gate 			ret = ECANCELED;
5240Sstevel@tonic-gate 			goto out;
5250Sstevel@tonic-gate 		}
5260Sstevel@tonic-gate 	}
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate out:
5290Sstevel@tonic-gate 	scf_transaction_destroy(tx);
5300Sstevel@tonic-gate 	scf_entry_destroy(ent);
5310Sstevel@tonic-gate 	return (ret);
5320Sstevel@tonic-gate }
5330Sstevel@tonic-gate 
5340Sstevel@tonic-gate /*
5350Sstevel@tonic-gate  * Returns 0 or EPERM.
5360Sstevel@tonic-gate  */
5370Sstevel@tonic-gate static int
5380Sstevel@tonic-gate pg_get_or_add(scf_instance_t *inst, const char *pgname, const char *pgtype,
5390Sstevel@tonic-gate     uint32_t pgflags, scf_propertygroup_t *pg)
5400Sstevel@tonic-gate {
5410Sstevel@tonic-gate again:
5420Sstevel@tonic-gate 	if (scf_instance_get_pg(inst, pgname, pg) == 0)
5430Sstevel@tonic-gate 		return (0);
5440Sstevel@tonic-gate 
5450Sstevel@tonic-gate 	if (scf_error() != SCF_ERROR_NOT_FOUND)
5460Sstevel@tonic-gate 		scfdie();
5470Sstevel@tonic-gate 
5480Sstevel@tonic-gate 	if (scf_instance_add_pg(inst, pgname, pgtype, pgflags, pg) == 0)
5490Sstevel@tonic-gate 		return (0);
5500Sstevel@tonic-gate 
5510Sstevel@tonic-gate 	switch (scf_error()) {
5520Sstevel@tonic-gate 	case SCF_ERROR_EXISTS:
5530Sstevel@tonic-gate 		goto again;
5540Sstevel@tonic-gate 
5550Sstevel@tonic-gate 	case SCF_ERROR_PERMISSION_DENIED:
5560Sstevel@tonic-gate 		return (EPERM);
5570Sstevel@tonic-gate 
5580Sstevel@tonic-gate 	default:
5590Sstevel@tonic-gate 		scfdie();
5600Sstevel@tonic-gate 		/* NOTREACHED */
5610Sstevel@tonic-gate 	}
5620Sstevel@tonic-gate }
5630Sstevel@tonic-gate 
5640Sstevel@tonic-gate /*
5650Sstevel@tonic-gate  * Enable or disable inst, per enable.  If temp is true, set
5660Sstevel@tonic-gate  * general_ovr/enabled.  Otherwise set general/enabled and delete
5670Sstevel@tonic-gate  * general_ovr/enabled if it exists (order is important here: we don't want the
5680Sstevel@tonic-gate  * enabled status to glitch).
5690Sstevel@tonic-gate  */
5700Sstevel@tonic-gate static void
5710Sstevel@tonic-gate set_inst_enabled(const char *fmri, scf_instance_t *inst, boolean_t temp,
5720Sstevel@tonic-gate     boolean_t enable)
5730Sstevel@tonic-gate {
5740Sstevel@tonic-gate 	scf_propertygroup_t *pg;
5750Sstevel@tonic-gate 	uint8_t b;
5760Sstevel@tonic-gate 	const char *pgname = NULL;	/* For emsg_pg_perm_denied */
5770Sstevel@tonic-gate 	int r;
5780Sstevel@tonic-gate 
5790Sstevel@tonic-gate 	pg = scf_pg_create(h);
5800Sstevel@tonic-gate 	if (pg == NULL)
5810Sstevel@tonic-gate 		scfdie();
5820Sstevel@tonic-gate 
5830Sstevel@tonic-gate 	if (temp) {
5840Sstevel@tonic-gate 		/* Set general_ovr/enabled */
5850Sstevel@tonic-gate 		pgname = SCF_PG_GENERAL_OVR;
5860Sstevel@tonic-gate 		if (pg_get_or_add(inst, pgname, SCF_PG_GENERAL_OVR_TYPE,
5870Sstevel@tonic-gate 		    SCF_PG_GENERAL_OVR_FLAGS, pg) != 0)
5880Sstevel@tonic-gate 			goto eperm;
5890Sstevel@tonic-gate 
5900Sstevel@tonic-gate 		switch (set_bool_prop(pg, SCF_PROPERTY_ENABLED, enable) != 0) {
5910Sstevel@tonic-gate 		case 0:
5920Sstevel@tonic-gate 			break;
5930Sstevel@tonic-gate 
5940Sstevel@tonic-gate 		case EPERM:
5950Sstevel@tonic-gate 			goto eperm;
5960Sstevel@tonic-gate 
5970Sstevel@tonic-gate 		case EROFS:
5980Sstevel@tonic-gate 			/* Shouldn't happen, but it can. */
5990Sstevel@tonic-gate 			if (!verbose)
6000Sstevel@tonic-gate 				uu_warn(gettext("%s: Repository read-only.\n"),
6010Sstevel@tonic-gate 				    fmri);
6020Sstevel@tonic-gate 			else
6030Sstevel@tonic-gate 				uu_warn(gettext("%s: Could not set %s/%s "
6040Sstevel@tonic-gate 				    "(repository read-only).\n"), fmri,
6050Sstevel@tonic-gate 				    SCF_PG_GENERAL_OVR, SCF_PROPERTY_ENABLED);
6060Sstevel@tonic-gate 			goto out;
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate 		default:
6090Sstevel@tonic-gate 			assert(0);
6100Sstevel@tonic-gate 			abort();
6110Sstevel@tonic-gate 		}
6120Sstevel@tonic-gate 
6130Sstevel@tonic-gate 		if (verbose)
6140Sstevel@tonic-gate 			(void) printf(enable ?
6150Sstevel@tonic-gate 			    gettext("%s temporarily enabled.\n") :
6160Sstevel@tonic-gate 			    gettext("%s temporarily disabled.\n"), fmri);
6170Sstevel@tonic-gate 	} else {
6180Sstevel@tonic-gate again:
6190Sstevel@tonic-gate 		pgname = SCF_PG_GENERAL;
6200Sstevel@tonic-gate 		if (pg_get_or_add(inst, pgname, SCF_PG_GENERAL_TYPE,
6210Sstevel@tonic-gate 		    SCF_PG_GENERAL_FLAGS, pg) != 0)
6220Sstevel@tonic-gate 			goto eperm;
6230Sstevel@tonic-gate 
6240Sstevel@tonic-gate 		switch (set_bool_prop(pg, SCF_PROPERTY_ENABLED, enable)) {
6250Sstevel@tonic-gate 		case 0:
6260Sstevel@tonic-gate 			break;
6270Sstevel@tonic-gate 
6280Sstevel@tonic-gate 		case EPERM:
6290Sstevel@tonic-gate 			goto eperm;
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate 		case EROFS:
6320Sstevel@tonic-gate 			/*
6330Sstevel@tonic-gate 			 * If general/enabled is already set the way we want,
6340Sstevel@tonic-gate 			 * proceed.
6350Sstevel@tonic-gate 			 */
6360Sstevel@tonic-gate 			switch (get_bool_prop(pg, SCF_PROPERTY_ENABLED, &b)) {
6370Sstevel@tonic-gate 			case 0:
6380Sstevel@tonic-gate 				if ((b != 0) == (enable != B_FALSE))
6390Sstevel@tonic-gate 					break;
6400Sstevel@tonic-gate 				/* FALLTHROUGH */
6410Sstevel@tonic-gate 
6420Sstevel@tonic-gate 			case ENOENT:
6430Sstevel@tonic-gate 			case EINVAL:
6440Sstevel@tonic-gate 			case E2BIG:
6450Sstevel@tonic-gate 				if (!verbose)
6460Sstevel@tonic-gate 					uu_warn(gettext("%s: Repository "
6470Sstevel@tonic-gate 					    "read-only.\n"), fmri);
6480Sstevel@tonic-gate 				else
6490Sstevel@tonic-gate 					uu_warn(gettext("%s: Could not set "
6500Sstevel@tonic-gate 					    "%s/%s (repository read-only).\n"),
6510Sstevel@tonic-gate 					    fmri, SCF_PG_GENERAL,
6520Sstevel@tonic-gate 					    SCF_PROPERTY_ENABLED);
6530Sstevel@tonic-gate 				goto out;
6540Sstevel@tonic-gate 
6550Sstevel@tonic-gate 			case ECANCELED:
6560Sstevel@tonic-gate 				goto again;
6570Sstevel@tonic-gate 
6580Sstevel@tonic-gate 			default:
6590Sstevel@tonic-gate 				assert(0);
6600Sstevel@tonic-gate 				abort();
6610Sstevel@tonic-gate 			}
6620Sstevel@tonic-gate 			break;
6630Sstevel@tonic-gate 
6640Sstevel@tonic-gate 		default:
6650Sstevel@tonic-gate 			assert(0);
6660Sstevel@tonic-gate 			abort();
6670Sstevel@tonic-gate 		}
6680Sstevel@tonic-gate 
6690Sstevel@tonic-gate 		pgname = SCF_PG_GENERAL_OVR;
6700Sstevel@tonic-gate 		if (scf_instance_get_pg(inst, pgname, pg) == 0) {
6710Sstevel@tonic-gate 			r = delete_prop(pg, SCF_PROPERTY_ENABLED);
6720Sstevel@tonic-gate 			switch (r) {
6730Sstevel@tonic-gate 			case 0:
6740Sstevel@tonic-gate 				break;
6750Sstevel@tonic-gate 
6760Sstevel@tonic-gate 			case ECANCELED:
6770Sstevel@tonic-gate 				uu_warn(emsg_no_service, fmri);
6780Sstevel@tonic-gate 				goto out;
6790Sstevel@tonic-gate 
6800Sstevel@tonic-gate 			case EPERM:
6810Sstevel@tonic-gate 				goto eperm;
6820Sstevel@tonic-gate 
6830Sstevel@tonic-gate 			case EACCES:
6840Sstevel@tonic-gate 				uu_warn(gettext("Could not delete %s/%s "
6850Sstevel@tonic-gate 				    "property of %s: backend access denied.\n"),
6860Sstevel@tonic-gate 				    pgname, SCF_PROPERTY_ENABLED, fmri);
6870Sstevel@tonic-gate 				goto out;
6880Sstevel@tonic-gate 
6890Sstevel@tonic-gate 			case EROFS:
6900Sstevel@tonic-gate 				uu_warn(gettext("Could not delete %s/%s "
6910Sstevel@tonic-gate 				    "property of %s: backend is read-only.\n"),
6920Sstevel@tonic-gate 				    pgname, SCF_PROPERTY_ENABLED, fmri);
6930Sstevel@tonic-gate 				goto out;
6940Sstevel@tonic-gate 
6950Sstevel@tonic-gate 			default:
6960Sstevel@tonic-gate 				bad_error("delete_prop", r);
6970Sstevel@tonic-gate 			}
6980Sstevel@tonic-gate 		} else {
6990Sstevel@tonic-gate 			switch (scf_error()) {
7000Sstevel@tonic-gate 			case SCF_ERROR_DELETED:
7010Sstevel@tonic-gate 				/* Print something? */
7020Sstevel@tonic-gate 
7030Sstevel@tonic-gate 			case SCF_ERROR_NOT_FOUND:
7040Sstevel@tonic-gate 				break;
7050Sstevel@tonic-gate 
7060Sstevel@tonic-gate 			case SCF_ERROR_HANDLE_MISMATCH:
7070Sstevel@tonic-gate 			case SCF_ERROR_INVALID_ARGUMENT:
7080Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
7090Sstevel@tonic-gate 				assert(0);
7100Sstevel@tonic-gate 				abort();
7110Sstevel@tonic-gate 				/* NOTREACHED */
7120Sstevel@tonic-gate 
7130Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
7140Sstevel@tonic-gate 			default:
7150Sstevel@tonic-gate 				scfdie();
7160Sstevel@tonic-gate 			}
7170Sstevel@tonic-gate 		}
7180Sstevel@tonic-gate 
7190Sstevel@tonic-gate 		if (verbose)
7200Sstevel@tonic-gate 			(void) printf(enable ?  gettext("%s enabled.\n") :
7210Sstevel@tonic-gate 			    gettext("%s disabled.\n"), fmri);
7220Sstevel@tonic-gate 	}
7230Sstevel@tonic-gate 
7240Sstevel@tonic-gate 	scf_pg_destroy(pg);
7250Sstevel@tonic-gate 	return;
7260Sstevel@tonic-gate 
7270Sstevel@tonic-gate eperm:
7280Sstevel@tonic-gate 	assert(pgname != NULL);
7290Sstevel@tonic-gate 	if (!verbose)
7300Sstevel@tonic-gate 		uu_warn(emsg_permission_denied, fmri);
7310Sstevel@tonic-gate 	else
7320Sstevel@tonic-gate 		uu_warn(emsg_pg_perm_denied, fmri, pgname);
7330Sstevel@tonic-gate 
7340Sstevel@tonic-gate out:
7350Sstevel@tonic-gate 	scf_pg_destroy(pg);
7360Sstevel@tonic-gate 	exit_status = 1;
7370Sstevel@tonic-gate }
7380Sstevel@tonic-gate 
7390Sstevel@tonic-gate /*
7400Sstevel@tonic-gate  * Set inst to the instance which corresponds to fmri.  If fmri identifies
7410Sstevel@tonic-gate  * a service with a single instance, get that instance.
7420Sstevel@tonic-gate  *
7430Sstevel@tonic-gate  * Fails with
7440Sstevel@tonic-gate  *   ENOTSUP - fmri has an unsupported scheme
7450Sstevel@tonic-gate  *   EINVAL - fmri is invalid
7460Sstevel@tonic-gate  *   ENOTDIR - fmri does not identify a service or instance
7470Sstevel@tonic-gate  *   ENOENT - could not locate instance
7480Sstevel@tonic-gate  *   E2BIG - fmri is a service with multiple instances (warning not printed)
7490Sstevel@tonic-gate  */
7500Sstevel@tonic-gate static int
7510Sstevel@tonic-gate get_inst_mult(const char *fmri, scf_instance_t *inst)
7520Sstevel@tonic-gate {
7530Sstevel@tonic-gate 	char *cfmri;
7540Sstevel@tonic-gate 	const char *svc_name, *inst_name, *pg_name;
7550Sstevel@tonic-gate 	scf_service_t *svc;
7560Sstevel@tonic-gate 	scf_instance_t *inst2;
7570Sstevel@tonic-gate 	scf_iter_t *iter;
7580Sstevel@tonic-gate 	int ret;
7590Sstevel@tonic-gate 
7600Sstevel@tonic-gate 	if (strncmp(fmri, "lrc:", sizeof ("lrc:") - 1) == 0) {
7610Sstevel@tonic-gate 		uu_warn(gettext("FMRI \"%s\" is a legacy service.\n"), fmri);
7620Sstevel@tonic-gate 		exit_status = 1;
7630Sstevel@tonic-gate 		return (ENOTSUP);
7640Sstevel@tonic-gate 	}
7650Sstevel@tonic-gate 
7660Sstevel@tonic-gate 	cfmri = strdup(fmri);
7670Sstevel@tonic-gate 	if (cfmri == NULL)
7680Sstevel@tonic-gate 		uu_die(emsg_nomem);
7690Sstevel@tonic-gate 
7700Sstevel@tonic-gate 	if (scf_parse_svc_fmri(cfmri, NULL, &svc_name, &inst_name, &pg_name,
7710Sstevel@tonic-gate 	    NULL) != SCF_SUCCESS) {
7720Sstevel@tonic-gate 		free(cfmri);
7730Sstevel@tonic-gate 		uu_warn(gettext("FMRI \"%s\" is invalid.\n"), fmri);
7740Sstevel@tonic-gate 		exit_status = 1;
7750Sstevel@tonic-gate 		return (EINVAL);
7760Sstevel@tonic-gate 	}
7770Sstevel@tonic-gate 
7780Sstevel@tonic-gate 	free(cfmri);
7790Sstevel@tonic-gate 
7800Sstevel@tonic-gate 	if (svc_name == NULL || pg_name != NULL) {
7810Sstevel@tonic-gate 		uu_warn(gettext(
7820Sstevel@tonic-gate 		    "FMRI \"%s\" does not designate a service or instance.\n"),
7830Sstevel@tonic-gate 		    fmri);
7840Sstevel@tonic-gate 		exit_status = 1;
7850Sstevel@tonic-gate 		return (ENOTDIR);
7860Sstevel@tonic-gate 	}
7870Sstevel@tonic-gate 
7880Sstevel@tonic-gate 	if (inst_name != NULL) {
7890Sstevel@tonic-gate 		if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
7900Sstevel@tonic-gate 		    NULL, SCF_DECODE_FMRI_EXACT) == 0)
7910Sstevel@tonic-gate 			return (0);
7920Sstevel@tonic-gate 
7930Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND)
7940Sstevel@tonic-gate 			scfdie();
7950Sstevel@tonic-gate 
7960Sstevel@tonic-gate 		uu_warn(gettext("No such instance \"%s\".\n"), fmri);
7970Sstevel@tonic-gate 		exit_status = 1;
7980Sstevel@tonic-gate 
7990Sstevel@tonic-gate 		return (ENOENT);
8000Sstevel@tonic-gate 	}
8010Sstevel@tonic-gate 
8020Sstevel@tonic-gate 	if ((svc = scf_service_create(h)) == NULL ||
8030Sstevel@tonic-gate 	    (inst2 = scf_instance_create(h)) == NULL ||
8040Sstevel@tonic-gate 	    (iter = scf_iter_create(h)) == NULL)
8050Sstevel@tonic-gate 		scfdie();
8060Sstevel@tonic-gate 
8070Sstevel@tonic-gate 	if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL,
8080Sstevel@tonic-gate 	    SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
8090Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND)
8100Sstevel@tonic-gate 			scfdie();
8110Sstevel@tonic-gate 
8120Sstevel@tonic-gate 		uu_warn(emsg_no_service, fmri);
8130Sstevel@tonic-gate 		exit_status = 1;
8140Sstevel@tonic-gate 
8150Sstevel@tonic-gate 		ret = ENOENT;
8160Sstevel@tonic-gate 		goto out;
8170Sstevel@tonic-gate 	}
8180Sstevel@tonic-gate 
8190Sstevel@tonic-gate 	/* If the service has only one child, use it. */
8200Sstevel@tonic-gate 	if (scf_iter_service_instances(iter, svc) != SCF_SUCCESS)
8210Sstevel@tonic-gate 		scfdie();
8220Sstevel@tonic-gate 
8230Sstevel@tonic-gate 	ret = scf_iter_next_instance(iter, inst);
8240Sstevel@tonic-gate 	if (ret < 0)
8250Sstevel@tonic-gate 		scfdie();
8260Sstevel@tonic-gate 	if (ret != 1) {
8270Sstevel@tonic-gate 		uu_warn(gettext("Service \"%s\" has no instances.\n"),
8280Sstevel@tonic-gate 		    fmri);
8290Sstevel@tonic-gate 		exit_status = 1;
8300Sstevel@tonic-gate 		ret = ENOENT;
8310Sstevel@tonic-gate 		goto out;
8320Sstevel@tonic-gate 	}
8330Sstevel@tonic-gate 
8340Sstevel@tonic-gate 	ret = scf_iter_next_instance(iter, inst2);
8350Sstevel@tonic-gate 	if (ret < 0)
8360Sstevel@tonic-gate 		scfdie();
8370Sstevel@tonic-gate 
8380Sstevel@tonic-gate 	if (ret != 0) {
8390Sstevel@tonic-gate 		ret = E2BIG;
8400Sstevel@tonic-gate 		goto out;
8410Sstevel@tonic-gate 	}
8420Sstevel@tonic-gate 
8430Sstevel@tonic-gate 	ret = 0;
8440Sstevel@tonic-gate 
8450Sstevel@tonic-gate out:
8460Sstevel@tonic-gate 	scf_iter_destroy(iter);
8470Sstevel@tonic-gate 	scf_instance_destroy(inst2);
8480Sstevel@tonic-gate 	scf_service_destroy(svc);
8490Sstevel@tonic-gate 	return (ret);
8500Sstevel@tonic-gate }
8510Sstevel@tonic-gate 
8520Sstevel@tonic-gate /*
8530Sstevel@tonic-gate  * Same as get_inst_mult(), but on E2BIG prints a warning and returns ENOENT.
8540Sstevel@tonic-gate  */
8550Sstevel@tonic-gate static int
8560Sstevel@tonic-gate get_inst(const char *fmri, scf_instance_t *inst)
8570Sstevel@tonic-gate {
8580Sstevel@tonic-gate 	int r;
8590Sstevel@tonic-gate 
8600Sstevel@tonic-gate 	r = get_inst_mult(fmri, inst);
8610Sstevel@tonic-gate 	if (r != E2BIG)
8620Sstevel@tonic-gate 		return (r);
8630Sstevel@tonic-gate 
8640Sstevel@tonic-gate 	uu_warn(gettext("operation on service %s is ambiguous; "
8650Sstevel@tonic-gate 	    "instance specification needed.\n"), fmri);
8660Sstevel@tonic-gate 	return (ENOENT);
8670Sstevel@tonic-gate }
8680Sstevel@tonic-gate 
8690Sstevel@tonic-gate static char *
8700Sstevel@tonic-gate inst_get_fmri(const scf_instance_t *inst)
8710Sstevel@tonic-gate {
8720Sstevel@tonic-gate 	ssize_t sz;
8730Sstevel@tonic-gate 
8740Sstevel@tonic-gate 	sz = scf_instance_to_fmri(inst, scratch_fmri, max_scf_fmri_sz);
8750Sstevel@tonic-gate 	if (sz < 0)
8760Sstevel@tonic-gate 		scfdie();
8770Sstevel@tonic-gate 	if (sz >= max_scf_fmri_sz)
8780Sstevel@tonic-gate 		uu_die(gettext("scf_instance_to_fmri() returned unexpectedly "
8790Sstevel@tonic-gate 		    "long value.\n"));
8800Sstevel@tonic-gate 
8810Sstevel@tonic-gate 	return (scratch_fmri);
8820Sstevel@tonic-gate }
8830Sstevel@tonic-gate 
8840Sstevel@tonic-gate static ssize_t
8850Sstevel@tonic-gate dep_get_astring(const char *fmri, const char *pgname,
8860Sstevel@tonic-gate     const scf_propertygroup_t *pg, const char *propname, scf_property_t *prop,
8870Sstevel@tonic-gate     scf_value_t *v, char *buf, size_t bufsz)
8880Sstevel@tonic-gate {
8890Sstevel@tonic-gate 	ssize_t sz;
8900Sstevel@tonic-gate 
8910Sstevel@tonic-gate 	sz = get_astring_prop(pg, propname, prop, v, buf, bufsz);
8920Sstevel@tonic-gate 	if (sz >= 0)
8930Sstevel@tonic-gate 		return (sz);
8940Sstevel@tonic-gate 
8950Sstevel@tonic-gate 	switch (-sz) {
8960Sstevel@tonic-gate 	case ENOENT:
8970Sstevel@tonic-gate 		uu_warn(gettext("\"%s\" is misconfigured (\"%s\" dependency "
8980Sstevel@tonic-gate 		    "lacks \"%s\" property.)\n"), fmri, pgname, propname);
8990Sstevel@tonic-gate 		return (-1);
9000Sstevel@tonic-gate 
9010Sstevel@tonic-gate 	case E2BIG:
9020Sstevel@tonic-gate 		uu_warn(gettext("\"%s\" is misconfigured (\"%s/%s\" property "
9030Sstevel@tonic-gate 		    "is not single-valued.)\n"), fmri, pgname, propname);
9040Sstevel@tonic-gate 		return (-1);
9050Sstevel@tonic-gate 
9060Sstevel@tonic-gate 	case EINVAL:
9070Sstevel@tonic-gate 		uu_warn(gettext("\"%s\" is misconfigured (\"%s/%s\" property "
9080Sstevel@tonic-gate 		    "is not of astring type.)\n"), fmri, pgname, propname);
9090Sstevel@tonic-gate 		return (-1);
9100Sstevel@tonic-gate 
9110Sstevel@tonic-gate 	default:
9120Sstevel@tonic-gate 		assert(0);
9130Sstevel@tonic-gate 		abort();
9140Sstevel@tonic-gate 		/* NOTREACHED */
9150Sstevel@tonic-gate 	}
9160Sstevel@tonic-gate }
9170Sstevel@tonic-gate 
9180Sstevel@tonic-gate static boolean_t
9190Sstevel@tonic-gate multiple_instances(scf_iter_t *iter, scf_value_t *v, char *buf)
9200Sstevel@tonic-gate {
9210Sstevel@tonic-gate 	int count = 0, r;
9220Sstevel@tonic-gate 	boolean_t ret;
9230Sstevel@tonic-gate 	scf_instance_t *inst;
9240Sstevel@tonic-gate 
9250Sstevel@tonic-gate 	inst = scf_instance_create(h);
9260Sstevel@tonic-gate 	if (inst == NULL)
9270Sstevel@tonic-gate 		scfdie();
9280Sstevel@tonic-gate 
9290Sstevel@tonic-gate 	for (;;) {
9300Sstevel@tonic-gate 		r = scf_iter_next_value(iter, v);
9310Sstevel@tonic-gate 		if (r == 0) {
9320Sstevel@tonic-gate 			ret = B_FALSE;
9330Sstevel@tonic-gate 			goto out;
9340Sstevel@tonic-gate 		}
9350Sstevel@tonic-gate 		if (r != 1)
9360Sstevel@tonic-gate 			scfdie();
9370Sstevel@tonic-gate 
9380Sstevel@tonic-gate 		if (scf_value_get_astring(v, buf, max_scf_fmri_sz) < 0)
9390Sstevel@tonic-gate 			scfdie();
9400Sstevel@tonic-gate 
9410Sstevel@tonic-gate 		switch (get_inst_mult(buf, inst)) {
9420Sstevel@tonic-gate 		case 0:
9430Sstevel@tonic-gate 			++count;
9440Sstevel@tonic-gate 			if (count > 1) {
9450Sstevel@tonic-gate 				ret = B_TRUE;
9460Sstevel@tonic-gate 				goto out;
9470Sstevel@tonic-gate 			}
9480Sstevel@tonic-gate 			break;
9490Sstevel@tonic-gate 
9500Sstevel@tonic-gate 		case ENOTSUP:
9510Sstevel@tonic-gate 		case EINVAL:
9520Sstevel@tonic-gate 		case ENOTDIR:
9530Sstevel@tonic-gate 		case ENOENT:
9540Sstevel@tonic-gate 			continue;
9550Sstevel@tonic-gate 
9560Sstevel@tonic-gate 		case E2BIG:
9570Sstevel@tonic-gate 			ret = B_TRUE;
9580Sstevel@tonic-gate 			goto out;
9590Sstevel@tonic-gate 
9600Sstevel@tonic-gate 		default:
9610Sstevel@tonic-gate 			assert(0);
9620Sstevel@tonic-gate 			abort();
9630Sstevel@tonic-gate 		}
9640Sstevel@tonic-gate 	}
9650Sstevel@tonic-gate 
9660Sstevel@tonic-gate out:
9670Sstevel@tonic-gate 	scf_instance_destroy(inst);
9680Sstevel@tonic-gate 	return (ret);
9690Sstevel@tonic-gate }
9700Sstevel@tonic-gate 
9710Sstevel@tonic-gate /*
9720Sstevel@tonic-gate  * Enable the service or instance identified by fmri and its dependencies,
9730Sstevel@tonic-gate  * recursively.  Specifically, call get_inst(fmri), enable the result, and
9740Sstevel@tonic-gate  * recurse on its restarter and the dependencies.  To avoid duplication of
9750Sstevel@tonic-gate  * effort or looping around a dependency cycle, each FMRI is entered into the
9760Sstevel@tonic-gate  * "visited" hash table.  While recursing, the hash table entry is marked
9770Sstevel@tonic-gate  * "active", so that if we come upon it again, we know we've hit a cycle.
9780Sstevel@tonic-gate  * exclude_all and optional_all dependencies are ignored.  require_any
9790Sstevel@tonic-gate  * dependencies are followed only if they comprise a single service; otherwise
9800Sstevel@tonic-gate  * the user is warned.
9810Sstevel@tonic-gate  *
9820Sstevel@tonic-gate  * fmri must point to a writable max_scf_fmri_sz buffer.  Returns EINVAL if fmri
9830Sstevel@tonic-gate  * is invalid, E2BIG if fmri identifies a service with multiple instances, ELOOP
9840Sstevel@tonic-gate  * on cycle detection, or 0 on success.
9850Sstevel@tonic-gate  */
9860Sstevel@tonic-gate static int
9870Sstevel@tonic-gate enable_fmri_rec(char *fmri, boolean_t temp)
9880Sstevel@tonic-gate {
9890Sstevel@tonic-gate 	scf_instance_t *inst;
9900Sstevel@tonic-gate 	scf_snapshot_t *snap;
9910Sstevel@tonic-gate 	scf_propertygroup_t *pg;
9920Sstevel@tonic-gate 	scf_property_t *prop;
9930Sstevel@tonic-gate 	scf_value_t *v;
9940Sstevel@tonic-gate 	scf_iter_t *pg_iter, *val_iter;
9950Sstevel@tonic-gate 	scf_type_t ty;
9960Sstevel@tonic-gate 	char *buf, *pgname;
9970Sstevel@tonic-gate 	ssize_t name_sz, len, sz;
9980Sstevel@tonic-gate 	int ret;
9990Sstevel@tonic-gate 	struct ht_elt *he;
10000Sstevel@tonic-gate 
10010Sstevel@tonic-gate 	len = scf_canonify_fmri(fmri, fmri, max_scf_fmri_sz);
10020Sstevel@tonic-gate 	if (len < 0) {
10030Sstevel@tonic-gate 		assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT);
10040Sstevel@tonic-gate 		return (EINVAL);
10050Sstevel@tonic-gate 	}
10060Sstevel@tonic-gate 	assert(len < max_scf_fmri_sz);
10070Sstevel@tonic-gate 
10080Sstevel@tonic-gate 	switch (visited_find_or_add(fmri, &he)) {
10090Sstevel@tonic-gate 	case 0:
10100Sstevel@tonic-gate 		he->active = B_TRUE;
10110Sstevel@tonic-gate 		break;
10120Sstevel@tonic-gate 
10130Sstevel@tonic-gate 	case 1:
10140Sstevel@tonic-gate 		return (he->active ? ELOOP : 0);
10150Sstevel@tonic-gate 
10160Sstevel@tonic-gate 	case -1:
10170Sstevel@tonic-gate 		uu_die(emsg_nomem);
10180Sstevel@tonic-gate 
10190Sstevel@tonic-gate 	default:
10200Sstevel@tonic-gate 		assert(0);
10210Sstevel@tonic-gate 		abort();
10220Sstevel@tonic-gate 	}
10230Sstevel@tonic-gate 
10240Sstevel@tonic-gate 	inst = scf_instance_create(h);
10250Sstevel@tonic-gate 	if (inst == NULL)
10260Sstevel@tonic-gate 		scfdie();
10270Sstevel@tonic-gate 
10280Sstevel@tonic-gate 	switch (get_inst_mult(fmri, inst)) {
10290Sstevel@tonic-gate 	case 0:
10300Sstevel@tonic-gate 		break;
10310Sstevel@tonic-gate 
10320Sstevel@tonic-gate 	case E2BIG:
10330Sstevel@tonic-gate 		he->active = B_FALSE;
10340Sstevel@tonic-gate 		return (E2BIG);
10350Sstevel@tonic-gate 
10360Sstevel@tonic-gate 	default:
10370Sstevel@tonic-gate 		he->active = B_FALSE;
10380Sstevel@tonic-gate 		return (0);
10390Sstevel@tonic-gate 	}
10400Sstevel@tonic-gate 
10410Sstevel@tonic-gate 	set_inst_enabled(fmri, inst, temp, B_TRUE);
10420Sstevel@tonic-gate 
10430Sstevel@tonic-gate 	if ((snap = scf_snapshot_create(h)) == NULL ||
10440Sstevel@tonic-gate 	    (pg = scf_pg_create(h)) == NULL ||
10450Sstevel@tonic-gate 	    (prop = scf_property_create(h)) == NULL ||
10460Sstevel@tonic-gate 	    (v = scf_value_create(h)) == NULL ||
10470Sstevel@tonic-gate 	    (pg_iter = scf_iter_create(h)) == NULL ||
10480Sstevel@tonic-gate 	    (val_iter = scf_iter_create(h)) == NULL)
10490Sstevel@tonic-gate 		scfdie();
10500Sstevel@tonic-gate 
10510Sstevel@tonic-gate 	buf = malloc(max_scf_fmri_sz);
10520Sstevel@tonic-gate 	if (buf == NULL)
10530Sstevel@tonic-gate 		uu_die(emsg_nomem);
10540Sstevel@tonic-gate 
10550Sstevel@tonic-gate 	name_sz = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH);
10560Sstevel@tonic-gate 	if (name_sz < 0)
10570Sstevel@tonic-gate 		scfdie();
10580Sstevel@tonic-gate 	++name_sz;
10590Sstevel@tonic-gate 	pgname = malloc(name_sz);
10600Sstevel@tonic-gate 	if (pgname == NULL)
10610Sstevel@tonic-gate 		uu_die(emsg_nomem);
10620Sstevel@tonic-gate 
10630Sstevel@tonic-gate 	if (scf_instance_get_snapshot(inst, "running", snap) != 0) {
10640Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND)
10650Sstevel@tonic-gate 			scfdie();
10660Sstevel@tonic-gate 
10670Sstevel@tonic-gate 		scf_snapshot_destroy(snap);
10680Sstevel@tonic-gate 		snap = NULL;
10690Sstevel@tonic-gate 	}
10700Sstevel@tonic-gate 
10710Sstevel@tonic-gate 	/* Enable restarter */
10720Sstevel@tonic-gate 	if (scf_instance_get_pg_composed(inst, snap, SCF_PG_GENERAL, pg) != 0) {
10730Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND)
10740Sstevel@tonic-gate 			scfdie();
10750Sstevel@tonic-gate 
10760Sstevel@tonic-gate 		uu_warn(gettext("\"%s\" is misconfigured (lacks \"%s\" "
10770Sstevel@tonic-gate 		    "property group).\n"), fmri, SCF_PG_GENERAL);
10780Sstevel@tonic-gate 		ret = 0;
10790Sstevel@tonic-gate 		goto out;
10800Sstevel@tonic-gate 	}
10810Sstevel@tonic-gate 
10820Sstevel@tonic-gate 	sz = get_astring_prop(pg, SCF_PROPERTY_RESTARTER, prop, v, buf,
10830Sstevel@tonic-gate 	    max_scf_fmri_sz);
10840Sstevel@tonic-gate 	if (sz > max_scf_fmri_sz) {
10850Sstevel@tonic-gate 		uu_warn(gettext("\"%s\" is misconfigured (the value of "
10860Sstevel@tonic-gate 		    "\"%s/%s\" is too long).\n"), fmri, SCF_PG_GENERAL,
10870Sstevel@tonic-gate 		    SCF_PROPERTY_RESTARTER);
10880Sstevel@tonic-gate 		ret = 0;
10890Sstevel@tonic-gate 		goto out;
10900Sstevel@tonic-gate 	} else if (sz >= 0) {
10910Sstevel@tonic-gate 		switch (enable_fmri_rec(buf, temp)) {
10920Sstevel@tonic-gate 		case 0:
10930Sstevel@tonic-gate 			break;
10940Sstevel@tonic-gate 
10950Sstevel@tonic-gate 		case EINVAL:
10960Sstevel@tonic-gate 			uu_warn(gettext("Restarter FMRI for \"%s\" is "
10970Sstevel@tonic-gate 			    "invalid.\n"), fmri);
10980Sstevel@tonic-gate 			break;
10990Sstevel@tonic-gate 
11000Sstevel@tonic-gate 		case E2BIG:
11010Sstevel@tonic-gate 			uu_warn(gettext("Restarter FMRI for \"%s\" identifies "
11020Sstevel@tonic-gate 			    "a service with multiple instances.\n"), fmri);
11030Sstevel@tonic-gate 			break;
11040Sstevel@tonic-gate 
11050Sstevel@tonic-gate 		case ELOOP:
11060Sstevel@tonic-gate 			ret = ELOOP;
11070Sstevel@tonic-gate 			goto out;
11080Sstevel@tonic-gate 
11090Sstevel@tonic-gate 		default:
11100Sstevel@tonic-gate 			assert(0);
11110Sstevel@tonic-gate 			abort();
11120Sstevel@tonic-gate 		}
11130Sstevel@tonic-gate 	} else if (sz < 0) {
11140Sstevel@tonic-gate 		switch (-sz) {
11150Sstevel@tonic-gate 		case ENOENT:
11160Sstevel@tonic-gate 			break;
11170Sstevel@tonic-gate 
11180Sstevel@tonic-gate 		case E2BIG:
11190Sstevel@tonic-gate 			uu_warn(gettext("\"%s\" is misconfigured (\"%s/%s\" "
11200Sstevel@tonic-gate 			    "property is not single-valued).\n"), fmri,
11210Sstevel@tonic-gate 			    SCF_PG_GENERAL, SCF_PROPERTY_RESTARTER);
11220Sstevel@tonic-gate 			ret = 0;
11230Sstevel@tonic-gate 			goto out;
11240Sstevel@tonic-gate 
11250Sstevel@tonic-gate 		case EINVAL:
11260Sstevel@tonic-gate 			uu_warn(gettext("\"%s\" is misconfigured (\"%s/%s\" "
11270Sstevel@tonic-gate 			    "property is not of astring type).\n"), fmri,
11280Sstevel@tonic-gate 			    SCF_PG_GENERAL, SCF_PROPERTY_RESTARTER);
11290Sstevel@tonic-gate 			ret = 0;
11300Sstevel@tonic-gate 			goto out;
11310Sstevel@tonic-gate 
11320Sstevel@tonic-gate 		default:
11330Sstevel@tonic-gate 			assert(0);
11340Sstevel@tonic-gate 			abort();
11350Sstevel@tonic-gate 		}
11360Sstevel@tonic-gate 	}
11370Sstevel@tonic-gate 
11380Sstevel@tonic-gate 	if (scf_iter_instance_pgs_typed_composed(pg_iter, inst, snap,
11390Sstevel@tonic-gate 	    SCF_GROUP_DEPENDENCY) == -1)
11400Sstevel@tonic-gate 		scfdie();
11410Sstevel@tonic-gate 
11420Sstevel@tonic-gate 	while (scf_iter_next_pg(pg_iter, pg) > 0) {
11430Sstevel@tonic-gate 		len = scf_pg_get_name(pg, pgname, name_sz);
11440Sstevel@tonic-gate 		if (len < 0)
11450Sstevel@tonic-gate 			scfdie();
11460Sstevel@tonic-gate 		assert(len < name_sz);
11470Sstevel@tonic-gate 
11480Sstevel@tonic-gate 		if (dep_get_astring(fmri, pgname, pg, SCF_PROPERTY_TYPE, prop,
11490Sstevel@tonic-gate 		    v, buf, max_scf_fmri_sz) < 0)
11500Sstevel@tonic-gate 			continue;
11510Sstevel@tonic-gate 
11520Sstevel@tonic-gate 		if (strcmp(buf, "service") != 0)
11530Sstevel@tonic-gate 			continue;
11540Sstevel@tonic-gate 
11550Sstevel@tonic-gate 		if (dep_get_astring(fmri, pgname, pg, SCF_PROPERTY_GROUPING,
11560Sstevel@tonic-gate 		    prop, v, buf, max_scf_fmri_sz) < 0)
11570Sstevel@tonic-gate 			continue;
11580Sstevel@tonic-gate 
11590Sstevel@tonic-gate 		if (strcmp(buf, SCF_DEP_EXCLUDE_ALL) == 0 ||
11600Sstevel@tonic-gate 		    strcmp(buf, SCF_DEP_OPTIONAL_ALL) == 0)
11610Sstevel@tonic-gate 			continue;
11620Sstevel@tonic-gate 
11630Sstevel@tonic-gate 		if (strcmp(buf, SCF_DEP_REQUIRE_ALL) != 0 &&
11640Sstevel@tonic-gate 		    strcmp(buf, SCF_DEP_REQUIRE_ANY) != 0) {
11650Sstevel@tonic-gate 			uu_warn(gettext("Dependency \"%s\" of \"%s\" has "
11660Sstevel@tonic-gate 			    "unknown type \"%s\".\n"), pgname, fmri, buf);
11670Sstevel@tonic-gate 			continue;
11680Sstevel@tonic-gate 		}
11690Sstevel@tonic-gate 
11700Sstevel@tonic-gate 		if (scf_pg_get_property(pg, SCF_PROPERTY_ENTITIES, prop) ==
11710Sstevel@tonic-gate 		    -1) {
11720Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_NOT_FOUND)
11730Sstevel@tonic-gate 				scfdie();
11740Sstevel@tonic-gate 
11750Sstevel@tonic-gate 			uu_warn(gettext("\"%s\" is misconfigured (\"%s\" "
11760Sstevel@tonic-gate 			    "dependency lacks \"%s\" property.)\n"), fmri,
11770Sstevel@tonic-gate 			    pgname, SCF_PROPERTY_ENTITIES);
11780Sstevel@tonic-gate 			continue;
11790Sstevel@tonic-gate 		}
11800Sstevel@tonic-gate 
11810Sstevel@tonic-gate 		if (scf_property_type(prop, &ty) != SCF_SUCCESS)
11820Sstevel@tonic-gate 			scfdie();
11830Sstevel@tonic-gate 
11840Sstevel@tonic-gate 		if (ty != SCF_TYPE_FMRI) {
11850Sstevel@tonic-gate 			uu_warn(gettext("\"%s\" is misconfigured (property "
11860Sstevel@tonic-gate 			    "\"%s/%s\" is not of fmri type).\n"), fmri, pgname,
11870Sstevel@tonic-gate 			    SCF_PROPERTY_ENTITIES);
11880Sstevel@tonic-gate 			continue;
11890Sstevel@tonic-gate 		}
11900Sstevel@tonic-gate 
11910Sstevel@tonic-gate 		if (scf_iter_property_values(val_iter, prop) == -1)
11920Sstevel@tonic-gate 			scfdie();
11930Sstevel@tonic-gate 
11940Sstevel@tonic-gate 		if (strcmp(buf, SCF_DEP_REQUIRE_ANY) == 0) {
11950Sstevel@tonic-gate 			if (multiple_instances(val_iter, v, buf)) {
11960Sstevel@tonic-gate 				(void) printf(gettext("%s requires one of:\n"),
11970Sstevel@tonic-gate 				    fmri);
11980Sstevel@tonic-gate 
11990Sstevel@tonic-gate 				if (scf_iter_property_values(val_iter, prop) !=
12000Sstevel@tonic-gate 				    0)
12010Sstevel@tonic-gate 					scfdie();
12020Sstevel@tonic-gate 
12030Sstevel@tonic-gate 				for (;;) {
12040Sstevel@tonic-gate 					int r;
12050Sstevel@tonic-gate 
12060Sstevel@tonic-gate 					r = scf_iter_next_value(val_iter, v);
12070Sstevel@tonic-gate 					if (r == 0)
12080Sstevel@tonic-gate 						break;
12090Sstevel@tonic-gate 					if (r != 1)
12100Sstevel@tonic-gate 						scfdie();
12110Sstevel@tonic-gate 
12120Sstevel@tonic-gate 					if (scf_value_get_astring(v, buf,
12130Sstevel@tonic-gate 					    max_scf_fmri_sz) < 0)
12140Sstevel@tonic-gate 						scfdie();
12150Sstevel@tonic-gate 
12160Sstevel@tonic-gate 					(void) fputs("  ", stdout);
12170Sstevel@tonic-gate 					(void) puts(buf);
12180Sstevel@tonic-gate 				}
12190Sstevel@tonic-gate 
12200Sstevel@tonic-gate 				continue;
12210Sstevel@tonic-gate 			}
12220Sstevel@tonic-gate 
12230Sstevel@tonic-gate 			/*
12240Sstevel@tonic-gate 			 * Since there's only one instance, we can enable it.
12250Sstevel@tonic-gate 			 * Reset val_iter and continue.
12260Sstevel@tonic-gate 			 */
12270Sstevel@tonic-gate 			if (scf_iter_property_values(val_iter, prop) != 0)
12280Sstevel@tonic-gate 				scfdie();
12290Sstevel@tonic-gate 		}
12300Sstevel@tonic-gate 
12310Sstevel@tonic-gate 		for (;;) {
12320Sstevel@tonic-gate 			ret = scf_iter_next_value(val_iter, v);
12330Sstevel@tonic-gate 			if (ret == 0)
12340Sstevel@tonic-gate 				break;
12350Sstevel@tonic-gate 			if (ret != 1)
12360Sstevel@tonic-gate 				scfdie();
12370Sstevel@tonic-gate 
12380Sstevel@tonic-gate 			if (scf_value_get_astring(v, buf, max_scf_fmri_sz) ==
12390Sstevel@tonic-gate 			    -1)
12400Sstevel@tonic-gate 				scfdie();
12410Sstevel@tonic-gate 
12420Sstevel@tonic-gate 			switch (enable_fmri_rec(buf, temp)) {
12430Sstevel@tonic-gate 			case 0:
12440Sstevel@tonic-gate 				break;
12450Sstevel@tonic-gate 
12460Sstevel@tonic-gate 			case EINVAL:
12470Sstevel@tonic-gate 				uu_warn(gettext("\"%s\" dependency of \"%s\" "
12480Sstevel@tonic-gate 				    "has invalid FMRI \"%s\".\n"), pgname,
12490Sstevel@tonic-gate 				    fmri, buf);
12500Sstevel@tonic-gate 				break;
12510Sstevel@tonic-gate 
12520Sstevel@tonic-gate 			case E2BIG:
12530Sstevel@tonic-gate 				uu_warn(gettext("%s depends on %s, which has "
12540Sstevel@tonic-gate 				    "multiple instances.\n"), fmri, buf);
12550Sstevel@tonic-gate 				break;
12560Sstevel@tonic-gate 
12570Sstevel@tonic-gate 			case ELOOP:
12580Sstevel@tonic-gate 				ret = ELOOP;
12590Sstevel@tonic-gate 				goto out;
12600Sstevel@tonic-gate 
12610Sstevel@tonic-gate 			default:
12620Sstevel@tonic-gate 				assert(0);
12630Sstevel@tonic-gate 				abort();
12640Sstevel@tonic-gate 			}
12650Sstevel@tonic-gate 		}
12660Sstevel@tonic-gate 	}
12670Sstevel@tonic-gate 
12680Sstevel@tonic-gate 	ret = 0;
12690Sstevel@tonic-gate 
12700Sstevel@tonic-gate out:
12710Sstevel@tonic-gate 	he->active = B_FALSE;
12720Sstevel@tonic-gate 
12730Sstevel@tonic-gate 	free(buf);
12740Sstevel@tonic-gate 	free(pgname);
12750Sstevel@tonic-gate 
12760Sstevel@tonic-gate 	(void) scf_value_destroy(v);
12770Sstevel@tonic-gate 	scf_property_destroy(prop);
12780Sstevel@tonic-gate 	scf_pg_destroy(pg);
12790Sstevel@tonic-gate 	scf_snapshot_destroy(snap);
12800Sstevel@tonic-gate 	scf_iter_destroy(pg_iter);
12810Sstevel@tonic-gate 	scf_iter_destroy(val_iter);
12820Sstevel@tonic-gate 
12830Sstevel@tonic-gate 	return (ret);
12840Sstevel@tonic-gate }
12850Sstevel@tonic-gate 
12860Sstevel@tonic-gate /*
12870Sstevel@tonic-gate  * fmri here is only used for verbose messages.
12880Sstevel@tonic-gate  */
12890Sstevel@tonic-gate static void
12900Sstevel@tonic-gate set_inst_action(const char *fmri, const scf_instance_t *inst,
12910Sstevel@tonic-gate     const char *action)
12920Sstevel@tonic-gate {
12930Sstevel@tonic-gate 	scf_transaction_t *tx;
12940Sstevel@tonic-gate 	scf_transaction_entry_t *ent;
12950Sstevel@tonic-gate 	scf_propertygroup_t *pg;
12960Sstevel@tonic-gate 	scf_property_t *prop;
12970Sstevel@tonic-gate 	scf_value_t *v;
12980Sstevel@tonic-gate 	int ret;
12990Sstevel@tonic-gate 	int64_t t;
13000Sstevel@tonic-gate 	hrtime_t timestamp;
13010Sstevel@tonic-gate 
13020Sstevel@tonic-gate 	const char * const scf_pg_restarter_actions = SCF_PG_RESTARTER_ACTIONS;
13030Sstevel@tonic-gate 
13040Sstevel@tonic-gate 	if ((pg = scf_pg_create(h)) == NULL ||
13050Sstevel@tonic-gate 	    (prop = scf_property_create(h)) == NULL ||
13060Sstevel@tonic-gate 	    (v = scf_value_create(h)) == NULL ||
13070Sstevel@tonic-gate 	    (tx = scf_transaction_create(h)) == NULL ||
13080Sstevel@tonic-gate 	    (ent = scf_entry_create(h)) == NULL)
13090Sstevel@tonic-gate 		scfdie();
13100Sstevel@tonic-gate 
13110Sstevel@tonic-gate 	if (scf_instance_get_pg(inst, scf_pg_restarter_actions, pg) == -1) {
13120Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND)
13130Sstevel@tonic-gate 			scfdie();
13140Sstevel@tonic-gate 
13150Sstevel@tonic-gate 		/* Try creating the restarter_actions property group. */
13160Sstevel@tonic-gate 		if (scf_instance_add_pg(inst, scf_pg_restarter_actions,
13170Sstevel@tonic-gate 		    SCF_PG_RESTARTER_ACTIONS_TYPE,
13180Sstevel@tonic-gate 		    SCF_PG_RESTARTER_ACTIONS_FLAGS, pg) == -1) {
13190Sstevel@tonic-gate 			switch (scf_error()) {
13200Sstevel@tonic-gate 			case SCF_ERROR_EXISTS:
13210Sstevel@tonic-gate 				/* Someone must have added it. */
13220Sstevel@tonic-gate 				break;
13230Sstevel@tonic-gate 
13240Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
13250Sstevel@tonic-gate 				if (!verbose)
13260Sstevel@tonic-gate 					uu_warn(emsg_permission_denied, fmri);
13270Sstevel@tonic-gate 				else
13280Sstevel@tonic-gate 					uu_warn(emsg_create_pg_perm_denied,
13290Sstevel@tonic-gate 					    fmri, scf_pg_restarter_actions);
13300Sstevel@tonic-gate 				goto out;
13310Sstevel@tonic-gate 
13320Sstevel@tonic-gate 			default:
13330Sstevel@tonic-gate 				scfdie();
13340Sstevel@tonic-gate 			}
13350Sstevel@tonic-gate 		}
13360Sstevel@tonic-gate 	}
13370Sstevel@tonic-gate 
13380Sstevel@tonic-gate 	/*
13390Sstevel@tonic-gate 	 * If we lose the transaction race and need to retry, there are 2
13400Sstevel@tonic-gate 	 * potential other winners:
13410Sstevel@tonic-gate 	 *	- another process setting actions
13420Sstevel@tonic-gate 	 *	- the restarter marking the action complete
13430Sstevel@tonic-gate 	 * Therefore, re-read the property every time through the loop before
13440Sstevel@tonic-gate 	 * making any decisions based on their values.
13450Sstevel@tonic-gate 	 */
13460Sstevel@tonic-gate 	do {
13470Sstevel@tonic-gate 		timestamp = gethrtime();
13480Sstevel@tonic-gate 
13490Sstevel@tonic-gate 		if (scf_transaction_start(tx, pg) == -1) {
13500Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13510Sstevel@tonic-gate 				scfdie();
13520Sstevel@tonic-gate 
13530Sstevel@tonic-gate 			if (!verbose)
13540Sstevel@tonic-gate 				uu_warn(emsg_permission_denied, fmri);
13550Sstevel@tonic-gate 			else
13560Sstevel@tonic-gate 				uu_warn(emsg_pg_perm_denied, fmri,
13570Sstevel@tonic-gate 				    scf_pg_restarter_actions);
13580Sstevel@tonic-gate 			goto out;
13590Sstevel@tonic-gate 		}
13600Sstevel@tonic-gate 
13610Sstevel@tonic-gate 		if (scf_pg_get_property(pg, action, prop) == -1) {
13620Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_NOT_FOUND)
13630Sstevel@tonic-gate 				scfdie();
13640Sstevel@tonic-gate 			if (scf_transaction_property_new(tx, ent,
13650Sstevel@tonic-gate 			    action, SCF_TYPE_INTEGER) == -1)
13660Sstevel@tonic-gate 				scfdie();
13670Sstevel@tonic-gate 			goto action_set;
13680Sstevel@tonic-gate 		} else {
13690Sstevel@tonic-gate 			if (scf_transaction_property_change_type(tx, ent,
13700Sstevel@tonic-gate 			    action, SCF_TYPE_INTEGER) == -1)
13710Sstevel@tonic-gate 				scfdie();
13720Sstevel@tonic-gate 		}
13730Sstevel@tonic-gate 
13740Sstevel@tonic-gate 		if (scf_property_get_value(prop, v) == -1) {
13750Sstevel@tonic-gate 			switch (scf_error()) {
13760Sstevel@tonic-gate 			case SCF_ERROR_CONSTRAINT_VIOLATED:
13770Sstevel@tonic-gate 			case SCF_ERROR_NOT_FOUND:
13780Sstevel@tonic-gate 				/* Misconfigured, so set anyway. */
13790Sstevel@tonic-gate 				goto action_set;
13800Sstevel@tonic-gate 
13810Sstevel@tonic-gate 			default:
13820Sstevel@tonic-gate 				scfdie();
13830Sstevel@tonic-gate 			}
13840Sstevel@tonic-gate 		} else {
13850Sstevel@tonic-gate 			if (scf_value_get_integer(v, &t) == -1) {
13860Sstevel@tonic-gate 				assert(scf_error() == SCF_ERROR_TYPE_MISMATCH);
13870Sstevel@tonic-gate 				goto action_set;
13880Sstevel@tonic-gate 			}
13890Sstevel@tonic-gate 			if (t > timestamp)
13900Sstevel@tonic-gate 				break;
13910Sstevel@tonic-gate 		}
13920Sstevel@tonic-gate 
13930Sstevel@tonic-gate action_set:
13940Sstevel@tonic-gate 		scf_value_set_integer(v, timestamp);
13950Sstevel@tonic-gate 		if (scf_entry_add_value(ent, v) == -1)
13960Sstevel@tonic-gate 			scfdie();
13970Sstevel@tonic-gate 
13980Sstevel@tonic-gate 		ret = scf_transaction_commit(tx);
13990Sstevel@tonic-gate 		if (ret == -1) {
14000Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14010Sstevel@tonic-gate 				scfdie();
14020Sstevel@tonic-gate 
14030Sstevel@tonic-gate 			if (!verbose)
14040Sstevel@tonic-gate 				uu_warn(emsg_permission_denied, fmri);
14050Sstevel@tonic-gate 			else
14060Sstevel@tonic-gate 				uu_warn(emsg_prop_perm_denied, fmri,
14070Sstevel@tonic-gate 				    scf_pg_restarter_actions, action);
14080Sstevel@tonic-gate 			scf_transaction_reset(tx);
14090Sstevel@tonic-gate 			goto out;
14100Sstevel@tonic-gate 		}
14110Sstevel@tonic-gate 
14120Sstevel@tonic-gate 		scf_transaction_reset(tx);
14130Sstevel@tonic-gate 
14140Sstevel@tonic-gate 		if (ret == 0) {
14150Sstevel@tonic-gate 			if (scf_pg_update(pg) == -1)
14160Sstevel@tonic-gate 				scfdie();
14170Sstevel@tonic-gate 		}
14180Sstevel@tonic-gate 	} while (ret == 0);
14190Sstevel@tonic-gate 
14200Sstevel@tonic-gate 	if (verbose)
14210Sstevel@tonic-gate 		(void) printf(gettext("Action %s set for %s.\n"), action, fmri);
14220Sstevel@tonic-gate 
14230Sstevel@tonic-gate out:
14240Sstevel@tonic-gate 	scf_value_destroy(v);
14250Sstevel@tonic-gate 	scf_entry_destroy(ent);
14260Sstevel@tonic-gate 	scf_transaction_destroy(tx);
14270Sstevel@tonic-gate 	scf_property_destroy(prop);
14280Sstevel@tonic-gate 	scf_pg_destroy(pg);
14290Sstevel@tonic-gate }
14300Sstevel@tonic-gate 
14310Sstevel@tonic-gate /*
14320Sstevel@tonic-gate  * Get the state of inst.  state should point to a buffer of
14330Sstevel@tonic-gate  * MAX_SCF_STATE_STRING_SZ bytes.  Returns 0 on success or -1 if
14340Sstevel@tonic-gate  *   no restarter property group
14350Sstevel@tonic-gate  *   no state property
14360Sstevel@tonic-gate  *   state property is misconfigured (wrong type, not single-valued)
14370Sstevel@tonic-gate  *   state value is too long
14380Sstevel@tonic-gate  * In these cases, fmri is used to print a warning.
14390Sstevel@tonic-gate  *
14400Sstevel@tonic-gate  * If pgp is non-NULL, a successful call to inst_get_state will store
14410Sstevel@tonic-gate  * the SCF_PG_RESTARTER property group in *pgp, and the caller will be
14420Sstevel@tonic-gate  * responsible for calling scf_pg_destroy on the property group.
14430Sstevel@tonic-gate  */
14440Sstevel@tonic-gate int
14450Sstevel@tonic-gate inst_get_state(scf_instance_t *inst, char *state, const char *fmri,
14460Sstevel@tonic-gate     scf_propertygroup_t **pgp)
14470Sstevel@tonic-gate {
14480Sstevel@tonic-gate 	scf_propertygroup_t *pg;
14490Sstevel@tonic-gate 	scf_property_t *prop;
14500Sstevel@tonic-gate 	scf_value_t *val;
14510Sstevel@tonic-gate 	int ret = -1;
14520Sstevel@tonic-gate 	ssize_t szret;
14530Sstevel@tonic-gate 
14540Sstevel@tonic-gate 	if ((pg = scf_pg_create(h)) == NULL ||
14550Sstevel@tonic-gate 	    (prop = scf_property_create(h)) == NULL ||
14560Sstevel@tonic-gate 	    (val = scf_value_create(h)) == NULL)
14570Sstevel@tonic-gate 		scfdie();
14580Sstevel@tonic-gate 
14590Sstevel@tonic-gate 	if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) {
14600Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND)
14610Sstevel@tonic-gate 			scfdie();
14620Sstevel@tonic-gate 
14630Sstevel@tonic-gate 		uu_warn(gettext("%s is misconfigured (lacks \"%s\" property "
14640Sstevel@tonic-gate 		    "group).\n"), fmri ? fmri : inst_get_fmri(inst),
14650Sstevel@tonic-gate 		    SCF_PG_RESTARTER);
14660Sstevel@tonic-gate 		goto out;
14670Sstevel@tonic-gate 	}
14680Sstevel@tonic-gate 
14690Sstevel@tonic-gate 	szret = get_astring_prop(pg, SCF_PROPERTY_STATE, prop, val, state,
14700Sstevel@tonic-gate 	    MAX_SCF_STATE_STRING_SZ);
14710Sstevel@tonic-gate 	if (szret < 0) {
14720Sstevel@tonic-gate 		switch (-szret) {
14730Sstevel@tonic-gate 		case ENOENT:
14740Sstevel@tonic-gate 			uu_warn(gettext("%s is misconfigured (\"%s\" property "
14750Sstevel@tonic-gate 			    "group lacks \"%s\" property).\n"),
14760Sstevel@tonic-gate 			    fmri ? fmri : inst_get_fmri(inst), SCF_PG_RESTARTER,
14770Sstevel@tonic-gate 			    SCF_PROPERTY_STATE);
14780Sstevel@tonic-gate 			goto out;
14790Sstevel@tonic-gate 
14800Sstevel@tonic-gate 		case E2BIG:
14810Sstevel@tonic-gate 			uu_warn(gettext("%s is misconfigured (\"%s/%s\" "
14820Sstevel@tonic-gate 			    "property is not single-valued).\n"),
14830Sstevel@tonic-gate 			    fmri ? fmri : inst_get_fmri(inst), SCF_PG_RESTARTER,
14840Sstevel@tonic-gate 			    SCF_PROPERTY_STATE);
14850Sstevel@tonic-gate 			goto out;
14860Sstevel@tonic-gate 
14870Sstevel@tonic-gate 		case EINVAL:
14880Sstevel@tonic-gate 			uu_warn(gettext("%s is misconfigured (\"%s/%s\" "
14890Sstevel@tonic-gate 			    "property is not of type astring).\n"),
14900Sstevel@tonic-gate 			    fmri ? fmri : inst_get_fmri(inst), SCF_PG_RESTARTER,
14910Sstevel@tonic-gate 			    SCF_PROPERTY_STATE);
14920Sstevel@tonic-gate 			goto out;
14930Sstevel@tonic-gate 
14940Sstevel@tonic-gate 		default:
14950Sstevel@tonic-gate 			assert(0);
14960Sstevel@tonic-gate 			abort();
14970Sstevel@tonic-gate 		}
14980Sstevel@tonic-gate 	}
14990Sstevel@tonic-gate 	if (szret >= MAX_SCF_STATE_STRING_SZ) {
15000Sstevel@tonic-gate 		uu_warn(gettext("%s is misconfigured (\"%s/%s\" property value "
15010Sstevel@tonic-gate 		    "is too long).\n"), fmri ? fmri : inst_get_fmri(inst),
15020Sstevel@tonic-gate 		    SCF_PG_RESTARTER, SCF_PROPERTY_STATE);
15030Sstevel@tonic-gate 		goto out;
15040Sstevel@tonic-gate 	}
15050Sstevel@tonic-gate 
15060Sstevel@tonic-gate 	ret = 0;
15070Sstevel@tonic-gate 	if (pgp)
15080Sstevel@tonic-gate 		*pgp = pg;
15090Sstevel@tonic-gate 
15100Sstevel@tonic-gate out:
15110Sstevel@tonic-gate 	(void) scf_value_destroy(val);
15120Sstevel@tonic-gate 	scf_property_destroy(prop);
15130Sstevel@tonic-gate 	if (ret || pgp == NULL)
15140Sstevel@tonic-gate 		scf_pg_destroy(pg);
15150Sstevel@tonic-gate 	return (ret);
15160Sstevel@tonic-gate }
15170Sstevel@tonic-gate 
15180Sstevel@tonic-gate static void
15190Sstevel@tonic-gate set_astring_prop(const char *fmri, const char *pgname, const char *pgtype,
15200Sstevel@tonic-gate     uint32_t pgflags, const char *propname, const char *str)
15210Sstevel@tonic-gate {
15220Sstevel@tonic-gate 	scf_instance_t *inst;
15230Sstevel@tonic-gate 	scf_propertygroup_t *pg;
15240Sstevel@tonic-gate 	scf_property_t *prop;
15250Sstevel@tonic-gate 	scf_value_t *val;
15260Sstevel@tonic-gate 	scf_transaction_t *tx;
15270Sstevel@tonic-gate 	scf_transaction_entry_t *txent;
15280Sstevel@tonic-gate 	int ret;
15290Sstevel@tonic-gate 
15300Sstevel@tonic-gate 	inst = scf_instance_create(h);
15310Sstevel@tonic-gate 	if (inst == NULL)
15320Sstevel@tonic-gate 		scfdie();
15330Sstevel@tonic-gate 
15340Sstevel@tonic-gate 	if (get_inst(fmri, inst) != 0)
15350Sstevel@tonic-gate 		return;
15360Sstevel@tonic-gate 
15370Sstevel@tonic-gate 	if ((pg = scf_pg_create(h)) == NULL ||
15380Sstevel@tonic-gate 	    (prop = scf_property_create(h)) == NULL ||
15390Sstevel@tonic-gate 	    (val = scf_value_create(h)) == NULL ||
15400Sstevel@tonic-gate 	    (tx = scf_transaction_create(h)) == NULL ||
15410Sstevel@tonic-gate 	    (txent = scf_entry_create(h)) == NULL)
15420Sstevel@tonic-gate 		scfdie();
15430Sstevel@tonic-gate 
15440Sstevel@tonic-gate 	if (scf_instance_get_pg(inst, pgname, pg) != SCF_SUCCESS) {
15450Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND)
15460Sstevel@tonic-gate 			scfdie();
15470Sstevel@tonic-gate 
15480Sstevel@tonic-gate 		if (scf_instance_add_pg(inst, pgname, pgtype, pgflags, pg) !=
15490Sstevel@tonic-gate 		    SCF_SUCCESS) {
15500Sstevel@tonic-gate 			switch (scf_error()) {
15510Sstevel@tonic-gate 			case SCF_ERROR_EXISTS:
15520Sstevel@tonic-gate 				if (scf_instance_get_pg(inst, pgname, pg) !=
15530Sstevel@tonic-gate 				    SCF_SUCCESS) {
15540Sstevel@tonic-gate 					if (scf_error() != SCF_ERROR_NOT_FOUND)
15550Sstevel@tonic-gate 						scfdie();
15560Sstevel@tonic-gate 
15570Sstevel@tonic-gate 					uu_warn(gettext("Repository write "
15580Sstevel@tonic-gate 					    "contention.\n"));
15590Sstevel@tonic-gate 					goto out;
15600Sstevel@tonic-gate 				}
15610Sstevel@tonic-gate 				break;
15620Sstevel@tonic-gate 
15630Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
15640Sstevel@tonic-gate 				if (!verbose)
15650Sstevel@tonic-gate 					uu_warn(emsg_permission_denied, fmri);
15660Sstevel@tonic-gate 				else
15670Sstevel@tonic-gate 					uu_warn(emsg_create_pg_perm_denied,
15680Sstevel@tonic-gate 					    fmri, pgname);
15690Sstevel@tonic-gate 				goto out;
15700Sstevel@tonic-gate 
15710Sstevel@tonic-gate 			default:
15720Sstevel@tonic-gate 				scfdie();
15730Sstevel@tonic-gate 			}
15740Sstevel@tonic-gate 		}
15750Sstevel@tonic-gate 	}
15760Sstevel@tonic-gate 
15770Sstevel@tonic-gate 	do {
15780Sstevel@tonic-gate 		if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
15790Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15800Sstevel@tonic-gate 				scfdie();
15810Sstevel@tonic-gate 
15820Sstevel@tonic-gate 			if (!verbose)
15830Sstevel@tonic-gate 				uu_warn(emsg_permission_denied, fmri);
15840Sstevel@tonic-gate 			else
15850Sstevel@tonic-gate 				uu_warn(emsg_pg_perm_denied, fmri, pgname);
15860Sstevel@tonic-gate 			goto out;
15870Sstevel@tonic-gate 		}
15880Sstevel@tonic-gate 
15890Sstevel@tonic-gate 		if (scf_transaction_property_change_type(tx, txent, propname,
15900Sstevel@tonic-gate 		    SCF_TYPE_ASTRING) != 0) {
15910Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_NOT_FOUND)
15920Sstevel@tonic-gate 				scfdie();
15930Sstevel@tonic-gate 
15940Sstevel@tonic-gate 			if (scf_transaction_property_new(tx, txent, propname,
15950Sstevel@tonic-gate 			    SCF_TYPE_ASTRING) != 0)
15960Sstevel@tonic-gate 				scfdie();
15970Sstevel@tonic-gate 		}
15980Sstevel@tonic-gate 
15990Sstevel@tonic-gate 		if (scf_value_set_astring(val, str) != SCF_SUCCESS)
16000Sstevel@tonic-gate 			scfdie();
16010Sstevel@tonic-gate 
16020Sstevel@tonic-gate 		if (scf_entry_add_value(txent, val) != SCF_SUCCESS)
16030Sstevel@tonic-gate 			scfdie();
16040Sstevel@tonic-gate 
16050Sstevel@tonic-gate 		ret = scf_transaction_commit(tx);
16060Sstevel@tonic-gate 		if (ret == -1) {
16070Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
16080Sstevel@tonic-gate 				scfdie();
16090Sstevel@tonic-gate 
16100Sstevel@tonic-gate 			if (!verbose)
16110Sstevel@tonic-gate 				uu_warn(emsg_permission_denied, fmri);
16120Sstevel@tonic-gate 			else
16130Sstevel@tonic-gate 				uu_warn(emsg_prop_perm_denied, fmri, pgname,
16140Sstevel@tonic-gate 				    propname);
16150Sstevel@tonic-gate 			goto out;
16160Sstevel@tonic-gate 		}
16170Sstevel@tonic-gate 
16180Sstevel@tonic-gate 		if (ret == 0) {
16190Sstevel@tonic-gate 			scf_transaction_reset(tx);
16200Sstevel@tonic-gate 
16210Sstevel@tonic-gate 			if (scf_pg_update(pg) != SCF_SUCCESS)
16220Sstevel@tonic-gate 				scfdie();
16230Sstevel@tonic-gate 		}
16240Sstevel@tonic-gate 	} while (ret == 0);
16250Sstevel@tonic-gate 
16260Sstevel@tonic-gate out:
16270Sstevel@tonic-gate 	scf_transaction_destroy(tx);
16280Sstevel@tonic-gate 	scf_entry_destroy(txent);
16290Sstevel@tonic-gate 	scf_value_destroy(val);
16300Sstevel@tonic-gate 	scf_property_destroy(prop);
16310Sstevel@tonic-gate 	scf_pg_destroy(pg);
16320Sstevel@tonic-gate 	scf_instance_destroy(inst);
16330Sstevel@tonic-gate }
16340Sstevel@tonic-gate 
16350Sstevel@tonic-gate 
16360Sstevel@tonic-gate /*
16370Sstevel@tonic-gate  * Flags to control enable and disable actions.
16380Sstevel@tonic-gate  */
16390Sstevel@tonic-gate #define	SET_ENABLED	0x1
16400Sstevel@tonic-gate #define	SET_TEMPORARY	0x2
16410Sstevel@tonic-gate #define	SET_RECURSIVE	0x4
16420Sstevel@tonic-gate 
16430Sstevel@tonic-gate static int
16440Sstevel@tonic-gate set_fmri_enabled(void *data, scf_walkinfo_t *wip)
16450Sstevel@tonic-gate {
16460Sstevel@tonic-gate 	int flags = (int)data;
16470Sstevel@tonic-gate 
16480Sstevel@tonic-gate 	assert(wip->inst != NULL);
16490Sstevel@tonic-gate 	assert(wip->pg == NULL);
16500Sstevel@tonic-gate 
16510Sstevel@tonic-gate 	if (flags & SET_RECURSIVE) {
16520Sstevel@tonic-gate 		char *fmri_buf = malloc(max_scf_fmri_sz);
16530Sstevel@tonic-gate 		if (fmri_buf == NULL)
16540Sstevel@tonic-gate 			uu_die(emsg_nomem);
16550Sstevel@tonic-gate 
16560Sstevel@tonic-gate 		visited = calloc(HT_BUCKETS, sizeof (*visited));
16570Sstevel@tonic-gate 		if (visited == NULL)
16580Sstevel@tonic-gate 			uu_die(emsg_nomem);
16590Sstevel@tonic-gate 
16600Sstevel@tonic-gate 		/* scf_walk_fmri() guarantees that fmri isn't too long */
16610Sstevel@tonic-gate 		assert(strlen(wip->fmri) <= max_scf_fmri_sz);
16620Sstevel@tonic-gate 		(void) strlcpy(fmri_buf, wip->fmri, max_scf_fmri_sz);
16630Sstevel@tonic-gate 
16640Sstevel@tonic-gate 		switch (enable_fmri_rec(fmri_buf, (flags & SET_TEMPORARY))) {
16650Sstevel@tonic-gate 		case E2BIG:
16660Sstevel@tonic-gate 			uu_warn(gettext("operation on service %s is ambiguous; "
16670Sstevel@tonic-gate 			    "instance specification needed.\n"), fmri_buf);
16680Sstevel@tonic-gate 			break;
16690Sstevel@tonic-gate 
16700Sstevel@tonic-gate 		case ELOOP:
16710Sstevel@tonic-gate 			uu_warn(gettext("%s: Dependency cycle detected.\n"),
16720Sstevel@tonic-gate 			    fmri_buf);
16730Sstevel@tonic-gate 		}
16740Sstevel@tonic-gate 
16750Sstevel@tonic-gate 		free(visited);
16760Sstevel@tonic-gate 		free(fmri_buf);
16770Sstevel@tonic-gate 
16780Sstevel@tonic-gate 	} else {
16790Sstevel@tonic-gate 		set_inst_enabled(wip->fmri, wip->inst,
16800Sstevel@tonic-gate 		    (flags & SET_TEMPORARY) != 0, (flags & SET_ENABLED) != 0);
16810Sstevel@tonic-gate 	}
16820Sstevel@tonic-gate 
16830Sstevel@tonic-gate 	return (0);
16840Sstevel@tonic-gate }
16850Sstevel@tonic-gate 
16860Sstevel@tonic-gate /* ARGSUSED */
16870Sstevel@tonic-gate static int
16880Sstevel@tonic-gate wait_fmri_enabled(void *data, scf_walkinfo_t *wip)
16890Sstevel@tonic-gate {
16900Sstevel@tonic-gate 	scf_propertygroup_t *pg = NULL;
16910Sstevel@tonic-gate 	char state[MAX_SCF_STATE_STRING_SZ];
16920Sstevel@tonic-gate 
16930Sstevel@tonic-gate 	assert(wip->inst != NULL);
16940Sstevel@tonic-gate 	assert(wip->pg == NULL);
16950Sstevel@tonic-gate 
16960Sstevel@tonic-gate 	do {
16970Sstevel@tonic-gate 		if (pg)
16980Sstevel@tonic-gate 			scf_pg_destroy(pg);
16990Sstevel@tonic-gate 		if (inst_get_state(wip->inst, state, wip->fmri, &pg) != 0) {
17000Sstevel@tonic-gate 			exit_status = EXIT_SVC_FAILURE;
17010Sstevel@tonic-gate 			return (0);
17020Sstevel@tonic-gate 		}
17030Sstevel@tonic-gate 
17040Sstevel@tonic-gate 		if (strcmp(state, SCF_STATE_STRING_ONLINE) == 0 ||
17050Sstevel@tonic-gate 		    strcmp(state, SCF_STATE_STRING_DEGRADED) == 0) {
17060Sstevel@tonic-gate 			/*
17070Sstevel@tonic-gate 			 * We're done.
17080Sstevel@tonic-gate 			 */
17090Sstevel@tonic-gate 			goto out;
17100Sstevel@tonic-gate 		}
17110Sstevel@tonic-gate 
17120Sstevel@tonic-gate 		if (strcmp(state, SCF_STATE_STRING_MAINT) == 0) {
17130Sstevel@tonic-gate 			/*
17140Sstevel@tonic-gate 			 * The service is ill.
17150Sstevel@tonic-gate 			 */
17160Sstevel@tonic-gate 			uu_warn(gettext("Instance \"%s\" is in maintenance"
17170Sstevel@tonic-gate 			    " state.\n"), wip->fmri);
17180Sstevel@tonic-gate 			exit_status = EXIT_SVC_FAILURE;
17190Sstevel@tonic-gate 			goto out;
17200Sstevel@tonic-gate 		}
17210Sstevel@tonic-gate 
17220Sstevel@tonic-gate 		if (!is_enabled(wip->inst)) {
17230Sstevel@tonic-gate 			/*
17240Sstevel@tonic-gate 			 * Someone stepped in and disabled the service.
17250Sstevel@tonic-gate 			 */
17260Sstevel@tonic-gate 			uu_warn(gettext("Instance \"%s\" has been disabled"
17270Sstevel@tonic-gate 			    " by another entity.\n"), wip->fmri);
17280Sstevel@tonic-gate 			exit_status = EXIT_SVC_FAILURE;
17290Sstevel@tonic-gate 			goto out;
17300Sstevel@tonic-gate 		}
17310Sstevel@tonic-gate 
17320Sstevel@tonic-gate 		if (!has_potential(wip->inst, B_FALSE)) {
17330Sstevel@tonic-gate 			/*
17340Sstevel@tonic-gate 			 * Our dependencies aren't met.  We'll never
17350Sstevel@tonic-gate 			 * amount to anything.
17360Sstevel@tonic-gate 			 */
17370Sstevel@tonic-gate 			uu_warn(gettext("Instance \"%s\" has unsatisfied"
17380Sstevel@tonic-gate 			    " dependencies.\n"), wip->fmri);
17390Sstevel@tonic-gate 			/*
17400Sstevel@tonic-gate 			 * EXIT_SVC_FAILURE takes precedence over
17410Sstevel@tonic-gate 			 * EXIT_DEP_FAILURE
17420Sstevel@tonic-gate 			 */
17430Sstevel@tonic-gate 			if (exit_status == 0)
17440Sstevel@tonic-gate 				exit_status = EXIT_DEP_FAILURE;
17450Sstevel@tonic-gate 			goto out;
17460Sstevel@tonic-gate 		}
17470Sstevel@tonic-gate 	} while (_scf_pg_wait(pg, WAIT_INTERVAL) >= 0);
17480Sstevel@tonic-gate 	scfdie();
17490Sstevel@tonic-gate 	/* NOTREACHED */
17500Sstevel@tonic-gate 
17510Sstevel@tonic-gate out:
17520Sstevel@tonic-gate 	scf_pg_destroy(pg);
17530Sstevel@tonic-gate 	return (0);
17540Sstevel@tonic-gate }
17550Sstevel@tonic-gate 
17560Sstevel@tonic-gate /* ARGSUSED */
17570Sstevel@tonic-gate static int
17580Sstevel@tonic-gate wait_fmri_disabled(void *data, scf_walkinfo_t *wip)
17590Sstevel@tonic-gate {
17600Sstevel@tonic-gate 	scf_propertygroup_t *pg = NULL;
17610Sstevel@tonic-gate 	char state[MAX_SCF_STATE_STRING_SZ];
17620Sstevel@tonic-gate 
17630Sstevel@tonic-gate 	assert(wip->inst != NULL);
17640Sstevel@tonic-gate 	assert(wip->pg == NULL);
17650Sstevel@tonic-gate 
17660Sstevel@tonic-gate 	do {
17670Sstevel@tonic-gate 		if (pg)
17680Sstevel@tonic-gate 			scf_pg_destroy(pg);
17690Sstevel@tonic-gate 		if (inst_get_state(wip->inst, state, wip->fmri, &pg) != 0) {
17700Sstevel@tonic-gate 			exit_status = EXIT_SVC_FAILURE;
17710Sstevel@tonic-gate 			return (0);
17720Sstevel@tonic-gate 		}
17730Sstevel@tonic-gate 
17740Sstevel@tonic-gate 		if (strcmp(state, SCF_STATE_STRING_DISABLED) == 0) {
17750Sstevel@tonic-gate 			/*
17760Sstevel@tonic-gate 			 * We're done.
17770Sstevel@tonic-gate 			 */
17780Sstevel@tonic-gate 			goto out;
17790Sstevel@tonic-gate 		}
17800Sstevel@tonic-gate 
17810Sstevel@tonic-gate 		if (strcmp(state, SCF_STATE_STRING_MAINT) == 0) {
17820Sstevel@tonic-gate 			/*
17830Sstevel@tonic-gate 			 * The service is ill.
17840Sstevel@tonic-gate 			 */
17850Sstevel@tonic-gate 			uu_warn(gettext("Instance \"%s\" is in maintenance"
17860Sstevel@tonic-gate 			    " state.\n"), wip->fmri);
17870Sstevel@tonic-gate 			exit_status = EXIT_SVC_FAILURE;
17880Sstevel@tonic-gate 			goto out;
17890Sstevel@tonic-gate 		}
17900Sstevel@tonic-gate 
17910Sstevel@tonic-gate 		if (is_enabled(wip->inst)) {
17920Sstevel@tonic-gate 			/*
17930Sstevel@tonic-gate 			 * Someone stepped in and enabled the service.
17940Sstevel@tonic-gate 			 */
17950Sstevel@tonic-gate 			uu_warn(gettext("Instance \"%s\" has been enabled"
17960Sstevel@tonic-gate 			    " by another entity.\n"), wip->fmri);
17970Sstevel@tonic-gate 			exit_status = EXIT_SVC_FAILURE;
17980Sstevel@tonic-gate 			goto out;
17990Sstevel@tonic-gate 		}
18000Sstevel@tonic-gate 
18010Sstevel@tonic-gate 		if (!has_potential(wip->inst, B_TRUE)) {
18020Sstevel@tonic-gate 			/*
18030Sstevel@tonic-gate 			 * Our restarter is hopeless.
18040Sstevel@tonic-gate 			 */
18050Sstevel@tonic-gate 			uu_warn(gettext("Restarter for instance \"%s\" is"
18060Sstevel@tonic-gate 			    " unavailable.\n"), wip->fmri);
18070Sstevel@tonic-gate 			/*
18080Sstevel@tonic-gate 			 * EXIT_SVC_FAILURE takes precedence over
18090Sstevel@tonic-gate 			 * EXIT_DEP_FAILURE
18100Sstevel@tonic-gate 			 */
18110Sstevel@tonic-gate 			if (exit_status == 0)
18120Sstevel@tonic-gate 				exit_status = EXIT_DEP_FAILURE;
18130Sstevel@tonic-gate 			goto out;
18140Sstevel@tonic-gate 		}
18150Sstevel@tonic-gate 
18160Sstevel@tonic-gate 	} while (_scf_pg_wait(pg, WAIT_INTERVAL) >= 0);
18170Sstevel@tonic-gate 	scfdie();
18180Sstevel@tonic-gate 	/* NOTREACHED */
18190Sstevel@tonic-gate 
18200Sstevel@tonic-gate out:
18210Sstevel@tonic-gate 	scf_pg_destroy(pg);
18220Sstevel@tonic-gate 	return (0);
18230Sstevel@tonic-gate }
18240Sstevel@tonic-gate 
18250Sstevel@tonic-gate /* ARGSUSED */
18260Sstevel@tonic-gate static int
18270Sstevel@tonic-gate clear_instance(void *data, scf_walkinfo_t *wip)
18280Sstevel@tonic-gate {
18290Sstevel@tonic-gate 	char state[MAX_SCF_STATE_STRING_SZ];
18300Sstevel@tonic-gate 
18310Sstevel@tonic-gate 	assert(wip->inst != NULL);
18320Sstevel@tonic-gate 	assert(wip->pg == NULL);
18330Sstevel@tonic-gate 
18340Sstevel@tonic-gate 	if (inst_get_state(wip->inst, state, wip->fmri, NULL) != 0)
18350Sstevel@tonic-gate 		return (0);
18360Sstevel@tonic-gate 
18370Sstevel@tonic-gate 	if (strcmp(state, SCF_STATE_STRING_MAINT) == 0) {
18380Sstevel@tonic-gate 		set_inst_action(wip->fmri, wip->inst, SCF_PROPERTY_MAINT_OFF);
18390Sstevel@tonic-gate 	} else if (strcmp(state, SCF_STATE_STRING_DEGRADED) ==
18400Sstevel@tonic-gate 	    0) {
18410Sstevel@tonic-gate 		set_inst_action(wip->fmri, wip->inst, SCF_PROPERTY_RESTORE);
18420Sstevel@tonic-gate 	} else {
18430Sstevel@tonic-gate 		uu_warn(gettext("Instance \"%s\" is not in a "
18440Sstevel@tonic-gate 		    "maintenance or degraded state.\n"), wip->fmri);
18450Sstevel@tonic-gate 
18460Sstevel@tonic-gate 		exit_status = 1;
18470Sstevel@tonic-gate 	}
18480Sstevel@tonic-gate 
18490Sstevel@tonic-gate 	return (0);
18500Sstevel@tonic-gate }
18510Sstevel@tonic-gate 
18520Sstevel@tonic-gate static int
18530Sstevel@tonic-gate set_fmri_action(void *action, scf_walkinfo_t *wip)
18540Sstevel@tonic-gate {
18550Sstevel@tonic-gate 	assert(wip->inst != NULL && wip->pg == NULL);
18560Sstevel@tonic-gate 
18570Sstevel@tonic-gate 	set_inst_action(wip->fmri, wip->inst, action);
18580Sstevel@tonic-gate 
18590Sstevel@tonic-gate 	return (0);
18600Sstevel@tonic-gate }
18610Sstevel@tonic-gate 
18620Sstevel@tonic-gate /*
18630Sstevel@tonic-gate  * Flags to control 'mark' action.
18640Sstevel@tonic-gate  */
18650Sstevel@tonic-gate #define	MARK_IMMEDIATE	0x1
18660Sstevel@tonic-gate #define	MARK_TEMPORARY	0x2
18670Sstevel@tonic-gate 
18680Sstevel@tonic-gate static int
18690Sstevel@tonic-gate force_degraded(void *data, scf_walkinfo_t *wip)
18700Sstevel@tonic-gate {
18710Sstevel@tonic-gate 	int flags = (int)data;
18720Sstevel@tonic-gate 	char state[MAX_SCF_STATE_STRING_SZ];
18730Sstevel@tonic-gate 
18740Sstevel@tonic-gate 	if (inst_get_state(wip->inst, state, wip->fmri, NULL) != 0) {
18750Sstevel@tonic-gate 		exit_status = 1;
18760Sstevel@tonic-gate 		return (0);
18770Sstevel@tonic-gate 	}
18780Sstevel@tonic-gate 
18790Sstevel@tonic-gate 	if (strcmp(state, SCF_STATE_STRING_ONLINE) != 0) {
18800Sstevel@tonic-gate 		uu_warn(gettext("Instance \"%s\" is not online.\n"), wip->fmri);
18810Sstevel@tonic-gate 		exit_status = 1;
18820Sstevel@tonic-gate 		return (0);
18830Sstevel@tonic-gate 	}
18840Sstevel@tonic-gate 
18850Sstevel@tonic-gate 	set_inst_action(wip->fmri, wip->inst, (flags & MARK_IMMEDIATE) ?
18860Sstevel@tonic-gate 	    SCF_PROPERTY_DEGRADE_IMMEDIATE : SCF_PROPERTY_DEGRADED);
18870Sstevel@tonic-gate 
18880Sstevel@tonic-gate 	return (0);
18890Sstevel@tonic-gate }
18900Sstevel@tonic-gate 
18910Sstevel@tonic-gate static int
18920Sstevel@tonic-gate force_maintenance(void *data, scf_walkinfo_t *wip)
18930Sstevel@tonic-gate {
18940Sstevel@tonic-gate 	int flags = (int)data;
18950Sstevel@tonic-gate 	const char *prop;
18960Sstevel@tonic-gate 
18970Sstevel@tonic-gate 	if (flags & MARK_IMMEDIATE) {
18980Sstevel@tonic-gate 		prop = (flags & MARK_TEMPORARY) ?
18990Sstevel@tonic-gate 		    SCF_PROPERTY_MAINT_ON_IMMTEMP :
19000Sstevel@tonic-gate 		    SCF_PROPERTY_MAINT_ON_IMMEDIATE;
19010Sstevel@tonic-gate 	} else {
19020Sstevel@tonic-gate 		prop = (flags & MARK_TEMPORARY) ?
19030Sstevel@tonic-gate 		    SCF_PROPERTY_MAINT_ON_TEMPORARY :
19040Sstevel@tonic-gate 		    SCF_PROPERTY_MAINT_ON;
19050Sstevel@tonic-gate 	}
19060Sstevel@tonic-gate 
19070Sstevel@tonic-gate 	set_inst_action(wip->fmri, wip->inst, prop);
19080Sstevel@tonic-gate 
19090Sstevel@tonic-gate 	return (0);
19100Sstevel@tonic-gate }
19110Sstevel@tonic-gate 
19120Sstevel@tonic-gate static void
19130Sstevel@tonic-gate set_milestone(const char *fmri, boolean_t temporary)
19140Sstevel@tonic-gate {
19150Sstevel@tonic-gate 	scf_instance_t *inst;
19160Sstevel@tonic-gate 	scf_propertygroup_t *pg;
19170Sstevel@tonic-gate 	int r;
19180Sstevel@tonic-gate 
19190Sstevel@tonic-gate 	if (temporary) {
19200Sstevel@tonic-gate 		set_astring_prop(SCF_SERVICE_STARTD, SCF_PG_OPTIONS_OVR,
19210Sstevel@tonic-gate 		    SCF_PG_OPTIONS_OVR_TYPE, SCF_PG_OPTIONS_OVR_FLAGS,
19220Sstevel@tonic-gate 		    SCF_PROPERTY_MILESTONE, fmri);
19230Sstevel@tonic-gate 		return;
19240Sstevel@tonic-gate 	}
19250Sstevel@tonic-gate 
19260Sstevel@tonic-gate 	if ((inst = scf_instance_create(h)) == NULL ||
19270Sstevel@tonic-gate 	    (pg = scf_pg_create(h)) == NULL)
19280Sstevel@tonic-gate 		scfdie();
19290Sstevel@tonic-gate 
19300Sstevel@tonic-gate 	if (get_inst(SCF_SERVICE_STARTD, inst) != 0) {
19310Sstevel@tonic-gate 		scf_instance_destroy(inst);
19320Sstevel@tonic-gate 		return;
19330Sstevel@tonic-gate 	}
19340Sstevel@tonic-gate 
19350Sstevel@tonic-gate 	/*
19360Sstevel@tonic-gate 	 * Set the persistent milestone before deleting the override so we don't
19370Sstevel@tonic-gate 	 * glitch.
19380Sstevel@tonic-gate 	 */
19390Sstevel@tonic-gate 	set_astring_prop(SCF_SERVICE_STARTD, SCF_PG_OPTIONS,
19400Sstevel@tonic-gate 	    SCF_PG_OPTIONS_TYPE, SCF_PG_OPTIONS_FLAGS, SCF_PROPERTY_MILESTONE,
19410Sstevel@tonic-gate 	    fmri);
19420Sstevel@tonic-gate 
19430Sstevel@tonic-gate 	if (scf_instance_get_pg(inst, SCF_PG_OPTIONS_OVR, pg) == 0) {
19440Sstevel@tonic-gate 		r = delete_prop(pg, SCF_PROPERTY_MILESTONE);
19450Sstevel@tonic-gate 		switch (r) {
19460Sstevel@tonic-gate 		case 0:
19470Sstevel@tonic-gate 			break;
19480Sstevel@tonic-gate 
19490Sstevel@tonic-gate 		case ECANCELED:
19500Sstevel@tonic-gate 			uu_warn(emsg_no_service, fmri);
19510Sstevel@tonic-gate 			exit_status = 1;
19520Sstevel@tonic-gate 			goto out;
19530Sstevel@tonic-gate 
19540Sstevel@tonic-gate 		case EPERM:
19550Sstevel@tonic-gate 			uu_warn(gettext("Could not delete %s/%s property of "
19560Sstevel@tonic-gate 			    "%s: permission denied.\n"), SCF_PG_OPTIONS_OVR,
19570Sstevel@tonic-gate 			    SCF_PROPERTY_MILESTONE, SCF_SERVICE_STARTD);
19580Sstevel@tonic-gate 			exit_status = 1;
19590Sstevel@tonic-gate 			goto out;
19600Sstevel@tonic-gate 
19610Sstevel@tonic-gate 		case EACCES:
19620Sstevel@tonic-gate 			uu_warn(gettext("Could not delete %s/%s property of "
19630Sstevel@tonic-gate 			    "%s: access denied.\n"), SCF_PG_OPTIONS_OVR,
19640Sstevel@tonic-gate 			    SCF_PROPERTY_MILESTONE, SCF_SERVICE_STARTD);
19650Sstevel@tonic-gate 			exit_status = 1;
19660Sstevel@tonic-gate 			goto out;
19670Sstevel@tonic-gate 
19680Sstevel@tonic-gate 		case EROFS:
19690Sstevel@tonic-gate 			uu_warn(gettext("Could not delete %s/%s property of "
19700Sstevel@tonic-gate 			    "%s: backend read-only.\n"), SCF_PG_OPTIONS_OVR,
19710Sstevel@tonic-gate 			    SCF_PROPERTY_MILESTONE, SCF_SERVICE_STARTD);
19720Sstevel@tonic-gate 			exit_status = 1;
19730Sstevel@tonic-gate 			goto out;
19740Sstevel@tonic-gate 
19750Sstevel@tonic-gate 		default:
19760Sstevel@tonic-gate 			bad_error("delete_prop", r);
19770Sstevel@tonic-gate 		}
19780Sstevel@tonic-gate 	} else {
19790Sstevel@tonic-gate 		switch (scf_error()) {
19800Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
19810Sstevel@tonic-gate 			break;
19820Sstevel@tonic-gate 
19830Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
19840Sstevel@tonic-gate 			uu_warn(emsg_no_service, fmri);
19850Sstevel@tonic-gate 			exit_status = 1;
19860Sstevel@tonic-gate 			goto out;
19870Sstevel@tonic-gate 
19880Sstevel@tonic-gate 		case SCF_ERROR_CONNECTION_BROKEN:
19890Sstevel@tonic-gate 		case SCF_ERROR_HANDLE_MISMATCH:
19900Sstevel@tonic-gate 		case SCF_ERROR_NOT_BOUND:
19910Sstevel@tonic-gate 		case SCF_ERROR_INVALID_ARGUMENT:
19920Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
19930Sstevel@tonic-gate 		default:
19940Sstevel@tonic-gate 			scfdie();
19950Sstevel@tonic-gate 		}
19960Sstevel@tonic-gate 	}
19970Sstevel@tonic-gate 
19980Sstevel@tonic-gate out:
19990Sstevel@tonic-gate 	scf_pg_destroy(pg);
20000Sstevel@tonic-gate 	scf_instance_destroy(inst);
20010Sstevel@tonic-gate }
20020Sstevel@tonic-gate 
20030Sstevel@tonic-gate static char const *milestones[] = {
20040Sstevel@tonic-gate 	SCF_MILESTONE_SINGLE_USER,
20050Sstevel@tonic-gate 	SCF_MILESTONE_MULTI_USER,
20060Sstevel@tonic-gate 	SCF_MILESTONE_MULTI_USER_SERVER,
20070Sstevel@tonic-gate 	NULL
20080Sstevel@tonic-gate };
20090Sstevel@tonic-gate 
20100Sstevel@tonic-gate static void
2011*471Shg115875 usage_milestone(void)
20120Sstevel@tonic-gate {
20130Sstevel@tonic-gate 	const char **ms;
20140Sstevel@tonic-gate 
20150Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(
20160Sstevel@tonic-gate 	"Usage: svcadm milestone [-d] <milestone>\n\n"
20170Sstevel@tonic-gate 	"\t-d\tmake the specified milestone the default for system boot\n\n"
20180Sstevel@tonic-gate 	"\tMilestones can be specified using an FMRI or abbreviation.\n"
20190Sstevel@tonic-gate 	"\tThe major milestones are as follows:\n\n"
20200Sstevel@tonic-gate 	"\tall\n"
20210Sstevel@tonic-gate 	"\tnone\n"));
20220Sstevel@tonic-gate 
20230Sstevel@tonic-gate 	for (ms = milestones; *ms != NULL; ms++)
20240Sstevel@tonic-gate 		(void) fprintf(stderr, "\t%s\n", *ms);
20250Sstevel@tonic-gate 
20260Sstevel@tonic-gate 	exit(UU_EXIT_USAGE);
20270Sstevel@tonic-gate }
20280Sstevel@tonic-gate 
20290Sstevel@tonic-gate static const char *
20300Sstevel@tonic-gate validate_milestone(const char *milestone)
20310Sstevel@tonic-gate {
20320Sstevel@tonic-gate 	const char **ms;
20330Sstevel@tonic-gate 	const char *tmp;
20340Sstevel@tonic-gate 	size_t len;
20350Sstevel@tonic-gate 
20360Sstevel@tonic-gate 	if (strcmp(milestone, "all") == 0)
20370Sstevel@tonic-gate 		return (milestone);
20380Sstevel@tonic-gate 
20390Sstevel@tonic-gate 	if (strcmp(milestone, "none") == 0)
20400Sstevel@tonic-gate 		return (milestone);
20410Sstevel@tonic-gate 
20420Sstevel@tonic-gate 	/*
20430Sstevel@tonic-gate 	 * Determine if this is a full or partial milestone
20440Sstevel@tonic-gate 	 */
20450Sstevel@tonic-gate 	for (ms = milestones; *ms != NULL; ms++) {
20460Sstevel@tonic-gate 		if ((tmp = strstr(*ms, milestone)) != NULL) {
20470Sstevel@tonic-gate 			len = strlen(milestone);
20480Sstevel@tonic-gate 
20490Sstevel@tonic-gate 			/*
20500Sstevel@tonic-gate 			 * The beginning of the string must align with the start
20510Sstevel@tonic-gate 			 * of a milestone fmri, or on the boundary between
20520Sstevel@tonic-gate 			 * elements.  The end of the string must align with the
20530Sstevel@tonic-gate 			 * end of the milestone, or at the instance boundary.
20540Sstevel@tonic-gate 			 */
20550Sstevel@tonic-gate 			if ((tmp == *ms || tmp[-1] == '/') &&
20560Sstevel@tonic-gate 			    (tmp[len] == '\0' || tmp[len] == ':'))
20570Sstevel@tonic-gate 				return (*ms);
20580Sstevel@tonic-gate 		}
20590Sstevel@tonic-gate 	}
20600Sstevel@tonic-gate 
20610Sstevel@tonic-gate 	(void) fprintf(stderr,
20620Sstevel@tonic-gate 	    gettext("\"%s\" is not a valid major milestone.\n"), milestone);
20630Sstevel@tonic-gate 
20640Sstevel@tonic-gate 	usage_milestone();
20650Sstevel@tonic-gate 	/* NOTREACHED */
20660Sstevel@tonic-gate }
20670Sstevel@tonic-gate 
20680Sstevel@tonic-gate /*ARGSUSED*/
20690Sstevel@tonic-gate static void
20700Sstevel@tonic-gate quiet(const char *fmt, ...)
20710Sstevel@tonic-gate {
20720Sstevel@tonic-gate 	/* Do nothing */
20730Sstevel@tonic-gate }
20740Sstevel@tonic-gate 
20750Sstevel@tonic-gate int
20760Sstevel@tonic-gate main(int argc, char *argv[])
20770Sstevel@tonic-gate {
20780Sstevel@tonic-gate 	int o;
20790Sstevel@tonic-gate 	int err;
20800Sstevel@tonic-gate 
20810Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
20820Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
20830Sstevel@tonic-gate 
20840Sstevel@tonic-gate 	(void) uu_setpname(argv[0]);
20850Sstevel@tonic-gate 
20860Sstevel@tonic-gate 	if (argc < 2)
20870Sstevel@tonic-gate 		usage();
20880Sstevel@tonic-gate 
20890Sstevel@tonic-gate 	max_scf_fmri_sz = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH);
20900Sstevel@tonic-gate 	if (max_scf_fmri_sz < 0)
20910Sstevel@tonic-gate 		scfdie();
20920Sstevel@tonic-gate 	++max_scf_fmri_sz;
20930Sstevel@tonic-gate 
20940Sstevel@tonic-gate 	scratch_fmri = malloc(max_scf_fmri_sz);
20950Sstevel@tonic-gate 	if (scratch_fmri == NULL)
20960Sstevel@tonic-gate 		uu_die(emsg_nomem);
20970Sstevel@tonic-gate 
20980Sstevel@tonic-gate 	h = scf_handle_create(SCF_VERSION);
20990Sstevel@tonic-gate 	if (h == NULL)
21000Sstevel@tonic-gate 		scfdie();
21010Sstevel@tonic-gate 
21020Sstevel@tonic-gate 	if (scf_handle_bind(h) == -1)
21030Sstevel@tonic-gate 		uu_die(gettext("Couldn't bind to svc.configd.\n"));
21040Sstevel@tonic-gate 
21050Sstevel@tonic-gate 	while ((o = getopt(argc, argv, "v")) != -1) {
21060Sstevel@tonic-gate 		if (o == 'v')
21070Sstevel@tonic-gate 			verbose = 1;
21080Sstevel@tonic-gate 		else
21090Sstevel@tonic-gate 			usage();
21100Sstevel@tonic-gate 	}
21110Sstevel@tonic-gate 
21120Sstevel@tonic-gate 	if (optind >= argc)
21130Sstevel@tonic-gate 		usage();
21140Sstevel@tonic-gate 
21150Sstevel@tonic-gate 	emsg_permission_denied = gettext("%s: Permission denied.\n");
21160Sstevel@tonic-gate 	emsg_nomem = gettext("Out of memory.\n");
21170Sstevel@tonic-gate 	emsg_create_pg_perm_denied = gettext("%s: Couldn't create \"%s\" "
21180Sstevel@tonic-gate 	    "property group (permission denied).\n");
21190Sstevel@tonic-gate 	emsg_pg_perm_denied = gettext("%s: Couldn't modify \"%s\" property "
21200Sstevel@tonic-gate 	    "group (permission denied).\n");
21210Sstevel@tonic-gate 	emsg_prop_perm_denied = gettext("%s: Couldn't modify \"%s/%s\" "
21220Sstevel@tonic-gate 	    "property (permission denied).\n");
21230Sstevel@tonic-gate 	emsg_no_service = gettext("No such service \"%s\".\n");
21240Sstevel@tonic-gate 
21250Sstevel@tonic-gate 	if (strcmp(argv[optind], "enable") == 0) {
21260Sstevel@tonic-gate 		int flags = SET_ENABLED;
21270Sstevel@tonic-gate 		int wait = 0;
21280Sstevel@tonic-gate 		int error = 0;
21290Sstevel@tonic-gate 
21300Sstevel@tonic-gate 		++optind;
21310Sstevel@tonic-gate 
21320Sstevel@tonic-gate 		while ((o = getopt(argc, argv, "rst")) != -1) {
21330Sstevel@tonic-gate 			if (o == 'r')
21340Sstevel@tonic-gate 				flags |= SET_RECURSIVE;
21350Sstevel@tonic-gate 			else if (o == 't')
21360Sstevel@tonic-gate 				flags |= SET_TEMPORARY;
21370Sstevel@tonic-gate 			else if (o == 's')
21380Sstevel@tonic-gate 				wait = 1;
21390Sstevel@tonic-gate 			else if (o == '?')
21400Sstevel@tonic-gate 				usage();
21410Sstevel@tonic-gate 			else {
21420Sstevel@tonic-gate 				assert(0);
21430Sstevel@tonic-gate 				abort();
21440Sstevel@tonic-gate 			}
21450Sstevel@tonic-gate 		}
21460Sstevel@tonic-gate 		argc -= optind;
21470Sstevel@tonic-gate 		argv += optind;
21480Sstevel@tonic-gate 
21490Sstevel@tonic-gate 		if (argc <= 0)
21500Sstevel@tonic-gate 			usage();
21510Sstevel@tonic-gate 
21520Sstevel@tonic-gate 		/*
21530Sstevel@tonic-gate 		 * We want to continue with -s processing if we had
21540Sstevel@tonic-gate 		 * invalid options, but not if an enable failed.  We
21550Sstevel@tonic-gate 		 * squelch output the second time we walk fmris; we saw
21560Sstevel@tonic-gate 		 * the errors the first time.
21570Sstevel@tonic-gate 		 */
21580Sstevel@tonic-gate 		if ((err = scf_walk_fmri(h, argc, argv, 0, set_fmri_enabled,
21590Sstevel@tonic-gate 		    (void *)flags, &error, uu_warn)) != 0) {
21600Sstevel@tonic-gate 
21610Sstevel@tonic-gate 			uu_warn(gettext("failed to iterate over "
21620Sstevel@tonic-gate 			    "instances: %s\n"), scf_strerror(err));
21630Sstevel@tonic-gate 			exit_status = UU_EXIT_FATAL;
21640Sstevel@tonic-gate 
21650Sstevel@tonic-gate 		} else if (wait && exit_status == 0 &&
21660Sstevel@tonic-gate 		    (err = scf_walk_fmri(h, argc, argv, 0, wait_fmri_enabled,
21670Sstevel@tonic-gate 		    (void *)flags, &error, quiet)) != 0) {
21680Sstevel@tonic-gate 
21690Sstevel@tonic-gate 			uu_warn(gettext("failed to iterate over "
21700Sstevel@tonic-gate 			    "instances: %s\n"), scf_strerror(err));
21710Sstevel@tonic-gate 			exit_status = UU_EXIT_FATAL;
21720Sstevel@tonic-gate 		}
21730Sstevel@tonic-gate 
21740Sstevel@tonic-gate 		if (error > 0)
21750Sstevel@tonic-gate 			exit_status = error;
21760Sstevel@tonic-gate 
21770Sstevel@tonic-gate 	} else if (strcmp(argv[optind], "disable") == 0) {
21780Sstevel@tonic-gate 		int flags = 0;
21790Sstevel@tonic-gate 		int wait = 0;
21800Sstevel@tonic-gate 		int error = 0;
21810Sstevel@tonic-gate 
21820Sstevel@tonic-gate 		++optind;
21830Sstevel@tonic-gate 
21840Sstevel@tonic-gate 		while ((o = getopt(argc, argv, "st")) != -1) {
21850Sstevel@tonic-gate 			if (o == 't')
21860Sstevel@tonic-gate 				flags |= SET_TEMPORARY;
21870Sstevel@tonic-gate 			else if (o == 's')
21880Sstevel@tonic-gate 				wait = 1;
21890Sstevel@tonic-gate 			else if (o == '?')
21900Sstevel@tonic-gate 				usage();
21910Sstevel@tonic-gate 			else {
21920Sstevel@tonic-gate 				assert(0);
21930Sstevel@tonic-gate 				abort();
21940Sstevel@tonic-gate 			}
21950Sstevel@tonic-gate 		}
21960Sstevel@tonic-gate 		argc -= optind;
21970Sstevel@tonic-gate 		argv += optind;
21980Sstevel@tonic-gate 
21990Sstevel@tonic-gate 		if (argc <= 0)
22000Sstevel@tonic-gate 			usage();
22010Sstevel@tonic-gate 
22020Sstevel@tonic-gate 		/*
22030Sstevel@tonic-gate 		 * We want to continue with -s processing if we had
22040Sstevel@tonic-gate 		 * invalid options, but not if a disable failed.  We
22050Sstevel@tonic-gate 		 * squelch output the second time we walk fmris; we saw
22060Sstevel@tonic-gate 		 * the errors the first time.
22070Sstevel@tonic-gate 		 */
22080Sstevel@tonic-gate 		if ((err = scf_walk_fmri(h, argc, argv, 0, set_fmri_enabled,
22090Sstevel@tonic-gate 		    (void *)flags, &exit_status, uu_warn)) != 0) {
22100Sstevel@tonic-gate 
22110Sstevel@tonic-gate 			uu_warn(gettext("failed to iterate over "
22120Sstevel@tonic-gate 			    "instances: %s\n"), scf_strerror(err));
22130Sstevel@tonic-gate 			exit_status = UU_EXIT_FATAL;
22140Sstevel@tonic-gate 
22150Sstevel@tonic-gate 		} else if (wait && exit_status == 0 &&
22160Sstevel@tonic-gate 		    (err = scf_walk_fmri(h, argc, argv, 0, wait_fmri_disabled,
22170Sstevel@tonic-gate 		    (void *)flags, &error, quiet)) != 0) {
22180Sstevel@tonic-gate 
22190Sstevel@tonic-gate 			uu_warn(gettext("failed to iterate over "
22200Sstevel@tonic-gate 			    "instances: %s\n"), scf_strerror(err));
22210Sstevel@tonic-gate 			exit_status = UU_EXIT_FATAL;
22220Sstevel@tonic-gate 		}
22230Sstevel@tonic-gate 
22240Sstevel@tonic-gate 		if (error > 0)
22250Sstevel@tonic-gate 			exit_status = error;
22260Sstevel@tonic-gate 
22270Sstevel@tonic-gate 	} else if (strcmp(argv[optind], "restart") == 0) {
22280Sstevel@tonic-gate 		++optind;
22290Sstevel@tonic-gate 
22300Sstevel@tonic-gate 		if (optind >= argc)
22310Sstevel@tonic-gate 			usage();
22320Sstevel@tonic-gate 
22330Sstevel@tonic-gate 		if ((err = scf_walk_fmri(h, argc - optind, argv + optind, 0,
22340Sstevel@tonic-gate 		    set_fmri_action, (void *)SCF_PROPERTY_RESTART,
22350Sstevel@tonic-gate 		    &exit_status, uu_warn)) != 0) {
22360Sstevel@tonic-gate 			uu_warn(gettext("failed to iterate over "
22370Sstevel@tonic-gate 			    "instances: %s\n"), scf_strerror(err));
22380Sstevel@tonic-gate 			exit_status = UU_EXIT_FATAL;
22390Sstevel@tonic-gate 		}
22400Sstevel@tonic-gate 
22410Sstevel@tonic-gate 	} else if (strcmp(argv[optind], "refresh") == 0) {
22420Sstevel@tonic-gate 		++optind;
22430Sstevel@tonic-gate 
22440Sstevel@tonic-gate 		if (optind >= argc)
22450Sstevel@tonic-gate 			usage();
22460Sstevel@tonic-gate 
22470Sstevel@tonic-gate 		if ((err = scf_walk_fmri(h, argc - optind, argv + optind, 0,
22480Sstevel@tonic-gate 		    set_fmri_action, (void *)SCF_PROPERTY_REFRESH,
22490Sstevel@tonic-gate 		    &exit_status, uu_warn)) != 0) {
22500Sstevel@tonic-gate 			uu_warn(gettext("failed to iterate over "
22510Sstevel@tonic-gate 			    "instances: %s\n"), scf_strerror(scf_error()));
22520Sstevel@tonic-gate 			exit_status = UU_EXIT_FATAL;
22530Sstevel@tonic-gate 		}
22540Sstevel@tonic-gate 
22550Sstevel@tonic-gate 	} else if (strcmp(argv[optind], "mark") == 0) {
22560Sstevel@tonic-gate 		int flags = 0;
22570Sstevel@tonic-gate 		scf_walk_callback callback;
22580Sstevel@tonic-gate 
22590Sstevel@tonic-gate 		++optind;
22600Sstevel@tonic-gate 
22610Sstevel@tonic-gate 		while ((o = getopt(argc, argv, "It")) != -1) {
22620Sstevel@tonic-gate 			if (o == 'I')
22630Sstevel@tonic-gate 				flags |= MARK_IMMEDIATE;
22640Sstevel@tonic-gate 			else if (o == 't')
22650Sstevel@tonic-gate 				flags |= MARK_TEMPORARY;
22660Sstevel@tonic-gate 			else if (o == '?')
22670Sstevel@tonic-gate 				usage();
22680Sstevel@tonic-gate 			else {
22690Sstevel@tonic-gate 				assert(0);
22700Sstevel@tonic-gate 				abort();
22710Sstevel@tonic-gate 			}
22720Sstevel@tonic-gate 		}
22730Sstevel@tonic-gate 
22740Sstevel@tonic-gate 		if (argc - optind < 2)
22750Sstevel@tonic-gate 			usage();
22760Sstevel@tonic-gate 
22770Sstevel@tonic-gate 		if (strcmp(argv[optind], "degraded") == 0) {
22780Sstevel@tonic-gate 			if (flags & MARK_TEMPORARY)
22790Sstevel@tonic-gate 				uu_xdie(UU_EXIT_USAGE, gettext("-t may not be "
22800Sstevel@tonic-gate 				    "used with degraded.\n"));
22810Sstevel@tonic-gate 			callback = force_degraded;
22820Sstevel@tonic-gate 
22830Sstevel@tonic-gate 		} else if (strcmp(argv[optind], "maintenance") == 0) {
22840Sstevel@tonic-gate 			callback = force_maintenance;
22850Sstevel@tonic-gate 		} else {
22860Sstevel@tonic-gate 			usage();
22870Sstevel@tonic-gate 		}
22880Sstevel@tonic-gate 
22890Sstevel@tonic-gate 		if ((err = scf_walk_fmri(h, argc - optind - 1,
22900Sstevel@tonic-gate 		    argv + optind + 1, 0, callback, NULL, &exit_status,
22910Sstevel@tonic-gate 		    uu_warn)) != 0) {
22920Sstevel@tonic-gate 			uu_warn(gettext("failed to iterate over "
22930Sstevel@tonic-gate 			    "instances: %s\n"),
22940Sstevel@tonic-gate 			    scf_strerror(err));
22950Sstevel@tonic-gate 			exit_status = UU_EXIT_FATAL;
22960Sstevel@tonic-gate 		}
22970Sstevel@tonic-gate 
22980Sstevel@tonic-gate 	} else if (strcmp(argv[optind], "clear") == 0) {
22990Sstevel@tonic-gate 		++optind;
23000Sstevel@tonic-gate 
23010Sstevel@tonic-gate 		if (optind >= argc)
23020Sstevel@tonic-gate 			usage();
23030Sstevel@tonic-gate 
23040Sstevel@tonic-gate 		if ((err = scf_walk_fmri(h, argc - optind, argv + optind, 0,
23050Sstevel@tonic-gate 		    clear_instance, NULL, &exit_status, uu_warn)) != 0) {
23060Sstevel@tonic-gate 			uu_warn(gettext("failed to iterate over "
23070Sstevel@tonic-gate 			    "instances: %s\n"), scf_strerror(err));
23080Sstevel@tonic-gate 			exit_status = UU_EXIT_FATAL;
23090Sstevel@tonic-gate 		}
23100Sstevel@tonic-gate 
23110Sstevel@tonic-gate 	} else if (strcmp(argv[optind], "milestone") == 0) {
23120Sstevel@tonic-gate 		boolean_t temporary = B_TRUE;
23130Sstevel@tonic-gate 		const char *milestone;
23140Sstevel@tonic-gate 
23150Sstevel@tonic-gate 		++optind;
23160Sstevel@tonic-gate 
23170Sstevel@tonic-gate 		while ((o = getopt(argc, argv, "d")) != -1) {
23180Sstevel@tonic-gate 			if (o == 'd')
23190Sstevel@tonic-gate 				temporary = B_FALSE;
23200Sstevel@tonic-gate 			else if (o == '?')
23210Sstevel@tonic-gate 				usage_milestone();
23220Sstevel@tonic-gate 			else {
23230Sstevel@tonic-gate 				assert(0);
23240Sstevel@tonic-gate 				abort();
23250Sstevel@tonic-gate 			}
23260Sstevel@tonic-gate 		}
23270Sstevel@tonic-gate 
23280Sstevel@tonic-gate 		if (optind >= argc)
23290Sstevel@tonic-gate 			usage_milestone();
23300Sstevel@tonic-gate 
23310Sstevel@tonic-gate 		milestone = validate_milestone(argv[optind]);
23320Sstevel@tonic-gate 
23330Sstevel@tonic-gate 		set_milestone(milestone, temporary);
23340Sstevel@tonic-gate 	} else if (strcmp(argv[optind], "_smf_backup") == 0) {
23350Sstevel@tonic-gate 		const char *reason = NULL;
23360Sstevel@tonic-gate 
23370Sstevel@tonic-gate 		++optind;
23380Sstevel@tonic-gate 
23390Sstevel@tonic-gate 		if (optind != argc - 1)
23400Sstevel@tonic-gate 			usage();
23410Sstevel@tonic-gate 
23420Sstevel@tonic-gate 		if ((err = _scf_request_backup(h, argv[optind])) !=
23430Sstevel@tonic-gate 		    SCF_SUCCESS) {
23440Sstevel@tonic-gate 			switch (scf_error()) {
23450Sstevel@tonic-gate 			case SCF_ERROR_NOT_BOUND:
23460Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
23470Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_READONLY:
23480Sstevel@tonic-gate 				scfdie();
23490Sstevel@tonic-gate 				break;
23500Sstevel@tonic-gate 
23510Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
23520Sstevel@tonic-gate 			case SCF_ERROR_INVALID_ARGUMENT:
23530Sstevel@tonic-gate 				reason = scf_strerror(scf_error());
23540Sstevel@tonic-gate 				break;
23550Sstevel@tonic-gate 
23560Sstevel@tonic-gate 			case SCF_ERROR_INTERNAL:
23570Sstevel@tonic-gate 				reason =
23580Sstevel@tonic-gate 				    "unknown error (see console for details)";
23590Sstevel@tonic-gate 				break;
23600Sstevel@tonic-gate 			}
23610Sstevel@tonic-gate 			uu_warn("failed to backup repository: %s\n", reason);
23620Sstevel@tonic-gate 			exit_status = UU_EXIT_FATAL;
23630Sstevel@tonic-gate 		}
23640Sstevel@tonic-gate 	} else {
23650Sstevel@tonic-gate 		usage();
23660Sstevel@tonic-gate 	}
23670Sstevel@tonic-gate 
23680Sstevel@tonic-gate 	if (scf_handle_unbind(h) == -1)
23690Sstevel@tonic-gate 		scfdie();
23700Sstevel@tonic-gate 	scf_handle_destroy(h);
23710Sstevel@tonic-gate 
23720Sstevel@tonic-gate 	return (exit_status);
23730Sstevel@tonic-gate }
2374