libscf.c revision 8823:000507e9108d
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 2009 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 0, ECONNABORTED, ECANCELED, or EPERM.
1580 */
1581int
1582libscf_delete_enable_ovr(scf_instance_t *inst)
1583{
1584	return (scf_instance_delete_prop(inst, SCF_PG_GENERAL_OVR,
1585	    SCF_PROPERTY_ENABLED));
1586}
1587
1588/*
1589 * Fails with
1590 *   ECONNABORTED - repository connection was broken
1591 *   ECANCELED - pg was deleted
1592 *   ENOENT - pg has no milestone property
1593 *   EINVAL - the milestone property is misconfigured
1594 */
1595static int
1596pg_get_milestone(scf_propertygroup_t *pg, scf_property_t *prop,
1597    scf_value_t *val, char *buf, size_t buf_sz)
1598{
1599	if (scf_pg_get_property(pg, SCF_PROPERTY_MILESTONE, prop) != 0) {
1600		switch (scf_error()) {
1601		case SCF_ERROR_CONNECTION_BROKEN:
1602		default:
1603			return (ECONNABORTED);
1604
1605		case SCF_ERROR_DELETED:
1606			return (ECANCELED);
1607
1608		case SCF_ERROR_NOT_FOUND:
1609			return (ENOENT);
1610
1611		case SCF_ERROR_HANDLE_MISMATCH:
1612		case SCF_ERROR_INVALID_ARGUMENT:
1613		case SCF_ERROR_NOT_SET:
1614			bad_error("scf_pg_get_property", scf_error());
1615		}
1616	}
1617
1618	if (scf_property_get_value(prop, val) != 0) {
1619		switch (scf_error()) {
1620		case SCF_ERROR_CONNECTION_BROKEN:
1621		default:
1622			return (ECONNABORTED);
1623
1624		case SCF_ERROR_DELETED:
1625		case SCF_ERROR_CONSTRAINT_VIOLATED:
1626		case SCF_ERROR_NOT_FOUND:
1627			return (EINVAL);
1628
1629		case SCF_ERROR_NOT_SET:
1630		case SCF_ERROR_PERMISSION_DENIED:
1631			bad_error("scf_property_get_value", scf_error());
1632		}
1633	}
1634
1635	if (scf_value_get_astring(val, buf, buf_sz) < 0) {
1636		switch (scf_error()) {
1637		case SCF_ERROR_TYPE_MISMATCH:
1638			return (EINVAL);
1639
1640		case SCF_ERROR_NOT_SET:
1641		default:
1642			bad_error("scf_value_get_astring", scf_error());
1643		}
1644	}
1645
1646	return (0);
1647}
1648
1649/*
1650 * Fails with
1651 *   ECONNABORTED - repository connection was broken
1652 *   ECANCELED - inst was deleted
1653 *   ENOENT - inst has no milestone property
1654 *   EINVAL - the milestone property is misconfigured
1655 */
1656int
1657libscf_get_milestone(scf_instance_t *inst, scf_property_t *prop,
1658    scf_value_t *val, char *buf, size_t buf_sz)
1659{
1660	scf_propertygroup_t *pg;
1661	int r;
1662
1663	pg = safe_scf_pg_create(scf_instance_handle(inst));
1664
1665	if (scf_instance_get_pg(inst, SCF_PG_OPTIONS_OVR, pg) == 0) {
1666		switch (r = pg_get_milestone(pg, prop, val, buf, buf_sz)) {
1667		case 0:
1668		case ECONNABORTED:
1669		case EINVAL:
1670			goto out;
1671
1672		case ECANCELED:
1673		case ENOENT:
1674			break;
1675
1676		default:
1677			bad_error("pg_get_milestone", r);
1678		}
1679	} else {
1680		switch (scf_error()) {
1681		case SCF_ERROR_CONNECTION_BROKEN:
1682		default:
1683			r = ECONNABORTED;
1684			goto out;
1685
1686		case SCF_ERROR_DELETED:
1687			r = ECANCELED;
1688			goto out;
1689
1690		case SCF_ERROR_NOT_FOUND:
1691			break;
1692
1693		case SCF_ERROR_HANDLE_MISMATCH:
1694		case SCF_ERROR_INVALID_ARGUMENT:
1695		case SCF_ERROR_NOT_SET:
1696			bad_error("scf_instance_get_pg", scf_error());
1697		}
1698	}
1699
1700	if (scf_instance_get_pg(inst, SCF_PG_OPTIONS, pg) == 0) {
1701		r = pg_get_milestone(pg, prop, val, buf, buf_sz);
1702	} else {
1703		switch (scf_error()) {
1704		case SCF_ERROR_CONNECTION_BROKEN:
1705		default:
1706			r = ECONNABORTED;
1707			goto out;
1708
1709		case SCF_ERROR_DELETED:
1710			r = ECANCELED;
1711			goto out;
1712
1713		case SCF_ERROR_NOT_FOUND:
1714			r = ENOENT;
1715			break;
1716
1717		case SCF_ERROR_HANDLE_MISMATCH:
1718		case SCF_ERROR_INVALID_ARGUMENT:
1719		case SCF_ERROR_NOT_SET:
1720			bad_error("scf_instance_get_pg", scf_error());
1721		}
1722	}
1723
1724out:
1725	scf_pg_destroy(pg);
1726
1727	return (r);
1728}
1729
1730/*
1731 * Get the runlevel character from the runlevel property of the given property
1732 * group.  Fails with
1733 *   ECONNABORTED - repository connection was broken
1734 *   ECANCELED - prop's property group was deleted
1735 *   ENOENT - the property has no values
1736 *   EINVAL - the property has more than one value
1737 *	      the property is of the wrong type
1738 *	      the property value is malformed
1739 */
1740int
1741libscf_extract_runlevel(scf_property_t *prop, char *rlp)
1742{
1743	scf_value_t *val;
1744	char buf[2];
1745
1746	val = safe_scf_value_create(scf_property_handle(prop));
1747
1748	if (scf_property_get_value(prop, val) != 0) {
1749		switch (scf_error()) {
1750		case SCF_ERROR_CONNECTION_BROKEN:
1751			return (ECONNABORTED);
1752
1753		case SCF_ERROR_NOT_SET:
1754			return (ENOENT);
1755
1756		case SCF_ERROR_DELETED:
1757			return (ECANCELED);
1758
1759		case SCF_ERROR_CONSTRAINT_VIOLATED:
1760			return (EINVAL);
1761
1762		case SCF_ERROR_NOT_FOUND:
1763			return (ENOENT);
1764
1765		case SCF_ERROR_HANDLE_MISMATCH:
1766		case SCF_ERROR_NOT_BOUND:
1767		case SCF_ERROR_PERMISSION_DENIED:
1768		default:
1769			bad_error("scf_property_get_value", scf_error());
1770		}
1771	}
1772
1773	if (scf_value_get_astring(val, buf, sizeof (buf)) < 0) {
1774		if (scf_error() != SCF_ERROR_TYPE_MISMATCH)
1775			bad_error("scf_value_get_astring", scf_error());
1776
1777		return (EINVAL);
1778	}
1779
1780	if (buf[0] == '\0' || buf[1] != '\0')
1781		return (EINVAL);
1782
1783	*rlp = buf[0];
1784
1785	return (0);
1786}
1787
1788/*
1789 * Delete the "runlevel" property from the given property group.  Also set the
1790 * "milestone" property to the given string.  Fails with ECONNABORTED,
1791 * ECANCELED, EPERM, EACCES, or EROFS.
1792 */
1793int
1794libscf_clear_runlevel(scf_propertygroup_t *pg, const char *milestone)
1795{
1796	scf_handle_t *h;
1797	scf_transaction_t *tx;
1798	scf_transaction_entry_t *e_rl, *e_ms;
1799	scf_value_t *val;
1800	scf_error_t serr;
1801	boolean_t isempty = B_TRUE;
1802	int ret = 0, r;
1803
1804	h = scf_pg_handle(pg);
1805	tx = safe_scf_transaction_create(h);
1806	e_rl = safe_scf_entry_create(h);
1807	e_ms = safe_scf_entry_create(h);
1808	val = safe_scf_value_create(h);
1809
1810	if (milestone) {
1811		r = scf_value_set_astring(val, milestone);
1812		assert(r == 0);
1813	}
1814
1815	for (;;) {
1816		if (scf_transaction_start(tx, pg) != 0) {
1817			switch (scf_error()) {
1818			case SCF_ERROR_CONNECTION_BROKEN:
1819			default:
1820				ret = ECONNABORTED;
1821				goto out;
1822
1823			case SCF_ERROR_DELETED:
1824				ret = ECANCELED;
1825				goto out;
1826
1827			case SCF_ERROR_PERMISSION_DENIED:
1828				ret = EPERM;
1829				goto out;
1830
1831			case SCF_ERROR_BACKEND_ACCESS:
1832				ret = EACCES;
1833				goto out;
1834
1835			case SCF_ERROR_BACKEND_READONLY:
1836				ret = EROFS;
1837				goto out;
1838
1839			case SCF_ERROR_NOT_SET:
1840				bad_error("scf_transaction_start", scf_error());
1841			}
1842		}
1843
1844		if (scf_transaction_property_delete(tx, e_rl,
1845		    "runlevel") == 0) {
1846			isempty = B_FALSE;
1847		} else {
1848			switch (scf_error()) {
1849			case SCF_ERROR_CONNECTION_BROKEN:
1850			default:
1851				ret = ECONNABORTED;
1852				goto out;
1853
1854			case SCF_ERROR_DELETED:
1855				ret = ECANCELED;
1856				goto out;
1857
1858			case SCF_ERROR_NOT_FOUND:
1859				break;
1860
1861			case SCF_ERROR_HANDLE_MISMATCH:
1862			case SCF_ERROR_NOT_BOUND:
1863			case SCF_ERROR_INVALID_ARGUMENT:
1864				bad_error("scf_transaction_property_delete",
1865				    scf_error());
1866			}
1867		}
1868
1869		if (milestone) {
1870			ret = transaction_add_set(tx, e_ms,
1871			    SCF_PROPERTY_MILESTONE, SCF_TYPE_ASTRING);
1872			switch (ret) {
1873			case 0:
1874				break;
1875
1876			case ECONNABORTED:
1877			case ECANCELED:
1878				goto out;
1879
1880			default:
1881				bad_error("transaction_add_set", ret);
1882			}
1883
1884			isempty = B_FALSE;
1885
1886			r = scf_entry_add_value(e_ms, val);
1887			assert(r == 0);
1888		}
1889
1890		if (isempty)
1891			goto out;
1892
1893		r = scf_transaction_commit(tx);
1894		if (r == 1)
1895			break;
1896		if (r != 0) {
1897			serr = scf_error();
1898			scf_transaction_reset(tx);
1899			switch (serr) {
1900			case SCF_ERROR_CONNECTION_BROKEN:
1901				ret = ECONNABORTED;
1902				goto out;
1903
1904			case SCF_ERROR_PERMISSION_DENIED:
1905				ret = EPERM;
1906				goto out;
1907
1908			case SCF_ERROR_BACKEND_ACCESS:
1909				ret = EACCES;
1910				goto out;
1911
1912			case SCF_ERROR_BACKEND_READONLY:
1913				ret = EROFS;
1914				goto out;
1915
1916			default:
1917				bad_error("scf_transaction_commit", serr);
1918			}
1919		}
1920
1921		scf_transaction_reset(tx);
1922
1923		if (scf_pg_update(pg) == -1) {
1924			switch (scf_error()) {
1925			case SCF_ERROR_CONNECTION_BROKEN:
1926				ret = ECONNABORTED;
1927				goto out;
1928
1929			case SCF_ERROR_NOT_SET:
1930				ret = ECANCELED;
1931				goto out;
1932
1933			default:
1934				assert(0);
1935				abort();
1936			}
1937		}
1938	}
1939
1940out:
1941	scf_transaction_destroy(tx);
1942	scf_entry_destroy(e_rl);
1943	scf_entry_destroy(e_ms);
1944	scf_value_destroy(val);
1945	return (ret);
1946}
1947
1948/*
1949 * int libscf_get_template_values(scf_instance_t *, scf_snapshot_t *,
1950 *	char **)
1951 *
1952 *   Return template values for inst in *common_name suitable for use in
1953 *   restarter_inst_t->ri_common_name.  Called by restarter_insert_inst().
1954 *
1955 *   Returns 0 on success, ECANCELED if the instance is deleted, ECHILD if
1956 *   a value fetch failed for a property, ENOENT if the instance has no
1957 *   tm_common_name property group or the property group is deleted, and
1958 *   ECONNABORTED if the repository connection is broken.
1959 */
1960int
1961libscf_get_template_values(scf_instance_t *inst, scf_snapshot_t *snap,
1962    char **common_name, char **c_common_name)
1963{
1964	scf_handle_t *h;
1965	scf_propertygroup_t *pg = NULL;
1966	scf_property_t *prop = NULL;
1967	int ret = 0, r;
1968	char *cname = startd_alloc(max_scf_value_size);
1969	char *c_cname = startd_alloc(max_scf_value_size);
1970	int common_name_initialized = B_FALSE;
1971	int c_common_name_initialized = B_FALSE;
1972
1973	h = scf_instance_handle(inst);
1974	pg = safe_scf_pg_create(h);
1975	prop = safe_scf_property_create(h);
1976
1977	/*
1978	 * The tm_common_name property group, as with all template property
1979	 * groups, is optional.
1980	 */
1981	if (scf_instance_get_pg_composed(inst, snap, SCF_PG_TM_COMMON_NAME, pg)
1982	    == -1) {
1983		switch (scf_error()) {
1984		case SCF_ERROR_DELETED:
1985			ret = ECANCELED;
1986			goto template_values_out;
1987
1988		case SCF_ERROR_NOT_FOUND:
1989			goto template_values_out;
1990
1991		case SCF_ERROR_CONNECTION_BROKEN:
1992		default:
1993			ret = ECONNABORTED;
1994			goto template_values_out;
1995
1996		case SCF_ERROR_INVALID_ARGUMENT:
1997		case SCF_ERROR_HANDLE_MISMATCH:
1998		case SCF_ERROR_NOT_SET:
1999			bad_error("scf_instance_get_pg_composed", scf_error());
2000		}
2001	}
2002
2003	/*
2004	 * The name we wish uses the current locale name as the property name.
2005	 */
2006	if (st->st_locale != NULL) {
2007		if (scf_pg_get_property(pg, st->st_locale, prop) == -1) {
2008			switch (scf_error()) {
2009			case SCF_ERROR_DELETED:
2010			case SCF_ERROR_NOT_FOUND:
2011				break;
2012
2013			case SCF_ERROR_CONNECTION_BROKEN:
2014			default:
2015				ret = ECONNABORTED;
2016				goto template_values_out;
2017
2018			case SCF_ERROR_INVALID_ARGUMENT:
2019			case SCF_ERROR_HANDLE_MISMATCH:
2020			case SCF_ERROR_NOT_SET:
2021				bad_error("scf_pg_get_property", scf_error());
2022			}
2023		} else {
2024			if ((r = libscf_read_single_astring(h, prop, &cname)) !=
2025			    0) {
2026				if (r != LIBSCF_PROPERTY_ABSENT)
2027					ret = ECHILD;
2028				goto template_values_out;
2029			}
2030
2031			*common_name = cname;
2032			common_name_initialized = B_TRUE;
2033		}
2034	}
2035
2036	/*
2037	 * Also pull out the C locale name, as a fallback for the case where
2038	 * service offers no localized name.
2039	 */
2040	if (scf_pg_get_property(pg, "C", prop) == -1) {
2041		switch (scf_error()) {
2042		case SCF_ERROR_DELETED:
2043			ret = ENOENT;
2044			goto template_values_out;
2045
2046		case SCF_ERROR_NOT_FOUND:
2047			break;
2048
2049		case SCF_ERROR_CONNECTION_BROKEN:
2050		default:
2051			ret = ECONNABORTED;
2052			goto template_values_out;
2053
2054		case SCF_ERROR_INVALID_ARGUMENT:
2055		case SCF_ERROR_HANDLE_MISMATCH:
2056		case SCF_ERROR_NOT_SET:
2057			bad_error("scf_pg_get_property", scf_error());
2058		}
2059	} else {
2060		if ((r = libscf_read_single_astring(h, prop, &c_cname)) != 0) {
2061			if (r != LIBSCF_PROPERTY_ABSENT)
2062				ret = ECHILD;
2063			goto template_values_out;
2064		}
2065
2066		*c_common_name = c_cname;
2067		c_common_name_initialized = B_TRUE;
2068	}
2069
2070
2071template_values_out:
2072	if (common_name_initialized == B_FALSE)
2073		startd_free(cname, max_scf_value_size);
2074	if (c_common_name_initialized == B_FALSE)
2075		startd_free(c_cname, max_scf_value_size);
2076	scf_property_destroy(prop);
2077	scf_pg_destroy(pg);
2078
2079	return (ret);
2080}
2081
2082/*
2083 * int libscf_get_startd_properties(scf_handle_t *, scf_instance_t *,
2084 *	scf_snapshot_t *, uint_t *, char **)
2085 *
2086 *   Return startd settings for inst in *flags suitable for use in
2087 *   restarter_inst_t->ri_flags.  Called by restarter_insert_inst().
2088 *
2089 *   Returns 0 on success, ECANCELED if the instance is deleted, ECHILD if
2090 *   a value fetch failed for a property, ENOENT if the instance has no
2091 *   general property group or the property group is deleted, and
2092 *   ECONNABORTED if the repository connection is broken.
2093 */
2094int
2095libscf_get_startd_properties(scf_instance_t *inst,
2096    scf_snapshot_t *snap, uint_t *flags, char **prefixp)
2097{
2098	scf_handle_t *h;
2099	scf_propertygroup_t *pg = NULL;
2100	scf_property_t *prop = NULL;
2101	int style = RINST_CONTRACT;
2102	char *style_str = startd_alloc(max_scf_value_size);
2103	int ret = 0, r;
2104
2105	h = scf_instance_handle(inst);
2106	pg = safe_scf_pg_create(h);
2107	prop = safe_scf_property_create(h);
2108
2109	/*
2110	 * The startd property group is optional.
2111	 */
2112	if (scf_instance_get_pg_composed(inst, snap, SCF_PG_STARTD, pg) == -1) {
2113		switch (scf_error()) {
2114		case SCF_ERROR_DELETED:
2115			ret = ECANCELED;
2116			goto instance_flags_out;
2117
2118		case SCF_ERROR_NOT_FOUND:
2119			ret = ENOENT;
2120			goto instance_flags_out;
2121
2122		case SCF_ERROR_CONNECTION_BROKEN:
2123		default:
2124			ret = ECONNABORTED;
2125			goto instance_flags_out;
2126
2127		case SCF_ERROR_INVALID_ARGUMENT:
2128		case SCF_ERROR_HANDLE_MISMATCH:
2129		case SCF_ERROR_NOT_SET:
2130			bad_error("scf_instance_get_pg_composed", scf_error());
2131		}
2132	}
2133
2134	/*
2135	 * 1.  Duration property.
2136	 */
2137	if (scf_pg_get_property(pg, SCF_PROPERTY_DURATION, prop) == -1) {
2138		switch (scf_error()) {
2139		case SCF_ERROR_DELETED:
2140			ret = ENOENT;
2141			goto instance_flags_out;
2142
2143		case SCF_ERROR_NOT_FOUND:
2144			break;
2145
2146		case SCF_ERROR_CONNECTION_BROKEN:
2147		default:
2148			ret = ECONNABORTED;
2149			goto instance_flags_out;
2150
2151		case SCF_ERROR_INVALID_ARGUMENT:
2152		case SCF_ERROR_HANDLE_MISMATCH:
2153		case SCF_ERROR_NOT_SET:
2154			bad_error("scf_pg_get_property", scf_error());
2155		}
2156	} else {
2157		errno = 0;
2158		if ((r = libscf_read_single_astring(h, prop, &style_str))
2159		    != 0) {
2160			if (r != LIBSCF_PROPERTY_ABSENT)
2161				ret = ECHILD;
2162			goto instance_flags_out;
2163		}
2164
2165		if (strcmp(style_str, "child") == 0)
2166			style = RINST_WAIT;
2167		else if (strcmp(style_str, "transient") == 0)
2168			style = RINST_TRANSIENT;
2169	}
2170
2171	/*
2172	 * 2.  utmpx prefix property.
2173	 */
2174	if (scf_pg_get_property(pg, SCF_PROPERTY_UTMPX_PREFIX, prop) == 0) {
2175		errno = 0;
2176		if ((r = libscf_read_single_astring(h, prop, prefixp)) != 0) {
2177			if (r != LIBSCF_PROPERTY_ABSENT)
2178				ret = ECHILD;
2179			goto instance_flags_out;
2180		}
2181	} else {
2182		switch (scf_error()) {
2183		case SCF_ERROR_DELETED:
2184			ret = ENOENT;
2185			goto instance_flags_out;
2186
2187		case SCF_ERROR_NOT_FOUND:
2188			goto instance_flags_out;
2189
2190		case SCF_ERROR_CONNECTION_BROKEN:
2191		default:
2192			ret = ECONNABORTED;
2193			goto instance_flags_out;
2194
2195		case SCF_ERROR_INVALID_ARGUMENT:
2196		case SCF_ERROR_HANDLE_MISMATCH:
2197		case SCF_ERROR_NOT_SET:
2198			bad_error("scf_pg_get_property", scf_error());
2199		}
2200	}
2201
2202instance_flags_out:
2203	startd_free(style_str, max_scf_value_size);
2204	*flags = (*flags & ~RINST_STYLE_MASK) | style;
2205
2206	scf_property_destroy(prop);
2207	scf_pg_destroy(pg);
2208
2209	return (ret);
2210}
2211
2212/*
2213 * int libscf_read_method_ids(scf_handle_t *, scf_instance_t *, ctid_t *,
2214 *   ctid_t *, pid_t *)
2215 *
2216 *  Sets given id_t variables to primary and transient contract IDs and start
2217 *  PID.  Returns 0, ECONNABORTED, and ECANCELED.
2218 */
2219int
2220libscf_read_method_ids(scf_handle_t *h, scf_instance_t *inst, const char *fmri,
2221    ctid_t *primary, ctid_t *transient, pid_t *start_pid)
2222{
2223	scf_propertygroup_t *pg = NULL;
2224	scf_property_t *prop = NULL;
2225	scf_value_t *val = NULL;
2226	uint64_t p, t;
2227	int ret = 0;
2228
2229	*primary = 0;
2230	*transient = 0;
2231	*start_pid = -1;
2232
2233	pg = safe_scf_pg_create(h);
2234	prop = safe_scf_property_create(h);
2235	val = safe_scf_value_create(h);
2236
2237	if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) == -1) {
2238		switch (scf_error()) {
2239		case SCF_ERROR_CONNECTION_BROKEN:
2240		default:
2241			ret = ECONNABORTED;
2242			goto read_id_err;
2243
2244		case SCF_ERROR_DELETED:
2245			ret = ECANCELED;
2246			goto read_id_err;
2247
2248		case SCF_ERROR_NOT_FOUND:
2249			goto read_id_err;
2250
2251		case SCF_ERROR_NOT_SET:
2252			bad_error("scf_instance_get_pg", scf_error());
2253		}
2254	}
2255
2256	ret = get_count(pg, SCF_PROPERTY_CONTRACT, &p);
2257	switch (ret) {
2258	case 0:
2259		break;
2260
2261	case EINVAL:
2262		log_error(LOG_NOTICE,
2263		    "%s: Ignoring %s/%s: multivalued or not of type count\n",
2264		    fmri, SCF_PG_RESTARTER, SCF_PROPERTY_CONTRACT);
2265		/* FALLTHROUGH */
2266	case ENOENT:
2267		ret = 0;
2268		goto read_trans;
2269
2270	case ECONNABORTED:
2271	case ECANCELED:
2272		goto read_id_err;
2273
2274	case EACCES:
2275	default:
2276		bad_error("get_count", ret);
2277	}
2278
2279	*primary = p;
2280
2281read_trans:
2282	ret = get_count(pg, SCF_PROPERTY_TRANSIENT_CONTRACT, &t);
2283	switch (ret) {
2284	case 0:
2285		break;
2286
2287	case EINVAL:
2288		log_error(LOG_NOTICE,
2289		    "%s: Ignoring %s/%s: multivalued or not of type count\n",
2290		    fmri, SCF_PG_RESTARTER, SCF_PROPERTY_TRANSIENT_CONTRACT);
2291		/* FALLTHROUGH */
2292
2293	case ENOENT:
2294		ret = 0;
2295		goto read_pid_only;
2296
2297	case ECONNABORTED:
2298	case ECANCELED:
2299		goto read_id_err;
2300
2301	case EACCES:
2302	default:
2303		bad_error("get_count", ret);
2304	}
2305
2306	*transient = t;
2307
2308read_pid_only:
2309	ret = get_count(pg, SCF_PROPERTY_START_PID, &p);
2310	switch (ret) {
2311	case 0:
2312		break;
2313
2314	case EINVAL:
2315		log_error(LOG_NOTICE,
2316		    "%s: Ignoring %s/%s: multivalued or not of type count\n",
2317		    fmri, SCF_PG_RESTARTER, SCF_PROPERTY_START_PID);
2318		/* FALLTHROUGH */
2319	case ENOENT:
2320		ret = 0;
2321		goto read_id_err;
2322
2323	case ECONNABORTED:
2324	case ECANCELED:
2325		goto read_id_err;
2326
2327	case EACCES:
2328	default:
2329		bad_error("get_count", ret);
2330	}
2331
2332	*start_pid = p;
2333
2334read_id_err:
2335	scf_value_destroy(val);
2336	scf_property_destroy(prop);
2337	scf_pg_destroy(pg);
2338	return (ret);
2339}
2340
2341/*
2342 * Returns with
2343 *   0 - success
2344 *   ECONNABORTED - repository connection broken
2345 *		  - unknown libscf error
2346 *   ECANCELED - s_inst was deleted
2347 *   EPERM
2348 *   EACCES
2349 *   EROFS
2350 */
2351int
2352libscf_write_start_pid(scf_instance_t *s_inst, pid_t pid)
2353{
2354	scf_handle_t *h;
2355	scf_transaction_entry_t *t_pid;
2356	scf_value_t *v_pid;
2357	scf_propertygroup_t *pg;
2358	int ret = 0;
2359
2360	h = scf_instance_handle(s_inst);
2361
2362	pg = safe_scf_pg_create(h);
2363	t_pid = safe_scf_entry_create(h);
2364	v_pid = safe_scf_value_create(h);
2365
2366get_pg:
2367	ret = libscf_inst_get_or_add_pg(s_inst, SCF_PG_RESTARTER,
2368	    SCF_PG_RESTARTER_TYPE, SCF_PG_RESTARTER_FLAGS, pg);
2369	switch (ret) {
2370	case 0:
2371		break;
2372
2373	case ECONNABORTED:
2374	case ECANCELED:
2375	case EPERM:
2376	case EACCES:
2377	case EROFS:
2378		goto write_start_err;
2379
2380	default:
2381		bad_error("libscf_inst_get_or_add_pg", ret);
2382	}
2383
2384	scf_value_set_count(v_pid, pid);
2385
2386	ret = pg_set_prop_value(pg, SCF_PROPERTY_START_PID, v_pid);
2387	switch (ret) {
2388	case 0:
2389	case ECONNABORTED:
2390	case EPERM:
2391	case EACCES:
2392	case EROFS:
2393		break;
2394
2395	case ECANCELED:
2396		goto get_pg;
2397
2398	default:
2399		bad_error("pg_set_prop_value", ret);
2400	}
2401
2402write_start_err:
2403	scf_entry_destroy(t_pid);
2404	scf_value_destroy(v_pid);
2405	scf_pg_destroy(pg);
2406
2407	return (ret);
2408}
2409
2410/*
2411 * Add a property indicating the instance log file.  If the dir is
2412 * equal to LOG_PREFIX_EARLY, then the property restarter/alt_logfile
2413 * of the instance is used; otherwise, restarter/logfile is used.
2414 *
2415 * Returns
2416 *   0 - success
2417 *   ECONNABORTED
2418 *   ECANCELED
2419 *   EPERM
2420 *   EACCES
2421 *   EROFS
2422 *   EAGAIN
2423 */
2424int
2425libscf_note_method_log(scf_instance_t *inst, const char *dir, const char *file)
2426{
2427	scf_handle_t *h;
2428	scf_value_t *v;
2429	scf_propertygroup_t *pg;
2430	int ret = 0;
2431	char *logname;
2432	const char *propname;
2433
2434	h = scf_instance_handle(inst);
2435	pg = safe_scf_pg_create(h);
2436	v = safe_scf_value_create(h);
2437
2438	logname = uu_msprintf("%s%s", dir, file);
2439
2440	if (logname == NULL) {
2441		ret = errno;
2442		goto out;
2443	}
2444
2445	ret = libscf_inst_get_or_add_pg(inst, SCF_PG_RESTARTER,
2446	    SCF_PG_RESTARTER_TYPE, SCF_PG_RESTARTER_FLAGS, pg);
2447	switch (ret) {
2448	case 0:
2449		break;
2450
2451	case ECONNABORTED:
2452	case ECANCELED:
2453	case EPERM:
2454	case EACCES:
2455	case EROFS:
2456		goto out;
2457
2458	default:
2459		bad_error("libscf_inst_get_or_add_pg", ret);
2460	}
2461
2462	(void) scf_value_set_astring(v, logname);
2463
2464	if (strcmp(LOG_PREFIX_EARLY, dir) == 0)
2465		propname = SCF_PROPERTY_ALT_LOGFILE;
2466	else
2467		propname = SCF_PROPERTY_LOGFILE;
2468
2469	ret = pg_set_prop_value(pg, propname, v);
2470	switch (ret) {
2471	case 0:
2472	case ECONNABORTED:
2473	case ECANCELED:
2474	case EPERM:
2475	case EACCES:
2476	case EROFS:
2477		break;
2478
2479	default:
2480		bad_error("pg_set_prop_value", ret);
2481	}
2482
2483out:
2484	scf_pg_destroy(pg);
2485	scf_value_destroy(v);
2486	uu_free(logname);
2487	return (ret);
2488}
2489
2490/*
2491 * Returns
2492 *   0 - success
2493 *   ENAMETOOLONG - name is too long
2494 *   ECONNABORTED
2495 *   ECANCELED
2496 *   EPERM
2497 *   EACCES
2498 *   EROFS
2499 */
2500int
2501libscf_write_method_status(scf_instance_t *s_inst, const char *name,
2502    int status)
2503{
2504	scf_handle_t *h;
2505	scf_transaction_t *tx;
2506	scf_transaction_entry_t *e_time, *e_stat;
2507	scf_value_t *v_time, *v_stat;
2508	scf_propertygroup_t *pg;
2509	int ret = 0, r;
2510	char pname[30];
2511	struct timeval tv;
2512	scf_error_t scfe;
2513
2514	if (strlen(name) + sizeof ("_method_waitstatus") > sizeof (pname))
2515		return (ENAMETOOLONG);
2516
2517	h = scf_instance_handle(s_inst);
2518
2519	pg = safe_scf_pg_create(h);
2520	tx = safe_scf_transaction_create(h);
2521	e_time = safe_scf_entry_create(h);
2522	v_time = safe_scf_value_create(h);
2523	e_stat = safe_scf_entry_create(h);
2524	v_stat = safe_scf_value_create(h);
2525
2526get_pg:
2527	ret = libscf_inst_get_or_add_pg(s_inst, SCF_PG_RESTARTER,
2528	    SCF_PG_RESTARTER_TYPE, SCF_PG_RESTARTER_FLAGS, pg);
2529	switch (ret) {
2530	case 0:
2531		break;
2532
2533	case ECONNABORTED:
2534	case ECANCELED:
2535	case EPERM:
2536	case EACCES:
2537	case EROFS:
2538		goto out;
2539
2540	default:
2541		bad_error("libscf_inst_get_or_add_pg", ret);
2542	}
2543
2544	(void) gettimeofday(&tv, NULL);
2545
2546	r = scf_value_set_time(v_time, tv.tv_sec, tv.tv_usec * 1000);
2547	assert(r == 0);
2548
2549	scf_value_set_integer(v_stat, status);
2550
2551	for (;;) {
2552		if (scf_transaction_start(tx, pg) != 0) {
2553			switch (scf_error()) {
2554			case SCF_ERROR_CONNECTION_BROKEN:
2555			default:
2556				ret = ECONNABORTED;
2557				goto out;
2558
2559			case SCF_ERROR_DELETED:
2560				ret = ECANCELED;
2561				goto out;
2562
2563			case SCF_ERROR_PERMISSION_DENIED:
2564				ret = EPERM;
2565				goto out;
2566
2567			case SCF_ERROR_BACKEND_ACCESS:
2568				ret = EACCES;
2569				goto out;
2570
2571			case SCF_ERROR_BACKEND_READONLY:
2572				ret = EROFS;
2573				goto out;
2574
2575			case SCF_ERROR_NOT_SET:
2576				bad_error("scf_transaction_start", ret);
2577			}
2578		}
2579
2580		(void) snprintf(pname, sizeof (pname), "%s_method_timestamp",
2581		    name);
2582		ret = transaction_add_set(tx, e_time, pname, SCF_TYPE_TIME);
2583		switch (ret) {
2584		case 0:
2585			break;
2586
2587		case ECONNABORTED:
2588		case ECANCELED:
2589			goto out;
2590
2591		default:
2592			bad_error("transaction_add_set", ret);
2593		}
2594
2595		r = scf_entry_add_value(e_time, v_time);
2596		assert(r == 0);
2597
2598		(void) snprintf(pname, sizeof (pname), "%s_method_waitstatus",
2599		    name);
2600		ret = transaction_add_set(tx, e_stat, pname, SCF_TYPE_INTEGER);
2601		switch (ret) {
2602		case 0:
2603			break;
2604
2605		case ECONNABORTED:
2606		case ECANCELED:
2607			goto out;
2608
2609		default:
2610			bad_error("transaction_add_set", ret);
2611		}
2612
2613		r = scf_entry_add_value(e_stat, v_stat);
2614		if (r != 0)
2615			bad_error("scf_entry_add_value", scf_error());
2616
2617		r = scf_transaction_commit(tx);
2618		if (r == 1)
2619			break;
2620		if (r != 0) {
2621			scfe = scf_error();
2622			scf_transaction_reset_all(tx);
2623			switch (scfe) {
2624			case SCF_ERROR_CONNECTION_BROKEN:
2625			default:
2626				ret = ECONNABORTED;
2627				goto out;
2628
2629			case SCF_ERROR_DELETED:
2630				ret = ECANCELED;
2631				goto out;
2632
2633			case SCF_ERROR_PERMISSION_DENIED:
2634				ret = EPERM;
2635				goto out;
2636
2637			case SCF_ERROR_BACKEND_ACCESS:
2638				ret = EACCES;
2639				goto out;
2640
2641			case SCF_ERROR_BACKEND_READONLY:
2642				ret = EROFS;
2643				goto out;
2644
2645			case SCF_ERROR_NOT_SET:
2646				bad_error("scf_transaction_commit", scfe);
2647			}
2648		}
2649
2650		scf_transaction_reset_all(tx);
2651
2652		if (scf_pg_update(pg) == -1) {
2653			switch (scf_error()) {
2654			case SCF_ERROR_CONNECTION_BROKEN:
2655			default:
2656				ret = ECONNABORTED;
2657				goto out;
2658
2659			case SCF_ERROR_DELETED:
2660				ret = ECANCELED;
2661				goto out;
2662
2663			case SCF_ERROR_NOT_SET:
2664				bad_error("scf_pg_update", scf_error());
2665			}
2666		}
2667	}
2668
2669out:
2670	scf_transaction_destroy(tx);
2671	scf_entry_destroy(e_time);
2672	scf_value_destroy(v_time);
2673	scf_entry_destroy(e_stat);
2674	scf_value_destroy(v_stat);
2675	scf_pg_destroy(pg);
2676
2677	return (ret);
2678}
2679
2680/*
2681 * Call dgraph_add_instance() for each instance in the repository.
2682 */
2683void
2684libscf_populate_graph(scf_handle_t *h)
2685{
2686	scf_scope_t *scope;
2687	scf_service_t *svc;
2688	scf_instance_t *inst;
2689	scf_iter_t *svc_iter;
2690	scf_iter_t *inst_iter;
2691	int ret;
2692
2693	scope = safe_scf_scope_create(h);
2694	svc = safe_scf_service_create(h);
2695	inst = safe_scf_instance_create(h);
2696	svc_iter = safe_scf_iter_create(h);
2697	inst_iter = safe_scf_iter_create(h);
2698
2699	deathrow_init();
2700
2701	if ((ret = scf_handle_get_local_scope(h, scope)) !=
2702	    SCF_SUCCESS)
2703		uu_die("retrieving local scope failed: %d\n", ret);
2704
2705	if (scf_iter_scope_services(svc_iter, scope) == -1)
2706		uu_die("walking local scope's services failed\n");
2707
2708	while (scf_iter_next_service(svc_iter, svc) > 0) {
2709		if (scf_iter_service_instances(inst_iter, svc) == -1)
2710			uu_die("unable to walk service's instances");
2711
2712		while (scf_iter_next_instance(inst_iter, inst) > 0) {
2713			char *fmri;
2714
2715			if (libscf_instance_get_fmri(inst, &fmri) == 0) {
2716				int err;
2717
2718				err = dgraph_add_instance(fmri, inst, B_TRUE);
2719				if (err != 0 && err != EEXIST)
2720					log_error(LOG_WARNING,
2721					    "Failed to add %s (%s).\n", fmri,
2722					    strerror(err));
2723				startd_free(fmri, max_scf_fmri_size);
2724			}
2725		}
2726	}
2727
2728	deathrow_fini();
2729
2730	scf_iter_destroy(inst_iter);
2731	scf_iter_destroy(svc_iter);
2732	scf_instance_destroy(inst);
2733	scf_service_destroy(svc);
2734	scf_scope_destroy(scope);
2735}
2736
2737/*
2738 * Monitors get handled differently since there can be multiple of them.
2739 *
2740 * Returns exec string on success.  If method not defined, returns
2741 * LIBSCF_PGROUP_ABSENT; if exec property missing, returns
2742 * LIBSCF_PROPERTY_ABSENT.  Returns LIBSCF_PROPERTY_ERROR on other failures.
2743 */
2744char *
2745libscf_get_method(scf_handle_t *h, int type, restarter_inst_t *inst,
2746    scf_snapshot_t *snap, method_restart_t *restart_on, uint_t *cte_mask,
2747    uint8_t *need_sessionp, uint64_t *timeout, uint8_t *timeout_retry)
2748{
2749	scf_instance_t *scf_inst = NULL;
2750	scf_propertygroup_t *pg = NULL, *pg_startd = NULL;
2751	scf_property_t *prop = NULL;
2752	const char *name;
2753	char *method = startd_alloc(max_scf_value_size);
2754	char *ig = startd_alloc(max_scf_value_size);
2755	char *restart = startd_alloc(max_scf_value_size);
2756	char *ret;
2757	int error = 0, r;
2758
2759	scf_inst = safe_scf_instance_create(h);
2760	pg = safe_scf_pg_create(h);
2761	pg_startd = safe_scf_pg_create(h);
2762	prop = safe_scf_property_create(h);
2763
2764	ret = NULL;
2765
2766	*restart_on = METHOD_RESTART_UNKNOWN;
2767
2768	switch (type) {
2769	case METHOD_START:
2770		name = "start";
2771		break;
2772	case METHOD_STOP:
2773		name = "stop";
2774		break;
2775	case METHOD_REFRESH:
2776		name = "refresh";
2777		break;
2778	default:
2779		error = LIBSCF_PROPERTY_ERROR;
2780		goto get_method_cleanup;
2781	}
2782
2783	if (scf_handle_decode_fmri(h, inst->ri_i.i_fmri, NULL, NULL, scf_inst,
2784	    NULL, NULL, SCF_DECODE_FMRI_EXACT) == -1) {
2785		log_error(LOG_WARNING,
2786		    "%s: get_method decode instance FMRI failed: %s\n",
2787		    inst->ri_i.i_fmri, scf_strerror(scf_error()));
2788		error = LIBSCF_PROPERTY_ERROR;
2789		goto get_method_cleanup;
2790	}
2791
2792	if (scf_instance_get_pg_composed(scf_inst, snap, name, pg) == -1) {
2793		if (scf_error() == SCF_ERROR_NOT_FOUND)
2794			error = LIBSCF_PGROUP_ABSENT;
2795		else
2796			error = LIBSCF_PROPERTY_ERROR;
2797		goto get_method_cleanup;
2798	}
2799
2800	if (scf_pg_get_property(pg, SCF_PROPERTY_EXEC, prop) == -1) {
2801		if (scf_error() == SCF_ERROR_NOT_FOUND)
2802			error = LIBSCF_PROPERTY_ABSENT;
2803		else
2804			error = LIBSCF_PROPERTY_ERROR;
2805		goto get_method_cleanup;
2806	}
2807
2808	error = libscf_read_single_astring(h, prop, &method);
2809	if (error != 0) {
2810		log_error(LOG_WARNING,
2811		    "%s: get_method failed: can't get a single astring "
2812		    "from %s/%s\n", inst->ri_i.i_fmri, name, SCF_PROPERTY_EXEC);
2813		goto get_method_cleanup;
2814	}
2815
2816	error = expand_method_tokens(method, scf_inst, snap, type, &ret);
2817	if (error != 0) {
2818		log_instance(inst, B_TRUE, "Could not expand method tokens "
2819		    "in \"%s\": %s.", method, ret);
2820		error = LIBSCF_PROPERTY_ERROR;
2821		goto get_method_cleanup;
2822	}
2823
2824	r = get_count(pg, SCF_PROPERTY_TIMEOUT, timeout);
2825	switch (r) {
2826	case 0:
2827		break;
2828
2829	case ECONNABORTED:
2830		error = LIBSCF_PROPERTY_ERROR;
2831		goto get_method_cleanup;
2832
2833	case EINVAL:
2834		log_instance(inst, B_TRUE, "%s/%s is multi-valued or not of "
2835		    "type count.  Using infinite timeout.", name,
2836		    SCF_PROPERTY_TIMEOUT);
2837		/* FALLTHROUGH */
2838	case ECANCELED:
2839	case ENOENT:
2840		*timeout = METHOD_TIMEOUT_INFINITE;
2841		break;
2842
2843	case EACCES:
2844	default:
2845		bad_error("get_count", r);
2846	}
2847
2848	/* Both 0 and -1 (ugh) are considered infinite timeouts. */
2849	if (*timeout == -1 || *timeout == 0)
2850		*timeout = METHOD_TIMEOUT_INFINITE;
2851
2852	if (scf_instance_get_pg_composed(scf_inst, snap, SCF_PG_STARTD,
2853	    pg_startd) == -1) {
2854		switch (scf_error()) {
2855		case SCF_ERROR_CONNECTION_BROKEN:
2856		case SCF_ERROR_DELETED:
2857			error = LIBSCF_PROPERTY_ERROR;
2858			goto get_method_cleanup;
2859
2860		case SCF_ERROR_NOT_FOUND:
2861			*cte_mask = 0;
2862			break;
2863
2864		case SCF_ERROR_INVALID_ARGUMENT:
2865		case SCF_ERROR_HANDLE_MISMATCH:
2866		case SCF_ERROR_NOT_BOUND:
2867		case SCF_ERROR_NOT_SET:
2868			bad_error("scf_instance_get_pg_composed", scf_error());
2869		}
2870	} else {
2871		if (scf_pg_get_property(pg_startd, SCF_PROPERTY_IGNORE,
2872		    prop) == -1) {
2873			if (scf_error() == SCF_ERROR_NOT_FOUND)
2874				*cte_mask = 0;
2875			else {
2876				error = LIBSCF_PROPERTY_ERROR;
2877				goto get_method_cleanup;
2878			}
2879		} else {
2880			error = libscf_read_single_astring(h, prop, &ig);
2881			if (error != 0) {
2882				log_error(LOG_WARNING,
2883				    "%s: get_method failed: can't get a single "
2884				    "astring from %s/%s\n", inst->ri_i.i_fmri,
2885				    name, SCF_PROPERTY_IGNORE);
2886				goto get_method_cleanup;
2887			}
2888
2889			if (strcmp(ig, "core") == 0)
2890				*cte_mask = CT_PR_EV_CORE;
2891			else if (strcmp(ig, "signal") == 0)
2892				*cte_mask = CT_PR_EV_SIGNAL;
2893			else if (strcmp(ig, "core,signal") == 0 ||
2894			    strcmp(ig, "signal,core") == 0)
2895				*cte_mask = CT_PR_EV_CORE | CT_PR_EV_SIGNAL;
2896			else
2897				*cte_mask = 0;
2898		}
2899
2900		r = get_boolean(pg_startd, SCF_PROPERTY_NEED_SESSION,
2901		    need_sessionp);
2902		switch (r) {
2903		case 0:
2904			break;
2905
2906		case ECONNABORTED:
2907			error = LIBSCF_PROPERTY_ERROR;
2908			goto get_method_cleanup;
2909
2910		case ECANCELED:
2911		case ENOENT:
2912		case EINVAL:
2913			*need_sessionp = 0;
2914			break;
2915
2916		case EACCES:
2917		default:
2918			bad_error("get_boolean", r);
2919		}
2920
2921		/*
2922		 * Determine whether service has overriden retry after
2923		 * method timeout.  Default to retry if no value is
2924		 * specified.
2925		 */
2926		r = get_boolean(pg_startd, SCF_PROPERTY_TIMEOUT_RETRY,
2927		    timeout_retry);
2928		switch (r) {
2929		case 0:
2930			break;
2931
2932		case ECONNABORTED:
2933			error = LIBSCF_PROPERTY_ERROR;
2934			goto get_method_cleanup;
2935
2936		case ECANCELED:
2937		case ENOENT:
2938		case EINVAL:
2939			*timeout_retry = 1;
2940			break;
2941
2942		case EACCES:
2943		default:
2944			bad_error("get_boolean", r);
2945		}
2946	}
2947
2948	if (type != METHOD_START)
2949		goto get_method_cleanup;
2950
2951	/* Only start methods need to honor the restart_on property. */
2952
2953	if (scf_pg_get_property(pg, SCF_PROPERTY_RESTART_ON, prop) == -1) {
2954		if (scf_error() == SCF_ERROR_NOT_FOUND)
2955			*restart_on = METHOD_RESTART_ALL;
2956		else
2957			error = LIBSCF_PROPERTY_ERROR;
2958		goto get_method_cleanup;
2959	}
2960
2961	error = libscf_read_single_astring(h, prop, &restart);
2962	if (error != 0) {
2963		log_error(LOG_WARNING,
2964		    "%s: get_method failed: can't get a single astring "
2965		    "from %s/%s\n", inst->ri_i.i_fmri, name,
2966		    SCF_PROPERTY_RESTART_ON);
2967		goto get_method_cleanup;
2968	}
2969
2970	if (strcmp(restart, "all") == 0)
2971		*restart_on = METHOD_RESTART_ALL;
2972	else if (strcmp(restart, "external_fault") == 0)
2973		*restart_on = METHOD_RESTART_EXTERNAL_FAULT;
2974	else if (strcmp(restart, "any_fault") == 0)
2975		*restart_on = METHOD_RESTART_ANY_FAULT;
2976
2977get_method_cleanup:
2978	startd_free(ig, max_scf_value_size);
2979	startd_free(method, max_scf_value_size);
2980	startd_free(restart, max_scf_value_size);
2981
2982	scf_instance_destroy(scf_inst);
2983	scf_pg_destroy(pg);
2984	scf_pg_destroy(pg_startd);
2985	scf_property_destroy(prop);
2986
2987	if (error != 0 && ret != NULL) {
2988		free(ret);
2989		ret = NULL;
2990	}
2991
2992	errno = error;
2993	return (ret);
2994}
2995
2996/*
2997 * Returns 1 if we've reached the fault threshold
2998 */
2999int
3000update_fault_count(restarter_inst_t *inst, int type)
3001{
3002	assert(type == FAULT_COUNT_INCR || type == FAULT_COUNT_RESET);
3003
3004	if (type == FAULT_COUNT_INCR) {
3005		inst->ri_i.i_fault_count++;
3006		log_framework(LOG_INFO, "%s: Increasing fault count to %d\n",
3007		    inst->ri_i.i_fmri, inst->ri_i.i_fault_count);
3008	}
3009	if (type == FAULT_COUNT_RESET)
3010		inst->ri_i.i_fault_count = 0;
3011
3012	if (inst->ri_i.i_fault_count >= FAULT_THRESHOLD)
3013		return (1);
3014
3015	return (0);
3016}
3017
3018/*
3019 * int libscf_unset_action()
3020 *   Delete any pending timestamps for the specified action which is
3021 *   older than the supplied ts.
3022 *
3023 *   Returns 0 on success, ECONNABORTED, EACCES, or EPERM on failure.
3024 */
3025int
3026libscf_unset_action(scf_handle_t *h, scf_propertygroup_t *pg,
3027    admin_action_t a, hrtime_t ts)
3028{
3029	scf_transaction_t *t;
3030	scf_transaction_entry_t *e;
3031	scf_property_t *prop;
3032	scf_value_t *val;
3033	hrtime_t rep_ts;
3034	int ret = 0, r;
3035
3036	t = safe_scf_transaction_create(h);
3037	e = safe_scf_entry_create(h);
3038	prop = safe_scf_property_create(h);
3039	val = safe_scf_value_create(h);
3040
3041	for (;;) {
3042		if (scf_pg_update(pg) == -1) {
3043			switch (scf_error()) {
3044			case SCF_ERROR_CONNECTION_BROKEN:
3045			default:
3046				ret = ECONNABORTED;
3047				goto unset_action_cleanup;
3048
3049			case SCF_ERROR_DELETED:
3050				goto unset_action_cleanup;
3051
3052			case SCF_ERROR_NOT_SET:
3053				assert(0);
3054				abort();
3055			}
3056		}
3057
3058		if (scf_transaction_start(t, pg) == -1) {
3059			switch (scf_error()) {
3060			case SCF_ERROR_CONNECTION_BROKEN:
3061			default:
3062				ret = ECONNABORTED;
3063				goto unset_action_cleanup;
3064
3065			case SCF_ERROR_DELETED:
3066				goto unset_action_cleanup;
3067
3068			case SCF_ERROR_PERMISSION_DENIED:
3069				ret = EPERM;
3070				goto unset_action_cleanup;
3071
3072			case SCF_ERROR_BACKEND_ACCESS:
3073			case SCF_ERROR_BACKEND_READONLY:
3074				ret = EACCES;
3075				goto unset_action_cleanup;
3076
3077			case SCF_ERROR_IN_USE:
3078			case SCF_ERROR_HANDLE_MISMATCH:
3079			case SCF_ERROR_NOT_SET:
3080				assert(0);
3081				abort();
3082			}
3083		}
3084
3085		/* Return failure only if the property hasn't been deleted. */
3086		if (scf_pg_get_property(pg, admin_actions[a], prop) == -1) {
3087			switch (scf_error()) {
3088			case SCF_ERROR_CONNECTION_BROKEN:
3089			default:
3090				ret = ECONNABORTED;
3091				goto unset_action_cleanup;
3092
3093			case SCF_ERROR_DELETED:
3094			case SCF_ERROR_NOT_FOUND:
3095				goto unset_action_cleanup;
3096
3097			case SCF_ERROR_HANDLE_MISMATCH:
3098			case SCF_ERROR_INVALID_ARGUMENT:
3099			case SCF_ERROR_NOT_SET:
3100				assert(0);
3101				abort();
3102			}
3103		}
3104
3105		if (scf_property_get_value(prop, val) == -1) {
3106			switch (scf_error()) {
3107			case SCF_ERROR_CONNECTION_BROKEN:
3108			default:
3109				ret = ECONNABORTED;
3110				goto unset_action_cleanup;
3111
3112			case SCF_ERROR_DELETED:
3113			case SCF_ERROR_NOT_FOUND:
3114				goto unset_action_cleanup;
3115
3116			case SCF_ERROR_CONSTRAINT_VIOLATED:
3117				/*
3118				 * More than one value was associated with
3119				 * this property -- this is incorrect. Take
3120				 * the opportunity to clean up and clear the
3121				 * entire property.
3122				 */
3123				rep_ts = ts;
3124				break;
3125
3126			case SCF_ERROR_PERMISSION_DENIED:
3127			case SCF_ERROR_NOT_SET:
3128				assert(0);
3129				abort();
3130			}
3131		} else if (scf_value_get_integer(val, &rep_ts) == -1) {
3132			assert(scf_error() == SCF_ERROR_TYPE_MISMATCH);
3133			rep_ts = 0;
3134		}
3135
3136		/* Repository ts is more current. Don't clear the action. */
3137		if (rep_ts > ts)
3138			goto unset_action_cleanup;
3139
3140		r = scf_transaction_property_change_type(t, e,
3141		    admin_actions[a], SCF_TYPE_INTEGER);
3142		assert(r == 0);
3143
3144		r = scf_transaction_commit(t);
3145		if (r == 1)
3146			break;
3147
3148		if (r != 0) {
3149			switch (scf_error()) {
3150			case SCF_ERROR_CONNECTION_BROKEN:
3151			default:
3152				ret = ECONNABORTED;
3153				goto unset_action_cleanup;
3154
3155			case SCF_ERROR_DELETED:
3156				break;
3157
3158			case SCF_ERROR_PERMISSION_DENIED:
3159				ret = EPERM;
3160				goto unset_action_cleanup;
3161
3162			case SCF_ERROR_BACKEND_ACCESS:
3163			case SCF_ERROR_BACKEND_READONLY:
3164				ret = EACCES;
3165				goto unset_action_cleanup;
3166
3167			case SCF_ERROR_INVALID_ARGUMENT:
3168			case SCF_ERROR_NOT_SET:
3169				assert(0);
3170				abort();
3171			}
3172		}
3173
3174		scf_transaction_reset(t);
3175	}
3176
3177unset_action_cleanup:
3178	scf_transaction_destroy(t);
3179	scf_entry_destroy(e);
3180	scf_property_destroy(prop);
3181	scf_value_destroy(val);
3182
3183	return (ret);
3184}
3185
3186/*
3187 * Decorates & binds hndl.  hndl must be unbound.  Returns
3188 *   0 - success
3189 *   -1 - repository server is not running
3190 *   -1 - repository server is out of resources
3191 */
3192static int
3193handle_decorate_and_bind(scf_handle_t *hndl)
3194{
3195	scf_value_t *door_dec_value;
3196
3197	door_dec_value = safe_scf_value_create(hndl);
3198
3199	/*
3200	 * Decorate if alternate door path set.
3201	 */
3202	if (st->st_door_path) {
3203		if (scf_value_set_astring(door_dec_value, st->st_door_path) !=
3204		    0)
3205			uu_die("$STARTD_ALT_DOOR is too long.\n");
3206
3207		if (scf_handle_decorate(hndl, "door_path", door_dec_value) != 0)
3208			bad_error("scf_handle_decorate", scf_error());
3209	}
3210
3211	scf_value_destroy(door_dec_value);
3212
3213	if (scf_handle_bind(hndl) == 0)
3214		return (0);
3215
3216	switch (scf_error()) {
3217	case SCF_ERROR_NO_SERVER:
3218	case SCF_ERROR_NO_RESOURCES:
3219		return (-1);
3220
3221	case SCF_ERROR_INVALID_ARGUMENT:
3222	case SCF_ERROR_IN_USE:
3223	default:
3224		bad_error("scf_handle_bind", scf_error());
3225		/* NOTREACHED */
3226	}
3227}
3228
3229scf_handle_t *
3230libscf_handle_create_bound(scf_version_t v)
3231{
3232	scf_handle_t *hndl = scf_handle_create(v);
3233
3234	if (hndl == NULL)
3235		return (hndl);
3236
3237	if (handle_decorate_and_bind(hndl) == 0)
3238		return (hndl);
3239
3240	scf_handle_destroy(hndl);
3241	return (NULL);
3242}
3243
3244void
3245libscf_handle_rebind(scf_handle_t *h)
3246{
3247	(void) scf_handle_unbind(h);
3248
3249	MUTEX_LOCK(&st->st_configd_live_lock);
3250
3251	/*
3252	 * Try to rebind the handle before sleeping in case the server isn't
3253	 * really dead.
3254	 */
3255	while (handle_decorate_and_bind(h) != 0)
3256		(void) pthread_cond_wait(&st->st_configd_live_cv,
3257		    &st->st_configd_live_lock);
3258
3259	MUTEX_UNLOCK(&st->st_configd_live_lock);
3260}
3261
3262/*
3263 * Create a handle and try to bind it until it succeeds.  Always returns
3264 * a bound handle.
3265 */
3266scf_handle_t *
3267libscf_handle_create_bound_loop()
3268{
3269	scf_handle_t *h;
3270
3271	while ((h = scf_handle_create(SCF_VERSION)) == NULL) {
3272		/* This should have been caught earlier. */
3273		assert(scf_error() != SCF_ERROR_VERSION_MISMATCH);
3274		(void) sleep(2);
3275	}
3276
3277	if (handle_decorate_and_bind(h) != 0)
3278		libscf_handle_rebind(h);
3279
3280	return (h);
3281}
3282
3283/*
3284 * Call cb for each dependency property group of inst.  cb is invoked with
3285 * a pointer to the scf_propertygroup_t and arg.  If the repository connection
3286 * is broken, returns ECONNABORTED.  If inst is deleted, returns ECANCELED.
3287 * If cb returns non-zero, the walk is stopped and EINTR is returned.
3288 * Otherwise returns 0.
3289 */
3290int
3291walk_dependency_pgs(scf_instance_t *inst, callback_t cb, void *arg)
3292{
3293	scf_handle_t *h;
3294	scf_snapshot_t *snap;
3295	scf_iter_t *iter;
3296	scf_propertygroup_t *pg;
3297	int r;
3298
3299	h = scf_instance_handle(inst);
3300
3301	iter = safe_scf_iter_create(h);
3302	pg = safe_scf_pg_create(h);
3303
3304	snap = libscf_get_running_snapshot(inst);
3305
3306	if (scf_iter_instance_pgs_typed_composed(iter, inst, snap,
3307	    SCF_GROUP_DEPENDENCY) != 0) {
3308		scf_snapshot_destroy(snap);
3309		scf_pg_destroy(pg);
3310		scf_iter_destroy(iter);
3311		switch (scf_error()) {
3312		case SCF_ERROR_CONNECTION_BROKEN:
3313		default:
3314			return (ECONNABORTED);
3315
3316		case SCF_ERROR_DELETED:
3317			return (ECANCELED);
3318
3319		case SCF_ERROR_HANDLE_MISMATCH:
3320		case SCF_ERROR_INVALID_ARGUMENT:
3321		case SCF_ERROR_NOT_SET:
3322			assert(0);
3323			abort();
3324		}
3325	}
3326
3327	for (;;) {
3328		r = scf_iter_next_pg(iter, pg);
3329		if (r == 0)
3330			break;
3331		if (r == -1) {
3332			scf_snapshot_destroy(snap);
3333			scf_pg_destroy(pg);
3334			scf_iter_destroy(iter);
3335
3336			switch (scf_error()) {
3337			case SCF_ERROR_CONNECTION_BROKEN:
3338				return (ECONNABORTED);
3339
3340			case SCF_ERROR_DELETED:
3341				return (ECANCELED);
3342
3343			case SCF_ERROR_NOT_SET:
3344			case SCF_ERROR_INVALID_ARGUMENT:
3345			case SCF_ERROR_NOT_BOUND:
3346			case SCF_ERROR_HANDLE_MISMATCH:
3347			default:
3348				bad_error("scf_iter_next_pg", scf_error());
3349			}
3350		}
3351
3352		r = cb(pg, arg);
3353
3354		if (r != 0)
3355			break;
3356	}
3357
3358	scf_snapshot_destroy(snap);
3359	scf_pg_destroy(pg);
3360	scf_iter_destroy(iter);
3361
3362	return (r == 0 ? 0 : EINTR);
3363}
3364
3365/*
3366 * Call cb for each of the string values of prop.  cb is invoked with
3367 * a pointer to the string and arg.  If the connection to the repository is
3368 * broken, ECONNABORTED is returned.  If the property is deleted, ECANCELED is
3369 * returned.  If the property does not have astring type, EINVAL is returned.
3370 * If cb returns non-zero, the walk is stopped and EINTR is returned.
3371 * Otherwise 0 is returned.
3372 */
3373int
3374walk_property_astrings(scf_property_t *prop, callback_t cb, void *arg)
3375{
3376	scf_handle_t *h;
3377	scf_value_t *val;
3378	scf_iter_t *iter;
3379	char *buf;
3380	int r;
3381	ssize_t sz;
3382
3383	if (scf_property_is_type(prop, SCF_TYPE_ASTRING) != 0) {
3384		switch (scf_error()) {
3385		case SCF_ERROR_CONNECTION_BROKEN:
3386		default:
3387			return (ECONNABORTED);
3388
3389		case SCF_ERROR_DELETED:
3390			return (ECANCELED);
3391
3392		case SCF_ERROR_TYPE_MISMATCH:
3393			return (EINVAL);
3394
3395		case SCF_ERROR_NOT_SET:
3396			assert(0);
3397			abort();
3398		}
3399	}
3400
3401	h = scf_property_handle(prop);
3402
3403	val = safe_scf_value_create(h);
3404	iter = safe_scf_iter_create(h);
3405
3406	if (scf_iter_property_values(iter, prop) != 0) {
3407		scf_iter_destroy(iter);
3408		scf_value_destroy(val);
3409		switch (scf_error()) {
3410		case SCF_ERROR_CONNECTION_BROKEN:
3411		default:
3412			return (ECONNABORTED);
3413
3414		case SCF_ERROR_DELETED:
3415			return (ECANCELED);
3416
3417		case SCF_ERROR_HANDLE_MISMATCH:
3418		case SCF_ERROR_NOT_SET:
3419			assert(0);
3420			abort();
3421		}
3422	}
3423
3424	buf = startd_alloc(max_scf_value_size);
3425
3426	for (;;) {
3427		r = scf_iter_next_value(iter, val);
3428		if (r < 0) {
3429			startd_free(buf, max_scf_value_size);
3430			scf_iter_destroy(iter);
3431			scf_value_destroy(val);
3432
3433			switch (scf_error()) {
3434			case SCF_ERROR_CONNECTION_BROKEN:
3435				return (ECONNABORTED);
3436
3437			case SCF_ERROR_DELETED:
3438				return (ECANCELED);
3439
3440			case SCF_ERROR_NOT_SET:
3441			case SCF_ERROR_INVALID_ARGUMENT:
3442			case SCF_ERROR_NOT_BOUND:
3443			case SCF_ERROR_HANDLE_MISMATCH:
3444			case SCF_ERROR_PERMISSION_DENIED:
3445			default:
3446				bad_error("scf_iter_next_value", scf_error());
3447			}
3448		}
3449		if (r == 0)
3450			break;
3451
3452		sz = scf_value_get_astring(val, buf, max_scf_value_size);
3453		assert(sz >= 0);
3454
3455		r = cb(buf, arg);
3456
3457		if (r != 0)
3458			break;
3459	}
3460
3461	startd_free(buf, max_scf_value_size);
3462	scf_value_destroy(val);
3463	scf_iter_destroy(iter);
3464
3465	return (r == 0 ? 0 : EINTR);
3466}
3467
3468/*
3469 * Returns 0 or ECONNABORTED.
3470 */
3471int
3472libscf_create_self(scf_handle_t *h)
3473{
3474	scf_scope_t *scope;
3475	scf_service_t *svc;
3476	scf_instance_t *inst;
3477	instance_data_t idata;
3478	int ret = 0, r;
3479	ctid_t ctid;
3480	uint64_t uint64;
3481	uint_t count = 0, msecs = ALLOC_DELAY;
3482
3483	const char * const startd_svc = "system/svc/restarter";
3484	const char * const startd_inst = "default";
3485
3486	/* If SCF_SERVICE_STARTD changes, our strings must change, too. */
3487	assert(strcmp(SCF_SERVICE_STARTD,
3488	    "svc:/system/svc/restarter:default") == 0);
3489
3490	scope = safe_scf_scope_create(h);
3491	svc = safe_scf_service_create(h);
3492	inst = safe_scf_instance_create(h);
3493
3494	if (scf_handle_get_scope(h, SCF_SCOPE_LOCAL, scope) != 0) {
3495		assert(scf_error() == SCF_ERROR_CONNECTION_BROKEN);
3496		ret = ECONNABORTED;
3497		goto out;
3498	}
3499
3500get_svc:
3501	if (scf_scope_get_service(scope, startd_svc, svc) != 0) {
3502		switch (scf_error()) {
3503		case SCF_ERROR_CONNECTION_BROKEN:
3504		case SCF_ERROR_DELETED:
3505		default:
3506			ret = ECONNABORTED;
3507			goto out;
3508
3509		case SCF_ERROR_NOT_FOUND:
3510			break;
3511
3512		case SCF_ERROR_HANDLE_MISMATCH:
3513		case SCF_ERROR_INVALID_ARGUMENT:
3514		case SCF_ERROR_NOT_SET:
3515			bad_error("scf_scope_get_service", scf_error());
3516		}
3517
3518add_svc:
3519		if (scf_scope_add_service(scope, startd_svc, svc) != 0) {
3520			switch (scf_error()) {
3521			case SCF_ERROR_CONNECTION_BROKEN:
3522			case SCF_ERROR_DELETED:
3523			default:
3524				ret = ECONNABORTED;
3525				goto out;
3526
3527			case SCF_ERROR_EXISTS:
3528				goto get_svc;
3529
3530			case SCF_ERROR_PERMISSION_DENIED:
3531			case SCF_ERROR_BACKEND_ACCESS:
3532			case SCF_ERROR_BACKEND_READONLY:
3533				uu_warn("Could not create %s: %s\n",
3534				    SCF_SERVICE_STARTD,
3535				    scf_strerror(scf_error()));
3536				goto out;
3537
3538			case SCF_ERROR_HANDLE_MISMATCH:
3539			case SCF_ERROR_INVALID_ARGUMENT:
3540			case SCF_ERROR_NOT_SET:
3541				bad_error("scf_scope_add_service", scf_error());
3542			}
3543		}
3544	}
3545
3546	if (scf_service_get_instance(svc, startd_inst, NULL) == 0)
3547		goto out;
3548
3549	switch (scf_error()) {
3550	case SCF_ERROR_CONNECTION_BROKEN:
3551	default:
3552		ret = ECONNABORTED;
3553		goto out;
3554
3555	case SCF_ERROR_NOT_FOUND:
3556		break;
3557
3558	case SCF_ERROR_DELETED:
3559		goto add_svc;
3560
3561	case SCF_ERROR_HANDLE_MISMATCH:
3562	case SCF_ERROR_INVALID_ARGUMENT:
3563	case SCF_ERROR_NOT_SET:
3564		bad_error("scf_service_get_instance", scf_error());
3565	}
3566
3567add_inst:
3568	if (scf_service_add_instance(svc, startd_inst, inst) != 0) {
3569		switch (scf_error()) {
3570		case SCF_ERROR_CONNECTION_BROKEN:
3571		default:
3572			ret = ECONNABORTED;
3573			goto out;
3574
3575		case SCF_ERROR_EXISTS:
3576			break;
3577
3578		case SCF_ERROR_PERMISSION_DENIED:
3579		case SCF_ERROR_BACKEND_ACCESS:
3580			uu_die("Could not create %s: %s\n", SCF_SERVICE_STARTD,
3581			    scf_strerror(scf_error()));
3582			/* NOTREACHED */
3583
3584		case SCF_ERROR_BACKEND_READONLY:
3585			log_error(LOG_NOTICE,
3586			    "Could not create %s: backend readonly.\n",
3587			    SCF_SERVICE_STARTD);
3588			goto out;
3589
3590		case SCF_ERROR_DELETED:
3591			goto add_svc;
3592
3593		case SCF_ERROR_HANDLE_MISMATCH:
3594		case SCF_ERROR_INVALID_ARGUMENT:
3595		case SCF_ERROR_NOT_SET:
3596			bad_error("scf_service_add_instance", scf_error());
3597		}
3598	}
3599
3600	/* Set start time. */
3601	idata.i_fmri = SCF_SERVICE_STARTD;
3602	idata.i_state = RESTARTER_STATE_NONE;
3603	idata.i_next_state = RESTARTER_STATE_NONE;
3604set_state:
3605	switch (r = _restarter_commit_states(h, &idata, RESTARTER_STATE_ONLINE,
3606	    RESTARTER_STATE_NONE, NULL)) {
3607	case 0:
3608		break;
3609
3610	case ENOMEM:
3611		++count;
3612		if (count < ALLOC_RETRY) {
3613			(void) poll(NULL, 0, msecs);
3614			msecs *= ALLOC_DELAY_MULT;
3615			goto set_state;
3616		}
3617
3618		uu_die("Insufficient memory.\n");
3619		/* NOTREACHED */
3620
3621	case ECONNABORTED:
3622		ret = ECONNABORTED;
3623		goto out;
3624
3625	case ENOENT:
3626		goto add_inst;
3627
3628	case EPERM:
3629	case EACCES:
3630	case EROFS:
3631		uu_warn("Could not timestamp %s: %s\n", idata.i_fmri,
3632		    strerror(r));
3633		break;
3634
3635	case EINVAL:
3636	default:
3637		bad_error("_restarter_commit_states", r);
3638	}
3639
3640	/* Set general/enabled. */
3641	ret = libscf_inst_set_boolean_prop(inst, SCF_PG_GENERAL,
3642	    SCF_PG_GENERAL_TYPE, SCF_PG_GENERAL_FLAGS, SCF_PROPERTY_ENABLED, 1);
3643	switch (ret) {
3644	case 0:
3645	case ECONNABORTED:
3646	case EPERM:
3647	case EACCES:
3648	case EROFS:
3649		break;
3650
3651	case ECANCELED:
3652		goto add_inst;
3653
3654	default:
3655		bad_error("libscf_inst_set_boolean_prop", ret);
3656	}
3657
3658	ret = libscf_write_start_pid(inst, getpid());
3659	switch (ret) {
3660	case 0:
3661	case ECONNABORTED:
3662	case EPERM:
3663	case EACCES:
3664	case EROFS:
3665		break;
3666
3667	case ECANCELED:
3668		goto add_inst;
3669
3670	default:
3671		bad_error("libscf_write_start_pid", ret);
3672	}
3673
3674	ctid = proc_get_ctid();
3675	if (ctid > 0) {
3676
3677		uint64 = (uint64_t)ctid;
3678		ret = libscf_inst_set_count_prop(inst,
3679		    SCF_PG_RESTARTER, SCF_PG_RESTARTER_TYPE,
3680		    SCF_PG_RESTARTER_FLAGS, SCF_PROPERTY_CONTRACT, uint64);
3681
3682		switch (ret) {
3683		case 0:
3684		case ECONNABORTED:
3685		case EPERM:
3686		case EACCES:
3687		case EROFS:
3688			break;
3689
3690		case ECANCELED:
3691			goto add_inst;
3692
3693		default:
3694			bad_error("libscf_inst_set_count_prop", ret);
3695		}
3696	}
3697
3698	ret = libscf_note_method_log(inst, LOG_PREFIX_EARLY,
3699	    STARTD_DEFAULT_LOG);
3700	if (ret == 0) {
3701		ret = libscf_note_method_log(inst, LOG_PREFIX_NORMAL,
3702		    STARTD_DEFAULT_LOG);
3703	}
3704
3705	switch (ret) {
3706		case 0:
3707		case ECONNABORTED:
3708		case EPERM:
3709		case EACCES:
3710		case EROFS:
3711		case EAGAIN:
3712			break;
3713
3714		case ECANCELED:
3715			goto add_inst;
3716
3717		default:
3718			bad_error("libscf_note_method_log", ret);
3719	}
3720
3721out:
3722	scf_instance_destroy(inst);
3723	scf_service_destroy(svc);
3724	scf_scope_destroy(scope);
3725	return (ret);
3726}
3727
3728/*
3729 * Returns
3730 *   0 - success
3731 *   ENOENT - SCF_SERVICE_STARTD does not exist in repository
3732 *   EPERM
3733 *   EACCES
3734 *   EROFS
3735 */
3736int
3737libscf_set_reconfig(int set)
3738{
3739	scf_handle_t *h;
3740	scf_instance_t *inst;
3741	scf_propertygroup_t *pg;
3742	int ret = 0;
3743
3744	h = libscf_handle_create_bound_loop();
3745	inst = safe_scf_instance_create(h);
3746	pg = safe_scf_pg_create(h);
3747
3748again:
3749	if (scf_handle_decode_fmri(h, SCF_SERVICE_STARTD, NULL, NULL,
3750	    inst, NULL, NULL,  SCF_DECODE_FMRI_EXACT) == -1) {
3751		switch (scf_error()) {
3752		case SCF_ERROR_CONNECTION_BROKEN:
3753		default:
3754			libscf_handle_rebind(h);
3755			goto again;
3756
3757		case SCF_ERROR_NOT_FOUND:
3758			ret = ENOENT;
3759			goto reconfig_out;
3760
3761		case SCF_ERROR_HANDLE_MISMATCH:
3762		case SCF_ERROR_INVALID_ARGUMENT:
3763		case SCF_ERROR_CONSTRAINT_VIOLATED:
3764			bad_error("scf_handle_decode_fmri", scf_error());
3765		}
3766	}
3767
3768	ret = libscf_inst_set_boolean_prop(inst, "system", SCF_GROUP_FRAMEWORK,
3769	    SCF_PG_FLAG_NONPERSISTENT, "reconfigure", set);
3770	switch (ret) {
3771	case 0:
3772	case EPERM:
3773	case EACCES:
3774	case EROFS:
3775		break;
3776
3777	case ECONNABORTED:
3778		libscf_handle_rebind(h);
3779		goto again;
3780
3781	case ECANCELED:
3782		ret = ENOENT;
3783		break;
3784
3785	default:
3786		bad_error("libscf_inst_set_boolean_prop", ret);
3787	}
3788
3789reconfig_out:
3790	scf_pg_destroy(pg);
3791	scf_instance_destroy(inst);
3792	scf_handle_destroy(h);
3793	return (ret);
3794}
3795
3796/*
3797 * Set inst->ri_m_inst to the scf instance for inst.  If it has been deleted,
3798 * set inst->ri_mi_deleted to true.  If the repository connection is broken, it
3799 * is rebound with libscf_handle_rebound().
3800 */
3801void
3802libscf_reget_instance(restarter_inst_t *inst)
3803{
3804	scf_handle_t *h;
3805	int r;
3806
3807	h = scf_instance_handle(inst->ri_m_inst);
3808
3809again:
3810	r = libscf_lookup_instance(inst->ri_i.i_fmri, inst->ri_m_inst);
3811	switch (r) {
3812	case 0:
3813	case ENOENT:
3814		inst->ri_mi_deleted = (r == ENOENT);
3815		return;
3816
3817	case ECONNABORTED:
3818		libscf_handle_rebind(h);
3819		goto again;
3820
3821	case EINVAL:
3822	case ENOTSUP:
3823	default:
3824		bad_error("libscf_lookup_instance", r);
3825	}
3826}
3827