1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2013, Joyent, Inc. All rights reserved.
  25  * Copyright 2016 RackTop Systems.
  26  * Copyright (c) 2016 by Delphix. All rights reserved.
  27  * Copyright 2017 OmniOS Community Edition (OmniOSce) Association.
  28  */
  29 
  30 /*
  31  * This is the main implementation file for the low-level repository
  32  * interface.
  33  */
  34 
  35 #include "lowlevel_impl.h"
  36 
  37 #include "repcache_protocol.h"
  38 #include "scf_type.h"
  39 
  40 #include <assert.h>
  41 #include <door.h>
  42 #include <errno.h>
  43 #include <fcntl.h>
  44 #include <fnmatch.h>
  45 #include <libuutil.h>
  46 #include <poll.h>
  47 #include <pthread.h>
  48 #include <synch.h>
  49 #include <stddef.h>
  50 #include <stdio.h>
  51 #include <stdlib.h>
  52 #include <string.h>
  53 #include <sys/mman.h>
  54 #include <sys/sysmacros.h>
  55 #include <libzonecfg.h>
  56 #include <unistd.h>
  57 #include <dlfcn.h>
  58 
  59 #define ENV_SCF_DEBUG           "LIBSCF_DEBUG"
  60 #define ENV_SCF_DOORPATH        "LIBSCF_DOORPATH"
  61 
  62 static uint32_t default_debug = 0;
  63 static const char *default_door_path = REPOSITORY_DOOR_NAME;
  64 
  65 #define CALL_FAILED             -1
  66 #define RESULT_TOO_BIG          -2
  67 #define NOT_BOUND               -3
  68 
  69 static pthread_mutex_t  lowlevel_init_lock;
  70 static int32_t          lowlevel_inited;
  71 
  72 static uu_list_pool_t   *tran_entry_pool;
  73 static uu_list_pool_t   *datael_pool;
  74 static uu_list_pool_t   *iter_pool;
  75 
  76 /*
  77  * base32[] index32[] are used in base32 encoding and decoding.
  78  */
  79 static char base32[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
  80 static char index32[128] = {
  81         -1, -1, -1, -1, -1, -1, -1, -1, /* 0-7 */
  82         -1, -1, -1, -1, -1, -1, -1, -1, /* 8-15 */
  83         -1, -1, -1, -1, -1, -1, -1, -1, /* 16-23 */
  84         -1, -1, -1, -1, -1, -1, -1, -1, /* 24-31 */
  85         -1, -1, -1, -1, -1, -1, -1, -1, /* 32-39 */
  86         -1, -1, -1, -1, -1, -1, -1, -1, /* 40-47 */
  87         -1, -1, 26, 27, 28, 29, 30, 31, /* 48-55 */
  88         -1, -1, -1, -1, -1, -1, -1, -1, /* 56-63 */
  89         -1, 0, 1, 2, 3, 4, 5, 6,        /* 64-71 */
  90         7, 8, 9, 10, 11, 12, 13, 14,    /* 72-79 */
  91         15, 16, 17, 18, 19, 20, 21, 22, /* 80-87 */
  92         23, 24, 25, -1, -1, -1, -1, -1, /* 88-95 */
  93         -1, -1, -1, -1, -1, -1, -1, -1, /* 96-103 */
  94         -1, -1, -1, -1, -1, -1, -1, -1, /* 104-111 */
  95         -1, -1, -1, -1, -1, -1, -1, -1, /* 112-119 */
  96         -1, -1, -1, -1, -1, -1, -1, -1  /* 120-127 */
  97 };
  98 
  99 #define DECODE32_GS     (8)     /* scf_decode32 group size */
 100 
 101 #ifdef lint
 102 #define assert_nolint(x) (void)0
 103 #else
 104 #define assert_nolint(x) assert(x)
 105 #endif
 106 
 107 static void scf_iter_reset_locked(scf_iter_t *iter);
 108 static void scf_value_reset_locked(scf_value_t *val, int and_destroy);
 109 
 110 #define TYPE_VALUE      (-100)
 111 
 112 /*
 113  * Hold and release subhandles.  We only allow one thread access to the
 114  * subhandles at a time, and it can use any subset, grabbing and releasing
 115  * them in any order.  The only restrictions are that you cannot hold an
 116  * already-held subhandle, and all subhandles must be released before
 117  * returning to the original caller.
 118  */
 119 static void
 120 handle_hold_subhandles(scf_handle_t *h, int mask)
 121 {
 122         assert(mask != 0 && (mask & ~RH_HOLD_ALL) == 0);
 123 
 124         (void) pthread_mutex_lock(&h->rh_lock);
 125         while (h->rh_hold_flags != 0 && h->rh_holder != pthread_self()) {
 126                 int cancel_state;
 127 
 128                 (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,
 129                     &cancel_state);
 130                 (void) pthread_cond_wait(&h->rh_cv, &h->rh_lock);
 131                 (void) pthread_setcancelstate(cancel_state, NULL);
 132         }
 133         if (h->rh_hold_flags == 0)
 134                 h->rh_holder = pthread_self();
 135         assert(!(h->rh_hold_flags & mask));
 136         h->rh_hold_flags |= mask;
 137         (void) pthread_mutex_unlock(&h->rh_lock);
 138 }
 139 
 140 static void
 141 handle_rele_subhandles(scf_handle_t *h, int mask)
 142 {
 143         assert(mask != 0 && (mask & ~RH_HOLD_ALL) == 0);
 144 
 145         (void) pthread_mutex_lock(&h->rh_lock);
 146         assert(h->rh_holder == pthread_self());
 147         assert((h->rh_hold_flags & mask));
 148 
 149         h->rh_hold_flags &= ~mask;
 150         if (h->rh_hold_flags == 0)
 151                 (void) pthread_cond_signal(&h->rh_cv);
 152         (void) pthread_mutex_unlock(&h->rh_lock);
 153 }
 154 
 155 #define HOLD_HANDLE(h, flag, field) \
 156         (handle_hold_subhandles((h), (flag)), (h)->field)
 157 
 158 #define RELE_HANDLE(h, flag) \
 159         (handle_rele_subhandles((h), (flag)))
 160 
 161 /*
 162  * convenience macros, for functions that only need a one or two handles at
 163  * any given time
 164  */
 165 #define HANDLE_HOLD_ITER(h)     HOLD_HANDLE((h), RH_HOLD_ITER, rh_iter)
 166 #define HANDLE_HOLD_SCOPE(h)    HOLD_HANDLE((h), RH_HOLD_SCOPE, rh_scope)
 167 #define HANDLE_HOLD_SERVICE(h)  HOLD_HANDLE((h), RH_HOLD_SERVICE, rh_service)
 168 #define HANDLE_HOLD_INSTANCE(h) HOLD_HANDLE((h), RH_HOLD_INSTANCE, rh_instance)
 169 #define HANDLE_HOLD_SNAPSHOT(h) HOLD_HANDLE((h), RH_HOLD_SNAPSHOT, rh_snapshot)
 170 #define HANDLE_HOLD_SNAPLVL(h)  HOLD_HANDLE((h), RH_HOLD_SNAPLVL, rh_snaplvl)
 171 #define HANDLE_HOLD_PG(h)       HOLD_HANDLE((h), RH_HOLD_PG, rh_pg)
 172 #define HANDLE_HOLD_PROPERTY(h) HOLD_HANDLE((h), RH_HOLD_PROPERTY, rh_property)
 173 #define HANDLE_HOLD_VALUE(h)    HOLD_HANDLE((h), RH_HOLD_VALUE, rh_value)
 174 
 175 #define HANDLE_RELE_ITER(h)     RELE_HANDLE((h), RH_HOLD_ITER)
 176 #define HANDLE_RELE_SCOPE(h)    RELE_HANDLE((h), RH_HOLD_SCOPE)
 177 #define HANDLE_RELE_SERVICE(h)  RELE_HANDLE((h), RH_HOLD_SERVICE)
 178 #define HANDLE_RELE_INSTANCE(h) RELE_HANDLE((h), RH_HOLD_INSTANCE)
 179 #define HANDLE_RELE_SNAPSHOT(h) RELE_HANDLE((h), RH_HOLD_SNAPSHOT)
 180 #define HANDLE_RELE_SNAPLVL(h)  RELE_HANDLE((h), RH_HOLD_SNAPLVL)
 181 #define HANDLE_RELE_PG(h)       RELE_HANDLE((h), RH_HOLD_PG)
 182 #define HANDLE_RELE_PROPERTY(h) RELE_HANDLE((h), RH_HOLD_PROPERTY)
 183 #define HANDLE_RELE_VALUE(h)    RELE_HANDLE((h), RH_HOLD_VALUE)
 184 
 185 /*ARGSUSED*/
 186 static int
 187 transaction_entry_compare(const void *l_arg, const void *r_arg, void *private)
 188 {
 189         const char *l_prop =
 190             ((scf_transaction_entry_t *)l_arg)->entry_property;
 191         const char *r_prop =
 192             ((scf_transaction_entry_t *)r_arg)->entry_property;
 193 
 194         int ret;
 195 
 196         ret = strcmp(l_prop, r_prop);
 197         if (ret > 0)
 198                 return (1);
 199         if (ret < 0)
 200                 return (-1);
 201         return (0);
 202 }
 203 
 204 static int
 205 datael_compare(const void *l_arg, const void *r_arg, void *private)
 206 {
 207         uint32_t l_id = ((scf_datael_t *)l_arg)->rd_entity;
 208         uint32_t r_id = (r_arg != NULL) ? ((scf_datael_t *)r_arg)->rd_entity :
 209             *(uint32_t *)private;
 210 
 211         if (l_id > r_id)
 212                 return (1);
 213         if (l_id < r_id)
 214                 return (-1);
 215         return (0);
 216 }
 217 
 218 static int
 219 iter_compare(const void *l_arg, const void *r_arg, void *private)
 220 {
 221         uint32_t l_id = ((scf_iter_t *)l_arg)->iter_id;
 222         uint32_t r_id = (r_arg != NULL) ? ((scf_iter_t *)r_arg)->iter_id :
 223             *(uint32_t *)private;
 224 
 225         if (l_id > r_id)
 226                 return (1);
 227         if (l_id < r_id)
 228                 return (-1);
 229         return (0);
 230 }
 231 
 232 static int
 233 lowlevel_init(void)
 234 {
 235         const char *debug;
 236         const char *door_path;
 237 
 238         (void) pthread_mutex_lock(&lowlevel_init_lock);
 239         if (lowlevel_inited == 0) {
 240                 if (!issetugid() &&
 241                     (debug = getenv(ENV_SCF_DEBUG)) != NULL && debug[0] != 0 &&
 242                     uu_strtoint(debug, &default_debug, sizeof (default_debug),
 243                     0, 0, 0) == -1) {
 244                         (void) fprintf(stderr, "LIBSCF: $%s (%s): %s",
 245                             ENV_SCF_DEBUG, debug,
 246                             uu_strerror(uu_error()));
 247                 }
 248 
 249                 if (!issetugid() &&
 250                     (door_path = getenv(ENV_SCF_DOORPATH)) != NULL &&
 251                     door_path[0] != 0) {
 252                         default_door_path = strdup(door_path);
 253                         if (default_door_path == NULL)
 254                                 default_door_path = door_path;
 255                 }
 256 
 257                 datael_pool = uu_list_pool_create("SUNW,libscf_datael",
 258                     sizeof (scf_datael_t), offsetof(scf_datael_t, rd_node),
 259                     datael_compare, UU_LIST_POOL_DEBUG);
 260 
 261                 iter_pool = uu_list_pool_create("SUNW,libscf_iter",
 262                     sizeof (scf_iter_t), offsetof(scf_iter_t, iter_node),
 263                     iter_compare, UU_LIST_POOL_DEBUG);
 264 
 265                 assert_nolint(offsetof(scf_transaction_entry_t,
 266                     entry_property) == 0);
 267                 tran_entry_pool = uu_list_pool_create(
 268                     "SUNW,libscf_transaction_entity",
 269                     sizeof (scf_transaction_entry_t),
 270                     offsetof(scf_transaction_entry_t, entry_link),
 271                     transaction_entry_compare, UU_LIST_POOL_DEBUG);
 272 
 273                 if (datael_pool == NULL || iter_pool == NULL ||
 274                     tran_entry_pool == NULL) {
 275                         lowlevel_inited = -1;
 276                         goto end;
 277                 }
 278 
 279                 if (!scf_setup_error()) {
 280                         lowlevel_inited = -1;
 281                         goto end;
 282                 }
 283                 lowlevel_inited = 1;
 284         }
 285 end:
 286         (void) pthread_mutex_unlock(&lowlevel_init_lock);
 287         if (lowlevel_inited > 0)
 288                 return (1);
 289         return (0);
 290 }
 291 
 292 static const struct {
 293         scf_type_t ti_type;
 294         rep_protocol_value_type_t ti_proto_type;
 295         const char *ti_name;
 296 } scf_type_info[] = {
 297         {SCF_TYPE_BOOLEAN,      REP_PROTOCOL_TYPE_BOOLEAN,
 298             SCF_TYPE_STRING_BOOLEAN},
 299         {SCF_TYPE_COUNT,        REP_PROTOCOL_TYPE_COUNT,
 300             SCF_TYPE_STRING_COUNT},
 301         {SCF_TYPE_INTEGER,      REP_PROTOCOL_TYPE_INTEGER,
 302             SCF_TYPE_STRING_INTEGER},
 303         {SCF_TYPE_TIME,         REP_PROTOCOL_TYPE_TIME,
 304             SCF_TYPE_STRING_TIME},
 305         {SCF_TYPE_ASTRING,      REP_PROTOCOL_TYPE_STRING,
 306             SCF_TYPE_STRING_ASTRING},
 307         {SCF_TYPE_OPAQUE,       REP_PROTOCOL_TYPE_OPAQUE,
 308             SCF_TYPE_STRING_OPAQUE},
 309         {SCF_TYPE_USTRING,      REP_PROTOCOL_SUBTYPE_USTRING,
 310             SCF_TYPE_STRING_USTRING},
 311         {SCF_TYPE_URI,          REP_PROTOCOL_SUBTYPE_URI,
 312             SCF_TYPE_STRING_URI},
 313         {SCF_TYPE_FMRI,         REP_PROTOCOL_SUBTYPE_FMRI,
 314             SCF_TYPE_STRING_FMRI},
 315         {SCF_TYPE_HOST,         REP_PROTOCOL_SUBTYPE_HOST,
 316             SCF_TYPE_STRING_HOST},
 317         {SCF_TYPE_HOSTNAME,     REP_PROTOCOL_SUBTYPE_HOSTNAME,
 318             SCF_TYPE_STRING_HOSTNAME},
 319         {SCF_TYPE_NET_ADDR,     REP_PROTOCOL_SUBTYPE_NETADDR,
 320             SCF_TYPE_STRING_NET_ADDR},
 321         {SCF_TYPE_NET_ADDR_V4,  REP_PROTOCOL_SUBTYPE_NETADDR_V4,
 322             SCF_TYPE_STRING_NET_ADDR_V4},
 323         {SCF_TYPE_NET_ADDR_V6,  REP_PROTOCOL_SUBTYPE_NETADDR_V6,
 324             SCF_TYPE_STRING_NET_ADDR_V6}
 325 };
 326 
 327 #define SCF_TYPE_INFO_COUNT (sizeof (scf_type_info) / sizeof (*scf_type_info))
 328 static rep_protocol_value_type_t
 329 scf_type_to_protocol_type(scf_type_t t)
 330 {
 331         int i;
 332 
 333         for (i = 0; i < SCF_TYPE_INFO_COUNT; i++)
 334                 if (scf_type_info[i].ti_type == t)
 335                         return (scf_type_info[i].ti_proto_type);
 336 
 337         return (REP_PROTOCOL_TYPE_INVALID);
 338 }
 339 
 340 static scf_type_t
 341 scf_protocol_type_to_type(rep_protocol_value_type_t t)
 342 {
 343         int i;
 344 
 345         for (i = 0; i < SCF_TYPE_INFO_COUNT; i++)
 346                 if (scf_type_info[i].ti_proto_type == t)
 347                         return (scf_type_info[i].ti_type);
 348 
 349         return (SCF_TYPE_INVALID);
 350 }
 351 
 352 const char *
 353 scf_type_to_string(scf_type_t ty)
 354 {
 355         int i;
 356 
 357         for (i = 0; i < SCF_TYPE_INFO_COUNT; i++)
 358                 if (scf_type_info[i].ti_type == ty)
 359                         return (scf_type_info[i].ti_name);
 360 
 361         return ("unknown");
 362 }
 363 
 364 scf_type_t
 365 scf_string_to_type(const char *name)
 366 {
 367         int i;
 368 
 369         for (i = 0; i < sizeof (scf_type_info) / sizeof (*scf_type_info); i++)
 370                 if (strcmp(scf_type_info[i].ti_name, name) == 0)
 371                         return (scf_type_info[i].ti_type);
 372 
 373         return (SCF_TYPE_INVALID);
 374 }
 375 
 376 int
 377 scf_type_base_type(scf_type_t type, scf_type_t *out)
 378 {
 379         rep_protocol_value_type_t t = scf_type_to_protocol_type(type);
 380         if (t == REP_PROTOCOL_TYPE_INVALID)
 381                 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
 382 
 383         *out = scf_protocol_type_to_type(scf_proto_underlying_type(t));
 384         return (SCF_SUCCESS);
 385 }
 386 
 387 /*
 388  * Convert a protocol error code into an SCF_ERROR_* code.
 389  */
 390 static scf_error_t
 391 proto_error(rep_protocol_responseid_t e)
 392 {
 393         switch (e) {
 394         case REP_PROTOCOL_FAIL_MISORDERED:
 395         case REP_PROTOCOL_FAIL_UNKNOWN_ID:
 396         case REP_PROTOCOL_FAIL_INVALID_TYPE:
 397         case REP_PROTOCOL_FAIL_TRUNCATED:
 398         case REP_PROTOCOL_FAIL_TYPE_MISMATCH:
 399         case REP_PROTOCOL_FAIL_NOT_APPLICABLE:
 400         case REP_PROTOCOL_FAIL_UNKNOWN:
 401                 return (SCF_ERROR_INTERNAL);
 402 
 403         case REP_PROTOCOL_FAIL_BAD_TX:
 404                 return (SCF_ERROR_INVALID_ARGUMENT);
 405         case REP_PROTOCOL_FAIL_BAD_REQUEST:
 406                 return (SCF_ERROR_INVALID_ARGUMENT);
 407         case REP_PROTOCOL_FAIL_NO_RESOURCES:
 408                 return (SCF_ERROR_NO_RESOURCES);
 409         case REP_PROTOCOL_FAIL_NOT_FOUND:
 410                 return (SCF_ERROR_NOT_FOUND);
 411         case REP_PROTOCOL_FAIL_DELETED:
 412                 return (SCF_ERROR_DELETED);
 413         case REP_PROTOCOL_FAIL_NOT_SET:
 414                 return (SCF_ERROR_NOT_SET);
 415         case REP_PROTOCOL_FAIL_EXISTS:
 416                 return (SCF_ERROR_EXISTS);
 417         case REP_PROTOCOL_FAIL_DUPLICATE_ID:
 418                 return (SCF_ERROR_EXISTS);
 419         case REP_PROTOCOL_FAIL_PERMISSION_DENIED:
 420                 return (SCF_ERROR_PERMISSION_DENIED);
 421         case REP_PROTOCOL_FAIL_BACKEND_ACCESS:
 422                 return (SCF_ERROR_BACKEND_ACCESS);
 423         case REP_PROTOCOL_FAIL_BACKEND_READONLY:
 424                 return (SCF_ERROR_BACKEND_READONLY);
 425 
 426         case REP_PROTOCOL_SUCCESS:
 427         case REP_PROTOCOL_DONE:
 428         case REP_PROTOCOL_FAIL_NOT_LATEST:      /* TX code should handle this */
 429         default:
 430 #ifndef NDEBUG
 431                 uu_warn("%s:%d: Bad error code %d passed to proto_error().\n",
 432                     __FILE__, __LINE__, e);
 433 #endif
 434                 abort();
 435                 /*NOTREACHED*/
 436         }
 437 }
 438 
 439 ssize_t
 440 scf_limit(uint32_t limit)
 441 {
 442         switch (limit) {
 443         case SCF_LIMIT_MAX_NAME_LENGTH:
 444         case SCF_LIMIT_MAX_PG_TYPE_LENGTH:
 445                 return (REP_PROTOCOL_NAME_LEN - 1);
 446         case SCF_LIMIT_MAX_VALUE_LENGTH:
 447                 return (REP_PROTOCOL_VALUE_LEN - 1);
 448         case SCF_LIMIT_MAX_FMRI_LENGTH:
 449                 return (SCF_FMRI_PREFIX_MAX_LEN +
 450                     sizeof (SCF_FMRI_SCOPE_PREFIX) - 1 +
 451                     sizeof (SCF_FMRI_SCOPE_SUFFIX) - 1 +
 452                     sizeof (SCF_FMRI_SERVICE_PREFIX) - 1 +
 453                     sizeof (SCF_FMRI_INSTANCE_PREFIX) - 1 +
 454                     sizeof (SCF_FMRI_PROPERTYGRP_PREFIX) - 1 +
 455                     sizeof (SCF_FMRI_PROPERTY_PREFIX) - 1 +
 456                     5 * (REP_PROTOCOL_NAME_LEN - 1));
 457         default:
 458                 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
 459         }
 460 }
 461 
 462 static size_t
 463 scf_opaque_decode(char *out_arg, const char *in, size_t max_out)
 464 {
 465         char a, b;
 466         char *out = out_arg;
 467 
 468         while (max_out > 0 && (a = in[0]) != 0 && (b = in[1]) != 0) {
 469                 in += 2;
 470 
 471                 if (a >= '0' && a <= '9')
 472                         a -= '0';
 473                 else if (a >= 'a' && a <= 'f')
 474                         a = a - 'a' + 10;
 475                 else if (a >= 'A' && a <= 'F')
 476                         a = a - 'A' + 10;
 477                 else
 478                         break;
 479 
 480                 if (b >= '0' && b <= '9')
 481                         b -= '0';
 482                 else if (b >= 'a' && b <= 'f')
 483                         b = b - 'a' + 10;
 484                 else if (b >= 'A' && b <= 'F')
 485                         b = b - 'A' + 10;
 486                 else
 487                         break;
 488 
 489                 *out++ = (a << 4) | b;
 490                 max_out--;
 491         }
 492 
 493         return (out - out_arg);
 494 }
 495 
 496 static size_t
 497 scf_opaque_encode(char *out_arg, const char *in_arg, size_t in_sz)
 498 {
 499         uint8_t *in = (uint8_t *)in_arg;
 500         uint8_t *end = in + in_sz;
 501         char *out = out_arg;
 502 
 503         if (out == NULL)
 504                 return (2 * in_sz);
 505 
 506         while (in < end) {
 507                 uint8_t c = *in++;
 508 
 509                 uint8_t a = (c & 0xf0) >> 4;
 510                 uint8_t b = (c & 0x0f);
 511 
 512                 if (a <= 9)
 513                         *out++ = a + '0';
 514                 else
 515                         *out++ = a + 'a' - 10;
 516 
 517                 if (b <= 9)
 518                         *out++ = b + '0';
 519                 else
 520                         *out++ = b + 'a' - 10;
 521         }
 522 
 523         *out = 0;
 524 
 525         return (out - out_arg);
 526 }
 527 
 528 static void
 529 handle_do_close(scf_handle_t *h)
 530 {
 531         assert(MUTEX_HELD(&h->rh_lock));
 532         assert(h->rh_doorfd != -1);
 533 
 534         /*
 535          * if there are any active FD users, we just move the FD over
 536          * to rh_doorfd_old -- they'll close it when they finish.
 537          */
 538         if (h->rh_fd_users > 0) {
 539                 h->rh_doorfd_old = h->rh_doorfd;
 540                 h->rh_doorfd = -1;
 541         } else {
 542                 assert(h->rh_doorfd_old == -1);
 543                 (void) close(h->rh_doorfd);
 544                 h->rh_doorfd = -1;
 545         }
 546 }
 547 
 548 /*
 549  * Check if a handle is currently bound.  fork()ing implicitly unbinds
 550  * the handle in the child.
 551  */
 552 static int
 553 handle_is_bound(scf_handle_t *h)
 554 {
 555         assert(MUTEX_HELD(&h->rh_lock));
 556 
 557         if (h->rh_doorfd == -1)
 558                 return (0);
 559 
 560         if (getpid() == h->rh_doorpid)
 561                 return (1);
 562 
 563         /* forked since our last bind -- initiate handle close */
 564         handle_do_close(h);
 565         return (0);
 566 }
 567 
 568 static int
 569 handle_has_server_locked(scf_handle_t *h)
 570 {
 571         door_info_t i;
 572         assert(MUTEX_HELD(&h->rh_lock));
 573 
 574         return (handle_is_bound(h) && door_info(h->rh_doorfd, &i) != -1 &&
 575             i.di_target != -1);
 576 }
 577 
 578 static int
 579 handle_has_server(scf_handle_t *h)
 580 {
 581         int ret;
 582 
 583         (void) pthread_mutex_lock(&h->rh_lock);
 584         ret = handle_has_server_locked(h);
 585         (void) pthread_mutex_unlock(&h->rh_lock);
 586 
 587         return (ret);
 588 }
 589 
 590 /*
 591  * This makes a door request on the client door associated with handle h.
 592  * It will automatically retry calls which fail on EINTR.  If h is not bound,
 593  * returns NOT_BOUND.  If the door call fails or the server response is too
 594  * small, returns CALL_FAILED.  If the server response is too big, truncates the
 595  * response and returns RESULT_TOO_BIG.  Otherwise, the size of the result is
 596  * returned.
 597  */
 598 static ssize_t
 599 make_door_call(scf_handle_t *h, const void *req, size_t req_sz,
 600     void *res, size_t res_sz)
 601 {
 602         door_arg_t arg;
 603         int r;
 604 
 605         assert(MUTEX_HELD(&h->rh_lock));
 606 
 607         if (!handle_is_bound(h)) {
 608                 return (NOT_BOUND);
 609         }
 610 
 611         arg.data_ptr = (void *)req;
 612         arg.data_size = req_sz;
 613         arg.desc_ptr = NULL;
 614         arg.desc_num = 0;
 615         arg.rbuf = res;
 616         arg.rsize = res_sz;
 617 
 618         while ((r = door_call(h->rh_doorfd, &arg)) < 0) {
 619                 if (errno != EINTR)
 620                         break;
 621         }
 622 
 623         if (r < 0) {
 624                 return (CALL_FAILED);
 625         }
 626 
 627         if (arg.desc_num > 0) {
 628                 while (arg.desc_num > 0) {
 629                         if (arg.desc_ptr->d_attributes & DOOR_DESCRIPTOR) {
 630                                 int cfd = arg.desc_ptr->d_data.d_desc.d_id;
 631                                 (void) close(cfd);
 632                         }
 633                         arg.desc_ptr++;
 634                         arg.desc_num--;
 635                 }
 636         }
 637         if (arg.data_ptr != res && arg.data_size > 0)
 638                 (void) memmove(res, arg.data_ptr, MIN(arg.data_size, res_sz));
 639 
 640         if (arg.rbuf != res)
 641                 (void) munmap(arg.rbuf, arg.rsize);
 642 
 643         if (arg.data_size > res_sz)
 644                 return (RESULT_TOO_BIG);
 645 
 646         if (arg.data_size < sizeof (uint32_t))
 647                 return (CALL_FAILED);
 648 
 649         return (arg.data_size);
 650 }
 651 
 652 /*
 653  * Should only be used when r < 0.
 654  */
 655 #define DOOR_ERRORS_BLOCK(r)    {                                       \
 656         switch (r) {                                                    \
 657         case NOT_BOUND:                                                 \
 658                 return (scf_set_error(SCF_ERROR_NOT_BOUND));            \
 659                                                                         \
 660         case CALL_FAILED:                                               \
 661                 return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN));    \
 662                                                                         \
 663         case RESULT_TOO_BIG:                                            \
 664                 return (scf_set_error(SCF_ERROR_INTERNAL));             \
 665                                                                         \
 666         default:                                                        \
 667                 assert(r == NOT_BOUND || r == CALL_FAILED ||            \
 668                     r == RESULT_TOO_BIG);                               \
 669                 abort();                                                \
 670         }                                                               \
 671 }
 672 
 673 /*
 674  * Like make_door_call(), but takes an fd instead of a handle, and expects
 675  * a single file descriptor, returned via res_fd.
 676  *
 677  * If no file descriptor is returned, *res_fd == -1.
 678  */
 679 static int
 680 make_door_call_retfd(int fd, const void *req, size_t req_sz, void *res,
 681     size_t res_sz, int *res_fd)
 682 {
 683         door_arg_t arg;
 684         int r;
 685         char rbuf[256];
 686 
 687         *res_fd = -1;
 688 
 689         if (fd == -1)
 690                 return (NOT_BOUND);
 691 
 692         arg.data_ptr = (void *)req;
 693         arg.data_size = req_sz;
 694         arg.desc_ptr = NULL;
 695         arg.desc_num = 0;
 696         arg.rbuf = rbuf;
 697         arg.rsize = sizeof (rbuf);
 698 
 699         while ((r = door_call(fd, &arg)) < 0) {
 700                 if (errno != EINTR)
 701                         break;
 702         }
 703 
 704         if (r < 0)
 705                 return (CALL_FAILED);
 706 
 707         if (arg.desc_num > 1) {
 708                 while (arg.desc_num > 0) {
 709                         if (arg.desc_ptr->d_attributes & DOOR_DESCRIPTOR) {
 710                                 int cfd =
 711                                     arg.desc_ptr->d_data.d_desc.d_descriptor;
 712                                 (void) close(cfd);
 713                         }
 714                         arg.desc_ptr++;
 715                         arg.desc_num--;
 716                 }
 717         }
 718         if (arg.desc_num == 1 && arg.desc_ptr->d_attributes & DOOR_DESCRIPTOR)
 719                 *res_fd = arg.desc_ptr->d_data.d_desc.d_descriptor;
 720 
 721         if (arg.data_size > 0)
 722                 (void) memmove(res, arg.data_ptr, MIN(arg.data_size, res_sz));
 723 
 724         if (arg.rbuf != rbuf)
 725                 (void) munmap(arg.rbuf, arg.rsize);
 726 
 727         if (arg.data_size > res_sz)
 728                 return (RESULT_TOO_BIG);
 729 
 730         if (arg.data_size < sizeof (uint32_t))
 731                 return (CALL_FAILED);
 732 
 733         return (arg.data_size);
 734 }
 735 
 736 /*
 737  * Fails with
 738  *   _VERSION_MISMATCH
 739  *   _NO_MEMORY
 740  */
 741 scf_handle_t *
 742 scf_handle_create(scf_version_t v)
 743 {
 744         scf_handle_t *ret;
 745         int failed;
 746 
 747         /*
 748          * This will need to be revisited when we bump SCF_VERSION
 749          */
 750         if (v != SCF_VERSION) {
 751                 (void) scf_set_error(SCF_ERROR_VERSION_MISMATCH);
 752                 return (NULL);
 753         }
 754 
 755         if (!lowlevel_init()) {
 756                 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
 757                 return (NULL);
 758         }
 759 
 760         ret = uu_zalloc(sizeof (*ret));
 761         if (ret == NULL) {
 762                 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
 763                 return (NULL);
 764         }
 765 
 766         ret->rh_dataels = uu_list_create(datael_pool, ret, 0);
 767         ret->rh_iters = uu_list_create(iter_pool, ret, 0);
 768         if (ret->rh_dataels == NULL || ret->rh_iters == NULL) {
 769                 if (ret->rh_dataels != NULL)
 770                         uu_list_destroy(ret->rh_dataels);
 771                 if (ret->rh_iters != NULL)
 772                         uu_list_destroy(ret->rh_iters);
 773                 uu_free(ret);
 774                 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
 775                 return (NULL);
 776         }
 777 
 778         ret->rh_doorfd = -1;
 779         ret->rh_doorfd_old = -1;
 780         (void) pthread_mutex_init(&ret->rh_lock, NULL);
 781 
 782         handle_hold_subhandles(ret, RH_HOLD_ALL);
 783 
 784         failed = ((ret->rh_iter = scf_iter_create(ret)) == NULL ||
 785             (ret->rh_scope = scf_scope_create(ret)) == NULL ||
 786             (ret->rh_service = scf_service_create(ret)) == NULL ||
 787             (ret->rh_instance = scf_instance_create(ret)) == NULL ||
 788             (ret->rh_snapshot = scf_snapshot_create(ret)) == NULL ||
 789             (ret->rh_snaplvl = scf_snaplevel_create(ret)) == NULL ||
 790             (ret->rh_pg = scf_pg_create(ret)) == NULL ||
 791             (ret->rh_property = scf_property_create(ret)) == NULL ||
 792             (ret->rh_value = scf_value_create(ret)) == NULL);
 793 
 794         /*
 795          * these subhandles count as internal references, not external ones.
 796          */
 797         ret->rh_intrefs = ret->rh_extrefs;
 798         ret->rh_extrefs = 0;
 799         handle_rele_subhandles(ret, RH_HOLD_ALL);
 800 
 801         if (failed) {
 802                 scf_handle_destroy(ret);
 803                 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
 804                 return (NULL);
 805         }
 806 
 807         scf_value_set_count(ret->rh_value, default_debug);
 808         (void) scf_handle_decorate(ret, "debug", ret->rh_value);
 809 
 810         return (ret);
 811 }
 812 
 813 /*
 814  * Fails with
 815  *   _NO_MEMORY
 816  *   _NO_SERVER - server door could not be open()ed
 817  *                door call failed
 818  *                door_info() failed
 819  *   _VERSION_MISMATCH - server returned bad file descriptor
 820  *                       server claimed bad request
 821  *                       server reported version mismatch
 822  *                       server refused with unknown reason
 823  *   _INVALID_ARGUMENT
 824  *   _NO_RESOURCES - server is out of memory
 825  *   _PERMISSION_DENIED
 826  *   _INTERNAL - could not set up entities or iters
 827  *               server response too big
 828  */
 829 scf_handle_t *
 830 _scf_handle_create_and_bind(scf_version_t ver)
 831 {
 832         scf_handle_t *h;
 833 
 834         h = scf_handle_create(ver);
 835         if (h == NULL)
 836                 return (NULL);
 837 
 838         if (scf_handle_bind(h) == -1) {
 839                 scf_handle_destroy(h);
 840                 return (NULL);
 841         }
 842         return (h);
 843 }
 844 
 845 int
 846 scf_handle_decorate(scf_handle_t *handle, const char *name, scf_value_t *v)
 847 {
 848         if (v != SCF_DECORATE_CLEAR && handle != v->value_handle)
 849                 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
 850 
 851         (void) pthread_mutex_lock(&handle->rh_lock);
 852         if (handle_is_bound(handle)) {
 853                 (void) pthread_mutex_unlock(&handle->rh_lock);
 854                 return (scf_set_error(SCF_ERROR_IN_USE));
 855         }
 856         (void) pthread_mutex_unlock(&handle->rh_lock);
 857 
 858         if (strcmp(name, "debug") == 0) {
 859                 if (v == SCF_DECORATE_CLEAR) {
 860                         (void) pthread_mutex_lock(&handle->rh_lock);
 861                         handle->rh_debug = 0;
 862                         (void) pthread_mutex_unlock(&handle->rh_lock);
 863                 } else {
 864                         uint64_t val;
 865                         if (scf_value_get_count(v, &val) < 0)
 866                                 return (-1);            /* error already set */
 867 
 868                         (void) pthread_mutex_lock(&handle->rh_lock);
 869                         handle->rh_debug = (uid_t)val;
 870                         (void) pthread_mutex_unlock(&handle->rh_lock);
 871                 }
 872                 return (0);
 873         }
 874         if (strcmp(name, "door_path") == 0) {
 875                 char name[sizeof (handle->rh_doorpath)];
 876 
 877                 if (v == SCF_DECORATE_CLEAR) {
 878                         (void) pthread_mutex_lock(&handle->rh_lock);
 879                         handle->rh_doorpath[0] = 0;
 880                         (void) pthread_mutex_unlock(&handle->rh_lock);
 881                 } else {
 882                         ssize_t len;
 883 
 884                         if ((len = scf_value_get_astring(v, name,
 885                             sizeof (name))) < 0) {
 886                                 return (-1);            /* error already set */
 887                         }
 888                         if (len == 0 || len >= sizeof (name)) {
 889                                 return (scf_set_error(
 890                                     SCF_ERROR_INVALID_ARGUMENT));
 891                         }
 892                         (void) pthread_mutex_lock(&handle->rh_lock);
 893                         (void) strlcpy(handle->rh_doorpath, name,
 894                             sizeof (handle->rh_doorpath));
 895                         (void) pthread_mutex_unlock(&handle->rh_lock);
 896                 }
 897                 return (0);
 898         }
 899 
 900         if (strcmp(name, "zone") == 0) {
 901                 char zone[MAXPATHLEN], root[MAXPATHLEN], door[MAXPATHLEN];
 902                 static int (*zone_get_rootpath)(char *, char *, size_t);
 903                 ssize_t len;
 904 
 905                 /*
 906                  * In order to be able to set the zone on a handle, we want
 907                  * to determine the zone's path, which requires us to call into
 908                  * libzonecfg -- but libzonecfg.so links against libscf.so so
 909                  * we must not explicitly link to it.  To circumvent the
 910                  * circular dependency, we will pull it in here via dlopen().
 911                  */
 912                 if (zone_get_rootpath == NULL) {
 913                         void *dl = dlopen("libzonecfg.so.1", RTLD_LAZY), *sym;
 914 
 915                         if (dl == NULL)
 916                                 return (scf_set_error(SCF_ERROR_NOT_FOUND));
 917 
 918                         if ((sym = dlsym(dl, "zone_get_rootpath")) == NULL) {
 919                                 (void) dlclose(dl);
 920                                 return (scf_set_error(SCF_ERROR_INTERNAL));
 921                         }
 922 
 923                         zone_get_rootpath = (int(*)(char *, char *, size_t))sym;
 924                 }
 925 
 926                 if (v == SCF_DECORATE_CLEAR) {
 927                         (void) pthread_mutex_lock(&handle->rh_lock);
 928                         handle->rh_doorpath[0] = 0;
 929                         (void) pthread_mutex_unlock(&handle->rh_lock);
 930 
 931                         return (0);
 932                 }
 933 
 934                 if ((len = scf_value_get_astring(v, zone, sizeof (zone))) < 0)
 935                         return (-1);
 936 
 937                 if (len == 0 || len >= sizeof (zone))
 938                         return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
 939 
 940                 if (zone_get_rootpath(zone, root, sizeof (root)) != Z_OK) {
 941                         if (strcmp(zone, GLOBAL_ZONENAME) == 0) {
 942                                 root[0] = '\0';
 943                         } else {
 944                                 return (scf_set_error(SCF_ERROR_NOT_FOUND));
 945                         }
 946                 }
 947 
 948                 if (snprintf(door, sizeof (door), "%s/%s", root,
 949                     default_door_path) >= sizeof (door))
 950                         return (scf_set_error(SCF_ERROR_INTERNAL));
 951 
 952                 (void) pthread_mutex_lock(&handle->rh_lock);
 953                 (void) strlcpy(handle->rh_doorpath, door,
 954                     sizeof (handle->rh_doorpath));
 955                 (void) pthread_mutex_unlock(&handle->rh_lock);
 956 
 957                 return (0);
 958         }
 959 
 960         return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
 961 }
 962 
 963 /*
 964  * fails with INVALID_ARGUMENT and HANDLE_MISMATCH.
 965  */
 966 int
 967 _scf_handle_decorations(scf_handle_t *handle, scf_decoration_func *f,
 968     scf_value_t *v, void *data)
 969 {
 970         scf_decoration_info_t i;
 971         char name[sizeof (handle->rh_doorpath)];
 972         uint64_t debug;
 973 
 974         if (f == NULL || v == NULL)
 975                 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
 976 
 977         if (v->value_handle != handle)
 978                 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
 979 
 980         i.sdi_name = (const char *)"debug";
 981         i.sdi_type = SCF_TYPE_COUNT;
 982         (void) pthread_mutex_lock(&handle->rh_lock);
 983         debug = handle->rh_debug;
 984         (void) pthread_mutex_unlock(&handle->rh_lock);
 985         if (debug != 0) {
 986                 scf_value_set_count(v, debug);
 987                 i.sdi_value = v;
 988         } else {
 989                 i.sdi_value = SCF_DECORATE_CLEAR;
 990         }
 991 
 992         if ((*f)(&i, data) == 0)
 993                 return (0);
 994 
 995         i.sdi_name = (const char *)"door_path";
 996         i.sdi_type = SCF_TYPE_ASTRING;
 997         (void) pthread_mutex_lock(&handle->rh_lock);
 998         (void) strlcpy(name, handle->rh_doorpath, sizeof (name));
 999         (void) pthread_mutex_unlock(&handle->rh_lock);
1000         if (name[0] != 0) {
1001                 (void) scf_value_set_astring(v, name);
1002                 i.sdi_value = v;
1003         } else {
1004                 i.sdi_value = SCF_DECORATE_CLEAR;
1005         }
1006 
1007         if ((*f)(&i, data) == 0)
1008                 return (0);
1009 
1010         return (1);
1011 }
1012 
1013 /*
1014  * Fails if handle is not bound.
1015  */
1016 static int
1017 handle_unbind_unlocked(scf_handle_t *handle)
1018 {
1019         rep_protocol_request_t request;
1020         rep_protocol_response_t response;
1021 
1022         if (!handle_is_bound(handle))
1023                 return (-1);
1024 
1025         request.rpr_request = REP_PROTOCOL_CLOSE;
1026 
1027         (void) make_door_call(handle, &request, sizeof (request),
1028             &response, sizeof (response));
1029 
1030         handle_do_close(handle);
1031 
1032         return (SCF_SUCCESS);
1033 }
1034 
1035 /*
1036  * Fails with
1037  *   _HANDLE_DESTROYED - dp's handle has been destroyed
1038  *   _INTERNAL - server response too big
1039  *               entity already set up with different type
1040  *   _NO_RESOURCES - server out of memory
1041  */
1042 static int
1043 datael_attach(scf_datael_t *dp)
1044 {
1045         scf_handle_t *h = dp->rd_handle;
1046 
1047         struct rep_protocol_entity_setup request;
1048         rep_protocol_response_t response;
1049         ssize_t r;
1050 
1051         assert(MUTEX_HELD(&h->rh_lock));
1052 
1053         dp->rd_reset = 0;            /* setup implicitly resets */
1054 
1055         if (h->rh_flags & HANDLE_DEAD)
1056                 return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED));
1057 
1058         if (!handle_is_bound(h))
1059                 return (SCF_SUCCESS);           /* nothing to do */
1060 
1061         request.rpr_request = REP_PROTOCOL_ENTITY_SETUP;
1062         request.rpr_entityid = dp->rd_entity;
1063         request.rpr_entitytype = dp->rd_type;
1064 
1065         r = make_door_call(h, &request, sizeof (request),
1066             &response, sizeof (response));
1067 
1068         if (r == NOT_BOUND || r == CALL_FAILED)
1069                 return (SCF_SUCCESS);
1070         if (r == RESULT_TOO_BIG)
1071                 return (scf_set_error(SCF_ERROR_INTERNAL));
1072 
1073         if (response.rpr_response != REP_PROTOCOL_SUCCESS)
1074                 return (scf_set_error(proto_error(response.rpr_response)));
1075 
1076         return (SCF_SUCCESS);
1077 }
1078 
1079 /*
1080  * Fails with
1081  *   _HANDLE_DESTROYED - iter's handle has been destroyed
1082  *   _INTERNAL - server response too big
1083  *               iter already existed
1084  *   _NO_RESOURCES
1085  */
1086 static int
1087 iter_attach(scf_iter_t *iter)
1088 {
1089         scf_handle_t *h = iter->iter_handle;
1090         struct rep_protocol_iter_request request;
1091         struct rep_protocol_response response;
1092         int r;
1093 
1094         assert(MUTEX_HELD(&h->rh_lock));
1095 
1096         if (h->rh_flags & HANDLE_DEAD)
1097                 return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED));
1098 
1099         if (!handle_is_bound(h))
1100                 return (SCF_SUCCESS);           /* nothing to do */
1101 
1102         request.rpr_request = REP_PROTOCOL_ITER_SETUP;
1103         request.rpr_iterid = iter->iter_id;
1104 
1105         r = make_door_call(h, &request, sizeof (request),
1106             &response, sizeof (response));
1107 
1108         if (r == NOT_BOUND || r == CALL_FAILED)
1109                 return (SCF_SUCCESS);
1110         if (r == RESULT_TOO_BIG)
1111                 return (scf_set_error(SCF_ERROR_INTERNAL));
1112 
1113         if (response.rpr_response != REP_PROTOCOL_SUCCESS)
1114                 return (scf_set_error(proto_error(response.rpr_response)));
1115 
1116         return (SCF_SUCCESS);
1117 }
1118 
1119 /*
1120  * Fails with
1121  *   _IN_USE - handle already bound
1122  *   _NO_SERVER - server door could not be open()ed
1123  *                door call failed
1124  *                door_info() failed
1125  *   _VERSION_MISMATCH - server returned bad file descriptor
1126  *                       server claimed bad request
1127  *                       server reported version mismatch
1128  *                       server refused with unknown reason
1129  *   _INVALID_ARGUMENT
1130  *   _NO_RESOURCES - server is out of memory
1131  *   _PERMISSION_DENIED
1132  *   _INTERNAL - could not set up entities or iters
1133  *               server response too big
1134  *
1135  * perhaps this should try multiple times.
1136  */
1137 int
1138 scf_handle_bind(scf_handle_t *handle)
1139 {
1140         scf_datael_t *el;
1141         scf_iter_t *iter;
1142 
1143         pid_t pid;
1144         int fd;
1145         int res;
1146         door_info_t info;
1147         repository_door_request_t request;
1148         repository_door_response_t response;
1149         const char *door_name = default_door_path;
1150 
1151         (void) pthread_mutex_lock(&handle->rh_lock);
1152         if (handle_is_bound(handle)) {
1153                 (void) pthread_mutex_unlock(&handle->rh_lock);
1154                 return (scf_set_error(SCF_ERROR_IN_USE));
1155         }
1156 
1157         /* wait until any active fd users have cleared out */
1158         while (handle->rh_fd_users > 0) {
1159                 int cancel_state;
1160 
1161                 (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,
1162                     &cancel_state);
1163                 (void) pthread_cond_wait(&handle->rh_cv, &handle->rh_lock);
1164                 (void) pthread_setcancelstate(cancel_state, NULL);
1165         }
1166 
1167         /* check again, since we had to drop the lock */
1168         if (handle_is_bound(handle)) {
1169                 (void) pthread_mutex_unlock(&handle->rh_lock);
1170                 return (scf_set_error(SCF_ERROR_IN_USE));
1171         }
1172 
1173         assert(handle->rh_doorfd == -1 && handle->rh_doorfd_old == -1);
1174 
1175         if (handle->rh_doorpath[0] != 0)
1176                 door_name = handle->rh_doorpath;
1177 
1178         fd = open(door_name, O_RDONLY, 0);
1179         if (fd == -1) {
1180                 (void) pthread_mutex_unlock(&handle->rh_lock);
1181                 return (scf_set_error(SCF_ERROR_NO_SERVER));
1182         }
1183 
1184         request.rdr_version = REPOSITORY_DOOR_VERSION;
1185         request.rdr_request = REPOSITORY_DOOR_REQUEST_CONNECT;
1186         request.rdr_flags = handle->rh_flags;
1187         request.rdr_debug = handle->rh_debug;
1188 
1189         pid = getpid();
1190 
1191         res = make_door_call_retfd(fd, &request, sizeof (request),
1192             &response, sizeof (response), &handle->rh_doorfd);
1193 
1194         (void) close(fd);
1195 
1196         if (res < 0) {
1197                 (void) pthread_mutex_unlock(&handle->rh_lock);
1198 
1199                 assert(res != NOT_BOUND);
1200                 if (res == CALL_FAILED)
1201                         return (scf_set_error(SCF_ERROR_NO_SERVER));
1202                 assert(res == RESULT_TOO_BIG);
1203                 return (scf_set_error(SCF_ERROR_INTERNAL));
1204         }
1205 
1206         if (handle->rh_doorfd < 0) {
1207                 (void) pthread_mutex_unlock(&handle->rh_lock);
1208 
1209                 switch (response.rdr_status) {
1210                 case REPOSITORY_DOOR_SUCCESS:
1211                         return (scf_set_error(SCF_ERROR_VERSION_MISMATCH));
1212 
1213                 case REPOSITORY_DOOR_FAIL_BAD_REQUEST:
1214                         return (scf_set_error(SCF_ERROR_VERSION_MISMATCH));
1215 
1216                 case REPOSITORY_DOOR_FAIL_VERSION_MISMATCH:
1217                         return (scf_set_error(SCF_ERROR_VERSION_MISMATCH));
1218 
1219                 case REPOSITORY_DOOR_FAIL_BAD_FLAG:
1220                         return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
1221 
1222                 case REPOSITORY_DOOR_FAIL_NO_RESOURCES:
1223                         return (scf_set_error(SCF_ERROR_NO_RESOURCES));
1224 
1225                 case REPOSITORY_DOOR_FAIL_PERMISSION_DENIED:
1226                         return (scf_set_error(SCF_ERROR_PERMISSION_DENIED));
1227 
1228                 default:
1229                         return (scf_set_error(SCF_ERROR_VERSION_MISMATCH));
1230                 }
1231         }
1232 
1233         (void) fcntl(handle->rh_doorfd, F_SETFD, FD_CLOEXEC);
1234 
1235         if (door_info(handle->rh_doorfd, &info) < 0) {
1236                 (void) close(handle->rh_doorfd);
1237                 handle->rh_doorfd = -1;
1238 
1239                 (void) pthread_mutex_unlock(&handle->rh_lock);
1240                 return (scf_set_error(SCF_ERROR_NO_SERVER));
1241         }
1242 
1243         handle->rh_doorpid = pid;
1244         handle->rh_doorid = info.di_uniquifier;
1245 
1246         /*
1247          * Now, re-attach everything
1248          */
1249         for (el = uu_list_first(handle->rh_dataels); el != NULL;
1250             el = uu_list_next(handle->rh_dataels, el)) {
1251                 if (datael_attach(el) == -1) {
1252                         assert(scf_error() != SCF_ERROR_HANDLE_DESTROYED);
1253                         (void) handle_unbind_unlocked(handle);
1254                         (void) pthread_mutex_unlock(&handle->rh_lock);
1255                         return (-1);
1256                 }
1257         }
1258 
1259         for (iter = uu_list_first(handle->rh_iters); iter != NULL;
1260             iter = uu_list_next(handle->rh_iters, iter)) {
1261                 if (iter_attach(iter) == -1) {
1262                         assert(scf_error() != SCF_ERROR_HANDLE_DESTROYED);
1263                         (void) handle_unbind_unlocked(handle);
1264                         (void) pthread_mutex_unlock(&handle->rh_lock);
1265                         return (-1);
1266                 }
1267         }
1268         (void) pthread_mutex_unlock(&handle->rh_lock);
1269         return (SCF_SUCCESS);
1270 }
1271 
1272 int
1273 scf_handle_unbind(scf_handle_t *handle)
1274 {
1275         int ret;
1276         (void) pthread_mutex_lock(&handle->rh_lock);
1277         ret = handle_unbind_unlocked(handle);
1278         (void) pthread_mutex_unlock(&handle->rh_lock);
1279         return (ret == SCF_SUCCESS ? ret : scf_set_error(SCF_ERROR_NOT_BOUND));
1280 }
1281 
1282 static scf_handle_t *
1283 handle_get(scf_handle_t *h)
1284 {
1285         (void) pthread_mutex_lock(&h->rh_lock);
1286         if (h->rh_flags & HANDLE_DEAD) {
1287                 (void) pthread_mutex_unlock(&h->rh_lock);
1288                 (void) scf_set_error(SCF_ERROR_HANDLE_DESTROYED);
1289                 return (NULL);
1290         }
1291         (void) pthread_mutex_unlock(&h->rh_lock);
1292         return (h);
1293 }
1294 
1295 /*
1296  * Called when an object is removed from the handle.  On the last remove,
1297  * cleans up and frees the handle.
1298  */
1299 static void
1300 handle_unrefed(scf_handle_t *handle)
1301 {
1302         scf_iter_t *iter;
1303         scf_value_t *v;
1304         scf_scope_t *sc;
1305         scf_service_t *svc;
1306         scf_instance_t *inst;
1307         scf_snapshot_t *snap;
1308         scf_snaplevel_t *snaplvl;
1309         scf_propertygroup_t *pg;
1310         scf_property_t *prop;
1311 
1312         assert(MUTEX_HELD(&handle->rh_lock));
1313 
1314         /*
1315          * Don't do anything if the handle has not yet been destroyed, there
1316          * are still external references, or we're already doing unrefed
1317          * handling.
1318          */
1319         if (!(handle->rh_flags & HANDLE_DEAD) ||
1320             handle->rh_extrefs > 0 ||
1321             handle->rh_fd_users > 0 ||
1322             (handle->rh_flags & HANDLE_UNREFED)) {
1323                 (void) pthread_mutex_unlock(&handle->rh_lock);
1324                 return;
1325         }
1326 
1327         handle->rh_flags |= HANDLE_UNREFED;
1328 
1329         /*
1330          * Now that we know that there are no external references, and the
1331          * HANDLE_DEAD flag keeps new ones from appearing, we can clean up
1332          * our subhandles and destroy the handle completely.
1333          */
1334         assert(handle->rh_intrefs >= 0);
1335         handle->rh_extrefs = handle->rh_intrefs;
1336         handle->rh_intrefs = 0;
1337         (void) pthread_mutex_unlock(&handle->rh_lock);
1338 
1339         handle_hold_subhandles(handle, RH_HOLD_ALL);
1340 
1341         iter = handle->rh_iter;
1342         sc = handle->rh_scope;
1343         svc = handle->rh_service;
1344         inst = handle->rh_instance;
1345         snap = handle->rh_snapshot;
1346         snaplvl = handle->rh_snaplvl;
1347         pg = handle->rh_pg;
1348         prop = handle->rh_property;
1349         v = handle->rh_value;
1350 
1351         handle->rh_iter = NULL;
1352         handle->rh_scope = NULL;
1353         handle->rh_service = NULL;
1354         handle->rh_instance = NULL;
1355         handle->rh_snapshot = NULL;
1356         handle->rh_snaplvl = NULL;
1357         handle->rh_pg = NULL;
1358         handle->rh_property = NULL;
1359         handle->rh_value = NULL;
1360 
1361         if (iter != NULL)
1362                 scf_iter_destroy(iter);
1363         if (sc != NULL)
1364                 scf_scope_destroy(sc);
1365         if (svc != NULL)
1366                 scf_service_destroy(svc);
1367         if (inst != NULL)
1368                 scf_instance_destroy(inst);
1369         if (snap != NULL)
1370                 scf_snapshot_destroy(snap);
1371         if (snaplvl != NULL)
1372                 scf_snaplevel_destroy(snaplvl);
1373         if (pg != NULL)
1374                 scf_pg_destroy(pg);
1375         if (prop != NULL)
1376                 scf_property_destroy(prop);
1377         if (v != NULL)
1378                 scf_value_destroy(v);
1379 
1380         (void) pthread_mutex_lock(&handle->rh_lock);
1381 
1382         /* there should be no outstanding children at this point */
1383         assert(handle->rh_extrefs == 0);
1384         assert(handle->rh_intrefs == 0);
1385         assert(handle->rh_values == 0);
1386         assert(handle->rh_entries == 0);
1387         assert(uu_list_numnodes(handle->rh_dataels) == 0);
1388         assert(uu_list_numnodes(handle->rh_iters) == 0);
1389 
1390         uu_list_destroy(handle->rh_dataels);
1391         uu_list_destroy(handle->rh_iters);
1392         handle->rh_dataels = NULL;
1393         handle->rh_iters = NULL;
1394         (void) pthread_mutex_unlock(&handle->rh_lock);
1395 
1396         (void) pthread_mutex_destroy(&handle->rh_lock);
1397 
1398         uu_free(handle);
1399 }
1400 
1401 void
1402 scf_handle_destroy(scf_handle_t *handle)
1403 {
1404         if (handle == NULL)
1405                 return;
1406 
1407         (void) pthread_mutex_lock(&handle->rh_lock);
1408         if (handle->rh_flags & HANDLE_DEAD) {
1409                 /*
1410                  * This is an error (you are not allowed to reference the
1411                  * handle after it is destroyed), but we can't report it.
1412                  */
1413                 (void) pthread_mutex_unlock(&handle->rh_lock);
1414                 return;
1415         }
1416         handle->rh_flags |= HANDLE_DEAD;
1417         (void) handle_unbind_unlocked(handle);
1418         handle_unrefed(handle);
1419 }
1420 
1421 ssize_t
1422 scf_myname(scf_handle_t *h, char *out, size_t len)
1423 {
1424         char *cp;
1425 
1426         if (!handle_has_server(h))
1427                 return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN));
1428 
1429         cp = getenv("SMF_FMRI");
1430         if (cp == NULL)
1431                 return (scf_set_error(SCF_ERROR_NOT_SET));
1432 
1433         return (strlcpy(out, cp, len));
1434 }
1435 
1436 static uint32_t
1437 handle_alloc_entityid(scf_handle_t *h)
1438 {
1439         uint32_t nextid;
1440 
1441         assert(MUTEX_HELD(&h->rh_lock));
1442 
1443         if (uu_list_numnodes(h->rh_dataels) == UINT32_MAX)
1444                 return (0);             /* no ids available */
1445 
1446         /*
1447          * The following loop assumes that there are not a huge number of
1448          * outstanding entities when we've wrapped.  If that ends up not
1449          * being the case, the O(N^2) nature of this search will hurt a lot,
1450          * and the data structure should be switched to an AVL tree.
1451          */
1452         nextid = h->rh_nextentity + 1;
1453         for (;;) {
1454                 scf_datael_t *cur;
1455 
1456                 if (nextid == 0) {
1457                         nextid++;
1458                         h->rh_flags |= HANDLE_WRAPPED_ENTITY;
1459                 }
1460                 if (!(h->rh_flags & HANDLE_WRAPPED_ENTITY))
1461                         break;
1462 
1463                 cur = uu_list_find(h->rh_dataels, NULL, &nextid, NULL);
1464                 if (cur == NULL)
1465                         break;          /* not in use */
1466 
1467                 if (nextid == h->rh_nextentity)
1468                         return (0);     /* wrapped around; no ids available */
1469                 nextid++;
1470         }
1471 
1472         h->rh_nextentity = nextid;
1473         return (nextid);
1474 }
1475 
1476 static uint32_t
1477 handle_alloc_iterid(scf_handle_t *h)
1478 {
1479         uint32_t nextid;
1480 
1481         assert(MUTEX_HELD(&h->rh_lock));
1482 
1483         if (uu_list_numnodes(h->rh_iters) == UINT32_MAX)
1484                 return (0);             /* no ids available */
1485 
1486         /* see the comment in handle_alloc_entityid */
1487         nextid = h->rh_nextiter + 1;
1488         for (;;) {
1489                 scf_iter_t *cur;
1490 
1491                 if (nextid == 0) {
1492                         nextid++;
1493                         h->rh_flags |= HANDLE_WRAPPED_ITER;
1494                 }
1495                 if (!(h->rh_flags & HANDLE_WRAPPED_ITER))
1496                         break;                  /* not yet wrapped */
1497 
1498                 cur = uu_list_find(h->rh_iters, NULL, &nextid, NULL);
1499                 if (cur == NULL)
1500                         break;          /* not in use */
1501 
1502                 if (nextid == h->rh_nextiter)
1503                         return (0);     /* wrapped around; no ids available */
1504                 nextid++;
1505         }
1506 
1507         h->rh_nextiter = nextid;
1508         return (nextid);
1509 }
1510 
1511 static uint32_t
1512 handle_next_changeid(scf_handle_t *handle)
1513 {
1514         uint32_t nextid;
1515 
1516         assert(MUTEX_HELD(&handle->rh_lock));
1517 
1518         nextid = ++handle->rh_nextchangeid;
1519         if (nextid == 0)
1520                 nextid = ++handle->rh_nextchangeid;
1521         return (nextid);
1522 }
1523 
1524 /*
1525  * Fails with
1526  *   _INVALID_ARGUMENT - h is NULL
1527  *   _HANDLE_DESTROYED
1528  *   _INTERNAL - server response too big
1529  *               entity already set up with different type
1530  *   _NO_RESOURCES
1531  */
1532 static int
1533 datael_init(scf_datael_t *dp, scf_handle_t *h, uint32_t type)
1534 {
1535         int ret;
1536 
1537         if (h == NULL)
1538                 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
1539 
1540         uu_list_node_init(dp, &dp->rd_node, datael_pool);
1541 
1542         dp->rd_handle = h;
1543         dp->rd_type = type;
1544         dp->rd_reset = 0;
1545 
1546         (void) pthread_mutex_lock(&h->rh_lock);
1547         if (h->rh_flags & HANDLE_DEAD) {
1548                 /*
1549                  * we're in undefined territory (the user cannot use a handle
1550                  * directly after it has been destroyed), but we don't want
1551                  * to allow any new references to happen, so we fail here.
1552                  */
1553                 (void) pthread_mutex_unlock(&h->rh_lock);
1554                 return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED));
1555         }
1556         dp->rd_entity = handle_alloc_entityid(h);
1557         if (dp->rd_entity == 0) {
1558                 (void) pthread_mutex_unlock(&h->rh_lock);
1559                 uu_list_node_fini(dp, &dp->rd_node, datael_pool);
1560                 return (scf_set_error(SCF_ERROR_NO_MEMORY));
1561         }
1562 
1563         ret = datael_attach(dp);
1564         if (ret == 0) {
1565                 (void) uu_list_insert_before(h->rh_dataels, NULL, dp);
1566                 h->rh_extrefs++;
1567         } else {
1568                 uu_list_node_fini(dp, &dp->rd_node, datael_pool);
1569         }
1570         (void) pthread_mutex_unlock(&h->rh_lock);
1571 
1572         return (ret);
1573 }
1574 
1575 static void
1576 datael_destroy(scf_datael_t *dp)
1577 {
1578         scf_handle_t *h = dp->rd_handle;
1579 
1580         struct rep_protocol_entity_teardown request;
1581         rep_protocol_response_t response;
1582 
1583         (void) pthread_mutex_lock(&h->rh_lock);
1584         uu_list_remove(h->rh_dataels, dp);
1585         --h->rh_extrefs;
1586 
1587         if (handle_is_bound(h)) {
1588                 request.rpr_request = REP_PROTOCOL_ENTITY_TEARDOWN;
1589                 request.rpr_entityid = dp->rd_entity;
1590 
1591                 (void) make_door_call(h, &request, sizeof (request),
1592                     &response, sizeof (response));
1593         }
1594         handle_unrefed(h);                      /* drops h->rh_lock */
1595 
1596         dp->rd_handle = NULL;
1597 }
1598 
1599 static scf_handle_t *
1600 datael_handle(const scf_datael_t *dp)
1601 {
1602         return (handle_get(dp->rd_handle));
1603 }
1604 
1605 /*
1606  * We delay ENTITY_RESETs until right before the entity is used.  By doing
1607  * them lazily, we remove quite a few unnecessary calls.
1608  */
1609 static void
1610 datael_do_reset_locked(scf_datael_t *dp)
1611 {
1612         scf_handle_t *h = dp->rd_handle;
1613 
1614         struct rep_protocol_entity_reset request;
1615         rep_protocol_response_t response;
1616 
1617         assert(MUTEX_HELD(&h->rh_lock));
1618 
1619         request.rpr_request = REP_PROTOCOL_ENTITY_RESET;
1620         request.rpr_entityid = dp->rd_entity;
1621 
1622         (void) make_door_call(h, &request, sizeof (request),
1623             &response, sizeof (response));
1624 
1625         dp->rd_reset = 0;
1626 }
1627 
1628 static void
1629 datael_reset_locked(scf_datael_t *dp)
1630 {
1631         assert(MUTEX_HELD(&dp->rd_handle->rh_lock));
1632         dp->rd_reset = 1;
1633 }
1634 
1635 static void
1636 datael_reset(scf_datael_t *dp)
1637 {
1638         scf_handle_t *h = dp->rd_handle;
1639 
1640         (void) pthread_mutex_lock(&h->rh_lock);
1641         dp->rd_reset = 1;
1642         (void) pthread_mutex_unlock(&h->rh_lock);
1643 }
1644 
1645 static void
1646 datael_finish_reset(const scf_datael_t *dp_arg)
1647 {
1648         scf_datael_t *dp = (scf_datael_t *)dp_arg;
1649 
1650         if (dp->rd_reset)
1651                 datael_do_reset_locked(dp);
1652 }
1653 
1654 /*
1655  * Fails with _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response too
1656  * big, bad entity id, request not applicable to entity, name too long for
1657  * buffer), _NOT_SET, _DELETED, or _CONSTRAINT_VIOLATED (snaplevel is not of an
1658  * instance).
1659  */
1660 static ssize_t
1661 datael_get_name(const scf_datael_t *dp, char *buf, size_t size, uint32_t type)
1662 {
1663         scf_handle_t *h = dp->rd_handle;
1664 
1665         struct rep_protocol_entity_name request;
1666         struct rep_protocol_name_response response;
1667         ssize_t r;
1668 
1669         (void) pthread_mutex_lock(&h->rh_lock);
1670         request.rpr_request = REP_PROTOCOL_ENTITY_NAME;
1671         request.rpr_entityid = dp->rd_entity;
1672         request.rpr_answertype = type;
1673 
1674         datael_finish_reset(dp);
1675         r = make_door_call(h, &request, sizeof (request),
1676             &response, sizeof (response));
1677         (void) pthread_mutex_unlock(&h->rh_lock);
1678 
1679         if (r < 0)
1680                 DOOR_ERRORS_BLOCK(r);
1681 
1682         if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
1683                 assert(response.rpr_response != REP_PROTOCOL_FAIL_BAD_REQUEST);
1684                 if (response.rpr_response == REP_PROTOCOL_FAIL_NOT_FOUND)
1685                         return (scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED));
1686                 return (scf_set_error(proto_error(response.rpr_response)));
1687         }
1688         return (strlcpy(buf, response.rpr_name, size));
1689 }
1690 
1691 /*
1692  * Fails with _HANDLE_MISMATCH, _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL
1693  * (server response too big, bad element id), _EXISTS (elements have same id),
1694  * _NOT_SET, _DELETED, _CONSTRAINT_VIOLATED, _NOT_FOUND (scope has no parent),
1695  * or _SUCCESS.
1696  */
1697 static int
1698 datael_get_parent(const scf_datael_t *dp, scf_datael_t *pp)
1699 {
1700         scf_handle_t *h = dp->rd_handle;
1701 
1702         struct rep_protocol_entity_parent request;
1703         struct rep_protocol_response response;
1704 
1705         ssize_t r;
1706 
1707         if (h != pp->rd_handle)
1708                 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
1709 
1710         (void) pthread_mutex_lock(&h->rh_lock);
1711         request.rpr_request = REP_PROTOCOL_ENTITY_GET_PARENT;
1712         request.rpr_entityid = dp->rd_entity;
1713         request.rpr_outid = pp->rd_entity;
1714 
1715         datael_finish_reset(dp);
1716         datael_finish_reset(pp);
1717         r = make_door_call(h, &request, sizeof (request),
1718             &response, sizeof (response));
1719         (void) pthread_mutex_unlock(&h->rh_lock);
1720 
1721         if (r < 0)
1722                 DOOR_ERRORS_BLOCK(r);
1723 
1724         if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
1725                 if (response.rpr_response == REP_PROTOCOL_FAIL_TYPE_MISMATCH)
1726                         return (scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED));
1727                 return (scf_set_error(proto_error(response.rpr_response)));
1728         }
1729 
1730         return (SCF_SUCCESS);
1731 }
1732 
1733 /*
1734  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT (out does not have type type,
1735  * name is invalid), _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response
1736  * too big, bad id, iter already exists, element cannot have children of type,
1737  * type is invalid, iter was reset, sequence was bad, iter walks values, iter
1738  * does not walk type entities), _NOT_SET, _DELETED, _NO_RESOURCES,
1739  * _BACKEND_ACCESS, _NOT_FOUND.
1740  */
1741 static int
1742 datael_get_child_composed_locked(const scf_datael_t *dp, const char *name,
1743     uint32_t type, scf_datael_t *out, scf_iter_t *iter)
1744 {
1745         struct rep_protocol_iter_start request;
1746         struct rep_protocol_iter_read read_request;
1747         struct rep_protocol_response response;
1748 
1749         scf_handle_t *h = dp->rd_handle;
1750         ssize_t r;
1751 
1752         if (h != out->rd_handle)
1753                 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
1754 
1755         if (out->rd_type != type)
1756                 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
1757 
1758         assert(MUTEX_HELD(&h->rh_lock));
1759         assert(iter != NULL);
1760 
1761         scf_iter_reset_locked(iter);
1762         iter->iter_type = type;
1763 
1764         request.rpr_request = REP_PROTOCOL_ITER_START;
1765         request.rpr_iterid = iter->iter_id;
1766         request.rpr_entity = dp->rd_entity;
1767         request.rpr_itertype = type;
1768         request.rpr_flags = RP_ITER_START_EXACT | RP_ITER_START_COMPOSED;
1769 
1770         if (name == NULL || strlcpy(request.rpr_pattern, name,
1771             sizeof (request.rpr_pattern)) >= sizeof (request.rpr_pattern)) {
1772                 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
1773         }
1774 
1775         datael_finish_reset(dp);
1776         datael_finish_reset(out);
1777 
1778         /*
1779          * We hold the handle lock across both door calls, so that they
1780          * appear atomic.
1781          */
1782         r = make_door_call(h, &request, sizeof (request),
1783             &response, sizeof (response));
1784 
1785         if (r < 0)
1786                 DOOR_ERRORS_BLOCK(r);
1787 
1788         if (response.rpr_response != REP_PROTOCOL_SUCCESS)
1789                 return (scf_set_error(proto_error(response.rpr_response)));
1790 
1791         iter->iter_sequence++;
1792 
1793         read_request.rpr_request = REP_PROTOCOL_ITER_READ;
1794         read_request.rpr_iterid = iter->iter_id;
1795         read_request.rpr_sequence = iter->iter_sequence;
1796         read_request.rpr_entityid = out->rd_entity;
1797 
1798         r = make_door_call(h, &read_request, sizeof (read_request),
1799             &response, sizeof (response));
1800 
1801         scf_iter_reset_locked(iter);
1802 
1803         if (r < 0)
1804                 DOOR_ERRORS_BLOCK(r);
1805 
1806         if (response.rpr_response == REP_PROTOCOL_DONE) {
1807                 return (scf_set_error(SCF_ERROR_NOT_FOUND));
1808         }
1809 
1810         if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
1811                 if (response.rpr_response == REP_PROTOCOL_FAIL_NOT_SET ||
1812                     response.rpr_response == REP_PROTOCOL_FAIL_BAD_REQUEST)
1813                         return (scf_set_error(SCF_ERROR_INTERNAL));
1814                 return (scf_set_error(proto_error(response.rpr_response)));
1815         }
1816 
1817         return (0);
1818 }
1819 
1820 /*
1821  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT (out does not have type type,
1822  * name is invalid), _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response
1823  * too big, bad id, element cannot have children of type, type is invalid),
1824  * _NOT_SET, _DELETED, _NO_RESOURCES, _BACKEND_ACCESS.
1825  */
1826 static int
1827 datael_get_child_locked(const scf_datael_t *dp, const char *name,
1828     uint32_t type, scf_datael_t *out)
1829 {
1830         struct rep_protocol_entity_get_child request;
1831         struct rep_protocol_response response;
1832 
1833         scf_handle_t *h = dp->rd_handle;
1834         ssize_t r;
1835 
1836         if (h != out->rd_handle)
1837                 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
1838 
1839         if (out->rd_type != type)
1840                 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
1841 
1842         assert(MUTEX_HELD(&h->rh_lock));
1843 
1844         request.rpr_request = REP_PROTOCOL_ENTITY_GET_CHILD;
1845         request.rpr_entityid = dp->rd_entity;
1846         request.rpr_childid = out->rd_entity;
1847 
1848         if (name == NULL || strlcpy(request.rpr_name, name,
1849             sizeof (request.rpr_name)) >= sizeof (request.rpr_name)) {
1850                 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
1851         }
1852 
1853         datael_finish_reset(dp);
1854         datael_finish_reset(out);
1855 
1856         r = make_door_call(h, &request, sizeof (request),
1857             &response, sizeof (response));
1858 
1859         if (r < 0)
1860                 DOOR_ERRORS_BLOCK(r);
1861 
1862         if (response.rpr_response != REP_PROTOCOL_SUCCESS)
1863                 return (scf_set_error(proto_error(response.rpr_response)));
1864         return (0);
1865 }
1866 
1867 /*
1868  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT (out does not have type type,
1869  * name is invalid), _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response
1870  * too big, bad id, iter already exists, element cannot have children of type,
1871  * type is invalid, iter was reset, sequence was bad, iter walks values, iter
1872  * does not walk type entities), _NOT_SET, _DELETED, _NO_RESOURCES,
1873  * _BACKEND_ACCESS, _NOT_FOUND.
1874  */
1875 static int
1876 datael_get_child(const scf_datael_t *dp, const char *name, uint32_t type,
1877     scf_datael_t *out, boolean_t composed)
1878 {
1879         scf_handle_t *h = dp->rd_handle;
1880         uint32_t held = 0;
1881         int ret;
1882 
1883         scf_iter_t *iter = NULL;
1884 
1885         if (composed)
1886                 iter = HANDLE_HOLD_ITER(h);
1887 
1888         if (out == NULL) {
1889                 switch (type) {
1890                 case REP_PROTOCOL_ENTITY_SERVICE:
1891                         out = &HANDLE_HOLD_SERVICE(h)->rd_d;
1892                         held = RH_HOLD_SERVICE;
1893                         break;
1894 
1895                 case REP_PROTOCOL_ENTITY_INSTANCE:
1896                         out = &HANDLE_HOLD_INSTANCE(h)->rd_d;
1897                         held = RH_HOLD_INSTANCE;
1898                         break;
1899 
1900                 case REP_PROTOCOL_ENTITY_SNAPSHOT:
1901                         out = &HANDLE_HOLD_SNAPSHOT(h)->rd_d;
1902                         held = RH_HOLD_SNAPSHOT;
1903                         break;
1904 
1905                 case REP_PROTOCOL_ENTITY_SNAPLEVEL:
1906                         out = &HANDLE_HOLD_SNAPLVL(h)->rd_d;
1907                         held = RH_HOLD_SNAPLVL;
1908                         break;
1909 
1910                 case REP_PROTOCOL_ENTITY_PROPERTYGRP:
1911                         out = &HANDLE_HOLD_PG(h)->rd_d;
1912                         held = RH_HOLD_PG;
1913                         break;
1914 
1915                 case REP_PROTOCOL_ENTITY_PROPERTY:
1916                         out = &HANDLE_HOLD_PROPERTY(h)->rd_d;
1917                         held = RH_HOLD_PROPERTY;
1918                         break;
1919 
1920                 default:
1921                         assert(0);
1922                         abort();
1923                 }
1924         }
1925 
1926         (void) pthread_mutex_lock(&h->rh_lock);
1927         if (composed)
1928                 ret = datael_get_child_composed_locked(dp, name, type, out,
1929                     iter);
1930         else
1931                 ret = datael_get_child_locked(dp, name, type, out);
1932         (void) pthread_mutex_unlock(&h->rh_lock);
1933 
1934         if (composed)
1935                 HANDLE_RELE_ITER(h);
1936 
1937         if (held)
1938                 handle_rele_subhandles(h, held);
1939 
1940         return (ret);
1941 }
1942 
1943 /*
1944  * Fails with
1945  *   _HANDLE_MISMATCH
1946  *   _INVALID_ARGUMENT - name is too long
1947  *                       invalid changeid
1948  *                       name is invalid
1949  *                       cannot create children for dp's type of node
1950  *   _NOT_BOUND - handle is not bound
1951  *   _CONNECTION_BROKEN - server is not reachable
1952  *   _INTERNAL - server response too big
1953  *               dp or cp has unknown id
1954  *               type is _PROPERTYGRP
1955  *               type is invalid
1956  *               dp cannot have children of type type
1957  *               database is corrupt
1958  *   _EXISTS - dp & cp have the same id
1959  *   _EXISTS - child already exists
1960  *   _DELETED - dp has been deleted
1961  *   _NOT_SET - dp is reset
1962  *   _NO_RESOURCES
1963  *   _PERMISSION_DENIED
1964  *   _BACKEND_ACCESS
1965  *   _BACKEND_READONLY
1966  */
1967 static int
1968 datael_add_child(const scf_datael_t *dp, const char *name, uint32_t type,
1969     scf_datael_t *cp)
1970 {
1971         scf_handle_t *h = dp->rd_handle;
1972 
1973         struct rep_protocol_entity_create_child request;
1974         struct rep_protocol_response response;
1975         ssize_t r;
1976         uint32_t held = 0;
1977 
1978         if (cp == NULL) {
1979                 switch (type) {
1980                 case REP_PROTOCOL_ENTITY_SCOPE:
1981                         cp = &HANDLE_HOLD_SCOPE(h)->rd_d;
1982                         held = RH_HOLD_SCOPE;
1983                         break;
1984                 case REP_PROTOCOL_ENTITY_SERVICE:
1985                         cp = &HANDLE_HOLD_SERVICE(h)->rd_d;
1986                         held = RH_HOLD_SERVICE;
1987                         break;
1988                 case REP_PROTOCOL_ENTITY_INSTANCE:
1989                         cp = &HANDLE_HOLD_INSTANCE(h)->rd_d;
1990                         held = RH_HOLD_INSTANCE;
1991                         break;
1992                 case REP_PROTOCOL_ENTITY_SNAPSHOT:
1993                 default:
1994                         assert(0);
1995                         abort();
1996                 }
1997                 assert(h == cp->rd_handle);
1998 
1999         } else if (h != cp->rd_handle) {
2000                 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2001         }
2002 
2003         if (strlcpy(request.rpr_name, name, sizeof (request.rpr_name)) >=
2004             sizeof (request.rpr_name)) {
2005                 r = scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
2006                 goto err;
2007         }
2008 
2009         (void) pthread_mutex_lock(&h->rh_lock);
2010         request.rpr_request = REP_PROTOCOL_ENTITY_CREATE_CHILD;
2011         request.rpr_entityid = dp->rd_entity;
2012         request.rpr_childtype = type;
2013         request.rpr_childid = cp->rd_entity;
2014 
2015         datael_finish_reset(dp);
2016         request.rpr_changeid = handle_next_changeid(h);
2017         r = make_door_call(h, &request, sizeof (request),
2018             &response, sizeof (response));
2019         (void) pthread_mutex_unlock(&h->rh_lock);
2020 
2021         if (held)
2022                 handle_rele_subhandles(h, held);
2023 
2024         if (r < 0)
2025                 DOOR_ERRORS_BLOCK(r);
2026 
2027         if (response.rpr_response != REP_PROTOCOL_SUCCESS)
2028                 return (scf_set_error(proto_error(response.rpr_response)));
2029 
2030         return (SCF_SUCCESS);
2031 
2032 err:
2033         if (held)
2034                 handle_rele_subhandles(h, held);
2035         return (r);
2036 }
2037 
2038 static int
2039 datael_add_pg(const scf_datael_t *dp, const char *name, const char *type,
2040     uint32_t flags, scf_datael_t *cp)
2041 {
2042         scf_handle_t *h = dp->rd_handle;
2043 
2044         struct rep_protocol_entity_create_pg request;
2045         struct rep_protocol_response response;
2046         ssize_t r;
2047 
2048         int holding_els = 0;
2049 
2050         if (cp == NULL) {
2051                 holding_els = 1;
2052                 cp = &HANDLE_HOLD_PG(h)->rd_d;
2053                 assert(h == cp->rd_handle);
2054 
2055         } else if (h != cp->rd_handle) {
2056                 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2057         }
2058 
2059         request.rpr_request = REP_PROTOCOL_ENTITY_CREATE_PG;
2060 
2061         if (name == NULL || strlcpy(request.rpr_name, name,
2062             sizeof (request.rpr_name)) > sizeof (request.rpr_name)) {
2063                 r = scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
2064                 goto err;
2065         }
2066 
2067         if (type == NULL || strlcpy(request.rpr_type, type,
2068             sizeof (request.rpr_type)) > sizeof (request.rpr_type)) {
2069                 r = scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
2070                 goto err;
2071         }
2072 
2073         (void) pthread_mutex_lock(&h->rh_lock);
2074         request.rpr_entityid = dp->rd_entity;
2075         request.rpr_childid = cp->rd_entity;
2076         request.rpr_flags = flags;
2077 
2078         datael_finish_reset(dp);
2079         datael_finish_reset(cp);
2080         request.rpr_changeid = handle_next_changeid(h);
2081         r = make_door_call(h, &request, sizeof (request),
2082             &response, sizeof (response));
2083         (void) pthread_mutex_unlock(&h->rh_lock);
2084 
2085         if (holding_els)
2086                 HANDLE_RELE_PG(h);
2087 
2088         if (r < 0)
2089                 DOOR_ERRORS_BLOCK(r);
2090 
2091         if (response.rpr_response != REP_PROTOCOL_SUCCESS)
2092                 return (scf_set_error(proto_error(response.rpr_response)));
2093 
2094         return (SCF_SUCCESS);
2095 
2096 err:
2097         if (holding_els)
2098                 HANDLE_RELE_PG(h);
2099         return (r);
2100 }
2101 
2102 static int
2103 datael_delete(const scf_datael_t *dp)
2104 {
2105         scf_handle_t *h = dp->rd_handle;
2106 
2107         struct rep_protocol_entity_delete request;
2108         struct rep_protocol_response response;
2109         ssize_t r;
2110 
2111         (void) pthread_mutex_lock(&h->rh_lock);
2112         request.rpr_request = REP_PROTOCOL_ENTITY_DELETE;
2113         request.rpr_entityid = dp->rd_entity;
2114 
2115         datael_finish_reset(dp);
2116         request.rpr_changeid = handle_next_changeid(h);
2117         r = make_door_call(h, &request, sizeof (request),
2118             &response, sizeof (response));
2119         (void) pthread_mutex_unlock(&h->rh_lock);
2120 
2121         if (r < 0)
2122                 DOOR_ERRORS_BLOCK(r);
2123 
2124         if (response.rpr_response != REP_PROTOCOL_SUCCESS)
2125                 return (scf_set_error(proto_error(response.rpr_response)));
2126 
2127         return (SCF_SUCCESS);
2128 }
2129 
2130 /*
2131  * Fails with
2132  *   _INVALID_ARGUMENT - h is NULL
2133  *   _NO_MEMORY
2134  *   _HANDLE_DESTROYED - h has been destroyed
2135  *   _INTERNAL - server response too big
2136  *               iter already exists
2137  *   _NO_RESOURCES
2138  */
2139 scf_iter_t *
2140 scf_iter_create(scf_handle_t *h)
2141 {
2142         scf_iter_t *iter;
2143 
2144         if (h == NULL) {
2145                 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
2146                 return (NULL);
2147         }
2148 
2149         iter = uu_zalloc(sizeof (*iter));
2150         if (iter == NULL) {
2151                 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
2152                 return (NULL);
2153         }
2154 
2155         uu_list_node_init(iter, &iter->iter_node, iter_pool);
2156         iter->iter_handle = h;
2157         iter->iter_sequence = 1;
2158         iter->iter_type = REP_PROTOCOL_ENTITY_NONE;
2159 
2160         (void) pthread_mutex_lock(&h->rh_lock);
2161         iter->iter_id = handle_alloc_iterid(h);
2162         if (iter->iter_id == 0) {
2163                 (void) pthread_mutex_unlock(&h->rh_lock);
2164                 uu_list_node_fini(iter, &iter->iter_node, iter_pool);
2165                 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
2166                 uu_free(iter);
2167                 return (NULL);
2168         }
2169         if (iter_attach(iter) == -1) {
2170                 uu_list_node_fini(iter, &iter->iter_node, iter_pool);
2171                 (void) pthread_mutex_unlock(&h->rh_lock);
2172                 uu_free(iter);
2173                 return (NULL);
2174         }
2175         (void) uu_list_insert_before(h->rh_iters, NULL, iter);
2176         h->rh_extrefs++;
2177         (void) pthread_mutex_unlock(&h->rh_lock);
2178         return (iter);
2179 }
2180 
2181 scf_handle_t *
2182 scf_iter_handle(const scf_iter_t *iter)
2183 {
2184         return (handle_get(iter->iter_handle));
2185 }
2186 
2187 static void
2188 scf_iter_reset_locked(scf_iter_t *iter)
2189 {
2190         struct rep_protocol_iter_request request;
2191         struct rep_protocol_response response;
2192 
2193         request.rpr_request = REP_PROTOCOL_ITER_RESET;
2194         request.rpr_iterid = iter->iter_id;
2195 
2196         assert(MUTEX_HELD(&iter->iter_handle->rh_lock));
2197 
2198         (void) make_door_call(iter->iter_handle,
2199             &request, sizeof (request), &response, sizeof (response));
2200 
2201         iter->iter_type = REP_PROTOCOL_ENTITY_NONE;
2202         iter->iter_sequence = 1;
2203 }
2204 
2205 void
2206 scf_iter_reset(scf_iter_t *iter)
2207 {
2208         (void) pthread_mutex_lock(&iter->iter_handle->rh_lock);
2209         scf_iter_reset_locked(iter);
2210         (void) pthread_mutex_unlock(&iter->iter_handle->rh_lock);
2211 }
2212 
2213 void
2214 scf_iter_destroy(scf_iter_t *iter)
2215 {
2216         scf_handle_t *handle;
2217 
2218         struct rep_protocol_iter_request request;
2219         struct rep_protocol_response response;
2220 
2221         if (iter == NULL)
2222                 return;
2223 
2224         handle = iter->iter_handle;
2225 
2226         (void) pthread_mutex_lock(&handle->rh_lock);
2227         request.rpr_request = REP_PROTOCOL_ITER_TEARDOWN;
2228         request.rpr_iterid = iter->iter_id;
2229 
2230         (void) make_door_call(handle, &request, sizeof (request),
2231             &response, sizeof (response));
2232 
2233         uu_list_remove(handle->rh_iters, iter);
2234         --handle->rh_extrefs;
2235         handle_unrefed(handle);                 /* drops h->rh_lock */
2236         iter->iter_handle = NULL;
2237 
2238         uu_list_node_fini(iter, &iter->iter_node, iter_pool);
2239         uu_free(iter);
2240 }
2241 
2242 static int
2243 handle_get_local_scope_locked(scf_handle_t *handle, scf_scope_t *out)
2244 {
2245         struct rep_protocol_entity_get request;
2246         struct rep_protocol_name_response response;
2247         ssize_t r;
2248 
2249         assert(MUTEX_HELD(&handle->rh_lock));
2250 
2251         if (handle != out->rd_d.rd_handle)
2252                 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2253 
2254         request.rpr_request = REP_PROTOCOL_ENTITY_GET;
2255         request.rpr_entityid = out->rd_d.rd_entity;
2256         request.rpr_object = RP_ENTITY_GET_MOST_LOCAL_SCOPE;
2257 
2258         datael_finish_reset(&out->rd_d);
2259         r = make_door_call(handle, &request, sizeof (request),
2260             &response, sizeof (response));
2261 
2262         if (r < 0)
2263                 DOOR_ERRORS_BLOCK(r);
2264 
2265         if (response.rpr_response != REP_PROTOCOL_SUCCESS)
2266                 return (scf_set_error(proto_error(response.rpr_response)));
2267 
2268         return (SCF_SUCCESS);
2269 }
2270 
2271 int
2272 scf_iter_handle_scopes(scf_iter_t *iter, const scf_handle_t *handle)
2273 {
2274         scf_handle_t *h = iter->iter_handle;
2275         if (h != handle)
2276                 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2277 
2278         (void) pthread_mutex_lock(&h->rh_lock);
2279         scf_iter_reset_locked(iter);
2280 
2281         if (!handle_is_bound(h)) {
2282                 (void) pthread_mutex_unlock(&h->rh_lock);
2283                 return (scf_set_error(SCF_ERROR_NOT_BOUND));
2284         }
2285 
2286         if (!handle_has_server_locked(h)) {
2287                 (void) pthread_mutex_unlock(&h->rh_lock);
2288                 return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN));
2289         }
2290 
2291         iter->iter_type = REP_PROTOCOL_ENTITY_SCOPE;
2292         iter->iter_sequence = 1;
2293         (void) pthread_mutex_unlock(&h->rh_lock);
2294         return (0);
2295 }
2296 
2297 int
2298 scf_iter_next_scope(scf_iter_t *iter, scf_scope_t *out)
2299 {
2300         int ret;
2301         scf_handle_t *h = iter->iter_handle;
2302 
2303         if (h != out->rd_d.rd_handle)
2304                 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2305 
2306         (void) pthread_mutex_lock(&h->rh_lock);
2307         if (iter->iter_type == REP_PROTOCOL_ENTITY_NONE) {
2308                 (void) pthread_mutex_unlock(&h->rh_lock);
2309                 return (scf_set_error(SCF_ERROR_NOT_SET));
2310         }
2311         if (iter->iter_type != REP_PROTOCOL_ENTITY_SCOPE) {
2312                 (void) pthread_mutex_unlock(&h->rh_lock);
2313                 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
2314         }
2315         if (iter->iter_sequence == 1) {
2316                 if ((ret = handle_get_local_scope_locked(h, out)) ==
2317                     SCF_SUCCESS) {
2318                         iter->iter_sequence++;
2319                         ret = 1;
2320                 }
2321         } else {
2322                 datael_reset_locked(&out->rd_d);
2323                 ret = 0;
2324         }
2325         (void) pthread_mutex_unlock(&h->rh_lock);
2326         return (ret);
2327 }
2328 
2329 int
2330 scf_handle_get_scope(scf_handle_t *h, const char *name, scf_scope_t *out)
2331 {
2332         int ret;
2333 
2334         if (h != out->rd_d.rd_handle)
2335                 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2336 
2337         (void) pthread_mutex_lock(&h->rh_lock);
2338         if (strcmp(name, SCF_SCOPE_LOCAL) == 0) {
2339                 ret = handle_get_local_scope_locked(h, out);
2340         } else {
2341                 datael_reset_locked(&out->rd_d);
2342                 if (uu_check_name(name, 0) == -1)
2343                         ret = scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
2344                 else
2345                         ret = scf_set_error(SCF_ERROR_NOT_FOUND);
2346         }
2347         (void) pthread_mutex_unlock(&h->rh_lock);
2348         return (ret);
2349 }
2350 
2351 static int
2352 datael_setup_iter(scf_iter_t *iter, const scf_datael_t *dp, uint32_t res_type,
2353     boolean_t composed)
2354 {
2355         scf_handle_t *h = dp->rd_handle;
2356 
2357         struct rep_protocol_iter_start request;
2358         struct rep_protocol_response response;
2359 
2360         ssize_t r;
2361 
2362         if (h != iter->iter_handle)
2363                 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2364 
2365         (void) pthread_mutex_lock(&h->rh_lock);
2366         scf_iter_reset_locked(iter);
2367         iter->iter_type = res_type;
2368 
2369         request.rpr_request = REP_PROTOCOL_ITER_START;
2370         request.rpr_iterid = iter->iter_id;
2371         request.rpr_entity = dp->rd_entity;
2372         request.rpr_itertype = res_type;
2373         request.rpr_flags = RP_ITER_START_ALL |
2374             (composed ? RP_ITER_START_COMPOSED : 0);
2375         request.rpr_pattern[0] = 0;
2376 
2377         datael_finish_reset(dp);
2378         r = make_door_call(h, &request, sizeof (request),
2379             &response, sizeof (response));
2380 
2381         if (r < 0) {
2382                 (void) pthread_mutex_unlock(&h->rh_lock);
2383                 DOOR_ERRORS_BLOCK(r);
2384         }
2385         if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
2386                 (void) pthread_mutex_unlock(&h->rh_lock);
2387                 return (scf_set_error(proto_error(response.rpr_response)));
2388         }
2389         iter->iter_sequence++;
2390         (void) pthread_mutex_unlock(&h->rh_lock);
2391         return (SCF_SUCCESS);
2392 }
2393 
2394 static int
2395 datael_setup_iter_pgtyped(scf_iter_t *iter, const scf_datael_t *dp,
2396     const char *pgtype, boolean_t composed)
2397 {
2398         scf_handle_t *h = dp->rd_handle;
2399 
2400         struct rep_protocol_iter_start request;
2401         struct rep_protocol_response response;
2402 
2403         ssize_t r;
2404 
2405         if (h != iter->iter_handle)
2406                 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2407 
2408         if (pgtype == NULL || strlcpy(request.rpr_pattern, pgtype,
2409             sizeof (request.rpr_pattern)) >= sizeof (request.rpr_pattern)) {
2410                 scf_iter_reset(iter);
2411                 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
2412         }
2413 
2414         (void) pthread_mutex_lock(&h->rh_lock);
2415         request.rpr_request = REP_PROTOCOL_ITER_START;
2416         request.rpr_iterid = iter->iter_id;
2417         request.rpr_entity = dp->rd_entity;
2418         request.rpr_itertype = REP_PROTOCOL_ENTITY_PROPERTYGRP;
2419         request.rpr_flags = RP_ITER_START_PGTYPE |
2420             (composed ? RP_ITER_START_COMPOSED : 0);
2421 
2422         datael_finish_reset(dp);
2423         scf_iter_reset_locked(iter);
2424         iter->iter_type = REP_PROTOCOL_ENTITY_PROPERTYGRP;
2425 
2426         r = make_door_call(h, &request, sizeof (request),
2427             &response, sizeof (response));
2428 
2429         if (r < 0) {
2430                 (void) pthread_mutex_unlock(&h->rh_lock);
2431 
2432                 DOOR_ERRORS_BLOCK(r);
2433         }
2434         if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
2435                 (void) pthread_mutex_unlock(&h->rh_lock);
2436                 return (scf_set_error(proto_error(response.rpr_response)));
2437         }
2438         iter->iter_sequence++;
2439         (void) pthread_mutex_unlock(&h->rh_lock);
2440         return (SCF_SUCCESS);
2441 }
2442 
2443 static int
2444 datael_iter_next(scf_iter_t *iter, scf_datael_t *out)
2445 {
2446         scf_handle_t *h = iter->iter_handle;
2447 
2448         struct rep_protocol_iter_read request;
2449         struct rep_protocol_response response;
2450         ssize_t r;
2451 
2452         if (h != out->rd_handle)
2453                 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2454 
2455         (void) pthread_mutex_lock(&h->rh_lock);
2456         if (iter->iter_type == REP_PROTOCOL_ENTITY_NONE ||
2457             iter->iter_sequence == 1) {
2458                 (void) pthread_mutex_unlock(&h->rh_lock);
2459                 return (scf_set_error(SCF_ERROR_NOT_SET));
2460         }
2461 
2462         if (out->rd_type != iter->iter_type) {
2463                 (void) pthread_mutex_unlock(&h->rh_lock);
2464                 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
2465         }
2466 
2467         request.rpr_request = REP_PROTOCOL_ITER_READ;
2468         request.rpr_iterid = iter->iter_id;
2469         request.rpr_sequence = iter->iter_sequence;
2470         request.rpr_entityid = out->rd_entity;
2471 
2472         datael_finish_reset(out);
2473         r = make_door_call(h, &request, sizeof (request),
2474             &response, sizeof (response));
2475 
2476         if (r < 0) {
2477                 (void) pthread_mutex_unlock(&h->rh_lock);
2478                 DOOR_ERRORS_BLOCK(r);
2479         }
2480 
2481         if (response.rpr_response == REP_PROTOCOL_DONE) {
2482                 (void) pthread_mutex_unlock(&h->rh_lock);
2483                 return (0);
2484         }
2485         if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
2486                 (void) pthread_mutex_unlock(&h->rh_lock);
2487                 return (scf_set_error(proto_error(response.rpr_response)));
2488         }
2489         iter->iter_sequence++;
2490         (void) pthread_mutex_unlock(&h->rh_lock);
2491 
2492         return (1);
2493 }
2494 
2495 int
2496 scf_iter_scope_services(scf_iter_t *iter, const scf_scope_t *s)
2497 {
2498         return (datael_setup_iter(iter, &s->rd_d,
2499             REP_PROTOCOL_ENTITY_SERVICE, 0));
2500 }
2501 
2502 int
2503 scf_iter_next_service(scf_iter_t *iter, scf_service_t *out)
2504 {
2505         return (datael_iter_next(iter, &out->rd_d));
2506 }
2507 
2508 int
2509 scf_iter_service_instances(scf_iter_t *iter, const scf_service_t *svc)
2510 {
2511         return (datael_setup_iter(iter, &svc->rd_d,
2512             REP_PROTOCOL_ENTITY_INSTANCE, 0));
2513 }
2514 
2515 int
2516 scf_iter_next_instance(scf_iter_t *iter, scf_instance_t *out)
2517 {
2518         return (datael_iter_next(iter, &out->rd_d));
2519 }
2520 
2521 int
2522 scf_iter_service_pgs(scf_iter_t *iter, const scf_service_t *svc)
2523 {
2524         return (datael_setup_iter(iter, &svc->rd_d,
2525             REP_PROTOCOL_ENTITY_PROPERTYGRP, 0));
2526 }
2527 
2528 int
2529 scf_iter_service_pgs_typed(scf_iter_t *iter, const scf_service_t *svc,
2530     const char *type)
2531 {
2532         return (datael_setup_iter_pgtyped(iter, &svc->rd_d, type, 0));
2533 }
2534 
2535 int
2536 scf_iter_instance_snapshots(scf_iter_t *iter, const scf_instance_t *inst)
2537 {
2538         return (datael_setup_iter(iter, &inst->rd_d,
2539             REP_PROTOCOL_ENTITY_SNAPSHOT, 0));
2540 }
2541 
2542 int
2543 scf_iter_next_snapshot(scf_iter_t *iter, scf_snapshot_t *out)
2544 {
2545         return (datael_iter_next(iter, &out->rd_d));
2546 }
2547 
2548 int
2549 scf_iter_instance_pgs(scf_iter_t *iter, const scf_instance_t *inst)
2550 {
2551         return (datael_setup_iter(iter, &inst->rd_d,
2552             REP_PROTOCOL_ENTITY_PROPERTYGRP, 0));
2553 }
2554 
2555 int
2556 scf_iter_instance_pgs_typed(scf_iter_t *iter, const scf_instance_t *inst,
2557     const char *type)
2558 {
2559         return (datael_setup_iter_pgtyped(iter, &inst->rd_d, type, 0));
2560 }
2561 
2562 int
2563 scf_iter_instance_pgs_composed(scf_iter_t *iter, const scf_instance_t *inst,
2564     const scf_snapshot_t *snap)
2565 {
2566         if (snap != NULL && inst->rd_d.rd_handle != snap->rd_d.rd_handle)
2567                 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2568 
2569         return (datael_setup_iter(iter, snap ? &snap->rd_d : &inst->rd_d,
2570             REP_PROTOCOL_ENTITY_PROPERTYGRP, 1));
2571 }
2572 
2573 int
2574 scf_iter_instance_pgs_typed_composed(scf_iter_t *iter,
2575     const scf_instance_t *inst, const scf_snapshot_t *snap, const char *type)
2576 {
2577         if (snap != NULL && inst->rd_d.rd_handle != snap->rd_d.rd_handle)
2578                 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2579 
2580         return (datael_setup_iter_pgtyped(iter,
2581             snap ? &snap->rd_d : &inst->rd_d, type, 1));
2582 }
2583 
2584 int
2585 scf_iter_snaplevel_pgs(scf_iter_t *iter, const scf_snaplevel_t *inst)
2586 {
2587         return (datael_setup_iter(iter, &inst->rd_d,
2588             REP_PROTOCOL_ENTITY_PROPERTYGRP, 0));
2589 }
2590 
2591 int
2592 scf_iter_snaplevel_pgs_typed(scf_iter_t *iter, const scf_snaplevel_t *inst,
2593     const char *type)
2594 {
2595         return (datael_setup_iter_pgtyped(iter, &inst->rd_d, type, 0));
2596 }
2597 
2598 int
2599 scf_iter_next_pg(scf_iter_t *iter, scf_propertygroup_t *out)
2600 {
2601         return (datael_iter_next(iter, &out->rd_d));
2602 }
2603 
2604 int
2605 scf_iter_pg_properties(scf_iter_t *iter, const scf_propertygroup_t *pg)
2606 {
2607         return (datael_setup_iter(iter, &pg->rd_d,
2608             REP_PROTOCOL_ENTITY_PROPERTY, 0));
2609 }
2610 
2611 int
2612 scf_iter_next_property(scf_iter_t *iter, scf_property_t *out)
2613 {
2614         return (datael_iter_next(iter, &out->rd_d));
2615 }
2616 
2617 /*
2618  * Fails with
2619  *   _INVALID_ARGUMENT - handle is NULL
2620  *   _INTERNAL - server response too big
2621  *               entity already set up with different type
2622  *   _NO_RESOURCES
2623  *   _NO_MEMORY
2624  */
2625 scf_scope_t *
2626 scf_scope_create(scf_handle_t *handle)
2627 {
2628         scf_scope_t *ret;
2629 
2630         ret = uu_zalloc(sizeof (*ret));
2631         if (ret != NULL) {
2632                 if (datael_init(&ret->rd_d, handle,
2633                     REP_PROTOCOL_ENTITY_SCOPE) == -1) {
2634                         uu_free(ret);
2635                         return (NULL);
2636                 }
2637         } else {
2638                 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
2639         }
2640 
2641         return (ret);
2642 }
2643 
2644 scf_handle_t *
2645 scf_scope_handle(const scf_scope_t *val)
2646 {
2647         return (datael_handle(&val->rd_d));
2648 }
2649 
2650 void
2651 scf_scope_destroy(scf_scope_t *val)
2652 {
2653         if (val == NULL)
2654                 return;
2655 
2656         datael_destroy(&val->rd_d);
2657         uu_free(val);
2658 }
2659 
2660 ssize_t
2661 scf_scope_get_name(const scf_scope_t *rep, char *out, size_t len)
2662 {
2663         return (datael_get_name(&rep->rd_d, out, len, RP_ENTITY_NAME_NAME));
2664 }
2665 
2666 /*ARGSUSED*/
2667 int
2668 scf_scope_get_parent(const scf_scope_t *child, scf_scope_t *parent)
2669 {
2670         char name[1];
2671 
2672         /* fake up the side-effects */
2673         datael_reset(&parent->rd_d);
2674         if (scf_scope_get_name(child, name, sizeof (name)) < 0)
2675                 return (-1);
2676         return (scf_set_error(SCF_ERROR_NOT_FOUND));
2677 }
2678 
2679 /*
2680  * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
2681  * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
2682  */
2683 scf_service_t *
2684 scf_service_create(scf_handle_t *handle)
2685 {
2686         scf_service_t *ret;
2687         ret = uu_zalloc(sizeof (*ret));
2688         if (ret != NULL) {
2689                 if (datael_init(&ret->rd_d, handle,
2690                     REP_PROTOCOL_ENTITY_SERVICE) == -1) {
2691                         uu_free(ret);
2692                         return (NULL);
2693                 }
2694         } else {
2695                 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
2696         }
2697 
2698         return (ret);
2699 }
2700 
2701 
2702 /*
2703  * Fails with
2704  *   _HANDLE_MISMATCH
2705  *   _INVALID_ARGUMENT
2706  *   _NOT_BOUND
2707  *   _CONNECTION_BROKEN
2708  *   _INTERNAL
2709  *   _EXISTS
2710  *   _DELETED
2711  *   _NOT_SET
2712  *   _NO_RESOURCES
2713  *   _PERMISSION_DENIED
2714  *   _BACKEND_ACCESS
2715  *   _BACKEND_READONLY
2716  */
2717 int
2718 scf_scope_add_service(const scf_scope_t *scope, const char *name,
2719     scf_service_t *svc)
2720 {
2721         return (datael_add_child(&scope->rd_d, name,
2722             REP_PROTOCOL_ENTITY_SERVICE, (svc != NULL)? &svc->rd_d : NULL));
2723 }
2724 
2725 /*
2726  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2727  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2728  * _BACKEND_ACCESS, _NOT_FOUND.
2729  */
2730 int
2731 scf_scope_get_service(const scf_scope_t *s, const char *name,
2732     scf_service_t *svc)
2733 {
2734         return (datael_get_child(&s->rd_d, name, REP_PROTOCOL_ENTITY_SERVICE,
2735             svc ? &svc->rd_d : NULL, 0));
2736 }
2737 
2738 scf_handle_t *
2739 scf_service_handle(const scf_service_t *val)
2740 {
2741         return (datael_handle(&val->rd_d));
2742 }
2743 
2744 int
2745 scf_service_delete(scf_service_t *svc)
2746 {
2747         return (datael_delete(&svc->rd_d));
2748 }
2749 
2750 int
2751 scf_instance_delete(scf_instance_t *inst)
2752 {
2753         return (datael_delete(&inst->rd_d));
2754 }
2755 
2756 int
2757 scf_pg_delete(scf_propertygroup_t *pg)
2758 {
2759         return (datael_delete(&pg->rd_d));
2760 }
2761 
2762 int
2763 _scf_snapshot_delete(scf_snapshot_t *snap)
2764 {
2765         return (datael_delete(&snap->rd_d));
2766 }
2767 
2768 /*
2769  * Fails with
2770  *   _HANDLE_MISMATCH
2771  *   _INVALID_ARGUMENT
2772  *   _NOT_BOUND
2773  *   _CONNECTION_BROKEN
2774  *   _INTERNAL
2775  *   _EXISTS
2776  *   _DELETED
2777  *   _NOT_SET
2778  *   _NO_RESOURCES
2779  *   _PERMISSION_DENIED
2780  *   _BACKEND_ACCESS
2781  *   _BACKEND_READONLY
2782  */
2783 int
2784 scf_service_add_instance(const scf_service_t *svc, const char *name,
2785     scf_instance_t *instance)
2786 {
2787         return (datael_add_child(&svc->rd_d, name,
2788             REP_PROTOCOL_ENTITY_INSTANCE,
2789             (instance != NULL)? &instance->rd_d : NULL));
2790 }
2791 
2792 
2793 /*
2794  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2795  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2796  * _BACKEND_ACCESS, _NOT_FOUND.
2797  */
2798 int
2799 scf_service_get_instance(const scf_service_t *svc, const char *name,
2800     scf_instance_t *inst)
2801 {
2802         return (datael_get_child(&svc->rd_d, name, REP_PROTOCOL_ENTITY_INSTANCE,
2803             inst ? &inst->rd_d : NULL, 0));
2804 }
2805 
2806 int
2807 scf_service_add_pg(const scf_service_t *svc, const char *name,
2808     const char *type, uint32_t flags, scf_propertygroup_t *pg)
2809 {
2810         return (datael_add_pg(&svc->rd_d, name, type, flags,
2811             (pg != NULL)?&pg->rd_d : NULL));
2812 }
2813 
2814 /*
2815  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2816  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2817  * _BACKEND_ACCESS, _NOT_FOUND.
2818  */
2819 int
2820 scf_service_get_pg(const scf_service_t *svc, const char *name,
2821     scf_propertygroup_t *pg)
2822 {
2823         return (datael_get_child(&svc->rd_d, name,
2824             REP_PROTOCOL_ENTITY_PROPERTYGRP, pg ? &pg->rd_d : NULL, 0));
2825 }
2826 
2827 int
2828 scf_instance_add_pg(const scf_instance_t *inst, const char *name,
2829     const char *type, uint32_t flags, scf_propertygroup_t *pg)
2830 {
2831         return (datael_add_pg(&inst->rd_d, name, type, flags,
2832             (pg != NULL)?&pg->rd_d : NULL));
2833 }
2834 
2835 /*
2836  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2837  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2838  * _BACKEND_ACCESS, _NOT_FOUND.
2839  */
2840 int
2841 scf_instance_get_snapshot(const scf_instance_t *inst, const char *name,
2842     scf_snapshot_t *pg)
2843 {
2844         return (datael_get_child(&inst->rd_d, name,
2845             REP_PROTOCOL_ENTITY_SNAPSHOT, pg ? &pg->rd_d : NULL, 0));
2846 }
2847 
2848 /*
2849  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2850  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2851  * _BACKEND_ACCESS, _NOT_FOUND.
2852  */
2853 int
2854 scf_instance_get_pg(const scf_instance_t *inst, const char *name,
2855     scf_propertygroup_t *pg)
2856 {
2857         return (datael_get_child(&inst->rd_d, name,
2858             REP_PROTOCOL_ENTITY_PROPERTYGRP, pg ? &pg->rd_d : NULL, 0));
2859 }
2860 
2861 /*
2862  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2863  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2864  * _BACKEND_ACCESS, _NOT_FOUND.
2865  */
2866 int
2867 scf_instance_get_pg_composed(const scf_instance_t *inst,
2868     const scf_snapshot_t *snap, const char *name, scf_propertygroup_t *pg)
2869 {
2870         if (snap != NULL && inst->rd_d.rd_handle != snap->rd_d.rd_handle)
2871                 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2872 
2873         return (datael_get_child(snap ? &snap->rd_d : &inst->rd_d, name,
2874             REP_PROTOCOL_ENTITY_PROPERTYGRP, pg ? &pg->rd_d : NULL, 1));
2875 }
2876 
2877 /*
2878  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2879  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2880  * _BACKEND_ACCESS, _NOT_FOUND.
2881  */
2882 int
2883 scf_pg_get_property(const scf_propertygroup_t *pg, const char *name,
2884     scf_property_t *prop)
2885 {
2886         return (datael_get_child(&pg->rd_d, name, REP_PROTOCOL_ENTITY_PROPERTY,
2887             prop ? &prop->rd_d : NULL, 0));
2888 }
2889 
2890 void
2891 scf_service_destroy(scf_service_t *val)
2892 {
2893         if (val == NULL)
2894                 return;
2895 
2896         datael_destroy(&val->rd_d);
2897         uu_free(val);
2898 }
2899 
2900 ssize_t
2901 scf_service_get_name(const scf_service_t *rep, char *out, size_t len)
2902 {
2903         return (datael_get_name(&rep->rd_d, out, len, RP_ENTITY_NAME_NAME));
2904 }
2905 
2906 /*
2907  * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
2908  * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
2909  */
2910 scf_instance_t *
2911 scf_instance_create(scf_handle_t *handle)
2912 {
2913         scf_instance_t *ret;
2914 
2915         ret = uu_zalloc(sizeof (*ret));
2916         if (ret != NULL) {
2917                 if (datael_init(&ret->rd_d, handle,
2918                     REP_PROTOCOL_ENTITY_INSTANCE) == -1) {
2919                         uu_free(ret);
2920                         return (NULL);
2921                 }
2922         } else {
2923                 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
2924         }
2925 
2926         return (ret);
2927 }
2928 
2929 scf_handle_t *
2930 scf_instance_handle(const scf_instance_t *val)
2931 {
2932         return (datael_handle(&val->rd_d));
2933 }
2934 
2935 void
2936 scf_instance_destroy(scf_instance_t *val)
2937 {
2938         if (val == NULL)
2939                 return;
2940 
2941         datael_destroy(&val->rd_d);
2942         uu_free(val);
2943 }
2944 
2945 ssize_t
2946 scf_instance_get_name(const scf_instance_t *rep, char *out, size_t len)
2947 {
2948         return (datael_get_name(&rep->rd_d, out, len, RP_ENTITY_NAME_NAME));
2949 }
2950 
2951 /*
2952  * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
2953  * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
2954  */
2955 scf_snapshot_t *
2956 scf_snapshot_create(scf_handle_t *handle)
2957 {
2958         scf_snapshot_t *ret;
2959 
2960         ret = uu_zalloc(sizeof (*ret));
2961         if (ret != NULL) {
2962                 if (datael_init(&ret->rd_d, handle,
2963                     REP_PROTOCOL_ENTITY_SNAPSHOT) == -1) {
2964                         uu_free(ret);
2965                         return (NULL);
2966                 }
2967         } else {
2968                 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
2969         }
2970 
2971         return (ret);
2972 }
2973 
2974 scf_handle_t *
2975 scf_snapshot_handle(const scf_snapshot_t *val)
2976 {
2977         return (datael_handle(&val->rd_d));
2978 }
2979 
2980 void
2981 scf_snapshot_destroy(scf_snapshot_t *val)
2982 {
2983         if (val == NULL)
2984                 return;
2985 
2986         datael_destroy(&val->rd_d);
2987         uu_free(val);
2988 }
2989 
2990 ssize_t
2991 scf_snapshot_get_name(const scf_snapshot_t *rep, char *out, size_t len)
2992 {
2993         return (datael_get_name(&rep->rd_d, out, len, RP_ENTITY_NAME_NAME));
2994 }
2995 
2996 /*
2997  * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
2998  * (bad server response or id in use), _NO_RESOURCES, _NO_MEMORY.
2999  */
3000 scf_snaplevel_t *
3001 scf_snaplevel_create(scf_handle_t *handle)
3002 {
3003         scf_snaplevel_t *ret;
3004 
3005         ret = uu_zalloc(sizeof (*ret));
3006         if (ret != NULL) {
3007                 if (datael_init(&ret->rd_d, handle,
3008                     REP_PROTOCOL_ENTITY_SNAPLEVEL) == -1) {
3009                         uu_free(ret);
3010                         return (NULL);
3011                 }
3012         } else {
3013                 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
3014         }
3015 
3016         return (ret);
3017 }
3018 
3019 scf_handle_t *
3020 scf_snaplevel_handle(const scf_snaplevel_t *val)
3021 {
3022         return (datael_handle(&val->rd_d));
3023 }
3024 
3025 void
3026 scf_snaplevel_destroy(scf_snaplevel_t *val)
3027 {
3028         if (val == NULL)
3029                 return;
3030 
3031         datael_destroy(&val->rd_d);
3032         uu_free(val);
3033 }
3034 
3035 ssize_t
3036 scf_snaplevel_get_scope_name(const scf_snaplevel_t *rep, char *out, size_t len)
3037 {
3038         return (datael_get_name(&rep->rd_d, out, len,
3039             RP_ENTITY_NAME_SNAPLEVEL_SCOPE));
3040 }
3041 
3042 ssize_t
3043 scf_snaplevel_get_service_name(const scf_snaplevel_t *rep, char *out,
3044     size_t len)
3045 {
3046         return (datael_get_name(&rep->rd_d, out, len,
3047             RP_ENTITY_NAME_SNAPLEVEL_SERVICE));
3048 }
3049 
3050 ssize_t
3051 scf_snaplevel_get_instance_name(const scf_snaplevel_t *rep, char *out,
3052     size_t len)
3053 {
3054         return (datael_get_name(&rep->rd_d, out, len,
3055             RP_ENTITY_NAME_SNAPLEVEL_INSTANCE));
3056 }
3057 
3058 /*
3059  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
3060  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
3061  * _BACKEND_ACCESS, _NOT_FOUND.
3062  */
3063 int
3064 scf_snaplevel_get_pg(const scf_snaplevel_t *snap, const char *name,
3065     scf_propertygroup_t *pg)
3066 {
3067         return (datael_get_child(&snap->rd_d, name,
3068             REP_PROTOCOL_ENTITY_PROPERTYGRP, pg ? &pg->rd_d : NULL, 0));
3069 }
3070 
3071 static int
3072 snaplevel_next(const scf_datael_t *src, scf_snaplevel_t *dst_arg)
3073 {
3074         scf_handle_t *h = src->rd_handle;
3075         scf_snaplevel_t *dst = dst_arg;
3076         struct rep_protocol_entity_pair request;
3077         struct rep_protocol_response response;
3078         int r;
3079         int dups = 0;
3080 
3081         if (h != dst->rd_d.rd_handle)
3082                 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
3083 
3084         if (src == &dst->rd_d) {
3085                 dups = 1;
3086                 dst = HANDLE_HOLD_SNAPLVL(h);
3087         }
3088         (void) pthread_mutex_lock(&h->rh_lock);
3089         request.rpr_request = REP_PROTOCOL_NEXT_SNAPLEVEL;
3090         request.rpr_entity_src = src->rd_entity;
3091         request.rpr_entity_dst = dst->rd_d.rd_entity;
3092 
3093         datael_finish_reset(src);
3094         datael_finish_reset(&dst->rd_d);
3095         r = make_door_call(h, &request, sizeof (request),
3096             &response, sizeof (response));
3097         /*
3098          * if we succeeded, we need to swap dst and dst_arg's identity.  We
3099          * take advantage of the fact that the only in-library knowledge is
3100          * their entity ids.
3101          */
3102         if (dups && r >= 0 &&
3103             (response.rpr_response == REP_PROTOCOL_SUCCESS ||
3104             response.rpr_response == REP_PROTOCOL_DONE)) {
3105                 int entity = dst->rd_d.rd_entity;
3106 
3107                 dst->rd_d.rd_entity = dst_arg->rd_d.rd_entity;
3108                 dst_arg->rd_d.rd_entity = entity;
3109         }
3110         (void) pthread_mutex_unlock(&h->rh_lock);
3111 
3112         if (dups)
3113                 HANDLE_RELE_SNAPLVL(h);
3114 
3115         if (r < 0)
3116                 DOOR_ERRORS_BLOCK(r);
3117 
3118         if (response.rpr_response != REP_PROTOCOL_SUCCESS &&
3119             response.rpr_response != REP_PROTOCOL_DONE) {
3120                 return (scf_set_error(proto_error(response.rpr_response)));
3121         }
3122 
3123         return (response.rpr_response == REP_PROTOCOL_SUCCESS) ?
3124             SCF_SUCCESS : SCF_COMPLETE;
3125 }
3126 
3127 int scf_snapshot_get_base_snaplevel(const scf_snapshot_t *base,
3128     scf_snaplevel_t *out)
3129 {
3130         return (snaplevel_next(&base->rd_d, out));
3131 }
3132 
3133 int scf_snaplevel_get_next_snaplevel(const scf_snaplevel_t *base,
3134     scf_snaplevel_t *out)
3135 {
3136         return (snaplevel_next(&base->rd_d, out));
3137 }
3138 
3139 /*
3140  * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
3141  * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
3142  */
3143 scf_propertygroup_t *
3144 scf_pg_create(scf_handle_t *handle)
3145 {
3146         scf_propertygroup_t *ret;
3147         ret = uu_zalloc(sizeof (*ret));
3148         if (ret != NULL) {
3149                 if (datael_init(&ret->rd_d, handle,
3150                     REP_PROTOCOL_ENTITY_PROPERTYGRP) == -1) {
3151                         uu_free(ret);
3152                         return (NULL);
3153                 }
3154         } else {
3155                 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
3156         }
3157 
3158         return (ret);
3159 }
3160 
3161 scf_handle_t *
3162 scf_pg_handle(const scf_propertygroup_t *val)
3163 {
3164         return (datael_handle(&val->rd_d));
3165 }
3166 
3167 void
3168 scf_pg_destroy(scf_propertygroup_t *val)
3169 {
3170         if (val == NULL)
3171                 return;
3172 
3173         datael_destroy(&val->rd_d);
3174         uu_free(val);
3175 }
3176 
3177 ssize_t
3178 scf_pg_get_name(const scf_propertygroup_t *pg,  char *out, size_t len)
3179 {
3180         return (datael_get_name(&pg->rd_d, out, len, RP_ENTITY_NAME_NAME));
3181 }
3182 
3183 ssize_t
3184 scf_pg_get_type(const scf_propertygroup_t *pg,  char *out, size_t len)
3185 {
3186         return (datael_get_name(&pg->rd_d, out, len, RP_ENTITY_NAME_PGTYPE));
3187 }
3188 
3189 int
3190 scf_pg_get_flags(const scf_propertygroup_t *pg, uint32_t *out)
3191 {
3192         char buf[REP_PROTOCOL_NAME_LEN];
3193         ssize_t res;
3194 
3195         res = datael_get_name(&pg->rd_d, buf, sizeof (buf),
3196             RP_ENTITY_NAME_PGFLAGS);
3197 
3198         if (res == -1)
3199                 return (-1);
3200 
3201         if (uu_strtouint(buf, out, sizeof (*out), 0, 0, UINT32_MAX) == -1)
3202                 return (scf_set_error(SCF_ERROR_INTERNAL));
3203 
3204         return (0);
3205 }
3206 
3207 static int
3208 datael_update(scf_datael_t *dp)
3209 {
3210         scf_handle_t *h = dp->rd_handle;
3211 
3212         struct rep_protocol_entity_update request;
3213         struct rep_protocol_response response;
3214 
3215         int r;
3216 
3217         (void) pthread_mutex_lock(&h->rh_lock);
3218         request.rpr_request = REP_PROTOCOL_ENTITY_UPDATE;
3219         request.rpr_entityid = dp->rd_entity;
3220 
3221         datael_finish_reset(dp);
3222         request.rpr_changeid = handle_next_changeid(h);
3223 
3224         r = make_door_call(h, &request, sizeof (request),
3225             &response, sizeof (response));
3226         (void) pthread_mutex_unlock(&h->rh_lock);
3227 
3228         if (r < 0)
3229                 DOOR_ERRORS_BLOCK(r);
3230 
3231         /*
3232          * This should never happen but if it does something has
3233          * gone terribly wrong and we should abort.
3234          */
3235         if (response.rpr_response == REP_PROTOCOL_FAIL_BAD_REQUEST)
3236                 abort();
3237 
3238         if (response.rpr_response != REP_PROTOCOL_SUCCESS &&
3239             response.rpr_response != REP_PROTOCOL_DONE) {
3240                 return (scf_set_error(proto_error(response.rpr_response)));
3241         }
3242 
3243         return (response.rpr_response == REP_PROTOCOL_SUCCESS) ?
3244             SCF_SUCCESS : SCF_COMPLETE;
3245 }
3246 
3247 int
3248 scf_pg_update(scf_propertygroup_t *pg)
3249 {
3250         return (datael_update(&pg->rd_d));
3251 }
3252 
3253 int
3254 scf_snapshot_update(scf_snapshot_t *snap)
3255 {
3256         return (datael_update(&snap->rd_d));
3257 }
3258 
3259 int
3260 _scf_pg_wait(scf_propertygroup_t *pg, int timeout)
3261 {
3262         scf_handle_t *h = pg->rd_d.rd_handle;
3263 
3264         struct rep_protocol_propertygrp_request request;
3265         struct rep_protocol_response response;
3266 
3267         struct pollfd pollfd;
3268 
3269         int r;
3270 
3271         (void) pthread_mutex_lock(&h->rh_lock);
3272         request.rpr_request = REP_PROTOCOL_PROPERTYGRP_SETUP_WAIT;
3273         request.rpr_entityid = pg->rd_d.rd_entity;
3274 
3275         datael_finish_reset(&pg->rd_d);
3276         if (!handle_is_bound(h)) {
3277                 (void) pthread_mutex_unlock(&h->rh_lock);
3278                 return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN));
3279         }
3280         r = make_door_call_retfd(h->rh_doorfd, &request, sizeof (request),
3281             &response, sizeof (response), &pollfd.fd);
3282         (void) pthread_mutex_unlock(&h->rh_lock);
3283 
3284         if (r < 0)
3285                 DOOR_ERRORS_BLOCK(r);
3286 
3287         assert((response.rpr_response == REP_PROTOCOL_SUCCESS) ==
3288             (pollfd.fd != -1));
3289 
3290         if (response.rpr_response == REP_PROTOCOL_FAIL_NOT_LATEST)
3291                 return (SCF_SUCCESS);
3292 
3293         if (response.rpr_response != REP_PROTOCOL_SUCCESS)
3294                 return (scf_set_error(proto_error(response.rpr_response)));
3295 
3296         pollfd.events = 0;
3297         pollfd.revents = 0;
3298 
3299         r = poll(&pollfd, 1, timeout * MILLISEC);
3300 
3301         (void) close(pollfd.fd);
3302         return (pollfd.revents ? SCF_SUCCESS : SCF_COMPLETE);
3303 }
3304 
3305 static int
3306 scf_notify_add_pattern(scf_handle_t *h, int type, const char *name)
3307 {
3308         struct rep_protocol_notify_request request;
3309         struct rep_protocol_response response;
3310         int r;
3311 
3312         (void) pthread_mutex_lock(&h->rh_lock);
3313         request.rpr_request = REP_PROTOCOL_CLIENT_ADD_NOTIFY;
3314         request.rpr_type = type;
3315         (void) strlcpy(request.rpr_pattern, name, sizeof (request.rpr_pattern));
3316 
3317         r = make_door_call(h, &request, sizeof (request),
3318             &response, sizeof (response));
3319         (void) pthread_mutex_unlock(&h->rh_lock);
3320 
3321         if (r < 0)
3322                 DOOR_ERRORS_BLOCK(r);
3323 
3324         if (response.rpr_response != REP_PROTOCOL_SUCCESS)
3325                 return (scf_set_error(proto_error(response.rpr_response)));
3326 
3327         return (SCF_SUCCESS);
3328 }
3329 
3330 int
3331 _scf_notify_add_pgname(scf_handle_t *h, const char *name)
3332 {
3333         return (scf_notify_add_pattern(h, REP_PROTOCOL_NOTIFY_PGNAME, name));
3334 }
3335 
3336 int
3337 _scf_notify_add_pgtype(scf_handle_t *h, const char *type)
3338 {
3339         return (scf_notify_add_pattern(h, REP_PROTOCOL_NOTIFY_PGTYPE, type));
3340 }
3341 
3342 int
3343 _scf_notify_wait(scf_propertygroup_t *pg, char *out, size_t sz)
3344 {
3345         struct rep_protocol_wait_request request;
3346         struct rep_protocol_fmri_response response;
3347 
3348         scf_handle_t *h = pg->rd_d.rd_handle;
3349         int dummy;
3350         int fd;
3351         int r;
3352 
3353         (void) pthread_mutex_lock(&h->rh_lock);
3354         datael_finish_reset(&pg->rd_d);
3355         if (!handle_is_bound(h)) {
3356                 (void) pthread_mutex_unlock(&h->rh_lock);
3357                 return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN));
3358         }
3359         fd = h->rh_doorfd;
3360         ++h->rh_fd_users;
3361         assert(h->rh_fd_users > 0);
3362 
3363         request.rpr_request = REP_PROTOCOL_CLIENT_WAIT;
3364         request.rpr_entityid = pg->rd_d.rd_entity;
3365         (void) pthread_mutex_unlock(&h->rh_lock);
3366 
3367         r = make_door_call_retfd(fd, &request, sizeof (request),
3368             &response, sizeof (response), &dummy);
3369 
3370         (void) pthread_mutex_lock(&h->rh_lock);
3371         assert(h->rh_fd_users > 0);
3372         if (--h->rh_fd_users == 0) {
3373                 (void) pthread_cond_broadcast(&h->rh_cv);
3374                 /*
3375                  * check for a delayed close, now that there are no other
3376                  * users.
3377                  */
3378                 if (h->rh_doorfd_old != -1) {
3379                         assert(h->rh_doorfd == -1);
3380                         assert(fd == h->rh_doorfd_old);
3381                         (void) close(h->rh_doorfd_old);
3382                         h->rh_doorfd_old = -1;
3383                 }
3384         }
3385         handle_unrefed(h);                      /* drops h->rh_lock */
3386 
3387         if (r < 0)
3388                 DOOR_ERRORS_BLOCK(r);
3389 
3390         if (response.rpr_response == REP_PROTOCOL_DONE)
3391                 return (scf_set_error(SCF_ERROR_NOT_SET));
3392 
3393         if (response.rpr_response != REP_PROTOCOL_SUCCESS)
3394                 return (scf_set_error(proto_error(response.rpr_response)));
3395 
3396         /* the following will be non-zero for delete notifications */
3397         return (strlcpy(out, response.rpr_fmri, sz));
3398 }
3399 
3400 static int
3401 _scf_snapshot_take(scf_instance_t *inst, const char *name,
3402     scf_snapshot_t *snap, int flags)
3403 {
3404         scf_handle_t *h = inst->rd_d.rd_handle;
3405 
3406         struct rep_protocol_snapshot_take request;
3407         struct rep_protocol_response response;
3408 
3409         int r;
3410 
3411         if (h != snap->rd_d.rd_handle)
3412                 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
3413 
3414         if (strlcpy(request.rpr_name, (name != NULL)? name : "",
3415             sizeof (request.rpr_name)) >= sizeof (request.rpr_name))
3416                 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
3417 
3418         (void) pthread_mutex_lock(&h->rh_lock);
3419         request.rpr_request = REP_PROTOCOL_SNAPSHOT_TAKE;
3420         request.rpr_entityid_src = inst->rd_d.rd_entity;
3421         request.rpr_entityid_dest = snap->rd_d.rd_entity;
3422         request.rpr_flags = flags;
3423 
3424         datael_finish_reset(&inst->rd_d);
3425         datael_finish_reset(&snap->rd_d);
3426 
3427         r = make_door_call(h, &request, sizeof (request),
3428             &response, sizeof (response));
3429         (void) pthread_mutex_unlock(&h->rh_lock);
3430 
3431         if (r < 0)
3432                 DOOR_ERRORS_BLOCK(r);
3433 
3434         if (response.rpr_response != REP_PROTOCOL_SUCCESS)
3435                 return (scf_set_error(proto_error(response.rpr_response)));
3436 
3437         return (SCF_SUCCESS);
3438 }
3439 
3440 int
3441 _scf_snapshot_take_new_named(scf_instance_t *inst,
3442     const char *svcname, const char *instname, const char *snapname,
3443     scf_snapshot_t *snap)
3444 {
3445         scf_handle_t *h = inst->rd_d.rd_handle;
3446 
3447         struct rep_protocol_snapshot_take_named request;
3448         struct rep_protocol_response response;
3449 
3450         int r;
3451 
3452         if (h != snap->rd_d.rd_handle)
3453                 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
3454 
3455         if (strlcpy(request.rpr_svcname, svcname,
3456             sizeof (request.rpr_svcname)) >= sizeof (request.rpr_svcname))
3457                 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
3458 
3459         if (strlcpy(request.rpr_instname, instname,
3460             sizeof (request.rpr_instname)) >= sizeof (request.rpr_instname))
3461                 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
3462 
3463         if (strlcpy(request.rpr_name, snapname,
3464             sizeof (request.rpr_name)) >= sizeof (request.rpr_name))
3465                 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
3466 
3467         (void) pthread_mutex_lock(&h->rh_lock);
3468         request.rpr_request = REP_PROTOCOL_SNAPSHOT_TAKE_NAMED;
3469         request.rpr_entityid_src = inst->rd_d.rd_entity;
3470         request.rpr_entityid_dest = snap->rd_d.rd_entity;
3471 
3472         datael_finish_reset(&inst->rd_d);
3473         datael_finish_reset(&snap->rd_d);
3474 
3475         r = make_door_call(h, &request, sizeof (request),
3476             &response, sizeof (response));
3477         (void) pthread_mutex_unlock(&h->rh_lock);
3478 
3479         if (r < 0)
3480                 DOOR_ERRORS_BLOCK(r);
3481 
3482         if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
3483                 assert(response.rpr_response !=
3484                     REP_PROTOCOL_FAIL_TYPE_MISMATCH);
3485                 return (scf_set_error(proto_error(response.rpr_response)));
3486         }
3487 
3488         return (SCF_SUCCESS);
3489 }
3490 
3491 int
3492 _scf_snapshot_take_new(scf_instance_t *inst, const char *name,
3493     scf_snapshot_t *snap)
3494 {
3495         return (_scf_snapshot_take(inst, name, snap, REP_SNAPSHOT_NEW));
3496 }
3497 
3498 int
3499 _scf_snapshot_take_attach(scf_instance_t *inst, scf_snapshot_t *snap)
3500 {
3501         return (_scf_snapshot_take(inst, NULL, snap, REP_SNAPSHOT_ATTACH));
3502 }
3503 
3504 int
3505 _scf_snapshot_attach(scf_snapshot_t *src, scf_snapshot_t *dest)
3506 {
3507         scf_handle_t *h = dest->rd_d.rd_handle;
3508 
3509         struct rep_protocol_snapshot_attach request;
3510         struct rep_protocol_response response;
3511 
3512         int r;
3513 
3514         if (h != src->rd_d.rd_handle)
3515                 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
3516 
3517         (void) pthread_mutex_lock(&h->rh_lock);
3518         request.rpr_request = REP_PROTOCOL_SNAPSHOT_ATTACH;
3519         request.rpr_entityid_src = src->rd_d.rd_entity;
3520         request.rpr_entityid_dest = dest->rd_d.rd_entity;
3521 
3522         datael_finish_reset(&src->rd_d);
3523         datael_finish_reset(&dest->rd_d);
3524 
3525         r = make_door_call(h, &request, sizeof (request),
3526             &response, sizeof (response));
3527         (void) pthread_mutex_unlock(&h->rh_lock);
3528 
3529         if (r < 0)
3530                 DOOR_ERRORS_BLOCK(r);
3531 
3532         if (response.rpr_response != REP_PROTOCOL_SUCCESS)
3533                 return (scf_set_error(proto_error(response.rpr_response)));
3534 
3535         return (SCF_SUCCESS);
3536 }
3537 
3538 /*
3539  * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
3540  * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
3541  */
3542 scf_property_t *
3543 scf_property_create(scf_handle_t *handle)
3544 {
3545         scf_property_t *ret;
3546         ret = uu_zalloc(sizeof (*ret));
3547         if (ret != NULL) {
3548                 if (datael_init(&ret->rd_d, handle,
3549                     REP_PROTOCOL_ENTITY_PROPERTY) == -1) {
3550                         uu_free(ret);
3551                         return (NULL);
3552                 }
3553         } else {
3554                 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
3555         }
3556 
3557         return (ret);
3558 }
3559 
3560 scf_handle_t *
3561 scf_property_handle(const scf_property_t *val)
3562 {
3563         return (datael_handle(&val->rd_d));
3564 }
3565 
3566 void
3567 scf_property_destroy(scf_property_t *val)
3568 {
3569         if (val == NULL)
3570                 return;
3571 
3572         datael_destroy(&val->rd_d);
3573         uu_free(val);
3574 }
3575 
3576 static int
3577 property_type_locked(const scf_property_t *prop,
3578     rep_protocol_value_type_t *out)
3579 {
3580         scf_handle_t *h = prop->rd_d.rd_handle;
3581 
3582         struct rep_protocol_property_request request;
3583         struct rep_protocol_integer_response response;
3584 
3585         int r;
3586 
3587         assert(MUTEX_HELD(&h->rh_lock));
3588 
3589         request.rpr_request = REP_PROTOCOL_PROPERTY_GET_TYPE;
3590         request.rpr_entityid = prop->rd_d.rd_entity;
3591 
3592         datael_finish_reset(&prop->rd_d);
3593         r = make_door_call(h, &request, sizeof (request),
3594             &response, sizeof (response));
3595 
3596         if (r < 0)
3597                 DOOR_ERRORS_BLOCK(r);
3598 
3599         if (response.rpr_response != REP_PROTOCOL_SUCCESS ||
3600             r < sizeof (response)) {
3601                 return (scf_set_error(proto_error(response.rpr_response)));
3602         }
3603         *out = response.rpr_value;
3604         return (SCF_SUCCESS);
3605 }
3606 
3607 int
3608 scf_property_type(const scf_property_t *prop, scf_type_t *out)
3609 {
3610         scf_handle_t *h = prop->rd_d.rd_handle;
3611         rep_protocol_value_type_t out_raw;
3612         int ret;
3613 
3614         (void) pthread_mutex_lock(&h->rh_lock);
3615         ret = property_type_locked(prop, &out_raw);
3616         (void) pthread_mutex_unlock(&h->rh_lock);
3617 
3618         if (ret == SCF_SUCCESS)
3619                 *out = scf_protocol_type_to_type(out_raw);
3620 
3621         return (ret);
3622 }
3623 
3624 int
3625 scf_property_is_type(const scf_property_t *prop, scf_type_t base_arg)
3626 {
3627         scf_handle_t *h = prop->rd_d.rd_handle;
3628         rep_protocol_value_type_t base = scf_type_to_protocol_type(base_arg);
3629         rep_protocol_value_type_t type;
3630         int ret;
3631 
3632         if (base == REP_PROTOCOL_TYPE_INVALID)
3633                 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
3634 
3635         (void) pthread_mutex_lock(&h->rh_lock);
3636         ret = property_type_locked(prop, &type);
3637         (void) pthread_mutex_unlock(&h->rh_lock);
3638 
3639         if (ret == SCF_SUCCESS) {
3640                 if (!scf_is_compatible_protocol_type(base, type))
3641                         return (scf_set_error(SCF_ERROR_TYPE_MISMATCH));
3642         }
3643         return (ret);
3644 }
3645 
3646 int
3647 scf_is_compatible_type(scf_type_t base_arg, scf_type_t type_arg)
3648 {
3649         rep_protocol_value_type_t base = scf_type_to_protocol_type(base_arg);
3650         rep_protocol_value_type_t type = scf_type_to_protocol_type(type_arg);
3651 
3652         if (base == REP_PROTOCOL_TYPE_INVALID ||
3653             type == REP_PROTOCOL_TYPE_INVALID)
3654                 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
3655 
3656         if (!scf_is_compatible_protocol_type(base, type))
3657                 return (scf_set_error(SCF_ERROR_TYPE_MISMATCH));
3658 
3659         return (SCF_SUCCESS);
3660 }
3661 
3662 ssize_t
3663 scf_property_get_name(const scf_property_t *prop, char *out, size_t len)
3664 {
3665         return (datael_get_name(&prop->rd_d, out, len, RP_ENTITY_NAME_NAME));
3666 }
3667 
3668 /*
3669  * transaction functions
3670  */
3671 
3672 /*
3673  * Fails with _NO_MEMORY, _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED,
3674  * _INTERNAL (bad server response or id in use), or _NO_RESOURCES.
3675  */
3676 scf_transaction_t *
3677 scf_transaction_create(scf_handle_t *handle)
3678 {
3679         scf_transaction_t *ret;
3680 
3681         ret = uu_zalloc(sizeof (scf_transaction_t));
3682         if (ret == NULL) {
3683                 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
3684                 return (NULL);
3685         }
3686         if (datael_init(&ret->tran_pg.rd_d, handle,
3687             REP_PROTOCOL_ENTITY_PROPERTYGRP) == -1) {
3688                 uu_free(ret);
3689                 return (NULL);                  /* error already set */
3690         }
3691         ret->tran_state = TRAN_STATE_NEW;
3692         ret->tran_props = uu_list_create(tran_entry_pool, ret, UU_LIST_SORTED);
3693         if (ret->tran_props == NULL) {
3694                 datael_destroy(&ret->tran_pg.rd_d);
3695                 uu_free(ret);
3696                 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
3697                 return (NULL);
3698         }
3699 
3700         return (ret);
3701 }
3702 
3703 scf_handle_t *
3704 scf_transaction_handle(const scf_transaction_t *val)
3705 {
3706         return (handle_get(val->tran_pg.rd_d.rd_handle));
3707 }
3708 
3709 int
3710 scf_transaction_start(scf_transaction_t *tran, scf_propertygroup_t *pg)
3711 {
3712         scf_handle_t *h = tran->tran_pg.rd_d.rd_handle;
3713 
3714         struct rep_protocol_transaction_start request;
3715         struct rep_protocol_response response;
3716         int r;
3717 
3718         if (h != pg->rd_d.rd_handle)
3719                 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
3720 
3721         (void) pthread_mutex_lock(&h->rh_lock);
3722         if (tran->tran_state != TRAN_STATE_NEW) {
3723                 (void) pthread_mutex_unlock(&h->rh_lock);
3724                 return (scf_set_error(SCF_ERROR_IN_USE));
3725         }
3726         request.rpr_request = REP_PROTOCOL_PROPERTYGRP_TX_START;
3727         request.rpr_entityid_tx = tran->tran_pg.rd_d.rd_entity;
3728         request.rpr_entityid = pg->rd_d.rd_entity;
3729 
3730         datael_finish_reset(&tran->tran_pg.rd_d);
3731         datael_finish_reset(&pg->rd_d);
3732 
3733         r = make_door_call(h, &request, sizeof (request),
3734             &response, sizeof (response));
3735 
3736         if (r < 0) {
3737                 (void) pthread_mutex_unlock(&h->rh_lock);
3738                 DOOR_ERRORS_BLOCK(r);
3739         }
3740 
3741         /* r < sizeof (response) cannot happen because sizeof (response) == 4 */
3742 
3743         if (response.rpr_response != REP_PROTOCOL_SUCCESS ||
3744             r < sizeof (response)) {
3745                 (void) pthread_mutex_unlock(&h->rh_lock);
3746                 return (scf_set_error(proto_error(response.rpr_response)));
3747         }
3748 
3749         tran->tran_state = TRAN_STATE_SETUP;
3750         tran->tran_invalid = 0;
3751         (void) pthread_mutex_unlock(&h->rh_lock);
3752         return (SCF_SUCCESS);
3753 }
3754 
3755 static void
3756 entry_invalidate(scf_transaction_entry_t *cur, int and_destroy,
3757     int and_reset_value)
3758 {
3759         scf_value_t *v, *next;
3760         scf_transaction_t *tx;
3761         scf_handle_t *h = cur->entry_handle;
3762 
3763         assert(MUTEX_HELD(&h->rh_lock));
3764 
3765         if ((tx = cur->entry_tx) != NULL) {
3766                 tx->tran_invalid = 1;
3767                 uu_list_remove(tx->tran_props, cur);
3768                 cur->entry_tx = NULL;
3769         }
3770 
3771         cur->entry_property = NULL;
3772         cur->entry_state = ENTRY_STATE_INVALID;
3773         cur->entry_action = REP_PROTOCOL_TX_ENTRY_INVALID;
3774         cur->entry_type = REP_PROTOCOL_TYPE_INVALID;
3775 
3776         for (v = cur->entry_head; v != NULL; v = next) {
3777                 next = v->value_next;
3778                 v->value_tx = NULL;
3779                 v->value_next = NULL;
3780                 if (and_destroy || and_reset_value)
3781                         scf_value_reset_locked(v, and_destroy);
3782         }
3783         cur->entry_head = NULL;
3784         cur->entry_tail = NULL;
3785 }
3786 
3787 static void
3788 entry_destroy_locked(scf_transaction_entry_t *entry)
3789 {
3790         scf_handle_t *h = entry->entry_handle;
3791 
3792         assert(MUTEX_HELD(&h->rh_lock));
3793 
3794         entry_invalidate(entry, 0, 0);
3795 
3796         entry->entry_handle = NULL;
3797         assert(h->rh_entries > 0);
3798         --h->rh_entries;
3799         --h->rh_extrefs;
3800         uu_list_node_fini(entry, &entry->entry_link, tran_entry_pool);
3801         uu_free(entry);
3802 }
3803 
3804 /*
3805  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
3806  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
3807  * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
3808  */
3809 static int
3810 transaction_add(scf_transaction_t *tran, scf_transaction_entry_t *entry,
3811     enum rep_protocol_transaction_action action,
3812     const char *prop, rep_protocol_value_type_t type)
3813 {
3814         scf_handle_t *h = tran->tran_pg.rd_d.rd_handle;
3815         scf_transaction_entry_t *old;
3816         scf_property_t *prop_p;
3817         rep_protocol_value_type_t oldtype;
3818         scf_error_t error = SCF_ERROR_NONE;
3819         int ret;
3820         uu_list_index_t idx;
3821 
3822         if (h != entry->entry_handle)
3823                 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
3824 
3825         if (action == REP_PROTOCOL_TX_ENTRY_DELETE)
3826                 assert(type == REP_PROTOCOL_TYPE_INVALID);
3827         else if (type == REP_PROTOCOL_TYPE_INVALID)
3828                 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
3829 
3830         prop_p = HANDLE_HOLD_PROPERTY(h);
3831 
3832         (void) pthread_mutex_lock(&h->rh_lock);
3833         if (tran->tran_state != TRAN_STATE_SETUP) {
3834                 error = SCF_ERROR_NOT_SET;
3835                 goto error;
3836         }
3837         if (tran->tran_invalid) {
3838                 error = SCF_ERROR_NOT_SET;
3839                 goto error;
3840         }
3841 
3842         if (entry->entry_state != ENTRY_STATE_INVALID)
3843                 entry_invalidate(entry, 0, 0);
3844 
3845         old = uu_list_find(tran->tran_props, &prop, NULL, &idx);
3846         if (old != NULL) {
3847                 error = SCF_ERROR_IN_USE;
3848                 goto error;
3849         }
3850 
3851         ret = datael_get_child_locked(&tran->tran_pg.rd_d, prop,
3852             REP_PROTOCOL_ENTITY_PROPERTY, &prop_p->rd_d);
3853         if (ret == -1 && (error = scf_error()) != SCF_ERROR_NOT_FOUND) {
3854                 goto error;
3855         }
3856 
3857         switch (action) {
3858         case REP_PROTOCOL_TX_ENTRY_DELETE:
3859                 if (ret == -1) {
3860                         error = SCF_ERROR_NOT_FOUND;
3861                         goto error;
3862                 }
3863                 break;
3864         case REP_PROTOCOL_TX_ENTRY_NEW:
3865                 if (ret != -1) {
3866                         error = SCF_ERROR_EXISTS;
3867                         goto error;
3868                 }
3869                 break;
3870 
3871         case REP_PROTOCOL_TX_ENTRY_CLEAR:
3872         case REP_PROTOCOL_TX_ENTRY_REPLACE:
3873                 if (ret == -1) {
3874                         error = SCF_ERROR_NOT_FOUND;
3875                         goto error;
3876                 }
3877                 if (action == REP_PROTOCOL_TX_ENTRY_CLEAR) {
3878                         if (property_type_locked(prop_p, &oldtype) == -1) {
3879                                 error = scf_error();
3880                                 goto error;
3881                         }
3882                         if (oldtype != type) {
3883                                 error = SCF_ERROR_TYPE_MISMATCH;
3884                                 goto error;
3885                         }
3886                 }
3887                 break;
3888         default:
3889                 assert(0);
3890                 abort();
3891         }
3892 
3893         (void) strlcpy(entry->entry_namebuf, prop,
3894             sizeof (entry->entry_namebuf));
3895         entry->entry_property = entry->entry_namebuf;
3896         entry->entry_action = action;
3897         entry->entry_type = type;
3898 
3899         entry->entry_state = ENTRY_STATE_IN_TX_ACTION;
3900         entry->entry_tx = tran;
3901         uu_list_insert(tran->tran_props, entry, idx);
3902 
3903         (void) pthread_mutex_unlock(&h->rh_lock);
3904 
3905         HANDLE_RELE_PROPERTY(h);
3906 
3907         return (SCF_SUCCESS);
3908 
3909 error:
3910         (void) pthread_mutex_unlock(&h->rh_lock);
3911 
3912         HANDLE_RELE_PROPERTY(h);
3913 
3914         return (scf_set_error(error));
3915 }
3916 
3917 /*
3918  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
3919  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
3920  * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
3921  */
3922 int
3923 scf_transaction_property_new(scf_transaction_t *tx,
3924     scf_transaction_entry_t *entry, const char *prop, scf_type_t type)
3925 {
3926         return (transaction_add(tx, entry, REP_PROTOCOL_TX_ENTRY_NEW,
3927             prop, scf_type_to_protocol_type(type)));
3928 }
3929 
3930 /*
3931  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
3932  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
3933  * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
3934  */
3935 int
3936 scf_transaction_property_change(scf_transaction_t *tx,
3937     scf_transaction_entry_t *entry, const char *prop, scf_type_t type)
3938 {
3939         return (transaction_add(tx, entry, REP_PROTOCOL_TX_ENTRY_CLEAR,
3940             prop, scf_type_to_protocol_type(type)));
3941 }
3942 
3943 /*
3944  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
3945  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
3946  * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
3947  */
3948 int
3949 scf_transaction_property_change_type(scf_transaction_t *tx,
3950     scf_transaction_entry_t *entry, const char *prop, scf_type_t type)
3951 {
3952         return (transaction_add(tx, entry, REP_PROTOCOL_TX_ENTRY_REPLACE,
3953             prop, scf_type_to_protocol_type(type)));
3954 }
3955 
3956 /*
3957  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
3958  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
3959  * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
3960  */
3961 int
3962 scf_transaction_property_delete(scf_transaction_t *tx,
3963     scf_transaction_entry_t *entry, const char *prop)
3964 {
3965         return (transaction_add(tx, entry, REP_PROTOCOL_TX_ENTRY_DELETE,
3966             prop, REP_PROTOCOL_TYPE_INVALID));
3967 }
3968 
3969 #define BAD_SIZE (-1UL)
3970 
3971 static size_t
3972 commit_value(caddr_t data, scf_value_t *val, rep_protocol_value_type_t t)
3973 {
3974         size_t len;
3975 
3976         assert(val->value_type == t);
3977 
3978         if (t == REP_PROTOCOL_TYPE_OPAQUE) {
3979                 len = scf_opaque_encode(data, val->value_value,
3980                     val->value_size);
3981         } else {
3982                 if (data != NULL)
3983                         len = strlcpy(data, val->value_value,
3984                             REP_PROTOCOL_VALUE_LEN);
3985                 else
3986                         len = strlen(val->value_value);
3987                 if (len >= REP_PROTOCOL_VALUE_LEN)
3988                         return (BAD_SIZE);
3989         }
3990         return (len + 1);       /* count the '\0' */
3991 }
3992 
3993 static size_t
3994 commit_process(scf_transaction_entry_t *cur,
3995     struct rep_protocol_transaction_cmd *out)
3996 {
3997         scf_value_t *child;
3998         size_t sz = 0;
3999         size_t len;
4000         caddr_t data = (caddr_t)out->rptc_data;
4001         caddr_t val_data;
4002 
4003         if (out != NULL) {
4004                 len = strlcpy(data, cur->entry_property, REP_PROTOCOL_NAME_LEN);
4005 
4006                 out->rptc_action = cur->entry_action;
4007                 out->rptc_type = cur->entry_type;
4008                 out->rptc_name_len = len + 1;
4009         } else {
4010                 len = strlen(cur->entry_property);
4011         }
4012 
4013         if (len >= REP_PROTOCOL_NAME_LEN)
4014                 return (BAD_SIZE);
4015 
4016         len = TX_SIZE(len + 1);
4017 
4018         sz += len;
4019         val_data = data + len;
4020 
4021         for (child = cur->entry_head; child != NULL;
4022             child = child->value_next) {
4023                 assert(cur->entry_action != REP_PROTOCOL_TX_ENTRY_DELETE);
4024                 if (out != NULL) {
4025                         len = commit_value(val_data + sizeof (uint32_t), child,
4026                             cur->entry_type);
4027                         /* LINTED alignment */
4028                         *(uint32_t *)val_data = len;
4029                 } else
4030                         len = commit_value(NULL, child, cur->entry_type);
4031 
4032                 if (len == BAD_SIZE)
4033                         return (BAD_SIZE);
4034 
4035                 len += sizeof (uint32_t);
4036                 len = TX_SIZE(len);
4037 
4038                 sz += len;
4039                 val_data += len;
4040         }
4041 
4042         assert(val_data - data == sz);
4043 
4044         if (out != NULL)
4045                 out->rptc_size = REP_PROTOCOL_TRANSACTION_CMD_SIZE(sz);
4046 
4047         return (REP_PROTOCOL_TRANSACTION_CMD_SIZE(sz));
4048 }
4049 
4050 int
4051 scf_transaction_commit(scf_transaction_t *tran)
4052 {
4053         scf_handle_t *h = tran->tran_pg.rd_d.rd_handle;
4054 
4055         struct rep_protocol_transaction_commit *request;
4056         struct rep_protocol_response response;
4057         uintptr_t cmd;
4058         scf_transaction_entry_t *cur;
4059         size_t total, size;
4060         size_t request_size;
4061         size_t new_total;
4062         int r;
4063 
4064         (void) pthread_mutex_lock(&h->rh_lock);
4065         if (tran->tran_state != TRAN_STATE_SETUP ||
4066             tran->tran_invalid) {
4067                 (void) pthread_mutex_unlock(&h->rh_lock);
4068                 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4069         }
4070 
4071         total = 0;
4072         for (cur = uu_list_first(tran->tran_props); cur != NULL;
4073             cur = uu_list_next(tran->tran_props, cur)) {
4074                 size = commit_process(cur, NULL);
4075                 if (size == BAD_SIZE) {
4076                         (void) pthread_mutex_unlock(&h->rh_lock);
4077                         return (scf_set_error(SCF_ERROR_INTERNAL));
4078                 }
4079                 assert(TX_SIZE(size) == size);
4080                 total += size;
4081         }
4082 
4083         request_size = REP_PROTOCOL_TRANSACTION_COMMIT_SIZE(total);
4084         request = calloc(1, request_size);
4085         if (request == NULL) {
4086                 (void) pthread_mutex_unlock(&h->rh_lock);
4087                 return (scf_set_error(SCF_ERROR_NO_MEMORY));
4088         }
4089 
4090         request->rpr_request = REP_PROTOCOL_PROPERTYGRP_TX_COMMIT;
4091         request->rpr_entityid = tran->tran_pg.rd_d.rd_entity;
4092         request->rpr_size = request_size;
4093         cmd = (uintptr_t)request->rpr_cmd;
4094 
4095         datael_finish_reset(&tran->tran_pg.rd_d);
4096 
4097         new_total = 0;
4098         for (cur = uu_list_first(tran->tran_props); cur != NULL;
4099             cur = uu_list_next(tran->tran_props, cur)) {
4100                 size = commit_process(cur, (void *)cmd);
4101                 if (size == BAD_SIZE) {
4102                         (void) pthread_mutex_unlock(&h->rh_lock);
4103                         r = (scf_set_error(SCF_ERROR_INTERNAL));
4104                         goto out;
4105                 }
4106                 cmd += size;
4107                 new_total += size;
4108         }
4109         assert(new_total == total);
4110 
4111         r = make_door_call(h, request, request_size,
4112             &response, sizeof (response));
4113 
4114         if (r < 0) {
4115                 (void) pthread_mutex_unlock(&h->rh_lock);
4116                 DOOR_ERRORS_BLOCK(r);
4117         }
4118 
4119         if (response.rpr_response != REP_PROTOCOL_SUCCESS &&
4120             response.rpr_response != REP_PROTOCOL_FAIL_NOT_LATEST) {
4121                 (void) pthread_mutex_unlock(&h->rh_lock);
4122                 r = (scf_set_error(proto_error(response.rpr_response)));
4123                 goto out;
4124         }
4125 
4126         tran->tran_state = TRAN_STATE_COMMITTED;
4127         (void) pthread_mutex_unlock(&h->rh_lock);
4128         r = (response.rpr_response == REP_PROTOCOL_SUCCESS);
4129 
4130 out:
4131         free(request);
4132         return (r);
4133 }
4134 
4135 static void
4136 transaction_reset(scf_transaction_t *tran)
4137 {
4138         assert(MUTEX_HELD(&tran->tran_pg.rd_d.rd_handle->rh_lock));
4139 
4140         tran->tran_state = TRAN_STATE_NEW;
4141         datael_reset_locked(&tran->tran_pg.rd_d);
4142 }
4143 
4144 static void
4145 scf_transaction_reset_impl(scf_transaction_t *tran, int and_destroy,
4146     int and_reset_value)
4147 {
4148         scf_transaction_entry_t *cur;
4149         void *cookie;
4150 
4151         (void) pthread_mutex_lock(&tran->tran_pg.rd_d.rd_handle->rh_lock);
4152         cookie = NULL;
4153         while ((cur = uu_list_teardown(tran->tran_props, &cookie)) != NULL) {
4154                 cur->entry_tx = NULL;
4155 
4156                 assert(cur->entry_state == ENTRY_STATE_IN_TX_ACTION);
4157                 cur->entry_state = ENTRY_STATE_INVALID;
4158 
4159                 entry_invalidate(cur, and_destroy, and_reset_value);
4160                 if (and_destroy)
4161                         entry_destroy_locked(cur);
4162         }
4163         transaction_reset(tran);
4164         handle_unrefed(tran->tran_pg.rd_d.rd_handle);
4165 }
4166 
4167 void
4168 scf_transaction_reset(scf_transaction_t *tran)
4169 {
4170         scf_transaction_reset_impl(tran, 0, 0);
4171 }
4172 
4173 void
4174 scf_transaction_reset_all(scf_transaction_t *tran)
4175 {
4176         scf_transaction_reset_impl(tran, 0, 1);
4177 }
4178 
4179 void
4180 scf_transaction_destroy(scf_transaction_t *val)
4181 {
4182         if (val == NULL)
4183                 return;
4184 
4185         scf_transaction_reset(val);
4186 
4187         datael_destroy(&val->tran_pg.rd_d);
4188 
4189         uu_list_destroy(val->tran_props);
4190         uu_free(val);
4191 }
4192 
4193 void
4194 scf_transaction_destroy_children(scf_transaction_t *tran)
4195 {
4196         if (tran == NULL)
4197                 return;
4198 
4199         scf_transaction_reset_impl(tran, 1, 0);
4200 }
4201 
4202 scf_transaction_entry_t *
4203 scf_entry_create(scf_handle_t *h)
4204 {
4205         scf_transaction_entry_t *ret;
4206 
4207         if (h == NULL) {
4208                 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
4209                 return (NULL);
4210         }
4211 
4212         ret = uu_zalloc(sizeof (scf_transaction_entry_t));
4213         if (ret == NULL) {
4214                 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
4215                 return (NULL);
4216         }
4217         ret->entry_action = REP_PROTOCOL_TX_ENTRY_INVALID;
4218         ret->entry_handle = h;
4219 
4220         (void) pthread_mutex_lock(&h->rh_lock);
4221         if (h->rh_flags & HANDLE_DEAD) {
4222                 (void) pthread_mutex_unlock(&h->rh_lock);
4223                 uu_free(ret);
4224                 (void) scf_set_error(SCF_ERROR_HANDLE_DESTROYED);
4225                 return (NULL);
4226         }
4227         h->rh_entries++;
4228         h->rh_extrefs++;
4229         (void) pthread_mutex_unlock(&h->rh_lock);
4230 
4231         uu_list_node_init(ret, &ret->entry_link, tran_entry_pool);
4232 
4233         return (ret);
4234 }
4235 
4236 scf_handle_t *
4237 scf_entry_handle(const scf_transaction_entry_t *val)
4238 {
4239         return (handle_get(val->entry_handle));
4240 }
4241 
4242 void
4243 scf_entry_reset(scf_transaction_entry_t *entry)
4244 {
4245         scf_handle_t *h = entry->entry_handle;
4246 
4247         (void) pthread_mutex_lock(&h->rh_lock);
4248         entry_invalidate(entry, 0, 0);
4249         (void) pthread_mutex_unlock(&h->rh_lock);
4250 }
4251 
4252 void
4253 scf_entry_destroy_children(scf_transaction_entry_t *entry)
4254 {
4255         scf_handle_t *h = entry->entry_handle;
4256 
4257         (void) pthread_mutex_lock(&h->rh_lock);
4258         entry_invalidate(entry, 1, 0);
4259         handle_unrefed(h);                      /* drops h->rh_lock */
4260 }
4261 
4262 void
4263 scf_entry_destroy(scf_transaction_entry_t *entry)
4264 {
4265         scf_handle_t *h;
4266 
4267         if (entry == NULL)
4268                 return;
4269 
4270         h = entry->entry_handle;
4271 
4272         (void) pthread_mutex_lock(&h->rh_lock);
4273         entry_destroy_locked(entry);
4274         handle_unrefed(h);                      /* drops h->rh_lock */
4275 }
4276 
4277 /*
4278  * Fails with
4279  *   _HANDLE_MISMATCH
4280  *   _NOT_SET - has not been added to a transaction
4281  *   _INTERNAL - entry is corrupt
4282  *   _INVALID_ARGUMENT - entry's transaction is not started or corrupt
4283  *                       entry is set to delete a property
4284  *                       v is reset or corrupt
4285  *   _TYPE_MISMATCH - entry & v's types aren't compatible
4286  *   _IN_USE - v has been added to another entry
4287  */
4288 int
4289 scf_entry_add_value(scf_transaction_entry_t *entry, scf_value_t *v)
4290 {
4291         scf_handle_t *h = entry->entry_handle;
4292 
4293         if (h != v->value_handle)
4294                 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
4295 
4296         (void) pthread_mutex_lock(&h->rh_lock);
4297 
4298         if (entry->entry_state == ENTRY_STATE_INVALID) {
4299                 (void) pthread_mutex_unlock(&h->rh_lock);
4300                 return (scf_set_error(SCF_ERROR_NOT_SET));
4301         }
4302 
4303         if (entry->entry_state != ENTRY_STATE_IN_TX_ACTION) {
4304                 (void) pthread_mutex_unlock(&h->rh_lock);
4305                 return (scf_set_error(SCF_ERROR_INTERNAL));
4306         }
4307 
4308         if (entry->entry_tx->tran_state != TRAN_STATE_SETUP) {
4309                 (void) pthread_mutex_unlock(&h->rh_lock);
4310                 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4311         }
4312 
4313         if (entry->entry_action == REP_PROTOCOL_TX_ENTRY_DELETE) {
4314                 (void) pthread_mutex_unlock(&h->rh_lock);
4315                 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4316         }
4317 
4318         if (v->value_type == REP_PROTOCOL_TYPE_INVALID) {
4319                 (void) pthread_mutex_unlock(&h->rh_lock);
4320                 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4321         }
4322 
4323         if (!scf_is_compatible_protocol_type(entry->entry_type,
4324             v->value_type)) {
4325                 (void) pthread_mutex_unlock(&h->rh_lock);
4326                 return (scf_set_error(SCF_ERROR_TYPE_MISMATCH));
4327         }
4328 
4329         if (v->value_tx != NULL) {
4330                 (void) pthread_mutex_unlock(&h->rh_lock);
4331                 return (scf_set_error(SCF_ERROR_IN_USE));
4332         }
4333 
4334         v->value_tx = entry;
4335         v->value_next = NULL;
4336         if (entry->entry_head == NULL) {
4337                 entry->entry_head = v;
4338                 entry->entry_tail = v;
4339         } else {
4340                 entry->entry_tail->value_next = v;
4341                 entry->entry_tail = v;
4342         }
4343 
4344         (void) pthread_mutex_unlock(&h->rh_lock);
4345 
4346         return (SCF_SUCCESS);
4347 }
4348 
4349 /*
4350  * value functions
4351  */
4352 scf_value_t *
4353 scf_value_create(scf_handle_t *h)
4354 {
4355         scf_value_t *ret;
4356 
4357         if (h == NULL) {
4358                 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
4359                 return (NULL);
4360         }
4361 
4362         ret = uu_zalloc(sizeof (*ret));
4363         if (ret != NULL) {
4364                 ret->value_type = REP_PROTOCOL_TYPE_INVALID;
4365                 ret->value_handle = h;
4366                 (void) pthread_mutex_lock(&h->rh_lock);
4367                 if (h->rh_flags & HANDLE_DEAD) {
4368                         (void) pthread_mutex_unlock(&h->rh_lock);
4369                         uu_free(ret);
4370                         (void) scf_set_error(SCF_ERROR_HANDLE_DESTROYED);
4371                         return (NULL);
4372                 }
4373                 h->rh_values++;
4374                 h->rh_extrefs++;
4375                 (void) pthread_mutex_unlock(&h->rh_lock);
4376         } else {
4377                 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
4378         }
4379 
4380         return (ret);
4381 }
4382 
4383 static void
4384 scf_value_reset_locked(scf_value_t *val, int and_destroy)
4385 {
4386         scf_value_t **curp;
4387         scf_transaction_entry_t *te;
4388 
4389         scf_handle_t *h = val->value_handle;
4390         assert(MUTEX_HELD(&h->rh_lock));
4391         if (val->value_tx != NULL) {
4392                 te = val->value_tx;
4393                 te->entry_tx->tran_invalid = 1;
4394 
4395                 val->value_tx = NULL;
4396 
4397                 for (curp = &te->entry_head; *curp != NULL;
4398                     curp = &(*curp)->value_next) {
4399                         if (*curp == val) {
4400                                 *curp = val->value_next;
4401                                 curp = NULL;
4402                                 break;
4403                         }
4404                 }
4405                 assert(curp == NULL);
4406         }
4407         val->value_type = REP_PROTOCOL_TYPE_INVALID;
4408 
4409         if (and_destroy) {
4410                 val->value_handle = NULL;
4411                 assert(h->rh_values > 0);
4412                 --h->rh_values;
4413                 --h->rh_extrefs;
4414                 uu_free(val);
4415         }
4416 }
4417 
4418 void
4419 scf_value_reset(scf_value_t *val)
4420 {
4421         scf_handle_t *h = val->value_handle;
4422 
4423         (void) pthread_mutex_lock(&h->rh_lock);
4424         scf_value_reset_locked(val, 0);
4425         (void) pthread_mutex_unlock(&h->rh_lock);
4426 }
4427 
4428 scf_handle_t *
4429 scf_value_handle(const scf_value_t *val)
4430 {
4431         return (handle_get(val->value_handle));
4432 }
4433 
4434 void
4435 scf_value_destroy(scf_value_t *val)
4436 {
4437         scf_handle_t *h;
4438 
4439         if (val == NULL)
4440                 return;
4441 
4442         h = val->value_handle;
4443 
4444         (void) pthread_mutex_lock(&h->rh_lock);
4445         scf_value_reset_locked(val, 1);
4446         handle_unrefed(h);                      /* drops h->rh_lock */
4447 }
4448 
4449 scf_type_t
4450 scf_value_base_type(const scf_value_t *val)
4451 {
4452         rep_protocol_value_type_t t, cur;
4453         scf_handle_t *h = val->value_handle;
4454 
4455         (void) pthread_mutex_lock(&h->rh_lock);
4456         t = val->value_type;
4457         (void) pthread_mutex_unlock(&h->rh_lock);
4458 
4459         for (;;) {
4460                 cur = scf_proto_underlying_type(t);
4461                 if (cur == t)
4462                         break;
4463                 t = cur;
4464         }
4465 
4466         return (scf_protocol_type_to_type(t));
4467 }
4468 
4469 scf_type_t
4470 scf_value_type(const scf_value_t *val)
4471 {
4472         rep_protocol_value_type_t t;
4473         scf_handle_t *h = val->value_handle;
4474 
4475         (void) pthread_mutex_lock(&h->rh_lock);
4476         t = val->value_type;
4477         (void) pthread_mutex_unlock(&h->rh_lock);
4478 
4479         return (scf_protocol_type_to_type(t));
4480 }
4481 
4482 int
4483 scf_value_is_type(const scf_value_t *val, scf_type_t base_arg)
4484 {
4485         rep_protocol_value_type_t t;
4486         rep_protocol_value_type_t base = scf_type_to_protocol_type(base_arg);
4487         scf_handle_t *h = val->value_handle;
4488 
4489         (void) pthread_mutex_lock(&h->rh_lock);
4490         t = val->value_type;
4491         (void) pthread_mutex_unlock(&h->rh_lock);
4492 
4493         if (t == REP_PROTOCOL_TYPE_INVALID)
4494                 return (scf_set_error(SCF_ERROR_NOT_SET));
4495         if (base == REP_PROTOCOL_TYPE_INVALID)
4496                 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4497         if (!scf_is_compatible_protocol_type(base, t))
4498                 return (scf_set_error(SCF_ERROR_TYPE_MISMATCH));
4499 
4500         return (SCF_SUCCESS);
4501 }
4502 
4503 /*
4504  * Fails with
4505  *   _NOT_SET - val is reset
4506  *   _TYPE_MISMATCH - val's type is not compatible with t
4507  */
4508 static int
4509 scf_value_check_type(const scf_value_t *val, rep_protocol_value_type_t t)
4510 {
4511         if (val->value_type == REP_PROTOCOL_TYPE_INVALID) {
4512                 (void) scf_set_error(SCF_ERROR_NOT_SET);
4513                 return (0);
4514         }
4515         if (!scf_is_compatible_protocol_type(t, val->value_type)) {
4516                 (void) scf_set_error(SCF_ERROR_TYPE_MISMATCH);
4517                 return (0);
4518         }
4519         return (1);
4520 }
4521 
4522 /*
4523  * Fails with
4524  *   _NOT_SET - val is reset
4525  *   _TYPE_MISMATCH - val is not _TYPE_BOOLEAN
4526  */
4527 int
4528 scf_value_get_boolean(const scf_value_t *val, uint8_t *out)
4529 {
4530         char c;
4531         scf_handle_t *h = val->value_handle;
4532         uint8_t o;
4533 
4534         (void) pthread_mutex_lock(&h->rh_lock);
4535         if (!scf_value_check_type(val, REP_PROTOCOL_TYPE_BOOLEAN)) {
4536                 (void) pthread_mutex_unlock(&h->rh_lock);
4537                 return (-1);
4538         }
4539 
4540         c = val->value_value[0];
4541         assert((c == '0' || c == '1') && val->value_value[1] == 0);
4542 
4543         o = (c != '0');
4544         (void) pthread_mutex_unlock(&h->rh_lock);
4545         if (out != NULL)
4546                 *out = o;
4547         return (SCF_SUCCESS);
4548 }
4549 
4550 int
4551 scf_value_get_count(const scf_value_t *val, uint64_t *out)
4552 {
4553         scf_handle_t *h = val->value_handle;
4554         uint64_t o;
4555 
4556         (void) pthread_mutex_lock(&h->rh_lock);
4557         if (!scf_value_check_type(val, REP_PROTOCOL_TYPE_COUNT)) {
4558                 (void) pthread_mutex_unlock(&h->rh_lock);
4559                 return (-1);
4560         }
4561 
4562         o = strtoull(val->value_value, NULL, 10);
4563         (void) pthread_mutex_unlock(&h->rh_lock);
4564         if (out != NULL)
4565                 *out = o;
4566         return (SCF_SUCCESS);
4567 }
4568 
4569 int
4570 scf_value_get_integer(const scf_value_t *val, int64_t *out)
4571 {
4572         scf_handle_t *h = val->value_handle;
4573         int64_t o;
4574 
4575         (void) pthread_mutex_lock(&h->rh_lock);
4576         if (!scf_value_check_type(val, REP_PROTOCOL_TYPE_INTEGER)) {
4577                 (void) pthread_mutex_unlock(&h->rh_lock);
4578                 return (-1);
4579         }
4580 
4581         o = strtoll(val->value_value, NULL, 10);
4582         (void) pthread_mutex_unlock(&h->rh_lock);
4583         if (out != NULL)
4584                 *out = o;
4585         return (SCF_SUCCESS);
4586 }
4587 
4588 int
4589 scf_value_get_time(const scf_value_t *val, int64_t *sec_out, int32_t *nsec_out)
4590 {
4591         scf_handle_t *h = val->value_handle;
4592         char *p;
4593         int64_t os;
4594         int32_t ons;
4595 
4596         (void) pthread_mutex_lock(&h->rh_lock);
4597         if (!scf_value_check_type(val, REP_PROTOCOL_TYPE_TIME)) {
4598                 (void) pthread_mutex_unlock(&h->rh_lock);
4599                 return (-1);
4600         }
4601 
4602         os = strtoll(val->value_value, &p, 10);
4603         if (*p == '.')
4604                 ons = strtoul(p + 1, NULL, 10);
4605         else
4606                 ons = 0;
4607         (void) pthread_mutex_unlock(&h->rh_lock);
4608         if (sec_out != NULL)
4609                 *sec_out = os;
4610         if (nsec_out != NULL)
4611                 *nsec_out = ons;
4612 
4613         return (SCF_SUCCESS);
4614 }
4615 
4616 /*
4617  * Fails with
4618  *   _NOT_SET - val is reset
4619  *   _TYPE_MISMATCH - val's type is not compatible with _TYPE_STRING.
4620  */
4621 ssize_t
4622 scf_value_get_astring(const scf_value_t *val, char *out, size_t len)
4623 {
4624         ssize_t ret;
4625         scf_handle_t *h = val->value_handle;
4626 
4627         (void) pthread_mutex_lock(&h->rh_lock);
4628         if (!scf_value_check_type(val, REP_PROTOCOL_TYPE_STRING)) {
4629                 (void) pthread_mutex_unlock(&h->rh_lock);
4630                 return ((ssize_t)-1);
4631         }
4632         ret = (ssize_t)strlcpy(out, val->value_value, len);
4633         (void) pthread_mutex_unlock(&h->rh_lock);
4634         return (ret);
4635 }
4636 
4637 ssize_t
4638 scf_value_get_ustring(const scf_value_t *val, char *out, size_t len)
4639 {
4640         ssize_t ret;
4641         scf_handle_t *h = val->value_handle;
4642 
4643         (void) pthread_mutex_lock(&h->rh_lock);
4644         if (!scf_value_check_type(val, REP_PROTOCOL_SUBTYPE_USTRING)) {
4645                 (void) pthread_mutex_unlock(&h->rh_lock);
4646                 return ((ssize_t)-1);
4647         }
4648         ret = (ssize_t)strlcpy(out, val->value_value, len);
4649         (void) pthread_mutex_unlock(&h->rh_lock);
4650         return (ret);
4651 }
4652 
4653 ssize_t
4654 scf_value_get_opaque(const scf_value_t *v, void *out, size_t len)
4655 {
4656         ssize_t ret;
4657         scf_handle_t *h = v->value_handle;
4658 
4659         (void) pthread_mutex_lock(&h->rh_lock);
4660         if (!scf_value_check_type(v, REP_PROTOCOL_TYPE_OPAQUE)) {
4661                 (void) pthread_mutex_unlock(&h->rh_lock);
4662                 return ((ssize_t)-1);
4663         }
4664         if (len > v->value_size)
4665                 len = v->value_size;
4666         ret = len;
4667 
4668         (void) memcpy(out, v->value_value, len);
4669         (void) pthread_mutex_unlock(&h->rh_lock);
4670         return (ret);
4671 }
4672 
4673 void
4674 scf_value_set_boolean(scf_value_t *v, uint8_t new)
4675 {
4676         scf_handle_t *h = v->value_handle;
4677 
4678         (void) pthread_mutex_lock(&h->rh_lock);
4679         scf_value_reset_locked(v, 0);
4680         v->value_type = REP_PROTOCOL_TYPE_BOOLEAN;
4681         (void) sprintf(v->value_value, "%d", (new != 0));
4682         (void) pthread_mutex_unlock(&h->rh_lock);
4683 }
4684 
4685 void
4686 scf_value_set_count(scf_value_t *v, uint64_t new)
4687 {
4688         scf_handle_t *h = v->value_handle;
4689 
4690         (void) pthread_mutex_lock(&h->rh_lock);
4691         scf_value_reset_locked(v, 0);
4692         v->value_type = REP_PROTOCOL_TYPE_COUNT;
4693         (void) sprintf(v->value_value, "%llu", (unsigned long long)new);
4694         (void) pthread_mutex_unlock(&h->rh_lock);
4695 }
4696 
4697 void
4698 scf_value_set_integer(scf_value_t *v, int64_t new)
4699 {
4700         scf_handle_t *h = v->value_handle;
4701 
4702         (void) pthread_mutex_lock(&h->rh_lock);
4703         scf_value_reset_locked(v, 0);
4704         v->value_type = REP_PROTOCOL_TYPE_INTEGER;
4705         (void) sprintf(v->value_value, "%lld", (long long)new);
4706         (void) pthread_mutex_unlock(&h->rh_lock);
4707 }
4708 
4709 int
4710 scf_value_set_time(scf_value_t *v, int64_t new_sec, int32_t new_nsec)
4711 {
4712         scf_handle_t *h = v->value_handle;
4713 
4714         (void) pthread_mutex_lock(&h->rh_lock);
4715         scf_value_reset_locked(v, 0);
4716         if (new_nsec < 0 || new_nsec >= NANOSEC) {
4717                 (void) pthread_mutex_unlock(&h->rh_lock);
4718                 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4719         }
4720         v->value_type = REP_PROTOCOL_TYPE_TIME;
4721         if (new_nsec == 0)
4722                 (void) sprintf(v->value_value, "%lld", (long long)new_sec);
4723         else
4724                 (void) sprintf(v->value_value, "%lld.%09u", (long long)new_sec,
4725                     (unsigned)new_nsec);
4726         (void) pthread_mutex_unlock(&h->rh_lock);
4727         return (0);
4728 }
4729 
4730 int
4731 scf_value_set_astring(scf_value_t *v, const char *new)
4732 {
4733         scf_handle_t *h = v->value_handle;
4734 
4735         (void) pthread_mutex_lock(&h->rh_lock);
4736         scf_value_reset_locked(v, 0);
4737         if (!scf_validate_encoded_value(REP_PROTOCOL_TYPE_STRING, new)) {
4738                 (void) pthread_mutex_unlock(&h->rh_lock);
4739                 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4740         }
4741         if (strlcpy(v->value_value, new, sizeof (v->value_value)) >=
4742             sizeof (v->value_value)) {
4743                 (void) pthread_mutex_unlock(&h->rh_lock);
4744                 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4745         }
4746         v->value_type = REP_PROTOCOL_TYPE_STRING;
4747         (void) pthread_mutex_unlock(&h->rh_lock);
4748         return (0);
4749 }
4750 
4751 int
4752 scf_value_set_ustring(scf_value_t *v, const char *new)
4753 {
4754         scf_handle_t *h = v->value_handle;
4755 
4756         (void) pthread_mutex_lock(&h->rh_lock);
4757         scf_value_reset_locked(v, 0);
4758         if (!scf_validate_encoded_value(REP_PROTOCOL_SUBTYPE_USTRING, new)) {
4759                 (void) pthread_mutex_unlock(&h->rh_lock);
4760                 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4761         }
4762         if (strlcpy(v->value_value, new, sizeof (v->value_value)) >=
4763             sizeof (v->value_value)) {
4764                 (void) pthread_mutex_unlock(&h->rh_lock);
4765                 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4766         }
4767         v->value_type = REP_PROTOCOL_SUBTYPE_USTRING;
4768         (void) pthread_mutex_unlock(&h->rh_lock);
4769         return (0);
4770 }
4771 
4772 int
4773 scf_value_set_opaque(scf_value_t *v, const void *new, size_t len)
4774 {
4775         scf_handle_t *h = v->value_handle;
4776 
4777         (void) pthread_mutex_lock(&h->rh_lock);
4778         scf_value_reset_locked(v, 0);
4779         if (len > sizeof (v->value_value)) {
4780                 (void) pthread_mutex_unlock(&h->rh_lock);
4781                 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4782         }
4783         (void) memcpy(v->value_value, new, len);
4784         v->value_size = len;
4785         v->value_type = REP_PROTOCOL_TYPE_OPAQUE;
4786         (void) pthread_mutex_unlock(&h->rh_lock);
4787         return (0);
4788 }
4789 
4790 /*
4791  * Fails with
4792  *   _NOT_SET - v_arg is reset
4793  *   _INTERNAL - v_arg is corrupt
4794  *
4795  * If t is not _TYPE_INVALID, fails with
4796  *   _TYPE_MISMATCH - v_arg's type is not compatible with t
4797  */
4798 static ssize_t
4799 scf_value_get_as_string_common(const scf_value_t *v_arg,
4800     rep_protocol_value_type_t t, char *buf, size_t bufsz)
4801 {
4802         scf_handle_t *h = v_arg->value_handle;
4803         scf_value_t v_s;
4804         scf_value_t *v = &v_s;
4805         ssize_t r;
4806         uint8_t b;
4807 
4808         (void) pthread_mutex_lock(&h->rh_lock);
4809         if (t != REP_PROTOCOL_TYPE_INVALID && !scf_value_check_type(v_arg, t)) {
4810                 (void) pthread_mutex_unlock(&h->rh_lock);
4811                 return (-1);
4812         }
4813 
4814         v_s = *v_arg;                   /* copy locally so we can unlock */
4815         h->rh_values++;                      /* keep the handle from going away */
4816         h->rh_extrefs++;
4817         (void) pthread_mutex_unlock(&h->rh_lock);
4818 
4819 
4820         switch (REP_PROTOCOL_BASE_TYPE(v->value_type)) {
4821         case REP_PROTOCOL_TYPE_BOOLEAN:
4822                 r = scf_value_get_boolean(v, &b);
4823                 assert(r == SCF_SUCCESS);
4824 
4825                 r = strlcpy(buf, b ? "true" : "false", bufsz);
4826                 break;
4827 
4828         case REP_PROTOCOL_TYPE_COUNT:
4829         case REP_PROTOCOL_TYPE_INTEGER:
4830         case REP_PROTOCOL_TYPE_TIME:
4831         case REP_PROTOCOL_TYPE_STRING:
4832                 r = strlcpy(buf, v->value_value, bufsz);
4833                 break;
4834 
4835         case REP_PROTOCOL_TYPE_OPAQUE:
4836                 /*
4837                  * Note that we only write out full hex bytes -- if they're
4838                  * short, and bufsz is even, we'll only fill (bufsz - 2) bytes
4839                  * with data.
4840                  */
4841                 if (bufsz > 0)
4842                         (void) scf_opaque_encode(buf, v->value_value,
4843                             MIN(v->value_size, (bufsz - 1)/2));
4844                 r = (v->value_size * 2);
4845                 break;
4846 
4847         case REP_PROTOCOL_TYPE_INVALID:
4848                 r = scf_set_error(SCF_ERROR_NOT_SET);
4849                 break;
4850 
4851         default:
4852                 r = (scf_set_error(SCF_ERROR_INTERNAL));
4853                 break;
4854         }
4855 
4856         (void) pthread_mutex_lock(&h->rh_lock);
4857         h->rh_values--;
4858         h->rh_extrefs--;
4859         handle_unrefed(h);
4860 
4861         return (r);
4862 }
4863 
4864 ssize_t
4865 scf_value_get_as_string(const scf_value_t *v, char *buf, size_t bufsz)
4866 {
4867         return (scf_value_get_as_string_common(v, REP_PROTOCOL_TYPE_INVALID,
4868             buf, bufsz));
4869 }
4870 
4871 ssize_t
4872 scf_value_get_as_string_typed(const scf_value_t *v, scf_type_t type,
4873     char *buf, size_t bufsz)
4874 {
4875         rep_protocol_value_type_t ty = scf_type_to_protocol_type(type);
4876         if (ty == REP_PROTOCOL_TYPE_INVALID)
4877                 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4878 
4879         return (scf_value_get_as_string_common(v, ty, buf, bufsz));
4880 }
4881 
4882 int
4883 scf_value_set_from_string(scf_value_t *v, scf_type_t type, const char *str)
4884 {
4885         scf_handle_t *h = v->value_handle;
4886         rep_protocol_value_type_t ty;
4887 
4888         switch (type) {
4889         case SCF_TYPE_BOOLEAN: {
4890                 uint8_t b;
4891 
4892                 if (strcmp(str, "true") == 0 || strcmp(str, "t") == 0 ||
4893                     strcmp(str, "1") == 0)
4894                         b = 1;
4895                 else if (strcmp(str, "false") == 0 ||
4896                     strcmp(str, "f") == 0 || strcmp(str, "0") == 0)
4897                         b = 0;
4898                 else {
4899                         goto bad;
4900                 }
4901 
4902                 scf_value_set_boolean(v, b);
4903                 return (0);
4904         }
4905 
4906         case SCF_TYPE_COUNT: {
4907                 uint64_t c;
4908                 char *endp;
4909 
4910                 errno = 0;
4911                 c = strtoull(str, &endp, 0);
4912 
4913                 if (errno != 0 || endp == str || *endp != '\0')
4914                         goto bad;
4915 
4916                 scf_value_set_count(v, c);
4917                 return (0);
4918         }
4919 
4920         case SCF_TYPE_INTEGER: {
4921                 int64_t i;
4922                 char *endp;
4923 
4924                 errno = 0;
4925                 i = strtoll(str, &endp, 0);
4926 
4927                 if (errno != 0 || endp == str || *endp != '\0')
4928                         goto bad;
4929 
4930                 scf_value_set_integer(v, i);
4931                 return (0);
4932         }
4933 
4934         case SCF_TYPE_TIME: {
4935                 int64_t s;
4936                 uint32_t ns = 0;
4937                 char *endp, *ns_str;
4938                 size_t len;
4939 
4940                 errno = 0;
4941                 s = strtoll(str, &endp, 10);
4942                 if (errno != 0 || endp == str ||
4943                     (*endp != '\0' && *endp != '.'))
4944                         goto bad;
4945 
4946                 if (*endp == '.') {
4947                         ns_str = endp + 1;
4948                         len = strlen(ns_str);
4949                         if (len == 0 || len > 9)
4950                                 goto bad;
4951 
4952                         ns = strtoul(ns_str, &endp, 10);
4953                         if (errno != 0 || endp == ns_str || *endp != '\0')
4954                                 goto bad;
4955 
4956                         while (len++ < 9)
4957                                 ns *= 10;
4958                         assert(ns < NANOSEC);
4959                 }
4960 
4961                 return (scf_value_set_time(v, s, ns));
4962         }
4963 
4964         case SCF_TYPE_ASTRING:
4965         case SCF_TYPE_USTRING:
4966         case SCF_TYPE_OPAQUE:
4967         case SCF_TYPE_URI:
4968         case SCF_TYPE_FMRI:
4969         case SCF_TYPE_HOST:
4970         case SCF_TYPE_HOSTNAME:
4971         case SCF_TYPE_NET_ADDR:
4972         case SCF_TYPE_NET_ADDR_V4:
4973         case SCF_TYPE_NET_ADDR_V6:
4974                 ty = scf_type_to_protocol_type(type);
4975 
4976                 (void) pthread_mutex_lock(&h->rh_lock);
4977                 scf_value_reset_locked(v, 0);
4978                 if (type == SCF_TYPE_OPAQUE) {
4979                         v->value_size = scf_opaque_decode(v->value_value,
4980                             str, sizeof (v->value_value));
4981                         if (!scf_validate_encoded_value(ty, str)) {
4982                                 (void) pthread_mutex_lock(&h->rh_lock);
4983                                 goto bad;
4984                         }
4985                 } else {
4986                         (void) strlcpy(v->value_value, str,
4987                             sizeof (v->value_value));
4988                         if (!scf_validate_encoded_value(ty, v->value_value)) {
4989                                 (void) pthread_mutex_lock(&h->rh_lock);
4990                                 goto bad;
4991                         }
4992                 }
4993                 v->value_type = ty;
4994                 (void) pthread_mutex_unlock(&h->rh_lock);
4995                 return (SCF_SUCCESS);
4996 
4997         case REP_PROTOCOL_TYPE_INVALID:
4998         default:
4999                 scf_value_reset(v);
5000                 return (scf_set_error(SCF_ERROR_TYPE_MISMATCH));
5001         }
5002 bad:
5003         scf_value_reset(v);
5004         return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
5005 }
5006 
5007 int
5008 scf_iter_property_values(scf_iter_t *iter, const scf_property_t *prop)
5009 {
5010         return (datael_setup_iter(iter, &prop->rd_d,
5011             REP_PROTOCOL_ENTITY_VALUE, 0));
5012 }
5013 
5014 int
5015 scf_iter_next_value(scf_iter_t *iter, scf_value_t *v)
5016 {
5017         scf_handle_t *h = iter->iter_handle;
5018 
5019         struct rep_protocol_iter_read_value request;
5020         struct rep_protocol_value_response response;
5021 
5022         int r;
5023 
5024         if (h != v->value_handle)
5025                 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
5026 
5027         (void) pthread_mutex_lock(&h->rh_lock);
5028 
5029         scf_value_reset_locked(v, 0);
5030 
5031         if (iter->iter_type == REP_PROTOCOL_ENTITY_NONE) {
5032                 (void) pthread_mutex_unlock(&h->rh_lock);
5033                 return (scf_set_error(SCF_ERROR_NOT_SET));
5034         }
5035 
5036         if (iter->iter_type != REP_PROTOCOL_ENTITY_VALUE) {
5037                 (void) pthread_mutex_unlock(&h->rh_lock);
5038                 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
5039         }
5040 
5041         request.rpr_request = REP_PROTOCOL_ITER_READ_VALUE;
5042         request.rpr_iterid = iter->iter_id;
5043         request.rpr_sequence = iter->iter_sequence;
5044 
5045         r = make_door_call(h, &request, sizeof (request),
5046             &response, sizeof (response));
5047 
5048         if (r < 0) {
5049                 (void) pthread_mutex_unlock(&h->rh_lock);
5050                 DOOR_ERRORS_BLOCK(r);
5051         }
5052 
5053         if (response.rpr_response == REP_PROTOCOL_DONE) {
5054                 (void) pthread_mutex_unlock(&h->rh_lock);
5055                 return (0);
5056         }
5057         if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
5058                 (void) pthread_mutex_unlock(&h->rh_lock);
5059                 return (scf_set_error(proto_error(response.rpr_response)));
5060         }
5061         iter->iter_sequence++;
5062 
5063         v->value_type = response.rpr_type;
5064 
5065         assert(scf_validate_encoded_value(response.rpr_type,
5066             response.rpr_value));
5067 
5068         if (v->value_type != REP_PROTOCOL_TYPE_OPAQUE) {
5069                 (void) strlcpy(v->value_value, response.rpr_value,
5070                     sizeof (v->value_value));
5071         } else {
5072                 v->value_size = scf_opaque_decode(v->value_value,
5073                     response.rpr_value, sizeof (v->value_value));
5074         }
5075         (void) pthread_mutex_unlock(&h->rh_lock);
5076 
5077         return (1);
5078 }
5079 
5080 int
5081 scf_property_get_value(const scf_property_t *prop, scf_value_t *v)
5082 {
5083         scf_handle_t *h = prop->rd_d.rd_handle;
5084         struct rep_protocol_property_request request;
5085         struct rep_protocol_value_response response;
5086         int r;
5087 
5088         if (h != v->value_handle)
5089                 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
5090 
5091         (void) pthread_mutex_lock(&h->rh_lock);
5092 
5093         request.rpr_request = REP_PROTOCOL_PROPERTY_GET_VALUE;
5094         request.rpr_entityid = prop->rd_d.rd_entity;
5095 
5096         scf_value_reset_locked(v, 0);
5097         datael_finish_reset(&prop->rd_d);
5098 
5099         r = make_door_call(h, &request, sizeof (request),
5100             &response, sizeof (response));
5101 
5102         if (r < 0) {
5103                 (void) pthread_mutex_unlock(&h->rh_lock);
5104                 DOOR_ERRORS_BLOCK(r);
5105         }
5106 
5107         if (response.rpr_response != REP_PROTOCOL_SUCCESS &&
5108             response.rpr_response != REP_PROTOCOL_FAIL_TRUNCATED) {
5109                 (void) pthread_mutex_unlock(&h->rh_lock);
5110                 assert(response.rpr_response !=
5111                     REP_PROTOCOL_FAIL_TYPE_MISMATCH);
5112                 return (scf_set_error(proto_error(response.rpr_response)));
5113         }
5114 
5115         v->value_type = response.rpr_type;
5116         if (v->value_type != REP_PROTOCOL_TYPE_OPAQUE) {
5117                 (void) strlcpy(v->value_value, response.rpr_value,
5118                     sizeof (v->value_value));
5119         } else {
5120                 v->value_size = scf_opaque_decode(v->value_value,
5121                     response.rpr_value, sizeof (v->value_value));
5122         }
5123         (void) pthread_mutex_unlock(&h->rh_lock);
5124         return ((response.rpr_response == REP_PROTOCOL_SUCCESS)?
5125             SCF_SUCCESS : scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED));
5126 }
5127 
5128 int
5129 scf_pg_get_parent_service(const scf_propertygroup_t *pg, scf_service_t *svc)
5130 {
5131         return (datael_get_parent(&pg->rd_d, &svc->rd_d));
5132 }
5133 
5134 int
5135 scf_pg_get_parent_instance(const scf_propertygroup_t *pg, scf_instance_t *inst)
5136 {
5137         return (datael_get_parent(&pg->rd_d, &inst->rd_d));
5138 }
5139 
5140 int
5141 scf_pg_get_parent_snaplevel(const scf_propertygroup_t *pg,
5142     scf_snaplevel_t *level)
5143 {
5144         return (datael_get_parent(&pg->rd_d, &level->rd_d));
5145 }
5146 
5147 int
5148 scf_service_get_parent(const scf_service_t *svc, scf_scope_t *s)
5149 {
5150         return (datael_get_parent(&svc->rd_d, &s->rd_d));
5151 }
5152 
5153 int
5154 scf_instance_get_parent(const scf_instance_t *inst, scf_service_t *svc)
5155 {
5156         return (datael_get_parent(&inst->rd_d, &svc->rd_d));
5157 }
5158 
5159 int
5160 scf_snapshot_get_parent(const scf_snapshot_t *inst, scf_instance_t *svc)
5161 {
5162         return (datael_get_parent(&inst->rd_d, &svc->rd_d));
5163 }
5164 
5165 int
5166 scf_snaplevel_get_parent(const scf_snaplevel_t *inst, scf_snapshot_t *svc)
5167 {
5168         return (datael_get_parent(&inst->rd_d, &svc->rd_d));
5169 }
5170 
5171 /*
5172  * FMRI functions
5173  *
5174  * Note: In the scf_parse_svc_fmri(), scf_parse_file_fmri() and
5175  * scf_parse_fmri(), fmri isn't const because that would require
5176  * allocating memory. Also, note that scope, at least, is not necessarily
5177  * in the passed in fmri.
5178  */
5179 
5180 int
5181 scf_parse_svc_fmri(char *fmri, const char **scope, const char **service,
5182     const char **instance, const char **propertygroup, const char **property)
5183 {
5184         char *s, *e, *te, *tpg;
5185         char *my_s = NULL, *my_i = NULL, *my_pg = NULL, *my_p = NULL;
5186 
5187         if (scope != NULL)
5188                 *scope = NULL;
5189         if (service != NULL)
5190                 *service = NULL;
5191         if (instance != NULL)
5192                 *instance = NULL;
5193         if (propertygroup != NULL)
5194                 *propertygroup = NULL;
5195         if (property != NULL)
5196                 *property = NULL;
5197 
5198         s = fmri;
5199         e = strchr(s, '\0');
5200 
5201         if (strncmp(s, SCF_FMRI_SVC_PREFIX,
5202             sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0)
5203                 s += sizeof (SCF_FMRI_SVC_PREFIX) - 1;
5204 
5205         if (strncmp(s, SCF_FMRI_SCOPE_PREFIX,
5206             sizeof (SCF_FMRI_SCOPE_PREFIX) - 1) == 0) {
5207                 char *my_scope;
5208 
5209                 s += sizeof (SCF_FMRI_SCOPE_PREFIX) - 1;
5210                 te = strstr(s, SCF_FMRI_SERVICE_PREFIX);
5211                 if (te == NULL)
5212                         te = e;
5213 
5214                 *te = 0;
5215                 my_scope = s;
5216 
5217                 s = te;
5218                 if (s < e)
5219                         s += sizeof (SCF_FMRI_SERVICE_PREFIX) - 1;
5220 
5221                 /* If the scope ends with the suffix, remove it. */
5222                 te = strstr(my_scope, SCF_FMRI_SCOPE_SUFFIX);
5223                 if (te != NULL && te[sizeof (SCF_FMRI_SCOPE_SUFFIX) - 1] == 0)
5224                         *te = 0;
5225 
5226                 /* Validate the scope. */
5227                 if (my_scope[0] == '\0')
5228                         my_scope = SCF_FMRI_LOCAL_SCOPE;
5229                 else if (uu_check_name(my_scope, 0) == -1) {
5230                         return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
5231                 }
5232 
5233                 if (scope != NULL)
5234                         *scope = my_scope;
5235         } else {
5236                 if (scope != NULL)
5237                         *scope = SCF_FMRI_LOCAL_SCOPE;
5238         }
5239 
5240         if (s[0] != 0) {
5241                 if (strncmp(s, SCF_FMRI_SERVICE_PREFIX,
5242                     sizeof (SCF_FMRI_SERVICE_PREFIX) - 1) == 0)
5243                         s += sizeof (SCF_FMRI_SERVICE_PREFIX) - 1;
5244 
5245                 /*
5246                  * Can't validate service here because it might not be null
5247                  * terminated.
5248                  */
5249                 my_s = s;
5250         }
5251 
5252         tpg = strstr(s, SCF_FMRI_PROPERTYGRP_PREFIX);
5253         te = strstr(s, SCF_FMRI_INSTANCE_PREFIX);
5254         if (te != NULL && (tpg == NULL || te < tpg)) {
5255                 *te = 0;
5256                 te += sizeof (SCF_FMRI_INSTANCE_PREFIX) - 1;
5257 
5258                 /* Can't validate instance here either. */
5259                 my_i = s = te;
5260 
5261                 te = strstr(s, SCF_FMRI_PROPERTYGRP_PREFIX);
5262         } else {
5263                 te = tpg;
5264         }
5265 
5266         if (te != NULL) {
5267                 *te = 0;
5268                 te += sizeof (SCF_FMRI_PROPERTYGRP_PREFIX) - 1;
5269 
5270                 my_pg = s = te;
5271                 te = strstr(s, SCF_FMRI_PROPERTY_PREFIX);
5272                 if (te != NULL) {
5273                         *te = 0;
5274                         te += sizeof (SCF_FMRI_PROPERTY_PREFIX) - 1;
5275 
5276                         my_p = te;
5277                         s = te;
5278                 }
5279         }
5280 
5281         if (my_s != NULL) {
5282                 if (uu_check_name(my_s, UU_NAME_DOMAIN | UU_NAME_PATH) == -1)
5283                         return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
5284 
5285                 if (service != NULL)
5286                         *service = my_s;
5287         }
5288 
5289         if (my_i != NULL) {
5290                 if (uu_check_name(my_i, UU_NAME_DOMAIN) == -1)
5291                         return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
5292 
5293                 if (instance != NULL)
5294                         *instance = my_i;
5295         }
5296 
5297         if (my_pg != NULL) {
5298                 if (uu_check_name(my_pg, UU_NAME_DOMAIN) == -1)
5299                         return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
5300 
5301                 if (propertygroup != NULL)
5302                         *propertygroup = my_pg;
5303         }
5304 
5305         if (my_p != NULL) {
5306                 if (uu_check_name(my_p, UU_NAME_DOMAIN) == -1)
5307                         return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
5308 
5309                 if (property != NULL)
5310                         *property = my_p;
5311         }
5312 
5313         return (0);
5314 }
5315 
5316 int
5317 scf_parse_file_fmri(char *fmri, const char **scope, const char **path)
5318 {
5319         char *s, *e, *te;
5320 
5321         if (scope != NULL)
5322                 *scope = NULL;
5323 
5324         s = fmri;
5325         e = strchr(s, '\0');
5326 
5327         if (strncmp(s, SCF_FMRI_FILE_PREFIX,
5328             sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0)
5329                 s += sizeof (SCF_FMRI_FILE_PREFIX) - 1;
5330 
5331         if (strncmp(s, SCF_FMRI_SCOPE_PREFIX,
5332             sizeof (SCF_FMRI_SCOPE_PREFIX) - 1) == 0) {
5333                 char *my_scope;
5334 
5335                 s += sizeof (SCF_FMRI_SCOPE_PREFIX) - 1;
5336                 te = strstr(s, SCF_FMRI_SERVICE_PREFIX);
5337                 if (te == NULL)
5338                         te = e;
5339 
5340                 *te = 0;
5341                 my_scope = s;
5342 
5343                 s = te;
5344 
5345                 /* Validate the scope. */
5346                 if (my_scope[0] != '\0' &&
5347                     strcmp(my_scope, SCF_FMRI_LOCAL_SCOPE) != 0) {
5348                         return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
5349                 }
5350 
5351                 if (scope != NULL)
5352                         *scope = my_scope;
5353         } else {
5354                 /*
5355                  * FMRI paths must be absolute
5356                  */
5357                 if (s[0] != '/')
5358                         return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
5359         }
5360 
5361         s += sizeof (SCF_FMRI_SERVICE_PREFIX) - 1;
5362 
5363         if (s >= e)
5364                 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
5365 
5366         /*
5367          * If the user requests it, return the full path of the file.
5368          */
5369         if (path != NULL) {
5370                 assert(s > fmri);
5371                 s[-1] = '/';
5372                 *path = s - 1;
5373         }
5374 
5375         return (0);
5376 }
5377 
5378 int
5379 scf_parse_fmri(char *fmri, int *type, const char **scope, const char **service,
5380     const char **instance, const char **propertygroup, const char **property)
5381 {
5382         if (strncmp(fmri, SCF_FMRI_SVC_PREFIX,
5383             sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
5384                 if (type)
5385                         *type = SCF_FMRI_TYPE_SVC;
5386                 return (scf_parse_svc_fmri(fmri, scope, service, instance,
5387                     propertygroup, property));
5388         } else if (strncmp(fmri, SCF_FMRI_FILE_PREFIX,
5389             sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
5390                 if (type)
5391                         *type = SCF_FMRI_TYPE_FILE;
5392                 return (scf_parse_file_fmri(fmri, scope, NULL));
5393         } else {
5394                 /*
5395                  * Parse as a svc if the fmri type is not explicitly
5396                  * specified.
5397                  */
5398                 if (type)
5399                         *type = SCF_FMRI_TYPE_SVC;
5400                 return (scf_parse_svc_fmri(fmri, scope, service, instance,
5401                     propertygroup, property));
5402         }
5403 }
5404 
5405 /*
5406  * Fails with _INVALID_ARGUMENT.  fmri and buf may be equal.
5407  */
5408 ssize_t
5409 scf_canonify_fmri(const char *fmri, char *buf, size_t bufsz)
5410 {
5411         const char *scope, *service, *instance, *pg, *property;
5412         char local[6 * REP_PROTOCOL_NAME_LEN];
5413         int r;
5414         size_t len;
5415 
5416         if (strlcpy(local, fmri, sizeof (local)) >= sizeof (local)) {
5417                 /* Should this be CONSTRAINT_VIOLATED? */
5418                 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
5419                 return (-1);
5420         }
5421 
5422 
5423         r = scf_parse_svc_fmri(local, &scope, &service, &instance, &pg,
5424             &property);
5425         if (r != 0)
5426                 return (-1);
5427 
5428         len = strlcpy(buf, "svc:/", bufsz);
5429 
5430         if (scope != NULL && strcmp(scope, SCF_SCOPE_LOCAL) != 0) {
5431                 len += strlcat(buf, "/", bufsz);
5432                 len += strlcat(buf, scope, bufsz);
5433         }
5434 
5435         if (service)
5436                 len += strlcat(buf, service, bufsz);
5437 
5438         if (instance) {
5439                 len += strlcat(buf, ":", bufsz);
5440                 len += strlcat(buf, instance, bufsz);
5441         }
5442 
5443         if (pg) {
5444                 len += strlcat(buf, "/:properties/", bufsz);
5445                 len += strlcat(buf, pg, bufsz);
5446         }
5447 
5448         if (property) {
5449                 len += strlcat(buf, "/", bufsz);
5450                 len += strlcat(buf, property, bufsz);
5451         }
5452 
5453         return (len);
5454 }
5455 
5456 /*
5457  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _CONSTRAINT_VIOLATED,
5458  * _NOT_FOUND, _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED,
5459  * _NO_RESOURCES, _BACKEND_ACCESS.
5460  */
5461 int
5462 scf_handle_decode_fmri(scf_handle_t *h, const char *fmri, scf_scope_t *sc,
5463     scf_service_t *svc, scf_instance_t *inst, scf_propertygroup_t *pg,
5464     scf_property_t *prop, int flags)
5465 {
5466         const char *scope, *service, *instance, *propertygroup, *property;
5467         int last;
5468         char local[6 * REP_PROTOCOL_NAME_LEN];
5469         int ret;
5470         const uint32_t holds = RH_HOLD_SCOPE | RH_HOLD_SERVICE |
5471             RH_HOLD_INSTANCE | RH_HOLD_PG | RH_HOLD_PROPERTY;
5472 
5473         /*
5474          * verify that all handles match
5475          */
5476         if ((sc != NULL && h != sc->rd_d.rd_handle) ||
5477             (svc != NULL && h != svc->rd_d.rd_handle) ||
5478             (inst != NULL && h != inst->rd_d.rd_handle) ||
5479             (pg != NULL && h != pg->rd_d.rd_handle) ||
5480             (prop != NULL && h != prop->rd_d.rd_handle))
5481                 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
5482 
5483         if (strlcpy(local, fmri, sizeof (local)) >= sizeof (local)) {
5484                 ret = scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
5485                 goto reset_args;
5486         }
5487 
5488         /*
5489          * We can simply return from an error in parsing, because
5490          * scf_parse_fmri sets the error code correctly.
5491          */
5492         if (scf_parse_svc_fmri(local, &scope, &service, &instance,
5493             &propertygroup, &property) == -1) {
5494                 ret = -1;
5495                 goto reset_args;
5496         }
5497 
5498         /*
5499          * the FMRI looks valid at this point -- do constraint checks.
5500          */
5501 
5502         if (instance != NULL && (flags & SCF_DECODE_FMRI_REQUIRE_NO_INSTANCE)) {
5503                 ret = scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED);
5504                 goto reset_args;
5505         }
5506         if (instance == NULL && (flags & SCF_DECODE_FMRI_REQUIRE_INSTANCE)) {
5507                 ret = scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED);
5508                 goto reset_args;
5509         }
5510 
5511         if (prop != NULL)
5512                 last = REP_PROTOCOL_ENTITY_PROPERTY;
5513         else if (pg != NULL)
5514                 last = REP_PROTOCOL_ENTITY_PROPERTYGRP;
5515         else if (inst != NULL)
5516                 last = REP_PROTOCOL_ENTITY_INSTANCE;
5517         else if (svc != NULL)
5518                 last = REP_PROTOCOL_ENTITY_SERVICE;
5519         else if (sc != NULL)
5520                 last = REP_PROTOCOL_ENTITY_SCOPE;
5521         else
5522                 last = REP_PROTOCOL_ENTITY_NONE;
5523 
5524         if (flags & SCF_DECODE_FMRI_EXACT) {
5525                 int last_fmri;
5526 
5527                 if (property != NULL)
5528                         last_fmri = REP_PROTOCOL_ENTITY_PROPERTY;
5529                 else if (propertygroup != NULL)
5530                         last_fmri = REP_PROTOCOL_ENTITY_PROPERTYGRP;
5531                 else if (instance != NULL)
5532                         last_fmri = REP_PROTOCOL_ENTITY_INSTANCE;
5533                 else if (service != NULL)
5534                         last_fmri = REP_PROTOCOL_ENTITY_SERVICE;
5535                 else if (scope != NULL)
5536                         last_fmri = REP_PROTOCOL_ENTITY_SCOPE;
5537                 else
5538                         last_fmri = REP_PROTOCOL_ENTITY_NONE;
5539 
5540                 if (last != last_fmri) {
5541                         ret = scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED);
5542                         goto reset_args;
5543                 }
5544         }
5545 
5546         if ((flags & SCF_DECODE_FMRI_TRUNCATE) &&
5547             last == REP_PROTOCOL_ENTITY_NONE) {
5548                 ret = 0;                                /* nothing to do */
5549                 goto reset_args;
5550         }
5551 
5552         if (!(flags & SCF_DECODE_FMRI_TRUNCATE))
5553                 last = REP_PROTOCOL_ENTITY_NONE;        /* never stop */
5554 
5555         /*
5556          * passed the constraint checks -- try to grab the thing itself.
5557          */
5558 
5559         handle_hold_subhandles(h, holds);
5560         if (sc == NULL)
5561                 sc = h->rh_scope;
5562         else
5563                 datael_reset(&sc->rd_d);
5564 
5565         if (svc == NULL)
5566                 svc = h->rh_service;
5567         else
5568                 datael_reset(&svc->rd_d);
5569 
5570         if (inst == NULL)
5571                 inst = h->rh_instance;
5572         else
5573                 datael_reset(&inst->rd_d);
5574 
5575         if (pg == NULL)
5576                 pg = h->rh_pg;
5577         else
5578                 datael_reset(&pg->rd_d);
5579 
5580         if (prop == NULL)
5581                 prop = h->rh_property;
5582         else
5583                 datael_reset(&prop->rd_d);
5584 
5585         /*
5586          * We only support local scopes, but we check *after* getting
5587          * the local scope, so that any repository-related errors take
5588          * precedence.
5589          */
5590         if (scf_handle_get_scope(h, SCF_SCOPE_LOCAL, sc) == -1) {
5591                 handle_rele_subhandles(h, holds);
5592                 ret = -1;
5593                 goto reset_args;
5594         }
5595 
5596         if (scope != NULL && strcmp(scope, SCF_FMRI_LOCAL_SCOPE) != 0) {
5597                 handle_rele_subhandles(h, holds);
5598                 ret = scf_set_error(SCF_ERROR_NOT_FOUND);
5599                 goto reset_args;
5600         }
5601 
5602 
5603         if (service == NULL || last == REP_PROTOCOL_ENTITY_SCOPE) {
5604                 handle_rele_subhandles(h, holds);
5605                 return (0);
5606         }
5607 
5608         if (scf_scope_get_service(sc, service, svc) == -1) {
5609                 handle_rele_subhandles(h, holds);
5610                 ret = -1;
5611                 assert(scf_error() != SCF_ERROR_NOT_SET);
5612                 if (scf_error() == SCF_ERROR_DELETED)
5613                         (void) scf_set_error(SCF_ERROR_NOT_FOUND);
5614                 goto reset_args;
5615         }
5616 
5617         if (last == REP_PROTOCOL_ENTITY_SERVICE) {
5618                 handle_rele_subhandles(h, holds);
5619                 return (0);
5620         }
5621 
5622         if (instance == NULL) {
5623                 if (propertygroup == NULL ||
5624                     last == REP_PROTOCOL_ENTITY_INSTANCE) {
5625                         handle_rele_subhandles(h, holds);
5626                         return (0);
5627                 }
5628 
5629                 if (scf_service_get_pg(svc, propertygroup, pg) == -1) {
5630                         handle_rele_subhandles(h, holds);
5631                         ret = -1;
5632                         assert(scf_error() != SCF_ERROR_NOT_SET);
5633                         if (scf_error() == SCF_ERROR_DELETED)
5634                                 (void) scf_set_error(SCF_ERROR_NOT_FOUND);
5635                         goto reset_args;
5636                 }
5637         } else {
5638                 if (scf_service_get_instance(svc, instance, inst) == -1) {
5639                         handle_rele_subhandles(h, holds);
5640                         ret = -1;
5641                         assert(scf_error() != SCF_ERROR_NOT_SET);
5642                         if (scf_error() == SCF_ERROR_DELETED)
5643                                 (void) scf_set_error(SCF_ERROR_NOT_FOUND);
5644                         goto reset_args;
5645                 }
5646 
5647                 if (propertygroup == NULL ||
5648                     last == REP_PROTOCOL_ENTITY_INSTANCE) {
5649                         handle_rele_subhandles(h, holds);
5650                         return (0);
5651                 }
5652 
5653                 if (scf_instance_get_pg(inst, propertygroup, pg) == -1) {
5654                         handle_rele_subhandles(h, holds);
5655                         ret = -1;
5656                         assert(scf_error() != SCF_ERROR_NOT_SET);
5657                         if (scf_error() == SCF_ERROR_DELETED)
5658                                 (void) scf_set_error(SCF_ERROR_NOT_FOUND);
5659                         goto reset_args;
5660                 }
5661         }
5662 
5663         if (property == NULL || last == REP_PROTOCOL_ENTITY_PROPERTYGRP) {
5664                 handle_rele_subhandles(h, holds);
5665                 return (0);
5666         }
5667 
5668         if (scf_pg_get_property(pg, property, prop) == -1) {
5669                 handle_rele_subhandles(h, holds);
5670                 ret = -1;
5671                 assert(scf_error() != SCF_ERROR_NOT_SET);
5672                 if (scf_error() == SCF_ERROR_DELETED)
5673                         (void) scf_set_error(SCF_ERROR_NOT_FOUND);
5674                 goto reset_args;
5675         }
5676 
5677         handle_rele_subhandles(h, holds);
5678         return (0);
5679 
5680 reset_args:
5681         if (sc != NULL)
5682                 datael_reset(&sc->rd_d);
5683         if (svc != NULL)
5684                 datael_reset(&svc->rd_d);
5685         if (inst != NULL)
5686                 datael_reset(&inst->rd_d);
5687         if (pg != NULL)
5688                 datael_reset(&pg->rd_d);
5689         if (prop != NULL)
5690                 datael_reset(&prop->rd_d);
5691 
5692         return (ret);
5693 }
5694 
5695 /*
5696  * Fails with _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response too
5697  * big, bad entity id, request not applicable to entity, name too long for
5698  * buffer), _NOT_SET, or _DELETED.
5699  */
5700 ssize_t
5701 scf_scope_to_fmri(const scf_scope_t *scope, char *out, size_t sz)
5702 {
5703         ssize_t r, len;
5704 
5705         char tmp[REP_PROTOCOL_NAME_LEN];
5706 
5707         r = scf_scope_get_name(scope, tmp, sizeof (tmp));
5708 
5709         if (r <= 0)
5710                 return (r);
5711 
5712         len = strlcpy(out, SCF_FMRI_SVC_PREFIX, sz);
5713         if (strcmp(tmp, SCF_FMRI_LOCAL_SCOPE) != 0) {
5714                 if (len >= sz)
5715                         return (len + r + sizeof (SCF_FMRI_SCOPE_SUFFIX) - 1);
5716 
5717                 len = strlcat(out, tmp, sz);
5718                 if (len >= sz)
5719                         return (len + sizeof (SCF_FMRI_SCOPE_SUFFIX) - 1);
5720                 len = strlcat(out,
5721                     SCF_FMRI_SCOPE_SUFFIX SCF_FMRI_SERVICE_PREFIX, sz);
5722         }
5723 
5724         return (len);
5725 }
5726 
5727 /*
5728  * Fails with _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response too
5729  * big, bad element id, bad ids, bad types, scope has no parent, request not
5730  * applicable to entity, name too long), _NOT_SET, _DELETED,
5731  */
5732 ssize_t
5733 scf_service_to_fmri(const scf_service_t *svc, char *out, size_t sz)
5734 {
5735         scf_handle_t *h = svc->rd_d.rd_handle;
5736         scf_scope_t *scope = HANDLE_HOLD_SCOPE(h);
5737         ssize_t r, len;
5738 
5739         char tmp[REP_PROTOCOL_NAME_LEN];
5740 
5741         r = datael_get_parent(&svc->rd_d, &scope->rd_d);
5742         if (r != SCF_SUCCESS) {
5743                 HANDLE_RELE_SCOPE(h);
5744 
5745                 assert(scf_error() != SCF_ERROR_HANDLE_MISMATCH);
5746                 return (-1);
5747         }
5748         if (out != NULL && sz > 0)
5749                 len = scf_scope_to_fmri(scope, out, sz);
5750         else
5751                 len = scf_scope_to_fmri(scope, tmp, 2);
5752 
5753         HANDLE_RELE_SCOPE(h);
5754 
5755         if (len < 0)
5756                 return (-1);
5757 
5758         if (out == NULL || len >= sz)
5759                 len += sizeof (SCF_FMRI_SERVICE_PREFIX) - 1;
5760         else
5761                 len = strlcat(out, SCF_FMRI_SERVICE_PREFIX, sz);
5762 
5763         r = scf_service_get_name(svc, tmp, sizeof (tmp));
5764         if (r < 0)
5765                 return (r);
5766 
5767         if (out == NULL || len >= sz)
5768                 len += r;
5769         else
5770                 len = strlcat(out, tmp, sz);
5771 
5772         return (len);
5773 }
5774 
5775 ssize_t
5776 scf_instance_to_fmri(const scf_instance_t *inst, char *out, size_t sz)
5777 {
5778         scf_handle_t *h = inst->rd_d.rd_handle;
5779         scf_service_t *svc = HANDLE_HOLD_SERVICE(h);
5780         ssize_t r, len;
5781 
5782         char tmp[REP_PROTOCOL_NAME_LEN];
5783 
5784         r = datael_get_parent(&inst->rd_d, &svc->rd_d);
5785         if (r != SCF_SUCCESS) {
5786                 HANDLE_RELE_SERVICE(h);
5787                 return (-1);
5788         }
5789 
5790         len = scf_service_to_fmri(svc, out, sz);
5791 
5792         HANDLE_RELE_SERVICE(h);
5793 
5794         if (len < 0)
5795                 return (len);
5796 
5797         if (len >= sz)
5798                 len += sizeof (SCF_FMRI_INSTANCE_PREFIX) - 1;
5799         else
5800                 len = strlcat(out, SCF_FMRI_INSTANCE_PREFIX, sz);
5801 
5802         r = scf_instance_get_name(inst, tmp, sizeof (tmp));
5803         if (r < 0)
5804                 return (r);
5805 
5806         if (len >= sz)
5807                 len += r;
5808         else
5809                 len = strlcat(out, tmp, sz);
5810 
5811         return (len);
5812 }
5813 
5814 ssize_t
5815 scf_pg_to_fmri(const scf_propertygroup_t *pg, char *out, size_t sz)
5816 {
5817         scf_handle_t *h = pg->rd_d.rd_handle;
5818 
5819         struct rep_protocol_entity_parent_type request;
5820         struct rep_protocol_integer_response response;
5821 
5822         char tmp[REP_PROTOCOL_NAME_LEN];
5823         ssize_t len, r;
5824 
5825         (void) pthread_mutex_lock(&h->rh_lock);
5826         request.rpr_request = REP_PROTOCOL_ENTITY_PARENT_TYPE;
5827         request.rpr_entityid = pg->rd_d.rd_entity;
5828 
5829         datael_finish_reset(&pg->rd_d);
5830         r = make_door_call(h, &request, sizeof (request),
5831             &response, sizeof (response));
5832         (void) pthread_mutex_unlock(&h->rh_lock);
5833 
5834         if (r < 0)
5835                 DOOR_ERRORS_BLOCK(r);
5836 
5837         if (response.rpr_response != REP_PROTOCOL_SUCCESS ||
5838             r < sizeof (response)) {
5839                 return (scf_set_error(proto_error(response.rpr_response)));
5840         }
5841 
5842         switch (response.rpr_value) {
5843         case REP_PROTOCOL_ENTITY_SERVICE: {
5844                 scf_service_t *svc;
5845 
5846                 svc = HANDLE_HOLD_SERVICE(h);
5847 
5848                 r = datael_get_parent(&pg->rd_d, &svc->rd_d);
5849 
5850                 if (r == SCF_SUCCESS)
5851                         len = scf_service_to_fmri(svc, out, sz);
5852 
5853                 HANDLE_RELE_SERVICE(h);
5854                 break;
5855         }
5856 
5857         case REP_PROTOCOL_ENTITY_INSTANCE: {
5858                 scf_instance_t *inst;
5859 
5860                 inst = HANDLE_HOLD_INSTANCE(h);
5861 
5862                 r = datael_get_parent(&pg->rd_d, &inst->rd_d);
5863 
5864                 if (r == SCF_SUCCESS)
5865                         len = scf_instance_to_fmri(inst, out, sz);
5866 
5867                 HANDLE_RELE_INSTANCE(h);
5868                 break;
5869         }
5870 
5871         case REP_PROTOCOL_ENTITY_SNAPLEVEL: {
5872                 scf_instance_t *inst = HANDLE_HOLD_INSTANCE(h);
5873                 scf_snapshot_t *snap = HANDLE_HOLD_SNAPSHOT(h);
5874                 scf_snaplevel_t *level = HANDLE_HOLD_SNAPLVL(h);
5875 
5876                 r = datael_get_parent(&pg->rd_d, &level->rd_d);
5877 
5878                 if (r == SCF_SUCCESS)
5879                         r = datael_get_parent(&level->rd_d, &snap->rd_d);
5880 
5881                 if (r == SCF_SUCCESS)
5882                         r = datael_get_parent(&snap->rd_d, &inst->rd_d);
5883 
5884                 if (r == SCF_SUCCESS)
5885                         len = scf_instance_to_fmri(inst, out, sz);
5886 
5887                 HANDLE_RELE_INSTANCE(h);
5888                 HANDLE_RELE_SNAPSHOT(h);
5889                 HANDLE_RELE_SNAPLVL(h);
5890                 break;
5891         }
5892 
5893         default:
5894                 return (scf_set_error(SCF_ERROR_INTERNAL));
5895         }
5896 
5897         if (r != SCF_SUCCESS)
5898                 return (r);
5899 
5900         if (len >= sz)
5901                 len += sizeof (SCF_FMRI_PROPERTYGRP_PREFIX) - 1;
5902         else
5903                 len = strlcat(out, SCF_FMRI_PROPERTYGRP_PREFIX, sz);
5904 
5905         r = scf_pg_get_name(pg, tmp, sizeof (tmp));
5906 
5907         if (r < 0)
5908                 return (r);
5909 
5910         if (len >= sz)
5911                 len += r;
5912         else
5913                 len = strlcat(out, tmp, sz);
5914 
5915         return (len);
5916 }
5917 
5918 ssize_t
5919 scf_property_to_fmri(const scf_property_t *prop, char *out, size_t sz)
5920 {
5921         scf_handle_t *h = prop->rd_d.rd_handle;
5922         scf_propertygroup_t *pg = HANDLE_HOLD_PG(h);
5923 
5924         char tmp[REP_PROTOCOL_NAME_LEN];
5925         ssize_t len;
5926         int r;
5927 
5928         r = datael_get_parent(&prop->rd_d, &pg->rd_d);
5929         if (r != SCF_SUCCESS) {
5930                 HANDLE_RELE_PG(h);
5931                 return (-1);
5932         }
5933 
5934         len = scf_pg_to_fmri(pg, out, sz);
5935 
5936         HANDLE_RELE_PG(h);
5937 
5938         if (len >= sz)
5939                 len += sizeof (SCF_FMRI_PROPERTY_PREFIX) - 1;
5940         else
5941                 len = strlcat(out, SCF_FMRI_PROPERTY_PREFIX, sz);
5942 
5943         r = scf_property_get_name(prop, tmp, sizeof (tmp));
5944 
5945         if (r < 0)
5946                 return (r);
5947 
5948         if (len >= sz)
5949                 len += r;
5950         else
5951                 len = strlcat(out, tmp, sz);
5952 
5953         return (len);
5954 }
5955 
5956 /*
5957  * Fails with _HANDLE_MISMATCH, _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL
5958  * (server response too big, bad entity id, request not applicable to entity,
5959  * name too long for buffer, bad element id, iter already exists, element
5960  * cannot have children of type, type is invalid, iter was reset, sequence
5961  * was bad, iter walks values, iter does not walk type entities),
5962  * _NOT_SET, _DELETED, or _CONSTRAINT_VIOLATED,
5963  * _NOT_FOUND (scope has no parent),  _INVALID_ARGUMENT, _NO_RESOURCES,
5964  * _BACKEND_ACCESS.
5965  */
5966 int
5967 scf_pg_get_underlying_pg(const scf_propertygroup_t *pg,
5968     scf_propertygroup_t *out)
5969 {
5970         scf_handle_t *h = pg->rd_d.rd_handle;
5971         scf_service_t *svc;
5972         scf_instance_t *inst;
5973 
5974         char me[REP_PROTOCOL_NAME_LEN];
5975         int r;
5976 
5977         if (h != out->rd_d.rd_handle)
5978                 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
5979 
5980         r = scf_pg_get_name(pg, me, sizeof (me));
5981 
5982         if (r < 0)
5983                 return (r);
5984 
5985         svc = HANDLE_HOLD_SERVICE(h);
5986         inst = HANDLE_HOLD_INSTANCE(h);
5987 
5988         r = datael_get_parent(&pg->rd_d, &inst->rd_d);
5989 
5990         if (r == SCF_SUCCESS) {
5991                 r = datael_get_parent(&inst->rd_d, &svc->rd_d);
5992                 if (r != SCF_SUCCESS) {
5993                         goto out;
5994                 }
5995                 r = scf_service_get_pg(svc, me, out);
5996         } else {
5997                 r = scf_set_error(SCF_ERROR_NOT_FOUND);
5998         }
5999 
6000 out:
6001         HANDLE_RELE_SERVICE(h);
6002         HANDLE_RELE_INSTANCE(h);
6003         return (r);
6004 }
6005 
6006 #define LEGACY_SCHEME   "lrc:"
6007 #define LEGACY_UNKNOWN  "unknown"
6008 
6009 /*
6010  * Implementation of scf_walk_fmri()
6011  *
6012  * This is a little tricky due to the many-to-many relationship between patterns
6013  * and matches.  We need to be able to satisfy the following requirements:
6014  *
6015  *      1) Detect patterns which match more than one FMRI, and be able to
6016  *         report which FMRIs have been matched.
6017  *      2) Detect patterns which have not matched any FMRIs
6018  *      3) Visit each matching FMRI exactly once across all patterns
6019  *      4) Ignore FMRIs which have only been matched due to multiply-matching
6020  *         patterns.
6021  *
6022  * We maintain an array of scf_pattern_t structures, one for each argument, and
6023  * maintain a linked list of scf_match_t structures for each one.  We first
6024  * qualify each pattern's type:
6025  *
6026  *      PATTERN_INVALID         The argument is invalid (too long).
6027  *
6028  *      PATTERN_EXACT           The pattern is a complete FMRI.  The list of
6029  *                              matches contains only a single entry.
6030  *
6031  *      PATTERN_GLOB            The pattern will be matched against all
6032  *                              FMRIs via fnmatch() in the second phase.
6033  *                              Matches will be added to the pattern's list
6034  *                              as they are found.
6035  *
6036  *      PATTERN_PARTIAL         Everything else.  We will assume that this is
6037  *                              an abbreviated FMRI, and match according to
6038  *                              our abbreviated FMRI rules.  Matches will be
6039  *                              added to the pattern's list as they are found.
6040  *
6041  * The first pass searches for arguments that are complete FMRIs.  These are
6042  * classified as EXACT patterns and do not necessitate searching the entire
6043  * tree.
6044  *
6045  * Once this is done, if we have any GLOB or PARTIAL patterns (or if no
6046  * arguments were given), we iterate over all services and instances in the
6047  * repository, looking for matches.
6048  *
6049  * When a match is found, we add the match to the pattern's list.  We also enter
6050  * the match into a hash table, resulting in something like this:
6051  *
6052  *       scf_pattern_t       scf_match_t
6053  *     +---------------+      +-------+     +-------+
6054  *     | pattern 'foo' |----->| match |---->| match |
6055  *     +---------------+      +-------+     +-------+
6056  *                                |             |
6057  *           scf_match_key_t      |             |
6058  *           +--------------+     |             |
6059  *           | FMRI bar/foo |<----+             |
6060  *           +--------------+                   |
6061  *           | FMRI baz/foo |<------------------+
6062  *           +--------------+
6063  *
6064  * Once we have all of this set up, we do one pass to report patterns matching
6065  * multiple FMRIs (if SCF_WALK_MULTIPLE is not set) and patterns for which no
6066  * match was found.
6067  *
6068  * Finally, we walk through all valid patterns, and for each match, if we
6069  * haven't already seen the match (as recorded in the hash table), then we
6070  * execute the callback.
6071  */
6072 
6073 struct scf_matchkey;
6074 struct scf_match;
6075 
6076 /*
6077  * scf_matchkey_t
6078  */
6079 typedef struct scf_matchkey {
6080         char                    *sk_fmri;       /* Matching FMRI */
6081         char                    *sk_legacy;     /* Legacy name */
6082         int                     sk_seen;        /* If we've been seen */
6083         struct scf_matchkey     *sk_next;       /* Next in hash chain */
6084 } scf_matchkey_t;
6085 
6086 /*
6087  * scf_match_t
6088  */
6089 typedef struct scf_match {
6090         scf_matchkey_t          *sm_key;
6091         struct scf_match        *sm_next;
6092 } scf_match_t;
6093 
6094 #define WALK_HTABLE_SIZE        123
6095 
6096 /*
6097  * scf_get_key()
6098  *
6099  * Given an FMRI and a hash table, returns the scf_matchkey_t corresponding to
6100  * this FMRI.  If the FMRI does not exist, it is added to the hash table.  If a
6101  * new entry cannot be allocated due to lack of memory, NULL is returned.
6102  */
6103 static scf_matchkey_t *
6104 scf_get_key(scf_matchkey_t **htable, const char *fmri, const char *legacy)
6105 {
6106         uint_t h = 0, g;
6107         const char *p, *k;
6108         scf_matchkey_t *key;
6109 
6110         k = strstr(fmri, ":/");
6111         assert(k != NULL);
6112         k += 2;
6113 
6114         /*
6115          * Generic hash function from uts/common/os/modhash.c.
6116          */
6117         for (p = k; *p != '\0'; ++p) {
6118                 h = (h << 4) + *p;
6119                 if ((g = (h & 0xf0000000)) != 0) {
6120                         h ^= (g >> 24);
6121                         h ^= g;
6122                 }
6123         }
6124 
6125         h %= WALK_HTABLE_SIZE;
6126 
6127         /*
6128          * Search for an existing key
6129          */
6130         for (key = htable[h]; key != NULL; key = key->sk_next) {
6131                 if (strcmp(key->sk_fmri, fmri) == 0)
6132                         return (key);
6133         }
6134 
6135         if ((key = calloc(sizeof (scf_matchkey_t), 1)) == NULL)
6136                 return (NULL);
6137 
6138         /*
6139          * Add new key to hash table.
6140          */
6141         if ((key->sk_fmri = strdup(fmri)) == NULL) {
6142                 free(key);
6143                 return (NULL);
6144         }
6145 
6146         if (legacy == NULL) {
6147                 key->sk_legacy = NULL;
6148         } else if ((key->sk_legacy = strdup(legacy)) == NULL) {
6149                 free(key->sk_fmri);
6150                 free(key);
6151                 return (NULL);
6152         }
6153 
6154         key->sk_next = htable[h];
6155         htable[h] = key;
6156 
6157         return (key);
6158 }
6159 
6160 /*
6161  * Given an FMRI, insert it into the pattern's list appropriately.
6162  * svc_explicit indicates whether matching services should take
6163  * precedence over matching instances.
6164  */
6165 static scf_error_t
6166 scf_add_match(scf_matchkey_t **htable, const char *fmri, const char *legacy,
6167     scf_pattern_t *pattern, int svc_explicit)
6168 {
6169         scf_match_t *match;
6170 
6171         /*
6172          * If svc_explicit is set, enforce the constaint that matching
6173          * instances take precedence over matching services. Otherwise,
6174          * matching services take precedence over matching instances.
6175          */
6176         if (svc_explicit) {
6177                 scf_match_t *next, *prev;
6178                 /*
6179                  * If we match an instance, check to see if we must remove
6180                  * any matching services (for SCF_WALK_EXPLICIT).
6181                  */
6182                 for (prev = match = pattern->sp_matches; match != NULL;
6183                     match = next) {
6184                         size_t len = strlen(match->sm_key->sk_fmri);
6185                         next = match->sm_next;
6186                         if (strncmp(match->sm_key->sk_fmri, fmri, len) == 0 &&
6187                             fmri[len] == ':') {
6188                                 if (prev == match)
6189                                         pattern->sp_matches = match->sm_next;
6190                                 else
6191                                         prev->sm_next = match->sm_next;
6192                                 pattern->sp_matchcount--;
6193                                 free(match);
6194                         } else
6195                                 prev = match;
6196                 }
6197         } else {
6198                 /*
6199                  * If we've matched a service don't add any instances (for
6200                  * SCF_WALK_SERVICE).
6201                  */
6202                 for (match = pattern->sp_matches; match != NULL;
6203                     match = match->sm_next) {
6204                         size_t len = strlen(match->sm_key->sk_fmri);
6205                         if (strncmp(match->sm_key->sk_fmri, fmri, len) == 0 &&
6206                             fmri[len] == ':')
6207                                 return (0);
6208                 }
6209         }
6210 
6211         if ((match = malloc(sizeof (scf_match_t))) == NULL)
6212                 return (SCF_ERROR_NO_MEMORY);
6213 
6214         if ((match->sm_key = scf_get_key(htable, fmri, legacy)) == NULL) {
6215                 free(match);
6216                 return (SCF_ERROR_NO_MEMORY);
6217         }
6218 
6219         match->sm_next = pattern->sp_matches;
6220         pattern->sp_matches = match;
6221         pattern->sp_matchcount++;
6222 
6223         return (0);
6224 }
6225 
6226 /*
6227  * Returns 1 if the fmri matches the given pattern, 0 otherwise.
6228  */
6229 int
6230 scf_cmp_pattern(char *fmri, scf_pattern_t *pattern)
6231 {
6232         char *tmp;
6233 
6234         if (pattern->sp_type == PATTERN_GLOB) {
6235                 if (fnmatch(pattern->sp_arg, fmri, 0) == 0)
6236                         return (1);
6237         } else if (pattern->sp_type == PATTERN_PARTIAL &&
6238             (tmp = strstr(fmri, pattern->sp_arg)) != NULL) {
6239                 /*
6240                  * We only allow partial matches anchored on the end of
6241                  * a service or instance, and beginning on an element
6242                  * boundary.
6243                  */
6244                 if (tmp != fmri && tmp[-1] != '/' && tmp[-1] != ':' &&
6245                     tmp[0] != ':')
6246                         return (0);
6247                 tmp += strlen(pattern->sp_arg);
6248                 if (tmp != fmri + strlen(fmri) && tmp[0] != ':' &&
6249                     tmp[-1] != ':')
6250                         return (0);
6251 
6252                 /*
6253                  * If the user has supplied a short pattern that matches
6254                  * 'svc:/' or 'lrc:/', ignore it.
6255                  */
6256                 if (tmp <= fmri + 4)
6257                         return (0);
6258 
6259                 return (1);
6260         }
6261 
6262         return (0);
6263 }
6264 
6265 /*
6266  * Attempts to match the given FMRI against a set of patterns, keeping track of
6267  * the results.
6268  */
6269 static scf_error_t
6270 scf_pattern_match(scf_matchkey_t **htable, char *fmri, const char *legacy,
6271     int npattern, scf_pattern_t *pattern, int svc_explicit)
6272 {
6273         int i;
6274         int ret = 0;
6275 
6276         for (i = 0; i < npattern; i++) {
6277                 if (scf_cmp_pattern(fmri, &pattern[i]) &&
6278                     (ret = scf_add_match(htable, fmri,
6279                     legacy, &pattern[i], svc_explicit)) != 0)
6280                         return (ret);
6281         }
6282 
6283         return (0);
6284 }
6285 
6286 /*
6287  * Construct an error message from a provided format string and include all
6288  * of the matched FMRIs.
6289  */
6290 static char *
6291 scf_multiple_match_error(scf_pattern_t *pattern, const char *format)
6292 {
6293         scf_match_t *match;
6294         size_t len, off;
6295         char *msg;
6296 
6297         /*
6298          * Note that strlen(format) includes the length of '%s', which
6299          * accounts for the terminating null byte.
6300          */
6301         assert(strstr(format, "%s") != NULL);
6302         len = strlen(format) + strlen(pattern->sp_arg);
6303         for (match = pattern->sp_matches; match != NULL;
6304             match = match->sm_next)
6305                 len += strlen(match->sm_key->sk_fmri) + 2;
6306 
6307         if ((msg = malloc(len)) == NULL)
6308                 return (NULL);
6309 
6310         (void) snprintf(msg, len, format, pattern->sp_arg);
6311         off = strlen(msg);
6312         for (match = pattern->sp_matches; match != NULL;
6313             match = match->sm_next) {
6314                 assert(off < len);
6315                 off += snprintf(msg + off, len - off, "\t%s\n",
6316                     match->sm_key->sk_fmri);
6317         }
6318 
6319         return (msg);
6320 }
6321 
6322 /*
6323  * Fails with _INVALID_ARGUMENT, _HANDLE_DESTROYED, _INTERNAL (bad server
6324  * response or id in use), _NO_MEMORY, _HANDLE_MISMATCH, _CONSTRAINT_VIOLATED,
6325  * _NOT_FOUND, _NOT_BOUND, _CONNECTION_BROKEN, _NOT_SET, _DELETED,
6326  * _NO_RESOURCES, _BACKEND_ACCESS, _TYPE_MISMATCH.
6327  */
6328 scf_error_t
6329 scf_walk_fmri(scf_handle_t *h, int argc, char **argv, int flags,
6330     scf_walk_callback callback, void *data, int *err,
6331     void (*errfunc)(const char *, ...))
6332 {
6333         scf_pattern_t *pattern = NULL;
6334         int i;
6335         char *fmri = NULL;
6336         ssize_t max_fmri_length;
6337         scf_service_t *svc = NULL;
6338         scf_instance_t *inst = NULL;
6339         scf_iter_t *iter = NULL, *sciter = NULL, *siter = NULL;
6340         scf_scope_t *scope = NULL;
6341         scf_propertygroup_t *pg = NULL;
6342         scf_property_t *prop = NULL;
6343         scf_value_t *value = NULL;
6344         int ret = 0;
6345         scf_matchkey_t **htable = NULL;
6346         int pattern_search = 0;
6347         ssize_t max_name_length;
6348         char *pgname = NULL;
6349         scf_walkinfo_t info;
6350 
6351 #ifndef NDEBUG
6352         if (flags & SCF_WALK_EXPLICIT)
6353                 assert(flags & SCF_WALK_SERVICE);
6354         if (flags & SCF_WALK_NOINSTANCE)
6355                 assert(flags & SCF_WALK_SERVICE);
6356         if (flags & SCF_WALK_PROPERTY)
6357                 assert(!(flags & SCF_WALK_LEGACY));
6358 #endif
6359 
6360         /*
6361          * Setup initial variables
6362          */
6363         max_fmri_length = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH);
6364         assert(max_fmri_length != -1);
6365         max_name_length = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH);
6366         assert(max_name_length != -1);
6367 
6368         if ((fmri = malloc(max_fmri_length + 1)) == NULL ||
6369             (pgname = malloc(max_name_length + 1)) == NULL) {
6370                 ret = SCF_ERROR_NO_MEMORY;
6371                 goto error;
6372         }
6373 
6374         if (argc == 0) {
6375                 pattern = NULL;
6376         } else if ((pattern = calloc(argc, sizeof (scf_pattern_t)))
6377             == NULL) {
6378                 ret = SCF_ERROR_NO_MEMORY;
6379                 goto error;
6380         }
6381 
6382         if ((htable = calloc(WALK_HTABLE_SIZE, sizeof (void *))) == NULL) {
6383                 ret = SCF_ERROR_NO_MEMORY;
6384                 goto error;
6385         }
6386 
6387         if ((inst = scf_instance_create(h)) == NULL ||
6388             (svc = scf_service_create(h)) == NULL ||
6389             (iter = scf_iter_create(h)) == NULL ||
6390             (sciter = scf_iter_create(h)) == NULL ||
6391             (siter = scf_iter_create(h)) == NULL ||
6392             (scope = scf_scope_create(h)) == NULL ||
6393             (pg = scf_pg_create(h)) == NULL ||
6394             (prop = scf_property_create(h)) == NULL ||
6395             (value = scf_value_create(h)) == NULL) {
6396                 ret = scf_error();
6397                 goto error;
6398         }
6399 
6400         /*
6401          * For each fmri given, we first check to see if it's a full service,
6402          * instance, property group, or property FMRI.  This avoids having to do
6403          * the (rather expensive) walk of all instances.  Any element which does
6404          * not match a full fmri is identified as a globbed pattern or a partial
6405          * fmri and stored in a private array when walking instances.
6406          */
6407         for (i = 0; i < argc; i++) {
6408                 const char *scope_name, *svc_name, *inst_name, *pg_name;
6409                 const char *prop_name;
6410 
6411                 if (strlen(argv[i]) > max_fmri_length) {
6412                         errfunc(scf_get_msg(SCF_MSG_ARGTOOLONG), argv[i]);
6413                         if (err != NULL)
6414                                 *err = UU_EXIT_FATAL;
6415                         continue;
6416                 }
6417 
6418                 (void) strcpy(fmri, argv[i]);
6419                 if (scf_parse_svc_fmri(fmri, &scope_name, &svc_name, &inst_name,
6420                     &pg_name, &prop_name) != SCF_SUCCESS)
6421                         goto badfmri;
6422 
6423                 /*
6424                  * If the user has specified SCF_WALK_PROPERTY, allow property
6425                  * groups and properties.
6426                  */
6427                 if (pg_name != NULL || prop_name != NULL) {
6428                         if (!(flags & SCF_WALK_PROPERTY))
6429                                 goto badfmri;
6430 
6431                         if (scf_handle_decode_fmri(h, argv[i], NULL, NULL,
6432                             NULL, pg, prop, 0) != 0)
6433                                 goto badfmri;
6434 
6435                         if (scf_pg_get_name(pg, NULL, 0) < 0 &&
6436                             scf_property_get_name(prop, NULL, 0) < 0)
6437                                 goto badfmri;
6438 
6439                         if (scf_canonify_fmri(argv[i], fmri, max_fmri_length)
6440                             <= 0) {
6441                                 /*
6442                                  * scf_parse_fmri() should have caught this.
6443                                  */
6444                                 abort();
6445                         }
6446 
6447                         if ((ret = scf_add_match(htable, fmri, NULL,
6448                             &pattern[i], flags & SCF_WALK_EXPLICIT)) != 0)
6449                                 goto error;
6450 
6451                         if ((pattern[i].sp_arg = strdup(argv[i])) == NULL) {
6452                                 ret = SCF_ERROR_NO_MEMORY;
6453                                 goto error;
6454                         }
6455                         pattern[i].sp_type = PATTERN_EXACT;
6456                 }
6457 
6458                 /*
6459                  * We need at least a service name
6460                  */
6461                 if (scope_name == NULL || svc_name == NULL)
6462                         goto badfmri;
6463 
6464                 /*
6465                  * If we have a fully qualified instance, add it to our list of
6466                  * fmris to watch.
6467                  */
6468                 if (inst_name != NULL) {
6469                         if (flags & SCF_WALK_NOINSTANCE)
6470                                 goto badfmri;
6471 
6472                         if (scf_handle_decode_fmri(h, argv[i], NULL, NULL,
6473                             inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != 0)
6474                                 goto badfmri;
6475 
6476                         if (scf_canonify_fmri(argv[i], fmri, max_fmri_length)
6477                             <= 0)
6478                                 goto badfmri;
6479 
6480                         if ((ret = scf_add_match(htable, fmri, NULL,
6481                             &pattern[i], flags & SCF_WALK_EXPLICIT)) != 0)
6482                                 goto error;
6483 
6484                         if ((pattern[i].sp_arg = strdup(argv[i])) == NULL) {
6485                                 ret = SCF_ERROR_NO_MEMORY;
6486                                 goto error;
6487                         }
6488                         pattern[i].sp_type = PATTERN_EXACT;
6489 
6490                         continue;
6491                 }
6492 
6493                 if (scf_handle_decode_fmri(h, argv[i], NULL, svc,
6494                     NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) !=
6495                     SCF_SUCCESS)
6496                         goto badfmri;
6497 
6498                 /*
6499                  * If the user allows for bare services, then simply
6500                  * pass this service on.
6501                  */
6502                 if (flags & SCF_WALK_SERVICE) {
6503                         if (scf_service_to_fmri(svc, fmri,
6504                             max_fmri_length + 1) <= 0) {
6505                                 ret = scf_error();
6506                                 goto error;
6507                         }
6508 
6509                         if ((ret = scf_add_match(htable, fmri, NULL,
6510                             &pattern[i], flags & SCF_WALK_EXPLICIT)) != 0)
6511                                 goto error;
6512 
6513                         if ((pattern[i].sp_arg = strdup(argv[i]))
6514                             == NULL) {
6515                                 ret = SCF_ERROR_NO_MEMORY;
6516                                 goto error;
6517                         }
6518                         pattern[i].sp_type = PATTERN_EXACT;
6519                         continue;
6520                 }
6521 
6522                 if (flags & SCF_WALK_NOINSTANCE)
6523                         goto badfmri;
6524 
6525                 /*
6526                  * Otherwise, iterate over all instances in the service.
6527                  */
6528                 if (scf_iter_service_instances(iter, svc) !=
6529                     SCF_SUCCESS) {
6530                         ret = scf_error();
6531                         goto error;
6532                 }
6533 
6534                 for (;;) {
6535                         ret = scf_iter_next_instance(iter, inst);
6536                         if (ret == 0)
6537                                 break;
6538                         if (ret != 1) {
6539                                 ret = scf_error();
6540                                 goto error;
6541                         }
6542 
6543                         if (scf_instance_to_fmri(inst, fmri,
6544                             max_fmri_length + 1) == -1)
6545                                 goto badfmri;
6546 
6547                         if ((ret = scf_add_match(htable, fmri, NULL,
6548                             &pattern[i], flags & SCF_WALK_EXPLICIT)) != 0)
6549                                 goto error;
6550                 }
6551 
6552                 if ((pattern[i].sp_arg = strdup(argv[i])) == NULL) {
6553                         ret = SCF_ERROR_NO_MEMORY;
6554                         goto error;
6555                 }
6556                 pattern[i].sp_type = PATTERN_EXACT;
6557 
6558                 continue;
6559 
6560 badfmri:
6561 
6562                 /*
6563                  * If we got here because of a fatal error, bail out
6564                  * immediately.
6565                  */
6566                 if (scf_error() == SCF_ERROR_CONNECTION_BROKEN) {
6567                         ret = scf_error();
6568                         goto error;
6569                 }
6570 
6571                 /*
6572                  * At this point we failed to interpret the argument as a
6573                  * complete fmri, so mark it as a partial or globbed FMRI for
6574                  * later processing.
6575                  */
6576                 if (strpbrk(argv[i], "*?[") != NULL) {
6577                         /*
6578                          * Prepend svc:/ to patterns which don't begin with * or
6579                          * svc: or lrc:.
6580                          */
6581                         pattern[i].sp_type = PATTERN_GLOB;
6582                         if (argv[i][0] == '*' ||
6583                             (strlen(argv[i]) >= 4 && argv[i][3] == ':'))
6584                                 pattern[i].sp_arg = strdup(argv[i]);
6585                         else {
6586                                 pattern[i].sp_arg = malloc(strlen(argv[i]) + 6);
6587                                 if (pattern[i].sp_arg != NULL)
6588                                         (void) snprintf(pattern[i].sp_arg,
6589                                             strlen(argv[i]) + 6, "svc:/%s",
6590                                             argv[i]);
6591                         }
6592                 } else {
6593                         pattern[i].sp_type = PATTERN_PARTIAL;
6594                         pattern[i].sp_arg = strdup(argv[i]);
6595                 }
6596                 pattern_search = 1;
6597                 if (pattern[i].sp_arg == NULL) {
6598                         ret = SCF_ERROR_NO_MEMORY;
6599                         goto error;
6600                 }
6601         }
6602 
6603         if (pattern_search || argc == 0) {
6604                 /*
6605                  * We have a set of patterns to search for.  Iterate over all
6606                  * instances and legacy services searching for matches.
6607                  */
6608                 if (scf_handle_get_local_scope(h, scope) != 0) {
6609                         ret = scf_error();
6610                         goto error;
6611                 }
6612 
6613                 if (scf_iter_scope_services(sciter, scope) != 0) {
6614                         ret = scf_error();
6615                         goto error;
6616                 }
6617 
6618                 for (;;) {
6619                         ret = scf_iter_next_service(sciter, svc);
6620                         if (ret == 0)
6621                                 break;
6622                         if (ret != 1) {
6623                                 ret = scf_error();
6624                                 goto error;
6625                         }
6626 
6627                         if (flags & SCF_WALK_SERVICE) {
6628                                 /*
6629                                  * If the user is requesting bare services, try
6630                                  * to match the service first.
6631                                  */
6632                                 if (scf_service_to_fmri(svc, fmri,
6633                                     max_fmri_length + 1) < 0) {
6634                                         ret = scf_error();
6635                                         goto error;
6636                                 }
6637 
6638                                 if (argc == 0) {
6639                                         info.fmri = fmri;
6640                                         info.scope = scope;
6641                                         info.svc = svc;
6642                                         info.inst = NULL;
6643                                         info.pg = NULL;
6644                                         info.prop = NULL;
6645                                         if ((ret = callback(data, &info)) != 0)
6646                                                 goto error;
6647                                         continue;
6648                                 } else if ((ret = scf_pattern_match(htable,
6649                                     fmri, NULL, argc, pattern,
6650                                     flags & SCF_WALK_EXPLICIT)) != 0) {
6651                                         goto error;
6652                                 }
6653                         }
6654 
6655                         if (flags & SCF_WALK_NOINSTANCE)
6656                                 continue;
6657 
6658                         /*
6659                          * Iterate over all instances in the service.
6660                          */
6661                         if (scf_iter_service_instances(siter, svc) != 0) {
6662                                 if (scf_error() != SCF_ERROR_DELETED) {
6663                                         ret = scf_error();
6664                                         goto error;
6665                                 }
6666                                 continue;
6667                         }
6668 
6669                         for (;;) {
6670                                 ret = scf_iter_next_instance(siter, inst);
6671                                 if (ret == 0)
6672                                         break;
6673                                 if (ret != 1) {
6674                                         if (scf_error() != SCF_ERROR_DELETED) {
6675                                                 ret = scf_error();
6676                                                 goto error;
6677                                         }
6678                                         break;
6679                                 }
6680 
6681                                 if (scf_instance_to_fmri(inst, fmri,
6682                                     max_fmri_length + 1) < 0) {
6683                                         ret = scf_error();
6684                                         goto error;
6685                                 }
6686 
6687                                 /*
6688                                  * Without arguments, execute the callback
6689                                  * immediately.
6690                                  */
6691                                 if (argc == 0) {
6692                                         info.fmri = fmri;
6693                                         info.scope = scope;
6694                                         info.svc = svc;
6695                                         info.inst = inst;
6696                                         info.pg = NULL;
6697                                         info.prop = NULL;
6698                                         if ((ret = callback(data, &info)) != 0)
6699                                                 goto error;
6700                                 } else if ((ret = scf_pattern_match(htable,
6701                                     fmri, NULL, argc, pattern,
6702                                     flags & SCF_WALK_EXPLICIT)) != 0) {
6703                                         goto error;
6704                                 }
6705                         }
6706                 }
6707 
6708                 /*
6709                  * Search legacy services
6710                  */
6711                 if ((flags & SCF_WALK_LEGACY)) {
6712                         if (scf_scope_get_service(scope, SCF_LEGACY_SERVICE,
6713                             svc) != 0) {
6714                                 if (scf_error() != SCF_ERROR_NOT_FOUND) {
6715                                         ret = scf_error();
6716                                         goto error;
6717                                 }
6718 
6719                                 goto nolegacy;
6720                         }
6721 
6722                         if (scf_iter_service_pgs_typed(iter, svc,
6723                             SCF_GROUP_FRAMEWORK) != SCF_SUCCESS) {
6724                                 ret = scf_error();
6725                                 goto error;
6726                         }
6727 
6728                         (void) strcpy(fmri, LEGACY_SCHEME);
6729 
6730                         for (;;) {
6731                                 ret = scf_iter_next_pg(iter, pg);
6732                                 if (ret == -1) {
6733                                         ret = scf_error();
6734                                         goto error;
6735                                 }
6736                                 if (ret == 0)
6737                                         break;
6738 
6739                                 if (scf_pg_get_property(pg,
6740                                     SCF_LEGACY_PROPERTY_NAME, prop) == -1) {
6741                                         ret = scf_error();
6742                                         if (ret == SCF_ERROR_DELETED ||
6743                                             ret == SCF_ERROR_NOT_FOUND) {
6744                                                 ret = 0;
6745                                                 continue;
6746                                         }
6747                                         goto error;
6748                                 }
6749 
6750                                 if (scf_property_is_type(prop, SCF_TYPE_ASTRING)
6751                                     != SCF_SUCCESS) {
6752                                         if (scf_error() == SCF_ERROR_DELETED)
6753                                                 continue;
6754                                         ret = scf_error();
6755                                         goto error;
6756                                 }
6757 
6758                                 if (scf_property_get_value(prop, value) !=
6759                                     SCF_SUCCESS)
6760                                         continue;
6761 
6762                                 if (scf_value_get_astring(value,
6763                                     fmri + sizeof (LEGACY_SCHEME) - 1,
6764                                     max_fmri_length + 2 -
6765                                     sizeof (LEGACY_SCHEME)) <= 0)
6766                                         continue;
6767 
6768                                 if (scf_pg_get_name(pg, pgname,
6769                                     max_name_length + 1) <= 0) {
6770                                         if (scf_error() == SCF_ERROR_DELETED)
6771                                                 continue;
6772                                         ret = scf_error();
6773                                         goto error;
6774                                 }
6775 
6776                                 if (argc == 0) {
6777                                         info.fmri = fmri;
6778                                         info.scope = scope;
6779                                         info.svc = NULL;
6780                                         info.inst = NULL;
6781                                         info.pg = pg;
6782                                         info.prop = NULL;
6783                                         if ((ret = callback(data, &info)) != 0)
6784                                                 goto error;
6785                                 } else if ((ret = scf_pattern_match(htable,
6786                                     fmri, pgname, argc, pattern,
6787                                     flags & SCF_WALK_EXPLICIT)) != 0)
6788                                         goto error;
6789                         }
6790 
6791                 }
6792         }
6793 nolegacy:
6794         ret = 0;
6795 
6796         if (argc == 0)
6797                 goto error;
6798 
6799         /*
6800          * Check all patterns, and see if we have that any that didn't match
6801          * or any that matched multiple instances.  For svcprop, add up the
6802          * total number of matching keys.
6803          */
6804         info.count = 0;
6805         for (i = 0; i < argc; i++) {
6806                 scf_match_t *match;
6807 
6808                 if (pattern[i].sp_type == PATTERN_INVALID)
6809                         continue;
6810                 if (pattern[i].sp_matchcount == 0) {
6811                         scf_msg_t msgid;
6812                         /*
6813                          * Provide a useful error message based on the argument
6814                          * and the type of entity requested.
6815                          */
6816                         if (!(flags & SCF_WALK_LEGACY) &&
6817                             strncmp(pattern[i].sp_arg, "lrc:/", 5) == 0)
6818                                 msgid = SCF_MSG_PATTERN_LEGACY;
6819                         else if (flags & SCF_WALK_PROPERTY)
6820                                 msgid = SCF_MSG_PATTERN_NOENTITY;
6821                         else if (flags & SCF_WALK_NOINSTANCE)
6822                                 msgid = SCF_MSG_PATTERN_NOSERVICE;
6823                         else if (flags & SCF_WALK_SERVICE)
6824                                 msgid = SCF_MSG_PATTERN_NOINSTSVC;
6825                         else
6826                                 msgid = SCF_MSG_PATTERN_NOINSTANCE;
6827 
6828                         errfunc(scf_get_msg(msgid), pattern[i].sp_arg);
6829                         if (err)
6830                                 *err = UU_EXIT_FATAL;
6831                 } else if (!(flags & SCF_WALK_MULTIPLE) &&
6832                     pattern[i].sp_matchcount > 1) {
6833                         char *msg;
6834 
6835                         msg = scf_multiple_match_error(&pattern[i],
6836                             scf_get_msg(SCF_MSG_PATTERN_MULTIMATCH));
6837 
6838                         if (msg == NULL) {
6839                                 ret = SCF_ERROR_NO_MEMORY;
6840                                 goto error;
6841                         }
6842 
6843                         errfunc(msg);
6844 
6845                         if (err != NULL)
6846                                 *err = UU_EXIT_FATAL;
6847 
6848                         free(msg);
6849 
6850                         /*
6851                          * Set matchcount to 0 so the callback is not
6852                          * performed for this pattern.
6853                          */
6854                         pattern[i].sp_matchcount = 0;
6855 
6856                 } else if ((flags & SCF_WALK_UNIPARTIAL) &&
6857                     pattern[i].sp_type == PATTERN_PARTIAL &&
6858                     pattern[i].sp_matchcount > 1) {
6859                         char *msg;
6860 
6861                         msg = scf_multiple_match_error(&pattern[i],
6862                             scf_get_msg(SCF_MSG_PATTERN_MULTIPARTIAL));
6863 
6864                         if (msg == NULL) {
6865                                 ret = SCF_ERROR_NO_MEMORY;
6866                                 goto error;
6867                         }
6868 
6869                         errfunc(msg);
6870 
6871                         if (err != NULL)
6872                                 *err = UU_EXIT_FATAL;
6873 
6874                         free(msg);
6875 
6876                         /*
6877                          * Set matchcount to 0 so the callback is not
6878                          * performed for this pattern.
6879                          */
6880                         pattern[i].sp_matchcount = 0;
6881 
6882                 } else {
6883                         for (match = pattern[i].sp_matches; match != NULL;
6884                             match = match->sm_next) {
6885                                 if (!match->sm_key->sk_seen)
6886                                         info.count++;
6887                                 match->sm_key->sk_seen = 1;
6888                         }
6889                 }
6890         }
6891 
6892         /*
6893          * Clear 'sk_seen' for all keys.
6894          */
6895         for (i = 0; i < WALK_HTABLE_SIZE; i++) {
6896                 scf_matchkey_t *key;
6897                 for (key = htable[i]; key != NULL; key = key->sk_next)
6898                         key->sk_seen = 0;
6899         }
6900 
6901         /*
6902          * Iterate over all the FMRIs in our hash table and execute the
6903          * callback.
6904          */
6905         for (i = 0; i < argc; i++) {
6906                 scf_match_t *match;
6907                 scf_matchkey_t *key;
6908 
6909                 /*
6910                  * Ignore patterns which didn't match anything or
6911                  * for which the matchcount has been set to 0 due to an
6912                  * error detected above.
6913                  */
6914                 if (pattern[i].sp_matchcount == 0)
6915                         continue;
6916 
6917                 for (match = pattern[i].sp_matches; match != NULL;
6918                     match = match->sm_next) {
6919 
6920                         key = match->sm_key;
6921                         if (key->sk_seen)
6922                                 continue;
6923 
6924                         key->sk_seen = 1;
6925 
6926                         if (key->sk_legacy != NULL) {
6927                                 if (scf_scope_get_service(scope,
6928                                     "smf/legacy_run", svc) != 0) {
6929                                         ret = scf_error();
6930                                         goto error;
6931                                 }
6932 
6933                                 if (scf_service_get_pg(svc, key->sk_legacy,
6934                                     pg) != 0)
6935                                         continue;
6936 
6937                                 info.fmri = key->sk_fmri;
6938                                 info.scope = scope;
6939                                 info.svc = NULL;
6940                                 info.inst = NULL;
6941                                 info.pg = pg;
6942                                 info.prop = NULL;
6943                                 if ((ret = callback(data, &info)) != 0)
6944                                         goto error;
6945                         } else {
6946                                 if (scf_handle_decode_fmri(h, key->sk_fmri,
6947                                     scope, svc, inst, pg, prop, 0) !=
6948                                     SCF_SUCCESS)
6949                                         continue;
6950 
6951                                 info.fmri = key->sk_fmri;
6952                                 info.scope = scope;
6953                                 info.svc = svc;
6954                                 if (scf_instance_get_name(inst, NULL, 0) < 0) {
6955                                         if (scf_error() ==
6956                                             SCF_ERROR_CONNECTION_BROKEN) {
6957                                                 ret = scf_error();
6958                                                 goto error;
6959                                         }
6960                                         info.inst = NULL;
6961                                 } else {
6962                                         info.inst = inst;
6963                                 }
6964                                 if (scf_pg_get_name(pg, NULL, 0) < 0) {
6965                                         if (scf_error() ==
6966                                             SCF_ERROR_CONNECTION_BROKEN) {
6967                                                 ret = scf_error();
6968                                                 goto error;
6969                                         }
6970                                         info.pg = NULL;
6971                                 } else {
6972                                         info.pg = pg;
6973                                 }
6974                                 if (scf_property_get_name(prop, NULL, 0) < 0) {
6975                                         if (scf_error() ==
6976                                             SCF_ERROR_CONNECTION_BROKEN) {
6977                                                 ret = scf_error();
6978                                                 goto error;
6979                                         }
6980                                         info.prop = NULL;
6981                                 } else {
6982                                         info.prop = prop;
6983                                 }
6984 
6985                                 if ((ret = callback(data, &info)) != 0)
6986                                         goto error;
6987                         }
6988                 }
6989         }
6990 
6991 error:
6992         if (htable) {
6993                 scf_matchkey_t *key, *next;
6994 
6995                 for (i = 0; i < WALK_HTABLE_SIZE; i++) {
6996 
6997                         for (key = htable[i]; key != NULL;
6998                             key = next) {
6999 
7000                                 next = key->sk_next;
7001 
7002                                 if (key->sk_fmri != NULL)
7003                                         free(key->sk_fmri);
7004                                 if (key->sk_legacy != NULL)
7005                                         free(key->sk_legacy);
7006                                 free(key);
7007                         }
7008                 }
7009                 free(htable);
7010         }
7011         if (pattern != NULL) {
7012                 for (i = 0; i < argc; i++) {
7013                         scf_match_t *match, *next;
7014 
7015                         if (pattern[i].sp_arg != NULL)
7016                                 free(pattern[i].sp_arg);
7017 
7018                         for (match = pattern[i].sp_matches; match != NULL;
7019                             match = next) {
7020 
7021                                 next = match->sm_next;
7022 
7023                                 free(match);
7024                         }
7025                 }
7026                 free(pattern);
7027         }
7028 
7029         free(fmri);
7030         free(pgname);
7031 
7032         scf_value_destroy(value);
7033         scf_property_destroy(prop);
7034         scf_pg_destroy(pg);
7035         scf_scope_destroy(scope);
7036         scf_iter_destroy(siter);
7037         scf_iter_destroy(sciter);
7038         scf_iter_destroy(iter);
7039         scf_instance_destroy(inst);
7040         scf_service_destroy(svc);
7041 
7042         return (ret);
7043 }
7044 
7045 /*
7046  * scf_encode32() is an implementation of Base32 encoding as described in
7047  * section 6 of RFC 4648 - "The Base16, Base32, and Base64 Data
7048  * Encodings". See http://www.ietf.org/rfc/rfc4648.txt?number=4648.  The
7049  * input stream is divided into groups of 5 characters (40 bits).  Each
7050  * group is encoded into 8 output characters where each output character
7051  * represents 5 bits of input.
7052  *
7053  * If the input is not an even multiple of 5 characters, the output will be
7054  * padded so that the output is an even multiple of 8 characters.  The
7055  * standard specifies that the pad character is '='.  Unfortunately, '=' is
7056  * not a legal character in SMF property names.  Thus, the caller can
7057  * specify an alternate pad character with the pad argument.  If pad is 0,
7058  * scf_encode32() will use '='.  Note that use of anything other than '='
7059  * produces output that is not in conformance with RFC 4648.  It is
7060  * suitable, however, for internal use of SMF software.  When the encoded
7061  * data is used as part of an SMF property name, SCF_ENCODE32_PAD should be
7062  * used as the pad character.
7063  *
7064  * Arguments:
7065  *      input -         Address of the buffer to be encoded.
7066  *      inlen -         Number of characters at input.
7067  *      output -        Address of the buffer to receive the encoded data.
7068  *      outmax -        Size of the buffer at output.
7069  *      outlen -        If it is not NULL, outlen receives the number of
7070  *                      bytes placed in output.
7071  *      pad -           Alternate padding character.
7072  *
7073  * Returns:
7074  *      0       Buffer was successfully encoded.
7075  *      -1      Indicates output buffer too small, or pad is one of the
7076  *              standard encoding characters.
7077  */
7078 int
7079 scf_encode32(const char *input, size_t inlen, char *output, size_t outmax,
7080     size_t *outlen, char pad)
7081 {
7082         uint_t group_size = 5;
7083         uint_t i;
7084         const unsigned char *in = (const unsigned char *)input;
7085         size_t olen;
7086         uchar_t *out = (uchar_t *)output;
7087         uint_t oval;
7088         uint_t pad_count;
7089 
7090         /* Verify that there is enough room for the output. */
7091         olen = ((inlen + (group_size - 1)) / group_size) * 8;
7092         if (outlen)
7093                 *outlen = olen;
7094         if (olen > outmax)
7095                 return (-1);
7096 
7097         /* If caller did not provide pad character, use the default. */
7098         if (pad == 0) {
7099                 pad = '=';
7100         } else {
7101                 /*
7102                  * Make sure that caller's pad is not one of the encoding
7103                  * characters.
7104                  */
7105                 for (i = 0; i < sizeof (base32) - 1; i++) {
7106                         if (pad == base32[i])
7107                                 return (-1);
7108                 }
7109         }
7110 
7111         /* Process full groups capturing 5 bits per output character. */
7112         for (; inlen >= group_size; in += group_size, inlen -= group_size) {
7113                 /*
7114                  * The comments in this section number the bits in an
7115                  * 8 bit byte 0 to 7.  The high order bit is bit 7 and
7116                  * the low order bit is bit 0.
7117                  */
7118 
7119                 /* top 5 bits (7-3) from in[0] */
7120                 *out++ = base32[in[0] >> 3];
7121                 /* bits 2-0 from in[0] and top 2 (7-6) from in[1] */
7122                 *out++ = base32[((in[0] << 2) & 0x1c) | (in[1] >> 6)];
7123                 /* 5 bits (5-1) from in[1] */
7124                 *out++ = base32[(in[1] >> 1) & 0x1f];
7125                 /* low bit (0) from in[1] and top 4 (7-4) from in[2] */
7126                 *out++ = base32[((in[1] << 4) & 0x10) | ((in[2] >> 4) & 0xf)];
7127                 /* low 4 (3-0) from in[2] and top bit (7) from in[3] */
7128                 *out++ = base32[((in[2] << 1) & 0x1e) | (in[3] >> 7)];
7129                 /* 5 bits (6-2) from in[3] */
7130                 *out++ = base32[(in[3] >> 2) & 0x1f];
7131                 /* low 2 (1-0) from in[3] and top 3 (7-5) from in[4] */
7132                 *out++ = base32[((in[3] << 3) & 0x18) | (in[4] >> 5)];
7133                 /* low 5 (4-0) from in[4] */
7134                 *out++ = base32[in[4] & 0x1f];
7135         }
7136 
7137         /* Take care of final input bytes. */
7138         pad_count = 0;
7139         if (inlen) {
7140                 /* top 5 bits (7-3) from in[0] */
7141                 *out++ = base32[in[0] >> 3];
7142                 /*
7143                  * low 3 (2-0) from in[0] and top 2 (7-6) from in[1] if
7144                  * available.
7145                  */
7146                 oval = (in[0] << 2) & 0x1c;
7147                 if (inlen == 1) {
7148                         *out++ = base32[oval];
7149                         pad_count = 6;
7150                         goto padout;
7151                 }
7152                 oval |= in[1] >> 6;
7153                 *out++ = base32[oval];
7154                 /* 5 bits (5-1) from in[1] */
7155                 *out++ = base32[(in[1] >> 1) & 0x1f];
7156                 /*
7157                  * low bit (0) from in[1] and top 4 (7-4) from in[2] if
7158                  * available.
7159                  */
7160                 oval = (in[1] << 4) & 0x10;
7161                 if (inlen == 2) {
7162                         *out++ = base32[oval];
7163                         pad_count = 4;
7164                         goto padout;
7165                 }
7166                 oval |= in[2] >> 4;
7167                 *out++ = base32[oval];
7168                 /*
7169                  * low 4 (3-0) from in[2] and top 1 (7) from in[3] if
7170                  * available.
7171                  */
7172                 oval = (in[2] << 1) & 0x1e;
7173                 if (inlen == 3) {
7174                         *out++ = base32[oval];
7175                         pad_count = 3;
7176                         goto padout;
7177                 }
7178                 oval |= in[3] >> 7;
7179                 *out++ = base32[oval];
7180                 /* 5 bits (6-2) from in[3] */
7181                 *out++ = base32[(in[3] >> 2) & 0x1f];
7182                 /* low 2 bits (1-0) from in[3] */
7183                 *out++ = base32[(in[3] << 3) & 0x18];
7184                 pad_count = 1;
7185         }
7186 padout:
7187         /*
7188          * Pad the output so that it is a multiple of 8 bytes.
7189          */
7190         for (; pad_count > 0; pad_count--) {
7191                 *out++ = pad;
7192         }
7193 
7194         /*
7195          * Null terminate the output if there is enough room.
7196          */
7197         if (olen < outmax)
7198                 *out = 0;
7199 
7200         return (0);
7201 }
7202 
7203 /*
7204  * scf_decode32() is an implementation of Base32 decoding as described in
7205  * section 6 of RFC 4648 - "The Base16, Base32, and Base64 Data
7206  * Encodings". See http://www.ietf.org/rfc/rfc4648.txt?number=4648.  The
7207  * input stream is divided into groups of 8 encoded characters.  Each
7208  * encoded character represents 5 bits of data.  Thus, the 8 encoded
7209  * characters are used to produce 40 bits or 5 bytes of unencoded data in
7210  * outbuf.
7211  *
7212  * If the encoder did not have enough data to generate a mulitple of 8
7213  * characters of encoded data, it used a pad character to get to the 8
7214  * character boundry. The standard specifies that the pad character is '='.
7215  * Unfortunately, '=' is not a legal character in SMF property names.
7216  * Thus, the caller can specify an alternate pad character with the pad
7217  * argument.  If pad is 0, scf_decode32() will use '='.  Note that use of
7218  * anything other than '=' is not in conformance with RFC 4648.  It is
7219  * suitable, however, for internal use of SMF software.  When the encoded
7220  * data is used in SMF property names, SCF_ENCODE32_PAD should be used as
7221  * the pad character.
7222  *
7223  * Arguments:
7224  *      in -            Buffer of encoded characters.
7225  *      inlen -         Number of characters at in.
7226  *      outbuf -        Buffer to receive the decoded bytes.  It can be the
7227  *                      same buffer as in.
7228  *      outmax -        Size of the buffer at outbuf.
7229  *      outlen -        If it is not NULL, outlen receives the number of
7230  *                      bytes placed in output.
7231  *      pad -           Alternate padding character.
7232  *
7233  * Returns:
7234  *      0       Buffer was successfully decoded.
7235  *      -1      Indicates an invalid input character, output buffer too
7236  *              small, or pad is one of the standard encoding characters.
7237  */
7238 int
7239 scf_decode32(const char *in, size_t inlen, char *outbuf, size_t outmax,
7240     size_t *outlen, char pad)
7241 {
7242         char *bufend = outbuf + outmax;
7243         char c;
7244         uint_t count;
7245         uint32_t g[DECODE32_GS];
7246         size_t i;
7247         uint_t j;
7248         char *out = outbuf;
7249         boolean_t pad_seen = B_FALSE;
7250 
7251         /* If caller did not provide pad character, use the default. */
7252         if (pad == 0) {
7253                 pad = '=';
7254         } else {
7255                 /*
7256                  * Make sure that caller's pad is not one of the encoding
7257                  * characters.
7258                  */
7259                 for (i = 0; i < sizeof (base32) - 1; i++) {
7260                         if (pad == base32[i])
7261                                 return (-1);
7262                 }
7263         }
7264 
7265         i = 0;
7266         while ((i < inlen) && (out < bufend)) {
7267                 /* Get a group of input characters. */
7268                 for (j = 0, count = 0;
7269                     (j < DECODE32_GS) && (i < inlen);
7270                     i++) {
7271                         c = in[i];
7272                         /*
7273                          * RFC 4648 allows for the encoded data to be split
7274                          * into multiple lines, so skip carriage returns
7275                          * and new lines.
7276                          */
7277                         if ((c == '\r') || (c == '\n'))
7278                                 continue;
7279                         if ((pad_seen == B_TRUE) && (c != pad)) {
7280                                 /* Group not completed by pads */
7281                                 return (-1);
7282                         }
7283                         if ((c < 0) || (c >= sizeof (index32))) {
7284                                 /* Illegal character. */
7285                                 return (-1);
7286                         }
7287                         if (c == pad) {
7288                                 pad_seen = B_TRUE;
7289                                 continue;
7290                         }
7291                         if ((g[j++] = index32[c]) == 0xff) {
7292                                 /* Illegal character */
7293                                 return (-1);
7294                         }
7295                         count++;
7296                 }
7297 
7298                 /* Pack the group into five 8 bit bytes. */
7299                 if ((count >= 2) && (out < bufend)) {
7300                         /*
7301                          * Output byte 0:
7302                          *      5 bits (7-3) from g[0]
7303                          *      3 bits (2-0) from g[1] (4-2)
7304                          */
7305                         *out++ = (g[0] << 3) | ((g[1] >> 2) & 0x7);
7306                 }
7307                 if ((count >= 4) && (out < bufend)) {
7308                         /*
7309                          * Output byte 1:
7310                          *      2 bits (7-6) from g[1] (1-0)
7311                          *      5 bits (5-1) from g[2] (4-0)
7312                          *      1 bit (0) from g[3] (4)
7313                          */
7314                         *out++ = (g[1] << 6) | (g[2] << 1) | \
7315                             ((g[3] >> 4) & 0x1);
7316                 }
7317                 if ((count >= 5) && (out < bufend)) {
7318                         /*
7319                          * Output byte 2:
7320                          *      4 bits (7-4) from g[3] (3-0)
7321                          *      4 bits (3-0) from g[4] (4-1)
7322                          */
7323                         *out++ = (g[3] << 4) | ((g[4] >> 1) & 0xf);
7324                 }
7325                 if ((count >= 7) && (out < bufend)) {
7326                         /*
7327                          * Output byte 3:
7328                          *      1 bit (7) from g[4] (0)
7329                          *      5 bits (6-2) from g[5] (4-0)
7330                          *      2 bits (0-1) from g[6] (4-3)
7331                          */
7332                         *out++ = (g[4] << 7) | (g[5] << 2) |
7333                             ((g[6] >> 3) & 0x3);
7334                 }
7335                 if ((count == 8) && (out < bufend)) {
7336                         /*
7337                          * Output byte 4;
7338                          *      3 bits (7-5) from g[6] (2-0)
7339                          *      5 bits (4-0) from g[7] (4-0)
7340                          */
7341                         *out++ = (g[6] << 5) | g[7];
7342                 }
7343         }
7344         if (i < inlen) {
7345                 /* Did not process all input characters. */
7346                 return (-1);
7347         }
7348         if (outlen)
7349                 *outlen = out - outbuf;
7350         /* Null terminate the output if there is room. */
7351         if (out < bufend)
7352                 *out = 0;
7353         return (0);
7354 }
7355 
7356 
7357 /*
7358  * _scf_request_backup:  a simple wrapper routine
7359  */
7360 int
7361 _scf_request_backup(scf_handle_t *h, const char *name)
7362 {
7363         struct rep_protocol_backup_request request;
7364         struct rep_protocol_response response;
7365 
7366         int r;
7367 
7368         if (strlcpy(request.rpr_name, name, sizeof (request.rpr_name)) >=
7369             sizeof (request.rpr_name))
7370                 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
7371 
7372         (void) pthread_mutex_lock(&h->rh_lock);
7373         request.rpr_request = REP_PROTOCOL_BACKUP;
7374         request.rpr_changeid = handle_next_changeid(h);
7375 
7376         r = make_door_call(h, &request, sizeof (request),
7377             &response, sizeof (response));
7378         (void) pthread_mutex_unlock(&h->rh_lock);
7379 
7380         if (r < 0) {
7381                 DOOR_ERRORS_BLOCK(r);
7382         }
7383 
7384         if (response.rpr_response != REP_PROTOCOL_SUCCESS)
7385                 return (scf_set_error(proto_error(response.rpr_response)));
7386         return (SCF_SUCCESS);
7387 }
7388 
7389 /*
7390  * Request svc.configd daemon to switch repository database.
7391  *
7392  * Can fail:
7393  *
7394  *      _NOT_BOUND              handle is not bound
7395  *      _CONNECTION_BROKEN      server is not reachable
7396  *      _INTERNAL               file operation error
7397  *                              the server response is too big
7398  *      _PERMISSION_DENIED      not enough privileges to do request
7399  *      _BACKEND_READONLY       backend is not writable
7400  *      _BACKEND_ACCESS         backend access fails
7401  *      _NO_RESOURCES           svc.configd is out of memory
7402  */
7403 int
7404 _scf_repository_switch(scf_handle_t *h, int scf_sw)
7405 {
7406         struct rep_protocol_switch_request request;
7407         struct rep_protocol_response response;
7408         int     r;
7409 
7410         /*
7411          * Setup request protocol and make door call
7412          * Hold rh_lock lock before handle_next_changeid call
7413          */
7414         (void) pthread_mutex_lock(&h->rh_lock);
7415 
7416         request.rpr_flag = scf_sw;
7417         request.rpr_request = REP_PROTOCOL_SWITCH;
7418         request.rpr_changeid = handle_next_changeid(h);
7419 
7420         r = make_door_call(h, &request, sizeof (request),
7421             &response, sizeof (response));
7422 
7423         (void) pthread_mutex_unlock(&h->rh_lock);
7424 
7425         if (r < 0) {
7426                 DOOR_ERRORS_BLOCK(r);
7427         }
7428 
7429         /*
7430          * Pass protocol error up
7431          */
7432         if (response.rpr_response != REP_PROTOCOL_SUCCESS)
7433                 return (scf_set_error(proto_error(response.rpr_response)));
7434 
7435         return (SCF_SUCCESS);
7436 }
7437 
7438 int
7439 _scf_pg_is_read_protected(const scf_propertygroup_t *pg, boolean_t *out)
7440 {
7441         char buf[REP_PROTOCOL_NAME_LEN];
7442         ssize_t res;
7443 
7444         res = datael_get_name(&pg->rd_d, buf, sizeof (buf),
7445             RP_ENTITY_NAME_PGREADPROT);
7446 
7447         if (res == -1)
7448                 return (-1);
7449 
7450         if (uu_strtouint(buf, out, sizeof (*out), 0, 0, 1) == -1)
7451                 return (scf_set_error(SCF_ERROR_INTERNAL));
7452         return (SCF_SUCCESS);
7453 }
7454 
7455 /*
7456  * _scf_set_annotation: a wrapper to set the annotation fields for SMF
7457  * security auditing.
7458  *
7459  * Fails with following in scf_error_key thread specific data:
7460  *      _INVALID_ARGUMENT - operation or file too large
7461  *      _NOT_BOUND
7462  *      _CONNECTION_BROKEN
7463  *      _INTERNAL
7464  *      _NO_RESOURCES
7465  */
7466 int
7467 _scf_set_annotation(scf_handle_t *h, const char *operation, const char *file)
7468 {
7469         struct rep_protocol_annotation request;
7470         struct rep_protocol_response response;
7471         size_t copied;
7472         int r;
7473 
7474         if (h == NULL) {
7475                 /* We can't do anything if the handle is destroyed. */
7476                 return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED));
7477         }
7478 
7479         request.rpr_request = REP_PROTOCOL_SET_AUDIT_ANNOTATION;
7480         copied = strlcpy(request.rpr_operation,
7481             (operation == NULL) ? "" : operation,
7482             sizeof (request.rpr_operation));
7483         if (copied >= sizeof (request.rpr_operation))
7484                 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
7485 
7486         copied = strlcpy(request.rpr_file,
7487             (file == NULL) ? "" : file,
7488             sizeof (request.rpr_file));
7489         if (copied >= sizeof (request.rpr_file))
7490                 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
7491 
7492         (void) pthread_mutex_lock(&h->rh_lock);
7493         r = make_door_call(h, &request, sizeof (request),
7494             &response, sizeof (response));
7495         (void) pthread_mutex_unlock(&h->rh_lock);
7496 
7497         if (r < 0) {
7498                 DOOR_ERRORS_BLOCK(r);
7499         }
7500 
7501         if (response.rpr_response != REP_PROTOCOL_SUCCESS)
7502                 return (scf_set_error(proto_error(response.rpr_response)));
7503         return (0);
7504 }