xref: /illumos-gate/usr/src/lib/libscf/common/midlevel.c (revision c42520eba4ad2249406ee84492401db194e6104e)
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 (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 #include "libscf_impl.h"
27 
28 #include <assert.h>
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 			if (ret == -1 && scf_error() == SCF_ERROR_DELETED)
951 				(void) scf_set_error(SCF_ERROR_NOT_FOUND);
952 		} else {
953 			switch (scf_error()) {
954 			case SCF_ERROR_CONSTRAINT_VIOLATED:
955 				(void) scf_set_error(
956 				    SCF_ERROR_INVALID_ARGUMENT);
957 				break;
958 			case SCF_ERROR_DELETED:
959 				(void) scf_set_error(SCF_ERROR_NOT_FOUND);
960 				break;
961 			}
962 		}
963 
964 		scf_instance_destroy(inst);
965 	}
966 
967 	scf_handle_destroy(h);
968 
969 	return (ret);
970 }
971 
972 
973 /*
974  * get_inst_state() gets the state string from an instance, and returns
975  * the SCF_STATE_* constant that coincides with the instance's current state.
976  */
977 
978 static int
979 get_inst_state(scf_instance_t *inst, scf_handle_t *h)
980 {
981 	scf_propertygroup_t	*pg = NULL;
982 	scf_property_t		*prop = NULL;
983 	scf_value_t		*val = NULL;
984 	char			state[MAX_SCF_STATE_STRING_SZ];
985 	int			ret = -1;
986 
987 	if (((pg = scf_pg_create(h)) == NULL) ||
988 	    ((prop = scf_property_create(h)) == NULL) ||
989 	    ((val = scf_value_create(h)) == NULL))
990 		goto out;
991 
992 	/* Pull the state property from the instance */
993 
994 	if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) == -1 ||
995 	    scf_pg_get_property(pg, SCF_PROPERTY_STATE, prop) == -1 ||
996 	    scf_property_get_value(prop, val) == -1) {
997 		if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
998 			(void) scf_set_error(SCF_ERROR_INTERNAL);
999 		goto out;
1000 	}
1001 
1002 	if (scf_value_get_astring(val, state, sizeof (state)) <= 0) {
1003 		(void) scf_set_error(SCF_ERROR_INTERNAL);
1004 		goto out;
1005 	}
1006 
1007 	if (strcmp(state, SCF_STATE_STRING_UNINIT) == 0) {
1008 		ret = SCF_STATE_UNINIT;
1009 	} else if (strcmp(state, SCF_STATE_STRING_MAINT) == 0) {
1010 		ret = SCF_STATE_MAINT;
1011 	} else if (strcmp(state, SCF_STATE_STRING_OFFLINE) == 0) {
1012 		ret = SCF_STATE_OFFLINE;
1013 	} else if (strcmp(state, SCF_STATE_STRING_DISABLED) == 0) {
1014 		ret = SCF_STATE_DISABLED;
1015 	} else if (strcmp(state, SCF_STATE_STRING_ONLINE) == 0) {
1016 		ret = SCF_STATE_ONLINE;
1017 	} else if (strcmp(state, SCF_STATE_STRING_DEGRADED) == 0) {
1018 		ret = SCF_STATE_DEGRADED;
1019 	}
1020 
1021 out:
1022 	scf_pg_destroy(pg);
1023 	scf_property_destroy(prop);
1024 	(void) scf_value_destroy(val);
1025 
1026 	return (ret);
1027 }
1028 
1029 /*
1030  * Sets an instance to be enabled or disabled after reboot, using the
1031  * temporary (overriding) general_ovr property group to reflect the
1032  * present state, if it is different.
1033  */
1034 static int
1035 set_inst_enabled_atboot(scf_instance_t *inst, uint8_t desired)
1036 {
1037 	int enabled;
1038 	int persistent;
1039 	int ret = -1;
1040 
1041 	if ((persistent = get_inst_enabled(inst, SCF_PG_GENERAL)) < 0) {
1042 		if (scf_error() != SCF_ERROR_NOT_FOUND)
1043 			goto out;
1044 		persistent = B_FALSE;
1045 	}
1046 	if ((enabled = get_inst_enabled(inst, SCF_PG_GENERAL_OVR)) < 0) {
1047 		enabled = persistent;
1048 		if (persistent != desired) {
1049 			/*
1050 			 * Temporarily store the present enabled state.
1051 			 */
1052 			if (set_inst_enabled(inst, persistent,
1053 			    SCF_PG_GENERAL_OVR, SCF_PG_GENERAL_OVR_FLAGS))
1054 				goto out;
1055 		}
1056 	}
1057 	if (persistent != desired)
1058 		if (set_inst_enabled(inst, desired, SCF_PG_GENERAL,
1059 		    SCF_PG_GENERAL_FLAGS))
1060 			goto out;
1061 	if (enabled == desired)
1062 		ret = delete_inst_enabled(inst, SCF_PG_GENERAL_OVR);
1063 	else
1064 		ret = 0;
1065 
1066 out:
1067 	return (ret);
1068 }
1069 
1070 static int
1071 set_inst_enabled_flags(const char *fmri, int flags, uint8_t desired)
1072 {
1073 	int ret = -1;
1074 	scf_handle_t *h;
1075 	scf_instance_t *inst;
1076 
1077 	if (flags & ~(SMF_TEMPORARY | SMF_AT_NEXT_BOOT) ||
1078 	    flags & SMF_TEMPORARY && flags & SMF_AT_NEXT_BOOT) {
1079 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1080 		return (ret);
1081 	}
1082 
1083 	if ((h = handle_create()) == NULL)
1084 		return (ret);
1085 
1086 	if ((inst = scf_instance_create(h)) == NULL) {
1087 		scf_handle_destroy(h);
1088 		return (ret);
1089 	}
1090 
1091 	if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL, NULL,
1092 	    SCF_DECODE_FMRI_EXACT) == -1) {
1093 		if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED)
1094 			(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1095 		goto out;
1096 	}
1097 
1098 	if (flags & SMF_AT_NEXT_BOOT) {
1099 		ret = set_inst_enabled_atboot(inst, desired);
1100 	} else {
1101 		if (set_inst_enabled(inst, desired, flags & SMF_TEMPORARY ?
1102 		    SCF_PG_GENERAL_OVR : SCF_PG_GENERAL, flags & SMF_TEMPORARY ?
1103 		    SCF_PG_GENERAL_OVR_FLAGS : SCF_PG_GENERAL_FLAGS))
1104 			goto out;
1105 
1106 		/*
1107 		 * Make the persistent value effective by deleting the
1108 		 * temporary one.
1109 		 */
1110 		if (flags & SMF_TEMPORARY)
1111 			ret = 0;
1112 		else
1113 			ret = delete_inst_enabled(inst, SCF_PG_GENERAL_OVR);
1114 	}
1115 
1116 out:
1117 	scf_instance_destroy(inst);
1118 	scf_handle_destroy(h);
1119 	if (ret == -1 && scf_error() == SCF_ERROR_DELETED)
1120 		(void) scf_set_error(SCF_ERROR_NOT_FOUND);
1121 	return (ret);
1122 }
1123 
1124 /*
1125  * Create and return a pg from the instance associated with the given handle.
1126  * This function is only called in scf_transaction_setup and
1127  * scf_transaction_restart where the h->rh_instance pointer is properly filled
1128  * in by scf_general_setup_pg().
1129  */
1130 static scf_propertygroup_t *
1131 get_instance_pg(scf_simple_handle_t *simple_h)
1132 {
1133 	scf_propertygroup_t	*ret_pg = scf_pg_create(simple_h->h);
1134 	char			*pg_name;
1135 	ssize_t			namelen;
1136 
1137 	if (ret_pg == NULL) {
1138 		return (NULL);
1139 	}
1140 
1141 	namelen = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
1142 	assert(namelen > 0);
1143 
1144 	if ((pg_name = malloc(namelen)) == NULL) {
1145 		if (scf_error() == SCF_ERROR_NOT_SET) {
1146 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
1147 		}
1148 		return (NULL);
1149 	}
1150 
1151 	if (scf_pg_get_name(simple_h->running_pg, pg_name, namelen) < 0) {
1152 		if (scf_error() == SCF_ERROR_NOT_SET) {
1153 			(void) scf_set_error(SCF_ERROR_INTERNAL);
1154 		}
1155 		return (NULL);
1156 	}
1157 
1158 	/* Get pg from instance */
1159 	if (scf_instance_get_pg(simple_h->inst, pg_name, ret_pg) == -1) {
1160 		return (NULL);
1161 	}
1162 
1163 	return (ret_pg);
1164 }
1165 
1166 int
1167 smf_enable_instance(const char *fmri, int flags)
1168 {
1169 	return (set_inst_enabled_flags(fmri, flags, B_TRUE));
1170 }
1171 
1172 int
1173 smf_disable_instance(const char *fmri, int flags)
1174 {
1175 	return (set_inst_enabled_flags(fmri, flags, B_FALSE));
1176 }
1177 
1178 int
1179 _smf_refresh_instance_i(scf_instance_t *inst)
1180 {
1181 	return (set_inst_action_inst(inst, SCF_PROPERTY_REFRESH));
1182 }
1183 
1184 int
1185 smf_refresh_instance(const char *instance)
1186 {
1187 	return (set_inst_action(instance, SCF_PROPERTY_REFRESH));
1188 }
1189 
1190 int
1191 smf_restart_instance(const char *instance)
1192 {
1193 	return (set_inst_action(instance, SCF_PROPERTY_RESTART));
1194 }
1195 
1196 int
1197 smf_maintain_instance(const char *instance, int flags)
1198 {
1199 	if (flags & SMF_TEMPORARY)
1200 		return (set_inst_action(instance,
1201 		    (flags & SMF_IMMEDIATE) ?
1202 		    SCF_PROPERTY_MAINT_ON_IMMTEMP :
1203 		    SCF_PROPERTY_MAINT_ON_TEMPORARY));
1204 	else
1205 		return (set_inst_action(instance,
1206 		    (flags & SMF_IMMEDIATE) ?
1207 		    SCF_PROPERTY_MAINT_ON_IMMEDIATE :
1208 		    SCF_PROPERTY_MAINT_ON));
1209 }
1210 
1211 int
1212 smf_degrade_instance(const char *instance, int flags)
1213 {
1214 	scf_simple_prop_t		*prop;
1215 	const char			*state_str;
1216 
1217 	if (flags & SMF_TEMPORARY)
1218 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
1219 
1220 	if ((prop = scf_simple_prop_get(NULL, instance, SCF_PG_RESTARTER,
1221 	    SCF_PROPERTY_STATE)) == NULL)
1222 		return (SCF_FAILED);
1223 
1224 	if ((state_str = scf_simple_prop_next_astring(prop)) == NULL) {
1225 		scf_simple_prop_free(prop);
1226 		return (SCF_FAILED);
1227 	}
1228 
1229 	if (strcmp(state_str, SCF_STATE_STRING_ONLINE) != 0) {
1230 		scf_simple_prop_free(prop);
1231 		return (scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED));
1232 	}
1233 	scf_simple_prop_free(prop);
1234 
1235 	return (set_inst_action(instance, (flags & SMF_IMMEDIATE) ?
1236 	    SCF_PROPERTY_DEGRADE_IMMEDIATE : SCF_PROPERTY_DEGRADED));
1237 }
1238 
1239 int
1240 smf_restore_instance(const char *instance)
1241 {
1242 	scf_simple_prop_t		*prop;
1243 	const char			*state_str;
1244 	int				ret;
1245 
1246 	if ((prop = scf_simple_prop_get(NULL, instance, SCF_PG_RESTARTER,
1247 	    SCF_PROPERTY_STATE)) == NULL)
1248 		return (SCF_FAILED);
1249 
1250 	if ((state_str = scf_simple_prop_next_astring(prop)) == NULL) {
1251 		scf_simple_prop_free(prop);
1252 		return (SCF_FAILED);
1253 	}
1254 
1255 	if (strcmp(state_str, SCF_STATE_STRING_MAINT) == 0) {
1256 		ret = set_inst_action(instance, SCF_PROPERTY_MAINT_OFF);
1257 	} else if (strcmp(state_str, SCF_STATE_STRING_DEGRADED) == 0) {
1258 		ret = set_inst_action(instance, SCF_PROPERTY_RESTORE);
1259 	} else {
1260 		ret = scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED);
1261 	}
1262 
1263 	scf_simple_prop_free(prop);
1264 	return (ret);
1265 }
1266 
1267 char *
1268 smf_get_state(const char *instance)
1269 {
1270 	scf_simple_prop_t		*prop;
1271 	const char			*state_str;
1272 	char				*ret;
1273 
1274 	if ((prop = scf_simple_prop_get(NULL, instance, SCF_PG_RESTARTER,
1275 	    SCF_PROPERTY_STATE)) == NULL)
1276 		return (NULL);
1277 
1278 	if ((state_str = scf_simple_prop_next_astring(prop)) == NULL) {
1279 		scf_simple_prop_free(prop);
1280 		return (NULL);
1281 	}
1282 
1283 	if ((ret = strdup(state_str)) == NULL)
1284 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
1285 
1286 	scf_simple_prop_free(prop);
1287 	return (ret);
1288 }
1289 
1290 /*
1291  * scf_general_pg_setup(fmri, pg_name)
1292  * Create a scf_simple_handle_t and fill in the instance, snapshot, and
1293  * property group fields associated with the given fmri and property group
1294  * name.
1295  * Returns:
1296  *      Handle  on success
1297  *      Null  on error with scf_error set to:
1298  *              SCF_ERROR_HANDLE_MISMATCH,
1299  *              SCF_ERROR_INVALID_ARGUMENT,
1300  *              SCF_ERROR_CONSTRAINT_VIOLATED,
1301  *              SCF_ERROR_NOT_FOUND,
1302  *              SCF_ERROR_NOT_SET,
1303  *              SCF_ERROR_DELETED,
1304  *              SCF_ERROR_NOT_BOUND,
1305  *              SCF_ERROR_CONNECTION_BROKEN,
1306  *              SCF_ERROR_INTERNAL,
1307  *              SCF_ERROR_NO_RESOURCES,
1308  *              SCF_ERROR_BACKEND_ACCESS
1309  */
1310 scf_simple_handle_t *
1311 scf_general_pg_setup(const char *fmri, const char *pg_name)
1312 {
1313 	scf_simple_handle_t	*ret;
1314 
1315 	ret = uu_zalloc(sizeof (*ret));
1316 	if (ret == NULL) {
1317 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
1318 		return (NULL);
1319 	} else {
1320 
1321 		ret->h = handle_create();
1322 		ret->inst = scf_instance_create(ret->h);
1323 		ret->snap = scf_snapshot_create(ret->h);
1324 		ret->running_pg = scf_pg_create(ret->h);
1325 	}
1326 
1327 	if ((ret->h == NULL) || (ret->inst == NULL) ||
1328 	    (ret->snap == NULL) || (ret->running_pg == NULL)) {
1329 		goto out;
1330 	}
1331 
1332 	if (scf_handle_decode_fmri(ret->h, fmri, NULL, NULL, ret->inst,
1333 	    NULL, NULL, NULL) == -1) {
1334 		goto out;
1335 	}
1336 
1337 	if ((scf_instance_get_snapshot(ret->inst, "running", ret->snap))
1338 	    != 0) {
1339 		goto out;
1340 	}
1341 
1342 	if (scf_instance_get_pg_composed(ret->inst, ret->snap, pg_name,
1343 	    ret->running_pg) != 0) {
1344 		goto out;
1345 	}
1346 
1347 	return (ret);
1348 
1349 out:
1350 	scf_simple_handle_destroy(ret);
1351 	return (NULL);
1352 }
1353 
1354 /*
1355  * scf_transaction_setup(h)
1356  * creates and starts the transaction
1357  * Returns:
1358  *      transaction  on success
1359  *      NULL on failure with scf_error set to:
1360  *      SCF_ERROR_NO_MEMORY,
1361  *	SCF_ERROR_INVALID_ARGUMENT,
1362  *      SCF_ERROR_HANDLE_DESTROYED,
1363  *	SCF_ERROR_INTERNAL,
1364  *	SCF_ERROR_NO_RESOURCES,
1365  *      SCF_ERROR_NOT_BOUND,
1366  *	SCF_ERROR_CONNECTION_BROKEN,
1367  *      SCF_ERROR_NOT_SET,
1368  *	SCF_ERROR_DELETED,
1369  *	SCF_ERROR_CONSTRAINT_VIOLATED,
1370  *      SCF_ERROR_HANDLE_MISMATCH,
1371  *	SCF_ERROR_BACKEND_ACCESS,
1372  *	SCF_ERROR_IN_USE
1373  */
1374 scf_transaction_t *
1375 scf_transaction_setup(scf_simple_handle_t *simple_h)
1376 {
1377 	scf_transaction_t	*tx = NULL;
1378 
1379 	if ((tx = scf_transaction_create(simple_h->h)) == NULL) {
1380 		return (NULL);
1381 	}
1382 
1383 	if ((simple_h->editing_pg = get_instance_pg(simple_h)) == NULL) {
1384 		return (NULL);
1385 	}
1386 
1387 	if (scf_transaction_start(tx, simple_h->editing_pg) == -1) {
1388 		scf_pg_destroy(simple_h->editing_pg);
1389 		simple_h->editing_pg = NULL;
1390 		return (NULL);
1391 	}
1392 
1393 	return (tx);
1394 }
1395 
1396 int
1397 scf_transaction_restart(scf_simple_handle_t *simple_h, scf_transaction_t *tx)
1398 {
1399 	scf_transaction_reset(tx);
1400 
1401 	if (scf_pg_update(simple_h->editing_pg) == -1) {
1402 		return (SCF_FAILED);
1403 	}
1404 
1405 	if (scf_transaction_start(tx, simple_h->editing_pg) == -1) {
1406 		return (SCF_FAILED);
1407 	}
1408 
1409 	return (SCF_SUCCESS);
1410 }
1411 
1412 /*
1413  * scf_read_count_property(scf_simple_handle_t *simple_h, char *prop_name,
1414  * uint64_t *ret_count)
1415  *
1416  * For the given property name, return the count value.
1417  * RETURNS:
1418  *	SCF_SUCCESS
1419  *	SCF_FAILED on failure with scf_error() set to:
1420  *		SCF_ERROR_HANDLE_DESTROYED
1421  *		SCF_ERROR_INTERNAL
1422  *		SCF_ERROR_NO_RESOURCES
1423  *		SCF_ERROR_NO_MEMORY
1424  *		SCF_ERROR_HANDLE_MISMATCH
1425  *		SCF_ERROR_INVALID_ARGUMENT
1426  *		SCF_ERROR_NOT_BOUND
1427  *		SCF_ERROR_CONNECTION_BROKEN
1428  *		SCF_ERROR_NOT_SET
1429  *		SCF_ERROR_DELETED
1430  *		SCF_ERROR_BACKEND_ACCESS
1431  *		SCF_ERROR_CONSTRAINT_VIOLATED
1432  *		SCF_ERROR_TYPE_MISMATCH
1433  */
1434 int
1435 scf_read_count_property(
1436 	scf_simple_handle_t	*simple_h,
1437 	char			*prop_name,
1438 	uint64_t		*ret_count)
1439 {
1440 	scf_property_t		*prop = scf_property_create(simple_h->h);
1441 	scf_value_t		*val = scf_value_create(simple_h->h);
1442 	int			ret = SCF_FAILED;
1443 
1444 	if ((val == NULL) || (prop == NULL)) {
1445 		goto out;
1446 	}
1447 
1448 	/*
1449 	 * Get the property struct that goes with this property group and
1450 	 * property name.
1451 	 */
1452 	if (scf_pg_get_property(simple_h->running_pg, prop_name, prop) != 0) {
1453 		goto out;
1454 	}
1455 
1456 	/* Get the value structure */
1457 	if (scf_property_get_value(prop, val) == -1) {
1458 		goto out;
1459 	}
1460 
1461 	/*
1462 	 * Now get the count value.
1463 	 */
1464 	if (scf_value_get_count(val, ret_count) == -1) {
1465 		goto out;
1466 	}
1467 
1468 	ret = SCF_SUCCESS;
1469 
1470 out:
1471 	scf_property_destroy(prop);
1472 	scf_value_destroy(val);
1473 	return (ret);
1474 }
1475 
1476 /*
1477  * scf_trans_add_count_property(trans, propname, count, create_flag)
1478  *
1479  * Set a count property transaction entry into the pending SMF transaction.
1480  * The transaction is created and committed outside of this function.
1481  * Returns:
1482  *	SCF_SUCCESS
1483  *	SCF_FAILED on failure with scf_error() set to:
1484  *			SCF_ERROR_HANDLE_DESTROYED,
1485  *			SCF_ERROR_INVALID_ARGUMENT,
1486  *			SCF_ERROR_NO_MEMORY,
1487  *			SCF_ERROR_HANDLE_MISMATCH,
1488  *			SCF_ERROR_NOT_SET,
1489  *			SCF_ERROR_IN_USE,
1490  *			SCF_ERROR_NOT_FOUND,
1491  *			SCF_ERROR_EXISTS,
1492  *			SCF_ERROR_TYPE_MISMATCH,
1493  *			SCF_ERROR_NOT_BOUND,
1494  *			SCF_ERROR_CONNECTION_BROKEN,
1495  *			SCF_ERROR_INTERNAL,
1496  *			SCF_ERROR_DELETED,
1497  *			SCF_ERROR_NO_RESOURCES,
1498  *			SCF_ERROR_BACKEND_ACCESS
1499  */
1500 int
1501 scf_set_count_property(
1502 	scf_transaction_t	*trans,
1503 	char			*propname,
1504 	uint64_t		count,
1505 	boolean_t		create_flag)
1506 {
1507 	scf_handle_t		*handle = scf_transaction_handle(trans);
1508 	scf_value_t		*value = scf_value_create(handle);
1509 	scf_transaction_entry_t	*entry = scf_entry_create(handle);
1510 
1511 	if ((value == NULL) || (entry == NULL)) {
1512 		return (SCF_FAILED);
1513 	}
1514 
1515 	/*
1516 	 * Property must be set in transaction and won't take
1517 	 * effect until the transaction is committed.
1518 	 *
1519 	 * Attempt to change the current value. However, create new property
1520 	 * if it doesn't exist and the create flag is set.
1521 	 */
1522 	if (scf_transaction_property_change(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 	} else {
1529 		if ((create_flag == B_TRUE) &&
1530 		    (scf_error() == SCF_ERROR_NOT_FOUND)) {
1531 			if (scf_transaction_property_new(trans, entry, propname,
1532 			    SCF_TYPE_COUNT) == 0) {
1533 				scf_value_set_count(value, count);
1534 				if (scf_entry_add_value(entry, value) == 0) {
1535 					return (SCF_SUCCESS);
1536 				}
1537 			}
1538 		}
1539 	}
1540 
1541 	/*
1542 	 * cleanup if there were any errors that didn't leave these
1543 	 * values where they would be cleaned up later.
1544 	 */
1545 	if (value != NULL)
1546 		scf_value_destroy(value);
1547 	if (entry != NULL)
1548 		scf_entry_destroy(entry);
1549 	return (SCF_FAILED);
1550 }
1551 
1552 int
1553 scf_simple_walk_instances(uint_t state_flags, void *private,
1554     int (*inst_callback)(scf_handle_t *, scf_instance_t *, void *))
1555 {
1556 	scf_scope_t 		*scope = NULL;
1557 	scf_service_t		*svc = NULL;
1558 	scf_instance_t		*inst = NULL;
1559 	scf_iter_t		*svc_iter = NULL, *inst_iter = NULL;
1560 	scf_handle_t		*h = NULL;
1561 	int			ret = SCF_FAILED;
1562 	int			svc_iter_ret, inst_iter_ret;
1563 	int			inst_state;
1564 
1565 	if ((h = handle_create()) == NULL)
1566 		return (ret);
1567 
1568 	if (((scope = scf_scope_create(h)) == NULL) ||
1569 	    ((svc = scf_service_create(h)) == NULL) ||
1570 	    ((inst = scf_instance_create(h)) == NULL) ||
1571 	    ((svc_iter = scf_iter_create(h)) == NULL) ||
1572 	    ((inst_iter = scf_iter_create(h)) == NULL))
1573 		goto out;
1574 
1575 	/*
1576 	 * Get the local scope, and set up nested iteration through every
1577 	 * local service, and every instance of every service.
1578 	 */
1579 
1580 	if ((scf_handle_get_local_scope(h, scope) != SCF_SUCCESS) ||
1581 	    (scf_iter_scope_services(svc_iter, scope) != SCF_SUCCESS))
1582 		goto out;
1583 
1584 	while ((svc_iter_ret = scf_iter_next_service(svc_iter, svc)) > 0) {
1585 
1586 		if ((scf_iter_service_instances(inst_iter, svc)) !=
1587 		    SCF_SUCCESS)
1588 			goto out;
1589 
1590 		while ((inst_iter_ret =
1591 		    scf_iter_next_instance(inst_iter, inst)) > 0) {
1592 			/*
1593 			 * If get_inst_state fails from an internal error,
1594 			 * IE, being unable to get the property group or
1595 			 * property containing the state of the instance,
1596 			 * we continue instead of failing, as this might just
1597 			 * be an improperly configured instance.
1598 			 */
1599 			if ((inst_state = get_inst_state(inst, h)) == -1) {
1600 				if (scf_error() == SCF_ERROR_INTERNAL) {
1601 					continue;
1602 				} else {
1603 					goto out;
1604 				}
1605 			}
1606 
1607 			if ((uint_t)inst_state & state_flags) {
1608 				if (inst_callback(h, inst, private) !=
1609 				    SCF_SUCCESS) {
1610 					(void) scf_set_error(
1611 					    SCF_ERROR_CALLBACK_FAILED);
1612 					goto out;
1613 				}
1614 			}
1615 		}
1616 
1617 		if (inst_iter_ret == -1)
1618 			goto out;
1619 		scf_iter_reset(inst_iter);
1620 	}
1621 
1622 	if (svc_iter_ret != -1)
1623 		ret = SCF_SUCCESS;
1624 
1625 out:
1626 	scf_scope_destroy(scope);
1627 	scf_service_destroy(svc);
1628 	scf_instance_destroy(inst);
1629 	scf_iter_destroy(svc_iter);
1630 	scf_iter_destroy(inst_iter);
1631 	scf_handle_destroy(h);
1632 
1633 	return (ret);
1634 }
1635 
1636 
1637 scf_simple_prop_t *
1638 scf_simple_prop_get(scf_handle_t *hin, const char *instance, const char *pgname,
1639 			const char *propname)
1640 {
1641 	char 			*fmri_buf, *svcfmri = NULL;
1642 	ssize_t 		fmri_sz;
1643 	scf_property_t 		*prop = NULL;
1644 	scf_service_t 		*svc = NULL;
1645 	scf_simple_prop_t 	*ret;
1646 	scf_handle_t		*h = NULL;
1647 	boolean_t		local_h = B_TRUE;
1648 
1649 	/* If the user passed in a handle, use it. */
1650 	if (hin != NULL) {
1651 		h = hin;
1652 		local_h = B_FALSE;
1653 	}
1654 
1655 	if (local_h && ((h = handle_create()) == NULL))
1656 		return (NULL);
1657 
1658 	if ((fmri_buf = assemble_fmri(h, instance, pgname, propname)) == NULL) {
1659 		if (local_h)
1660 			scf_handle_destroy(h);
1661 		return (NULL);
1662 	}
1663 
1664 	if ((svc = scf_service_create(h)) == NULL ||
1665 	    (prop = scf_property_create(h)) == NULL)
1666 		goto error1;
1667 	if (scf_handle_decode_fmri(h, fmri_buf, NULL, NULL, NULL, NULL, prop,
1668 	    SCF_DECODE_FMRI_REQUIRE_INSTANCE) == -1) {
1669 		switch (scf_error()) {
1670 		/*
1671 		 * If the property isn't found in the instance, we grab the
1672 		 * underlying service, create an FMRI out of it, and then
1673 		 * query the datastore again at the service level for the
1674 		 * property.
1675 		 */
1676 		case SCF_ERROR_NOT_FOUND:
1677 			if (scf_handle_decode_fmri(h, fmri_buf, NULL, svc,
1678 			    NULL, NULL, NULL, SCF_DECODE_FMRI_TRUNCATE) == -1)
1679 				goto error1;
1680 
1681 			fmri_sz = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH) + 1;
1682 			assert(fmri_sz > 0);
1683 
1684 			if (scf_service_to_fmri(svc, fmri_buf, fmri_sz) == -1)
1685 				goto error1;
1686 			if ((svcfmri = assemble_fmri(h, fmri_buf, pgname,
1687 			    propname)) == NULL)
1688 				goto error1;
1689 			if (scf_handle_decode_fmri(h, svcfmri, NULL, NULL,
1690 			    NULL, NULL, prop, 0) == -1) {
1691 				free(svcfmri);
1692 				goto error1;
1693 			}
1694 			free(svcfmri);
1695 			break;
1696 		case SCF_ERROR_CONSTRAINT_VIOLATED:
1697 			(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1698 		default:
1699 			goto error1;
1700 		}
1701 	}
1702 	/*
1703 	 * At this point, we've successfully pulled the property from the
1704 	 * datastore, and simply need to copy its innards into an
1705 	 * scf_simple_prop_t.
1706 	 */
1707 	if ((ret = fill_prop(prop, pgname, propname, h)) == NULL)
1708 		goto error1;
1709 
1710 	scf_service_destroy(svc);
1711 	scf_property_destroy(prop);
1712 	free(fmri_buf);
1713 	if (local_h)
1714 		scf_handle_destroy(h);
1715 	return (ret);
1716 
1717 	/*
1718 	 * Exit point for a successful call.  Below this line are exit points
1719 	 * for failures at various stages during the function.
1720 	 */
1721 
1722 error1:
1723 	scf_service_destroy(svc);
1724 	scf_property_destroy(prop);
1725 error2:
1726 	free(fmri_buf);
1727 	if (local_h)
1728 		scf_handle_destroy(h);
1729 	return (NULL);
1730 }
1731 
1732 
1733 void
1734 scf_simple_prop_free(scf_simple_prop_t *prop)
1735 {
1736 	int i;
1737 
1738 	if (prop == NULL)
1739 		return;
1740 
1741 	free(prop->pr_propname);
1742 	free(prop->pr_pgname);
1743 	switch (prop->pr_type) {
1744 	case SCF_TYPE_OPAQUE: {
1745 		for (i = 0; i < prop->pr_numvalues; i++) {
1746 			free(prop->pr_vallist[i].pv_opaque.o_value);
1747 		}
1748 		break;
1749 	}
1750 	case SCF_TYPE_ASTRING:
1751 	case SCF_TYPE_USTRING:
1752 	case SCF_TYPE_HOST:
1753 	case SCF_TYPE_HOSTNAME:
1754 	case SCF_TYPE_NET_ADDR_V4:
1755 	case SCF_TYPE_NET_ADDR_V6:
1756 	case SCF_TYPE_URI:
1757 	case SCF_TYPE_FMRI: {
1758 		for (i = 0; i < prop->pr_numvalues; i++) {
1759 			free(prop->pr_vallist[i].pv_str);
1760 		}
1761 		break;
1762 	}
1763 	default:
1764 		break;
1765 	}
1766 	free(prop->pr_vallist);
1767 	free(prop);
1768 }
1769 
1770 
1771 scf_simple_app_props_t *
1772 scf_simple_app_props_get(scf_handle_t *hin, const char *inst_fmri)
1773 {
1774 	scf_instance_t 		*inst = NULL;
1775 	scf_service_t 		*svc = NULL;
1776 	scf_propertygroup_t 	*pg = NULL;
1777 	scf_property_t 		*prop = NULL;
1778 	scf_simple_app_props_t	*ret = NULL;
1779 	scf_iter_t		*pgiter = NULL, *propiter = NULL;
1780 	struct scf_simple_pg	*thispg = NULL, *nextpg;
1781 	scf_simple_prop_t	*thisprop, *nextprop;
1782 	scf_handle_t		*h = NULL;
1783 	int			pgiter_ret, propiter_ret;
1784 	ssize_t			namelen;
1785 	char 			*propname = NULL, *pgname = NULL, *sys_fmri;
1786 	uint8_t			found;
1787 	boolean_t		local_h = B_TRUE;
1788 
1789 	/* If the user passed in a handle, use it. */
1790 	if (hin != NULL) {
1791 		h = hin;
1792 		local_h = B_FALSE;
1793 	}
1794 
1795 	if (local_h && ((h = handle_create()) == NULL))
1796 		return (NULL);
1797 
1798 	if (inst_fmri == NULL) {
1799 		if ((namelen = scf_myname(h, NULL, 0)) == -1) {
1800 			if (local_h)
1801 				scf_handle_destroy(h);
1802 			return (NULL);
1803 		}
1804 		if ((sys_fmri = malloc(namelen + 1)) == NULL) {
1805 			if (local_h)
1806 				scf_handle_destroy(h);
1807 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
1808 			return (NULL);
1809 		}
1810 		if (scf_myname(h, sys_fmri, namelen + 1) == -1) {
1811 			if (local_h)
1812 				scf_handle_destroy(h);
1813 			free(sys_fmri);
1814 			return (NULL);
1815 		}
1816 	} else {
1817 		if ((sys_fmri = strdup(inst_fmri)) == NULL) {
1818 			if (local_h)
1819 				scf_handle_destroy(h);
1820 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
1821 			return (NULL);
1822 		}
1823 	}
1824 
1825 	namelen = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
1826 	assert(namelen > 0);
1827 
1828 	if ((inst = scf_instance_create(h)) == NULL ||
1829 	    (svc = scf_service_create(h)) == NULL ||
1830 	    (pgiter = scf_iter_create(h)) == NULL ||
1831 	    (propiter = scf_iter_create(h)) == NULL ||
1832 	    (pg = scf_pg_create(h)) == NULL ||
1833 	    (prop = scf_property_create(h)) == NULL)
1834 		goto error2;
1835 
1836 	if (scf_handle_decode_fmri(h, sys_fmri, NULL, svc, inst, NULL, NULL,
1837 	    SCF_DECODE_FMRI_REQUIRE_INSTANCE) == -1) {
1838 		if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED)
1839 			(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1840 		goto error2;
1841 	}
1842 
1843 	if ((ret = malloc(sizeof (*ret))) == NULL ||
1844 	    (thispg = malloc(sizeof (*thispg))) == NULL ||
1845 	    (propname = malloc(namelen)) == NULL ||
1846 	    (pgname = malloc(namelen)) == NULL) {
1847 		free(thispg);
1848 		free(ret);
1849 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
1850 		goto error2;
1851 	}
1852 
1853 	ret->ap_fmri = sys_fmri;
1854 	thispg->pg_name = NULL;
1855 	thispg->pg_proplist = NULL;
1856 	thispg->pg_next = NULL;
1857 	ret->ap_pglist = thispg;
1858 
1859 	if (scf_iter_service_pgs_typed(pgiter, svc, SCF_GROUP_APPLICATION) !=
1860 	    0) {
1861 		if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
1862 			(void) scf_set_error(SCF_ERROR_INTERNAL);
1863 		goto error1;
1864 	}
1865 
1866 	while ((pgiter_ret = scf_iter_next_pg(pgiter, pg)) == 1) {
1867 		if (thispg->pg_name != NULL) {
1868 			if ((nextpg = malloc(sizeof (*nextpg))) == NULL) {
1869 				(void) scf_set_error(SCF_ERROR_NO_MEMORY);
1870 				goto error1;
1871 			}
1872 			nextpg->pg_name = NULL;
1873 			nextpg->pg_next = NULL;
1874 			nextpg->pg_proplist = NULL;
1875 			thispg->pg_next = nextpg;
1876 			thispg = nextpg;
1877 		} else {
1878 			/* This is the first iteration */
1879 			nextpg = thispg;
1880 		}
1881 
1882 		if ((nextpg->pg_name = malloc(namelen)) == NULL) {
1883 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
1884 			goto error1;
1885 		}
1886 
1887 		if (scf_pg_get_name(pg, nextpg->pg_name, namelen) < 0) {
1888 			if (scf_error() == SCF_ERROR_NOT_SET)
1889 				(void) scf_set_error(SCF_ERROR_INTERNAL);
1890 			goto error1;
1891 		}
1892 
1893 		thisprop = NULL;
1894 
1895 		scf_iter_reset(propiter);
1896 
1897 		if (scf_iter_pg_properties(propiter, pg) != 0) {
1898 			if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
1899 				(void) scf_set_error(SCF_ERROR_INTERNAL);
1900 			goto error1;
1901 		}
1902 
1903 		while ((propiter_ret = scf_iter_next_property(propiter, prop))
1904 		    == 1) {
1905 			if (scf_property_get_name(prop, propname, namelen) <
1906 			    0) {
1907 				if (scf_error() == SCF_ERROR_NOT_SET)
1908 					(void) scf_set_error(
1909 					    SCF_ERROR_INTERNAL);
1910 				goto error1;
1911 			}
1912 			if (thisprop != NULL) {
1913 				if ((nextprop = fill_prop(prop,
1914 				    nextpg->pg_name, propname, h)) == NULL)
1915 					goto error1;
1916 				thisprop->pr_next = nextprop;
1917 				thisprop = nextprop;
1918 			} else {
1919 				/* This is the first iteration */
1920 				if ((thisprop = fill_prop(prop,
1921 				    nextpg->pg_name, propname, h)) == NULL)
1922 					goto error1;
1923 				nextpg->pg_proplist = thisprop;
1924 				nextprop = thisprop;
1925 			}
1926 			nextprop->pr_pg = nextpg;
1927 			nextprop->pr_next = NULL;
1928 		}
1929 
1930 		if (propiter_ret == -1) {
1931 			if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
1932 				(void) scf_set_error(SCF_ERROR_INTERNAL);
1933 			goto error1;
1934 		}
1935 	}
1936 
1937 	if (pgiter_ret == -1) {
1938 		if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
1939 			(void) scf_set_error(SCF_ERROR_INTERNAL);
1940 		goto error1;
1941 	}
1942 
1943 	/*
1944 	 * At this point, we've filled the scf_simple_app_props_t with all the
1945 	 * properties at the service level.  Now we iterate over all the
1946 	 * properties at the instance level, overwriting any duplicate
1947 	 * properties, in order to provide service/instance composition.
1948 	 */
1949 
1950 	scf_iter_reset(pgiter);
1951 	scf_iter_reset(propiter);
1952 
1953 	if (scf_iter_instance_pgs_typed(pgiter, inst, SCF_GROUP_APPLICATION)
1954 	    != 0) {
1955 		if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
1956 			(void) scf_set_error(SCF_ERROR_INTERNAL);
1957 		goto error1;
1958 	}
1959 
1960 	while ((pgiter_ret = scf_iter_next_pg(pgiter, pg)) == 1) {
1961 
1962 		thispg = ret->ap_pglist;
1963 		found = 0;
1964 
1965 		/*
1966 		 * Find either the end of the list, so we can append the
1967 		 * property group, or an existing property group that matches
1968 		 * it, so we can insert/overwrite its properties.
1969 		 */
1970 
1971 		if (scf_pg_get_name(pg, pgname, namelen) < 0) {
1972 			if (scf_error() == SCF_ERROR_NOT_SET)
1973 				(void) scf_set_error(SCF_ERROR_INTERNAL);
1974 			goto error1;
1975 		}
1976 
1977 		while ((thispg != NULL) && (thispg->pg_name != NULL)) {
1978 			if (strcmp(thispg->pg_name, pgname) == 0) {
1979 				found = 1;
1980 				break;
1981 			}
1982 			if (thispg->pg_next == NULL)
1983 				break;
1984 
1985 			thispg = thispg->pg_next;
1986 		}
1987 
1988 		scf_iter_reset(propiter);
1989 
1990 		if (scf_iter_pg_properties(propiter, pg) != 0) {
1991 			if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
1992 				(void) scf_set_error(SCF_ERROR_INTERNAL);
1993 			goto error1;
1994 		}
1995 
1996 		if (found) {
1997 			/*
1998 			 * insert_app_props inserts or overwrites the
1999 			 * properties in thispg.
2000 			 */
2001 
2002 			if (insert_app_props(propiter, pgname, propname,
2003 			    thispg, prop, namelen, h) == -1)
2004 				goto error1;
2005 
2006 		} else {
2007 			/*
2008 			 * If the property group wasn't found, we're adding
2009 			 * a newly allocated property group to the end of the
2010 			 * list.
2011 			 */
2012 
2013 			if ((nextpg = malloc(sizeof (*nextpg))) == NULL) {
2014 				(void) scf_set_error(SCF_ERROR_NO_MEMORY);
2015 				goto error1;
2016 			}
2017 			nextpg->pg_next = NULL;
2018 			nextpg->pg_proplist = NULL;
2019 			thisprop = NULL;
2020 
2021 			if ((nextpg->pg_name = strdup(pgname)) == NULL) {
2022 				(void) scf_set_error(SCF_ERROR_NO_MEMORY);
2023 				free(nextpg);
2024 				goto error1;
2025 			}
2026 
2027 			if (thispg->pg_name == NULL) {
2028 				free(thispg);
2029 				ret->ap_pglist = nextpg;
2030 			} else {
2031 				thispg->pg_next = nextpg;
2032 			}
2033 
2034 			while ((propiter_ret =
2035 			    scf_iter_next_property(propiter, prop)) == 1) {
2036 				if (scf_property_get_name(prop, propname,
2037 				    namelen) < 0) {
2038 					if (scf_error() == SCF_ERROR_NOT_SET)
2039 						(void) scf_set_error(
2040 						    SCF_ERROR_INTERNAL);
2041 					goto error1;
2042 				}
2043 				if (thisprop != NULL) {
2044 					if ((nextprop = fill_prop(prop,
2045 					    pgname, propname, h)) ==
2046 					    NULL)
2047 						goto error1;
2048 					thisprop->pr_next = nextprop;
2049 					thisprop = nextprop;
2050 				} else {
2051 					/* This is the first iteration */
2052 					if ((thisprop = fill_prop(prop,
2053 					    pgname, propname, h)) ==
2054 					    NULL)
2055 						goto error1;
2056 					nextpg->pg_proplist = thisprop;
2057 					nextprop = thisprop;
2058 				}
2059 				nextprop->pr_pg = nextpg;
2060 				nextprop->pr_next = NULL;
2061 			}
2062 
2063 			if (propiter_ret == -1) {
2064 				if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
2065 					(void) scf_set_error(
2066 					    SCF_ERROR_INTERNAL);
2067 				goto error1;
2068 			}
2069 		}
2070 
2071 	}
2072 
2073 	if (pgiter_ret == -1) {
2074 		if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
2075 			(void) scf_set_error(SCF_ERROR_INTERNAL);
2076 		goto error1;
2077 	}
2078 
2079 	scf_iter_destroy(pgiter);
2080 	scf_iter_destroy(propiter);
2081 	scf_pg_destroy(pg);
2082 	scf_property_destroy(prop);
2083 	scf_instance_destroy(inst);
2084 	scf_service_destroy(svc);
2085 	free(propname);
2086 	free(pgname);
2087 	if (local_h)
2088 		scf_handle_destroy(h);
2089 
2090 	if (ret->ap_pglist->pg_name == NULL)
2091 		return (NULL);
2092 
2093 	return (ret);
2094 
2095 	/*
2096 	 * Exit point for a successful call.  Below this line are exit points
2097 	 * for failures at various stages during the function.
2098 	 */
2099 
2100 error1:
2101 	scf_simple_app_props_free(ret);
2102 
2103 error2:
2104 	scf_iter_destroy(pgiter);
2105 	scf_iter_destroy(propiter);
2106 	scf_pg_destroy(pg);
2107 	scf_property_destroy(prop);
2108 	scf_instance_destroy(inst);
2109 	scf_service_destroy(svc);
2110 	free(propname);
2111 	free(pgname);
2112 	if (local_h)
2113 		scf_handle_destroy(h);
2114 	return (NULL);
2115 }
2116 
2117 
2118 void
2119 scf_simple_app_props_free(scf_simple_app_props_t *propblock)
2120 {
2121 	struct scf_simple_pg 	*pgthis, *pgnext;
2122 	scf_simple_prop_t 	*propthis, *propnext;
2123 
2124 	if ((propblock == NULL) || (propblock->ap_pglist == NULL))
2125 		return;
2126 
2127 	for (pgthis = propblock->ap_pglist; pgthis != NULL; pgthis = pgnext) {
2128 		pgnext = pgthis->pg_next;
2129 
2130 		propthis = pgthis->pg_proplist;
2131 
2132 		while (propthis != NULL) {
2133 			propnext = propthis->pr_next;
2134 			scf_simple_prop_free(propthis);
2135 			propthis = propnext;
2136 		}
2137 
2138 		free(pgthis->pg_name);
2139 		free(pgthis);
2140 	}
2141 
2142 	free(propblock->ap_fmri);
2143 	free(propblock);
2144 }
2145 
2146 const scf_simple_prop_t *
2147 scf_simple_app_props_next(const scf_simple_app_props_t *propblock,
2148     scf_simple_prop_t *last)
2149 {
2150 	struct scf_simple_pg 	*this;
2151 
2152 	if (propblock == NULL) {
2153 		(void) scf_set_error(SCF_ERROR_NOT_SET);
2154 		return (NULL);
2155 	}
2156 
2157 	this = propblock->ap_pglist;
2158 
2159 	/*
2160 	 * We're looking for the first property in this block if last is
2161 	 * NULL
2162 	 */
2163 
2164 	if (last == NULL) {
2165 		/* An empty pglist is legal, it just means no properties */
2166 		if (this == NULL) {
2167 			(void) scf_set_error(SCF_ERROR_NONE);
2168 			return (NULL);
2169 		}
2170 		/*
2171 		 * Walk until we find a pg with a property in it, or we run
2172 		 * out of property groups.
2173 		 */
2174 		while ((this->pg_proplist == NULL) && (this->pg_next != NULL))
2175 			this = this->pg_next;
2176 
2177 		if (this->pg_proplist == NULL) {
2178 			(void) scf_set_error(SCF_ERROR_NONE);
2179 			return (NULL);
2180 		}
2181 
2182 		return (this->pg_proplist);
2183 
2184 	}
2185 	/*
2186 	 * If last isn't NULL, then return the next prop in the property group,
2187 	 * or walk the property groups until we find another property, or
2188 	 * run out of property groups.
2189 	 */
2190 	if (last->pr_next != NULL)
2191 		return (last->pr_next);
2192 
2193 	if (last->pr_pg->pg_next == NULL) {
2194 		(void) scf_set_error(SCF_ERROR_NONE);
2195 		return (NULL);
2196 	}
2197 
2198 	this = last->pr_pg->pg_next;
2199 
2200 	while ((this->pg_proplist == NULL) && (this->pg_next != NULL))
2201 		this = this->pg_next;
2202 
2203 	if (this->pg_proplist == NULL) {
2204 		(void) scf_set_error(SCF_ERROR_NONE);
2205 		return (NULL);
2206 	}
2207 
2208 	return (this->pg_proplist);
2209 }
2210 
2211 const scf_simple_prop_t *
2212 scf_simple_app_props_search(const scf_simple_app_props_t *propblock,
2213     const char *pgname, const char *propname)
2214 {
2215 	struct scf_simple_pg 	*pg;
2216 	scf_simple_prop_t 	*prop;
2217 
2218 	if ((propblock == NULL) || (propname == NULL)) {
2219 		(void) scf_set_error(SCF_ERROR_NOT_SET);
2220 		return (NULL);
2221 	}
2222 
2223 	pg = propblock->ap_pglist;
2224 
2225 	/*
2226 	 * If pgname is NULL, we're searching the default application
2227 	 * property group, otherwise we look for the specified group.
2228 	 */
2229 	if (pgname == NULL) {
2230 		while ((pg != NULL) &&
2231 		    (strcmp(SCF_PG_APP_DEFAULT, pg->pg_name) != 0))
2232 			pg = pg->pg_next;
2233 	} else {
2234 		while ((pg != NULL) && (strcmp(pgname, pg->pg_name) != 0))
2235 			pg = pg->pg_next;
2236 	}
2237 
2238 	if (pg == NULL) {
2239 		(void) scf_set_error(SCF_ERROR_NOT_FOUND);
2240 		return (NULL);
2241 	}
2242 
2243 	prop = pg->pg_proplist;
2244 
2245 	while ((prop != NULL) && (strcmp(propname, prop->pr_propname) != 0))
2246 		prop = prop->pr_next;
2247 
2248 	if (prop == NULL) {
2249 		(void) scf_set_error(SCF_ERROR_NOT_FOUND);
2250 		return (NULL);
2251 	}
2252 
2253 	return (prop);
2254 }
2255 
2256 void
2257 scf_simple_prop_next_reset(scf_simple_prop_t *prop)
2258 {
2259 	if (prop == NULL)
2260 		return;
2261 	prop->pr_iter = 0;
2262 }
2263 
2264 ssize_t
2265 scf_simple_prop_numvalues(const scf_simple_prop_t *prop)
2266 {
2267 	if (prop == NULL)
2268 		return (scf_set_error(SCF_ERROR_NOT_SET));
2269 
2270 	return (prop->pr_numvalues);
2271 }
2272 
2273 
2274 scf_type_t
2275 scf_simple_prop_type(const scf_simple_prop_t *prop)
2276 {
2277 	if (prop == NULL)
2278 		return (scf_set_error(SCF_ERROR_NOT_SET));
2279 
2280 	return (prop->pr_type);
2281 }
2282 
2283 
2284 char *
2285 scf_simple_prop_name(const scf_simple_prop_t *prop)
2286 {
2287 	if ((prop == NULL) || (prop->pr_propname == NULL)) {
2288 		(void) scf_set_error(SCF_ERROR_NOT_SET);
2289 		return (NULL);
2290 	}
2291 
2292 	return (prop->pr_propname);
2293 }
2294 
2295 
2296 char *
2297 scf_simple_prop_pgname(const scf_simple_prop_t *prop)
2298 {
2299 	if ((prop == NULL) || (prop->pr_pgname == NULL)) {
2300 		(void) scf_set_error(SCF_ERROR_NOT_SET);
2301 		return (NULL);
2302 	}
2303 
2304 	return (prop->pr_pgname);
2305 }
2306 
2307 
2308 static union scf_simple_prop_val *
2309 scf_next_val(scf_simple_prop_t *prop, scf_type_t type)
2310 {
2311 	if (prop == NULL) {
2312 		(void) scf_set_error(SCF_ERROR_NOT_SET);
2313 		return (NULL);
2314 	}
2315 
2316 	switch (prop->pr_type) {
2317 	case SCF_TYPE_USTRING:
2318 	case SCF_TYPE_HOST:
2319 	case SCF_TYPE_HOSTNAME:
2320 	case SCF_TYPE_NET_ADDR_V4:
2321 	case SCF_TYPE_NET_ADDR_V6:
2322 	case SCF_TYPE_URI:
2323 	case SCF_TYPE_FMRI: {
2324 		if (type != SCF_TYPE_USTRING) {
2325 			(void) scf_set_error(SCF_ERROR_TYPE_MISMATCH);
2326 			return (NULL);
2327 		}
2328 		break;
2329 		}
2330 	default: {
2331 		if (type != prop->pr_type) {
2332 			(void) scf_set_error(SCF_ERROR_TYPE_MISMATCH);
2333 			return (NULL);
2334 		}
2335 		break;
2336 		}
2337 	}
2338 
2339 	if (prop->pr_iter >= prop->pr_numvalues) {
2340 		(void) scf_set_error(SCF_ERROR_NONE);
2341 		return (NULL);
2342 	}
2343 
2344 	return (&prop->pr_vallist[prop->pr_iter++]);
2345 }
2346 
2347 
2348 uint8_t *
2349 scf_simple_prop_next_boolean(scf_simple_prop_t *prop)
2350 {
2351 	union scf_simple_prop_val *ret;
2352 
2353 	ret = scf_next_val(prop, SCF_TYPE_BOOLEAN);
2354 
2355 	if (ret == NULL)
2356 		return (NULL);
2357 
2358 	return (&ret->pv_bool);
2359 }
2360 
2361 
2362 uint64_t *
2363 scf_simple_prop_next_count(scf_simple_prop_t *prop)
2364 {
2365 	union scf_simple_prop_val *ret;
2366 
2367 	ret = scf_next_val(prop, SCF_TYPE_COUNT);
2368 
2369 	if (ret == NULL)
2370 		return (NULL);
2371 
2372 	return (&ret->pv_uint);
2373 }
2374 
2375 
2376 int64_t *
2377 scf_simple_prop_next_integer(scf_simple_prop_t *prop)
2378 {
2379 	union scf_simple_prop_val *ret;
2380 
2381 	ret = scf_next_val(prop, SCF_TYPE_INTEGER);
2382 
2383 	if (ret == NULL)
2384 		return (NULL);
2385 
2386 	return (&ret->pv_int);
2387 }
2388 
2389 int64_t *
2390 scf_simple_prop_next_time(scf_simple_prop_t *prop, int32_t *nsec)
2391 {
2392 	union scf_simple_prop_val *ret;
2393 
2394 	ret = scf_next_val(prop, SCF_TYPE_TIME);
2395 
2396 	if (ret == NULL)
2397 		return (NULL);
2398 
2399 	if (nsec != NULL)
2400 		*nsec = ret->pv_time.t_nsec;
2401 
2402 	return (&ret->pv_time.t_sec);
2403 }
2404 
2405 char *
2406 scf_simple_prop_next_astring(scf_simple_prop_t *prop)
2407 {
2408 	union scf_simple_prop_val *ret;
2409 
2410 	ret = scf_next_val(prop, SCF_TYPE_ASTRING);
2411 
2412 	if (ret == NULL)
2413 		return (NULL);
2414 
2415 	return (ret->pv_str);
2416 }
2417 
2418 char *
2419 scf_simple_prop_next_ustring(scf_simple_prop_t *prop)
2420 {
2421 	union scf_simple_prop_val *ret;
2422 
2423 	ret = scf_next_val(prop, SCF_TYPE_USTRING);
2424 
2425 	if (ret == NULL)
2426 		return (NULL);
2427 
2428 	return (ret->pv_str);
2429 }
2430 
2431 void *
2432 scf_simple_prop_next_opaque(scf_simple_prop_t *prop, size_t *length)
2433 {
2434 	union scf_simple_prop_val *ret;
2435 
2436 	ret = scf_next_val(prop, SCF_TYPE_OPAQUE);
2437 
2438 	if (ret == NULL) {
2439 		*length = 0;
2440 		return (NULL);
2441 	}
2442 
2443 	*length = ret->pv_opaque.o_size;
2444 	return (ret->pv_opaque.o_value);
2445 }
2446 
2447 /*
2448  * Generate a filename based on the fmri and the given name and return
2449  * it in the buffer of MAXPATHLEN provided by the caller.
2450  * If temp_filename is non-zero, also generate a temporary, unique filename
2451  * and return it in the temp buffer of MAXPATHLEN provided by the caller.
2452  * The path to the generated pathname is also created.
2453  * Given fmri should begin with a scheme such as "svc:".
2454  * Returns
2455  *      0 on success
2456  *      -1 if filename would exceed MAXPATHLEN or
2457  *	-2 if unable to create directory to filename path
2458  */
2459 int
2460 gen_filenms_from_fmri(const char *fmri, const char *name, char *filename,
2461     char *temp_filename)
2462 {
2463 	int		len;
2464 
2465 	len = strlen(SMF_SPEEDY_FILES_PATH);
2466 	len += strlen(fmri);
2467 	len += 2;			/* for slash and null */
2468 	len += strlen(name);
2469 	len += 6;			/* For X's needed for mkstemp */
2470 
2471 	if (len > MAXPATHLEN)
2472 		return (-1);
2473 
2474 	/* Construct directory name first - speedy path ends in slash */
2475 	(void) strcpy(filename, SMF_SPEEDY_FILES_PATH);
2476 	(void) strcat(filename, fmri);
2477 	if (mkdirp(filename, 0755) == -1) {
2478 		/* errno is set */
2479 		if (errno != EEXIST)
2480 			return (-2);
2481 	}
2482 
2483 	(void) strcat(filename, "/");
2484 	(void) strcat(filename, name);
2485 
2486 	if (temp_filename) {
2487 		(void) strcpy(temp_filename, filename);
2488 		(void) strcat(temp_filename, "XXXXXX");
2489 	}
2490 
2491 	return (0);
2492 }
2493 
2494 static scf_type_t
2495 scf_true_base_type(scf_type_t type)
2496 {
2497 	scf_type_t base = type;
2498 
2499 	do {
2500 		type = base;
2501 		(void) scf_type_base_type(type, &base);
2502 	} while (base != type);
2503 
2504 	return (base);
2505 }
2506 
2507 /*
2508  * Convenience routine which frees all strings and opaque data
2509  * allocated by scf_read_propvec.
2510  *
2511  * Like free(3C), this function preserves the value of errno.
2512  */
2513 void
2514 scf_clean_propvec(scf_propvec_t *propvec)
2515 {
2516 	int saved_errno = errno;
2517 	scf_propvec_t *prop;
2518 
2519 	for (prop = propvec; prop->pv_prop != NULL; prop++) {
2520 		assert(prop->pv_type != SCF_TYPE_INVALID);
2521 		if (prop->pv_type == SCF_TYPE_OPAQUE) {
2522 			scf_opaque_t *o = prop->pv_ptr;
2523 
2524 			if (o->so_addr != NULL)
2525 				free(o->so_addr);
2526 		} else if (scf_true_base_type(prop->pv_type) ==
2527 		    SCF_TYPE_ASTRING) {
2528 			if (*(char **)prop->pv_ptr != NULL)
2529 				free(*(char **)prop->pv_ptr);
2530 		}
2531 	}
2532 
2533 	errno = saved_errno;
2534 }
2535 
2536 static int
2537 count_props(scf_propvec_t *props)
2538 {
2539 	int count = 0;
2540 
2541 	for (; props->pv_prop != NULL; props++)
2542 		count++;
2543 	return (count);
2544 }
2545 
2546 /*
2547  * Reads a vector of properties from the specified fmri/property group.
2548  * If 'running' is true, reads from the running snapshot instead of the
2549  * editing snapshot.
2550  *
2551  * For string types, a buffer is allocated using malloc(3C) to hold the
2552  * zero-terminated string, a pointer to which is stored in the
2553  * caller-provided char **.  It is the caller's responsbility to free
2554  * this string.  To simplify error handling, unread strings are
2555  * initialized to NULL.
2556  *
2557  * For opaque types, a buffer is allocated using malloc(3C) to hold the
2558  * opaque data.  A pointer to this buffer and its size are stored in
2559  * the caller-provided scf_opaque_t.  It is the caller's responsibility
2560  * to free this buffer.  To simplify error handling, the address fields
2561  * for unread opaque data are initialized to NULL.
2562  *
2563  * All other data is stored directly in caller-provided variables or
2564  * structures.
2565  *
2566  * If this function fails to read a specific property, *badprop is set
2567  * to point at that property's entry in the properties array.
2568  *
2569  * On all failures, all memory allocated by this function is freed.
2570  */
2571 int
2572 scf_read_propvec(const char *fmri, const char *pgname, boolean_t running,
2573     scf_propvec_t *properties, scf_propvec_t **badprop)
2574 {
2575 	scf_handle_t *h = handle_create();
2576 	scf_service_t *s = scf_service_create(h);
2577 	scf_instance_t *i = scf_instance_create(h);
2578 	scf_snapshot_t *snap = running ? scf_snapshot_create(h) : NULL;
2579 	scf_propertygroup_t *pg = scf_pg_create(h);
2580 	scf_property_t *p = scf_property_create(h);
2581 	scf_value_t *v = scf_value_create(h);
2582 	boolean_t instance = B_TRUE;
2583 	scf_propvec_t *prop;
2584 	int error = 0;
2585 
2586 	if (h == NULL || s == NULL || i == NULL || (running && snap == NULL) ||
2587 	    pg == NULL || p == NULL || v == NULL)
2588 		goto scferror;
2589 
2590 	if (scf_handle_decode_fmri(h, fmri, NULL, s, i, NULL, NULL, 0) == -1)
2591 		goto scferror;
2592 
2593 	if (scf_instance_to_fmri(i, NULL, 0) == -1) {
2594 		if (scf_error() != SCF_ERROR_NOT_SET)
2595 			goto scferror;
2596 		instance = B_FALSE;
2597 	}
2598 
2599 	if (running) {
2600 		if (!instance) {
2601 			error = SCF_ERROR_TYPE_MISMATCH;
2602 			goto out;
2603 		}
2604 
2605 		if (scf_instance_get_snapshot(i, "running", snap) !=
2606 		    SCF_SUCCESS)
2607 			goto scferror;
2608 	}
2609 
2610 	if ((instance ? scf_instance_get_pg_composed(i, snap, pgname, pg) :
2611 	    scf_service_get_pg(s, pgname, pg)) == -1)
2612 		goto scferror;
2613 
2614 	for (prop = properties; prop->pv_prop != NULL; prop++) {
2615 		if (prop->pv_type == SCF_TYPE_OPAQUE)
2616 			((scf_opaque_t *)prop->pv_ptr)->so_addr = NULL;
2617 		else if (scf_true_base_type(prop->pv_type) == SCF_TYPE_ASTRING)
2618 			*((char **)prop->pv_ptr) = NULL;
2619 	}
2620 
2621 	for (prop = properties; prop->pv_prop != NULL; prop++) {
2622 		int ret = 0;
2623 
2624 		if (scf_pg_get_property(pg, prop->pv_prop, p) == -1 ||
2625 		    scf_property_get_value(p, v) == -1) {
2626 			*badprop = prop;
2627 			goto scferror;
2628 		}
2629 		switch (prop->pv_type) {
2630 		case SCF_TYPE_BOOLEAN: {
2631 			uint8_t b;
2632 
2633 			ret = scf_value_get_boolean(v, &b);
2634 			if (ret == -1)
2635 				break;
2636 			if (prop->pv_aux != 0) {
2637 				uint64_t *bits = prop->pv_ptr;
2638 				*bits = b ? (*bits | prop->pv_aux) :
2639 				    (*bits & ~prop->pv_aux);
2640 			} else {
2641 				boolean_t *bool = prop->pv_ptr;
2642 				*bool = b ? B_TRUE : B_FALSE;
2643 			}
2644 			break;
2645 		}
2646 		case SCF_TYPE_COUNT:
2647 			ret = scf_value_get_count(v, prop->pv_ptr);
2648 			break;
2649 		case SCF_TYPE_INTEGER:
2650 			ret = scf_value_get_integer(v, prop->pv_ptr);
2651 			break;
2652 		case SCF_TYPE_TIME: {
2653 			scf_time_t *time = prop->pv_ptr;
2654 
2655 			ret = scf_value_get_time(v, &time->t_seconds,
2656 			    &time->t_ns);
2657 			break;
2658 		}
2659 		case SCF_TYPE_OPAQUE: {
2660 			scf_opaque_t *opaque = prop->pv_ptr;
2661 			ssize_t size = scf_value_get_opaque(v, NULL, 0);
2662 
2663 			if (size == -1) {
2664 				*badprop = prop;
2665 				goto scferror;
2666 			}
2667 			if ((opaque->so_addr = malloc(size)) == NULL) {
2668 				error = SCF_ERROR_NO_MEMORY;
2669 				goto out;
2670 			}
2671 			opaque->so_size = size;
2672 			ret = scf_value_get_opaque(v, opaque->so_addr, size);
2673 			break;
2674 		}
2675 		default: {
2676 			char *s;
2677 			ssize_t size;
2678 
2679 			assert(scf_true_base_type(prop->pv_type) ==
2680 			    SCF_TYPE_ASTRING);
2681 
2682 			size = scf_value_get_astring(v, NULL, 0);
2683 			if (size == -1) {
2684 				*badprop = prop;
2685 				goto scferror;
2686 			}
2687 			if ((s = malloc(++size)) == NULL) {
2688 				error = SCF_ERROR_NO_MEMORY;
2689 				goto out;
2690 			}
2691 			ret = scf_value_get_astring(v, s, size);
2692 			*(char **)prop->pv_ptr = s;
2693 		}
2694 
2695 		if (ret == -1) {
2696 			*badprop = prop;
2697 			goto scferror;
2698 		}
2699 
2700 		}
2701 	}
2702 
2703 	goto out;
2704 
2705 scferror:
2706 	error = scf_error();
2707 	scf_clean_propvec(properties);
2708 
2709 out:
2710 	scf_value_destroy(v);
2711 	scf_property_destroy(p);
2712 	scf_pg_destroy(pg);
2713 	scf_snapshot_destroy(snap);
2714 	scf_instance_destroy(i);
2715 	scf_service_destroy(s);
2716 	scf_handle_destroy(h);
2717 
2718 	if (error != 0) {
2719 		(void) scf_set_error(error);
2720 		return (SCF_FAILED);
2721 	}
2722 
2723 	return (SCF_SUCCESS);
2724 }
2725 
2726 /*
2727  * Writes a vector of properties to the specified fmri/property group.
2728  *
2729  * If this function fails to write a specific property, *badprop is set
2730  * to point at that property's entry in the properties array.
2731  *
2732  * One significant difference between this function and the
2733  * scf_read_propvec function is that for string types, pv_ptr is a
2734  * char *, not a char **.  This means that you can't write a propvec
2735  * you just read, but makes other uses (hopefully the majority) simpler.
2736  */
2737 int
2738 scf_write_propvec(const char *fmri, const char *pgname,
2739     scf_propvec_t *properties, scf_propvec_t **badprop)
2740 {
2741 	scf_handle_t *h = handle_create();
2742 	scf_service_t *s = scf_service_create(h);
2743 	scf_instance_t *inst = scf_instance_create(h);
2744 	scf_snapshot_t *snap = scf_snapshot_create(h);
2745 	scf_propertygroup_t *pg = scf_pg_create(h);
2746 	scf_property_t *p = scf_property_create(h);
2747 	scf_transaction_t *tx = scf_transaction_create(h);
2748 	scf_value_t **v = NULL;
2749 	scf_transaction_entry_t **e = NULL;
2750 	boolean_t instance = B_TRUE;
2751 	int i, n;
2752 	scf_propvec_t *prop;
2753 	int error = 0, ret;
2754 
2755 	n = count_props(properties);
2756 	v = calloc(n, sizeof (scf_value_t *));
2757 	e = calloc(n, sizeof (scf_transaction_entry_t *));
2758 
2759 	if (v == NULL || e == NULL) {
2760 		error = SCF_ERROR_NO_MEMORY;
2761 		goto out;
2762 	}
2763 
2764 	if (h == NULL || s == NULL || inst == NULL || pg == NULL || p == NULL ||
2765 	    tx == NULL)
2766 		goto scferror;
2767 
2768 	for (i = 0; i < n; i++) {
2769 		v[i] = scf_value_create(h);
2770 		e[i] = scf_entry_create(h);
2771 		if (v[i] == NULL || e[i] == NULL)
2772 			goto scferror;
2773 	}
2774 
2775 	if (scf_handle_decode_fmri(h, fmri, NULL, s, inst, NULL, NULL, 0)
2776 	    != SCF_SUCCESS)
2777 		goto scferror;
2778 
2779 	if (scf_instance_to_fmri(inst, NULL, 0) == -1) {
2780 		if (scf_error() != SCF_ERROR_NOT_SET)
2781 			goto scferror;
2782 		instance = B_FALSE;
2783 	}
2784 
2785 	if ((instance ? scf_instance_get_pg(inst, pgname, pg) :
2786 	    scf_service_get_pg(s, pgname, pg)) == -1)
2787 		goto scferror;
2788 
2789 top:
2790 	if (scf_transaction_start(tx, pg) == -1)
2791 		goto scferror;
2792 
2793 	for (prop = properties, i = 0; prop->pv_prop != NULL; prop++, i++) {
2794 		ret = scf_transaction_property_change(tx, e[i], prop->pv_prop,
2795 		    prop->pv_type);
2796 		if (ret == -1 && scf_error() == SCF_ERROR_NOT_FOUND)
2797 			ret = scf_transaction_property_new(tx, e[i],
2798 			    prop->pv_prop, prop->pv_type);
2799 
2800 		if (ret == -1) {
2801 			*badprop = prop;
2802 			goto scferror;
2803 		}
2804 
2805 		switch (prop->pv_type) {
2806 		case SCF_TYPE_BOOLEAN: {
2807 			boolean_t b = (prop->pv_aux != 0) ?
2808 			    (*(uint64_t *)prop->pv_ptr & prop->pv_aux) != 0 :
2809 			    *(boolean_t *)prop->pv_ptr;
2810 
2811 			scf_value_set_boolean(v[i], b ? 1 : 0);
2812 			break;
2813 		}
2814 		case SCF_TYPE_COUNT:
2815 			scf_value_set_count(v[i], *(uint64_t *)prop->pv_ptr);
2816 			break;
2817 		case SCF_TYPE_INTEGER:
2818 			scf_value_set_integer(v[i], *(int64_t *)prop->pv_ptr);
2819 			break;
2820 		case SCF_TYPE_TIME: {
2821 			scf_time_t *time = prop->pv_ptr;
2822 
2823 			ret = scf_value_set_time(v[i], time->t_seconds,
2824 			    time->t_ns);
2825 			break;
2826 		}
2827 		case SCF_TYPE_OPAQUE: {
2828 			scf_opaque_t *opaque = prop->pv_ptr;
2829 
2830 			ret = scf_value_set_opaque(v[i], opaque->so_addr,
2831 			    opaque->so_size);
2832 			break;
2833 		}
2834 		case SCF_TYPE_ASTRING:
2835 			ret = scf_value_set_astring(v[i],
2836 			    (const char *)prop->pv_ptr);
2837 			break;
2838 		default:
2839 			ret = scf_value_set_from_string(v[i], prop->pv_type,
2840 			    (const char *)prop->pv_ptr);
2841 		}
2842 
2843 		if (ret == -1 || scf_entry_add_value(e[i], v[i]) == -1) {
2844 			*badprop = prop;
2845 			goto scferror;
2846 		}
2847 	}
2848 
2849 	ret = scf_transaction_commit(tx);
2850 	if (ret == 1)
2851 		goto out;
2852 
2853 	if (ret == 0 && scf_pg_update(pg) != -1) {
2854 		scf_transaction_reset(tx);
2855 		goto top;
2856 	}
2857 
2858 scferror:
2859 	error = scf_error();
2860 
2861 out:
2862 	if (v != NULL) {
2863 		for (i = 0; i < n; i++)
2864 			scf_value_destroy(v[i]);
2865 		free(v);
2866 	}
2867 
2868 	if (e != NULL) {
2869 		for (i = 0; i < n; i++)
2870 			scf_entry_destroy(e[i]);
2871 		free(e);
2872 	}
2873 
2874 	scf_transaction_destroy(tx);
2875 	scf_property_destroy(p);
2876 	scf_pg_destroy(pg);
2877 	scf_snapshot_destroy(snap);
2878 	scf_instance_destroy(inst);
2879 	scf_service_destroy(s);
2880 	scf_handle_destroy(h);
2881 
2882 	if (error != 0) {
2883 		(void) scf_set_error(error);
2884 		return (SCF_FAILED);
2885 	}
2886 
2887 	return (SCF_SUCCESS);
2888 }
2889 
2890 /*
2891  * Returns
2892  *   0 - success
2893  *   ECONNABORTED - repository connection broken
2894  *   ECANCELED - inst was deleted
2895  *   EPERM
2896  *   EACCES
2897  *   EROFS
2898  *   ENOMEM
2899  */
2900 int
2901 scf_instance_delete_prop(scf_instance_t *inst, const char *pgname,
2902     const char *pname)
2903 {
2904 	scf_handle_t *h;
2905 	scf_propertygroup_t *pg;
2906 	scf_transaction_t *tx;
2907 	scf_transaction_entry_t *e;
2908 	int error = 0, ret = 1, r;
2909 
2910 	h = scf_instance_handle(inst);
2911 
2912 	if ((pg = scf_pg_create(h)) == NULL) {
2913 		return (ENOMEM);
2914 	}
2915 
2916 	if (scf_instance_get_pg(inst, pgname, pg) != 0) {
2917 		error = scf_error();
2918 		scf_pg_destroy(pg);
2919 		switch (error) {
2920 		case SCF_ERROR_NOT_FOUND:
2921 			return (SCF_SUCCESS);
2922 
2923 		case SCF_ERROR_DELETED:
2924 			return (ECANCELED);
2925 
2926 		case SCF_ERROR_CONNECTION_BROKEN:
2927 		default:
2928 			return (ECONNABORTED);
2929 
2930 		case SCF_ERROR_NOT_SET:
2931 			bad_error("scf_instance_get_pg", scf_error());
2932 		}
2933 	}
2934 
2935 	tx = scf_transaction_create(h);
2936 	e = scf_entry_create(h);
2937 	if (tx == NULL || e == NULL) {
2938 		ret = ENOMEM;
2939 		goto out;
2940 	}
2941 
2942 	for (;;) {
2943 		if (scf_transaction_start(tx, pg) != 0) {
2944 			goto scferror;
2945 		}
2946 
2947 		if (scf_transaction_property_delete(tx, e, pname) != 0) {
2948 			goto scferror;
2949 		}
2950 
2951 		if ((r = scf_transaction_commit(tx)) == 1) {
2952 			ret = 0;
2953 			goto out;
2954 		}
2955 
2956 		if (r == -1) {
2957 			goto scferror;
2958 		}
2959 
2960 		scf_transaction_reset(tx);
2961 		if (scf_pg_update(pg) == -1) {
2962 			goto scferror;
2963 		}
2964 	}
2965 
2966 scferror:
2967 	switch (scf_error()) {
2968 	case SCF_ERROR_DELETED:
2969 	case SCF_ERROR_NOT_FOUND:
2970 		ret = 0;
2971 		break;
2972 
2973 	case SCF_ERROR_PERMISSION_DENIED:
2974 		ret = EPERM;
2975 		break;
2976 
2977 	case SCF_ERROR_BACKEND_ACCESS:
2978 		ret = EACCES;
2979 		break;
2980 
2981 	case SCF_ERROR_BACKEND_READONLY:
2982 		ret = EROFS;
2983 		break;
2984 
2985 	case SCF_ERROR_CONNECTION_BROKEN:
2986 	default:
2987 		ret = ECONNABORTED;
2988 		break;
2989 
2990 	case SCF_ERROR_HANDLE_MISMATCH:
2991 	case SCF_ERROR_INVALID_ARGUMENT:
2992 	case SCF_ERROR_NOT_BOUND:
2993 	case SCF_ERROR_NOT_SET:
2994 		bad_error("scf_instance_delete_prop", scf_error());
2995 	}
2996 
2997 out:
2998 	scf_transaction_destroy(tx);
2999 	scf_entry_destroy(e);
3000 	scf_pg_destroy(pg);
3001 
3002 	return (ret);
3003 }
3004