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