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 2012 Milan Jurik. All rights reserved.
  25  */
  26 
  27 
  28 #include <sys/contract/process.h>
  29 #include <assert.h>
  30 #include <errno.h>
  31 #include <libscf.h>
  32 #include <libscf_priv.h>
  33 #include <poll.h>
  34 #include <stdlib.h>
  35 #include <string.h>
  36 #include <unistd.h>
  37 
  38 #include "startd.h"
  39 
  40 #define SMF_SNAPSHOT_RUNNING    "running"
  41 
  42 #define INFO_EVENTS_ALL "info_events_all"
  43 
  44 char *
  45 inst_fmri_to_svc_fmri(const char *fmri)
  46 {
  47         char *buf, *sfmri;
  48         const char *scope, *svc;
  49         int r;
  50         boolean_t local;
  51 
  52         buf = startd_alloc(max_scf_fmri_size);
  53         sfmri = startd_alloc(max_scf_fmri_size);
  54 
  55         (void) strcpy(buf, fmri);
  56 
  57         r = scf_parse_svc_fmri(buf, &scope, &svc, NULL, NULL, NULL);
  58         assert(r == 0);
  59 
  60         local = strcmp(scope, SCF_SCOPE_LOCAL) == 0;
  61 
  62         (void) snprintf(sfmri, max_scf_fmri_size, "svc:%s%s/%s",
  63             local ? "" : "//", local ? "" : scope, svc);
  64 
  65         startd_free(buf, max_scf_fmri_size);
  66 
  67         return (sfmri);
  68 }
  69 
  70 /*
  71  * Wrapper for the scf_*_create() functions.  On SCF_ERROR_NO_MEMORY and
  72  * SCF_ERROR_NO_RESOURCES, retries or dies.  So this can only fail with
  73  * SCF_ERROR_INVALID_ARGUMENT, if h is NULL.
  74  */
  75 void *
  76 libscf_object_create(void *f(scf_handle_t *), scf_handle_t *h)
  77 {
  78         void *o;
  79         uint_t try, msecs;
  80         scf_error_t err;
  81 
  82         o = f(h);
  83         if (o != NULL)
  84                 return (o);
  85         err = scf_error();
  86         if (err != SCF_ERROR_NO_MEMORY && err != SCF_ERROR_NO_RESOURCES)
  87                 return (NULL);
  88 
  89         msecs = ALLOC_DELAY;
  90 
  91         for (try = 0; try < ALLOC_RETRY; ++try) {
  92                 (void) poll(NULL, 0, msecs);
  93                 msecs *= ALLOC_DELAY_MULT;
  94                 o = f(h);
  95                 if (o != NULL)
  96                         return (o);
  97                 err = scf_error();
  98                 if (err != SCF_ERROR_NO_MEMORY && err != SCF_ERROR_NO_RESOURCES)
  99                         return (NULL);
 100         }
 101 
 102         uu_die("Insufficient memory.\n");
 103         /* NOTREACHED */
 104 }
 105 
 106 scf_snapshot_t *
 107 libscf_get_running_snapshot(scf_instance_t *inst)
 108 {
 109         scf_handle_t *h;
 110         scf_snapshot_t *snap;
 111 
 112         h = scf_instance_handle(inst);
 113         if (h == NULL)
 114                 return (NULL);
 115 
 116         snap = scf_snapshot_create(h);
 117         if (snap == NULL)
 118                 return (NULL);
 119 
 120         if (scf_instance_get_snapshot(inst, SMF_SNAPSHOT_RUNNING, snap) == 0)
 121                 return (snap);
 122 
 123         scf_snapshot_destroy(snap);
 124         return (NULL);
 125 }
 126 
 127 /*
 128  * Make sure a service has a "running" snapshot.  If it doesn't, make one from
 129  * the editing configuration.
 130  */
 131 scf_snapshot_t *
 132 libscf_get_or_make_running_snapshot(scf_instance_t *inst, const char *fmri,
 133     boolean_t retake)
 134 {
 135         scf_handle_t *h;
 136         scf_snapshot_t *snap;
 137 
 138         h = scf_instance_handle(inst);
 139 
 140         snap = scf_snapshot_create(h);
 141         if (snap == NULL)
 142                 goto err;
 143 
 144         if (scf_instance_get_snapshot(inst, SMF_SNAPSHOT_RUNNING, snap) == 0)
 145                 return (snap);
 146 
 147         switch (scf_error()) {
 148         case SCF_ERROR_NOT_FOUND:
 149                 break;
 150 
 151         case SCF_ERROR_DELETED:
 152                 scf_snapshot_destroy(snap);
 153                 return (NULL);
 154 
 155         default:
 156 err:
 157                 log_error(LOG_NOTICE,
 158                     "Could not check for running snapshot of %s (%s).\n", fmri,
 159                     scf_strerror(scf_error()));
 160                 scf_snapshot_destroy(snap);
 161                 return (NULL);
 162         }
 163 
 164         if (_scf_snapshot_take_new(inst, SMF_SNAPSHOT_RUNNING, snap) == 0) {
 165                 log_framework(LOG_DEBUG, "Took running snapshot for %s.\n",
 166                     fmri);
 167         } else {
 168                 if (retake && scf_error() == SCF_ERROR_BACKEND_READONLY)
 169                         restarter_mark_pending_snapshot(fmri,
 170                             RINST_RETAKE_RUNNING);
 171                 else
 172                         log_error(LOG_DEBUG,
 173                             "Could not create running snapshot for %s "
 174                             "(%s).\n", fmri, scf_strerror(scf_error()));
 175 
 176                 scf_snapshot_destroy(snap);
 177                 snap = NULL;
 178         }
 179 
 180         return (snap);
 181 }
 182 
 183 /*
 184  * When a service comes up, point the "start" snapshot at the "running"
 185  * snapshot.  Returns 0 on success, ENOTSUP if fmri designates something other
 186  * than an instance, ECONNABORTED, ENOENT if the instance does not exist, or
 187  * EACCES.
 188  */
 189 int
 190 libscf_snapshots_poststart(scf_handle_t *h, const char *fmri, boolean_t retake)
 191 {
 192         scf_instance_t *inst = NULL;
 193         scf_snapshot_t *running, *start = NULL;
 194         int ret = 0, r;
 195 
 196         r = libscf_fmri_get_instance(h, fmri, &inst);
 197         switch (r) {
 198         case 0:
 199                 break;
 200 
 201         case ENOTSUP:
 202         case ECONNABORTED:
 203         case ENOENT:
 204                 return (r);
 205 
 206         case EINVAL:
 207         default:
 208                 assert(0);
 209                 abort();
 210         }
 211 
 212         start = safe_scf_snapshot_create(h);
 213 
 214 again:
 215         running = libscf_get_or_make_running_snapshot(inst, fmri, retake);
 216         if (running == NULL) {
 217                 ret = 0;
 218                 goto out;
 219         }
 220 
 221 lookup:
 222         if (scf_instance_get_snapshot(inst, "start", start) != 0) {
 223                 switch (scf_error()) {
 224                 case SCF_ERROR_CONNECTION_BROKEN:
 225                 default:
 226                         ret = ECONNABORTED;
 227                         goto out;
 228 
 229                 case SCF_ERROR_NOT_FOUND:
 230                         if (_scf_snapshot_take_new(inst, "start", start) != 0) {
 231                                 switch (scf_error()) {
 232                                 case SCF_ERROR_CONNECTION_BROKEN:
 233                                 default:
 234                                         ret = ECONNABORTED;
 235                                         goto out;
 236 
 237                                 case SCF_ERROR_DELETED:
 238                                         ret = ENOENT;
 239                                         goto out;
 240 
 241                                 case SCF_ERROR_EXISTS:
 242                                         goto lookup;
 243 
 244                                 case SCF_ERROR_NO_RESOURCES:
 245                                         uu_die("Repository server out of "
 246                                             "resources.\n");
 247                                         /* NOTREACHED */
 248 
 249                                 case SCF_ERROR_BACKEND_READONLY:
 250                                         goto readonly;
 251 
 252                                 case SCF_ERROR_PERMISSION_DENIED:
 253                                         uu_die("Insufficient privileges.\n");
 254                                         /* NOTREACHED */
 255 
 256                                 case SCF_ERROR_BACKEND_ACCESS:
 257                                         ret = EACCES;
 258                                         goto out;
 259 
 260                                 case SCF_ERROR_HANDLE_MISMATCH:
 261                                 case SCF_ERROR_INTERNAL:
 262                                 case SCF_ERROR_INVALID_ARGUMENT:
 263                                 case SCF_ERROR_NOT_SET:
 264                                         bad_error("_scf_snapshot_take_new",
 265                                             scf_error());
 266                                 }
 267                         }
 268                         break;
 269 
 270                 case SCF_ERROR_DELETED:
 271                         ret = ENOENT;
 272                         goto out;
 273 
 274                 case SCF_ERROR_HANDLE_MISMATCH:
 275                 case SCF_ERROR_NOT_SET:
 276                 case SCF_ERROR_INVALID_ARGUMENT:
 277                         bad_error("scf_instance_get_snapshot", scf_error());
 278                 }
 279         }
 280 
 281         if (_scf_snapshot_attach(running, start) == 0) {
 282                 log_framework(LOG_DEBUG, "Updated \"start\" snapshot for %s.\n",
 283                     fmri);
 284         } else {
 285                 switch (scf_error()) {
 286                 case SCF_ERROR_CONNECTION_BROKEN:
 287                 default:
 288                         ret = ECONNABORTED;
 289                         goto out;
 290 
 291                 case SCF_ERROR_DELETED:
 292                         scf_snapshot_destroy(running);
 293                         goto again;
 294 
 295                 case SCF_ERROR_NO_RESOURCES:
 296                         uu_die("Repository server out of resources.\n");
 297                         /* NOTREACHED */
 298 
 299                 case SCF_ERROR_PERMISSION_DENIED:
 300                         uu_die("Insufficient privileges.\n");
 301                         /* NOTREACHED */
 302 
 303                 case SCF_ERROR_BACKEND_ACCESS:
 304                         ret = EACCES;
 305                         goto out;
 306 
 307                 case SCF_ERROR_BACKEND_READONLY:
 308 readonly:
 309                         if (retake)
 310                                 restarter_mark_pending_snapshot(fmri,
 311                                     RINST_RETAKE_START);
 312                         break;
 313 
 314                 case SCF_ERROR_HANDLE_MISMATCH:
 315                 case SCF_ERROR_NOT_SET:
 316                         bad_error("_scf_snapshot_attach", scf_error());
 317                 }
 318         }
 319 
 320 out:
 321         scf_snapshot_destroy(start);
 322         scf_snapshot_destroy(running);
 323         scf_instance_destroy(inst);
 324 
 325         return (ret);
 326 }
 327 
 328 /*
 329  * Before a refresh, update the "running" snapshot from the editing
 330  * configuration.
 331  *
 332  * Returns 0 on success and -1 on failure.
 333  */
 334 int
 335 libscf_snapshots_refresh(scf_instance_t *inst, const char *fmri)
 336 {
 337         scf_handle_t *h;
 338         scf_snapshot_t *snap;
 339         boolean_t err = 1;
 340 
 341         h = scf_instance_handle(inst);
 342         if (h == NULL)
 343                 goto out;
 344 
 345         snap = scf_snapshot_create(h);
 346         if (snap == NULL)
 347                 goto out;
 348 
 349         if (scf_instance_get_snapshot(inst, SMF_SNAPSHOT_RUNNING, snap) == 0) {
 350                 if (_scf_snapshot_take_attach(inst, snap) == 0)
 351                         err = 0;
 352         } else {
 353                 switch (scf_error()) {
 354                 case SCF_ERROR_DELETED:
 355                         err = 0;
 356                         goto out;
 357 
 358                 case SCF_ERROR_NOT_FOUND:
 359                         break;
 360 
 361                 case SCF_ERROR_NOT_SET:
 362                         assert(0);
 363                         abort();
 364                         /* NOTREACHED */
 365 
 366                 default:
 367                         goto out;
 368                 }
 369 
 370                 log_error(LOG_DEBUG,
 371                     "Service %s has no %s snapshot; creating one.\n", fmri,
 372                     SMF_SNAPSHOT_RUNNING);
 373 
 374                 if (_scf_snapshot_take_new(inst, SMF_SNAPSHOT_RUNNING,
 375                     snap) == 0)
 376                         err = 0;
 377         }
 378 
 379 out:
 380         scf_snapshot_destroy(snap);
 381 
 382         if (!err)
 383                 return (0);
 384 
 385         log_error(LOG_WARNING,
 386             "Could not update \"running\" snapshot for refresh of %s.\n", fmri);
 387         return (-1);
 388 }
 389 
 390 /*
 391  * int libscf_read_single_astring()
 392  *   Reads a single astring value of the requested property into the
 393  *   pre-allocated buffer (conventionally of size max_scf_value_size).
 394  *   Multiple values constitute an error.
 395  *
 396  * Returns 0 on success or LIBSCF_PROPERTY_ABSENT or LIBSCF_PROPERTY_ERROR.
 397  */
 398 static int
 399 libscf_read_single_astring(scf_handle_t *h, scf_property_t *prop, char **ret)
 400 {
 401         scf_value_t *val = safe_scf_value_create(h);
 402         int r = 0;
 403 
 404         if (scf_property_get_value(prop, val) == -1) {
 405                 if (scf_error() == SCF_ERROR_NOT_FOUND)
 406                         r = LIBSCF_PROPERTY_ABSENT;
 407                 else
 408                         r = LIBSCF_PROPERTY_ERROR;
 409                 goto read_single_astring_fail;
 410         }
 411 
 412         if (scf_value_get_astring(val, *ret, max_scf_value_size) <= 0) {
 413                 r = LIBSCF_PROPERTY_ERROR;
 414                 goto read_single_astring_fail;
 415         }
 416 
 417 read_single_astring_fail:
 418         scf_value_destroy(val);
 419         return (r);
 420 }
 421 
 422 /*
 423  * libscf_get_stn_tset
 424  */
 425 int32_t
 426 libscf_get_stn_tset(scf_instance_t *inst)
 427 {
 428         scf_handle_t            *h = scf_instance_handle(inst);
 429         scf_propertygroup_t     *pg = scf_pg_create(h);
 430         char                    *pgname = NULL;
 431         int32_t                 t, f, tset;
 432 
 433         assert(inst != NULL);
 434 
 435         pgname =  startd_alloc(max_scf_fmri_size);
 436         if (h == NULL || pg == NULL) {
 437                 tset = -1;
 438                 goto cleanup;
 439         }
 440 
 441         for (tset = 0, t = 1; t < SCF_STATE_ALL; t <<= 1) {
 442                 f = t << 16;
 443 
 444                 (void) strcpy(pgname, SCF_STN_PREFIX_TO);
 445                 (void) strlcat(pgname, smf_state_to_string(t),
 446                     max_scf_fmri_size);
 447 
 448                 if (scf_instance_get_pg_composed(inst, NULL, pgname, pg) ==
 449                     SCF_SUCCESS) {
 450                         tset |= t;
 451                 } else if (scf_error() != SCF_ERROR_NOT_FOUND && scf_error() !=
 452                     SCF_ERROR_DELETED) {
 453                         tset = -1;
 454                         goto cleanup;
 455                 }
 456 
 457                 (void) strcpy(pgname, SCF_STN_PREFIX_FROM);
 458                 (void) strlcat(pgname, smf_state_to_string(t),
 459                     max_scf_fmri_size);
 460 
 461                 if (scf_instance_get_pg_composed(inst, NULL, pgname, pg) ==
 462                     SCF_SUCCESS) {
 463                         tset |= f;
 464                 } else if (scf_error() != SCF_ERROR_NOT_FOUND && scf_error() !=
 465                     SCF_ERROR_DELETED) {
 466                         tset = -1;
 467                         goto cleanup;
 468                 }
 469         }
 470 
 471 cleanup:
 472         scf_pg_destroy(pg);
 473         startd_free(pgname, max_scf_fmri_size);
 474 
 475         return (tset);
 476 }
 477 
 478 static int32_t
 479 libscf_get_global_stn_tset(scf_handle_t *h)
 480 {
 481         scf_instance_t  *inst = scf_instance_create(h);
 482         int32_t         tset = -1;
 483 
 484         if (inst == NULL) {
 485                 goto cleanup;
 486         }
 487 
 488         if (scf_handle_decode_fmri(h, SCF_INSTANCE_GLOBAL, NULL, NULL, inst,
 489             NULL, NULL, SCF_DECODE_FMRI_REQUIRE_INSTANCE) != 0) {
 490                 goto cleanup;
 491         }
 492 
 493         tset = libscf_get_stn_tset(inst);
 494 
 495 cleanup:
 496         scf_instance_destroy(inst);
 497 
 498         if (tset == -1)
 499                 log_framework(LOG_WARNING,
 500                     "Failed to get system wide notification parameters: %s\n",
 501                     scf_strerror(scf_error()));
 502 
 503         return (tset);
 504 }
 505 
 506 static int
 507 libscf_read_state(const scf_propertygroup_t *pg, const char *prop_name,
 508     restarter_instance_state_t *state)
 509 {
 510         scf_handle_t *h;
 511         scf_property_t *prop;
 512         char *char_state = startd_alloc(max_scf_value_size);
 513         int ret = 0;
 514 
 515         h = scf_pg_handle(pg);
 516         prop = safe_scf_property_create(h);
 517 
 518         if (scf_pg_get_property(pg, prop_name, prop) == -1) {
 519                 if (scf_error() == SCF_ERROR_NOT_FOUND)
 520                         ret = LIBSCF_PROPERTY_ABSENT;
 521                 else
 522                         ret = LIBSCF_PROPERTY_ERROR;
 523         } else {
 524                 ret = libscf_read_single_astring(h, prop, &char_state);
 525                 if (ret != 0) {
 526                         if (ret != LIBSCF_PROPERTY_ABSENT)
 527                                 ret = LIBSCF_PROPERTY_ERROR;
 528                 } else {
 529                         *state = restarter_string_to_state(char_state);
 530                         ret = 0;
 531                 }
 532         }
 533 
 534         startd_free(char_state, max_scf_value_size);
 535         scf_property_destroy(prop);
 536         return (ret);
 537 }
 538 
 539 /*
 540  * int libscf_read_states(const scf_propertygroup_t *,
 541  *   restarter_instance_state_t *, restarter_instance_state_t *)
 542  *
 543  *   Set the current state and next_state values for the given service instance.
 544  *   Returns 0 on success, or a libscf error code on failure.
 545  */
 546 int
 547 libscf_read_states(const scf_propertygroup_t *pg,
 548     restarter_instance_state_t *state, restarter_instance_state_t *next_state)
 549 {
 550         int state_ret, next_state_ret, ret;
 551 
 552         state_ret = libscf_read_state(pg, SCF_PROPERTY_STATE, state);
 553         next_state_ret = libscf_read_state(pg, SCF_PROPERTY_NEXT_STATE,
 554             next_state);
 555 
 556         if (state_ret == LIBSCF_PROPERTY_ERROR ||
 557             next_state_ret == LIBSCF_PROPERTY_ERROR) {
 558                 ret = LIBSCF_PROPERTY_ERROR;
 559         } else if (state_ret == 0 && next_state_ret == 0) {
 560                 ret = 0;
 561         } else if (state_ret == LIBSCF_PROPERTY_ABSENT &&
 562             next_state_ret == LIBSCF_PROPERTY_ABSENT) {
 563                 *state = RESTARTER_STATE_UNINIT;
 564                 *next_state = RESTARTER_STATE_NONE;
 565                 ret = 0;
 566         } else if (state_ret == LIBSCF_PROPERTY_ABSENT ||
 567             next_state_ret == LIBSCF_PROPERTY_ABSENT) {
 568                 log_framework(LOG_DEBUG,
 569                     "Only one repository state exists, setting "
 570                     "restarter states to MAINTENANCE and NONE\n");
 571                 *state = RESTARTER_STATE_MAINT;
 572                 *next_state = RESTARTER_STATE_NONE;
 573                 ret = 0;
 574         } else {
 575                 ret = LIBSCF_PROPERTY_ERROR;
 576         }
 577 
 578 read_states_out:
 579         return (ret);
 580 }
 581 
 582 /*
 583  * depgroup_empty()
 584  *
 585  * Returns 0 if not empty.
 586  * Returns 1 if empty.
 587  * Returns -1 on error (check scf_error()).
 588  */
 589 int
 590 depgroup_empty(scf_handle_t *h, scf_propertygroup_t *pg)
 591 {
 592         int empty = 1;
 593         scf_iter_t *iter;
 594         scf_property_t *prop;
 595         int ret;
 596 
 597         iter = safe_scf_iter_create(h);
 598         prop = safe_scf_property_create(h);
 599 
 600         if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS) {
 601                 scf_property_destroy(prop);
 602                 scf_iter_destroy(iter);
 603                 return (-1);
 604         }
 605 
 606         ret = scf_iter_next_property(iter, prop);
 607         if (ret < 0) {
 608                 scf_property_destroy(prop);
 609                 scf_iter_destroy(iter);
 610                 return (-1);
 611         }
 612 
 613         if (ret == 1)
 614                 empty = 0;
 615 
 616         scf_property_destroy(prop);
 617         scf_iter_destroy(iter);
 618 
 619         return (empty);
 620 }
 621 
 622 gv_type_t
 623 depgroup_read_scheme(scf_handle_t *h, scf_propertygroup_t *pg)
 624 {
 625         scf_property_t *prop;
 626         char *scheme = startd_alloc(max_scf_value_size);
 627         gv_type_t ret;
 628 
 629         prop = safe_scf_property_create(h);
 630 
 631         if (scf_pg_get_property(pg, SCF_PROPERTY_TYPE, prop) == -1 ||
 632             libscf_read_single_astring(h, prop, &scheme) != 0) {
 633                 scf_property_destroy(prop);
 634                 startd_free(scheme, max_scf_value_size);
 635                 return (GVT_UNSUPPORTED);
 636         }
 637 
 638         if (strcmp(scheme, "service") == 0)
 639                 ret = GVT_INST;
 640         else if (strcmp(scheme, "path") == 0)
 641                 ret = GVT_FILE;
 642         else
 643                 ret = GVT_UNSUPPORTED;
 644 
 645         startd_free(scheme, max_scf_value_size);
 646         scf_property_destroy(prop);
 647         return (ret);
 648 }
 649 
 650 depgroup_type_t
 651 depgroup_read_grouping(scf_handle_t *h, scf_propertygroup_t *pg)
 652 {
 653         char *grouping = startd_alloc(max_scf_value_size);
 654         depgroup_type_t ret;
 655         scf_property_t *prop = safe_scf_property_create(h);
 656 
 657         if (scf_pg_get_property(pg, SCF_PROPERTY_GROUPING, prop) == -1 ||
 658             libscf_read_single_astring(h, prop, &grouping) != 0) {
 659                 scf_property_destroy(prop);
 660                 startd_free(grouping, max_scf_value_size);
 661                 return (DEPGRP_UNSUPPORTED);
 662         }
 663 
 664         if (strcmp(grouping, SCF_DEP_REQUIRE_ANY) == 0)
 665                 ret = DEPGRP_REQUIRE_ANY;
 666         else if (strcmp(grouping, SCF_DEP_REQUIRE_ALL) == 0)
 667                 ret = DEPGRP_REQUIRE_ALL;
 668         else if (strcmp(grouping, SCF_DEP_OPTIONAL_ALL) == 0)
 669                 ret = DEPGRP_OPTIONAL_ALL;
 670         else if (strcmp(grouping, SCF_DEP_EXCLUDE_ALL) == 0)
 671                 ret = DEPGRP_EXCLUDE_ALL;
 672         else {
 673                 ret = DEPGRP_UNSUPPORTED;
 674         }
 675         startd_free(grouping, max_scf_value_size);
 676         scf_property_destroy(prop);
 677         return (ret);
 678 }
 679 
 680 restarter_error_t
 681 depgroup_read_restart(scf_handle_t *h, scf_propertygroup_t *pg)
 682 {
 683         scf_property_t *prop = safe_scf_property_create(h);
 684         char *restart_on = startd_alloc(max_scf_value_size);
 685         restarter_error_t ret;
 686 
 687         if (scf_pg_get_property(pg, SCF_PROPERTY_RESTART_ON, prop) == -1 ||
 688             libscf_read_single_astring(h, prop, &restart_on) != 0) {
 689                 startd_free(restart_on, max_scf_value_size);
 690                 scf_property_destroy(prop);
 691                 return (RERR_UNSUPPORTED);
 692         }
 693 
 694         if (strcmp(restart_on, SCF_DEP_RESET_ON_ERROR) == 0)
 695                 ret = RERR_FAULT;
 696         else if (strcmp(restart_on, SCF_DEP_RESET_ON_RESTART) == 0)
 697                 ret = RERR_RESTART;
 698         else if (strcmp(restart_on, SCF_DEP_RESET_ON_REFRESH) == 0)
 699                 ret = RERR_REFRESH;
 700         else if (strcmp(restart_on, SCF_DEP_RESET_ON_NONE) == 0)
 701                 ret = RERR_NONE;
 702         else
 703                 ret = RERR_UNSUPPORTED;
 704 
 705         startd_free(restart_on, max_scf_value_size);
 706         scf_property_destroy(prop);
 707         return (ret);
 708 }
 709 
 710 /*
 711  * int get_boolean()
 712  *   Fetches the value of a boolean property of the given property group.
 713  *   Returns
 714  *     0 - success
 715  *     ECONNABORTED - repository connection broken
 716  *     ECANCELED - pg was deleted
 717  *     ENOENT - the property doesn't exist or has no values
 718  *     EINVAL - the property has the wrong type
 719  *              the property is not single-valued
 720  *     EACCES - the current user does not have permission to read the value
 721  */
 722 static int
 723 get_boolean(scf_propertygroup_t *pg, const char *propname, uint8_t *valuep)
 724 {
 725         scf_handle_t *h;
 726         scf_property_t *prop;
 727         scf_value_t *val;
 728         int ret = 0, r;
 729         scf_type_t type;
 730 
 731         h = scf_pg_handle(pg);
 732         prop = safe_scf_property_create(h);
 733         val = safe_scf_value_create(h);
 734 
 735         if (scf_pg_get_property(pg, propname, prop) != 0) {
 736                 switch (scf_error()) {
 737                 case SCF_ERROR_CONNECTION_BROKEN:
 738                 default:
 739                         ret = ECONNABORTED;
 740                         goto out;
 741 
 742                 case SCF_ERROR_DELETED:
 743                         ret = ECANCELED;
 744                         goto out;
 745 
 746                 case SCF_ERROR_NOT_FOUND:
 747                         ret = ENOENT;
 748                         goto out;
 749 
 750                 case SCF_ERROR_HANDLE_MISMATCH:
 751                 case SCF_ERROR_INVALID_ARGUMENT:
 752                 case SCF_ERROR_NOT_SET:
 753                         bad_error("scf_pg_get_property", scf_error());
 754                 }
 755         }
 756 
 757         if (scf_property_type(prop, &type) != 0) {
 758                 switch (scf_error()) {
 759                 case SCF_ERROR_CONNECTION_BROKEN:
 760                 default:
 761                         ret = ECONNABORTED;
 762                         goto out;
 763 
 764                 case SCF_ERROR_DELETED:
 765                         ret = ENOENT;
 766                         goto out;
 767 
 768                 case SCF_ERROR_NOT_SET:
 769                         bad_error("scf_property_type", scf_error());
 770                 }
 771         }
 772 
 773         if (type != SCF_TYPE_BOOLEAN) {
 774                 ret = EINVAL;
 775                 goto out;
 776         }
 777 
 778         if (scf_property_get_value(prop, val) != 0) {
 779                 switch (scf_error()) {
 780                 case SCF_ERROR_CONNECTION_BROKEN:
 781                 default:
 782                         ret = ECONNABORTED;
 783                         goto out;
 784 
 785                 case SCF_ERROR_DELETED:
 786                 case SCF_ERROR_NOT_FOUND:
 787                         ret = ENOENT;
 788                         goto out;
 789 
 790                 case SCF_ERROR_CONSTRAINT_VIOLATED:
 791                         ret = EINVAL;
 792                         goto out;
 793 
 794                 case SCF_ERROR_PERMISSION_DENIED:
 795                         ret = EACCES;
 796                         goto out;
 797 
 798                 case SCF_ERROR_NOT_SET:
 799                         bad_error("scf_property_get_value", scf_error());
 800                 }
 801         }
 802 
 803         r = scf_value_get_boolean(val, valuep);
 804         assert(r == 0);
 805 
 806 out:
 807         scf_value_destroy(val);
 808         scf_property_destroy(prop);
 809         return (ret);
 810 }
 811 
 812 /*
 813  * get info event property from restarter:default
 814  */
 815 int
 816 libscf_get_info_events_all(scf_propertygroup_t *pg)
 817 {
 818         uint8_t v;
 819         int r = 0;
 820 
 821         if (get_boolean(pg, INFO_EVENTS_ALL, &v) == 0) {
 822                 r = v;
 823         } else if (scf_error() != SCF_ERROR_NOT_FOUND) {
 824                 uu_warn("Failed get_boolean %s/%s: %s\n",
 825                     SCF_PG_OPTIONS, INFO_EVENTS_ALL,
 826                     scf_strerror(scf_error()));
 827         }
 828 
 829         return (r);
 830 }
 831 
 832 /*
 833  * int get_count()
 834  *   Fetches the value of a count property of the given property group.
 835  *   Returns
 836  *     0 - success
 837  *     ECONNABORTED - repository connection broken
 838  *                    unknown libscf error
 839  *     ECANCELED - pg was deleted
 840  *     ENOENT - the property doesn't exist or has no values
 841  *     EINVAL - the property has the wrong type
 842  *              the property is not single-valued
 843  *     EACCES - the current user does not have permission to read the value
 844  */
 845 static int
 846 get_count(scf_propertygroup_t *pg, const char *propname, uint64_t *valuep)
 847 {
 848         scf_handle_t *h;
 849         scf_property_t *prop;
 850         scf_value_t *val;
 851         int ret = 0, r;
 852 
 853         h = scf_pg_handle(pg);
 854         prop = safe_scf_property_create(h);
 855         val = safe_scf_value_create(h);
 856 
 857         if (scf_pg_get_property(pg, propname, prop) != 0) {
 858                 switch (scf_error()) {
 859                 case SCF_ERROR_CONNECTION_BROKEN:
 860                 default:
 861                         ret = ECONNABORTED;
 862                         goto out;
 863 
 864                 case SCF_ERROR_DELETED:
 865                         ret = ECANCELED;
 866                         goto out;
 867 
 868                 case SCF_ERROR_NOT_FOUND:
 869                         ret = ENOENT;
 870                         goto out;
 871 
 872                 case SCF_ERROR_HANDLE_MISMATCH:
 873                 case SCF_ERROR_INVALID_ARGUMENT:
 874                 case SCF_ERROR_NOT_SET:
 875                         bad_error("scf_pg_get_property", scf_error());
 876                 }
 877         }
 878 
 879         if (scf_property_is_type(prop, SCF_TYPE_COUNT) != 0) {
 880                 switch (scf_error()) {
 881                 case SCF_ERROR_CONNECTION_BROKEN:
 882                 default:
 883                         ret = ECONNABORTED;
 884                         goto out;
 885 
 886                 case SCF_ERROR_TYPE_MISMATCH:
 887                         ret = EINVAL;
 888                         goto out;
 889 
 890                 case SCF_ERROR_DELETED:
 891                         ret = ECANCELED;
 892                         goto out;
 893 
 894                 case SCF_ERROR_INVALID_ARGUMENT:
 895                 case SCF_ERROR_NOT_BOUND:
 896                 case SCF_ERROR_NOT_SET:
 897                         bad_error("scf_property_is_type", scf_error());
 898                 }
 899         }
 900 
 901         if (scf_property_get_value(prop, val) != 0) {
 902                 switch (scf_error()) {
 903                 case SCF_ERROR_CONNECTION_BROKEN:
 904                 default:
 905                         ret = ECONNABORTED;
 906                         goto out;
 907 
 908                 case SCF_ERROR_DELETED:
 909                         ret = ECANCELED;
 910                         goto out;
 911 
 912                 case SCF_ERROR_NOT_FOUND:
 913                         ret = ENOENT;
 914                         goto out;
 915 
 916                 case SCF_ERROR_CONSTRAINT_VIOLATED:
 917                         ret = EINVAL;
 918                         goto out;
 919 
 920                 case SCF_ERROR_PERMISSION_DENIED:
 921                         ret = EACCES;
 922                         goto out;
 923 
 924                 case SCF_ERROR_NOT_SET:
 925                         bad_error("scf_property_get_value", scf_error());
 926                 }
 927         }
 928 
 929         r = scf_value_get_count(val, valuep);
 930         assert(r == 0);
 931 
 932 out:
 933         scf_value_destroy(val);
 934         scf_property_destroy(prop);
 935         return (ret);
 936 }
 937 
 938 
 939 static void
 940 get_restarter(scf_handle_t *h, scf_propertygroup_t *pg, char **restarter)
 941 {
 942         scf_property_t *prop = safe_scf_property_create(h);
 943 
 944         if (scf_pg_get_property(pg, SCF_PROPERTY_RESTARTER, prop) == -1 ||
 945             libscf_read_single_astring(h, prop, restarter) != 0)
 946                 *restarter[0] = '\0';
 947 
 948         scf_property_destroy(prop);
 949 }
 950 
 951 /*
 952  * int libscf_instance_get_fmri(scf_instance_t *, char **)
 953  *   Give a valid SCF instance, return its FMRI.  Returns 0 on success,
 954  *   ECONNABORTED, or ECANCELED if inst is deleted.
 955  */
 956 int
 957 libscf_instance_get_fmri(scf_instance_t *inst, char **retp)
 958 {
 959         char *inst_fmri = startd_alloc(max_scf_fmri_size);
 960 
 961         inst_fmri[0] = 0;
 962         if (scf_instance_to_fmri(inst, inst_fmri, max_scf_fmri_size) <= 0) {
 963                 startd_free(inst_fmri, max_scf_fmri_size);
 964                 switch (scf_error()) {
 965                 case SCF_ERROR_CONNECTION_BROKEN:
 966                 default:
 967                         return (ECONNABORTED);
 968 
 969                 case SCF_ERROR_DELETED:
 970                         return (ECANCELED);
 971 
 972                 case SCF_ERROR_NOT_SET:
 973                         assert(0);
 974                         abort();
 975                 }
 976         }
 977 
 978         *retp = inst_fmri;
 979         return (0);
 980 }
 981 
 982 /*
 983  * int libscf_fmri_get_instance(scf_handle_t *, const char *,
 984  *      scf_instance_t **)
 985  *   Given a valid SCF handle and an FMRI, return the SCF instance that matches
 986  *   exactly.  The instance must be released using scf_instance_destroy().
 987  *   Returns 0 on success, EINVAL if the FMRI is invalid, ENOTSUP if the FMRI
 988  *   is valid but designates something other than an instance, ECONNABORTED if
 989  *   the repository connection is broken, or ENOENT if the instance does not
 990  *   exist.
 991  */
 992 int
 993 libscf_fmri_get_instance(scf_handle_t *h, const char *fmri,
 994     scf_instance_t **instp)
 995 {
 996         scf_instance_t *inst;
 997         int r;
 998 
 999         inst = safe_scf_instance_create(h);
1000 
1001         r = libscf_lookup_instance(fmri, inst);
1002 
1003         if (r == 0)
1004                 *instp = inst;
1005         else
1006                 scf_instance_destroy(inst);
1007 
1008         return (r);
1009 }
1010 
1011 int
1012 libscf_lookup_instance(const char *fmri, scf_instance_t *inst)
1013 {
1014         if (scf_handle_decode_fmri(scf_instance_handle(inst), fmri, NULL, NULL,
1015             inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1016                 switch (scf_error()) {
1017                 case SCF_ERROR_INVALID_ARGUMENT:
1018                         return (EINVAL);
1019 
1020                 case SCF_ERROR_CONSTRAINT_VIOLATED:
1021                         return (ENOTSUP);
1022 
1023                 case SCF_ERROR_CONNECTION_BROKEN:
1024                         return (ECONNABORTED);
1025 
1026                 case SCF_ERROR_NOT_FOUND:
1027                         return (ENOENT);
1028 
1029                 case SCF_ERROR_HANDLE_MISMATCH:
1030                 default:
1031                         bad_error("scf_handle_decode_fmri", scf_error());
1032                 }
1033         }
1034 
1035         return (0);
1036 }
1037 
1038 /*
1039  * int libscf_get_deathrow()
1040  * Read deathrow for inst. Returns 0, ECONNABORTED if the connection to the
1041  * repository is broken, ECANCELED if inst is deleted, or ENOENT if inst
1042  * has no deathrow property group.
1043  *
1044  * If deathrow/deathrow was missing or invalid, *deathrow will be -1 and a
1045  * debug message is logged.
1046  */
1047 int
1048 libscf_get_deathrow(scf_handle_t *h, scf_instance_t *inst, int *deathrow)
1049 {
1050         scf_propertygroup_t *pg;
1051         int r;
1052         uint8_t deathrow_8;
1053 
1054         pg = safe_scf_pg_create(h);
1055 
1056         if (scf_instance_get_pg_composed(inst, NULL, SCF_PG_DEATHROW, pg) !=
1057             0) {
1058                 switch (scf_error()) {
1059                 case SCF_ERROR_CONNECTION_BROKEN:
1060                 default:
1061                         scf_pg_destroy(pg);
1062                         return (ECONNABORTED);
1063 
1064                 case SCF_ERROR_DELETED:
1065                         scf_pg_destroy(pg);
1066                         return (ECANCELED);
1067 
1068                 case SCF_ERROR_NOT_FOUND:
1069                         *deathrow = -1;
1070                         break;
1071 
1072                 case SCF_ERROR_HANDLE_MISMATCH:
1073                 case SCF_ERROR_INVALID_ARGUMENT:
1074                 case SCF_ERROR_NOT_SET:
1075                         bad_error("libscf_get_deathrow", scf_error());
1076                 }
1077         } else {
1078                 switch (r = get_boolean(pg,
1079                     SCF_PROPERTY_DEATHROW, &deathrow_8)) {
1080                 case 0:
1081                         *deathrow = deathrow_8;
1082                         break;
1083 
1084                 case ECONNABORTED:
1085                 case ECANCELED:
1086                         scf_pg_destroy(pg);
1087                         return (r);
1088 
1089                 case ENOENT:
1090                 case EINVAL:
1091                         *deathrow = -1;
1092                         break;
1093 
1094                 default:
1095                         bad_error("get_boolean", r);
1096                 }
1097         }
1098 
1099         scf_pg_destroy(pg);
1100 
1101         return (0);
1102 }
1103 
1104 /*
1105  * void libscf_get_basic_instance_data()
1106  *   Read enabled, enabled_ovr, and restarter_fmri (into an allocated
1107  *   buffer) for inst.  Returns 0, ECONNABORTED if the connection to the
1108  *   repository is broken, ECANCELED if inst is deleted, or ENOENT if inst
1109  *   has no general property group.
1110  *
1111  *   On success, restarter_fmri may be NULL.  If general/enabled was missing
1112  *   or invalid, *enabledp will be -1 and a debug message is logged.
1113  */
1114 int
1115 libscf_get_basic_instance_data(scf_handle_t *h, scf_instance_t *inst,
1116     const char *fmri, int *enabledp, int *enabled_ovrp, char **restarter_fmri)
1117 {
1118         scf_propertygroup_t *pg;
1119         int r;
1120         uint8_t enabled_8;
1121 
1122         pg = safe_scf_pg_create(h);
1123 
1124         if (enabled_ovrp == NULL)
1125                 goto enabled;
1126 
1127         if (scf_instance_get_pg_composed(inst, NULL, SCF_PG_GENERAL_OVR, pg) !=
1128             0) {
1129                 switch (scf_error()) {
1130                 case SCF_ERROR_CONNECTION_BROKEN:
1131                 default:
1132                         scf_pg_destroy(pg);
1133                         return (ECONNABORTED);
1134 
1135                 case SCF_ERROR_DELETED:
1136                         scf_pg_destroy(pg);
1137                         return (ECANCELED);
1138 
1139                 case SCF_ERROR_NOT_FOUND:
1140                         *enabled_ovrp = -1;
1141                         break;
1142 
1143                 case SCF_ERROR_HANDLE_MISMATCH:
1144                 case SCF_ERROR_INVALID_ARGUMENT:
1145                 case SCF_ERROR_NOT_SET:
1146                         bad_error("scf_instance_get_pg_composed", scf_error());
1147                 }
1148         } else {
1149                 switch (r = get_boolean(pg, SCF_PROPERTY_ENABLED, &enabled_8)) {
1150                 case 0:
1151                         *enabled_ovrp = enabled_8;
1152                         break;
1153 
1154                 case ECONNABORTED:
1155                 case ECANCELED:
1156                         scf_pg_destroy(pg);
1157                         return (r);
1158 
1159                 case ENOENT:
1160                 case EINVAL:
1161                         *enabled_ovrp = -1;
1162                         break;
1163 
1164                 case EACCES:
1165                 default:
1166                         bad_error("get_boolean", r);
1167                 }
1168         }
1169 
1170 enabled:
1171         /*
1172          * Since general/restarter can be at the service level, we must do
1173          * a composed lookup.  These properties are immediate, though, so we
1174          * must use the "editing" snapshot.  Technically enabled shouldn't be
1175          * at the service level, but looking it up composed, too, doesn't
1176          * hurt.
1177          */
1178         if (scf_instance_get_pg_composed(inst, NULL, SCF_PG_GENERAL, pg) != 0) {
1179                 scf_pg_destroy(pg);
1180                 switch (scf_error()) {
1181                 case SCF_ERROR_CONNECTION_BROKEN:
1182                 default:
1183                         return (ECONNABORTED);
1184 
1185                 case SCF_ERROR_DELETED:
1186                         return (ECANCELED);
1187 
1188                 case SCF_ERROR_NOT_FOUND:
1189                         return (ENOENT);
1190 
1191                 case SCF_ERROR_NOT_SET:
1192                         bad_error("scf_instance_get_pg_composed", scf_error());
1193                 }
1194         }
1195 
1196         switch (r = get_boolean(pg, SCF_PROPERTY_ENABLED, &enabled_8)) {
1197         case 0:
1198                 *enabledp = enabled_8;
1199                 break;
1200 
1201         case ECONNABORTED:
1202         case ECANCELED:
1203                 scf_pg_destroy(pg);
1204                 return (r);
1205 
1206         case ENOENT:
1207                 /*
1208                  * DEBUG because this happens when svccfg import creates
1209                  * a temporary service.
1210                  */
1211                 log_framework(LOG_DEBUG,
1212                     "general/enabled property of %s is missing.\n", fmri);
1213                 *enabledp = -1;
1214                 break;
1215 
1216         case EINVAL:
1217                 log_framework(LOG_ERR,
1218                     "general/enabled property of %s is invalid.\n", fmri);
1219                 *enabledp = -1;
1220                 break;
1221 
1222         case EACCES:
1223         default:
1224                 bad_error("get_boolean", r);
1225         }
1226 
1227         if (restarter_fmri != NULL)
1228                 get_restarter(h, pg, restarter_fmri);
1229 
1230         scf_pg_destroy(pg);
1231 
1232         return (0);
1233 }
1234 
1235 /*
1236  * Sets pg to the name property group of s_inst.  If it doesn't exist, it is
1237  * added.
1238  *
1239  * Fails with
1240  *   ECONNABORTED - repository disconnection or unknown libscf error
1241  *   ECANCELED - inst is deleted
1242  *   EPERM - permission is denied
1243  *   EACCES - backend denied access
1244  *   EROFS - backend readonly
1245  */
1246 int
1247 libscf_inst_get_or_add_pg(scf_instance_t *inst, const char *name,
1248     const char *type, uint32_t flags, scf_propertygroup_t *pg)
1249 {
1250         uint32_t f;
1251 
1252 again:
1253         if (scf_instance_get_pg(inst, name, pg) == 0) {
1254                 if (scf_pg_get_flags(pg, &f) != 0) {
1255                         switch (scf_error()) {
1256                         case SCF_ERROR_CONNECTION_BROKEN:
1257                         default:
1258                                 return (ECONNABORTED);
1259 
1260                         case SCF_ERROR_DELETED:
1261                                 goto add;
1262 
1263                         case SCF_ERROR_NOT_SET:
1264                                 bad_error("scf_pg_get_flags", scf_error());
1265                         }
1266                 }
1267 
1268                 if (f == flags)
1269                         return (0);
1270 
1271                 if (scf_pg_delete(pg) != 0) {
1272                         switch (scf_error()) {
1273                         case SCF_ERROR_CONNECTION_BROKEN:
1274                         default:
1275                                 return (ECONNABORTED);
1276 
1277                         case SCF_ERROR_DELETED:
1278                                 break;
1279 
1280                         case SCF_ERROR_PERMISSION_DENIED:
1281                                 return (EPERM);
1282 
1283                         case SCF_ERROR_BACKEND_ACCESS:
1284                                 return (EACCES);
1285 
1286                         case SCF_ERROR_BACKEND_READONLY:
1287                                 return (EROFS);
1288 
1289                         case SCF_ERROR_NOT_SET:
1290                                 bad_error("scf_pg_delete", scf_error());
1291                         }
1292                 }
1293         } else {
1294                 switch (scf_error()) {
1295                 case SCF_ERROR_CONNECTION_BROKEN:
1296                 default:
1297                         return (ECONNABORTED);
1298 
1299                 case SCF_ERROR_DELETED:
1300                         return (ECANCELED);
1301 
1302                 case SCF_ERROR_NOT_FOUND:
1303                         break;
1304 
1305                 case SCF_ERROR_HANDLE_MISMATCH:
1306                 case SCF_ERROR_INVALID_ARGUMENT:
1307                 case SCF_ERROR_NOT_SET:
1308                         bad_error("scf_instance_get_pg", scf_error());
1309                 }
1310         }
1311 
1312 add:
1313         if (scf_instance_add_pg(inst, name, type, flags, pg) == 0)
1314                 return (0);
1315 
1316         switch (scf_error()) {
1317         case SCF_ERROR_CONNECTION_BROKEN:
1318         default:
1319                 return (ECONNABORTED);
1320 
1321         case SCF_ERROR_DELETED:
1322                 return (ECANCELED);
1323 
1324         case SCF_ERROR_EXISTS:
1325                 goto again;
1326 
1327         case SCF_ERROR_PERMISSION_DENIED:
1328                 return (EPERM);
1329 
1330         case SCF_ERROR_BACKEND_ACCESS:
1331                 return (EACCES);
1332 
1333         case SCF_ERROR_BACKEND_READONLY:
1334                 return (EROFS);
1335 
1336         case SCF_ERROR_HANDLE_MISMATCH:
1337         case SCF_ERROR_INVALID_ARGUMENT:
1338         case SCF_ERROR_NOT_SET:
1339                 bad_error("scf_instance_add_pg", scf_error());
1340                 /* NOTREACHED */
1341         }
1342 }
1343 
1344 /*
1345  * Returns
1346  *   0 - success
1347  *   ECONNABORTED - repository connection broken
1348  *                - unknown libscf error
1349  *   ECANCELED
1350  */
1351 static scf_error_t
1352 transaction_add_set(scf_transaction_t *tx, scf_transaction_entry_t *ent,
1353     const char *pname, scf_type_t ty)
1354 {
1355         for (;;) {
1356                 if (scf_transaction_property_change_type(tx, ent, pname,
1357                     ty) == 0)
1358                         return (0);
1359 
1360                 switch (scf_error()) {
1361                 case SCF_ERROR_CONNECTION_BROKEN:
1362                 default:
1363                         return (ECONNABORTED);
1364 
1365                 case SCF_ERROR_DELETED:
1366                         return (ECANCELED);
1367 
1368                 case SCF_ERROR_NOT_FOUND:
1369                         break;
1370 
1371                 case SCF_ERROR_HANDLE_MISMATCH:
1372                 case SCF_ERROR_INVALID_ARGUMENT:
1373                 case SCF_ERROR_IN_USE:
1374                 case SCF_ERROR_NOT_SET:
1375                         bad_error("scf_transaction_property_change_type",
1376                             scf_error());
1377                 }
1378 
1379                 if (scf_transaction_property_new(tx, ent, pname, ty) == 0)
1380                         return (0);
1381 
1382                 switch (scf_error()) {
1383                 case SCF_ERROR_CONNECTION_BROKEN:
1384                 default:
1385                         return (ECONNABORTED);
1386 
1387                 case SCF_ERROR_DELETED:
1388                         return (ECANCELED);
1389 
1390                 case SCF_ERROR_EXISTS:
1391                         break;
1392 
1393                 case SCF_ERROR_HANDLE_MISMATCH:
1394                 case SCF_ERROR_INVALID_ARGUMENT:
1395                 case SCF_ERROR_IN_USE:
1396                 case SCF_ERROR_NOT_SET:
1397                         bad_error("scf_transaction_property_new", scf_error());
1398                         /* NOTREACHED */
1399                 }
1400         }
1401 }
1402 
1403 /*
1404  * Returns
1405  *   0 - success
1406  *   ECONNABORTED - repository connection broken
1407  *                - unknown libscf error
1408  *   ECANCELED - pg was deleted
1409  *   EPERM
1410  *   EACCES
1411  *   EROFS
1412  */
1413 static int
1414 pg_set_prop_value(scf_propertygroup_t *pg, const char *pname, scf_value_t *v)
1415 {
1416         scf_handle_t *h;
1417         scf_transaction_t *tx;
1418         scf_transaction_entry_t *e;
1419         scf_type_t ty;
1420         scf_error_t scfe;
1421         int ret, r;
1422 
1423         h = scf_pg_handle(pg);
1424         tx = safe_scf_transaction_create(h);
1425         e = safe_scf_entry_create(h);
1426 
1427         ty = scf_value_type(v);
1428         assert(ty != SCF_TYPE_INVALID);
1429 
1430         for (;;) {
1431                 if (scf_transaction_start(tx, pg) != 0) {
1432                         switch (scf_error()) {
1433                         case SCF_ERROR_CONNECTION_BROKEN:
1434                         default:
1435                                 ret = ECONNABORTED;
1436                                 goto out;
1437 
1438                         case SCF_ERROR_DELETED:
1439                                 ret = ECANCELED;
1440                                 goto out;
1441 
1442                         case SCF_ERROR_PERMISSION_DENIED:
1443                                 ret = EPERM;
1444                                 goto out;
1445 
1446                         case SCF_ERROR_BACKEND_ACCESS:
1447                                 ret = EACCES;
1448                                 goto out;
1449 
1450                         case SCF_ERROR_BACKEND_READONLY:
1451                                 ret = EROFS;
1452                                 goto out;
1453 
1454                         case SCF_ERROR_NOT_SET:
1455                                 bad_error("scf_transaction_start", ret);
1456                         }
1457                 }
1458 
1459                 ret = transaction_add_set(tx, e, pname, ty);
1460                 switch (ret) {
1461                 case 0:
1462                         break;
1463 
1464                 case ECONNABORTED:
1465                 case ECANCELED:
1466                         goto out;
1467 
1468                 default:
1469                         bad_error("transaction_add_set", ret);
1470                 }
1471 
1472                 r = scf_entry_add_value(e, v);
1473                 assert(r == 0);
1474 
1475                 r = scf_transaction_commit(tx);
1476                 if (r == 1)
1477                         break;
1478                 if (r != 0) {
1479                         scfe = scf_error();
1480                         scf_transaction_reset(tx);
1481                         switch (scfe) {
1482                         case SCF_ERROR_CONNECTION_BROKEN:
1483                         default:
1484                                 ret = ECONNABORTED;
1485                                 goto out;
1486 
1487                         case SCF_ERROR_DELETED:
1488                                 ret = ECANCELED;
1489                                 goto out;
1490 
1491                         case SCF_ERROR_PERMISSION_DENIED:
1492                                 ret = EPERM;
1493                                 goto out;
1494 
1495                         case SCF_ERROR_BACKEND_ACCESS:
1496                                 ret = EACCES;
1497                                 goto out;
1498 
1499                         case SCF_ERROR_BACKEND_READONLY:
1500                                 ret = EROFS;
1501                                 goto out;
1502 
1503                         case SCF_ERROR_NOT_SET:
1504                                 bad_error("scf_transaction_commit", scfe);
1505                         }
1506                 }
1507 
1508                 scf_transaction_reset(tx);
1509 
1510                 if (scf_pg_update(pg) == -1) {
1511                         switch (scf_error()) {
1512                         case SCF_ERROR_CONNECTION_BROKEN:
1513                         default:
1514                                 ret = ECONNABORTED;
1515                                 goto out;
1516 
1517                         case SCF_ERROR_DELETED:
1518                                 ret = ECANCELED;
1519                                 goto out;
1520 
1521                         case SCF_ERROR_NOT_SET:
1522                                 bad_error("scf_pg_update", scf_error());
1523                         }
1524                 }
1525         }
1526 
1527         ret = 0;
1528 
1529 out:
1530         scf_transaction_destroy(tx);
1531         scf_entry_destroy(e);
1532         return (ret);
1533 }
1534 
1535 /*
1536  * Returns
1537  *   0 - success
1538  *   ECONNABORTED - repository connection broken
1539  *                - unknown libscf error
1540  *   ECANCELED - inst was deleted
1541  *   EPERM
1542  *   EACCES
1543  *   EROFS
1544  */
1545 int
1546 libscf_inst_set_boolean_prop(scf_instance_t *inst, const char *pgname,
1547     const char *pgtype, uint32_t pgflags, const char *pname, int val)
1548 {
1549         scf_handle_t *h;
1550         scf_propertygroup_t *pg = NULL;
1551         scf_value_t *v;
1552         int ret = 0;
1553 
1554         h = scf_instance_handle(inst);
1555         pg = safe_scf_pg_create(h);
1556         v = safe_scf_value_create(h);
1557 
1558         ret = libscf_inst_get_or_add_pg(inst, pgname, pgtype, pgflags, pg);
1559         switch (ret) {
1560         case 0:
1561                 break;
1562 
1563         case ECONNABORTED:
1564         case ECANCELED:
1565         case EPERM:
1566         case EACCES:
1567         case EROFS:
1568                 goto out;
1569 
1570         default:
1571                 bad_error("libscf_inst_get_or_add_pg", ret);
1572         }
1573 
1574         scf_value_set_boolean(v, val);
1575 
1576         ret = pg_set_prop_value(pg, pname, v);
1577         switch (ret) {
1578         case 0:
1579         case ECONNABORTED:
1580         case ECANCELED:
1581         case EPERM:
1582         case EACCES:
1583         case EROFS:
1584                 break;
1585 
1586         default:
1587                 bad_error("pg_set_prop_value", ret);
1588         }
1589 
1590 out:
1591         scf_pg_destroy(pg);
1592         scf_value_destroy(v);
1593         return (ret);
1594 }
1595 
1596 /*
1597  * Returns
1598  *   0 - success
1599  *   ECONNABORTED - repository connection broken
1600  *                - unknown libscf error
1601  *   ECANCELED - inst was deleted
1602  *   EPERM
1603  *   EACCES
1604  *   EROFS
1605  */
1606 int
1607 libscf_inst_set_count_prop(scf_instance_t *inst, const char *pgname,
1608     const char *pgtype, uint32_t pgflags, const char *pname, uint64_t count)
1609 {
1610         scf_handle_t *h;
1611         scf_propertygroup_t *pg = NULL;
1612         scf_value_t *v;
1613         int ret = 0;
1614 
1615         h = scf_instance_handle(inst);
1616         pg = safe_scf_pg_create(h);
1617         v = safe_scf_value_create(h);
1618 
1619         ret = libscf_inst_get_or_add_pg(inst, pgname, pgtype, pgflags, pg);
1620         switch (ret) {
1621         case 0:
1622                 break;
1623 
1624         case ECONNABORTED:
1625         case ECANCELED:
1626         case EPERM:
1627         case EACCES:
1628         case EROFS:
1629                 goto out;
1630 
1631         default:
1632                 bad_error("libscf_inst_get_or_add_pg", ret);
1633         }
1634 
1635         scf_value_set_count(v, count);
1636 
1637         ret = pg_set_prop_value(pg, pname, v);
1638         switch (ret) {
1639         case 0:
1640         case ECONNABORTED:
1641         case ECANCELED:
1642         case EPERM:
1643         case EACCES:
1644         case EROFS:
1645                 break;
1646 
1647         default:
1648                 bad_error("pg_set_prop_value", ret);
1649         }
1650 
1651 out:
1652         scf_pg_destroy(pg);
1653         scf_value_destroy(v);
1654         return (ret);
1655 }
1656 
1657 /*
1658  * Returns 0 on success, ECONNABORTED if the repository connection is broken,
1659  * ECANCELED if inst is deleted, EROFS if the backend is readonly, or EPERM if
1660  * permission was denied.
1661  */
1662 int
1663 libscf_set_enable_ovr(scf_instance_t *inst, int enable)
1664 {
1665         return (libscf_inst_set_boolean_prop(inst, SCF_PG_GENERAL_OVR,
1666             SCF_PG_GENERAL_OVR_TYPE, SCF_PG_GENERAL_OVR_FLAGS,
1667             SCF_PROPERTY_ENABLED, enable));
1668 }
1669 
1670 /*
1671  * Returns 0 on success, ECONNABORTED if the repository connection is broken,
1672  * ECANCELED if inst is deleted, EROFS if the backend is readonly, or EPERM if
1673  * permission was denied.
1674  */
1675 int
1676 libscf_set_deathrow(scf_instance_t *inst, int deathrow)
1677 {
1678         return (libscf_inst_set_boolean_prop(inst, SCF_PG_DEATHROW,
1679             SCF_PG_DEATHROW_TYPE, SCF_PG_DEATHROW_FLAGS,
1680             SCF_PROPERTY_DEATHROW, deathrow));
1681 }
1682 
1683 /*
1684  * Returns 0, ECONNABORTED, ECANCELED, or EPERM.
1685  */
1686 int
1687 libscf_delete_enable_ovr(scf_instance_t *inst)
1688 {
1689         return (scf_instance_delete_prop(inst, SCF_PG_GENERAL_OVR,
1690             SCF_PROPERTY_ENABLED));
1691 }
1692 
1693 /*
1694  * Fails with
1695  *   ECONNABORTED - repository connection was broken
1696  *   ECANCELED - pg was deleted
1697  *   ENOENT - pg has no milestone property
1698  *   EINVAL - the milestone property is misconfigured
1699  */
1700 static int
1701 pg_get_milestone(scf_propertygroup_t *pg, scf_property_t *prop,
1702     scf_value_t *val, char *buf, size_t buf_sz)
1703 {
1704         if (scf_pg_get_property(pg, SCF_PROPERTY_MILESTONE, prop) != 0) {
1705                 switch (scf_error()) {
1706                 case SCF_ERROR_CONNECTION_BROKEN:
1707                 default:
1708                         return (ECONNABORTED);
1709 
1710                 case SCF_ERROR_DELETED:
1711                         return (ECANCELED);
1712 
1713                 case SCF_ERROR_NOT_FOUND:
1714                         return (ENOENT);
1715 
1716                 case SCF_ERROR_HANDLE_MISMATCH:
1717                 case SCF_ERROR_INVALID_ARGUMENT:
1718                 case SCF_ERROR_NOT_SET:
1719                         bad_error("scf_pg_get_property", scf_error());
1720                 }
1721         }
1722 
1723         if (scf_property_get_value(prop, val) != 0) {
1724                 switch (scf_error()) {
1725                 case SCF_ERROR_CONNECTION_BROKEN:
1726                 default:
1727                         return (ECONNABORTED);
1728 
1729                 case SCF_ERROR_DELETED:
1730                 case SCF_ERROR_CONSTRAINT_VIOLATED:
1731                 case SCF_ERROR_NOT_FOUND:
1732                         return (EINVAL);
1733 
1734                 case SCF_ERROR_NOT_SET:
1735                 case SCF_ERROR_PERMISSION_DENIED:
1736                         bad_error("scf_property_get_value", scf_error());
1737                 }
1738         }
1739 
1740         if (scf_value_get_astring(val, buf, buf_sz) < 0) {
1741                 switch (scf_error()) {
1742                 case SCF_ERROR_TYPE_MISMATCH:
1743                         return (EINVAL);
1744 
1745                 case SCF_ERROR_NOT_SET:
1746                 default:
1747                         bad_error("scf_value_get_astring", scf_error());
1748                 }
1749         }
1750 
1751         return (0);
1752 }
1753 
1754 /*
1755  * Fails with
1756  *   ECONNABORTED - repository connection was broken
1757  *   ECANCELED - inst was deleted
1758  *   ENOENT - inst has no milestone property
1759  *   EINVAL - the milestone property is misconfigured
1760  */
1761 int
1762 libscf_get_milestone(scf_instance_t *inst, scf_property_t *prop,
1763     scf_value_t *val, char *buf, size_t buf_sz)
1764 {
1765         scf_propertygroup_t *pg;
1766         int r;
1767 
1768         pg = safe_scf_pg_create(scf_instance_handle(inst));
1769 
1770         if (scf_instance_get_pg(inst, SCF_PG_OPTIONS_OVR, pg) == 0) {
1771                 switch (r = pg_get_milestone(pg, prop, val, buf, buf_sz)) {
1772                 case 0:
1773                 case ECONNABORTED:
1774                 case EINVAL:
1775                         goto out;
1776 
1777                 case ECANCELED:
1778                 case ENOENT:
1779                         break;
1780 
1781                 default:
1782                         bad_error("pg_get_milestone", r);
1783                 }
1784         } else {
1785                 switch (scf_error()) {
1786                 case SCF_ERROR_CONNECTION_BROKEN:
1787                 default:
1788                         r = ECONNABORTED;
1789                         goto out;
1790 
1791                 case SCF_ERROR_DELETED:
1792                         r = ECANCELED;
1793                         goto out;
1794 
1795                 case SCF_ERROR_NOT_FOUND:
1796                         break;
1797 
1798                 case SCF_ERROR_HANDLE_MISMATCH:
1799                 case SCF_ERROR_INVALID_ARGUMENT:
1800                 case SCF_ERROR_NOT_SET:
1801                         bad_error("scf_instance_get_pg", scf_error());
1802                 }
1803         }
1804 
1805         if (scf_instance_get_pg(inst, SCF_PG_OPTIONS, pg) == 0) {
1806                 r = pg_get_milestone(pg, prop, val, buf, buf_sz);
1807         } else {
1808                 switch (scf_error()) {
1809                 case SCF_ERROR_CONNECTION_BROKEN:
1810                 default:
1811                         r = ECONNABORTED;
1812                         goto out;
1813 
1814                 case SCF_ERROR_DELETED:
1815                         r = ECANCELED;
1816                         goto out;
1817 
1818                 case SCF_ERROR_NOT_FOUND:
1819                         r = ENOENT;
1820                         break;
1821 
1822                 case SCF_ERROR_HANDLE_MISMATCH:
1823                 case SCF_ERROR_INVALID_ARGUMENT:
1824                 case SCF_ERROR_NOT_SET:
1825                         bad_error("scf_instance_get_pg", scf_error());
1826                 }
1827         }
1828 
1829 out:
1830         scf_pg_destroy(pg);
1831 
1832         return (r);
1833 }
1834 
1835 /*
1836  * Get the runlevel character from the runlevel property of the given property
1837  * group.  Fails with
1838  *   ECONNABORTED - repository connection was broken
1839  *   ECANCELED - prop's property group was deleted
1840  *   ENOENT - the property has no values
1841  *   EINVAL - the property has more than one value
1842  *            the property is of the wrong type
1843  *            the property value is malformed
1844  */
1845 int
1846 libscf_extract_runlevel(scf_property_t *prop, char *rlp)
1847 {
1848         scf_value_t *val;
1849         char buf[2];
1850 
1851         val = safe_scf_value_create(scf_property_handle(prop));
1852 
1853         if (scf_property_get_value(prop, val) != 0) {
1854                 scf_value_destroy(val);
1855                 switch (scf_error()) {
1856                 case SCF_ERROR_CONNECTION_BROKEN:
1857                         return (ECONNABORTED);
1858 
1859                 case SCF_ERROR_NOT_SET:
1860                         return (ENOENT);
1861 
1862                 case SCF_ERROR_DELETED:
1863                         return (ECANCELED);
1864 
1865                 case SCF_ERROR_CONSTRAINT_VIOLATED:
1866                         return (EINVAL);
1867 
1868                 case SCF_ERROR_NOT_FOUND:
1869                         return (ENOENT);
1870 
1871                 case SCF_ERROR_HANDLE_MISMATCH:
1872                 case SCF_ERROR_NOT_BOUND:
1873                 case SCF_ERROR_PERMISSION_DENIED:
1874                 default:
1875                         bad_error("scf_property_get_value", scf_error());
1876                 }
1877         }
1878 
1879         if (scf_value_get_astring(val, buf, sizeof (buf)) < 0) {
1880                 scf_value_destroy(val);
1881                 if (scf_error() != SCF_ERROR_TYPE_MISMATCH)
1882                         bad_error("scf_value_get_astring", scf_error());
1883 
1884                 return (EINVAL);
1885         }
1886 
1887         scf_value_destroy(val);
1888 
1889         if (buf[0] == '\0' || buf[1] != '\0')
1890                 return (EINVAL);
1891 
1892         *rlp = buf[0];
1893 
1894         return (0);
1895 }
1896 
1897 /*
1898  * Delete the "runlevel" property from the given property group.  Also set the
1899  * "milestone" property to the given string.  Fails with ECONNABORTED,
1900  * ECANCELED, EPERM, EACCES, or EROFS.
1901  */
1902 int
1903 libscf_clear_runlevel(scf_propertygroup_t *pg, const char *milestone)
1904 {
1905         scf_handle_t *h;
1906         scf_transaction_t *tx;
1907         scf_transaction_entry_t *e_rl, *e_ms;
1908         scf_value_t *val;
1909         scf_error_t serr;
1910         boolean_t isempty = B_TRUE;
1911         int ret = 0, r;
1912 
1913         h = scf_pg_handle(pg);
1914         tx = safe_scf_transaction_create(h);
1915         e_rl = safe_scf_entry_create(h);
1916         e_ms = safe_scf_entry_create(h);
1917         val = safe_scf_value_create(h);
1918 
1919         if (milestone) {
1920                 r = scf_value_set_astring(val, milestone);
1921                 assert(r == 0);
1922         }
1923 
1924         for (;;) {
1925                 if (scf_transaction_start(tx, pg) != 0) {
1926                         switch (scf_error()) {
1927                         case SCF_ERROR_CONNECTION_BROKEN:
1928                         default:
1929                                 ret = ECONNABORTED;
1930                                 goto out;
1931 
1932                         case SCF_ERROR_DELETED:
1933                                 ret = ECANCELED;
1934                                 goto out;
1935 
1936                         case SCF_ERROR_PERMISSION_DENIED:
1937                                 ret = EPERM;
1938                                 goto out;
1939 
1940                         case SCF_ERROR_BACKEND_ACCESS:
1941                                 ret = EACCES;
1942                                 goto out;
1943 
1944                         case SCF_ERROR_BACKEND_READONLY:
1945                                 ret = EROFS;
1946                                 goto out;
1947 
1948                         case SCF_ERROR_NOT_SET:
1949                                 bad_error("scf_transaction_start", scf_error());
1950                         }
1951                 }
1952 
1953                 if (scf_transaction_property_delete(tx, e_rl,
1954                     "runlevel") == 0) {
1955                         isempty = B_FALSE;
1956                 } else {
1957                         switch (scf_error()) {
1958                         case SCF_ERROR_CONNECTION_BROKEN:
1959                         default:
1960                                 ret = ECONNABORTED;
1961                                 goto out;
1962 
1963                         case SCF_ERROR_DELETED:
1964                                 ret = ECANCELED;
1965                                 goto out;
1966 
1967                         case SCF_ERROR_NOT_FOUND:
1968                                 break;
1969 
1970                         case SCF_ERROR_HANDLE_MISMATCH:
1971                         case SCF_ERROR_NOT_BOUND:
1972                         case SCF_ERROR_INVALID_ARGUMENT:
1973                                 bad_error("scf_transaction_property_delete",
1974                                     scf_error());
1975                         }
1976                 }
1977 
1978                 if (milestone) {
1979                         ret = transaction_add_set(tx, e_ms,
1980                             SCF_PROPERTY_MILESTONE, SCF_TYPE_ASTRING);
1981                         switch (ret) {
1982                         case 0:
1983                                 break;
1984 
1985                         case ECONNABORTED:
1986                         case ECANCELED:
1987                                 goto out;
1988 
1989                         default:
1990                                 bad_error("transaction_add_set", ret);
1991                         }
1992 
1993                         isempty = B_FALSE;
1994 
1995                         r = scf_entry_add_value(e_ms, val);
1996                         assert(r == 0);
1997                 }
1998 
1999                 if (isempty)
2000                         goto out;
2001 
2002                 r = scf_transaction_commit(tx);
2003                 if (r == 1)
2004                         break;
2005                 if (r != 0) {
2006                         serr = scf_error();
2007                         scf_transaction_reset(tx);
2008                         switch (serr) {
2009                         case SCF_ERROR_CONNECTION_BROKEN:
2010                                 ret = ECONNABORTED;
2011                                 goto out;
2012 
2013                         case SCF_ERROR_PERMISSION_DENIED:
2014                                 ret = EPERM;
2015                                 goto out;
2016 
2017                         case SCF_ERROR_BACKEND_ACCESS:
2018                                 ret = EACCES;
2019                                 goto out;
2020 
2021                         case SCF_ERROR_BACKEND_READONLY:
2022                                 ret = EROFS;
2023                                 goto out;
2024 
2025                         default:
2026                                 bad_error("scf_transaction_commit", serr);
2027                         }
2028                 }
2029 
2030                 scf_transaction_reset(tx);
2031 
2032                 if (scf_pg_update(pg) == -1) {
2033                         switch (scf_error()) {
2034                         case SCF_ERROR_CONNECTION_BROKEN:
2035                                 ret = ECONNABORTED;
2036                                 goto out;
2037 
2038                         case SCF_ERROR_NOT_SET:
2039                                 ret = ECANCELED;
2040                                 goto out;
2041 
2042                         default:
2043                                 assert(0);
2044                                 abort();
2045                         }
2046                 }
2047         }
2048 
2049 out:
2050         scf_transaction_destroy(tx);
2051         scf_entry_destroy(e_rl);
2052         scf_entry_destroy(e_ms);
2053         scf_value_destroy(val);
2054         return (ret);
2055 }
2056 
2057 /*
2058  * int libscf_get_template_values(scf_instance_t *, scf_snapshot_t *,
2059  *      char **)
2060  *
2061  *   Return template values for inst in *common_name suitable for use in
2062  *   restarter_inst_t->ri_common_name.  Called by restarter_insert_inst().
2063  *
2064  *   Returns 0 on success, ECANCELED if the instance is deleted, ECHILD if
2065  *   a value fetch failed for a property, ENOENT if the instance has no
2066  *   tm_common_name property group or the property group is deleted, and
2067  *   ECONNABORTED if the repository connection is broken.
2068  */
2069 int
2070 libscf_get_template_values(scf_instance_t *inst, scf_snapshot_t *snap,
2071     char **common_name, char **c_common_name)
2072 {
2073         scf_handle_t *h;
2074         scf_propertygroup_t *pg = NULL;
2075         scf_property_t *prop = NULL;
2076         int ret = 0, r;
2077         char *cname = startd_alloc(max_scf_value_size);
2078         char *c_cname = startd_alloc(max_scf_value_size);
2079         int common_name_initialized = B_FALSE;
2080         int c_common_name_initialized = B_FALSE;
2081 
2082         h = scf_instance_handle(inst);
2083         pg = safe_scf_pg_create(h);
2084         prop = safe_scf_property_create(h);
2085 
2086         /*
2087          * The tm_common_name property group, as with all template property
2088          * groups, is optional.
2089          */
2090         if (scf_instance_get_pg_composed(inst, snap, SCF_PG_TM_COMMON_NAME, pg)
2091             == -1) {
2092                 switch (scf_error()) {
2093                 case SCF_ERROR_DELETED:
2094                         ret = ECANCELED;
2095                         goto template_values_out;
2096 
2097                 case SCF_ERROR_NOT_FOUND:
2098                         goto template_values_out;
2099 
2100                 case SCF_ERROR_CONNECTION_BROKEN:
2101                 default:
2102                         ret = ECONNABORTED;
2103                         goto template_values_out;
2104 
2105                 case SCF_ERROR_INVALID_ARGUMENT:
2106                 case SCF_ERROR_HANDLE_MISMATCH:
2107                 case SCF_ERROR_NOT_SET:
2108                         bad_error("scf_instance_get_pg_composed", scf_error());
2109                 }
2110         }
2111 
2112         /*
2113          * The name we wish uses the current locale name as the property name.
2114          */
2115         if (st->st_locale != NULL) {
2116                 if (scf_pg_get_property(pg, st->st_locale, prop) == -1) {
2117                         switch (scf_error()) {
2118                         case SCF_ERROR_DELETED:
2119                         case SCF_ERROR_NOT_FOUND:
2120                                 break;
2121 
2122                         case SCF_ERROR_CONNECTION_BROKEN:
2123                         default:
2124                                 ret = ECONNABORTED;
2125                                 goto template_values_out;
2126 
2127                         case SCF_ERROR_INVALID_ARGUMENT:
2128                         case SCF_ERROR_HANDLE_MISMATCH:
2129                         case SCF_ERROR_NOT_SET:
2130                                 bad_error("scf_pg_get_property", scf_error());
2131                         }
2132                 } else {
2133                         if ((r = libscf_read_single_astring(h, prop, &cname)) !=
2134                             0) {
2135                                 if (r != LIBSCF_PROPERTY_ABSENT)
2136                                         ret = ECHILD;
2137                                 goto template_values_out;
2138                         }
2139 
2140                         *common_name = cname;
2141                         common_name_initialized = B_TRUE;
2142                 }
2143         }
2144 
2145         /*
2146          * Also pull out the C locale name, as a fallback for the case where
2147          * service offers no localized name.
2148          */
2149         if (scf_pg_get_property(pg, "C", prop) == -1) {
2150                 switch (scf_error()) {
2151                 case SCF_ERROR_DELETED:
2152                         ret = ENOENT;
2153                         goto template_values_out;
2154 
2155                 case SCF_ERROR_NOT_FOUND:
2156                         break;
2157 
2158                 case SCF_ERROR_CONNECTION_BROKEN:
2159                 default:
2160                         ret = ECONNABORTED;
2161                         goto template_values_out;
2162 
2163                 case SCF_ERROR_INVALID_ARGUMENT:
2164                 case SCF_ERROR_HANDLE_MISMATCH:
2165                 case SCF_ERROR_NOT_SET:
2166                         bad_error("scf_pg_get_property", scf_error());
2167                 }
2168         } else {
2169                 if ((r = libscf_read_single_astring(h, prop, &c_cname)) != 0) {
2170                         if (r != LIBSCF_PROPERTY_ABSENT)
2171                                 ret = ECHILD;
2172                         goto template_values_out;
2173                 }
2174 
2175                 *c_common_name = c_cname;
2176                 c_common_name_initialized = B_TRUE;
2177         }
2178 
2179 
2180 template_values_out:
2181         if (common_name_initialized == B_FALSE)
2182                 startd_free(cname, max_scf_value_size);
2183         if (c_common_name_initialized == B_FALSE)
2184                 startd_free(c_cname, max_scf_value_size);
2185         scf_property_destroy(prop);
2186         scf_pg_destroy(pg);
2187 
2188         return (ret);
2189 }
2190 
2191 /*
2192  * int libscf_get_startd_properties(scf_handle_t *, scf_instance_t *,
2193  *      scf_snapshot_t *, uint_t *, char **)
2194  *
2195  *   Return startd settings for inst in *flags suitable for use in
2196  *   restarter_inst_t->ri_flags.  Called by restarter_insert_inst().
2197  *
2198  *   Returns 0 on success, ECANCELED if the instance is deleted, ECHILD if
2199  *   a value fetch failed for a property, ENOENT if the instance has no
2200  *   general property group or the property group is deleted, and
2201  *   ECONNABORTED if the repository connection is broken.
2202  */
2203 int
2204 libscf_get_startd_properties(scf_instance_t *inst,
2205     scf_snapshot_t *snap, uint_t *flags, char **prefixp)
2206 {
2207         scf_handle_t *h;
2208         scf_propertygroup_t *pg = NULL;
2209         scf_property_t *prop = NULL;
2210         int style = RINST_CONTRACT;
2211         char *style_str = startd_alloc(max_scf_value_size);
2212         int ret = 0, r;
2213 
2214         h = scf_instance_handle(inst);
2215         pg = safe_scf_pg_create(h);
2216         prop = safe_scf_property_create(h);
2217 
2218         /*
2219          * The startd property group is optional.
2220          */
2221         if (scf_instance_get_pg_composed(inst, snap, SCF_PG_STARTD, pg) == -1) {
2222                 switch (scf_error()) {
2223                 case SCF_ERROR_DELETED:
2224                         ret = ECANCELED;
2225                         goto instance_flags_out;
2226 
2227                 case SCF_ERROR_NOT_FOUND:
2228                         ret = ENOENT;
2229                         goto instance_flags_out;
2230 
2231                 case SCF_ERROR_CONNECTION_BROKEN:
2232                 default:
2233                         ret = ECONNABORTED;
2234                         goto instance_flags_out;
2235 
2236                 case SCF_ERROR_INVALID_ARGUMENT:
2237                 case SCF_ERROR_HANDLE_MISMATCH:
2238                 case SCF_ERROR_NOT_SET:
2239                         bad_error("scf_instance_get_pg_composed", scf_error());
2240                 }
2241         }
2242 
2243         /*
2244          * 1.  Duration property.
2245          */
2246         if (scf_pg_get_property(pg, SCF_PROPERTY_DURATION, prop) == -1) {
2247                 switch (scf_error()) {
2248                 case SCF_ERROR_DELETED:
2249                         ret = ENOENT;
2250                         goto instance_flags_out;
2251 
2252                 case SCF_ERROR_NOT_FOUND:
2253                         break;
2254 
2255                 case SCF_ERROR_CONNECTION_BROKEN:
2256                 default:
2257                         ret = ECONNABORTED;
2258                         goto instance_flags_out;
2259 
2260                 case SCF_ERROR_INVALID_ARGUMENT:
2261                 case SCF_ERROR_HANDLE_MISMATCH:
2262                 case SCF_ERROR_NOT_SET:
2263                         bad_error("scf_pg_get_property", scf_error());
2264                 }
2265         } else {
2266                 errno = 0;
2267                 if ((r = libscf_read_single_astring(h, prop, &style_str))
2268                     != 0) {
2269                         if (r != LIBSCF_PROPERTY_ABSENT)
2270                                 ret = ECHILD;
2271                         goto instance_flags_out;
2272                 }
2273 
2274                 if (strcmp(style_str, "child") == 0)
2275                         style = RINST_WAIT;
2276                 else if (strcmp(style_str, "transient") == 0)
2277                         style = RINST_TRANSIENT;
2278         }
2279 
2280         /*
2281          * 2.  utmpx prefix property.
2282          */
2283         if (scf_pg_get_property(pg, SCF_PROPERTY_UTMPX_PREFIX, prop) == 0) {
2284                 errno = 0;
2285                 if ((r = libscf_read_single_astring(h, prop, prefixp)) != 0) {
2286                         if (r != LIBSCF_PROPERTY_ABSENT)
2287                                 ret = ECHILD;
2288                         goto instance_flags_out;
2289                 }
2290         } else {
2291                 switch (scf_error()) {
2292                 case SCF_ERROR_DELETED:
2293                         ret = ENOENT;
2294                         goto instance_flags_out;
2295 
2296                 case SCF_ERROR_NOT_FOUND:
2297                         goto instance_flags_out;
2298 
2299                 case SCF_ERROR_CONNECTION_BROKEN:
2300                 default:
2301                         ret = ECONNABORTED;
2302                         goto instance_flags_out;
2303 
2304                 case SCF_ERROR_INVALID_ARGUMENT:
2305                 case SCF_ERROR_HANDLE_MISMATCH:
2306                 case SCF_ERROR_NOT_SET:
2307                         bad_error("scf_pg_get_property", scf_error());
2308                 }
2309         }
2310 
2311 instance_flags_out:
2312         startd_free(style_str, max_scf_value_size);
2313         *flags = (*flags & ~RINST_STYLE_MASK) | style;
2314 
2315         scf_property_destroy(prop);
2316         scf_pg_destroy(pg);
2317 
2318         return (ret);
2319 }
2320 
2321 /*
2322  * int libscf_read_method_ids(scf_handle_t *, scf_instance_t *, ctid_t *,
2323  *   ctid_t *, pid_t *)
2324  *
2325  *  Sets given id_t variables to primary and transient contract IDs and start
2326  *  PID.  Returns 0, ECONNABORTED, and ECANCELED.
2327  */
2328 int
2329 libscf_read_method_ids(scf_handle_t *h, scf_instance_t *inst, const char *fmri,
2330     ctid_t *primary, ctid_t *transient, pid_t *start_pid)
2331 {
2332         scf_propertygroup_t *pg = NULL;
2333         scf_property_t *prop = NULL;
2334         scf_value_t *val = NULL;
2335         uint64_t p, t;
2336         int ret = 0;
2337 
2338         *primary = 0;
2339         *transient = 0;
2340         *start_pid = -1;
2341 
2342         pg = safe_scf_pg_create(h);
2343         prop = safe_scf_property_create(h);
2344         val = safe_scf_value_create(h);
2345 
2346         if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) == -1) {
2347                 switch (scf_error()) {
2348                 case SCF_ERROR_CONNECTION_BROKEN:
2349                 default:
2350                         ret = ECONNABORTED;
2351                         goto read_id_err;
2352 
2353                 case SCF_ERROR_DELETED:
2354                         ret = ECANCELED;
2355                         goto read_id_err;
2356 
2357                 case SCF_ERROR_NOT_FOUND:
2358                         goto read_id_err;
2359 
2360                 case SCF_ERROR_NOT_SET:
2361                         bad_error("scf_instance_get_pg", scf_error());
2362                 }
2363         }
2364 
2365         ret = get_count(pg, SCF_PROPERTY_CONTRACT, &p);
2366         switch (ret) {
2367         case 0:
2368                 break;
2369 
2370         case EINVAL:
2371                 log_error(LOG_NOTICE,
2372                     "%s: Ignoring %s/%s: multivalued or not of type count\n",
2373                     fmri, SCF_PG_RESTARTER, SCF_PROPERTY_CONTRACT);
2374                 /* FALLTHROUGH */
2375         case ENOENT:
2376                 ret = 0;
2377                 goto read_trans;
2378 
2379         case ECONNABORTED:
2380         case ECANCELED:
2381                 goto read_id_err;
2382 
2383         case EACCES:
2384         default:
2385                 bad_error("get_count", ret);
2386         }
2387 
2388         *primary = p;
2389 
2390 read_trans:
2391         ret = get_count(pg, SCF_PROPERTY_TRANSIENT_CONTRACT, &t);
2392         switch (ret) {
2393         case 0:
2394                 break;
2395 
2396         case EINVAL:
2397                 log_error(LOG_NOTICE,
2398                     "%s: Ignoring %s/%s: multivalued or not of type count\n",
2399                     fmri, SCF_PG_RESTARTER, SCF_PROPERTY_TRANSIENT_CONTRACT);
2400                 /* FALLTHROUGH */
2401 
2402         case ENOENT:
2403                 ret = 0;
2404                 goto read_pid_only;
2405 
2406         case ECONNABORTED:
2407         case ECANCELED:
2408                 goto read_id_err;
2409 
2410         case EACCES:
2411         default:
2412                 bad_error("get_count", ret);
2413         }
2414 
2415         *transient = t;
2416 
2417 read_pid_only:
2418         ret = get_count(pg, SCF_PROPERTY_START_PID, &p);
2419         switch (ret) {
2420         case 0:
2421                 break;
2422 
2423         case EINVAL:
2424                 log_error(LOG_NOTICE,
2425                     "%s: Ignoring %s/%s: multivalued or not of type count\n",
2426                     fmri, SCF_PG_RESTARTER, SCF_PROPERTY_START_PID);
2427                 /* FALLTHROUGH */
2428         case ENOENT:
2429                 ret = 0;
2430                 goto read_id_err;
2431 
2432         case ECONNABORTED:
2433         case ECANCELED:
2434                 goto read_id_err;
2435 
2436         case EACCES:
2437         default:
2438                 bad_error("get_count", ret);
2439         }
2440 
2441         *start_pid = p;
2442 
2443 read_id_err:
2444         scf_value_destroy(val);
2445         scf_property_destroy(prop);
2446         scf_pg_destroy(pg);
2447         return (ret);
2448 }
2449 
2450 /*
2451  * Returns with
2452  *   0 - success
2453  *   ECONNABORTED - repository connection broken
2454  *                - unknown libscf error
2455  *   ECANCELED - s_inst was deleted
2456  *   EPERM
2457  *   EACCES
2458  *   EROFS
2459  */
2460 int
2461 libscf_write_start_pid(scf_instance_t *s_inst, pid_t pid)
2462 {
2463         scf_handle_t *h;
2464         scf_transaction_entry_t *t_pid;
2465         scf_value_t *v_pid;
2466         scf_propertygroup_t *pg;
2467         int ret = 0;
2468 
2469         h = scf_instance_handle(s_inst);
2470 
2471         pg = safe_scf_pg_create(h);
2472         t_pid = safe_scf_entry_create(h);
2473         v_pid = safe_scf_value_create(h);
2474 
2475 get_pg:
2476         ret = libscf_inst_get_or_add_pg(s_inst, SCF_PG_RESTARTER,
2477             SCF_PG_RESTARTER_TYPE, SCF_PG_RESTARTER_FLAGS, pg);
2478         switch (ret) {
2479         case 0:
2480                 break;
2481 
2482         case ECONNABORTED:
2483         case ECANCELED:
2484         case EPERM:
2485         case EACCES:
2486         case EROFS:
2487                 goto write_start_err;
2488 
2489         default:
2490                 bad_error("libscf_inst_get_or_add_pg", ret);
2491         }
2492 
2493         scf_value_set_count(v_pid, pid);
2494 
2495         ret = pg_set_prop_value(pg, SCF_PROPERTY_START_PID, v_pid);
2496         switch (ret) {
2497         case 0:
2498         case ECONNABORTED:
2499         case EPERM:
2500         case EACCES:
2501         case EROFS:
2502                 break;
2503 
2504         case ECANCELED:
2505                 goto get_pg;
2506 
2507         default:
2508                 bad_error("pg_set_prop_value", ret);
2509         }
2510 
2511 write_start_err:
2512         scf_entry_destroy(t_pid);
2513         scf_value_destroy(v_pid);
2514         scf_pg_destroy(pg);
2515 
2516         return (ret);
2517 }
2518 
2519 /*
2520  * Add a property indicating the instance log file.  If the dir is
2521  * equal to LOG_PREFIX_EARLY, then the property restarter/alt_logfile
2522  * of the instance is used; otherwise, restarter/logfile is used.
2523  *
2524  * Returns
2525  *   0 - success
2526  *   ECONNABORTED
2527  *   ECANCELED
2528  *   EPERM
2529  *   EACCES
2530  *   EROFS
2531  *   EAGAIN
2532  */
2533 int
2534 libscf_note_method_log(scf_instance_t *inst, const char *dir, const char *file)
2535 {
2536         scf_handle_t *h;
2537         scf_value_t *v;
2538         scf_propertygroup_t *pg;
2539         int ret = 0;
2540         char *logname;
2541         const char *propname;
2542 
2543         h = scf_instance_handle(inst);
2544         pg = safe_scf_pg_create(h);
2545         v = safe_scf_value_create(h);
2546 
2547         logname = uu_msprintf("%s%s", dir, file);
2548 
2549         if (logname == NULL) {
2550                 ret = errno;
2551                 goto out;
2552         }
2553 
2554         ret = libscf_inst_get_or_add_pg(inst, SCF_PG_RESTARTER,
2555             SCF_PG_RESTARTER_TYPE, SCF_PG_RESTARTER_FLAGS, pg);
2556         switch (ret) {
2557         case 0:
2558                 break;
2559 
2560         case ECONNABORTED:
2561         case ECANCELED:
2562         case EPERM:
2563         case EACCES:
2564         case EROFS:
2565                 goto out;
2566 
2567         default:
2568                 bad_error("libscf_inst_get_or_add_pg", ret);
2569         }
2570 
2571         (void) scf_value_set_astring(v, logname);
2572 
2573         if (strcmp(LOG_PREFIX_EARLY, dir) == 0)
2574                 propname = SCF_PROPERTY_ALT_LOGFILE;
2575         else
2576                 propname = SCF_PROPERTY_LOGFILE;
2577 
2578         ret = pg_set_prop_value(pg, propname, v);
2579         switch (ret) {
2580         case 0:
2581         case ECONNABORTED:
2582         case ECANCELED:
2583         case EPERM:
2584         case EACCES:
2585         case EROFS:
2586                 break;
2587 
2588         default:
2589                 bad_error("pg_set_prop_value", ret);
2590         }
2591 
2592 out:
2593         scf_pg_destroy(pg);
2594         scf_value_destroy(v);
2595         uu_free(logname);
2596         return (ret);
2597 }
2598 
2599 /*
2600  * Returns
2601  *   0 - success
2602  *   ENAMETOOLONG - name is too long
2603  *   ECONNABORTED
2604  *   ECANCELED
2605  *   EPERM
2606  *   EACCES
2607  *   EROFS
2608  */
2609 int
2610 libscf_write_method_status(scf_instance_t *s_inst, const char *name,
2611     int status)
2612 {
2613         scf_handle_t *h;
2614         scf_transaction_t *tx;
2615         scf_transaction_entry_t *e_time, *e_stat;
2616         scf_value_t *v_time, *v_stat;
2617         scf_propertygroup_t *pg;
2618         int ret = 0, r;
2619         char pname[30];
2620         struct timeval tv;
2621         scf_error_t scfe;
2622 
2623         if (strlen(name) + sizeof ("_method_waitstatus") > sizeof (pname))
2624                 return (ENAMETOOLONG);
2625 
2626         h = scf_instance_handle(s_inst);
2627 
2628         pg = safe_scf_pg_create(h);
2629         tx = safe_scf_transaction_create(h);
2630         e_time = safe_scf_entry_create(h);
2631         v_time = safe_scf_value_create(h);
2632         e_stat = safe_scf_entry_create(h);
2633         v_stat = safe_scf_value_create(h);
2634 
2635 get_pg:
2636         ret = libscf_inst_get_or_add_pg(s_inst, SCF_PG_RESTARTER,
2637             SCF_PG_RESTARTER_TYPE, SCF_PG_RESTARTER_FLAGS, pg);
2638         switch (ret) {
2639         case 0:
2640                 break;
2641 
2642         case ECONNABORTED:
2643         case ECANCELED:
2644         case EPERM:
2645         case EACCES:
2646         case EROFS:
2647                 goto out;
2648 
2649         default:
2650                 bad_error("libscf_inst_get_or_add_pg", ret);
2651         }
2652 
2653         (void) gettimeofday(&tv, NULL);
2654 
2655         r = scf_value_set_time(v_time, tv.tv_sec, tv.tv_usec * 1000);
2656         assert(r == 0);
2657 
2658         scf_value_set_integer(v_stat, status);
2659 
2660         for (;;) {
2661                 if (scf_transaction_start(tx, pg) != 0) {
2662                         switch (scf_error()) {
2663                         case SCF_ERROR_CONNECTION_BROKEN:
2664                         default:
2665                                 ret = ECONNABORTED;
2666                                 goto out;
2667 
2668                         case SCF_ERROR_DELETED:
2669                                 ret = ECANCELED;
2670                                 goto out;
2671 
2672                         case SCF_ERROR_PERMISSION_DENIED:
2673                                 ret = EPERM;
2674                                 goto out;
2675 
2676                         case SCF_ERROR_BACKEND_ACCESS:
2677                                 ret = EACCES;
2678                                 goto out;
2679 
2680                         case SCF_ERROR_BACKEND_READONLY:
2681                                 ret = EROFS;
2682                                 goto out;
2683 
2684                         case SCF_ERROR_NOT_SET:
2685                                 bad_error("scf_transaction_start", ret);
2686                         }
2687                 }
2688 
2689                 (void) snprintf(pname, sizeof (pname), "%s_method_timestamp",
2690                     name);
2691                 ret = transaction_add_set(tx, e_time, pname, SCF_TYPE_TIME);
2692                 switch (ret) {
2693                 case 0:
2694                         break;
2695 
2696                 case ECONNABORTED:
2697                 case ECANCELED:
2698                         goto out;
2699 
2700                 default:
2701                         bad_error("transaction_add_set", ret);
2702                 }
2703 
2704                 r = scf_entry_add_value(e_time, v_time);
2705                 assert(r == 0);
2706 
2707                 (void) snprintf(pname, sizeof (pname), "%s_method_waitstatus",
2708                     name);
2709                 ret = transaction_add_set(tx, e_stat, pname, SCF_TYPE_INTEGER);
2710                 switch (ret) {
2711                 case 0:
2712                         break;
2713 
2714                 case ECONNABORTED:
2715                 case ECANCELED:
2716                         goto out;
2717 
2718                 default:
2719                         bad_error("transaction_add_set", ret);
2720                 }
2721 
2722                 r = scf_entry_add_value(e_stat, v_stat);
2723                 if (r != 0)
2724                         bad_error("scf_entry_add_value", scf_error());
2725 
2726                 r = scf_transaction_commit(tx);
2727                 if (r == 1)
2728                         break;
2729                 if (r != 0) {
2730                         scfe = scf_error();
2731                         scf_transaction_reset_all(tx);
2732                         switch (scfe) {
2733                         case SCF_ERROR_CONNECTION_BROKEN:
2734                         default:
2735                                 ret = ECONNABORTED;
2736                                 goto out;
2737 
2738                         case SCF_ERROR_DELETED:
2739                                 ret = ECANCELED;
2740                                 goto out;
2741 
2742                         case SCF_ERROR_PERMISSION_DENIED:
2743                                 ret = EPERM;
2744                                 goto out;
2745 
2746                         case SCF_ERROR_BACKEND_ACCESS:
2747                                 ret = EACCES;
2748                                 goto out;
2749 
2750                         case SCF_ERROR_BACKEND_READONLY:
2751                                 ret = EROFS;
2752                                 goto out;
2753 
2754                         case SCF_ERROR_NOT_SET:
2755                                 bad_error("scf_transaction_commit", scfe);
2756                         }
2757                 }
2758 
2759                 scf_transaction_reset_all(tx);
2760 
2761                 if (scf_pg_update(pg) == -1) {
2762                         switch (scf_error()) {
2763                         case SCF_ERROR_CONNECTION_BROKEN:
2764                         default:
2765                                 ret = ECONNABORTED;
2766                                 goto out;
2767 
2768                         case SCF_ERROR_DELETED:
2769                                 ret = ECANCELED;
2770                                 goto out;
2771 
2772                         case SCF_ERROR_NOT_SET:
2773                                 bad_error("scf_pg_update", scf_error());
2774                         }
2775                 }
2776         }
2777 
2778 out:
2779         scf_transaction_destroy(tx);
2780         scf_entry_destroy(e_time);
2781         scf_value_destroy(v_time);
2782         scf_entry_destroy(e_stat);
2783         scf_value_destroy(v_stat);
2784         scf_pg_destroy(pg);
2785 
2786         return (ret);
2787 }
2788 
2789 extern int32_t stn_global;
2790 /*
2791  * Call dgraph_add_instance() for each instance in the repository.
2792  */
2793 void
2794 libscf_populate_graph(scf_handle_t *h)
2795 {
2796         scf_scope_t *scope;
2797         scf_service_t *svc;
2798         scf_instance_t *inst;
2799         scf_iter_t *svc_iter;
2800         scf_iter_t *inst_iter;
2801 
2802         scope = safe_scf_scope_create(h);
2803         svc = safe_scf_service_create(h);
2804         inst = safe_scf_instance_create(h);
2805         svc_iter = safe_scf_iter_create(h);
2806         inst_iter = safe_scf_iter_create(h);
2807 
2808         deathrow_init();
2809 
2810         stn_global = libscf_get_global_stn_tset(h);
2811 
2812         if (scf_handle_get_local_scope(h, scope) !=
2813             SCF_SUCCESS)
2814                 uu_die("retrieving local scope failed: %s\n",
2815                     scf_strerror(scf_error()));
2816 
2817         if (scf_iter_scope_services(svc_iter, scope) == -1)
2818                 uu_die("walking local scope's services failed\n");
2819 
2820         while (scf_iter_next_service(svc_iter, svc) > 0) {
2821                 if (scf_iter_service_instances(inst_iter, svc) == -1)
2822                         uu_die("unable to walk service's instances");
2823 
2824                 while (scf_iter_next_instance(inst_iter, inst) > 0) {
2825                         char *fmri;
2826 
2827                         if (libscf_instance_get_fmri(inst, &fmri) == 0) {
2828                                 int err;
2829 
2830                                 err = dgraph_add_instance(fmri, inst, B_TRUE);
2831                                 if (err != 0 && err != EEXIST)
2832                                         log_error(LOG_WARNING,
2833                                             "Failed to add %s (%s).\n", fmri,
2834                                             strerror(err));
2835                                 startd_free(fmri, max_scf_fmri_size);
2836                         }
2837                 }
2838         }
2839 
2840         deathrow_fini();
2841 
2842         scf_iter_destroy(inst_iter);
2843         scf_iter_destroy(svc_iter);
2844         scf_instance_destroy(inst);
2845         scf_service_destroy(svc);
2846         scf_scope_destroy(scope);
2847 }
2848 
2849 /*
2850  * Monitors get handled differently since there can be multiple of them.
2851  *
2852  * Returns exec string on success.  If method not defined, returns
2853  * LIBSCF_PGROUP_ABSENT; if exec property missing, returns
2854  * LIBSCF_PROPERTY_ABSENT.  Returns LIBSCF_PROPERTY_ERROR on other failures.
2855  */
2856 char *
2857 libscf_get_method(scf_handle_t *h, int type, restarter_inst_t *inst,
2858     scf_snapshot_t *snap, method_restart_t *restart_on, uint_t *cte_mask,
2859     uint8_t *need_sessionp, uint64_t *timeout, uint8_t *timeout_retry)
2860 {
2861         scf_instance_t *scf_inst = NULL;
2862         scf_propertygroup_t *pg = NULL, *pg_startd = NULL;
2863         scf_property_t *prop = NULL;
2864         const char *name;
2865         char *method = startd_alloc(max_scf_value_size);
2866         char *ig = startd_alloc(max_scf_value_size);
2867         char *restart = startd_alloc(max_scf_value_size);
2868         char *ret;
2869         int error = 0, r;
2870 
2871         scf_inst = safe_scf_instance_create(h);
2872         pg = safe_scf_pg_create(h);
2873         pg_startd = safe_scf_pg_create(h);
2874         prop = safe_scf_property_create(h);
2875 
2876         ret = NULL;
2877 
2878         *restart_on = METHOD_RESTART_UNKNOWN;
2879 
2880         switch (type) {
2881         case METHOD_START:
2882                 name = "start";
2883                 break;
2884         case METHOD_STOP:
2885                 name = "stop";
2886                 break;
2887         case METHOD_REFRESH:
2888                 name = "refresh";
2889                 break;
2890         default:
2891                 error = LIBSCF_PROPERTY_ERROR;
2892                 goto get_method_cleanup;
2893         }
2894 
2895         if (scf_handle_decode_fmri(h, inst->ri_i.i_fmri, NULL, NULL, scf_inst,
2896             NULL, NULL, SCF_DECODE_FMRI_EXACT) == -1) {
2897                 log_error(LOG_WARNING,
2898                     "%s: get_method decode instance FMRI failed: %s\n",
2899                     inst->ri_i.i_fmri, scf_strerror(scf_error()));
2900                 error = LIBSCF_PROPERTY_ERROR;
2901                 goto get_method_cleanup;
2902         }
2903 
2904         if (scf_instance_get_pg_composed(scf_inst, snap, name, pg) == -1) {
2905                 if (scf_error() == SCF_ERROR_NOT_FOUND)
2906                         error = LIBSCF_PGROUP_ABSENT;
2907                 else
2908                         error = LIBSCF_PROPERTY_ERROR;
2909                 goto get_method_cleanup;
2910         }
2911 
2912         if (scf_pg_get_property(pg, SCF_PROPERTY_EXEC, prop) == -1) {
2913                 if (scf_error() == SCF_ERROR_NOT_FOUND)
2914                         error = LIBSCF_PROPERTY_ABSENT;
2915                 else
2916                         error = LIBSCF_PROPERTY_ERROR;
2917                 goto get_method_cleanup;
2918         }
2919 
2920         error = libscf_read_single_astring(h, prop, &method);
2921         if (error != 0) {
2922                 log_error(LOG_WARNING,
2923                     "%s: get_method failed: can't get a single astring "
2924                     "from %s/%s\n", inst->ri_i.i_fmri, name, SCF_PROPERTY_EXEC);
2925                 goto get_method_cleanup;
2926         }
2927 
2928         error = expand_method_tokens(method, scf_inst, snap, type, &ret);
2929         if (error != 0) {
2930                 log_instance(inst, B_TRUE, "Could not expand method tokens "
2931                     "in \"%s\": %s.", method, ret);
2932                 error = LIBSCF_PROPERTY_ERROR;
2933                 goto get_method_cleanup;
2934         }
2935 
2936         r = get_count(pg, SCF_PROPERTY_TIMEOUT, timeout);
2937         switch (r) {
2938         case 0:
2939                 break;
2940 
2941         case ECONNABORTED:
2942                 error = LIBSCF_PROPERTY_ERROR;
2943                 goto get_method_cleanup;
2944 
2945         case EINVAL:
2946                 log_instance(inst, B_TRUE, "%s/%s is multi-valued or not of "
2947                     "type count.  Using infinite timeout.", name,
2948                     SCF_PROPERTY_TIMEOUT);
2949                 /* FALLTHROUGH */
2950         case ECANCELED:
2951         case ENOENT:
2952                 *timeout = METHOD_TIMEOUT_INFINITE;
2953                 break;
2954 
2955         case EACCES:
2956         default:
2957                 bad_error("get_count", r);
2958         }
2959 
2960         /* Both 0 and -1 (ugh) are considered infinite timeouts. */
2961         if (*timeout == -1 || *timeout == 0)
2962                 *timeout = METHOD_TIMEOUT_INFINITE;
2963 
2964         if (scf_instance_get_pg_composed(scf_inst, snap, SCF_PG_STARTD,
2965             pg_startd) == -1) {
2966                 switch (scf_error()) {
2967                 case SCF_ERROR_CONNECTION_BROKEN:
2968                 case SCF_ERROR_DELETED:
2969                         error = LIBSCF_PROPERTY_ERROR;
2970                         goto get_method_cleanup;
2971 
2972                 case SCF_ERROR_NOT_FOUND:
2973                         *cte_mask = 0;
2974                         break;
2975 
2976                 case SCF_ERROR_INVALID_ARGUMENT:
2977                 case SCF_ERROR_HANDLE_MISMATCH:
2978                 case SCF_ERROR_NOT_BOUND:
2979                 case SCF_ERROR_NOT_SET:
2980                         bad_error("scf_instance_get_pg_composed", scf_error());
2981                 }
2982         } else {
2983                 if (scf_pg_get_property(pg_startd, SCF_PROPERTY_IGNORE,
2984                     prop) == -1) {
2985                         if (scf_error() == SCF_ERROR_NOT_FOUND)
2986                                 *cte_mask = 0;
2987                         else {
2988                                 error = LIBSCF_PROPERTY_ERROR;
2989                                 goto get_method_cleanup;
2990                         }
2991                 } else {
2992                         error = libscf_read_single_astring(h, prop, &ig);
2993                         if (error != 0) {
2994                                 log_error(LOG_WARNING,
2995                                     "%s: get_method failed: can't get a single "
2996                                     "astring from %s/%s\n", inst->ri_i.i_fmri,
2997                                     name, SCF_PROPERTY_IGNORE);
2998                                 goto get_method_cleanup;
2999                         }
3000 
3001                         if (strcmp(ig, "core") == 0)
3002                                 *cte_mask = CT_PR_EV_CORE;
3003                         else if (strcmp(ig, "signal") == 0)
3004                                 *cte_mask = CT_PR_EV_SIGNAL;
3005                         else if (strcmp(ig, "core,signal") == 0 ||
3006                             strcmp(ig, "signal,core") == 0)
3007                                 *cte_mask = CT_PR_EV_CORE | CT_PR_EV_SIGNAL;
3008                         else
3009                                 *cte_mask = 0;
3010                 }
3011 
3012                 r = get_boolean(pg_startd, SCF_PROPERTY_NEED_SESSION,
3013                     need_sessionp);
3014                 switch (r) {
3015                 case 0:
3016                         break;
3017 
3018                 case ECONNABORTED:
3019                         error = LIBSCF_PROPERTY_ERROR;
3020                         goto get_method_cleanup;
3021 
3022                 case ECANCELED:
3023                 case ENOENT:
3024                 case EINVAL:
3025                         *need_sessionp = 0;
3026                         break;
3027 
3028                 case EACCES:
3029                 default:
3030                         bad_error("get_boolean", r);
3031                 }
3032 
3033                 /*
3034                  * Determine whether service has overriden retry after
3035                  * method timeout.  Default to retry if no value is
3036                  * specified.
3037                  */
3038                 r = get_boolean(pg_startd, SCF_PROPERTY_TIMEOUT_RETRY,
3039                     timeout_retry);
3040                 switch (r) {
3041                 case 0:
3042                         break;
3043 
3044                 case ECONNABORTED:
3045                         error = LIBSCF_PROPERTY_ERROR;
3046                         goto get_method_cleanup;
3047 
3048                 case ECANCELED:
3049                 case ENOENT:
3050                 case EINVAL:
3051                         *timeout_retry = 1;
3052                         break;
3053 
3054                 case EACCES:
3055                 default:
3056                         bad_error("get_boolean", r);
3057                 }
3058         }
3059 
3060         if (type != METHOD_START)
3061                 goto get_method_cleanup;
3062 
3063         /* Only start methods need to honor the restart_on property. */
3064 
3065         if (scf_pg_get_property(pg, SCF_PROPERTY_RESTART_ON, prop) == -1) {
3066                 if (scf_error() == SCF_ERROR_NOT_FOUND)
3067                         *restart_on = METHOD_RESTART_ALL;
3068                 else
3069                         error = LIBSCF_PROPERTY_ERROR;
3070                 goto get_method_cleanup;
3071         }
3072 
3073         error = libscf_read_single_astring(h, prop, &restart);
3074         if (error != 0) {
3075                 log_error(LOG_WARNING,
3076                     "%s: get_method failed: can't get a single astring "
3077                     "from %s/%s\n", inst->ri_i.i_fmri, name,
3078                     SCF_PROPERTY_RESTART_ON);
3079                 goto get_method_cleanup;
3080         }
3081 
3082         if (strcmp(restart, "all") == 0)
3083                 *restart_on = METHOD_RESTART_ALL;
3084         else if (strcmp(restart, "external_fault") == 0)
3085                 *restart_on = METHOD_RESTART_EXTERNAL_FAULT;
3086         else if (strcmp(restart, "any_fault") == 0)
3087                 *restart_on = METHOD_RESTART_ANY_FAULT;
3088 
3089 get_method_cleanup:
3090         startd_free(ig, max_scf_value_size);
3091         startd_free(method, max_scf_value_size);
3092         startd_free(restart, max_scf_value_size);
3093 
3094         scf_instance_destroy(scf_inst);
3095         scf_pg_destroy(pg);
3096         scf_pg_destroy(pg_startd);
3097         scf_property_destroy(prop);
3098 
3099         if (error != 0 && ret != NULL) {
3100                 free(ret);
3101                 ret = NULL;
3102         }
3103 
3104         errno = error;
3105         return (ret);
3106 }
3107 
3108 /*
3109  * Returns 1 if we've reached the fault threshold
3110  */
3111 int
3112 update_fault_count(restarter_inst_t *inst, int type)
3113 {
3114         assert(type == FAULT_COUNT_INCR || type == FAULT_COUNT_RESET);
3115 
3116         if (type == FAULT_COUNT_INCR) {
3117                 inst->ri_i.i_fault_count++;
3118                 log_framework(LOG_INFO, "%s: Increasing fault count to %d\n",
3119                     inst->ri_i.i_fmri, inst->ri_i.i_fault_count);
3120         }
3121         if (type == FAULT_COUNT_RESET)
3122                 inst->ri_i.i_fault_count = 0;
3123 
3124         if (inst->ri_i.i_fault_count >= FAULT_THRESHOLD)
3125                 return (1);
3126 
3127         return (0);
3128 }
3129 
3130 /*
3131  * int libscf_unset_action()
3132  *   Delete any pending timestamps for the specified action which is
3133  *   older than the supplied ts.
3134  *
3135  *   Returns 0 on success, ECONNABORTED, EACCES, or EPERM on failure.
3136  */
3137 int
3138 libscf_unset_action(scf_handle_t *h, scf_propertygroup_t *pg,
3139     admin_action_t a, hrtime_t ts)
3140 {
3141         scf_transaction_t *t;
3142         scf_transaction_entry_t *e;
3143         scf_property_t *prop;
3144         scf_value_t *val;
3145         hrtime_t rep_ts;
3146         int ret = 0, r;
3147 
3148         t = safe_scf_transaction_create(h);
3149         e = safe_scf_entry_create(h);
3150         prop = safe_scf_property_create(h);
3151         val = safe_scf_value_create(h);
3152 
3153         for (;;) {
3154                 if (scf_pg_update(pg) == -1) {
3155                         switch (scf_error()) {
3156                         case SCF_ERROR_CONNECTION_BROKEN:
3157                         default:
3158                                 ret = ECONNABORTED;
3159                                 goto unset_action_cleanup;
3160 
3161                         case SCF_ERROR_DELETED:
3162                                 goto unset_action_cleanup;
3163 
3164                         case SCF_ERROR_NOT_SET:
3165                                 assert(0);
3166                                 abort();
3167                         }
3168                 }
3169 
3170                 if (scf_transaction_start(t, pg) == -1) {
3171                         switch (scf_error()) {
3172                         case SCF_ERROR_CONNECTION_BROKEN:
3173                         default:
3174                                 ret = ECONNABORTED;
3175                                 goto unset_action_cleanup;
3176 
3177                         case SCF_ERROR_DELETED:
3178                                 goto unset_action_cleanup;
3179 
3180                         case SCF_ERROR_PERMISSION_DENIED:
3181                                 ret = EPERM;
3182                                 goto unset_action_cleanup;
3183 
3184                         case SCF_ERROR_BACKEND_ACCESS:
3185                         case SCF_ERROR_BACKEND_READONLY:
3186                                 ret = EACCES;
3187                                 goto unset_action_cleanup;
3188 
3189                         case SCF_ERROR_IN_USE:
3190                         case SCF_ERROR_HANDLE_MISMATCH:
3191                         case SCF_ERROR_NOT_SET:
3192                                 assert(0);
3193                                 abort();
3194                         }
3195                 }
3196 
3197                 /* Return failure only if the property hasn't been deleted. */
3198                 if (scf_pg_get_property(pg, admin_actions[a], prop) == -1) {
3199                         switch (scf_error()) {
3200                         case SCF_ERROR_CONNECTION_BROKEN:
3201                         default:
3202                                 ret = ECONNABORTED;
3203                                 goto unset_action_cleanup;
3204 
3205                         case SCF_ERROR_DELETED:
3206                         case SCF_ERROR_NOT_FOUND:
3207                                 goto unset_action_cleanup;
3208 
3209                         case SCF_ERROR_HANDLE_MISMATCH:
3210                         case SCF_ERROR_INVALID_ARGUMENT:
3211                         case SCF_ERROR_NOT_SET:
3212                                 assert(0);
3213                                 abort();
3214                         }
3215                 }
3216 
3217                 if (scf_property_get_value(prop, val) == -1) {
3218                         switch (scf_error()) {
3219                         case SCF_ERROR_CONNECTION_BROKEN:
3220                         default:
3221                                 ret = ECONNABORTED;
3222                                 goto unset_action_cleanup;
3223 
3224                         case SCF_ERROR_DELETED:
3225                         case SCF_ERROR_NOT_FOUND:
3226                                 goto unset_action_cleanup;
3227 
3228                         case SCF_ERROR_CONSTRAINT_VIOLATED:
3229                                 /*
3230                                  * More than one value was associated with
3231                                  * this property -- this is incorrect. Take
3232                                  * the opportunity to clean up and clear the
3233                                  * entire property.
3234                                  */
3235                                 rep_ts = ts;
3236                                 break;
3237 
3238                         case SCF_ERROR_PERMISSION_DENIED:
3239                         case SCF_ERROR_NOT_SET:
3240                                 assert(0);
3241                                 abort();
3242                         }
3243                 } else if (scf_value_get_integer(val, &rep_ts) == -1) {
3244                         assert(scf_error() == SCF_ERROR_TYPE_MISMATCH);
3245                         rep_ts = 0;
3246                 }
3247 
3248                 /* Repository ts is more current. Don't clear the action. */
3249                 if (rep_ts > ts)
3250                         goto unset_action_cleanup;
3251 
3252                 r = scf_transaction_property_change_type(t, e,
3253                     admin_actions[a], SCF_TYPE_INTEGER);
3254                 assert(r == 0);
3255 
3256                 r = scf_transaction_commit(t);
3257                 if (r == 1)
3258                         break;
3259 
3260                 if (r != 0) {
3261                         switch (scf_error()) {
3262                         case SCF_ERROR_CONNECTION_BROKEN:
3263                         default:
3264                                 ret = ECONNABORTED;
3265                                 goto unset_action_cleanup;
3266 
3267                         case SCF_ERROR_DELETED:
3268                                 break;
3269 
3270                         case SCF_ERROR_PERMISSION_DENIED:
3271                                 ret = EPERM;
3272                                 goto unset_action_cleanup;
3273 
3274                         case SCF_ERROR_BACKEND_ACCESS:
3275                         case SCF_ERROR_BACKEND_READONLY:
3276                                 ret = EACCES;
3277                                 goto unset_action_cleanup;
3278 
3279                         case SCF_ERROR_INVALID_ARGUMENT:
3280                         case SCF_ERROR_NOT_SET:
3281                                 assert(0);
3282                                 abort();
3283                         }
3284                 }
3285 
3286                 scf_transaction_reset(t);
3287         }
3288 
3289 unset_action_cleanup:
3290         scf_transaction_destroy(t);
3291         scf_entry_destroy(e);
3292         scf_property_destroy(prop);
3293         scf_value_destroy(val);
3294 
3295         return (ret);
3296 }
3297 
3298 /*
3299  * Decorates & binds hndl.  hndl must be unbound.  Returns
3300  *   0 - success
3301  *   -1 - repository server is not running
3302  *   -1 - repository server is out of resources
3303  */
3304 static int
3305 handle_decorate_and_bind(scf_handle_t *hndl)
3306 {
3307         scf_value_t *door_dec_value;
3308 
3309         door_dec_value = safe_scf_value_create(hndl);
3310 
3311         /*
3312          * Decorate if alternate door path set.
3313          */
3314         if (st->st_door_path) {
3315                 if (scf_value_set_astring(door_dec_value, st->st_door_path) !=
3316                     0)
3317                         uu_die("$STARTD_ALT_DOOR is too long.\n");
3318 
3319                 if (scf_handle_decorate(hndl, "door_path", door_dec_value) != 0)
3320                         bad_error("scf_handle_decorate", scf_error());
3321         }
3322 
3323         scf_value_destroy(door_dec_value);
3324 
3325         if (scf_handle_bind(hndl) == 0)
3326                 return (0);
3327 
3328         switch (scf_error()) {
3329         case SCF_ERROR_NO_SERVER:
3330         case SCF_ERROR_NO_RESOURCES:
3331                 return (-1);
3332 
3333         case SCF_ERROR_INVALID_ARGUMENT:
3334         case SCF_ERROR_IN_USE:
3335         default:
3336                 bad_error("scf_handle_bind", scf_error());
3337                 /* NOTREACHED */
3338         }
3339 }
3340 
3341 scf_handle_t *
3342 libscf_handle_create_bound(scf_version_t v)
3343 {
3344         scf_handle_t *hndl = scf_handle_create(v);
3345 
3346         if (hndl == NULL)
3347                 return (hndl);
3348 
3349         if (handle_decorate_and_bind(hndl) == 0)
3350                 return (hndl);
3351 
3352         scf_handle_destroy(hndl);
3353         return (NULL);
3354 }
3355 
3356 void
3357 libscf_handle_rebind(scf_handle_t *h)
3358 {
3359         (void) scf_handle_unbind(h);
3360 
3361         MUTEX_LOCK(&st->st_configd_live_lock);
3362 
3363         /*
3364          * Try to rebind the handle before sleeping in case the server isn't
3365          * really dead.
3366          */
3367         while (handle_decorate_and_bind(h) != 0)
3368                 (void) pthread_cond_wait(&st->st_configd_live_cv,
3369                     &st->st_configd_live_lock);
3370 
3371         MUTEX_UNLOCK(&st->st_configd_live_lock);
3372 }
3373 
3374 /*
3375  * Create a handle and try to bind it until it succeeds.  Always returns
3376  * a bound handle.
3377  */
3378 scf_handle_t *
3379 libscf_handle_create_bound_loop()
3380 {
3381         scf_handle_t *h;
3382 
3383         while ((h = scf_handle_create(SCF_VERSION)) == NULL) {
3384                 /* This should have been caught earlier. */
3385                 assert(scf_error() != SCF_ERROR_VERSION_MISMATCH);
3386                 (void) sleep(2);
3387         }
3388 
3389         if (handle_decorate_and_bind(h) != 0)
3390                 libscf_handle_rebind(h);
3391 
3392         return (h);
3393 }
3394 
3395 /*
3396  * Call cb for each dependency property group of inst.  cb is invoked with
3397  * a pointer to the scf_propertygroup_t and arg.  If the repository connection
3398  * is broken, returns ECONNABORTED.  If inst is deleted, returns ECANCELED.
3399  * If cb returns non-zero, the walk is stopped and EINTR is returned.
3400  * Otherwise returns 0.
3401  */
3402 int
3403 walk_dependency_pgs(scf_instance_t *inst, callback_t cb, void *arg)
3404 {
3405         scf_handle_t *h;
3406         scf_snapshot_t *snap;
3407         scf_iter_t *iter;
3408         scf_propertygroup_t *pg;
3409         int r;
3410 
3411         h = scf_instance_handle(inst);
3412 
3413         iter = safe_scf_iter_create(h);
3414         pg = safe_scf_pg_create(h);
3415 
3416         snap = libscf_get_running_snapshot(inst);
3417 
3418         if (scf_iter_instance_pgs_typed_composed(iter, inst, snap,
3419             SCF_GROUP_DEPENDENCY) != 0) {
3420                 scf_snapshot_destroy(snap);
3421                 scf_pg_destroy(pg);
3422                 scf_iter_destroy(iter);
3423                 switch (scf_error()) {
3424                 case SCF_ERROR_CONNECTION_BROKEN:
3425                 default:
3426                         return (ECONNABORTED);
3427 
3428                 case SCF_ERROR_DELETED:
3429                         return (ECANCELED);
3430 
3431                 case SCF_ERROR_HANDLE_MISMATCH:
3432                 case SCF_ERROR_INVALID_ARGUMENT:
3433                 case SCF_ERROR_NOT_SET:
3434                         assert(0);
3435                         abort();
3436                 }
3437         }
3438 
3439         for (;;) {
3440                 r = scf_iter_next_pg(iter, pg);
3441                 if (r == 0)
3442                         break;
3443                 if (r == -1) {
3444                         scf_snapshot_destroy(snap);
3445                         scf_pg_destroy(pg);
3446                         scf_iter_destroy(iter);
3447 
3448                         switch (scf_error()) {
3449                         case SCF_ERROR_CONNECTION_BROKEN:
3450                                 return (ECONNABORTED);
3451 
3452                         case SCF_ERROR_DELETED:
3453                                 return (ECANCELED);
3454 
3455                         case SCF_ERROR_NOT_SET:
3456                         case SCF_ERROR_INVALID_ARGUMENT:
3457                         case SCF_ERROR_NOT_BOUND:
3458                         case SCF_ERROR_HANDLE_MISMATCH:
3459                         default:
3460                                 bad_error("scf_iter_next_pg", scf_error());
3461                         }
3462                 }
3463 
3464                 r = cb(pg, arg);
3465 
3466                 if (r != 0)
3467                         break;
3468         }
3469 
3470         scf_snapshot_destroy(snap);
3471         scf_pg_destroy(pg);
3472         scf_iter_destroy(iter);
3473 
3474         return (r == 0 ? 0 : EINTR);
3475 }
3476 
3477 /*
3478  * Call cb for each of the string values of prop.  cb is invoked with
3479  * a pointer to the string and arg.  If the connection to the repository is
3480  * broken, ECONNABORTED is returned.  If the property is deleted, ECANCELED is
3481  * returned.  If the property does not have astring type, EINVAL is returned.
3482  * If cb returns non-zero, the walk is stopped and EINTR is returned.
3483  * Otherwise 0 is returned.
3484  */
3485 int
3486 walk_property_astrings(scf_property_t *prop, callback_t cb, void *arg)
3487 {
3488         scf_handle_t *h;
3489         scf_value_t *val;
3490         scf_iter_t *iter;
3491         char *buf;
3492         int r;
3493         ssize_t sz;
3494 
3495         if (scf_property_is_type(prop, SCF_TYPE_ASTRING) != 0) {
3496                 switch (scf_error()) {
3497                 case SCF_ERROR_CONNECTION_BROKEN:
3498                 default:
3499                         return (ECONNABORTED);
3500 
3501                 case SCF_ERROR_DELETED:
3502                         return (ECANCELED);
3503 
3504                 case SCF_ERROR_TYPE_MISMATCH:
3505                         return (EINVAL);
3506 
3507                 case SCF_ERROR_NOT_SET:
3508                         assert(0);
3509                         abort();
3510                 }
3511         }
3512 
3513         h = scf_property_handle(prop);
3514 
3515         val = safe_scf_value_create(h);
3516         iter = safe_scf_iter_create(h);
3517 
3518         if (scf_iter_property_values(iter, prop) != 0) {
3519                 scf_iter_destroy(iter);
3520                 scf_value_destroy(val);
3521                 switch (scf_error()) {
3522                 case SCF_ERROR_CONNECTION_BROKEN:
3523                 default:
3524                         return (ECONNABORTED);
3525 
3526                 case SCF_ERROR_DELETED:
3527                         return (ECANCELED);
3528 
3529                 case SCF_ERROR_HANDLE_MISMATCH:
3530                 case SCF_ERROR_NOT_SET:
3531                         assert(0);
3532                         abort();
3533                 }
3534         }
3535 
3536         buf = startd_alloc(max_scf_value_size);
3537 
3538         for (;;) {
3539                 r = scf_iter_next_value(iter, val);
3540                 if (r < 0) {
3541                         startd_free(buf, max_scf_value_size);
3542                         scf_iter_destroy(iter);
3543                         scf_value_destroy(val);
3544 
3545                         switch (scf_error()) {
3546                         case SCF_ERROR_CONNECTION_BROKEN:
3547                                 return (ECONNABORTED);
3548 
3549                         case SCF_ERROR_DELETED:
3550                                 return (ECANCELED);
3551 
3552                         case SCF_ERROR_NOT_SET:
3553                         case SCF_ERROR_INVALID_ARGUMENT:
3554                         case SCF_ERROR_NOT_BOUND:
3555                         case SCF_ERROR_HANDLE_MISMATCH:
3556                         case SCF_ERROR_PERMISSION_DENIED:
3557                         default:
3558                                 bad_error("scf_iter_next_value", scf_error());
3559                         }
3560                 }
3561                 if (r == 0)
3562                         break;
3563 
3564                 sz = scf_value_get_astring(val, buf, max_scf_value_size);
3565                 assert(sz >= 0);
3566 
3567                 r = cb(buf, arg);
3568 
3569                 if (r != 0)
3570                         break;
3571         }
3572 
3573         startd_free(buf, max_scf_value_size);
3574         scf_value_destroy(val);
3575         scf_iter_destroy(iter);
3576 
3577         return (r == 0 ? 0 : EINTR);
3578 }
3579 
3580 /*
3581  * Returns 0 or ECONNABORTED.
3582  */
3583 int
3584 libscf_create_self(scf_handle_t *h)
3585 {
3586         scf_scope_t *scope;
3587         scf_service_t *svc;
3588         scf_instance_t *inst;
3589         instance_data_t idata;
3590         int ret = 0, r;
3591         ctid_t ctid;
3592         uint64_t uint64;
3593         uint_t count = 0, msecs = ALLOC_DELAY;
3594 
3595         const char * const startd_svc = "system/svc/restarter";
3596         const char * const startd_inst = "default";
3597 
3598         /* If SCF_SERVICE_STARTD changes, our strings must change, too. */
3599         assert(strcmp(SCF_SERVICE_STARTD,
3600             "svc:/system/svc/restarter:default") == 0);
3601 
3602         scope = safe_scf_scope_create(h);
3603         svc = safe_scf_service_create(h);
3604         inst = safe_scf_instance_create(h);
3605 
3606         if (scf_handle_get_scope(h, SCF_SCOPE_LOCAL, scope) != 0) {
3607                 assert(scf_error() == SCF_ERROR_CONNECTION_BROKEN);
3608                 ret = ECONNABORTED;
3609                 goto out;
3610         }
3611 
3612 get_svc:
3613         if (scf_scope_get_service(scope, startd_svc, svc) != 0) {
3614                 switch (scf_error()) {
3615                 case SCF_ERROR_CONNECTION_BROKEN:
3616                 case SCF_ERROR_DELETED:
3617                 default:
3618                         ret = ECONNABORTED;
3619                         goto out;
3620 
3621                 case SCF_ERROR_NOT_FOUND:
3622                         break;
3623 
3624                 case SCF_ERROR_HANDLE_MISMATCH:
3625                 case SCF_ERROR_INVALID_ARGUMENT:
3626                 case SCF_ERROR_NOT_SET:
3627                         bad_error("scf_scope_get_service", scf_error());
3628                 }
3629 
3630 add_svc:
3631                 if (scf_scope_add_service(scope, startd_svc, svc) != 0) {
3632                         switch (scf_error()) {
3633                         case SCF_ERROR_CONNECTION_BROKEN:
3634                         case SCF_ERROR_DELETED:
3635                         default:
3636                                 ret = ECONNABORTED;
3637                                 goto out;
3638 
3639                         case SCF_ERROR_EXISTS:
3640                                 goto get_svc;
3641 
3642                         case SCF_ERROR_PERMISSION_DENIED:
3643                         case SCF_ERROR_BACKEND_ACCESS:
3644                         case SCF_ERROR_BACKEND_READONLY:
3645                                 uu_warn("Could not create %s: %s\n",
3646                                     SCF_SERVICE_STARTD,
3647                                     scf_strerror(scf_error()));
3648                                 goto out;
3649 
3650                         case SCF_ERROR_HANDLE_MISMATCH:
3651                         case SCF_ERROR_INVALID_ARGUMENT:
3652                         case SCF_ERROR_NOT_SET:
3653                                 bad_error("scf_scope_add_service", scf_error());
3654                         }
3655                 }
3656         }
3657 
3658         if (scf_service_get_instance(svc, startd_inst, NULL) == 0)
3659                 goto out;
3660 
3661         switch (scf_error()) {
3662         case SCF_ERROR_CONNECTION_BROKEN:
3663         default:
3664                 ret = ECONNABORTED;
3665                 goto out;
3666 
3667         case SCF_ERROR_NOT_FOUND:
3668                 break;
3669 
3670         case SCF_ERROR_DELETED:
3671                 goto add_svc;
3672 
3673         case SCF_ERROR_HANDLE_MISMATCH:
3674         case SCF_ERROR_INVALID_ARGUMENT:
3675         case SCF_ERROR_NOT_SET:
3676                 bad_error("scf_service_get_instance", scf_error());
3677         }
3678 
3679 add_inst:
3680         if (scf_service_add_instance(svc, startd_inst, inst) != 0) {
3681                 switch (scf_error()) {
3682                 case SCF_ERROR_CONNECTION_BROKEN:
3683                 default:
3684                         ret = ECONNABORTED;
3685                         goto out;
3686 
3687                 case SCF_ERROR_EXISTS:
3688                         break;
3689 
3690                 case SCF_ERROR_PERMISSION_DENIED:
3691                 case SCF_ERROR_BACKEND_ACCESS:
3692                         uu_die("Could not create %s: %s\n", SCF_SERVICE_STARTD,
3693                             scf_strerror(scf_error()));
3694                         /* NOTREACHED */
3695 
3696                 case SCF_ERROR_BACKEND_READONLY:
3697                         log_error(LOG_NOTICE,
3698                             "Could not create %s: backend readonly.\n",
3699                             SCF_SERVICE_STARTD);
3700                         goto out;
3701 
3702                 case SCF_ERROR_DELETED:
3703                         goto add_svc;
3704 
3705                 case SCF_ERROR_HANDLE_MISMATCH:
3706                 case SCF_ERROR_INVALID_ARGUMENT:
3707                 case SCF_ERROR_NOT_SET:
3708                         bad_error("scf_service_add_instance", scf_error());
3709                 }
3710         }
3711 
3712         /* Set start time. */
3713         idata.i_fmri = SCF_SERVICE_STARTD;
3714         idata.i_state = RESTARTER_STATE_NONE;
3715         idata.i_next_state = RESTARTER_STATE_NONE;
3716 set_state:
3717         switch (r = _restarter_commit_states(h, &idata,
3718             RESTARTER_STATE_ONLINE, RESTARTER_STATE_NONE,
3719             restarter_get_str_short(restarter_str_insert_in_graph))) {
3720         case 0:
3721                 break;
3722 
3723         case ENOMEM:
3724                 ++count;
3725                 if (count < ALLOC_RETRY) {
3726                         (void) poll(NULL, 0, msecs);
3727                         msecs *= ALLOC_DELAY_MULT;
3728                         goto set_state;
3729                 }
3730 
3731                 uu_die("Insufficient memory.\n");
3732                 /* NOTREACHED */
3733 
3734         case ECONNABORTED:
3735                 ret = ECONNABORTED;
3736                 goto out;
3737 
3738         case ENOENT:
3739                 goto add_inst;
3740 
3741         case EPERM:
3742         case EACCES:
3743         case EROFS:
3744                 uu_warn("Could not timestamp %s: %s\n", idata.i_fmri,
3745                     strerror(r));
3746                 break;
3747 
3748         case EINVAL:
3749         default:
3750                 bad_error("_restarter_commit_states", r);
3751         }
3752 
3753         /* Set general/enabled. */
3754         ret = libscf_inst_set_boolean_prop(inst, SCF_PG_GENERAL,
3755             SCF_PG_GENERAL_TYPE, SCF_PG_GENERAL_FLAGS, SCF_PROPERTY_ENABLED, 1);
3756         switch (ret) {
3757         case 0:
3758         case ECONNABORTED:
3759         case EPERM:
3760         case EACCES:
3761         case EROFS:
3762                 break;
3763 
3764         case ECANCELED:
3765                 goto add_inst;
3766 
3767         default:
3768                 bad_error("libscf_inst_set_boolean_prop", ret);
3769         }
3770 
3771         ret = libscf_write_start_pid(inst, getpid());
3772         switch (ret) {
3773         case 0:
3774         case ECONNABORTED:
3775         case EPERM:
3776         case EACCES:
3777         case EROFS:
3778                 break;
3779 
3780         case ECANCELED:
3781                 goto add_inst;
3782 
3783         default:
3784                 bad_error("libscf_write_start_pid", ret);
3785         }
3786 
3787         ctid = proc_get_ctid();
3788         if (ctid > 0) {
3789 
3790                 uint64 = (uint64_t)ctid;
3791                 ret = libscf_inst_set_count_prop(inst,
3792                     SCF_PG_RESTARTER, SCF_PG_RESTARTER_TYPE,
3793                     SCF_PG_RESTARTER_FLAGS, SCF_PROPERTY_CONTRACT, uint64);
3794 
3795                 switch (ret) {
3796                 case 0:
3797                 case ECONNABORTED:
3798                 case EPERM:
3799                 case EACCES:
3800                 case EROFS:
3801                         break;
3802 
3803                 case ECANCELED:
3804                         goto add_inst;
3805 
3806                 default:
3807                         bad_error("libscf_inst_set_count_prop", ret);
3808                 }
3809         }
3810 
3811         ret = libscf_note_method_log(inst, LOG_PREFIX_EARLY,
3812             STARTD_DEFAULT_LOG);
3813         if (ret == 0) {
3814                 ret = libscf_note_method_log(inst, LOG_PREFIX_NORMAL,
3815                     STARTD_DEFAULT_LOG);
3816         }
3817 
3818         switch (ret) {
3819                 case 0:
3820                 case ECONNABORTED:
3821                 case EPERM:
3822                 case EACCES:
3823                 case EROFS:
3824                 case EAGAIN:
3825                         break;
3826 
3827                 case ECANCELED:
3828                         goto add_inst;
3829 
3830                 default:
3831                         bad_error("libscf_note_method_log", ret);
3832         }
3833 
3834 out:
3835         scf_instance_destroy(inst);
3836         scf_service_destroy(svc);
3837         scf_scope_destroy(scope);
3838         return (ret);
3839 }
3840 
3841 /*
3842  * Returns
3843  *   0 - success
3844  *   ENOENT - SCF_SERVICE_STARTD does not exist in repository
3845  *   EPERM
3846  *   EACCES
3847  *   EROFS
3848  */
3849 int
3850 libscf_set_reconfig(int set)
3851 {
3852         scf_handle_t *h;
3853         scf_instance_t *inst;
3854         scf_propertygroup_t *pg;
3855         int ret = 0;
3856 
3857         h = libscf_handle_create_bound_loop();
3858         inst = safe_scf_instance_create(h);
3859         pg = safe_scf_pg_create(h);
3860 
3861 again:
3862         if (scf_handle_decode_fmri(h, SCF_SERVICE_STARTD, NULL, NULL,
3863             inst, NULL, NULL,  SCF_DECODE_FMRI_EXACT) == -1) {
3864                 switch (scf_error()) {
3865                 case SCF_ERROR_CONNECTION_BROKEN:
3866                 default:
3867                         libscf_handle_rebind(h);
3868                         goto again;
3869 
3870                 case SCF_ERROR_NOT_FOUND:
3871                         ret = ENOENT;
3872                         goto reconfig_out;
3873 
3874                 case SCF_ERROR_HANDLE_MISMATCH:
3875                 case SCF_ERROR_INVALID_ARGUMENT:
3876                 case SCF_ERROR_CONSTRAINT_VIOLATED:
3877                         bad_error("scf_handle_decode_fmri", scf_error());
3878                 }
3879         }
3880 
3881         ret = libscf_inst_set_boolean_prop(inst, "system", SCF_GROUP_FRAMEWORK,
3882             SCF_PG_FLAG_NONPERSISTENT, "reconfigure", set);
3883         switch (ret) {
3884         case 0:
3885         case EPERM:
3886         case EACCES:
3887         case EROFS:
3888                 break;
3889 
3890         case ECONNABORTED:
3891                 libscf_handle_rebind(h);
3892                 goto again;
3893 
3894         case ECANCELED:
3895                 ret = ENOENT;
3896                 break;
3897 
3898         default:
3899                 bad_error("libscf_inst_set_boolean_prop", ret);
3900         }
3901 
3902 reconfig_out:
3903         scf_pg_destroy(pg);
3904         scf_instance_destroy(inst);
3905         scf_handle_destroy(h);
3906         return (ret);
3907 }
3908 
3909 /*
3910  * Set inst->ri_m_inst to the scf instance for inst.  If it has been deleted,
3911  * set inst->ri_mi_deleted to true.  If the repository connection is broken, it
3912  * is rebound with libscf_handle_rebound().
3913  */
3914 void
3915 libscf_reget_instance(restarter_inst_t *inst)
3916 {
3917         scf_handle_t *h;
3918         int r;
3919 
3920         h = scf_instance_handle(inst->ri_m_inst);
3921 
3922 again:
3923         r = libscf_lookup_instance(inst->ri_i.i_fmri, inst->ri_m_inst);
3924         switch (r) {
3925         case 0:
3926         case ENOENT:
3927                 inst->ri_mi_deleted = (r == ENOENT);
3928                 return;
3929 
3930         case ECONNABORTED:
3931                 libscf_handle_rebind(h);
3932                 goto again;
3933 
3934         case EINVAL:
3935         case ENOTSUP:
3936         default:
3937                 bad_error("libscf_lookup_instance", r);
3938         }
3939 }