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