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