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