midlevel.c revision 8823:000507e9108d
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#include "libscf_impl.h"
28
29#include <assert.h>
30#include <libuutil.h>
31#include <stdio.h>
32#include <strings.h>
33#include <string.h>
34#include <stdlib.h>
35#include <sys/param.h>
36#include <errno.h>
37#include <libgen.h>
38#include <assert.h>
39#include "midlevel_impl.h"
40#include "lowlevel_impl.h"
41
42#ifndef NDEBUG
43#define	bad_error(func, err)	{					\
44	uu_warn("%s:%d: %s failed with unexpected error %d.  Aborting.\n", \
45	    __FILE__, __LINE__, func, err);				\
46	abort();							\
47}
48#else
49#define	bad_error(func, err)	abort()
50#endif
51
52/* Path to speedy files area must end with a slash */
53#define	SMF_SPEEDY_FILES_PATH		"/etc/svc/volatile/"
54
55/*
56 * Internal private function that creates and binds a handle.
57 */
58static scf_handle_t *
59handle_create(void)
60{
61	scf_handle_t *h;
62
63	h = scf_handle_create(SCF_VERSION);
64	if (h == NULL)
65		return (NULL);
66
67	if (scf_handle_bind(h) == -1) {
68		scf_handle_destroy(h);
69		return (NULL);
70	}
71	return (h);
72}
73
74void
75scf_simple_handle_destroy(scf_simple_handle_t *simple_h)
76{
77	if (simple_h == NULL)
78		return;
79
80	scf_pg_destroy(simple_h->running_pg);
81	scf_pg_destroy(simple_h->editing_pg);
82	scf_snapshot_destroy(simple_h->snap);
83	scf_instance_destroy(simple_h->inst);
84	scf_handle_destroy(simple_h->h);
85	uu_free(simple_h);
86}
87
88/*
89 * Given a base service FMRI and the names of a property group and property,
90 * assemble_fmri() merges them into a property FMRI.  Note that if the base
91 * FMRI is NULL, assemble_fmri() gets the base FMRI from scf_myname().
92 */
93
94static char *
95assemble_fmri(scf_handle_t *h, const char *base, const char *pg,
96    const char *prop)
97{
98	size_t	fmri_sz, pglen;
99	ssize_t baselen;
100	char	*fmri_buf;
101
102	if (prop == NULL) {
103		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
104		return (NULL);
105	}
106
107	if (pg == NULL)
108		pglen = strlen(SCF_PG_APP_DEFAULT);
109	else
110		pglen = strlen(pg);
111
112	if (base == NULL) {
113		if ((baselen = scf_myname(h, NULL, 0)) == -1)
114			return (NULL);
115	} else {
116		baselen = strlen(base);
117	}
118
119	fmri_sz = baselen + sizeof (SCF_FMRI_PROPERTYGRP_PREFIX) - 1 +
120	    pglen + sizeof (SCF_FMRI_PROPERTY_PREFIX) - 1 +
121	    strlen(prop) + 1;
122
123	if ((fmri_buf = malloc(fmri_sz)) == NULL) {
124		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
125		return (NULL);
126	}
127
128	if (base == NULL) {
129		if (scf_myname(h, fmri_buf, fmri_sz) == -1) {
130			free(fmri_buf);
131			return (NULL);
132		}
133	} else {
134		(void) strcpy(fmri_buf, base);
135	}
136
137	(void) strcat(fmri_buf, SCF_FMRI_PROPERTYGRP_PREFIX);
138
139	if (pg == NULL)
140		(void) strcat(fmri_buf, SCF_PG_APP_DEFAULT);
141	else
142		(void) strcat(fmri_buf, pg);
143
144	(void) strcat(fmri_buf, SCF_FMRI_PROPERTY_PREFIX);
145	(void) strcat(fmri_buf, prop);
146	return (fmri_buf);
147}
148
149/*
150 * Given a property, this function allocates and fills an scf_simple_prop_t
151 * with the data it contains.
152 */
153
154static scf_simple_prop_t *
155fill_prop(scf_property_t *prop, const char *pgname, const char *propname,
156    scf_handle_t *h)
157{
158	scf_simple_prop_t 		*ret;
159	scf_iter_t 			*iter;
160	scf_value_t 			*val;
161	int 				iterret, i;
162	ssize_t 			valsize, numvals;
163	union scf_simple_prop_val 	*vallist = NULL, *vallist_backup = NULL;
164
165	if ((ret = malloc(sizeof (*ret))) == NULL) {
166		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
167		return (NULL);
168	}
169
170	ret->pr_next = NULL;
171	ret->pr_pg = NULL;
172	ret->pr_iter = 0;
173
174	if (pgname == NULL)
175		ret->pr_pgname = strdup(SCF_PG_APP_DEFAULT);
176	else
177		ret->pr_pgname = strdup(pgname);
178
179	if (ret->pr_pgname == NULL) {
180		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
181		free(ret);
182		return (NULL);
183	}
184
185	if ((ret->pr_propname = strdup(propname)) == NULL) {
186		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
187		free(ret->pr_pgname);
188		free(ret);
189		return (NULL);
190	}
191
192	if (scf_property_type(prop, &ret->pr_type) == -1)
193		goto error3;
194
195	if ((iter = scf_iter_create(h)) == NULL)
196		goto error3;
197	if ((val = scf_value_create(h)) == NULL) {
198		scf_iter_destroy(iter);
199		goto error3;
200	}
201
202	if (scf_iter_property_values(iter, prop) == -1)
203		goto error1;
204
205	for (numvals = 0; (iterret = scf_iter_next_value(iter, val)) == 1;
206	    numvals++) {
207		vallist_backup = vallist;
208		if ((vallist = realloc(vallist, (numvals + 1) *
209		    sizeof (*vallist))) == NULL) {
210			vallist = vallist_backup;
211			goto error1;
212		}
213
214		switch (ret->pr_type) {
215		case SCF_TYPE_BOOLEAN:
216			if (scf_value_get_boolean(val,
217			    &vallist[numvals].pv_bool) == -1)
218				goto error1;
219			break;
220
221		case SCF_TYPE_COUNT:
222			if (scf_value_get_count(val,
223			    &vallist[numvals].pv_uint) == -1)
224				goto error1;
225			break;
226
227		case SCF_TYPE_INTEGER:
228			if (scf_value_get_integer(val,
229			    &vallist[numvals].pv_int) == -1)
230				goto error1;
231			break;
232
233		case SCF_TYPE_TIME:
234			if (scf_value_get_time(val,
235			    &vallist[numvals].pv_time.t_sec,
236			    &vallist[numvals].pv_time.t_nsec) == -1)
237				goto error1;
238			break;
239
240		case SCF_TYPE_ASTRING:
241			vallist[numvals].pv_str = NULL;
242			if ((valsize = scf_value_get_astring(val, NULL, 0)) ==
243			    -1)
244				goto error1;
245			if ((vallist[numvals].pv_str = malloc(valsize+1)) ==
246			    NULL) {
247				(void) scf_set_error(SCF_ERROR_NO_MEMORY);
248				goto error1;
249			}
250			if (scf_value_get_astring(val,
251			    vallist[numvals].pv_str, valsize+1) == -1) {
252				free(vallist[numvals].pv_str);
253				goto error1;
254			}
255			break;
256
257		case SCF_TYPE_USTRING:
258		case SCF_TYPE_HOST:
259		case SCF_TYPE_HOSTNAME:
260		case SCF_TYPE_NET_ADDR_V4:
261		case SCF_TYPE_NET_ADDR_V6:
262		case SCF_TYPE_URI:
263		case SCF_TYPE_FMRI:
264			vallist[numvals].pv_str = NULL;
265			if ((valsize = scf_value_get_ustring(val, NULL, 0)) ==
266			    -1)
267				goto error1;
268			if ((vallist[numvals].pv_str = malloc(valsize+1)) ==
269			    NULL) {
270				(void) scf_set_error(SCF_ERROR_NO_MEMORY);
271				goto error1;
272			}
273			if (scf_value_get_ustring(val,
274			    vallist[numvals].pv_str, valsize+1) == -1) {
275				free(vallist[numvals].pv_str);
276				goto error1;
277			}
278			break;
279
280		case SCF_TYPE_OPAQUE:
281			vallist[numvals].pv_opaque.o_value = NULL;
282			if ((valsize = scf_value_get_opaque(val, NULL, 0)) ==
283			    -1)
284				goto error1;
285			if ((vallist[numvals].pv_opaque.o_value =
286			    malloc(valsize)) == NULL) {
287				(void) scf_set_error(SCF_ERROR_NO_MEMORY);
288				goto error1;
289			}
290			vallist[numvals].pv_opaque.o_size = valsize;
291			if (scf_value_get_opaque(val,
292			    vallist[numvals].pv_opaque.o_value,
293			    valsize) == -1) {
294				free(vallist[numvals].pv_opaque.o_value);
295				goto error1;
296			}
297			break;
298
299		default:
300			(void) scf_set_error(SCF_ERROR_INTERNAL);
301			goto error1;
302
303		}
304	}
305
306	if (iterret == -1) {
307		int err = scf_error();
308		if (err != SCF_ERROR_CONNECTION_BROKEN &&
309		    err != SCF_ERROR_PERMISSION_DENIED)
310			(void) scf_set_error(SCF_ERROR_INTERNAL);
311		goto error1;
312	}
313
314	ret->pr_vallist = vallist;
315	ret->pr_numvalues = numvals;
316
317	scf_iter_destroy(iter);
318	(void) scf_value_destroy(val);
319
320	return (ret);
321
322	/*
323	 * Exit point for a successful call.  Below this line are exit points
324	 * for failures at various stages during the function.
325	 */
326
327error1:
328	if (vallist == NULL)
329		goto error2;
330
331	switch (ret->pr_type) {
332	case SCF_TYPE_ASTRING:
333	case SCF_TYPE_USTRING:
334	case SCF_TYPE_HOST:
335	case SCF_TYPE_HOSTNAME:
336	case SCF_TYPE_NET_ADDR_V4:
337	case SCF_TYPE_NET_ADDR_V6:
338	case SCF_TYPE_URI:
339	case SCF_TYPE_FMRI: {
340		for (i = 0; i < numvals; i++) {
341			free(vallist[i].pv_str);
342		}
343		break;
344	}
345	case SCF_TYPE_OPAQUE: {
346		for (i = 0; i < numvals; i++) {
347			free(vallist[i].pv_opaque.o_value);
348		}
349		break;
350	}
351	default:
352		break;
353	}
354
355	free(vallist);
356
357error2:
358	scf_iter_destroy(iter);
359	(void) scf_value_destroy(val);
360
361error3:
362	free(ret->pr_pgname);
363	free(ret->pr_propname);
364	free(ret);
365	return (NULL);
366}
367
368/*
369 * insert_app_props iterates over a property iterator, getting all the
370 * properties from a property group, and adding or overwriting them into
371 * a simple_app_props_t.  This is used by scf_simple_app_props_get to provide
372 * service/instance composition while filling the app_props_t.
373 * insert_app_props iterates over a single property group.
374 */
375
376static int
377insert_app_props(scf_iter_t *propiter, char *pgname, char *propname, struct
378    scf_simple_pg *thispg, scf_property_t *prop, size_t namelen,
379    scf_handle_t *h)
380{
381	scf_simple_prop_t	*thisprop, *prevprop, *newprop;
382	uint8_t			found;
383	int			propiter_ret;
384
385	while ((propiter_ret = scf_iter_next_property(propiter, prop)) == 1) {
386
387		if (scf_property_get_name(prop, propname, namelen) < 0) {
388			if (scf_error() == SCF_ERROR_NOT_SET)
389				(void) scf_set_error(SCF_ERROR_INTERNAL);
390			return (-1);
391		}
392
393		thisprop = thispg->pg_proplist;
394		prevprop = thispg->pg_proplist;
395		found = 0;
396
397		while ((thisprop != NULL) && (!found)) {
398			if (strcmp(thisprop->pr_propname, propname) == 0) {
399				found = 1;
400				if ((newprop = fill_prop(prop, pgname,
401				    propname, h)) == NULL)
402					return (-1);
403
404				if (thisprop == thispg->pg_proplist)
405					thispg->pg_proplist = newprop;
406				else
407					prevprop->pr_next = newprop;
408
409				newprop->pr_pg = thispg;
410				newprop->pr_next = thisprop->pr_next;
411				scf_simple_prop_free(thisprop);
412				thisprop = NULL;
413			} else {
414				if (thisprop != thispg->pg_proplist)
415					prevprop = prevprop->pr_next;
416				thisprop = thisprop->pr_next;
417			}
418		}
419
420		if (!found) {
421			if ((newprop = fill_prop(prop, pgname, propname, h)) ==
422			    NULL)
423				return (-1);
424
425			if (thispg->pg_proplist == NULL)
426				thispg->pg_proplist = newprop;
427			else
428				prevprop->pr_next = newprop;
429
430			newprop->pr_pg = thispg;
431		}
432	}
433
434	if (propiter_ret == -1) {
435		if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
436			(void) scf_set_error(SCF_ERROR_INTERNAL);
437		return (-1);
438	}
439
440	return (0);
441}
442
443
444/*
445 * Sets up e in tx to set pname's values.  Returns 0 on success or -1 on
446 * failure, with scf_error() set to
447 *   SCF_ERROR_HANDLE_MISMATCH - tx & e are derived from different handles
448 *   SCF_ERROR_INVALID_ARGUMENT - pname or ty are invalid
449 *   SCF_ERROR_NOT_BOUND - handle is not bound
450 *   SCF_ERROR_CONNECTION_BROKEN - connection was broken
451 *   SCF_ERROR_NOT_SET - tx has not been started
452 *   SCF_ERROR_DELETED - the pg tx was started on was deleted
453 */
454static int
455transaction_property_set(scf_transaction_t *tx, scf_transaction_entry_t *e,
456    const char *pname, scf_type_t ty)
457{
458	for (;;) {
459		if (scf_transaction_property_change_type(tx, e, pname, ty) == 0)
460			return (0);
461
462		switch (scf_error()) {
463		case SCF_ERROR_HANDLE_MISMATCH:
464		case SCF_ERROR_INVALID_ARGUMENT:
465		case SCF_ERROR_NOT_BOUND:
466		case SCF_ERROR_CONNECTION_BROKEN:
467		case SCF_ERROR_NOT_SET:
468		case SCF_ERROR_DELETED:
469		default:
470			return (-1);
471
472		case SCF_ERROR_NOT_FOUND:
473			break;
474		}
475
476		if (scf_transaction_property_new(tx, e, pname, ty) == 0)
477			return (0);
478
479		switch (scf_error()) {
480		case SCF_ERROR_HANDLE_MISMATCH:
481		case SCF_ERROR_INVALID_ARGUMENT:
482		case SCF_ERROR_NOT_BOUND:
483		case SCF_ERROR_CONNECTION_BROKEN:
484		case SCF_ERROR_NOT_SET:
485		case SCF_ERROR_DELETED:
486		default:
487			return (-1);
488
489		case SCF_ERROR_EXISTS:
490			break;
491		}
492	}
493}
494
495static int
496get_inst_enabled(const scf_instance_t *inst, const char *pgname)
497{
498	scf_propertygroup_t 	*gpg = NULL;
499	scf_property_t 		*eprop = NULL;
500	scf_value_t 		*v = NULL;
501	scf_handle_t		*h = NULL;
502	uint8_t			enabled;
503	int			ret = -1;
504
505	if ((h = scf_instance_handle(inst)) == NULL)
506		return (-1);
507
508	if ((gpg = scf_pg_create(h)) == NULL ||
509	    (eprop = scf_property_create(h)) == NULL ||
510	    (v = scf_value_create(h)) == NULL)
511		goto out;
512
513	if (scf_instance_get_pg(inst, pgname, gpg) ||
514	    scf_pg_get_property(gpg, SCF_PROPERTY_ENABLED, eprop) ||
515	    scf_property_get_value(eprop, v) ||
516	    scf_value_get_boolean(v, &enabled))
517		goto out;
518	ret = enabled;
519
520out:
521	scf_pg_destroy(gpg);
522	scf_property_destroy(eprop);
523	scf_value_destroy(v);
524	return (ret);
525}
526
527/*
528 * set_inst_enabled() is a "master" enable/disable call that takes the
529 * instance and the desired state for the enabled bit in the instance's
530 * named property group.  If the group doesn't exist, it's created with the
531 * given flags.  Called by smf_{dis,en}able_instance().
532 */
533static int
534set_inst_enabled(const scf_instance_t *inst, uint8_t desired,
535    const char *pgname, uint32_t pgflags)
536{
537	scf_transaction_t 	*tx = NULL;
538	scf_transaction_entry_t *ent = NULL;
539	scf_propertygroup_t 	*gpg = NULL;
540	scf_property_t 		*eprop = NULL;
541	scf_value_t 		*v = NULL;
542	scf_handle_t		*h = NULL;
543	int 			ret = -1;
544	int			committed;
545	uint8_t			b;
546
547	if ((h = scf_instance_handle(inst)) == NULL)
548		return (-1);
549
550	if ((gpg = scf_pg_create(h)) == NULL ||
551	    (eprop = scf_property_create(h)) == NULL ||
552	    (v = scf_value_create(h)) == NULL ||
553	    (tx = scf_transaction_create(h)) == NULL ||
554	    (ent = scf_entry_create(h)) == NULL)
555		goto out;
556
557general_pg_get:
558	if (scf_instance_get_pg(inst, SCF_PG_GENERAL, gpg) == -1) {
559		if (scf_error() != SCF_ERROR_NOT_FOUND)
560			goto out;
561
562		if (scf_instance_add_pg(inst, SCF_PG_GENERAL,
563		    SCF_GROUP_FRAMEWORK, SCF_PG_GENERAL_FLAGS, gpg) == -1) {
564			if (scf_error() != SCF_ERROR_EXISTS)
565				goto out;
566			goto general_pg_get;
567		}
568	}
569
570	if (strcmp(pgname, SCF_PG_GENERAL) != 0) {
571get:
572		if (scf_instance_get_pg(inst, pgname, gpg) == -1) {
573			if (scf_error() != SCF_ERROR_NOT_FOUND)
574				goto out;
575
576			if (scf_instance_add_pg(inst, pgname,
577			    SCF_GROUP_FRAMEWORK, pgflags, gpg) == -1) {
578				if (scf_error() != SCF_ERROR_EXISTS)
579					goto out;
580				goto get;
581			}
582		}
583	}
584
585	if (scf_pg_get_property(gpg, SCF_PROPERTY_ENABLED, eprop) == -1) {
586		if (scf_error() != SCF_ERROR_NOT_FOUND)
587			goto out;
588		else
589			goto set;
590	}
591
592	/*
593	 * If it's already set the way we want, forgo the transaction.
594	 */
595	if (scf_property_get_value(eprop, v) == -1) {
596		switch (scf_error()) {
597		case SCF_ERROR_CONSTRAINT_VIOLATED:
598		case SCF_ERROR_NOT_FOUND:
599			/* Misconfigured, so set anyway. */
600			goto set;
601
602		default:
603			goto out;
604		}
605	}
606	if (scf_value_get_boolean(v, &b) == -1) {
607		if (scf_error() != SCF_ERROR_TYPE_MISMATCH)
608			goto out;
609		goto set;
610	}
611	if (b == desired) {
612		ret = 0;
613		goto out;
614	}
615
616set:
617	do {
618		if (scf_transaction_start(tx, gpg) == -1)
619			goto out;
620
621		if (transaction_property_set(tx, ent, SCF_PROPERTY_ENABLED,
622		    SCF_TYPE_BOOLEAN) != 0) {
623			switch (scf_error()) {
624			case SCF_ERROR_CONNECTION_BROKEN:
625			case SCF_ERROR_DELETED:
626			default:
627				goto out;
628
629			case SCF_ERROR_HANDLE_MISMATCH:
630			case SCF_ERROR_INVALID_ARGUMENT:
631			case SCF_ERROR_NOT_BOUND:
632			case SCF_ERROR_NOT_SET:
633				bad_error("transaction_property_set",
634				    scf_error());
635			}
636		}
637
638		scf_value_set_boolean(v, desired);
639		if (scf_entry_add_value(ent, v) == -1)
640			goto out;
641
642		committed = scf_transaction_commit(tx);
643		if (committed == -1)
644			goto out;
645
646		scf_transaction_reset(tx);
647
648		if (committed == 0) { /* out-of-sync */
649			if (scf_pg_update(gpg) == -1)
650				goto out;
651		}
652	} while (committed == 0);
653
654	ret = 0;
655
656out:
657	scf_value_destroy(v);
658	scf_entry_destroy(ent);
659	scf_transaction_destroy(tx);
660	scf_property_destroy(eprop);
661	scf_pg_destroy(gpg);
662
663	return (ret);
664}
665
666static int
667delete_inst_enabled(const scf_instance_t *inst, const char *pgname)
668{
669	scf_transaction_t 	*tx = NULL;
670	scf_transaction_entry_t *ent = NULL;
671	scf_propertygroup_t 	*gpg = NULL;
672	scf_handle_t		*h = NULL;
673	int			ret = -1;
674	int			committed;
675
676	if ((h = scf_instance_handle(inst)) == NULL)
677		return (-1);
678
679	if ((gpg = scf_pg_create(h)) == NULL ||
680	    (tx = scf_transaction_create(h)) == NULL ||
681	    (ent = scf_entry_create(h)) == NULL)
682		goto out;
683
684	if (scf_instance_get_pg(inst, pgname, gpg) != 0)
685		goto error;
686	do {
687		if (scf_transaction_start(tx, gpg) == -1 ||
688		    scf_transaction_property_delete(tx, ent,
689		    SCF_PROPERTY_ENABLED) == -1 ||
690		    (committed = scf_transaction_commit(tx)) == -1)
691			goto error;
692
693		scf_transaction_reset(tx);
694
695		if (committed == 0 && scf_pg_update(gpg) == -1)
696			goto error;
697	} while (committed == 0);
698
699	ret = 0;
700	goto out;
701
702error:
703	switch (scf_error()) {
704	case SCF_ERROR_DELETED:
705	case SCF_ERROR_NOT_FOUND:
706		/* success */
707		ret = 0;
708	}
709
710out:
711	scf_entry_destroy(ent);
712	scf_transaction_destroy(tx);
713	scf_pg_destroy(gpg);
714
715	return (ret);
716}
717
718/*
719 * Returns 0 on success or -1 on failure.  On failure leaves scf_error() set to
720 *   SCF_ERROR_HANDLE_DESTROYED - inst's handle has been destroyed
721 *   SCF_ERROR_NOT_BOUND - inst's handle is not bound
722 *   SCF_ERROR_CONNECTION_BROKEN - the repository connection was broken
723 *   SCF_ERROR_NOT_SET - inst is not set
724 *   SCF_ERROR_DELETED - inst was deleted
725 *   SCF_ERROR_PERMISSION_DENIED
726 *   SCF_ERROR_BACKEND_ACCESS
727 *   SCF_ERROR_BACKEND_READONLY
728 */
729static int
730set_inst_action_inst(scf_instance_t *inst, const char *action)
731{
732	scf_handle_t			*h;
733	scf_transaction_t		*tx = NULL;
734	scf_transaction_entry_t		*ent = NULL;
735	scf_propertygroup_t		*pg = NULL;
736	scf_property_t			*prop = NULL;
737	scf_value_t			*v = NULL;
738	int				trans, ret = -1;
739	int64_t				t;
740	hrtime_t			timestamp;
741
742	if ((h = scf_instance_handle(inst)) == NULL ||
743	    (pg = scf_pg_create(h)) == NULL ||
744	    (prop = scf_property_create(h)) == NULL ||
745	    (v = scf_value_create(h)) == NULL ||
746	    (tx = scf_transaction_create(h)) == NULL ||
747	    (ent = scf_entry_create(h)) == NULL)
748		goto out;
749
750get:
751	if (scf_instance_get_pg(inst, SCF_PG_RESTARTER_ACTIONS, pg) == -1) {
752		switch (scf_error()) {
753		case SCF_ERROR_NOT_BOUND:
754		case SCF_ERROR_CONNECTION_BROKEN:
755		case SCF_ERROR_NOT_SET:
756		case SCF_ERROR_DELETED:
757		default:
758			goto out;
759
760		case SCF_ERROR_NOT_FOUND:
761			break;
762
763		case SCF_ERROR_HANDLE_MISMATCH:
764		case SCF_ERROR_INVALID_ARGUMENT:
765			bad_error("scf_instance_get_pg", scf_error());
766		}
767
768		/* Try creating the restarter_actions property group. */
769add:
770		if (scf_instance_add_pg(inst, SCF_PG_RESTARTER_ACTIONS,
771		    SCF_PG_RESTARTER_ACTIONS_TYPE,
772		    SCF_PG_RESTARTER_ACTIONS_FLAGS, pg) == -1) {
773			switch (scf_error()) {
774			case SCF_ERROR_NOT_BOUND:
775			case SCF_ERROR_CONNECTION_BROKEN:
776			case SCF_ERROR_NOT_SET:
777			case SCF_ERROR_DELETED:
778			case SCF_ERROR_PERMISSION_DENIED:
779			case SCF_ERROR_BACKEND_ACCESS:
780			case SCF_ERROR_BACKEND_READONLY:
781			default:
782				goto out;
783
784			case SCF_ERROR_EXISTS:
785				goto get;
786
787			case SCF_ERROR_HANDLE_MISMATCH:
788			case SCF_ERROR_INVALID_ARGUMENT:
789				bad_error("scf_instance_add_pg", scf_error());
790			}
791		}
792	}
793
794	for (;;) {
795		timestamp = gethrtime();
796
797		if (scf_pg_get_property(pg, action, prop) != 0) {
798			switch (scf_error()) {
799			case SCF_ERROR_CONNECTION_BROKEN:
800			default:
801				goto out;
802
803			case SCF_ERROR_DELETED:
804				goto add;
805
806			case SCF_ERROR_NOT_FOUND:
807				break;
808
809			case SCF_ERROR_HANDLE_MISMATCH:
810			case SCF_ERROR_INVALID_ARGUMENT:
811			case SCF_ERROR_NOT_BOUND:
812			case SCF_ERROR_NOT_SET:
813				bad_error("scf_pg_get_property", scf_error());
814			}
815		} else if (scf_property_get_value(prop, v) != 0) {
816			switch (scf_error()) {
817			case SCF_ERROR_CONNECTION_BROKEN:
818			default:
819				goto out;
820
821			case SCF_ERROR_DELETED:
822				goto add;
823
824			case SCF_ERROR_CONSTRAINT_VIOLATED:
825			case SCF_ERROR_NOT_FOUND:
826				break;
827
828			case SCF_ERROR_HANDLE_MISMATCH:
829			case SCF_ERROR_NOT_BOUND:
830			case SCF_ERROR_NOT_SET:
831				bad_error("scf_property_get_value",
832				    scf_error());
833			}
834		} else if (scf_value_get_integer(v, &t) != 0) {
835			bad_error("scf_value_get_integer", scf_error());
836		} else if (t > timestamp) {
837			break;
838		}
839
840		if (scf_transaction_start(tx, pg) == -1) {
841			switch (scf_error()) {
842			case SCF_ERROR_NOT_BOUND:
843			case SCF_ERROR_CONNECTION_BROKEN:
844			case SCF_ERROR_PERMISSION_DENIED:
845			case SCF_ERROR_BACKEND_ACCESS:
846			case SCF_ERROR_BACKEND_READONLY:
847			default:
848				goto out;
849
850			case SCF_ERROR_DELETED:
851				goto add;
852
853			case SCF_ERROR_HANDLE_MISMATCH:
854			case SCF_ERROR_NOT_SET:
855			case SCF_ERROR_IN_USE:
856				bad_error("scf_transaction_start", scf_error());
857			}
858		}
859
860		if (transaction_property_set(tx, ent, action,
861		    SCF_TYPE_INTEGER) != 0) {
862			switch (scf_error()) {
863			case SCF_ERROR_NOT_BOUND:
864			case SCF_ERROR_CONNECTION_BROKEN:
865			case SCF_ERROR_DELETED:
866			default:
867				goto out;
868
869			case SCF_ERROR_HANDLE_MISMATCH:
870			case SCF_ERROR_INVALID_ARGUMENT:
871			case SCF_ERROR_NOT_SET:
872				bad_error("transaction_property_set",
873				    scf_error());
874			}
875		}
876
877		scf_value_set_integer(v, timestamp);
878		if (scf_entry_add_value(ent, v) == -1)
879			bad_error("scf_entry_add_value", scf_error());
880
881		trans = scf_transaction_commit(tx);
882		if (trans == 1)
883			break;
884
885		if (trans != 0) {
886			switch (scf_error()) {
887			case SCF_ERROR_CONNECTION_BROKEN:
888			case SCF_ERROR_PERMISSION_DENIED:
889			case SCF_ERROR_BACKEND_ACCESS:
890			case SCF_ERROR_BACKEND_READONLY:
891			default:
892				goto out;
893
894			case SCF_ERROR_DELETED:
895				scf_transaction_reset(tx);
896				goto add;
897
898			case SCF_ERROR_INVALID_ARGUMENT:
899			case SCF_ERROR_NOT_BOUND:
900			case SCF_ERROR_NOT_SET:
901				bad_error("scf_transaction_commit",
902				    scf_error());
903			}
904		}
905
906		scf_transaction_reset(tx);
907		if (scf_pg_update(pg) == -1) {
908			switch (scf_error()) {
909			case SCF_ERROR_CONNECTION_BROKEN:
910			default:
911				goto out;
912
913			case SCF_ERROR_DELETED:
914				goto add;
915
916			case SCF_ERROR_NOT_SET:
917			case SCF_ERROR_NOT_BOUND:
918				bad_error("scf_pg_update", scf_error());
919			}
920		}
921	}
922
923	ret = 0;
924
925out:
926	scf_value_destroy(v);
927	scf_entry_destroy(ent);
928	scf_transaction_destroy(tx);
929	scf_property_destroy(prop);
930	scf_pg_destroy(pg);
931	return (ret);
932}
933
934static int
935set_inst_action(const char *fmri, const char *action)
936{
937	scf_handle_t *h;
938	scf_instance_t *inst;
939	int ret = -1;
940
941	h = handle_create();
942	if (h == NULL)
943		return (-1);
944
945	inst = scf_instance_create(h);
946
947	if (inst != NULL) {
948		if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
949		    NULL, SCF_DECODE_FMRI_EXACT) == 0)
950			ret = set_inst_action_inst(inst, action);
951		else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED)
952			(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
953
954		scf_instance_destroy(inst);
955	}
956
957	scf_handle_destroy(h);
958
959	return (ret);
960}
961
962
963/*
964 * get_inst_state() gets the state string from an instance, and returns
965 * the SCF_STATE_* constant that coincides with the instance's current state.
966 */
967
968static int
969get_inst_state(scf_instance_t *inst, scf_handle_t *h)
970{
971	scf_propertygroup_t	*pg = NULL;
972	scf_property_t		*prop = NULL;
973	scf_value_t		*val = NULL;
974	char			state[MAX_SCF_STATE_STRING_SZ];
975	int			ret = -1;
976
977	if (((pg = scf_pg_create(h)) == NULL) ||
978	    ((prop = scf_property_create(h)) == NULL) ||
979	    ((val = scf_value_create(h)) == NULL))
980		goto out;
981
982	/* Pull the state property from the instance */
983
984	if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) == -1 ||
985	    scf_pg_get_property(pg, SCF_PROPERTY_STATE, prop) == -1 ||
986	    scf_property_get_value(prop, val) == -1) {
987		if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
988			(void) scf_set_error(SCF_ERROR_INTERNAL);
989		goto out;
990	}
991
992	if (scf_value_get_astring(val, state, sizeof (state)) <= 0) {
993		(void) scf_set_error(SCF_ERROR_INTERNAL);
994		goto out;
995	}
996
997	if (strcmp(state, SCF_STATE_STRING_UNINIT) == 0) {
998		ret = SCF_STATE_UNINIT;
999	} else if (strcmp(state, SCF_STATE_STRING_MAINT) == 0) {
1000		ret = SCF_STATE_MAINT;
1001	} else if (strcmp(state, SCF_STATE_STRING_OFFLINE) == 0) {
1002		ret = SCF_STATE_OFFLINE;
1003	} else if (strcmp(state, SCF_STATE_STRING_DISABLED) == 0) {
1004		ret = SCF_STATE_DISABLED;
1005	} else if (strcmp(state, SCF_STATE_STRING_ONLINE) == 0) {
1006		ret = SCF_STATE_ONLINE;
1007	} else if (strcmp(state, SCF_STATE_STRING_DEGRADED) == 0) {
1008		ret = SCF_STATE_DEGRADED;
1009	}
1010
1011out:
1012	scf_pg_destroy(pg);
1013	scf_property_destroy(prop);
1014	(void) scf_value_destroy(val);
1015
1016	return (ret);
1017}
1018
1019/*
1020 * Sets an instance to be enabled or disabled after reboot, using the
1021 * temporary (overriding) general_ovr property group to reflect the
1022 * present state, if it is different.
1023 */
1024static int
1025set_inst_enabled_atboot(scf_instance_t *inst, uint8_t desired)
1026{
1027	int enabled;
1028	int persistent;
1029	int ret = -1;
1030
1031	if ((persistent = get_inst_enabled(inst, SCF_PG_GENERAL)) < 0) {
1032		if (scf_error() != SCF_ERROR_NOT_FOUND)
1033			goto out;
1034		persistent = B_FALSE;
1035	}
1036	if ((enabled = get_inst_enabled(inst, SCF_PG_GENERAL_OVR)) < 0) {
1037		enabled = persistent;
1038		if (persistent != desired) {
1039			/*
1040			 * Temporarily store the present enabled state.
1041			 */
1042			if (set_inst_enabled(inst, persistent,
1043			    SCF_PG_GENERAL_OVR, SCF_PG_GENERAL_OVR_FLAGS))
1044				goto out;
1045		}
1046	}
1047	if (persistent != desired)
1048		if (set_inst_enabled(inst, desired, SCF_PG_GENERAL,
1049		    SCF_PG_GENERAL_FLAGS))
1050			goto out;
1051	if (enabled == desired)
1052		ret = delete_inst_enabled(inst, SCF_PG_GENERAL_OVR);
1053	else
1054		ret = 0;
1055
1056out:
1057	return (ret);
1058}
1059
1060static int
1061set_inst_enabled_flags(const char *fmri, int flags, uint8_t desired)
1062{
1063	int ret = -1;
1064	scf_handle_t *h;
1065	scf_instance_t *inst;
1066
1067	if (flags & ~(SMF_TEMPORARY | SMF_AT_NEXT_BOOT) ||
1068	    flags & SMF_TEMPORARY && flags & SMF_AT_NEXT_BOOT) {
1069		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1070		return (ret);
1071	}
1072
1073	if ((h = handle_create()) == NULL)
1074		return (ret);
1075
1076	if ((inst = scf_instance_create(h)) == NULL) {
1077		scf_handle_destroy(h);
1078		return (ret);
1079	}
1080
1081	if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL, NULL,
1082	    SCF_DECODE_FMRI_EXACT) == -1) {
1083		if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED)
1084			(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1085		goto out;
1086	}
1087
1088	if (flags & SMF_AT_NEXT_BOOT) {
1089		ret = set_inst_enabled_atboot(inst, desired);
1090	} else {
1091		if (set_inst_enabled(inst, desired, flags & SMF_TEMPORARY ?
1092		    SCF_PG_GENERAL_OVR : SCF_PG_GENERAL, flags & SMF_TEMPORARY ?
1093		    SCF_PG_GENERAL_OVR_FLAGS : SCF_PG_GENERAL_FLAGS))
1094			goto out;
1095
1096		/*
1097		 * Make the persistent value effective by deleting the
1098		 * temporary one.
1099		 */
1100		if (flags & SMF_TEMPORARY)
1101			ret = 0;
1102		else
1103			ret = delete_inst_enabled(inst, SCF_PG_GENERAL_OVR);
1104	}
1105
1106out:
1107	scf_instance_destroy(inst);
1108	scf_handle_destroy(h);
1109	return (ret);
1110}
1111
1112/*
1113 * Create and return a pg from the instance associated with the given handle.
1114 * This function is only called in scf_transaction_setup and
1115 * scf_transaction_restart where the h->rh_instance pointer is properly filled
1116 * in by scf_general_setup_pg().
1117 */
1118static scf_propertygroup_t *
1119get_instance_pg(scf_simple_handle_t *simple_h)
1120{
1121	scf_propertygroup_t	*ret_pg = scf_pg_create(simple_h->h);
1122	char			*pg_name;
1123	ssize_t			namelen;
1124
1125	if (ret_pg == NULL) {
1126		return (NULL);
1127	}
1128
1129	namelen = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
1130	assert(namelen > 0);
1131
1132	if ((pg_name = malloc(namelen)) == NULL) {
1133		if (scf_error() == SCF_ERROR_NOT_SET) {
1134			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
1135		}
1136		return (NULL);
1137	}
1138
1139	if (scf_pg_get_name(simple_h->running_pg, pg_name, namelen) < 0) {
1140		if (scf_error() == SCF_ERROR_NOT_SET) {
1141			(void) scf_set_error(SCF_ERROR_INTERNAL);
1142		}
1143		return (NULL);
1144	}
1145
1146	/* Get pg from instance */
1147	if (scf_instance_get_pg(simple_h->inst, pg_name, ret_pg) == -1) {
1148		return (NULL);
1149	}
1150
1151	return (ret_pg);
1152}
1153
1154int
1155smf_enable_instance(const char *fmri, int flags)
1156{
1157	return (set_inst_enabled_flags(fmri, flags, B_TRUE));
1158}
1159
1160int
1161smf_disable_instance(const char *fmri, int flags)
1162{
1163	return (set_inst_enabled_flags(fmri, flags, B_FALSE));
1164}
1165
1166int
1167_smf_refresh_instance_i(scf_instance_t *inst)
1168{
1169	return (set_inst_action_inst(inst, SCF_PROPERTY_REFRESH));
1170}
1171
1172int
1173smf_refresh_instance(const char *instance)
1174{
1175	return (set_inst_action(instance, SCF_PROPERTY_REFRESH));
1176}
1177
1178int
1179smf_restart_instance(const char *instance)
1180{
1181	return (set_inst_action(instance, SCF_PROPERTY_RESTART));
1182}
1183
1184int
1185smf_maintain_instance(const char *instance, int flags)
1186{
1187	if (flags & SMF_TEMPORARY)
1188		return (set_inst_action(instance,
1189		    (flags & SMF_IMMEDIATE) ?
1190		    SCF_PROPERTY_MAINT_ON_IMMTEMP :
1191		    SCF_PROPERTY_MAINT_ON_TEMPORARY));
1192	else
1193		return (set_inst_action(instance,
1194		    (flags & SMF_IMMEDIATE) ?
1195		    SCF_PROPERTY_MAINT_ON_IMMEDIATE :
1196		    SCF_PROPERTY_MAINT_ON));
1197}
1198
1199int
1200smf_degrade_instance(const char *instance, int flags)
1201{
1202	scf_simple_prop_t		*prop;
1203	const char			*state_str;
1204
1205	if (flags & SMF_TEMPORARY)
1206		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
1207
1208	if ((prop = scf_simple_prop_get(NULL, instance, SCF_PG_RESTARTER,
1209	    SCF_PROPERTY_STATE)) == NULL)
1210		return (SCF_FAILED);
1211
1212	if ((state_str = scf_simple_prop_next_astring(prop)) == NULL) {
1213		scf_simple_prop_free(prop);
1214		return (SCF_FAILED);
1215	}
1216
1217	if (strcmp(state_str, SCF_STATE_STRING_ONLINE) != 0) {
1218		scf_simple_prop_free(prop);
1219		return (scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED));
1220	}
1221	scf_simple_prop_free(prop);
1222
1223	return (set_inst_action(instance, (flags & SMF_IMMEDIATE) ?
1224	    SCF_PROPERTY_DEGRADE_IMMEDIATE : SCF_PROPERTY_DEGRADED));
1225}
1226
1227int
1228smf_restore_instance(const char *instance)
1229{
1230	scf_simple_prop_t		*prop;
1231	const char			*state_str;
1232	int				ret;
1233
1234	if ((prop = scf_simple_prop_get(NULL, instance, SCF_PG_RESTARTER,
1235	    SCF_PROPERTY_STATE)) == NULL)
1236		return (SCF_FAILED);
1237
1238	if ((state_str = scf_simple_prop_next_astring(prop)) == NULL) {
1239		scf_simple_prop_free(prop);
1240		return (SCF_FAILED);
1241	}
1242
1243	if (strcmp(state_str, SCF_STATE_STRING_MAINT) == 0) {
1244		ret = set_inst_action(instance, SCF_PROPERTY_MAINT_OFF);
1245	} else if (strcmp(state_str, SCF_STATE_STRING_DEGRADED) == 0) {
1246		ret = set_inst_action(instance, SCF_PROPERTY_RESTORE);
1247	} else {
1248		ret = scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED);
1249	}
1250
1251	scf_simple_prop_free(prop);
1252	return (ret);
1253}
1254
1255char *
1256smf_get_state(const char *instance)
1257{
1258	scf_simple_prop_t		*prop;
1259	const char			*state_str;
1260	char				*ret;
1261
1262	if ((prop = scf_simple_prop_get(NULL, instance, SCF_PG_RESTARTER,
1263	    SCF_PROPERTY_STATE)) == NULL)
1264		return (NULL);
1265
1266	if ((state_str = scf_simple_prop_next_astring(prop)) == NULL) {
1267		scf_simple_prop_free(prop);
1268		return (NULL);
1269	}
1270
1271	if ((ret = strdup(state_str)) == NULL)
1272		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
1273
1274	scf_simple_prop_free(prop);
1275	return (ret);
1276}
1277
1278/*
1279 * scf_general_pg_setup(fmri, pg_name)
1280 * Create a scf_simple_handle_t and fill in the instance, snapshot, and
1281 * property group fields associated with the given fmri and property group
1282 * name.
1283 * Returns:
1284 *      Handle  on success
1285 *      Null  on error with scf_error set to:
1286 *              SCF_ERROR_HANDLE_MISMATCH,
1287 *              SCF_ERROR_INVALID_ARGUMENT,
1288 *              SCF_ERROR_CONSTRAINT_VIOLATED,
1289 *              SCF_ERROR_NOT_FOUND,
1290 *              SCF_ERROR_NOT_SET,
1291 *              SCF_ERROR_DELETED,
1292 *              SCF_ERROR_NOT_BOUND,
1293 *              SCF_ERROR_CONNECTION_BROKEN,
1294 *              SCF_ERROR_INTERNAL,
1295 *              SCF_ERROR_NO_RESOURCES,
1296 *              SCF_ERROR_BACKEND_ACCESS
1297 */
1298scf_simple_handle_t *
1299scf_general_pg_setup(const char *fmri, const char *pg_name)
1300{
1301	scf_simple_handle_t	*ret;
1302
1303	ret = uu_zalloc(sizeof (*ret));
1304	if (ret == NULL) {
1305		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
1306		return (NULL);
1307	} else {
1308
1309		ret->h = handle_create();
1310		ret->inst = scf_instance_create(ret->h);
1311		ret->snap = scf_snapshot_create(ret->h);
1312		ret->running_pg = scf_pg_create(ret->h);
1313	}
1314
1315	if ((ret->h == NULL) || (ret->inst == NULL) ||
1316	    (ret->snap == NULL) || (ret->running_pg == NULL)) {
1317		goto out;
1318	}
1319
1320	if (scf_handle_decode_fmri(ret->h, fmri, NULL, NULL, ret->inst,
1321	    NULL, NULL, NULL) == -1) {
1322		goto out;
1323	}
1324
1325	if ((scf_instance_get_snapshot(ret->inst, "running", ret->snap))
1326	    != 0) {
1327		goto out;
1328	}
1329
1330	if (scf_instance_get_pg_composed(ret->inst, ret->snap, pg_name,
1331	    ret->running_pg) != 0) {
1332		goto out;
1333	}
1334
1335	return (ret);
1336
1337out:
1338	scf_simple_handle_destroy(ret);
1339	return (NULL);
1340}
1341
1342/*
1343 * scf_transaction_setup(h)
1344 * creates and starts the transaction
1345 * Returns:
1346 *      transaction  on success
1347 *      NULL on failure with scf_error set to:
1348 *      SCF_ERROR_NO_MEMORY,
1349 *	SCF_ERROR_INVALID_ARGUMENT,
1350 *      SCF_ERROR_HANDLE_DESTROYED,
1351 *	SCF_ERROR_INTERNAL,
1352 *	SCF_ERROR_NO_RESOURCES,
1353 *      SCF_ERROR_NOT_BOUND,
1354 *	SCF_ERROR_CONNECTION_BROKEN,
1355 *      SCF_ERROR_NOT_SET,
1356 *	SCF_ERROR_DELETED,
1357 *	SCF_ERROR_CONSTRAINT_VIOLATED,
1358 *      SCF_ERROR_HANDLE_MISMATCH,
1359 *	SCF_ERROR_BACKEND_ACCESS,
1360 *	SCF_ERROR_IN_USE
1361 */
1362scf_transaction_t *
1363scf_transaction_setup(scf_simple_handle_t *simple_h)
1364{
1365	scf_transaction_t	*tx = NULL;
1366
1367	if ((tx = scf_transaction_create(simple_h->h)) == NULL) {
1368		return (NULL);
1369	}
1370
1371	if ((simple_h->editing_pg = get_instance_pg(simple_h)) == NULL) {
1372		return (NULL);
1373	}
1374
1375	if (scf_transaction_start(tx, simple_h->editing_pg) == -1) {
1376		scf_pg_destroy(simple_h->editing_pg);
1377		simple_h->editing_pg = NULL;
1378		return (NULL);
1379	}
1380
1381	return (tx);
1382}
1383
1384int
1385scf_transaction_restart(scf_simple_handle_t *simple_h, scf_transaction_t *tx)
1386{
1387	scf_transaction_reset(tx);
1388
1389	if (scf_pg_update(simple_h->editing_pg) == -1) {
1390		return (SCF_FAILED);
1391	}
1392
1393	if (scf_transaction_start(tx, simple_h->editing_pg) == -1) {
1394		return (SCF_FAILED);
1395	}
1396
1397	return (SCF_SUCCESS);
1398}
1399
1400/*
1401 * scf_read_count_property(scf_simple_handle_t *simple_h, char *prop_name,
1402 * uint64_t *ret_count)
1403 *
1404 * For the given property name, return the count value.
1405 * RETURNS:
1406 *	SCF_SUCCESS
1407 *	SCF_FAILED on failure with scf_error() set to:
1408 *		SCF_ERROR_HANDLE_DESTROYED
1409 *		SCF_ERROR_INTERNAL
1410 *		SCF_ERROR_NO_RESOURCES
1411 *		SCF_ERROR_NO_MEMORY
1412 *		SCF_ERROR_HANDLE_MISMATCH
1413 *		SCF_ERROR_INVALID_ARGUMENT
1414 *		SCF_ERROR_NOT_BOUND
1415 *		SCF_ERROR_CONNECTION_BROKEN
1416 *		SCF_ERROR_NOT_SET
1417 *		SCF_ERROR_DELETED
1418 *		SCF_ERROR_BACKEND_ACCESS
1419 *		SCF_ERROR_CONSTRAINT_VIOLATED
1420 *		SCF_ERROR_TYPE_MISMATCH
1421 */
1422int
1423scf_read_count_property(
1424	scf_simple_handle_t	*simple_h,
1425	char			*prop_name,
1426	uint64_t		*ret_count)
1427{
1428	scf_property_t		*prop = scf_property_create(simple_h->h);
1429	scf_value_t		*val = scf_value_create(simple_h->h);
1430	int			ret = SCF_FAILED;
1431
1432	if ((val == NULL) || (prop == NULL)) {
1433		goto out;
1434	}
1435
1436	/*
1437	 * Get the property struct that goes with this property group and
1438	 * property name.
1439	 */
1440	if (scf_pg_get_property(simple_h->running_pg, prop_name, prop) != 0) {
1441		goto out;
1442	}
1443
1444	/* Get the value structure */
1445	if (scf_property_get_value(prop, val) == -1) {
1446		goto out;
1447	}
1448
1449	/*
1450	 * Now get the count value.
1451	 */
1452	if (scf_value_get_count(val, ret_count) == -1) {
1453		goto out;
1454	}
1455
1456	ret = SCF_SUCCESS;
1457
1458out:
1459	scf_property_destroy(prop);
1460	scf_value_destroy(val);
1461	return (ret);
1462}
1463
1464/*
1465 * scf_trans_add_count_property(trans, propname, count, create_flag)
1466 *
1467 * Set a count property transaction entry into the pending SMF transaction.
1468 * The transaction is created and committed outside of this function.
1469 * Returns:
1470 *	SCF_SUCCESS
1471 *	SCF_FAILED on failure with scf_error() set to:
1472 *			SCF_ERROR_HANDLE_DESTROYED,
1473 *			SCF_ERROR_INVALID_ARGUMENT,
1474 *			SCF_ERROR_NO_MEMORY,
1475 *			SCF_ERROR_HANDLE_MISMATCH,
1476 *			SCF_ERROR_NOT_SET,
1477 *			SCF_ERROR_IN_USE,
1478 *			SCF_ERROR_NOT_FOUND,
1479 *			SCF_ERROR_EXISTS,
1480 *			SCF_ERROR_TYPE_MISMATCH,
1481 *			SCF_ERROR_NOT_BOUND,
1482 *			SCF_ERROR_CONNECTION_BROKEN,
1483 *			SCF_ERROR_INTERNAL,
1484 *			SCF_ERROR_DELETED,
1485 *			SCF_ERROR_NO_RESOURCES,
1486 *			SCF_ERROR_BACKEND_ACCESS
1487 */
1488int
1489scf_set_count_property(
1490	scf_transaction_t	*trans,
1491	char			*propname,
1492	uint64_t		count,
1493	boolean_t		create_flag)
1494{
1495	scf_handle_t		*handle = scf_transaction_handle(trans);
1496	scf_value_t		*value = scf_value_create(handle);
1497	scf_transaction_entry_t	*entry = scf_entry_create(handle);
1498
1499	if ((value == NULL) || (entry == NULL)) {
1500		return (SCF_FAILED);
1501	}
1502
1503	/*
1504	 * Property must be set in transaction and won't take
1505	 * effect until the transaction is committed.
1506	 *
1507	 * Attempt to change the current value. However, create new property
1508	 * if it doesn't exist and the create flag is set.
1509	 */
1510	if (scf_transaction_property_change(trans, entry, propname,
1511	    SCF_TYPE_COUNT) == 0) {
1512		scf_value_set_count(value, count);
1513		if (scf_entry_add_value(entry, value) == 0) {
1514			return (SCF_SUCCESS);
1515		}
1516	} else {
1517		if ((create_flag == B_TRUE) &&
1518		    (scf_error() == SCF_ERROR_NOT_FOUND)) {
1519			if (scf_transaction_property_new(trans, entry, propname,
1520			    SCF_TYPE_COUNT) == 0) {
1521				scf_value_set_count(value, count);
1522				if (scf_entry_add_value(entry, value) == 0) {
1523					return (SCF_SUCCESS);
1524				}
1525			}
1526		}
1527	}
1528
1529	/*
1530	 * cleanup if there were any errors that didn't leave these
1531	 * values where they would be cleaned up later.
1532	 */
1533	if (value != NULL)
1534		scf_value_destroy(value);
1535	if (entry != NULL)
1536		scf_entry_destroy(entry);
1537	return (SCF_FAILED);
1538}
1539
1540int
1541scf_simple_walk_instances(uint_t state_flags, void *private,
1542    int (*inst_callback)(scf_handle_t *, scf_instance_t *, void *))
1543{
1544	scf_scope_t 		*scope = NULL;
1545	scf_service_t		*svc = NULL;
1546	scf_instance_t		*inst = NULL;
1547	scf_iter_t		*svc_iter = NULL, *inst_iter = NULL;
1548	scf_handle_t		*h = NULL;
1549	int			ret = SCF_FAILED;
1550	int			svc_iter_ret, inst_iter_ret;
1551	int			inst_state;
1552
1553	if ((h = handle_create()) == NULL)
1554		return (ret);
1555
1556	if (((scope = scf_scope_create(h)) == NULL) ||
1557	    ((svc = scf_service_create(h)) == NULL) ||
1558	    ((inst = scf_instance_create(h)) == NULL) ||
1559	    ((svc_iter = scf_iter_create(h)) == NULL) ||
1560	    ((inst_iter = scf_iter_create(h)) == NULL))
1561		goto out;
1562
1563	/*
1564	 * Get the local scope, and set up nested iteration through every
1565	 * local service, and every instance of every service.
1566	 */
1567
1568	if ((scf_handle_get_local_scope(h, scope) != SCF_SUCCESS) ||
1569	    (scf_iter_scope_services(svc_iter, scope) != SCF_SUCCESS))
1570		goto out;
1571
1572	while ((svc_iter_ret = scf_iter_next_service(svc_iter, svc)) > 0) {
1573
1574		if ((scf_iter_service_instances(inst_iter, svc)) !=
1575		    SCF_SUCCESS)
1576			goto out;
1577
1578		while ((inst_iter_ret =
1579		    scf_iter_next_instance(inst_iter, inst)) > 0) {
1580			/*
1581			 * If get_inst_state fails from an internal error,
1582			 * IE, being unable to get the property group or
1583			 * property containing the state of the instance,
1584			 * we continue instead of failing, as this might just
1585			 * be an improperly configured instance.
1586			 */
1587			if ((inst_state = get_inst_state(inst, h)) == -1) {
1588				if (scf_error() == SCF_ERROR_INTERNAL) {
1589					continue;
1590				} else {
1591					goto out;
1592				}
1593			}
1594
1595			if ((uint_t)inst_state & state_flags) {
1596				if (inst_callback(h, inst, private) !=
1597				    SCF_SUCCESS) {
1598					(void) scf_set_error(
1599					    SCF_ERROR_CALLBACK_FAILED);
1600					goto out;
1601				}
1602			}
1603		}
1604
1605		if (inst_iter_ret == -1)
1606			goto out;
1607		scf_iter_reset(inst_iter);
1608	}
1609
1610	if (svc_iter_ret != -1)
1611		ret = SCF_SUCCESS;
1612
1613out:
1614	scf_scope_destroy(scope);
1615	scf_service_destroy(svc);
1616	scf_instance_destroy(inst);
1617	scf_iter_destroy(svc_iter);
1618	scf_iter_destroy(inst_iter);
1619	scf_handle_destroy(h);
1620
1621	return (ret);
1622}
1623
1624
1625scf_simple_prop_t *
1626scf_simple_prop_get(scf_handle_t *hin, const char *instance, const char *pgname,
1627			const char *propname)
1628{
1629	char 			*fmri_buf, *svcfmri = NULL;
1630	ssize_t 		fmri_sz;
1631	scf_property_t 		*prop = NULL;
1632	scf_service_t 		*svc = NULL;
1633	scf_simple_prop_t 	*ret;
1634	scf_handle_t		*h = NULL;
1635	boolean_t		local_h = B_TRUE;
1636
1637	/* If the user passed in a handle, use it. */
1638	if (hin != NULL) {
1639		h = hin;
1640		local_h = B_FALSE;
1641	}
1642
1643	if (local_h && ((h = handle_create()) == NULL))
1644		return (NULL);
1645
1646	if ((fmri_buf = assemble_fmri(h, instance, pgname, propname)) == NULL) {
1647		if (local_h)
1648			scf_handle_destroy(h);
1649		return (NULL);
1650	}
1651
1652	if ((svc = scf_service_create(h)) == NULL ||
1653	    (prop = scf_property_create(h)) == NULL)
1654		goto error1;
1655	if (scf_handle_decode_fmri(h, fmri_buf, NULL, NULL, NULL, NULL, prop,
1656	    SCF_DECODE_FMRI_REQUIRE_INSTANCE) == -1) {
1657		switch (scf_error()) {
1658		/*
1659		 * If the property isn't found in the instance, we grab the
1660		 * underlying service, create an FMRI out of it, and then
1661		 * query the datastore again at the service level for the
1662		 * property.
1663		 */
1664		case SCF_ERROR_NOT_FOUND:
1665			if (scf_handle_decode_fmri(h, fmri_buf, NULL, svc,
1666			    NULL, NULL, NULL, SCF_DECODE_FMRI_TRUNCATE) == -1)
1667				goto error1;
1668
1669			fmri_sz = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH) + 1;
1670			assert(fmri_sz > 0);
1671
1672			if (scf_service_to_fmri(svc, fmri_buf, fmri_sz) == -1)
1673				goto error1;
1674			if ((svcfmri = assemble_fmri(h, fmri_buf, pgname,
1675			    propname)) == NULL)
1676				goto error1;
1677			if (scf_handle_decode_fmri(h, svcfmri, NULL, NULL,
1678			    NULL, NULL, prop, 0) == -1) {
1679				free(svcfmri);
1680				goto error1;
1681			}
1682			free(svcfmri);
1683			break;
1684		case SCF_ERROR_CONSTRAINT_VIOLATED:
1685			(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1686		default:
1687			goto error1;
1688		}
1689	}
1690	/*
1691	 * At this point, we've successfully pulled the property from the
1692	 * datastore, and simply need to copy its innards into an
1693	 * scf_simple_prop_t.
1694	 */
1695	if ((ret = fill_prop(prop, pgname, propname, h)) == NULL)
1696		goto error1;
1697
1698	scf_service_destroy(svc);
1699	scf_property_destroy(prop);
1700	free(fmri_buf);
1701	if (local_h)
1702		scf_handle_destroy(h);
1703	return (ret);
1704
1705	/*
1706	 * Exit point for a successful call.  Below this line are exit points
1707	 * for failures at various stages during the function.
1708	 */
1709
1710error1:
1711	scf_service_destroy(svc);
1712	scf_property_destroy(prop);
1713error2:
1714	free(fmri_buf);
1715	if (local_h)
1716		scf_handle_destroy(h);
1717	return (NULL);
1718}
1719
1720
1721void
1722scf_simple_prop_free(scf_simple_prop_t *prop)
1723{
1724	int i;
1725
1726	if (prop == NULL)
1727		return;
1728
1729	free(prop->pr_propname);
1730	free(prop->pr_pgname);
1731	switch (prop->pr_type) {
1732	case SCF_TYPE_OPAQUE: {
1733		for (i = 0; i < prop->pr_numvalues; i++) {
1734			free(prop->pr_vallist[i].pv_opaque.o_value);
1735		}
1736		break;
1737	}
1738	case SCF_TYPE_ASTRING:
1739	case SCF_TYPE_USTRING:
1740	case SCF_TYPE_HOST:
1741	case SCF_TYPE_HOSTNAME:
1742	case SCF_TYPE_NET_ADDR_V4:
1743	case SCF_TYPE_NET_ADDR_V6:
1744	case SCF_TYPE_URI:
1745	case SCF_TYPE_FMRI: {
1746		for (i = 0; i < prop->pr_numvalues; i++) {
1747			free(prop->pr_vallist[i].pv_str);
1748		}
1749		break;
1750	}
1751	default:
1752		break;
1753	}
1754	free(prop->pr_vallist);
1755	free(prop);
1756}
1757
1758
1759scf_simple_app_props_t *
1760scf_simple_app_props_get(scf_handle_t *hin, const char *inst_fmri)
1761{
1762	scf_instance_t 		*inst = NULL;
1763	scf_service_t 		*svc = NULL;
1764	scf_propertygroup_t 	*pg = NULL;
1765	scf_property_t 		*prop = NULL;
1766	scf_simple_app_props_t	*ret = NULL;
1767	scf_iter_t		*pgiter = NULL, *propiter = NULL;
1768	struct scf_simple_pg	*thispg = NULL, *nextpg;
1769	scf_simple_prop_t	*thisprop, *nextprop;
1770	scf_handle_t		*h = NULL;
1771	int			pgiter_ret, propiter_ret;
1772	ssize_t			namelen;
1773	char 			*propname = NULL, *pgname = NULL, *sys_fmri;
1774	uint8_t			found;
1775	boolean_t		local_h = B_TRUE;
1776
1777	/* If the user passed in a handle, use it. */
1778	if (hin != NULL) {
1779		h = hin;
1780		local_h = B_FALSE;
1781	}
1782
1783	if (local_h && ((h = handle_create()) == NULL))
1784		return (NULL);
1785
1786	if (inst_fmri == NULL) {
1787		if ((namelen = scf_myname(h, NULL, 0)) == -1) {
1788			if (local_h)
1789				scf_handle_destroy(h);
1790			return (NULL);
1791		}
1792		if ((sys_fmri = malloc(namelen + 1)) == NULL) {
1793			if (local_h)
1794				scf_handle_destroy(h);
1795			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
1796			return (NULL);
1797		}
1798		if (scf_myname(h, sys_fmri, namelen + 1) == -1) {
1799			if (local_h)
1800				scf_handle_destroy(h);
1801			free(sys_fmri);
1802			return (NULL);
1803		}
1804	} else {
1805		if ((sys_fmri = strdup(inst_fmri)) == NULL) {
1806			if (local_h)
1807				scf_handle_destroy(h);
1808			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
1809			return (NULL);
1810		}
1811	}
1812
1813	namelen = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
1814	assert(namelen > 0);
1815
1816	if ((inst = scf_instance_create(h)) == NULL ||
1817	    (svc = scf_service_create(h)) == NULL ||
1818	    (pgiter = scf_iter_create(h)) == NULL ||
1819	    (propiter = scf_iter_create(h)) == NULL ||
1820	    (pg = scf_pg_create(h)) == NULL ||
1821	    (prop = scf_property_create(h)) == NULL)
1822		goto error2;
1823
1824	if (scf_handle_decode_fmri(h, sys_fmri, NULL, svc, inst, NULL, NULL,
1825	    SCF_DECODE_FMRI_REQUIRE_INSTANCE) == -1) {
1826		if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED)
1827			(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1828		goto error2;
1829	}
1830
1831	if ((ret = malloc(sizeof (*ret))) == NULL ||
1832	    (thispg = malloc(sizeof (*thispg))) == NULL ||
1833	    (propname = malloc(namelen)) == NULL ||
1834	    (pgname = malloc(namelen)) == NULL) {
1835		free(thispg);
1836		free(ret);
1837		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
1838		goto error2;
1839	}
1840
1841	ret->ap_fmri = sys_fmri;
1842	thispg->pg_name = NULL;
1843	thispg->pg_proplist = NULL;
1844	thispg->pg_next = NULL;
1845	ret->ap_pglist = thispg;
1846
1847	if (scf_iter_service_pgs_typed(pgiter, svc, SCF_GROUP_APPLICATION) !=
1848	    0) {
1849		if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
1850			(void) scf_set_error(SCF_ERROR_INTERNAL);
1851		goto error1;
1852	}
1853
1854	while ((pgiter_ret = scf_iter_next_pg(pgiter, pg)) == 1) {
1855		if (thispg->pg_name != NULL) {
1856			if ((nextpg = malloc(sizeof (*nextpg))) == NULL) {
1857				(void) scf_set_error(SCF_ERROR_NO_MEMORY);
1858				goto error1;
1859			}
1860			nextpg->pg_name = NULL;
1861			nextpg->pg_next = NULL;
1862			nextpg->pg_proplist = NULL;
1863			thispg->pg_next = nextpg;
1864			thispg = nextpg;
1865		} else {
1866			/* This is the first iteration */
1867			nextpg = thispg;
1868		}
1869
1870		if ((nextpg->pg_name = malloc(namelen)) == NULL) {
1871			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
1872			goto error1;
1873		}
1874
1875		if (scf_pg_get_name(pg, nextpg->pg_name, namelen) < 0) {
1876			if (scf_error() == SCF_ERROR_NOT_SET)
1877				(void) scf_set_error(SCF_ERROR_INTERNAL);
1878			goto error1;
1879		}
1880
1881		thisprop = NULL;
1882
1883		scf_iter_reset(propiter);
1884
1885		if (scf_iter_pg_properties(propiter, pg) != 0) {
1886			if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
1887				(void) scf_set_error(SCF_ERROR_INTERNAL);
1888			goto error1;
1889		}
1890
1891		while ((propiter_ret = scf_iter_next_property(propiter, prop))
1892		    == 1) {
1893			if (scf_property_get_name(prop, propname, namelen) <
1894			    0) {
1895				if (scf_error() == SCF_ERROR_NOT_SET)
1896					(void) scf_set_error(
1897					    SCF_ERROR_INTERNAL);
1898				goto error1;
1899			}
1900			if (thisprop != NULL) {
1901				if ((nextprop = fill_prop(prop,
1902				    nextpg->pg_name, propname, h)) == NULL)
1903					goto error1;
1904				thisprop->pr_next = nextprop;
1905				thisprop = nextprop;
1906			} else {
1907				/* This is the first iteration */
1908				if ((thisprop = fill_prop(prop,
1909				    nextpg->pg_name, propname, h)) == NULL)
1910					goto error1;
1911				nextpg->pg_proplist = thisprop;
1912				nextprop = thisprop;
1913			}
1914			nextprop->pr_pg = nextpg;
1915			nextprop->pr_next = NULL;
1916		}
1917
1918		if (propiter_ret == -1) {
1919			if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
1920				(void) scf_set_error(SCF_ERROR_INTERNAL);
1921			goto error1;
1922		}
1923	}
1924
1925	if (pgiter_ret == -1) {
1926		if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
1927			(void) scf_set_error(SCF_ERROR_INTERNAL);
1928		goto error1;
1929	}
1930
1931	/*
1932	 * At this point, we've filled the scf_simple_app_props_t with all the
1933	 * properties at the service level.  Now we iterate over all the
1934	 * properties at the instance level, overwriting any duplicate
1935	 * properties, in order to provide service/instance composition.
1936	 */
1937
1938	scf_iter_reset(pgiter);
1939	scf_iter_reset(propiter);
1940
1941	if (scf_iter_instance_pgs_typed(pgiter, inst, SCF_GROUP_APPLICATION)
1942	    != 0) {
1943		if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
1944			(void) scf_set_error(SCF_ERROR_INTERNAL);
1945		goto error1;
1946	}
1947
1948	while ((pgiter_ret = scf_iter_next_pg(pgiter, pg)) == 1) {
1949
1950		thispg = ret->ap_pglist;
1951		found = 0;
1952
1953		/*
1954		 * Find either the end of the list, so we can append the
1955		 * property group, or an existing property group that matches
1956		 * it, so we can insert/overwrite its properties.
1957		 */
1958
1959		if (scf_pg_get_name(pg, pgname, namelen) < 0) {
1960			if (scf_error() == SCF_ERROR_NOT_SET)
1961				(void) scf_set_error(SCF_ERROR_INTERNAL);
1962			goto error1;
1963		}
1964
1965		while ((thispg != NULL) && (thispg->pg_name != NULL)) {
1966			if (strcmp(thispg->pg_name, pgname) == 0) {
1967				found = 1;
1968				break;
1969			}
1970			if (thispg->pg_next == NULL)
1971				break;
1972
1973			thispg = thispg->pg_next;
1974		}
1975
1976		scf_iter_reset(propiter);
1977
1978		if (scf_iter_pg_properties(propiter, pg) != 0) {
1979			if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
1980				(void) scf_set_error(SCF_ERROR_INTERNAL);
1981			goto error1;
1982		}
1983
1984		if (found) {
1985			/*
1986			 * insert_app_props inserts or overwrites the
1987			 * properties in thispg.
1988			 */
1989
1990			if (insert_app_props(propiter, pgname, propname,
1991			    thispg, prop, namelen, h) == -1)
1992				goto error1;
1993
1994		} else {
1995			/*
1996			 * If the property group wasn't found, we're adding
1997			 * a newly allocated property group to the end of the
1998			 * list.
1999			 */
2000
2001			if ((nextpg = malloc(sizeof (*nextpg))) == NULL) {
2002				(void) scf_set_error(SCF_ERROR_NO_MEMORY);
2003				goto error1;
2004			}
2005			nextpg->pg_next = NULL;
2006			nextpg->pg_proplist = NULL;
2007			thisprop = NULL;
2008
2009			if ((nextpg->pg_name = strdup(pgname)) == NULL) {
2010				(void) scf_set_error(SCF_ERROR_NO_MEMORY);
2011				free(nextpg);
2012				goto error1;
2013			}
2014
2015			if (thispg->pg_name == NULL) {
2016				free(thispg);
2017				ret->ap_pglist = nextpg;
2018			} else {
2019				thispg->pg_next = nextpg;
2020			}
2021
2022			while ((propiter_ret =
2023			    scf_iter_next_property(propiter, prop)) == 1) {
2024				if (scf_property_get_name(prop, propname,
2025				    namelen) < 0) {
2026					if (scf_error() == SCF_ERROR_NOT_SET)
2027						(void) scf_set_error(
2028						    SCF_ERROR_INTERNAL);
2029					goto error1;
2030				}
2031				if (thisprop != NULL) {
2032					if ((nextprop = fill_prop(prop,
2033					    pgname, propname, h)) ==
2034					    NULL)
2035						goto error1;
2036					thisprop->pr_next = nextprop;
2037					thisprop = nextprop;
2038				} else {
2039					/* This is the first iteration */
2040					if ((thisprop = fill_prop(prop,
2041					    pgname, propname, h)) ==
2042					    NULL)
2043						goto error1;
2044					nextpg->pg_proplist = thisprop;
2045					nextprop = thisprop;
2046				}
2047				nextprop->pr_pg = nextpg;
2048				nextprop->pr_next = NULL;
2049			}
2050
2051			if (propiter_ret == -1) {
2052				if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
2053					(void) scf_set_error(
2054					    SCF_ERROR_INTERNAL);
2055				goto error1;
2056			}
2057		}
2058
2059	}
2060
2061	if (pgiter_ret == -1) {
2062		if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
2063			(void) scf_set_error(SCF_ERROR_INTERNAL);
2064		goto error1;
2065	}
2066
2067	scf_iter_destroy(pgiter);
2068	scf_iter_destroy(propiter);
2069	scf_pg_destroy(pg);
2070	scf_property_destroy(prop);
2071	scf_instance_destroy(inst);
2072	scf_service_destroy(svc);
2073	free(propname);
2074	free(pgname);
2075	if (local_h)
2076		scf_handle_destroy(h);
2077
2078	if (ret->ap_pglist->pg_name == NULL)
2079		return (NULL);
2080
2081	return (ret);
2082
2083	/*
2084	 * Exit point for a successful call.  Below this line are exit points
2085	 * for failures at various stages during the function.
2086	 */
2087
2088error1:
2089	scf_simple_app_props_free(ret);
2090
2091error2:
2092	scf_iter_destroy(pgiter);
2093	scf_iter_destroy(propiter);
2094	scf_pg_destroy(pg);
2095	scf_property_destroy(prop);
2096	scf_instance_destroy(inst);
2097	scf_service_destroy(svc);
2098	free(propname);
2099	free(pgname);
2100	if (local_h)
2101		scf_handle_destroy(h);
2102	return (NULL);
2103}
2104
2105
2106void
2107scf_simple_app_props_free(scf_simple_app_props_t *propblock)
2108{
2109	struct scf_simple_pg 	*pgthis, *pgnext;
2110	scf_simple_prop_t 	*propthis, *propnext;
2111
2112	if ((propblock == NULL) || (propblock->ap_pglist == NULL))
2113		return;
2114
2115	for (pgthis = propblock->ap_pglist; pgthis != NULL; pgthis = pgnext) {
2116		pgnext = pgthis->pg_next;
2117
2118		propthis = pgthis->pg_proplist;
2119
2120		while (propthis != NULL) {
2121			propnext = propthis->pr_next;
2122			scf_simple_prop_free(propthis);
2123			propthis = propnext;
2124		}
2125
2126		free(pgthis->pg_name);
2127		free(pgthis);
2128	}
2129
2130	free(propblock->ap_fmri);
2131	free(propblock);
2132}
2133
2134const scf_simple_prop_t *
2135scf_simple_app_props_next(const scf_simple_app_props_t *propblock,
2136    scf_simple_prop_t *last)
2137{
2138	struct scf_simple_pg 	*this;
2139
2140	if (propblock == NULL) {
2141		(void) scf_set_error(SCF_ERROR_NOT_SET);
2142		return (NULL);
2143	}
2144
2145	this = propblock->ap_pglist;
2146
2147	/*
2148	 * We're looking for the first property in this block if last is
2149	 * NULL
2150	 */
2151
2152	if (last == NULL) {
2153		/* An empty pglist is legal, it just means no properties */
2154		if (this == NULL) {
2155			(void) scf_set_error(SCF_ERROR_NONE);
2156			return (NULL);
2157		}
2158		/*
2159		 * Walk until we find a pg with a property in it, or we run
2160		 * out of property groups.
2161		 */
2162		while ((this->pg_proplist == NULL) && (this->pg_next != NULL))
2163			this = this->pg_next;
2164
2165		if (this->pg_proplist == NULL) {
2166			(void) scf_set_error(SCF_ERROR_NONE);
2167			return (NULL);
2168		}
2169
2170		return (this->pg_proplist);
2171
2172	}
2173	/*
2174	 * If last isn't NULL, then return the next prop in the property group,
2175	 * or walk the property groups until we find another property, or
2176	 * run out of property groups.
2177	 */
2178	if (last->pr_next != NULL)
2179		return (last->pr_next);
2180
2181	if (last->pr_pg->pg_next == NULL) {
2182		(void) scf_set_error(SCF_ERROR_NONE);
2183		return (NULL);
2184	}
2185
2186	this = last->pr_pg->pg_next;
2187
2188	while ((this->pg_proplist == NULL) && (this->pg_next != NULL))
2189		this = this->pg_next;
2190
2191	if (this->pg_proplist == NULL) {
2192		(void) scf_set_error(SCF_ERROR_NONE);
2193		return (NULL);
2194	}
2195
2196	return (this->pg_proplist);
2197}
2198
2199const scf_simple_prop_t *
2200scf_simple_app_props_search(const scf_simple_app_props_t *propblock,
2201    const char *pgname, const char *propname)
2202{
2203	struct scf_simple_pg 	*pg;
2204	scf_simple_prop_t 	*prop;
2205
2206	if ((propblock == NULL) || (propname == NULL)) {
2207		(void) scf_set_error(SCF_ERROR_NOT_SET);
2208		return (NULL);
2209	}
2210
2211	pg = propblock->ap_pglist;
2212
2213	/*
2214	 * If pgname is NULL, we're searching the default application
2215	 * property group, otherwise we look for the specified group.
2216	 */
2217	if (pgname == NULL) {
2218		while ((pg != NULL) &&
2219		    (strcmp(SCF_PG_APP_DEFAULT, pg->pg_name) != 0))
2220			pg = pg->pg_next;
2221	} else {
2222		while ((pg != NULL) && (strcmp(pgname, pg->pg_name) != 0))
2223			pg = pg->pg_next;
2224	}
2225
2226	if (pg == NULL) {
2227		(void) scf_set_error(SCF_ERROR_NOT_FOUND);
2228		return (NULL);
2229	}
2230
2231	prop = pg->pg_proplist;
2232
2233	while ((prop != NULL) && (strcmp(propname, prop->pr_propname) != 0))
2234		prop = prop->pr_next;
2235
2236	if (prop == NULL) {
2237		(void) scf_set_error(SCF_ERROR_NOT_FOUND);
2238		return (NULL);
2239	}
2240
2241	return (prop);
2242}
2243
2244void
2245scf_simple_prop_next_reset(scf_simple_prop_t *prop)
2246{
2247	if (prop == NULL)
2248		return;
2249	prop->pr_iter = 0;
2250}
2251
2252ssize_t
2253scf_simple_prop_numvalues(const scf_simple_prop_t *prop)
2254{
2255	if (prop == NULL)
2256		return (scf_set_error(SCF_ERROR_NOT_SET));
2257
2258	return (prop->pr_numvalues);
2259}
2260
2261
2262scf_type_t
2263scf_simple_prop_type(const scf_simple_prop_t *prop)
2264{
2265	if (prop == NULL)
2266		return (scf_set_error(SCF_ERROR_NOT_SET));
2267
2268	return (prop->pr_type);
2269}
2270
2271
2272char *
2273scf_simple_prop_name(const scf_simple_prop_t *prop)
2274{
2275	if ((prop == NULL) || (prop->pr_propname == NULL)) {
2276		(void) scf_set_error(SCF_ERROR_NOT_SET);
2277		return (NULL);
2278	}
2279
2280	return (prop->pr_propname);
2281}
2282
2283
2284char *
2285scf_simple_prop_pgname(const scf_simple_prop_t *prop)
2286{
2287	if ((prop == NULL) || (prop->pr_pgname == NULL)) {
2288		(void) scf_set_error(SCF_ERROR_NOT_SET);
2289		return (NULL);
2290	}
2291
2292	return (prop->pr_pgname);
2293}
2294
2295
2296static union scf_simple_prop_val *
2297scf_next_val(scf_simple_prop_t *prop, scf_type_t type)
2298{
2299	if (prop == NULL) {
2300		(void) scf_set_error(SCF_ERROR_NOT_SET);
2301		return (NULL);
2302	}
2303
2304	switch (prop->pr_type) {
2305	case SCF_TYPE_USTRING:
2306	case SCF_TYPE_HOST:
2307	case SCF_TYPE_HOSTNAME:
2308	case SCF_TYPE_NET_ADDR_V4:
2309	case SCF_TYPE_NET_ADDR_V6:
2310	case SCF_TYPE_URI:
2311	case SCF_TYPE_FMRI: {
2312		if (type != SCF_TYPE_USTRING) {
2313			(void) scf_set_error(SCF_ERROR_TYPE_MISMATCH);
2314			return (NULL);
2315		}
2316		break;
2317		}
2318	default: {
2319		if (type != prop->pr_type) {
2320			(void) scf_set_error(SCF_ERROR_TYPE_MISMATCH);
2321			return (NULL);
2322		}
2323		break;
2324		}
2325	}
2326
2327	if (prop->pr_iter >= prop->pr_numvalues) {
2328		(void) scf_set_error(SCF_ERROR_NONE);
2329		return (NULL);
2330	}
2331
2332	return (&prop->pr_vallist[prop->pr_iter++]);
2333}
2334
2335
2336uint8_t *
2337scf_simple_prop_next_boolean(scf_simple_prop_t *prop)
2338{
2339	union scf_simple_prop_val *ret;
2340
2341	ret = scf_next_val(prop, SCF_TYPE_BOOLEAN);
2342
2343	if (ret == NULL)
2344		return (NULL);
2345
2346	return (&ret->pv_bool);
2347}
2348
2349
2350uint64_t *
2351scf_simple_prop_next_count(scf_simple_prop_t *prop)
2352{
2353	union scf_simple_prop_val *ret;
2354
2355	ret = scf_next_val(prop, SCF_TYPE_COUNT);
2356
2357	if (ret == NULL)
2358		return (NULL);
2359
2360	return (&ret->pv_uint);
2361}
2362
2363
2364int64_t *
2365scf_simple_prop_next_integer(scf_simple_prop_t *prop)
2366{
2367	union scf_simple_prop_val *ret;
2368
2369	ret = scf_next_val(prop, SCF_TYPE_INTEGER);
2370
2371	if (ret == NULL)
2372		return (NULL);
2373
2374	return (&ret->pv_int);
2375}
2376
2377int64_t *
2378scf_simple_prop_next_time(scf_simple_prop_t *prop, int32_t *nsec)
2379{
2380	union scf_simple_prop_val *ret;
2381
2382	ret = scf_next_val(prop, SCF_TYPE_TIME);
2383
2384	if (ret == NULL)
2385		return (NULL);
2386
2387	if (nsec != NULL)
2388		*nsec = ret->pv_time.t_nsec;
2389
2390	return (&ret->pv_time.t_sec);
2391}
2392
2393char *
2394scf_simple_prop_next_astring(scf_simple_prop_t *prop)
2395{
2396	union scf_simple_prop_val *ret;
2397
2398	ret = scf_next_val(prop, SCF_TYPE_ASTRING);
2399
2400	if (ret == NULL)
2401		return (NULL);
2402
2403	return (ret->pv_str);
2404}
2405
2406char *
2407scf_simple_prop_next_ustring(scf_simple_prop_t *prop)
2408{
2409	union scf_simple_prop_val *ret;
2410
2411	ret = scf_next_val(prop, SCF_TYPE_USTRING);
2412
2413	if (ret == NULL)
2414		return (NULL);
2415
2416	return (ret->pv_str);
2417}
2418
2419void *
2420scf_simple_prop_next_opaque(scf_simple_prop_t *prop, size_t *length)
2421{
2422	union scf_simple_prop_val *ret;
2423
2424	ret = scf_next_val(prop, SCF_TYPE_OPAQUE);
2425
2426	if (ret == NULL) {
2427		*length = 0;
2428		return (NULL);
2429	}
2430
2431	*length = ret->pv_opaque.o_size;
2432	return (ret->pv_opaque.o_value);
2433}
2434
2435/*
2436 * Generate a filename based on the fmri and the given name and return
2437 * it in the buffer of MAXPATHLEN provided by the caller.
2438 * If temp_filename is non-zero, also generate a temporary, unique filename
2439 * and return it in the temp buffer of MAXPATHLEN provided by the caller.
2440 * The path to the generated pathname is also created.
2441 * Given fmri should begin with a scheme such as "svc:".
2442 * Returns
2443 *      0 on success
2444 *      -1 if filename would exceed MAXPATHLEN or
2445 *	-2 if unable to create directory to filename path
2446 */
2447int
2448gen_filenms_from_fmri(const char *fmri, const char *name, char *filename,
2449    char *temp_filename)
2450{
2451	int		len;
2452
2453	len = strlen(SMF_SPEEDY_FILES_PATH);
2454	len += strlen(fmri);
2455	len += 2;			/* for slash and null */
2456	len += strlen(name);
2457	len += 6;			/* For X's needed for mkstemp */
2458
2459	if (len > MAXPATHLEN)
2460		return (-1);
2461
2462	/* Construct directory name first - speedy path ends in slash */
2463	(void) strcpy(filename, SMF_SPEEDY_FILES_PATH);
2464	(void) strcat(filename, fmri);
2465	if (mkdirp(filename, 0755) == -1) {
2466		/* errno is set */
2467		if (errno != EEXIST)
2468			return (-2);
2469	}
2470
2471	(void) strcat(filename, "/");
2472	(void) strcat(filename, name);
2473
2474	if (temp_filename) {
2475		(void) strcpy(temp_filename, filename);
2476		(void) strcat(temp_filename, "XXXXXX");
2477	}
2478
2479	return (0);
2480}
2481
2482static scf_type_t
2483scf_true_base_type(scf_type_t type)
2484{
2485	scf_type_t base = type;
2486
2487	do {
2488		type = base;
2489		(void) scf_type_base_type(type, &base);
2490	} while (base != type);
2491
2492	return (base);
2493}
2494
2495/*
2496 * Convenience routine which frees all strings and opaque data
2497 * allocated by scf_read_propvec.
2498 *
2499 * Like free(3C), this function preserves the value of errno.
2500 */
2501void
2502scf_clean_propvec(scf_propvec_t *propvec)
2503{
2504	int saved_errno = errno;
2505	scf_propvec_t *prop;
2506
2507	for (prop = propvec; prop->pv_prop != NULL; prop++) {
2508		assert(prop->pv_type != SCF_TYPE_INVALID);
2509		if (prop->pv_type == SCF_TYPE_OPAQUE) {
2510			scf_opaque_t *o = prop->pv_ptr;
2511
2512			if (o->so_addr != NULL)
2513				free(o->so_addr);
2514		} else if (scf_true_base_type(prop->pv_type) ==
2515		    SCF_TYPE_ASTRING) {
2516			if (*(char **)prop->pv_ptr != NULL)
2517				free(*(char **)prop->pv_ptr);
2518		}
2519	}
2520
2521	errno = saved_errno;
2522}
2523
2524static int
2525count_props(scf_propvec_t *props)
2526{
2527	int count = 0;
2528
2529	for (; props->pv_prop != NULL; props++)
2530		count++;
2531	return (count);
2532}
2533
2534/*
2535 * Reads a vector of properties from the specified fmri/property group.
2536 * If 'running' is true, reads from the running snapshot instead of the
2537 * editing snapshot.
2538 *
2539 * For string types, a buffer is allocated using malloc(3C) to hold the
2540 * zero-terminated string, a pointer to which is stored in the
2541 * caller-provided char **.  It is the caller's responsbility to free
2542 * this string.  To simplify error handling, unread strings are
2543 * initialized to NULL.
2544 *
2545 * For opaque types, a buffer is allocated using malloc(3C) to hold the
2546 * opaque data.  A pointer to this buffer and its size are stored in
2547 * the caller-provided scf_opaque_t.  It is the caller's responsibility
2548 * to free this buffer.  To simplify error handling, the address fields
2549 * for unread opaque data are initialized to NULL.
2550 *
2551 * All other data is stored directly in caller-provided variables or
2552 * structures.
2553 *
2554 * If this function fails to read a specific property, *badprop is set
2555 * to point at that property's entry in the properties array.
2556 *
2557 * On all failures, all memory allocated by this function is freed.
2558 */
2559int
2560scf_read_propvec(const char *fmri, const char *pgname, boolean_t running,
2561    scf_propvec_t *properties, scf_propvec_t **badprop)
2562{
2563	scf_handle_t *h = handle_create();
2564	scf_service_t *s = scf_service_create(h);
2565	scf_instance_t *i = scf_instance_create(h);
2566	scf_snapshot_t *snap = running ? scf_snapshot_create(h) : NULL;
2567	scf_propertygroup_t *pg = scf_pg_create(h);
2568	scf_property_t *p = scf_property_create(h);
2569	scf_value_t *v = scf_value_create(h);
2570	boolean_t instance = B_TRUE;
2571	scf_propvec_t *prop;
2572	int error = 0;
2573
2574	if (h == NULL || s == NULL || i == NULL || (running && snap == NULL) ||
2575	    pg == NULL || p == NULL || v == NULL)
2576		goto scferror;
2577
2578	if (scf_handle_decode_fmri(h, fmri, NULL, s, i, NULL, NULL, 0) == -1)
2579		goto scferror;
2580
2581	if (scf_instance_to_fmri(i, NULL, 0) == -1) {
2582		if (scf_error() != SCF_ERROR_NOT_SET)
2583			goto scferror;
2584		instance = B_FALSE;
2585	}
2586
2587	if (running) {
2588		if (!instance) {
2589			error = SCF_ERROR_TYPE_MISMATCH;
2590			goto out;
2591		}
2592
2593		if (scf_instance_get_snapshot(i, "running", snap) !=
2594		    SCF_SUCCESS)
2595			goto scferror;
2596	}
2597
2598	if ((instance ? scf_instance_get_pg_composed(i, snap, pgname, pg) :
2599	    scf_service_get_pg(s, pgname, pg)) == -1)
2600		goto scferror;
2601
2602	for (prop = properties; prop->pv_prop != NULL; prop++) {
2603		if (prop->pv_type == SCF_TYPE_OPAQUE)
2604			((scf_opaque_t *)prop->pv_ptr)->so_addr = NULL;
2605		else if (scf_true_base_type(prop->pv_type) == SCF_TYPE_ASTRING)
2606			*((char **)prop->pv_ptr) = NULL;
2607	}
2608
2609	for (prop = properties; prop->pv_prop != NULL; prop++) {
2610		int ret = 0;
2611
2612		if (scf_pg_get_property(pg, prop->pv_prop, p) == -1 ||
2613		    scf_property_get_value(p, v) == -1) {
2614			*badprop = prop;
2615			goto scferror;
2616		}
2617		switch (prop->pv_type) {
2618		case SCF_TYPE_BOOLEAN: {
2619			uint8_t b;
2620
2621			ret = scf_value_get_boolean(v, &b);
2622			if (ret == -1)
2623				break;
2624			if (prop->pv_aux != 0) {
2625				uint64_t *bits = prop->pv_ptr;
2626				*bits = b ? (*bits | prop->pv_aux) :
2627				    (*bits & ~prop->pv_aux);
2628			} else {
2629				boolean_t *bool = prop->pv_ptr;
2630				*bool = b ? B_TRUE : B_FALSE;
2631			}
2632			break;
2633		}
2634		case SCF_TYPE_COUNT:
2635			ret = scf_value_get_count(v, prop->pv_ptr);
2636			break;
2637		case SCF_TYPE_INTEGER:
2638			ret = scf_value_get_integer(v, prop->pv_ptr);
2639			break;
2640		case SCF_TYPE_TIME: {
2641			scf_time_t *time = prop->pv_ptr;
2642
2643			ret = scf_value_get_time(v, &time->t_seconds,
2644			    &time->t_ns);
2645			break;
2646		}
2647		case SCF_TYPE_OPAQUE: {
2648			scf_opaque_t *opaque = prop->pv_ptr;
2649			ssize_t size = scf_value_get_opaque(v, NULL, 0);
2650
2651			if (size == -1) {
2652				*badprop = prop;
2653				goto scferror;
2654			}
2655			if ((opaque->so_addr = malloc(size)) == NULL) {
2656				error = SCF_ERROR_NO_MEMORY;
2657				goto out;
2658			}
2659			opaque->so_size = size;
2660			ret = scf_value_get_opaque(v, opaque->so_addr, size);
2661			break;
2662		}
2663		default: {
2664			char *s;
2665			ssize_t size;
2666
2667			assert(scf_true_base_type(prop->pv_type) ==
2668			    SCF_TYPE_ASTRING);
2669
2670			size = scf_value_get_astring(v, NULL, 0);
2671			if (size == -1) {
2672				*badprop = prop;
2673				goto scferror;
2674			}
2675			if ((s = malloc(++size)) == NULL) {
2676				error = SCF_ERROR_NO_MEMORY;
2677				goto out;
2678			}
2679			ret = scf_value_get_astring(v, s, size);
2680			*(char **)prop->pv_ptr = s;
2681		}
2682
2683		if (ret == -1) {
2684			*badprop = prop;
2685			goto scferror;
2686		}
2687
2688		}
2689	}
2690
2691	goto out;
2692
2693scferror:
2694	error = scf_error();
2695	scf_clean_propvec(properties);
2696
2697out:
2698	scf_pg_destroy(pg);
2699	scf_snapshot_destroy(snap);
2700	scf_instance_destroy(i);
2701	scf_service_destroy(s);
2702	scf_handle_destroy(h);
2703
2704	if (error != 0) {
2705		(void) scf_set_error(error);
2706		return (SCF_FAILED);
2707	}
2708
2709	return (SCF_SUCCESS);
2710}
2711
2712/*
2713 * Writes a vector of properties to the specified fmri/property group.
2714 *
2715 * If this function fails to write a specific property, *badprop is set
2716 * to point at that property's entry in the properties array.
2717 *
2718 * One significant difference between this function and the
2719 * scf_read_propvec function is that for string types, pv_ptr is a
2720 * char *, not a char **.  This means that you can't write a propvec
2721 * you just read, but makes other uses (hopefully the majority) simpler.
2722 */
2723int
2724scf_write_propvec(const char *fmri, const char *pgname,
2725    scf_propvec_t *properties, scf_propvec_t **badprop)
2726{
2727	scf_handle_t *h = handle_create();
2728	scf_service_t *s = scf_service_create(h);
2729	scf_instance_t *inst = scf_instance_create(h);
2730	scf_snapshot_t *snap = scf_snapshot_create(h);
2731	scf_propertygroup_t *pg = scf_pg_create(h);
2732	scf_property_t *p = scf_property_create(h);
2733	scf_transaction_t *tx = scf_transaction_create(h);
2734	scf_value_t **v = NULL;
2735	scf_transaction_entry_t **e = NULL;
2736	boolean_t instance = B_TRUE;
2737	int i, n;
2738	scf_propvec_t *prop;
2739	int error = 0, ret;
2740
2741	n = count_props(properties);
2742	v = calloc(n, sizeof (scf_value_t *));
2743	e = calloc(n, sizeof (scf_transaction_entry_t *));
2744
2745	if (v == NULL || e == NULL) {
2746		error = SCF_ERROR_NO_MEMORY;
2747		goto out;
2748	}
2749
2750	if (h == NULL || s == NULL || inst == NULL || pg == NULL || p == NULL ||
2751	    tx == NULL)
2752		goto scferror;
2753
2754	for (i = 0; i < n; i++) {
2755		v[i] = scf_value_create(h);
2756		e[i] = scf_entry_create(h);
2757		if (v[i] == NULL || e[i] == NULL)
2758			goto scferror;
2759	}
2760
2761	if (scf_handle_decode_fmri(h, fmri, NULL, s, inst, NULL, NULL, 0)
2762	    != SCF_SUCCESS)
2763		goto scferror;
2764
2765	if (scf_instance_to_fmri(inst, NULL, 0) == -1) {
2766		if (scf_error() != SCF_ERROR_NOT_SET)
2767			goto scferror;
2768		instance = B_FALSE;
2769	}
2770
2771	if ((instance ? scf_instance_get_pg(inst, pgname, pg) :
2772	    scf_service_get_pg(s, pgname, pg)) == -1)
2773		goto scferror;
2774
2775top:
2776	if (scf_transaction_start(tx, pg) == -1)
2777		goto scferror;
2778
2779	for (prop = properties, i = 0; prop->pv_prop != NULL; prop++, i++) {
2780		ret = scf_transaction_property_change(tx, e[i], prop->pv_prop,
2781		    prop->pv_type);
2782		if (ret == -1 && scf_error() == SCF_ERROR_NOT_FOUND)
2783			ret = scf_transaction_property_new(tx, e[i],
2784			    prop->pv_prop, prop->pv_type);
2785
2786		if (ret == -1) {
2787			*badprop = prop;
2788			goto scferror;
2789		}
2790
2791		switch (prop->pv_type) {
2792		case SCF_TYPE_BOOLEAN: {
2793			boolean_t b = (prop->pv_aux != 0) ?
2794			    (*(uint64_t *)prop->pv_ptr & prop->pv_aux) != 0 :
2795			    *(boolean_t *)prop->pv_ptr;
2796
2797			scf_value_set_boolean(v[i], b ? 1 : 0);
2798			break;
2799		}
2800		case SCF_TYPE_COUNT:
2801			scf_value_set_count(v[i], *(uint64_t *)prop->pv_ptr);
2802			break;
2803		case SCF_TYPE_INTEGER:
2804			scf_value_set_integer(v[i], *(int64_t *)prop->pv_ptr);
2805			break;
2806		case SCF_TYPE_TIME: {
2807			scf_time_t *time = prop->pv_ptr;
2808
2809			ret = scf_value_set_time(v[i], time->t_seconds,
2810			    time->t_ns);
2811			break;
2812		}
2813		case SCF_TYPE_OPAQUE: {
2814			scf_opaque_t *opaque = prop->pv_ptr;
2815
2816			ret = scf_value_set_opaque(v[i], opaque->so_addr,
2817			    opaque->so_size);
2818			break;
2819		}
2820		case SCF_TYPE_ASTRING:
2821			ret = scf_value_set_astring(v[i],
2822			    (const char *)prop->pv_ptr);
2823			break;
2824		default:
2825			ret = scf_value_set_from_string(v[i], prop->pv_type,
2826			    (const char *)prop->pv_ptr);
2827		}
2828
2829		if (ret == -1 || scf_entry_add_value(e[i], v[i]) == -1) {
2830			*badprop = prop;
2831			goto scferror;
2832		}
2833	}
2834
2835	ret = scf_transaction_commit(tx);
2836	if (ret == 1)
2837		goto out;
2838
2839	if (ret == 0 && scf_pg_update(pg) != -1) {
2840		scf_transaction_reset(tx);
2841		goto top;
2842	}
2843
2844scferror:
2845	error = scf_error();
2846
2847out:
2848	if (v != NULL) {
2849		for (i = 0; i < n; i++)
2850			scf_value_destroy(v[i]);
2851		free(v);
2852	}
2853
2854	if (e != NULL) {
2855		for (i = 0; i < n; i++)
2856			scf_entry_destroy(e[i]);
2857		free(e);
2858	}
2859
2860	scf_transaction_destroy(tx);
2861	scf_property_destroy(p);
2862	scf_pg_destroy(pg);
2863	scf_snapshot_destroy(snap);
2864	scf_instance_destroy(inst);
2865	scf_service_destroy(s);
2866	scf_handle_destroy(h);
2867
2868	if (error != 0) {
2869		(void) scf_set_error(error);
2870		return (SCF_FAILED);
2871	}
2872
2873	return (SCF_SUCCESS);
2874}
2875
2876/*
2877 * Returns
2878 *   0 - success
2879 *   ECONNABORTED - repository connection broken
2880 *   ECANCELED - inst was deleted
2881 *   EPERM
2882 *   EACCES
2883 *   EROFS
2884 *   ENOMEM
2885 */
2886int
2887scf_instance_delete_prop(scf_instance_t *inst, const char *pgname,
2888    const char *pname)
2889{
2890	scf_handle_t *h;
2891	scf_propertygroup_t *pg;
2892	scf_transaction_t *tx;
2893	scf_transaction_entry_t *e;
2894	int error = 0, ret = 1, r;
2895
2896	h = scf_instance_handle(inst);
2897
2898	if ((pg = scf_pg_create(h)) == NULL) {
2899		return (ENOMEM);
2900	}
2901
2902	if (scf_instance_get_pg(inst, pgname, pg) != 0) {
2903		error = scf_error();
2904		scf_pg_destroy(pg);
2905		switch (error) {
2906		case SCF_ERROR_NOT_FOUND:
2907			return (SCF_SUCCESS);
2908
2909		case SCF_ERROR_DELETED:
2910			return (ECANCELED);
2911
2912		case SCF_ERROR_CONNECTION_BROKEN:
2913		default:
2914			return (ECONNABORTED);
2915
2916		case SCF_ERROR_NOT_SET:
2917			bad_error("scf_instance_get_pg", scf_error());
2918		}
2919	}
2920
2921	tx = scf_transaction_create(h);
2922	e = scf_entry_create(h);
2923	if (tx == NULL || e == NULL) {
2924		ret = ENOMEM;
2925		goto out;
2926	}
2927
2928	for (;;) {
2929		if (scf_transaction_start(tx, pg) != 0) {
2930			goto scferror;
2931		}
2932
2933		if (scf_transaction_property_delete(tx, e, pname) != 0) {
2934			goto scferror;
2935		}
2936
2937		if ((r = scf_transaction_commit(tx)) == 1) {
2938			ret = 0;
2939			goto out;
2940		}
2941
2942		if (r == -1) {
2943			goto scferror;
2944		}
2945
2946		scf_transaction_reset(tx);
2947		if (scf_pg_update(pg) == -1) {
2948			goto scferror;
2949		}
2950	}
2951
2952scferror:
2953	switch (scf_error()) {
2954	case SCF_ERROR_DELETED:
2955	case SCF_ERROR_NOT_FOUND:
2956		ret = 0;
2957		break;
2958
2959	case SCF_ERROR_PERMISSION_DENIED:
2960		ret = EPERM;
2961		break;
2962
2963	case SCF_ERROR_BACKEND_ACCESS:
2964		ret = EACCES;
2965		break;
2966
2967	case SCF_ERROR_BACKEND_READONLY:
2968		ret = EROFS;
2969		break;
2970
2971	case SCF_ERROR_CONNECTION_BROKEN:
2972	default:
2973		ret = ECONNABORTED;
2974		break;
2975
2976	case SCF_ERROR_HANDLE_MISMATCH:
2977	case SCF_ERROR_INVALID_ARGUMENT:
2978	case SCF_ERROR_NOT_BOUND:
2979	case SCF_ERROR_NOT_SET:
2980		bad_error("scf_instance_delete_prop", scf_error());
2981	}
2982
2983out:
2984	scf_transaction_destroy(tx);
2985	scf_entry_destroy(e);
2986	scf_pg_destroy(pg);
2987
2988	return (ret);
2989}
2990