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