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