xref: /titanic_52/usr/src/lib/librestart/common/librestart.c (revision f6e214c7418f43af38bd8c3a557e3d0a1d311cfa)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
53ad28c1eSrm88369  * Common Development and Distribution License (the "License").
63ad28c1eSrm88369  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217257d1b4Sraf 
227c478bd9Sstevel@tonic-gate /*
23*f6e214c7SGavin Maltby  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
26*f6e214c7SGavin Maltby #include <libintl.h>
277c478bd9Sstevel@tonic-gate #include <librestart.h>
287c478bd9Sstevel@tonic-gate #include <librestart_priv.h>
297c478bd9Sstevel@tonic-gate #include <libscf.h>
307c478bd9Sstevel@tonic-gate #include <libscf_priv.h>
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate #include <assert.h>
337c478bd9Sstevel@tonic-gate #include <ctype.h>
347c478bd9Sstevel@tonic-gate #include <dlfcn.h>
357c478bd9Sstevel@tonic-gate #include <errno.h>
367c478bd9Sstevel@tonic-gate #include <exec_attr.h>
377c478bd9Sstevel@tonic-gate #include <grp.h>
387c478bd9Sstevel@tonic-gate #include <libsysevent.h>
397c478bd9Sstevel@tonic-gate #include <libuutil.h>
407c478bd9Sstevel@tonic-gate #include <limits.h>
417c478bd9Sstevel@tonic-gate #include <link.h>
427c478bd9Sstevel@tonic-gate #include <malloc.h>
437c478bd9Sstevel@tonic-gate #include <pool.h>
447c478bd9Sstevel@tonic-gate #include <priv.h>
457c478bd9Sstevel@tonic-gate #include <project.h>
467c478bd9Sstevel@tonic-gate #include <pthread.h>
477c478bd9Sstevel@tonic-gate #include <pwd.h>
487c478bd9Sstevel@tonic-gate #include <secdb.h>
497c478bd9Sstevel@tonic-gate #include <signal.h>
507c478bd9Sstevel@tonic-gate #include <stdlib.h>
517c478bd9Sstevel@tonic-gate #include <string.h>
527c478bd9Sstevel@tonic-gate #include <syslog.h>
537c478bd9Sstevel@tonic-gate #include <sys/corectl.h>
547c478bd9Sstevel@tonic-gate #include <sys/machelf.h>
557c478bd9Sstevel@tonic-gate #include <sys/task.h>
567c478bd9Sstevel@tonic-gate #include <sys/types.h>
577c478bd9Sstevel@tonic-gate #include <time.h>
587c478bd9Sstevel@tonic-gate #include <unistd.h>
597c478bd9Sstevel@tonic-gate #include <ucontext.h>
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate #define	min(a, b)		((a) > (b) ? (b) : (a))
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate #define	MKW_TRUE	":true"
647c478bd9Sstevel@tonic-gate #define	MKW_KILL	":kill"
657c478bd9Sstevel@tonic-gate #define	MKW_KILL_PROC	":kill_process"
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate #define	ALLOCFAIL	((char *)"Allocation failure.")
687c478bd9Sstevel@tonic-gate #define	RCBROKEN	((char *)"Repository connection broken.")
697c478bd9Sstevel@tonic-gate 
702c65c8b0Srm88369 #define	MAX_COMMIT_RETRIES		10
717c478bd9Sstevel@tonic-gate #define	MAX_COMMIT_RETRY_INT		(5 * 1000000)	/* 5 seconds */
727c478bd9Sstevel@tonic-gate #define	INITIAL_COMMIT_RETRY_INT	(10000)		/* 1/100th second */
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate /*
757c478bd9Sstevel@tonic-gate  * bad_fail() catches bugs in this and lower layers by reporting supposedly
767c478bd9Sstevel@tonic-gate  * impossible function failures.  The NDEBUG case keeps the strings out of the
777c478bd9Sstevel@tonic-gate  * library but still calls abort() so we can root-cause from the coredump.
787c478bd9Sstevel@tonic-gate  */
797c478bd9Sstevel@tonic-gate #ifndef NDEBUG
807c478bd9Sstevel@tonic-gate #define	bad_fail(func, err)	{					\
817c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,						\
827c478bd9Sstevel@tonic-gate 	    "At %s:%d, %s() failed with unexpected error %d.  Aborting.\n", \
837c478bd9Sstevel@tonic-gate 	    __FILE__, __LINE__, (func), (err));				\
847c478bd9Sstevel@tonic-gate 	abort();							\
857c478bd9Sstevel@tonic-gate }
867c478bd9Sstevel@tonic-gate #else
877c478bd9Sstevel@tonic-gate #define	bad_fail(func, err)	abort()
887c478bd9Sstevel@tonic-gate #endif
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate struct restarter_event_handle {
917c478bd9Sstevel@tonic-gate 	char				*reh_restarter_name;
927c478bd9Sstevel@tonic-gate 	char				*reh_delegate_channel_name;
937c478bd9Sstevel@tonic-gate 	evchan_t			*reh_delegate_channel;
947c478bd9Sstevel@tonic-gate 	char				*reh_delegate_subscriber_id;
957c478bd9Sstevel@tonic-gate 	char				*reh_master_channel_name;
967c478bd9Sstevel@tonic-gate 	evchan_t			*reh_master_channel;
977c478bd9Sstevel@tonic-gate 	char				*reh_master_subscriber_id;
987c478bd9Sstevel@tonic-gate 	int				(*reh_handler)(restarter_event_t *);
997c478bd9Sstevel@tonic-gate };
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate struct restarter_event {
1027c478bd9Sstevel@tonic-gate 	sysevent_t			*re_sysevent;
1037c478bd9Sstevel@tonic-gate 	restarter_event_type_t		re_type;
1047c478bd9Sstevel@tonic-gate 	char				*re_instance_name;
1057c478bd9Sstevel@tonic-gate 	restarter_event_handle_t	*re_event_handle;
1067c478bd9Sstevel@tonic-gate 	restarter_instance_state_t	re_state;
1077c478bd9Sstevel@tonic-gate 	restarter_instance_state_t	re_next_state;
1087c478bd9Sstevel@tonic-gate };
1097c478bd9Sstevel@tonic-gate 
110870ad75aSSean Wilcox /*
111*f6e214c7SGavin Maltby  * Long reasons must all parse/read correctly in the following contexts:
112*f6e214c7SGavin Maltby  *
113*f6e214c7SGavin Maltby  * "A service instance transitioned state: %s."
114*f6e214c7SGavin Maltby  * "A service failed: %s."
115*f6e214c7SGavin Maltby  * "Reason: %s."
116*f6e214c7SGavin Maltby  * "The service transitioned state (%s) and ..."
117*f6e214c7SGavin Maltby  *
118*f6e214c7SGavin Maltby  * With the exception of restart_str_none they must also fit the following
119*f6e214c7SGavin Maltby  * moulds:
120*f6e214c7SGavin Maltby  *
121*f6e214c7SGavin Maltby  * "An instance transitioned because %s, and ..."
122*f6e214c7SGavin Maltby  * "An instance transitioned to <new-state> because %s, and ..."
123*f6e214c7SGavin Maltby  *
124*f6e214c7SGavin Maltby  * Note that whoever is rendering the long message must provide the
125*f6e214c7SGavin Maltby  * terminal punctuation - don't include it here.  Similarly, do not
126*f6e214c7SGavin Maltby  * provide an initial capital letter in reason-long.
127*f6e214c7SGavin Maltby  *
128*f6e214c7SGavin Maltby  * The long reason strings are Volatile - within the grammatical constraints
129*f6e214c7SGavin Maltby  * above we may improve them as need be.  The intention is that a consumer
130*f6e214c7SGavin Maltby  * may blindly render the string along the lines of the above examples,
131*f6e214c7SGavin Maltby  * but has no other guarantees as to the exact wording.  Long reasons
132*f6e214c7SGavin Maltby  * are localized.
133*f6e214c7SGavin Maltby  *
134*f6e214c7SGavin Maltby  * We define revisions of the set of short reason strings in use.  Within
135*f6e214c7SGavin Maltby  * a given revision, all short reasons are Committed.  Consumers must check
136*f6e214c7SGavin Maltby  * the revision in use before relying on the semantics of the short reason
137*f6e214c7SGavin Maltby  * codes - if the version exceeds that which they are familiar with they should
138*f6e214c7SGavin Maltby  * fail gracefully.  Having checked for version compatability, a consumer
139*f6e214c7SGavin Maltby  * is assured that
140*f6e214c7SGavin Maltby  *
141*f6e214c7SGavin Maltby  *	"short_reason_A iff semantic_A", provided:
142*f6e214c7SGavin Maltby  *
143*f6e214c7SGavin Maltby  *		. the restarter uses this short reason code at all,
144*f6e214c7SGavin Maltby  *		. the short reason is not "none" (which a restarter could
145*f6e214c7SGavin Maltby  *		  specifiy for any transition semantics)
146*f6e214c7SGavin Maltby  *
147*f6e214c7SGavin Maltby  * To split/refine such a Committed semantic_A into further cases,
148*f6e214c7SGavin Maltby  * we are required to bump the revision number.  This should be an
149*f6e214c7SGavin Maltby  * infrequent occurence.  If you bump the revision number you may
150*f6e214c7SGavin Maltby  * need to make corresponding changes in any source that calls
151*f6e214c7SGavin Maltby  * restarter_str_version (e.g., FMA event generation).
152*f6e214c7SGavin Maltby  *
153*f6e214c7SGavin Maltby  * To add additional reasons to the set you must also bump the version
154*f6e214c7SGavin Maltby  * number.
155*f6e214c7SGavin Maltby  */
156*f6e214c7SGavin Maltby 
157*f6e214c7SGavin Maltby /*
158*f6e214c7SGavin Maltby  * The following describes revision 0 of the set of transition reasons.
159*f6e214c7SGavin Maltby  * Read the preceding block comment before making any changes.
160*f6e214c7SGavin Maltby  */
161*f6e214c7SGavin Maltby static const struct restarter_state_transition_reason restarter_str[] = {
162*f6e214c7SGavin Maltby 	/*
163*f6e214c7SGavin Maltby 	 * Any transition for which the restarter has not provided a reason.
164*f6e214c7SGavin Maltby 	 */
165*f6e214c7SGavin Maltby 	{
166*f6e214c7SGavin Maltby 	    restarter_str_none,
167*f6e214c7SGavin Maltby 	    "none",
168*f6e214c7SGavin Maltby 	    "the restarter gave no reason"
169*f6e214c7SGavin Maltby 	},
170*f6e214c7SGavin Maltby 
171*f6e214c7SGavin Maltby 	/*
172*f6e214c7SGavin Maltby 	 * A transition to maintenance state due to a
173*f6e214c7SGavin Maltby 	 * 'svcadm mark maintenance <fmri>'.  *Not* used if the libscf
174*f6e214c7SGavin Maltby 	 * interface smf_maintain_instance(3SCF) is used to request maintenance.
175*f6e214c7SGavin Maltby 	 */
176*f6e214c7SGavin Maltby 	{
177*f6e214c7SGavin Maltby 	    restarter_str_administrative_request,
178*f6e214c7SGavin Maltby 	    "administrative_request",
179*f6e214c7SGavin Maltby 	    "maintenance was requested by an administrator"
180*f6e214c7SGavin Maltby 	},
181*f6e214c7SGavin Maltby 
182*f6e214c7SGavin Maltby 	/*
183*f6e214c7SGavin Maltby 	 * A transition to maintenance state if a repository inconsistency
184*f6e214c7SGavin Maltby 	 * exists when the service/instance state is first read by startd
185*f6e214c7SGavin Maltby 	 * into the graph engine (this can also happen during startd restart).
186*f6e214c7SGavin Maltby 	 */
187*f6e214c7SGavin Maltby 	{
188*f6e214c7SGavin Maltby 	    restarter_str_bad_repo_state,
189*f6e214c7SGavin Maltby 	    "bad_repo_state",
190*f6e214c7SGavin Maltby 	    "an SMF repository inconsistecy exists"
191*f6e214c7SGavin Maltby 	},
192*f6e214c7SGavin Maltby 
193*f6e214c7SGavin Maltby 	/*
194*f6e214c7SGavin Maltby 	 * A transition 'maintenance -> uninitialized' resulting always
195*f6e214c7SGavin Maltby 	 * from 'svcadm clear <fmri>'.  *Not* used if the libscf interface
196*f6e214c7SGavin Maltby 	 * smf_restore_instance(3SCF) is used.
197*f6e214c7SGavin Maltby 	 */
198*f6e214c7SGavin Maltby 	{
199*f6e214c7SGavin Maltby 	    restarter_str_clear_request,
200*f6e214c7SGavin Maltby 	    "clear_request",
201*f6e214c7SGavin Maltby 	    "maintenance clear was requested by an administrator"
202*f6e214c7SGavin Maltby 	},
203*f6e214c7SGavin Maltby 
204*f6e214c7SGavin Maltby 	/*
205*f6e214c7SGavin Maltby 	 * A transition 'online -> offline' due to a process core dump.
206*f6e214c7SGavin Maltby 	 */
207*f6e214c7SGavin Maltby 	{
208*f6e214c7SGavin Maltby 	    restarter_str_ct_ev_core,
209*f6e214c7SGavin Maltby 	    "ct_ev_core",
210*f6e214c7SGavin Maltby 	    "a process dumped core"
211*f6e214c7SGavin Maltby 	},
212*f6e214c7SGavin Maltby 
213*f6e214c7SGavin Maltby 	/*
214*f6e214c7SGavin Maltby 	 * A transition 'online -> offline' due to an empty process contract,
215*f6e214c7SGavin Maltby 	 * i.e., the last process in a contract type service has exited.
216*f6e214c7SGavin Maltby 	 */
217*f6e214c7SGavin Maltby 	{
218*f6e214c7SGavin Maltby 	    restarter_str_ct_ev_exit,
219*f6e214c7SGavin Maltby 	    "ct_ev_exit",
220*f6e214c7SGavin Maltby 	    "all processes in the service have exited"
221*f6e214c7SGavin Maltby 	},
222*f6e214c7SGavin Maltby 
223*f6e214c7SGavin Maltby 	/*
224*f6e214c7SGavin Maltby 	 * A transition 'online -> offline' due to a hardware error.
225*f6e214c7SGavin Maltby 	 */
226*f6e214c7SGavin Maltby 	{
227*f6e214c7SGavin Maltby 	    restarter_str_ct_ev_hwerr,
228*f6e214c7SGavin Maltby 	    "ct_ev_hwerr",
229*f6e214c7SGavin Maltby 	    "a process was killed due to uncorrectable hardware error"
230*f6e214c7SGavin Maltby 	},
231*f6e214c7SGavin Maltby 
232*f6e214c7SGavin Maltby 	/*
233*f6e214c7SGavin Maltby 	 * A transition 'online -> offline' due to a process in the service
234*f6e214c7SGavin Maltby 	 * having received a fatal signal originating from outside the
235*f6e214c7SGavin Maltby 	 * service process contract.
236*f6e214c7SGavin Maltby 	 */
237*f6e214c7SGavin Maltby 	{
238*f6e214c7SGavin Maltby 	    restarter_str_ct_ev_signal,
239*f6e214c7SGavin Maltby 	    "ct_ev_signal",
240*f6e214c7SGavin Maltby 	    "a process received a fatal signal from outside the service"
241*f6e214c7SGavin Maltby 	},
242*f6e214c7SGavin Maltby 
243*f6e214c7SGavin Maltby 	/*
244*f6e214c7SGavin Maltby 	 * A transition 'offline -> online' when all dependencies for the
245*f6e214c7SGavin Maltby 	 * service have been met.
246*f6e214c7SGavin Maltby 	 */
247*f6e214c7SGavin Maltby 	{
248*f6e214c7SGavin Maltby 	    restarter_str_dependencies_satisfied,
249*f6e214c7SGavin Maltby 	    "dependencies_satisfied",
250*f6e214c7SGavin Maltby 	    "all dependencies have been satisfied"
251*f6e214c7SGavin Maltby 	},
252*f6e214c7SGavin Maltby 
253*f6e214c7SGavin Maltby 	/*
254*f6e214c7SGavin Maltby 	 * A transition 'online -> offline' because some dependency for the
255*f6e214c7SGavin Maltby 	 * service is no-longer met.
256*f6e214c7SGavin Maltby 	 */
257*f6e214c7SGavin Maltby 	{
258*f6e214c7SGavin Maltby 	    restarter_str_dependency_activity,
259*f6e214c7SGavin Maltby 	    "dependency_activity",
260*f6e214c7SGavin Maltby 	    "a dependency activity required a stop"
261*f6e214c7SGavin Maltby 	},
262*f6e214c7SGavin Maltby 
263*f6e214c7SGavin Maltby 	/*
264*f6e214c7SGavin Maltby 	 * A transition to maintenance state due to a cycle in the
265*f6e214c7SGavin Maltby 	 * service dependencies.
266*f6e214c7SGavin Maltby 	 */
267*f6e214c7SGavin Maltby 	{
268*f6e214c7SGavin Maltby 	    restarter_str_dependency_cycle,
269*f6e214c7SGavin Maltby 	    "dependency_cycle",
270*f6e214c7SGavin Maltby 	    "a dependency cycle exists"
271*f6e214c7SGavin Maltby 	},
272*f6e214c7SGavin Maltby 
273*f6e214c7SGavin Maltby 	/*
274*f6e214c7SGavin Maltby 	 * A transition 'online -> offline -> disabled' due to a
275*f6e214c7SGavin Maltby 	 * 'svcadm disable [-t] <fmri>' or smf_disable_instance(3SCF) call.
276*f6e214c7SGavin Maltby 	 */
277*f6e214c7SGavin Maltby 	{
278*f6e214c7SGavin Maltby 	    restarter_str_disable_request,
279*f6e214c7SGavin Maltby 	    "disable_request",
280*f6e214c7SGavin Maltby 	    "a disable was requested"
281*f6e214c7SGavin Maltby 	},
282*f6e214c7SGavin Maltby 
283*f6e214c7SGavin Maltby 	/*
284*f6e214c7SGavin Maltby 	 * A transition 'disabled -> offline' due to a
285*f6e214c7SGavin Maltby 	 * 'svcadm enable [-t] <fmri>' or smf_enable_instance(3SCF) call.
286*f6e214c7SGavin Maltby 	 */
287*f6e214c7SGavin Maltby 	{
288*f6e214c7SGavin Maltby 	    restarter_str_enable_request,
289*f6e214c7SGavin Maltby 	    "enable_request",
290*f6e214c7SGavin Maltby 	    "an enable was requested"
291*f6e214c7SGavin Maltby 	},
292*f6e214c7SGavin Maltby 
293*f6e214c7SGavin Maltby 	/*
294*f6e214c7SGavin Maltby 	 * A transition to maintenance state when a method fails
295*f6e214c7SGavin Maltby 	 * repeatedly for a retryable reason.
296*f6e214c7SGavin Maltby 	 */
297*f6e214c7SGavin Maltby 	{
298*f6e214c7SGavin Maltby 	    restarter_str_fault_threshold_reached,
299*f6e214c7SGavin Maltby 	    "fault_threshold_reached",
300*f6e214c7SGavin Maltby 	    "a method is failing in a retryable manner but too often"
301*f6e214c7SGavin Maltby 	},
302*f6e214c7SGavin Maltby 
303*f6e214c7SGavin Maltby 	/*
304*f6e214c7SGavin Maltby 	 * A transition to uninitialized state when startd reads the service
305*f6e214c7SGavin Maltby 	 * configuration and inserts it into the graph engine.
306*f6e214c7SGavin Maltby 	 */
307*f6e214c7SGavin Maltby 	{
308*f6e214c7SGavin Maltby 	    restarter_str_insert_in_graph,
309*f6e214c7SGavin Maltby 	    "insert_in_graph",
310*f6e214c7SGavin Maltby 	    "the instance was inserted in the graph"
311*f6e214c7SGavin Maltby 	},
312*f6e214c7SGavin Maltby 
313*f6e214c7SGavin Maltby 	/*
314*f6e214c7SGavin Maltby 	 * A transition to maintenance state due to an invalid dependency
315*f6e214c7SGavin Maltby 	 * declared for the service.
316*f6e214c7SGavin Maltby 	 */
317*f6e214c7SGavin Maltby 	{
318*f6e214c7SGavin Maltby 	    restarter_str_invalid_dependency,
319*f6e214c7SGavin Maltby 	    "invalid_dependency",
320*f6e214c7SGavin Maltby 	    "a service has an invalid dependency"
321*f6e214c7SGavin Maltby 	},
322*f6e214c7SGavin Maltby 
323*f6e214c7SGavin Maltby 	/*
324*f6e214c7SGavin Maltby 	 * A transition to maintenance state because the service-declared
325*f6e214c7SGavin Maltby 	 * restarter is invalid.
326*f6e214c7SGavin Maltby 	 */
327*f6e214c7SGavin Maltby 	{
328*f6e214c7SGavin Maltby 	    restarter_str_invalid_restarter,
329*f6e214c7SGavin Maltby 	    "invalid_restarter",
330*f6e214c7SGavin Maltby 	    "the service restarter is invalid"
331*f6e214c7SGavin Maltby 	},
332*f6e214c7SGavin Maltby 
333*f6e214c7SGavin Maltby 	/*
334*f6e214c7SGavin Maltby 	 * A transition to maintenance state because a restarter method
335*f6e214c7SGavin Maltby 	 * exited with one of SMF_EXIT_ERR_CONFIG, SMF_EXIT_ERR_NOSMF,
336*f6e214c7SGavin Maltby 	 * SMF_EXIT_ERR_PERM, or SMF_EXIT_ERR_FATAL.
337*f6e214c7SGavin Maltby 	 */
338*f6e214c7SGavin Maltby 	{
339*f6e214c7SGavin Maltby 	    restarter_str_method_failed,
340*f6e214c7SGavin Maltby 	    "method_failed",
341*f6e214c7SGavin Maltby 	    "a start, stop or refresh method failed"
342*f6e214c7SGavin Maltby 	},
343*f6e214c7SGavin Maltby 
344*f6e214c7SGavin Maltby 	/*
345*f6e214c7SGavin Maltby 	 * A transition 'uninitialized -> {disabled|offline}' after
346*f6e214c7SGavin Maltby 	 * "insert_in_graph" to match the state configured in the
347*f6e214c7SGavin Maltby 	 * repository.
348*f6e214c7SGavin Maltby 	 */
349*f6e214c7SGavin Maltby 	{
350*f6e214c7SGavin Maltby 	    restarter_str_per_configuration,
351*f6e214c7SGavin Maltby 	    "per_configuration",
352*f6e214c7SGavin Maltby 	    "the SMF repository configuration specifies this state"
353*f6e214c7SGavin Maltby 	},
354*f6e214c7SGavin Maltby 
355*f6e214c7SGavin Maltby 	/*
356*f6e214c7SGavin Maltby 	 * Refresh requested - no state change.
357*f6e214c7SGavin Maltby 	 */
358*f6e214c7SGavin Maltby 	{
359*f6e214c7SGavin Maltby 	    restarter_str_refresh,
360*f6e214c7SGavin Maltby 	    NULL,
361*f6e214c7SGavin Maltby 	    "a refresh was requested (no change of state)"
362*f6e214c7SGavin Maltby 	},
363*f6e214c7SGavin Maltby 
364*f6e214c7SGavin Maltby 	/*
365*f6e214c7SGavin Maltby 	 * A transition 'online -> offline -> online' due to a
366*f6e214c7SGavin Maltby 	 * 'svcadm restart <fmri> or equivlaent libscf API call.
367*f6e214c7SGavin Maltby 	 * Both the 'online -> offline' and 'offline -> online' transtions
368*f6e214c7SGavin Maltby 	 * specify this reason.
369*f6e214c7SGavin Maltby 	 */
370*f6e214c7SGavin Maltby 	{
371*f6e214c7SGavin Maltby 	    restarter_str_restart_request,
372*f6e214c7SGavin Maltby 	    "restart_request",
373*f6e214c7SGavin Maltby 	    "a restart was requested"
374*f6e214c7SGavin Maltby 	},
375*f6e214c7SGavin Maltby 
376*f6e214c7SGavin Maltby 	/*
377*f6e214c7SGavin Maltby 	 * A transition to maintenance state because the start method is
378*f6e214c7SGavin Maltby 	 * being executed successfully but too frequently.
379*f6e214c7SGavin Maltby 	 */
380*f6e214c7SGavin Maltby 	{
381*f6e214c7SGavin Maltby 	    restarter_str_restarting_too_quickly,
382*f6e214c7SGavin Maltby 	    "restarting_too_quickly",
383*f6e214c7SGavin Maltby 	    "the instance is restarting too quickly"
384*f6e214c7SGavin Maltby 	},
385*f6e214c7SGavin Maltby 
386*f6e214c7SGavin Maltby 	/*
387*f6e214c7SGavin Maltby 	 * A transition to maintenance state due a service requesting
388*f6e214c7SGavin Maltby 	 * 'svcadm mark maintenance <fmri>' or equivalent libscf API call.
389*f6e214c7SGavin Maltby 	 * A command line 'svcadm mark maintenance <fmri>' does not produce
390*f6e214c7SGavin Maltby 	 * this reason - it produces administrative_request instead.
391*f6e214c7SGavin Maltby 	 */
392*f6e214c7SGavin Maltby 	{
393*f6e214c7SGavin Maltby 	    restarter_str_service_request,
394*f6e214c7SGavin Maltby 	    "service_request",
395*f6e214c7SGavin Maltby 	    "maintenance was requested by another service"
396*f6e214c7SGavin Maltby 	},
397*f6e214c7SGavin Maltby 
398*f6e214c7SGavin Maltby 	/*
399*f6e214c7SGavin Maltby 	 * An instanced inserted into the graph at its existing state
400*f6e214c7SGavin Maltby 	 * during a startd restart - no state change.
401*f6e214c7SGavin Maltby 	 */
402*f6e214c7SGavin Maltby 	{
403*f6e214c7SGavin Maltby 	    restarter_str_startd_restart,
404*f6e214c7SGavin Maltby 	    NULL,
405*f6e214c7SGavin Maltby 	    "the instance was inserted in the graph due to startd restart"
406*f6e214c7SGavin Maltby 	}
407*f6e214c7SGavin Maltby };
408*f6e214c7SGavin Maltby 
409*f6e214c7SGavin Maltby uint32_t
410*f6e214c7SGavin Maltby restarter_str_version(void)
411*f6e214c7SGavin Maltby {
412*f6e214c7SGavin Maltby 	return (RESTARTER_STRING_VERSION);
413*f6e214c7SGavin Maltby }
414*f6e214c7SGavin Maltby 
415*f6e214c7SGavin Maltby const char *
416*f6e214c7SGavin Maltby restarter_get_str_short(restarter_str_t key)
417*f6e214c7SGavin Maltby {
418*f6e214c7SGavin Maltby 	int i;
419*f6e214c7SGavin Maltby 	for (i = 0; i < sizeof (restarter_str) /
420*f6e214c7SGavin Maltby 	    sizeof (struct restarter_state_transition_reason); i++)
421*f6e214c7SGavin Maltby 		if (key == restarter_str[i].str_key)
422*f6e214c7SGavin Maltby 			return (restarter_str[i].str_short);
423*f6e214c7SGavin Maltby 	return (NULL);
424*f6e214c7SGavin Maltby }
425*f6e214c7SGavin Maltby 
426*f6e214c7SGavin Maltby const char *
427*f6e214c7SGavin Maltby restarter_get_str_long(restarter_str_t key)
428*f6e214c7SGavin Maltby {
429*f6e214c7SGavin Maltby 	int i;
430*f6e214c7SGavin Maltby 	for (i = 0; i < sizeof (restarter_str) /
431*f6e214c7SGavin Maltby 	    sizeof (struct restarter_state_transition_reason); i++)
432*f6e214c7SGavin Maltby 		if (key == restarter_str[i].str_key)
433*f6e214c7SGavin Maltby 			return (dgettext(TEXT_DOMAIN,
434*f6e214c7SGavin Maltby 			    restarter_str[i].str_long));
435*f6e214c7SGavin Maltby 	return (NULL);
436*f6e214c7SGavin Maltby }
437*f6e214c7SGavin Maltby 
438*f6e214c7SGavin Maltby /*
439870ad75aSSean Wilcox  * A static no memory error message mc_error_t structure
440870ad75aSSean Wilcox  * to be used in cases when memory errors are to be returned
441870ad75aSSean Wilcox  * This avoids the need to attempt to allocate memory for the
442870ad75aSSean Wilcox  * message, therefore getting into a cycle of no memory failures.
443870ad75aSSean Wilcox  */
444870ad75aSSean Wilcox mc_error_t mc_nomem_err = {
445870ad75aSSean Wilcox 	0, ENOMEM, sizeof ("Out of memory") - 1, "Out of memory"
446870ad75aSSean Wilcox };
447870ad75aSSean Wilcox 
4487c478bd9Sstevel@tonic-gate static const char * const allocfail = "Allocation failure.\n";
4497c478bd9Sstevel@tonic-gate static const char * const rcbroken = "Repository connection broken.\n";
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate static int method_context_safety = 0;	/* Can safely call pools/projects. */
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate int ndebug = 1;
4547c478bd9Sstevel@tonic-gate 
455870ad75aSSean Wilcox /* PRINTFLIKE3 */
456870ad75aSSean Wilcox static mc_error_t *
457870ad75aSSean Wilcox mc_error_create(mc_error_t *e, int type, const char *format, ...)
458870ad75aSSean Wilcox {
459870ad75aSSean Wilcox 	mc_error_t	*le;
460870ad75aSSean Wilcox 	va_list		args;
461870ad75aSSean Wilcox 	int		size;
462870ad75aSSean Wilcox 
463870ad75aSSean Wilcox 	/*
464870ad75aSSean Wilcox 	 * If the type is ENOMEM and format is NULL, then
465870ad75aSSean Wilcox 	 * go ahead and return the default nomem error.
466870ad75aSSean Wilcox 	 * Otherwise, attempt to allocate the memory and if
467870ad75aSSean Wilcox 	 * that fails then there is no reason to continue.
468870ad75aSSean Wilcox 	 */
469870ad75aSSean Wilcox 	if (type == ENOMEM && format == NULL)
470870ad75aSSean Wilcox 		return (&mc_nomem_err);
471870ad75aSSean Wilcox 
472870ad75aSSean Wilcox 	if (e == NULL && (le = malloc(sizeof (mc_error_t))) == NULL)
473870ad75aSSean Wilcox 		return (&mc_nomem_err);
474870ad75aSSean Wilcox 	else
475870ad75aSSean Wilcox 		le = e;
476870ad75aSSean Wilcox 
477870ad75aSSean Wilcox 	le->type = type;
478870ad75aSSean Wilcox 	le->destroy = 1;
479870ad75aSSean Wilcox 	va_start(args, format);
480870ad75aSSean Wilcox 	size = vsnprintf(NULL, 0, format, args) + 1;
481870ad75aSSean Wilcox 	if (size >= RESTARTER_ERRMSGSZ) {
482870ad75aSSean Wilcox 		if ((le = realloc(e, sizeof (mc_error_t) +
483870ad75aSSean Wilcox 		    (size - RESTARTER_ERRMSGSZ))) == NULL) {
484870ad75aSSean Wilcox 			size = RESTARTER_ERRMSGSZ - 1;
485870ad75aSSean Wilcox 			le = e;
486870ad75aSSean Wilcox 		}
487870ad75aSSean Wilcox 	}
488870ad75aSSean Wilcox 
489870ad75aSSean Wilcox 	le->size = size;
490870ad75aSSean Wilcox 	(void) vsnprintf(le->msg, le->size, format, args);
491870ad75aSSean Wilcox 	va_end(args);
492870ad75aSSean Wilcox 
493870ad75aSSean Wilcox 	return (le);
494870ad75aSSean Wilcox }
495870ad75aSSean Wilcox 
496870ad75aSSean Wilcox void
497870ad75aSSean Wilcox restarter_mc_error_destroy(mc_error_t *mc_err)
498870ad75aSSean Wilcox {
499870ad75aSSean Wilcox 	if (mc_err == NULL)
500870ad75aSSean Wilcox 		return;
501870ad75aSSean Wilcox 
502870ad75aSSean Wilcox 	/*
503870ad75aSSean Wilcox 	 * If the error messages was allocated then free.
504870ad75aSSean Wilcox 	 */
505870ad75aSSean Wilcox 	if (mc_err->destroy) {
506870ad75aSSean Wilcox 		free(mc_err);
507870ad75aSSean Wilcox 	}
508870ad75aSSean Wilcox }
509870ad75aSSean Wilcox 
5107c478bd9Sstevel@tonic-gate static void
5117c478bd9Sstevel@tonic-gate free_restarter_event_handle(struct restarter_event_handle *h)
5127c478bd9Sstevel@tonic-gate {
5137c478bd9Sstevel@tonic-gate 	if (h == NULL)
5147c478bd9Sstevel@tonic-gate 		return;
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate 	/*
5177c478bd9Sstevel@tonic-gate 	 * Just free the memory -- don't unbind the sysevent handle,
5187c478bd9Sstevel@tonic-gate 	 * as otherwise events may be lost if this is just a restarter
5197c478bd9Sstevel@tonic-gate 	 * restart.
5207c478bd9Sstevel@tonic-gate 	 */
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate 	if (h->reh_restarter_name != NULL)
5237c478bd9Sstevel@tonic-gate 		free(h->reh_restarter_name);
5247c478bd9Sstevel@tonic-gate 	if (h->reh_delegate_channel_name != NULL)
5257c478bd9Sstevel@tonic-gate 		free(h->reh_delegate_channel_name);
5267c478bd9Sstevel@tonic-gate 	if (h->reh_delegate_subscriber_id != NULL)
5277c478bd9Sstevel@tonic-gate 		free(h->reh_delegate_subscriber_id);
5287c478bd9Sstevel@tonic-gate 	if (h->reh_master_channel_name != NULL)
5297c478bd9Sstevel@tonic-gate 		free(h->reh_master_channel_name);
5307c478bd9Sstevel@tonic-gate 	if (h->reh_master_subscriber_id != NULL)
5317c478bd9Sstevel@tonic-gate 		free(h->reh_master_subscriber_id);
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate 	free(h);
5347c478bd9Sstevel@tonic-gate }
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate char *
5377c478bd9Sstevel@tonic-gate _restarter_get_channel_name(const char *fmri, int type)
5387c478bd9Sstevel@tonic-gate {
53913d8aaa1SSean Wilcox 	char *name;
5407c478bd9Sstevel@tonic-gate 	char *chan_name = malloc(MAX_CHNAME_LEN);
5417c478bd9Sstevel@tonic-gate 	char prefix_name[3];
54213d8aaa1SSean Wilcox 	int i;
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate 	if (chan_name == NULL)
5457c478bd9Sstevel@tonic-gate 		return (NULL);
5467c478bd9Sstevel@tonic-gate 
5477c478bd9Sstevel@tonic-gate 	if (type == RESTARTER_CHANNEL_DELEGATE)
5487c478bd9Sstevel@tonic-gate 		(void) strcpy(prefix_name, "d_");
5497c478bd9Sstevel@tonic-gate 	else if (type == RESTARTER_CHANNEL_MASTER)
5507c478bd9Sstevel@tonic-gate 		(void) strcpy(prefix_name, "m_");
5517c478bd9Sstevel@tonic-gate 	else {
5527c478bd9Sstevel@tonic-gate 		free(chan_name);
5537c478bd9Sstevel@tonic-gate 		return (NULL);
5547c478bd9Sstevel@tonic-gate 	}
5557c478bd9Sstevel@tonic-gate 
55613d8aaa1SSean Wilcox 	/*
55713d8aaa1SSean Wilcox 	 * Create a unique name
55813d8aaa1SSean Wilcox 	 *
55913d8aaa1SSean Wilcox 	 * Use the entire name, using a replacement of the /
56013d8aaa1SSean Wilcox 	 * characters to get a better name.
56113d8aaa1SSean Wilcox 	 *
56213d8aaa1SSean Wilcox 	 * Remove the svc:/ from the beginning as this really
56313d8aaa1SSean Wilcox 	 * isn't going to provide any uniqueness...
56413d8aaa1SSean Wilcox 	 *
56513d8aaa1SSean Wilcox 	 * An fmri name greater than MAX_CHNAME_LEN is going
56613d8aaa1SSean Wilcox 	 * to be rejected as too long for the chan_name below
56713d8aaa1SSean Wilcox 	 * in the snprintf call.
56813d8aaa1SSean Wilcox 	 */
56913d8aaa1SSean Wilcox 	if ((name = strdup(strchr(fmri, '/') + 1)) == NULL) {
57013d8aaa1SSean Wilcox 		free(chan_name);
57113d8aaa1SSean Wilcox 		return (NULL);
57213d8aaa1SSean Wilcox 	}
57313d8aaa1SSean Wilcox 	i = 0;
57413d8aaa1SSean Wilcox 	while (name[i]) {
57513d8aaa1SSean Wilcox 		if (name[i] == '/') {
57613d8aaa1SSean Wilcox 			name[i] = '_';
57713d8aaa1SSean Wilcox 		}
57813d8aaa1SSean Wilcox 
57913d8aaa1SSean Wilcox 		i++;
58013d8aaa1SSean Wilcox 	}
5817c478bd9Sstevel@tonic-gate 
5827c478bd9Sstevel@tonic-gate 	/*
5837c478bd9Sstevel@tonic-gate 	 * Should check for [a-z],[A-Z],[0-9],.,_,-,:
5847c478bd9Sstevel@tonic-gate 	 */
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate 	if (snprintf(chan_name, MAX_CHNAME_LEN, "com.sun:scf:%s%s",
5877c478bd9Sstevel@tonic-gate 	    prefix_name, name) > MAX_CHNAME_LEN) {
5887c478bd9Sstevel@tonic-gate 		free(chan_name);
58913d8aaa1SSean Wilcox 		chan_name = NULL;
5907c478bd9Sstevel@tonic-gate 	}
5917c478bd9Sstevel@tonic-gate 
59213d8aaa1SSean Wilcox 	free(name);
5937c478bd9Sstevel@tonic-gate 	return (chan_name);
5947c478bd9Sstevel@tonic-gate }
5957c478bd9Sstevel@tonic-gate 
5967c478bd9Sstevel@tonic-gate int
5977c478bd9Sstevel@tonic-gate cb(sysevent_t *syse, void *cookie)
5987c478bd9Sstevel@tonic-gate {
5997c478bd9Sstevel@tonic-gate 	restarter_event_handle_t *h = (restarter_event_handle_t *)cookie;
6007c478bd9Sstevel@tonic-gate 	restarter_event_t *e;
6017c478bd9Sstevel@tonic-gate 	nvlist_t *attr_list = NULL;
6027c478bd9Sstevel@tonic-gate 	int ret = 0;
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate 	e = uu_zalloc(sizeof (restarter_event_t));
6057c478bd9Sstevel@tonic-gate 	if (e == NULL)
6067c478bd9Sstevel@tonic-gate 		uu_die(allocfail);
6077c478bd9Sstevel@tonic-gate 	e->re_event_handle = h;
6087c478bd9Sstevel@tonic-gate 	e->re_sysevent = syse;
6097c478bd9Sstevel@tonic-gate 
6107c478bd9Sstevel@tonic-gate 	if (sysevent_get_attr_list(syse, &attr_list) != 0)
6117c478bd9Sstevel@tonic-gate 		uu_die(allocfail);
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate 	if ((nvlist_lookup_uint32(attr_list, RESTARTER_NAME_TYPE,
6147c478bd9Sstevel@tonic-gate 	    &(e->re_type)) != 0) ||
6157c478bd9Sstevel@tonic-gate 	    (nvlist_lookup_string(attr_list,
6167c478bd9Sstevel@tonic-gate 	    RESTARTER_NAME_INSTANCE, &(e->re_instance_name)) != 0)) {
6177c478bd9Sstevel@tonic-gate 		uu_warn("%s: Can't decode nvlist for event %p\n",
6187c478bd9Sstevel@tonic-gate 		    h->reh_restarter_name, (void *)syse);
6197c478bd9Sstevel@tonic-gate 
6207c478bd9Sstevel@tonic-gate 		ret = 0;
6217c478bd9Sstevel@tonic-gate 	} else {
6227c478bd9Sstevel@tonic-gate 		ret = h->reh_handler(e);
6237c478bd9Sstevel@tonic-gate 	}
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate 	uu_free(e);
6267c478bd9Sstevel@tonic-gate 	nvlist_free(attr_list);
6277c478bd9Sstevel@tonic-gate 	return (ret);
6287c478bd9Sstevel@tonic-gate }
6297c478bd9Sstevel@tonic-gate 
6307c478bd9Sstevel@tonic-gate /*
6317c478bd9Sstevel@tonic-gate  * restarter_bind_handle(uint32_t, char *, int (*)(restarter_event_t *), int,
6327c478bd9Sstevel@tonic-gate  *     restarter_event_handle_t **)
6337c478bd9Sstevel@tonic-gate  *
6347c478bd9Sstevel@tonic-gate  * Bind to a delegated restarter event channel.
6357c478bd9Sstevel@tonic-gate  * Each delegated restarter gets its own channel for resource management.
6367c478bd9Sstevel@tonic-gate  *
6377c478bd9Sstevel@tonic-gate  * Returns 0 on success or
6387c478bd9Sstevel@tonic-gate  *   ENOTSUP	version mismatch
6397c478bd9Sstevel@tonic-gate  *   EINVAL	restarter_name or event_handle is NULL
6407c478bd9Sstevel@tonic-gate  *   ENOMEM	out of memory, too many channels, or too many subscriptions
6417c478bd9Sstevel@tonic-gate  *   EBUSY	sysevent_evc_bind() could not establish binding
6427c478bd9Sstevel@tonic-gate  *   EFAULT	internal sysevent_evc_bind()/sysevent_evc_subscribe() error
6437c478bd9Sstevel@tonic-gate  *   EMFILE	out of file descriptors
6447c478bd9Sstevel@tonic-gate  *   EPERM	insufficient privilege for sysevent_evc_bind()
6457c478bd9Sstevel@tonic-gate  *   EEXIST	already subscribed
6467c478bd9Sstevel@tonic-gate  */
6477c478bd9Sstevel@tonic-gate int
6487c478bd9Sstevel@tonic-gate restarter_bind_handle(uint32_t version, const char *restarter_name,
6497c478bd9Sstevel@tonic-gate     int (*event_handler)(restarter_event_t *), int flags,
6507c478bd9Sstevel@tonic-gate     restarter_event_handle_t **rehp)
6517c478bd9Sstevel@tonic-gate {
6527c478bd9Sstevel@tonic-gate 	restarter_event_handle_t *h;
6537c478bd9Sstevel@tonic-gate 	size_t sz;
6547c478bd9Sstevel@tonic-gate 	int err;
6557c478bd9Sstevel@tonic-gate 
6567c478bd9Sstevel@tonic-gate 	if (version != RESTARTER_EVENT_VERSION)
6577c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
6587c478bd9Sstevel@tonic-gate 
6597c478bd9Sstevel@tonic-gate 	if (restarter_name == NULL || event_handler == NULL)
6607c478bd9Sstevel@tonic-gate 		return (EINVAL);
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate 	if (flags & RESTARTER_FLAG_DEBUG)
6637c478bd9Sstevel@tonic-gate 		ndebug++;
6647c478bd9Sstevel@tonic-gate 
6657c478bd9Sstevel@tonic-gate 	if ((h = uu_zalloc(sizeof (restarter_event_handle_t))) == NULL)
6667c478bd9Sstevel@tonic-gate 		return (ENOMEM);
6677c478bd9Sstevel@tonic-gate 
6687c478bd9Sstevel@tonic-gate 	h->reh_delegate_subscriber_id = malloc(MAX_SUBID_LEN);
6697c478bd9Sstevel@tonic-gate 	h->reh_master_subscriber_id = malloc(MAX_SUBID_LEN);
6707c478bd9Sstevel@tonic-gate 	h->reh_restarter_name = strdup(restarter_name);
6717c478bd9Sstevel@tonic-gate 	if (h->reh_delegate_subscriber_id == NULL ||
6727c478bd9Sstevel@tonic-gate 	    h->reh_master_subscriber_id == NULL ||
6737c478bd9Sstevel@tonic-gate 	    h->reh_restarter_name == NULL) {
6747c478bd9Sstevel@tonic-gate 		free_restarter_event_handle(h);
6757c478bd9Sstevel@tonic-gate 		return (ENOMEM);
6767c478bd9Sstevel@tonic-gate 	}
6777c478bd9Sstevel@tonic-gate 
6787c478bd9Sstevel@tonic-gate 	sz = strlcpy(h->reh_delegate_subscriber_id, "del", MAX_SUBID_LEN);
6797c478bd9Sstevel@tonic-gate 	assert(sz < MAX_SUBID_LEN);
6807c478bd9Sstevel@tonic-gate 	sz = strlcpy(h->reh_master_subscriber_id, "master", MAX_SUBID_LEN);
6817c478bd9Sstevel@tonic-gate 	assert(sz < MAX_SUBID_LEN);
6827c478bd9Sstevel@tonic-gate 
6837c478bd9Sstevel@tonic-gate 	h->reh_delegate_channel_name =
6847c478bd9Sstevel@tonic-gate 	    _restarter_get_channel_name(restarter_name,
6857c478bd9Sstevel@tonic-gate 	    RESTARTER_CHANNEL_DELEGATE);
6867c478bd9Sstevel@tonic-gate 	h->reh_master_channel_name =
6877c478bd9Sstevel@tonic-gate 	    _restarter_get_channel_name(restarter_name,
6887c478bd9Sstevel@tonic-gate 	    RESTARTER_CHANNEL_MASTER);
6897c478bd9Sstevel@tonic-gate 
6907c478bd9Sstevel@tonic-gate 	if (h->reh_delegate_channel_name == NULL ||
6917c478bd9Sstevel@tonic-gate 	    h->reh_master_channel_name == NULL) {
6927c478bd9Sstevel@tonic-gate 		free_restarter_event_handle(h);
6937c478bd9Sstevel@tonic-gate 		return (ENOMEM);
6947c478bd9Sstevel@tonic-gate 	}
6957c478bd9Sstevel@tonic-gate 
6967c478bd9Sstevel@tonic-gate 	if (sysevent_evc_bind(h->reh_delegate_channel_name,
6977c478bd9Sstevel@tonic-gate 	    &h->reh_delegate_channel, EVCH_CREAT|EVCH_HOLD_PEND) != 0) {
6987c478bd9Sstevel@tonic-gate 		err = errno;
6997c478bd9Sstevel@tonic-gate 		assert(err != EINVAL);
7007c478bd9Sstevel@tonic-gate 		assert(err != ENOENT);
7017c478bd9Sstevel@tonic-gate 		free_restarter_event_handle(h);
7027c478bd9Sstevel@tonic-gate 		return (err);
7037c478bd9Sstevel@tonic-gate 	}
7047c478bd9Sstevel@tonic-gate 
7057c478bd9Sstevel@tonic-gate 	if (sysevent_evc_bind(h->reh_master_channel_name,
7067c478bd9Sstevel@tonic-gate 	    &h->reh_master_channel, EVCH_CREAT|EVCH_HOLD_PEND) != 0) {
7077c478bd9Sstevel@tonic-gate 		err = errno;
7087c478bd9Sstevel@tonic-gate 		assert(err != EINVAL);
7097c478bd9Sstevel@tonic-gate 		assert(err != ENOENT);
7107c478bd9Sstevel@tonic-gate 		free_restarter_event_handle(h);
7117c478bd9Sstevel@tonic-gate 		return (err);
7127c478bd9Sstevel@tonic-gate 	}
7137c478bd9Sstevel@tonic-gate 
7147c478bd9Sstevel@tonic-gate 	h->reh_handler = event_handler;
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate 	assert(strlen(restarter_name) <= MAX_CLASS_LEN - 1);
7177c478bd9Sstevel@tonic-gate 	assert(strlen(h->reh_delegate_subscriber_id) <= MAX_SUBID_LEN - 1);
7187c478bd9Sstevel@tonic-gate 	assert(strlen(h->reh_master_subscriber_id) <= MAX_SUBID_LEN - 1);
7197c478bd9Sstevel@tonic-gate 
7207c478bd9Sstevel@tonic-gate 	if (sysevent_evc_subscribe(h->reh_delegate_channel,
7217c478bd9Sstevel@tonic-gate 	    h->reh_delegate_subscriber_id, EC_ALL, cb, h, EVCH_SUB_KEEP) != 0) {
7227c478bd9Sstevel@tonic-gate 		err = errno;
7237c478bd9Sstevel@tonic-gate 		assert(err != EINVAL);
7247c478bd9Sstevel@tonic-gate 		free_restarter_event_handle(h);
7257c478bd9Sstevel@tonic-gate 		return (err);
7267c478bd9Sstevel@tonic-gate 	}
7277c478bd9Sstevel@tonic-gate 
7287c478bd9Sstevel@tonic-gate 	*rehp = h;
7297c478bd9Sstevel@tonic-gate 	return (0);
7307c478bd9Sstevel@tonic-gate }
7317c478bd9Sstevel@tonic-gate 
7327c478bd9Sstevel@tonic-gate restarter_event_handle_t *
7337c478bd9Sstevel@tonic-gate restarter_event_get_handle(restarter_event_t *e)
7347c478bd9Sstevel@tonic-gate {
7357c478bd9Sstevel@tonic-gate 	assert(e != NULL && e->re_event_handle != NULL);
7367c478bd9Sstevel@tonic-gate 	return (e->re_event_handle);
7377c478bd9Sstevel@tonic-gate }
7387c478bd9Sstevel@tonic-gate 
7397c478bd9Sstevel@tonic-gate restarter_event_type_t
7407c478bd9Sstevel@tonic-gate restarter_event_get_type(restarter_event_t *e)
7417c478bd9Sstevel@tonic-gate {
7427c478bd9Sstevel@tonic-gate 	assert(e != NULL);
7437c478bd9Sstevel@tonic-gate 	return (e->re_type);
7447c478bd9Sstevel@tonic-gate }
7457c478bd9Sstevel@tonic-gate 
7467c478bd9Sstevel@tonic-gate ssize_t
7477c478bd9Sstevel@tonic-gate restarter_event_get_instance(restarter_event_t *e, char *inst, size_t sz)
7487c478bd9Sstevel@tonic-gate {
7497c478bd9Sstevel@tonic-gate 	assert(e != NULL && inst != NULL);
7507c478bd9Sstevel@tonic-gate 	return ((ssize_t)strlcpy(inst, e->re_instance_name, sz));
7517c478bd9Sstevel@tonic-gate }
7527c478bd9Sstevel@tonic-gate 
7537c478bd9Sstevel@tonic-gate int
7547c478bd9Sstevel@tonic-gate restarter_event_get_current_states(restarter_event_t *e,
7557c478bd9Sstevel@tonic-gate     restarter_instance_state_t *state, restarter_instance_state_t *next_state)
7567c478bd9Sstevel@tonic-gate {
7577c478bd9Sstevel@tonic-gate 	if (e == NULL)
7587c478bd9Sstevel@tonic-gate 		return (-1);
7597c478bd9Sstevel@tonic-gate 	*state = e->re_state;
7607c478bd9Sstevel@tonic-gate 	*next_state = e->re_next_state;
7617c478bd9Sstevel@tonic-gate 	return (0);
7627c478bd9Sstevel@tonic-gate }
7637c478bd9Sstevel@tonic-gate 
7647c478bd9Sstevel@tonic-gate /*
7652c65c8b0Srm88369  * restarter_event_publish_retry() is a wrapper around sysevent_evc_publish().
7662c65c8b0Srm88369  * In case, the event cannot be sent at the first attempt (sysevent_evc_publish
7672c65c8b0Srm88369  * returned EAGAIN - sysevent queue full), this function retries a few time
7682c65c8b0Srm88369  * and return ENOSPC if it reaches the retry limit.
7692c65c8b0Srm88369  *
7702c65c8b0Srm88369  * The arguments to this function map the arguments of sysevent_evc_publish().
7712c65c8b0Srm88369  *
7722c65c8b0Srm88369  * On success, return 0. On error, return
7732c65c8b0Srm88369  *
7742c65c8b0Srm88369  *   EFAULT - internal sysevent_evc_publish() error
7752c65c8b0Srm88369  *   ENOMEM - internal sysevent_evc_publish() error
7762c65c8b0Srm88369  *   EBADF - scp is invalid (sysevent_evc_publish() returned EINVAL)
7772c65c8b0Srm88369  *   ENOSPC - sysevent queue full (sysevent_evc_publish() returned EAGAIN)
7782c65c8b0Srm88369  */
7792c65c8b0Srm88369 int
7802c65c8b0Srm88369 restarter_event_publish_retry(evchan_t *scp, const char *class,
7812c65c8b0Srm88369     const char *subclass, const char *vendor, const char *pub_name,
7822c65c8b0Srm88369     nvlist_t *attr_list, uint32_t flags)
7832c65c8b0Srm88369 {
7842c65c8b0Srm88369 	int retries, ret;
7852c65c8b0Srm88369 	useconds_t retry_int = INITIAL_COMMIT_RETRY_INT;
7862c65c8b0Srm88369 
7872c65c8b0Srm88369 	for (retries = 0; retries < MAX_COMMIT_RETRIES; retries++) {
7882c65c8b0Srm88369 		ret = sysevent_evc_publish(scp, class, subclass, vendor,
7892c65c8b0Srm88369 		    pub_name, attr_list, flags);
7902c65c8b0Srm88369 		if (ret == 0)
7912c65c8b0Srm88369 			break;
7922c65c8b0Srm88369 
7932c65c8b0Srm88369 		switch (ret) {
7942c65c8b0Srm88369 		case EAGAIN:
7952c65c8b0Srm88369 			/* Queue is full */
7962c65c8b0Srm88369 			(void) usleep(retry_int);
7972c65c8b0Srm88369 
7982c65c8b0Srm88369 			retry_int = min(retry_int * 2, MAX_COMMIT_RETRY_INT);
7992c65c8b0Srm88369 			break;
8002c65c8b0Srm88369 
8012c65c8b0Srm88369 		case EINVAL:
8022c65c8b0Srm88369 			ret = EBADF;
8032c65c8b0Srm88369 			/* FALLTHROUGH */
8042c65c8b0Srm88369 
8052c65c8b0Srm88369 		case EFAULT:
8062c65c8b0Srm88369 		case ENOMEM:
8072c65c8b0Srm88369 			return (ret);
8082c65c8b0Srm88369 
8092c65c8b0Srm88369 		case EOVERFLOW:
8102c65c8b0Srm88369 		default:
8112c65c8b0Srm88369 			/* internal error - abort */
8122c65c8b0Srm88369 			bad_fail("sysevent_evc_publish", ret);
8132c65c8b0Srm88369 		}
8142c65c8b0Srm88369 	}
8152c65c8b0Srm88369 
8162c65c8b0Srm88369 	if (retries == MAX_COMMIT_RETRIES)
8172c65c8b0Srm88369 		ret = ENOSPC;
8182c65c8b0Srm88369 
8192c65c8b0Srm88369 	return (ret);
8202c65c8b0Srm88369 }
8212c65c8b0Srm88369 
8222c65c8b0Srm88369 /*
8237c478bd9Sstevel@tonic-gate  * Commit the state, next state, and auxiliary state into the repository.
8247c478bd9Sstevel@tonic-gate  * Let the graph engine know about the state change and error.  On success,
8257c478bd9Sstevel@tonic-gate  * return 0. On error, return
8267c478bd9Sstevel@tonic-gate  *   EPROTO - librestart compiled against different libscf
8277c478bd9Sstevel@tonic-gate  *   ENOMEM - out of memory
8287c478bd9Sstevel@tonic-gate  *	    - repository server out of resources
8297c478bd9Sstevel@tonic-gate  *   ENOTACTIVE - repository server not running
8307c478bd9Sstevel@tonic-gate  *   ECONNABORTED - repository connection established, but then broken
8317c478bd9Sstevel@tonic-gate  *		  - unknown libscf error
8327c478bd9Sstevel@tonic-gate  *   ENOENT - inst does not exist in the repository
8337c478bd9Sstevel@tonic-gate  *   EPERM - insufficient permissions
8347c478bd9Sstevel@tonic-gate  *   EACCESS - backend access denied
8357c478bd9Sstevel@tonic-gate  *   EROFS - backend is readonly
8367c478bd9Sstevel@tonic-gate  *   EFAULT - internal sysevent_evc_publish() error
8377c478bd9Sstevel@tonic-gate  *   EBADF - h is invalid (sysevent_evc_publish() returned EINVAL)
8382c65c8b0Srm88369  *   ENOSPC - sysevent queue full (sysevent_evc_publish() returned EAGAIN)
8397c478bd9Sstevel@tonic-gate  */
8407c478bd9Sstevel@tonic-gate int
8417c478bd9Sstevel@tonic-gate restarter_set_states(restarter_event_handle_t *h, const char *inst,
8427c478bd9Sstevel@tonic-gate     restarter_instance_state_t cur_state,
8437c478bd9Sstevel@tonic-gate     restarter_instance_state_t new_cur_state,
8447c478bd9Sstevel@tonic-gate     restarter_instance_state_t next_state,
8457c478bd9Sstevel@tonic-gate     restarter_instance_state_t new_next_state, restarter_error_t e,
846*f6e214c7SGavin Maltby     restarter_str_t aux)
8477c478bd9Sstevel@tonic-gate {
8487c478bd9Sstevel@tonic-gate 	nvlist_t *attr;
8497c478bd9Sstevel@tonic-gate 	scf_handle_t *scf_h;
8507c478bd9Sstevel@tonic-gate 	instance_data_t id;
8517c478bd9Sstevel@tonic-gate 	int ret = 0;
852*f6e214c7SGavin Maltby 	const char *p = restarter_get_str_short(aux);
8537c478bd9Sstevel@tonic-gate 
8547c478bd9Sstevel@tonic-gate 	assert(h->reh_master_channel != NULL);
8557c478bd9Sstevel@tonic-gate 	assert(h->reh_master_channel_name != NULL);
8567c478bd9Sstevel@tonic-gate 	assert(h->reh_master_subscriber_id != NULL);
8577c478bd9Sstevel@tonic-gate 
8587c478bd9Sstevel@tonic-gate 	if ((scf_h = scf_handle_create(SCF_VERSION)) == NULL) {
8597c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
8607c478bd9Sstevel@tonic-gate 		case SCF_ERROR_VERSION_MISMATCH:
8617c478bd9Sstevel@tonic-gate 			return (EPROTO);
8627c478bd9Sstevel@tonic-gate 
8637c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NO_MEMORY:
8647c478bd9Sstevel@tonic-gate 			return (ENOMEM);
8657c478bd9Sstevel@tonic-gate 
8667c478bd9Sstevel@tonic-gate 		default:
8677c478bd9Sstevel@tonic-gate 			bad_fail("scf_handle_create", scf_error());
8687c478bd9Sstevel@tonic-gate 		}
8697c478bd9Sstevel@tonic-gate 	}
8707c478bd9Sstevel@tonic-gate 
8717c478bd9Sstevel@tonic-gate 	if (scf_handle_bind(scf_h) == -1) {
8727c478bd9Sstevel@tonic-gate 		scf_handle_destroy(scf_h);
8737c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
8747c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NO_SERVER:
8757c478bd9Sstevel@tonic-gate 			return (ENOTACTIVE);
8767c478bd9Sstevel@tonic-gate 
8777c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NO_RESOURCES:
8787c478bd9Sstevel@tonic-gate 			return (ENOMEM);
8797c478bd9Sstevel@tonic-gate 
8807c478bd9Sstevel@tonic-gate 		case SCF_ERROR_INVALID_ARGUMENT:
8817c478bd9Sstevel@tonic-gate 		case SCF_ERROR_IN_USE:
8827c478bd9Sstevel@tonic-gate 		default:
8837c478bd9Sstevel@tonic-gate 			bad_fail("scf_handle_bind", scf_error());
8847c478bd9Sstevel@tonic-gate 		}
8857c478bd9Sstevel@tonic-gate 	}
8867c478bd9Sstevel@tonic-gate 
8877c478bd9Sstevel@tonic-gate 	if (nvlist_alloc(&attr, NV_UNIQUE_NAME, 0) != 0 ||
8887c478bd9Sstevel@tonic-gate 	    nvlist_add_int32(attr, RESTARTER_NAME_STATE, new_cur_state) != 0 ||
8897c478bd9Sstevel@tonic-gate 	    nvlist_add_int32(attr, RESTARTER_NAME_NEXT_STATE, new_next_state)
8907c478bd9Sstevel@tonic-gate 	    != 0 ||
8917c478bd9Sstevel@tonic-gate 	    nvlist_add_int32(attr, RESTARTER_NAME_ERROR, e) != 0 ||
892*f6e214c7SGavin Maltby 	    nvlist_add_string(attr, RESTARTER_NAME_INSTANCE, inst) != 0 ||
893*f6e214c7SGavin Maltby 	    nvlist_add_int32(attr, RESTARTER_NAME_REASON, aux) != 0) {
8947c478bd9Sstevel@tonic-gate 		ret = ENOMEM;
8952c65c8b0Srm88369 	} else {
8967c478bd9Sstevel@tonic-gate 		id.i_fmri = inst;
8977c478bd9Sstevel@tonic-gate 		id.i_state = cur_state;
8987c478bd9Sstevel@tonic-gate 		id.i_next_state = next_state;
8997c478bd9Sstevel@tonic-gate 
9007c478bd9Sstevel@tonic-gate 		ret = _restarter_commit_states(scf_h, &id, new_cur_state,
901*f6e214c7SGavin Maltby 		    new_next_state, p);
9027c478bd9Sstevel@tonic-gate 
9032c65c8b0Srm88369 		if (ret == 0) {
9042c65c8b0Srm88369 			ret = restarter_event_publish_retry(
9052c65c8b0Srm88369 			    h->reh_master_channel, "master", "state_change",
9062c65c8b0Srm88369 			    "com.sun", "librestart", attr, EVCH_NOSLEEP);
9077c478bd9Sstevel@tonic-gate 		}
9087c478bd9Sstevel@tonic-gate 	}
9097c478bd9Sstevel@tonic-gate 
9107c478bd9Sstevel@tonic-gate 	nvlist_free(attr);
9117c478bd9Sstevel@tonic-gate 	(void) scf_handle_unbind(scf_h);
9127c478bd9Sstevel@tonic-gate 	scf_handle_destroy(scf_h);
9137c478bd9Sstevel@tonic-gate 
9147c478bd9Sstevel@tonic-gate 	return (ret);
9157c478bd9Sstevel@tonic-gate }
9167c478bd9Sstevel@tonic-gate 
9177c478bd9Sstevel@tonic-gate restarter_instance_state_t
9187c478bd9Sstevel@tonic-gate restarter_string_to_state(char *string)
9197c478bd9Sstevel@tonic-gate {
9207c478bd9Sstevel@tonic-gate 	assert(string != NULL);
9217c478bd9Sstevel@tonic-gate 
9227c478bd9Sstevel@tonic-gate 	if (strcmp(string, SCF_STATE_STRING_NONE) == 0)
9237c478bd9Sstevel@tonic-gate 		return (RESTARTER_STATE_NONE);
9247c478bd9Sstevel@tonic-gate 	else if (strcmp(string, SCF_STATE_STRING_UNINIT) == 0)
9257c478bd9Sstevel@tonic-gate 		return (RESTARTER_STATE_UNINIT);
9267c478bd9Sstevel@tonic-gate 	else if (strcmp(string, SCF_STATE_STRING_MAINT) == 0)
9277c478bd9Sstevel@tonic-gate 		return (RESTARTER_STATE_MAINT);
9287c478bd9Sstevel@tonic-gate 	else if (strcmp(string, SCF_STATE_STRING_OFFLINE) == 0)
9297c478bd9Sstevel@tonic-gate 		return (RESTARTER_STATE_OFFLINE);
9307c478bd9Sstevel@tonic-gate 	else if (strcmp(string, SCF_STATE_STRING_DISABLED) == 0)
9317c478bd9Sstevel@tonic-gate 		return (RESTARTER_STATE_DISABLED);
9327c478bd9Sstevel@tonic-gate 	else if (strcmp(string, SCF_STATE_STRING_ONLINE) == 0)
9337c478bd9Sstevel@tonic-gate 		return (RESTARTER_STATE_ONLINE);
9347c478bd9Sstevel@tonic-gate 	else if (strcmp(string, SCF_STATE_STRING_DEGRADED) == 0)
9357c478bd9Sstevel@tonic-gate 		return (RESTARTER_STATE_DEGRADED);
9367c478bd9Sstevel@tonic-gate 	else {
9377c478bd9Sstevel@tonic-gate 		return (RESTARTER_STATE_NONE);
9387c478bd9Sstevel@tonic-gate 	}
9397c478bd9Sstevel@tonic-gate }
9407c478bd9Sstevel@tonic-gate 
9417c478bd9Sstevel@tonic-gate ssize_t
9427c478bd9Sstevel@tonic-gate restarter_state_to_string(restarter_instance_state_t state, char *string,
9437c478bd9Sstevel@tonic-gate     size_t len)
9447c478bd9Sstevel@tonic-gate {
9457c478bd9Sstevel@tonic-gate 	assert(string != NULL);
9467c478bd9Sstevel@tonic-gate 
9477c478bd9Sstevel@tonic-gate 	if (state == RESTARTER_STATE_NONE)
9487c478bd9Sstevel@tonic-gate 		return ((ssize_t)strlcpy(string, SCF_STATE_STRING_NONE, len));
9497c478bd9Sstevel@tonic-gate 	else if (state == RESTARTER_STATE_UNINIT)
9507c478bd9Sstevel@tonic-gate 		return ((ssize_t)strlcpy(string, SCF_STATE_STRING_UNINIT, len));
9517c478bd9Sstevel@tonic-gate 	else if (state == RESTARTER_STATE_MAINT)
9527c478bd9Sstevel@tonic-gate 		return ((ssize_t)strlcpy(string, SCF_STATE_STRING_MAINT, len));
9537c478bd9Sstevel@tonic-gate 	else if (state == RESTARTER_STATE_OFFLINE)
9547c478bd9Sstevel@tonic-gate 		return ((ssize_t)strlcpy(string, SCF_STATE_STRING_OFFLINE,
9557c478bd9Sstevel@tonic-gate 		    len));
9567c478bd9Sstevel@tonic-gate 	else if (state == RESTARTER_STATE_DISABLED)
9577c478bd9Sstevel@tonic-gate 		return ((ssize_t)strlcpy(string, SCF_STATE_STRING_DISABLED,
9587c478bd9Sstevel@tonic-gate 		    len));
9597c478bd9Sstevel@tonic-gate 	else if (state == RESTARTER_STATE_ONLINE)
9607c478bd9Sstevel@tonic-gate 		return ((ssize_t)strlcpy(string, SCF_STATE_STRING_ONLINE, len));
9617c478bd9Sstevel@tonic-gate 	else if (state == RESTARTER_STATE_DEGRADED)
9627c478bd9Sstevel@tonic-gate 		return ((ssize_t)strlcpy(string, SCF_STATE_STRING_DEGRADED,
9637c478bd9Sstevel@tonic-gate 		    len));
9647c478bd9Sstevel@tonic-gate 	else
9657c478bd9Sstevel@tonic-gate 		return ((ssize_t)strlcpy(string, "unknown", len));
9667c478bd9Sstevel@tonic-gate }
9677c478bd9Sstevel@tonic-gate 
9687c478bd9Sstevel@tonic-gate /*
9697c478bd9Sstevel@tonic-gate  * Sets pg to the name property group of s_inst.  If it doesn't exist, it is
9707c478bd9Sstevel@tonic-gate  * added.
9717c478bd9Sstevel@tonic-gate  *
9727c478bd9Sstevel@tonic-gate  * Fails with
9737c478bd9Sstevel@tonic-gate  *   ECONNABORTED - repository disconnection or unknown libscf error
9747c478bd9Sstevel@tonic-gate  *   EBADF - inst is not set
9757c478bd9Sstevel@tonic-gate  *   ECANCELED - inst is deleted
9767c478bd9Sstevel@tonic-gate  *   EPERM - permission is denied
9777c478bd9Sstevel@tonic-gate  *   EACCES - backend denied access
9787c478bd9Sstevel@tonic-gate  *   EROFS - backend readonly
9797c478bd9Sstevel@tonic-gate  */
9807c478bd9Sstevel@tonic-gate static int
9817c478bd9Sstevel@tonic-gate instance_get_or_add_pg(scf_instance_t *inst, const char *name,
9827c478bd9Sstevel@tonic-gate     const char *type, uint32_t flags, scf_propertygroup_t *pg)
9837c478bd9Sstevel@tonic-gate {
9847c478bd9Sstevel@tonic-gate again:
9857c478bd9Sstevel@tonic-gate 	if (scf_instance_get_pg(inst, name, pg) == 0)
9867c478bd9Sstevel@tonic-gate 		return (0);
9877c478bd9Sstevel@tonic-gate 
9887c478bd9Sstevel@tonic-gate 	switch (scf_error()) {
9897c478bd9Sstevel@tonic-gate 	case SCF_ERROR_CONNECTION_BROKEN:
9907c478bd9Sstevel@tonic-gate 	default:
9917c478bd9Sstevel@tonic-gate 		return (ECONNABORTED);
9927c478bd9Sstevel@tonic-gate 
9937c478bd9Sstevel@tonic-gate 	case SCF_ERROR_NOT_SET:
9947c478bd9Sstevel@tonic-gate 		return (EBADF);
9957c478bd9Sstevel@tonic-gate 
9967c478bd9Sstevel@tonic-gate 	case SCF_ERROR_DELETED:
9977c478bd9Sstevel@tonic-gate 		return (ECANCELED);
9987c478bd9Sstevel@tonic-gate 
9997c478bd9Sstevel@tonic-gate 	case SCF_ERROR_NOT_FOUND:
10007c478bd9Sstevel@tonic-gate 		break;
10017c478bd9Sstevel@tonic-gate 
10027c478bd9Sstevel@tonic-gate 	case SCF_ERROR_HANDLE_MISMATCH:
10037c478bd9Sstevel@tonic-gate 	case SCF_ERROR_INVALID_ARGUMENT:
10047c478bd9Sstevel@tonic-gate 		bad_fail("scf_instance_get_pg", scf_error());
10057c478bd9Sstevel@tonic-gate 	}
10067c478bd9Sstevel@tonic-gate 
10077c478bd9Sstevel@tonic-gate 	if (scf_instance_add_pg(inst, name, type, flags, pg) == 0)
10087c478bd9Sstevel@tonic-gate 		return (0);
10097c478bd9Sstevel@tonic-gate 
10107c478bd9Sstevel@tonic-gate 	switch (scf_error()) {
10117c478bd9Sstevel@tonic-gate 	case SCF_ERROR_CONNECTION_BROKEN:
10127c478bd9Sstevel@tonic-gate 	default:
10137c478bd9Sstevel@tonic-gate 		return (ECONNABORTED);
10147c478bd9Sstevel@tonic-gate 
10157c478bd9Sstevel@tonic-gate 	case SCF_ERROR_DELETED:
10167c478bd9Sstevel@tonic-gate 		return (ECANCELED);
10177c478bd9Sstevel@tonic-gate 
10187c478bd9Sstevel@tonic-gate 	case SCF_ERROR_EXISTS:
10197c478bd9Sstevel@tonic-gate 		goto again;
10207c478bd9Sstevel@tonic-gate 
10217c478bd9Sstevel@tonic-gate 	case SCF_ERROR_PERMISSION_DENIED:
10227c478bd9Sstevel@tonic-gate 		return (EPERM);
10237c478bd9Sstevel@tonic-gate 
10247c478bd9Sstevel@tonic-gate 	case SCF_ERROR_BACKEND_ACCESS:
10257c478bd9Sstevel@tonic-gate 		return (EACCES);
10267c478bd9Sstevel@tonic-gate 
10277c478bd9Sstevel@tonic-gate 	case SCF_ERROR_BACKEND_READONLY:
10287c478bd9Sstevel@tonic-gate 		return (EROFS);
10297c478bd9Sstevel@tonic-gate 
10307c478bd9Sstevel@tonic-gate 	case SCF_ERROR_HANDLE_MISMATCH:
10317c478bd9Sstevel@tonic-gate 	case SCF_ERROR_INVALID_ARGUMENT:
10327c478bd9Sstevel@tonic-gate 	case SCF_ERROR_NOT_SET:			/* should be caught above */
10337c478bd9Sstevel@tonic-gate 		bad_fail("scf_instance_add_pg", scf_error());
10347c478bd9Sstevel@tonic-gate 	}
10357c478bd9Sstevel@tonic-gate 
10367c478bd9Sstevel@tonic-gate 	return (0);
10377c478bd9Sstevel@tonic-gate }
10387c478bd9Sstevel@tonic-gate 
10397c478bd9Sstevel@tonic-gate /*
10407c478bd9Sstevel@tonic-gate  * Fails with
10417c478bd9Sstevel@tonic-gate  *   ECONNABORTED
10427c478bd9Sstevel@tonic-gate  *   ECANCELED - pg was deleted
10437c478bd9Sstevel@tonic-gate  */
10447c478bd9Sstevel@tonic-gate static int
10457c478bd9Sstevel@tonic-gate tx_set_value(scf_transaction_t *tx, scf_transaction_entry_t *ent,
10467c478bd9Sstevel@tonic-gate     const char *pname, scf_type_t ty, scf_value_t *val)
10477c478bd9Sstevel@tonic-gate {
10487c478bd9Sstevel@tonic-gate 	int r;
10497c478bd9Sstevel@tonic-gate 
10507c478bd9Sstevel@tonic-gate 	for (;;) {
10517c478bd9Sstevel@tonic-gate 		if (scf_transaction_property_change_type(tx, ent, pname,
10527c478bd9Sstevel@tonic-gate 		    ty) == 0)
10537c478bd9Sstevel@tonic-gate 			break;
10547c478bd9Sstevel@tonic-gate 
10557c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
10567c478bd9Sstevel@tonic-gate 		case SCF_ERROR_CONNECTION_BROKEN:
10577c478bd9Sstevel@tonic-gate 		default:
10587c478bd9Sstevel@tonic-gate 			return (ECONNABORTED);
10597c478bd9Sstevel@tonic-gate 
10607c478bd9Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
10617c478bd9Sstevel@tonic-gate 			return (ECANCELED);
10627c478bd9Sstevel@tonic-gate 
10637c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
10647c478bd9Sstevel@tonic-gate 			break;
10657c478bd9Sstevel@tonic-gate 
10667c478bd9Sstevel@tonic-gate 		case SCF_ERROR_HANDLE_MISMATCH:
10677c478bd9Sstevel@tonic-gate 		case SCF_ERROR_INVALID_ARGUMENT:
10687c478bd9Sstevel@tonic-gate 		case SCF_ERROR_IN_USE:
10697c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
10707c478bd9Sstevel@tonic-gate 			bad_fail("scf_transaction_property_change_type",
10717c478bd9Sstevel@tonic-gate 			    scf_error());
10727c478bd9Sstevel@tonic-gate 		}
10737c478bd9Sstevel@tonic-gate 
10747c478bd9Sstevel@tonic-gate 		if (scf_transaction_property_new(tx, ent, pname, ty) == 0)
10757c478bd9Sstevel@tonic-gate 			break;
10767c478bd9Sstevel@tonic-gate 
10777c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
10787c478bd9Sstevel@tonic-gate 		case SCF_ERROR_CONNECTION_BROKEN:
10797c478bd9Sstevel@tonic-gate 		default:
10807c478bd9Sstevel@tonic-gate 			return (ECONNABORTED);
10817c478bd9Sstevel@tonic-gate 
10827c478bd9Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
10837c478bd9Sstevel@tonic-gate 			return (ECANCELED);
10847c478bd9Sstevel@tonic-gate 
10857c478bd9Sstevel@tonic-gate 		case SCF_ERROR_EXISTS:
10867c478bd9Sstevel@tonic-gate 			break;
10877c478bd9Sstevel@tonic-gate 
10887c478bd9Sstevel@tonic-gate 		case SCF_ERROR_HANDLE_MISMATCH:
10897c478bd9Sstevel@tonic-gate 		case SCF_ERROR_INVALID_ARGUMENT:
10907c478bd9Sstevel@tonic-gate 		case SCF_ERROR_IN_USE:
10917c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
10927c478bd9Sstevel@tonic-gate 			bad_fail("scf_transaction_property_new", scf_error());
10937c478bd9Sstevel@tonic-gate 		}
10947c478bd9Sstevel@tonic-gate 	}
10957c478bd9Sstevel@tonic-gate 
10967c478bd9Sstevel@tonic-gate 	r = scf_entry_add_value(ent, val);
10977c478bd9Sstevel@tonic-gate 	assert(r == 0);
10987c478bd9Sstevel@tonic-gate 
10997c478bd9Sstevel@tonic-gate 	return (0);
11007c478bd9Sstevel@tonic-gate }
11017c478bd9Sstevel@tonic-gate 
11027c478bd9Sstevel@tonic-gate /*
11037c478bd9Sstevel@tonic-gate  * Commit new_state, new_next_state, and aux to the repository for id.  If
11047c478bd9Sstevel@tonic-gate  * successful, also set id's state and next-state as given, and return 0.
11057c478bd9Sstevel@tonic-gate  * Fails with
11067c478bd9Sstevel@tonic-gate  *   ENOMEM - out of memory
11077c478bd9Sstevel@tonic-gate  *   ECONNABORTED - repository connection broken
11087c478bd9Sstevel@tonic-gate  *		  - unknown libscf error
11097c478bd9Sstevel@tonic-gate  *   EINVAL - id->i_fmri is invalid or not an instance FMRI
11107c478bd9Sstevel@tonic-gate  *   ENOENT - id->i_fmri does not exist
11117c478bd9Sstevel@tonic-gate  *   EPERM - insufficient permissions
11127c478bd9Sstevel@tonic-gate  *   EACCES - backend access denied
11137c478bd9Sstevel@tonic-gate  *   EROFS - backend is readonly
11147c478bd9Sstevel@tonic-gate  */
11157c478bd9Sstevel@tonic-gate int
11167c478bd9Sstevel@tonic-gate _restarter_commit_states(scf_handle_t *h, instance_data_t *id,
11177c478bd9Sstevel@tonic-gate     restarter_instance_state_t new_state,
11187c478bd9Sstevel@tonic-gate     restarter_instance_state_t new_state_next, const char *aux)
11197c478bd9Sstevel@tonic-gate {
11207c478bd9Sstevel@tonic-gate 	char str_state[MAX_SCF_STATE_STRING_SZ];
11217c478bd9Sstevel@tonic-gate 	char str_new_state[MAX_SCF_STATE_STRING_SZ];
11227c478bd9Sstevel@tonic-gate 	char str_state_next[MAX_SCF_STATE_STRING_SZ];
11237c478bd9Sstevel@tonic-gate 	char str_new_state_next[MAX_SCF_STATE_STRING_SZ];
11247c478bd9Sstevel@tonic-gate 	int ret = 0, r;
11257c478bd9Sstevel@tonic-gate 	struct timeval now;
11267c478bd9Sstevel@tonic-gate 	ssize_t sz;
11277c478bd9Sstevel@tonic-gate 
11287c478bd9Sstevel@tonic-gate 	scf_transaction_t *t = NULL;
11297c478bd9Sstevel@tonic-gate 	scf_transaction_entry_t *t_state = NULL, *t_state_next = NULL;
11307c478bd9Sstevel@tonic-gate 	scf_transaction_entry_t *t_stime = NULL, *t_aux = NULL;
11317c478bd9Sstevel@tonic-gate 	scf_value_t *v_state = NULL, *v_state_next = NULL, *v_stime = NULL;
11327c478bd9Sstevel@tonic-gate 	scf_value_t *v_aux = NULL;
11337c478bd9Sstevel@tonic-gate 	scf_instance_t *s_inst = NULL;
11347c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg = NULL;
11357c478bd9Sstevel@tonic-gate 
11367c478bd9Sstevel@tonic-gate 	assert(new_state != RESTARTER_STATE_NONE);
11377c478bd9Sstevel@tonic-gate 
11387c478bd9Sstevel@tonic-gate 	if ((s_inst = scf_instance_create(h)) == NULL ||
11397c478bd9Sstevel@tonic-gate 	    (pg = scf_pg_create(h)) == NULL ||
11407c478bd9Sstevel@tonic-gate 	    (t = scf_transaction_create(h)) == NULL ||
11417c478bd9Sstevel@tonic-gate 	    (t_state = scf_entry_create(h)) == NULL ||
11427c478bd9Sstevel@tonic-gate 	    (t_state_next = scf_entry_create(h)) == NULL ||
11437c478bd9Sstevel@tonic-gate 	    (t_stime = scf_entry_create(h)) == NULL ||
11447c478bd9Sstevel@tonic-gate 	    (t_aux = scf_entry_create(h)) == NULL ||
11457c478bd9Sstevel@tonic-gate 	    (v_state = scf_value_create(h)) == NULL ||
11467c478bd9Sstevel@tonic-gate 	    (v_state_next = scf_value_create(h)) == NULL ||
11477c478bd9Sstevel@tonic-gate 	    (v_stime = scf_value_create(h)) == NULL ||
11487c478bd9Sstevel@tonic-gate 	    (v_aux = scf_value_create(h)) == NULL) {
11497c478bd9Sstevel@tonic-gate 		ret = ENOMEM;
11507c478bd9Sstevel@tonic-gate 		goto out;
11517c478bd9Sstevel@tonic-gate 	}
11527c478bd9Sstevel@tonic-gate 
11537c478bd9Sstevel@tonic-gate 	sz = restarter_state_to_string(new_state, str_new_state,
11547c478bd9Sstevel@tonic-gate 	    sizeof (str_new_state));
11557c478bd9Sstevel@tonic-gate 	assert(sz < sizeof (str_new_state));
11567c478bd9Sstevel@tonic-gate 	sz = restarter_state_to_string(new_state_next, str_new_state_next,
11577c478bd9Sstevel@tonic-gate 	    sizeof (str_new_state_next));
11587c478bd9Sstevel@tonic-gate 	assert(sz < sizeof (str_new_state_next));
11597c478bd9Sstevel@tonic-gate 	sz = restarter_state_to_string(id->i_state, str_state,
11607c478bd9Sstevel@tonic-gate 	    sizeof (str_state));
11617c478bd9Sstevel@tonic-gate 	assert(sz < sizeof (str_state));
11627c478bd9Sstevel@tonic-gate 	sz = restarter_state_to_string(id->i_next_state, str_state_next,
11637c478bd9Sstevel@tonic-gate 	    sizeof (str_state_next));
11647c478bd9Sstevel@tonic-gate 	assert(sz < sizeof (str_state_next));
11657c478bd9Sstevel@tonic-gate 
11667c478bd9Sstevel@tonic-gate 	ret = gettimeofday(&now, NULL);
11677c478bd9Sstevel@tonic-gate 	assert(ret != -1);
11687c478bd9Sstevel@tonic-gate 
11697c478bd9Sstevel@tonic-gate 	if (scf_handle_decode_fmri(h, id->i_fmri, NULL, NULL, s_inst,
11707c478bd9Sstevel@tonic-gate 	    NULL, NULL, SCF_DECODE_FMRI_EXACT) == -1) {
11717c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
11727c478bd9Sstevel@tonic-gate 		case SCF_ERROR_CONNECTION_BROKEN:
11737c478bd9Sstevel@tonic-gate 		default:
11747c478bd9Sstevel@tonic-gate 			ret = ECONNABORTED;
11757c478bd9Sstevel@tonic-gate 			break;
11767c478bd9Sstevel@tonic-gate 
11777c478bd9Sstevel@tonic-gate 		case SCF_ERROR_INVALID_ARGUMENT:
11787c478bd9Sstevel@tonic-gate 		case SCF_ERROR_CONSTRAINT_VIOLATED:
11797c478bd9Sstevel@tonic-gate 			ret = EINVAL;
11807c478bd9Sstevel@tonic-gate 			break;
11817c478bd9Sstevel@tonic-gate 
11827c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
11837c478bd9Sstevel@tonic-gate 			ret = ENOENT;
11847c478bd9Sstevel@tonic-gate 			break;
11857c478bd9Sstevel@tonic-gate 
11867c478bd9Sstevel@tonic-gate 		case SCF_ERROR_HANDLE_MISMATCH:
11877c478bd9Sstevel@tonic-gate 			bad_fail("scf_handle_decode_fmri", scf_error());
11887c478bd9Sstevel@tonic-gate 		}
11897c478bd9Sstevel@tonic-gate 		goto out;
11907c478bd9Sstevel@tonic-gate 	}
11917c478bd9Sstevel@tonic-gate 
11927c478bd9Sstevel@tonic-gate 
11937c478bd9Sstevel@tonic-gate 	if (scf_value_set_astring(v_state, str_new_state) != 0 ||
1194eb1a3463STruong Nguyen 	    scf_value_set_astring(v_state_next, str_new_state_next) != 0)
11957c478bd9Sstevel@tonic-gate 		bad_fail("scf_value_set_astring", scf_error());
11967c478bd9Sstevel@tonic-gate 
1197eb1a3463STruong Nguyen 	if (aux) {
1198eb1a3463STruong Nguyen 		if (scf_value_set_astring(v_aux, aux) != 0)
1199eb1a3463STruong Nguyen 			bad_fail("scf_value_set_astring", scf_error());
1200eb1a3463STruong Nguyen 	}
1201eb1a3463STruong Nguyen 
12027c478bd9Sstevel@tonic-gate 	if (scf_value_set_time(v_stime, now.tv_sec, now.tv_usec * 1000) != 0)
12037c478bd9Sstevel@tonic-gate 		bad_fail("scf_value_set_time", scf_error());
12047c478bd9Sstevel@tonic-gate 
12057c478bd9Sstevel@tonic-gate add_pg:
12067c478bd9Sstevel@tonic-gate 	switch (r = instance_get_or_add_pg(s_inst, SCF_PG_RESTARTER,
12077c478bd9Sstevel@tonic-gate 	    SCF_PG_RESTARTER_TYPE, SCF_PG_RESTARTER_FLAGS, pg)) {
12087c478bd9Sstevel@tonic-gate 	case 0:
12097c478bd9Sstevel@tonic-gate 		break;
12107c478bd9Sstevel@tonic-gate 
12117c478bd9Sstevel@tonic-gate 	case ECONNABORTED:
12127c478bd9Sstevel@tonic-gate 	case EPERM:
12137c478bd9Sstevel@tonic-gate 	case EACCES:
12147c478bd9Sstevel@tonic-gate 	case EROFS:
12157c478bd9Sstevel@tonic-gate 		ret = r;
12167c478bd9Sstevel@tonic-gate 		goto out;
12177c478bd9Sstevel@tonic-gate 
12187c478bd9Sstevel@tonic-gate 	case ECANCELED:
12197c478bd9Sstevel@tonic-gate 		ret = ENOENT;
12207c478bd9Sstevel@tonic-gate 		goto out;
12217c478bd9Sstevel@tonic-gate 
12227c478bd9Sstevel@tonic-gate 	case EBADF:
12237c478bd9Sstevel@tonic-gate 	default:
12247c478bd9Sstevel@tonic-gate 		bad_fail("instance_get_or_add_pg", r);
12257c478bd9Sstevel@tonic-gate 	}
12267c478bd9Sstevel@tonic-gate 
12277c478bd9Sstevel@tonic-gate 	for (;;) {
12287c478bd9Sstevel@tonic-gate 		if (scf_transaction_start(t, pg) != 0) {
12297c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
12307c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
12317c478bd9Sstevel@tonic-gate 			default:
12327c478bd9Sstevel@tonic-gate 				ret = ECONNABORTED;
12337c478bd9Sstevel@tonic-gate 				goto out;
12347c478bd9Sstevel@tonic-gate 
12357c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
12367c478bd9Sstevel@tonic-gate 				goto add_pg;
12377c478bd9Sstevel@tonic-gate 
12387c478bd9Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
12397c478bd9Sstevel@tonic-gate 				ret = EPERM;
12407c478bd9Sstevel@tonic-gate 				goto out;
12417c478bd9Sstevel@tonic-gate 
12427c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_ACCESS:
12437c478bd9Sstevel@tonic-gate 				ret = EACCES;
12447c478bd9Sstevel@tonic-gate 				goto out;
12457c478bd9Sstevel@tonic-gate 
12467c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_READONLY:
12477c478bd9Sstevel@tonic-gate 				ret = EROFS;
12487c478bd9Sstevel@tonic-gate 				goto out;
12497c478bd9Sstevel@tonic-gate 
12507c478bd9Sstevel@tonic-gate 			case SCF_ERROR_HANDLE_MISMATCH:
12517c478bd9Sstevel@tonic-gate 			case SCF_ERROR_IN_USE:
12527c478bd9Sstevel@tonic-gate 				bad_fail("scf_transaction_start", scf_error());
12537c478bd9Sstevel@tonic-gate 			}
12547c478bd9Sstevel@tonic-gate 		}
12557c478bd9Sstevel@tonic-gate 
12567c478bd9Sstevel@tonic-gate 		if ((r = tx_set_value(t, t_state, SCF_PROPERTY_STATE,
12577c478bd9Sstevel@tonic-gate 		    SCF_TYPE_ASTRING, v_state)) != 0 ||
12587c478bd9Sstevel@tonic-gate 		    (r = tx_set_value(t, t_state_next, SCF_PROPERTY_NEXT_STATE,
12597c478bd9Sstevel@tonic-gate 		    SCF_TYPE_ASTRING, v_state_next)) != 0 ||
12607c478bd9Sstevel@tonic-gate 		    (r = tx_set_value(t, t_stime, SCF_PROPERTY_STATE_TIMESTAMP,
12617c478bd9Sstevel@tonic-gate 		    SCF_TYPE_TIME, v_stime)) != 0) {
12627c478bd9Sstevel@tonic-gate 			switch (r) {
12637c478bd9Sstevel@tonic-gate 			case ECONNABORTED:
12647c478bd9Sstevel@tonic-gate 				ret = ECONNABORTED;
12657c478bd9Sstevel@tonic-gate 				goto out;
12667c478bd9Sstevel@tonic-gate 
12677c478bd9Sstevel@tonic-gate 			case ECANCELED:
12687c478bd9Sstevel@tonic-gate 				scf_transaction_reset(t);
12697c478bd9Sstevel@tonic-gate 				goto add_pg;
12707c478bd9Sstevel@tonic-gate 
12717c478bd9Sstevel@tonic-gate 			default:
12727c478bd9Sstevel@tonic-gate 				bad_fail("tx_set_value", r);
12737c478bd9Sstevel@tonic-gate 			}
12747c478bd9Sstevel@tonic-gate 		}
12757c478bd9Sstevel@tonic-gate 
1276eb1a3463STruong Nguyen 		if (aux) {
1277eb1a3463STruong Nguyen 			if ((r = tx_set_value(t, t_aux, SCF_PROPERTY_AUX_STATE,
1278eb1a3463STruong Nguyen 			    SCF_TYPE_ASTRING, v_aux)) != 0) {
1279eb1a3463STruong Nguyen 				switch (r) {
1280eb1a3463STruong Nguyen 				case ECONNABORTED:
1281eb1a3463STruong Nguyen 					ret = ECONNABORTED;
1282eb1a3463STruong Nguyen 					goto out;
1283eb1a3463STruong Nguyen 
1284eb1a3463STruong Nguyen 				case ECANCELED:
1285eb1a3463STruong Nguyen 					scf_transaction_reset(t);
1286eb1a3463STruong Nguyen 					goto add_pg;
1287eb1a3463STruong Nguyen 
1288eb1a3463STruong Nguyen 				default:
1289eb1a3463STruong Nguyen 					bad_fail("tx_set_value", r);
1290eb1a3463STruong Nguyen 				}
1291eb1a3463STruong Nguyen 			}
1292eb1a3463STruong Nguyen 		}
1293eb1a3463STruong Nguyen 
12947c478bd9Sstevel@tonic-gate 		ret = scf_transaction_commit(t);
12957c478bd9Sstevel@tonic-gate 		if (ret == 1)
12967c478bd9Sstevel@tonic-gate 			break;
12977c478bd9Sstevel@tonic-gate 		if (ret == -1) {
12987c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
12997c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
13007c478bd9Sstevel@tonic-gate 			default:
13017c478bd9Sstevel@tonic-gate 				ret = ECONNABORTED;
13027c478bd9Sstevel@tonic-gate 				goto out;
13037c478bd9Sstevel@tonic-gate 
13047c478bd9Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
13057c478bd9Sstevel@tonic-gate 				ret = EPERM;
13067c478bd9Sstevel@tonic-gate 				goto out;
13077c478bd9Sstevel@tonic-gate 
13087c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_ACCESS:
13097c478bd9Sstevel@tonic-gate 				ret = EACCES;
13107c478bd9Sstevel@tonic-gate 				goto out;
13117c478bd9Sstevel@tonic-gate 
13127c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_READONLY:
13137c478bd9Sstevel@tonic-gate 				ret = EROFS;
13147c478bd9Sstevel@tonic-gate 				goto out;
13157c478bd9Sstevel@tonic-gate 
13167c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
13177c478bd9Sstevel@tonic-gate 				bad_fail("scf_transaction_commit", scf_error());
13187c478bd9Sstevel@tonic-gate 			}
13197c478bd9Sstevel@tonic-gate 		}
13207c478bd9Sstevel@tonic-gate 
13217c478bd9Sstevel@tonic-gate 		scf_transaction_reset(t);
13227c478bd9Sstevel@tonic-gate 		if (scf_pg_update(pg) == -1) {
13237c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
13247c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
13257c478bd9Sstevel@tonic-gate 			default:
13267c478bd9Sstevel@tonic-gate 				ret = ECONNABORTED;
13277c478bd9Sstevel@tonic-gate 				goto out;
13287c478bd9Sstevel@tonic-gate 
13297c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
13307c478bd9Sstevel@tonic-gate 				goto add_pg;
13317c478bd9Sstevel@tonic-gate 			}
13327c478bd9Sstevel@tonic-gate 		}
13337c478bd9Sstevel@tonic-gate 	}
13347c478bd9Sstevel@tonic-gate 
13357c478bd9Sstevel@tonic-gate 	id->i_state = new_state;
13367c478bd9Sstevel@tonic-gate 	id->i_next_state = new_state_next;
13377c478bd9Sstevel@tonic-gate 	ret = 0;
13387c478bd9Sstevel@tonic-gate 
13397c478bd9Sstevel@tonic-gate out:
13407c478bd9Sstevel@tonic-gate 	scf_transaction_destroy(t);
13417c478bd9Sstevel@tonic-gate 	scf_entry_destroy(t_state);
13427c478bd9Sstevel@tonic-gate 	scf_entry_destroy(t_state_next);
13437c478bd9Sstevel@tonic-gate 	scf_entry_destroy(t_stime);
13447c478bd9Sstevel@tonic-gate 	scf_entry_destroy(t_aux);
13457c478bd9Sstevel@tonic-gate 	scf_value_destroy(v_state);
13467c478bd9Sstevel@tonic-gate 	scf_value_destroy(v_state_next);
13477c478bd9Sstevel@tonic-gate 	scf_value_destroy(v_stime);
13487c478bd9Sstevel@tonic-gate 	scf_value_destroy(v_aux);
13497c478bd9Sstevel@tonic-gate 	scf_pg_destroy(pg);
13507c478bd9Sstevel@tonic-gate 	scf_instance_destroy(s_inst);
13517c478bd9Sstevel@tonic-gate 
13527c478bd9Sstevel@tonic-gate 	return (ret);
13537c478bd9Sstevel@tonic-gate }
13547c478bd9Sstevel@tonic-gate 
13557c478bd9Sstevel@tonic-gate /*
13567c478bd9Sstevel@tonic-gate  * Fails with
13577c478bd9Sstevel@tonic-gate  *   EINVAL - type is invalid
13587c478bd9Sstevel@tonic-gate  *   ENOMEM
13597c478bd9Sstevel@tonic-gate  *   ECONNABORTED - repository connection broken
13607c478bd9Sstevel@tonic-gate  *   EBADF - s_inst is not set
13617c478bd9Sstevel@tonic-gate  *   ECANCELED - s_inst is deleted
13627c478bd9Sstevel@tonic-gate  *   EPERM - permission denied
13637c478bd9Sstevel@tonic-gate  *   EACCES - backend access denied
13647c478bd9Sstevel@tonic-gate  *   EROFS - backend readonly
13657c478bd9Sstevel@tonic-gate  */
13667c478bd9Sstevel@tonic-gate int
13677c478bd9Sstevel@tonic-gate restarter_remove_contract(scf_instance_t *s_inst, ctid_t contract_id,
13687c478bd9Sstevel@tonic-gate     restarter_contract_type_t type)
13697c478bd9Sstevel@tonic-gate {
13707c478bd9Sstevel@tonic-gate 	scf_handle_t *h;
13717c478bd9Sstevel@tonic-gate 	scf_transaction_t *t = NULL;
13727c478bd9Sstevel@tonic-gate 	scf_transaction_entry_t *t_cid = NULL;
13737c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg = NULL;
13747c478bd9Sstevel@tonic-gate 	scf_property_t *prop = NULL;
13757c478bd9Sstevel@tonic-gate 	scf_value_t *val;
13767c478bd9Sstevel@tonic-gate 	scf_iter_t *iter = NULL;
13777c478bd9Sstevel@tonic-gate 	const char *pname;
13787c478bd9Sstevel@tonic-gate 	int ret = 0, primary;
13797c478bd9Sstevel@tonic-gate 	uint64_t c;
13807c478bd9Sstevel@tonic-gate 
13817c478bd9Sstevel@tonic-gate 	switch (type) {
13827c478bd9Sstevel@tonic-gate 	case RESTARTER_CONTRACT_PRIMARY:
13837c478bd9Sstevel@tonic-gate 		primary = 1;
13847c478bd9Sstevel@tonic-gate 		break;
13857c478bd9Sstevel@tonic-gate 	case RESTARTER_CONTRACT_TRANSIENT:
13867c478bd9Sstevel@tonic-gate 		primary = 0;
13877c478bd9Sstevel@tonic-gate 		break;
13887c478bd9Sstevel@tonic-gate 	default:
13897c478bd9Sstevel@tonic-gate 		return (EINVAL);
13907c478bd9Sstevel@tonic-gate 	}
13917c478bd9Sstevel@tonic-gate 
13927c478bd9Sstevel@tonic-gate 	h = scf_instance_handle(s_inst);
13937c478bd9Sstevel@tonic-gate 
13947c478bd9Sstevel@tonic-gate 	pg = scf_pg_create(h);
13957c478bd9Sstevel@tonic-gate 	prop = scf_property_create(h);
13967c478bd9Sstevel@tonic-gate 	iter = scf_iter_create(h);
13977c478bd9Sstevel@tonic-gate 	t = scf_transaction_create(h);
13987c478bd9Sstevel@tonic-gate 
13997c478bd9Sstevel@tonic-gate 	if (pg == NULL || prop == NULL || iter == NULL || t == NULL) {
14007c478bd9Sstevel@tonic-gate 		ret = ENOMEM;
14017c478bd9Sstevel@tonic-gate 		goto remove_contract_cleanup;
14027c478bd9Sstevel@tonic-gate 	}
14037c478bd9Sstevel@tonic-gate 
14047c478bd9Sstevel@tonic-gate add:
14057c478bd9Sstevel@tonic-gate 	scf_transaction_destroy_children(t);
14067c478bd9Sstevel@tonic-gate 	ret = instance_get_or_add_pg(s_inst, SCF_PG_RESTARTER,
14077c478bd9Sstevel@tonic-gate 	    SCF_PG_RESTARTER_TYPE, SCF_PG_RESTARTER_FLAGS, pg);
14087c478bd9Sstevel@tonic-gate 	if (ret != 0)
14097c478bd9Sstevel@tonic-gate 		goto remove_contract_cleanup;
14107c478bd9Sstevel@tonic-gate 
14117c478bd9Sstevel@tonic-gate 	pname = primary? SCF_PROPERTY_CONTRACT :
14127c478bd9Sstevel@tonic-gate 	    SCF_PROPERTY_TRANSIENT_CONTRACT;
14137c478bd9Sstevel@tonic-gate 
14147c478bd9Sstevel@tonic-gate 	for (;;) {
14157c478bd9Sstevel@tonic-gate 		if (scf_transaction_start(t, pg) != 0) {
14167c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
14177c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
14187c478bd9Sstevel@tonic-gate 			default:
14197c478bd9Sstevel@tonic-gate 				ret = ECONNABORTED;
14207c478bd9Sstevel@tonic-gate 				goto remove_contract_cleanup;
14217c478bd9Sstevel@tonic-gate 
14227c478bd9Sstevel@tonic-gate 			case SCF_ERROR_DELETED:
14237c478bd9Sstevel@tonic-gate 				goto add;
14247c478bd9Sstevel@tonic-gate 
14257c478bd9Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
14267c478bd9Sstevel@tonic-gate 				ret = EPERM;
14277c478bd9Sstevel@tonic-gate 				goto remove_contract_cleanup;
14287c478bd9Sstevel@tonic-gate 
14297c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_ACCESS:
14307c478bd9Sstevel@tonic-gate 				ret = EACCES;
14317c478bd9Sstevel@tonic-gate 				goto remove_contract_cleanup;
14327c478bd9Sstevel@tonic-gate 
14337c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_READONLY:
14347c478bd9Sstevel@tonic-gate 				ret = EROFS;
14357c478bd9Sstevel@tonic-gate 				goto remove_contract_cleanup;
14367c478bd9Sstevel@tonic-gate 
14377c478bd9Sstevel@tonic-gate 			case SCF_ERROR_HANDLE_MISMATCH:
14387c478bd9Sstevel@tonic-gate 			case SCF_ERROR_IN_USE:
14397c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
14407c478bd9Sstevel@tonic-gate 				bad_fail("scf_transaction_start", scf_error());
14417c478bd9Sstevel@tonic-gate 			}
14427c478bd9Sstevel@tonic-gate 		}
14437c478bd9Sstevel@tonic-gate 
14447c478bd9Sstevel@tonic-gate 		t_cid = scf_entry_create(h);
14457c478bd9Sstevel@tonic-gate 
14467c478bd9Sstevel@tonic-gate 		if (scf_pg_get_property(pg, pname, prop) == 0) {
14477c478bd9Sstevel@tonic-gate replace:
14487c478bd9Sstevel@tonic-gate 			if (scf_transaction_property_change_type(t, t_cid,
14497c478bd9Sstevel@tonic-gate 			    pname, SCF_TYPE_COUNT) != 0) {
14507c478bd9Sstevel@tonic-gate 				switch (scf_error()) {
14517c478bd9Sstevel@tonic-gate 				case SCF_ERROR_CONNECTION_BROKEN:
14527c478bd9Sstevel@tonic-gate 				default:
14537c478bd9Sstevel@tonic-gate 					ret = ECONNABORTED;
14547c478bd9Sstevel@tonic-gate 					goto remove_contract_cleanup;
14557c478bd9Sstevel@tonic-gate 
14567c478bd9Sstevel@tonic-gate 				case SCF_ERROR_DELETED:
14577c478bd9Sstevel@tonic-gate 					scf_entry_destroy(t_cid);
14587c478bd9Sstevel@tonic-gate 					goto add;
14597c478bd9Sstevel@tonic-gate 
14607c478bd9Sstevel@tonic-gate 				case SCF_ERROR_NOT_FOUND:
14617c478bd9Sstevel@tonic-gate 					goto new;
14627c478bd9Sstevel@tonic-gate 
14637c478bd9Sstevel@tonic-gate 				case SCF_ERROR_HANDLE_MISMATCH:
14647c478bd9Sstevel@tonic-gate 				case SCF_ERROR_INVALID_ARGUMENT:
14657c478bd9Sstevel@tonic-gate 				case SCF_ERROR_IN_USE:
14667c478bd9Sstevel@tonic-gate 				case SCF_ERROR_NOT_SET:
14677c478bd9Sstevel@tonic-gate 					bad_fail(
14687c478bd9Sstevel@tonic-gate 					"scf_transaction_property_changetype",
14697c478bd9Sstevel@tonic-gate 					    scf_error());
14707c478bd9Sstevel@tonic-gate 				}
14717c478bd9Sstevel@tonic-gate 			}
14727c478bd9Sstevel@tonic-gate 
14737c478bd9Sstevel@tonic-gate 			if (scf_property_is_type(prop, SCF_TYPE_COUNT) == 0) {
14747c478bd9Sstevel@tonic-gate 				if (scf_iter_property_values(iter, prop) != 0) {
14757c478bd9Sstevel@tonic-gate 					switch (scf_error()) {
14767c478bd9Sstevel@tonic-gate 					case SCF_ERROR_CONNECTION_BROKEN:
14777c478bd9Sstevel@tonic-gate 					default:
14787c478bd9Sstevel@tonic-gate 						ret = ECONNABORTED;
14797c478bd9Sstevel@tonic-gate 						goto remove_contract_cleanup;
14807c478bd9Sstevel@tonic-gate 
14817c478bd9Sstevel@tonic-gate 					case SCF_ERROR_NOT_SET:
14827c478bd9Sstevel@tonic-gate 					case SCF_ERROR_HANDLE_MISMATCH:
14837c478bd9Sstevel@tonic-gate 						bad_fail(
14847c478bd9Sstevel@tonic-gate 						    "scf_iter_property_values",
14857c478bd9Sstevel@tonic-gate 						    scf_error());
14867c478bd9Sstevel@tonic-gate 					}
14877c478bd9Sstevel@tonic-gate 				}
14887c478bd9Sstevel@tonic-gate 
14897c478bd9Sstevel@tonic-gate next_val:
14907c478bd9Sstevel@tonic-gate 				val = scf_value_create(h);
14917c478bd9Sstevel@tonic-gate 				if (val == NULL) {
14927c478bd9Sstevel@tonic-gate 					assert(scf_error() ==
14937c478bd9Sstevel@tonic-gate 					    SCF_ERROR_NO_MEMORY);
14947c478bd9Sstevel@tonic-gate 					ret = ENOMEM;
14957c478bd9Sstevel@tonic-gate 					goto remove_contract_cleanup;
14967c478bd9Sstevel@tonic-gate 				}
14977c478bd9Sstevel@tonic-gate 
14987c478bd9Sstevel@tonic-gate 				ret = scf_iter_next_value(iter, val);
14997c478bd9Sstevel@tonic-gate 				if (ret == -1) {
15007c478bd9Sstevel@tonic-gate 					switch (scf_error()) {
15017c478bd9Sstevel@tonic-gate 					case SCF_ERROR_CONNECTION_BROKEN:
15027c478bd9Sstevel@tonic-gate 						ret = ECONNABORTED;
15037c478bd9Sstevel@tonic-gate 						goto remove_contract_cleanup;
15047c478bd9Sstevel@tonic-gate 
15057c478bd9Sstevel@tonic-gate 					case SCF_ERROR_DELETED:
15067c478bd9Sstevel@tonic-gate 						scf_value_destroy(val);
15077c478bd9Sstevel@tonic-gate 						goto add;
15087c478bd9Sstevel@tonic-gate 
15097c478bd9Sstevel@tonic-gate 					case SCF_ERROR_HANDLE_MISMATCH:
15107c478bd9Sstevel@tonic-gate 					case SCF_ERROR_INVALID_ARGUMENT:
15113eae19d9Swesolows 					case SCF_ERROR_PERMISSION_DENIED:
15127c478bd9Sstevel@tonic-gate 					default:
15137c478bd9Sstevel@tonic-gate 						bad_fail("scf_iter_next_value",
15147c478bd9Sstevel@tonic-gate 						    scf_error());
15157c478bd9Sstevel@tonic-gate 					}
15167c478bd9Sstevel@tonic-gate 				}
15177c478bd9Sstevel@tonic-gate 
15187c478bd9Sstevel@tonic-gate 				if (ret == 1) {
15197c478bd9Sstevel@tonic-gate 					ret = scf_value_get_count(val, &c);
15207c478bd9Sstevel@tonic-gate 					assert(ret == 0);
15217c478bd9Sstevel@tonic-gate 
15227c478bd9Sstevel@tonic-gate 					if (c != contract_id) {
15237c478bd9Sstevel@tonic-gate 						ret = scf_entry_add_value(t_cid,
15247c478bd9Sstevel@tonic-gate 						    val);
15257c478bd9Sstevel@tonic-gate 						assert(ret == 0);
15267c478bd9Sstevel@tonic-gate 					} else {
15277c478bd9Sstevel@tonic-gate 						scf_value_destroy(val);
15287c478bd9Sstevel@tonic-gate 					}
15297c478bd9Sstevel@tonic-gate 
15307c478bd9Sstevel@tonic-gate 					goto next_val;
15317c478bd9Sstevel@tonic-gate 				}
15327c478bd9Sstevel@tonic-gate 
15337c478bd9Sstevel@tonic-gate 				scf_value_destroy(val);
15347c478bd9Sstevel@tonic-gate 			} else {
15357c478bd9Sstevel@tonic-gate 				switch (scf_error()) {
15367c478bd9Sstevel@tonic-gate 				case SCF_ERROR_CONNECTION_BROKEN:
15377c478bd9Sstevel@tonic-gate 				default:
15387c478bd9Sstevel@tonic-gate 					ret = ECONNABORTED;
15397c478bd9Sstevel@tonic-gate 					goto remove_contract_cleanup;
15407c478bd9Sstevel@tonic-gate 
15417c478bd9Sstevel@tonic-gate 				case SCF_ERROR_TYPE_MISMATCH:
15427c478bd9Sstevel@tonic-gate 					break;
15437c478bd9Sstevel@tonic-gate 
15447c478bd9Sstevel@tonic-gate 				case SCF_ERROR_INVALID_ARGUMENT:
15457c478bd9Sstevel@tonic-gate 				case SCF_ERROR_NOT_SET:
15467c478bd9Sstevel@tonic-gate 					bad_fail("scf_property_is_type",
15477c478bd9Sstevel@tonic-gate 					    scf_error());
15487c478bd9Sstevel@tonic-gate 				}
15497c478bd9Sstevel@tonic-gate 			}
15507c478bd9Sstevel@tonic-gate 		} else {
15517c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
15527c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
15537c478bd9Sstevel@tonic-gate 			default:
15547c478bd9Sstevel@tonic-gate 				ret = ECONNABORTED;
15557c478bd9Sstevel@tonic-gate 				goto remove_contract_cleanup;
15567c478bd9Sstevel@tonic-gate 
15577c478bd9Sstevel@tonic-gate 			case SCF_ERROR_DELETED:
15587c478bd9Sstevel@tonic-gate 				scf_entry_destroy(t_cid);
15597c478bd9Sstevel@tonic-gate 				goto add;
15607c478bd9Sstevel@tonic-gate 
15617c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_FOUND:
15627c478bd9Sstevel@tonic-gate 				break;
15637c478bd9Sstevel@tonic-gate 
15647c478bd9Sstevel@tonic-gate 			case SCF_ERROR_HANDLE_MISMATCH:
15657c478bd9Sstevel@tonic-gate 			case SCF_ERROR_INVALID_ARGUMENT:
15667c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
15677c478bd9Sstevel@tonic-gate 				bad_fail("scf_pg_get_property", scf_error());
15687c478bd9Sstevel@tonic-gate 			}
15697c478bd9Sstevel@tonic-gate 
15707c478bd9Sstevel@tonic-gate new:
15717c478bd9Sstevel@tonic-gate 			if (scf_transaction_property_new(t, t_cid, pname,
15727c478bd9Sstevel@tonic-gate 			    SCF_TYPE_COUNT) != 0) {
15737c478bd9Sstevel@tonic-gate 				switch (scf_error()) {
15747c478bd9Sstevel@tonic-gate 				case SCF_ERROR_CONNECTION_BROKEN:
15757c478bd9Sstevel@tonic-gate 				default:
15767c478bd9Sstevel@tonic-gate 					ret = ECONNABORTED;
15777c478bd9Sstevel@tonic-gate 					goto remove_contract_cleanup;
15787c478bd9Sstevel@tonic-gate 
15797c478bd9Sstevel@tonic-gate 				case SCF_ERROR_DELETED:
15807c478bd9Sstevel@tonic-gate 					scf_entry_destroy(t_cid);
15817c478bd9Sstevel@tonic-gate 					goto add;
15827c478bd9Sstevel@tonic-gate 
15837c478bd9Sstevel@tonic-gate 				case SCF_ERROR_EXISTS:
15847c478bd9Sstevel@tonic-gate 					goto replace;
15857c478bd9Sstevel@tonic-gate 
15867c478bd9Sstevel@tonic-gate 				case SCF_ERROR_HANDLE_MISMATCH:
15877c478bd9Sstevel@tonic-gate 				case SCF_ERROR_INVALID_ARGUMENT:
15887c478bd9Sstevel@tonic-gate 				case SCF_ERROR_NOT_SET:
15897c478bd9Sstevel@tonic-gate 					bad_fail("scf_transaction_property_new",
15907c478bd9Sstevel@tonic-gate 					    scf_error());
15917c478bd9Sstevel@tonic-gate 				}
15927c478bd9Sstevel@tonic-gate 			}
15937c478bd9Sstevel@tonic-gate 		}
15947c478bd9Sstevel@tonic-gate 
15957c478bd9Sstevel@tonic-gate 		ret = scf_transaction_commit(t);
15967c478bd9Sstevel@tonic-gate 		if (ret == -1) {
15977c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
15987c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
15997c478bd9Sstevel@tonic-gate 			default:
16007c478bd9Sstevel@tonic-gate 				ret = ECONNABORTED;
16017c478bd9Sstevel@tonic-gate 				goto remove_contract_cleanup;
16027c478bd9Sstevel@tonic-gate 
16037c478bd9Sstevel@tonic-gate 			case SCF_ERROR_DELETED:
16047c478bd9Sstevel@tonic-gate 				goto add;
16057c478bd9Sstevel@tonic-gate 
16067c478bd9Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
16077c478bd9Sstevel@tonic-gate 				ret = EPERM;
16087c478bd9Sstevel@tonic-gate 				goto remove_contract_cleanup;
16097c478bd9Sstevel@tonic-gate 
16107c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_ACCESS:
16117c478bd9Sstevel@tonic-gate 				ret = EACCES;
16127c478bd9Sstevel@tonic-gate 				goto remove_contract_cleanup;
16137c478bd9Sstevel@tonic-gate 
16147c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_READONLY:
16157c478bd9Sstevel@tonic-gate 				ret = EROFS;
16167c478bd9Sstevel@tonic-gate 				goto remove_contract_cleanup;
16177c478bd9Sstevel@tonic-gate 
16187c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
16197c478bd9Sstevel@tonic-gate 				bad_fail("scf_transaction_commit", scf_error());
16207c478bd9Sstevel@tonic-gate 			}
16217c478bd9Sstevel@tonic-gate 		}
16227c478bd9Sstevel@tonic-gate 		if (ret == 1) {
16237c478bd9Sstevel@tonic-gate 			ret = 0;
16247c478bd9Sstevel@tonic-gate 			break;
16257c478bd9Sstevel@tonic-gate 		}
16267c478bd9Sstevel@tonic-gate 
16277c478bd9Sstevel@tonic-gate 		scf_transaction_destroy_children(t);
16287c478bd9Sstevel@tonic-gate 		if (scf_pg_update(pg) == -1) {
16297c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
16307c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
16317c478bd9Sstevel@tonic-gate 			default:
16327c478bd9Sstevel@tonic-gate 				ret = ECONNABORTED;
16337c478bd9Sstevel@tonic-gate 				goto remove_contract_cleanup;
16347c478bd9Sstevel@tonic-gate 
16357c478bd9Sstevel@tonic-gate 			case SCF_ERROR_DELETED:
16367c478bd9Sstevel@tonic-gate 				goto add;
16377c478bd9Sstevel@tonic-gate 
16387c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
16397c478bd9Sstevel@tonic-gate 				bad_fail("scf_pg_update", scf_error());
16407c478bd9Sstevel@tonic-gate 			}
16417c478bd9Sstevel@tonic-gate 		}
16427c478bd9Sstevel@tonic-gate 	}
16437c478bd9Sstevel@tonic-gate 
16447c478bd9Sstevel@tonic-gate remove_contract_cleanup:
16457c478bd9Sstevel@tonic-gate 	scf_transaction_destroy_children(t);
16467c478bd9Sstevel@tonic-gate 	scf_transaction_destroy(t);
16477c478bd9Sstevel@tonic-gate 	scf_iter_destroy(iter);
16487c478bd9Sstevel@tonic-gate 	scf_property_destroy(prop);
16497c478bd9Sstevel@tonic-gate 	scf_pg_destroy(pg);
16507c478bd9Sstevel@tonic-gate 
16517c478bd9Sstevel@tonic-gate 	return (ret);
16527c478bd9Sstevel@tonic-gate }
16537c478bd9Sstevel@tonic-gate 
16547c478bd9Sstevel@tonic-gate /*
16557c478bd9Sstevel@tonic-gate  * Fails with
16567c478bd9Sstevel@tonic-gate  *   EINVAL - type is invalid
16577c478bd9Sstevel@tonic-gate  *   ENOMEM
16587c478bd9Sstevel@tonic-gate  *   ECONNABORTED - repository disconnection
16597c478bd9Sstevel@tonic-gate  *   EBADF - s_inst is not set
16607c478bd9Sstevel@tonic-gate  *   ECANCELED - s_inst is deleted
16617c478bd9Sstevel@tonic-gate  *   EPERM
16627c478bd9Sstevel@tonic-gate  *   EACCES
16637c478bd9Sstevel@tonic-gate  *   EROFS
16647c478bd9Sstevel@tonic-gate  */
16657c478bd9Sstevel@tonic-gate int
16667c478bd9Sstevel@tonic-gate restarter_store_contract(scf_instance_t *s_inst, ctid_t contract_id,
16677c478bd9Sstevel@tonic-gate     restarter_contract_type_t type)
16687c478bd9Sstevel@tonic-gate {
16697c478bd9Sstevel@tonic-gate 	scf_handle_t *h;
16707c478bd9Sstevel@tonic-gate 	scf_transaction_t *t = NULL;
16717c478bd9Sstevel@tonic-gate 	scf_transaction_entry_t *t_cid = NULL;
16727c478bd9Sstevel@tonic-gate 	scf_value_t *val;
16737c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg = NULL;
16747c478bd9Sstevel@tonic-gate 	scf_property_t *prop = NULL;
16757c478bd9Sstevel@tonic-gate 	scf_iter_t *iter = NULL;
16767c478bd9Sstevel@tonic-gate 	const char *pname;
16777c478bd9Sstevel@tonic-gate 	int ret = 0, primary;
16787c478bd9Sstevel@tonic-gate 
16797c478bd9Sstevel@tonic-gate 	if (type == RESTARTER_CONTRACT_PRIMARY)
16807c478bd9Sstevel@tonic-gate 		primary = 1;
16817c478bd9Sstevel@tonic-gate 	else if (type == RESTARTER_CONTRACT_TRANSIENT)
16827c478bd9Sstevel@tonic-gate 		primary = 0;
16837c478bd9Sstevel@tonic-gate 	else
16847c478bd9Sstevel@tonic-gate 		return (EINVAL);
16857c478bd9Sstevel@tonic-gate 
16867c478bd9Sstevel@tonic-gate 	h = scf_instance_handle(s_inst);
16877c478bd9Sstevel@tonic-gate 
16887c478bd9Sstevel@tonic-gate 	pg = scf_pg_create(h);
16897c478bd9Sstevel@tonic-gate 	prop = scf_property_create(h);
16907c478bd9Sstevel@tonic-gate 	iter = scf_iter_create(h);
16917c478bd9Sstevel@tonic-gate 	t = scf_transaction_create(h);
16927c478bd9Sstevel@tonic-gate 
16937c478bd9Sstevel@tonic-gate 	if (pg == NULL || prop == NULL || iter == NULL || t == NULL) {
16947c478bd9Sstevel@tonic-gate 		ret = ENOMEM;
16957c478bd9Sstevel@tonic-gate 		goto out;
16967c478bd9Sstevel@tonic-gate 	}
16977c478bd9Sstevel@tonic-gate 
16987c478bd9Sstevel@tonic-gate add:
16997c478bd9Sstevel@tonic-gate 	scf_transaction_destroy_children(t);
17007c478bd9Sstevel@tonic-gate 	ret = instance_get_or_add_pg(s_inst, SCF_PG_RESTARTER,
17017c478bd9Sstevel@tonic-gate 	    SCF_PG_RESTARTER_TYPE, SCF_PG_RESTARTER_FLAGS, pg);
17027c478bd9Sstevel@tonic-gate 	if (ret != 0)
17037c478bd9Sstevel@tonic-gate 		goto out;
17047c478bd9Sstevel@tonic-gate 
17057c478bd9Sstevel@tonic-gate 	pname = primary ? SCF_PROPERTY_CONTRACT :
17067c478bd9Sstevel@tonic-gate 	    SCF_PROPERTY_TRANSIENT_CONTRACT;
17077c478bd9Sstevel@tonic-gate 
17087c478bd9Sstevel@tonic-gate 	for (;;) {
17097c478bd9Sstevel@tonic-gate 		if (scf_transaction_start(t, pg) != 0) {
17107c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
17117c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
17127c478bd9Sstevel@tonic-gate 			default:
17137c478bd9Sstevel@tonic-gate 				ret = ECONNABORTED;
17147c478bd9Sstevel@tonic-gate 				goto out;
17157c478bd9Sstevel@tonic-gate 
17167c478bd9Sstevel@tonic-gate 			case SCF_ERROR_DELETED:
17177c478bd9Sstevel@tonic-gate 				goto add;
17187c478bd9Sstevel@tonic-gate 
17197c478bd9Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
17207c478bd9Sstevel@tonic-gate 				ret = EPERM;
17217c478bd9Sstevel@tonic-gate 				goto out;
17227c478bd9Sstevel@tonic-gate 
17237c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_ACCESS:
17247c478bd9Sstevel@tonic-gate 				ret = EACCES;
17257c478bd9Sstevel@tonic-gate 				goto out;
17267c478bd9Sstevel@tonic-gate 
17277c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_READONLY:
17287c478bd9Sstevel@tonic-gate 				ret = EROFS;
17297c478bd9Sstevel@tonic-gate 				goto out;
17307c478bd9Sstevel@tonic-gate 
17317c478bd9Sstevel@tonic-gate 			case SCF_ERROR_HANDLE_MISMATCH:
17327c478bd9Sstevel@tonic-gate 			case SCF_ERROR_IN_USE:
17337c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
17347c478bd9Sstevel@tonic-gate 				bad_fail("scf_transaction_start", scf_error());
17357c478bd9Sstevel@tonic-gate 			}
17367c478bd9Sstevel@tonic-gate 		}
17377c478bd9Sstevel@tonic-gate 
17387c478bd9Sstevel@tonic-gate 		t_cid = scf_entry_create(h);
17397c478bd9Sstevel@tonic-gate 		if (t_cid == NULL) {
17407c478bd9Sstevel@tonic-gate 			ret = ENOMEM;
17417c478bd9Sstevel@tonic-gate 			goto out;
17427c478bd9Sstevel@tonic-gate 		}
17437c478bd9Sstevel@tonic-gate 
17447c478bd9Sstevel@tonic-gate 		if (scf_pg_get_property(pg, pname, prop) == 0) {
17457c478bd9Sstevel@tonic-gate replace:
17467c478bd9Sstevel@tonic-gate 			if (scf_transaction_property_change_type(t, t_cid,
17477c478bd9Sstevel@tonic-gate 			    pname, SCF_TYPE_COUNT) != 0) {
17487c478bd9Sstevel@tonic-gate 				switch (scf_error()) {
17497c478bd9Sstevel@tonic-gate 				case SCF_ERROR_CONNECTION_BROKEN:
17507c478bd9Sstevel@tonic-gate 				default:
17517c478bd9Sstevel@tonic-gate 					ret = ECONNABORTED;
17527c478bd9Sstevel@tonic-gate 					goto out;
17537c478bd9Sstevel@tonic-gate 
17547c478bd9Sstevel@tonic-gate 				case SCF_ERROR_DELETED:
17557c478bd9Sstevel@tonic-gate 					scf_entry_destroy(t_cid);
17567c478bd9Sstevel@tonic-gate 					goto add;
17577c478bd9Sstevel@tonic-gate 
17587c478bd9Sstevel@tonic-gate 				case SCF_ERROR_NOT_FOUND:
17597c478bd9Sstevel@tonic-gate 					goto new;
17607c478bd9Sstevel@tonic-gate 
17617c478bd9Sstevel@tonic-gate 				case SCF_ERROR_HANDLE_MISMATCH:
17627c478bd9Sstevel@tonic-gate 				case SCF_ERROR_INVALID_ARGUMENT:
17637c478bd9Sstevel@tonic-gate 				case SCF_ERROR_IN_USE:
17647c478bd9Sstevel@tonic-gate 				case SCF_ERROR_NOT_SET:
17657c478bd9Sstevel@tonic-gate 					bad_fail(
17667c478bd9Sstevel@tonic-gate 					"scf_transaction_propert_change_type",
17677c478bd9Sstevel@tonic-gate 					    scf_error());
17687c478bd9Sstevel@tonic-gate 				}
17697c478bd9Sstevel@tonic-gate 			}
17707c478bd9Sstevel@tonic-gate 
17717c478bd9Sstevel@tonic-gate 			if (scf_property_is_type(prop, SCF_TYPE_COUNT) == 0) {
17727c478bd9Sstevel@tonic-gate 				if (scf_iter_property_values(iter, prop) != 0) {
17737c478bd9Sstevel@tonic-gate 					switch (scf_error()) {
17747c478bd9Sstevel@tonic-gate 					case SCF_ERROR_CONNECTION_BROKEN:
17757c478bd9Sstevel@tonic-gate 					default:
17767c478bd9Sstevel@tonic-gate 						ret = ECONNABORTED;
17777c478bd9Sstevel@tonic-gate 						goto out;
17787c478bd9Sstevel@tonic-gate 
17797c478bd9Sstevel@tonic-gate 					case SCF_ERROR_NOT_SET:
17807c478bd9Sstevel@tonic-gate 					case SCF_ERROR_HANDLE_MISMATCH:
17817c478bd9Sstevel@tonic-gate 						bad_fail(
17827c478bd9Sstevel@tonic-gate 						    "scf_iter_property_values",
17837c478bd9Sstevel@tonic-gate 						    scf_error());
17847c478bd9Sstevel@tonic-gate 					}
17857c478bd9Sstevel@tonic-gate 				}
17867c478bd9Sstevel@tonic-gate 
17877c478bd9Sstevel@tonic-gate next_val:
17887c478bd9Sstevel@tonic-gate 				val = scf_value_create(h);
17897c478bd9Sstevel@tonic-gate 				if (val == NULL) {
17907c478bd9Sstevel@tonic-gate 					assert(scf_error() ==
17917c478bd9Sstevel@tonic-gate 					    SCF_ERROR_NO_MEMORY);
17927c478bd9Sstevel@tonic-gate 					ret = ENOMEM;
17937c478bd9Sstevel@tonic-gate 					goto out;
17947c478bd9Sstevel@tonic-gate 				}
17957c478bd9Sstevel@tonic-gate 
17967c478bd9Sstevel@tonic-gate 				ret = scf_iter_next_value(iter, val);
17977c478bd9Sstevel@tonic-gate 				if (ret == -1) {
17987c478bd9Sstevel@tonic-gate 					switch (scf_error()) {
17997c478bd9Sstevel@tonic-gate 					case SCF_ERROR_CONNECTION_BROKEN:
18007c478bd9Sstevel@tonic-gate 					default:
18017c478bd9Sstevel@tonic-gate 						ret = ECONNABORTED;
18027c478bd9Sstevel@tonic-gate 						goto out;
18037c478bd9Sstevel@tonic-gate 
18047c478bd9Sstevel@tonic-gate 					case SCF_ERROR_DELETED:
18057c478bd9Sstevel@tonic-gate 						scf_value_destroy(val);
18067c478bd9Sstevel@tonic-gate 						goto add;
18077c478bd9Sstevel@tonic-gate 
18087c478bd9Sstevel@tonic-gate 					case SCF_ERROR_HANDLE_MISMATCH:
18097c478bd9Sstevel@tonic-gate 					case SCF_ERROR_INVALID_ARGUMENT:
18103eae19d9Swesolows 					case SCF_ERROR_PERMISSION_DENIED:
18117c478bd9Sstevel@tonic-gate 						bad_fail(
18127c478bd9Sstevel@tonic-gate 						    "scf_iter_next_value",
18137c478bd9Sstevel@tonic-gate 						    scf_error());
18147c478bd9Sstevel@tonic-gate 					}
18157c478bd9Sstevel@tonic-gate 				}
18167c478bd9Sstevel@tonic-gate 
18177c478bd9Sstevel@tonic-gate 				if (ret == 1) {
18187c478bd9Sstevel@tonic-gate 					ret = scf_entry_add_value(t_cid, val);
18197c478bd9Sstevel@tonic-gate 					assert(ret == 0);
18207c478bd9Sstevel@tonic-gate 
18217c478bd9Sstevel@tonic-gate 					goto next_val;
18227c478bd9Sstevel@tonic-gate 				}
18237c478bd9Sstevel@tonic-gate 
18247c478bd9Sstevel@tonic-gate 				scf_value_destroy(val);
18257c478bd9Sstevel@tonic-gate 			} else {
18267c478bd9Sstevel@tonic-gate 				switch (scf_error()) {
18277c478bd9Sstevel@tonic-gate 				case SCF_ERROR_CONNECTION_BROKEN:
18287c478bd9Sstevel@tonic-gate 				default:
18297c478bd9Sstevel@tonic-gate 					ret = ECONNABORTED;
18307c478bd9Sstevel@tonic-gate 					goto out;
18317c478bd9Sstevel@tonic-gate 
18327c478bd9Sstevel@tonic-gate 				case SCF_ERROR_TYPE_MISMATCH:
18337c478bd9Sstevel@tonic-gate 					break;
18347c478bd9Sstevel@tonic-gate 
18357c478bd9Sstevel@tonic-gate 				case SCF_ERROR_INVALID_ARGUMENT:
18367c478bd9Sstevel@tonic-gate 				case SCF_ERROR_NOT_SET:
18377c478bd9Sstevel@tonic-gate 					bad_fail("scf_property_is_type",
18387c478bd9Sstevel@tonic-gate 					    scf_error());
18397c478bd9Sstevel@tonic-gate 				}
18407c478bd9Sstevel@tonic-gate 			}
18417c478bd9Sstevel@tonic-gate 		} else {
18427c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
18437c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
18447c478bd9Sstevel@tonic-gate 			default:
18457c478bd9Sstevel@tonic-gate 				ret = ECONNABORTED;
18467c478bd9Sstevel@tonic-gate 				goto out;
18477c478bd9Sstevel@tonic-gate 
18487c478bd9Sstevel@tonic-gate 			case SCF_ERROR_DELETED:
18497c478bd9Sstevel@tonic-gate 				scf_entry_destroy(t_cid);
18507c478bd9Sstevel@tonic-gate 				goto add;
18517c478bd9Sstevel@tonic-gate 
18527c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_FOUND:
18537c478bd9Sstevel@tonic-gate 				break;
18547c478bd9Sstevel@tonic-gate 
18557c478bd9Sstevel@tonic-gate 			case SCF_ERROR_HANDLE_MISMATCH:
18567c478bd9Sstevel@tonic-gate 			case SCF_ERROR_INVALID_ARGUMENT:
18577c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
18587c478bd9Sstevel@tonic-gate 				bad_fail("scf_pg_get_property", scf_error());
18597c478bd9Sstevel@tonic-gate 			}
18607c478bd9Sstevel@tonic-gate 
18617c478bd9Sstevel@tonic-gate new:
18627c478bd9Sstevel@tonic-gate 			if (scf_transaction_property_new(t, t_cid, pname,
18637c478bd9Sstevel@tonic-gate 			    SCF_TYPE_COUNT) != 0) {
18647c478bd9Sstevel@tonic-gate 				switch (scf_error()) {
18657c478bd9Sstevel@tonic-gate 				case SCF_ERROR_CONNECTION_BROKEN:
18667c478bd9Sstevel@tonic-gate 				default:
18677c478bd9Sstevel@tonic-gate 					ret = ECONNABORTED;
18687c478bd9Sstevel@tonic-gate 					goto out;
18697c478bd9Sstevel@tonic-gate 
18707c478bd9Sstevel@tonic-gate 				case SCF_ERROR_DELETED:
18717c478bd9Sstevel@tonic-gate 					scf_entry_destroy(t_cid);
18727c478bd9Sstevel@tonic-gate 					goto add;
18737c478bd9Sstevel@tonic-gate 
18747c478bd9Sstevel@tonic-gate 				case SCF_ERROR_EXISTS:
18757c478bd9Sstevel@tonic-gate 					goto replace;
18767c478bd9Sstevel@tonic-gate 
18777c478bd9Sstevel@tonic-gate 				case SCF_ERROR_HANDLE_MISMATCH:
18787c478bd9Sstevel@tonic-gate 				case SCF_ERROR_INVALID_ARGUMENT:
18797c478bd9Sstevel@tonic-gate 				case SCF_ERROR_NOT_SET:
18807c478bd9Sstevel@tonic-gate 					bad_fail("scf_transaction_property_new",
18817c478bd9Sstevel@tonic-gate 					    scf_error());
18827c478bd9Sstevel@tonic-gate 				}
18837c478bd9Sstevel@tonic-gate 			}
18847c478bd9Sstevel@tonic-gate 		}
18857c478bd9Sstevel@tonic-gate 
18867c478bd9Sstevel@tonic-gate 		val = scf_value_create(h);
18877c478bd9Sstevel@tonic-gate 		if (val == NULL) {
18887c478bd9Sstevel@tonic-gate 			assert(scf_error() == SCF_ERROR_NO_MEMORY);
18897c478bd9Sstevel@tonic-gate 			ret = ENOMEM;
18907c478bd9Sstevel@tonic-gate 			goto out;
18917c478bd9Sstevel@tonic-gate 		}
18927c478bd9Sstevel@tonic-gate 
18937c478bd9Sstevel@tonic-gate 		scf_value_set_count(val, contract_id);
18947c478bd9Sstevel@tonic-gate 		ret = scf_entry_add_value(t_cid, val);
18957c478bd9Sstevel@tonic-gate 		assert(ret == 0);
18967c478bd9Sstevel@tonic-gate 
18977c478bd9Sstevel@tonic-gate 		ret = scf_transaction_commit(t);
18987c478bd9Sstevel@tonic-gate 		if (ret == -1) {
18997c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
19007c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
19017c478bd9Sstevel@tonic-gate 			default:
19027c478bd9Sstevel@tonic-gate 				ret = ECONNABORTED;
19037c478bd9Sstevel@tonic-gate 				goto out;
19047c478bd9Sstevel@tonic-gate 
19057c478bd9Sstevel@tonic-gate 			case SCF_ERROR_DELETED:
19067c478bd9Sstevel@tonic-gate 				goto add;
19077c478bd9Sstevel@tonic-gate 
19087c478bd9Sstevel@tonic-gate 			case SCF_ERROR_PERMISSION_DENIED:
19097c478bd9Sstevel@tonic-gate 				ret = EPERM;
19107c478bd9Sstevel@tonic-gate 				goto out;
19117c478bd9Sstevel@tonic-gate 
19127c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_ACCESS:
19137c478bd9Sstevel@tonic-gate 				ret = EACCES;
19147c478bd9Sstevel@tonic-gate 				goto out;
19157c478bd9Sstevel@tonic-gate 
19167c478bd9Sstevel@tonic-gate 			case SCF_ERROR_BACKEND_READONLY:
19177c478bd9Sstevel@tonic-gate 				ret = EROFS;
19187c478bd9Sstevel@tonic-gate 				goto out;
19197c478bd9Sstevel@tonic-gate 
19207c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
19217c478bd9Sstevel@tonic-gate 				bad_fail("scf_transaction_commit", scf_error());
19227c478bd9Sstevel@tonic-gate 			}
19237c478bd9Sstevel@tonic-gate 		}
19247c478bd9Sstevel@tonic-gate 		if (ret == 1) {
19257c478bd9Sstevel@tonic-gate 			ret = 0;
19267c478bd9Sstevel@tonic-gate 			break;
19277c478bd9Sstevel@tonic-gate 		}
19287c478bd9Sstevel@tonic-gate 
19297c478bd9Sstevel@tonic-gate 		scf_transaction_destroy_children(t);
19307c478bd9Sstevel@tonic-gate 		if (scf_pg_update(pg) == -1) {
19317c478bd9Sstevel@tonic-gate 			switch (scf_error()) {
19327c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
19337c478bd9Sstevel@tonic-gate 			default:
19347c478bd9Sstevel@tonic-gate 				ret = ECONNABORTED;
19357c478bd9Sstevel@tonic-gate 				goto out;
19367c478bd9Sstevel@tonic-gate 
19377c478bd9Sstevel@tonic-gate 			case SCF_ERROR_DELETED:
19387c478bd9Sstevel@tonic-gate 				goto add;
19397c478bd9Sstevel@tonic-gate 
19407c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
19417c478bd9Sstevel@tonic-gate 				bad_fail("scf_pg_update", scf_error());
19427c478bd9Sstevel@tonic-gate 			}
19437c478bd9Sstevel@tonic-gate 		}
19447c478bd9Sstevel@tonic-gate 	}
19457c478bd9Sstevel@tonic-gate 
19467c478bd9Sstevel@tonic-gate out:
19477c478bd9Sstevel@tonic-gate 	scf_transaction_destroy_children(t);
19487c478bd9Sstevel@tonic-gate 	scf_transaction_destroy(t);
19497c478bd9Sstevel@tonic-gate 	scf_iter_destroy(iter);
19507c478bd9Sstevel@tonic-gate 	scf_property_destroy(prop);
19517c478bd9Sstevel@tonic-gate 	scf_pg_destroy(pg);
19527c478bd9Sstevel@tonic-gate 
19537c478bd9Sstevel@tonic-gate 	return (ret);
19547c478bd9Sstevel@tonic-gate }
19557c478bd9Sstevel@tonic-gate 
19567c478bd9Sstevel@tonic-gate int
19577c478bd9Sstevel@tonic-gate restarter_rm_libs_loadable()
19587c478bd9Sstevel@tonic-gate {
19597c478bd9Sstevel@tonic-gate 	void *libhndl;
19607c478bd9Sstevel@tonic-gate 
19617c478bd9Sstevel@tonic-gate 	if (method_context_safety)
19627c478bd9Sstevel@tonic-gate 		return (1);
19637c478bd9Sstevel@tonic-gate 
19647c478bd9Sstevel@tonic-gate 	if ((libhndl = dlopen("libpool.so", RTLD_LAZY | RTLD_LOCAL)) == NULL)
19657c478bd9Sstevel@tonic-gate 		return (0);
19667c478bd9Sstevel@tonic-gate 
19677c478bd9Sstevel@tonic-gate 	(void) dlclose(libhndl);
19687c478bd9Sstevel@tonic-gate 
19697c478bd9Sstevel@tonic-gate 	if ((libhndl = dlopen("libproject.so", RTLD_LAZY | RTLD_LOCAL)) == NULL)
19707c478bd9Sstevel@tonic-gate 		return (0);
19717c478bd9Sstevel@tonic-gate 
19727c478bd9Sstevel@tonic-gate 	(void) dlclose(libhndl);
19737c478bd9Sstevel@tonic-gate 
19747c478bd9Sstevel@tonic-gate 	method_context_safety = 1;
19757c478bd9Sstevel@tonic-gate 
19767c478bd9Sstevel@tonic-gate 	return (1);
19777c478bd9Sstevel@tonic-gate }
19787c478bd9Sstevel@tonic-gate 
19797c478bd9Sstevel@tonic-gate static int
19807c478bd9Sstevel@tonic-gate get_astring_val(scf_propertygroup_t *pg, const char *name, char *buf,
19817c478bd9Sstevel@tonic-gate     size_t bufsz, scf_property_t *prop, scf_value_t *val)
19827c478bd9Sstevel@tonic-gate {
19837c478bd9Sstevel@tonic-gate 	ssize_t szret;
19847c478bd9Sstevel@tonic-gate 
198513d8aaa1SSean Wilcox 	if (pg == NULL)
198613d8aaa1SSean Wilcox 		return (-1);
198713d8aaa1SSean Wilcox 
19887c478bd9Sstevel@tonic-gate 	if (scf_pg_get_property(pg, name, prop) != SCF_SUCCESS) {
19897c478bd9Sstevel@tonic-gate 		if (scf_error() == SCF_ERROR_CONNECTION_BROKEN)
19907c478bd9Sstevel@tonic-gate 			uu_die(rcbroken);
19917c478bd9Sstevel@tonic-gate 		return (-1);
19927c478bd9Sstevel@tonic-gate 	}
19937c478bd9Sstevel@tonic-gate 
19947c478bd9Sstevel@tonic-gate 	if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
19957c478bd9Sstevel@tonic-gate 		if (scf_error() == SCF_ERROR_CONNECTION_BROKEN)
19967c478bd9Sstevel@tonic-gate 			uu_die(rcbroken);
19977c478bd9Sstevel@tonic-gate 		return (-1);
19987c478bd9Sstevel@tonic-gate 	}
19997c478bd9Sstevel@tonic-gate 
20007c478bd9Sstevel@tonic-gate 	szret = scf_value_get_astring(val, buf, bufsz);
20017c478bd9Sstevel@tonic-gate 
20027c478bd9Sstevel@tonic-gate 	return (szret >= 0 ? 0 : -1);
20037c478bd9Sstevel@tonic-gate }
20047c478bd9Sstevel@tonic-gate 
2005eb1a3463STruong Nguyen static int
2006eb1a3463STruong Nguyen get_boolean_val(scf_propertygroup_t *pg, const char *name, uint8_t *b,
2007eb1a3463STruong Nguyen     scf_property_t *prop, scf_value_t *val)
2008eb1a3463STruong Nguyen {
2009eb1a3463STruong Nguyen 	if (scf_pg_get_property(pg, name, prop) != SCF_SUCCESS) {
2010eb1a3463STruong Nguyen 		if (scf_error() == SCF_ERROR_CONNECTION_BROKEN)
2011eb1a3463STruong Nguyen 			uu_die(rcbroken);
2012eb1a3463STruong Nguyen 		return (-1);
2013eb1a3463STruong Nguyen 	}
2014eb1a3463STruong Nguyen 
2015eb1a3463STruong Nguyen 	if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
2016eb1a3463STruong Nguyen 		if (scf_error() == SCF_ERROR_CONNECTION_BROKEN)
2017eb1a3463STruong Nguyen 			uu_die(rcbroken);
2018eb1a3463STruong Nguyen 		return (-1);
2019eb1a3463STruong Nguyen 	}
2020eb1a3463STruong Nguyen 
2021eb1a3463STruong Nguyen 	if (scf_value_get_boolean(val, b))
2022eb1a3463STruong Nguyen 		return (-1);
2023eb1a3463STruong Nguyen 
2024eb1a3463STruong Nguyen 	return (0);
2025eb1a3463STruong Nguyen }
2026eb1a3463STruong Nguyen 
20277c478bd9Sstevel@tonic-gate /*
20287c478bd9Sstevel@tonic-gate  * Try to load mcp->pwd, if it isn't already.
20297c478bd9Sstevel@tonic-gate  * Fails with
20307c478bd9Sstevel@tonic-gate  *   ENOMEM - malloc() failed
20317c478bd9Sstevel@tonic-gate  *   ENOENT - no entry found
20327c478bd9Sstevel@tonic-gate  *   EIO - I/O error
20337c478bd9Sstevel@tonic-gate  *   EMFILE - process out of file descriptors
20347c478bd9Sstevel@tonic-gate  *   ENFILE - system out of file handles
20357c478bd9Sstevel@tonic-gate  */
20367c478bd9Sstevel@tonic-gate static int
20377c478bd9Sstevel@tonic-gate lookup_pwd(struct method_context *mcp)
20387c478bd9Sstevel@tonic-gate {
20397c478bd9Sstevel@tonic-gate 	struct passwd *pwdp;
20407c478bd9Sstevel@tonic-gate 
20417c478bd9Sstevel@tonic-gate 	if (mcp->pwbuf != NULL && mcp->pwd.pw_uid == mcp->uid)
20427c478bd9Sstevel@tonic-gate 		return (0);
20437c478bd9Sstevel@tonic-gate 
20447c478bd9Sstevel@tonic-gate 	if (mcp->pwbuf == NULL) {
20457c478bd9Sstevel@tonic-gate 		mcp->pwbufsz = sysconf(_SC_GETPW_R_SIZE_MAX);
20467c478bd9Sstevel@tonic-gate 		assert(mcp->pwbufsz >= 0);
20477c478bd9Sstevel@tonic-gate 		mcp->pwbuf = malloc(mcp->pwbufsz);
20487c478bd9Sstevel@tonic-gate 		if (mcp->pwbuf == NULL)
20497c478bd9Sstevel@tonic-gate 			return (ENOMEM);
20507c478bd9Sstevel@tonic-gate 	}
20517c478bd9Sstevel@tonic-gate 
20527c478bd9Sstevel@tonic-gate 	do {
20537c478bd9Sstevel@tonic-gate 		errno = 0;
20547c478bd9Sstevel@tonic-gate 		pwdp = getpwuid_r(mcp->uid, &mcp->pwd, mcp->pwbuf,
20557c478bd9Sstevel@tonic-gate 		    mcp->pwbufsz);
20567c478bd9Sstevel@tonic-gate 	} while (pwdp == NULL && errno == EINTR);
20577c478bd9Sstevel@tonic-gate 	if (pwdp != NULL)
20587c478bd9Sstevel@tonic-gate 		return (0);
20597c478bd9Sstevel@tonic-gate 
20607c478bd9Sstevel@tonic-gate 	free(mcp->pwbuf);
20617c478bd9Sstevel@tonic-gate 	mcp->pwbuf = NULL;
20627c478bd9Sstevel@tonic-gate 
20637c478bd9Sstevel@tonic-gate 	switch (errno) {
20647c478bd9Sstevel@tonic-gate 	case 0:
20657c478bd9Sstevel@tonic-gate 	default:
20667c478bd9Sstevel@tonic-gate 		/*
20677c478bd9Sstevel@tonic-gate 		 * Until bug 5065780 is fixed, getpwuid_r() can fail with
20687c478bd9Sstevel@tonic-gate 		 * ENOENT, particularly on the miniroot.  Since the
20697c478bd9Sstevel@tonic-gate 		 * documentation is inaccurate, we'll return ENOENT for unknown
20707c478bd9Sstevel@tonic-gate 		 * errors.
20717c478bd9Sstevel@tonic-gate 		 */
20727c478bd9Sstevel@tonic-gate 		return (ENOENT);
20737c478bd9Sstevel@tonic-gate 
20747c478bd9Sstevel@tonic-gate 	case EIO:
20757c478bd9Sstevel@tonic-gate 	case EMFILE:
20767c478bd9Sstevel@tonic-gate 	case ENFILE:
20777c478bd9Sstevel@tonic-gate 		return (errno);
20787c478bd9Sstevel@tonic-gate 
20797c478bd9Sstevel@tonic-gate 	case ERANGE:
20807c478bd9Sstevel@tonic-gate 		bad_fail("getpwuid_r", errno);
20817c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
20827c478bd9Sstevel@tonic-gate 	}
20837c478bd9Sstevel@tonic-gate }
20847c478bd9Sstevel@tonic-gate 
20857c478bd9Sstevel@tonic-gate /*
20867c478bd9Sstevel@tonic-gate  * Get the user id for str.  Returns 0 on success or
20877c478bd9Sstevel@tonic-gate  *   ERANGE	the uid is too big
20887c478bd9Sstevel@tonic-gate  *   EINVAL	the string starts with a digit, but is not a valid uid
20897c478bd9Sstevel@tonic-gate  *   ENOMEM	out of memory
20907c478bd9Sstevel@tonic-gate  *   ENOENT	no passwd entry for str
20917c478bd9Sstevel@tonic-gate  *   EIO	an I/O error has occurred
20927c478bd9Sstevel@tonic-gate  *   EMFILE/ENFILE  out of file descriptors
20937c478bd9Sstevel@tonic-gate  */
20947c478bd9Sstevel@tonic-gate int
20957c478bd9Sstevel@tonic-gate get_uid(const char *str, struct method_context *ci, uid_t *uidp)
20967c478bd9Sstevel@tonic-gate {
20977c478bd9Sstevel@tonic-gate 	if (isdigit(str[0])) {
20987c478bd9Sstevel@tonic-gate 		uid_t uid;
20997c478bd9Sstevel@tonic-gate 		char *cp;
21007c478bd9Sstevel@tonic-gate 
21017c478bd9Sstevel@tonic-gate 		errno = 0;
21027c478bd9Sstevel@tonic-gate 		uid = strtol(str, &cp, 10);
21037c478bd9Sstevel@tonic-gate 
21047c478bd9Sstevel@tonic-gate 		if (uid == 0 && errno != 0) {
21057c478bd9Sstevel@tonic-gate 			assert(errno != EINVAL);
21067c478bd9Sstevel@tonic-gate 			return (errno);
21077c478bd9Sstevel@tonic-gate 		}
21087c478bd9Sstevel@tonic-gate 
21097c478bd9Sstevel@tonic-gate 		for (; *cp != '\0'; ++cp)
21107c478bd9Sstevel@tonic-gate 			if (*cp != ' ' || *cp != '\t')
21117c478bd9Sstevel@tonic-gate 				return (EINVAL);
21127c478bd9Sstevel@tonic-gate 
21137c478bd9Sstevel@tonic-gate 		if (uid > UID_MAX)
21147c478bd9Sstevel@tonic-gate 			return (EINVAL);
21157c478bd9Sstevel@tonic-gate 
21167c478bd9Sstevel@tonic-gate 		*uidp = uid;
21177c478bd9Sstevel@tonic-gate 		return (0);
21187c478bd9Sstevel@tonic-gate 	} else {
21197c478bd9Sstevel@tonic-gate 		struct passwd *pwdp;
21207c478bd9Sstevel@tonic-gate 
21217c478bd9Sstevel@tonic-gate 		if (ci->pwbuf == NULL) {
21227c478bd9Sstevel@tonic-gate 			ci->pwbufsz = sysconf(_SC_GETPW_R_SIZE_MAX);
21237c478bd9Sstevel@tonic-gate 			ci->pwbuf = malloc(ci->pwbufsz);
21247c478bd9Sstevel@tonic-gate 			if (ci->pwbuf == NULL)
21257c478bd9Sstevel@tonic-gate 				return (ENOMEM);
21267c478bd9Sstevel@tonic-gate 		}
21277c478bd9Sstevel@tonic-gate 
21287c478bd9Sstevel@tonic-gate 		do {
21297c478bd9Sstevel@tonic-gate 			errno = 0;
21307c478bd9Sstevel@tonic-gate 			pwdp =
21317c478bd9Sstevel@tonic-gate 			    getpwnam_r(str, &ci->pwd, ci->pwbuf, ci->pwbufsz);
21327c478bd9Sstevel@tonic-gate 		} while (pwdp == NULL && errno == EINTR);
21337c478bd9Sstevel@tonic-gate 
21347c478bd9Sstevel@tonic-gate 		if (pwdp != NULL) {
21357c478bd9Sstevel@tonic-gate 			*uidp = ci->pwd.pw_uid;
21367c478bd9Sstevel@tonic-gate 			return (0);
21377c478bd9Sstevel@tonic-gate 		} else {
21387c478bd9Sstevel@tonic-gate 			free(ci->pwbuf);
21397c478bd9Sstevel@tonic-gate 			ci->pwbuf = NULL;
21407c478bd9Sstevel@tonic-gate 			switch (errno) {
21417c478bd9Sstevel@tonic-gate 			case 0:
21427c478bd9Sstevel@tonic-gate 				return (ENOENT);
21437c478bd9Sstevel@tonic-gate 
21447c478bd9Sstevel@tonic-gate 			case ENOENT:
21457c478bd9Sstevel@tonic-gate 			case EIO:
21467c478bd9Sstevel@tonic-gate 			case EMFILE:
21477c478bd9Sstevel@tonic-gate 			case ENFILE:
21487c478bd9Sstevel@tonic-gate 				return (errno);
21497c478bd9Sstevel@tonic-gate 
21507c478bd9Sstevel@tonic-gate 			case ERANGE:
21517c478bd9Sstevel@tonic-gate 			default:
21527c478bd9Sstevel@tonic-gate 				bad_fail("getpwnam_r", errno);
21537c478bd9Sstevel@tonic-gate 				/* NOTREACHED */
21547c478bd9Sstevel@tonic-gate 			}
21557c478bd9Sstevel@tonic-gate 		}
21567c478bd9Sstevel@tonic-gate 	}
21577c478bd9Sstevel@tonic-gate }
21587c478bd9Sstevel@tonic-gate 
21597c478bd9Sstevel@tonic-gate gid_t
21607c478bd9Sstevel@tonic-gate get_gid(const char *str)
21617c478bd9Sstevel@tonic-gate {
21627c478bd9Sstevel@tonic-gate 	if (isdigit(str[0])) {
21637c478bd9Sstevel@tonic-gate 		gid_t gid;
21647c478bd9Sstevel@tonic-gate 		char *cp;
21657c478bd9Sstevel@tonic-gate 
21667c478bd9Sstevel@tonic-gate 		errno = 0;
21677c478bd9Sstevel@tonic-gate 		gid = strtol(str, &cp, 10);
21687c478bd9Sstevel@tonic-gate 
21697c478bd9Sstevel@tonic-gate 		if (gid == 0 && errno != 0)
2170f48205beScasper 			return ((gid_t)-1);
21717c478bd9Sstevel@tonic-gate 
21727c478bd9Sstevel@tonic-gate 		for (; *cp != '\0'; ++cp)
21737c478bd9Sstevel@tonic-gate 			if (*cp != ' ' || *cp != '\t')
2174f48205beScasper 				return ((gid_t)-1);
21757c478bd9Sstevel@tonic-gate 
21767c478bd9Sstevel@tonic-gate 		return (gid);
21777c478bd9Sstevel@tonic-gate 	} else {
21787c478bd9Sstevel@tonic-gate 		struct group grp, *ret;
21797c478bd9Sstevel@tonic-gate 		char *buffer;
21807c478bd9Sstevel@tonic-gate 		size_t buflen;
21817c478bd9Sstevel@tonic-gate 
21827c478bd9Sstevel@tonic-gate 		buflen = sysconf(_SC_GETGR_R_SIZE_MAX);
21837c478bd9Sstevel@tonic-gate 		buffer = malloc(buflen);
21847c478bd9Sstevel@tonic-gate 		if (buffer == NULL)
21857c478bd9Sstevel@tonic-gate 			uu_die(allocfail);
21867c478bd9Sstevel@tonic-gate 
21877c478bd9Sstevel@tonic-gate 		errno = 0;
21887c478bd9Sstevel@tonic-gate 		ret = getgrnam_r(str, &grp, buffer, buflen);
21897c478bd9Sstevel@tonic-gate 		free(buffer);
21907c478bd9Sstevel@tonic-gate 
2191f48205beScasper 		return (ret == NULL ? (gid_t)-1 : grp.gr_gid);
21927c478bd9Sstevel@tonic-gate 	}
21937c478bd9Sstevel@tonic-gate }
21947c478bd9Sstevel@tonic-gate 
21957c478bd9Sstevel@tonic-gate /*
21967c478bd9Sstevel@tonic-gate  * Fails with
21977c478bd9Sstevel@tonic-gate  *   ENOMEM - out of memory
21987c478bd9Sstevel@tonic-gate  *   ENOENT - no passwd entry
21997c478bd9Sstevel@tonic-gate  *	      no project entry
22007c478bd9Sstevel@tonic-gate  *   EIO - an I/O error occurred
22017c478bd9Sstevel@tonic-gate  *   EMFILE - the process is out of file descriptors
22027c478bd9Sstevel@tonic-gate  *   ENFILE - the system is out of file handles
22037c478bd9Sstevel@tonic-gate  *   ERANGE - the project id is out of range
22047c478bd9Sstevel@tonic-gate  *   EINVAL - str is invalid
22057c478bd9Sstevel@tonic-gate  *   E2BIG - the project entry was too big
22067c478bd9Sstevel@tonic-gate  *   -1 - the name service switch is misconfigured
22077c478bd9Sstevel@tonic-gate  */
22087c478bd9Sstevel@tonic-gate int
22097c478bd9Sstevel@tonic-gate get_projid(const char *str, struct method_context *cip)
22107c478bd9Sstevel@tonic-gate {
22117c478bd9Sstevel@tonic-gate 	int ret;
22127c478bd9Sstevel@tonic-gate 	void *buf;
22137c478bd9Sstevel@tonic-gate 	const size_t bufsz = PROJECT_BUFSZ;
22147c478bd9Sstevel@tonic-gate 	struct project proj, *pp;
22157c478bd9Sstevel@tonic-gate 
22167c478bd9Sstevel@tonic-gate 	if (strcmp(str, ":default") == 0) {
22177c478bd9Sstevel@tonic-gate 		if (cip->uid == 0) {
22187c478bd9Sstevel@tonic-gate 			/* Don't change project for root services */
22197c478bd9Sstevel@tonic-gate 			cip->project = NULL;
22207c478bd9Sstevel@tonic-gate 			return (0);
22217c478bd9Sstevel@tonic-gate 		}
22227c478bd9Sstevel@tonic-gate 
22237c478bd9Sstevel@tonic-gate 		switch (ret = lookup_pwd(cip)) {
22247c478bd9Sstevel@tonic-gate 		case 0:
22257c478bd9Sstevel@tonic-gate 			break;
22267c478bd9Sstevel@tonic-gate 
22277c478bd9Sstevel@tonic-gate 		case ENOMEM:
22287c478bd9Sstevel@tonic-gate 		case ENOENT:
22297c478bd9Sstevel@tonic-gate 		case EIO:
22307c478bd9Sstevel@tonic-gate 		case EMFILE:
22317c478bd9Sstevel@tonic-gate 		case ENFILE:
22327c478bd9Sstevel@tonic-gate 			return (ret);
22337c478bd9Sstevel@tonic-gate 
22347c478bd9Sstevel@tonic-gate 		default:
22357c478bd9Sstevel@tonic-gate 			bad_fail("lookup_pwd", ret);
22367c478bd9Sstevel@tonic-gate 		}
22377c478bd9Sstevel@tonic-gate 
22387c478bd9Sstevel@tonic-gate 		buf = malloc(bufsz);
22397c478bd9Sstevel@tonic-gate 		if (buf == NULL)
22407c478bd9Sstevel@tonic-gate 			return (ENOMEM);
22417c478bd9Sstevel@tonic-gate 
22427c478bd9Sstevel@tonic-gate 		do {
22437c478bd9Sstevel@tonic-gate 			errno = 0;
22447c478bd9Sstevel@tonic-gate 			pp = getdefaultproj(cip->pwd.pw_name, &proj, buf,
22457c478bd9Sstevel@tonic-gate 			    bufsz);
22467c478bd9Sstevel@tonic-gate 		} while (pp == NULL && errno == EINTR);
22477c478bd9Sstevel@tonic-gate 
22487c478bd9Sstevel@tonic-gate 		/* to be continued ... */
22497c478bd9Sstevel@tonic-gate 	} else {
22507c478bd9Sstevel@tonic-gate 		projid_t projid;
22517c478bd9Sstevel@tonic-gate 		char *cp;
22527c478bd9Sstevel@tonic-gate 
22537c478bd9Sstevel@tonic-gate 		if (!isdigit(str[0])) {
22547c478bd9Sstevel@tonic-gate 			cip->project = strdup(str);
22557c478bd9Sstevel@tonic-gate 			return (cip->project != NULL ? 0 : ENOMEM);
22567c478bd9Sstevel@tonic-gate 		}
22577c478bd9Sstevel@tonic-gate 
22587c478bd9Sstevel@tonic-gate 		errno = 0;
22597c478bd9Sstevel@tonic-gate 		projid = strtol(str, &cp, 10);
22607c478bd9Sstevel@tonic-gate 
22617c478bd9Sstevel@tonic-gate 		if (projid == 0 && errno != 0) {
22627c478bd9Sstevel@tonic-gate 			assert(errno == ERANGE);
22637c478bd9Sstevel@tonic-gate 			return (errno);
22647c478bd9Sstevel@tonic-gate 		}
22657c478bd9Sstevel@tonic-gate 
22667c478bd9Sstevel@tonic-gate 		for (; *cp != '\0'; ++cp)
22677c478bd9Sstevel@tonic-gate 			if (*cp != ' ' || *cp != '\t')
22687c478bd9Sstevel@tonic-gate 				return (EINVAL);
22697c478bd9Sstevel@tonic-gate 
22707c478bd9Sstevel@tonic-gate 		if (projid > MAXPROJID)
22717c478bd9Sstevel@tonic-gate 			return (ERANGE);
22727c478bd9Sstevel@tonic-gate 
22737c478bd9Sstevel@tonic-gate 		buf = malloc(bufsz);
22747c478bd9Sstevel@tonic-gate 		if (buf == NULL)
22757c478bd9Sstevel@tonic-gate 			return (ENOMEM);
22767c478bd9Sstevel@tonic-gate 
22777c478bd9Sstevel@tonic-gate 		do {
22787c478bd9Sstevel@tonic-gate 			errno = 0;
22797c478bd9Sstevel@tonic-gate 			pp = getprojbyid(projid, &proj, buf, bufsz);
22807c478bd9Sstevel@tonic-gate 		} while (pp == NULL && errno == EINTR);
22817c478bd9Sstevel@tonic-gate 	}
22827c478bd9Sstevel@tonic-gate 
22837c478bd9Sstevel@tonic-gate 	if (pp) {
22847c478bd9Sstevel@tonic-gate 		cip->project = strdup(pp->pj_name);
22857c478bd9Sstevel@tonic-gate 		free(buf);
22867c478bd9Sstevel@tonic-gate 		return (cip->project != NULL ? 0 : ENOMEM);
22877c478bd9Sstevel@tonic-gate 	}
22887c478bd9Sstevel@tonic-gate 
22897c478bd9Sstevel@tonic-gate 	free(buf);
22907c478bd9Sstevel@tonic-gate 
22917c478bd9Sstevel@tonic-gate 	switch (errno) {
22927c478bd9Sstevel@tonic-gate 	case 0:
22937c478bd9Sstevel@tonic-gate 		return (ENOENT);
22947c478bd9Sstevel@tonic-gate 
22957c478bd9Sstevel@tonic-gate 	case EIO:
22967c478bd9Sstevel@tonic-gate 	case EMFILE:
22977c478bd9Sstevel@tonic-gate 	case ENFILE:
22987c478bd9Sstevel@tonic-gate 		return (errno);
22997c478bd9Sstevel@tonic-gate 
23007c478bd9Sstevel@tonic-gate 	case ERANGE:
23017c478bd9Sstevel@tonic-gate 		return (E2BIG);
23027c478bd9Sstevel@tonic-gate 
23037c478bd9Sstevel@tonic-gate 	default:
23047c478bd9Sstevel@tonic-gate 		return (-1);
23057c478bd9Sstevel@tonic-gate 	}
23067c478bd9Sstevel@tonic-gate }
23077c478bd9Sstevel@tonic-gate 
23087c478bd9Sstevel@tonic-gate /*
23097c478bd9Sstevel@tonic-gate  * Parse the supp_groups property value and populate ci->groups.  Returns
23107c478bd9Sstevel@tonic-gate  * EINVAL (get_gid() failed for one of the components), E2BIG (the property has
23117c478bd9Sstevel@tonic-gate  * more than NGROUPS_MAX-1 groups), or 0 on success.
23127c478bd9Sstevel@tonic-gate  */
23137c478bd9Sstevel@tonic-gate int
23147c478bd9Sstevel@tonic-gate get_groups(char *str, struct method_context *ci)
23157c478bd9Sstevel@tonic-gate {
23167c478bd9Sstevel@tonic-gate 	char *cp, *end, *next;
23177c478bd9Sstevel@tonic-gate 	uint_t i;
23187c478bd9Sstevel@tonic-gate 
23197c478bd9Sstevel@tonic-gate 	const char * const whitespace = " \t";
23207c478bd9Sstevel@tonic-gate 	const char * const illegal = ", \t";
23217c478bd9Sstevel@tonic-gate 
23227c478bd9Sstevel@tonic-gate 	if (str[0] == '\0') {
23237c478bd9Sstevel@tonic-gate 		ci->ngroups = 0;
23247c478bd9Sstevel@tonic-gate 		return (0);
23257c478bd9Sstevel@tonic-gate 	}
23267c478bd9Sstevel@tonic-gate 
23277c478bd9Sstevel@tonic-gate 	for (cp = str, i = 0; *cp != '\0'; ) {
23287c478bd9Sstevel@tonic-gate 		/* skip whitespace */
23297c478bd9Sstevel@tonic-gate 		cp += strspn(cp, whitespace);
23307c478bd9Sstevel@tonic-gate 
23317c478bd9Sstevel@tonic-gate 		/* find the end */
23327c478bd9Sstevel@tonic-gate 		end = cp + strcspn(cp, illegal);
23337c478bd9Sstevel@tonic-gate 
23347c478bd9Sstevel@tonic-gate 		/* skip whitespace after end */
23357c478bd9Sstevel@tonic-gate 		next = end + strspn(end, whitespace);
23367c478bd9Sstevel@tonic-gate 
23377c478bd9Sstevel@tonic-gate 		/* if there's a comma, it separates the fields */
23387c478bd9Sstevel@tonic-gate 		if (*next == ',')
23397c478bd9Sstevel@tonic-gate 			++next;
23407c478bd9Sstevel@tonic-gate 
23417c478bd9Sstevel@tonic-gate 		*end = '\0';
23427c478bd9Sstevel@tonic-gate 
2343f48205beScasper 		if ((ci->groups[i] = get_gid(cp)) == (gid_t)-1) {
23447c478bd9Sstevel@tonic-gate 			ci->ngroups = 0;
23457c478bd9Sstevel@tonic-gate 			return (EINVAL);
23467c478bd9Sstevel@tonic-gate 		}
23477c478bd9Sstevel@tonic-gate 
23487c478bd9Sstevel@tonic-gate 		++i;
23497c478bd9Sstevel@tonic-gate 		if (i > NGROUPS_MAX - 1) {
23507c478bd9Sstevel@tonic-gate 			ci->ngroups = 0;
23517c478bd9Sstevel@tonic-gate 			return (E2BIG);
23527c478bd9Sstevel@tonic-gate 		}
23537c478bd9Sstevel@tonic-gate 
23547c478bd9Sstevel@tonic-gate 		cp = next;
23557c478bd9Sstevel@tonic-gate 	}
23567c478bd9Sstevel@tonic-gate 
23577c478bd9Sstevel@tonic-gate 	ci->ngroups = i;
23587c478bd9Sstevel@tonic-gate 	return (0);
23597c478bd9Sstevel@tonic-gate }
23607c478bd9Sstevel@tonic-gate 
2361870ad75aSSean Wilcox 
23627c478bd9Sstevel@tonic-gate /*
2363870ad75aSSean Wilcox  * Return an error message structure containing the error message
2364870ad75aSSean Wilcox  * with context, and the error so the caller can make a decision
2365870ad75aSSean Wilcox  * on what to do next.
2366870ad75aSSean Wilcox  *
2367870ad75aSSean Wilcox  * Because get_ids uses the mc_error_create() function which can
2368870ad75aSSean Wilcox  * reallocate the merr, this function must return the merr pointer
2369870ad75aSSean Wilcox  * in case it was reallocated.
23707c478bd9Sstevel@tonic-gate  */
2371870ad75aSSean Wilcox static mc_error_t *
237213d8aaa1SSean Wilcox get_profile(scf_propertygroup_t *methpg, scf_propertygroup_t *instpg,
237313d8aaa1SSean Wilcox     scf_property_t *prop, scf_value_t *val, const char *cmdline,
2374870ad75aSSean Wilcox     struct method_context *ci, mc_error_t *merr)
23757c478bd9Sstevel@tonic-gate {
23767c478bd9Sstevel@tonic-gate 	char *buf = ci->vbuf;
23777c478bd9Sstevel@tonic-gate 	ssize_t buf_sz = ci->vbuf_sz;
23787c478bd9Sstevel@tonic-gate 	char cmd[PATH_MAX];
23797c478bd9Sstevel@tonic-gate 	char *cp, *value;
23807c478bd9Sstevel@tonic-gate 	const char *cmdp;
23817c478bd9Sstevel@tonic-gate 	execattr_t *eap;
2382870ad75aSSean Wilcox 	mc_error_t *err = merr;
2383870ad75aSSean Wilcox 	int r;
23847c478bd9Sstevel@tonic-gate 
238513d8aaa1SSean Wilcox 	if (!(get_astring_val(methpg, SCF_PROPERTY_PROFILE, buf, buf_sz, prop,
238613d8aaa1SSean Wilcox 	    val) == 0 || get_astring_val(instpg, SCF_PROPERTY_PROFILE, buf,
238713d8aaa1SSean Wilcox 	    buf_sz, prop, val) == 0))
2388870ad75aSSean Wilcox 		return (mc_error_create(merr, scf_error(),
2389870ad75aSSean Wilcox 		    "Method context requires a profile, but the  \"%s\" "
2390870ad75aSSean Wilcox 		    "property could not be read. scf_error is %s",
2391870ad75aSSean Wilcox 		    SCF_PROPERTY_PROFILE, scf_strerror(scf_error())));
23927c478bd9Sstevel@tonic-gate 
23937c478bd9Sstevel@tonic-gate 	/* Extract the command from the command line. */
23947c478bd9Sstevel@tonic-gate 	cp = strpbrk(cmdline, " \t");
23957c478bd9Sstevel@tonic-gate 
23967c478bd9Sstevel@tonic-gate 	if (cp == NULL) {
23977c478bd9Sstevel@tonic-gate 		cmdp = cmdline;
23987c478bd9Sstevel@tonic-gate 	} else {
23997c478bd9Sstevel@tonic-gate 		(void) strncpy(cmd, cmdline, cp - cmdline);
24007c478bd9Sstevel@tonic-gate 		cmd[cp - cmdline] = '\0';
24017c478bd9Sstevel@tonic-gate 		cmdp = cmd;
24027c478bd9Sstevel@tonic-gate 	}
24037c478bd9Sstevel@tonic-gate 
24047c478bd9Sstevel@tonic-gate 	/* Require that cmdp[0] == '/'? */
24057c478bd9Sstevel@tonic-gate 
24067c478bd9Sstevel@tonic-gate 	eap = getexecprof(buf, KV_COMMAND, cmdp, GET_ONE);
24077c478bd9Sstevel@tonic-gate 	if (eap == NULL)
2408870ad75aSSean Wilcox 		return (mc_error_create(merr, ENOENT,
2409870ad75aSSean Wilcox 		    "Could not find the execution profile \"%s\", "
2410870ad75aSSean Wilcox 		    "command %s.", buf, cmdp));
24117c478bd9Sstevel@tonic-gate 
24127c478bd9Sstevel@tonic-gate 	/* Based on pfexec.c */
24137c478bd9Sstevel@tonic-gate 
24147c478bd9Sstevel@tonic-gate 	/* Get the euid first so we don't override ci->pwd for the uid. */
24157c478bd9Sstevel@tonic-gate 	if ((value = kva_match(eap->attr, EXECATTR_EUID_KW)) != NULL) {
2416870ad75aSSean Wilcox 		if ((r = get_uid(value, ci, &ci->euid)) != 0) {
2417f48205beScasper 			ci->euid = (uid_t)-1;
2418870ad75aSSean Wilcox 			err = mc_error_create(merr, r,
2419870ad75aSSean Wilcox 			    "Could not interpret profile euid value \"%s\", "
2420870ad75aSSean Wilcox 			    "from the execution profile \"%s\", error %d.",
2421870ad75aSSean Wilcox 			    value, buf, r);
24227c478bd9Sstevel@tonic-gate 			goto out;
24237c478bd9Sstevel@tonic-gate 		}
24247c478bd9Sstevel@tonic-gate 	}
24257c478bd9Sstevel@tonic-gate 
24267c478bd9Sstevel@tonic-gate 	if ((value = kva_match(eap->attr, EXECATTR_UID_KW)) != NULL) {
2427870ad75aSSean Wilcox 		if ((r = get_uid(value, ci, &ci->uid)) != 0) {
2428f48205beScasper 			ci->euid = ci->uid = (uid_t)-1;
2429870ad75aSSean Wilcox 			err = mc_error_create(merr, r,
2430870ad75aSSean Wilcox 			    "Could not interpret profile uid value \"%s\", "
2431870ad75aSSean Wilcox 			    "from the execution profile \"%s\", error %d.",
2432870ad75aSSean Wilcox 			    value, buf, r);
24337c478bd9Sstevel@tonic-gate 			goto out;
24347c478bd9Sstevel@tonic-gate 		}
24357c478bd9Sstevel@tonic-gate 		ci->euid = ci->uid;
24367c478bd9Sstevel@tonic-gate 	}
24377c478bd9Sstevel@tonic-gate 
24387c478bd9Sstevel@tonic-gate 	if ((value = kva_match(eap->attr, EXECATTR_GID_KW)) != NULL) {
24397c478bd9Sstevel@tonic-gate 		ci->egid = ci->gid = get_gid(value);
2440f48205beScasper 		if (ci->gid == (gid_t)-1) {
2441870ad75aSSean Wilcox 			err = mc_error_create(merr, EINVAL,
2442870ad75aSSean Wilcox 			    "Could not interpret profile gid value \"%s\", "
2443870ad75aSSean Wilcox 			    "from the execution profile \"%s\".", value, buf);
24447c478bd9Sstevel@tonic-gate 			goto out;
24457c478bd9Sstevel@tonic-gate 		}
24467c478bd9Sstevel@tonic-gate 	}
24477c478bd9Sstevel@tonic-gate 
24487c478bd9Sstevel@tonic-gate 	if ((value = kva_match(eap->attr, EXECATTR_EGID_KW)) != NULL) {
24497c478bd9Sstevel@tonic-gate 		ci->egid = get_gid(value);
2450f48205beScasper 		if (ci->egid == (gid_t)-1) {
2451870ad75aSSean Wilcox 			err = mc_error_create(merr, EINVAL,
2452870ad75aSSean Wilcox 			    "Could not interpret profile egid value \"%s\", "
2453870ad75aSSean Wilcox 			    "from the execution profile \"%s\".", value, buf);
24547c478bd9Sstevel@tonic-gate 			goto out;
24557c478bd9Sstevel@tonic-gate 		}
24567c478bd9Sstevel@tonic-gate 	}
24577c478bd9Sstevel@tonic-gate 
24587c478bd9Sstevel@tonic-gate 	if ((value = kva_match(eap->attr, EXECATTR_LPRIV_KW)) != NULL) {
24597c478bd9Sstevel@tonic-gate 		ci->lpriv_set = priv_str_to_set(value, ",", NULL);
24607c478bd9Sstevel@tonic-gate 		if (ci->lpriv_set == NULL) {
24617c478bd9Sstevel@tonic-gate 			if (errno != EINVAL)
2462870ad75aSSean Wilcox 				err = mc_error_create(merr, ENOMEM,
2463870ad75aSSean Wilcox 				    ALLOCFAIL);
24647c478bd9Sstevel@tonic-gate 			else
2465870ad75aSSean Wilcox 				err = mc_error_create(merr, EINVAL,
2466870ad75aSSean Wilcox 				    "Could not interpret profile "
2467870ad75aSSean Wilcox 				    "limitprivs value \"%s\", from "
2468870ad75aSSean Wilcox 				    "the execution profile \"%s\".",
2469870ad75aSSean Wilcox 				    value, buf);
24707c478bd9Sstevel@tonic-gate 			goto out;
24717c478bd9Sstevel@tonic-gate 		}
24727c478bd9Sstevel@tonic-gate 	}
24737c478bd9Sstevel@tonic-gate 
24747c478bd9Sstevel@tonic-gate 	if ((value = kva_match(eap->attr, EXECATTR_IPRIV_KW)) != NULL) {
24757c478bd9Sstevel@tonic-gate 		ci->priv_set = priv_str_to_set(value, ",", NULL);
24767c478bd9Sstevel@tonic-gate 		if (ci->priv_set == NULL) {
24777c478bd9Sstevel@tonic-gate 			if (errno != EINVAL)
2478870ad75aSSean Wilcox 				err = mc_error_create(merr, ENOMEM,
2479870ad75aSSean Wilcox 				    ALLOCFAIL);
24807c478bd9Sstevel@tonic-gate 			else
2481870ad75aSSean Wilcox 				err = mc_error_create(merr, EINVAL,
2482870ad75aSSean Wilcox 				    "Could not interpret profile privs value "
2483870ad75aSSean Wilcox 				    "\"%s\", from the execution profile "
2484870ad75aSSean Wilcox 				    "\"%s\".", value, buf);
24857c478bd9Sstevel@tonic-gate 			goto out;
24867c478bd9Sstevel@tonic-gate 		}
24877c478bd9Sstevel@tonic-gate 	}
24887c478bd9Sstevel@tonic-gate 
24897c478bd9Sstevel@tonic-gate out:
24907c478bd9Sstevel@tonic-gate 	free_execattr(eap);
24917c478bd9Sstevel@tonic-gate 
2492870ad75aSSean Wilcox 	return (err);
24937c478bd9Sstevel@tonic-gate }
24947c478bd9Sstevel@tonic-gate 
24957c478bd9Sstevel@tonic-gate /*
2496870ad75aSSean Wilcox  * Return an error message structure containing the error message
2497870ad75aSSean Wilcox  * with context, and the error so the caller can make a decision
2498870ad75aSSean Wilcox  * on what to do next.
2499870ad75aSSean Wilcox  *
2500870ad75aSSean Wilcox  * Because get_ids uses the mc_error_create() function which can
2501870ad75aSSean Wilcox  * reallocate the merr, this function must return the merr pointer
2502870ad75aSSean Wilcox  * in case it was reallocated.
25037c478bd9Sstevel@tonic-gate  */
2504870ad75aSSean Wilcox static mc_error_t *
250513d8aaa1SSean Wilcox get_ids(scf_propertygroup_t *methpg, scf_propertygroup_t *instpg,
2506870ad75aSSean Wilcox     scf_property_t *prop, scf_value_t *val, struct method_context *ci,
2507870ad75aSSean Wilcox     mc_error_t *merr)
25087c478bd9Sstevel@tonic-gate {
25097c478bd9Sstevel@tonic-gate 	char *vbuf = ci->vbuf;
25107c478bd9Sstevel@tonic-gate 	ssize_t vbuf_sz = ci->vbuf_sz;
25117c478bd9Sstevel@tonic-gate 	int r;
25127c478bd9Sstevel@tonic-gate 
251313d8aaa1SSean Wilcox 	/*
251413d8aaa1SSean Wilcox 	 * This should never happen because the caller should fall through
251513d8aaa1SSean Wilcox 	 * another path of just setting the ids to defaults, instead of
251613d8aaa1SSean Wilcox 	 * attempting to get the ids here.
251713d8aaa1SSean Wilcox 	 */
2518870ad75aSSean Wilcox 	if (methpg == NULL && instpg == NULL)
2519870ad75aSSean Wilcox 		return (mc_error_create(merr, ENOENT,
2520870ad75aSSean Wilcox 		    "No property groups to get ids from."));
252113d8aaa1SSean Wilcox 
252213d8aaa1SSean Wilcox 	if (!(get_astring_val(methpg, SCF_PROPERTY_USER,
252313d8aaa1SSean Wilcox 	    vbuf, vbuf_sz, prop, val) == 0 || get_astring_val(instpg,
252413d8aaa1SSean Wilcox 	    SCF_PROPERTY_USER, vbuf, vbuf_sz, prop,
2525870ad75aSSean Wilcox 	    val) == 0))
2526870ad75aSSean Wilcox 		return (mc_error_create(merr, ENOENT,
2527870ad75aSSean Wilcox 		    "Could not get \"%s\" property.", SCF_PROPERTY_USER));
25287c478bd9Sstevel@tonic-gate 
2529870ad75aSSean Wilcox 	if ((r = get_uid(vbuf, ci, &ci->uid)) != 0) {
2530f48205beScasper 		ci->uid = (uid_t)-1;
2531870ad75aSSean Wilcox 		return (mc_error_create(merr, r,
2532870ad75aSSean Wilcox 		    "Could not interpret \"%s\" property value \"%s\", "
2533870ad75aSSean Wilcox 		    "error %d.", SCF_PROPERTY_USER, vbuf, r));
25347c478bd9Sstevel@tonic-gate 	}
25357c478bd9Sstevel@tonic-gate 
253613d8aaa1SSean Wilcox 	if (!(get_astring_val(methpg, SCF_PROPERTY_GROUP, vbuf, vbuf_sz, prop,
253713d8aaa1SSean Wilcox 	    val) == 0 || get_astring_val(instpg, SCF_PROPERTY_GROUP, vbuf,
253813d8aaa1SSean Wilcox 	    vbuf_sz, prop, val) == 0)) {
253913d8aaa1SSean Wilcox 		if (scf_error() == SCF_ERROR_NOT_FOUND) {
254013d8aaa1SSean Wilcox 			(void) strcpy(vbuf, ":default");
254113d8aaa1SSean Wilcox 		} else {
2542870ad75aSSean Wilcox 			return (mc_error_create(merr, ENOENT,
2543870ad75aSSean Wilcox 			    "Could not get \"%s\" property.",
2544870ad75aSSean Wilcox 			    SCF_PROPERTY_GROUP));
25457c478bd9Sstevel@tonic-gate 		}
254613d8aaa1SSean Wilcox 	}
25477c478bd9Sstevel@tonic-gate 
25487c478bd9Sstevel@tonic-gate 	if (strcmp(vbuf, ":default") != 0) {
25497c478bd9Sstevel@tonic-gate 		ci->gid = get_gid(vbuf);
2550f48205beScasper 		if (ci->gid == (gid_t)-1) {
2551870ad75aSSean Wilcox 			return (mc_error_create(merr, ENOENT,
2552870ad75aSSean Wilcox 			    "Could not interpret \"%s\" property value \"%s\".",
2553870ad75aSSean Wilcox 			    SCF_PROPERTY_GROUP, vbuf));
25547c478bd9Sstevel@tonic-gate 		}
25557c478bd9Sstevel@tonic-gate 	} else {
25567c478bd9Sstevel@tonic-gate 		switch (r = lookup_pwd(ci)) {
25577c478bd9Sstevel@tonic-gate 		case 0:
25587c478bd9Sstevel@tonic-gate 			ci->gid = ci->pwd.pw_gid;
25597c478bd9Sstevel@tonic-gate 			break;
25607c478bd9Sstevel@tonic-gate 
25617c478bd9Sstevel@tonic-gate 		case ENOENT:
2562f48205beScasper 			ci->gid = (gid_t)-1;
2563870ad75aSSean Wilcox 			return (mc_error_create(merr, ENOENT,
2564870ad75aSSean Wilcox 			    "No passwd entry for uid \"%d\".", ci->uid));
25657c478bd9Sstevel@tonic-gate 
25667c478bd9Sstevel@tonic-gate 		case ENOMEM:
2567870ad75aSSean Wilcox 			return (mc_error_create(merr, ENOMEM,
2568870ad75aSSean Wilcox 			    "Out of memory."));
25697c478bd9Sstevel@tonic-gate 
25707c478bd9Sstevel@tonic-gate 		case EIO:
25717c478bd9Sstevel@tonic-gate 		case EMFILE:
25727c478bd9Sstevel@tonic-gate 		case ENFILE:
2573870ad75aSSean Wilcox 			return (mc_error_create(merr, ENFILE,
2574870ad75aSSean Wilcox 			    "getpwuid_r() failed, error %d.", r));
25757c478bd9Sstevel@tonic-gate 
25767c478bd9Sstevel@tonic-gate 		default:
25777c478bd9Sstevel@tonic-gate 			bad_fail("lookup_pwd", r);
25787c478bd9Sstevel@tonic-gate 		}
25797c478bd9Sstevel@tonic-gate 	}
25807c478bd9Sstevel@tonic-gate 
258113d8aaa1SSean Wilcox 	if (!(get_astring_val(methpg, SCF_PROPERTY_SUPP_GROUPS, vbuf, vbuf_sz,
258213d8aaa1SSean Wilcox 	    prop, val) == 0 || get_astring_val(instpg,
258313d8aaa1SSean Wilcox 	    SCF_PROPERTY_SUPP_GROUPS, vbuf, vbuf_sz, prop, val) == 0)) {
258413d8aaa1SSean Wilcox 		if (scf_error() == SCF_ERROR_NOT_FOUND) {
258513d8aaa1SSean Wilcox 			(void) strcpy(vbuf, ":default");
258613d8aaa1SSean Wilcox 		} else {
2587870ad75aSSean Wilcox 			return (mc_error_create(merr, ENOENT,
2588870ad75aSSean Wilcox 			    "Could not get supplemental groups (\"%s\") "
2589870ad75aSSean Wilcox 			    "property.", SCF_PROPERTY_SUPP_GROUPS));
25907c478bd9Sstevel@tonic-gate 		}
259113d8aaa1SSean Wilcox 	}
25927c478bd9Sstevel@tonic-gate 
25937c478bd9Sstevel@tonic-gate 	if (strcmp(vbuf, ":default") != 0) {
25947c478bd9Sstevel@tonic-gate 		switch (r = get_groups(vbuf, ci)) {
25957c478bd9Sstevel@tonic-gate 		case 0:
25967c478bd9Sstevel@tonic-gate 			break;
25977c478bd9Sstevel@tonic-gate 
25987c478bd9Sstevel@tonic-gate 		case EINVAL:
2599870ad75aSSean Wilcox 			return (mc_error_create(merr, EINVAL,
2600870ad75aSSean Wilcox 			    "Could not interpret supplemental groups (\"%s\") "
2601870ad75aSSean Wilcox 			    "property value \"%s\".", SCF_PROPERTY_SUPP_GROUPS,
2602870ad75aSSean Wilcox 			    vbuf));
26037c478bd9Sstevel@tonic-gate 
26047c478bd9Sstevel@tonic-gate 		case E2BIG:
2605870ad75aSSean Wilcox 			return (mc_error_create(merr, E2BIG,
2606870ad75aSSean Wilcox 			    "Too many supplemental groups values in \"%s\".",
2607870ad75aSSean Wilcox 			    vbuf));
26087c478bd9Sstevel@tonic-gate 
26097c478bd9Sstevel@tonic-gate 		default:
26107c478bd9Sstevel@tonic-gate 			bad_fail("get_groups", r);
26117c478bd9Sstevel@tonic-gate 		}
26127c478bd9Sstevel@tonic-gate 	} else {
26137c478bd9Sstevel@tonic-gate 		ci->ngroups = -1;
26147c478bd9Sstevel@tonic-gate 	}
26157c478bd9Sstevel@tonic-gate 
261613d8aaa1SSean Wilcox 	if (!(get_astring_val(methpg, SCF_PROPERTY_PRIVILEGES, vbuf, vbuf_sz,
261713d8aaa1SSean Wilcox 	    prop, val) == 0 || get_astring_val(instpg, SCF_PROPERTY_PRIVILEGES,
261813d8aaa1SSean Wilcox 	    vbuf, vbuf_sz, prop, val) == 0)) {
261913d8aaa1SSean Wilcox 		if (scf_error() == SCF_ERROR_NOT_FOUND) {
262013d8aaa1SSean Wilcox 			(void) strcpy(vbuf, ":default");
262113d8aaa1SSean Wilcox 		} else {
2622870ad75aSSean Wilcox 			return (mc_error_create(merr, ENOENT,
2623870ad75aSSean Wilcox 			    "Could not get \"%s\" property.",
2624870ad75aSSean Wilcox 			    SCF_PROPERTY_PRIVILEGES));
26257c478bd9Sstevel@tonic-gate 		}
262613d8aaa1SSean Wilcox 	}
26277c478bd9Sstevel@tonic-gate 
26287c478bd9Sstevel@tonic-gate 	/*
26297c478bd9Sstevel@tonic-gate 	 * For default privs, we need to keep priv_set == NULL, as
26307c478bd9Sstevel@tonic-gate 	 * we use this test elsewhere.
26317c478bd9Sstevel@tonic-gate 	 */
26327c478bd9Sstevel@tonic-gate 	if (strcmp(vbuf, ":default") != 0) {
26337c478bd9Sstevel@tonic-gate 		ci->priv_set = priv_str_to_set(vbuf, ",", NULL);
26347c478bd9Sstevel@tonic-gate 		if (ci->priv_set == NULL) {
26357c478bd9Sstevel@tonic-gate 			if (errno != EINVAL) {
2636870ad75aSSean Wilcox 				return (mc_error_create(merr, ENOMEM,
2637870ad75aSSean Wilcox 				    ALLOCFAIL));
26387c478bd9Sstevel@tonic-gate 			} else {
2639870ad75aSSean Wilcox 				return (mc_error_create(merr, EINVAL,
2640870ad75aSSean Wilcox 				    "Could not interpret \"%s\" "
2641870ad75aSSean Wilcox 				    "property value \"%s\".",
2642870ad75aSSean Wilcox 				    SCF_PROPERTY_PRIVILEGES, vbuf));
26437c478bd9Sstevel@tonic-gate 			}
26447c478bd9Sstevel@tonic-gate 		}
26457c478bd9Sstevel@tonic-gate 	}
26467c478bd9Sstevel@tonic-gate 
264713d8aaa1SSean Wilcox 	if (!(get_astring_val(methpg, SCF_PROPERTY_LIMIT_PRIVILEGES, vbuf,
264813d8aaa1SSean Wilcox 	    vbuf_sz, prop, val) == 0 || get_astring_val(instpg,
264913d8aaa1SSean Wilcox 	    SCF_PROPERTY_LIMIT_PRIVILEGES, vbuf, vbuf_sz, prop, val) == 0)) {
265013d8aaa1SSean Wilcox 		if (scf_error() == SCF_ERROR_NOT_FOUND) {
265113d8aaa1SSean Wilcox 			(void) strcpy(vbuf, ":default");
265213d8aaa1SSean Wilcox 		} else {
2653870ad75aSSean Wilcox 			return (mc_error_create(merr, ENOENT,
2654870ad75aSSean Wilcox 			    "Could not get \"%s\" property.",
2655870ad75aSSean Wilcox 			    SCF_PROPERTY_LIMIT_PRIVILEGES));
26567c478bd9Sstevel@tonic-gate 		}
265713d8aaa1SSean Wilcox 	}
26587c478bd9Sstevel@tonic-gate 
26597c478bd9Sstevel@tonic-gate 	if (strcmp(vbuf, ":default") == 0)
26607c478bd9Sstevel@tonic-gate 		/*
26617c478bd9Sstevel@tonic-gate 		 * L must default to all privileges so root NPA services see
26627c478bd9Sstevel@tonic-gate 		 * iE = all.  "zone" is all privileges available in the current
26637c478bd9Sstevel@tonic-gate 		 * zone, equivalent to "all" in the global zone.
26647c478bd9Sstevel@tonic-gate 		 */
26657c478bd9Sstevel@tonic-gate 		(void) strcpy(vbuf, "zone");
26667c478bd9Sstevel@tonic-gate 
26677c478bd9Sstevel@tonic-gate 	ci->lpriv_set = priv_str_to_set(vbuf, ",", NULL);
26687c478bd9Sstevel@tonic-gate 	if (ci->lpriv_set == NULL) {
2669870ad75aSSean Wilcox 		if (errno != EINVAL) {
2670870ad75aSSean Wilcox 			return (mc_error_create(merr, ENOMEM, ALLOCFAIL));
2671870ad75aSSean Wilcox 		} else {
2672870ad75aSSean Wilcox 			return (mc_error_create(merr, EINVAL,
2673870ad75aSSean Wilcox 			    "Could not interpret \"%s\" property value \"%s\".",
2674870ad75aSSean Wilcox 			    SCF_PROPERTY_LIMIT_PRIVILEGES, vbuf));
26757c478bd9Sstevel@tonic-gate 		}
26767c478bd9Sstevel@tonic-gate 	}
26777c478bd9Sstevel@tonic-gate 
2678870ad75aSSean Wilcox 	return (merr);
26797c478bd9Sstevel@tonic-gate }
26807c478bd9Sstevel@tonic-gate 
26817c478bd9Sstevel@tonic-gate static int
26827c478bd9Sstevel@tonic-gate get_environment(scf_handle_t *h, scf_propertygroup_t *pg,
26837c478bd9Sstevel@tonic-gate     struct method_context *mcp, scf_property_t *prop, scf_value_t *val)
26847c478bd9Sstevel@tonic-gate {
26857c478bd9Sstevel@tonic-gate 	scf_iter_t *iter;
26867c478bd9Sstevel@tonic-gate 	scf_type_t type;
26877c478bd9Sstevel@tonic-gate 	size_t i = 0;
26887c478bd9Sstevel@tonic-gate 	int ret;
26897c478bd9Sstevel@tonic-gate 
26907c478bd9Sstevel@tonic-gate 	if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, prop) != 0) {
26917c478bd9Sstevel@tonic-gate 		if (scf_error() == SCF_ERROR_NOT_FOUND)
26927c478bd9Sstevel@tonic-gate 			return (ENOENT);
26937c478bd9Sstevel@tonic-gate 		return (scf_error());
26947c478bd9Sstevel@tonic-gate 	}
26957c478bd9Sstevel@tonic-gate 	if (scf_property_type(prop, &type) != 0)
26967c478bd9Sstevel@tonic-gate 		return (scf_error());
26977c478bd9Sstevel@tonic-gate 	if (type != SCF_TYPE_ASTRING)
26987c478bd9Sstevel@tonic-gate 		return (EINVAL);
26997c478bd9Sstevel@tonic-gate 	if ((iter = scf_iter_create(h)) == NULL)
27007c478bd9Sstevel@tonic-gate 		return (scf_error());
27017c478bd9Sstevel@tonic-gate 
27027c478bd9Sstevel@tonic-gate 	if (scf_iter_property_values(iter, prop) != 0) {
27037c478bd9Sstevel@tonic-gate 		ret = scf_error();
27047c478bd9Sstevel@tonic-gate 		scf_iter_destroy(iter);
27057c478bd9Sstevel@tonic-gate 		return (ret);
27067c478bd9Sstevel@tonic-gate 	}
27077c478bd9Sstevel@tonic-gate 
27087c478bd9Sstevel@tonic-gate 	mcp->env_sz = 10;
27097c478bd9Sstevel@tonic-gate 
27107c478bd9Sstevel@tonic-gate 	if ((mcp->env = uu_zalloc(sizeof (*mcp->env) * mcp->env_sz)) == NULL) {
27117c478bd9Sstevel@tonic-gate 		ret = ENOMEM;
27127c478bd9Sstevel@tonic-gate 		goto out;
27137c478bd9Sstevel@tonic-gate 	}
27147c478bd9Sstevel@tonic-gate 
27157c478bd9Sstevel@tonic-gate 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
27167c478bd9Sstevel@tonic-gate 		ret = scf_value_get_as_string(val, mcp->vbuf, mcp->vbuf_sz);
27177c478bd9Sstevel@tonic-gate 		if (ret == -1) {
27187c478bd9Sstevel@tonic-gate 			ret = scf_error();
27197c478bd9Sstevel@tonic-gate 			goto out;
27207c478bd9Sstevel@tonic-gate 		}
27217c478bd9Sstevel@tonic-gate 
27227c478bd9Sstevel@tonic-gate 		if ((mcp->env[i] = strdup(mcp->vbuf)) == NULL) {
27237c478bd9Sstevel@tonic-gate 			ret = ENOMEM;
27247c478bd9Sstevel@tonic-gate 			goto out;
27257c478bd9Sstevel@tonic-gate 		}
27267c478bd9Sstevel@tonic-gate 
27277c478bd9Sstevel@tonic-gate 		if (++i == mcp->env_sz) {
27287c478bd9Sstevel@tonic-gate 			char **env;
27297c478bd9Sstevel@tonic-gate 			mcp->env_sz *= 2;
27307c478bd9Sstevel@tonic-gate 			env = uu_zalloc(sizeof (*mcp->env) * mcp->env_sz);
27317c478bd9Sstevel@tonic-gate 			if (env == NULL) {
27327c478bd9Sstevel@tonic-gate 				ret = ENOMEM;
27337c478bd9Sstevel@tonic-gate 				goto out;
27347c478bd9Sstevel@tonic-gate 			}
27357c478bd9Sstevel@tonic-gate 			(void) memcpy(env, mcp->env,
27367c478bd9Sstevel@tonic-gate 			    sizeof (*mcp->env) * (mcp->env_sz / 2));
27377c478bd9Sstevel@tonic-gate 			free(mcp->env);
27387c478bd9Sstevel@tonic-gate 			mcp->env = env;
27397c478bd9Sstevel@tonic-gate 		}
27407c478bd9Sstevel@tonic-gate 	}
27417c478bd9Sstevel@tonic-gate 
27427c478bd9Sstevel@tonic-gate 	if (ret == -1)
27437c478bd9Sstevel@tonic-gate 		ret = scf_error();
27447c478bd9Sstevel@tonic-gate 
27457c478bd9Sstevel@tonic-gate out:
27467c478bd9Sstevel@tonic-gate 	scf_iter_destroy(iter);
27477c478bd9Sstevel@tonic-gate 	return (ret);
27487c478bd9Sstevel@tonic-gate }
27497c478bd9Sstevel@tonic-gate 
27507c478bd9Sstevel@tonic-gate /*
27517c478bd9Sstevel@tonic-gate  * Fetch method context information from the repository, allocate and fill
2752870ad75aSSean Wilcox  * a method_context structure, return it in *mcpp, and return NULL.
27537c478bd9Sstevel@tonic-gate  *
275413d8aaa1SSean Wilcox  * If no method_context is defined, original init context is provided, where
275513d8aaa1SSean Wilcox  * the working directory is '/', and uid/gid are 0/0.  But if a method_context
275613d8aaa1SSean Wilcox  * is defined at any level the smf_method(5) method_context defaults are used.
275713d8aaa1SSean Wilcox  *
2758870ad75aSSean Wilcox  * Return an error message structure containing the error message
2759870ad75aSSean Wilcox  * with context, and the error so the caller can make a decision
2760870ad75aSSean Wilcox  * on what to do next.
2761870ad75aSSean Wilcox  *
2762870ad75aSSean Wilcox  * Error Types :
2763870ad75aSSean Wilcox  * 	E2BIG		Too many values or entry is too big
2764870ad75aSSean Wilcox  * 	EINVAL		Invalid value
2765870ad75aSSean Wilcox  * 	EIO		an I/O error has occured
2766870ad75aSSean Wilcox  * 	ENOENT		no entry for value
2767870ad75aSSean Wilcox  * 	ENOMEM		out of memory
2768870ad75aSSean Wilcox  * 	ENOTSUP		Version mismatch
2769870ad75aSSean Wilcox  * 	ERANGE		value is out of range
2770870ad75aSSean Wilcox  * 	EMFILE/ENFILE	out of file descriptors
2771870ad75aSSean Wilcox  *
2772870ad75aSSean Wilcox  * 	SCF_ERROR_BACKEND_ACCESS
2773870ad75aSSean Wilcox  * 	SCF_ERROR_CONNECTION_BROKEN
2774870ad75aSSean Wilcox  * 	SCF_ERROR_DELETED
2775870ad75aSSean Wilcox  * 	SCF_ERROR_CONSTRAINT_VIOLATED
2776870ad75aSSean Wilcox  * 	SCF_ERROR_HANDLE_DESTROYED
2777870ad75aSSean Wilcox  * 	SCF_ERROR_INTERNAL
2778870ad75aSSean Wilcox  * 	SCF_ERROR_INVALID_ARGUMENT
2779870ad75aSSean Wilcox  * 	SCF_ERROR_NO_MEMORY
2780870ad75aSSean Wilcox  * 	SCF_ERROR_NO_RESOURCES
2781870ad75aSSean Wilcox  * 	SCF_ERROR_NOT_BOUND
2782870ad75aSSean Wilcox  * 	SCF_ERROR_NOT_FOUND
2783870ad75aSSean Wilcox  * 	SCF_ERROR_NOT_SET
2784870ad75aSSean Wilcox  * 	SCF_ERROR_TYPE_MISMATCH
2785870ad75aSSean Wilcox  *
27867c478bd9Sstevel@tonic-gate  */
2787870ad75aSSean Wilcox mc_error_t *
27887c478bd9Sstevel@tonic-gate restarter_get_method_context(uint_t version, scf_instance_t *inst,
27897c478bd9Sstevel@tonic-gate     scf_snapshot_t *snap, const char *mname, const char *cmdline,
27907c478bd9Sstevel@tonic-gate     struct method_context **mcpp)
27917c478bd9Sstevel@tonic-gate {
27927c478bd9Sstevel@tonic-gate 	scf_handle_t *h;
27937c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *methpg = NULL;
27947c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *instpg = NULL;
27957c478bd9Sstevel@tonic-gate 	scf_propertygroup_t *pg = NULL;
27967c478bd9Sstevel@tonic-gate 	scf_property_t *prop = NULL;
27977c478bd9Sstevel@tonic-gate 	scf_value_t *val = NULL;
27987c478bd9Sstevel@tonic-gate 	scf_type_t ty;
27997c478bd9Sstevel@tonic-gate 	uint8_t use_profile;
2800870ad75aSSean Wilcox 	int ret = 0;
280113d8aaa1SSean Wilcox 	int mc_used = 0;
2802870ad75aSSean Wilcox 	mc_error_t *err = NULL;
28037c478bd9Sstevel@tonic-gate 	struct method_context *cip;
28047c478bd9Sstevel@tonic-gate 
2805870ad75aSSean Wilcox 	if ((err = malloc(sizeof (mc_error_t))) == NULL)
2806870ad75aSSean Wilcox 		return (mc_error_create(NULL, ENOMEM, NULL));
2807870ad75aSSean Wilcox 
2808870ad75aSSean Wilcox 	/* Set the type to zero to track if an error occured. */
2809870ad75aSSean Wilcox 	err->type = 0;
2810870ad75aSSean Wilcox 
28117c478bd9Sstevel@tonic-gate 	if (version != RESTARTER_METHOD_CONTEXT_VERSION)
2812870ad75aSSean Wilcox 		return (mc_error_create(err, ENOTSUP,
2813870ad75aSSean Wilcox 		    "Invalid client version %d. (Expected %d)",
2814870ad75aSSean Wilcox 		    version, RESTARTER_METHOD_CONTEXT_VERSION));
28157c478bd9Sstevel@tonic-gate 
28167c478bd9Sstevel@tonic-gate 	/* Get the handle before we allocate anything. */
28177c478bd9Sstevel@tonic-gate 	h = scf_instance_handle(inst);
28187c478bd9Sstevel@tonic-gate 	if (h == NULL)
2819870ad75aSSean Wilcox 		return (mc_error_create(err, scf_error(),
2820870ad75aSSean Wilcox 		    scf_strerror(scf_error())));
28217c478bd9Sstevel@tonic-gate 
28227c478bd9Sstevel@tonic-gate 	cip = malloc(sizeof (*cip));
28237c478bd9Sstevel@tonic-gate 	if (cip == NULL)
2824870ad75aSSean Wilcox 		return (mc_error_create(err, ENOMEM, ALLOCFAIL));
28257c478bd9Sstevel@tonic-gate 
28267c478bd9Sstevel@tonic-gate 	(void) memset(cip, 0, sizeof (*cip));
2827f48205beScasper 	cip->uid = (uid_t)-1;
2828f48205beScasper 	cip->euid = (uid_t)-1;
2829f48205beScasper 	cip->gid = (gid_t)-1;
2830f48205beScasper 	cip->egid = (gid_t)-1;
28317c478bd9Sstevel@tonic-gate 
28327c478bd9Sstevel@tonic-gate 	cip->vbuf_sz = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
28337c478bd9Sstevel@tonic-gate 	assert(cip->vbuf_sz >= 0);
28347c478bd9Sstevel@tonic-gate 	cip->vbuf = malloc(cip->vbuf_sz);
28357c478bd9Sstevel@tonic-gate 	if (cip->vbuf == NULL) {
28367c478bd9Sstevel@tonic-gate 		free(cip);
2837870ad75aSSean Wilcox 		return (mc_error_create(err, ENOMEM, ALLOCFAIL));
28387c478bd9Sstevel@tonic-gate 	}
28397c478bd9Sstevel@tonic-gate 
28407c478bd9Sstevel@tonic-gate 	if ((instpg = scf_pg_create(h)) == NULL ||
28417c478bd9Sstevel@tonic-gate 	    (methpg = scf_pg_create(h)) == NULL ||
28427c478bd9Sstevel@tonic-gate 	    (prop = scf_property_create(h)) == NULL ||
28437c478bd9Sstevel@tonic-gate 	    (val = scf_value_create(h)) == NULL) {
2844870ad75aSSean Wilcox 		err = mc_error_create(err, scf_error(),
2845870ad75aSSean Wilcox 		    "Failed to create repository object: %s\n",
2846870ad75aSSean Wilcox 		    scf_strerror(scf_error()));
28477c478bd9Sstevel@tonic-gate 		goto out;
28487c478bd9Sstevel@tonic-gate 	}
28497c478bd9Sstevel@tonic-gate 
28507c478bd9Sstevel@tonic-gate 	/*
28517c478bd9Sstevel@tonic-gate 	 * The method environment, and the credentials/profile data,
28527c478bd9Sstevel@tonic-gate 	 * may be found either in the pg for the method (methpg),
28537c478bd9Sstevel@tonic-gate 	 * or in the instance/service SCF_PG_METHOD_CONTEXT pg (named
28547c478bd9Sstevel@tonic-gate 	 * instpg below).
28557c478bd9Sstevel@tonic-gate 	 */
28567c478bd9Sstevel@tonic-gate 
28577c478bd9Sstevel@tonic-gate 	if (scf_instance_get_pg_composed(inst, snap, mname, methpg) !=
28587c478bd9Sstevel@tonic-gate 	    SCF_SUCCESS) {
2859870ad75aSSean Wilcox 		err = mc_error_create(err, scf_error(), "Unable to get the "
2860870ad75aSSean Wilcox 		    "\"%s\" method, %s", mname, scf_strerror(scf_error()));
28617c478bd9Sstevel@tonic-gate 		goto out;
28627c478bd9Sstevel@tonic-gate 	}
28637c478bd9Sstevel@tonic-gate 
28647c478bd9Sstevel@tonic-gate 	if (scf_instance_get_pg_composed(inst, snap, SCF_PG_METHOD_CONTEXT,
28657c478bd9Sstevel@tonic-gate 	    instpg) != SCF_SUCCESS) {
28667c478bd9Sstevel@tonic-gate 		if (scf_error() != SCF_ERROR_NOT_FOUND) {
2867870ad75aSSean Wilcox 			err = mc_error_create(err, scf_error(),
2868870ad75aSSean Wilcox 			    "Unable to retrieve the \"%s\" property group, %s",
2869870ad75aSSean Wilcox 			    SCF_PG_METHOD_CONTEXT, scf_strerror(scf_error()));
28707c478bd9Sstevel@tonic-gate 			goto out;
28717c478bd9Sstevel@tonic-gate 		}
28727c478bd9Sstevel@tonic-gate 		scf_pg_destroy(instpg);
28737c478bd9Sstevel@tonic-gate 		instpg = NULL;
287413d8aaa1SSean Wilcox 	} else {
287513d8aaa1SSean Wilcox 		mc_used++;
28767c478bd9Sstevel@tonic-gate 	}
28777c478bd9Sstevel@tonic-gate 
28787c478bd9Sstevel@tonic-gate 	ret = get_environment(h, methpg, cip, prop, val);
28797c478bd9Sstevel@tonic-gate 	if (ret == ENOENT && instpg != NULL) {
28807c478bd9Sstevel@tonic-gate 		ret = get_environment(h, instpg, cip, prop, val);
28817c478bd9Sstevel@tonic-gate 	}
28827c478bd9Sstevel@tonic-gate 
28837c478bd9Sstevel@tonic-gate 	switch (ret) {
28847c478bd9Sstevel@tonic-gate 	case 0:
288513d8aaa1SSean Wilcox 		mc_used++;
288613d8aaa1SSean Wilcox 		break;
28877c478bd9Sstevel@tonic-gate 	case ENOENT:
28887c478bd9Sstevel@tonic-gate 		break;
28897c478bd9Sstevel@tonic-gate 	case ENOMEM:
2890870ad75aSSean Wilcox 		err = mc_error_create(err, ret, "Out of memory.");
28917c478bd9Sstevel@tonic-gate 		goto out;
28927c478bd9Sstevel@tonic-gate 	case EINVAL:
2893870ad75aSSean Wilcox 		err = mc_error_create(err, ret, "Invalid method environment.");
28947c478bd9Sstevel@tonic-gate 		goto out;
28957c478bd9Sstevel@tonic-gate 	default:
2896870ad75aSSean Wilcox 		err = mc_error_create(err, ret,
2897870ad75aSSean Wilcox 		    "Get method environment failed : %s\n", scf_strerror(ret));
28987c478bd9Sstevel@tonic-gate 		goto out;
28997c478bd9Sstevel@tonic-gate 	}
29007c478bd9Sstevel@tonic-gate 
29017c478bd9Sstevel@tonic-gate 	pg = methpg;
29027c478bd9Sstevel@tonic-gate 
29037c478bd9Sstevel@tonic-gate 	ret = scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, prop);
29047c478bd9Sstevel@tonic-gate 	if (ret && scf_error() == SCF_ERROR_NOT_FOUND && instpg != NULL) {
290513d8aaa1SSean Wilcox 		pg = NULL;
290613d8aaa1SSean Wilcox 		ret = scf_pg_get_property(instpg, SCF_PROPERTY_USE_PROFILE,
290713d8aaa1SSean Wilcox 		    prop);
29087c478bd9Sstevel@tonic-gate 	}
29097c478bd9Sstevel@tonic-gate 
29107c478bd9Sstevel@tonic-gate 	if (ret) {
29117c478bd9Sstevel@tonic-gate 		switch (scf_error()) {
29127c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
291313d8aaa1SSean Wilcox 			/* No profile context: use default credentials */
29147c478bd9Sstevel@tonic-gate 			cip->uid = 0;
29157c478bd9Sstevel@tonic-gate 			cip->gid = 0;
291613d8aaa1SSean Wilcox 			break;
29177c478bd9Sstevel@tonic-gate 
29187c478bd9Sstevel@tonic-gate 		case SCF_ERROR_CONNECTION_BROKEN:
2919870ad75aSSean Wilcox 			err = mc_error_create(err, SCF_ERROR_CONNECTION_BROKEN,
2920870ad75aSSean Wilcox 			    RCBROKEN);
29217c478bd9Sstevel@tonic-gate 			goto out;
29227c478bd9Sstevel@tonic-gate 
29237c478bd9Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
2924870ad75aSSean Wilcox 			err = mc_error_create(err, SCF_ERROR_NOT_FOUND,
2925870ad75aSSean Wilcox 			    "Could not find property group \"%s\"",
2926870ad75aSSean Wilcox 			    pg == NULL ? SCF_PG_METHOD_CONTEXT : mname);
29277c478bd9Sstevel@tonic-gate 			goto out;
29287c478bd9Sstevel@tonic-gate 
29297c478bd9Sstevel@tonic-gate 		case SCF_ERROR_HANDLE_MISMATCH:
29307c478bd9Sstevel@tonic-gate 		case SCF_ERROR_INVALID_ARGUMENT:
29317c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
29327c478bd9Sstevel@tonic-gate 		default:
29337c478bd9Sstevel@tonic-gate 			bad_fail("scf_pg_get_property", scf_error());
29347c478bd9Sstevel@tonic-gate 		}
293513d8aaa1SSean Wilcox 	} else {
29367c478bd9Sstevel@tonic-gate 		if (scf_property_type(prop, &ty) != SCF_SUCCESS) {
2937870ad75aSSean Wilcox 			ret = scf_error();
2938870ad75aSSean Wilcox 			switch (ret) {
29397c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
2940870ad75aSSean Wilcox 				err = mc_error_create(err,
2941870ad75aSSean Wilcox 				    SCF_ERROR_CONNECTION_BROKEN, RCBROKEN);
29427c478bd9Sstevel@tonic-gate 				break;
29437c478bd9Sstevel@tonic-gate 
29447c478bd9Sstevel@tonic-gate 			case SCF_ERROR_DELETED:
2945870ad75aSSean Wilcox 				err = mc_error_create(err,
2946870ad75aSSean Wilcox 				    SCF_ERROR_NOT_FOUND,
2947870ad75aSSean Wilcox 				    "Could not find property group \"%s\"",
2948870ad75aSSean Wilcox 				    pg == NULL ? SCF_PG_METHOD_CONTEXT : mname);
29497c478bd9Sstevel@tonic-gate 				break;
29507c478bd9Sstevel@tonic-gate 
29517c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_SET:
29527c478bd9Sstevel@tonic-gate 			default:
2953870ad75aSSean Wilcox 				bad_fail("scf_property_type", ret);
29547c478bd9Sstevel@tonic-gate 			}
29557c478bd9Sstevel@tonic-gate 
29567c478bd9Sstevel@tonic-gate 			goto out;
29577c478bd9Sstevel@tonic-gate 		}
29587c478bd9Sstevel@tonic-gate 
29597c478bd9Sstevel@tonic-gate 		if (ty != SCF_TYPE_BOOLEAN) {
2960870ad75aSSean Wilcox 			err = mc_error_create(err,
2961870ad75aSSean Wilcox 			    SCF_ERROR_TYPE_MISMATCH,
2962870ad75aSSean Wilcox 			    "\"%s\" property is not boolean in property group "
2963870ad75aSSean Wilcox 			    "\"%s\".", SCF_PROPERTY_USE_PROFILE,
2964870ad75aSSean Wilcox 			    pg == NULL ? SCF_PG_METHOD_CONTEXT : mname);
29657c478bd9Sstevel@tonic-gate 			goto out;
29667c478bd9Sstevel@tonic-gate 		}
29677c478bd9Sstevel@tonic-gate 
29687c478bd9Sstevel@tonic-gate 		if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
2969870ad75aSSean Wilcox 			ret = scf_error();
2970870ad75aSSean Wilcox 			switch (ret) {
29717c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONNECTION_BROKEN:
2972870ad75aSSean Wilcox 				err = mc_error_create(err,
2973870ad75aSSean Wilcox 				    SCF_ERROR_CONNECTION_BROKEN, RCBROKEN);
29747c478bd9Sstevel@tonic-gate 				break;
29757c478bd9Sstevel@tonic-gate 
29767c478bd9Sstevel@tonic-gate 			case SCF_ERROR_CONSTRAINT_VIOLATED:
2977870ad75aSSean Wilcox 				err = mc_error_create(err,
2978870ad75aSSean Wilcox 				    SCF_ERROR_CONSTRAINT_VIOLATED,
2979870ad75aSSean Wilcox 				    "\"%s\" property has multiple values.",
2980870ad75aSSean Wilcox 				    SCF_PROPERTY_USE_PROFILE);
29817c478bd9Sstevel@tonic-gate 				break;
29827c478bd9Sstevel@tonic-gate 
29837c478bd9Sstevel@tonic-gate 			case SCF_ERROR_NOT_FOUND:
2984870ad75aSSean Wilcox 				err = mc_error_create(err,
2985870ad75aSSean Wilcox 				    SCF_ERROR_NOT_FOUND,
2986870ad75aSSean Wilcox 				    "\"%s\" property has no values.",
2987870ad75aSSean Wilcox 				    SCF_PROPERTY_USE_PROFILE);
29887c478bd9Sstevel@tonic-gate 				break;
29897c478bd9Sstevel@tonic-gate 			default:
2990870ad75aSSean Wilcox 				bad_fail("scf_property_get_value", ret);
29917c478bd9Sstevel@tonic-gate 			}
29927c478bd9Sstevel@tonic-gate 
29937c478bd9Sstevel@tonic-gate 			goto out;
29947c478bd9Sstevel@tonic-gate 		}
29957c478bd9Sstevel@tonic-gate 
299613d8aaa1SSean Wilcox 		mc_used++;
29977c478bd9Sstevel@tonic-gate 		ret = scf_value_get_boolean(val, &use_profile);
29987c478bd9Sstevel@tonic-gate 		assert(ret == SCF_SUCCESS);
29997c478bd9Sstevel@tonic-gate 
30007c478bd9Sstevel@tonic-gate 		/* get ids & privileges */
30017c478bd9Sstevel@tonic-gate 		if (use_profile)
3002870ad75aSSean Wilcox 			err = get_profile(pg, instpg, prop, val, cmdline,
3003870ad75aSSean Wilcox 			    cip, err);
30047c478bd9Sstevel@tonic-gate 		else
3005870ad75aSSean Wilcox 			err = get_ids(pg, instpg, prop, val, cip, err);
300613d8aaa1SSean Wilcox 
3007870ad75aSSean Wilcox 		if (err->type != 0)
30087c478bd9Sstevel@tonic-gate 			goto out;
300913d8aaa1SSean Wilcox 	}
30107c478bd9Sstevel@tonic-gate 
30117c478bd9Sstevel@tonic-gate 	/* get working directory */
301213d8aaa1SSean Wilcox 	if ((methpg != NULL && scf_pg_get_property(methpg,
301313d8aaa1SSean Wilcox 	    SCF_PROPERTY_WORKING_DIRECTORY, prop) == SCF_SUCCESS) ||
301413d8aaa1SSean Wilcox 	    (instpg != NULL && scf_pg_get_property(instpg,
301513d8aaa1SSean Wilcox 	    SCF_PROPERTY_WORKING_DIRECTORY, prop) == SCF_SUCCESS)) {
301613d8aaa1SSean Wilcox 		if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
3017870ad75aSSean Wilcox 			ret = scf_error();
3018870ad75aSSean Wilcox 			switch (ret) {
301913d8aaa1SSean Wilcox 			case SCF_ERROR_CONNECTION_BROKEN:
3020870ad75aSSean Wilcox 				err = mc_error_create(err, ret, RCBROKEN);
302113d8aaa1SSean Wilcox 				break;
302213d8aaa1SSean Wilcox 
302313d8aaa1SSean Wilcox 			case SCF_ERROR_CONSTRAINT_VIOLATED:
3024870ad75aSSean Wilcox 				err = mc_error_create(err, ret,
3025870ad75aSSean Wilcox 				    "\"%s\" property has multiple values.",
3026870ad75aSSean Wilcox 				    SCF_PROPERTY_WORKING_DIRECTORY);
302713d8aaa1SSean Wilcox 				break;
302813d8aaa1SSean Wilcox 
302913d8aaa1SSean Wilcox 			case SCF_ERROR_NOT_FOUND:
3030870ad75aSSean Wilcox 				err = mc_error_create(err, ret,
3031870ad75aSSean Wilcox 				    "\"%s\" property has no values.",
3032870ad75aSSean Wilcox 				    SCF_PROPERTY_WORKING_DIRECTORY);
303313d8aaa1SSean Wilcox 				break;
303413d8aaa1SSean Wilcox 
303513d8aaa1SSean Wilcox 			default:
3036870ad75aSSean Wilcox 				bad_fail("scf_property_get_value", ret);
303713d8aaa1SSean Wilcox 			}
303813d8aaa1SSean Wilcox 
30397c478bd9Sstevel@tonic-gate 			goto out;
30407c478bd9Sstevel@tonic-gate 		}
30417c478bd9Sstevel@tonic-gate 
304213d8aaa1SSean Wilcox 		mc_used++;
304313d8aaa1SSean Wilcox 		ret = scf_value_get_astring(val, cip->vbuf, cip->vbuf_sz);
304413d8aaa1SSean Wilcox 		assert(ret != -1);
304513d8aaa1SSean Wilcox 	} else {
3046870ad75aSSean Wilcox 		ret = scf_error();
3047870ad75aSSean Wilcox 		switch (ret) {
304813d8aaa1SSean Wilcox 		case SCF_ERROR_NOT_FOUND:
304913d8aaa1SSean Wilcox 			/* okay if missing. */
305013d8aaa1SSean Wilcox 			(void) strcpy(cip->vbuf, ":default");
305113d8aaa1SSean Wilcox 			break;
305213d8aaa1SSean Wilcox 
305313d8aaa1SSean Wilcox 		case SCF_ERROR_CONNECTION_BROKEN:
3054870ad75aSSean Wilcox 			err = mc_error_create(err, ret, RCBROKEN);
305513d8aaa1SSean Wilcox 			goto out;
305613d8aaa1SSean Wilcox 
305713d8aaa1SSean Wilcox 		case SCF_ERROR_DELETED:
3058870ad75aSSean Wilcox 			err = mc_error_create(err, ret,
3059870ad75aSSean Wilcox 			    "Property group could not be found");
306013d8aaa1SSean Wilcox 			goto out;
306113d8aaa1SSean Wilcox 
306213d8aaa1SSean Wilcox 		case SCF_ERROR_HANDLE_MISMATCH:
306313d8aaa1SSean Wilcox 		case SCF_ERROR_INVALID_ARGUMENT:
306413d8aaa1SSean Wilcox 		case SCF_ERROR_NOT_SET:
306513d8aaa1SSean Wilcox 		default:
3066870ad75aSSean Wilcox 			bad_fail("scf_pg_get_property", ret);
306713d8aaa1SSean Wilcox 		}
306813d8aaa1SSean Wilcox 	}
306913d8aaa1SSean Wilcox 
30707c478bd9Sstevel@tonic-gate 	if (strcmp(cip->vbuf, ":default") == 0 ||
30717c478bd9Sstevel@tonic-gate 	    strcmp(cip->vbuf, ":home") == 0) {
30727c478bd9Sstevel@tonic-gate 		switch (ret = lookup_pwd(cip)) {
30737c478bd9Sstevel@tonic-gate 		case 0:
30747c478bd9Sstevel@tonic-gate 			break;
30757c478bd9Sstevel@tonic-gate 
30767c478bd9Sstevel@tonic-gate 		case ENOMEM:
3077870ad75aSSean Wilcox 			err = mc_error_create(err, ret, "Out of memory.");
30787c478bd9Sstevel@tonic-gate 			goto out;
30797c478bd9Sstevel@tonic-gate 
30807c478bd9Sstevel@tonic-gate 		case ENOENT:
30817c478bd9Sstevel@tonic-gate 		case EIO:
30827c478bd9Sstevel@tonic-gate 		case EMFILE:
30837c478bd9Sstevel@tonic-gate 		case ENFILE:
3084870ad75aSSean Wilcox 			err = mc_error_create(err, ret,
3085870ad75aSSean Wilcox 			    "Could not get passwd entry.");
30867c478bd9Sstevel@tonic-gate 			goto out;
30877c478bd9Sstevel@tonic-gate 
30887c478bd9Sstevel@tonic-gate 		default:
30897c478bd9Sstevel@tonic-gate 			bad_fail("lookup_pwd", ret);
30907c478bd9Sstevel@tonic-gate 		}
30917c478bd9Sstevel@tonic-gate 
30927c478bd9Sstevel@tonic-gate 		cip->working_dir = strdup(cip->pwd.pw_dir);
30937c478bd9Sstevel@tonic-gate 		if (cip->working_dir == NULL) {
3094870ad75aSSean Wilcox 			err = mc_error_create(err, ENOMEM, ALLOCFAIL);
30957c478bd9Sstevel@tonic-gate 			goto out;
30967c478bd9Sstevel@tonic-gate 		}
30977c478bd9Sstevel@tonic-gate 	} else {
30987c478bd9Sstevel@tonic-gate 		cip->working_dir = strdup(cip->vbuf);
30997c478bd9Sstevel@tonic-gate 		if (cip->working_dir == NULL) {
3100870ad75aSSean Wilcox 			err = mc_error_create(err, ENOMEM, ALLOCFAIL);
31017c478bd9Sstevel@tonic-gate 			goto out;
31027c478bd9Sstevel@tonic-gate 		}
31037c478bd9Sstevel@tonic-gate 	}
31047c478bd9Sstevel@tonic-gate 
31057c478bd9Sstevel@tonic-gate 	/* get (optional) corefile pattern */
310613d8aaa1SSean Wilcox 	if ((methpg != NULL && scf_pg_get_property(methpg,
310713d8aaa1SSean Wilcox 	    SCF_PROPERTY_COREFILE_PATTERN, prop) == SCF_SUCCESS) ||
310813d8aaa1SSean Wilcox 	    (instpg != NULL && scf_pg_get_property(instpg,
310913d8aaa1SSean Wilcox 	    SCF_PROPERTY_COREFILE_PATTERN, prop) == SCF_SUCCESS)) {
311013d8aaa1SSean Wilcox 		if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
3111870ad75aSSean Wilcox 			ret = scf_error();
3112870ad75aSSean Wilcox 			switch (ret) {
311313d8aaa1SSean Wilcox 			case SCF_ERROR_CONNECTION_BROKEN:
3114870ad75aSSean Wilcox 				err = mc_error_create(err, ret, RCBROKEN);
311513d8aaa1SSean Wilcox 				break;
311613d8aaa1SSean Wilcox 
311713d8aaa1SSean Wilcox 			case SCF_ERROR_CONSTRAINT_VIOLATED:
3118870ad75aSSean Wilcox 				err = mc_error_create(err, ret,
3119870ad75aSSean Wilcox 				    "\"%s\" property has multiple values.",
3120870ad75aSSean Wilcox 				    SCF_PROPERTY_COREFILE_PATTERN);
312113d8aaa1SSean Wilcox 				break;
312213d8aaa1SSean Wilcox 
312313d8aaa1SSean Wilcox 			case SCF_ERROR_NOT_FOUND:
3124870ad75aSSean Wilcox 				err = mc_error_create(err, ret,
3125870ad75aSSean Wilcox 				    "\"%s\" property has no values.",
3126870ad75aSSean Wilcox 				    SCF_PROPERTY_COREFILE_PATTERN);
312713d8aaa1SSean Wilcox 				break;
312813d8aaa1SSean Wilcox 
312913d8aaa1SSean Wilcox 			default:
3130870ad75aSSean Wilcox 				bad_fail("scf_property_get_value", ret);
31317c478bd9Sstevel@tonic-gate 			}
31327c478bd9Sstevel@tonic-gate 
313313d8aaa1SSean Wilcox 		} else {
313413d8aaa1SSean Wilcox 
313513d8aaa1SSean Wilcox 			ret = scf_value_get_astring(val, cip->vbuf,
313613d8aaa1SSean Wilcox 			    cip->vbuf_sz);
313713d8aaa1SSean Wilcox 			assert(ret != -1);
313813d8aaa1SSean Wilcox 
31397c478bd9Sstevel@tonic-gate 			cip->corefile_pattern = strdup(cip->vbuf);
31407c478bd9Sstevel@tonic-gate 			if (cip->corefile_pattern == NULL) {
3141870ad75aSSean Wilcox 				err = mc_error_create(err, ENOMEM, ALLOCFAIL);
31427c478bd9Sstevel@tonic-gate 				goto out;
31437c478bd9Sstevel@tonic-gate 			}
314413d8aaa1SSean Wilcox 		}
314513d8aaa1SSean Wilcox 
314613d8aaa1SSean Wilcox 		mc_used++;
31477c478bd9Sstevel@tonic-gate 	} else {
3148870ad75aSSean Wilcox 		ret = scf_error();
3149870ad75aSSean Wilcox 		switch (ret) {
31507c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_FOUND:
31517c478bd9Sstevel@tonic-gate 			/* okay if missing. */
31527c478bd9Sstevel@tonic-gate 			break;
31537c478bd9Sstevel@tonic-gate 
31547c478bd9Sstevel@tonic-gate 		case SCF_ERROR_CONNECTION_BROKEN:
3155870ad75aSSean Wilcox 			err = mc_error_create(err, ret, RCBROKEN);
31567c478bd9Sstevel@tonic-gate 			goto out;
31577c478bd9Sstevel@tonic-gate 
31587c478bd9Sstevel@tonic-gate 		case SCF_ERROR_DELETED:
3159870ad75aSSean Wilcox 			err = mc_error_create(err, ret,
3160870ad75aSSean Wilcox 			    "Property group could not be found");
31617c478bd9Sstevel@tonic-gate 			goto out;
31627c478bd9Sstevel@tonic-gate 
31637c478bd9Sstevel@tonic-gate 		case SCF_ERROR_HANDLE_MISMATCH:
31647c478bd9Sstevel@tonic-gate 		case SCF_ERROR_INVALID_ARGUMENT:
31657c478bd9Sstevel@tonic-gate 		case SCF_ERROR_NOT_SET:
31667c478bd9Sstevel@tonic-gate 		default:
3167870ad75aSSean Wilcox 			bad_fail("scf_pg_get_property", ret);
31687c478bd9Sstevel@tonic-gate 		}
31697c478bd9Sstevel@tonic-gate 	}
31707c478bd9Sstevel@tonic-gate 
31717c478bd9Sstevel@tonic-gate 	if (restarter_rm_libs_loadable()) {
31727c478bd9Sstevel@tonic-gate 		/* get project */
317313d8aaa1SSean Wilcox 		if ((methpg != NULL && scf_pg_get_property(methpg,
317413d8aaa1SSean Wilcox 		    SCF_PROPERTY_PROJECT, prop) == SCF_SUCCESS) ||
317513d8aaa1SSean Wilcox 		    (instpg != NULL && scf_pg_get_property(instpg,
317613d8aaa1SSean Wilcox 		    SCF_PROPERTY_PROJECT, prop) == SCF_SUCCESS)) {
317713d8aaa1SSean Wilcox 			if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
3178870ad75aSSean Wilcox 				ret = scf_error();
3179870ad75aSSean Wilcox 				switch (ret) {
318013d8aaa1SSean Wilcox 				case SCF_ERROR_CONNECTION_BROKEN:
3181870ad75aSSean Wilcox 					err = mc_error_create(err, ret,
3182870ad75aSSean Wilcox 					    RCBROKEN);
318313d8aaa1SSean Wilcox 					break;
318413d8aaa1SSean Wilcox 
318513d8aaa1SSean Wilcox 				case SCF_ERROR_CONSTRAINT_VIOLATED:
3186870ad75aSSean Wilcox 					err = mc_error_create(err, ret,
3187870ad75aSSean Wilcox 					    "\"%s\" property has multiple "
3188870ad75aSSean Wilcox 					    "values.", SCF_PROPERTY_PROJECT);
318913d8aaa1SSean Wilcox 					break;
319013d8aaa1SSean Wilcox 
319113d8aaa1SSean Wilcox 				case SCF_ERROR_NOT_FOUND:
3192870ad75aSSean Wilcox 					err = mc_error_create(err, ret,
3193870ad75aSSean Wilcox 					    "\"%s\" property has no values.",
3194870ad75aSSean Wilcox 					    SCF_PROPERTY_PROJECT);
319513d8aaa1SSean Wilcox 					break;
319613d8aaa1SSean Wilcox 
319713d8aaa1SSean Wilcox 				default:
3198870ad75aSSean Wilcox 					bad_fail("scf_property_get_value", ret);
319913d8aaa1SSean Wilcox 				}
320013d8aaa1SSean Wilcox 
320113d8aaa1SSean Wilcox 				(void) strcpy(cip->vbuf, ":default");
320213d8aaa1SSean Wilcox 			} else {
320313d8aaa1SSean Wilcox 				ret = scf_value_get_astring(val, cip->vbuf,
320413d8aaa1SSean Wilcox 				    cip->vbuf_sz);
320513d8aaa1SSean Wilcox 				assert(ret != -1);
320613d8aaa1SSean Wilcox 			}
320713d8aaa1SSean Wilcox 
320813d8aaa1SSean Wilcox 			mc_used++;
320913d8aaa1SSean Wilcox 		} else {
321013d8aaa1SSean Wilcox 			(void) strcpy(cip->vbuf, ":default");
32117c478bd9Sstevel@tonic-gate 		}
32127c478bd9Sstevel@tonic-gate 
32137c478bd9Sstevel@tonic-gate 		switch (ret = get_projid(cip->vbuf, cip)) {
32147c478bd9Sstevel@tonic-gate 		case 0:
32157c478bd9Sstevel@tonic-gate 			break;
32167c478bd9Sstevel@tonic-gate 
32177c478bd9Sstevel@tonic-gate 		case ENOMEM:
3218870ad75aSSean Wilcox 			err = mc_error_create(err, ret, "Out of memory.");
32197c478bd9Sstevel@tonic-gate 			goto out;
32207c478bd9Sstevel@tonic-gate 
32217c478bd9Sstevel@tonic-gate 		case ENOENT:
3222870ad75aSSean Wilcox 			err = mc_error_create(err, ret,
3223870ad75aSSean Wilcox 			    "Missing passwd or project entry for \"%s\".",
3224870ad75aSSean Wilcox 			    cip->vbuf);
32257c478bd9Sstevel@tonic-gate 			goto out;
32267c478bd9Sstevel@tonic-gate 
32277c478bd9Sstevel@tonic-gate 		case EIO:
3228870ad75aSSean Wilcox 			err = mc_error_create(err, ret, "I/O error.");
32297c478bd9Sstevel@tonic-gate 			goto out;
32307c478bd9Sstevel@tonic-gate 
32317c478bd9Sstevel@tonic-gate 		case EMFILE:
32327c478bd9Sstevel@tonic-gate 		case ENFILE:
3233870ad75aSSean Wilcox 			err = mc_error_create(err, ret,
3234870ad75aSSean Wilcox 			    "Out of file descriptors.");
32357c478bd9Sstevel@tonic-gate 			goto out;
32367c478bd9Sstevel@tonic-gate 
32377c478bd9Sstevel@tonic-gate 		case -1:
3238870ad75aSSean Wilcox 			err = mc_error_create(err, ret,
3239870ad75aSSean Wilcox 			    "Name service switch is misconfigured.");
32407c478bd9Sstevel@tonic-gate 			goto out;
32417c478bd9Sstevel@tonic-gate 
32427c478bd9Sstevel@tonic-gate 		case ERANGE:
3243870ad75aSSean Wilcox 		case E2BIG:
3244870ad75aSSean Wilcox 			err = mc_error_create(err, ret,
3245870ad75aSSean Wilcox 			    "Project ID \"%s\" too big.", cip->vbuf);
32467c478bd9Sstevel@tonic-gate 			goto out;
32477c478bd9Sstevel@tonic-gate 
32487c478bd9Sstevel@tonic-gate 		case EINVAL:
3249870ad75aSSean Wilcox 			err = mc_error_create(err, ret,
3250870ad75aSSean Wilcox 			    "Project ID \"%s\" is invalid.", cip->vbuf);
32517c478bd9Sstevel@tonic-gate 			goto out;
32527c478bd9Sstevel@tonic-gate 
32537c478bd9Sstevel@tonic-gate 		default:
32547c478bd9Sstevel@tonic-gate 			bad_fail("get_projid", ret);
32557c478bd9Sstevel@tonic-gate 		}
32567c478bd9Sstevel@tonic-gate 
32577c478bd9Sstevel@tonic-gate 		/* get resource pool */
325813d8aaa1SSean Wilcox 		if ((methpg != NULL && scf_pg_get_property(methpg,
325913d8aaa1SSean Wilcox 		    SCF_PROPERTY_RESOURCE_POOL, prop) == SCF_SUCCESS) ||
326013d8aaa1SSean Wilcox 		    (instpg != NULL && scf_pg_get_property(instpg,
326113d8aaa1SSean Wilcox 		    SCF_PROPERTY_RESOURCE_POOL, prop) == SCF_SUCCESS)) {
326213d8aaa1SSean Wilcox 			if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
3263870ad75aSSean Wilcox 				ret = scf_error();
3264870ad75aSSean Wilcox 				switch (ret) {
326513d8aaa1SSean Wilcox 				case SCF_ERROR_CONNECTION_BROKEN:
3266870ad75aSSean Wilcox 					err = mc_error_create(err, ret,
3267870ad75aSSean Wilcox 					    RCBROKEN);
326813d8aaa1SSean Wilcox 					break;
326913d8aaa1SSean Wilcox 
327013d8aaa1SSean Wilcox 				case SCF_ERROR_CONSTRAINT_VIOLATED:
3271870ad75aSSean Wilcox 					err = mc_error_create(err, ret,
3272870ad75aSSean Wilcox 					    "\"%s\" property has multiple "
3273870ad75aSSean Wilcox 					    "values.",
3274870ad75aSSean Wilcox 					    SCF_PROPERTY_RESOURCE_POOL);
327513d8aaa1SSean Wilcox 					break;
327613d8aaa1SSean Wilcox 
327713d8aaa1SSean Wilcox 				case SCF_ERROR_NOT_FOUND:
3278870ad75aSSean Wilcox 					err = mc_error_create(err, ret,
3279870ad75aSSean Wilcox 					    "\"%s\" property has no "
3280870ad75aSSean Wilcox 					    "values.",
3281870ad75aSSean Wilcox 					    SCF_PROPERTY_RESOURCE_POOL);
328213d8aaa1SSean Wilcox 					break;
328313d8aaa1SSean Wilcox 
328413d8aaa1SSean Wilcox 				default:
3285870ad75aSSean Wilcox 					bad_fail("scf_property_get_value", ret);
328613d8aaa1SSean Wilcox 				}
328713d8aaa1SSean Wilcox 
328813d8aaa1SSean Wilcox 				(void) strcpy(cip->vbuf, ":default");
328913d8aaa1SSean Wilcox 			} else {
329013d8aaa1SSean Wilcox 				ret = scf_value_get_astring(val, cip->vbuf,
329113d8aaa1SSean Wilcox 				    cip->vbuf_sz);
329213d8aaa1SSean Wilcox 				assert(ret != -1);
329313d8aaa1SSean Wilcox 			}
329413d8aaa1SSean Wilcox 
329513d8aaa1SSean Wilcox 			mc_used++;
329613d8aaa1SSean Wilcox 		} else {
3297870ad75aSSean Wilcox 			ret = scf_error();
3298870ad75aSSean Wilcox 			switch (ret) {
329913d8aaa1SSean Wilcox 			case SCF_ERROR_NOT_FOUND:
330013d8aaa1SSean Wilcox 				/* okay if missing. */
330113d8aaa1SSean Wilcox 				(void) strcpy(cip->vbuf, ":default");
330213d8aaa1SSean Wilcox 				break;
330313d8aaa1SSean Wilcox 
330413d8aaa1SSean Wilcox 			case SCF_ERROR_CONNECTION_BROKEN:
3305870ad75aSSean Wilcox 				err = mc_error_create(err, ret, RCBROKEN);
33067c478bd9Sstevel@tonic-gate 				goto out;
330713d8aaa1SSean Wilcox 
330813d8aaa1SSean Wilcox 			case SCF_ERROR_DELETED:
3309870ad75aSSean Wilcox 				err = mc_error_create(err, ret,
3310870ad75aSSean Wilcox 				    "property group could not be found.");
331113d8aaa1SSean Wilcox 				goto out;
331213d8aaa1SSean Wilcox 
331313d8aaa1SSean Wilcox 			case SCF_ERROR_HANDLE_MISMATCH:
331413d8aaa1SSean Wilcox 			case SCF_ERROR_INVALID_ARGUMENT:
331513d8aaa1SSean Wilcox 			case SCF_ERROR_NOT_SET:
331613d8aaa1SSean Wilcox 			default:
3317870ad75aSSean Wilcox 				bad_fail("scf_pg_get_property", ret);
331813d8aaa1SSean Wilcox 			}
33197c478bd9Sstevel@tonic-gate 		}
33207c478bd9Sstevel@tonic-gate 
33217c478bd9Sstevel@tonic-gate 		if (strcmp(cip->vbuf, ":default") != 0) {
33227c478bd9Sstevel@tonic-gate 			cip->resource_pool = strdup(cip->vbuf);
33237c478bd9Sstevel@tonic-gate 			if (cip->resource_pool == NULL) {
3324870ad75aSSean Wilcox 				err = mc_error_create(err, ENOMEM, ALLOCFAIL);
33257c478bd9Sstevel@tonic-gate 				goto out;
33267c478bd9Sstevel@tonic-gate 			}
33277c478bd9Sstevel@tonic-gate 		}
33287c478bd9Sstevel@tonic-gate 	}
33297c478bd9Sstevel@tonic-gate 
333013d8aaa1SSean Wilcox 	/*
333113d8aaa1SSean Wilcox 	 * A method_context was not used for any configurable
333213d8aaa1SSean Wilcox 	 * elements or attributes, so reset and use the simple
333313d8aaa1SSean Wilcox 	 * defaults that provide historic init behavior.
333413d8aaa1SSean Wilcox 	 */
333513d8aaa1SSean Wilcox 	if (mc_used == 0) {
333613d8aaa1SSean Wilcox 		(void) memset(cip, 0, sizeof (*cip));
333713d8aaa1SSean Wilcox 		cip->uid = 0;
333813d8aaa1SSean Wilcox 		cip->gid = 0;
333913d8aaa1SSean Wilcox 		cip->euid = (uid_t)-1;
334013d8aaa1SSean Wilcox 		cip->egid = (gid_t)-1;
334113d8aaa1SSean Wilcox 	}
334213d8aaa1SSean Wilcox 
33437c478bd9Sstevel@tonic-gate 	*mcpp = cip;
33447c478bd9Sstevel@tonic-gate 
33457c478bd9Sstevel@tonic-gate out:
33467c478bd9Sstevel@tonic-gate 	(void) scf_value_destroy(val);
33477c478bd9Sstevel@tonic-gate 	scf_property_destroy(prop);
33487c478bd9Sstevel@tonic-gate 	scf_pg_destroy(instpg);
33497c478bd9Sstevel@tonic-gate 	scf_pg_destroy(methpg);
33507c478bd9Sstevel@tonic-gate 
33517c478bd9Sstevel@tonic-gate 	if (cip->pwbuf != NULL)
33527c478bd9Sstevel@tonic-gate 		free(cip->pwbuf);
33537c478bd9Sstevel@tonic-gate 	free(cip->vbuf);
33547c478bd9Sstevel@tonic-gate 
3355870ad75aSSean Wilcox 	if (err->type != 0) {
33567c478bd9Sstevel@tonic-gate 		restarter_free_method_context(cip);
3357870ad75aSSean Wilcox 	} else {
3358870ad75aSSean Wilcox 		restarter_mc_error_destroy(err);
3359870ad75aSSean Wilcox 		err = NULL;
3360870ad75aSSean Wilcox 	}
33617c478bd9Sstevel@tonic-gate 
3362870ad75aSSean Wilcox 	return (err);
33637c478bd9Sstevel@tonic-gate }
33647c478bd9Sstevel@tonic-gate 
33657c478bd9Sstevel@tonic-gate /*
33667c478bd9Sstevel@tonic-gate  * Modify the current process per the given method_context.  On success, returns
33677c478bd9Sstevel@tonic-gate  * 0.  Note that the environment is not modified by this function to include the
33687c478bd9Sstevel@tonic-gate  * environment variables in cip->env.
33697c478bd9Sstevel@tonic-gate  *
33707c478bd9Sstevel@tonic-gate  * On failure, sets *fp to NULL or the name of the function which failed,
33717c478bd9Sstevel@tonic-gate  * and returns one of the following error codes.  The words in parentheses are
33727c478bd9Sstevel@tonic-gate  * the values to which *fp may be set for the error case.
33737c478bd9Sstevel@tonic-gate  *   ENOMEM - malloc() failed
33747c478bd9Sstevel@tonic-gate  *   EIO - an I/O error occurred (getpwuid_r, chdir)
33757c478bd9Sstevel@tonic-gate  *   EMFILE - process is out of file descriptors (getpwuid_r)
33767c478bd9Sstevel@tonic-gate  *   ENFILE - system is out of file handles (getpwuid_r)
33777c478bd9Sstevel@tonic-gate  *   EINVAL - gid or egid is out of range (setregid)
33787c478bd9Sstevel@tonic-gate  *	      ngroups is too big (setgroups)
33797c478bd9Sstevel@tonic-gate  *	      project's project id is bad (setproject)
33807c478bd9Sstevel@tonic-gate  *	      uid or euid is out of range (setreuid)
33813ad28c1eSrm88369  *	      poolname is invalid (pool_set_binding)
33827c478bd9Sstevel@tonic-gate  *   EPERM - insufficient privilege (setregid, initgroups, setgroups, setppriv,
33837c478bd9Sstevel@tonic-gate  *	         setproject, setreuid, settaskid)
33847c478bd9Sstevel@tonic-gate  *   ENOENT - uid has a passwd entry but no shadow entry
33857c478bd9Sstevel@tonic-gate  *	      working_dir does not exist (chdir)
33867c478bd9Sstevel@tonic-gate  *	      uid has no passwd entry
33877c478bd9Sstevel@tonic-gate  *	      the pool could not be found (pool_set_binding)
33887c478bd9Sstevel@tonic-gate  *   EFAULT - lpriv_set or priv_set has a bad address (setppriv)
33897c478bd9Sstevel@tonic-gate  *	      working_dir has a bad address (chdir)
33907c478bd9Sstevel@tonic-gate  *   EACCES - could not access working_dir (chdir)
33917c478bd9Sstevel@tonic-gate  *	      in a TASK_FINAL task (setproject, settaskid)
33927c478bd9Sstevel@tonic-gate  *	      no resource pool accepting default binding exists (setproject)
33937c478bd9Sstevel@tonic-gate  *   ELOOP - too many symbolic links in working_dir (chdir)
33947c478bd9Sstevel@tonic-gate  *   ENAMETOOLONG - working_dir is too long (chdir)
33957c478bd9Sstevel@tonic-gate  *   ENOLINK - working_dir is on an inaccessible remote machine (chdir)
33967c478bd9Sstevel@tonic-gate  *   ENOTDIR - working_dir is not a directory (chdir)
33977c478bd9Sstevel@tonic-gate  *   ESRCH - uid is not a user of project (setproject)
33987c478bd9Sstevel@tonic-gate  *	     project is invalid (setproject)
33997c478bd9Sstevel@tonic-gate  *	     the resource pool specified for project is unknown (setproject)
34007c478bd9Sstevel@tonic-gate  *   EBADF - the configuration for the pool is invalid (pool_set_binding)
34017c478bd9Sstevel@tonic-gate  *   -1 - core_set_process_path() failed (core_set_process_path)
34027c478bd9Sstevel@tonic-gate  *	  a resource control assignment failed (setproject)
34037c478bd9Sstevel@tonic-gate  *	  a system error occurred during pool_set_binding (pool_set_binding)
34047c478bd9Sstevel@tonic-gate  */
34057c478bd9Sstevel@tonic-gate int
34067c478bd9Sstevel@tonic-gate restarter_set_method_context(struct method_context *cip, const char **fp)
34077c478bd9Sstevel@tonic-gate {
34087c478bd9Sstevel@tonic-gate 	pid_t mypid = -1;
34097c478bd9Sstevel@tonic-gate 	int r, ret;
34107c478bd9Sstevel@tonic-gate 
34117c478bd9Sstevel@tonic-gate 	cip->pwbuf = NULL;
34127c478bd9Sstevel@tonic-gate 	*fp = NULL;
34137c478bd9Sstevel@tonic-gate 
3414f48205beScasper 	if (cip->gid != (gid_t)-1) {
34157c478bd9Sstevel@tonic-gate 		if (setregid(cip->gid,
3416f48205beScasper 		    cip->egid != (gid_t)-1 ? cip->egid : cip->gid) != 0) {
34177c478bd9Sstevel@tonic-gate 			*fp = "setregid";
34187c478bd9Sstevel@tonic-gate 
34197c478bd9Sstevel@tonic-gate 			ret = errno;
34207c478bd9Sstevel@tonic-gate 			assert(ret == EINVAL || ret == EPERM);
34217c478bd9Sstevel@tonic-gate 			goto out;
34227c478bd9Sstevel@tonic-gate 		}
34237c478bd9Sstevel@tonic-gate 	} else {
34247c478bd9Sstevel@tonic-gate 		if (cip->pwbuf == NULL) {
34257c478bd9Sstevel@tonic-gate 			switch (ret = lookup_pwd(cip)) {
34267c478bd9Sstevel@tonic-gate 			case 0:
34277c478bd9Sstevel@tonic-gate 				break;
34287c478bd9Sstevel@tonic-gate 
34297c478bd9Sstevel@tonic-gate 			case ENOMEM:
34307c478bd9Sstevel@tonic-gate 			case ENOENT:
34317c478bd9Sstevel@tonic-gate 				*fp = NULL;
34327c478bd9Sstevel@tonic-gate 				goto out;
34337c478bd9Sstevel@tonic-gate 
34347c478bd9Sstevel@tonic-gate 			case EIO:
34357c478bd9Sstevel@tonic-gate 			case EMFILE:
34367c478bd9Sstevel@tonic-gate 			case ENFILE:
34377c478bd9Sstevel@tonic-gate 				*fp = "getpwuid_r";
34387c478bd9Sstevel@tonic-gate 				goto out;
34397c478bd9Sstevel@tonic-gate 
34407c478bd9Sstevel@tonic-gate 			default:
34417c478bd9Sstevel@tonic-gate 				bad_fail("lookup_pwd", ret);
34427c478bd9Sstevel@tonic-gate 			}
34437c478bd9Sstevel@tonic-gate 		}
34447c478bd9Sstevel@tonic-gate 
34457c478bd9Sstevel@tonic-gate 		if (setregid(cip->pwd.pw_gid,
3446f48205beScasper 		    cip->egid != (gid_t)-1 ?
3447f48205beScasper 		    cip->egid : cip->pwd.pw_gid) != 0) {
34487c478bd9Sstevel@tonic-gate 			*fp = "setregid";
34497c478bd9Sstevel@tonic-gate 
34507c478bd9Sstevel@tonic-gate 			ret = errno;
34517c478bd9Sstevel@tonic-gate 			assert(ret == EINVAL || ret == EPERM);
34527c478bd9Sstevel@tonic-gate 			goto out;
34537c478bd9Sstevel@tonic-gate 		}
34547c478bd9Sstevel@tonic-gate 	}
34557c478bd9Sstevel@tonic-gate 
34567c478bd9Sstevel@tonic-gate 	if (cip->ngroups == -1) {
34577c478bd9Sstevel@tonic-gate 		if (cip->pwbuf == NULL) {
34587c478bd9Sstevel@tonic-gate 			switch (ret = lookup_pwd(cip)) {
34597c478bd9Sstevel@tonic-gate 			case 0:
34607c478bd9Sstevel@tonic-gate 				break;
34617c478bd9Sstevel@tonic-gate 
34627c478bd9Sstevel@tonic-gate 			case ENOMEM:
34637c478bd9Sstevel@tonic-gate 			case ENOENT:
34647c478bd9Sstevel@tonic-gate 				*fp = NULL;
34657c478bd9Sstevel@tonic-gate 				goto out;
34667c478bd9Sstevel@tonic-gate 
34677c478bd9Sstevel@tonic-gate 			case EIO:
34687c478bd9Sstevel@tonic-gate 			case EMFILE:
34697c478bd9Sstevel@tonic-gate 			case ENFILE:
34707c478bd9Sstevel@tonic-gate 				*fp = "getpwuid_r";
34717c478bd9Sstevel@tonic-gate 				goto out;
34727c478bd9Sstevel@tonic-gate 
34737c478bd9Sstevel@tonic-gate 			default:
34747c478bd9Sstevel@tonic-gate 				bad_fail("lookup_pwd", ret);
34757c478bd9Sstevel@tonic-gate 			}
34767c478bd9Sstevel@tonic-gate 		}
34777c478bd9Sstevel@tonic-gate 
34787c478bd9Sstevel@tonic-gate 		/* Ok if cip->gid == -1 */
34797c478bd9Sstevel@tonic-gate 		if (initgroups(cip->pwd.pw_name, cip->gid) != 0) {
34807c478bd9Sstevel@tonic-gate 			*fp = "initgroups";
34817c478bd9Sstevel@tonic-gate 			ret = errno;
34827c478bd9Sstevel@tonic-gate 			assert(ret == EPERM);
34837c478bd9Sstevel@tonic-gate 			goto out;
34847c478bd9Sstevel@tonic-gate 		}
34857c478bd9Sstevel@tonic-gate 	} else if (cip->ngroups > 0 &&
34867c478bd9Sstevel@tonic-gate 	    setgroups(cip->ngroups, cip->groups) != 0) {
34877c478bd9Sstevel@tonic-gate 		*fp = "setgroups";
34887c478bd9Sstevel@tonic-gate 
34897c478bd9Sstevel@tonic-gate 		ret = errno;
34907c478bd9Sstevel@tonic-gate 		assert(ret == EINVAL || ret == EPERM);
34917c478bd9Sstevel@tonic-gate 		goto out;
34927c478bd9Sstevel@tonic-gate 	}
34937c478bd9Sstevel@tonic-gate 
34947c478bd9Sstevel@tonic-gate 	if (cip->corefile_pattern != NULL) {
34957c478bd9Sstevel@tonic-gate 		mypid = getpid();
34967c478bd9Sstevel@tonic-gate 
34977c478bd9Sstevel@tonic-gate 		if (core_set_process_path(cip->corefile_pattern,
34987c478bd9Sstevel@tonic-gate 		    strlen(cip->corefile_pattern) + 1, mypid) != 0) {
34997c478bd9Sstevel@tonic-gate 			*fp = "core_set_process_path";
35007c478bd9Sstevel@tonic-gate 			ret = -1;
35017c478bd9Sstevel@tonic-gate 			goto out;
35027c478bd9Sstevel@tonic-gate 		}
35037c478bd9Sstevel@tonic-gate 	}
35047c478bd9Sstevel@tonic-gate 
35057c478bd9Sstevel@tonic-gate 	if (restarter_rm_libs_loadable()) {
35067c478bd9Sstevel@tonic-gate 		if (cip->project == NULL) {
35077c478bd9Sstevel@tonic-gate 			if (settaskid(getprojid(), TASK_NORMAL) == -1) {
35087c478bd9Sstevel@tonic-gate 				switch (errno) {
35097c478bd9Sstevel@tonic-gate 				case EACCES:
35107c478bd9Sstevel@tonic-gate 				case EPERM:
35117c478bd9Sstevel@tonic-gate 					*fp = "settaskid";
35127c478bd9Sstevel@tonic-gate 					ret = errno;
35137c478bd9Sstevel@tonic-gate 					goto out;
35147c478bd9Sstevel@tonic-gate 
35157c478bd9Sstevel@tonic-gate 				case EINVAL:
35167c478bd9Sstevel@tonic-gate 				default:
35177c478bd9Sstevel@tonic-gate 					bad_fail("settaskid", errno);
35187c478bd9Sstevel@tonic-gate 				}
35197c478bd9Sstevel@tonic-gate 			}
35207c478bd9Sstevel@tonic-gate 		} else {
35217c478bd9Sstevel@tonic-gate 			switch (ret = lookup_pwd(cip)) {
35227c478bd9Sstevel@tonic-gate 			case 0:
35237c478bd9Sstevel@tonic-gate 				break;
35247c478bd9Sstevel@tonic-gate 
35257c478bd9Sstevel@tonic-gate 			case ENOMEM:
35267c478bd9Sstevel@tonic-gate 			case ENOENT:
35277c478bd9Sstevel@tonic-gate 				*fp = NULL;
35287c478bd9Sstevel@tonic-gate 				goto out;
35297c478bd9Sstevel@tonic-gate 
35307c478bd9Sstevel@tonic-gate 			case EIO:
35317c478bd9Sstevel@tonic-gate 			case EMFILE:
35327c478bd9Sstevel@tonic-gate 			case ENFILE:
35337c478bd9Sstevel@tonic-gate 				*fp = "getpwuid_r";
35347c478bd9Sstevel@tonic-gate 				goto out;
35357c478bd9Sstevel@tonic-gate 
35367c478bd9Sstevel@tonic-gate 			default:
35377c478bd9Sstevel@tonic-gate 				bad_fail("lookup_pwd", ret);
35387c478bd9Sstevel@tonic-gate 			}
35397c478bd9Sstevel@tonic-gate 
35407c478bd9Sstevel@tonic-gate 			*fp = "setproject";
35417c478bd9Sstevel@tonic-gate 
35427c478bd9Sstevel@tonic-gate 			switch (setproject(cip->project, cip->pwd.pw_name,
35437c478bd9Sstevel@tonic-gate 			    TASK_NORMAL)) {
35447c478bd9Sstevel@tonic-gate 			case 0:
35457c478bd9Sstevel@tonic-gate 				break;
35467c478bd9Sstevel@tonic-gate 
35477c478bd9Sstevel@tonic-gate 			case SETPROJ_ERR_TASK:
35487c478bd9Sstevel@tonic-gate 			case SETPROJ_ERR_POOL:
35497c478bd9Sstevel@tonic-gate 				ret = errno;
35507c478bd9Sstevel@tonic-gate 				goto out;
35517c478bd9Sstevel@tonic-gate 
35527c478bd9Sstevel@tonic-gate 			default:
35537c478bd9Sstevel@tonic-gate 				ret = -1;
35547c478bd9Sstevel@tonic-gate 				goto out;
35557c478bd9Sstevel@tonic-gate 			}
35567c478bd9Sstevel@tonic-gate 		}
35577c478bd9Sstevel@tonic-gate 
35587c478bd9Sstevel@tonic-gate 		if (cip->resource_pool != NULL) {
35597c478bd9Sstevel@tonic-gate 			if (mypid == -1)
35607c478bd9Sstevel@tonic-gate 				mypid = getpid();
35617c478bd9Sstevel@tonic-gate 
35627c478bd9Sstevel@tonic-gate 			*fp = "pool_set_binding";
35637c478bd9Sstevel@tonic-gate 
35647c478bd9Sstevel@tonic-gate 			if (pool_set_binding(cip->resource_pool, P_PID,
35657c478bd9Sstevel@tonic-gate 			    mypid) != PO_SUCCESS) {
35667c478bd9Sstevel@tonic-gate 				switch (pool_error()) {
35673ad28c1eSrm88369 				case POE_INVALID_SEARCH:
35687c478bd9Sstevel@tonic-gate 					ret = ENOENT;
35697c478bd9Sstevel@tonic-gate 					break;
35707c478bd9Sstevel@tonic-gate 
35713ad28c1eSrm88369 				case POE_BADPARAM:
35723ad28c1eSrm88369 					ret = EINVAL;
35733ad28c1eSrm88369 					break;
35743ad28c1eSrm88369 
35757c478bd9Sstevel@tonic-gate 				case POE_INVALID_CONF:
35767c478bd9Sstevel@tonic-gate 					ret = EBADF;
35777c478bd9Sstevel@tonic-gate 					break;
35787c478bd9Sstevel@tonic-gate 
35797c478bd9Sstevel@tonic-gate 				case POE_SYSTEM:
35807c478bd9Sstevel@tonic-gate 					ret = -1;
35817c478bd9Sstevel@tonic-gate 					break;
35827c478bd9Sstevel@tonic-gate 
35837c478bd9Sstevel@tonic-gate 				default:
35847c478bd9Sstevel@tonic-gate 					bad_fail("pool_set_binding",
35857c478bd9Sstevel@tonic-gate 					    pool_error());
35867c478bd9Sstevel@tonic-gate 				}
35877c478bd9Sstevel@tonic-gate 
35887c478bd9Sstevel@tonic-gate 				goto out;
35897c478bd9Sstevel@tonic-gate 			}
35907c478bd9Sstevel@tonic-gate 		}
35917c478bd9Sstevel@tonic-gate 	}
35927c478bd9Sstevel@tonic-gate 
35937c478bd9Sstevel@tonic-gate 	/*
35942a3221a4Svp157776 	 * Now, we have to assume our ID. If the UID is 0, we want it to be
35952a3221a4Svp157776 	 * privilege-aware, otherwise the limit set gets used instead of E/P.
35967c478bd9Sstevel@tonic-gate 	 * We can do this by setting P as well, which keeps
35977c478bd9Sstevel@tonic-gate 	 * PA status (see priv_can_clear_PA()).
35987c478bd9Sstevel@tonic-gate 	 */
35997c478bd9Sstevel@tonic-gate 
360013d8aaa1SSean Wilcox 	*fp = "setppriv";
360113d8aaa1SSean Wilcox 
360213d8aaa1SSean Wilcox 	if (cip->lpriv_set != NULL) {
360313d8aaa1SSean Wilcox 		if (setppriv(PRIV_SET, PRIV_LIMIT, cip->lpriv_set) != 0) {
360413d8aaa1SSean Wilcox 			ret = errno;
360513d8aaa1SSean Wilcox 			assert(ret == EFAULT || ret == EPERM);
360613d8aaa1SSean Wilcox 			goto out;
360713d8aaa1SSean Wilcox 		}
360813d8aaa1SSean Wilcox 	}
360913d8aaa1SSean Wilcox 	if (cip->priv_set != NULL) {
361013d8aaa1SSean Wilcox 		if (setppriv(PRIV_SET, PRIV_INHERITABLE, cip->priv_set) != 0) {
361113d8aaa1SSean Wilcox 			ret = errno;
361213d8aaa1SSean Wilcox 			assert(ret == EFAULT || ret == EPERM);
361313d8aaa1SSean Wilcox 			goto out;
361413d8aaa1SSean Wilcox 		}
361513d8aaa1SSean Wilcox 	}
361613d8aaa1SSean Wilcox 
361713d8aaa1SSean Wilcox 	/*
361813d8aaa1SSean Wilcox 	 * If the limit privset is already set, then must be privilege
361913d8aaa1SSean Wilcox 	 * aware.  Otherwise, don't assume anything, and force privilege
362013d8aaa1SSean Wilcox 	 * aware status.
362113d8aaa1SSean Wilcox 	 */
362213d8aaa1SSean Wilcox 
362313d8aaa1SSean Wilcox 	if (cip->lpriv_set == NULL && cip->priv_set != NULL) {
362413d8aaa1SSean Wilcox 		ret = setpflags(PRIV_AWARE, 1);
362513d8aaa1SSean Wilcox 		assert(ret == 0);
362613d8aaa1SSean Wilcox 	}
362713d8aaa1SSean Wilcox 
36287c478bd9Sstevel@tonic-gate 	*fp = "setreuid";
3629f48205beScasper 	if (setreuid(cip->uid,
3630f48205beScasper 	    cip->euid != (uid_t)-1 ? cip->euid : cip->uid) != 0) {
36317c478bd9Sstevel@tonic-gate 		ret = errno;
36327c478bd9Sstevel@tonic-gate 		assert(ret == EINVAL || ret == EPERM);
36337c478bd9Sstevel@tonic-gate 		goto out;
36347c478bd9Sstevel@tonic-gate 	}
36357c478bd9Sstevel@tonic-gate 
36367c478bd9Sstevel@tonic-gate 	*fp = "setppriv";
36377c478bd9Sstevel@tonic-gate 	if (cip->priv_set != NULL) {
36387c478bd9Sstevel@tonic-gate 		if (setppriv(PRIV_SET, PRIV_PERMITTED, cip->priv_set) != 0) {
36397c478bd9Sstevel@tonic-gate 			ret = errno;
36407c478bd9Sstevel@tonic-gate 			assert(ret == EFAULT || ret == EPERM);
36417c478bd9Sstevel@tonic-gate 			goto out;
36427c478bd9Sstevel@tonic-gate 		}
36437c478bd9Sstevel@tonic-gate 	}
36447c478bd9Sstevel@tonic-gate 
36452a3221a4Svp157776 	/*
36462a3221a4Svp157776 	 * The last thing to do is chdir to the specified working directory.
36472a3221a4Svp157776 	 * This should come after the uid switching as only the user might
36482a3221a4Svp157776 	 * have access to the specified directory.
36492a3221a4Svp157776 	 */
36502a3221a4Svp157776 	if (cip->working_dir != NULL) {
36513eae19d9Swesolows 		do {
36522a3221a4Svp157776 			r = chdir(cip->working_dir);
36533eae19d9Swesolows 		} while (r != 0 && errno == EINTR);
36542a3221a4Svp157776 		if (r != 0) {
36552a3221a4Svp157776 			*fp = "chdir";
36562a3221a4Svp157776 			ret = errno;
36572a3221a4Svp157776 			goto out;
36582a3221a4Svp157776 		}
36592a3221a4Svp157776 	}
36602a3221a4Svp157776 
36617c478bd9Sstevel@tonic-gate 	ret = 0;
36627c478bd9Sstevel@tonic-gate out:
36637c478bd9Sstevel@tonic-gate 	free(cip->pwbuf);
36647c478bd9Sstevel@tonic-gate 	cip->pwbuf = NULL;
36657c478bd9Sstevel@tonic-gate 	return (ret);
36667c478bd9Sstevel@tonic-gate }
36677c478bd9Sstevel@tonic-gate 
36687c478bd9Sstevel@tonic-gate void
36697c478bd9Sstevel@tonic-gate restarter_free_method_context(struct method_context *mcp)
36707c478bd9Sstevel@tonic-gate {
36717c478bd9Sstevel@tonic-gate 	size_t i;
36727c478bd9Sstevel@tonic-gate 
36737c478bd9Sstevel@tonic-gate 	if (mcp->lpriv_set != NULL)
36747c478bd9Sstevel@tonic-gate 		priv_freeset(mcp->lpriv_set);
36757c478bd9Sstevel@tonic-gate 	if (mcp->priv_set != NULL)
36767c478bd9Sstevel@tonic-gate 		priv_freeset(mcp->priv_set);
36777c478bd9Sstevel@tonic-gate 
36787c478bd9Sstevel@tonic-gate 	if (mcp->env != NULL) {
36797c478bd9Sstevel@tonic-gate 		for (i = 0; i < mcp->env_sz; i++)
36807c478bd9Sstevel@tonic-gate 			free(mcp->env[i]);
36817c478bd9Sstevel@tonic-gate 		free(mcp->env);
36827c478bd9Sstevel@tonic-gate 	}
36837c478bd9Sstevel@tonic-gate 
36847c478bd9Sstevel@tonic-gate 	free(mcp->working_dir);
36857c478bd9Sstevel@tonic-gate 	free(mcp->corefile_pattern);
36867c478bd9Sstevel@tonic-gate 	free(mcp->project);
36877c478bd9Sstevel@tonic-gate 	free(mcp->resource_pool);
36887c478bd9Sstevel@tonic-gate 	free(mcp);
36897c478bd9Sstevel@tonic-gate }
36907c478bd9Sstevel@tonic-gate 
36917c478bd9Sstevel@tonic-gate /*
36927c478bd9Sstevel@tonic-gate  * Method keyword functions
36937c478bd9Sstevel@tonic-gate  */
36947c478bd9Sstevel@tonic-gate 
36957c478bd9Sstevel@tonic-gate int
36967c478bd9Sstevel@tonic-gate restarter_is_null_method(const char *meth)
36977c478bd9Sstevel@tonic-gate {
36987c478bd9Sstevel@tonic-gate 	return (strcmp(meth, MKW_TRUE) == 0);
36997c478bd9Sstevel@tonic-gate }
37007c478bd9Sstevel@tonic-gate 
37017c478bd9Sstevel@tonic-gate static int
37027c478bd9Sstevel@tonic-gate is_kill_method(const char *method, const char *kill_str,
37037c478bd9Sstevel@tonic-gate     size_t kill_str_len)
37047c478bd9Sstevel@tonic-gate {
37057c478bd9Sstevel@tonic-gate 	const char *cp;
37067c478bd9Sstevel@tonic-gate 	int sig;
37077c478bd9Sstevel@tonic-gate 
37087c478bd9Sstevel@tonic-gate 	if (strncmp(method, kill_str, kill_str_len) != 0 ||
37097c478bd9Sstevel@tonic-gate 	    (method[kill_str_len] != '\0' &&
37107c478bd9Sstevel@tonic-gate 	    !isspace(method[kill_str_len])))
37117c478bd9Sstevel@tonic-gate 		return (-1);
37127c478bd9Sstevel@tonic-gate 
37137c478bd9Sstevel@tonic-gate 	cp = method + kill_str_len;
37147c478bd9Sstevel@tonic-gate 	while (*cp != '\0' && isspace(*cp))
37157c478bd9Sstevel@tonic-gate 		++cp;
37167c478bd9Sstevel@tonic-gate 
37177c478bd9Sstevel@tonic-gate 	if (*cp == '\0')
37187c478bd9Sstevel@tonic-gate 		return (SIGTERM);
37197c478bd9Sstevel@tonic-gate 
37207c478bd9Sstevel@tonic-gate 	if (*cp != '-')
37217c478bd9Sstevel@tonic-gate 		return (-1);
37227c478bd9Sstevel@tonic-gate 
37237c478bd9Sstevel@tonic-gate 	return (str2sig(cp + 1, &sig) == 0 ? sig : -1);
37247c478bd9Sstevel@tonic-gate }
37257c478bd9Sstevel@tonic-gate 
37267c478bd9Sstevel@tonic-gate int
37277c478bd9Sstevel@tonic-gate restarter_is_kill_proc_method(const char *method)
37287c478bd9Sstevel@tonic-gate {
37297c478bd9Sstevel@tonic-gate 	return (is_kill_method(method, MKW_KILL_PROC,
37307c478bd9Sstevel@tonic-gate 	    sizeof (MKW_KILL_PROC) - 1));
37317c478bd9Sstevel@tonic-gate }
37327c478bd9Sstevel@tonic-gate 
37337c478bd9Sstevel@tonic-gate int
37347c478bd9Sstevel@tonic-gate restarter_is_kill_method(const char *method)
37357c478bd9Sstevel@tonic-gate {
37367c478bd9Sstevel@tonic-gate 	return (is_kill_method(method, MKW_KILL, sizeof (MKW_KILL) - 1));
37377c478bd9Sstevel@tonic-gate }
37387c478bd9Sstevel@tonic-gate 
37397c478bd9Sstevel@tonic-gate /*
37407c478bd9Sstevel@tonic-gate  * Stubs for now.
37417c478bd9Sstevel@tonic-gate  */
37427c478bd9Sstevel@tonic-gate 
37437c478bd9Sstevel@tonic-gate /* ARGSUSED */
37447c478bd9Sstevel@tonic-gate int
37457c478bd9Sstevel@tonic-gate restarter_event_get_enabled(restarter_event_t *e)
37467c478bd9Sstevel@tonic-gate {
37477c478bd9Sstevel@tonic-gate 	return (-1);
37487c478bd9Sstevel@tonic-gate }
37497c478bd9Sstevel@tonic-gate 
37507c478bd9Sstevel@tonic-gate /* ARGSUSED */
37517c478bd9Sstevel@tonic-gate uint64_t
37527c478bd9Sstevel@tonic-gate restarter_event_get_seq(restarter_event_t *e)
37537c478bd9Sstevel@tonic-gate {
37547c478bd9Sstevel@tonic-gate 	return (-1);
37557c478bd9Sstevel@tonic-gate }
37567c478bd9Sstevel@tonic-gate 
37577c478bd9Sstevel@tonic-gate /* ARGSUSED */
37587c478bd9Sstevel@tonic-gate void
37597c478bd9Sstevel@tonic-gate restarter_event_get_time(restarter_event_t *e, hrtime_t *time)
37607c478bd9Sstevel@tonic-gate {
37617c478bd9Sstevel@tonic-gate }
3762eb1a3463STruong Nguyen 
3763eb1a3463STruong Nguyen /*
3764eb1a3463STruong Nguyen  * Check for and validate fmri specified in restarter_actions/auxiliary_fmri
3765eb1a3463STruong Nguyen  * 0 - Success
3766eb1a3463STruong Nguyen  * 1 - Failure
3767eb1a3463STruong Nguyen  */
3768eb1a3463STruong Nguyen int
3769eb1a3463STruong Nguyen restarter_inst_validate_ractions_aux_fmri(scf_instance_t *inst)
3770eb1a3463STruong Nguyen {
3771eb1a3463STruong Nguyen 	scf_handle_t *h;
3772eb1a3463STruong Nguyen 	scf_propertygroup_t *pg;
3773eb1a3463STruong Nguyen 	scf_property_t *prop;
3774eb1a3463STruong Nguyen 	scf_value_t *val;
3775eb1a3463STruong Nguyen 	char *aux_fmri;
3776eb1a3463STruong Nguyen 	size_t size = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
3777eb1a3463STruong Nguyen 	int ret = 1;
3778eb1a3463STruong Nguyen 
3779eb1a3463STruong Nguyen 	if ((aux_fmri = malloc(size)) == NULL)
3780eb1a3463STruong Nguyen 		return (1);
3781eb1a3463STruong Nguyen 
3782eb1a3463STruong Nguyen 	h = scf_instance_handle(inst);
3783eb1a3463STruong Nguyen 
3784eb1a3463STruong Nguyen 	pg = scf_pg_create(h);
3785eb1a3463STruong Nguyen 	prop = scf_property_create(h);
3786eb1a3463STruong Nguyen 	val = scf_value_create(h);
3787eb1a3463STruong Nguyen 	if (pg == NULL || prop == NULL || val == NULL)
3788eb1a3463STruong Nguyen 		goto out;
3789eb1a3463STruong Nguyen 
3790eb1a3463STruong Nguyen 	if (instance_get_or_add_pg(inst, SCF_PG_RESTARTER_ACTIONS,
3791eb1a3463STruong Nguyen 	    SCF_PG_RESTARTER_ACTIONS_TYPE, SCF_PG_RESTARTER_ACTIONS_FLAGS,
3792eb1a3463STruong Nguyen 	    pg) != SCF_SUCCESS)
3793eb1a3463STruong Nguyen 		goto out;
3794eb1a3463STruong Nguyen 
3795eb1a3463STruong Nguyen 	if (get_astring_val(pg, SCF_PROPERTY_AUX_FMRI, aux_fmri, size,
3796eb1a3463STruong Nguyen 	    prop, val) != SCF_SUCCESS)
3797eb1a3463STruong Nguyen 		goto out;
3798eb1a3463STruong Nguyen 
3799eb1a3463STruong Nguyen 	if (scf_parse_fmri(aux_fmri, NULL, NULL, NULL, NULL, NULL,
3800eb1a3463STruong Nguyen 	    NULL) != SCF_SUCCESS)
3801eb1a3463STruong Nguyen 		goto out;
3802eb1a3463STruong Nguyen 
3803eb1a3463STruong Nguyen 	ret = 0;
3804eb1a3463STruong Nguyen 
3805eb1a3463STruong Nguyen out:
3806eb1a3463STruong Nguyen 	free(aux_fmri);
3807eb1a3463STruong Nguyen 	scf_value_destroy(val);
3808eb1a3463STruong Nguyen 	scf_property_destroy(prop);
3809eb1a3463STruong Nguyen 	scf_pg_destroy(pg);
3810eb1a3463STruong Nguyen 	return (ret);
3811eb1a3463STruong Nguyen }
3812eb1a3463STruong Nguyen 
3813eb1a3463STruong Nguyen /*
3814eb1a3463STruong Nguyen  * Get instance's boolean value in restarter_actions/auxiliary_tty
3815eb1a3463STruong Nguyen  * Return -1 on failure
3816eb1a3463STruong Nguyen  */
3817eb1a3463STruong Nguyen int
3818eb1a3463STruong Nguyen restarter_inst_ractions_from_tty(scf_instance_t *inst)
3819eb1a3463STruong Nguyen {
3820eb1a3463STruong Nguyen 	scf_handle_t *h;
3821eb1a3463STruong Nguyen 	scf_propertygroup_t *pg;
3822eb1a3463STruong Nguyen 	scf_property_t *prop;
3823eb1a3463STruong Nguyen 	scf_value_t *val;
3824eb1a3463STruong Nguyen 	uint8_t	has_tty;
3825eb1a3463STruong Nguyen 	int ret = -1;
3826eb1a3463STruong Nguyen 
3827eb1a3463STruong Nguyen 	h = scf_instance_handle(inst);
3828eb1a3463STruong Nguyen 	pg = scf_pg_create(h);
3829eb1a3463STruong Nguyen 	prop = scf_property_create(h);
3830eb1a3463STruong Nguyen 	val = scf_value_create(h);
3831eb1a3463STruong Nguyen 	if (pg == NULL || prop == NULL || val == NULL)
3832eb1a3463STruong Nguyen 		goto out;
3833eb1a3463STruong Nguyen 
3834eb1a3463STruong Nguyen 	if (instance_get_or_add_pg(inst, SCF_PG_RESTARTER_ACTIONS,
3835eb1a3463STruong Nguyen 	    SCF_PG_RESTARTER_ACTIONS_TYPE, SCF_PG_RESTARTER_ACTIONS_FLAGS,
3836eb1a3463STruong Nguyen 	    pg) != SCF_SUCCESS)
3837eb1a3463STruong Nguyen 		goto out;
3838eb1a3463STruong Nguyen 
3839eb1a3463STruong Nguyen 	if (get_boolean_val(pg, SCF_PROPERTY_AUX_TTY, &has_tty, prop,
3840eb1a3463STruong Nguyen 	    val) != SCF_SUCCESS)
3841eb1a3463STruong Nguyen 		goto out;
3842eb1a3463STruong Nguyen 
3843eb1a3463STruong Nguyen 	ret = has_tty;
3844eb1a3463STruong Nguyen 
3845eb1a3463STruong Nguyen out:
3846eb1a3463STruong Nguyen 	scf_value_destroy(val);
3847eb1a3463STruong Nguyen 	scf_property_destroy(prop);
3848eb1a3463STruong Nguyen 	scf_pg_destroy(pg);
3849eb1a3463STruong Nguyen 	return (ret);
3850eb1a3463STruong Nguyen }
3851eb1a3463STruong Nguyen 
3852eb1a3463STruong Nguyen static int
3853eb1a3463STruong Nguyen restarter_inst_set_astring_prop(scf_instance_t *inst, const char *pgname,
3854eb1a3463STruong Nguyen     const char *pgtype, uint32_t pgflags, const char *pname, const char *str)
3855eb1a3463STruong Nguyen {
3856eb1a3463STruong Nguyen 	scf_handle_t *h;
3857eb1a3463STruong Nguyen 	scf_propertygroup_t *pg;
3858eb1a3463STruong Nguyen 	scf_transaction_t *t;
3859eb1a3463STruong Nguyen 	scf_transaction_entry_t *e;
3860eb1a3463STruong Nguyen 	scf_value_t *v;
3861eb1a3463STruong Nguyen 	int ret = 1, r;
3862eb1a3463STruong Nguyen 
3863eb1a3463STruong Nguyen 	h = scf_instance_handle(inst);
3864eb1a3463STruong Nguyen 
3865eb1a3463STruong Nguyen 	pg = scf_pg_create(h);
3866eb1a3463STruong Nguyen 	t = scf_transaction_create(h);
3867eb1a3463STruong Nguyen 	e = scf_entry_create(h);
3868eb1a3463STruong Nguyen 	v = scf_value_create(h);
3869eb1a3463STruong Nguyen 	if (pg == NULL || t == NULL || e == NULL || v == NULL)
3870eb1a3463STruong Nguyen 		goto out;
3871eb1a3463STruong Nguyen 
3872eb1a3463STruong Nguyen 	if (instance_get_or_add_pg(inst, pgname, pgtype, pgflags, pg))
3873eb1a3463STruong Nguyen 		goto out;
3874eb1a3463STruong Nguyen 
3875eb1a3463STruong Nguyen 	if (scf_value_set_astring(v, str) != SCF_SUCCESS)
3876eb1a3463STruong Nguyen 		goto out;
3877eb1a3463STruong Nguyen 
3878eb1a3463STruong Nguyen 	for (;;) {
3879eb1a3463STruong Nguyen 		if (scf_transaction_start(t, pg) != 0)
3880eb1a3463STruong Nguyen 			goto out;
3881eb1a3463STruong Nguyen 
3882eb1a3463STruong Nguyen 		if (tx_set_value(t, e, pname, SCF_TYPE_ASTRING, v) != 0)
3883eb1a3463STruong Nguyen 			goto out;
3884eb1a3463STruong Nguyen 
3885eb1a3463STruong Nguyen 		if ((r = scf_transaction_commit(t)) == 1)
3886eb1a3463STruong Nguyen 			break;
3887eb1a3463STruong Nguyen 
3888eb1a3463STruong Nguyen 		if (r == -1)
3889eb1a3463STruong Nguyen 			goto out;
3890eb1a3463STruong Nguyen 
3891eb1a3463STruong Nguyen 		scf_transaction_reset(t);
3892eb1a3463STruong Nguyen 		if (scf_pg_update(pg) == -1)
3893eb1a3463STruong Nguyen 			goto out;
3894eb1a3463STruong Nguyen 	}
3895eb1a3463STruong Nguyen 	ret = 0;
3896eb1a3463STruong Nguyen 
3897eb1a3463STruong Nguyen out:
3898eb1a3463STruong Nguyen 	scf_transaction_destroy(t);
3899eb1a3463STruong Nguyen 	scf_entry_destroy(e);
3900eb1a3463STruong Nguyen 	scf_value_destroy(v);
3901eb1a3463STruong Nguyen 	scf_pg_destroy(pg);
3902eb1a3463STruong Nguyen 
3903eb1a3463STruong Nguyen 	return (ret);
3904eb1a3463STruong Nguyen }
3905eb1a3463STruong Nguyen 
3906eb1a3463STruong Nguyen int
3907eb1a3463STruong Nguyen restarter_inst_set_aux_fmri(scf_instance_t *inst)
3908eb1a3463STruong Nguyen {
3909eb1a3463STruong Nguyen 	scf_handle_t *h;
3910eb1a3463STruong Nguyen 	scf_propertygroup_t *pg;
3911eb1a3463STruong Nguyen 	scf_property_t *prop;
3912eb1a3463STruong Nguyen 	scf_value_t *val;
3913eb1a3463STruong Nguyen 	char *aux_fmri;
3914eb1a3463STruong Nguyen 	size_t size = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
3915eb1a3463STruong Nguyen 	int ret = 1;
3916eb1a3463STruong Nguyen 
3917eb1a3463STruong Nguyen 	if ((aux_fmri = malloc(size)) == NULL)
3918eb1a3463STruong Nguyen 		return (1);
3919eb1a3463STruong Nguyen 
3920eb1a3463STruong Nguyen 	h = scf_instance_handle(inst);
3921eb1a3463STruong Nguyen 
3922eb1a3463STruong Nguyen 	pg = scf_pg_create(h);
3923eb1a3463STruong Nguyen 	prop = scf_property_create(h);
3924eb1a3463STruong Nguyen 	val = scf_value_create(h);
3925eb1a3463STruong Nguyen 	if (pg == NULL || prop == NULL || val == NULL)
3926eb1a3463STruong Nguyen 		goto out;
3927eb1a3463STruong Nguyen 
3928eb1a3463STruong Nguyen 	/*
3929eb1a3463STruong Nguyen 	 * Get auxiliary_fmri value from restarter_actions pg
3930eb1a3463STruong Nguyen 	 */
3931eb1a3463STruong Nguyen 	if (instance_get_or_add_pg(inst, SCF_PG_RESTARTER_ACTIONS,
3932eb1a3463STruong Nguyen 	    SCF_PG_RESTARTER_ACTIONS_TYPE, SCF_PG_RESTARTER_ACTIONS_FLAGS,
3933eb1a3463STruong Nguyen 	    pg) != SCF_SUCCESS)
3934eb1a3463STruong Nguyen 		goto out;
3935eb1a3463STruong Nguyen 
3936eb1a3463STruong Nguyen 	if (get_astring_val(pg, SCF_PROPERTY_AUX_FMRI, aux_fmri, size,
3937eb1a3463STruong Nguyen 	    prop, val) != SCF_SUCCESS)
3938eb1a3463STruong Nguyen 		goto out;
3939eb1a3463STruong Nguyen 
3940eb1a3463STruong Nguyen 	/*
3941eb1a3463STruong Nguyen 	 * Populate restarter/auxiliary_fmri with the obtained fmri.
3942eb1a3463STruong Nguyen 	 */
3943eb1a3463STruong Nguyen 	ret = restarter_inst_set_astring_prop(inst, SCF_PG_RESTARTER,
3944eb1a3463STruong Nguyen 	    SCF_PG_RESTARTER_TYPE, SCF_PG_RESTARTER_FLAGS,
3945eb1a3463STruong Nguyen 	    SCF_PROPERTY_AUX_FMRI, aux_fmri);
3946eb1a3463STruong Nguyen 
3947eb1a3463STruong Nguyen out:
3948eb1a3463STruong Nguyen 	free(aux_fmri);
3949eb1a3463STruong Nguyen 	scf_value_destroy(val);
3950eb1a3463STruong Nguyen 	scf_property_destroy(prop);
3951eb1a3463STruong Nguyen 	scf_pg_destroy(pg);
3952eb1a3463STruong Nguyen 	return (ret);
3953eb1a3463STruong Nguyen }
3954eb1a3463STruong Nguyen 
3955eb1a3463STruong Nguyen int
3956eb1a3463STruong Nguyen restarter_inst_reset_aux_fmri(scf_instance_t *inst)
3957eb1a3463STruong Nguyen {
3958eb1a3463STruong Nguyen 	return (scf_instance_delete_prop(inst,
3959eb1a3463STruong Nguyen 	    SCF_PG_RESTARTER, SCF_PROPERTY_AUX_FMRI));
3960eb1a3463STruong Nguyen }
3961eb1a3463STruong Nguyen 
3962eb1a3463STruong Nguyen int
3963eb1a3463STruong Nguyen restarter_inst_reset_ractions_aux_fmri(scf_instance_t *inst)
3964eb1a3463STruong Nguyen {
3965eb1a3463STruong Nguyen 	return (scf_instance_delete_prop(inst,
3966eb1a3463STruong Nguyen 	    SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_AUX_FMRI));
3967eb1a3463STruong Nguyen }
3968