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