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