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