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