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 */ 1827 static int 1828 datael_add_child(const scf_datael_t *dp, const char *name, uint32_t type, 1829 scf_datael_t *cp) 1830 { 1831 scf_handle_t *h = dp->rd_handle; 1832 1833 struct rep_protocol_entity_create_child request; 1834 struct rep_protocol_response response; 1835 ssize_t r; 1836 uint32_t held = 0; 1837 1838 if (cp == NULL) { 1839 switch (type) { 1840 case REP_PROTOCOL_ENTITY_SCOPE: 1841 cp = &HANDLE_HOLD_SCOPE(h)->rd_d; 1842 held = RH_HOLD_SCOPE; 1843 break; 1844 case REP_PROTOCOL_ENTITY_SERVICE: 1845 cp = &HANDLE_HOLD_SERVICE(h)->rd_d; 1846 held = RH_HOLD_SERVICE; 1847 break; 1848 case REP_PROTOCOL_ENTITY_INSTANCE: 1849 cp = &HANDLE_HOLD_INSTANCE(h)->rd_d; 1850 held = RH_HOLD_INSTANCE; 1851 break; 1852 case REP_PROTOCOL_ENTITY_SNAPSHOT: 1853 default: 1854 assert(0); 1855 abort(); 1856 } 1857 assert(h == cp->rd_handle); 1858 1859 } else if (h != cp->rd_handle) { 1860 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH)); 1861 } 1862 1863 if (strlcpy(request.rpr_name, name, sizeof (request.rpr_name)) >= 1864 sizeof (request.rpr_name)) { 1865 r = scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 1866 goto err; 1867 } 1868 1869 (void) pthread_mutex_lock(&h->rh_lock); 1870 request.rpr_request = REP_PROTOCOL_ENTITY_CREATE_CHILD; 1871 request.rpr_entityid = dp->rd_entity; 1872 request.rpr_childtype = type; 1873 request.rpr_childid = cp->rd_entity; 1874 1875 datael_finish_reset(dp); 1876 request.rpr_changeid = handle_next_changeid(h); 1877 r = make_door_call(h, &request, sizeof (request), 1878 &response, sizeof (response)); 1879 (void) pthread_mutex_unlock(&h->rh_lock); 1880 1881 if (held) 1882 handle_rele_subhandles(h, held); 1883 1884 if (r < 0) 1885 DOOR_ERRORS_BLOCK(r); 1886 1887 if (response.rpr_response != REP_PROTOCOL_SUCCESS) 1888 return (scf_set_error(proto_error(response.rpr_response))); 1889 1890 return (SCF_SUCCESS); 1891 1892 err: 1893 if (held) 1894 handle_rele_subhandles(h, held); 1895 return (r); 1896 } 1897 1898 static int 1899 datael_add_pg(const scf_datael_t *dp, const char *name, const char *type, 1900 uint32_t flags, scf_datael_t *cp) 1901 { 1902 scf_handle_t *h = dp->rd_handle; 1903 1904 struct rep_protocol_entity_create_pg request; 1905 struct rep_protocol_response response; 1906 ssize_t r; 1907 1908 int holding_els = 0; 1909 1910 if (cp == NULL) { 1911 holding_els = 1; 1912 cp = &HANDLE_HOLD_PG(h)->rd_d; 1913 assert(h == cp->rd_handle); 1914 1915 } else if (h != cp->rd_handle) { 1916 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH)); 1917 } 1918 1919 request.rpr_request = REP_PROTOCOL_ENTITY_CREATE_PG; 1920 1921 if (name == NULL || strlcpy(request.rpr_name, name, 1922 sizeof (request.rpr_name)) > sizeof (request.rpr_name)) { 1923 r = scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 1924 goto err; 1925 } 1926 1927 if (type == NULL || strlcpy(request.rpr_type, type, 1928 sizeof (request.rpr_type)) > sizeof (request.rpr_type)) { 1929 r = scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 1930 goto err; 1931 } 1932 1933 (void) pthread_mutex_lock(&h->rh_lock); 1934 request.rpr_entityid = dp->rd_entity; 1935 request.rpr_childid = cp->rd_entity; 1936 request.rpr_flags = flags; 1937 1938 datael_finish_reset(dp); 1939 datael_finish_reset(cp); 1940 request.rpr_changeid = handle_next_changeid(h); 1941 r = make_door_call(h, &request, sizeof (request), 1942 &response, sizeof (response)); 1943 (void) pthread_mutex_unlock(&h->rh_lock); 1944 1945 if (holding_els) 1946 HANDLE_RELE_PG(h); 1947 1948 if (r < 0) 1949 DOOR_ERRORS_BLOCK(r); 1950 1951 if (response.rpr_response != REP_PROTOCOL_SUCCESS) 1952 return (scf_set_error(proto_error(response.rpr_response))); 1953 1954 return (SCF_SUCCESS); 1955 1956 err: 1957 if (holding_els) 1958 HANDLE_RELE_PG(h); 1959 return (r); 1960 } 1961 1962 static int 1963 datael_delete(const scf_datael_t *dp) 1964 { 1965 scf_handle_t *h = dp->rd_handle; 1966 1967 struct rep_protocol_entity_delete request; 1968 struct rep_protocol_response response; 1969 ssize_t r; 1970 1971 (void) pthread_mutex_lock(&h->rh_lock); 1972 request.rpr_request = REP_PROTOCOL_ENTITY_DELETE; 1973 request.rpr_entityid = dp->rd_entity; 1974 1975 datael_finish_reset(dp); 1976 request.rpr_changeid = handle_next_changeid(h); 1977 r = make_door_call(h, &request, sizeof (request), 1978 &response, sizeof (response)); 1979 (void) pthread_mutex_unlock(&h->rh_lock); 1980 1981 if (r < 0) 1982 DOOR_ERRORS_BLOCK(r); 1983 1984 if (response.rpr_response != REP_PROTOCOL_SUCCESS) 1985 return (scf_set_error(proto_error(response.rpr_response))); 1986 1987 return (SCF_SUCCESS); 1988 } 1989 1990 /* 1991 * Fails with 1992 * _INVALID_ARGUMENT - h is NULL 1993 * _NO_MEMORY 1994 * _HANDLE_DESTROYED - h has been destroyed 1995 * _INTERNAL - server response too big 1996 * iter already exists 1997 * _NO_RESOURCES 1998 */ 1999 scf_iter_t * 2000 scf_iter_create(scf_handle_t *h) 2001 { 2002 scf_iter_t *iter; 2003 2004 if (h == NULL) { 2005 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 2006 return (NULL); 2007 } 2008 2009 iter = uu_zalloc(sizeof (*iter)); 2010 if (iter == NULL) { 2011 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 2012 return (NULL); 2013 } 2014 2015 uu_list_node_init(iter, &iter->iter_node, iter_pool); 2016 iter->iter_handle = h; 2017 iter->iter_sequence = 1; 2018 iter->iter_type = REP_PROTOCOL_ENTITY_NONE; 2019 2020 (void) pthread_mutex_lock(&h->rh_lock); 2021 iter->iter_id = handle_alloc_iterid(h); 2022 if (iter->iter_id == 0) { 2023 (void) pthread_mutex_unlock(&h->rh_lock); 2024 uu_list_node_fini(iter, &iter->iter_node, iter_pool); 2025 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 2026 return (NULL); 2027 } 2028 if (iter_attach(iter) == -1) { 2029 uu_list_node_fini(iter, &iter->iter_node, iter_pool); 2030 (void) pthread_mutex_unlock(&h->rh_lock); 2031 uu_free(iter); 2032 return (NULL); 2033 } 2034 (void) uu_list_insert_before(h->rh_iters, NULL, iter); 2035 h->rh_extrefs++; 2036 (void) pthread_mutex_unlock(&h->rh_lock); 2037 return (iter); 2038 } 2039 2040 scf_handle_t * 2041 scf_iter_handle(const scf_iter_t *iter) 2042 { 2043 return (handle_get(iter->iter_handle)); 2044 } 2045 2046 static void 2047 scf_iter_reset_locked(scf_iter_t *iter) 2048 { 2049 struct rep_protocol_iter_request request; 2050 struct rep_protocol_response response; 2051 2052 request.rpr_request = REP_PROTOCOL_ITER_RESET; 2053 request.rpr_iterid = iter->iter_id; 2054 2055 assert(MUTEX_HELD(&iter->iter_handle->rh_lock)); 2056 2057 (void) make_door_call(iter->iter_handle, 2058 &request, sizeof (request), &response, sizeof (response)); 2059 2060 iter->iter_type = REP_PROTOCOL_ENTITY_NONE; 2061 iter->iter_sequence = 1; 2062 } 2063 2064 void 2065 scf_iter_reset(scf_iter_t *iter) 2066 { 2067 (void) pthread_mutex_lock(&iter->iter_handle->rh_lock); 2068 scf_iter_reset_locked(iter); 2069 (void) pthread_mutex_unlock(&iter->iter_handle->rh_lock); 2070 } 2071 2072 void 2073 scf_iter_destroy(scf_iter_t *iter) 2074 { 2075 scf_handle_t *handle; 2076 2077 struct rep_protocol_iter_request request; 2078 struct rep_protocol_response response; 2079 2080 if (iter == NULL) 2081 return; 2082 2083 handle = iter->iter_handle; 2084 2085 (void) pthread_mutex_lock(&handle->rh_lock); 2086 request.rpr_request = REP_PROTOCOL_ITER_TEARDOWN; 2087 request.rpr_iterid = iter->iter_id; 2088 2089 (void) make_door_call(handle, &request, sizeof (request), 2090 &response, sizeof (response)); 2091 2092 uu_list_remove(handle->rh_iters, iter); 2093 --handle->rh_extrefs; 2094 handle_unrefed(handle); /* drops h->rh_lock */ 2095 iter->iter_handle = NULL; 2096 2097 uu_list_node_fini(iter, &iter->iter_node, iter_pool); 2098 uu_free(iter); 2099 } 2100 2101 static int 2102 handle_get_local_scope_locked(scf_handle_t *handle, scf_scope_t *out) 2103 { 2104 struct rep_protocol_entity_get request; 2105 struct rep_protocol_name_response response; 2106 ssize_t r; 2107 2108 assert(MUTEX_HELD(&handle->rh_lock)); 2109 2110 if (handle != out->rd_d.rd_handle) 2111 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH)); 2112 2113 request.rpr_request = REP_PROTOCOL_ENTITY_GET; 2114 request.rpr_entityid = out->rd_d.rd_entity; 2115 request.rpr_object = RP_ENTITY_GET_MOST_LOCAL_SCOPE; 2116 2117 datael_finish_reset(&out->rd_d); 2118 r = make_door_call(handle, &request, sizeof (request), 2119 &response, sizeof (response)); 2120 2121 if (r < 0) 2122 DOOR_ERRORS_BLOCK(r); 2123 2124 if (response.rpr_response != REP_PROTOCOL_SUCCESS) 2125 return (scf_set_error(proto_error(response.rpr_response))); 2126 2127 return (SCF_SUCCESS); 2128 } 2129 2130 int 2131 scf_iter_handle_scopes(scf_iter_t *iter, const scf_handle_t *handle) 2132 { 2133 scf_handle_t *h = iter->iter_handle; 2134 if (h != handle) 2135 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH)); 2136 2137 (void) pthread_mutex_lock(&h->rh_lock); 2138 scf_iter_reset_locked(iter); 2139 2140 if (!handle_is_bound(h)) { 2141 (void) pthread_mutex_unlock(&h->rh_lock); 2142 return (scf_set_error(SCF_ERROR_NOT_BOUND)); 2143 } 2144 2145 if (!handle_has_server_locked(h)) { 2146 (void) pthread_mutex_unlock(&h->rh_lock); 2147 return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN)); 2148 } 2149 2150 iter->iter_type = REP_PROTOCOL_ENTITY_SCOPE; 2151 iter->iter_sequence = 1; 2152 (void) pthread_mutex_unlock(&h->rh_lock); 2153 return (0); 2154 } 2155 2156 int 2157 scf_iter_next_scope(scf_iter_t *iter, scf_scope_t *out) 2158 { 2159 int ret; 2160 scf_handle_t *h = iter->iter_handle; 2161 2162 if (h != out->rd_d.rd_handle) 2163 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH)); 2164 2165 (void) pthread_mutex_lock(&h->rh_lock); 2166 if (iter->iter_type == REP_PROTOCOL_ENTITY_NONE) { 2167 (void) pthread_mutex_unlock(&h->rh_lock); 2168 return (scf_set_error(SCF_ERROR_NOT_SET)); 2169 } 2170 if (iter->iter_type != REP_PROTOCOL_ENTITY_SCOPE) { 2171 (void) pthread_mutex_unlock(&h->rh_lock); 2172 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 2173 } 2174 if (iter->iter_sequence == 1) { 2175 if ((ret = handle_get_local_scope_locked(h, out)) == 2176 SCF_SUCCESS) { 2177 iter->iter_sequence++; 2178 ret = 1; 2179 } 2180 } else { 2181 datael_reset_locked(&out->rd_d); 2182 ret = 0; 2183 } 2184 (void) pthread_mutex_unlock(&h->rh_lock); 2185 return (ret); 2186 } 2187 2188 int 2189 scf_handle_get_scope(scf_handle_t *h, const char *name, scf_scope_t *out) 2190 { 2191 int ret; 2192 2193 if (h != out->rd_d.rd_handle) 2194 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH)); 2195 2196 (void) pthread_mutex_lock(&h->rh_lock); 2197 if (strcmp(name, SCF_SCOPE_LOCAL) == 0) { 2198 ret = handle_get_local_scope_locked(h, out); 2199 } else { 2200 datael_reset_locked(&out->rd_d); 2201 if (uu_check_name(name, 0) == -1) 2202 ret = scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 2203 else 2204 ret = scf_set_error(SCF_ERROR_NOT_FOUND); 2205 } 2206 (void) pthread_mutex_unlock(&h->rh_lock); 2207 return (ret); 2208 } 2209 2210 static int 2211 datael_setup_iter(scf_iter_t *iter, const scf_datael_t *dp, uint32_t res_type, 2212 boolean_t composed) 2213 { 2214 scf_handle_t *h = dp->rd_handle; 2215 2216 struct rep_protocol_iter_start request; 2217 struct rep_protocol_response response; 2218 2219 ssize_t r; 2220 2221 if (h != iter->iter_handle) 2222 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH)); 2223 2224 (void) pthread_mutex_lock(&h->rh_lock); 2225 scf_iter_reset_locked(iter); 2226 iter->iter_type = res_type; 2227 2228 request.rpr_request = REP_PROTOCOL_ITER_START; 2229 request.rpr_iterid = iter->iter_id; 2230 request.rpr_entity = dp->rd_entity; 2231 request.rpr_itertype = res_type; 2232 request.rpr_flags = RP_ITER_START_ALL | 2233 (composed ? RP_ITER_START_COMPOSED : 0); 2234 request.rpr_pattern[0] = 0; 2235 2236 datael_finish_reset(dp); 2237 r = make_door_call(h, &request, sizeof (request), 2238 &response, sizeof (response)); 2239 2240 if (r < 0) { 2241 (void) pthread_mutex_unlock(&h->rh_lock); 2242 DOOR_ERRORS_BLOCK(r); 2243 } 2244 if (response.rpr_response != REP_PROTOCOL_SUCCESS) { 2245 (void) pthread_mutex_unlock(&h->rh_lock); 2246 return (scf_set_error(proto_error(response.rpr_response))); 2247 } 2248 iter->iter_sequence++; 2249 (void) pthread_mutex_unlock(&h->rh_lock); 2250 return (SCF_SUCCESS); 2251 } 2252 2253 static int 2254 datael_setup_iter_pgtyped(scf_iter_t *iter, const scf_datael_t *dp, 2255 const char *pgtype, boolean_t composed) 2256 { 2257 scf_handle_t *h = dp->rd_handle; 2258 2259 struct rep_protocol_iter_start request; 2260 struct rep_protocol_response response; 2261 2262 ssize_t r; 2263 2264 if (h != iter->iter_handle) 2265 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH)); 2266 2267 if (pgtype == NULL || strlcpy(request.rpr_pattern, pgtype, 2268 sizeof (request.rpr_pattern)) >= sizeof (request.rpr_pattern)) { 2269 scf_iter_reset(iter); 2270 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 2271 } 2272 2273 (void) pthread_mutex_lock(&h->rh_lock); 2274 request.rpr_request = REP_PROTOCOL_ITER_START; 2275 request.rpr_iterid = iter->iter_id; 2276 request.rpr_entity = dp->rd_entity; 2277 request.rpr_itertype = REP_PROTOCOL_ENTITY_PROPERTYGRP; 2278 request.rpr_flags = RP_ITER_START_PGTYPE | 2279 (composed ? RP_ITER_START_COMPOSED : 0); 2280 2281 datael_finish_reset(dp); 2282 scf_iter_reset_locked(iter); 2283 iter->iter_type = REP_PROTOCOL_ENTITY_PROPERTYGRP; 2284 2285 r = make_door_call(h, &request, sizeof (request), 2286 &response, sizeof (response)); 2287 2288 if (r < 0) { 2289 (void) pthread_mutex_unlock(&h->rh_lock); 2290 2291 DOOR_ERRORS_BLOCK(r); 2292 } 2293 if (response.rpr_response != REP_PROTOCOL_SUCCESS) { 2294 (void) pthread_mutex_unlock(&h->rh_lock); 2295 return (scf_set_error(proto_error(response.rpr_response))); 2296 } 2297 iter->iter_sequence++; 2298 (void) pthread_mutex_unlock(&h->rh_lock); 2299 return (SCF_SUCCESS); 2300 } 2301 2302 static int 2303 datael_iter_next(scf_iter_t *iter, scf_datael_t *out) 2304 { 2305 scf_handle_t *h = iter->iter_handle; 2306 2307 struct rep_protocol_iter_read request; 2308 struct rep_protocol_response response; 2309 ssize_t r; 2310 2311 if (h != out->rd_handle) 2312 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH)); 2313 2314 (void) pthread_mutex_lock(&h->rh_lock); 2315 if (iter->iter_type == REP_PROTOCOL_ENTITY_NONE || 2316 iter->iter_sequence == 1) { 2317 (void) pthread_mutex_unlock(&h->rh_lock); 2318 return (scf_set_error(SCF_ERROR_NOT_SET)); 2319 } 2320 2321 if (out->rd_type != iter->iter_type) { 2322 (void) pthread_mutex_unlock(&h->rh_lock); 2323 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 2324 } 2325 2326 request.rpr_request = REP_PROTOCOL_ITER_READ; 2327 request.rpr_iterid = iter->iter_id; 2328 request.rpr_sequence = iter->iter_sequence; 2329 request.rpr_entityid = out->rd_entity; 2330 2331 datael_finish_reset(out); 2332 r = make_door_call(h, &request, sizeof (request), 2333 &response, sizeof (response)); 2334 2335 if (r < 0) { 2336 (void) pthread_mutex_unlock(&h->rh_lock); 2337 DOOR_ERRORS_BLOCK(r); 2338 } 2339 2340 if (response.rpr_response == REP_PROTOCOL_DONE) { 2341 (void) pthread_mutex_unlock(&h->rh_lock); 2342 return (0); 2343 } 2344 if (response.rpr_response != REP_PROTOCOL_SUCCESS) { 2345 (void) pthread_mutex_unlock(&h->rh_lock); 2346 return (scf_set_error(proto_error(response.rpr_response))); 2347 } 2348 iter->iter_sequence++; 2349 (void) pthread_mutex_unlock(&h->rh_lock); 2350 2351 return (1); 2352 } 2353 2354 int 2355 scf_iter_scope_services(scf_iter_t *iter, const scf_scope_t *s) 2356 { 2357 return (datael_setup_iter(iter, &s->rd_d, 2358 REP_PROTOCOL_ENTITY_SERVICE, 0)); 2359 } 2360 2361 int 2362 scf_iter_next_service(scf_iter_t *iter, scf_service_t *out) 2363 { 2364 return (datael_iter_next(iter, &out->rd_d)); 2365 } 2366 2367 int 2368 scf_iter_service_instances(scf_iter_t *iter, const scf_service_t *svc) 2369 { 2370 return (datael_setup_iter(iter, &svc->rd_d, 2371 REP_PROTOCOL_ENTITY_INSTANCE, 0)); 2372 } 2373 2374 int 2375 scf_iter_next_instance(scf_iter_t *iter, scf_instance_t *out) 2376 { 2377 return (datael_iter_next(iter, &out->rd_d)); 2378 } 2379 2380 int 2381 scf_iter_service_pgs(scf_iter_t *iter, const scf_service_t *svc) 2382 { 2383 return (datael_setup_iter(iter, &svc->rd_d, 2384 REP_PROTOCOL_ENTITY_PROPERTYGRP, 0)); 2385 } 2386 2387 int 2388 scf_iter_service_pgs_typed(scf_iter_t *iter, const scf_service_t *svc, 2389 const char *type) 2390 { 2391 return (datael_setup_iter_pgtyped(iter, &svc->rd_d, type, 0)); 2392 } 2393 2394 int 2395 scf_iter_instance_snapshots(scf_iter_t *iter, const scf_instance_t *inst) 2396 { 2397 return (datael_setup_iter(iter, &inst->rd_d, 2398 REP_PROTOCOL_ENTITY_SNAPSHOT, 0)); 2399 } 2400 2401 int 2402 scf_iter_next_snapshot(scf_iter_t *iter, scf_snapshot_t *out) 2403 { 2404 return (datael_iter_next(iter, &out->rd_d)); 2405 } 2406 2407 int 2408 scf_iter_instance_pgs(scf_iter_t *iter, const scf_instance_t *inst) 2409 { 2410 return (datael_setup_iter(iter, &inst->rd_d, 2411 REP_PROTOCOL_ENTITY_PROPERTYGRP, 0)); 2412 } 2413 2414 int 2415 scf_iter_instance_pgs_typed(scf_iter_t *iter, const scf_instance_t *inst, 2416 const char *type) 2417 { 2418 return (datael_setup_iter_pgtyped(iter, &inst->rd_d, type, 0)); 2419 } 2420 2421 int 2422 scf_iter_instance_pgs_composed(scf_iter_t *iter, const scf_instance_t *inst, 2423 const scf_snapshot_t *snap) 2424 { 2425 if (snap != NULL && inst->rd_d.rd_handle != snap->rd_d.rd_handle) 2426 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH)); 2427 2428 return (datael_setup_iter(iter, snap ? &snap->rd_d : &inst->rd_d, 2429 REP_PROTOCOL_ENTITY_PROPERTYGRP, 1)); 2430 } 2431 2432 int 2433 scf_iter_instance_pgs_typed_composed(scf_iter_t *iter, 2434 const scf_instance_t *inst, const scf_snapshot_t *snap, const char *type) 2435 { 2436 if (snap != NULL && inst->rd_d.rd_handle != snap->rd_d.rd_handle) 2437 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH)); 2438 2439 return (datael_setup_iter_pgtyped(iter, 2440 snap ? &snap->rd_d : &inst->rd_d, type, 1)); 2441 } 2442 2443 int 2444 scf_iter_snaplevel_pgs(scf_iter_t *iter, const scf_snaplevel_t *inst) 2445 { 2446 return (datael_setup_iter(iter, &inst->rd_d, 2447 REP_PROTOCOL_ENTITY_PROPERTYGRP, 0)); 2448 } 2449 2450 int 2451 scf_iter_snaplevel_pgs_typed(scf_iter_t *iter, const scf_snaplevel_t *inst, 2452 const char *type) 2453 { 2454 return (datael_setup_iter_pgtyped(iter, &inst->rd_d, type, 0)); 2455 } 2456 2457 int 2458 scf_iter_next_pg(scf_iter_t *iter, scf_propertygroup_t *out) 2459 { 2460 return (datael_iter_next(iter, &out->rd_d)); 2461 } 2462 2463 int 2464 scf_iter_pg_properties(scf_iter_t *iter, const scf_propertygroup_t *pg) 2465 { 2466 return (datael_setup_iter(iter, &pg->rd_d, 2467 REP_PROTOCOL_ENTITY_PROPERTY, 0)); 2468 } 2469 2470 int 2471 scf_iter_next_property(scf_iter_t *iter, scf_property_t *out) 2472 { 2473 return (datael_iter_next(iter, &out->rd_d)); 2474 } 2475 2476 /* 2477 * Fails with 2478 * _INVALID_ARGUMENT - handle is NULL 2479 * _INTERNAL - server response too big 2480 * entity already set up with different type 2481 * _NO_RESOURCES 2482 * _NO_MEMORY 2483 */ 2484 scf_scope_t * 2485 scf_scope_create(scf_handle_t *handle) 2486 { 2487 scf_scope_t *ret; 2488 2489 ret = uu_zalloc(sizeof (*ret)); 2490 if (ret != NULL) { 2491 if (datael_init(&ret->rd_d, handle, 2492 REP_PROTOCOL_ENTITY_SCOPE) == -1) { 2493 uu_free(ret); 2494 return (NULL); 2495 } 2496 } else { 2497 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 2498 } 2499 2500 return (ret); 2501 } 2502 2503 scf_handle_t * 2504 scf_scope_handle(const scf_scope_t *val) 2505 { 2506 return (datael_handle(&val->rd_d)); 2507 } 2508 2509 void 2510 scf_scope_destroy(scf_scope_t *val) 2511 { 2512 if (val == NULL) 2513 return; 2514 2515 datael_destroy(&val->rd_d); 2516 uu_free(val); 2517 } 2518 2519 ssize_t 2520 scf_scope_get_name(const scf_scope_t *rep, char *out, size_t len) 2521 { 2522 return (datael_get_name(&rep->rd_d, out, len, RP_ENTITY_NAME_NAME)); 2523 } 2524 2525 /*ARGSUSED*/ 2526 int 2527 scf_scope_get_parent(const scf_scope_t *child, scf_scope_t *parent) 2528 { 2529 char name[1]; 2530 2531 /* fake up the side-effects */ 2532 datael_reset(&parent->rd_d); 2533 if (scf_scope_get_name(child, name, sizeof (name)) < 0) 2534 return (-1); 2535 return (scf_set_error(SCF_ERROR_NOT_FOUND)); 2536 } 2537 2538 /* 2539 * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL 2540 * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY. 2541 */ 2542 scf_service_t * 2543 scf_service_create(scf_handle_t *handle) 2544 { 2545 scf_service_t *ret; 2546 ret = uu_zalloc(sizeof (*ret)); 2547 if (ret != NULL) { 2548 if (datael_init(&ret->rd_d, handle, 2549 REP_PROTOCOL_ENTITY_SERVICE) == -1) { 2550 uu_free(ret); 2551 return (NULL); 2552 } 2553 } else { 2554 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 2555 } 2556 2557 return (ret); 2558 } 2559 2560 int 2561 scf_scope_add_service(const scf_scope_t *scope, const char *name, 2562 scf_service_t *svc) 2563 { 2564 return (datael_add_child(&scope->rd_d, name, 2565 REP_PROTOCOL_ENTITY_SERVICE, (svc != NULL)? &svc->rd_d : NULL)); 2566 } 2567 2568 int 2569 scf_scope_get_service(const scf_scope_t *s, const char *name, 2570 scf_service_t *svc) 2571 { 2572 return (datael_get_child(&s->rd_d, name, REP_PROTOCOL_ENTITY_SERVICE, 2573 svc ? &svc->rd_d : NULL, 0)); 2574 } 2575 2576 scf_handle_t * 2577 scf_service_handle(const scf_service_t *val) 2578 { 2579 return (datael_handle(&val->rd_d)); 2580 } 2581 2582 int 2583 scf_service_delete(scf_service_t *svc) 2584 { 2585 return (datael_delete(&svc->rd_d)); 2586 } 2587 2588 int 2589 scf_instance_delete(scf_instance_t *inst) 2590 { 2591 return (datael_delete(&inst->rd_d)); 2592 } 2593 2594 int 2595 scf_pg_delete(scf_propertygroup_t *pg) 2596 { 2597 return (datael_delete(&pg->rd_d)); 2598 } 2599 2600 int 2601 _scf_snapshot_delete(scf_snapshot_t *snap) 2602 { 2603 return (datael_delete(&snap->rd_d)); 2604 } 2605 2606 int 2607 scf_service_add_instance(const scf_service_t *svc, const char *name, 2608 scf_instance_t *instance) 2609 { 2610 return (datael_add_child(&svc->rd_d, name, 2611 REP_PROTOCOL_ENTITY_INSTANCE, 2612 (instance != NULL)? &instance->rd_d : NULL)); 2613 } 2614 2615 int 2616 scf_service_get_instance(const scf_service_t *svc, const char *name, 2617 scf_instance_t *inst) 2618 { 2619 return (datael_get_child(&svc->rd_d, name, REP_PROTOCOL_ENTITY_INSTANCE, 2620 inst ? &inst->rd_d : NULL, 0)); 2621 } 2622 2623 int 2624 scf_service_add_pg(const scf_service_t *svc, const char *name, 2625 const char *type, uint32_t flags, scf_propertygroup_t *pg) 2626 { 2627 return (datael_add_pg(&svc->rd_d, name, type, flags, 2628 (pg != NULL)?&pg->rd_d : NULL)); 2629 } 2630 2631 int 2632 scf_service_get_pg(const scf_service_t *svc, const char *name, 2633 scf_propertygroup_t *pg) 2634 { 2635 return (datael_get_child(&svc->rd_d, name, 2636 REP_PROTOCOL_ENTITY_PROPERTYGRP, pg ? &pg->rd_d : NULL, 0)); 2637 } 2638 2639 int 2640 scf_instance_add_pg(const scf_instance_t *inst, const char *name, 2641 const char *type, uint32_t flags, scf_propertygroup_t *pg) 2642 { 2643 return (datael_add_pg(&inst->rd_d, name, type, flags, 2644 (pg != NULL)?&pg->rd_d : NULL)); 2645 } 2646 2647 int 2648 scf_instance_get_snapshot(const scf_instance_t *inst, const char *name, 2649 scf_snapshot_t *pg) 2650 { 2651 return (datael_get_child(&inst->rd_d, name, 2652 REP_PROTOCOL_ENTITY_SNAPSHOT, pg ? &pg->rd_d : NULL, 0)); 2653 } 2654 2655 int 2656 scf_instance_get_pg(const scf_instance_t *inst, const char *name, 2657 scf_propertygroup_t *pg) 2658 { 2659 return (datael_get_child(&inst->rd_d, name, 2660 REP_PROTOCOL_ENTITY_PROPERTYGRP, pg ? &pg->rd_d : NULL, 0)); 2661 } 2662 2663 int 2664 scf_instance_get_pg_composed(const scf_instance_t *inst, 2665 const scf_snapshot_t *snap, const char *name, scf_propertygroup_t *pg) 2666 { 2667 if (snap != NULL && inst->rd_d.rd_handle != snap->rd_d.rd_handle) 2668 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH)); 2669 2670 return (datael_get_child(snap ? &snap->rd_d : &inst->rd_d, name, 2671 REP_PROTOCOL_ENTITY_PROPERTYGRP, pg ? &pg->rd_d : NULL, 1)); 2672 } 2673 2674 int 2675 scf_pg_get_property(const scf_propertygroup_t *pg, const char *name, 2676 scf_property_t *prop) 2677 { 2678 return (datael_get_child(&pg->rd_d, name, REP_PROTOCOL_ENTITY_PROPERTY, 2679 prop ? &prop->rd_d : NULL, 0)); 2680 } 2681 2682 void 2683 scf_service_destroy(scf_service_t *val) 2684 { 2685 if (val == NULL) 2686 return; 2687 2688 datael_destroy(&val->rd_d); 2689 uu_free(val); 2690 } 2691 2692 ssize_t 2693 scf_service_get_name(const scf_service_t *rep, char *out, size_t len) 2694 { 2695 return (datael_get_name(&rep->rd_d, out, len, RP_ENTITY_NAME_NAME)); 2696 } 2697 2698 /* 2699 * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL 2700 * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY. 2701 */ 2702 scf_instance_t * 2703 scf_instance_create(scf_handle_t *handle) 2704 { 2705 scf_instance_t *ret; 2706 2707 ret = uu_zalloc(sizeof (*ret)); 2708 if (ret != NULL) { 2709 if (datael_init(&ret->rd_d, handle, 2710 REP_PROTOCOL_ENTITY_INSTANCE) == -1) { 2711 uu_free(ret); 2712 return (NULL); 2713 } 2714 } else { 2715 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 2716 } 2717 2718 return (ret); 2719 } 2720 2721 scf_handle_t * 2722 scf_instance_handle(const scf_instance_t *val) 2723 { 2724 return (datael_handle(&val->rd_d)); 2725 } 2726 2727 void 2728 scf_instance_destroy(scf_instance_t *val) 2729 { 2730 if (val == NULL) 2731 return; 2732 2733 datael_destroy(&val->rd_d); 2734 uu_free(val); 2735 } 2736 2737 ssize_t 2738 scf_instance_get_name(const scf_instance_t *rep, char *out, size_t len) 2739 { 2740 return (datael_get_name(&rep->rd_d, out, len, RP_ENTITY_NAME_NAME)); 2741 } 2742 2743 /* 2744 * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL 2745 * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY. 2746 */ 2747 scf_snapshot_t * 2748 scf_snapshot_create(scf_handle_t *handle) 2749 { 2750 scf_snapshot_t *ret; 2751 2752 ret = uu_zalloc(sizeof (*ret)); 2753 if (ret != NULL) { 2754 if (datael_init(&ret->rd_d, handle, 2755 REP_PROTOCOL_ENTITY_SNAPSHOT) == -1) { 2756 uu_free(ret); 2757 return (NULL); 2758 } 2759 } else { 2760 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 2761 } 2762 2763 return (ret); 2764 } 2765 2766 scf_handle_t * 2767 scf_snapshot_handle(const scf_snapshot_t *val) 2768 { 2769 return (datael_handle(&val->rd_d)); 2770 } 2771 2772 void 2773 scf_snapshot_destroy(scf_snapshot_t *val) 2774 { 2775 if (val == NULL) 2776 return; 2777 2778 datael_destroy(&val->rd_d); 2779 uu_free(val); 2780 } 2781 2782 ssize_t 2783 scf_snapshot_get_name(const scf_snapshot_t *rep, char *out, size_t len) 2784 { 2785 return (datael_get_name(&rep->rd_d, out, len, RP_ENTITY_NAME_NAME)); 2786 } 2787 2788 /* 2789 * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL 2790 * (bad server response or id in use), _NO_RESOURCES, _NO_MEMORY. 2791 */ 2792 scf_snaplevel_t * 2793 scf_snaplevel_create(scf_handle_t *handle) 2794 { 2795 scf_snaplevel_t *ret; 2796 2797 ret = uu_zalloc(sizeof (*ret)); 2798 if (ret != NULL) { 2799 if (datael_init(&ret->rd_d, handle, 2800 REP_PROTOCOL_ENTITY_SNAPLEVEL) == -1) { 2801 uu_free(ret); 2802 return (NULL); 2803 } 2804 } else { 2805 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 2806 } 2807 2808 return (ret); 2809 } 2810 2811 scf_handle_t * 2812 scf_snaplevel_handle(const scf_snaplevel_t *val) 2813 { 2814 return (datael_handle(&val->rd_d)); 2815 } 2816 2817 void 2818 scf_snaplevel_destroy(scf_snaplevel_t *val) 2819 { 2820 if (val == NULL) 2821 return; 2822 2823 datael_destroy(&val->rd_d); 2824 uu_free(val); 2825 } 2826 2827 ssize_t 2828 scf_snaplevel_get_scope_name(const scf_snaplevel_t *rep, char *out, size_t len) 2829 { 2830 return (datael_get_name(&rep->rd_d, out, len, 2831 RP_ENTITY_NAME_SNAPLEVEL_SCOPE)); 2832 } 2833 2834 ssize_t 2835 scf_snaplevel_get_service_name(const scf_snaplevel_t *rep, char *out, 2836 size_t len) 2837 { 2838 return (datael_get_name(&rep->rd_d, out, len, 2839 RP_ENTITY_NAME_SNAPLEVEL_SERVICE)); 2840 } 2841 2842 ssize_t 2843 scf_snaplevel_get_instance_name(const scf_snaplevel_t *rep, char *out, 2844 size_t len) 2845 { 2846 return (datael_get_name(&rep->rd_d, out, len, 2847 RP_ENTITY_NAME_SNAPLEVEL_INSTANCE)); 2848 } 2849 2850 int 2851 scf_snaplevel_get_pg(const scf_snaplevel_t *snap, const char *name, 2852 scf_propertygroup_t *pg) 2853 { 2854 return (datael_get_child(&snap->rd_d, name, 2855 REP_PROTOCOL_ENTITY_PROPERTYGRP, pg ? &pg->rd_d : NULL, 0)); 2856 } 2857 2858 static int 2859 snaplevel_next(const scf_datael_t *src, scf_snaplevel_t *dst_arg) 2860 { 2861 scf_handle_t *h = src->rd_handle; 2862 scf_snaplevel_t *dst = dst_arg; 2863 struct rep_protocol_entity_pair request; 2864 struct rep_protocol_response response; 2865 int r; 2866 int dups = 0; 2867 2868 if (h != dst->rd_d.rd_handle) 2869 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH)); 2870 2871 if (src == &dst->rd_d) { 2872 dups = 1; 2873 dst = HANDLE_HOLD_SNAPLVL(h); 2874 } 2875 (void) pthread_mutex_lock(&h->rh_lock); 2876 request.rpr_request = REP_PROTOCOL_NEXT_SNAPLEVEL; 2877 request.rpr_entity_src = src->rd_entity; 2878 request.rpr_entity_dst = dst->rd_d.rd_entity; 2879 2880 datael_finish_reset(src); 2881 datael_finish_reset(&dst->rd_d); 2882 r = make_door_call(h, &request, sizeof (request), 2883 &response, sizeof (response)); 2884 /* 2885 * if we succeeded, we need to swap dst and dst_arg's identity. We 2886 * take advantage of the fact that the only in-library knowledge is 2887 * their entity ids. 2888 */ 2889 if (dups && r >= 0 && 2890 (response.rpr_response == REP_PROTOCOL_SUCCESS || 2891 response.rpr_response == REP_PROTOCOL_DONE)) { 2892 int entity = dst->rd_d.rd_entity; 2893 2894 dst->rd_d.rd_entity = dst_arg->rd_d.rd_entity; 2895 dst_arg->rd_d.rd_entity = entity; 2896 } 2897 (void) pthread_mutex_unlock(&h->rh_lock); 2898 2899 if (dups) 2900 HANDLE_RELE_SNAPLVL(h); 2901 2902 if (r < 0) 2903 DOOR_ERRORS_BLOCK(r); 2904 2905 if (response.rpr_response != REP_PROTOCOL_SUCCESS && 2906 response.rpr_response != REP_PROTOCOL_DONE) { 2907 return (scf_set_error(proto_error(response.rpr_response))); 2908 } 2909 2910 return (response.rpr_response == REP_PROTOCOL_SUCCESS) ? 2911 SCF_SUCCESS : SCF_COMPLETE; 2912 } 2913 2914 int scf_snapshot_get_base_snaplevel(const scf_snapshot_t *base, 2915 scf_snaplevel_t *out) 2916 { 2917 return (snaplevel_next(&base->rd_d, out)); 2918 } 2919 2920 int scf_snaplevel_get_next_snaplevel(const scf_snaplevel_t *base, 2921 scf_snaplevel_t *out) 2922 { 2923 return (snaplevel_next(&base->rd_d, out)); 2924 } 2925 2926 /* 2927 * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL 2928 * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY. 2929 */ 2930 scf_propertygroup_t * 2931 scf_pg_create(scf_handle_t *handle) 2932 { 2933 scf_propertygroup_t *ret; 2934 ret = uu_zalloc(sizeof (*ret)); 2935 if (ret != NULL) { 2936 if (datael_init(&ret->rd_d, handle, 2937 REP_PROTOCOL_ENTITY_PROPERTYGRP) == -1) { 2938 uu_free(ret); 2939 return (NULL); 2940 } 2941 } else { 2942 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 2943 } 2944 2945 return (ret); 2946 } 2947 2948 scf_handle_t * 2949 scf_pg_handle(const scf_propertygroup_t *val) 2950 { 2951 return (datael_handle(&val->rd_d)); 2952 } 2953 2954 void 2955 scf_pg_destroy(scf_propertygroup_t *val) 2956 { 2957 if (val == NULL) 2958 return; 2959 2960 datael_destroy(&val->rd_d); 2961 uu_free(val); 2962 } 2963 2964 ssize_t 2965 scf_pg_get_name(const scf_propertygroup_t *pg, char *out, size_t len) 2966 { 2967 return (datael_get_name(&pg->rd_d, out, len, RP_ENTITY_NAME_NAME)); 2968 } 2969 2970 ssize_t 2971 scf_pg_get_type(const scf_propertygroup_t *pg, char *out, size_t len) 2972 { 2973 return (datael_get_name(&pg->rd_d, out, len, RP_ENTITY_NAME_PGTYPE)); 2974 } 2975 2976 int 2977 scf_pg_get_flags(const scf_propertygroup_t *pg, uint32_t *out) 2978 { 2979 char buf[REP_PROTOCOL_NAME_LEN]; 2980 ssize_t res; 2981 2982 res = datael_get_name(&pg->rd_d, buf, sizeof (buf), 2983 RP_ENTITY_NAME_PGFLAGS); 2984 2985 if (res == -1) 2986 return (-1); 2987 2988 if (uu_strtouint(buf, out, sizeof (*out), 0, 0, UINT32_MAX) == -1) 2989 return (scf_set_error(SCF_ERROR_INTERNAL)); 2990 2991 return (0); 2992 } 2993 2994 static int 2995 datael_update(scf_datael_t *dp) 2996 { 2997 scf_handle_t *h = dp->rd_handle; 2998 2999 struct rep_protocol_entity_update request; 3000 struct rep_protocol_response response; 3001 3002 int r; 3003 3004 (void) pthread_mutex_lock(&h->rh_lock); 3005 request.rpr_request = REP_PROTOCOL_ENTITY_UPDATE; 3006 request.rpr_entityid = dp->rd_entity; 3007 3008 datael_finish_reset(dp); 3009 request.rpr_changeid = handle_next_changeid(h); 3010 3011 r = make_door_call(h, &request, sizeof (request), 3012 &response, sizeof (response)); 3013 (void) pthread_mutex_unlock(&h->rh_lock); 3014 3015 if (r < 0) 3016 DOOR_ERRORS_BLOCK(r); 3017 3018 if (response.rpr_response != REP_PROTOCOL_SUCCESS && 3019 response.rpr_response != REP_PROTOCOL_DONE) { 3020 return (scf_set_error(proto_error(response.rpr_response))); 3021 } 3022 3023 return (response.rpr_response == REP_PROTOCOL_SUCCESS) ? 3024 SCF_SUCCESS : SCF_COMPLETE; 3025 } 3026 3027 int 3028 scf_pg_update(scf_propertygroup_t *pg) 3029 { 3030 return (datael_update(&pg->rd_d)); 3031 } 3032 3033 int 3034 scf_snapshot_update(scf_snapshot_t *snap) 3035 { 3036 return (datael_update(&snap->rd_d)); 3037 } 3038 3039 int 3040 _scf_pg_wait(scf_propertygroup_t *pg, int timeout) 3041 { 3042 scf_handle_t *h = pg->rd_d.rd_handle; 3043 3044 struct rep_protocol_propertygrp_request request; 3045 struct rep_protocol_response response; 3046 3047 struct pollfd pollfd; 3048 3049 int r; 3050 3051 (void) pthread_mutex_lock(&h->rh_lock); 3052 request.rpr_request = REP_PROTOCOL_PROPERTYGRP_SETUP_WAIT; 3053 request.rpr_entityid = pg->rd_d.rd_entity; 3054 3055 datael_finish_reset(&pg->rd_d); 3056 if (!handle_is_bound(h)) { 3057 (void) pthread_mutex_unlock(&h->rh_lock); 3058 return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN)); 3059 } 3060 r = make_door_call_retfd(h->rh_doorfd, &request, sizeof (request), 3061 &response, sizeof (response), &pollfd.fd); 3062 (void) pthread_mutex_unlock(&h->rh_lock); 3063 3064 if (r < 0) 3065 DOOR_ERRORS_BLOCK(r); 3066 3067 assert((response.rpr_response == REP_PROTOCOL_SUCCESS) == 3068 (pollfd.fd != -1)); 3069 3070 if (response.rpr_response == REP_PROTOCOL_FAIL_NOT_LATEST) 3071 return (SCF_SUCCESS); 3072 3073 if (response.rpr_response != REP_PROTOCOL_SUCCESS) 3074 return (scf_set_error(proto_error(response.rpr_response))); 3075 3076 pollfd.events = 0; 3077 pollfd.revents = 0; 3078 3079 r = poll(&pollfd, 1, timeout * MILLISEC); 3080 3081 (void) close(pollfd.fd); 3082 return (pollfd.revents ? SCF_SUCCESS : SCF_COMPLETE); 3083 } 3084 3085 static int 3086 scf_notify_add_pattern(scf_handle_t *h, int type, const char *name) 3087 { 3088 struct rep_protocol_notify_request request; 3089 struct rep_protocol_response response; 3090 int r; 3091 3092 (void) pthread_mutex_lock(&h->rh_lock); 3093 request.rpr_request = REP_PROTOCOL_CLIENT_ADD_NOTIFY; 3094 request.rpr_type = type; 3095 (void) strlcpy(request.rpr_pattern, name, sizeof (request.rpr_pattern)); 3096 3097 r = make_door_call(h, &request, sizeof (request), 3098 &response, sizeof (response)); 3099 (void) pthread_mutex_unlock(&h->rh_lock); 3100 3101 if (r < 0) 3102 DOOR_ERRORS_BLOCK(r); 3103 3104 if (response.rpr_response != REP_PROTOCOL_SUCCESS) 3105 return (scf_set_error(proto_error(response.rpr_response))); 3106 3107 return (SCF_SUCCESS); 3108 } 3109 3110 int 3111 _scf_notify_add_pgname(scf_handle_t *h, const char *name) 3112 { 3113 return (scf_notify_add_pattern(h, REP_PROTOCOL_NOTIFY_PGNAME, name)); 3114 } 3115 3116 int 3117 _scf_notify_add_pgtype(scf_handle_t *h, const char *type) 3118 { 3119 return (scf_notify_add_pattern(h, REP_PROTOCOL_NOTIFY_PGTYPE, type)); 3120 } 3121 3122 int 3123 _scf_notify_wait(scf_propertygroup_t *pg, char *out, size_t sz) 3124 { 3125 struct rep_protocol_wait_request request; 3126 struct rep_protocol_fmri_response response; 3127 3128 scf_handle_t *h = pg->rd_d.rd_handle; 3129 int dummy; 3130 int fd; 3131 int r; 3132 3133 (void) pthread_mutex_lock(&h->rh_lock); 3134 datael_finish_reset(&pg->rd_d); 3135 if (!handle_is_bound(h)) { 3136 (void) pthread_mutex_unlock(&h->rh_lock); 3137 return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN)); 3138 } 3139 fd = h->rh_doorfd; 3140 ++h->rh_fd_users; 3141 assert(h->rh_fd_users > 0); 3142 3143 request.rpr_request = REP_PROTOCOL_CLIENT_WAIT; 3144 request.rpr_entityid = pg->rd_d.rd_entity; 3145 (void) pthread_mutex_unlock(&h->rh_lock); 3146 3147 r = make_door_call_retfd(fd, &request, sizeof (request), 3148 &response, sizeof (response), &dummy); 3149 3150 (void) pthread_mutex_lock(&h->rh_lock); 3151 assert(h->rh_fd_users > 0); 3152 if (--h->rh_fd_users == 0) { 3153 (void) pthread_cond_broadcast(&h->rh_cv); 3154 /* 3155 * check for a delayed close, now that there are no other 3156 * users. 3157 */ 3158 if (h->rh_doorfd_old != -1) { 3159 assert(h->rh_doorfd == -1); 3160 assert(fd == h->rh_doorfd_old); 3161 (void) close(h->rh_doorfd_old); 3162 h->rh_doorfd_old = -1; 3163 } 3164 } 3165 handle_unrefed(h); /* drops h->rh_lock */ 3166 3167 if (r < 0) 3168 DOOR_ERRORS_BLOCK(r); 3169 3170 if (response.rpr_response == REP_PROTOCOL_DONE) 3171 return (scf_set_error(SCF_ERROR_NOT_SET)); 3172 3173 if (response.rpr_response != REP_PROTOCOL_SUCCESS) 3174 return (scf_set_error(proto_error(response.rpr_response))); 3175 3176 /* the following will be non-zero for delete notifications */ 3177 return (strlcpy(out, response.rpr_fmri, sz)); 3178 } 3179 3180 static int 3181 _scf_snapshot_take(scf_instance_t *inst, const char *name, 3182 scf_snapshot_t *snap, int flags) 3183 { 3184 scf_handle_t *h = inst->rd_d.rd_handle; 3185 3186 struct rep_protocol_snapshot_take request; 3187 struct rep_protocol_response response; 3188 3189 int r; 3190 3191 if (h != snap->rd_d.rd_handle) 3192 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH)); 3193 3194 if (strlcpy(request.rpr_name, (name != NULL)? name : "", 3195 sizeof (request.rpr_name)) >= sizeof (request.rpr_name)) 3196 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 3197 3198 (void) pthread_mutex_lock(&h->rh_lock); 3199 request.rpr_request = REP_PROTOCOL_SNAPSHOT_TAKE; 3200 request.rpr_entityid_src = inst->rd_d.rd_entity; 3201 request.rpr_entityid_dest = snap->rd_d.rd_entity; 3202 request.rpr_flags = flags; 3203 3204 datael_finish_reset(&inst->rd_d); 3205 datael_finish_reset(&snap->rd_d); 3206 3207 r = make_door_call(h, &request, sizeof (request), 3208 &response, sizeof (response)); 3209 (void) pthread_mutex_unlock(&h->rh_lock); 3210 3211 if (r < 0) 3212 DOOR_ERRORS_BLOCK(r); 3213 3214 if (response.rpr_response != REP_PROTOCOL_SUCCESS) 3215 return (scf_set_error(proto_error(response.rpr_response))); 3216 3217 return (SCF_SUCCESS); 3218 } 3219 3220 int 3221 _scf_snapshot_take_new_named(scf_instance_t *inst, 3222 const char *svcname, const char *instname, const char *snapname, 3223 scf_snapshot_t *snap) 3224 { 3225 scf_handle_t *h = inst->rd_d.rd_handle; 3226 3227 struct rep_protocol_snapshot_take_named request; 3228 struct rep_protocol_response response; 3229 3230 int r; 3231 3232 if (h != snap->rd_d.rd_handle) 3233 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH)); 3234 3235 if (strlcpy(request.rpr_svcname, svcname, 3236 sizeof (request.rpr_svcname)) >= sizeof (request.rpr_svcname)) 3237 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 3238 3239 if (strlcpy(request.rpr_instname, instname, 3240 sizeof (request.rpr_instname)) >= sizeof (request.rpr_instname)) 3241 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 3242 3243 if (strlcpy(request.rpr_name, snapname, 3244 sizeof (request.rpr_name)) >= sizeof (request.rpr_name)) 3245 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 3246 3247 (void) pthread_mutex_lock(&h->rh_lock); 3248 request.rpr_request = REP_PROTOCOL_SNAPSHOT_TAKE_NAMED; 3249 request.rpr_entityid_src = inst->rd_d.rd_entity; 3250 request.rpr_entityid_dest = snap->rd_d.rd_entity; 3251 3252 datael_finish_reset(&inst->rd_d); 3253 datael_finish_reset(&snap->rd_d); 3254 3255 r = make_door_call(h, &request, sizeof (request), 3256 &response, sizeof (response)); 3257 (void) pthread_mutex_unlock(&h->rh_lock); 3258 3259 if (r < 0) 3260 DOOR_ERRORS_BLOCK(r); 3261 3262 if (response.rpr_response != REP_PROTOCOL_SUCCESS) { 3263 assert(response.rpr_response != 3264 REP_PROTOCOL_FAIL_TYPE_MISMATCH); 3265 return (scf_set_error(proto_error(response.rpr_response))); 3266 } 3267 3268 return (SCF_SUCCESS); 3269 } 3270 3271 int 3272 _scf_snapshot_take_new(scf_instance_t *inst, const char *name, 3273 scf_snapshot_t *snap) 3274 { 3275 return (_scf_snapshot_take(inst, name, snap, REP_SNAPSHOT_NEW)); 3276 } 3277 3278 int 3279 _scf_snapshot_take_attach(scf_instance_t *inst, scf_snapshot_t *snap) 3280 { 3281 return (_scf_snapshot_take(inst, NULL, snap, REP_SNAPSHOT_ATTACH)); 3282 } 3283 3284 int 3285 _scf_snapshot_attach(scf_snapshot_t *src, scf_snapshot_t *dest) 3286 { 3287 scf_handle_t *h = dest->rd_d.rd_handle; 3288 3289 struct rep_protocol_snapshot_attach request; 3290 struct rep_protocol_response response; 3291 3292 int r; 3293 3294 if (h != src->rd_d.rd_handle) 3295 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH)); 3296 3297 (void) pthread_mutex_lock(&h->rh_lock); 3298 request.rpr_request = REP_PROTOCOL_SNAPSHOT_ATTACH; 3299 request.rpr_entityid_src = src->rd_d.rd_entity; 3300 request.rpr_entityid_dest = dest->rd_d.rd_entity; 3301 3302 datael_finish_reset(&src->rd_d); 3303 datael_finish_reset(&dest->rd_d); 3304 3305 r = make_door_call(h, &request, sizeof (request), 3306 &response, sizeof (response)); 3307 (void) pthread_mutex_unlock(&h->rh_lock); 3308 3309 if (r < 0) 3310 DOOR_ERRORS_BLOCK(r); 3311 3312 if (response.rpr_response != REP_PROTOCOL_SUCCESS) 3313 return (scf_set_error(proto_error(response.rpr_response))); 3314 3315 return (SCF_SUCCESS); 3316 } 3317 3318 /* 3319 * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL 3320 * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY. 3321 */ 3322 scf_property_t * 3323 scf_property_create(scf_handle_t *handle) 3324 { 3325 scf_property_t *ret; 3326 ret = uu_zalloc(sizeof (*ret)); 3327 if (ret != NULL) { 3328 if (datael_init(&ret->rd_d, handle, 3329 REP_PROTOCOL_ENTITY_PROPERTY) == -1) { 3330 uu_free(ret); 3331 return (NULL); 3332 } 3333 } else { 3334 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 3335 } 3336 3337 return (ret); 3338 } 3339 3340 scf_handle_t * 3341 scf_property_handle(const scf_property_t *val) 3342 { 3343 return (datael_handle(&val->rd_d)); 3344 } 3345 3346 void 3347 scf_property_destroy(scf_property_t *val) 3348 { 3349 if (val == NULL) 3350 return; 3351 3352 datael_destroy(&val->rd_d); 3353 uu_free(val); 3354 } 3355 3356 static int 3357 property_type_locked(const scf_property_t *prop, 3358 rep_protocol_value_type_t *out) 3359 { 3360 scf_handle_t *h = prop->rd_d.rd_handle; 3361 3362 struct rep_protocol_property_request request; 3363 struct rep_protocol_integer_response response; 3364 3365 int r; 3366 3367 assert(MUTEX_HELD(&h->rh_lock)); 3368 3369 request.rpr_request = REP_PROTOCOL_PROPERTY_GET_TYPE; 3370 request.rpr_entityid = prop->rd_d.rd_entity; 3371 3372 datael_finish_reset(&prop->rd_d); 3373 r = make_door_call(h, &request, sizeof (request), 3374 &response, sizeof (response)); 3375 3376 if (r < 0) 3377 DOOR_ERRORS_BLOCK(r); 3378 3379 if (response.rpr_response != REP_PROTOCOL_SUCCESS || 3380 r < sizeof (response)) { 3381 return (scf_set_error(proto_error(response.rpr_response))); 3382 } 3383 *out = response.rpr_value; 3384 return (SCF_SUCCESS); 3385 } 3386 3387 int 3388 scf_property_type(const scf_property_t *prop, scf_type_t *out) 3389 { 3390 scf_handle_t *h = prop->rd_d.rd_handle; 3391 rep_protocol_value_type_t out_raw; 3392 int ret; 3393 3394 (void) pthread_mutex_lock(&h->rh_lock); 3395 ret = property_type_locked(prop, &out_raw); 3396 (void) pthread_mutex_unlock(&h->rh_lock); 3397 3398 if (ret == SCF_SUCCESS) 3399 *out = scf_protocol_type_to_type(out_raw); 3400 3401 return (ret); 3402 } 3403 3404 int 3405 scf_property_is_type(const scf_property_t *prop, scf_type_t base_arg) 3406 { 3407 scf_handle_t *h = prop->rd_d.rd_handle; 3408 rep_protocol_value_type_t base = scf_type_to_protocol_type(base_arg); 3409 rep_protocol_value_type_t type; 3410 int ret; 3411 3412 if (base == REP_PROTOCOL_TYPE_INVALID) 3413 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 3414 3415 (void) pthread_mutex_lock(&h->rh_lock); 3416 ret = property_type_locked(prop, &type); 3417 (void) pthread_mutex_unlock(&h->rh_lock); 3418 3419 if (ret == SCF_SUCCESS) { 3420 if (!scf_is_compatible_type(base, type)) 3421 return (scf_set_error(SCF_ERROR_TYPE_MISMATCH)); 3422 } 3423 return (ret); 3424 } 3425 3426 ssize_t 3427 scf_property_get_name(const scf_property_t *prop, char *out, size_t len) 3428 { 3429 return (datael_get_name(&prop->rd_d, out, len, RP_ENTITY_NAME_NAME)); 3430 } 3431 3432 /* 3433 * transaction functions 3434 */ 3435 3436 /* 3437 * Fails with _NO_MEMORY, _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, 3438 * _INTERNAL (bad server response or id in use), or _NO_RESOURCES. 3439 */ 3440 scf_transaction_t * 3441 scf_transaction_create(scf_handle_t *handle) 3442 { 3443 scf_transaction_t *ret; 3444 3445 ret = uu_zalloc(sizeof (scf_transaction_t)); 3446 if (ret == NULL) { 3447 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 3448 return (NULL); 3449 } 3450 if (datael_init(&ret->tran_pg.rd_d, handle, 3451 REP_PROTOCOL_ENTITY_PROPERTYGRP) == -1) { 3452 uu_free(ret); 3453 return (NULL); /* error already set */ 3454 } 3455 ret->tran_state = TRAN_STATE_NEW; 3456 ret->tran_props = uu_list_create(tran_entry_pool, ret, UU_LIST_SORTED); 3457 if (ret->tran_props == NULL) { 3458 datael_destroy(&ret->tran_pg.rd_d); 3459 uu_free(ret); 3460 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 3461 return (NULL); 3462 } 3463 3464 return (ret); 3465 } 3466 3467 scf_handle_t * 3468 scf_transaction_handle(const scf_transaction_t *val) 3469 { 3470 return (handle_get(val->tran_pg.rd_d.rd_handle)); 3471 } 3472 3473 int 3474 scf_transaction_start(scf_transaction_t *tran, scf_propertygroup_t *pg) 3475 { 3476 scf_handle_t *h = tran->tran_pg.rd_d.rd_handle; 3477 3478 struct rep_protocol_transaction_start request; 3479 struct rep_protocol_response response; 3480 int r; 3481 3482 if (h != pg->rd_d.rd_handle) 3483 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH)); 3484 3485 (void) pthread_mutex_lock(&h->rh_lock); 3486 if (tran->tran_state != TRAN_STATE_NEW) { 3487 (void) pthread_mutex_unlock(&h->rh_lock); 3488 return (scf_set_error(SCF_ERROR_IN_USE)); 3489 } 3490 request.rpr_request = REP_PROTOCOL_PROPERTYGRP_TX_START; 3491 request.rpr_entityid_tx = tran->tran_pg.rd_d.rd_entity; 3492 request.rpr_entityid = pg->rd_d.rd_entity; 3493 3494 datael_finish_reset(&tran->tran_pg.rd_d); 3495 datael_finish_reset(&pg->rd_d); 3496 3497 r = make_door_call(h, &request, sizeof (request), 3498 &response, sizeof (response)); 3499 3500 if (r < 0) { 3501 (void) pthread_mutex_unlock(&h->rh_lock); 3502 DOOR_ERRORS_BLOCK(r); 3503 } 3504 3505 /* r < sizeof (response) cannot happen because sizeof (response) == 4 */ 3506 3507 if (response.rpr_response != REP_PROTOCOL_SUCCESS || 3508 r < sizeof (response)) { 3509 (void) pthread_mutex_unlock(&h->rh_lock); 3510 return (scf_set_error(proto_error(response.rpr_response))); 3511 } 3512 3513 tran->tran_state = TRAN_STATE_SETUP; 3514 tran->tran_invalid = 0; 3515 (void) pthread_mutex_unlock(&h->rh_lock); 3516 return (SCF_SUCCESS); 3517 } 3518 3519 static void 3520 entry_invalidate(scf_transaction_entry_t *cur, int and_destroy, 3521 int and_reset_value) 3522 { 3523 scf_value_t *v, *next; 3524 scf_transaction_t *tx; 3525 scf_handle_t *h = cur->entry_handle; 3526 3527 assert(MUTEX_HELD(&h->rh_lock)); 3528 3529 if ((tx = cur->entry_tx) != NULL) { 3530 tx->tran_invalid = 1; 3531 uu_list_remove(tx->tran_props, cur); 3532 cur->entry_tx = NULL; 3533 } 3534 3535 cur->entry_property = NULL; 3536 cur->entry_state = ENTRY_STATE_INVALID; 3537 cur->entry_action = REP_PROTOCOL_TX_ENTRY_INVALID; 3538 cur->entry_type = REP_PROTOCOL_TYPE_INVALID; 3539 3540 for (v = cur->entry_head; v != NULL; v = next) { 3541 next = v->value_next; 3542 v->value_tx = NULL; 3543 v->value_next = NULL; 3544 if (and_destroy || and_reset_value) 3545 scf_value_reset_locked(v, and_destroy); 3546 } 3547 cur->entry_head = NULL; 3548 } 3549 3550 static void 3551 entry_destroy_locked(scf_transaction_entry_t *entry) 3552 { 3553 scf_handle_t *h = entry->entry_handle; 3554 3555 assert(MUTEX_HELD(&h->rh_lock)); 3556 3557 entry_invalidate(entry, 0, 0); 3558 3559 entry->entry_handle = NULL; 3560 assert(h->rh_entries > 0); 3561 --h->rh_entries; 3562 --h->rh_extrefs; 3563 uu_list_node_fini(entry, &entry->entry_link, tran_entry_pool); 3564 uu_free(entry); 3565 } 3566 3567 static int 3568 transaction_add(scf_transaction_t *tran, scf_transaction_entry_t *entry, 3569 enum rep_protocol_transaction_action action, 3570 const char *prop, rep_protocol_value_type_t type) 3571 { 3572 scf_handle_t *h = tran->tran_pg.rd_d.rd_handle; 3573 scf_transaction_entry_t *old; 3574 scf_property_t *prop_p; 3575 rep_protocol_value_type_t oldtype; 3576 scf_error_t error = SCF_ERROR_NONE; 3577 int ret; 3578 uu_list_index_t idx; 3579 3580 if (h != entry->entry_handle) 3581 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH)); 3582 3583 if (action == REP_PROTOCOL_TX_ENTRY_DELETE) 3584 assert(type == REP_PROTOCOL_TYPE_INVALID); 3585 else if (type == REP_PROTOCOL_TYPE_INVALID) 3586 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 3587 3588 prop_p = HANDLE_HOLD_PROPERTY(h); 3589 3590 (void) pthread_mutex_lock(&h->rh_lock); 3591 if (tran->tran_state != TRAN_STATE_SETUP) { 3592 error = SCF_ERROR_NOT_SET; 3593 goto error; 3594 } 3595 if (tran->tran_invalid) { 3596 error = SCF_ERROR_NOT_SET; 3597 goto error; 3598 } 3599 3600 if (entry->entry_state != ENTRY_STATE_INVALID) 3601 entry_invalidate(entry, 0, 0); 3602 3603 old = uu_list_find(tran->tran_props, &prop, NULL, &idx); 3604 if (old != NULL) { 3605 error = SCF_ERROR_IN_USE; 3606 goto error; 3607 } 3608 3609 ret = datael_get_child_locked(&tran->tran_pg.rd_d, prop, 3610 REP_PROTOCOL_ENTITY_PROPERTY, &prop_p->rd_d); 3611 if (ret == -1 && (error = scf_error()) != SCF_ERROR_NOT_FOUND) { 3612 goto error; 3613 } 3614 3615 switch (action) { 3616 case REP_PROTOCOL_TX_ENTRY_DELETE: 3617 if (ret == -1) { 3618 error = SCF_ERROR_NOT_FOUND; 3619 goto error; 3620 } 3621 break; 3622 case REP_PROTOCOL_TX_ENTRY_NEW: 3623 if (ret != -1) { 3624 error = SCF_ERROR_EXISTS; 3625 goto error; 3626 } 3627 break; 3628 3629 case REP_PROTOCOL_TX_ENTRY_CLEAR: 3630 case REP_PROTOCOL_TX_ENTRY_REPLACE: 3631 if (ret == -1) { 3632 error = SCF_ERROR_NOT_FOUND; 3633 goto error; 3634 } 3635 if (action == REP_PROTOCOL_TX_ENTRY_CLEAR) { 3636 if (property_type_locked(prop_p, &oldtype) == -1) { 3637 error = scf_error(); 3638 goto error; 3639 } 3640 if (oldtype != type) { 3641 error = SCF_ERROR_TYPE_MISMATCH; 3642 goto error; 3643 } 3644 } 3645 break; 3646 default: 3647 assert(0); 3648 abort(); 3649 } 3650 3651 (void) strlcpy(entry->entry_namebuf, prop, 3652 sizeof (entry->entry_namebuf)); 3653 entry->entry_property = entry->entry_namebuf; 3654 entry->entry_action = action; 3655 entry->entry_type = type; 3656 3657 entry->entry_state = ENTRY_STATE_IN_TX_ACTION; 3658 entry->entry_tx = tran; 3659 uu_list_insert(tran->tran_props, entry, idx); 3660 3661 (void) pthread_mutex_unlock(&h->rh_lock); 3662 3663 HANDLE_RELE_PROPERTY(h); 3664 3665 return (SCF_SUCCESS); 3666 3667 error: 3668 (void) pthread_mutex_unlock(&h->rh_lock); 3669 3670 HANDLE_RELE_PROPERTY(h); 3671 3672 return (scf_set_error(error)); 3673 } 3674 3675 int 3676 scf_transaction_property_new(scf_transaction_t *tx, 3677 scf_transaction_entry_t *entry, const char *prop, scf_type_t type) 3678 { 3679 return (transaction_add(tx, entry, REP_PROTOCOL_TX_ENTRY_NEW, 3680 prop, scf_type_to_protocol_type(type))); 3681 } 3682 3683 int 3684 scf_transaction_property_change(scf_transaction_t *tx, 3685 scf_transaction_entry_t *entry, const char *prop, scf_type_t type) 3686 { 3687 return (transaction_add(tx, entry, REP_PROTOCOL_TX_ENTRY_CLEAR, 3688 prop, scf_type_to_protocol_type(type))); 3689 } 3690 3691 int 3692 scf_transaction_property_change_type(scf_transaction_t *tx, 3693 scf_transaction_entry_t *entry, const char *prop, scf_type_t type) 3694 { 3695 return (transaction_add(tx, entry, REP_PROTOCOL_TX_ENTRY_REPLACE, 3696 prop, scf_type_to_protocol_type(type))); 3697 } 3698 3699 int 3700 scf_transaction_property_delete(scf_transaction_t *tx, 3701 scf_transaction_entry_t *entry, const char *prop) 3702 { 3703 return (transaction_add(tx, entry, REP_PROTOCOL_TX_ENTRY_DELETE, 3704 prop, REP_PROTOCOL_TYPE_INVALID)); 3705 } 3706 3707 #define BAD_SIZE (-1UL) 3708 3709 static size_t 3710 commit_value(caddr_t data, scf_value_t *val, rep_protocol_value_type_t t) 3711 { 3712 size_t len; 3713 3714 assert(val->value_type == t); 3715 3716 if (t == REP_PROTOCOL_TYPE_OPAQUE) { 3717 len = scf_opaque_encode(data, val->value_value, 3718 val->value_size); 3719 } else { 3720 if (data != NULL) 3721 len = strlcpy(data, val->value_value, 3722 REP_PROTOCOL_VALUE_LEN); 3723 else 3724 len = strlen(val->value_value); 3725 if (len >= REP_PROTOCOL_VALUE_LEN) 3726 return (BAD_SIZE); 3727 } 3728 return (len + 1); /* count the '\0' */ 3729 } 3730 3731 static size_t 3732 commit_process(scf_transaction_entry_t *cur, 3733 struct rep_protocol_transaction_cmd *out) 3734 { 3735 scf_value_t *child; 3736 size_t sz = 0; 3737 size_t len; 3738 caddr_t data = (caddr_t)out->rptc_data; 3739 caddr_t val_data; 3740 3741 if (out != NULL) { 3742 len = strlcpy(data, cur->entry_property, REP_PROTOCOL_NAME_LEN); 3743 3744 out->rptc_action = cur->entry_action; 3745 out->rptc_type = cur->entry_type; 3746 out->rptc_name_len = len + 1; 3747 } else { 3748 len = strlen(cur->entry_property); 3749 } 3750 3751 if (len >= REP_PROTOCOL_NAME_LEN) 3752 return (BAD_SIZE); 3753 3754 len = TX_SIZE(len + 1); 3755 3756 sz += len; 3757 val_data = data + len; 3758 3759 for (child = cur->entry_head; child != NULL; 3760 child = child->value_next) { 3761 assert(cur->entry_action != REP_PROTOCOL_TX_ENTRY_DELETE); 3762 if (out != NULL) { 3763 len = commit_value(val_data + sizeof (uint32_t), child, 3764 cur->entry_type); 3765 /* LINTED alignment */ 3766 *(uint32_t *)val_data = len; 3767 } else 3768 len = commit_value(NULL, child, cur->entry_type); 3769 3770 if (len == BAD_SIZE) 3771 return (BAD_SIZE); 3772 3773 len += sizeof (uint32_t); 3774 len = TX_SIZE(len); 3775 3776 sz += len; 3777 val_data += len; 3778 } 3779 3780 assert(val_data - data == sz); 3781 3782 if (out != NULL) 3783 out->rptc_size = REP_PROTOCOL_TRANSACTION_CMD_SIZE(sz); 3784 3785 return (REP_PROTOCOL_TRANSACTION_CMD_SIZE(sz)); 3786 } 3787 3788 int 3789 scf_transaction_commit(scf_transaction_t *tran) 3790 { 3791 scf_handle_t *h = tran->tran_pg.rd_d.rd_handle; 3792 3793 struct rep_protocol_transaction_commit *request; 3794 struct rep_protocol_response response; 3795 uintptr_t cmd; 3796 scf_transaction_entry_t *cur; 3797 size_t total, size; 3798 size_t request_size; 3799 size_t new_total; 3800 int r; 3801 3802 (void) pthread_mutex_lock(&h->rh_lock); 3803 if (tran->tran_state != TRAN_STATE_SETUP || 3804 tran->tran_invalid) { 3805 (void) pthread_mutex_unlock(&h->rh_lock); 3806 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 3807 } 3808 3809 total = 0; 3810 for (cur = uu_list_first(tran->tran_props); cur != NULL; 3811 cur = uu_list_next(tran->tran_props, cur)) { 3812 size = commit_process(cur, NULL); 3813 if (size == BAD_SIZE) { 3814 (void) pthread_mutex_unlock(&h->rh_lock); 3815 return (scf_set_error(SCF_ERROR_INTERNAL)); 3816 } 3817 assert(TX_SIZE(size) == size); 3818 total += size; 3819 } 3820 3821 request_size = REP_PROTOCOL_TRANSACTION_COMMIT_SIZE(total); 3822 request = alloca(request_size); 3823 (void) memset(request, '\0', request_size); 3824 request->rpr_request = REP_PROTOCOL_PROPERTYGRP_TX_COMMIT; 3825 request->rpr_entityid = tran->tran_pg.rd_d.rd_entity; 3826 request->rpr_size = request_size; 3827 cmd = (uintptr_t)request->rpr_cmd; 3828 3829 datael_finish_reset(&tran->tran_pg.rd_d); 3830 3831 new_total = 0; 3832 for (cur = uu_list_first(tran->tran_props); cur != NULL; 3833 cur = uu_list_next(tran->tran_props, cur)) { 3834 size = commit_process(cur, (void *)cmd); 3835 if (size == BAD_SIZE) { 3836 (void) pthread_mutex_unlock(&h->rh_lock); 3837 return (scf_set_error(SCF_ERROR_INTERNAL)); 3838 } 3839 cmd += size; 3840 new_total += size; 3841 } 3842 assert(new_total == total); 3843 3844 r = make_door_call(h, request, request_size, 3845 &response, sizeof (response)); 3846 3847 if (r < 0) { 3848 (void) pthread_mutex_unlock(&h->rh_lock); 3849 DOOR_ERRORS_BLOCK(r); 3850 } 3851 3852 if (response.rpr_response != REP_PROTOCOL_SUCCESS && 3853 response.rpr_response != REP_PROTOCOL_FAIL_NOT_LATEST) { 3854 (void) pthread_mutex_unlock(&h->rh_lock); 3855 return (scf_set_error(proto_error(response.rpr_response))); 3856 } 3857 3858 tran->tran_state = TRAN_STATE_COMMITTED; 3859 (void) pthread_mutex_unlock(&h->rh_lock); 3860 return (response.rpr_response == REP_PROTOCOL_SUCCESS); 3861 } 3862 3863 static void 3864 transaction_reset(scf_transaction_t *tran) 3865 { 3866 assert(MUTEX_HELD(&tran->tran_pg.rd_d.rd_handle->rh_lock)); 3867 3868 tran->tran_state = TRAN_STATE_NEW; 3869 datael_reset_locked(&tran->tran_pg.rd_d); 3870 } 3871 3872 static void 3873 scf_transaction_reset_impl(scf_transaction_t *tran, int and_destroy, 3874 int and_reset_value) 3875 { 3876 scf_transaction_entry_t *cur; 3877 void *cookie; 3878 3879 (void) pthread_mutex_lock(&tran->tran_pg.rd_d.rd_handle->rh_lock); 3880 cookie = NULL; 3881 while ((cur = uu_list_teardown(tran->tran_props, &cookie)) != NULL) { 3882 cur->entry_tx = NULL; 3883 3884 assert(cur->entry_state == ENTRY_STATE_IN_TX_ACTION); 3885 cur->entry_state = ENTRY_STATE_INVALID; 3886 3887 entry_invalidate(cur, and_destroy, and_reset_value); 3888 if (and_destroy) 3889 entry_destroy_locked(cur); 3890 } 3891 transaction_reset(tran); 3892 handle_unrefed(tran->tran_pg.rd_d.rd_handle); 3893 } 3894 3895 void 3896 scf_transaction_reset(scf_transaction_t *tran) 3897 { 3898 scf_transaction_reset_impl(tran, 0, 0); 3899 } 3900 3901 void 3902 scf_transaction_reset_all(scf_transaction_t *tran) 3903 { 3904 scf_transaction_reset_impl(tran, 0, 1); 3905 } 3906 3907 void 3908 scf_transaction_destroy(scf_transaction_t *val) 3909 { 3910 if (val == NULL) 3911 return; 3912 3913 scf_transaction_reset(val); 3914 3915 datael_destroy(&val->tran_pg.rd_d); 3916 3917 uu_list_destroy(val->tran_props); 3918 uu_free(val); 3919 } 3920 3921 void 3922 scf_transaction_destroy_children(scf_transaction_t *tran) 3923 { 3924 scf_transaction_reset_impl(tran, 1, 0); 3925 } 3926 3927 scf_transaction_entry_t * 3928 scf_entry_create(scf_handle_t *h) 3929 { 3930 scf_transaction_entry_t *ret; 3931 3932 if (h == NULL) { 3933 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 3934 return (NULL); 3935 } 3936 3937 ret = uu_zalloc(sizeof (scf_transaction_entry_t)); 3938 if (ret == NULL) { 3939 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 3940 return (NULL); 3941 } 3942 ret->entry_action = REP_PROTOCOL_TX_ENTRY_INVALID; 3943 ret->entry_handle = h; 3944 3945 (void) pthread_mutex_lock(&h->rh_lock); 3946 if (h->rh_flags & HANDLE_DEAD) { 3947 (void) pthread_mutex_unlock(&h->rh_lock); 3948 uu_free(ret); 3949 (void) scf_set_error(SCF_ERROR_HANDLE_DESTROYED); 3950 return (NULL); 3951 } 3952 h->rh_entries++; 3953 h->rh_extrefs++; 3954 (void) pthread_mutex_unlock(&h->rh_lock); 3955 3956 uu_list_node_init(ret, &ret->entry_link, tran_entry_pool); 3957 3958 return (ret); 3959 } 3960 3961 scf_handle_t * 3962 scf_entry_handle(const scf_transaction_entry_t *val) 3963 { 3964 return (handle_get(val->entry_handle)); 3965 } 3966 3967 void 3968 scf_entry_reset(scf_transaction_entry_t *entry) 3969 { 3970 scf_handle_t *h = entry->entry_handle; 3971 3972 (void) pthread_mutex_lock(&h->rh_lock); 3973 entry_invalidate(entry, 0, 0); 3974 (void) pthread_mutex_unlock(&h->rh_lock); 3975 } 3976 3977 void 3978 scf_entry_destroy_children(scf_transaction_entry_t *entry) 3979 { 3980 scf_handle_t *h = entry->entry_handle; 3981 3982 (void) pthread_mutex_lock(&h->rh_lock); 3983 entry_invalidate(entry, 1, 0); 3984 handle_unrefed(h); /* drops h->rh_lock */ 3985 } 3986 3987 void 3988 scf_entry_destroy(scf_transaction_entry_t *entry) 3989 { 3990 scf_handle_t *h; 3991 3992 if (entry == NULL) 3993 return; 3994 3995 h = entry->entry_handle; 3996 3997 (void) pthread_mutex_lock(&h->rh_lock); 3998 entry_destroy_locked(entry); 3999 handle_unrefed(h); /* drops h->rh_lock */ 4000 } 4001 4002 /* 4003 * Fails with 4004 * _HANDLE_MISMATCH 4005 * _NOT_SET - has not been added to a transaction 4006 * _INTERNAL - entry is corrupt 4007 * _INVALID_ARGUMENT - entry's transaction is not started or corrupt 4008 * entry is set to delete a property 4009 * v is reset or corrupt 4010 * _TYPE_MISMATCH - entry & v's types aren't compatible 4011 * _IN_USE - v has been added to another entry 4012 */ 4013 int 4014 scf_entry_add_value(scf_transaction_entry_t *entry, scf_value_t *v) 4015 { 4016 scf_handle_t *h = entry->entry_handle; 4017 4018 if (h != v->value_handle) 4019 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH)); 4020 4021 (void) pthread_mutex_lock(&h->rh_lock); 4022 4023 if (entry->entry_state == ENTRY_STATE_INVALID) { 4024 (void) pthread_mutex_unlock(&h->rh_lock); 4025 return (scf_set_error(SCF_ERROR_NOT_SET)); 4026 } 4027 4028 if (entry->entry_state != ENTRY_STATE_IN_TX_ACTION) { 4029 (void) pthread_mutex_unlock(&h->rh_lock); 4030 return (scf_set_error(SCF_ERROR_INTERNAL)); 4031 } 4032 4033 if (entry->entry_tx->tran_state != TRAN_STATE_SETUP) { 4034 (void) pthread_mutex_unlock(&h->rh_lock); 4035 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 4036 } 4037 4038 if (entry->entry_action == REP_PROTOCOL_TX_ENTRY_DELETE) { 4039 (void) pthread_mutex_unlock(&h->rh_lock); 4040 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 4041 } 4042 4043 if (v->value_type == REP_PROTOCOL_TYPE_INVALID) { 4044 (void) pthread_mutex_unlock(&h->rh_lock); 4045 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 4046 } 4047 4048 if (!scf_is_compatible_type(entry->entry_type, v->value_type)) { 4049 (void) pthread_mutex_unlock(&h->rh_lock); 4050 return (scf_set_error(SCF_ERROR_TYPE_MISMATCH)); 4051 } 4052 4053 if (v->value_tx != NULL) { 4054 (void) pthread_mutex_unlock(&h->rh_lock); 4055 return (scf_set_error(SCF_ERROR_IN_USE)); 4056 } 4057 4058 v->value_tx = entry; 4059 v->value_next = entry->entry_head; 4060 entry->entry_head = v; 4061 (void) pthread_mutex_unlock(&h->rh_lock); 4062 4063 return (SCF_SUCCESS); 4064 } 4065 4066 /* 4067 * value functions 4068 */ 4069 scf_value_t * 4070 scf_value_create(scf_handle_t *h) 4071 { 4072 scf_value_t *ret; 4073 4074 if (h == NULL) { 4075 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 4076 return (NULL); 4077 } 4078 4079 ret = uu_zalloc(sizeof (*ret)); 4080 if (ret != NULL) { 4081 ret->value_type = REP_PROTOCOL_TYPE_INVALID; 4082 ret->value_handle = h; 4083 (void) pthread_mutex_lock(&h->rh_lock); 4084 if (h->rh_flags & HANDLE_DEAD) { 4085 (void) pthread_mutex_unlock(&h->rh_lock); 4086 uu_free(ret); 4087 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 4088 return (NULL); 4089 } 4090 h->rh_values++; 4091 h->rh_extrefs++; 4092 (void) pthread_mutex_unlock(&h->rh_lock); 4093 } else { 4094 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 4095 } 4096 4097 return (ret); 4098 } 4099 4100 static void 4101 scf_value_reset_locked(scf_value_t *val, int and_destroy) 4102 { 4103 scf_value_t **curp; 4104 scf_transaction_entry_t *te; 4105 4106 scf_handle_t *h = val->value_handle; 4107 assert(MUTEX_HELD(&h->rh_lock)); 4108 if (val->value_tx != NULL) { 4109 te = val->value_tx; 4110 te->entry_tx->tran_invalid = 1; 4111 4112 val->value_tx = NULL; 4113 4114 for (curp = &te->entry_head; *curp != NULL; 4115 curp = &(*curp)->value_next) { 4116 if (*curp == val) { 4117 *curp = val->value_next; 4118 curp = NULL; 4119 break; 4120 } 4121 } 4122 assert(curp == NULL); 4123 } 4124 val->value_type = REP_PROTOCOL_TYPE_INVALID; 4125 4126 if (and_destroy) { 4127 val->value_handle = NULL; 4128 assert(h->rh_values > 0); 4129 --h->rh_values; 4130 --h->rh_extrefs; 4131 uu_free(val); 4132 } 4133 } 4134 4135 void 4136 scf_value_reset(scf_value_t *val) 4137 { 4138 scf_handle_t *h = val->value_handle; 4139 4140 (void) pthread_mutex_lock(&h->rh_lock); 4141 scf_value_reset_locked(val, 0); 4142 (void) pthread_mutex_unlock(&h->rh_lock); 4143 } 4144 4145 scf_handle_t * 4146 scf_value_handle(const scf_value_t *val) 4147 { 4148 return (handle_get(val->value_handle)); 4149 } 4150 4151 void 4152 scf_value_destroy(scf_value_t *val) 4153 { 4154 scf_handle_t *h; 4155 4156 if (val == NULL) 4157 return; 4158 4159 h = val->value_handle; 4160 4161 (void) pthread_mutex_lock(&h->rh_lock); 4162 scf_value_reset_locked(val, 1); 4163 handle_unrefed(h); /* drops h->rh_lock */ 4164 } 4165 4166 scf_type_t 4167 scf_value_base_type(const scf_value_t *val) 4168 { 4169 rep_protocol_value_type_t t, cur; 4170 scf_handle_t *h = val->value_handle; 4171 4172 (void) pthread_mutex_lock(&h->rh_lock); 4173 t = val->value_type; 4174 (void) pthread_mutex_unlock(&h->rh_lock); 4175 4176 for (;;) { 4177 cur = scf_proto_underlying_type(t); 4178 if (cur == t) 4179 break; 4180 t = cur; 4181 } 4182 4183 return (scf_protocol_type_to_type(t)); 4184 } 4185 4186 scf_type_t 4187 scf_value_type(const scf_value_t *val) 4188 { 4189 rep_protocol_value_type_t t; 4190 scf_handle_t *h = val->value_handle; 4191 4192 (void) pthread_mutex_lock(&h->rh_lock); 4193 t = val->value_type; 4194 (void) pthread_mutex_unlock(&h->rh_lock); 4195 4196 return (scf_protocol_type_to_type(t)); 4197 } 4198 4199 int 4200 scf_value_is_type(const scf_value_t *val, scf_type_t base_arg) 4201 { 4202 rep_protocol_value_type_t t; 4203 rep_protocol_value_type_t base = scf_type_to_protocol_type(base_arg); 4204 scf_handle_t *h = val->value_handle; 4205 4206 (void) pthread_mutex_lock(&h->rh_lock); 4207 t = val->value_type; 4208 (void) pthread_mutex_unlock(&h->rh_lock); 4209 4210 if (t == REP_PROTOCOL_TYPE_INVALID) 4211 return (scf_set_error(SCF_ERROR_NOT_SET)); 4212 if (base == REP_PROTOCOL_TYPE_INVALID) 4213 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 4214 if (!scf_is_compatible_type(base, t)) 4215 return (scf_set_error(SCF_ERROR_TYPE_MISMATCH)); 4216 4217 return (SCF_SUCCESS); 4218 } 4219 4220 /* 4221 * Fails with 4222 * _NOT_SET - val is reset 4223 * _TYPE_MISMATCH - val's type is not compatible with t 4224 */ 4225 static int 4226 scf_value_check_type(const scf_value_t *val, rep_protocol_value_type_t t) 4227 { 4228 if (val->value_type == REP_PROTOCOL_TYPE_INVALID) { 4229 (void) scf_set_error(SCF_ERROR_NOT_SET); 4230 return (0); 4231 } 4232 if (!scf_is_compatible_type(t, val->value_type)) { 4233 (void) scf_set_error(SCF_ERROR_TYPE_MISMATCH); 4234 return (0); 4235 } 4236 return (1); 4237 } 4238 4239 /* 4240 * Fails with 4241 * _NOT_SET - val is reset 4242 * _TYPE_MISMATCH - val is not _TYPE_BOOLEAN 4243 */ 4244 int 4245 scf_value_get_boolean(const scf_value_t *val, uint8_t *out) 4246 { 4247 char c; 4248 scf_handle_t *h = val->value_handle; 4249 uint8_t o; 4250 4251 (void) pthread_mutex_lock(&h->rh_lock); 4252 if (!scf_value_check_type(val, REP_PROTOCOL_TYPE_BOOLEAN)) { 4253 (void) pthread_mutex_unlock(&h->rh_lock); 4254 return (-1); 4255 } 4256 4257 c = val->value_value[0]; 4258 assert((c == '0' || c == '1') && val->value_value[1] == 0); 4259 4260 o = (c != '0'); 4261 (void) pthread_mutex_unlock(&h->rh_lock); 4262 if (out != NULL) 4263 *out = o; 4264 return (SCF_SUCCESS); 4265 } 4266 4267 int 4268 scf_value_get_count(const scf_value_t *val, uint64_t *out) 4269 { 4270 scf_handle_t *h = val->value_handle; 4271 uint64_t o; 4272 4273 (void) pthread_mutex_lock(&h->rh_lock); 4274 if (!scf_value_check_type(val, REP_PROTOCOL_TYPE_COUNT)) { 4275 (void) pthread_mutex_unlock(&h->rh_lock); 4276 return (-1); 4277 } 4278 4279 o = strtoull(val->value_value, NULL, 10); 4280 (void) pthread_mutex_unlock(&h->rh_lock); 4281 if (out != NULL) 4282 *out = o; 4283 return (SCF_SUCCESS); 4284 } 4285 4286 int 4287 scf_value_get_integer(const scf_value_t *val, int64_t *out) 4288 { 4289 scf_handle_t *h = val->value_handle; 4290 int64_t o; 4291 4292 (void) pthread_mutex_lock(&h->rh_lock); 4293 if (!scf_value_check_type(val, REP_PROTOCOL_TYPE_INTEGER)) { 4294 (void) pthread_mutex_unlock(&h->rh_lock); 4295 return (-1); 4296 } 4297 4298 o = strtoll(val->value_value, NULL, 10); 4299 (void) pthread_mutex_unlock(&h->rh_lock); 4300 if (out != NULL) 4301 *out = o; 4302 return (SCF_SUCCESS); 4303 } 4304 4305 int 4306 scf_value_get_time(const scf_value_t *val, int64_t *sec_out, int32_t *nsec_out) 4307 { 4308 scf_handle_t *h = val->value_handle; 4309 char *p; 4310 int64_t os; 4311 int32_t ons; 4312 4313 (void) pthread_mutex_lock(&h->rh_lock); 4314 if (!scf_value_check_type(val, REP_PROTOCOL_TYPE_TIME)) { 4315 (void) pthread_mutex_unlock(&h->rh_lock); 4316 return (-1); 4317 } 4318 4319 os = strtoll(val->value_value, &p, 10); 4320 if (*p == '.') 4321 ons = strtoul(p + 1, NULL, 10); 4322 else 4323 ons = 0; 4324 (void) pthread_mutex_unlock(&h->rh_lock); 4325 if (sec_out != NULL) 4326 *sec_out = os; 4327 if (nsec_out != NULL) 4328 *nsec_out = ons; 4329 4330 return (SCF_SUCCESS); 4331 } 4332 4333 /* 4334 * Fails with 4335 * _NOT_SET - val is reset 4336 * _TYPE_MISMATCH - val's type is not compatible with _TYPE_STRING. 4337 */ 4338 ssize_t 4339 scf_value_get_astring(const scf_value_t *val, char *out, size_t len) 4340 { 4341 ssize_t ret; 4342 scf_handle_t *h = val->value_handle; 4343 4344 (void) pthread_mutex_lock(&h->rh_lock); 4345 if (!scf_value_check_type(val, REP_PROTOCOL_TYPE_STRING)) { 4346 (void) pthread_mutex_unlock(&h->rh_lock); 4347 return ((ssize_t)-1); 4348 } 4349 ret = (ssize_t)strlcpy(out, val->value_value, len); 4350 (void) pthread_mutex_unlock(&h->rh_lock); 4351 return (ret); 4352 } 4353 4354 ssize_t 4355 scf_value_get_ustring(const scf_value_t *val, char *out, size_t len) 4356 { 4357 ssize_t ret; 4358 scf_handle_t *h = val->value_handle; 4359 4360 (void) pthread_mutex_lock(&h->rh_lock); 4361 if (!scf_value_check_type(val, REP_PROTOCOL_SUBTYPE_USTRING)) { 4362 (void) pthread_mutex_unlock(&h->rh_lock); 4363 return ((ssize_t)-1); 4364 } 4365 ret = (ssize_t)strlcpy(out, val->value_value, len); 4366 (void) pthread_mutex_unlock(&h->rh_lock); 4367 return (ret); 4368 } 4369 4370 ssize_t 4371 scf_value_get_opaque(const scf_value_t *v, void *out, size_t len) 4372 { 4373 ssize_t ret; 4374 scf_handle_t *h = v->value_handle; 4375 4376 (void) pthread_mutex_lock(&h->rh_lock); 4377 if (!scf_value_check_type(v, REP_PROTOCOL_TYPE_OPAQUE)) { 4378 (void) pthread_mutex_unlock(&h->rh_lock); 4379 return ((ssize_t)-1); 4380 } 4381 if (len > v->value_size) 4382 len = v->value_size; 4383 ret = len; 4384 4385 (void) memcpy(out, v->value_value, len); 4386 (void) pthread_mutex_unlock(&h->rh_lock); 4387 return (ret); 4388 } 4389 4390 void 4391 scf_value_set_boolean(scf_value_t *v, uint8_t new) 4392 { 4393 scf_handle_t *h = v->value_handle; 4394 4395 (void) pthread_mutex_lock(&h->rh_lock); 4396 scf_value_reset_locked(v, 0); 4397 v->value_type = REP_PROTOCOL_TYPE_BOOLEAN; 4398 (void) sprintf(v->value_value, "%d", (new != 0)); 4399 (void) pthread_mutex_unlock(&h->rh_lock); 4400 } 4401 4402 void 4403 scf_value_set_count(scf_value_t *v, uint64_t new) 4404 { 4405 scf_handle_t *h = v->value_handle; 4406 4407 (void) pthread_mutex_lock(&h->rh_lock); 4408 scf_value_reset_locked(v, 0); 4409 v->value_type = REP_PROTOCOL_TYPE_COUNT; 4410 (void) sprintf(v->value_value, "%llu", (unsigned long long)new); 4411 (void) pthread_mutex_unlock(&h->rh_lock); 4412 } 4413 4414 void 4415 scf_value_set_integer(scf_value_t *v, int64_t new) 4416 { 4417 scf_handle_t *h = v->value_handle; 4418 4419 (void) pthread_mutex_lock(&h->rh_lock); 4420 scf_value_reset_locked(v, 0); 4421 v->value_type = REP_PROTOCOL_TYPE_INTEGER; 4422 (void) sprintf(v->value_value, "%lld", (long long)new); 4423 (void) pthread_mutex_unlock(&h->rh_lock); 4424 } 4425 4426 int 4427 scf_value_set_time(scf_value_t *v, int64_t new_sec, int32_t new_nsec) 4428 { 4429 scf_handle_t *h = v->value_handle; 4430 4431 (void) pthread_mutex_lock(&h->rh_lock); 4432 scf_value_reset_locked(v, 0); 4433 if (new_nsec < 0 || new_nsec >= NANOSEC) { 4434 (void) pthread_mutex_unlock(&h->rh_lock); 4435 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 4436 } 4437 v->value_type = REP_PROTOCOL_TYPE_TIME; 4438 if (new_nsec == 0) 4439 (void) sprintf(v->value_value, "%lld", (long long)new_sec); 4440 else 4441 (void) sprintf(v->value_value, "%lld.%09u", (long long)new_sec, 4442 (unsigned)new_nsec); 4443 (void) pthread_mutex_unlock(&h->rh_lock); 4444 return (0); 4445 } 4446 4447 int 4448 scf_value_set_astring(scf_value_t *v, const char *new) 4449 { 4450 scf_handle_t *h = v->value_handle; 4451 4452 (void) pthread_mutex_lock(&h->rh_lock); 4453 scf_value_reset_locked(v, 0); 4454 if (!scf_validate_encoded_value(REP_PROTOCOL_TYPE_STRING, new)) { 4455 (void) pthread_mutex_unlock(&h->rh_lock); 4456 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 4457 } 4458 if (strlcpy(v->value_value, new, sizeof (v->value_value)) >= 4459 sizeof (v->value_value)) { 4460 (void) pthread_mutex_unlock(&h->rh_lock); 4461 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 4462 } 4463 v->value_type = REP_PROTOCOL_TYPE_STRING; 4464 (void) pthread_mutex_unlock(&h->rh_lock); 4465 return (0); 4466 } 4467 4468 int 4469 scf_value_set_ustring(scf_value_t *v, const char *new) 4470 { 4471 scf_handle_t *h = v->value_handle; 4472 4473 (void) pthread_mutex_lock(&h->rh_lock); 4474 scf_value_reset_locked(v, 0); 4475 if (!scf_validate_encoded_value(REP_PROTOCOL_SUBTYPE_USTRING, new)) { 4476 (void) pthread_mutex_unlock(&h->rh_lock); 4477 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 4478 } 4479 if (strlcpy(v->value_value, new, sizeof (v->value_value)) >= 4480 sizeof (v->value_value)) { 4481 (void) pthread_mutex_unlock(&h->rh_lock); 4482 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 4483 } 4484 v->value_type = REP_PROTOCOL_SUBTYPE_USTRING; 4485 (void) pthread_mutex_unlock(&h->rh_lock); 4486 return (0); 4487 } 4488 4489 int 4490 scf_value_set_opaque(scf_value_t *v, const void *new, size_t len) 4491 { 4492 scf_handle_t *h = v->value_handle; 4493 4494 (void) pthread_mutex_lock(&h->rh_lock); 4495 scf_value_reset_locked(v, 0); 4496 if (len > sizeof (v->value_value)) { 4497 (void) pthread_mutex_unlock(&h->rh_lock); 4498 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 4499 } 4500 (void) memcpy(v->value_value, new, len); 4501 v->value_size = len; 4502 v->value_type = REP_PROTOCOL_TYPE_OPAQUE; 4503 (void) pthread_mutex_unlock(&h->rh_lock); 4504 return (0); 4505 } 4506 4507 /* 4508 * Fails with 4509 * _NOT_SET - v_arg is reset 4510 * _INTERNAL - v_arg is corrupt 4511 * 4512 * If t is not _TYPE_INVALID, fails with 4513 * _TYPE_MISMATCH - v_arg's type is not compatible with t 4514 */ 4515 static ssize_t 4516 scf_value_get_as_string_common(const scf_value_t *v_arg, 4517 rep_protocol_value_type_t t, char *buf, size_t bufsz) 4518 { 4519 scf_handle_t *h = v_arg->value_handle; 4520 scf_value_t v_s; 4521 scf_value_t *v = &v_s; 4522 ssize_t r; 4523 uint8_t b; 4524 4525 (void) pthread_mutex_lock(&h->rh_lock); 4526 if (t != REP_PROTOCOL_TYPE_INVALID && !scf_value_check_type(v_arg, t)) { 4527 (void) pthread_mutex_unlock(&h->rh_lock); 4528 return (-1); 4529 } 4530 4531 v_s = *v_arg; /* copy locally so we can unlock */ 4532 h->rh_values++; /* keep the handle from going away */ 4533 h->rh_extrefs++; 4534 (void) pthread_mutex_unlock(&h->rh_lock); 4535 4536 4537 switch (REP_PROTOCOL_BASE_TYPE(v->value_type)) { 4538 case REP_PROTOCOL_TYPE_BOOLEAN: 4539 r = scf_value_get_boolean(v, &b); 4540 assert(r == SCF_SUCCESS); 4541 4542 r = strlcpy(buf, b ? "true" : "false", bufsz); 4543 break; 4544 4545 case REP_PROTOCOL_TYPE_COUNT: 4546 case REP_PROTOCOL_TYPE_INTEGER: 4547 case REP_PROTOCOL_TYPE_TIME: 4548 case REP_PROTOCOL_TYPE_STRING: 4549 r = strlcpy(buf, v->value_value, bufsz); 4550 break; 4551 4552 case REP_PROTOCOL_TYPE_OPAQUE: 4553 /* 4554 * Note that we only write out full hex bytes -- if they're 4555 * short, and bufsz is even, we'll only fill (bufsz - 2) bytes 4556 * with data. 4557 */ 4558 if (bufsz > 0) 4559 (void) scf_opaque_encode(buf, v->value_value, 4560 MIN(v->value_size, (bufsz - 1)/2)); 4561 r = (v->value_size * 2); 4562 break; 4563 4564 case REP_PROTOCOL_TYPE_INVALID: 4565 r = scf_set_error(SCF_ERROR_NOT_SET); 4566 break; 4567 4568 default: 4569 r = (scf_set_error(SCF_ERROR_INTERNAL)); 4570 break; 4571 } 4572 4573 (void) pthread_mutex_lock(&h->rh_lock); 4574 h->rh_values--; 4575 h->rh_extrefs--; 4576 handle_unrefed(h); 4577 4578 return (r); 4579 } 4580 4581 ssize_t 4582 scf_value_get_as_string(const scf_value_t *v, char *buf, size_t bufsz) 4583 { 4584 return (scf_value_get_as_string_common(v, REP_PROTOCOL_TYPE_INVALID, 4585 buf, bufsz)); 4586 } 4587 4588 ssize_t 4589 scf_value_get_as_string_typed(const scf_value_t *v, scf_type_t type, 4590 char *buf, size_t bufsz) 4591 { 4592 rep_protocol_value_type_t ty = scf_type_to_protocol_type(type); 4593 if (ty == REP_PROTOCOL_TYPE_INVALID) 4594 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 4595 4596 return (scf_value_get_as_string_common(v, ty, buf, bufsz)); 4597 } 4598 4599 int 4600 scf_value_set_from_string(scf_value_t *v, scf_type_t type, const char *str) 4601 { 4602 scf_handle_t *h = v->value_handle; 4603 rep_protocol_value_type_t ty; 4604 4605 switch (type) { 4606 case SCF_TYPE_BOOLEAN: { 4607 uint8_t b; 4608 4609 if (strcmp(str, "true") == 0 || strcmp(str, "t") == 0 || 4610 strcmp(str, "1") == 0) 4611 b = 1; 4612 else if (strcmp(str, "false") == 0 || 4613 strcmp(str, "f") == 0 || strcmp(str, "0") == 0) 4614 b = 0; 4615 else { 4616 goto bad; 4617 } 4618 4619 scf_value_set_boolean(v, b); 4620 return (0); 4621 } 4622 4623 case SCF_TYPE_COUNT: { 4624 uint64_t c; 4625 char *endp; 4626 4627 errno = 0; 4628 c = strtoull(str, &endp, 0); 4629 4630 if (errno != 0 || endp == str || *endp != '\0') 4631 goto bad; 4632 4633 scf_value_set_count(v, c); 4634 return (0); 4635 } 4636 4637 case SCF_TYPE_INTEGER: { 4638 int64_t i; 4639 char *endp; 4640 4641 errno = 0; 4642 i = strtoll(str, &endp, 0); 4643 4644 if (errno != 0 || endp == str || *endp != '\0') 4645 goto bad; 4646 4647 scf_value_set_integer(v, i); 4648 return (0); 4649 } 4650 4651 case SCF_TYPE_TIME: { 4652 int64_t s; 4653 uint32_t ns = 0; 4654 char *endp, *ns_str; 4655 size_t len; 4656 4657 errno = 0; 4658 s = strtoll(str, &endp, 10); 4659 if (errno != 0 || endp == str || 4660 (*endp != '\0' && *endp != '.')) 4661 goto bad; 4662 4663 if (*endp == '.') { 4664 ns_str = endp + 1; 4665 len = strlen(ns_str); 4666 if (len == 0 || len > 9) 4667 goto bad; 4668 4669 ns = strtoul(ns_str, &endp, 10); 4670 if (errno != 0 || endp == ns_str || *endp != '\0') 4671 goto bad; 4672 4673 while (len++ < 9) 4674 ns *= 10; 4675 assert(ns < NANOSEC); 4676 } 4677 4678 return (scf_value_set_time(v, s, ns)); 4679 } 4680 4681 case SCF_TYPE_ASTRING: 4682 case SCF_TYPE_USTRING: 4683 case SCF_TYPE_OPAQUE: 4684 case SCF_TYPE_URI: 4685 case SCF_TYPE_FMRI: 4686 case SCF_TYPE_HOST: 4687 case SCF_TYPE_HOSTNAME: 4688 case SCF_TYPE_NET_ADDR_V4: 4689 case SCF_TYPE_NET_ADDR_V6: 4690 ty = scf_type_to_protocol_type(type); 4691 4692 (void) pthread_mutex_lock(&h->rh_lock); 4693 scf_value_reset_locked(v, 0); 4694 if (type == SCF_TYPE_OPAQUE) { 4695 v->value_size = scf_opaque_decode(v->value_value, 4696 str, sizeof (v->value_value)); 4697 if (!scf_validate_encoded_value(ty, str)) { 4698 (void) pthread_mutex_lock(&h->rh_lock); 4699 goto bad; 4700 } 4701 } else { 4702 (void) strlcpy(v->value_value, str, 4703 sizeof (v->value_value)); 4704 if (!scf_validate_encoded_value(ty, v->value_value)) { 4705 (void) pthread_mutex_lock(&h->rh_lock); 4706 goto bad; 4707 } 4708 } 4709 v->value_type = ty; 4710 (void) pthread_mutex_unlock(&h->rh_lock); 4711 return (SCF_SUCCESS); 4712 4713 case REP_PROTOCOL_TYPE_INVALID: 4714 default: 4715 scf_value_reset(v); 4716 return (scf_set_error(SCF_ERROR_TYPE_MISMATCH)); 4717 } 4718 bad: 4719 scf_value_reset(v); 4720 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 4721 } 4722 4723 int 4724 scf_iter_property_values(scf_iter_t *iter, const scf_property_t *prop) 4725 { 4726 return (datael_setup_iter(iter, &prop->rd_d, 4727 REP_PROTOCOL_ENTITY_VALUE, 0)); 4728 } 4729 4730 int 4731 scf_iter_next_value(scf_iter_t *iter, scf_value_t *v) 4732 { 4733 scf_handle_t *h = iter->iter_handle; 4734 4735 struct rep_protocol_iter_read_value request; 4736 struct rep_protocol_value_response response; 4737 4738 int r; 4739 4740 if (h != v->value_handle) 4741 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH)); 4742 4743 (void) pthread_mutex_lock(&h->rh_lock); 4744 4745 scf_value_reset_locked(v, 0); 4746 4747 if (iter->iter_type == REP_PROTOCOL_ENTITY_NONE) { 4748 (void) pthread_mutex_unlock(&h->rh_lock); 4749 return (scf_set_error(SCF_ERROR_NOT_SET)); 4750 } 4751 4752 if (iter->iter_type != REP_PROTOCOL_ENTITY_VALUE) { 4753 (void) pthread_mutex_unlock(&h->rh_lock); 4754 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 4755 } 4756 4757 request.rpr_request = REP_PROTOCOL_ITER_READ_VALUE; 4758 request.rpr_iterid = iter->iter_id; 4759 request.rpr_sequence = iter->iter_sequence; 4760 4761 r = make_door_call(h, &request, sizeof (request), 4762 &response, sizeof (response)); 4763 4764 if (r < 0) { 4765 (void) pthread_mutex_unlock(&h->rh_lock); 4766 DOOR_ERRORS_BLOCK(r); 4767 } 4768 4769 if (response.rpr_response == REP_PROTOCOL_DONE) { 4770 (void) pthread_mutex_unlock(&h->rh_lock); 4771 return (0); 4772 } 4773 if (response.rpr_response != REP_PROTOCOL_SUCCESS) { 4774 (void) pthread_mutex_unlock(&h->rh_lock); 4775 return (scf_set_error(proto_error(response.rpr_response))); 4776 } 4777 iter->iter_sequence++; 4778 4779 v->value_type = response.rpr_type; 4780 4781 assert(scf_validate_encoded_value(response.rpr_type, 4782 response.rpr_value)); 4783 4784 if (v->value_type != REP_PROTOCOL_TYPE_OPAQUE) { 4785 (void) strlcpy(v->value_value, response.rpr_value, 4786 sizeof (v->value_value)); 4787 } else { 4788 v->value_size = scf_opaque_decode(v->value_value, 4789 response.rpr_value, sizeof (v->value_value)); 4790 } 4791 (void) pthread_mutex_unlock(&h->rh_lock); 4792 4793 return (1); 4794 } 4795 4796 int 4797 scf_property_get_value(const scf_property_t *prop, scf_value_t *v) 4798 { 4799 scf_handle_t *h = prop->rd_d.rd_handle; 4800 struct rep_protocol_property_request request; 4801 struct rep_protocol_value_response response; 4802 int r; 4803 4804 if (h != v->value_handle) 4805 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH)); 4806 4807 (void) pthread_mutex_lock(&h->rh_lock); 4808 4809 request.rpr_request = REP_PROTOCOL_PROPERTY_GET_VALUE; 4810 request.rpr_entityid = prop->rd_d.rd_entity; 4811 4812 scf_value_reset_locked(v, 0); 4813 datael_finish_reset(&prop->rd_d); 4814 4815 r = make_door_call(h, &request, sizeof (request), 4816 &response, sizeof (response)); 4817 4818 if (r < 0) { 4819 (void) pthread_mutex_unlock(&h->rh_lock); 4820 DOOR_ERRORS_BLOCK(r); 4821 } 4822 4823 if (response.rpr_response != REP_PROTOCOL_SUCCESS && 4824 response.rpr_response != REP_PROTOCOL_FAIL_TRUNCATED) { 4825 (void) pthread_mutex_unlock(&h->rh_lock); 4826 assert(response.rpr_response != 4827 REP_PROTOCOL_FAIL_TYPE_MISMATCH); 4828 return (scf_set_error(proto_error(response.rpr_response))); 4829 } 4830 4831 v->value_type = response.rpr_type; 4832 if (v->value_type != REP_PROTOCOL_TYPE_OPAQUE) { 4833 (void) strlcpy(v->value_value, response.rpr_value, 4834 sizeof (v->value_value)); 4835 } else { 4836 v->value_size = scf_opaque_decode(v->value_value, 4837 response.rpr_value, sizeof (v->value_value)); 4838 } 4839 (void) pthread_mutex_unlock(&h->rh_lock); 4840 return ((response.rpr_response == REP_PROTOCOL_SUCCESS)? 4841 SCF_SUCCESS : scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED)); 4842 } 4843 4844 int 4845 scf_pg_get_parent_service(const scf_propertygroup_t *pg, scf_service_t *svc) 4846 { 4847 return (datael_get_parent(&pg->rd_d, &svc->rd_d)); 4848 } 4849 4850 int 4851 scf_pg_get_parent_instance(const scf_propertygroup_t *pg, scf_instance_t *inst) 4852 { 4853 return (datael_get_parent(&pg->rd_d, &inst->rd_d)); 4854 } 4855 4856 int 4857 scf_pg_get_parent_snaplevel(const scf_propertygroup_t *pg, 4858 scf_snaplevel_t *level) 4859 { 4860 return (datael_get_parent(&pg->rd_d, &level->rd_d)); 4861 } 4862 4863 int 4864 scf_service_get_parent(const scf_service_t *svc, scf_scope_t *s) 4865 { 4866 return (datael_get_parent(&svc->rd_d, &s->rd_d)); 4867 } 4868 4869 int 4870 scf_instance_get_parent(const scf_instance_t *inst, scf_service_t *svc) 4871 { 4872 return (datael_get_parent(&inst->rd_d, &svc->rd_d)); 4873 } 4874 4875 int 4876 scf_snapshot_get_parent(const scf_snapshot_t *inst, scf_instance_t *svc) 4877 { 4878 return (datael_get_parent(&inst->rd_d, &svc->rd_d)); 4879 } 4880 4881 int 4882 scf_snaplevel_get_parent(const scf_snaplevel_t *inst, scf_snapshot_t *svc) 4883 { 4884 return (datael_get_parent(&inst->rd_d, &svc->rd_d)); 4885 } 4886 4887 /* 4888 * FMRI functions 4889 * 4890 * Note: In the scf_parse_svc_fmri(), scf_parse_file_fmri() and 4891 * scf_parse_fmri(), fmri isn't const because that would require 4892 * allocating memory. Also, note that scope, at least, is not necessarily 4893 * in the passed in fmri. 4894 */ 4895 4896 int 4897 scf_parse_svc_fmri(char *fmri, const char **scope, const char **service, 4898 const char **instance, const char **propertygroup, const char **property) 4899 { 4900 char *s, *e, *te, *tpg; 4901 char *my_s = NULL, *my_i = NULL, *my_pg = NULL, *my_p = NULL; 4902 4903 if (scope != NULL) 4904 *scope = NULL; 4905 if (service != NULL) 4906 *service = NULL; 4907 if (instance != NULL) 4908 *instance = NULL; 4909 if (propertygroup != NULL) 4910 *propertygroup = NULL; 4911 if (property != NULL) 4912 *property = NULL; 4913 4914 s = fmri; 4915 e = strchr(s, '\0'); 4916 4917 if (strncmp(s, SCF_FMRI_SVC_PREFIX, 4918 sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) 4919 s += sizeof (SCF_FMRI_SVC_PREFIX) - 1; 4920 4921 if (strncmp(s, SCF_FMRI_SCOPE_PREFIX, 4922 sizeof (SCF_FMRI_SCOPE_PREFIX) - 1) == 0) { 4923 char *my_scope; 4924 4925 s += sizeof (SCF_FMRI_SCOPE_PREFIX) - 1; 4926 te = strstr(s, SCF_FMRI_SERVICE_PREFIX); 4927 if (te == NULL) 4928 te = e; 4929 4930 *te = 0; 4931 my_scope = s; 4932 4933 s = te; 4934 if (s < e) 4935 s += sizeof (SCF_FMRI_SERVICE_PREFIX) - 1; 4936 4937 /* If the scope ends with the suffix, remove it. */ 4938 te = strstr(my_scope, SCF_FMRI_SCOPE_SUFFIX); 4939 if (te != NULL && te[sizeof (SCF_FMRI_SCOPE_SUFFIX) - 1] == 0) 4940 *te = 0; 4941 4942 /* Validate the scope. */ 4943 if (my_scope[0] == '\0') 4944 my_scope = SCF_FMRI_LOCAL_SCOPE; 4945 else if (uu_check_name(my_scope, 0) == -1) { 4946 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 4947 } 4948 4949 if (scope != NULL) 4950 *scope = my_scope; 4951 } else { 4952 if (scope != NULL) 4953 *scope = SCF_FMRI_LOCAL_SCOPE; 4954 } 4955 4956 if (s[0] != 0) { 4957 if (strncmp(s, SCF_FMRI_SERVICE_PREFIX, 4958 sizeof (SCF_FMRI_SERVICE_PREFIX) - 1) == 0) 4959 s += sizeof (SCF_FMRI_SERVICE_PREFIX) - 1; 4960 4961 /* 4962 * Can't validate service here because it might not be null 4963 * terminated. 4964 */ 4965 my_s = s; 4966 } 4967 4968 tpg = strstr(s, SCF_FMRI_PROPERTYGRP_PREFIX); 4969 te = strstr(s, SCF_FMRI_INSTANCE_PREFIX); 4970 if (te != NULL && (tpg == NULL || te < tpg)) { 4971 *te = 0; 4972 te += sizeof (SCF_FMRI_INSTANCE_PREFIX) - 1; 4973 4974 /* Can't validate instance here either. */ 4975 my_i = s = te; 4976 4977 te = strstr(s, SCF_FMRI_PROPERTYGRP_PREFIX); 4978 } else { 4979 te = tpg; 4980 } 4981 4982 if (te != NULL) { 4983 *te = 0; 4984 te += sizeof (SCF_FMRI_PROPERTYGRP_PREFIX) - 1; 4985 4986 my_pg = s = te; 4987 te = strstr(s, SCF_FMRI_PROPERTY_PREFIX); 4988 if (te != NULL) { 4989 *te = 0; 4990 te += sizeof (SCF_FMRI_PROPERTY_PREFIX) - 1; 4991 4992 my_p = te; 4993 s = te; 4994 } 4995 } 4996 4997 if (my_s != NULL) { 4998 if (uu_check_name(my_s, UU_NAME_DOMAIN | UU_NAME_PATH) == -1) 4999 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 5000 5001 if (service != NULL) 5002 *service = my_s; 5003 } 5004 5005 if (my_i != NULL) { 5006 if (uu_check_name(my_i, UU_NAME_DOMAIN) == -1) 5007 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 5008 5009 if (instance != NULL) 5010 *instance = my_i; 5011 } 5012 5013 if (my_pg != NULL) { 5014 if (uu_check_name(my_pg, UU_NAME_DOMAIN) == -1) 5015 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 5016 5017 if (propertygroup != NULL) 5018 *propertygroup = my_pg; 5019 } 5020 5021 if (my_p != NULL) { 5022 if (uu_check_name(my_p, UU_NAME_DOMAIN) == -1) 5023 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 5024 5025 if (property != NULL) 5026 *property = my_p; 5027 } 5028 5029 return (0); 5030 } 5031 5032 int 5033 scf_parse_file_fmri(char *fmri, const char **scope, const char **path) 5034 { 5035 char *s, *e, *te; 5036 5037 if (scope != NULL) 5038 *scope = NULL; 5039 5040 s = fmri; 5041 e = strchr(s, '\0'); 5042 5043 if (strncmp(s, SCF_FMRI_FILE_PREFIX, 5044 sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) 5045 s += sizeof (SCF_FMRI_FILE_PREFIX) - 1; 5046 5047 if (strncmp(s, SCF_FMRI_SCOPE_PREFIX, 5048 sizeof (SCF_FMRI_SCOPE_PREFIX) - 1) == 0) { 5049 char *my_scope; 5050 5051 s += sizeof (SCF_FMRI_SCOPE_PREFIX) - 1; 5052 te = strstr(s, SCF_FMRI_SERVICE_PREFIX); 5053 if (te == NULL) 5054 te = e; 5055 5056 *te = 0; 5057 my_scope = s; 5058 5059 s = te; 5060 5061 /* Validate the scope. */ 5062 if (my_scope[0] != '\0' && 5063 strcmp(my_scope, SCF_FMRI_LOCAL_SCOPE) != 0) { 5064 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 5065 } 5066 5067 if (scope != NULL) 5068 *scope = my_scope; 5069 } else { 5070 /* 5071 * FMRI paths must be absolute 5072 */ 5073 if (s[0] != '/') 5074 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 5075 } 5076 5077 s += sizeof (SCF_FMRI_SERVICE_PREFIX) - 1; 5078 5079 if (s >= e) 5080 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 5081 5082 /* 5083 * If the user requests it, return the full path of the file. 5084 */ 5085 if (path != NULL) { 5086 assert(s > fmri); 5087 s[-1] = '/'; 5088 *path = s - 1; 5089 } 5090 5091 return (0); 5092 } 5093 5094 int 5095 scf_parse_fmri(char *fmri, int *type, const char **scope, const char **service, 5096 const char **instance, const char **propertygroup, const char **property) 5097 { 5098 if (strncmp(fmri, SCF_FMRI_SVC_PREFIX, 5099 sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) { 5100 if (type) 5101 *type = SCF_FMRI_TYPE_SVC; 5102 return (scf_parse_svc_fmri(fmri, scope, service, instance, 5103 propertygroup, property)); 5104 } else if (strncmp(fmri, SCF_FMRI_FILE_PREFIX, 5105 sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) { 5106 if (type) 5107 *type = SCF_FMRI_TYPE_FILE; 5108 return (scf_parse_file_fmri(fmri, scope, NULL)); 5109 } else { 5110 /* 5111 * Parse as a svc if the fmri type is not explicitly 5112 * specified. 5113 */ 5114 if (type) 5115 *type = SCF_FMRI_TYPE_SVC; 5116 return (scf_parse_svc_fmri(fmri, scope, service, instance, 5117 propertygroup, property)); 5118 } 5119 } 5120 5121 /* 5122 * Fails with _INVALID_ARGUMENT. fmri and buf may be equal. 5123 */ 5124 ssize_t 5125 scf_canonify_fmri(const char *fmri, char *buf, size_t bufsz) 5126 { 5127 const char *scope, *service, *instance, *pg, *property; 5128 char local[6 * REP_PROTOCOL_NAME_LEN]; 5129 int r; 5130 size_t len; 5131 5132 if (strlcpy(local, fmri, sizeof (local)) >= sizeof (local)) { 5133 /* Should this be CONSTRAINT_VIOLATED? */ 5134 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 5135 return (-1); 5136 } 5137 5138 5139 r = scf_parse_svc_fmri(local, &scope, &service, &instance, &pg, 5140 &property); 5141 if (r != 0) 5142 return (-1); 5143 5144 len = strlcpy(buf, "svc:/", bufsz); 5145 5146 if (scope != NULL && strcmp(scope, SCF_SCOPE_LOCAL) != 0) { 5147 len += strlcat(buf, "/", bufsz); 5148 len += strlcat(buf, scope, bufsz); 5149 } 5150 5151 if (service) 5152 len += strlcat(buf, service, bufsz); 5153 5154 if (instance) { 5155 len += strlcat(buf, ":", bufsz); 5156 len += strlcat(buf, instance, bufsz); 5157 } 5158 5159 if (pg) { 5160 len += strlcat(buf, "/:properties/", bufsz); 5161 len += strlcat(buf, pg, bufsz); 5162 } 5163 5164 if (property) { 5165 len += strlcat(buf, "/", bufsz); 5166 len += strlcat(buf, property, bufsz); 5167 } 5168 5169 return (len); 5170 } 5171 5172 int 5173 scf_handle_decode_fmri(scf_handle_t *h, const char *fmri, scf_scope_t *sc, 5174 scf_service_t *svc, scf_instance_t *inst, scf_propertygroup_t *pg, 5175 scf_property_t *prop, int flags) 5176 { 5177 const char *scope, *service, *instance, *propertygroup, *property; 5178 int last; 5179 char local[6 * REP_PROTOCOL_NAME_LEN]; 5180 int ret; 5181 const uint32_t holds = RH_HOLD_SCOPE | RH_HOLD_SERVICE | 5182 RH_HOLD_INSTANCE | RH_HOLD_PG | RH_HOLD_PROPERTY; 5183 5184 /* 5185 * verify that all handles match 5186 */ 5187 if ((sc != NULL && h != sc->rd_d.rd_handle) || 5188 (svc != NULL && h != svc->rd_d.rd_handle) || 5189 (inst != NULL && h != inst->rd_d.rd_handle) || 5190 (pg != NULL && h != pg->rd_d.rd_handle) || 5191 (prop != NULL && h != prop->rd_d.rd_handle)) 5192 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH)); 5193 5194 if (strlcpy(local, fmri, sizeof (local)) >= sizeof (local)) { 5195 ret = scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 5196 goto reset_args; 5197 } 5198 5199 /* 5200 * We can simply return from an error in parsing, because 5201 * scf_parse_fmri sets the error code correctly. 5202 */ 5203 if (scf_parse_svc_fmri(local, &scope, &service, &instance, 5204 &propertygroup, &property) == -1) { 5205 ret = -1; 5206 goto reset_args; 5207 } 5208 5209 /* 5210 * the FMRI looks valid at this point -- do constraint checks. 5211 */ 5212 5213 if (instance != NULL && (flags & SCF_DECODE_FMRI_REQUIRE_NO_INSTANCE)) { 5214 ret = scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED); 5215 goto reset_args; 5216 } 5217 if (instance == NULL && (flags & SCF_DECODE_FMRI_REQUIRE_INSTANCE)) { 5218 ret = scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED); 5219 goto reset_args; 5220 } 5221 5222 if (prop != NULL) 5223 last = REP_PROTOCOL_ENTITY_PROPERTY; 5224 else if (pg != NULL) 5225 last = REP_PROTOCOL_ENTITY_PROPERTYGRP; 5226 else if (inst != NULL) 5227 last = REP_PROTOCOL_ENTITY_INSTANCE; 5228 else if (svc != NULL) 5229 last = REP_PROTOCOL_ENTITY_SERVICE; 5230 else if (sc != NULL) 5231 last = REP_PROTOCOL_ENTITY_SCOPE; 5232 else 5233 last = REP_PROTOCOL_ENTITY_NONE; 5234 5235 if (flags & SCF_DECODE_FMRI_EXACT) { 5236 int last_fmri; 5237 5238 if (property != NULL) 5239 last_fmri = REP_PROTOCOL_ENTITY_PROPERTY; 5240 else if (propertygroup != NULL) 5241 last_fmri = REP_PROTOCOL_ENTITY_PROPERTYGRP; 5242 else if (instance != NULL) 5243 last_fmri = REP_PROTOCOL_ENTITY_INSTANCE; 5244 else if (service != NULL) 5245 last_fmri = REP_PROTOCOL_ENTITY_SERVICE; 5246 else if (scope != NULL) 5247 last_fmri = REP_PROTOCOL_ENTITY_SCOPE; 5248 else 5249 last_fmri = REP_PROTOCOL_ENTITY_NONE; 5250 5251 if (last != last_fmri) { 5252 ret = scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED); 5253 goto reset_args; 5254 } 5255 } 5256 5257 if ((flags & SCF_DECODE_FMRI_TRUNCATE) && 5258 last == REP_PROTOCOL_ENTITY_NONE) { 5259 ret = 0; /* nothing to do */ 5260 goto reset_args; 5261 } 5262 5263 if (!(flags & SCF_DECODE_FMRI_TRUNCATE)) 5264 last = REP_PROTOCOL_ENTITY_NONE; /* never stop */ 5265 5266 /* 5267 * passed the constraint checks -- try to grab the thing itself. 5268 */ 5269 5270 handle_hold_subhandles(h, holds); 5271 if (sc == NULL) 5272 sc = h->rh_scope; 5273 else 5274 datael_reset(&sc->rd_d); 5275 5276 if (svc == NULL) 5277 svc = h->rh_service; 5278 else 5279 datael_reset(&svc->rd_d); 5280 5281 if (inst == NULL) 5282 inst = h->rh_instance; 5283 else 5284 datael_reset(&inst->rd_d); 5285 5286 if (pg == NULL) 5287 pg = h->rh_pg; 5288 else 5289 datael_reset(&pg->rd_d); 5290 5291 if (prop == NULL) 5292 prop = h->rh_property; 5293 else 5294 datael_reset(&prop->rd_d); 5295 5296 /* 5297 * We only support local scopes, but we check *after* getting 5298 * the local scope, so that any repository-related errors take 5299 * precedence. 5300 */ 5301 if (scf_handle_get_scope(h, SCF_SCOPE_LOCAL, sc) == -1) { 5302 handle_rele_subhandles(h, holds); 5303 ret = -1; 5304 goto reset_args; 5305 } 5306 5307 if (scope != NULL && strcmp(scope, SCF_FMRI_LOCAL_SCOPE) != 0) { 5308 handle_rele_subhandles(h, holds); 5309 ret = scf_set_error(SCF_ERROR_NOT_FOUND); 5310 goto reset_args; 5311 } 5312 5313 5314 if (service == NULL || last == REP_PROTOCOL_ENTITY_SCOPE) { 5315 handle_rele_subhandles(h, holds); 5316 return (0); 5317 } 5318 5319 if (scf_scope_get_service(sc, service, svc) == -1) { 5320 handle_rele_subhandles(h, holds); 5321 ret = -1; 5322 assert(scf_error() != SCF_ERROR_NOT_SET); 5323 if (scf_error() == SCF_ERROR_DELETED) 5324 (void) scf_set_error(SCF_ERROR_NOT_FOUND); 5325 goto reset_args; 5326 } 5327 5328 if (last == REP_PROTOCOL_ENTITY_SERVICE) { 5329 handle_rele_subhandles(h, holds); 5330 return (0); 5331 } 5332 5333 if (instance == NULL) { 5334 if (propertygroup == NULL || 5335 last == REP_PROTOCOL_ENTITY_INSTANCE) { 5336 handle_rele_subhandles(h, holds); 5337 return (0); 5338 } 5339 5340 if (scf_service_get_pg(svc, propertygroup, pg) == -1) { 5341 handle_rele_subhandles(h, holds); 5342 ret = -1; 5343 assert(scf_error() != SCF_ERROR_NOT_SET); 5344 if (scf_error() == SCF_ERROR_DELETED) 5345 (void) scf_set_error(SCF_ERROR_NOT_FOUND); 5346 goto reset_args; 5347 } 5348 } else { 5349 if (scf_service_get_instance(svc, instance, inst) == -1) { 5350 handle_rele_subhandles(h, holds); 5351 ret = -1; 5352 assert(scf_error() != SCF_ERROR_NOT_SET); 5353 if (scf_error() == SCF_ERROR_DELETED) 5354 (void) scf_set_error(SCF_ERROR_NOT_FOUND); 5355 goto reset_args; 5356 } 5357 5358 if (propertygroup == NULL || 5359 last == REP_PROTOCOL_ENTITY_INSTANCE) { 5360 handle_rele_subhandles(h, holds); 5361 return (0); 5362 } 5363 5364 if (scf_instance_get_pg(inst, propertygroup, pg) == -1) { 5365 handle_rele_subhandles(h, holds); 5366 ret = -1; 5367 assert(scf_error() != SCF_ERROR_NOT_SET); 5368 if (scf_error() == SCF_ERROR_DELETED) 5369 (void) scf_set_error(SCF_ERROR_NOT_FOUND); 5370 goto reset_args; 5371 } 5372 } 5373 5374 if (property == NULL || last == REP_PROTOCOL_ENTITY_PROPERTYGRP) { 5375 handle_rele_subhandles(h, holds); 5376 return (0); 5377 } 5378 5379 if (scf_pg_get_property(pg, property, prop) == -1) { 5380 handle_rele_subhandles(h, holds); 5381 ret = -1; 5382 assert(scf_error() != SCF_ERROR_NOT_SET); 5383 if (scf_error() == SCF_ERROR_DELETED) 5384 (void) scf_set_error(SCF_ERROR_NOT_FOUND); 5385 goto reset_args; 5386 } 5387 5388 handle_rele_subhandles(h, holds); 5389 return (0); 5390 5391 reset_args: 5392 if (sc != NULL) 5393 datael_reset(&sc->rd_d); 5394 if (svc != NULL) 5395 datael_reset(&svc->rd_d); 5396 if (inst != NULL) 5397 datael_reset(&inst->rd_d); 5398 if (pg != NULL) 5399 datael_reset(&pg->rd_d); 5400 if (prop != NULL) 5401 datael_reset(&prop->rd_d); 5402 5403 return (ret); 5404 } 5405 5406 /* 5407 * Fails with _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response too 5408 * big, bad entity id, request not applicable to entity, name too long for 5409 * buffer), _NOT_SET, or _DELETED. 5410 */ 5411 ssize_t 5412 scf_scope_to_fmri(const scf_scope_t *scope, char *out, size_t sz) 5413 { 5414 ssize_t r, len; 5415 5416 char tmp[REP_PROTOCOL_NAME_LEN]; 5417 5418 r = scf_scope_get_name(scope, tmp, sizeof (tmp)); 5419 5420 if (r <= 0) 5421 return (r); 5422 5423 len = strlcpy(out, SCF_FMRI_SVC_PREFIX, sz); 5424 if (strcmp(tmp, SCF_FMRI_LOCAL_SCOPE) != 0) { 5425 if (len >= sz) 5426 return (len + r + sizeof (SCF_FMRI_SCOPE_SUFFIX) - 1); 5427 5428 len = strlcat(out, tmp, sz); 5429 if (len >= sz) 5430 return (len + sizeof (SCF_FMRI_SCOPE_SUFFIX) - 1); 5431 len = strlcat(out, 5432 SCF_FMRI_SCOPE_SUFFIX SCF_FMRI_SERVICE_PREFIX, sz); 5433 } 5434 5435 return (len); 5436 } 5437 5438 /* 5439 * Fails with _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response too 5440 * big, bad element id, bad ids, bad types, scope has no parent, request not 5441 * applicable to entity, name too long), _NOT_SET, _DELETED, 5442 */ 5443 ssize_t 5444 scf_service_to_fmri(const scf_service_t *svc, char *out, size_t sz) 5445 { 5446 scf_handle_t *h = svc->rd_d.rd_handle; 5447 scf_scope_t *scope = HANDLE_HOLD_SCOPE(h); 5448 ssize_t r, len; 5449 5450 char tmp[REP_PROTOCOL_NAME_LEN]; 5451 5452 r = datael_get_parent(&svc->rd_d, &scope->rd_d); 5453 if (r != SCF_SUCCESS) { 5454 HANDLE_RELE_SCOPE(h); 5455 5456 assert(scf_error() != SCF_ERROR_HANDLE_MISMATCH); 5457 return (-1); 5458 } 5459 if (out != NULL && sz > 0) 5460 len = scf_scope_to_fmri(scope, out, sz); 5461 else 5462 len = scf_scope_to_fmri(scope, tmp, 2); 5463 5464 HANDLE_RELE_SCOPE(h); 5465 5466 if (len < 0) 5467 return (-1); 5468 5469 if (out == NULL || len >= sz) 5470 len += sizeof (SCF_FMRI_SERVICE_PREFIX) - 1; 5471 else 5472 len = strlcat(out, SCF_FMRI_SERVICE_PREFIX, sz); 5473 5474 r = scf_service_get_name(svc, tmp, sizeof (tmp)); 5475 if (r < 0) 5476 return (r); 5477 5478 if (out == NULL || len >= sz) 5479 len += r; 5480 else 5481 len = strlcat(out, tmp, sz); 5482 5483 return (len); 5484 } 5485 5486 ssize_t 5487 scf_instance_to_fmri(const scf_instance_t *inst, char *out, size_t sz) 5488 { 5489 scf_handle_t *h = inst->rd_d.rd_handle; 5490 scf_service_t *svc = HANDLE_HOLD_SERVICE(h); 5491 ssize_t r, len; 5492 5493 char tmp[REP_PROTOCOL_NAME_LEN]; 5494 5495 r = datael_get_parent(&inst->rd_d, &svc->rd_d); 5496 if (r != SCF_SUCCESS) { 5497 HANDLE_RELE_SERVICE(h); 5498 return (-1); 5499 } 5500 5501 len = scf_service_to_fmri(svc, out, sz); 5502 5503 HANDLE_RELE_SERVICE(h); 5504 5505 if (len < 0) 5506 return (len); 5507 5508 if (len >= sz) 5509 len += sizeof (SCF_FMRI_INSTANCE_PREFIX) - 1; 5510 else 5511 len = strlcat(out, SCF_FMRI_INSTANCE_PREFIX, sz); 5512 5513 r = scf_instance_get_name(inst, tmp, sizeof (tmp)); 5514 if (r < 0) 5515 return (r); 5516 5517 if (len >= sz) 5518 len += r; 5519 else 5520 len = strlcat(out, tmp, sz); 5521 5522 return (len); 5523 } 5524 5525 ssize_t 5526 scf_pg_to_fmri(const scf_propertygroup_t *pg, char *out, size_t sz) 5527 { 5528 scf_handle_t *h = pg->rd_d.rd_handle; 5529 5530 struct rep_protocol_entity_parent_type request; 5531 struct rep_protocol_integer_response response; 5532 5533 char tmp[REP_PROTOCOL_NAME_LEN]; 5534 ssize_t len, r; 5535 5536 (void) pthread_mutex_lock(&h->rh_lock); 5537 request.rpr_request = REP_PROTOCOL_ENTITY_PARENT_TYPE; 5538 request.rpr_entityid = pg->rd_d.rd_entity; 5539 5540 datael_finish_reset(&pg->rd_d); 5541 r = make_door_call(h, &request, sizeof (request), 5542 &response, sizeof (response)); 5543 (void) pthread_mutex_unlock(&h->rh_lock); 5544 5545 if (r < 0) 5546 DOOR_ERRORS_BLOCK(r); 5547 5548 if (response.rpr_response != REP_PROTOCOL_SUCCESS || 5549 r < sizeof (response)) { 5550 return (scf_set_error(proto_error(response.rpr_response))); 5551 } 5552 5553 switch (response.rpr_value) { 5554 case REP_PROTOCOL_ENTITY_SERVICE: { 5555 scf_service_t *svc; 5556 5557 svc = HANDLE_HOLD_SERVICE(h); 5558 5559 r = datael_get_parent(&pg->rd_d, &svc->rd_d); 5560 5561 if (r == SCF_SUCCESS) 5562 len = scf_service_to_fmri(svc, out, sz); 5563 5564 HANDLE_RELE_SERVICE(h); 5565 break; 5566 } 5567 5568 case REP_PROTOCOL_ENTITY_INSTANCE: { 5569 scf_instance_t *inst; 5570 5571 inst = HANDLE_HOLD_INSTANCE(h); 5572 5573 r = datael_get_parent(&pg->rd_d, &inst->rd_d); 5574 5575 if (r == SCF_SUCCESS) 5576 len = scf_instance_to_fmri(inst, out, sz); 5577 5578 HANDLE_RELE_INSTANCE(h); 5579 break; 5580 } 5581 5582 case REP_PROTOCOL_ENTITY_SNAPLEVEL: { 5583 scf_instance_t *inst = HANDLE_HOLD_INSTANCE(h); 5584 scf_snapshot_t *snap = HANDLE_HOLD_SNAPSHOT(h); 5585 scf_snaplevel_t *level = HANDLE_HOLD_SNAPLVL(h); 5586 5587 r = datael_get_parent(&pg->rd_d, &level->rd_d); 5588 5589 if (r == SCF_SUCCESS) 5590 r = datael_get_parent(&level->rd_d, &snap->rd_d); 5591 5592 if (r == SCF_SUCCESS) 5593 r = datael_get_parent(&snap->rd_d, &inst->rd_d); 5594 5595 if (r == SCF_SUCCESS) 5596 len = scf_instance_to_fmri(inst, out, sz); 5597 5598 HANDLE_RELE_INSTANCE(h); 5599 HANDLE_RELE_SNAPSHOT(h); 5600 HANDLE_RELE_SNAPLVL(h); 5601 break; 5602 } 5603 5604 default: 5605 return (scf_set_error(SCF_ERROR_INTERNAL)); 5606 } 5607 5608 if (r != SCF_SUCCESS) 5609 return (r); 5610 5611 if (len >= sz) 5612 len += sizeof (SCF_FMRI_PROPERTYGRP_PREFIX) - 1; 5613 else 5614 len = strlcat(out, SCF_FMRI_PROPERTYGRP_PREFIX, sz); 5615 5616 r = scf_pg_get_name(pg, tmp, sizeof (tmp)); 5617 5618 if (r < 0) 5619 return (r); 5620 5621 if (len >= sz) 5622 len += r; 5623 else 5624 len = strlcat(out, tmp, sz); 5625 5626 return (len); 5627 } 5628 5629 ssize_t 5630 scf_property_to_fmri(const scf_property_t *prop, char *out, size_t sz) 5631 { 5632 scf_handle_t *h = prop->rd_d.rd_handle; 5633 scf_propertygroup_t *pg = HANDLE_HOLD_PG(h); 5634 5635 char tmp[REP_PROTOCOL_NAME_LEN]; 5636 ssize_t len; 5637 int r; 5638 5639 r = datael_get_parent(&prop->rd_d, &pg->rd_d); 5640 if (r != SCF_SUCCESS) { 5641 HANDLE_RELE_PG(h); 5642 return (-1); 5643 } 5644 5645 len = scf_pg_to_fmri(pg, out, sz); 5646 5647 HANDLE_RELE_PG(h); 5648 5649 if (len >= sz) 5650 len += sizeof (SCF_FMRI_PROPERTY_PREFIX) - 1; 5651 else 5652 len = strlcat(out, SCF_FMRI_PROPERTY_PREFIX, sz); 5653 5654 r = scf_property_get_name(prop, tmp, sizeof (tmp)); 5655 5656 if (r < 0) 5657 return (r); 5658 5659 if (len >= sz) 5660 len += r; 5661 else 5662 len = strlcat(out, tmp, sz); 5663 5664 return (len); 5665 } 5666 5667 int 5668 scf_pg_get_underlying_pg(const scf_propertygroup_t *pg, 5669 scf_propertygroup_t *out) 5670 { 5671 scf_handle_t *h = pg->rd_d.rd_handle; 5672 scf_service_t *svc; 5673 scf_instance_t *inst; 5674 5675 char me[REP_PROTOCOL_NAME_LEN]; 5676 int r; 5677 5678 if (h != out->rd_d.rd_handle) 5679 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH)); 5680 5681 r = scf_pg_get_name(pg, me, sizeof (me)); 5682 5683 if (r < 0) 5684 return (r); 5685 5686 svc = HANDLE_HOLD_SERVICE(h); 5687 inst = HANDLE_HOLD_INSTANCE(h); 5688 5689 r = datael_get_parent(&pg->rd_d, &inst->rd_d); 5690 5691 if (r == SCF_SUCCESS) { 5692 r = datael_get_parent(&inst->rd_d, &svc->rd_d); 5693 if (r != SCF_SUCCESS) { 5694 goto out; 5695 } 5696 r = scf_service_get_pg(svc, me, out); 5697 } else { 5698 r = scf_set_error(SCF_ERROR_NOT_FOUND); 5699 } 5700 5701 out: 5702 HANDLE_RELE_SERVICE(h); 5703 HANDLE_RELE_INSTANCE(h); 5704 return (r); 5705 } 5706 5707 #define LEGACY_SCHEME "lrc:" 5708 #define LEGACY_UNKNOWN "unknown" 5709 5710 /* 5711 * Implementation of scf_walk_fmri() 5712 * 5713 * This is a little tricky due to the many-to-many relationship between patterns 5714 * and matches. We need to be able to satisfy the following requirements: 5715 * 5716 * 1) Detect patterns which match more than one FMRI, and be able to 5717 * report which FMRIs have been matched. 5718 * 2) Detect patterns which have not matched any FMRIs 5719 * 3) Visit each matching FMRI exactly once across all patterns 5720 * 4) Ignore FMRIs which have only been matched due to multiply-matching 5721 * patterns. 5722 * 5723 * We maintain an array of scf_pattern_t structures, one for each argument, and 5724 * maintain a linked list of scf_match_t structures for each one. We first 5725 * qualify each pattern's type: 5726 * 5727 * PATTERN_INVALID The argument is invalid (too long). 5728 * 5729 * PATTERN_EXACT The pattern is a complete FMRI. The list of 5730 * matches contains only a single entry. 5731 * 5732 * PATTERN_GLOB The pattern will be matched against all 5733 * FMRIs via fnmatch() in the second phase. 5734 * Matches will be added to the pattern's list 5735 * as they are found. 5736 * 5737 * PATTERN_PARTIAL Everything else. We will assume that this is 5738 * an abbreviated FMRI, and match according to 5739 * our abbreviated FMRI rules. Matches will be 5740 * added to the pattern's list as they are found. 5741 * 5742 * The first pass searches for arguments that are complete FMRIs. These are 5743 * classified as EXACT patterns and do not necessitate searching the entire 5744 * tree. 5745 * 5746 * Once this is done, if we have any GLOB or PARTIAL patterns (or if no 5747 * arguments were given), we iterate over all services and instances in the 5748 * repository, looking for matches. 5749 * 5750 * When a match is found, we add the match to the pattern's list. We also enter 5751 * the match into a hash table, resulting in something like this: 5752 * 5753 * scf_pattern_t scf_match_t 5754 * +---------------+ +-------+ +-------+ 5755 * | pattern 'foo' |----->| match |---->| match | 5756 * +---------------+ +-------+ +-------+ 5757 * | | 5758 * scf_match_key_t | | 5759 * +--------------+ | | 5760 * | FMRI bar/foo |<----+ | 5761 * +--------------+ | 5762 * | FMRI baz/foo |<------------------+ 5763 * +--------------+ 5764 * 5765 * Once we have all of this set up, we do one pass to report patterns matching 5766 * multiple FMRIs (if SCF_WALK_MULTIPLE is not set) and patterns for which no 5767 * match was found. 5768 * 5769 * Finally, we walk through all valid patterns, and for each match, if we 5770 * haven't already seen the match (as recorded in the hash table), then we 5771 * execute the callback. 5772 */ 5773 5774 struct scf_matchkey; 5775 struct scf_match; 5776 5777 /* 5778 * scf_matchkey_t 5779 */ 5780 typedef struct scf_matchkey { 5781 char *sk_fmri; /* Matching FMRI */ 5782 char *sk_legacy; /* Legacy name */ 5783 int sk_seen; /* If we've been seen */ 5784 struct scf_matchkey *sk_next; /* Next in hash chain */ 5785 } scf_matchkey_t; 5786 5787 /* 5788 * scf_match_t 5789 */ 5790 typedef struct scf_match { 5791 scf_matchkey_t *sm_key; 5792 struct scf_match *sm_next; 5793 } scf_match_t; 5794 5795 #define WALK_HTABLE_SIZE 123 5796 5797 /* 5798 * scf_get_key() 5799 * 5800 * Given an FMRI and a hash table, returns the scf_matchkey_t corresponding to 5801 * this FMRI. If the FMRI does not exist, it is added to the hash table. If a 5802 * new entry cannot be allocated due to lack of memory, NULL is returned. 5803 */ 5804 static scf_matchkey_t * 5805 scf_get_key(scf_matchkey_t **htable, const char *fmri, const char *legacy) 5806 { 5807 uint_t h = 0, g; 5808 const char *p, *k; 5809 scf_matchkey_t *key; 5810 5811 k = strstr(fmri, ":/"); 5812 assert(k != NULL); 5813 k += 2; 5814 5815 /* 5816 * Generic hash function from uts/common/os/modhash.c. 5817 */ 5818 for (p = k; *p != '\0'; ++p) { 5819 h = (h << 4) + *p; 5820 if ((g = (h & 0xf0000000)) != 0) { 5821 h ^= (g >> 24); 5822 h ^= g; 5823 } 5824 } 5825 5826 h %= WALK_HTABLE_SIZE; 5827 5828 /* 5829 * Search for an existing key 5830 */ 5831 for (key = htable[h]; key != NULL; key = key->sk_next) { 5832 if (strcmp(key->sk_fmri, fmri) == 0) 5833 return (key); 5834 } 5835 5836 if ((key = calloc(sizeof (scf_matchkey_t), 1)) == NULL) 5837 return (NULL); 5838 5839 /* 5840 * Add new key to hash table. 5841 */ 5842 if ((key->sk_fmri = strdup(fmri)) == NULL) { 5843 free(key); 5844 return (NULL); 5845 } 5846 5847 if (legacy == NULL) { 5848 key->sk_legacy = NULL; 5849 } else if ((key->sk_legacy = strdup(legacy)) == NULL) { 5850 free(key->sk_fmri); 5851 free(key); 5852 return (NULL); 5853 } 5854 5855 key->sk_next = htable[h]; 5856 htable[h] = key; 5857 5858 return (key); 5859 } 5860 5861 /* 5862 * Given an FMRI, insert it into the pattern's list appropriately. 5863 * svc_explicit indicates whether matching services should take 5864 * precedence over matching instances. 5865 */ 5866 static scf_error_t 5867 scf_add_match(scf_matchkey_t **htable, const char *fmri, const char *legacy, 5868 scf_pattern_t *pattern, int svc_explicit) 5869 { 5870 scf_match_t *match; 5871 5872 /* 5873 * If svc_explicit is set, enforce the constaint that matching 5874 * instances take precedence over matching services. Otherwise, 5875 * matching services take precedence over matching instances. 5876 */ 5877 if (svc_explicit) { 5878 scf_match_t *next, *prev; 5879 /* 5880 * If we match an instance, check to see if we must remove 5881 * any matching services (for SCF_WALK_EXPLICIT). 5882 */ 5883 for (prev = match = pattern->sp_matches; match != NULL; 5884 match = next) { 5885 size_t len = strlen(match->sm_key->sk_fmri); 5886 next = match->sm_next; 5887 if (strncmp(match->sm_key->sk_fmri, fmri, len) == 0 && 5888 fmri[len] == ':') { 5889 if (prev == match) 5890 pattern->sp_matches = match->sm_next; 5891 else 5892 prev->sm_next = match->sm_next; 5893 pattern->sp_matchcount--; 5894 free(match); 5895 } else 5896 prev = match; 5897 } 5898 } else { 5899 /* 5900 * If we've matched a service don't add any instances (for 5901 * SCF_WALK_SERVICE). 5902 */ 5903 for (match = pattern->sp_matches; match != NULL; 5904 match = match->sm_next) { 5905 size_t len = strlen(match->sm_key->sk_fmri); 5906 if (strncmp(match->sm_key->sk_fmri, fmri, len) == 0 && 5907 fmri[len] == ':') 5908 return (0); 5909 } 5910 } 5911 5912 if ((match = malloc(sizeof (scf_match_t))) == NULL) 5913 return (SCF_ERROR_NO_MEMORY); 5914 5915 if ((match->sm_key = scf_get_key(htable, fmri, legacy)) == NULL) { 5916 free(match); 5917 return (SCF_ERROR_NO_MEMORY); 5918 } 5919 5920 match->sm_next = pattern->sp_matches; 5921 pattern->sp_matches = match; 5922 pattern->sp_matchcount++; 5923 5924 return (0); 5925 } 5926 5927 /* 5928 * Returns 1 if the fmri matches the given pattern, 0 otherwise. 5929 */ 5930 int 5931 scf_cmp_pattern(char *fmri, scf_pattern_t *pattern) 5932 { 5933 char *tmp; 5934 5935 if (pattern->sp_type == PATTERN_GLOB) { 5936 if (fnmatch(pattern->sp_arg, fmri, 0) == 0) 5937 return (1); 5938 } else if (pattern->sp_type == PATTERN_PARTIAL && 5939 (tmp = strstr(fmri, pattern->sp_arg)) != NULL) { 5940 /* 5941 * We only allow partial matches anchored on the end of 5942 * a service or instance, and beginning on an element 5943 * boundary. 5944 */ 5945 if (tmp != fmri && tmp[-1] != '/' && tmp[-1] != ':' && 5946 tmp[0] != ':') 5947 return (0); 5948 tmp += strlen(pattern->sp_arg); 5949 if (tmp != fmri + strlen(fmri) && tmp[0] != ':' && 5950 tmp[-1] != ':') 5951 return (0); 5952 5953 /* 5954 * If the user has supplied a short pattern that matches 5955 * 'svc:/' or 'lrc:/', ignore it. 5956 */ 5957 if (tmp <= fmri + 4) 5958 return (0); 5959 5960 return (1); 5961 } 5962 5963 return (0); 5964 } 5965 5966 /* 5967 * Attempts to match the given FMRI against a set of patterns, keeping track of 5968 * the results. 5969 */ 5970 static scf_error_t 5971 scf_pattern_match(scf_matchkey_t **htable, char *fmri, const char *legacy, 5972 int npattern, scf_pattern_t *pattern, int svc_explicit) 5973 { 5974 int i; 5975 int ret = 0; 5976 5977 for (i = 0; i < npattern; i++) { 5978 if (scf_cmp_pattern(fmri, &pattern[i]) && 5979 (ret = scf_add_match(htable, fmri, 5980 legacy, &pattern[i], svc_explicit)) != 0) 5981 return (ret); 5982 } 5983 5984 return (0); 5985 } 5986 5987 scf_error_t 5988 scf_walk_fmri(scf_handle_t *h, int argc, char **argv, int flags, 5989 scf_walk_callback callback, void *data, int *err, 5990 void (*errfunc)(const char *, ...)) 5991 { 5992 scf_pattern_t *pattern = NULL; 5993 int i; 5994 char *fmri = NULL; 5995 ssize_t max_fmri_length; 5996 scf_service_t *svc = NULL; 5997 scf_instance_t *inst = NULL; 5998 scf_iter_t *iter = NULL, *sciter = NULL, *siter = NULL; 5999 scf_scope_t *scope = NULL; 6000 scf_propertygroup_t *pg = NULL; 6001 scf_property_t *prop = NULL; 6002 scf_value_t *value = NULL; 6003 int ret = 0; 6004 scf_matchkey_t **htable = NULL; 6005 int pattern_search = 0; 6006 ssize_t max_name_length; 6007 char *pgname = NULL; 6008 scf_walkinfo_t info; 6009 6010 #ifndef NDEBUG 6011 if (flags & SCF_WALK_EXPLICIT) 6012 assert(flags & SCF_WALK_SERVICE); 6013 if (flags & SCF_WALK_NOINSTANCE) 6014 assert(flags & SCF_WALK_SERVICE); 6015 if (flags & SCF_WALK_PROPERTY) 6016 assert(!(flags & SCF_WALK_LEGACY)); 6017 #endif 6018 6019 /* 6020 * Setup initial variables 6021 */ 6022 if ((max_fmri_length = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) == -1 || 6023 (max_name_length = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) == -1) 6024 return (SCF_ERROR_INTERNAL); 6025 6026 if ((fmri = malloc(max_fmri_length + 1)) == NULL || 6027 (pgname = malloc(max_name_length + 1)) == NULL) { 6028 ret = SCF_ERROR_NO_MEMORY; 6029 goto error; 6030 } 6031 6032 if (argc == 0) { 6033 pattern = NULL; 6034 } else if ((pattern = calloc(argc, sizeof (scf_pattern_t))) 6035 == NULL) { 6036 ret = SCF_ERROR_NO_MEMORY; 6037 goto error; 6038 } 6039 6040 if ((htable = calloc(WALK_HTABLE_SIZE, sizeof (void *))) == NULL) { 6041 ret = SCF_ERROR_NO_MEMORY; 6042 goto error; 6043 } 6044 6045 if ((inst = scf_instance_create(h)) == NULL || 6046 (svc = scf_service_create(h)) == NULL || 6047 (iter = scf_iter_create(h)) == NULL || 6048 (sciter = scf_iter_create(h)) == NULL || 6049 (siter = scf_iter_create(h)) == NULL || 6050 (scope = scf_scope_create(h)) == NULL || 6051 (pg = scf_pg_create(h)) == NULL || 6052 (prop = scf_property_create(h)) == NULL || 6053 (value = scf_value_create(h)) == NULL) { 6054 ret = scf_error(); 6055 goto error; 6056 } 6057 6058 /* 6059 * For each fmri given, we first check to see if it's a full service, 6060 * instance, property group, or property FMRI. This avoids having to do 6061 * the (rather expensive) walk of all instances. Any element which does 6062 * not match a full fmri is identified as a globbed pattern or a partial 6063 * fmri and stored in a private array when walking instances. 6064 */ 6065 for (i = 0; i < argc; i++) { 6066 const char *scope_name, *svc_name, *inst_name, *pg_name; 6067 const char *prop_name; 6068 6069 if (strlen(argv[i]) > max_fmri_length) { 6070 errfunc(scf_get_msg(SCF_MSG_ARGTOOLONG), argv[i]); 6071 if (err != NULL) 6072 *err = UU_EXIT_FATAL; 6073 continue; 6074 } 6075 6076 (void) strcpy(fmri, argv[i]); 6077 if (scf_parse_svc_fmri(fmri, &scope_name, &svc_name, &inst_name, 6078 &pg_name, &prop_name) != SCF_SUCCESS) 6079 goto badfmri; 6080 6081 /* 6082 * If the user has specified SCF_WALK_PROPERTY, allow property 6083 * groups and properties. 6084 */ 6085 if (pg_name != NULL || prop_name != NULL) { 6086 if (!(flags & SCF_WALK_PROPERTY)) 6087 goto badfmri; 6088 6089 if (scf_handle_decode_fmri(h, argv[i], NULL, NULL, 6090 NULL, pg, prop, 0) != 0) 6091 goto badfmri; 6092 6093 if (scf_pg_get_name(pg, NULL, 0) < 0 && 6094 scf_property_get_name(prop, NULL, 0) < 0) 6095 goto badfmri; 6096 6097 if (scf_canonify_fmri(argv[i], fmri, max_fmri_length) 6098 <= 0) { 6099 /* 6100 * scf_parse_fmri() should have caught this. 6101 */ 6102 abort(); 6103 } 6104 6105 if ((ret = scf_add_match(htable, fmri, NULL, 6106 &pattern[i], flags & SCF_WALK_EXPLICIT)) != 0) 6107 goto error; 6108 6109 if ((pattern[i].sp_arg = strdup(argv[i])) == NULL) { 6110 ret = SCF_ERROR_NO_MEMORY; 6111 goto error; 6112 } 6113 pattern[i].sp_type = PATTERN_EXACT; 6114 } 6115 6116 /* 6117 * We need at least a service name 6118 */ 6119 if (scope_name == NULL || svc_name == NULL) 6120 goto badfmri; 6121 6122 /* 6123 * If we have a fully qualified instance, add it to our list of 6124 * fmris to watch. 6125 */ 6126 if (inst_name != NULL) { 6127 if (flags & SCF_WALK_NOINSTANCE) 6128 goto badfmri; 6129 6130 if (scf_handle_decode_fmri(h, argv[i], NULL, NULL, 6131 inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != 0) 6132 goto badfmri; 6133 6134 if (scf_canonify_fmri(argv[i], fmri, max_fmri_length) 6135 <= 0) 6136 goto badfmri; 6137 6138 if ((ret = scf_add_match(htable, fmri, NULL, 6139 &pattern[i], flags & SCF_WALK_EXPLICIT)) != 0) 6140 goto error; 6141 6142 if ((pattern[i].sp_arg = strdup(argv[i])) == NULL) { 6143 ret = SCF_ERROR_NO_MEMORY; 6144 goto error; 6145 } 6146 pattern[i].sp_type = PATTERN_EXACT; 6147 6148 continue; 6149 } 6150 6151 if (scf_handle_decode_fmri(h, argv[i], NULL, svc, 6152 NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != 6153 SCF_SUCCESS) 6154 goto badfmri; 6155 6156 /* 6157 * If the user allows for bare services, then simply 6158 * pass this service on. 6159 */ 6160 if (flags & SCF_WALK_SERVICE) { 6161 if (scf_service_to_fmri(svc, fmri, 6162 max_fmri_length + 1) <= 0) { 6163 ret = scf_error(); 6164 goto error; 6165 } 6166 6167 if ((ret = scf_add_match(htable, fmri, NULL, 6168 &pattern[i], flags & SCF_WALK_EXPLICIT)) != 0) 6169 goto error; 6170 6171 if ((pattern[i].sp_arg = strdup(argv[i])) 6172 == NULL) { 6173 ret = SCF_ERROR_NO_MEMORY; 6174 goto error; 6175 } 6176 pattern[i].sp_type = PATTERN_EXACT; 6177 continue; 6178 } 6179 6180 if (flags & SCF_WALK_NOINSTANCE) 6181 goto badfmri; 6182 6183 /* 6184 * Otherwise, iterate over all instances in the service. 6185 */ 6186 if (scf_iter_service_instances(iter, svc) != 6187 SCF_SUCCESS) { 6188 ret = scf_error(); 6189 goto error; 6190 } 6191 6192 for (;;) { 6193 ret = scf_iter_next_instance(iter, inst); 6194 if (ret == 0) 6195 break; 6196 if (ret != 1) { 6197 ret = scf_error(); 6198 goto error; 6199 } 6200 6201 if (scf_instance_to_fmri(inst, fmri, 6202 max_fmri_length + 1) == -1) 6203 goto badfmri; 6204 6205 if ((ret = scf_add_match(htable, fmri, NULL, 6206 &pattern[i], flags & SCF_WALK_EXPLICIT)) != 0) 6207 goto error; 6208 } 6209 6210 if ((pattern[i].sp_arg = strdup(argv[i])) == NULL) { 6211 ret = SCF_ERROR_NO_MEMORY; 6212 goto error; 6213 } 6214 pattern[i].sp_type = PATTERN_EXACT; 6215 6216 continue; 6217 6218 badfmri: 6219 6220 /* 6221 * If we got here because of a fatal error, bail out 6222 * immediately. 6223 */ 6224 if (scf_error() == SCF_ERROR_CONNECTION_BROKEN) { 6225 ret = scf_error(); 6226 goto error; 6227 } 6228 6229 /* 6230 * At this point we failed to interpret the argument as a 6231 * complete fmri, so mark it as a partial or globbed FMRI for 6232 * later processing. 6233 */ 6234 if (strpbrk(argv[i], "*?[") != NULL) { 6235 /* 6236 * Prepend svc:/ to patterns which don't begin with * or 6237 * svc: or lrc:. 6238 */ 6239 pattern[i].sp_type = PATTERN_GLOB; 6240 if (argv[i][0] == '*' || 6241 (strlen(argv[i]) >= 4 && argv[i][3] == ':')) 6242 pattern[i].sp_arg = strdup(argv[i]); 6243 else { 6244 pattern[i].sp_arg = malloc(strlen(argv[i]) + 6); 6245 if (pattern[i].sp_arg != NULL) 6246 (void) snprintf(pattern[i].sp_arg, 6247 strlen(argv[i]) + 6, "svc:/%s", 6248 argv[i]); 6249 } 6250 } else { 6251 pattern[i].sp_type = PATTERN_PARTIAL; 6252 pattern[i].sp_arg = strdup(argv[i]); 6253 } 6254 pattern_search = 1; 6255 if (pattern[i].sp_arg == NULL) { 6256 ret = SCF_ERROR_NO_MEMORY; 6257 goto error; 6258 } 6259 } 6260 6261 if (pattern_search || argc == 0) { 6262 /* 6263 * We have a set of patterns to search for. Iterate over all 6264 * instances and legacy services searching for matches. 6265 */ 6266 if (scf_handle_get_local_scope(h, scope) != 0) { 6267 ret = scf_error(); 6268 goto error; 6269 } 6270 6271 if (scf_iter_scope_services(sciter, scope) != 0) { 6272 ret = scf_error(); 6273 goto error; 6274 } 6275 6276 for (;;) { 6277 ret = scf_iter_next_service(sciter, svc); 6278 if (ret == 0) 6279 break; 6280 if (ret != 1) { 6281 ret = scf_error(); 6282 goto error; 6283 } 6284 6285 if (flags & SCF_WALK_SERVICE) { 6286 /* 6287 * If the user is requesting bare services, try 6288 * to match the service first. 6289 */ 6290 if (scf_service_to_fmri(svc, fmri, 6291 max_fmri_length + 1) < 0) { 6292 ret = scf_error(); 6293 goto error; 6294 } 6295 6296 if (argc == 0) { 6297 info.fmri = fmri; 6298 info.scope = scope; 6299 info.svc = svc; 6300 info.inst = NULL; 6301 info.pg = NULL; 6302 info.prop = NULL; 6303 if ((ret = callback(data, &info)) != 0) 6304 goto error; 6305 continue; 6306 } else if ((ret = scf_pattern_match(htable, 6307 fmri, NULL, argc, pattern, 6308 flags & SCF_WALK_EXPLICIT)) != 0) { 6309 goto error; 6310 } 6311 } 6312 6313 if (flags & SCF_WALK_NOINSTANCE) 6314 continue; 6315 6316 /* 6317 * Iterate over all instances in the service. 6318 */ 6319 if (scf_iter_service_instances(siter, svc) != 0) { 6320 if (scf_error() != SCF_ERROR_DELETED) { 6321 ret = scf_error(); 6322 goto error; 6323 } 6324 continue; 6325 } 6326 6327 for (;;) { 6328 ret = scf_iter_next_instance(siter, inst); 6329 if (ret == 0) 6330 break; 6331 if (ret != 1) { 6332 if (scf_error() != SCF_ERROR_DELETED) { 6333 ret = scf_error(); 6334 goto error; 6335 } 6336 break; 6337 } 6338 6339 if (scf_instance_to_fmri(inst, fmri, 6340 max_fmri_length + 1) < 0) { 6341 ret = scf_error(); 6342 goto error; 6343 } 6344 6345 /* 6346 * Without arguments, execute the callback 6347 * immediately. 6348 */ 6349 if (argc == 0) { 6350 info.fmri = fmri; 6351 info.scope = scope; 6352 info.svc = svc; 6353 info.inst = inst; 6354 info.pg = NULL; 6355 info.prop = NULL; 6356 if ((ret = callback(data, &info)) != 0) 6357 goto error; 6358 } else if ((ret = scf_pattern_match(htable, 6359 fmri, NULL, argc, pattern, 6360 flags & SCF_WALK_EXPLICIT)) != 0) { 6361 goto error; 6362 } 6363 } 6364 } 6365 6366 /* 6367 * Search legacy services 6368 */ 6369 if ((flags & SCF_WALK_LEGACY)) { 6370 if (scf_scope_get_service(scope, SCF_LEGACY_SERVICE, 6371 svc) != 0) { 6372 if (scf_error() != SCF_ERROR_NOT_FOUND) { 6373 ret = scf_error(); 6374 goto error; 6375 } 6376 6377 goto nolegacy; 6378 } 6379 6380 if (scf_iter_service_pgs_typed(iter, svc, 6381 SCF_GROUP_FRAMEWORK) != SCF_SUCCESS) { 6382 ret = scf_error(); 6383 goto error; 6384 } 6385 6386 (void) strcpy(fmri, LEGACY_SCHEME); 6387 6388 for (;;) { 6389 ret = scf_iter_next_pg(iter, pg); 6390 if (ret == -1) { 6391 ret = scf_error(); 6392 goto error; 6393 } 6394 if (ret == 0) 6395 break; 6396 6397 if (scf_pg_get_property(pg, 6398 SCF_LEGACY_PROPERTY_NAME, prop) == -1) { 6399 ret = scf_error(); 6400 if (ret == SCF_ERROR_DELETED || 6401 ret == SCF_ERROR_NOT_FOUND) { 6402 ret = 0; 6403 continue; 6404 } 6405 goto error; 6406 } 6407 6408 if (scf_property_is_type(prop, SCF_TYPE_ASTRING) 6409 != SCF_SUCCESS) { 6410 if (scf_error() == SCF_ERROR_DELETED) 6411 continue; 6412 ret = scf_error(); 6413 goto error; 6414 } 6415 6416 if (scf_property_get_value(prop, value) != 6417 SCF_SUCCESS) 6418 continue; 6419 6420 if (scf_value_get_astring(value, 6421 fmri + sizeof (LEGACY_SCHEME) - 1, 6422 max_fmri_length + 2 - 6423 sizeof (LEGACY_SCHEME)) <= 0) 6424 continue; 6425 6426 if (scf_pg_get_name(pg, pgname, 6427 max_name_length + 1) <= 0) { 6428 if (scf_error() == SCF_ERROR_DELETED) 6429 continue; 6430 ret = scf_error(); 6431 goto error; 6432 } 6433 6434 if (argc == 0) { 6435 info.fmri = fmri; 6436 info.scope = scope; 6437 info.svc = NULL; 6438 info.inst = NULL; 6439 info.pg = pg; 6440 info.prop = NULL; 6441 if ((ret = callback(data, &info)) != 0) 6442 goto error; 6443 } else if ((ret = scf_pattern_match(htable, 6444 fmri, pgname, argc, pattern, 6445 flags & SCF_WALK_EXPLICIT)) != 0) 6446 goto error; 6447 } 6448 6449 } 6450 } 6451 nolegacy: 6452 ret = 0; 6453 6454 if (argc == 0) 6455 goto error; 6456 6457 /* 6458 * Check all patterns, and see if we have that any that didn't match 6459 * or any that matched multiple instances. For svcprop, add up the 6460 * total number of matching keys. 6461 */ 6462 info.count = 0; 6463 for (i = 0; i < argc; i++) { 6464 scf_match_t *match; 6465 6466 if (pattern[i].sp_type == PATTERN_INVALID) 6467 continue; 6468 if (pattern[i].sp_matchcount == 0) { 6469 scf_msg_t msgid; 6470 /* 6471 * Provide a useful error message based on the argument 6472 * and the type of entity requested. 6473 */ 6474 if (!(flags & SCF_WALK_LEGACY) && 6475 strncmp(pattern[i].sp_arg, "lrc:/", 5) == 0) 6476 msgid = SCF_MSG_PATTERN_LEGACY; 6477 else if (flags & SCF_WALK_PROPERTY) 6478 msgid = SCF_MSG_PATTERN_NOENTITY; 6479 else if (flags & SCF_WALK_NOINSTANCE) 6480 msgid = SCF_MSG_PATTERN_NOSERVICE; 6481 else if (flags & SCF_WALK_SERVICE) 6482 msgid = SCF_MSG_PATTERN_NOINSTSVC; 6483 else 6484 msgid = SCF_MSG_PATTERN_NOINSTANCE; 6485 6486 errfunc(scf_get_msg(msgid), pattern[i].sp_arg); 6487 if (err) 6488 *err = UU_EXIT_FATAL; 6489 } else if (!(flags & SCF_WALK_MULTIPLE) && 6490 pattern[i].sp_matchcount > 1) { 6491 size_t len, off; 6492 char *msg; 6493 6494 /* 6495 * Construct a message with all possible FMRIs before 6496 * passing off to error handling function. 6497 * 6498 * Note that strlen(scf_get_msg(...)) includes the 6499 * length of '%s', which accounts for the terminating 6500 * null byte. 6501 */ 6502 len = strlen(scf_get_msg(SCF_MSG_PATTERN_MULTIMATCH)) + 6503 strlen(pattern[i].sp_arg); 6504 for (match = pattern[i].sp_matches; match != NULL; 6505 match = match->sm_next) { 6506 len += strlen(match->sm_key->sk_fmri) + 2; 6507 } 6508 if ((msg = malloc(len)) == NULL) { 6509 ret = SCF_ERROR_NO_MEMORY; 6510 goto error; 6511 } 6512 6513 /* LINTED - format argument */ 6514 (void) snprintf(msg, len, 6515 scf_get_msg(SCF_MSG_PATTERN_MULTIMATCH), 6516 pattern[i].sp_arg); 6517 off = strlen(msg); 6518 for (match = pattern[i].sp_matches; match != NULL; 6519 match = match->sm_next) { 6520 off += snprintf(msg + off, len - off, "\t%s\n", 6521 match->sm_key->sk_fmri); 6522 } 6523 6524 errfunc(msg); 6525 if (err != NULL) 6526 *err = UU_EXIT_FATAL; 6527 6528 free(msg); 6529 } else { 6530 for (match = pattern[i].sp_matches; match != NULL; 6531 match = match->sm_next) { 6532 if (!match->sm_key->sk_seen) 6533 info.count++; 6534 match->sm_key->sk_seen = 1; 6535 } 6536 } 6537 } 6538 6539 /* 6540 * Clear 'sk_seen' for all keys. 6541 */ 6542 for (i = 0; i < WALK_HTABLE_SIZE; i++) { 6543 scf_matchkey_t *key; 6544 for (key = htable[i]; key != NULL; key = key->sk_next) 6545 key->sk_seen = 0; 6546 } 6547 6548 /* 6549 * Iterate over all the FMRIs in our hash table and execute the 6550 * callback. 6551 */ 6552 for (i = 0; i < argc; i++) { 6553 scf_match_t *match; 6554 scf_matchkey_t *key; 6555 6556 /* 6557 * Ignore patterns which didn't match anything or matched too 6558 * many FMRIs. 6559 */ 6560 if (pattern[i].sp_matchcount == 0 || 6561 (!(flags & SCF_WALK_MULTIPLE) && 6562 pattern[i].sp_matchcount > 1)) 6563 continue; 6564 6565 for (match = pattern[i].sp_matches; match != NULL; 6566 match = match->sm_next) { 6567 6568 key = match->sm_key; 6569 if (key->sk_seen) 6570 continue; 6571 6572 key->sk_seen = 1; 6573 6574 if (key->sk_legacy != NULL) { 6575 if (scf_scope_get_service(scope, 6576 "smf/legacy_run", svc) != 0) { 6577 ret = scf_error(); 6578 goto error; 6579 } 6580 6581 if (scf_service_get_pg(svc, key->sk_legacy, 6582 pg) != 0) 6583 continue; 6584 6585 info.fmri = key->sk_fmri; 6586 info.scope = scope; 6587 info.svc = NULL; 6588 info.inst = NULL; 6589 info.pg = pg; 6590 info.prop = NULL; 6591 if ((ret = callback(data, &info)) != 0) 6592 goto error; 6593 } else { 6594 if (scf_handle_decode_fmri(h, key->sk_fmri, 6595 scope, svc, inst, pg, prop, 0) != 6596 SCF_SUCCESS) 6597 continue; 6598 6599 info.fmri = key->sk_fmri; 6600 info.scope = scope; 6601 info.svc = svc; 6602 if (scf_instance_get_name(inst, NULL, 0) < 0) { 6603 if (scf_error() == 6604 SCF_ERROR_CONNECTION_BROKEN) { 6605 ret = scf_error(); 6606 goto error; 6607 } 6608 info.inst = NULL; 6609 } else { 6610 info.inst = inst; 6611 } 6612 if (scf_pg_get_name(pg, NULL, 0) < 0) { 6613 if (scf_error() == 6614 SCF_ERROR_CONNECTION_BROKEN) { 6615 ret = scf_error(); 6616 goto error; 6617 } 6618 info.pg = NULL; 6619 } else { 6620 info.pg = pg; 6621 } 6622 if (scf_property_get_name(prop, NULL, 0) < 0) { 6623 if (scf_error() == 6624 SCF_ERROR_CONNECTION_BROKEN) { 6625 ret = scf_error(); 6626 goto error; 6627 } 6628 info.prop = NULL; 6629 } else { 6630 info.prop = prop; 6631 } 6632 6633 if ((ret = callback(data, &info)) != 0) 6634 goto error; 6635 } 6636 } 6637 } 6638 6639 error: 6640 if (htable) { 6641 scf_matchkey_t *key, *next; 6642 6643 for (i = 0; i < WALK_HTABLE_SIZE; i++) { 6644 6645 for (key = htable[i]; key != NULL; 6646 key = next) { 6647 6648 next = key->sk_next; 6649 6650 if (key->sk_fmri != NULL) 6651 free(key->sk_fmri); 6652 if (key->sk_legacy != NULL) 6653 free(key->sk_legacy); 6654 free(key); 6655 } 6656 } 6657 free(htable); 6658 } 6659 if (pattern != NULL) { 6660 for (i = 0; i < argc; i++) { 6661 scf_match_t *match, *next; 6662 6663 if (pattern[i].sp_arg != NULL) 6664 free(pattern[i].sp_arg); 6665 6666 for (match = pattern[i].sp_matches; match != NULL; 6667 match = next) { 6668 6669 next = match->sm_next; 6670 6671 free(match); 6672 } 6673 } 6674 free(pattern); 6675 } 6676 6677 free(fmri); 6678 free(pgname); 6679 6680 scf_value_destroy(value); 6681 scf_property_destroy(prop); 6682 scf_pg_destroy(pg); 6683 scf_scope_destroy(scope); 6684 scf_iter_destroy(siter); 6685 scf_iter_destroy(sciter); 6686 scf_iter_destroy(iter); 6687 scf_instance_destroy(inst); 6688 scf_service_destroy(svc); 6689 6690 return (ret); 6691 } 6692 6693 /* 6694 * _scf_request_backup: a simple wrapper routine 6695 */ 6696 int 6697 _scf_request_backup(scf_handle_t *h, const char *name) 6698 { 6699 struct rep_protocol_backup_request request; 6700 struct rep_protocol_response response; 6701 6702 int r; 6703 6704 if (strlcpy(request.rpr_name, name, sizeof (request.rpr_name)) >= 6705 sizeof (request.rpr_name)) 6706 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 6707 6708 (void) pthread_mutex_lock(&h->rh_lock); 6709 request.rpr_request = REP_PROTOCOL_BACKUP; 6710 request.rpr_changeid = handle_next_changeid(h); 6711 6712 r = make_door_call(h, &request, sizeof (request), 6713 &response, sizeof (response)); 6714 (void) pthread_mutex_unlock(&h->rh_lock); 6715 6716 if (r < 0) { 6717 DOOR_ERRORS_BLOCK(r); 6718 } 6719 6720 if (response.rpr_response != REP_PROTOCOL_SUCCESS) 6721 return (scf_set_error(proto_error(response.rpr_response))); 6722 return (SCF_SUCCESS); 6723 } 6724