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