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