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