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