xref: /illumos-gate/usr/src/cmd/svc/svcadm/svcadm.c (revision 6c7c876ca6ff79eaf105ad9329de9003cabead35)
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 /*
27*6c7c876cSJerry Jelinek  * Copyright 2013, Joyent, Inc. All rights reserved.
28647f8444SBryan Cantrill  */
29647f8444SBryan Cantrill 
307c478bd9Sstevel@tonic-gate /*
317c478bd9Sstevel@tonic-gate  * svcadm - request adminstrative actions for service instances
327c478bd9Sstevel@tonic-gate  */
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate #include <locale.h>
357c478bd9Sstevel@tonic-gate #include <libintl.h>
367c478bd9Sstevel@tonic-gate #include <libscf.h>
377c478bd9Sstevel@tonic-gate #include <libscf_priv.h>
38eb1a3463STruong Nguyen #include <libcontract.h>
39eb1a3463STruong Nguyen #include <libcontract_priv.h>
40eb1a3463STruong Nguyen #include <sys/contract/process.h>
417c478bd9Sstevel@tonic-gate #include <libuutil.h>
427c478bd9Sstevel@tonic-gate #include <stddef.h>
437c478bd9Sstevel@tonic-gate #include <stdio.h>
447c478bd9Sstevel@tonic-gate #include <stdlib.h>
457c478bd9Sstevel@tonic-gate #include <string.h>
467c478bd9Sstevel@tonic-gate #include <unistd.h>
47eb1a3463STruong Nguyen #include <fcntl.h>
48eb1a3463STruong Nguyen #include <procfs.h>
497c478bd9Sstevel@tonic-gate #include <assert.h>
507c478bd9Sstevel@tonic-gate #include <errno.h>
51647f8444SBryan Cantrill #include <zone.h>
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate #ifndef TEXT_DOMAIN
547c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN	"SUNW_OST_OSCMD"
557c478bd9Sstevel@tonic-gate #endif /* TEXT_DOMAIN */
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate /* Must be a power of two */
587c478bd9Sstevel@tonic-gate #define	HT_BUCKETS	64
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate /*
617c478bd9Sstevel@tonic-gate  * Exit codes for enable and disable -s.
627c478bd9Sstevel@tonic-gate  */
637c478bd9Sstevel@tonic-gate #define	EXIT_SVC_FAILURE	3
647c478bd9Sstevel@tonic-gate #define	EXIT_DEP_FAILURE	4
657c478bd9Sstevel@tonic-gate 
66*6c7c876cSJerry Jelinek #define	WALK_FLAGS	(SCF_WALK_UNIPARTIAL | SCF_WALK_MULTIPLE)
67*6c7c876cSJerry Jelinek 
687c478bd9Sstevel@tonic-gate /*
697c478bd9Sstevel@tonic-gate  * How long we will wait (in seconds) for a service to change state
707c478bd9Sstevel@tonic-gate  * before re-checking its dependencies.
717c478bd9Sstevel@tonic-gate  */
727c478bd9Sstevel@tonic-gate #define	WAIT_INTERVAL		3
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate #ifndef NDEBUG
757c478bd9Sstevel@tonic-gate #define	bad_error(func, err)	{					\
767c478bd9Sstevel@tonic-gate 	uu_warn("%s:%d: %s() failed with unexpected error %d.\n",	\
777c478bd9Sstevel@tonic-gate 	    __FILE__, __LINE__, (func), (err));				\
787c478bd9Sstevel@tonic-gate 	abort();							\
797c478bd9Sstevel@tonic-gate }
807c478bd9Sstevel@tonic-gate #else
817c478bd9Sstevel@tonic-gate #define	bad_error(func, err)	abort()
827c478bd9Sstevel@tonic-gate #endif
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate struct ht_elt {
867c478bd9Sstevel@tonic-gate 	struct ht_elt	*next;
877c478bd9Sstevel@tonic-gate 	boolean_t	active;
887c478bd9Sstevel@tonic-gate 	char		str[1];
897c478bd9Sstevel@tonic-gate };
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate scf_handle_t *h;
937c478bd9Sstevel@tonic-gate ssize_t max_scf_fmri_sz;
947c478bd9Sstevel@tonic-gate static const char *emsg_permission_denied;
957c478bd9Sstevel@tonic-gate static const char *emsg_nomem;
967c478bd9Sstevel@tonic-gate static const char *emsg_create_pg_perm_denied;
977c478bd9Sstevel@tonic-gate static const char *emsg_pg_perm_denied;
987c478bd9Sstevel@tonic-gate static const char *emsg_prop_perm_denied;
997c478bd9Sstevel@tonic-gate static const char *emsg_no_service;
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate static int exit_status = 0;
1027c478bd9Sstevel@tonic-gate static int verbose = 0;
1037c478bd9Sstevel@tonic-gate static char *scratch_fmri;
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate static struct ht_elt **visited;
1067c478bd9Sstevel@tonic-gate 
1070b5c9250Shg void do_scfdie(int lineno) __NORETURN;
1080b5c9250Shg static void usage_milestone(void) __NORETURN;
109eb1a3463STruong Nguyen static void set_astring_prop(const char *, const char *, const char *,
110eb1a3463STruong Nguyen     uint32_t, const char *, const char *);
1110b5c9250Shg 
1127c478bd9Sstevel@tonic-gate /*
1137c478bd9Sstevel@tonic-gate  * Visitors from synch.c, needed for enable -s and disable -s.
1147c478bd9Sstevel@tonic-gate  */
1157c478bd9Sstevel@tonic-gate extern int is_enabled(scf_instance_t *);
1167c478bd9Sstevel@tonic-gate extern int has_potential(scf_instance_t *, int);
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate void
1197c478bd9Sstevel@tonic-gate do_scfdie(int lineno)
1207c478bd9Sstevel@tonic-gate {
1217c478bd9Sstevel@tonic-gate 	scf_error_t err;
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate 	switch (err = scf_error()) {
1247c478bd9Sstevel@tonic-gate 	case SCF_ERROR_CONNECTION_BROKEN:
1257c478bd9Sstevel@tonic-gate 		uu_die(gettext("Connection to repository server broken.  "
1267c478bd9Sstevel@tonic-gate 		    "Exiting.\n"));
1277c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate 	case SCF_ERROR_BACKEND_READONLY:
1307c478bd9Sstevel@tonic-gate 		uu_die(gettext("Repository is read-only.  Exiting.\n"));
1317c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate 	default:
1347c478bd9Sstevel@tonic-gate #ifdef NDEBUG
1357c478bd9Sstevel@tonic-gate 		uu_die(gettext("Unexpected libscf error: %s.  Exiting.\n"),
1367c478bd9Sstevel@tonic-gate 		    scf_strerror(err));
1377c478bd9Sstevel@tonic-gate #else
1387c478bd9Sstevel@tonic-gate 		uu_die("Unexpected libscf error on line %d: %s.\n", lineno,
1397c478bd9Sstevel@tonic-gate 		    scf_strerror(err));
1407c478bd9Sstevel@tonic-gate #endif
1417c478bd9Sstevel@tonic-gate 	}
1427c478bd9Sstevel@tonic-gate }
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate #define	scfdie()	do_scfdie(__LINE__)
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate static void
1477c478bd9Sstevel@tonic-gate usage()
1487c478bd9Sstevel@tonic-gate {
1497c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(
150647f8444SBryan Cantrill 	"Usage: %1$s [-v] [-z zone] [cmd [args ... ]]\n\n"
1517c478bd9Sstevel@tonic-gate 	"\t%1$s enable [-rst] <service> ...\t- enable and online service(s)\n"
1527c478bd9Sstevel@tonic-gate 	"\t%1$s disable [-st] <service> ...\t- disable and offline service(s)\n"
1537c478bd9Sstevel@tonic-gate 	"\t%1$s restart <service> ...\t\t- restart specified service(s)\n"
1547c478bd9Sstevel@tonic-gate 	"\t%1$s refresh <service> ...\t\t- re-read service configuration\n"
1557c478bd9Sstevel@tonic-gate 	"\t%1$s mark [-It] <state> <service> ...\t- set maintenance state\n"
1567c478bd9Sstevel@tonic-gate 	"\t%1$s clear <service> ...\t\t- clear maintenance state\n"
1577c478bd9Sstevel@tonic-gate 	"\t%1$s milestone [-d] <milestone>\t- advance to a service milestone\n"
1587c478bd9Sstevel@tonic-gate 	"\n\t"
1597c478bd9Sstevel@tonic-gate 	"Services can be specified using an FMRI, abbreviation, or fnmatch(5)\n"
1607c478bd9Sstevel@tonic-gate 	"\tpattern, as shown in these examples for svc:/network/smtp:sendmail\n"
1617c478bd9Sstevel@tonic-gate 	"\n"
1627c478bd9Sstevel@tonic-gate 	"\t%1$s <cmd> svc:/network/smtp:sendmail\n"
1637c478bd9Sstevel@tonic-gate 	"\t%1$s <cmd> network/smtp:sendmail\n"
1647c478bd9Sstevel@tonic-gate 	"\t%1$s <cmd> network/*mail\n"
1657c478bd9Sstevel@tonic-gate 	"\t%1$s <cmd> network/smtp\n"
1667c478bd9Sstevel@tonic-gate 	"\t%1$s <cmd> smtp:sendmail\n"
1677c478bd9Sstevel@tonic-gate 	"\t%1$s <cmd> smtp\n"
1687c478bd9Sstevel@tonic-gate 	"\t%1$s <cmd> sendmail\n"), uu_getpname());
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate 	exit(UU_EXIT_USAGE);
1717c478bd9Sstevel@tonic-gate }
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate /*
1757c478bd9Sstevel@tonic-gate  * FMRI hash table for recursive enable.
1767c478bd9Sstevel@tonic-gate  */
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate static uint32_t
1797c478bd9Sstevel@tonic-gate hash_fmri(const char *str)
1807c478bd9Sstevel@tonic-gate {
1817c478bd9Sstevel@tonic-gate 	uint32_t h = 0, g;
1827c478bd9Sstevel@tonic-gate 	const char *p;
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate 	/* Generic hash function from uts/common/os/modhash.c . */
1857c478bd9Sstevel@tonic-gate 	for (p = str; *p != '\0'; ++p) {
1867c478bd9Sstevel@tonic-gate 		h = (h << 4) + *p;
1877c478bd9Sstevel@tonic-gate 		if ((g = (h & 0xf0000000)) != 0) {
1887c478bd9Sstevel@tonic-gate 			h ^= (g >> 24);
1897c478bd9Sstevel@tonic-gate 			h ^= g;
1907c478bd9Sstevel@tonic-gate 		}
1917c478bd9Sstevel@tonic-gate 	}
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate 	return (h);
1947c478bd9Sstevel@tonic-gate }
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate /*
1977c478bd9Sstevel@tonic-gate  * Return 1 if str has been visited, 0 if it has not, and -1 if memory could not
1987c478bd9Sstevel@tonic-gate  * be allocated.
1997c478bd9Sstevel@tonic-gate  */
2007c478bd9Sstevel@tonic-gate static int
2017c478bd9Sstevel@tonic-gate visited_find_or_add(const char *str, struct ht_elt **hep)
2027c478bd9Sstevel@tonic-gate {
2037c478bd9Sstevel@tonic-gate 	uint32_t h;
2047c478bd9Sstevel@tonic-gate 	uint_t i;
2057c478bd9Sstevel@tonic-gate 	struct ht_elt *he;
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate 	h = hash_fmri(str);
2087c478bd9Sstevel@tonic-gate 	i = h & (HT_BUCKETS - 1);
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	for (he = visited[i]; he != NULL; he = he->next) {
2117c478bd9Sstevel@tonic-gate 		if (strcmp(he->str, str) == 0) {
2127c478bd9Sstevel@tonic-gate 			if (hep)
2137c478bd9Sstevel@tonic-gate 				*hep = he;
2147c478bd9Sstevel@tonic-gate 			return (1);
2157c478bd9Sstevel@tonic-gate 		}
2167c478bd9Sstevel@tonic-gate 	}
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate 	he = malloc(offsetof(struct ht_elt, str) + strlen(str) + 1);
2197c478bd9Sstevel@tonic-gate 	if (he == NULL)
2207c478bd9Sstevel@tonic-gate 		return (-1);
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate 	(void) strcpy(he->str, str);
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate 	he->next = visited[i];
2257c478bd9Sstevel@tonic-gate 	visited[i] = he;
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 	if (hep)
2287c478bd9Sstevel@tonic-gate 		*hep = he;
2297c478bd9Sstevel@tonic-gate 	return (0);
2307c478bd9Sstevel@tonic-gate }
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate /*
2347c478bd9Sstevel@tonic-gate  * Returns 0, ECANCELED if pg is deleted, ENOENT if propname doesn't exist,
2357c478bd9Sstevel@tonic-gate  * EINVAL if the property is not of boolean type or has no values, and E2BIG
2367c478bd9Sstevel@tonic-gate  * if it has more than one value.  *bp is set if 0 or E2BIG is returned.
2377c478bd9Sstevel@tonic-gate  */
2387c478bd9Sstevel@tonic-gate int
2397c478bd9Sstevel@tonic-gate get_bool_prop(scf_propertygroup_t *pg, const char *propname, uint8_t *bp)
2407c478bd9Sstevel@tonic-gate {
2417c478bd9Sstevel@tonic-gate 	scf_property_t *prop;
2427c478bd9Sstevel@tonic-gate 	scf_value_t *val;
2437c478bd9Sstevel@tonic-gate 	int ret;
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate 	if ((prop = scf_property_create(h)) == NULL ||
2467c478bd9Sstevel@tonic-gate 	    (val = scf_value_create(h)) == NULL)
2477c478bd9Sstevel@tonic-gate 		scfdie();
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 	if (scf_pg_get_property(pg, propname, prop) != 0) {
2507c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
2517c478bd9Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
2527c478bd9Sstevel@tonic-gate 			ret = ECANCELED;
2537c478bd9Sstevel@tonic-gate 			goto out;
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
2567c478bd9Sstevel@tonic-gate 			ret = ENOENT;
2577c478bd9Sstevel@tonic-gate 			goto out;
2587c478bd9Sstevel@tonic-gate 
2597c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
2607c478bd9Sstevel@tonic-gate 			assert(0);
2617c478bd9Sstevel@tonic-gate 			abort();
2627c478bd9Sstevel@tonic-gate 			/* NOTREACHED */
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate 		default:
2657c478bd9Sstevel@tonic-gate 			scfdie();
2667c478bd9Sstevel@tonic-gate 		}
2677c478bd9Sstevel@tonic-gate 	}
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate 	if (scf_property_get_value(prop, val) == 0) {
2707c478bd9Sstevel@tonic-gate 		ret = 0;
2717c478bd9Sstevel@tonic-gate 	} else {
2727c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
2737c478bd9Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
2747c478bd9Sstevel@tonic-gate 			ret = ENOENT;
2757c478bd9Sstevel@tonic-gate 			goto out;
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
2787c478bd9Sstevel@tonic-gate 			ret = EINVAL;
2797c478bd9Sstevel@tonic-gate 			goto out;
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 		case SCF_ERROR_CONSTRAINT_VIOLATED:
2827c478bd9Sstevel@tonic-gate 			ret = E2BIG;
2837c478bd9Sstevel@tonic-gate 			break;
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
2867c478bd9Sstevel@tonic-gate 			assert(0);
2877c478bd9Sstevel@tonic-gate 			abort();
2887c478bd9Sstevel@tonic-gate 			/* NOTREACHED */
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate 		default:
2917c478bd9Sstevel@tonic-gate 			scfdie();
2927c478bd9Sstevel@tonic-gate 		}
2937c478bd9Sstevel@tonic-gate 	}
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate 	if (scf_value_get_boolean(val, bp) != 0) {
2967c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_TYPE_MISMATCH)
2977c478bd9Sstevel@tonic-gate 			scfdie();
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate 		ret = EINVAL;
3007c478bd9Sstevel@tonic-gate 		goto out;
3017c478bd9Sstevel@tonic-gate 	}
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate out:
3047c478bd9Sstevel@tonic-gate 	scf_value_destroy(val);
3057c478bd9Sstevel@tonic-gate 	scf_property_destroy(prop);
3067c478bd9Sstevel@tonic-gate 	return (ret);
3077c478bd9Sstevel@tonic-gate }
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate /*
3107c478bd9Sstevel@tonic-gate  * Returns 0, EPERM, or EROFS.
3117c478bd9Sstevel@tonic-gate  */
3127c478bd9Sstevel@tonic-gate static int
3137c478bd9Sstevel@tonic-gate set_bool_prop(scf_propertygroup_t *pg, const char *propname, boolean_t b)
3147c478bd9Sstevel@tonic-gate {
3157c478bd9Sstevel@tonic-gate 	scf_value_t *v;
3167c478bd9Sstevel@tonic-gate 	scf_transaction_t *tx;
3177c478bd9Sstevel@tonic-gate 	scf_transaction_entry_t *ent;
3187c478bd9Sstevel@tonic-gate 	int ret = 0, r;
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate 	if ((tx = scf_transaction_create(h)) == NULL ||
3217c478bd9Sstevel@tonic-gate 	    (ent = scf_entry_create(h)) == NULL ||
3227c478bd9Sstevel@tonic-gate 	    (v = scf_value_create(h)) == NULL)
3237c478bd9Sstevel@tonic-gate 		scfdie();
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 	scf_value_set_boolean(v, b);
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate 	for (;;) {
3287c478bd9Sstevel@tonic-gate 		if (scf_transaction_start(tx, pg) == -1) {
3297c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
3307c478bd9Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
3317c478bd9Sstevel@tonic-gate 				ret = EPERM;
3327c478bd9Sstevel@tonic-gate 				goto out;
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_READONLY:
3357c478bd9Sstevel@tonic-gate 				ret = EROFS;
3367c478bd9Sstevel@tonic-gate 				goto out;
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate 			default:
3397c478bd9Sstevel@tonic-gate 				scfdie();
3407c478bd9Sstevel@tonic-gate 			}
3417c478bd9Sstevel@tonic-gate 		}
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate 		if (scf_transaction_property_change_type(tx, ent, propname,
3447c478bd9Sstevel@tonic-gate 		    SCF_TYPE_BOOLEAN) != 0) {
3457c478bd9Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_NOT_FOUND)
3467c478bd9Sstevel@tonic-gate 				scfdie();
3477c478bd9Sstevel@tonic-gate 
3487c478bd9Sstevel@tonic-gate 			if (scf_transaction_property_new(tx, ent, propname,
3497c478bd9Sstevel@tonic-gate 			    SCF_TYPE_BOOLEAN) != 0)
3507c478bd9Sstevel@tonic-gate 				scfdie();
3517c478bd9Sstevel@tonic-gate 		}
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 		r = scf_entry_add_value(ent, v);
3547c478bd9Sstevel@tonic-gate 		assert(r == 0);
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate 		r = scf_transaction_commit(tx);
3577c478bd9Sstevel@tonic-gate 		if (r == 1)
3587c478bd9Sstevel@tonic-gate 			break;
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate 		scf_transaction_reset(tx);
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 		if (r != 0) {
3637c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
3647c478bd9Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
3657c478bd9Sstevel@tonic-gate 				ret = EPERM;
3667c478bd9Sstevel@tonic-gate 				goto out;
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_READONLY:
3697c478bd9Sstevel@tonic-gate 				ret = EROFS;
3707c478bd9Sstevel@tonic-gate 				goto out;
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate 			default:
3737c478bd9Sstevel@tonic-gate 				scfdie();
3747c478bd9Sstevel@tonic-gate 			}
3757c478bd9Sstevel@tonic-gate 		}
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate 		if (scf_pg_update(pg) == -1)
3787c478bd9Sstevel@tonic-gate 			scfdie();
3797c478bd9Sstevel@tonic-gate 	}
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate out:
3827c478bd9Sstevel@tonic-gate 	scf_transaction_destroy(tx);
3837c478bd9Sstevel@tonic-gate 	scf_entry_destroy(ent);
3847c478bd9Sstevel@tonic-gate 	scf_value_destroy(v);
3857c478bd9Sstevel@tonic-gate 	return (ret);
3867c478bd9Sstevel@tonic-gate }
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate /*
3897c478bd9Sstevel@tonic-gate  * Gets the single astring value of the propname property of pg.  prop & v are
3907c478bd9Sstevel@tonic-gate  * scratch space.  Returns the length of the string on success or
3917c478bd9Sstevel@tonic-gate  *   -ENOENT - pg has no property named propname
3927c478bd9Sstevel@tonic-gate  *   -E2BIG - property has no values or multiple values
3937c478bd9Sstevel@tonic-gate  *   -EINVAL - property type is not compatible with astring
3947c478bd9Sstevel@tonic-gate  */
3957c478bd9Sstevel@tonic-gate ssize_t
3967c478bd9Sstevel@tonic-gate get_astring_prop(const scf_propertygroup_t *pg, const char *propname,
3977c478bd9Sstevel@tonic-gate     scf_property_t *prop, scf_value_t *v, char *buf, size_t bufsz)
3987c478bd9Sstevel@tonic-gate {
3997c478bd9Sstevel@tonic-gate 	ssize_t sz;
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate 	if (scf_pg_get_property(pg, propname, prop) != 0) {
4027c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND)
4037c478bd9Sstevel@tonic-gate 			scfdie();
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate 		return (-ENOENT);
4067c478bd9Sstevel@tonic-gate 	}
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate 	if (scf_property_get_value(prop, v) != 0) {
4097c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
4107c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
4117c478bd9Sstevel@tonic-gate 		case SCF_ERROR_CONSTRAINT_VIOLATED:
4127c478bd9Sstevel@tonic-gate 			return (-E2BIG);
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate 		default:
4157c478bd9Sstevel@tonic-gate 			scfdie();
4167c478bd9Sstevel@tonic-gate 		}
4177c478bd9Sstevel@tonic-gate 	}
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate 	sz = scf_value_get_astring(v, buf, bufsz);
4207c478bd9Sstevel@tonic-gate 	if (sz < 0) {
4217c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_TYPE_MISMATCH)
4227c478bd9Sstevel@tonic-gate 			scfdie();
4237c478bd9Sstevel@tonic-gate 
4247c478bd9Sstevel@tonic-gate 		return (-EINVAL);
4257c478bd9Sstevel@tonic-gate 	}
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate 	return (sz);
4287c478bd9Sstevel@tonic-gate }
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate /*
431eb1a3463STruong Nguyen  * Returns 0 or EPERM.
4327c478bd9Sstevel@tonic-gate  */
4337c478bd9Sstevel@tonic-gate static int
434eb1a3463STruong Nguyen pg_get_or_add(const scf_instance_t *inst, const char *pgname,
435eb1a3463STruong Nguyen     const char *pgtype, uint32_t pgflags, scf_propertygroup_t *pg)
4367c478bd9Sstevel@tonic-gate {
437eb1a3463STruong Nguyen again:
438eb1a3463STruong Nguyen 	if (scf_instance_get_pg(inst, pgname, pg) == 0)
439eb1a3463STruong Nguyen 		return (0);
4407c478bd9Sstevel@tonic-gate 
441eb1a3463STruong Nguyen 	if (scf_error() != SCF_ERROR_NOT_FOUND)
4427c478bd9Sstevel@tonic-gate 		scfdie();
4437c478bd9Sstevel@tonic-gate 
444eb1a3463STruong Nguyen 	if (scf_instance_add_pg(inst, pgname, pgtype, pgflags, pg) == 0)
445eb1a3463STruong Nguyen 		return (0);
4467c478bd9Sstevel@tonic-gate 
447eb1a3463STruong Nguyen 	switch (scf_error()) {
448eb1a3463STruong Nguyen 	case SCF_ERROR_EXISTS:
449eb1a3463STruong Nguyen 		goto again;
4507c478bd9Sstevel@tonic-gate 
451eb1a3463STruong Nguyen 	case SCF_ERROR_PERMISSION_DENIED:
452eb1a3463STruong Nguyen 		return (EPERM);
4537c478bd9Sstevel@tonic-gate 
454eb1a3463STruong Nguyen 	default:
455eb1a3463STruong Nguyen 		scfdie();
456eb1a3463STruong Nguyen 		/* NOTREACHED */
457eb1a3463STruong Nguyen 	}
458eb1a3463STruong Nguyen }
4597c478bd9Sstevel@tonic-gate 
460eb1a3463STruong Nguyen static int
461eb1a3463STruong Nguyen my_ct_name(char *out, size_t len)
462eb1a3463STruong Nguyen {
463eb1a3463STruong Nguyen 	ct_stathdl_t st;
464eb1a3463STruong Nguyen 	char *ct_fmri;
465eb1a3463STruong Nguyen 	ctid_t ct;
466eb1a3463STruong Nguyen 	int fd, errno, ret;
4677c478bd9Sstevel@tonic-gate 
468eb1a3463STruong Nguyen 	if ((ct = getctid()) == -1)
469eb1a3463STruong Nguyen 		uu_die(gettext("Could not get contract id for process"));
4707c478bd9Sstevel@tonic-gate 
471eb1a3463STruong Nguyen 	fd = contract_open(ct, "process", "status", O_RDONLY);
4727c478bd9Sstevel@tonic-gate 
473eb1a3463STruong Nguyen 	if ((errno = ct_status_read(fd, CTD_ALL, &st)) != 0)
474eb1a3463STruong Nguyen 		uu_warn(gettext("Could not read status of contract "
475eb1a3463STruong Nguyen 		    "%ld: %s.\n"), ct, strerror(errno));
4767c478bd9Sstevel@tonic-gate 
477eb1a3463STruong Nguyen 	if ((errno = ct_pr_status_get_svc_fmri(st, &ct_fmri)) != 0)
478eb1a3463STruong Nguyen 		uu_warn(gettext("Could not get svc_fmri for contract "
479eb1a3463STruong Nguyen 		    "%ld: %s.\n"), ct, strerror(errno));
4807c478bd9Sstevel@tonic-gate 
481eb1a3463STruong Nguyen 	ret = strlcpy(out, ct_fmri, len);
4827c478bd9Sstevel@tonic-gate 
483eb1a3463STruong Nguyen 	ct_status_free(st);
484eb1a3463STruong Nguyen 	(void) close(fd);
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate 	return (ret);
4877c478bd9Sstevel@tonic-gate }
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate /*
490eb1a3463STruong Nguyen  * Set auxiliary_tty and auxiliary_fmri properties in restarter_actions pg to
491eb1a3463STruong Nguyen  * communicate whether the action is requested from a tty and the fmri of the
492eb1a3463STruong Nguyen  * responsible process.
493e8f5b3f5STruong Nguyen  *
494e8f5b3f5STruong Nguyen  * Returns 0, EPERM, or EROFS
4957c478bd9Sstevel@tonic-gate  */
4967c478bd9Sstevel@tonic-gate static int
497eb1a3463STruong Nguyen restarter_setup(const char *fmri, const scf_instance_t *inst)
4987c478bd9Sstevel@tonic-gate {
499eb1a3463STruong Nguyen 	boolean_t b = B_FALSE;
500eb1a3463STruong Nguyen 	scf_propertygroup_t *pg = NULL;
501e8f5b3f5STruong Nguyen 	int ret = 0;
5027c478bd9Sstevel@tonic-gate 
503eb1a3463STruong Nguyen 	if ((pg = scf_pg_create(h)) == NULL)
5047c478bd9Sstevel@tonic-gate 		scfdie();
5057c478bd9Sstevel@tonic-gate 
506eb1a3463STruong Nguyen 	if (pg_get_or_add(inst, SCF_PG_RESTARTER_ACTIONS,
507eb1a3463STruong Nguyen 	    SCF_PG_RESTARTER_ACTIONS_TYPE, SCF_PG_RESTARTER_ACTIONS_FLAGS,
508e8f5b3f5STruong Nguyen 	    pg) == EPERM) {
509e8f5b3f5STruong Nguyen 		if (!verbose)
510e8f5b3f5STruong Nguyen 			uu_warn(emsg_permission_denied, fmri);
511e8f5b3f5STruong Nguyen 		else
512e8f5b3f5STruong Nguyen 			uu_warn(emsg_create_pg_perm_denied, fmri,
513e8f5b3f5STruong Nguyen 			    SCF_PG_RESTARTER_ACTIONS);
514e8f5b3f5STruong Nguyen 
515e8f5b3f5STruong Nguyen 		ret = EPERM;
516e8f5b3f5STruong Nguyen 		goto out;
517e8f5b3f5STruong Nguyen 	}
5187c478bd9Sstevel@tonic-gate 
519eb1a3463STruong Nguyen 	/* Set auxiliary_tty property */
520eb1a3463STruong Nguyen 	if (isatty(STDIN_FILENO))
521eb1a3463STruong Nguyen 		b = B_TRUE;
5227c478bd9Sstevel@tonic-gate 
523eb1a3463STruong Nguyen 	/* Create and set state to disabled */
524eb1a3463STruong Nguyen 	switch (set_bool_prop(pg, SCF_PROPERTY_AUX_TTY, b) != 0) {
525eb1a3463STruong Nguyen 	case 0:
526eb1a3463STruong Nguyen 		break;
527eb1a3463STruong Nguyen 
528eb1a3463STruong Nguyen 	case EPERM:
529e8f5b3f5STruong Nguyen 		if (!verbose)
530e8f5b3f5STruong Nguyen 			uu_warn(emsg_permission_denied, fmri);
531e8f5b3f5STruong Nguyen 		else
532e8f5b3f5STruong Nguyen 			uu_warn(emsg_prop_perm_denied, fmri,
533e8f5b3f5STruong Nguyen 			    SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_AUX_TTY);
534e8f5b3f5STruong Nguyen 
535e8f5b3f5STruong Nguyen 		ret = EPERM;
536e8f5b3f5STruong Nguyen 		goto out;
537e8f5b3f5STruong Nguyen 		/* NOTREACHED */
538eb1a3463STruong Nguyen 
539eb1a3463STruong Nguyen 	case EROFS:
540e8f5b3f5STruong Nguyen 		/* Shouldn't happen, but it can. */
541e8f5b3f5STruong Nguyen 		if (!verbose)
542e8f5b3f5STruong Nguyen 			uu_warn(gettext("%s: Repository read-only.\n"), fmri);
543e8f5b3f5STruong Nguyen 		else
544e8f5b3f5STruong Nguyen 			uu_warn(gettext("%s: Could not set %s/%s "
545e8f5b3f5STruong Nguyen 			    "(repository read-only).\n"), fmri,
546e8f5b3f5STruong Nguyen 			    SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_AUX_TTY);
547e8f5b3f5STruong Nguyen 
548e8f5b3f5STruong Nguyen 		ret = EROFS;
549e8f5b3f5STruong Nguyen 		goto out;
550e8f5b3f5STruong Nguyen 		/* NOTREACHED */
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate 	default:
5537c478bd9Sstevel@tonic-gate 		scfdie();
5547c478bd9Sstevel@tonic-gate 	}
555eb1a3463STruong Nguyen 
556eb1a3463STruong Nguyen 	if (my_ct_name(scratch_fmri, max_scf_fmri_sz) > 0) {
557eb1a3463STruong Nguyen 		set_astring_prop(fmri, SCF_PG_RESTARTER_ACTIONS,
558eb1a3463STruong Nguyen 		    SCF_PG_RESTARTER_ACTIONS_TYPE,
559eb1a3463STruong Nguyen 		    SCF_PG_RESTARTER_ACTIONS_FLAGS,
560eb1a3463STruong Nguyen 		    SCF_PROPERTY_AUX_FMRI, scratch_fmri);
561eb1a3463STruong Nguyen 	} else {
562eb1a3463STruong Nguyen 		uu_warn(gettext("%s: Could not set %s/%s: "
563eb1a3463STruong Nguyen 		    "my_ct_name failed.\n"), fmri,
564eb1a3463STruong Nguyen 		    SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_AUX_FMRI);
565eb1a3463STruong Nguyen 	}
566eb1a3463STruong Nguyen 
567e8f5b3f5STruong Nguyen out:
568eb1a3463STruong Nguyen 	scf_pg_destroy(pg);
569e8f5b3f5STruong Nguyen 	return (ret);
5707c478bd9Sstevel@tonic-gate }
5717c478bd9Sstevel@tonic-gate 
5727c478bd9Sstevel@tonic-gate /*
5737c478bd9Sstevel@tonic-gate  * Enable or disable inst, per enable.  If temp is true, set
5747c478bd9Sstevel@tonic-gate  * general_ovr/enabled.  Otherwise set general/enabled and delete
5757c478bd9Sstevel@tonic-gate  * general_ovr/enabled if it exists (order is important here: we don't want the
5767c478bd9Sstevel@tonic-gate  * enabled status to glitch).
5777c478bd9Sstevel@tonic-gate  */
5787c478bd9Sstevel@tonic-gate static void
5797c478bd9Sstevel@tonic-gate set_inst_enabled(const char *fmri, scf_instance_t *inst, boolean_t temp,
5807c478bd9Sstevel@tonic-gate     boolean_t enable)
5817c478bd9Sstevel@tonic-gate {
5827c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg;
5837c478bd9Sstevel@tonic-gate 	uint8_t b;
5847c478bd9Sstevel@tonic-gate 	const char *pgname = NULL;	/* For emsg_pg_perm_denied */
5857c478bd9Sstevel@tonic-gate 	int r;
5867c478bd9Sstevel@tonic-gate 
5877c478bd9Sstevel@tonic-gate 	pg = scf_pg_create(h);
5887c478bd9Sstevel@tonic-gate 	if (pg == NULL)
5897c478bd9Sstevel@tonic-gate 		scfdie();
5907c478bd9Sstevel@tonic-gate 
591eb1a3463STruong Nguyen 	if (restarter_setup(fmri, inst))
592e8f5b3f5STruong Nguyen 		goto out;
593eb1a3463STruong Nguyen 
594fee38f6fStn 	/*
595fee38f6fStn 	 * An instance's configuration is incomplete if general/enabled
596fee38f6fStn 	 * doesn't exist. Create both the property group and property
597fee38f6fStn 	 * here if they don't exist.
598fee38f6fStn 	 */
599fee38f6fStn 	pgname = SCF_PG_GENERAL;
600fee38f6fStn 	if (pg_get_or_add(inst, pgname, SCF_PG_GENERAL_TYPE,
601fee38f6fStn 	    SCF_PG_GENERAL_FLAGS, pg) != 0)
602fee38f6fStn 		goto eperm;
603fee38f6fStn 
604fee38f6fStn 	if (get_bool_prop(pg, SCF_PROPERTY_ENABLED, &b) != 0) {
605fee38f6fStn 		/* Create and set state to disabled */
606fee38f6fStn 		switch (set_bool_prop(pg, SCF_PROPERTY_ENABLED, B_FALSE) != 0) {
607fee38f6fStn 		case 0:
608fee38f6fStn 			break;
609fee38f6fStn 
610fee38f6fStn 		case EPERM:
611fee38f6fStn 			goto eperm;
612fee38f6fStn 
613fee38f6fStn 		case EROFS:
614fee38f6fStn 			/* Shouldn't happen, but it can. */
615fee38f6fStn 			if (!verbose)
616fee38f6fStn 				uu_warn(gettext("%s: Repository read-only.\n"),
617fee38f6fStn 				    fmri);
618fee38f6fStn 			else
619fee38f6fStn 				uu_warn(gettext("%s: Could not set %s/%s "
620fee38f6fStn 				    "(repository read-only).\n"), fmri,
621fee38f6fStn 				    SCF_PG_GENERAL, SCF_PROPERTY_ENABLED);
622fee38f6fStn 			goto out;
623fee38f6fStn 
624fee38f6fStn 		default:
625fee38f6fStn 			assert(0);
626fee38f6fStn 			abort();
627fee38f6fStn 		}
628fee38f6fStn 	}
629fee38f6fStn 
6307c478bd9Sstevel@tonic-gate 	if (temp) {
6317c478bd9Sstevel@tonic-gate 		/* Set general_ovr/enabled */
6327c478bd9Sstevel@tonic-gate 		pgname = SCF_PG_GENERAL_OVR;
6337c478bd9Sstevel@tonic-gate 		if (pg_get_or_add(inst, pgname, SCF_PG_GENERAL_OVR_TYPE,
6347c478bd9Sstevel@tonic-gate 		    SCF_PG_GENERAL_OVR_FLAGS, pg) != 0)
6357c478bd9Sstevel@tonic-gate 			goto eperm;
6367c478bd9Sstevel@tonic-gate 
6377c478bd9Sstevel@tonic-gate 		switch (set_bool_prop(pg, SCF_PROPERTY_ENABLED, enable) != 0) {
6387c478bd9Sstevel@tonic-gate 		case 0:
6397c478bd9Sstevel@tonic-gate 			break;
6407c478bd9Sstevel@tonic-gate 
6417c478bd9Sstevel@tonic-gate 		case EPERM:
6427c478bd9Sstevel@tonic-gate 			goto eperm;
6437c478bd9Sstevel@tonic-gate 
6447c478bd9Sstevel@tonic-gate 		case EROFS:
6457c478bd9Sstevel@tonic-gate 			/* Shouldn't happen, but it can. */
6467c478bd9Sstevel@tonic-gate 			if (!verbose)
6477c478bd9Sstevel@tonic-gate 				uu_warn(gettext("%s: Repository read-only.\n"),
6487c478bd9Sstevel@tonic-gate 				    fmri);
6497c478bd9Sstevel@tonic-gate 			else
6507c478bd9Sstevel@tonic-gate 				uu_warn(gettext("%s: Could not set %s/%s "
6517c478bd9Sstevel@tonic-gate 				    "(repository read-only).\n"), fmri,
6527c478bd9Sstevel@tonic-gate 				    SCF_PG_GENERAL_OVR, SCF_PROPERTY_ENABLED);
6537c478bd9Sstevel@tonic-gate 			goto out;
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate 		default:
6567c478bd9Sstevel@tonic-gate 			assert(0);
6577c478bd9Sstevel@tonic-gate 			abort();
6587c478bd9Sstevel@tonic-gate 		}
6597c478bd9Sstevel@tonic-gate 
6607c478bd9Sstevel@tonic-gate 		if (verbose)
6617c478bd9Sstevel@tonic-gate 			(void) printf(enable ?
6627c478bd9Sstevel@tonic-gate 			    gettext("%s temporarily enabled.\n") :
6637c478bd9Sstevel@tonic-gate 			    gettext("%s temporarily disabled.\n"), fmri);
6647c478bd9Sstevel@tonic-gate 	} else {
6657c478bd9Sstevel@tonic-gate again:
666fee38f6fStn 		/*
667fee38f6fStn 		 * Both pg and property should exist since we created
668fee38f6fStn 		 * them earlier. However, there's still a chance that
669fee38f6fStn 		 * someone may have deleted the property out from under
670fee38f6fStn 		 * us.
671fee38f6fStn 		 */
6727c478bd9Sstevel@tonic-gate 		if (pg_get_or_add(inst, pgname, SCF_PG_GENERAL_TYPE,
6737c478bd9Sstevel@tonic-gate 		    SCF_PG_GENERAL_FLAGS, pg) != 0)
6747c478bd9Sstevel@tonic-gate 			goto eperm;
6757c478bd9Sstevel@tonic-gate 
6767c478bd9Sstevel@tonic-gate 		switch (set_bool_prop(pg, SCF_PROPERTY_ENABLED, enable)) {
6777c478bd9Sstevel@tonic-gate 		case 0:
6787c478bd9Sstevel@tonic-gate 			break;
6797c478bd9Sstevel@tonic-gate 
6807c478bd9Sstevel@tonic-gate 		case EPERM:
6817c478bd9Sstevel@tonic-gate 			goto eperm;
6827c478bd9Sstevel@tonic-gate 
6837c478bd9Sstevel@tonic-gate 		case EROFS:
6847c478bd9Sstevel@tonic-gate 			/*
6857c478bd9Sstevel@tonic-gate 			 * If general/enabled is already set the way we want,
6867c478bd9Sstevel@tonic-gate 			 * proceed.
6877c478bd9Sstevel@tonic-gate 			 */
6887c478bd9Sstevel@tonic-gate 			switch (get_bool_prop(pg, SCF_PROPERTY_ENABLED, &b)) {
6897c478bd9Sstevel@tonic-gate 			case 0:
6907c478bd9Sstevel@tonic-gate 				if ((b != 0) == (enable != B_FALSE))
6917c478bd9Sstevel@tonic-gate 					break;
6927c478bd9Sstevel@tonic-gate 				/* FALLTHROUGH */
6937c478bd9Sstevel@tonic-gate 
6947c478bd9Sstevel@tonic-gate 			case ENOENT:
6957c478bd9Sstevel@tonic-gate 			case EINVAL:
6967c478bd9Sstevel@tonic-gate 			case E2BIG:
6977c478bd9Sstevel@tonic-gate 				if (!verbose)
6987c478bd9Sstevel@tonic-gate 					uu_warn(gettext("%s: Repository "
6997c478bd9Sstevel@tonic-gate 					    "read-only.\n"), fmri);
7007c478bd9Sstevel@tonic-gate 				else
7017c478bd9Sstevel@tonic-gate 					uu_warn(gettext("%s: Could not set "
7027c478bd9Sstevel@tonic-gate 					    "%s/%s (repository read-only).\n"),
7037c478bd9Sstevel@tonic-gate 					    fmri, SCF_PG_GENERAL,
7047c478bd9Sstevel@tonic-gate 					    SCF_PROPERTY_ENABLED);
7057c478bd9Sstevel@tonic-gate 				goto out;
7067c478bd9Sstevel@tonic-gate 
7077c478bd9Sstevel@tonic-gate 			case ECANCELED:
7087c478bd9Sstevel@tonic-gate 				goto again;
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate 			default:
7117c478bd9Sstevel@tonic-gate 				assert(0);
7127c478bd9Sstevel@tonic-gate 				abort();
7137c478bd9Sstevel@tonic-gate 			}
7147c478bd9Sstevel@tonic-gate 			break;
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate 		default:
7177c478bd9Sstevel@tonic-gate 			assert(0);
7187c478bd9Sstevel@tonic-gate 			abort();
7197c478bd9Sstevel@tonic-gate 		}
7207c478bd9Sstevel@tonic-gate 
7217c478bd9Sstevel@tonic-gate 		pgname = SCF_PG_GENERAL_OVR;
722eb1a3463STruong Nguyen 		r = scf_instance_delete_prop(inst, pgname,
723eb1a3463STruong Nguyen 		    SCF_PROPERTY_ENABLED);
724eb1a3463STruong Nguyen 		switch (r) {
725eb1a3463STruong Nguyen 		case 0:
726eb1a3463STruong Nguyen 			break;
7277c478bd9Sstevel@tonic-gate 
728eb1a3463STruong Nguyen 		case ECANCELED:
729eb1a3463STruong Nguyen 			uu_warn(emsg_no_service, fmri);
730eb1a3463STruong Nguyen 			goto out;
7317c478bd9Sstevel@tonic-gate 
732eb1a3463STruong Nguyen 		case EPERM:
733eb1a3463STruong Nguyen 			goto eperm;
7347c478bd9Sstevel@tonic-gate 
735eb1a3463STruong Nguyen 		case EACCES:
736eb1a3463STruong Nguyen 			uu_warn(gettext("Could not delete %s/%s "
737eb1a3463STruong Nguyen 			    "property of %s: backend access denied.\n"),
738eb1a3463STruong Nguyen 			    pgname, SCF_PROPERTY_ENABLED, fmri);
739eb1a3463STruong Nguyen 			goto out;
7407c478bd9Sstevel@tonic-gate 
741eb1a3463STruong Nguyen 		case EROFS:
742eb1a3463STruong Nguyen 			uu_warn(gettext("Could not delete %s/%s "
743eb1a3463STruong Nguyen 			    "property of %s: backend is read-only.\n"),
744eb1a3463STruong Nguyen 			    pgname, SCF_PROPERTY_ENABLED, fmri);
745eb1a3463STruong Nguyen 			goto out;
7467c478bd9Sstevel@tonic-gate 
747eb1a3463STruong Nguyen 		default:
748eb1a3463STruong Nguyen 			bad_error("scf_instance_delete_prop", r);
7497c478bd9Sstevel@tonic-gate 		}
7507c478bd9Sstevel@tonic-gate 
7517c478bd9Sstevel@tonic-gate 		if (verbose)
7527c478bd9Sstevel@tonic-gate 			(void) printf(enable ?  gettext("%s enabled.\n") :
7537c478bd9Sstevel@tonic-gate 			    gettext("%s disabled.\n"), fmri);
7547c478bd9Sstevel@tonic-gate 	}
7557c478bd9Sstevel@tonic-gate 
7567c478bd9Sstevel@tonic-gate 	scf_pg_destroy(pg);
7577c478bd9Sstevel@tonic-gate 	return;
7587c478bd9Sstevel@tonic-gate 
7597c478bd9Sstevel@tonic-gate eperm:
7607c478bd9Sstevel@tonic-gate 	assert(pgname != NULL);
7617c478bd9Sstevel@tonic-gate 	if (!verbose)
7627c478bd9Sstevel@tonic-gate 		uu_warn(emsg_permission_denied, fmri);
7637c478bd9Sstevel@tonic-gate 	else
7647c478bd9Sstevel@tonic-gate 		uu_warn(emsg_pg_perm_denied, fmri, pgname);
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate out:
7677c478bd9Sstevel@tonic-gate 	scf_pg_destroy(pg);
7687c478bd9Sstevel@tonic-gate 	exit_status = 1;
7697c478bd9Sstevel@tonic-gate }
7707c478bd9Sstevel@tonic-gate 
7717c478bd9Sstevel@tonic-gate /*
7727c478bd9Sstevel@tonic-gate  * Set inst to the instance which corresponds to fmri.  If fmri identifies
7737c478bd9Sstevel@tonic-gate  * a service with a single instance, get that instance.
7747c478bd9Sstevel@tonic-gate  *
7757c478bd9Sstevel@tonic-gate  * Fails with
7767c478bd9Sstevel@tonic-gate  *   ENOTSUP - fmri has an unsupported scheme
7777c478bd9Sstevel@tonic-gate  *   EINVAL - fmri is invalid
7787c478bd9Sstevel@tonic-gate  *   ENOTDIR - fmri does not identify a service or instance
7797c478bd9Sstevel@tonic-gate  *   ENOENT - could not locate instance
7807c478bd9Sstevel@tonic-gate  *   E2BIG - fmri is a service with multiple instances (warning not printed)
7817c478bd9Sstevel@tonic-gate  */
7827c478bd9Sstevel@tonic-gate static int
7837c478bd9Sstevel@tonic-gate get_inst_mult(const char *fmri, scf_instance_t *inst)
7847c478bd9Sstevel@tonic-gate {
7857c478bd9Sstevel@tonic-gate 	char *cfmri;
7867c478bd9Sstevel@tonic-gate 	const char *svc_name, *inst_name, *pg_name;
7877c478bd9Sstevel@tonic-gate 	scf_service_t *svc;
7887c478bd9Sstevel@tonic-gate 	scf_instance_t *inst2;
7897c478bd9Sstevel@tonic-gate 	scf_iter_t *iter;
7907c478bd9Sstevel@tonic-gate 	int ret;
7917c478bd9Sstevel@tonic-gate 
7927c478bd9Sstevel@tonic-gate 	if (strncmp(fmri, "lrc:", sizeof ("lrc:") - 1) == 0) {
7937c478bd9Sstevel@tonic-gate 		uu_warn(gettext("FMRI \"%s\" is a legacy service.\n"), fmri);
7947c478bd9Sstevel@tonic-gate 		exit_status = 1;
7957c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
7967c478bd9Sstevel@tonic-gate 	}
7977c478bd9Sstevel@tonic-gate 
7987c478bd9Sstevel@tonic-gate 	cfmri = strdup(fmri);
7997c478bd9Sstevel@tonic-gate 	if (cfmri == NULL)
8007c478bd9Sstevel@tonic-gate 		uu_die(emsg_nomem);
8017c478bd9Sstevel@tonic-gate 
8027c478bd9Sstevel@tonic-gate 	if (scf_parse_svc_fmri(cfmri, NULL, &svc_name, &inst_name, &pg_name,
8037c478bd9Sstevel@tonic-gate 	    NULL) != SCF_SUCCESS) {
8047c478bd9Sstevel@tonic-gate 		free(cfmri);
8057c478bd9Sstevel@tonic-gate 		uu_warn(gettext("FMRI \"%s\" is invalid.\n"), fmri);
8067c478bd9Sstevel@tonic-gate 		exit_status = 1;
8077c478bd9Sstevel@tonic-gate 		return (EINVAL);
8087c478bd9Sstevel@tonic-gate 	}
8097c478bd9Sstevel@tonic-gate 
8107c478bd9Sstevel@tonic-gate 	free(cfmri);
8117c478bd9Sstevel@tonic-gate 
8127c478bd9Sstevel@tonic-gate 	if (svc_name == NULL || pg_name != NULL) {
8137c478bd9Sstevel@tonic-gate 		uu_warn(gettext(
8147c478bd9Sstevel@tonic-gate 		    "FMRI \"%s\" does not designate a service or instance.\n"),
8157c478bd9Sstevel@tonic-gate 		    fmri);
8167c478bd9Sstevel@tonic-gate 		exit_status = 1;
8177c478bd9Sstevel@tonic-gate 		return (ENOTDIR);
8187c478bd9Sstevel@tonic-gate 	}
8197c478bd9Sstevel@tonic-gate 
8207c478bd9Sstevel@tonic-gate 	if (inst_name != NULL) {
8217c478bd9Sstevel@tonic-gate 		if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
8227c478bd9Sstevel@tonic-gate 		    NULL, SCF_DECODE_FMRI_EXACT) == 0)
8237c478bd9Sstevel@tonic-gate 			return (0);
8247c478bd9Sstevel@tonic-gate 
8257c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND)
8267c478bd9Sstevel@tonic-gate 			scfdie();
8277c478bd9Sstevel@tonic-gate 
8287c478bd9Sstevel@tonic-gate 		uu_warn(gettext("No such instance \"%s\".\n"), fmri);
8297c478bd9Sstevel@tonic-gate 		exit_status = 1;
8307c478bd9Sstevel@tonic-gate 
8317c478bd9Sstevel@tonic-gate 		return (ENOENT);
8327c478bd9Sstevel@tonic-gate 	}
8337c478bd9Sstevel@tonic-gate 
8347c478bd9Sstevel@tonic-gate 	if ((svc = scf_service_create(h)) == NULL ||
8357c478bd9Sstevel@tonic-gate 	    (inst2 = scf_instance_create(h)) == NULL ||
8367c478bd9Sstevel@tonic-gate 	    (iter = scf_iter_create(h)) == NULL)
8377c478bd9Sstevel@tonic-gate 		scfdie();
8387c478bd9Sstevel@tonic-gate 
8397c478bd9Sstevel@tonic-gate 	if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL,
8407c478bd9Sstevel@tonic-gate 	    SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
8417c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND)
8427c478bd9Sstevel@tonic-gate 			scfdie();
8437c478bd9Sstevel@tonic-gate 
8447c478bd9Sstevel@tonic-gate 		uu_warn(emsg_no_service, fmri);
8457c478bd9Sstevel@tonic-gate 		exit_status = 1;
8467c478bd9Sstevel@tonic-gate 
8477c478bd9Sstevel@tonic-gate 		ret = ENOENT;
8487c478bd9Sstevel@tonic-gate 		goto out;
8497c478bd9Sstevel@tonic-gate 	}
8507c478bd9Sstevel@tonic-gate 
8517c478bd9Sstevel@tonic-gate 	/* If the service has only one child, use it. */
8527c478bd9Sstevel@tonic-gate 	if (scf_iter_service_instances(iter, svc) != SCF_SUCCESS)
8537c478bd9Sstevel@tonic-gate 		scfdie();
8547c478bd9Sstevel@tonic-gate 
8557c478bd9Sstevel@tonic-gate 	ret = scf_iter_next_instance(iter, inst);
8567c478bd9Sstevel@tonic-gate 	if (ret < 0)
8577c478bd9Sstevel@tonic-gate 		scfdie();
8587c478bd9Sstevel@tonic-gate 	if (ret != 1) {
8597c478bd9Sstevel@tonic-gate 		uu_warn(gettext("Service \"%s\" has no instances.\n"),
8607c478bd9Sstevel@tonic-gate 		    fmri);
8617c478bd9Sstevel@tonic-gate 		exit_status = 1;
8627c478bd9Sstevel@tonic-gate 		ret = ENOENT;
8637c478bd9Sstevel@tonic-gate 		goto out;
8647c478bd9Sstevel@tonic-gate 	}
8657c478bd9Sstevel@tonic-gate 
8667c478bd9Sstevel@tonic-gate 	ret = scf_iter_next_instance(iter, inst2);
8677c478bd9Sstevel@tonic-gate 	if (ret < 0)
8687c478bd9Sstevel@tonic-gate 		scfdie();
8697c478bd9Sstevel@tonic-gate 
8707c478bd9Sstevel@tonic-gate 	if (ret != 0) {
8717c478bd9Sstevel@tonic-gate 		ret = E2BIG;
8727c478bd9Sstevel@tonic-gate 		goto out;
8737c478bd9Sstevel@tonic-gate 	}
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate 	ret = 0;
8767c478bd9Sstevel@tonic-gate 
8777c478bd9Sstevel@tonic-gate out:
8787c478bd9Sstevel@tonic-gate 	scf_iter_destroy(iter);
8797c478bd9Sstevel@tonic-gate 	scf_instance_destroy(inst2);
8807c478bd9Sstevel@tonic-gate 	scf_service_destroy(svc);
8817c478bd9Sstevel@tonic-gate 	return (ret);
8827c478bd9Sstevel@tonic-gate }
8837c478bd9Sstevel@tonic-gate 
8847c478bd9Sstevel@tonic-gate /*
8857c478bd9Sstevel@tonic-gate  * Same as get_inst_mult(), but on E2BIG prints a warning and returns ENOENT.
8867c478bd9Sstevel@tonic-gate  */
8877c478bd9Sstevel@tonic-gate static int
8887c478bd9Sstevel@tonic-gate get_inst(const char *fmri, scf_instance_t *inst)
8897c478bd9Sstevel@tonic-gate {
8907c478bd9Sstevel@tonic-gate 	int r;
8917c478bd9Sstevel@tonic-gate 
8927c478bd9Sstevel@tonic-gate 	r = get_inst_mult(fmri, inst);
8937c478bd9Sstevel@tonic-gate 	if (r != E2BIG)
8947c478bd9Sstevel@tonic-gate 		return (r);
8957c478bd9Sstevel@tonic-gate 
8967c478bd9Sstevel@tonic-gate 	uu_warn(gettext("operation on service %s is ambiguous; "
8977c478bd9Sstevel@tonic-gate 	    "instance specification needed.\n"), fmri);
8987c478bd9Sstevel@tonic-gate 	return (ENOENT);
8997c478bd9Sstevel@tonic-gate }
9007c478bd9Sstevel@tonic-gate 
9017c478bd9Sstevel@tonic-gate static char *
9027c478bd9Sstevel@tonic-gate inst_get_fmri(const scf_instance_t *inst)
9037c478bd9Sstevel@tonic-gate {
9047c478bd9Sstevel@tonic-gate 	ssize_t sz;
9057c478bd9Sstevel@tonic-gate 
9067c478bd9Sstevel@tonic-gate 	sz = scf_instance_to_fmri(inst, scratch_fmri, max_scf_fmri_sz);
9077c478bd9Sstevel@tonic-gate 	if (sz < 0)
9087c478bd9Sstevel@tonic-gate 		scfdie();
9097c478bd9Sstevel@tonic-gate 	if (sz >= max_scf_fmri_sz)
9107c478bd9Sstevel@tonic-gate 		uu_die(gettext("scf_instance_to_fmri() returned unexpectedly "
9117c478bd9Sstevel@tonic-gate 		    "long value.\n"));
9127c478bd9Sstevel@tonic-gate 
9137c478bd9Sstevel@tonic-gate 	return (scratch_fmri);
9147c478bd9Sstevel@tonic-gate }
9157c478bd9Sstevel@tonic-gate 
9167c478bd9Sstevel@tonic-gate static ssize_t
9177c478bd9Sstevel@tonic-gate dep_get_astring(const char *fmri, const char *pgname,
9187c478bd9Sstevel@tonic-gate     const scf_propertygroup_t *pg, const char *propname, scf_property_t *prop,
9197c478bd9Sstevel@tonic-gate     scf_value_t *v, char *buf, size_t bufsz)
9207c478bd9Sstevel@tonic-gate {
9217c478bd9Sstevel@tonic-gate 	ssize_t sz;
9227c478bd9Sstevel@tonic-gate 
9237c478bd9Sstevel@tonic-gate 	sz = get_astring_prop(pg, propname, prop, v, buf, bufsz);
9247c478bd9Sstevel@tonic-gate 	if (sz >= 0)
9257c478bd9Sstevel@tonic-gate 		return (sz);
9267c478bd9Sstevel@tonic-gate 
9277c478bd9Sstevel@tonic-gate 	switch (-sz) {
9287c478bd9Sstevel@tonic-gate 	case ENOENT:
9297c478bd9Sstevel@tonic-gate 		uu_warn(gettext("\"%s\" is misconfigured (\"%s\" dependency "
9307c478bd9Sstevel@tonic-gate 		    "lacks \"%s\" property.)\n"), fmri, pgname, propname);
9317c478bd9Sstevel@tonic-gate 		return (-1);
9327c478bd9Sstevel@tonic-gate 
9337c478bd9Sstevel@tonic-gate 	case E2BIG:
9347c478bd9Sstevel@tonic-gate 		uu_warn(gettext("\"%s\" is misconfigured (\"%s/%s\" property "
9357c478bd9Sstevel@tonic-gate 		    "is not single-valued.)\n"), fmri, pgname, propname);
9367c478bd9Sstevel@tonic-gate 		return (-1);
9377c478bd9Sstevel@tonic-gate 
9387c478bd9Sstevel@tonic-gate 	case EINVAL:
9397c478bd9Sstevel@tonic-gate 		uu_warn(gettext("\"%s\" is misconfigured (\"%s/%s\" property "
9407c478bd9Sstevel@tonic-gate 		    "is not of astring type.)\n"), fmri, pgname, propname);
9417c478bd9Sstevel@tonic-gate 		return (-1);
9427c478bd9Sstevel@tonic-gate 
9437c478bd9Sstevel@tonic-gate 	default:
9447c478bd9Sstevel@tonic-gate 		assert(0);
9457c478bd9Sstevel@tonic-gate 		abort();
9467c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
9477c478bd9Sstevel@tonic-gate 	}
9487c478bd9Sstevel@tonic-gate }
9497c478bd9Sstevel@tonic-gate 
9507c478bd9Sstevel@tonic-gate static boolean_t
9517c478bd9Sstevel@tonic-gate multiple_instances(scf_iter_t *iter, scf_value_t *v, char *buf)
9527c478bd9Sstevel@tonic-gate {
9537c478bd9Sstevel@tonic-gate 	int count = 0, r;
9547c478bd9Sstevel@tonic-gate 	boolean_t ret;
9557c478bd9Sstevel@tonic-gate 	scf_instance_t *inst;
9567c478bd9Sstevel@tonic-gate 
9577c478bd9Sstevel@tonic-gate 	inst = scf_instance_create(h);
9587c478bd9Sstevel@tonic-gate 	if (inst == NULL)
9597c478bd9Sstevel@tonic-gate 		scfdie();
9607c478bd9Sstevel@tonic-gate 
9617c478bd9Sstevel@tonic-gate 	for (;;) {
9627c478bd9Sstevel@tonic-gate 		r = scf_iter_next_value(iter, v);
9637c478bd9Sstevel@tonic-gate 		if (r == 0) {
9647c478bd9Sstevel@tonic-gate 			ret = B_FALSE;
9657c478bd9Sstevel@tonic-gate 			goto out;
9667c478bd9Sstevel@tonic-gate 		}
9677c478bd9Sstevel@tonic-gate 		if (r != 1)
9687c478bd9Sstevel@tonic-gate 			scfdie();
9697c478bd9Sstevel@tonic-gate 
9707c478bd9Sstevel@tonic-gate 		if (scf_value_get_astring(v, buf, max_scf_fmri_sz) < 0)
9717c478bd9Sstevel@tonic-gate 			scfdie();
9727c478bd9Sstevel@tonic-gate 
9737c478bd9Sstevel@tonic-gate 		switch (get_inst_mult(buf, inst)) {
9747c478bd9Sstevel@tonic-gate 		case 0:
9757c478bd9Sstevel@tonic-gate 			++count;
9767c478bd9Sstevel@tonic-gate 			if (count > 1) {
9777c478bd9Sstevel@tonic-gate 				ret = B_TRUE;
9787c478bd9Sstevel@tonic-gate 				goto out;
9797c478bd9Sstevel@tonic-gate 			}
9807c478bd9Sstevel@tonic-gate 			break;
9817c478bd9Sstevel@tonic-gate 
9827c478bd9Sstevel@tonic-gate 		case ENOTSUP:
9837c478bd9Sstevel@tonic-gate 		case EINVAL:
9847c478bd9Sstevel@tonic-gate 		case ENOTDIR:
9857c478bd9Sstevel@tonic-gate 		case ENOENT:
9867c478bd9Sstevel@tonic-gate 			continue;
9877c478bd9Sstevel@tonic-gate 
9887c478bd9Sstevel@tonic-gate 		case E2BIG:
9897c478bd9Sstevel@tonic-gate 			ret = B_TRUE;
9907c478bd9Sstevel@tonic-gate 			goto out;
9917c478bd9Sstevel@tonic-gate 
9927c478bd9Sstevel@tonic-gate 		default:
9937c478bd9Sstevel@tonic-gate 			assert(0);
9947c478bd9Sstevel@tonic-gate 			abort();
9957c478bd9Sstevel@tonic-gate 		}
9967c478bd9Sstevel@tonic-gate 	}
9977c478bd9Sstevel@tonic-gate 
9987c478bd9Sstevel@tonic-gate out:
9997c478bd9Sstevel@tonic-gate 	scf_instance_destroy(inst);
10007c478bd9Sstevel@tonic-gate 	return (ret);
10017c478bd9Sstevel@tonic-gate }
10027c478bd9Sstevel@tonic-gate 
10037c478bd9Sstevel@tonic-gate /*
10047c478bd9Sstevel@tonic-gate  * Enable the service or instance identified by fmri and its dependencies,
10057c478bd9Sstevel@tonic-gate  * recursively.  Specifically, call get_inst(fmri), enable the result, and
10067c478bd9Sstevel@tonic-gate  * recurse on its restarter and the dependencies.  To avoid duplication of
10077c478bd9Sstevel@tonic-gate  * effort or looping around a dependency cycle, each FMRI is entered into the
10087c478bd9Sstevel@tonic-gate  * "visited" hash table.  While recursing, the hash table entry is marked
10097c478bd9Sstevel@tonic-gate  * "active", so that if we come upon it again, we know we've hit a cycle.
10107c478bd9Sstevel@tonic-gate  * exclude_all and optional_all dependencies are ignored.  require_any
10117c478bd9Sstevel@tonic-gate  * dependencies are followed only if they comprise a single service; otherwise
10127c478bd9Sstevel@tonic-gate  * the user is warned.
10137c478bd9Sstevel@tonic-gate  *
10147c478bd9Sstevel@tonic-gate  * fmri must point to a writable max_scf_fmri_sz buffer.  Returns EINVAL if fmri
10157c478bd9Sstevel@tonic-gate  * is invalid, E2BIG if fmri identifies a service with multiple instances, ELOOP
10167c478bd9Sstevel@tonic-gate  * on cycle detection, or 0 on success.
10177c478bd9Sstevel@tonic-gate  */
10187c478bd9Sstevel@tonic-gate static int
10197c478bd9Sstevel@tonic-gate enable_fmri_rec(char *fmri, boolean_t temp)
10207c478bd9Sstevel@tonic-gate {
10217c478bd9Sstevel@tonic-gate 	scf_instance_t *inst;
10227c478bd9Sstevel@tonic-gate 	scf_snapshot_t *snap;
10237c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg;
10247c478bd9Sstevel@tonic-gate 	scf_property_t *prop;
10257c478bd9Sstevel@tonic-gate 	scf_value_t *v;
10267c478bd9Sstevel@tonic-gate 	scf_iter_t *pg_iter, *val_iter;
10277c478bd9Sstevel@tonic-gate 	scf_type_t ty;
10287c478bd9Sstevel@tonic-gate 	char *buf, *pgname;
10297c478bd9Sstevel@tonic-gate 	ssize_t name_sz, len, sz;
10307c478bd9Sstevel@tonic-gate 	int ret;
10317c478bd9Sstevel@tonic-gate 	struct ht_elt *he;
10327c478bd9Sstevel@tonic-gate 
10337c478bd9Sstevel@tonic-gate 	len = scf_canonify_fmri(fmri, fmri, max_scf_fmri_sz);
10347c478bd9Sstevel@tonic-gate 	if (len < 0) {
10357c478bd9Sstevel@tonic-gate 		assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT);
10367c478bd9Sstevel@tonic-gate 		return (EINVAL);
10377c478bd9Sstevel@tonic-gate 	}
10387c478bd9Sstevel@tonic-gate 	assert(len < max_scf_fmri_sz);
10397c478bd9Sstevel@tonic-gate 
10407c478bd9Sstevel@tonic-gate 	switch (visited_find_or_add(fmri, &he)) {
10417c478bd9Sstevel@tonic-gate 	case 0:
10427c478bd9Sstevel@tonic-gate 		he->active = B_TRUE;
10437c478bd9Sstevel@tonic-gate 		break;
10447c478bd9Sstevel@tonic-gate 
10457c478bd9Sstevel@tonic-gate 	case 1:
10467c478bd9Sstevel@tonic-gate 		return (he->active ? ELOOP : 0);
10477c478bd9Sstevel@tonic-gate 
10487c478bd9Sstevel@tonic-gate 	case -1:
10497c478bd9Sstevel@tonic-gate 		uu_die(emsg_nomem);
10507c478bd9Sstevel@tonic-gate 
10517c478bd9Sstevel@tonic-gate 	default:
10527c478bd9Sstevel@tonic-gate 		assert(0);
10537c478bd9Sstevel@tonic-gate 		abort();
10547c478bd9Sstevel@tonic-gate 	}
10557c478bd9Sstevel@tonic-gate 
10567c478bd9Sstevel@tonic-gate 	inst = scf_instance_create(h);
10577c478bd9Sstevel@tonic-gate 	if (inst == NULL)
10587c478bd9Sstevel@tonic-gate 		scfdie();
10597c478bd9Sstevel@tonic-gate 
10607c478bd9Sstevel@tonic-gate 	switch (get_inst_mult(fmri, inst)) {
10617c478bd9Sstevel@tonic-gate 	case 0:
10627c478bd9Sstevel@tonic-gate 		break;
10637c478bd9Sstevel@tonic-gate 
10647c478bd9Sstevel@tonic-gate 	case E2BIG:
10657c478bd9Sstevel@tonic-gate 		he->active = B_FALSE;
10667c478bd9Sstevel@tonic-gate 		return (E2BIG);
10677c478bd9Sstevel@tonic-gate 
10687c478bd9Sstevel@tonic-gate 	default:
10697c478bd9Sstevel@tonic-gate 		he->active = B_FALSE;
10707c478bd9Sstevel@tonic-gate 		return (0);
10717c478bd9Sstevel@tonic-gate 	}
10727c478bd9Sstevel@tonic-gate 
10737c478bd9Sstevel@tonic-gate 	set_inst_enabled(fmri, inst, temp, B_TRUE);
10747c478bd9Sstevel@tonic-gate 
10757c478bd9Sstevel@tonic-gate 	if ((snap = scf_snapshot_create(h)) == NULL ||
10767c478bd9Sstevel@tonic-gate 	    (pg = scf_pg_create(h)) == NULL ||
10777c478bd9Sstevel@tonic-gate 	    (prop = scf_property_create(h)) == NULL ||
10787c478bd9Sstevel@tonic-gate 	    (v = scf_value_create(h)) == NULL ||
10797c478bd9Sstevel@tonic-gate 	    (pg_iter = scf_iter_create(h)) == NULL ||
10807c478bd9Sstevel@tonic-gate 	    (val_iter = scf_iter_create(h)) == NULL)
10817c478bd9Sstevel@tonic-gate 		scfdie();
10827c478bd9Sstevel@tonic-gate 
10837c478bd9Sstevel@tonic-gate 	buf = malloc(max_scf_fmri_sz);
10847c478bd9Sstevel@tonic-gate 	if (buf == NULL)
10857c478bd9Sstevel@tonic-gate 		uu_die(emsg_nomem);
10867c478bd9Sstevel@tonic-gate 
10877c478bd9Sstevel@tonic-gate 	name_sz = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH);
10887c478bd9Sstevel@tonic-gate 	if (name_sz < 0)
10897c478bd9Sstevel@tonic-gate 		scfdie();
10907c478bd9Sstevel@tonic-gate 	++name_sz;
10917c478bd9Sstevel@tonic-gate 	pgname = malloc(name_sz);
10927c478bd9Sstevel@tonic-gate 	if (pgname == NULL)
10937c478bd9Sstevel@tonic-gate 		uu_die(emsg_nomem);
10947c478bd9Sstevel@tonic-gate 
10957c478bd9Sstevel@tonic-gate 	if (scf_instance_get_snapshot(inst, "running", snap) != 0) {
10967c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND)
10977c478bd9Sstevel@tonic-gate 			scfdie();
10987c478bd9Sstevel@tonic-gate 
10997c478bd9Sstevel@tonic-gate 		scf_snapshot_destroy(snap);
11007c478bd9Sstevel@tonic-gate 		snap = NULL;
11017c478bd9Sstevel@tonic-gate 	}
11027c478bd9Sstevel@tonic-gate 
11037c478bd9Sstevel@tonic-gate 	/* Enable restarter */
11047c478bd9Sstevel@tonic-gate 	if (scf_instance_get_pg_composed(inst, snap, SCF_PG_GENERAL, pg) != 0) {
11057c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND)
11067c478bd9Sstevel@tonic-gate 			scfdie();
11077c478bd9Sstevel@tonic-gate 
11087c478bd9Sstevel@tonic-gate 		uu_warn(gettext("\"%s\" is misconfigured (lacks \"%s\" "
11097c478bd9Sstevel@tonic-gate 		    "property group).\n"), fmri, SCF_PG_GENERAL);
11107c478bd9Sstevel@tonic-gate 		ret = 0;
11117c478bd9Sstevel@tonic-gate 		goto out;
11127c478bd9Sstevel@tonic-gate 	}
11137c478bd9Sstevel@tonic-gate 
11147c478bd9Sstevel@tonic-gate 	sz = get_astring_prop(pg, SCF_PROPERTY_RESTARTER, prop, v, buf,
11157c478bd9Sstevel@tonic-gate 	    max_scf_fmri_sz);
11167c478bd9Sstevel@tonic-gate 	if (sz > max_scf_fmri_sz) {
11177c478bd9Sstevel@tonic-gate 		uu_warn(gettext("\"%s\" is misconfigured (the value of "
11187c478bd9Sstevel@tonic-gate 		    "\"%s/%s\" is too long).\n"), fmri, SCF_PG_GENERAL,
11197c478bd9Sstevel@tonic-gate 		    SCF_PROPERTY_RESTARTER);
11207c478bd9Sstevel@tonic-gate 		ret = 0;
11217c478bd9Sstevel@tonic-gate 		goto out;
11227c478bd9Sstevel@tonic-gate 	} else if (sz >= 0) {
11237c478bd9Sstevel@tonic-gate 		switch (enable_fmri_rec(buf, temp)) {
11247c478bd9Sstevel@tonic-gate 		case 0:
11257c478bd9Sstevel@tonic-gate 			break;
11267c478bd9Sstevel@tonic-gate 
11277c478bd9Sstevel@tonic-gate 		case EINVAL:
11287c478bd9Sstevel@tonic-gate 			uu_warn(gettext("Restarter FMRI for \"%s\" is "
11297c478bd9Sstevel@tonic-gate 			    "invalid.\n"), fmri);
11307c478bd9Sstevel@tonic-gate 			break;
11317c478bd9Sstevel@tonic-gate 
11327c478bd9Sstevel@tonic-gate 		case E2BIG:
11337c478bd9Sstevel@tonic-gate 			uu_warn(gettext("Restarter FMRI for \"%s\" identifies "
11347c478bd9Sstevel@tonic-gate 			    "a service with multiple instances.\n"), fmri);
11357c478bd9Sstevel@tonic-gate 			break;
11367c478bd9Sstevel@tonic-gate 
11377c478bd9Sstevel@tonic-gate 		case ELOOP:
11387c478bd9Sstevel@tonic-gate 			ret = ELOOP;
11397c478bd9Sstevel@tonic-gate 			goto out;
11407c478bd9Sstevel@tonic-gate 
11417c478bd9Sstevel@tonic-gate 		default:
11427c478bd9Sstevel@tonic-gate 			assert(0);
11437c478bd9Sstevel@tonic-gate 			abort();
11447c478bd9Sstevel@tonic-gate 		}
11457c478bd9Sstevel@tonic-gate 	} else if (sz < 0) {
11467c478bd9Sstevel@tonic-gate 		switch (-sz) {
11477c478bd9Sstevel@tonic-gate 		case ENOENT:
11487c478bd9Sstevel@tonic-gate 			break;
11497c478bd9Sstevel@tonic-gate 
11507c478bd9Sstevel@tonic-gate 		case E2BIG:
11517c478bd9Sstevel@tonic-gate 			uu_warn(gettext("\"%s\" is misconfigured (\"%s/%s\" "
11527c478bd9Sstevel@tonic-gate 			    "property is not single-valued).\n"), fmri,
11537c478bd9Sstevel@tonic-gate 			    SCF_PG_GENERAL, SCF_PROPERTY_RESTARTER);
11547c478bd9Sstevel@tonic-gate 			ret = 0;
11557c478bd9Sstevel@tonic-gate 			goto out;
11567c478bd9Sstevel@tonic-gate 
11577c478bd9Sstevel@tonic-gate 		case EINVAL:
11587c478bd9Sstevel@tonic-gate 			uu_warn(gettext("\"%s\" is misconfigured (\"%s/%s\" "
11597c478bd9Sstevel@tonic-gate 			    "property is not of astring type).\n"), fmri,
11607c478bd9Sstevel@tonic-gate 			    SCF_PG_GENERAL, SCF_PROPERTY_RESTARTER);
11617c478bd9Sstevel@tonic-gate 			ret = 0;
11627c478bd9Sstevel@tonic-gate 			goto out;
11637c478bd9Sstevel@tonic-gate 
11647c478bd9Sstevel@tonic-gate 		default:
11657c478bd9Sstevel@tonic-gate 			assert(0);
11667c478bd9Sstevel@tonic-gate 			abort();
11677c478bd9Sstevel@tonic-gate 		}
11687c478bd9Sstevel@tonic-gate 	}
11697c478bd9Sstevel@tonic-gate 
11707c478bd9Sstevel@tonic-gate 	if (scf_iter_instance_pgs_typed_composed(pg_iter, inst, snap,
11717c478bd9Sstevel@tonic-gate 	    SCF_GROUP_DEPENDENCY) == -1)
11727c478bd9Sstevel@tonic-gate 		scfdie();
11737c478bd9Sstevel@tonic-gate 
11747c478bd9Sstevel@tonic-gate 	while (scf_iter_next_pg(pg_iter, pg) > 0) {
11757c478bd9Sstevel@tonic-gate 		len = scf_pg_get_name(pg, pgname, name_sz);
11767c478bd9Sstevel@tonic-gate 		if (len < 0)
11777c478bd9Sstevel@tonic-gate 			scfdie();
11787c478bd9Sstevel@tonic-gate 		assert(len < name_sz);
11797c478bd9Sstevel@tonic-gate 
11807c478bd9Sstevel@tonic-gate 		if (dep_get_astring(fmri, pgname, pg, SCF_PROPERTY_TYPE, prop,
11817c478bd9Sstevel@tonic-gate 		    v, buf, max_scf_fmri_sz) < 0)
11827c478bd9Sstevel@tonic-gate 			continue;
11837c478bd9Sstevel@tonic-gate 
11847c478bd9Sstevel@tonic-gate 		if (strcmp(buf, "service") != 0)
11857c478bd9Sstevel@tonic-gate 			continue;
11867c478bd9Sstevel@tonic-gate 
11877c478bd9Sstevel@tonic-gate 		if (dep_get_astring(fmri, pgname, pg, SCF_PROPERTY_GROUPING,
11887c478bd9Sstevel@tonic-gate 		    prop, v, buf, max_scf_fmri_sz) < 0)
11897c478bd9Sstevel@tonic-gate 			continue;
11907c478bd9Sstevel@tonic-gate 
11917c478bd9Sstevel@tonic-gate 		if (strcmp(buf, SCF_DEP_EXCLUDE_ALL) == 0 ||
11927c478bd9Sstevel@tonic-gate 		    strcmp(buf, SCF_DEP_OPTIONAL_ALL) == 0)
11937c478bd9Sstevel@tonic-gate 			continue;
11947c478bd9Sstevel@tonic-gate 
11957c478bd9Sstevel@tonic-gate 		if (strcmp(buf, SCF_DEP_REQUIRE_ALL) != 0 &&
11967c478bd9Sstevel@tonic-gate 		    strcmp(buf, SCF_DEP_REQUIRE_ANY) != 0) {
11977c478bd9Sstevel@tonic-gate 			uu_warn(gettext("Dependency \"%s\" of \"%s\" has "
11987c478bd9Sstevel@tonic-gate 			    "unknown type \"%s\".\n"), pgname, fmri, buf);
11997c478bd9Sstevel@tonic-gate 			continue;
12007c478bd9Sstevel@tonic-gate 		}
12017c478bd9Sstevel@tonic-gate 
12027c478bd9Sstevel@tonic-gate 		if (scf_pg_get_property(pg, SCF_PROPERTY_ENTITIES, prop) ==
12037c478bd9Sstevel@tonic-gate 		    -1) {
12047c478bd9Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_NOT_FOUND)
12057c478bd9Sstevel@tonic-gate 				scfdie();
12067c478bd9Sstevel@tonic-gate 
12077c478bd9Sstevel@tonic-gate 			uu_warn(gettext("\"%s\" is misconfigured (\"%s\" "
12087c478bd9Sstevel@tonic-gate 			    "dependency lacks \"%s\" property.)\n"), fmri,
12097c478bd9Sstevel@tonic-gate 			    pgname, SCF_PROPERTY_ENTITIES);
12107c478bd9Sstevel@tonic-gate 			continue;
12117c478bd9Sstevel@tonic-gate 		}
12127c478bd9Sstevel@tonic-gate 
12137c478bd9Sstevel@tonic-gate 		if (scf_property_type(prop, &ty) != SCF_SUCCESS)
12147c478bd9Sstevel@tonic-gate 			scfdie();
12157c478bd9Sstevel@tonic-gate 
12167c478bd9Sstevel@tonic-gate 		if (ty != SCF_TYPE_FMRI) {
12177c478bd9Sstevel@tonic-gate 			uu_warn(gettext("\"%s\" is misconfigured (property "
12187c478bd9Sstevel@tonic-gate 			    "\"%s/%s\" is not of fmri type).\n"), fmri, pgname,
12197c478bd9Sstevel@tonic-gate 			    SCF_PROPERTY_ENTITIES);
12207c478bd9Sstevel@tonic-gate 			continue;
12217c478bd9Sstevel@tonic-gate 		}
12227c478bd9Sstevel@tonic-gate 
12237c478bd9Sstevel@tonic-gate 		if (scf_iter_property_values(val_iter, prop) == -1)
12247c478bd9Sstevel@tonic-gate 			scfdie();
12257c478bd9Sstevel@tonic-gate 
12267c478bd9Sstevel@tonic-gate 		if (strcmp(buf, SCF_DEP_REQUIRE_ANY) == 0) {
12277c478bd9Sstevel@tonic-gate 			if (multiple_instances(val_iter, v, buf)) {
12287c478bd9Sstevel@tonic-gate 				(void) printf(gettext("%s requires one of:\n"),
12297c478bd9Sstevel@tonic-gate 				    fmri);
12307c478bd9Sstevel@tonic-gate 
12317c478bd9Sstevel@tonic-gate 				if (scf_iter_property_values(val_iter, prop) !=
12327c478bd9Sstevel@tonic-gate 				    0)
12337c478bd9Sstevel@tonic-gate 					scfdie();
12347c478bd9Sstevel@tonic-gate 
12357c478bd9Sstevel@tonic-gate 				for (;;) {
12367c478bd9Sstevel@tonic-gate 					int r;
12377c478bd9Sstevel@tonic-gate 
12387c478bd9Sstevel@tonic-gate 					r = scf_iter_next_value(val_iter, v);
12397c478bd9Sstevel@tonic-gate 					if (r == 0)
12407c478bd9Sstevel@tonic-gate 						break;
12417c478bd9Sstevel@tonic-gate 					if (r != 1)
12427c478bd9Sstevel@tonic-gate 						scfdie();
12437c478bd9Sstevel@tonic-gate 
12447c478bd9Sstevel@tonic-gate 					if (scf_value_get_astring(v, buf,
12457c478bd9Sstevel@tonic-gate 					    max_scf_fmri_sz) < 0)
12467c478bd9Sstevel@tonic-gate 						scfdie();
12477c478bd9Sstevel@tonic-gate 
12487c478bd9Sstevel@tonic-gate 					(void) fputs("  ", stdout);
12497c478bd9Sstevel@tonic-gate 					(void) puts(buf);
12507c478bd9Sstevel@tonic-gate 				}
12517c478bd9Sstevel@tonic-gate 
12527c478bd9Sstevel@tonic-gate 				continue;
12537c478bd9Sstevel@tonic-gate 			}
12547c478bd9Sstevel@tonic-gate 
12557c478bd9Sstevel@tonic-gate 			/*
12567c478bd9Sstevel@tonic-gate 			 * Since there's only one instance, we can enable it.
12577c478bd9Sstevel@tonic-gate 			 * Reset val_iter and continue.
12587c478bd9Sstevel@tonic-gate 			 */
12597c478bd9Sstevel@tonic-gate 			if (scf_iter_property_values(val_iter, prop) != 0)
12607c478bd9Sstevel@tonic-gate 				scfdie();
12617c478bd9Sstevel@tonic-gate 		}
12627c478bd9Sstevel@tonic-gate 
12637c478bd9Sstevel@tonic-gate 		for (;;) {
12647c478bd9Sstevel@tonic-gate 			ret = scf_iter_next_value(val_iter, v);
12657c478bd9Sstevel@tonic-gate 			if (ret == 0)
12667c478bd9Sstevel@tonic-gate 				break;
12677c478bd9Sstevel@tonic-gate 			if (ret != 1)
12687c478bd9Sstevel@tonic-gate 				scfdie();
12697c478bd9Sstevel@tonic-gate 
12707c478bd9Sstevel@tonic-gate 			if (scf_value_get_astring(v, buf, max_scf_fmri_sz) ==
12717c478bd9Sstevel@tonic-gate 			    -1)
12727c478bd9Sstevel@tonic-gate 				scfdie();
12737c478bd9Sstevel@tonic-gate 
12747c478bd9Sstevel@tonic-gate 			switch (enable_fmri_rec(buf, temp)) {
12757c478bd9Sstevel@tonic-gate 			case 0:
12767c478bd9Sstevel@tonic-gate 				break;
12777c478bd9Sstevel@tonic-gate 
12787c478bd9Sstevel@tonic-gate 			case EINVAL:
12797c478bd9Sstevel@tonic-gate 				uu_warn(gettext("\"%s\" dependency of \"%s\" "
12807c478bd9Sstevel@tonic-gate 				    "has invalid FMRI \"%s\".\n"), pgname,
12817c478bd9Sstevel@tonic-gate 				    fmri, buf);
12827c478bd9Sstevel@tonic-gate 				break;
12837c478bd9Sstevel@tonic-gate 
12847c478bd9Sstevel@tonic-gate 			case E2BIG:
12857c478bd9Sstevel@tonic-gate 				uu_warn(gettext("%s depends on %s, which has "
12867c478bd9Sstevel@tonic-gate 				    "multiple instances.\n"), fmri, buf);
12877c478bd9Sstevel@tonic-gate 				break;
12887c478bd9Sstevel@tonic-gate 
12897c478bd9Sstevel@tonic-gate 			case ELOOP:
12907c478bd9Sstevel@tonic-gate 				ret = ELOOP;
12917c478bd9Sstevel@tonic-gate 				goto out;
12927c478bd9Sstevel@tonic-gate 
12937c478bd9Sstevel@tonic-gate 			default:
12947c478bd9Sstevel@tonic-gate 				assert(0);
12957c478bd9Sstevel@tonic-gate 				abort();
12967c478bd9Sstevel@tonic-gate 			}
12977c478bd9Sstevel@tonic-gate 		}
12987c478bd9Sstevel@tonic-gate 	}
12997c478bd9Sstevel@tonic-gate 
13007c478bd9Sstevel@tonic-gate 	ret = 0;
13017c478bd9Sstevel@tonic-gate 
13027c478bd9Sstevel@tonic-gate out:
13037c478bd9Sstevel@tonic-gate 	he->active = B_FALSE;
13047c478bd9Sstevel@tonic-gate 
13057c478bd9Sstevel@tonic-gate 	free(buf);
13067c478bd9Sstevel@tonic-gate 	free(pgname);
13077c478bd9Sstevel@tonic-gate 
13087c478bd9Sstevel@tonic-gate 	(void) scf_value_destroy(v);
13097c478bd9Sstevel@tonic-gate 	scf_property_destroy(prop);
13107c478bd9Sstevel@tonic-gate 	scf_pg_destroy(pg);
13117c478bd9Sstevel@tonic-gate 	scf_snapshot_destroy(snap);
13127c478bd9Sstevel@tonic-gate 	scf_iter_destroy(pg_iter);
13137c478bd9Sstevel@tonic-gate 	scf_iter_destroy(val_iter);
13147c478bd9Sstevel@tonic-gate 
13157c478bd9Sstevel@tonic-gate 	return (ret);
13167c478bd9Sstevel@tonic-gate }
13177c478bd9Sstevel@tonic-gate 
13187c478bd9Sstevel@tonic-gate /*
13197c478bd9Sstevel@tonic-gate  * fmri here is only used for verbose messages.
13207c478bd9Sstevel@tonic-gate  */
13217c478bd9Sstevel@tonic-gate static void
13227c478bd9Sstevel@tonic-gate set_inst_action(const char *fmri, const scf_instance_t *inst,
13237c478bd9Sstevel@tonic-gate     const char *action)
13247c478bd9Sstevel@tonic-gate {
13257c478bd9Sstevel@tonic-gate 	scf_transaction_t *tx;
13267c478bd9Sstevel@tonic-gate 	scf_transaction_entry_t *ent;
13277c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg;
13287c478bd9Sstevel@tonic-gate 	scf_property_t *prop;
13297c478bd9Sstevel@tonic-gate 	scf_value_t *v;
13307c478bd9Sstevel@tonic-gate 	int ret;
13317c478bd9Sstevel@tonic-gate 	int64_t t;
13327c478bd9Sstevel@tonic-gate 	hrtime_t timestamp;
13337c478bd9Sstevel@tonic-gate 
13347c478bd9Sstevel@tonic-gate 	const char * const scf_pg_restarter_actions = SCF_PG_RESTARTER_ACTIONS;
13357c478bd9Sstevel@tonic-gate 
13367c478bd9Sstevel@tonic-gate 	if ((pg = scf_pg_create(h)) == NULL ||
13377c478bd9Sstevel@tonic-gate 	    (prop = scf_property_create(h)) == NULL ||
13387c478bd9Sstevel@tonic-gate 	    (v = scf_value_create(h)) == NULL ||
13397c478bd9Sstevel@tonic-gate 	    (tx = scf_transaction_create(h)) == NULL ||
13407c478bd9Sstevel@tonic-gate 	    (ent = scf_entry_create(h)) == NULL)
13417c478bd9Sstevel@tonic-gate 		scfdie();
13427c478bd9Sstevel@tonic-gate 
1343a97d4a16SDave Eddy 	if (restarter_setup(fmri, inst)) {
1344a97d4a16SDave Eddy 		exit_status = 1;
1345e8f5b3f5STruong Nguyen 		goto out;
1346a97d4a16SDave Eddy 	}
1347eb1a3463STruong Nguyen 
13487c478bd9Sstevel@tonic-gate 	if (scf_instance_get_pg(inst, scf_pg_restarter_actions, pg) == -1) {
13497c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND)
13507c478bd9Sstevel@tonic-gate 			scfdie();
13517c478bd9Sstevel@tonic-gate 
13527c478bd9Sstevel@tonic-gate 		/* Try creating the restarter_actions property group. */
13537c478bd9Sstevel@tonic-gate 		if (scf_instance_add_pg(inst, scf_pg_restarter_actions,
13547c478bd9Sstevel@tonic-gate 		    SCF_PG_RESTARTER_ACTIONS_TYPE,
13557c478bd9Sstevel@tonic-gate 		    SCF_PG_RESTARTER_ACTIONS_FLAGS, pg) == -1) {
13567c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
13577c478bd9Sstevel@tonic-gate 			case SCF_ERROR_EXISTS:
13587c478bd9Sstevel@tonic-gate 				/* Someone must have added it. */
13597c478bd9Sstevel@tonic-gate 				break;
13607c478bd9Sstevel@tonic-gate 
13617c478bd9Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
13627c478bd9Sstevel@tonic-gate 				if (!verbose)
13637c478bd9Sstevel@tonic-gate 					uu_warn(emsg_permission_denied, fmri);
13647c478bd9Sstevel@tonic-gate 				else
13657c478bd9Sstevel@tonic-gate 					uu_warn(emsg_create_pg_perm_denied,
13667c478bd9Sstevel@tonic-gate 					    fmri, scf_pg_restarter_actions);
13677c478bd9Sstevel@tonic-gate 				goto out;
13687c478bd9Sstevel@tonic-gate 
13697c478bd9Sstevel@tonic-gate 			default:
13707c478bd9Sstevel@tonic-gate 				scfdie();
13717c478bd9Sstevel@tonic-gate 			}
13727c478bd9Sstevel@tonic-gate 		}
13737c478bd9Sstevel@tonic-gate 	}
13747c478bd9Sstevel@tonic-gate 
13757c478bd9Sstevel@tonic-gate 	/*
13767c478bd9Sstevel@tonic-gate 	 * If we lose the transaction race and need to retry, there are 2
13777c478bd9Sstevel@tonic-gate 	 * potential other winners:
13787c478bd9Sstevel@tonic-gate 	 *	- another process setting actions
13797c478bd9Sstevel@tonic-gate 	 *	- the restarter marking the action complete
13807c478bd9Sstevel@tonic-gate 	 * Therefore, re-read the property every time through the loop before
13817c478bd9Sstevel@tonic-gate 	 * making any decisions based on their values.
13827c478bd9Sstevel@tonic-gate 	 */
13837c478bd9Sstevel@tonic-gate 	do {
13847c478bd9Sstevel@tonic-gate 		timestamp = gethrtime();
13857c478bd9Sstevel@tonic-gate 
13867c478bd9Sstevel@tonic-gate 		if (scf_transaction_start(tx, pg) == -1) {
13877c478bd9Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13887c478bd9Sstevel@tonic-gate 				scfdie();
13897c478bd9Sstevel@tonic-gate 
13907c478bd9Sstevel@tonic-gate 			if (!verbose)
13917c478bd9Sstevel@tonic-gate 				uu_warn(emsg_permission_denied, fmri);
13927c478bd9Sstevel@tonic-gate 			else
13937c478bd9Sstevel@tonic-gate 				uu_warn(emsg_pg_perm_denied, fmri,
13947c478bd9Sstevel@tonic-gate 				    scf_pg_restarter_actions);
13957c478bd9Sstevel@tonic-gate 			goto out;
13967c478bd9Sstevel@tonic-gate 		}
13977c478bd9Sstevel@tonic-gate 
13987c478bd9Sstevel@tonic-gate 		if (scf_pg_get_property(pg, action, prop) == -1) {
13997c478bd9Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_NOT_FOUND)
14007c478bd9Sstevel@tonic-gate 				scfdie();
14017c478bd9Sstevel@tonic-gate 			if (scf_transaction_property_new(tx, ent,
14027c478bd9Sstevel@tonic-gate 			    action, SCF_TYPE_INTEGER) == -1)
14037c478bd9Sstevel@tonic-gate 				scfdie();
14047c478bd9Sstevel@tonic-gate 			goto action_set;
14057c478bd9Sstevel@tonic-gate 		} else {
14067c478bd9Sstevel@tonic-gate 			if (scf_transaction_property_change_type(tx, ent,
14077c478bd9Sstevel@tonic-gate 			    action, SCF_TYPE_INTEGER) == -1)
14087c478bd9Sstevel@tonic-gate 				scfdie();
14097c478bd9Sstevel@tonic-gate 		}
14107c478bd9Sstevel@tonic-gate 
14117c478bd9Sstevel@tonic-gate 		if (scf_property_get_value(prop, v) == -1) {
14127c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
14137c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONSTRAINT_VIOLATED:
14147c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_FOUND:
14157c478bd9Sstevel@tonic-gate 				/* Misconfigured, so set anyway. */
14167c478bd9Sstevel@tonic-gate 				goto action_set;
14177c478bd9Sstevel@tonic-gate 
14187c478bd9Sstevel@tonic-gate 			default:
14197c478bd9Sstevel@tonic-gate 				scfdie();
14207c478bd9Sstevel@tonic-gate 			}
14217c478bd9Sstevel@tonic-gate 		} else {
14227c478bd9Sstevel@tonic-gate 			if (scf_value_get_integer(v, &t) == -1) {
14237c478bd9Sstevel@tonic-gate 				assert(scf_error() == SCF_ERROR_TYPE_MISMATCH);
14247c478bd9Sstevel@tonic-gate 				goto action_set;
14257c478bd9Sstevel@tonic-gate 			}
14267c478bd9Sstevel@tonic-gate 			if (t > timestamp)
14277c478bd9Sstevel@tonic-gate 				break;
14287c478bd9Sstevel@tonic-gate 		}
14297c478bd9Sstevel@tonic-gate 
14307c478bd9Sstevel@tonic-gate action_set:
14317c478bd9Sstevel@tonic-gate 		scf_value_set_integer(v, timestamp);
14327c478bd9Sstevel@tonic-gate 		if (scf_entry_add_value(ent, v) == -1)
14337c478bd9Sstevel@tonic-gate 			scfdie();
14347c478bd9Sstevel@tonic-gate 
14357c478bd9Sstevel@tonic-gate 		ret = scf_transaction_commit(tx);
14367c478bd9Sstevel@tonic-gate 		if (ret == -1) {
14377c478bd9Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14387c478bd9Sstevel@tonic-gate 				scfdie();
14397c478bd9Sstevel@tonic-gate 
14407c478bd9Sstevel@tonic-gate 			if (!verbose)
14417c478bd9Sstevel@tonic-gate 				uu_warn(emsg_permission_denied, fmri);
14427c478bd9Sstevel@tonic-gate 			else
14437c478bd9Sstevel@tonic-gate 				uu_warn(emsg_prop_perm_denied, fmri,
14447c478bd9Sstevel@tonic-gate 				    scf_pg_restarter_actions, action);
14457c478bd9Sstevel@tonic-gate 			scf_transaction_reset(tx);
14467c478bd9Sstevel@tonic-gate 			goto out;
14477c478bd9Sstevel@tonic-gate 		}
14487c478bd9Sstevel@tonic-gate 
14497c478bd9Sstevel@tonic-gate 		scf_transaction_reset(tx);
14507c478bd9Sstevel@tonic-gate 
14517c478bd9Sstevel@tonic-gate 		if (ret == 0) {
14527c478bd9Sstevel@tonic-gate 			if (scf_pg_update(pg) == -1)
14537c478bd9Sstevel@tonic-gate 				scfdie();
14547c478bd9Sstevel@tonic-gate 		}
14557c478bd9Sstevel@tonic-gate 	} while (ret == 0);
14567c478bd9Sstevel@tonic-gate 
14577c478bd9Sstevel@tonic-gate 	if (verbose)
14587c478bd9Sstevel@tonic-gate 		(void) printf(gettext("Action %s set for %s.\n"), action, fmri);
14597c478bd9Sstevel@tonic-gate 
14607c478bd9Sstevel@tonic-gate out:
14617c478bd9Sstevel@tonic-gate 	scf_value_destroy(v);
14627c478bd9Sstevel@tonic-gate 	scf_entry_destroy(ent);
14637c478bd9Sstevel@tonic-gate 	scf_transaction_destroy(tx);
14647c478bd9Sstevel@tonic-gate 	scf_property_destroy(prop);
14657c478bd9Sstevel@tonic-gate 	scf_pg_destroy(pg);
14667c478bd9Sstevel@tonic-gate }
14677c478bd9Sstevel@tonic-gate 
14687c478bd9Sstevel@tonic-gate /*
14697c478bd9Sstevel@tonic-gate  * Get the state of inst.  state should point to a buffer of
14707c478bd9Sstevel@tonic-gate  * MAX_SCF_STATE_STRING_SZ bytes.  Returns 0 on success or -1 if
14717c478bd9Sstevel@tonic-gate  *   no restarter property group
14727c478bd9Sstevel@tonic-gate  *   no state property
14737c478bd9Sstevel@tonic-gate  *   state property is misconfigured (wrong type, not single-valued)
14747c478bd9Sstevel@tonic-gate  *   state value is too long
14757c478bd9Sstevel@tonic-gate  * In these cases, fmri is used to print a warning.
14767c478bd9Sstevel@tonic-gate  *
14777c478bd9Sstevel@tonic-gate  * If pgp is non-NULL, a successful call to inst_get_state will store
14787c478bd9Sstevel@tonic-gate  * the SCF_PG_RESTARTER property group in *pgp, and the caller will be
14797c478bd9Sstevel@tonic-gate  * responsible for calling scf_pg_destroy on the property group.
14807c478bd9Sstevel@tonic-gate  */
14817c478bd9Sstevel@tonic-gate int
14827c478bd9Sstevel@tonic-gate inst_get_state(scf_instance_t *inst, char *state, const char *fmri,
14837c478bd9Sstevel@tonic-gate     scf_propertygroup_t **pgp)
14847c478bd9Sstevel@tonic-gate {
14857c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg;
14867c478bd9Sstevel@tonic-gate 	scf_property_t *prop;
14877c478bd9Sstevel@tonic-gate 	scf_value_t *val;
14887c478bd9Sstevel@tonic-gate 	int ret = -1;
14897c478bd9Sstevel@tonic-gate 	ssize_t szret;
14907c478bd9Sstevel@tonic-gate 
14917c478bd9Sstevel@tonic-gate 	if ((pg = scf_pg_create(h)) == NULL ||
14927c478bd9Sstevel@tonic-gate 	    (prop = scf_property_create(h)) == NULL ||
14937c478bd9Sstevel@tonic-gate 	    (val = scf_value_create(h)) == NULL)
14947c478bd9Sstevel@tonic-gate 		scfdie();
14957c478bd9Sstevel@tonic-gate 
14967c478bd9Sstevel@tonic-gate 	if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) {
14977c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND)
14987c478bd9Sstevel@tonic-gate 			scfdie();
14997c478bd9Sstevel@tonic-gate 
15007c478bd9Sstevel@tonic-gate 		uu_warn(gettext("%s is misconfigured (lacks \"%s\" property "
15017c478bd9Sstevel@tonic-gate 		    "group).\n"), fmri ? fmri : inst_get_fmri(inst),
15027c478bd9Sstevel@tonic-gate 		    SCF_PG_RESTARTER);
15037c478bd9Sstevel@tonic-gate 		goto out;
15047c478bd9Sstevel@tonic-gate 	}
15057c478bd9Sstevel@tonic-gate 
15067c478bd9Sstevel@tonic-gate 	szret = get_astring_prop(pg, SCF_PROPERTY_STATE, prop, val, state,
15077c478bd9Sstevel@tonic-gate 	    MAX_SCF_STATE_STRING_SZ);
15087c478bd9Sstevel@tonic-gate 	if (szret < 0) {
15097c478bd9Sstevel@tonic-gate 		switch (-szret) {
15107c478bd9Sstevel@tonic-gate 		case ENOENT:
15117c478bd9Sstevel@tonic-gate 			uu_warn(gettext("%s is misconfigured (\"%s\" property "
15127c478bd9Sstevel@tonic-gate 			    "group lacks \"%s\" property).\n"),
15137c478bd9Sstevel@tonic-gate 			    fmri ? fmri : inst_get_fmri(inst), SCF_PG_RESTARTER,
15147c478bd9Sstevel@tonic-gate 			    SCF_PROPERTY_STATE);
15157c478bd9Sstevel@tonic-gate 			goto out;
15167c478bd9Sstevel@tonic-gate 
15177c478bd9Sstevel@tonic-gate 		case E2BIG:
15187c478bd9Sstevel@tonic-gate 			uu_warn(gettext("%s is misconfigured (\"%s/%s\" "
15197c478bd9Sstevel@tonic-gate 			    "property is not single-valued).\n"),
15207c478bd9Sstevel@tonic-gate 			    fmri ? fmri : inst_get_fmri(inst), SCF_PG_RESTARTER,
15217c478bd9Sstevel@tonic-gate 			    SCF_PROPERTY_STATE);
15227c478bd9Sstevel@tonic-gate 			goto out;
15237c478bd9Sstevel@tonic-gate 
15247c478bd9Sstevel@tonic-gate 		case EINVAL:
15257c478bd9Sstevel@tonic-gate 			uu_warn(gettext("%s is misconfigured (\"%s/%s\" "
15267c478bd9Sstevel@tonic-gate 			    "property is not of type astring).\n"),
15277c478bd9Sstevel@tonic-gate 			    fmri ? fmri : inst_get_fmri(inst), SCF_PG_RESTARTER,
15287c478bd9Sstevel@tonic-gate 			    SCF_PROPERTY_STATE);
15297c478bd9Sstevel@tonic-gate 			goto out;
15307c478bd9Sstevel@tonic-gate 
15317c478bd9Sstevel@tonic-gate 		default:
15327c478bd9Sstevel@tonic-gate 			assert(0);
15337c478bd9Sstevel@tonic-gate 			abort();
15347c478bd9Sstevel@tonic-gate 		}
15357c478bd9Sstevel@tonic-gate 	}
15367c478bd9Sstevel@tonic-gate 	if (szret >= MAX_SCF_STATE_STRING_SZ) {
15377c478bd9Sstevel@tonic-gate 		uu_warn(gettext("%s is misconfigured (\"%s/%s\" property value "
15387c478bd9Sstevel@tonic-gate 		    "is too long).\n"), fmri ? fmri : inst_get_fmri(inst),
15397c478bd9Sstevel@tonic-gate 		    SCF_PG_RESTARTER, SCF_PROPERTY_STATE);
15407c478bd9Sstevel@tonic-gate 		goto out;
15417c478bd9Sstevel@tonic-gate 	}
15427c478bd9Sstevel@tonic-gate 
15437c478bd9Sstevel@tonic-gate 	ret = 0;
15447c478bd9Sstevel@tonic-gate 	if (pgp)
15457c478bd9Sstevel@tonic-gate 		*pgp = pg;
15467c478bd9Sstevel@tonic-gate 
15477c478bd9Sstevel@tonic-gate out:
15487c478bd9Sstevel@tonic-gate 	(void) scf_value_destroy(val);
15497c478bd9Sstevel@tonic-gate 	scf_property_destroy(prop);
15507c478bd9Sstevel@tonic-gate 	if (ret || pgp == NULL)
15517c478bd9Sstevel@tonic-gate 		scf_pg_destroy(pg);
15527c478bd9Sstevel@tonic-gate 	return (ret);
15537c478bd9Sstevel@tonic-gate }
15547c478bd9Sstevel@tonic-gate 
15557c478bd9Sstevel@tonic-gate static void
15567c478bd9Sstevel@tonic-gate set_astring_prop(const char *fmri, const char *pgname, const char *pgtype,
15577c478bd9Sstevel@tonic-gate     uint32_t pgflags, const char *propname, const char *str)
15587c478bd9Sstevel@tonic-gate {
15597c478bd9Sstevel@tonic-gate 	scf_instance_t *inst;
15607c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg;
15617c478bd9Sstevel@tonic-gate 	scf_property_t *prop;
15627c478bd9Sstevel@tonic-gate 	scf_value_t *val;
15637c478bd9Sstevel@tonic-gate 	scf_transaction_t *tx;
15647c478bd9Sstevel@tonic-gate 	scf_transaction_entry_t *txent;
15657c478bd9Sstevel@tonic-gate 	int ret;
15667c478bd9Sstevel@tonic-gate 
15677c478bd9Sstevel@tonic-gate 	inst = scf_instance_create(h);
15687c478bd9Sstevel@tonic-gate 	if (inst == NULL)
15697c478bd9Sstevel@tonic-gate 		scfdie();
15707c478bd9Sstevel@tonic-gate 
15717c478bd9Sstevel@tonic-gate 	if (get_inst(fmri, inst) != 0)
15727c478bd9Sstevel@tonic-gate 		return;
15737c478bd9Sstevel@tonic-gate 
15747c478bd9Sstevel@tonic-gate 	if ((pg = scf_pg_create(h)) == NULL ||
15757c478bd9Sstevel@tonic-gate 	    (prop = scf_property_create(h)) == NULL ||
15767c478bd9Sstevel@tonic-gate 	    (val = scf_value_create(h)) == NULL ||
15777c478bd9Sstevel@tonic-gate 	    (tx = scf_transaction_create(h)) == NULL ||
15787c478bd9Sstevel@tonic-gate 	    (txent = scf_entry_create(h)) == NULL)
15797c478bd9Sstevel@tonic-gate 		scfdie();
15807c478bd9Sstevel@tonic-gate 
15817c478bd9Sstevel@tonic-gate 	if (scf_instance_get_pg(inst, pgname, pg) != SCF_SUCCESS) {
15827c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND)
15837c478bd9Sstevel@tonic-gate 			scfdie();
15847c478bd9Sstevel@tonic-gate 
15857c478bd9Sstevel@tonic-gate 		if (scf_instance_add_pg(inst, pgname, pgtype, pgflags, pg) !=
15867c478bd9Sstevel@tonic-gate 		    SCF_SUCCESS) {
15877c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
15887c478bd9Sstevel@tonic-gate 			case SCF_ERROR_EXISTS:
15897c478bd9Sstevel@tonic-gate 				if (scf_instance_get_pg(inst, pgname, pg) !=
15907c478bd9Sstevel@tonic-gate 				    SCF_SUCCESS) {
15917c478bd9Sstevel@tonic-gate 					if (scf_error() != SCF_ERROR_NOT_FOUND)
15927c478bd9Sstevel@tonic-gate 						scfdie();
15937c478bd9Sstevel@tonic-gate 
15947c478bd9Sstevel@tonic-gate 					uu_warn(gettext("Repository write "
15957c478bd9Sstevel@tonic-gate 					    "contention.\n"));
15967c478bd9Sstevel@tonic-gate 					goto out;
15977c478bd9Sstevel@tonic-gate 				}
15987c478bd9Sstevel@tonic-gate 				break;
15997c478bd9Sstevel@tonic-gate 
16007c478bd9Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
16017c478bd9Sstevel@tonic-gate 				if (!verbose)
16027c478bd9Sstevel@tonic-gate 					uu_warn(emsg_permission_denied, fmri);
16037c478bd9Sstevel@tonic-gate 				else
16047c478bd9Sstevel@tonic-gate 					uu_warn(emsg_create_pg_perm_denied,
16057c478bd9Sstevel@tonic-gate 					    fmri, pgname);
16067c478bd9Sstevel@tonic-gate 				goto out;
16077c478bd9Sstevel@tonic-gate 
16087c478bd9Sstevel@tonic-gate 			default:
16097c478bd9Sstevel@tonic-gate 				scfdie();
16107c478bd9Sstevel@tonic-gate 			}
16117c478bd9Sstevel@tonic-gate 		}
16127c478bd9Sstevel@tonic-gate 	}
16137c478bd9Sstevel@tonic-gate 
16147c478bd9Sstevel@tonic-gate 	do {
16157c478bd9Sstevel@tonic-gate 		if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
16167c478bd9Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
16177c478bd9Sstevel@tonic-gate 				scfdie();
16187c478bd9Sstevel@tonic-gate 
16197c478bd9Sstevel@tonic-gate 			if (!verbose)
16207c478bd9Sstevel@tonic-gate 				uu_warn(emsg_permission_denied, fmri);
16217c478bd9Sstevel@tonic-gate 			else
16227c478bd9Sstevel@tonic-gate 				uu_warn(emsg_pg_perm_denied, fmri, pgname);
16237c478bd9Sstevel@tonic-gate 			goto out;
16247c478bd9Sstevel@tonic-gate 		}
16257c478bd9Sstevel@tonic-gate 
16267c478bd9Sstevel@tonic-gate 		if (scf_transaction_property_change_type(tx, txent, propname,
16277c478bd9Sstevel@tonic-gate 		    SCF_TYPE_ASTRING) != 0) {
16287c478bd9Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_NOT_FOUND)
16297c478bd9Sstevel@tonic-gate 				scfdie();
16307c478bd9Sstevel@tonic-gate 
16317c478bd9Sstevel@tonic-gate 			if (scf_transaction_property_new(tx, txent, propname,
16327c478bd9Sstevel@tonic-gate 			    SCF_TYPE_ASTRING) != 0)
16337c478bd9Sstevel@tonic-gate 				scfdie();
16347c478bd9Sstevel@tonic-gate 		}
16357c478bd9Sstevel@tonic-gate 
16367c478bd9Sstevel@tonic-gate 		if (scf_value_set_astring(val, str) != SCF_SUCCESS)
16377c478bd9Sstevel@tonic-gate 			scfdie();
16387c478bd9Sstevel@tonic-gate 
16397c478bd9Sstevel@tonic-gate 		if (scf_entry_add_value(txent, val) != SCF_SUCCESS)
16407c478bd9Sstevel@tonic-gate 			scfdie();
16417c478bd9Sstevel@tonic-gate 
16427c478bd9Sstevel@tonic-gate 		ret = scf_transaction_commit(tx);
16437c478bd9Sstevel@tonic-gate 		if (ret == -1) {
16447c478bd9Sstevel@tonic-gate 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
16457c478bd9Sstevel@tonic-gate 				scfdie();
16467c478bd9Sstevel@tonic-gate 
16477c478bd9Sstevel@tonic-gate 			if (!verbose)
16487c478bd9Sstevel@tonic-gate 				uu_warn(emsg_permission_denied, fmri);
16497c478bd9Sstevel@tonic-gate 			else
16507c478bd9Sstevel@tonic-gate 				uu_warn(emsg_prop_perm_denied, fmri, pgname,
16517c478bd9Sstevel@tonic-gate 				    propname);
16527c478bd9Sstevel@tonic-gate 			goto out;
16537c478bd9Sstevel@tonic-gate 		}
16547c478bd9Sstevel@tonic-gate 
16557c478bd9Sstevel@tonic-gate 		if (ret == 0) {
16567c478bd9Sstevel@tonic-gate 			scf_transaction_reset(tx);
16577c478bd9Sstevel@tonic-gate 
1658bc9767f9Stn 			if (scf_pg_update(pg) == -1)
16597c478bd9Sstevel@tonic-gate 				scfdie();
16607c478bd9Sstevel@tonic-gate 		}
16617c478bd9Sstevel@tonic-gate 	} while (ret == 0);
16627c478bd9Sstevel@tonic-gate 
16637c478bd9Sstevel@tonic-gate out:
16647c478bd9Sstevel@tonic-gate 	scf_transaction_destroy(tx);
16657c478bd9Sstevel@tonic-gate 	scf_entry_destroy(txent);
16667c478bd9Sstevel@tonic-gate 	scf_value_destroy(val);
16677c478bd9Sstevel@tonic-gate 	scf_property_destroy(prop);
16687c478bd9Sstevel@tonic-gate 	scf_pg_destroy(pg);
16697c478bd9Sstevel@tonic-gate 	scf_instance_destroy(inst);
16707c478bd9Sstevel@tonic-gate }
16717c478bd9Sstevel@tonic-gate 
16727c478bd9Sstevel@tonic-gate 
16737c478bd9Sstevel@tonic-gate /*
16747c478bd9Sstevel@tonic-gate  * Flags to control enable and disable actions.
16757c478bd9Sstevel@tonic-gate  */
16767c478bd9Sstevel@tonic-gate #define	SET_ENABLED	0x1
16777c478bd9Sstevel@tonic-gate #define	SET_TEMPORARY	0x2
16787c478bd9Sstevel@tonic-gate #define	SET_RECURSIVE	0x4
16797c478bd9Sstevel@tonic-gate 
16807c478bd9Sstevel@tonic-gate static int
16817c478bd9Sstevel@tonic-gate set_fmri_enabled(void *data, scf_walkinfo_t *wip)
16827c478bd9Sstevel@tonic-gate {
16837c478bd9Sstevel@tonic-gate 	int flags = (int)data;
16847c478bd9Sstevel@tonic-gate 
16857c478bd9Sstevel@tonic-gate 	assert(wip->inst != NULL);
16867c478bd9Sstevel@tonic-gate 	assert(wip->pg == NULL);
16877c478bd9Sstevel@tonic-gate 
16887c478bd9Sstevel@tonic-gate 	if (flags & SET_RECURSIVE) {
16897c478bd9Sstevel@tonic-gate 		char *fmri_buf = malloc(max_scf_fmri_sz);
16907c478bd9Sstevel@tonic-gate 		if (fmri_buf == NULL)
16917c478bd9Sstevel@tonic-gate 			uu_die(emsg_nomem);
16927c478bd9Sstevel@tonic-gate 
16937c478bd9Sstevel@tonic-gate 		visited = calloc(HT_BUCKETS, sizeof (*visited));
16947c478bd9Sstevel@tonic-gate 		if (visited == NULL)
16957c478bd9Sstevel@tonic-gate 			uu_die(emsg_nomem);
16967c478bd9Sstevel@tonic-gate 
16977c478bd9Sstevel@tonic-gate 		/* scf_walk_fmri() guarantees that fmri isn't too long */
16987c478bd9Sstevel@tonic-gate 		assert(strlen(wip->fmri) <= max_scf_fmri_sz);
16997c478bd9Sstevel@tonic-gate 		(void) strlcpy(fmri_buf, wip->fmri, max_scf_fmri_sz);
17007c478bd9Sstevel@tonic-gate 
17017c478bd9Sstevel@tonic-gate 		switch (enable_fmri_rec(fmri_buf, (flags & SET_TEMPORARY))) {
17027c478bd9Sstevel@tonic-gate 		case E2BIG:
17037c478bd9Sstevel@tonic-gate 			uu_warn(gettext("operation on service %s is ambiguous; "
17047c478bd9Sstevel@tonic-gate 			    "instance specification needed.\n"), fmri_buf);
17057c478bd9Sstevel@tonic-gate 			break;
17067c478bd9Sstevel@tonic-gate 
17077c478bd9Sstevel@tonic-gate 		case ELOOP:
17087c478bd9Sstevel@tonic-gate 			uu_warn(gettext("%s: Dependency cycle detected.\n"),
17097c478bd9Sstevel@tonic-gate 			    fmri_buf);
17107c478bd9Sstevel@tonic-gate 		}
17117c478bd9Sstevel@tonic-gate 
17127c478bd9Sstevel@tonic-gate 		free(visited);
17137c478bd9Sstevel@tonic-gate 		free(fmri_buf);
17147c478bd9Sstevel@tonic-gate 
17157c478bd9Sstevel@tonic-gate 	} else {
17167c478bd9Sstevel@tonic-gate 		set_inst_enabled(wip->fmri, wip->inst,
17177c478bd9Sstevel@tonic-gate 		    (flags & SET_TEMPORARY) != 0, (flags & SET_ENABLED) != 0);
17187c478bd9Sstevel@tonic-gate 	}
17197c478bd9Sstevel@tonic-gate 
17207c478bd9Sstevel@tonic-gate 	return (0);
17217c478bd9Sstevel@tonic-gate }
17227c478bd9Sstevel@tonic-gate 
17237c478bd9Sstevel@tonic-gate /* ARGSUSED */
17247c478bd9Sstevel@tonic-gate static int
17257c478bd9Sstevel@tonic-gate wait_fmri_enabled(void *data, scf_walkinfo_t *wip)
17267c478bd9Sstevel@tonic-gate {
17277c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg = NULL;
17287c478bd9Sstevel@tonic-gate 	char state[MAX_SCF_STATE_STRING_SZ];
17297c478bd9Sstevel@tonic-gate 
17307c478bd9Sstevel@tonic-gate 	assert(wip->inst != NULL);
17317c478bd9Sstevel@tonic-gate 	assert(wip->pg == NULL);
17327c478bd9Sstevel@tonic-gate 
17337c478bd9Sstevel@tonic-gate 	do {
17347c478bd9Sstevel@tonic-gate 		if (pg)
17357c478bd9Sstevel@tonic-gate 			scf_pg_destroy(pg);
17367c478bd9Sstevel@tonic-gate 		if (inst_get_state(wip->inst, state, wip->fmri, &pg) != 0) {
17377c478bd9Sstevel@tonic-gate 			exit_status = EXIT_SVC_FAILURE;
17387c478bd9Sstevel@tonic-gate 			return (0);
17397c478bd9Sstevel@tonic-gate 		}
17407c478bd9Sstevel@tonic-gate 
17417c478bd9Sstevel@tonic-gate 		if (strcmp(state, SCF_STATE_STRING_ONLINE) == 0 ||
17427c478bd9Sstevel@tonic-gate 		    strcmp(state, SCF_STATE_STRING_DEGRADED) == 0) {
17437c478bd9Sstevel@tonic-gate 			/*
17447c478bd9Sstevel@tonic-gate 			 * We're done.
17457c478bd9Sstevel@tonic-gate 			 */
17467c478bd9Sstevel@tonic-gate 			goto out;
17477c478bd9Sstevel@tonic-gate 		}
17487c478bd9Sstevel@tonic-gate 
17497c478bd9Sstevel@tonic-gate 		if (strcmp(state, SCF_STATE_STRING_MAINT) == 0) {
17507c478bd9Sstevel@tonic-gate 			/*
17517c478bd9Sstevel@tonic-gate 			 * The service is ill.
17527c478bd9Sstevel@tonic-gate 			 */
17537c478bd9Sstevel@tonic-gate 			uu_warn(gettext("Instance \"%s\" is in maintenance"
17547c478bd9Sstevel@tonic-gate 			    " state.\n"), wip->fmri);
17557c478bd9Sstevel@tonic-gate 			exit_status = EXIT_SVC_FAILURE;
17567c478bd9Sstevel@tonic-gate 			goto out;
17577c478bd9Sstevel@tonic-gate 		}
17587c478bd9Sstevel@tonic-gate 
17597c478bd9Sstevel@tonic-gate 		if (!is_enabled(wip->inst)) {
17607c478bd9Sstevel@tonic-gate 			/*
17617c478bd9Sstevel@tonic-gate 			 * Someone stepped in and disabled the service.
17627c478bd9Sstevel@tonic-gate 			 */
17637c478bd9Sstevel@tonic-gate 			uu_warn(gettext("Instance \"%s\" has been disabled"
17647c478bd9Sstevel@tonic-gate 			    " by another entity.\n"), wip->fmri);
17657c478bd9Sstevel@tonic-gate 			exit_status = EXIT_SVC_FAILURE;
17667c478bd9Sstevel@tonic-gate 			goto out;
17677c478bd9Sstevel@tonic-gate 		}
17687c478bd9Sstevel@tonic-gate 
17697c478bd9Sstevel@tonic-gate 		if (!has_potential(wip->inst, B_FALSE)) {
17707c478bd9Sstevel@tonic-gate 			/*
17717c478bd9Sstevel@tonic-gate 			 * Our dependencies aren't met.  We'll never
17727c478bd9Sstevel@tonic-gate 			 * amount to anything.
17737c478bd9Sstevel@tonic-gate 			 */
17747c478bd9Sstevel@tonic-gate 			uu_warn(gettext("Instance \"%s\" has unsatisfied"
17757c478bd9Sstevel@tonic-gate 			    " dependencies.\n"), wip->fmri);
17767c478bd9Sstevel@tonic-gate 			/*
17777c478bd9Sstevel@tonic-gate 			 * EXIT_SVC_FAILURE takes precedence over
17787c478bd9Sstevel@tonic-gate 			 * EXIT_DEP_FAILURE
17797c478bd9Sstevel@tonic-gate 			 */
17807c478bd9Sstevel@tonic-gate 			if (exit_status == 0)
17817c478bd9Sstevel@tonic-gate 				exit_status = EXIT_DEP_FAILURE;
17827c478bd9Sstevel@tonic-gate 			goto out;
17837c478bd9Sstevel@tonic-gate 		}
17847c478bd9Sstevel@tonic-gate 	} while (_scf_pg_wait(pg, WAIT_INTERVAL) >= 0);
17857c478bd9Sstevel@tonic-gate 	scfdie();
17867c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
17877c478bd9Sstevel@tonic-gate 
17887c478bd9Sstevel@tonic-gate out:
17897c478bd9Sstevel@tonic-gate 	scf_pg_destroy(pg);
17907c478bd9Sstevel@tonic-gate 	return (0);
17917c478bd9Sstevel@tonic-gate }
17927c478bd9Sstevel@tonic-gate 
17937c478bd9Sstevel@tonic-gate /* ARGSUSED */
17947c478bd9Sstevel@tonic-gate static int
17957c478bd9Sstevel@tonic-gate wait_fmri_disabled(void *data, scf_walkinfo_t *wip)
17967c478bd9Sstevel@tonic-gate {
17977c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg = NULL;
17987c478bd9Sstevel@tonic-gate 	char state[MAX_SCF_STATE_STRING_SZ];
17997c478bd9Sstevel@tonic-gate 
18007c478bd9Sstevel@tonic-gate 	assert(wip->inst != NULL);
18017c478bd9Sstevel@tonic-gate 	assert(wip->pg == NULL);
18027c478bd9Sstevel@tonic-gate 
18037c478bd9Sstevel@tonic-gate 	do {
18047c478bd9Sstevel@tonic-gate 		if (pg)
18057c478bd9Sstevel@tonic-gate 			scf_pg_destroy(pg);
18067c478bd9Sstevel@tonic-gate 		if (inst_get_state(wip->inst, state, wip->fmri, &pg) != 0) {
18077c478bd9Sstevel@tonic-gate 			exit_status = EXIT_SVC_FAILURE;
18087c478bd9Sstevel@tonic-gate 			return (0);
18097c478bd9Sstevel@tonic-gate 		}
18107c478bd9Sstevel@tonic-gate 
18117c478bd9Sstevel@tonic-gate 		if (strcmp(state, SCF_STATE_STRING_DISABLED) == 0) {
18127c478bd9Sstevel@tonic-gate 			/*
18137c478bd9Sstevel@tonic-gate 			 * We're done.
18147c478bd9Sstevel@tonic-gate 			 */
18157c478bd9Sstevel@tonic-gate 			goto out;
18167c478bd9Sstevel@tonic-gate 		}
18177c478bd9Sstevel@tonic-gate 
18187c478bd9Sstevel@tonic-gate 		if (is_enabled(wip->inst)) {
18197c478bd9Sstevel@tonic-gate 			/*
18207c478bd9Sstevel@tonic-gate 			 * Someone stepped in and enabled the service.
18217c478bd9Sstevel@tonic-gate 			 */
18227c478bd9Sstevel@tonic-gate 			uu_warn(gettext("Instance \"%s\" has been enabled"
18237c478bd9Sstevel@tonic-gate 			    " by another entity.\n"), wip->fmri);
18247c478bd9Sstevel@tonic-gate 			exit_status = EXIT_SVC_FAILURE;
18257c478bd9Sstevel@tonic-gate 			goto out;
18267c478bd9Sstevel@tonic-gate 		}
18277c478bd9Sstevel@tonic-gate 
18287c478bd9Sstevel@tonic-gate 		if (!has_potential(wip->inst, B_TRUE)) {
18297c478bd9Sstevel@tonic-gate 			/*
18307c478bd9Sstevel@tonic-gate 			 * Our restarter is hopeless.
18317c478bd9Sstevel@tonic-gate 			 */
18327c478bd9Sstevel@tonic-gate 			uu_warn(gettext("Restarter for instance \"%s\" is"
18337c478bd9Sstevel@tonic-gate 			    " unavailable.\n"), wip->fmri);
18347c478bd9Sstevel@tonic-gate 			/*
18357c478bd9Sstevel@tonic-gate 			 * EXIT_SVC_FAILURE takes precedence over
18367c478bd9Sstevel@tonic-gate 			 * EXIT_DEP_FAILURE
18377c478bd9Sstevel@tonic-gate 			 */
18387c478bd9Sstevel@tonic-gate 			if (exit_status == 0)
18397c478bd9Sstevel@tonic-gate 				exit_status = EXIT_DEP_FAILURE;
18407c478bd9Sstevel@tonic-gate 			goto out;
18417c478bd9Sstevel@tonic-gate 		}
18427c478bd9Sstevel@tonic-gate 
18437c478bd9Sstevel@tonic-gate 	} while (_scf_pg_wait(pg, WAIT_INTERVAL) >= 0);
18447c478bd9Sstevel@tonic-gate 	scfdie();
18457c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
18467c478bd9Sstevel@tonic-gate 
18477c478bd9Sstevel@tonic-gate out:
18487c478bd9Sstevel@tonic-gate 	scf_pg_destroy(pg);
18497c478bd9Sstevel@tonic-gate 	return (0);
18507c478bd9Sstevel@tonic-gate }
18517c478bd9Sstevel@tonic-gate 
18527c478bd9Sstevel@tonic-gate /* ARGSUSED */
18537c478bd9Sstevel@tonic-gate static int
18547c478bd9Sstevel@tonic-gate clear_instance(void *data, scf_walkinfo_t *wip)
18557c478bd9Sstevel@tonic-gate {
18567c478bd9Sstevel@tonic-gate 	char state[MAX_SCF_STATE_STRING_SZ];
18577c478bd9Sstevel@tonic-gate 
18587c478bd9Sstevel@tonic-gate 	assert(wip->inst != NULL);
18597c478bd9Sstevel@tonic-gate 	assert(wip->pg == NULL);
18607c478bd9Sstevel@tonic-gate 
18617c478bd9Sstevel@tonic-gate 	if (inst_get_state(wip->inst, state, wip->fmri, NULL) != 0)
18627c478bd9Sstevel@tonic-gate 		return (0);
18637c478bd9Sstevel@tonic-gate 
18647c478bd9Sstevel@tonic-gate 	if (strcmp(state, SCF_STATE_STRING_MAINT) == 0) {
18657c478bd9Sstevel@tonic-gate 		set_inst_action(wip->fmri, wip->inst, SCF_PROPERTY_MAINT_OFF);
18667c478bd9Sstevel@tonic-gate 	} else if (strcmp(state, SCF_STATE_STRING_DEGRADED) ==
18677c478bd9Sstevel@tonic-gate 	    0) {
18687c478bd9Sstevel@tonic-gate 		set_inst_action(wip->fmri, wip->inst, SCF_PROPERTY_RESTORE);
18697c478bd9Sstevel@tonic-gate 	} else {
18707c478bd9Sstevel@tonic-gate 		uu_warn(gettext("Instance \"%s\" is not in a "
18717c478bd9Sstevel@tonic-gate 		    "maintenance or degraded state.\n"), wip->fmri);
18727c478bd9Sstevel@tonic-gate 
18737c478bd9Sstevel@tonic-gate 		exit_status = 1;
18747c478bd9Sstevel@tonic-gate 	}
18757c478bd9Sstevel@tonic-gate 
18767c478bd9Sstevel@tonic-gate 	return (0);
18777c478bd9Sstevel@tonic-gate }
18787c478bd9Sstevel@tonic-gate 
18797c478bd9Sstevel@tonic-gate static int
18807c478bd9Sstevel@tonic-gate set_fmri_action(void *action, scf_walkinfo_t *wip)
18817c478bd9Sstevel@tonic-gate {
18827c478bd9Sstevel@tonic-gate 	assert(wip->inst != NULL && wip->pg == NULL);
18837c478bd9Sstevel@tonic-gate 
18847c478bd9Sstevel@tonic-gate 	set_inst_action(wip->fmri, wip->inst, action);
18857c478bd9Sstevel@tonic-gate 
18867c478bd9Sstevel@tonic-gate 	return (0);
18877c478bd9Sstevel@tonic-gate }
18887c478bd9Sstevel@tonic-gate 
18897c478bd9Sstevel@tonic-gate /*
18907c478bd9Sstevel@tonic-gate  * Flags to control 'mark' action.
18917c478bd9Sstevel@tonic-gate  */
18927c478bd9Sstevel@tonic-gate #define	MARK_IMMEDIATE	0x1
18937c478bd9Sstevel@tonic-gate #define	MARK_TEMPORARY	0x2
18947c478bd9Sstevel@tonic-gate 
18957c478bd9Sstevel@tonic-gate static int
18967c478bd9Sstevel@tonic-gate force_degraded(void *data, scf_walkinfo_t *wip)
18977c478bd9Sstevel@tonic-gate {
18987c478bd9Sstevel@tonic-gate 	int flags = (int)data;
18997c478bd9Sstevel@tonic-gate 	char state[MAX_SCF_STATE_STRING_SZ];
19007c478bd9Sstevel@tonic-gate 
19017c478bd9Sstevel@tonic-gate 	if (inst_get_state(wip->inst, state, wip->fmri, NULL) != 0) {
19027c478bd9Sstevel@tonic-gate 		exit_status = 1;
19037c478bd9Sstevel@tonic-gate 		return (0);
19047c478bd9Sstevel@tonic-gate 	}
19057c478bd9Sstevel@tonic-gate 
19067c478bd9Sstevel@tonic-gate 	if (strcmp(state, SCF_STATE_STRING_ONLINE) != 0) {
19077c478bd9Sstevel@tonic-gate 		uu_warn(gettext("Instance \"%s\" is not online.\n"), wip->fmri);
19087c478bd9Sstevel@tonic-gate 		exit_status = 1;
19097c478bd9Sstevel@tonic-gate 		return (0);
19107c478bd9Sstevel@tonic-gate 	}
19117c478bd9Sstevel@tonic-gate 
19127c478bd9Sstevel@tonic-gate 	set_inst_action(wip->fmri, wip->inst, (flags & MARK_IMMEDIATE) ?
19137c478bd9Sstevel@tonic-gate 	    SCF_PROPERTY_DEGRADE_IMMEDIATE : SCF_PROPERTY_DEGRADED);
19147c478bd9Sstevel@tonic-gate 
19157c478bd9Sstevel@tonic-gate 	return (0);
19167c478bd9Sstevel@tonic-gate }
19177c478bd9Sstevel@tonic-gate 
19187c478bd9Sstevel@tonic-gate static int
19197c478bd9Sstevel@tonic-gate force_maintenance(void *data, scf_walkinfo_t *wip)
19207c478bd9Sstevel@tonic-gate {
19217c478bd9Sstevel@tonic-gate 	int flags = (int)data;
19227c478bd9Sstevel@tonic-gate 	const char *prop;
19237c478bd9Sstevel@tonic-gate 
19247c478bd9Sstevel@tonic-gate 	if (flags & MARK_IMMEDIATE) {
19257c478bd9Sstevel@tonic-gate 		prop = (flags & MARK_TEMPORARY) ?
19267c478bd9Sstevel@tonic-gate 		    SCF_PROPERTY_MAINT_ON_IMMTEMP :
19277c478bd9Sstevel@tonic-gate 		    SCF_PROPERTY_MAINT_ON_IMMEDIATE;
19287c478bd9Sstevel@tonic-gate 	} else {
19297c478bd9Sstevel@tonic-gate 		prop = (flags & MARK_TEMPORARY) ?
19307c478bd9Sstevel@tonic-gate 		    SCF_PROPERTY_MAINT_ON_TEMPORARY :
19317c478bd9Sstevel@tonic-gate 		    SCF_PROPERTY_MAINT_ON;
19327c478bd9Sstevel@tonic-gate 	}
19337c478bd9Sstevel@tonic-gate 
19347c478bd9Sstevel@tonic-gate 	set_inst_action(wip->fmri, wip->inst, prop);
19357c478bd9Sstevel@tonic-gate 
19367c478bd9Sstevel@tonic-gate 	return (0);
19377c478bd9Sstevel@tonic-gate }
19387c478bd9Sstevel@tonic-gate 
19397c478bd9Sstevel@tonic-gate static void
19407c478bd9Sstevel@tonic-gate set_milestone(const char *fmri, boolean_t temporary)
19417c478bd9Sstevel@tonic-gate {
19427c478bd9Sstevel@tonic-gate 	scf_instance_t *inst;
19437c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg;
19447c478bd9Sstevel@tonic-gate 	int r;
19457c478bd9Sstevel@tonic-gate 
19467c478bd9Sstevel@tonic-gate 	if (temporary) {
19477c478bd9Sstevel@tonic-gate 		set_astring_prop(SCF_SERVICE_STARTD, SCF_PG_OPTIONS_OVR,
19487c478bd9Sstevel@tonic-gate 		    SCF_PG_OPTIONS_OVR_TYPE, SCF_PG_OPTIONS_OVR_FLAGS,
19497c478bd9Sstevel@tonic-gate 		    SCF_PROPERTY_MILESTONE, fmri);
19507c478bd9Sstevel@tonic-gate 		return;
19517c478bd9Sstevel@tonic-gate 	}
19527c478bd9Sstevel@tonic-gate 
19537c478bd9Sstevel@tonic-gate 	if ((inst = scf_instance_create(h)) == NULL ||
19547c478bd9Sstevel@tonic-gate 	    (pg = scf_pg_create(h)) == NULL)
19557c478bd9Sstevel@tonic-gate 		scfdie();
19567c478bd9Sstevel@tonic-gate 
19577c478bd9Sstevel@tonic-gate 	if (get_inst(SCF_SERVICE_STARTD, inst) != 0) {
19587c478bd9Sstevel@tonic-gate 		scf_instance_destroy(inst);
19597c478bd9Sstevel@tonic-gate 		return;
19607c478bd9Sstevel@tonic-gate 	}
19617c478bd9Sstevel@tonic-gate 
19627c478bd9Sstevel@tonic-gate 	/*
19637c478bd9Sstevel@tonic-gate 	 * Set the persistent milestone before deleting the override so we don't
19647c478bd9Sstevel@tonic-gate 	 * glitch.
19657c478bd9Sstevel@tonic-gate 	 */
19667c478bd9Sstevel@tonic-gate 	set_astring_prop(SCF_SERVICE_STARTD, SCF_PG_OPTIONS,
19677c478bd9Sstevel@tonic-gate 	    SCF_PG_OPTIONS_TYPE, SCF_PG_OPTIONS_FLAGS, SCF_PROPERTY_MILESTONE,
19687c478bd9Sstevel@tonic-gate 	    fmri);
19697c478bd9Sstevel@tonic-gate 
1970eb1a3463STruong Nguyen 	r = scf_instance_delete_prop(inst, SCF_PG_OPTIONS_OVR,
1971eb1a3463STruong Nguyen 	    SCF_PROPERTY_MILESTONE);
1972eb1a3463STruong Nguyen 	switch (r) {
1973eb1a3463STruong Nguyen 	case 0:
1974eb1a3463STruong Nguyen 		break;
19757c478bd9Sstevel@tonic-gate 
1976eb1a3463STruong Nguyen 	case ECANCELED:
1977eb1a3463STruong Nguyen 		uu_warn(emsg_no_service, fmri);
1978eb1a3463STruong Nguyen 		exit_status = 1;
1979eb1a3463STruong Nguyen 		goto out;
19807c478bd9Sstevel@tonic-gate 
1981eb1a3463STruong Nguyen 	case EPERM:
1982eb1a3463STruong Nguyen 		uu_warn(gettext("Could not delete %s/%s property of "
1983eb1a3463STruong Nguyen 		    "%s: permission denied.\n"), SCF_PG_OPTIONS_OVR,
1984eb1a3463STruong Nguyen 		    SCF_PROPERTY_MILESTONE, SCF_SERVICE_STARTD);
1985eb1a3463STruong Nguyen 		exit_status = 1;
1986eb1a3463STruong Nguyen 		goto out;
19877c478bd9Sstevel@tonic-gate 
1988eb1a3463STruong Nguyen 	case EACCES:
1989eb1a3463STruong Nguyen 		uu_warn(gettext("Could not delete %s/%s property of "
1990eb1a3463STruong Nguyen 		    "%s: access denied.\n"), SCF_PG_OPTIONS_OVR,
1991eb1a3463STruong Nguyen 		    SCF_PROPERTY_MILESTONE, SCF_SERVICE_STARTD);
1992eb1a3463STruong Nguyen 		exit_status = 1;
1993eb1a3463STruong Nguyen 		goto out;
19947c478bd9Sstevel@tonic-gate 
1995eb1a3463STruong Nguyen 	case EROFS:
1996eb1a3463STruong Nguyen 		uu_warn(gettext("Could not delete %s/%s property of "
1997eb1a3463STruong Nguyen 		    "%s: backend read-only.\n"), SCF_PG_OPTIONS_OVR,
1998eb1a3463STruong Nguyen 		    SCF_PROPERTY_MILESTONE, SCF_SERVICE_STARTD);
1999eb1a3463STruong Nguyen 		exit_status = 1;
2000eb1a3463STruong Nguyen 		goto out;
20017c478bd9Sstevel@tonic-gate 
2002eb1a3463STruong Nguyen 	default:
2003eb1a3463STruong Nguyen 		bad_error("scf_instance_delete_prop", r);
20047c478bd9Sstevel@tonic-gate 	}
20057c478bd9Sstevel@tonic-gate 
20067c478bd9Sstevel@tonic-gate out:
20077c478bd9Sstevel@tonic-gate 	scf_pg_destroy(pg);
20087c478bd9Sstevel@tonic-gate 	scf_instance_destroy(inst);
20097c478bd9Sstevel@tonic-gate }
20107c478bd9Sstevel@tonic-gate 
20117c478bd9Sstevel@tonic-gate static char const *milestones[] = {
20127c478bd9Sstevel@tonic-gate 	SCF_MILESTONE_SINGLE_USER,
20137c478bd9Sstevel@tonic-gate 	SCF_MILESTONE_MULTI_USER,
20147c478bd9Sstevel@tonic-gate 	SCF_MILESTONE_MULTI_USER_SERVER,
20157c478bd9Sstevel@tonic-gate 	NULL
20167c478bd9Sstevel@tonic-gate };
20177c478bd9Sstevel@tonic-gate 
20187c478bd9Sstevel@tonic-gate static void
20190b5c9250Shg usage_milestone(void)
20207c478bd9Sstevel@tonic-gate {
20217c478bd9Sstevel@tonic-gate 	const char **ms;
20227c478bd9Sstevel@tonic-gate 
20237c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(
20247c478bd9Sstevel@tonic-gate 	"Usage: svcadm milestone [-d] <milestone>\n\n"
20257c478bd9Sstevel@tonic-gate 	"\t-d\tmake the specified milestone the default for system boot\n\n"
20267c478bd9Sstevel@tonic-gate 	"\tMilestones can be specified using an FMRI or abbreviation.\n"
20277c478bd9Sstevel@tonic-gate 	"\tThe major milestones are as follows:\n\n"
20287c478bd9Sstevel@tonic-gate 	"\tall\n"
20297c478bd9Sstevel@tonic-gate 	"\tnone\n"));
20307c478bd9Sstevel@tonic-gate 
20317c478bd9Sstevel@tonic-gate 	for (ms = milestones; *ms != NULL; ms++)
20327c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "\t%s\n", *ms);
20337c478bd9Sstevel@tonic-gate 
20347c478bd9Sstevel@tonic-gate 	exit(UU_EXIT_USAGE);
20357c478bd9Sstevel@tonic-gate }
20367c478bd9Sstevel@tonic-gate 
20377c478bd9Sstevel@tonic-gate static const char *
20387c478bd9Sstevel@tonic-gate validate_milestone(const char *milestone)
20397c478bd9Sstevel@tonic-gate {
20407c478bd9Sstevel@tonic-gate 	const char **ms;
20417c478bd9Sstevel@tonic-gate 	const char *tmp;
20427c478bd9Sstevel@tonic-gate 	size_t len;
20437c478bd9Sstevel@tonic-gate 
20447c478bd9Sstevel@tonic-gate 	if (strcmp(milestone, "all") == 0)
20457c478bd9Sstevel@tonic-gate 		return (milestone);
20467c478bd9Sstevel@tonic-gate 
20477c478bd9Sstevel@tonic-gate 	if (strcmp(milestone, "none") == 0)
20487c478bd9Sstevel@tonic-gate 		return (milestone);
20497c478bd9Sstevel@tonic-gate 
20507c478bd9Sstevel@tonic-gate 	/*
20517c478bd9Sstevel@tonic-gate 	 * Determine if this is a full or partial milestone
20527c478bd9Sstevel@tonic-gate 	 */
20537c478bd9Sstevel@tonic-gate 	for (ms = milestones; *ms != NULL; ms++) {
20547c478bd9Sstevel@tonic-gate 		if ((tmp = strstr(*ms, milestone)) != NULL) {
20557c478bd9Sstevel@tonic-gate 			len = strlen(milestone);
20567c478bd9Sstevel@tonic-gate 
20577c478bd9Sstevel@tonic-gate 			/*
20587c478bd9Sstevel@tonic-gate 			 * The beginning of the string must align with the start
20597c478bd9Sstevel@tonic-gate 			 * of a milestone fmri, or on the boundary between
20607c478bd9Sstevel@tonic-gate 			 * elements.  The end of the string must align with the
20617c478bd9Sstevel@tonic-gate 			 * end of the milestone, or at the instance boundary.
20627c478bd9Sstevel@tonic-gate 			 */
20637c478bd9Sstevel@tonic-gate 			if ((tmp == *ms || tmp[-1] == '/') &&
20647c478bd9Sstevel@tonic-gate 			    (tmp[len] == '\0' || tmp[len] == ':'))
20657c478bd9Sstevel@tonic-gate 				return (*ms);
20667c478bd9Sstevel@tonic-gate 		}
20677c478bd9Sstevel@tonic-gate 	}
20687c478bd9Sstevel@tonic-gate 
20697c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
20707c478bd9Sstevel@tonic-gate 	    gettext("\"%s\" is not a valid major milestone.\n"), milestone);
20717c478bd9Sstevel@tonic-gate 
20727c478bd9Sstevel@tonic-gate 	usage_milestone();
20737c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
20747c478bd9Sstevel@tonic-gate }
20757c478bd9Sstevel@tonic-gate 
20767c478bd9Sstevel@tonic-gate /*ARGSUSED*/
20777c478bd9Sstevel@tonic-gate static void
20787c478bd9Sstevel@tonic-gate quiet(const char *fmt, ...)
20797c478bd9Sstevel@tonic-gate {
20807c478bd9Sstevel@tonic-gate 	/* Do nothing */
20817c478bd9Sstevel@tonic-gate }
20827c478bd9Sstevel@tonic-gate 
20837c478bd9Sstevel@tonic-gate int
20847c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
20857c478bd9Sstevel@tonic-gate {
20867c478bd9Sstevel@tonic-gate 	int o;
20877c478bd9Sstevel@tonic-gate 	int err;
2088c0889d7aSstevep 	int sw_back;
20897c478bd9Sstevel@tonic-gate 
20907c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
20917c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
20927c478bd9Sstevel@tonic-gate 
20937c478bd9Sstevel@tonic-gate 	(void) uu_setpname(argv[0]);
20947c478bd9Sstevel@tonic-gate 
20957c478bd9Sstevel@tonic-gate 	if (argc < 2)
20967c478bd9Sstevel@tonic-gate 		usage();
20977c478bd9Sstevel@tonic-gate 
20987c478bd9Sstevel@tonic-gate 	max_scf_fmri_sz = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH);
20997c478bd9Sstevel@tonic-gate 	if (max_scf_fmri_sz < 0)
21007c478bd9Sstevel@tonic-gate 		scfdie();
21017c478bd9Sstevel@tonic-gate 	++max_scf_fmri_sz;
21027c478bd9Sstevel@tonic-gate 
21037c478bd9Sstevel@tonic-gate 	scratch_fmri = malloc(max_scf_fmri_sz);
21047c478bd9Sstevel@tonic-gate 	if (scratch_fmri == NULL)
21057c478bd9Sstevel@tonic-gate 		uu_die(emsg_nomem);
21067c478bd9Sstevel@tonic-gate 
21077c478bd9Sstevel@tonic-gate 	h = scf_handle_create(SCF_VERSION);
21087c478bd9Sstevel@tonic-gate 	if (h == NULL)
21097c478bd9Sstevel@tonic-gate 		scfdie();
21107c478bd9Sstevel@tonic-gate 
2111647f8444SBryan Cantrill 	while ((o = getopt(argc, argv, "vz:")) != -1) {
2112647f8444SBryan Cantrill 		switch (o) {
2113647f8444SBryan Cantrill 		case 'v':
21147c478bd9Sstevel@tonic-gate 			verbose = 1;
2115647f8444SBryan Cantrill 			break;
2116647f8444SBryan Cantrill 
2117647f8444SBryan Cantrill 		case 'z': {
2118647f8444SBryan Cantrill 			scf_value_t *zone;
2119647f8444SBryan Cantrill 
2120647f8444SBryan Cantrill 			if (getzoneid() != GLOBAL_ZONEID)
2121647f8444SBryan Cantrill 				uu_die(gettext("svcadm -z may only be used "
2122647f8444SBryan Cantrill 				    "from the global zone\n"));
2123647f8444SBryan Cantrill 
2124647f8444SBryan Cantrill 			if ((zone = scf_value_create(h)) == NULL)
2125647f8444SBryan Cantrill 				scfdie();
2126647f8444SBryan Cantrill 
2127647f8444SBryan Cantrill 			if (scf_value_set_astring(zone, optarg) != SCF_SUCCESS)
2128647f8444SBryan Cantrill 				scfdie();
2129647f8444SBryan Cantrill 
2130647f8444SBryan Cantrill 			if (scf_handle_decorate(h, "zone", zone) != SCF_SUCCESS)
2131647f8444SBryan Cantrill 				uu_die(gettext("invalid zone '%s'\n"), optarg);
2132647f8444SBryan Cantrill 
2133647f8444SBryan Cantrill 			scf_value_destroy(zone);
2134647f8444SBryan Cantrill 			break;
2135647f8444SBryan Cantrill 		}
2136647f8444SBryan Cantrill 
2137647f8444SBryan Cantrill 		default:
21387c478bd9Sstevel@tonic-gate 			usage();
2139647f8444SBryan Cantrill 		}
21407c478bd9Sstevel@tonic-gate 	}
21417c478bd9Sstevel@tonic-gate 
2142647f8444SBryan Cantrill 	if (scf_handle_bind(h) == -1)
2143ade09663SRichard Lowe 		uu_die(gettext("Couldn't bind to configuration repository: "
2144ade09663SRichard Lowe 		    "%s.\n"), scf_strerror(scf_error()));
2145647f8444SBryan Cantrill 
21467c478bd9Sstevel@tonic-gate 	if (optind >= argc)
21477c478bd9Sstevel@tonic-gate 		usage();
21487c478bd9Sstevel@tonic-gate 
21497c478bd9Sstevel@tonic-gate 	emsg_permission_denied = gettext("%s: Permission denied.\n");
21507c478bd9Sstevel@tonic-gate 	emsg_nomem = gettext("Out of memory.\n");
21517c478bd9Sstevel@tonic-gate 	emsg_create_pg_perm_denied = gettext("%s: Couldn't create \"%s\" "
21527c478bd9Sstevel@tonic-gate 	    "property group (permission denied).\n");
21537c478bd9Sstevel@tonic-gate 	emsg_pg_perm_denied = gettext("%s: Couldn't modify \"%s\" property "
21547c478bd9Sstevel@tonic-gate 	    "group (permission denied).\n");
21557c478bd9Sstevel@tonic-gate 	emsg_prop_perm_denied = gettext("%s: Couldn't modify \"%s/%s\" "
21567c478bd9Sstevel@tonic-gate 	    "property (permission denied).\n");
21577c478bd9Sstevel@tonic-gate 	emsg_no_service = gettext("No such service \"%s\".\n");
21587c478bd9Sstevel@tonic-gate 
21597c478bd9Sstevel@tonic-gate 	if (strcmp(argv[optind], "enable") == 0) {
21607c478bd9Sstevel@tonic-gate 		int flags = SET_ENABLED;
21617c478bd9Sstevel@tonic-gate 		int wait = 0;
21627c478bd9Sstevel@tonic-gate 		int error = 0;
21637c478bd9Sstevel@tonic-gate 
21647c478bd9Sstevel@tonic-gate 		++optind;
21657c478bd9Sstevel@tonic-gate 
21667c478bd9Sstevel@tonic-gate 		while ((o = getopt(argc, argv, "rst")) != -1) {
21677c478bd9Sstevel@tonic-gate 			if (o == 'r')
21687c478bd9Sstevel@tonic-gate 				flags |= SET_RECURSIVE;
21697c478bd9Sstevel@tonic-gate 			else if (o == 't')
21707c478bd9Sstevel@tonic-gate 				flags |= SET_TEMPORARY;
21717c478bd9Sstevel@tonic-gate 			else if (o == 's')
21727c478bd9Sstevel@tonic-gate 				wait = 1;
21737c478bd9Sstevel@tonic-gate 			else if (o == '?')
21747c478bd9Sstevel@tonic-gate 				usage();
21757c478bd9Sstevel@tonic-gate 			else {
21767c478bd9Sstevel@tonic-gate 				assert(0);
21777c478bd9Sstevel@tonic-gate 				abort();
21787c478bd9Sstevel@tonic-gate 			}
21797c478bd9Sstevel@tonic-gate 		}
21807c478bd9Sstevel@tonic-gate 		argc -= optind;
21817c478bd9Sstevel@tonic-gate 		argv += optind;
21827c478bd9Sstevel@tonic-gate 
21837c478bd9Sstevel@tonic-gate 		if (argc <= 0)
21847c478bd9Sstevel@tonic-gate 			usage();
21857c478bd9Sstevel@tonic-gate 
21867c478bd9Sstevel@tonic-gate 		/*
21877c478bd9Sstevel@tonic-gate 		 * We want to continue with -s processing if we had
21887c478bd9Sstevel@tonic-gate 		 * invalid options, but not if an enable failed.  We
21897c478bd9Sstevel@tonic-gate 		 * squelch output the second time we walk fmris; we saw
21907c478bd9Sstevel@tonic-gate 		 * the errors the first time.
21917c478bd9Sstevel@tonic-gate 		 */
2192*6c7c876cSJerry Jelinek 		if ((err = scf_walk_fmri(h, argc, argv, WALK_FLAGS,
2193*6c7c876cSJerry Jelinek 		    set_fmri_enabled, (void *)flags, &error, uu_warn)) != 0) {
21947c478bd9Sstevel@tonic-gate 
21957c478bd9Sstevel@tonic-gate 			uu_warn(gettext("failed to iterate over "
21967c478bd9Sstevel@tonic-gate 			    "instances: %s\n"), scf_strerror(err));
21977c478bd9Sstevel@tonic-gate 			exit_status = UU_EXIT_FATAL;
21987c478bd9Sstevel@tonic-gate 
21997c478bd9Sstevel@tonic-gate 		} else if (wait && exit_status == 0 &&
2200*6c7c876cSJerry Jelinek 		    (err = scf_walk_fmri(h, argc, argv, WALK_FLAGS,
2201*6c7c876cSJerry Jelinek 		    wait_fmri_enabled, (void *)flags, &error, quiet)) != 0) {
22027c478bd9Sstevel@tonic-gate 
22037c478bd9Sstevel@tonic-gate 			uu_warn(gettext("failed to iterate over "
22047c478bd9Sstevel@tonic-gate 			    "instances: %s\n"), scf_strerror(err));
22057c478bd9Sstevel@tonic-gate 			exit_status = UU_EXIT_FATAL;
22067c478bd9Sstevel@tonic-gate 		}
22077c478bd9Sstevel@tonic-gate 
22087c478bd9Sstevel@tonic-gate 		if (error > 0)
22097c478bd9Sstevel@tonic-gate 			exit_status = error;
22107c478bd9Sstevel@tonic-gate 
22117c478bd9Sstevel@tonic-gate 	} else if (strcmp(argv[optind], "disable") == 0) {
22127c478bd9Sstevel@tonic-gate 		int flags = 0;
22137c478bd9Sstevel@tonic-gate 		int wait = 0;
22147c478bd9Sstevel@tonic-gate 		int error = 0;
22157c478bd9Sstevel@tonic-gate 
22167c478bd9Sstevel@tonic-gate 		++optind;
22177c478bd9Sstevel@tonic-gate 
22187c478bd9Sstevel@tonic-gate 		while ((o = getopt(argc, argv, "st")) != -1) {
22197c478bd9Sstevel@tonic-gate 			if (o == 't')
22207c478bd9Sstevel@tonic-gate 				flags |= SET_TEMPORARY;
22217c478bd9Sstevel@tonic-gate 			else if (o == 's')
22227c478bd9Sstevel@tonic-gate 				wait = 1;
22237c478bd9Sstevel@tonic-gate 			else if (o == '?')
22247c478bd9Sstevel@tonic-gate 				usage();
22257c478bd9Sstevel@tonic-gate 			else {
22267c478bd9Sstevel@tonic-gate 				assert(0);
22277c478bd9Sstevel@tonic-gate 				abort();
22287c478bd9Sstevel@tonic-gate 			}
22297c478bd9Sstevel@tonic-gate 		}
22307c478bd9Sstevel@tonic-gate 		argc -= optind;
22317c478bd9Sstevel@tonic-gate 		argv += optind;
22327c478bd9Sstevel@tonic-gate 
22337c478bd9Sstevel@tonic-gate 		if (argc <= 0)
22347c478bd9Sstevel@tonic-gate 			usage();
22357c478bd9Sstevel@tonic-gate 
22367c478bd9Sstevel@tonic-gate 		/*
22377c478bd9Sstevel@tonic-gate 		 * We want to continue with -s processing if we had
22387c478bd9Sstevel@tonic-gate 		 * invalid options, but not if a disable failed.  We
22397c478bd9Sstevel@tonic-gate 		 * squelch output the second time we walk fmris; we saw
22407c478bd9Sstevel@tonic-gate 		 * the errors the first time.
22417c478bd9Sstevel@tonic-gate 		 */
2242*6c7c876cSJerry Jelinek 		if ((err = scf_walk_fmri(h, argc, argv, WALK_FLAGS,
2243*6c7c876cSJerry Jelinek 		    set_fmri_enabled, (void *)flags, &exit_status,
2244*6c7c876cSJerry Jelinek 		    uu_warn)) != 0) {
22457c478bd9Sstevel@tonic-gate 
22467c478bd9Sstevel@tonic-gate 			uu_warn(gettext("failed to iterate over "
22477c478bd9Sstevel@tonic-gate 			    "instances: %s\n"), scf_strerror(err));
22487c478bd9Sstevel@tonic-gate 			exit_status = UU_EXIT_FATAL;
22497c478bd9Sstevel@tonic-gate 
22507c478bd9Sstevel@tonic-gate 		} else if (wait && exit_status == 0 &&
2251*6c7c876cSJerry Jelinek 		    (err = scf_walk_fmri(h, argc, argv, WALK_FLAGS,
2252*6c7c876cSJerry Jelinek 		    wait_fmri_disabled, (void *)flags, &error, quiet)) != 0) {
22537c478bd9Sstevel@tonic-gate 
22547c478bd9Sstevel@tonic-gate 			uu_warn(gettext("failed to iterate over "
22557c478bd9Sstevel@tonic-gate 			    "instances: %s\n"), scf_strerror(err));
22567c478bd9Sstevel@tonic-gate 			exit_status = UU_EXIT_FATAL;
22577c478bd9Sstevel@tonic-gate 		}
22587c478bd9Sstevel@tonic-gate 
22597c478bd9Sstevel@tonic-gate 		if (error > 0)
22607c478bd9Sstevel@tonic-gate 			exit_status = error;
22617c478bd9Sstevel@tonic-gate 
22627c478bd9Sstevel@tonic-gate 	} else if (strcmp(argv[optind], "restart") == 0) {
22637c478bd9Sstevel@tonic-gate 		++optind;
22647c478bd9Sstevel@tonic-gate 
22657c478bd9Sstevel@tonic-gate 		if (optind >= argc)
22667c478bd9Sstevel@tonic-gate 			usage();
22677c478bd9Sstevel@tonic-gate 
2268*6c7c876cSJerry Jelinek 		if ((err = scf_walk_fmri(h, argc - optind, argv + optind,
2269*6c7c876cSJerry Jelinek 		    WALK_FLAGS, set_fmri_action,
2270*6c7c876cSJerry Jelinek 		    (void *)SCF_PROPERTY_RESTART, &exit_status,
2271*6c7c876cSJerry Jelinek 		    uu_warn)) != 0) {
22727c478bd9Sstevel@tonic-gate 			uu_warn(gettext("failed to iterate over "
22737c478bd9Sstevel@tonic-gate 			    "instances: %s\n"), scf_strerror(err));
22747c478bd9Sstevel@tonic-gate 			exit_status = UU_EXIT_FATAL;
22757c478bd9Sstevel@tonic-gate 		}
22767c478bd9Sstevel@tonic-gate 
22777c478bd9Sstevel@tonic-gate 	} else if (strcmp(argv[optind], "refresh") == 0) {
22787c478bd9Sstevel@tonic-gate 		++optind;
22797c478bd9Sstevel@tonic-gate 
22807c478bd9Sstevel@tonic-gate 		if (optind >= argc)
22817c478bd9Sstevel@tonic-gate 			usage();
22827c478bd9Sstevel@tonic-gate 
2283*6c7c876cSJerry Jelinek 		if ((err = scf_walk_fmri(h, argc - optind, argv + optind,
2284*6c7c876cSJerry Jelinek 		    WALK_FLAGS, set_fmri_action,
2285*6c7c876cSJerry Jelinek 		    (void *)SCF_PROPERTY_REFRESH, &exit_status,
2286*6c7c876cSJerry Jelinek 		    uu_warn)) != 0) {
22877c478bd9Sstevel@tonic-gate 			uu_warn(gettext("failed to iterate over "
22887c478bd9Sstevel@tonic-gate 			    "instances: %s\n"), scf_strerror(scf_error()));
22897c478bd9Sstevel@tonic-gate 			exit_status = UU_EXIT_FATAL;
22907c478bd9Sstevel@tonic-gate 		}
22917c478bd9Sstevel@tonic-gate 
22927c478bd9Sstevel@tonic-gate 	} else if (strcmp(argv[optind], "mark") == 0) {
22937c478bd9Sstevel@tonic-gate 		int flags = 0;
22947c478bd9Sstevel@tonic-gate 		scf_walk_callback callback;
22957c478bd9Sstevel@tonic-gate 
22967c478bd9Sstevel@tonic-gate 		++optind;
22977c478bd9Sstevel@tonic-gate 
22987c478bd9Sstevel@tonic-gate 		while ((o = getopt(argc, argv, "It")) != -1) {
22997c478bd9Sstevel@tonic-gate 			if (o == 'I')
23007c478bd9Sstevel@tonic-gate 				flags |= MARK_IMMEDIATE;
23017c478bd9Sstevel@tonic-gate 			else if (o == 't')
23027c478bd9Sstevel@tonic-gate 				flags |= MARK_TEMPORARY;
23037c478bd9Sstevel@tonic-gate 			else if (o == '?')
23047c478bd9Sstevel@tonic-gate 				usage();
23057c478bd9Sstevel@tonic-gate 			else {
23067c478bd9Sstevel@tonic-gate 				assert(0);
23077c478bd9Sstevel@tonic-gate 				abort();
23087c478bd9Sstevel@tonic-gate 			}
23097c478bd9Sstevel@tonic-gate 		}
23107c478bd9Sstevel@tonic-gate 
23117c478bd9Sstevel@tonic-gate 		if (argc - optind < 2)
23127c478bd9Sstevel@tonic-gate 			usage();
23137c478bd9Sstevel@tonic-gate 
23147c478bd9Sstevel@tonic-gate 		if (strcmp(argv[optind], "degraded") == 0) {
23157c478bd9Sstevel@tonic-gate 			if (flags & MARK_TEMPORARY)
23167c478bd9Sstevel@tonic-gate 				uu_xdie(UU_EXIT_USAGE, gettext("-t may not be "
23177c478bd9Sstevel@tonic-gate 				    "used with degraded.\n"));
23187c478bd9Sstevel@tonic-gate 			callback = force_degraded;
23197c478bd9Sstevel@tonic-gate 
23207c478bd9Sstevel@tonic-gate 		} else if (strcmp(argv[optind], "maintenance") == 0) {
23217c478bd9Sstevel@tonic-gate 			callback = force_maintenance;
23227c478bd9Sstevel@tonic-gate 		} else {
23237c478bd9Sstevel@tonic-gate 			usage();
23247c478bd9Sstevel@tonic-gate 		}
23257c478bd9Sstevel@tonic-gate 
23267c478bd9Sstevel@tonic-gate 		if ((err = scf_walk_fmri(h, argc - optind - 1,
2327*6c7c876cSJerry Jelinek 		    argv + optind + 1, WALK_FLAGS, callback, NULL,
2328*6c7c876cSJerry Jelinek 		    &exit_status, uu_warn)) != 0) {
23297c478bd9Sstevel@tonic-gate 			uu_warn(gettext("failed to iterate over "
23307c478bd9Sstevel@tonic-gate 			    "instances: %s\n"),
23317c478bd9Sstevel@tonic-gate 			    scf_strerror(err));
23327c478bd9Sstevel@tonic-gate 			exit_status = UU_EXIT_FATAL;
23337c478bd9Sstevel@tonic-gate 		}
23347c478bd9Sstevel@tonic-gate 
23357c478bd9Sstevel@tonic-gate 	} else if (strcmp(argv[optind], "clear") == 0) {
23367c478bd9Sstevel@tonic-gate 		++optind;
23377c478bd9Sstevel@tonic-gate 
23387c478bd9Sstevel@tonic-gate 		if (optind >= argc)
23397c478bd9Sstevel@tonic-gate 			usage();
23407c478bd9Sstevel@tonic-gate 
2341*6c7c876cSJerry Jelinek 		if ((err = scf_walk_fmri(h, argc - optind, argv + optind,
2342*6c7c876cSJerry Jelinek 		    WALK_FLAGS, clear_instance, NULL, &exit_status,
2343*6c7c876cSJerry Jelinek 		    uu_warn)) != 0) {
23447c478bd9Sstevel@tonic-gate 			uu_warn(gettext("failed to iterate over "
23457c478bd9Sstevel@tonic-gate 			    "instances: %s\n"), scf_strerror(err));
23467c478bd9Sstevel@tonic-gate 			exit_status = UU_EXIT_FATAL;
23477c478bd9Sstevel@tonic-gate 		}
23487c478bd9Sstevel@tonic-gate 
23497c478bd9Sstevel@tonic-gate 	} else if (strcmp(argv[optind], "milestone") == 0) {
23507c478bd9Sstevel@tonic-gate 		boolean_t temporary = B_TRUE;
23517c478bd9Sstevel@tonic-gate 		const char *milestone;
23527c478bd9Sstevel@tonic-gate 
23537c478bd9Sstevel@tonic-gate 		++optind;
23547c478bd9Sstevel@tonic-gate 
23557c478bd9Sstevel@tonic-gate 		while ((o = getopt(argc, argv, "d")) != -1) {
23567c478bd9Sstevel@tonic-gate 			if (o == 'd')
23577c478bd9Sstevel@tonic-gate 				temporary = B_FALSE;
23587c478bd9Sstevel@tonic-gate 			else if (o == '?')
23597c478bd9Sstevel@tonic-gate 				usage_milestone();
23607c478bd9Sstevel@tonic-gate 			else {
23617c478bd9Sstevel@tonic-gate 				assert(0);
23627c478bd9Sstevel@tonic-gate 				abort();
23637c478bd9Sstevel@tonic-gate 			}
23647c478bd9Sstevel@tonic-gate 		}
23657c478bd9Sstevel@tonic-gate 
23667c478bd9Sstevel@tonic-gate 		if (optind >= argc)
23677c478bd9Sstevel@tonic-gate 			usage_milestone();
23687c478bd9Sstevel@tonic-gate 
23697c478bd9Sstevel@tonic-gate 		milestone = validate_milestone(argv[optind]);
23707c478bd9Sstevel@tonic-gate 
23717c478bd9Sstevel@tonic-gate 		set_milestone(milestone, temporary);
23727c478bd9Sstevel@tonic-gate 	} else if (strcmp(argv[optind], "_smf_backup") == 0) {
23737c478bd9Sstevel@tonic-gate 		const char *reason = NULL;
23747c478bd9Sstevel@tonic-gate 
23757c478bd9Sstevel@tonic-gate 		++optind;
23767c478bd9Sstevel@tonic-gate 
23777c478bd9Sstevel@tonic-gate 		if (optind != argc - 1)
23787c478bd9Sstevel@tonic-gate 			usage();
23797c478bd9Sstevel@tonic-gate 
23807c478bd9Sstevel@tonic-gate 		if ((err = _scf_request_backup(h, argv[optind])) !=
23817c478bd9Sstevel@tonic-gate 		    SCF_SUCCESS) {
23827c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
23837c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_BOUND:
23847c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
23857c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_READONLY:
23867c478bd9Sstevel@tonic-gate 				scfdie();
23877c478bd9Sstevel@tonic-gate 				break;
23887c478bd9Sstevel@tonic-gate 
23897c478bd9Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
23907c478bd9Sstevel@tonic-gate 			case SCF_ERROR_INVALID_ARGUMENT:
23917c478bd9Sstevel@tonic-gate 				reason = scf_strerror(scf_error());
23927c478bd9Sstevel@tonic-gate 				break;
23937c478bd9Sstevel@tonic-gate 
23947c478bd9Sstevel@tonic-gate 			case SCF_ERROR_INTERNAL:
23957c478bd9Sstevel@tonic-gate 				reason =
23967c478bd9Sstevel@tonic-gate 				    "unknown error (see console for details)";
23977c478bd9Sstevel@tonic-gate 				break;
23987c478bd9Sstevel@tonic-gate 			}
2399c0889d7aSstevep 
24007c478bd9Sstevel@tonic-gate 			uu_warn("failed to backup repository: %s\n", reason);
24017c478bd9Sstevel@tonic-gate 			exit_status = UU_EXIT_FATAL;
24027c478bd9Sstevel@tonic-gate 		}
2403c0889d7aSstevep 	} else if (strcmp(argv[optind], "_smf_repository_switch") == 0) {
2404c0889d7aSstevep 		const char *reason = NULL;
2405c0889d7aSstevep 
2406c0889d7aSstevep 		++optind;
2407c0889d7aSstevep 
2408c0889d7aSstevep 		/*
2409c0889d7aSstevep 		 * Check argument and setup scf_switch structure
2410c0889d7aSstevep 		 */
2411c0889d7aSstevep 		if (optind != argc - 1)
2412c0889d7aSstevep 			exit(1);
2413c0889d7aSstevep 
2414c0889d7aSstevep 		if (strcmp(argv[optind], "fast") == 0) {
2415c0889d7aSstevep 			sw_back = 0;
2416c0889d7aSstevep 		} else if (strcmp(argv[optind], "perm") == 0) {
2417c0889d7aSstevep 			sw_back = 1;
2418c0889d7aSstevep 		} else {
2419c0889d7aSstevep 			exit(UU_EXIT_USAGE);
2420c0889d7aSstevep 		}
2421c0889d7aSstevep 
2422c0889d7aSstevep 		/*
2423c0889d7aSstevep 		 * Call into switch primitive
2424c0889d7aSstevep 		 */
2425c0889d7aSstevep 		if ((err = _scf_repository_switch(h, sw_back)) !=
2426c0889d7aSstevep 		    SCF_SUCCESS) {
2427c0889d7aSstevep 			/*
2428c0889d7aSstevep 			 * Retrieve per thread SCF error code
2429c0889d7aSstevep 			 */
2430c0889d7aSstevep 			switch (scf_error()) {
2431c0889d7aSstevep 			case SCF_ERROR_NOT_BOUND:
2432c0889d7aSstevep 				abort();
2433c0889d7aSstevep 				/* NOTREACHED */
2434c0889d7aSstevep 
2435c0889d7aSstevep 			case SCF_ERROR_CONNECTION_BROKEN:
2436c0889d7aSstevep 			case SCF_ERROR_BACKEND_READONLY:
2437c0889d7aSstevep 				scfdie();
2438c0889d7aSstevep 				/* NOTREACHED */
2439c0889d7aSstevep 
2440c0889d7aSstevep 			case SCF_ERROR_PERMISSION_DENIED:
2441c0889d7aSstevep 			case SCF_ERROR_INVALID_ARGUMENT:
2442c0889d7aSstevep 				reason = scf_strerror(scf_error());
2443c0889d7aSstevep 				break;
2444c0889d7aSstevep 
2445c0889d7aSstevep 			case SCF_ERROR_INTERNAL:
2446c0889d7aSstevep 				reason = "File operation error: (see console)";
2447c0889d7aSstevep 				break;
2448c0889d7aSstevep 
2449c0889d7aSstevep 			default:
2450c0889d7aSstevep 				abort();
2451c0889d7aSstevep 				/* NOTREACHED */
2452c0889d7aSstevep 			}
2453c0889d7aSstevep 
2454c0889d7aSstevep 			uu_warn("failed to switch repository: %s\n", reason);
2455c0889d7aSstevep 			exit_status = UU_EXIT_FATAL;
2456c0889d7aSstevep 		}
24577c478bd9Sstevel@tonic-gate 	} else {
24587c478bd9Sstevel@tonic-gate 		usage();
24597c478bd9Sstevel@tonic-gate 	}
24607c478bd9Sstevel@tonic-gate 
24617c478bd9Sstevel@tonic-gate 	if (scf_handle_unbind(h) == -1)
24627c478bd9Sstevel@tonic-gate 		scfdie();
24637c478bd9Sstevel@tonic-gate 	scf_handle_destroy(h);
24647c478bd9Sstevel@tonic-gate 
24657c478bd9Sstevel@tonic-gate 	return (exit_status);
24667c478bd9Sstevel@tonic-gate }
2467