xref: /titanic_50/usr/src/lib/librestart/common/librestart.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include <librestart.h>
30*7c478bd9Sstevel@tonic-gate #include <librestart_priv.h>
31*7c478bd9Sstevel@tonic-gate #include <libscf.h>
32*7c478bd9Sstevel@tonic-gate #include <libscf_priv.h>
33*7c478bd9Sstevel@tonic-gate 
34*7c478bd9Sstevel@tonic-gate #include <assert.h>
35*7c478bd9Sstevel@tonic-gate #include <ctype.h>
36*7c478bd9Sstevel@tonic-gate #include <dlfcn.h>
37*7c478bd9Sstevel@tonic-gate #include <errno.h>
38*7c478bd9Sstevel@tonic-gate #include <exec_attr.h>
39*7c478bd9Sstevel@tonic-gate #include <grp.h>
40*7c478bd9Sstevel@tonic-gate #include <libsysevent.h>
41*7c478bd9Sstevel@tonic-gate #include <libuutil.h>
42*7c478bd9Sstevel@tonic-gate #include <limits.h>
43*7c478bd9Sstevel@tonic-gate #include <link.h>
44*7c478bd9Sstevel@tonic-gate #include <malloc.h>
45*7c478bd9Sstevel@tonic-gate #include <pool.h>
46*7c478bd9Sstevel@tonic-gate #include <priv.h>
47*7c478bd9Sstevel@tonic-gate #include <project.h>
48*7c478bd9Sstevel@tonic-gate #include <pthread.h>
49*7c478bd9Sstevel@tonic-gate #include <pwd.h>
50*7c478bd9Sstevel@tonic-gate #include <secdb.h>
51*7c478bd9Sstevel@tonic-gate #include <signal.h>
52*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
53*7c478bd9Sstevel@tonic-gate #include <string.h>
54*7c478bd9Sstevel@tonic-gate #include <syslog.h>
55*7c478bd9Sstevel@tonic-gate #include <sys/corectl.h>
56*7c478bd9Sstevel@tonic-gate #include <sys/machelf.h>
57*7c478bd9Sstevel@tonic-gate #include <sys/task.h>
58*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
59*7c478bd9Sstevel@tonic-gate #include <time.h>
60*7c478bd9Sstevel@tonic-gate #include <unistd.h>
61*7c478bd9Sstevel@tonic-gate 
62*7c478bd9Sstevel@tonic-gate #define	walkcontext	_walkcontext
63*7c478bd9Sstevel@tonic-gate #include <ucontext.h>
64*7c478bd9Sstevel@tonic-gate 
65*7c478bd9Sstevel@tonic-gate #define	min(a, b)		((a) > (b) ? (b) : (a))
66*7c478bd9Sstevel@tonic-gate 
67*7c478bd9Sstevel@tonic-gate #define	MKW_TRUE	":true"
68*7c478bd9Sstevel@tonic-gate #define	MKW_KILL	":kill"
69*7c478bd9Sstevel@tonic-gate #define	MKW_KILL_PROC	":kill_process"
70*7c478bd9Sstevel@tonic-gate 
71*7c478bd9Sstevel@tonic-gate #define	ALLOCFAIL	((char *)"Allocation failure.")
72*7c478bd9Sstevel@tonic-gate #define	RCBROKEN	((char *)"Repository connection broken.")
73*7c478bd9Sstevel@tonic-gate 
74*7c478bd9Sstevel@tonic-gate #define	MAX_COMMIT_RETRIES		20
75*7c478bd9Sstevel@tonic-gate #define	MAX_COMMIT_RETRY_INT		(5 * 1000000)	/* 5 seconds */
76*7c478bd9Sstevel@tonic-gate #define	INITIAL_COMMIT_RETRY_INT	(10000)		/* 1/100th second */
77*7c478bd9Sstevel@tonic-gate 
78*7c478bd9Sstevel@tonic-gate /*
79*7c478bd9Sstevel@tonic-gate  * bad_fail() catches bugs in this and lower layers by reporting supposedly
80*7c478bd9Sstevel@tonic-gate  * impossible function failures.  The NDEBUG case keeps the strings out of the
81*7c478bd9Sstevel@tonic-gate  * library but still calls abort() so we can root-cause from the coredump.
82*7c478bd9Sstevel@tonic-gate  */
83*7c478bd9Sstevel@tonic-gate #ifndef NDEBUG
84*7c478bd9Sstevel@tonic-gate #define	bad_fail(func, err)	{					\
85*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,						\
86*7c478bd9Sstevel@tonic-gate 	    "At %s:%d, %s() failed with unexpected error %d.  Aborting.\n", \
87*7c478bd9Sstevel@tonic-gate 	    __FILE__, __LINE__, (func), (err));				\
88*7c478bd9Sstevel@tonic-gate 	abort();							\
89*7c478bd9Sstevel@tonic-gate }
90*7c478bd9Sstevel@tonic-gate #else
91*7c478bd9Sstevel@tonic-gate #define	bad_fail(func, err)	abort()
92*7c478bd9Sstevel@tonic-gate #endif
93*7c478bd9Sstevel@tonic-gate 
94*7c478bd9Sstevel@tonic-gate struct restarter_event_handle {
95*7c478bd9Sstevel@tonic-gate 	char				*reh_restarter_name;
96*7c478bd9Sstevel@tonic-gate 	char				*reh_delegate_channel_name;
97*7c478bd9Sstevel@tonic-gate 	evchan_t			*reh_delegate_channel;
98*7c478bd9Sstevel@tonic-gate 	char				*reh_delegate_subscriber_id;
99*7c478bd9Sstevel@tonic-gate 	char				*reh_master_channel_name;
100*7c478bd9Sstevel@tonic-gate 	evchan_t			*reh_master_channel;
101*7c478bd9Sstevel@tonic-gate 	char				*reh_master_subscriber_id;
102*7c478bd9Sstevel@tonic-gate 	int				(*reh_handler)(restarter_event_t *);
103*7c478bd9Sstevel@tonic-gate };
104*7c478bd9Sstevel@tonic-gate 
105*7c478bd9Sstevel@tonic-gate struct restarter_event {
106*7c478bd9Sstevel@tonic-gate 	sysevent_t			*re_sysevent;
107*7c478bd9Sstevel@tonic-gate 	restarter_event_type_t		re_type;
108*7c478bd9Sstevel@tonic-gate 	char				*re_instance_name;
109*7c478bd9Sstevel@tonic-gate 	restarter_event_handle_t	*re_event_handle;
110*7c478bd9Sstevel@tonic-gate 	restarter_instance_state_t	re_state;
111*7c478bd9Sstevel@tonic-gate 	restarter_instance_state_t	re_next_state;
112*7c478bd9Sstevel@tonic-gate };
113*7c478bd9Sstevel@tonic-gate 
114*7c478bd9Sstevel@tonic-gate static const char * const allocfail = "Allocation failure.\n";
115*7c478bd9Sstevel@tonic-gate static const char * const rcbroken = "Repository connection broken.\n";
116*7c478bd9Sstevel@tonic-gate 
117*7c478bd9Sstevel@tonic-gate static int method_context_safety = 0;	/* Can safely call pools/projects. */
118*7c478bd9Sstevel@tonic-gate 
119*7c478bd9Sstevel@tonic-gate int ndebug = 1;
120*7c478bd9Sstevel@tonic-gate 
121*7c478bd9Sstevel@tonic-gate static void
122*7c478bd9Sstevel@tonic-gate free_restarter_event_handle(struct restarter_event_handle *h)
123*7c478bd9Sstevel@tonic-gate {
124*7c478bd9Sstevel@tonic-gate 	if (h == NULL)
125*7c478bd9Sstevel@tonic-gate 		return;
126*7c478bd9Sstevel@tonic-gate 
127*7c478bd9Sstevel@tonic-gate 	/*
128*7c478bd9Sstevel@tonic-gate 	 * Just free the memory -- don't unbind the sysevent handle,
129*7c478bd9Sstevel@tonic-gate 	 * as otherwise events may be lost if this is just a restarter
130*7c478bd9Sstevel@tonic-gate 	 * restart.
131*7c478bd9Sstevel@tonic-gate 	 */
132*7c478bd9Sstevel@tonic-gate 
133*7c478bd9Sstevel@tonic-gate 	if (h->reh_restarter_name != NULL)
134*7c478bd9Sstevel@tonic-gate 		free(h->reh_restarter_name);
135*7c478bd9Sstevel@tonic-gate 	if (h->reh_delegate_channel_name != NULL)
136*7c478bd9Sstevel@tonic-gate 		free(h->reh_delegate_channel_name);
137*7c478bd9Sstevel@tonic-gate 	if (h->reh_delegate_subscriber_id != NULL)
138*7c478bd9Sstevel@tonic-gate 		free(h->reh_delegate_subscriber_id);
139*7c478bd9Sstevel@tonic-gate 	if (h->reh_master_channel_name != NULL)
140*7c478bd9Sstevel@tonic-gate 		free(h->reh_master_channel_name);
141*7c478bd9Sstevel@tonic-gate 	if (h->reh_master_subscriber_id != NULL)
142*7c478bd9Sstevel@tonic-gate 		free(h->reh_master_subscriber_id);
143*7c478bd9Sstevel@tonic-gate 
144*7c478bd9Sstevel@tonic-gate 	free(h);
145*7c478bd9Sstevel@tonic-gate }
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate static const char *
148*7c478bd9Sstevel@tonic-gate last_part(const char *fmri)
149*7c478bd9Sstevel@tonic-gate {
150*7c478bd9Sstevel@tonic-gate 	char *last_part;
151*7c478bd9Sstevel@tonic-gate 
152*7c478bd9Sstevel@tonic-gate 	last_part = strrchr(fmri, '/');
153*7c478bd9Sstevel@tonic-gate 	last_part++;
154*7c478bd9Sstevel@tonic-gate 	assert(last_part != NULL);
155*7c478bd9Sstevel@tonic-gate 
156*7c478bd9Sstevel@tonic-gate 	return (last_part);
157*7c478bd9Sstevel@tonic-gate }
158*7c478bd9Sstevel@tonic-gate 
159*7c478bd9Sstevel@tonic-gate char *
160*7c478bd9Sstevel@tonic-gate _restarter_get_channel_name(const char *fmri, int type)
161*7c478bd9Sstevel@tonic-gate {
162*7c478bd9Sstevel@tonic-gate 	const char *name;
163*7c478bd9Sstevel@tonic-gate 	char *chan_name = malloc(MAX_CHNAME_LEN);
164*7c478bd9Sstevel@tonic-gate 	char prefix_name[3];
165*7c478bd9Sstevel@tonic-gate 
166*7c478bd9Sstevel@tonic-gate 	if (chan_name == NULL)
167*7c478bd9Sstevel@tonic-gate 		return (NULL);
168*7c478bd9Sstevel@tonic-gate 
169*7c478bd9Sstevel@tonic-gate 	if (type == RESTARTER_CHANNEL_DELEGATE)
170*7c478bd9Sstevel@tonic-gate 		(void) strcpy(prefix_name, "d_");
171*7c478bd9Sstevel@tonic-gate 	else if (type == RESTARTER_CHANNEL_MASTER)
172*7c478bd9Sstevel@tonic-gate 		(void) strcpy(prefix_name, "m_");
173*7c478bd9Sstevel@tonic-gate 	else {
174*7c478bd9Sstevel@tonic-gate 		free(chan_name);
175*7c478bd9Sstevel@tonic-gate 		return (NULL);
176*7c478bd9Sstevel@tonic-gate 	}
177*7c478bd9Sstevel@tonic-gate 
178*7c478bd9Sstevel@tonic-gate 	name = last_part(fmri);
179*7c478bd9Sstevel@tonic-gate 
180*7c478bd9Sstevel@tonic-gate 	/*
181*7c478bd9Sstevel@tonic-gate 	 * Should check for [a-z],[A-Z],[0-9],.,_,-,:
182*7c478bd9Sstevel@tonic-gate 	 */
183*7c478bd9Sstevel@tonic-gate 
184*7c478bd9Sstevel@tonic-gate 	if (snprintf(chan_name, MAX_CHNAME_LEN, "com.sun:scf:%s%s",
185*7c478bd9Sstevel@tonic-gate 	    prefix_name, name) > MAX_CHNAME_LEN) {
186*7c478bd9Sstevel@tonic-gate 		free(chan_name);
187*7c478bd9Sstevel@tonic-gate 		return (NULL);
188*7c478bd9Sstevel@tonic-gate 	}
189*7c478bd9Sstevel@tonic-gate 
190*7c478bd9Sstevel@tonic-gate 	return (chan_name);
191*7c478bd9Sstevel@tonic-gate }
192*7c478bd9Sstevel@tonic-gate 
193*7c478bd9Sstevel@tonic-gate int
194*7c478bd9Sstevel@tonic-gate cb(sysevent_t *syse, void *cookie)
195*7c478bd9Sstevel@tonic-gate {
196*7c478bd9Sstevel@tonic-gate 	restarter_event_handle_t *h = (restarter_event_handle_t *)cookie;
197*7c478bd9Sstevel@tonic-gate 	restarter_event_t *e;
198*7c478bd9Sstevel@tonic-gate 	nvlist_t *attr_list = NULL;
199*7c478bd9Sstevel@tonic-gate 	int ret = 0;
200*7c478bd9Sstevel@tonic-gate 
201*7c478bd9Sstevel@tonic-gate 	e = uu_zalloc(sizeof (restarter_event_t));
202*7c478bd9Sstevel@tonic-gate 	if (e == NULL)
203*7c478bd9Sstevel@tonic-gate 		uu_die(allocfail);
204*7c478bd9Sstevel@tonic-gate 	e->re_event_handle = h;
205*7c478bd9Sstevel@tonic-gate 	e->re_sysevent = syse;
206*7c478bd9Sstevel@tonic-gate 
207*7c478bd9Sstevel@tonic-gate 	if (sysevent_get_attr_list(syse, &attr_list) != 0)
208*7c478bd9Sstevel@tonic-gate 		uu_die(allocfail);
209*7c478bd9Sstevel@tonic-gate 
210*7c478bd9Sstevel@tonic-gate 	if ((nvlist_lookup_uint32(attr_list, RESTARTER_NAME_TYPE,
211*7c478bd9Sstevel@tonic-gate 	    &(e->re_type)) != 0) ||
212*7c478bd9Sstevel@tonic-gate 	    (nvlist_lookup_string(attr_list,
213*7c478bd9Sstevel@tonic-gate 	    RESTARTER_NAME_INSTANCE, &(e->re_instance_name)) != 0)) {
214*7c478bd9Sstevel@tonic-gate 		uu_warn("%s: Can't decode nvlist for event %p\n",
215*7c478bd9Sstevel@tonic-gate 		    h->reh_restarter_name, (void *)syse);
216*7c478bd9Sstevel@tonic-gate 
217*7c478bd9Sstevel@tonic-gate 		ret = 0;
218*7c478bd9Sstevel@tonic-gate 	} else {
219*7c478bd9Sstevel@tonic-gate 		ret = h->reh_handler(e);
220*7c478bd9Sstevel@tonic-gate 	}
221*7c478bd9Sstevel@tonic-gate 
222*7c478bd9Sstevel@tonic-gate 	uu_free(e);
223*7c478bd9Sstevel@tonic-gate 	nvlist_free(attr_list);
224*7c478bd9Sstevel@tonic-gate 	return (ret);
225*7c478bd9Sstevel@tonic-gate }
226*7c478bd9Sstevel@tonic-gate 
227*7c478bd9Sstevel@tonic-gate /*
228*7c478bd9Sstevel@tonic-gate  * restarter_bind_handle(uint32_t, char *, int (*)(restarter_event_t *), int,
229*7c478bd9Sstevel@tonic-gate  *     restarter_event_handle_t **)
230*7c478bd9Sstevel@tonic-gate  *
231*7c478bd9Sstevel@tonic-gate  * Bind to a delegated restarter event channel.
232*7c478bd9Sstevel@tonic-gate  * Each delegated restarter gets its own channel for resource management.
233*7c478bd9Sstevel@tonic-gate  *
234*7c478bd9Sstevel@tonic-gate  * Returns 0 on success or
235*7c478bd9Sstevel@tonic-gate  *   ENOTSUP	version mismatch
236*7c478bd9Sstevel@tonic-gate  *   EINVAL	restarter_name or event_handle is NULL
237*7c478bd9Sstevel@tonic-gate  *   ENOMEM	out of memory, too many channels, or too many subscriptions
238*7c478bd9Sstevel@tonic-gate  *   EBUSY	sysevent_evc_bind() could not establish binding
239*7c478bd9Sstevel@tonic-gate  *   EFAULT	internal sysevent_evc_bind()/sysevent_evc_subscribe() error
240*7c478bd9Sstevel@tonic-gate  *   EMFILE	out of file descriptors
241*7c478bd9Sstevel@tonic-gate  *   EPERM	insufficient privilege for sysevent_evc_bind()
242*7c478bd9Sstevel@tonic-gate  *   EEXIST	already subscribed
243*7c478bd9Sstevel@tonic-gate  */
244*7c478bd9Sstevel@tonic-gate int
245*7c478bd9Sstevel@tonic-gate restarter_bind_handle(uint32_t version, const char *restarter_name,
246*7c478bd9Sstevel@tonic-gate     int (*event_handler)(restarter_event_t *), int flags,
247*7c478bd9Sstevel@tonic-gate     restarter_event_handle_t **rehp)
248*7c478bd9Sstevel@tonic-gate {
249*7c478bd9Sstevel@tonic-gate 	restarter_event_handle_t *h;
250*7c478bd9Sstevel@tonic-gate 	size_t sz;
251*7c478bd9Sstevel@tonic-gate 	int err;
252*7c478bd9Sstevel@tonic-gate 
253*7c478bd9Sstevel@tonic-gate 	if (version != RESTARTER_EVENT_VERSION)
254*7c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
255*7c478bd9Sstevel@tonic-gate 
256*7c478bd9Sstevel@tonic-gate 	if (restarter_name == NULL || event_handler == NULL)
257*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
258*7c478bd9Sstevel@tonic-gate 
259*7c478bd9Sstevel@tonic-gate 	if (flags & RESTARTER_FLAG_DEBUG)
260*7c478bd9Sstevel@tonic-gate 		ndebug++;
261*7c478bd9Sstevel@tonic-gate 
262*7c478bd9Sstevel@tonic-gate 	if ((h = uu_zalloc(sizeof (restarter_event_handle_t))) == NULL)
263*7c478bd9Sstevel@tonic-gate 		return (ENOMEM);
264*7c478bd9Sstevel@tonic-gate 
265*7c478bd9Sstevel@tonic-gate 	h->reh_delegate_subscriber_id = malloc(MAX_SUBID_LEN);
266*7c478bd9Sstevel@tonic-gate 	h->reh_master_subscriber_id = malloc(MAX_SUBID_LEN);
267*7c478bd9Sstevel@tonic-gate 	h->reh_restarter_name = strdup(restarter_name);
268*7c478bd9Sstevel@tonic-gate 	if (h->reh_delegate_subscriber_id == NULL ||
269*7c478bd9Sstevel@tonic-gate 	    h->reh_master_subscriber_id == NULL ||
270*7c478bd9Sstevel@tonic-gate 	    h->reh_restarter_name == NULL) {
271*7c478bd9Sstevel@tonic-gate 		free_restarter_event_handle(h);
272*7c478bd9Sstevel@tonic-gate 		return (ENOMEM);
273*7c478bd9Sstevel@tonic-gate 	}
274*7c478bd9Sstevel@tonic-gate 
275*7c478bd9Sstevel@tonic-gate 	sz = strlcpy(h->reh_delegate_subscriber_id, "del", MAX_SUBID_LEN);
276*7c478bd9Sstevel@tonic-gate 	assert(sz < MAX_SUBID_LEN);
277*7c478bd9Sstevel@tonic-gate 	sz = strlcpy(h->reh_master_subscriber_id, "master", MAX_SUBID_LEN);
278*7c478bd9Sstevel@tonic-gate 	assert(sz < MAX_SUBID_LEN);
279*7c478bd9Sstevel@tonic-gate 
280*7c478bd9Sstevel@tonic-gate 	h->reh_delegate_channel_name =
281*7c478bd9Sstevel@tonic-gate 	    _restarter_get_channel_name(restarter_name,
282*7c478bd9Sstevel@tonic-gate 	    RESTARTER_CHANNEL_DELEGATE);
283*7c478bd9Sstevel@tonic-gate 	h->reh_master_channel_name =
284*7c478bd9Sstevel@tonic-gate 	    _restarter_get_channel_name(restarter_name,
285*7c478bd9Sstevel@tonic-gate 	    RESTARTER_CHANNEL_MASTER);
286*7c478bd9Sstevel@tonic-gate 
287*7c478bd9Sstevel@tonic-gate 	if (h->reh_delegate_channel_name == NULL ||
288*7c478bd9Sstevel@tonic-gate 	    h->reh_master_channel_name == NULL) {
289*7c478bd9Sstevel@tonic-gate 		free_restarter_event_handle(h);
290*7c478bd9Sstevel@tonic-gate 		return (ENOMEM);
291*7c478bd9Sstevel@tonic-gate 	}
292*7c478bd9Sstevel@tonic-gate 
293*7c478bd9Sstevel@tonic-gate 	if (sysevent_evc_bind(h->reh_delegate_channel_name,
294*7c478bd9Sstevel@tonic-gate 	    &h->reh_delegate_channel, EVCH_CREAT|EVCH_HOLD_PEND) != 0) {
295*7c478bd9Sstevel@tonic-gate 		err = errno;
296*7c478bd9Sstevel@tonic-gate 		assert(err != EINVAL);
297*7c478bd9Sstevel@tonic-gate 		assert(err != ENOENT);
298*7c478bd9Sstevel@tonic-gate 		free_restarter_event_handle(h);
299*7c478bd9Sstevel@tonic-gate 		return (err);
300*7c478bd9Sstevel@tonic-gate 	}
301*7c478bd9Sstevel@tonic-gate 
302*7c478bd9Sstevel@tonic-gate 	if (sysevent_evc_bind(h->reh_master_channel_name,
303*7c478bd9Sstevel@tonic-gate 	    &h->reh_master_channel, EVCH_CREAT|EVCH_HOLD_PEND) != 0) {
304*7c478bd9Sstevel@tonic-gate 		err = errno;
305*7c478bd9Sstevel@tonic-gate 		assert(err != EINVAL);
306*7c478bd9Sstevel@tonic-gate 		assert(err != ENOENT);
307*7c478bd9Sstevel@tonic-gate 		free_restarter_event_handle(h);
308*7c478bd9Sstevel@tonic-gate 		return (err);
309*7c478bd9Sstevel@tonic-gate 	}
310*7c478bd9Sstevel@tonic-gate 
311*7c478bd9Sstevel@tonic-gate 	h->reh_handler = event_handler;
312*7c478bd9Sstevel@tonic-gate 
313*7c478bd9Sstevel@tonic-gate 	assert(strlen(restarter_name) <= MAX_CLASS_LEN - 1);
314*7c478bd9Sstevel@tonic-gate 	assert(strlen(h->reh_delegate_subscriber_id) <= MAX_SUBID_LEN - 1);
315*7c478bd9Sstevel@tonic-gate 	assert(strlen(h->reh_master_subscriber_id) <= MAX_SUBID_LEN - 1);
316*7c478bd9Sstevel@tonic-gate 
317*7c478bd9Sstevel@tonic-gate 	if (sysevent_evc_subscribe(h->reh_delegate_channel,
318*7c478bd9Sstevel@tonic-gate 	    h->reh_delegate_subscriber_id, EC_ALL, cb, h, EVCH_SUB_KEEP) != 0) {
319*7c478bd9Sstevel@tonic-gate 		err = errno;
320*7c478bd9Sstevel@tonic-gate 		assert(err != EINVAL);
321*7c478bd9Sstevel@tonic-gate 		free_restarter_event_handle(h);
322*7c478bd9Sstevel@tonic-gate 		return (err);
323*7c478bd9Sstevel@tonic-gate 	}
324*7c478bd9Sstevel@tonic-gate 
325*7c478bd9Sstevel@tonic-gate 	*rehp = h;
326*7c478bd9Sstevel@tonic-gate 	return (0);
327*7c478bd9Sstevel@tonic-gate }
328*7c478bd9Sstevel@tonic-gate 
329*7c478bd9Sstevel@tonic-gate void
330*7c478bd9Sstevel@tonic-gate restarter_unbind_handle(restarter_event_handle_t *h)
331*7c478bd9Sstevel@tonic-gate {
332*7c478bd9Sstevel@tonic-gate 	free_restarter_event_handle(h);
333*7c478bd9Sstevel@tonic-gate }
334*7c478bd9Sstevel@tonic-gate 
335*7c478bd9Sstevel@tonic-gate restarter_event_handle_t *
336*7c478bd9Sstevel@tonic-gate restarter_event_get_handle(restarter_event_t *e)
337*7c478bd9Sstevel@tonic-gate {
338*7c478bd9Sstevel@tonic-gate 	assert(e != NULL && e->re_event_handle != NULL);
339*7c478bd9Sstevel@tonic-gate 	return (e->re_event_handle);
340*7c478bd9Sstevel@tonic-gate }
341*7c478bd9Sstevel@tonic-gate 
342*7c478bd9Sstevel@tonic-gate restarter_event_type_t
343*7c478bd9Sstevel@tonic-gate restarter_event_get_type(restarter_event_t *e)
344*7c478bd9Sstevel@tonic-gate {
345*7c478bd9Sstevel@tonic-gate 	assert(e != NULL);
346*7c478bd9Sstevel@tonic-gate 	return (e->re_type);
347*7c478bd9Sstevel@tonic-gate }
348*7c478bd9Sstevel@tonic-gate 
349*7c478bd9Sstevel@tonic-gate ssize_t
350*7c478bd9Sstevel@tonic-gate restarter_event_get_instance(restarter_event_t *e, char *inst, size_t sz)
351*7c478bd9Sstevel@tonic-gate {
352*7c478bd9Sstevel@tonic-gate 	assert(e != NULL && inst != NULL);
353*7c478bd9Sstevel@tonic-gate 	return ((ssize_t)strlcpy(inst, e->re_instance_name, sz));
354*7c478bd9Sstevel@tonic-gate }
355*7c478bd9Sstevel@tonic-gate 
356*7c478bd9Sstevel@tonic-gate int
357*7c478bd9Sstevel@tonic-gate restarter_event_get_current_states(restarter_event_t *e,
358*7c478bd9Sstevel@tonic-gate     restarter_instance_state_t *state, restarter_instance_state_t *next_state)
359*7c478bd9Sstevel@tonic-gate {
360*7c478bd9Sstevel@tonic-gate 	if (e == NULL)
361*7c478bd9Sstevel@tonic-gate 		return (-1);
362*7c478bd9Sstevel@tonic-gate 	*state = e->re_state;
363*7c478bd9Sstevel@tonic-gate 	*next_state = e->re_next_state;
364*7c478bd9Sstevel@tonic-gate 	return (0);
365*7c478bd9Sstevel@tonic-gate }
366*7c478bd9Sstevel@tonic-gate 
367*7c478bd9Sstevel@tonic-gate /*
368*7c478bd9Sstevel@tonic-gate  * Commit the state, next state, and auxiliary state into the repository.
369*7c478bd9Sstevel@tonic-gate  * Let the graph engine know about the state change and error.  On success,
370*7c478bd9Sstevel@tonic-gate  * return 0. On error, return
371*7c478bd9Sstevel@tonic-gate  *   EINVAL - aux has spaces
372*7c478bd9Sstevel@tonic-gate  *	    - inst is invalid or not an instance FMRI
373*7c478bd9Sstevel@tonic-gate  *   EPROTO - librestart compiled against different libscf
374*7c478bd9Sstevel@tonic-gate  *   ENOMEM - out of memory
375*7c478bd9Sstevel@tonic-gate  *	    - repository server out of resources
376*7c478bd9Sstevel@tonic-gate  *   ENOTACTIVE - repository server not running
377*7c478bd9Sstevel@tonic-gate  *   ECONNABORTED - repository connection established, but then broken
378*7c478bd9Sstevel@tonic-gate  *		  - unknown libscf error
379*7c478bd9Sstevel@tonic-gate  *   ENOENT - inst does not exist in the repository
380*7c478bd9Sstevel@tonic-gate  *   EPERM - insufficient permissions
381*7c478bd9Sstevel@tonic-gate  *   EACCESS - backend access denied
382*7c478bd9Sstevel@tonic-gate  *   EROFS - backend is readonly
383*7c478bd9Sstevel@tonic-gate  *   EFAULT - internal sysevent_evc_publish() error
384*7c478bd9Sstevel@tonic-gate  *   EBADF - h is invalid (sysevent_evc_publish() returned EINVAL)
385*7c478bd9Sstevel@tonic-gate  */
386*7c478bd9Sstevel@tonic-gate int
387*7c478bd9Sstevel@tonic-gate restarter_set_states(restarter_event_handle_t *h, const char *inst,
388*7c478bd9Sstevel@tonic-gate     restarter_instance_state_t cur_state,
389*7c478bd9Sstevel@tonic-gate     restarter_instance_state_t new_cur_state,
390*7c478bd9Sstevel@tonic-gate     restarter_instance_state_t next_state,
391*7c478bd9Sstevel@tonic-gate     restarter_instance_state_t new_next_state, restarter_error_t e,
392*7c478bd9Sstevel@tonic-gate     const char *aux)
393*7c478bd9Sstevel@tonic-gate {
394*7c478bd9Sstevel@tonic-gate 	nvlist_t *attr;
395*7c478bd9Sstevel@tonic-gate 	scf_handle_t *scf_h;
396*7c478bd9Sstevel@tonic-gate 	instance_data_t id;
397*7c478bd9Sstevel@tonic-gate 	useconds_t retry_int = INITIAL_COMMIT_RETRY_INT;
398*7c478bd9Sstevel@tonic-gate 	int retries;
399*7c478bd9Sstevel@tonic-gate 	int ret = 0;
400*7c478bd9Sstevel@tonic-gate 	char *p = (char *)aux;
401*7c478bd9Sstevel@tonic-gate 
402*7c478bd9Sstevel@tonic-gate 	assert(h->reh_master_channel != NULL);
403*7c478bd9Sstevel@tonic-gate 	assert(h->reh_master_channel_name != NULL);
404*7c478bd9Sstevel@tonic-gate 	assert(h->reh_master_subscriber_id != NULL);
405*7c478bd9Sstevel@tonic-gate 
406*7c478bd9Sstevel@tonic-gate 	/* Validate format of auxiliary state: no spaces allowed */
407*7c478bd9Sstevel@tonic-gate 	while (p != NULL) {
408*7c478bd9Sstevel@tonic-gate 		if (isspace(*p))
409*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
410*7c478bd9Sstevel@tonic-gate 		p++;
411*7c478bd9Sstevel@tonic-gate 	}
412*7c478bd9Sstevel@tonic-gate 
413*7c478bd9Sstevel@tonic-gate 	if ((scf_h = scf_handle_create(SCF_VERSION)) == NULL) {
414*7c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
415*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_VERSION_MISMATCH:
416*7c478bd9Sstevel@tonic-gate 			return (EPROTO);
417*7c478bd9Sstevel@tonic-gate 
418*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NO_MEMORY:
419*7c478bd9Sstevel@tonic-gate 			return (ENOMEM);
420*7c478bd9Sstevel@tonic-gate 
421*7c478bd9Sstevel@tonic-gate 		default:
422*7c478bd9Sstevel@tonic-gate 			bad_fail("scf_handle_create", scf_error());
423*7c478bd9Sstevel@tonic-gate 		}
424*7c478bd9Sstevel@tonic-gate 	}
425*7c478bd9Sstevel@tonic-gate 
426*7c478bd9Sstevel@tonic-gate 	if (scf_handle_bind(scf_h) == -1) {
427*7c478bd9Sstevel@tonic-gate 		scf_handle_destroy(scf_h);
428*7c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
429*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NO_SERVER:
430*7c478bd9Sstevel@tonic-gate 			return (ENOTACTIVE);
431*7c478bd9Sstevel@tonic-gate 
432*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NO_RESOURCES:
433*7c478bd9Sstevel@tonic-gate 			return (ENOMEM);
434*7c478bd9Sstevel@tonic-gate 
435*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_INVALID_ARGUMENT:
436*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_IN_USE:
437*7c478bd9Sstevel@tonic-gate 		default:
438*7c478bd9Sstevel@tonic-gate 			bad_fail("scf_handle_bind", scf_error());
439*7c478bd9Sstevel@tonic-gate 		}
440*7c478bd9Sstevel@tonic-gate 	}
441*7c478bd9Sstevel@tonic-gate 
442*7c478bd9Sstevel@tonic-gate 	if (nvlist_alloc(&attr, NV_UNIQUE_NAME, 0) != 0 ||
443*7c478bd9Sstevel@tonic-gate 	    nvlist_add_int32(attr, RESTARTER_NAME_STATE, new_cur_state) != 0 ||
444*7c478bd9Sstevel@tonic-gate 	    nvlist_add_int32(attr, RESTARTER_NAME_NEXT_STATE, new_next_state)
445*7c478bd9Sstevel@tonic-gate 	    != 0 ||
446*7c478bd9Sstevel@tonic-gate 	    nvlist_add_int32(attr, RESTARTER_NAME_ERROR, e) != 0 ||
447*7c478bd9Sstevel@tonic-gate 	    nvlist_add_string(attr, RESTARTER_NAME_INSTANCE, inst) != 0) {
448*7c478bd9Sstevel@tonic-gate 		ret = ENOMEM;
449*7c478bd9Sstevel@tonic-gate 		goto errout;
450*7c478bd9Sstevel@tonic-gate 	}
451*7c478bd9Sstevel@tonic-gate 
452*7c478bd9Sstevel@tonic-gate 	id.i_fmri = inst;
453*7c478bd9Sstevel@tonic-gate 	id.i_state = cur_state;
454*7c478bd9Sstevel@tonic-gate 	id.i_next_state = next_state;
455*7c478bd9Sstevel@tonic-gate 
456*7c478bd9Sstevel@tonic-gate 	ret = _restarter_commit_states(scf_h, &id, new_cur_state,
457*7c478bd9Sstevel@tonic-gate 	    new_next_state, aux);
458*7c478bd9Sstevel@tonic-gate 	if (ret != 0)
459*7c478bd9Sstevel@tonic-gate 		goto errout;
460*7c478bd9Sstevel@tonic-gate 
461*7c478bd9Sstevel@tonic-gate 	for (retries = 0; retries < MAX_COMMIT_RETRIES; retries++) {
462*7c478bd9Sstevel@tonic-gate 		ret = sysevent_evc_publish(h->reh_master_channel, "master",
463*7c478bd9Sstevel@tonic-gate 		    "state_change", "com.sun", "librestart", attr,
464*7c478bd9Sstevel@tonic-gate 		    EVCH_NOSLEEP);
465*7c478bd9Sstevel@tonic-gate 		if (ret == 0)
466*7c478bd9Sstevel@tonic-gate 			break;
467*7c478bd9Sstevel@tonic-gate 
468*7c478bd9Sstevel@tonic-gate 		switch (ret) {
469*7c478bd9Sstevel@tonic-gate 		case EAGAIN:
470*7c478bd9Sstevel@tonic-gate 			/* Queue is full */
471*7c478bd9Sstevel@tonic-gate 			(void) usleep(retry_int);
472*7c478bd9Sstevel@tonic-gate 
473*7c478bd9Sstevel@tonic-gate 			retry_int = min(retry_int * 2, MAX_COMMIT_RETRY_INT);
474*7c478bd9Sstevel@tonic-gate 			break;
475*7c478bd9Sstevel@tonic-gate 
476*7c478bd9Sstevel@tonic-gate 		case EFAULT:
477*7c478bd9Sstevel@tonic-gate 		case ENOMEM:
478*7c478bd9Sstevel@tonic-gate 			goto errout;
479*7c478bd9Sstevel@tonic-gate 
480*7c478bd9Sstevel@tonic-gate 		case EINVAL:
481*7c478bd9Sstevel@tonic-gate 			ret = EBADF;
482*7c478bd9Sstevel@tonic-gate 			goto errout;
483*7c478bd9Sstevel@tonic-gate 
484*7c478bd9Sstevel@tonic-gate 		case EOVERFLOW:
485*7c478bd9Sstevel@tonic-gate 		default:
486*7c478bd9Sstevel@tonic-gate 			bad_fail("sysevent_evc_publish", ret);
487*7c478bd9Sstevel@tonic-gate 		}
488*7c478bd9Sstevel@tonic-gate 	}
489*7c478bd9Sstevel@tonic-gate 
490*7c478bd9Sstevel@tonic-gate errout:
491*7c478bd9Sstevel@tonic-gate 	nvlist_free(attr);
492*7c478bd9Sstevel@tonic-gate 	(void) scf_handle_unbind(scf_h);
493*7c478bd9Sstevel@tonic-gate 	scf_handle_destroy(scf_h);
494*7c478bd9Sstevel@tonic-gate 
495*7c478bd9Sstevel@tonic-gate 	return (ret);
496*7c478bd9Sstevel@tonic-gate }
497*7c478bd9Sstevel@tonic-gate 
498*7c478bd9Sstevel@tonic-gate restarter_instance_state_t
499*7c478bd9Sstevel@tonic-gate restarter_string_to_state(char *string)
500*7c478bd9Sstevel@tonic-gate {
501*7c478bd9Sstevel@tonic-gate 	assert(string != NULL);
502*7c478bd9Sstevel@tonic-gate 
503*7c478bd9Sstevel@tonic-gate 	if (strcmp(string, SCF_STATE_STRING_NONE) == 0)
504*7c478bd9Sstevel@tonic-gate 		return (RESTARTER_STATE_NONE);
505*7c478bd9Sstevel@tonic-gate 	else if (strcmp(string, SCF_STATE_STRING_UNINIT) == 0)
506*7c478bd9Sstevel@tonic-gate 		return (RESTARTER_STATE_UNINIT);
507*7c478bd9Sstevel@tonic-gate 	else if (strcmp(string, SCF_STATE_STRING_MAINT) == 0)
508*7c478bd9Sstevel@tonic-gate 		return (RESTARTER_STATE_MAINT);
509*7c478bd9Sstevel@tonic-gate 	else if (strcmp(string, SCF_STATE_STRING_OFFLINE) == 0)
510*7c478bd9Sstevel@tonic-gate 		return (RESTARTER_STATE_OFFLINE);
511*7c478bd9Sstevel@tonic-gate 	else if (strcmp(string, SCF_STATE_STRING_DISABLED) == 0)
512*7c478bd9Sstevel@tonic-gate 		return (RESTARTER_STATE_DISABLED);
513*7c478bd9Sstevel@tonic-gate 	else if (strcmp(string, SCF_STATE_STRING_ONLINE) == 0)
514*7c478bd9Sstevel@tonic-gate 		return (RESTARTER_STATE_ONLINE);
515*7c478bd9Sstevel@tonic-gate 	else if (strcmp(string, SCF_STATE_STRING_DEGRADED) == 0)
516*7c478bd9Sstevel@tonic-gate 		return (RESTARTER_STATE_DEGRADED);
517*7c478bd9Sstevel@tonic-gate 	else {
518*7c478bd9Sstevel@tonic-gate 		return (RESTARTER_STATE_NONE);
519*7c478bd9Sstevel@tonic-gate 	}
520*7c478bd9Sstevel@tonic-gate }
521*7c478bd9Sstevel@tonic-gate 
522*7c478bd9Sstevel@tonic-gate ssize_t
523*7c478bd9Sstevel@tonic-gate restarter_state_to_string(restarter_instance_state_t state, char *string,
524*7c478bd9Sstevel@tonic-gate     size_t len)
525*7c478bd9Sstevel@tonic-gate {
526*7c478bd9Sstevel@tonic-gate 	assert(string != NULL);
527*7c478bd9Sstevel@tonic-gate 
528*7c478bd9Sstevel@tonic-gate 	if (state == RESTARTER_STATE_NONE)
529*7c478bd9Sstevel@tonic-gate 		return ((ssize_t)strlcpy(string, SCF_STATE_STRING_NONE, len));
530*7c478bd9Sstevel@tonic-gate 	else if (state == RESTARTER_STATE_UNINIT)
531*7c478bd9Sstevel@tonic-gate 		return ((ssize_t)strlcpy(string, SCF_STATE_STRING_UNINIT, len));
532*7c478bd9Sstevel@tonic-gate 	else if (state == RESTARTER_STATE_MAINT)
533*7c478bd9Sstevel@tonic-gate 		return ((ssize_t)strlcpy(string, SCF_STATE_STRING_MAINT, len));
534*7c478bd9Sstevel@tonic-gate 	else if (state == RESTARTER_STATE_OFFLINE)
535*7c478bd9Sstevel@tonic-gate 		return ((ssize_t)strlcpy(string, SCF_STATE_STRING_OFFLINE,
536*7c478bd9Sstevel@tonic-gate 		    len));
537*7c478bd9Sstevel@tonic-gate 	else if (state == RESTARTER_STATE_DISABLED)
538*7c478bd9Sstevel@tonic-gate 		return ((ssize_t)strlcpy(string, SCF_STATE_STRING_DISABLED,
539*7c478bd9Sstevel@tonic-gate 		    len));
540*7c478bd9Sstevel@tonic-gate 	else if (state == RESTARTER_STATE_ONLINE)
541*7c478bd9Sstevel@tonic-gate 		return ((ssize_t)strlcpy(string, SCF_STATE_STRING_ONLINE, len));
542*7c478bd9Sstevel@tonic-gate 	else if (state == RESTARTER_STATE_DEGRADED)
543*7c478bd9Sstevel@tonic-gate 		return ((ssize_t)strlcpy(string, SCF_STATE_STRING_DEGRADED,
544*7c478bd9Sstevel@tonic-gate 		    len));
545*7c478bd9Sstevel@tonic-gate 	else
546*7c478bd9Sstevel@tonic-gate 		return ((ssize_t)strlcpy(string, "unknown", len));
547*7c478bd9Sstevel@tonic-gate }
548*7c478bd9Sstevel@tonic-gate 
549*7c478bd9Sstevel@tonic-gate /*
550*7c478bd9Sstevel@tonic-gate  * Sets pg to the name property group of s_inst.  If it doesn't exist, it is
551*7c478bd9Sstevel@tonic-gate  * added.
552*7c478bd9Sstevel@tonic-gate  *
553*7c478bd9Sstevel@tonic-gate  * Fails with
554*7c478bd9Sstevel@tonic-gate  *   ECONNABORTED - repository disconnection or unknown libscf error
555*7c478bd9Sstevel@tonic-gate  *   EBADF - inst is not set
556*7c478bd9Sstevel@tonic-gate  *   ECANCELED - inst is deleted
557*7c478bd9Sstevel@tonic-gate  *   EPERM - permission is denied
558*7c478bd9Sstevel@tonic-gate  *   EACCES - backend denied access
559*7c478bd9Sstevel@tonic-gate  *   EROFS - backend readonly
560*7c478bd9Sstevel@tonic-gate  */
561*7c478bd9Sstevel@tonic-gate static int
562*7c478bd9Sstevel@tonic-gate instance_get_or_add_pg(scf_instance_t *inst, const char *name,
563*7c478bd9Sstevel@tonic-gate     const char *type, uint32_t flags, scf_propertygroup_t *pg)
564*7c478bd9Sstevel@tonic-gate {
565*7c478bd9Sstevel@tonic-gate again:
566*7c478bd9Sstevel@tonic-gate 	if (scf_instance_get_pg(inst, name, pg) == 0)
567*7c478bd9Sstevel@tonic-gate 		return (0);
568*7c478bd9Sstevel@tonic-gate 
569*7c478bd9Sstevel@tonic-gate 	switch (scf_error()) {
570*7c478bd9Sstevel@tonic-gate 	case SCF_ERROR_CONNECTION_BROKEN:
571*7c478bd9Sstevel@tonic-gate 	default:
572*7c478bd9Sstevel@tonic-gate 		return (ECONNABORTED);
573*7c478bd9Sstevel@tonic-gate 
574*7c478bd9Sstevel@tonic-gate 	case SCF_ERROR_NOT_SET:
575*7c478bd9Sstevel@tonic-gate 		return (EBADF);
576*7c478bd9Sstevel@tonic-gate 
577*7c478bd9Sstevel@tonic-gate 	case SCF_ERROR_DELETED:
578*7c478bd9Sstevel@tonic-gate 		return (ECANCELED);
579*7c478bd9Sstevel@tonic-gate 
580*7c478bd9Sstevel@tonic-gate 	case SCF_ERROR_NOT_FOUND:
581*7c478bd9Sstevel@tonic-gate 		break;
582*7c478bd9Sstevel@tonic-gate 
583*7c478bd9Sstevel@tonic-gate 	case SCF_ERROR_HANDLE_MISMATCH:
584*7c478bd9Sstevel@tonic-gate 	case SCF_ERROR_INVALID_ARGUMENT:
585*7c478bd9Sstevel@tonic-gate 		bad_fail("scf_instance_get_pg", scf_error());
586*7c478bd9Sstevel@tonic-gate 	}
587*7c478bd9Sstevel@tonic-gate 
588*7c478bd9Sstevel@tonic-gate 	if (scf_instance_add_pg(inst, name, type, flags, pg) == 0)
589*7c478bd9Sstevel@tonic-gate 		return (0);
590*7c478bd9Sstevel@tonic-gate 
591*7c478bd9Sstevel@tonic-gate 	switch (scf_error()) {
592*7c478bd9Sstevel@tonic-gate 	case SCF_ERROR_CONNECTION_BROKEN:
593*7c478bd9Sstevel@tonic-gate 	default:
594*7c478bd9Sstevel@tonic-gate 		return (ECONNABORTED);
595*7c478bd9Sstevel@tonic-gate 
596*7c478bd9Sstevel@tonic-gate 	case SCF_ERROR_DELETED:
597*7c478bd9Sstevel@tonic-gate 		return (ECANCELED);
598*7c478bd9Sstevel@tonic-gate 
599*7c478bd9Sstevel@tonic-gate 	case SCF_ERROR_EXISTS:
600*7c478bd9Sstevel@tonic-gate 		goto again;
601*7c478bd9Sstevel@tonic-gate 
602*7c478bd9Sstevel@tonic-gate 	case SCF_ERROR_PERMISSION_DENIED:
603*7c478bd9Sstevel@tonic-gate 		return (EPERM);
604*7c478bd9Sstevel@tonic-gate 
605*7c478bd9Sstevel@tonic-gate 	case SCF_ERROR_BACKEND_ACCESS:
606*7c478bd9Sstevel@tonic-gate 		return (EACCES);
607*7c478bd9Sstevel@tonic-gate 
608*7c478bd9Sstevel@tonic-gate 	case SCF_ERROR_BACKEND_READONLY:
609*7c478bd9Sstevel@tonic-gate 		return (EROFS);
610*7c478bd9Sstevel@tonic-gate 
611*7c478bd9Sstevel@tonic-gate 	case SCF_ERROR_HANDLE_MISMATCH:
612*7c478bd9Sstevel@tonic-gate 	case SCF_ERROR_INVALID_ARGUMENT:
613*7c478bd9Sstevel@tonic-gate 	case SCF_ERROR_NOT_SET:			/* should be caught above */
614*7c478bd9Sstevel@tonic-gate 		bad_fail("scf_instance_add_pg", scf_error());
615*7c478bd9Sstevel@tonic-gate 	}
616*7c478bd9Sstevel@tonic-gate 
617*7c478bd9Sstevel@tonic-gate 	return (0);
618*7c478bd9Sstevel@tonic-gate }
619*7c478bd9Sstevel@tonic-gate 
620*7c478bd9Sstevel@tonic-gate /*
621*7c478bd9Sstevel@tonic-gate  * Fails with
622*7c478bd9Sstevel@tonic-gate  *   ECONNABORTED
623*7c478bd9Sstevel@tonic-gate  *   ECANCELED - pg was deleted
624*7c478bd9Sstevel@tonic-gate  */
625*7c478bd9Sstevel@tonic-gate static int
626*7c478bd9Sstevel@tonic-gate tx_set_value(scf_transaction_t *tx, scf_transaction_entry_t *ent,
627*7c478bd9Sstevel@tonic-gate     const char *pname, scf_type_t ty, scf_value_t *val)
628*7c478bd9Sstevel@tonic-gate {
629*7c478bd9Sstevel@tonic-gate 	int r;
630*7c478bd9Sstevel@tonic-gate 
631*7c478bd9Sstevel@tonic-gate 	for (;;) {
632*7c478bd9Sstevel@tonic-gate 		if (scf_transaction_property_change_type(tx, ent, pname,
633*7c478bd9Sstevel@tonic-gate 		    ty) == 0)
634*7c478bd9Sstevel@tonic-gate 			break;
635*7c478bd9Sstevel@tonic-gate 
636*7c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
637*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_CONNECTION_BROKEN:
638*7c478bd9Sstevel@tonic-gate 		default:
639*7c478bd9Sstevel@tonic-gate 			return (ECONNABORTED);
640*7c478bd9Sstevel@tonic-gate 
641*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
642*7c478bd9Sstevel@tonic-gate 			return (ECANCELED);
643*7c478bd9Sstevel@tonic-gate 
644*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
645*7c478bd9Sstevel@tonic-gate 			break;
646*7c478bd9Sstevel@tonic-gate 
647*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_HANDLE_MISMATCH:
648*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_INVALID_ARGUMENT:
649*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_IN_USE:
650*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
651*7c478bd9Sstevel@tonic-gate 			bad_fail("scf_transaction_property_change_type",
652*7c478bd9Sstevel@tonic-gate 			    scf_error());
653*7c478bd9Sstevel@tonic-gate 		}
654*7c478bd9Sstevel@tonic-gate 
655*7c478bd9Sstevel@tonic-gate 		if (scf_transaction_property_new(tx, ent, pname, ty) == 0)
656*7c478bd9Sstevel@tonic-gate 			break;
657*7c478bd9Sstevel@tonic-gate 
658*7c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
659*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_CONNECTION_BROKEN:
660*7c478bd9Sstevel@tonic-gate 		default:
661*7c478bd9Sstevel@tonic-gate 			return (ECONNABORTED);
662*7c478bd9Sstevel@tonic-gate 
663*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
664*7c478bd9Sstevel@tonic-gate 			return (ECANCELED);
665*7c478bd9Sstevel@tonic-gate 
666*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_EXISTS:
667*7c478bd9Sstevel@tonic-gate 			break;
668*7c478bd9Sstevel@tonic-gate 
669*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_HANDLE_MISMATCH:
670*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_INVALID_ARGUMENT:
671*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_IN_USE:
672*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
673*7c478bd9Sstevel@tonic-gate 			bad_fail("scf_transaction_property_new", scf_error());
674*7c478bd9Sstevel@tonic-gate 		}
675*7c478bd9Sstevel@tonic-gate 	}
676*7c478bd9Sstevel@tonic-gate 
677*7c478bd9Sstevel@tonic-gate 	r = scf_entry_add_value(ent, val);
678*7c478bd9Sstevel@tonic-gate 	assert(r == 0);
679*7c478bd9Sstevel@tonic-gate 
680*7c478bd9Sstevel@tonic-gate 	return (0);
681*7c478bd9Sstevel@tonic-gate }
682*7c478bd9Sstevel@tonic-gate 
683*7c478bd9Sstevel@tonic-gate /*
684*7c478bd9Sstevel@tonic-gate  * Commit new_state, new_next_state, and aux to the repository for id.  If
685*7c478bd9Sstevel@tonic-gate  * successful, also set id's state and next-state as given, and return 0.
686*7c478bd9Sstevel@tonic-gate  * Fails with
687*7c478bd9Sstevel@tonic-gate  *   ENOMEM - out of memory
688*7c478bd9Sstevel@tonic-gate  *   ECONNABORTED - repository connection broken
689*7c478bd9Sstevel@tonic-gate  *		  - unknown libscf error
690*7c478bd9Sstevel@tonic-gate  *   EINVAL - id->i_fmri is invalid or not an instance FMRI
691*7c478bd9Sstevel@tonic-gate  *   ENOENT - id->i_fmri does not exist
692*7c478bd9Sstevel@tonic-gate  *   EPERM - insufficient permissions
693*7c478bd9Sstevel@tonic-gate  *   EACCES - backend access denied
694*7c478bd9Sstevel@tonic-gate  *   EROFS - backend is readonly
695*7c478bd9Sstevel@tonic-gate  */
696*7c478bd9Sstevel@tonic-gate int
697*7c478bd9Sstevel@tonic-gate _restarter_commit_states(scf_handle_t *h, instance_data_t *id,
698*7c478bd9Sstevel@tonic-gate     restarter_instance_state_t new_state,
699*7c478bd9Sstevel@tonic-gate     restarter_instance_state_t new_state_next, const char *aux)
700*7c478bd9Sstevel@tonic-gate {
701*7c478bd9Sstevel@tonic-gate 	char str_state[MAX_SCF_STATE_STRING_SZ];
702*7c478bd9Sstevel@tonic-gate 	char str_new_state[MAX_SCF_STATE_STRING_SZ];
703*7c478bd9Sstevel@tonic-gate 	char str_state_next[MAX_SCF_STATE_STRING_SZ];
704*7c478bd9Sstevel@tonic-gate 	char str_new_state_next[MAX_SCF_STATE_STRING_SZ];
705*7c478bd9Sstevel@tonic-gate 	int ret = 0, r;
706*7c478bd9Sstevel@tonic-gate 	struct timeval now;
707*7c478bd9Sstevel@tonic-gate 	ssize_t sz;
708*7c478bd9Sstevel@tonic-gate 	char *default_aux = "none";
709*7c478bd9Sstevel@tonic-gate 
710*7c478bd9Sstevel@tonic-gate 	scf_transaction_t *t = NULL;
711*7c478bd9Sstevel@tonic-gate 	scf_transaction_entry_t *t_state = NULL, *t_state_next = NULL;
712*7c478bd9Sstevel@tonic-gate 	scf_transaction_entry_t *t_stime = NULL, *t_aux = NULL;
713*7c478bd9Sstevel@tonic-gate 	scf_value_t *v_state = NULL, *v_state_next = NULL, *v_stime = NULL;
714*7c478bd9Sstevel@tonic-gate 	scf_value_t *v_aux = NULL;
715*7c478bd9Sstevel@tonic-gate 	scf_instance_t *s_inst = NULL;
716*7c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg = NULL;
717*7c478bd9Sstevel@tonic-gate 
718*7c478bd9Sstevel@tonic-gate 	assert(new_state != RESTARTER_STATE_NONE);
719*7c478bd9Sstevel@tonic-gate 
720*7c478bd9Sstevel@tonic-gate 	/* If aux state is unset, set aux to a default string. */
721*7c478bd9Sstevel@tonic-gate 	if (aux == NULL)
722*7c478bd9Sstevel@tonic-gate 		aux = default_aux;
723*7c478bd9Sstevel@tonic-gate 
724*7c478bd9Sstevel@tonic-gate 	if ((s_inst = scf_instance_create(h)) == NULL ||
725*7c478bd9Sstevel@tonic-gate 	    (pg = scf_pg_create(h)) == NULL ||
726*7c478bd9Sstevel@tonic-gate 	    (t = scf_transaction_create(h)) == NULL ||
727*7c478bd9Sstevel@tonic-gate 	    (t_state = scf_entry_create(h)) == NULL ||
728*7c478bd9Sstevel@tonic-gate 	    (t_state_next = scf_entry_create(h)) == NULL ||
729*7c478bd9Sstevel@tonic-gate 	    (t_stime = scf_entry_create(h)) == NULL ||
730*7c478bd9Sstevel@tonic-gate 	    (t_aux = scf_entry_create(h)) == NULL ||
731*7c478bd9Sstevel@tonic-gate 	    (v_state = scf_value_create(h)) == NULL ||
732*7c478bd9Sstevel@tonic-gate 	    (v_state_next = scf_value_create(h)) == NULL ||
733*7c478bd9Sstevel@tonic-gate 	    (v_stime = scf_value_create(h)) == NULL ||
734*7c478bd9Sstevel@tonic-gate 	    (v_aux = scf_value_create(h)) == NULL) {
735*7c478bd9Sstevel@tonic-gate 		ret = ENOMEM;
736*7c478bd9Sstevel@tonic-gate 		goto out;
737*7c478bd9Sstevel@tonic-gate 	}
738*7c478bd9Sstevel@tonic-gate 
739*7c478bd9Sstevel@tonic-gate 	sz = restarter_state_to_string(new_state, str_new_state,
740*7c478bd9Sstevel@tonic-gate 	    sizeof (str_new_state));
741*7c478bd9Sstevel@tonic-gate 	assert(sz < sizeof (str_new_state));
742*7c478bd9Sstevel@tonic-gate 	sz = restarter_state_to_string(new_state_next, str_new_state_next,
743*7c478bd9Sstevel@tonic-gate 	    sizeof (str_new_state_next));
744*7c478bd9Sstevel@tonic-gate 	assert(sz < sizeof (str_new_state_next));
745*7c478bd9Sstevel@tonic-gate 	sz = restarter_state_to_string(id->i_state, str_state,
746*7c478bd9Sstevel@tonic-gate 	    sizeof (str_state));
747*7c478bd9Sstevel@tonic-gate 	assert(sz < sizeof (str_state));
748*7c478bd9Sstevel@tonic-gate 	sz = restarter_state_to_string(id->i_next_state, str_state_next,
749*7c478bd9Sstevel@tonic-gate 	    sizeof (str_state_next));
750*7c478bd9Sstevel@tonic-gate 	assert(sz < sizeof (str_state_next));
751*7c478bd9Sstevel@tonic-gate 
752*7c478bd9Sstevel@tonic-gate 	ret = gettimeofday(&now, NULL);
753*7c478bd9Sstevel@tonic-gate 	assert(ret != -1);
754*7c478bd9Sstevel@tonic-gate 
755*7c478bd9Sstevel@tonic-gate 	if (scf_handle_decode_fmri(h, id->i_fmri, NULL, NULL, s_inst,
756*7c478bd9Sstevel@tonic-gate 	    NULL, NULL, SCF_DECODE_FMRI_EXACT) == -1) {
757*7c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
758*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_CONNECTION_BROKEN:
759*7c478bd9Sstevel@tonic-gate 		default:
760*7c478bd9Sstevel@tonic-gate 			ret = ECONNABORTED;
761*7c478bd9Sstevel@tonic-gate 			break;
762*7c478bd9Sstevel@tonic-gate 
763*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_INVALID_ARGUMENT:
764*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_CONSTRAINT_VIOLATED:
765*7c478bd9Sstevel@tonic-gate 			ret = EINVAL;
766*7c478bd9Sstevel@tonic-gate 			break;
767*7c478bd9Sstevel@tonic-gate 
768*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
769*7c478bd9Sstevel@tonic-gate 			ret = ENOENT;
770*7c478bd9Sstevel@tonic-gate 			break;
771*7c478bd9Sstevel@tonic-gate 
772*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_HANDLE_MISMATCH:
773*7c478bd9Sstevel@tonic-gate 			bad_fail("scf_handle_decode_fmri", scf_error());
774*7c478bd9Sstevel@tonic-gate 		}
775*7c478bd9Sstevel@tonic-gate 		goto out;
776*7c478bd9Sstevel@tonic-gate 	}
777*7c478bd9Sstevel@tonic-gate 
778*7c478bd9Sstevel@tonic-gate 
779*7c478bd9Sstevel@tonic-gate 	if (scf_value_set_astring(v_state, str_new_state) != 0 ||
780*7c478bd9Sstevel@tonic-gate 	    scf_value_set_astring(v_state_next, str_new_state_next) != 0 ||
781*7c478bd9Sstevel@tonic-gate 	    scf_value_set_astring(v_aux, aux) != 0)
782*7c478bd9Sstevel@tonic-gate 		bad_fail("scf_value_set_astring", scf_error());
783*7c478bd9Sstevel@tonic-gate 
784*7c478bd9Sstevel@tonic-gate 	if (scf_value_set_time(v_stime, now.tv_sec, now.tv_usec * 1000) != 0)
785*7c478bd9Sstevel@tonic-gate 		bad_fail("scf_value_set_time", scf_error());
786*7c478bd9Sstevel@tonic-gate 
787*7c478bd9Sstevel@tonic-gate add_pg:
788*7c478bd9Sstevel@tonic-gate 	switch (r = instance_get_or_add_pg(s_inst, SCF_PG_RESTARTER,
789*7c478bd9Sstevel@tonic-gate 	    SCF_PG_RESTARTER_TYPE, SCF_PG_RESTARTER_FLAGS, pg)) {
790*7c478bd9Sstevel@tonic-gate 	case 0:
791*7c478bd9Sstevel@tonic-gate 		break;
792*7c478bd9Sstevel@tonic-gate 
793*7c478bd9Sstevel@tonic-gate 	case ECONNABORTED:
794*7c478bd9Sstevel@tonic-gate 	case EPERM:
795*7c478bd9Sstevel@tonic-gate 	case EACCES:
796*7c478bd9Sstevel@tonic-gate 	case EROFS:
797*7c478bd9Sstevel@tonic-gate 		ret = r;
798*7c478bd9Sstevel@tonic-gate 		goto out;
799*7c478bd9Sstevel@tonic-gate 
800*7c478bd9Sstevel@tonic-gate 	case ECANCELED:
801*7c478bd9Sstevel@tonic-gate 		ret = ENOENT;
802*7c478bd9Sstevel@tonic-gate 		goto out;
803*7c478bd9Sstevel@tonic-gate 
804*7c478bd9Sstevel@tonic-gate 	case EBADF:
805*7c478bd9Sstevel@tonic-gate 	default:
806*7c478bd9Sstevel@tonic-gate 		bad_fail("instance_get_or_add_pg", r);
807*7c478bd9Sstevel@tonic-gate 	}
808*7c478bd9Sstevel@tonic-gate 
809*7c478bd9Sstevel@tonic-gate 	for (;;) {
810*7c478bd9Sstevel@tonic-gate 		if (scf_transaction_start(t, pg) != 0) {
811*7c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
812*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
813*7c478bd9Sstevel@tonic-gate 			default:
814*7c478bd9Sstevel@tonic-gate 				ret = ECONNABORTED;
815*7c478bd9Sstevel@tonic-gate 				goto out;
816*7c478bd9Sstevel@tonic-gate 
817*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
818*7c478bd9Sstevel@tonic-gate 				goto add_pg;
819*7c478bd9Sstevel@tonic-gate 
820*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
821*7c478bd9Sstevel@tonic-gate 				ret = EPERM;
822*7c478bd9Sstevel@tonic-gate 				goto out;
823*7c478bd9Sstevel@tonic-gate 
824*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_ACCESS:
825*7c478bd9Sstevel@tonic-gate 				ret = EACCES;
826*7c478bd9Sstevel@tonic-gate 				goto out;
827*7c478bd9Sstevel@tonic-gate 
828*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_READONLY:
829*7c478bd9Sstevel@tonic-gate 				ret = EROFS;
830*7c478bd9Sstevel@tonic-gate 				goto out;
831*7c478bd9Sstevel@tonic-gate 
832*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_HANDLE_MISMATCH:
833*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_IN_USE:
834*7c478bd9Sstevel@tonic-gate 				bad_fail("scf_transaction_start", scf_error());
835*7c478bd9Sstevel@tonic-gate 			}
836*7c478bd9Sstevel@tonic-gate 		}
837*7c478bd9Sstevel@tonic-gate 
838*7c478bd9Sstevel@tonic-gate 		if ((r = tx_set_value(t, t_state, SCF_PROPERTY_STATE,
839*7c478bd9Sstevel@tonic-gate 		    SCF_TYPE_ASTRING, v_state)) != 0 ||
840*7c478bd9Sstevel@tonic-gate 		    (r = tx_set_value(t, t_state_next, SCF_PROPERTY_NEXT_STATE,
841*7c478bd9Sstevel@tonic-gate 		    SCF_TYPE_ASTRING, v_state_next)) != 0 ||
842*7c478bd9Sstevel@tonic-gate 		    (r = tx_set_value(t, t_aux, SCF_PROPERTY_AUX_STATE,
843*7c478bd9Sstevel@tonic-gate 		    SCF_TYPE_ASTRING, v_aux)) != 0 ||
844*7c478bd9Sstevel@tonic-gate 		    (r = tx_set_value(t, t_stime, SCF_PROPERTY_STATE_TIMESTAMP,
845*7c478bd9Sstevel@tonic-gate 		    SCF_TYPE_TIME, v_stime)) != 0) {
846*7c478bd9Sstevel@tonic-gate 			switch (r) {
847*7c478bd9Sstevel@tonic-gate 			case ECONNABORTED:
848*7c478bd9Sstevel@tonic-gate 				ret = ECONNABORTED;
849*7c478bd9Sstevel@tonic-gate 				goto out;
850*7c478bd9Sstevel@tonic-gate 
851*7c478bd9Sstevel@tonic-gate 			case ECANCELED:
852*7c478bd9Sstevel@tonic-gate 				scf_transaction_reset(t);
853*7c478bd9Sstevel@tonic-gate 				goto add_pg;
854*7c478bd9Sstevel@tonic-gate 
855*7c478bd9Sstevel@tonic-gate 			default:
856*7c478bd9Sstevel@tonic-gate 				bad_fail("tx_set_value", r);
857*7c478bd9Sstevel@tonic-gate 			}
858*7c478bd9Sstevel@tonic-gate 		}
859*7c478bd9Sstevel@tonic-gate 
860*7c478bd9Sstevel@tonic-gate 		ret = scf_transaction_commit(t);
861*7c478bd9Sstevel@tonic-gate 		if (ret == 1)
862*7c478bd9Sstevel@tonic-gate 			break;
863*7c478bd9Sstevel@tonic-gate 		if (ret == -1) {
864*7c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
865*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
866*7c478bd9Sstevel@tonic-gate 			default:
867*7c478bd9Sstevel@tonic-gate 				ret = ECONNABORTED;
868*7c478bd9Sstevel@tonic-gate 				goto out;
869*7c478bd9Sstevel@tonic-gate 
870*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
871*7c478bd9Sstevel@tonic-gate 				ret = EPERM;
872*7c478bd9Sstevel@tonic-gate 				goto out;
873*7c478bd9Sstevel@tonic-gate 
874*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_ACCESS:
875*7c478bd9Sstevel@tonic-gate 				ret = EACCES;
876*7c478bd9Sstevel@tonic-gate 				goto out;
877*7c478bd9Sstevel@tonic-gate 
878*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_READONLY:
879*7c478bd9Sstevel@tonic-gate 				ret = EROFS;
880*7c478bd9Sstevel@tonic-gate 				goto out;
881*7c478bd9Sstevel@tonic-gate 
882*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
883*7c478bd9Sstevel@tonic-gate 				bad_fail("scf_transaction_commit", scf_error());
884*7c478bd9Sstevel@tonic-gate 			}
885*7c478bd9Sstevel@tonic-gate 		}
886*7c478bd9Sstevel@tonic-gate 
887*7c478bd9Sstevel@tonic-gate 		scf_transaction_reset(t);
888*7c478bd9Sstevel@tonic-gate 		if (scf_pg_update(pg) == -1) {
889*7c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
890*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
891*7c478bd9Sstevel@tonic-gate 			default:
892*7c478bd9Sstevel@tonic-gate 				ret = ECONNABORTED;
893*7c478bd9Sstevel@tonic-gate 				goto out;
894*7c478bd9Sstevel@tonic-gate 
895*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
896*7c478bd9Sstevel@tonic-gate 				goto add_pg;
897*7c478bd9Sstevel@tonic-gate 			}
898*7c478bd9Sstevel@tonic-gate 		}
899*7c478bd9Sstevel@tonic-gate 	}
900*7c478bd9Sstevel@tonic-gate 
901*7c478bd9Sstevel@tonic-gate 	id->i_state = new_state;
902*7c478bd9Sstevel@tonic-gate 	id->i_next_state = new_state_next;
903*7c478bd9Sstevel@tonic-gate 	ret = 0;
904*7c478bd9Sstevel@tonic-gate 
905*7c478bd9Sstevel@tonic-gate out:
906*7c478bd9Sstevel@tonic-gate 	scf_transaction_destroy(t);
907*7c478bd9Sstevel@tonic-gate 	scf_entry_destroy(t_state);
908*7c478bd9Sstevel@tonic-gate 	scf_entry_destroy(t_state_next);
909*7c478bd9Sstevel@tonic-gate 	scf_entry_destroy(t_stime);
910*7c478bd9Sstevel@tonic-gate 	scf_entry_destroy(t_aux);
911*7c478bd9Sstevel@tonic-gate 	scf_value_destroy(v_state);
912*7c478bd9Sstevel@tonic-gate 	scf_value_destroy(v_state_next);
913*7c478bd9Sstevel@tonic-gate 	scf_value_destroy(v_stime);
914*7c478bd9Sstevel@tonic-gate 	scf_value_destroy(v_aux);
915*7c478bd9Sstevel@tonic-gate 	scf_pg_destroy(pg);
916*7c478bd9Sstevel@tonic-gate 	scf_instance_destroy(s_inst);
917*7c478bd9Sstevel@tonic-gate 
918*7c478bd9Sstevel@tonic-gate 	return (ret);
919*7c478bd9Sstevel@tonic-gate }
920*7c478bd9Sstevel@tonic-gate 
921*7c478bd9Sstevel@tonic-gate /*
922*7c478bd9Sstevel@tonic-gate  * Fails with
923*7c478bd9Sstevel@tonic-gate  *   EINVAL - type is invalid
924*7c478bd9Sstevel@tonic-gate  *   ENOMEM
925*7c478bd9Sstevel@tonic-gate  *   ECONNABORTED - repository connection broken
926*7c478bd9Sstevel@tonic-gate  *   EBADF - s_inst is not set
927*7c478bd9Sstevel@tonic-gate  *   ECANCELED - s_inst is deleted
928*7c478bd9Sstevel@tonic-gate  *   EPERM - permission denied
929*7c478bd9Sstevel@tonic-gate  *   EACCES - backend access denied
930*7c478bd9Sstevel@tonic-gate  *   EROFS - backend readonly
931*7c478bd9Sstevel@tonic-gate  */
932*7c478bd9Sstevel@tonic-gate int
933*7c478bd9Sstevel@tonic-gate restarter_remove_contract(scf_instance_t *s_inst, ctid_t contract_id,
934*7c478bd9Sstevel@tonic-gate     restarter_contract_type_t type)
935*7c478bd9Sstevel@tonic-gate {
936*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h;
937*7c478bd9Sstevel@tonic-gate 	scf_transaction_t *t = NULL;
938*7c478bd9Sstevel@tonic-gate 	scf_transaction_entry_t *t_cid = NULL;
939*7c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg = NULL;
940*7c478bd9Sstevel@tonic-gate 	scf_property_t *prop = NULL;
941*7c478bd9Sstevel@tonic-gate 	scf_value_t *val;
942*7c478bd9Sstevel@tonic-gate 	scf_iter_t *iter = NULL;
943*7c478bd9Sstevel@tonic-gate 	const char *pname;
944*7c478bd9Sstevel@tonic-gate 	int ret = 0, primary;
945*7c478bd9Sstevel@tonic-gate 	uint64_t c;
946*7c478bd9Sstevel@tonic-gate 
947*7c478bd9Sstevel@tonic-gate 	switch (type) {
948*7c478bd9Sstevel@tonic-gate 	case RESTARTER_CONTRACT_PRIMARY:
949*7c478bd9Sstevel@tonic-gate 		primary = 1;
950*7c478bd9Sstevel@tonic-gate 		break;
951*7c478bd9Sstevel@tonic-gate 	case RESTARTER_CONTRACT_TRANSIENT:
952*7c478bd9Sstevel@tonic-gate 		primary = 0;
953*7c478bd9Sstevel@tonic-gate 		break;
954*7c478bd9Sstevel@tonic-gate 	default:
955*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
956*7c478bd9Sstevel@tonic-gate 	}
957*7c478bd9Sstevel@tonic-gate 
958*7c478bd9Sstevel@tonic-gate 	h = scf_instance_handle(s_inst);
959*7c478bd9Sstevel@tonic-gate 
960*7c478bd9Sstevel@tonic-gate 	pg = scf_pg_create(h);
961*7c478bd9Sstevel@tonic-gate 	prop = scf_property_create(h);
962*7c478bd9Sstevel@tonic-gate 	iter = scf_iter_create(h);
963*7c478bd9Sstevel@tonic-gate 	t = scf_transaction_create(h);
964*7c478bd9Sstevel@tonic-gate 
965*7c478bd9Sstevel@tonic-gate 	if (pg == NULL || prop == NULL || iter == NULL || t == NULL) {
966*7c478bd9Sstevel@tonic-gate 		ret = ENOMEM;
967*7c478bd9Sstevel@tonic-gate 		goto remove_contract_cleanup;
968*7c478bd9Sstevel@tonic-gate 	}
969*7c478bd9Sstevel@tonic-gate 
970*7c478bd9Sstevel@tonic-gate add:
971*7c478bd9Sstevel@tonic-gate 	scf_transaction_destroy_children(t);
972*7c478bd9Sstevel@tonic-gate 	ret = instance_get_or_add_pg(s_inst, SCF_PG_RESTARTER,
973*7c478bd9Sstevel@tonic-gate 	    SCF_PG_RESTARTER_TYPE, SCF_PG_RESTARTER_FLAGS, pg);
974*7c478bd9Sstevel@tonic-gate 	if (ret != 0)
975*7c478bd9Sstevel@tonic-gate 		goto remove_contract_cleanup;
976*7c478bd9Sstevel@tonic-gate 
977*7c478bd9Sstevel@tonic-gate 	pname = primary? SCF_PROPERTY_CONTRACT :
978*7c478bd9Sstevel@tonic-gate 	    SCF_PROPERTY_TRANSIENT_CONTRACT;
979*7c478bd9Sstevel@tonic-gate 
980*7c478bd9Sstevel@tonic-gate 	for (;;) {
981*7c478bd9Sstevel@tonic-gate 		if (scf_transaction_start(t, pg) != 0) {
982*7c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
983*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
984*7c478bd9Sstevel@tonic-gate 			default:
985*7c478bd9Sstevel@tonic-gate 				ret = ECONNABORTED;
986*7c478bd9Sstevel@tonic-gate 				goto remove_contract_cleanup;
987*7c478bd9Sstevel@tonic-gate 
988*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_DELETED:
989*7c478bd9Sstevel@tonic-gate 				goto add;
990*7c478bd9Sstevel@tonic-gate 
991*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
992*7c478bd9Sstevel@tonic-gate 				ret = EPERM;
993*7c478bd9Sstevel@tonic-gate 				goto remove_contract_cleanup;
994*7c478bd9Sstevel@tonic-gate 
995*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_ACCESS:
996*7c478bd9Sstevel@tonic-gate 				ret = EACCES;
997*7c478bd9Sstevel@tonic-gate 				goto remove_contract_cleanup;
998*7c478bd9Sstevel@tonic-gate 
999*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_READONLY:
1000*7c478bd9Sstevel@tonic-gate 				ret = EROFS;
1001*7c478bd9Sstevel@tonic-gate 				goto remove_contract_cleanup;
1002*7c478bd9Sstevel@tonic-gate 
1003*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_HANDLE_MISMATCH:
1004*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_IN_USE:
1005*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
1006*7c478bd9Sstevel@tonic-gate 				bad_fail("scf_transaction_start", scf_error());
1007*7c478bd9Sstevel@tonic-gate 			}
1008*7c478bd9Sstevel@tonic-gate 		}
1009*7c478bd9Sstevel@tonic-gate 
1010*7c478bd9Sstevel@tonic-gate 		t_cid = scf_entry_create(h);
1011*7c478bd9Sstevel@tonic-gate 
1012*7c478bd9Sstevel@tonic-gate 		if (scf_pg_get_property(pg, pname, prop) == 0) {
1013*7c478bd9Sstevel@tonic-gate replace:
1014*7c478bd9Sstevel@tonic-gate 			if (scf_transaction_property_change_type(t, t_cid,
1015*7c478bd9Sstevel@tonic-gate 			    pname, SCF_TYPE_COUNT) != 0) {
1016*7c478bd9Sstevel@tonic-gate 				switch (scf_error()) {
1017*7c478bd9Sstevel@tonic-gate 				case SCF_ERROR_CONNECTION_BROKEN:
1018*7c478bd9Sstevel@tonic-gate 				default:
1019*7c478bd9Sstevel@tonic-gate 					ret = ECONNABORTED;
1020*7c478bd9Sstevel@tonic-gate 					goto remove_contract_cleanup;
1021*7c478bd9Sstevel@tonic-gate 
1022*7c478bd9Sstevel@tonic-gate 				case SCF_ERROR_DELETED:
1023*7c478bd9Sstevel@tonic-gate 					scf_entry_destroy(t_cid);
1024*7c478bd9Sstevel@tonic-gate 					goto add;
1025*7c478bd9Sstevel@tonic-gate 
1026*7c478bd9Sstevel@tonic-gate 				case SCF_ERROR_NOT_FOUND:
1027*7c478bd9Sstevel@tonic-gate 					goto new;
1028*7c478bd9Sstevel@tonic-gate 
1029*7c478bd9Sstevel@tonic-gate 				case SCF_ERROR_HANDLE_MISMATCH:
1030*7c478bd9Sstevel@tonic-gate 				case SCF_ERROR_INVALID_ARGUMENT:
1031*7c478bd9Sstevel@tonic-gate 				case SCF_ERROR_IN_USE:
1032*7c478bd9Sstevel@tonic-gate 				case SCF_ERROR_NOT_SET:
1033*7c478bd9Sstevel@tonic-gate 					bad_fail(
1034*7c478bd9Sstevel@tonic-gate 					"scf_transaction_property_changetype",
1035*7c478bd9Sstevel@tonic-gate 					    scf_error());
1036*7c478bd9Sstevel@tonic-gate 				}
1037*7c478bd9Sstevel@tonic-gate 			}
1038*7c478bd9Sstevel@tonic-gate 
1039*7c478bd9Sstevel@tonic-gate 			if (scf_property_is_type(prop, SCF_TYPE_COUNT) == 0) {
1040*7c478bd9Sstevel@tonic-gate 				if (scf_iter_property_values(iter, prop) != 0) {
1041*7c478bd9Sstevel@tonic-gate 					switch (scf_error()) {
1042*7c478bd9Sstevel@tonic-gate 					case SCF_ERROR_CONNECTION_BROKEN:
1043*7c478bd9Sstevel@tonic-gate 					default:
1044*7c478bd9Sstevel@tonic-gate 						ret = ECONNABORTED;
1045*7c478bd9Sstevel@tonic-gate 						goto remove_contract_cleanup;
1046*7c478bd9Sstevel@tonic-gate 
1047*7c478bd9Sstevel@tonic-gate 					case SCF_ERROR_NOT_SET:
1048*7c478bd9Sstevel@tonic-gate 					case SCF_ERROR_HANDLE_MISMATCH:
1049*7c478bd9Sstevel@tonic-gate 						bad_fail(
1050*7c478bd9Sstevel@tonic-gate 						    "scf_iter_property_values",
1051*7c478bd9Sstevel@tonic-gate 						    scf_error());
1052*7c478bd9Sstevel@tonic-gate 					}
1053*7c478bd9Sstevel@tonic-gate 				}
1054*7c478bd9Sstevel@tonic-gate 
1055*7c478bd9Sstevel@tonic-gate next_val:
1056*7c478bd9Sstevel@tonic-gate 				val = scf_value_create(h);
1057*7c478bd9Sstevel@tonic-gate 				if (val == NULL) {
1058*7c478bd9Sstevel@tonic-gate 					assert(scf_error() ==
1059*7c478bd9Sstevel@tonic-gate 					    SCF_ERROR_NO_MEMORY);
1060*7c478bd9Sstevel@tonic-gate 					ret = ENOMEM;
1061*7c478bd9Sstevel@tonic-gate 					goto remove_contract_cleanup;
1062*7c478bd9Sstevel@tonic-gate 				}
1063*7c478bd9Sstevel@tonic-gate 
1064*7c478bd9Sstevel@tonic-gate 				ret = scf_iter_next_value(iter, val);
1065*7c478bd9Sstevel@tonic-gate 				if (ret == -1) {
1066*7c478bd9Sstevel@tonic-gate 					switch (scf_error()) {
1067*7c478bd9Sstevel@tonic-gate 					case SCF_ERROR_CONNECTION_BROKEN:
1068*7c478bd9Sstevel@tonic-gate 						ret = ECONNABORTED;
1069*7c478bd9Sstevel@tonic-gate 						goto remove_contract_cleanup;
1070*7c478bd9Sstevel@tonic-gate 
1071*7c478bd9Sstevel@tonic-gate 					case SCF_ERROR_DELETED:
1072*7c478bd9Sstevel@tonic-gate 						scf_value_destroy(val);
1073*7c478bd9Sstevel@tonic-gate 						goto add;
1074*7c478bd9Sstevel@tonic-gate 
1075*7c478bd9Sstevel@tonic-gate 					case SCF_ERROR_HANDLE_MISMATCH:
1076*7c478bd9Sstevel@tonic-gate 					case SCF_ERROR_INVALID_ARGUMENT:
1077*7c478bd9Sstevel@tonic-gate 					default:
1078*7c478bd9Sstevel@tonic-gate 						bad_fail("scf_iter_next_value",
1079*7c478bd9Sstevel@tonic-gate 						    scf_error());
1080*7c478bd9Sstevel@tonic-gate 					}
1081*7c478bd9Sstevel@tonic-gate 				}
1082*7c478bd9Sstevel@tonic-gate 
1083*7c478bd9Sstevel@tonic-gate 				if (ret == 1) {
1084*7c478bd9Sstevel@tonic-gate 					ret = scf_value_get_count(val, &c);
1085*7c478bd9Sstevel@tonic-gate 					assert(ret == 0);
1086*7c478bd9Sstevel@tonic-gate 
1087*7c478bd9Sstevel@tonic-gate 					if (c != contract_id) {
1088*7c478bd9Sstevel@tonic-gate 						ret = scf_entry_add_value(t_cid,
1089*7c478bd9Sstevel@tonic-gate 						    val);
1090*7c478bd9Sstevel@tonic-gate 						assert(ret == 0);
1091*7c478bd9Sstevel@tonic-gate 					} else {
1092*7c478bd9Sstevel@tonic-gate 						scf_value_destroy(val);
1093*7c478bd9Sstevel@tonic-gate 					}
1094*7c478bd9Sstevel@tonic-gate 
1095*7c478bd9Sstevel@tonic-gate 					goto next_val;
1096*7c478bd9Sstevel@tonic-gate 				}
1097*7c478bd9Sstevel@tonic-gate 
1098*7c478bd9Sstevel@tonic-gate 				scf_value_destroy(val);
1099*7c478bd9Sstevel@tonic-gate 			} else {
1100*7c478bd9Sstevel@tonic-gate 				switch (scf_error()) {
1101*7c478bd9Sstevel@tonic-gate 				case SCF_ERROR_CONNECTION_BROKEN:
1102*7c478bd9Sstevel@tonic-gate 				default:
1103*7c478bd9Sstevel@tonic-gate 					ret = ECONNABORTED;
1104*7c478bd9Sstevel@tonic-gate 					goto remove_contract_cleanup;
1105*7c478bd9Sstevel@tonic-gate 
1106*7c478bd9Sstevel@tonic-gate 				case SCF_ERROR_TYPE_MISMATCH:
1107*7c478bd9Sstevel@tonic-gate 					break;
1108*7c478bd9Sstevel@tonic-gate 
1109*7c478bd9Sstevel@tonic-gate 				case SCF_ERROR_INVALID_ARGUMENT:
1110*7c478bd9Sstevel@tonic-gate 				case SCF_ERROR_NOT_SET:
1111*7c478bd9Sstevel@tonic-gate 					bad_fail("scf_property_is_type",
1112*7c478bd9Sstevel@tonic-gate 					    scf_error());
1113*7c478bd9Sstevel@tonic-gate 				}
1114*7c478bd9Sstevel@tonic-gate 			}
1115*7c478bd9Sstevel@tonic-gate 		} else {
1116*7c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
1117*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
1118*7c478bd9Sstevel@tonic-gate 			default:
1119*7c478bd9Sstevel@tonic-gate 				ret = ECONNABORTED;
1120*7c478bd9Sstevel@tonic-gate 				goto remove_contract_cleanup;
1121*7c478bd9Sstevel@tonic-gate 
1122*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_DELETED:
1123*7c478bd9Sstevel@tonic-gate 				scf_entry_destroy(t_cid);
1124*7c478bd9Sstevel@tonic-gate 				goto add;
1125*7c478bd9Sstevel@tonic-gate 
1126*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_FOUND:
1127*7c478bd9Sstevel@tonic-gate 				break;
1128*7c478bd9Sstevel@tonic-gate 
1129*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_HANDLE_MISMATCH:
1130*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_INVALID_ARGUMENT:
1131*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
1132*7c478bd9Sstevel@tonic-gate 				bad_fail("scf_pg_get_property", scf_error());
1133*7c478bd9Sstevel@tonic-gate 			}
1134*7c478bd9Sstevel@tonic-gate 
1135*7c478bd9Sstevel@tonic-gate new:
1136*7c478bd9Sstevel@tonic-gate 			if (scf_transaction_property_new(t, t_cid, pname,
1137*7c478bd9Sstevel@tonic-gate 			    SCF_TYPE_COUNT) != 0) {
1138*7c478bd9Sstevel@tonic-gate 				switch (scf_error()) {
1139*7c478bd9Sstevel@tonic-gate 				case SCF_ERROR_CONNECTION_BROKEN:
1140*7c478bd9Sstevel@tonic-gate 				default:
1141*7c478bd9Sstevel@tonic-gate 					ret = ECONNABORTED;
1142*7c478bd9Sstevel@tonic-gate 					goto remove_contract_cleanup;
1143*7c478bd9Sstevel@tonic-gate 
1144*7c478bd9Sstevel@tonic-gate 				case SCF_ERROR_DELETED:
1145*7c478bd9Sstevel@tonic-gate 					scf_entry_destroy(t_cid);
1146*7c478bd9Sstevel@tonic-gate 					goto add;
1147*7c478bd9Sstevel@tonic-gate 
1148*7c478bd9Sstevel@tonic-gate 				case SCF_ERROR_EXISTS:
1149*7c478bd9Sstevel@tonic-gate 					goto replace;
1150*7c478bd9Sstevel@tonic-gate 
1151*7c478bd9Sstevel@tonic-gate 				case SCF_ERROR_HANDLE_MISMATCH:
1152*7c478bd9Sstevel@tonic-gate 				case SCF_ERROR_INVALID_ARGUMENT:
1153*7c478bd9Sstevel@tonic-gate 				case SCF_ERROR_NOT_SET:
1154*7c478bd9Sstevel@tonic-gate 					bad_fail("scf_transaction_property_new",
1155*7c478bd9Sstevel@tonic-gate 					    scf_error());
1156*7c478bd9Sstevel@tonic-gate 				}
1157*7c478bd9Sstevel@tonic-gate 			}
1158*7c478bd9Sstevel@tonic-gate 		}
1159*7c478bd9Sstevel@tonic-gate 
1160*7c478bd9Sstevel@tonic-gate 		ret = scf_transaction_commit(t);
1161*7c478bd9Sstevel@tonic-gate 		if (ret == -1) {
1162*7c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
1163*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
1164*7c478bd9Sstevel@tonic-gate 			default:
1165*7c478bd9Sstevel@tonic-gate 				ret = ECONNABORTED;
1166*7c478bd9Sstevel@tonic-gate 				goto remove_contract_cleanup;
1167*7c478bd9Sstevel@tonic-gate 
1168*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_DELETED:
1169*7c478bd9Sstevel@tonic-gate 				goto add;
1170*7c478bd9Sstevel@tonic-gate 
1171*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
1172*7c478bd9Sstevel@tonic-gate 				ret = EPERM;
1173*7c478bd9Sstevel@tonic-gate 				goto remove_contract_cleanup;
1174*7c478bd9Sstevel@tonic-gate 
1175*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_ACCESS:
1176*7c478bd9Sstevel@tonic-gate 				ret = EACCES;
1177*7c478bd9Sstevel@tonic-gate 				goto remove_contract_cleanup;
1178*7c478bd9Sstevel@tonic-gate 
1179*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_READONLY:
1180*7c478bd9Sstevel@tonic-gate 				ret = EROFS;
1181*7c478bd9Sstevel@tonic-gate 				goto remove_contract_cleanup;
1182*7c478bd9Sstevel@tonic-gate 
1183*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
1184*7c478bd9Sstevel@tonic-gate 				bad_fail("scf_transaction_commit", scf_error());
1185*7c478bd9Sstevel@tonic-gate 			}
1186*7c478bd9Sstevel@tonic-gate 		}
1187*7c478bd9Sstevel@tonic-gate 		if (ret == 1) {
1188*7c478bd9Sstevel@tonic-gate 			ret = 0;
1189*7c478bd9Sstevel@tonic-gate 			break;
1190*7c478bd9Sstevel@tonic-gate 		}
1191*7c478bd9Sstevel@tonic-gate 
1192*7c478bd9Sstevel@tonic-gate 		scf_transaction_destroy_children(t);
1193*7c478bd9Sstevel@tonic-gate 		if (scf_pg_update(pg) == -1) {
1194*7c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
1195*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
1196*7c478bd9Sstevel@tonic-gate 			default:
1197*7c478bd9Sstevel@tonic-gate 				ret = ECONNABORTED;
1198*7c478bd9Sstevel@tonic-gate 				goto remove_contract_cleanup;
1199*7c478bd9Sstevel@tonic-gate 
1200*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_DELETED:
1201*7c478bd9Sstevel@tonic-gate 				goto add;
1202*7c478bd9Sstevel@tonic-gate 
1203*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
1204*7c478bd9Sstevel@tonic-gate 				bad_fail("scf_pg_update", scf_error());
1205*7c478bd9Sstevel@tonic-gate 			}
1206*7c478bd9Sstevel@tonic-gate 		}
1207*7c478bd9Sstevel@tonic-gate 	}
1208*7c478bd9Sstevel@tonic-gate 
1209*7c478bd9Sstevel@tonic-gate remove_contract_cleanup:
1210*7c478bd9Sstevel@tonic-gate 	scf_transaction_destroy_children(t);
1211*7c478bd9Sstevel@tonic-gate 	scf_transaction_destroy(t);
1212*7c478bd9Sstevel@tonic-gate 	scf_iter_destroy(iter);
1213*7c478bd9Sstevel@tonic-gate 	scf_property_destroy(prop);
1214*7c478bd9Sstevel@tonic-gate 	scf_pg_destroy(pg);
1215*7c478bd9Sstevel@tonic-gate 
1216*7c478bd9Sstevel@tonic-gate 	return (ret);
1217*7c478bd9Sstevel@tonic-gate }
1218*7c478bd9Sstevel@tonic-gate 
1219*7c478bd9Sstevel@tonic-gate /*
1220*7c478bd9Sstevel@tonic-gate  * Fails with
1221*7c478bd9Sstevel@tonic-gate  *   EINVAL - type is invalid
1222*7c478bd9Sstevel@tonic-gate  *   ENOMEM
1223*7c478bd9Sstevel@tonic-gate  *   ECONNABORTED - repository disconnection
1224*7c478bd9Sstevel@tonic-gate  *   EBADF - s_inst is not set
1225*7c478bd9Sstevel@tonic-gate  *   ECANCELED - s_inst is deleted
1226*7c478bd9Sstevel@tonic-gate  *   EPERM
1227*7c478bd9Sstevel@tonic-gate  *   EACCES
1228*7c478bd9Sstevel@tonic-gate  *   EROFS
1229*7c478bd9Sstevel@tonic-gate  */
1230*7c478bd9Sstevel@tonic-gate int
1231*7c478bd9Sstevel@tonic-gate restarter_store_contract(scf_instance_t *s_inst, ctid_t contract_id,
1232*7c478bd9Sstevel@tonic-gate     restarter_contract_type_t type)
1233*7c478bd9Sstevel@tonic-gate {
1234*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h;
1235*7c478bd9Sstevel@tonic-gate 	scf_transaction_t *t = NULL;
1236*7c478bd9Sstevel@tonic-gate 	scf_transaction_entry_t *t_cid = NULL;
1237*7c478bd9Sstevel@tonic-gate 	scf_value_t *val;
1238*7c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg = NULL;
1239*7c478bd9Sstevel@tonic-gate 	scf_property_t *prop = NULL;
1240*7c478bd9Sstevel@tonic-gate 	scf_iter_t *iter = NULL;
1241*7c478bd9Sstevel@tonic-gate 	const char *pname;
1242*7c478bd9Sstevel@tonic-gate 	int ret = 0, primary;
1243*7c478bd9Sstevel@tonic-gate 
1244*7c478bd9Sstevel@tonic-gate 	if (type == RESTARTER_CONTRACT_PRIMARY)
1245*7c478bd9Sstevel@tonic-gate 		primary = 1;
1246*7c478bd9Sstevel@tonic-gate 	else if (type == RESTARTER_CONTRACT_TRANSIENT)
1247*7c478bd9Sstevel@tonic-gate 		primary = 0;
1248*7c478bd9Sstevel@tonic-gate 	else
1249*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
1250*7c478bd9Sstevel@tonic-gate 
1251*7c478bd9Sstevel@tonic-gate 	h = scf_instance_handle(s_inst);
1252*7c478bd9Sstevel@tonic-gate 
1253*7c478bd9Sstevel@tonic-gate 	pg = scf_pg_create(h);
1254*7c478bd9Sstevel@tonic-gate 	prop = scf_property_create(h);
1255*7c478bd9Sstevel@tonic-gate 	iter = scf_iter_create(h);
1256*7c478bd9Sstevel@tonic-gate 	t = scf_transaction_create(h);
1257*7c478bd9Sstevel@tonic-gate 
1258*7c478bd9Sstevel@tonic-gate 	if (pg == NULL || prop == NULL || iter == NULL || t == NULL) {
1259*7c478bd9Sstevel@tonic-gate 		ret = ENOMEM;
1260*7c478bd9Sstevel@tonic-gate 		goto out;
1261*7c478bd9Sstevel@tonic-gate 	}
1262*7c478bd9Sstevel@tonic-gate 
1263*7c478bd9Sstevel@tonic-gate add:
1264*7c478bd9Sstevel@tonic-gate 	scf_transaction_destroy_children(t);
1265*7c478bd9Sstevel@tonic-gate 	ret = instance_get_or_add_pg(s_inst, SCF_PG_RESTARTER,
1266*7c478bd9Sstevel@tonic-gate 	    SCF_PG_RESTARTER_TYPE, SCF_PG_RESTARTER_FLAGS, pg);
1267*7c478bd9Sstevel@tonic-gate 	if (ret != 0)
1268*7c478bd9Sstevel@tonic-gate 		goto out;
1269*7c478bd9Sstevel@tonic-gate 
1270*7c478bd9Sstevel@tonic-gate 	pname = primary ? SCF_PROPERTY_CONTRACT :
1271*7c478bd9Sstevel@tonic-gate 	    SCF_PROPERTY_TRANSIENT_CONTRACT;
1272*7c478bd9Sstevel@tonic-gate 
1273*7c478bd9Sstevel@tonic-gate 	for (;;) {
1274*7c478bd9Sstevel@tonic-gate 		if (scf_transaction_start(t, pg) != 0) {
1275*7c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
1276*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
1277*7c478bd9Sstevel@tonic-gate 			default:
1278*7c478bd9Sstevel@tonic-gate 				ret = ECONNABORTED;
1279*7c478bd9Sstevel@tonic-gate 				goto out;
1280*7c478bd9Sstevel@tonic-gate 
1281*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_DELETED:
1282*7c478bd9Sstevel@tonic-gate 				goto add;
1283*7c478bd9Sstevel@tonic-gate 
1284*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
1285*7c478bd9Sstevel@tonic-gate 				ret = EPERM;
1286*7c478bd9Sstevel@tonic-gate 				goto out;
1287*7c478bd9Sstevel@tonic-gate 
1288*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_ACCESS:
1289*7c478bd9Sstevel@tonic-gate 				ret = EACCES;
1290*7c478bd9Sstevel@tonic-gate 				goto out;
1291*7c478bd9Sstevel@tonic-gate 
1292*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_READONLY:
1293*7c478bd9Sstevel@tonic-gate 				ret = EROFS;
1294*7c478bd9Sstevel@tonic-gate 				goto out;
1295*7c478bd9Sstevel@tonic-gate 
1296*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_HANDLE_MISMATCH:
1297*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_IN_USE:
1298*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
1299*7c478bd9Sstevel@tonic-gate 				bad_fail("scf_transaction_start", scf_error());
1300*7c478bd9Sstevel@tonic-gate 			}
1301*7c478bd9Sstevel@tonic-gate 		}
1302*7c478bd9Sstevel@tonic-gate 
1303*7c478bd9Sstevel@tonic-gate 		t_cid = scf_entry_create(h);
1304*7c478bd9Sstevel@tonic-gate 		if (t_cid == NULL) {
1305*7c478bd9Sstevel@tonic-gate 			ret = ENOMEM;
1306*7c478bd9Sstevel@tonic-gate 			goto out;
1307*7c478bd9Sstevel@tonic-gate 		}
1308*7c478bd9Sstevel@tonic-gate 
1309*7c478bd9Sstevel@tonic-gate 		if (scf_pg_get_property(pg, pname, prop) == 0) {
1310*7c478bd9Sstevel@tonic-gate replace:
1311*7c478bd9Sstevel@tonic-gate 			if (scf_transaction_property_change_type(t, t_cid,
1312*7c478bd9Sstevel@tonic-gate 			    pname, SCF_TYPE_COUNT) != 0) {
1313*7c478bd9Sstevel@tonic-gate 				switch (scf_error()) {
1314*7c478bd9Sstevel@tonic-gate 				case SCF_ERROR_CONNECTION_BROKEN:
1315*7c478bd9Sstevel@tonic-gate 				default:
1316*7c478bd9Sstevel@tonic-gate 					ret = ECONNABORTED;
1317*7c478bd9Sstevel@tonic-gate 					goto out;
1318*7c478bd9Sstevel@tonic-gate 
1319*7c478bd9Sstevel@tonic-gate 				case SCF_ERROR_DELETED:
1320*7c478bd9Sstevel@tonic-gate 					scf_entry_destroy(t_cid);
1321*7c478bd9Sstevel@tonic-gate 					goto add;
1322*7c478bd9Sstevel@tonic-gate 
1323*7c478bd9Sstevel@tonic-gate 				case SCF_ERROR_NOT_FOUND:
1324*7c478bd9Sstevel@tonic-gate 					goto new;
1325*7c478bd9Sstevel@tonic-gate 
1326*7c478bd9Sstevel@tonic-gate 				case SCF_ERROR_HANDLE_MISMATCH:
1327*7c478bd9Sstevel@tonic-gate 				case SCF_ERROR_INVALID_ARGUMENT:
1328*7c478bd9Sstevel@tonic-gate 				case SCF_ERROR_IN_USE:
1329*7c478bd9Sstevel@tonic-gate 				case SCF_ERROR_NOT_SET:
1330*7c478bd9Sstevel@tonic-gate 					bad_fail(
1331*7c478bd9Sstevel@tonic-gate 					"scf_transaction_propert_change_type",
1332*7c478bd9Sstevel@tonic-gate 					    scf_error());
1333*7c478bd9Sstevel@tonic-gate 				}
1334*7c478bd9Sstevel@tonic-gate 			}
1335*7c478bd9Sstevel@tonic-gate 
1336*7c478bd9Sstevel@tonic-gate 			if (scf_property_is_type(prop, SCF_TYPE_COUNT) == 0) {
1337*7c478bd9Sstevel@tonic-gate 				if (scf_iter_property_values(iter, prop) != 0) {
1338*7c478bd9Sstevel@tonic-gate 					switch (scf_error()) {
1339*7c478bd9Sstevel@tonic-gate 					case SCF_ERROR_CONNECTION_BROKEN:
1340*7c478bd9Sstevel@tonic-gate 					default:
1341*7c478bd9Sstevel@tonic-gate 						ret = ECONNABORTED;
1342*7c478bd9Sstevel@tonic-gate 						goto out;
1343*7c478bd9Sstevel@tonic-gate 
1344*7c478bd9Sstevel@tonic-gate 					case SCF_ERROR_NOT_SET:
1345*7c478bd9Sstevel@tonic-gate 					case SCF_ERROR_HANDLE_MISMATCH:
1346*7c478bd9Sstevel@tonic-gate 						bad_fail(
1347*7c478bd9Sstevel@tonic-gate 						    "scf_iter_property_values",
1348*7c478bd9Sstevel@tonic-gate 						    scf_error());
1349*7c478bd9Sstevel@tonic-gate 					}
1350*7c478bd9Sstevel@tonic-gate 				}
1351*7c478bd9Sstevel@tonic-gate 
1352*7c478bd9Sstevel@tonic-gate next_val:
1353*7c478bd9Sstevel@tonic-gate 				val = scf_value_create(h);
1354*7c478bd9Sstevel@tonic-gate 				if (val == NULL) {
1355*7c478bd9Sstevel@tonic-gate 					assert(scf_error() ==
1356*7c478bd9Sstevel@tonic-gate 					    SCF_ERROR_NO_MEMORY);
1357*7c478bd9Sstevel@tonic-gate 					ret = ENOMEM;
1358*7c478bd9Sstevel@tonic-gate 					goto out;
1359*7c478bd9Sstevel@tonic-gate 				}
1360*7c478bd9Sstevel@tonic-gate 
1361*7c478bd9Sstevel@tonic-gate 				ret = scf_iter_next_value(iter, val);
1362*7c478bd9Sstevel@tonic-gate 				if (ret == -1) {
1363*7c478bd9Sstevel@tonic-gate 					switch (scf_error()) {
1364*7c478bd9Sstevel@tonic-gate 					case SCF_ERROR_CONNECTION_BROKEN:
1365*7c478bd9Sstevel@tonic-gate 					default:
1366*7c478bd9Sstevel@tonic-gate 						ret = ECONNABORTED;
1367*7c478bd9Sstevel@tonic-gate 						goto out;
1368*7c478bd9Sstevel@tonic-gate 
1369*7c478bd9Sstevel@tonic-gate 					case SCF_ERROR_DELETED:
1370*7c478bd9Sstevel@tonic-gate 						scf_value_destroy(val);
1371*7c478bd9Sstevel@tonic-gate 						goto add;
1372*7c478bd9Sstevel@tonic-gate 
1373*7c478bd9Sstevel@tonic-gate 					case SCF_ERROR_HANDLE_MISMATCH:
1374*7c478bd9Sstevel@tonic-gate 					case SCF_ERROR_INVALID_ARGUMENT:
1375*7c478bd9Sstevel@tonic-gate 						bad_fail(
1376*7c478bd9Sstevel@tonic-gate 						    "scf_iter_next_value",
1377*7c478bd9Sstevel@tonic-gate 						    scf_error());
1378*7c478bd9Sstevel@tonic-gate 					}
1379*7c478bd9Sstevel@tonic-gate 				}
1380*7c478bd9Sstevel@tonic-gate 
1381*7c478bd9Sstevel@tonic-gate 				if (ret == 1) {
1382*7c478bd9Sstevel@tonic-gate 					ret = scf_entry_add_value(t_cid, val);
1383*7c478bd9Sstevel@tonic-gate 					assert(ret == 0);
1384*7c478bd9Sstevel@tonic-gate 
1385*7c478bd9Sstevel@tonic-gate 					goto next_val;
1386*7c478bd9Sstevel@tonic-gate 				}
1387*7c478bd9Sstevel@tonic-gate 
1388*7c478bd9Sstevel@tonic-gate 				scf_value_destroy(val);
1389*7c478bd9Sstevel@tonic-gate 			} else {
1390*7c478bd9Sstevel@tonic-gate 				switch (scf_error()) {
1391*7c478bd9Sstevel@tonic-gate 				case SCF_ERROR_CONNECTION_BROKEN:
1392*7c478bd9Sstevel@tonic-gate 				default:
1393*7c478bd9Sstevel@tonic-gate 					ret = ECONNABORTED;
1394*7c478bd9Sstevel@tonic-gate 					goto out;
1395*7c478bd9Sstevel@tonic-gate 
1396*7c478bd9Sstevel@tonic-gate 				case SCF_ERROR_TYPE_MISMATCH:
1397*7c478bd9Sstevel@tonic-gate 					break;
1398*7c478bd9Sstevel@tonic-gate 
1399*7c478bd9Sstevel@tonic-gate 				case SCF_ERROR_INVALID_ARGUMENT:
1400*7c478bd9Sstevel@tonic-gate 				case SCF_ERROR_NOT_SET:
1401*7c478bd9Sstevel@tonic-gate 					bad_fail("scf_property_is_type",
1402*7c478bd9Sstevel@tonic-gate 					    scf_error());
1403*7c478bd9Sstevel@tonic-gate 				}
1404*7c478bd9Sstevel@tonic-gate 			}
1405*7c478bd9Sstevel@tonic-gate 		} else {
1406*7c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
1407*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
1408*7c478bd9Sstevel@tonic-gate 			default:
1409*7c478bd9Sstevel@tonic-gate 				ret = ECONNABORTED;
1410*7c478bd9Sstevel@tonic-gate 				goto out;
1411*7c478bd9Sstevel@tonic-gate 
1412*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_DELETED:
1413*7c478bd9Sstevel@tonic-gate 				scf_entry_destroy(t_cid);
1414*7c478bd9Sstevel@tonic-gate 				goto add;
1415*7c478bd9Sstevel@tonic-gate 
1416*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_FOUND:
1417*7c478bd9Sstevel@tonic-gate 				break;
1418*7c478bd9Sstevel@tonic-gate 
1419*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_HANDLE_MISMATCH:
1420*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_INVALID_ARGUMENT:
1421*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
1422*7c478bd9Sstevel@tonic-gate 				bad_fail("scf_pg_get_property", scf_error());
1423*7c478bd9Sstevel@tonic-gate 			}
1424*7c478bd9Sstevel@tonic-gate 
1425*7c478bd9Sstevel@tonic-gate new:
1426*7c478bd9Sstevel@tonic-gate 			if (scf_transaction_property_new(t, t_cid, pname,
1427*7c478bd9Sstevel@tonic-gate 			    SCF_TYPE_COUNT) != 0) {
1428*7c478bd9Sstevel@tonic-gate 				switch (scf_error()) {
1429*7c478bd9Sstevel@tonic-gate 				case SCF_ERROR_CONNECTION_BROKEN:
1430*7c478bd9Sstevel@tonic-gate 				default:
1431*7c478bd9Sstevel@tonic-gate 					ret = ECONNABORTED;
1432*7c478bd9Sstevel@tonic-gate 					goto out;
1433*7c478bd9Sstevel@tonic-gate 
1434*7c478bd9Sstevel@tonic-gate 				case SCF_ERROR_DELETED:
1435*7c478bd9Sstevel@tonic-gate 					scf_entry_destroy(t_cid);
1436*7c478bd9Sstevel@tonic-gate 					goto add;
1437*7c478bd9Sstevel@tonic-gate 
1438*7c478bd9Sstevel@tonic-gate 				case SCF_ERROR_EXISTS:
1439*7c478bd9Sstevel@tonic-gate 					goto replace;
1440*7c478bd9Sstevel@tonic-gate 
1441*7c478bd9Sstevel@tonic-gate 				case SCF_ERROR_HANDLE_MISMATCH:
1442*7c478bd9Sstevel@tonic-gate 				case SCF_ERROR_INVALID_ARGUMENT:
1443*7c478bd9Sstevel@tonic-gate 				case SCF_ERROR_NOT_SET:
1444*7c478bd9Sstevel@tonic-gate 					bad_fail("scf_transaction_property_new",
1445*7c478bd9Sstevel@tonic-gate 					    scf_error());
1446*7c478bd9Sstevel@tonic-gate 				}
1447*7c478bd9Sstevel@tonic-gate 			}
1448*7c478bd9Sstevel@tonic-gate 		}
1449*7c478bd9Sstevel@tonic-gate 
1450*7c478bd9Sstevel@tonic-gate 		val = scf_value_create(h);
1451*7c478bd9Sstevel@tonic-gate 		if (val == NULL) {
1452*7c478bd9Sstevel@tonic-gate 			assert(scf_error() == SCF_ERROR_NO_MEMORY);
1453*7c478bd9Sstevel@tonic-gate 			ret = ENOMEM;
1454*7c478bd9Sstevel@tonic-gate 			goto out;
1455*7c478bd9Sstevel@tonic-gate 		}
1456*7c478bd9Sstevel@tonic-gate 
1457*7c478bd9Sstevel@tonic-gate 		scf_value_set_count(val, contract_id);
1458*7c478bd9Sstevel@tonic-gate 		ret = scf_entry_add_value(t_cid, val);
1459*7c478bd9Sstevel@tonic-gate 		assert(ret == 0);
1460*7c478bd9Sstevel@tonic-gate 
1461*7c478bd9Sstevel@tonic-gate 		ret = scf_transaction_commit(t);
1462*7c478bd9Sstevel@tonic-gate 		if (ret == -1) {
1463*7c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
1464*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
1465*7c478bd9Sstevel@tonic-gate 			default:
1466*7c478bd9Sstevel@tonic-gate 				ret = ECONNABORTED;
1467*7c478bd9Sstevel@tonic-gate 				goto out;
1468*7c478bd9Sstevel@tonic-gate 
1469*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_DELETED:
1470*7c478bd9Sstevel@tonic-gate 				goto add;
1471*7c478bd9Sstevel@tonic-gate 
1472*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
1473*7c478bd9Sstevel@tonic-gate 				ret = EPERM;
1474*7c478bd9Sstevel@tonic-gate 				goto out;
1475*7c478bd9Sstevel@tonic-gate 
1476*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_ACCESS:
1477*7c478bd9Sstevel@tonic-gate 				ret = EACCES;
1478*7c478bd9Sstevel@tonic-gate 				goto out;
1479*7c478bd9Sstevel@tonic-gate 
1480*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_READONLY:
1481*7c478bd9Sstevel@tonic-gate 				ret = EROFS;
1482*7c478bd9Sstevel@tonic-gate 				goto out;
1483*7c478bd9Sstevel@tonic-gate 
1484*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
1485*7c478bd9Sstevel@tonic-gate 				bad_fail("scf_transaction_commit", scf_error());
1486*7c478bd9Sstevel@tonic-gate 			}
1487*7c478bd9Sstevel@tonic-gate 		}
1488*7c478bd9Sstevel@tonic-gate 		if (ret == 1) {
1489*7c478bd9Sstevel@tonic-gate 			ret = 0;
1490*7c478bd9Sstevel@tonic-gate 			break;
1491*7c478bd9Sstevel@tonic-gate 		}
1492*7c478bd9Sstevel@tonic-gate 
1493*7c478bd9Sstevel@tonic-gate 		scf_transaction_destroy_children(t);
1494*7c478bd9Sstevel@tonic-gate 		if (scf_pg_update(pg) == -1) {
1495*7c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
1496*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
1497*7c478bd9Sstevel@tonic-gate 			default:
1498*7c478bd9Sstevel@tonic-gate 				ret = ECONNABORTED;
1499*7c478bd9Sstevel@tonic-gate 				goto out;
1500*7c478bd9Sstevel@tonic-gate 
1501*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_DELETED:
1502*7c478bd9Sstevel@tonic-gate 				goto add;
1503*7c478bd9Sstevel@tonic-gate 
1504*7c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
1505*7c478bd9Sstevel@tonic-gate 				bad_fail("scf_pg_update", scf_error());
1506*7c478bd9Sstevel@tonic-gate 			}
1507*7c478bd9Sstevel@tonic-gate 		}
1508*7c478bd9Sstevel@tonic-gate 	}
1509*7c478bd9Sstevel@tonic-gate 
1510*7c478bd9Sstevel@tonic-gate out:
1511*7c478bd9Sstevel@tonic-gate 	scf_transaction_destroy_children(t);
1512*7c478bd9Sstevel@tonic-gate 	scf_transaction_destroy(t);
1513*7c478bd9Sstevel@tonic-gate 	scf_iter_destroy(iter);
1514*7c478bd9Sstevel@tonic-gate 	scf_property_destroy(prop);
1515*7c478bd9Sstevel@tonic-gate 	scf_pg_destroy(pg);
1516*7c478bd9Sstevel@tonic-gate 
1517*7c478bd9Sstevel@tonic-gate 	return (ret);
1518*7c478bd9Sstevel@tonic-gate }
1519*7c478bd9Sstevel@tonic-gate 
1520*7c478bd9Sstevel@tonic-gate int
1521*7c478bd9Sstevel@tonic-gate restarter_rm_libs_loadable()
1522*7c478bd9Sstevel@tonic-gate {
1523*7c478bd9Sstevel@tonic-gate 	void *libhndl;
1524*7c478bd9Sstevel@tonic-gate 
1525*7c478bd9Sstevel@tonic-gate 	if (method_context_safety)
1526*7c478bd9Sstevel@tonic-gate 		return (1);
1527*7c478bd9Sstevel@tonic-gate 
1528*7c478bd9Sstevel@tonic-gate 	if ((libhndl = dlopen("libpool.so", RTLD_LAZY | RTLD_LOCAL)) == NULL)
1529*7c478bd9Sstevel@tonic-gate 		return (0);
1530*7c478bd9Sstevel@tonic-gate 
1531*7c478bd9Sstevel@tonic-gate 	(void) dlclose(libhndl);
1532*7c478bd9Sstevel@tonic-gate 
1533*7c478bd9Sstevel@tonic-gate 	if ((libhndl = dlopen("libproject.so", RTLD_LAZY | RTLD_LOCAL)) == NULL)
1534*7c478bd9Sstevel@tonic-gate 		return (0);
1535*7c478bd9Sstevel@tonic-gate 
1536*7c478bd9Sstevel@tonic-gate 	(void) dlclose(libhndl);
1537*7c478bd9Sstevel@tonic-gate 
1538*7c478bd9Sstevel@tonic-gate 	method_context_safety = 1;
1539*7c478bd9Sstevel@tonic-gate 
1540*7c478bd9Sstevel@tonic-gate 	return (1);
1541*7c478bd9Sstevel@tonic-gate }
1542*7c478bd9Sstevel@tonic-gate 
1543*7c478bd9Sstevel@tonic-gate 
1544*7c478bd9Sstevel@tonic-gate static int
1545*7c478bd9Sstevel@tonic-gate get_astring_val(scf_propertygroup_t *pg, const char *name, char *buf,
1546*7c478bd9Sstevel@tonic-gate     size_t bufsz, scf_property_t *prop, scf_value_t *val)
1547*7c478bd9Sstevel@tonic-gate {
1548*7c478bd9Sstevel@tonic-gate 	ssize_t szret;
1549*7c478bd9Sstevel@tonic-gate 
1550*7c478bd9Sstevel@tonic-gate 	if (scf_pg_get_property(pg, name, prop) != SCF_SUCCESS) {
1551*7c478bd9Sstevel@tonic-gate 		if (scf_error() == SCF_ERROR_CONNECTION_BROKEN)
1552*7c478bd9Sstevel@tonic-gate 			uu_die(rcbroken);
1553*7c478bd9Sstevel@tonic-gate 		return (-1);
1554*7c478bd9Sstevel@tonic-gate 	}
1555*7c478bd9Sstevel@tonic-gate 
1556*7c478bd9Sstevel@tonic-gate 	if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
1557*7c478bd9Sstevel@tonic-gate 		if (scf_error() == SCF_ERROR_CONNECTION_BROKEN)
1558*7c478bd9Sstevel@tonic-gate 			uu_die(rcbroken);
1559*7c478bd9Sstevel@tonic-gate 		return (-1);
1560*7c478bd9Sstevel@tonic-gate 	}
1561*7c478bd9Sstevel@tonic-gate 
1562*7c478bd9Sstevel@tonic-gate 	szret = scf_value_get_astring(val, buf, bufsz);
1563*7c478bd9Sstevel@tonic-gate 
1564*7c478bd9Sstevel@tonic-gate 	return (szret >= 0 ? 0 : -1);
1565*7c478bd9Sstevel@tonic-gate }
1566*7c478bd9Sstevel@tonic-gate 
1567*7c478bd9Sstevel@tonic-gate /*
1568*7c478bd9Sstevel@tonic-gate  * Try to load mcp->pwd, if it isn't already.
1569*7c478bd9Sstevel@tonic-gate  * Fails with
1570*7c478bd9Sstevel@tonic-gate  *   ENOMEM - malloc() failed
1571*7c478bd9Sstevel@tonic-gate  *   ENOENT - no entry found
1572*7c478bd9Sstevel@tonic-gate  *   EIO - I/O error
1573*7c478bd9Sstevel@tonic-gate  *   EMFILE - process out of file descriptors
1574*7c478bd9Sstevel@tonic-gate  *   ENFILE - system out of file handles
1575*7c478bd9Sstevel@tonic-gate  */
1576*7c478bd9Sstevel@tonic-gate static int
1577*7c478bd9Sstevel@tonic-gate lookup_pwd(struct method_context *mcp)
1578*7c478bd9Sstevel@tonic-gate {
1579*7c478bd9Sstevel@tonic-gate 	struct passwd *pwdp;
1580*7c478bd9Sstevel@tonic-gate 
1581*7c478bd9Sstevel@tonic-gate 	if (mcp->pwbuf != NULL && mcp->pwd.pw_uid == mcp->uid)
1582*7c478bd9Sstevel@tonic-gate 		return (0);
1583*7c478bd9Sstevel@tonic-gate 
1584*7c478bd9Sstevel@tonic-gate 	if (mcp->pwbuf == NULL) {
1585*7c478bd9Sstevel@tonic-gate 		mcp->pwbufsz = sysconf(_SC_GETPW_R_SIZE_MAX);
1586*7c478bd9Sstevel@tonic-gate 		assert(mcp->pwbufsz >= 0);
1587*7c478bd9Sstevel@tonic-gate 		mcp->pwbuf = malloc(mcp->pwbufsz);
1588*7c478bd9Sstevel@tonic-gate 		if (mcp->pwbuf == NULL)
1589*7c478bd9Sstevel@tonic-gate 			return (ENOMEM);
1590*7c478bd9Sstevel@tonic-gate 	}
1591*7c478bd9Sstevel@tonic-gate 
1592*7c478bd9Sstevel@tonic-gate 	do {
1593*7c478bd9Sstevel@tonic-gate 		errno = 0;
1594*7c478bd9Sstevel@tonic-gate 		pwdp = getpwuid_r(mcp->uid, &mcp->pwd, mcp->pwbuf,
1595*7c478bd9Sstevel@tonic-gate 		    mcp->pwbufsz);
1596*7c478bd9Sstevel@tonic-gate 	} while (pwdp == NULL && errno == EINTR);
1597*7c478bd9Sstevel@tonic-gate 	if (pwdp != NULL)
1598*7c478bd9Sstevel@tonic-gate 		return (0);
1599*7c478bd9Sstevel@tonic-gate 
1600*7c478bd9Sstevel@tonic-gate 	free(mcp->pwbuf);
1601*7c478bd9Sstevel@tonic-gate 	mcp->pwbuf = NULL;
1602*7c478bd9Sstevel@tonic-gate 
1603*7c478bd9Sstevel@tonic-gate 	switch (errno) {
1604*7c478bd9Sstevel@tonic-gate 	case 0:
1605*7c478bd9Sstevel@tonic-gate 	default:
1606*7c478bd9Sstevel@tonic-gate 		/*
1607*7c478bd9Sstevel@tonic-gate 		 * Until bug 5065780 is fixed, getpwuid_r() can fail with
1608*7c478bd9Sstevel@tonic-gate 		 * ENOENT, particularly on the miniroot.  Since the
1609*7c478bd9Sstevel@tonic-gate 		 * documentation is inaccurate, we'll return ENOENT for unknown
1610*7c478bd9Sstevel@tonic-gate 		 * errors.
1611*7c478bd9Sstevel@tonic-gate 		 */
1612*7c478bd9Sstevel@tonic-gate 		return (ENOENT);
1613*7c478bd9Sstevel@tonic-gate 
1614*7c478bd9Sstevel@tonic-gate 	case EIO:
1615*7c478bd9Sstevel@tonic-gate 	case EMFILE:
1616*7c478bd9Sstevel@tonic-gate 	case ENFILE:
1617*7c478bd9Sstevel@tonic-gate 		return (errno);
1618*7c478bd9Sstevel@tonic-gate 
1619*7c478bd9Sstevel@tonic-gate 	case ERANGE:
1620*7c478bd9Sstevel@tonic-gate 		bad_fail("getpwuid_r", errno);
1621*7c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
1622*7c478bd9Sstevel@tonic-gate 	}
1623*7c478bd9Sstevel@tonic-gate }
1624*7c478bd9Sstevel@tonic-gate 
1625*7c478bd9Sstevel@tonic-gate /*
1626*7c478bd9Sstevel@tonic-gate  * Get the user id for str.  Returns 0 on success or
1627*7c478bd9Sstevel@tonic-gate  *   ERANGE	the uid is too big
1628*7c478bd9Sstevel@tonic-gate  *   EINVAL	the string starts with a digit, but is not a valid uid
1629*7c478bd9Sstevel@tonic-gate  *   ENOMEM	out of memory
1630*7c478bd9Sstevel@tonic-gate  *   ENOENT	no passwd entry for str
1631*7c478bd9Sstevel@tonic-gate  *   EIO	an I/O error has occurred
1632*7c478bd9Sstevel@tonic-gate  *   EMFILE/ENFILE  out of file descriptors
1633*7c478bd9Sstevel@tonic-gate  */
1634*7c478bd9Sstevel@tonic-gate int
1635*7c478bd9Sstevel@tonic-gate get_uid(const char *str, struct method_context *ci, uid_t *uidp)
1636*7c478bd9Sstevel@tonic-gate {
1637*7c478bd9Sstevel@tonic-gate 	if (isdigit(str[0])) {
1638*7c478bd9Sstevel@tonic-gate 		uid_t uid;
1639*7c478bd9Sstevel@tonic-gate 		char *cp;
1640*7c478bd9Sstevel@tonic-gate 
1641*7c478bd9Sstevel@tonic-gate 		errno = 0;
1642*7c478bd9Sstevel@tonic-gate 		uid = strtol(str, &cp, 10);
1643*7c478bd9Sstevel@tonic-gate 
1644*7c478bd9Sstevel@tonic-gate 		if (uid == 0 && errno != 0) {
1645*7c478bd9Sstevel@tonic-gate 			assert(errno != EINVAL);
1646*7c478bd9Sstevel@tonic-gate 			return (errno);
1647*7c478bd9Sstevel@tonic-gate 		}
1648*7c478bd9Sstevel@tonic-gate 
1649*7c478bd9Sstevel@tonic-gate 		for (; *cp != '\0'; ++cp)
1650*7c478bd9Sstevel@tonic-gate 			if (*cp != ' ' || *cp != '\t')
1651*7c478bd9Sstevel@tonic-gate 				return (EINVAL);
1652*7c478bd9Sstevel@tonic-gate 
1653*7c478bd9Sstevel@tonic-gate 		if (uid > UID_MAX)
1654*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
1655*7c478bd9Sstevel@tonic-gate 
1656*7c478bd9Sstevel@tonic-gate 		*uidp = uid;
1657*7c478bd9Sstevel@tonic-gate 		return (0);
1658*7c478bd9Sstevel@tonic-gate 	} else {
1659*7c478bd9Sstevel@tonic-gate 		struct passwd *pwdp;
1660*7c478bd9Sstevel@tonic-gate 
1661*7c478bd9Sstevel@tonic-gate 		if (ci->pwbuf == NULL) {
1662*7c478bd9Sstevel@tonic-gate 			ci->pwbufsz = sysconf(_SC_GETPW_R_SIZE_MAX);
1663*7c478bd9Sstevel@tonic-gate 			ci->pwbuf = malloc(ci->pwbufsz);
1664*7c478bd9Sstevel@tonic-gate 			if (ci->pwbuf == NULL)
1665*7c478bd9Sstevel@tonic-gate 				return (ENOMEM);
1666*7c478bd9Sstevel@tonic-gate 		}
1667*7c478bd9Sstevel@tonic-gate 
1668*7c478bd9Sstevel@tonic-gate 		do {
1669*7c478bd9Sstevel@tonic-gate 			errno = 0;
1670*7c478bd9Sstevel@tonic-gate 			pwdp =
1671*7c478bd9Sstevel@tonic-gate 			    getpwnam_r(str, &ci->pwd, ci->pwbuf, ci->pwbufsz);
1672*7c478bd9Sstevel@tonic-gate 		} while (pwdp == NULL && errno == EINTR);
1673*7c478bd9Sstevel@tonic-gate 
1674*7c478bd9Sstevel@tonic-gate 		if (pwdp != NULL) {
1675*7c478bd9Sstevel@tonic-gate 			*uidp = ci->pwd.pw_uid;
1676*7c478bd9Sstevel@tonic-gate 			return (0);
1677*7c478bd9Sstevel@tonic-gate 		} else {
1678*7c478bd9Sstevel@tonic-gate 			free(ci->pwbuf);
1679*7c478bd9Sstevel@tonic-gate 			ci->pwbuf = NULL;
1680*7c478bd9Sstevel@tonic-gate 			switch (errno) {
1681*7c478bd9Sstevel@tonic-gate 			case 0:
1682*7c478bd9Sstevel@tonic-gate 				return (ENOENT);
1683*7c478bd9Sstevel@tonic-gate 
1684*7c478bd9Sstevel@tonic-gate 			case ENOENT:
1685*7c478bd9Sstevel@tonic-gate 			case EIO:
1686*7c478bd9Sstevel@tonic-gate 			case EMFILE:
1687*7c478bd9Sstevel@tonic-gate 			case ENFILE:
1688*7c478bd9Sstevel@tonic-gate 				return (errno);
1689*7c478bd9Sstevel@tonic-gate 
1690*7c478bd9Sstevel@tonic-gate 			case ERANGE:
1691*7c478bd9Sstevel@tonic-gate 			default:
1692*7c478bd9Sstevel@tonic-gate 				bad_fail("getpwnam_r", errno);
1693*7c478bd9Sstevel@tonic-gate 				/* NOTREACHED */
1694*7c478bd9Sstevel@tonic-gate 			}
1695*7c478bd9Sstevel@tonic-gate 		}
1696*7c478bd9Sstevel@tonic-gate 	}
1697*7c478bd9Sstevel@tonic-gate }
1698*7c478bd9Sstevel@tonic-gate 
1699*7c478bd9Sstevel@tonic-gate gid_t
1700*7c478bd9Sstevel@tonic-gate get_gid(const char *str)
1701*7c478bd9Sstevel@tonic-gate {
1702*7c478bd9Sstevel@tonic-gate 	if (isdigit(str[0])) {
1703*7c478bd9Sstevel@tonic-gate 		gid_t gid;
1704*7c478bd9Sstevel@tonic-gate 		char *cp;
1705*7c478bd9Sstevel@tonic-gate 
1706*7c478bd9Sstevel@tonic-gate 		errno = 0;
1707*7c478bd9Sstevel@tonic-gate 		gid = strtol(str, &cp, 10);
1708*7c478bd9Sstevel@tonic-gate 
1709*7c478bd9Sstevel@tonic-gate 		if (gid == 0 && errno != 0)
1710*7c478bd9Sstevel@tonic-gate 			return (-1);
1711*7c478bd9Sstevel@tonic-gate 
1712*7c478bd9Sstevel@tonic-gate 		for (; *cp != '\0'; ++cp)
1713*7c478bd9Sstevel@tonic-gate 			if (*cp != ' ' || *cp != '\t')
1714*7c478bd9Sstevel@tonic-gate 				return (-1);
1715*7c478bd9Sstevel@tonic-gate 
1716*7c478bd9Sstevel@tonic-gate 		return (gid);
1717*7c478bd9Sstevel@tonic-gate 	} else {
1718*7c478bd9Sstevel@tonic-gate 		struct group grp, *ret;
1719*7c478bd9Sstevel@tonic-gate 		char *buffer;
1720*7c478bd9Sstevel@tonic-gate 		size_t buflen;
1721*7c478bd9Sstevel@tonic-gate 
1722*7c478bd9Sstevel@tonic-gate 		buflen = sysconf(_SC_GETGR_R_SIZE_MAX);
1723*7c478bd9Sstevel@tonic-gate 		buffer = malloc(buflen);
1724*7c478bd9Sstevel@tonic-gate 		if (buffer == NULL)
1725*7c478bd9Sstevel@tonic-gate 			uu_die(allocfail);
1726*7c478bd9Sstevel@tonic-gate 
1727*7c478bd9Sstevel@tonic-gate 		errno = 0;
1728*7c478bd9Sstevel@tonic-gate 		ret = getgrnam_r(str, &grp, buffer, buflen);
1729*7c478bd9Sstevel@tonic-gate 		free(buffer);
1730*7c478bd9Sstevel@tonic-gate 
1731*7c478bd9Sstevel@tonic-gate 		return (ret == NULL ? -1 : grp.gr_gid);
1732*7c478bd9Sstevel@tonic-gate 	}
1733*7c478bd9Sstevel@tonic-gate }
1734*7c478bd9Sstevel@tonic-gate 
1735*7c478bd9Sstevel@tonic-gate /*
1736*7c478bd9Sstevel@tonic-gate  * Fails with
1737*7c478bd9Sstevel@tonic-gate  *   ENOMEM - out of memory
1738*7c478bd9Sstevel@tonic-gate  *   ENOENT - no passwd entry
1739*7c478bd9Sstevel@tonic-gate  *	      no project entry
1740*7c478bd9Sstevel@tonic-gate  *   EIO - an I/O error occurred
1741*7c478bd9Sstevel@tonic-gate  *   EMFILE - the process is out of file descriptors
1742*7c478bd9Sstevel@tonic-gate  *   ENFILE - the system is out of file handles
1743*7c478bd9Sstevel@tonic-gate  *   ERANGE - the project id is out of range
1744*7c478bd9Sstevel@tonic-gate  *   EINVAL - str is invalid
1745*7c478bd9Sstevel@tonic-gate  *   E2BIG - the project entry was too big
1746*7c478bd9Sstevel@tonic-gate  *   -1 - the name service switch is misconfigured
1747*7c478bd9Sstevel@tonic-gate  */
1748*7c478bd9Sstevel@tonic-gate int
1749*7c478bd9Sstevel@tonic-gate get_projid(const char *str, struct method_context *cip)
1750*7c478bd9Sstevel@tonic-gate {
1751*7c478bd9Sstevel@tonic-gate 	int ret;
1752*7c478bd9Sstevel@tonic-gate 	void *buf;
1753*7c478bd9Sstevel@tonic-gate 	const size_t bufsz = PROJECT_BUFSZ;
1754*7c478bd9Sstevel@tonic-gate 	struct project proj, *pp;
1755*7c478bd9Sstevel@tonic-gate 
1756*7c478bd9Sstevel@tonic-gate 	if (strcmp(str, ":default") == 0) {
1757*7c478bd9Sstevel@tonic-gate 		if (cip->uid == 0) {
1758*7c478bd9Sstevel@tonic-gate 			/* Don't change project for root services */
1759*7c478bd9Sstevel@tonic-gate 			cip->project = NULL;
1760*7c478bd9Sstevel@tonic-gate 			return (0);
1761*7c478bd9Sstevel@tonic-gate 		}
1762*7c478bd9Sstevel@tonic-gate 
1763*7c478bd9Sstevel@tonic-gate 		switch (ret = lookup_pwd(cip)) {
1764*7c478bd9Sstevel@tonic-gate 		case 0:
1765*7c478bd9Sstevel@tonic-gate 			break;
1766*7c478bd9Sstevel@tonic-gate 
1767*7c478bd9Sstevel@tonic-gate 		case ENOMEM:
1768*7c478bd9Sstevel@tonic-gate 		case ENOENT:
1769*7c478bd9Sstevel@tonic-gate 		case EIO:
1770*7c478bd9Sstevel@tonic-gate 		case EMFILE:
1771*7c478bd9Sstevel@tonic-gate 		case ENFILE:
1772*7c478bd9Sstevel@tonic-gate 			return (ret);
1773*7c478bd9Sstevel@tonic-gate 
1774*7c478bd9Sstevel@tonic-gate 		default:
1775*7c478bd9Sstevel@tonic-gate 			bad_fail("lookup_pwd", ret);
1776*7c478bd9Sstevel@tonic-gate 		}
1777*7c478bd9Sstevel@tonic-gate 
1778*7c478bd9Sstevel@tonic-gate 		buf = malloc(bufsz);
1779*7c478bd9Sstevel@tonic-gate 		if (buf == NULL)
1780*7c478bd9Sstevel@tonic-gate 			return (ENOMEM);
1781*7c478bd9Sstevel@tonic-gate 
1782*7c478bd9Sstevel@tonic-gate 		do {
1783*7c478bd9Sstevel@tonic-gate 			errno = 0;
1784*7c478bd9Sstevel@tonic-gate 			pp = getdefaultproj(cip->pwd.pw_name, &proj, buf,
1785*7c478bd9Sstevel@tonic-gate 			    bufsz);
1786*7c478bd9Sstevel@tonic-gate 		} while (pp == NULL && errno == EINTR);
1787*7c478bd9Sstevel@tonic-gate 
1788*7c478bd9Sstevel@tonic-gate 		/* to be continued ... */
1789*7c478bd9Sstevel@tonic-gate 	} else {
1790*7c478bd9Sstevel@tonic-gate 		projid_t projid;
1791*7c478bd9Sstevel@tonic-gate 		char *cp;
1792*7c478bd9Sstevel@tonic-gate 
1793*7c478bd9Sstevel@tonic-gate 		if (!isdigit(str[0])) {
1794*7c478bd9Sstevel@tonic-gate 			cip->project = strdup(str);
1795*7c478bd9Sstevel@tonic-gate 			return (cip->project != NULL ? 0 : ENOMEM);
1796*7c478bd9Sstevel@tonic-gate 		}
1797*7c478bd9Sstevel@tonic-gate 
1798*7c478bd9Sstevel@tonic-gate 		errno = 0;
1799*7c478bd9Sstevel@tonic-gate 		projid = strtol(str, &cp, 10);
1800*7c478bd9Sstevel@tonic-gate 
1801*7c478bd9Sstevel@tonic-gate 		if (projid == 0 && errno != 0) {
1802*7c478bd9Sstevel@tonic-gate 			assert(errno == ERANGE);
1803*7c478bd9Sstevel@tonic-gate 			return (errno);
1804*7c478bd9Sstevel@tonic-gate 		}
1805*7c478bd9Sstevel@tonic-gate 
1806*7c478bd9Sstevel@tonic-gate 		for (; *cp != '\0'; ++cp)
1807*7c478bd9Sstevel@tonic-gate 			if (*cp != ' ' || *cp != '\t')
1808*7c478bd9Sstevel@tonic-gate 				return (EINVAL);
1809*7c478bd9Sstevel@tonic-gate 
1810*7c478bd9Sstevel@tonic-gate 		if (projid > MAXPROJID)
1811*7c478bd9Sstevel@tonic-gate 			return (ERANGE);
1812*7c478bd9Sstevel@tonic-gate 
1813*7c478bd9Sstevel@tonic-gate 		buf = malloc(bufsz);
1814*7c478bd9Sstevel@tonic-gate 		if (buf == NULL)
1815*7c478bd9Sstevel@tonic-gate 			return (ENOMEM);
1816*7c478bd9Sstevel@tonic-gate 
1817*7c478bd9Sstevel@tonic-gate 		do {
1818*7c478bd9Sstevel@tonic-gate 			errno = 0;
1819*7c478bd9Sstevel@tonic-gate 			pp = getprojbyid(projid, &proj, buf, bufsz);
1820*7c478bd9Sstevel@tonic-gate 		} while (pp == NULL && errno == EINTR);
1821*7c478bd9Sstevel@tonic-gate 	}
1822*7c478bd9Sstevel@tonic-gate 
1823*7c478bd9Sstevel@tonic-gate 	if (pp) {
1824*7c478bd9Sstevel@tonic-gate 		cip->project = strdup(pp->pj_name);
1825*7c478bd9Sstevel@tonic-gate 		free(buf);
1826*7c478bd9Sstevel@tonic-gate 		return (cip->project != NULL ? 0 : ENOMEM);
1827*7c478bd9Sstevel@tonic-gate 	}
1828*7c478bd9Sstevel@tonic-gate 
1829*7c478bd9Sstevel@tonic-gate 	free(buf);
1830*7c478bd9Sstevel@tonic-gate 
1831*7c478bd9Sstevel@tonic-gate 	switch (errno) {
1832*7c478bd9Sstevel@tonic-gate 	case 0:
1833*7c478bd9Sstevel@tonic-gate 		return (ENOENT);
1834*7c478bd9Sstevel@tonic-gate 
1835*7c478bd9Sstevel@tonic-gate 	case EIO:
1836*7c478bd9Sstevel@tonic-gate 	case EMFILE:
1837*7c478bd9Sstevel@tonic-gate 	case ENFILE:
1838*7c478bd9Sstevel@tonic-gate 		return (errno);
1839*7c478bd9Sstevel@tonic-gate 
1840*7c478bd9Sstevel@tonic-gate 	case ERANGE:
1841*7c478bd9Sstevel@tonic-gate 		return (E2BIG);
1842*7c478bd9Sstevel@tonic-gate 
1843*7c478bd9Sstevel@tonic-gate 	default:
1844*7c478bd9Sstevel@tonic-gate 		return (-1);
1845*7c478bd9Sstevel@tonic-gate 	}
1846*7c478bd9Sstevel@tonic-gate }
1847*7c478bd9Sstevel@tonic-gate 
1848*7c478bd9Sstevel@tonic-gate /*
1849*7c478bd9Sstevel@tonic-gate  * Parse the supp_groups property value and populate ci->groups.  Returns
1850*7c478bd9Sstevel@tonic-gate  * EINVAL (get_gid() failed for one of the components), E2BIG (the property has
1851*7c478bd9Sstevel@tonic-gate  * more than NGROUPS_MAX-1 groups), or 0 on success.
1852*7c478bd9Sstevel@tonic-gate  */
1853*7c478bd9Sstevel@tonic-gate int
1854*7c478bd9Sstevel@tonic-gate get_groups(char *str, struct method_context *ci)
1855*7c478bd9Sstevel@tonic-gate {
1856*7c478bd9Sstevel@tonic-gate 	char *cp, *end, *next;
1857*7c478bd9Sstevel@tonic-gate 	uint_t i;
1858*7c478bd9Sstevel@tonic-gate 
1859*7c478bd9Sstevel@tonic-gate 	const char * const whitespace = " \t";
1860*7c478bd9Sstevel@tonic-gate 	const char * const illegal = ", \t";
1861*7c478bd9Sstevel@tonic-gate 
1862*7c478bd9Sstevel@tonic-gate 	if (str[0] == '\0') {
1863*7c478bd9Sstevel@tonic-gate 		ci->ngroups = 0;
1864*7c478bd9Sstevel@tonic-gate 		return (0);
1865*7c478bd9Sstevel@tonic-gate 	}
1866*7c478bd9Sstevel@tonic-gate 
1867*7c478bd9Sstevel@tonic-gate 	for (cp = str, i = 0; *cp != '\0'; ) {
1868*7c478bd9Sstevel@tonic-gate 		/* skip whitespace */
1869*7c478bd9Sstevel@tonic-gate 		cp += strspn(cp, whitespace);
1870*7c478bd9Sstevel@tonic-gate 
1871*7c478bd9Sstevel@tonic-gate 		/* find the end */
1872*7c478bd9Sstevel@tonic-gate 		end = cp + strcspn(cp, illegal);
1873*7c478bd9Sstevel@tonic-gate 
1874*7c478bd9Sstevel@tonic-gate 		/* skip whitespace after end */
1875*7c478bd9Sstevel@tonic-gate 		next = end + strspn(end, whitespace);
1876*7c478bd9Sstevel@tonic-gate 
1877*7c478bd9Sstevel@tonic-gate 		/* if there's a comma, it separates the fields */
1878*7c478bd9Sstevel@tonic-gate 		if (*next == ',')
1879*7c478bd9Sstevel@tonic-gate 			++next;
1880*7c478bd9Sstevel@tonic-gate 
1881*7c478bd9Sstevel@tonic-gate 		*end = '\0';
1882*7c478bd9Sstevel@tonic-gate 
1883*7c478bd9Sstevel@tonic-gate 		if ((ci->groups[i] = get_gid(cp)) == -1) {
1884*7c478bd9Sstevel@tonic-gate 			ci->ngroups = 0;
1885*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
1886*7c478bd9Sstevel@tonic-gate 		}
1887*7c478bd9Sstevel@tonic-gate 
1888*7c478bd9Sstevel@tonic-gate 		++i;
1889*7c478bd9Sstevel@tonic-gate 		if (i > NGROUPS_MAX - 1) {
1890*7c478bd9Sstevel@tonic-gate 			ci->ngroups = 0;
1891*7c478bd9Sstevel@tonic-gate 			return (E2BIG);
1892*7c478bd9Sstevel@tonic-gate 		}
1893*7c478bd9Sstevel@tonic-gate 
1894*7c478bd9Sstevel@tonic-gate 		cp = next;
1895*7c478bd9Sstevel@tonic-gate 	}
1896*7c478bd9Sstevel@tonic-gate 
1897*7c478bd9Sstevel@tonic-gate 	ci->ngroups = i;
1898*7c478bd9Sstevel@tonic-gate 	return (0);
1899*7c478bd9Sstevel@tonic-gate }
1900*7c478bd9Sstevel@tonic-gate 
1901*7c478bd9Sstevel@tonic-gate /*
1902*7c478bd9Sstevel@tonic-gate  * Eventually, we will return a structured error in the case of
1903*7c478bd9Sstevel@tonic-gate  * retryable or abortable failures such as memory allocation errors and
1904*7c478bd9Sstevel@tonic-gate  * repository connection failures.  For now, these failures are just
1905*7c478bd9Sstevel@tonic-gate  * encoded in the failure string.
1906*7c478bd9Sstevel@tonic-gate  */
1907*7c478bd9Sstevel@tonic-gate static const char *
1908*7c478bd9Sstevel@tonic-gate get_profile(scf_propertygroup_t *pg, scf_property_t *prop, scf_value_t *val,
1909*7c478bd9Sstevel@tonic-gate     const char *cmdline, struct method_context *ci)
1910*7c478bd9Sstevel@tonic-gate {
1911*7c478bd9Sstevel@tonic-gate 	char *buf = ci->vbuf;
1912*7c478bd9Sstevel@tonic-gate 	ssize_t buf_sz = ci->vbuf_sz;
1913*7c478bd9Sstevel@tonic-gate 	char cmd[PATH_MAX];
1914*7c478bd9Sstevel@tonic-gate 	char *cp, *value;
1915*7c478bd9Sstevel@tonic-gate 	const char *cmdp;
1916*7c478bd9Sstevel@tonic-gate 	execattr_t *eap;
1917*7c478bd9Sstevel@tonic-gate 	char *errstr = NULL;
1918*7c478bd9Sstevel@tonic-gate 
1919*7c478bd9Sstevel@tonic-gate 	if (get_astring_val(pg, SCF_PROPERTY_PROFILE, buf, buf_sz, prop, val) !=
1920*7c478bd9Sstevel@tonic-gate 	    0)
1921*7c478bd9Sstevel@tonic-gate 		return ("Could not get profile property.");
1922*7c478bd9Sstevel@tonic-gate 
1923*7c478bd9Sstevel@tonic-gate 	/* Extract the command from the command line. */
1924*7c478bd9Sstevel@tonic-gate 	cp = strpbrk(cmdline, " \t");
1925*7c478bd9Sstevel@tonic-gate 
1926*7c478bd9Sstevel@tonic-gate 	if (cp == NULL) {
1927*7c478bd9Sstevel@tonic-gate 		cmdp = cmdline;
1928*7c478bd9Sstevel@tonic-gate 	} else {
1929*7c478bd9Sstevel@tonic-gate 		(void) strncpy(cmd, cmdline, cp - cmdline);
1930*7c478bd9Sstevel@tonic-gate 		cmd[cp - cmdline] = '\0';
1931*7c478bd9Sstevel@tonic-gate 		cmdp = cmd;
1932*7c478bd9Sstevel@tonic-gate 	}
1933*7c478bd9Sstevel@tonic-gate 
1934*7c478bd9Sstevel@tonic-gate 	/* Require that cmdp[0] == '/'? */
1935*7c478bd9Sstevel@tonic-gate 
1936*7c478bd9Sstevel@tonic-gate 	eap = getexecprof(buf, KV_COMMAND, cmdp, GET_ONE);
1937*7c478bd9Sstevel@tonic-gate 	if (eap == NULL)
1938*7c478bd9Sstevel@tonic-gate 		return ("Could not find profile.");
1939*7c478bd9Sstevel@tonic-gate 
1940*7c478bd9Sstevel@tonic-gate 	/* Based on pfexec.c */
1941*7c478bd9Sstevel@tonic-gate 
1942*7c478bd9Sstevel@tonic-gate 	/* Get the euid first so we don't override ci->pwd for the uid. */
1943*7c478bd9Sstevel@tonic-gate 	if ((value = kva_match(eap->attr, EXECATTR_EUID_KW)) != NULL) {
1944*7c478bd9Sstevel@tonic-gate 		if (get_uid(value, ci, &ci->euid) != 0) {
1945*7c478bd9Sstevel@tonic-gate 			ci->euid = -1;
1946*7c478bd9Sstevel@tonic-gate 			errstr = "Could not interpret profile euid.";
1947*7c478bd9Sstevel@tonic-gate 			goto out;
1948*7c478bd9Sstevel@tonic-gate 		}
1949*7c478bd9Sstevel@tonic-gate 	}
1950*7c478bd9Sstevel@tonic-gate 
1951*7c478bd9Sstevel@tonic-gate 	if ((value = kva_match(eap->attr, EXECATTR_UID_KW)) != NULL) {
1952*7c478bd9Sstevel@tonic-gate 		if (get_uid(value, ci, &ci->uid) != 0) {
1953*7c478bd9Sstevel@tonic-gate 			ci->euid = ci->uid = -1;
1954*7c478bd9Sstevel@tonic-gate 			errstr = "Could not interpret profile uid.";
1955*7c478bd9Sstevel@tonic-gate 			goto out;
1956*7c478bd9Sstevel@tonic-gate 		}
1957*7c478bd9Sstevel@tonic-gate 		ci->euid = ci->uid;
1958*7c478bd9Sstevel@tonic-gate 	}
1959*7c478bd9Sstevel@tonic-gate 
1960*7c478bd9Sstevel@tonic-gate 	if ((value = kva_match(eap->attr, EXECATTR_GID_KW)) != NULL) {
1961*7c478bd9Sstevel@tonic-gate 		ci->egid = ci->gid = get_gid(value);
1962*7c478bd9Sstevel@tonic-gate 		if (ci->gid == -1) {
1963*7c478bd9Sstevel@tonic-gate 			errstr = "Could not interpret profile gid.";
1964*7c478bd9Sstevel@tonic-gate 			goto out;
1965*7c478bd9Sstevel@tonic-gate 		}
1966*7c478bd9Sstevel@tonic-gate 	}
1967*7c478bd9Sstevel@tonic-gate 
1968*7c478bd9Sstevel@tonic-gate 	if ((value = kva_match(eap->attr, EXECATTR_EGID_KW)) != NULL) {
1969*7c478bd9Sstevel@tonic-gate 		ci->egid = get_gid(value);
1970*7c478bd9Sstevel@tonic-gate 		if (ci->egid == -1) {
1971*7c478bd9Sstevel@tonic-gate 			errstr = "Could not interpret profile egid.";
1972*7c478bd9Sstevel@tonic-gate 			goto out;
1973*7c478bd9Sstevel@tonic-gate 		}
1974*7c478bd9Sstevel@tonic-gate 	}
1975*7c478bd9Sstevel@tonic-gate 
1976*7c478bd9Sstevel@tonic-gate 	if ((value = kva_match(eap->attr, EXECATTR_LPRIV_KW)) != NULL) {
1977*7c478bd9Sstevel@tonic-gate 		ci->lpriv_set = priv_str_to_set(value, ",", NULL);
1978*7c478bd9Sstevel@tonic-gate 		if (ci->lpriv_set == NULL) {
1979*7c478bd9Sstevel@tonic-gate 			if (errno != EINVAL)
1980*7c478bd9Sstevel@tonic-gate 				errstr = ALLOCFAIL;
1981*7c478bd9Sstevel@tonic-gate 			else
1982*7c478bd9Sstevel@tonic-gate 				errstr = "Could not interpret profile "
1983*7c478bd9Sstevel@tonic-gate 				    "limitprivs.";
1984*7c478bd9Sstevel@tonic-gate 			goto out;
1985*7c478bd9Sstevel@tonic-gate 		}
1986*7c478bd9Sstevel@tonic-gate 	}
1987*7c478bd9Sstevel@tonic-gate 
1988*7c478bd9Sstevel@tonic-gate 	if ((value = kva_match(eap->attr, EXECATTR_IPRIV_KW)) != NULL) {
1989*7c478bd9Sstevel@tonic-gate 		ci->priv_set = priv_str_to_set(value, ",", NULL);
1990*7c478bd9Sstevel@tonic-gate 		if (ci->priv_set == NULL) {
1991*7c478bd9Sstevel@tonic-gate 			if (errno != EINVAL)
1992*7c478bd9Sstevel@tonic-gate 				errstr = ALLOCFAIL;
1993*7c478bd9Sstevel@tonic-gate 			else
1994*7c478bd9Sstevel@tonic-gate 				errstr = "Could not interpret profile privs.";
1995*7c478bd9Sstevel@tonic-gate 			goto out;
1996*7c478bd9Sstevel@tonic-gate 		}
1997*7c478bd9Sstevel@tonic-gate 	}
1998*7c478bd9Sstevel@tonic-gate 
1999*7c478bd9Sstevel@tonic-gate out:
2000*7c478bd9Sstevel@tonic-gate 	free_execattr(eap);
2001*7c478bd9Sstevel@tonic-gate 
2002*7c478bd9Sstevel@tonic-gate 	return (errstr);
2003*7c478bd9Sstevel@tonic-gate }
2004*7c478bd9Sstevel@tonic-gate 
2005*7c478bd9Sstevel@tonic-gate /*
2006*7c478bd9Sstevel@tonic-gate  * Eventually, we will return a structured error in the case of
2007*7c478bd9Sstevel@tonic-gate  * retryable or abortable failures such as memory allocation errors and
2008*7c478bd9Sstevel@tonic-gate  * repository connection failures.  For now, these failures are just
2009*7c478bd9Sstevel@tonic-gate  * encoded in the failure string.
2010*7c478bd9Sstevel@tonic-gate  */
2011*7c478bd9Sstevel@tonic-gate static const char *
2012*7c478bd9Sstevel@tonic-gate get_ids(scf_propertygroup_t *pg, scf_property_t *prop, scf_value_t *val,
2013*7c478bd9Sstevel@tonic-gate     struct method_context *ci)
2014*7c478bd9Sstevel@tonic-gate {
2015*7c478bd9Sstevel@tonic-gate 	const char *errstr = NULL;
2016*7c478bd9Sstevel@tonic-gate 	char *vbuf = ci->vbuf;
2017*7c478bd9Sstevel@tonic-gate 	ssize_t vbuf_sz = ci->vbuf_sz;
2018*7c478bd9Sstevel@tonic-gate 	int r;
2019*7c478bd9Sstevel@tonic-gate 
2020*7c478bd9Sstevel@tonic-gate 	if (get_astring_val(pg, SCF_PROPERTY_USER, vbuf, vbuf_sz, prop, val) !=
2021*7c478bd9Sstevel@tonic-gate 	    0) {
2022*7c478bd9Sstevel@tonic-gate 		errstr = "Could not get user property.";
2023*7c478bd9Sstevel@tonic-gate 		goto out;
2024*7c478bd9Sstevel@tonic-gate 	}
2025*7c478bd9Sstevel@tonic-gate 
2026*7c478bd9Sstevel@tonic-gate 	if (get_uid(vbuf, ci, &ci->uid) != 0) {
2027*7c478bd9Sstevel@tonic-gate 		ci->uid = -1;
2028*7c478bd9Sstevel@tonic-gate 		errstr = "Could not interpret user property.";
2029*7c478bd9Sstevel@tonic-gate 		goto out;
2030*7c478bd9Sstevel@tonic-gate 	}
2031*7c478bd9Sstevel@tonic-gate 
2032*7c478bd9Sstevel@tonic-gate 	if (get_astring_val(pg, SCF_PROPERTY_GROUP, vbuf, vbuf_sz, prop, val) !=
2033*7c478bd9Sstevel@tonic-gate 	    0) {
2034*7c478bd9Sstevel@tonic-gate 		errstr = "Could not get group property.";
2035*7c478bd9Sstevel@tonic-gate 		goto out;
2036*7c478bd9Sstevel@tonic-gate 	}
2037*7c478bd9Sstevel@tonic-gate 
2038*7c478bd9Sstevel@tonic-gate 	if (strcmp(vbuf, ":default") != 0) {
2039*7c478bd9Sstevel@tonic-gate 		ci->gid = get_gid(vbuf);
2040*7c478bd9Sstevel@tonic-gate 		if (ci->gid == -1) {
2041*7c478bd9Sstevel@tonic-gate 			errstr = "Could not interpret group property.";
2042*7c478bd9Sstevel@tonic-gate 			goto out;
2043*7c478bd9Sstevel@tonic-gate 		}
2044*7c478bd9Sstevel@tonic-gate 	} else {
2045*7c478bd9Sstevel@tonic-gate 		switch (r = lookup_pwd(ci)) {
2046*7c478bd9Sstevel@tonic-gate 		case 0:
2047*7c478bd9Sstevel@tonic-gate 			ci->gid = ci->pwd.pw_gid;
2048*7c478bd9Sstevel@tonic-gate 			break;
2049*7c478bd9Sstevel@tonic-gate 
2050*7c478bd9Sstevel@tonic-gate 		case ENOENT:
2051*7c478bd9Sstevel@tonic-gate 			ci->gid = -1;
2052*7c478bd9Sstevel@tonic-gate 			errstr = "No passwd entry.";
2053*7c478bd9Sstevel@tonic-gate 			goto out;
2054*7c478bd9Sstevel@tonic-gate 
2055*7c478bd9Sstevel@tonic-gate 		case ENOMEM:
2056*7c478bd9Sstevel@tonic-gate 			errstr = "Out of memory.";
2057*7c478bd9Sstevel@tonic-gate 			goto out;
2058*7c478bd9Sstevel@tonic-gate 
2059*7c478bd9Sstevel@tonic-gate 		case EIO:
2060*7c478bd9Sstevel@tonic-gate 		case EMFILE:
2061*7c478bd9Sstevel@tonic-gate 		case ENFILE:
2062*7c478bd9Sstevel@tonic-gate 			errstr = "getpwuid_r() failed.";
2063*7c478bd9Sstevel@tonic-gate 			goto out;
2064*7c478bd9Sstevel@tonic-gate 
2065*7c478bd9Sstevel@tonic-gate 		default:
2066*7c478bd9Sstevel@tonic-gate 			bad_fail("lookup_pwd", r);
2067*7c478bd9Sstevel@tonic-gate 		}
2068*7c478bd9Sstevel@tonic-gate 	}
2069*7c478bd9Sstevel@tonic-gate 
2070*7c478bd9Sstevel@tonic-gate 	if (get_astring_val(pg, SCF_PROPERTY_SUPP_GROUPS, vbuf, vbuf_sz, prop,
2071*7c478bd9Sstevel@tonic-gate 	    val) != 0) {
2072*7c478bd9Sstevel@tonic-gate 		errstr = "Could not get supplemental groups property.";
2073*7c478bd9Sstevel@tonic-gate 		goto out;
2074*7c478bd9Sstevel@tonic-gate 	}
2075*7c478bd9Sstevel@tonic-gate 
2076*7c478bd9Sstevel@tonic-gate 	if (strcmp(vbuf, ":default") != 0) {
2077*7c478bd9Sstevel@tonic-gate 		switch (r = get_groups(vbuf, ci)) {
2078*7c478bd9Sstevel@tonic-gate 		case 0:
2079*7c478bd9Sstevel@tonic-gate 			break;
2080*7c478bd9Sstevel@tonic-gate 
2081*7c478bd9Sstevel@tonic-gate 		case EINVAL:
2082*7c478bd9Sstevel@tonic-gate 			errstr =
2083*7c478bd9Sstevel@tonic-gate 			    "Could not interpret supplemental groups property.";
2084*7c478bd9Sstevel@tonic-gate 			goto out;
2085*7c478bd9Sstevel@tonic-gate 
2086*7c478bd9Sstevel@tonic-gate 		case E2BIG:
2087*7c478bd9Sstevel@tonic-gate 			errstr = "Too many supplemental groups.";
2088*7c478bd9Sstevel@tonic-gate 			goto out;
2089*7c478bd9Sstevel@tonic-gate 
2090*7c478bd9Sstevel@tonic-gate 		default:
2091*7c478bd9Sstevel@tonic-gate 			bad_fail("get_groups", r);
2092*7c478bd9Sstevel@tonic-gate 		}
2093*7c478bd9Sstevel@tonic-gate 	} else {
2094*7c478bd9Sstevel@tonic-gate 		ci->ngroups = -1;
2095*7c478bd9Sstevel@tonic-gate 	}
2096*7c478bd9Sstevel@tonic-gate 
2097*7c478bd9Sstevel@tonic-gate 	if (get_astring_val(pg, SCF_PROPERTY_PRIVILEGES, vbuf, vbuf_sz, prop,
2098*7c478bd9Sstevel@tonic-gate 	    val) != 0) {
2099*7c478bd9Sstevel@tonic-gate 		errstr = "Could not get privileges property.";
2100*7c478bd9Sstevel@tonic-gate 		goto out;
2101*7c478bd9Sstevel@tonic-gate 	}
2102*7c478bd9Sstevel@tonic-gate 
2103*7c478bd9Sstevel@tonic-gate 	/*
2104*7c478bd9Sstevel@tonic-gate 	 * For default privs, we need to keep priv_set == NULL, as
2105*7c478bd9Sstevel@tonic-gate 	 * we use this test elsewhere.
2106*7c478bd9Sstevel@tonic-gate 	 */
2107*7c478bd9Sstevel@tonic-gate 	if (strcmp(vbuf, ":default") != 0) {
2108*7c478bd9Sstevel@tonic-gate 		ci->priv_set = priv_str_to_set(vbuf, ",", NULL);
2109*7c478bd9Sstevel@tonic-gate 		if (ci->priv_set == NULL) {
2110*7c478bd9Sstevel@tonic-gate 			if (errno != EINVAL) {
2111*7c478bd9Sstevel@tonic-gate 				errstr = ALLOCFAIL;
2112*7c478bd9Sstevel@tonic-gate 			} else {
2113*7c478bd9Sstevel@tonic-gate 				errstr = "Could not interpret privileges "
2114*7c478bd9Sstevel@tonic-gate 				    "property.";
2115*7c478bd9Sstevel@tonic-gate 			}
2116*7c478bd9Sstevel@tonic-gate 			goto out;
2117*7c478bd9Sstevel@tonic-gate 		}
2118*7c478bd9Sstevel@tonic-gate 	}
2119*7c478bd9Sstevel@tonic-gate 
2120*7c478bd9Sstevel@tonic-gate 	if (get_astring_val(pg, SCF_PROPERTY_LIMIT_PRIVILEGES, vbuf, vbuf_sz,
2121*7c478bd9Sstevel@tonic-gate 	    prop, val) != 0) {
2122*7c478bd9Sstevel@tonic-gate 		errstr = "Could not get limit_privileges property.";
2123*7c478bd9Sstevel@tonic-gate 		goto out;
2124*7c478bd9Sstevel@tonic-gate 	}
2125*7c478bd9Sstevel@tonic-gate 
2126*7c478bd9Sstevel@tonic-gate 	if (strcmp(vbuf, ":default") == 0)
2127*7c478bd9Sstevel@tonic-gate 		/*
2128*7c478bd9Sstevel@tonic-gate 		 * L must default to all privileges so root NPA services see
2129*7c478bd9Sstevel@tonic-gate 		 * iE = all.  "zone" is all privileges available in the current
2130*7c478bd9Sstevel@tonic-gate 		 * zone, equivalent to "all" in the global zone.
2131*7c478bd9Sstevel@tonic-gate 		 */
2132*7c478bd9Sstevel@tonic-gate 		(void) strcpy(vbuf, "zone");
2133*7c478bd9Sstevel@tonic-gate 
2134*7c478bd9Sstevel@tonic-gate 	ci->lpriv_set = priv_str_to_set(vbuf, ",", NULL);
2135*7c478bd9Sstevel@tonic-gate 	if (ci->lpriv_set == NULL) {
2136*7c478bd9Sstevel@tonic-gate 		if (errno != EINVAL)
2137*7c478bd9Sstevel@tonic-gate 			errstr = ALLOCFAIL;
2138*7c478bd9Sstevel@tonic-gate 		else {
2139*7c478bd9Sstevel@tonic-gate 			errstr = "Could not interpret limit_privileges "
2140*7c478bd9Sstevel@tonic-gate 			    "property.";
2141*7c478bd9Sstevel@tonic-gate 		}
2142*7c478bd9Sstevel@tonic-gate 		goto out;
2143*7c478bd9Sstevel@tonic-gate 	}
2144*7c478bd9Sstevel@tonic-gate 
2145*7c478bd9Sstevel@tonic-gate out:
2146*7c478bd9Sstevel@tonic-gate 	return (errstr);
2147*7c478bd9Sstevel@tonic-gate }
2148*7c478bd9Sstevel@tonic-gate 
2149*7c478bd9Sstevel@tonic-gate static int
2150*7c478bd9Sstevel@tonic-gate get_environment(scf_handle_t *h, scf_propertygroup_t *pg,
2151*7c478bd9Sstevel@tonic-gate     struct method_context *mcp, scf_property_t *prop, scf_value_t *val)
2152*7c478bd9Sstevel@tonic-gate {
2153*7c478bd9Sstevel@tonic-gate 	scf_iter_t *iter;
2154*7c478bd9Sstevel@tonic-gate 	scf_type_t type;
2155*7c478bd9Sstevel@tonic-gate 	size_t i = 0;
2156*7c478bd9Sstevel@tonic-gate 	int ret;
2157*7c478bd9Sstevel@tonic-gate 
2158*7c478bd9Sstevel@tonic-gate 	if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, prop) != 0) {
2159*7c478bd9Sstevel@tonic-gate 		if (scf_error() == SCF_ERROR_NOT_FOUND)
2160*7c478bd9Sstevel@tonic-gate 			return (ENOENT);
2161*7c478bd9Sstevel@tonic-gate 		return (scf_error());
2162*7c478bd9Sstevel@tonic-gate 	}
2163*7c478bd9Sstevel@tonic-gate 	if (scf_property_type(prop, &type) != 0)
2164*7c478bd9Sstevel@tonic-gate 		return (scf_error());
2165*7c478bd9Sstevel@tonic-gate 	if (type != SCF_TYPE_ASTRING)
2166*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
2167*7c478bd9Sstevel@tonic-gate 	if ((iter = scf_iter_create(h)) == NULL)
2168*7c478bd9Sstevel@tonic-gate 		return (scf_error());
2169*7c478bd9Sstevel@tonic-gate 
2170*7c478bd9Sstevel@tonic-gate 	if (scf_iter_property_values(iter, prop) != 0) {
2171*7c478bd9Sstevel@tonic-gate 		ret = scf_error();
2172*7c478bd9Sstevel@tonic-gate 		scf_iter_destroy(iter);
2173*7c478bd9Sstevel@tonic-gate 		return (ret);
2174*7c478bd9Sstevel@tonic-gate 	}
2175*7c478bd9Sstevel@tonic-gate 
2176*7c478bd9Sstevel@tonic-gate 	mcp->env_sz = 10;
2177*7c478bd9Sstevel@tonic-gate 
2178*7c478bd9Sstevel@tonic-gate 	if ((mcp->env = uu_zalloc(sizeof (*mcp->env) * mcp->env_sz)) == NULL) {
2179*7c478bd9Sstevel@tonic-gate 		ret = ENOMEM;
2180*7c478bd9Sstevel@tonic-gate 		goto out;
2181*7c478bd9Sstevel@tonic-gate 	}
2182*7c478bd9Sstevel@tonic-gate 
2183*7c478bd9Sstevel@tonic-gate 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
2184*7c478bd9Sstevel@tonic-gate 		ret = scf_value_get_as_string(val, mcp->vbuf, mcp->vbuf_sz);
2185*7c478bd9Sstevel@tonic-gate 		if (ret == -1) {
2186*7c478bd9Sstevel@tonic-gate 			ret = scf_error();
2187*7c478bd9Sstevel@tonic-gate 			goto out;
2188*7c478bd9Sstevel@tonic-gate 		}
2189*7c478bd9Sstevel@tonic-gate 
2190*7c478bd9Sstevel@tonic-gate 		if ((mcp->env[i] = strdup(mcp->vbuf)) == NULL) {
2191*7c478bd9Sstevel@tonic-gate 			ret = ENOMEM;
2192*7c478bd9Sstevel@tonic-gate 			goto out;
2193*7c478bd9Sstevel@tonic-gate 		}
2194*7c478bd9Sstevel@tonic-gate 
2195*7c478bd9Sstevel@tonic-gate 		if (++i == mcp->env_sz) {
2196*7c478bd9Sstevel@tonic-gate 			char **env;
2197*7c478bd9Sstevel@tonic-gate 			mcp->env_sz *= 2;
2198*7c478bd9Sstevel@tonic-gate 			env = uu_zalloc(sizeof (*mcp->env) * mcp->env_sz);
2199*7c478bd9Sstevel@tonic-gate 			if (env == NULL) {
2200*7c478bd9Sstevel@tonic-gate 				ret = ENOMEM;
2201*7c478bd9Sstevel@tonic-gate 				goto out;
2202*7c478bd9Sstevel@tonic-gate 			}
2203*7c478bd9Sstevel@tonic-gate 			(void) memcpy(env, mcp->env,
2204*7c478bd9Sstevel@tonic-gate 			    sizeof (*mcp->env) * (mcp->env_sz / 2));
2205*7c478bd9Sstevel@tonic-gate 			free(mcp->env);
2206*7c478bd9Sstevel@tonic-gate 			mcp->env = env;
2207*7c478bd9Sstevel@tonic-gate 		}
2208*7c478bd9Sstevel@tonic-gate 	}
2209*7c478bd9Sstevel@tonic-gate 
2210*7c478bd9Sstevel@tonic-gate 	if (ret == -1)
2211*7c478bd9Sstevel@tonic-gate 		ret = scf_error();
2212*7c478bd9Sstevel@tonic-gate 
2213*7c478bd9Sstevel@tonic-gate out:
2214*7c478bd9Sstevel@tonic-gate 	scf_iter_destroy(iter);
2215*7c478bd9Sstevel@tonic-gate 	return (ret);
2216*7c478bd9Sstevel@tonic-gate }
2217*7c478bd9Sstevel@tonic-gate 
2218*7c478bd9Sstevel@tonic-gate /*
2219*7c478bd9Sstevel@tonic-gate  * Fetch method context information from the repository, allocate and fill
2220*7c478bd9Sstevel@tonic-gate  * a method_context structure, return it in *mcpp, and return NULL.  On error,
2221*7c478bd9Sstevel@tonic-gate  * return a human-readable string which indicates the error.
2222*7c478bd9Sstevel@tonic-gate  *
2223*7c478bd9Sstevel@tonic-gate  * Eventually, we will return a structured error in the case of
2224*7c478bd9Sstevel@tonic-gate  * retryable or abortable failures such as memory allocation errors and
2225*7c478bd9Sstevel@tonic-gate  * repository connection failures.  For now, these failures are just
2226*7c478bd9Sstevel@tonic-gate  * encoded in the failure string.
2227*7c478bd9Sstevel@tonic-gate  */
2228*7c478bd9Sstevel@tonic-gate const char *
2229*7c478bd9Sstevel@tonic-gate restarter_get_method_context(uint_t version, scf_instance_t *inst,
2230*7c478bd9Sstevel@tonic-gate     scf_snapshot_t *snap, const char *mname, const char *cmdline,
2231*7c478bd9Sstevel@tonic-gate     struct method_context **mcpp)
2232*7c478bd9Sstevel@tonic-gate {
2233*7c478bd9Sstevel@tonic-gate 	scf_handle_t *h;
2234*7c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *methpg = NULL;
2235*7c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *instpg = NULL;
2236*7c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg = NULL;
2237*7c478bd9Sstevel@tonic-gate 	scf_property_t *prop = NULL;
2238*7c478bd9Sstevel@tonic-gate 	scf_value_t *val = NULL;
2239*7c478bd9Sstevel@tonic-gate 	scf_type_t ty;
2240*7c478bd9Sstevel@tonic-gate 	uint8_t use_profile;
2241*7c478bd9Sstevel@tonic-gate 	int ret;
2242*7c478bd9Sstevel@tonic-gate 	const char *errstr = NULL;
2243*7c478bd9Sstevel@tonic-gate 	struct method_context *cip;
2244*7c478bd9Sstevel@tonic-gate 
2245*7c478bd9Sstevel@tonic-gate 
2246*7c478bd9Sstevel@tonic-gate 	if (version != RESTARTER_METHOD_CONTEXT_VERSION)
2247*7c478bd9Sstevel@tonic-gate 		return ("Unknown method_context version.");
2248*7c478bd9Sstevel@tonic-gate 
2249*7c478bd9Sstevel@tonic-gate 	/* Get the handle before we allocate anything. */
2250*7c478bd9Sstevel@tonic-gate 	h = scf_instance_handle(inst);
2251*7c478bd9Sstevel@tonic-gate 	if (h == NULL)
2252*7c478bd9Sstevel@tonic-gate 		return (scf_strerror(scf_error()));
2253*7c478bd9Sstevel@tonic-gate 
2254*7c478bd9Sstevel@tonic-gate 	cip = malloc(sizeof (*cip));
2255*7c478bd9Sstevel@tonic-gate 	if (cip == NULL)
2256*7c478bd9Sstevel@tonic-gate 		return (ALLOCFAIL);
2257*7c478bd9Sstevel@tonic-gate 
2258*7c478bd9Sstevel@tonic-gate 	(void) memset(cip, 0, sizeof (*cip));
2259*7c478bd9Sstevel@tonic-gate 	cip->uid = -1;
2260*7c478bd9Sstevel@tonic-gate 	cip->euid = -1;
2261*7c478bd9Sstevel@tonic-gate 	cip->gid = -1;
2262*7c478bd9Sstevel@tonic-gate 	cip->egid = -1;
2263*7c478bd9Sstevel@tonic-gate 
2264*7c478bd9Sstevel@tonic-gate 	cip->vbuf_sz = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
2265*7c478bd9Sstevel@tonic-gate 	assert(cip->vbuf_sz >= 0);
2266*7c478bd9Sstevel@tonic-gate 	cip->vbuf = malloc(cip->vbuf_sz);
2267*7c478bd9Sstevel@tonic-gate 	if (cip->vbuf == NULL) {
2268*7c478bd9Sstevel@tonic-gate 		free(cip);
2269*7c478bd9Sstevel@tonic-gate 		return (ALLOCFAIL);
2270*7c478bd9Sstevel@tonic-gate 	}
2271*7c478bd9Sstevel@tonic-gate 
2272*7c478bd9Sstevel@tonic-gate 	if ((instpg = scf_pg_create(h)) == NULL ||
2273*7c478bd9Sstevel@tonic-gate 	    (methpg = scf_pg_create(h)) == NULL ||
2274*7c478bd9Sstevel@tonic-gate 	    (prop = scf_property_create(h)) == NULL ||
2275*7c478bd9Sstevel@tonic-gate 	    (val = scf_value_create(h)) == NULL) {
2276*7c478bd9Sstevel@tonic-gate 		errstr = ALLOCFAIL;
2277*7c478bd9Sstevel@tonic-gate 		goto out;
2278*7c478bd9Sstevel@tonic-gate 	}
2279*7c478bd9Sstevel@tonic-gate 
2280*7c478bd9Sstevel@tonic-gate 	/*
2281*7c478bd9Sstevel@tonic-gate 	 * The method environment, and the credentials/profile data,
2282*7c478bd9Sstevel@tonic-gate 	 * may be found either in the pg for the method (methpg),
2283*7c478bd9Sstevel@tonic-gate 	 * or in the instance/service SCF_PG_METHOD_CONTEXT pg (named
2284*7c478bd9Sstevel@tonic-gate 	 * instpg below).
2285*7c478bd9Sstevel@tonic-gate 	 */
2286*7c478bd9Sstevel@tonic-gate 
2287*7c478bd9Sstevel@tonic-gate 	if (scf_instance_get_pg_composed(inst, snap, mname, methpg) !=
2288*7c478bd9Sstevel@tonic-gate 	    SCF_SUCCESS) {
2289*7c478bd9Sstevel@tonic-gate 		errstr = scf_strerror(scf_error());
2290*7c478bd9Sstevel@tonic-gate 		goto out;
2291*7c478bd9Sstevel@tonic-gate 	}
2292*7c478bd9Sstevel@tonic-gate 
2293*7c478bd9Sstevel@tonic-gate 	if (scf_instance_get_pg_composed(inst, snap, SCF_PG_METHOD_CONTEXT,
2294*7c478bd9Sstevel@tonic-gate 	    instpg) != SCF_SUCCESS) {
2295*7c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND) {
2296*7c478bd9Sstevel@tonic-gate 			errstr = scf_strerror(scf_error());
2297*7c478bd9Sstevel@tonic-gate 			goto out;
2298*7c478bd9Sstevel@tonic-gate 		}
2299*7c478bd9Sstevel@tonic-gate 		scf_pg_destroy(instpg);
2300*7c478bd9Sstevel@tonic-gate 		instpg = NULL;
2301*7c478bd9Sstevel@tonic-gate 	}
2302*7c478bd9Sstevel@tonic-gate 
2303*7c478bd9Sstevel@tonic-gate 	ret = get_environment(h, methpg, cip, prop, val);
2304*7c478bd9Sstevel@tonic-gate 	if (ret == ENOENT && instpg != NULL) {
2305*7c478bd9Sstevel@tonic-gate 		ret = get_environment(h, instpg, cip, prop, val);
2306*7c478bd9Sstevel@tonic-gate 	}
2307*7c478bd9Sstevel@tonic-gate 
2308*7c478bd9Sstevel@tonic-gate 	switch (ret) {
2309*7c478bd9Sstevel@tonic-gate 	case 0:
2310*7c478bd9Sstevel@tonic-gate 	case ENOENT:
2311*7c478bd9Sstevel@tonic-gate 		break;
2312*7c478bd9Sstevel@tonic-gate 	case ENOMEM:
2313*7c478bd9Sstevel@tonic-gate 		errstr = "Out of memory.";
2314*7c478bd9Sstevel@tonic-gate 		goto out;
2315*7c478bd9Sstevel@tonic-gate 	case EINVAL:
2316*7c478bd9Sstevel@tonic-gate 		errstr = "Invalid method environment.";
2317*7c478bd9Sstevel@tonic-gate 		goto out;
2318*7c478bd9Sstevel@tonic-gate 	default:
2319*7c478bd9Sstevel@tonic-gate 		errstr = scf_strerror(ret);
2320*7c478bd9Sstevel@tonic-gate 		goto out;
2321*7c478bd9Sstevel@tonic-gate 	}
2322*7c478bd9Sstevel@tonic-gate 
2323*7c478bd9Sstevel@tonic-gate 	pg = methpg;
2324*7c478bd9Sstevel@tonic-gate 
2325*7c478bd9Sstevel@tonic-gate 	ret = scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, prop);
2326*7c478bd9Sstevel@tonic-gate 	if (ret && scf_error() == SCF_ERROR_NOT_FOUND && instpg != NULL) {
2327*7c478bd9Sstevel@tonic-gate 		pg = instpg;
2328*7c478bd9Sstevel@tonic-gate 		ret = scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, prop);
2329*7c478bd9Sstevel@tonic-gate 	}
2330*7c478bd9Sstevel@tonic-gate 
2331*7c478bd9Sstevel@tonic-gate 	if (ret) {
2332*7c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
2333*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
2334*7c478bd9Sstevel@tonic-gate 			/* No context: use defaults */
2335*7c478bd9Sstevel@tonic-gate 			cip->uid = 0;
2336*7c478bd9Sstevel@tonic-gate 			cip->gid = 0;
2337*7c478bd9Sstevel@tonic-gate 			*mcpp = cip;
2338*7c478bd9Sstevel@tonic-gate 			goto out;
2339*7c478bd9Sstevel@tonic-gate 
2340*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_CONNECTION_BROKEN:
2341*7c478bd9Sstevel@tonic-gate 			errstr = RCBROKEN;
2342*7c478bd9Sstevel@tonic-gate 			goto out;
2343*7c478bd9Sstevel@tonic-gate 
2344*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
2345*7c478bd9Sstevel@tonic-gate 			errstr = "\"use_profile\" property deleted.";
2346*7c478bd9Sstevel@tonic-gate 			goto out;
2347*7c478bd9Sstevel@tonic-gate 
2348*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_HANDLE_MISMATCH:
2349*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_INVALID_ARGUMENT:
2350*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
2351*7c478bd9Sstevel@tonic-gate 		default:
2352*7c478bd9Sstevel@tonic-gate 			bad_fail("scf_pg_get_property", scf_error());
2353*7c478bd9Sstevel@tonic-gate 		}
2354*7c478bd9Sstevel@tonic-gate 	}
2355*7c478bd9Sstevel@tonic-gate 
2356*7c478bd9Sstevel@tonic-gate 	if (scf_property_type(prop, &ty) != SCF_SUCCESS) {
2357*7c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
2358*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_CONNECTION_BROKEN:
2359*7c478bd9Sstevel@tonic-gate 			errstr = RCBROKEN;
2360*7c478bd9Sstevel@tonic-gate 			break;
2361*7c478bd9Sstevel@tonic-gate 
2362*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
2363*7c478bd9Sstevel@tonic-gate 			errstr = "\"use profile\" property deleted.";
2364*7c478bd9Sstevel@tonic-gate 			break;
2365*7c478bd9Sstevel@tonic-gate 
2366*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
2367*7c478bd9Sstevel@tonic-gate 		default:
2368*7c478bd9Sstevel@tonic-gate 			bad_fail("scf_property_type", scf_error());
2369*7c478bd9Sstevel@tonic-gate 		}
2370*7c478bd9Sstevel@tonic-gate 
2371*7c478bd9Sstevel@tonic-gate 		goto out;
2372*7c478bd9Sstevel@tonic-gate 	}
2373*7c478bd9Sstevel@tonic-gate 
2374*7c478bd9Sstevel@tonic-gate 	if (ty != SCF_TYPE_BOOLEAN) {
2375*7c478bd9Sstevel@tonic-gate 		errstr = "\"use profile\" property is not boolean.";
2376*7c478bd9Sstevel@tonic-gate 		goto out;
2377*7c478bd9Sstevel@tonic-gate 	}
2378*7c478bd9Sstevel@tonic-gate 
2379*7c478bd9Sstevel@tonic-gate 	if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
2380*7c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
2381*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_CONNECTION_BROKEN:
2382*7c478bd9Sstevel@tonic-gate 			errstr = RCBROKEN;
2383*7c478bd9Sstevel@tonic-gate 			break;
2384*7c478bd9Sstevel@tonic-gate 
2385*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_CONSTRAINT_VIOLATED:
2386*7c478bd9Sstevel@tonic-gate 			errstr =
2387*7c478bd9Sstevel@tonic-gate 			    "\"use profile\" property has multiple values.";
2388*7c478bd9Sstevel@tonic-gate 			break;
2389*7c478bd9Sstevel@tonic-gate 
2390*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
2391*7c478bd9Sstevel@tonic-gate 			errstr = "\"use profile\" property has no values.";
2392*7c478bd9Sstevel@tonic-gate 			break;
2393*7c478bd9Sstevel@tonic-gate 
2394*7c478bd9Sstevel@tonic-gate 		default:
2395*7c478bd9Sstevel@tonic-gate 			bad_fail("scf_property_get_value", scf_error());
2396*7c478bd9Sstevel@tonic-gate 		}
2397*7c478bd9Sstevel@tonic-gate 
2398*7c478bd9Sstevel@tonic-gate 		goto out;
2399*7c478bd9Sstevel@tonic-gate 	}
2400*7c478bd9Sstevel@tonic-gate 
2401*7c478bd9Sstevel@tonic-gate 	ret = scf_value_get_boolean(val, &use_profile);
2402*7c478bd9Sstevel@tonic-gate 	assert(ret == SCF_SUCCESS);
2403*7c478bd9Sstevel@tonic-gate 
2404*7c478bd9Sstevel@tonic-gate 	/* get ids & privileges */
2405*7c478bd9Sstevel@tonic-gate 	if (use_profile)
2406*7c478bd9Sstevel@tonic-gate 		errstr = get_profile(pg, prop, val, cmdline, cip);
2407*7c478bd9Sstevel@tonic-gate 	else
2408*7c478bd9Sstevel@tonic-gate 		errstr = get_ids(pg, prop, val, cip);
2409*7c478bd9Sstevel@tonic-gate 	if (errstr != NULL)
2410*7c478bd9Sstevel@tonic-gate 		goto out;
2411*7c478bd9Sstevel@tonic-gate 
2412*7c478bd9Sstevel@tonic-gate 	/* get working directory */
2413*7c478bd9Sstevel@tonic-gate 	if (get_astring_val(pg, SCF_PROPERTY_WORKING_DIRECTORY, cip->vbuf,
2414*7c478bd9Sstevel@tonic-gate 	    cip->vbuf_sz, prop, val) != 0) {
2415*7c478bd9Sstevel@tonic-gate 		errstr = "Could not get value for working directory.";
2416*7c478bd9Sstevel@tonic-gate 		goto out;
2417*7c478bd9Sstevel@tonic-gate 	}
2418*7c478bd9Sstevel@tonic-gate 
2419*7c478bd9Sstevel@tonic-gate 	if (strcmp(cip->vbuf, ":default") == 0 ||
2420*7c478bd9Sstevel@tonic-gate 	    strcmp(cip->vbuf, ":home") == 0) {
2421*7c478bd9Sstevel@tonic-gate 		switch (ret = lookup_pwd(cip)) {
2422*7c478bd9Sstevel@tonic-gate 		case 0:
2423*7c478bd9Sstevel@tonic-gate 			break;
2424*7c478bd9Sstevel@tonic-gate 
2425*7c478bd9Sstevel@tonic-gate 		case ENOMEM:
2426*7c478bd9Sstevel@tonic-gate 			errstr = "Out of memory.";
2427*7c478bd9Sstevel@tonic-gate 			goto out;
2428*7c478bd9Sstevel@tonic-gate 
2429*7c478bd9Sstevel@tonic-gate 		case ENOENT:
2430*7c478bd9Sstevel@tonic-gate 		case EIO:
2431*7c478bd9Sstevel@tonic-gate 		case EMFILE:
2432*7c478bd9Sstevel@tonic-gate 		case ENFILE:
2433*7c478bd9Sstevel@tonic-gate 			errstr = "Could not get passwd entry.";
2434*7c478bd9Sstevel@tonic-gate 			goto out;
2435*7c478bd9Sstevel@tonic-gate 
2436*7c478bd9Sstevel@tonic-gate 		default:
2437*7c478bd9Sstevel@tonic-gate 			bad_fail("lookup_pwd", ret);
2438*7c478bd9Sstevel@tonic-gate 		}
2439*7c478bd9Sstevel@tonic-gate 
2440*7c478bd9Sstevel@tonic-gate 		cip->working_dir = strdup(cip->pwd.pw_dir);
2441*7c478bd9Sstevel@tonic-gate 		if (cip->working_dir == NULL) {
2442*7c478bd9Sstevel@tonic-gate 			errstr = ALLOCFAIL;
2443*7c478bd9Sstevel@tonic-gate 			goto out;
2444*7c478bd9Sstevel@tonic-gate 		}
2445*7c478bd9Sstevel@tonic-gate 	} else {
2446*7c478bd9Sstevel@tonic-gate 		cip->working_dir = strdup(cip->vbuf);
2447*7c478bd9Sstevel@tonic-gate 		if (cip->working_dir == NULL) {
2448*7c478bd9Sstevel@tonic-gate 			errstr = ALLOCFAIL;
2449*7c478bd9Sstevel@tonic-gate 			goto out;
2450*7c478bd9Sstevel@tonic-gate 		}
2451*7c478bd9Sstevel@tonic-gate 	}
2452*7c478bd9Sstevel@tonic-gate 
2453*7c478bd9Sstevel@tonic-gate 	/* get (optional) corefile pattern */
2454*7c478bd9Sstevel@tonic-gate 	if (scf_pg_get_property(pg, SCF_PROPERTY_COREFILE_PATTERN, prop) ==
2455*7c478bd9Sstevel@tonic-gate 	    SCF_SUCCESS) {
2456*7c478bd9Sstevel@tonic-gate 		if (get_astring_val(pg, SCF_PROPERTY_COREFILE_PATTERN,
2457*7c478bd9Sstevel@tonic-gate 		    cip->vbuf, cip->vbuf_sz, prop, val) != 0) {
2458*7c478bd9Sstevel@tonic-gate 			errstr = "Could not get value for corefile pattern.";
2459*7c478bd9Sstevel@tonic-gate 			goto out;
2460*7c478bd9Sstevel@tonic-gate 		}
2461*7c478bd9Sstevel@tonic-gate 
2462*7c478bd9Sstevel@tonic-gate 		cip->corefile_pattern = strdup(cip->vbuf);
2463*7c478bd9Sstevel@tonic-gate 		if (cip->corefile_pattern == NULL) {
2464*7c478bd9Sstevel@tonic-gate 			errstr = ALLOCFAIL;
2465*7c478bd9Sstevel@tonic-gate 			goto out;
2466*7c478bd9Sstevel@tonic-gate 		}
2467*7c478bd9Sstevel@tonic-gate 	} else {
2468*7c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
2469*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
2470*7c478bd9Sstevel@tonic-gate 			/* okay if missing. */
2471*7c478bd9Sstevel@tonic-gate 			break;
2472*7c478bd9Sstevel@tonic-gate 
2473*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_CONNECTION_BROKEN:
2474*7c478bd9Sstevel@tonic-gate 			errstr = RCBROKEN;
2475*7c478bd9Sstevel@tonic-gate 			goto out;
2476*7c478bd9Sstevel@tonic-gate 
2477*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
2478*7c478bd9Sstevel@tonic-gate 			errstr = "\"corefile_pattern\" property deleted.";
2479*7c478bd9Sstevel@tonic-gate 			goto out;
2480*7c478bd9Sstevel@tonic-gate 
2481*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_HANDLE_MISMATCH:
2482*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_INVALID_ARGUMENT:
2483*7c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
2484*7c478bd9Sstevel@tonic-gate 		default:
2485*7c478bd9Sstevel@tonic-gate 			bad_fail("scf_pg_get_property", scf_error());
2486*7c478bd9Sstevel@tonic-gate 		}
2487*7c478bd9Sstevel@tonic-gate 	}
2488*7c478bd9Sstevel@tonic-gate 
2489*7c478bd9Sstevel@tonic-gate 	if (restarter_rm_libs_loadable()) {
2490*7c478bd9Sstevel@tonic-gate 		/* get project */
2491*7c478bd9Sstevel@tonic-gate 		if (get_astring_val(pg, SCF_PROPERTY_PROJECT, cip->vbuf,
2492*7c478bd9Sstevel@tonic-gate 		    cip->vbuf_sz, prop, val) != 0) {
2493*7c478bd9Sstevel@tonic-gate 			errstr = "Could not get project.";
2494*7c478bd9Sstevel@tonic-gate 			goto out;
2495*7c478bd9Sstevel@tonic-gate 		}
2496*7c478bd9Sstevel@tonic-gate 
2497*7c478bd9Sstevel@tonic-gate 		switch (ret = get_projid(cip->vbuf, cip)) {
2498*7c478bd9Sstevel@tonic-gate 		case 0:
2499*7c478bd9Sstevel@tonic-gate 			break;
2500*7c478bd9Sstevel@tonic-gate 
2501*7c478bd9Sstevel@tonic-gate 		case ENOMEM:
2502*7c478bd9Sstevel@tonic-gate 			errstr = "Out of memory.";
2503*7c478bd9Sstevel@tonic-gate 			goto out;
2504*7c478bd9Sstevel@tonic-gate 
2505*7c478bd9Sstevel@tonic-gate 		case ENOENT:
2506*7c478bd9Sstevel@tonic-gate 			errstr = "Missing passwd or project entry.";
2507*7c478bd9Sstevel@tonic-gate 			goto out;
2508*7c478bd9Sstevel@tonic-gate 
2509*7c478bd9Sstevel@tonic-gate 		case EIO:
2510*7c478bd9Sstevel@tonic-gate 			errstr = "I/O error.";
2511*7c478bd9Sstevel@tonic-gate 			goto out;
2512*7c478bd9Sstevel@tonic-gate 
2513*7c478bd9Sstevel@tonic-gate 		case EMFILE:
2514*7c478bd9Sstevel@tonic-gate 		case ENFILE:
2515*7c478bd9Sstevel@tonic-gate 			errstr = "Out of file descriptors.";
2516*7c478bd9Sstevel@tonic-gate 			goto out;
2517*7c478bd9Sstevel@tonic-gate 
2518*7c478bd9Sstevel@tonic-gate 		case -1:
2519*7c478bd9Sstevel@tonic-gate 			errstr = "Name service switch is misconfigured.";
2520*7c478bd9Sstevel@tonic-gate 			goto out;
2521*7c478bd9Sstevel@tonic-gate 
2522*7c478bd9Sstevel@tonic-gate 		case ERANGE:
2523*7c478bd9Sstevel@tonic-gate 			errstr = "Project ID too big.";
2524*7c478bd9Sstevel@tonic-gate 			goto out;
2525*7c478bd9Sstevel@tonic-gate 
2526*7c478bd9Sstevel@tonic-gate 		case EINVAL:
2527*7c478bd9Sstevel@tonic-gate 			errstr = "Project ID is invalid.";
2528*7c478bd9Sstevel@tonic-gate 			goto out;
2529*7c478bd9Sstevel@tonic-gate 
2530*7c478bd9Sstevel@tonic-gate 		case E2BIG:
2531*7c478bd9Sstevel@tonic-gate 			errstr = "Project entry is too big.";
2532*7c478bd9Sstevel@tonic-gate 			goto out;
2533*7c478bd9Sstevel@tonic-gate 
2534*7c478bd9Sstevel@tonic-gate 		default:
2535*7c478bd9Sstevel@tonic-gate 			bad_fail("get_projid", ret);
2536*7c478bd9Sstevel@tonic-gate 		}
2537*7c478bd9Sstevel@tonic-gate 
2538*7c478bd9Sstevel@tonic-gate 		/* get resource pool */
2539*7c478bd9Sstevel@tonic-gate 		if (get_astring_val(pg, SCF_PROPERTY_RESOURCE_POOL, cip->vbuf,
2540*7c478bd9Sstevel@tonic-gate 			cip->vbuf_sz, prop, val) != 0) {
2541*7c478bd9Sstevel@tonic-gate 			errstr = "Could not get value of resource pool.";
2542*7c478bd9Sstevel@tonic-gate 			goto out;
2543*7c478bd9Sstevel@tonic-gate 		}
2544*7c478bd9Sstevel@tonic-gate 
2545*7c478bd9Sstevel@tonic-gate 		if (strcmp(cip->vbuf, ":default") != 0) {
2546*7c478bd9Sstevel@tonic-gate 			cip->resource_pool = strdup(cip->vbuf);
2547*7c478bd9Sstevel@tonic-gate 			if (cip->resource_pool == NULL) {
2548*7c478bd9Sstevel@tonic-gate 				errstr = ALLOCFAIL;
2549*7c478bd9Sstevel@tonic-gate 				goto out;
2550*7c478bd9Sstevel@tonic-gate 			}
2551*7c478bd9Sstevel@tonic-gate 		}
2552*7c478bd9Sstevel@tonic-gate 	}
2553*7c478bd9Sstevel@tonic-gate 
2554*7c478bd9Sstevel@tonic-gate 	*mcpp = cip;
2555*7c478bd9Sstevel@tonic-gate 
2556*7c478bd9Sstevel@tonic-gate out:
2557*7c478bd9Sstevel@tonic-gate 	(void) scf_value_destroy(val);
2558*7c478bd9Sstevel@tonic-gate 	scf_property_destroy(prop);
2559*7c478bd9Sstevel@tonic-gate 	scf_pg_destroy(instpg);
2560*7c478bd9Sstevel@tonic-gate 	scf_pg_destroy(methpg);
2561*7c478bd9Sstevel@tonic-gate 
2562*7c478bd9Sstevel@tonic-gate 	if (cip->pwbuf != NULL)
2563*7c478bd9Sstevel@tonic-gate 		free(cip->pwbuf);
2564*7c478bd9Sstevel@tonic-gate 	free(cip->vbuf);
2565*7c478bd9Sstevel@tonic-gate 
2566*7c478bd9Sstevel@tonic-gate 	if (errstr != NULL)
2567*7c478bd9Sstevel@tonic-gate 		restarter_free_method_context(cip);
2568*7c478bd9Sstevel@tonic-gate 
2569*7c478bd9Sstevel@tonic-gate 	return (errstr);
2570*7c478bd9Sstevel@tonic-gate }
2571*7c478bd9Sstevel@tonic-gate 
2572*7c478bd9Sstevel@tonic-gate /*
2573*7c478bd9Sstevel@tonic-gate  * Modify the current process per the given method_context.  On success, returns
2574*7c478bd9Sstevel@tonic-gate  * 0.  Note that the environment is not modified by this function to include the
2575*7c478bd9Sstevel@tonic-gate  * environment variables in cip->env.
2576*7c478bd9Sstevel@tonic-gate  *
2577*7c478bd9Sstevel@tonic-gate  * On failure, sets *fp to NULL or the name of the function which failed,
2578*7c478bd9Sstevel@tonic-gate  * and returns one of the following error codes.  The words in parentheses are
2579*7c478bd9Sstevel@tonic-gate  * the values to which *fp may be set for the error case.
2580*7c478bd9Sstevel@tonic-gate  *   ENOMEM - malloc() failed
2581*7c478bd9Sstevel@tonic-gate  *   EIO - an I/O error occurred (getpwuid_r, chdir)
2582*7c478bd9Sstevel@tonic-gate  *   EMFILE - process is out of file descriptors (getpwuid_r)
2583*7c478bd9Sstevel@tonic-gate  *   ENFILE - system is out of file handles (getpwuid_r)
2584*7c478bd9Sstevel@tonic-gate  *   EINVAL - gid or egid is out of range (setregid)
2585*7c478bd9Sstevel@tonic-gate  *	      ngroups is too big (setgroups)
2586*7c478bd9Sstevel@tonic-gate  *	      project's project id is bad (setproject)
2587*7c478bd9Sstevel@tonic-gate  *	      uid or euid is out of range (setreuid)
2588*7c478bd9Sstevel@tonic-gate  *   EPERM - insufficient privilege (setregid, initgroups, setgroups, setppriv,
2589*7c478bd9Sstevel@tonic-gate  *	         setproject, setreuid, settaskid)
2590*7c478bd9Sstevel@tonic-gate  *   ENOENT - uid has a passwd entry but no shadow entry
2591*7c478bd9Sstevel@tonic-gate  *	      working_dir does not exist (chdir)
2592*7c478bd9Sstevel@tonic-gate  *	      uid has no passwd entry
2593*7c478bd9Sstevel@tonic-gate  *	      the pool could not be found (pool_set_binding)
2594*7c478bd9Sstevel@tonic-gate  *   EFAULT - lpriv_set or priv_set has a bad address (setppriv)
2595*7c478bd9Sstevel@tonic-gate  *	      working_dir has a bad address (chdir)
2596*7c478bd9Sstevel@tonic-gate  *   EACCES - could not access working_dir (chdir)
2597*7c478bd9Sstevel@tonic-gate  *	      in a TASK_FINAL task (setproject, settaskid)
2598*7c478bd9Sstevel@tonic-gate  *	      no resource pool accepting default binding exists (setproject)
2599*7c478bd9Sstevel@tonic-gate  *   ELOOP - too many symbolic links in working_dir (chdir)
2600*7c478bd9Sstevel@tonic-gate  *   ENAMETOOLONG - working_dir is too long (chdir)
2601*7c478bd9Sstevel@tonic-gate  *   ENOLINK - working_dir is on an inaccessible remote machine (chdir)
2602*7c478bd9Sstevel@tonic-gate  *   ENOTDIR - working_dir is not a directory (chdir)
2603*7c478bd9Sstevel@tonic-gate  *   ESRCH - uid is not a user of project (setproject)
2604*7c478bd9Sstevel@tonic-gate  *	     project is invalid (setproject)
2605*7c478bd9Sstevel@tonic-gate  *	     the resource pool specified for project is unknown (setproject)
2606*7c478bd9Sstevel@tonic-gate  *   EBADF - the configuration for the pool is invalid (pool_set_binding)
2607*7c478bd9Sstevel@tonic-gate  *   -1 - core_set_process_path() failed (core_set_process_path)
2608*7c478bd9Sstevel@tonic-gate  *	  a resource control assignment failed (setproject)
2609*7c478bd9Sstevel@tonic-gate  *	  a system error occurred during pool_set_binding (pool_set_binding)
2610*7c478bd9Sstevel@tonic-gate  */
2611*7c478bd9Sstevel@tonic-gate int
2612*7c478bd9Sstevel@tonic-gate restarter_set_method_context(struct method_context *cip, const char **fp)
2613*7c478bd9Sstevel@tonic-gate {
2614*7c478bd9Sstevel@tonic-gate 	pid_t mypid = -1;
2615*7c478bd9Sstevel@tonic-gate 	int r, ret;
2616*7c478bd9Sstevel@tonic-gate 
2617*7c478bd9Sstevel@tonic-gate 	cip->pwbuf = NULL;
2618*7c478bd9Sstevel@tonic-gate 	*fp = NULL;
2619*7c478bd9Sstevel@tonic-gate 
2620*7c478bd9Sstevel@tonic-gate 	if (cip->gid != -1) {
2621*7c478bd9Sstevel@tonic-gate 		if (setregid(cip->gid,
2622*7c478bd9Sstevel@tonic-gate 		    cip->egid != -1 ? cip->egid : cip->gid) != 0) {
2623*7c478bd9Sstevel@tonic-gate 			*fp = "setregid";
2624*7c478bd9Sstevel@tonic-gate 
2625*7c478bd9Sstevel@tonic-gate 			ret = errno;
2626*7c478bd9Sstevel@tonic-gate 			assert(ret == EINVAL || ret == EPERM);
2627*7c478bd9Sstevel@tonic-gate 			goto out;
2628*7c478bd9Sstevel@tonic-gate 		}
2629*7c478bd9Sstevel@tonic-gate 	} else {
2630*7c478bd9Sstevel@tonic-gate 		if (cip->pwbuf == NULL) {
2631*7c478bd9Sstevel@tonic-gate 			switch (ret = lookup_pwd(cip)) {
2632*7c478bd9Sstevel@tonic-gate 			case 0:
2633*7c478bd9Sstevel@tonic-gate 				break;
2634*7c478bd9Sstevel@tonic-gate 
2635*7c478bd9Sstevel@tonic-gate 			case ENOMEM:
2636*7c478bd9Sstevel@tonic-gate 			case ENOENT:
2637*7c478bd9Sstevel@tonic-gate 				*fp = NULL;
2638*7c478bd9Sstevel@tonic-gate 				goto out;
2639*7c478bd9Sstevel@tonic-gate 
2640*7c478bd9Sstevel@tonic-gate 			case EIO:
2641*7c478bd9Sstevel@tonic-gate 			case EMFILE:
2642*7c478bd9Sstevel@tonic-gate 			case ENFILE:
2643*7c478bd9Sstevel@tonic-gate 				*fp = "getpwuid_r";
2644*7c478bd9Sstevel@tonic-gate 				goto out;
2645*7c478bd9Sstevel@tonic-gate 
2646*7c478bd9Sstevel@tonic-gate 			default:
2647*7c478bd9Sstevel@tonic-gate 				bad_fail("lookup_pwd", ret);
2648*7c478bd9Sstevel@tonic-gate 			}
2649*7c478bd9Sstevel@tonic-gate 		}
2650*7c478bd9Sstevel@tonic-gate 
2651*7c478bd9Sstevel@tonic-gate 		if (setregid(cip->pwd.pw_gid,
2652*7c478bd9Sstevel@tonic-gate 		    cip->egid != -1 ? cip->egid : cip->pwd.pw_gid) != 0) {
2653*7c478bd9Sstevel@tonic-gate 			*fp = "setregid";
2654*7c478bd9Sstevel@tonic-gate 
2655*7c478bd9Sstevel@tonic-gate 			ret = errno;
2656*7c478bd9Sstevel@tonic-gate 			assert(ret == EINVAL || ret == EPERM);
2657*7c478bd9Sstevel@tonic-gate 			goto out;
2658*7c478bd9Sstevel@tonic-gate 		}
2659*7c478bd9Sstevel@tonic-gate 	}
2660*7c478bd9Sstevel@tonic-gate 
2661*7c478bd9Sstevel@tonic-gate 	if (cip->ngroups == -1) {
2662*7c478bd9Sstevel@tonic-gate 		if (cip->pwbuf == NULL) {
2663*7c478bd9Sstevel@tonic-gate 			switch (ret = lookup_pwd(cip)) {
2664*7c478bd9Sstevel@tonic-gate 			case 0:
2665*7c478bd9Sstevel@tonic-gate 				break;
2666*7c478bd9Sstevel@tonic-gate 
2667*7c478bd9Sstevel@tonic-gate 			case ENOMEM:
2668*7c478bd9Sstevel@tonic-gate 			case ENOENT:
2669*7c478bd9Sstevel@tonic-gate 				*fp = NULL;
2670*7c478bd9Sstevel@tonic-gate 				goto out;
2671*7c478bd9Sstevel@tonic-gate 
2672*7c478bd9Sstevel@tonic-gate 			case EIO:
2673*7c478bd9Sstevel@tonic-gate 			case EMFILE:
2674*7c478bd9Sstevel@tonic-gate 			case ENFILE:
2675*7c478bd9Sstevel@tonic-gate 				*fp = "getpwuid_r";
2676*7c478bd9Sstevel@tonic-gate 				goto out;
2677*7c478bd9Sstevel@tonic-gate 
2678*7c478bd9Sstevel@tonic-gate 			default:
2679*7c478bd9Sstevel@tonic-gate 				bad_fail("lookup_pwd", ret);
2680*7c478bd9Sstevel@tonic-gate 			}
2681*7c478bd9Sstevel@tonic-gate 		}
2682*7c478bd9Sstevel@tonic-gate 
2683*7c478bd9Sstevel@tonic-gate 		/* Ok if cip->gid == -1 */
2684*7c478bd9Sstevel@tonic-gate 		if (initgroups(cip->pwd.pw_name, cip->gid) != 0) {
2685*7c478bd9Sstevel@tonic-gate 			*fp = "initgroups";
2686*7c478bd9Sstevel@tonic-gate 			ret = errno;
2687*7c478bd9Sstevel@tonic-gate 			assert(ret == EPERM);
2688*7c478bd9Sstevel@tonic-gate 			goto out;
2689*7c478bd9Sstevel@tonic-gate 		}
2690*7c478bd9Sstevel@tonic-gate 	} else if (cip->ngroups > 0 &&
2691*7c478bd9Sstevel@tonic-gate 	    setgroups(cip->ngroups, cip->groups) != 0) {
2692*7c478bd9Sstevel@tonic-gate 		*fp = "setgroups";
2693*7c478bd9Sstevel@tonic-gate 
2694*7c478bd9Sstevel@tonic-gate 		ret = errno;
2695*7c478bd9Sstevel@tonic-gate 		assert(ret == EINVAL || ret == EPERM);
2696*7c478bd9Sstevel@tonic-gate 		goto out;
2697*7c478bd9Sstevel@tonic-gate 	}
2698*7c478bd9Sstevel@tonic-gate 
2699*7c478bd9Sstevel@tonic-gate 	*fp = "setppriv";
2700*7c478bd9Sstevel@tonic-gate 
2701*7c478bd9Sstevel@tonic-gate 	if (cip->lpriv_set != NULL) {
2702*7c478bd9Sstevel@tonic-gate 		if (setppriv(PRIV_SET, PRIV_LIMIT, cip->lpriv_set) != 0) {
2703*7c478bd9Sstevel@tonic-gate 			ret = errno;
2704*7c478bd9Sstevel@tonic-gate 			assert(ret == EFAULT || ret == EPERM);
2705*7c478bd9Sstevel@tonic-gate 			goto out;
2706*7c478bd9Sstevel@tonic-gate 		}
2707*7c478bd9Sstevel@tonic-gate 	}
2708*7c478bd9Sstevel@tonic-gate 	if (cip->priv_set != NULL) {
2709*7c478bd9Sstevel@tonic-gate 		if (setppriv(PRIV_SET, PRIV_INHERITABLE, cip->priv_set) != 0) {
2710*7c478bd9Sstevel@tonic-gate 			ret = errno;
2711*7c478bd9Sstevel@tonic-gate 			assert(ret == EFAULT || ret == EPERM);
2712*7c478bd9Sstevel@tonic-gate 			goto out;
2713*7c478bd9Sstevel@tonic-gate 		}
2714*7c478bd9Sstevel@tonic-gate 	}
2715*7c478bd9Sstevel@tonic-gate 
2716*7c478bd9Sstevel@tonic-gate 	if (cip->working_dir != NULL) {
2717*7c478bd9Sstevel@tonic-gate 		do
2718*7c478bd9Sstevel@tonic-gate 			r = chdir(cip->working_dir);
2719*7c478bd9Sstevel@tonic-gate 		while (r != 0 && errno == EINTR);
2720*7c478bd9Sstevel@tonic-gate 		if (r != 0) {
2721*7c478bd9Sstevel@tonic-gate 			*fp = "chdir";
2722*7c478bd9Sstevel@tonic-gate 			ret = errno;
2723*7c478bd9Sstevel@tonic-gate 			goto out;
2724*7c478bd9Sstevel@tonic-gate 		}
2725*7c478bd9Sstevel@tonic-gate 	}
2726*7c478bd9Sstevel@tonic-gate 
2727*7c478bd9Sstevel@tonic-gate 	if (cip->corefile_pattern != NULL) {
2728*7c478bd9Sstevel@tonic-gate 		mypid = getpid();
2729*7c478bd9Sstevel@tonic-gate 
2730*7c478bd9Sstevel@tonic-gate 		if (core_set_process_path(cip->corefile_pattern,
2731*7c478bd9Sstevel@tonic-gate 		    strlen(cip->corefile_pattern) + 1, mypid) != 0) {
2732*7c478bd9Sstevel@tonic-gate 			*fp = "core_set_process_path";
2733*7c478bd9Sstevel@tonic-gate 			ret = -1;
2734*7c478bd9Sstevel@tonic-gate 			goto out;
2735*7c478bd9Sstevel@tonic-gate 		}
2736*7c478bd9Sstevel@tonic-gate 	}
2737*7c478bd9Sstevel@tonic-gate 
2738*7c478bd9Sstevel@tonic-gate 	if (restarter_rm_libs_loadable()) {
2739*7c478bd9Sstevel@tonic-gate 		if (cip->project == NULL) {
2740*7c478bd9Sstevel@tonic-gate 			if (settaskid(getprojid(), TASK_NORMAL) == -1) {
2741*7c478bd9Sstevel@tonic-gate 				switch (errno) {
2742*7c478bd9Sstevel@tonic-gate 				case EACCES:
2743*7c478bd9Sstevel@tonic-gate 				case EPERM:
2744*7c478bd9Sstevel@tonic-gate 					*fp = "settaskid";
2745*7c478bd9Sstevel@tonic-gate 					ret = errno;
2746*7c478bd9Sstevel@tonic-gate 					goto out;
2747*7c478bd9Sstevel@tonic-gate 
2748*7c478bd9Sstevel@tonic-gate 				case EINVAL:
2749*7c478bd9Sstevel@tonic-gate 				default:
2750*7c478bd9Sstevel@tonic-gate 					bad_fail("settaskid", errno);
2751*7c478bd9Sstevel@tonic-gate 				}
2752*7c478bd9Sstevel@tonic-gate 			}
2753*7c478bd9Sstevel@tonic-gate 		} else {
2754*7c478bd9Sstevel@tonic-gate 			switch (ret = lookup_pwd(cip)) {
2755*7c478bd9Sstevel@tonic-gate 			case 0:
2756*7c478bd9Sstevel@tonic-gate 				break;
2757*7c478bd9Sstevel@tonic-gate 
2758*7c478bd9Sstevel@tonic-gate 			case ENOMEM:
2759*7c478bd9Sstevel@tonic-gate 			case ENOENT:
2760*7c478bd9Sstevel@tonic-gate 				*fp = NULL;
2761*7c478bd9Sstevel@tonic-gate 				goto out;
2762*7c478bd9Sstevel@tonic-gate 
2763*7c478bd9Sstevel@tonic-gate 			case EIO:
2764*7c478bd9Sstevel@tonic-gate 			case EMFILE:
2765*7c478bd9Sstevel@tonic-gate 			case ENFILE:
2766*7c478bd9Sstevel@tonic-gate 				*fp = "getpwuid_r";
2767*7c478bd9Sstevel@tonic-gate 				goto out;
2768*7c478bd9Sstevel@tonic-gate 
2769*7c478bd9Sstevel@tonic-gate 			default:
2770*7c478bd9Sstevel@tonic-gate 				bad_fail("lookup_pwd", ret);
2771*7c478bd9Sstevel@tonic-gate 			}
2772*7c478bd9Sstevel@tonic-gate 
2773*7c478bd9Sstevel@tonic-gate 			*fp = "setproject";
2774*7c478bd9Sstevel@tonic-gate 
2775*7c478bd9Sstevel@tonic-gate 			switch (setproject(cip->project, cip->pwd.pw_name,
2776*7c478bd9Sstevel@tonic-gate 			    TASK_NORMAL)) {
2777*7c478bd9Sstevel@tonic-gate 			case 0:
2778*7c478bd9Sstevel@tonic-gate 				break;
2779*7c478bd9Sstevel@tonic-gate 
2780*7c478bd9Sstevel@tonic-gate 			case SETPROJ_ERR_TASK:
2781*7c478bd9Sstevel@tonic-gate 			case SETPROJ_ERR_POOL:
2782*7c478bd9Sstevel@tonic-gate 				ret = errno;
2783*7c478bd9Sstevel@tonic-gate 				goto out;
2784*7c478bd9Sstevel@tonic-gate 
2785*7c478bd9Sstevel@tonic-gate 			default:
2786*7c478bd9Sstevel@tonic-gate 				ret = -1;
2787*7c478bd9Sstevel@tonic-gate 				goto out;
2788*7c478bd9Sstevel@tonic-gate 			}
2789*7c478bd9Sstevel@tonic-gate 		}
2790*7c478bd9Sstevel@tonic-gate 
2791*7c478bd9Sstevel@tonic-gate 		if (cip->resource_pool != NULL) {
2792*7c478bd9Sstevel@tonic-gate 			if (mypid == -1)
2793*7c478bd9Sstevel@tonic-gate 				mypid = getpid();
2794*7c478bd9Sstevel@tonic-gate 
2795*7c478bd9Sstevel@tonic-gate 			*fp = "pool_set_binding";
2796*7c478bd9Sstevel@tonic-gate 
2797*7c478bd9Sstevel@tonic-gate 			if (pool_set_binding(cip->resource_pool, P_PID,
2798*7c478bd9Sstevel@tonic-gate 			    mypid) != PO_SUCCESS) {
2799*7c478bd9Sstevel@tonic-gate 				switch (pool_error()) {
2800*7c478bd9Sstevel@tonic-gate 				case POE_BADPARAM:
2801*7c478bd9Sstevel@tonic-gate 					ret = ENOENT;
2802*7c478bd9Sstevel@tonic-gate 					break;
2803*7c478bd9Sstevel@tonic-gate 
2804*7c478bd9Sstevel@tonic-gate 				case POE_INVALID_CONF:
2805*7c478bd9Sstevel@tonic-gate 					ret = EBADF;
2806*7c478bd9Sstevel@tonic-gate 					break;
2807*7c478bd9Sstevel@tonic-gate 
2808*7c478bd9Sstevel@tonic-gate 				case POE_SYSTEM:
2809*7c478bd9Sstevel@tonic-gate 					ret = -1;
2810*7c478bd9Sstevel@tonic-gate 					break;
2811*7c478bd9Sstevel@tonic-gate 
2812*7c478bd9Sstevel@tonic-gate 				default:
2813*7c478bd9Sstevel@tonic-gate 					bad_fail("pool_set_binding",
2814*7c478bd9Sstevel@tonic-gate 					    pool_error());
2815*7c478bd9Sstevel@tonic-gate 				}
2816*7c478bd9Sstevel@tonic-gate 
2817*7c478bd9Sstevel@tonic-gate 				goto out;
2818*7c478bd9Sstevel@tonic-gate 			}
2819*7c478bd9Sstevel@tonic-gate 		}
2820*7c478bd9Sstevel@tonic-gate 	}
2821*7c478bd9Sstevel@tonic-gate 
2822*7c478bd9Sstevel@tonic-gate 	/*
2823*7c478bd9Sstevel@tonic-gate 	 * The last thing we must do is assume our ID.
2824*7c478bd9Sstevel@tonic-gate 	 * If the UID is 0, we want it to be privilege-aware,
2825*7c478bd9Sstevel@tonic-gate 	 * otherwise the limit set gets used instead of E/P.
2826*7c478bd9Sstevel@tonic-gate 	 * We can do this by setting P as well, which keeps
2827*7c478bd9Sstevel@tonic-gate 	 * PA status (see priv_can_clear_PA()).
2828*7c478bd9Sstevel@tonic-gate 	 */
2829*7c478bd9Sstevel@tonic-gate 
2830*7c478bd9Sstevel@tonic-gate 	*fp = "setreuid";
2831*7c478bd9Sstevel@tonic-gate 	if (setreuid(cip->uid, cip->euid != -1 ? cip->euid : cip->uid) != 0) {
2832*7c478bd9Sstevel@tonic-gate 		ret = errno;
2833*7c478bd9Sstevel@tonic-gate 		assert(ret == EINVAL || ret == EPERM);
2834*7c478bd9Sstevel@tonic-gate 		goto out;
2835*7c478bd9Sstevel@tonic-gate 	}
2836*7c478bd9Sstevel@tonic-gate 
2837*7c478bd9Sstevel@tonic-gate 	*fp = "setppriv";
2838*7c478bd9Sstevel@tonic-gate 	if (cip->priv_set != NULL) {
2839*7c478bd9Sstevel@tonic-gate 		if (setppriv(PRIV_SET, PRIV_PERMITTED, cip->priv_set) != 0) {
2840*7c478bd9Sstevel@tonic-gate 			ret = errno;
2841*7c478bd9Sstevel@tonic-gate 			assert(ret == EFAULT || ret == EPERM);
2842*7c478bd9Sstevel@tonic-gate 			goto out;
2843*7c478bd9Sstevel@tonic-gate 		}
2844*7c478bd9Sstevel@tonic-gate 	}
2845*7c478bd9Sstevel@tonic-gate 
2846*7c478bd9Sstevel@tonic-gate 	ret = 0;
2847*7c478bd9Sstevel@tonic-gate out:
2848*7c478bd9Sstevel@tonic-gate 	free(cip->pwbuf);
2849*7c478bd9Sstevel@tonic-gate 	cip->pwbuf = NULL;
2850*7c478bd9Sstevel@tonic-gate 	return (ret);
2851*7c478bd9Sstevel@tonic-gate }
2852*7c478bd9Sstevel@tonic-gate 
2853*7c478bd9Sstevel@tonic-gate void
2854*7c478bd9Sstevel@tonic-gate restarter_free_method_context(struct method_context *mcp)
2855*7c478bd9Sstevel@tonic-gate {
2856*7c478bd9Sstevel@tonic-gate 	size_t i;
2857*7c478bd9Sstevel@tonic-gate 
2858*7c478bd9Sstevel@tonic-gate 	if (mcp->lpriv_set != NULL)
2859*7c478bd9Sstevel@tonic-gate 		priv_freeset(mcp->lpriv_set);
2860*7c478bd9Sstevel@tonic-gate 	if (mcp->priv_set != NULL)
2861*7c478bd9Sstevel@tonic-gate 		priv_freeset(mcp->priv_set);
2862*7c478bd9Sstevel@tonic-gate 
2863*7c478bd9Sstevel@tonic-gate 	if (mcp->env != NULL) {
2864*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < mcp->env_sz; i++)
2865*7c478bd9Sstevel@tonic-gate 			free(mcp->env[i]);
2866*7c478bd9Sstevel@tonic-gate 		free(mcp->env);
2867*7c478bd9Sstevel@tonic-gate 	}
2868*7c478bd9Sstevel@tonic-gate 
2869*7c478bd9Sstevel@tonic-gate 	free(mcp->working_dir);
2870*7c478bd9Sstevel@tonic-gate 	free(mcp->corefile_pattern);
2871*7c478bd9Sstevel@tonic-gate 	free(mcp->project);
2872*7c478bd9Sstevel@tonic-gate 	free(mcp->resource_pool);
2873*7c478bd9Sstevel@tonic-gate 	free(mcp);
2874*7c478bd9Sstevel@tonic-gate }
2875*7c478bd9Sstevel@tonic-gate 
2876*7c478bd9Sstevel@tonic-gate /*
2877*7c478bd9Sstevel@tonic-gate  * Method keyword functions
2878*7c478bd9Sstevel@tonic-gate  */
2879*7c478bd9Sstevel@tonic-gate 
2880*7c478bd9Sstevel@tonic-gate int
2881*7c478bd9Sstevel@tonic-gate restarter_is_null_method(const char *meth)
2882*7c478bd9Sstevel@tonic-gate {
2883*7c478bd9Sstevel@tonic-gate 	return (strcmp(meth, MKW_TRUE) == 0);
2884*7c478bd9Sstevel@tonic-gate }
2885*7c478bd9Sstevel@tonic-gate 
2886*7c478bd9Sstevel@tonic-gate static int
2887*7c478bd9Sstevel@tonic-gate is_kill_method(const char *method, const char *kill_str,
2888*7c478bd9Sstevel@tonic-gate     size_t kill_str_len)
2889*7c478bd9Sstevel@tonic-gate {
2890*7c478bd9Sstevel@tonic-gate 	const char *cp;
2891*7c478bd9Sstevel@tonic-gate 	int sig;
2892*7c478bd9Sstevel@tonic-gate 
2893*7c478bd9Sstevel@tonic-gate 	if (strncmp(method, kill_str, kill_str_len) != 0 ||
2894*7c478bd9Sstevel@tonic-gate 	    (method[kill_str_len] != '\0' &&
2895*7c478bd9Sstevel@tonic-gate 	    !isspace(method[kill_str_len])))
2896*7c478bd9Sstevel@tonic-gate 		return (-1);
2897*7c478bd9Sstevel@tonic-gate 
2898*7c478bd9Sstevel@tonic-gate 	cp = method + kill_str_len;
2899*7c478bd9Sstevel@tonic-gate 	while (*cp != '\0' && isspace(*cp))
2900*7c478bd9Sstevel@tonic-gate 		++cp;
2901*7c478bd9Sstevel@tonic-gate 
2902*7c478bd9Sstevel@tonic-gate 	if (*cp == '\0')
2903*7c478bd9Sstevel@tonic-gate 		return (SIGTERM);
2904*7c478bd9Sstevel@tonic-gate 
2905*7c478bd9Sstevel@tonic-gate 	if (*cp != '-')
2906*7c478bd9Sstevel@tonic-gate 		return (-1);
2907*7c478bd9Sstevel@tonic-gate 
2908*7c478bd9Sstevel@tonic-gate 	return (str2sig(cp + 1, &sig) == 0 ? sig : -1);
2909*7c478bd9Sstevel@tonic-gate }
2910*7c478bd9Sstevel@tonic-gate 
2911*7c478bd9Sstevel@tonic-gate int
2912*7c478bd9Sstevel@tonic-gate restarter_is_kill_proc_method(const char *method)
2913*7c478bd9Sstevel@tonic-gate {
2914*7c478bd9Sstevel@tonic-gate 	return (is_kill_method(method, MKW_KILL_PROC,
2915*7c478bd9Sstevel@tonic-gate 	    sizeof (MKW_KILL_PROC) - 1));
2916*7c478bd9Sstevel@tonic-gate }
2917*7c478bd9Sstevel@tonic-gate 
2918*7c478bd9Sstevel@tonic-gate int
2919*7c478bd9Sstevel@tonic-gate restarter_is_kill_method(const char *method)
2920*7c478bd9Sstevel@tonic-gate {
2921*7c478bd9Sstevel@tonic-gate 	return (is_kill_method(method, MKW_KILL, sizeof (MKW_KILL) - 1));
2922*7c478bd9Sstevel@tonic-gate }
2923*7c478bd9Sstevel@tonic-gate 
2924*7c478bd9Sstevel@tonic-gate /*
2925*7c478bd9Sstevel@tonic-gate  * Stubs for now.
2926*7c478bd9Sstevel@tonic-gate  */
2927*7c478bd9Sstevel@tonic-gate 
2928*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
2929*7c478bd9Sstevel@tonic-gate int
2930*7c478bd9Sstevel@tonic-gate restarter_event_get_enabled(restarter_event_t *e)
2931*7c478bd9Sstevel@tonic-gate {
2932*7c478bd9Sstevel@tonic-gate 	return (-1);
2933*7c478bd9Sstevel@tonic-gate }
2934*7c478bd9Sstevel@tonic-gate 
2935*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
2936*7c478bd9Sstevel@tonic-gate uint64_t
2937*7c478bd9Sstevel@tonic-gate restarter_event_get_seq(restarter_event_t *e)
2938*7c478bd9Sstevel@tonic-gate {
2939*7c478bd9Sstevel@tonic-gate 	return (-1);
2940*7c478bd9Sstevel@tonic-gate }
2941*7c478bd9Sstevel@tonic-gate 
2942*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
2943*7c478bd9Sstevel@tonic-gate void
2944*7c478bd9Sstevel@tonic-gate restarter_event_get_time(restarter_event_t *e, hrtime_t *time)
2945*7c478bd9Sstevel@tonic-gate {
2946*7c478bd9Sstevel@tonic-gate }
2947