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