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