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