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