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