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