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