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