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