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