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