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