xref: /illumos-gate/usr/src/lib/libscf/common/midlevel.c (revision fee38f6fd6a6fbebea04db28cf9e4d351fb48311)
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  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include "libscf_impl.h"
29 
30 #include <libuutil.h>
31 #include <stdio.h>
32 #include <strings.h>
33 #include <string.h>
34 #include <stdlib.h>
35 #include <sys/param.h>
36 #include <errno.h>
37 #include <libgen.h>
38 #include "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 		if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
307 			(void) scf_set_error(SCF_ERROR_INTERNAL);
308 		goto error1;
309 	}
310 
311 	ret->pr_vallist = vallist;
312 	ret->pr_numvalues = numvals;
313 
314 	scf_iter_destroy(iter);
315 	(void) scf_value_destroy(val);
316 
317 	return (ret);
318 
319 	/*
320 	 * Exit point for a successful call.  Below this line are exit points
321 	 * for failures at various stages during the function.
322 	 */
323 
324 error1:
325 	if (vallist == NULL)
326 		goto error2;
327 
328 	switch (ret->pr_type) {
329 	case SCF_TYPE_ASTRING:
330 	case SCF_TYPE_USTRING:
331 	case SCF_TYPE_HOST:
332 	case SCF_TYPE_HOSTNAME:
333 	case SCF_TYPE_NET_ADDR_V4:
334 	case SCF_TYPE_NET_ADDR_V6:
335 	case SCF_TYPE_URI:
336 	case SCF_TYPE_FMRI: {
337 		for (i = 0; i < numvals; i++) {
338 			free(vallist[i].pv_str);
339 		}
340 		break;
341 	}
342 	case SCF_TYPE_OPAQUE: {
343 		for (i = 0; i < numvals; i++) {
344 			free(vallist[i].pv_opaque.o_value);
345 		}
346 		break;
347 	}
348 	default:
349 		break;
350 	}
351 
352 	free(vallist);
353 
354 error2:
355 	scf_iter_destroy(iter);
356 	(void) scf_value_destroy(val);
357 
358 error3:
359 	free(ret->pr_pgname);
360 	free(ret->pr_propname);
361 	free(ret);
362 	return (NULL);
363 }
364 
365 /*
366  * insert_app_props iterates over a property iterator, getting all the
367  * properties from a property group, and adding or overwriting them into
368  * a simple_app_props_t.  This is used by scf_simple_app_props_get to provide
369  * service/instance composition while filling the app_props_t.
370  * insert_app_props iterates over a single property group.
371  */
372 
373 static int
374 insert_app_props(scf_iter_t *propiter, char *pgname, char *propname, struct
375     scf_simple_pg *thispg, scf_property_t *prop, size_t namelen,
376     scf_handle_t *h)
377 {
378 	scf_simple_prop_t	*thisprop, *prevprop, *newprop;
379 	uint8_t			found;
380 	int			propiter_ret;
381 
382 	while ((propiter_ret = scf_iter_next_property(propiter, prop)) == 1) {
383 
384 		if (scf_property_get_name(prop, propname, namelen) < 0) {
385 			if (scf_error() == SCF_ERROR_NOT_SET)
386 				(void) scf_set_error(SCF_ERROR_INTERNAL);
387 			return (-1);
388 		}
389 
390 		thisprop = thispg->pg_proplist;
391 		prevprop = thispg->pg_proplist;
392 		found = 0;
393 
394 		while ((thisprop != NULL) && (!found)) {
395 			if (strcmp(thisprop->pr_propname, propname) == 0) {
396 				found = 1;
397 				if ((newprop = fill_prop(prop, pgname,
398 				    propname, h)) == NULL)
399 					return (-1);
400 
401 				if (thisprop == thispg->pg_proplist)
402 					thispg->pg_proplist = newprop;
403 				else
404 					prevprop->pr_next = newprop;
405 
406 				newprop->pr_pg = thispg;
407 				newprop->pr_next = thisprop->pr_next;
408 				scf_simple_prop_free(thisprop);
409 				thisprop = NULL;
410 			} else {
411 				if (thisprop != thispg->pg_proplist)
412 					prevprop = prevprop->pr_next;
413 				thisprop = thisprop->pr_next;
414 			}
415 		}
416 
417 		if (!found) {
418 			if ((newprop = fill_prop(prop, pgname, propname, h)) ==
419 			    NULL)
420 				return (-1);
421 
422 			if (thispg->pg_proplist == NULL)
423 				thispg->pg_proplist = newprop;
424 			else
425 				prevprop->pr_next = newprop;
426 
427 			newprop->pr_pg = thispg;
428 		}
429 	}
430 
431 	if (propiter_ret == -1) {
432 		if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
433 			(void) scf_set_error(SCF_ERROR_INTERNAL);
434 		return (-1);
435 	}
436 
437 	return (0);
438 }
439 
440 
441 /*
442  * Sets up e in tx to set pname's values.  Returns 0 on success or -1 on
443  * failure, with scf_error() set to
444  *   SCF_ERROR_HANDLE_MISMATCH - tx & e are derived from different handles
445  *   SCF_ERROR_INVALID_ARGUMENT - pname or ty are invalid
446  *   SCF_ERROR_NOT_BOUND - handle is not bound
447  *   SCF_ERROR_CONNECTION_BROKEN - connection was broken
448  *   SCF_ERROR_NOT_SET - tx has not been started
449  *   SCF_ERROR_DELETED - the pg tx was started on was deleted
450  */
451 static int
452 transaction_property_set(scf_transaction_t *tx, scf_transaction_entry_t *e,
453     const char *pname, scf_type_t ty)
454 {
455 	for (;;) {
456 		if (scf_transaction_property_change_type(tx, e, pname, ty) == 0)
457 			return (0);
458 
459 		switch (scf_error()) {
460 		case SCF_ERROR_HANDLE_MISMATCH:
461 		case SCF_ERROR_INVALID_ARGUMENT:
462 		case SCF_ERROR_NOT_BOUND:
463 		case SCF_ERROR_CONNECTION_BROKEN:
464 		case SCF_ERROR_NOT_SET:
465 		case SCF_ERROR_DELETED:
466 		default:
467 			return (-1);
468 
469 		case SCF_ERROR_NOT_FOUND:
470 			break;
471 		}
472 
473 		if (scf_transaction_property_new(tx, e, pname, ty) == 0)
474 			return (0);
475 
476 		switch (scf_error()) {
477 		case SCF_ERROR_HANDLE_MISMATCH:
478 		case SCF_ERROR_INVALID_ARGUMENT:
479 		case SCF_ERROR_NOT_BOUND:
480 		case SCF_ERROR_CONNECTION_BROKEN:
481 		case SCF_ERROR_NOT_SET:
482 		case SCF_ERROR_DELETED:
483 		default:
484 			return (-1);
485 
486 		case SCF_ERROR_EXISTS:
487 			break;
488 		}
489 	}
490 }
491 
492 static int
493 get_inst_enabled(const scf_instance_t *inst, const char *pgname)
494 {
495 	scf_propertygroup_t 	*gpg = NULL;
496 	scf_property_t 		*eprop = NULL;
497 	scf_value_t 		*v = NULL;
498 	scf_handle_t		*h = NULL;
499 	uint8_t			enabled;
500 	int			ret = -1;
501 
502 	if ((h = scf_instance_handle(inst)) == NULL)
503 		return (-1);
504 
505 	if ((gpg = scf_pg_create(h)) == NULL ||
506 	    (eprop = scf_property_create(h)) == NULL ||
507 	    (v = scf_value_create(h)) == NULL)
508 		goto out;
509 
510 	if (scf_instance_get_pg(inst, pgname, gpg) ||
511 	    scf_pg_get_property(gpg, SCF_PROPERTY_ENABLED, eprop) ||
512 	    scf_property_get_value(eprop, v) ||
513 	    scf_value_get_boolean(v, &enabled))
514 		goto out;
515 	ret = enabled;
516 
517 out:
518 	scf_pg_destroy(gpg);
519 	scf_property_destroy(eprop);
520 	scf_value_destroy(v);
521 	return (ret);
522 }
523 
524 /*
525  * set_inst_enabled() is a "master" enable/disable call that takes the
526  * instance and the desired state for the enabled bit in the instance's
527  * named property group.  If the group doesn't exist, it's created with the
528  * given flags.  Called by smf_{dis,en}able_instance().
529  */
530 static int
531 set_inst_enabled(const scf_instance_t *inst, uint8_t desired,
532     const char *pgname, uint32_t pgflags)
533 {
534 	scf_transaction_t 	*tx = NULL;
535 	scf_transaction_entry_t *ent = NULL;
536 	scf_propertygroup_t 	*gpg = NULL;
537 	scf_property_t 		*eprop = NULL;
538 	scf_value_t 		*v = NULL;
539 	scf_handle_t		*h = NULL;
540 	int 			ret = -1;
541 	int			committed;
542 	uint8_t			b;
543 
544 	if ((h = scf_instance_handle(inst)) == NULL)
545 		return (-1);
546 
547 	if ((gpg = scf_pg_create(h)) == NULL ||
548 	    (eprop = scf_property_create(h)) == NULL ||
549 	    (v = scf_value_create(h)) == NULL ||
550 	    (tx = scf_transaction_create(h)) == NULL ||
551 	    (ent = scf_entry_create(h)) == NULL)
552 		goto out;
553 
554 general_pg_get:
555 	if (scf_instance_get_pg(inst, SCF_PG_GENERAL, gpg) == -1) {
556 		if (scf_error() != SCF_ERROR_NOT_FOUND)
557 			goto out;
558 
559 		if (scf_instance_add_pg(inst, SCF_PG_GENERAL,
560 		    SCF_GROUP_FRAMEWORK, SCF_PG_GENERAL_FLAGS, gpg) == -1) {
561 			if (scf_error() != SCF_ERROR_EXISTS)
562 				goto out;
563 			goto general_pg_get;
564 		}
565 	}
566 
567 	if (strcmp(pgname, SCF_PG_GENERAL) != 0) {
568 get:
569 		if (scf_instance_get_pg(inst, pgname, gpg) == -1) {
570 			if (scf_error() != SCF_ERROR_NOT_FOUND)
571 				goto out;
572 
573 			if (scf_instance_add_pg(inst, pgname,
574 			    SCF_GROUP_FRAMEWORK, pgflags, gpg) == -1) {
575 				if (scf_error() != SCF_ERROR_EXISTS)
576 					goto out;
577 				goto get;
578 			}
579 		}
580 	}
581 
582 	if (scf_pg_get_property(gpg, SCF_PROPERTY_ENABLED, eprop) == -1) {
583 		if (scf_error() != SCF_ERROR_NOT_FOUND)
584 			goto out;
585 		else
586 			goto set;
587 	}
588 
589 	/*
590 	 * If it's already set the way we want, forgo the transaction.
591 	 */
592 	if (scf_property_get_value(eprop, v) == -1) {
593 		switch (scf_error()) {
594 		case SCF_ERROR_CONSTRAINT_VIOLATED:
595 		case SCF_ERROR_NOT_FOUND:
596 			/* Misconfigured, so set anyway. */
597 			goto set;
598 
599 		default:
600 			goto out;
601 		}
602 	}
603 	if (scf_value_get_boolean(v, &b) == -1) {
604 		if (scf_error() != SCF_ERROR_TYPE_MISMATCH)
605 			goto out;
606 		goto set;
607 	}
608 	if (b == desired) {
609 		ret = 0;
610 		goto out;
611 	}
612 
613 set:
614 	do {
615 		if (scf_transaction_start(tx, gpg) == -1)
616 			goto out;
617 
618 		if (transaction_property_set(tx, ent, SCF_PROPERTY_ENABLED,
619 		    SCF_TYPE_BOOLEAN) != 0) {
620 			switch (scf_error()) {
621 			case SCF_ERROR_CONNECTION_BROKEN:
622 			case SCF_ERROR_DELETED:
623 			default:
624 				goto out;
625 
626 			case SCF_ERROR_HANDLE_MISMATCH:
627 			case SCF_ERROR_INVALID_ARGUMENT:
628 			case SCF_ERROR_NOT_BOUND:
629 			case SCF_ERROR_NOT_SET:
630 				bad_error("transaction_property_set",
631 				    scf_error());
632 			}
633 		}
634 
635 		scf_value_set_boolean(v, desired);
636 		if (scf_entry_add_value(ent, v) == -1)
637 			goto out;
638 
639 		committed = scf_transaction_commit(tx);
640 		if (committed == -1)
641 			goto out;
642 
643 		scf_transaction_reset(tx);
644 
645 		if (committed == 0) { /* out-of-sync */
646 			if (scf_pg_update(gpg) == -1)
647 				goto out;
648 		}
649 	} while (committed == 0);
650 
651 	ret = 0;
652 
653 out:
654 	scf_value_destroy(v);
655 	scf_entry_destroy(ent);
656 	scf_transaction_destroy(tx);
657 	scf_property_destroy(eprop);
658 	scf_pg_destroy(gpg);
659 
660 	return (ret);
661 }
662 
663 static int
664 delete_inst_enabled(const scf_instance_t *inst, const char *pgname)
665 {
666 	scf_transaction_t 	*tx = NULL;
667 	scf_transaction_entry_t *ent = NULL;
668 	scf_propertygroup_t 	*gpg = NULL;
669 	scf_handle_t		*h = NULL;
670 	int			ret = -1;
671 	int			committed;
672 
673 	if ((h = scf_instance_handle(inst)) == NULL)
674 		return (-1);
675 
676 	if ((gpg = scf_pg_create(h)) == NULL ||
677 	    (tx = scf_transaction_create(h)) == NULL ||
678 	    (ent = scf_entry_create(h)) == NULL)
679 		goto out;
680 
681 	if (scf_instance_get_pg(inst, pgname, gpg) != 0)
682 		goto error;
683 	do {
684 		if (scf_transaction_start(tx, gpg) == -1 ||
685 		    scf_transaction_property_delete(tx, ent,
686 		    SCF_PROPERTY_ENABLED) == -1 ||
687 		    (committed = scf_transaction_commit(tx)) == -1)
688 			goto error;
689 
690 		scf_transaction_reset(tx);
691 
692 		if (committed == 0 && scf_pg_update(gpg) == -1)
693 			goto error;
694 	} while (committed == 0);
695 
696 	ret = 0;
697 	goto out;
698 
699 error:
700 	switch (scf_error()) {
701 	case SCF_ERROR_DELETED:
702 	case SCF_ERROR_NOT_FOUND:
703 		/* success */
704 		ret = 0;
705 	}
706 
707 out:
708 	scf_entry_destroy(ent);
709 	scf_transaction_destroy(tx);
710 	scf_pg_destroy(gpg);
711 
712 	return (ret);
713 }
714 
715 /*
716  * Returns 0 on success or -1 on failure.  On failure leaves scf_error() set to
717  *   SCF_ERROR_HANDLE_DESTROYED - inst's handle has been destroyed
718  *   SCF_ERROR_NOT_BOUND - inst's handle is not bound
719  *   SCF_ERROR_CONNECTION_BROKEN - the repository connection was broken
720  *   SCF_ERROR_NOT_SET - inst is not set
721  *   SCF_ERROR_DELETED - inst was deleted
722  *   SCF_ERROR_PERMISSION_DENIED
723  *   SCF_ERROR_BACKEND_ACCESS
724  *   SCF_ERROR_BACKEND_READONLY
725  */
726 static int
727 set_inst_action_inst(scf_instance_t *inst, const char *action)
728 {
729 	scf_handle_t			*h;
730 	scf_transaction_t		*tx = NULL;
731 	scf_transaction_entry_t		*ent = NULL;
732 	scf_propertygroup_t		*pg = NULL;
733 	scf_property_t			*prop = NULL;
734 	scf_value_t			*v = NULL;
735 	int				trans, ret = -1;
736 	int64_t				t;
737 	hrtime_t			timestamp;
738 
739 	if ((h = scf_instance_handle(inst)) == NULL ||
740 	    (pg = scf_pg_create(h)) == NULL ||
741 	    (prop = scf_property_create(h)) == NULL ||
742 	    (v = scf_value_create(h)) == NULL ||
743 	    (tx = scf_transaction_create(h)) == NULL ||
744 	    (ent = scf_entry_create(h)) == NULL)
745 		goto out;
746 
747 get:
748 	if (scf_instance_get_pg(inst, SCF_PG_RESTARTER_ACTIONS, pg) == -1) {
749 		switch (scf_error()) {
750 		case SCF_ERROR_NOT_BOUND:
751 		case SCF_ERROR_CONNECTION_BROKEN:
752 		case SCF_ERROR_NOT_SET:
753 		case SCF_ERROR_DELETED:
754 		default:
755 			goto out;
756 
757 		case SCF_ERROR_NOT_FOUND:
758 			break;
759 
760 		case SCF_ERROR_HANDLE_MISMATCH:
761 		case SCF_ERROR_INVALID_ARGUMENT:
762 			bad_error("scf_instance_get_pg", scf_error());
763 		}
764 
765 		/* Try creating the restarter_actions property group. */
766 add:
767 		if (scf_instance_add_pg(inst, SCF_PG_RESTARTER_ACTIONS,
768 		    SCF_PG_RESTARTER_ACTIONS_TYPE,
769 		    SCF_PG_RESTARTER_ACTIONS_FLAGS, pg) == -1) {
770 			switch (scf_error()) {
771 			case SCF_ERROR_NOT_BOUND:
772 			case SCF_ERROR_CONNECTION_BROKEN:
773 			case SCF_ERROR_NOT_SET:
774 			case SCF_ERROR_DELETED:
775 			case SCF_ERROR_PERMISSION_DENIED:
776 			case SCF_ERROR_BACKEND_ACCESS:
777 			case SCF_ERROR_BACKEND_READONLY:
778 			default:
779 				goto out;
780 
781 			case SCF_ERROR_EXISTS:
782 				goto get;
783 
784 			case SCF_ERROR_HANDLE_MISMATCH:
785 			case SCF_ERROR_INVALID_ARGUMENT:
786 				bad_error("scf_instance_add_pg", scf_error());
787 			}
788 		}
789 	}
790 
791 	for (;;) {
792 		timestamp = gethrtime();
793 
794 		if (scf_pg_get_property(pg, action, prop) != 0) {
795 			switch (scf_error()) {
796 			case SCF_ERROR_CONNECTION_BROKEN:
797 			default:
798 				goto out;
799 
800 			case SCF_ERROR_DELETED:
801 				goto add;
802 
803 			case SCF_ERROR_NOT_FOUND:
804 				break;
805 
806 			case SCF_ERROR_HANDLE_MISMATCH:
807 			case SCF_ERROR_INVALID_ARGUMENT:
808 			case SCF_ERROR_NOT_BOUND:
809 			case SCF_ERROR_NOT_SET:
810 				bad_error("scf_pg_get_property", scf_error());
811 			}
812 		} else if (scf_property_get_value(prop, v) != 0) {
813 			switch (scf_error()) {
814 			case SCF_ERROR_CONNECTION_BROKEN:
815 			default:
816 				goto out;
817 
818 			case SCF_ERROR_DELETED:
819 				goto add;
820 
821 			case SCF_ERROR_CONSTRAINT_VIOLATED:
822 			case SCF_ERROR_NOT_FOUND:
823 				break;
824 
825 			case SCF_ERROR_HANDLE_MISMATCH:
826 			case SCF_ERROR_NOT_BOUND:
827 			case SCF_ERROR_NOT_SET:
828 				bad_error("scf_property_get_value",
829 				    scf_error());
830 			}
831 		} else if (scf_value_get_integer(v, &t) != 0) {
832 			bad_error("scf_value_get_integer", scf_error());
833 		} else if (t > timestamp) {
834 			break;
835 		}
836 
837 		if (scf_transaction_start(tx, pg) == -1) {
838 			switch (scf_error()) {
839 			case SCF_ERROR_NOT_BOUND:
840 			case SCF_ERROR_CONNECTION_BROKEN:
841 			case SCF_ERROR_PERMISSION_DENIED:
842 			case SCF_ERROR_BACKEND_ACCESS:
843 			case SCF_ERROR_BACKEND_READONLY:
844 			default:
845 				goto out;
846 
847 			case SCF_ERROR_DELETED:
848 				goto add;
849 
850 			case SCF_ERROR_HANDLE_MISMATCH:
851 			case SCF_ERROR_NOT_SET:
852 			case SCF_ERROR_IN_USE:
853 				bad_error("scf_transaction_start", scf_error());
854 			}
855 		}
856 
857 		if (transaction_property_set(tx, ent, action,
858 		    SCF_TYPE_INTEGER) != 0) {
859 			switch (scf_error()) {
860 			case SCF_ERROR_NOT_BOUND:
861 			case SCF_ERROR_CONNECTION_BROKEN:
862 			case SCF_ERROR_DELETED:
863 			default:
864 				goto out;
865 
866 			case SCF_ERROR_HANDLE_MISMATCH:
867 			case SCF_ERROR_INVALID_ARGUMENT:
868 			case SCF_ERROR_NOT_SET:
869 				bad_error("transaction_property_set",
870 				    scf_error());
871 			}
872 		}
873 
874 		scf_value_set_integer(v, timestamp);
875 		if (scf_entry_add_value(ent, v) == -1)
876 			bad_error("scf_entry_add_value", scf_error());
877 
878 		trans = scf_transaction_commit(tx);
879 		if (trans == 1)
880 			break;
881 
882 		if (trans != 0) {
883 			switch (scf_error()) {
884 			case SCF_ERROR_CONNECTION_BROKEN:
885 			case SCF_ERROR_PERMISSION_DENIED:
886 			case SCF_ERROR_BACKEND_ACCESS:
887 			case SCF_ERROR_BACKEND_READONLY:
888 			default:
889 				goto out;
890 
891 			case SCF_ERROR_DELETED:
892 				scf_transaction_reset(tx);
893 				goto add;
894 
895 			case SCF_ERROR_INVALID_ARGUMENT:
896 			case SCF_ERROR_NOT_BOUND:
897 			case SCF_ERROR_NOT_SET:
898 				bad_error("scf_transaction_commit",
899 				    scf_error());
900 			}
901 		}
902 
903 		scf_transaction_reset(tx);
904 		if (scf_pg_update(pg) != 0) {
905 			switch (scf_error()) {
906 			case SCF_ERROR_CONNECTION_BROKEN:
907 			default:
908 				goto out;
909 
910 			case SCF_ERROR_DELETED:
911 				goto add;
912 
913 			case SCF_ERROR_NOT_SET:
914 			case SCF_ERROR_NOT_BOUND:
915 				bad_error("scf_pg_update", scf_error());
916 			}
917 		}
918 	}
919 
920 	ret = 0;
921 
922 out:
923 	scf_value_destroy(v);
924 	scf_entry_destroy(ent);
925 	scf_transaction_destroy(tx);
926 	scf_property_destroy(prop);
927 	scf_pg_destroy(pg);
928 	return (ret);
929 }
930 
931 static int
932 set_inst_action(const char *fmri, const char *action)
933 {
934 	scf_handle_t *h;
935 	scf_instance_t *inst;
936 	int ret = -1;
937 
938 	h = handle_create();
939 	if (h == NULL)
940 		return (-1);
941 
942 	inst = scf_instance_create(h);
943 
944 	if (inst != NULL) {
945 		if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
946 		    NULL, SCF_DECODE_FMRI_EXACT) == 0)
947 			ret = set_inst_action_inst(inst, action);
948 		else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED)
949 			(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
950 
951 		scf_instance_destroy(inst);
952 	}
953 
954 	scf_handle_destroy(h);
955 
956 	return (ret);
957 }
958 
959 
960 /*
961  * get_inst_state() gets the state string from an instance, and returns
962  * the SCF_STATE_* constant that coincides with the instance's current state.
963  */
964 
965 static int
966 get_inst_state(scf_instance_t *inst, scf_handle_t *h)
967 {
968 	scf_propertygroup_t	*pg = NULL;
969 	scf_property_t		*prop = NULL;
970 	scf_value_t		*val = NULL;
971 	char			state[MAX_SCF_STATE_STRING_SZ];
972 	int			ret = -1;
973 
974 	if (((pg = scf_pg_create(h)) == NULL) ||
975 	    ((prop = scf_property_create(h)) == NULL) ||
976 	    ((val = scf_value_create(h)) == NULL))
977 		goto out;
978 
979 	/* Pull the state property from the instance */
980 
981 	if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) == -1 ||
982 	    scf_pg_get_property(pg, SCF_PROPERTY_STATE, prop) == -1 ||
983 	    scf_property_get_value(prop, val) == -1) {
984 		if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
985 			(void) scf_set_error(SCF_ERROR_INTERNAL);
986 		goto out;
987 	}
988 
989 	if (scf_value_get_astring(val, state, sizeof (state)) <= 0) {
990 		(void) scf_set_error(SCF_ERROR_INTERNAL);
991 		goto out;
992 	}
993 
994 	if (strcmp(state, SCF_STATE_STRING_UNINIT) == 0) {
995 		ret = SCF_STATE_UNINIT;
996 	} else if (strcmp(state, SCF_STATE_STRING_MAINT) == 0) {
997 		ret = SCF_STATE_MAINT;
998 	} else if (strcmp(state, SCF_STATE_STRING_OFFLINE) == 0) {
999 		ret = SCF_STATE_OFFLINE;
1000 	} else if (strcmp(state, SCF_STATE_STRING_DISABLED) == 0) {
1001 		ret = SCF_STATE_DISABLED;
1002 	} else if (strcmp(state, SCF_STATE_STRING_ONLINE) == 0) {
1003 		ret = SCF_STATE_ONLINE;
1004 	} else if (strcmp(state, SCF_STATE_STRING_DEGRADED) == 0) {
1005 		ret = SCF_STATE_DEGRADED;
1006 	}
1007 
1008 out:
1009 	scf_pg_destroy(pg);
1010 	scf_property_destroy(prop);
1011 	(void) scf_value_destroy(val);
1012 
1013 	return (ret);
1014 }
1015 
1016 /*
1017  * Sets an instance to be enabled or disabled after reboot, using the
1018  * temporary (overriding) general_ovr property group to reflect the
1019  * present state, if it is different.
1020  */
1021 static int
1022 set_inst_enabled_atboot(scf_instance_t *inst, uint8_t desired)
1023 {
1024 	int enabled;
1025 	int persistent;
1026 	int ret = -1;
1027 
1028 	if ((persistent = get_inst_enabled(inst, SCF_PG_GENERAL)) < 0) {
1029 		if (scf_error() != SCF_ERROR_NOT_FOUND)
1030 			goto out;
1031 		persistent = B_FALSE;
1032 	}
1033 	if ((enabled = get_inst_enabled(inst, SCF_PG_GENERAL_OVR)) < 0) {
1034 		enabled = persistent;
1035 		if (persistent != desired) {
1036 			/*
1037 			 * Temporarily store the present enabled state.
1038 			 */
1039 			if (set_inst_enabled(inst, persistent,
1040 			    SCF_PG_GENERAL_OVR, SCF_PG_GENERAL_OVR_FLAGS))
1041 				goto out;
1042 		}
1043 	}
1044 	if (persistent != desired)
1045 		if (set_inst_enabled(inst, desired, SCF_PG_GENERAL,
1046 		    SCF_PG_GENERAL_FLAGS))
1047 			goto out;
1048 	if (enabled == desired)
1049 		ret = delete_inst_enabled(inst, SCF_PG_GENERAL_OVR);
1050 	else
1051 		ret = 0;
1052 
1053 out:
1054 	return (ret);
1055 }
1056 
1057 static int
1058 set_inst_enabled_flags(const char *fmri, int flags, uint8_t desired)
1059 {
1060 	int ret = -1;
1061 	scf_handle_t *h;
1062 	scf_instance_t *inst;
1063 
1064 	if (flags & ~(SMF_TEMPORARY | SMF_AT_NEXT_BOOT) ||
1065 	    flags & SMF_TEMPORARY && flags & SMF_AT_NEXT_BOOT) {
1066 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1067 		return (ret);
1068 	}
1069 
1070 	if ((h = handle_create()) == NULL)
1071 		return (ret);
1072 
1073 	if ((inst = scf_instance_create(h)) == NULL) {
1074 		scf_handle_destroy(h);
1075 		return (ret);
1076 	}
1077 
1078 	if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL, NULL,
1079 	    SCF_DECODE_FMRI_EXACT) == -1) {
1080 		if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED)
1081 			(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1082 		goto out;
1083 	}
1084 
1085 	if (flags & SMF_AT_NEXT_BOOT) {
1086 		ret = set_inst_enabled_atboot(inst, desired);
1087 	} else {
1088 		if (set_inst_enabled(inst, desired, flags & SMF_TEMPORARY ?
1089 		    SCF_PG_GENERAL_OVR : SCF_PG_GENERAL, flags & SMF_TEMPORARY ?
1090 		    SCF_PG_GENERAL_OVR_FLAGS : SCF_PG_GENERAL_FLAGS))
1091 			goto out;
1092 
1093 		/*
1094 		 * Make the persistent value effective by deleting the
1095 		 * temporary one.
1096 		 */
1097 		if (flags & SMF_TEMPORARY)
1098 			ret = 0;
1099 		else
1100 			ret = delete_inst_enabled(inst, SCF_PG_GENERAL_OVR);
1101 	}
1102 
1103 out:
1104 	scf_instance_destroy(inst);
1105 	scf_handle_destroy(h);
1106 	return (ret);
1107 }
1108 
1109 /*
1110  * Create and return a pg from the instance associated with the given handle.
1111  * This function is only called in scf_transaction_setup and
1112  * scf_transaction_restart where the h->rh_instance pointer is properly filled
1113  * in by scf_general_setup_pg().
1114  */
1115 static scf_propertygroup_t *
1116 get_instance_pg(scf_simple_handle_t *simple_h)
1117 {
1118 	scf_propertygroup_t	*ret_pg = scf_pg_create(simple_h->h);
1119 	char			*pg_name;
1120 	ssize_t			namelen;
1121 
1122 	if (ret_pg == NULL) {
1123 		return (NULL);
1124 	}
1125 
1126 	if ((namelen = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) == -1) {
1127 		if (scf_error() == SCF_ERROR_NOT_SET) {
1128 			(void) scf_set_error(SCF_ERROR_INTERNAL);
1129 		}
1130 		return (NULL);
1131 	}
1132 
1133 	if ((pg_name = malloc(namelen)) == NULL) {
1134 		if (scf_error() == SCF_ERROR_NOT_SET) {
1135 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
1136 		}
1137 		return (NULL);
1138 	}
1139 
1140 	if (scf_pg_get_name(simple_h->running_pg, pg_name, namelen) < 0) {
1141 		if (scf_error() == SCF_ERROR_NOT_SET) {
1142 			(void) scf_set_error(SCF_ERROR_INTERNAL);
1143 		}
1144 		return (NULL);
1145 	}
1146 
1147 	/* Get pg from instance */
1148 	if (scf_instance_get_pg(simple_h->inst, pg_name, ret_pg) == -1) {
1149 		return (NULL);
1150 	}
1151 
1152 	return (ret_pg);
1153 }
1154 
1155 int
1156 smf_enable_instance(const char *fmri, int flags)
1157 {
1158 	return (set_inst_enabled_flags(fmri, flags, B_TRUE));
1159 }
1160 
1161 int
1162 smf_disable_instance(const char *fmri, int flags)
1163 {
1164 	return (set_inst_enabled_flags(fmri, flags, B_FALSE));
1165 }
1166 
1167 int
1168 _smf_refresh_instance_i(scf_instance_t *inst)
1169 {
1170 	return (set_inst_action_inst(inst, SCF_PROPERTY_REFRESH));
1171 }
1172 
1173 int
1174 smf_refresh_instance(const char *instance)
1175 {
1176 	return (set_inst_action(instance, SCF_PROPERTY_REFRESH));
1177 }
1178 
1179 int
1180 smf_restart_instance(const char *instance)
1181 {
1182 	return (set_inst_action(instance, SCF_PROPERTY_RESTART));
1183 }
1184 
1185 int
1186 smf_maintain_instance(const char *instance, int flags)
1187 {
1188 	if (flags & SMF_TEMPORARY)
1189 		return (set_inst_action(instance,
1190 		    (flags & SMF_IMMEDIATE) ?
1191 		    SCF_PROPERTY_MAINT_ON_IMMTEMP :
1192 		    SCF_PROPERTY_MAINT_ON_TEMPORARY));
1193 	else
1194 		return (set_inst_action(instance,
1195 		    (flags & SMF_IMMEDIATE) ?
1196 		    SCF_PROPERTY_MAINT_ON_IMMEDIATE :
1197 		    SCF_PROPERTY_MAINT_ON));
1198 }
1199 
1200 int
1201 smf_degrade_instance(const char *instance, int flags)
1202 {
1203 	scf_simple_prop_t		*prop;
1204 	const char			*state_str;
1205 
1206 	if (flags & SMF_TEMPORARY)
1207 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
1208 
1209 	if ((prop = scf_simple_prop_get(NULL, instance, SCF_PG_RESTARTER,
1210 	    SCF_PROPERTY_STATE)) == NULL)
1211 		return (SCF_FAILED);
1212 
1213 	if ((state_str = scf_simple_prop_next_astring(prop)) == NULL) {
1214 		scf_simple_prop_free(prop);
1215 		return (SCF_FAILED);
1216 	}
1217 
1218 	if (strcmp(state_str, SCF_STATE_STRING_ONLINE) != 0) {
1219 		scf_simple_prop_free(prop);
1220 		return (scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED));
1221 	}
1222 	scf_simple_prop_free(prop);
1223 
1224 	return (set_inst_action(instance, (flags & SMF_IMMEDIATE) ?
1225 	    SCF_PROPERTY_DEGRADE_IMMEDIATE : SCF_PROPERTY_DEGRADED));
1226 }
1227 
1228 int
1229 smf_restore_instance(const char *instance)
1230 {
1231 	scf_simple_prop_t		*prop;
1232 	const char			*state_str;
1233 	int				ret;
1234 
1235 	if ((prop = scf_simple_prop_get(NULL, instance, SCF_PG_RESTARTER,
1236 	    SCF_PROPERTY_STATE)) == NULL)
1237 		return (SCF_FAILED);
1238 
1239 	if ((state_str = scf_simple_prop_next_astring(prop)) == NULL) {
1240 		scf_simple_prop_free(prop);
1241 		return (SCF_FAILED);
1242 	}
1243 
1244 	if (strcmp(state_str, SCF_STATE_STRING_MAINT) == 0) {
1245 		ret = set_inst_action(instance, SCF_PROPERTY_MAINT_OFF);
1246 	} else if (strcmp(state_str, SCF_STATE_STRING_DEGRADED) == 0) {
1247 		ret = set_inst_action(instance, SCF_PROPERTY_RESTORE);
1248 	} else {
1249 		ret = scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED);
1250 	}
1251 
1252 	scf_simple_prop_free(prop);
1253 	return (ret);
1254 }
1255 
1256 char *
1257 smf_get_state(const char *instance)
1258 {
1259 	scf_simple_prop_t		*prop;
1260 	const char			*state_str;
1261 	char				*ret;
1262 
1263 	if ((prop = scf_simple_prop_get(NULL, instance, SCF_PG_RESTARTER,
1264 	    SCF_PROPERTY_STATE)) == NULL)
1265 		return (NULL);
1266 
1267 	if ((state_str = scf_simple_prop_next_astring(prop)) == NULL) {
1268 		scf_simple_prop_free(prop);
1269 		return (NULL);
1270 	}
1271 
1272 	if ((ret = strdup(state_str)) == NULL)
1273 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
1274 
1275 	scf_simple_prop_free(prop);
1276 	return (ret);
1277 }
1278 
1279 /*
1280  * scf_general_pg_setup(fmri, pg_name)
1281  * Create a scf_simple_handle_t and fill in the instance, snapshot, and
1282  * property group fields associated with the given fmri and property group
1283  * name.
1284  * Returns:
1285  *      Handle  on success
1286  *      Null  on error with scf_error set to:
1287  *              SCF_ERROR_HANDLE_MISMATCH,
1288  *              SCF_ERROR_INVALID_ARGUMENT,
1289  *              SCF_ERROR_CONSTRAINT_VIOLATED,
1290  *              SCF_ERROR_NOT_FOUND,
1291  *              SCF_ERROR_NOT_SET,
1292  *              SCF_ERROR_DELETED,
1293  *              SCF_ERROR_NOT_BOUND,
1294  *              SCF_ERROR_CONNECTION_BROKEN,
1295  *              SCF_ERROR_INTERNAL,
1296  *              SCF_ERROR_NO_RESOURCES,
1297  *              SCF_ERROR_BACKEND_ACCESS
1298  */
1299 scf_simple_handle_t *
1300 scf_general_pg_setup(const char *fmri, const char *pg_name)
1301 {
1302 	scf_simple_handle_t	*ret;
1303 
1304 	ret = uu_zalloc(sizeof (*ret));
1305 	if (ret == NULL) {
1306 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
1307 		return (NULL);
1308 	} else {
1309 
1310 		ret->h = handle_create();
1311 		ret->inst = scf_instance_create(ret->h);
1312 		ret->snap = scf_snapshot_create(ret->h);
1313 		ret->running_pg = scf_pg_create(ret->h);
1314 	}
1315 
1316 	if ((ret->h == NULL) || (ret->inst == NULL) ||
1317 	    (ret->snap == NULL) || (ret->running_pg == NULL)) {
1318 		goto out;
1319 	}
1320 
1321 	if (scf_handle_decode_fmri(ret->h, fmri, NULL, NULL, ret->inst,
1322 	    NULL, NULL, NULL) == -1) {
1323 		goto out;
1324 	}
1325 
1326 	if ((scf_instance_get_snapshot(ret->inst, "running", ret->snap))
1327 	    != 0) {
1328 		goto out;
1329 	}
1330 
1331 	if (scf_instance_get_pg_composed(ret->inst, ret->snap, pg_name,
1332 	    ret->running_pg) != 0) {
1333 		goto out;
1334 	}
1335 
1336 	return (ret);
1337 
1338 out:
1339 	scf_simple_handle_destroy(ret);
1340 	return (NULL);
1341 }
1342 
1343 /*
1344  * scf_transaction_setup(h)
1345  * creates and starts the transaction
1346  * Returns:
1347  *      transaction  on success
1348  *      NULL on failure with scf_error set to:
1349  *      SCF_ERROR_NO_MEMORY,
1350  *	SCF_ERROR_INVALID_ARGUMENT,
1351  *      SCF_ERROR_HANDLE_DESTROYED,
1352  *	SCF_ERROR_INTERNAL,
1353  *	SCF_ERROR_NO_RESOURCES,
1354  *      SCF_ERROR_NOT_BOUND,
1355  *	SCF_ERROR_CONNECTION_BROKEN,
1356  *      SCF_ERROR_NOT_SET,
1357  *	SCF_ERROR_DELETED,
1358  *	SCF_ERROR_CONSTRAINT_VIOLATED,
1359  *      SCF_ERROR_HANDLE_MISMATCH,
1360  *	SCF_ERROR_BACKEND_ACCESS,
1361  *	SCF_ERROR_IN_USE
1362  */
1363 scf_transaction_t *
1364 scf_transaction_setup(scf_simple_handle_t *simple_h)
1365 {
1366 	scf_transaction_t	*tx = NULL;
1367 
1368 	if ((tx = scf_transaction_create(simple_h->h)) == NULL) {
1369 		return (NULL);
1370 	}
1371 
1372 	if ((simple_h->editing_pg = get_instance_pg(simple_h)) == NULL) {
1373 		return (NULL);
1374 	}
1375 
1376 	if (scf_transaction_start(tx, simple_h->editing_pg) == -1) {
1377 		scf_pg_destroy(simple_h->editing_pg);
1378 		simple_h->editing_pg = NULL;
1379 		return (NULL);
1380 	}
1381 
1382 	return (tx);
1383 }
1384 
1385 int
1386 scf_transaction_restart(scf_simple_handle_t *simple_h, scf_transaction_t *tx)
1387 {
1388 	scf_transaction_reset(tx);
1389 
1390 	if (scf_pg_update(simple_h->editing_pg) == -1) {
1391 		return (SCF_FAILED);
1392 	}
1393 
1394 	if (scf_transaction_start(tx, simple_h->editing_pg) == -1) {
1395 		return (SCF_FAILED);
1396 	}
1397 
1398 	return (SCF_SUCCESS);
1399 }
1400 
1401 /*
1402  * scf_read_count_property(scf_simple_handle_t *simple_h, char *prop_name,
1403  * uint64_t *ret_count)
1404  *
1405  * For the given property name, return the count value.
1406  * RETURNS:
1407  *	SCF_SUCCESS
1408  *	SCF_FAILED on failure with scf_error() set to:
1409  *		SCF_ERROR_HANDLE_DESTROYED
1410  *		SCF_ERROR_INTERNAL
1411  *		SCF_ERROR_NO_RESOURCES
1412  *		SCF_ERROR_NO_MEMORY
1413  *		SCF_ERROR_HANDLE_MISMATCH
1414  *		SCF_ERROR_INVALID_ARGUMENT
1415  *		SCF_ERROR_NOT_BOUND
1416  *		SCF_ERROR_CONNECTION_BROKEN
1417  *		SCF_ERROR_NOT_SET
1418  *		SCF_ERROR_DELETED
1419  *		SCF_ERROR_BACKEND_ACCESS
1420  *		SCF_ERROR_CONSTRAINT_VIOLATED
1421  *		SCF_ERROR_TYPE_MISMATCH
1422  */
1423 int
1424 scf_read_count_property(
1425 	scf_simple_handle_t	*simple_h,
1426 	char			*prop_name,
1427 	uint64_t		*ret_count)
1428 {
1429 	scf_property_t		*prop = scf_property_create(simple_h->h);
1430 	scf_value_t		*val = scf_value_create(simple_h->h);
1431 	int			ret = SCF_FAILED;
1432 
1433 	if ((val == NULL) || (prop == NULL)) {
1434 		goto out;
1435 	}
1436 
1437 	/*
1438 	 * Get the property struct that goes with this property group and
1439 	 * property name.
1440 	 */
1441 	if (scf_pg_get_property(simple_h->running_pg, prop_name, prop) != 0) {
1442 		goto out;
1443 	}
1444 
1445 	/* Get the value structure */
1446 	if (scf_property_get_value(prop, val) == -1) {
1447 		goto out;
1448 	}
1449 
1450 	/*
1451 	 * Now get the count value.
1452 	 */
1453 	if (scf_value_get_count(val, ret_count) == -1) {
1454 		goto out;
1455 	}
1456 
1457 	ret = SCF_SUCCESS;
1458 
1459 out:
1460 	scf_property_destroy(prop);
1461 	scf_value_destroy(val);
1462 	return (ret);
1463 }
1464 
1465 /*
1466  * scf_trans_add_count_property(trans, propname, count, create_flag)
1467  *
1468  * Set a count property transaction entry into the pending SMF transaction.
1469  * The transaction is created and committed outside of this function.
1470  * Returns:
1471  *	SCF_SUCCESS
1472  *	SCF_FAILED on failure with scf_error() set to:
1473  *			SCF_ERROR_HANDLE_DESTROYED,
1474  *			SCF_ERROR_INVALID_ARGUMENT,
1475  *			SCF_ERROR_NO_MEMORY,
1476  *			SCF_ERROR_HANDLE_MISMATCH,
1477  *			SCF_ERROR_NOT_SET,
1478  *			SCF_ERROR_IN_USE,
1479  *			SCF_ERROR_NOT_FOUND,
1480  *			SCF_ERROR_EXISTS,
1481  *			SCF_ERROR_TYPE_MISMATCH,
1482  *			SCF_ERROR_NOT_BOUND,
1483  *			SCF_ERROR_CONNECTION_BROKEN,
1484  *			SCF_ERROR_INTERNAL,
1485  *			SCF_ERROR_DELETED,
1486  *			SCF_ERROR_NO_RESOURCES,
1487  *			SCF_ERROR_BACKEND_ACCESS
1488  */
1489 int
1490 scf_set_count_property(
1491 	scf_transaction_t	*trans,
1492 	char			*propname,
1493 	uint64_t		count,
1494 	boolean_t		create_flag)
1495 {
1496 	scf_handle_t		*handle = scf_transaction_handle(trans);
1497 	scf_value_t		*value = scf_value_create(handle);
1498 	scf_transaction_entry_t	*entry = scf_entry_create(handle);
1499 
1500 	if ((value == NULL) || (entry == NULL)) {
1501 		return (SCF_FAILED);
1502 	}
1503 
1504 	/*
1505 	 * Property must be set in transaction and won't take
1506 	 * effect until the transaction is committed.
1507 	 *
1508 	 * Attempt to change the current value. However, create new property
1509 	 * if it doesn't exist and the create flag is set.
1510 	 */
1511 	if (scf_transaction_property_change(trans, entry, propname,
1512 	    SCF_TYPE_COUNT) == 0) {
1513 		scf_value_set_count(value, count);
1514 		if (scf_entry_add_value(entry, value) == 0) {
1515 			return (SCF_SUCCESS);
1516 		}
1517 	} else {
1518 		if ((create_flag == B_TRUE) &&
1519 		    (scf_error() == SCF_ERROR_NOT_FOUND)) {
1520 			if (scf_transaction_property_new(trans, entry, propname,
1521 			    SCF_TYPE_COUNT) == 0) {
1522 				scf_value_set_count(value, count);
1523 				if (scf_entry_add_value(entry, value) == 0) {
1524 					return (SCF_SUCCESS);
1525 				}
1526 			}
1527 		}
1528 	}
1529 
1530 	/*
1531 	 * cleanup if there were any errors that didn't leave these
1532 	 * values where they would be cleaned up later.
1533 	 */
1534 	if (value != NULL)
1535 		scf_value_destroy(value);
1536 	if (entry != NULL)
1537 		scf_entry_destroy(entry);
1538 	return (SCF_FAILED);
1539 }
1540 
1541 int
1542 scf_simple_walk_instances(uint_t state_flags, void *private,
1543     int (*inst_callback)(scf_handle_t *, scf_instance_t *, void *))
1544 {
1545 	scf_scope_t 		*scope = NULL;
1546 	scf_service_t		*svc = NULL;
1547 	scf_instance_t		*inst = NULL;
1548 	scf_iter_t		*svc_iter = NULL, *inst_iter = NULL;
1549 	scf_handle_t		*h = NULL;
1550 	int			ret = SCF_FAILED;
1551 	int			svc_iter_ret, inst_iter_ret;
1552 	int			inst_state;
1553 
1554 	if ((h = handle_create()) == NULL)
1555 		return (ret);
1556 
1557 	if (((scope = scf_scope_create(h)) == NULL) ||
1558 	    ((svc = scf_service_create(h)) == NULL) ||
1559 	    ((inst = scf_instance_create(h)) == NULL) ||
1560 	    ((svc_iter = scf_iter_create(h)) == NULL) ||
1561 	    ((inst_iter = scf_iter_create(h)) == NULL))
1562 		goto out;
1563 
1564 	/*
1565 	 * Get the local scope, and set up nested iteration through every
1566 	 * local service, and every instance of every service.
1567 	 */
1568 
1569 	if ((scf_handle_get_local_scope(h, scope) != SCF_SUCCESS) ||
1570 	    (scf_iter_scope_services(svc_iter, scope) != SCF_SUCCESS))
1571 		goto out;
1572 
1573 	while ((svc_iter_ret = scf_iter_next_service(svc_iter, svc)) > 0) {
1574 
1575 		if ((scf_iter_service_instances(inst_iter, svc)) !=
1576 		    SCF_SUCCESS)
1577 			goto out;
1578 
1579 		while ((inst_iter_ret =
1580 		    scf_iter_next_instance(inst_iter, inst)) > 0) {
1581 			/*
1582 			 * If get_inst_state fails from an internal error,
1583 			 * IE, being unable to get the property group or
1584 			 * property containing the state of the instance,
1585 			 * we continue instead of failing, as this might just
1586 			 * be an improperly configured instance.
1587 			 */
1588 			if ((inst_state = get_inst_state(inst, h)) == -1) {
1589 				if (scf_error() == SCF_ERROR_INTERNAL) {
1590 					continue;
1591 				} else {
1592 					goto out;
1593 				}
1594 			}
1595 
1596 			if ((uint_t)inst_state & state_flags) {
1597 				if (inst_callback(h, inst, private) !=
1598 				    SCF_SUCCESS) {
1599 					(void) scf_set_error(
1600 					    SCF_ERROR_CALLBACK_FAILED);
1601 					goto out;
1602 				}
1603 			}
1604 		}
1605 
1606 		if (inst_iter_ret == -1)
1607 			goto out;
1608 		scf_iter_reset(inst_iter);
1609 	}
1610 
1611 	if (svc_iter_ret != -1)
1612 		ret = SCF_SUCCESS;
1613 
1614 out:
1615 	scf_scope_destroy(scope);
1616 	scf_service_destroy(svc);
1617 	scf_instance_destroy(inst);
1618 	scf_iter_destroy(svc_iter);
1619 	scf_iter_destroy(inst_iter);
1620 	scf_handle_destroy(h);
1621 
1622 	return (ret);
1623 }
1624 
1625 
1626 scf_simple_prop_t *
1627 scf_simple_prop_get(scf_handle_t *hin, const char *instance, const char *pgname,
1628 			const char *propname)
1629 {
1630 	char 			*fmri_buf, *svcfmri = NULL;
1631 	ssize_t 		fmri_sz;
1632 	scf_property_t 		*prop = NULL;
1633 	scf_service_t 		*svc = NULL;
1634 	scf_simple_prop_t 	*ret;
1635 	scf_handle_t		*h = NULL;
1636 	boolean_t		local_h = B_TRUE;
1637 
1638 	/* If the user passed in a handle, use it. */
1639 	if (hin != NULL) {
1640 		h = hin;
1641 		local_h = B_FALSE;
1642 	}
1643 
1644 	if (local_h && ((h = handle_create()) == NULL))
1645 		return (NULL);
1646 
1647 	if ((fmri_buf = assemble_fmri(h, instance, pgname, propname)) == NULL) {
1648 		if (local_h)
1649 			scf_handle_destroy(h);
1650 		return (NULL);
1651 	}
1652 
1653 	if ((svc = scf_service_create(h)) == NULL ||
1654 	    (prop = scf_property_create(h)) == NULL)
1655 		goto error1;
1656 	if (scf_handle_decode_fmri(h, fmri_buf, NULL, NULL, NULL, NULL, prop,
1657 	    SCF_DECODE_FMRI_REQUIRE_INSTANCE) == -1) {
1658 		switch (scf_error()) {
1659 		/*
1660 		 * If the property isn't found in the instance, we grab the
1661 		 * underlying service, create an FMRI out of it, and then
1662 		 * query the datastore again at the service level for the
1663 		 * property.
1664 		 */
1665 		case SCF_ERROR_NOT_FOUND:
1666 			if (scf_handle_decode_fmri(h, fmri_buf, NULL, svc,
1667 			    NULL, NULL, NULL, SCF_DECODE_FMRI_TRUNCATE) == -1)
1668 				goto error1;
1669 			if ((fmri_sz = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) ==
1670 			    -1) {
1671 				(void) scf_set_error(SCF_ERROR_INTERNAL);
1672 				goto error1;
1673 			}
1674 			if (scf_service_to_fmri(svc, fmri_buf, fmri_sz) == -1)
1675 				goto error1;
1676 			if ((svcfmri = assemble_fmri(h, fmri_buf, pgname,
1677 			    propname)) == NULL)
1678 				goto error1;
1679 			if (scf_handle_decode_fmri(h, svcfmri, NULL, NULL,
1680 			    NULL, NULL, prop, 0) == -1) {
1681 				free(svcfmri);
1682 				goto error1;
1683 			}
1684 			free(svcfmri);
1685 			break;
1686 		case SCF_ERROR_CONSTRAINT_VIOLATED:
1687 			(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1688 		default:
1689 			goto error1;
1690 		}
1691 	}
1692 	/*
1693 	 * At this point, we've successfully pulled the property from the
1694 	 * datastore, and simply need to copy its innards into an
1695 	 * scf_simple_prop_t.
1696 	 */
1697 	if ((ret = fill_prop(prop, pgname, propname, h)) == NULL)
1698 		goto error1;
1699 
1700 	scf_service_destroy(svc);
1701 	scf_property_destroy(prop);
1702 	free(fmri_buf);
1703 	if (local_h)
1704 		scf_handle_destroy(h);
1705 	return (ret);
1706 
1707 	/*
1708 	 * Exit point for a successful call.  Below this line are exit points
1709 	 * for failures at various stages during the function.
1710 	 */
1711 
1712 error1:
1713 	scf_service_destroy(svc);
1714 	scf_property_destroy(prop);
1715 error2:
1716 	free(fmri_buf);
1717 	if (local_h)
1718 		scf_handle_destroy(h);
1719 	return (NULL);
1720 }
1721 
1722 
1723 void
1724 scf_simple_prop_free(scf_simple_prop_t *prop)
1725 {
1726 	int i;
1727 
1728 	if (prop == NULL)
1729 		return;
1730 
1731 	free(prop->pr_propname);
1732 	free(prop->pr_pgname);
1733 	switch (prop->pr_type) {
1734 	case SCF_TYPE_OPAQUE: {
1735 		for (i = 0; i < prop->pr_numvalues; i++) {
1736 			free(prop->pr_vallist[i].pv_opaque.o_value);
1737 		}
1738 		break;
1739 	}
1740 	case SCF_TYPE_ASTRING:
1741 	case SCF_TYPE_USTRING:
1742 	case SCF_TYPE_HOST:
1743 	case SCF_TYPE_HOSTNAME:
1744 	case SCF_TYPE_NET_ADDR_V4:
1745 	case SCF_TYPE_NET_ADDR_V6:
1746 	case SCF_TYPE_URI:
1747 	case SCF_TYPE_FMRI: {
1748 		for (i = 0; i < prop->pr_numvalues; i++) {
1749 			free(prop->pr_vallist[i].pv_str);
1750 		}
1751 		break;
1752 	}
1753 	default:
1754 		break;
1755 	}
1756 	free(prop->pr_vallist);
1757 	free(prop);
1758 }
1759 
1760 
1761 scf_simple_app_props_t *
1762 scf_simple_app_props_get(scf_handle_t *hin, const char *inst_fmri)
1763 {
1764 	scf_instance_t 		*inst = NULL;
1765 	scf_service_t 		*svc = NULL;
1766 	scf_propertygroup_t 	*pg = NULL;
1767 	scf_property_t 		*prop = NULL;
1768 	scf_simple_app_props_t	*ret = NULL;
1769 	scf_iter_t		*pgiter = NULL, *propiter = NULL;
1770 	struct scf_simple_pg	*thispg = NULL, *nextpg;
1771 	scf_simple_prop_t	*thisprop, *nextprop;
1772 	scf_handle_t		*h = NULL;
1773 	int			pgiter_ret, propiter_ret;
1774 	ssize_t			namelen;
1775 	char 			*propname = NULL, *pgname = NULL, *sys_fmri;
1776 	uint8_t			found;
1777 	boolean_t		local_h = B_TRUE;
1778 
1779 	/* If the user passed in a handle, use it. */
1780 	if (hin != NULL) {
1781 		h = hin;
1782 		local_h = B_FALSE;
1783 	}
1784 
1785 	if (local_h && ((h = handle_create()) == NULL))
1786 		return (NULL);
1787 
1788 	if (inst_fmri == NULL) {
1789 		if ((namelen = scf_myname(h, NULL, 0)) == -1) {
1790 			if (local_h)
1791 				scf_handle_destroy(h);
1792 			return (NULL);
1793 		}
1794 		if ((sys_fmri = malloc(namelen + 1)) == NULL) {
1795 			if (local_h)
1796 				scf_handle_destroy(h);
1797 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
1798 			return (NULL);
1799 		}
1800 		if (scf_myname(h, sys_fmri, namelen + 1) == -1) {
1801 			if (local_h)
1802 				scf_handle_destroy(h);
1803 			free(sys_fmri);
1804 			return (NULL);
1805 		}
1806 	} else {
1807 		sys_fmri = strdup(inst_fmri);
1808 	}
1809 
1810 	if ((namelen = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) == -1) {
1811 		(void) scf_set_error(SCF_ERROR_INTERNAL);
1812 		return (NULL);
1813 	}
1814 
1815 	if ((inst = scf_instance_create(h)) == NULL ||
1816 	    (svc = scf_service_create(h)) == NULL ||
1817 	    (pgiter = scf_iter_create(h)) == NULL ||
1818 	    (propiter = scf_iter_create(h)) == NULL ||
1819 	    (pg = scf_pg_create(h)) == NULL ||
1820 	    (prop = scf_property_create(h)) == NULL)
1821 		goto error2;
1822 
1823 	if (scf_handle_decode_fmri(h, sys_fmri, NULL, svc, inst, NULL, NULL,
1824 	    SCF_DECODE_FMRI_REQUIRE_INSTANCE) == -1) {
1825 		if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED)
1826 			(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1827 		goto error2;
1828 	}
1829 
1830 	if ((ret = malloc(sizeof (*ret))) == NULL ||
1831 	    (thispg = malloc(sizeof (*thispg))) == NULL ||
1832 	    (propname = malloc(namelen)) == NULL ||
1833 	    (pgname = malloc(namelen)) == NULL) {
1834 		free(thispg);
1835 		free(ret);
1836 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
1837 		goto error2;
1838 	}
1839 
1840 	ret->ap_fmri = sys_fmri;
1841 	thispg->pg_name = NULL;
1842 	thispg->pg_proplist = NULL;
1843 	thispg->pg_next = NULL;
1844 	ret->ap_pglist = thispg;
1845 
1846 	if (scf_iter_service_pgs_typed(pgiter, svc, SCF_GROUP_APPLICATION) !=
1847 	    0) {
1848 		if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
1849 			(void) scf_set_error(SCF_ERROR_INTERNAL);
1850 		goto error1;
1851 	}
1852 
1853 	while ((pgiter_ret = scf_iter_next_pg(pgiter, pg)) == 1) {
1854 		if (thispg->pg_name != NULL) {
1855 			if ((nextpg = malloc(sizeof (*nextpg))) == NULL) {
1856 				(void) scf_set_error(SCF_ERROR_NO_MEMORY);
1857 				goto error1;
1858 			}
1859 			thispg->pg_next = nextpg;
1860 			thispg = nextpg;
1861 		} else {
1862 			/* This is the first iteration */
1863 			nextpg = thispg;
1864 		}
1865 
1866 		if ((nextpg->pg_name = malloc(namelen)) == NULL) {
1867 			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
1868 			goto error1;
1869 		}
1870 
1871 		if (scf_pg_get_name(pg, nextpg->pg_name, namelen) < 0) {
1872 			if (scf_error() == SCF_ERROR_NOT_SET)
1873 				(void) scf_set_error(SCF_ERROR_INTERNAL);
1874 			goto error1;
1875 		}
1876 
1877 		nextpg->pg_next = NULL;
1878 		nextpg->pg_proplist = NULL;
1879 		thisprop = NULL;
1880 
1881 		scf_iter_reset(propiter);
1882 
1883 		if (scf_iter_pg_properties(propiter, pg) != 0) {
1884 			if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
1885 				(void) scf_set_error(SCF_ERROR_INTERNAL);
1886 			goto error1;
1887 		}
1888 
1889 		while ((propiter_ret = scf_iter_next_property(propiter, prop))
1890 		    == 1) {
1891 			if (scf_property_get_name(prop, propname, namelen) <
1892 			    0) {
1893 				if (scf_error() == SCF_ERROR_NOT_SET)
1894 					(void) scf_set_error(
1895 					    SCF_ERROR_INTERNAL);
1896 				goto error1;
1897 			}
1898 			if (thisprop != NULL) {
1899 				if ((nextprop = fill_prop(prop,
1900 				    nextpg->pg_name, propname, h)) == NULL)
1901 					goto error1;
1902 				thisprop->pr_next = nextprop;
1903 				thisprop = nextprop;
1904 			} else {
1905 				/* This is the first iteration */
1906 				if ((thisprop = fill_prop(prop,
1907 				    nextpg->pg_name, propname, h)) == NULL)
1908 					goto error1;
1909 				nextpg->pg_proplist = thisprop;
1910 				nextprop = thisprop;
1911 			}
1912 			nextprop->pr_pg = nextpg;
1913 			nextprop->pr_next = NULL;
1914 		}
1915 
1916 		if (propiter_ret == -1) {
1917 			if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
1918 				(void) scf_set_error(SCF_ERROR_INTERNAL);
1919 			goto error1;
1920 		}
1921 	}
1922 
1923 	if (pgiter_ret == -1) {
1924 		if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
1925 			(void) scf_set_error(SCF_ERROR_INTERNAL);
1926 		goto error1;
1927 	}
1928 
1929 	/*
1930 	 * At this point, we've filled the scf_simple_app_props_t with all the
1931 	 * properties at the service level.  Now we iterate over all the
1932 	 * properties at the instance level, overwriting any duplicate
1933 	 * properties, in order to provide service/instance composition.
1934 	 */
1935 
1936 	scf_iter_reset(pgiter);
1937 	scf_iter_reset(propiter);
1938 
1939 	if (scf_iter_instance_pgs_typed(pgiter, inst, SCF_GROUP_APPLICATION)
1940 	    != 0) {
1941 		if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
1942 			(void) scf_set_error(SCF_ERROR_INTERNAL);
1943 		goto error1;
1944 	}
1945 
1946 	while ((pgiter_ret = scf_iter_next_pg(pgiter, pg)) == 1) {
1947 
1948 		thispg = ret->ap_pglist;
1949 		found = 0;
1950 
1951 		/*
1952 		 * Find either the end of the list, so we can append the
1953 		 * property group, or an existing property group that matches
1954 		 * it, so we can insert/overwrite its properties.
1955 		 */
1956 
1957 		if (scf_pg_get_name(pg, pgname, namelen) < 0) {
1958 			if (scf_error() == SCF_ERROR_NOT_SET)
1959 				(void) scf_set_error(SCF_ERROR_INTERNAL);
1960 			goto error1;
1961 		}
1962 
1963 		while ((thispg != NULL) && (thispg->pg_name != NULL)) {
1964 			if (strcmp(thispg->pg_name, pgname) == 0) {
1965 				found = 1;
1966 				break;
1967 			}
1968 			if (thispg->pg_next == NULL)
1969 				break;
1970 
1971 			thispg = thispg->pg_next;
1972 		}
1973 
1974 		scf_iter_reset(propiter);
1975 
1976 		if (scf_iter_pg_properties(propiter, pg) != 0) {
1977 			if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
1978 				(void) scf_set_error(SCF_ERROR_INTERNAL);
1979 			goto error1;
1980 		}
1981 
1982 		if (found) {
1983 			/*
1984 			 * insert_app_props inserts or overwrites the
1985 			 * properties in thispg.
1986 			 */
1987 
1988 			if (insert_app_props(propiter, pgname, propname,
1989 			    thispg, prop, namelen, h) == -1)
1990 				goto error1;
1991 
1992 		} else {
1993 			/*
1994 			 * If the property group wasn't found, we're adding
1995 			 * a newly allocated property group to the end of the
1996 			 * list.
1997 			 */
1998 
1999 			if ((nextpg = malloc(sizeof (*nextpg))) == NULL) {
2000 				(void) scf_set_error(SCF_ERROR_NO_MEMORY);
2001 				goto error1;
2002 			}
2003 			nextpg->pg_next = NULL;
2004 			nextpg->pg_proplist = NULL;
2005 			thisprop = NULL;
2006 
2007 			if ((nextpg->pg_name = strdup(pgname)) == NULL) {
2008 				free(nextpg);
2009 				goto error1;
2010 			}
2011 
2012 			if (thispg->pg_name == NULL) {
2013 				free(thispg);
2014 				ret->ap_pglist = nextpg;
2015 			} else {
2016 				thispg->pg_next = nextpg;
2017 			}
2018 
2019 			while ((propiter_ret =
2020 			    scf_iter_next_property(propiter, prop)) == 1) {
2021 				if (scf_property_get_name(prop, propname,
2022 				    namelen) < 0) {
2023 					if (scf_error() == SCF_ERROR_NOT_SET)
2024 						(void) scf_set_error(
2025 						    SCF_ERROR_INTERNAL);
2026 					goto error1;
2027 				}
2028 				if (thisprop != NULL) {
2029 					if ((nextprop = fill_prop(prop,
2030 					    pgname, propname, h)) ==
2031 					    NULL)
2032 						goto error1;
2033 					thisprop->pr_next = nextprop;
2034 					thisprop = nextprop;
2035 				} else {
2036 					/* This is the first iteration */
2037 					if ((thisprop = fill_prop(prop,
2038 					    pgname, propname, h)) ==
2039 					    NULL)
2040 						goto error1;
2041 					nextpg->pg_proplist = thisprop;
2042 					nextprop = thisprop;
2043 				}
2044 				nextprop->pr_pg = nextpg;
2045 				nextprop->pr_next = NULL;
2046 			}
2047 
2048 			if (propiter_ret == -1) {
2049 				if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
2050 					(void) scf_set_error(
2051 					    SCF_ERROR_INTERNAL);
2052 				goto error1;
2053 			}
2054 		}
2055 
2056 	}
2057 
2058 	if (pgiter_ret == -1) {
2059 		if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
2060 			(void) scf_set_error(SCF_ERROR_INTERNAL);
2061 		goto error1;
2062 	}
2063 
2064 	scf_iter_destroy(pgiter);
2065 	scf_iter_destroy(propiter);
2066 	scf_pg_destroy(pg);
2067 	scf_property_destroy(prop);
2068 	scf_instance_destroy(inst);
2069 	scf_service_destroy(svc);
2070 	free(propname);
2071 	free(pgname);
2072 	if (local_h)
2073 		scf_handle_destroy(h);
2074 
2075 	if (ret->ap_pglist->pg_name == NULL)
2076 		return (NULL);
2077 
2078 	return (ret);
2079 
2080 	/*
2081 	 * Exit point for a successful call.  Below this line are exit points
2082 	 * for failures at various stages during the function.
2083 	 */
2084 
2085 error1:
2086 	scf_simple_app_props_free(ret);
2087 
2088 error2:
2089 	scf_iter_destroy(pgiter);
2090 	scf_iter_destroy(propiter);
2091 	scf_pg_destroy(pg);
2092 	scf_property_destroy(prop);
2093 	scf_instance_destroy(inst);
2094 	scf_service_destroy(svc);
2095 	free(propname);
2096 	free(pgname);
2097 	if (local_h)
2098 		scf_handle_destroy(h);
2099 	return (NULL);
2100 }
2101 
2102 
2103 void
2104 scf_simple_app_props_free(scf_simple_app_props_t *propblock)
2105 {
2106 	struct scf_simple_pg 	*pgthis, *pgnext;
2107 	scf_simple_prop_t 	*propthis, *propnext;
2108 
2109 	if ((propblock == NULL) || (propblock->ap_pglist == NULL))
2110 		return;
2111 
2112 	for (pgthis = propblock->ap_pglist; pgthis != NULL; pgthis = pgnext) {
2113 		pgnext = pgthis->pg_next;
2114 
2115 		propthis = pgthis->pg_proplist;
2116 
2117 		while (propthis != NULL) {
2118 			propnext = propthis->pr_next;
2119 			scf_simple_prop_free(propthis);
2120 			propthis = propnext;
2121 		}
2122 
2123 		free(pgthis->pg_name);
2124 		free(pgthis);
2125 	}
2126 
2127 	free(propblock->ap_fmri);
2128 	free(propblock);
2129 }
2130 
2131 const scf_simple_prop_t *
2132 scf_simple_app_props_next(const scf_simple_app_props_t *propblock,
2133     scf_simple_prop_t *last)
2134 {
2135 	struct scf_simple_pg 	*this;
2136 
2137 	if (propblock == NULL) {
2138 		(void) scf_set_error(SCF_ERROR_NOT_SET);
2139 		return (NULL);
2140 	}
2141 
2142 	this = propblock->ap_pglist;
2143 
2144 	/*
2145 	 * We're looking for the first property in this block if last is
2146 	 * NULL
2147 	 */
2148 
2149 	if (last == NULL) {
2150 		/* An empty pglist is legal, it just means no properties */
2151 		if (this == NULL) {
2152 			(void) scf_set_error(SCF_ERROR_NONE);
2153 			return (NULL);
2154 		}
2155 		/*
2156 		 * Walk until we find a pg with a property in it, or we run
2157 		 * out of property groups.
2158 		 */
2159 		while ((this->pg_proplist == NULL) && (this->pg_next != NULL))
2160 			this = this->pg_next;
2161 
2162 		if (this->pg_proplist == NULL) {
2163 			(void) scf_set_error(SCF_ERROR_NONE);
2164 			return (NULL);
2165 		}
2166 
2167 		return (this->pg_proplist);
2168 
2169 	}
2170 	/*
2171 	 * If last isn't NULL, then return the next prop in the property group,
2172 	 * or walk the property groups until we find another property, or
2173 	 * run out of property groups.
2174 	 */
2175 	if (last->pr_next != NULL)
2176 		return (last->pr_next);
2177 
2178 	if (last->pr_pg->pg_next == NULL) {
2179 		(void) scf_set_error(SCF_ERROR_NONE);
2180 		return (NULL);
2181 	}
2182 
2183 	this = last->pr_pg->pg_next;
2184 
2185 	while ((this->pg_proplist == NULL) && (this->pg_next != NULL))
2186 		this = this->pg_next;
2187 
2188 	if (this->pg_proplist == NULL) {
2189 		(void) scf_set_error(SCF_ERROR_NONE);
2190 		return (NULL);
2191 	}
2192 
2193 	return (this->pg_proplist);
2194 }
2195 
2196 const scf_simple_prop_t *
2197 scf_simple_app_props_search(const scf_simple_app_props_t *propblock,
2198     const char *pgname, const char *propname)
2199 {
2200 	struct scf_simple_pg 	*pg;
2201 	scf_simple_prop_t 	*prop;
2202 
2203 	if ((propblock == NULL) || (propname == NULL)) {
2204 		(void) scf_set_error(SCF_ERROR_NOT_SET);
2205 		return (NULL);
2206 	}
2207 
2208 	pg = propblock->ap_pglist;
2209 
2210 	/*
2211 	 * If pgname is NULL, we're searching the default application
2212 	 * property group, otherwise we look for the specified group.
2213 	 */
2214 	if (pgname == NULL) {
2215 		while ((pg != NULL) &&
2216 		    (strcmp(SCF_PG_APP_DEFAULT, pg->pg_name) != 0))
2217 			pg = pg->pg_next;
2218 	} else {
2219 		while ((pg != NULL) && (strcmp(pgname, pg->pg_name) != 0))
2220 			pg = pg->pg_next;
2221 	}
2222 
2223 	if (pg == NULL) {
2224 		(void) scf_set_error(SCF_ERROR_NOT_FOUND);
2225 		return (NULL);
2226 	}
2227 
2228 	prop = pg->pg_proplist;
2229 
2230 	while ((prop != NULL) && (strcmp(propname, prop->pr_propname) != 0))
2231 		prop = prop->pr_next;
2232 
2233 	if (prop == NULL) {
2234 		(void) scf_set_error(SCF_ERROR_NOT_FOUND);
2235 		return (NULL);
2236 	}
2237 
2238 	return (prop);
2239 }
2240 
2241 void
2242 scf_simple_prop_next_reset(scf_simple_prop_t *prop)
2243 {
2244 	if (prop == NULL)
2245 		return;
2246 	prop->pr_iter = 0;
2247 }
2248 
2249 ssize_t
2250 scf_simple_prop_numvalues(const scf_simple_prop_t *prop)
2251 {
2252 	if (prop == NULL)
2253 		return (scf_set_error(SCF_ERROR_NOT_SET));
2254 
2255 	return (prop->pr_numvalues);
2256 }
2257 
2258 
2259 scf_type_t
2260 scf_simple_prop_type(const scf_simple_prop_t *prop)
2261 {
2262 	if (prop == NULL)
2263 		return (scf_set_error(SCF_ERROR_NOT_SET));
2264 
2265 	return (prop->pr_type);
2266 }
2267 
2268 
2269 char *
2270 scf_simple_prop_name(const scf_simple_prop_t *prop)
2271 {
2272 	if ((prop == NULL) || (prop->pr_propname == NULL)) {
2273 		(void) scf_set_error(SCF_ERROR_NOT_SET);
2274 		return (NULL);
2275 	}
2276 
2277 	return (prop->pr_propname);
2278 }
2279 
2280 
2281 char *
2282 scf_simple_prop_pgname(const scf_simple_prop_t *prop)
2283 {
2284 	if ((prop == NULL) || (prop->pr_pgname == NULL)) {
2285 		(void) scf_set_error(SCF_ERROR_NOT_SET);
2286 		return (NULL);
2287 	}
2288 
2289 	return (prop->pr_pgname);
2290 }
2291 
2292 
2293 static union scf_simple_prop_val *
2294 scf_next_val(scf_simple_prop_t *prop, scf_type_t type)
2295 {
2296 	if (prop == NULL) {
2297 		(void) scf_set_error(SCF_ERROR_NOT_SET);
2298 		return (NULL);
2299 	}
2300 
2301 	switch (prop->pr_type) {
2302 	case SCF_TYPE_USTRING:
2303 	case SCF_TYPE_HOST:
2304 	case SCF_TYPE_HOSTNAME:
2305 	case SCF_TYPE_NET_ADDR_V4:
2306 	case SCF_TYPE_NET_ADDR_V6:
2307 	case SCF_TYPE_URI:
2308 	case SCF_TYPE_FMRI: {
2309 		if (type != SCF_TYPE_USTRING) {
2310 			(void) scf_set_error(SCF_ERROR_TYPE_MISMATCH);
2311 			return (NULL);
2312 		}
2313 		break;
2314 		}
2315 	default: {
2316 		if (type != prop->pr_type) {
2317 			(void) scf_set_error(SCF_ERROR_TYPE_MISMATCH);
2318 			return (NULL);
2319 		}
2320 		break;
2321 		}
2322 	}
2323 
2324 	if (prop->pr_iter >= prop->pr_numvalues) {
2325 		(void) scf_set_error(SCF_ERROR_NONE);
2326 		return (NULL);
2327 	}
2328 
2329 	return (&prop->pr_vallist[prop->pr_iter++]);
2330 }
2331 
2332 
2333 uint8_t *
2334 scf_simple_prop_next_boolean(scf_simple_prop_t *prop)
2335 {
2336 	union scf_simple_prop_val *ret;
2337 
2338 	ret = scf_next_val(prop, SCF_TYPE_BOOLEAN);
2339 
2340 	if (ret == NULL)
2341 		return (NULL);
2342 
2343 	return (&ret->pv_bool);
2344 }
2345 
2346 
2347 uint64_t *
2348 scf_simple_prop_next_count(scf_simple_prop_t *prop)
2349 {
2350 	union scf_simple_prop_val *ret;
2351 
2352 	ret = scf_next_val(prop, SCF_TYPE_COUNT);
2353 
2354 	if (ret == NULL)
2355 		return (NULL);
2356 
2357 	return (&ret->pv_uint);
2358 }
2359 
2360 
2361 int64_t *
2362 scf_simple_prop_next_integer(scf_simple_prop_t *prop)
2363 {
2364 	union scf_simple_prop_val *ret;
2365 
2366 	ret = scf_next_val(prop, SCF_TYPE_INTEGER);
2367 
2368 	if (ret == NULL)
2369 		return (NULL);
2370 
2371 	return (&ret->pv_int);
2372 }
2373 
2374 int64_t *
2375 scf_simple_prop_next_time(scf_simple_prop_t *prop, int32_t *nsec)
2376 {
2377 	union scf_simple_prop_val *ret;
2378 
2379 	ret = scf_next_val(prop, SCF_TYPE_TIME);
2380 
2381 	if (ret == NULL)
2382 		return (NULL);
2383 
2384 	if (nsec != NULL)
2385 		*nsec = ret->pv_time.t_nsec;
2386 
2387 	return (&ret->pv_time.t_sec);
2388 }
2389 
2390 char *
2391 scf_simple_prop_next_astring(scf_simple_prop_t *prop)
2392 {
2393 	union scf_simple_prop_val *ret;
2394 
2395 	ret = scf_next_val(prop, SCF_TYPE_ASTRING);
2396 
2397 	if (ret == NULL)
2398 		return (NULL);
2399 
2400 	return (ret->pv_str);
2401 }
2402 
2403 char *
2404 scf_simple_prop_next_ustring(scf_simple_prop_t *prop)
2405 {
2406 	union scf_simple_prop_val *ret;
2407 
2408 	ret = scf_next_val(prop, SCF_TYPE_USTRING);
2409 
2410 	if (ret == NULL)
2411 		return (NULL);
2412 
2413 	return (ret->pv_str);
2414 }
2415 
2416 void *
2417 scf_simple_prop_next_opaque(scf_simple_prop_t *prop, size_t *length)
2418 {
2419 	union scf_simple_prop_val *ret;
2420 
2421 	ret = scf_next_val(prop, SCF_TYPE_OPAQUE);
2422 
2423 	if (ret == NULL) {
2424 		*length = 0;
2425 		return (NULL);
2426 	}
2427 
2428 	*length = ret->pv_opaque.o_size;
2429 	return (ret->pv_opaque.o_value);
2430 }
2431 
2432 /*
2433  * Generate a filename based on the fmri and the given name and return
2434  * it in the buffer of MAXPATHLEN provided by the caller.
2435  * If temp_filename is non-zero, also generate a temporary, unique filename
2436  * and return it in the temp buffer of MAXPATHLEN provided by the caller.
2437  * The path to the generated pathname is also created.
2438  * Given fmri should begin with a scheme such as "svc:".
2439  * Returns
2440  *      0 on success
2441  *      -1 if filename would exceed MAXPATHLEN or
2442  *	-2 if unable to create directory to filename path
2443  */
2444 int
2445 gen_filenms_from_fmri(const char *fmri, const char *name, char *filename,
2446     char *temp_filename)
2447 {
2448 	int		len;
2449 
2450 	len = strlen(SMF_SPEEDY_FILES_PATH);
2451 	len += strlen(fmri);
2452 	len += 2;			/* for slash and null */
2453 	len += strlen(name);
2454 	len += 6;			/* For X's needed for mkstemp */
2455 
2456 	if (len > MAXPATHLEN)
2457 		return (-1);
2458 
2459 	/* Construct directory name first - speedy path ends in slash */
2460 	(void) strcpy(filename, SMF_SPEEDY_FILES_PATH);
2461 	(void) strcat(filename, fmri);
2462 	if (mkdirp(filename, 0755) == -1) {
2463 		/* errno is set */
2464 		if (errno != EEXIST)
2465 			return (-2);
2466 	}
2467 
2468 	(void) strcat(filename, "/");
2469 	(void) strcat(filename, name);
2470 
2471 	if (temp_filename) {
2472 		(void) strcpy(temp_filename, filename);
2473 		(void) strcat(temp_filename, "XXXXXX");
2474 	}
2475 
2476 	return (0);
2477 }
2478