libscf.c revision 7475:9a5f7406e094
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27
28#include <sys/contract/process.h>
29#include <assert.h>
30#include <errno.h>
31#include <libscf.h>
32#include <libscf_priv.h>
33#include <poll.h>
34#include <stdlib.h>
35#include <string.h>
36#include <unistd.h>
37
38#include "startd.h"
39
40#define	SMF_SNAPSHOT_RUNNING	"running"
41
42char *
43inst_fmri_to_svc_fmri(const char *fmri)
44{
45	char *buf, *sfmri;
46	const char *scope, *svc;
47	int r;
48	boolean_t local;
49
50	buf = startd_alloc(max_scf_fmri_size);
51	sfmri = startd_alloc(max_scf_fmri_size);
52
53	(void) strcpy(buf, fmri);
54
55	r = scf_parse_svc_fmri(buf, &scope, &svc, NULL, NULL, NULL);
56	assert(r == 0);
57
58	local = strcmp(scope, SCF_SCOPE_LOCAL) == 0;
59
60	(void) snprintf(sfmri, max_scf_fmri_size, "svc:%s%s/%s",
61	    local ? "" : "//", local ? "" : scope, svc);
62
63	startd_free(buf, max_scf_fmri_size);
64
65	return (sfmri);
66}
67
68/*
69 * Wrapper for the scf_*_create() functions.  On SCF_ERROR_NO_MEMORY and
70 * SCF_ERROR_NO_RESOURCES, retries or dies.  So this can only fail with
71 * SCF_ERROR_INVALID_ARGUMENT, if h is NULL.
72 */
73void *
74libscf_object_create(void *f(scf_handle_t *), scf_handle_t *h)
75{
76	void *o;
77	uint_t try, msecs;
78	scf_error_t err;
79
80	o = f(h);
81	if (o != NULL)
82		return (o);
83	err = scf_error();
84	if (err != SCF_ERROR_NO_MEMORY && err != SCF_ERROR_NO_RESOURCES)
85		return (NULL);
86
87	msecs = ALLOC_DELAY;
88
89	for (try = 0; try < ALLOC_RETRY; ++try) {
90		(void) poll(NULL, 0, msecs);
91		msecs *= ALLOC_DELAY_MULT;
92		o = f(h);
93		if (o != NULL)
94			return (o);
95		err = scf_error();
96		if (err != SCF_ERROR_NO_MEMORY && err != SCF_ERROR_NO_RESOURCES)
97			return (NULL);
98	}
99
100	uu_die("Insufficient memory.\n");
101	/* NOTREACHED */
102}
103
104scf_snapshot_t *
105libscf_get_running_snapshot(scf_instance_t *inst)
106{
107	scf_handle_t *h;
108	scf_snapshot_t *snap;
109
110	h = scf_instance_handle(inst);
111	if (h == NULL)
112		return (NULL);
113
114	snap = scf_snapshot_create(h);
115	if (snap == NULL)
116		return (NULL);
117
118	if (scf_instance_get_snapshot(inst, SMF_SNAPSHOT_RUNNING, snap) == 0)
119		return (snap);
120
121	scf_snapshot_destroy(snap);
122	return (NULL);
123}
124
125/*
126 * Make sure a service has a "running" snapshot.  If it doesn't, make one from
127 * the editing configuration.
128 */
129scf_snapshot_t *
130libscf_get_or_make_running_snapshot(scf_instance_t *inst, const char *fmri,
131    boolean_t retake)
132{
133	scf_handle_t *h;
134	scf_snapshot_t *snap;
135
136	h = scf_instance_handle(inst);
137
138	snap = scf_snapshot_create(h);
139	if (snap == NULL)
140		goto err;
141
142	if (scf_instance_get_snapshot(inst, SMF_SNAPSHOT_RUNNING, snap) == 0)
143		return (snap);
144
145	switch (scf_error()) {
146	case SCF_ERROR_NOT_FOUND:
147		break;
148
149	case SCF_ERROR_DELETED:
150		scf_snapshot_destroy(snap);
151		return (NULL);
152
153	default:
154err:
155		log_error(LOG_NOTICE,
156		    "Could not check for running snapshot of %s (%s).\n", fmri,
157		    scf_strerror(scf_error()));
158		scf_snapshot_destroy(snap);
159		return (NULL);
160	}
161
162	if (_scf_snapshot_take_new(inst, SMF_SNAPSHOT_RUNNING, snap) == 0) {
163		log_framework(LOG_DEBUG, "Took running snapshot for %s.\n",
164		    fmri);
165	} else {
166		if (retake && scf_error() == SCF_ERROR_BACKEND_READONLY)
167			restarter_mark_pending_snapshot(fmri,
168			    RINST_RETAKE_RUNNING);
169		else
170			log_error(LOG_DEBUG,
171			    "Could not create running snapshot for %s "
172			    "(%s).\n", fmri, scf_strerror(scf_error()));
173
174		scf_snapshot_destroy(snap);
175		snap = NULL;
176	}
177
178	return (snap);
179}
180
181/*
182 * When a service comes up, point the "start" snapshot at the "running"
183 * snapshot.  Returns 0 on success, ENOTSUP if fmri designates something other
184 * than an instance, ECONNABORTED, ENOENT if the instance does not exist, or
185 * EACCES.
186 */
187int
188libscf_snapshots_poststart(scf_handle_t *h, const char *fmri, boolean_t retake)
189{
190	scf_instance_t *inst = NULL;
191	scf_snapshot_t *running, *start = NULL;
192	int ret = 0, r;
193
194	r = libscf_fmri_get_instance(h, fmri, &inst);
195	switch (r) {
196	case 0:
197		break;
198
199	case ENOTSUP:
200	case ECONNABORTED:
201	case ENOENT:
202		return (r);
203
204	case EINVAL:
205	default:
206		assert(0);
207		abort();
208	}
209
210	start = safe_scf_snapshot_create(h);
211
212again:
213	running = libscf_get_or_make_running_snapshot(inst, fmri, retake);
214	if (running == NULL) {
215		ret = 0;
216		goto out;
217	}
218
219lookup:
220	if (scf_instance_get_snapshot(inst, "start", start) != 0) {
221		switch (scf_error()) {
222		case SCF_ERROR_CONNECTION_BROKEN:
223		default:
224			ret = ECONNABORTED;
225			goto out;
226
227		case SCF_ERROR_NOT_FOUND:
228			if (_scf_snapshot_take_new(inst, "start", start) != 0) {
229				switch (scf_error()) {
230				case SCF_ERROR_CONNECTION_BROKEN:
231				default:
232					ret = ECONNABORTED;
233					goto out;
234
235				case SCF_ERROR_DELETED:
236					ret = ENOENT;
237					goto out;
238
239				case SCF_ERROR_EXISTS:
240					goto lookup;
241
242				case SCF_ERROR_NO_RESOURCES:
243					uu_die("Repository server out of "
244					    "resources.\n");
245					/* NOTREACHED */
246
247				case SCF_ERROR_BACKEND_READONLY:
248					goto readonly;
249
250				case SCF_ERROR_PERMISSION_DENIED:
251					uu_die("Insufficient privileges.\n");
252					/* NOTREACHED */
253
254				case SCF_ERROR_BACKEND_ACCESS:
255					ret = EACCES;
256					goto out;
257
258				case SCF_ERROR_HANDLE_MISMATCH:
259				case SCF_ERROR_INTERNAL:
260				case SCF_ERROR_INVALID_ARGUMENT:
261				case SCF_ERROR_NOT_SET:
262					bad_error("_scf_snapshot_take_new",
263					    scf_error());
264				}
265			}
266			break;
267
268		case SCF_ERROR_DELETED:
269			ret = ENOENT;
270			goto out;
271
272		case SCF_ERROR_HANDLE_MISMATCH:
273		case SCF_ERROR_NOT_SET:
274		case SCF_ERROR_INVALID_ARGUMENT:
275			bad_error("scf_instance_get_snapshot", scf_error());
276		}
277	}
278
279	if (_scf_snapshot_attach(running, start) == 0) {
280		log_framework(LOG_DEBUG, "Updated \"start\" snapshot for %s.\n",
281		    fmri);
282	} else {
283		switch (scf_error()) {
284		case SCF_ERROR_CONNECTION_BROKEN:
285		default:
286			ret = ECONNABORTED;
287			goto out;
288
289		case SCF_ERROR_DELETED:
290			scf_snapshot_destroy(running);
291			goto again;
292
293		case SCF_ERROR_NO_RESOURCES:
294			uu_die("Repository server out of resources.\n");
295			/* NOTREACHED */
296
297		case SCF_ERROR_PERMISSION_DENIED:
298			uu_die("Insufficient privileges.\n");
299			/* NOTREACHED */
300
301		case SCF_ERROR_BACKEND_ACCESS:
302			ret = EACCES;
303			goto out;
304
305		case SCF_ERROR_BACKEND_READONLY:
306readonly:
307			if (retake)
308				restarter_mark_pending_snapshot(fmri,
309				    RINST_RETAKE_START);
310			break;
311
312		case SCF_ERROR_HANDLE_MISMATCH:
313		case SCF_ERROR_NOT_SET:
314			bad_error("_scf_snapshot_attach", scf_error());
315		}
316	}
317
318out:
319	scf_snapshot_destroy(start);
320	scf_snapshot_destroy(running);
321	scf_instance_destroy(inst);
322
323	return (ret);
324}
325
326/*
327 * Before a refresh, update the "running" snapshot from the editing
328 * configuration.
329 *
330 * Returns 0 on success and -1 on failure.
331 */
332int
333libscf_snapshots_refresh(scf_instance_t *inst, const char *fmri)
334{
335	scf_handle_t *h;
336	scf_snapshot_t *snap;
337	boolean_t err = 1;
338
339	h = scf_instance_handle(inst);
340	if (h == NULL)
341		goto out;
342
343	snap = scf_snapshot_create(h);
344	if (snap == NULL)
345		goto out;
346
347	if (scf_instance_get_snapshot(inst, SMF_SNAPSHOT_RUNNING, snap) == 0) {
348		if (_scf_snapshot_take_attach(inst, snap) == 0)
349			err = 0;
350	} else {
351		switch (scf_error()) {
352		case SCF_ERROR_DELETED:
353			err = 0;
354			goto out;
355
356		case SCF_ERROR_NOT_FOUND:
357			break;
358
359		case SCF_ERROR_NOT_SET:
360			assert(0);
361			abort();
362			/* NOTREACHED */
363
364		default:
365			goto out;
366		}
367
368		log_error(LOG_DEBUG,
369		    "Service %s has no %s snapshot; creating one.\n", fmri,
370		    SMF_SNAPSHOT_RUNNING);
371
372		if (_scf_snapshot_take_new(inst, SMF_SNAPSHOT_RUNNING,
373		    snap) == 0)
374			err = 0;
375	}
376
377out:
378	scf_snapshot_destroy(snap);
379
380	if (!err)
381		return (0);
382
383	log_error(LOG_WARNING,
384	    "Could not update \"running\" snapshot for refresh of %s.\n", fmri);
385	return (-1);
386}
387
388/*
389 * int libscf_read_single_astring()
390 *   Reads a single astring value of the requested property into the
391 *   pre-allocated buffer (conventionally of size max_scf_value_size).
392 *   Multiple values constitute an error.
393 *
394 * Returns 0 on success or LIBSCF_PROPERTY_ABSENT or LIBSCF_PROPERTY_ERROR.
395 */
396static int
397libscf_read_single_astring(scf_handle_t *h, scf_property_t *prop, char **ret)
398{
399	scf_value_t *val = safe_scf_value_create(h);
400	int r = 0;
401
402	if (scf_property_get_value(prop, val) == -1) {
403		if (scf_error() == SCF_ERROR_NOT_FOUND)
404			r = LIBSCF_PROPERTY_ABSENT;
405		else
406			r = LIBSCF_PROPERTY_ERROR;
407		goto read_single_astring_fail;
408	}
409
410	if (scf_value_get_astring(val, *ret, max_scf_value_size) <= 0) {
411		r = LIBSCF_PROPERTY_ERROR;
412		goto read_single_astring_fail;
413	}
414
415read_single_astring_fail:
416	scf_value_destroy(val);
417	return (r);
418}
419
420static int
421libscf_read_state(const scf_propertygroup_t *pg, const char *prop_name,
422    restarter_instance_state_t *state)
423{
424	scf_handle_t *h;
425	scf_property_t *prop;
426	char *char_state = startd_alloc(max_scf_value_size);
427	int ret = 0;
428
429	h = scf_pg_handle(pg);
430	prop = safe_scf_property_create(h);
431
432	if (scf_pg_get_property(pg, prop_name, prop) == -1) {
433		if (scf_error() == SCF_ERROR_NOT_FOUND)
434			ret = LIBSCF_PROPERTY_ABSENT;
435		else
436			ret = LIBSCF_PROPERTY_ERROR;
437	} else {
438		ret = libscf_read_single_astring(h, prop, &char_state);
439		if (ret != 0) {
440			if (ret != LIBSCF_PROPERTY_ABSENT)
441				ret = LIBSCF_PROPERTY_ERROR;
442		} else {
443			*state = restarter_string_to_state(char_state);
444			ret = 0;
445		}
446	}
447
448	startd_free(char_state, max_scf_value_size);
449	scf_property_destroy(prop);
450	return (ret);
451}
452
453/*
454 * int libscf_read_states(const scf_propertygroup_t *,
455 *   restarter_instance_state_t *, restarter_instance_state_t *)
456 *
457 *   Set the current state and next_state values for the given service instance.
458 *   Returns 0 on success, or a libscf error code on failure.
459 */
460int
461libscf_read_states(const scf_propertygroup_t *pg,
462    restarter_instance_state_t *state, restarter_instance_state_t *next_state)
463{
464	int state_ret, next_state_ret, ret;
465
466	state_ret = libscf_read_state(pg, SCF_PROPERTY_STATE, state);
467	next_state_ret = libscf_read_state(pg, SCF_PROPERTY_NEXT_STATE,
468	    next_state);
469
470	if (state_ret == LIBSCF_PROPERTY_ERROR ||
471	    next_state_ret == LIBSCF_PROPERTY_ERROR) {
472		ret = LIBSCF_PROPERTY_ERROR;
473	} else if (state_ret == 0 && next_state_ret == 0) {
474		ret = 0;
475	} else if (state_ret == LIBSCF_PROPERTY_ABSENT &&
476	    next_state_ret == LIBSCF_PROPERTY_ABSENT) {
477		*state = RESTARTER_STATE_UNINIT;
478		*next_state = RESTARTER_STATE_NONE;
479		ret = 0;
480	} else if (state_ret == LIBSCF_PROPERTY_ABSENT ||
481	    next_state_ret == LIBSCF_PROPERTY_ABSENT) {
482		log_framework(LOG_DEBUG,
483		    "Only one repository state exists, setting "
484		    "restarter states to MAINTENANCE and NONE\n");
485		*state = RESTARTER_STATE_MAINT;
486		*next_state = RESTARTER_STATE_NONE;
487		ret = 0;
488	} else {
489		ret = LIBSCF_PROPERTY_ERROR;
490	}
491
492read_states_out:
493	return (ret);
494}
495
496/*
497 * depgroup_empty()
498 *
499 * Returns 0 if not empty.
500 * Returns 1 if empty.
501 * Returns -1 on error (check scf_error()).
502 */
503int
504depgroup_empty(scf_handle_t *h, scf_propertygroup_t *pg)
505{
506	int empty = 1;
507	scf_iter_t *iter;
508	scf_property_t *prop;
509	int ret;
510
511	iter = safe_scf_iter_create(h);
512	prop = safe_scf_property_create(h);
513
514	if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS) {
515		scf_property_destroy(prop);
516		scf_iter_destroy(iter);
517		return (-1);
518	}
519
520	ret = scf_iter_next_property(iter, prop);
521	if (ret < 0) {
522		scf_property_destroy(prop);
523		scf_iter_destroy(iter);
524		return (-1);
525	}
526
527	if (ret == 1)
528		empty = 0;
529
530	scf_property_destroy(prop);
531	scf_iter_destroy(iter);
532
533	return (empty);
534}
535
536gv_type_t
537depgroup_read_scheme(scf_handle_t *h, scf_propertygroup_t *pg)
538{
539	scf_property_t *prop;
540	char *scheme = startd_alloc(max_scf_value_size);
541	gv_type_t ret;
542
543	prop = safe_scf_property_create(h);
544
545	if (scf_pg_get_property(pg, SCF_PROPERTY_TYPE, prop) == -1 ||
546	    libscf_read_single_astring(h, prop, &scheme) != 0) {
547		scf_property_destroy(prop);
548		startd_free(scheme, max_scf_value_size);
549		return (GVT_UNSUPPORTED);
550	}
551
552	if (strcmp(scheme, "service") == 0)
553		ret = GVT_INST;
554	else if (strcmp(scheme, "path") == 0)
555		ret = GVT_FILE;
556	else
557		ret = GVT_UNSUPPORTED;
558
559	startd_free(scheme, max_scf_value_size);
560	scf_property_destroy(prop);
561	return (ret);
562}
563
564depgroup_type_t
565depgroup_read_grouping(scf_handle_t *h, scf_propertygroup_t *pg)
566{
567	char *grouping = startd_alloc(max_scf_value_size);
568	depgroup_type_t ret;
569	scf_property_t *prop = safe_scf_property_create(h);
570
571	if (scf_pg_get_property(pg, SCF_PROPERTY_GROUPING, prop) == -1 ||
572	    libscf_read_single_astring(h, prop, &grouping) != 0) {
573		scf_property_destroy(prop);
574		startd_free(grouping, max_scf_value_size);
575		return (DEPGRP_UNSUPPORTED);
576	}
577
578	if (strcmp(grouping, SCF_DEP_REQUIRE_ANY) == 0)
579		ret = DEPGRP_REQUIRE_ANY;
580	else if (strcmp(grouping, SCF_DEP_REQUIRE_ALL) == 0)
581		ret = DEPGRP_REQUIRE_ALL;
582	else if (strcmp(grouping, SCF_DEP_OPTIONAL_ALL) == 0)
583		ret = DEPGRP_OPTIONAL_ALL;
584	else if (strcmp(grouping, SCF_DEP_EXCLUDE_ALL) == 0)
585		ret = DEPGRP_EXCLUDE_ALL;
586	else {
587		ret = DEPGRP_UNSUPPORTED;
588	}
589	startd_free(grouping, max_scf_value_size);
590	scf_property_destroy(prop);
591	return (ret);
592}
593
594restarter_error_t
595depgroup_read_restart(scf_handle_t *h, scf_propertygroup_t *pg)
596{
597	scf_property_t *prop = safe_scf_property_create(h);
598	char *restart_on = startd_alloc(max_scf_value_size);
599	restarter_error_t ret;
600
601	if (scf_pg_get_property(pg, SCF_PROPERTY_RESTART_ON, prop) == -1 ||
602	    libscf_read_single_astring(h, prop, &restart_on) != 0) {
603		startd_free(restart_on, max_scf_value_size);
604		scf_property_destroy(prop);
605		return (RERR_UNSUPPORTED);
606	}
607
608	if (strcmp(restart_on, SCF_DEP_RESET_ON_ERROR) == 0)
609		ret = RERR_FAULT;
610	else if (strcmp(restart_on, SCF_DEP_RESET_ON_RESTART) == 0)
611		ret = RERR_RESTART;
612	else if (strcmp(restart_on, SCF_DEP_RESET_ON_REFRESH) == 0)
613		ret = RERR_REFRESH;
614	else if (strcmp(restart_on, SCF_DEP_RESET_ON_NONE) == 0)
615		ret = RERR_NONE;
616	else
617		ret = RERR_UNSUPPORTED;
618
619	startd_free(restart_on, max_scf_value_size);
620	scf_property_destroy(prop);
621	return (ret);
622}
623
624/*
625 * int get_boolean()
626 *   Fetches the value of a boolean property of the given property group.
627 *   Returns
628 *     0 - success
629 *     ECONNABORTED - repository connection broken
630 *     ECANCELED - pg was deleted
631 *     ENOENT - the property doesn't exist or has no values
632 *     EINVAL - the property has the wrong type
633 *		the property is not single-valued
634 *     EACCES - the current user does not have permission to read the value
635 */
636static int
637get_boolean(scf_propertygroup_t *pg, const char *propname, uint8_t *valuep)
638{
639	scf_handle_t *h;
640	scf_property_t *prop;
641	scf_value_t *val;
642	int ret = 0, r;
643	scf_type_t type;
644
645	h = scf_pg_handle(pg);
646	prop = safe_scf_property_create(h);
647	val = safe_scf_value_create(h);
648
649	if (scf_pg_get_property(pg, propname, prop) != 0) {
650		switch (scf_error()) {
651		case SCF_ERROR_CONNECTION_BROKEN:
652		default:
653			ret = ECONNABORTED;
654			goto out;
655
656		case SCF_ERROR_DELETED:
657			ret = ECANCELED;
658			goto out;
659
660		case SCF_ERROR_NOT_FOUND:
661			ret = ENOENT;
662			goto out;
663
664		case SCF_ERROR_HANDLE_MISMATCH:
665		case SCF_ERROR_INVALID_ARGUMENT:
666		case SCF_ERROR_NOT_SET:
667			bad_error("scf_pg_get_property", scf_error());
668		}
669	}
670
671	if (scf_property_type(prop, &type) != 0) {
672		switch (scf_error()) {
673		case SCF_ERROR_CONNECTION_BROKEN:
674		default:
675			ret = ECONNABORTED;
676			goto out;
677
678		case SCF_ERROR_DELETED:
679			ret = ENOENT;
680			goto out;
681
682		case SCF_ERROR_NOT_SET:
683			bad_error("scf_property_type", scf_error());
684		}
685	}
686
687	if (type != SCF_TYPE_BOOLEAN) {
688		ret = EINVAL;
689		goto out;
690	}
691
692	if (scf_property_get_value(prop, val) != 0) {
693		switch (scf_error()) {
694		case SCF_ERROR_CONNECTION_BROKEN:
695		default:
696			ret = ECONNABORTED;
697			goto out;
698
699		case SCF_ERROR_DELETED:
700		case SCF_ERROR_NOT_FOUND:
701			ret = ENOENT;
702			goto out;
703
704		case SCF_ERROR_CONSTRAINT_VIOLATED:
705			ret = EINVAL;
706			goto out;
707
708		case SCF_ERROR_PERMISSION_DENIED:
709			ret = EACCES;
710			goto out;
711
712		case SCF_ERROR_NOT_SET:
713			bad_error("scf_property_get_value", scf_error());
714		}
715	}
716
717	r = scf_value_get_boolean(val, valuep);
718	assert(r == 0);
719
720out:
721	scf_value_destroy(val);
722	scf_property_destroy(prop);
723	return (ret);
724}
725
726/*
727 * int get_count()
728 *   Fetches the value of a count property of the given property group.
729 *   Returns
730 *     0 - success
731 *     ECONNABORTED - repository connection broken
732 *                    unknown libscf error
733 *     ECANCELED - pg was deleted
734 *     ENOENT - the property doesn't exist or has no values
735 *     EINVAL - the property has the wrong type
736 *              the property is not single-valued
737 *     EACCES - the current user does not have permission to read the value
738 */
739static int
740get_count(scf_propertygroup_t *pg, const char *propname, uint64_t *valuep)
741{
742	scf_handle_t *h;
743	scf_property_t *prop;
744	scf_value_t *val;
745	int ret = 0, r;
746
747	h = scf_pg_handle(pg);
748	prop = safe_scf_property_create(h);
749	val = safe_scf_value_create(h);
750
751	if (scf_pg_get_property(pg, propname, prop) != 0) {
752		switch (scf_error()) {
753		case SCF_ERROR_CONNECTION_BROKEN:
754		default:
755			ret = ECONNABORTED;
756			goto out;
757
758		case SCF_ERROR_DELETED:
759			ret = ECANCELED;
760			goto out;
761
762		case SCF_ERROR_NOT_FOUND:
763			ret = ENOENT;
764			goto out;
765
766		case SCF_ERROR_HANDLE_MISMATCH:
767		case SCF_ERROR_INVALID_ARGUMENT:
768		case SCF_ERROR_NOT_SET:
769			bad_error("scf_pg_get_property", scf_error());
770		}
771	}
772
773	if (scf_property_is_type(prop, SCF_TYPE_COUNT) != 0) {
774		switch (scf_error()) {
775		case SCF_ERROR_CONNECTION_BROKEN:
776		default:
777			ret = ECONNABORTED;
778			goto out;
779
780		case SCF_ERROR_TYPE_MISMATCH:
781			ret = EINVAL;
782			goto out;
783
784		case SCF_ERROR_DELETED:
785			ret = ECANCELED;
786			goto out;
787
788		case SCF_ERROR_INVALID_ARGUMENT:
789		case SCF_ERROR_NOT_BOUND:
790		case SCF_ERROR_NOT_SET:
791			bad_error("scf_property_is_type", scf_error());
792		}
793	}
794
795	if (scf_property_get_value(prop, val) != 0) {
796		switch (scf_error()) {
797		case SCF_ERROR_CONNECTION_BROKEN:
798		default:
799			ret = ECONNABORTED;
800			goto out;
801
802		case SCF_ERROR_DELETED:
803			ret = ECANCELED;
804			goto out;
805
806		case SCF_ERROR_NOT_FOUND:
807			ret = ENOENT;
808			goto out;
809
810		case SCF_ERROR_CONSTRAINT_VIOLATED:
811			ret = EINVAL;
812			goto out;
813
814		case SCF_ERROR_PERMISSION_DENIED:
815			ret = EACCES;
816			goto out;
817
818		case SCF_ERROR_NOT_SET:
819			bad_error("scf_property_get_value", scf_error());
820		}
821	}
822
823	r = scf_value_get_count(val, valuep);
824	assert(r == 0);
825
826out:
827	scf_value_destroy(val);
828	scf_property_destroy(prop);
829	return (ret);
830}
831
832
833static void
834get_restarter(scf_handle_t *h, scf_propertygroup_t *pg, char **restarter)
835{
836	scf_property_t *prop = safe_scf_property_create(h);
837
838	if (scf_pg_get_property(pg, SCF_PROPERTY_RESTARTER, prop) == -1 ||
839	    libscf_read_single_astring(h, prop, restarter) != 0)
840		*restarter[0] = '\0';
841
842	scf_property_destroy(prop);
843}
844
845/*
846 * int libscf_instance_get_fmri(scf_instance_t *, char **)
847 *   Give a valid SCF instance, return its FMRI.  Returns 0 on success,
848 *   ECONNABORTED, or ECANCELED if inst is deleted.
849 */
850int
851libscf_instance_get_fmri(scf_instance_t *inst, char **retp)
852{
853	char *inst_fmri = startd_alloc(max_scf_fmri_size);
854
855	inst_fmri[0] = 0;
856	if (scf_instance_to_fmri(inst, inst_fmri, max_scf_fmri_size) <= 0) {
857		startd_free(inst_fmri, max_scf_fmri_size);
858		switch (scf_error()) {
859		case SCF_ERROR_CONNECTION_BROKEN:
860		default:
861			return (ECONNABORTED);
862
863		case SCF_ERROR_DELETED:
864			return (ECANCELED);
865
866		case SCF_ERROR_NOT_SET:
867			assert(0);
868			abort();
869		}
870	}
871
872	*retp = inst_fmri;
873	return (0);
874}
875
876/*
877 * int libscf_fmri_get_instance(scf_handle_t *, const char *,
878 *	scf_instance_t **)
879 *   Given a valid SCF handle and an FMRI, return the SCF instance that matches
880 *   exactly.  The instance must be released using scf_instance_destroy().
881 *   Returns 0 on success, EINVAL if the FMRI is invalid, ENOTSUP if the FMRI
882 *   is valid but designates something other than an instance, ECONNABORTED if
883 *   the repository connection is broken, or ENOENT if the instance does not
884 *   exist.
885 */
886int
887libscf_fmri_get_instance(scf_handle_t *h, const char *fmri,
888    scf_instance_t **instp)
889{
890	scf_instance_t *inst;
891	int r;
892
893	inst = safe_scf_instance_create(h);
894
895	r = libscf_lookup_instance(fmri, inst);
896
897	if (r == 0)
898		*instp = inst;
899	else
900		scf_instance_destroy(inst);
901
902	return (r);
903}
904
905int
906libscf_lookup_instance(const char *fmri, scf_instance_t *inst)
907{
908	if (scf_handle_decode_fmri(scf_instance_handle(inst), fmri, NULL, NULL,
909	    inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
910		switch (scf_error()) {
911		case SCF_ERROR_INVALID_ARGUMENT:
912			return (EINVAL);
913
914		case SCF_ERROR_CONSTRAINT_VIOLATED:
915			return (ENOTSUP);
916
917		case SCF_ERROR_CONNECTION_BROKEN:
918			return (ECONNABORTED);
919
920		case SCF_ERROR_NOT_FOUND:
921			return (ENOENT);
922
923		case SCF_ERROR_HANDLE_MISMATCH:
924		default:
925			bad_error("scf_handle_decode_fmri", scf_error());
926		}
927	}
928
929	return (0);
930}
931
932/*
933 * int libscf_get_deathrow()
934 * Read deathrow for inst. Returns 0, ECONNABORTED if the connection to the
935 * repository is broken, ECANCELED if inst is deleted, or ENOENT if inst
936 * has no deathrow property group.
937 *
938 * If deathrow/deathrow was missing or invalid, *deathrow will be -1 and a
939 * debug message is logged.
940 */
941int
942libscf_get_deathrow(scf_handle_t *h, scf_instance_t *inst, int *deathrow)
943{
944	scf_propertygroup_t *pg;
945	int r;
946	uint8_t deathrow_8;
947
948	pg = safe_scf_pg_create(h);
949
950	if (scf_instance_get_pg_composed(inst, NULL, SCF_PG_DEATHROW, pg) !=
951	    0) {
952		switch (scf_error()) {
953		case SCF_ERROR_CONNECTION_BROKEN:
954		default:
955			scf_pg_destroy(pg);
956			return (ECONNABORTED);
957
958		case SCF_ERROR_DELETED:
959			scf_pg_destroy(pg);
960			return (ECANCELED);
961
962		case SCF_ERROR_NOT_FOUND:
963			*deathrow = -1;
964			break;
965
966		case SCF_ERROR_HANDLE_MISMATCH:
967		case SCF_ERROR_INVALID_ARGUMENT:
968		case SCF_ERROR_NOT_SET:
969			bad_error("libscf_get_deathrow", scf_error());
970		}
971	} else {
972		switch (r = get_boolean(pg,
973		    SCF_PROPERTY_DEATHROW, &deathrow_8)) {
974		case 0:
975			*deathrow = deathrow_8;
976			break;
977
978		case ECONNABORTED:
979		case ECANCELED:
980			scf_pg_destroy(pg);
981			return (r);
982
983		case ENOENT:
984		case EINVAL:
985			*deathrow = -1;
986			break;
987
988		default:
989			bad_error("get_boolean", r);
990		}
991	}
992
993	scf_pg_destroy(pg);
994
995	return (0);
996}
997
998/*
999 * void libscf_get_basic_instance_data()
1000 *   Read enabled, enabled_ovr, and restarter_fmri (into an allocated
1001 *   buffer) for inst.  Returns 0, ECONNABORTED if the connection to the
1002 *   repository is broken, ECANCELED if inst is deleted, or ENOENT if inst
1003 *   has no general property group.
1004 *
1005 *   On success, restarter_fmri may be NULL.  If general/enabled was missing
1006 *   or invalid, *enabledp will be -1 and a debug message is logged.
1007 */
1008int
1009libscf_get_basic_instance_data(scf_handle_t *h, scf_instance_t *inst,
1010    const char *fmri, int *enabledp, int *enabled_ovrp, char **restarter_fmri)
1011{
1012	scf_propertygroup_t *pg;
1013	int r;
1014	uint8_t enabled_8;
1015
1016	pg = safe_scf_pg_create(h);
1017
1018	if (enabled_ovrp == NULL)
1019		goto enabled;
1020
1021	if (scf_instance_get_pg_composed(inst, NULL, SCF_PG_GENERAL_OVR, pg) !=
1022	    0) {
1023		switch (scf_error()) {
1024		case SCF_ERROR_CONNECTION_BROKEN:
1025		default:
1026			scf_pg_destroy(pg);
1027			return (ECONNABORTED);
1028
1029		case SCF_ERROR_DELETED:
1030			scf_pg_destroy(pg);
1031			return (ECANCELED);
1032
1033		case SCF_ERROR_NOT_FOUND:
1034			*enabled_ovrp = -1;
1035			break;
1036
1037		case SCF_ERROR_HANDLE_MISMATCH:
1038		case SCF_ERROR_INVALID_ARGUMENT:
1039		case SCF_ERROR_NOT_SET:
1040			bad_error("scf_instance_get_pg_composed", scf_error());
1041		}
1042	} else {
1043		switch (r = get_boolean(pg, SCF_PROPERTY_ENABLED, &enabled_8)) {
1044		case 0:
1045			*enabled_ovrp = enabled_8;
1046			break;
1047
1048		case ECONNABORTED:
1049		case ECANCELED:
1050			scf_pg_destroy(pg);
1051			return (r);
1052
1053		case ENOENT:
1054		case EINVAL:
1055			*enabled_ovrp = -1;
1056			break;
1057
1058		case EACCES:
1059		default:
1060			bad_error("get_boolean", r);
1061		}
1062	}
1063
1064enabled:
1065	/*
1066	 * Since general/restarter can be at the service level, we must do
1067	 * a composed lookup.  These properties are immediate, though, so we
1068	 * must use the "editing" snapshot.  Technically enabled shouldn't be
1069	 * at the service level, but looking it up composed, too, doesn't
1070	 * hurt.
1071	 */
1072	if (scf_instance_get_pg_composed(inst, NULL, SCF_PG_GENERAL, pg) != 0) {
1073		scf_pg_destroy(pg);
1074		switch (scf_error()) {
1075		case SCF_ERROR_CONNECTION_BROKEN:
1076		default:
1077			return (ECONNABORTED);
1078
1079		case SCF_ERROR_DELETED:
1080			return (ECANCELED);
1081
1082		case SCF_ERROR_NOT_FOUND:
1083			return (ENOENT);
1084
1085		case SCF_ERROR_NOT_SET:
1086			bad_error("scf_instance_get_pg_composed", scf_error());
1087		}
1088	}
1089
1090	switch (r = get_boolean(pg, SCF_PROPERTY_ENABLED, &enabled_8)) {
1091	case 0:
1092		*enabledp = enabled_8;
1093		break;
1094
1095	case ECONNABORTED:
1096	case ECANCELED:
1097		scf_pg_destroy(pg);
1098		return (r);
1099
1100	case ENOENT:
1101		/*
1102		 * DEBUG because this happens when svccfg import creates
1103		 * a temporary service.
1104		 */
1105		log_framework(LOG_DEBUG,
1106		    "general/enabled property of %s is missing.\n", fmri);
1107		*enabledp = -1;
1108		break;
1109
1110	case EINVAL:
1111		log_framework(LOG_ERR,
1112		    "general/enabled property of %s is invalid.\n", fmri);
1113		*enabledp = -1;
1114		break;
1115
1116	case EACCES:
1117	default:
1118		bad_error("get_boolean", r);
1119	}
1120
1121	if (restarter_fmri != NULL)
1122		get_restarter(h, pg, restarter_fmri);
1123
1124	scf_pg_destroy(pg);
1125
1126	return (0);
1127}
1128
1129
1130/*
1131 * Sets pg to the name property group of s_inst.  If it doesn't exist, it is
1132 * added.
1133 *
1134 * Fails with
1135 *   ECONNABORTED - repository disconnection or unknown libscf error
1136 *   ECANCELED - inst is deleted
1137 *   EPERM - permission is denied
1138 *   EACCES - backend denied access
1139 *   EROFS - backend readonly
1140 */
1141int
1142libscf_inst_get_or_add_pg(scf_instance_t *inst, const char *name,
1143    const char *type, uint32_t flags, scf_propertygroup_t *pg)
1144{
1145	uint32_t f;
1146
1147again:
1148	if (scf_instance_get_pg(inst, name, pg) == 0) {
1149		if (scf_pg_get_flags(pg, &f) != 0) {
1150			switch (scf_error()) {
1151			case SCF_ERROR_CONNECTION_BROKEN:
1152			default:
1153				return (ECONNABORTED);
1154
1155			case SCF_ERROR_DELETED:
1156				goto add;
1157
1158			case SCF_ERROR_NOT_SET:
1159				bad_error("scf_pg_get_flags", scf_error());
1160			}
1161		}
1162
1163		if (f == flags)
1164			return (0);
1165
1166		if (scf_pg_delete(pg) != 0) {
1167			switch (scf_error()) {
1168			case SCF_ERROR_CONNECTION_BROKEN:
1169			default:
1170				return (ECONNABORTED);
1171
1172			case SCF_ERROR_DELETED:
1173				break;
1174
1175			case SCF_ERROR_PERMISSION_DENIED:
1176				return (EPERM);
1177
1178			case SCF_ERROR_BACKEND_ACCESS:
1179				return (EACCES);
1180
1181			case SCF_ERROR_BACKEND_READONLY:
1182				return (EROFS);
1183
1184			case SCF_ERROR_NOT_SET:
1185				bad_error("scf_pg_delete", scf_error());
1186			}
1187		}
1188	} else {
1189		switch (scf_error()) {
1190		case SCF_ERROR_CONNECTION_BROKEN:
1191		default:
1192			return (ECONNABORTED);
1193
1194		case SCF_ERROR_DELETED:
1195			return (ECANCELED);
1196
1197		case SCF_ERROR_NOT_FOUND:
1198			break;
1199
1200		case SCF_ERROR_HANDLE_MISMATCH:
1201		case SCF_ERROR_INVALID_ARGUMENT:
1202		case SCF_ERROR_NOT_SET:
1203			bad_error("scf_instance_get_pg", scf_error());
1204		}
1205	}
1206
1207add:
1208	if (scf_instance_add_pg(inst, name, type, flags, pg) == 0)
1209		return (0);
1210
1211	switch (scf_error()) {
1212	case SCF_ERROR_CONNECTION_BROKEN:
1213	default:
1214		return (ECONNABORTED);
1215
1216	case SCF_ERROR_DELETED:
1217		return (ECANCELED);
1218
1219	case SCF_ERROR_EXISTS:
1220		goto again;
1221
1222	case SCF_ERROR_PERMISSION_DENIED:
1223		return (EPERM);
1224
1225	case SCF_ERROR_BACKEND_ACCESS:
1226		return (EACCES);
1227
1228	case SCF_ERROR_BACKEND_READONLY:
1229		return (EROFS);
1230
1231	case SCF_ERROR_HANDLE_MISMATCH:
1232	case SCF_ERROR_INVALID_ARGUMENT:
1233	case SCF_ERROR_NOT_SET:
1234		bad_error("scf_instance_add_pg", scf_error());
1235		/* NOTREACHED */
1236	}
1237}
1238
1239/*
1240 * Returns
1241 *   0 - success
1242 *   ECONNABORTED - repository connection broken
1243 *		  - unknown libscf error
1244 *   ECANCELED
1245 */
1246static scf_error_t
1247transaction_add_set(scf_transaction_t *tx, scf_transaction_entry_t *ent,
1248    const char *pname, scf_type_t ty)
1249{
1250	for (;;) {
1251		if (scf_transaction_property_change_type(tx, ent, pname,
1252		    ty) == 0)
1253			return (0);
1254
1255		switch (scf_error()) {
1256		case SCF_ERROR_CONNECTION_BROKEN:
1257		default:
1258			return (ECONNABORTED);
1259
1260		case SCF_ERROR_DELETED:
1261			return (ECANCELED);
1262
1263		case SCF_ERROR_NOT_FOUND:
1264			break;
1265
1266		case SCF_ERROR_HANDLE_MISMATCH:
1267		case SCF_ERROR_INVALID_ARGUMENT:
1268		case SCF_ERROR_IN_USE:
1269		case SCF_ERROR_NOT_SET:
1270			bad_error("scf_transaction_property_change_type",
1271			    scf_error());
1272		}
1273
1274		if (scf_transaction_property_new(tx, ent, pname, ty) == 0)
1275			return (0);
1276
1277		switch (scf_error()) {
1278		case SCF_ERROR_CONNECTION_BROKEN:
1279		default:
1280			return (ECONNABORTED);
1281
1282		case SCF_ERROR_DELETED:
1283			return (ECANCELED);
1284
1285		case SCF_ERROR_EXISTS:
1286			break;
1287
1288		case SCF_ERROR_HANDLE_MISMATCH:
1289		case SCF_ERROR_INVALID_ARGUMENT:
1290		case SCF_ERROR_IN_USE:
1291		case SCF_ERROR_NOT_SET:
1292			bad_error("scf_transaction_property_new", scf_error());
1293			/* NOTREACHED */
1294		}
1295	}
1296}
1297
1298/*
1299 * Returns
1300 *   0 - success
1301 *   ECONNABORTED - repository connection broken
1302 *		  - unknown libscf error
1303 *   ECANCELED - pg was deleted
1304 *   EPERM
1305 *   EACCES
1306 *   EROFS
1307 */
1308static int
1309pg_set_prop_value(scf_propertygroup_t *pg, const char *pname, scf_value_t *v)
1310{
1311	scf_handle_t *h;
1312	scf_transaction_t *tx;
1313	scf_transaction_entry_t *e;
1314	scf_type_t ty;
1315	scf_error_t scfe;
1316	int ret, r;
1317
1318	h = scf_pg_handle(pg);
1319	tx = safe_scf_transaction_create(h);
1320	e = safe_scf_entry_create(h);
1321
1322	ty = scf_value_type(v);
1323	assert(ty != SCF_TYPE_INVALID);
1324
1325	for (;;) {
1326		if (scf_transaction_start(tx, pg) != 0) {
1327			switch (scf_error()) {
1328			case SCF_ERROR_CONNECTION_BROKEN:
1329			default:
1330				ret = ECONNABORTED;
1331				goto out;
1332
1333			case SCF_ERROR_DELETED:
1334				ret = ECANCELED;
1335				goto out;
1336
1337			case SCF_ERROR_PERMISSION_DENIED:
1338				ret = EPERM;
1339				goto out;
1340
1341			case SCF_ERROR_BACKEND_ACCESS:
1342				ret = EACCES;
1343				goto out;
1344
1345			case SCF_ERROR_BACKEND_READONLY:
1346				ret = EROFS;
1347				goto out;
1348
1349			case SCF_ERROR_NOT_SET:
1350				bad_error("scf_transaction_start", ret);
1351			}
1352		}
1353
1354		ret = transaction_add_set(tx, e, pname, ty);
1355		switch (ret) {
1356		case 0:
1357			break;
1358
1359		case ECONNABORTED:
1360		case ECANCELED:
1361			goto out;
1362
1363		default:
1364			bad_error("transaction_add_set", ret);
1365		}
1366
1367		r = scf_entry_add_value(e, v);
1368		assert(r == 0);
1369
1370		r = scf_transaction_commit(tx);
1371		if (r == 1)
1372			break;
1373		if (r != 0) {
1374			scfe = scf_error();
1375			scf_transaction_reset(tx);
1376			switch (scfe) {
1377			case SCF_ERROR_CONNECTION_BROKEN:
1378			default:
1379				ret = ECONNABORTED;
1380				goto out;
1381
1382			case SCF_ERROR_DELETED:
1383				ret = ECANCELED;
1384				goto out;
1385
1386			case SCF_ERROR_PERMISSION_DENIED:
1387				ret = EPERM;
1388				goto out;
1389
1390			case SCF_ERROR_BACKEND_ACCESS:
1391				ret = EACCES;
1392				goto out;
1393
1394			case SCF_ERROR_BACKEND_READONLY:
1395				ret = EROFS;
1396				goto out;
1397
1398			case SCF_ERROR_NOT_SET:
1399				bad_error("scf_transaction_commit", scfe);
1400			}
1401		}
1402
1403		scf_transaction_reset(tx);
1404
1405		if (scf_pg_update(pg) == -1) {
1406			switch (scf_error()) {
1407			case SCF_ERROR_CONNECTION_BROKEN:
1408			default:
1409				ret = ECONNABORTED;
1410				goto out;
1411
1412			case SCF_ERROR_DELETED:
1413				ret = ECANCELED;
1414				goto out;
1415
1416			case SCF_ERROR_NOT_SET:
1417				bad_error("scf_pg_update", scf_error());
1418			}
1419		}
1420	}
1421
1422	ret = 0;
1423
1424out:
1425	scf_transaction_destroy(tx);
1426	scf_entry_destroy(e);
1427	return (ret);
1428}
1429
1430/*
1431 * Returns
1432 *   0 - success
1433 *   ECONNABORTED - repository connection broken
1434 *		  - unknown libscf error
1435 *   ECANCELED - inst was deleted
1436 *   EPERM
1437 *   EACCES
1438 *   EROFS
1439 */
1440int
1441libscf_inst_set_boolean_prop(scf_instance_t *inst, const char *pgname,
1442    const char *pgtype, uint32_t pgflags, const char *pname, int val)
1443{
1444	scf_handle_t *h;
1445	scf_propertygroup_t *pg = NULL;
1446	scf_value_t *v;
1447	int ret = 0;
1448
1449	h = scf_instance_handle(inst);
1450	pg = safe_scf_pg_create(h);
1451	v = safe_scf_value_create(h);
1452
1453	ret = libscf_inst_get_or_add_pg(inst, pgname, pgtype, pgflags, pg);
1454	switch (ret) {
1455	case 0:
1456		break;
1457
1458	case ECONNABORTED:
1459	case ECANCELED:
1460	case EPERM:
1461	case EACCES:
1462	case EROFS:
1463		goto out;
1464
1465	default:
1466		bad_error("libscf_inst_get_or_add_pg", ret);
1467	}
1468
1469	scf_value_set_boolean(v, val);
1470
1471	ret = pg_set_prop_value(pg, pname, v);
1472	switch (ret) {
1473	case 0:
1474	case ECONNABORTED:
1475	case ECANCELED:
1476	case EPERM:
1477	case EACCES:
1478	case EROFS:
1479		break;
1480
1481	default:
1482		bad_error("pg_set_prop_value", ret);
1483	}
1484
1485out:
1486	scf_pg_destroy(pg);
1487	scf_value_destroy(v);
1488	return (ret);
1489}
1490
1491/*
1492 * Returns
1493 *   0 - success
1494 *   ECONNABORTED - repository connection broken
1495 *		  - unknown libscf error
1496 *   ECANCELED - inst was deleted
1497 *   EPERM
1498 *   EACCES
1499 *   EROFS
1500 */
1501int
1502libscf_inst_set_count_prop(scf_instance_t *inst, const char *pgname,
1503    const char *pgtype, uint32_t pgflags, const char *pname, uint64_t count)
1504{
1505	scf_handle_t *h;
1506	scf_propertygroup_t *pg = NULL;
1507	scf_value_t *v;
1508	int ret = 0;
1509
1510	h = scf_instance_handle(inst);
1511	pg = safe_scf_pg_create(h);
1512	v = safe_scf_value_create(h);
1513
1514	ret = libscf_inst_get_or_add_pg(inst, pgname, pgtype, pgflags, pg);
1515	switch (ret) {
1516	case 0:
1517		break;
1518
1519	case ECONNABORTED:
1520	case ECANCELED:
1521	case EPERM:
1522	case EACCES:
1523	case EROFS:
1524		goto out;
1525
1526	default:
1527		bad_error("libscf_inst_get_or_add_pg", ret);
1528	}
1529
1530	scf_value_set_count(v, count);
1531
1532	ret = pg_set_prop_value(pg, pname, v);
1533	switch (ret) {
1534	case 0:
1535	case ECONNABORTED:
1536	case ECANCELED:
1537	case EPERM:
1538	case EACCES:
1539	case EROFS:
1540		break;
1541
1542	default:
1543		bad_error("pg_set_prop_value", ret);
1544	}
1545
1546out:
1547	scf_pg_destroy(pg);
1548	scf_value_destroy(v);
1549	return (ret);
1550}
1551
1552/*
1553 * Returns 0 on success, ECONNABORTED if the repository connection is broken,
1554 * ECANCELED if inst is deleted, EROFS if the backend is readonly, or EPERM if
1555 * permission was denied.
1556 */
1557int
1558libscf_set_enable_ovr(scf_instance_t *inst, int enable)
1559{
1560	return (libscf_inst_set_boolean_prop(inst, SCF_PG_GENERAL_OVR,
1561	    SCF_PG_GENERAL_OVR_TYPE, SCF_PG_GENERAL_OVR_FLAGS,
1562	    SCF_PROPERTY_ENABLED, enable));
1563}
1564
1565/*
1566 * Returns 0 on success, ECONNABORTED if the repository connection is broken,
1567 * ECANCELED if inst is deleted, EROFS if the backend is readonly, or EPERM if
1568 * permission was denied.
1569 */
1570int
1571libscf_set_deathrow(scf_instance_t *inst, int deathrow)
1572{
1573	return (libscf_inst_set_boolean_prop(inst, SCF_PG_DEATHROW,
1574	    SCF_PG_DEATHROW_TYPE, SCF_PG_DEATHROW_FLAGS,
1575	    SCF_PROPERTY_DEATHROW, deathrow));
1576}
1577
1578/*
1579 * Returns
1580 *   0 - success
1581 *   ECONNABORTED - repository connection broken
1582 *   ECANCELED - inst was deleted
1583 *   EPERM
1584 *   EACCES
1585 *   EROFS
1586 */
1587int
1588libscf_inst_delete_prop(scf_instance_t *inst, const char *pgname,
1589    const char *pname)
1590{
1591	scf_handle_t *h;
1592	scf_propertygroup_t *pg;
1593	scf_transaction_t *tx;
1594	scf_transaction_entry_t *e;
1595	scf_error_t serr;
1596	int ret = 0, r;
1597
1598	h = scf_instance_handle(inst);
1599	pg = safe_scf_pg_create(h);
1600
1601	if (scf_instance_get_pg(inst, pgname, pg) != 0) {
1602		scf_pg_destroy(pg);
1603		switch (scf_error()) {
1604		case SCF_ERROR_CONNECTION_BROKEN:
1605		default:
1606			return (ECONNABORTED);
1607
1608		case SCF_ERROR_DELETED:
1609			return (ECANCELED);
1610
1611		case SCF_ERROR_NOT_FOUND:
1612			return (0);
1613
1614		case SCF_ERROR_NOT_SET:
1615			bad_error("scf_instance_get_pg", scf_error());
1616		}
1617	}
1618
1619	tx = safe_scf_transaction_create(h);
1620	e = safe_scf_entry_create(h);
1621
1622	for (;;) {
1623		if (scf_transaction_start(tx, pg) != 0) {
1624			switch (scf_error()) {
1625			case SCF_ERROR_CONNECTION_BROKEN:
1626			default:
1627				ret = ECONNABORTED;
1628				goto out;
1629
1630			case SCF_ERROR_DELETED:
1631				ret = 0;
1632				goto out;
1633
1634			case SCF_ERROR_PERMISSION_DENIED:
1635				ret = EPERM;
1636				goto out;
1637
1638			case SCF_ERROR_BACKEND_ACCESS:
1639				ret = EACCES;
1640				goto out;
1641
1642			case SCF_ERROR_BACKEND_READONLY:
1643				ret = EROFS;
1644				goto out;
1645
1646			case SCF_ERROR_HANDLE_MISMATCH:
1647			case SCF_ERROR_INVALID_ARGUMENT:
1648			case SCF_ERROR_NOT_SET:
1649				bad_error("scf_transaction_start", scf_error());
1650			}
1651		}
1652
1653		if (scf_transaction_property_delete(tx, e, pname) != 0) {
1654			switch (scf_error()) {
1655			case SCF_ERROR_CONNECTION_BROKEN:
1656			default:
1657				ret = ECONNABORTED;
1658				goto out;
1659
1660			case SCF_ERROR_DELETED:
1661			case SCF_ERROR_NOT_FOUND:
1662				ret = 0;
1663				goto out;
1664
1665			case SCF_ERROR_NOT_SET:
1666			case SCF_ERROR_HANDLE_MISMATCH:
1667			case SCF_ERROR_NOT_BOUND:
1668			case SCF_ERROR_INVALID_ARGUMENT:
1669				bad_error("scf_transaction_property_delete",
1670				    scf_error());
1671			}
1672		}
1673
1674		r = scf_transaction_commit(tx);
1675		if (r == 1)
1676			break;
1677		if (r != 0) {
1678			serr = scf_error();
1679			scf_transaction_reset(tx);
1680			switch (serr) {
1681			case SCF_ERROR_CONNECTION_BROKEN:
1682			default:
1683				ret = ECONNABORTED;
1684				goto out;
1685
1686			case SCF_ERROR_DELETED:
1687				ret = 0;
1688				goto out;
1689
1690			case SCF_ERROR_PERMISSION_DENIED:
1691				ret = EPERM;
1692				goto out;
1693
1694			case SCF_ERROR_BACKEND_ACCESS:
1695				ret = EACCES;
1696				goto out;
1697
1698			case SCF_ERROR_BACKEND_READONLY:
1699				ret = EROFS;
1700				goto out;
1701
1702			case SCF_ERROR_NOT_SET:
1703			case SCF_ERROR_INVALID_ARGUMENT:
1704			case SCF_ERROR_NOT_BOUND:
1705				bad_error("scf_transaction_commit", serr);
1706			}
1707		}
1708
1709		scf_transaction_reset(tx);
1710
1711		if (scf_pg_update(pg) == -1) {
1712			switch (scf_error()) {
1713			case SCF_ERROR_CONNECTION_BROKEN:
1714			default:
1715				ret = ECONNABORTED;
1716				goto out;
1717
1718			case SCF_ERROR_DELETED:
1719				ret = 0;
1720				goto out;
1721
1722			case SCF_ERROR_NOT_SET:
1723			case SCF_ERROR_NOT_BOUND:
1724				bad_error("scf_pg_update", scf_error());
1725			}
1726		}
1727	}
1728
1729out:
1730	scf_transaction_destroy(tx);
1731	(void) scf_entry_destroy(e);
1732	scf_pg_destroy(pg);
1733	return (ret);
1734}
1735
1736/*
1737 * Returns 0, ECONNABORTED, ECANCELED, or EPERM.
1738 */
1739int
1740libscf_delete_enable_ovr(scf_instance_t *inst)
1741{
1742	return (libscf_inst_delete_prop(inst, SCF_PG_GENERAL_OVR,
1743	    SCF_PROPERTY_ENABLED));
1744}
1745
1746/*
1747 * Fails with
1748 *   ECONNABORTED - repository connection was broken
1749 *   ECANCELED - pg was deleted
1750 *   ENOENT - pg has no milestone property
1751 *   EINVAL - the milestone property is misconfigured
1752 */
1753static int
1754pg_get_milestone(scf_propertygroup_t *pg, scf_property_t *prop,
1755    scf_value_t *val, char *buf, size_t buf_sz)
1756{
1757	if (scf_pg_get_property(pg, SCF_PROPERTY_MILESTONE, prop) != 0) {
1758		switch (scf_error()) {
1759		case SCF_ERROR_CONNECTION_BROKEN:
1760		default:
1761			return (ECONNABORTED);
1762
1763		case SCF_ERROR_DELETED:
1764			return (ECANCELED);
1765
1766		case SCF_ERROR_NOT_FOUND:
1767			return (ENOENT);
1768
1769		case SCF_ERROR_HANDLE_MISMATCH:
1770		case SCF_ERROR_INVALID_ARGUMENT:
1771		case SCF_ERROR_NOT_SET:
1772			bad_error("scf_pg_get_property", scf_error());
1773		}
1774	}
1775
1776	if (scf_property_get_value(prop, val) != 0) {
1777		switch (scf_error()) {
1778		case SCF_ERROR_CONNECTION_BROKEN:
1779		default:
1780			return (ECONNABORTED);
1781
1782		case SCF_ERROR_DELETED:
1783		case SCF_ERROR_CONSTRAINT_VIOLATED:
1784		case SCF_ERROR_NOT_FOUND:
1785			return (EINVAL);
1786
1787		case SCF_ERROR_NOT_SET:
1788		case SCF_ERROR_PERMISSION_DENIED:
1789			bad_error("scf_property_get_value", scf_error());
1790		}
1791	}
1792
1793	if (scf_value_get_astring(val, buf, buf_sz) < 0) {
1794		switch (scf_error()) {
1795		case SCF_ERROR_TYPE_MISMATCH:
1796			return (EINVAL);
1797
1798		case SCF_ERROR_NOT_SET:
1799		default:
1800			bad_error("scf_value_get_astring", scf_error());
1801		}
1802	}
1803
1804	return (0);
1805}
1806
1807/*
1808 * Fails with
1809 *   ECONNABORTED - repository connection was broken
1810 *   ECANCELED - inst was deleted
1811 *   ENOENT - inst has no milestone property
1812 *   EINVAL - the milestone property is misconfigured
1813 */
1814int
1815libscf_get_milestone(scf_instance_t *inst, scf_property_t *prop,
1816    scf_value_t *val, char *buf, size_t buf_sz)
1817{
1818	scf_propertygroup_t *pg;
1819	int r;
1820
1821	pg = safe_scf_pg_create(scf_instance_handle(inst));
1822
1823	if (scf_instance_get_pg(inst, SCF_PG_OPTIONS_OVR, pg) == 0) {
1824		switch (r = pg_get_milestone(pg, prop, val, buf, buf_sz)) {
1825		case 0:
1826		case ECONNABORTED:
1827		case EINVAL:
1828			goto out;
1829
1830		case ECANCELED:
1831		case ENOENT:
1832			break;
1833
1834		default:
1835			bad_error("pg_get_milestone", r);
1836		}
1837	} else {
1838		switch (scf_error()) {
1839		case SCF_ERROR_CONNECTION_BROKEN:
1840		default:
1841			r = ECONNABORTED;
1842			goto out;
1843
1844		case SCF_ERROR_DELETED:
1845			r = ECANCELED;
1846			goto out;
1847
1848		case SCF_ERROR_NOT_FOUND:
1849			break;
1850
1851		case SCF_ERROR_HANDLE_MISMATCH:
1852		case SCF_ERROR_INVALID_ARGUMENT:
1853		case SCF_ERROR_NOT_SET:
1854			bad_error("scf_instance_get_pg", scf_error());
1855		}
1856	}
1857
1858	if (scf_instance_get_pg(inst, SCF_PG_OPTIONS, pg) == 0) {
1859		r = pg_get_milestone(pg, prop, val, buf, buf_sz);
1860	} else {
1861		switch (scf_error()) {
1862		case SCF_ERROR_CONNECTION_BROKEN:
1863		default:
1864			r = ECONNABORTED;
1865			goto out;
1866
1867		case SCF_ERROR_DELETED:
1868			r = ECANCELED;
1869			goto out;
1870
1871		case SCF_ERROR_NOT_FOUND:
1872			r = ENOENT;
1873			break;
1874
1875		case SCF_ERROR_HANDLE_MISMATCH:
1876		case SCF_ERROR_INVALID_ARGUMENT:
1877		case SCF_ERROR_NOT_SET:
1878			bad_error("scf_instance_get_pg", scf_error());
1879		}
1880	}
1881
1882out:
1883	scf_pg_destroy(pg);
1884
1885	return (r);
1886}
1887
1888/*
1889 * Get the runlevel character from the runlevel property of the given property
1890 * group.  Fails with
1891 *   ECONNABORTED - repository connection was broken
1892 *   ECANCELED - prop's property group was deleted
1893 *   ENOENT - the property has no values
1894 *   EINVAL - the property has more than one value
1895 *	      the property is of the wrong type
1896 *	      the property value is malformed
1897 */
1898int
1899libscf_extract_runlevel(scf_property_t *prop, char *rlp)
1900{
1901	scf_value_t *val;
1902	char buf[2];
1903
1904	val = safe_scf_value_create(scf_property_handle(prop));
1905
1906	if (scf_property_get_value(prop, val) != 0) {
1907		switch (scf_error()) {
1908		case SCF_ERROR_CONNECTION_BROKEN:
1909			return (ECONNABORTED);
1910
1911		case SCF_ERROR_NOT_SET:
1912			return (ENOENT);
1913
1914		case SCF_ERROR_DELETED:
1915			return (ECANCELED);
1916
1917		case SCF_ERROR_CONSTRAINT_VIOLATED:
1918			return (EINVAL);
1919
1920		case SCF_ERROR_NOT_FOUND:
1921			return (ENOENT);
1922
1923		case SCF_ERROR_HANDLE_MISMATCH:
1924		case SCF_ERROR_NOT_BOUND:
1925		case SCF_ERROR_PERMISSION_DENIED:
1926		default:
1927			bad_error("scf_property_get_value", scf_error());
1928		}
1929	}
1930
1931	if (scf_value_get_astring(val, buf, sizeof (buf)) < 0) {
1932		if (scf_error() != SCF_ERROR_TYPE_MISMATCH)
1933			bad_error("scf_value_get_astring", scf_error());
1934
1935		return (EINVAL);
1936	}
1937
1938	if (buf[0] == '\0' || buf[1] != '\0')
1939		return (EINVAL);
1940
1941	*rlp = buf[0];
1942
1943	return (0);
1944}
1945
1946/*
1947 * Delete the "runlevel" property from the given property group.  Also set the
1948 * "milestone" property to the given string.  Fails with ECONNABORTED,
1949 * ECANCELED, EPERM, EACCES, or EROFS.
1950 */
1951int
1952libscf_clear_runlevel(scf_propertygroup_t *pg, const char *milestone)
1953{
1954	scf_handle_t *h;
1955	scf_transaction_t *tx;
1956	scf_transaction_entry_t *e_rl, *e_ms;
1957	scf_value_t *val;
1958	scf_error_t serr;
1959	boolean_t isempty = B_TRUE;
1960	int ret = 0, r;
1961
1962	h = scf_pg_handle(pg);
1963	tx = safe_scf_transaction_create(h);
1964	e_rl = safe_scf_entry_create(h);
1965	e_ms = safe_scf_entry_create(h);
1966	val = safe_scf_value_create(h);
1967
1968	if (milestone) {
1969		r = scf_value_set_astring(val, milestone);
1970		assert(r == 0);
1971	}
1972
1973	for (;;) {
1974		if (scf_transaction_start(tx, pg) != 0) {
1975			switch (scf_error()) {
1976			case SCF_ERROR_CONNECTION_BROKEN:
1977			default:
1978				ret = ECONNABORTED;
1979				goto out;
1980
1981			case SCF_ERROR_DELETED:
1982				ret = ECANCELED;
1983				goto out;
1984
1985			case SCF_ERROR_PERMISSION_DENIED:
1986				ret = EPERM;
1987				goto out;
1988
1989			case SCF_ERROR_BACKEND_ACCESS:
1990				ret = EACCES;
1991				goto out;
1992
1993			case SCF_ERROR_BACKEND_READONLY:
1994				ret = EROFS;
1995				goto out;
1996
1997			case SCF_ERROR_NOT_SET:
1998				bad_error("scf_transaction_start", scf_error());
1999			}
2000		}
2001
2002		if (scf_transaction_property_delete(tx, e_rl,
2003		    "runlevel") == 0) {
2004			isempty = B_FALSE;
2005		} else {
2006			switch (scf_error()) {
2007			case SCF_ERROR_CONNECTION_BROKEN:
2008			default:
2009				ret = ECONNABORTED;
2010				goto out;
2011
2012			case SCF_ERROR_DELETED:
2013				ret = ECANCELED;
2014				goto out;
2015
2016			case SCF_ERROR_NOT_FOUND:
2017				break;
2018
2019			case SCF_ERROR_HANDLE_MISMATCH:
2020			case SCF_ERROR_NOT_BOUND:
2021			case SCF_ERROR_INVALID_ARGUMENT:
2022				bad_error("scf_transaction_property_delete",
2023				    scf_error());
2024			}
2025		}
2026
2027		if (milestone) {
2028			ret = transaction_add_set(tx, e_ms,
2029			    SCF_PROPERTY_MILESTONE, SCF_TYPE_ASTRING);
2030			switch (ret) {
2031			case 0:
2032				break;
2033
2034			case ECONNABORTED:
2035			case ECANCELED:
2036				goto out;
2037
2038			default:
2039				bad_error("transaction_add_set", ret);
2040			}
2041
2042			isempty = B_FALSE;
2043
2044			r = scf_entry_add_value(e_ms, val);
2045			assert(r == 0);
2046		}
2047
2048		if (isempty)
2049			goto out;
2050
2051		r = scf_transaction_commit(tx);
2052		if (r == 1)
2053			break;
2054		if (r != 0) {
2055			serr = scf_error();
2056			scf_transaction_reset(tx);
2057			switch (serr) {
2058			case SCF_ERROR_CONNECTION_BROKEN:
2059				ret = ECONNABORTED;
2060				goto out;
2061
2062			case SCF_ERROR_PERMISSION_DENIED:
2063				ret = EPERM;
2064				goto out;
2065
2066			case SCF_ERROR_BACKEND_ACCESS:
2067				ret = EACCES;
2068				goto out;
2069
2070			case SCF_ERROR_BACKEND_READONLY:
2071				ret = EROFS;
2072				goto out;
2073
2074			default:
2075				bad_error("scf_transaction_commit", serr);
2076			}
2077		}
2078
2079		scf_transaction_reset(tx);
2080
2081		if (scf_pg_update(pg) == -1) {
2082			switch (scf_error()) {
2083			case SCF_ERROR_CONNECTION_BROKEN:
2084				ret = ECONNABORTED;
2085				goto out;
2086
2087			case SCF_ERROR_NOT_SET:
2088				ret = ECANCELED;
2089				goto out;
2090
2091			default:
2092				assert(0);
2093				abort();
2094			}
2095		}
2096	}
2097
2098out:
2099	scf_transaction_destroy(tx);
2100	scf_entry_destroy(e_rl);
2101	scf_entry_destroy(e_ms);
2102	scf_value_destroy(val);
2103	return (ret);
2104}
2105
2106/*
2107 * int libscf_get_template_values(scf_instance_t *, scf_snapshot_t *,
2108 *	char **)
2109 *
2110 *   Return template values for inst in *common_name suitable for use in
2111 *   restarter_inst_t->ri_common_name.  Called by restarter_insert_inst().
2112 *
2113 *   Returns 0 on success, ECANCELED if the instance is deleted, ECHILD if
2114 *   a value fetch failed for a property, ENOENT if the instance has no
2115 *   tm_common_name property group or the property group is deleted, and
2116 *   ECONNABORTED if the repository connection is broken.
2117 */
2118int
2119libscf_get_template_values(scf_instance_t *inst, scf_snapshot_t *snap,
2120    char **common_name, char **c_common_name)
2121{
2122	scf_handle_t *h;
2123	scf_propertygroup_t *pg = NULL;
2124	scf_property_t *prop = NULL;
2125	int ret = 0, r;
2126	char *cname = startd_alloc(max_scf_value_size);
2127	char *c_cname = startd_alloc(max_scf_value_size);
2128	int common_name_initialized = B_FALSE;
2129	int c_common_name_initialized = B_FALSE;
2130
2131	h = scf_instance_handle(inst);
2132	pg = safe_scf_pg_create(h);
2133	prop = safe_scf_property_create(h);
2134
2135	/*
2136	 * The tm_common_name property group, as with all template property
2137	 * groups, is optional.
2138	 */
2139	if (scf_instance_get_pg_composed(inst, snap, SCF_PG_TM_COMMON_NAME, pg)
2140	    == -1) {
2141		switch (scf_error()) {
2142		case SCF_ERROR_DELETED:
2143			ret = ECANCELED;
2144			goto template_values_out;
2145
2146		case SCF_ERROR_NOT_FOUND:
2147			goto template_values_out;
2148
2149		case SCF_ERROR_CONNECTION_BROKEN:
2150		default:
2151			ret = ECONNABORTED;
2152			goto template_values_out;
2153
2154		case SCF_ERROR_INVALID_ARGUMENT:
2155		case SCF_ERROR_HANDLE_MISMATCH:
2156		case SCF_ERROR_NOT_SET:
2157			bad_error("scf_instance_get_pg_composed", scf_error());
2158		}
2159	}
2160
2161	/*
2162	 * The name we wish uses the current locale name as the property name.
2163	 */
2164	if (st->st_locale != NULL) {
2165		if (scf_pg_get_property(pg, st->st_locale, prop) == -1) {
2166			switch (scf_error()) {
2167			case SCF_ERROR_DELETED:
2168			case SCF_ERROR_NOT_FOUND:
2169				break;
2170
2171			case SCF_ERROR_CONNECTION_BROKEN:
2172			default:
2173				ret = ECONNABORTED;
2174				goto template_values_out;
2175
2176			case SCF_ERROR_INVALID_ARGUMENT:
2177			case SCF_ERROR_HANDLE_MISMATCH:
2178			case SCF_ERROR_NOT_SET:
2179				bad_error("scf_pg_get_property", scf_error());
2180			}
2181		} else {
2182			if ((r = libscf_read_single_astring(h, prop, &cname)) !=
2183			    0) {
2184				if (r != LIBSCF_PROPERTY_ABSENT)
2185					ret = ECHILD;
2186				goto template_values_out;
2187			}
2188
2189			*common_name = cname;
2190			common_name_initialized = B_TRUE;
2191		}
2192	}
2193
2194	/*
2195	 * Also pull out the C locale name, as a fallback for the case where
2196	 * service offers no localized name.
2197	 */
2198	if (scf_pg_get_property(pg, "C", prop) == -1) {
2199		switch (scf_error()) {
2200		case SCF_ERROR_DELETED:
2201			ret = ENOENT;
2202			goto template_values_out;
2203
2204		case SCF_ERROR_NOT_FOUND:
2205			break;
2206
2207		case SCF_ERROR_CONNECTION_BROKEN:
2208		default:
2209			ret = ECONNABORTED;
2210			goto template_values_out;
2211
2212		case SCF_ERROR_INVALID_ARGUMENT:
2213		case SCF_ERROR_HANDLE_MISMATCH:
2214		case SCF_ERROR_NOT_SET:
2215			bad_error("scf_pg_get_property", scf_error());
2216		}
2217	} else {
2218		if ((r = libscf_read_single_astring(h, prop, &c_cname)) != 0) {
2219			if (r != LIBSCF_PROPERTY_ABSENT)
2220				ret = ECHILD;
2221			goto template_values_out;
2222		}
2223
2224		*c_common_name = c_cname;
2225		c_common_name_initialized = B_TRUE;
2226	}
2227
2228
2229template_values_out:
2230	if (common_name_initialized == B_FALSE)
2231		startd_free(cname, max_scf_value_size);
2232	if (c_common_name_initialized == B_FALSE)
2233		startd_free(c_cname, max_scf_value_size);
2234	scf_property_destroy(prop);
2235	scf_pg_destroy(pg);
2236
2237	return (ret);
2238}
2239
2240/*
2241 * int libscf_get_startd_properties(scf_handle_t *, scf_instance_t *,
2242 *	scf_snapshot_t *, uint_t *, char **)
2243 *
2244 *   Return startd settings for inst in *flags suitable for use in
2245 *   restarter_inst_t->ri_flags.  Called by restarter_insert_inst().
2246 *
2247 *   Returns 0 on success, ECANCELED if the instance is deleted, ECHILD if
2248 *   a value fetch failed for a property, ENOENT if the instance has no
2249 *   general property group or the property group is deleted, and
2250 *   ECONNABORTED if the repository connection is broken.
2251 */
2252int
2253libscf_get_startd_properties(scf_instance_t *inst,
2254    scf_snapshot_t *snap, uint_t *flags, char **prefixp)
2255{
2256	scf_handle_t *h;
2257	scf_propertygroup_t *pg = NULL;
2258	scf_property_t *prop = NULL;
2259	int style = RINST_CONTRACT;
2260	char *style_str = startd_alloc(max_scf_value_size);
2261	int ret = 0, r;
2262
2263	h = scf_instance_handle(inst);
2264	pg = safe_scf_pg_create(h);
2265	prop = safe_scf_property_create(h);
2266
2267	/*
2268	 * The startd property group is optional.
2269	 */
2270	if (scf_instance_get_pg_composed(inst, snap, SCF_PG_STARTD, pg) == -1) {
2271		switch (scf_error()) {
2272		case SCF_ERROR_DELETED:
2273			ret = ECANCELED;
2274			goto instance_flags_out;
2275
2276		case SCF_ERROR_NOT_FOUND:
2277			ret = ENOENT;
2278			goto instance_flags_out;
2279
2280		case SCF_ERROR_CONNECTION_BROKEN:
2281		default:
2282			ret = ECONNABORTED;
2283			goto instance_flags_out;
2284
2285		case SCF_ERROR_INVALID_ARGUMENT:
2286		case SCF_ERROR_HANDLE_MISMATCH:
2287		case SCF_ERROR_NOT_SET:
2288			bad_error("scf_instance_get_pg_composed", scf_error());
2289		}
2290	}
2291
2292	/*
2293	 * 1.  Duration property.
2294	 */
2295	if (scf_pg_get_property(pg, SCF_PROPERTY_DURATION, prop) == -1) {
2296		switch (scf_error()) {
2297		case SCF_ERROR_DELETED:
2298			ret = ENOENT;
2299			goto instance_flags_out;
2300
2301		case SCF_ERROR_NOT_FOUND:
2302			break;
2303
2304		case SCF_ERROR_CONNECTION_BROKEN:
2305		default:
2306			ret = ECONNABORTED;
2307			goto instance_flags_out;
2308
2309		case SCF_ERROR_INVALID_ARGUMENT:
2310		case SCF_ERROR_HANDLE_MISMATCH:
2311		case SCF_ERROR_NOT_SET:
2312			bad_error("scf_pg_get_property", scf_error());
2313		}
2314	} else {
2315		errno = 0;
2316		if ((r = libscf_read_single_astring(h, prop, &style_str))
2317		    != 0) {
2318			if (r != LIBSCF_PROPERTY_ABSENT)
2319				ret = ECHILD;
2320			goto instance_flags_out;
2321		}
2322
2323		if (strcmp(style_str, "child") == 0)
2324			style = RINST_WAIT;
2325		else if (strcmp(style_str, "transient") == 0)
2326			style = RINST_TRANSIENT;
2327	}
2328
2329	/*
2330	 * 2.  utmpx prefix property.
2331	 */
2332	if (scf_pg_get_property(pg, SCF_PROPERTY_UTMPX_PREFIX, prop) == 0) {
2333		errno = 0;
2334		if ((r = libscf_read_single_astring(h, prop, prefixp)) != 0) {
2335			if (r != LIBSCF_PROPERTY_ABSENT)
2336				ret = ECHILD;
2337			goto instance_flags_out;
2338		}
2339	} else {
2340		switch (scf_error()) {
2341		case SCF_ERROR_DELETED:
2342			ret = ENOENT;
2343			goto instance_flags_out;
2344
2345		case SCF_ERROR_NOT_FOUND:
2346			goto instance_flags_out;
2347
2348		case SCF_ERROR_CONNECTION_BROKEN:
2349		default:
2350			ret = ECONNABORTED;
2351			goto instance_flags_out;
2352
2353		case SCF_ERROR_INVALID_ARGUMENT:
2354		case SCF_ERROR_HANDLE_MISMATCH:
2355		case SCF_ERROR_NOT_SET:
2356			bad_error("scf_pg_get_property", scf_error());
2357		}
2358	}
2359
2360instance_flags_out:
2361	startd_free(style_str, max_scf_value_size);
2362	*flags = (*flags & ~RINST_STYLE_MASK) | style;
2363
2364	scf_property_destroy(prop);
2365	scf_pg_destroy(pg);
2366
2367	return (ret);
2368}
2369
2370/*
2371 * int libscf_read_method_ids(scf_handle_t *, scf_instance_t *, ctid_t *,
2372 *   ctid_t *, pid_t *)
2373 *
2374 *  Sets given id_t variables to primary and transient contract IDs and start
2375 *  PID.  Returns 0, ECONNABORTED, and ECANCELED.
2376 */
2377int
2378libscf_read_method_ids(scf_handle_t *h, scf_instance_t *inst, const char *fmri,
2379    ctid_t *primary, ctid_t *transient, pid_t *start_pid)
2380{
2381	scf_propertygroup_t *pg = NULL;
2382	scf_property_t *prop = NULL;
2383	scf_value_t *val = NULL;
2384	uint64_t p, t;
2385	int ret = 0;
2386
2387	*primary = 0;
2388	*transient = 0;
2389	*start_pid = -1;
2390
2391	pg = safe_scf_pg_create(h);
2392	prop = safe_scf_property_create(h);
2393	val = safe_scf_value_create(h);
2394
2395	if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) == -1) {
2396		switch (scf_error()) {
2397		case SCF_ERROR_CONNECTION_BROKEN:
2398		default:
2399			ret = ECONNABORTED;
2400			goto read_id_err;
2401
2402		case SCF_ERROR_DELETED:
2403			ret = ECANCELED;
2404			goto read_id_err;
2405
2406		case SCF_ERROR_NOT_FOUND:
2407			goto read_id_err;
2408
2409		case SCF_ERROR_NOT_SET:
2410			bad_error("scf_instance_get_pg", scf_error());
2411		}
2412	}
2413
2414	ret = get_count(pg, SCF_PROPERTY_CONTRACT, &p);
2415	switch (ret) {
2416	case 0:
2417		break;
2418
2419	case EINVAL:
2420		log_error(LOG_NOTICE,
2421		    "%s: Ignoring %s/%s: multivalued or not of type count\n",
2422		    fmri, SCF_PG_RESTARTER, SCF_PROPERTY_CONTRACT);
2423		/* FALLTHROUGH */
2424	case ENOENT:
2425		ret = 0;
2426		goto read_trans;
2427
2428	case ECONNABORTED:
2429	case ECANCELED:
2430		goto read_id_err;
2431
2432	case EACCES:
2433	default:
2434		bad_error("get_count", ret);
2435	}
2436
2437	*primary = p;
2438
2439read_trans:
2440	ret = get_count(pg, SCF_PROPERTY_TRANSIENT_CONTRACT, &t);
2441	switch (ret) {
2442	case 0:
2443		break;
2444
2445	case EINVAL:
2446		log_error(LOG_NOTICE,
2447		    "%s: Ignoring %s/%s: multivalued or not of type count\n",
2448		    fmri, SCF_PG_RESTARTER, SCF_PROPERTY_TRANSIENT_CONTRACT);
2449		/* FALLTHROUGH */
2450
2451	case ENOENT:
2452		ret = 0;
2453		goto read_pid_only;
2454
2455	case ECONNABORTED:
2456	case ECANCELED:
2457		goto read_id_err;
2458
2459	case EACCES:
2460	default:
2461		bad_error("get_count", ret);
2462	}
2463
2464	*transient = t;
2465
2466read_pid_only:
2467	ret = get_count(pg, SCF_PROPERTY_START_PID, &p);
2468	switch (ret) {
2469	case 0:
2470		break;
2471
2472	case EINVAL:
2473		log_error(LOG_NOTICE,
2474		    "%s: Ignoring %s/%s: multivalued or not of type count\n",
2475		    fmri, SCF_PG_RESTARTER, SCF_PROPERTY_START_PID);
2476		/* FALLTHROUGH */
2477	case ENOENT:
2478		ret = 0;
2479		goto read_id_err;
2480
2481	case ECONNABORTED:
2482	case ECANCELED:
2483		goto read_id_err;
2484
2485	case EACCES:
2486	default:
2487		bad_error("get_count", ret);
2488	}
2489
2490	*start_pid = p;
2491
2492read_id_err:
2493	scf_value_destroy(val);
2494	scf_property_destroy(prop);
2495	scf_pg_destroy(pg);
2496	return (ret);
2497}
2498
2499/*
2500 * Returns with
2501 *   0 - success
2502 *   ECONNABORTED - repository connection broken
2503 *		  - unknown libscf error
2504 *   ECANCELED - s_inst was deleted
2505 *   EPERM
2506 *   EACCES
2507 *   EROFS
2508 */
2509int
2510libscf_write_start_pid(scf_instance_t *s_inst, pid_t pid)
2511{
2512	scf_handle_t *h;
2513	scf_transaction_entry_t *t_pid;
2514	scf_value_t *v_pid;
2515	scf_propertygroup_t *pg;
2516	int ret = 0;
2517
2518	h = scf_instance_handle(s_inst);
2519
2520	pg = safe_scf_pg_create(h);
2521	t_pid = safe_scf_entry_create(h);
2522	v_pid = safe_scf_value_create(h);
2523
2524get_pg:
2525	ret = libscf_inst_get_or_add_pg(s_inst, SCF_PG_RESTARTER,
2526	    SCF_PG_RESTARTER_TYPE, SCF_PG_RESTARTER_FLAGS, pg);
2527	switch (ret) {
2528	case 0:
2529		break;
2530
2531	case ECONNABORTED:
2532	case ECANCELED:
2533	case EPERM:
2534	case EACCES:
2535	case EROFS:
2536		goto write_start_err;
2537
2538	default:
2539		bad_error("libscf_inst_get_or_add_pg", ret);
2540	}
2541
2542	scf_value_set_count(v_pid, pid);
2543
2544	ret = pg_set_prop_value(pg, SCF_PROPERTY_START_PID, v_pid);
2545	switch (ret) {
2546	case 0:
2547	case ECONNABORTED:
2548	case EPERM:
2549	case EACCES:
2550	case EROFS:
2551		break;
2552
2553	case ECANCELED:
2554		goto get_pg;
2555
2556	default:
2557		bad_error("pg_set_prop_value", ret);
2558	}
2559
2560write_start_err:
2561	scf_entry_destroy(t_pid);
2562	scf_value_destroy(v_pid);
2563	scf_pg_destroy(pg);
2564
2565	return (ret);
2566}
2567
2568/*
2569 * Add a property indicating the instance log file.  If the dir is
2570 * equal to LOG_PREFIX_EARLY, then the property restarter/alt_logfile
2571 * of the instance is used; otherwise, restarter/logfile is used.
2572 *
2573 * Returns
2574 *   0 - success
2575 *   ECONNABORTED
2576 *   ECANCELED
2577 *   EPERM
2578 *   EACCES
2579 *   EROFS
2580 *   EAGAIN
2581 */
2582int
2583libscf_note_method_log(scf_instance_t *inst, const char *dir, const char *file)
2584{
2585	scf_handle_t *h;
2586	scf_value_t *v;
2587	scf_propertygroup_t *pg;
2588	int ret = 0;
2589	char *logname;
2590	const char *propname;
2591
2592	h = scf_instance_handle(inst);
2593	pg = safe_scf_pg_create(h);
2594	v = safe_scf_value_create(h);
2595
2596	logname = uu_msprintf("%s%s", dir, file);
2597
2598	if (logname == NULL) {
2599		ret = errno;
2600		goto out;
2601	}
2602
2603	ret = libscf_inst_get_or_add_pg(inst, SCF_PG_RESTARTER,
2604	    SCF_PG_RESTARTER_TYPE, SCF_PG_RESTARTER_FLAGS, pg);
2605	switch (ret) {
2606	case 0:
2607		break;
2608
2609	case ECONNABORTED:
2610	case ECANCELED:
2611	case EPERM:
2612	case EACCES:
2613	case EROFS:
2614		goto out;
2615
2616	default:
2617		bad_error("libscf_inst_get_or_add_pg", ret);
2618	}
2619
2620	(void) scf_value_set_astring(v, logname);
2621
2622	if (strcmp(LOG_PREFIX_EARLY, dir) == 0)
2623		propname = SCF_PROPERTY_ALT_LOGFILE;
2624	else
2625		propname = SCF_PROPERTY_LOGFILE;
2626
2627	ret = pg_set_prop_value(pg, propname, v);
2628	switch (ret) {
2629	case 0:
2630	case ECONNABORTED:
2631	case ECANCELED:
2632	case EPERM:
2633	case EACCES:
2634	case EROFS:
2635		break;
2636
2637	default:
2638		bad_error("pg_set_prop_value", ret);
2639	}
2640
2641out:
2642	scf_pg_destroy(pg);
2643	scf_value_destroy(v);
2644	uu_free(logname);
2645	return (ret);
2646}
2647
2648/*
2649 * Returns
2650 *   0 - success
2651 *   ENAMETOOLONG - name is too long
2652 *   ECONNABORTED
2653 *   ECANCELED
2654 *   EPERM
2655 *   EACCES
2656 *   EROFS
2657 */
2658int
2659libscf_write_method_status(scf_instance_t *s_inst, const char *name,
2660    int status)
2661{
2662	scf_handle_t *h;
2663	scf_transaction_t *tx;
2664	scf_transaction_entry_t *e_time, *e_stat;
2665	scf_value_t *v_time, *v_stat;
2666	scf_propertygroup_t *pg;
2667	int ret = 0, r;
2668	char pname[30];
2669	struct timeval tv;
2670	scf_error_t scfe;
2671
2672	if (strlen(name) + sizeof ("_method_waitstatus") > sizeof (pname))
2673		return (ENAMETOOLONG);
2674
2675	h = scf_instance_handle(s_inst);
2676
2677	pg = safe_scf_pg_create(h);
2678	tx = safe_scf_transaction_create(h);
2679	e_time = safe_scf_entry_create(h);
2680	v_time = safe_scf_value_create(h);
2681	e_stat = safe_scf_entry_create(h);
2682	v_stat = safe_scf_value_create(h);
2683
2684get_pg:
2685	ret = libscf_inst_get_or_add_pg(s_inst, SCF_PG_RESTARTER,
2686	    SCF_PG_RESTARTER_TYPE, SCF_PG_RESTARTER_FLAGS, pg);
2687	switch (ret) {
2688	case 0:
2689		break;
2690
2691	case ECONNABORTED:
2692	case ECANCELED:
2693	case EPERM:
2694	case EACCES:
2695	case EROFS:
2696		goto out;
2697
2698	default:
2699		bad_error("libscf_inst_get_or_add_pg", ret);
2700	}
2701
2702	(void) gettimeofday(&tv, NULL);
2703
2704	r = scf_value_set_time(v_time, tv.tv_sec, tv.tv_usec * 1000);
2705	assert(r == 0);
2706
2707	scf_value_set_integer(v_stat, status);
2708
2709	for (;;) {
2710		if (scf_transaction_start(tx, pg) != 0) {
2711			switch (scf_error()) {
2712			case SCF_ERROR_CONNECTION_BROKEN:
2713			default:
2714				ret = ECONNABORTED;
2715				goto out;
2716
2717			case SCF_ERROR_DELETED:
2718				ret = ECANCELED;
2719				goto out;
2720
2721			case SCF_ERROR_PERMISSION_DENIED:
2722				ret = EPERM;
2723				goto out;
2724
2725			case SCF_ERROR_BACKEND_ACCESS:
2726				ret = EACCES;
2727				goto out;
2728
2729			case SCF_ERROR_BACKEND_READONLY:
2730				ret = EROFS;
2731				goto out;
2732
2733			case SCF_ERROR_NOT_SET:
2734				bad_error("scf_transaction_start", ret);
2735			}
2736		}
2737
2738		(void) snprintf(pname, sizeof (pname), "%s_method_timestamp",
2739		    name);
2740		ret = transaction_add_set(tx, e_time, pname, SCF_TYPE_TIME);
2741		switch (ret) {
2742		case 0:
2743			break;
2744
2745		case ECONNABORTED:
2746		case ECANCELED:
2747			goto out;
2748
2749		default:
2750			bad_error("transaction_add_set", ret);
2751		}
2752
2753		r = scf_entry_add_value(e_time, v_time);
2754		assert(r == 0);
2755
2756		(void) snprintf(pname, sizeof (pname), "%s_method_waitstatus",
2757		    name);
2758		ret = transaction_add_set(tx, e_stat, pname, SCF_TYPE_INTEGER);
2759		switch (ret) {
2760		case 0:
2761			break;
2762
2763		case ECONNABORTED:
2764		case ECANCELED:
2765			goto out;
2766
2767		default:
2768			bad_error("transaction_add_set", ret);
2769		}
2770
2771		r = scf_entry_add_value(e_stat, v_stat);
2772		if (r != 0)
2773			bad_error("scf_entry_add_value", scf_error());
2774
2775		r = scf_transaction_commit(tx);
2776		if (r == 1)
2777			break;
2778		if (r != 0) {
2779			scfe = scf_error();
2780			scf_transaction_reset_all(tx);
2781			switch (scfe) {
2782			case SCF_ERROR_CONNECTION_BROKEN:
2783			default:
2784				ret = ECONNABORTED;
2785				goto out;
2786
2787			case SCF_ERROR_DELETED:
2788				ret = ECANCELED;
2789				goto out;
2790
2791			case SCF_ERROR_PERMISSION_DENIED:
2792				ret = EPERM;
2793				goto out;
2794
2795			case SCF_ERROR_BACKEND_ACCESS:
2796				ret = EACCES;
2797				goto out;
2798
2799			case SCF_ERROR_BACKEND_READONLY:
2800				ret = EROFS;
2801				goto out;
2802
2803			case SCF_ERROR_NOT_SET:
2804				bad_error("scf_transaction_commit", scfe);
2805			}
2806		}
2807
2808		scf_transaction_reset_all(tx);
2809
2810		if (scf_pg_update(pg) == -1) {
2811			switch (scf_error()) {
2812			case SCF_ERROR_CONNECTION_BROKEN:
2813			default:
2814				ret = ECONNABORTED;
2815				goto out;
2816
2817			case SCF_ERROR_DELETED:
2818				ret = ECANCELED;
2819				goto out;
2820
2821			case SCF_ERROR_NOT_SET:
2822				bad_error("scf_pg_update", scf_error());
2823			}
2824		}
2825	}
2826
2827out:
2828	scf_transaction_destroy(tx);
2829	scf_entry_destroy(e_time);
2830	scf_value_destroy(v_time);
2831	scf_entry_destroy(e_stat);
2832	scf_value_destroy(v_stat);
2833	scf_pg_destroy(pg);
2834
2835	return (ret);
2836}
2837
2838/*
2839 * Call dgraph_add_instance() for each instance in the repository.
2840 */
2841void
2842libscf_populate_graph(scf_handle_t *h)
2843{
2844	scf_scope_t *scope;
2845	scf_service_t *svc;
2846	scf_instance_t *inst;
2847	scf_iter_t *svc_iter;
2848	scf_iter_t *inst_iter;
2849	int ret;
2850
2851	scope = safe_scf_scope_create(h);
2852	svc = safe_scf_service_create(h);
2853	inst = safe_scf_instance_create(h);
2854	svc_iter = safe_scf_iter_create(h);
2855	inst_iter = safe_scf_iter_create(h);
2856
2857	deathrow_init();
2858
2859	if ((ret = scf_handle_get_local_scope(h, scope)) !=
2860	    SCF_SUCCESS)
2861		uu_die("retrieving local scope failed: %d\n", ret);
2862
2863	if (scf_iter_scope_services(svc_iter, scope) == -1)
2864		uu_die("walking local scope's services failed\n");
2865
2866	while (scf_iter_next_service(svc_iter, svc) > 0) {
2867		if (scf_iter_service_instances(inst_iter, svc) == -1)
2868			uu_die("unable to walk service's instances");
2869
2870		while (scf_iter_next_instance(inst_iter, inst) > 0) {
2871			char *fmri;
2872
2873			if (libscf_instance_get_fmri(inst, &fmri) == 0) {
2874				int err;
2875
2876				err = dgraph_add_instance(fmri, inst, B_TRUE);
2877				if (err != 0 && err != EEXIST)
2878					log_error(LOG_WARNING,
2879					    "Failed to add %s (%s).\n", fmri,
2880					    strerror(err));
2881				startd_free(fmri, max_scf_fmri_size);
2882			}
2883		}
2884	}
2885
2886	deathrow_fini();
2887
2888	scf_iter_destroy(inst_iter);
2889	scf_iter_destroy(svc_iter);
2890	scf_instance_destroy(inst);
2891	scf_service_destroy(svc);
2892	scf_scope_destroy(scope);
2893}
2894
2895/*
2896 * Monitors get handled differently since there can be multiple of them.
2897 *
2898 * Returns exec string on success.  If method not defined, returns
2899 * LIBSCF_PGROUP_ABSENT; if exec property missing, returns
2900 * LIBSCF_PROPERTY_ABSENT.  Returns LIBSCF_PROPERTY_ERROR on other failures.
2901 */
2902char *
2903libscf_get_method(scf_handle_t *h, int type, restarter_inst_t *inst,
2904    scf_snapshot_t *snap, method_restart_t *restart_on, uint_t *cte_mask,
2905    uint8_t *need_sessionp, uint64_t *timeout, uint8_t *timeout_retry)
2906{
2907	scf_instance_t *scf_inst = NULL;
2908	scf_propertygroup_t *pg = NULL, *pg_startd = NULL;
2909	scf_property_t *prop = NULL;
2910	const char *name;
2911	char *method = startd_alloc(max_scf_value_size);
2912	char *ig = startd_alloc(max_scf_value_size);
2913	char *restart = startd_alloc(max_scf_value_size);
2914	char *ret;
2915	int error = 0, r;
2916
2917	scf_inst = safe_scf_instance_create(h);
2918	pg = safe_scf_pg_create(h);
2919	pg_startd = safe_scf_pg_create(h);
2920	prop = safe_scf_property_create(h);
2921
2922	ret = NULL;
2923
2924	*restart_on = METHOD_RESTART_UNKNOWN;
2925
2926	switch (type) {
2927	case METHOD_START:
2928		name = "start";
2929		break;
2930	case METHOD_STOP:
2931		name = "stop";
2932		break;
2933	case METHOD_REFRESH:
2934		name = "refresh";
2935		break;
2936	default:
2937		error = LIBSCF_PROPERTY_ERROR;
2938		goto get_method_cleanup;
2939	}
2940
2941	if (scf_handle_decode_fmri(h, inst->ri_i.i_fmri, NULL, NULL, scf_inst,
2942	    NULL, NULL, SCF_DECODE_FMRI_EXACT) == -1) {
2943		log_error(LOG_WARNING,
2944		    "%s: get_method decode instance FMRI failed: %s\n",
2945		    inst->ri_i.i_fmri, scf_strerror(scf_error()));
2946		error = LIBSCF_PROPERTY_ERROR;
2947		goto get_method_cleanup;
2948	}
2949
2950	if (scf_instance_get_pg_composed(scf_inst, snap, name, pg) == -1) {
2951		if (scf_error() == SCF_ERROR_NOT_FOUND)
2952			error = LIBSCF_PGROUP_ABSENT;
2953		else
2954			error = LIBSCF_PROPERTY_ERROR;
2955		goto get_method_cleanup;
2956	}
2957
2958	if (scf_pg_get_property(pg, SCF_PROPERTY_EXEC, prop) == -1) {
2959		if (scf_error() == SCF_ERROR_NOT_FOUND)
2960			error = LIBSCF_PROPERTY_ABSENT;
2961		else
2962			error = LIBSCF_PROPERTY_ERROR;
2963		goto get_method_cleanup;
2964	}
2965
2966	error = libscf_read_single_astring(h, prop, &method);
2967	if (error != 0) {
2968		log_error(LOG_WARNING,
2969		    "%s: get_method failed: can't get a single astring "
2970		    "from %s/%s\n", inst->ri_i.i_fmri, name, SCF_PROPERTY_EXEC);
2971		goto get_method_cleanup;
2972	}
2973
2974	error = expand_method_tokens(method, scf_inst, snap, type, &ret);
2975	if (error != 0) {
2976		log_instance(inst, B_TRUE, "Could not expand method tokens "
2977		    "in \"%s\": %s.", method, ret);
2978		error = LIBSCF_PROPERTY_ERROR;
2979		goto get_method_cleanup;
2980	}
2981
2982	r = get_count(pg, SCF_PROPERTY_TIMEOUT, timeout);
2983	switch (r) {
2984	case 0:
2985		break;
2986
2987	case ECONNABORTED:
2988		error = LIBSCF_PROPERTY_ERROR;
2989		goto get_method_cleanup;
2990
2991	case EINVAL:
2992		log_instance(inst, B_TRUE, "%s/%s is multi-valued or not of "
2993		    "type count.  Using infinite timeout.", name,
2994		    SCF_PROPERTY_TIMEOUT);
2995		/* FALLTHROUGH */
2996	case ECANCELED:
2997	case ENOENT:
2998		*timeout = METHOD_TIMEOUT_INFINITE;
2999		break;
3000
3001	case EACCES:
3002	default:
3003		bad_error("get_count", r);
3004	}
3005
3006	/* Both 0 and -1 (ugh) are considered infinite timeouts. */
3007	if (*timeout == -1 || *timeout == 0)
3008		*timeout = METHOD_TIMEOUT_INFINITE;
3009
3010	if (scf_instance_get_pg_composed(scf_inst, snap, SCF_PG_STARTD,
3011	    pg_startd) == -1) {
3012		switch (scf_error()) {
3013		case SCF_ERROR_CONNECTION_BROKEN:
3014		case SCF_ERROR_DELETED:
3015			error = LIBSCF_PROPERTY_ERROR;
3016			goto get_method_cleanup;
3017
3018		case SCF_ERROR_NOT_FOUND:
3019			*cte_mask = 0;
3020			break;
3021
3022		case SCF_ERROR_INVALID_ARGUMENT:
3023		case SCF_ERROR_HANDLE_MISMATCH:
3024		case SCF_ERROR_NOT_BOUND:
3025		case SCF_ERROR_NOT_SET:
3026			bad_error("scf_instance_get_pg_composed", scf_error());
3027		}
3028	} else {
3029		if (scf_pg_get_property(pg_startd, SCF_PROPERTY_IGNORE,
3030		    prop) == -1) {
3031			if (scf_error() == SCF_ERROR_NOT_FOUND)
3032				*cte_mask = 0;
3033			else {
3034				error = LIBSCF_PROPERTY_ERROR;
3035				goto get_method_cleanup;
3036			}
3037		} else {
3038			error = libscf_read_single_astring(h, prop, &ig);
3039			if (error != 0) {
3040				log_error(LOG_WARNING,
3041				    "%s: get_method failed: can't get a single "
3042				    "astring from %s/%s\n", inst->ri_i.i_fmri,
3043				    name, SCF_PROPERTY_IGNORE);
3044				goto get_method_cleanup;
3045			}
3046
3047			if (strcmp(ig, "core") == 0)
3048				*cte_mask = CT_PR_EV_CORE;
3049			else if (strcmp(ig, "signal") == 0)
3050				*cte_mask = CT_PR_EV_SIGNAL;
3051			else if (strcmp(ig, "core,signal") == 0 ||
3052			    strcmp(ig, "signal,core") == 0)
3053				*cte_mask = CT_PR_EV_CORE | CT_PR_EV_SIGNAL;
3054			else
3055				*cte_mask = 0;
3056		}
3057
3058		r = get_boolean(pg_startd, SCF_PROPERTY_NEED_SESSION,
3059		    need_sessionp);
3060		switch (r) {
3061		case 0:
3062			break;
3063
3064		case ECONNABORTED:
3065			error = LIBSCF_PROPERTY_ERROR;
3066			goto get_method_cleanup;
3067
3068		case ECANCELED:
3069		case ENOENT:
3070		case EINVAL:
3071			*need_sessionp = 0;
3072			break;
3073
3074		case EACCES:
3075		default:
3076			bad_error("get_boolean", r);
3077		}
3078
3079		/*
3080		 * Determine whether service has overriden retry after
3081		 * method timeout.  Default to retry if no value is
3082		 * specified.
3083		 */
3084		r = get_boolean(pg_startd, SCF_PROPERTY_TIMEOUT_RETRY,
3085		    timeout_retry);
3086		switch (r) {
3087		case 0:
3088			break;
3089
3090		case ECONNABORTED:
3091			error = LIBSCF_PROPERTY_ERROR;
3092			goto get_method_cleanup;
3093
3094		case ECANCELED:
3095		case ENOENT:
3096		case EINVAL:
3097			*timeout_retry = 1;
3098			break;
3099
3100		case EACCES:
3101		default:
3102			bad_error("get_boolean", r);
3103		}
3104	}
3105
3106	if (type != METHOD_START)
3107		goto get_method_cleanup;
3108
3109	/* Only start methods need to honor the restart_on property. */
3110
3111	if (scf_pg_get_property(pg, SCF_PROPERTY_RESTART_ON, prop) == -1) {
3112		if (scf_error() == SCF_ERROR_NOT_FOUND)
3113			*restart_on = METHOD_RESTART_ALL;
3114		else
3115			error = LIBSCF_PROPERTY_ERROR;
3116		goto get_method_cleanup;
3117	}
3118
3119	error = libscf_read_single_astring(h, prop, &restart);
3120	if (error != 0) {
3121		log_error(LOG_WARNING,
3122		    "%s: get_method failed: can't get a single astring "
3123		    "from %s/%s\n", inst->ri_i.i_fmri, name,
3124		    SCF_PROPERTY_RESTART_ON);
3125		goto get_method_cleanup;
3126	}
3127
3128	if (strcmp(restart, "all") == 0)
3129		*restart_on = METHOD_RESTART_ALL;
3130	else if (strcmp(restart, "external_fault") == 0)
3131		*restart_on = METHOD_RESTART_EXTERNAL_FAULT;
3132	else if (strcmp(restart, "any_fault") == 0)
3133		*restart_on = METHOD_RESTART_ANY_FAULT;
3134
3135get_method_cleanup:
3136	startd_free(ig, max_scf_value_size);
3137	startd_free(method, max_scf_value_size);
3138	startd_free(restart, max_scf_value_size);
3139
3140	scf_instance_destroy(scf_inst);
3141	scf_pg_destroy(pg);
3142	scf_pg_destroy(pg_startd);
3143	scf_property_destroy(prop);
3144
3145	if (error != 0 && ret != NULL) {
3146		free(ret);
3147		ret = NULL;
3148	}
3149
3150	errno = error;
3151	return (ret);
3152}
3153
3154/*
3155 * Returns 1 if we've reached the fault threshold
3156 */
3157int
3158update_fault_count(restarter_inst_t *inst, int type)
3159{
3160	assert(type == FAULT_COUNT_INCR || type == FAULT_COUNT_RESET);
3161
3162	if (type == FAULT_COUNT_INCR) {
3163		inst->ri_i.i_fault_count++;
3164		log_framework(LOG_INFO, "%s: Increasing fault count to %d\n",
3165		    inst->ri_i.i_fmri, inst->ri_i.i_fault_count);
3166	}
3167	if (type == FAULT_COUNT_RESET)
3168		inst->ri_i.i_fault_count = 0;
3169
3170	if (inst->ri_i.i_fault_count >= FAULT_THRESHOLD)
3171		return (1);
3172
3173	return (0);
3174}
3175
3176/*
3177 * int libscf_unset_action()
3178 *   Delete any pending timestamps for the specified action which is
3179 *   older than the supplied ts.
3180 *
3181 *   Returns 0 on success, ECONNABORTED, EACCES, or EPERM on failure.
3182 */
3183int
3184libscf_unset_action(scf_handle_t *h, scf_propertygroup_t *pg,
3185    admin_action_t a, hrtime_t ts)
3186{
3187	scf_transaction_t *t;
3188	scf_transaction_entry_t *e;
3189	scf_property_t *prop;
3190	scf_value_t *val;
3191	hrtime_t rep_ts;
3192	int ret = 0, r;
3193
3194	t = safe_scf_transaction_create(h);
3195	e = safe_scf_entry_create(h);
3196	prop = safe_scf_property_create(h);
3197	val = safe_scf_value_create(h);
3198
3199	for (;;) {
3200		if (scf_pg_update(pg) == -1) {
3201			switch (scf_error()) {
3202			case SCF_ERROR_CONNECTION_BROKEN:
3203			default:
3204				ret = ECONNABORTED;
3205				goto unset_action_cleanup;
3206
3207			case SCF_ERROR_DELETED:
3208				goto unset_action_cleanup;
3209
3210			case SCF_ERROR_NOT_SET:
3211				assert(0);
3212				abort();
3213			}
3214		}
3215
3216		if (scf_transaction_start(t, pg) == -1) {
3217			switch (scf_error()) {
3218			case SCF_ERROR_CONNECTION_BROKEN:
3219			default:
3220				ret = ECONNABORTED;
3221				goto unset_action_cleanup;
3222
3223			case SCF_ERROR_DELETED:
3224				goto unset_action_cleanup;
3225
3226			case SCF_ERROR_PERMISSION_DENIED:
3227				ret = EPERM;
3228				goto unset_action_cleanup;
3229
3230			case SCF_ERROR_BACKEND_ACCESS:
3231			case SCF_ERROR_BACKEND_READONLY:
3232				ret = EACCES;
3233				goto unset_action_cleanup;
3234
3235			case SCF_ERROR_IN_USE:
3236			case SCF_ERROR_HANDLE_MISMATCH:
3237			case SCF_ERROR_NOT_SET:
3238				assert(0);
3239				abort();
3240			}
3241		}
3242
3243		/* Return failure only if the property hasn't been deleted. */
3244		if (scf_pg_get_property(pg, admin_actions[a], prop) == -1) {
3245			switch (scf_error()) {
3246			case SCF_ERROR_CONNECTION_BROKEN:
3247			default:
3248				ret = ECONNABORTED;
3249				goto unset_action_cleanup;
3250
3251			case SCF_ERROR_DELETED:
3252			case SCF_ERROR_NOT_FOUND:
3253				goto unset_action_cleanup;
3254
3255			case SCF_ERROR_HANDLE_MISMATCH:
3256			case SCF_ERROR_INVALID_ARGUMENT:
3257			case SCF_ERROR_NOT_SET:
3258				assert(0);
3259				abort();
3260			}
3261		}
3262
3263		if (scf_property_get_value(prop, val) == -1) {
3264			switch (scf_error()) {
3265			case SCF_ERROR_CONNECTION_BROKEN:
3266			default:
3267				ret = ECONNABORTED;
3268				goto unset_action_cleanup;
3269
3270			case SCF_ERROR_DELETED:
3271			case SCF_ERROR_NOT_FOUND:
3272				goto unset_action_cleanup;
3273
3274			case SCF_ERROR_CONSTRAINT_VIOLATED:
3275				/*
3276				 * More than one value was associated with
3277				 * this property -- this is incorrect. Take
3278				 * the opportunity to clean up and clear the
3279				 * entire property.
3280				 */
3281				rep_ts = ts;
3282				break;
3283
3284			case SCF_ERROR_PERMISSION_DENIED:
3285			case SCF_ERROR_NOT_SET:
3286				assert(0);
3287				abort();
3288			}
3289		} else if (scf_value_get_integer(val, &rep_ts) == -1) {
3290			assert(scf_error() == SCF_ERROR_TYPE_MISMATCH);
3291			rep_ts = 0;
3292		}
3293
3294		/* Repository ts is more current. Don't clear the action. */
3295		if (rep_ts > ts)
3296			goto unset_action_cleanup;
3297
3298		r = scf_transaction_property_change_type(t, e,
3299		    admin_actions[a], SCF_TYPE_INTEGER);
3300		assert(r == 0);
3301
3302		r = scf_transaction_commit(t);
3303		if (r == 1)
3304			break;
3305
3306		if (r != 0) {
3307			switch (scf_error()) {
3308			case SCF_ERROR_CONNECTION_BROKEN:
3309			default:
3310				ret = ECONNABORTED;
3311				goto unset_action_cleanup;
3312
3313			case SCF_ERROR_DELETED:
3314				break;
3315
3316			case SCF_ERROR_PERMISSION_DENIED:
3317				ret = EPERM;
3318				goto unset_action_cleanup;
3319
3320			case SCF_ERROR_BACKEND_ACCESS:
3321			case SCF_ERROR_BACKEND_READONLY:
3322				ret = EACCES;
3323				goto unset_action_cleanup;
3324
3325			case SCF_ERROR_INVALID_ARGUMENT:
3326			case SCF_ERROR_NOT_SET:
3327				assert(0);
3328				abort();
3329			}
3330		}
3331
3332		scf_transaction_reset(t);
3333	}
3334
3335unset_action_cleanup:
3336	scf_transaction_destroy(t);
3337	scf_entry_destroy(e);
3338	scf_property_destroy(prop);
3339	scf_value_destroy(val);
3340
3341	return (ret);
3342}
3343
3344/*
3345 * Decorates & binds hndl.  hndl must be unbound.  Returns
3346 *   0 - success
3347 *   -1 - repository server is not running
3348 *   -1 - repository server is out of resources
3349 */
3350static int
3351handle_decorate_and_bind(scf_handle_t *hndl)
3352{
3353	scf_value_t *door_dec_value;
3354
3355	door_dec_value = safe_scf_value_create(hndl);
3356
3357	/*
3358	 * Decorate if alternate door path set.
3359	 */
3360	if (st->st_door_path) {
3361		if (scf_value_set_astring(door_dec_value, st->st_door_path) !=
3362		    0)
3363			uu_die("$STARTD_ALT_DOOR is too long.\n");
3364
3365		if (scf_handle_decorate(hndl, "door_path", door_dec_value) != 0)
3366			bad_error("scf_handle_decorate", scf_error());
3367	}
3368
3369	scf_value_destroy(door_dec_value);
3370
3371	if (scf_handle_bind(hndl) == 0)
3372		return (0);
3373
3374	switch (scf_error()) {
3375	case SCF_ERROR_NO_SERVER:
3376	case SCF_ERROR_NO_RESOURCES:
3377		return (-1);
3378
3379	case SCF_ERROR_INVALID_ARGUMENT:
3380	case SCF_ERROR_IN_USE:
3381	default:
3382		bad_error("scf_handle_bind", scf_error());
3383		/* NOTREACHED */
3384	}
3385}
3386
3387scf_handle_t *
3388libscf_handle_create_bound(scf_version_t v)
3389{
3390	scf_handle_t *hndl = scf_handle_create(v);
3391
3392	if (hndl == NULL)
3393		return (hndl);
3394
3395	if (handle_decorate_and_bind(hndl) == 0)
3396		return (hndl);
3397
3398	scf_handle_destroy(hndl);
3399	return (NULL);
3400}
3401
3402void
3403libscf_handle_rebind(scf_handle_t *h)
3404{
3405	(void) scf_handle_unbind(h);
3406
3407	MUTEX_LOCK(&st->st_configd_live_lock);
3408
3409	/*
3410	 * Try to rebind the handle before sleeping in case the server isn't
3411	 * really dead.
3412	 */
3413	while (handle_decorate_and_bind(h) != 0)
3414		(void) pthread_cond_wait(&st->st_configd_live_cv,
3415		    &st->st_configd_live_lock);
3416
3417	MUTEX_UNLOCK(&st->st_configd_live_lock);
3418}
3419
3420/*
3421 * Create a handle and try to bind it until it succeeds.  Always returns
3422 * a bound handle.
3423 */
3424scf_handle_t *
3425libscf_handle_create_bound_loop()
3426{
3427	scf_handle_t *h;
3428
3429	while ((h = scf_handle_create(SCF_VERSION)) == NULL) {
3430		/* This should have been caught earlier. */
3431		assert(scf_error() != SCF_ERROR_VERSION_MISMATCH);
3432		(void) sleep(2);
3433	}
3434
3435	if (handle_decorate_and_bind(h) != 0)
3436		libscf_handle_rebind(h);
3437
3438	return (h);
3439}
3440
3441/*
3442 * Call cb for each dependency property group of inst.  cb is invoked with
3443 * a pointer to the scf_propertygroup_t and arg.  If the repository connection
3444 * is broken, returns ECONNABORTED.  If inst is deleted, returns ECANCELED.
3445 * If cb returns non-zero, the walk is stopped and EINTR is returned.
3446 * Otherwise returns 0.
3447 */
3448int
3449walk_dependency_pgs(scf_instance_t *inst, callback_t cb, void *arg)
3450{
3451	scf_handle_t *h;
3452	scf_snapshot_t *snap;
3453	scf_iter_t *iter;
3454	scf_propertygroup_t *pg;
3455	int r;
3456
3457	h = scf_instance_handle(inst);
3458
3459	iter = safe_scf_iter_create(h);
3460	pg = safe_scf_pg_create(h);
3461
3462	snap = libscf_get_running_snapshot(inst);
3463
3464	if (scf_iter_instance_pgs_typed_composed(iter, inst, snap,
3465	    SCF_GROUP_DEPENDENCY) != 0) {
3466		scf_snapshot_destroy(snap);
3467		scf_pg_destroy(pg);
3468		scf_iter_destroy(iter);
3469		switch (scf_error()) {
3470		case SCF_ERROR_CONNECTION_BROKEN:
3471		default:
3472			return (ECONNABORTED);
3473
3474		case SCF_ERROR_DELETED:
3475			return (ECANCELED);
3476
3477		case SCF_ERROR_HANDLE_MISMATCH:
3478		case SCF_ERROR_INVALID_ARGUMENT:
3479		case SCF_ERROR_NOT_SET:
3480			assert(0);
3481			abort();
3482		}
3483	}
3484
3485	for (;;) {
3486		r = scf_iter_next_pg(iter, pg);
3487		if (r == 0)
3488			break;
3489		if (r == -1) {
3490			scf_snapshot_destroy(snap);
3491			scf_pg_destroy(pg);
3492			scf_iter_destroy(iter);
3493
3494			switch (scf_error()) {
3495			case SCF_ERROR_CONNECTION_BROKEN:
3496				return (ECONNABORTED);
3497
3498			case SCF_ERROR_DELETED:
3499				return (ECANCELED);
3500
3501			case SCF_ERROR_NOT_SET:
3502			case SCF_ERROR_INVALID_ARGUMENT:
3503			case SCF_ERROR_NOT_BOUND:
3504			case SCF_ERROR_HANDLE_MISMATCH:
3505			default:
3506				bad_error("scf_iter_next_pg", scf_error());
3507			}
3508		}
3509
3510		r = cb(pg, arg);
3511
3512		if (r != 0)
3513			break;
3514	}
3515
3516	scf_snapshot_destroy(snap);
3517	scf_pg_destroy(pg);
3518	scf_iter_destroy(iter);
3519
3520	return (r == 0 ? 0 : EINTR);
3521}
3522
3523/*
3524 * Call cb for each of the string values of prop.  cb is invoked with
3525 * a pointer to the string and arg.  If the connection to the repository is
3526 * broken, ECONNABORTED is returned.  If the property is deleted, ECANCELED is
3527 * returned.  If the property does not have astring type, EINVAL is returned.
3528 * If cb returns non-zero, the walk is stopped and EINTR is returned.
3529 * Otherwise 0 is returned.
3530 */
3531int
3532walk_property_astrings(scf_property_t *prop, callback_t cb, void *arg)
3533{
3534	scf_handle_t *h;
3535	scf_value_t *val;
3536	scf_iter_t *iter;
3537	char *buf;
3538	int r;
3539	ssize_t sz;
3540
3541	if (scf_property_is_type(prop, SCF_TYPE_ASTRING) != 0) {
3542		switch (scf_error()) {
3543		case SCF_ERROR_CONNECTION_BROKEN:
3544		default:
3545			return (ECONNABORTED);
3546
3547		case SCF_ERROR_DELETED:
3548			return (ECANCELED);
3549
3550		case SCF_ERROR_TYPE_MISMATCH:
3551			return (EINVAL);
3552
3553		case SCF_ERROR_NOT_SET:
3554			assert(0);
3555			abort();
3556		}
3557	}
3558
3559	h = scf_property_handle(prop);
3560
3561	val = safe_scf_value_create(h);
3562	iter = safe_scf_iter_create(h);
3563
3564	if (scf_iter_property_values(iter, prop) != 0) {
3565		scf_iter_destroy(iter);
3566		scf_value_destroy(val);
3567		switch (scf_error()) {
3568		case SCF_ERROR_CONNECTION_BROKEN:
3569		default:
3570			return (ECONNABORTED);
3571
3572		case SCF_ERROR_DELETED:
3573			return (ECANCELED);
3574
3575		case SCF_ERROR_HANDLE_MISMATCH:
3576		case SCF_ERROR_NOT_SET:
3577			assert(0);
3578			abort();
3579		}
3580	}
3581
3582	buf = startd_alloc(max_scf_value_size);
3583
3584	for (;;) {
3585		r = scf_iter_next_value(iter, val);
3586		if (r < 0) {
3587			startd_free(buf, max_scf_value_size);
3588			scf_iter_destroy(iter);
3589			scf_value_destroy(val);
3590
3591			switch (scf_error()) {
3592			case SCF_ERROR_CONNECTION_BROKEN:
3593				return (ECONNABORTED);
3594
3595			case SCF_ERROR_DELETED:
3596				return (ECANCELED);
3597
3598			case SCF_ERROR_NOT_SET:
3599			case SCF_ERROR_INVALID_ARGUMENT:
3600			case SCF_ERROR_NOT_BOUND:
3601			case SCF_ERROR_HANDLE_MISMATCH:
3602			case SCF_ERROR_PERMISSION_DENIED:
3603			default:
3604				bad_error("scf_iter_next_value", scf_error());
3605			}
3606		}
3607		if (r == 0)
3608			break;
3609
3610		sz = scf_value_get_astring(val, buf, max_scf_value_size);
3611		assert(sz >= 0);
3612
3613		r = cb(buf, arg);
3614
3615		if (r != 0)
3616			break;
3617	}
3618
3619	startd_free(buf, max_scf_value_size);
3620	scf_value_destroy(val);
3621	scf_iter_destroy(iter);
3622
3623	return (r == 0 ? 0 : EINTR);
3624}
3625
3626/*
3627 * Returns 0 or ECONNABORTED.
3628 */
3629int
3630libscf_create_self(scf_handle_t *h)
3631{
3632	scf_scope_t *scope;
3633	scf_service_t *svc;
3634	scf_instance_t *inst;
3635	instance_data_t idata;
3636	int ret = 0, r;
3637	ctid_t ctid;
3638	uint64_t uint64;
3639	uint_t count = 0, msecs = ALLOC_DELAY;
3640
3641	const char * const startd_svc = "system/svc/restarter";
3642	const char * const startd_inst = "default";
3643
3644	/* If SCF_SERVICE_STARTD changes, our strings must change, too. */
3645	assert(strcmp(SCF_SERVICE_STARTD,
3646	    "svc:/system/svc/restarter:default") == 0);
3647
3648	scope = safe_scf_scope_create(h);
3649	svc = safe_scf_service_create(h);
3650	inst = safe_scf_instance_create(h);
3651
3652	if (scf_handle_get_scope(h, SCF_SCOPE_LOCAL, scope) != 0) {
3653		assert(scf_error() == SCF_ERROR_CONNECTION_BROKEN);
3654		ret = ECONNABORTED;
3655		goto out;
3656	}
3657
3658get_svc:
3659	if (scf_scope_get_service(scope, startd_svc, svc) != 0) {
3660		switch (scf_error()) {
3661		case SCF_ERROR_CONNECTION_BROKEN:
3662		case SCF_ERROR_DELETED:
3663		default:
3664			ret = ECONNABORTED;
3665			goto out;
3666
3667		case SCF_ERROR_NOT_FOUND:
3668			break;
3669
3670		case SCF_ERROR_HANDLE_MISMATCH:
3671		case SCF_ERROR_INVALID_ARGUMENT:
3672		case SCF_ERROR_NOT_SET:
3673			bad_error("scf_scope_get_service", scf_error());
3674		}
3675
3676add_svc:
3677		if (scf_scope_add_service(scope, startd_svc, svc) != 0) {
3678			switch (scf_error()) {
3679			case SCF_ERROR_CONNECTION_BROKEN:
3680			case SCF_ERROR_DELETED:
3681			default:
3682				ret = ECONNABORTED;
3683				goto out;
3684
3685			case SCF_ERROR_EXISTS:
3686				goto get_svc;
3687
3688			case SCF_ERROR_PERMISSION_DENIED:
3689			case SCF_ERROR_BACKEND_ACCESS:
3690			case SCF_ERROR_BACKEND_READONLY:
3691				uu_warn("Could not create %s: %s\n",
3692				    SCF_SERVICE_STARTD,
3693				    scf_strerror(scf_error()));
3694				goto out;
3695
3696			case SCF_ERROR_HANDLE_MISMATCH:
3697			case SCF_ERROR_INVALID_ARGUMENT:
3698			case SCF_ERROR_NOT_SET:
3699				bad_error("scf_scope_add_service", scf_error());
3700			}
3701		}
3702	}
3703
3704	if (scf_service_get_instance(svc, startd_inst, NULL) == 0)
3705		goto out;
3706
3707	switch (scf_error()) {
3708	case SCF_ERROR_CONNECTION_BROKEN:
3709	default:
3710		ret = ECONNABORTED;
3711		goto out;
3712
3713	case SCF_ERROR_NOT_FOUND:
3714		break;
3715
3716	case SCF_ERROR_DELETED:
3717		goto add_svc;
3718
3719	case SCF_ERROR_HANDLE_MISMATCH:
3720	case SCF_ERROR_INVALID_ARGUMENT:
3721	case SCF_ERROR_NOT_SET:
3722		bad_error("scf_service_get_instance", scf_error());
3723	}
3724
3725add_inst:
3726	if (scf_service_add_instance(svc, startd_inst, inst) != 0) {
3727		switch (scf_error()) {
3728		case SCF_ERROR_CONNECTION_BROKEN:
3729		default:
3730			ret = ECONNABORTED;
3731			goto out;
3732
3733		case SCF_ERROR_EXISTS:
3734			break;
3735
3736		case SCF_ERROR_PERMISSION_DENIED:
3737		case SCF_ERROR_BACKEND_ACCESS:
3738			uu_die("Could not create %s: %s\n", SCF_SERVICE_STARTD,
3739			    scf_strerror(scf_error()));
3740			/* NOTREACHED */
3741
3742		case SCF_ERROR_BACKEND_READONLY:
3743			log_error(LOG_NOTICE,
3744			    "Could not create %s: backend readonly.\n",
3745			    SCF_SERVICE_STARTD);
3746			goto out;
3747
3748		case SCF_ERROR_DELETED:
3749			goto add_svc;
3750
3751		case SCF_ERROR_HANDLE_MISMATCH:
3752		case SCF_ERROR_INVALID_ARGUMENT:
3753		case SCF_ERROR_NOT_SET:
3754			bad_error("scf_service_add_instance", scf_error());
3755		}
3756	}
3757
3758	/* Set start time. */
3759	idata.i_fmri = SCF_SERVICE_STARTD;
3760	idata.i_state = RESTARTER_STATE_NONE;
3761	idata.i_next_state = RESTARTER_STATE_NONE;
3762set_state:
3763	switch (r = _restarter_commit_states(h, &idata, RESTARTER_STATE_ONLINE,
3764	    RESTARTER_STATE_NONE, NULL)) {
3765	case 0:
3766		break;
3767
3768	case ENOMEM:
3769		++count;
3770		if (count < ALLOC_RETRY) {
3771			(void) poll(NULL, 0, msecs);
3772			msecs *= ALLOC_DELAY_MULT;
3773			goto set_state;
3774		}
3775
3776		uu_die("Insufficient memory.\n");
3777		/* NOTREACHED */
3778
3779	case ECONNABORTED:
3780		ret = ECONNABORTED;
3781		goto out;
3782
3783	case ENOENT:
3784		goto add_inst;
3785
3786	case EPERM:
3787	case EACCES:
3788	case EROFS:
3789		uu_warn("Could not timestamp %s: %s\n", idata.i_fmri,
3790		    strerror(r));
3791		break;
3792
3793	case EINVAL:
3794	default:
3795		bad_error("_restarter_commit_states", r);
3796	}
3797
3798	/* Set general/enabled. */
3799	ret = libscf_inst_set_boolean_prop(inst, SCF_PG_GENERAL,
3800	    SCF_PG_GENERAL_TYPE, SCF_PG_GENERAL_FLAGS, SCF_PROPERTY_ENABLED, 1);
3801	switch (ret) {
3802	case 0:
3803	case ECONNABORTED:
3804	case EPERM:
3805	case EACCES:
3806	case EROFS:
3807		break;
3808
3809	case ECANCELED:
3810		goto add_inst;
3811
3812	default:
3813		bad_error("libscf_inst_set_boolean_prop", ret);
3814	}
3815
3816	ret = libscf_write_start_pid(inst, getpid());
3817	switch (ret) {
3818	case 0:
3819	case ECONNABORTED:
3820	case EPERM:
3821	case EACCES:
3822	case EROFS:
3823		break;
3824
3825	case ECANCELED:
3826		goto add_inst;
3827
3828	default:
3829		bad_error("libscf_write_start_pid", ret);
3830	}
3831
3832	ctid = proc_get_ctid();
3833	if (ctid > 0) {
3834
3835		uint64 = (uint64_t)ctid;
3836		ret = libscf_inst_set_count_prop(inst,
3837		    SCF_PG_RESTARTER, SCF_PG_RESTARTER_TYPE,
3838		    SCF_PG_RESTARTER_FLAGS, SCF_PROPERTY_CONTRACT, uint64);
3839
3840		switch (ret) {
3841		case 0:
3842		case ECONNABORTED:
3843		case EPERM:
3844		case EACCES:
3845		case EROFS:
3846			break;
3847
3848		case ECANCELED:
3849			goto add_inst;
3850
3851		default:
3852			bad_error("libscf_inst_set_count_prop", ret);
3853		}
3854	}
3855
3856	ret = libscf_note_method_log(inst, LOG_PREFIX_EARLY,
3857	    STARTD_DEFAULT_LOG);
3858	if (ret == 0) {
3859		ret = libscf_note_method_log(inst, LOG_PREFIX_NORMAL,
3860		    STARTD_DEFAULT_LOG);
3861	}
3862
3863	switch (ret) {
3864		case ECONNABORTED:
3865		case EPERM:
3866		case EACCES:
3867		case EROFS:
3868		case EAGAIN:
3869			break;
3870
3871		case ECANCELED:
3872			goto add_inst;
3873
3874		default:
3875			bad_error("libscf_note_method_log", ret);
3876	}
3877
3878out:
3879	scf_instance_destroy(inst);
3880	scf_service_destroy(svc);
3881	scf_scope_destroy(scope);
3882	return (ret);
3883}
3884
3885/*
3886 * Returns
3887 *   0 - success
3888 *   ENOENT - SCF_SERVICE_STARTD does not exist in repository
3889 *   EPERM
3890 *   EACCES
3891 *   EROFS
3892 */
3893int
3894libscf_set_reconfig(int set)
3895{
3896	scf_handle_t *h;
3897	scf_instance_t *inst;
3898	scf_propertygroup_t *pg;
3899	int ret = 0;
3900
3901	h = libscf_handle_create_bound_loop();
3902	inst = safe_scf_instance_create(h);
3903	pg = safe_scf_pg_create(h);
3904
3905again:
3906	if (scf_handle_decode_fmri(h, SCF_SERVICE_STARTD, NULL, NULL,
3907	    inst, NULL, NULL,  SCF_DECODE_FMRI_EXACT) == -1) {
3908		switch (scf_error()) {
3909		case SCF_ERROR_CONNECTION_BROKEN:
3910		default:
3911			libscf_handle_rebind(h);
3912			goto again;
3913
3914		case SCF_ERROR_NOT_FOUND:
3915			ret = ENOENT;
3916			goto reconfig_out;
3917
3918		case SCF_ERROR_HANDLE_MISMATCH:
3919		case SCF_ERROR_INVALID_ARGUMENT:
3920		case SCF_ERROR_CONSTRAINT_VIOLATED:
3921			bad_error("scf_handle_decode_fmri", scf_error());
3922		}
3923	}
3924
3925	ret = libscf_inst_set_boolean_prop(inst, "system", SCF_GROUP_FRAMEWORK,
3926	    SCF_PG_FLAG_NONPERSISTENT, "reconfigure", set);
3927	switch (ret) {
3928	case 0:
3929	case EPERM:
3930	case EACCES:
3931	case EROFS:
3932		break;
3933
3934	case ECONNABORTED:
3935		libscf_handle_rebind(h);
3936		goto again;
3937
3938	case ECANCELED:
3939		ret = ENOENT;
3940		break;
3941
3942	default:
3943		bad_error("libscf_inst_set_boolean_prop", ret);
3944	}
3945
3946reconfig_out:
3947	scf_pg_destroy(pg);
3948	scf_instance_destroy(inst);
3949	scf_handle_destroy(h);
3950	return (ret);
3951}
3952
3953/*
3954 * Set inst->ri_m_inst to the scf instance for inst.  If it has been deleted,
3955 * set inst->ri_mi_deleted to true.  If the repository connection is broken, it
3956 * is rebound with libscf_handle_rebound().
3957 */
3958void
3959libscf_reget_instance(restarter_inst_t *inst)
3960{
3961	scf_handle_t *h;
3962	int r;
3963
3964	h = scf_instance_handle(inst->ri_m_inst);
3965
3966again:
3967	r = libscf_lookup_instance(inst->ri_i.i_fmri, inst->ri_m_inst);
3968	switch (r) {
3969	case 0:
3970	case ENOENT:
3971		inst->ri_mi_deleted = (r == ENOENT);
3972		return;
3973
3974	case ECONNABORTED:
3975		libscf_handle_rebind(h);
3976		goto again;
3977
3978	case EINVAL:
3979	case ENOTSUP:
3980	default:
3981		bad_error("libscf_lookup_instance", r);
3982	}
3983}
3984