xref: /illumos-gate/usr/src/lib/libscf/common/midlevel.c (revision dfac3eb25a53097b94643fa6f32bb2fc1107df0c)
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  */
57 static scf_handle_t *
58 handle_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 
73 void
74 scf_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 
93 static char *
94 assemble_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 
153 static scf_simple_prop_t *
154 fill_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 
326 error1:
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 
356 error2:
357 	scf_iter_destroy(iter);
358 	(void) scf_value_destroy(val);
359 
360 error3:
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 
375 static int
376 insert_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  */
453 static int
454 transaction_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 
494 static int
495 get_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 
519 out:
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  */
532 static int
533 set_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 
556 general_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) {
570 get:
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 
615 set:
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 
655 out:
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 
665 static int
666 delete_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 
701 error:
702 	switch (scf_error()) {
703 	case SCF_ERROR_DELETED:
704 	case SCF_ERROR_NOT_FOUND:
705 		/* success */
706 		ret = 0;
707 	}
708 
709 out:
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  */
728 static int
729 set_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 
749 get:
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. */
768 add:
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 
924 out:
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 
933 static int
934 set_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 
967 static int
968 get_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 
1010 out:
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  */
1023 static int
1024 set_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 
1055 out:
1056 	return (ret);
1057 }
1058 
1059 static int
1060 set_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 
1105 out:
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  */
1117 static scf_propertygroup_t *
1118 get_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 
1157 int
1158 smf_enable_instance(const char *fmri, int flags)
1159 {
1160 	return (set_inst_enabled_flags(fmri, flags, B_TRUE));
1161 }
1162 
1163 int
1164 smf_disable_instance(const char *fmri, int flags)
1165 {
1166 	return (set_inst_enabled_flags(fmri, flags, B_FALSE));
1167 }
1168 
1169 int
1170 _smf_refresh_instance_i(scf_instance_t *inst)
1171 {
1172 	return (set_inst_action_inst(inst, SCF_PROPERTY_REFRESH));
1173 }
1174 
1175 int
1176 smf_refresh_instance(const char *instance)
1177 {
1178 	return (set_inst_action(instance, SCF_PROPERTY_REFRESH));
1179 }
1180 
1181 int
1182 smf_restart_instance(const char *instance)
1183 {
1184 	return (set_inst_action(instance, SCF_PROPERTY_RESTART));
1185 }
1186 
1187 int
1188 smf_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 
1202 int
1203 smf_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 
1230 int
1231 smf_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 
1258 char *
1259 smf_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  */
1301 scf_simple_handle_t *
1302 scf_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 
1340 out:
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  */
1365 scf_transaction_t *
1366 scf_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 
1387 int
1388 scf_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  */
1425 int
1426 scf_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 
1461 out:
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  */
1491 int
1492 scf_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 
1543 int
1544 scf_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 
1616 out:
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 
1628 scf_simple_prop_t *
1629 scf_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 
1714 error1:
1715 	scf_service_destroy(svc);
1716 	scf_property_destroy(prop);
1717 error2:
1718 	free(fmri_buf);
1719 	if (local_h)
1720 		scf_handle_destroy(h);
1721 	return (NULL);
1722 }
1723 
1724 
1725 void
1726 scf_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 
1763 scf_simple_app_props_t *
1764 scf_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 
2094 error1:
2095 	scf_simple_app_props_free(ret);
2096 
2097 error2:
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 
2112 void
2113 scf_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 
2140 const scf_simple_prop_t *
2141 scf_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 
2205 const scf_simple_prop_t *
2206 scf_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 
2250 void
2251 scf_simple_prop_next_reset(scf_simple_prop_t *prop)
2252 {
2253 	if (prop == NULL)
2254 		return;
2255 	prop->pr_iter = 0;
2256 }
2257 
2258 ssize_t
2259 scf_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 
2268 scf_type_t
2269 scf_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 
2278 char *
2279 scf_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 
2290 char *
2291 scf_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 
2302 static union scf_simple_prop_val *
2303 scf_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 
2342 uint8_t *
2343 scf_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 
2356 uint64_t *
2357 scf_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 
2370 int64_t *
2371 scf_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 
2383 int64_t *
2384 scf_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 
2399 char *
2400 scf_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 
2412 char *
2413 scf_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 
2425 void *
2426 scf_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  */
2453 int
2454 gen_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 
2488 static scf_type_t
2489 scf_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  */
2507 void
2508 scf_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 
2530 static int
2531 count_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  */
2565 int
2566 scf_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 
2699 scferror:
2700 	error = scf_error();
2701 	scf_clean_propvec(properties);
2702 
2703 out:
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  */
2729 int
2730 scf_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 
2781 top:
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 
2850 scferror:
2851 	error = scf_error();
2852 
2853 out:
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