17c478bdstevel@tonic-gate/*
27c478bdstevel@tonic-gate * CDDL HEADER START
37c478bdstevel@tonic-gate *
47c478bdstevel@tonic-gate * The contents of this file are subject to the terms of the
57646ae2lianep * Common Development and Distribution License (the "License").
67646ae2lianep * You may not use this file except in compliance with the License.
77c478bdstevel@tonic-gate *
87c478bdstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bdstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bdstevel@tonic-gate * See the License for the specific language governing permissions
117c478bdstevel@tonic-gate * and limitations under the License.
127c478bdstevel@tonic-gate *
137c478bdstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bdstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bdstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bdstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bdstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bdstevel@tonic-gate *
197c478bdstevel@tonic-gate * CDDL HEADER END
207c478bdstevel@tonic-gate */
217c478bdstevel@tonic-gate/*
22eb1a346Truong Nguyen * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bdstevel@tonic-gate * Use is subject to license terms.
247c478bdstevel@tonic-gate */
257c478bdstevel@tonic-gate
267c478bdstevel@tonic-gate/*
278fff788John Levon * Copyright 2020, Joyent, Inc. All rights reserved.
28647f844Bryan Cantrill */
29647f844Bryan Cantrill
30647f844Bryan Cantrill/*
317c478bdstevel@tonic-gate * svcadm - request adminstrative actions for service instances
327c478bdstevel@tonic-gate */
337c478bdstevel@tonic-gate
347c478bdstevel@tonic-gate#include <locale.h>
357c478bdstevel@tonic-gate#include <libintl.h>
367c478bdstevel@tonic-gate#include <libscf.h>
377c478bdstevel@tonic-gate#include <libscf_priv.h>
38eb1a346Truong Nguyen#include <libcontract.h>
39eb1a346Truong Nguyen#include <libcontract_priv.h>
40eb1a346Truong Nguyen#include <sys/contract/process.h>
417c478bdstevel@tonic-gate#include <libuutil.h>
427c478bdstevel@tonic-gate#include <stddef.h>
437c478bdstevel@tonic-gate#include <stdio.h>
447c478bdstevel@tonic-gate#include <stdlib.h>
457c478bdstevel@tonic-gate#include <string.h>
467c478bdstevel@tonic-gate#include <unistd.h>
47eb1a346Truong Nguyen#include <fcntl.h>
48eb1a346Truong Nguyen#include <procfs.h>
497c478bdstevel@tonic-gate#include <assert.h>
507c478bdstevel@tonic-gate#include <errno.h>
51647f844Bryan Cantrill#include <zone.h>
527c478bdstevel@tonic-gate
537c478bdstevel@tonic-gate#ifndef TEXT_DOMAIN
547c478bdstevel@tonic-gate#define	TEXT_DOMAIN	"SUNW_OST_OSCMD"
557c478bdstevel@tonic-gate#endif /* TEXT_DOMAIN */
567c478bdstevel@tonic-gate
577c478bdstevel@tonic-gate/* Must be a power of two */
587c478bdstevel@tonic-gate#define	HT_BUCKETS	64
597c478bdstevel@tonic-gate
607c478bdstevel@tonic-gate/*
617c478bdstevel@tonic-gate * Exit codes for enable and disable -s.
627c478bdstevel@tonic-gate */
637c478bdstevel@tonic-gate#define	EXIT_SVC_FAILURE	3
647c478bdstevel@tonic-gate#define	EXIT_DEP_FAILURE	4
657c478bdstevel@tonic-gate
666c7c876Jerry Jelinek#define	WALK_FLAGS	(SCF_WALK_UNIPARTIAL | SCF_WALK_MULTIPLE)
676c7c876Jerry Jelinek
687c478bdstevel@tonic-gate/*
697c478bdstevel@tonic-gate * How long we will wait (in seconds) for a service to change state
707c478bdstevel@tonic-gate * before re-checking its dependencies.
717c478bdstevel@tonic-gate */
727c478bdstevel@tonic-gate#define	WAIT_INTERVAL		3
737c478bdstevel@tonic-gate
7454d0224Bryan Cantrill#define	bad_error(func, err)						\
7554d0224Bryan Cantrill	uu_panic("%s:%d: %s() failed with unexpected error %d.\n",	\
7654d0224Bryan Cantrill	    __FILE__, __LINE__, (func), (err));
777c478bdstevel@tonic-gate
787c478bdstevel@tonic-gatestruct ht_elt {
797c478bdstevel@tonic-gate	struct ht_elt	*next;
807c478bdstevel@tonic-gate	boolean_t	active;
817c478bdstevel@tonic-gate	char		str[1];
827c478bdstevel@tonic-gate};
837c478bdstevel@tonic-gate
847c478bdstevel@tonic-gate
858fff788John Levon/*
868fff788John Levon * Callback data for enable/disable.
878fff788John Levon */
888fff788John Levon#define	SET_ENABLED	0x1
898fff788John Levon#define	SET_TEMPORARY	0x2
908fff788John Levon#define	SET_RECURSIVE	0x4
918fff788John Levon
928fff788John Levontypedef struct {
938fff788John Levon	char ed_comment[SCF_COMMENT_MAX_LENGTH];
948fff788John Levon	int ed_flags;
958fff788John Levon} enable_data_t;
968fff788John Levon
978fff788John Levon
987c478bdstevel@tonic-gatescf_handle_t *h;
997c478bdstevel@tonic-gatessize_t max_scf_fmri_sz;
1007c478bdstevel@tonic-gatestatic const char *emsg_permission_denied;
1017c478bdstevel@tonic-gatestatic const char *emsg_nomem;
1027c478bdstevel@tonic-gatestatic const char *emsg_create_pg_perm_denied;
1037c478bdstevel@tonic-gatestatic const char *emsg_pg_perm_denied;
1047c478bdstevel@tonic-gatestatic const char *emsg_prop_perm_denied;
1057c478bdstevel@tonic-gatestatic const char *emsg_no_service;
1067c478bdstevel@tonic-gate
1077c478bdstevel@tonic-gatestatic int exit_status = 0;
1087c478bdstevel@tonic-gatestatic int verbose = 0;
1097c478bdstevel@tonic-gatestatic char *scratch_fmri;
110702a871Jerry Jelinekstatic char *g_zonename = NULL;
11137b4022Jerry Jelinekstatic char svcstate[80];
11237b4022Jerry Jelinekstatic boolean_t svcsearch = B_FALSE;
1137c478bdstevel@tonic-gate
1147c478bdstevel@tonic-gatestatic struct ht_elt **visited;
1157c478bdstevel@tonic-gate
1160b5c925hgvoid do_scfdie(int lineno) __NORETURN;
1170b5c925hgstatic void usage_milestone(void) __NORETURN;
118eb1a346Truong Nguyenstatic void set_astring_prop(const char *, const char *, const char *,
119eb1a346Truong Nguyen    uint32_t, const char *, const char *);
120702a871Jerry Jelinekstatic void pr_warn(const char *format, ...);
1210b5c925hg
1227c478bdstevel@tonic-gate/*
1237c478bdstevel@tonic-gate * Visitors from synch.c, needed for enable -s and disable -s.
1247c478bdstevel@tonic-gate */
1257c478bdstevel@tonic-gateextern int is_enabled(scf_instance_t *);
1267c478bdstevel@tonic-gateextern int has_potential(scf_instance_t *, int);
1277c478bdstevel@tonic-gate
1287c478bdstevel@tonic-gatevoid
1297c478bdstevel@tonic-gatedo_scfdie(int lineno)
1307c478bdstevel@tonic-gate{
1317c478bdstevel@tonic-gate	scf_error_t err;
1327c478bdstevel@tonic-gate
1337c478bdstevel@tonic-gate	switch (err = scf_error()) {
1347c478bdstevel@tonic-gate	case SCF_ERROR_CONNECTION_BROKEN:
1357c478bdstevel@tonic-gate		uu_die(gettext("Connection to repository server broken.  "
1367c478bdstevel@tonic-gate		    "Exiting.\n"));
1377c478bdstevel@tonic-gate		/* NOTREACHED */
1387c478bdstevel@tonic-gate
1397c478bdstevel@tonic-gate	case SCF_ERROR_BACKEND_READONLY:
1407c478bdstevel@tonic-gate		uu_die(gettext("Repository is read-only.  Exiting.\n"));
1417c478bdstevel@tonic-gate		/* NOTREACHED */
1427c478bdstevel@tonic-gate
1437c478bdstevel@tonic-gate	default:
1447c478bdstevel@tonic-gate#ifdef NDEBUG
1457c478bdstevel@tonic-gate		uu_die(gettext("Unexpected libscf error: %s.  Exiting.\n"),
1467c478bdstevel@tonic-gate		    scf_strerror(err));
1477c478bdstevel@tonic-gate#else
1487c478bdstevel@tonic-gate		uu_die("Unexpected libscf error on line %d: %s.\n", lineno,
1497c478bdstevel@tonic-gate		    scf_strerror(err));
1507c478bdstevel@tonic-gate#endif
1517c478bdstevel@tonic-gate	}
1527c478bdstevel@tonic-gate}
1537c478bdstevel@tonic-gate
1547c478bdstevel@tonic-gate#define	scfdie()	do_scfdie(__LINE__)
1557c478bdstevel@tonic-gate
1567c478bdstevel@tonic-gatestatic void
1577c478bdstevel@tonic-gateusage()
1587c478bdstevel@tonic-gate{
1597c478bdstevel@tonic-gate	(void) fprintf(stderr, gettext(
16037b4022Jerry Jelinek	"Usage: %1$s [-S <state>] [-v] [-Z | -z zone] [cmd [args ... ]]\n\n"
16137b4022Jerry Jelinek	"\t%1$s enable [-rst] [<service> ...]\t- enable and online service(s)\n"
1628fff788John Levon	"\t%1$s disable [-c comment] [-st] [<service> ...] - disable "
16337b4022Jerry Jelinek	"service(s)\n"
164ac0324dJerry Jelinek	"\t%1$s restart [-d] [<service> ...]\t- restart specified service(s)\n"
16537b4022Jerry Jelinek	"\t%1$s refresh [<service> ...]\t\t- re-read service configuration\n"
16637b4022Jerry Jelinek	"\t%1$s mark [-It] <state> [<service> ...] - set maintenance state\n"
16737b4022Jerry Jelinek	"\t%1$s clear [<service> ...]\t\t- clear maintenance state\n"
1687c478bdstevel@tonic-gate	"\t%1$s milestone [-d] <milestone>\t- advance to a service milestone\n"
1697c478bdstevel@tonic-gate	"\n\t"
1707c478bdstevel@tonic-gate	"Services can be specified using an FMRI, abbreviation, or fnmatch(5)\n"
1717c478bdstevel@tonic-gate	"\tpattern, as shown in these examples for svc:/network/smtp:sendmail\n"
1727c478bdstevel@tonic-gate	"\n"
1737c478bdstevel@tonic-gate	"\t%1$s <cmd> svc:/network/smtp:sendmail\n"
1747c478bdstevel@tonic-gate	"\t%1$s <cmd> network/smtp:sendmail\n"
1757c478bdstevel@tonic-gate	"\t%1$s <cmd> network/*mail\n"
1767c478bdstevel@tonic-gate	"\t%1$s <cmd> network/smtp\n"
1777c478bdstevel@tonic-gate	"\t%1$s <cmd> smtp:sendmail\n"
1787c478bdstevel@tonic-gate	"\t%1$s <cmd> smtp\n"
1797c478bdstevel@tonic-gate	"\t%1$s <cmd> sendmail\n"), uu_getpname());
1807c478bdstevel@tonic-gate
1817c478bdstevel@tonic-gate	exit(UU_EXIT_USAGE);
1827c478bdstevel@tonic-gate}
1837c478bdstevel@tonic-gate
1847c478bdstevel@tonic-gate
1857c478bdstevel@tonic-gate/*
1867c478bdstevel@tonic-gate * FMRI hash table for recursive enable.
1877c478bdstevel@tonic-gate */
1887c478bdstevel@tonic-gate
1897c478bdstevel@tonic-gatestatic uint32_t
1907c478bdstevel@tonic-gatehash_fmri(const char *str)
1917c478bdstevel@tonic-gate{
1927c478bdstevel@tonic-gate	uint32_t h = 0, g;
1937c478bdstevel@tonic-gate	const char *p;
1947c478bdstevel@tonic-gate
1957c478bdstevel@tonic-gate	/* Generic hash function from uts/common/os/modhash.c . */
1967c478bdstevel@tonic-gate	for (p = str; *p != '\0'; ++p) {
1977c478bdstevel@tonic-gate		h = (h << 4) + *p;
1987c478bdstevel@tonic-gate		if ((g = (h & 0xf0000000)) != 0) {
1997c478bdstevel@tonic-gate			h ^= (g >> 24);
2007c478bdstevel@tonic-gate			h ^= g;
2017c478bdstevel@tonic-gate		}
2027c478bdstevel@tonic-gate	}
2037c478bdstevel@tonic-gate
2047c478bdstevel@tonic-gate	return (h);
2057c478bdstevel@tonic-gate}
2067c478bdstevel@tonic-gate
2077c478bdstevel@tonic-gate/*
2087c478bdstevel@tonic-gate * Return 1 if str has been visited, 0 if it has not, and -1 if memory could not
2097c478bdstevel@tonic-gate * be allocated.
2107c478bdstevel@tonic-gate */
2117c478bdstevel@tonic-gatestatic int
2127c478bdstevel@tonic-gatevisited_find_or_add(const char *str, struct ht_elt **hep)
2137c478bdstevel@tonic-gate{
2147c478bdstevel@tonic-gate	uint32_t h;
2157c478bdstevel@tonic-gate	uint_t i;
2167c478bdstevel@tonic-gate	struct ht_elt *he;
2177c478bdstevel@tonic-gate
2187c478bdstevel@tonic-gate	h = hash_fmri(str);
2197c478bdstevel@tonic-gate	i = h & (HT_BUCKETS - 1);
2207c478bdstevel@tonic-gate
2217c478bdstevel@tonic-gate	for (he = visited[i]; he != NULL; he = he->next) {
2227c478bdstevel@tonic-gate		if (strcmp(he->str, str) == 0) {
2237c478bdstevel@tonic-gate			if (hep)
2247c478bdstevel@tonic-gate				*hep = he;
2257c478bdstevel@tonic-gate			return (1);
2267c478bdstevel@tonic-gate		}
2277c478bdstevel@tonic-gate	}
2287c478bdstevel@tonic-gate
2297c478bdstevel@tonic-gate	he = malloc(offsetof(struct ht_elt, str) + strlen(str) + 1);
2307c478bdstevel@tonic-gate	if (he == NULL)
2317c478bdstevel@tonic-gate		return (-1);
2327c478bdstevel@tonic-gate
2337c478bdstevel@tonic-gate	(void) strcpy(he->str, str);
2347c478bdstevel@tonic-gate
2357c478bdstevel@tonic-gate	he->next = visited[i];
2367c478bdstevel@tonic-gate	visited[i] = he;
2377c478bdstevel@tonic-gate
2387c478bdstevel@tonic-gate	if (hep)
2397c478bdstevel@tonic-gate		*hep = he;
2407c478bdstevel@tonic-gate	return (0);
2417c478bdstevel@tonic-gate}
2427c478bdstevel@tonic-gate
2437c478bdstevel@tonic-gate
2447c478bdstevel@tonic-gate/*
2457c478bdstevel@tonic-gate * Returns 0, ECANCELED if pg is deleted, ENOENT if propname doesn't exist,
2467c478bdstevel@tonic-gate * EINVAL if the property is not of boolean type or has no values, and E2BIG
2477c478bdstevel@tonic-gate * if it has more than one value.  *bp is set if 0 or E2BIG is returned.
2487c478bdstevel@tonic-gate */
2497c478bdstevel@tonic-gateint
2507c478bdstevel@tonic-gateget_bool_prop(scf_propertygroup_t *pg, const char *propname, uint8_t *bp)
2517c478bdstevel@tonic-gate{
2527c478bdstevel@tonic-gate	scf_property_t *prop;
2537c478bdstevel@tonic-gate	scf_value_t *val;
2547c478bdstevel@tonic-gate	int ret;
2557c478bdstevel@tonic-gate
2567c478bdstevel@tonic-gate	if ((prop = scf_property_create(h)) == NULL ||
2577c478bdstevel@tonic-gate	    (val = scf_value_create(h)) == NULL)
2587c478bdstevel@tonic-gate		scfdie();
2597c478bdstevel@tonic-gate
2607c478bdstevel@tonic-gate	if (scf_pg_get_property(pg, propname, prop) != 0) {
2617c478bdstevel@tonic-gate		switch (scf_error()) {
2627c478bdstevel@tonic-gate		case SCF_ERROR_DELETED:
2637c478bdstevel@tonic-gate			ret = ECANCELED;
2647c478bdstevel@tonic-gate			goto out;
2657c478bdstevel@tonic-gate
2667c478bdstevel@tonic-gate		case SCF_ERROR_NOT_FOUND:
2677c478bdstevel@tonic-gate			ret = ENOENT;
2687c478bdstevel@tonic-gate			goto out;
2697c478bdstevel@tonic-gate
2707c478bdstevel@tonic-gate		case SCF_ERROR_NOT_SET:
2717c478bdstevel@tonic-gate			assert(0);
2727c478bdstevel@tonic-gate			abort();
2737c478bdstevel@tonic-gate			/* NOTREACHED */
2747c478bdstevel@tonic-gate
2757c478bdstevel@tonic-gate		default:
2767c478bdstevel@tonic-gate			scfdie();
2777c478bdstevel@tonic-gate		}
2787c478bdstevel@tonic-gate	}
2797c478bdstevel@tonic-gate
2807c478bdstevel@tonic-gate	if (scf_property_get_value(prop, val) == 0) {
2817c478bdstevel@tonic-gate		ret = 0;
2827c478bdstevel@tonic-gate	} else {
2837c478bdstevel@tonic-gate		switch (scf_error()) {
2847c478bdstevel@tonic-gate		case SCF_ERROR_DELETED:
2857c478bdstevel@tonic-gate			ret = ENOENT;
2867c478bdstevel@tonic-gate			goto out;
2877c478bdstevel@tonic-gate
2887c478bdstevel@tonic-gate		case SCF_ERROR_NOT_FOUND:
2897c478bdstevel@tonic-gate			ret = EINVAL;
2907c478bdstevel@tonic-gate			goto out;
2917c478bdstevel@tonic-gate
2927c478bdstevel@tonic-gate		case SCF_ERROR_CONSTRAINT_VIOLATED:
2937c478bdstevel@tonic-gate			ret = E2BIG;
2947c478bdstevel@tonic-gate			break;
2957c478bdstevel@tonic-gate
2967c478bdstevel@tonic-gate		case SCF_ERROR_NOT_SET:
2977c478bdstevel@tonic-gate			assert(0);
2987c478bdstevel@tonic-gate			abort();
2997c478bdstevel@tonic-gate			/* NOTREACHED */
3007c478bdstevel@tonic-gate
3017c478bdstevel@tonic-gate		default:
3027c478bdstevel@tonic-gate			scfdie();
3037c478bdstevel@tonic-gate		}
3047c478bdstevel@tonic-gate	}
3057c478bdstevel@tonic-gate
3067c478bdstevel@tonic-gate	if (scf_value_get_boolean(val, bp) != 0) {
3077c478bdstevel@tonic-gate		if (scf_error() != SCF_ERROR_TYPE_MISMATCH)
3087c478bdstevel@tonic-gate			scfdie();
3097c478bdstevel@tonic-gate
3107c478bdstevel@tonic-gate		ret = EINVAL;
3117c478bdstevel@tonic-gate		goto out;
3127c478bdstevel@tonic-gate	}
3137c478bdstevel@tonic-gate
3147c478bdstevel@tonic-gateout:
3157c478bdstevel@tonic-gate	scf_value_destroy(val);
3167c478bdstevel@tonic-gate	scf_property_destroy(prop);
3177c478bdstevel@tonic-gate	return (ret);
3187c478bdstevel@tonic-gate}
3197c478bdstevel@tonic-gate
3207c478bdstevel@tonic-gate/*
3217c478bdstevel@tonic-gate * Returns 0, EPERM, or EROFS.
3227c478bdstevel@tonic-gate */
3237c478bdstevel@tonic-gatestatic int
3247c478bdstevel@tonic-gateset_bool_prop(scf_propertygroup_t *pg, const char *propname, boolean_t b)
3257c478bdstevel@tonic-gate{
3267c478bdstevel@tonic-gate	scf_value_t *v;
3277c478bdstevel@tonic-gate	scf_transaction_t *tx;
3287c478bdstevel@tonic-gate	scf_transaction_entry_t *ent;
3297c478bdstevel@tonic-gate	int ret = 0, r;
3307c478bdstevel@tonic-gate
3317c478bdstevel@tonic-gate	if ((tx = scf_transaction_create(h)) == NULL ||
3327c478bdstevel@tonic-gate	    (ent = scf_entry_create(h)) == NULL ||
3337c478bdstevel@tonic-gate	    (v = scf_value_create(h)) == NULL)
3347c478bdstevel@tonic-gate		scfdie();
3357c478bdstevel@tonic-gate
3367c478bdstevel@tonic-gate	scf_value_set_boolean(v, b);
3377c478bdstevel@tonic-gate
3387c478bdstevel@tonic-gate	for (;;) {
3397c478bdstevel@tonic-gate		if (scf_transaction_start(tx, pg) == -1) {
3407c478bdstevel@tonic-gate			switch (scf_error()) {
3417c478bdstevel@tonic-gate			case SCF_ERROR_PERMISSION_DENIED:
3427c478bdstevel@tonic-gate				ret = EPERM;
3437c478bdstevel@tonic-gate				goto out;
3447c478bdstevel@tonic-gate
3457c478bdstevel@tonic-gate			case SCF_ERROR_BACKEND_READONLY:
3467c478bdstevel@tonic-gate				ret = EROFS;
3477c478bdstevel@tonic-gate				goto out;
3487c478bdstevel@tonic-gate
3497c478bdstevel@tonic-gate			default:
3507c478bdstevel@tonic-gate				scfdie();
3517c478bdstevel@tonic-gate			}
3527c478bdstevel@tonic-gate		}
3537c478bdstevel@tonic-gate
3547c478bdstevel@tonic-gate		if (scf_transaction_property_change_type(tx, ent, propname,
3557c478bdstevel@tonic-gate		    SCF_TYPE_BOOLEAN) != 0) {
3567c478bdstevel@tonic-gate			if (scf_error() != SCF_ERROR_NOT_FOUND)
3577c478bdstevel@tonic-gate				scfdie();
3587c478bdstevel@tonic-gate
3597c478bdstevel@tonic-gate			if (scf_transaction_property_new(tx, ent, propname,
3607c478bdstevel@tonic-gate			    SCF_TYPE_BOOLEAN) != 0)
3617c478bdstevel@tonic-gate				scfdie();
3627c478bdstevel@tonic-gate		}
3637c478bdstevel@tonic-gate
3647c478bdstevel@tonic-gate		r = scf_entry_add_value(ent, v);
3657c478bdstevel@tonic-gate		assert(r == 0);
3667c478bdstevel@tonic-gate
3677c478bdstevel@tonic-gate		r = scf_transaction_commit(tx);
3687c478bdstevel@tonic-gate		if (r == 1)
3697c478bdstevel@tonic-gate			break;
3707c478bdstevel@tonic-gate
3717c478bdstevel@tonic-gate		scf_transaction_reset(tx);
3727c478bdstevel@tonic-gate
3737c478bdstevel@tonic-gate		if (r != 0) {
3747c478bdstevel@tonic-gate			switch (scf_error()) {
3757c478bdstevel@tonic-gate			case SCF_ERROR_PERMISSION_DENIED:
3767c478bdstevel@tonic-gate				ret = EPERM;
3777c478bdstevel@tonic-gate				goto out;
3787c478bdstevel@tonic-gate
3797c478bdstevel@tonic-gate			case SCF_ERROR_BACKEND_READONLY:
3807c478bdstevel@tonic-gate				ret = EROFS;
3817c478bdstevel@tonic-gate				goto out;
3827c478bdstevel@tonic-gate
3837c478bdstevel@tonic-gate			default:
3847c478bdstevel@tonic-gate				scfdie();
3857c478bdstevel@tonic-gate			}
3867c478bdstevel@tonic-gate		}
3877c478bdstevel@tonic-gate
3887c478bdstevel@tonic-gate		if (scf_pg_update(pg) == -1)
3897c478bdstevel@tonic-gate			scfdie();
3907c478bdstevel@tonic-gate	}
3917c478bdstevel@tonic-gate
3927c478bdstevel@tonic-gateout:
3937c478bdstevel@tonic-gate	scf_transaction_destroy(tx);
3947c478bdstevel@tonic-gate	scf_entry_destroy(ent);
3957c478bdstevel@tonic-gate	scf_value_destroy(v);
3967c478bdstevel@tonic-gate	return (ret);
3977c478bdstevel@tonic-gate}
3987c478bdstevel@tonic-gate
3997c478bdstevel@tonic-gate/*
4007c478bdstevel@tonic-gate * Gets the single astring value of the propname property of pg.  prop & v are
4017c478bdstevel@tonic-gate * scratch space.  Returns the length of the string on success or
4027c478bdstevel@tonic-gate *   -ENOENT - pg has no property named propname
4037c478bdstevel@tonic-gate *   -E2BIG - property has no values or multiple values
4047c478bdstevel@tonic-gate *   -EINVAL - property type is not compatible with astring
4057c478bdstevel@tonic-gate */
4067c478bdstevel@tonic-gatessize_t
4077c478bdstevel@tonic-gateget_astring_prop(const scf_propertygroup_t *pg, const char *propname,
4087c478bdstevel@tonic-gate    scf_property_t *prop, scf_value_t *v, char *buf, size_t bufsz)
4097c478bdstevel@tonic-gate{
4107c478bdstevel@tonic-gate	ssize_t sz;
4117c478bdstevel@tonic-gate
4127c478bdstevel@tonic-gate	if (scf_pg_get_property(pg, propname, prop) != 0) {
4137c478bdstevel@tonic-gate		if (scf_error() != SCF_ERROR_NOT_FOUND)
4147c478bdstevel@tonic-gate			scfdie();
4157c478bdstevel@tonic-gate
4167c478bdstevel@tonic-gate		return (-ENOENT);
4177c478bdstevel@tonic-gate	}
4187c478bdstevel@tonic-gate
4197c478bdstevel@tonic-gate	if (scf_property_get_value(prop, v) != 0) {
4207c478bdstevel@tonic-gate		switch (scf_error()) {
4217c478bdstevel@tonic-gate		case SCF_ERROR_NOT_FOUND:
4227c478bdstevel@tonic-gate		case SCF_ERROR_CONSTRAINT_VIOLATED:
4237c478bdstevel@tonic-gate			return (-E2BIG);
4247c478bdstevel@tonic-gate
4257c478bdstevel@tonic-gate		default:
4267c478bdstevel@tonic-gate			scfdie();
4277c478bdstevel@tonic-gate		}
4287c478bdstevel@tonic-gate	}
4297c478bdstevel@tonic-gate
4307c478bdstevel@tonic-gate	sz = scf_value_get_astring(v, buf, bufsz);
4317c478bdstevel@tonic-gate	if (sz < 0) {
4327c478bdstevel@tonic-gate		if (scf_error() != SCF_ERROR_TYPE_MISMATCH)
4337c478bdstevel@tonic-gate			scfdie();
4347c478bdstevel@tonic-gate
4357c478bdstevel@tonic-gate		return (-EINVAL);
4367c478bdstevel@tonic-gate	}
4377c478bdstevel@tonic-gate
4387c478bdstevel@tonic-gate	return (sz);
4397c478bdstevel@tonic-gate}
4407c478bdstevel@tonic-gate
4417c478bdstevel@tonic-gate/*
442eb1a346Truong Nguyen * Returns 0 or EPERM.
4437c478bdstevel@tonic-gate */
4447c478bdstevel@tonic-gatestatic int
445eb1a346Truong Nguyenpg_get_or_add(const scf_instance_t *inst, const char *pgname,
446eb1a346Truong Nguyen    const char *pgtype, uint32_t pgflags, scf_propertygroup_t *pg)
4477c478bdstevel@tonic-gate{
448eb1a346Truong Nguyenagain:
449eb1a346Truong Nguyen	if (scf_instance_get_pg(inst, pgname, pg) == 0)
450eb1a346Truong Nguyen		return (0);
4517c478bdstevel@tonic-gate
452eb1a346Truong Nguyen	if (scf_error() != SCF_ERROR_NOT_FOUND)
4537c478bdstevel@tonic-gate		scfdie();
4547c478bdstevel@tonic-gate
455eb1a346Truong Nguyen	if (scf_instance_add_pg(inst, pgname, pgtype, pgflags, pg) == 0)
456eb1a346Truong Nguyen		return (0);
4577c478bdstevel@tonic-gate
458eb1a346Truong Nguyen	switch (scf_error()) {
459eb1a346Truong Nguyen	case SCF_ERROR_EXISTS:
460eb1a346Truong Nguyen		goto again;
4617c478bdstevel@tonic-gate
462eb1a346Truong Nguyen	case SCF_ERROR_PERMISSION_DENIED:
463eb1a346Truong Nguyen		return (EPERM);
4647c478bdstevel@tonic-gate
465eb1a346Truong Nguyen	default:
466eb1a346Truong Nguyen		scfdie();
467eb1a346Truong Nguyen		/* NOTREACHED */
468eb1a346Truong Nguyen	}
469eb1a346Truong Nguyen}
4707c478bdstevel@tonic-gate
471eb1a346Truong Nguyenstatic int
472eb1a346Truong Nguyenmy_ct_name(char *out, size_t len)
473eb1a346Truong Nguyen{
474eb1a346Truong Nguyen	ct_stathdl_t st;
475eb1a346Truong Nguyen	char *ct_fmri;
476eb1a346Truong Nguyen	ctid_t ct;
477eb1a346Truong Nguyen	int fd, errno, ret;
4787c478bdstevel@tonic-gate
479eb1a346Truong Nguyen	if ((ct = getctid()) == -1)
480eb1a346Truong Nguyen		uu_die(gettext("Could not get contract id for process"));
4817c478bdstevel@tonic-gate
482eb1a346Truong Nguyen	fd = contract_open(ct, "process", "status", O_RDONLY);
4837c478bdstevel@tonic-gate
484eb1a346Truong Nguyen	if ((errno = ct_status_read(fd, CTD_ALL, &st)) != 0)
485eb1a346Truong Nguyen		uu_warn(gettext("Could not read status of contract "
486eb1a346Truong Nguyen		    "%ld: %s.\n"), ct, strerror(errno));
4877c478bdstevel@tonic-gate
488eb1a346Truong Nguyen	if ((errno = ct_pr_status_get_svc_fmri(st, &ct_fmri)) != 0)
489eb1a346Truong Nguyen		uu_warn(gettext("Could not get svc_fmri for contract "
490eb1a346Truong Nguyen		    "%ld: %s.\n"), ct, strerror(errno));
4917c478bdstevel@tonic-gate
492eb1a346Truong Nguyen	ret = strlcpy(out, ct_fmri, len);
4937c478bdstevel@tonic-gate
494eb1a346Truong Nguyen	ct_status_free(st);
495eb1a346Truong Nguyen	(void) close(fd);
4967c478bdstevel@tonic-gate
4977c478bdstevel@tonic-gate	return (ret);
4987c478bdstevel@tonic-gate}
4997c478bdstevel@tonic-gate
5007c478bdstevel@tonic-gate/*
501eb1a346Truong Nguyen * Set auxiliary_tty and auxiliary_fmri properties in restarter_actions pg to
502eb1a346Truong Nguyen * communicate whether the action is requested from a tty and the fmri of the
503eb1a346Truong Nguyen * responsible process.
504e8f5b3fTruong Nguyen *
505e8f5b3fTruong Nguyen * Returns 0, EPERM, or EROFS
5067c478bdstevel@tonic-gate */
5077c478bdstevel@tonic-gatestatic int
508eb1a346Truong Nguyenrestarter_setup(const char *fmri, const scf_instance_t *inst)
5097c478bdstevel@tonic-gate{
510eb1a346Truong Nguyen	boolean_t b = B_FALSE;
511eb1a346Truong Nguyen	scf_propertygroup_t *pg = NULL;
512e8f5b3fTruong Nguyen	int ret = 0;
5137c478bdstevel@tonic-gate
514eb1a346Truong Nguyen	if ((pg = scf_pg_create(h)) == NULL)
5157c478bdstevel@tonic-gate		scfdie();
5167c478bdstevel@tonic-gate
517eb1a346Truong Nguyen	if (pg_get_or_add(inst, SCF_PG_RESTARTER_ACTIONS,
518eb1a346Truong Nguyen	    SCF_PG_RESTARTER_ACTIONS_TYPE, SCF_PG_RESTARTER_ACTIONS_FLAGS,
519e8f5b3fTruong Nguyen	    pg) == EPERM) {
520e8f5b3fTruong Nguyen		if (!verbose)
521e8f5b3fTruong Nguyen			uu_warn(emsg_permission_denied, fmri);
522e8f5b3fTruong Nguyen		else
523e8f5b3fTruong Nguyen			uu_warn(emsg_create_pg_perm_denied, fmri,
524e8f5b3fTruong Nguyen			    SCF_PG_RESTARTER_ACTIONS);
525e8f5b3fTruong Nguyen
526e8f5b3fTruong Nguyen		ret = EPERM;
527e8f5b3fTruong Nguyen		goto out;
528e8f5b3fTruong Nguyen	}
5297c478bdstevel@tonic-gate
530eb1a346Truong Nguyen	/* Set auxiliary_tty property */
531eb1a346Truong Nguyen	if (isatty(STDIN_FILENO))
532eb1a346Truong Nguyen		b = B_TRUE;
5337c478bdstevel@tonic-gate
534eb1a346Truong Nguyen	/* Create and set state to disabled */
53550c9b2fToomas Soome	switch (set_bool_prop(pg, SCF_PROPERTY_AUX_TTY, b)) {
536eb1a346Truong Nguyen	case 0:
537eb1a346Truong Nguyen		break;
538eb1a346Truong Nguyen
539eb1a346Truong Nguyen	case EPERM:
540e8f5b3fTruong Nguyen		if (!verbose)
541e8f5b3fTruong Nguyen			uu_warn(emsg_permission_denied, fmri);
542e8f5b3fTruong Nguyen		else
543e8f5b3fTruong Nguyen			uu_warn(emsg_prop_perm_denied, fmri,
544e8f5b3fTruong Nguyen			    SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_AUX_TTY);
545e8f5b3fTruong Nguyen
546e8f5b3fTruong Nguyen		ret = EPERM;
547e8f5b3fTruong Nguyen		goto out;
548e8f5b3fTruong Nguyen		/* NOTREACHED */
549eb1a346Truong Nguyen
550eb1a346Truong Nguyen	case EROFS:
551e8f5b3fTruong Nguyen		/* Shouldn't happen, but it can. */
552e8f5b3fTruong Nguyen		if (!verbose)
553e8f5b3fTruong Nguyen			uu_warn(gettext("%s: Repository read-only.\n"), fmri);
554e8f5b3fTruong Nguyen		else
555e8f5b3fTruong Nguyen			uu_warn(gettext("%s: Could not set %s/%s "
556e8f5b3fTruong Nguyen			    "(repository read-only).\n"), fmri,
557e8f5b3fTruong Nguyen			    SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_AUX_TTY);
558e8f5b3fTruong Nguyen
559e8f5b3fTruong Nguyen		ret = EROFS;
560e8f5b3fTruong Nguyen		goto out;
561e8f5b3fTruong Nguyen		/* NOTREACHED */
5627c478bdstevel@tonic-gate
5637c478bdstevel@tonic-gate	default:
5647c478bdstevel@tonic-gate		scfdie();
5657c478bdstevel@tonic-gate	}
566eb1a346Truong Nguyen
567eb1a346Truong Nguyen	if (my_ct_name(scratch_fmri, max_scf_fmri_sz) > 0) {
568eb1a346Truong Nguyen		set_astring_prop(fmri, SCF_PG_RESTARTER_ACTIONS,
569eb1a346Truong Nguyen		    SCF_PG_RESTARTER_ACTIONS_TYPE,
570eb1a346Truong Nguyen		    SCF_PG_RESTARTER_ACTIONS_FLAGS,
571eb1a346Truong Nguyen		    SCF_PROPERTY_AUX_FMRI, scratch_fmri);
572eb1a346Truong Nguyen	} else {
573eb1a346Truong Nguyen		uu_warn(gettext("%s: Could not set %s/%s: "
574eb1a346Truong Nguyen		    "my_ct_name failed.\n"), fmri,
575eb1a346Truong Nguyen		    SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_AUX_FMRI);
576eb1a346Truong Nguyen	}
577eb1a346Truong Nguyen
578e8f5b3fTruong Nguyenout:
579eb1a346Truong Nguyen	scf_pg_destroy(pg);
580e8f5b3fTruong Nguyen	return (ret);
5817c478bdstevel@tonic-gate}
5827c478bdstevel@tonic-gate
5838fff788John Levonstatic int
5848fff788John Levondelete_prop(const char *fmri, scf_instance_t *inst, const char *pgname,
5858fff788John Levon    const char *propname)
5868fff788John Levon{
5878fff788John Levon	int r = scf_instance_delete_prop(inst, pgname, propname);
5888fff788John Levon
5898fff788John Levon	switch (r) {
5908fff788John Levon	case 0:
5918fff788John Levon		break;
5928fff788John Levon
5938fff788John Levon	case ECANCELED:
5948fff788John Levon		uu_warn(emsg_no_service, fmri);
5958fff788John Levon		break;
5968fff788John Levon
5978fff788John Levon	case EACCES:
5988fff788John Levon		uu_warn(gettext("Could not delete %s/%s "
5998fff788John Levon		    "property of %s: backend access denied.\n"),
6008fff788John Levon		    pgname, propname, fmri);
6018fff788John Levon		break;
6028fff788John Levon
6038fff788John Levon	case EROFS:
6048fff788John Levon		uu_warn(gettext("Could not delete %s/%s "
6058fff788John Levon		    "property of %s: backend is read-only.\n"),
6068fff788John Levon		    pgname, propname, fmri);
6078fff788John Levon		break;
6088fff788John Levon
6098fff788John Levon	default:
6108fff788John Levon		bad_error("scf_instance_delete_prop", r);
6118fff788John Levon	}
6128fff788John Levon
6138fff788John Levon	return (r);
6148fff788John Levon}
6158fff788John Levon
6168fff788John Levon/*
6178fff788John Levon * Returns 0, EPERM, or EROFS.
6188fff788John Levon */
6198fff788John Levonstatic int
6208fff788John Levonset_enabled_props(scf_propertygroup_t *pg, enable_data_t *ed)
6218fff788John Levon{
6228fff788John Levon	scf_transaction_entry_t *ent1;
6238fff788John Levon	scf_transaction_entry_t *ent2;
6248fff788John Levon	scf_transaction_t *tx;
6258fff788John Levon	scf_value_t *v2;
6268fff788John Levon	scf_value_t *v1;
6278fff788John Levon	int ret = 0, r;
6288fff788John Levon
6298fff788John Levon	if ((tx = scf_transaction_create(h)) == NULL ||
6308fff788John Levon	    (ent1 = scf_entry_create(h)) == NULL ||
6318fff788John Levon	    (ent2 = scf_entry_create(h)) == NULL ||
6328fff788John Levon	    (v1 = scf_value_create(h)) == NULL ||
6338fff788John Levon	    (v2 = scf_value_create(h)) == NULL)
6348fff788John Levon		scfdie();
6358fff788John Levon
6368fff788John Levon	for (;;) {
6378fff788John Levon		if (scf_transaction_start(tx, pg) == -1) {
6388fff788John Levon			switch (scf_error()) {
6398fff788John Levon			case SCF_ERROR_PERMISSION_DENIED:
6408fff788John Levon				ret = EPERM;
6418fff788John Levon				goto out;
6428fff788John Levon
6438fff788John Levon			case SCF_ERROR_BACKEND_READONLY:
6448fff788John Levon				ret = EROFS;
6458fff788John Levon				goto out;
6468fff788John Levon
6478fff788John Levon			default:
6488fff788John Levon				scfdie();
6498fff788John Levon			}
6508fff788John Levon		}
6518fff788John Levon
6528fff788John Levon		if (scf_transaction_property_change_type(tx, ent1,
6538fff788John Levon		    SCF_PROPERTY_ENABLED, SCF_TYPE_BOOLEAN) != 0) {
6548fff788John Levon			if (scf_error() != SCF_ERROR_NOT_FOUND)
6558fff788John Levon				scfdie();
6568fff788John Levon
6578fff788John Levon			if (scf_transaction_property_new(tx, ent1,
6588fff788John Levon			    SCF_PROPERTY_ENABLED, SCF_TYPE_BOOLEAN) != 0)
6598fff788John Levon				scfdie();
6608fff788John Levon		}
6618fff788John Levon
6628fff788John Levon		scf_value_set_boolean(v1, !!(ed->ed_flags & SET_ENABLED));
6638fff788John Levon
6648fff788John Levon		r = scf_entry_add_value(ent1, v1);
6658fff788John Levon		assert(r == 0);
6668fff788John Levon
6678fff788John Levon		if (scf_transaction_property_change_type(tx, ent2,
6688fff788John Levon		    SCF_PROPERTY_COMMENT, SCF_TYPE_ASTRING) != 0) {
6698fff788John Levon			if (scf_error() != SCF_ERROR_NOT_FOUND)
6708fff788John Levon				scfdie();
6718fff788John Levon
6728fff788John Levon			if (scf_transaction_property_new(tx, ent2,
6738fff788John Levon			    SCF_PROPERTY_COMMENT, SCF_TYPE_ASTRING) != 0)
6748fff788John Levon				scfdie();
6758fff788John Levon		}
6768fff788John Levon
6778fff788John Levon		if (scf_value_set_astring(v2, ed->ed_comment) != SCF_SUCCESS)
6788fff788John Levon			scfdie();
6798fff788John Levon
6808fff788John Levon		if (scf_entry_add_value(ent2, v2) != SCF_SUCCESS)
6818fff788John Levon			scfdie();
6828fff788John Levon
6838fff788John Levon		r = scf_transaction_commit(tx);
6848fff788John Levon		if (r == 1)
6858fff788John Levon			break;
6868fff788John Levon
6878fff788John Levon		scf_transaction_reset(tx);
6888fff788John Levon
6898fff788John Levon		if (r != 0) {
6908fff788John Levon			switch (scf_error()) {
6918fff788John Levon			case SCF_ERROR_PERMISSION_DENIED:
6928fff788John Levon				ret = EPERM;
6938fff788John Levon				goto out;
6948fff788John Levon
6958fff788John Levon			case SCF_ERROR_BACKEND_READONLY:
6968fff788John Levon				ret = EROFS;
6978fff788John Levon				goto out;
6988fff788John Levon
6998fff788John Levon			default:
7008fff788John Levon				scfdie();
7018fff788John Levon			}
7028fff788John Levon		}
7038fff788John Levon
7048fff788John Levon		if (scf_pg_update(pg) == -1)
7058fff788John Levon			scfdie();
7068fff788John Levon	}
7078fff788John Levon
7088fff788John Levonout:
7098fff788John Levon	scf_transaction_destroy(tx);
7108fff788John Levon	scf_entry_destroy(ent1);
7118fff788John Levon	scf_entry_destroy(ent2);
7128fff788John Levon	scf_value_destroy(v1);
7138fff788John Levon	scf_value_destroy(v2);
7148fff788John Levon	return (ret);
7158fff788John Levon}
7168fff788John Levon
7177c478bdstevel@tonic-gate/*
7188fff788John Levon * Enable or disable an instance.  SET_TEMPORARY modifications apply to
7198fff788John Levon * general_ovr/ property group.
7207c478bdstevel@tonic-gate */
7217c478bdstevel@tonic-gatestatic void
7228fff788John Levonset_inst_enabled(const char *fmri, scf_instance_t *inst, enable_data_t *ed)
7237c478bdstevel@tonic-gate{
7247c478bdstevel@tonic-gate	scf_propertygroup_t *pg;
7257c478bdstevel@tonic-gate	uint8_t b;
7267c478bdstevel@tonic-gate	const char *pgname = NULL;	/* For emsg_pg_perm_denied */
7277c478bdstevel@tonic-gate
7287c478bdstevel@tonic-gate	pg = scf_pg_create(h);
7297c478bdstevel@tonic-gate	if (pg == NULL)
7307c478bdstevel@tonic-gate		scfdie();
7317c478bdstevel@tonic-gate
732eb1a346Truong Nguyen	if (restarter_setup(fmri, inst))
733e8f5b3fTruong Nguyen		goto out;
734eb1a346Truong Nguyen
735fee38f6tn	/*
736fee38f6tn	 * An instance's configuration is incomplete if general/enabled
737fee38f6tn	 * doesn't exist. Create both the property group and property
738fee38f6tn	 * here if they don't exist.
739fee38f6tn	 */
740fee38f6tn	pgname = SCF_PG_GENERAL;
741fee38f6tn	if (pg_get_or_add(inst, pgname, SCF_PG_GENERAL_TYPE,
742fee38f6tn	    SCF_PG_GENERAL_FLAGS, pg) != 0)
743fee38f6tn		goto eperm;
744fee38f6tn
745fee38f6tn	if (get_bool_prop(pg, SCF_PROPERTY_ENABLED, &b) != 0) {
746fee38f6tn		/* Create and set state to disabled */
74750c9b2fToomas Soome		switch (set_bool_prop(pg, SCF_PROPERTY_ENABLED, B_FALSE)) {
748fee38f6tn		case 0:
749fee38f6tn			break;
750fee38f6tn
751fee38f6tn		case EPERM:
752fee38f6tn			goto eperm;
753fee38f6tn
754fee38f6tn		case EROFS:
755fee38f6tn			/* Shouldn't happen, but it can. */
756fee38f6tn			if (!verbose)
757fee38f6tn				uu_warn(gettext("%s: Repository read-only.\n"),
758fee38f6tn				    fmri);
759fee38f6tn			else
760fee38f6tn				uu_warn(gettext("%s: Could not set %s/%s "
761fee38f6tn				    "(repository read-only).\n"), fmri,
762fee38f6tn				    SCF_PG_GENERAL, SCF_PROPERTY_ENABLED);
763fee38f6tn			goto out;
764fee38f6tn
765fee38f6tn		default:
766fee38f6tn			assert(0);
767fee38f6tn			abort();
768fee38f6tn		}
769fee38f6tn	}
770fee38f6tn
7718fff788John Levon	if (ed->ed_flags & SET_TEMPORARY) {
7727c478bdstevel@tonic-gate		pgname = SCF_PG_GENERAL_OVR;
7737c478bdstevel@tonic-gate		if (pg_get_or_add(inst, pgname, SCF_PG_GENERAL_OVR_TYPE,
7747c478bdstevel@tonic-gate		    SCF_PG_GENERAL_OVR_FLAGS, pg) != 0)
7757c478bdstevel@tonic-gate			goto eperm;
7767c478bdstevel@tonic-gate
7778fff788John Levon		switch (set_enabled_props(pg, ed)) {
7787c478bdstevel@tonic-gate		case 0:
7797c478bdstevel@tonic-gate			break;
7807c478bdstevel@tonic-gate
7817c478bdstevel@tonic-gate		case EPERM:
7827c478bdstevel@tonic-gate			goto eperm;
7837c478bdstevel@tonic-gate
7847c478bdstevel@tonic-gate		case EROFS:
7857c478bdstevel@tonic-gate			/* Shouldn't happen, but it can. */
7867c478bdstevel@tonic-gate			if (!verbose)
7877c478bdstevel@tonic-gate				uu_warn(gettext("%s: Repository read-only.\n"),
7887c478bdstevel@tonic-gate				    fmri);
7897c478bdstevel@tonic-gate			else
7907c478bdstevel@tonic-gate				uu_warn(gettext("%s: Could not set %s/%s "
7917c478bdstevel@tonic-gate				    "(repository read-only).\n"), fmri,
7927c478bdstevel@tonic-gate				    SCF_PG_GENERAL_OVR, SCF_PROPERTY_ENABLED);
7937c478bdstevel@tonic-gate			goto out;
7947c478bdstevel@tonic-gate
7957c478bdstevel@tonic-gate		default:
7967c478bdstevel@tonic-gate			assert(0);
7977c478bdstevel@tonic-gate			abort();
7987c478bdstevel@tonic-gate		}
7997c478bdstevel@tonic-gate
8007c478bdstevel@tonic-gate		if (verbose)
8018fff788John Levon			(void) printf((ed->ed_flags & SET_ENABLED) ?
8027c478bdstevel@tonic-gate			    gettext("%s temporarily enabled.\n") :
8037c478bdstevel@tonic-gate			    gettext("%s temporarily disabled.\n"), fmri);
8047c478bdstevel@tonic-gate	} else {
8057c478bdstevel@tonic-gateagain:
806fee38f6tn		/*
807fee38f6tn		 * Both pg and property should exist since we created
808fee38f6tn		 * them earlier. However, there's still a chance that
809fee38f6tn		 * someone may have deleted the property out from under
810fee38f6tn		 * us.
811fee38f6tn		 */
8127c478bdstevel@tonic-gate		if (pg_get_or_add(inst, pgname, SCF_PG_GENERAL_TYPE,
8137c478bdstevel@tonic-gate		    SCF_PG_GENERAL_FLAGS, pg) != 0)
8147c478bdstevel@tonic-gate			goto eperm;
8157c478bdstevel@tonic-gate
8168fff788John Levon		switch (set_enabled_props(pg, ed)) {
8177c478bdstevel@tonic-gate		case 0:
8187c478bdstevel@tonic-gate			break;
8197c478bdstevel@tonic-gate
8207c478bdstevel@tonic-gate		case EPERM:
8217c478bdstevel@tonic-gate			goto eperm;
8227c478bdstevel@tonic-gate
8237c478bdstevel@tonic-gate		case EROFS:
8247c478bdstevel@tonic-gate			/*
8257c478bdstevel@tonic-gate			 * If general/enabled is already set the way we want,
8267c478bdstevel@tonic-gate			 * proceed.
8277c478bdstevel@tonic-gate			 */
8287c478bdstevel@tonic-gate			switch (get_bool_prop(pg, SCF_PROPERTY_ENABLED, &b)) {
8297c478bdstevel@tonic-gate			case 0:
8308fff788John Levon				if (!(b) == !(ed->ed_flags & SET_ENABLED))
8317c478bdstevel@tonic-gate					break;
8327c478bdstevel@tonic-gate				/* FALLTHROUGH */
8337c478bdstevel@tonic-gate
8347c478bdstevel@tonic-gate			case ENOENT:
8357c478bdstevel@tonic-gate			case EINVAL:
8367c478bdstevel@tonic-gate			case E2BIG:
8377c478bdstevel@tonic-gate				if (!verbose)
8387c478bdstevel@tonic-gate					uu_warn(gettext("%s: Repository "
8397c478bdstevel@tonic-gate					    "read-only.\n"), fmri);
8407c478bdstevel@tonic-gate				else
8417c478bdstevel@tonic-gate					uu_warn(gettext("%s: Could not set "
8427c478bdstevel@tonic-gate					    "%s/%s (repository read-only).\n"),
8437c478bdstevel@tonic-gate					    fmri, SCF_PG_GENERAL,
8447c478bdstevel@tonic-gate					    SCF_PROPERTY_ENABLED);
8457c478bdstevel@tonic-gate				goto out;
8467c478bdstevel@tonic-gate
8477c478bdstevel@tonic-gate			case ECANCELED:
8487c478bdstevel@tonic-gate				goto again;
8497c478bdstevel@tonic-gate
8507c478bdstevel@tonic-gate			default:
8517c478bdstevel@tonic-gate				assert(0);
8527c478bdstevel@tonic-gate				abort();
8537c478bdstevel@tonic-gate			}
8547c478bdstevel@tonic-gate			break;
8557c478bdstevel@tonic-gate
8567c478bdstevel@tonic-gate		default:
8577c478bdstevel@tonic-gate			assert(0);
8587c478bdstevel@tonic-gate			abort();
8597c478bdstevel@tonic-gate		}
8607c478bdstevel@tonic-gate
8618fff788John Levon		switch (delete_prop(fmri, inst, SCF_PG_GENERAL_OVR,
8628fff788John Levon		    SCF_PROPERTY_ENABLED)) {
863eb1a346Truong Nguyen		case 0:
864eb1a346Truong Nguyen			break;
8657c478bdstevel@tonic-gate
866eb1a346Truong Nguyen		case EPERM:
867eb1a346Truong Nguyen			goto eperm;
8687c478bdstevel@tonic-gate
8698fff788John Levon		default:
870eb1a346Truong Nguyen			goto out;
8718fff788John Levon		}
8727c478bdstevel@tonic-gate
8738fff788John Levon		switch (delete_prop(fmri, inst, SCF_PG_GENERAL_OVR,
8748fff788John Levon		    SCF_PROPERTY_COMMENT)) {
8758fff788John Levon		case 0:
8768fff788John Levon			break;
8778fff788John Levon
8788fff788John Levon		case EPERM:
8798fff788John Levon			goto eperm;
8807c478bdstevel@tonic-gate
881eb1a346Truong Nguyen		default:
8828fff788John Levon			goto out;
8837c478bdstevel@tonic-gate		}
8847c478bdstevel@tonic-gate
8858fff788John Levon		if (verbose) {
8868fff788John Levon			(void) printf((ed->ed_flags & SET_ENABLED) ?
8878fff788John Levon			    gettext("%s enabled.\n") :
8887c478bdstevel@tonic-gate			    gettext("%s disabled.\n"), fmri);
8898fff788John Levon		}
8907c478bdstevel@tonic-gate	}
8917c478bdstevel@tonic-gate
8927c478bdstevel@tonic-gate	scf_pg_destroy(pg);
8937c478bdstevel@tonic-gate	return;
8947c478bdstevel@tonic-gate
8957c478bdstevel@tonic-gateeperm:
8967c478bdstevel@tonic-gate	assert(pgname != NULL);
8977c478bdstevel@tonic-gate	if (!verbose)
8987c478bdstevel@tonic-gate		uu_warn(emsg_permission_denied, fmri);
8997c478bdstevel@tonic-gate	else
9007c478bdstevel@tonic-gate		uu_warn(emsg_pg_perm_denied, fmri, pgname);
9017c478bdstevel@tonic-gate
9027c478bdstevel@tonic-gateout:
9037c478bdstevel@tonic-gate	scf_pg_destroy(pg);
9047c478bdstevel@tonic-gate	exit_status = 1;
9057c478bdstevel@tonic-gate}
9067c478bdstevel@tonic-gate
9077c478bdstevel@tonic-gate/*
9087c478bdstevel@tonic-gate * Set inst to the instance which corresponds to fmri.  If fmri identifies
9097c478bdstevel@tonic-gate * a service with a single instance, get that instance.
9107c478bdstevel@tonic-gate *
9117c478bdstevel@tonic-gate * Fails with
9127c478bdstevel@tonic-gate *   ENOTSUP - fmri has an unsupported scheme
9137c478bdstevel@tonic-gate *   EINVAL - fmri is invalid
9147c478bdstevel@tonic-gate *   ENOTDIR - fmri does not identify a service or instance
9157c478bdstevel@tonic-gate *   ENOENT - could not locate instance
9167c478bdstevel@tonic-gate *   E2BIG - fmri is a service with multiple instances (warning not printed)
9177c478bdstevel@tonic-gate */
9187c478bdstevel@tonic-gatestatic int
9197c478bdstevel@tonic-gateget_inst_mult(const char *fmri, scf_instance_t *inst)
9207c478bdstevel@tonic-gate{
9217c478bdstevel@tonic-gate	char *cfmri;
9227c478bdstevel@tonic-gate	const char *svc_name, *inst_name, *pg_name;
9237c478bdstevel@tonic-gate	scf_service_t *svc;
9247c478bdstevel@tonic-gate	scf_instance_t *inst2;
9257c478bdstevel@tonic-gate	scf_iter_t *iter;
9267c478bdstevel@tonic-gate	int ret;
9277c478bdstevel@tonic-gate
9287c478bdstevel@tonic-gate	if (strncmp(fmri, "lrc:", sizeof ("lrc:") - 1) == 0) {
9297c478bdstevel@tonic-gate		uu_warn(gettext("FMRI \"%s\" is a legacy service.\n"), fmri);
9307c478bdstevel@tonic-gate		exit_status = 1;
9317c478bdstevel@tonic-gate		return (ENOTSUP);
9327c478bdstevel@tonic-gate	}
9337c478bdstevel@tonic-gate
9347c478bdstevel@tonic-gate	cfmri = strdup(fmri);
9357c478bdstevel@tonic-gate	if (cfmri == NULL)
9367c478bdstevel@tonic-gate		uu_die(emsg_nomem);
9377c478bdstevel@tonic-gate
9387c478bdstevel@tonic-gate	if (scf_parse_svc_fmri(cfmri, NULL, &svc_name, &inst_name, &pg_name,
9397c478bdstevel@tonic-gate	    NULL) != SCF_SUCCESS) {
9407c478bdstevel@tonic-gate		free(cfmri);
9417c478bdstevel@tonic-gate		uu_warn(gettext("FMRI \"%s\" is invalid.\n"), fmri);
9427c478bdstevel@tonic-gate		exit_status = 1;
9437c478bdstevel@tonic-gate		return (EINVAL);
9447c478bdstevel@tonic-gate	}
9457c478bdstevel@tonic-gate
9467c478bdstevel@tonic-gate	free(cfmri);
9477c478bdstevel@tonic-gate
9487c478bdstevel@tonic-gate	if (svc_name == NULL || pg_name != NULL) {
9497c478bdstevel@tonic-gate		uu_warn(gettext(
9507c478bdstevel@tonic-gate		    "FMRI \"%s\" does not designate a service or instance.\n"),
9517c478bdstevel@tonic-gate		    fmri);
9527c478bdstevel@tonic-gate		exit_status = 1;
9537c478bdstevel@tonic-gate		return (ENOTDIR);
9547c478bdstevel@tonic-gate	}
9557c478bdstevel@tonic-gate
9567c478bdstevel@tonic-gate	if (inst_name != NULL) {
9577c478bdstevel@tonic-gate		if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
9587c478bdstevel@tonic-gate		    NULL, SCF_DECODE_FMRI_EXACT) == 0)
9597c478bdstevel@tonic-gate			return (0);
9607c478bdstevel@tonic-gate
9617c478bdstevel@tonic-gate		if (scf_error() != SCF_ERROR_NOT_FOUND)
9627c478bdstevel@tonic-gate			scfdie();
9637c478bdstevel@tonic-gate
9647c478bdstevel@tonic-gate		uu_warn(gettext("No such instance \"%s\".\n"), fmri);
9657c478bdstevel@tonic-gate		exit_status = 1;
9667c478bdstevel@tonic-gate
9677c478bdstevel@tonic-gate		return (ENOENT);
9687c478bdstevel@tonic-gate	}
9697c478bdstevel@tonic-gate
9707c478bdstevel@tonic-gate	if ((svc = scf_service_create(h)) == NULL ||
9717c478bdstevel@tonic-gate	    (inst2 = scf_instance_create(h)) == NULL ||
9727c478bdstevel@tonic-gate	    (iter = scf_iter_create(h)) == NULL)
9737c478bdstevel@tonic-gate		scfdie();
9747c478bdstevel@tonic-gate
9757c478bdstevel@tonic-gate	if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL,
9767c478bdstevel@tonic-gate	    SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
9777c478bdstevel@tonic-gate		if (scf_error() != SCF_ERROR_NOT_FOUND)
9787c478bdstevel@tonic-gate			scfdie();
9797c478bdstevel@tonic-gate
9807c478bdstevel@tonic-gate		uu_warn(emsg_no_service, fmri);
9817c478bdstevel@tonic-gate		exit_status = 1;
9827c478bdstevel@tonic-gate
9837c478bdstevel@tonic-gate		ret = ENOENT;
9847c478bdstevel@tonic-gate		goto out;
9857c478bdstevel@tonic-gate	}
9867c478bdstevel@tonic-gate
9877c478bdstevel@tonic-gate	/* If the service has only one child, use it. */
9887c478bdstevel@tonic-gate	if (scf_iter_service_instances(iter, svc) != SCF_SUCCESS)
9897c478bdstevel@tonic-gate		scfdie();
9907c478bdstevel@tonic-gate
9917c478bdstevel@tonic-gate	ret = scf_iter_next_instance(iter, inst);
9927c478bdstevel@tonic-gate	if (ret < 0)
9937c478bdstevel@tonic-gate		scfdie();
9947c478bdstevel@tonic-gate	if (ret != 1) {
9957c478bdstevel@tonic-gate		uu_warn(gettext("Service \"%s\" has no instances.\n"),
9967c478bdstevel@tonic-gate		    fmri);
9977c478bdstevel@tonic-gate		exit_status = 1;
9987c478bdstevel@tonic-gate		ret = ENOENT;
9997c478bdstevel@tonic-gate		goto out;
10007c478bdstevel@tonic-gate	}
10017c478bdstevel@tonic-gate
10027c478bdstevel@tonic-gate	ret = scf_iter_next_instance(iter, inst2);
10037c478bdstevel@tonic-gate	if (ret < 0)
10047c478bdstevel@tonic-gate		scfdie();
10057c478bdstevel@tonic-gate
10067c478bdstevel@tonic-gate	if (ret != 0) {
10077c478bdstevel@tonic-gate		ret = E2BIG;
10087c478bdstevel@tonic-gate		goto out;
10097c478bdstevel@tonic-gate	}
10107c478bdstevel@tonic-gate
10117c478bdstevel@tonic-gate	ret = 0;
10127c478bdstevel@tonic-gate
10137c478bdstevel@tonic-gateout:
10147c478bdstevel@tonic-gate	scf_iter_destroy(iter);
10157c478bdstevel@tonic-gate	scf_instance_destroy(inst2);
10167c478bdstevel@tonic-gate	scf_service_destroy(svc);
10177c478bdstevel@tonic-gate	return (ret);
10187c478bdstevel@tonic-gate}
10197c478bdstevel@tonic-gate
10207c478bdstevel@tonic-gate/*
10217c478bdstevel@tonic-gate * Same as get_inst_mult(), but on E2BIG prints a warning and returns ENOENT.
10227c478bdstevel@tonic-gate */
10237c478bdstevel@tonic-gatestatic int
10247c478bdstevel@tonic-gateget_inst(const char *fmri, scf_instance_t *inst)
10257c478bdstevel@tonic-gate{
10267c478bdstevel@tonic-gate	int r;
10277c478bdstevel@tonic-gate
10287c478bdstevel@tonic-gate	r = get_inst_mult(fmri, inst);
10297c478bdstevel@tonic-gate	if (r != E2BIG)
10307c478bdstevel@tonic-gate		return (r);
10317c478bdstevel@tonic-gate
10327c478bdstevel@tonic-gate	uu_warn(gettext("operation on service %s is ambiguous; "
10337c478bdstevel@tonic-gate	    "instance specification needed.\n"), fmri);
10347c478bdstevel@tonic-gate	return (ENOENT);
10357c478bdstevel@tonic-gate}
10367c478bdstevel@tonic-gate
10377c478bdstevel@tonic-gatestatic char *
10387c478bdstevel@tonic-gateinst_get_fmri(const scf_instance_t *inst)
10397c478bdstevel@tonic-gate{
10407c478bdstevel@tonic-gate	ssize_t sz;
10417c478bdstevel@tonic-gate
10427c478bdstevel@tonic-gate	sz = scf_instance_to_fmri(inst, scratch_fmri, max_scf_fmri_sz);
10437c478bdstevel@tonic-gate	if (sz < 0)
10447c478bdstevel@tonic-gate		scfdie();
10457c478bdstevel@tonic-gate	if (sz >= max_scf_fmri_sz)
10467c478bdstevel@tonic-gate		uu_die(gettext("scf_instance_to_fmri() returned unexpectedly "
10477c478bdstevel@tonic-gate		    "long value.\n"));
10487c478bdstevel@tonic-gate
10497c478bdstevel@tonic-gate	return (scratch_fmri);
10507c478bdstevel@tonic-gate}
10517c478bdstevel@tonic-gate
10527c478bdstevel@tonic-gatestatic ssize_t
10537c478bdstevel@tonic-gatedep_get_astring(const char *fmri, const char *pgname,
10547c478bdstevel@tonic-gate    const scf_propertygroup_t *pg, const char *propname, scf_property_t *prop,
10557c478bdstevel@tonic-gate    scf_value_t *v, char *buf, size_t bufsz)
10567c478bdstevel@tonic-gate{
10577c478bdstevel@tonic-gate	ssize_t sz;
10587c478bdstevel@tonic-gate
10597c478bdstevel@tonic-gate	sz = get_astring_prop(pg, propname, prop, v, buf, bufsz);
10607c478bdstevel@tonic-gate	if (sz >= 0)
10617c478bdstevel@tonic-gate		return (sz);
10627c478bdstevel@tonic-gate
10637c478bdstevel@tonic-gate	switch (-sz) {
10647c478bdstevel@tonic-gate	case ENOENT:
10657c478bdstevel@tonic-gate		uu_warn(gettext("\"%s\" is misconfigured (\"%s\" dependency "
10667c478bdstevel@tonic-gate		    "lacks \"%s\" property.)\n"), fmri, pgname, propname);
10677c478bdstevel@tonic-gate		return (-1);
10687c478bdstevel@tonic-gate
10697c478bdstevel@tonic-gate	case E2BIG:
10707c478bdstevel@tonic-gate		uu_warn(gettext("\"%s\" is misconfigured (\"%s/%s\" property "
10717c478bdstevel@tonic-gate		    "is not single-valued.)\n"), fmri, pgname, propname);
10727c478bdstevel@tonic-gate		return (-1);
10737c478bdstevel@tonic-gate
10747c478bdstevel@tonic-gate	case EINVAL:
10757c478bdstevel@tonic-gate		uu_warn(gettext("\"%s\" is misconfigured (\"%s/%s\" property "
10767c478bdstevel@tonic-gate		    "is not of astring type.)\n"), fmri, pgname, propname);
10777c478bdstevel@tonic-gate		return (-1);
10787c478bdstevel@tonic-gate
10797c478bdstevel@tonic-gate	default:
10807c478bdstevel@tonic-gate		assert(0);
10817c478bdstevel@tonic-gate		abort();
10827c478bdstevel@tonic-gate		/* NOTREACHED */
10837c478bdstevel@tonic-gate	}
10847c478bdstevel@tonic-gate}
10857c478bdstevel@tonic-gate
10867c478bdstevel@tonic-gatestatic boolean_t
10877c478bdstevel@tonic-gatemultiple_instances(scf_iter_t *iter, scf_value_t *v, char *buf)
10887c478bdstevel@tonic-gate{
10897c478bdstevel@tonic-gate	int count = 0, r;
10907c478bdstevel@tonic-gate	boolean_t ret;
10917c478bdstevel@tonic-gate	scf_instance_t *inst;
10927c478bdstevel@tonic-gate
10937c478bdstevel@tonic-gate	inst = scf_instance_create(h);
10947c478bdstevel@tonic-gate	if (inst == NULL)
10957c478bdstevel@tonic-gate		scfdie();
10967c478bdstevel@tonic-gate
10977c478bdstevel@tonic-gate	for (;;) {
10987c478bdstevel@tonic-gate		r = scf_iter_next_value(iter, v);
10997c478bdstevel@tonic-gate		if (r == 0) {
11007c478bdstevel@tonic-gate			ret = B_FALSE;
11017c478bdstevel@tonic-gate			goto out;
11027c478bdstevel@tonic-gate		}
11037c478bdstevel@tonic-gate		if (r != 1)
11047c478bdstevel@tonic-gate			scfdie();
11057c478bdstevel@tonic-gate
11067c478bdstevel@tonic-gate		if (scf_value_get_astring(v, buf, max_scf_fmri_sz) < 0)
11077c478bdstevel@tonic-gate			scfdie();
11087c478bdstevel@tonic-gate
11097c478bdstevel@tonic-gate		switch (get_inst_mult(buf, inst)) {
11107c478bdstevel@tonic-gate		case 0:
11117c478bdstevel@tonic-gate			++count;
11127c478bdstevel@tonic-gate			if (count > 1) {
11137c478bdstevel@tonic-gate				ret = B_TRUE;
11147c478bdstevel@tonic-gate				goto out;
11157c478bdstevel@tonic-gate			}
11167c478bdstevel@tonic-gate			break;
11177c478bdstevel@tonic-gate
11187c478bdstevel@tonic-gate		case ENOTSUP:
11197c478bdstevel@tonic-gate		case EINVAL:
11207c478bdstevel@tonic-gate		case ENOTDIR:
11217c478bdstevel@tonic-gate		case ENOENT:
11227c478bdstevel@tonic-gate			continue;
11237c478bdstevel@tonic-gate
11247c478bdstevel@tonic-gate		case E2BIG:
11257c478bdstevel@tonic-gate			ret = B_TRUE;
11267c478bdstevel@tonic-gate			goto out;
11277c478bdstevel@tonic-gate
11287c478bdstevel@tonic-gate		default:
11297c478bdstevel@tonic-gate			assert(0);
11307c478bdstevel@tonic-gate			abort();
11317c478bdstevel@tonic-gate		}
11327c478bdstevel@tonic-gate	}
11337c478bdstevel@tonic-gate
11347c478bdstevel@tonic-gateout:
11357c478bdstevel@tonic-gate	scf_instance_destroy(inst);
11367c478bdstevel@tonic-gate	return (ret);
11377c478bdstevel@tonic-gate}
11387c478bdstevel@tonic-gate
11397c478bdstevel@tonic-gate/*
11407c478bdstevel@tonic-gate * Enable the service or instance identified by fmri and its dependencies,
11417c478bdstevel@tonic-gate * recursively.  Specifically, call get_inst(fmri), enable the result, and
11427c478bdstevel@tonic-gate * recurse on its restarter and the dependencies.  To avoid duplication of
11437c478bdstevel@tonic-gate * effort or looping around a dependency cycle, each FMRI is entered into the
11447c478bdstevel@tonic-gate * "visited" hash table.  While recursing, the hash table entry is marked
11457c478bdstevel@tonic-gate * "active", so that if we come upon it again, we know we've hit a cycle.
11467c478bdstevel@tonic-gate * exclude_all and optional_all dependencies are ignored.  require_any
11477c478bdstevel@tonic-gate * dependencies are followed only if they comprise a single service; otherwise
11487c478bdstevel@tonic-gate * the user is warned.
11497c478bdstevel@tonic-gate *
11507c478bdstevel@tonic-gate * fmri must point to a writable max_scf_fmri_sz buffer.  Returns EINVAL if fmri
11517c478bdstevel@tonic-gate * is invalid, E2BIG if fmri identifies a service with multiple instances, ELOOP
11527c478bdstevel@tonic-gate * on cycle detection, or 0 on success.
11537c478bdstevel@tonic-gate */
11547c478bdstevel@tonic-gatestatic int
11558fff788John Levonenable_fmri_rec(char *fmri, enable_data_t *ed)
11567c478bdstevel@tonic-gate{
11577c478bdstevel@tonic-gate	scf_instance_t *inst;
11587c478bdstevel@tonic-gate	scf_snapshot_t *snap;
11597c478bdstevel@tonic-gate	scf_propertygroup_t *pg;
11607c478bdstevel@tonic-gate	scf_property_t *prop;
11617c478bdstevel@tonic-gate	scf_value_t *v;
11627c478bdstevel@tonic-gate	scf_iter_t *pg_iter, *val_iter;
11637c478bdstevel@tonic-gate	scf_type_t ty;
11647c478bdstevel@tonic-gate	char *buf, *pgname;
11657c478bdstevel@tonic-gate	ssize_t name_sz, len, sz;
11667c478bdstevel@tonic-gate	int ret;
11677c478bdstevel@tonic-gate	struct ht_elt *he;
11687c478bdstevel@tonic-gate
11697c478bdstevel@tonic-gate	len = scf_canonify_fmri(fmri, fmri, max_scf_fmri_sz);
11707c478bdstevel@tonic-gate	if (len < 0) {
11717c478bdstevel@tonic-gate		assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT);
11727c478bdstevel@tonic-gate		return (EINVAL);
11737c478bdstevel@tonic-gate	}
11747c478bdstevel@tonic-gate	assert(len < max_scf_fmri_sz);
11757c478bdstevel@tonic-gate
11767c478bdstevel@tonic-gate	switch (visited_find_or_add(fmri, &he)) {
11777c478bdstevel@tonic-gate	case 0:
11787c478bdstevel@tonic-gate		he->active = B_TRUE;
11797c478bdstevel@tonic-gate		break;
11807c478bdstevel@tonic-gate
11817c478bdstevel@tonic-gate	case 1:
11827c478bdstevel@tonic-gate		return (he->active ? ELOOP : 0);
11837c478bdstevel@tonic-gate
11847c478bdstevel@tonic-gate	case -1:
11857c478bdstevel@tonic-gate		uu_die(emsg_nomem);
11867c478bdstevel@tonic-gate
11877c478bdstevel@tonic-gate	default:
11887c478bdstevel@tonic-gate		assert(0);
11897c478bdstevel@tonic-gate		abort();
11907c478bdstevel@tonic-gate	}
11917c478bdstevel@tonic-gate
11927c478bdstevel@tonic-gate	inst = scf_instance_create(h);
11937c478bdstevel@tonic-gate	if (inst == NULL)
11947c478bdstevel@tonic-gate		scfdie();
11957c478bdstevel@tonic-gate
11967c478bdstevel@tonic-gate	switch (get_inst_mult(fmri, inst)) {
11977c478bdstevel@tonic-gate	case 0:
11987c478bdstevel@tonic-gate		break;
11997c478bdstevel@tonic-gate
12007c478bdstevel@tonic-gate	case E2BIG:
12017c478bdstevel@tonic-gate		he->active = B_FALSE;
12027c478bdstevel@tonic-gate		return (E2BIG);
12037c478bdstevel@tonic-gate
12047c478bdstevel@tonic-gate	default:
12057c478bdstevel@tonic-gate		he->active = B_FALSE;
12067c478bdstevel@tonic-gate		return (0);
12077c478bdstevel@tonic-gate	}
12087c478bdstevel@tonic-gate
12098fff788John Levon	set_inst_enabled(fmri, inst, ed);
12107c478bdstevel@tonic-gate
12117c478bdstevel@tonic-gate	if ((snap = scf_snapshot_create(h)) == NULL ||
12127c478bdstevel@tonic-gate	    (pg = scf_pg_create(h)) == NULL ||
12137c478bdstevel@tonic-gate	    (prop = scf_property_create(h)) == NULL ||
12147c478bdstevel@tonic-gate	    (v = scf_value_create(h)) == NULL ||
12157c478bdstevel@tonic-gate	    (pg_iter = scf_iter_create(h)) == NULL ||
12167c478bdstevel@tonic-gate	    (val_iter = scf_iter_create(h)) == NULL)
12177c478bdstevel@tonic-gate		scfdie();
12187c478bdstevel@tonic-gate
12197c478bdstevel@tonic-gate	buf = malloc(max_scf_fmri_sz);
12207c478bdstevel@tonic-gate	if (buf == NULL)
12217c478bdstevel@tonic-gate		uu_die(emsg_nomem);
12227c478bdstevel@tonic-gate
12237c478bdstevel@tonic-gate	name_sz = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH);
12247c478bdstevel@tonic-gate	if (name_sz < 0)
12257c478bdstevel@tonic-gate		scfdie();
12267c478bdstevel@tonic-gate	++name_sz;
12277c478bdstevel@tonic-gate	pgname = malloc(name_sz);
12287c478bdstevel@tonic-gate	if (pgname == NULL)
12297c478bdstevel@tonic-gate		uu_die(emsg_nomem);
12307c478bdstevel@tonic-gate
12317c478bdstevel@tonic-gate	if (scf_instance_get_snapshot(inst, "running", snap) != 0) {
12327c478bdstevel@tonic-gate		if (scf_error() != SCF_ERROR_NOT_FOUND)
12337c478bdstevel@tonic-gate			scfdie();
12347c478bdstevel@tonic-gate
12357c478bdstevel@tonic-gate		scf_snapshot_destroy(snap);
12367c478bdstevel@tonic-gate		snap = NULL;
12377c478bdstevel@tonic-gate	}
12387c478bdstevel@tonic-gate
12397c478bdstevel@tonic-gate	/* Enable restarter */
12407c478bdstevel@tonic-gate	if (scf_instance_get_pg_composed(inst, snap, SCF_PG_GENERAL, pg) != 0) {
12417c478bdstevel@tonic-gate		if (scf_error() != SCF_ERROR_NOT_FOUND)
12427c478bdstevel@tonic-gate			scfdie();
12437c478bdstevel@tonic-gate
12447c478bdstevel@tonic-gate		uu_warn(gettext("\"%s\" is misconfigured (lacks \"%s\" "
12457c478bdstevel@tonic-gate		    "property group).\n"), fmri, SCF_PG_GENERAL);
12467c478bdstevel@tonic-gate		ret = 0;
12477c478bdstevel@tonic-gate		goto out;
12487c478bdstevel@tonic-gate	}
12497c478bdstevel@tonic-gate
12507c478bdstevel@tonic-gate	sz = get_astring_prop(pg, SCF_PROPERTY_RESTARTER, prop, v, buf,
12517c478bdstevel@tonic-gate	    max_scf_fmri_sz);
12527c478bdstevel@tonic-gate	if (sz > max_scf_fmri_sz) {
12537c478bdstevel@tonic-gate		uu_warn(gettext("\"%s\" is misconfigured (the value of "
12547c478bdstevel@tonic-gate		    "\"%s/%s\" is too long).\n"), fmri, SCF_PG_GENERAL,
12557c478bdstevel@tonic-gate		    SCF_PROPERTY_RESTARTER);
12567c478bdstevel@tonic-gate		ret = 0;
12577c478bdstevel@tonic-gate		goto out;
12587c478bdstevel@tonic-gate	} else if (sz >= 0) {
12598fff788John Levon		switch (enable_fmri_rec(buf, ed)) {
12607c478bdstevel@tonic-gate		case 0:
12617c478bdstevel@tonic-gate			break;
12627c478bdstevel@tonic-gate
12637c478bdstevel@tonic-gate		case EINVAL:
12647c478bdstevel@tonic-gate			uu_warn(gettext("Restarter FMRI for \"%s\" is "
12657c478bdstevel@tonic-gate			    "invalid.\n"), fmri);
12667c478bdstevel@tonic-gate			break;
12677c478bdstevel@tonic-gate
12687c478bdstevel@tonic-gate		case E2BIG:
12697c478bdstevel@tonic-gate			uu_warn(gettext("Restarter FMRI for \"%s\" identifies "
12707c478bdstevel@tonic-gate			    "a service with multiple instances.\n"), fmri);
12717c478bdstevel@tonic-gate			break;
12727c478bdstevel@tonic-gate
12737c478bdstevel@tonic-gate		case ELOOP:
12747c478bdstevel@tonic-gate			ret = ELOOP;
12757c478bdstevel@tonic-gate			goto out;
12767c478bdstevel@tonic-gate
12777c478bdstevel@tonic-gate		default:
12787c478bdstevel@tonic-gate			assert(0);
12797c478bdstevel@tonic-gate			abort();
12807c478bdstevel@tonic-gate		}
12817c478bdstevel@tonic-gate	} else if (sz < 0) {
12827c478bdstevel@tonic-gate		switch (-sz) {
12837c478bdstevel@tonic-gate		case ENOENT:
12847c478bdstevel@tonic-gate			break;
12857c478bdstevel@tonic-gate
12867c478bdstevel@tonic-gate		case E2BIG:
12877c478bdstevel@tonic-gate			uu_warn(gettext("\"%s\" is misconfigured (\"%s/%s\" "
12887c478bdstevel@tonic-gate			    "property is not single-valued).\n"), fmri,
12897c478bdstevel@tonic-gate			    SCF_PG_GENERAL, SCF_PROPERTY_RESTARTER);
12907c478bdstevel@tonic-gate			ret = 0;
12917c478bdstevel@tonic-gate			goto out;
12927c478bdstevel@tonic-gate
12937c478bdstevel@tonic-gate		case EINVAL:
12947c478bdstevel@tonic-gate			uu_warn(gettext("\"%s\" is misconfigured (\"%s/%s\" "
12957c478bdstevel@tonic-gate			    "property is not of astring type).\n"), fmri,
12967c478bdstevel@tonic-gate			    SCF_PG_GENERAL, SCF_PROPERTY_RESTARTER);
12977c478bdstevel@tonic-gate			ret = 0;
12987c478bdstevel@tonic-gate			goto out;
12997c478bdstevel@tonic-gate
13007c478bdstevel@tonic-gate		default:
13017c478bdstevel@tonic-gate			assert(0);
13027c478bdstevel@tonic-gate			abort();
13037c478bdstevel@tonic-gate		}
13047c478bdstevel@tonic-gate	}
13057c478bdstevel@tonic-gate
13067c478bdstevel@tonic-gate	if (scf_iter_instance_pgs_typed_composed(pg_iter, inst, snap,
13077c478bdstevel@tonic-gate	    SCF_GROUP_DEPENDENCY) == -1)
13087c478bdstevel@tonic-gate		scfdie();
13097c478bdstevel@tonic-gate
13107c478bdstevel@tonic-gate	while (scf_iter_next_pg(pg_iter, pg) > 0) {
13117c478bdstevel@tonic-gate		len = scf_pg_get_name(pg, pgname, name_sz);
13127c478bdstevel@tonic-gate		if (len < 0)
13137c478bdstevel@tonic-gate			scfdie();
13147c478bdstevel@tonic-gate		assert(len < name_sz);
13157c478bdstevel@tonic-gate
13167c478bdstevel@tonic-gate		if (dep_get_astring(fmri, pgname, pg, SCF_PROPERTY_TYPE, prop,
13177c478bdstevel@tonic-gate		    v, buf, max_scf_fmri_sz) < 0)
13187c478bdstevel@tonic-gate			continue;
13197c478bdstevel@tonic-gate
13207c478bdstevel@tonic-gate		if (strcmp(buf, "service") != 0)
13217c478bdstevel@tonic-gate			continue;
13227c478bdstevel@tonic-gate
13237c478bdstevel@tonic-gate		if (dep_get_astring(fmri, pgname, pg, SCF_PROPERTY_GROUPING,
13247c478bdstevel@tonic-gate		    prop, v, buf, max_scf_fmri_sz) < 0)
13257c478bdstevel@tonic-gate			continue;
13267c478bdstevel@tonic-gate
13277c478bdstevel@tonic-gate		if (strcmp(buf, SCF_DEP_EXCLUDE_ALL) == 0 ||
13287c478bdstevel@tonic-gate		    strcmp(buf, SCF_DEP_OPTIONAL_ALL) == 0)
13297c478bdstevel@tonic-gate			continue;
13307c478bdstevel@tonic-gate
13317c478bdstevel@tonic-gate		if (strcmp(buf, SCF_DEP_REQUIRE_ALL) != 0 &&
13327c478bdstevel@tonic-gate		    strcmp(buf, SCF_DEP_REQUIRE_ANY) != 0) {
13337c478bdstevel@tonic-gate			uu_warn(gettext("Dependency \"%s\" of \"%s\" has "
13347c478bdstevel@tonic-gate			    "unknown type \"%s\".\n"), pgname, fmri, buf);
13357c478bdstevel@tonic-gate			continue;
13367c478bdstevel@tonic-gate		}
13377c478bdstevel@tonic-gate
13387c478bdstevel@tonic-gate		if (scf_pg_get_property(pg, SCF_PROPERTY_ENTITIES, prop) ==
13397c478bdstevel@tonic-gate		    -1) {
13407c478bdstevel@tonic-gate			if (scf_error() != SCF_ERROR_NOT_FOUND)
13417c478bdstevel@tonic-gate				scfdie();
13427c478bdstevel@tonic-gate
13437c478bdstevel@tonic-gate			uu_warn(gettext("\"%s\" is misconfigured (\"%s\" "
13447c478bdstevel@tonic-gate			    "dependency lacks \"%s\" property.)\n"), fmri,
13457c478bdstevel@tonic-gate			    pgname, SCF_PROPERTY_ENTITIES);
13467c478bdstevel@tonic-gate			continue;
13477c478bdstevel@tonic-gate		}
13487c478bdstevel@tonic-gate
13497c478bdstevel@tonic-gate		if (scf_property_type(prop, &ty) != SCF_SUCCESS)
13507c478bdstevel@tonic-gate			scfdie();
13517c478bdstevel@tonic-gate
13527c478bdstevel@tonic-gate		if (ty != SCF_TYPE_FMRI) {
13537c478bdstevel@tonic-gate			uu_warn(gettext("\"%s\" is misconfigured (property "
13547c478bdstevel@tonic-gate			    "\"%s/%s\" is not of fmri type).\n"), fmri, pgname,
13557c478bdstevel@tonic-gate			    SCF_PROPERTY_ENTITIES);
13567c478bdstevel@tonic-gate			continue;
13577c478bdstevel@tonic-gate		}
13587c478bdstevel@tonic-gate
13597c478bdstevel@tonic-gate		if (scf_iter_property_values(val_iter, prop) == -1)
13607c478bdstevel@tonic-gate			scfdie();
13617c478bdstevel@tonic-gate
13627c478bdstevel@tonic-gate		if (strcmp(buf, SCF_DEP_REQUIRE_ANY) == 0) {
13637c478bdstevel@tonic-gate			if (multiple_instances(val_iter, v, buf)) {
13647c478bdstevel@tonic-gate				(void) printf(gettext("%s requires one of:\n"),
13657c478bdstevel@tonic-gate				    fmri);
13667c478bdstevel@tonic-gate
13677c478bdstevel@tonic-gate				if (scf_iter_property_values(val_iter, prop) !=
13687c478bdstevel@tonic-gate				    0)
13697c478bdstevel@tonic-gate					scfdie();
13707c478bdstevel@tonic-gate
13717c478bdstevel@tonic-gate				for (;;) {
13727c478bdstevel@tonic-gate					int r;
13737c478bdstevel@tonic-gate
13747c478bdstevel@tonic-gate					r = scf_iter_next_value(val_iter, v);
13757c478bdstevel@tonic-gate					if (r == 0)
13767c478bdstevel@tonic-gate						break;
13777c478bdstevel@tonic-gate					if (r != 1)
13787c478bdstevel@tonic-gate						scfdie();
13797c478bdstevel@tonic-gate
13807c478bdstevel@tonic-gate					if (scf_value_get_astring(v, buf,
13817c478bdstevel@tonic-gate					    max_scf_fmri_sz) < 0)
13827c478bdstevel@tonic-gate						scfdie();
13837c478bdstevel@tonic-gate
13847c478bdstevel@tonic-gate					(void) fputs("  ", stdout);
13857c478bdstevel@tonic-gate					(void) puts(buf);
13867c478bdstevel@tonic-gate				}
13877c478bdstevel@tonic-gate
13887c478bdstevel@tonic-gate				continue;
13897c478bdstevel@tonic-gate			}
13907c478bdstevel@tonic-gate
13917c478bdstevel@tonic-gate			/*
13927c478bdstevel@tonic-gate			 * Since there's only one instance, we can enable it.
13937c478bdstevel@tonic-gate			 * Reset val_iter and continue.
13947c478bdstevel@tonic-gate			 */
13957c478bdstevel@tonic-gate			if (scf_iter_property_values(val_iter, prop) != 0)
13967c478bdstevel@tonic-gate				scfdie();
13977c478bdstevel@tonic-gate		}
13987c478bdstevel@tonic-gate
13997c478bdstevel@tonic-gate		for (;;) {
14007c478bdstevel@tonic-gate			ret = scf_iter_next_value(val_iter, v);
14017c478bdstevel@tonic-gate			if (ret == 0)
14027c478bdstevel@tonic-gate				break;
14037c478bdstevel@tonic-gate			if (ret != 1)
14047c478bdstevel@tonic-gate				scfdie();
14057c478bdstevel@tonic-gate
14067c478bdstevel@tonic-gate			if (scf_value_get_astring(v, buf, max_scf_fmri_sz) ==
14077c478bdstevel@tonic-gate			    -1)
14087c478bdstevel@tonic-gate				scfdie();
14097c478bdstevel@tonic-gate
14108fff788John Levon			switch (enable_fmri_rec(buf, ed)) {
14117c478bdstevel@tonic-gate			case 0:
14127c478bdstevel@tonic-gate				break;
14137c478bdstevel@tonic-gate
14147c478bdstevel@tonic-gate			case EINVAL:
14157c478bdstevel@tonic-gate				uu_warn(gettext("\"%s\" dependency of \"%s\" "
14167c478bdstevel@tonic-gate				    "has invalid FMRI \"%s\".\n"), pgname,
14177c478bdstevel@tonic-gate				    fmri, buf);
14187c478bdstevel@tonic-gate				break;
14197c478bdstevel@tonic-gate
14207c478bdstevel@tonic-gate			case E2BIG:
14217c478bdstevel@tonic-gate				uu_warn(gettext("%s depends on %s, which has "
14227c478bdstevel@tonic-gate				    "multiple instances.\n"), fmri, buf);
14237c478bdstevel@tonic-gate				break;
14247c478bdstevel@tonic-gate
14257c478bdstevel@tonic-gate			case ELOOP:
14267c478bdstevel@tonic-gate				ret = ELOOP;
14277c478bdstevel@tonic-gate				goto out;
14287c478bdstevel@tonic-gate
14297c478bdstevel@tonic-gate			default:
14307c478bdstevel@tonic-gate				assert(0);
14317c478bdstevel@tonic-gate				abort();
14327c478bdstevel@tonic-gate			}
14337c478bdstevel@tonic-gate		}
14347c478bdstevel@tonic-gate	}
14357c478bdstevel@tonic-gate
14367c478bdstevel@tonic-gate	ret = 0;
14377c478bdstevel@tonic-gate
14387c478bdstevel@tonic-gateout:
14397c478bdstevel@tonic-gate	he->active = B_FALSE;
14407c478bdstevel@tonic-gate
14417c478bdstevel@tonic-gate	free(buf);
14427c478bdstevel@tonic-gate	free(pgname);
14437c478bdstevel@tonic-gate
14447c478bdstevel@tonic-gate	(void) scf_value_destroy(v);
14457c478bdstevel@tonic-gate	scf_property_destroy(prop);
14467c478bdstevel@tonic-gate	scf_pg_destroy(pg);
14477c478bdstevel@tonic-gate	scf_snapshot_destroy(snap);
14487c478bdstevel@tonic-gate	scf_iter_destroy(pg_iter);
14497c478bdstevel@tonic-gate	scf_iter_destroy(val_iter);
14507c478bdstevel@tonic-gate
14517c478bdstevel@tonic-gate	return (ret);
14527c478bdstevel@tonic-gate}
14537c478bdstevel@tonic-gate
14547c478bdstevel@tonic-gate/*
14557c478bdstevel@tonic-gate * fmri here is only used for verbose messages.
14567c478bdstevel@tonic-gate */
14577c478bdstevel@tonic-gatestatic void
14587c478bdstevel@tonic-gateset_inst_action(const char *fmri, const scf_instance_t *inst,
14597c478bdstevel@tonic-gate    const char *action)
14607c478bdstevel@tonic-gate{
14617c478bdstevel@tonic-gate	scf_transaction_t *tx;
14627c478bdstevel@tonic-gate	scf_transaction_entry_t *ent;
14637c478bdstevel@tonic-gate	scf_propertygroup_t *pg;
14647c478bdstevel@tonic-gate	scf_property_t *prop;
14657c478bdstevel@tonic-gate	scf_value_t *v;
14667c478bdstevel@tonic-gate	int ret;
14677c478bdstevel@tonic-gate	int64_t t;
14687c478bdstevel@tonic-gate	hrtime_t timestamp;
14697c478bdstevel@tonic-gate
14707c478bdstevel@tonic-gate	const char * const scf_pg_restarter_actions = SCF_PG_RESTARTER_ACTIONS;
14717c478bdstevel@tonic-gate
14727c478bdstevel@tonic-gate	if ((pg = scf_pg_create(h)) == NULL ||
14737c478bdstevel@tonic-gate	    (prop = scf_property_create(h)) == NULL ||
14747c478bdstevel@tonic-gate	    (v = scf_value_create(h)) == NULL ||
14757c478bdstevel@tonic-gate	    (tx = scf_transaction_create(h)) == NULL ||
14767c478bdstevel@tonic-gate	    (ent = scf_entry_create(h)) == NULL)
14777c478bdstevel@tonic-gate		scfdie();
14787c478bdstevel@tonic-gate
1479a97d4a1Dave Eddy	if (restarter_setup(fmri, inst)) {
1480a97d4a1Dave Eddy		exit_status = 1;
1481e8f5b3fTruong Nguyen		goto out;
1482a97d4a1Dave Eddy	}
1483eb1a346Truong Nguyen
14847c478bdstevel@tonic-gate	if (scf_instance_get_pg(inst, scf_pg_restarter_actions, pg) == -1) {
14857c478bdstevel@tonic-gate		if (scf_error() != SCF_ERROR_NOT_FOUND)
14867c478bdstevel@tonic-gate			scfdie();
14877c478bdstevel@tonic-gate
14887c478bdstevel@tonic-gate		/* Try creating the restarter_actions property group. */
14897c478bdstevel@tonic-gate		if (scf_instance_add_pg(inst, scf_pg_restarter_actions,
14907c478bdstevel@tonic-gate		    SCF_PG_RESTARTER_ACTIONS_TYPE,
14917c478bdstevel@tonic-gate		    SCF_PG_RESTARTER_ACTIONS_FLAGS, pg) == -1) {
14927c478bdstevel@tonic-gate			switch (scf_error()) {
14937c478bdstevel@tonic-gate			case SCF_ERROR_EXISTS:
14947c478bdstevel@tonic-gate				/* Someone must have added it. */
14957c478bdstevel@tonic-gate				break;
14967c478bdstevel@tonic-gate
14977c478bdstevel@tonic-gate			case SCF_ERROR_PERMISSION_DENIED:
14987c478bdstevel@tonic-gate				if (!verbose)
14997c478bdstevel@tonic-gate					uu_warn(emsg_permission_denied, fmri);
15007c478bdstevel@tonic-gate				else
15017c478bdstevel@tonic-gate					uu_warn(emsg_create_pg_perm_denied,
15027c478bdstevel@tonic-gate					    fmri, scf_pg_restarter_actions);
15037c478bdstevel@tonic-gate				goto out;
15047c478bdstevel@tonic-gate
15057c478bdstevel@tonic-gate			default:
15067c478bdstevel@tonic-gate				scfdie();
15077c478bdstevel@tonic-gate			}
15087c478bdstevel@tonic-gate		}
15097c478bdstevel@tonic-gate	}
15107c478bdstevel@tonic-gate
15117c478bdstevel@tonic-gate	/*
15127c478bdstevel@tonic-gate	 * If we lose the transaction race and need to retry, there are 2
15137c478bdstevel@tonic-gate	 * potential other winners:
15147c478bdstevel@tonic-gate	 *	- another process setting actions
15157c478bdstevel@tonic-gate	 *	- the restarter marking the action complete
15167c478bdstevel@tonic-gate	 * Therefore, re-read the property every time through the loop before
15177c478bdstevel@tonic-gate	 * making any decisions based on their values.
15187c478bdstevel@tonic-gate	 */
15197c478bdstevel@tonic-gate	do {
15207c478bdstevel@tonic-gate		timestamp = gethrtime();
15217c478bdstevel@tonic-gate
15227c478bdstevel@tonic-gate		if (scf_transaction_start(tx, pg) == -1) {
15237c478bdstevel@tonic-gate			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15247c478bdstevel@tonic-gate				scfdie();
15257c478bdstevel@tonic-gate
15267c478bdstevel@tonic-gate			if (!verbose)
15277c478bdstevel@tonic-gate				uu_warn(emsg_permission_denied, fmri);
15287c478bdstevel@tonic-gate			else
15297c478bdstevel@tonic-gate				uu_warn(emsg_pg_perm_denied, fmri,
15307c478bdstevel@tonic-gate				    scf_pg_restarter_actions);
15317c478bdstevel@tonic-gate			goto out;
15327c478bdstevel@tonic-gate		}
15337c478bdstevel@tonic-gate
15347c478bdstevel@tonic-gate		if (scf_pg_get_property(pg, action, prop) == -1) {
15357c478bdstevel@tonic-gate			if (scf_error() != SCF_ERROR_NOT_FOUND)
15367c478bdstevel@tonic-gate				scfdie();
15377c478bdstevel@tonic-gate			if (scf_transaction_property_new(tx, ent,
15387c478bdstevel@tonic-gate			    action, SCF_TYPE_INTEGER) == -1)
15397c478bdstevel@tonic-gate				scfdie();
15407c478bdstevel@tonic-gate			goto action_set;
15417c478bdstevel@tonic-gate		} else {
15427c478bdstevel@tonic-gate			if (scf_transaction_property_change_type(tx, ent,
15437c478bdstevel@tonic-gate			    action, SCF_TYPE_INTEGER) == -1)
15447c478bdstevel@tonic-gate				scfdie();
15457c478bdstevel@tonic-gate		}
15467c478bdstevel@tonic-gate
15477c478bdstevel@tonic-gate		if (scf_property_get_value(prop, v) == -1) {
15487c478bdstevel@tonic-gate			switch (scf_error()) {
15497c478bdstevel@tonic-gate			case SCF_ERROR_CONSTRAINT_VIOLATED:
15507c478bdstevel@tonic-gate			case SCF_ERROR_NOT_FOUND:
15517c478bdstevel@tonic-gate				/* Misconfigured, so set anyway. */
15527c478bdstevel@tonic-gate				goto action_set;
15537c478bdstevel@tonic-gate
15547c478bdstevel@tonic-gate			default:
15557c478bdstevel@tonic-gate				scfdie();
15567c478bdstevel@tonic-gate			}
15577c478bdstevel@tonic-gate		} else {
15587c478bdstevel@tonic-gate			if (scf_value_get_integer(v, &t) == -1) {
15597c478bdstevel@tonic-gate				assert(scf_error() == SCF_ERROR_TYPE_MISMATCH);
15607c478bdstevel@tonic-gate				goto action_set;
15617c478bdstevel@tonic-gate			}
15627c478bdstevel@tonic-gate			if (t > timestamp)
15637c478bdstevel@tonic-gate				break;
15647c478bdstevel@tonic-gate		}
15657c478bdstevel@tonic-gate
15667c478bdstevel@tonic-gateaction_set:
15677c478bdstevel@tonic-gate		scf_value_set_integer(v, timestamp);
15687c478bdstevel@tonic-gate		if (scf_entry_add_value(ent, v) == -1)
15697c478bdstevel@tonic-gate			scfdie();
15707c478bdstevel@tonic-gate
15717c478bdstevel@tonic-gate		ret = scf_transaction_commit(tx);
15727c478bdstevel@tonic-gate		if (ret == -1) {
15737c478bdstevel@tonic-gate			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15747c478bdstevel@tonic-gate				scfdie();
15757c478bdstevel@tonic-gate
15767c478bdstevel@tonic-gate			if (!verbose)
15777c478bdstevel@tonic-gate				uu_warn(emsg_permission_denied, fmri);
15787c478bdstevel@tonic-gate			else
15797c478bdstevel@tonic-gate				uu_warn(emsg_prop_perm_denied, fmri,
15807c478bdstevel@tonic-gate				    scf_pg_restarter_actions, action);
15817c478bdstevel@tonic-gate			scf_transaction_reset(tx);
15827c478bdstevel@tonic-gate			goto out;
15837c478bdstevel@tonic-gate		}
15847c478bdstevel@tonic-gate
15857c478bdstevel@tonic-gate		scf_transaction_reset(tx);
15867c478bdstevel@tonic-gate
15877c478bdstevel@tonic-gate		if (ret == 0) {
15887c478bdstevel@tonic-gate			if (scf_pg_update(pg) == -1)
15897c478bdstevel@tonic-gate				scfdie();
15907c478bdstevel@tonic-gate		}
15917c478bdstevel@tonic-gate	} while (ret == 0);
15927c478bdstevel@tonic-gate
15937c478bdstevel@tonic-gate	if (verbose)
15947c478bdstevel@tonic-gate		(void) printf(gettext("Action %s set for %s.\n"), action, fmri);
15957c478bdstevel@tonic-gate
15967c478bdstevel@tonic-gateout:
15977c478bdstevel@tonic-gate	scf_value_destroy(v);
15987c478bdstevel@tonic-gate	scf_entry_destroy(ent);
15997c478bdstevel@tonic-gate	scf_transaction_destroy(tx);
16007c478bdstevel@tonic-gate	scf_property_destroy(prop);
16017c478bdstevel@tonic-gate	scf_pg_destroy(pg);
16027c478bdstevel@tonic-gate}
16037c478bdstevel@tonic-gate
16047c478bdstevel@tonic-gate/*
16057c478bdstevel@tonic-gate * Get the state of inst.  state should point to a buffer of
16067c478bdstevel@tonic-gate * MAX_SCF_STATE_STRING_SZ bytes.  Returns 0 on success or -1 if
16077c478bdstevel@tonic-gate *   no restarter property group
16087c478bdstevel@tonic-gate *   no state property
16097c478bdstevel@tonic-gate *   state property is misconfigured (wrong type, not single-valued)
16107c478bdstevel@tonic-gate *   state value is too long
16117c478bdstevel@tonic-gate * In these cases, fmri is used to print a warning.
16127c478bdstevel@tonic-gate *
16137c478bdstevel@tonic-gate * If pgp is non-NULL, a successful call to inst_get_state will store
16147c478bdstevel@tonic-gate * the SCF_PG_RESTARTER property group in *pgp, and the caller will be
16157c478bdstevel@tonic-gate * responsible for calling scf_pg_destroy on the property group.
16167c478bdstevel@tonic-gate */
16177c478bdstevel@tonic-gateint
16187c478bdstevel@tonic-gateinst_get_state(scf_instance_t *inst, char *state, const char *fmri,
16197c478bdstevel@tonic-gate    scf_propertygroup_t **pgp)
16207c478bdstevel@tonic-gate{
16217c478bdstevel@tonic-gate	scf_propertygroup_t *pg;
16227c478bdstevel@tonic-gate	scf_property_t *prop;
16237c478bdstevel@tonic-gate	scf_value_t *val;
16247c478bdstevel@tonic-gate	int ret = -1;
16257c478bdstevel@tonic-gate	ssize_t szret;
16267c478bdstevel@tonic-gate
16277c478bdstevel@tonic-gate	if ((pg = scf_pg_create(h)) == NULL ||
16287c478bdstevel@tonic-gate	    (prop = scf_property_create(h)) == NULL ||
16297c478bdstevel@tonic-gate	    (val = scf_value_create(h)) == NULL)
16307c478bdstevel@tonic-gate		scfdie();
16317c478bdstevel@tonic-gate
16327c478bdstevel@tonic-gate	if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) {
16337c478bdstevel@tonic-gate		if (scf_error() != SCF_ERROR_NOT_FOUND)
16347c478bdstevel@tonic-gate			scfdie();
16357c478bdstevel@tonic-gate
16367c478bdstevel@tonic-gate		uu_warn(gettext("%s is misconfigured (lacks \"%s\" property "
16377c478bdstevel@tonic-gate		    "group).\n"), fmri ? fmri : inst_get_fmri(inst),
16387c478bdstevel@tonic-gate		    SCF_PG_RESTARTER);
16397c478bdstevel@tonic-gate		goto out;
16407c478bdstevel@tonic-gate	}
16417c478bdstevel@tonic-gate
16427c478bdstevel@tonic-gate	szret = get_astring_prop(pg, SCF_PROPERTY_STATE, prop, val, state,
16437c478bdstevel@tonic-gate	    MAX_SCF_STATE_STRING_SZ);
16447c478bdstevel@tonic-gate	if (szret < 0) {
16457c478bdstevel@tonic-gate		switch (-szret) {
16467c478bdstevel@tonic-gate		case ENOENT:
16477c478bdstevel@tonic-gate			uu_warn(gettext("%s is misconfigured (\"%s\" property "
16487c478bdstevel@tonic-gate			    "group lacks \"%s\" property).\n"),
16497c478bdstevel@tonic-gate			    fmri ? fmri : inst_get_fmri(inst), SCF_PG_RESTARTER,
16507c478bdstevel@tonic-gate			    SCF_PROPERTY_STATE);
16517c478bdstevel@tonic-gate			goto out;
16527c478bdstevel@tonic-gate
16537c478bdstevel@tonic-gate		case E2BIG:
16547c478bdstevel@tonic-gate			uu_warn(gettext("%s is misconfigured (\"%s/%s\" "
16557c478bdstevel@tonic-gate			    "property is not single-valued).\n"),
16567c478bdstevel@tonic-gate			    fmri ? fmri : inst_get_fmri(inst), SCF_PG_RESTARTER,
16577c478bdstevel@tonic-gate			    SCF_PROPERTY_STATE);
16587c478bdstevel@tonic-gate			goto out;
16597c478bdstevel@tonic-gate
16607c478bdstevel@tonic-gate		case EINVAL:
16617c478bdstevel@tonic-gate			uu_warn(gettext("%s is misconfigured (\"%s/%s\" "
16627c478bdstevel@tonic-gate			    "property is not of type astring).\n"),
16637c478bdstevel@tonic-gate			    fmri ? fmri : inst_get_fmri(inst), SCF_PG_RESTARTER,
16647c478bdstevel@tonic-gate			    SCF_PROPERTY_STATE);
16657c478bdstevel@tonic-gate			goto out;
16667c478bdstevel@tonic-gate
16677c478bdstevel@tonic-gate		default:
16687c478bdstevel@tonic-gate			assert(0);
16697c478bdstevel@tonic-gate			abort();
16707c478bdstevel@tonic-gate		}
16717c478bdstevel@tonic-gate	}
16727c478bdstevel@tonic-gate	if (szret >= MAX_SCF_STATE_STRING_SZ) {
16737c478bdstevel@tonic-gate		uu_warn(gettext("%s is misconfigured (\"%s/%s\" property value "
16747c478bdstevel@tonic-gate		    "is too long).\n"), fmri ? fmri : inst_get_fmri(inst),
16757c478bdstevel@tonic-gate		    SCF_PG_RESTARTER, SCF_PROPERTY_STATE);
16767c478bdstevel@tonic-gate		goto out;
16777c478bdstevel@tonic-gate	}
16787c478bdstevel@tonic-gate
16797c478bdstevel@tonic-gate	ret = 0;
16807c478bdstevel@tonic-gate	if (pgp)
16817c478bdstevel@tonic-gate		*pgp = pg;
16827c478bdstevel@tonic-gate
16837c478bdstevel@tonic-gateout:
16847c478bdstevel@tonic-gate	(void) scf_value_destroy(val);
16857c478bdstevel@tonic-gate	scf_property_destroy(prop);
16867c478bdstevel@tonic-gate	if (ret || pgp == NULL)
16877c478bdstevel@tonic-gate		scf_pg_destroy(pg);
16887c478bdstevel@tonic-gate	return (ret);
16897c478bdstevel@tonic-gate}
16907c478bdstevel@tonic-gate
16917c478bdstevel@tonic-gatestatic void
16927c478bdstevel@tonic-gateset_astring_prop(const char *fmri, const char *pgname, const char *pgtype,
16937c478bdstevel@tonic-gate    uint32_t pgflags, const char *propname, const char *str)
16947c478bdstevel@tonic-gate{
16957c478bdstevel@tonic-gate	scf_instance_t *inst;
16967c478bdstevel@tonic-gate	scf_propertygroup_t *pg;
16977c478bdstevel@tonic-gate	scf_property_t *prop;
16987c478bdstevel@tonic-gate	scf_value_t *val;
16997c478bdstevel@tonic-gate	scf_transaction_t *tx;
17007c478bdstevel@tonic-gate	scf_transaction_entry_t *txent;
17017c478bdstevel@tonic-gate	int ret;
17027c478bdstevel@tonic-gate
17037c478bdstevel@tonic-gate	inst = scf_instance_create(h);
17047c478bdstevel@tonic-gate	if (inst == NULL)
17057c478bdstevel@tonic-gate		scfdie();
17067c478bdstevel@tonic-gate
17077c478bdstevel@tonic-gate	if (get_inst(fmri, inst) != 0)
17087c478bdstevel@tonic-gate		return;
17097c478bdstevel@tonic-gate
17107c478bdstevel@tonic-gate	if ((pg = scf_pg_create(h)) == NULL ||
17117c478bdstevel@tonic-gate	    (prop = scf_property_create(h)) == NULL ||
17127c478bdstevel@tonic-gate	    (val = scf_value_create(h)) == NULL ||
17137c478bdstevel@tonic-gate	    (tx = scf_transaction_create(h)) == NULL ||
17147c478bdstevel@tonic-gate	    (txent = scf_entry_create(h)) == NULL)
17157c478bdstevel@tonic-gate		scfdie();
17167c478bdstevel@tonic-gate
17177c478bdstevel@tonic-gate	if (scf_instance_get_pg(inst, pgname, pg) != SCF_SUCCESS) {
17187c478bdstevel@tonic-gate		if (scf_error() != SCF_ERROR_NOT_FOUND)
17197c478bdstevel@tonic-gate			scfdie();
17207c478bdstevel@tonic-gate
17217c478bdstevel@tonic-gate		if (scf_instance_add_pg(inst, pgname, pgtype, pgflags, pg) !=
17227c478bdstevel@tonic-gate		    SCF_SUCCESS) {
17237c478bdstevel@tonic-gate			switch (scf_error()) {
17247c478bdstevel@tonic-gate			case SCF_ERROR_EXISTS:
17257c478bdstevel@tonic-gate				if (scf_instance_get_pg(inst, pgname, pg) !=
17267c478bdstevel@tonic-gate				    SCF_SUCCESS) {
17277c478bdstevel@tonic-gate					if (scf_error() != SCF_ERROR_NOT_FOUND)
17287c478bdstevel@tonic-gate						scfdie();
17297c478bdstevel@tonic-gate
17307c478bdstevel@tonic-gate					uu_warn(gettext("Repository write "
17317c478bdstevel@tonic-gate					    "contention.\n"));
17327c478bdstevel@tonic-gate					goto out;
17337c478bdstevel@tonic-gate				}
17347c478bdstevel@tonic-gate				break;
17357c478bdstevel@tonic-gate
17367c478bdstevel@tonic-gate			case SCF_ERROR_PERMISSION_DENIED:
17377c478bdstevel@tonic-gate				if (!verbose)
17387c478bdstevel@tonic-gate					uu_warn(emsg_permission_denied, fmri);
17397c478bdstevel@tonic-gate				else
17407c478bdstevel@tonic-gate					uu_warn(emsg_create_pg_perm_denied,
17417c478bdstevel@tonic-gate					    fmri, pgname);
17427c478bdstevel@tonic-gate				goto out;
17437c478bdstevel@tonic-gate
17447c478bdstevel@tonic-gate			default:
17457c478bdstevel@tonic-gate				scfdie();
17467c478bdstevel@tonic-gate			}
17477c478bdstevel@tonic-gate		}
17487c478bdstevel@tonic-gate	}
17497c478bdstevel@tonic-gate
17507c478bdstevel@tonic-gate	do {
17517c478bdstevel@tonic-gate		if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
17527c478bdstevel@tonic-gate			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
17537c478bdstevel@tonic-gate				scfdie();
17547c478bdstevel@tonic-gate
17557c478bdstevel@tonic-gate			if (!verbose)
17567c478bdstevel@tonic-gate				uu_warn(emsg_permission_denied, fmri);
17577c478bdstevel@tonic-gate			else
17587c478bdstevel@tonic-gate				uu_warn(emsg_pg_perm_denied, fmri, pgname);
17597c478bdstevel@tonic-gate			goto out;
17607c478bdstevel@tonic-gate		}
17617c478bdstevel@tonic-gate
17627c478bdstevel@tonic-gate		if (scf_transaction_property_change_type(tx, txent, propname,
17637c478bdstevel@tonic-gate		    SCF_TYPE_ASTRING) != 0) {
17647c478bdstevel@tonic-gate			if (scf_error() != SCF_ERROR_NOT_FOUND)
17657c478bdstevel@tonic-gate				scfdie();
17667c478bdstevel@tonic-gate
17677c478bdstevel@tonic-gate			if (scf_transaction_property_new(tx, txent, propname,
17687c478bdstevel@tonic-gate			    SCF_TYPE_ASTRING) != 0)
17697c478bdstevel@tonic-gate				scfdie();
17707c478bdstevel@tonic-gate		}
17717c478bdstevel@tonic-gate
17727c478bdstevel@tonic-gate		if (scf_value_set_astring(val, str) != SCF_SUCCESS)
17737c478bdstevel@tonic-gate			scfdie();
17747c478bdstevel@tonic-gate
17757c478bdstevel@tonic-gate		if (scf_entry_add_value(txent, val) != SCF_SUCCESS)
17767c478bdstevel@tonic-gate			scfdie();
17777c478bdstevel@tonic-gate
17787c478bdstevel@tonic-gate		ret = scf_transaction_commit(tx);
17797c478bdstevel@tonic-gate		if (ret == -1) {
17807c478bdstevel@tonic-gate			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
17817c478bdstevel@tonic-gate				scfdie();
17827c478bdstevel@tonic-gate
17837c478bdstevel@tonic-gate			if (!verbose)
17847c478bdstevel@tonic-gate				uu_warn(emsg_permission_denied, fmri);
17857c478bdstevel@tonic-gate			else
17867c478bdstevel@tonic-gate				uu_warn(emsg_prop_perm_denied, fmri, pgname,
17877c478bdstevel@tonic-gate				    propname);
17887c478bdstevel@tonic-gate			goto out;
17897c478bdstevel@tonic-gate		}
17907c478bdstevel@tonic-gate
17917c478bdstevel@tonic-gate		if (ret == 0) {
17927c478bdstevel@tonic-gate			scf_transaction_reset(tx);
17937c478bdstevel@tonic-gate
1794bc9767ftn			if (scf_pg_update(pg) == -1)
17957c478bdstevel@tonic-gate				scfdie();
17967c478bdstevel@tonic-gate		}
17977c478bdstevel@tonic-gate	} while (ret == 0);
17987c478bdstevel@tonic-gate
17997c478bdstevel@tonic-gateout:
18007c478bdstevel@tonic-gate	scf_transaction_destroy(tx);
18017c478bdstevel@tonic-gate	scf_entry_destroy(txent);
18027c478bdstevel@tonic-gate	scf_value_destroy(val);
18037c478bdstevel@tonic-gate	scf_property_destroy(prop);
18047c478bdstevel@tonic-gate	scf_pg_destroy(pg);
18057c478bdstevel@tonic-gate	scf_instance_destroy(inst);
18067c478bdstevel@tonic-gate}
18077c478bdstevel@tonic-gate
18087c478bdstevel@tonic-gate
18097c478bdstevel@tonic-gatestatic int
18107c478bdstevel@tonic-gateset_fmri_enabled(void *data, scf_walkinfo_t *wip)
18117c478bdstevel@tonic-gate{
18128fff788John Levon	enable_data_t *ed = data;
18137c478bdstevel@tonic-gate
18147c478bdstevel@tonic-gate	assert(wip->inst != NULL);
18157c478bdstevel@tonic-gate	assert(wip->pg == NULL);
18167c478bdstevel@tonic-gate
181737b4022Jerry Jelinek	if (svcsearch) {
181837b4022Jerry Jelinek		char state[MAX_SCF_STATE_STRING_SZ];
181937b4022Jerry Jelinek
182037b4022Jerry Jelinek		if (inst_get_state(wip->inst, state, wip->fmri, NULL) != 0)
182137b4022Jerry Jelinek			return (0);
182237b4022Jerry Jelinek		if (strcmp(state, svcstate) != 0)
182337b4022Jerry Jelinek			return (0);
182437b4022Jerry Jelinek	}
182537b4022Jerry Jelinek
18268fff788John Levon	if (ed->ed_flags & SET_RECURSIVE) {
18277c478bdstevel@tonic-gate		char *fmri_buf = malloc(max_scf_fmri_sz);
18287c478bdstevel@tonic-gate		if (fmri_buf == NULL)
18297c478bdstevel@tonic-gate			uu_die(emsg_nomem);
18307c478bdstevel@tonic-gate
18317c478bdstevel@tonic-gate		visited = calloc(HT_BUCKETS, sizeof (*visited));
18327c478bdstevel@tonic-gate		if (visited == NULL)
18337c478bdstevel@tonic-gate			uu_die(emsg_nomem);
18347c478bdstevel@tonic-gate
18357c478bdstevel@tonic-gate		/* scf_walk_fmri() guarantees that fmri isn't too long */
18367c478bdstevel@tonic-gate		assert(strlen(wip->fmri) <= max_scf_fmri_sz);
18377c478bdstevel@tonic-gate		(void) strlcpy(fmri_buf, wip->fmri, max_scf_fmri_sz);
18387c478bdstevel@tonic-gate
18398fff788John Levon		switch (enable_fmri_rec(fmri_buf, ed)) {
18407c478bdstevel@tonic-gate		case E2BIG:
18417c478bdstevel@tonic-gate			uu_warn(gettext("operation on service %s is ambiguous; "
18427c478bdstevel@tonic-gate			    "instance specification needed.\n"), fmri_buf);
18437c478bdstevel@tonic-gate			break;
18447c478bdstevel@tonic-gate
18457c478bdstevel@tonic-gate		case ELOOP:
18467c478bdstevel@tonic-gate			uu_warn(gettext("%s: Dependency cycle detected.\n"),
18477c478bdstevel@tonic-gate			    fmri_buf);
18487c478bdstevel@tonic-gate		}
18497c478bdstevel@tonic-gate
18507c478bdstevel@tonic-gate		free(visited);
18517c478bdstevel@tonic-gate		free(fmri_buf);
18527c478bdstevel@tonic-gate
18537c478bdstevel@tonic-gate	} else {
18548fff788John Levon		set_inst_enabled(wip->fmri, wip->inst, ed);
18557c478bdstevel@tonic-gate	}
18567c478bdstevel@tonic-gate
18577c478bdstevel@tonic-gate	return (0);
18587c478bdstevel@tonic-gate}
18597c478bdstevel@tonic-gate
18607c478bdstevel@tonic-gate/* ARGSUSED */
18617c478bdstevel@tonic-gatestatic int
18627c478bdstevel@tonic-gatewait_fmri_enabled(void *data, scf_walkinfo_t *wip)
18637c478bdstevel@tonic-gate{
18647c478bdstevel@tonic-gate	scf_propertygroup_t *pg = NULL;
18657c478bdstevel@tonic-gate	char state[MAX_SCF_STATE_STRING_SZ];
18667c478bdstevel@tonic-gate
18677c478bdstevel@tonic-gate	assert(wip->inst != NULL);
18687c478bdstevel@tonic-gate	assert(wip->pg == NULL);
18697c478bdstevel@tonic-gate
18707c478bdstevel@tonic-gate	do {
18717c478bdstevel@tonic-gate		if (pg)
18727c478bdstevel@tonic-gate			scf_pg_destroy(pg);
18737c478bdstevel@tonic-gate		if (inst_get_state(wip->inst, state, wip->fmri, &pg) != 0) {
18747c478bdstevel@tonic-gate			exit_status = EXIT_SVC_FAILURE;
18757c478bdstevel@tonic-gate			return (0);
18767c478bdstevel@tonic-gate		}
18777c478bdstevel@tonic-gate
18787c478bdstevel@tonic-gate		if (strcmp(state, SCF_STATE_STRING_ONLINE) == 0 ||
18797c478bdstevel@tonic-gate		    strcmp(state, SCF_STATE_STRING_DEGRADED) == 0) {
18807c478bdstevel@tonic-gate			/*
18817c478bdstevel@tonic-gate			 * We're done.
18827c478bdstevel@tonic-gate			 */
18837c478bdstevel@tonic-gate			goto out;
18847c478bdstevel@tonic-gate		}
18857c478bdstevel@tonic-gate
18867c478bdstevel@tonic-gate		if (strcmp(state, SCF_STATE_STRING_MAINT) == 0) {
18877c478bdstevel@tonic-gate			/*
18887c478bdstevel@tonic-gate			 * The service is ill.
18897c478bdstevel@tonic-gate			 */
18907c478bdstevel@tonic-gate			uu_warn(gettext("Instance \"%s\" is in maintenance"
18917c478bdstevel@tonic-gate			    " state.\n"), wip->fmri);
18927c478bdstevel@tonic-gate			exit_status = EXIT_SVC_FAILURE;
18937c478bdstevel@tonic-gate			goto out;
18947c478bdstevel@tonic-gate		}
18957c478bdstevel@tonic-gate
18967c478bdstevel@tonic-gate		if (!is_enabled(wip->inst)) {
18977c478bdstevel@tonic-gate			/*
18987c478bdstevel@tonic-gate			 * Someone stepped in and disabled the service.
18997c478bdstevel@tonic-gate			 */
19007c478bdstevel@tonic-gate			uu_warn(gettext("Instance \"%s\" has been disabled"
19017c478bdstevel@tonic-gate			    " by another entity.\n"), wip->fmri);
19027c478bdstevel@tonic-gate			exit_status = EXIT_SVC_FAILURE;
19037c478bdstevel@tonic-gate			goto out;
19047c478bdstevel@tonic-gate		}
19057c478bdstevel@tonic-gate
19067c478bdstevel@tonic-gate		if (!has_potential(wip->inst, B_FALSE)) {
19077c478bdstevel@tonic-gate			/*
19087c478bdstevel@tonic-gate			 * Our dependencies aren't met.  We'll never
19097c478bdstevel@tonic-gate			 * amount to anything.
19107c478bdstevel@tonic-gate			 */
19117c478bdstevel@tonic-gate			uu_warn(gettext("Instance \"%s\" has unsatisfied"
19127c478bdstevel@tonic-gate			    " dependencies.\n"), wip->fmri);
19137c478bdstevel@tonic-gate			/*
19147c478bdstevel@tonic-gate			 * EXIT_SVC_FAILURE takes precedence over
19157c478bdstevel@tonic-gate			 * EXIT_DEP_FAILURE
19167c478bdstevel@tonic-gate			 */
19177c478bdstevel@tonic-gate			if (exit_status == 0)
19187c478bdstevel@tonic-gate				exit_status = EXIT_DEP_FAILURE;
19197c478bdstevel@tonic-gate			goto out;
19207c478bdstevel@tonic-gate		}
19217c478bdstevel@tonic-gate	} while (_scf_pg_wait(pg, WAIT_INTERVAL) >= 0);
19227c478bdstevel@tonic-gate	scfdie();
19237c478bdstevel@tonic-gate	/* NOTREACHED */
19247c478bdstevel@tonic-gate
19257c478bdstevel@tonic-gateout:
19267c478bdstevel@tonic-gate	scf_pg_destroy(pg);
19277c478bdstevel@tonic-gate	return (0);
19287c478bdstevel@tonic-gate}
19297c478bdstevel@tonic-gate
19307c478bdstevel@tonic-gate/* ARGSUSED */
19317c478bdstevel@tonic-gatestatic int
19327c478bdstevel@tonic-gatewait_fmri_disabled(void *data, scf_walkinfo_t *wip)
19337c478bdstevel@tonic-gate{
19347c478bdstevel@tonic-gate	scf_propertygroup_t *pg = NULL;
19357c478bdstevel@tonic-gate	char state[MAX_SCF_STATE_STRING_SZ];
19367c478bdstevel@tonic-gate
19377c478bdstevel@tonic-gate	assert(wip->inst != NULL);
19387c478bdstevel@tonic-gate	assert(wip->pg == NULL);
19397c478bdstevel@tonic-gate
19407c478bdstevel@tonic-gate	do {
19417c478bdstevel@tonic-gate		if (pg)
19427c478bdstevel@tonic-gate			scf_pg_destroy(pg);
19437c478bdstevel@tonic-gate		if (inst_get_state(wip->inst, state, wip->fmri, &pg) != 0) {
19447c478bdstevel@tonic-gate			exit_status = EXIT_SVC_FAILURE;
19457c478bdstevel@tonic-gate			return (0);
19467c478bdstevel@tonic-gate		}
19477c478bdstevel@tonic-gate
19487c478bdstevel@tonic-gate		if (strcmp(state, SCF_STATE_STRING_DISABLED) == 0) {
19497c478bdstevel@tonic-gate			/*
19507c478bdstevel@tonic-gate			 * We're done.
19517c478bdstevel@tonic-gate			 */
19527c478bdstevel@tonic-gate			goto out;
19537c478bdstevel@tonic-gate		}
19547c478bdstevel@tonic-gate
19557c478bdstevel@tonic-gate		if (is_enabled(wip->inst)) {
19567c478bdstevel@tonic-gate			/*
19577c478bdstevel@tonic-gate			 * Someone stepped in and enabled the service.
19587c478bdstevel@tonic-gate			 */
19597c478bdstevel@tonic-gate			uu_warn(gettext("Instance \"%s\" has been enabled"
19607c478bdstevel@tonic-gate			    " by another entity.\n"), wip->fmri);
19617c478bdstevel@tonic-gate			exit_status = EXIT_SVC_FAILURE;
19627c478bdstevel@tonic-gate			goto out;
19637c478bdstevel@tonic-gate		}
19647c478bdstevel@tonic-gate
19657c478bdstevel@tonic-gate		if (!has_potential(wip->inst, B_TRUE)) {
19667c478bdstevel@tonic-gate			/*
19677c478bdstevel@tonic-gate			 * Our restarter is hopeless.
19687c478bdstevel@tonic-gate			 */
19697c478bdstevel@tonic-gate			uu_warn(gettext("Restarter for instance \"%s\" is"
19707c478bdstevel@tonic-gate			    " unavailable.\n"), wip->fmri);
19717c478bdstevel@tonic-gate			/*
19727c478bdstevel@tonic-gate			 * EXIT_SVC_FAILURE takes precedence over
19737c478bdstevel@tonic-gate			 * EXIT_DEP_FAILURE
19747c478bdstevel@tonic-gate			 */
19757c478bdstevel@tonic-gate			if (exit_status == 0)
19767c478bdstevel@tonic-gate				exit_status = EXIT_DEP_FAILURE;
19777c478bdstevel@tonic-gate			goto out;
19787c478bdstevel@tonic-gate		}
19797c478bdstevel@tonic-gate
19807c478bdstevel@tonic-gate	} while (_scf_pg_wait(pg, WAIT_INTERVAL) >= 0);
19817c478bdstevel@tonic-gate	scfdie();
19827c478bdstevel@tonic-gate	/* NOTREACHED */
19837c478bdstevel@tonic-gate
19847c478bdstevel@tonic-gateout:
19857c478bdstevel@tonic-gate	scf_pg_destroy(pg);
19867c478bdstevel@tonic-gate	return (0);
19877c478bdstevel@tonic-gate}
19887c478bdstevel@tonic-gate
19897c478bdstevel@tonic-gate/* ARGSUSED */
19907c478bdstevel@tonic-gatestatic int
19917c478bdstevel@tonic-gateclear_instance(void *data, scf_walkinfo_t *wip)
19927c478bdstevel@tonic-gate{
19937c478bdstevel@tonic-gate	char state[MAX_SCF_STATE_STRING_SZ];
19947c478bdstevel@tonic-gate
19957c478bdstevel@tonic-gate	assert(wip->inst != NULL);
19967c478bdstevel@tonic-gate	assert(wip->pg == NULL);
19977c478bdstevel@tonic-gate
19987c478bdstevel@tonic-gate	if (inst_get_state(wip->inst, state, wip->fmri, NULL) != 0)
19997c478bdstevel@tonic-gate		return (0);
20007c478bdstevel@tonic-gate
200137b4022Jerry Jelinek	if (svcsearch && strcmp(state, svcstate) != 0)
200237b4022Jerry Jelinek		return (0);
200337b4022Jerry Jelinek
20047c478bdstevel@tonic-gate	if (strcmp(state, SCF_STATE_STRING_MAINT) == 0) {
20057c478bdstevel@tonic-gate		set_inst_action(wip->fmri, wip->inst, SCF_PROPERTY_MAINT_OFF);
20067c478bdstevel@tonic-gate	} else if (strcmp(state, SCF_STATE_STRING_DEGRADED) ==
20077c478bdstevel@tonic-gate	    0) {
20087c478bdstevel@tonic-gate		set_inst_action(wip->fmri, wip->inst, SCF_PROPERTY_RESTORE);
20097c478bdstevel@tonic-gate	} else {
20107c478bdstevel@tonic-gate		uu_warn(gettext("Instance \"%s\" is not in a "
20117c478bdstevel@tonic-gate		    "maintenance or degraded state.\n"), wip->fmri);
20127c478bdstevel@tonic-gate
20137c478bdstevel@tonic-gate		exit_status = 1;
20147c478bdstevel@tonic-gate	}
20157c478bdstevel@tonic-gate
20167c478bdstevel@tonic-gate	return (0);
20177c478bdstevel@tonic-gate}
20187c478bdstevel@tonic-gate
20197c478bdstevel@tonic-gatestatic int
20207c478bdstevel@tonic-gateset_fmri_action(void *action, scf_walkinfo_t *wip)
20217c478bdstevel@tonic-gate{
20227c478bdstevel@tonic-gate	assert(wip->inst != NULL && wip->pg == NULL);
20237c478bdstevel@tonic-gate
202437b4022Jerry Jelinek	if (svcsearch) {
202537b4022Jerry Jelinek		char state[MAX_SCF_STATE_STRING_SZ];
202637b4022Jerry Jelinek
202737b4022Jerry Jelinek		if (inst_get_state(wip->inst, state, wip->fmri, NULL) != 0)
202837b4022Jerry Jelinek			return (0);
202937b4022Jerry Jelinek		if (strcmp(state, svcstate) != 0)
203037b4022Jerry Jelinek			return (0);
203137b4022Jerry Jelinek	}
203237b4022Jerry Jelinek
20337c478bdstevel@tonic-gate	set_inst_action(wip->fmri, wip->inst, action);
20347c478bdstevel@tonic-gate
20357c478bdstevel@tonic-gate	return (0);
20367c478bdstevel@tonic-gate}
20377c478bdstevel@tonic-gate
20387c478bdstevel@tonic-gate/*
20397c478bdstevel@tonic-gate * Flags to control 'mark' action.
20407c478bdstevel@tonic-gate */
20417c478bdstevel@tonic-gate#define	MARK_IMMEDIATE	0x1
20427c478bdstevel@tonic-gate#define	MARK_TEMPORARY	0x2
20437c478bdstevel@tonic-gate
20447c478bdstevel@tonic-gatestatic int
20457c478bdstevel@tonic-gateforce_degraded(void *data, scf_walkinfo_t *wip)
20467c478bdstevel@tonic-gate{
20477c478bdstevel@tonic-gate	int flags = (int)data;
20487c478bdstevel@tonic-gate	char state[MAX_SCF_STATE_STRING_SZ];
20497c478bdstevel@tonic-gate
20507c478bdstevel@tonic-gate	if (inst_get_state(wip->inst, state, wip->fmri, NULL) != 0) {
20517c478bdstevel@tonic-gate		exit_status = 1;
20527c478bdstevel@tonic-gate		return (0);
20537c478bdstevel@tonic-gate	}
20547c478bdstevel@tonic-gate
205537b4022Jerry Jelinek	if (svcsearch && strcmp(state, svcstate) != 0)
205637b4022Jerry Jelinek		return (0);
205737b4022Jerry Jelinek
20587c478bdstevel@tonic-gate	if (strcmp(state, SCF_STATE_STRING_ONLINE) != 0) {
20597c478bdstevel@tonic-gate		uu_warn(gettext("Instance \"%s\" is not online.\n"), wip->fmri);
20607c478bdstevel@tonic-gate		exit_status = 1;
20617c478bdstevel@tonic-gate		return (0);
20627c478bdstevel@tonic-gate	}
20637c478bdstevel@tonic-gate
20647c478bdstevel@tonic-gate	set_inst_action(wip->fmri, wip->inst, (flags & MARK_IMMEDIATE) ?
20657c478bdstevel@tonic-gate	    SCF_PROPERTY_DEGRADE_IMMEDIATE : SCF_PROPERTY_DEGRADED);
20667c478bdstevel@tonic-gate
20677c478bdstevel@tonic-gate	return (0);
20687c478bdstevel@tonic-gate}
20697c478bdstevel@tonic-gate
20707c478bdstevel@tonic-gatestatic int
20717c478bdstevel@tonic-gateforce_maintenance(void *data, scf_walkinfo_t *wip)
20727c478bdstevel@tonic-gate{
20737c478bdstevel@tonic-gate	int flags = (int)data;
20747c478bdstevel@tonic-gate	const char *prop;
20757c478bdstevel@tonic-gate
207637b4022Jerry Jelinek	if (svcsearch) {
207737b4022Jerry Jelinek		char state[MAX_SCF_STATE_STRING_SZ];
207837b4022Jerry Jelinek
207937b4022Jerry Jelinek		if (inst_get_state(wip->inst, state, wip->fmri, NULL) != 0)
208037b4022Jerry Jelinek			return (0);
208137b4022Jerry Jelinek		if (strcmp(state, svcstate) != 0)
208237b4022Jerry Jelinek			return (0);
208337b4022Jerry Jelinek	}
208437b4022Jerry Jelinek
20857c478bdstevel@tonic-gate	if (flags & MARK_IMMEDIATE) {
20867c478bdstevel@tonic-gate		prop = (flags & MARK_TEMPORARY) ?
20877c478bdstevel@tonic-gate		    SCF_PROPERTY_MAINT_ON_IMMTEMP :
20887c478bdstevel@tonic-gate		    SCF_PROPERTY_MAINT_ON_IMMEDIATE;
20897c478bdstevel@tonic-gate	} else {
20907c478bdstevel@tonic-gate		prop = (flags & MARK_TEMPORARY) ?
20917c478bdstevel@tonic-gate		    SCF_PROPERTY_MAINT_ON_TEMPORARY :
20927c478bdstevel@tonic-gate		    SCF_PROPERTY_MAINT_ON;
20937c478bdstevel@tonic-gate	}
20947c478bdstevel@tonic-gate
20957c478bdstevel@tonic-gate	set_inst_action(wip->fmri, wip->inst, prop);
20967c478bdstevel@tonic-gate
20977c478bdstevel@tonic-gate	return (0);
20987c478bdstevel@tonic-gate}
20997c478bdstevel@tonic-gate
21007c478bdstevel@tonic-gatestatic void
21017c478bdstevel@tonic-gateset_milestone(const char *fmri, boolean_t temporary)
21027c478bdstevel@tonic-gate{
21037c478bdstevel@tonic-gate	scf_instance_t *inst;
21047c478bdstevel@tonic-gate	scf_propertygroup_t *pg;
21057c478bdstevel@tonic-gate
21067c478bdstevel@tonic-gate	if (temporary) {
21077c478bdstevel@tonic-gate		set_astring_prop(SCF_SERVICE_STARTD, SCF_PG_OPTIONS_OVR,
21087c478bdstevel@tonic-gate		    SCF_PG_OPTIONS_OVR_TYPE, SCF_PG_OPTIONS_OVR_FLAGS,
21097c478bdstevel@tonic-gate		    SCF_PROPERTY_MILESTONE, fmri);
21107c478bdstevel@tonic-gate		return;
21117c478bdstevel@tonic-gate	}
21127c478bdstevel@tonic-gate
21137c478bdstevel@tonic-gate	if ((inst = scf_instance_create(h)) == NULL ||
21147c478bdstevel@tonic-gate	    (pg = scf_pg_create(h)) == NULL)
21157c478bdstevel@tonic-gate		scfdie();
21167c478bdstevel@tonic-gate
21177c478bdstevel@tonic-gate	if (get_inst(SCF_SERVICE_STARTD, inst) != 0) {
21187c478bdstevel@tonic-gate		scf_instance_destroy(inst);
21197c478bdstevel@tonic-gate		return;
21207c478bdstevel@tonic-gate	}
21217c478bdstevel@tonic-gate
21227c478bdstevel@tonic-gate	/*
21237c478bdstevel@tonic-gate	 * Set the persistent milestone before deleting the override so we don't
21247c478bdstevel@tonic-gate	 * glitch.
21257c478bdstevel@tonic-gate	 */
21267c478bdstevel@tonic-gate	set_astring_prop(SCF_SERVICE_STARTD, SCF_PG_OPTIONS,
21277c478bdstevel@tonic-gate	    SCF_PG_OPTIONS_TYPE, SCF_PG_OPTIONS_FLAGS, SCF_PROPERTY_MILESTONE,
21287c478bdstevel@tonic-gate	    fmri);
21297c478bdstevel@tonic-gate
21308fff788John Levon	if (delete_prop(SCF_SERVICE_STARTD, inst, SCF_PG_OPTIONS_OVR,
21318fff788John Levon	    SCF_PROPERTY_MILESTONE) != 0)
2132eb1a346Truong Nguyen		exit_status = 1;
21337c478bdstevel@tonic-gate
21347c478bdstevel@tonic-gate	scf_pg_destroy(pg);
21357c478bdstevel@tonic-gate	scf_instance_destroy(inst);
21367c478bdstevel@tonic-gate}
21377c478bdstevel@tonic-gate
21387c478bdstevel@tonic-gatestatic char const *milestones[] = {
21397c478bdstevel@tonic-gate	SCF_MILESTONE_SINGLE_USER,
21407c478bdstevel@tonic-gate	SCF_MILESTONE_MULTI_USER,
21417c478bdstevel@tonic-gate	SCF_MILESTONE_MULTI_USER_SERVER,
21427c478bdstevel@tonic-gate	NULL
21437c478bdstevel@tonic-gate};
21447c478bdstevel@tonic-gate
21457c478bdstevel@tonic-gatestatic void
21460b5c925hgusage_milestone(void)
21477c478bdstevel@tonic-gate{
21487c478bdstevel@tonic-gate	const char **ms;
21497c478bdstevel@tonic-gate
21507c478bdstevel@tonic-gate	(void) fprintf(stderr, gettext(
21517c478bdstevel@tonic-gate	"Usage: svcadm milestone [-d] <milestone>\n\n"
21527c478bdstevel@tonic-gate	"\t-d\tmake the specified milestone the default for system boot\n\n"
2153