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