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