xref: /illumos-gate/usr/src/cmd/svc/svcadm/svcadm.c (revision 29267a9d)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57646ae23Slianep  * Common Development and Distribution License (the "License").
67646ae23Slianep  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22eb1a3463STruong Nguyen  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
26647f8444SBryan Cantrill /*
278fff7887SJohn Levon  * Copyright 2020, Joyent, Inc. All rights reserved.
2875987085SAndy Fiddaman  * Copyright 2023 Oxide Computer Company
29647f8444SBryan Cantrill  */
30647f8444SBryan Cantrill 
317c478bd9Sstevel@tonic-gate /*
327c478bd9Sstevel@tonic-gate  * svcadm - request adminstrative actions for service instances
337c478bd9Sstevel@tonic-gate  */
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate #include <locale.h>
367c478bd9Sstevel@tonic-gate #include <libintl.h>
377c478bd9Sstevel@tonic-gate #include <libscf.h>
387c478bd9Sstevel@tonic-gate #include <libscf_priv.h>
39eb1a3463STruong Nguyen #include <libcontract.h>
40eb1a3463STruong Nguyen #include <libcontract_priv.h>
41eb1a3463STruong Nguyen #include <sys/contract/process.h>
427c478bd9Sstevel@tonic-gate #include <libuutil.h>
437c478bd9Sstevel@tonic-gate #include <stddef.h>
447c478bd9Sstevel@tonic-gate #include <stdio.h>
457c478bd9Sstevel@tonic-gate #include <stdlib.h>
467c478bd9Sstevel@tonic-gate #include <string.h>
477c478bd9Sstevel@tonic-gate #include <unistd.h>
48eb1a3463STruong Nguyen #include <fcntl.h>
49eb1a3463STruong Nguyen #include <procfs.h>
507c478bd9Sstevel@tonic-gate #include <assert.h>
517c478bd9Sstevel@tonic-gate #include <errno.h>
52647f8444SBryan Cantrill #include <zone.h>
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate #ifndef TEXT_DOMAIN
557c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN	"SUNW_OST_OSCMD"
567c478bd9Sstevel@tonic-gate #endif /* TEXT_DOMAIN */
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate /* Must be a power of two */
597c478bd9Sstevel@tonic-gate #define	HT_BUCKETS	64
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate /*
627c478bd9Sstevel@tonic-gate  * Exit codes for enable and disable -s.
637c478bd9Sstevel@tonic-gate  */
647c478bd9Sstevel@tonic-gate #define	EXIT_SVC_FAILURE	3
657c478bd9Sstevel@tonic-gate #define	EXIT_DEP_FAILURE	4
667c478bd9Sstevel@tonic-gate 
676c7c876cSJerry Jelinek #define	WALK_FLAGS	(SCF_WALK_UNIPARTIAL | SCF_WALK_MULTIPLE)
686c7c876cSJerry Jelinek 
697c478bd9Sstevel@tonic-gate /*
707c478bd9Sstevel@tonic-gate  * How long we will wait (in seconds) for a service to change state
717c478bd9Sstevel@tonic-gate  * before re-checking its dependencies.
727c478bd9Sstevel@tonic-gate  */
737c478bd9Sstevel@tonic-gate #define	WAIT_INTERVAL		3
747c478bd9Sstevel@tonic-gate 
7554d02241SBryan Cantrill #define	bad_error(func, err)						\
7654d02241SBryan Cantrill 	uu_panic("%s:%d: %s() failed with unexpected error %d.\n",	\
7754d02241SBryan Cantrill 	    __FILE__, __LINE__, (func), (err));
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate struct ht_elt {
807c478bd9Sstevel@tonic-gate 	struct ht_elt	*next;
817c478bd9Sstevel@tonic-gate 	boolean_t	active;
827c478bd9Sstevel@tonic-gate 	char		str[1];
837c478bd9Sstevel@tonic-gate };
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate 
868fff7887SJohn Levon /*
878fff7887SJohn Levon  * Callback data for enable/disable.
888fff7887SJohn Levon  */
898fff7887SJohn Levon #define	SET_ENABLED	0x1
908fff7887SJohn Levon #define	SET_TEMPORARY	0x2
918fff7887SJohn Levon #define	SET_RECURSIVE	0x4
928fff7887SJohn Levon 
938fff7887SJohn Levon typedef struct {
948fff7887SJohn Levon 	char ed_comment[SCF_COMMENT_MAX_LENGTH];
958fff7887SJohn Levon 	int ed_flags;
968fff7887SJohn Levon } enable_data_t;
978fff7887SJohn Levon 
988fff7887SJohn Levon 
997c478bd9Sstevel@tonic-gate scf_handle_t *h;
1007c478bd9Sstevel@tonic-gate ssize_t max_scf_fmri_sz;
1017c478bd9Sstevel@tonic-gate static const char *emsg_permission_denied;
1027c478bd9Sstevel@tonic-gate static const char *emsg_nomem;
1037c478bd9Sstevel@tonic-gate static const char *emsg_create_pg_perm_denied;
1047c478bd9Sstevel@tonic-gate static const char *emsg_pg_perm_denied;
1057c478bd9Sstevel@tonic-gate static const char *emsg_prop_perm_denied;
1067c478bd9Sstevel@tonic-gate static const char *emsg_no_service;
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate static int exit_status = 0;
1097c478bd9Sstevel@tonic-gate static int verbose = 0;
1107c478bd9Sstevel@tonic-gate static char *scratch_fmri;
111702a871aSJerry Jelinek static char *g_zonename = NULL;
11237b40227SJerry Jelinek static char svcstate[80];
11337b40227SJerry Jelinek static boolean_t svcsearch = B_FALSE;
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate static struct ht_elt **visited;
1167c478bd9Sstevel@tonic-gate 
1170b5c9250Shg void do_scfdie(int lineno) __NORETURN;
1180b5c9250Shg static void usage_milestone(void) __NORETURN;
119eb1a3463STruong Nguyen static void set_astring_prop(const char *, const char *, const char *,
120eb1a3463STruong Nguyen     uint32_t, const char *, const char *);
121702a871aSJerry Jelinek static void pr_warn(const char *format, ...);
1220b5c9250Shg 
1237c478bd9Sstevel@tonic-gate /*
1247c478bd9Sstevel@tonic-gate  * Visitors from synch.c, needed for enable -s and disable -s.
1257c478bd9Sstevel@tonic-gate  */
1267c478bd9Sstevel@tonic-gate extern int is_enabled(scf_instance_t *);
1277c478bd9Sstevel@tonic-gate extern int has_potential(scf_instance_t *, int);
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate void
do_scfdie(int lineno)1307c478bd9Sstevel@tonic-gate do_scfdie(int lineno)
1317c478bd9Sstevel@tonic-gate {
1327c478bd9Sstevel@tonic-gate 	scf_error_t err;
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate 	switch (err = scf_error()) {
1357c478bd9Sstevel@tonic-gate 	case SCF_ERROR_CONNECTION_BROKEN:
1367c478bd9Sstevel@tonic-gate 		uu_die(gettext("Connection to repository server broken.  "
1377c478bd9Sstevel@tonic-gate 		    "Exiting.\n"));
1387c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate 	case SCF_ERROR_BACKEND_READONLY:
1417c478bd9Sstevel@tonic-gate 		uu_die(gettext("Repository is read-only.  Exiting.\n"));
1427c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate 	default:
1457c478bd9Sstevel@tonic-gate #ifdef NDEBUG
1467c478bd9Sstevel@tonic-gate 		uu_die(gettext("Unexpected libscf error: %s.  Exiting.\n"),
1477c478bd9Sstevel@tonic-gate 		    scf_strerror(err));
1487c478bd9Sstevel@tonic-gate #else
1497c478bd9Sstevel@tonic-gate 		uu_die("Unexpected libscf error on line %d: %s.\n", lineno,
1507c478bd9Sstevel@tonic-gate 		    scf_strerror(err));
1517c478bd9Sstevel@tonic-gate #endif
1527c478bd9Sstevel@tonic-gate 	}
1537c478bd9Sstevel@tonic-gate }
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate #define	scfdie()	do_scfdie(__LINE__)
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate static void
usage()1587c478bd9Sstevel@tonic-gate usage()
1597c478bd9Sstevel@tonic-gate {
1607c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(
16137b40227SJerry Jelinek 	"Usage: %1$s [-S <state>] [-v] [-Z | -z zone] [cmd [args ... ]]\n\n"
16237b40227SJerry Jelinek 	"\t%1$s enable [-rst] [<service> ...]\t- enable and online service(s)\n"
1638fff7887SJohn Levon 	"\t%1$s disable [-c comment] [-st] [<service> ...] - disable "
16437b40227SJerry Jelinek 	"service(s)\n"
165ac0324d2SJerry Jelinek 	"\t%1$s restart [-d] [<service> ...]\t- restart specified service(s)\n"
16637b40227SJerry Jelinek 	"\t%1$s refresh [<service> ...]\t\t- re-read service configuration\n"
16737b40227SJerry Jelinek 	"\t%1$s mark [-It] <state> [<service> ...] - set maintenance state\n"
16837b40227SJerry Jelinek 	"\t%1$s clear [<service> ...]\t\t- clear maintenance state\n"
1697c478bd9Sstevel@tonic-gate 	"\t%1$s milestone [-d] <milestone>\t- advance to a service milestone\n"
1707c478bd9Sstevel@tonic-gate 	"\n\t"
171bbf21555SRichard Lowe 	"Services can be specified using an FMRI, abbreviation, or fnmatch(7)\n"
1727c478bd9Sstevel@tonic-gate 	"\tpattern, as shown in these examples for svc:/network/smtp:sendmail\n"
1737c478bd9Sstevel@tonic-gate 	"\n"
1747c478bd9Sstevel@tonic-gate 	"\t%1$s <cmd> svc:/network/smtp:sendmail\n"
1757c478bd9Sstevel@tonic-gate 	"\t%1$s <cmd> network/smtp:sendmail\n"
1767c478bd9Sstevel@tonic-gate 	"\t%1$s <cmd> network/*mail\n"
1777c478bd9Sstevel@tonic-gate 	"\t%1$s <cmd> network/smtp\n"
1787c478bd9Sstevel@tonic-gate 	"\t%1$s <cmd> smtp:sendmail\n"
1797c478bd9Sstevel@tonic-gate 	"\t%1$s <cmd> smtp\n"
1807c478bd9Sstevel@tonic-gate 	"\t%1$s <cmd> sendmail\n"), uu_getpname());
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate 	exit(UU_EXIT_USAGE);
1837c478bd9Sstevel@tonic-gate }
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate /*
1877c478bd9Sstevel@tonic-gate  * FMRI hash table for recursive enable.
1887c478bd9Sstevel@tonic-gate  */
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate static uint32_t
hash_fmri(const char * str)1917c478bd9Sstevel@tonic-gate hash_fmri(const char *str)
1927c478bd9Sstevel@tonic-gate {
1937c478bd9Sstevel@tonic-gate 	uint32_t h = 0, g;
1947c478bd9Sstevel@tonic-gate 	const char *p;
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate 	/* Generic hash function from uts/common/os/modhash.c . */
1977c478bd9Sstevel@tonic-gate 	for (p = str; *p != '\0'; ++p) {
1987c478bd9Sstevel@tonic-gate 		h = (h << 4) + *p;
1997c478bd9Sstevel@tonic-gate 		if ((g = (h & 0xf0000000)) != 0) {
2007c478bd9Sstevel@tonic-gate 			h ^= (g >> 24);
2017c478bd9Sstevel@tonic-gate 			h ^= g;
2027c478bd9Sstevel@tonic-gate 		}
2037c478bd9Sstevel@tonic-gate 	}
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 	return (h);
2067c478bd9Sstevel@tonic-gate }
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate /*
2097c478bd9Sstevel@tonic-gate  * Return 1 if str has been visited, 0 if it has not, and -1 if memory could not
2107c478bd9Sstevel@tonic-gate  * be allocated.
2117c478bd9Sstevel@tonic-gate  */
2127c478bd9Sstevel@tonic-gate static int
visited_find_or_add(const char * str,struct ht_elt ** hep)2137c478bd9Sstevel@tonic-gate visited_find_or_add(const char *str, struct ht_elt **hep)
2147c478bd9Sstevel@tonic-gate {
2157c478bd9Sstevel@tonic-gate 	uint32_t h;
2167c478bd9Sstevel@tonic-gate 	uint_t i;
2177c478bd9Sstevel@tonic-gate 	struct ht_elt *he;
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 	h = hash_fmri(str);
2207c478bd9Sstevel@tonic-gate 	i = h & (HT_BUCKETS - 1);
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate 	for (he = visited[i]; he != NULL; he = he->next) {
2237c478bd9Sstevel@tonic-gate 		if (strcmp(he->str, str) == 0) {
2247c478bd9Sstevel@tonic-gate 			if (hep)
2257c478bd9Sstevel@tonic-gate 				*hep = he;
2267c478bd9Sstevel@tonic-gate 			return (1);
2277c478bd9Sstevel@tonic-gate 		}
2287c478bd9Sstevel@tonic-gate 	}
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate 	he = malloc(offsetof(struct ht_elt, str) + strlen(str) + 1);
2317c478bd9Sstevel@tonic-gate 	if (he == NULL)
2327c478bd9Sstevel@tonic-gate 		return (-1);
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate 	(void) strcpy(he->str, str);
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate 	he->next = visited[i];
2377c478bd9Sstevel@tonic-gate 	visited[i] = he;
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate 	if (hep)
2407c478bd9Sstevel@tonic-gate 		*hep = he;
2417c478bd9Sstevel@tonic-gate 	return (0);
2427c478bd9Sstevel@tonic-gate }
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate /*
2467c478bd9Sstevel@tonic-gate  * Returns 0, ECANCELED if pg is deleted, ENOENT if propname doesn't exist,
2477c478bd9Sstevel@tonic-gate  * EINVAL if the property is not of boolean type or has no values, and E2BIG
2487c478bd9Sstevel@tonic-gate  * if it has more than one value.  *bp is set if 0 or E2BIG is returned.
2497c478bd9Sstevel@tonic-gate  */
2507c478bd9Sstevel@tonic-gate int
get_bool_prop(scf_propertygroup_t * pg,const char * propname,uint8_t * bp)2517c478bd9Sstevel@tonic-gate get_bool_prop(scf_propertygroup_t *pg, const char *propname, uint8_t *bp)
2527c478bd9Sstevel@tonic-gate {
2537c478bd9Sstevel@tonic-gate 	scf_property_t *prop;
2547c478bd9Sstevel@tonic-gate 	scf_value_t *val;
2557c478bd9Sstevel@tonic-gate 	int ret;
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 	if ((prop = scf_property_create(h)) == NULL ||
2587c478bd9Sstevel@tonic-gate 	    (val = scf_value_create(h)) == NULL)
2597c478bd9Sstevel@tonic-gate 		scfdie();
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate 	if (scf_pg_get_property(pg, propname, prop) != 0) {
2627c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
2637c478bd9Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
2647c478bd9Sstevel@tonic-gate 			ret = ECANCELED;
2657c478bd9Sstevel@tonic-gate 			goto out;
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
2687c478bd9Sstevel@tonic-gate 			ret = ENOENT;
2697c478bd9Sstevel@tonic-gate 			goto out;
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
2727c478bd9Sstevel@tonic-gate 			assert(0);
2737c478bd9Sstevel@tonic-gate 			abort();
2747c478bd9Sstevel@tonic-gate 			/* NOTREACHED */
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate 		default:
2777c478bd9Sstevel@tonic-gate 			scfdie();
2787c478bd9Sstevel@tonic-gate 		}
2797c478bd9Sstevel@tonic-gate 	}
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 	if (scf_property_get_value(prop, val) == 0) {
2827c478bd9Sstevel@tonic-gate 		ret = 0;
2837c478bd9Sstevel@tonic-gate 	} else {
2847c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
2857c478bd9Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
2867c478bd9Sstevel@tonic-gate 			ret = ENOENT;
2877c478bd9Sstevel@tonic-gate 			goto out;
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
2907c478bd9Sstevel@tonic-gate 			ret = EINVAL;
2917c478bd9Sstevel@tonic-gate 			goto out;
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate 		case SCF_ERROR_CONSTRAINT_VIOLATED:
2947c478bd9Sstevel@tonic-gate 			ret = E2BIG;
2957c478bd9Sstevel@tonic-gate 			break;
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
2987c478bd9Sstevel@tonic-gate 			assert(0);
2997c478bd9Sstevel@tonic-gate 			abort();
3007c478bd9Sstevel@tonic-gate 			/* NOTREACHED */
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate 		default:
3037c478bd9Sstevel@tonic-gate 			scfdie();
3047c478bd9Sstevel@tonic-gate 		}
3057c478bd9Sstevel@tonic-gate 	}
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 	if (scf_value_get_boolean(val, bp) != 0) {
3087c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_TYPE_MISMATCH)
3097c478bd9Sstevel@tonic-gate 			scfdie();
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate 		ret = EINVAL;
3127c478bd9Sstevel@tonic-gate 		goto out;
3137c478bd9Sstevel@tonic-gate 	}
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate out:
3167c478bd9Sstevel@tonic-gate 	scf_value_destroy(val);
3177c478bd9Sstevel@tonic-gate 	scf_property_destroy(prop);
3187c478bd9Sstevel@tonic-gate 	return (ret);
3197c478bd9Sstevel@tonic-gate }
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate /*
3227c478bd9Sstevel@tonic-gate  * Returns 0, EPERM, or EROFS.
3237c478bd9Sstevel@tonic-gate  */
3247c478bd9Sstevel@tonic-gate static int
set_bool_prop(scf_propertygroup_t * pg,const char * propname,boolean_t b)3257c478bd9Sstevel@tonic-gate set_bool_prop(scf_propertygroup_t *pg, const char *propname, boolean_t b)
3267c478bd9Sstevel@tonic-gate {
3277c478bd9Sstevel@tonic-gate 	scf_value_t *v;
3287c478bd9Sstevel@tonic-gate 	scf_transaction_t *tx;
3297c478bd9Sstevel@tonic-gate 	scf_transaction_entry_t *ent;
3307c478bd9Sstevel@tonic-gate 	int ret = 0, r;
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate 	if ((tx = scf_transaction_create(h)) == NULL ||
3337c478bd9Sstevel@tonic-gate 	    (ent = scf_entry_create(h)) == NULL ||
3347c478bd9Sstevel@tonic-gate 	    (v = scf_value_create(h)) == NULL)
3357c478bd9Sstevel@tonic-gate 		scfdie();
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate 	scf_value_set_boolean(v, b);
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 	for (;;) {
3407c478bd9Sstevel@tonic-gate 		if (scf_transaction_start(tx, pg) == -1) {
3417c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
3427c478bd9Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
3437c478bd9Sstevel@tonic-gate 				ret = EPERM;
3447c478bd9Sstevel@tonic-gate 				goto out;
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_READONLY:
3477c478bd9Sstevel@tonic-gate 				ret = EROFS;
3487c478bd9Sstevel@tonic-gate 				goto out;
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 			default:
3517c478bd9Sstevel@tonic-gate 				scfdie();
3527c478bd9Sstevel@tonic-gate 			}
3537c478bd9Sstevel@tonic-gate 		}
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate 		if (scf_transaction_property_change_type(tx, ent, propname,
3567c478bd9Sstevel@tonic-gate 		    SCF_TYPE_BOOLEAN) != 0) {
3577c478bd9Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_NOT_FOUND)
3587c478bd9Sstevel@tonic-gate 				scfdie();
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate 			if (scf_transaction_property_new(tx, ent, propname,
3617c478bd9Sstevel@tonic-gate 			    SCF_TYPE_BOOLEAN) != 0)
3627c478bd9Sstevel@tonic-gate 				scfdie();
3637c478bd9Sstevel@tonic-gate 		}
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate 		r = scf_entry_add_value(ent, v);
3667c478bd9Sstevel@tonic-gate 		assert(r == 0);
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate 		r = scf_transaction_commit(tx);
3697c478bd9Sstevel@tonic-gate 		if (r == 1)
3707c478bd9Sstevel@tonic-gate 			break;
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate 		scf_transaction_reset(tx);
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate 		if (r != 0) {
3757c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
3767c478bd9Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
3777c478bd9Sstevel@tonic-gate 				ret = EPERM;
3787c478bd9Sstevel@tonic-gate 				goto out;
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_READONLY:
3817c478bd9Sstevel@tonic-gate 				ret = EROFS;
3827c478bd9Sstevel@tonic-gate 				goto out;
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate 			default:
3857c478bd9Sstevel@tonic-gate 				scfdie();
3867c478bd9Sstevel@tonic-gate 			}
3877c478bd9Sstevel@tonic-gate 		}
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate 		if (scf_pg_update(pg) == -1)
3907c478bd9Sstevel@tonic-gate 			scfdie();
3917c478bd9Sstevel@tonic-gate 	}
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate out:
3947c478bd9Sstevel@tonic-gate 	scf_transaction_destroy(tx);
3957c478bd9Sstevel@tonic-gate 	scf_entry_destroy(ent);
3967c478bd9Sstevel@tonic-gate 	scf_value_destroy(v);
3977c478bd9Sstevel@tonic-gate 	return (ret);
3987c478bd9Sstevel@tonic-gate }
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate /*
4017c478bd9Sstevel@tonic-gate  * Gets the single astring value of the propname property of pg.  prop & v are
4027c478bd9Sstevel@tonic-gate  * scratch space.  Returns the length of the string on success or
4037c478bd9Sstevel@tonic-gate  *   -ENOENT - pg has no property named propname
4047c478bd9Sstevel@tonic-gate  *   -E2BIG - property has no values or multiple values
4057c478bd9Sstevel@tonic-gate  *   -EINVAL - property type is not compatible with astring
4067c478bd9Sstevel@tonic-gate  */
4077c478bd9Sstevel@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)4087c478bd9Sstevel@tonic-gate get_astring_prop(const scf_propertygroup_t *pg, const char *propname,
4097c478bd9Sstevel@tonic-gate     scf_property_t *prop, scf_value_t *v, char *buf, size_t bufsz)
4107c478bd9Sstevel@tonic-gate {
4117c478bd9Sstevel@tonic-gate 	ssize_t sz;
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate 	if (scf_pg_get_property(pg, propname, prop) != 0) {
4147c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND)
4157c478bd9Sstevel@tonic-gate 			scfdie();
4167c478bd9Sstevel@tonic-gate 
4177c478bd9Sstevel@tonic-gate 		return (-ENOENT);
4187c478bd9Sstevel@tonic-gate 	}
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate 	if (scf_property_get_value(prop, v) != 0) {
4217c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
4227c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
4237c478bd9Sstevel@tonic-gate 		case SCF_ERROR_CONSTRAINT_VIOLATED:
4247c478bd9Sstevel@tonic-gate 			return (-E2BIG);
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate 		default:
4277c478bd9Sstevel@tonic-gate 			scfdie();
4287c478bd9Sstevel@tonic-gate 		}
4297c478bd9Sstevel@tonic-gate 	}
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate 	sz = scf_value_get_astring(v, buf, bufsz);
4327c478bd9Sstevel@tonic-gate 	if (sz < 0) {
4337c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_TYPE_MISMATCH)
4347c478bd9Sstevel@tonic-gate 			scfdie();
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate 		return (-EINVAL);
4377c478bd9Sstevel@tonic-gate 	}
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate 	return (sz);
4407c478bd9Sstevel@tonic-gate }
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate /*
443eb1a3463STruong Nguyen  * Returns 0 or EPERM.
4447c478bd9Sstevel@tonic-gate  */
4457c478bd9Sstevel@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)446eb1a3463STruong Nguyen pg_get_or_add(const scf_instance_t *inst, const char *pgname,
447eb1a3463STruong Nguyen     const char *pgtype, uint32_t pgflags, scf_propertygroup_t *pg)
4487c478bd9Sstevel@tonic-gate {
449eb1a3463STruong Nguyen again:
450eb1a3463STruong Nguyen 	if (scf_instance_get_pg(inst, pgname, pg) == 0)
451eb1a3463STruong Nguyen 		return (0);
4527c478bd9Sstevel@tonic-gate 
453eb1a3463STruong Nguyen 	if (scf_error() != SCF_ERROR_NOT_FOUND)
4547c478bd9Sstevel@tonic-gate 		scfdie();
4557c478bd9Sstevel@tonic-gate 
456eb1a3463STruong Nguyen 	if (scf_instance_add_pg(inst, pgname, pgtype, pgflags, pg) == 0)
457eb1a3463STruong Nguyen 		return (0);
4587c478bd9Sstevel@tonic-gate 
459eb1a3463STruong Nguyen 	switch (scf_error()) {
460eb1a3463STruong Nguyen 	case SCF_ERROR_EXISTS:
461eb1a3463STruong Nguyen 		goto again;
4627c478bd9Sstevel@tonic-gate 
463eb1a3463STruong Nguyen 	case SCF_ERROR_PERMISSION_DENIED:
464eb1a3463STruong Nguyen 		return (EPERM);
4657c478bd9Sstevel@tonic-gate 
466eb1a3463STruong Nguyen 	default:
467eb1a3463STruong Nguyen 		scfdie();
468eb1a3463STruong Nguyen 		/* NOTREACHED */
469eb1a3463STruong Nguyen 	}
470eb1a3463STruong Nguyen }
4717c478bd9Sstevel@tonic-gate 
472eb1a3463STruong Nguyen static int
my_ct_name(char * out,size_t len)473eb1a3463STruong Nguyen my_ct_name(char *out, size_t len)
474eb1a3463STruong Nguyen {
475eb1a3463STruong Nguyen 	ct_stathdl_t st;
476eb1a3463STruong Nguyen 	char *ct_fmri;
477eb1a3463STruong Nguyen 	ctid_t ct;
478eb1a3463STruong Nguyen 	int fd, errno, ret;
4797c478bd9Sstevel@tonic-gate 
480eb1a3463STruong Nguyen 	if ((ct = getctid()) == -1)
481eb1a3463STruong Nguyen 		uu_die(gettext("Could not get contract id for process"));
4827c478bd9Sstevel@tonic-gate 
483eb1a3463STruong Nguyen 	fd = contract_open(ct, "process", "status", O_RDONLY);
4847c478bd9Sstevel@tonic-gate 
485eb1a3463STruong Nguyen 	if ((errno = ct_status_read(fd, CTD_ALL, &st)) != 0)
486eb1a3463STruong Nguyen 		uu_warn(gettext("Could not read status of contract "
487eb1a3463STruong Nguyen 		    "%ld: %s.\n"), ct, strerror(errno));
4887c478bd9Sstevel@tonic-gate 
489eb1a3463STruong Nguyen 	if ((errno = ct_pr_status_get_svc_fmri(st, &ct_fmri)) != 0)
490eb1a3463STruong Nguyen 		uu_warn(gettext("Could not get svc_fmri for contract "
491eb1a3463STruong Nguyen 		    "%ld: %s.\n"), ct, strerror(errno));
4927c478bd9Sstevel@tonic-gate 
493eb1a3463STruong Nguyen 	ret = strlcpy(out, ct_fmri, len);
4947c478bd9Sstevel@tonic-gate 
495eb1a3463STruong Nguyen 	ct_status_free(st);
496eb1a3463STruong Nguyen 	(void) close(fd);
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate 	return (ret);
4997c478bd9Sstevel@tonic-gate }
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate /*
502eb1a3463STruong Nguyen  * Set auxiliary_tty and auxiliary_fmri properties in restarter_actions pg to
503eb1a3463STruong Nguyen  * communicate whether the action is requested from a tty and the fmri of the
504eb1a3463STruong Nguyen  * responsible process.
505e8f5b3f5STruong Nguyen  *
506e8f5b3f5STruong Nguyen  * Returns 0, EPERM, or EROFS
5077c478bd9Sstevel@tonic-gate  */
5087c478bd9Sstevel@tonic-gate static int
restarter_setup(const char * fmri,const scf_instance_t * inst)509eb1a3463STruong Nguyen restarter_setup(const char *fmri, const scf_instance_t *inst)
5107c478bd9Sstevel@tonic-gate {
511eb1a3463STruong Nguyen 	boolean_t b = B_FALSE;
512eb1a3463STruong Nguyen 	scf_propertygroup_t *pg = NULL;
513e8f5b3f5STruong Nguyen 	int ret = 0;
5147c478bd9Sstevel@tonic-gate 
515eb1a3463STruong Nguyen 	if ((pg = scf_pg_create(h)) == NULL)
5167c478bd9Sstevel@tonic-gate 		scfdie();
5177c478bd9Sstevel@tonic-gate 
518eb1a3463STruong Nguyen 	if (pg_get_or_add(inst, SCF_PG_RESTARTER_ACTIONS,
519eb1a3463STruong Nguyen 	    SCF_PG_RESTARTER_ACTIONS_TYPE, SCF_PG_RESTARTER_ACTIONS_FLAGS,
520e8f5b3f5STruong Nguyen 	    pg) == EPERM) {
521e8f5b3f5STruong Nguyen 		if (!verbose)
522e8f5b3f5STruong Nguyen 			uu_warn(emsg_permission_denied, fmri);
523e8f5b3f5STruong Nguyen 		else
524e8f5b3f5STruong Nguyen 			uu_warn(emsg_create_pg_perm_denied, fmri,
525e8f5b3f5STruong Nguyen 			    SCF_PG_RESTARTER_ACTIONS);
526e8f5b3f5STruong Nguyen 
527e8f5b3f5STruong Nguyen 		ret = EPERM;
528e8f5b3f5STruong Nguyen 		goto out;
529e8f5b3f5STruong Nguyen 	}
5307c478bd9Sstevel@tonic-gate 
531eb1a3463STruong Nguyen 	/* Set auxiliary_tty property */
532eb1a3463STruong Nguyen 	if (isatty(STDIN_FILENO))
533eb1a3463STruong Nguyen 		b = B_TRUE;
5347c478bd9Sstevel@tonic-gate 
535eb1a3463STruong Nguyen 	/* Create and set state to disabled */
53650c9b2feSToomas Soome 	switch (set_bool_prop(pg, SCF_PROPERTY_AUX_TTY, b)) {
537eb1a3463STruong Nguyen 	case 0:
538eb1a3463STruong Nguyen 		break;
539eb1a3463STruong Nguyen 
540eb1a3463STruong Nguyen 	case EPERM:
541e8f5b3f5STruong Nguyen 		if (!verbose)
542e8f5b3f5STruong Nguyen 			uu_warn(emsg_permission_denied, fmri);
543e8f5b3f5STruong Nguyen 		else
544e8f5b3f5STruong Nguyen 			uu_warn(emsg_prop_perm_denied, fmri,
545e8f5b3f5STruong Nguyen 			    SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_AUX_TTY);
546e8f5b3f5STruong Nguyen 
547e8f5b3f5STruong Nguyen 		ret = EPERM;
548e8f5b3f5STruong Nguyen 		goto out;
549e8f5b3f5STruong Nguyen 		/* NOTREACHED */
550eb1a3463STruong Nguyen 
551eb1a3463STruong Nguyen 	case EROFS:
552e8f5b3f5STruong Nguyen 		/* Shouldn't happen, but it can. */
553e8f5b3f5STruong Nguyen 		if (!verbose)
554e8f5b3f5STruong Nguyen 			uu_warn(gettext("%s: Repository read-only.\n"), fmri);
555e8f5b3f5STruong Nguyen 		else
556e8f5b3f5STruong Nguyen 			uu_warn(gettext("%s: Could not set %s/%s "
557e8f5b3f5STruong Nguyen 			    "(repository read-only).\n"), fmri,
558e8f5b3f5STruong Nguyen 			    SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_AUX_TTY);
559e8f5b3f5STruong Nguyen 
560e8f5b3f5STruong Nguyen 		ret = EROFS;
561e8f5b3f5STruong Nguyen 		goto out;
562e8f5b3f5STruong Nguyen 		/* NOTREACHED */
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate 	default:
5657c478bd9Sstevel@tonic-gate 		scfdie();
5667c478bd9Sstevel@tonic-gate 	}
567eb1a3463STruong Nguyen 
568eb1a3463STruong Nguyen 	if (my_ct_name(scratch_fmri, max_scf_fmri_sz) > 0) {
569eb1a3463STruong Nguyen 		set_astring_prop(fmri, SCF_PG_RESTARTER_ACTIONS,
570eb1a3463STruong Nguyen 		    SCF_PG_RESTARTER_ACTIONS_TYPE,
571eb1a3463STruong Nguyen 		    SCF_PG_RESTARTER_ACTIONS_FLAGS,
572eb1a3463STruong Nguyen 		    SCF_PROPERTY_AUX_FMRI, scratch_fmri);
573eb1a3463STruong Nguyen 	} else {
574eb1a3463STruong Nguyen 		uu_warn(gettext("%s: Could not set %s/%s: "
575eb1a3463STruong Nguyen 		    "my_ct_name failed.\n"), fmri,
576eb1a3463STruong Nguyen 		    SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_AUX_FMRI);
577eb1a3463STruong Nguyen 	}
578eb1a3463STruong Nguyen 
579e8f5b3f5STruong Nguyen out:
580eb1a3463STruong Nguyen 	scf_pg_destroy(pg);
581e8f5b3f5STruong Nguyen 	return (ret);
5827c478bd9Sstevel@tonic-gate }
5837c478bd9Sstevel@tonic-gate 
5848fff7887SJohn Levon static int
delete_prop(const char * fmri,scf_instance_t * inst,const char * pgname,const char * propname)5858fff7887SJohn Levon delete_prop(const char *fmri, scf_instance_t *inst, const char *pgname,
5868fff7887SJohn Levon     const char *propname)
5878fff7887SJohn Levon {
5888fff7887SJohn Levon 	int r = scf_instance_delete_prop(inst, pgname, propname);
5898fff7887SJohn Levon 
5908fff7887SJohn Levon 	switch (r) {
5918fff7887SJohn Levon 	case 0:
5928fff7887SJohn Levon 		break;
5938fff7887SJohn Levon 
5948fff7887SJohn Levon 	case ECANCELED:
5958fff7887SJohn Levon 		uu_warn(emsg_no_service, fmri);
5968fff7887SJohn Levon 		break;
5978fff7887SJohn Levon 
5988fff7887SJohn Levon 	case EACCES:
5998fff7887SJohn Levon 		uu_warn(gettext("Could not delete %s/%s "
6008fff7887SJohn Levon 		    "property of %s: backend access denied.\n"),
6018fff7887SJohn Levon 		    pgname, propname, fmri);
6028fff7887SJohn Levon 		break;
6038fff7887SJohn Levon 
6048fff7887SJohn Levon 	case EROFS:
6058fff7887SJohn Levon 		uu_warn(gettext("Could not delete %s/%s "
6068fff7887SJohn Levon 		    "property of %s: backend is read-only.\n"),
6078fff7887SJohn Levon 		    pgname, propname, fmri);
6088fff7887SJohn Levon 		break;
6098fff7887SJohn Levon 
6108fff7887SJohn Levon 	default:
6118fff7887SJohn Levon 		bad_error("scf_instance_delete_prop", r);
6128fff7887SJohn Levon 	}
6138fff7887SJohn Levon 
6148fff7887SJohn Levon 	return (r);
6158fff7887SJohn Levon }
6168fff7887SJohn Levon 
6178fff7887SJohn Levon /*
6188fff7887SJohn Levon  * Returns 0, EPERM, or EROFS.
6198fff7887SJohn Levon  */
6208fff7887SJohn Levon static int
set_enabled_props(scf_propertygroup_t * pg,enable_data_t * ed)6218fff7887SJohn Levon set_enabled_props(scf_propertygroup_t *pg, enable_data_t *ed)
6228fff7887SJohn Levon {
6238fff7887SJohn Levon 	scf_transaction_entry_t *ent1;
6248fff7887SJohn Levon 	scf_transaction_entry_t *ent2;
6258fff7887SJohn Levon 	scf_transaction_t *tx;
6268fff7887SJohn Levon 	scf_value_t *v2;
6278fff7887SJohn Levon 	scf_value_t *v1;
6288fff7887SJohn Levon 	int ret = 0, r;
6298fff7887SJohn Levon 
6308fff7887SJohn Levon 	if ((tx = scf_transaction_create(h)) == NULL ||
6318fff7887SJohn Levon 	    (ent1 = scf_entry_create(h)) == NULL ||
6328fff7887SJohn Levon 	    (ent2 = scf_entry_create(h)) == NULL ||
6338fff7887SJohn Levon 	    (v1 = scf_value_create(h)) == NULL ||
6348fff7887SJohn Levon 	    (v2 = scf_value_create(h)) == NULL)
6358fff7887SJohn Levon 		scfdie();
6368fff7887SJohn Levon 
6378fff7887SJohn Levon 	for (;;) {
6388fff7887SJohn Levon 		if (scf_transaction_start(tx, pg) == -1) {
6398fff7887SJohn Levon 			switch (scf_error()) {
6408fff7887SJohn Levon 			case SCF_ERROR_PERMISSION_DENIED:
6418fff7887SJohn Levon 				ret = EPERM;
6428fff7887SJohn Levon 				goto out;
6438fff7887SJohn Levon 
6448fff7887SJohn Levon 			case SCF_ERROR_BACKEND_READONLY:
6458fff7887SJohn Levon 				ret = EROFS;
6468fff7887SJohn Levon 				goto out;
6478fff7887SJohn Levon 
6488fff7887SJohn Levon 			default:
6498fff7887SJohn Levon 				scfdie();
6508fff7887SJohn Levon 			}
6518fff7887SJohn Levon 		}
6528fff7887SJohn Levon 
6538fff7887SJohn Levon 		if (scf_transaction_property_change_type(tx, ent1,
6548fff7887SJohn Levon 		    SCF_PROPERTY_ENABLED, SCF_TYPE_BOOLEAN) != 0) {
6558fff7887SJohn Levon 			if (scf_error() != SCF_ERROR_NOT_FOUND)
6568fff7887SJohn Levon 				scfdie();
6578fff7887SJohn Levon 
6588fff7887SJohn Levon 			if (scf_transaction_property_new(tx, ent1,
6598fff7887SJohn Levon 			    SCF_PROPERTY_ENABLED, SCF_TYPE_BOOLEAN) != 0)
6608fff7887SJohn Levon 				scfdie();
6618fff7887SJohn Levon 		}
6628fff7887SJohn Levon 
6638fff7887SJohn Levon 		scf_value_set_boolean(v1, !!(ed->ed_flags & SET_ENABLED));
6648fff7887SJohn Levon 
6658fff7887SJohn Levon 		r = scf_entry_add_value(ent1, v1);
6668fff7887SJohn Levon 		assert(r == 0);
6678fff7887SJohn Levon 
6688fff7887SJohn Levon 		if (scf_transaction_property_change_type(tx, ent2,
6698fff7887SJohn Levon 		    SCF_PROPERTY_COMMENT, SCF_TYPE_ASTRING) != 0) {
6708fff7887SJohn Levon 			if (scf_error() != SCF_ERROR_NOT_FOUND)
6718fff7887SJohn Levon 				scfdie();
6728fff7887SJohn Levon 
6738fff7887SJohn Levon 			if (scf_transaction_property_new(tx, ent2,
6748fff7887SJohn Levon 			    SCF_PROPERTY_COMMENT, SCF_TYPE_ASTRING) != 0)
6758fff7887SJohn Levon 				scfdie();
6768fff7887SJohn Levon 		}
6778fff7887SJohn Levon 
6788fff7887SJohn Levon 		if (scf_value_set_astring(v2, ed->ed_comment) != SCF_SUCCESS)
6798fff7887SJohn Levon 			scfdie();
6808fff7887SJohn Levon 
6818fff7887SJohn Levon 		if (scf_entry_add_value(ent2, v2) != SCF_SUCCESS)
6828fff7887SJohn Levon 			scfdie();
6838fff7887SJohn Levon 
6848fff7887SJohn Levon 		r = scf_transaction_commit(tx);
6858fff7887SJohn Levon 		if (r == 1)
6868fff7887SJohn Levon 			break;
6878fff7887SJohn Levon 
6888fff7887SJohn Levon 		scf_transaction_reset(tx);
6898fff7887SJohn Levon 
6908fff7887SJohn Levon 		if (r != 0) {
6918fff7887SJohn Levon 			switch (scf_error()) {
6928fff7887SJohn Levon 			case SCF_ERROR_PERMISSION_DENIED:
6938fff7887SJohn Levon 				ret = EPERM;
6948fff7887SJohn Levon 				goto out;
6958fff7887SJohn Levon 
6968fff7887SJohn Levon 			case SCF_ERROR_BACKEND_READONLY:
6978fff7887SJohn Levon 				ret = EROFS;
6988fff7887SJohn Levon 				goto out;
6998fff7887SJohn Levon 
7008fff7887SJohn Levon 			default:
7018fff7887SJohn Levon 				scfdie();
7028fff7887SJohn Levon 			}
7038fff7887SJohn Levon 		}
7048fff7887SJohn Levon 
7058fff7887SJohn Levon 		if (scf_pg_update(pg) == -1)
7068fff7887SJohn Levon 			scfdie();
7078fff7887SJohn Levon 	}
7088fff7887SJohn Levon 
7098fff7887SJohn Levon out:
7108fff7887SJohn Levon 	scf_transaction_destroy(tx);
7118fff7887SJohn Levon 	scf_entry_destroy(ent1);
7128fff7887SJohn Levon 	scf_entry_destroy(ent2);
7138fff7887SJohn Levon 	scf_value_destroy(v1);
7148fff7887SJohn Levon 	scf_value_destroy(v2);
7158fff7887SJohn Levon 	return (ret);
7168fff7887SJohn Levon }
7178fff7887SJohn Levon 
7187c478bd9Sstevel@tonic-gate /*
7198fff7887SJohn Levon  * Enable or disable an instance.  SET_TEMPORARY modifications apply to
7208fff7887SJohn Levon  * general_ovr/ property group.
7217c478bd9Sstevel@tonic-gate  */
7227c478bd9Sstevel@tonic-gate static void
set_inst_enabled(const char * fmri,scf_instance_t * inst,enable_data_t * ed)7238fff7887SJohn Levon set_inst_enabled(const char *fmri, scf_instance_t *inst, enable_data_t *ed)
7247c478bd9Sstevel@tonic-gate {
7257c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg;
7267c478bd9Sstevel@tonic-gate 	uint8_t b;
7277c478bd9Sstevel@tonic-gate 	const char *pgname = NULL;	/* For emsg_pg_perm_denied */
7287c478bd9Sstevel@tonic-gate 
7297c478bd9Sstevel@tonic-gate 	pg = scf_pg_create(h);
7307c478bd9Sstevel@tonic-gate 	if (pg == NULL)
7317c478bd9Sstevel@tonic-gate 		scfdie();
7327c478bd9Sstevel@tonic-gate 
733eb1a3463STruong Nguyen 	if (restarter_setup(fmri, inst))
734e8f5b3f5STruong Nguyen 		goto out;
735eb1a3463STruong Nguyen 
736fee38f6fStn 	/*
737fee38f6fStn 	 * An instance's configuration is incomplete if general/enabled
738fee38f6fStn 	 * doesn't exist. Create both the property group and property
739fee38f6fStn 	 * here if they don't exist.
740fee38f6fStn 	 */
741fee38f6fStn 	pgname = SCF_PG_GENERAL;
742fee38f6fStn 	if (pg_get_or_add(inst, pgname, SCF_PG_GENERAL_TYPE,
743fee38f6fStn 	    SCF_PG_GENERAL_FLAGS, pg) != 0)
744fee38f6fStn 		goto eperm;
745fee38f6fStn 
746fee38f6fStn 	if (get_bool_prop(pg, SCF_PROPERTY_ENABLED, &b) != 0) {
747fee38f6fStn 		/* Create and set state to disabled */
74850c9b2feSToomas Soome 		switch (set_bool_prop(pg, SCF_PROPERTY_ENABLED, B_FALSE)) {
749fee38f6fStn 		case 0:
750fee38f6fStn 			break;
751fee38f6fStn 
752fee38f6fStn 		case EPERM:
753fee38f6fStn 			goto eperm;
754fee38f6fStn 
755fee38f6fStn 		case EROFS:
756fee38f6fStn 			/* Shouldn't happen, but it can. */
757fee38f6fStn 			if (!verbose)
758fee38f6fStn 				uu_warn(gettext("%s: Repository read-only.\n"),
759fee38f6fStn 				    fmri);
760fee38f6fStn 			else
761fee38f6fStn 				uu_warn(gettext("%s: Could not set %s/%s "
762fee38f6fStn 				    "(repository read-only).\n"), fmri,
763fee38f6fStn 				    SCF_PG_GENERAL, SCF_PROPERTY_ENABLED);
764fee38f6fStn 			goto out;
765fee38f6fStn 
766fee38f6fStn 		default:
767fee38f6fStn 			assert(0);
768fee38f6fStn 			abort();
769fee38f6fStn 		}
770fee38f6fStn 	}
771fee38f6fStn 
7728fff7887SJohn Levon 	if (ed->ed_flags & SET_TEMPORARY) {
7737c478bd9Sstevel@tonic-gate 		pgname = SCF_PG_GENERAL_OVR;
7747c478bd9Sstevel@tonic-gate 		if (pg_get_or_add(inst, pgname, SCF_PG_GENERAL_OVR_TYPE,
7757c478bd9Sstevel@tonic-gate 		    SCF_PG_GENERAL_OVR_FLAGS, pg) != 0)
7767c478bd9Sstevel@tonic-gate 			goto eperm;
7777c478bd9Sstevel@tonic-gate 
7788fff7887SJohn Levon 		switch (set_enabled_props(pg, ed)) {
7797c478bd9Sstevel@tonic-gate 		case 0:
7807c478bd9Sstevel@tonic-gate 			break;
7817c478bd9Sstevel@tonic-gate 
7827c478bd9Sstevel@tonic-gate 		case EPERM:
7837c478bd9Sstevel@tonic-gate 			goto eperm;
7847c478bd9Sstevel@tonic-gate 
7857c478bd9Sstevel@tonic-gate 		case EROFS:
7867c478bd9Sstevel@tonic-gate 			/* Shouldn't happen, but it can. */
7877c478bd9Sstevel@tonic-gate 			if (!verbose)
7887c478bd9Sstevel@tonic-gate 				uu_warn(gettext("%s: Repository read-only.\n"),
7897c478bd9Sstevel@tonic-gate 				    fmri);
7907c478bd9Sstevel@tonic-gate 			else
7917c478bd9Sstevel@tonic-gate 				uu_warn(gettext("%s: Could not set %s/%s "
7927c478bd9Sstevel@tonic-gate 				    "(repository read-only).\n"), fmri,
7937c478bd9Sstevel@tonic-gate 				    SCF_PG_GENERAL_OVR, SCF_PROPERTY_ENABLED);
7947c478bd9Sstevel@tonic-gate 			goto out;
7957c478bd9Sstevel@tonic-gate 
7967c478bd9Sstevel@tonic-gate 		default:
7977c478bd9Sstevel@tonic-gate 			assert(0);
7987c478bd9Sstevel@tonic-gate 			abort();
7997c478bd9Sstevel@tonic-gate 		}
8007c478bd9Sstevel@tonic-gate 
8017c478bd9Sstevel@tonic-gate 		if (verbose)
8028fff7887SJohn Levon 			(void) printf((ed->ed_flags & SET_ENABLED) ?
8037c478bd9Sstevel@tonic-gate 			    gettext("%s temporarily enabled.\n") :
8047c478bd9Sstevel@tonic-gate 			    gettext("%s temporarily disabled.\n"), fmri);
8057c478bd9Sstevel@tonic-gate 	} else {
8067c478bd9Sstevel@tonic-gate again:
807fee38f6fStn 		/*
808fee38f6fStn 		 * Both pg and property should exist since we created
809fee38f6fStn 		 * them earlier. However, there's still a chance that
810fee38f6fStn 		 * someone may have deleted the property out from under
811fee38f6fStn 		 * us.
812fee38f6fStn 		 */
8137c478bd9Sstevel@tonic-gate 		if (pg_get_or_add(inst, pgname, SCF_PG_GENERAL_TYPE,
8147c478bd9Sstevel@tonic-gate 		    SCF_PG_GENERAL_FLAGS, pg) != 0)
8157c478bd9Sstevel@tonic-gate 			goto eperm;
8167c478bd9Sstevel@tonic-gate 
8178fff7887SJohn Levon 		switch (set_enabled_props(pg, ed)) {
8187c478bd9Sstevel@tonic-gate 		case 0:
8197c478bd9Sstevel@tonic-gate 			break;
8207c478bd9Sstevel@tonic-gate 
8217c478bd9Sstevel@tonic-gate 		case EPERM:
8227c478bd9Sstevel@tonic-gate 			goto eperm;
8237c478bd9Sstevel@tonic-gate 
8247c478bd9Sstevel@tonic-gate 		case EROFS:
8257c478bd9Sstevel@tonic-gate 			/*
8267c478bd9Sstevel@tonic-gate 			 * If general/enabled is already set the way we want,
8277c478bd9Sstevel@tonic-gate 			 * proceed.
8287c478bd9Sstevel@tonic-gate 			 */
8297c478bd9Sstevel@tonic-gate 			switch (get_bool_prop(pg, SCF_PROPERTY_ENABLED, &b)) {
8307c478bd9Sstevel@tonic-gate 			case 0:
8318fff7887SJohn Levon 				if (!(b) == !(ed->ed_flags & SET_ENABLED))
8327c478bd9Sstevel@tonic-gate 					break;
8337c478bd9Sstevel@tonic-gate 				/* FALLTHROUGH */
8347c478bd9Sstevel@tonic-gate 
8357c478bd9Sstevel@tonic-gate 			case ENOENT:
8367c478bd9Sstevel@tonic-gate 			case EINVAL:
8377c478bd9Sstevel@tonic-gate 			case E2BIG:
8387c478bd9Sstevel@tonic-gate 				if (!verbose)
8397c478bd9Sstevel@tonic-gate 					uu_warn(gettext("%s: Repository "
8407c478bd9Sstevel@tonic-gate 					    "read-only.\n"), fmri);
8417c478bd9Sstevel@tonic-gate 				else
8427c478bd9Sstevel@tonic-gate 					uu_warn(gettext("%s: Could not set "
8437c478bd9Sstevel@tonic-gate 					    "%s/%s (repository read-only).\n"),
8447c478bd9Sstevel@tonic-gate 					    fmri, SCF_PG_GENERAL,
8457c478bd9Sstevel@tonic-gate 					    SCF_PROPERTY_ENABLED);
8467c478bd9Sstevel@tonic-gate 				goto out;
8477c478bd9Sstevel@tonic-gate 
8487c478bd9Sstevel@tonic-gate 			case ECANCELED:
8497c478bd9Sstevel@tonic-gate 				goto again;
8507c478bd9Sstevel@tonic-gate 
8517c478bd9Sstevel@tonic-gate 			default:
8527c478bd9Sstevel@tonic-gate 				assert(0);
8537c478bd9Sstevel@tonic-gate 				abort();
8547c478bd9Sstevel@tonic-gate 			}
8557c478bd9Sstevel@tonic-gate 			break;
8567c478bd9Sstevel@tonic-gate 
8577c478bd9Sstevel@tonic-gate 		default:
8587c478bd9Sstevel@tonic-gate 			assert(0);
8597c478bd9Sstevel@tonic-gate 			abort();
8607c478bd9Sstevel@tonic-gate 		}
8617c478bd9Sstevel@tonic-gate 
8628fff7887SJohn Levon 		switch (delete_prop(fmri, inst, SCF_PG_GENERAL_OVR,
8638fff7887SJohn Levon 		    SCF_PROPERTY_ENABLED)) {
864eb1a3463STruong Nguyen 		case 0:
865eb1a3463STruong Nguyen 			break;
8667c478bd9Sstevel@tonic-gate 
867eb1a3463STruong Nguyen 		case EPERM:
868eb1a3463STruong Nguyen 			goto eperm;
8697c478bd9Sstevel@tonic-gate 
8708fff7887SJohn Levon 		default:
871eb1a3463STruong Nguyen 			goto out;
8728fff7887SJohn Levon 		}
8737c478bd9Sstevel@tonic-gate 
8748fff7887SJohn Levon 		switch (delete_prop(fmri, inst, SCF_PG_GENERAL_OVR,
8758fff7887SJohn Levon 		    SCF_PROPERTY_COMMENT)) {
8768fff7887SJohn Levon 		case 0:
8778fff7887SJohn Levon 			break;
8788fff7887SJohn Levon 
8798fff7887SJohn Levon 		case EPERM:
8808fff7887SJohn Levon 			goto eperm;
8817c478bd9Sstevel@tonic-gate 
882eb1a3463STruong Nguyen 		default:
8838fff7887SJohn Levon 			goto out;
8847c478bd9Sstevel@tonic-gate 		}
8857c478bd9Sstevel@tonic-gate 
8868fff7887SJohn Levon 		if (verbose) {
8878fff7887SJohn Levon 			(void) printf((ed->ed_flags & SET_ENABLED) ?
8888fff7887SJohn Levon 			    gettext("%s enabled.\n") :
8897c478bd9Sstevel@tonic-gate 			    gettext("%s disabled.\n"), fmri);
8908fff7887SJohn Levon 		}
8917c478bd9Sstevel@tonic-gate 	}
8927c478bd9Sstevel@tonic-gate 
8937c478bd9Sstevel@tonic-gate 	scf_pg_destroy(pg);
8947c478bd9Sstevel@tonic-gate 	return;
8957c478bd9Sstevel@tonic-gate 
8967c478bd9Sstevel@tonic-gate eperm:
8977c478bd9Sstevel@tonic-gate 	assert(pgname != NULL);
8987c478bd9Sstevel@tonic-gate 	if (!verbose)
8997c478bd9Sstevel@tonic-gate 		uu_warn(emsg_permission_denied, fmri);
9007c478bd9Sstevel@tonic-gate 	else
9017c478bd9Sstevel@tonic-gate 		uu_warn(emsg_pg_perm_denied, fmri, pgname);
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate out:
9047c478bd9Sstevel@tonic-gate 	scf_pg_destroy(pg);
9057c478bd9Sstevel@tonic-gate 	exit_status = 1;
9067c478bd9Sstevel@tonic-gate }
9077c478bd9Sstevel@tonic-gate 
9087c478bd9Sstevel@tonic-gate /*
9097c478bd9Sstevel@tonic-gate  * Set inst to the instance which corresponds to fmri.  If fmri identifies
9107c478bd9Sstevel@tonic-gate  * a service with a single instance, get that instance.
9117c478bd9Sstevel@tonic-gate  *
9127c478bd9Sstevel@tonic-gate  * Fails with
9137c478bd9Sstevel@tonic-gate  *   ENOTSUP - fmri has an unsupported scheme
9147c478bd9Sstevel@tonic-gate  *   EINVAL - fmri is invalid
9157c478bd9Sstevel@tonic-gate  *   ENOTDIR - fmri does not identify a service or instance
9167c478bd9Sstevel@tonic-gate  *   ENOENT - could not locate instance
9177c478bd9Sstevel@tonic-gate  *   E2BIG - fmri is a service with multiple instances (warning not printed)
9187c478bd9Sstevel@tonic-gate  */
9197c478bd9Sstevel@tonic-gate static int
get_inst_mult(const char * fmri,scf_instance_t * inst)9207c478bd9Sstevel@tonic-gate get_inst_mult(const char *fmri, scf_instance_t *inst)
9217c478bd9Sstevel@tonic-gate {
9227c478bd9Sstevel@tonic-gate 	char *cfmri;
9237c478bd9Sstevel@tonic-gate 	const char *svc_name, *inst_name, *pg_name;
9247c478bd9Sstevel@tonic-gate 	scf_service_t *svc;
9257c478bd9Sstevel@tonic-gate 	scf_instance_t *inst2;
9267c478bd9Sstevel@tonic-gate 	scf_iter_t *iter;
9277c478bd9Sstevel@tonic-gate 	int ret;
9287c478bd9Sstevel@tonic-gate 
9297c478bd9Sstevel@tonic-gate 	if (strncmp(fmri, "lrc:", sizeof ("lrc:") - 1) == 0) {
9307c478bd9Sstevel@tonic-gate 		uu_warn(gettext("FMRI \"%s\" is a legacy service.\n"), fmri);
9317c478bd9Sstevel@tonic-gate 		exit_status = 1;
9327c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
9337c478bd9Sstevel@tonic-gate 	}
9347c478bd9Sstevel@tonic-gate 
9357c478bd9Sstevel@tonic-gate 	cfmri = strdup(fmri);
9367c478bd9Sstevel@tonic-gate 	if (cfmri == NULL)
9377c478bd9Sstevel@tonic-gate 		uu_die(emsg_nomem);
9387c478bd9Sstevel@tonic-gate 
9397c478bd9Sstevel@tonic-gate 	if (scf_parse_svc_fmri(cfmri, NULL, &svc_name, &inst_name, &pg_name,
9407c478bd9Sstevel@tonic-gate 	    NULL) != SCF_SUCCESS) {
9417c478bd9Sstevel@tonic-gate 		free(cfmri);
9427c478bd9Sstevel@tonic-gate 		uu_warn(gettext("FMRI \"%s\" is invalid.\n"), fmri);
9437c478bd9Sstevel@tonic-gate 		exit_status = 1;
9447c478bd9Sstevel@tonic-gate 		return (EINVAL);
9457c478bd9Sstevel@tonic-gate 	}
9467c478bd9Sstevel@tonic-gate 
9477c478bd9Sstevel@tonic-gate 	free(cfmri);
9487c478bd9Sstevel@tonic-gate 
9497c478bd9Sstevel@tonic-gate 	if (svc_name == NULL || pg_name != NULL) {
9507c478bd9Sstevel@tonic-gate 		uu_warn(gettext(
9517c478bd9Sstevel@tonic-gate 		    "FMRI \"%s\" does not designate a service or instance.\n"),
9527c478bd9Sstevel@tonic-gate 		    fmri);
9537c478bd9Sstevel@tonic-gate 		exit_status = 1;
9547c478bd9Sstevel@tonic-gate 		return (ENOTDIR);
9557c478bd9Sstevel@tonic-gate 	}
9567c478bd9Sstevel@tonic-gate 
9577c478bd9Sstevel@tonic-gate 	if (inst_name != NULL) {
9587c478bd9Sstevel@tonic-gate 		if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
9597c478bd9Sstevel@tonic-gate 		    NULL, SCF_DECODE_FMRI_EXACT) == 0)
9607c478bd9Sstevel@tonic-gate 			return (0);
9617c478bd9Sstevel@tonic-gate 
9627c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND)
9637c478bd9Sstevel@tonic-gate 			scfdie();
9647c478bd9Sstevel@tonic-gate 
9657c478bd9Sstevel@tonic-gate 		uu_warn(gettext("No such instance \"%s\".\n"), fmri);
9667c478bd9Sstevel@tonic-gate 		exit_status = 1;
9677c478bd9Sstevel@tonic-gate 
9687c478bd9Sstevel@tonic-gate 		return (ENOENT);
9697c478bd9Sstevel@tonic-gate 	}
9707c478bd9Sstevel@tonic-gate 
9717c478bd9Sstevel@tonic-gate 	if ((svc = scf_service_create(h)) == NULL ||
9727c478bd9Sstevel@tonic-gate 	    (inst2 = scf_instance_create(h)) == NULL ||
9737c478bd9Sstevel@tonic-gate 	    (iter = scf_iter_create(h)) == NULL)
9747c478bd9Sstevel@tonic-gate 		scfdie();
9757c478bd9Sstevel@tonic-gate 
9767c478bd9Sstevel@tonic-gate 	if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL,
9777c478bd9Sstevel@tonic-gate 	    SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
9787c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND)
9797c478bd9Sstevel@tonic-gate 			scfdie();
9807c478bd9Sstevel@tonic-gate 
9817c478bd9Sstevel@tonic-gate 		uu_warn(emsg_no_service, fmri);
9827c478bd9Sstevel@tonic-gate 		exit_status = 1;
9837c478bd9Sstevel@tonic-gate 
9847c478bd9Sstevel@tonic-gate 		ret = ENOENT;
9857c478bd9Sstevel@tonic-gate 		goto out;
9867c478bd9Sstevel@tonic-gate 	}
9877c478bd9Sstevel@tonic-gate 
9887c478bd9Sstevel@tonic-gate 	/* If the service has only one child, use it. */
9897c478bd9Sstevel@tonic-gate 	if (scf_iter_service_instances(iter, svc) != SCF_SUCCESS)
9907c478bd9Sstevel@tonic-gate 		scfdie();
9917c478bd9Sstevel@tonic-gate 
9927c478bd9Sstevel@tonic-gate 	ret = scf_iter_next_instance(iter, inst);
9937c478bd9Sstevel@tonic-gate 	if (ret < 0)
9947c478bd9Sstevel@tonic-gate 		scfdie();
9957c478bd9Sstevel@tonic-gate 	if (ret != 1) {
9967c478bd9Sstevel@tonic-gate 		uu_warn(gettext("Service \"%s\" has no instances.\n"),
9977c478bd9Sstevel@tonic-gate 		    fmri);
9987c478bd9Sstevel@tonic-gate 		exit_status = 1;
9997c478bd9Sstevel@tonic-gate 		ret = ENOENT;
10007c478bd9Sstevel@tonic-gate 		goto out;
10017c478bd9Sstevel@tonic-gate 	}
10027c478bd9Sstevel@tonic-gate 
10037c478bd9Sstevel@tonic-gate 	ret = scf_iter_next_instance(iter, inst2);
10047c478bd9Sstevel@tonic-gate 	if (ret < 0)
10057c478bd9Sstevel@tonic-gate 		scfdie();
10067c478bd9Sstevel@tonic-gate 
10077c478bd9Sstevel@tonic-gate 	if (ret != 0) {
10087c478bd9Sstevel@tonic-gate 		ret = E2BIG;
10097c478bd9Sstevel@tonic-gate 		goto out;
10107c478bd9Sstevel@tonic-gate 	}
10117c478bd9Sstevel@tonic-gate 
10127c478bd9Sstevel@tonic-gate 	ret = 0;
10137c478bd9Sstevel@tonic-gate 
10147c478bd9Sstevel@tonic-gate out:
10157c478bd9Sstevel@tonic-gate 	scf_iter_destroy(iter);
10167c478bd9Sstevel@tonic-gate 	scf_instance_destroy(inst2);
10177c478bd9Sstevel@tonic-gate 	scf_service_destroy(svc);
10187c478bd9Sstevel@tonic-gate 	return (ret);
10197c478bd9Sstevel@tonic-gate }
10207c478bd9Sstevel@tonic-gate 
10217c478bd9Sstevel@tonic-gate /*
10227c478bd9Sstevel@tonic-gate  * Same as get_inst_mult(), but on E2BIG prints a warning and returns ENOENT.
10237c478bd9Sstevel@tonic-gate  */
10247c478bd9Sstevel@tonic-gate static int
get_inst(const char * fmri,scf_instance_t * inst)10257c478bd9Sstevel@tonic-gate get_inst(const char *fmri, scf_instance_t *inst)
10267c478bd9Sstevel@tonic-gate {
10277c478bd9Sstevel@tonic-gate 	int r;
10287c478bd9Sstevel@tonic-gate 
10297c478bd9Sstevel@tonic-gate 	r = get_inst_mult(fmri, inst);
10307c478bd9Sstevel@tonic-gate 	if (r != E2BIG)
10317c478bd9Sstevel@tonic-gate 		return (r);
10327c478bd9Sstevel@tonic-gate 
10337c478bd9Sstevel@tonic-gate 	uu_warn(gettext("operation on service %s is ambiguous; "
10347c478bd9Sstevel@tonic-gate 	    "instance specification needed.\n"), fmri);
10357c478bd9Sstevel@tonic-gate 	return (ENOENT);
10367c478bd9Sstevel@tonic-gate }
10377c478bd9Sstevel@tonic-gate 
10387c478bd9Sstevel@tonic-gate static char *
inst_get_fmri(const scf_instance_t * inst)10397c478bd9Sstevel@tonic-gate inst_get_fmri(const scf_instance_t *inst)
10407c478bd9Sstevel@tonic-gate {
10417c478bd9Sstevel@tonic-gate 	ssize_t sz;
10427c478bd9Sstevel@tonic-gate 
10437c478bd9Sstevel@tonic-gate 	sz = scf_instance_to_fmri(inst, scratch_fmri, max_scf_fmri_sz);
10447c478bd9Sstevel@tonic-gate 	if (sz < 0)
10457c478bd9Sstevel@tonic-gate 		scfdie();
10467c478bd9Sstevel@tonic-gate 	if (sz >= max_scf_fmri_sz)
10477c478bd9Sstevel@tonic-gate 		uu_die(gettext("scf_instance_to_fmri() returned unexpectedly "
10487c478bd9Sstevel@tonic-gate 		    "long value.\n"));
10497c478bd9Sstevel@tonic-gate 
10507c478bd9Sstevel@tonic-gate 	return (scratch_fmri);
10517c478bd9Sstevel@tonic-gate }
10527c478bd9Sstevel@tonic-gate 
10537c478bd9Sstevel@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)10547c478bd9Sstevel@tonic-gate dep_get_astring(const char *fmri, const char *pgname,
10557c478bd9Sstevel@tonic-gate     const scf_propertygroup_t *pg, const char *propname, scf_property_t *prop,
10567c478bd9Sstevel@tonic-gate     scf_value_t *v, char *buf, size_t bufsz)
10577c478bd9Sstevel@tonic-gate {
10587c478bd9Sstevel@tonic-gate 	ssize_t sz;
10597c478bd9Sstevel@tonic-gate 
10607c478bd9Sstevel@tonic-gate 	sz = get_astring_prop(pg, propname, prop, v, buf, bufsz);
10617c478bd9Sstevel@tonic-gate 	if (sz >= 0)
10627c478bd9Sstevel@tonic-gate 		return (sz);
10637c478bd9Sstevel@tonic-gate 
10647c478bd9Sstevel@tonic-gate 	switch (-sz) {
10657c478bd9Sstevel@tonic-gate 	case ENOENT:
10667c478bd9Sstevel@tonic-gate 		uu_warn(gettext("\"%s\" is misconfigured (\"%s\" dependency "
10677c478bd9Sstevel@tonic-gate 		    "lacks \"%s\" property.)\n"), fmri, pgname, propname);
10687c478bd9Sstevel@tonic-gate 		return (-1);
10697c478bd9Sstevel@tonic-gate 
10707c478bd9Sstevel@tonic-gate 	case E2BIG:
10717c478bd9Sstevel@tonic-gate 		uu_warn(gettext("\"%s\" is misconfigured (\"%s/%s\" property "
10727c478bd9Sstevel@tonic-gate 		    "is not single-valued.)\n"), fmri, pgname, propname);
10737c478bd9Sstevel@tonic-gate 		return (-1);
10747c478bd9Sstevel@tonic-gate 
10757c478bd9Sstevel@tonic-gate 	case EINVAL:
10767c478bd9Sstevel@tonic-gate 		uu_warn(gettext("\"%s\" is misconfigured (\"%s/%s\" property "
10777c478bd9Sstevel@tonic-gate 		    "is not of astring type.)\n"), fmri, pgname, propname);
10787c478bd9Sstevel@tonic-gate 		return (-1);
10797c478bd9Sstevel@tonic-gate 
10807c478bd9Sstevel@tonic-gate 	default:
10817c478bd9Sstevel@tonic-gate 		assert(0);
10827c478bd9Sstevel@tonic-gate 		abort();
10837c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
10847c478bd9Sstevel@tonic-gate 	}
10857c478bd9Sstevel@tonic-gate }
10867c478bd9Sstevel@tonic-gate 
10877c478bd9Sstevel@tonic-gate static boolean_t
multiple_instances(scf_iter_t * iter,scf_value_t * v,char * buf)10887c478bd9Sstevel@tonic-gate multiple_instances(scf_iter_t *iter, scf_value_t *v, char *buf)
10897c478bd9Sstevel@tonic-gate {
10907c478bd9Sstevel@tonic-gate 	int count = 0, r;
10917c478bd9Sstevel@tonic-gate 	boolean_t ret;
10927c478bd9Sstevel@tonic-gate 	scf_instance_t *inst;
10937c478bd9Sstevel@tonic-gate 
10947c478bd9Sstevel@tonic-gate 	inst = scf_instance_create(h);
10957c478bd9Sstevel@tonic-gate 	if (inst == NULL)
10967c478bd9Sstevel@tonic-gate 		scfdie();
10977c478bd9Sstevel@tonic-gate 
10987c478bd9Sstevel@tonic-gate 	for (;;) {
10997c478bd9Sstevel@tonic-gate 		r = scf_iter_next_value(iter, v);
11007c478bd9Sstevel@tonic-gate 		if (r == 0) {
11017c478bd9Sstevel@tonic-gate 			ret = B_FALSE;
11027c478bd9Sstevel@tonic-gate 			goto out;
11037c478bd9Sstevel@tonic-gate 		}
11047c478bd9Sstevel@tonic-gate 		if (r != 1)
11057c478bd9Sstevel@tonic-gate 			scfdie();
11067c478bd9Sstevel@tonic-gate 
11077c478bd9Sstevel@tonic-gate 		if (scf_value_get_astring(v, buf, max_scf_fmri_sz) < 0)
11087c478bd9Sstevel@tonic-gate 			scfdie();
11097c478bd9Sstevel@tonic-gate 
11107c478bd9Sstevel@tonic-gate 		switch (get_inst_mult(buf, inst)) {
11117c478bd9Sstevel@tonic-gate 		case 0:
11127c478bd9Sstevel@tonic-gate 			++count;
11137c478bd9Sstevel@tonic-gate 			if (count > 1) {
11147c478bd9Sstevel@tonic-gate 				ret = B_TRUE;
11157c478bd9Sstevel@tonic-gate 				goto out;
11167c478bd9Sstevel@tonic-gate 			}
11177c478bd9Sstevel@tonic-gate 			break;
11187c478bd9Sstevel@tonic-gate 
11197c478bd9Sstevel@tonic-gate 		case ENOTSUP:
11207c478bd9Sstevel@tonic-gate 		case EINVAL:
11217c478bd9Sstevel@tonic-gate 		case ENOTDIR:
11227c478bd9Sstevel@tonic-gate 		case ENOENT:
11237c478bd9Sstevel@tonic-gate 			continue;
11247c478bd9Sstevel@tonic-gate 
11257c478bd9Sstevel@tonic-gate 		case E2BIG:
11267c478bd9Sstevel@tonic-gate 			ret = B_TRUE;
11277c478bd9Sstevel@tonic-gate 			goto out;
11287c478bd9Sstevel@tonic-gate 
11297c478bd9Sstevel@tonic-gate 		default:
11307c478bd9Sstevel@tonic-gate 			assert(0);
11317c478bd9Sstevel@tonic-gate 			abort();
11327c478bd9Sstevel@tonic-gate 		}
11337c478bd9Sstevel@tonic-gate 	}
11347c478bd9Sstevel@tonic-gate 
11357c478bd9Sstevel@tonic-gate out:
11367c478bd9Sstevel@tonic-gate 	scf_instance_destroy(inst);
11377c478bd9Sstevel@tonic-gate 	return (ret);
11387c478bd9Sstevel@tonic-gate }
11397c478bd9Sstevel@tonic-gate 
11407c478bd9Sstevel@tonic-gate /*
11417c478bd9Sstevel@tonic-gate  * Enable the service or instance identified by fmri and its dependencies,
11427c478bd9Sstevel@tonic-gate  * recursively.  Specifically, call get_inst(fmri), enable the result, and
11437c478bd9Sstevel@tonic-gate  * recurse on its restarter and the dependencies.  To avoid duplication of
11447c478bd9Sstevel@tonic-gate  * effort or looping around a dependency cycle, each FMRI is entered into the
11457c478bd9Sstevel@tonic-gate  * "visited" hash table.  While recursing, the hash table entry is marked
11467c478bd9Sstevel@tonic-gate  * "active", so that if we come upon it again, we know we've hit a cycle.
11477c478bd9Sstevel@tonic-gate  * exclude_all and optional_all dependencies are ignored.  require_any
11487c478bd9Sstevel@tonic-gate  * dependencies are followed only if they comprise a single service; otherwise
11497c478bd9Sstevel@tonic-gate  * the user is warned.
11507c478bd9Sstevel@tonic-gate  *
11517c478bd9Sstevel@tonic-gate  * fmri must point to a writable max_scf_fmri_sz buffer.  Returns EINVAL if fmri
11527c478bd9Sstevel@tonic-gate  * is invalid, E2BIG if fmri identifies a service with multiple instances, ELOOP
11537c478bd9Sstevel@tonic-gate  * on cycle detection, or 0 on success.
11547c478bd9Sstevel@tonic-gate  */
11557c478bd9Sstevel@tonic-gate static int
enable_fmri_rec(char * fmri,enable_data_t * ed)11568fff7887SJohn Levon enable_fmri_rec(char *fmri, enable_data_t *ed)
11577c478bd9Sstevel@tonic-gate {
11587c478bd9Sstevel@tonic-gate 	scf_instance_t *inst;
11597c478bd9Sstevel@tonic-gate 	scf_snapshot_t *snap;
11607c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg;
11617c478bd9Sstevel@tonic-gate 	scf_property_t *prop;
11627c478bd9Sstevel@tonic-gate 	scf_value_t *v;
11637c478bd9Sstevel@tonic-gate 	scf_iter_t *pg_iter, *val_iter;
11647c478bd9Sstevel@tonic-gate 	scf_type_t ty;
11657c478bd9Sstevel@tonic-gate 	char *buf, *pgname;
11667c478bd9Sstevel@tonic-gate 	ssize_t name_sz, len, sz;
11677c478bd9Sstevel@tonic-gate 	int ret;
11687c478bd9Sstevel@tonic-gate 	struct ht_elt *he;
11697c478bd9Sstevel@tonic-gate 
11707c478bd9Sstevel@tonic-gate 	len = scf_canonify_fmri(fmri, fmri, max_scf_fmri_sz);
11717c478bd9Sstevel@tonic-gate 	if (len < 0) {
11727c478bd9Sstevel@tonic-gate 		assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT);
11737c478bd9Sstevel@tonic-gate 		return (EINVAL);
11747c478bd9Sstevel@tonic-gate 	}
11757c478bd9Sstevel@tonic-gate 	assert(len < max_scf_fmri_sz);
11767c478bd9Sstevel@tonic-gate 
11777c478bd9Sstevel@tonic-gate 	switch (visited_find_or_add(fmri, &he)) {
11787c478bd9Sstevel@tonic-gate 	case 0:
11797c478bd9Sstevel@tonic-gate 		he->active = B_TRUE;
11807c478bd9Sstevel@tonic-gate 		break;
11817c478bd9Sstevel@tonic-gate 
11827c478bd9Sstevel@tonic-gate 	case 1:
11837c478bd9Sstevel@tonic-gate 		return (he->active ? ELOOP : 0);
11847c478bd9Sstevel@tonic-gate 
11857c478bd9Sstevel@tonic-gate 	case -1:
11867c478bd9Sstevel@tonic-gate 		uu_die(emsg_nomem);
11877c478bd9Sstevel@tonic-gate 
11887c478bd9Sstevel@tonic-gate 	default:
11897c478bd9Sstevel@tonic-gate 		assert(0);
11907c478bd9Sstevel@tonic-gate 		abort();
11917c478bd9Sstevel@tonic-gate 	}
11927c478bd9Sstevel@tonic-gate 
11937c478bd9Sstevel@tonic-gate 	inst = scf_instance_create(h);
11947c478bd9Sstevel@tonic-gate 	if (inst == NULL)
11957c478bd9Sstevel@tonic-gate 		scfdie();
11967c478bd9Sstevel@tonic-gate 
11977c478bd9Sstevel@tonic-gate 	switch (get_inst_mult(fmri, inst)) {
11987c478bd9Sstevel@tonic-gate 	case 0:
11997c478bd9Sstevel@tonic-gate 		break;
12007c478bd9Sstevel@tonic-gate 
12017c478bd9Sstevel@tonic-gate 	case E2BIG:
12027c478bd9Sstevel@tonic-gate 		he->active = B_FALSE;
12037c478bd9Sstevel@tonic-gate 		return (E2BIG);
12047c478bd9Sstevel@tonic-gate 
12057c478bd9Sstevel@tonic-gate 	default:
12067c478bd9Sstevel@tonic-gate 		he->active = B_FALSE;
12077c478bd9Sstevel@tonic-gate 		return (0);
12087c478bd9Sstevel@tonic-gate 	}
12097c478bd9Sstevel@tonic-gate 
12108fff7887SJohn Levon 	set_inst_enabled(fmri, inst, ed);
12117c478bd9Sstevel@tonic-gate 
12127c478bd9Sstevel@tonic-gate 	if ((snap = scf_snapshot_create(h)) == NULL ||
12137c478bd9Sstevel@tonic-gate 	    (pg = scf_pg_create(h)) == NULL ||
12147c478bd9Sstevel@tonic-gate 	    (prop = scf_property_create(h)) == NULL ||
12157c478bd9Sstevel@tonic-gate 	    (v = scf_value_create(h)) == NULL ||
12167c478bd9Sstevel@tonic-gate 	    (pg_iter = scf_iter_create(h)) == NULL ||
12177c478bd9Sstevel@tonic-gate 	    (val_iter = scf_iter_create(h)) == NULL)
12187c478bd9Sstevel@tonic-gate 		scfdie();
12197c478bd9Sstevel@tonic-gate 
12207c478bd9Sstevel@tonic-gate 	buf = malloc(max_scf_fmri_sz);
12217c478bd9Sstevel@tonic-gate 	if (buf == NULL)
12227c478bd9Sstevel@tonic-gate 		uu_die(emsg_nomem);
12237c478bd9Sstevel@tonic-gate 
12247c478bd9Sstevel@tonic-gate 	name_sz = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH);
12257c478bd9Sstevel@tonic-gate 	if (name_sz < 0)
12267c478bd9Sstevel@tonic-gate 		scfdie();
12277c478bd9Sstevel@tonic-gate 	++name_sz;
12287c478bd9Sstevel@tonic-gate 	pgname = malloc(name_sz);
12297c478bd9Sstevel@tonic-gate 	if (pgname == NULL)
12307c478bd9Sstevel@tonic-gate 		uu_die(emsg_nomem);
12317c478bd9Sstevel@tonic-gate 
12327c478bd9Sstevel@tonic-gate 	if (scf_instance_get_snapshot(inst, "running", snap) != 0) {
12337c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND)
12347c478bd9Sstevel@tonic-gate 			scfdie();
12357c478bd9Sstevel@tonic-gate 
12367c478bd9Sstevel@tonic-gate 		scf_snapshot_destroy(snap);
12377c478bd9Sstevel@tonic-gate 		snap = NULL;
12387c478bd9Sstevel@tonic-gate 	}
12397c478bd9Sstevel@tonic-gate 
12407c478bd9Sstevel@tonic-gate 	/* Enable restarter */
12417c478bd9Sstevel@tonic-gate 	if (scf_instance_get_pg_composed(inst, snap, SCF_PG_GENERAL, pg) != 0) {
12427c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND)
12437c478bd9Sstevel@tonic-gate 			scfdie();
12447c478bd9Sstevel@tonic-gate 
12457c478bd9Sstevel@tonic-gate 		uu_warn(gettext("\"%s\" is misconfigured (lacks \"%s\" "
12467c478bd9Sstevel@tonic-gate 		    "property group).\n"), fmri, SCF_PG_GENERAL);
12477c478bd9Sstevel@tonic-gate 		ret = 0;
12487c478bd9Sstevel@tonic-gate 		goto out;
12497c478bd9Sstevel@tonic-gate 	}
12507c478bd9Sstevel@tonic-gate 
12517c478bd9Sstevel@tonic-gate 	sz = get_astring_prop(pg, SCF_PROPERTY_RESTARTER, prop, v, buf,
12527c478bd9Sstevel@tonic-gate 	    max_scf_fmri_sz);
12537c478bd9Sstevel@tonic-gate 	if (sz > max_scf_fmri_sz) {
12547c478bd9Sstevel@tonic-gate 		uu_warn(gettext("\"%s\" is misconfigured (the value of "
12557c478bd9Sstevel@tonic-gate 		    "\"%s/%s\" is too long).\n"), fmri, SCF_PG_GENERAL,
12567c478bd9Sstevel@tonic-gate 		    SCF_PROPERTY_RESTARTER);
12577c478bd9Sstevel@tonic-gate 		ret = 0;
12587c478bd9Sstevel@tonic-gate 		goto out;
12597c478bd9Sstevel@tonic-gate 	} else if (sz >= 0) {
12608fff7887SJohn Levon 		switch (enable_fmri_rec(buf, ed)) {
12617c478bd9Sstevel@tonic-gate 		case 0:
12627c478bd9Sstevel@tonic-gate 			break;
12637c478bd9Sstevel@tonic-gate 
12647c478bd9Sstevel@tonic-gate 		case EINVAL:
12657c478bd9Sstevel@tonic-gate 			uu_warn(gettext("Restarter FMRI for \"%s\" is "
12667c478bd9Sstevel@tonic-gate 			    "invalid.\n"), fmri);
12677c478bd9Sstevel@tonic-gate 			break;
12687c478bd9Sstevel@tonic-gate 
12697c478bd9Sstevel@tonic-gate 		case E2BIG:
12707c478bd9Sstevel@tonic-gate 			uu_warn(gettext("Restarter FMRI for \"%s\" identifies "
12717c478bd9Sstevel@tonic-gate 			    "a service with multiple instances.\n"), fmri);
12727c478bd9Sstevel@tonic-gate 			break;
12737c478bd9Sstevel@tonic-gate 
12747c478bd9Sstevel@tonic-gate 		case ELOOP:
12757c478bd9Sstevel@tonic-gate 			ret = ELOOP;
12767c478bd9Sstevel@tonic-gate 			goto out;
12777c478bd9Sstevel@tonic-gate 
12787c478bd9Sstevel@tonic-gate 		default:
12797c478bd9Sstevel@tonic-gate 			assert(0);
12807c478bd9Sstevel@tonic-gate 			abort();
12817c478bd9Sstevel@tonic-gate 		}
12827c478bd9Sstevel@tonic-gate 	} else if (sz < 0) {
12837c478bd9Sstevel@tonic-gate 		switch (-sz) {
12847c478bd9Sstevel@tonic-gate 		case ENOENT:
12857c478bd9Sstevel@tonic-gate 			break;
12867c478bd9Sstevel@tonic-gate 
12877c478bd9Sstevel@tonic-gate 		case E2BIG:
12887c478bd9Sstevel@tonic-gate 			uu_warn(gettext("\"%s\" is misconfigured (\"%s/%s\" "
12897c478bd9Sstevel@tonic-gate 			    "property is not single-valued).\n"), fmri,
12907c478bd9Sstevel@tonic-gate 			    SCF_PG_GENERAL, SCF_PROPERTY_RESTARTER);
12917c478bd9Sstevel@tonic-gate 			ret = 0;
12927c478bd9Sstevel@tonic-gate 			goto out;
12937c478bd9Sstevel@tonic-gate 
12947c478bd9Sstevel@tonic-gate 		case EINVAL:
12957c478bd9Sstevel@tonic-gate 			uu_warn(gettext("\"%s\" is misconfigured (\"%s/%s\" "
12967c478bd9Sstevel@tonic-gate 			    "property is not of astring type).\n"), fmri,
12977c478bd9Sstevel@tonic-gate 			    SCF_PG_GENERAL, SCF_PROPERTY_RESTARTER);
12987c478bd9Sstevel@tonic-gate 			ret = 0;
12997c478bd9Sstevel@tonic-gate 			goto out;
13007c478bd9Sstevel@tonic-gate 
13017c478bd9Sstevel@tonic-gate 		default:
13027c478bd9Sstevel@tonic-gate 			assert(0);
13037c478bd9Sstevel@tonic-gate 			abort();
13047c478bd9Sstevel@tonic-gate 		}
13057c478bd9Sstevel@tonic-gate 	}
13067c478bd9Sstevel@tonic-gate 
13077c478bd9Sstevel@tonic-gate 	if (scf_iter_instance_pgs_typed_composed(pg_iter, inst, snap,
13087c478bd9Sstevel@tonic-gate 	    SCF_GROUP_DEPENDENCY) == -1)
13097c478bd9Sstevel@tonic-gate 		scfdie();
13107c478bd9Sstevel@tonic-gate 
13117c478bd9Sstevel@tonic-gate 	while (scf_iter_next_pg(pg_iter, pg) > 0) {
13127c478bd9Sstevel@tonic-gate 		len = scf_pg_get_name(pg, pgname, name_sz);
13137c478bd9Sstevel@tonic-gate 		if (len < 0)
13147c478bd9Sstevel@tonic-gate 			scfdie();
13157c478bd9Sstevel@tonic-gate 		assert(len < name_sz);
13167c478bd9Sstevel@tonic-gate 
13177c478bd9Sstevel@tonic-gate 		if (dep_get_astring(fmri, pgname, pg, SCF_PROPERTY_TYPE, prop,
13187c478bd9Sstevel@tonic-gate 		    v, buf, max_scf_fmri_sz) < 0)
13197c478bd9Sstevel@tonic-gate 			continue;
13207c478bd9Sstevel@tonic-gate 
13217c478bd9Sstevel@tonic-gate 		if (strcmp(buf, "service") != 0)
13227c478bd9Sstevel@tonic-gate 			continue;
13237c478bd9Sstevel@tonic-gate 
13247c478bd9Sstevel@tonic-gate 		if (dep_get_astring(fmri, pgname, pg, SCF_PROPERTY_GROUPING,
13257c478bd9Sstevel@tonic-gate 		    prop, v, buf, max_scf_fmri_sz) < 0)
13267c478bd9Sstevel@tonic-gate 			continue;
13277c478bd9Sstevel@tonic-gate 
13287c478bd9Sstevel@tonic-gate 		if (strcmp(buf, SCF_DEP_EXCLUDE_ALL) == 0 ||
13297c478bd9Sstevel@tonic-gate 		    strcmp(buf, SCF_DEP_OPTIONAL_ALL) == 0)
13307c478bd9Sstevel@tonic-gate 			continue;
13317c478bd9Sstevel@tonic-gate 
13327c478bd9Sstevel@tonic-gate 		if (strcmp(buf, SCF_DEP_REQUIRE_ALL) != 0 &&
13337c478bd9Sstevel@tonic-gate 		    strcmp(buf, SCF_DEP_REQUIRE_ANY) != 0) {
13347c478bd9Sstevel@tonic-gate 			uu_warn(gettext("Dependency \"%s\" of \"%s\" has "
13357c478bd9Sstevel@tonic-gate 			    "unknown type \"%s\".\n"), pgname, fmri, buf);
13367c478bd9Sstevel@tonic-gate 			continue;
13377c478bd9Sstevel@tonic-gate 		}
13387c478bd9Sstevel@tonic-gate 
13397c478bd9Sstevel@tonic-gate 		if (scf_pg_get_property(pg, SCF_PROPERTY_ENTITIES, prop) ==
13407c478bd9Sstevel@tonic-gate 		    -1) {
13417c478bd9Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_NOT_FOUND)
13427c478bd9Sstevel@tonic-gate 				scfdie();
13437c478bd9Sstevel@tonic-gate 
13447c478bd9Sstevel@tonic-gate 			uu_warn(gettext("\"%s\" is misconfigured (\"%s\" "
13457c478bd9Sstevel@tonic-gate 			    "dependency lacks \"%s\" property.)\n"), fmri,
13467c478bd9Sstevel@tonic-gate 			    pgname, SCF_PROPERTY_ENTITIES);
13477c478bd9Sstevel@tonic-gate 			continue;
13487c478bd9Sstevel@tonic-gate 		}
13497c478bd9Sstevel@tonic-gate 
13507c478bd9Sstevel@tonic-gate 		if (scf_property_type(prop, &ty) != SCF_SUCCESS)
13517c478bd9Sstevel@tonic-gate 			scfdie();
13527c478bd9Sstevel@tonic-gate 
13537c478bd9Sstevel@tonic-gate 		if (ty != SCF_TYPE_FMRI) {
13547c478bd9Sstevel@tonic-gate 			uu_warn(gettext("\"%s\" is misconfigured (property "
13557c478bd9Sstevel@tonic-gate 			    "\"%s/%s\" is not of fmri type).\n"), fmri, pgname,
13567c478bd9Sstevel@tonic-gate 			    SCF_PROPERTY_ENTITIES);
13577c478bd9Sstevel@tonic-gate 			continue;
13587c478bd9Sstevel@tonic-gate 		}
13597c478bd9Sstevel@tonic-gate 
13607c478bd9Sstevel@tonic-gate 		if (scf_iter_property_values(val_iter, prop) == -1)
13617c478bd9Sstevel@tonic-gate 			scfdie();
13627c478bd9Sstevel@tonic-gate 
13637c478bd9Sstevel@tonic-gate 		if (strcmp(buf, SCF_DEP_REQUIRE_ANY) == 0) {
13647c478bd9Sstevel@tonic-gate 			if (multiple_instances(val_iter, v, buf)) {
13657c478bd9Sstevel@tonic-gate 				(void) printf(gettext("%s requires one of:\n"),
13667c478bd9Sstevel@tonic-gate 				    fmri);
13677c478bd9Sstevel@tonic-gate 
13687c478bd9Sstevel@tonic-gate 				if (scf_iter_property_values(val_iter, prop) !=
13697c478bd9Sstevel@tonic-gate 				    0)
13707c478bd9Sstevel@tonic-gate 					scfdie();
13717c478bd9Sstevel@tonic-gate 
13727c478bd9Sstevel@tonic-gate 				for (;;) {
13737c478bd9Sstevel@tonic-gate 					int r;
13747c478bd9Sstevel@tonic-gate 
13757c478bd9Sstevel@tonic-gate 					r = scf_iter_next_value(val_iter, v);
13767c478bd9Sstevel@tonic-gate 					if (r == 0)
13777c478bd9Sstevel@tonic-gate 						break;
13787c478bd9Sstevel@tonic-gate 					if (r != 1)
13797c478bd9Sstevel@tonic-gate 						scfdie();
13807c478bd9Sstevel@tonic-gate 
13817c478bd9Sstevel@tonic-gate 					if (scf_value_get_astring(v, buf,
13827c478bd9Sstevel@tonic-gate 					    max_scf_fmri_sz) < 0)
13837c478bd9Sstevel@tonic-gate 						scfdie();
13847c478bd9Sstevel@tonic-gate 
13857c478bd9Sstevel@tonic-gate 					(void) fputs("  ", stdout);
13867c478bd9Sstevel@tonic-gate 					(void) puts(buf);
13877c478bd9Sstevel@tonic-gate 				}
13887c478bd9Sstevel@tonic-gate 
13897c478bd9Sstevel@tonic-gate 				continue;
13907c478bd9Sstevel@tonic-gate 			}
13917c478bd9Sstevel@tonic-gate 
13927c478bd9Sstevel@tonic-gate 			/*
13937c478bd9Sstevel@tonic-gate 			 * Since there's only one instance, we can enable it.
13947c478bd9Sstevel@tonic-gate 			 * Reset val_iter and continue.
13957c478bd9Sstevel@tonic-gate 			 */
13967c478bd9Sstevel@tonic-gate 			if (scf_iter_property_values(val_iter, prop) != 0)
13977c478bd9Sstevel@tonic-gate 				scfdie();
13987c478bd9Sstevel@tonic-gate 		}
13997c478bd9Sstevel@tonic-gate 
14007c478bd9Sstevel@tonic-gate 		for (;;) {
14017c478bd9Sstevel@tonic-gate 			ret = scf_iter_next_value(val_iter, v);
14027c478bd9Sstevel@tonic-gate 			if (ret == 0)
14037c478bd9Sstevel@tonic-gate 				break;
14047c478bd9Sstevel@tonic-gate 			if (ret != 1)
14057c478bd9Sstevel@tonic-gate 				scfdie();
14067c478bd9Sstevel@tonic-gate 
14077c478bd9Sstevel@tonic-gate 			if (scf_value_get_astring(v, buf, max_scf_fmri_sz) ==
14087c478bd9Sstevel@tonic-gate 			    -1)
14097c478bd9Sstevel@tonic-gate 				scfdie();
14107c478bd9Sstevel@tonic-gate 
14118fff7887SJohn Levon 			switch (enable_fmri_rec(buf, ed)) {
14127c478bd9Sstevel@tonic-gate 			case 0:
14137c478bd9Sstevel@tonic-gate 				break;
14147c478bd9Sstevel@tonic-gate 
14157c478bd9Sstevel@tonic-gate 			case EINVAL:
14167c478bd9Sstevel@tonic-gate 				uu_warn(gettext("\"%s\" dependency of \"%s\" "
14177c478bd9Sstevel@tonic-gate 				    "has invalid FMRI \"%s\".\n"), pgname,
14187c478bd9Sstevel@tonic-gate 				    fmri, buf);
14197c478bd9Sstevel@tonic-gate 				break;
14207c478bd9Sstevel@tonic-gate 
14217c478bd9Sstevel@tonic-gate 			case E2BIG:
14227c478bd9Sstevel@tonic-gate 				uu_warn(gettext("%s depends on %s, which has "
14237c478bd9Sstevel@tonic-gate 				    "multiple instances.\n"), fmri, buf);
14247c478bd9Sstevel@tonic-gate 				break;
14257c478bd9Sstevel@tonic-gate 
14267c478bd9Sstevel@tonic-gate 			case ELOOP:
14277c478bd9Sstevel@tonic-gate 				ret = ELOOP;
14287c478bd9Sstevel@tonic-gate 				goto out;
14297c478bd9Sstevel@tonic-gate 
14307c478bd9Sstevel@tonic-gate 			default:
14317c478bd9Sstevel@tonic-gate 				assert(0);
14327c478bd9Sstevel@tonic-gate 				abort();
14337c478bd9Sstevel@tonic-gate 			}
14347c478bd9Sstevel@tonic-gate 		}
14357c478bd9Sstevel@tonic-gate 	}
14367c478bd9Sstevel@tonic-gate 
14377c478bd9Sstevel@tonic-gate 	ret = 0;
14387c478bd9Sstevel@tonic-gate 
14397c478bd9Sstevel@tonic-gate out:
14407c478bd9Sstevel@tonic-gate 	he->active = B_FALSE;
14417c478bd9Sstevel@tonic-gate 
14427c478bd9Sstevel@tonic-gate 	free(buf);
14437c478bd9Sstevel@tonic-gate 	free(pgname);
14447c478bd9Sstevel@tonic-gate 
14457c478bd9Sstevel@tonic-gate 	(void) scf_value_destroy(v);
14467c478bd9Sstevel@tonic-gate 	scf_property_destroy(prop);
14477c478bd9Sstevel@tonic-gate 	scf_pg_destroy(pg);
14487c478bd9Sstevel@tonic-gate 	scf_snapshot_destroy(snap);
14497c478bd9Sstevel@tonic-gate 	scf_iter_destroy(pg_iter);
14507c478bd9Sstevel@tonic-gate 	scf_iter_destroy(val_iter);
14517c478bd9Sstevel@tonic-gate 
14527c478bd9Sstevel@tonic-gate 	return (ret);
14537c478bd9Sstevel@tonic-gate }
14547c478bd9Sstevel@tonic-gate 
14557c478bd9Sstevel@tonic-gate /*
14567c478bd9Sstevel@tonic-gate  * fmri here is only used for verbose messages.
14577c478bd9Sstevel@tonic-gate  */
14587c478bd9Sstevel@tonic-gate static void
set_inst_action(const char * fmri,const scf_instance_t * inst,const char * action)14597c478bd9Sstevel@tonic-gate set_inst_action(const char *fmri, const scf_instance_t *inst,
14607c478bd9Sstevel@tonic-gate     const char *action)
14617c478bd9Sstevel@tonic-gate {
14627c478bd9Sstevel@tonic-gate 	scf_transaction_t *tx;
14637c478bd9Sstevel@tonic-gate 	scf_transaction_entry_t *ent;
14647c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg;
14657c478bd9Sstevel@tonic-gate 	scf_property_t *prop;
14667c478bd9Sstevel@tonic-gate 	scf_value_t *v;
14677c478bd9Sstevel@tonic-gate 	int ret;
14687c478bd9Sstevel@tonic-gate 	int64_t t;
14697c478bd9Sstevel@tonic-gate 	hrtime_t timestamp;
14707c478bd9Sstevel@tonic-gate 
14717c478bd9Sstevel@tonic-gate 	const char * const scf_pg_restarter_actions = SCF_PG_RESTARTER_ACTIONS;
14727c478bd9Sstevel@tonic-gate 
14737c478bd9Sstevel@tonic-gate 	if ((pg = scf_pg_create(h)) == NULL ||
14747c478bd9Sstevel@tonic-gate 	    (prop = scf_property_create(h)) == NULL ||
14757c478bd9Sstevel@tonic-gate 	    (v = scf_value_create(h)) == NULL ||
14767c478bd9Sstevel@tonic-gate 	    (tx = scf_transaction_create(h)) == NULL ||
14777c478bd9Sstevel@tonic-gate 	    (ent = scf_entry_create(h)) == NULL)
14787c478bd9Sstevel@tonic-gate 		scfdie();
14797c478bd9Sstevel@tonic-gate 
1480a97d4a16SDave Eddy 	if (restarter_setup(fmri, inst)) {
1481a97d4a16SDave Eddy 		exit_status = 1;
1482e8f5b3f5STruong Nguyen 		goto out;
1483a97d4a16SDave Eddy 	}
1484eb1a3463STruong Nguyen 
14857c478bd9Sstevel@tonic-gate 	if (scf_instance_get_pg(inst, scf_pg_restarter_actions, pg) == -1) {
14867c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND)
14877c478bd9Sstevel@tonic-gate 			scfdie();
14887c478bd9Sstevel@tonic-gate 
14897c478bd9Sstevel@tonic-gate 		/* Try creating the restarter_actions property group. */
14907c478bd9Sstevel@tonic-gate 		if (scf_instance_add_pg(inst, scf_pg_restarter_actions,
14917c478bd9Sstevel@tonic-gate 		    SCF_PG_RESTARTER_ACTIONS_TYPE,
14927c478bd9Sstevel@tonic-gate 		    SCF_PG_RESTARTER_ACTIONS_FLAGS, pg) == -1) {
14937c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
14947c478bd9Sstevel@tonic-gate 			case SCF_ERROR_EXISTS:
14957c478bd9Sstevel@tonic-gate 				/* Someone must have added it. */
14967c478bd9Sstevel@tonic-gate 				break;
14977c478bd9Sstevel@tonic-gate 
14987c478bd9Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
14997c478bd9Sstevel@tonic-gate 				if (!verbose)
15007c478bd9Sstevel@tonic-gate 					uu_warn(emsg_permission_denied, fmri);
15017c478bd9Sstevel@tonic-gate 				else
15027c478bd9Sstevel@tonic-gate 					uu_warn(emsg_create_pg_perm_denied,
15037c478bd9Sstevel@tonic-gate 					    fmri, scf_pg_restarter_actions);
15047c478bd9Sstevel@tonic-gate 				goto out;
15057c478bd9Sstevel@tonic-gate 
15067c478bd9Sstevel@tonic-gate 			default:
15077c478bd9Sstevel@tonic-gate 				scfdie();
15087c478bd9Sstevel@tonic-gate 			}
15097c478bd9Sstevel@tonic-gate 		}
15107c478bd9Sstevel@tonic-gate 	}
15117c478bd9Sstevel@tonic-gate 
15127c478bd9Sstevel@tonic-gate 	/*
15137c478bd9Sstevel@tonic-gate 	 * If we lose the transaction race and need to retry, there are 2
15147c478bd9Sstevel@tonic-gate 	 * potential other winners:
15157c478bd9Sstevel@tonic-gate 	 *	- another process setting actions
15167c478bd9Sstevel@tonic-gate 	 *	- the restarter marking the action complete
15177c478bd9Sstevel@tonic-gate 	 * Therefore, re-read the property every time through the loop before
15187c478bd9Sstevel@tonic-gate 	 * making any decisions based on their values.
15197c478bd9Sstevel@tonic-gate 	 */
15207c478bd9Sstevel@tonic-gate 	do {
15217c478bd9Sstevel@tonic-gate 		timestamp = gethrtime();
15227c478bd9Sstevel@tonic-gate 
15237c478bd9Sstevel@tonic-gate 		if (scf_transaction_start(tx, pg) == -1) {
15247c478bd9Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15257c478bd9Sstevel@tonic-gate 				scfdie();
15267c478bd9Sstevel@tonic-gate 
15277c478bd9Sstevel@tonic-gate 			if (!verbose)
15287c478bd9Sstevel@tonic-gate 				uu_warn(emsg_permission_denied, fmri);
15297c478bd9Sstevel@tonic-gate 			else
15307c478bd9Sstevel@tonic-gate 				uu_warn(emsg_pg_perm_denied, fmri,
15317c478bd9Sstevel@tonic-gate 				    scf_pg_restarter_actions);
15327c478bd9Sstevel@tonic-gate 			goto out;
15337c478bd9Sstevel@tonic-gate 		}
15347c478bd9Sstevel@tonic-gate 
15357c478bd9Sstevel@tonic-gate 		if (scf_pg_get_property(pg, action, prop) == -1) {
15367c478bd9Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_NOT_FOUND)
15377c478bd9Sstevel@tonic-gate 				scfdie();
15387c478bd9Sstevel@tonic-gate 			if (scf_transaction_property_new(tx, ent,
15397c478bd9Sstevel@tonic-gate 			    action, SCF_TYPE_INTEGER) == -1)
15407c478bd9Sstevel@tonic-gate 				scfdie();
15417c478bd9Sstevel@tonic-gate 			goto action_set;
15427c478bd9Sstevel@tonic-gate 		} else {
15437c478bd9Sstevel@tonic-gate 			if (scf_transaction_property_change_type(tx, ent,
15447c478bd9Sstevel@tonic-gate 			    action, SCF_TYPE_INTEGER) == -1)
15457c478bd9Sstevel@tonic-gate 				scfdie();
15467c478bd9Sstevel@tonic-gate 		}
15477c478bd9Sstevel@tonic-gate 
15487c478bd9Sstevel@tonic-gate 		if (scf_property_get_value(prop, v) == -1) {
15497c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
15507c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONSTRAINT_VIOLATED:
15517c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_FOUND:
15527c478bd9Sstevel@tonic-gate 				/* Misconfigured, so set anyway. */
15537c478bd9Sstevel@tonic-gate 				goto action_set;
15547c478bd9Sstevel@tonic-gate 
15557c478bd9Sstevel@tonic-gate 			default:
15567c478bd9Sstevel@tonic-gate 				scfdie();
15577c478bd9Sstevel@tonic-gate 			}
15587c478bd9Sstevel@tonic-gate 		} else {
15597c478bd9Sstevel@tonic-gate 			if (scf_value_get_integer(v, &t) == -1) {
15607c478bd9Sstevel@tonic-gate 				assert(scf_error() == SCF_ERROR_TYPE_MISMATCH);
15617c478bd9Sstevel@tonic-gate 				goto action_set;
15627c478bd9Sstevel@tonic-gate 			}
15637c478bd9Sstevel@tonic-gate 			if (t > timestamp)
15647c478bd9Sstevel@tonic-gate 				break;
15657c478bd9Sstevel@tonic-gate 		}
15667c478bd9Sstevel@tonic-gate 
15677c478bd9Sstevel@tonic-gate action_set:
15687c478bd9Sstevel@tonic-gate 		scf_value_set_integer(v, timestamp);
15697c478bd9Sstevel@tonic-gate 		if (scf_entry_add_value(ent, v) == -1)
15707c478bd9Sstevel@tonic-gate 			scfdie();
15717c478bd9Sstevel@tonic-gate 
15727c478bd9Sstevel@tonic-gate 		ret = scf_transaction_commit(tx);
15737c478bd9Sstevel@tonic-gate 		if (ret == -1) {
15747c478bd9Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15757c478bd9Sstevel@tonic-gate 				scfdie();
15767c478bd9Sstevel@tonic-gate 
15777c478bd9Sstevel@tonic-gate 			if (!verbose)
15787c478bd9Sstevel@tonic-gate 				uu_warn(emsg_permission_denied, fmri);
15797c478bd9Sstevel@tonic-gate 			else
15807c478bd9Sstevel@tonic-gate 				uu_warn(emsg_prop_perm_denied, fmri,
15817c478bd9Sstevel@tonic-gate 				    scf_pg_restarter_actions, action);
15827c478bd9Sstevel@tonic-gate 			scf_transaction_reset(tx);
15837c478bd9Sstevel@tonic-gate 			goto out;
15847c478bd9Sstevel@tonic-gate 		}
15857c478bd9Sstevel@tonic-gate 
15867c478bd9Sstevel@tonic-gate 		scf_transaction_reset(tx);
15877c478bd9Sstevel@tonic-gate 
15887c478bd9Sstevel@tonic-gate 		if (ret == 0) {
15897c478bd9Sstevel@tonic-gate 			if (scf_pg_update(pg) == -1)
15907c478bd9Sstevel@tonic-gate 				scfdie();
15917c478bd9Sstevel@tonic-gate 		}
15927c478bd9Sstevel@tonic-gate 	} while (ret == 0);
15937c478bd9Sstevel@tonic-gate 
15947c478bd9Sstevel@tonic-gate 	if (verbose)
15957c478bd9Sstevel@tonic-gate 		(void) printf(gettext("Action %s set for %s.\n"), action, fmri);
15967c478bd9Sstevel@tonic-gate 
15977c478bd9Sstevel@tonic-gate out:
15987c478bd9Sstevel@tonic-gate 	scf_value_destroy(v);
15997c478bd9Sstevel@tonic-gate 	scf_entry_destroy(ent);
16007c478bd9Sstevel@tonic-gate 	scf_transaction_destroy(tx);
16017c478bd9Sstevel@tonic-gate 	scf_property_destroy(prop);
16027c478bd9Sstevel@tonic-gate 	scf_pg_destroy(pg);
16037c478bd9Sstevel@tonic-gate }
16047c478bd9Sstevel@tonic-gate 
16057c478bd9Sstevel@tonic-gate /*
16067c478bd9Sstevel@tonic-gate  * Get the state of inst.  state should point to a buffer of
16077c478bd9Sstevel@tonic-gate  * MAX_SCF_STATE_STRING_SZ bytes.  Returns 0 on success or -1 if
16087c478bd9Sstevel@tonic-gate  *   no restarter property group
16097c478bd9Sstevel@tonic-gate  *   no state property
16107c478bd9Sstevel@tonic-gate  *   state property is misconfigured (wrong type, not single-valued)
16117c478bd9Sstevel@tonic-gate  *   state value is too long
16127c478bd9Sstevel@tonic-gate  * In these cases, fmri is used to print a warning.
16137c478bd9Sstevel@tonic-gate  *
16147c478bd9Sstevel@tonic-gate  * If pgp is non-NULL, a successful call to inst_get_state will store
16157c478bd9Sstevel@tonic-gate  * the SCF_PG_RESTARTER property group in *pgp, and the caller will be
16167c478bd9Sstevel@tonic-gate  * responsible for calling scf_pg_destroy on the property group.
16177c478bd9Sstevel@tonic-gate  */
16187c478bd9Sstevel@tonic-gate int
inst_get_state(scf_instance_t * inst,char * state,const char * fmri,scf_propertygroup_t ** pgp)16197c478bd9Sstevel@tonic-gate inst_get_state(scf_instance_t *inst, char *state, const char *fmri,
16207c478bd9Sstevel@tonic-gate     scf_propertygroup_t **pgp)
16217c478bd9Sstevel@tonic-gate {
16227c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg;
16237c478bd9Sstevel@tonic-gate 	scf_property_t *prop;
16247c478bd9Sstevel@tonic-gate 	scf_value_t *val;
16257c478bd9Sstevel@tonic-gate 	int ret = -1;
16267c478bd9Sstevel@tonic-gate 	ssize_t szret;
16277c478bd9Sstevel@tonic-gate 
16287c478bd9Sstevel@tonic-gate 	if ((pg = scf_pg_create(h)) == NULL ||
16297c478bd9Sstevel@tonic-gate 	    (prop = scf_property_create(h)) == NULL ||
16307c478bd9Sstevel@tonic-gate 	    (val = scf_value_create(h)) == NULL)
16317c478bd9Sstevel@tonic-gate 		scfdie();
16327c478bd9Sstevel@tonic-gate 
16337c478bd9Sstevel@tonic-gate 	if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) {
16347c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND)
16357c478bd9Sstevel@tonic-gate 			scfdie();
16367c478bd9Sstevel@tonic-gate 
16377c478bd9Sstevel@tonic-gate 		uu_warn(gettext("%s is misconfigured (lacks \"%s\" property "
16387c478bd9Sstevel@tonic-gate 		    "group).\n"), fmri ? fmri : inst_get_fmri(inst),
16397c478bd9Sstevel@tonic-gate 		    SCF_PG_RESTARTER);
16407c478bd9Sstevel@tonic-gate 		goto out;
16417c478bd9Sstevel@tonic-gate 	}
16427c478bd9Sstevel@tonic-gate 
16437c478bd9Sstevel@tonic-gate 	szret = get_astring_prop(pg, SCF_PROPERTY_STATE, prop, val, state,
16447c478bd9Sstevel@tonic-gate 	    MAX_SCF_STATE_STRING_SZ);
16457c478bd9Sstevel@tonic-gate 	if (szret < 0) {
16467c478bd9Sstevel@tonic-gate 		switch (-szret) {
16477c478bd9Sstevel@tonic-gate 		case ENOENT:
16487c478bd9Sstevel@tonic-gate 			uu_warn(gettext("%s is misconfigured (\"%s\" property "
16497c478bd9Sstevel@tonic-gate 			    "group lacks \"%s\" property).\n"),
16507c478bd9Sstevel@tonic-gate 			    fmri ? fmri : inst_get_fmri(inst), SCF_PG_RESTARTER,
16517c478bd9Sstevel@tonic-gate 			    SCF_PROPERTY_STATE);
16527c478bd9Sstevel@tonic-gate 			goto out;
16537c478bd9Sstevel@tonic-gate 
16547c478bd9Sstevel@tonic-gate 		case E2BIG:
16557c478bd9Sstevel@tonic-gate 			uu_warn(gettext("%s is misconfigured (\"%s/%s\" "
16567c478bd9Sstevel@tonic-gate 			    "property is not single-valued).\n"),
16577c478bd9Sstevel@tonic-gate 			    fmri ? fmri : inst_get_fmri(inst), SCF_PG_RESTARTER,
16587c478bd9Sstevel@tonic-gate 			    SCF_PROPERTY_STATE);
16597c478bd9Sstevel@tonic-gate 			goto out;
16607c478bd9Sstevel@tonic-gate 
16617c478bd9Sstevel@tonic-gate 		case EINVAL:
16627c478bd9Sstevel@tonic-gate 			uu_warn(gettext("%s is misconfigured (\"%s/%s\" "
16637c478bd9Sstevel@tonic-gate 			    "property is not of type astring).\n"),
16647c478bd9Sstevel@tonic-gate 			    fmri ? fmri : inst_get_fmri(inst), SCF_PG_RESTARTER,
16657c478bd9Sstevel@tonic-gate 			    SCF_PROPERTY_STATE);
16667c478bd9Sstevel@tonic-gate 			goto out;
16677c478bd9Sstevel@tonic-gate 
16687c478bd9Sstevel@tonic-gate 		default:
16697c478bd9Sstevel@tonic-gate 			assert(0);
16707c478bd9Sstevel@tonic-gate 			abort();
16717c478bd9Sstevel@tonic-gate 		}
16727c478bd9Sstevel@tonic-gate 	}
16737c478bd9Sstevel@tonic-gate 	if (szret >= MAX_SCF_STATE_STRING_SZ) {
16747c478bd9Sstevel@tonic-gate 		uu_warn(gettext("%s is misconfigured (\"%s/%s\" property value "
16757c478bd9Sstevel@tonic-gate 		    "is too long).\n"), fmri ? fmri : inst_get_fmri(inst),
16767c478bd9Sstevel@tonic-gate 		    SCF_PG_RESTARTER, SCF_PROPERTY_STATE);
16777c478bd9Sstevel@tonic-gate 		goto out;
16787c478bd9Sstevel@tonic-gate 	}
16797c478bd9Sstevel@tonic-gate 
16807c478bd9Sstevel@tonic-gate 	ret = 0;
16817c478bd9Sstevel@tonic-gate 	if (pgp)
16827c478bd9Sstevel@tonic-gate 		*pgp = pg;
16837c478bd9Sstevel@tonic-gate 
16847c478bd9Sstevel@tonic-gate out:
16857c478bd9Sstevel@tonic-gate 	(void) scf_value_destroy(val);
16867c478bd9Sstevel@tonic-gate 	scf_property_destroy(prop);
16877c478bd9Sstevel@tonic-gate 	if (ret || pgp == NULL)
16887c478bd9Sstevel@tonic-gate 		scf_pg_destroy(pg);
16897c478bd9Sstevel@tonic-gate 	return (ret);
16907c478bd9Sstevel@tonic-gate }
16917c478bd9Sstevel@tonic-gate 
16927c478bd9Sstevel@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)16937c478bd9Sstevel@tonic-gate set_astring_prop(const char *fmri, const char *pgname, const char *pgtype,
16947c478bd9Sstevel@tonic-gate     uint32_t pgflags, const char *propname, const char *str)
16957c478bd9Sstevel@tonic-gate {
16967c478bd9Sstevel@tonic-gate 	scf_instance_t *inst;
16977c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg;
16987c478bd9Sstevel@tonic-gate 	scf_property_t *prop;
16997c478bd9Sstevel@tonic-gate 	scf_value_t *val;
17007c478bd9Sstevel@tonic-gate 	scf_transaction_t *tx;
17017c478bd9Sstevel@tonic-gate 	scf_transaction_entry_t *txent;
17027c478bd9Sstevel@tonic-gate 	int ret;
17037c478bd9Sstevel@tonic-gate 
17047c478bd9Sstevel@tonic-gate 	inst = scf_instance_create(h);
17057c478bd9Sstevel@tonic-gate 	if (inst == NULL)
17067c478bd9Sstevel@tonic-gate 		scfdie();
17077c478bd9Sstevel@tonic-gate 
17087c478bd9Sstevel@tonic-gate 	if (get_inst(fmri, inst) != 0)
17097c478bd9Sstevel@tonic-gate 		return;
17107c478bd9Sstevel@tonic-gate 
17117c478bd9Sstevel@tonic-gate 	if ((pg = scf_pg_create(h)) == NULL ||
17127c478bd9Sstevel@tonic-gate 	    (prop = scf_property_create(h)) == NULL ||
17137c478bd9Sstevel@tonic-gate 	    (val = scf_value_create(h)) == NULL ||
17147c478bd9Sstevel@tonic-gate 	    (tx = scf_transaction_create(h)) == NULL ||
17157c478bd9Sstevel@tonic-gate 	    (txent = scf_entry_create(h)) == NULL)
17167c478bd9Sstevel@tonic-gate 		scfdie();
17177c478bd9Sstevel@tonic-gate 
17187c478bd9Sstevel@tonic-gate 	if (scf_instance_get_pg(inst, pgname, pg) != SCF_SUCCESS) {
17197c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND)
17207c478bd9Sstevel@tonic-gate 			scfdie();
17217c478bd9Sstevel@tonic-gate 
17227c478bd9Sstevel@tonic-gate 		if (scf_instance_add_pg(inst, pgname, pgtype, pgflags, pg) !=
17237c478bd9Sstevel@tonic-gate 		    SCF_SUCCESS) {
17247c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
17257c478bd9Sstevel@tonic-gate 			case SCF_ERROR_EXISTS:
17267c478bd9Sstevel@tonic-gate 				if (scf_instance_get_pg(inst, pgname, pg) !=
17277c478bd9Sstevel@tonic-gate 				    SCF_SUCCESS) {
17287c478bd9Sstevel@tonic-gate 					if (scf_error() != SCF_ERROR_NOT_FOUND)
17297c478bd9Sstevel@tonic-gate 						scfdie();
17307c478bd9Sstevel@tonic-gate 
17317c478bd9Sstevel@tonic-gate 					uu_warn(gettext("Repository write "
17327c478bd9Sstevel@tonic-gate 					    "contention.\n"));
17337c478bd9Sstevel@tonic-gate 					goto out;
17347c478bd9Sstevel@tonic-gate 				}
17357c478bd9Sstevel@tonic-gate 				break;
17367c478bd9Sstevel@tonic-gate 
17377c478bd9Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
17387c478bd9Sstevel@tonic-gate 				if (!verbose)
17397c478bd9Sstevel@tonic-gate 					uu_warn(emsg_permission_denied, fmri);
17407c478bd9Sstevel@tonic-gate 				else
17417c478bd9Sstevel@tonic-gate 					uu_warn(emsg_create_pg_perm_denied,
17427c478bd9Sstevel@tonic-gate 					    fmri, pgname);
17437c478bd9Sstevel@tonic-gate 				goto out;
17447c478bd9Sstevel@tonic-gate 
17457c478bd9Sstevel@tonic-gate 			default:
17467c478bd9Sstevel@tonic-gate 				scfdie();
17477c478bd9Sstevel@tonic-gate 			}
17487c478bd9Sstevel@tonic-gate 		}
17497c478bd9Sstevel@tonic-gate 	}
17507c478bd9Sstevel@tonic-gate 
17517c478bd9Sstevel@tonic-gate 	do {
17527c478bd9Sstevel@tonic-gate 		if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
17537c478bd9Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
17547c478bd9Sstevel@tonic-gate 				scfdie();
17557c478bd9Sstevel@tonic-gate 
17567c478bd9Sstevel@tonic-gate 			if (!verbose)
17577c478bd9Sstevel@tonic-gate 				uu_warn(emsg_permission_denied, fmri);
17587c478bd9Sstevel@tonic-gate 			else
17597c478bd9Sstevel@tonic-gate 				uu_warn(emsg_pg_perm_denied, fmri, pgname);
17607c478bd9Sstevel@tonic-gate 			goto out;
17617c478bd9Sstevel@tonic-gate 		}
17627c478bd9Sstevel@tonic-gate 
17637c478bd9Sstevel@tonic-gate 		if (scf_transaction_property_change_type(tx, txent, propname,
17647c478bd9Sstevel@tonic-gate 		    SCF_TYPE_ASTRING) != 0) {
17657c478bd9Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_NOT_FOUND)
17667c478bd9Sstevel@tonic-gate 				scfdie();
17677c478bd9Sstevel@tonic-gate 
17687c478bd9Sstevel@tonic-gate 			if (scf_transaction_property_new(tx, txent, propname,
17697c478bd9Sstevel@tonic-gate 			    SCF_TYPE_ASTRING) != 0)
17707c478bd9Sstevel@tonic-gate 				scfdie();
17717c478bd9Sstevel@tonic-gate 		}
17727c478bd9Sstevel@tonic-gate 
17737c478bd9Sstevel@tonic-gate 		if (scf_value_set_astring(val, str) != SCF_SUCCESS)
17747c478bd9Sstevel@tonic-gate 			scfdie();
17757c478bd9Sstevel@tonic-gate 
17767c478bd9Sstevel@tonic-gate 		if (scf_entry_add_value(txent, val) != SCF_SUCCESS)
17777c478bd9Sstevel@tonic-gate 			scfdie();
17787c478bd9Sstevel@tonic-gate 
17797c478bd9Sstevel@tonic-gate 		ret = scf_transaction_commit(tx);
17807c478bd9Sstevel@tonic-gate 		if (ret == -1) {
17817c478bd9Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
17827c478bd9Sstevel@tonic-gate 				scfdie();
17837c478bd9Sstevel@tonic-gate 
17847c478bd9Sstevel@tonic-gate 			if (!verbose)
17857c478bd9Sstevel@tonic-gate 				uu_warn(emsg_permission_denied, fmri);
17867c478bd9Sstevel@tonic-gate 			else
17877c478bd9Sstevel@tonic-gate 				uu_warn(emsg_prop_perm_denied, fmri, pgname,
17887c478bd9Sstevel@tonic-gate 				    propname);
17897c478bd9Sstevel@tonic-gate 			goto out;
17907c478bd9Sstevel@tonic-gate 		}
17917c478bd9Sstevel@tonic-gate 
17927c478bd9Sstevel@tonic-gate 		if (ret == 0) {
17937c478bd9Sstevel@tonic-gate 			scf_transaction_reset(tx);
17947c478bd9Sstevel@tonic-gate 
1795bc9767f9Stn 			if (scf_pg_update(pg) == -1)
17967c478bd9Sstevel@tonic-gate 				scfdie();
17977c478bd9Sstevel@tonic-gate 		}
17987c478bd9Sstevel@tonic-gate 	} while (ret == 0);
17997c478bd9Sstevel@tonic-gate 
18007c478bd9Sstevel@tonic-gate out:
18017c478bd9Sstevel@tonic-gate 	scf_transaction_destroy(tx);
18027c478bd9Sstevel@tonic-gate 	scf_entry_destroy(txent);
18037c478bd9Sstevel@tonic-gate 	scf_value_destroy(val);
18047c478bd9Sstevel@tonic-gate 	scf_property_destroy(prop);
18057c478bd9Sstevel@tonic-gate 	scf_pg_destroy(pg);
18067c478bd9Sstevel@tonic-gate 	scf_instance_destroy(inst);
18077c478bd9Sstevel@tonic-gate }
18087c478bd9Sstevel@tonic-gate 
18097c478bd9Sstevel@tonic-gate 
18107c478bd9Sstevel@tonic-gate static int
set_fmri_enabled(void * data,scf_walkinfo_t * wip)18117c478bd9Sstevel@tonic-gate set_fmri_enabled(void *data, scf_walkinfo_t *wip)
18127c478bd9Sstevel@tonic-gate {
18138fff7887SJohn Levon 	enable_data_t *ed = data;
18147c478bd9Sstevel@tonic-gate 
18157c478bd9Sstevel@tonic-gate 	assert(wip->inst != NULL);
18167c478bd9Sstevel@tonic-gate 	assert(wip->pg == NULL);
18177c478bd9Sstevel@tonic-gate 
181837b40227SJerry Jelinek 	if (svcsearch) {
181937b40227SJerry Jelinek 		char state[MAX_SCF_STATE_STRING_SZ];
182037b40227SJerry Jelinek 
182137b40227SJerry Jelinek 		if (inst_get_state(wip->inst, state, wip->fmri, NULL) != 0)
182237b40227SJerry Jelinek 			return (0);
182337b40227SJerry Jelinek 		if (strcmp(state, svcstate) != 0)
182437b40227SJerry Jelinek 			return (0);
182537b40227SJerry Jelinek 	}
182637b40227SJerry Jelinek 
18278fff7887SJohn Levon 	if (ed->ed_flags & SET_RECURSIVE) {
18287c478bd9Sstevel@tonic-gate 		char *fmri_buf = malloc(max_scf_fmri_sz);
18297c478bd9Sstevel@tonic-gate 		if (fmri_buf == NULL)
18307c478bd9Sstevel@tonic-gate 			uu_die(emsg_nomem);
18317c478bd9Sstevel@tonic-gate 
18327c478bd9Sstevel@tonic-gate 		visited = calloc(HT_BUCKETS, sizeof (*visited));
18337c478bd9Sstevel@tonic-gate 		if (visited == NULL)
18347c478bd9Sstevel@tonic-gate 			uu_die(emsg_nomem);
18357c478bd9Sstevel@tonic-gate 
18367c478bd9Sstevel@tonic-gate 		/* scf_walk_fmri() guarantees that fmri isn't too long */
18377c478bd9Sstevel@tonic-gate 		assert(strlen(wip->fmri) <= max_scf_fmri_sz);
18387c478bd9Sstevel@tonic-gate 		(void) strlcpy(fmri_buf, wip->fmri, max_scf_fmri_sz);
18397c478bd9Sstevel@tonic-gate 
18408fff7887SJohn Levon 		switch (enable_fmri_rec(fmri_buf, ed)) {
18417c478bd9Sstevel@tonic-gate 		case E2BIG:
18427c478bd9Sstevel@tonic-gate 			uu_warn(gettext("operation on service %s is ambiguous; "
18437c478bd9Sstevel@tonic-gate 			    "instance specification needed.\n"), fmri_buf);
18447c478bd9Sstevel@tonic-gate 			break;
18457c478bd9Sstevel@tonic-gate 
18467c478bd9Sstevel@tonic-gate 		case ELOOP:
18477c478bd9Sstevel@tonic-gate 			uu_warn(gettext("%s: Dependency cycle detected.\n"),
18487c478bd9Sstevel@tonic-gate 			    fmri_buf);
18497c478bd9Sstevel@tonic-gate 		}
18507c478bd9Sstevel@tonic-gate 
18517c478bd9Sstevel@tonic-gate 		free(visited);
18527c478bd9Sstevel@tonic-gate 		free(fmri_buf);
18537c478bd9Sstevel@tonic-gate 
18547c478bd9Sstevel@tonic-gate 	} else {
18558fff7887SJohn Levon 		set_inst_enabled(wip->fmri, wip->inst, ed);
18567c478bd9Sstevel@tonic-gate 	}
18577c478bd9Sstevel@tonic-gate 
18587c478bd9Sstevel@tonic-gate 	return (0);
18597c478bd9Sstevel@tonic-gate }
18607c478bd9Sstevel@tonic-gate 
18617c478bd9Sstevel@tonic-gate /* ARGSUSED */
18627c478bd9Sstevel@tonic-gate static int
wait_fmri_enabled(void * data,scf_walkinfo_t * wip)18637c478bd9Sstevel@tonic-gate wait_fmri_enabled(void *data, scf_walkinfo_t *wip)
18647c478bd9Sstevel@tonic-gate {
18657c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg = NULL;
18667c478bd9Sstevel@tonic-gate 	char state[MAX_SCF_STATE_STRING_SZ];
18677c478bd9Sstevel@tonic-gate 
18687c478bd9Sstevel@tonic-gate 	assert(wip->inst != NULL);
18697c478bd9Sstevel@tonic-gate 	assert(wip->pg == NULL);
18707c478bd9Sstevel@tonic-gate 
18717c478bd9Sstevel@tonic-gate 	do {
18727c478bd9Sstevel@tonic-gate 		if (pg)
18737c478bd9Sstevel@tonic-gate 			scf_pg_destroy(pg);
18747c478bd9Sstevel@tonic-gate 		if (inst_get_state(wip->inst, state, wip->fmri, &pg) != 0) {
18757c478bd9Sstevel@tonic-gate 			exit_status = EXIT_SVC_FAILURE;
18767c478bd9Sstevel@tonic-gate 			return (0);
18777c478bd9Sstevel@tonic-gate 		}
18787c478bd9Sstevel@tonic-gate 
18797c478bd9Sstevel@tonic-gate 		if (strcmp(state, SCF_STATE_STRING_ONLINE) == 0 ||
18807c478bd9Sstevel@tonic-gate 		    strcmp(state, SCF_STATE_STRING_DEGRADED) == 0) {
18817c478bd9Sstevel@tonic-gate 			/*
18827c478bd9Sstevel@tonic-gate 			 * We're done.
18837c478bd9Sstevel@tonic-gate 			 */
18847c478bd9Sstevel@tonic-gate 			goto out;
18857c478bd9Sstevel@tonic-gate 		}
18867c478bd9Sstevel@tonic-gate 
18877c478bd9Sstevel@tonic-gate 		if (strcmp(state, SCF_STATE_STRING_MAINT) == 0) {
18887c478bd9Sstevel@tonic-gate 			/*
18897c478bd9Sstevel@tonic-gate 			 * The service is ill.
18907c478bd9Sstevel@tonic-gate 			 */
18917c478bd9Sstevel@tonic-gate 			uu_warn(gettext("Instance \"%s\" is in maintenance"
18927c478bd9Sstevel@tonic-gate 			    " state.\n"), wip->fmri);
18937c478bd9Sstevel@tonic-gate 			exit_status = EXIT_SVC_FAILURE;
18947c478bd9Sstevel@tonic-gate 			goto out;
18957c478bd9Sstevel@tonic-gate 		}
18967c478bd9Sstevel@tonic-gate 
18977c478bd9Sstevel@tonic-gate 		if (!is_enabled(wip->inst)) {
18987c478bd9Sstevel@tonic-gate 			/*
18997c478bd9Sstevel@tonic-gate 			 * Someone stepped in and disabled the service.
19007c478bd9Sstevel@tonic-gate 			 */
19017c478bd9Sstevel@tonic-gate 			uu_warn(gettext("Instance \"%s\" has been disabled"
19027c478bd9Sstevel@tonic-gate 			    " by another entity.\n"), wip->fmri);
19037c478bd9Sstevel@tonic-gate 			exit_status = EXIT_SVC_FAILURE;
19047c478bd9Sstevel@tonic-gate 			goto out;
19057c478bd9Sstevel@tonic-gate 		}
19067c478bd9Sstevel@tonic-gate 
19077c478bd9Sstevel@tonic-gate 		if (!has_potential(wip->inst, B_FALSE)) {
19087c478bd9Sstevel@tonic-gate 			/*
19097c478bd9Sstevel@tonic-gate 			 * Our dependencies aren't met.  We'll never
19107c478bd9Sstevel@tonic-gate 			 * amount to anything.
19117c478bd9Sstevel@tonic-gate 			 */
19127c478bd9Sstevel@tonic-gate 			uu_warn(gettext("Instance \"%s\" has unsatisfied"
19137c478bd9Sstevel@tonic-gate 			    " dependencies.\n"), wip->fmri);
19147c478bd9Sstevel@tonic-gate 			/*
19157c478bd9Sstevel@tonic-gate 			 * EXIT_SVC_FAILURE takes precedence over
19167c478bd9Sstevel@tonic-gate 			 * EXIT_DEP_FAILURE
19177c478bd9Sstevel@tonic-gate 			 */
19187c478bd9Sstevel@tonic-gate 			if (exit_status == 0)
19197c478bd9Sstevel@tonic-gate 				exit_status = EXIT_DEP_FAILURE;
19207c478bd9Sstevel@tonic-gate 			goto out;
19217c478bd9Sstevel@tonic-gate 		}
19227c478bd9Sstevel@tonic-gate 	} while (_scf_pg_wait(pg, WAIT_INTERVAL) >= 0);
19237c478bd9Sstevel@tonic-gate 	scfdie();
19247c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
19257c478bd9Sstevel@tonic-gate 
19267c478bd9Sstevel@tonic-gate out:
19277c478bd9Sstevel@tonic-gate 	scf_pg_destroy(pg);
19287c478bd9Sstevel@tonic-gate 	return (0);
19297c478bd9Sstevel@tonic-gate }
19307c478bd9Sstevel@tonic-gate 
19317c478bd9Sstevel@tonic-gate /* ARGSUSED */
19327c478bd9Sstevel@tonic-gate static int
wait_fmri_disabled(void * data,scf_walkinfo_t * wip)19337c478bd9Sstevel@tonic-gate wait_fmri_disabled(void *data, scf_walkinfo_t *wip)
19347c478bd9Sstevel@tonic-gate {
19357c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg = NULL;
19367c478bd9Sstevel@tonic-gate 	char state[MAX_SCF_STATE_STRING_SZ];
19377c478bd9Sstevel@tonic-gate 
19387c478bd9Sstevel@tonic-gate 	assert(wip->inst != NULL);
19397c478bd9Sstevel@tonic-gate 	assert(wip->pg == NULL);
19407c478bd9Sstevel@tonic-gate 
19417c478bd9Sstevel@tonic-gate 	do {
19427c478bd9Sstevel@tonic-gate 		if (pg)
19437c478bd9Sstevel@tonic-gate 			scf_pg_destroy(pg);
19447c478bd9Sstevel@tonic-gate 		if (inst_get_state(wip->inst, state, wip->fmri, &pg) != 0) {
19457c478bd9Sstevel@tonic-gate 			exit_status = EXIT_SVC_FAILURE;
19467c478bd9Sstevel@tonic-gate 			return (0);
19477c478bd9Sstevel@tonic-gate 		}
19487c478bd9Sstevel@tonic-gate 
19497c478bd9Sstevel@tonic-gate 		if (strcmp(state, SCF_STATE_STRING_DISABLED) == 0) {
19507c478bd9Sstevel@tonic-gate 			/*
19517c478bd9Sstevel@tonic-gate 			 * We're done.
19527c478bd9Sstevel@tonic-gate 			 */
19537c478bd9Sstevel@tonic-gate 			goto out;
19547c478bd9Sstevel@tonic-gate 		}
19557c478bd9Sstevel@tonic-gate 
19567c478bd9Sstevel@tonic-gate 		if (is_enabled(wip->inst)) {
19577c478bd9Sstevel@tonic-gate 			/*
19587c478bd9Sstevel@tonic-gate 			 * Someone stepped in and enabled the service.
19597c478bd9Sstevel@tonic-gate 			 */
19607c478bd9Sstevel@tonic-gate 			uu_warn(gettext("Instance \"%s\" has been enabled"
19617c478bd9Sstevel@tonic-gate 			    " by another entity.\n"), wip->fmri);
19627c478bd9Sstevel@tonic-gate 			exit_status = EXIT_SVC_FAILURE;
19637c478bd9Sstevel@tonic-gate 			goto out;
19647c478bd9Sstevel@tonic-gate 		}
19657c478bd9Sstevel@tonic-gate 
19667c478bd9Sstevel@tonic-gate 		if (!has_potential(wip->inst, B_TRUE)) {
19677c478bd9Sstevel@tonic-gate 			/*
19687c478bd9Sstevel@tonic-gate 			 * Our restarter is hopeless.
19697c478bd9Sstevel@tonic-gate 			 */
19707c478bd9Sstevel@tonic-gate 			uu_warn(gettext("Restarter for instance \"%s\" is"
19717c478bd9Sstevel@tonic-gate 			    " unavailable.\n"), wip->fmri);
19727c478bd9Sstevel@tonic-gate 			/*
19737c478bd9Sstevel@tonic-gate 			 * EXIT_SVC_FAILURE takes precedence over
19747c478bd9Sstevel@tonic-gate 			 * EXIT_DEP_FAILURE
19757c478bd9Sstevel@tonic-gate 			 */
19767c478bd9Sstevel@tonic-gate 			if (exit_status == 0)
19777c478bd9Sstevel@tonic-gate 				exit_status = EXIT_DEP_FAILURE;
19787c478bd9Sstevel@tonic-gate 			goto out;
19797c478bd9Sstevel@tonic-gate 		}
19807c478bd9Sstevel@tonic-gate 
19817c478bd9Sstevel@tonic-gate 	} while (_scf_pg_wait(pg, WAIT_INTERVAL) >= 0);
19827c478bd9Sstevel@tonic-gate 	scfdie();
19837c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
19847c478bd9Sstevel@tonic-gate 
19857c478bd9Sstevel@tonic-gate out:
19867c478bd9Sstevel@tonic-gate 	scf_pg_destroy(pg);
19877c478bd9Sstevel@tonic-gate 	return (0);
19887c478bd9Sstevel@tonic-gate }
19897c478bd9Sstevel@tonic-gate 
19907c478bd9Sstevel@tonic-gate /* ARGSUSED */
19917c478bd9Sstevel@tonic-gate static int
clear_instance(void * data,scf_walkinfo_t * wip)19927c478bd9Sstevel@tonic-gate clear_instance(void *data, scf_walkinfo_t *wip)
19937c478bd9Sstevel@tonic-gate {
19947c478bd9Sstevel@tonic-gate 	char state[MAX_SCF_STATE_STRING_SZ];
19957c478bd9Sstevel@tonic-gate 
19967c478bd9Sstevel@tonic-gate 	assert(wip->inst != NULL);
19977c478bd9Sstevel@tonic-gate 	assert(wip->pg == NULL);
19987c478bd9Sstevel@tonic-gate 
19997c478bd9Sstevel@tonic-gate 	if (inst_get_state(wip->inst, state, wip->fmri, NULL) != 0)
20007c478bd9Sstevel@tonic-gate 		return (0);
20017c478bd9Sstevel@tonic-gate 
200237b40227SJerry Jelinek 	if (svcsearch && strcmp(state, svcstate) != 0)
200337b40227SJerry Jelinek 		return (0);
200437b40227SJerry Jelinek 
20057c478bd9Sstevel@tonic-gate 	if (strcmp(state, SCF_STATE_STRING_MAINT) == 0) {
20067c478bd9Sstevel@tonic-gate 		set_inst_action(wip->fmri, wip->inst, SCF_PROPERTY_MAINT_OFF);
20077c478bd9Sstevel@tonic-gate 	} else if (strcmp(state, SCF_STATE_STRING_DEGRADED) ==
20087c478bd9Sstevel@tonic-gate 	    0) {
20097c478bd9Sstevel@tonic-gate 		set_inst_action(wip->fmri, wip->inst, SCF_PROPERTY_RESTORE);
20107c478bd9Sstevel@tonic-gate 	} else {
20117c478bd9Sstevel@tonic-gate 		uu_warn(gettext("Instance \"%s\" is not in a "
20127c478bd9Sstevel@tonic-gate 		    "maintenance or degraded state.\n"), wip->fmri);
20137c478bd9Sstevel@tonic-gate 
20147c478bd9Sstevel@tonic-gate 		exit_status = 1;
20157c478bd9Sstevel@tonic-gate 	}
20167c478bd9Sstevel@tonic-gate 
20177c478bd9Sstevel@tonic-gate 	return (0);
20187c478bd9Sstevel@tonic-gate }
20197c478bd9Sstevel@tonic-gate 
20207c478bd9Sstevel@tonic-gate static int
set_fmri_action(void * action,scf_walkinfo_t * wip)20217c478bd9Sstevel@tonic-gate set_fmri_action(void *action, scf_walkinfo_t *wip)
20227c478bd9Sstevel@tonic-gate {
20237c478bd9Sstevel@tonic-gate 	assert(wip->inst != NULL && wip->pg == NULL);
20247c478bd9Sstevel@tonic-gate 
202537b40227SJerry Jelinek 	if (svcsearch) {
202637b40227SJerry Jelinek 		char state[MAX_SCF_STATE_STRING_SZ];
202737b40227SJerry Jelinek 
202837b40227SJerry Jelinek 		if (inst_get_state(wip->inst, state, wip->fmri, NULL) != 0)
202937b40227SJerry Jelinek 			return (0);
203037b40227SJerry Jelinek 		if (strcmp(state, svcstate) != 0)
203137b40227SJerry Jelinek 			return (0);
203237b40227SJerry Jelinek 	}
203337b40227SJerry Jelinek 
20347c478bd9Sstevel@tonic-gate 	set_inst_action(wip->fmri, wip->inst, action);
20357c478bd9Sstevel@tonic-gate 
20367c478bd9Sstevel@tonic-gate 	return (0);
20377c478bd9Sstevel@tonic-gate }
20387c478bd9Sstevel@tonic-gate 
20397c478bd9Sstevel@tonic-gate /*
20407c478bd9Sstevel@tonic-gate  * Flags to control 'mark' action.
20417c478bd9Sstevel@tonic-gate  */
20427c478bd9Sstevel@tonic-gate #define	MARK_IMMEDIATE	0x1
20437c478bd9Sstevel@tonic-gate #define	MARK_TEMPORARY	0x2
20447c478bd9Sstevel@tonic-gate 
20457c478bd9Sstevel@tonic-gate static int
force_degraded(void * data,scf_walkinfo_t * wip)20467c478bd9Sstevel@tonic-gate force_degraded(void *data, scf_walkinfo_t *wip)
20477c478bd9Sstevel@tonic-gate {
20487c478bd9Sstevel@tonic-gate 	int flags = (int)data;
20497c478bd9Sstevel@tonic-gate 	char state[MAX_SCF_STATE_STRING_SZ];
20507c478bd9Sstevel@tonic-gate 
20517c478bd9Sstevel@tonic-gate 	if (inst_get_state(wip->inst, state, wip->fmri, NULL) != 0) {
20527c478bd9Sstevel@tonic-gate 		exit_status = 1;
20537c478bd9Sstevel@tonic-gate 		return (0);
20547c478bd9Sstevel@tonic-gate 	}
20557c478bd9Sstevel@tonic-gate 
205637b40227SJerry Jelinek 	if (svcsearch && strcmp(state, svcstate) != 0)
205737b40227SJerry Jelinek 		return (0);
205837b40227SJerry Jelinek 
20597c478bd9Sstevel@tonic-gate 	if (strcmp(state, SCF_STATE_STRING_ONLINE) != 0) {
20607c478bd9Sstevel@tonic-gate 		uu_warn(gettext("Instance \"%s\" is not online.\n"), wip->fmri);
20617c478bd9Sstevel@tonic-gate 		exit_status = 1;
20627c478bd9Sstevel@tonic-gate 		return (0);
20637c478bd9Sstevel@tonic-gate 	}
20647c478bd9Sstevel@tonic-gate 
20657c478bd9Sstevel@tonic-gate 	set_inst_action(wip->fmri, wip->inst, (flags & MARK_IMMEDIATE) ?
20667c478bd9Sstevel@tonic-gate 	    SCF_PROPERTY_DEGRADE_IMMEDIATE : SCF_PROPERTY_DEGRADED);
20677c478bd9Sstevel@tonic-gate 
20687c478bd9Sstevel@tonic-gate 	return (0);
20697c478bd9Sstevel@tonic-gate }
20707c478bd9Sstevel@tonic-gate 
20717c478bd9Sstevel@tonic-gate static int
force_maintenance(void * data,scf_walkinfo_t * wip)20727c478bd9Sstevel@tonic-gate force_maintenance(void *data, scf_walkinfo_t *wip)
20737c478bd9Sstevel@tonic-gate {
20747c478bd9Sstevel@tonic-gate 	int flags = (int)data;
20757c478bd9Sstevel@tonic-gate 	const char *prop;
20767c478bd9Sstevel@tonic-gate 
207737b40227SJerry Jelinek 	if (svcsearch) {
207837b40227SJerry Jelinek 		char state[MAX_SCF_STATE_STRING_SZ];
207937b40227SJerry Jelinek 
208037b40227SJerry Jelinek 		if (inst_get_state(wip->inst, state, wip->fmri, NULL) != 0)
208137b40227SJerry Jelinek 			return (0);
208237b40227SJerry Jelinek 		if (strcmp(state, svcstate) != 0)
208337b40227SJerry Jelinek 			return (0);
208437b40227SJerry Jelinek 	}
208537b40227SJerry Jelinek 
20867c478bd9Sstevel@tonic-gate 	if (flags & MARK_IMMEDIATE) {
20877c478bd9Sstevel@tonic-gate 		prop = (flags & MARK_TEMPORARY) ?
20887c478bd9Sstevel@tonic-gate 		    SCF_PROPERTY_MAINT_ON_IMMTEMP :
20897c478bd9Sstevel@tonic-gate 		    SCF_PROPERTY_MAINT_ON_IMMEDIATE;
20907c478bd9Sstevel@tonic-gate 	} else {
20917c478bd9Sstevel@tonic-gate 		prop = (flags & MARK_TEMPORARY) ?
20927c478bd9Sstevel@tonic-gate 		    SCF_PROPERTY_MAINT_ON_TEMPORARY :
20937c478bd9Sstevel@tonic-gate 		    SCF_PROPERTY_MAINT_ON;
20947c478bd9Sstevel@tonic-gate 	}
20957c478bd9Sstevel@tonic-gate 
20967c478bd9Sstevel@tonic-gate 	set_inst_action(wip->fmri, wip->inst, prop);
20977c478bd9Sstevel@tonic-gate 
20987c478bd9Sstevel@tonic-gate 	return (0);
20997c478bd9Sstevel@tonic-gate }
21007c478bd9Sstevel@tonic-gate 
21017c478bd9Sstevel@tonic-gate static void
set_milestone(const char * fmri,boolean_t temporary)21027c478bd9Sstevel@tonic-gate set_milestone(const char *fmri, boolean_t temporary)
21037c478bd9Sstevel@tonic-gate {
21047c478bd9Sstevel@tonic-gate 	scf_instance_t *inst;
21057c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg;
21067c478bd9Sstevel@tonic-gate 
21077c478bd9Sstevel@tonic-gate 	if (temporary) {
21087c478bd9Sstevel@tonic-gate 		set_astring_prop(SCF_SERVICE_STARTD, SCF_PG_OPTIONS_OVR,
21097c478bd9Sstevel@tonic-gate 		    SCF_PG_OPTIONS_OVR_TYPE, SCF_PG_OPTIONS_OVR_FLAGS,
21107c478bd9Sstevel@tonic-gate 		    SCF_PROPERTY_MILESTONE, fmri);
21117c478bd9Sstevel@tonic-gate 		return;
21127c478bd9Sstevel@tonic-gate 	}
21137c478bd9Sstevel@tonic-gate 
21147c478bd9Sstevel@tonic-gate 	if ((inst = scf_instance_create(h)) == NULL ||
21157c478bd9Sstevel@tonic-gate 	    (pg = scf_pg_create(h)) == NULL)
21167c478bd9Sstevel@tonic-gate 		scfdie();
21177c478bd9Sstevel@tonic-gate 
21187c478bd9Sstevel@tonic-gate 	if (get_inst(SCF_SERVICE_STARTD, inst) != 0) {
21197c478bd9Sstevel@tonic-gate 		scf_instance_destroy(inst);
21207c478bd9Sstevel@tonic-gate 		return;
21217c478bd9Sstevel@tonic-gate 	}
21227c478bd9Sstevel@tonic-gate 
21237c478bd9Sstevel@tonic-gate 	/*
21247c478bd9Sstevel@tonic-gate 	 * Set the persistent milestone before deleting the override so we don't
21257c478bd9Sstevel@tonic-gate 	 * glitch.
21267c478bd9Sstevel@tonic-gate 	 */
21277c478bd9Sstevel@tonic-gate 	set_astring_prop(SCF_SERVICE_STARTD, SCF_PG_OPTIONS,
21287c478bd9Sstevel@tonic-gate 	    SCF_PG_OPTIONS_TYPE, SCF_PG_OPTIONS_FLAGS, SCF_PROPERTY_MILESTONE,
21297c478bd9Sstevel@tonic-gate 	    fmri);
21307c478bd9Sstevel@tonic-gate 
21318fff7887SJohn Levon 	if (delete_prop(SCF_SERVICE_STARTD, inst, SCF_PG_OPTIONS_OVR,
21328fff7887SJohn Levon 	    SCF_PROPERTY_MILESTONE) != 0)
2133eb1a3463STruong Nguyen 		exit_status = 1;
21347c478bd9Sstevel@tonic-gate 
21357c478bd9Sstevel@tonic-gate 	scf_pg_destroy(pg);
21367c478bd9Sstevel@tonic-gate 	scf_instance_destroy(inst);
21377c478bd9Sstevel@tonic-gate }
21387c478bd9Sstevel@tonic-gate 
21397c478bd9Sstevel@tonic-gate static char const *milestones[] = {
21407c478bd9Sstevel@tonic-gate 	SCF_MILESTONE_SINGLE_USER,
21417c478bd9Sstevel@tonic-gate 	SCF_MILESTONE_MULTI_USER,
21427c478bd9Sstevel@tonic-gate 	SCF_MILESTONE_MULTI_USER_SERVER,
21437c478bd9Sstevel@tonic-gate 	NULL
21447c478bd9Sstevel@tonic-gate };
21457c478bd9Sstevel@tonic-gate 
21467c478bd9Sstevel@tonic-gate static void
usage_milestone(void)21470b5c9250Shg usage_milestone(void)
21487c478bd9Sstevel@tonic-gate {
21497c478bd9Sstevel@tonic-gate 	const char **ms;
21507c478bd9Sstevel@tonic-gate 
21517c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(
21527c478bd9Sstevel@tonic-gate 	"Usage: svcadm milestone [-d] <milestone>\n\n"
21537c478bd9Sstevel@tonic-gate 	"\t-d\tmake the specified milestone the default for system boot\n\n"
21547c478bd9Sstevel@tonic-gate 	"\tMilestones can be specified using an FMRI or abbreviation.\n"
21557c478bd9Sstevel@tonic-gate 	"\tThe major milestones are as follows:\n\n"
21567c478bd9Sstevel@tonic-gate 	"\tall\n"
21577c478bd9Sstevel@tonic-gate 	"\tnone\n"));
21587c478bd9Sstevel@tonic-gate 
21597c478bd9Sstevel@tonic-gate 	for (ms = milestones; *ms != NULL; ms++)
21607c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "\t%s\n", *ms);
21617c478bd9Sstevel@tonic-gate 
21627c478bd9Sstevel@tonic-gate 	exit(UU_EXIT_USAGE);
21637c478bd9Sstevel@tonic-gate }
21647c478bd9Sstevel@tonic-gate 
21657c478bd9Sstevel@tonic-gate static const char *
validate_milestone(const char * milestone)21667c478bd9Sstevel@tonic-gate validate_milestone(const char *milestone)
21677c478bd9Sstevel@tonic-gate {
21687c478bd9Sstevel@tonic-gate 	const char **ms;
21697c478bd9Sstevel@tonic-gate 	const char *tmp;
21707c478bd9Sstevel@tonic-gate 	size_t len;
21717c478bd9Sstevel@tonic-gate 
21727c478bd9Sstevel@tonic-gate 	if (strcmp(milestone, "all") == 0)
21737c478bd9Sstevel@tonic-gate 		return (milestone);
21747c478bd9Sstevel@tonic-gate 
21757c478bd9Sstevel@tonic-gate 	if (strcmp(milestone, "none") == 0)
21767c478bd9Sstevel@tonic-gate 		return (milestone);
21777c478bd9Sstevel@tonic-gate 
21787c478bd9Sstevel@tonic-gate 	/*
21797c478bd9Sstevel@tonic-gate 	 * Determine if this is a full or partial milestone
21807c478bd9Sstevel@tonic-gate 	 */
21817c478bd9Sstevel@tonic-gate 	for (ms = milestones; *ms != NULL; ms++) {
21827c478bd9Sstevel@tonic-gate 		if ((tmp = strstr(*ms, milestone)) != NULL) {
21837c478bd9Sstevel@tonic-gate 			len = strlen(milestone);
21847c478bd9Sstevel@tonic-gate 
21857c478bd9Sstevel@tonic-gate 			/*
21867c478bd9Sstevel@tonic-gate 			 * The beginning of the string must align with the start
21877c478bd9Sstevel@tonic-gate 			 * of a milestone fmri, or on the boundary between
21887c478bd9Sstevel@tonic-gate 			 * elements.  The end of the string must align with the
21897c478bd9Sstevel@tonic-gate 			 * end of the milestone, or at the instance boundary.
21907c478bd9Sstevel@tonic-gate 			 */
21917c478bd9Sstevel@tonic-gate 			if ((tmp == *ms || tmp[-1] == '/') &&
21927c478bd9Sstevel@tonic-gate 			    (tmp[len] == '\0' || tmp[len] == ':'))
21937c478bd9Sstevel@tonic-gate 				return (*ms);
21947c478bd9Sstevel@tonic-gate 		}
21957c478bd9Sstevel@tonic-gate 	}
21967c478bd9Sstevel@tonic-gate 
21977c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
21987c478bd9Sstevel@tonic-gate 	    gettext("\"%s\" is not a valid major milestone.\n"), milestone);
21997c478bd9Sstevel@tonic-gate 
22007c478bd9Sstevel@tonic-gate 	usage_milestone();
22017c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
22027c478bd9Sstevel@tonic-gate }
22037c478bd9Sstevel@tonic-gate 
2204702a871aSJerry Jelinek /*PRINTFLIKE1*/
2205702a871aSJerry Jelinek static void
pr_warn(const char * format,...)2206702a871aSJerry Jelinek pr_warn(const char *format, ...)
2207702a871aSJerry Jelinek {
2208702a871aSJerry Jelinek 	const char *pname = uu_getpname();
2209702a871aSJerry Jelinek 	va_list alist;
2210702a871aSJerry Jelinek 
2211702a871aSJerry Jelinek 	va_start(alist, format);
2212702a871aSJerry Jelinek 
2213702a871aSJerry Jelinek 	if (pname != NULL)
2214702a871aSJerry Jelinek 		(void) fprintf(stderr, "%s", pname);
2215702a871aSJerry Jelinek 
2216702a871aSJerry Jelinek 	if (g_zonename != NULL)
2217702a871aSJerry Jelinek 		(void) fprintf(stderr, " (%s)", g_zonename);
2218702a871aSJerry Jelinek 
2219702a871aSJerry Jelinek 	(void) fprintf(stderr, ": ");
2220702a871aSJerry Jelinek 
2221702a871aSJerry Jelinek 	(void) vfprintf(stderr, format, alist);
2222702a871aSJerry Jelinek 
2223702a871aSJerry Jelinek 	if (strrchr(format, '\n') == NULL)
2224702a871aSJerry Jelinek 		(void) fprintf(stderr, ": %s\n", strerror(errno));
2225702a871aSJerry Jelinek 
2226702a871aSJerry Jelinek 	va_end(alist);
2227702a871aSJerry Jelinek }
2228702a871aSJerry Jelinek 
22297c478bd9Sstevel@tonic-gate /*ARGSUSED*/
22307c478bd9Sstevel@tonic-gate static void
quiet(const char * fmt,...)22317c478bd9Sstevel@tonic-gate quiet(const char *fmt, ...)
22327c478bd9Sstevel@tonic-gate {
22337c478bd9Sstevel@tonic-gate 	/* Do nothing */
22347c478bd9Sstevel@tonic-gate }
22357c478bd9Sstevel@tonic-gate 
22367c478bd9Sstevel@tonic-gate int
main(int argc,char * argv[])22377c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
22387c478bd9Sstevel@tonic-gate {
22397c478bd9Sstevel@tonic-gate 	int o;
22407c478bd9Sstevel@tonic-gate 	int err;
2241c0889d7aSstevep 	int sw_back;
2242702a871aSJerry Jelinek 	boolean_t do_zones = B_FALSE;
2243702a871aSJerry Jelinek 	boolean_t do_a_zone = B_FALSE;
2244702a871aSJerry Jelinek 	char zonename[ZONENAME_MAX];
2245702a871aSJerry Jelinek 	uint_t nzents = 0, zent = 0;
2246702a871aSJerry Jelinek 	zoneid_t *zids = NULL;
2247702a871aSJerry Jelinek 	int orig_optind, orig_argc;
2248702a871aSJerry Jelinek 	char **orig_argv;
22497c478bd9Sstevel@tonic-gate 
22507c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
22517c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
22527c478bd9Sstevel@tonic-gate 
22537c478bd9Sstevel@tonic-gate 	(void) uu_setpname(argv[0]);
22547c478bd9Sstevel@tonic-gate 
22557c478bd9Sstevel@tonic-gate 	if (argc < 2)
22567c478bd9Sstevel@tonic-gate 		usage();
22577c478bd9Sstevel@tonic-gate 
22587c478bd9Sstevel@tonic-gate 	max_scf_fmri_sz = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH);
22597c478bd9Sstevel@tonic-gate 	if (max_scf_fmri_sz < 0)
22607c478bd9Sstevel@tonic-gate 		scfdie();
22617c478bd9Sstevel@tonic-gate 	++max_scf_fmri_sz;
22627c478bd9Sstevel@tonic-gate 
22637c478bd9Sstevel@tonic-gate 	scratch_fmri = malloc(max_scf_fmri_sz);
22647c478bd9Sstevel@tonic-gate 	if (scratch_fmri == NULL)
22657c478bd9Sstevel@tonic-gate 		uu_die(emsg_nomem);
22667c478bd9Sstevel@tonic-gate 
226737b40227SJerry Jelinek 	while ((o = getopt(argc, argv, "S:vZz:")) != -1) {
2268647f8444SBryan Cantrill 		switch (o) {
226937b40227SJerry Jelinek 		case 'S':
227037b40227SJerry Jelinek 			(void) strlcpy(svcstate, optarg, sizeof (svcstate));
227137b40227SJerry Jelinek 			svcsearch = B_TRUE;
227237b40227SJerry Jelinek 			break;
227337b40227SJerry Jelinek 
2274647f8444SBryan Cantrill 		case 'v':
22757c478bd9Sstevel@tonic-gate 			verbose = 1;
2276647f8444SBryan Cantrill 			break;
2277647f8444SBryan Cantrill 
2278702a871aSJerry Jelinek 		case 'z':
2279647f8444SBryan Cantrill 			if (getzoneid() != GLOBAL_ZONEID)
2280647f8444SBryan Cantrill 				uu_die(gettext("svcadm -z may only be used "
2281647f8444SBryan Cantrill 				    "from the global zone\n"));
2282702a871aSJerry Jelinek 			if (do_zones)
2283702a871aSJerry Jelinek 				usage();
2284647f8444SBryan Cantrill 
2285702a871aSJerry Jelinek 			(void) strlcpy(zonename, optarg, sizeof (zonename));
2286702a871aSJerry Jelinek 			do_a_zone = B_TRUE;
2287702a871aSJerry Jelinek 			break;
2288647f8444SBryan Cantrill 
2289702a871aSJerry Jelinek 		case 'Z':
2290702a871aSJerry Jelinek 			if (getzoneid() != GLOBAL_ZONEID)
2291702a871aSJerry Jelinek 				uu_die(gettext("svcadm -Z may only be used "
2292702a871aSJerry Jelinek 				    "from the global zone\n"));
2293702a871aSJerry Jelinek 			if (do_a_zone)
2294702a871aSJerry Jelinek 				usage();
2295647f8444SBryan Cantrill 
2296702a871aSJerry Jelinek 			do_zones = B_TRUE;
2297647f8444SBryan Cantrill 			break;
2298647f8444SBryan Cantrill 
2299647f8444SBryan Cantrill 		default:
23007c478bd9Sstevel@tonic-gate 			usage();
2301647f8444SBryan Cantrill 		}
23027c478bd9Sstevel@tonic-gate 	}
23037c478bd9Sstevel@tonic-gate 
2304702a871aSJerry Jelinek 	while (do_zones) {
2305702a871aSJerry Jelinek 		uint_t found;
2306647f8444SBryan Cantrill 
2307702a871aSJerry Jelinek 		if (zone_list(NULL, &nzents) != 0)
2308702a871aSJerry Jelinek 			uu_die(gettext("could not get number of zones"));
2309702a871aSJerry Jelinek 
2310702a871aSJerry Jelinek 		if ((zids = malloc(nzents * sizeof (zoneid_t))) == NULL) {
2311702a871aSJerry Jelinek 			uu_die(gettext("could not allocate array for "
2312702a871aSJerry Jelinek 			    "%d zone IDs"), nzents);
2313702a871aSJerry Jelinek 		}
2314702a871aSJerry Jelinek 
2315702a871aSJerry Jelinek 		found = nzents;
2316702a871aSJerry Jelinek 
2317702a871aSJerry Jelinek 		if (zone_list(zids, &found) != 0)
2318702a871aSJerry Jelinek 			uu_die(gettext("could not get zone list"));
2319702a871aSJerry Jelinek 
2320702a871aSJerry Jelinek 		/*
2321702a871aSJerry Jelinek 		 * If the number of zones has not changed between our calls to
2322702a871aSJerry Jelinek 		 * zone_list(), we're done -- otherwise, we must free our array
2323702a871aSJerry Jelinek 		 * of zone IDs and take another lap.
2324702a871aSJerry Jelinek 		 */
2325702a871aSJerry Jelinek 		if (found == nzents)
2326702a871aSJerry Jelinek 			break;
2327702a871aSJerry Jelinek 
2328702a871aSJerry Jelinek 		free(zids);
2329702a871aSJerry Jelinek 	}
23307c478bd9Sstevel@tonic-gate 
23317c478bd9Sstevel@tonic-gate 	emsg_permission_denied = gettext("%s: Permission denied.\n");
23327c478bd9Sstevel@tonic-gate 	emsg_nomem = gettext("Out of memory.\n");
23337c478bd9Sstevel@tonic-gate 	emsg_create_pg_perm_denied = gettext("%s: Couldn't create \"%s\" "
23347c478bd9Sstevel@tonic-gate 	    "property group (permission denied).\n");
23357c478bd9Sstevel@tonic-gate 	emsg_pg_perm_denied = gettext("%s: Couldn't modify \"%s\" property "
23367c478bd9Sstevel@tonic-gate 	    "group (permission denied).\n");
23377c478bd9Sstevel@tonic-gate 	emsg_prop_perm_denied = gettext("%s: Couldn't modify \"%s/%s\" "
23387c478bd9Sstevel@tonic-gate 	    "property (permission denied).\n");
23397c478bd9Sstevel@tonic-gate 	emsg_no_service = gettext("No such service \"%s\".\n");
23407c478bd9Sstevel@tonic-gate 
2341702a871aSJerry Jelinek 	orig_optind = optind;
2342702a871aSJerry Jelinek 	orig_argc = argc;
2343702a871aSJerry Jelinek 	orig_argv = argv;
2344702a871aSJerry Jelinek 
2345702a871aSJerry Jelinek again:
2346702a871aSJerry Jelinek 	h = scf_handle_create(SCF_VERSION);
2347702a871aSJerry Jelinek 	if (h == NULL)
2348702a871aSJerry Jelinek 		scfdie();
2349702a871aSJerry Jelinek 
2350702a871aSJerry Jelinek 	if (do_zones) {
2351702a871aSJerry Jelinek 		zone_status_t status;
2352702a871aSJerry Jelinek 
2353702a871aSJerry Jelinek 		if (zone_getattr(zids[zent], ZONE_ATTR_STATUS, &status,
2354702a871aSJerry Jelinek 		    sizeof (status)) < 0 || status != ZONE_IS_RUNNING) {
2355702a871aSJerry Jelinek 			/*
2356702a871aSJerry Jelinek 			 * If this zone is not running or we cannot
2357702a871aSJerry Jelinek 			 * get its status, we do not want to attempt
2358702a871aSJerry Jelinek 			 * to bind an SCF handle to it, lest we
2359702a871aSJerry Jelinek 			 * accidentally interfere with a zone that
2360702a871aSJerry Jelinek 			 * is not yet running by looking up a door
2361702a871aSJerry Jelinek 			 * to its svc.configd (which could potentially
2362702a871aSJerry Jelinek 			 * block a mount with an EBUSY).
2363702a871aSJerry Jelinek 			 */
2364702a871aSJerry Jelinek 			zent++;
2365702a871aSJerry Jelinek 			goto nextzone;
2366702a871aSJerry Jelinek 		}
2367702a871aSJerry Jelinek 
2368702a871aSJerry Jelinek 		if (getzonenamebyid(zids[zent++], zonename,
2369702a871aSJerry Jelinek 		    sizeof (zonename)) < 0) {
2370702a871aSJerry Jelinek 			uu_warn(gettext("could not get name for "
2371702a871aSJerry Jelinek 			    "zone %d; ignoring"), zids[zent - 1]);
2372702a871aSJerry Jelinek 			goto nextzone;
2373702a871aSJerry Jelinek 		}
2374702a871aSJerry Jelinek 
2375702a871aSJerry Jelinek 		g_zonename = zonename;
2376702a871aSJerry Jelinek 	}
2377702a871aSJerry Jelinek 
2378702a871aSJerry Jelinek 	if (do_a_zone || do_zones) {
2379702a871aSJerry Jelinek 		scf_value_t *zone;
2380702a871aSJerry Jelinek 
2381702a871aSJerry Jelinek 		if ((zone = scf_value_create(h)) == NULL)
2382702a871aSJerry Jelinek 			scfdie();
2383702a871aSJerry Jelinek 
2384702a871aSJerry Jelinek 		if (scf_value_set_astring(zone, zonename) != SCF_SUCCESS)
2385702a871aSJerry Jelinek 			scfdie();
2386702a871aSJerry Jelinek 
2387702a871aSJerry Jelinek 		if (scf_handle_decorate(h, "zone", zone) != SCF_SUCCESS) {
2388702a871aSJerry Jelinek 			if (do_a_zone) {
2389*29267a9dSAndy Fiddaman 				uu_die(gettext("zone '%s': %s\n"),
2390*29267a9dSAndy Fiddaman 				    zonename, scf_strerror(scf_error()));
2391702a871aSJerry Jelinek 			} else {
2392702a871aSJerry Jelinek 				scf_value_destroy(zone);
2393702a871aSJerry Jelinek 				goto nextzone;
2394702a871aSJerry Jelinek 			}
2395702a871aSJerry Jelinek 		}
2396702a871aSJerry Jelinek 
2397702a871aSJerry Jelinek 		scf_value_destroy(zone);
2398702a871aSJerry Jelinek 	}
2399702a871aSJerry Jelinek 
2400702a871aSJerry Jelinek 	if (scf_handle_bind(h) == -1) {
2401702a871aSJerry Jelinek 		if (do_zones)
2402702a871aSJerry Jelinek 			goto nextzone;
2403702a871aSJerry Jelinek 
2404702a871aSJerry Jelinek 		uu_die(gettext("Couldn't bind to configuration repository: "
2405702a871aSJerry Jelinek 		    "%s.\n"), scf_strerror(scf_error()));
2406702a871aSJerry Jelinek 	}
2407702a871aSJerry Jelinek 
2408702a871aSJerry Jelinek 	optind = orig_optind;
2409702a871aSJerry Jelinek 	argc = orig_argc;
2410702a871aSJerry Jelinek 	argv = orig_argv;
2411702a871aSJerry Jelinek 
2412702a871aSJerry Jelinek 	if (optind >= argc)
2413702a871aSJerry Jelinek 		usage();
2414702a871aSJerry Jelinek 
24157c478bd9Sstevel@tonic-gate 	if (strcmp(argv[optind], "enable") == 0) {
24168fff7887SJohn Levon 		enable_data_t ed = {
24178fff7887SJohn Levon 			.ed_flags = SET_ENABLED,
24188fff7887SJohn Levon 			.ed_comment = ""
24198fff7887SJohn Levon 		};
24207c478bd9Sstevel@tonic-gate 		int wait = 0;
24217c478bd9Sstevel@tonic-gate 		int error = 0;
24227c478bd9Sstevel@tonic-gate 
24237c478bd9Sstevel@tonic-gate 		++optind;
24247c478bd9Sstevel@tonic-gate 
24257c478bd9Sstevel@tonic-gate 		while ((o = getopt(argc, argv, "rst")) != -1) {
24267c478bd9Sstevel@tonic-gate 			if (o == 'r')
24278fff7887SJohn Levon 				ed.ed_flags |= SET_RECURSIVE;
24287c478bd9Sstevel@tonic-gate 			else if (o == 't')
24298fff7887SJohn Levon 				ed.ed_flags |= SET_TEMPORARY;
24307c478bd9Sstevel@tonic-gate 			else if (o == 's')
24317c478bd9Sstevel@tonic-gate 				wait = 1;
24327c478bd9Sstevel@tonic-gate 			else if (o == '?')
24337c478bd9Sstevel@tonic-gate 				usage();
24347c478bd9Sstevel@tonic-gate 			else {
24357c478bd9Sstevel@tonic-gate 				assert(0);
24367c478bd9Sstevel@tonic-gate 				abort();
24377c478bd9Sstevel@tonic-gate 			}
24387c478bd9Sstevel@tonic-gate 		}
24397c478bd9Sstevel@tonic-gate 		argc -= optind;
24407c478bd9Sstevel@tonic-gate 		argv += optind;
24417c478bd9Sstevel@tonic-gate 
244237b40227SJerry Jelinek 		if (argc == 0 && !svcsearch)
244337b40227SJerry Jelinek 			usage();
244437b40227SJerry Jelinek 
244537b40227SJerry Jelinek 		if (argc > 0 && svcsearch)
24467c478bd9Sstevel@tonic-gate 			usage();
24477c478bd9Sstevel@tonic-gate 
24487c478bd9Sstevel@tonic-gate 		/*
24497c478bd9Sstevel@tonic-gate 		 * We want to continue with -s processing if we had
24507c478bd9Sstevel@tonic-gate 		 * invalid options, but not if an enable failed.  We
24517c478bd9Sstevel@tonic-gate 		 * squelch output the second time we walk fmris; we saw
24527c478bd9Sstevel@tonic-gate 		 * the errors the first time.
24537c478bd9Sstevel@tonic-gate 		 */
24546c7c876cSJerry Jelinek 		if ((err = scf_walk_fmri(h, argc, argv, WALK_FLAGS,
24558fff7887SJohn Levon 		    set_fmri_enabled, &ed, &error, pr_warn)) != 0) {
24567c478bd9Sstevel@tonic-gate 
2457702a871aSJerry Jelinek 			pr_warn(gettext("failed to iterate over "
24587c478bd9Sstevel@tonic-gate 			    "instances: %s\n"), scf_strerror(err));
24597c478bd9Sstevel@tonic-gate 			exit_status = UU_EXIT_FATAL;
24607c478bd9Sstevel@tonic-gate 
24617c478bd9Sstevel@tonic-gate 		} else if (wait && exit_status == 0 &&
24626c7c876cSJerry Jelinek 		    (err = scf_walk_fmri(h, argc, argv, WALK_FLAGS,
24638fff7887SJohn Levon 		    wait_fmri_enabled, NULL, &error, quiet)) != 0) {
24647c478bd9Sstevel@tonic-gate 
2465702a871aSJerry Jelinek 			pr_warn(gettext("failed to iterate over "
24667c478bd9Sstevel@tonic-gate 			    "instances: %s\n"), scf_strerror(err));
24677c478bd9Sstevel@tonic-gate 			exit_status = UU_EXIT_FATAL;
24687c478bd9Sstevel@tonic-gate 		}
24697c478bd9Sstevel@tonic-gate 
24707c478bd9Sstevel@tonic-gate 		if (error > 0)
24717c478bd9Sstevel@tonic-gate 			exit_status = error;
24727c478bd9Sstevel@tonic-gate 
24737c478bd9Sstevel@tonic-gate 	} else if (strcmp(argv[optind], "disable") == 0) {
24748fff7887SJohn Levon 		enable_data_t ed = {
24758fff7887SJohn Levon 			.ed_flags = 0,
24768fff7887SJohn Levon 			.ed_comment = ""
24778fff7887SJohn Levon 		};
24787c478bd9Sstevel@tonic-gate 		int wait = 0;
24797c478bd9Sstevel@tonic-gate 		int error = 0;
24807c478bd9Sstevel@tonic-gate 
24817c478bd9Sstevel@tonic-gate 		++optind;
24827c478bd9Sstevel@tonic-gate 
24838fff7887SJohn Levon 		while ((o = getopt(argc, argv, "c:st")) != -1) {
24848fff7887SJohn Levon 			if (o == 'c') {
24858fff7887SJohn Levon 				if (strlcpy(ed.ed_comment, optarg,
24868fff7887SJohn Levon 				    sizeof (ed.ed_comment)) >=
24878fff7887SJohn Levon 				    sizeof (ed.ed_comment)) {
24888fff7887SJohn Levon 					uu_die(gettext("disable -c comment "
24898fff7887SJohn Levon 					    "too long.\n"));
24908fff7887SJohn Levon 				}
24918fff7887SJohn Levon 			} else if (o == 't')
24928fff7887SJohn Levon 				ed.ed_flags |= SET_TEMPORARY;
24937c478bd9Sstevel@tonic-gate 			else if (o == 's')
24947c478bd9Sstevel@tonic-gate 				wait = 1;
24957c478bd9Sstevel@tonic-gate 			else if (o == '?')
24967c478bd9Sstevel@tonic-gate 				usage();
24977c478bd9Sstevel@tonic-gate 			else {
24987c478bd9Sstevel@tonic-gate 				assert(0);
24997c478bd9Sstevel@tonic-gate 				abort();
25007c478bd9Sstevel@tonic-gate 			}
25017c478bd9Sstevel@tonic-gate 		}
25027c478bd9Sstevel@tonic-gate 		argc -= optind;
25037c478bd9Sstevel@tonic-gate 		argv += optind;
25047c478bd9Sstevel@tonic-gate 
250537b40227SJerry Jelinek 		if (argc == 0 && !svcsearch)
250637b40227SJerry Jelinek 			usage();
250737b40227SJerry Jelinek 
250837b40227SJerry Jelinek 		if (argc > 0 && svcsearch)
25097c478bd9Sstevel@tonic-gate 			usage();
25107c478bd9Sstevel@tonic-gate 
25117c478bd9Sstevel@tonic-gate 		/*
25127c478bd9Sstevel@tonic-gate 		 * We want to continue with -s processing if we had
25137c478bd9Sstevel@tonic-gate 		 * invalid options, but not if a disable failed.  We
25147c478bd9Sstevel@tonic-gate 		 * squelch output the second time we walk fmris; we saw
25157c478bd9Sstevel@tonic-gate 		 * the errors the first time.
25167c478bd9Sstevel@tonic-gate 		 */
25176c7c876cSJerry Jelinek 		if ((err = scf_walk_fmri(h, argc, argv, WALK_FLAGS,
25188fff7887SJohn Levon 		    set_fmri_enabled, &ed, &exit_status,
2519702a871aSJerry Jelinek 		    pr_warn)) != 0) {
25207c478bd9Sstevel@tonic-gate 
2521702a871aSJerry Jelinek 			pr_warn(gettext("failed to iterate over "
25227c478bd9Sstevel@tonic-gate 			    "instances: %s\n"), scf_strerror(err));
25237c478bd9Sstevel@tonic-gate 			exit_status = UU_EXIT_FATAL;
25247c478bd9Sstevel@tonic-gate 
25257c478bd9Sstevel@tonic-gate 		} else if (wait && exit_status == 0 &&
25266c7c876cSJerry Jelinek 		    (err = scf_walk_fmri(h, argc, argv, WALK_FLAGS,
25278fff7887SJohn Levon 		    wait_fmri_disabled, NULL, &error, quiet)) != 0) {
25287c478bd9Sstevel@tonic-gate 
2529702a871aSJerry Jelinek 			pr_warn(gettext("failed to iterate over "
25307c478bd9Sstevel@tonic-gate 			    "instances: %s\n"), scf_strerror(err));
25317c478bd9Sstevel@tonic-gate 			exit_status = UU_EXIT_FATAL;
25327c478bd9Sstevel@tonic-gate 		}
25337c478bd9Sstevel@tonic-gate 
25347c478bd9Sstevel@tonic-gate 		if (error > 0)
25357c478bd9Sstevel@tonic-gate 			exit_status = error;
25367c478bd9Sstevel@tonic-gate 
25377c478bd9Sstevel@tonic-gate 	} else if (strcmp(argv[optind], "restart") == 0) {
2538ac0324d2SJerry Jelinek 		boolean_t do_dump = B_FALSE;
2539ac0324d2SJerry Jelinek 
25407c478bd9Sstevel@tonic-gate 		++optind;
2541ac0324d2SJerry Jelinek 
2542ac0324d2SJerry Jelinek 		while ((o = getopt(argc, argv, "d")) != -1) {
2543ac0324d2SJerry Jelinek 			if (o == 'd')
2544ac0324d2SJerry Jelinek 				do_dump = B_TRUE;
2545ac0324d2SJerry Jelinek 			else if (o == '?')
2546ac0324d2SJerry Jelinek 				usage();
2547ac0324d2SJerry Jelinek 			else {
2548ac0324d2SJerry Jelinek 				assert(0);
2549ac0324d2SJerry Jelinek 				abort();
2550ac0324d2SJerry Jelinek 			}
2551ac0324d2SJerry Jelinek 		}
255237b40227SJerry Jelinek 		argc -= optind;
255337b40227SJerry Jelinek 		argv += optind;
25547c478bd9Sstevel@tonic-gate 
255537b40227SJerry Jelinek 		if (argc == 0 && !svcsearch)
255637b40227SJerry Jelinek 			usage();
255737b40227SJerry Jelinek 
255837b40227SJerry Jelinek 		if (argc > 0 && svcsearch)
25597c478bd9Sstevel@tonic-gate 			usage();
25607c478bd9Sstevel@tonic-gate 
2561ac0324d2SJerry Jelinek 		if (do_dump) {
2562ac0324d2SJerry Jelinek 			if ((err = scf_walk_fmri(h, argc, argv, WALK_FLAGS,
2563ac0324d2SJerry Jelinek 			    set_fmri_action, (void *)SCF_PROPERTY_DODUMP,
2564ac0324d2SJerry Jelinek 			    &exit_status, pr_warn)) != 0) {
2565ac0324d2SJerry Jelinek 				pr_warn(gettext("failed to iterate over "
2566ac0324d2SJerry Jelinek 				    "instances: %s\n"), scf_strerror(err));
2567ac0324d2SJerry Jelinek 				exit_status = UU_EXIT_FATAL;
2568ac0324d2SJerry Jelinek 			}
2569ac0324d2SJerry Jelinek 		}
2570ac0324d2SJerry Jelinek 
257137b40227SJerry Jelinek 		if ((err = scf_walk_fmri(h, argc, argv, WALK_FLAGS,
257237b40227SJerry Jelinek 		    set_fmri_action, (void *)SCF_PROPERTY_RESTART, &exit_status,
2573702a871aSJerry Jelinek 		    pr_warn)) != 0) {
2574702a871aSJerry Jelinek 			pr_warn(gettext("failed to iterate over "
25757c478bd9Sstevel@tonic-gate 			    "instances: %s\n"), scf_strerror(err));
25767c478bd9Sstevel@tonic-gate 			exit_status = UU_EXIT_FATAL;
25777c478bd9Sstevel@tonic-gate 		}
25787c478bd9Sstevel@tonic-gate 
25797c478bd9Sstevel@tonic-gate 	} else if (strcmp(argv[optind], "refresh") == 0) {
25807c478bd9Sstevel@tonic-gate 		++optind;
258137b40227SJerry Jelinek 		argc -= optind;
258237b40227SJerry Jelinek 		argv += optind;
25837c478bd9Sstevel@tonic-gate 
258437b40227SJerry Jelinek 		if (argc == 0 && !svcsearch)
258537b40227SJerry Jelinek 			usage();
258637b40227SJerry Jelinek 
258737b40227SJerry Jelinek 		if (argc > 0 && svcsearch)
25887c478bd9Sstevel@tonic-gate 			usage();
25897c478bd9Sstevel@tonic-gate 
259037b40227SJerry Jelinek 		if ((err = scf_walk_fmri(h, argc, argv, WALK_FLAGS,
259137b40227SJerry Jelinek 		    set_fmri_action, (void *)SCF_PROPERTY_REFRESH, &exit_status,
2592702a871aSJerry Jelinek 		    pr_warn)) != 0) {
2593702a871aSJerry Jelinek 			pr_warn(gettext("failed to iterate over "
25947c478bd9Sstevel@tonic-gate 			    "instances: %s\n"), scf_strerror(scf_error()));
25957c478bd9Sstevel@tonic-gate 			exit_status = UU_EXIT_FATAL;
25967c478bd9Sstevel@tonic-gate 		}
25977c478bd9Sstevel@tonic-gate 
25987c478bd9Sstevel@tonic-gate 	} else if (strcmp(argv[optind], "mark") == 0) {
25997c478bd9Sstevel@tonic-gate 		int flags = 0;
26007c478bd9Sstevel@tonic-gate 		scf_walk_callback callback;
26017c478bd9Sstevel@tonic-gate 
26027c478bd9Sstevel@tonic-gate 		++optind;
26037c478bd9Sstevel@tonic-gate 
26047c478bd9Sstevel@tonic-gate 		while ((o = getopt(argc, argv, "It")) != -1) {
26057c478bd9Sstevel@tonic-gate 			if (o == 'I')
26067c478bd9Sstevel@tonic-gate 				flags |= MARK_IMMEDIATE;
26077c478bd9Sstevel@tonic-gate 			else if (o == 't')
26087c478bd9Sstevel@tonic-gate 				flags |= MARK_TEMPORARY;
26097c478bd9Sstevel@tonic-gate 			else if (o == '?')
26107c478bd9Sstevel@tonic-gate 				usage();
26117c478bd9Sstevel@tonic-gate 			else {
26127c478bd9Sstevel@tonic-gate 				assert(0);
26137c478bd9Sstevel@tonic-gate 				abort();
26147c478bd9Sstevel@tonic-gate 			}
26157c478bd9Sstevel@tonic-gate 		}
26167c478bd9Sstevel@tonic-gate 
26177c478bd9Sstevel@tonic-gate 		if (argc - optind < 2)
26187c478bd9Sstevel@tonic-gate 			usage();
26197c478bd9Sstevel@tonic-gate 
26207c478bd9Sstevel@tonic-gate 		if (strcmp(argv[optind], "degraded") == 0) {
26217c478bd9Sstevel@tonic-gate 			if (flags & MARK_TEMPORARY)
26227c478bd9Sstevel@tonic-gate 				uu_xdie(UU_EXIT_USAGE, gettext("-t may not be "
26237c478bd9Sstevel@tonic-gate 				    "used with degraded.\n"));
26247c478bd9Sstevel@tonic-gate 			callback = force_degraded;
26257c478bd9Sstevel@tonic-gate 
26267c478bd9Sstevel@tonic-gate 		} else if (strcmp(argv[optind], "maintenance") == 0) {
26277c478bd9Sstevel@tonic-gate 			callback = force_maintenance;
26287c478bd9Sstevel@tonic-gate 		} else {
26297c478bd9Sstevel@tonic-gate 			usage();
26307c478bd9Sstevel@tonic-gate 		}
26317c478bd9Sstevel@tonic-gate 
263237b40227SJerry Jelinek 		optind++;
263337b40227SJerry Jelinek 		argc -= optind;
263437b40227SJerry Jelinek 		argv += optind;
263537b40227SJerry Jelinek 
263637b40227SJerry Jelinek 		if (argc == 0 && !svcsearch)
263737b40227SJerry Jelinek 			usage();
263837b40227SJerry Jelinek 
263937b40227SJerry Jelinek 		if (argc > 0 && svcsearch)
264037b40227SJerry Jelinek 			usage();
264137b40227SJerry Jelinek 
264237b40227SJerry Jelinek 		if ((err = scf_walk_fmri(h, argc, argv, WALK_FLAGS, callback,
264337b40227SJerry Jelinek 		    NULL, &exit_status, pr_warn)) != 0) {
2644702a871aSJerry Jelinek 			pr_warn(gettext("failed to iterate over "
26457c478bd9Sstevel@tonic-gate 			    "instances: %s\n"),
26467c478bd9Sstevel@tonic-gate 			    scf_strerror(err));
26477c478bd9Sstevel@tonic-gate 			exit_status = UU_EXIT_FATAL;
26487c478bd9Sstevel@tonic-gate 		}
26497c478bd9Sstevel@tonic-gate 
26507c478bd9Sstevel@tonic-gate 	} else if (strcmp(argv[optind], "clear") == 0) {
26517c478bd9Sstevel@tonic-gate 		++optind;
265237b40227SJerry Jelinek 		argc -= optind;
265337b40227SJerry Jelinek 		argv += optind;
26547c478bd9Sstevel@tonic-gate 
265537b40227SJerry Jelinek 		if (argc == 0 && !svcsearch)
26567c478bd9Sstevel@tonic-gate 			usage();
26577c478bd9Sstevel@tonic-gate 
265837b40227SJerry Jelinek 		if (svcsearch) {
265937b40227SJerry Jelinek 			if (argc > 0)
266037b40227SJerry Jelinek 				usage();
266137b40227SJerry Jelinek 			if (strcmp(svcstate, SCF_STATE_STRING_MAINT) != 0 &&
266237b40227SJerry Jelinek 			    strcmp(svcstate, SCF_STATE_STRING_DEGRADED) != 0)
266337b40227SJerry Jelinek 				uu_die(gettext("State must be '%s' or '%s'\n"),
266437b40227SJerry Jelinek 				    SCF_STATE_STRING_MAINT,
266537b40227SJerry Jelinek 				    SCF_STATE_STRING_DEGRADED);
266637b40227SJerry Jelinek 		}
266737b40227SJerry Jelinek 
266837b40227SJerry Jelinek 		if ((err = scf_walk_fmri(h, argc, argv, WALK_FLAGS,
266937b40227SJerry Jelinek 		    clear_instance, NULL, &exit_status, pr_warn)) != 0) {
2670702a871aSJerry Jelinek 			pr_warn(gettext("failed to iterate over "
26717c478bd9Sstevel@tonic-gate 			    "instances: %s\n"), scf_strerror(err));
26727c478bd9Sstevel@tonic-gate 			exit_status = UU_EXIT_FATAL;
26737c478bd9Sstevel@tonic-gate 		}
26747c478bd9Sstevel@tonic-gate 
26757c478bd9Sstevel@tonic-gate 	} else if (strcmp(argv[optind], "milestone") == 0) {
26767c478bd9Sstevel@tonic-gate 		boolean_t temporary = B_TRUE;
26777c478bd9Sstevel@tonic-gate 		const char *milestone;
26787c478bd9Sstevel@tonic-gate 
26797c478bd9Sstevel@tonic-gate 		++optind;
26807c478bd9Sstevel@tonic-gate 
26817c478bd9Sstevel@tonic-gate 		while ((o = getopt(argc, argv, "d")) != -1) {
26827c478bd9Sstevel@tonic-gate 			if (o == 'd')
26837c478bd9Sstevel@tonic-gate 				temporary = B_FALSE;
26847c478bd9Sstevel@tonic-gate 			else if (o == '?')
26857c478bd9Sstevel@tonic-gate 				usage_milestone();
26867c478bd9Sstevel@tonic-gate 			else {
26877c478bd9Sstevel@tonic-gate 				assert(0);
26887c478bd9Sstevel@tonic-gate 				abort();
26897c478bd9Sstevel@tonic-gate 			}
26907c478bd9Sstevel@tonic-gate 		}
26917c478bd9Sstevel@tonic-gate 
26927c478bd9Sstevel@tonic-gate 		if (optind >= argc)
26937c478bd9Sstevel@tonic-gate 			usage_milestone();
26947c478bd9Sstevel@tonic-gate 
26957c478bd9Sstevel@tonic-gate 		milestone = validate_milestone(argv[optind]);
26967c478bd9Sstevel@tonic-gate 
26977c478bd9Sstevel@tonic-gate 		set_milestone(milestone, temporary);
26987c478bd9Sstevel@tonic-gate 	} else if (strcmp(argv[optind], "_smf_backup") == 0) {
26997c478bd9Sstevel@tonic-gate 		const char *reason = NULL;
27007c478bd9Sstevel@tonic-gate 
27017c478bd9Sstevel@tonic-gate 		++optind;
27027c478bd9Sstevel@tonic-gate 
27037c478bd9Sstevel@tonic-gate 		if (optind != argc - 1)
27047c478bd9Sstevel@tonic-gate 			usage();
27057c478bd9Sstevel@tonic-gate 
27067c478bd9Sstevel@tonic-gate 		if ((err = _scf_request_backup(h, argv[optind])) !=
27077c478bd9Sstevel@tonic-gate 		    SCF_SUCCESS) {
27087c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
27097c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_BOUND:
27107c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
27117c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_READONLY:
27127c478bd9Sstevel@tonic-gate 				scfdie();
27137c478bd9Sstevel@tonic-gate 				break;
27147c478bd9Sstevel@tonic-gate 
27157c478bd9Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
27167c478bd9Sstevel@tonic-gate 			case SCF_ERROR_INVALID_ARGUMENT:
27177c478bd9Sstevel@tonic-gate 				reason = scf_strerror(scf_error());
27187c478bd9Sstevel@tonic-gate 				break;
27197c478bd9Sstevel@tonic-gate 
27207c478bd9Sstevel@tonic-gate 			case SCF_ERROR_INTERNAL:
27217c478bd9Sstevel@tonic-gate 				reason =
27227c478bd9Sstevel@tonic-gate 				    "unknown error (see console for details)";
27237c478bd9Sstevel@tonic-gate 				break;
27247c478bd9Sstevel@tonic-gate 			}
2725c0889d7aSstevep 
2726702a871aSJerry Jelinek 			pr_warn("failed to backup repository: %s\n", reason);
27277c478bd9Sstevel@tonic-gate 			exit_status = UU_EXIT_FATAL;
27287c478bd9Sstevel@tonic-gate 		}
2729c0889d7aSstevep 	} else if (strcmp(argv[optind], "_smf_repository_switch") == 0) {
2730c0889d7aSstevep 		const char *reason = NULL;
2731c0889d7aSstevep 
2732c0889d7aSstevep 		++optind;
2733c0889d7aSstevep 
2734c0889d7aSstevep 		/*
2735c0889d7aSstevep 		 * Check argument and setup scf_switch structure
2736c0889d7aSstevep 		 */
2737c0889d7aSstevep 		if (optind != argc - 1)
2738c0889d7aSstevep 			exit(1);
2739c0889d7aSstevep 
2740c0889d7aSstevep 		if (strcmp(argv[optind], "fast") == 0) {
2741c0889d7aSstevep 			sw_back = 0;
2742c0889d7aSstevep 		} else if (strcmp(argv[optind], "perm") == 0) {
2743c0889d7aSstevep 			sw_back = 1;
2744c0889d7aSstevep 		} else {
2745c0889d7aSstevep 			exit(UU_EXIT_USAGE);
2746c0889d7aSstevep 		}
2747c0889d7aSstevep 
2748c0889d7aSstevep 		/*
2749c0889d7aSstevep 		 * Call into switch primitive
2750c0889d7aSstevep 		 */
2751c0889d7aSstevep 		if ((err = _scf_repository_switch(h, sw_back)) !=
2752c0889d7aSstevep 		    SCF_SUCCESS) {
2753c0889d7aSstevep 			/*
2754c0889d7aSstevep 			 * Retrieve per thread SCF error code
2755c0889d7aSstevep 			 */
2756c0889d7aSstevep 			switch (scf_error()) {
2757c0889d7aSstevep 			case SCF_ERROR_NOT_BOUND:
2758c0889d7aSstevep 				abort();
2759c0889d7aSstevep 				/* NOTREACHED */
2760c0889d7aSstevep 
2761c0889d7aSstevep 			case SCF_ERROR_CONNECTION_BROKEN:
2762c0889d7aSstevep 			case SCF_ERROR_BACKEND_READONLY:
2763c0889d7aSstevep 				scfdie();
2764c0889d7aSstevep 				/* NOTREACHED */
2765c0889d7aSstevep 
2766c0889d7aSstevep 			case SCF_ERROR_PERMISSION_DENIED:
2767c0889d7aSstevep 			case SCF_ERROR_INVALID_ARGUMENT:
2768c0889d7aSstevep 				reason = scf_strerror(scf_error());
2769c0889d7aSstevep 				break;
2770c0889d7aSstevep 
2771c0889d7aSstevep 			case SCF_ERROR_INTERNAL:
2772c0889d7aSstevep 				reason = "File operation error: (see console)";
2773c0889d7aSstevep 				break;
2774c0889d7aSstevep 
2775c0889d7aSstevep 			default:
2776c0889d7aSstevep 				abort();
2777c0889d7aSstevep 				/* NOTREACHED */
2778c0889d7aSstevep 			}
2779c0889d7aSstevep 
2780702a871aSJerry Jelinek 			pr_warn("failed to switch repository: %s\n", reason);
2781c0889d7aSstevep 			exit_status = UU_EXIT_FATAL;
2782c0889d7aSstevep 		}
27837c478bd9Sstevel@tonic-gate 	} else {
27847c478bd9Sstevel@tonic-gate 		usage();
27857c478bd9Sstevel@tonic-gate 	}
27867c478bd9Sstevel@tonic-gate 
27877c478bd9Sstevel@tonic-gate 	if (scf_handle_unbind(h) == -1)
27887c478bd9Sstevel@tonic-gate 		scfdie();
2789702a871aSJerry Jelinek nextzone:
27907c478bd9Sstevel@tonic-gate 	scf_handle_destroy(h);
2791702a871aSJerry Jelinek 	if (do_zones && zent < nzents)
2792702a871aSJerry Jelinek 		goto again;
27937c478bd9Sstevel@tonic-gate 
27947c478bd9Sstevel@tonic-gate 	return (exit_status);
27957c478bd9Sstevel@tonic-gate }
2796