1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 1780 gww * Common Development and Distribution License (the "License"). 6 1780 gww * You may not use this file except in compliance with the License. 7 0 stevel * 8 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 0 stevel * or http://www.opensolaris.org/os/licensing. 10 0 stevel * See the License for the specific language governing permissions 11 0 stevel * and limitations under the License. 12 0 stevel * 13 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 14 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 0 stevel * If applicable, add the following below this CDDL HEADER, with the 16 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 17 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 18 0 stevel * 19 0 stevel * CDDL HEADER END 20 0 stevel */ 21 5891 raf 22 0 stevel /* 23 8497 Thomas * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 0 stevel * Use is subject to license terms. 25 0 stevel */ 26 0 stevel 27 0 stevel /* 28 0 stevel * This is the main implementation file for the low-level repository 29 0 stevel * interface. 30 0 stevel */ 31 0 stevel 32 0 stevel #include "lowlevel_impl.h" 33 0 stevel 34 0 stevel #include "repcache_protocol.h" 35 0 stevel #include "scf_type.h" 36 0 stevel 37 0 stevel #include <assert.h> 38 0 stevel #include <alloca.h> 39 0 stevel #include <door.h> 40 0 stevel #include <errno.h> 41 0 stevel #include <fcntl.h> 42 0 stevel #include <fnmatch.h> 43 0 stevel #include <libuutil.h> 44 0 stevel #include <poll.h> 45 0 stevel #include <pthread.h> 46 0 stevel #include <stddef.h> 47 0 stevel #include <stdio.h> 48 0 stevel #include <stdlib.h> 49 0 stevel #include <string.h> 50 0 stevel #include <sys/mman.h> 51 0 stevel #include <sys/sysmacros.h> 52 0 stevel #include <unistd.h> 53 0 stevel 54 0 stevel #define ENV_SCF_DEBUG "LIBSCF_DEBUG" 55 0 stevel #define ENV_SCF_DOORPATH "LIBSCF_DOORPATH" 56 0 stevel 57 0 stevel static uint32_t default_debug = 0; 58 0 stevel static const char *default_door_path = REPOSITORY_DOOR_NAME; 59 0 stevel 60 0 stevel #define CALL_FAILED -1 61 0 stevel #define RESULT_TOO_BIG -2 62 0 stevel #define NOT_BOUND -3 63 0 stevel 64 0 stevel static pthread_mutex_t lowlevel_init_lock; 65 0 stevel static int32_t lowlevel_inited; 66 0 stevel 67 0 stevel static uu_list_pool_t *tran_entry_pool; 68 0 stevel static uu_list_pool_t *datael_pool; 69 0 stevel static uu_list_pool_t *iter_pool; 70 7887 Liane 71 7887 Liane /* 72 7887 Liane * base32[] index32[] are used in base32 encoding and decoding. 73 7887 Liane */ 74 7887 Liane static char base32[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; 75 7887 Liane static char index32[128] = { 76 7887 Liane -1, -1, -1, -1, -1, -1, -1, -1, /* 0-7 */ 77 7887 Liane -1, -1, -1, -1, -1, -1, -1, -1, /* 8-15 */ 78 7887 Liane -1, -1, -1, -1, -1, -1, -1, -1, /* 16-23 */ 79 7887 Liane -1, -1, -1, -1, -1, -1, -1, -1, /* 24-31 */ 80 7887 Liane -1, -1, -1, -1, -1, -1, -1, -1, /* 32-39 */ 81 7887 Liane -1, -1, -1, -1, -1, -1, -1, -1, /* 40-47 */ 82 7887 Liane -1, -1, 26, 27, 28, 29, 30, 31, /* 48-55 */ 83 7887 Liane -1, -1, -1, -1, -1, -1, -1, -1, /* 56-63 */ 84 7887 Liane -1, 0, 1, 2, 3, 4, 5, 6, /* 64-71 */ 85 7887 Liane 7, 8, 9, 10, 11, 12, 13, 14, /* 72-79 */ 86 7887 Liane 15, 16, 17, 18, 19, 20, 21, 22, /* 80-87 */ 87 7887 Liane 23, 24, 25, -1, -1, -1, -1, -1, /* 88-95 */ 88 7887 Liane -1, -1, -1, -1, -1, -1, -1, -1, /* 96-103 */ 89 7887 Liane -1, -1, -1, -1, -1, -1, -1, -1, /* 104-111 */ 90 7887 Liane -1, -1, -1, -1, -1, -1, -1, -1, /* 112-119 */ 91 7887 Liane -1, -1, -1, -1, -1, -1, -1, -1 /* 120-127 */ 92 7887 Liane }; 93 7887 Liane 94 7887 Liane #define DECODE32_GS (8) /* scf_decode32 group size */ 95 0 stevel 96 0 stevel /* 97 0 stevel * We want MUTEX_HELD, but we also want pthreads. 98 0 stevel */ 99 0 stevel struct _lwp_mutex; 100 0 stevel extern int _mutex_held(struct _lwp_mutex *); 101 0 stevel #define MUTEX_HELD(m) _mutex_held((struct _lwp_mutex *)(m)) 102 0 stevel 103 0 stevel #ifdef lint 104 0 stevel #define assert_nolint(x) (void)0 105 0 stevel #else 106 0 stevel #define assert_nolint(x) assert(x) 107 0 stevel #endif 108 0 stevel 109 0 stevel static void scf_iter_reset_locked(scf_iter_t *iter); 110 0 stevel static void scf_value_reset_locked(scf_value_t *val, int and_destroy); 111 0 stevel 112 0 stevel #define TYPE_VALUE (-100) 113 0 stevel 114 0 stevel /* 115 0 stevel * Hold and release subhandles. We only allow one thread access to the 116 0 stevel * subhandles at a time, and he can use any subset, grabbing and releasing 117 0 stevel * them in any order. The only restrictions are that you cannot hold an 118 0 stevel * already-held subhandle, and all subhandles must be released before 119 0 stevel * returning to the original caller. 120 0 stevel */ 121 0 stevel static void 122 0 stevel handle_hold_subhandles(scf_handle_t *h, int mask) 123 0 stevel { 124 0 stevel assert(mask != 0 && (mask & ~RH_HOLD_ALL) == 0); 125 0 stevel 126 0 stevel (void) pthread_mutex_lock(&h->rh_lock); 127 5891 raf while (h->rh_hold_flags != 0 && h->rh_holder != pthread_self()) { 128 5891 raf int cancel_state; 129 5891 raf 130 5891 raf (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 131 5891 raf &cancel_state); 132 5891 raf (void) pthread_cond_wait(&h->rh_cv, &h->rh_lock); 133 5891 raf (void) pthread_setcancelstate(cancel_state, NULL); 134 5891 raf } 135 0 stevel if (h->rh_hold_flags == 0) 136 0 stevel h->rh_holder = pthread_self(); 137 0 stevel assert(!(h->rh_hold_flags & mask)); 138 0 stevel h->rh_hold_flags |= mask; 139 0 stevel (void) pthread_mutex_unlock(&h->rh_lock); 140 0 stevel } 141 0 stevel 142 0 stevel static void 143 0 stevel handle_rele_subhandles(scf_handle_t *h, int mask) 144 0 stevel { 145 0 stevel assert(mask != 0 && (mask & ~RH_HOLD_ALL) == 0); 146 0 stevel 147 0 stevel (void) pthread_mutex_lock(&h->rh_lock); 148 0 stevel assert(h->rh_holder == pthread_self()); 149 0 stevel assert((h->rh_hold_flags & mask)); 150 0 stevel 151 0 stevel h->rh_hold_flags &= ~mask; 152 0 stevel if (h->rh_hold_flags == 0) 153 0 stevel (void) pthread_cond_signal(&h->rh_cv); 154 0 stevel (void) pthread_mutex_unlock(&h->rh_lock); 155 0 stevel } 156 0 stevel 157 0 stevel #define HOLD_HANDLE(h, flag, field) \ 158 0 stevel (handle_hold_subhandles((h), (flag)), (h)->field) 159 0 stevel 160 0 stevel #define RELE_HANDLE(h, flag) \ 161 0 stevel (handle_rele_subhandles((h), (flag))) 162 0 stevel 163 0 stevel /* 164 0 stevel * convenience macros, for functions that only need a one or two handles at 165 0 stevel * any given time 166 0 stevel */ 167 0 stevel #define HANDLE_HOLD_ITER(h) HOLD_HANDLE((h), RH_HOLD_ITER, rh_iter) 168 0 stevel #define HANDLE_HOLD_SCOPE(h) HOLD_HANDLE((h), RH_HOLD_SCOPE, rh_scope) 169 0 stevel #define HANDLE_HOLD_SERVICE(h) HOLD_HANDLE((h), RH_HOLD_SERVICE, rh_service) 170 0 stevel #define HANDLE_HOLD_INSTANCE(h) HOLD_HANDLE((h), RH_HOLD_INSTANCE, rh_instance) 171 0 stevel #define HANDLE_HOLD_SNAPSHOT(h) HOLD_HANDLE((h), RH_HOLD_SNAPSHOT, rh_snapshot) 172 0 stevel #define HANDLE_HOLD_SNAPLVL(h) HOLD_HANDLE((h), RH_HOLD_SNAPLVL, rh_snaplvl) 173 0 stevel #define HANDLE_HOLD_PG(h) HOLD_HANDLE((h), RH_HOLD_PG, rh_pg) 174 0 stevel #define HANDLE_HOLD_PROPERTY(h) HOLD_HANDLE((h), RH_HOLD_PROPERTY, rh_property) 175 0 stevel #define HANDLE_HOLD_VALUE(h) HOLD_HANDLE((h), RH_HOLD_VALUE, rh_value) 176 0 stevel 177 0 stevel #define HANDLE_RELE_ITER(h) RELE_HANDLE((h), RH_HOLD_ITER) 178 0 stevel #define HANDLE_RELE_SCOPE(h) RELE_HANDLE((h), RH_HOLD_SCOPE) 179 0 stevel #define HANDLE_RELE_SERVICE(h) RELE_HANDLE((h), RH_HOLD_SERVICE) 180 0 stevel #define HANDLE_RELE_INSTANCE(h) RELE_HANDLE((h), RH_HOLD_INSTANCE) 181 0 stevel #define HANDLE_RELE_SNAPSHOT(h) RELE_HANDLE((h), RH_HOLD_SNAPSHOT) 182 0 stevel #define HANDLE_RELE_SNAPLVL(h) RELE_HANDLE((h), RH_HOLD_SNAPLVL) 183 0 stevel #define HANDLE_RELE_PG(h) RELE_HANDLE((h), RH_HOLD_PG) 184 0 stevel #define HANDLE_RELE_PROPERTY(h) RELE_HANDLE((h), RH_HOLD_PROPERTY) 185 0 stevel #define HANDLE_RELE_VALUE(h) RELE_HANDLE((h), RH_HOLD_VALUE) 186 0 stevel 187 0 stevel /*ARGSUSED*/ 188 0 stevel static int 189 0 stevel transaction_entry_compare(const void *l_arg, const void *r_arg, void *private) 190 0 stevel { 191 0 stevel const char *l_prop = 192 0 stevel ((scf_transaction_entry_t *)l_arg)->entry_property; 193 0 stevel const char *r_prop = 194 0 stevel ((scf_transaction_entry_t *)r_arg)->entry_property; 195 0 stevel 196 0 stevel int ret; 197 0 stevel 198 0 stevel ret = strcmp(l_prop, r_prop); 199 0 stevel if (ret > 0) 200 0 stevel return (1); 201 407 jwadams if (ret < 0) 202 407 jwadams return (-1); 203 407 jwadams return (0); 204 407 jwadams } 205 407 jwadams 206 407 jwadams static int 207 407 jwadams datael_compare(const void *l_arg, const void *r_arg, void *private) 208 407 jwadams { 209 407 jwadams uint32_t l_id = ((scf_datael_t *)l_arg)->rd_entity; 210 407 jwadams uint32_t r_id = (r_arg != NULL) ? ((scf_datael_t *)r_arg)->rd_entity : 211 407 jwadams *(uint32_t *)private; 212 407 jwadams 213 407 jwadams if (l_id > r_id) 214 407 jwadams return (1); 215 407 jwadams if (l_id < r_id) 216 407 jwadams return (-1); 217 407 jwadams return (0); 218 407 jwadams } 219 407 jwadams 220 407 jwadams static int 221 407 jwadams iter_compare(const void *l_arg, const void *r_arg, void *private) 222 407 jwadams { 223 407 jwadams uint32_t l_id = ((scf_iter_t *)l_arg)->iter_id; 224 407 jwadams uint32_t r_id = (r_arg != NULL) ? ((scf_iter_t *)r_arg)->iter_id : 225 407 jwadams *(uint32_t *)private; 226 407 jwadams 227 407 jwadams if (l_id > r_id) 228 407 jwadams return (1); 229 407 jwadams if (l_id < r_id) 230 0 stevel return (-1); 231 0 stevel return (0); 232 0 stevel } 233 0 stevel 234 0 stevel static int 235 0 stevel lowlevel_init(void) 236 0 stevel { 237 0 stevel const char *debug; 238 0 stevel const char *door_path; 239 0 stevel 240 0 stevel (void) pthread_mutex_lock(&lowlevel_init_lock); 241 0 stevel if (lowlevel_inited == 0) { 242 0 stevel if (!issetugid() && 243 0 stevel (debug = getenv(ENV_SCF_DEBUG)) != NULL && debug[0] != 0 && 244 0 stevel uu_strtoint(debug, &default_debug, sizeof (default_debug), 245 0 stevel 0, 0, 0) == -1) { 246 0 stevel (void) fprintf(stderr, "LIBSCF: $%s (%s): %s", 247 0 stevel ENV_SCF_DEBUG, debug, 248 0 stevel uu_strerror(uu_error())); 249 0 stevel } 250 0 stevel 251 0 stevel if (!issetugid() && 252 0 stevel (door_path = getenv(ENV_SCF_DOORPATH)) != NULL && 253 0 stevel door_path[0] != 0) { 254 0 stevel default_door_path = strdup(door_path); 255 0 stevel if (default_door_path == NULL) 256 0 stevel default_door_path = door_path; 257 0 stevel } 258 0 stevel 259 0 stevel datael_pool = uu_list_pool_create("SUNW,libscf_datael", 260 0 stevel sizeof (scf_datael_t), offsetof(scf_datael_t, rd_node), 261 407 jwadams datael_compare, UU_LIST_POOL_DEBUG); 262 0 stevel 263 0 stevel iter_pool = uu_list_pool_create("SUNW,libscf_iter", 264 0 stevel sizeof (scf_iter_t), offsetof(scf_iter_t, iter_node), 265 407 jwadams iter_compare, UU_LIST_POOL_DEBUG); 266 0 stevel 267 0 stevel assert_nolint(offsetof(scf_transaction_entry_t, 268 0 stevel entry_property) == 0); 269 0 stevel tran_entry_pool = uu_list_pool_create( 270 0 stevel "SUNW,libscf_transaction_entity", 271 0 stevel sizeof (scf_transaction_entry_t), 272 0 stevel offsetof(scf_transaction_entry_t, entry_link), 273 0 stevel transaction_entry_compare, UU_LIST_POOL_DEBUG); 274 0 stevel 275 0 stevel if (datael_pool == NULL || iter_pool == NULL || 276 0 stevel tran_entry_pool == NULL) { 277 0 stevel lowlevel_inited = -1; 278 0 stevel goto end; 279 0 stevel } 280 0 stevel 281 0 stevel if (!scf_setup_error()) { 282 0 stevel lowlevel_inited = -1; 283 0 stevel goto end; 284 0 stevel } 285 0 stevel lowlevel_inited = 1; 286 0 stevel } 287 0 stevel end: 288 0 stevel (void) pthread_mutex_unlock(&lowlevel_init_lock); 289 0 stevel if (lowlevel_inited > 0) 290 0 stevel return (1); 291 0 stevel return (0); 292 0 stevel } 293 0 stevel 294 0 stevel static const struct { 295 0 stevel scf_type_t ti_type; 296 0 stevel rep_protocol_value_type_t ti_proto_type; 297 0 stevel const char *ti_name; 298 0 stevel } scf_type_info[] = { 299 0 stevel {SCF_TYPE_BOOLEAN, REP_PROTOCOL_TYPE_BOOLEAN, "boolean"}, 300 0 stevel {SCF_TYPE_COUNT, REP_PROTOCOL_TYPE_COUNT, "count"}, 301 0 stevel {SCF_TYPE_INTEGER, REP_PROTOCOL_TYPE_INTEGER, "integer"}, 302 0 stevel {SCF_TYPE_TIME, REP_PROTOCOL_TYPE_TIME, "time"}, 303 0 stevel {SCF_TYPE_ASTRING, REP_PROTOCOL_TYPE_STRING, "astring"}, 304 0 stevel {SCF_TYPE_OPAQUE, REP_PROTOCOL_TYPE_OPAQUE, "opaque"}, 305 0 stevel {SCF_TYPE_USTRING, REP_PROTOCOL_SUBTYPE_USTRING, "ustring"}, 306 0 stevel {SCF_TYPE_URI, REP_PROTOCOL_SUBTYPE_URI, "uri"}, 307 0 stevel {SCF_TYPE_FMRI, REP_PROTOCOL_SUBTYPE_FMRI, "fmri"}, 308 0 stevel {SCF_TYPE_HOST, REP_PROTOCOL_SUBTYPE_HOST, "host"}, 309 0 stevel {SCF_TYPE_HOSTNAME, REP_PROTOCOL_SUBTYPE_HOSTNAME, "hostname"}, 310 0 stevel {SCF_TYPE_NET_ADDR_V4, REP_PROTOCOL_SUBTYPE_NETADDR_V4, 311 0 stevel "net_address_v4"}, 312 0 stevel {SCF_TYPE_NET_ADDR_V6, REP_PROTOCOL_SUBTYPE_NETADDR_V6, 313 0 stevel "net_address_v6"} 314 0 stevel }; 315 0 stevel 316 0 stevel #define SCF_TYPE_INFO_COUNT (sizeof (scf_type_info) / sizeof (*scf_type_info)) 317 0 stevel static rep_protocol_value_type_t 318 0 stevel scf_type_to_protocol_type(scf_type_t t) 319 0 stevel { 320 0 stevel int i; 321 0 stevel 322 0 stevel for (i = 0; i < SCF_TYPE_INFO_COUNT; i++) 323 0 stevel if (scf_type_info[i].ti_type == t) 324 0 stevel return (scf_type_info[i].ti_proto_type); 325 0 stevel 326 0 stevel return (REP_PROTOCOL_TYPE_INVALID); 327 0 stevel } 328 0 stevel 329 0 stevel static scf_type_t 330 0 stevel scf_protocol_type_to_type(rep_protocol_value_type_t t) 331 0 stevel { 332 0 stevel int i; 333 0 stevel 334 0 stevel for (i = 0; i < SCF_TYPE_INFO_COUNT; i++) 335 0 stevel if (scf_type_info[i].ti_proto_type == t) 336 0 stevel return (scf_type_info[i].ti_type); 337 0 stevel 338 0 stevel return (SCF_TYPE_INVALID); 339 0 stevel } 340 0 stevel 341 0 stevel const char * 342 0 stevel scf_type_to_string(scf_type_t ty) 343 0 stevel { 344 0 stevel int i; 345 0 stevel 346 0 stevel for (i = 0; i < SCF_TYPE_INFO_COUNT; i++) 347 0 stevel if (scf_type_info[i].ti_type == ty) 348 0 stevel return (scf_type_info[i].ti_name); 349 0 stevel 350 0 stevel return ("unknown"); 351 0 stevel } 352 0 stevel 353 0 stevel scf_type_t 354 0 stevel scf_string_to_type(const char *name) 355 0 stevel { 356 0 stevel int i; 357 0 stevel 358 0 stevel for (i = 0; i < sizeof (scf_type_info) / sizeof (*scf_type_info); i++) 359 0 stevel if (strcmp(scf_type_info[i].ti_name, name) == 0) 360 0 stevel return (scf_type_info[i].ti_type); 361 0 stevel 362 0 stevel return (SCF_TYPE_INVALID); 363 0 stevel } 364 0 stevel 365 0 stevel int 366 0 stevel scf_type_base_type(scf_type_t type, scf_type_t *out) 367 0 stevel { 368 0 stevel rep_protocol_value_type_t t = scf_type_to_protocol_type(type); 369 0 stevel if (t == REP_PROTOCOL_TYPE_INVALID) 370 0 stevel return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 371 0 stevel 372 0 stevel *out = scf_protocol_type_to_type(scf_proto_underlying_type(t)); 373 0 stevel return (SCF_SUCCESS); 374 0 stevel } 375 0 stevel 376 0 stevel /* 377 0 stevel * Convert a protocol error code into an SCF_ERROR_* code. 378 0 stevel */ 379 0 stevel static scf_error_t 380 0 stevel proto_error(rep_protocol_responseid_t e) 381 0 stevel { 382 0 stevel switch (e) { 383 0 stevel case REP_PROTOCOL_FAIL_MISORDERED: 384 0 stevel case REP_PROTOCOL_FAIL_UNKNOWN_ID: 385 0 stevel case REP_PROTOCOL_FAIL_INVALID_TYPE: 386 0 stevel case REP_PROTOCOL_FAIL_TRUNCATED: 387 0 stevel case REP_PROTOCOL_FAIL_TYPE_MISMATCH: 388 0 stevel case REP_PROTOCOL_FAIL_NOT_APPLICABLE: 389 0 stevel case REP_PROTOCOL_FAIL_UNKNOWN: 390 0 stevel return (SCF_ERROR_INTERNAL); 391 0 stevel 392 0 stevel case REP_PROTOCOL_FAIL_BAD_TX: 393 0 stevel return (SCF_ERROR_INVALID_ARGUMENT); 394 0 stevel case REP_PROTOCOL_FAIL_BAD_REQUEST: 395 0 stevel return (SCF_ERROR_INVALID_ARGUMENT); 396 0 stevel case REP_PROTOCOL_FAIL_NO_RESOURCES: 397 0 stevel return (SCF_ERROR_NO_RESOURCES); 398 0 stevel case REP_PROTOCOL_FAIL_NOT_FOUND: 399 0 stevel return (SCF_ERROR_NOT_FOUND); 400 0 stevel case REP_PROTOCOL_FAIL_DELETED: 401 0 stevel return (SCF_ERROR_DELETED); 402 0 stevel case REP_PROTOCOL_FAIL_NOT_SET: 403 0 stevel return (SCF_ERROR_NOT_SET); 404 0 stevel case REP_PROTOCOL_FAIL_EXISTS: 405 0 stevel return (SCF_ERROR_EXISTS); 406 0 stevel case REP_PROTOCOL_FAIL_DUPLICATE_ID: 407 0 stevel return (SCF_ERROR_EXISTS); 408 0 stevel case REP_PROTOCOL_FAIL_PERMISSION_DENIED: 409 0 stevel return (SCF_ERROR_PERMISSION_DENIED); 410 0 stevel case REP_PROTOCOL_FAIL_BACKEND_ACCESS: 411 0 stevel return (SCF_ERROR_BACKEND_ACCESS); 412 0 stevel case REP_PROTOCOL_FAIL_BACKEND_READONLY: 413 0 stevel return (SCF_ERROR_BACKEND_READONLY); 414 0 stevel 415 0 stevel case REP_PROTOCOL_SUCCESS: 416 0 stevel case REP_PROTOCOL_DONE: 417 0 stevel case REP_PROTOCOL_FAIL_NOT_LATEST: /* TX code should handle this */ 418 0 stevel default: 419 0 stevel #ifndef NDEBUG 420 0 stevel uu_warn("%s:%d: Bad error code %d passed to proto_error().\n", 421 0 stevel __FILE__, __LINE__, e); 422 0 stevel #endif 423 0 stevel abort(); 424 0 stevel /*NOTREACHED*/ 425 0 stevel } 426 0 stevel } 427 0 stevel 428 0 stevel ssize_t 429 0 stevel scf_limit(uint32_t limit) 430 0 stevel { 431 0 stevel switch (limit) { 432 0 stevel case SCF_LIMIT_MAX_NAME_LENGTH: 433 0 stevel case SCF_LIMIT_MAX_PG_TYPE_LENGTH: 434 0 stevel return (REP_PROTOCOL_NAME_LEN - 1); 435 0 stevel case SCF_LIMIT_MAX_VALUE_LENGTH: 436 0 stevel return (REP_PROTOCOL_VALUE_LEN - 1); 437 0 stevel case SCF_LIMIT_MAX_FMRI_LENGTH: 438 0 stevel return (SCF_FMRI_PREFIX_MAX_LEN + 439 0 stevel sizeof (SCF_FMRI_SCOPE_PREFIX) - 1 + 440 0 stevel sizeof (SCF_FMRI_SCOPE_SUFFIX) - 1 + 441 0 stevel sizeof (SCF_FMRI_SERVICE_PREFIX) - 1 + 442 0 stevel sizeof (SCF_FMRI_INSTANCE_PREFIX) - 1 + 443 0 stevel sizeof (SCF_FMRI_PROPERTYGRP_PREFIX) - 1 + 444 0 stevel sizeof (SCF_FMRI_PROPERTY_PREFIX) - 1 + 445 0 stevel 5 * (REP_PROTOCOL_NAME_LEN - 1)); 446 0 stevel default: 447 0 stevel return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 448 0 stevel } 449 0 stevel } 450 0 stevel 451 0 stevel static size_t 452 0 stevel scf_opaque_decode(char *out_arg, const char *in, size_t max_out) 453 0 stevel { 454 0 stevel char a, b; 455 0 stevel char *out = out_arg; 456 0 stevel 457 0 stevel while (max_out > 0 && (a = in[0]) != 0 && (b = in[1]) != 0) { 458 0 stevel in += 2; 459 0 stevel 460 0 stevel if (a >= '0' && a <= '9') 461 0 stevel a -= '0'; 462 0 stevel else if (a >= 'a' && a <= 'f') 463 0 stevel a = a - 'a' + 10; 464 0 stevel else if (a >= 'A' && a <= 'F') 465 0 stevel a = a - 'A' + 10; 466 0 stevel else 467 0 stevel break; 468 0 stevel 469 0 stevel if (b >= '0' && b <= '9') 470 0 stevel b -= '0'; 471 0 stevel else if (b >= 'a' && b <= 'f') 472 0 stevel b = b - 'a' + 10; 473 0 stevel else if (b >= 'A' && b <= 'F') 474 0 stevel b = b - 'A' + 10; 475 0 stevel else 476 0 stevel break; 477 0 stevel 478 0 stevel *out++ = (a << 4) | b; 479 0 stevel max_out--; 480 0 stevel } 481 0 stevel 482 0 stevel return (out - out_arg); 483 0 stevel } 484 0 stevel 485 0 stevel static size_t 486 0 stevel scf_opaque_encode(char *out_arg, const char *in_arg, size_t in_sz) 487 0 stevel { 488 0 stevel uint8_t *in = (uint8_t *)in_arg; 489 0 stevel uint8_t *end = in + in_sz; 490 0 stevel char *out = out_arg; 491 0 stevel 492 0 stevel if (out == NULL) 493 0 stevel return (2 * in_sz); 494 0 stevel 495 0 stevel while (in < end) { 496 0 stevel uint8_t c = *in++; 497 0 stevel 498 0 stevel uint8_t a = (c & 0xf0) >> 4; 499 0 stevel uint8_t b = (c & 0x0f); 500 0 stevel 501 0 stevel if (a <= 9) 502 0 stevel *out++ = a + '0'; 503 0 stevel else 504 0 stevel *out++ = a + 'a' - 10; 505 0 stevel 506 0 stevel if (b <= 9) 507 0 stevel *out++ = b + '0'; 508 0 stevel else 509 0 stevel *out++ = b + 'a' - 10; 510 0 stevel } 511 0 stevel 512 0 stevel *out = 0; 513 0 stevel 514 0 stevel return (out - out_arg); 515 0 stevel } 516 0 stevel 517 0 stevel static void 518 0 stevel handle_do_close(scf_handle_t *h) 519 0 stevel { 520 0 stevel assert(MUTEX_HELD(&h->rh_lock)); 521 0 stevel assert(h->rh_doorfd != -1); 522 0 stevel 523 0 stevel /* 524 0 stevel * if there are any active FD users, we just move the FD over 525 0 stevel * to rh_doorfd_old -- they'll close it when they finish. 526 0 stevel */ 527 0 stevel if (h->rh_fd_users > 0) { 528 0 stevel h->rh_doorfd_old = h->rh_doorfd; 529 0 stevel h->rh_doorfd = -1; 530 0 stevel } else { 531 0 stevel assert(h->rh_doorfd_old == -1); 532 0 stevel (void) close(h->rh_doorfd); 533 0 stevel h->rh_doorfd = -1; 534 0 stevel } 535 0 stevel } 536 0 stevel 537 0 stevel /* 538 0 stevel * Check if a handle is currently bound. fork()ing implicitly unbinds 539 0 stevel * the handle in the child. 540 0 stevel */ 541 0 stevel static int 542 0 stevel handle_is_bound(scf_handle_t *h) 543 0 stevel { 544 0 stevel assert(MUTEX_HELD(&h->rh_lock)); 545 0 stevel 546 0 stevel if (h->rh_doorfd == -1) 547 0 stevel return (0); 548 0 stevel 549 0 stevel if (getpid() == h->rh_doorpid) 550 0 stevel return (1); 551 0 stevel 552 0 stevel /* forked since our last bind -- initiate handle close */ 553 0 stevel handle_do_close(h); 554 0 stevel return (0); 555 0 stevel } 556 0 stevel 557 0 stevel static int 558 407 jwadams handle_has_server_locked(scf_handle_t *h) 559 407 jwadams { 560 407 jwadams door_info_t i; 561 407 jwadams assert(MUTEX_HELD(&h->rh_lock)); 562 407 jwadams 563 407 jwadams return (handle_is_bound(h) && door_info(h->rh_doorfd, &i) != -1 && 564 407 jwadams i.di_target != -1); 565 407 jwadams } 566 407 jwadams 567 407 jwadams static int 568 0 stevel handle_has_server(scf_handle_t *h) 569 0 stevel { 570 407 jwadams int ret; 571 407 jwadams 572 407 jwadams (void) pthread_mutex_lock(&h->rh_lock); 573 407 jwadams ret = handle_has_server_locked(h); 574 0 stevel (void) pthread_mutex_unlock(&h->rh_lock); 575 0 stevel 576 0 stevel return (ret); 577 0 stevel } 578 0 stevel 579 0 stevel /* 580 0 stevel * This makes a door request on the client door associated with handle h. 581 0 stevel * It will automatically retry calls which fail on EINTR. If h is not bound, 582 0 stevel * returns NOT_BOUND. If the door call fails or the server response is too 583 0 stevel * small, returns CALL_FAILED. If the server response is too big, truncates the 584 0 stevel * response and returns RESULT_TOO_BIG. Otherwise, the size of the result is 585 0 stevel * returned. 586 0 stevel */ 587 0 stevel static ssize_t 588 0 stevel make_door_call(scf_handle_t *h, const void *req, size_t req_sz, 589 0 stevel void *res, size_t res_sz) 590 0 stevel { 591 0 stevel door_arg_t arg; 592 0 stevel int r; 593 0 stevel 594 0 stevel assert(MUTEX_HELD(&h->rh_lock)); 595 0 stevel 596 0 stevel if (!handle_is_bound(h)) { 597 0 stevel return (NOT_BOUND); 598 0 stevel } 599 0 stevel 600 0 stevel arg.data_ptr = (void *)req; 601 0 stevel arg.data_size = req_sz; 602 0 stevel arg.desc_ptr = NULL; 603 0 stevel arg.desc_num = 0; 604 0 stevel arg.rbuf = res; 605 0 stevel arg.rsize = res_sz; 606 0 stevel 607 0 stevel while ((r = door_call(h->rh_doorfd, &arg)) < 0) { 608 0 stevel if (errno != EINTR) 609 0 stevel break; 610 0 stevel } 611 0 stevel 612 0 stevel if (r < 0) { 613 0 stevel return (CALL_FAILED); 614 0 stevel } 615 0 stevel 616 0 stevel if (arg.desc_num > 0) { 617 0 stevel while (arg.desc_num > 0) { 618 0 stevel if (arg.desc_ptr->d_attributes & DOOR_DESCRIPTOR) { 619 0 stevel int cfd = arg.desc_ptr->d_data.d_desc.d_id; 620 0 stevel (void) close(cfd); 621 0 stevel } 622 0 stevel arg.desc_ptr++; 623 0 stevel arg.desc_num--; 624 0 stevel } 625 0 stevel } 626 0 stevel if (arg.data_ptr != res && arg.data_size > 0) 627 0 stevel (void) memmove(res, arg.data_ptr, MIN(arg.data_size, res_sz)); 628 0 stevel 629 0 stevel if (arg.rbuf != res) 630 0 stevel (void) munmap(arg.rbuf, arg.rsize); 631 0 stevel 632 0 stevel if (arg.data_size > res_sz) 633 0 stevel return (RESULT_TOO_BIG); 634 0 stevel 635 0 stevel if (arg.data_size < sizeof (uint32_t)) 636 0 stevel return (CALL_FAILED); 637 0 stevel 638 0 stevel return (arg.data_size); 639 0 stevel } 640 0 stevel 641 0 stevel /* 642 0 stevel * Should only be used when r < 0. 643 0 stevel */ 644 0 stevel #define DOOR_ERRORS_BLOCK(r) { \ 645 0 stevel switch (r) { \ 646 0 stevel case NOT_BOUND: \ 647 0 stevel return (scf_set_error(SCF_ERROR_NOT_BOUND)); \ 648 0 stevel \ 649 0 stevel case CALL_FAILED: \ 650 0 stevel return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN)); \ 651 0 stevel \ 652 0 stevel case RESULT_TOO_BIG: \ 653 0 stevel return (scf_set_error(SCF_ERROR_INTERNAL)); \ 654 0 stevel \ 655 0 stevel default: \ 656 0 stevel assert(r == NOT_BOUND || r == CALL_FAILED || \ 657 0 stevel r == RESULT_TOO_BIG); \ 658 0 stevel abort(); \ 659 0 stevel } \ 660 0 stevel } 661 0 stevel 662 0 stevel /* 663 0 stevel * Like make_door_call(), but takes an fd instead of a handle, and expects 664 0 stevel * a single file descriptor, returned via res_fd. 665 0 stevel * 666 0 stevel * If no file descriptor is returned, *res_fd == -1. 667 0 stevel */ 668 0 stevel static int 669 0 stevel make_door_call_retfd(int fd, const void *req, size_t req_sz, void *res, 670 0 stevel size_t res_sz, int *res_fd) 671 0 stevel { 672 0 stevel door_arg_t arg; 673 0 stevel int r; 674 0 stevel char rbuf[256]; 675 0 stevel 676 0 stevel *res_fd = -1; 677 0 stevel 678 0 stevel if (fd == -1) 679 0 stevel return (NOT_BOUND); 680 0 stevel 681 0 stevel arg.data_ptr = (void *)req; 682 0 stevel arg.data_size = req_sz; 683 0 stevel arg.desc_ptr = NULL; 684 0 stevel arg.desc_num = 0; 685 0 stevel arg.rbuf = rbuf; 686 0 stevel arg.rsize = sizeof (rbuf); 687 0 stevel 688 0 stevel while ((r = door_call(fd, &arg)) < 0) { 689 0 stevel if (errno != EINTR) 690 0 stevel break; 691 0 stevel } 692 0 stevel 693 0 stevel if (r < 0) 694 0 stevel return (CALL_FAILED); 695 0 stevel 696 0 stevel if (arg.desc_num > 1) { 697 0 stevel while (arg.desc_num > 0) { 698 0 stevel if (arg.desc_ptr->d_attributes & DOOR_DESCRIPTOR) { 699 0 stevel int cfd = 700 0 stevel arg.desc_ptr->d_data.d_desc.d_descriptor; 701 0 stevel (void) close(cfd); 702 0 stevel } 703 0 stevel arg.desc_ptr++; 704 0 stevel arg.desc_num--; 705 0 stevel } 706 0 stevel } 707 0 stevel if (arg.desc_num == 1 && arg.desc_ptr->d_attributes & DOOR_DESCRIPTOR) 708 0 stevel *res_fd = arg.desc_ptr->d_data.d_desc.d_descriptor; 709 0 stevel 710 0 stevel if (arg.data_size > 0) 711 0 stevel (void) memmove(res, arg.data_ptr, MIN(arg.data_size, res_sz)); 712 0 stevel 713 0 stevel if (arg.rbuf != rbuf) 714 0 stevel (void) munmap(arg.rbuf, arg.rsize); 715 0 stevel 716 0 stevel if (arg.data_size > res_sz) 717 0 stevel return (RESULT_TOO_BIG); 718 0 stevel 719 0 stevel if (arg.data_size < sizeof (uint32_t)) 720 0 stevel return (CALL_FAILED); 721 0 stevel 722 0 stevel return (arg.data_size); 723 0 stevel } 724 0 stevel 725 0 stevel /* 726 0 stevel * Fails with 727 0 stevel * _VERSION_MISMATCH 728 0 stevel * _NO_MEMORY 729 0 stevel */ 730 0 stevel scf_handle_t * 731 0 stevel scf_handle_create(scf_version_t v) 732 0 stevel { 733 0 stevel scf_handle_t *ret; 734 0 stevel int failed; 735 0 stevel 736 0 stevel /* 737 0 stevel * This will need to be revisited when we bump SCF_VERSION 738 0 stevel */ 739 0 stevel if (v != SCF_VERSION) { 740 0 stevel (void) scf_set_error(SCF_ERROR_VERSION_MISMATCH); 741 0 stevel return (NULL); 742 0 stevel } 743 0 stevel 744 0 stevel if (!lowlevel_init()) { 745 0 stevel (void) scf_set_error(SCF_ERROR_NO_MEMORY); 746 0 stevel return (NULL); 747 0 stevel } 748 0 stevel 749 0 stevel ret = uu_zalloc(sizeof (*ret)); 750 0 stevel if (ret == NULL) { 751 0 stevel (void) scf_set_error(SCF_ERROR_NO_MEMORY); 752 0 stevel return (NULL); 753 0 stevel } 754 0 stevel 755 0 stevel ret->rh_dataels = uu_list_create(datael_pool, ret, 0); 756 0 stevel ret->rh_iters = uu_list_create(iter_pool, ret, 0); 757 0 stevel if (ret->rh_dataels == NULL || ret->rh_iters == NULL) { 758 0 stevel if (ret->rh_dataels != NULL) 759 0 stevel uu_list_destroy(ret->rh_dataels); 760 0 stevel if (ret->rh_iters != NULL) 761 0 stevel uu_list_destroy(ret->rh_iters); 762 0 stevel uu_free(ret); 763 0 stevel (void) scf_set_error(SCF_ERROR_NO_MEMORY); 764 0 stevel return (NULL); 765 0 stevel } 766 0 stevel 767 0 stevel ret->rh_doorfd = -1; 768 0 stevel ret->rh_doorfd_old = -1; 769 0 stevel (void) pthread_mutex_init(&ret->rh_lock, NULL); 770 0 stevel 771 0 stevel handle_hold_subhandles(ret, RH_HOLD_ALL); 772 0 stevel 773 0 stevel failed = ((ret->rh_iter = scf_iter_create(ret)) == NULL || 774 0 stevel (ret->rh_scope = scf_scope_create(ret)) == NULL || 775 0 stevel (ret->rh_service = scf_service_create(ret)) == NULL || 776 0 stevel (ret->rh_instance = scf_instance_create(ret)) == NULL || 777 0 stevel (ret->rh_snapshot = scf_snapshot_create(ret)) == NULL || 778 0 stevel (ret->rh_snaplvl = scf_snaplevel_create(ret)) == NULL || 779 0 stevel (ret->rh_pg = scf_pg_create(ret)) == NULL || 780 0 stevel (ret->rh_property = scf_property_create(ret)) == NULL || 781 0 stevel (ret->rh_value = scf_value_create(ret)) == NULL); 782 0 stevel 783 0 stevel /* 784 0 stevel * these subhandles count as internal references, not external ones. 785 0 stevel */ 786 0 stevel ret->rh_intrefs = ret->rh_extrefs; 787 0 stevel ret->rh_extrefs = 0; 788 0 stevel handle_rele_subhandles(ret, RH_HOLD_ALL); 789 0 stevel 790 0 stevel if (failed) { 791 0 stevel scf_handle_destroy(ret); 792 0 stevel (void) scf_set_error(SCF_ERROR_NO_MEMORY); 793 0 stevel return (NULL); 794 0 stevel } 795 0 stevel 796 0 stevel scf_value_set_count(ret->rh_value, default_debug); 797 0 stevel (void) scf_handle_decorate(ret, "debug", ret->rh_value); 798 0 stevel 799 0 stevel return (ret); 800 0 stevel } 801 0 stevel 802 0 stevel int 803 0 stevel scf_handle_decorate(scf_handle_t *handle, const char *name, scf_value_t *v) 804 0 stevel { 805 0 stevel if (v != SCF_DECORATE_CLEAR && handle != v->value_handle) 806 0 stevel return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH)); 807 0 stevel 808 0 stevel (void) pthread_mutex_lock(&handle->rh_lock); 809 0 stevel if (handle_is_bound(handle)) { 810 0 stevel (void) pthread_mutex_unlock(&handle->rh_lock); 811 0 stevel return (scf_set_error(SCF_ERROR_IN_USE)); 812 0 stevel } 813 0 stevel (void) pthread_mutex_unlock(&handle->rh_lock); 814 0 stevel 815 0 stevel if (strcmp(name, "debug") == 0) { 816 0 stevel if (v == SCF_DECORATE_CLEAR) { 817 0 stevel (void) pthread_mutex_lock(&handle->rh_lock); 818 0 stevel handle->rh_debug = 0; 819 0 stevel (void) pthread_mutex_unlock(&handle->rh_lock); 820 0 stevel } else { 821 0 stevel uint64_t val; 822 0 stevel if (scf_value_get_count(v, &val) < 0) 823 0 stevel return (-1); /* error already set */ 824 0 stevel 825 0 stevel (void) pthread_mutex_lock(&handle->rh_lock); 826 0 stevel handle->rh_debug = (uid_t)val; 827 0 stevel (void) pthread_mutex_unlock(&handle->rh_lock); 828 0 stevel } 829 0 stevel return (0); 830 0 stevel } 831 0 stevel if (strcmp(name, "door_path") == 0) { 832 0 stevel char name[sizeof (handle->rh_doorpath)]; 833 0 stevel 834 0 stevel if (v == SCF_DECORATE_CLEAR) { 835 0 stevel (void) pthread_mutex_lock(&handle->rh_lock); 836 0 stevel handle->rh_doorpath[0] = 0; 837 0 stevel (void) pthread_mutex_unlock(&handle->rh_lock); 838 0 stevel } else { 839 0 stevel ssize_t len; 840 0 stevel 841 0 stevel if ((len = scf_value_get_astring(v, name, 842 0 stevel sizeof (name))) < 0) { 843 0 stevel return (-1); /* error already set */ 844 0 stevel } 845 0 stevel if (len == 0 || len >= sizeof (name)) { 846 0 stevel return (scf_set_error( 847 0 stevel SCF_ERROR_INVALID_ARGUMENT)); 848 0 stevel } 849 0 stevel (void) pthread_mutex_lock(&handle->rh_lock); 850 0 stevel (void) strlcpy(handle->rh_doorpath, name, 851 0 stevel sizeof (handle->rh_doorpath)); 852 0 stevel (void) pthread_mutex_unlock(&handle->rh_lock); 853 0 stevel } 854 0 stevel return (0); 855 0 stevel } 856 0 stevel return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 857 0 stevel } 858 0 stevel 859 0 stevel /* 860 0 stevel * fails with INVALID_ARGUMENT and HANDLE_MISMATCH. 861 0 stevel */ 862 0 stevel int 863 0 stevel _scf_handle_decorations(scf_handle_t *handle, scf_decoration_func *f, 864 0 stevel scf_value_t *v, void *data) 865 0 stevel { 866 0 stevel scf_decoration_info_t i; 867 0 stevel char name[sizeof (handle->rh_doorpath)]; 868 0 stevel uint64_t debug; 869 0 stevel 870 0 stevel if (f == NULL || v == NULL) 871 0 stevel return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 872 0 stevel 873 0 stevel if (v->value_handle != handle) 874 0 stevel return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH)); 875 0 stevel 876 0 stevel i.sdi_name = (const char *)"debug"; 877 0 stevel i.sdi_type = SCF_TYPE_COUNT; 878 0 stevel (void) pthread_mutex_lock(&handle->rh_lock); 879 0 stevel debug = handle->rh_debug; 880 0 stevel (void) pthread_mutex_unlock(&handle->rh_lock); 881 0 stevel if (debug != 0) { 882 0 stevel scf_value_set_count(v, debug); 883 0 stevel i.sdi_value = v; 884 0 stevel } else { 885 0 stevel i.sdi_value = SCF_DECORATE_CLEAR; 886 0 stevel } 887 0 stevel 888 0 stevel if ((*f)(&i, data) == 0) 889 0 stevel return (0); 890 0 stevel 891 0 stevel i.sdi_name = (const char *)"door_path"; 892 0 stevel i.sdi_type = SCF_TYPE_ASTRING; 893 0 stevel (void) pthread_mutex_lock(&handle->rh_lock); 894 0 stevel (void) strlcpy(name, handle->rh_doorpath, sizeof (name)); 895 0 stevel (void) pthread_mutex_unlock(&handle->rh_lock); 896 0 stevel if (name[0] != 0) { 897 0 stevel (void) scf_value_set_astring(v, name); 898 0 stevel i.sdi_value = v; 899 0 stevel } else { 900 0 stevel i.sdi_value = SCF_DECORATE_CLEAR; 901 0 stevel } 902 0 stevel 903 0 stevel if ((*f)(&i, data) == 0) 904 0 stevel return (0); 905 0 stevel 906 0 stevel return (1); 907 0 stevel } 908 0 stevel 909 0 stevel /* 910 0 stevel * Fails if handle is not bound. 911 0 stevel */ 912 0 stevel static int 913 0 stevel handle_unbind_unlocked(scf_handle_t *handle) 914 0 stevel { 915 0 stevel rep_protocol_request_t request; 916 0 stevel rep_protocol_response_t response; 917 0 stevel 918 0 stevel if (!handle_is_bound(handle)) 919 0 stevel return (-1); 920 0 stevel 921 0 stevel request.rpr_request = REP_PROTOCOL_CLOSE; 922 0 stevel 923 0 stevel (void) make_door_call(handle, &request, sizeof (request), 924 0 stevel &response, sizeof (response)); 925 0 stevel 926 0 stevel handle_do_close(handle); 927 0 stevel 928 0 stevel return (SCF_SUCCESS); 929 0 stevel } 930 0 stevel 931 0 stevel /* 932 0 stevel * Fails with 933 0 stevel * _HANDLE_DESTROYED - dp's handle has been destroyed 934 0 stevel * _INTERNAL - server response too big 935 0 stevel * entity already set up with different type 936 0 stevel * _NO_RESOURCES - server out of memory 937 0 stevel */ 938 0 stevel static int 939 0 stevel datael_attach(scf_datael_t *dp) 940 0 stevel { 941 0 stevel scf_handle_t *h = dp->rd_handle; 942 0 stevel 943 0 stevel struct rep_protocol_entity_setup request; 944 0 stevel rep_protocol_response_t response; 945 0 stevel ssize_t r; 946 0 stevel 947 0 stevel assert(MUTEX_HELD(&h->rh_lock)); 948 0 stevel 949 0 stevel dp->rd_reset = 0; /* setup implicitly resets */ 950 0 stevel 951 0 stevel if (h->rh_flags & HANDLE_DEAD) 952 0 stevel return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED)); 953 0 stevel 954 0 stevel if (!handle_is_bound(h)) 955 0 stevel return (SCF_SUCCESS); /* nothing to do */ 956 0 stevel 957 0 stevel request.rpr_request = REP_PROTOCOL_ENTITY_SETUP; 958 0 stevel request.rpr_entityid = dp->rd_entity; 959 0 stevel request.rpr_entitytype = dp->rd_type; 960 0 stevel 961 0 stevel r = make_door_call(h, &request, sizeof (request), 962 0 stevel &response, sizeof (response)); 963 0 stevel 964 0 stevel if (r == NOT_BOUND || r == CALL_FAILED) 965 0 stevel return (SCF_SUCCESS); 966 0 stevel if (r == RESULT_TOO_BIG) 967 0 stevel return (scf_set_error(SCF_ERROR_INTERNAL)); 968 0 stevel 969 0 stevel if (response.rpr_response != REP_PROTOCOL_SUCCESS) 970 0 stevel return (scf_set_error(proto_error(response.rpr_response))); 971 0 stevel 972 0 stevel return (SCF_SUCCESS); 973 0 stevel } 974 0 stevel 975 0 stevel /* 976 0 stevel * Fails with 977 0 stevel * _HANDLE_DESTROYED - iter's handle has been destroyed 978 0 stevel * _INTERNAL - server response too big 979 0 stevel * iter already existed 980 0 stevel * _NO_RESOURCES 981 0 stevel */ 982 0 stevel static int 983 0 stevel iter_attach(scf_iter_t *iter) 984 0 stevel { 985 0 stevel scf_handle_t *h = iter->iter_handle; 986 0 stevel struct rep_protocol_iter_request request; 987 0 stevel struct rep_protocol_response response; 988 0 stevel int r; 989 0 stevel 990 0 stevel assert(MUTEX_HELD(&h->rh_lock)); 991 0 stevel 992 0 stevel if (h->rh_flags & HANDLE_DEAD) 993 0 stevel return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED)); 994 0 stevel 995 0 stevel if (!handle_is_bound(h)) 996 0 stevel return (SCF_SUCCESS); /* nothing to do */ 997 0 stevel 998 0 stevel request.rpr_request = REP_PROTOCOL_ITER_SETUP; 999 0 stevel request.rpr_iterid = iter->iter_id; 1000 0 stevel 1001 0 stevel r = make_door_call(h, &request, sizeof (request), 1002 0 stevel &response, sizeof (response)); 1003 0 stevel 1004 0 stevel if (r == NOT_BOUND || r == CALL_FAILED) 1005 0 stevel return (SCF_SUCCESS); 1006 0 stevel if (r == RESULT_TOO_BIG) 1007 0 stevel return (scf_set_error(SCF_ERROR_INTERNAL)); 1008 0 stevel 1009 0 stevel if (response.rpr_response != REP_PROTOCOL_SUCCESS) 1010 0 stevel return (scf_set_error(proto_error(response.rpr_response))); 1011 0 stevel 1012 0 stevel return (SCF_SUCCESS); 1013 0 stevel } 1014 0 stevel 1015 0 stevel /* 1016 0 stevel * Fails with 1017 0 stevel * _IN_USE - handle already bound 1018 0 stevel * _NO_SERVER - server door could not be open()ed 1019 0 stevel * door call failed 1020 0 stevel * door_info() failed 1021 0 stevel * _VERSION_MISMATCH - server returned bad file descriptor 1022 0 stevel * server claimed bad request 1023 0 stevel * server reported version mismatch 1024 0 stevel * server refused with unknown reason 1025 0 stevel * _INVALID_ARGUMENT 1026 0 stevel * _NO_RESOURCES - server is out of memory 1027 0 stevel * _PERMISSION_DENIED 1028 0 stevel * _INTERNAL - could not set up entities or iters 1029 0 stevel * server response too big 1030 0 stevel * 1031 0 stevel * perhaps this should try multiple times. 1032 0 stevel */ 1033 0 stevel int 1034 0 stevel scf_handle_bind(scf_handle_t *handle) 1035 0 stevel { 1036 0 stevel scf_datael_t *el; 1037 0 stevel scf_iter_t *iter; 1038 0 stevel 1039 0 stevel pid_t pid; 1040 0 stevel int fd; 1041 0 stevel int res; 1042 0 stevel door_info_t info; 1043 0 stevel repository_door_request_t request; 1044 0 stevel repository_door_response_t response; 1045 0 stevel const char *door_name = default_door_path; 1046 0 stevel 1047 0 stevel (void) pthread_mutex_lock(&handle->rh_lock); 1048 0 stevel if (handle_is_bound(handle)) { 1049 0 stevel (void) pthread_mutex_unlock(&handle->rh_lock); 1050 0 stevel return (scf_set_error(SCF_ERROR_IN_USE)); 1051 0 stevel } 1052 0 stevel 1053 0 stevel /* wait until any active fd users have cleared out */ 1054 5891 raf while (handle->rh_fd_users > 0) { 1055 5891 raf int cancel_state; 1056 5891 raf 1057 5891 raf (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 1058 5891 raf &cancel_state); 1059 5891 raf (void) pthread_cond_wait(&handle->rh_cv, &handle->rh_lock); 1060 5891 raf (void) pthread_setcancelstate(cancel_state, NULL); 1061 5891 raf } 1062 0 stevel 1063 0 stevel /* check again, since we had to drop the lock */ 1064 0 stevel if (handle_is_bound(handle)) { 1065 0 stevel (void) pthread_mutex_unlock(&handle->rh_lock); 1066 0 stevel return (scf_set_error(SCF_ERROR_IN_USE)); 1067 0 stevel } 1068 0 stevel 1069 0 stevel assert(handle->rh_doorfd == -1 && handle->rh_doorfd_old == -1); 1070 0 stevel 1071 0 stevel if (handle->rh_doorpath[0] != 0) 1072 0 stevel door_name = handle->rh_doorpath; 1073 0 stevel 1074 0 stevel fd = open(door_name, O_RDONLY, 0); 1075 0 stevel if (fd == -1) { 1076 0 stevel (void) pthread_mutex_unlock(&handle->rh_lock); 1077 0 stevel return (scf_set_error(SCF_ERROR_NO_SERVER)); 1078 0 stevel } 1079 0 stevel 1080 0 stevel request.rdr_version = REPOSITORY_DOOR_VERSION; 1081 0 stevel request.rdr_request = REPOSITORY_DOOR_REQUEST_CONNECT; 1082 0 stevel request.rdr_flags = handle->rh_flags; 1083 0 stevel request.rdr_debug = handle->rh_debug; 1084 0 stevel 1085 0 stevel pid = getpid(); 1086 0 stevel 1087 0 stevel res = make_door_call_retfd(fd, &request, sizeof (request), 1088 0 stevel &response, sizeof (response), &handle->rh_doorfd); 1089 0 stevel 1090 0 stevel (void) close(fd); 1091 0 stevel 1092 0 stevel if (res < 0) { 1093 0 stevel (void) pthread_mutex_unlock(&handle->rh_lock); 1094 0 stevel 1095 0 stevel assert(res != NOT_BOUND); 1096 0 stevel if (res == CALL_FAILED) 1097 0 stevel return (scf_set_error(SCF_ERROR_NO_SERVER)); 1098 0 stevel assert(res == RESULT_TOO_BIG); 1099 0 stevel return (scf_set_error(SCF_ERROR_INTERNAL)); 1100 0 stevel } 1101 0 stevel 1102 0 stevel if (handle->rh_doorfd < 0) { 1103 0 stevel (void) pthread_mutex_unlock(&handle->rh_lock); 1104 0 stevel 1105 0 stevel switch (response.rdr_status) { 1106 0 stevel case REPOSITORY_DOOR_SUCCESS: 1107 0 stevel return (scf_set_error(SCF_ERROR_VERSION_MISMATCH)); 1108 0 stevel 1109 0 stevel case REPOSITORY_DOOR_FAIL_BAD_REQUEST: 1110 0 stevel return (scf_set_error(SCF_ERROR_VERSION_MISMATCH)); 1111 0 stevel 1112 0 stevel case REPOSITORY_DOOR_FAIL_VERSION_MISMATCH: 1113 0 stevel return (scf_set_error(SCF_ERROR_VERSION_MISMATCH)); 1114 0 stevel 1115 0 stevel case REPOSITORY_DOOR_FAIL_BAD_FLAG: 1116 0 stevel return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 1117 0 stevel 1118 0 stevel case REPOSITORY_DOOR_FAIL_NO_RESOURCES: 1119 0 stevel return (scf_set_error(SCF_ERROR_NO_RESOURCES)); 1120 0 stevel 1121 0 stevel case REPOSITORY_DOOR_FAIL_PERMISSION_DENIED: 1122 0 stevel return (scf_set_error(SCF_ERROR_PERMISSION_DENIED)); 1123 0 stevel 1124 0 stevel default: 1125 0 stevel return (scf_set_error(SCF_ERROR_VERSION_MISMATCH)); 1126 0 stevel } 1127 0 stevel } 1128 0 stevel 1129 0 stevel (void) fcntl(handle->rh_doorfd, F_SETFD, FD_CLOEXEC); 1130 0 stevel 1131 0 stevel if (door_info(handle->rh_doorfd, &info) < 0) { 1132 0 stevel (void) close(handle->rh_doorfd); 1133 0 stevel handle->rh_doorfd = -1; 1134 0 stevel 1135 0 stevel (void) pthread_mutex_unlock(&handle->rh_lock); 1136 0 stevel return (scf_set_error(SCF_ERROR_NO_SERVER)); 1137 0 stevel } 1138 0 stevel 1139 0 stevel handle->rh_doorpid = pid; 1140 0 stevel handle->rh_doorid = info.di_uniquifier; 1141 0 stevel 1142 0 stevel /* 1143 0 stevel * Now, re-attach everything 1144 0 stevel */ 1145 0 stevel for (el = uu_list_first(handle->rh_dataels); el != NULL; 1146 0 stevel el = uu_list_next(handle->rh_dataels, el)) { 1147 0 stevel if (datael_attach(el) == -1) { 1148 0 stevel assert(scf_error() != SCF_ERROR_HANDLE_DESTROYED); 1149 0 stevel (void) handle_unbind_unlocked(handle); 1150 0 stevel (void) pthread_mutex_unlock(&handle->rh_lock); 1151 0 stevel return (-1); 1152 0 stevel } 1153 0 stevel } 1154 0 stevel 1155 0 stevel for (iter = uu_list_first(handle->rh_iters); iter != NULL; 1156 0 stevel iter = uu_list_next(handle->rh_iters, iter)) { 1157 0 stevel if (iter_attach(iter) == -1) { 1158 0 stevel assert(scf_error() != SCF_ERROR_HANDLE_DESTROYED); 1159 0 stevel (void) handle_unbind_unlocked(handle); 1160 0 stevel (void) pthread_mutex_unlock(&handle->rh_lock); 1161 0 stevel return (-1); 1162 0 stevel } 1163 0 stevel } 1164 0 stevel (void) pthread_mutex_unlock(&handle->rh_lock); 1165 0 stevel return (SCF_SUCCESS); 1166 0 stevel } 1167 0 stevel 1168 0 stevel int 1169 0 stevel scf_handle_unbind(scf_handle_t *handle) 1170 0 stevel { 1171 0 stevel int ret; 1172 0 stevel (void) pthread_mutex_lock(&handle->rh_lock); 1173 0 stevel ret = handle_unbind_unlocked(handle); 1174 0 stevel (void) pthread_mutex_unlock(&handle->rh_lock); 1175 0 stevel return (ret == SCF_SUCCESS ? ret : scf_set_error(SCF_ERROR_NOT_BOUND)); 1176 0 stevel } 1177 0 stevel 1178 0 stevel static scf_handle_t * 1179 0 stevel handle_get(scf_handle_t *h) 1180 0 stevel { 1181 0 stevel (void) pthread_mutex_lock(&h->rh_lock); 1182 0 stevel if (h->rh_flags & HANDLE_DEAD) { 1183 0 stevel (void) pthread_mutex_unlock(&h->rh_lock); 1184 0 stevel (void) scf_set_error(SCF_ERROR_HANDLE_DESTROYED); 1185 0 stevel return (NULL); 1186 0 stevel } 1187 0 stevel (void) pthread_mutex_unlock(&h->rh_lock); 1188 0 stevel return (h); 1189 0 stevel } 1190 0 stevel 1191 0 stevel /* 1192 0 stevel * Called when an object is removed from the handle. On the last remove, 1193 0 stevel * cleans up and frees the handle. 1194 0 stevel */ 1195 0 stevel static void 1196 0 stevel handle_unrefed(scf_handle_t *handle) 1197 0 stevel { 1198 0 stevel scf_iter_t *iter; 1199 0 stevel scf_value_t *v; 1200 0 stevel scf_scope_t *sc; 1201 0 stevel scf_service_t *svc; 1202 0 stevel scf_instance_t *inst; 1203 0 stevel scf_snapshot_t *snap; 1204 0 stevel scf_snaplevel_t *snaplvl; 1205 0 stevel scf_propertygroup_t *pg; 1206 0 stevel scf_property_t *prop; 1207 0 stevel 1208 0 stevel assert(MUTEX_HELD(&handle->rh_lock)); 1209 0 stevel 1210 0 stevel /* 1211 0 stevel * Don't do anything if the handle has not yet been destroyed, there 1212 0 stevel * are still external references, or we're already doing unrefed 1213 0 stevel * handling. 1214 0 stevel */ 1215 0 stevel if (!(handle->rh_flags & HANDLE_DEAD) || 1216 0 stevel handle->rh_extrefs > 0 || 1217 0 stevel handle->rh_fd_users > 0 || 1218 0 stevel (handle->rh_flags & HANDLE_UNREFED)) { 1219 0 stevel (void) pthread_mutex_unlock(&handle->rh_lock); 1220 0 stevel return; 1221 0 stevel } 1222 0 stevel 1223 0 stevel handle->rh_flags |= HANDLE_UNREFED; 1224 0 stevel 1225 0 stevel /* 1226 0 stevel * Now that we know that there are no external references, and the 1227 0 stevel * HANDLE_DEAD flag keeps new ones from appearing, we can clean up 1228 0 stevel * our subhandles and destroy the handle completely. 1229 0 stevel */ 1230 0 stevel assert(handle->rh_intrefs >= 0); 1231 0 stevel handle->rh_extrefs = handle->rh_intrefs; 1232 0 stevel handle->rh_intrefs = 0; 1233 0 stevel (void) pthread_mutex_unlock(&handle->rh_lock); 1234 0 stevel 1235 0 stevel handle_hold_subhandles(handle, RH_HOLD_ALL); 1236 0 stevel 1237 0 stevel iter = handle->rh_iter; 1238 0 stevel sc = handle->rh_scope; 1239 0 stevel svc = handle->rh_service; 1240 0 stevel inst = handle->rh_instance; 1241 0 stevel snap = handle->rh_snapshot; 1242 0 stevel snaplvl = handle->rh_snaplvl; 1243 0 stevel pg = handle->rh_pg; 1244 0 stevel prop = handle->rh_property; 1245 0 stevel v = handle->rh_value; 1246 0 stevel 1247 0 stevel handle->rh_iter = NULL; 1248 0 stevel handle->rh_scope = NULL; 1249 0 stevel handle->rh_service = NULL; 1250 0 stevel handle->rh_instance = NULL; 1251 0 stevel handle->rh_snapshot = NULL; 1252 0 stevel handle->rh_snaplvl = NULL; 1253 0 stevel handle->rh_pg = NULL; 1254 0 stevel handle->rh_property = NULL; 1255 0 stevel handle->rh_value = NULL; 1256 0 stevel 1257 0 stevel if (iter != NULL) 1258 0 stevel scf_iter_destroy(iter); 1259 0 stevel if (sc != NULL) 1260 0 stevel scf_scope_destroy(sc); 1261 0 stevel if (svc != NULL) 1262 0 stevel scf_service_destroy(svc); 1263 0 stevel if (inst != NULL) 1264 0 stevel scf_instance_destroy(inst); 1265 0 stevel if (snap != NULL) 1266 0 stevel scf_snapshot_destroy(snap); 1267 0 stevel if (snaplvl != NULL) 1268 0 stevel scf_snaplevel_destroy(snaplvl); 1269 0 stevel if (pg != NULL) 1270 0 stevel scf_pg_destroy(pg); 1271 0 stevel if (prop != NULL) 1272 0 stevel scf_property_destroy(prop); 1273 0 stevel if (v != NULL) 1274 0 stevel scf_value_destroy(v); 1275 0 stevel 1276 0 stevel (void) pthread_mutex_lock(&handle->rh_lock); 1277 0 stevel 1278 0 stevel /* there should be no outstanding children at this point */ 1279 0 stevel assert(handle->rh_extrefs == 0); 1280 0 stevel assert(handle->rh_intrefs == 0); 1281 0 stevel assert(handle->rh_values == 0); 1282 0 stevel assert(handle->rh_entries == 0); 1283 0 stevel assert(uu_list_numnodes(handle->rh_dataels) == 0); 1284 0 stevel assert(uu_list_numnodes(handle->rh_iters) == 0); 1285 0 stevel 1286 0 stevel uu_list_destroy(handle->rh_dataels); 1287 0 stevel uu_list_destroy(handle->rh_iters); 1288 0 stevel handle->rh_dataels = NULL; 1289 0 stevel handle->rh_iters = NULL; 1290 0 stevel (void) pthread_mutex_unlock(&handle->rh_lock); 1291 0 stevel 1292 0 stevel (void) pthread_mutex_destroy(&handle->rh_lock); 1293 0 stevel 1294 0 stevel uu_free(handle); 1295 0 stevel } 1296 0 stevel 1297 0 stevel void 1298 0 stevel scf_handle_destroy(scf_handle_t *handle) 1299 0 stevel { 1300 0 stevel if (handle == NULL) 1301 0 stevel return; 1302 0 stevel 1303 0 stevel (void) pthread_mutex_lock(&handle->rh_lock); 1304 0 stevel if (handle->rh_flags & HANDLE_DEAD) { 1305 0 stevel /* 1306 0 stevel * This is an error (you are not allowed to reference the 1307 0 stevel * handle after it is destroyed), but we can't report it. 1308 0 stevel */ 1309 0 stevel (void) pthread_mutex_unlock(&handle->rh_lock); 1310 0 stevel return; 1311 0 stevel } 1312 0 stevel handle->rh_flags |= HANDLE_DEAD; 1313 0 stevel (void) handle_unbind_unlocked(handle); 1314 0 stevel handle_unrefed(handle); 1315 0 stevel } 1316 0 stevel 1317 0 stevel ssize_t 1318 0 stevel scf_myname(scf_handle_t *h, char *out, size_t len) 1319 0 stevel { 1320 0 stevel char *cp; 1321 0 stevel 1322 0 stevel if (!handle_has_server(h)) 1323 0 stevel return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN)); 1324 0 stevel 1325 0 stevel cp = getenv("SMF_FMRI"); 1326 0 stevel if (cp == NULL) 1327 0 stevel return (scf_set_error(SCF_ERROR_NOT_SET)); 1328 0 stevel 1329 0 stevel return (strlcpy(out, cp, len)); 1330 0 stevel } 1331 0 stevel 1332 0 stevel static uint32_t 1333 407 jwadams handle_alloc_entityid(scf_handle_t *h) 1334 407 jwadams { 1335 407 jwadams uint32_t nextid; 1336 407 jwadams 1337 407 jwadams assert(MUTEX_HELD(&h->rh_lock)); 1338 407 jwadams 1339 407 jwadams if (uu_list_numnodes(h->rh_dataels) == UINT32_MAX) 1340 407 jwadams return (0); /* no ids available */ 1341 407 jwadams 1342 407 jwadams /* 1343 407 jwadams * The following loop assumes that there are not a huge number of 1344 407 jwadams * outstanding entities when we've wrapped. If that ends up not 1345 407 jwadams * being the case, the O(N^2) nature of this search will hurt a lot, 1346 407 jwadams * and the data structure should be switched to an AVL tree. 1347 407 jwadams */ 1348 407 jwadams nextid = h->rh_nextentity + 1; 1349 407 jwadams for (;;) { 1350 407 jwadams scf_datael_t *cur; 1351 407 jwadams 1352 407 jwadams if (nextid == 0) { 1353 407 jwadams nextid++; 1354 407 jwadams h->rh_flags |= HANDLE_WRAPPED_ENTITY; 1355 407 jwadams } 1356 407 jwadams if (!(h->rh_flags & HANDLE_WRAPPED_ENTITY)) 1357 407 jwadams break; 1358 407 jwadams 1359 407 jwadams cur = uu_list_find(h->rh_dataels, NULL, &nextid, NULL); 1360 407 jwadams if (cur == NULL) 1361 407 jwadams break; /* not in use */ 1362 407 jwadams 1363 407 jwadams if (nextid == h->rh_nextentity) 1364 407 jwadams return (0); /* wrapped around; no ids available */ 1365 407 jwadams nextid++; 1366 407 jwadams } 1367 407 jwadams 1368 407 jwadams h->rh_nextentity = nextid; 1369 407 jwadams return (nextid); 1370 407 jwadams } 1371 407 jwadams 1372 407 jwadams static uint32_t 1373 407 jwadams handle_alloc_iterid(scf_handle_t *h) 1374 407 jwadams { 1375 407 jwadams uint32_t nextid; 1376 407 jwadams 1377 407 jwadams assert(MUTEX_HELD(&h->rh_lock)); 1378 407 jwadams 1379 407 jwadams if (uu_list_numnodes(h->rh_iters) == UINT32_MAX) 1380 407 jwadams return (0); /* no ids available */ 1381 407 jwadams 1382 407 jwadams /* see the comment in handle_alloc_entityid */ 1383 407 jwadams nextid = h->rh_nextiter + 1; 1384 407 jwadams for (;;) { 1385 407 jwadams scf_iter_t *cur; 1386 407 jwadams 1387 407 jwadams if (nextid == 0) { 1388 407 jwadams nextid++; 1389 407 jwadams h->rh_flags |= HANDLE_WRAPPED_ITER; 1390 407 jwadams } 1391 407 jwadams if (!(h->rh_flags & HANDLE_WRAPPED_ITER)) 1392 407 jwadams break; /* not yet wrapped */ 1393 407 jwadams 1394 407 jwadams cur = uu_list_find(h->rh_iters, NULL, &nextid, NULL); 1395 407 jwadams if (cur == NULL) 1396 407 jwadams break; /* not in use */ 1397 407 jwadams 1398 407 jwadams if (nextid == h->rh_nextiter) 1399 407 jwadams return (0); /* wrapped around; no ids available */ 1400 407 jwadams nextid++; 1401 407 jwadams } 1402 407 jwadams 1403 407 jwadams h->rh_nextiter = nextid; 1404 407 jwadams return (nextid); 1405 407 jwadams } 1406 407 jwadams 1407 407 jwadams static uint32_t 1408 407 jwadams handle_next_changeid(scf_handle_t *handle) 1409 407 jwadams { 1410 407 jwadams uint32_t nextid; 1411 407 jwadams 1412 0 stevel assert(MUTEX_HELD(&handle->rh_lock)); 1413 407 jwadams 1414 407 jwadams nextid = ++handle->rh_nextchangeid; 1415 407 jwadams if (nextid == 0) 1416 407 jwadams nextid = ++handle->rh_nextchangeid; 1417 407 jwadams return (nextid); 1418 0 stevel } 1419 0 stevel 1420 0 stevel /* 1421 0 stevel * Fails with 1422 0 stevel * _INVALID_ARGUMENT - h is NULL 1423 0 stevel * _HANDLE_DESTROYED 1424 0 stevel * _INTERNAL - server response too big 1425 0 stevel * entity already set up with different type 1426 0 stevel * _NO_RESOURCES 1427 0 stevel */ 1428 0 stevel static int 1429 0 stevel datael_init(scf_datael_t *dp, scf_handle_t *h, uint32_t type) 1430 0 stevel { 1431 0 stevel int ret; 1432 0 stevel 1433 0 stevel if (h == NULL) 1434 0 stevel return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 1435 0 stevel 1436 0 stevel uu_list_node_init(dp, &dp->rd_node, datael_pool); 1437 0 stevel 1438 0 stevel dp->rd_handle = h; 1439 0 stevel dp->rd_type = type; 1440 0 stevel dp->rd_reset = 0; 1441 0 stevel 1442 0 stevel (void) pthread_mutex_lock(&h->rh_lock); 1443 0 stevel if (h->rh_flags & HANDLE_DEAD) { 1444 0 stevel /* 1445 0 stevel * we're in undefined territory (the user cannot use a handle 1446 0 stevel * directly after it has been destroyed), but we don't want 1447 0 stevel * to allow any new references to happen, so we fail here. 1448 0 stevel */ 1449 0 stevel (void) pthread_mutex_unlock(&h->rh_lock); 1450 0 stevel return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED)); 1451 0 stevel } 1452 0 stevel dp->rd_entity = handle_alloc_entityid(h); 1453 407 jwadams if (dp->rd_entity == 0) { 1454 407 jwadams (void) pthread_mutex_unlock(&h->rh_lock); 1455 407 jwadams uu_list_node_fini(dp, &dp->rd_node, datael_pool); 1456 407 jwadams return (scf_set_error(SCF_ERROR_NO_MEMORY)); 1457 407 jwadams } 1458 0 stevel 1459 0 stevel ret = datael_attach(dp); 1460 0 stevel if (ret == 0) { 1461 0 stevel (void) uu_list_insert_before(h->rh_dataels, NULL, dp); 1462 0 stevel h->rh_extrefs++; 1463 0 stevel } else { 1464 0 stevel uu_list_node_fini(dp, &dp->rd_node, datael_pool); 1465 0 stevel } 1466 0 stevel (void) pthread_mutex_unlock(&h->rh_lock); 1467 0 stevel 1468 0 stevel return (ret); 1469 0 stevel } 1470 0 stevel 1471 0 stevel static void 1472 0 stevel datael_destroy(scf_datael_t *dp) 1473 0 stevel { 1474 0 stevel scf_handle_t *h = dp->rd_handle; 1475 0 stevel 1476 0 stevel struct rep_protocol_entity_teardown request; 1477 0 stevel rep_protocol_response_t response; 1478 0 stevel 1479 0 stevel (void) pthread_mutex_lock(&h->rh_lock); 1480 0 stevel uu_list_remove(h->rh_dataels, dp); 1481 0 stevel --h->rh_extrefs; 1482 0 stevel 1483 0 stevel if (handle_is_bound(h)) { 1484 0 stevel request.rpr_request = REP_PROTOCOL_ENTITY_TEARDOWN; 1485 0 stevel request.rpr_entityid = dp->rd_entity; 1486 0 stevel 1487 0 stevel (void) make_door_call(h, &request, sizeof (request), 1488 0 stevel &response, sizeof (response)); 1489 0 stevel } 1490 0 stevel handle_unrefed(h); /* drops h->rh_lock */ 1491 0 stevel 1492 0 stevel dp->rd_handle = NULL; 1493 0 stevel } 1494 0 stevel 1495 0 stevel static scf_handle_t * 1496 0 stevel datael_handle(const scf_datael_t *dp) 1497 0 stevel { 1498 0 stevel return (handle_get(dp->rd_handle)); 1499 0 stevel } 1500 0 stevel 1501 0 stevel /* 1502 0 stevel * We delay ENTITY_RESETs until right before the entity is used. By doing 1503 0 stevel * them lazily, we remove quite a few unnecessary calls. 1504 0 stevel */ 1505 0 stevel static void 1506 0 stevel datael_do_reset_locked(scf_datael_t *dp) 1507 0 stevel { 1508 0 stevel scf_handle_t *h = dp->rd_handle; 1509 0 stevel 1510 0 stevel struct rep_protocol_entity_reset request; 1511 0 stevel rep_protocol_response_t response; 1512 0 stevel 1513 0 stevel assert(MUTEX_HELD(&h->rh_lock)); 1514 0 stevel 1515 0 stevel request.rpr_request = REP_PROTOCOL_ENTITY_RESET; 1516 0 stevel request.rpr_entityid = dp->rd_entity; 1517 0 stevel 1518 0 stevel (void) make_door_call(h, &request, sizeof (request), 1519 0 stevel &response, sizeof (response)); 1520 0 stevel 1521 0 stevel dp->rd_reset = 0; 1522 0 stevel } 1523 0 stevel 1524 0 stevel static void 1525 0 stevel datael_reset_locked(scf_datael_t *dp) 1526 0 stevel { 1527 0 stevel assert(MUTEX_HELD(&dp->rd_handle->rh_lock)); 1528 0 stevel dp->rd_reset = 1; 1529 0 stevel } 1530 0 stevel 1531 0 stevel static void 1532 0 stevel datael_reset(scf_datael_t *dp) 1533 0 stevel { 1534 0 stevel scf_handle_t *h = dp->rd_handle; 1535 0 stevel 1536 0 stevel (void) pthread_mutex_lock(&h->rh_lock); 1537 0 stevel dp->rd_reset = 1; 1538 0 stevel (void) pthread_mutex_unlock(&h->rh_lock); 1539 0 stevel } 1540 0 stevel 1541 0 stevel static void 1542 0 stevel datael_finish_reset(const scf_datael_t *dp_arg) 1543 0 stevel { 1544 0 stevel scf_datael_t *dp = (scf_datael_t *)dp_arg; 1545 0 stevel 1546 0 stevel if (dp->rd_reset) 1547 0 stevel datael_do_reset_locked(dp); 1548 0 stevel } 1549 0 stevel 1550 0 stevel /* 1551 0 stevel * Fails with _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response too 1552 0 stevel * big, bad entity id, request not applicable to entity, name too long for 1553 0 stevel * buffer), _NOT_SET, _DELETED, or _CONSTRAINT_VIOLATED (snaplevel is not of an 1554 0 stevel * instance). 1555 0 stevel */ 1556 0 stevel static ssize_t 1557 0 stevel datael_get_name(const scf_datael_t *dp, char *buf, size_t size, uint32_t type) 1558 0 stevel { 1559 0 stevel scf_handle_t *h = dp->rd_handle; 1560 0 stevel 1561 0 stevel struct rep_protocol_entity_name request; 1562 0 stevel struct rep_protocol_name_response response; 1563 0 stevel ssize_t r; 1564 0 stevel 1565 0 stevel (void) pthread_mutex_lock(&h->rh_lock); 1566 0 stevel request.rpr_request = REP_PROTOCOL_ENTITY_NAME; 1567 0 stevel request.rpr_entityid = dp->rd_entity; 1568 0 stevel request.rpr_answertype = type; 1569 0 stevel 1570 0 stevel datael_finish_reset(dp); 1571 0 stevel r = make_door_call(h, &request, sizeof (request), 1572 0 stevel &response, sizeof (response)); 1573 0 stevel (void) pthread_mutex_unlock(&h->rh_lock); 1574 0 stevel 1575 0 stevel if (r < 0) 1576 0 stevel DOOR_ERRORS_BLOCK(r); 1577 0 stevel 1578 0 stevel if (response.rpr_response != REP_PROTOCOL_SUCCESS) { 1579 0 stevel assert(response.rpr_response != REP_PROTOCOL_FAIL_BAD_REQUEST); 1580 0 stevel if (response.rpr_response == REP_PROTOCOL_FAIL_NOT_FOUND) 1581 0 stevel return (scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED)); 1582 0 stevel return (scf_set_error(proto_error(response.rpr_response))); 1583 0 stevel } 1584 0 stevel return (strlcpy(buf, response.rpr_name, size)); 1585 0 stevel } 1586 0 stevel 1587 0 stevel /* 1588 0 stevel * Fails with _HANDLE_MISMATCH, _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL 1589 0 stevel * (server response too big, bad element id), _EXISTS (elements have same id), 1590 0 stevel * _NOT_SET, _DELETED, _CONSTRAINT_VIOLATED, _NOT_FOUND (scope has no parent), 1591 0 stevel * or _SUCCESS. 1592 0 stevel */ 1593 0 stevel static int 1594 0 stevel datael_get_parent(const scf_datael_t *dp, scf_datael_t *pp) 1595 0 stevel { 1596 0 stevel scf_handle_t *h = dp->rd_handle; 1597 0 stevel 1598 0 stevel struct rep_protocol_entity_parent request; 1599 0 stevel struct rep_protocol_response response; 1600 0 stevel 1601 0 stevel ssize_t r; 1602 0 stevel 1603 0 stevel if (h != pp->rd_handle) 1604 0 stevel return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH)); 1605 0 stevel 1606 0 stevel (void) pthread_mutex_lock(&h->rh_lock); 1607 0 stevel request.rpr_request = REP_PROTOCOL_ENTITY_GET_PARENT; 1608 0 stevel request.rpr_entityid = dp->rd_entity; 1609 0 stevel request.rpr_outid = pp->rd_entity; 1610 0 stevel 1611 0 stevel datael_finish_reset(dp); 1612 0 stevel datael_finish_reset(pp); 1613 0 stevel r = make_door_call(h, &request, sizeof (request), 1614 0 stevel &response, sizeof (response)); 1615 0 stevel (void) pthread_mutex_unlock(&h->rh_lock); 1616 0 stevel 1617 0 stevel if (r < 0) 1618 0 stevel DOOR_ERRORS_BLOCK(r); 1619 0 stevel 1620 0 stevel if (response.rpr_response != REP_PROTOCOL_SUCCESS) { 1621 0 stevel if (response.rpr_response == REP_PROTOCOL_FAIL_TYPE_MISMATCH) 1622 0 stevel return (scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED)); 1623 0 stevel return (scf_set_error(proto_error(response.rpr_response))); 1624 0 stevel } 1625 0 stevel 1626 0 stevel return (SCF_SUCCESS); 1627 0 stevel } 1628 0 stevel 1629 0 stevel /* 1630 0 stevel * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT (out does not have type type, 1631 0 stevel * name is invalid), _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response 1632 0 stevel * too big, bad id, iter already exists, element cannot have children of type, 1633 0 stevel * type is invalid, iter was reset, sequence was bad, iter walks values, iter 1634 0 stevel * does not walk type entities), _NOT_SET, _DELETED, _NO_RESOURCES, 1635 4740 jeanm * _BACKEND_ACCESS, _NOT_FOUND. 1636 0 stevel */ 1637 0 stevel static int 1638 0 stevel datael_get_child_composed_locked(const scf_datael_t *dp, const char *name, 1639 0 stevel uint32_t type, scf_datael_t *out, scf_iter_t *iter) 1640 0 stevel { 1641 0 stevel struct rep_protocol_iter_start request; 1642 0 stevel struct rep_protocol_iter_read read_request; 1643 0 stevel struct rep_protocol_response response; 1644 0 stevel 1645 0 stevel scf_handle_t *h = dp->rd_handle; 1646 0 stevel ssize_t r; 1647 0 stevel 1648 0 stevel if (h != out->rd_handle) 1649 0 stevel return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH)); 1650 0 stevel 1651 0 stevel if (out->rd_type != type) 1652 0 stevel return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 1653 0 stevel 1654 0 stevel assert(MUTEX_HELD(&h->rh_lock)); 1655 0 stevel assert(iter != NULL); 1656 0 stevel 1657 0 stevel scf_iter_reset_locked(iter); 1658 0 stevel iter->iter_type = type; 1659 0 stevel 1660 0 stevel request.rpr_request = REP_PROTOCOL_ITER_START; 1661 0 stevel request.rpr_iterid = iter->iter_id; 1662 0 stevel request.rpr_entity = dp->rd_entity; 1663 0 stevel request.rpr_itertype = type; 1664 0 stevel request.rpr_flags = RP_ITER_START_EXACT | RP_ITER_START_COMPOSED; 1665 0 stevel 1666 0 stevel if (name == NULL || strlcpy(request.rpr_pattern, name, 1667 0 stevel sizeof (request.rpr_pattern)) >= sizeof (request.rpr_pattern)) { 1668 0 stevel return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 1669 0 stevel } 1670 0 stevel 1671 0 stevel datael_finish_reset(dp); 1672 0 stevel datael_finish_reset(out); 1673 0 stevel 1674 0 stevel /* 1675 0 stevel * We hold the handle lock across both door calls, so that they 1676 0 stevel * appear atomic. 1677 0 stevel */ 1678 0 stevel r = make_door_call(h, &request, sizeof (request), 1679 0 stevel &response, sizeof (response)); 1680 0 stevel 1681 0 stevel if (r < 0) 1682 0 stevel DOOR_ERRORS_BLOCK(r); 1683 0 stevel 1684 0 stevel if (response.rpr_response != REP_PROTOCOL_SUCCESS) 1685 0 stevel return (scf_set_error(proto_error(response.rpr_response))); 1686 0 stevel 1687 0 stevel iter->iter_sequence++; 1688 0 stevel 1689 0 stevel read_request.rpr_request = REP_PROTOCOL_ITER_READ; 1690 0 stevel read_request.rpr_iterid = iter->iter_id; 1691 0 stevel read_request.rpr_sequence = iter->iter_sequence; 1692 0 stevel read_request.rpr_entityid = out->rd_entity; 1693 0 stevel 1694 0 stevel r = make_door_call(h, &read_request, sizeof (read_request), 1695 0 stevel &response, sizeof (response)); 1696 0 stevel 1697 0 stevel scf_iter_reset_locked(iter); 1698 0 stevel 1699 0 stevel if (r < 0) 1700 0 stevel DOOR_ERRORS_BLOCK(r); 1701 0 stevel 1702 0 stevel if (response.rpr_response == REP_PROTOCOL_DONE) { 1703 0 stevel return (scf_set_error(SCF_ERROR_NOT_FOUND)); 1704 0 stevel } 1705 0 stevel 1706 0 stevel if (response.rpr_response != REP_PROTOCOL_SUCCESS) { 1707 0 stevel if (response.rpr_response == REP_PROTOCOL_FAIL_NOT_SET || 1708 0 stevel response.rpr_response == REP_PROTOCOL_FAIL_BAD_REQUEST) 1709 0 stevel return (scf_set_error(SCF_ERROR_INTERNAL)); 1710 0 stevel return (scf_set_error(proto_error(response.rpr_response))); 1711 0 stevel } 1712 0 stevel 1713 0 stevel return (0); 1714 0 stevel } 1715 0 stevel 1716 0 stevel /* 1717 0 stevel * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT (out does not have type type, 1718 0 stevel * name is invalid), _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response 1719 0 stevel * too big, bad id, element cannot have children of type, type is invalid), 1720 0 stevel * _NOT_SET, _DELETED, _NO_RESOURCES, _BACKEND_ACCESS. 1721 0 stevel */ 1722 0 stevel static int 1723 0 stevel datael_get_child_locked(const scf_datael_t *dp, const char *name, 1724 0 stevel uint32_t type, scf_datael_t *out) 1725 0 stevel { 1726 0 stevel struct rep_protocol_entity_get_child request; 1727 0 stevel struct rep_protocol_response response; 1728 0 stevel 1729 0 stevel scf_handle_t *h = dp->rd_handle; 1730 0 stevel ssize_t r; 1731 0 stevel 1732 0 stevel if (h != out->rd_handle) 1733 0 stevel return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH)); 1734 0 stevel 1735 0 stevel if (out->rd_type != type) 1736 0 stevel return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 1737 0 stevel 1738 0 stevel assert(MUTEX_HELD(&h->rh_lock)); 1739 0 stevel 1740 0 stevel request.rpr_request = REP_PROTOCOL_ENTITY_GET_CHILD; 1741 0 stevel request.rpr_entityid = dp->rd_entity; 1742 0 stevel request.rpr_childid = out->rd_entity; 1743 0 stevel 1744 0 stevel if (name == NULL || strlcpy(request.rpr_name, name, 1745 0 stevel sizeof (request.rpr_name)) >= sizeof (request.rpr_name)) { 1746 0 stevel return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 1747 0 stevel } 1748 0 stevel 1749 0 stevel datael_finish_reset(dp); 1750 0 stevel datael_finish_reset(out); 1751 0 stevel 1752 0 stevel r = make_door_call(h, &request, sizeof (request), 1753 0 stevel &response, sizeof (response)); 1754 0 stevel 1755 0 stevel if (r < 0) 1756 0 stevel DOOR_ERRORS_BLOCK(r); 1757 0 stevel 1758 0 stevel if (response.rpr_response != REP_PROTOCOL_SUCCESS) 1759 0 stevel return (scf_set_error(proto_error(response.rpr_response))); 1760 0 stevel return (0); 1761 0 stevel } 1762 0 stevel 1763 4740 jeanm /* 1764 4740 jeanm * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT (out does not have type type, 1765 4740 jeanm * name is invalid), _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response 1766 4740 jeanm * too big, bad id, iter already exists, element cannot have children of type, 1767 4740 jeanm * type is invalid, iter was reset, sequence was bad, iter walks values, iter 1768 4740 jeanm * does not walk type entities), _NOT_SET, _DELETED, _NO_RESOURCES, 1769 4740 jeanm * _BACKEND_ACCESS, _NOT_FOUND. 1770 4740 jeanm */ 1771 0 stevel static int 1772 0 stevel datael_get_child(const scf_datael_t *dp, const char *name, uint32_t type, 1773 0 stevel scf_datael_t *out, boolean_t composed) 1774 0 stevel { 1775 0 stevel scf_handle_t *h = dp->rd_handle; 1776 0 stevel uint32_t held = 0; 1777 0 stevel int ret; 1778 0 stevel 1779 0 stevel scf_iter_t *iter = NULL; 1780 0 stevel 1781 0 stevel if (composed) 1782 0 stevel iter = HANDLE_HOLD_ITER(h); 1783 0 stevel 1784 0 stevel if (out == NULL) { 1785 0 stevel switch (type) { 1786 0 stevel case REP_PROTOCOL_ENTITY_SERVICE: 1787 0 stevel out = &HANDLE_HOLD_SERVICE(h)->rd_d; 1788 0 stevel held = RH_HOLD_SERVICE; 1789 0 stevel break; 1790 0 stevel 1791 0 stevel case REP_PROTOCOL_ENTITY_INSTANCE: 1792 0 stevel out = &HANDLE_HOLD_INSTANCE(h)->rd_d; 1793 0 stevel held = RH_HOLD_INSTANCE; 1794 0 stevel break; 1795 0 stevel 1796 0 stevel case REP_PROTOCOL_ENTITY_SNAPSHOT: 1797 0 stevel out = &HANDLE_HOLD_SNAPSHOT(h)->rd_d; 1798 0 stevel held = RH_HOLD_SNAPSHOT; 1799 0 stevel break; 1800 0 stevel 1801 0 stevel case REP_PROTOCOL_ENTITY_SNAPLEVEL: 1802 0 stevel out = &HANDLE_HOLD_SNAPLVL(h)->rd_d; 1803 0 stevel held = RH_HOLD_SNAPLVL; 1804 0 stevel break; 1805 0 stevel 1806 0 stevel case REP_PROTOCOL_ENTITY_PROPERTYGRP: 1807 0 stevel out = &HANDLE_HOLD_PG(h)->rd_d; 1808 0 stevel held = RH_HOLD_PG; 1809 0 stevel break; 1810 0 stevel 1811 0 stevel case REP_PROTOCOL_ENTITY_PROPERTY: 1812 0 stevel out = &HANDLE_HOLD_PROPERTY(h)->rd_d; 1813 0 stevel held = RH_HOLD_PROPERTY; 1814 0 stevel break; 1815 0 stevel 1816 0 stevel default: 1817 0 stevel assert(0); 1818 0 stevel abort(); 1819 0 stevel } 1820 0 stevel } 1821 0 stevel 1822 0 stevel (void) pthread_mutex_lock(&h->rh_lock); 1823 0 stevel if (composed) 1824 0 stevel ret = datael_get_child_composed_locked(dp, name, type, out, 1825 0 stevel iter); 1826 0 stevel else 1827 0 stevel ret = datael_get_child_locked(dp, name, type, out); 1828 0 stevel (void) pthread_mutex_unlock(&h->rh_lock); 1829 0 stevel 1830 0 stevel if (composed) 1831 0 stevel HANDLE_RELE_ITER(h); 1832 0 stevel 1833 0 stevel if (held) 1834 0 stevel handle_rele_subhandles(h, held); 1835 0 stevel 1836 0 stevel return (ret); 1837 0 stevel } 1838 0 stevel 1839 0 stevel /* 1840 0 stevel * Fails with 1841 0 stevel * _HANDLE_MISMATCH 1842 0 stevel * _INVALID_ARGUMENT - name is too long 1843 0 stevel * invalid changeid 1844 0 stevel * name is invalid 1845 0 stevel * cannot create children for dp's type of node 1846 0 stevel * _NOT_BOUND - handle is not bound 1847 0 stevel * _CONNECTION_BROKEN - server is not reachable 1848 0 stevel * _INTERNAL - server response too big 1849 0 stevel * dp or cp has unknown id 1850 0 stevel * type is _PROPERTYGRP 1851 0 stevel * type is invalid 1852 0 stevel * dp cannot have children of type type 1853 0 stevel * database is corrupt 1854 0 stevel * _EXISTS - dp & cp have the same id 1855 0 stevel * _EXISTS - child already exists 1856 0 stevel * _DELETED - dp has been deleted 1857 0 stevel * _NOT_SET - dp is reset 1858 0 stevel * _NO_RESOURCES 1859 0 stevel * _PERMISSION_DENIED 1860 0 stevel * _BACKEND_ACCESS 1861 0 stevel * _BACKEND_READONLY 1862 0 stevel */ 1863 0 stevel static int 1864 0 stevel datael_add_child(const scf_datael_t *dp, const char *name, uint32_t type, 1865 0 stevel scf_datael_t *cp) 1866 0 stevel { 1867 0 stevel scf_handle_t *h = dp->rd_handle; 1868 0 stevel 1869 0 stevel struct rep_protocol_entity_create_child request; 1870 0 stevel struct rep_protocol_response response; 1871 0 stevel ssize_t r; 1872 0 stevel uint32_t held = 0; 1873 0 stevel 1874 0 stevel if (cp == NULL) { 1875 0 stevel switch (type) { 1876 0 stevel case REP_PROTOCOL_ENTITY_SCOPE: 1877 0 stevel cp = &HANDLE_HOLD_SCOPE(h)->rd_d; 1878 0 stevel held = RH_HOLD_SCOPE; 1879 0 stevel break; 1880 0 stevel case REP_PROTOCOL_ENTITY_SERVICE: 1881 0 stevel cp = &HANDLE_HOLD_SERVICE(h)->rd_d; 1882 0 stevel held = RH_HOLD_SERVICE; 1883 0 stevel break; 1884 0 stevel case REP_PROTOCOL_ENTITY_INSTANCE: 1885 0 stevel cp = &HANDLE_HOLD_INSTANCE(h)->rd_d; 1886 0 stevel held = RH_HOLD_INSTANCE; 1887 0 stevel break; 1888 0 stevel case REP_PROTOCOL_ENTITY_SNAPSHOT: 1889 0 stevel default: 1890 0 stevel assert(0); 1891 0 stevel abort(); 1892 0 stevel } 1893 0 stevel assert(h == cp->rd_handle); 1894 0 stevel 1895 0 stevel } else if (h != cp->rd_handle) { 1896 0 stevel return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH)); 1897 0 stevel } 1898 0 stevel 1899 0 stevel if (strlcpy(request.rpr_name, name, sizeof (request.rpr_name)) >= 1900 0 stevel sizeof (request.rpr_name)) { 1901 0 stevel r = scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 1902 0 stevel goto err; 1903 0 stevel } 1904 0 stevel 1905 0 stevel (void) pthread_mutex_lock(&h->rh_lock); 1906 0 stevel request.rpr_request = REP_PROTOCOL_ENTITY_CREATE_CHILD; 1907 0 stevel request.rpr_entityid = dp->rd_entity; 1908 0 stevel request.rpr_childtype = type; 1909 0 stevel request.rpr_childid = cp->rd_entity; 1910 0 stevel 1911 0 stevel datael_finish_reset(dp); 1912 407 jwadams request.rpr_changeid = handle_next_changeid(h); 1913 0 stevel r = make_door_call(h, &request, sizeof (request), 1914 0 stevel &response, sizeof (response)); 1915 0 stevel (void) pthread_mutex_unlock(&h->rh_lock); 1916 0 stevel 1917 0 stevel if (held) 1918 0 stevel handle_rele_subhandles(h, held); 1919 0 stevel 1920 0 stevel if (r < 0) 1921 0 stevel DOOR_ERRORS_BLOCK(r); 1922 0 stevel 1923 0 stevel if (response.rpr_response != REP_PROTOCOL_SUCCESS) 1924 0 stevel return (scf_set_error(proto_error(response.rpr_response))); 1925 0 stevel 1926 0 stevel return (SCF_SUCCESS); 1927 0 stevel 1928 0 stevel err: 1929 0 stevel if (held) 1930 0 stevel handle_rele_subhandles(h, held); 1931 0 stevel return (r); 1932 0 stevel } 1933 0 stevel 1934 0 stevel static int 1935 0 stevel datael_add_pg(const scf_datael_t *dp, const char *name, const char *type, 1936 0 stevel uint32_t flags, scf_datael_t *cp) 1937 0 stevel { 1938 0 stevel scf_handle_t *h = dp->rd_handle; 1939 0 stevel 1940 0 stevel struct rep_protocol_entity_create_pg request; 1941 0 stevel struct rep_protocol_response response; 1942 0 stevel ssize_t r; 1943 0 stevel 1944 0 stevel int holding_els = 0; 1945 0 stevel 1946 0 stevel if (cp == NULL) { 1947 0 stevel holding_els = 1; 1948 0 stevel cp = &HANDLE_HOLD_PG(h)->rd_d; 1949 0 stevel assert(h == cp->rd_handle); 1950 0 stevel 1951 0 stevel } else if (h != cp->rd_handle) { 1952 0 stevel return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH)); 1953 0 stevel } 1954 0 stevel 1955 0 stevel request.rpr_request = REP_PROTOCOL_ENTITY_CREATE_PG; 1956 0 stevel 1957 0 stevel if (name == NULL || strlcpy(request.rpr_name, name, 1958 0 stevel sizeof (request.rpr_name)) > sizeof (request.rpr_name)) { 1959 0 stevel r = scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 1960 0 stevel goto err; 1961 0 stevel } 1962 0 stevel 1963 0 stevel if (type == NULL || strlcpy(request.rpr_type, type, 1964 0 stevel sizeof (request.rpr_type)) > sizeof (request.rpr_type)) { 1965 0 stevel r = scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 1966 0 stevel goto err; 1967 0 stevel } 1968 0 stevel 1969 0 stevel (void) pthread_mutex_lock(&h->rh_lock); 1970 0 stevel request.rpr_entityid = dp->rd_entity; 1971 0 stevel request.rpr_childid = cp->rd_entity; 1972 0 stevel request.rpr_flags = flags; 1973 0 stevel 1974 0 stevel datael_finish_reset(dp); 1975 0 stevel datael_finish_reset(cp); 1976 407 jwadams request.rpr_changeid = handle_next_changeid(h); 1977 0 stevel r = make_door_call(h, &request, sizeof (request), 1978 0 stevel &response, sizeof (response)); 1979 0 stevel (void) pthread_mutex_unlock(&h->rh_lock); 1980 0 stevel 1981 0 stevel if (holding_els) 1982 0 stevel HANDLE_RELE_PG(h); 1983 0 stevel 1984 0 stevel if (r < 0) 1985 0 stevel DOOR_ERRORS_BLOCK(r); 1986 0 stevel 1987 0 stevel if (response.rpr_response != REP_PROTOCOL_SUCCESS) 1988 0 stevel return (scf_set_error(proto_error(response.rpr_response))); 1989 0 stevel 1990 0 stevel return (SCF_SUCCESS); 1991 0 stevel 1992 0 stevel err: 1993 0 stevel if (holding_els) 1994 0 stevel HANDLE_RELE_PG(h); 1995 0 stevel return (r); 1996 0 stevel } 1997 0 stevel 1998 0 stevel static int 1999 0 stevel datael_delete(const scf_datael_t *dp) 2000 0 stevel { 2001 0 stevel scf_handle_t *h = dp->rd_handle; 2002 0 stevel 2003 0 stevel struct rep_protocol_entity_delete request; 2004 0 stevel struct rep_protocol_response response; 2005 0 stevel ssize_t r; 2006 0 stevel 2007 0 stevel (void) pthread_mutex_lock(&h->rh_lock); 2008 0 stevel request.rpr_request = REP_PROTOCOL_ENTITY_DELETE; 2009 0 stevel request.rpr_entityid = dp->rd_entity; 2010 0 stevel 2011 0 stevel datael_finish_reset(dp); 2012 407 jwadams request.rpr_changeid = handle_next_changeid(h); 2013 0 stevel r = make_door_call(h, &request, sizeof (request), 2014 0 stevel &response, sizeof (response)); 2015 0 stevel (void) pthread_mutex_unlock(&h->rh_lock); 2016 0 stevel 2017 0 stevel if (r < 0) 2018 0 stevel DOOR_ERRORS_BLOCK(r); 2019 0 stevel 2020 0 stevel if (response.rpr_response != REP_PROTOCOL_SUCCESS) 2021 0 stevel return (scf_set_error(proto_error(response.rpr_response))); 2022 0 stevel 2023 0 stevel return (SCF_SUCCESS); 2024 0 stevel } 2025 0 stevel 2026 0 stevel /* 2027 0 stevel * Fails with 2028 0 stevel * _INVALID_ARGUMENT - h is NULL 2029 0 stevel * _NO_MEMORY 2030 0 stevel * _HANDLE_DESTROYED - h has been destroyed 2031 0 stevel * _INTERNAL - server response too big 2032 0 stevel * iter already exists 2033 0 stevel * _NO_RESOURCES 2034 0 stevel */ 2035 0 stevel scf_iter_t * 2036 0 stevel scf_iter_create(scf_handle_t *h) 2037 0 stevel { 2038 0 stevel scf_iter_t *iter; 2039 0 stevel 2040 0 stevel if (h == NULL) { 2041 0 stevel (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 2042 0 stevel return (NULL); 2043 0 stevel } 2044 0 stevel 2045 0 stevel iter = uu_zalloc(sizeof (*iter)); 2046 0 stevel if (iter == NULL) { 2047 0 stevel (void) scf_set_error(SCF_ERROR_NO_MEMORY); 2048 0 stevel return (NULL); 2049 0 stevel } 2050 0 stevel 2051 0 stevel uu_list_node_init(iter, &iter->iter_node, iter_pool); 2052 0 stevel iter->iter_handle = h; 2053 0 stevel iter->iter_sequence = 1; 2054 0 stevel iter->iter_type = REP_PROTOCOL_ENTITY_NONE; 2055 0 stevel 2056 0 stevel (void) pthread_mutex_lock(&h->rh_lock); 2057 0 stevel iter->iter_id = handle_alloc_iterid(h); 2058 407 jwadams if (iter->iter_id == 0) { 2059 407 jwadams (void) pthread_mutex_unlock(&h->rh_lock); 2060 407 jwadams uu_list_node_fini(iter, &iter->iter_node, iter_pool); 2061 407 jwadams (void) scf_set_error(SCF_ERROR_NO_MEMORY); 2062 7887 Liane uu_free(iter); 2063 407 jwadams return (NULL); 2064 407 jwadams } 2065 0 stevel if (iter_attach(iter) == -1) { 2066 0 stevel uu_list_node_fini(iter, &iter->iter_node, iter_pool); 2067 0 stevel (void) pthread_mutex_unlock(&h->rh_lock); 2068 0 stevel uu_free(iter); 2069 0 stevel return (NULL); 2070 0 stevel } 2071 0 stevel (void) uu_list_insert_before(h->rh_iters, NULL, iter); 2072 0 stevel h->rh_extrefs++; 2073 0 stevel (void) pthread_mutex_unlock(&h->rh_lock); 2074 0 stevel return (iter); 2075 0 stevel } 2076 0 stevel 2077 0 stevel scf_handle_t * 2078 0 stevel scf_iter_handle(const scf_iter_t *iter) 2079 0 stevel { 2080 0 stevel return (handle_get(iter->iter_handle)); 2081 0 stevel } 2082 0 stevel 2083 0 stevel static void 2084 0 stevel scf_iter_reset_locked(scf_iter_t *iter) 2085 0 stevel { 2086 0 stevel struct rep_protocol_iter_request request; 2087 0 stevel struct rep_protocol_response response; 2088 0 stevel 2089 0 stevel request.rpr_request = REP_PROTOCOL_ITER_RESET; 2090 0 stevel request.rpr_iterid = iter->iter_id; 2091 0 stevel 2092 0 stevel assert(MUTEX_HELD(&iter->iter_handle->rh_lock)); 2093 0 stevel 2094 0 stevel (void) make_door_call(iter->iter_handle, 2095 0 stevel &request, sizeof (request), &response, sizeof (response)); 2096 0 stevel 2097 0 stevel iter->iter_type = REP_PROTOCOL_ENTITY_NONE; 2098 0 stevel iter->iter_sequence = 1; 2099 0 stevel } 2100 0 stevel 2101 0 stevel void 2102 0 stevel scf_iter_reset(scf_iter_t *iter) 2103 0 stevel { 2104 0 stevel (void) pthread_mutex_lock(&iter->iter_handle->rh_lock); 2105 0 stevel scf_iter_reset_locked(iter); 2106 0 stevel (void) pthread_mutex_unlock(&iter->iter_handle->rh_lock); 2107 0 stevel } 2108 0 stevel 2109 0 stevel void 2110 0 stevel scf_iter_destroy(scf_iter_t *iter) 2111 0 stevel { 2112 0 stevel scf_handle_t *handle; 2113 0 stevel 2114 0 stevel struct rep_protocol_iter_request request; 2115 0 stevel struct rep_protocol_response response; 2116 0 stevel 2117 0 stevel if (iter == NULL) 2118 0 stevel return; 2119 0 stevel 2120 0 stevel handle = iter->iter_handle; 2121 0 stevel 2122 0 stevel (void) pthread_mutex_lock(&handle->rh_lock); 2123 0 stevel request.rpr_request = REP_PROTOCOL_ITER_TEARDOWN; 2124 0 stevel request.rpr_iterid = iter->iter_id; 2125 0 stevel 2126 0 stevel (void) make_door_call(handle, &request, sizeof (request), 2127 0 stevel &response, sizeof (response)); 2128 0 stevel 2129 0 stevel uu_list_remove(handle->rh_iters, iter); 2130 0 stevel --handle->rh_extrefs; 2131 0 stevel handle_unrefed(handle); /* drops h->rh_lock */ 2132 0 stevel iter->iter_handle = NULL; 2133 0 stevel 2134 0 stevel uu_list_node_fini(iter, &iter->iter_node, iter_pool); 2135 0 stevel uu_free(iter); 2136 0 stevel } 2137 0 stevel 2138 0 stevel static int 2139 0 stevel handle_get_local_scope_locked(scf_handle_t *handle, scf_scope_t *out) 2140 0 stevel { 2141 0 stevel struct rep_protocol_entity_get request; 2142 0 stevel struct rep_protocol_name_response response; 2143 0 stevel ssize_t r; 2144 0 stevel 2145 0 stevel assert(MUTEX_HELD(&handle->rh_lock)); 2146 0 stevel 2147 0 stevel if (handle != out->rd_d.rd_handle) 2148 0 stevel return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH)); 2149 0 stevel 2150 0 stevel request.rpr_request = REP_PROTOCOL_ENTITY_GET; 2151 0 stevel request.rpr_entityid = out->rd_d.rd_entity; 2152 0 stevel request.rpr_object = RP_ENTITY_GET_MOST_LOCAL_SCOPE; 2153 0 stevel 2154 0 stevel datael_finish_reset(&out->rd_d); 2155 0 stevel r = make_door_call(handle, &request, sizeof (request), 2156 0 stevel &response, sizeof (response)); 2157 0 stevel 2158 0 stevel if (r < 0) 2159 0 stevel DOOR_ERRORS_BLOCK(r); 2160 0 stevel 2161 0 stevel if (response.rpr_response != REP_PROTOCOL_SUCCESS) 2162 0 stevel return (scf_set_error(proto_error(response.rpr_response))); 2163 0 stevel 2164 0 stevel return (SCF_SUCCESS); 2165 0 stevel } 2166 0 stevel 2167 0 stevel int 2168 0 stevel scf_iter_handle_scopes(scf_iter_t *iter, const scf_handle_t *handle) 2169 0 stevel { 2170 0 stevel scf_handle_t *h = iter->iter_handle; 2171 0 stevel if (h != handle) 2172 0 stevel return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH)); 2173 0 stevel 2174 0 stevel (void) pthread_mutex_lock(&h->rh_lock); 2175 0 stevel scf_iter_reset_locked(iter); 2176 0 stevel 2177 0 stevel if (!handle_is_bound(h)) { 2178 0 stevel (void) pthread_mutex_unlock(&h->rh_lock); 2179 0 stevel return (scf_set_error(SCF_ERROR_NOT_BOUND)); 2180 0 stevel } 2181 0 stevel 2182 407 jwadams if (!handle_has_server_locked(h)) { 2183 0 stevel (void) pthread_mutex_unlock(&h->rh_lock); 2184 0 stevel return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN)); 2185 0 stevel } 2186 0 stevel 2187 0 stevel iter->iter_type = REP_PROTOCOL_ENTITY_SCOPE; 2188 0 stevel iter->iter_sequence = 1; 2189 0 stevel (void) pthread_mutex_unlock(&h->rh_lock); 2190 0 stevel return (0); 2191 0 stevel } 2192 0 stevel 2193 0 stevel int 2194 0 stevel scf_iter_next_scope(scf_iter_t *iter, scf_scope_t *out) 2195 0 stevel { 2196 0 stevel int ret; 2197 0 stevel scf_handle_t *h = iter->iter_handle; 2198 0 stevel 2199 0 stevel if (h != out->rd_d.rd_handle) 2200 0 stevel return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH)); 2201 0 stevel 2202 0 stevel (void) pthread_mutex_lock(&h->rh_lock); 2203 0 stevel if (iter->iter_type == REP_PROTOCOL_ENTITY_NONE) { 2204 0 stevel (void) pthread_mutex_unlock(&h->rh_lock); 2205 0 stevel return (scf_set_error(SCF_ERROR_NOT_SET)); 2206 0 stevel } 2207 0 stevel if (iter->iter_type != REP_PROTOCOL_ENTITY_SCOPE) { 2208 0 stevel (void) pthread_mutex_unlock(&h->rh_lock); 2209 0 stevel return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 2210 0 stevel } 2211 0 stevel if (iter->iter_sequence == 1) { 2212 0 stevel if ((ret = handle_get_local_scope_locked(h, out)) == 2213 0 stevel SCF_SUCCESS) { 2214 0 stevel iter->iter_sequence++; 2215 0 stevel ret = 1; 2216 0 stevel } 2217 0 stevel } else { 2218 0 stevel datael_reset_locked(&out->rd_d); 2219 0 stevel ret = 0; 2220 0 stevel } 2221 0 stevel (void) pthread_mutex_unlock(&h->rh_lock); 2222 0 stevel return (ret); 2223 0 stevel } 2224 0 stevel 2225 0 stevel int 2226 0 stevel scf_handle_get_scope(scf_handle_t *h, const char *name, scf_scope_t *out) 2227 0 stevel { 2228 0 stevel int ret; 2229 0 stevel 2230 0 stevel if (h != out->rd_d.rd_handle) 2231 0 stevel return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH)); 2232 0 stevel 2233 0 stevel (void) pthread_mutex_lock(&h->rh_lock); 2234 0 stevel if (strcmp(name, SCF_SCOPE_LOCAL) == 0) { 2235 0 stevel ret = handle_get_local_scope_locked(h, out); 2236 0 stevel } else { 2237 0 stevel datael_reset_locked(&out->rd_d); 2238 0 stevel if (uu_check_name(name, 0) == -1) 2239 0 stevel ret = scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 2240 0 stevel else 2241 0 stevel ret = scf_set_error(SCF_ERROR_NOT_FOUND); 2242 0 stevel } 2243 0 stevel (void) pthread_mutex_unlock(&h->rh_lock); 2244 0 stevel return (ret); 2245 0 stevel } 2246 0 stevel 2247 0 stevel static int 2248 0 stevel datael_setup_iter(scf_iter_t *iter, const scf_datael_t *dp, uint32_t res_type, 2249 0 stevel boolean_t composed) 2250 0 stevel { 2251 0 stevel scf_handle_t *h = dp->rd_handle; 2252 0 stevel 2253 0 stevel struct rep_protocol_iter_start request; 2254 0 stevel struct rep_protocol_response response; 2255 0 stevel 2256 0 stevel ssize_t r; 2257 0 stevel 2258 0 stevel if (h != iter->iter_handle) 2259 0 stevel return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH)); 2260 0 stevel 2261 0 stevel (void) pthread_mutex_lock(&h->rh_lock); 2262 0 stevel scf_iter_reset_locked(iter); 2263 0 stevel iter->iter_type = res_type; 2264 0 stevel 2265 0 stevel request.rpr_request = REP_PROTOCOL_ITER_START; 2266 0 stevel request.rpr_iterid = iter->iter_id; 2267 0 stevel request.rpr_entity = dp->rd_entity; 2268 0 stevel request.rpr_itertype = res_type; 2269 0 stevel request.rpr_flags = RP_ITER_START_ALL | 2270 0 stevel (composed ? RP_ITER_START_COMPOSED : 0); 2271 0 stevel request.rpr_pattern[0] = 0; 2272 0 stevel 2273 0 stevel datael_finish_reset(dp); 2274 0 stevel r = make_door_call(h, &request, sizeof (request), 2275 0 stevel &response, sizeof (response)); 2276 0 stevel 2277 0 stevel if (r < 0) { 2278 0 stevel (void) pthread_mutex_unlock(&h->rh_lock); 2279 0 stevel DOOR_ERRORS_BLOCK(r); 2280 0 stevel } 2281 0 stevel if (response.rpr_response != REP_PROTOCOL_SUCCESS) { 2282 0 stevel (void) pthread_mutex_unlock(&h->rh_lock); 2283 0 stevel return (scf_set_error(proto_error(response.rpr_response))); 2284 0 stevel } 2285 0 stevel iter->iter_sequence++; 2286 0 stevel (void) pthread_mutex_unlock(&h->rh_lock); 2287 0 stevel return (SCF_SUCCESS); 2288 0 stevel } 2289 0 stevel 2290 0 stevel static int 2291 0 stevel datael_setup_iter_pgtyped(scf_iter_t *iter, const scf_datael_t *dp, 2292 0 stevel const char *pgtype, boolean_t composed) 2293 0 stevel { 2294 0 stevel scf_handle_t *h = dp->rd_handle; 2295 0 stevel 2296 0 stevel struct rep_protocol_iter_start request; 2297 0 stevel struct rep_protocol_response response; 2298 0 stevel 2299 0 stevel ssize_t r; 2300 0 stevel 2301 0 stevel if (h != iter->iter_handle) 2302 0 stevel return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH)); 2303 0 stevel 2304 0 stevel if (pgtype == NULL || strlcpy(request.rpr_pattern, pgtype, 2305 0 stevel sizeof (request.rpr_pattern)) >= sizeof (request.rpr_pattern)) { 2306 0 stevel scf_iter_reset(iter); 2307 0 stevel return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 2308 0 stevel } 2309 0 stevel 2310 0 stevel (void) pthread_mutex_lock(&h->rh_lock); 2311 0 stevel request.rpr_request = REP_PROTOCOL_ITER_START; 2312 0 stevel request.rpr_iterid = iter->iter_id; 2313 0 stevel request.rpr_entity = dp->rd_entity; 2314 0 stevel request.rpr_itertype = REP_PROTOCOL_ENTITY_PROPERTYGRP; 2315 0 stevel request.rpr_flags = RP_ITER_START_PGTYPE | 2316 0 stevel (composed ? RP_ITER_START_COMPOSED : 0); 2317 0 stevel 2318 0 stevel datael_finish_reset(dp); 2319 0 stevel scf_iter_reset_locked(iter); 2320 0 stevel iter->iter_type = REP_PROTOCOL_ENTITY_PROPERTYGRP; 2321 0 stevel 2322 0 stevel r = make_door_call(h, &request, sizeof (request), 2323 0 stevel &response, sizeof (response)); 2324 0 stevel 2325 0 stevel if (r < 0) { 2326 0 stevel (void) pthread_mutex_unlock(&h->rh_lock); 2327 0 stevel 2328 0 stevel DOOR_ERRORS_BLOCK(r); 2329 0 stevel } 2330 0 stevel if (response.rpr_response != REP_PROTOCOL_SUCCESS) { 2331 0 stevel (void) pthread_mutex_unlock(&h->rh_lock); 2332 0 stevel return (scf_set_error(proto_error(response.rpr_response))); 2333 0 stevel } 2334 0 stevel iter->iter_sequence++; 2335 0 stevel (void) pthread_mutex_unlock(&h->rh_lock); 2336 0 stevel return (SCF_SUCCESS); 2337 0 stevel } 2338 0 stevel 2339 0 stevel static int 2340 0 stevel datael_iter_next(scf_iter_t *iter, scf_datael_t *out) 2341 0 stevel { 2342 0 stevel scf_handle_t *h = iter->iter_handle; 2343 0 stevel 2344 0 stevel struct rep_protocol_iter_read request; 2345 0 stevel struct rep_protocol_response response; 2346 0 stevel ssize_t r; 2347 0 stevel 2348 0 stevel if (h != out->rd_handle) 2349 0 stevel return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH)); 2350 0 stevel 2351 0 stevel (void) pthread_mutex_lock(&h->rh_lock); 2352 0 stevel if (iter->iter_type == REP_PROTOCOL_ENTITY_NONE || 2353 0 stevel iter->iter_sequence == 1) { 2354 0 stevel (void) pthread_mutex_unlock(&h->rh_lock); 2355 0 stevel return (scf_set_error(SCF_ERROR_NOT_SET)); 2356 0 stevel } 2357 0 stevel 2358 0 stevel if (out->rd_type != iter->iter_type) { 2359 0 stevel (void) pthread_mutex_unlock(&h->rh_lock); 2360 0 stevel return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 2361 0 stevel } 2362 0 stevel 2363 0 stevel request.rpr_request = REP_PROTOCOL_ITER_READ; 2364 0 stevel request.rpr_iterid = iter->iter_id; 2365 0 stevel request.rpr_sequence = iter->iter_sequence; 2366 0 stevel request.rpr_entityid = out->rd_entity; 2367 0 stevel 2368 0 stevel datael_finish_reset(out); 2369 0 stevel r = make_door_call(h, &request, sizeof (request), 2370 0 stevel &response, sizeof (response)); 2371 0 stevel 2372 0 stevel if (r < 0) { 2373 0 stevel (void) pthread_mutex_unlock(&h->rh_lock); 2374 0 stevel DOOR_ERRORS_BLOCK(r); 2375 0 stevel } 2376 0 stevel 2377 0 stevel if (response.rpr_response == REP_PROTOCOL_DONE) { 2378 0 stevel (void) pthread_mutex_unlock(&h->rh_lock); 2379 0 stevel return (0); 2380 0 stevel } 2381 0 stevel if (response.rpr_response != REP_PROTOCOL_SUCCESS) { 2382 0 stevel (void) pthread_mutex_unlock(&h->rh_lock); 2383 0 stevel return (scf_set_error(proto_error(response.rpr_response))); 2384 0 stevel } 2385 0 stevel iter->iter_sequence++; 2386 0 stevel (void) pthread_mutex_unlock(&h->rh_lock); 2387 0 stevel 2388 0 stevel return (1); 2389 0 stevel } 2390 0 stevel 2391 0 stevel int 2392 0 stevel scf_iter_scope_services(scf_iter_t *iter, const scf_scope_t *s) 2393 0 stevel { 2394 0 stevel return (datael_setup_iter(iter, &s->rd_d, 2395 0 stevel REP_PROTOCOL_ENTITY_SERVICE, 0)); 2396 0 stevel } 2397 0 stevel 2398 0 stevel int 2399 0 stevel scf_iter_next_service(scf_iter_t *iter, scf_service_t *out) 2400 0 stevel { 2401 0 stevel return (datael_iter_next(iter, &out->rd_d)); 2402 0 stevel } 2403 0 stevel 2404 0 stevel int 2405 0 stevel scf_iter_service_instances(scf_iter_t *iter, const scf_service_t *svc) 2406 0 stevel { 2407 0 stevel return (datael_setup_iter(iter, &svc->rd_d, 2408 0 stevel REP_PROTOCOL_ENTITY_INSTANCE, 0)); 2409 0 stevel } 2410 0 stevel 2411 0 stevel int 2412 0 stevel scf_iter_next_instance(scf_iter_t *iter, scf_instance_t *out) 2413 0 stevel { 2414 0 stevel return (datael_iter_next(iter, &out->rd_d)); 2415 0 stevel } 2416 0 stevel 2417 0 stevel int 2418 0 stevel scf_iter_service_pgs(scf_iter_t *iter, const scf_service_t *svc) 2419 0 stevel { 2420 0 stevel return (datael_setup_iter(iter, &svc->rd_d, 2421 0 stevel REP_PROTOCOL_ENTITY_PROPERTYGRP, 0)); 2422 0 stevel } 2423 0 stevel 2424 0 stevel int 2425 0 stevel scf_iter_service_pgs_typed(scf_iter_t *iter, const scf_service_t *svc, 2426 0 stevel const char *type) 2427 0 stevel { 2428 0 stevel return (datael_setup_iter_pgtyped(iter, &svc->rd_d, type, 0)); 2429 0 stevel } 2430 0 stevel 2431 0 stevel int 2432 0 stevel scf_iter_instance_snapshots(scf_iter_t *iter, const scf_instance_t *inst) 2433 0 stevel { 2434 0 stevel return (datael_setup_iter(iter, &inst->rd_d, 2435 0 stevel REP_PROTOCOL_ENTITY_SNAPSHOT, 0)); 2436 0 stevel } 2437 0 stevel 2438 0 stevel int 2439 0 stevel scf_iter_next_snapshot(scf_iter_t *iter, scf_snapshot_t *out) 2440 0 stevel { 2441 0 stevel return (datael_iter_next(iter, &out->rd_d)); 2442 0 stevel } 2443 0 stevel 2444 0 stevel int 2445 0 stevel scf_iter_instance_pgs(scf_iter_t *iter, const scf_instance_t *inst) 2446 0 stevel { 2447 0 stevel return (datael_setup_iter(iter, &inst->rd_d, 2448 0 stevel REP_PROTOCOL_ENTITY_PROPERTYGRP, 0)); 2449 0 stevel } 2450 0 stevel 2451 0 stevel int 2452 0 stevel scf_iter_instance_pgs_typed(scf_iter_t *iter, const scf_instance_t *inst, 2453 0 stevel const char *type) 2454 0 stevel { 2455 0 stevel return (datael_setup_iter_pgtyped(iter, &inst->rd_d, type, 0)); 2456 0 stevel } 2457 0 stevel 2458 0 stevel int 2459 0 stevel scf_iter_instance_pgs_composed(scf_iter_t *iter, const scf_instance_t *inst, 2460 0 stevel const scf_snapshot_t *snap) 2461 0 stevel { 2462 0 stevel if (snap != NULL && inst->rd_d.rd_handle != snap->rd_d.rd_handle) 2463 0 stevel return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH)); 2464 0 stevel 2465 0 stevel return (datael_setup_iter(iter, snap ? &snap->rd_d : &inst->rd_d, 2466 0 stevel REP_PROTOCOL_ENTITY_PROPERTYGRP, 1)); 2467 0 stevel } 2468 0 stevel 2469 0 stevel int 2470 0 stevel scf_iter_instance_pgs_typed_composed(scf_iter_t *iter, 2471 0 stevel const scf_instance_t *inst, const scf_snapshot_t *snap, const char *type) 2472 0 stevel { 2473 0 stevel if (snap != NULL && inst->rd_d.rd_handle != snap->rd_d.rd_handle) 2474 0 stevel return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH)); 2475 0 stevel 2476 0 stevel return (datael_setup_iter_pgtyped(iter, 2477 0 stevel snap ? &snap->rd_d : &inst->rd_d, type, 1)); 2478 0 stevel } 2479 0 stevel 2480 0 stevel int 2481 0 stevel scf_iter_snaplevel_pgs(scf_iter_t *iter, const scf_snaplevel_t *inst) 2482 0 stevel { 2483 0 stevel return (datael_setup_iter(iter, &inst->rd_d, 2484 0 stevel REP_PROTOCOL_ENTITY_PROPERTYGRP, 0)); 2485 0 stevel } 2486 0 stevel 2487 0 stevel int 2488 0 stevel scf_iter_snaplevel_pgs_typed(scf_iter_t *iter, const scf_snaplevel_t *inst, 2489 0 stevel const char *type) 2490 0 stevel { 2491 0 stevel return (datael_setup_iter_pgtyped(iter, &inst->rd_d, type, 0)); 2492 0 stevel } 2493 0 stevel 2494 0 stevel int 2495 0 stevel scf_iter_next_pg(scf_iter_t *iter, scf_propertygroup_t *out) 2496 0 stevel { 2497 0 stevel return (datael_iter_next(iter, &out->rd_d)); 2498 0 stevel } 2499 0 stevel 2500 0 stevel int 2501 0 stevel scf_iter_pg_properties(scf_iter_t *iter, const scf_propertygroup_t *pg) 2502 0 stevel { 2503 0 stevel return (datael_setup_iter(iter, &pg->rd_d, 2504 0 stevel REP_PROTOCOL_ENTITY_PROPERTY, 0)); 2505 0 stevel } 2506 0 stevel 2507 0 stevel int 2508 0 stevel scf_iter_next_property(scf_iter_t *iter, scf_property_t *out) 2509 0 stevel { 2510 0 stevel return (datael_iter_next(iter, &out->rd_d)); 2511 0 stevel } 2512 0 stevel 2513 0 stevel /* 2514 0 stevel * Fails with 2515 0 stevel * _INVALID_ARGUMENT - handle is NULL 2516 0 stevel * _INTERNAL - server response too big 2517 0 stevel * entity already set up with different type 2518 0 stevel * _NO_RESOURCES 2519 0 stevel * _NO_MEMORY 2520 0 stevel */ 2521 0 stevel scf_scope_t * 2522 0 stevel scf_scope_create(scf_handle_t *handle) 2523 0 stevel { 2524 0 stevel scf_scope_t *ret; 2525 0 stevel 2526 0 stevel ret = uu_zalloc(sizeof (*ret)); 2527 0 stevel if (ret != NULL) { 2528 0 stevel if (datael_init(&ret->rd_d, handle, 2529 0 stevel REP_PROTOCOL_ENTITY_SCOPE) == -1) { 2530 0 stevel uu_free(ret); 2531 0 stevel return (NULL); 2532 0 stevel } 2533 0 stevel } else { 2534 0 stevel (void) scf_set_error(SCF_ERROR_NO_MEMORY); 2535 0 stevel } 2536 0 stevel 2537 0 stevel return (ret); 2538 0 stevel } 2539 0 stevel 2540 0 stevel scf_handle_t * 2541 0 stevel scf_scope_handle(const scf_scope_t *val) 2542 0 stevel { 2543 0 stevel return (datael_handle(&val->rd_d)); 2544 0 stevel } 2545 0 stevel 2546 0 stevel void 2547 0 stevel scf_scope_destroy(scf_scope_t *val) 2548 0 stevel { 2549 0 stevel if (val == NULL) 2550 0 stevel return; 2551 0 stevel 2552 0 stevel datael_destroy(&val->rd_d); 2553 0 stevel uu_free(val); 2554 0 stevel } 2555 0 stevel 2556 0 stevel ssize_t 2557 0 stevel scf_scope_get_name(const scf_scope_t *rep, char *out, size_t len) 2558 0 stevel { 2559 0 stevel return (datael_get_name(&rep->rd_d, out, len, RP_ENTITY_NAME_NAME)); 2560 0 stevel } 2561 0 stevel 2562 0 stevel /*ARGSUSED*/ 2563 0 stevel int 2564 0 stevel scf_scope_get_parent(const scf_scope_t *child, scf_scope_t *parent) 2565 0 stevel { 2566 0 stevel char name[1]; 2567 0 stevel 2568 0 stevel /* fake up the side-effects */ 2569 0 stevel datael_reset(&parent->rd_d); 2570 0 stevel if (scf_scope_get_name(child, name, sizeof (name)) < 0) 2571 0 stevel return (-1); 2572 0 stevel return (scf_set_error(SCF_ERROR_NOT_FOUND)); 2573 0 stevel } 2574 0 stevel 2575 0 stevel /* 2576 0 stevel * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL 2577 0 stevel * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY. 2578 0 stevel */ 2579 0 stevel scf_service_t * 2580 0 stevel scf_service_create(scf_handle_t *handle) 2581 0 stevel { 2582 0 stevel scf_service_t *ret; 2583 0 stevel ret = uu_zalloc(sizeof (*ret)); 2584 0 stevel if (ret != NULL) { 2585 0 stevel if (datael_init(&ret->rd_d, handle, 2586 0 stevel REP_PROTOCOL_ENTITY_SERVICE) == -1) { 2587 0 stevel uu_free(ret); 2588 0 stevel return (NULL); 2589 0 stevel } 2590 0 stevel } else { 2591 0 stevel (void) scf_set_error(SCF_ERROR_NO_MEMORY); 2592 0 stevel } 2593 0 stevel 2594 0 stevel return (ret); 2595 0 stevel } 2596 0 stevel 2597 4740 jeanm 2598 4740 jeanm /* 2599 4740 jeanm * Fails with 2600 4740 jeanm * _HANDLE_MISMATCH 2601 4740 jeanm * _INVALID_ARGUMENT 2602 4740 jeanm * _NOT_BOUND 2603 4740 jeanm * _CONNECTION_BROKEN 2604 4740 jeanm * _INTERNAL 2605 4740 jeanm * _EXISTS 2606 4740 jeanm * _DELETED 2607 4740 jeanm * _NOT_SET 2608 4740 jeanm * _NO_RESOURCES 2609 4740 jeanm * _PERMISSION_DENIED 2610 4740 jeanm * _BACKEND_ACCESS 2611 4740 jeanm * _BACKEND_READONLY 2612 4740 jeanm */ 2613 0 stevel int 2614 0 stevel scf_scope_add_service(const scf_scope_t *scope, const char *name, 2615 0 stevel scf_service_t *svc) 2616 0 stevel { 2617 0 stevel return (datael_add_child(&scope->rd_d, name, 2618 0 stevel REP_PROTOCOL_ENTITY_SERVICE, (svc != NULL)? &svc->rd_d : NULL)); 2619 0 stevel } 2620 0 stevel 2621 4740 jeanm /* 2622 4740 jeanm * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND, 2623 4740 jeanm * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES, 2624 4740 jeanm * _BACKEND_ACCESS, _NOT_FOUND. 2625 4740 jeanm */ 2626 0 stevel int 2627 0 stevel scf_scope_get_service(const scf_scope_t *s, const char *name, 2628 0 stevel scf_service_t *svc) 2629 0 stevel { 2630 0 stevel return (datael_get_child(&s->rd_d, name, REP_PROTOCOL_ENTITY_SERVICE, 2631 0 stevel svc ? &svc->rd_d : NULL, 0)); 2632 0 stevel } 2633 0 stevel 2634 0 stevel scf_handle_t * 2635 0 stevel scf_service_handle(const scf_service_t *val) 2636 0 stevel { 2637 0 stevel return (datael_handle(&val->rd_d)); 2638 0 stevel } 2639 0 stevel 2640 0 stevel int 2641 0 stevel scf_service_delete(scf_service_t *svc) 2642 0 stevel { 2643 0 stevel return (datael_delete(&svc->rd_d)); 2644 0 stevel } 2645 0 stevel 2646 0 stevel int 2647 0 stevel scf_instance_delete(scf_instance_t *inst) 2648 0 stevel { 2649 0 stevel return (datael_delete(&inst->rd_d)); 2650 0 stevel } 2651 0 stevel 2652 0 stevel int 2653 0 stevel scf_pg_delete(scf_propertygroup_t *pg) 2654 0 stevel { 2655 0 stevel return (datael_delete(&pg->rd_d)); 2656 0 stevel } 2657 0 stevel 2658 0 stevel int 2659 0 stevel _scf_snapshot_delete(scf_snapshot_t *snap) 2660 0 stevel { 2661 0 stevel return (datael_delete(&snap->rd_d)); 2662 0 stevel } 2663 0 stevel 2664 4740 jeanm /* 2665 4740 jeanm * Fails with 2666 4740 jeanm * _HANDLE_MISMATCH 2667 4740 jeanm * _INVALID_ARGUMENT 2668 4740 jeanm * _NOT_BOUND 2669 4740 jeanm * _CONNECTION_BROKEN 2670 4740 jeanm * _INTERNAL 2671 4740 jeanm * _EXISTS 2672 4740 jeanm * _DELETED 2673 4740 jeanm * _NOT_SET 2674 4740 jeanm * _NO_RESOURCES 2675 4740 jeanm * _PERMISSION_DENIED 2676 4740 jeanm * _BACKEND_ACCESS 2677 4740 jeanm * _BACKEND_READONLY 2678 4740 jeanm */ 2679 0 stevel int 2680 0 stevel scf_service_add_instance(const scf_service_t *svc, const char *name, 2681 0 stevel scf_instance_t *instance) 2682 0 stevel { 2683 0 stevel return (datael_add_child(&svc->rd_d, name, 2684 0 stevel REP_PROTOCOL_ENTITY_INSTANCE, 2685 0 stevel (instance != NULL)? &instance->rd_d : NULL)); 2686 0 stevel } 2687 0 stevel 2688 4740 jeanm 2689 4740 jeanm /* 2690 4740 jeanm * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND, 2691 4740 jeanm * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES, 2692 4740 jeanm * _BACKEND_ACCESS, _NOT_FOUND. 2693 4740 jeanm */ 2694 0 stevel int 2695 0 stevel scf_service_get_instance(const scf_service_t *svc, const char *name, 2696 0 stevel scf_instance_t *inst) 2697 0 stevel { 2698 0 stevel return (datael_get_child(&svc->rd_d, name, REP_PROTOCOL_ENTITY_INSTANCE, 2699 0 stevel inst ? &inst->rd_d : NULL, 0)); 2700 0 stevel } 2701 0 stevel 2702 0 stevel int 2703 0 stevel scf_service_add_pg(const scf_service_t *svc, const char *name, 2704 0 stevel const char *type, uint32_t flags, scf_propertygroup_t *pg) 2705 0 stevel { 2706 0 stevel return (datael_add_pg(&svc->rd_d, name, type, flags, 2707 0 stevel (pg != NULL)?&pg->rd_d : NULL)); 2708 0 stevel } 2709 0 stevel 2710 4740 jeanm /* 2711 4740 jeanm * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND, 2712 4740 jeanm * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES, 2713 4740 jeanm * _BACKEND_ACCESS, _NOT_FOUND. 2714 4740 jeanm */ 2715 0 stevel int 2716 0 stevel scf_service_get_pg(const scf_service_t *svc, const char *name, 2717 0 stevel scf_propertygroup_t *pg) 2718 0 stevel { 2719 0 stevel return (datael_get_child(&svc->rd_d, name, 2720 0 stevel REP_PROTOCOL_ENTITY_PROPERTYGRP, pg ? &pg->rd_d : NULL, 0)); 2721 0 stevel } 2722 0 stevel 2723 0 stevel int 2724 0 stevel scf_instance_add_pg(const scf_instance_t *inst, const char *name, 2725 0 stevel const char *type, uint32_t flags, scf_propertygroup_t *pg) 2726 0 stevel { 2727 0 stevel return (datael_add_pg(&inst->rd_d, name, type, flags, 2728 0 stevel (pg != NULL)?&pg->rd_d : NULL)); 2729 0 stevel } 2730 0 stevel 2731 4740 jeanm /* 2732 4740 jeanm * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND, 2733 4740 jeanm * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES, 2734 4740 jeanm * _BACKEND_ACCESS, _NOT_FOUND. 2735 4740 jeanm */ 2736 0 stevel int 2737 0 stevel scf_instance_get_snapshot(const scf_instance_t *inst, const char *name, 2738 0 stevel scf_snapshot_t *pg) 2739 0 stevel { 2740 0 stevel return (datael_get_child(&inst->rd_d, name, 2741 0 stevel REP_PROTOCOL_ENTITY_SNAPSHOT, pg ? &pg->rd_d : NULL, 0)); 2742 0 stevel } 2743 0 stevel 2744 4740 jeanm /* 2745 4740 jeanm * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND, 2746 4740 jeanm * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES, 2747 4740 jeanm * _BACKEND_ACCESS, _NOT_FOUND. 2748 4740 jeanm */ 2749 0 stevel int 2750 0 stevel scf_instance_get_pg(const scf_instance_t *inst, const char *name, 2751 0 stevel scf_propertygroup_t *pg) 2752 0 stevel { 2753 0 stevel return (datael_get_child(&inst->rd_d, name, 2754 0 stevel REP_PROTOCOL_ENTITY_PROPERTYGRP, pg ? &pg->rd_d : NULL, 0)); 2755 0 stevel } 2756 0 stevel 2757 4740 jeanm /* 2758 4740 jeanm * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND, 2759 4740 jeanm * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES, 2760 4740 jeanm * _BACKEND_ACCESS, _NOT_FOUND. 2761 4740 jeanm */ 2762 0 stevel int 2763 0 stevel scf_instance_get_pg_composed(const scf_instance_t *inst, 2764 0 stevel const scf_snapshot_t *snap, const char *name, scf_propertygroup_t *pg) 2765 0 stevel { 2766 0 stevel if (snap != NULL && inst->rd_d.rd_handle != snap->rd_d.rd_handle) 2767 0 stevel return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH)); 2768 0 stevel 2769 0 stevel return (datael_get_child(snap ? &snap->rd_d : &inst->rd_d, name, 2770 0 stevel REP_PROTOCOL_ENTITY_PROPERTYGRP, pg ? &pg->rd_d : NULL, 1)); 2771 0 stevel } 2772 0 stevel 2773 4740 jeanm /* 2774 4740 jeanm * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND, 2775 4740 jeanm * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES, 2776 4740 jeanm * _BACKEND_ACCESS, _NOT_FOUND. 2777 4740 jeanm */ 2778 0 stevel int 2779 0 stevel scf_pg_get_property(const scf_propertygroup_t *pg, const char *name, 2780 0 stevel scf_property_t *prop) 2781 0 stevel { 2782 0 stevel return (datael_get_child(&pg->rd_d, name, REP_PROTOCOL_ENTITY_PROPERTY, 2783 0 stevel prop ? &prop->rd_d : NULL, 0)); 2784 0 stevel } 2785 0 stevel 2786 0 stevel void 2787 0 stevel scf_service_destroy(scf_service_t *val) 2788 0 stevel { 2789 0 stevel if (val == NULL) 2790 0 stevel return; 2791 0 stevel 2792 0 stevel datael_destroy(&val->rd_d); 2793 0 stevel uu_free(val); 2794 0 stevel } 2795 0 stevel 2796 0 stevel ssize_t 2797 0 stevel scf_service_get_name(const scf_service_t *rep, char *out, size_t len) 2798 0 stevel { 2799 0 stevel return (datael_get_name(&rep->rd_d, out, len, RP_ENTITY_NAME_NAME)); 2800 0 stevel } 2801 0 stevel 2802 0 stevel /* 2803 0 stevel * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL 2804 0 stevel * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY. 2805 0 stevel */ 2806 0 stevel scf_instance_t * 2807 0 stevel scf_instance_create(scf_handle_t *handle) 2808 0 stevel { 2809 0 stevel scf_instance_t *ret; 2810 0 stevel 2811 0 stevel ret = uu_zalloc(sizeof (*ret)); 2812 0 stevel if (ret != NULL) { 2813 0 stevel if (datael_init(&ret->rd_d, handle, 2814 0 stevel REP_PROTOCOL_ENTITY_INSTANCE) == -1) { 2815 0 stevel uu_free(ret); 2816 0 stevel return (NULL); 2817 0 stevel } 2818 0 stevel } else { 2819 0 stevel (void) scf_set_error(SCF_ERROR_NO_MEMORY); 2820 0 stevel } 2821 0 stevel 2822 0 stevel return (ret); 2823 0 stevel } 2824 0 stevel 2825 0 stevel scf_handle_t * 2826 0 stevel scf_instance_handle(const scf_instance_t *val) 2827 0 stevel { 2828 0 stevel return (datael_handle(&val->rd_d)); 2829 0 stevel } 2830 0 stevel 2831 0 stevel void 2832 0 stevel scf_instance_destroy(scf_instance_t *val) 2833 0 stevel { 2834 0 stevel if (val == NULL) 2835 0 stevel return; 2836 0 stevel 2837 0 stevel datael_destroy(&val->rd_d); 2838 0 stevel uu_free(val); 2839 0 stevel } 2840 0 stevel 2841 0 stevel ssize_t 2842 0 stevel scf_instance_get_name(const scf_instance_t *rep, char *out, size_t len) 2843 0 stevel { 2844 0 stevel return (datael_get_name(&rep->rd_d, out, len, RP_ENTITY_NAME_NAME)); 2845 0 stevel } 2846 0 stevel 2847 0 stevel /* 2848 0 stevel * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL 2849 0 stevel * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY. 2850 0 stevel */ 2851 0 stevel scf_snapshot_t * 2852 0 stevel scf_snapshot_create(scf_handle_t *handle) 2853 0 stevel { 2854 0 stevel scf_snapshot_t *ret; 2855 0 stevel 2856 0 stevel ret = uu_zalloc(sizeof (*ret)); 2857 0 stevel if (ret != NULL) { 2858 0 stevel if (datael_init(&ret->rd_d, handle, 2859 0 stevel REP_PROTOCOL_ENTITY_SNAPSHOT) == -1) { 2860 0 stevel uu_free(ret); 2861 0 stevel return (NULL); 2862 0 stevel } 2863 0 stevel } else { 2864 0 stevel (void) scf_set_error(SCF_ERROR_NO_MEMORY); 2865 0 stevel } 2866 0 stevel 2867 0 stevel return (ret); 2868 0 stevel } 2869 0 stevel 2870 0 stevel scf_handle_t * 2871 0 stevel scf_snapshot_handle(const scf_snapshot_t *val) 2872 0 stevel { 2873 0 stevel return (datael_handle(&val->rd_d)); 2874 0 stevel } 2875 0 stevel 2876 0 stevel void 2877 0 stevel scf_snapshot_destroy(scf_snapshot_t *val) 2878 0 stevel { 2879 0 stevel if (val == NULL) 2880 0 stevel return; 2881 0 stevel 2882 0 stevel datael_destroy(&val->rd_d); 2883 0 stevel uu_free(val); 2884 0 stevel } 2885 0 stevel 2886 0 stevel ssize_t 2887 0 stevel scf_snapshot_get_name(const scf_snapshot_t *rep, char *out, size_t len) 2888 0 stevel { 2889 0 stevel return (datael_get_name(&rep->rd_d, out, len, RP_ENTITY_NAME_NAME)); 2890 0 stevel } 2891 0 stevel 2892 0 stevel /* 2893 0 stevel * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL 2894 0 stevel * (bad server response or id in use), _NO_RESOURCES, _NO_MEMORY. 2895 0 stevel */ 2896 0 stevel scf_snaplevel_t * 2897 0 stevel scf_snaplevel_create(scf_handle_t *handle) 2898 0 stevel { 2899 0 stevel scf_snaplevel_t *ret; 2900 0 stevel 2901 0 stevel ret = uu_zalloc(sizeof (*ret)); 2902 0 stevel if (ret != NULL) { 2903 0 stevel if (datael_init(&ret->rd_d, handle, 2904 0 stevel REP_PROTOCOL_ENTITY_SNAPLEVEL) == -1) { 2905 0 stevel uu_free(ret); 2906 0 stevel return (NULL); 2907 0 stevel } 2908 0 stevel } else { 2909 0 stevel (void) scf_set_error(SCF_ERROR_NO_MEMORY); 2910 0 stevel } 2911 0 stevel 2912 0 stevel return (ret); 2913 0 stevel } 2914 0 stevel 2915 0 stevel scf_handle_t * 2916 0 stevel scf_snaplevel_handle(const scf_snaplevel_t *val) 2917 0 stevel { 2918 0 stevel return (datael_handle(&val->rd_d)); 2919 0 stevel } 2920 0 stevel 2921 0 stevel void 2922 0 stevel scf_snaplevel_destroy(scf_snaplevel_t *val) 2923 0 stevel { 2924 0 stevel if (val == NULL) 2925 0 stevel return; 2926 0 stevel 2927 0 stevel datael_destroy(&val->rd_d); 2928 0 stevel uu_free(val); 2929 0 stevel } 2930 0 stevel 2931 0 stevel ssize_t 2932 0 stevel scf_snaplevel_get_scope_name(const scf_snaplevel_t *rep, char *out, size_t len) 2933 0 stevel { 2934 0 stevel return (datael_get_name(&rep->rd_d, out, len, 2935 0 stevel RP_ENTITY_NAME_SNAPLEVEL_SCOPE)); 2936 0 stevel } 2937 0 stevel 2938 0 stevel ssize_t 2939 0 stevel scf_snaplevel_get_service_name(const scf_snaplevel_t *rep, char *out, 2940 0 stevel size_t len) 2941 0 stevel { 2942 0 stevel return (datael_get_name(&rep->rd_d, out, len, 2943 0 stevel RP_ENTITY_NAME_SNAPLEVEL_SERVICE)); 2944 0 stevel } 2945 0 stevel 2946 0 stevel ssize_t 2947 0 stevel scf_snaplevel_get_instance_name(const scf_snaplevel_t *rep, char *out, 2948 0 stevel size_t len) 2949 0 stevel { 2950 0 stevel return (datael_get_name(&rep->rd_d, out, len, 2951 0 stevel RP_ENTITY_NAME_SNAPLEVEL_INSTANCE)); 2952 0 stevel } 2953 0 stevel 2954 4740 jeanm /* 2955 4740 jeanm * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND, 2956 4740 jeanm * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES, 2957 4740 jeanm * _BACKEND_ACCESS, _NOT_FOUND. 2958 4740 jeanm */ 2959 0 stevel int 2960 0 stevel scf_snaplevel_get_pg(const scf_snaplevel_t *snap, const char *name, 2961 0 stevel scf_propertygroup_t *pg) 2962 0 stevel { 2963 0 stevel return (datael_get_child(&snap->rd_d, name, 2964 0 stevel REP_PROTOCOL_ENTITY_PROPERTYGRP, pg ? &pg->rd_d : NULL, 0)); 2965 0 stevel } 2966 0 stevel 2967 0 stevel static int 2968 0 stevel snaplevel_next(const scf_datael_t *src, scf_snaplevel_t *dst_arg) 2969 0 stevel { 2970 0 stevel scf_handle_t *h = src->rd_handle; 2971 0 stevel scf_snaplevel_t *dst = dst_arg; 2972 0 stevel struct rep_protocol_entity_pair request; 2973 0 stevel struct rep_protocol_response response; 2974 0 stevel int r; 2975 0 stevel int dups = 0; 2976 0 stevel 2977 0 stevel if (h != dst->rd_d.rd_handle) 2978 0 stevel return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH)); 2979 0 stevel 2980 0 stevel if (src == &dst->rd_d) { 2981 0 stevel dups = 1; 2982 0 stevel dst = HANDLE_HOLD_SNAPLVL(h); 2983 0 stevel } 2984 0 stevel (void) pthread_mutex_lock(&h->rh_lock); 2985 0 stevel request.rpr_request = REP_PROTOCOL_NEXT_SNAPLEVEL; 2986 0 stevel request.rpr_entity_src = src->rd_entity; 2987 0 stevel request.rpr_entity_dst = dst->rd_d.rd_entity; 2988 0 stevel 2989 0 stevel datael_finish_reset(src); 2990 0 stevel datael_finish_reset(&dst->rd_d); 2991 0 stevel r = make_door_call(h, &request, sizeof (request), 2992 0 stevel &response, sizeof (response)); 2993 0 stevel /* 2994 0 stevel * if we succeeded, we need to swap dst and dst_arg's identity. We 2995 0 stevel * take advantage of the fact that the only in-library knowledge is 2996 0 stevel * their entity ids. 2997 0 stevel */ 2998 0 stevel if (dups && r >= 0 && 2999 0 stevel (response.rpr_response == REP_PROTOCOL_SUCCESS || 3000 0 stevel response.rpr_response == REP_PROTOCOL_DONE)) { 3001 0 stevel int entity = dst->rd_d.rd_entity; 3002 0 stevel 3003 0 stevel dst->rd_d.rd_entity = dst_arg->rd_d.rd_entity; 3004 0 stevel dst_arg->rd_d.rd_entity = entity; 3005 0 stevel } 3006 0 stevel (void) pthread_mutex_unlock(&h->rh_lock); 3007 0 stevel 3008 0 stevel if (dups) 3009 0 stevel HANDLE_RELE_SNAPLVL(h); 3010 0 stevel 3011 0 stevel if (r < 0) 3012 0 stevel DOOR_ERRORS_BLOCK(r); 3013 0 stevel 3014 0 stevel if (response.rpr_response != REP_PROTOCOL_SUCCESS && 3015 0 stevel response.rpr_response != REP_PROTOCOL_DONE) { 3016 0 stevel return (scf_set_error(proto_error(response.rpr_response))); 3017 0 stevel } 3018 0 stevel 3019 0 stevel return (response.rpr_response == REP_PROTOCOL_SUCCESS) ? 3020 0 stevel SCF_SUCCESS : SCF_COMPLETE; 3021 0 stevel } 3022 0 stevel 3023 0 stevel int scf_snapshot_get_base_snaplevel(const scf_snapshot_t *base, 3024 0 stevel scf_snaplevel_t *out) 3025 0 stevel { 3026 0 stevel return (snaplevel_next(&base->rd_d, out)); 3027 0 stevel } 3028 0 stevel 3029 0 stevel int scf_snaplevel_get_next_snaplevel(const scf_snaplevel_t *base, 3030 0 stevel scf_snaplevel_t *out) 3031 0 stevel { 3032 0 stevel return (snaplevel_next(&base->rd_d, out)); 3033 0 stevel } 3034 0 stevel 3035 0 stevel /* 3036 0 stevel * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL 3037 0 stevel * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY. 3038 0 stevel */ 3039 0 stevel scf_propertygroup_t * 3040 0 stevel scf_pg_create(scf_handle_t *handle) 3041 0 stevel { 3042 0 stevel scf_propertygroup_t *ret; 3043 0 stevel ret = uu_zalloc(sizeof (*ret)); 3044 0 stevel if (ret != NULL) { 3045 0 stevel if (datael_init(&ret->rd_d, handle, 3046 0 stevel REP_PROTOCOL_ENTITY_PROPERTYGRP) == -1) { 3047 0 stevel uu_free(ret); 3048 0 stevel return (NULL); 3049 0 stevel } 3050 0 stevel } else { 3051 0 stevel (void) scf_set_error(SCF_ERROR_NO_MEMORY); 3052 0 stevel } 3053 0 stevel 3054 0 stevel return (ret); 3055 0 stevel } 3056 0 stevel 3057 0 stevel scf_handle_t * 3058 0 stevel scf_pg_handle(const scf_propertygroup_t *val) 3059 0 stevel { 3060 0 stevel return (datael_handle(&val->rd_d)); 3061 0 stevel } 3062 0 stevel 3063 0 stevel void 3064 0 stevel scf_pg_destroy(scf_propertygroup_t *val) 3065 0 stevel { 3066 0 stevel if (val == NULL) 3067 0 stevel return; 3068 0 stevel 3069 0 stevel datael_destroy(&val->rd_d); 3070 0 stevel uu_free(val); 3071 0 stevel } 3072 0 stevel 3073 0 stevel ssize_t 3074 0 stevel scf_pg_get_name(const scf_propertygroup_t *pg, char *out, size_t len) 3075 0 stevel { 3076 0 stevel return (datael_get_name(&pg->rd_d, out, len, RP_ENTITY_NAME_NAME)); 3077 0 stevel } 3078 0 stevel 3079 0 stevel ssize_t 3080 0 stevel scf_pg_get_type(const scf_propertygroup_t *pg, char *out, size_t len) 3081 0 stevel { 3082 0 stevel <