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