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