libscf.c revision 5777:e3276fcb93e7
1116742Ssam/*
2116904Ssam * CDDL HEADER START
3186904Ssam *
4116742Ssam * The contents of this file are subject to the terms of the
5116742Ssam * Common Development and Distribution License (the "License").
6116742Ssam * You may not use this file except in compliance with the License.
7116742Ssam *
8116742Ssam * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9116742Ssam * or http://www.opensolaris.org/os/licensing.
10116904Ssam * See the License for the specific language governing permissions
11116904Ssam * and limitations under the License.
12116904Ssam *
13116904Ssam * When distributing Covered Code, include this CDDL HEADER in each
14116742Ssam * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15116904Ssam * If applicable, add the following below this CDDL HEADER, with the
16116904Ssam * fields enclosed by brackets "[]" replaced with your own identifying
17116904Ssam * information: Portions Copyright [yyyy] [name of copyright owner]
18116904Ssam *
19116904Ssam * CDDL HEADER END
20116904Ssam */
21116904Ssam
22116904Ssam/*
23116904Ssam * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24116904Ssam * Use is subject to license terms.
25116742Ssam */
26116742Ssam
27116742Ssam#pragma ident	"%Z%%M%	%I%	%E% SMI"
28116742Ssam
29116742Ssam#include <sys/contract/process.h>
30116742Ssam#include <assert.h>
31116742Ssam#include <errno.h>
32116742Ssam#include <libscf.h>
33178354Ssam#include <libscf_priv.h>
34116742Ssam#include <poll.h>
35116742Ssam#include <stdlib.h>
36191746Sthompsa#include <string.h>
37116742Ssam#include <unistd.h>
38182742Sbrooks
39116742Ssam#include "startd.h"
40116742Ssam
41116742Ssam#define	SMF_SNAPSHOT_RUNNING	"running"
42178354Ssam
43116742Ssamchar *
44178354Ssaminst_fmri_to_svc_fmri(const char *fmri)
45116742Ssam{
46116742Ssam	char *buf, *sfmri;
47116742Ssam	const char *scope, *svc;
48178354Ssam	int r;
49190391Ssam	boolean_t local;
50190391Ssam
51190391Ssam	buf = startd_alloc(max_scf_fmri_size);
52116742Ssam	sfmri = startd_alloc(max_scf_fmri_size);
53116742Ssam
54116742Ssam	(void) strcpy(buf, fmri);
55178955Ssam
56178955Ssam	r = scf_parse_svc_fmri(buf, &scope, &svc, NULL, NULL, NULL);
57178955Ssam	assert(r == 0);
58178955Ssam
59178955Ssam	local = strcmp(scope, SCF_SCOPE_LOCAL) == 0;
60178955Ssam
61178955Ssam	(void) snprintf(sfmri, max_scf_fmri_size, "svc:%s%s/%s",
62178955Ssam	    local ? "" : "//", local ? "" : scope, svc);
63178955Ssam
64188782Ssam	startd_free(buf, max_scf_fmri_size);
65188782Ssam
66178955Ssam	return (sfmri);
67178955Ssam}
68116742Ssam
69178957Ssam/*
70178957Ssam * Wrapper for the scf_*_create() functions.  On SCF_ERROR_NO_MEMORY and
71178957Ssam * SCF_ERROR_NO_RESOURCES, retries or dies.  So this can only fail with
72178957Ssam * SCF_ERROR_INVALID_ARGUMENT, if h is NULL.
73178957Ssam */
74178957Ssamvoid *
75178957Ssamlibscf_object_create(void *f(scf_handle_t *), scf_handle_t *h)
76178957Ssam{
77195618Srpaulo	void *o;
78195618Srpaulo	uint_t try, msecs;
79195618Srpaulo	scf_error_t err;
80178957Ssam
81178957Ssam	o = f(h);
82178354Ssam	if (o != NULL)
83178354Ssam		return (o);
84116742Ssam	err = scf_error();
85178354Ssam	if (err != SCF_ERROR_NO_MEMORY && err != SCF_ERROR_NO_RESOURCES)
86193655Ssam		return (NULL);
87178354Ssam
88178354Ssam	msecs = ALLOC_DELAY;
89178354Ssam
90178354Ssam	for (try = 0; try < ALLOC_RETRY; ++try) {
91178354Ssam		(void) poll(NULL, 0, msecs);
92178354Ssam		msecs *= ALLOC_DELAY_MULT;
93178354Ssam		o = f(h);
94178354Ssam		if (o != NULL)
95178354Ssam			return (o);
96178354Ssam		err = scf_error();
97178354Ssam		if (err != SCF_ERROR_NO_MEMORY && err != SCF_ERROR_NO_RESOURCES)
98164645Ssam			return (NULL);
99164645Ssam	}
100164645Ssam
101164645Ssam	uu_die("Insufficient memory.\n");
102164645Ssam	/* NOTREACHED */
103164645Ssam}
104165569Ssam
105165569Ssamscf_snapshot_t *
106165569Ssamlibscf_get_running_snapshot(scf_instance_t *inst)
107165569Ssam{
108164645Ssam	scf_handle_t *h;
109164645Ssam	scf_snapshot_t *snap;
110164645Ssam
111164645Ssam	h = scf_instance_handle(inst);
112164645Ssam	if (h == NULL)
113164645Ssam		return (NULL);
114164645Ssam
115140915Ssam	snap = scf_snapshot_create(h);
116165569Ssam	if (snap == NULL)
117165569Ssam		return (NULL);
118165569Ssam
119165569Ssam	if (scf_instance_get_snapshot(inst, SMF_SNAPSHOT_RUNNING, snap) == 0)
120165569Ssam		return (snap);
121165569Ssam
122116742Ssam	scf_snapshot_destroy(snap);
123165569Ssam	return (NULL);
124188782Ssam}
125165574Ssam
126165569Ssam/*
127116742Ssam * Make sure a service has a "running" snapshot.  If it doesn't, make one from
128116742Ssam * the editing configuration.
129116742Ssam */
130186107Ssamscf_snapshot_t *
131170530Ssamlibscf_get_or_make_running_snapshot(scf_instance_t *inst, const char *fmri,
132116742Ssam    boolean_t retake)
133178354Ssam{
134167468Ssam	scf_handle_t *h;
135170530Ssam	scf_snapshot_t *snap;
136116742Ssam
137170530Ssam	h = scf_instance_handle(inst);
138187796Ssam
139187796Ssam	snap = scf_snapshot_create(h);
140187796Ssam	if (snap == NULL)
141187796Ssam		goto err;
142187796Ssam
143187796Ssam	if (scf_instance_get_snapshot(inst, SMF_SNAPSHOT_RUNNING, snap) == 0)
144187796Ssam		return (snap);
145187796Ssam
146187796Ssam	switch (scf_error()) {
147187796Ssam	case SCF_ERROR_NOT_FOUND:
148187796Ssam		break;
149187796Ssam
150187796Ssam	case SCF_ERROR_DELETED:
151187796Ssam		scf_snapshot_destroy(snap);
152187796Ssam		return (NULL);
153170530Ssam
154170530Ssam	default:
155170530Ssamerr:
156170530Ssam		log_error(LOG_NOTICE,
157170530Ssam		    "Could not check for running snapshot of %s (%s).\n", fmri,
158170530Ssam		    scf_strerror(scf_error()));
159170530Ssam		scf_snapshot_destroy(snap);
160170530Ssam		return (NULL);
161170530Ssam	}
162170530Ssam
163170530Ssam	if (_scf_snapshot_take_new(inst, SMF_SNAPSHOT_RUNNING, snap) == 0) {
164170530Ssam		log_framework(LOG_DEBUG, "Took running snapshot for %s.\n",
165170530Ssam		    fmri);
166170530Ssam	} else {
167170530Ssam		if (retake && scf_error() == SCF_ERROR_BACKEND_READONLY)
168170530Ssam			restarter_mark_pending_snapshot(fmri,
169170530Ssam			    RINST_RETAKE_RUNNING);
170170530Ssam		else
171188782Ssam			log_error(LOG_DEBUG,
172188782Ssam			    "Could not create running snapshot for %s "
173188782Ssam			    "(%s).\n", fmri, scf_strerror(scf_error()));
174188782Ssam
175170530Ssam		scf_snapshot_destroy(snap);
176170530Ssam		snap = NULL;
177170530Ssam	}
178170530Ssam
179116742Ssam	return (snap);
180170530Ssam}
181170530Ssam
182170530Ssam/*
183164645Ssam * When a service comes up, point the "start" snapshot at the "running"
184178354Ssam * snapshot.  Returns 0 on success, ENOTSUP if fmri designates something other
185178354Ssam * than an instance, ECONNABORTED, ENOENT if the instance does not exist, or
186178354Ssam * EACCES.
187178354Ssam */
188170530Ssamint
189172233Ssamlibscf_snapshots_poststart(scf_handle_t *h, const char *fmri, boolean_t retake)
190178354Ssam{
191170530Ssam	scf_instance_t *inst = NULL;
192170530Ssam	scf_snapshot_t *running, *start = NULL;
193190532Ssam	int ret = 0, r;
194170530Ssam
195164645Ssam	r = libscf_fmri_get_instance(h, fmri, &inst);
196165569Ssam	switch (r) {
197165569Ssam	case 0:
198165569Ssam		break;
199165569Ssam
200165569Ssam	case ENOTSUP:
201187897Ssam	case ECONNABORTED:
202188782Ssam	case ENOENT:
203188782Ssam		return (r);
204188774Ssam
205188774Ssam	case EINVAL:
206165569Ssam	default:
207165569Ssam		assert(0);
208165569Ssam		abort();
209165569Ssam	}
210165569Ssam
211165569Ssam	start = safe_scf_snapshot_create(h);
212165569Ssam
213165569Ssamagain:
214178354Ssam	running = libscf_get_or_make_running_snapshot(inst, fmri, retake);
215178354Ssam	if (running == NULL) {
216178354Ssam		ret = 0;
217178354Ssam		goto out;
218178354Ssam	}
219178354Ssam
220178354Ssamlookup:
221178354Ssam	if (scf_instance_get_snapshot(inst, "start", start) != 0) {
222178354Ssam		switch (scf_error()) {
223178354Ssam		case SCF_ERROR_CONNECTION_BROKEN:
224178354Ssam		default:
225178354Ssam			ret = ECONNABORTED;
226178521Ssam			goto out;
227178521Ssam
228191148Skmacy		case SCF_ERROR_NOT_FOUND:
229178521Ssam			if (_scf_snapshot_take_new(inst, "start", start) != 0) {
230178521Ssam				switch (scf_error()) {
231178521Ssam				case SCF_ERROR_CONNECTION_BROKEN:
232178521Ssam				default:
233178521Ssam					ret = ECONNABORTED;
234178521Ssam					goto out;
235178521Ssam
236178521Ssam				case SCF_ERROR_DELETED:
237178521Ssam					ret = ENOENT;
238178521Ssam					goto out;
239178521Ssam
240178521Ssam				case SCF_ERROR_EXISTS:
241178521Ssam					goto lookup;
242178354Ssam
243178354Ssam				case SCF_ERROR_NO_RESOURCES:
244178354Ssam					uu_die("Repository server out of "
245178354Ssam					    "resources.\n");
246165569Ssam					/* NOTREACHED */
247190526Ssam
248190526Ssam				case SCF_ERROR_BACKEND_READONLY:
249165569Ssam					goto readonly;
250165569Ssam
251178354Ssam				case SCF_ERROR_PERMISSION_DENIED:
252178354Ssam					uu_die("Insufficient privileges.\n");
253165569Ssam					/* NOTREACHED */
254178354Ssam
255165569Ssam				case SCF_ERROR_BACKEND_ACCESS:
256179388Ssam					ret = EACCES;
257178354Ssam					goto out;
258191746Sthompsa
259191746Sthompsa				case SCF_ERROR_HANDLE_MISMATCH:
260191746Sthompsa				case SCF_ERROR_INTERNAL:
261191746Sthompsa				case SCF_ERROR_INVALID_ARGUMENT:
262191746Sthompsa				case SCF_ERROR_NOT_SET:
263191746Sthompsa					bad_error("_scf_snapshot_take_new",
264165569Ssam					    scf_error());
265165569Ssam				}
266165569Ssam			}
267165569Ssam			break;
268165569Ssam
269178354Ssam		case SCF_ERROR_DELETED:
270170530Ssam			ret = ENOENT;
271178354Ssam			goto out;
272178354Ssam
273116742Ssam		case SCF_ERROR_HANDLE_MISMATCH:
274195379Ssam		case SCF_ERROR_NOT_SET:
275155688Ssam		case SCF_ERROR_INVALID_ARGUMENT:
276155688Ssam			bad_error("scf_instance_get_snapshot", scf_error());
277138568Ssam		}
278138568Ssam	}
279170530Ssam
280138568Ssam	if (_scf_snapshot_attach(running, start) == 0) {
281170530Ssam		log_framework(LOG_DEBUG, "Updated \"start\" snapshot for %s.\n",
282138568Ssam		    fmri);
283190391Ssam	} else {
284190391Ssam		switch (scf_error()) {
285190391Ssam		case SCF_ERROR_CONNECTION_BROKEN:
286170530Ssam		default:
287170530Ssam			ret = ECONNABORTED;
288178354Ssam			goto out;
289193843Ssam
290138568Ssam		case SCF_ERROR_DELETED:
291178354Ssam			scf_snapshot_destroy(running);
292138568Ssam			goto again;
293178354Ssam
294178354Ssam		case SCF_ERROR_NO_RESOURCES:
295178354Ssam			uu_die("Repository server out of resources.\n");
296178354Ssam			/* NOTREACHED */
297178354Ssam
298178521Ssam		case SCF_ERROR_PERMISSION_DENIED:
299178521Ssam			uu_die("Insufficient privileges.\n");
300178521Ssam			/* NOTREACHED */
301140915Ssam
302178354Ssam		case SCF_ERROR_BACKEND_ACCESS:
303178354Ssam			ret = EACCES;
304178354Ssam			goto out;
305178354Ssam
306178354Ssam		case SCF_ERROR_BACKEND_READONLY:
307190526Ssamreadonly:
308194760Srwatson			if (retake)
309116742Ssam				restarter_mark_pending_snapshot(fmri,
310116742Ssam				    RINST_RETAKE_START);
311178354Ssam			break;
312178354Ssam
313178354Ssam		case SCF_ERROR_HANDLE_MISMATCH:
314178354Ssam		case SCF_ERROR_NOT_SET:
315178354Ssam			bad_error("_scf_snapshot_attach", scf_error());
316178354Ssam		}
317116742Ssam	}
318138568Ssam
319116742Ssamout:
320138568Ssam	scf_snapshot_destroy(start);
321178354Ssam	scf_snapshot_destroy(running);
322116742Ssam	scf_instance_destroy(inst);
323193337Ssam
324193337Ssam	return (ret);
325178354Ssam}
326178354Ssam
327188533Sthompsa/*
328138568Ssam * Before a refresh, update the "running" snapshot from the editing
329138568Ssam * configuration.
330193843Ssam *
331178354Ssam * Returns 0 on success and -1 on failure.
332170530Ssam */
333190391Ssamint
334190391Ssamlibscf_snapshots_refresh(scf_instance_t *inst, const char *fmri)
335190391Ssam{
336170530Ssam	scf_handle_t *h;
337166012Ssam	scf_snapshot_t *snap;
338138568Ssam	boolean_t err = 1;
339138568Ssam
340170530Ssam	h = scf_instance_handle(inst);
341138568Ssam	if (h == NULL)
342193337Ssam		goto out;
343116742Ssam
344191746Sthompsa	snap = scf_snapshot_create(h);
345170530Ssam	if (snap == NULL)
346178354Ssam		goto out;
347138568Ssam
348178354Ssam	if (scf_instance_get_snapshot(inst, SMF_SNAPSHOT_RUNNING, snap) == 0) {
349178354Ssam		if (_scf_snapshot_take_attach(inst, snap) == 0)
350178354Ssam			err = 0;
351178354Ssam	} else {
352178354Ssam		switch (scf_error()) {
353178354Ssam		case SCF_ERROR_DELETED:
354178354Ssam			err = 0;
355178354Ssam			goto out;
356178354Ssam
357178354Ssam		case SCF_ERROR_NOT_FOUND:
358178354Ssam			break;
359178354Ssam
360178354Ssam		case SCF_ERROR_NOT_SET:
361178354Ssam			assert(0);
362178354Ssam			abort();
363178354Ssam			/* NOTREACHED */
364178354Ssam
365178354Ssam		default:
366178354Ssam			goto out;
367178354Ssam		}
368178354Ssam
369178354Ssam		log_error(LOG_DEBUG,
370178354Ssam		    "Service %s has no %s snapshot; creating one.\n", fmri,
371178354Ssam		    SMF_SNAPSHOT_RUNNING);
372178354Ssam
373178354Ssam		if (_scf_snapshot_take_new(inst, SMF_SNAPSHOT_RUNNING,
374178354Ssam		    snap) == 0)
375178354Ssam			err = 0;
376178354Ssam	}
377178354Ssam
378178354Ssamout:
379178354Ssam	scf_snapshot_destroy(snap);
380178354Ssam
381178354Ssam	if (!err)
382178354Ssam		return (0);
383178354Ssam
384178354Ssam	log_error(LOG_WARNING,
385178354Ssam	    "Could not update \"running\" snapshot for refresh of %s.\n", fmri);
386178354Ssam	return (-1);
387178354Ssam}
388178354Ssam
389178354Ssam/*
390178354Ssam * int libscf_read_single_astring()
391178354Ssam *   Reads a single astring value of the requested property into the
392178354Ssam *   pre-allocated buffer (conventionally of size max_scf_value_size).
393178354Ssam *   Multiple values constitute an error.
394178354Ssam *
395178354Ssam * Returns 0 on success or LIBSCF_PROPERTY_ABSENT or LIBSCF_PROPERTY_ERROR.
396178354Ssam */
397178354Ssamstatic int
398178354Ssamlibscf_read_single_astring(scf_handle_t *h, scf_property_t *prop, char **ret)
399178354Ssam{
400178354Ssam	scf_value_t *val = safe_scf_value_create(h);
401178354Ssam	int r = 0;
402178957Ssam
403178354Ssam	if (scf_property_get_value(prop, val) == -1) {
404178354Ssam		if (scf_error() == SCF_ERROR_NOT_FOUND)
405178354Ssam			r = LIBSCF_PROPERTY_ABSENT;
406178354Ssam		else
407178354Ssam			r = LIBSCF_PROPERTY_ERROR;
408178354Ssam		goto read_single_astring_fail;
409178354Ssam	}
410178354Ssam
411178354Ssam	if (scf_value_get_astring(val, *ret, max_scf_value_size) <= 0) {
412178354Ssam		r = LIBSCF_PROPERTY_ERROR;
413178354Ssam		goto read_single_astring_fail;
414178354Ssam	}
415178354Ssam
416178354Ssamread_single_astring_fail:
417178354Ssam	scf_value_destroy(val);
418186904Ssam	return (r);
419186904Ssam}
420186904Ssam
421186904Ssamstatic int
422186904Ssamlibscf_read_state(const scf_propertygroup_t *pg, const char *prop_name,
423186904Ssam    restarter_instance_state_t *state)
424186904Ssam{
425186904Ssam	scf_handle_t *h;
426186904Ssam	scf_property_t *prop;
427186904Ssam	char *char_state = startd_alloc(max_scf_value_size);
428186904Ssam	int ret = 0;
429186904Ssam
430186904Ssam	h = scf_pg_handle(pg);
431186904Ssam	prop = safe_scf_property_create(h);
432186904Ssam
433178354Ssam	if (scf_pg_get_property(pg, prop_name, prop) == -1) {
434184278Ssam		if (scf_error() == SCF_ERROR_NOT_FOUND)
435184278Ssam			ret = LIBSCF_PROPERTY_ABSENT;
436184278Ssam		else
437178354Ssam			ret = LIBSCF_PROPERTY_ERROR;
438178354Ssam	} else {
439178354Ssam		ret = libscf_read_single_astring(h, prop, &char_state);
440178354Ssam		if (ret != 0) {
441178354Ssam			if (ret != LIBSCF_PROPERTY_ABSENT)
442178354Ssam				ret = LIBSCF_PROPERTY_ERROR;
443178354Ssam		} else {
444178354Ssam			*state = restarter_string_to_state(char_state);
445178354Ssam			ret = 0;
446178354Ssam		}
447178354Ssam	}
448178354Ssam
449178957Ssam	startd_free(char_state, max_scf_value_size);
450178954Ssam	scf_property_destroy(prop);
451178954Ssam	return (ret);
452178954Ssam}
453178354Ssam
454178354Ssam/*
455178354Ssam * int libscf_read_states(const scf_propertygroup_t *,
456178354Ssam *   restarter_instance_state_t *, restarter_instance_state_t *)
457178354Ssam *
458178354Ssam *   Set the current state and next_state values for the given service instance.
459178354Ssam *   Returns 0 on success, or a libscf error code on failure.
460178354Ssam */
461178354Ssamint
462178354Ssamlibscf_read_states(const scf_propertygroup_t *pg,
463178354Ssam    restarter_instance_state_t *state, restarter_instance_state_t *next_state)
464178354Ssam{
465178354Ssam	int state_ret, next_state_ret, ret;
466178354Ssam
467178354Ssam	state_ret = libscf_read_state(pg, SCF_PROPERTY_STATE, state);
468178354Ssam	next_state_ret = libscf_read_state(pg, SCF_PROPERTY_NEXT_STATE,
469178354Ssam	    next_state);
470178354Ssam
471190391Ssam	if (state_ret == LIBSCF_PROPERTY_ERROR ||
472190391Ssam	    next_state_ret == LIBSCF_PROPERTY_ERROR) {
473190391Ssam		ret = LIBSCF_PROPERTY_ERROR;
474178354Ssam	} else if (state_ret == 0 && next_state_ret == 0) {
475178354Ssam		ret = 0;
476178354Ssam	} else if (state_ret == LIBSCF_PROPERTY_ABSENT &&
477192468Ssam	    next_state_ret == LIBSCF_PROPERTY_ABSENT) {
478178354Ssam		*state = RESTARTER_STATE_UNINIT;
479178354Ssam		*next_state = RESTARTER_STATE_NONE;
480178354Ssam		ret = 0;
481178354Ssam	} else if (state_ret == LIBSCF_PROPERTY_ABSENT ||
482178354Ssam	    next_state_ret == LIBSCF_PROPERTY_ABSENT) {
483178354Ssam		log_framework(LOG_DEBUG,
484178354Ssam		    "Only one repository state exists, setting "
485178354Ssam		    "restarter states to MAINTENANCE and NONE\n");
486178354Ssam		*state = RESTARTER_STATE_MAINT;
487178354Ssam		*next_state = RESTARTER_STATE_NONE;
488178354Ssam		ret = 0;
489178354Ssam	} else {
490178354Ssam		ret = LIBSCF_PROPERTY_ERROR;
491178354Ssam	}
492178354Ssam
493178354Ssamread_states_out:
494178354Ssam	return (ret);
495178354Ssam}
496178354Ssam
497178354Ssam/*
498178354Ssam * depgroup_empty()
499178354Ssam *
500178354Ssam * Returns 0 if not empty.
501178354Ssam * Returns 1 if empty.
502178354Ssam * Returns -1 on error (check scf_error()).
503178354Ssam */
504178354Ssamint
505178354Ssamdepgroup_empty(scf_handle_t *h, scf_propertygroup_t *pg)
506178354Ssam{
507178354Ssam	int empty = 1;
508178354Ssam	scf_iter_t *iter;
509178354Ssam	scf_property_t *prop;
510178354Ssam	int ret;
511178354Ssam
512188106Ssam	iter = safe_scf_iter_create(h);
513188106Ssam	prop = safe_scf_property_create(h);
514178354Ssam
515178354Ssam	if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS) {
516178354Ssam		scf_property_destroy(prop);
517178354Ssam		scf_iter_destroy(iter);
518178354Ssam		return (-1);
519178354Ssam	}
520178354Ssam
521178354Ssam	ret = scf_iter_next_property(iter, prop);
522178354Ssam	if (ret < 0) {
523178354Ssam		scf_property_destroy(prop);
524178354Ssam		scf_iter_destroy(iter);
525178354Ssam		return (-1);
526190391Ssam	}
527178354Ssam
528190391Ssam	if (ret == 1)
529178354Ssam		empty = 0;
530178354Ssam
531193655Ssam	scf_property_destroy(prop);
532193655Ssam	scf_iter_destroy(iter);
533178354Ssam
534178354Ssam	return (empty);
535178354Ssam}
536178354Ssam
537178354Ssamgv_type_t
538178354Ssamdepgroup_read_scheme(scf_handle_t *h, scf_propertygroup_t *pg)
539178354Ssam{
540178354Ssam	scf_property_t *prop;
541178354Ssam	char *scheme = startd_alloc(max_scf_value_size);
542178354Ssam	gv_type_t ret;
543178354Ssam
544178354Ssam	prop = safe_scf_property_create(h);
545178354Ssam
546178354Ssam	if (scf_pg_get_property(pg, SCF_PROPERTY_TYPE, prop) == -1 ||
547178354Ssam	    libscf_read_single_astring(h, prop, &scheme) != 0) {
548178354Ssam		scf_property_destroy(prop);
549178354Ssam		startd_free(scheme, max_scf_value_size);
550178354Ssam		return (GVT_UNSUPPORTED);
551178354Ssam	}
552178354Ssam
553178354Ssam	if (strcmp(scheme, "service") == 0)
554178354Ssam		ret = GVT_INST;
555178354Ssam	else if (strcmp(scheme, "path") == 0)
556193312Ssam		ret = GVT_FILE;
557193312Ssam	else
558178354Ssam		ret = GVT_UNSUPPORTED;
559193312Ssam
560193312Ssam	startd_free(scheme, max_scf_value_size);
561191746Sthompsa	scf_property_destroy(prop);
562191746Sthompsa	return (ret);
563191746Sthompsa}
564191746Sthompsa
565191746Sthompsadepgroup_type_t
566191746Sthompsadepgroup_read_grouping(scf_handle_t *h, scf_propertygroup_t *pg)
567191746Sthompsa{
568191746Sthompsa	char *grouping = startd_alloc(max_scf_value_size);
569191746Sthompsa	depgroup_type_t ret;
570178354Ssam	scf_property_t *prop = safe_scf_property_create(h);
571178354Ssam
572190391Ssam	if (scf_pg_get_property(pg, SCF_PROPERTY_GROUPING, prop) == -1 ||
573178354Ssam	    libscf_read_single_astring(h, prop, &grouping) != 0) {
574190391Ssam		scf_property_destroy(prop);
575178354Ssam		startd_free(grouping, max_scf_value_size);
576178354Ssam		return (DEPGRP_UNSUPPORTED);
577193655Ssam	}
578193655Ssam
579192468Ssam	if (strcmp(grouping, SCF_DEP_REQUIRE_ANY) == 0)
580192468Ssam		ret = DEPGRP_REQUIRE_ANY;
581178354Ssam	else if (strcmp(grouping, SCF_DEP_REQUIRE_ALL) == 0)
582178354Ssam		ret = DEPGRP_REQUIRE_ALL;
583178354Ssam	else if (strcmp(grouping, SCF_DEP_OPTIONAL_ALL) == 0)
584178354Ssam		ret = DEPGRP_OPTIONAL_ALL;
585178354Ssam	else if (strcmp(grouping, SCF_DEP_EXCLUDE_ALL) == 0)
586178354Ssam		ret = DEPGRP_EXCLUDE_ALL;
587192468Ssam	else {
588178354Ssam		ret = DEPGRP_UNSUPPORTED;
589178354Ssam	}
590190391Ssam	startd_free(grouping, max_scf_value_size);
591190391Ssam	scf_property_destroy(prop);
592190391Ssam	return (ret);
593178354Ssam}
594178354Ssam
595178354Ssamrestarter_error_t
596178354Ssamdepgroup_read_restart(scf_handle_t *h, scf_propertygroup_t *pg)
597178354Ssam{
598178354Ssam	scf_property_t *prop = safe_scf_property_create(h);
599178354Ssam	char *restart_on = startd_alloc(max_scf_value_size);
600182674Sweongyo	restarter_error_t ret;
601182674Sweongyo
602116742Ssam	if (scf_pg_get_property(pg, SCF_PROPERTY_RESTART_ON, prop) == -1 ||
603116742Ssam	    libscf_read_single_astring(h, prop, &restart_on) != 0) {
604178354Ssam		startd_free(restart_on, max_scf_value_size);
605178354Ssam		scf_property_destroy(prop);
606178354Ssam		return (RERR_UNSUPPORTED);
607178354Ssam	}
608178354Ssam
609178354Ssam	if (strcmp(restart_on, SCF_DEP_RESET_ON_ERROR) == 0)
610178354Ssam		ret = RERR_FAULT;
611178354Ssam	else if (strcmp(restart_on, SCF_DEP_RESET_ON_RESTART) == 0)
612178354Ssam		ret = RERR_RESTART;
613178354Ssam	else if (strcmp(restart_on, SCF_DEP_RESET_ON_REFRESH) == 0)
614178354Ssam		ret = RERR_REFRESH;
615178354Ssam	else if (strcmp(restart_on, SCF_DEP_RESET_ON_NONE) == 0)
616178354Ssam		ret = RERR_NONE;
617178354Ssam	else
618178354Ssam		ret = RERR_UNSUPPORTED;
619178354Ssam
620178354Ssam	startd_free(restart_on, max_scf_value_size);
621178354Ssam	scf_property_destroy(prop);
622178354Ssam	return (ret);
623178354Ssam}
624178354Ssam
625178354Ssam/*
626178354Ssam * int get_boolean()
627178354Ssam *   Fetches the value of a boolean property of the given property group.
628178354Ssam *   Returns
629178354Ssam *     0 - success
630178354Ssam *     ECONNABORTED - repository connection broken
631178354Ssam *     ECANCELED - pg was deleted
632178354Ssam *     ENOENT - the property doesn't exist or has no values
633178354Ssam *     EINVAL - the property has the wrong type
634178354Ssam *		the property is not single-valued
635178354Ssam *     EACCES - the current user does not have permission to read the value
636178354Ssam */
637178354Ssamstatic int
638178354Ssamget_boolean(scf_propertygroup_t *pg, const char *propname, uint8_t *valuep)
639178354Ssam{
640178354Ssam	scf_handle_t *h;
641191746Sthompsa	scf_property_t *prop;
642178354Ssam	scf_value_t *val;
643191746Sthompsa	int ret = 0, r;
644178354Ssam	scf_type_t type;
645178354Ssam
646178354Ssam	h = scf_pg_handle(pg);
647178354Ssam	prop = safe_scf_property_create(h);
648178354Ssam	val = safe_scf_value_create(h);
649178354Ssam
650178354Ssam	if (scf_pg_get_property(pg, propname, prop) != 0) {
651178354Ssam		switch (scf_error()) {
652178354Ssam		case SCF_ERROR_CONNECTION_BROKEN:
653178354Ssam		default:
654178354Ssam			ret = ECONNABORTED;
655178354Ssam			goto out;
656178354Ssam
657178354Ssam		case SCF_ERROR_DELETED:
658178354Ssam			ret = ECANCELED;
659178354Ssam			goto out;
660178354Ssam
661178354Ssam		case SCF_ERROR_NOT_FOUND:
662178354Ssam			ret = ENOENT;
663178354Ssam			goto out;
664178354Ssam
665178354Ssam		case SCF_ERROR_HANDLE_MISMATCH:
666178354Ssam		case SCF_ERROR_INVALID_ARGUMENT:
667178354Ssam		case SCF_ERROR_NOT_SET:
668178354Ssam			bad_error("scf_pg_get_property", scf_error());
669178354Ssam		}
670178354Ssam	}
671178354Ssam
672178354Ssam	if (scf_property_type(prop, &type) != 0) {
673178354Ssam		switch (scf_error()) {
674178354Ssam		case SCF_ERROR_CONNECTION_BROKEN:
675178354Ssam		default:
676178354Ssam			ret = ECONNABORTED;
677178354Ssam			goto out;
678178354Ssam
679178354Ssam		case SCF_ERROR_DELETED:
680178354Ssam			ret = ENOENT;
681178354Ssam			goto out;
682178354Ssam
683178354Ssam		case SCF_ERROR_NOT_SET:
684178354Ssam			bad_error("scf_property_type", scf_error());
685178354Ssam		}
686178354Ssam	}
687178354Ssam
688178354Ssam	if (type != SCF_TYPE_BOOLEAN) {
689193655Ssam		ret = EINVAL;
690178354Ssam		goto out;
691178354Ssam	}
692178354Ssam
693178354Ssam	if (scf_property_get_value(prop, val) != 0) {
694193655Ssam		switch (scf_error()) {
695193655Ssam		case SCF_ERROR_CONNECTION_BROKEN:
696193655Ssam		default:
697193655Ssam			ret = ECONNABORTED;
698193655Ssam			goto out;
699193655Ssam
700193655Ssam		case SCF_ERROR_DELETED:
701193655Ssam		case SCF_ERROR_NOT_FOUND:
702193655Ssam			ret = ENOENT;
703193655Ssam			goto out;
704193655Ssam
705193655Ssam		case SCF_ERROR_CONSTRAINT_VIOLATED:
706193655Ssam			ret = EINVAL;
707193655Ssam			goto out;
708193655Ssam
709193655Ssam		case SCF_ERROR_PERMISSION_DENIED:
710193655Ssam			ret = EACCES;
711193655Ssam			goto out;
712193655Ssam
713193655Ssam		case SCF_ERROR_NOT_SET:
714193655Ssam			bad_error("scf_property_get_value", scf_error());
715193655Ssam		}
716193655Ssam	}
717193655Ssam
718193655Ssam	r = scf_value_get_boolean(val, valuep);
719193655Ssam	assert(r == 0);
720193655Ssam
721193655Ssamout:
722193655Ssam	scf_value_destroy(val);
723193655Ssam	scf_property_destroy(prop);
724193655Ssam	return (ret);
725193655Ssam}
726193655Ssam
727193655Ssam/*
728193655Ssam * int get_count()
729193655Ssam *   Fetches the value of a count property of the given property group.
730193655Ssam *   Returns
731193655Ssam *     0 - success
732193655Ssam *     ECONNABORTED - repository connection broken
733193655Ssam *                    unknown libscf error
734178354Ssam *     ECANCELED - pg was deleted
735178354Ssam *     ENOENT - the property doesn't exist or has no values
736178354Ssam *     EINVAL - the property has the wrong type
737178354Ssam *              the property is not single-valued
738178354Ssam *     EACCES - the current user does not have permission to read the value
739178354Ssam */
740178354Ssamstatic int
741178354Ssamget_count(scf_propertygroup_t *pg, const char *propname, uint64_t *valuep)
742178354Ssam{
743178354Ssam	scf_handle_t *h;
744178354Ssam	scf_property_t *prop;
745178354Ssam	scf_value_t *val;
746178354Ssam	int ret = 0, r;
747178354Ssam
748178354Ssam	h = scf_pg_handle(pg);
749178354Ssam	prop = safe_scf_property_create(h);
750178354Ssam	val = safe_scf_value_create(h);
751178354Ssam
752178354Ssam	if (scf_pg_get_property(pg, propname, prop) != 0) {
753178354Ssam		switch (scf_error()) {
754178354Ssam		case SCF_ERROR_CONNECTION_BROKEN:
755178354Ssam		default:
756178354Ssam			ret = ECONNABORTED;
757178354Ssam			goto out;
758178354Ssam
759178354Ssam		case SCF_ERROR_DELETED:
760178354Ssam			ret = ECANCELED;
761178354Ssam			goto out;
762178354Ssam
763178354Ssam		case SCF_ERROR_NOT_FOUND:
764178354Ssam			ret = ENOENT;
765178354Ssam			goto out;
766178354Ssam
767178354Ssam		case SCF_ERROR_HANDLE_MISMATCH:
768166012Ssam		case SCF_ERROR_INVALID_ARGUMENT:
769166012Ssam		case SCF_ERROR_NOT_SET:
770166012Ssam			bad_error("scf_pg_get_property", scf_error());
771166012Ssam		}
772166012Ssam	}
773166012Ssam
774166012Ssam	if (scf_property_is_type(prop, SCF_TYPE_COUNT) != 0) {
775166012Ssam		switch (scf_error()) {
776166012Ssam		case SCF_ERROR_CONNECTION_BROKEN:
777166012Ssam		default:
778166012Ssam			ret = ECONNABORTED;
779166012Ssam			goto out;
780166012Ssam
781166012Ssam		case SCF_ERROR_TYPE_MISMATCH:
782166012Ssam			ret = EINVAL;
783166012Ssam			goto out;
784166012Ssam
785166012Ssam		case SCF_ERROR_DELETED:
786166012Ssam			ret = ECANCELED;
787166012Ssam			goto out;
788116742Ssam
789116742Ssam		case SCF_ERROR_INVALID_ARGUMENT:
790116742Ssam		case SCF_ERROR_NOT_BOUND:
791152450Ssam		case SCF_ERROR_NOT_SET:
792116742Ssam			bad_error("scf_property_is_type", scf_error());
793116742Ssam		}
794167430Ssam	}
795166012Ssam
796166012Ssam	if (scf_property_get_value(prop, val) != 0) {
797116742Ssam		switch (scf_error()) {
798116742Ssam		case SCF_ERROR_CONNECTION_BROKEN:
799116742Ssam		default:
800116742Ssam			ret = ECONNABORTED;
801152450Ssam			goto out;
802116742Ssam
803116742Ssam		case SCF_ERROR_DELETED:
804116899Ssam			ret = ECANCELED;
805165569Ssam			goto out;
806170530Ssam
807167430Ssam		case SCF_ERROR_NOT_FOUND:
808166012Ssam			ret = ENOENT;
809152450Ssam			goto out;
810165569Ssam
811152450Ssam		case SCF_ERROR_CONSTRAINT_VIOLATED:
812116742Ssam			ret = EINVAL;
813116742Ssam			goto out;
814116742Ssam
815166012Ssam		case SCF_ERROR_PERMISSION_DENIED:
816166012Ssam			ret = EACCES;
817166012Ssam			goto out;
818152450Ssam
819166012Ssam		case SCF_ERROR_NOT_SET:
820152450Ssam			bad_error("scf_property_get_value", scf_error());
821167430Ssam		}
822166012Ssam	}
823165569Ssam
824152450Ssam	r = scf_value_get_count(val, valuep);
825152450Ssam	assert(r == 0);
826152450Ssam
827152450Ssamout:
828116742Ssam	scf_value_destroy(val);
829116742Ssam	scf_property_destroy(prop);
830167430Ssam	return (ret);
831116742Ssam}
832116742Ssam
833116742Ssam
834116742Ssamstatic void
835116742Ssamget_restarter(scf_handle_t *h, scf_propertygroup_t *pg, char **restarter)
836152450Ssam{
837165825Smjacob	scf_property_t *prop = safe_scf_property_create(h);
838116742Ssam
839170530Ssam	if (scf_pg_get_property(pg, SCF_PROPERTY_RESTARTER, prop) == -1 ||
840138568Ssam	    libscf_read_single_astring(h, prop, restarter) != 0)
841117039Ssam		*restarter[0] = '\0';
842116742Ssam
843170530Ssam	scf_property_destroy(prop);
844116742Ssam}
845116742Ssam
846116742Ssam/*
847116742Ssam * int libscf_instance_get_fmri(scf_instance_t *, char **)
848116742Ssam *   Give a valid SCF instance, return its FMRI.  Returns 0 on success,
849116742Ssam *   ECONNABORTED, or ECANCELED if inst is deleted.
850116742Ssam */
851116742Ssamint
852166012Ssamlibscf_instance_get_fmri(scf_instance_t *inst, char **retp)
853166012Ssam{
854116742Ssam	char *inst_fmri = startd_alloc(max_scf_fmri_size);
855116742Ssam
856116742Ssam	inst_fmri[0] = 0;
857116742Ssam	if (scf_instance_to_fmri(inst, inst_fmri, max_scf_fmri_size) <= 0) {
858116742Ssam		startd_free(inst_fmri, max_scf_fmri_size);
859116742Ssam		switch (scf_error()) {
860116742Ssam		case SCF_ERROR_CONNECTION_BROKEN:
861116742Ssam		default:
862165569Ssam			return (ECONNABORTED);
863165569Ssam
864165569Ssam		case SCF_ERROR_DELETED:
865165569Ssam			return (ECANCELED);
866116742Ssam
867116742Ssam		case SCF_ERROR_NOT_SET:
868166012Ssam			assert(0);
869116742Ssam			abort();
870116742Ssam		}
871116742Ssam	}
872116742Ssam
873116742Ssam	*retp = inst_fmri;
874116742Ssam	return (0);
875116742Ssam}
876116742Ssam
877116742Ssam/*
878116742Ssam * int libscf_fmri_get_instance(scf_handle_t *, const char *,
879116742Ssam *	scf_instance_t **)
880170530Ssam *   Given a valid SCF handle and an FMRI, return the SCF instance that matches
881178354Ssam *   exactly.  The instance must be released using scf_instance_destroy().
882170530Ssam *   Returns 0 on success, EINVAL if the FMRI is invalid, ENOTSUP if the FMRI
883170530Ssam *   is valid but designates something other than an instance, ECONNABORTED if
884170530Ssam *   the repository connection is broken, or ENOENT if the instance does not
885170530Ssam *   exist.
886170530Ssam */
887170530Ssamint
888170530Ssamlibscf_fmri_get_instance(scf_handle_t *h, const char *fmri,
889170530Ssam    scf_instance_t **instp)
890170530Ssam{
891170530Ssam	scf_instance_t *inst;
892170530Ssam	int r;
893170530Ssam
894170530Ssam	inst = safe_scf_instance_create(h);
895170530Ssam
896170530Ssam	r = libscf_lookup_instance(fmri, inst);
897170530Ssam
898170530Ssam	if (r == 0)
899170530Ssam		*instp = inst;
900170530Ssam	else
901170530Ssam		scf_instance_destroy(inst);
902170530Ssam
903170530Ssam	return (r);
904170530Ssam}
905173861Ssam
906173861Ssamint
907173861Ssamlibscf_lookup_instance(const char *fmri, scf_instance_t *inst)
908173861Ssam{
909173861Ssam	if (scf_handle_decode_fmri(scf_instance_handle(inst), fmri, NULL, NULL,
910173861Ssam	    inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
911173861Ssam		switch (scf_error()) {
912173861Ssam		case SCF_ERROR_INVALID_ARGUMENT:
913173861Ssam			return (EINVAL);
914173861Ssam
915173861Ssam		case SCF_ERROR_CONSTRAINT_VIOLATED:
916173861Ssam			return (ENOTSUP);
917173861Ssam
918173861Ssam		case SCF_ERROR_CONNECTION_BROKEN:
919173861Ssam			return (ECONNABORTED);
920173861Ssam
921173861Ssam		case SCF_ERROR_NOT_FOUND:
922173861Ssam			return (ENOENT);
923173861Ssam
924173861Ssam		case SCF_ERROR_HANDLE_MISMATCH:
925173861Ssam		default:
926173861Ssam			bad_error("scf_handle_decode_fmri", scf_error());
927173861Ssam		}
928173861Ssam	}
929173861Ssam
930173861Ssam	return (0);
931170530Ssam}
932178354Ssam
933170530Ssam/*
934170530Ssam * void libscf_get_basic_instance_data()
935178354Ssam *   Read enabled, enabled_ovr, and restarter_fmri (into an allocated
936170530Ssam *   buffer) for inst.  Returns 0, ECONNABORTED if the connection to the
937170530Ssam *   repository is broken, ECANCELED if inst is deleted, or ENOENT if inst
938188106Ssam *   has no general property group.
939188106Ssam *
940188106Ssam *   On success, restarter_fmri may be NULL.  If general/enabled was missing
941188106Ssam *   or invalid, *enabledp will be -1 and a debug message is logged.
942188106Ssam */
943188106Ssamint
944188106Ssamlibscf_get_basic_instance_data(scf_handle_t *h, scf_instance_t *inst,
945188106Ssam    const char *fmri, int *enabledp, int *enabled_ovrp, char **restarter_fmri)
946188782Ssam{
947188782Ssam	scf_propertygroup_t *pg;
948188106Ssam	int r;
949188106Ssam	uint8_t enabled_8;
950170530Ssam
951170530Ssam	pg = safe_scf_pg_create(h);
952170530Ssam
953170530Ssam	if (enabled_ovrp == NULL)
954178354Ssam		goto enabled;
955178354Ssam
956178354Ssam	if (scf_instance_get_pg_composed(inst, NULL, SCF_PG_GENERAL_OVR, pg) !=
957178354Ssam	    0) {
958178354Ssam		switch (scf_error()) {
959178354Ssam		case SCF_ERROR_CONNECTION_BROKEN:
960178354Ssam		default:
961178354Ssam			scf_pg_destroy(pg);
962178354Ssam			return (ECONNABORTED);
963178354Ssam
964178354Ssam		case SCF_ERROR_DELETED:
965178354Ssam			scf_pg_destroy(pg);
966195618Srpaulo			return (ECANCELED);
967195618Srpaulo
968170530Ssam		case SCF_ERROR_NOT_FOUND:
969170530Ssam			*enabled_ovrp = -1;
970170530Ssam			break;
971170530Ssam
972116742Ssam		case SCF_ERROR_HANDLE_MISMATCH:
973178354Ssam		case SCF_ERROR_INVALID_ARGUMENT:
974116742Ssam		case SCF_ERROR_NOT_SET:
975178354Ssam			bad_error("scf_instance_get_pg_composed", scf_error());
976178354Ssam		}
977178354Ssam	} else {
978116742Ssam		switch (r = get_boolean(pg, SCF_PROPERTY_ENABLED, &enabled_8)) {
979116742Ssam		case 0:
980170530Ssam			*enabled_ovrp = enabled_8;
981170530Ssam			break;
982116742Ssam
983116742Ssam		case ECONNABORTED:
984118887Ssam		case ECANCELED:
985116742Ssam			scf_pg_destroy(pg);
986116742Ssam			return (r);
987178354Ssam
988116742Ssam		case ENOENT:
989170530Ssam		case EINVAL:
990170530Ssam			*enabled_ovrp = -1;
991170530Ssam			break;
992116742Ssam
993170530Ssam		case EACCES:
994167468Ssam		default:
995116742Ssam			bad_error("get_boolean", r);
996178354Ssam		}
997116742Ssam	}
998116742Ssam
999116742Ssamenabled:
1000116742Ssam	/*
1001116742Ssam	 * Since general/restarter can be at the service level, we must do
1002116742Ssam	 * a composed lookup.  These properties are immediate, though, so we
1003116742Ssam	 * must use the "editing" snapshot.  Technically enabled shouldn't be
1004116742Ssam	 * at the service level, but looking it up composed, too, doesn't
1005178354Ssam	 * hurt.
1006116742Ssam	 */
1007170530Ssam	if (scf_instance_get_pg_composed(inst, NULL, SCF_PG_GENERAL, pg) != 0) {
1008116742Ssam		scf_pg_destroy(pg);
1009116742Ssam		switch (scf_error()) {
1010116742Ssam		case SCF_ERROR_CONNECTION_BROKEN:
1011116742Ssam		default:
1012116742Ssam			return (ECONNABORTED);
1013116742Ssam
1014116742Ssam		case SCF_ERROR_DELETED:
1015116742Ssam			return (ECANCELED);
1016116742Ssam
1017116742Ssam		case SCF_ERROR_NOT_FOUND:
1018116742Ssam			return (ENOENT);
1019116742Ssam
1020116742Ssam		case SCF_ERROR_NOT_SET:
1021116742Ssam			bad_error("scf_instance_get_pg_composed", scf_error());
1022116742Ssam		}
1023116742Ssam	}
1024116742Ssam
1025116742Ssam	switch (r = get_boolean(pg, SCF_PROPERTY_ENABLED, &enabled_8)) {
1026116742Ssam	case 0:
1027116742Ssam		*enabledp = enabled_8;
1028170530Ssam		break;
1029178354Ssam
1030178354Ssam	case ECONNABORTED:
1031116742Ssam	case ECANCELED:
1032170530Ssam		scf_pg_destroy(pg);
1033170530Ssam		return (r);
1034170530Ssam
1035170530Ssam	case ENOENT:
1036170530Ssam		/*
1037170530Ssam		 * DEBUG because this happens when svccfg import creates
1038188782Ssam		 * a temporary service.
1039170530Ssam		 */
1040170530Ssam		log_framework(LOG_DEBUG,
1041178354Ssam		    "general/enabled property of %s is missing.\n", fmri);
1042178354Ssam		*enabledp = -1;
1043170530Ssam		break;
1044170530Ssam
1045170530Ssam	case EINVAL:
1046178354Ssam		log_framework(LOG_ERR,
1047178354Ssam		    "general/enabled property of %s is invalid.\n", fmri);
1048170530Ssam		*enabledp = -1;
1049170530Ssam		break;
1050178354Ssam
1051178354Ssam	case EACCES:
1052170530Ssam	default:
1053178354Ssam		bad_error("get_boolean", r);
1054178354Ssam	}
1055116742Ssam
1056178354Ssam	if (restarter_fmri != NULL)
1057178354Ssam		get_restarter(h, pg, restarter_fmri);
1058178354Ssam
1059178354Ssam	scf_pg_destroy(pg);
1060178354Ssam
1061178354Ssam	return (0);
1062178354Ssam}
1063178354Ssam
1064178354Ssam
1065178354Ssam/*
1066178354Ssam * Sets pg to the name property group of s_inst.  If it doesn't exist, it is
1067178354Ssam * added.
1068178354Ssam *
1069178354Ssam * Fails with
1070178354Ssam *   ECONNABORTED - repository disconnection or unknown libscf error
1071178354Ssam *   ECANCELED - inst is deleted
1072178354Ssam *   EPERM - permission is denied
1073178354Ssam *   EACCES - backend denied access
1074178354Ssam *   EROFS - backend readonly
1075178354Ssam */
1076178354Ssamint
1077178354Ssamlibscf_inst_get_or_add_pg(scf_instance_t *inst, const char *name,
1078178354Ssam    const char *type, uint32_t flags, scf_propertygroup_t *pg)
1079170530Ssam{
1080170530Ssam	uint32_t f;
1081188106Ssam
1082188106Ssamagain:
1083116742Ssam	if (scf_instance_get_pg(inst, name, pg) == 0) {
1084116742Ssam		if (scf_pg_get_flags(pg, &f) != 0) {
1085178354Ssam			switch (scf_error()) {
1086178354Ssam			case SCF_ERROR_CONNECTION_BROKEN:
1087116742Ssam			default:
1088116742Ssam				return (ECONNABORTED);
1089188782Ssam
1090165569Ssam			case SCF_ERROR_DELETED:
1091165569Ssam				goto add;
1092165569Ssam
1093188774Ssam			case SCF_ERROR_NOT_SET:
1094170530Ssam				bad_error("scf_pg_get_flags", scf_error());
1095165569Ssam			}
1096165569Ssam		}
1097138568Ssam
1098138568Ssam		if (f == flags)
1099138568Ssam			return (0);
1100138568Ssam
1101138568Ssam		if (scf_pg_delete(pg) != 0) {
1102170530Ssam			switch (scf_error()) {
1103138568Ssam			case SCF_ERROR_CONNECTION_BROKEN:
1104172227Ssam			default:
1105172227Ssam				return (ECONNABORTED);
1106167468Ssam
1107138568Ssam			case SCF_ERROR_DELETED:
1108138568Ssam				break;
1109138568Ssam
1110138568Ssam			case SCF_ERROR_PERMISSION_DENIED:
1111170530Ssam				return (EPERM);
1112138568Ssam
1113138568Ssam			case SCF_ERROR_BACKEND_ACCESS:
1114170530Ssam				return (EACCES);
1115138568Ssam
1116170530Ssam			case SCF_ERROR_BACKEND_READONLY:
1117138568Ssam				return (EROFS);
1118138568Ssam
1119138568Ssam			case SCF_ERROR_NOT_SET:
1120170530Ssam				bad_error("scf_pg_delete", scf_error());
1121138568Ssam			}
1122138568Ssam		}
1123170530Ssam	} else {
1124170530Ssam		switch (scf_error()) {
1125116742Ssam		case SCF_ERROR_CONNECTION_BROKEN:
1126170530Ssam		default:
1127170530Ssam			return (ECONNABORTED);
1128170530Ssam
1129170530Ssam		case SCF_ERROR_DELETED:
1130170530Ssam			return (ECANCELED);
1131170530Ssam
1132170530Ssam		case SCF_ERROR_NOT_FOUND:
1133170530Ssam			break;
1134170530Ssam
1135170530Ssam		case SCF_ERROR_HANDLE_MISMATCH:
1136170530Ssam		case SCF_ERROR_INVALID_ARGUMENT:
1137170530Ssam		case SCF_ERROR_NOT_SET:
1138170530Ssam			bad_error("scf_instance_get_pg", scf_error());
1139170530Ssam		}
1140170530Ssam	}
1141170530Ssam
1142170530Ssamadd:
1143170530Ssam	if (scf_instance_add_pg(inst, name, type, flags, pg) == 0)
1144170530Ssam		return (0);
1145170530Ssam
1146170530Ssam	switch (scf_error()) {
1147170530Ssam	case SCF_ERROR_CONNECTION_BROKEN:
1148170530Ssam	default:
1149170530Ssam		return (ECONNABORTED);
1150170530Ssam
1151170530Ssam	case SCF_ERROR_DELETED:
1152170530Ssam		return (ECANCELED);
1153170530Ssam
1154170530Ssam	case SCF_ERROR_EXISTS:
1155170530Ssam		goto again;
1156170530Ssam
1157170530Ssam	case SCF_ERROR_PERMISSION_DENIED:
1158170530Ssam		return (EPERM);
1159170530Ssam
1160170530Ssam	case SCF_ERROR_BACKEND_ACCESS:
1161170530Ssam		return (EACCES);
1162170530Ssam
1163170530Ssam	case SCF_ERROR_BACKEND_READONLY:
1164170530Ssam		return (EROFS);
1165170530Ssam
1166170530Ssam	case SCF_ERROR_HANDLE_MISMATCH:
1167116742Ssam	case SCF_ERROR_INVALID_ARGUMENT:
1168116742Ssam	case SCF_ERROR_NOT_SET:
1169170530Ssam		bad_error("scf_instance_add_pg", scf_error());
1170184273Ssam		/* NOTREACHED */
1171170530Ssam	}
1172116742Ssam}
1173116742Ssam
1174178354Ssam/*
1175116742Ssam * Returns
1176116742Ssam *   0 - success
1177178354Ssam *   ECONNABORTED - repository connection broken
1178116742Ssam *		  - unknown libscf error
1179116742Ssam *   ECANCELED
1180178354Ssam */
1181116742Ssamstatic scf_error_t
1182124543Sonoetransaction_add_set(scf_transaction_t *tx, scf_transaction_entry_t *ent,
1183178354Ssam    const char *pname, scf_type_t ty)
1184124543Sonoe{
1185170530Ssam	for (;;) {
1186178354Ssam		if (scf_transaction_property_change_type(tx, ent, pname,
1187170530Ssam		    ty) == 0)
1188170530Ssam			return (0);
1189178354Ssam
1190170530Ssam		switch (scf_error()) {
1191116742Ssam		case SCF_ERROR_CONNECTION_BROKEN:
1192178354Ssam		default:
1193116742Ssam			return (ECONNABORTED);
1194116742Ssam
1195178354Ssam		case SCF_ERROR_DELETED:
1196116742Ssam			return (ECANCELED);
1197116742Ssam
1198138568Ssam		case SCF_ERROR_NOT_FOUND:
1199138568Ssam			break;
1200116742Ssam
1201116742Ssam		case SCF_ERROR_HANDLE_MISMATCH:
1202178354Ssam		case SCF_ERROR_INVALID_ARGUMENT:
1203184273Ssam		case SCF_ERROR_IN_USE:
1204178354Ssam		case SCF_ERROR_NOT_SET:
1205170530Ssam			bad_error("scf_transaction_property_change_type",
1206178354Ssam			    scf_error());
1207178354Ssam		}
1208178354Ssam
1209138568Ssam		if (scf_transaction_property_new(tx, ent, pname, ty) == 0)
1210178354Ssam			return (0);
1211116742Ssam
1212170530Ssam		switch (scf_error()) {
1213178354Ssam		case SCF_ERROR_CONNECTION_BROKEN:
1214178354Ssam		default:
1215116742Ssam			return (ECONNABORTED);
1216178354Ssam
1217184273Ssam		case SCF_ERROR_DELETED:
1218178354Ssam			return (ECANCELED);
1219178354Ssam
1220178354Ssam		case SCF_ERROR_EXISTS:
1221178354Ssam			break;
1222184273Ssam
1223178354Ssam		case SCF_ERROR_HANDLE_MISMATCH:
1224116742Ssam		case SCF_ERROR_INVALID_ARGUMENT:
1225178354Ssam		case SCF_ERROR_IN_USE:
1226178354Ssam		case SCF_ERROR_NOT_SET:
1227178354Ssam			bad_error("scf_transaction_property_new", scf_error());
1228178354Ssam			/* NOTREACHED */
1229178354Ssam		}
1230178354Ssam	}
1231178354Ssam}
1232178354Ssam
1233184273Ssam/*
1234178354Ssam * Returns
1235184273Ssam *   0 - success
1236178354Ssam *   ECONNABORTED - repository connection broken
1237184273Ssam *		  - unknown libscf error
1238184273Ssam *   ECANCELED - pg was deleted
1239193340Ssam *   EPERM
1240178354Ssam *   EACCES
1241178354Ssam *   EROFS
1242116742Ssam */
1243116742Ssamstatic int
1244170530Ssampg_set_prop_value(scf_propertygroup_t *pg, const char *pname, scf_value_t *v)
1245170530Ssam{
1246170530Ssam	scf_handle_t *h;
1247170530Ssam	scf_transaction_t *tx;
1248170530Ssam	scf_transaction_entry_t *e;
1249170530Ssam	scf_type_t ty;
1250170530Ssam	scf_error_t scfe;
1251170530Ssam	int ret, r;
1252170530Ssam
1253170530Ssam	h = scf_pg_handle(pg);
1254170530Ssam	tx = safe_scf_transaction_create(h);
1255170530Ssam	e = safe_scf_entry_create(h);
1256170530Ssam
1257170530Ssam	ty = scf_value_type(v);
1258170530Ssam	assert(ty != SCF_TYPE_INVALID);
1259170530Ssam
1260170530Ssam	for (;;) {
1261170530Ssam		if (scf_transaction_start(tx, pg) != 0) {
1262170530Ssam			switch (scf_error()) {
1263170530Ssam			case SCF_ERROR_CONNECTION_BROKEN:
1264170530Ssam			default:
1265170530Ssam				ret = ECONNABORTED;
1266170530Ssam				goto out;
1267170530Ssam
1268170530Ssam			case SCF_ERROR_DELETED:
1269170530Ssam				ret = ECANCELED;
1270178354Ssam				goto out;
1271170530Ssam
1272195618Srpaulo			case SCF_ERROR_PERMISSION_DENIED:
1273195618Srpaulo				ret = EPERM;
1274195618Srpaulo				goto out;
1275170530Ssam
1276170530Ssam			case SCF_ERROR_BACKEND_ACCESS:
1277170530Ssam				ret = EACCES;
1278170530Ssam				goto out;
1279170530Ssam
1280170530Ssam			case SCF_ERROR_BACKEND_READONLY:
1281170530Ssam				ret = EROFS;
1282170530Ssam				goto out;
1283170530Ssam
1284170530Ssam			case SCF_ERROR_NOT_SET:
1285170530Ssam				bad_error("scf_transaction_start", ret);
1286170530Ssam			}
1287170530Ssam		}
1288170530Ssam
1289170530Ssam		ret = transaction_add_set(tx, e, pname, ty);
1290170530Ssam		switch (ret) {
1291170530Ssam		case 0:
1292170530Ssam			break;
1293178354Ssam
1294178354Ssam		case ECONNABORTED:
1295178354Ssam		case ECANCELED:
1296178354Ssam			goto out;
1297178354Ssam
1298178354Ssam		default:
1299170530Ssam			bad_error("transaction_add_set", ret);
1300170530Ssam		}
1301170530Ssam
1302178354Ssam		r = scf_entry_add_value(e, v);
1303178354Ssam		assert(r == 0);
1304178354Ssam
1305178354Ssam		r = scf_transaction_commit(tx);
1306178354Ssam		if (r == 1)
1307178354Ssam			break;
1308178354Ssam		if (r != 0) {
1309178354Ssam			scfe = scf_error();
1310178354Ssam			scf_transaction_reset(tx);
1311178354Ssam			switch (scfe) {
1312178354Ssam			case SCF_ERROR_CONNECTION_BROKEN:
1313178354Ssam			default:
1314178354Ssam				ret = ECONNABORTED;
1315178354Ssam				goto out;
1316178354Ssam
1317178354Ssam			case SCF_ERROR_DELETED:
1318178354Ssam				ret = ECANCELED;
1319116742Ssam				goto out;
1320116742Ssam
1321116742Ssam			case SCF_ERROR_PERMISSION_DENIED:
1322178354Ssam				ret = EPERM;
1323178354Ssam				goto out;
1324170530Ssam
1325116742Ssam			case SCF_ERROR_BACKEND_ACCESS:
1326116742Ssam				ret = EACCES;
1327170530Ssam				goto out;
1328170530Ssam
1329170530Ssam			case SCF_ERROR_BACKEND_READONLY:
1330170530Ssam				ret = EROFS;
1331170530Ssam				goto out;
1332178354Ssam
1333116742Ssam			case SCF_ERROR_NOT_SET:
1334170530Ssam				bad_error("scf_transaction_commit", scfe);
1335170530Ssam			}
1336170530Ssam		}
1337178354Ssam
1338138568Ssam		scf_transaction_reset(tx);
1339138568Ssam
1340138568Ssam		if (scf_pg_update(pg) == -1) {
1341178354Ssam			switch (scf_error()) {
1342138568Ssam			case SCF_ERROR_CONNECTION_BROKEN:
1343138568Ssam			default:
1344138568Ssam				ret = ECONNABORTED;
1345138568Ssam				goto out;
1346178354Ssam
1347178354Ssam			case SCF_ERROR_DELETED:
1348138568Ssam				ret = ECANCELED;
1349138568Ssam				goto out;
1350138568Ssam
1351138568Ssam			case SCF_ERROR_NOT_SET:
1352178354Ssam				bad_error("scf_pg_update", scf_error());
1353128966Sandre			}
1354138568Ssam		}
1355178354Ssam	}
1356178354Ssam
1357116742Ssam	ret = 0;
1358116742Ssam
1359116742Ssamout:
1360116742Ssam	scf_transaction_destroy(tx);
1361116742Ssam	scf_entry_destroy(e);
1362116742Ssam	return (ret);
1363116742Ssam}
1364116742Ssam
1365116742Ssam/*
1366116742Ssam * Returns
1367116742Ssam *   0 - success
1368116742Ssam *   ECONNABORTED - repository connection broken
1369166012Ssam *		  - unknown libscf error
1370166012Ssam *   ECANCELED - inst was deleted
1371166012Ssam *   EPERM
1372166012Ssam *   EACCES
1373116742Ssam *   EROFS
1374166012Ssam */
1375178354Ssamint
1376166012Ssamlibscf_inst_set_boolean_prop(scf_instance_t *inst, const char *pgname,
1377116742Ssam    const char *pgtype, uint32_t pgflags, const char *pname, int val)
1378138568Ssam{
1379138568Ssam	scf_handle_t *h;
1380116742Ssam	scf_propertygroup_t *pg = NULL;
1381116742Ssam	scf_value_t *v;
1382116742Ssam	int ret = 0;
1383116742Ssam
1384170530Ssam	h = scf_instance_handle(inst);
1385116742Ssam	pg = safe_scf_pg_create(h);
1386116742Ssam	v = safe_scf_value_create(h);
1387170530Ssam
1388116742Ssam	ret = libscf_inst_get_or_add_pg(inst, pgname, pgtype, pgflags, pg);
1389170530Ssam	switch (ret) {
1390170530Ssam	case 0:
1391170530Ssam		break;
1392170530Ssam
1393170530Ssam	case ECONNABORTED:
1394170530Ssam	case ECANCELED:
1395170530Ssam	case EPERM:
1396170530Ssam	case EACCES:
1397170530Ssam	case EROFS:
1398170530Ssam		goto out;
1399153350Ssam
1400188782Ssam	default:
1401188782Ssam		bad_error("libscf_inst_get_or_add_pg", ret);
1402188782Ssam	}
1403188782Ssam
1404170530Ssam	scf_value_set_boolean(v, val);
1405116742Ssam
1406170530Ssam	ret = pg_set_prop_value(pg, pname, v);
1407116742Ssam	switch (ret) {
1408170530Ssam	case 0:
1409116742Ssam	case ECONNABORTED:
1410170530Ssam	case ECANCELED:
1411170530Ssam	case EPERM:
1412170530Ssam	case EACCES:
1413170530Ssam	case EROFS:
1414170530Ssam		break;
1415170530Ssam
1416170530Ssam	default:
1417116742Ssam		bad_error("pg_set_prop_value", ret);
1418116742Ssam	}
1419170530Ssam
1420170530Ssamout:
1421170530Ssam	scf_pg_destroy(pg);
1422170530Ssam	scf_value_destroy(v);
1423170530Ssam	return (ret);
1424170530Ssam}
1425170530Ssam
1426170530Ssam/*
1427170530Ssam * Returns
1428170530Ssam *   0 - success
1429170530Ssam *   ECONNABORTED - repository connection broken
1430170530Ssam *		  - unknown libscf error
1431170530Ssam *   ECANCELED - inst was deleted
1432170530Ssam *   EPERM
1433170530Ssam *   EACCES
1434170530Ssam *   EROFS
1435116742Ssam */
1436170530Ssamint
1437170530Ssamlibscf_inst_set_count_prop(scf_instance_t *inst, const char *pgname,
1438170530Ssam    const char *pgtype, uint32_t pgflags, const char *pname, uint64_t count)
1439116742Ssam{
1440116742Ssam	scf_handle_t *h;
1441116742Ssam	scf_propertygroup_t *pg = NULL;
1442116742Ssam	scf_value_t *v;
1443116742Ssam	int ret = 0;
1444170530Ssam
1445124543Sonoe	h = scf_instance_handle(inst);
1446124543Sonoe	pg = safe_scf_pg_create(h);
1447124543Sonoe	v = safe_scf_value_create(h);
1448124543Sonoe
1449124543Sonoe	ret = libscf_inst_get_or_add_pg(inst, pgname, pgtype, pgflags, pg);
1450124543Sonoe	switch (ret) {
1451124543Sonoe	case 0:
1452124543Sonoe		break;
1453124543Sonoe
1454124543Sonoe	case ECONNABORTED:
1455124543Sonoe	case ECANCELED:
1456124543Sonoe	case EPERM:
1457124543Sonoe	case EACCES:
1458124543Sonoe	case EROFS:
1459124543Sonoe		goto out;
1460124543Sonoe
1461124543Sonoe	default:
1462124543Sonoe		bad_error("libscf_inst_get_or_add_pg", ret);
1463124543Sonoe	}
1464124543Sonoe
1465124543Sonoe	scf_value_set_count(v, count);
1466124543Sonoe
1467124543Sonoe	ret = pg_set_prop_value(pg, pname, v);
1468124543Sonoe	switch (ret) {
1469124543Sonoe	case 0:
1470124543Sonoe	case ECONNABORTED:
1471124543Sonoe	case ECANCELED:
1472165569Ssam	case EPERM:
1473165569Ssam	case EACCES:
1474165569Ssam	case EROFS:
1475116742Ssam		break;
1476116742Ssam
1477170530Ssam	default:
1478170530Ssam		bad_error("pg_set_prop_value", ret);
1479170530Ssam	}
1480170530Ssam
1481170530Ssamout:
1482170530Ssam	scf_pg_destroy(pg);
1483170530Ssam	scf_value_destroy(v);
1484170530Ssam	return (ret);
1485170530Ssam}
1486170530Ssam
1487170530Ssam/*
1488170530Ssam * Returns 0 on success, ECONNABORTED if the repository connection is broken,
1489170530Ssam * ECANCELED if inst is deleted, EROFS if the backend is readonly, or EPERM if
1490170530Ssam * permission was denied.
1491170530Ssam */
1492170530Ssamint
1493170530Ssamlibscf_set_enable_ovr(scf_instance_t *inst, int enable)
1494170530Ssam{
1495170530Ssam	return (libscf_inst_set_boolean_prop(inst, SCF_PG_GENERAL_OVR,
1496116742Ssam	    SCF_PG_GENERAL_OVR_TYPE, SCF_PG_GENERAL_OVR_FLAGS,
1497170530Ssam	    SCF_PROPERTY_ENABLED, enable));
1498170530Ssam}
1499170530Ssam
1500170530Ssam/*
1501172226Ssam * Returns
1502172226Ssam *   0 - success
1503170530Ssam *   ECONNABORTED - repository connection broken
1504170530Ssam *   ECANCELED - inst was deleted
1505170530Ssam *   EPERM
1506170530Ssam *   EACCES
1507170530Ssam *   EROFS
1508170530Ssam */
1509172226Ssamint
1510172226Ssamlibscf_inst_delete_prop(scf_instance_t *inst, const char *pgname,
1511170530Ssam    const char *pname)
1512170530Ssam{
1513170530Ssam	scf_handle_t *h;
1514170530Ssam	scf_propertygroup_t *pg;
1515170530Ssam	scf_transaction_t *tx;
1516170530Ssam	scf_transaction_entry_t *e;
1517116742Ssam	scf_error_t serr;
1518116742Ssam	int ret = 0, r;
1519188782Ssam
1520188782Ssam	h = scf_instance_handle(inst);
1521170530Ssam	pg = safe_scf_pg_create(h);
1522138568Ssam
1523170530Ssam	if (scf_instance_get_pg(inst, pgname, pg) != 0) {
1524170530Ssam		scf_pg_destroy(pg);
1525116742Ssam		switch (scf_error()) {
1526170530Ssam		case SCF_ERROR_CONNECTION_BROKEN:
1527124543Sonoe		default:
1528170530Ssam			return (ECONNABORTED);
1529116742Ssam
1530116742Ssam		case SCF_ERROR_DELETED:
1531188775Ssam			return (ECANCELED);
1532170530Ssam
1533170530Ssam		case SCF_ERROR_NOT_FOUND:
1534116742Ssam			return (0);
1535116742Ssam
1536116742Ssam		case SCF_ERROR_NOT_SET:
1537170530Ssam			bad_error("scf_instance_get_pg", scf_error());
1538138568Ssam		}
1539170530Ssam	}
1540116742Ssam
1541116742Ssam	tx = safe_scf_transaction_create(h);
1542116742Ssam	e = safe_scf_entry_create(h);
1543116742Ssam
1544116742Ssam	for (;;) {
1545116742Ssam		if (scf_transaction_start(tx, pg) != 0) {
1546116742Ssam			switch (scf_error()) {
1547116742Ssam			case SCF_ERROR_CONNECTION_BROKEN:
1548116742Ssam			default:
1549116742Ssam				ret = ECONNABORTED;
1550116742Ssam				goto out;
1551116742Ssam
1552116742Ssam			case SCF_ERROR_DELETED:
1553116742Ssam				ret = 0;
1554116742Ssam				goto out;
1555116742Ssam
1556116742Ssam			case SCF_ERROR_PERMISSION_DENIED:
1557116742Ssam				ret = EPERM;
1558116742Ssam				goto out;
1559116742Ssam
1560116742Ssam			case SCF_ERROR_BACKEND_ACCESS:
1561116742Ssam				ret = EACCES;
1562116742Ssam				goto out;
1563116742Ssam
1564116742Ssam			case SCF_ERROR_BACKEND_READONLY:
1565116742Ssam				ret = EROFS;
1566116742Ssam				goto out;
1567116742Ssam
1568116742Ssam			case SCF_ERROR_HANDLE_MISMATCH:
1569165569Ssam			case SCF_ERROR_INVALID_ARGUMENT:
1570165569Ssam			case SCF_ERROR_NOT_SET:
1571165569Ssam				bad_error("scf_transaction_start", scf_error());
1572165569Ssam			}
1573165569Ssam		}
1574170530Ssam
1575116742Ssam		if (scf_transaction_property_delete(tx, e, pname) != 0) {
1576116742Ssam			switch (scf_error()) {
1577116742Ssam			case SCF_ERROR_CONNECTION_BROKEN:
1578116742Ssam			default:
1579116742Ssam				ret = ECONNABORTED;
1580195379Ssam				goto out;
1581195379Ssam
1582195379Ssam			case SCF_ERROR_DELETED:
1583195379Ssam			case SCF_ERROR_NOT_FOUND:
1584195379Ssam				ret = 0;
1585195379Ssam				goto out;
1586195379Ssam
1587195379Ssam			case SCF_ERROR_NOT_SET:
1588195379Ssam			case SCF_ERROR_HANDLE_MISMATCH:
1589195379Ssam			case SCF_ERROR_NOT_BOUND:
1590195379Ssam			case SCF_ERROR_INVALID_ARGUMENT:
1591195379Ssam				bad_error("scf_transaction_property_delete",
1592195379Ssam				    scf_error());
1593195379Ssam			}
1594195379Ssam		}
1595195379Ssam
1596195379Ssam		r = scf_transaction_commit(tx);
1597195379Ssam		if (r == 1)
1598195379Ssam			break;
1599195379Ssam		if (r != 0) {
1600195379Ssam			serr = scf_error();
1601195379Ssam			scf_transaction_reset(tx);
1602195379Ssam			switch (serr) {
1603195379Ssam			case SCF_ERROR_CONNECTION_BROKEN:
1604195379Ssam			default:
1605195379Ssam				ret = ECONNABORTED;
1606195379Ssam				goto out;
1607195379Ssam
1608195379Ssam			case SCF_ERROR_DELETED:
1609195379Ssam				ret = 0;
1610195379Ssam				goto out;
1611195379Ssam
1612195379Ssam			case SCF_ERROR_PERMISSION_DENIED:
1613195379Ssam				ret = EPERM;
1614195379Ssam				goto out;
1615195379Ssam
1616			case SCF_ERROR_BACKEND_ACCESS:
1617				ret = EACCES;
1618				goto out;
1619
1620			case SCF_ERROR_BACKEND_READONLY:
1621				ret = EROFS;
1622				goto out;
1623
1624			case SCF_ERROR_NOT_SET:
1625			case SCF_ERROR_INVALID_ARGUMENT:
1626			case SCF_ERROR_NOT_BOUND:
1627				bad_error("scf_transaction_commit", serr);
1628			}
1629		}
1630
1631		scf_transaction_reset(tx);
1632
1633		if (scf_pg_update(pg) == -1) {
1634			switch (scf_error()) {
1635			case SCF_ERROR_CONNECTION_BROKEN:
1636			default:
1637				ret = ECONNABORTED;
1638				goto out;
1639
1640			case SCF_ERROR_DELETED:
1641				ret = 0;
1642				goto out;
1643
1644			case SCF_ERROR_NOT_SET:
1645			case SCF_ERROR_NOT_BOUND:
1646				bad_error("scf_pg_update", scf_error());
1647			}
1648		}
1649	}
1650
1651out:
1652	scf_transaction_destroy(tx);
1653	(void) scf_entry_destroy(e);
1654	scf_pg_destroy(pg);
1655	return (ret);
1656}
1657
1658/*
1659 * Returns 0, ECONNABORTED, ECANCELED, or EPERM.
1660 */
1661int
1662libscf_delete_enable_ovr(scf_instance_t *inst)
1663{
1664	return (libscf_inst_delete_prop(inst, SCF_PG_GENERAL_OVR,
1665	    SCF_PROPERTY_ENABLED));
1666}
1667
1668/*
1669 * Fails with
1670 *   ECONNABORTED - repository connection was broken
1671 *   ECANCELED - pg was deleted
1672 *   ENOENT - pg has no milestone property
1673 *   EINVAL - the milestone property is misconfigured
1674 */
1675static int
1676pg_get_milestone(scf_propertygroup_t *pg, scf_property_t *prop,
1677    scf_value_t *val, char *buf, size_t buf_sz)
1678{
1679	if (scf_pg_get_property(pg, SCF_PROPERTY_MILESTONE, prop) != 0) {
1680		switch (scf_error()) {
1681		case SCF_ERROR_CONNECTION_BROKEN:
1682		default:
1683			return (ECONNABORTED);
1684
1685		case SCF_ERROR_DELETED:
1686			return (ECANCELED);
1687
1688		case SCF_ERROR_NOT_FOUND:
1689			return (ENOENT);
1690
1691		case SCF_ERROR_HANDLE_MISMATCH:
1692		case SCF_ERROR_INVALID_ARGUMENT:
1693		case SCF_ERROR_NOT_SET:
1694			bad_error("scf_pg_get_property", scf_error());
1695		}
1696	}
1697
1698	if (scf_property_get_value(prop, val) != 0) {
1699		switch (scf_error()) {
1700		case SCF_ERROR_CONNECTION_BROKEN:
1701		default:
1702			return (ECONNABORTED);
1703
1704		case SCF_ERROR_DELETED:
1705		case SCF_ERROR_CONSTRAINT_VIOLATED:
1706		case SCF_ERROR_NOT_FOUND:
1707			return (EINVAL);
1708
1709		case SCF_ERROR_NOT_SET:
1710		case SCF_ERROR_PERMISSION_DENIED:
1711			bad_error("scf_property_get_value", scf_error());
1712		}
1713	}
1714
1715	if (scf_value_get_astring(val, buf, buf_sz) < 0) {
1716		switch (scf_error()) {
1717		case SCF_ERROR_TYPE_MISMATCH:
1718			return (EINVAL);
1719
1720		case SCF_ERROR_NOT_SET:
1721		default:
1722			bad_error("scf_value_get_astring", scf_error());
1723		}
1724	}
1725
1726	return (0);
1727}
1728
1729/*
1730 * Fails with
1731 *   ECONNABORTED - repository connection was broken
1732 *   ECANCELED - inst was deleted
1733 *   ENOENT - inst has no milestone property
1734 *   EINVAL - the milestone property is misconfigured
1735 */
1736int
1737libscf_get_milestone(scf_instance_t *inst, scf_property_t *prop,
1738    scf_value_t *val, char *buf, size_t buf_sz)
1739{
1740	scf_propertygroup_t *pg;
1741	int r;
1742
1743	pg = safe_scf_pg_create(scf_instance_handle(inst));
1744
1745	if (scf_instance_get_pg(inst, SCF_PG_OPTIONS_OVR, pg) == 0) {
1746		switch (r = pg_get_milestone(pg, prop, val, buf, buf_sz)) {
1747		case 0:
1748		case ECONNABORTED:
1749		case EINVAL:
1750			goto out;
1751
1752		case ECANCELED:
1753		case ENOENT:
1754			break;
1755
1756		default:
1757			bad_error("pg_get_milestone", r);
1758		}
1759	} else {
1760		switch (scf_error()) {
1761		case SCF_ERROR_CONNECTION_BROKEN:
1762		default:
1763			r = ECONNABORTED;
1764			goto out;
1765
1766		case SCF_ERROR_DELETED:
1767			r = ECANCELED;
1768			goto out;
1769
1770		case SCF_ERROR_NOT_FOUND:
1771			break;
1772
1773		case SCF_ERROR_HANDLE_MISMATCH:
1774		case SCF_ERROR_INVALID_ARGUMENT:
1775		case SCF_ERROR_NOT_SET:
1776			bad_error("scf_instance_get_pg", scf_error());
1777		}
1778	}
1779
1780	if (scf_instance_get_pg(inst, SCF_PG_OPTIONS, pg) == 0) {
1781		r = pg_get_milestone(pg, prop, val, buf, buf_sz);
1782	} else {
1783		switch (scf_error()) {
1784		case SCF_ERROR_CONNECTION_BROKEN:
1785		default:
1786			r = ECONNABORTED;
1787			goto out;
1788
1789		case SCF_ERROR_DELETED:
1790			r = ECANCELED;
1791			goto out;
1792
1793		case SCF_ERROR_NOT_FOUND:
1794			r = ENOENT;
1795			break;
1796
1797		case SCF_ERROR_HANDLE_MISMATCH:
1798		case SCF_ERROR_INVALID_ARGUMENT:
1799		case SCF_ERROR_NOT_SET:
1800			bad_error("scf_instance_get_pg", scf_error());
1801		}
1802	}
1803
1804out:
1805	scf_pg_destroy(pg);
1806
1807	return (r);
1808}
1809
1810/*
1811 * Get the runlevel character from the runlevel property of the given property
1812 * group.  Fails with
1813 *   ECONNABORTED - repository connection was broken
1814 *   ECANCELED - prop's property group was deleted
1815 *   ENOENT - the property has no values
1816 *   EINVAL - the property has more than one value
1817 *	      the property is of the wrong type
1818 *	      the property value is malformed
1819 */
1820int
1821libscf_extract_runlevel(scf_property_t *prop, char *rlp)
1822{
1823	scf_value_t *val;
1824	char buf[2];
1825
1826	val = safe_scf_value_create(scf_property_handle(prop));
1827
1828	if (scf_property_get_value(prop, val) != 0) {
1829		switch (scf_error()) {
1830		case SCF_ERROR_CONNECTION_BROKEN:
1831			return (ECONNABORTED);
1832
1833		case SCF_ERROR_NOT_SET:
1834			return (ENOENT);
1835
1836		case SCF_ERROR_DELETED:
1837			return (ECANCELED);
1838
1839		case SCF_ERROR_CONSTRAINT_VIOLATED:
1840			return (EINVAL);
1841
1842		case SCF_ERROR_NOT_FOUND:
1843			return (ENOENT);
1844
1845		case SCF_ERROR_HANDLE_MISMATCH:
1846		case SCF_ERROR_NOT_BOUND:
1847		case SCF_ERROR_PERMISSION_DENIED:
1848		default:
1849			bad_error("scf_property_get_value", scf_error());
1850		}
1851	}
1852
1853	if (scf_value_get_astring(val, buf, sizeof (buf)) < 0) {
1854		if (scf_error() != SCF_ERROR_TYPE_MISMATCH)
1855			bad_error("scf_value_get_astring", scf_error());
1856
1857		return (EINVAL);
1858	}
1859
1860	if (buf[0] == '\0' || buf[1] != '\0')
1861		return (EINVAL);
1862
1863	*rlp = buf[0];
1864
1865	return (0);
1866}
1867
1868/*
1869 * Delete the "runlevel" property from the given property group.  Also set the
1870 * "milestone" property to the given string.  Fails with ECONNABORTED,
1871 * ECANCELED, EPERM, EACCES, or EROFS.
1872 */
1873int
1874libscf_clear_runlevel(scf_propertygroup_t *pg, const char *milestone)
1875{
1876	scf_handle_t *h;
1877	scf_transaction_t *tx;
1878	scf_transaction_entry_t *e_rl, *e_ms;
1879	scf_value_t *val;
1880	scf_error_t serr;
1881	boolean_t isempty = B_TRUE;
1882	int ret = 0, r;
1883
1884	h = scf_pg_handle(pg);
1885	tx = safe_scf_transaction_create(h);
1886	e_rl = safe_scf_entry_create(h);
1887	e_ms = safe_scf_entry_create(h);
1888	val = safe_scf_value_create(h);
1889
1890	if (milestone) {
1891		r = scf_value_set_astring(val, milestone);
1892		assert(r == 0);
1893	}
1894
1895	for (;;) {
1896		if (scf_transaction_start(tx, pg) != 0) {
1897			switch (scf_error()) {
1898			case SCF_ERROR_CONNECTION_BROKEN:
1899			default:
1900				ret = ECONNABORTED;
1901				goto out;
1902
1903			case SCF_ERROR_DELETED:
1904				ret = ECANCELED;
1905				goto out;
1906
1907			case SCF_ERROR_PERMISSION_DENIED:
1908				ret = EPERM;
1909				goto out;
1910
1911			case SCF_ERROR_BACKEND_ACCESS:
1912				ret = EACCES;
1913				goto out;
1914
1915			case SCF_ERROR_BACKEND_READONLY:
1916				ret = EROFS;
1917				goto out;
1918
1919			case SCF_ERROR_NOT_SET:
1920				bad_error("scf_transaction_start", scf_error());
1921			}
1922		}
1923
1924		if (scf_transaction_property_delete(tx, e_rl,
1925		    "runlevel") == 0) {
1926			isempty = B_FALSE;
1927		} else {
1928			switch (scf_error()) {
1929			case SCF_ERROR_CONNECTION_BROKEN:
1930			default:
1931				ret = ECONNABORTED;
1932				goto out;
1933
1934			case SCF_ERROR_DELETED:
1935				ret = ECANCELED;
1936				goto out;
1937
1938			case SCF_ERROR_NOT_FOUND:
1939				break;
1940
1941			case SCF_ERROR_HANDLE_MISMATCH:
1942			case SCF_ERROR_NOT_BOUND:
1943			case SCF_ERROR_INVALID_ARGUMENT:
1944				bad_error("scf_transaction_property_delete",
1945				    scf_error());
1946			}
1947		}
1948
1949		if (milestone) {
1950			ret = transaction_add_set(tx, e_ms,
1951			    SCF_PROPERTY_MILESTONE, SCF_TYPE_ASTRING);
1952			switch (ret) {
1953			case 0:
1954				break;
1955
1956			case ECONNABORTED:
1957			case ECANCELED:
1958				goto out;
1959
1960			default:
1961				bad_error("transaction_add_set", ret);
1962			}
1963
1964			isempty = B_FALSE;
1965
1966			r = scf_entry_add_value(e_ms, val);
1967			assert(r == 0);
1968		}
1969
1970		if (isempty)
1971			goto out;
1972
1973		r = scf_transaction_commit(tx);
1974		if (r == 1)
1975			break;
1976		if (r != 0) {
1977			serr = scf_error();
1978			scf_transaction_reset(tx);
1979			switch (serr) {
1980			case SCF_ERROR_CONNECTION_BROKEN:
1981				ret = ECONNABORTED;
1982				goto out;
1983
1984			case SCF_ERROR_PERMISSION_DENIED:
1985				ret = EPERM;
1986				goto out;
1987
1988			case SCF_ERROR_BACKEND_ACCESS:
1989				ret = EACCES;
1990				goto out;
1991
1992			case SCF_ERROR_BACKEND_READONLY:
1993				ret = EROFS;
1994				goto out;
1995
1996			default:
1997				bad_error("scf_transaction_commit", serr);
1998			}
1999		}
2000
2001		scf_transaction_reset(tx);
2002
2003		if (scf_pg_update(pg) == -1) {
2004			switch (scf_error()) {
2005			case SCF_ERROR_CONNECTION_BROKEN:
2006				ret = ECONNABORTED;
2007				goto out;
2008
2009			case SCF_ERROR_NOT_SET:
2010				ret = ECANCELED;
2011				goto out;
2012
2013			default:
2014				assert(0);
2015				abort();
2016			}
2017		}
2018	}
2019
2020out:
2021	scf_transaction_destroy(tx);
2022	scf_entry_destroy(e_rl);
2023	scf_entry_destroy(e_ms);
2024	scf_value_destroy(val);
2025	return (ret);
2026}
2027
2028/*
2029 * int libscf_get_template_values(scf_instance_t *, scf_snapshot_t *,
2030 *	char **)
2031 *
2032 *   Return template values for inst in *common_name suitable for use in
2033 *   restarter_inst_t->ri_common_name.  Called by restarter_insert_inst().
2034 *
2035 *   Returns 0 on success, ECANCELED if the instance is deleted, ECHILD if
2036 *   a value fetch failed for a property, ENOENT if the instance has no
2037 *   tm_common_name property group or the property group is deleted, and
2038 *   ECONNABORTED if the repository connection is broken.
2039 */
2040int
2041libscf_get_template_values(scf_instance_t *inst, scf_snapshot_t *snap,
2042    char **common_name, char **c_common_name)
2043{
2044	scf_handle_t *h;
2045	scf_propertygroup_t *pg = NULL;
2046	scf_property_t *prop = NULL;
2047	int ret = 0, r;
2048	char *cname = startd_alloc(max_scf_value_size);
2049	char *c_cname = startd_alloc(max_scf_value_size);
2050	int common_name_initialized = B_FALSE;
2051	int c_common_name_initialized = B_FALSE;
2052
2053	h = scf_instance_handle(inst);
2054	pg = safe_scf_pg_create(h);
2055	prop = safe_scf_property_create(h);
2056
2057	/*
2058	 * The tm_common_name property group, as with all template property
2059	 * groups, is optional.
2060	 */
2061	if (scf_instance_get_pg_composed(inst, snap, SCF_PG_TM_COMMON_NAME, pg)
2062	    == -1) {
2063		switch (scf_error()) {
2064		case SCF_ERROR_DELETED:
2065			ret = ECANCELED;
2066			goto template_values_out;
2067
2068		case SCF_ERROR_NOT_FOUND:
2069			goto template_values_out;
2070
2071		case SCF_ERROR_CONNECTION_BROKEN:
2072		default:
2073			ret = ECONNABORTED;
2074			goto template_values_out;
2075
2076		case SCF_ERROR_INVALID_ARGUMENT:
2077		case SCF_ERROR_HANDLE_MISMATCH:
2078		case SCF_ERROR_NOT_SET:
2079			bad_error("scf_instance_get_pg_composed", scf_error());
2080		}
2081	}
2082
2083	/*
2084	 * The name we wish uses the current locale name as the property name.
2085	 */
2086	if (st->st_locale != NULL) {
2087		if (scf_pg_get_property(pg, st->st_locale, prop) == -1) {
2088			switch (scf_error()) {
2089			case SCF_ERROR_DELETED:
2090			case SCF_ERROR_NOT_FOUND:
2091				break;
2092
2093			case SCF_ERROR_CONNECTION_BROKEN:
2094			default:
2095				ret = ECONNABORTED;
2096				goto template_values_out;
2097
2098			case SCF_ERROR_INVALID_ARGUMENT:
2099			case SCF_ERROR_HANDLE_MISMATCH:
2100			case SCF_ERROR_NOT_SET:
2101				bad_error("scf_pg_get_property", scf_error());
2102			}
2103		} else {
2104			if ((r = libscf_read_single_astring(h, prop, &cname)) !=
2105			    0) {
2106				if (r != LIBSCF_PROPERTY_ABSENT)
2107					ret = ECHILD;
2108				goto template_values_out;
2109			}
2110
2111			*common_name = cname;
2112			common_name_initialized = B_TRUE;
2113		}
2114	}
2115
2116	/*
2117	 * Also pull out the C locale name, as a fallback for the case where
2118	 * service offers no localized name.
2119	 */
2120	if (scf_pg_get_property(pg, "C", prop) == -1) {
2121		switch (scf_error()) {
2122		case SCF_ERROR_DELETED:
2123			ret = ENOENT;
2124			goto template_values_out;
2125
2126		case SCF_ERROR_NOT_FOUND:
2127			break;
2128
2129		case SCF_ERROR_CONNECTION_BROKEN:
2130		default:
2131			ret = ECONNABORTED;
2132			goto template_values_out;
2133
2134		case SCF_ERROR_INVALID_ARGUMENT:
2135		case SCF_ERROR_HANDLE_MISMATCH:
2136		case SCF_ERROR_NOT_SET:
2137			bad_error("scf_pg_get_property", scf_error());
2138		}
2139	} else {
2140		if ((r = libscf_read_single_astring(h, prop, &c_cname)) != 0) {
2141			if (r != LIBSCF_PROPERTY_ABSENT)
2142				ret = ECHILD;
2143			goto template_values_out;
2144		}
2145
2146		*c_common_name = c_cname;
2147		c_common_name_initialized = B_TRUE;
2148	}
2149
2150
2151template_values_out:
2152	if (common_name_initialized == B_FALSE)
2153		startd_free(cname, max_scf_value_size);
2154	if (c_common_name_initialized == B_FALSE)
2155		startd_free(c_cname, max_scf_value_size);
2156	scf_property_destroy(prop);
2157	scf_pg_destroy(pg);
2158
2159	return (ret);
2160}
2161
2162/*
2163 * int libscf_get_startd_properties(scf_handle_t *, scf_instance_t *,
2164 *	scf_snapshot_t *, uint_t *, char **)
2165 *
2166 *   Return startd settings for inst in *flags suitable for use in
2167 *   restarter_inst_t->ri_flags.  Called by restarter_insert_inst().
2168 *
2169 *   Returns 0 on success, ECANCELED if the instance is deleted, ECHILD if
2170 *   a value fetch failed for a property, ENOENT if the instance has no
2171 *   general property group or the property group is deleted, and
2172 *   ECONNABORTED if the repository connection is broken.
2173 */
2174int
2175libscf_get_startd_properties(scf_instance_t *inst,
2176    scf_snapshot_t *snap, uint_t *flags, char **prefixp)
2177{
2178	scf_handle_t *h;
2179	scf_propertygroup_t *pg = NULL;
2180	scf_property_t *prop = NULL;
2181	int style = RINST_CONTRACT;
2182	char *style_str = startd_alloc(max_scf_value_size);
2183	int ret = 0, r;
2184
2185	h = scf_instance_handle(inst);
2186	pg = safe_scf_pg_create(h);
2187	prop = safe_scf_property_create(h);
2188
2189	/*
2190	 * The startd property group is optional.
2191	 */
2192	if (scf_instance_get_pg_composed(inst, snap, SCF_PG_STARTD, pg) == -1) {
2193		switch (scf_error()) {
2194		case SCF_ERROR_DELETED:
2195			ret = ECANCELED;
2196			goto instance_flags_out;
2197
2198		case SCF_ERROR_NOT_FOUND:
2199			ret = ENOENT;
2200			goto instance_flags_out;
2201
2202		case SCF_ERROR_CONNECTION_BROKEN:
2203		default:
2204			ret = ECONNABORTED;
2205			goto instance_flags_out;
2206
2207		case SCF_ERROR_INVALID_ARGUMENT:
2208		case SCF_ERROR_HANDLE_MISMATCH:
2209		case SCF_ERROR_NOT_SET:
2210			bad_error("scf_instance_get_pg_composed", scf_error());
2211		}
2212	}
2213
2214	/*
2215	 * 1.  Duration property.
2216	 */
2217	if (scf_pg_get_property(pg, SCF_PROPERTY_DURATION, prop) == -1) {
2218		switch (scf_error()) {
2219		case SCF_ERROR_DELETED:
2220			ret = ENOENT;
2221			goto instance_flags_out;
2222
2223		case SCF_ERROR_NOT_FOUND:
2224			break;
2225
2226		case SCF_ERROR_CONNECTION_BROKEN:
2227		default:
2228			ret = ECONNABORTED;
2229			goto instance_flags_out;
2230
2231		case SCF_ERROR_INVALID_ARGUMENT:
2232		case SCF_ERROR_HANDLE_MISMATCH:
2233		case SCF_ERROR_NOT_SET:
2234			bad_error("scf_pg_get_property", scf_error());
2235		}
2236	} else {
2237		errno = 0;
2238		if ((r = libscf_read_single_astring(h, prop, &style_str))
2239		    != 0) {
2240			if (r != LIBSCF_PROPERTY_ABSENT)
2241				ret = ECHILD;
2242			goto instance_flags_out;
2243		}
2244
2245		if (strcmp(style_str, "child") == 0)
2246			style = RINST_WAIT;
2247		else if (strcmp(style_str, "transient") == 0)
2248			style = RINST_TRANSIENT;
2249	}
2250
2251	/*
2252	 * 2.  utmpx prefix property.
2253	 */
2254	if (scf_pg_get_property(pg, SCF_PROPERTY_UTMPX_PREFIX, prop) == 0) {
2255		errno = 0;
2256		if ((r = libscf_read_single_astring(h, prop, prefixp)) != 0) {
2257			if (r != LIBSCF_PROPERTY_ABSENT)
2258				ret = ECHILD;
2259			goto instance_flags_out;
2260		}
2261	} else {
2262		switch (scf_error()) {
2263		case SCF_ERROR_DELETED:
2264			ret = ENOENT;
2265			goto instance_flags_out;
2266
2267		case SCF_ERROR_NOT_FOUND:
2268			goto instance_flags_out;
2269
2270		case SCF_ERROR_CONNECTION_BROKEN:
2271		default:
2272			ret = ECONNABORTED;
2273			goto instance_flags_out;
2274
2275		case SCF_ERROR_INVALID_ARGUMENT:
2276		case SCF_ERROR_HANDLE_MISMATCH:
2277		case SCF_ERROR_NOT_SET:
2278			bad_error("scf_pg_get_property", scf_error());
2279		}
2280	}
2281
2282instance_flags_out:
2283	startd_free(style_str, max_scf_value_size);
2284	*flags = (*flags & ~RINST_STYLE_MASK) | style;
2285
2286	scf_property_destroy(prop);
2287	scf_pg_destroy(pg);
2288
2289	return (ret);
2290}
2291
2292/*
2293 * int libscf_read_method_ids(scf_handle_t *, scf_instance_t *, ctid_t *,
2294 *   ctid_t *, pid_t *)
2295 *
2296 *  Sets given id_t variables to primary and transient contract IDs and start
2297 *  PID.  Returns 0, ECONNABORTED, and ECANCELED.
2298 */
2299int
2300libscf_read_method_ids(scf_handle_t *h, scf_instance_t *inst, const char *fmri,
2301    ctid_t *primary, ctid_t *transient, pid_t *start_pid)
2302{
2303	scf_propertygroup_t *pg = NULL;
2304	scf_property_t *prop = NULL;
2305	scf_value_t *val = NULL;
2306	uint64_t p, t;
2307	int ret = 0;
2308
2309	*primary = 0;
2310	*transient = 0;
2311	*start_pid = -1;
2312
2313	pg = safe_scf_pg_create(h);
2314	prop = safe_scf_property_create(h);
2315	val = safe_scf_value_create(h);
2316
2317	if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) == -1) {
2318		switch (scf_error()) {
2319		case SCF_ERROR_CONNECTION_BROKEN:
2320		default:
2321			ret = ECONNABORTED;
2322			goto read_id_err;
2323
2324		case SCF_ERROR_DELETED:
2325			ret = ECANCELED;
2326			goto read_id_err;
2327
2328		case SCF_ERROR_NOT_FOUND:
2329			goto read_id_err;
2330
2331		case SCF_ERROR_NOT_SET:
2332			bad_error("scf_instance_get_pg", scf_error());
2333		}
2334	}
2335
2336	ret = get_count(pg, SCF_PROPERTY_CONTRACT, &p);
2337	switch (ret) {
2338	case 0:
2339		break;
2340
2341	case EINVAL:
2342		log_error(LOG_NOTICE,
2343		    "%s: Ignoring %s/%s: multivalued or not of type count\n",
2344		    fmri, SCF_PG_RESTARTER, SCF_PROPERTY_CONTRACT);
2345		/* FALLTHROUGH */
2346	case ENOENT:
2347		ret = 0;
2348		goto read_trans;
2349
2350	case ECONNABORTED:
2351	case ECANCELED:
2352		goto read_id_err;
2353
2354	case EACCES:
2355	default:
2356		bad_error("get_count", ret);
2357	}
2358
2359	*primary = p;
2360
2361read_trans:
2362	ret = get_count(pg, SCF_PROPERTY_TRANSIENT_CONTRACT, &t);
2363	switch (ret) {
2364	case 0:
2365		break;
2366
2367	case EINVAL:
2368		log_error(LOG_NOTICE,
2369		    "%s: Ignoring %s/%s: multivalued or not of type count\n",
2370		    fmri, SCF_PG_RESTARTER, SCF_PROPERTY_TRANSIENT_CONTRACT);
2371		/* FALLTHROUGH */
2372
2373	case ENOENT:
2374		ret = 0;
2375		goto read_pid_only;
2376
2377	case ECONNABORTED:
2378	case ECANCELED:
2379		goto read_id_err;
2380
2381	case EACCES:
2382	default:
2383		bad_error("get_count", ret);
2384	}
2385
2386	*transient = t;
2387
2388read_pid_only:
2389	ret = get_count(pg, SCF_PROPERTY_START_PID, &p);
2390	switch (ret) {
2391	case 0:
2392		break;
2393
2394	case EINVAL:
2395		log_error(LOG_NOTICE,
2396		    "%s: Ignoring %s/%s: multivalued or not of type count\n",
2397		    fmri, SCF_PG_RESTARTER, SCF_PROPERTY_START_PID);
2398		/* FALLTHROUGH */
2399	case ENOENT:
2400		ret = 0;
2401		goto read_id_err;
2402
2403	case ECONNABORTED:
2404	case ECANCELED:
2405		goto read_id_err;
2406
2407	case EACCES:
2408	default:
2409		bad_error("get_count", ret);
2410	}
2411
2412	*start_pid = p;
2413
2414read_id_err:
2415	scf_value_destroy(val);
2416	scf_property_destroy(prop);
2417	scf_pg_destroy(pg);
2418	return (ret);
2419}
2420
2421/*
2422 * Returns with
2423 *   0 - success
2424 *   ECONNABORTED - repository connection broken
2425 *		  - unknown libscf error
2426 *   ECANCELED - s_inst was deleted
2427 *   EPERM
2428 *   EACCES
2429 *   EROFS
2430 */
2431int
2432libscf_write_start_pid(scf_instance_t *s_inst, pid_t pid)
2433{
2434	scf_handle_t *h;
2435	scf_transaction_entry_t *t_pid;
2436	scf_value_t *v_pid;
2437	scf_propertygroup_t *pg;
2438	int ret = 0;
2439
2440	h = scf_instance_handle(s_inst);
2441
2442	pg = safe_scf_pg_create(h);
2443	t_pid = safe_scf_entry_create(h);
2444	v_pid = safe_scf_value_create(h);
2445
2446get_pg:
2447	ret = libscf_inst_get_or_add_pg(s_inst, SCF_PG_RESTARTER,
2448	    SCF_PG_RESTARTER_TYPE, SCF_PG_RESTARTER_FLAGS, pg);
2449	switch (ret) {
2450	case 0:
2451		break;
2452
2453	case ECONNABORTED:
2454	case ECANCELED:
2455	case EPERM:
2456	case EACCES:
2457	case EROFS:
2458		goto write_start_err;
2459
2460	default:
2461		bad_error("libscf_inst_get_or_add_pg", ret);
2462	}
2463
2464	scf_value_set_count(v_pid, pid);
2465
2466	ret = pg_set_prop_value(pg, SCF_PROPERTY_START_PID, v_pid);
2467	switch (ret) {
2468	case 0:
2469	case ECONNABORTED:
2470	case EPERM:
2471	case EACCES:
2472	case EROFS:
2473		break;
2474
2475	case ECANCELED:
2476		goto get_pg;
2477
2478	default:
2479		bad_error("pg_set_prop_value", ret);
2480	}
2481
2482write_start_err:
2483	scf_entry_destroy(t_pid);
2484	scf_value_destroy(v_pid);
2485	scf_pg_destroy(pg);
2486
2487	return (ret);
2488}
2489
2490/*
2491 * Add a property indicating the instance log file.  If the dir is
2492 * equal to LOG_PREFIX_EARLY, then the property restarter/alt_logfile
2493 * of the instance is used; otherwise, restarter/logfile is used.
2494 *
2495 * Returns
2496 *   0 - success
2497 *   ECONNABORTED
2498 *   ECANCELED
2499 *   EPERM
2500 *   EACCES
2501 *   EROFS
2502 *   EAGAIN
2503 */
2504int
2505libscf_note_method_log(scf_instance_t *inst, const char *dir, const char *file)
2506{
2507	scf_handle_t *h;
2508	scf_value_t *v;
2509	scf_propertygroup_t *pg;
2510	int ret = 0;
2511	char *logname;
2512	const char *propname;
2513
2514	h = scf_instance_handle(inst);
2515	pg = safe_scf_pg_create(h);
2516	v = safe_scf_value_create(h);
2517
2518	logname = uu_msprintf("%s%s", dir, file);
2519
2520	if (logname == NULL) {
2521		ret = errno;
2522		goto out;
2523	}
2524
2525	ret = libscf_inst_get_or_add_pg(inst, SCF_PG_RESTARTER,
2526	    SCF_PG_RESTARTER_TYPE, SCF_PG_RESTARTER_FLAGS, pg);
2527	switch (ret) {
2528	case 0:
2529		break;
2530
2531	case ECONNABORTED:
2532	case ECANCELED:
2533	case EPERM:
2534	case EACCES:
2535	case EROFS:
2536		goto out;
2537
2538	default:
2539		bad_error("libscf_inst_get_or_add_pg", ret);
2540	}
2541
2542	(void) scf_value_set_astring(v, logname);
2543
2544	if (strcmp(LOG_PREFIX_EARLY, dir) == 0)
2545		propname = SCF_PROPERTY_ALT_LOGFILE;
2546	else
2547		propname = SCF_PROPERTY_LOGFILE;
2548
2549	ret = pg_set_prop_value(pg, propname, v);
2550	switch (ret) {
2551	case 0:
2552	case ECONNABORTED:
2553	case ECANCELED:
2554	case EPERM:
2555	case EACCES:
2556	case EROFS:
2557		break;
2558
2559	default:
2560		bad_error("pg_set_prop_value", ret);
2561	}
2562
2563out:
2564	scf_pg_destroy(pg);
2565	scf_value_destroy(v);
2566	uu_free(logname);
2567	return (ret);
2568}
2569
2570/*
2571 * Returns
2572 *   0 - success
2573 *   ENAMETOOLONG - name is too long
2574 *   ECONNABORTED
2575 *   ECANCELED
2576 *   EPERM
2577 *   EACCES
2578 *   EROFS
2579 */
2580int
2581libscf_write_method_status(scf_instance_t *s_inst, const char *name,
2582    int status)
2583{
2584	scf_handle_t *h;
2585	scf_transaction_t *tx;
2586	scf_transaction_entry_t *e_time, *e_stat;
2587	scf_value_t *v_time, *v_stat;
2588	scf_propertygroup_t *pg;
2589	int ret = 0, r;
2590	char pname[30];
2591	struct timeval tv;
2592	scf_error_t scfe;
2593
2594	if (strlen(name) + sizeof ("_method_waitstatus") > sizeof (pname))
2595		return (ENAMETOOLONG);
2596
2597	h = scf_instance_handle(s_inst);
2598
2599	pg = safe_scf_pg_create(h);
2600	tx = safe_scf_transaction_create(h);
2601	e_time = safe_scf_entry_create(h);
2602	v_time = safe_scf_value_create(h);
2603	e_stat = safe_scf_entry_create(h);
2604	v_stat = safe_scf_value_create(h);
2605
2606get_pg:
2607	ret = libscf_inst_get_or_add_pg(s_inst, SCF_PG_RESTARTER,
2608	    SCF_PG_RESTARTER_TYPE, SCF_PG_RESTARTER_FLAGS, pg);
2609	switch (ret) {
2610	case 0:
2611		break;
2612
2613	case ECONNABORTED:
2614	case ECANCELED:
2615	case EPERM:
2616	case EACCES:
2617	case EROFS:
2618		goto out;
2619
2620	default:
2621		bad_error("libscf_inst_get_or_add_pg", ret);
2622	}
2623
2624	(void) gettimeofday(&tv, NULL);
2625
2626	r = scf_value_set_time(v_time, tv.tv_sec, tv.tv_usec * 1000);
2627	assert(r == 0);
2628
2629	scf_value_set_integer(v_stat, status);
2630
2631	for (;;) {
2632		if (scf_transaction_start(tx, pg) != 0) {
2633			switch (scf_error()) {
2634			case SCF_ERROR_CONNECTION_BROKEN:
2635			default:
2636				ret = ECONNABORTED;
2637				goto out;
2638
2639			case SCF_ERROR_DELETED:
2640				ret = ECANCELED;
2641				goto out;
2642
2643			case SCF_ERROR_PERMISSION_DENIED:
2644				ret = EPERM;
2645				goto out;
2646
2647			case SCF_ERROR_BACKEND_ACCESS:
2648				ret = EACCES;
2649				goto out;
2650
2651			case SCF_ERROR_BACKEND_READONLY:
2652				ret = EROFS;
2653				goto out;
2654
2655			case SCF_ERROR_NOT_SET:
2656				bad_error("scf_transaction_start", ret);
2657			}
2658		}
2659
2660		(void) snprintf(pname, sizeof (pname), "%s_method_timestamp",
2661		    name);
2662		ret = transaction_add_set(tx, e_time, pname, SCF_TYPE_TIME);
2663		switch (ret) {
2664		case 0:
2665			break;
2666
2667		case ECONNABORTED:
2668		case ECANCELED:
2669			goto out;
2670
2671		default:
2672			bad_error("transaction_add_set", ret);
2673		}
2674
2675		r = scf_entry_add_value(e_time, v_time);
2676		assert(r == 0);
2677
2678		(void) snprintf(pname, sizeof (pname), "%s_method_waitstatus",
2679		    name);
2680		ret = transaction_add_set(tx, e_stat, pname, SCF_TYPE_INTEGER);
2681		switch (ret) {
2682		case 0:
2683			break;
2684
2685		case ECONNABORTED:
2686		case ECANCELED:
2687			goto out;
2688
2689		default:
2690			bad_error("transaction_add_set", ret);
2691		}
2692
2693		r = scf_entry_add_value(e_stat, v_stat);
2694		if (r != 0)
2695			bad_error("scf_entry_add_value", scf_error());
2696
2697		r = scf_transaction_commit(tx);
2698		if (r == 1)
2699			break;
2700		if (r != 0) {
2701			scfe = scf_error();
2702			scf_transaction_reset_all(tx);
2703			switch (scfe) {
2704			case SCF_ERROR_CONNECTION_BROKEN:
2705			default:
2706				ret = ECONNABORTED;
2707				goto out;
2708
2709			case SCF_ERROR_DELETED:
2710				ret = ECANCELED;
2711				goto out;
2712
2713			case SCF_ERROR_PERMISSION_DENIED:
2714				ret = EPERM;
2715				goto out;
2716
2717			case SCF_ERROR_BACKEND_ACCESS:
2718				ret = EACCES;
2719				goto out;
2720
2721			case SCF_ERROR_BACKEND_READONLY:
2722				ret = EROFS;
2723				goto out;
2724
2725			case SCF_ERROR_NOT_SET:
2726				bad_error("scf_transaction_commit", scfe);
2727			}
2728		}
2729
2730		scf_transaction_reset_all(tx);
2731
2732		if (scf_pg_update(pg) == -1) {
2733			switch (scf_error()) {
2734			case SCF_ERROR_CONNECTION_BROKEN:
2735			default:
2736				ret = ECONNABORTED;
2737				goto out;
2738
2739			case SCF_ERROR_DELETED:
2740				ret = ECANCELED;
2741				goto out;
2742
2743			case SCF_ERROR_NOT_SET:
2744				bad_error("scf_pg_update", scf_error());
2745			}
2746		}
2747	}
2748
2749out:
2750	scf_transaction_destroy(tx);
2751	scf_entry_destroy(e_time);
2752	scf_value_destroy(v_time);
2753	scf_entry_destroy(e_stat);
2754	scf_value_destroy(v_stat);
2755	scf_pg_destroy(pg);
2756
2757	return (ret);
2758}
2759
2760/*
2761 * Call dgraph_add_instance() for each instance in the repository.
2762 */
2763void
2764libscf_populate_graph(scf_handle_t *h)
2765{
2766	scf_scope_t *scope;
2767	scf_service_t *svc;
2768	scf_instance_t *inst;
2769	scf_iter_t *svc_iter;
2770	scf_iter_t *inst_iter;
2771	int ret;
2772
2773	scope = safe_scf_scope_create(h);
2774	svc = safe_scf_service_create(h);
2775	inst = safe_scf_instance_create(h);
2776	svc_iter = safe_scf_iter_create(h);
2777	inst_iter = safe_scf_iter_create(h);
2778
2779	if ((ret = scf_handle_get_local_scope(h, scope)) !=
2780	    SCF_SUCCESS)
2781		uu_die("retrieving local scope failed: %d\n", ret);
2782
2783	if (scf_iter_scope_services(svc_iter, scope) == -1)
2784		uu_die("walking local scope's services failed\n");
2785
2786	while (scf_iter_next_service(svc_iter, svc) > 0) {
2787		if (scf_iter_service_instances(inst_iter, svc) == -1)
2788			uu_die("unable to walk service's instances");
2789
2790		while (scf_iter_next_instance(inst_iter, inst) > 0) {
2791			char *fmri;
2792
2793			if (libscf_instance_get_fmri(inst, &fmri) == 0) {
2794				int err;
2795
2796				err = dgraph_add_instance(fmri, inst, B_TRUE);
2797				if (err != 0 && err != EEXIST)
2798					log_error(LOG_WARNING,
2799					    "Failed to add %s (%s).\n", fmri,
2800					    strerror(err));
2801				startd_free(fmri, max_scf_fmri_size);
2802			}
2803		}
2804	}
2805
2806	scf_iter_destroy(inst_iter);
2807	scf_iter_destroy(svc_iter);
2808	scf_instance_destroy(inst);
2809	scf_service_destroy(svc);
2810	scf_scope_destroy(scope);
2811}
2812
2813/*
2814 * Monitors get handled differently since there can be multiple of them.
2815 *
2816 * Returns exec string on success.  If method not defined, returns
2817 * LIBSCF_PGROUP_ABSENT; if exec property missing, returns
2818 * LIBSCF_PROPERTY_ABSENT.  Returns LIBSCF_PROPERTY_ERROR on other failures.
2819 */
2820char *
2821libscf_get_method(scf_handle_t *h, int type, restarter_inst_t *inst,
2822    scf_snapshot_t *snap, method_restart_t *restart_on, uint_t *cte_mask,
2823    uint8_t *need_sessionp, uint64_t *timeout, uint8_t *timeout_retry)
2824{
2825	scf_instance_t *scf_inst = NULL;
2826	scf_propertygroup_t *pg = NULL, *pg_startd = NULL;
2827	scf_property_t *prop = NULL;
2828	const char *name;
2829	char *method = startd_alloc(max_scf_value_size);
2830	char *ig = startd_alloc(max_scf_value_size);
2831	char *restart = startd_alloc(max_scf_value_size);
2832	char *ret;
2833	int error = 0, r;
2834
2835	scf_inst = safe_scf_instance_create(h);
2836	pg = safe_scf_pg_create(h);
2837	pg_startd = safe_scf_pg_create(h);
2838	prop = safe_scf_property_create(h);
2839
2840	ret = NULL;
2841
2842	*restart_on = METHOD_RESTART_UNKNOWN;
2843
2844	switch (type) {
2845	case METHOD_START:
2846		name = "start";
2847		break;
2848	case METHOD_STOP:
2849		name = "stop";
2850		break;
2851	case METHOD_REFRESH:
2852		name = "refresh";
2853		break;
2854	default:
2855		error = LIBSCF_PROPERTY_ERROR;
2856		goto get_method_cleanup;
2857	}
2858
2859	if (scf_handle_decode_fmri(h, inst->ri_i.i_fmri, NULL, NULL, scf_inst,
2860	    NULL, NULL, SCF_DECODE_FMRI_EXACT) == -1) {
2861		log_error(LOG_WARNING,
2862		    "%s: get_method decode instance FMRI failed: %s\n",
2863		    inst->ri_i.i_fmri, scf_strerror(scf_error()));
2864		error = LIBSCF_PROPERTY_ERROR;
2865		goto get_method_cleanup;
2866	}
2867
2868	if (scf_instance_get_pg_composed(scf_inst, snap, name, pg) == -1) {
2869		if (scf_error() == SCF_ERROR_NOT_FOUND)
2870			error = LIBSCF_PGROUP_ABSENT;
2871		else
2872			error = LIBSCF_PROPERTY_ERROR;
2873		goto get_method_cleanup;
2874	}
2875
2876	if (scf_pg_get_property(pg, SCF_PROPERTY_EXEC, prop) == -1) {
2877		if (scf_error() == SCF_ERROR_NOT_FOUND)
2878			error = LIBSCF_PROPERTY_ABSENT;
2879		else
2880			error = LIBSCF_PROPERTY_ERROR;
2881		goto get_method_cleanup;
2882	}
2883
2884	error = libscf_read_single_astring(h, prop, &method);
2885	if (error != 0) {
2886		log_error(LOG_WARNING,
2887		    "%s: get_method failed: can't get a single astring "
2888		    "from %s/%s\n", inst->ri_i.i_fmri, name, SCF_PROPERTY_EXEC);
2889		goto get_method_cleanup;
2890	}
2891
2892	error = expand_method_tokens(method, scf_inst, snap, type, &ret);
2893	if (error != 0) {
2894		log_instance(inst, B_TRUE, "Could not expand method tokens "
2895		    "in \"%s\": %s.", method, ret);
2896		error = LIBSCF_PROPERTY_ERROR;
2897		goto get_method_cleanup;
2898	}
2899
2900	r = get_count(pg, SCF_PROPERTY_TIMEOUT, timeout);
2901	switch (r) {
2902	case 0:
2903		break;
2904
2905	case ECONNABORTED:
2906		error = LIBSCF_PROPERTY_ERROR;
2907		goto get_method_cleanup;
2908
2909	case EINVAL:
2910		log_instance(inst, B_TRUE, "%s/%s is multi-valued or not of "
2911		    "type count.  Using infinite timeout.", name,
2912		    SCF_PROPERTY_TIMEOUT);
2913		/* FALLTHROUGH */
2914	case ECANCELED:
2915	case ENOENT:
2916		*timeout = METHOD_TIMEOUT_INFINITE;
2917		break;
2918
2919	case EACCES:
2920	default:
2921		bad_error("get_count", r);
2922	}
2923
2924	/* Both 0 and -1 (ugh) are considered infinite timeouts. */
2925	if (*timeout == -1 || *timeout == 0)
2926		*timeout = METHOD_TIMEOUT_INFINITE;
2927
2928	if (scf_instance_get_pg_composed(scf_inst, snap, SCF_PG_STARTD,
2929	    pg_startd) == -1) {
2930		switch (scf_error()) {
2931		case SCF_ERROR_CONNECTION_BROKEN:
2932		case SCF_ERROR_DELETED:
2933			error = LIBSCF_PROPERTY_ERROR;
2934			goto get_method_cleanup;
2935
2936		case SCF_ERROR_NOT_FOUND:
2937			*cte_mask = 0;
2938			break;
2939
2940		case SCF_ERROR_INVALID_ARGUMENT:
2941		case SCF_ERROR_HANDLE_MISMATCH:
2942		case SCF_ERROR_NOT_BOUND:
2943		case SCF_ERROR_NOT_SET:
2944			bad_error("scf_instance_get_pg_composed", scf_error());
2945		}
2946	} else {
2947		if (scf_pg_get_property(pg_startd, SCF_PROPERTY_IGNORE,
2948		    prop) == -1) {
2949			if (scf_error() == SCF_ERROR_NOT_FOUND)
2950				*cte_mask = 0;
2951			else {
2952				error = LIBSCF_PROPERTY_ERROR;
2953				goto get_method_cleanup;
2954			}
2955		} else {
2956			error = libscf_read_single_astring(h, prop, &ig);
2957			if (error != 0) {
2958				log_error(LOG_WARNING,
2959				    "%s: get_method failed: can't get a single "
2960				    "astring from %s/%s\n", inst->ri_i.i_fmri,
2961				    name, SCF_PROPERTY_IGNORE);
2962				goto get_method_cleanup;
2963			}
2964
2965			if (strcmp(ig, "core") == 0)
2966				*cte_mask = CT_PR_EV_CORE;
2967			else if (strcmp(ig, "signal") == 0)
2968				*cte_mask = CT_PR_EV_SIGNAL;
2969			else if (strcmp(ig, "core,signal") == 0 ||
2970			    strcmp(ig, "signal,core") == 0)
2971				*cte_mask = CT_PR_EV_CORE | CT_PR_EV_SIGNAL;
2972			else
2973				*cte_mask = 0;
2974		}
2975
2976		r = get_boolean(pg_startd, SCF_PROPERTY_NEED_SESSION,
2977		    need_sessionp);
2978		switch (r) {
2979		case 0:
2980			break;
2981
2982		case ECONNABORTED:
2983			error = LIBSCF_PROPERTY_ERROR;
2984			goto get_method_cleanup;
2985
2986		case ECANCELED:
2987		case ENOENT:
2988		case EINVAL:
2989			*need_sessionp = 0;
2990			break;
2991
2992		case EACCES:
2993		default:
2994			bad_error("get_boolean", r);
2995		}
2996
2997		/*
2998		 * Determine whether service has overriden retry after
2999		 * method timeout.  Default to retry if no value is
3000		 * specified.
3001		 */
3002		r = get_boolean(pg_startd, SCF_PROPERTY_TIMEOUT_RETRY,
3003		    timeout_retry);
3004		switch (r) {
3005		case 0:
3006			break;
3007
3008		case ECONNABORTED:
3009			error = LIBSCF_PROPERTY_ERROR;
3010			goto get_method_cleanup;
3011
3012		case ECANCELED:
3013		case ENOENT:
3014		case EINVAL:
3015			*timeout_retry = 1;
3016			break;
3017
3018		case EACCES:
3019		default:
3020			bad_error("get_boolean", r);
3021		}
3022	}
3023
3024	if (type != METHOD_START)
3025		goto get_method_cleanup;
3026
3027	/* Only start methods need to honor the restart_on property. */
3028
3029	if (scf_pg_get_property(pg, SCF_PROPERTY_RESTART_ON, prop) == -1) {
3030		if (scf_error() == SCF_ERROR_NOT_FOUND)
3031			*restart_on = METHOD_RESTART_ALL;
3032		else
3033			error = LIBSCF_PROPERTY_ERROR;
3034		goto get_method_cleanup;
3035	}
3036
3037	error = libscf_read_single_astring(h, prop, &restart);
3038	if (error != 0) {
3039		log_error(LOG_WARNING,
3040		    "%s: get_method failed: can't get a single astring "
3041		    "from %s/%s\n", inst->ri_i.i_fmri, name,
3042		    SCF_PROPERTY_RESTART_ON);
3043		goto get_method_cleanup;
3044	}
3045
3046	if (strcmp(restart, "all") == 0)
3047		*restart_on = METHOD_RESTART_ALL;
3048	else if (strcmp(restart, "external_fault") == 0)
3049		*restart_on = METHOD_RESTART_EXTERNAL_FAULT;
3050	else if (strcmp(restart, "any_fault") == 0)
3051		*restart_on = METHOD_RESTART_ANY_FAULT;
3052
3053get_method_cleanup:
3054	startd_free(ig, max_scf_value_size);
3055	startd_free(method, max_scf_value_size);
3056	startd_free(restart, max_scf_value_size);
3057
3058	scf_instance_destroy(scf_inst);
3059	scf_pg_destroy(pg);
3060	scf_pg_destroy(pg_startd);
3061	scf_property_destroy(prop);
3062
3063	if (error != 0 && ret != NULL) {
3064		free(ret);
3065		ret = NULL;
3066	}
3067
3068	errno = error;
3069	return (ret);
3070}
3071
3072/*
3073 * Returns 1 if we've reached the fault threshold
3074 */
3075int
3076update_fault_count(restarter_inst_t *inst, int type)
3077{
3078	assert(type == FAULT_COUNT_INCR || type == FAULT_COUNT_RESET);
3079
3080	if (type == FAULT_COUNT_INCR) {
3081		inst->ri_i.i_fault_count++;
3082		log_framework(LOG_INFO, "%s: Increasing fault count to %d\n",
3083		    inst->ri_i.i_fmri, inst->ri_i.i_fault_count);
3084	}
3085	if (type == FAULT_COUNT_RESET)
3086		inst->ri_i.i_fault_count = 0;
3087
3088	if (inst->ri_i.i_fault_count >= FAULT_THRESHOLD)
3089		return (1);
3090
3091	return (0);
3092}
3093
3094/*
3095 * int libscf_unset_action()
3096 *   Delete any pending timestamps for the specified action which is
3097 *   older than the supplied ts.
3098 *
3099 *   Returns 0 on success, ECONNABORTED, EACCES, or EPERM on failure.
3100 */
3101int
3102libscf_unset_action(scf_handle_t *h, scf_propertygroup_t *pg,
3103    admin_action_t a, hrtime_t ts)
3104{
3105	scf_transaction_t *t;
3106	scf_transaction_entry_t *e;
3107	scf_property_t *prop;
3108	scf_value_t *val;
3109	hrtime_t rep_ts;
3110	int ret = 0, r;
3111
3112	t = safe_scf_transaction_create(h);
3113	e = safe_scf_entry_create(h);
3114	prop = safe_scf_property_create(h);
3115	val = safe_scf_value_create(h);
3116
3117	for (;;) {
3118		if (scf_pg_update(pg) == -1) {
3119			switch (scf_error()) {
3120			case SCF_ERROR_CONNECTION_BROKEN:
3121			default:
3122				ret = ECONNABORTED;
3123				goto unset_action_cleanup;
3124
3125			case SCF_ERROR_DELETED:
3126				goto unset_action_cleanup;
3127
3128			case SCF_ERROR_NOT_SET:
3129				assert(0);
3130				abort();
3131			}
3132		}
3133
3134		if (scf_transaction_start(t, pg) == -1) {
3135			switch (scf_error()) {
3136			case SCF_ERROR_CONNECTION_BROKEN:
3137			default:
3138				ret = ECONNABORTED;
3139				goto unset_action_cleanup;
3140
3141			case SCF_ERROR_DELETED:
3142				goto unset_action_cleanup;
3143
3144			case SCF_ERROR_PERMISSION_DENIED:
3145				ret = EPERM;
3146				goto unset_action_cleanup;
3147
3148			case SCF_ERROR_BACKEND_ACCESS:
3149			case SCF_ERROR_BACKEND_READONLY:
3150				ret = EACCES;
3151				goto unset_action_cleanup;
3152
3153			case SCF_ERROR_IN_USE:
3154			case SCF_ERROR_HANDLE_MISMATCH:
3155			case SCF_ERROR_NOT_SET:
3156				assert(0);
3157				abort();
3158			}
3159		}
3160
3161		/* Return failure only if the property hasn't been deleted. */
3162		if (scf_pg_get_property(pg, admin_actions[a], prop) == -1) {
3163			switch (scf_error()) {
3164			case SCF_ERROR_CONNECTION_BROKEN:
3165			default:
3166				ret = ECONNABORTED;
3167				goto unset_action_cleanup;
3168
3169			case SCF_ERROR_DELETED:
3170			case SCF_ERROR_NOT_FOUND:
3171				goto unset_action_cleanup;
3172
3173			case SCF_ERROR_HANDLE_MISMATCH:
3174			case SCF_ERROR_INVALID_ARGUMENT:
3175			case SCF_ERROR_NOT_SET:
3176				assert(0);
3177				abort();
3178			}
3179		}
3180
3181		if (scf_property_get_value(prop, val) == -1) {
3182			switch (scf_error()) {
3183			case SCF_ERROR_CONNECTION_BROKEN:
3184			default:
3185				ret = ECONNABORTED;
3186				goto unset_action_cleanup;
3187
3188			case SCF_ERROR_DELETED:
3189			case SCF_ERROR_NOT_FOUND:
3190				goto unset_action_cleanup;
3191
3192			case SCF_ERROR_CONSTRAINT_VIOLATED:
3193				/*
3194				 * More than one value was associated with
3195				 * this property -- this is incorrect. Take
3196				 * the opportunity to clean up and clear the
3197				 * entire property.
3198				 */
3199				rep_ts = ts;
3200				break;
3201
3202			case SCF_ERROR_PERMISSION_DENIED:
3203			case SCF_ERROR_NOT_SET:
3204				assert(0);
3205				abort();
3206			}
3207		} else if (scf_value_get_integer(val, &rep_ts) == -1) {
3208			assert(scf_error() == SCF_ERROR_TYPE_MISMATCH);
3209			rep_ts = 0;
3210		}
3211
3212		/* Repository ts is more current. Don't clear the action. */
3213		if (rep_ts > ts)
3214			goto unset_action_cleanup;
3215
3216		r = scf_transaction_property_change_type(t, e,
3217		    admin_actions[a], SCF_TYPE_INTEGER);
3218		assert(r == 0);
3219
3220		r = scf_transaction_commit(t);
3221		if (r == 1)
3222			break;
3223
3224		if (r != 0) {
3225			switch (scf_error()) {
3226			case SCF_ERROR_CONNECTION_BROKEN:
3227			default:
3228				ret = ECONNABORTED;
3229				goto unset_action_cleanup;
3230
3231			case SCF_ERROR_DELETED:
3232				break;
3233
3234			case SCF_ERROR_PERMISSION_DENIED:
3235				ret = EPERM;
3236				goto unset_action_cleanup;
3237
3238			case SCF_ERROR_BACKEND_ACCESS:
3239			case SCF_ERROR_BACKEND_READONLY:
3240				ret = EACCES;
3241				goto unset_action_cleanup;
3242
3243			case SCF_ERROR_INVALID_ARGUMENT:
3244			case SCF_ERROR_NOT_SET:
3245				assert(0);
3246				abort();
3247			}
3248		}
3249
3250		scf_transaction_reset(t);
3251	}
3252
3253unset_action_cleanup:
3254	scf_transaction_destroy(t);
3255	scf_entry_destroy(e);
3256	scf_property_destroy(prop);
3257	scf_value_destroy(val);
3258
3259	return (ret);
3260}
3261
3262/*
3263 * Decorates & binds hndl.  hndl must be unbound.  Returns
3264 *   0 - success
3265 *   -1 - repository server is not running
3266 *   -1 - repository server is out of resources
3267 */
3268static int
3269handle_decorate_and_bind(scf_handle_t *hndl)
3270{
3271	scf_value_t *door_dec_value;
3272
3273	door_dec_value = safe_scf_value_create(hndl);
3274
3275	/*
3276	 * Decorate if alternate door path set.
3277	 */
3278	if (st->st_door_path) {
3279		if (scf_value_set_astring(door_dec_value, st->st_door_path) !=
3280		    0)
3281			uu_die("$STARTD_ALT_DOOR is too long.\n");
3282
3283		if (scf_handle_decorate(hndl, "door_path", door_dec_value) != 0)
3284			bad_error("scf_handle_decorate", scf_error());
3285	}
3286
3287	scf_value_destroy(door_dec_value);
3288
3289	if (scf_handle_bind(hndl) == 0)
3290		return (0);
3291
3292	switch (scf_error()) {
3293	case SCF_ERROR_NO_SERVER:
3294	case SCF_ERROR_NO_RESOURCES:
3295		return (-1);
3296
3297	case SCF_ERROR_INVALID_ARGUMENT:
3298	case SCF_ERROR_IN_USE:
3299	default:
3300		bad_error("scf_handle_bind", scf_error());
3301		/* NOTREACHED */
3302	}
3303}
3304
3305scf_handle_t *
3306libscf_handle_create_bound(scf_version_t v)
3307{
3308	scf_handle_t *hndl = scf_handle_create(v);
3309
3310	if (hndl == NULL)
3311		return (hndl);
3312
3313	if (handle_decorate_and_bind(hndl) == 0)
3314		return (hndl);
3315
3316	scf_handle_destroy(hndl);
3317	return (NULL);
3318}
3319
3320void
3321libscf_handle_rebind(scf_handle_t *h)
3322{
3323	(void) scf_handle_unbind(h);
3324
3325	MUTEX_LOCK(&st->st_configd_live_lock);
3326
3327	/*
3328	 * Try to rebind the handle before sleeping in case the server isn't
3329	 * really dead.
3330	 */
3331	while (handle_decorate_and_bind(h) != 0)
3332		(void) pthread_cond_wait(&st->st_configd_live_cv,
3333		    &st->st_configd_live_lock);
3334
3335	MUTEX_UNLOCK(&st->st_configd_live_lock);
3336}
3337
3338/*
3339 * Create a handle and try to bind it until it succeeds.  Always returns
3340 * a bound handle.
3341 */
3342scf_handle_t *
3343libscf_handle_create_bound_loop()
3344{
3345	scf_handle_t *h;
3346
3347	while ((h = scf_handle_create(SCF_VERSION)) == NULL) {
3348		/* This should have been caught earlier. */
3349		assert(scf_error() != SCF_ERROR_VERSION_MISMATCH);
3350		(void) sleep(2);
3351	}
3352
3353	if (handle_decorate_and_bind(h) != 0)
3354		libscf_handle_rebind(h);
3355
3356	return (h);
3357}
3358
3359/*
3360 * Call cb for each dependency property group of inst.  cb is invoked with
3361 * a pointer to the scf_propertygroup_t and arg.  If the repository connection
3362 * is broken, returns ECONNABORTED.  If inst is deleted, returns ECANCELED.
3363 * If cb returns non-zero, the walk is stopped and EINTR is returned.
3364 * Otherwise returns 0.
3365 */
3366int
3367walk_dependency_pgs(scf_instance_t *inst, callback_t cb, void *arg)
3368{
3369	scf_handle_t *h;
3370	scf_snapshot_t *snap;
3371	scf_iter_t *iter;
3372	scf_propertygroup_t *pg;
3373	int r;
3374
3375	h = scf_instance_handle(inst);
3376
3377	iter = safe_scf_iter_create(h);
3378	pg = safe_scf_pg_create(h);
3379
3380	snap = libscf_get_running_snapshot(inst);
3381
3382	if (scf_iter_instance_pgs_typed_composed(iter, inst, snap,
3383	    SCF_GROUP_DEPENDENCY) != 0) {
3384		scf_snapshot_destroy(snap);
3385		scf_pg_destroy(pg);
3386		scf_iter_destroy(iter);
3387		switch (scf_error()) {
3388		case SCF_ERROR_CONNECTION_BROKEN:
3389		default:
3390			return (ECONNABORTED);
3391
3392		case SCF_ERROR_DELETED:
3393			return (ECANCELED);
3394
3395		case SCF_ERROR_HANDLE_MISMATCH:
3396		case SCF_ERROR_INVALID_ARGUMENT:
3397		case SCF_ERROR_NOT_SET:
3398			assert(0);
3399			abort();
3400		}
3401	}
3402
3403	for (;;) {
3404		r = scf_iter_next_pg(iter, pg);
3405		if (r == 0)
3406			break;
3407		if (r == -1) {
3408			scf_snapshot_destroy(snap);
3409			scf_pg_destroy(pg);
3410			scf_iter_destroy(iter);
3411
3412			switch (scf_error()) {
3413			case SCF_ERROR_CONNECTION_BROKEN:
3414				return (ECONNABORTED);
3415
3416			case SCF_ERROR_DELETED:
3417				return (ECANCELED);
3418
3419			case SCF_ERROR_NOT_SET:
3420			case SCF_ERROR_INVALID_ARGUMENT:
3421			case SCF_ERROR_NOT_BOUND:
3422			case SCF_ERROR_HANDLE_MISMATCH:
3423			default:
3424				bad_error("scf_iter_next_pg", scf_error());
3425			}
3426		}
3427
3428		r = cb(pg, arg);
3429
3430		if (r != 0)
3431			break;
3432	}
3433
3434	scf_snapshot_destroy(snap);
3435	scf_pg_destroy(pg);
3436	scf_iter_destroy(iter);
3437
3438	return (r == 0 ? 0 : EINTR);
3439}
3440
3441/*
3442 * Call cb for each of the string values of prop.  cb is invoked with
3443 * a pointer to the string and arg.  If the connection to the repository is
3444 * broken, ECONNABORTED is returned.  If the property is deleted, ECANCELED is
3445 * returned.  If the property does not have astring type, EINVAL is returned.
3446 * If cb returns non-zero, the walk is stopped and EINTR is returned.
3447 * Otherwise 0 is returned.
3448 */
3449int
3450walk_property_astrings(scf_property_t *prop, callback_t cb, void *arg)
3451{
3452	scf_handle_t *h;
3453	scf_value_t *val;
3454	scf_iter_t *iter;
3455	char *buf;
3456	int r;
3457	ssize_t sz;
3458
3459	if (scf_property_is_type(prop, SCF_TYPE_ASTRING) != 0) {
3460		switch (scf_error()) {
3461		case SCF_ERROR_CONNECTION_BROKEN:
3462		default:
3463			return (ECONNABORTED);
3464
3465		case SCF_ERROR_DELETED:
3466			return (ECANCELED);
3467
3468		case SCF_ERROR_TYPE_MISMATCH:
3469			return (EINVAL);
3470
3471		case SCF_ERROR_NOT_SET:
3472			assert(0);
3473			abort();
3474		}
3475	}
3476
3477	h = scf_property_handle(prop);
3478
3479	val = safe_scf_value_create(h);
3480	iter = safe_scf_iter_create(h);
3481
3482	if (scf_iter_property_values(iter, prop) != 0) {
3483		scf_iter_destroy(iter);
3484		scf_value_destroy(val);
3485		switch (scf_error()) {
3486		case SCF_ERROR_CONNECTION_BROKEN:
3487		default:
3488			return (ECONNABORTED);
3489
3490		case SCF_ERROR_DELETED:
3491			return (ECANCELED);
3492
3493		case SCF_ERROR_HANDLE_MISMATCH:
3494		case SCF_ERROR_NOT_SET:
3495			assert(0);
3496			abort();
3497		}
3498	}
3499
3500	buf = startd_alloc(max_scf_value_size);
3501
3502	for (;;) {
3503		r = scf_iter_next_value(iter, val);
3504		if (r < 0) {
3505			startd_free(buf, max_scf_value_size);
3506			scf_iter_destroy(iter);
3507			scf_value_destroy(val);
3508
3509			switch (scf_error()) {
3510			case SCF_ERROR_CONNECTION_BROKEN:
3511				return (ECONNABORTED);
3512
3513			case SCF_ERROR_DELETED:
3514				return (ECANCELED);
3515
3516			case SCF_ERROR_NOT_SET:
3517			case SCF_ERROR_INVALID_ARGUMENT:
3518			case SCF_ERROR_NOT_BOUND:
3519			case SCF_ERROR_HANDLE_MISMATCH:
3520			case SCF_ERROR_PERMISSION_DENIED:
3521			default:
3522				bad_error("scf_iter_next_value", scf_error());
3523			}
3524		}
3525		if (r == 0)
3526			break;
3527
3528		sz = scf_value_get_astring(val, buf, max_scf_value_size);
3529		assert(sz >= 0);
3530
3531		r = cb(buf, arg);
3532
3533		if (r != 0)
3534			break;
3535	}
3536
3537	startd_free(buf, max_scf_value_size);
3538	scf_value_destroy(val);
3539	scf_iter_destroy(iter);
3540
3541	return (r == 0 ? 0 : EINTR);
3542}
3543
3544/*
3545 * Returns 0 or ECONNABORTED.
3546 */
3547int
3548libscf_create_self(scf_handle_t *h)
3549{
3550	scf_scope_t *scope;
3551	scf_service_t *svc;
3552	scf_instance_t *inst;
3553	instance_data_t idata;
3554	int ret = 0, r;
3555	ctid_t ctid;
3556	uint64_t uint64;
3557	uint_t count = 0, msecs = ALLOC_DELAY;
3558
3559	const char * const startd_svc = "system/svc/restarter";
3560	const char * const startd_inst = "default";
3561
3562	/* If SCF_SERVICE_STARTD changes, our strings must change, too. */
3563	assert(strcmp(SCF_SERVICE_STARTD,
3564	    "svc:/system/svc/restarter:default") == 0);
3565
3566	scope = safe_scf_scope_create(h);
3567	svc = safe_scf_service_create(h);
3568	inst = safe_scf_instance_create(h);
3569
3570	if (scf_handle_get_scope(h, SCF_SCOPE_LOCAL, scope) != 0) {
3571		assert(scf_error() == SCF_ERROR_CONNECTION_BROKEN);
3572		ret = ECONNABORTED;
3573		goto out;
3574	}
3575
3576get_svc:
3577	if (scf_scope_get_service(scope, startd_svc, svc) != 0) {
3578		switch (scf_error()) {
3579		case SCF_ERROR_CONNECTION_BROKEN:
3580		case SCF_ERROR_DELETED:
3581		default:
3582			ret = ECONNABORTED;
3583			goto out;
3584
3585		case SCF_ERROR_NOT_FOUND:
3586			break;
3587
3588		case SCF_ERROR_HANDLE_MISMATCH:
3589		case SCF_ERROR_INVALID_ARGUMENT:
3590		case SCF_ERROR_NOT_SET:
3591			bad_error("scf_scope_get_service", scf_error());
3592		}
3593
3594add_svc:
3595		if (scf_scope_add_service(scope, startd_svc, svc) != 0) {
3596			switch (scf_error()) {
3597			case SCF_ERROR_CONNECTION_BROKEN:
3598			case SCF_ERROR_DELETED:
3599			default:
3600				ret = ECONNABORTED;
3601				goto out;
3602
3603			case SCF_ERROR_EXISTS:
3604				goto get_svc;
3605
3606			case SCF_ERROR_PERMISSION_DENIED:
3607			case SCF_ERROR_BACKEND_ACCESS:
3608			case SCF_ERROR_BACKEND_READONLY:
3609				uu_warn("Could not create %s: %s\n",
3610				    SCF_SERVICE_STARTD,
3611				    scf_strerror(scf_error()));
3612				goto out;
3613
3614			case SCF_ERROR_HANDLE_MISMATCH:
3615			case SCF_ERROR_INVALID_ARGUMENT:
3616			case SCF_ERROR_NOT_SET:
3617				bad_error("scf_scope_add_service", scf_error());
3618			}
3619		}
3620	}
3621
3622	if (scf_service_get_instance(svc, startd_inst, NULL) == 0)
3623		goto out;
3624
3625	switch (scf_error()) {
3626	case SCF_ERROR_CONNECTION_BROKEN:
3627	default:
3628		ret = ECONNABORTED;
3629		goto out;
3630
3631	case SCF_ERROR_NOT_FOUND:
3632		break;
3633
3634	case SCF_ERROR_DELETED:
3635		goto add_svc;
3636
3637	case SCF_ERROR_HANDLE_MISMATCH:
3638	case SCF_ERROR_INVALID_ARGUMENT:
3639	case SCF_ERROR_NOT_SET:
3640		bad_error("scf_service_get_instance", scf_error());
3641	}
3642
3643add_inst:
3644	if (scf_service_add_instance(svc, startd_inst, inst) != 0) {
3645		switch (scf_error()) {
3646		case SCF_ERROR_CONNECTION_BROKEN:
3647		default:
3648			ret = ECONNABORTED;
3649			goto out;
3650
3651		case SCF_ERROR_EXISTS:
3652			break;
3653
3654		case SCF_ERROR_PERMISSION_DENIED:
3655		case SCF_ERROR_BACKEND_ACCESS:
3656			uu_die("Could not create %s: %s\n", SCF_SERVICE_STARTD,
3657			    scf_strerror(scf_error()));
3658			/* NOTREACHED */
3659
3660		case SCF_ERROR_BACKEND_READONLY:
3661			log_error(LOG_NOTICE,
3662			    "Could not create %s: backend readonly.\n",
3663			    SCF_SERVICE_STARTD);
3664			goto out;
3665
3666		case SCF_ERROR_DELETED:
3667			goto add_svc;
3668
3669		case SCF_ERROR_HANDLE_MISMATCH:
3670		case SCF_ERROR_INVALID_ARGUMENT:
3671		case SCF_ERROR_NOT_SET:
3672			bad_error("scf_service_add_instance", scf_error());
3673		}
3674	}
3675
3676	/* Set start time. */
3677	idata.i_fmri = SCF_SERVICE_STARTD;
3678	idata.i_state = RESTARTER_STATE_NONE;
3679	idata.i_next_state = RESTARTER_STATE_NONE;
3680set_state:
3681	switch (r = _restarter_commit_states(h, &idata, RESTARTER_STATE_ONLINE,
3682	    RESTARTER_STATE_NONE, NULL)) {
3683	case 0:
3684		break;
3685
3686	case ENOMEM:
3687		++count;
3688		if (count < ALLOC_RETRY) {
3689			(void) poll(NULL, 0, msecs);
3690			msecs *= ALLOC_DELAY_MULT;
3691			goto set_state;
3692		}
3693
3694		uu_die("Insufficient memory.\n");
3695		/* NOTREACHED */
3696
3697	case ECONNABORTED:
3698		ret = ECONNABORTED;
3699		goto out;
3700
3701	case ENOENT:
3702		goto add_inst;
3703
3704	case EPERM:
3705	case EACCES:
3706	case EROFS:
3707		uu_warn("Could not timestamp %s: %s\n", idata.i_fmri,
3708		    strerror(r));
3709		break;
3710
3711	case EINVAL:
3712	default:
3713		bad_error("_restarter_commit_states", r);
3714	}
3715
3716	/* Set general/enabled. */
3717	ret = libscf_inst_set_boolean_prop(inst, SCF_PG_GENERAL,
3718	    SCF_PG_GENERAL_TYPE, SCF_PG_GENERAL_FLAGS, SCF_PROPERTY_ENABLED, 1);
3719	switch (ret) {
3720	case 0:
3721	case ECONNABORTED:
3722	case EPERM:
3723	case EACCES:
3724	case EROFS:
3725		break;
3726
3727	case ECANCELED:
3728		goto add_inst;
3729
3730	default:
3731		bad_error("libscf_inst_set_boolean_prop", ret);
3732	}
3733
3734	ret = libscf_write_start_pid(inst, getpid());
3735	switch (ret) {
3736	case 0:
3737	case ECONNABORTED:
3738	case EPERM:
3739	case EACCES:
3740	case EROFS:
3741		break;
3742
3743	case ECANCELED:
3744		goto add_inst;
3745
3746	default:
3747		bad_error("libscf_write_start_pid", ret);
3748	}
3749
3750	ctid = proc_get_ctid();
3751	if (ctid > 0) {
3752
3753		uint64 = (uint64_t)ctid;
3754		ret = libscf_inst_set_count_prop(inst,
3755		    SCF_PG_RESTARTER, SCF_PG_RESTARTER_TYPE,
3756		    SCF_PG_RESTARTER_FLAGS, SCF_PROPERTY_CONTRACT, uint64);
3757
3758		switch (ret) {
3759		case 0:
3760		case ECONNABORTED:
3761		case EPERM:
3762		case EACCES:
3763		case EROFS:
3764			break;
3765
3766		case ECANCELED:
3767			goto add_inst;
3768
3769		default:
3770			bad_error("libscf_inst_set_count_prop", ret);
3771		}
3772	}
3773
3774	ret = libscf_note_method_log(inst, LOG_PREFIX_EARLY,
3775	    STARTD_DEFAULT_LOG);
3776	if (ret == 0) {
3777		ret = libscf_note_method_log(inst, LOG_PREFIX_NORMAL,
3778		    STARTD_DEFAULT_LOG);
3779	}
3780
3781	switch (ret) {
3782		case ECONNABORTED:
3783		case EPERM:
3784		case EACCES:
3785		case EROFS:
3786		case EAGAIN:
3787			break;
3788
3789		case ECANCELED:
3790			goto add_inst;
3791
3792		default:
3793			bad_error("libscf_note_method_log", ret);
3794	}
3795
3796out:
3797	scf_instance_destroy(inst);
3798	scf_service_destroy(svc);
3799	scf_scope_destroy(scope);
3800	return (ret);
3801}
3802
3803/*
3804 * Returns
3805 *   0 - success
3806 *   ENOENT - SCF_SERVICE_STARTD does not exist in repository
3807 *   EPERM
3808 *   EACCES
3809 *   EROFS
3810 */
3811int
3812libscf_set_reconfig(int set)
3813{
3814	scf_handle_t *h;
3815	scf_instance_t *inst;
3816	scf_propertygroup_t *pg;
3817	int ret = 0;
3818
3819	h = libscf_handle_create_bound_loop();
3820	inst = safe_scf_instance_create(h);
3821	pg = safe_scf_pg_create(h);
3822
3823again:
3824	if (scf_handle_decode_fmri(h, SCF_SERVICE_STARTD, NULL, NULL,
3825	    inst, NULL, NULL,  SCF_DECODE_FMRI_EXACT) == -1) {
3826		switch (scf_error()) {
3827		case SCF_ERROR_CONNECTION_BROKEN:
3828		default:
3829			libscf_handle_rebind(h);
3830			goto again;
3831
3832		case SCF_ERROR_NOT_FOUND:
3833			ret = ENOENT;
3834			goto reconfig_out;
3835
3836		case SCF_ERROR_HANDLE_MISMATCH:
3837		case SCF_ERROR_INVALID_ARGUMENT:
3838		case SCF_ERROR_CONSTRAINT_VIOLATED:
3839			bad_error("scf_handle_decode_fmri", scf_error());
3840		}
3841	}
3842
3843	ret = libscf_inst_set_boolean_prop(inst, "system", SCF_GROUP_FRAMEWORK,
3844	    SCF_PG_FLAG_NONPERSISTENT, "reconfigure", set);
3845	switch (ret) {
3846	case 0:
3847	case EPERM:
3848	case EACCES:
3849	case EROFS:
3850		break;
3851
3852	case ECONNABORTED:
3853		libscf_handle_rebind(h);
3854		goto again;
3855
3856	case ECANCELED:
3857		ret = ENOENT;
3858		break;
3859
3860	default:
3861		bad_error("libscf_inst_set_boolean_prop", ret);
3862	}
3863
3864reconfig_out:
3865	scf_pg_destroy(pg);
3866	scf_instance_destroy(inst);
3867	scf_handle_destroy(h);
3868	return (ret);
3869}
3870
3871/*
3872 * Set inst->ri_m_inst to the scf instance for inst.  If it has been deleted,
3873 * set inst->ri_mi_deleted to true.  If the repository connection is broken, it
3874 * is rebound with libscf_handle_rebound().
3875 */
3876void
3877libscf_reget_instance(restarter_inst_t *inst)
3878{
3879	scf_handle_t *h;
3880	int r;
3881
3882	h = scf_instance_handle(inst->ri_m_inst);
3883
3884again:
3885	r = libscf_lookup_instance(inst->ri_i.i_fmri, inst->ri_m_inst);
3886	switch (r) {
3887	case 0:
3888	case ENOENT:
3889		inst->ri_mi_deleted = (r == ENOENT);
3890		return;
3891
3892	case ECONNABORTED:
3893		libscf_handle_rebind(h);
3894		goto again;
3895
3896	case EINVAL:
3897	case ENOTSUP:
3898	default:
3899		bad_error("libscf_lookup_instance", r);
3900	}
3901}
3902