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