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