midlevel.c revision 3175:5903f61aa150
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 */
56static scf_handle_t *
57handle_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
78static char *
79assemble_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
138static scf_simple_prop_t *
139fill_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
309error1:
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
339error2:
340	scf_iter_destroy(iter);
341	(void) scf_value_destroy(val);
342
343error3:
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
358static int
359insert_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 */
436static int
437transaction_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
477static int
478get_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
502out:
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 */
515static int
516set_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
539get:
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
582set:
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
622out:
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
632static int
633delete_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
668error:
669	switch (scf_error()) {
670	case SCF_ERROR_DELETED:
671	case SCF_ERROR_NOT_FOUND:
672		/* success */
673		ret = 0;
674	}
675
676out:
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 */
695static int
696set_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
716get:
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. */
735add:
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
891out:
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
900static int
901set_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
934static int
935get_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
977out:
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 */
990static int
991set_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
1022out:
1023	return (ret);
1024}
1025
1026static int
1027set_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
1072out:
1073	scf_instance_destroy(inst);
1074	scf_handle_destroy(h);
1075	return (ret);
1076}
1077
1078int
1079smf_enable_instance(const char *fmri, int flags)
1080{
1081	return (set_inst_enabled_flags(fmri, flags, B_TRUE));
1082}
1083
1084int
1085smf_disable_instance(const char *fmri, int flags)
1086{
1087	return (set_inst_enabled_flags(fmri, flags, B_FALSE));
1088}
1089
1090int
1091_smf_refresh_instance_i(scf_instance_t *inst)
1092{
1093	return (set_inst_action_inst(inst, SCF_PROPERTY_REFRESH));
1094}
1095
1096int
1097smf_refresh_instance(const char *instance)
1098{
1099	return (set_inst_action(instance, SCF_PROPERTY_REFRESH));
1100}
1101
1102int
1103smf_restart_instance(const char *instance)
1104{
1105	return (set_inst_action(instance, SCF_PROPERTY_RESTART));
1106}
1107
1108int
1109smf_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
1123int
1124smf_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
1151int
1152smf_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
1179char *
1180smf_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
1202int
1203scf_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
1275out:
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
1287scf_simple_prop_t *
1288scf_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
1373error1:
1374	scf_service_destroy(svc);
1375	scf_property_destroy(prop);
1376error2:
1377	free(fmri_buf);
1378	if (local_h)
1379		scf_handle_destroy(h);
1380	return (NULL);
1381}
1382
1383
1384void
1385scf_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
1422scf_simple_app_props_t *
1423scf_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
1746error1:
1747	scf_simple_app_props_free(ret);
1748
1749error2:
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
1764void
1765scf_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
1792const scf_simple_prop_t *
1793scf_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
1857const scf_simple_prop_t *
1858scf_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
1902void
1903scf_simple_prop_next_reset(scf_simple_prop_t *prop)
1904{
1905	if (prop == NULL)
1906		return;
1907	prop->pr_iter = 0;
1908}
1909
1910ssize_t
1911scf_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
1920scf_type_t
1921scf_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
1930char *
1931scf_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
1942char *
1943scf_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
1954static union scf_simple_prop_val *
1955scf_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
1994uint8_t *
1995scf_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
2008uint64_t *
2009scf_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
2022int64_t *
2023scf_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
2035int64_t *
2036scf_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
2051char *
2052scf_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
2064char *
2065scf_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
2077void *
2078scf_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 */
2105int
2106gen_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