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