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