xref: /titanic_50/usr/src/lib/librestart/common/librestart.c (revision eb1a34638eba7c5add1421327f3eb225a8ea7518)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
53ad28c1eSrm88369  * Common Development and Distribution License (the "License").
63ad28c1eSrm88369  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217257d1b4Sraf 
227c478bd9Sstevel@tonic-gate /*
23*eb1a3463STruong Nguyen  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #include <librestart.h>
287c478bd9Sstevel@tonic-gate #include <librestart_priv.h>
297c478bd9Sstevel@tonic-gate #include <libscf.h>
307c478bd9Sstevel@tonic-gate #include <libscf_priv.h>
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate #include <assert.h>
337c478bd9Sstevel@tonic-gate #include <ctype.h>
347c478bd9Sstevel@tonic-gate #include <dlfcn.h>
357c478bd9Sstevel@tonic-gate #include <errno.h>
367c478bd9Sstevel@tonic-gate #include <exec_attr.h>
377c478bd9Sstevel@tonic-gate #include <grp.h>
387c478bd9Sstevel@tonic-gate #include <libsysevent.h>
397c478bd9Sstevel@tonic-gate #include <libuutil.h>
407c478bd9Sstevel@tonic-gate #include <limits.h>
417c478bd9Sstevel@tonic-gate #include <link.h>
427c478bd9Sstevel@tonic-gate #include <malloc.h>
437c478bd9Sstevel@tonic-gate #include <pool.h>
447c478bd9Sstevel@tonic-gate #include <priv.h>
457c478bd9Sstevel@tonic-gate #include <project.h>
467c478bd9Sstevel@tonic-gate #include <pthread.h>
477c478bd9Sstevel@tonic-gate #include <pwd.h>
487c478bd9Sstevel@tonic-gate #include <secdb.h>
497c478bd9Sstevel@tonic-gate #include <signal.h>
507c478bd9Sstevel@tonic-gate #include <stdlib.h>
517c478bd9Sstevel@tonic-gate #include <string.h>
527c478bd9Sstevel@tonic-gate #include <syslog.h>
537c478bd9Sstevel@tonic-gate #include <sys/corectl.h>
547c478bd9Sstevel@tonic-gate #include <sys/machelf.h>
557c478bd9Sstevel@tonic-gate #include <sys/task.h>
567c478bd9Sstevel@tonic-gate #include <sys/types.h>
577c478bd9Sstevel@tonic-gate #include <time.h>
587c478bd9Sstevel@tonic-gate #include <unistd.h>
597c478bd9Sstevel@tonic-gate #include <ucontext.h>
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate #define	min(a, b)		((a) > (b) ? (b) : (a))
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate #define	MKW_TRUE	":true"
647c478bd9Sstevel@tonic-gate #define	MKW_KILL	":kill"
657c478bd9Sstevel@tonic-gate #define	MKW_KILL_PROC	":kill_process"
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate #define	ALLOCFAIL	((char *)"Allocation failure.")
687c478bd9Sstevel@tonic-gate #define	RCBROKEN	((char *)"Repository connection broken.")
697c478bd9Sstevel@tonic-gate 
702c65c8b0Srm88369 #define	MAX_COMMIT_RETRIES		10
717c478bd9Sstevel@tonic-gate #define	MAX_COMMIT_RETRY_INT		(5 * 1000000)	/* 5 seconds */
727c478bd9Sstevel@tonic-gate #define	INITIAL_COMMIT_RETRY_INT	(10000)		/* 1/100th second */
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate /*
757c478bd9Sstevel@tonic-gate  * bad_fail() catches bugs in this and lower layers by reporting supposedly
767c478bd9Sstevel@tonic-gate  * impossible function failures.  The NDEBUG case keeps the strings out of the
777c478bd9Sstevel@tonic-gate  * library but still calls abort() so we can root-cause from the coredump.
787c478bd9Sstevel@tonic-gate  */
797c478bd9Sstevel@tonic-gate #ifndef NDEBUG
807c478bd9Sstevel@tonic-gate #define	bad_fail(func, err)	{					\
817c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,						\
827c478bd9Sstevel@tonic-gate 	    "At %s:%d, %s() failed with unexpected error %d.  Aborting.\n", \
837c478bd9Sstevel@tonic-gate 	    __FILE__, __LINE__, (func), (err));				\
847c478bd9Sstevel@tonic-gate 	abort();							\
857c478bd9Sstevel@tonic-gate }
867c478bd9Sstevel@tonic-gate #else
877c478bd9Sstevel@tonic-gate #define	bad_fail(func, err)	abort()
887c478bd9Sstevel@tonic-gate #endif
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate struct restarter_event_handle {
917c478bd9Sstevel@tonic-gate 	char				*reh_restarter_name;
927c478bd9Sstevel@tonic-gate 	char				*reh_delegate_channel_name;
937c478bd9Sstevel@tonic-gate 	evchan_t			*reh_delegate_channel;
947c478bd9Sstevel@tonic-gate 	char				*reh_delegate_subscriber_id;
957c478bd9Sstevel@tonic-gate 	char				*reh_master_channel_name;
967c478bd9Sstevel@tonic-gate 	evchan_t			*reh_master_channel;
977c478bd9Sstevel@tonic-gate 	char				*reh_master_subscriber_id;
987c478bd9Sstevel@tonic-gate 	int				(*reh_handler)(restarter_event_t *);
997c478bd9Sstevel@tonic-gate };
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate struct restarter_event {
1027c478bd9Sstevel@tonic-gate 	sysevent_t			*re_sysevent;
1037c478bd9Sstevel@tonic-gate 	restarter_event_type_t		re_type;
1047c478bd9Sstevel@tonic-gate 	char				*re_instance_name;
1057c478bd9Sstevel@tonic-gate 	restarter_event_handle_t	*re_event_handle;
1067c478bd9Sstevel@tonic-gate 	restarter_instance_state_t	re_state;
1077c478bd9Sstevel@tonic-gate 	restarter_instance_state_t	re_next_state;
1087c478bd9Sstevel@tonic-gate };
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate static const char * const allocfail = "Allocation failure.\n";
1117c478bd9Sstevel@tonic-gate static const char * const rcbroken = "Repository connection broken.\n";
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate static int method_context_safety = 0;	/* Can safely call pools/projects. */
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate int ndebug = 1;
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate static void
1187c478bd9Sstevel@tonic-gate free_restarter_event_handle(struct restarter_event_handle *h)
1197c478bd9Sstevel@tonic-gate {
1207c478bd9Sstevel@tonic-gate 	if (h == NULL)
1217c478bd9Sstevel@tonic-gate 		return;
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate 	/*
1247c478bd9Sstevel@tonic-gate 	 * Just free the memory -- don't unbind the sysevent handle,
1257c478bd9Sstevel@tonic-gate 	 * as otherwise events may be lost if this is just a restarter
1267c478bd9Sstevel@tonic-gate 	 * restart.
1277c478bd9Sstevel@tonic-gate 	 */
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate 	if (h->reh_restarter_name != NULL)
1307c478bd9Sstevel@tonic-gate 		free(h->reh_restarter_name);
1317c478bd9Sstevel@tonic-gate 	if (h->reh_delegate_channel_name != NULL)
1327c478bd9Sstevel@tonic-gate 		free(h->reh_delegate_channel_name);
1337c478bd9Sstevel@tonic-gate 	if (h->reh_delegate_subscriber_id != NULL)
1347c478bd9Sstevel@tonic-gate 		free(h->reh_delegate_subscriber_id);
1357c478bd9Sstevel@tonic-gate 	if (h->reh_master_channel_name != NULL)
1367c478bd9Sstevel@tonic-gate 		free(h->reh_master_channel_name);
1377c478bd9Sstevel@tonic-gate 	if (h->reh_master_subscriber_id != NULL)
1387c478bd9Sstevel@tonic-gate 		free(h->reh_master_subscriber_id);
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate 	free(h);
1417c478bd9Sstevel@tonic-gate }
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate static const char *
1447c478bd9Sstevel@tonic-gate last_part(const char *fmri)
1457c478bd9Sstevel@tonic-gate {
1467c478bd9Sstevel@tonic-gate 	char *last_part;
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate 	last_part = strrchr(fmri, '/');
1497c478bd9Sstevel@tonic-gate 	last_part++;
1507c478bd9Sstevel@tonic-gate 	assert(last_part != NULL);
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate 	return (last_part);
1537c478bd9Sstevel@tonic-gate }
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate char *
1567c478bd9Sstevel@tonic-gate _restarter_get_channel_name(const char *fmri, int type)
1577c478bd9Sstevel@tonic-gate {
1587c478bd9Sstevel@tonic-gate 	const char *name;
1597c478bd9Sstevel@tonic-gate 	char *chan_name = malloc(MAX_CHNAME_LEN);
1607c478bd9Sstevel@tonic-gate 	char prefix_name[3];
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate 	if (chan_name == NULL)
1637c478bd9Sstevel@tonic-gate 		return (NULL);
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 	if (type == RESTARTER_CHANNEL_DELEGATE)
1667c478bd9Sstevel@tonic-gate 		(void) strcpy(prefix_name, "d_");
1677c478bd9Sstevel@tonic-gate 	else if (type == RESTARTER_CHANNEL_MASTER)
1687c478bd9Sstevel@tonic-gate 		(void) strcpy(prefix_name, "m_");
1697c478bd9Sstevel@tonic-gate 	else {
1707c478bd9Sstevel@tonic-gate 		free(chan_name);
1717c478bd9Sstevel@tonic-gate 		return (NULL);
1727c478bd9Sstevel@tonic-gate 	}
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate 	name = last_part(fmri);
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 	/*
1777c478bd9Sstevel@tonic-gate 	 * Should check for [a-z],[A-Z],[0-9],.,_,-,:
1787c478bd9Sstevel@tonic-gate 	 */
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 	if (snprintf(chan_name, MAX_CHNAME_LEN, "com.sun:scf:%s%s",
1817c478bd9Sstevel@tonic-gate 	    prefix_name, name) > MAX_CHNAME_LEN) {
1827c478bd9Sstevel@tonic-gate 		free(chan_name);
1837c478bd9Sstevel@tonic-gate 		return (NULL);
1847c478bd9Sstevel@tonic-gate 	}
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate 	return (chan_name);
1877c478bd9Sstevel@tonic-gate }
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate int
1907c478bd9Sstevel@tonic-gate cb(sysevent_t *syse, void *cookie)
1917c478bd9Sstevel@tonic-gate {
1927c478bd9Sstevel@tonic-gate 	restarter_event_handle_t *h = (restarter_event_handle_t *)cookie;
1937c478bd9Sstevel@tonic-gate 	restarter_event_t *e;
1947c478bd9Sstevel@tonic-gate 	nvlist_t *attr_list = NULL;
1957c478bd9Sstevel@tonic-gate 	int ret = 0;
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate 	e = uu_zalloc(sizeof (restarter_event_t));
1987c478bd9Sstevel@tonic-gate 	if (e == NULL)
1997c478bd9Sstevel@tonic-gate 		uu_die(allocfail);
2007c478bd9Sstevel@tonic-gate 	e->re_event_handle = h;
2017c478bd9Sstevel@tonic-gate 	e->re_sysevent = syse;
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate 	if (sysevent_get_attr_list(syse, &attr_list) != 0)
2047c478bd9Sstevel@tonic-gate 		uu_die(allocfail);
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate 	if ((nvlist_lookup_uint32(attr_list, RESTARTER_NAME_TYPE,
2077c478bd9Sstevel@tonic-gate 	    &(e->re_type)) != 0) ||
2087c478bd9Sstevel@tonic-gate 	    (nvlist_lookup_string(attr_list,
2097c478bd9Sstevel@tonic-gate 	    RESTARTER_NAME_INSTANCE, &(e->re_instance_name)) != 0)) {
2107c478bd9Sstevel@tonic-gate 		uu_warn("%s: Can't decode nvlist for event %p\n",
2117c478bd9Sstevel@tonic-gate 		    h->reh_restarter_name, (void *)syse);
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate 		ret = 0;
2147c478bd9Sstevel@tonic-gate 	} else {
2157c478bd9Sstevel@tonic-gate 		ret = h->reh_handler(e);
2167c478bd9Sstevel@tonic-gate 	}
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate 	uu_free(e);
2197c478bd9Sstevel@tonic-gate 	nvlist_free(attr_list);
2207c478bd9Sstevel@tonic-gate 	return (ret);
2217c478bd9Sstevel@tonic-gate }
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate /*
2247c478bd9Sstevel@tonic-gate  * restarter_bind_handle(uint32_t, char *, int (*)(restarter_event_t *), int,
2257c478bd9Sstevel@tonic-gate  *     restarter_event_handle_t **)
2267c478bd9Sstevel@tonic-gate  *
2277c478bd9Sstevel@tonic-gate  * Bind to a delegated restarter event channel.
2287c478bd9Sstevel@tonic-gate  * Each delegated restarter gets its own channel for resource management.
2297c478bd9Sstevel@tonic-gate  *
2307c478bd9Sstevel@tonic-gate  * Returns 0 on success or
2317c478bd9Sstevel@tonic-gate  *   ENOTSUP	version mismatch
2327c478bd9Sstevel@tonic-gate  *   EINVAL	restarter_name or event_handle is NULL
2337c478bd9Sstevel@tonic-gate  *   ENOMEM	out of memory, too many channels, or too many subscriptions
2347c478bd9Sstevel@tonic-gate  *   EBUSY	sysevent_evc_bind() could not establish binding
2357c478bd9Sstevel@tonic-gate  *   EFAULT	internal sysevent_evc_bind()/sysevent_evc_subscribe() error
2367c478bd9Sstevel@tonic-gate  *   EMFILE	out of file descriptors
2377c478bd9Sstevel@tonic-gate  *   EPERM	insufficient privilege for sysevent_evc_bind()
2387c478bd9Sstevel@tonic-gate  *   EEXIST	already subscribed
2397c478bd9Sstevel@tonic-gate  */
2407c478bd9Sstevel@tonic-gate int
2417c478bd9Sstevel@tonic-gate restarter_bind_handle(uint32_t version, const char *restarter_name,
2427c478bd9Sstevel@tonic-gate     int (*event_handler)(restarter_event_t *), int flags,
2437c478bd9Sstevel@tonic-gate     restarter_event_handle_t **rehp)
2447c478bd9Sstevel@tonic-gate {
2457c478bd9Sstevel@tonic-gate 	restarter_event_handle_t *h;
2467c478bd9Sstevel@tonic-gate 	size_t sz;
2477c478bd9Sstevel@tonic-gate 	int err;
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 	if (version != RESTARTER_EVENT_VERSION)
2507c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate 	if (restarter_name == NULL || event_handler == NULL)
2537c478bd9Sstevel@tonic-gate 		return (EINVAL);
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate 	if (flags & RESTARTER_FLAG_DEBUG)
2567c478bd9Sstevel@tonic-gate 		ndebug++;
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 	if ((h = uu_zalloc(sizeof (restarter_event_handle_t))) == NULL)
2597c478bd9Sstevel@tonic-gate 		return (ENOMEM);
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate 	h->reh_delegate_subscriber_id = malloc(MAX_SUBID_LEN);
2627c478bd9Sstevel@tonic-gate 	h->reh_master_subscriber_id = malloc(MAX_SUBID_LEN);
2637c478bd9Sstevel@tonic-gate 	h->reh_restarter_name = strdup(restarter_name);
2647c478bd9Sstevel@tonic-gate 	if (h->reh_delegate_subscriber_id == NULL ||
2657c478bd9Sstevel@tonic-gate 	    h->reh_master_subscriber_id == NULL ||
2667c478bd9Sstevel@tonic-gate 	    h->reh_restarter_name == NULL) {
2677c478bd9Sstevel@tonic-gate 		free_restarter_event_handle(h);
2687c478bd9Sstevel@tonic-gate 		return (ENOMEM);
2697c478bd9Sstevel@tonic-gate 	}
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate 	sz = strlcpy(h->reh_delegate_subscriber_id, "del", MAX_SUBID_LEN);
2727c478bd9Sstevel@tonic-gate 	assert(sz < MAX_SUBID_LEN);
2737c478bd9Sstevel@tonic-gate 	sz = strlcpy(h->reh_master_subscriber_id, "master", MAX_SUBID_LEN);
2747c478bd9Sstevel@tonic-gate 	assert(sz < MAX_SUBID_LEN);
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate 	h->reh_delegate_channel_name =
2777c478bd9Sstevel@tonic-gate 	    _restarter_get_channel_name(restarter_name,
2787c478bd9Sstevel@tonic-gate 	    RESTARTER_CHANNEL_DELEGATE);
2797c478bd9Sstevel@tonic-gate 	h->reh_master_channel_name =
2807c478bd9Sstevel@tonic-gate 	    _restarter_get_channel_name(restarter_name,
2817c478bd9Sstevel@tonic-gate 	    RESTARTER_CHANNEL_MASTER);
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 	if (h->reh_delegate_channel_name == NULL ||
2847c478bd9Sstevel@tonic-gate 	    h->reh_master_channel_name == NULL) {
2857c478bd9Sstevel@tonic-gate 		free_restarter_event_handle(h);
2867c478bd9Sstevel@tonic-gate 		return (ENOMEM);
2877c478bd9Sstevel@tonic-gate 	}
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate 	if (sysevent_evc_bind(h->reh_delegate_channel_name,
2907c478bd9Sstevel@tonic-gate 	    &h->reh_delegate_channel, EVCH_CREAT|EVCH_HOLD_PEND) != 0) {
2917c478bd9Sstevel@tonic-gate 		err = errno;
2927c478bd9Sstevel@tonic-gate 		assert(err != EINVAL);
2937c478bd9Sstevel@tonic-gate 		assert(err != ENOENT);
2947c478bd9Sstevel@tonic-gate 		free_restarter_event_handle(h);
2957c478bd9Sstevel@tonic-gate 		return (err);
2967c478bd9Sstevel@tonic-gate 	}
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 	if (sysevent_evc_bind(h->reh_master_channel_name,
2997c478bd9Sstevel@tonic-gate 	    &h->reh_master_channel, EVCH_CREAT|EVCH_HOLD_PEND) != 0) {
3007c478bd9Sstevel@tonic-gate 		err = errno;
3017c478bd9Sstevel@tonic-gate 		assert(err != EINVAL);
3027c478bd9Sstevel@tonic-gate 		assert(err != ENOENT);
3037c478bd9Sstevel@tonic-gate 		free_restarter_event_handle(h);
3047c478bd9Sstevel@tonic-gate 		return (err);
3057c478bd9Sstevel@tonic-gate 	}
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 	h->reh_handler = event_handler;
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate 	assert(strlen(restarter_name) <= MAX_CLASS_LEN - 1);
3107c478bd9Sstevel@tonic-gate 	assert(strlen(h->reh_delegate_subscriber_id) <= MAX_SUBID_LEN - 1);
3117c478bd9Sstevel@tonic-gate 	assert(strlen(h->reh_master_subscriber_id) <= MAX_SUBID_LEN - 1);
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate 	if (sysevent_evc_subscribe(h->reh_delegate_channel,
3147c478bd9Sstevel@tonic-gate 	    h->reh_delegate_subscriber_id, EC_ALL, cb, h, EVCH_SUB_KEEP) != 0) {
3157c478bd9Sstevel@tonic-gate 		err = errno;
3167c478bd9Sstevel@tonic-gate 		assert(err != EINVAL);
3177c478bd9Sstevel@tonic-gate 		free_restarter_event_handle(h);
3187c478bd9Sstevel@tonic-gate 		return (err);
3197c478bd9Sstevel@tonic-gate 	}
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 	*rehp = h;
3227c478bd9Sstevel@tonic-gate 	return (0);
3237c478bd9Sstevel@tonic-gate }
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate restarter_event_handle_t *
3267c478bd9Sstevel@tonic-gate restarter_event_get_handle(restarter_event_t *e)
3277c478bd9Sstevel@tonic-gate {
3287c478bd9Sstevel@tonic-gate 	assert(e != NULL && e->re_event_handle != NULL);
3297c478bd9Sstevel@tonic-gate 	return (e->re_event_handle);
3307c478bd9Sstevel@tonic-gate }
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate restarter_event_type_t
3337c478bd9Sstevel@tonic-gate restarter_event_get_type(restarter_event_t *e)
3347c478bd9Sstevel@tonic-gate {
3357c478bd9Sstevel@tonic-gate 	assert(e != NULL);
3367c478bd9Sstevel@tonic-gate 	return (e->re_type);
3377c478bd9Sstevel@tonic-gate }
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate ssize_t
3407c478bd9Sstevel@tonic-gate restarter_event_get_instance(restarter_event_t *e, char *inst, size_t sz)
3417c478bd9Sstevel@tonic-gate {
3427c478bd9Sstevel@tonic-gate 	assert(e != NULL && inst != NULL);
3437c478bd9Sstevel@tonic-gate 	return ((ssize_t)strlcpy(inst, e->re_instance_name, sz));
3447c478bd9Sstevel@tonic-gate }
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate int
3477c478bd9Sstevel@tonic-gate restarter_event_get_current_states(restarter_event_t *e,
3487c478bd9Sstevel@tonic-gate     restarter_instance_state_t *state, restarter_instance_state_t *next_state)
3497c478bd9Sstevel@tonic-gate {
3507c478bd9Sstevel@tonic-gate 	if (e == NULL)
3517c478bd9Sstevel@tonic-gate 		return (-1);
3527c478bd9Sstevel@tonic-gate 	*state = e->re_state;
3537c478bd9Sstevel@tonic-gate 	*next_state = e->re_next_state;
3547c478bd9Sstevel@tonic-gate 	return (0);
3557c478bd9Sstevel@tonic-gate }
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate /*
3582c65c8b0Srm88369  * restarter_event_publish_retry() is a wrapper around sysevent_evc_publish().
3592c65c8b0Srm88369  * In case, the event cannot be sent at the first attempt (sysevent_evc_publish
3602c65c8b0Srm88369  * returned EAGAIN - sysevent queue full), this function retries a few time
3612c65c8b0Srm88369  * and return ENOSPC if it reaches the retry limit.
3622c65c8b0Srm88369  *
3632c65c8b0Srm88369  * The arguments to this function map the arguments of sysevent_evc_publish().
3642c65c8b0Srm88369  *
3652c65c8b0Srm88369  * On success, return 0. On error, return
3662c65c8b0Srm88369  *
3672c65c8b0Srm88369  *   EFAULT - internal sysevent_evc_publish() error
3682c65c8b0Srm88369  *   ENOMEM - internal sysevent_evc_publish() error
3692c65c8b0Srm88369  *   EBADF - scp is invalid (sysevent_evc_publish() returned EINVAL)
3702c65c8b0Srm88369  *   ENOSPC - sysevent queue full (sysevent_evc_publish() returned EAGAIN)
3712c65c8b0Srm88369  */
3722c65c8b0Srm88369 int
3732c65c8b0Srm88369 restarter_event_publish_retry(evchan_t *scp, const char *class,
3742c65c8b0Srm88369     const char *subclass, const char *vendor, const char *pub_name,
3752c65c8b0Srm88369     nvlist_t *attr_list, uint32_t flags)
3762c65c8b0Srm88369 {
3772c65c8b0Srm88369 	int retries, ret;
3782c65c8b0Srm88369 	useconds_t retry_int = INITIAL_COMMIT_RETRY_INT;
3792c65c8b0Srm88369 
3802c65c8b0Srm88369 	for (retries = 0; retries < MAX_COMMIT_RETRIES; retries++) {
3812c65c8b0Srm88369 		ret = sysevent_evc_publish(scp, class, subclass, vendor,
3822c65c8b0Srm88369 		    pub_name, attr_list, flags);
3832c65c8b0Srm88369 		if (ret == 0)
3842c65c8b0Srm88369 			break;
3852c65c8b0Srm88369 
3862c65c8b0Srm88369 		switch (ret) {
3872c65c8b0Srm88369 		case EAGAIN:
3882c65c8b0Srm88369 			/* Queue is full */
3892c65c8b0Srm88369 			(void) usleep(retry_int);
3902c65c8b0Srm88369 
3912c65c8b0Srm88369 			retry_int = min(retry_int * 2, MAX_COMMIT_RETRY_INT);
3922c65c8b0Srm88369 			break;
3932c65c8b0Srm88369 
3942c65c8b0Srm88369 		case EINVAL:
3952c65c8b0Srm88369 			ret = EBADF;
3962c65c8b0Srm88369 			/* FALLTHROUGH */
3972c65c8b0Srm88369 
3982c65c8b0Srm88369 		case EFAULT:
3992c65c8b0Srm88369 		case ENOMEM:
4002c65c8b0Srm88369 			return (ret);
4012c65c8b0Srm88369 
4022c65c8b0Srm88369 		case EOVERFLOW:
4032c65c8b0Srm88369 		default:
4042c65c8b0Srm88369 			/* internal error - abort */
4052c65c8b0Srm88369 			bad_fail("sysevent_evc_publish", ret);
4062c65c8b0Srm88369 		}
4072c65c8b0Srm88369 	}
4082c65c8b0Srm88369 
4092c65c8b0Srm88369 	if (retries == MAX_COMMIT_RETRIES)
4102c65c8b0Srm88369 		ret = ENOSPC;
4112c65c8b0Srm88369 
4122c65c8b0Srm88369 	return (ret);
4132c65c8b0Srm88369 }
4142c65c8b0Srm88369 
4152c65c8b0Srm88369 /*
4167c478bd9Sstevel@tonic-gate  * Commit the state, next state, and auxiliary state into the repository.
4177c478bd9Sstevel@tonic-gate  * Let the graph engine know about the state change and error.  On success,
4187c478bd9Sstevel@tonic-gate  * return 0. On error, return
4197c478bd9Sstevel@tonic-gate  *   EINVAL - aux has spaces
4207c478bd9Sstevel@tonic-gate  *	    - inst is invalid or not an instance FMRI
4217c478bd9Sstevel@tonic-gate  *   EPROTO - librestart compiled against different libscf
4227c478bd9Sstevel@tonic-gate  *   ENOMEM - out of memory
4237c478bd9Sstevel@tonic-gate  *	    - repository server out of resources
4247c478bd9Sstevel@tonic-gate  *   ENOTACTIVE - repository server not running
4257c478bd9Sstevel@tonic-gate  *   ECONNABORTED - repository connection established, but then broken
4267c478bd9Sstevel@tonic-gate  *		  - unknown libscf error
4277c478bd9Sstevel@tonic-gate  *   ENOENT - inst does not exist in the repository
4287c478bd9Sstevel@tonic-gate  *   EPERM - insufficient permissions
4297c478bd9Sstevel@tonic-gate  *   EACCESS - backend access denied
4307c478bd9Sstevel@tonic-gate  *   EROFS - backend is readonly
4317c478bd9Sstevel@tonic-gate  *   EFAULT - internal sysevent_evc_publish() error
4327c478bd9Sstevel@tonic-gate  *   EBADF - h is invalid (sysevent_evc_publish() returned EINVAL)
4332c65c8b0Srm88369  *   ENOSPC - sysevent queue full (sysevent_evc_publish() returned EAGAIN)
4347c478bd9Sstevel@tonic-gate  */
4357c478bd9Sstevel@tonic-gate int
4367c478bd9Sstevel@tonic-gate restarter_set_states(restarter_event_handle_t *h, const char *inst,
4377c478bd9Sstevel@tonic-gate     restarter_instance_state_t cur_state,
4387c478bd9Sstevel@tonic-gate     restarter_instance_state_t new_cur_state,
4397c478bd9Sstevel@tonic-gate     restarter_instance_state_t next_state,
4407c478bd9Sstevel@tonic-gate     restarter_instance_state_t new_next_state, restarter_error_t e,
4417c478bd9Sstevel@tonic-gate     const char *aux)
4427c478bd9Sstevel@tonic-gate {
4437c478bd9Sstevel@tonic-gate 	nvlist_t *attr;
4447c478bd9Sstevel@tonic-gate 	scf_handle_t *scf_h;
4457c478bd9Sstevel@tonic-gate 	instance_data_t id;
4467c478bd9Sstevel@tonic-gate 	int ret = 0;
4477c478bd9Sstevel@tonic-gate 	char *p = (char *)aux;
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate 	assert(h->reh_master_channel != NULL);
4507c478bd9Sstevel@tonic-gate 	assert(h->reh_master_channel_name != NULL);
4517c478bd9Sstevel@tonic-gate 	assert(h->reh_master_subscriber_id != NULL);
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate 	/* Validate format of auxiliary state: no spaces allowed */
454ba91983eSlianep 	if (p != NULL) {
455ba91983eSlianep 		while (*p != '\0') {
4567c478bd9Sstevel@tonic-gate 			if (isspace(*p))
4577c478bd9Sstevel@tonic-gate 				return (EINVAL);
4587c478bd9Sstevel@tonic-gate 			p++;
4597c478bd9Sstevel@tonic-gate 		}
460ba91983eSlianep 	}
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate 	if ((scf_h = scf_handle_create(SCF_VERSION)) == NULL) {
4637c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
4647c478bd9Sstevel@tonic-gate 		case SCF_ERROR_VERSION_MISMATCH:
4657c478bd9Sstevel@tonic-gate 			return (EPROTO);
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NO_MEMORY:
4687c478bd9Sstevel@tonic-gate 			return (ENOMEM);
4697c478bd9Sstevel@tonic-gate 
4707c478bd9Sstevel@tonic-gate 		default:
4717c478bd9Sstevel@tonic-gate 			bad_fail("scf_handle_create", scf_error());
4727c478bd9Sstevel@tonic-gate 		}
4737c478bd9Sstevel@tonic-gate 	}
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate 	if (scf_handle_bind(scf_h) == -1) {
4767c478bd9Sstevel@tonic-gate 		scf_handle_destroy(scf_h);
4777c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
4787c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NO_SERVER:
4797c478bd9Sstevel@tonic-gate 			return (ENOTACTIVE);
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NO_RESOURCES:
4827c478bd9Sstevel@tonic-gate 			return (ENOMEM);
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate 		case SCF_ERROR_INVALID_ARGUMENT:
4857c478bd9Sstevel@tonic-gate 		case SCF_ERROR_IN_USE:
4867c478bd9Sstevel@tonic-gate 		default:
4877c478bd9Sstevel@tonic-gate 			bad_fail("scf_handle_bind", scf_error());
4887c478bd9Sstevel@tonic-gate 		}
4897c478bd9Sstevel@tonic-gate 	}
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate 	if (nvlist_alloc(&attr, NV_UNIQUE_NAME, 0) != 0 ||
4927c478bd9Sstevel@tonic-gate 	    nvlist_add_int32(attr, RESTARTER_NAME_STATE, new_cur_state) != 0 ||
4937c478bd9Sstevel@tonic-gate 	    nvlist_add_int32(attr, RESTARTER_NAME_NEXT_STATE, new_next_state)
4947c478bd9Sstevel@tonic-gate 	    != 0 ||
4957c478bd9Sstevel@tonic-gate 	    nvlist_add_int32(attr, RESTARTER_NAME_ERROR, e) != 0 ||
4967c478bd9Sstevel@tonic-gate 	    nvlist_add_string(attr, RESTARTER_NAME_INSTANCE, inst) != 0) {
4977c478bd9Sstevel@tonic-gate 		ret = ENOMEM;
4982c65c8b0Srm88369 	} else {
4997c478bd9Sstevel@tonic-gate 		id.i_fmri = inst;
5007c478bd9Sstevel@tonic-gate 		id.i_state = cur_state;
5017c478bd9Sstevel@tonic-gate 		id.i_next_state = next_state;
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate 		ret = _restarter_commit_states(scf_h, &id, new_cur_state,
5047c478bd9Sstevel@tonic-gate 		    new_next_state, aux);
5057c478bd9Sstevel@tonic-gate 
5062c65c8b0Srm88369 		if (ret == 0) {
5072c65c8b0Srm88369 			ret = restarter_event_publish_retry(
5082c65c8b0Srm88369 			    h->reh_master_channel, "master", "state_change",
5092c65c8b0Srm88369 			    "com.sun", "librestart", attr, EVCH_NOSLEEP);
5107c478bd9Sstevel@tonic-gate 		}
5117c478bd9Sstevel@tonic-gate 	}
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate 	nvlist_free(attr);
5147c478bd9Sstevel@tonic-gate 	(void) scf_handle_unbind(scf_h);
5157c478bd9Sstevel@tonic-gate 	scf_handle_destroy(scf_h);
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate 	return (ret);
5187c478bd9Sstevel@tonic-gate }
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate restarter_instance_state_t
5217c478bd9Sstevel@tonic-gate restarter_string_to_state(char *string)
5227c478bd9Sstevel@tonic-gate {
5237c478bd9Sstevel@tonic-gate 	assert(string != NULL);
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate 	if (strcmp(string, SCF_STATE_STRING_NONE) == 0)
5267c478bd9Sstevel@tonic-gate 		return (RESTARTER_STATE_NONE);
5277c478bd9Sstevel@tonic-gate 	else if (strcmp(string, SCF_STATE_STRING_UNINIT) == 0)
5287c478bd9Sstevel@tonic-gate 		return (RESTARTER_STATE_UNINIT);
5297c478bd9Sstevel@tonic-gate 	else if (strcmp(string, SCF_STATE_STRING_MAINT) == 0)
5307c478bd9Sstevel@tonic-gate 		return (RESTARTER_STATE_MAINT);
5317c478bd9Sstevel@tonic-gate 	else if (strcmp(string, SCF_STATE_STRING_OFFLINE) == 0)
5327c478bd9Sstevel@tonic-gate 		return (RESTARTER_STATE_OFFLINE);
5337c478bd9Sstevel@tonic-gate 	else if (strcmp(string, SCF_STATE_STRING_DISABLED) == 0)
5347c478bd9Sstevel@tonic-gate 		return (RESTARTER_STATE_DISABLED);
5357c478bd9Sstevel@tonic-gate 	else if (strcmp(string, SCF_STATE_STRING_ONLINE) == 0)
5367c478bd9Sstevel@tonic-gate 		return (RESTARTER_STATE_ONLINE);
5377c478bd9Sstevel@tonic-gate 	else if (strcmp(string, SCF_STATE_STRING_DEGRADED) == 0)
5387c478bd9Sstevel@tonic-gate 		return (RESTARTER_STATE_DEGRADED);
5397c478bd9Sstevel@tonic-gate 	else {
5407c478bd9Sstevel@tonic-gate 		return (RESTARTER_STATE_NONE);
5417c478bd9Sstevel@tonic-gate 	}
5427c478bd9Sstevel@tonic-gate }
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate ssize_t
5457c478bd9Sstevel@tonic-gate restarter_state_to_string(restarter_instance_state_t state, char *string,
5467c478bd9Sstevel@tonic-gate     size_t len)
5477c478bd9Sstevel@tonic-gate {
5487c478bd9Sstevel@tonic-gate 	assert(string != NULL);
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate 	if (state == RESTARTER_STATE_NONE)
5517c478bd9Sstevel@tonic-gate 		return ((ssize_t)strlcpy(string, SCF_STATE_STRING_NONE, len));
5527c478bd9Sstevel@tonic-gate 	else if (state == RESTARTER_STATE_UNINIT)
5537c478bd9Sstevel@tonic-gate 		return ((ssize_t)strlcpy(string, SCF_STATE_STRING_UNINIT, len));
5547c478bd9Sstevel@tonic-gate 	else if (state == RESTARTER_STATE_MAINT)
5557c478bd9Sstevel@tonic-gate 		return ((ssize_t)strlcpy(string, SCF_STATE_STRING_MAINT, len));
5567c478bd9Sstevel@tonic-gate 	else if (state == RESTARTER_STATE_OFFLINE)
5577c478bd9Sstevel@tonic-gate 		return ((ssize_t)strlcpy(string, SCF_STATE_STRING_OFFLINE,
5587c478bd9Sstevel@tonic-gate 		    len));
5597c478bd9Sstevel@tonic-gate 	else if (state == RESTARTER_STATE_DISABLED)
5607c478bd9Sstevel@tonic-gate 		return ((ssize_t)strlcpy(string, SCF_STATE_STRING_DISABLED,
5617c478bd9Sstevel@tonic-gate 		    len));
5627c478bd9Sstevel@tonic-gate 	else if (state == RESTARTER_STATE_ONLINE)
5637c478bd9Sstevel@tonic-gate 		return ((ssize_t)strlcpy(string, SCF_STATE_STRING_ONLINE, len));
5647c478bd9Sstevel@tonic-gate 	else if (state == RESTARTER_STATE_DEGRADED)
5657c478bd9Sstevel@tonic-gate 		return ((ssize_t)strlcpy(string, SCF_STATE_STRING_DEGRADED,
5667c478bd9Sstevel@tonic-gate 		    len));
5677c478bd9Sstevel@tonic-gate 	else
5687c478bd9Sstevel@tonic-gate 		return ((ssize_t)strlcpy(string, "unknown", len));
5697c478bd9Sstevel@tonic-gate }
5707c478bd9Sstevel@tonic-gate 
5717c478bd9Sstevel@tonic-gate /*
5727c478bd9Sstevel@tonic-gate  * Sets pg to the name property group of s_inst.  If it doesn't exist, it is
5737c478bd9Sstevel@tonic-gate  * added.
5747c478bd9Sstevel@tonic-gate  *
5757c478bd9Sstevel@tonic-gate  * Fails with
5767c478bd9Sstevel@tonic-gate  *   ECONNABORTED - repository disconnection or unknown libscf error
5777c478bd9Sstevel@tonic-gate  *   EBADF - inst is not set
5787c478bd9Sstevel@tonic-gate  *   ECANCELED - inst is deleted
5797c478bd9Sstevel@tonic-gate  *   EPERM - permission is denied
5807c478bd9Sstevel@tonic-gate  *   EACCES - backend denied access
5817c478bd9Sstevel@tonic-gate  *   EROFS - backend readonly
5827c478bd9Sstevel@tonic-gate  */
5837c478bd9Sstevel@tonic-gate static int
5847c478bd9Sstevel@tonic-gate instance_get_or_add_pg(scf_instance_t *inst, const char *name,
5857c478bd9Sstevel@tonic-gate     const char *type, uint32_t flags, scf_propertygroup_t *pg)
5867c478bd9Sstevel@tonic-gate {
5877c478bd9Sstevel@tonic-gate again:
5887c478bd9Sstevel@tonic-gate 	if (scf_instance_get_pg(inst, name, pg) == 0)
5897c478bd9Sstevel@tonic-gate 		return (0);
5907c478bd9Sstevel@tonic-gate 
5917c478bd9Sstevel@tonic-gate 	switch (scf_error()) {
5927c478bd9Sstevel@tonic-gate 	case SCF_ERROR_CONNECTION_BROKEN:
5937c478bd9Sstevel@tonic-gate 	default:
5947c478bd9Sstevel@tonic-gate 		return (ECONNABORTED);
5957c478bd9Sstevel@tonic-gate 
5967c478bd9Sstevel@tonic-gate 	case SCF_ERROR_NOT_SET:
5977c478bd9Sstevel@tonic-gate 		return (EBADF);
5987c478bd9Sstevel@tonic-gate 
5997c478bd9Sstevel@tonic-gate 	case SCF_ERROR_DELETED:
6007c478bd9Sstevel@tonic-gate 		return (ECANCELED);
6017c478bd9Sstevel@tonic-gate 
6027c478bd9Sstevel@tonic-gate 	case SCF_ERROR_NOT_FOUND:
6037c478bd9Sstevel@tonic-gate 		break;
6047c478bd9Sstevel@tonic-gate 
6057c478bd9Sstevel@tonic-gate 	case SCF_ERROR_HANDLE_MISMATCH:
6067c478bd9Sstevel@tonic-gate 	case SCF_ERROR_INVALID_ARGUMENT:
6077c478bd9Sstevel@tonic-gate 		bad_fail("scf_instance_get_pg", scf_error());
6087c478bd9Sstevel@tonic-gate 	}
6097c478bd9Sstevel@tonic-gate 
6107c478bd9Sstevel@tonic-gate 	if (scf_instance_add_pg(inst, name, type, flags, pg) == 0)
6117c478bd9Sstevel@tonic-gate 		return (0);
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate 	switch (scf_error()) {
6147c478bd9Sstevel@tonic-gate 	case SCF_ERROR_CONNECTION_BROKEN:
6157c478bd9Sstevel@tonic-gate 	default:
6167c478bd9Sstevel@tonic-gate 		return (ECONNABORTED);
6177c478bd9Sstevel@tonic-gate 
6187c478bd9Sstevel@tonic-gate 	case SCF_ERROR_DELETED:
6197c478bd9Sstevel@tonic-gate 		return (ECANCELED);
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate 	case SCF_ERROR_EXISTS:
6227c478bd9Sstevel@tonic-gate 		goto again;
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate 	case SCF_ERROR_PERMISSION_DENIED:
6257c478bd9Sstevel@tonic-gate 		return (EPERM);
6267c478bd9Sstevel@tonic-gate 
6277c478bd9Sstevel@tonic-gate 	case SCF_ERROR_BACKEND_ACCESS:
6287c478bd9Sstevel@tonic-gate 		return (EACCES);
6297c478bd9Sstevel@tonic-gate 
6307c478bd9Sstevel@tonic-gate 	case SCF_ERROR_BACKEND_READONLY:
6317c478bd9Sstevel@tonic-gate 		return (EROFS);
6327c478bd9Sstevel@tonic-gate 
6337c478bd9Sstevel@tonic-gate 	case SCF_ERROR_HANDLE_MISMATCH:
6347c478bd9Sstevel@tonic-gate 	case SCF_ERROR_INVALID_ARGUMENT:
6357c478bd9Sstevel@tonic-gate 	case SCF_ERROR_NOT_SET:			/* should be caught above */
6367c478bd9Sstevel@tonic-gate 		bad_fail("scf_instance_add_pg", scf_error());
6377c478bd9Sstevel@tonic-gate 	}
6387c478bd9Sstevel@tonic-gate 
6397c478bd9Sstevel@tonic-gate 	return (0);
6407c478bd9Sstevel@tonic-gate }
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate /*
6437c478bd9Sstevel@tonic-gate  * Fails with
6447c478bd9Sstevel@tonic-gate  *   ECONNABORTED
6457c478bd9Sstevel@tonic-gate  *   ECANCELED - pg was deleted
6467c478bd9Sstevel@tonic-gate  */
6477c478bd9Sstevel@tonic-gate static int
6487c478bd9Sstevel@tonic-gate tx_set_value(scf_transaction_t *tx, scf_transaction_entry_t *ent,
6497c478bd9Sstevel@tonic-gate     const char *pname, scf_type_t ty, scf_value_t *val)
6507c478bd9Sstevel@tonic-gate {
6517c478bd9Sstevel@tonic-gate 	int r;
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate 	for (;;) {
6547c478bd9Sstevel@tonic-gate 		if (scf_transaction_property_change_type(tx, ent, pname,
6557c478bd9Sstevel@tonic-gate 		    ty) == 0)
6567c478bd9Sstevel@tonic-gate 			break;
6577c478bd9Sstevel@tonic-gate 
6587c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
6597c478bd9Sstevel@tonic-gate 		case SCF_ERROR_CONNECTION_BROKEN:
6607c478bd9Sstevel@tonic-gate 		default:
6617c478bd9Sstevel@tonic-gate 			return (ECONNABORTED);
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
6647c478bd9Sstevel@tonic-gate 			return (ECANCELED);
6657c478bd9Sstevel@tonic-gate 
6667c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
6677c478bd9Sstevel@tonic-gate 			break;
6687c478bd9Sstevel@tonic-gate 
6697c478bd9Sstevel@tonic-gate 		case SCF_ERROR_HANDLE_MISMATCH:
6707c478bd9Sstevel@tonic-gate 		case SCF_ERROR_INVALID_ARGUMENT:
6717c478bd9Sstevel@tonic-gate 		case SCF_ERROR_IN_USE:
6727c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
6737c478bd9Sstevel@tonic-gate 			bad_fail("scf_transaction_property_change_type",
6747c478bd9Sstevel@tonic-gate 			    scf_error());
6757c478bd9Sstevel@tonic-gate 		}
6767c478bd9Sstevel@tonic-gate 
6777c478bd9Sstevel@tonic-gate 		if (scf_transaction_property_new(tx, ent, pname, ty) == 0)
6787c478bd9Sstevel@tonic-gate 			break;
6797c478bd9Sstevel@tonic-gate 
6807c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
6817c478bd9Sstevel@tonic-gate 		case SCF_ERROR_CONNECTION_BROKEN:
6827c478bd9Sstevel@tonic-gate 		default:
6837c478bd9Sstevel@tonic-gate 			return (ECONNABORTED);
6847c478bd9Sstevel@tonic-gate 
6857c478bd9Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
6867c478bd9Sstevel@tonic-gate 			return (ECANCELED);
6877c478bd9Sstevel@tonic-gate 
6887c478bd9Sstevel@tonic-gate 		case SCF_ERROR_EXISTS:
6897c478bd9Sstevel@tonic-gate 			break;
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate 		case SCF_ERROR_HANDLE_MISMATCH:
6927c478bd9Sstevel@tonic-gate 		case SCF_ERROR_INVALID_ARGUMENT:
6937c478bd9Sstevel@tonic-gate 		case SCF_ERROR_IN_USE:
6947c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
6957c478bd9Sstevel@tonic-gate 			bad_fail("scf_transaction_property_new", scf_error());
6967c478bd9Sstevel@tonic-gate 		}
6977c478bd9Sstevel@tonic-gate 	}
6987c478bd9Sstevel@tonic-gate 
6997c478bd9Sstevel@tonic-gate 	r = scf_entry_add_value(ent, val);
7007c478bd9Sstevel@tonic-gate 	assert(r == 0);
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate 	return (0);
7037c478bd9Sstevel@tonic-gate }
7047c478bd9Sstevel@tonic-gate 
7057c478bd9Sstevel@tonic-gate /*
7067c478bd9Sstevel@tonic-gate  * Commit new_state, new_next_state, and aux to the repository for id.  If
7077c478bd9Sstevel@tonic-gate  * successful, also set id's state and next-state as given, and return 0.
7087c478bd9Sstevel@tonic-gate  * Fails with
7097c478bd9Sstevel@tonic-gate  *   ENOMEM - out of memory
7107c478bd9Sstevel@tonic-gate  *   ECONNABORTED - repository connection broken
7117c478bd9Sstevel@tonic-gate  *		  - unknown libscf error
7127c478bd9Sstevel@tonic-gate  *   EINVAL - id->i_fmri is invalid or not an instance FMRI
7137c478bd9Sstevel@tonic-gate  *   ENOENT - id->i_fmri does not exist
7147c478bd9Sstevel@tonic-gate  *   EPERM - insufficient permissions
7157c478bd9Sstevel@tonic-gate  *   EACCES - backend access denied
7167c478bd9Sstevel@tonic-gate  *   EROFS - backend is readonly
7177c478bd9Sstevel@tonic-gate  */
7187c478bd9Sstevel@tonic-gate int
7197c478bd9Sstevel@tonic-gate _restarter_commit_states(scf_handle_t *h, instance_data_t *id,
7207c478bd9Sstevel@tonic-gate     restarter_instance_state_t new_state,
7217c478bd9Sstevel@tonic-gate     restarter_instance_state_t new_state_next, const char *aux)
7227c478bd9Sstevel@tonic-gate {
7237c478bd9Sstevel@tonic-gate 	char str_state[MAX_SCF_STATE_STRING_SZ];
7247c478bd9Sstevel@tonic-gate 	char str_new_state[MAX_SCF_STATE_STRING_SZ];
7257c478bd9Sstevel@tonic-gate 	char str_state_next[MAX_SCF_STATE_STRING_SZ];
7267c478bd9Sstevel@tonic-gate 	char str_new_state_next[MAX_SCF_STATE_STRING_SZ];
7277c478bd9Sstevel@tonic-gate 	int ret = 0, r;
7287c478bd9Sstevel@tonic-gate 	struct timeval now;
7297c478bd9Sstevel@tonic-gate 	ssize_t sz;
7307c478bd9Sstevel@tonic-gate 
7317c478bd9Sstevel@tonic-gate 	scf_transaction_t *t = NULL;
7327c478bd9Sstevel@tonic-gate 	scf_transaction_entry_t *t_state = NULL, *t_state_next = NULL;
7337c478bd9Sstevel@tonic-gate 	scf_transaction_entry_t *t_stime = NULL, *t_aux = NULL;
7347c478bd9Sstevel@tonic-gate 	scf_value_t *v_state = NULL, *v_state_next = NULL, *v_stime = NULL;
7357c478bd9Sstevel@tonic-gate 	scf_value_t *v_aux = NULL;
7367c478bd9Sstevel@tonic-gate 	scf_instance_t *s_inst = NULL;
7377c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg = NULL;
7387c478bd9Sstevel@tonic-gate 
7397c478bd9Sstevel@tonic-gate 	assert(new_state != RESTARTER_STATE_NONE);
7407c478bd9Sstevel@tonic-gate 
7417c478bd9Sstevel@tonic-gate 	if ((s_inst = scf_instance_create(h)) == NULL ||
7427c478bd9Sstevel@tonic-gate 	    (pg = scf_pg_create(h)) == NULL ||
7437c478bd9Sstevel@tonic-gate 	    (t = scf_transaction_create(h)) == NULL ||
7447c478bd9Sstevel@tonic-gate 	    (t_state = scf_entry_create(h)) == NULL ||
7457c478bd9Sstevel@tonic-gate 	    (t_state_next = scf_entry_create(h)) == NULL ||
7467c478bd9Sstevel@tonic-gate 	    (t_stime = scf_entry_create(h)) == NULL ||
7477c478bd9Sstevel@tonic-gate 	    (t_aux = scf_entry_create(h)) == NULL ||
7487c478bd9Sstevel@tonic-gate 	    (v_state = scf_value_create(h)) == NULL ||
7497c478bd9Sstevel@tonic-gate 	    (v_state_next = scf_value_create(h)) == NULL ||
7507c478bd9Sstevel@tonic-gate 	    (v_stime = scf_value_create(h)) == NULL ||
7517c478bd9Sstevel@tonic-gate 	    (v_aux = scf_value_create(h)) == NULL) {
7527c478bd9Sstevel@tonic-gate 		ret = ENOMEM;
7537c478bd9Sstevel@tonic-gate 		goto out;
7547c478bd9Sstevel@tonic-gate 	}
7557c478bd9Sstevel@tonic-gate 
7567c478bd9Sstevel@tonic-gate 	sz = restarter_state_to_string(new_state, str_new_state,
7577c478bd9Sstevel@tonic-gate 	    sizeof (str_new_state));
7587c478bd9Sstevel@tonic-gate 	assert(sz < sizeof (str_new_state));
7597c478bd9Sstevel@tonic-gate 	sz = restarter_state_to_string(new_state_next, str_new_state_next,
7607c478bd9Sstevel@tonic-gate 	    sizeof (str_new_state_next));
7617c478bd9Sstevel@tonic-gate 	assert(sz < sizeof (str_new_state_next));
7627c478bd9Sstevel@tonic-gate 	sz = restarter_state_to_string(id->i_state, str_state,
7637c478bd9Sstevel@tonic-gate 	    sizeof (str_state));
7647c478bd9Sstevel@tonic-gate 	assert(sz < sizeof (str_state));
7657c478bd9Sstevel@tonic-gate 	sz = restarter_state_to_string(id->i_next_state, str_state_next,
7667c478bd9Sstevel@tonic-gate 	    sizeof (str_state_next));
7677c478bd9Sstevel@tonic-gate 	assert(sz < sizeof (str_state_next));
7687c478bd9Sstevel@tonic-gate 
7697c478bd9Sstevel@tonic-gate 	ret = gettimeofday(&now, NULL);
7707c478bd9Sstevel@tonic-gate 	assert(ret != -1);
7717c478bd9Sstevel@tonic-gate 
7727c478bd9Sstevel@tonic-gate 	if (scf_handle_decode_fmri(h, id->i_fmri, NULL, NULL, s_inst,
7737c478bd9Sstevel@tonic-gate 	    NULL, NULL, SCF_DECODE_FMRI_EXACT) == -1) {
7747c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
7757c478bd9Sstevel@tonic-gate 		case SCF_ERROR_CONNECTION_BROKEN:
7767c478bd9Sstevel@tonic-gate 		default:
7777c478bd9Sstevel@tonic-gate 			ret = ECONNABORTED;
7787c478bd9Sstevel@tonic-gate 			break;
7797c478bd9Sstevel@tonic-gate 
7807c478bd9Sstevel@tonic-gate 		case SCF_ERROR_INVALID_ARGUMENT:
7817c478bd9Sstevel@tonic-gate 		case SCF_ERROR_CONSTRAINT_VIOLATED:
7827c478bd9Sstevel@tonic-gate 			ret = EINVAL;
7837c478bd9Sstevel@tonic-gate 			break;
7847c478bd9Sstevel@tonic-gate 
7857c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
7867c478bd9Sstevel@tonic-gate 			ret = ENOENT;
7877c478bd9Sstevel@tonic-gate 			break;
7887c478bd9Sstevel@tonic-gate 
7897c478bd9Sstevel@tonic-gate 		case SCF_ERROR_HANDLE_MISMATCH:
7907c478bd9Sstevel@tonic-gate 			bad_fail("scf_handle_decode_fmri", scf_error());
7917c478bd9Sstevel@tonic-gate 		}
7927c478bd9Sstevel@tonic-gate 		goto out;
7937c478bd9Sstevel@tonic-gate 	}
7947c478bd9Sstevel@tonic-gate 
7957c478bd9Sstevel@tonic-gate 
7967c478bd9Sstevel@tonic-gate 	if (scf_value_set_astring(v_state, str_new_state) != 0 ||
797*eb1a3463STruong Nguyen 	    scf_value_set_astring(v_state_next, str_new_state_next) != 0)
7987c478bd9Sstevel@tonic-gate 		bad_fail("scf_value_set_astring", scf_error());
7997c478bd9Sstevel@tonic-gate 
800*eb1a3463STruong Nguyen 	if (aux) {
801*eb1a3463STruong Nguyen 		if (scf_value_set_astring(v_aux, aux) != 0)
802*eb1a3463STruong Nguyen 			bad_fail("scf_value_set_astring", scf_error());
803*eb1a3463STruong Nguyen 	}
804*eb1a3463STruong Nguyen 
8057c478bd9Sstevel@tonic-gate 	if (scf_value_set_time(v_stime, now.tv_sec, now.tv_usec * 1000) != 0)
8067c478bd9Sstevel@tonic-gate 		bad_fail("scf_value_set_time", scf_error());
8077c478bd9Sstevel@tonic-gate 
8087c478bd9Sstevel@tonic-gate add_pg:
8097c478bd9Sstevel@tonic-gate 	switch (r = instance_get_or_add_pg(s_inst, SCF_PG_RESTARTER,
8107c478bd9Sstevel@tonic-gate 	    SCF_PG_RESTARTER_TYPE, SCF_PG_RESTARTER_FLAGS, pg)) {
8117c478bd9Sstevel@tonic-gate 	case 0:
8127c478bd9Sstevel@tonic-gate 		break;
8137c478bd9Sstevel@tonic-gate 
8147c478bd9Sstevel@tonic-gate 	case ECONNABORTED:
8157c478bd9Sstevel@tonic-gate 	case EPERM:
8167c478bd9Sstevel@tonic-gate 	case EACCES:
8177c478bd9Sstevel@tonic-gate 	case EROFS:
8187c478bd9Sstevel@tonic-gate 		ret = r;
8197c478bd9Sstevel@tonic-gate 		goto out;
8207c478bd9Sstevel@tonic-gate 
8217c478bd9Sstevel@tonic-gate 	case ECANCELED:
8227c478bd9Sstevel@tonic-gate 		ret = ENOENT;
8237c478bd9Sstevel@tonic-gate 		goto out;
8247c478bd9Sstevel@tonic-gate 
8257c478bd9Sstevel@tonic-gate 	case EBADF:
8267c478bd9Sstevel@tonic-gate 	default:
8277c478bd9Sstevel@tonic-gate 		bad_fail("instance_get_or_add_pg", r);
8287c478bd9Sstevel@tonic-gate 	}
8297c478bd9Sstevel@tonic-gate 
8307c478bd9Sstevel@tonic-gate 	for (;;) {
8317c478bd9Sstevel@tonic-gate 		if (scf_transaction_start(t, pg) != 0) {
8327c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
8337c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
8347c478bd9Sstevel@tonic-gate 			default:
8357c478bd9Sstevel@tonic-gate 				ret = ECONNABORTED;
8367c478bd9Sstevel@tonic-gate 				goto out;
8377c478bd9Sstevel@tonic-gate 
8387c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
8397c478bd9Sstevel@tonic-gate 				goto add_pg;
8407c478bd9Sstevel@tonic-gate 
8417c478bd9Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
8427c478bd9Sstevel@tonic-gate 				ret = EPERM;
8437c478bd9Sstevel@tonic-gate 				goto out;
8447c478bd9Sstevel@tonic-gate 
8457c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_ACCESS:
8467c478bd9Sstevel@tonic-gate 				ret = EACCES;
8477c478bd9Sstevel@tonic-gate 				goto out;
8487c478bd9Sstevel@tonic-gate 
8497c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_READONLY:
8507c478bd9Sstevel@tonic-gate 				ret = EROFS;
8517c478bd9Sstevel@tonic-gate 				goto out;
8527c478bd9Sstevel@tonic-gate 
8537c478bd9Sstevel@tonic-gate 			case SCF_ERROR_HANDLE_MISMATCH:
8547c478bd9Sstevel@tonic-gate 			case SCF_ERROR_IN_USE:
8557c478bd9Sstevel@tonic-gate 				bad_fail("scf_transaction_start", scf_error());
8567c478bd9Sstevel@tonic-gate 			}
8577c478bd9Sstevel@tonic-gate 		}
8587c478bd9Sstevel@tonic-gate 
8597c478bd9Sstevel@tonic-gate 		if ((r = tx_set_value(t, t_state, SCF_PROPERTY_STATE,
8607c478bd9Sstevel@tonic-gate 		    SCF_TYPE_ASTRING, v_state)) != 0 ||
8617c478bd9Sstevel@tonic-gate 		    (r = tx_set_value(t, t_state_next, SCF_PROPERTY_NEXT_STATE,
8627c478bd9Sstevel@tonic-gate 		    SCF_TYPE_ASTRING, v_state_next)) != 0 ||
8637c478bd9Sstevel@tonic-gate 		    (r = tx_set_value(t, t_stime, SCF_PROPERTY_STATE_TIMESTAMP,
8647c478bd9Sstevel@tonic-gate 		    SCF_TYPE_TIME, v_stime)) != 0) {
8657c478bd9Sstevel@tonic-gate 			switch (r) {
8667c478bd9Sstevel@tonic-gate 			case ECONNABORTED:
8677c478bd9Sstevel@tonic-gate 				ret = ECONNABORTED;
8687c478bd9Sstevel@tonic-gate 				goto out;
8697c478bd9Sstevel@tonic-gate 
8707c478bd9Sstevel@tonic-gate 			case ECANCELED:
8717c478bd9Sstevel@tonic-gate 				scf_transaction_reset(t);
8727c478bd9Sstevel@tonic-gate 				goto add_pg;
8737c478bd9Sstevel@tonic-gate 
8747c478bd9Sstevel@tonic-gate 			default:
8757c478bd9Sstevel@tonic-gate 				bad_fail("tx_set_value", r);
8767c478bd9Sstevel@tonic-gate 			}
8777c478bd9Sstevel@tonic-gate 		}
8787c478bd9Sstevel@tonic-gate 
879*eb1a3463STruong Nguyen 		if (aux) {
880*eb1a3463STruong Nguyen 			if ((r = tx_set_value(t, t_aux, SCF_PROPERTY_AUX_STATE,
881*eb1a3463STruong Nguyen 			    SCF_TYPE_ASTRING, v_aux)) != 0) {
882*eb1a3463STruong Nguyen 				switch (r) {
883*eb1a3463STruong Nguyen 				case ECONNABORTED:
884*eb1a3463STruong Nguyen 					ret = ECONNABORTED;
885*eb1a3463STruong Nguyen 					goto out;
886*eb1a3463STruong Nguyen 
887*eb1a3463STruong Nguyen 				case ECANCELED:
888*eb1a3463STruong Nguyen 					scf_transaction_reset(t);
889*eb1a3463STruong Nguyen 					goto add_pg;
890*eb1a3463STruong Nguyen 
891*eb1a3463STruong Nguyen 				default:
892*eb1a3463STruong Nguyen 					bad_fail("tx_set_value", r);
893*eb1a3463STruong Nguyen 				}
894*eb1a3463STruong Nguyen 			}
895*eb1a3463STruong Nguyen 		}
896*eb1a3463STruong Nguyen 
8977c478bd9Sstevel@tonic-gate 		ret = scf_transaction_commit(t);
8987c478bd9Sstevel@tonic-gate 		if (ret == 1)
8997c478bd9Sstevel@tonic-gate 			break;
9007c478bd9Sstevel@tonic-gate 		if (ret == -1) {
9017c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
9027c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
9037c478bd9Sstevel@tonic-gate 			default:
9047c478bd9Sstevel@tonic-gate 				ret = ECONNABORTED;
9057c478bd9Sstevel@tonic-gate 				goto out;
9067c478bd9Sstevel@tonic-gate 
9077c478bd9Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
9087c478bd9Sstevel@tonic-gate 				ret = EPERM;
9097c478bd9Sstevel@tonic-gate 				goto out;
9107c478bd9Sstevel@tonic-gate 
9117c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_ACCESS:
9127c478bd9Sstevel@tonic-gate 				ret = EACCES;
9137c478bd9Sstevel@tonic-gate 				goto out;
9147c478bd9Sstevel@tonic-gate 
9157c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_READONLY:
9167c478bd9Sstevel@tonic-gate 				ret = EROFS;
9177c478bd9Sstevel@tonic-gate 				goto out;
9187c478bd9Sstevel@tonic-gate 
9197c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
9207c478bd9Sstevel@tonic-gate 				bad_fail("scf_transaction_commit", scf_error());
9217c478bd9Sstevel@tonic-gate 			}
9227c478bd9Sstevel@tonic-gate 		}
9237c478bd9Sstevel@tonic-gate 
9247c478bd9Sstevel@tonic-gate 		scf_transaction_reset(t);
9257c478bd9Sstevel@tonic-gate 		if (scf_pg_update(pg) == -1) {
9267c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
9277c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
9287c478bd9Sstevel@tonic-gate 			default:
9297c478bd9Sstevel@tonic-gate 				ret = ECONNABORTED;
9307c478bd9Sstevel@tonic-gate 				goto out;
9317c478bd9Sstevel@tonic-gate 
9327c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
9337c478bd9Sstevel@tonic-gate 				goto add_pg;
9347c478bd9Sstevel@tonic-gate 			}
9357c478bd9Sstevel@tonic-gate 		}
9367c478bd9Sstevel@tonic-gate 	}
9377c478bd9Sstevel@tonic-gate 
9387c478bd9Sstevel@tonic-gate 	id->i_state = new_state;
9397c478bd9Sstevel@tonic-gate 	id->i_next_state = new_state_next;
9407c478bd9Sstevel@tonic-gate 	ret = 0;
9417c478bd9Sstevel@tonic-gate 
9427c478bd9Sstevel@tonic-gate out:
9437c478bd9Sstevel@tonic-gate 	scf_transaction_destroy(t);
9447c478bd9Sstevel@tonic-gate 	scf_entry_destroy(t_state);
9457c478bd9Sstevel@tonic-gate 	scf_entry_destroy(t_state_next);
9467c478bd9Sstevel@tonic-gate 	scf_entry_destroy(t_stime);
9477c478bd9Sstevel@tonic-gate 	scf_entry_destroy(t_aux);
9487c478bd9Sstevel@tonic-gate 	scf_value_destroy(v_state);
9497c478bd9Sstevel@tonic-gate 	scf_value_destroy(v_state_next);
9507c478bd9Sstevel@tonic-gate 	scf_value_destroy(v_stime);
9517c478bd9Sstevel@tonic-gate 	scf_value_destroy(v_aux);
9527c478bd9Sstevel@tonic-gate 	scf_pg_destroy(pg);
9537c478bd9Sstevel@tonic-gate 	scf_instance_destroy(s_inst);
9547c478bd9Sstevel@tonic-gate 
9557c478bd9Sstevel@tonic-gate 	return (ret);
9567c478bd9Sstevel@tonic-gate }
9577c478bd9Sstevel@tonic-gate 
9587c478bd9Sstevel@tonic-gate /*
9597c478bd9Sstevel@tonic-gate  * Fails with
9607c478bd9Sstevel@tonic-gate  *   EINVAL - type is invalid
9617c478bd9Sstevel@tonic-gate  *   ENOMEM
9627c478bd9Sstevel@tonic-gate  *   ECONNABORTED - repository connection broken
9637c478bd9Sstevel@tonic-gate  *   EBADF - s_inst is not set
9647c478bd9Sstevel@tonic-gate  *   ECANCELED - s_inst is deleted
9657c478bd9Sstevel@tonic-gate  *   EPERM - permission denied
9667c478bd9Sstevel@tonic-gate  *   EACCES - backend access denied
9677c478bd9Sstevel@tonic-gate  *   EROFS - backend readonly
9687c478bd9Sstevel@tonic-gate  */
9697c478bd9Sstevel@tonic-gate int
9707c478bd9Sstevel@tonic-gate restarter_remove_contract(scf_instance_t *s_inst, ctid_t contract_id,
9717c478bd9Sstevel@tonic-gate     restarter_contract_type_t type)
9727c478bd9Sstevel@tonic-gate {
9737c478bd9Sstevel@tonic-gate 	scf_handle_t *h;
9747c478bd9Sstevel@tonic-gate 	scf_transaction_t *t = NULL;
9757c478bd9Sstevel@tonic-gate 	scf_transaction_entry_t *t_cid = NULL;
9767c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg = NULL;
9777c478bd9Sstevel@tonic-gate 	scf_property_t *prop = NULL;
9787c478bd9Sstevel@tonic-gate 	scf_value_t *val;
9797c478bd9Sstevel@tonic-gate 	scf_iter_t *iter = NULL;
9807c478bd9Sstevel@tonic-gate 	const char *pname;
9817c478bd9Sstevel@tonic-gate 	int ret = 0, primary;
9827c478bd9Sstevel@tonic-gate 	uint64_t c;
9837c478bd9Sstevel@tonic-gate 
9847c478bd9Sstevel@tonic-gate 	switch (type) {
9857c478bd9Sstevel@tonic-gate 	case RESTARTER_CONTRACT_PRIMARY:
9867c478bd9Sstevel@tonic-gate 		primary = 1;
9877c478bd9Sstevel@tonic-gate 		break;
9887c478bd9Sstevel@tonic-gate 	case RESTARTER_CONTRACT_TRANSIENT:
9897c478bd9Sstevel@tonic-gate 		primary = 0;
9907c478bd9Sstevel@tonic-gate 		break;
9917c478bd9Sstevel@tonic-gate 	default:
9927c478bd9Sstevel@tonic-gate 		return (EINVAL);
9937c478bd9Sstevel@tonic-gate 	}
9947c478bd9Sstevel@tonic-gate 
9957c478bd9Sstevel@tonic-gate 	h = scf_instance_handle(s_inst);
9967c478bd9Sstevel@tonic-gate 
9977c478bd9Sstevel@tonic-gate 	pg = scf_pg_create(h);
9987c478bd9Sstevel@tonic-gate 	prop = scf_property_create(h);
9997c478bd9Sstevel@tonic-gate 	iter = scf_iter_create(h);
10007c478bd9Sstevel@tonic-gate 	t = scf_transaction_create(h);
10017c478bd9Sstevel@tonic-gate 
10027c478bd9Sstevel@tonic-gate 	if (pg == NULL || prop == NULL || iter == NULL || t == NULL) {
10037c478bd9Sstevel@tonic-gate 		ret = ENOMEM;
10047c478bd9Sstevel@tonic-gate 		goto remove_contract_cleanup;
10057c478bd9Sstevel@tonic-gate 	}
10067c478bd9Sstevel@tonic-gate 
10077c478bd9Sstevel@tonic-gate add:
10087c478bd9Sstevel@tonic-gate 	scf_transaction_destroy_children(t);
10097c478bd9Sstevel@tonic-gate 	ret = instance_get_or_add_pg(s_inst, SCF_PG_RESTARTER,
10107c478bd9Sstevel@tonic-gate 	    SCF_PG_RESTARTER_TYPE, SCF_PG_RESTARTER_FLAGS, pg);
10117c478bd9Sstevel@tonic-gate 	if (ret != 0)
10127c478bd9Sstevel@tonic-gate 		goto remove_contract_cleanup;
10137c478bd9Sstevel@tonic-gate 
10147c478bd9Sstevel@tonic-gate 	pname = primary? SCF_PROPERTY_CONTRACT :
10157c478bd9Sstevel@tonic-gate 	    SCF_PROPERTY_TRANSIENT_CONTRACT;
10167c478bd9Sstevel@tonic-gate 
10177c478bd9Sstevel@tonic-gate 	for (;;) {
10187c478bd9Sstevel@tonic-gate 		if (scf_transaction_start(t, pg) != 0) {
10197c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
10207c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
10217c478bd9Sstevel@tonic-gate 			default:
10227c478bd9Sstevel@tonic-gate 				ret = ECONNABORTED;
10237c478bd9Sstevel@tonic-gate 				goto remove_contract_cleanup;
10247c478bd9Sstevel@tonic-gate 
10257c478bd9Sstevel@tonic-gate 			case SCF_ERROR_DELETED:
10267c478bd9Sstevel@tonic-gate 				goto add;
10277c478bd9Sstevel@tonic-gate 
10287c478bd9Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
10297c478bd9Sstevel@tonic-gate 				ret = EPERM;
10307c478bd9Sstevel@tonic-gate 				goto remove_contract_cleanup;
10317c478bd9Sstevel@tonic-gate 
10327c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_ACCESS:
10337c478bd9Sstevel@tonic-gate 				ret = EACCES;
10347c478bd9Sstevel@tonic-gate 				goto remove_contract_cleanup;
10357c478bd9Sstevel@tonic-gate 
10367c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_READONLY:
10377c478bd9Sstevel@tonic-gate 				ret = EROFS;
10387c478bd9Sstevel@tonic-gate 				goto remove_contract_cleanup;
10397c478bd9Sstevel@tonic-gate 
10407c478bd9Sstevel@tonic-gate 			case SCF_ERROR_HANDLE_MISMATCH:
10417c478bd9Sstevel@tonic-gate 			case SCF_ERROR_IN_USE:
10427c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
10437c478bd9Sstevel@tonic-gate 				bad_fail("scf_transaction_start", scf_error());
10447c478bd9Sstevel@tonic-gate 			}
10457c478bd9Sstevel@tonic-gate 		}
10467c478bd9Sstevel@tonic-gate 
10477c478bd9Sstevel@tonic-gate 		t_cid = scf_entry_create(h);
10487c478bd9Sstevel@tonic-gate 
10497c478bd9Sstevel@tonic-gate 		if (scf_pg_get_property(pg, pname, prop) == 0) {
10507c478bd9Sstevel@tonic-gate replace:
10517c478bd9Sstevel@tonic-gate 			if (scf_transaction_property_change_type(t, t_cid,
10527c478bd9Sstevel@tonic-gate 			    pname, SCF_TYPE_COUNT) != 0) {
10537c478bd9Sstevel@tonic-gate 				switch (scf_error()) {
10547c478bd9Sstevel@tonic-gate 				case SCF_ERROR_CONNECTION_BROKEN:
10557c478bd9Sstevel@tonic-gate 				default:
10567c478bd9Sstevel@tonic-gate 					ret = ECONNABORTED;
10577c478bd9Sstevel@tonic-gate 					goto remove_contract_cleanup;
10587c478bd9Sstevel@tonic-gate 
10597c478bd9Sstevel@tonic-gate 				case SCF_ERROR_DELETED:
10607c478bd9Sstevel@tonic-gate 					scf_entry_destroy(t_cid);
10617c478bd9Sstevel@tonic-gate 					goto add;
10627c478bd9Sstevel@tonic-gate 
10637c478bd9Sstevel@tonic-gate 				case SCF_ERROR_NOT_FOUND:
10647c478bd9Sstevel@tonic-gate 					goto new;
10657c478bd9Sstevel@tonic-gate 
10667c478bd9Sstevel@tonic-gate 				case SCF_ERROR_HANDLE_MISMATCH:
10677c478bd9Sstevel@tonic-gate 				case SCF_ERROR_INVALID_ARGUMENT:
10687c478bd9Sstevel@tonic-gate 				case SCF_ERROR_IN_USE:
10697c478bd9Sstevel@tonic-gate 				case SCF_ERROR_NOT_SET:
10707c478bd9Sstevel@tonic-gate 					bad_fail(
10717c478bd9Sstevel@tonic-gate 					"scf_transaction_property_changetype",
10727c478bd9Sstevel@tonic-gate 					    scf_error());
10737c478bd9Sstevel@tonic-gate 				}
10747c478bd9Sstevel@tonic-gate 			}
10757c478bd9Sstevel@tonic-gate 
10767c478bd9Sstevel@tonic-gate 			if (scf_property_is_type(prop, SCF_TYPE_COUNT) == 0) {
10777c478bd9Sstevel@tonic-gate 				if (scf_iter_property_values(iter, prop) != 0) {
10787c478bd9Sstevel@tonic-gate 					switch (scf_error()) {
10797c478bd9Sstevel@tonic-gate 					case SCF_ERROR_CONNECTION_BROKEN:
10807c478bd9Sstevel@tonic-gate 					default:
10817c478bd9Sstevel@tonic-gate 						ret = ECONNABORTED;
10827c478bd9Sstevel@tonic-gate 						goto remove_contract_cleanup;
10837c478bd9Sstevel@tonic-gate 
10847c478bd9Sstevel@tonic-gate 					case SCF_ERROR_NOT_SET:
10857c478bd9Sstevel@tonic-gate 					case SCF_ERROR_HANDLE_MISMATCH:
10867c478bd9Sstevel@tonic-gate 						bad_fail(
10877c478bd9Sstevel@tonic-gate 						    "scf_iter_property_values",
10887c478bd9Sstevel@tonic-gate 						    scf_error());
10897c478bd9Sstevel@tonic-gate 					}
10907c478bd9Sstevel@tonic-gate 				}
10917c478bd9Sstevel@tonic-gate 
10927c478bd9Sstevel@tonic-gate next_val:
10937c478bd9Sstevel@tonic-gate 				val = scf_value_create(h);
10947c478bd9Sstevel@tonic-gate 				if (val == NULL) {
10957c478bd9Sstevel@tonic-gate 					assert(scf_error() ==
10967c478bd9Sstevel@tonic-gate 					    SCF_ERROR_NO_MEMORY);
10977c478bd9Sstevel@tonic-gate 					ret = ENOMEM;
10987c478bd9Sstevel@tonic-gate 					goto remove_contract_cleanup;
10997c478bd9Sstevel@tonic-gate 				}
11007c478bd9Sstevel@tonic-gate 
11017c478bd9Sstevel@tonic-gate 				ret = scf_iter_next_value(iter, val);
11027c478bd9Sstevel@tonic-gate 				if (ret == -1) {
11037c478bd9Sstevel@tonic-gate 					switch (scf_error()) {
11047c478bd9Sstevel@tonic-gate 					case SCF_ERROR_CONNECTION_BROKEN:
11057c478bd9Sstevel@tonic-gate 						ret = ECONNABORTED;
11067c478bd9Sstevel@tonic-gate 						goto remove_contract_cleanup;
11077c478bd9Sstevel@tonic-gate 
11087c478bd9Sstevel@tonic-gate 					case SCF_ERROR_DELETED:
11097c478bd9Sstevel@tonic-gate 						scf_value_destroy(val);
11107c478bd9Sstevel@tonic-gate 						goto add;
11117c478bd9Sstevel@tonic-gate 
11127c478bd9Sstevel@tonic-gate 					case SCF_ERROR_HANDLE_MISMATCH:
11137c478bd9Sstevel@tonic-gate 					case SCF_ERROR_INVALID_ARGUMENT:
11143eae19d9Swesolows 					case SCF_ERROR_PERMISSION_DENIED:
11157c478bd9Sstevel@tonic-gate 					default:
11167c478bd9Sstevel@tonic-gate 						bad_fail("scf_iter_next_value",
11177c478bd9Sstevel@tonic-gate 						    scf_error());
11187c478bd9Sstevel@tonic-gate 					}
11197c478bd9Sstevel@tonic-gate 				}
11207c478bd9Sstevel@tonic-gate 
11217c478bd9Sstevel@tonic-gate 				if (ret == 1) {
11227c478bd9Sstevel@tonic-gate 					ret = scf_value_get_count(val, &c);
11237c478bd9Sstevel@tonic-gate 					assert(ret == 0);
11247c478bd9Sstevel@tonic-gate 
11257c478bd9Sstevel@tonic-gate 					if (c != contract_id) {
11267c478bd9Sstevel@tonic-gate 						ret = scf_entry_add_value(t_cid,
11277c478bd9Sstevel@tonic-gate 						    val);
11287c478bd9Sstevel@tonic-gate 						assert(ret == 0);
11297c478bd9Sstevel@tonic-gate 					} else {
11307c478bd9Sstevel@tonic-gate 						scf_value_destroy(val);
11317c478bd9Sstevel@tonic-gate 					}
11327c478bd9Sstevel@tonic-gate 
11337c478bd9Sstevel@tonic-gate 					goto next_val;
11347c478bd9Sstevel@tonic-gate 				}
11357c478bd9Sstevel@tonic-gate 
11367c478bd9Sstevel@tonic-gate 				scf_value_destroy(val);
11377c478bd9Sstevel@tonic-gate 			} else {
11387c478bd9Sstevel@tonic-gate 				switch (scf_error()) {
11397c478bd9Sstevel@tonic-gate 				case SCF_ERROR_CONNECTION_BROKEN:
11407c478bd9Sstevel@tonic-gate 				default:
11417c478bd9Sstevel@tonic-gate 					ret = ECONNABORTED;
11427c478bd9Sstevel@tonic-gate 					goto remove_contract_cleanup;
11437c478bd9Sstevel@tonic-gate 
11447c478bd9Sstevel@tonic-gate 				case SCF_ERROR_TYPE_MISMATCH:
11457c478bd9Sstevel@tonic-gate 					break;
11467c478bd9Sstevel@tonic-gate 
11477c478bd9Sstevel@tonic-gate 				case SCF_ERROR_INVALID_ARGUMENT:
11487c478bd9Sstevel@tonic-gate 				case SCF_ERROR_NOT_SET:
11497c478bd9Sstevel@tonic-gate 					bad_fail("scf_property_is_type",
11507c478bd9Sstevel@tonic-gate 					    scf_error());
11517c478bd9Sstevel@tonic-gate 				}
11527c478bd9Sstevel@tonic-gate 			}
11537c478bd9Sstevel@tonic-gate 		} else {
11547c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
11557c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
11567c478bd9Sstevel@tonic-gate 			default:
11577c478bd9Sstevel@tonic-gate 				ret = ECONNABORTED;
11587c478bd9Sstevel@tonic-gate 				goto remove_contract_cleanup;
11597c478bd9Sstevel@tonic-gate 
11607c478bd9Sstevel@tonic-gate 			case SCF_ERROR_DELETED:
11617c478bd9Sstevel@tonic-gate 				scf_entry_destroy(t_cid);
11627c478bd9Sstevel@tonic-gate 				goto add;
11637c478bd9Sstevel@tonic-gate 
11647c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_FOUND:
11657c478bd9Sstevel@tonic-gate 				break;
11667c478bd9Sstevel@tonic-gate 
11677c478bd9Sstevel@tonic-gate 			case SCF_ERROR_HANDLE_MISMATCH:
11687c478bd9Sstevel@tonic-gate 			case SCF_ERROR_INVALID_ARGUMENT:
11697c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
11707c478bd9Sstevel@tonic-gate 				bad_fail("scf_pg_get_property", scf_error());
11717c478bd9Sstevel@tonic-gate 			}
11727c478bd9Sstevel@tonic-gate 
11737c478bd9Sstevel@tonic-gate new:
11747c478bd9Sstevel@tonic-gate 			if (scf_transaction_property_new(t, t_cid, pname,
11757c478bd9Sstevel@tonic-gate 			    SCF_TYPE_COUNT) != 0) {
11767c478bd9Sstevel@tonic-gate 				switch (scf_error()) {
11777c478bd9Sstevel@tonic-gate 				case SCF_ERROR_CONNECTION_BROKEN:
11787c478bd9Sstevel@tonic-gate 				default:
11797c478bd9Sstevel@tonic-gate 					ret = ECONNABORTED;
11807c478bd9Sstevel@tonic-gate 					goto remove_contract_cleanup;
11817c478bd9Sstevel@tonic-gate 
11827c478bd9Sstevel@tonic-gate 				case SCF_ERROR_DELETED:
11837c478bd9Sstevel@tonic-gate 					scf_entry_destroy(t_cid);
11847c478bd9Sstevel@tonic-gate 					goto add;
11857c478bd9Sstevel@tonic-gate 
11867c478bd9Sstevel@tonic-gate 				case SCF_ERROR_EXISTS:
11877c478bd9Sstevel@tonic-gate 					goto replace;
11887c478bd9Sstevel@tonic-gate 
11897c478bd9Sstevel@tonic-gate 				case SCF_ERROR_HANDLE_MISMATCH:
11907c478bd9Sstevel@tonic-gate 				case SCF_ERROR_INVALID_ARGUMENT:
11917c478bd9Sstevel@tonic-gate 				case SCF_ERROR_NOT_SET:
11927c478bd9Sstevel@tonic-gate 					bad_fail("scf_transaction_property_new",
11937c478bd9Sstevel@tonic-gate 					    scf_error());
11947c478bd9Sstevel@tonic-gate 				}
11957c478bd9Sstevel@tonic-gate 			}
11967c478bd9Sstevel@tonic-gate 		}
11977c478bd9Sstevel@tonic-gate 
11987c478bd9Sstevel@tonic-gate 		ret = scf_transaction_commit(t);
11997c478bd9Sstevel@tonic-gate 		if (ret == -1) {
12007c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
12017c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
12027c478bd9Sstevel@tonic-gate 			default:
12037c478bd9Sstevel@tonic-gate 				ret = ECONNABORTED;
12047c478bd9Sstevel@tonic-gate 				goto remove_contract_cleanup;
12057c478bd9Sstevel@tonic-gate 
12067c478bd9Sstevel@tonic-gate 			case SCF_ERROR_DELETED:
12077c478bd9Sstevel@tonic-gate 				goto add;
12087c478bd9Sstevel@tonic-gate 
12097c478bd9Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
12107c478bd9Sstevel@tonic-gate 				ret = EPERM;
12117c478bd9Sstevel@tonic-gate 				goto remove_contract_cleanup;
12127c478bd9Sstevel@tonic-gate 
12137c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_ACCESS:
12147c478bd9Sstevel@tonic-gate 				ret = EACCES;
12157c478bd9Sstevel@tonic-gate 				goto remove_contract_cleanup;
12167c478bd9Sstevel@tonic-gate 
12177c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_READONLY:
12187c478bd9Sstevel@tonic-gate 				ret = EROFS;
12197c478bd9Sstevel@tonic-gate 				goto remove_contract_cleanup;
12207c478bd9Sstevel@tonic-gate 
12217c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
12227c478bd9Sstevel@tonic-gate 				bad_fail("scf_transaction_commit", scf_error());
12237c478bd9Sstevel@tonic-gate 			}
12247c478bd9Sstevel@tonic-gate 		}
12257c478bd9Sstevel@tonic-gate 		if (ret == 1) {
12267c478bd9Sstevel@tonic-gate 			ret = 0;
12277c478bd9Sstevel@tonic-gate 			break;
12287c478bd9Sstevel@tonic-gate 		}
12297c478bd9Sstevel@tonic-gate 
12307c478bd9Sstevel@tonic-gate 		scf_transaction_destroy_children(t);
12317c478bd9Sstevel@tonic-gate 		if (scf_pg_update(pg) == -1) {
12327c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
12337c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
12347c478bd9Sstevel@tonic-gate 			default:
12357c478bd9Sstevel@tonic-gate 				ret = ECONNABORTED;
12367c478bd9Sstevel@tonic-gate 				goto remove_contract_cleanup;
12377c478bd9Sstevel@tonic-gate 
12387c478bd9Sstevel@tonic-gate 			case SCF_ERROR_DELETED:
12397c478bd9Sstevel@tonic-gate 				goto add;
12407c478bd9Sstevel@tonic-gate 
12417c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
12427c478bd9Sstevel@tonic-gate 				bad_fail("scf_pg_update", scf_error());
12437c478bd9Sstevel@tonic-gate 			}
12447c478bd9Sstevel@tonic-gate 		}
12457c478bd9Sstevel@tonic-gate 	}
12467c478bd9Sstevel@tonic-gate 
12477c478bd9Sstevel@tonic-gate remove_contract_cleanup:
12487c478bd9Sstevel@tonic-gate 	scf_transaction_destroy_children(t);
12497c478bd9Sstevel@tonic-gate 	scf_transaction_destroy(t);
12507c478bd9Sstevel@tonic-gate 	scf_iter_destroy(iter);
12517c478bd9Sstevel@tonic-gate 	scf_property_destroy(prop);
12527c478bd9Sstevel@tonic-gate 	scf_pg_destroy(pg);
12537c478bd9Sstevel@tonic-gate 
12547c478bd9Sstevel@tonic-gate 	return (ret);
12557c478bd9Sstevel@tonic-gate }
12567c478bd9Sstevel@tonic-gate 
12577c478bd9Sstevel@tonic-gate /*
12587c478bd9Sstevel@tonic-gate  * Fails with
12597c478bd9Sstevel@tonic-gate  *   EINVAL - type is invalid
12607c478bd9Sstevel@tonic-gate  *   ENOMEM
12617c478bd9Sstevel@tonic-gate  *   ECONNABORTED - repository disconnection
12627c478bd9Sstevel@tonic-gate  *   EBADF - s_inst is not set
12637c478bd9Sstevel@tonic-gate  *   ECANCELED - s_inst is deleted
12647c478bd9Sstevel@tonic-gate  *   EPERM
12657c478bd9Sstevel@tonic-gate  *   EACCES
12667c478bd9Sstevel@tonic-gate  *   EROFS
12677c478bd9Sstevel@tonic-gate  */
12687c478bd9Sstevel@tonic-gate int
12697c478bd9Sstevel@tonic-gate restarter_store_contract(scf_instance_t *s_inst, ctid_t contract_id,
12707c478bd9Sstevel@tonic-gate     restarter_contract_type_t type)
12717c478bd9Sstevel@tonic-gate {
12727c478bd9Sstevel@tonic-gate 	scf_handle_t *h;
12737c478bd9Sstevel@tonic-gate 	scf_transaction_t *t = NULL;
12747c478bd9Sstevel@tonic-gate 	scf_transaction_entry_t *t_cid = NULL;
12757c478bd9Sstevel@tonic-gate 	scf_value_t *val;
12767c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg = NULL;
12777c478bd9Sstevel@tonic-gate 	scf_property_t *prop = NULL;
12787c478bd9Sstevel@tonic-gate 	scf_iter_t *iter = NULL;
12797c478bd9Sstevel@tonic-gate 	const char *pname;
12807c478bd9Sstevel@tonic-gate 	int ret = 0, primary;
12817c478bd9Sstevel@tonic-gate 
12827c478bd9Sstevel@tonic-gate 	if (type == RESTARTER_CONTRACT_PRIMARY)
12837c478bd9Sstevel@tonic-gate 		primary = 1;
12847c478bd9Sstevel@tonic-gate 	else if (type == RESTARTER_CONTRACT_TRANSIENT)
12857c478bd9Sstevel@tonic-gate 		primary = 0;
12867c478bd9Sstevel@tonic-gate 	else
12877c478bd9Sstevel@tonic-gate 		return (EINVAL);
12887c478bd9Sstevel@tonic-gate 
12897c478bd9Sstevel@tonic-gate 	h = scf_instance_handle(s_inst);
12907c478bd9Sstevel@tonic-gate 
12917c478bd9Sstevel@tonic-gate 	pg = scf_pg_create(h);
12927c478bd9Sstevel@tonic-gate 	prop = scf_property_create(h);
12937c478bd9Sstevel@tonic-gate 	iter = scf_iter_create(h);
12947c478bd9Sstevel@tonic-gate 	t = scf_transaction_create(h);
12957c478bd9Sstevel@tonic-gate 
12967c478bd9Sstevel@tonic-gate 	if (pg == NULL || prop == NULL || iter == NULL || t == NULL) {
12977c478bd9Sstevel@tonic-gate 		ret = ENOMEM;
12987c478bd9Sstevel@tonic-gate 		goto out;
12997c478bd9Sstevel@tonic-gate 	}
13007c478bd9Sstevel@tonic-gate 
13017c478bd9Sstevel@tonic-gate add:
13027c478bd9Sstevel@tonic-gate 	scf_transaction_destroy_children(t);
13037c478bd9Sstevel@tonic-gate 	ret = instance_get_or_add_pg(s_inst, SCF_PG_RESTARTER,
13047c478bd9Sstevel@tonic-gate 	    SCF_PG_RESTARTER_TYPE, SCF_PG_RESTARTER_FLAGS, pg);
13057c478bd9Sstevel@tonic-gate 	if (ret != 0)
13067c478bd9Sstevel@tonic-gate 		goto out;
13077c478bd9Sstevel@tonic-gate 
13087c478bd9Sstevel@tonic-gate 	pname = primary ? SCF_PROPERTY_CONTRACT :
13097c478bd9Sstevel@tonic-gate 	    SCF_PROPERTY_TRANSIENT_CONTRACT;
13107c478bd9Sstevel@tonic-gate 
13117c478bd9Sstevel@tonic-gate 	for (;;) {
13127c478bd9Sstevel@tonic-gate 		if (scf_transaction_start(t, pg) != 0) {
13137c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
13147c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
13157c478bd9Sstevel@tonic-gate 			default:
13167c478bd9Sstevel@tonic-gate 				ret = ECONNABORTED;
13177c478bd9Sstevel@tonic-gate 				goto out;
13187c478bd9Sstevel@tonic-gate 
13197c478bd9Sstevel@tonic-gate 			case SCF_ERROR_DELETED:
13207c478bd9Sstevel@tonic-gate 				goto add;
13217c478bd9Sstevel@tonic-gate 
13227c478bd9Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
13237c478bd9Sstevel@tonic-gate 				ret = EPERM;
13247c478bd9Sstevel@tonic-gate 				goto out;
13257c478bd9Sstevel@tonic-gate 
13267c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_ACCESS:
13277c478bd9Sstevel@tonic-gate 				ret = EACCES;
13287c478bd9Sstevel@tonic-gate 				goto out;
13297c478bd9Sstevel@tonic-gate 
13307c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_READONLY:
13317c478bd9Sstevel@tonic-gate 				ret = EROFS;
13327c478bd9Sstevel@tonic-gate 				goto out;
13337c478bd9Sstevel@tonic-gate 
13347c478bd9Sstevel@tonic-gate 			case SCF_ERROR_HANDLE_MISMATCH:
13357c478bd9Sstevel@tonic-gate 			case SCF_ERROR_IN_USE:
13367c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
13377c478bd9Sstevel@tonic-gate 				bad_fail("scf_transaction_start", scf_error());
13387c478bd9Sstevel@tonic-gate 			}
13397c478bd9Sstevel@tonic-gate 		}
13407c478bd9Sstevel@tonic-gate 
13417c478bd9Sstevel@tonic-gate 		t_cid = scf_entry_create(h);
13427c478bd9Sstevel@tonic-gate 		if (t_cid == NULL) {
13437c478bd9Sstevel@tonic-gate 			ret = ENOMEM;
13447c478bd9Sstevel@tonic-gate 			goto out;
13457c478bd9Sstevel@tonic-gate 		}
13467c478bd9Sstevel@tonic-gate 
13477c478bd9Sstevel@tonic-gate 		if (scf_pg_get_property(pg, pname, prop) == 0) {
13487c478bd9Sstevel@tonic-gate replace:
13497c478bd9Sstevel@tonic-gate 			if (scf_transaction_property_change_type(t, t_cid,
13507c478bd9Sstevel@tonic-gate 			    pname, SCF_TYPE_COUNT) != 0) {
13517c478bd9Sstevel@tonic-gate 				switch (scf_error()) {
13527c478bd9Sstevel@tonic-gate 				case SCF_ERROR_CONNECTION_BROKEN:
13537c478bd9Sstevel@tonic-gate 				default:
13547c478bd9Sstevel@tonic-gate 					ret = ECONNABORTED;
13557c478bd9Sstevel@tonic-gate 					goto out;
13567c478bd9Sstevel@tonic-gate 
13577c478bd9Sstevel@tonic-gate 				case SCF_ERROR_DELETED:
13587c478bd9Sstevel@tonic-gate 					scf_entry_destroy(t_cid);
13597c478bd9Sstevel@tonic-gate 					goto add;
13607c478bd9Sstevel@tonic-gate 
13617c478bd9Sstevel@tonic-gate 				case SCF_ERROR_NOT_FOUND:
13627c478bd9Sstevel@tonic-gate 					goto new;
13637c478bd9Sstevel@tonic-gate 
13647c478bd9Sstevel@tonic-gate 				case SCF_ERROR_HANDLE_MISMATCH:
13657c478bd9Sstevel@tonic-gate 				case SCF_ERROR_INVALID_ARGUMENT:
13667c478bd9Sstevel@tonic-gate 				case SCF_ERROR_IN_USE:
13677c478bd9Sstevel@tonic-gate 				case SCF_ERROR_NOT_SET:
13687c478bd9Sstevel@tonic-gate 					bad_fail(
13697c478bd9Sstevel@tonic-gate 					"scf_transaction_propert_change_type",
13707c478bd9Sstevel@tonic-gate 					    scf_error());
13717c478bd9Sstevel@tonic-gate 				}
13727c478bd9Sstevel@tonic-gate 			}
13737c478bd9Sstevel@tonic-gate 
13747c478bd9Sstevel@tonic-gate 			if (scf_property_is_type(prop, SCF_TYPE_COUNT) == 0) {
13757c478bd9Sstevel@tonic-gate 				if (scf_iter_property_values(iter, prop) != 0) {
13767c478bd9Sstevel@tonic-gate 					switch (scf_error()) {
13777c478bd9Sstevel@tonic-gate 					case SCF_ERROR_CONNECTION_BROKEN:
13787c478bd9Sstevel@tonic-gate 					default:
13797c478bd9Sstevel@tonic-gate 						ret = ECONNABORTED;
13807c478bd9Sstevel@tonic-gate 						goto out;
13817c478bd9Sstevel@tonic-gate 
13827c478bd9Sstevel@tonic-gate 					case SCF_ERROR_NOT_SET:
13837c478bd9Sstevel@tonic-gate 					case SCF_ERROR_HANDLE_MISMATCH:
13847c478bd9Sstevel@tonic-gate 						bad_fail(
13857c478bd9Sstevel@tonic-gate 						    "scf_iter_property_values",
13867c478bd9Sstevel@tonic-gate 						    scf_error());
13877c478bd9Sstevel@tonic-gate 					}
13887c478bd9Sstevel@tonic-gate 				}
13897c478bd9Sstevel@tonic-gate 
13907c478bd9Sstevel@tonic-gate next_val:
13917c478bd9Sstevel@tonic-gate 				val = scf_value_create(h);
13927c478bd9Sstevel@tonic-gate 				if (val == NULL) {
13937c478bd9Sstevel@tonic-gate 					assert(scf_error() ==
13947c478bd9Sstevel@tonic-gate 					    SCF_ERROR_NO_MEMORY);
13957c478bd9Sstevel@tonic-gate 					ret = ENOMEM;
13967c478bd9Sstevel@tonic-gate 					goto out;
13977c478bd9Sstevel@tonic-gate 				}
13987c478bd9Sstevel@tonic-gate 
13997c478bd9Sstevel@tonic-gate 				ret = scf_iter_next_value(iter, val);
14007c478bd9Sstevel@tonic-gate 				if (ret == -1) {
14017c478bd9Sstevel@tonic-gate 					switch (scf_error()) {
14027c478bd9Sstevel@tonic-gate 					case SCF_ERROR_CONNECTION_BROKEN:
14037c478bd9Sstevel@tonic-gate 					default:
14047c478bd9Sstevel@tonic-gate 						ret = ECONNABORTED;
14057c478bd9Sstevel@tonic-gate 						goto out;
14067c478bd9Sstevel@tonic-gate 
14077c478bd9Sstevel@tonic-gate 					case SCF_ERROR_DELETED:
14087c478bd9Sstevel@tonic-gate 						scf_value_destroy(val);
14097c478bd9Sstevel@tonic-gate 						goto add;
14107c478bd9Sstevel@tonic-gate 
14117c478bd9Sstevel@tonic-gate 					case SCF_ERROR_HANDLE_MISMATCH:
14127c478bd9Sstevel@tonic-gate 					case SCF_ERROR_INVALID_ARGUMENT:
14133eae19d9Swesolows 					case SCF_ERROR_PERMISSION_DENIED:
14147c478bd9Sstevel@tonic-gate 						bad_fail(
14157c478bd9Sstevel@tonic-gate 						    "scf_iter_next_value",
14167c478bd9Sstevel@tonic-gate 						    scf_error());
14177c478bd9Sstevel@tonic-gate 					}
14187c478bd9Sstevel@tonic-gate 				}
14197c478bd9Sstevel@tonic-gate 
14207c478bd9Sstevel@tonic-gate 				if (ret == 1) {
14217c478bd9Sstevel@tonic-gate 					ret = scf_entry_add_value(t_cid, val);
14227c478bd9Sstevel@tonic-gate 					assert(ret == 0);
14237c478bd9Sstevel@tonic-gate 
14247c478bd9Sstevel@tonic-gate 					goto next_val;
14257c478bd9Sstevel@tonic-gate 				}
14267c478bd9Sstevel@tonic-gate 
14277c478bd9Sstevel@tonic-gate 				scf_value_destroy(val);
14287c478bd9Sstevel@tonic-gate 			} else {
14297c478bd9Sstevel@tonic-gate 				switch (scf_error()) {
14307c478bd9Sstevel@tonic-gate 				case SCF_ERROR_CONNECTION_BROKEN:
14317c478bd9Sstevel@tonic-gate 				default:
14327c478bd9Sstevel@tonic-gate 					ret = ECONNABORTED;
14337c478bd9Sstevel@tonic-gate 					goto out;
14347c478bd9Sstevel@tonic-gate 
14357c478bd9Sstevel@tonic-gate 				case SCF_ERROR_TYPE_MISMATCH:
14367c478bd9Sstevel@tonic-gate 					break;
14377c478bd9Sstevel@tonic-gate 
14387c478bd9Sstevel@tonic-gate 				case SCF_ERROR_INVALID_ARGUMENT:
14397c478bd9Sstevel@tonic-gate 				case SCF_ERROR_NOT_SET:
14407c478bd9Sstevel@tonic-gate 					bad_fail("scf_property_is_type",
14417c478bd9Sstevel@tonic-gate 					    scf_error());
14427c478bd9Sstevel@tonic-gate 				}
14437c478bd9Sstevel@tonic-gate 			}
14447c478bd9Sstevel@tonic-gate 		} else {
14457c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
14467c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
14477c478bd9Sstevel@tonic-gate 			default:
14487c478bd9Sstevel@tonic-gate 				ret = ECONNABORTED;
14497c478bd9Sstevel@tonic-gate 				goto out;
14507c478bd9Sstevel@tonic-gate 
14517c478bd9Sstevel@tonic-gate 			case SCF_ERROR_DELETED:
14527c478bd9Sstevel@tonic-gate 				scf_entry_destroy(t_cid);
14537c478bd9Sstevel@tonic-gate 				goto add;
14547c478bd9Sstevel@tonic-gate 
14557c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_FOUND:
14567c478bd9Sstevel@tonic-gate 				break;
14577c478bd9Sstevel@tonic-gate 
14587c478bd9Sstevel@tonic-gate 			case SCF_ERROR_HANDLE_MISMATCH:
14597c478bd9Sstevel@tonic-gate 			case SCF_ERROR_INVALID_ARGUMENT:
14607c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
14617c478bd9Sstevel@tonic-gate 				bad_fail("scf_pg_get_property", scf_error());
14627c478bd9Sstevel@tonic-gate 			}
14637c478bd9Sstevel@tonic-gate 
14647c478bd9Sstevel@tonic-gate new:
14657c478bd9Sstevel@tonic-gate 			if (scf_transaction_property_new(t, t_cid, pname,
14667c478bd9Sstevel@tonic-gate 			    SCF_TYPE_COUNT) != 0) {
14677c478bd9Sstevel@tonic-gate 				switch (scf_error()) {
14687c478bd9Sstevel@tonic-gate 				case SCF_ERROR_CONNECTION_BROKEN:
14697c478bd9Sstevel@tonic-gate 				default:
14707c478bd9Sstevel@tonic-gate 					ret = ECONNABORTED;
14717c478bd9Sstevel@tonic-gate 					goto out;
14727c478bd9Sstevel@tonic-gate 
14737c478bd9Sstevel@tonic-gate 				case SCF_ERROR_DELETED:
14747c478bd9Sstevel@tonic-gate 					scf_entry_destroy(t_cid);
14757c478bd9Sstevel@tonic-gate 					goto add;
14767c478bd9Sstevel@tonic-gate 
14777c478bd9Sstevel@tonic-gate 				case SCF_ERROR_EXISTS:
14787c478bd9Sstevel@tonic-gate 					goto replace;
14797c478bd9Sstevel@tonic-gate 
14807c478bd9Sstevel@tonic-gate 				case SCF_ERROR_HANDLE_MISMATCH:
14817c478bd9Sstevel@tonic-gate 				case SCF_ERROR_INVALID_ARGUMENT:
14827c478bd9Sstevel@tonic-gate 				case SCF_ERROR_NOT_SET:
14837c478bd9Sstevel@tonic-gate 					bad_fail("scf_transaction_property_new",
14847c478bd9Sstevel@tonic-gate 					    scf_error());
14857c478bd9Sstevel@tonic-gate 				}
14867c478bd9Sstevel@tonic-gate 			}
14877c478bd9Sstevel@tonic-gate 		}
14887c478bd9Sstevel@tonic-gate 
14897c478bd9Sstevel@tonic-gate 		val = scf_value_create(h);
14907c478bd9Sstevel@tonic-gate 		if (val == NULL) {
14917c478bd9Sstevel@tonic-gate 			assert(scf_error() == SCF_ERROR_NO_MEMORY);
14927c478bd9Sstevel@tonic-gate 			ret = ENOMEM;
14937c478bd9Sstevel@tonic-gate 			goto out;
14947c478bd9Sstevel@tonic-gate 		}
14957c478bd9Sstevel@tonic-gate 
14967c478bd9Sstevel@tonic-gate 		scf_value_set_count(val, contract_id);
14977c478bd9Sstevel@tonic-gate 		ret = scf_entry_add_value(t_cid, val);
14987c478bd9Sstevel@tonic-gate 		assert(ret == 0);
14997c478bd9Sstevel@tonic-gate 
15007c478bd9Sstevel@tonic-gate 		ret = scf_transaction_commit(t);
15017c478bd9Sstevel@tonic-gate 		if (ret == -1) {
15027c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
15037c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
15047c478bd9Sstevel@tonic-gate 			default:
15057c478bd9Sstevel@tonic-gate 				ret = ECONNABORTED;
15067c478bd9Sstevel@tonic-gate 				goto out;
15077c478bd9Sstevel@tonic-gate 
15087c478bd9Sstevel@tonic-gate 			case SCF_ERROR_DELETED:
15097c478bd9Sstevel@tonic-gate 				goto add;
15107c478bd9Sstevel@tonic-gate 
15117c478bd9Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
15127c478bd9Sstevel@tonic-gate 				ret = EPERM;
15137c478bd9Sstevel@tonic-gate 				goto out;
15147c478bd9Sstevel@tonic-gate 
15157c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_ACCESS:
15167c478bd9Sstevel@tonic-gate 				ret = EACCES;
15177c478bd9Sstevel@tonic-gate 				goto out;
15187c478bd9Sstevel@tonic-gate 
15197c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_READONLY:
15207c478bd9Sstevel@tonic-gate 				ret = EROFS;
15217c478bd9Sstevel@tonic-gate 				goto out;
15227c478bd9Sstevel@tonic-gate 
15237c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
15247c478bd9Sstevel@tonic-gate 				bad_fail("scf_transaction_commit", scf_error());
15257c478bd9Sstevel@tonic-gate 			}
15267c478bd9Sstevel@tonic-gate 		}
15277c478bd9Sstevel@tonic-gate 		if (ret == 1) {
15287c478bd9Sstevel@tonic-gate 			ret = 0;
15297c478bd9Sstevel@tonic-gate 			break;
15307c478bd9Sstevel@tonic-gate 		}
15317c478bd9Sstevel@tonic-gate 
15327c478bd9Sstevel@tonic-gate 		scf_transaction_destroy_children(t);
15337c478bd9Sstevel@tonic-gate 		if (scf_pg_update(pg) == -1) {
15347c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
15357c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
15367c478bd9Sstevel@tonic-gate 			default:
15377c478bd9Sstevel@tonic-gate 				ret = ECONNABORTED;
15387c478bd9Sstevel@tonic-gate 				goto out;
15397c478bd9Sstevel@tonic-gate 
15407c478bd9Sstevel@tonic-gate 			case SCF_ERROR_DELETED:
15417c478bd9Sstevel@tonic-gate 				goto add;
15427c478bd9Sstevel@tonic-gate 
15437c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
15447c478bd9Sstevel@tonic-gate 				bad_fail("scf_pg_update", scf_error());
15457c478bd9Sstevel@tonic-gate 			}
15467c478bd9Sstevel@tonic-gate 		}
15477c478bd9Sstevel@tonic-gate 	}
15487c478bd9Sstevel@tonic-gate 
15497c478bd9Sstevel@tonic-gate out:
15507c478bd9Sstevel@tonic-gate 	scf_transaction_destroy_children(t);
15517c478bd9Sstevel@tonic-gate 	scf_transaction_destroy(t);
15527c478bd9Sstevel@tonic-gate 	scf_iter_destroy(iter);
15537c478bd9Sstevel@tonic-gate 	scf_property_destroy(prop);
15547c478bd9Sstevel@tonic-gate 	scf_pg_destroy(pg);
15557c478bd9Sstevel@tonic-gate 
15567c478bd9Sstevel@tonic-gate 	return (ret);
15577c478bd9Sstevel@tonic-gate }
15587c478bd9Sstevel@tonic-gate 
15597c478bd9Sstevel@tonic-gate int
15607c478bd9Sstevel@tonic-gate restarter_rm_libs_loadable()
15617c478bd9Sstevel@tonic-gate {
15627c478bd9Sstevel@tonic-gate 	void *libhndl;
15637c478bd9Sstevel@tonic-gate 
15647c478bd9Sstevel@tonic-gate 	if (method_context_safety)
15657c478bd9Sstevel@tonic-gate 		return (1);
15667c478bd9Sstevel@tonic-gate 
15677c478bd9Sstevel@tonic-gate 	if ((libhndl = dlopen("libpool.so", RTLD_LAZY | RTLD_LOCAL)) == NULL)
15687c478bd9Sstevel@tonic-gate 		return (0);
15697c478bd9Sstevel@tonic-gate 
15707c478bd9Sstevel@tonic-gate 	(void) dlclose(libhndl);
15717c478bd9Sstevel@tonic-gate 
15727c478bd9Sstevel@tonic-gate 	if ((libhndl = dlopen("libproject.so", RTLD_LAZY | RTLD_LOCAL)) == NULL)
15737c478bd9Sstevel@tonic-gate 		return (0);
15747c478bd9Sstevel@tonic-gate 
15757c478bd9Sstevel@tonic-gate 	(void) dlclose(libhndl);
15767c478bd9Sstevel@tonic-gate 
15777c478bd9Sstevel@tonic-gate 	method_context_safety = 1;
15787c478bd9Sstevel@tonic-gate 
15797c478bd9Sstevel@tonic-gate 	return (1);
15807c478bd9Sstevel@tonic-gate }
15817c478bd9Sstevel@tonic-gate 
15827c478bd9Sstevel@tonic-gate static int
15837c478bd9Sstevel@tonic-gate get_astring_val(scf_propertygroup_t *pg, const char *name, char *buf,
15847c478bd9Sstevel@tonic-gate     size_t bufsz, scf_property_t *prop, scf_value_t *val)
15857c478bd9Sstevel@tonic-gate {
15867c478bd9Sstevel@tonic-gate 	ssize_t szret;
15877c478bd9Sstevel@tonic-gate 
15887c478bd9Sstevel@tonic-gate 	if (scf_pg_get_property(pg, name, prop) != SCF_SUCCESS) {
15897c478bd9Sstevel@tonic-gate 		if (scf_error() == SCF_ERROR_CONNECTION_BROKEN)
15907c478bd9Sstevel@tonic-gate 			uu_die(rcbroken);
15917c478bd9Sstevel@tonic-gate 		return (-1);
15927c478bd9Sstevel@tonic-gate 	}
15937c478bd9Sstevel@tonic-gate 
15947c478bd9Sstevel@tonic-gate 	if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
15957c478bd9Sstevel@tonic-gate 		if (scf_error() == SCF_ERROR_CONNECTION_BROKEN)
15967c478bd9Sstevel@tonic-gate 			uu_die(rcbroken);
15977c478bd9Sstevel@tonic-gate 		return (-1);
15987c478bd9Sstevel@tonic-gate 	}
15997c478bd9Sstevel@tonic-gate 
16007c478bd9Sstevel@tonic-gate 	szret = scf_value_get_astring(val, buf, bufsz);
16017c478bd9Sstevel@tonic-gate 
16027c478bd9Sstevel@tonic-gate 	return (szret >= 0 ? 0 : -1);
16037c478bd9Sstevel@tonic-gate }
16047c478bd9Sstevel@tonic-gate 
1605*eb1a3463STruong Nguyen static int
1606*eb1a3463STruong Nguyen get_boolean_val(scf_propertygroup_t *pg, const char *name, uint8_t *b,
1607*eb1a3463STruong Nguyen     scf_property_t *prop, scf_value_t *val)
1608*eb1a3463STruong Nguyen {
1609*eb1a3463STruong Nguyen 	if (scf_pg_get_property(pg, name, prop) != SCF_SUCCESS) {
1610*eb1a3463STruong Nguyen 		if (scf_error() == SCF_ERROR_CONNECTION_BROKEN)
1611*eb1a3463STruong Nguyen 			uu_die(rcbroken);
1612*eb1a3463STruong Nguyen 		return (-1);
1613*eb1a3463STruong Nguyen 	}
1614*eb1a3463STruong Nguyen 
1615*eb1a3463STruong Nguyen 	if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
1616*eb1a3463STruong Nguyen 		if (scf_error() == SCF_ERROR_CONNECTION_BROKEN)
1617*eb1a3463STruong Nguyen 			uu_die(rcbroken);
1618*eb1a3463STruong Nguyen 		return (-1);
1619*eb1a3463STruong Nguyen 	}
1620*eb1a3463STruong Nguyen 
1621*eb1a3463STruong Nguyen 	if (scf_value_get_boolean(val, b))
1622*eb1a3463STruong Nguyen 		return (-1);
1623*eb1a3463STruong Nguyen 
1624*eb1a3463STruong Nguyen 	return (0);
1625*eb1a3463STruong Nguyen }
1626*eb1a3463STruong Nguyen 
16277c478bd9Sstevel@tonic-gate /*
16287c478bd9Sstevel@tonic-gate  * Try to load mcp->pwd, if it isn't already.
16297c478bd9Sstevel@tonic-gate  * Fails with
16307c478bd9Sstevel@tonic-gate  *   ENOMEM - malloc() failed
16317c478bd9Sstevel@tonic-gate  *   ENOENT - no entry found
16327c478bd9Sstevel@tonic-gate  *   EIO - I/O error
16337c478bd9Sstevel@tonic-gate  *   EMFILE - process out of file descriptors
16347c478bd9Sstevel@tonic-gate  *   ENFILE - system out of file handles
16357c478bd9Sstevel@tonic-gate  */
16367c478bd9Sstevel@tonic-gate static int
16377c478bd9Sstevel@tonic-gate lookup_pwd(struct method_context *mcp)
16387c478bd9Sstevel@tonic-gate {
16397c478bd9Sstevel@tonic-gate 	struct passwd *pwdp;
16407c478bd9Sstevel@tonic-gate 
16417c478bd9Sstevel@tonic-gate 	if (mcp->pwbuf != NULL && mcp->pwd.pw_uid == mcp->uid)
16427c478bd9Sstevel@tonic-gate 		return (0);
16437c478bd9Sstevel@tonic-gate 
16447c478bd9Sstevel@tonic-gate 	if (mcp->pwbuf == NULL) {
16457c478bd9Sstevel@tonic-gate 		mcp->pwbufsz = sysconf(_SC_GETPW_R_SIZE_MAX);
16467c478bd9Sstevel@tonic-gate 		assert(mcp->pwbufsz >= 0);
16477c478bd9Sstevel@tonic-gate 		mcp->pwbuf = malloc(mcp->pwbufsz);
16487c478bd9Sstevel@tonic-gate 		if (mcp->pwbuf == NULL)
16497c478bd9Sstevel@tonic-gate 			return (ENOMEM);
16507c478bd9Sstevel@tonic-gate 	}
16517c478bd9Sstevel@tonic-gate 
16527c478bd9Sstevel@tonic-gate 	do {
16537c478bd9Sstevel@tonic-gate 		errno = 0;
16547c478bd9Sstevel@tonic-gate 		pwdp = getpwuid_r(mcp->uid, &mcp->pwd, mcp->pwbuf,
16557c478bd9Sstevel@tonic-gate 		    mcp->pwbufsz);
16567c478bd9Sstevel@tonic-gate 	} while (pwdp == NULL && errno == EINTR);
16577c478bd9Sstevel@tonic-gate 	if (pwdp != NULL)
16587c478bd9Sstevel@tonic-gate 		return (0);
16597c478bd9Sstevel@tonic-gate 
16607c478bd9Sstevel@tonic-gate 	free(mcp->pwbuf);
16617c478bd9Sstevel@tonic-gate 	mcp->pwbuf = NULL;
16627c478bd9Sstevel@tonic-gate 
16637c478bd9Sstevel@tonic-gate 	switch (errno) {
16647c478bd9Sstevel@tonic-gate 	case 0:
16657c478bd9Sstevel@tonic-gate 	default:
16667c478bd9Sstevel@tonic-gate 		/*
16677c478bd9Sstevel@tonic-gate 		 * Until bug 5065780 is fixed, getpwuid_r() can fail with
16687c478bd9Sstevel@tonic-gate 		 * ENOENT, particularly on the miniroot.  Since the
16697c478bd9Sstevel@tonic-gate 		 * documentation is inaccurate, we'll return ENOENT for unknown
16707c478bd9Sstevel@tonic-gate 		 * errors.
16717c478bd9Sstevel@tonic-gate 		 */
16727c478bd9Sstevel@tonic-gate 		return (ENOENT);
16737c478bd9Sstevel@tonic-gate 
16747c478bd9Sstevel@tonic-gate 	case EIO:
16757c478bd9Sstevel@tonic-gate 	case EMFILE:
16767c478bd9Sstevel@tonic-gate 	case ENFILE:
16777c478bd9Sstevel@tonic-gate 		return (errno);
16787c478bd9Sstevel@tonic-gate 
16797c478bd9Sstevel@tonic-gate 	case ERANGE:
16807c478bd9Sstevel@tonic-gate 		bad_fail("getpwuid_r", errno);
16817c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
16827c478bd9Sstevel@tonic-gate 	}
16837c478bd9Sstevel@tonic-gate }
16847c478bd9Sstevel@tonic-gate 
16857c478bd9Sstevel@tonic-gate /*
16867c478bd9Sstevel@tonic-gate  * Get the user id for str.  Returns 0 on success or
16877c478bd9Sstevel@tonic-gate  *   ERANGE	the uid is too big
16887c478bd9Sstevel@tonic-gate  *   EINVAL	the string starts with a digit, but is not a valid uid
16897c478bd9Sstevel@tonic-gate  *   ENOMEM	out of memory
16907c478bd9Sstevel@tonic-gate  *   ENOENT	no passwd entry for str
16917c478bd9Sstevel@tonic-gate  *   EIO	an I/O error has occurred
16927c478bd9Sstevel@tonic-gate  *   EMFILE/ENFILE  out of file descriptors
16937c478bd9Sstevel@tonic-gate  */
16947c478bd9Sstevel@tonic-gate int
16957c478bd9Sstevel@tonic-gate get_uid(const char *str, struct method_context *ci, uid_t *uidp)
16967c478bd9Sstevel@tonic-gate {
16977c478bd9Sstevel@tonic-gate 	if (isdigit(str[0])) {
16987c478bd9Sstevel@tonic-gate 		uid_t uid;
16997c478bd9Sstevel@tonic-gate 		char *cp;
17007c478bd9Sstevel@tonic-gate 
17017c478bd9Sstevel@tonic-gate 		errno = 0;
17027c478bd9Sstevel@tonic-gate 		uid = strtol(str, &cp, 10);
17037c478bd9Sstevel@tonic-gate 
17047c478bd9Sstevel@tonic-gate 		if (uid == 0 && errno != 0) {
17057c478bd9Sstevel@tonic-gate 			assert(errno != EINVAL);
17067c478bd9Sstevel@tonic-gate 			return (errno);
17077c478bd9Sstevel@tonic-gate 		}
17087c478bd9Sstevel@tonic-gate 
17097c478bd9Sstevel@tonic-gate 		for (; *cp != '\0'; ++cp)
17107c478bd9Sstevel@tonic-gate 			if (*cp != ' ' || *cp != '\t')
17117c478bd9Sstevel@tonic-gate 				return (EINVAL);
17127c478bd9Sstevel@tonic-gate 
17137c478bd9Sstevel@tonic-gate 		if (uid > UID_MAX)
17147c478bd9Sstevel@tonic-gate 			return (EINVAL);
17157c478bd9Sstevel@tonic-gate 
17167c478bd9Sstevel@tonic-gate 		*uidp = uid;
17177c478bd9Sstevel@tonic-gate 		return (0);
17187c478bd9Sstevel@tonic-gate 	} else {
17197c478bd9Sstevel@tonic-gate 		struct passwd *pwdp;
17207c478bd9Sstevel@tonic-gate 
17217c478bd9Sstevel@tonic-gate 		if (ci->pwbuf == NULL) {
17227c478bd9Sstevel@tonic-gate 			ci->pwbufsz = sysconf(_SC_GETPW_R_SIZE_MAX);
17237c478bd9Sstevel@tonic-gate 			ci->pwbuf = malloc(ci->pwbufsz);
17247c478bd9Sstevel@tonic-gate 			if (ci->pwbuf == NULL)
17257c478bd9Sstevel@tonic-gate 				return (ENOMEM);
17267c478bd9Sstevel@tonic-gate 		}
17277c478bd9Sstevel@tonic-gate 
17287c478bd9Sstevel@tonic-gate 		do {
17297c478bd9Sstevel@tonic-gate 			errno = 0;
17307c478bd9Sstevel@tonic-gate 			pwdp =
17317c478bd9Sstevel@tonic-gate 			    getpwnam_r(str, &ci->pwd, ci->pwbuf, ci->pwbufsz);
17327c478bd9Sstevel@tonic-gate 		} while (pwdp == NULL && errno == EINTR);
17337c478bd9Sstevel@tonic-gate 
17347c478bd9Sstevel@tonic-gate 		if (pwdp != NULL) {
17357c478bd9Sstevel@tonic-gate 			*uidp = ci->pwd.pw_uid;
17367c478bd9Sstevel@tonic-gate 			return (0);
17377c478bd9Sstevel@tonic-gate 		} else {
17387c478bd9Sstevel@tonic-gate 			free(ci->pwbuf);
17397c478bd9Sstevel@tonic-gate 			ci->pwbuf = NULL;
17407c478bd9Sstevel@tonic-gate 			switch (errno) {
17417c478bd9Sstevel@tonic-gate 			case 0:
17427c478bd9Sstevel@tonic-gate 				return (ENOENT);
17437c478bd9Sstevel@tonic-gate 
17447c478bd9Sstevel@tonic-gate 			case ENOENT:
17457c478bd9Sstevel@tonic-gate 			case EIO:
17467c478bd9Sstevel@tonic-gate 			case EMFILE:
17477c478bd9Sstevel@tonic-gate 			case ENFILE:
17487c478bd9Sstevel@tonic-gate 				return (errno);
17497c478bd9Sstevel@tonic-gate 
17507c478bd9Sstevel@tonic-gate 			case ERANGE:
17517c478bd9Sstevel@tonic-gate 			default:
17527c478bd9Sstevel@tonic-gate 				bad_fail("getpwnam_r", errno);
17537c478bd9Sstevel@tonic-gate 				/* NOTREACHED */
17547c478bd9Sstevel@tonic-gate 			}
17557c478bd9Sstevel@tonic-gate 		}
17567c478bd9Sstevel@tonic-gate 	}
17577c478bd9Sstevel@tonic-gate }
17587c478bd9Sstevel@tonic-gate 
17597c478bd9Sstevel@tonic-gate gid_t
17607c478bd9Sstevel@tonic-gate get_gid(const char *str)
17617c478bd9Sstevel@tonic-gate {
17627c478bd9Sstevel@tonic-gate 	if (isdigit(str[0])) {
17637c478bd9Sstevel@tonic-gate 		gid_t gid;
17647c478bd9Sstevel@tonic-gate 		char *cp;
17657c478bd9Sstevel@tonic-gate 
17667c478bd9Sstevel@tonic-gate 		errno = 0;
17677c478bd9Sstevel@tonic-gate 		gid = strtol(str, &cp, 10);
17687c478bd9Sstevel@tonic-gate 
17697c478bd9Sstevel@tonic-gate 		if (gid == 0 && errno != 0)
1770f48205beScasper 			return ((gid_t)-1);
17717c478bd9Sstevel@tonic-gate 
17727c478bd9Sstevel@tonic-gate 		for (; *cp != '\0'; ++cp)
17737c478bd9Sstevel@tonic-gate 			if (*cp != ' ' || *cp != '\t')
1774f48205beScasper 				return ((gid_t)-1);
17757c478bd9Sstevel@tonic-gate 
17767c478bd9Sstevel@tonic-gate 		return (gid);
17777c478bd9Sstevel@tonic-gate 	} else {
17787c478bd9Sstevel@tonic-gate 		struct group grp, *ret;
17797c478bd9Sstevel@tonic-gate 		char *buffer;
17807c478bd9Sstevel@tonic-gate 		size_t buflen;
17817c478bd9Sstevel@tonic-gate 
17827c478bd9Sstevel@tonic-gate 		buflen = sysconf(_SC_GETGR_R_SIZE_MAX);
17837c478bd9Sstevel@tonic-gate 		buffer = malloc(buflen);
17847c478bd9Sstevel@tonic-gate 		if (buffer == NULL)
17857c478bd9Sstevel@tonic-gate 			uu_die(allocfail);
17867c478bd9Sstevel@tonic-gate 
17877c478bd9Sstevel@tonic-gate 		errno = 0;
17887c478bd9Sstevel@tonic-gate 		ret = getgrnam_r(str, &grp, buffer, buflen);
17897c478bd9Sstevel@tonic-gate 		free(buffer);
17907c478bd9Sstevel@tonic-gate 
1791f48205beScasper 		return (ret == NULL ? (gid_t)-1 : grp.gr_gid);
17927c478bd9Sstevel@tonic-gate 	}
17937c478bd9Sstevel@tonic-gate }
17947c478bd9Sstevel@tonic-gate 
17957c478bd9Sstevel@tonic-gate /*
17967c478bd9Sstevel@tonic-gate  * Fails with
17977c478bd9Sstevel@tonic-gate  *   ENOMEM - out of memory
17987c478bd9Sstevel@tonic-gate  *   ENOENT - no passwd entry
17997c478bd9Sstevel@tonic-gate  *	      no project entry
18007c478bd9Sstevel@tonic-gate  *   EIO - an I/O error occurred
18017c478bd9Sstevel@tonic-gate  *   EMFILE - the process is out of file descriptors
18027c478bd9Sstevel@tonic-gate  *   ENFILE - the system is out of file handles
18037c478bd9Sstevel@tonic-gate  *   ERANGE - the project id is out of range
18047c478bd9Sstevel@tonic-gate  *   EINVAL - str is invalid
18057c478bd9Sstevel@tonic-gate  *   E2BIG - the project entry was too big
18067c478bd9Sstevel@tonic-gate  *   -1 - the name service switch is misconfigured
18077c478bd9Sstevel@tonic-gate  */
18087c478bd9Sstevel@tonic-gate int
18097c478bd9Sstevel@tonic-gate get_projid(const char *str, struct method_context *cip)
18107c478bd9Sstevel@tonic-gate {
18117c478bd9Sstevel@tonic-gate 	int ret;
18127c478bd9Sstevel@tonic-gate 	void *buf;
18137c478bd9Sstevel@tonic-gate 	const size_t bufsz = PROJECT_BUFSZ;
18147c478bd9Sstevel@tonic-gate 	struct project proj, *pp;
18157c478bd9Sstevel@tonic-gate 
18167c478bd9Sstevel@tonic-gate 	if (strcmp(str, ":default") == 0) {
18177c478bd9Sstevel@tonic-gate 		if (cip->uid == 0) {
18187c478bd9Sstevel@tonic-gate 			/* Don't change project for root services */
18197c478bd9Sstevel@tonic-gate 			cip->project = NULL;
18207c478bd9Sstevel@tonic-gate 			return (0);
18217c478bd9Sstevel@tonic-gate 		}
18227c478bd9Sstevel@tonic-gate 
18237c478bd9Sstevel@tonic-gate 		switch (ret = lookup_pwd(cip)) {
18247c478bd9Sstevel@tonic-gate 		case 0:
18257c478bd9Sstevel@tonic-gate 			break;
18267c478bd9Sstevel@tonic-gate 
18277c478bd9Sstevel@tonic-gate 		case ENOMEM:
18287c478bd9Sstevel@tonic-gate 		case ENOENT:
18297c478bd9Sstevel@tonic-gate 		case EIO:
18307c478bd9Sstevel@tonic-gate 		case EMFILE:
18317c478bd9Sstevel@tonic-gate 		case ENFILE:
18327c478bd9Sstevel@tonic-gate 			return (ret);
18337c478bd9Sstevel@tonic-gate 
18347c478bd9Sstevel@tonic-gate 		default:
18357c478bd9Sstevel@tonic-gate 			bad_fail("lookup_pwd", ret);
18367c478bd9Sstevel@tonic-gate 		}
18377c478bd9Sstevel@tonic-gate 
18387c478bd9Sstevel@tonic-gate 		buf = malloc(bufsz);
18397c478bd9Sstevel@tonic-gate 		if (buf == NULL)
18407c478bd9Sstevel@tonic-gate 			return (ENOMEM);
18417c478bd9Sstevel@tonic-gate 
18427c478bd9Sstevel@tonic-gate 		do {
18437c478bd9Sstevel@tonic-gate 			errno = 0;
18447c478bd9Sstevel@tonic-gate 			pp = getdefaultproj(cip->pwd.pw_name, &proj, buf,
18457c478bd9Sstevel@tonic-gate 			    bufsz);
18467c478bd9Sstevel@tonic-gate 		} while (pp == NULL && errno == EINTR);
18477c478bd9Sstevel@tonic-gate 
18487c478bd9Sstevel@tonic-gate 		/* to be continued ... */
18497c478bd9Sstevel@tonic-gate 	} else {
18507c478bd9Sstevel@tonic-gate 		projid_t projid;
18517c478bd9Sstevel@tonic-gate 		char *cp;
18527c478bd9Sstevel@tonic-gate 
18537c478bd9Sstevel@tonic-gate 		if (!isdigit(str[0])) {
18547c478bd9Sstevel@tonic-gate 			cip->project = strdup(str);
18557c478bd9Sstevel@tonic-gate 			return (cip->project != NULL ? 0 : ENOMEM);
18567c478bd9Sstevel@tonic-gate 		}
18577c478bd9Sstevel@tonic-gate 
18587c478bd9Sstevel@tonic-gate 		errno = 0;
18597c478bd9Sstevel@tonic-gate 		projid = strtol(str, &cp, 10);
18607c478bd9Sstevel@tonic-gate 
18617c478bd9Sstevel@tonic-gate 		if (projid == 0 && errno != 0) {
18627c478bd9Sstevel@tonic-gate 			assert(errno == ERANGE);
18637c478bd9Sstevel@tonic-gate 			return (errno);
18647c478bd9Sstevel@tonic-gate 		}
18657c478bd9Sstevel@tonic-gate 
18667c478bd9Sstevel@tonic-gate 		for (; *cp != '\0'; ++cp)
18677c478bd9Sstevel@tonic-gate 			if (*cp != ' ' || *cp != '\t')
18687c478bd9Sstevel@tonic-gate 				return (EINVAL);
18697c478bd9Sstevel@tonic-gate 
18707c478bd9Sstevel@tonic-gate 		if (projid > MAXPROJID)
18717c478bd9Sstevel@tonic-gate 			return (ERANGE);
18727c478bd9Sstevel@tonic-gate 
18737c478bd9Sstevel@tonic-gate 		buf = malloc(bufsz);
18747c478bd9Sstevel@tonic-gate 		if (buf == NULL)
18757c478bd9Sstevel@tonic-gate 			return (ENOMEM);
18767c478bd9Sstevel@tonic-gate 
18777c478bd9Sstevel@tonic-gate 		do {
18787c478bd9Sstevel@tonic-gate 			errno = 0;
18797c478bd9Sstevel@tonic-gate 			pp = getprojbyid(projid, &proj, buf, bufsz);
18807c478bd9Sstevel@tonic-gate 		} while (pp == NULL && errno == EINTR);
18817c478bd9Sstevel@tonic-gate 	}
18827c478bd9Sstevel@tonic-gate 
18837c478bd9Sstevel@tonic-gate 	if (pp) {
18847c478bd9Sstevel@tonic-gate 		cip->project = strdup(pp->pj_name);
18857c478bd9Sstevel@tonic-gate 		free(buf);
18867c478bd9Sstevel@tonic-gate 		return (cip->project != NULL ? 0 : ENOMEM);
18877c478bd9Sstevel@tonic-gate 	}
18887c478bd9Sstevel@tonic-gate 
18897c478bd9Sstevel@tonic-gate 	free(buf);
18907c478bd9Sstevel@tonic-gate 
18917c478bd9Sstevel@tonic-gate 	switch (errno) {
18927c478bd9Sstevel@tonic-gate 	case 0:
18937c478bd9Sstevel@tonic-gate 		return (ENOENT);
18947c478bd9Sstevel@tonic-gate 
18957c478bd9Sstevel@tonic-gate 	case EIO:
18967c478bd9Sstevel@tonic-gate 	case EMFILE:
18977c478bd9Sstevel@tonic-gate 	case ENFILE:
18987c478bd9Sstevel@tonic-gate 		return (errno);
18997c478bd9Sstevel@tonic-gate 
19007c478bd9Sstevel@tonic-gate 	case ERANGE:
19017c478bd9Sstevel@tonic-gate 		return (E2BIG);
19027c478bd9Sstevel@tonic-gate 
19037c478bd9Sstevel@tonic-gate 	default:
19047c478bd9Sstevel@tonic-gate 		return (-1);
19057c478bd9Sstevel@tonic-gate 	}
19067c478bd9Sstevel@tonic-gate }
19077c478bd9Sstevel@tonic-gate 
19087c478bd9Sstevel@tonic-gate /*
19097c478bd9Sstevel@tonic-gate  * Parse the supp_groups property value and populate ci->groups.  Returns
19107c478bd9Sstevel@tonic-gate  * EINVAL (get_gid() failed for one of the components), E2BIG (the property has
19117c478bd9Sstevel@tonic-gate  * more than NGROUPS_MAX-1 groups), or 0 on success.
19127c478bd9Sstevel@tonic-gate  */
19137c478bd9Sstevel@tonic-gate int
19147c478bd9Sstevel@tonic-gate get_groups(char *str, struct method_context *ci)
19157c478bd9Sstevel@tonic-gate {
19167c478bd9Sstevel@tonic-gate 	char *cp, *end, *next;
19177c478bd9Sstevel@tonic-gate 	uint_t i;
19187c478bd9Sstevel@tonic-gate 
19197c478bd9Sstevel@tonic-gate 	const char * const whitespace = " \t";
19207c478bd9Sstevel@tonic-gate 	const char * const illegal = ", \t";
19217c478bd9Sstevel@tonic-gate 
19227c478bd9Sstevel@tonic-gate 	if (str[0] == '\0') {
19237c478bd9Sstevel@tonic-gate 		ci->ngroups = 0;
19247c478bd9Sstevel@tonic-gate 		return (0);
19257c478bd9Sstevel@tonic-gate 	}
19267c478bd9Sstevel@tonic-gate 
19277c478bd9Sstevel@tonic-gate 	for (cp = str, i = 0; *cp != '\0'; ) {
19287c478bd9Sstevel@tonic-gate 		/* skip whitespace */
19297c478bd9Sstevel@tonic-gate 		cp += strspn(cp, whitespace);
19307c478bd9Sstevel@tonic-gate 
19317c478bd9Sstevel@tonic-gate 		/* find the end */
19327c478bd9Sstevel@tonic-gate 		end = cp + strcspn(cp, illegal);
19337c478bd9Sstevel@tonic-gate 
19347c478bd9Sstevel@tonic-gate 		/* skip whitespace after end */
19357c478bd9Sstevel@tonic-gate 		next = end + strspn(end, whitespace);
19367c478bd9Sstevel@tonic-gate 
19377c478bd9Sstevel@tonic-gate 		/* if there's a comma, it separates the fields */
19387c478bd9Sstevel@tonic-gate 		if (*next == ',')
19397c478bd9Sstevel@tonic-gate 			++next;
19407c478bd9Sstevel@tonic-gate 
19417c478bd9Sstevel@tonic-gate 		*end = '\0';
19427c478bd9Sstevel@tonic-gate 
1943f48205beScasper 		if ((ci->groups[i] = get_gid(cp)) == (gid_t)-1) {
19447c478bd9Sstevel@tonic-gate 			ci->ngroups = 0;
19457c478bd9Sstevel@tonic-gate 			return (EINVAL);
19467c478bd9Sstevel@tonic-gate 		}
19477c478bd9Sstevel@tonic-gate 
19487c478bd9Sstevel@tonic-gate 		++i;
19497c478bd9Sstevel@tonic-gate 		if (i > NGROUPS_MAX - 1) {
19507c478bd9Sstevel@tonic-gate 			ci->ngroups = 0;
19517c478bd9Sstevel@tonic-gate 			return (E2BIG);
19527c478bd9Sstevel@tonic-gate 		}
19537c478bd9Sstevel@tonic-gate 
19547c478bd9Sstevel@tonic-gate 		cp = next;
19557c478bd9Sstevel@tonic-gate 	}
19567c478bd9Sstevel@tonic-gate 
19577c478bd9Sstevel@tonic-gate 	ci->ngroups = i;
19587c478bd9Sstevel@tonic-gate 	return (0);
19597c478bd9Sstevel@tonic-gate }
19607c478bd9Sstevel@tonic-gate 
19617c478bd9Sstevel@tonic-gate /*
19627c478bd9Sstevel@tonic-gate  * Eventually, we will return a structured error in the case of
19637c478bd9Sstevel@tonic-gate  * retryable or abortable failures such as memory allocation errors and
19647c478bd9Sstevel@tonic-gate  * repository connection failures.  For now, these failures are just
19657c478bd9Sstevel@tonic-gate  * encoded in the failure string.
19667c478bd9Sstevel@tonic-gate  */
19677c478bd9Sstevel@tonic-gate static const char *
19687c478bd9Sstevel@tonic-gate get_profile(scf_propertygroup_t *pg, scf_property_t *prop, scf_value_t *val,
19697c478bd9Sstevel@tonic-gate     const char *cmdline, struct method_context *ci)
19707c478bd9Sstevel@tonic-gate {
19717c478bd9Sstevel@tonic-gate 	char *buf = ci->vbuf;
19727c478bd9Sstevel@tonic-gate 	ssize_t buf_sz = ci->vbuf_sz;
19737c478bd9Sstevel@tonic-gate 	char cmd[PATH_MAX];
19747c478bd9Sstevel@tonic-gate 	char *cp, *value;
19757c478bd9Sstevel@tonic-gate 	const char *cmdp;
19767c478bd9Sstevel@tonic-gate 	execattr_t *eap;
19777c478bd9Sstevel@tonic-gate 	char *errstr = NULL;
19787c478bd9Sstevel@tonic-gate 
19797c478bd9Sstevel@tonic-gate 	if (get_astring_val(pg, SCF_PROPERTY_PROFILE, buf, buf_sz, prop, val) !=
19807c478bd9Sstevel@tonic-gate 	    0)
19817c478bd9Sstevel@tonic-gate 		return ("Could not get profile property.");
19827c478bd9Sstevel@tonic-gate 
19837c478bd9Sstevel@tonic-gate 	/* Extract the command from the command line. */
19847c478bd9Sstevel@tonic-gate 	cp = strpbrk(cmdline, " \t");
19857c478bd9Sstevel@tonic-gate 
19867c478bd9Sstevel@tonic-gate 	if (cp == NULL) {
19877c478bd9Sstevel@tonic-gate 		cmdp = cmdline;
19887c478bd9Sstevel@tonic-gate 	} else {
19897c478bd9Sstevel@tonic-gate 		(void) strncpy(cmd, cmdline, cp - cmdline);
19907c478bd9Sstevel@tonic-gate 		cmd[cp - cmdline] = '\0';
19917c478bd9Sstevel@tonic-gate 		cmdp = cmd;
19927c478bd9Sstevel@tonic-gate 	}
19937c478bd9Sstevel@tonic-gate 
19947c478bd9Sstevel@tonic-gate 	/* Require that cmdp[0] == '/'? */
19957c478bd9Sstevel@tonic-gate 
19967c478bd9Sstevel@tonic-gate 	eap = getexecprof(buf, KV_COMMAND, cmdp, GET_ONE);
19977c478bd9Sstevel@tonic-gate 	if (eap == NULL)
19987c478bd9Sstevel@tonic-gate 		return ("Could not find profile.");
19997c478bd9Sstevel@tonic-gate 
20007c478bd9Sstevel@tonic-gate 	/* Based on pfexec.c */
20017c478bd9Sstevel@tonic-gate 
20027c478bd9Sstevel@tonic-gate 	/* Get the euid first so we don't override ci->pwd for the uid. */
20037c478bd9Sstevel@tonic-gate 	if ((value = kva_match(eap->attr, EXECATTR_EUID_KW)) != NULL) {
20047c478bd9Sstevel@tonic-gate 		if (get_uid(value, ci, &ci->euid) != 0) {
2005f48205beScasper 			ci->euid = (uid_t)-1;
20067c478bd9Sstevel@tonic-gate 			errstr = "Could not interpret profile euid.";
20077c478bd9Sstevel@tonic-gate 			goto out;
20087c478bd9Sstevel@tonic-gate 		}
20097c478bd9Sstevel@tonic-gate 	}
20107c478bd9Sstevel@tonic-gate 
20117c478bd9Sstevel@tonic-gate 	if ((value = kva_match(eap->attr, EXECATTR_UID_KW)) != NULL) {
20127c478bd9Sstevel@tonic-gate 		if (get_uid(value, ci, &ci->uid) != 0) {
2013f48205beScasper 			ci->euid = ci->uid = (uid_t)-1;
20147c478bd9Sstevel@tonic-gate 			errstr = "Could not interpret profile uid.";
20157c478bd9Sstevel@tonic-gate 			goto out;
20167c478bd9Sstevel@tonic-gate 		}
20177c478bd9Sstevel@tonic-gate 		ci->euid = ci->uid;
20187c478bd9Sstevel@tonic-gate 	}
20197c478bd9Sstevel@tonic-gate 
20207c478bd9Sstevel@tonic-gate 	if ((value = kva_match(eap->attr, EXECATTR_GID_KW)) != NULL) {
20217c478bd9Sstevel@tonic-gate 		ci->egid = ci->gid = get_gid(value);
2022f48205beScasper 		if (ci->gid == (gid_t)-1) {
20237c478bd9Sstevel@tonic-gate 			errstr = "Could not interpret profile gid.";
20247c478bd9Sstevel@tonic-gate 			goto out;
20257c478bd9Sstevel@tonic-gate 		}
20267c478bd9Sstevel@tonic-gate 	}
20277c478bd9Sstevel@tonic-gate 
20287c478bd9Sstevel@tonic-gate 	if ((value = kva_match(eap->attr, EXECATTR_EGID_KW)) != NULL) {
20297c478bd9Sstevel@tonic-gate 		ci->egid = get_gid(value);
2030f48205beScasper 		if (ci->egid == (gid_t)-1) {
20317c478bd9Sstevel@tonic-gate 			errstr = "Could not interpret profile egid.";
20327c478bd9Sstevel@tonic-gate 			goto out;
20337c478bd9Sstevel@tonic-gate 		}
20347c478bd9Sstevel@tonic-gate 	}
20357c478bd9Sstevel@tonic-gate 
20367c478bd9Sstevel@tonic-gate 	if ((value = kva_match(eap->attr, EXECATTR_LPRIV_KW)) != NULL) {
20377c478bd9Sstevel@tonic-gate 		ci->lpriv_set = priv_str_to_set(value, ",", NULL);
20387c478bd9Sstevel@tonic-gate 		if (ci->lpriv_set == NULL) {
20397c478bd9Sstevel@tonic-gate 			if (errno != EINVAL)
20407c478bd9Sstevel@tonic-gate 				errstr = ALLOCFAIL;
20417c478bd9Sstevel@tonic-gate 			else
20427c478bd9Sstevel@tonic-gate 				errstr = "Could not interpret profile "
20437c478bd9Sstevel@tonic-gate 				    "limitprivs.";
20447c478bd9Sstevel@tonic-gate 			goto out;
20457c478bd9Sstevel@tonic-gate 		}
20467c478bd9Sstevel@tonic-gate 	}
20477c478bd9Sstevel@tonic-gate 
20487c478bd9Sstevel@tonic-gate 	if ((value = kva_match(eap->attr, EXECATTR_IPRIV_KW)) != NULL) {
20497c478bd9Sstevel@tonic-gate 		ci->priv_set = priv_str_to_set(value, ",", NULL);
20507c478bd9Sstevel@tonic-gate 		if (ci->priv_set == NULL) {
20517c478bd9Sstevel@tonic-gate 			if (errno != EINVAL)
20527c478bd9Sstevel@tonic-gate 				errstr = ALLOCFAIL;
20537c478bd9Sstevel@tonic-gate 			else
20547c478bd9Sstevel@tonic-gate 				errstr = "Could not interpret profile privs.";
20557c478bd9Sstevel@tonic-gate 			goto out;
20567c478bd9Sstevel@tonic-gate 		}
20577c478bd9Sstevel@tonic-gate 	}
20587c478bd9Sstevel@tonic-gate 
20597c478bd9Sstevel@tonic-gate out:
20607c478bd9Sstevel@tonic-gate 	free_execattr(eap);
20617c478bd9Sstevel@tonic-gate 
20627c478bd9Sstevel@tonic-gate 	return (errstr);
20637c478bd9Sstevel@tonic-gate }
20647c478bd9Sstevel@tonic-gate 
20657c478bd9Sstevel@tonic-gate /*
20667c478bd9Sstevel@tonic-gate  * Eventually, we will return a structured error in the case of
20677c478bd9Sstevel@tonic-gate  * retryable or abortable failures such as memory allocation errors and
20687c478bd9Sstevel@tonic-gate  * repository connection failures.  For now, these failures are just
20697c478bd9Sstevel@tonic-gate  * encoded in the failure string.
20707c478bd9Sstevel@tonic-gate  */
20717c478bd9Sstevel@tonic-gate static const char *
20727c478bd9Sstevel@tonic-gate get_ids(scf_propertygroup_t *pg, scf_property_t *prop, scf_value_t *val,
20737c478bd9Sstevel@tonic-gate     struct method_context *ci)
20747c478bd9Sstevel@tonic-gate {
20757c478bd9Sstevel@tonic-gate 	const char *errstr = NULL;
20767c478bd9Sstevel@tonic-gate 	char *vbuf = ci->vbuf;
20777c478bd9Sstevel@tonic-gate 	ssize_t vbuf_sz = ci->vbuf_sz;
20787c478bd9Sstevel@tonic-gate 	int r;
20797c478bd9Sstevel@tonic-gate 
20807c478bd9Sstevel@tonic-gate 	if (get_astring_val(pg, SCF_PROPERTY_USER, vbuf, vbuf_sz, prop, val) !=
20817c478bd9Sstevel@tonic-gate 	    0) {
20827c478bd9Sstevel@tonic-gate 		errstr = "Could not get user property.";
20837c478bd9Sstevel@tonic-gate 		goto out;
20847c478bd9Sstevel@tonic-gate 	}
20857c478bd9Sstevel@tonic-gate 
20867c478bd9Sstevel@tonic-gate 	if (get_uid(vbuf, ci, &ci->uid) != 0) {
2087f48205beScasper 		ci->uid = (uid_t)-1;
20887c478bd9Sstevel@tonic-gate 		errstr = "Could not interpret user property.";
20897c478bd9Sstevel@tonic-gate 		goto out;
20907c478bd9Sstevel@tonic-gate 	}
20917c478bd9Sstevel@tonic-gate 
20927c478bd9Sstevel@tonic-gate 	if (get_astring_val(pg, SCF_PROPERTY_GROUP, vbuf, vbuf_sz, prop, val) !=
20937c478bd9Sstevel@tonic-gate 	    0) {
20947c478bd9Sstevel@tonic-gate 		errstr = "Could not get group property.";
20957c478bd9Sstevel@tonic-gate 		goto out;
20967c478bd9Sstevel@tonic-gate 	}
20977c478bd9Sstevel@tonic-gate 
20987c478bd9Sstevel@tonic-gate 	if (strcmp(vbuf, ":default") != 0) {
20997c478bd9Sstevel@tonic-gate 		ci->gid = get_gid(vbuf);
2100f48205beScasper 		if (ci->gid == (gid_t)-1) {
21017c478bd9Sstevel@tonic-gate 			errstr = "Could not interpret group property.";
21027c478bd9Sstevel@tonic-gate 			goto out;
21037c478bd9Sstevel@tonic-gate 		}
21047c478bd9Sstevel@tonic-gate 	} else {
21057c478bd9Sstevel@tonic-gate 		switch (r = lookup_pwd(ci)) {
21067c478bd9Sstevel@tonic-gate 		case 0:
21077c478bd9Sstevel@tonic-gate 			ci->gid = ci->pwd.pw_gid;
21087c478bd9Sstevel@tonic-gate 			break;
21097c478bd9Sstevel@tonic-gate 
21107c478bd9Sstevel@tonic-gate 		case ENOENT:
2111f48205beScasper 			ci->gid = (gid_t)-1;
21127c478bd9Sstevel@tonic-gate 			errstr = "No passwd entry.";
21137c478bd9Sstevel@tonic-gate 			goto out;
21147c478bd9Sstevel@tonic-gate 
21157c478bd9Sstevel@tonic-gate 		case ENOMEM:
21167c478bd9Sstevel@tonic-gate 			errstr = "Out of memory.";
21177c478bd9Sstevel@tonic-gate 			goto out;
21187c478bd9Sstevel@tonic-gate 
21197c478bd9Sstevel@tonic-gate 		case EIO:
21207c478bd9Sstevel@tonic-gate 		case EMFILE:
21217c478bd9Sstevel@tonic-gate 		case ENFILE:
21227c478bd9Sstevel@tonic-gate 			errstr = "getpwuid_r() failed.";
21237c478bd9Sstevel@tonic-gate 			goto out;
21247c478bd9Sstevel@tonic-gate 
21257c478bd9Sstevel@tonic-gate 		default:
21267c478bd9Sstevel@tonic-gate 			bad_fail("lookup_pwd", r);
21277c478bd9Sstevel@tonic-gate 		}
21287c478bd9Sstevel@tonic-gate 	}
21297c478bd9Sstevel@tonic-gate 
21307c478bd9Sstevel@tonic-gate 	if (get_astring_val(pg, SCF_PROPERTY_SUPP_GROUPS, vbuf, vbuf_sz, prop,
21317c478bd9Sstevel@tonic-gate 	    val) != 0) {
21327c478bd9Sstevel@tonic-gate 		errstr = "Could not get supplemental groups property.";
21337c478bd9Sstevel@tonic-gate 		goto out;
21347c478bd9Sstevel@tonic-gate 	}
21357c478bd9Sstevel@tonic-gate 
21367c478bd9Sstevel@tonic-gate 	if (strcmp(vbuf, ":default") != 0) {
21377c478bd9Sstevel@tonic-gate 		switch (r = get_groups(vbuf, ci)) {
21387c478bd9Sstevel@tonic-gate 		case 0:
21397c478bd9Sstevel@tonic-gate 			break;
21407c478bd9Sstevel@tonic-gate 
21417c478bd9Sstevel@tonic-gate 		case EINVAL:
21427c478bd9Sstevel@tonic-gate 			errstr =
21437c478bd9Sstevel@tonic-gate 			    "Could not interpret supplemental groups property.";
21447c478bd9Sstevel@tonic-gate 			goto out;
21457c478bd9Sstevel@tonic-gate 
21467c478bd9Sstevel@tonic-gate 		case E2BIG:
21477c478bd9Sstevel@tonic-gate 			errstr = "Too many supplemental groups.";
21487c478bd9Sstevel@tonic-gate 			goto out;
21497c478bd9Sstevel@tonic-gate 
21507c478bd9Sstevel@tonic-gate 		default:
21517c478bd9Sstevel@tonic-gate 			bad_fail("get_groups", r);
21527c478bd9Sstevel@tonic-gate 		}
21537c478bd9Sstevel@tonic-gate 	} else {
21547c478bd9Sstevel@tonic-gate 		ci->ngroups = -1;
21557c478bd9Sstevel@tonic-gate 	}
21567c478bd9Sstevel@tonic-gate 
21577c478bd9Sstevel@tonic-gate 	if (get_astring_val(pg, SCF_PROPERTY_PRIVILEGES, vbuf, vbuf_sz, prop,
21587c478bd9Sstevel@tonic-gate 	    val) != 0) {
21597c478bd9Sstevel@tonic-gate 		errstr = "Could not get privileges property.";
21607c478bd9Sstevel@tonic-gate 		goto out;
21617c478bd9Sstevel@tonic-gate 	}
21627c478bd9Sstevel@tonic-gate 
21637c478bd9Sstevel@tonic-gate 	/*
21647c478bd9Sstevel@tonic-gate 	 * For default privs, we need to keep priv_set == NULL, as
21657c478bd9Sstevel@tonic-gate 	 * we use this test elsewhere.
21667c478bd9Sstevel@tonic-gate 	 */
21677c478bd9Sstevel@tonic-gate 	if (strcmp(vbuf, ":default") != 0) {
21687c478bd9Sstevel@tonic-gate 		ci->priv_set = priv_str_to_set(vbuf, ",", NULL);
21697c478bd9Sstevel@tonic-gate 		if (ci->priv_set == NULL) {
21707c478bd9Sstevel@tonic-gate 			if (errno != EINVAL) {
21717c478bd9Sstevel@tonic-gate 				errstr = ALLOCFAIL;
21727c478bd9Sstevel@tonic-gate 			} else {
21737c478bd9Sstevel@tonic-gate 				errstr = "Could not interpret privileges "
21747c478bd9Sstevel@tonic-gate 				    "property.";
21757c478bd9Sstevel@tonic-gate 			}
21767c478bd9Sstevel@tonic-gate 			goto out;
21777c478bd9Sstevel@tonic-gate 		}
21787c478bd9Sstevel@tonic-gate 	}
21797c478bd9Sstevel@tonic-gate 
21807c478bd9Sstevel@tonic-gate 	if (get_astring_val(pg, SCF_PROPERTY_LIMIT_PRIVILEGES, vbuf, vbuf_sz,
21817c478bd9Sstevel@tonic-gate 	    prop, val) != 0) {
21827c478bd9Sstevel@tonic-gate 		errstr = "Could not get limit_privileges property.";
21837c478bd9Sstevel@tonic-gate 		goto out;
21847c478bd9Sstevel@tonic-gate 	}
21857c478bd9Sstevel@tonic-gate 
21867c478bd9Sstevel@tonic-gate 	if (strcmp(vbuf, ":default") == 0)
21877c478bd9Sstevel@tonic-gate 		/*
21887c478bd9Sstevel@tonic-gate 		 * L must default to all privileges so root NPA services see
21897c478bd9Sstevel@tonic-gate 		 * iE = all.  "zone" is all privileges available in the current
21907c478bd9Sstevel@tonic-gate 		 * zone, equivalent to "all" in the global zone.
21917c478bd9Sstevel@tonic-gate 		 */
21927c478bd9Sstevel@tonic-gate 		(void) strcpy(vbuf, "zone");
21937c478bd9Sstevel@tonic-gate 
21947c478bd9Sstevel@tonic-gate 	ci->lpriv_set = priv_str_to_set(vbuf, ",", NULL);
21957c478bd9Sstevel@tonic-gate 	if (ci->lpriv_set == NULL) {
21967c478bd9Sstevel@tonic-gate 		if (errno != EINVAL)
21977c478bd9Sstevel@tonic-gate 			errstr = ALLOCFAIL;
21987c478bd9Sstevel@tonic-gate 		else {
21997c478bd9Sstevel@tonic-gate 			errstr = "Could not interpret limit_privileges "
22007c478bd9Sstevel@tonic-gate 			    "property.";
22017c478bd9Sstevel@tonic-gate 		}
22027c478bd9Sstevel@tonic-gate 		goto out;
22037c478bd9Sstevel@tonic-gate 	}
22047c478bd9Sstevel@tonic-gate 
22057c478bd9Sstevel@tonic-gate out:
22067c478bd9Sstevel@tonic-gate 	return (errstr);
22077c478bd9Sstevel@tonic-gate }
22087c478bd9Sstevel@tonic-gate 
22097c478bd9Sstevel@tonic-gate static int
22107c478bd9Sstevel@tonic-gate get_environment(scf_handle_t *h, scf_propertygroup_t *pg,
22117c478bd9Sstevel@tonic-gate     struct method_context *mcp, scf_property_t *prop, scf_value_t *val)
22127c478bd9Sstevel@tonic-gate {
22137c478bd9Sstevel@tonic-gate 	scf_iter_t *iter;
22147c478bd9Sstevel@tonic-gate 	scf_type_t type;
22157c478bd9Sstevel@tonic-gate 	size_t i = 0;
22167c478bd9Sstevel@tonic-gate 	int ret;
22177c478bd9Sstevel@tonic-gate 
22187c478bd9Sstevel@tonic-gate 	if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, prop) != 0) {
22197c478bd9Sstevel@tonic-gate 		if (scf_error() == SCF_ERROR_NOT_FOUND)
22207c478bd9Sstevel@tonic-gate 			return (ENOENT);
22217c478bd9Sstevel@tonic-gate 		return (scf_error());
22227c478bd9Sstevel@tonic-gate 	}
22237c478bd9Sstevel@tonic-gate 	if (scf_property_type(prop, &type) != 0)
22247c478bd9Sstevel@tonic-gate 		return (scf_error());
22257c478bd9Sstevel@tonic-gate 	if (type != SCF_TYPE_ASTRING)
22267c478bd9Sstevel@tonic-gate 		return (EINVAL);
22277c478bd9Sstevel@tonic-gate 	if ((iter = scf_iter_create(h)) == NULL)
22287c478bd9Sstevel@tonic-gate 		return (scf_error());
22297c478bd9Sstevel@tonic-gate 
22307c478bd9Sstevel@tonic-gate 	if (scf_iter_property_values(iter, prop) != 0) {
22317c478bd9Sstevel@tonic-gate 		ret = scf_error();
22327c478bd9Sstevel@tonic-gate 		scf_iter_destroy(iter);
22337c478bd9Sstevel@tonic-gate 		return (ret);
22347c478bd9Sstevel@tonic-gate 	}
22357c478bd9Sstevel@tonic-gate 
22367c478bd9Sstevel@tonic-gate 	mcp->env_sz = 10;
22377c478bd9Sstevel@tonic-gate 
22387c478bd9Sstevel@tonic-gate 	if ((mcp->env = uu_zalloc(sizeof (*mcp->env) * mcp->env_sz)) == NULL) {
22397c478bd9Sstevel@tonic-gate 		ret = ENOMEM;
22407c478bd9Sstevel@tonic-gate 		goto out;
22417c478bd9Sstevel@tonic-gate 	}
22427c478bd9Sstevel@tonic-gate 
22437c478bd9Sstevel@tonic-gate 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
22447c478bd9Sstevel@tonic-gate 		ret = scf_value_get_as_string(val, mcp->vbuf, mcp->vbuf_sz);
22457c478bd9Sstevel@tonic-gate 		if (ret == -1) {
22467c478bd9Sstevel@tonic-gate 			ret = scf_error();
22477c478bd9Sstevel@tonic-gate 			goto out;
22487c478bd9Sstevel@tonic-gate 		}
22497c478bd9Sstevel@tonic-gate 
22507c478bd9Sstevel@tonic-gate 		if ((mcp->env[i] = strdup(mcp->vbuf)) == NULL) {
22517c478bd9Sstevel@tonic-gate 			ret = ENOMEM;
22527c478bd9Sstevel@tonic-gate 			goto out;
22537c478bd9Sstevel@tonic-gate 		}
22547c478bd9Sstevel@tonic-gate 
22557c478bd9Sstevel@tonic-gate 		if (++i == mcp->env_sz) {
22567c478bd9Sstevel@tonic-gate 			char **env;
22577c478bd9Sstevel@tonic-gate 			mcp->env_sz *= 2;
22587c478bd9Sstevel@tonic-gate 			env = uu_zalloc(sizeof (*mcp->env) * mcp->env_sz);
22597c478bd9Sstevel@tonic-gate 			if (env == NULL) {
22607c478bd9Sstevel@tonic-gate 				ret = ENOMEM;
22617c478bd9Sstevel@tonic-gate 				goto out;
22627c478bd9Sstevel@tonic-gate 			}
22637c478bd9Sstevel@tonic-gate 			(void) memcpy(env, mcp->env,
22647c478bd9Sstevel@tonic-gate 			    sizeof (*mcp->env) * (mcp->env_sz / 2));
22657c478bd9Sstevel@tonic-gate 			free(mcp->env);
22667c478bd9Sstevel@tonic-gate 			mcp->env = env;
22677c478bd9Sstevel@tonic-gate 		}
22687c478bd9Sstevel@tonic-gate 	}
22697c478bd9Sstevel@tonic-gate 
22707c478bd9Sstevel@tonic-gate 	if (ret == -1)
22717c478bd9Sstevel@tonic-gate 		ret = scf_error();
22727c478bd9Sstevel@tonic-gate 
22737c478bd9Sstevel@tonic-gate out:
22747c478bd9Sstevel@tonic-gate 	scf_iter_destroy(iter);
22757c478bd9Sstevel@tonic-gate 	return (ret);
22767c478bd9Sstevel@tonic-gate }
22777c478bd9Sstevel@tonic-gate 
22787c478bd9Sstevel@tonic-gate /*
22797c478bd9Sstevel@tonic-gate  * Fetch method context information from the repository, allocate and fill
22807c478bd9Sstevel@tonic-gate  * a method_context structure, return it in *mcpp, and return NULL.  On error,
22817c478bd9Sstevel@tonic-gate  * return a human-readable string which indicates the error.
22827c478bd9Sstevel@tonic-gate  *
22837c478bd9Sstevel@tonic-gate  * Eventually, we will return a structured error in the case of
22847c478bd9Sstevel@tonic-gate  * retryable or abortable failures such as memory allocation errors and
22857c478bd9Sstevel@tonic-gate  * repository connection failures.  For now, these failures are just
22867c478bd9Sstevel@tonic-gate  * encoded in the failure string.
22877c478bd9Sstevel@tonic-gate  */
22887c478bd9Sstevel@tonic-gate const char *
22897c478bd9Sstevel@tonic-gate restarter_get_method_context(uint_t version, scf_instance_t *inst,
22907c478bd9Sstevel@tonic-gate     scf_snapshot_t *snap, const char *mname, const char *cmdline,
22917c478bd9Sstevel@tonic-gate     struct method_context **mcpp)
22927c478bd9Sstevel@tonic-gate {
22937c478bd9Sstevel@tonic-gate 	scf_handle_t *h;
22947c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *methpg = NULL;
22957c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *instpg = NULL;
22967c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg = NULL;
22977c478bd9Sstevel@tonic-gate 	scf_property_t *prop = NULL;
22987c478bd9Sstevel@tonic-gate 	scf_value_t *val = NULL;
22997c478bd9Sstevel@tonic-gate 	scf_type_t ty;
23007c478bd9Sstevel@tonic-gate 	uint8_t use_profile;
23017c478bd9Sstevel@tonic-gate 	int ret;
23027c478bd9Sstevel@tonic-gate 	const char *errstr = NULL;
23037c478bd9Sstevel@tonic-gate 	struct method_context *cip;
23047c478bd9Sstevel@tonic-gate 
23057c478bd9Sstevel@tonic-gate 
23067c478bd9Sstevel@tonic-gate 	if (version != RESTARTER_METHOD_CONTEXT_VERSION)
23077c478bd9Sstevel@tonic-gate 		return ("Unknown method_context version.");
23087c478bd9Sstevel@tonic-gate 
23097c478bd9Sstevel@tonic-gate 	/* Get the handle before we allocate anything. */
23107c478bd9Sstevel@tonic-gate 	h = scf_instance_handle(inst);
23117c478bd9Sstevel@tonic-gate 	if (h == NULL)
23127c478bd9Sstevel@tonic-gate 		return (scf_strerror(scf_error()));
23137c478bd9Sstevel@tonic-gate 
23147c478bd9Sstevel@tonic-gate 	cip = malloc(sizeof (*cip));
23157c478bd9Sstevel@tonic-gate 	if (cip == NULL)
23167c478bd9Sstevel@tonic-gate 		return (ALLOCFAIL);
23177c478bd9Sstevel@tonic-gate 
23187c478bd9Sstevel@tonic-gate 	(void) memset(cip, 0, sizeof (*cip));
2319f48205beScasper 	cip->uid = (uid_t)-1;
2320f48205beScasper 	cip->euid = (uid_t)-1;
2321f48205beScasper 	cip->gid = (gid_t)-1;
2322f48205beScasper 	cip->egid = (gid_t)-1;
23237c478bd9Sstevel@tonic-gate 
23247c478bd9Sstevel@tonic-gate 	cip->vbuf_sz = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
23257c478bd9Sstevel@tonic-gate 	assert(cip->vbuf_sz >= 0);
23267c478bd9Sstevel@tonic-gate 	cip->vbuf = malloc(cip->vbuf_sz);
23277c478bd9Sstevel@tonic-gate 	if (cip->vbuf == NULL) {
23287c478bd9Sstevel@tonic-gate 		free(cip);
23297c478bd9Sstevel@tonic-gate 		return (ALLOCFAIL);
23307c478bd9Sstevel@tonic-gate 	}
23317c478bd9Sstevel@tonic-gate 
23327c478bd9Sstevel@tonic-gate 	if ((instpg = scf_pg_create(h)) == NULL ||
23337c478bd9Sstevel@tonic-gate 	    (methpg = scf_pg_create(h)) == NULL ||
23347c478bd9Sstevel@tonic-gate 	    (prop = scf_property_create(h)) == NULL ||
23357c478bd9Sstevel@tonic-gate 	    (val = scf_value_create(h)) == NULL) {
23367c478bd9Sstevel@tonic-gate 		errstr = ALLOCFAIL;
23377c478bd9Sstevel@tonic-gate 		goto out;
23387c478bd9Sstevel@tonic-gate 	}
23397c478bd9Sstevel@tonic-gate 
23407c478bd9Sstevel@tonic-gate 	/*
23417c478bd9Sstevel@tonic-gate 	 * The method environment, and the credentials/profile data,
23427c478bd9Sstevel@tonic-gate 	 * may be found either in the pg for the method (methpg),
23437c478bd9Sstevel@tonic-gate 	 * or in the instance/service SCF_PG_METHOD_CONTEXT pg (named
23447c478bd9Sstevel@tonic-gate 	 * instpg below).
23457c478bd9Sstevel@tonic-gate 	 */
23467c478bd9Sstevel@tonic-gate 
23477c478bd9Sstevel@tonic-gate 	if (scf_instance_get_pg_composed(inst, snap, mname, methpg) !=
23487c478bd9Sstevel@tonic-gate 	    SCF_SUCCESS) {
23497c478bd9Sstevel@tonic-gate 		errstr = scf_strerror(scf_error());
23507c478bd9Sstevel@tonic-gate 		goto out;
23517c478bd9Sstevel@tonic-gate 	}
23527c478bd9Sstevel@tonic-gate 
23537c478bd9Sstevel@tonic-gate 	if (scf_instance_get_pg_composed(inst, snap, SCF_PG_METHOD_CONTEXT,
23547c478bd9Sstevel@tonic-gate 	    instpg) != SCF_SUCCESS) {
23557c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND) {
23567c478bd9Sstevel@tonic-gate 			errstr = scf_strerror(scf_error());
23577c478bd9Sstevel@tonic-gate 			goto out;
23587c478bd9Sstevel@tonic-gate 		}
23597c478bd9Sstevel@tonic-gate 		scf_pg_destroy(instpg);
23607c478bd9Sstevel@tonic-gate 		instpg = NULL;
23617c478bd9Sstevel@tonic-gate 	}
23627c478bd9Sstevel@tonic-gate 
23637c478bd9Sstevel@tonic-gate 	ret = get_environment(h, methpg, cip, prop, val);
23647c478bd9Sstevel@tonic-gate 	if (ret == ENOENT && instpg != NULL) {
23657c478bd9Sstevel@tonic-gate 		ret = get_environment(h, instpg, cip, prop, val);
23667c478bd9Sstevel@tonic-gate 	}
23677c478bd9Sstevel@tonic-gate 
23687c478bd9Sstevel@tonic-gate 	switch (ret) {
23697c478bd9Sstevel@tonic-gate 	case 0:
23707c478bd9Sstevel@tonic-gate 	case ENOENT:
23717c478bd9Sstevel@tonic-gate 		break;
23727c478bd9Sstevel@tonic-gate 	case ENOMEM:
23737c478bd9Sstevel@tonic-gate 		errstr = "Out of memory.";
23747c478bd9Sstevel@tonic-gate 		goto out;
23757c478bd9Sstevel@tonic-gate 	case EINVAL:
23767c478bd9Sstevel@tonic-gate 		errstr = "Invalid method environment.";
23777c478bd9Sstevel@tonic-gate 		goto out;
23787c478bd9Sstevel@tonic-gate 	default:
23797c478bd9Sstevel@tonic-gate 		errstr = scf_strerror(ret);
23807c478bd9Sstevel@tonic-gate 		goto out;
23817c478bd9Sstevel@tonic-gate 	}
23827c478bd9Sstevel@tonic-gate 
23837c478bd9Sstevel@tonic-gate 	pg = methpg;
23847c478bd9Sstevel@tonic-gate 
23857c478bd9Sstevel@tonic-gate 	ret = scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, prop);
23867c478bd9Sstevel@tonic-gate 	if (ret && scf_error() == SCF_ERROR_NOT_FOUND && instpg != NULL) {
23877c478bd9Sstevel@tonic-gate 		pg = instpg;
23887c478bd9Sstevel@tonic-gate 		ret = scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, prop);
23897c478bd9Sstevel@tonic-gate 	}
23907c478bd9Sstevel@tonic-gate 
23917c478bd9Sstevel@tonic-gate 	if (ret) {
23927c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
23937c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
23947c478bd9Sstevel@tonic-gate 			/* No context: use defaults */
23957c478bd9Sstevel@tonic-gate 			cip->uid = 0;
23967c478bd9Sstevel@tonic-gate 			cip->gid = 0;
23977c478bd9Sstevel@tonic-gate 			*mcpp = cip;
23987c478bd9Sstevel@tonic-gate 			goto out;
23997c478bd9Sstevel@tonic-gate 
24007c478bd9Sstevel@tonic-gate 		case SCF_ERROR_CONNECTION_BROKEN:
24017c478bd9Sstevel@tonic-gate 			errstr = RCBROKEN;
24027c478bd9Sstevel@tonic-gate 			goto out;
24037c478bd9Sstevel@tonic-gate 
24047c478bd9Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
24057c478bd9Sstevel@tonic-gate 			errstr = "\"use_profile\" property deleted.";
24067c478bd9Sstevel@tonic-gate 			goto out;
24077c478bd9Sstevel@tonic-gate 
24087c478bd9Sstevel@tonic-gate 		case SCF_ERROR_HANDLE_MISMATCH:
24097c478bd9Sstevel@tonic-gate 		case SCF_ERROR_INVALID_ARGUMENT:
24107c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
24117c478bd9Sstevel@tonic-gate 		default:
24127c478bd9Sstevel@tonic-gate 			bad_fail("scf_pg_get_property", scf_error());
24137c478bd9Sstevel@tonic-gate 		}
24147c478bd9Sstevel@tonic-gate 	}
24157c478bd9Sstevel@tonic-gate 
24167c478bd9Sstevel@tonic-gate 	if (scf_property_type(prop, &ty) != SCF_SUCCESS) {
24177c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
24187c478bd9Sstevel@tonic-gate 		case SCF_ERROR_CONNECTION_BROKEN:
24197c478bd9Sstevel@tonic-gate 			errstr = RCBROKEN;
24207c478bd9Sstevel@tonic-gate 			break;
24217c478bd9Sstevel@tonic-gate 
24227c478bd9Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
24237c478bd9Sstevel@tonic-gate 			errstr = "\"use profile\" property deleted.";
24247c478bd9Sstevel@tonic-gate 			break;
24257c478bd9Sstevel@tonic-gate 
24267c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
24277c478bd9Sstevel@tonic-gate 		default:
24287c478bd9Sstevel@tonic-gate 			bad_fail("scf_property_type", scf_error());
24297c478bd9Sstevel@tonic-gate 		}
24307c478bd9Sstevel@tonic-gate 
24317c478bd9Sstevel@tonic-gate 		goto out;
24327c478bd9Sstevel@tonic-gate 	}
24337c478bd9Sstevel@tonic-gate 
24347c478bd9Sstevel@tonic-gate 	if (ty != SCF_TYPE_BOOLEAN) {
24357c478bd9Sstevel@tonic-gate 		errstr = "\"use profile\" property is not boolean.";
24367c478bd9Sstevel@tonic-gate 		goto out;
24377c478bd9Sstevel@tonic-gate 	}
24387c478bd9Sstevel@tonic-gate 
24397c478bd9Sstevel@tonic-gate 	if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
24407c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
24417c478bd9Sstevel@tonic-gate 		case SCF_ERROR_CONNECTION_BROKEN:
24427c478bd9Sstevel@tonic-gate 			errstr = RCBROKEN;
24437c478bd9Sstevel@tonic-gate 			break;
24447c478bd9Sstevel@tonic-gate 
24457c478bd9Sstevel@tonic-gate 		case SCF_ERROR_CONSTRAINT_VIOLATED:
24467c478bd9Sstevel@tonic-gate 			errstr =
24477c478bd9Sstevel@tonic-gate 			    "\"use profile\" property has multiple values.";
24487c478bd9Sstevel@tonic-gate 			break;
24497c478bd9Sstevel@tonic-gate 
24507c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
24517c478bd9Sstevel@tonic-gate 			errstr = "\"use profile\" property has no values.";
24527c478bd9Sstevel@tonic-gate 			break;
24537c478bd9Sstevel@tonic-gate 
24547c478bd9Sstevel@tonic-gate 		default:
24557c478bd9Sstevel@tonic-gate 			bad_fail("scf_property_get_value", scf_error());
24567c478bd9Sstevel@tonic-gate 		}
24577c478bd9Sstevel@tonic-gate 
24587c478bd9Sstevel@tonic-gate 		goto out;
24597c478bd9Sstevel@tonic-gate 	}
24607c478bd9Sstevel@tonic-gate 
24617c478bd9Sstevel@tonic-gate 	ret = scf_value_get_boolean(val, &use_profile);
24627c478bd9Sstevel@tonic-gate 	assert(ret == SCF_SUCCESS);
24637c478bd9Sstevel@tonic-gate 
24647c478bd9Sstevel@tonic-gate 	/* get ids & privileges */
24657c478bd9Sstevel@tonic-gate 	if (use_profile)
24667c478bd9Sstevel@tonic-gate 		errstr = get_profile(pg, prop, val, cmdline, cip);
24677c478bd9Sstevel@tonic-gate 	else
24687c478bd9Sstevel@tonic-gate 		errstr = get_ids(pg, prop, val, cip);
24697c478bd9Sstevel@tonic-gate 	if (errstr != NULL)
24707c478bd9Sstevel@tonic-gate 		goto out;
24717c478bd9Sstevel@tonic-gate 
24727c478bd9Sstevel@tonic-gate 	/* get working directory */
24737c478bd9Sstevel@tonic-gate 	if (get_astring_val(pg, SCF_PROPERTY_WORKING_DIRECTORY, cip->vbuf,
24747c478bd9Sstevel@tonic-gate 	    cip->vbuf_sz, prop, val) != 0) {
24757c478bd9Sstevel@tonic-gate 		errstr = "Could not get value for working directory.";
24767c478bd9Sstevel@tonic-gate 		goto out;
24777c478bd9Sstevel@tonic-gate 	}
24787c478bd9Sstevel@tonic-gate 
24797c478bd9Sstevel@tonic-gate 	if (strcmp(cip->vbuf, ":default") == 0 ||
24807c478bd9Sstevel@tonic-gate 	    strcmp(cip->vbuf, ":home") == 0) {
24817c478bd9Sstevel@tonic-gate 		switch (ret = lookup_pwd(cip)) {
24827c478bd9Sstevel@tonic-gate 		case 0:
24837c478bd9Sstevel@tonic-gate 			break;
24847c478bd9Sstevel@tonic-gate 
24857c478bd9Sstevel@tonic-gate 		case ENOMEM:
24867c478bd9Sstevel@tonic-gate 			errstr = "Out of memory.";
24877c478bd9Sstevel@tonic-gate 			goto out;
24887c478bd9Sstevel@tonic-gate 
24897c478bd9Sstevel@tonic-gate 		case ENOENT:
24907c478bd9Sstevel@tonic-gate 		case EIO:
24917c478bd9Sstevel@tonic-gate 		case EMFILE:
24927c478bd9Sstevel@tonic-gate 		case ENFILE:
24937c478bd9Sstevel@tonic-gate 			errstr = "Could not get passwd entry.";
24947c478bd9Sstevel@tonic-gate 			goto out;
24957c478bd9Sstevel@tonic-gate 
24967c478bd9Sstevel@tonic-gate 		default:
24977c478bd9Sstevel@tonic-gate 			bad_fail("lookup_pwd", ret);
24987c478bd9Sstevel@tonic-gate 		}
24997c478bd9Sstevel@tonic-gate 
25007c478bd9Sstevel@tonic-gate 		cip->working_dir = strdup(cip->pwd.pw_dir);
25017c478bd9Sstevel@tonic-gate 		if (cip->working_dir == NULL) {
25027c478bd9Sstevel@tonic-gate 			errstr = ALLOCFAIL;
25037c478bd9Sstevel@tonic-gate 			goto out;
25047c478bd9Sstevel@tonic-gate 		}
25057c478bd9Sstevel@tonic-gate 	} else {
25067c478bd9Sstevel@tonic-gate 		cip->working_dir = strdup(cip->vbuf);
25077c478bd9Sstevel@tonic-gate 		if (cip->working_dir == NULL) {
25087c478bd9Sstevel@tonic-gate 			errstr = ALLOCFAIL;
25097c478bd9Sstevel@tonic-gate 			goto out;
25107c478bd9Sstevel@tonic-gate 		}
25117c478bd9Sstevel@tonic-gate 	}
25127c478bd9Sstevel@tonic-gate 
25137c478bd9Sstevel@tonic-gate 	/* get (optional) corefile pattern */
25147c478bd9Sstevel@tonic-gate 	if (scf_pg_get_property(pg, SCF_PROPERTY_COREFILE_PATTERN, prop) ==
25157c478bd9Sstevel@tonic-gate 	    SCF_SUCCESS) {
25167c478bd9Sstevel@tonic-gate 		if (get_astring_val(pg, SCF_PROPERTY_COREFILE_PATTERN,
25177c478bd9Sstevel@tonic-gate 		    cip->vbuf, cip->vbuf_sz, prop, val) != 0) {
25187c478bd9Sstevel@tonic-gate 			errstr = "Could not get value for corefile pattern.";
25197c478bd9Sstevel@tonic-gate 			goto out;
25207c478bd9Sstevel@tonic-gate 		}
25217c478bd9Sstevel@tonic-gate 
25227c478bd9Sstevel@tonic-gate 		cip->corefile_pattern = strdup(cip->vbuf);
25237c478bd9Sstevel@tonic-gate 		if (cip->corefile_pattern == NULL) {
25247c478bd9Sstevel@tonic-gate 			errstr = ALLOCFAIL;
25257c478bd9Sstevel@tonic-gate 			goto out;
25267c478bd9Sstevel@tonic-gate 		}
25277c478bd9Sstevel@tonic-gate 	} else {
25287c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
25297c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
25307c478bd9Sstevel@tonic-gate 			/* okay if missing. */
25317c478bd9Sstevel@tonic-gate 			break;
25327c478bd9Sstevel@tonic-gate 
25337c478bd9Sstevel@tonic-gate 		case SCF_ERROR_CONNECTION_BROKEN:
25347c478bd9Sstevel@tonic-gate 			errstr = RCBROKEN;
25357c478bd9Sstevel@tonic-gate 			goto out;
25367c478bd9Sstevel@tonic-gate 
25377c478bd9Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
25387c478bd9Sstevel@tonic-gate 			errstr = "\"corefile_pattern\" property deleted.";
25397c478bd9Sstevel@tonic-gate 			goto out;
25407c478bd9Sstevel@tonic-gate 
25417c478bd9Sstevel@tonic-gate 		case SCF_ERROR_HANDLE_MISMATCH:
25427c478bd9Sstevel@tonic-gate 		case SCF_ERROR_INVALID_ARGUMENT:
25437c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
25447c478bd9Sstevel@tonic-gate 		default:
25457c478bd9Sstevel@tonic-gate 			bad_fail("scf_pg_get_property", scf_error());
25467c478bd9Sstevel@tonic-gate 		}
25477c478bd9Sstevel@tonic-gate 	}
25487c478bd9Sstevel@tonic-gate 
25497c478bd9Sstevel@tonic-gate 	if (restarter_rm_libs_loadable()) {
25507c478bd9Sstevel@tonic-gate 		/* get project */
25517c478bd9Sstevel@tonic-gate 		if (get_astring_val(pg, SCF_PROPERTY_PROJECT, cip->vbuf,
25527c478bd9Sstevel@tonic-gate 		    cip->vbuf_sz, prop, val) != 0) {
25537c478bd9Sstevel@tonic-gate 			errstr = "Could not get project.";
25547c478bd9Sstevel@tonic-gate 			goto out;
25557c478bd9Sstevel@tonic-gate 		}
25567c478bd9Sstevel@tonic-gate 
25577c478bd9Sstevel@tonic-gate 		switch (ret = get_projid(cip->vbuf, cip)) {
25587c478bd9Sstevel@tonic-gate 		case 0:
25597c478bd9Sstevel@tonic-gate 			break;
25607c478bd9Sstevel@tonic-gate 
25617c478bd9Sstevel@tonic-gate 		case ENOMEM:
25627c478bd9Sstevel@tonic-gate 			errstr = "Out of memory.";
25637c478bd9Sstevel@tonic-gate 			goto out;
25647c478bd9Sstevel@tonic-gate 
25657c478bd9Sstevel@tonic-gate 		case ENOENT:
25667c478bd9Sstevel@tonic-gate 			errstr = "Missing passwd or project entry.";
25677c478bd9Sstevel@tonic-gate 			goto out;
25687c478bd9Sstevel@tonic-gate 
25697c478bd9Sstevel@tonic-gate 		case EIO:
25707c478bd9Sstevel@tonic-gate 			errstr = "I/O error.";
25717c478bd9Sstevel@tonic-gate 			goto out;
25727c478bd9Sstevel@tonic-gate 
25737c478bd9Sstevel@tonic-gate 		case EMFILE:
25747c478bd9Sstevel@tonic-gate 		case ENFILE:
25757c478bd9Sstevel@tonic-gate 			errstr = "Out of file descriptors.";
25767c478bd9Sstevel@tonic-gate 			goto out;
25777c478bd9Sstevel@tonic-gate 
25787c478bd9Sstevel@tonic-gate 		case -1:
25797c478bd9Sstevel@tonic-gate 			errstr = "Name service switch is misconfigured.";
25807c478bd9Sstevel@tonic-gate 			goto out;
25817c478bd9Sstevel@tonic-gate 
25827c478bd9Sstevel@tonic-gate 		case ERANGE:
25837c478bd9Sstevel@tonic-gate 			errstr = "Project ID too big.";
25847c478bd9Sstevel@tonic-gate 			goto out;
25857c478bd9Sstevel@tonic-gate 
25867c478bd9Sstevel@tonic-gate 		case EINVAL:
25877c478bd9Sstevel@tonic-gate 			errstr = "Project ID is invalid.";
25887c478bd9Sstevel@tonic-gate 			goto out;
25897c478bd9Sstevel@tonic-gate 
25907c478bd9Sstevel@tonic-gate 		case E2BIG:
25917c478bd9Sstevel@tonic-gate 			errstr = "Project entry is too big.";
25927c478bd9Sstevel@tonic-gate 			goto out;
25937c478bd9Sstevel@tonic-gate 
25947c478bd9Sstevel@tonic-gate 		default:
25957c478bd9Sstevel@tonic-gate 			bad_fail("get_projid", ret);
25967c478bd9Sstevel@tonic-gate 		}
25977c478bd9Sstevel@tonic-gate 
25987c478bd9Sstevel@tonic-gate 		/* get resource pool */
25997c478bd9Sstevel@tonic-gate 		if (get_astring_val(pg, SCF_PROPERTY_RESOURCE_POOL, cip->vbuf,
26007c478bd9Sstevel@tonic-gate 		    cip->vbuf_sz, prop, val) != 0) {
26017c478bd9Sstevel@tonic-gate 			errstr = "Could not get value of resource pool.";
26027c478bd9Sstevel@tonic-gate 			goto out;
26037c478bd9Sstevel@tonic-gate 		}
26047c478bd9Sstevel@tonic-gate 
26057c478bd9Sstevel@tonic-gate 		if (strcmp(cip->vbuf, ":default") != 0) {
26067c478bd9Sstevel@tonic-gate 			cip->resource_pool = strdup(cip->vbuf);
26077c478bd9Sstevel@tonic-gate 			if (cip->resource_pool == NULL) {
26087c478bd9Sstevel@tonic-gate 				errstr = ALLOCFAIL;
26097c478bd9Sstevel@tonic-gate 				goto out;
26107c478bd9Sstevel@tonic-gate 			}
26117c478bd9Sstevel@tonic-gate 		}
26127c478bd9Sstevel@tonic-gate 	}
26137c478bd9Sstevel@tonic-gate 
26147c478bd9Sstevel@tonic-gate 	*mcpp = cip;
26157c478bd9Sstevel@tonic-gate 
26167c478bd9Sstevel@tonic-gate out:
26177c478bd9Sstevel@tonic-gate 	(void) scf_value_destroy(val);
26187c478bd9Sstevel@tonic-gate 	scf_property_destroy(prop);
26197c478bd9Sstevel@tonic-gate 	scf_pg_destroy(instpg);
26207c478bd9Sstevel@tonic-gate 	scf_pg_destroy(methpg);
26217c478bd9Sstevel@tonic-gate 
26227c478bd9Sstevel@tonic-gate 	if (cip->pwbuf != NULL)
26237c478bd9Sstevel@tonic-gate 		free(cip->pwbuf);
26247c478bd9Sstevel@tonic-gate 	free(cip->vbuf);
26257c478bd9Sstevel@tonic-gate 
26267c478bd9Sstevel@tonic-gate 	if (errstr != NULL)
26277c478bd9Sstevel@tonic-gate 		restarter_free_method_context(cip);
26287c478bd9Sstevel@tonic-gate 
26297c478bd9Sstevel@tonic-gate 	return (errstr);
26307c478bd9Sstevel@tonic-gate }
26317c478bd9Sstevel@tonic-gate 
26327c478bd9Sstevel@tonic-gate /*
26337c478bd9Sstevel@tonic-gate  * Modify the current process per the given method_context.  On success, returns
26347c478bd9Sstevel@tonic-gate  * 0.  Note that the environment is not modified by this function to include the
26357c478bd9Sstevel@tonic-gate  * environment variables in cip->env.
26367c478bd9Sstevel@tonic-gate  *
26377c478bd9Sstevel@tonic-gate  * On failure, sets *fp to NULL or the name of the function which failed,
26387c478bd9Sstevel@tonic-gate  * and returns one of the following error codes.  The words in parentheses are
26397c478bd9Sstevel@tonic-gate  * the values to which *fp may be set for the error case.
26407c478bd9Sstevel@tonic-gate  *   ENOMEM - malloc() failed
26417c478bd9Sstevel@tonic-gate  *   EIO - an I/O error occurred (getpwuid_r, chdir)
26427c478bd9Sstevel@tonic-gate  *   EMFILE - process is out of file descriptors (getpwuid_r)
26437c478bd9Sstevel@tonic-gate  *   ENFILE - system is out of file handles (getpwuid_r)
26447c478bd9Sstevel@tonic-gate  *   EINVAL - gid or egid is out of range (setregid)
26457c478bd9Sstevel@tonic-gate  *	      ngroups is too big (setgroups)
26467c478bd9Sstevel@tonic-gate  *	      project's project id is bad (setproject)
26477c478bd9Sstevel@tonic-gate  *	      uid or euid is out of range (setreuid)
26483ad28c1eSrm88369  *	      poolname is invalid (pool_set_binding)
26497c478bd9Sstevel@tonic-gate  *   EPERM - insufficient privilege (setregid, initgroups, setgroups, setppriv,
26507c478bd9Sstevel@tonic-gate  *	         setproject, setreuid, settaskid)
26517c478bd9Sstevel@tonic-gate  *   ENOENT - uid has a passwd entry but no shadow entry
26527c478bd9Sstevel@tonic-gate  *	      working_dir does not exist (chdir)
26537c478bd9Sstevel@tonic-gate  *	      uid has no passwd entry
26547c478bd9Sstevel@tonic-gate  *	      the pool could not be found (pool_set_binding)
26557c478bd9Sstevel@tonic-gate  *   EFAULT - lpriv_set or priv_set has a bad address (setppriv)
26567c478bd9Sstevel@tonic-gate  *	      working_dir has a bad address (chdir)
26577c478bd9Sstevel@tonic-gate  *   EACCES - could not access working_dir (chdir)
26587c478bd9Sstevel@tonic-gate  *	      in a TASK_FINAL task (setproject, settaskid)
26597c478bd9Sstevel@tonic-gate  *	      no resource pool accepting default binding exists (setproject)
26607c478bd9Sstevel@tonic-gate  *   ELOOP - too many symbolic links in working_dir (chdir)
26617c478bd9Sstevel@tonic-gate  *   ENAMETOOLONG - working_dir is too long (chdir)
26627c478bd9Sstevel@tonic-gate  *   ENOLINK - working_dir is on an inaccessible remote machine (chdir)
26637c478bd9Sstevel@tonic-gate  *   ENOTDIR - working_dir is not a directory (chdir)
26647c478bd9Sstevel@tonic-gate  *   ESRCH - uid is not a user of project (setproject)
26657c478bd9Sstevel@tonic-gate  *	     project is invalid (setproject)
26667c478bd9Sstevel@tonic-gate  *	     the resource pool specified for project is unknown (setproject)
26677c478bd9Sstevel@tonic-gate  *   EBADF - the configuration for the pool is invalid (pool_set_binding)
26687c478bd9Sstevel@tonic-gate  *   -1 - core_set_process_path() failed (core_set_process_path)
26697c478bd9Sstevel@tonic-gate  *	  a resource control assignment failed (setproject)
26707c478bd9Sstevel@tonic-gate  *	  a system error occurred during pool_set_binding (pool_set_binding)
26717c478bd9Sstevel@tonic-gate  */
26727c478bd9Sstevel@tonic-gate int
26737c478bd9Sstevel@tonic-gate restarter_set_method_context(struct method_context *cip, const char **fp)
26747c478bd9Sstevel@tonic-gate {
26757c478bd9Sstevel@tonic-gate 	pid_t mypid = -1;
26767c478bd9Sstevel@tonic-gate 	int r, ret;
26777c478bd9Sstevel@tonic-gate 
26787c478bd9Sstevel@tonic-gate 	cip->pwbuf = NULL;
26797c478bd9Sstevel@tonic-gate 	*fp = NULL;
26807c478bd9Sstevel@tonic-gate 
2681f48205beScasper 	if (cip->gid != (gid_t)-1) {
26827c478bd9Sstevel@tonic-gate 		if (setregid(cip->gid,
2683f48205beScasper 		    cip->egid != (gid_t)-1 ? cip->egid : cip->gid) != 0) {
26847c478bd9Sstevel@tonic-gate 			*fp = "setregid";
26857c478bd9Sstevel@tonic-gate 
26867c478bd9Sstevel@tonic-gate 			ret = errno;
26877c478bd9Sstevel@tonic-gate 			assert(ret == EINVAL || ret == EPERM);
26887c478bd9Sstevel@tonic-gate 			goto out;
26897c478bd9Sstevel@tonic-gate 		}
26907c478bd9Sstevel@tonic-gate 	} else {
26917c478bd9Sstevel@tonic-gate 		if (cip->pwbuf == NULL) {
26927c478bd9Sstevel@tonic-gate 			switch (ret = lookup_pwd(cip)) {
26937c478bd9Sstevel@tonic-gate 			case 0:
26947c478bd9Sstevel@tonic-gate 				break;
26957c478bd9Sstevel@tonic-gate 
26967c478bd9Sstevel@tonic-gate 			case ENOMEM:
26977c478bd9Sstevel@tonic-gate 			case ENOENT:
26987c478bd9Sstevel@tonic-gate 				*fp = NULL;
26997c478bd9Sstevel@tonic-gate 				goto out;
27007c478bd9Sstevel@tonic-gate 
27017c478bd9Sstevel@tonic-gate 			case EIO:
27027c478bd9Sstevel@tonic-gate 			case EMFILE:
27037c478bd9Sstevel@tonic-gate 			case ENFILE:
27047c478bd9Sstevel@tonic-gate 				*fp = "getpwuid_r";
27057c478bd9Sstevel@tonic-gate 				goto out;
27067c478bd9Sstevel@tonic-gate 
27077c478bd9Sstevel@tonic-gate 			default:
27087c478bd9Sstevel@tonic-gate 				bad_fail("lookup_pwd", ret);
27097c478bd9Sstevel@tonic-gate 			}
27107c478bd9Sstevel@tonic-gate 		}
27117c478bd9Sstevel@tonic-gate 
27127c478bd9Sstevel@tonic-gate 		if (setregid(cip->pwd.pw_gid,
2713f48205beScasper 		    cip->egid != (gid_t)-1 ?
2714f48205beScasper 		    cip->egid : cip->pwd.pw_gid) != 0) {
27157c478bd9Sstevel@tonic-gate 			*fp = "setregid";
27167c478bd9Sstevel@tonic-gate 
27177c478bd9Sstevel@tonic-gate 			ret = errno;
27187c478bd9Sstevel@tonic-gate 			assert(ret == EINVAL || ret == EPERM);
27197c478bd9Sstevel@tonic-gate 			goto out;
27207c478bd9Sstevel@tonic-gate 		}
27217c478bd9Sstevel@tonic-gate 	}
27227c478bd9Sstevel@tonic-gate 
27237c478bd9Sstevel@tonic-gate 	if (cip->ngroups == -1) {
27247c478bd9Sstevel@tonic-gate 		if (cip->pwbuf == NULL) {
27257c478bd9Sstevel@tonic-gate 			switch (ret = lookup_pwd(cip)) {
27267c478bd9Sstevel@tonic-gate 			case 0:
27277c478bd9Sstevel@tonic-gate 				break;
27287c478bd9Sstevel@tonic-gate 
27297c478bd9Sstevel@tonic-gate 			case ENOMEM:
27307c478bd9Sstevel@tonic-gate 			case ENOENT:
27317c478bd9Sstevel@tonic-gate 				*fp = NULL;
27327c478bd9Sstevel@tonic-gate 				goto out;
27337c478bd9Sstevel@tonic-gate 
27347c478bd9Sstevel@tonic-gate 			case EIO:
27357c478bd9Sstevel@tonic-gate 			case EMFILE:
27367c478bd9Sstevel@tonic-gate 			case ENFILE:
27377c478bd9Sstevel@tonic-gate 				*fp = "getpwuid_r";
27387c478bd9Sstevel@tonic-gate 				goto out;
27397c478bd9Sstevel@tonic-gate 
27407c478bd9Sstevel@tonic-gate 			default:
27417c478bd9Sstevel@tonic-gate 				bad_fail("lookup_pwd", ret);
27427c478bd9Sstevel@tonic-gate 			}
27437c478bd9Sstevel@tonic-gate 		}
27447c478bd9Sstevel@tonic-gate 
27457c478bd9Sstevel@tonic-gate 		/* Ok if cip->gid == -1 */
27467c478bd9Sstevel@tonic-gate 		if (initgroups(cip->pwd.pw_name, cip->gid) != 0) {
27477c478bd9Sstevel@tonic-gate 			*fp = "initgroups";
27487c478bd9Sstevel@tonic-gate 			ret = errno;
27497c478bd9Sstevel@tonic-gate 			assert(ret == EPERM);
27507c478bd9Sstevel@tonic-gate 			goto out;
27517c478bd9Sstevel@tonic-gate 		}
27527c478bd9Sstevel@tonic-gate 	} else if (cip->ngroups > 0 &&
27537c478bd9Sstevel@tonic-gate 	    setgroups(cip->ngroups, cip->groups) != 0) {
27547c478bd9Sstevel@tonic-gate 		*fp = "setgroups";
27557c478bd9Sstevel@tonic-gate 
27567c478bd9Sstevel@tonic-gate 		ret = errno;
27577c478bd9Sstevel@tonic-gate 		assert(ret == EINVAL || ret == EPERM);
27587c478bd9Sstevel@tonic-gate 		goto out;
27597c478bd9Sstevel@tonic-gate 	}
27607c478bd9Sstevel@tonic-gate 
27617c478bd9Sstevel@tonic-gate 	*fp = "setppriv";
27627c478bd9Sstevel@tonic-gate 
27637c478bd9Sstevel@tonic-gate 	if (cip->lpriv_set != NULL) {
27647c478bd9Sstevel@tonic-gate 		if (setppriv(PRIV_SET, PRIV_LIMIT, cip->lpriv_set) != 0) {
27657c478bd9Sstevel@tonic-gate 			ret = errno;
27667c478bd9Sstevel@tonic-gate 			assert(ret == EFAULT || ret == EPERM);
27677c478bd9Sstevel@tonic-gate 			goto out;
27687c478bd9Sstevel@tonic-gate 		}
27697c478bd9Sstevel@tonic-gate 	}
27707c478bd9Sstevel@tonic-gate 	if (cip->priv_set != NULL) {
27717c478bd9Sstevel@tonic-gate 		if (setppriv(PRIV_SET, PRIV_INHERITABLE, cip->priv_set) != 0) {
27727c478bd9Sstevel@tonic-gate 			ret = errno;
27737c478bd9Sstevel@tonic-gate 			assert(ret == EFAULT || ret == EPERM);
27747c478bd9Sstevel@tonic-gate 			goto out;
27757c478bd9Sstevel@tonic-gate 		}
27767c478bd9Sstevel@tonic-gate 	}
27777c478bd9Sstevel@tonic-gate 
27787c478bd9Sstevel@tonic-gate 	if (cip->corefile_pattern != NULL) {
27797c478bd9Sstevel@tonic-gate 		mypid = getpid();
27807c478bd9Sstevel@tonic-gate 
27817c478bd9Sstevel@tonic-gate 		if (core_set_process_path(cip->corefile_pattern,
27827c478bd9Sstevel@tonic-gate 		    strlen(cip->corefile_pattern) + 1, mypid) != 0) {
27837c478bd9Sstevel@tonic-gate 			*fp = "core_set_process_path";
27847c478bd9Sstevel@tonic-gate 			ret = -1;
27857c478bd9Sstevel@tonic-gate 			goto out;
27867c478bd9Sstevel@tonic-gate 		}
27877c478bd9Sstevel@tonic-gate 	}
27887c478bd9Sstevel@tonic-gate 
27897c478bd9Sstevel@tonic-gate 	if (restarter_rm_libs_loadable()) {
27907c478bd9Sstevel@tonic-gate 		if (cip->project == NULL) {
27917c478bd9Sstevel@tonic-gate 			if (settaskid(getprojid(), TASK_NORMAL) == -1) {
27927c478bd9Sstevel@tonic-gate 				switch (errno) {
27937c478bd9Sstevel@tonic-gate 				case EACCES:
27947c478bd9Sstevel@tonic-gate 				case EPERM:
27957c478bd9Sstevel@tonic-gate 					*fp = "settaskid";
27967c478bd9Sstevel@tonic-gate 					ret = errno;
27977c478bd9Sstevel@tonic-gate 					goto out;
27987c478bd9Sstevel@tonic-gate 
27997c478bd9Sstevel@tonic-gate 				case EINVAL:
28007c478bd9Sstevel@tonic-gate 				default:
28017c478bd9Sstevel@tonic-gate 					bad_fail("settaskid", errno);
28027c478bd9Sstevel@tonic-gate 				}
28037c478bd9Sstevel@tonic-gate 			}
28047c478bd9Sstevel@tonic-gate 		} else {
28057c478bd9Sstevel@tonic-gate 			switch (ret = lookup_pwd(cip)) {
28067c478bd9Sstevel@tonic-gate 			case 0:
28077c478bd9Sstevel@tonic-gate 				break;
28087c478bd9Sstevel@tonic-gate 
28097c478bd9Sstevel@tonic-gate 			case ENOMEM:
28107c478bd9Sstevel@tonic-gate 			case ENOENT:
28117c478bd9Sstevel@tonic-gate 				*fp = NULL;
28127c478bd9Sstevel@tonic-gate 				goto out;
28137c478bd9Sstevel@tonic-gate 
28147c478bd9Sstevel@tonic-gate 			case EIO:
28157c478bd9Sstevel@tonic-gate 			case EMFILE:
28167c478bd9Sstevel@tonic-gate 			case ENFILE:
28177c478bd9Sstevel@tonic-gate 				*fp = "getpwuid_r";
28187c478bd9Sstevel@tonic-gate 				goto out;
28197c478bd9Sstevel@tonic-gate 
28207c478bd9Sstevel@tonic-gate 			default:
28217c478bd9Sstevel@tonic-gate 				bad_fail("lookup_pwd", ret);
28227c478bd9Sstevel@tonic-gate 			}
28237c478bd9Sstevel@tonic-gate 
28247c478bd9Sstevel@tonic-gate 			*fp = "setproject";
28257c478bd9Sstevel@tonic-gate 
28267c478bd9Sstevel@tonic-gate 			switch (setproject(cip->project, cip->pwd.pw_name,
28277c478bd9Sstevel@tonic-gate 			    TASK_NORMAL)) {
28287c478bd9Sstevel@tonic-gate 			case 0:
28297c478bd9Sstevel@tonic-gate 				break;
28307c478bd9Sstevel@tonic-gate 
28317c478bd9Sstevel@tonic-gate 			case SETPROJ_ERR_TASK:
28327c478bd9Sstevel@tonic-gate 			case SETPROJ_ERR_POOL:
28337c478bd9Sstevel@tonic-gate 				ret = errno;
28347c478bd9Sstevel@tonic-gate 				goto out;
28357c478bd9Sstevel@tonic-gate 
28367c478bd9Sstevel@tonic-gate 			default:
28377c478bd9Sstevel@tonic-gate 				ret = -1;
28387c478bd9Sstevel@tonic-gate 				goto out;
28397c478bd9Sstevel@tonic-gate 			}
28407c478bd9Sstevel@tonic-gate 		}
28417c478bd9Sstevel@tonic-gate 
28427c478bd9Sstevel@tonic-gate 		if (cip->resource_pool != NULL) {
28437c478bd9Sstevel@tonic-gate 			if (mypid == -1)
28447c478bd9Sstevel@tonic-gate 				mypid = getpid();
28457c478bd9Sstevel@tonic-gate 
28467c478bd9Sstevel@tonic-gate 			*fp = "pool_set_binding";
28477c478bd9Sstevel@tonic-gate 
28487c478bd9Sstevel@tonic-gate 			if (pool_set_binding(cip->resource_pool, P_PID,
28497c478bd9Sstevel@tonic-gate 			    mypid) != PO_SUCCESS) {
28507c478bd9Sstevel@tonic-gate 				switch (pool_error()) {
28513ad28c1eSrm88369 				case POE_INVALID_SEARCH:
28527c478bd9Sstevel@tonic-gate 					ret = ENOENT;
28537c478bd9Sstevel@tonic-gate 					break;
28547c478bd9Sstevel@tonic-gate 
28553ad28c1eSrm88369 				case POE_BADPARAM:
28563ad28c1eSrm88369 					ret = EINVAL;
28573ad28c1eSrm88369 					break;
28583ad28c1eSrm88369 
28597c478bd9Sstevel@tonic-gate 				case POE_INVALID_CONF:
28607c478bd9Sstevel@tonic-gate 					ret = EBADF;
28617c478bd9Sstevel@tonic-gate 					break;
28627c478bd9Sstevel@tonic-gate 
28637c478bd9Sstevel@tonic-gate 				case POE_SYSTEM:
28647c478bd9Sstevel@tonic-gate 					ret = -1;
28657c478bd9Sstevel@tonic-gate 					break;
28667c478bd9Sstevel@tonic-gate 
28677c478bd9Sstevel@tonic-gate 				default:
28687c478bd9Sstevel@tonic-gate 					bad_fail("pool_set_binding",
28697c478bd9Sstevel@tonic-gate 					    pool_error());
28707c478bd9Sstevel@tonic-gate 				}
28717c478bd9Sstevel@tonic-gate 
28727c478bd9Sstevel@tonic-gate 				goto out;
28737c478bd9Sstevel@tonic-gate 			}
28747c478bd9Sstevel@tonic-gate 		}
28757c478bd9Sstevel@tonic-gate 	}
28767c478bd9Sstevel@tonic-gate 
28777c478bd9Sstevel@tonic-gate 	/*
28782a3221a4Svp157776 	 * Now, we have to assume our ID. If the UID is 0, we want it to be
28792a3221a4Svp157776 	 * privilege-aware, otherwise the limit set gets used instead of E/P.
28807c478bd9Sstevel@tonic-gate 	 * We can do this by setting P as well, which keeps
28817c478bd9Sstevel@tonic-gate 	 * PA status (see priv_can_clear_PA()).
28827c478bd9Sstevel@tonic-gate 	 */
28837c478bd9Sstevel@tonic-gate 
28847c478bd9Sstevel@tonic-gate 	*fp = "setreuid";
2885f48205beScasper 	if (setreuid(cip->uid,
2886f48205beScasper 	    cip->euid != (uid_t)-1 ? cip->euid : cip->uid) != 0) {
28877c478bd9Sstevel@tonic-gate 		ret = errno;
28887c478bd9Sstevel@tonic-gate 		assert(ret == EINVAL || ret == EPERM);
28897c478bd9Sstevel@tonic-gate 		goto out;
28907c478bd9Sstevel@tonic-gate 	}
28917c478bd9Sstevel@tonic-gate 
28927c478bd9Sstevel@tonic-gate 	*fp = "setppriv";
28937c478bd9Sstevel@tonic-gate 	if (cip->priv_set != NULL) {
28947c478bd9Sstevel@tonic-gate 		if (setppriv(PRIV_SET, PRIV_PERMITTED, cip->priv_set) != 0) {
28957c478bd9Sstevel@tonic-gate 			ret = errno;
28967c478bd9Sstevel@tonic-gate 			assert(ret == EFAULT || ret == EPERM);
28977c478bd9Sstevel@tonic-gate 			goto out;
28987c478bd9Sstevel@tonic-gate 		}
28997c478bd9Sstevel@tonic-gate 	}
29007c478bd9Sstevel@tonic-gate 
29012a3221a4Svp157776 	/*
29022a3221a4Svp157776 	 * The last thing to do is chdir to the specified working directory.
29032a3221a4Svp157776 	 * This should come after the uid switching as only the user might
29042a3221a4Svp157776 	 * have access to the specified directory.
29052a3221a4Svp157776 	 */
29062a3221a4Svp157776 	if (cip->working_dir != NULL) {
29073eae19d9Swesolows 		do {
29082a3221a4Svp157776 			r = chdir(cip->working_dir);
29093eae19d9Swesolows 		} while (r != 0 && errno == EINTR);
29102a3221a4Svp157776 		if (r != 0) {
29112a3221a4Svp157776 			*fp = "chdir";
29122a3221a4Svp157776 			ret = errno;
29132a3221a4Svp157776 			goto out;
29142a3221a4Svp157776 		}
29152a3221a4Svp157776 	}
29162a3221a4Svp157776 
29177c478bd9Sstevel@tonic-gate 	ret = 0;
29187c478bd9Sstevel@tonic-gate out:
29197c478bd9Sstevel@tonic-gate 	free(cip->pwbuf);
29207c478bd9Sstevel@tonic-gate 	cip->pwbuf = NULL;
29217c478bd9Sstevel@tonic-gate 	return (ret);
29227c478bd9Sstevel@tonic-gate }
29237c478bd9Sstevel@tonic-gate 
29247c478bd9Sstevel@tonic-gate void
29257c478bd9Sstevel@tonic-gate restarter_free_method_context(struct method_context *mcp)
29267c478bd9Sstevel@tonic-gate {
29277c478bd9Sstevel@tonic-gate 	size_t i;
29287c478bd9Sstevel@tonic-gate 
29297c478bd9Sstevel@tonic-gate 	if (mcp->lpriv_set != NULL)
29307c478bd9Sstevel@tonic-gate 		priv_freeset(mcp->lpriv_set);
29317c478bd9Sstevel@tonic-gate 	if (mcp->priv_set != NULL)
29327c478bd9Sstevel@tonic-gate 		priv_freeset(mcp->priv_set);
29337c478bd9Sstevel@tonic-gate 
29347c478bd9Sstevel@tonic-gate 	if (mcp->env != NULL) {
29357c478bd9Sstevel@tonic-gate 		for (i = 0; i < mcp->env_sz; i++)
29367c478bd9Sstevel@tonic-gate 			free(mcp->env[i]);
29377c478bd9Sstevel@tonic-gate 		free(mcp->env);
29387c478bd9Sstevel@tonic-gate 	}
29397c478bd9Sstevel@tonic-gate 
29407c478bd9Sstevel@tonic-gate 	free(mcp->working_dir);
29417c478bd9Sstevel@tonic-gate 	free(mcp->corefile_pattern);
29427c478bd9Sstevel@tonic-gate 	free(mcp->project);
29437c478bd9Sstevel@tonic-gate 	free(mcp->resource_pool);
29447c478bd9Sstevel@tonic-gate 	free(mcp);
29457c478bd9Sstevel@tonic-gate }
29467c478bd9Sstevel@tonic-gate 
29477c478bd9Sstevel@tonic-gate /*
29487c478bd9Sstevel@tonic-gate  * Method keyword functions
29497c478bd9Sstevel@tonic-gate  */
29507c478bd9Sstevel@tonic-gate 
29517c478bd9Sstevel@tonic-gate int
29527c478bd9Sstevel@tonic-gate restarter_is_null_method(const char *meth)
29537c478bd9Sstevel@tonic-gate {
29547c478bd9Sstevel@tonic-gate 	return (strcmp(meth, MKW_TRUE) == 0);
29557c478bd9Sstevel@tonic-gate }
29567c478bd9Sstevel@tonic-gate 
29577c478bd9Sstevel@tonic-gate static int
29587c478bd9Sstevel@tonic-gate is_kill_method(const char *method, const char *kill_str,
29597c478bd9Sstevel@tonic-gate     size_t kill_str_len)
29607c478bd9Sstevel@tonic-gate {
29617c478bd9Sstevel@tonic-gate 	const char *cp;
29627c478bd9Sstevel@tonic-gate 	int sig;
29637c478bd9Sstevel@tonic-gate 
29647c478bd9Sstevel@tonic-gate 	if (strncmp(method, kill_str, kill_str_len) != 0 ||
29657c478bd9Sstevel@tonic-gate 	    (method[kill_str_len] != '\0' &&
29667c478bd9Sstevel@tonic-gate 	    !isspace(method[kill_str_len])))
29677c478bd9Sstevel@tonic-gate 		return (-1);
29687c478bd9Sstevel@tonic-gate 
29697c478bd9Sstevel@tonic-gate 	cp = method + kill_str_len;
29707c478bd9Sstevel@tonic-gate 	while (*cp != '\0' && isspace(*cp))
29717c478bd9Sstevel@tonic-gate 		++cp;
29727c478bd9Sstevel@tonic-gate 
29737c478bd9Sstevel@tonic-gate 	if (*cp == '\0')
29747c478bd9Sstevel@tonic-gate 		return (SIGTERM);
29757c478bd9Sstevel@tonic-gate 
29767c478bd9Sstevel@tonic-gate 	if (*cp != '-')
29777c478bd9Sstevel@tonic-gate 		return (-1);
29787c478bd9Sstevel@tonic-gate 
29797c478bd9Sstevel@tonic-gate 	return (str2sig(cp + 1, &sig) == 0 ? sig : -1);
29807c478bd9Sstevel@tonic-gate }
29817c478bd9Sstevel@tonic-gate 
29827c478bd9Sstevel@tonic-gate int
29837c478bd9Sstevel@tonic-gate restarter_is_kill_proc_method(const char *method)
29847c478bd9Sstevel@tonic-gate {
29857c478bd9Sstevel@tonic-gate 	return (is_kill_method(method, MKW_KILL_PROC,
29867c478bd9Sstevel@tonic-gate 	    sizeof (MKW_KILL_PROC) - 1));
29877c478bd9Sstevel@tonic-gate }
29887c478bd9Sstevel@tonic-gate 
29897c478bd9Sstevel@tonic-gate int
29907c478bd9Sstevel@tonic-gate restarter_is_kill_method(const char *method)
29917c478bd9Sstevel@tonic-gate {
29927c478bd9Sstevel@tonic-gate 	return (is_kill_method(method, MKW_KILL, sizeof (MKW_KILL) - 1));
29937c478bd9Sstevel@tonic-gate }
29947c478bd9Sstevel@tonic-gate 
29957c478bd9Sstevel@tonic-gate /*
29967c478bd9Sstevel@tonic-gate  * Stubs for now.
29977c478bd9Sstevel@tonic-gate  */
29987c478bd9Sstevel@tonic-gate 
29997c478bd9Sstevel@tonic-gate /* ARGSUSED */
30007c478bd9Sstevel@tonic-gate int
30017c478bd9Sstevel@tonic-gate restarter_event_get_enabled(restarter_event_t *e)
30027c478bd9Sstevel@tonic-gate {
30037c478bd9Sstevel@tonic-gate 	return (-1);
30047c478bd9Sstevel@tonic-gate }
30057c478bd9Sstevel@tonic-gate 
30067c478bd9Sstevel@tonic-gate /* ARGSUSED */
30077c478bd9Sstevel@tonic-gate uint64_t
30087c478bd9Sstevel@tonic-gate restarter_event_get_seq(restarter_event_t *e)
30097c478bd9Sstevel@tonic-gate {
30107c478bd9Sstevel@tonic-gate 	return (-1);
30117c478bd9Sstevel@tonic-gate }
30127c478bd9Sstevel@tonic-gate 
30137c478bd9Sstevel@tonic-gate /* ARGSUSED */
30147c478bd9Sstevel@tonic-gate void
30157c478bd9Sstevel@tonic-gate restarter_event_get_time(restarter_event_t *e, hrtime_t *time)
30167c478bd9Sstevel@tonic-gate {
30177c478bd9Sstevel@tonic-gate }
3018*eb1a3463STruong Nguyen 
3019*eb1a3463STruong Nguyen /*
3020*eb1a3463STruong Nguyen  * Check for and validate fmri specified in restarter_actions/auxiliary_fmri
3021*eb1a3463STruong Nguyen  * 0 - Success
3022*eb1a3463STruong Nguyen  * 1 - Failure
3023*eb1a3463STruong Nguyen  */
3024*eb1a3463STruong Nguyen int
3025*eb1a3463STruong Nguyen restarter_inst_validate_ractions_aux_fmri(scf_instance_t *inst)
3026*eb1a3463STruong Nguyen {
3027*eb1a3463STruong Nguyen 	scf_handle_t *h;
3028*eb1a3463STruong Nguyen 	scf_propertygroup_t *pg;
3029*eb1a3463STruong Nguyen 	scf_property_t *prop;
3030*eb1a3463STruong Nguyen 	scf_value_t *val;
3031*eb1a3463STruong Nguyen 	char *aux_fmri;
3032*eb1a3463STruong Nguyen 	size_t size = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
3033*eb1a3463STruong Nguyen 	int ret = 1;
3034*eb1a3463STruong Nguyen 
3035*eb1a3463STruong Nguyen 	if ((aux_fmri = malloc(size)) == NULL)
3036*eb1a3463STruong Nguyen 		return (1);
3037*eb1a3463STruong Nguyen 
3038*eb1a3463STruong Nguyen 	h = scf_instance_handle(inst);
3039*eb1a3463STruong Nguyen 
3040*eb1a3463STruong Nguyen 	pg = scf_pg_create(h);
3041*eb1a3463STruong Nguyen 	prop = scf_property_create(h);
3042*eb1a3463STruong Nguyen 	val = scf_value_create(h);
3043*eb1a3463STruong Nguyen 	if (pg == NULL || prop == NULL || val == NULL)
3044*eb1a3463STruong Nguyen 		goto out;
3045*eb1a3463STruong Nguyen 
3046*eb1a3463STruong Nguyen 	if (instance_get_or_add_pg(inst, SCF_PG_RESTARTER_ACTIONS,
3047*eb1a3463STruong Nguyen 	    SCF_PG_RESTARTER_ACTIONS_TYPE, SCF_PG_RESTARTER_ACTIONS_FLAGS,
3048*eb1a3463STruong Nguyen 	    pg) != SCF_SUCCESS)
3049*eb1a3463STruong Nguyen 		goto out;
3050*eb1a3463STruong Nguyen 
3051*eb1a3463STruong Nguyen 	if (get_astring_val(pg, SCF_PROPERTY_AUX_FMRI, aux_fmri, size,
3052*eb1a3463STruong Nguyen 	    prop, val) != SCF_SUCCESS)
3053*eb1a3463STruong Nguyen 		goto out;
3054*eb1a3463STruong Nguyen 
3055*eb1a3463STruong Nguyen 	if (scf_parse_fmri(aux_fmri, NULL, NULL, NULL, NULL, NULL,
3056*eb1a3463STruong Nguyen 	    NULL) != SCF_SUCCESS)
3057*eb1a3463STruong Nguyen 		goto out;
3058*eb1a3463STruong Nguyen 
3059*eb1a3463STruong Nguyen 	ret = 0;
3060*eb1a3463STruong Nguyen 
3061*eb1a3463STruong Nguyen out:
3062*eb1a3463STruong Nguyen 	free(aux_fmri);
3063*eb1a3463STruong Nguyen 	scf_value_destroy(val);
3064*eb1a3463STruong Nguyen 	scf_property_destroy(prop);
3065*eb1a3463STruong Nguyen 	scf_pg_destroy(pg);
3066*eb1a3463STruong Nguyen 	return (ret);
3067*eb1a3463STruong Nguyen }
3068*eb1a3463STruong Nguyen 
3069*eb1a3463STruong Nguyen /*
3070*eb1a3463STruong Nguyen  * Get instance's boolean value in restarter_actions/auxiliary_tty
3071*eb1a3463STruong Nguyen  * Return -1 on failure
3072*eb1a3463STruong Nguyen  */
3073*eb1a3463STruong Nguyen int
3074*eb1a3463STruong Nguyen restarter_inst_ractions_from_tty(scf_instance_t *inst)
3075*eb1a3463STruong Nguyen {
3076*eb1a3463STruong Nguyen 	scf_handle_t *h;
3077*eb1a3463STruong Nguyen 	scf_propertygroup_t *pg;
3078*eb1a3463STruong Nguyen 	scf_property_t *prop;
3079*eb1a3463STruong Nguyen 	scf_value_t *val;
3080*eb1a3463STruong Nguyen 	uint8_t	has_tty;
3081*eb1a3463STruong Nguyen 	int ret = -1;
3082*eb1a3463STruong Nguyen 
3083*eb1a3463STruong Nguyen 	h = scf_instance_handle(inst);
3084*eb1a3463STruong Nguyen 	pg = scf_pg_create(h);
3085*eb1a3463STruong Nguyen 	prop = scf_property_create(h);
3086*eb1a3463STruong Nguyen 	val = scf_value_create(h);
3087*eb1a3463STruong Nguyen 	if (pg == NULL || prop == NULL || val == NULL)
3088*eb1a3463STruong Nguyen 		goto out;
3089*eb1a3463STruong Nguyen 
3090*eb1a3463STruong Nguyen 	if (instance_get_or_add_pg(inst, SCF_PG_RESTARTER_ACTIONS,
3091*eb1a3463STruong Nguyen 	    SCF_PG_RESTARTER_ACTIONS_TYPE, SCF_PG_RESTARTER_ACTIONS_FLAGS,
3092*eb1a3463STruong Nguyen 	    pg) != SCF_SUCCESS)
3093*eb1a3463STruong Nguyen 		goto out;
3094*eb1a3463STruong Nguyen 
3095*eb1a3463STruong Nguyen 	if (get_boolean_val(pg, SCF_PROPERTY_AUX_TTY, &has_tty, prop,
3096*eb1a3463STruong Nguyen 	    val) != SCF_SUCCESS)
3097*eb1a3463STruong Nguyen 		goto out;
3098*eb1a3463STruong Nguyen 
3099*eb1a3463STruong Nguyen 	ret = has_tty;
3100*eb1a3463STruong Nguyen 
3101*eb1a3463STruong Nguyen out:
3102*eb1a3463STruong Nguyen 	scf_value_destroy(val);
3103*eb1a3463STruong Nguyen 	scf_property_destroy(prop);
3104*eb1a3463STruong Nguyen 	scf_pg_destroy(pg);
3105*eb1a3463STruong Nguyen 	return (ret);
3106*eb1a3463STruong Nguyen }
3107*eb1a3463STruong Nguyen 
3108*eb1a3463STruong Nguyen static int
3109*eb1a3463STruong Nguyen restarter_inst_set_astring_prop(scf_instance_t *inst, const char *pgname,
3110*eb1a3463STruong Nguyen     const char *pgtype, uint32_t pgflags, const char *pname, const char *str)
3111*eb1a3463STruong Nguyen {
3112*eb1a3463STruong Nguyen 	scf_handle_t *h;
3113*eb1a3463STruong Nguyen 	scf_propertygroup_t *pg;
3114*eb1a3463STruong Nguyen 	scf_transaction_t *t;
3115*eb1a3463STruong Nguyen 	scf_transaction_entry_t *e;
3116*eb1a3463STruong Nguyen 	scf_value_t *v;
3117*eb1a3463STruong Nguyen 	int ret = 1, r;
3118*eb1a3463STruong Nguyen 
3119*eb1a3463STruong Nguyen 	h = scf_instance_handle(inst);
3120*eb1a3463STruong Nguyen 
3121*eb1a3463STruong Nguyen 	pg = scf_pg_create(h);
3122*eb1a3463STruong Nguyen 	t = scf_transaction_create(h);
3123*eb1a3463STruong Nguyen 	e = scf_entry_create(h);
3124*eb1a3463STruong Nguyen 	v = scf_value_create(h);
3125*eb1a3463STruong Nguyen 	if (pg == NULL || t == NULL || e == NULL || v == NULL)
3126*eb1a3463STruong Nguyen 		goto out;
3127*eb1a3463STruong Nguyen 
3128*eb1a3463STruong Nguyen 	if (instance_get_or_add_pg(inst, pgname, pgtype, pgflags, pg))
3129*eb1a3463STruong Nguyen 		goto out;
3130*eb1a3463STruong Nguyen 
3131*eb1a3463STruong Nguyen 	if (scf_value_set_astring(v, str) != SCF_SUCCESS)
3132*eb1a3463STruong Nguyen 		goto out;
3133*eb1a3463STruong Nguyen 
3134*eb1a3463STruong Nguyen 	for (;;) {
3135*eb1a3463STruong Nguyen 		if (scf_transaction_start(t, pg) != 0)
3136*eb1a3463STruong Nguyen 			goto out;
3137*eb1a3463STruong Nguyen 
3138*eb1a3463STruong Nguyen 		if (tx_set_value(t, e, pname, SCF_TYPE_ASTRING, v) != 0)
3139*eb1a3463STruong Nguyen 			goto out;
3140*eb1a3463STruong Nguyen 
3141*eb1a3463STruong Nguyen 		if ((r = scf_transaction_commit(t)) == 1)
3142*eb1a3463STruong Nguyen 			break;
3143*eb1a3463STruong Nguyen 
3144*eb1a3463STruong Nguyen 		if (r == -1)
3145*eb1a3463STruong Nguyen 			goto out;
3146*eb1a3463STruong Nguyen 
3147*eb1a3463STruong Nguyen 		scf_transaction_reset(t);
3148*eb1a3463STruong Nguyen 		if (scf_pg_update(pg) == -1)
3149*eb1a3463STruong Nguyen 			goto out;
3150*eb1a3463STruong Nguyen 	}
3151*eb1a3463STruong Nguyen 	ret = 0;
3152*eb1a3463STruong Nguyen 
3153*eb1a3463STruong Nguyen out:
3154*eb1a3463STruong Nguyen 	scf_transaction_destroy(t);
3155*eb1a3463STruong Nguyen 	scf_entry_destroy(e);
3156*eb1a3463STruong Nguyen 	scf_value_destroy(v);
3157*eb1a3463STruong Nguyen 	scf_pg_destroy(pg);
3158*eb1a3463STruong Nguyen 
3159*eb1a3463STruong Nguyen 	return (ret);
3160*eb1a3463STruong Nguyen }
3161*eb1a3463STruong Nguyen 
3162*eb1a3463STruong Nguyen int
3163*eb1a3463STruong Nguyen restarter_inst_set_aux_fmri(scf_instance_t *inst)
3164*eb1a3463STruong Nguyen {
3165*eb1a3463STruong Nguyen 	scf_handle_t *h;
3166*eb1a3463STruong Nguyen 	scf_propertygroup_t *pg;
3167*eb1a3463STruong Nguyen 	scf_property_t *prop;
3168*eb1a3463STruong Nguyen 	scf_value_t *val;
3169*eb1a3463STruong Nguyen 	char *aux_fmri;
3170*eb1a3463STruong Nguyen 	size_t size = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
3171*eb1a3463STruong Nguyen 	int ret = 1;
3172*eb1a3463STruong Nguyen 
3173*eb1a3463STruong Nguyen 	if ((aux_fmri = malloc(size)) == NULL)
3174*eb1a3463STruong Nguyen 		return (1);
3175*eb1a3463STruong Nguyen 
3176*eb1a3463STruong Nguyen 	h = scf_instance_handle(inst);
3177*eb1a3463STruong Nguyen 
3178*eb1a3463STruong Nguyen 	pg = scf_pg_create(h);
3179*eb1a3463STruong Nguyen 	prop = scf_property_create(h);
3180*eb1a3463STruong Nguyen 	val = scf_value_create(h);
3181*eb1a3463STruong Nguyen 	if (pg == NULL || prop == NULL || val == NULL)
3182*eb1a3463STruong Nguyen 		goto out;
3183*eb1a3463STruong Nguyen 
3184*eb1a3463STruong Nguyen 	/*
3185*eb1a3463STruong Nguyen 	 * Get auxiliary_fmri value from restarter_actions pg
3186*eb1a3463STruong Nguyen 	 */
3187*eb1a3463STruong Nguyen 	if (instance_get_or_add_pg(inst, SCF_PG_RESTARTER_ACTIONS,
3188*eb1a3463STruong Nguyen 	    SCF_PG_RESTARTER_ACTIONS_TYPE, SCF_PG_RESTARTER_ACTIONS_FLAGS,
3189*eb1a3463STruong Nguyen 	    pg) != SCF_SUCCESS)
3190*eb1a3463STruong Nguyen 		goto out;
3191*eb1a3463STruong Nguyen 
3192*eb1a3463STruong Nguyen 	if (get_astring_val(pg, SCF_PROPERTY_AUX_FMRI, aux_fmri, size,
3193*eb1a3463STruong Nguyen 	    prop, val) != SCF_SUCCESS)
3194*eb1a3463STruong Nguyen 		goto out;
3195*eb1a3463STruong Nguyen 
3196*eb1a3463STruong Nguyen 	/*
3197*eb1a3463STruong Nguyen 	 * Populate restarter/auxiliary_fmri with the obtained fmri.
3198*eb1a3463STruong Nguyen 	 */
3199*eb1a3463STruong Nguyen 	ret = restarter_inst_set_astring_prop(inst, SCF_PG_RESTARTER,
3200*eb1a3463STruong Nguyen 	    SCF_PG_RESTARTER_TYPE, SCF_PG_RESTARTER_FLAGS,
3201*eb1a3463STruong Nguyen 	    SCF_PROPERTY_AUX_FMRI, aux_fmri);
3202*eb1a3463STruong Nguyen 
3203*eb1a3463STruong Nguyen out:
3204*eb1a3463STruong Nguyen 	free(aux_fmri);
3205*eb1a3463STruong Nguyen 	scf_value_destroy(val);
3206*eb1a3463STruong Nguyen 	scf_property_destroy(prop);
3207*eb1a3463STruong Nguyen 	scf_pg_destroy(pg);
3208*eb1a3463STruong Nguyen 	return (ret);
3209*eb1a3463STruong Nguyen }
3210*eb1a3463STruong Nguyen 
3211*eb1a3463STruong Nguyen int
3212*eb1a3463STruong Nguyen restarter_inst_reset_aux_fmri(scf_instance_t *inst)
3213*eb1a3463STruong Nguyen {
3214*eb1a3463STruong Nguyen 	return (scf_instance_delete_prop(inst,
3215*eb1a3463STruong Nguyen 	    SCF_PG_RESTARTER, SCF_PROPERTY_AUX_FMRI));
3216*eb1a3463STruong Nguyen }
3217*eb1a3463STruong Nguyen 
3218*eb1a3463STruong Nguyen int
3219*eb1a3463STruong Nguyen restarter_inst_reset_ractions_aux_fmri(scf_instance_t *inst)
3220*eb1a3463STruong Nguyen {
3221*eb1a3463STruong Nguyen 	return (scf_instance_delete_prop(inst,
3222*eb1a3463STruong Nguyen 	    SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_AUX_FMRI));
3223*eb1a3463STruong Nguyen }
3224