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