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_type(base, type)) 3537 return (scf_set_error(SCF_ERROR_TYPE_MISMATCH)); 3538 } 3539 return (ret); 3540 } 3541 3542 ssize_t 3543 scf_property_get_name(const scf_property_t *prop, char *out, size_t len) 3544 { 3545 return (datael_get_name(&prop->rd_d, out, len, RP_ENTITY_NAME_NAME)); 3546 } 3547 3548 /* 3549 * transaction functions 3550 */ 3551 3552 /* 3553 * Fails with _NO_MEMORY, _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, 3554 * _INTERNAL (bad server response or id in use), or _NO_RESOURCES. 3555 */ 3556 scf_transaction_t * 3557 scf_transaction_create(scf_handle_t *handle) 3558 { 3559 scf_transaction_t *ret; 3560 3561 ret = uu_zalloc(sizeof (scf_transaction_t)); 3562 if (ret == NULL) { 3563 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 3564 return (NULL); 3565 } 3566 if (datael_init(&ret->tran_pg.rd_d, handle, 3567 REP_PROTOCOL_ENTITY_PROPERTYGRP) == -1) { 3568 uu_free(ret); 3569 return (NULL); /* error already set */ 3570 } 3571 ret->tran_state = TRAN_STATE_NEW; 3572 ret->tran_props = uu_list_create(tran_entry_pool, ret, UU_LIST_SORTED); 3573 if (ret->tran_props == NULL) { 3574 datael_destroy(&ret->tran_pg.rd_d); 3575 uu_free(ret); 3576 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 3577 return (NULL); 3578 } 3579 3580 return (ret); 3581 } 3582 3583 scf_handle_t * 3584 scf_transaction_handle(const scf_transaction_t *val) 3585 { 3586 return (handle_get(val->tran_pg.rd_d.rd_handle)); 3587 } 3588 3589 int 3590 scf_transaction_start(scf_transaction_t *tran, scf_propertygroup_t *pg) 3591 { 3592 scf_handle_t *h = tran->tran_pg.rd_d.rd_handle; 3593 3594 struct rep_protocol_transaction_start request; 3595 struct rep_protocol_response response; 3596 int r; 3597 3598 if (h != pg->rd_d.rd_handle) 3599 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH)); 3600 3601 (void) pthread_mutex_lock(&h->rh_lock); 3602 if (tran->tran_state != TRAN_STATE_NEW) { 3603 (void) pthread_mutex_unlock(&h->rh_lock); 3604 return (scf_set_error(SCF_ERROR_IN_USE)); 3605 } 3606 request.rpr_request = REP_PROTOCOL_PROPERTYGRP_TX_START; 3607 request.rpr_entityid_tx = tran->tran_pg.rd_d.rd_entity; 3608 request.rpr_entityid = pg->rd_d.rd_entity; 3609 3610 datael_finish_reset(&tran->tran_pg.rd_d); 3611 datael_finish_reset(&pg->rd_d); 3612 3613 r = make_door_call(h, &request, sizeof (request), 3614 &response, sizeof (response)); 3615 3616 if (r < 0) { 3617 (void) pthread_mutex_unlock(&h->rh_lock); 3618 DOOR_ERRORS_BLOCK(r); 3619 } 3620 3621 /* r < sizeof (response) cannot happen because sizeof (response) == 4 */ 3622 3623 if (response.rpr_response != REP_PROTOCOL_SUCCESS || 3624 r < sizeof (response)) { 3625 (void) pthread_mutex_unlock(&h->rh_lock); 3626 return (scf_set_error(proto_error(response.rpr_response))); 3627 } 3628 3629 tran->tran_state = TRAN_STATE_SETUP; 3630 tran->tran_invalid = 0; 3631 (void) pthread_mutex_unlock(&h->rh_lock); 3632 return (SCF_SUCCESS); 3633 } 3634 3635 static void 3636 entry_invalidate(scf_transaction_entry_t *cur, int and_destroy, 3637 int and_reset_value) 3638 { 3639 scf_value_t *v, *next; 3640 scf_transaction_t *tx; 3641 scf_handle_t *h = cur->entry_handle; 3642 3643 assert(MUTEX_HELD(&h->rh_lock)); 3644 3645 if ((tx = cur->entry_tx) != NULL) { 3646 tx->tran_invalid = 1; 3647 uu_list_remove(tx->tran_props, cur); 3648 cur->entry_tx = NULL; 3649 } 3650 3651 cur->entry_property = NULL; 3652 cur->entry_state = ENTRY_STATE_INVALID; 3653 cur->entry_action = REP_PROTOCOL_TX_ENTRY_INVALID; 3654 cur->entry_type = REP_PROTOCOL_TYPE_INVALID; 3655 3656 for (v = cur->entry_head; v != NULL; v = next) { 3657 next = v->value_next; 3658 v->value_tx = NULL; 3659 v->value_next = NULL; 3660 if (and_destroy || and_reset_value) 3661 scf_value_reset_locked(v, and_destroy); 3662 } 3663 cur->entry_head = NULL; 3664 cur->entry_tail = NULL; 3665 } 3666 3667 static void 3668 entry_destroy_locked(scf_transaction_entry_t *entry) 3669 { 3670 scf_handle_t *h = entry->entry_handle; 3671 3672 assert(MUTEX_HELD(&h->rh_lock)); 3673 3674 entry_invalidate(entry, 0, 0); 3675 3676 entry->entry_handle = NULL; 3677 assert(h->rh_entries > 0); 3678 --h->rh_entries; 3679 --h->rh_extrefs; 3680 uu_list_node_fini(entry, &entry->entry_link, tran_entry_pool); 3681 uu_free(entry); 3682 } 3683 3684 /* 3685 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND, 3686 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES, 3687 * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH. 3688 */ 3689 static int 3690 transaction_add(scf_transaction_t *tran, scf_transaction_entry_t *entry, 3691 enum rep_protocol_transaction_action action, 3692 const char *prop, rep_protocol_value_type_t type) 3693 { 3694 scf_handle_t *h = tran->tran_pg.rd_d.rd_handle; 3695 scf_transaction_entry_t *old; 3696 scf_property_t *prop_p; 3697 rep_protocol_value_type_t oldtype; 3698 scf_error_t error = SCF_ERROR_NONE; 3699 int ret; 3700 uu_list_index_t idx; 3701 3702 if (h != entry->entry_handle) 3703 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH)); 3704 3705 if (action == REP_PROTOCOL_TX_ENTRY_DELETE) 3706 assert(type == REP_PROTOCOL_TYPE_INVALID); 3707 else if (type == REP_PROTOCOL_TYPE_INVALID) 3708 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 3709 3710 prop_p = HANDLE_HOLD_PROPERTY(h); 3711 3712 (void) pthread_mutex_lock(&h->rh_lock); 3713 if (tran->tran_state != TRAN_STATE_SETUP) { 3714 error = SCF_ERROR_NOT_SET; 3715 goto error; 3716 } 3717 if (tran->tran_invalid) { 3718 error = SCF_ERROR_NOT_SET; 3719 goto error; 3720 } 3721 3722 if (entry->entry_state != ENTRY_STATE_INVALID) 3723 entry_invalidate(entry, 0, 0); 3724 3725 old = uu_list_find(tran->tran_props, &prop, NULL, &idx); 3726 if (old != NULL) { 3727 error = SCF_ERROR_IN_USE; 3728 goto error; 3729 } 3730 3731 ret = datael_get_child_locked(&tran->tran_pg.rd_d, prop, 3732 REP_PROTOCOL_ENTITY_PROPERTY, &prop_p->rd_d); 3733 if (ret == -1 && (error = scf_error()) != SCF_ERROR_NOT_FOUND) { 3734 goto error; 3735 } 3736 3737 switch (action) { 3738 case REP_PROTOCOL_TX_ENTRY_DELETE: 3739 if (ret == -1) { 3740 error = SCF_ERROR_NOT_FOUND; 3741 goto error; 3742 } 3743 break; 3744 case REP_PROTOCOL_TX_ENTRY_NEW: 3745 if (ret != -1) { 3746 error = SCF_ERROR_EXISTS; 3747 goto error; 3748 } 3749 break; 3750 3751 case REP_PROTOCOL_TX_ENTRY_CLEAR: 3752 case REP_PROTOCOL_TX_ENTRY_REPLACE: 3753 if (ret == -1) { 3754 error = SCF_ERROR_NOT_FOUND; 3755 goto error; 3756 } 3757 if (action == REP_PROTOCOL_TX_ENTRY_CLEAR) { 3758 if (property_type_locked(prop_p, &oldtype) == -1) { 3759 error = scf_error(); 3760 goto error; 3761 } 3762 if (oldtype != type) { 3763 error = SCF_ERROR_TYPE_MISMATCH; 3764 goto error; 3765 } 3766 } 3767 break; 3768 default: 3769 assert(0); 3770 abort(); 3771 } 3772 3773 (void) strlcpy(entry->entry_namebuf, prop, 3774 sizeof (entry->entry_namebuf)); 3775 entry->entry_property = entry->entry_namebuf; 3776 entry->entry_action = action; 3777 entry->entry_type = type; 3778 3779 entry->entry_state = ENTRY_STATE_IN_TX_ACTION; 3780 entry->entry_tx = tran; 3781 uu_list_insert(tran->tran_props, entry, idx); 3782 3783 (void) pthread_mutex_unlock(&h->rh_lock); 3784 3785 HANDLE_RELE_PROPERTY(h); 3786 3787 return (SCF_SUCCESS); 3788 3789 error: 3790 (void) pthread_mutex_unlock(&h->rh_lock); 3791 3792 HANDLE_RELE_PROPERTY(h); 3793 3794 return (scf_set_error(error)); 3795 } 3796 3797 /* 3798 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND, 3799 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES, 3800 * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH. 3801 */ 3802 int 3803 scf_transaction_property_new(scf_transaction_t *tx, 3804 scf_transaction_entry_t *entry, const char *prop, scf_type_t type) 3805 { 3806 return (transaction_add(tx, entry, REP_PROTOCOL_TX_ENTRY_NEW, 3807 prop, scf_type_to_protocol_type(type))); 3808 } 3809 3810 /* 3811 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND, 3812 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES, 3813 * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH. 3814 */ 3815 int 3816 scf_transaction_property_change(scf_transaction_t *tx, 3817 scf_transaction_entry_t *entry, const char *prop, scf_type_t type) 3818 { 3819 return (transaction_add(tx, entry, REP_PROTOCOL_TX_ENTRY_CLEAR, 3820 prop, scf_type_to_protocol_type(type))); 3821 } 3822 3823 /* 3824 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND, 3825 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES, 3826 * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH. 3827 */ 3828 int 3829 scf_transaction_property_change_type(scf_transaction_t *tx, 3830 scf_transaction_entry_t *entry, const char *prop, scf_type_t type) 3831 { 3832 return (transaction_add(tx, entry, REP_PROTOCOL_TX_ENTRY_REPLACE, 3833 prop, scf_type_to_protocol_type(type))); 3834 } 3835 3836 /* 3837 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND, 3838 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES, 3839 * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH. 3840 */ 3841 int 3842 scf_transaction_property_delete(scf_transaction_t *tx, 3843 scf_transaction_entry_t *entry, const char *prop) 3844 { 3845 return (transaction_add(tx, entry, REP_PROTOCOL_TX_ENTRY_DELETE, 3846 prop, REP_PROTOCOL_TYPE_INVALID)); 3847 } 3848 3849 #define BAD_SIZE (-1UL) 3850 3851 static size_t 3852 commit_value(caddr_t data, scf_value_t *val, rep_protocol_value_type_t t) 3853 { 3854 size_t len; 3855 3856 assert(val->value_type == t); 3857 3858 if (t == REP_PROTOCOL_TYPE_OPAQUE) { 3859 len = scf_opaque_encode(data, val->value_value, 3860 val->value_size); 3861 } else { 3862 if (data != NULL) 3863 len = strlcpy(data, val->value_value, 3864 REP_PROTOCOL_VALUE_LEN); 3865 else 3866 len = strlen(val->value_value); 3867 if (len >= REP_PROTOCOL_VALUE_LEN) 3868 return (BAD_SIZE); 3869 } 3870 return (len + 1); /* count the '\0' */ 3871 } 3872 3873 static size_t 3874 commit_process(scf_transaction_entry_t *cur, 3875 struct rep_protocol_transaction_cmd *out) 3876 { 3877 scf_value_t *child; 3878 size_t sz = 0; 3879 size_t len; 3880 caddr_t data = (caddr_t)out->rptc_data; 3881 caddr_t val_data; 3882 3883 if (out != NULL) { 3884 len = strlcpy(data, cur->entry_property, REP_PROTOCOL_NAME_LEN); 3885 3886 out->rptc_action = cur->entry_action; 3887 out->rptc_type = cur->entry_type; 3888 out->rptc_name_len = len + 1; 3889 } else { 3890 len = strlen(cur->entry_property); 3891 } 3892 3893 if (len >= REP_PROTOCOL_NAME_LEN) 3894 return (BAD_SIZE); 3895 3896 len = TX_SIZE(len + 1); 3897 3898 sz += len; 3899 val_data = data + len; 3900 3901 for (child = cur->entry_head; child != NULL; 3902 child = child->value_next) { 3903 assert(cur->entry_action != REP_PROTOCOL_TX_ENTRY_DELETE); 3904 if (out != NULL) { 3905 len = commit_value(val_data + sizeof (uint32_t), child, 3906 cur->entry_type); 3907 /* LINTED alignment */ 3908 *(uint32_t *)val_data = len; 3909 } else 3910 len = commit_value(NULL, child, cur->entry_type); 3911 3912 if (len == BAD_SIZE) 3913 return (BAD_SIZE); 3914 3915 len += sizeof (uint32_t); 3916 len = TX_SIZE(len); 3917 3918 sz += len; 3919 val_data += len; 3920 } 3921 3922 assert(val_data - data == sz); 3923 3924 if (out != NULL) 3925 out->rptc_size = REP_PROTOCOL_TRANSACTION_CMD_SIZE(sz); 3926 3927 return (REP_PROTOCOL_TRANSACTION_CMD_SIZE(sz)); 3928 } 3929 3930 int 3931 scf_transaction_commit(scf_transaction_t *tran) 3932 { 3933 scf_handle_t *h = tran->tran_pg.rd_d.rd_handle; 3934 3935 struct rep_protocol_transaction_commit *request; 3936 struct rep_protocol_response response; 3937 uintptr_t cmd; 3938 scf_transaction_entry_t *cur; 3939 size_t total, size; 3940 size_t request_size; 3941 size_t new_total; 3942 int r; 3943 3944 (void) pthread_mutex_lock(&h->rh_lock); 3945 if (tran->tran_state != TRAN_STATE_SETUP || 3946 tran->tran_invalid) { 3947 (void) pthread_mutex_unlock(&h->rh_lock); 3948 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 3949 } 3950 3951 total = 0; 3952 for (cur = uu_list_first(tran->tran_props); cur != NULL; 3953 cur = uu_list_next(tran->tran_props, cur)) { 3954 size = commit_process(cur, NULL); 3955 if (size == BAD_SIZE) { 3956 (void) pthread_mutex_unlock(&h->rh_lock); 3957 return (scf_set_error(SCF_ERROR_INTERNAL)); 3958 } 3959 assert(TX_SIZE(size) == size); 3960 total += size; 3961 } 3962 3963 request_size = REP_PROTOCOL_TRANSACTION_COMMIT_SIZE(total); 3964 request = alloca(request_size); 3965 (void) memset(request, '\0', request_size); 3966 request->rpr_request = REP_PROTOCOL_PROPERTYGRP_TX_COMMIT; 3967 request->rpr_entityid = tran->tran_pg.rd_d.rd_entity; 3968 request->rpr_size = request_size; 3969 cmd = (uintptr_t)request->rpr_cmd; 3970 3971 datael_finish_reset(&tran->tran_pg.rd_d); 3972 3973 new_total = 0; 3974 for (cur = uu_list_first(tran->tran_props); cur != NULL; 3975 cur = uu_list_next(tran->tran_props, cur)) { 3976 size = commit_process(cur, (void *)cmd); 3977 if (size == BAD_SIZE) { 3978 (void) pthread_mutex_unlock(&h->rh_lock); 3979 return (scf_set_error(SCF_ERROR_INTERNAL)); 3980 } 3981 cmd += size; 3982 new_total += size; 3983 } 3984 assert(new_total == total); 3985 3986 r = make_door_call(h, request, request_size, 3987 &response, sizeof (response)); 3988 3989 if (r < 0) { 3990 (void) pthread_mutex_unlock(&h->rh_lock); 3991 DOOR_ERRORS_BLOCK(r); 3992 } 3993 3994 if (response.rpr_response != REP_PROTOCOL_SUCCESS && 3995 response.rpr_response != REP_PROTOCOL_FAIL_NOT_LATEST) { 3996 (void) pthread_mutex_unlock(&h->rh_lock); 3997 return (scf_set_error(proto_error(response.rpr_response))); 3998 } 3999 4000 tran->tran_state = TRAN_STATE_COMMITTED; 4001 (void) pthread_mutex_unlock(&h->rh_lock); 4002 return (response.rpr_response == REP_PROTOCOL_SUCCESS); 4003 } 4004 4005 static void 4006 transaction_reset(scf_transaction_t *tran) 4007 { 4008 assert(MUTEX_HELD(&tran->tran_pg.rd_d.rd_handle->rh_lock)); 4009 4010 tran->tran_state = TRAN_STATE_NEW; 4011 datael_reset_locked(&tran->tran_pg.rd_d); 4012 } 4013 4014 static void 4015 scf_transaction_reset_impl(scf_transaction_t *tran, int and_destroy, 4016 int and_reset_value) 4017 { 4018 scf_transaction_entry_t *cur; 4019 void *cookie; 4020 4021 (void) pthread_mutex_lock(&tran->tran_pg.rd_d.rd_handle->rh_lock); 4022 cookie = NULL; 4023 while ((cur = uu_list_teardown(tran->tran_props, &cookie)) != NULL) { 4024 cur->entry_tx = NULL; 4025 4026 assert(cur->entry_state == ENTRY_STATE_IN_TX_ACTION); 4027 cur->entry_state = ENTRY_STATE_INVALID; 4028 4029 entry_invalidate(cur, and_destroy, and_reset_value); 4030 if (and_destroy) 4031 entry_destroy_locked(cur); 4032 } 4033 transaction_reset(tran); 4034 handle_unrefed(tran->tran_pg.rd_d.rd_handle); 4035 } 4036 4037 void 4038 scf_transaction_reset(scf_transaction_t *tran) 4039 { 4040 scf_transaction_reset_impl(tran, 0, 0); 4041 } 4042 4043 void 4044 scf_transaction_reset_all(scf_transaction_t *tran) 4045 { 4046 scf_transaction_reset_impl(tran, 0, 1); 4047 } 4048 4049 void 4050 scf_transaction_destroy(scf_transaction_t *val) 4051 { 4052 if (val == NULL) 4053 return; 4054 4055 scf_transaction_reset(val); 4056 4057 datael_destroy(&val->tran_pg.rd_d); 4058 4059 uu_list_destroy(val->tran_props); 4060 uu_free(val); 4061 } 4062 4063 void 4064 scf_transaction_destroy_children(scf_transaction_t *tran) 4065 { 4066 scf_transaction_reset_impl(tran, 1, 0); 4067 } 4068 4069 scf_transaction_entry_t * 4070 scf_entry_create(scf_handle_t *h) 4071 { 4072 scf_transaction_entry_t *ret; 4073 4074 if (h == NULL) { 4075 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 4076 return (NULL); 4077 } 4078 4079 ret = uu_zalloc(sizeof (scf_transaction_entry_t)); 4080 if (ret == NULL) { 4081 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 4082 return (NULL); 4083 } 4084 ret->entry_action = REP_PROTOCOL_TX_ENTRY_INVALID; 4085 ret->entry_handle = h; 4086 4087 (void) pthread_mutex_lock(&h->rh_lock); 4088 if (h->rh_flags & HANDLE_DEAD) { 4089 (void) pthread_mutex_unlock(&h->rh_lock); 4090 uu_free(ret); 4091 (void) scf_set_error(SCF_ERROR_HANDLE_DESTROYED); 4092 return (NULL); 4093 } 4094 h->rh_entries++; 4095 h->rh_extrefs++; 4096 (void) pthread_mutex_unlock(&h->rh_lock); 4097 4098 uu_list_node_init(ret, &ret->entry_link, tran_entry_pool); 4099 4100 return (ret); 4101 } 4102 4103 scf_handle_t * 4104 scf_entry_handle(const scf_transaction_entry_t *val) 4105 { 4106 return (handle_get(val->entry_handle)); 4107 } 4108 4109 void 4110 scf_entry_reset(scf_transaction_entry_t *entry) 4111 { 4112 scf_handle_t *h = entry->entry_handle; 4113 4114 (void) pthread_mutex_lock(&h->rh_lock); 4115 entry_invalidate(entry, 0, 0); 4116 (void) pthread_mutex_unlock(&h->rh_lock); 4117 } 4118 4119 void 4120 scf_entry_destroy_children(scf_transaction_entry_t *entry) 4121 { 4122 scf_handle_t *h = entry->entry_handle; 4123 4124 (void) pthread_mutex_lock(&h->rh_lock); 4125 entry_invalidate(entry, 1, 0); 4126 handle_unrefed(h); /* drops h->rh_lock */ 4127 } 4128 4129 void 4130 scf_entry_destroy(scf_transaction_entry_t *entry) 4131 { 4132 scf_handle_t *h; 4133 4134 if (entry == NULL) 4135 return; 4136 4137 h = entry->entry_handle; 4138 4139 (void) pthread_mutex_lock(&h->rh_lock); 4140 entry_destroy_locked(entry); 4141 handle_unrefed(h); /* drops h->rh_lock */ 4142 } 4143 4144 /* 4145 * Fails with 4146 * _HANDLE_MISMATCH 4147 * _NOT_SET - has not been added to a transaction 4148 * _INTERNAL - entry is corrupt 4149 * _INVALID_ARGUMENT - entry's transaction is not started or corrupt 4150 * entry is set to delete a property 4151 * v is reset or corrupt 4152 * _TYPE_MISMATCH - entry & v's types aren't compatible 4153 * _IN_USE - v has been added to another entry 4154 */ 4155 int 4156 scf_entry_add_value(scf_transaction_entry_t *entry, scf_value_t *v) 4157 { 4158 scf_handle_t *h = entry->entry_handle; 4159 4160 if (h != v->value_handle) 4161 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH)); 4162 4163 (void) pthread_mutex_lock(&h->rh_lock); 4164 4165 if (entry->entry_state == ENTRY_STATE_INVALID) { 4166 (void) pthread_mutex_unlock(&h->rh_lock); 4167 return (scf_set_error(SCF_ERROR_NOT_SET)); 4168 } 4169 4170 if (entry->entry_state != ENTRY_STATE_IN_TX_ACTION) { 4171 (void) pthread_mutex_unlock(&h->rh_lock); 4172 return (scf_set_error(SCF_ERROR_INTERNAL)); 4173 } 4174 4175 if (entry->entry_tx->tran_state != TRAN_STATE_SETUP) { 4176 (void) pthread_mutex_unlock(&h->rh_lock); 4177 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 4178 } 4179 4180 if (entry->entry_action == REP_PROTOCOL_TX_ENTRY_DELETE) { 4181 (void) pthread_mutex_unlock(&h->rh_lock); 4182 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 4183 } 4184 4185 if (v->value_type == REP_PROTOCOL_TYPE_INVALID) { 4186 (void) pthread_mutex_unlock(&h->rh_lock); 4187 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 4188 } 4189 4190 if (!scf_is_compatible_type(entry->entry_type, v->value_type)) { 4191 (void) pthread_mutex_unlock(&h->rh_lock); 4192 return (scf_set_error(SCF_ERROR_TYPE_MISMATCH)); 4193 } 4194 4195 if (v->value_tx != NULL) { 4196 (void) pthread_mutex_unlock(&h->rh_lock); 4197 return (scf_set_error(SCF_ERROR_IN_USE)); 4198 } 4199 4200 v->value_tx = entry; 4201 v->value_next = NULL; 4202 if (entry->entry_head == NULL) { 4203 entry->entry_head = v; 4204 entry->entry_tail = v; 4205 } else { 4206 entry->entry_tail->value_next = v; 4207 entry->entry_tail = v; 4208 } 4209 4210 (void) pthread_mutex_unlock(&h->rh_lock); 4211 4212 return (SCF_SUCCESS); 4213 } 4214 4215 /* 4216 * value functions 4217 */ 4218 scf_value_t * 4219 scf_value_create(scf_handle_t *h) 4220 { 4221 scf_value_t *ret; 4222 4223 if (h == NULL) { 4224 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 4225 return (NULL); 4226 } 4227 4228 ret = uu_zalloc(sizeof (*ret)); 4229 if (ret != NULL) { 4230 ret->value_type = REP_PROTOCOL_TYPE_INVALID; 4231 ret->value_handle = h; 4232 (void) pthread_mutex_lock(&h->rh_lock); 4233 if (h->rh_flags & HANDLE_DEAD) { 4234 (void) pthread_mutex_unlock(&h->rh_lock); 4235 uu_free(ret); 4236 (void) scf_set_error(SCF_ERROR_HANDLE_DESTROYED); 4237 return (NULL); 4238 } 4239 h->rh_values++; 4240 h->rh_extrefs++; 4241 (void) pthread_mutex_unlock(&h->rh_lock); 4242 } else { 4243 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 4244 } 4245 4246 return (ret); 4247 } 4248 4249 static void 4250 scf_value_reset_locked(scf_value_t *val, int and_destroy) 4251 { 4252 scf_value_t **curp; 4253 scf_transaction_entry_t *te; 4254 4255 scf_handle_t *h = val->value_handle; 4256 assert(MUTEX_HELD(&h->rh_lock)); 4257 if (val->value_tx != NULL) { 4258 te = val->value_tx; 4259 te->entry_tx->tran_invalid = 1; 4260 4261 val->value_tx = NULL; 4262 4263 for (curp = &te->entry_head; *curp != NULL; 4264 curp = &(*curp)->value_next) { 4265 if (*curp == val) { 4266 *curp = val->value_next; 4267 curp = NULL; 4268 break; 4269 } 4270 } 4271 assert(curp == NULL); 4272 } 4273 val->value_type = REP_PROTOCOL_TYPE_INVALID; 4274 4275 if (and_destroy) { 4276 val->value_handle = NULL; 4277 assert(h->rh_values > 0); 4278 --h->rh_values; 4279 --h->rh_extrefs; 4280 uu_free(val); 4281 } 4282 } 4283 4284 void 4285 scf_value_reset(scf_value_t *val) 4286 { 4287 scf_handle_t *h = val->value_handle; 4288 4289 (void) pthread_mutex_lock(&h->rh_lock); 4290 scf_value_reset_locked(val, 0); 4291 (void) pthread_mutex_unlock(&h->rh_lock); 4292 } 4293 4294 scf_handle_t * 4295 scf_value_handle(const scf_value_t *val) 4296 { 4297 return (handle_get(val->value_handle)); 4298 } 4299 4300 void 4301 scf_value_destroy(scf_value_t *val) 4302 { 4303 scf_handle_t *h; 4304 4305 if (val == NULL) 4306 return; 4307 4308 h = val->value_handle; 4309 4310 (void) pthread_mutex_lock(&h->rh_lock); 4311 scf_value_reset_locked(val, 1); 4312 handle_unrefed(h); /* drops h->rh_lock */ 4313 } 4314 4315 scf_type_t 4316 scf_value_base_type(const scf_value_t *val) 4317 { 4318 rep_protocol_value_type_t t, cur; 4319 scf_handle_t *h = val->value_handle; 4320 4321 (void) pthread_mutex_lock(&h->rh_lock); 4322 t = val->value_type; 4323 (void) pthread_mutex_unlock(&h->rh_lock); 4324 4325 for (;;) { 4326 cur = scf_proto_underlying_type(t); 4327 if (cur == t) 4328 break; 4329 t = cur; 4330 } 4331 4332 return (scf_protocol_type_to_type(t)); 4333 } 4334 4335 scf_type_t 4336 scf_value_type(const scf_value_t *val) 4337 { 4338 rep_protocol_value_type_t t; 4339 scf_handle_t *h = val->value_handle; 4340 4341 (void) pthread_mutex_lock(&h->rh_lock); 4342 t = val->value_type; 4343 (void) pthread_mutex_unlock(&h->rh_lock); 4344 4345 return (scf_protocol_type_to_type(t)); 4346 } 4347 4348 int 4349 scf_value_is_type(const scf_value_t *val, scf_type_t base_arg) 4350 { 4351 rep_protocol_value_type_t t; 4352 rep_protocol_value_type_t base = scf_type_to_protocol_type(base_arg); 4353 scf_handle_t *h = val->value_handle; 4354 4355 (void) pthread_mutex_lock(&h->rh_lock); 4356 t = val->value_type; 4357 (void) pthread_mutex_unlock(&h->rh_lock); 4358 4359 if (t == REP_PROTOCOL_TYPE_INVALID) 4360 return (scf_set_error(SCF_ERROR_NOT_SET)); 4361 if (base == REP_PROTOCOL_TYPE_INVALID) 4362 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 4363 if (!scf_is_compatible_type(base, t)) 4364 return (scf_set_error(SCF_ERROR_TYPE_MISMATCH)); 4365 4366 return (SCF_SUCCESS); 4367 } 4368 4369 /* 4370 * Fails with 4371 * _NOT_SET - val is reset 4372 * _TYPE_MISMATCH - val's type is not compatible with t 4373 */ 4374 static int 4375 scf_value_check_type(const scf_value_t *val, rep_protocol_value_type_t t) 4376 { 4377 if (val->value_type == REP_PROTOCOL_TYPE_INVALID) { 4378 (void) scf_set_error(SCF_ERROR_NOT_SET); 4379 return (0); 4380 } 4381 if (!scf_is_compatible_type(t, val->value_type)) { 4382 (void) scf_set_error(SCF_ERROR_TYPE_MISMATCH); 4383 return (0); 4384 } 4385 return (1); 4386 } 4387 4388 /* 4389 * Fails with 4390 * _NOT_SET - val is reset 4391 * _TYPE_MISMATCH - val is not _TYPE_BOOLEAN 4392 */ 4393 int 4394 scf_value_get_boolean(const scf_value_t *val, uint8_t *out) 4395 { 4396 char c; 4397 scf_handle_t *h = val->value_handle; 4398 uint8_t o; 4399 4400 (void) pthread_mutex_lock(&h->rh_lock); 4401 if (!scf_value_check_type(val, REP_PROTOCOL_TYPE_BOOLEAN)) { 4402 (void) pthread_mutex_unlock(&h->rh_lock); 4403 return (-1); 4404 } 4405 4406 c = val->value_value[0]; 4407 assert((c == '0' || c == '1') && val->value_value[1] == 0); 4408 4409 o = (c != '0'); 4410 (void) pthread_mutex_unlock(&h->rh_lock); 4411 if (out != NULL) 4412 *out = o; 4413 return (SCF_SUCCESS); 4414 } 4415 4416 int 4417 scf_value_get_count(const scf_value_t *val, uint64_t *out) 4418 { 4419 scf_handle_t *h = val->value_handle; 4420 uint64_t o; 4421 4422 (void) pthread_mutex_lock(&h->rh_lock); 4423 if (!scf_value_check_type(val, REP_PROTOCOL_TYPE_COUNT)) { 4424 (void) pthread_mutex_unlock(&h->rh_lock); 4425 return (-1); 4426 } 4427 4428 o = strtoull(val->value_value, NULL, 10); 4429 (void) pthread_mutex_unlock(&h->rh_lock); 4430 if (out != NULL) 4431 *out = o; 4432 return (SCF_SUCCESS); 4433 } 4434 4435 int 4436 scf_value_get_integer(const scf_value_t *val, int64_t *out) 4437 { 4438 scf_handle_t *h = val->value_handle; 4439 int64_t o; 4440 4441 (void) pthread_mutex_lock(&h->rh_lock); 4442 if (!scf_value_check_type(val, REP_PROTOCOL_TYPE_INTEGER)) { 4443 (void) pthread_mutex_unlock(&h->rh_lock); 4444 return (-1); 4445 } 4446 4447 o = strtoll(val->value_value, NULL, 10); 4448 (void) pthread_mutex_unlock(&h->rh_lock); 4449 if (out != NULL) 4450 *out = o; 4451 return (SCF_SUCCESS); 4452 } 4453 4454 int 4455 scf_value_get_time(const scf_value_t *val, int64_t *sec_out, int32_t *nsec_out) 4456 { 4457 scf_handle_t *h = val->value_handle; 4458 char *p; 4459 int64_t os; 4460 int32_t ons; 4461 4462 (void) pthread_mutex_lock(&h->rh_lock); 4463 if (!scf_value_check_type(val, REP_PROTOCOL_TYPE_TIME)) { 4464 (void) pthread_mutex_unlock(&h->rh_lock); 4465 return (-1); 4466 } 4467 4468 os = strtoll(val->value_value, &p, 10); 4469 if (*p == '.') 4470 ons = strtoul(p + 1, NULL, 10); 4471 else 4472 ons = 0; 4473 (void) pthread_mutex_unlock(&h->rh_lock); 4474 if (sec_out != NULL) 4475 *sec_out = os; 4476 if (nsec_out != NULL) 4477 *nsec_out = ons; 4478 4479 return (SCF_SUCCESS); 4480 } 4481 4482 /* 4483 * Fails with 4484 * _NOT_SET - val is reset 4485 * _TYPE_MISMATCH - val's type is not compatible with _TYPE_STRING. 4486 */ 4487 ssize_t 4488 scf_value_get_astring(const scf_value_t *val, char *out, size_t len) 4489 { 4490 ssize_t ret; 4491 scf_handle_t *h = val->value_handle; 4492 4493 (void) pthread_mutex_lock(&h->rh_lock); 4494 if (!scf_value_check_type(val, REP_PROTOCOL_TYPE_STRING)) { 4495 (void) pthread_mutex_unlock(&h->rh_lock); 4496 return ((ssize_t)-1); 4497 } 4498 ret = (ssize_t)strlcpy(out, val->value_value, len); 4499 (void) pthread_mutex_unlock(&h->rh_lock); 4500 return (ret); 4501 } 4502 4503 ssize_t 4504 scf_value_get_ustring(const scf_value_t *val, char *out, size_t len) 4505 { 4506 ssize_t ret; 4507 scf_handle_t *h = val->value_handle; 4508 4509 (void) pthread_mutex_lock(&h->rh_lock); 4510 if (!scf_value_check_type(val, REP_PROTOCOL_SUBTYPE_USTRING)) { 4511 (void) pthread_mutex_unlock(&h->rh_lock); 4512 return ((ssize_t)-1); 4513 } 4514 ret = (ssize_t)strlcpy(out, val->value_value, len); 4515 (void) pthread_mutex_unlock(&h->rh_lock); 4516 return (ret); 4517 } 4518 4519 ssize_t 4520 scf_value_get_opaque(const scf_value_t *v, void *out, size_t len) 4521 { 4522 ssize_t ret; 4523 scf_handle_t *h = v->value_handle; 4524 4525 (void) pthread_mutex_lock(&h->rh_lock); 4526 if (!scf_value_check_type(v, REP_PROTOCOL_TYPE_OPAQUE)) { 4527 (void) pthread_mutex_unlock(&h->rh_lock); 4528 return ((ssize_t)-1); 4529 } 4530 if (len > v->value_size) 4531 len = v->value_size; 4532 ret = len; 4533 4534 (void) memcpy(out, v->value_value, len); 4535 (void) pthread_mutex_unlock(&h->rh_lock); 4536 return (ret); 4537 } 4538 4539 void 4540 scf_value_set_boolean(scf_value_t *v, uint8_t new) 4541 { 4542 scf_handle_t *h = v->value_handle; 4543 4544 (void) pthread_mutex_lock(&h->rh_lock); 4545 scf_value_reset_locked(v, 0); 4546 v->value_type = REP_PROTOCOL_TYPE_BOOLEAN; 4547 (void) sprintf(v->value_value, "%d", (new != 0)); 4548 (void) pthread_mutex_unlock(&h->rh_lock); 4549 } 4550 4551 void 4552 scf_value_set_count(scf_value_t *v, uint64_t new) 4553 { 4554 scf_handle_t *h = v->value_handle; 4555 4556 (void) pthread_mutex_lock(&h->rh_lock); 4557 scf_value_reset_locked(v, 0); 4558 v->value_type = REP_PROTOCOL_TYPE_COUNT; 4559 (void) sprintf(v->value_value, "%llu", (unsigned long long)new); 4560 (void) pthread_mutex_unlock(&h->rh_lock); 4561 } 4562 4563 void 4564 scf_value_set_integer(scf_value_t *v, int64_t new) 4565 { 4566 scf_handle_t *h = v->value_handle; 4567 4568 (void) pthread_mutex_lock(&h->rh_lock); 4569 scf_value_reset_locked(v, 0); 4570 v->value_type = REP_PROTOCOL_TYPE_INTEGER; 4571 (void) sprintf(v->value_value, "%lld", (long long)new); 4572 (void) pthread_mutex_unlock(&h->rh_lock); 4573 } 4574 4575 int 4576 scf_value_set_time(scf_value_t *v, int64_t new_sec, int32_t new_nsec) 4577 { 4578 scf_handle_t *h = v->value_handle; 4579 4580 (void) pthread_mutex_lock(&h->rh_lock); 4581 scf_value_reset_locked(v, 0); 4582 if (new_nsec < 0 || new_nsec >= NANOSEC) { 4583 (void) pthread_mutex_unlock(&h->rh_lock); 4584 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 4585 } 4586 v->value_type = REP_PROTOCOL_TYPE_TIME; 4587 if (new_nsec == 0) 4588 (void) sprintf(v->value_value, "%lld", (long long)new_sec); 4589 else 4590 (void) sprintf(v->value_value, "%lld.%09u", (long long)new_sec, 4591 (unsigned)new_nsec); 4592 (void) pthread_mutex_unlock(&h->rh_lock); 4593 return (0); 4594 } 4595 4596 int 4597 scf_value_set_astring(scf_value_t *v, const char *new) 4598 { 4599 scf_handle_t *h = v->value_handle; 4600 4601 (void) pthread_mutex_lock(&h->rh_lock); 4602 scf_value_reset_locked(v, 0); 4603 if (!scf_validate_encoded_value(REP_PROTOCOL_TYPE_STRING, new)) { 4604 (void) pthread_mutex_unlock(&h->rh_lock); 4605 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 4606 } 4607 if (strlcpy(v->value_value, new, sizeof (v->value_value)) >= 4608 sizeof (v->value_value)) { 4609 (void) pthread_mutex_unlock(&h->rh_lock); 4610 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 4611 } 4612 v->value_type = REP_PROTOCOL_TYPE_STRING; 4613 (void) pthread_mutex_unlock(&h->rh_lock); 4614 return (0); 4615 } 4616 4617 int 4618 scf_value_set_ustring(scf_value_t *v, const char *new) 4619 { 4620 scf_handle_t *h = v->value_handle; 4621 4622 (void) pthread_mutex_lock(&h->rh_lock); 4623 scf_value_reset_locked(v, 0); 4624 if (!scf_validate_encoded_value(REP_PROTOCOL_SUBTYPE_USTRING, new)) { 4625 (void) pthread_mutex_unlock(&h->rh_lock); 4626 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 4627 } 4628 if (strlcpy(v->value_value, new, sizeof (v->value_value)) >= 4629 sizeof (v->value_value)) { 4630 (void) pthread_mutex_unlock(&h->rh_lock); 4631 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 4632 } 4633 v->value_type = REP_PROTOCOL_SUBTYPE_USTRING; 4634 (void) pthread_mutex_unlock(&h->rh_lock); 4635 return (0); 4636 } 4637 4638 int 4639 scf_value_set_opaque(scf_value_t *v, const void *new, size_t len) 4640 { 4641 scf_handle_t *h = v->value_handle; 4642 4643 (void) pthread_mutex_lock(&h->rh_lock); 4644 scf_value_reset_locked(v, 0); 4645 if (len > sizeof (v->value_value)) { 4646 (void) pthread_mutex_unlock(&h->rh_lock); 4647 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 4648 } 4649 (void) memcpy(v->value_value, new, len); 4650 v->value_size = len; 4651 v->value_type = REP_PROTOCOL_TYPE_OPAQUE; 4652 (void) pthread_mutex_unlock(&h->rh_lock); 4653 return (0); 4654 } 4655 4656 /* 4657 * Fails with 4658 * _NOT_SET - v_arg is reset 4659 * _INTERNAL - v_arg is corrupt 4660 * 4661 * If t is not _TYPE_INVALID, fails with 4662 * _TYPE_MISMATCH - v_arg's type is not compatible with t 4663 */ 4664 static ssize_t 4665 scf_value_get_as_string_common(const scf_value_t *v_arg, 4666 rep_protocol_value_type_t t, char *buf, size_t bufsz) 4667 { 4668 scf_handle_t *h = v_arg->value_handle; 4669 scf_value_t v_s; 4670 scf_value_t *v = &v_s; 4671 ssize_t r; 4672 uint8_t b; 4673 4674 (void) pthread_mutex_lock(&h->rh_lock); 4675 if (t != REP_PROTOCOL_TYPE_INVALID && !scf_value_check_type(v_arg, t)) { 4676 (void) pthread_mutex_unlock(&h->rh_lock); 4677 return (-1); 4678 } 4679 4680 v_s = *v_arg; /* copy locally so we can unlock */ 4681 h->rh_values++; /* keep the handle from going away */ 4682 h->rh_extrefs++; 4683 (void) pthread_mutex_unlock(&h->rh_lock); 4684 4685 4686 switch (REP_PROTOCOL_BASE_TYPE(v->value_type)) { 4687 case REP_PROTOCOL_TYPE_BOOLEAN: 4688 r = scf_value_get_boolean(v, &b); 4689 assert(r == SCF_SUCCESS); 4690 4691 r = strlcpy(buf, b ? "true" : "false", bufsz); 4692 break; 4693 4694 case REP_PROTOCOL_TYPE_COUNT: 4695 case REP_PROTOCOL_TYPE_INTEGER: 4696 case REP_PROTOCOL_TYPE_TIME: 4697 case REP_PROTOCOL_TYPE_STRING: 4698 r = strlcpy(buf, v->value_value, bufsz); 4699 break; 4700 4701 case REP_PROTOCOL_TYPE_OPAQUE: 4702 /* 4703 * Note that we only write out full hex bytes -- if they're 4704 * short, and bufsz is even, we'll only fill (bufsz - 2) bytes 4705 * with data. 4706 */ 4707 if (bufsz > 0) 4708 (void) scf_opaque_encode(buf, v->value_value, 4709 MIN(v->value_size, (bufsz - 1)/2)); 4710 r = (v->value_size * 2); 4711 break; 4712 4713 case REP_PROTOCOL_TYPE_INVALID: 4714 r = scf_set_error(SCF_ERROR_NOT_SET); 4715 break; 4716 4717 default: 4718 r = (scf_set_error(SCF_ERROR_INTERNAL)); 4719 break; 4720 } 4721 4722 (void) pthread_mutex_lock(&h->rh_lock); 4723 h->rh_values--; 4724 h->rh_extrefs--; 4725 handle_unrefed(h); 4726 4727 return (r); 4728 } 4729 4730 ssize_t 4731 scf_value_get_as_string(const scf_value_t *v, char *buf, size_t bufsz) 4732 { 4733 return (scf_value_get_as_string_common(v, REP_PROTOCOL_TYPE_INVALID, 4734 buf, bufsz)); 4735 } 4736 4737 ssize_t 4738 scf_value_get_as_string_typed(const scf_value_t *v, scf_type_t type, 4739 char *buf, size_t bufsz) 4740 { 4741 rep_protocol_value_type_t ty = scf_type_to_protocol_type(type); 4742 if (ty == REP_PROTOCOL_TYPE_INVALID) 4743 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 4744 4745 return (scf_value_get_as_string_common(v, ty, buf, bufsz)); 4746 } 4747 4748 int 4749 scf_value_set_from_string(scf_value_t *v, scf_type_t type, const char *str) 4750 { 4751 scf_handle_t *h = v->value_handle; 4752 rep_protocol_value_type_t ty; 4753 4754 switch (type) { 4755 case SCF_TYPE_BOOLEAN: { 4756 uint8_t b; 4757 4758 if (strcmp(str, "true") == 0 || strcmp(str, "t") == 0 || 4759 strcmp(str, "1") == 0) 4760 b = 1; 4761 else if (strcmp(str, "false") == 0 || 4762 strcmp(str, "f") == 0 || strcmp(str, "0") == 0) 4763 b = 0; 4764 else { 4765 goto bad; 4766 } 4767 4768 scf_value_set_boolean(v, b); 4769 return (0); 4770 } 4771 4772 case SCF_TYPE_COUNT: { 4773 uint64_t c; 4774 char *endp; 4775 4776 errno = 0; 4777 c = strtoull(str, &endp, 0); 4778 4779 if (errno != 0 || endp == str || *endp != '\0') 4780 goto bad; 4781 4782 scf_value_set_count(v, c); 4783 return (0); 4784 } 4785 4786 case SCF_TYPE_INTEGER: { 4787 int64_t i; 4788 char *endp; 4789 4790 errno = 0; 4791 i = strtoll(str, &endp, 0); 4792 4793 if (errno != 0 || endp == str || *endp != '\0') 4794 goto bad; 4795 4796 scf_value_set_integer(v, i); 4797 return (0); 4798 } 4799 4800 case SCF_TYPE_TIME: { 4801 int64_t s; 4802 uint32_t ns = 0; 4803 char *endp, *ns_str; 4804 size_t len; 4805 4806 errno = 0; 4807 s = strtoll(str, &endp, 10); 4808 if (errno != 0 || endp == str || 4809 (*endp != '\0' && *endp != '.')) 4810 goto bad; 4811 4812 if (*endp == '.') { 4813 ns_str = endp + 1; 4814 len = strlen(ns_str); 4815 if (len == 0 || len > 9) 4816 goto bad; 4817 4818 ns = strtoul(ns_str, &endp, 10); 4819 if (errno != 0 || endp == ns_str || *endp != '\0') 4820 goto bad; 4821 4822 while (len++ < 9) 4823 ns *= 10; 4824 assert(ns < NANOSEC); 4825 } 4826 4827 return (scf_value_set_time(v, s, ns)); 4828 } 4829 4830 case SCF_TYPE_ASTRING: 4831 case SCF_TYPE_USTRING: 4832 case SCF_TYPE_OPAQUE: 4833 case SCF_TYPE_URI: 4834 case SCF_TYPE_FMRI: 4835 case SCF_TYPE_HOST: 4836 case SCF_TYPE_HOSTNAME: 4837 case SCF_TYPE_NET_ADDR_V4: 4838 case SCF_TYPE_NET_ADDR_V6: 4839 ty = scf_type_to_protocol_type(type); 4840 4841 (void) pthread_mutex_lock(&h->rh_lock); 4842 scf_value_reset_locked(v, 0); 4843 if (type == SCF_TYPE_OPAQUE) { 4844 v->value_size = scf_opaque_decode(v->value_value, 4845 str, sizeof (v->value_value)); 4846 if (!scf_validate_encoded_value(ty, str)) { 4847 (void) pthread_mutex_lock(&h->rh_lock); 4848 goto bad; 4849 } 4850 } else { 4851 (void) strlcpy(v->value_value, str, 4852 sizeof (v->value_value)); 4853 if (!scf_validate_encoded_value(ty, v->value_value)) { 4854 (void) pthread_mutex_lock(&h->rh_lock); 4855 goto bad; 4856 } 4857 } 4858 v->value_type = ty; 4859 (void) pthread_mutex_unlock(&h->rh_lock); 4860 return (SCF_SUCCESS); 4861 4862 case REP_PROTOCOL_TYPE_INVALID: 4863 default: 4864 scf_value_reset(v); 4865 return (scf_set_error(SCF_ERROR_TYPE_MISMATCH)); 4866 } 4867 bad: 4868 scf_value_reset(v); 4869 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 4870 } 4871 4872 int 4873 scf_iter_property_values(scf_iter_t *iter, const scf_property_t *prop) 4874 { 4875 return (datael_setup_iter(iter, &prop->rd_d, 4876 REP_PROTOCOL_ENTITY_VALUE, 0)); 4877 } 4878 4879 int 4880 scf_iter_next_value(scf_iter_t *iter, scf_value_t *v) 4881 { 4882 scf_handle_t *h = iter->iter_handle; 4883 4884 struct rep_protocol_iter_read_value request; 4885 struct rep_protocol_value_response response; 4886 4887 int r; 4888 4889 if (h != v->value_handle) 4890 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH)); 4891 4892 (void) pthread_mutex_lock(&h->rh_lock); 4893 4894 scf_value_reset_locked(v, 0); 4895 4896 if (iter->iter_type == REP_PROTOCOL_ENTITY_NONE) { 4897 (void) pthread_mutex_unlock(&h->rh_lock); 4898 return (scf_set_error(SCF_ERROR_NOT_SET)); 4899 } 4900 4901 if (iter->iter_type != REP_PROTOCOL_ENTITY_VALUE) { 4902 (void) pthread_mutex_unlock(&h->rh_lock); 4903 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 4904 } 4905 4906 request.rpr_request = REP_PROTOCOL_ITER_READ_VALUE; 4907 request.rpr_iterid = iter->iter_id; 4908 request.rpr_sequence = iter->iter_sequence; 4909 4910 r = make_door_call(h, &request, sizeof (request), 4911 &response, sizeof (response)); 4912 4913 if (r < 0) { 4914 (void) pthread_mutex_unlock(&h->rh_lock); 4915 DOOR_ERRORS_BLOCK(r); 4916 } 4917 4918 if (response.rpr_response == REP_PROTOCOL_DONE) { 4919 (void) pthread_mutex_unlock(&h->rh_lock); 4920 return (0); 4921 } 4922 if (response.rpr_response != REP_PROTOCOL_SUCCESS) { 4923 (void) pthread_mutex_unlock(&h->rh_lock); 4924 return (scf_set_error(proto_error(response.rpr_response))); 4925 } 4926 iter->iter_sequence++; 4927 4928 v->value_type = response.rpr_type; 4929 4930 assert(scf_validate_encoded_value(response.rpr_type, 4931 response.rpr_value)); 4932 4933 if (v->value_type != REP_PROTOCOL_TYPE_OPAQUE) { 4934 (void) strlcpy(v->value_value, response.rpr_value, 4935 sizeof (v->value_value)); 4936 } else { 4937 v->value_size = scf_opaque_decode(v->value_value, 4938 response.rpr_value, sizeof (v->value_value)); 4939 } 4940 (void) pthread_mutex_unlock(&h->rh_lock); 4941 4942 return (1); 4943 } 4944 4945 int 4946 scf_property_get_value(const scf_property_t *prop, scf_value_t *v) 4947 { 4948 scf_handle_t *h = prop->rd_d.rd_handle; 4949 struct rep_protocol_property_request request; 4950 struct rep_protocol_value_response response; 4951 int r; 4952 4953 if (h != v->value_handle) 4954 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH)); 4955 4956 (void) pthread_mutex_lock(&h->rh_lock); 4957 4958 request.rpr_request = REP_PROTOCOL_PROPERTY_GET_VALUE; 4959 request.rpr_entityid = prop->rd_d.rd_entity; 4960 4961 scf_value_reset_locked(v, 0); 4962 datael_finish_reset(&prop->rd_d); 4963 4964 r = make_door_call(h, &request, sizeof (request), 4965 &response, sizeof (response)); 4966 4967 if (r < 0) { 4968 (void) pthread_mutex_unlock(&h->rh_lock); 4969 DOOR_ERRORS_BLOCK(r); 4970 } 4971 4972 if (response.rpr_response != REP_PROTOCOL_SUCCESS && 4973 response.rpr_response != REP_PROTOCOL_FAIL_TRUNCATED) { 4974 (void) pthread_mutex_unlock(&h->rh_lock); 4975 assert(response.rpr_response != 4976 REP_PROTOCOL_FAIL_TYPE_MISMATCH); 4977 return (scf_set_error(proto_error(response.rpr_response))); 4978 } 4979 4980 v->value_type = response.rpr_type; 4981 if (v->value_type != REP_PROTOCOL_TYPE_OPAQUE) { 4982 (void) strlcpy(v->value_value, response.rpr_value, 4983 sizeof (v->value_value)); 4984 } else { 4985 v->value_size = scf_opaque_decode(v->value_value, 4986 response.rpr_value, sizeof (v->value_value)); 4987 } 4988 (void) pthread_mutex_unlock(&h->rh_lock); 4989 return ((response.rpr_response == REP_PROTOCOL_SUCCESS)? 4990 SCF_SUCCESS : scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED)); 4991 } 4992 4993 int 4994 scf_pg_get_parent_service(const scf_propertygroup_t *pg, scf_service_t *svc) 4995 { 4996 return (datael_get_parent(&pg->rd_d, &svc->rd_d)); 4997 } 4998 4999 int 5000 scf_pg_get_parent_instance(const scf_propertygroup_t *pg, scf_instance_t *inst) 5001 { 5002 return (datael_get_parent(&pg->rd_d, &inst->rd_d)); 5003 } 5004 5005 int 5006 scf_pg_get_parent_snaplevel(const scf_propertygroup_t *pg, 5007 scf_snaplevel_t *level) 5008 { 5009 return (datael_get_parent(&pg->rd_d, &level->rd_d)); 5010 } 5011 5012 int 5013 scf_service_get_parent(const scf_service_t *svc, scf_scope_t *s) 5014 { 5015 return (datael_get_parent(&svc->rd_d, &s->rd_d)); 5016 } 5017 5018 int 5019 scf_instance_get_parent(const scf_instance_t *inst, scf_service_t *svc) 5020 { 5021 return (datael_get_parent(&inst->rd_d, &svc->rd_d)); 5022 } 5023 5024 int 5025 scf_snapshot_get_parent(const scf_snapshot_t *inst, scf_instance_t *svc) 5026 { 5027 return (datael_get_parent(&inst->rd_d, &svc->rd_d)); 5028 } 5029 5030 int 5031 scf_snaplevel_get_parent(const scf_snaplevel_t *inst, scf_snapshot_t *svc) 5032 { 5033 return (datael_get_parent(&inst->rd_d, &svc->rd_d)); 5034 } 5035 5036 /* 5037 * FMRI functions 5038 * 5039 * Note: In the scf_parse_svc_fmri(), scf_parse_file_fmri() and 5040 * scf_parse_fmri(), fmri isn't const because that would require 5041 * allocating memory. Also, note that scope, at least, is not necessarily 5042 * in the passed in fmri. 5043 */ 5044 5045 int 5046 scf_parse_svc_fmri(char *fmri, const char **scope, const char **service, 5047 const char **instance, const char **propertygroup, const char **property) 5048 { 5049 char *s, *e, *te, *tpg; 5050 char *my_s = NULL, *my_i = NULL, *my_pg = NULL, *my_p = NULL; 5051 5052 if (scope != NULL) 5053 *scope = NULL; 5054 if (service != NULL) 5055 *service = NULL; 5056 if (instance != NULL) 5057 *instance = NULL; 5058 if (propertygroup != NULL) 5059 *propertygroup = NULL; 5060 if (property != NULL) 5061 *property = NULL; 5062 5063 s = fmri; 5064 e = strchr(s, '\0'); 5065 5066 if (strncmp(s, SCF_FMRI_SVC_PREFIX, 5067 sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) 5068 s += sizeof (SCF_FMRI_SVC_PREFIX) - 1; 5069 5070 if (strncmp(s, SCF_FMRI_SCOPE_PREFIX, 5071 sizeof (SCF_FMRI_SCOPE_PREFIX) - 1) == 0) { 5072 char *my_scope; 5073 5074 s += sizeof (SCF_FMRI_SCOPE_PREFIX) - 1; 5075 te = strstr(s, SCF_FMRI_SERVICE_PREFIX); 5076 if (te == NULL) 5077 te = e; 5078 5079 *te = 0; 5080 my_scope = s; 5081 5082 s = te; 5083 if (s < e) 5084 s += sizeof (SCF_FMRI_SERVICE_PREFIX) - 1; 5085 5086 /* If the scope ends with the suffix, remove it. */ 5087 te = strstr(my_scope, SCF_FMRI_SCOPE_SUFFIX); 5088 if (te != NULL && te[sizeof (SCF_FMRI_SCOPE_SUFFIX) - 1] == 0) 5089 *te = 0; 5090 5091 /* Validate the scope. */ 5092 if (my_scope[0] == '\0') 5093 my_scope = SCF_FMRI_LOCAL_SCOPE; 5094 else if (uu_check_name(my_scope, 0) == -1) { 5095 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 5096 } 5097 5098 if (scope != NULL) 5099 *scope = my_scope; 5100 } else { 5101 if (scope != NULL) 5102 *scope = SCF_FMRI_LOCAL_SCOPE; 5103 } 5104 5105 if (s[0] != 0) { 5106 if (strncmp(s, SCF_FMRI_SERVICE_PREFIX, 5107 sizeof (SCF_FMRI_SERVICE_PREFIX) - 1) == 0) 5108 s += sizeof (SCF_FMRI_SERVICE_PREFIX) - 1; 5109 5110 /* 5111 * Can't validate service here because it might not be null 5112 * terminated. 5113 */ 5114 my_s = s; 5115 } 5116 5117 tpg = strstr(s, SCF_FMRI_PROPERTYGRP_PREFIX); 5118 te = strstr(s, SCF_FMRI_INSTANCE_PREFIX); 5119 if (te != NULL && (tpg == NULL || te < tpg)) { 5120 *te = 0; 5121 te += sizeof (SCF_FMRI_INSTANCE_PREFIX) - 1; 5122 5123 /* Can't validate instance here either. */ 5124 my_i = s = te; 5125 5126 te = strstr(s, SCF_FMRI_PROPERTYGRP_PREFIX); 5127 } else { 5128 te = tpg; 5129 } 5130 5131 if (te != NULL) { 5132 *te = 0; 5133 te += sizeof (SCF_FMRI_PROPERTYGRP_PREFIX) - 1; 5134 5135 my_pg = s = te; 5136 te = strstr(s, SCF_FMRI_PROPERTY_PREFIX); 5137 if (te != NULL) { 5138 *te = 0; 5139 te += sizeof (SCF_FMRI_PROPERTY_PREFIX) - 1; 5140 5141 my_p = te; 5142 s = te; 5143 } 5144 } 5145 5146 if (my_s != NULL) { 5147 if (uu_check_name(my_s, UU_NAME_DOMAIN | UU_NAME_PATH) == -1) 5148 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 5149 5150 if (service != NULL) 5151 *service = my_s; 5152 } 5153 5154 if (my_i != NULL) { 5155 if (uu_check_name(my_i, UU_NAME_DOMAIN) == -1) 5156 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 5157 5158 if (instance != NULL) 5159 *instance = my_i; 5160 } 5161 5162 if (my_pg != NULL) { 5163 if (uu_check_name(my_pg, UU_NAME_DOMAIN) == -1) 5164 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 5165 5166 if (propertygroup != NULL) 5167 *propertygroup = my_pg; 5168 } 5169 5170 if (my_p != NULL) { 5171 if (uu_check_name(my_p, UU_NAME_DOMAIN) == -1) 5172 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 5173 5174 if (property != NULL) 5175 *property = my_p; 5176 } 5177 5178 return (0); 5179 } 5180 5181 int 5182 scf_parse_file_fmri(char *fmri, const char **scope, const char **path) 5183 { 5184 char *s, *e, *te; 5185 5186 if (scope != NULL) 5187 *scope = NULL; 5188 5189 s = fmri; 5190 e = strchr(s, '\0'); 5191 5192 if (strncmp(s, SCF_FMRI_FILE_PREFIX, 5193 sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) 5194 s += sizeof (SCF_FMRI_FILE_PREFIX) - 1; 5195 5196 if (strncmp(s, SCF_FMRI_SCOPE_PREFIX, 5197 sizeof (SCF_FMRI_SCOPE_PREFIX) - 1) == 0) { 5198 char *my_scope; 5199 5200 s += sizeof (SCF_FMRI_SCOPE_PREFIX) - 1; 5201 te = strstr(s, SCF_FMRI_SERVICE_PREFIX); 5202 if (te == NULL) 5203 te = e; 5204 5205 *te = 0; 5206 my_scope = s; 5207 5208 s = te; 5209 5210 /* Validate the scope. */ 5211 if (my_scope[0] != '\0' && 5212 strcmp(my_scope, SCF_FMRI_LOCAL_SCOPE) != 0) { 5213 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 5214 } 5215 5216 if (scope != NULL) 5217 *scope = my_scope; 5218 } else { 5219 /* 5220 * FMRI paths must be absolute 5221 */ 5222 if (s[0] != '/') 5223 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 5224 } 5225 5226 s += sizeof (SCF_FMRI_SERVICE_PREFIX) - 1; 5227 5228 if (s >= e) 5229 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 5230 5231 /* 5232 * If the user requests it, return the full path of the file. 5233 */ 5234 if (path != NULL) { 5235 assert(s > fmri); 5236 s[-1] = '/'; 5237 *path = s - 1; 5238 } 5239 5240 return (0); 5241 } 5242 5243 int 5244 scf_parse_fmri(char *fmri, int *type, const char **scope, const char **service, 5245 const char **instance, const char **propertygroup, const char **property) 5246 { 5247 if (strncmp(fmri, SCF_FMRI_SVC_PREFIX, 5248 sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) { 5249 if (type) 5250 *type = SCF_FMRI_TYPE_SVC; 5251 return (scf_parse_svc_fmri(fmri, scope, service, instance, 5252 propertygroup, property)); 5253 } else if (strncmp(fmri, SCF_FMRI_FILE_PREFIX, 5254 sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) { 5255 if (type) 5256 *type = SCF_FMRI_TYPE_FILE; 5257 return (scf_parse_file_fmri(fmri, scope, NULL)); 5258 } else { 5259 /* 5260 * Parse as a svc if the fmri type is not explicitly 5261 * specified. 5262 */ 5263 if (type) 5264 *type = SCF_FMRI_TYPE_SVC; 5265 return (scf_parse_svc_fmri(fmri, scope, service, instance, 5266 propertygroup, property)); 5267 } 5268 } 5269 5270 /* 5271 * Fails with _INVALID_ARGUMENT. fmri and buf may be equal. 5272 */ 5273 ssize_t 5274 scf_canonify_fmri(const char *fmri, char *buf, size_t bufsz) 5275 { 5276 const char *scope, *service, *instance, *pg, *property; 5277 char local[6 * REP_PROTOCOL_NAME_LEN]; 5278 int r; 5279 size_t len; 5280 5281 if (strlcpy(local, fmri, sizeof (local)) >= sizeof (local)) { 5282 /* Should this be CONSTRAINT_VIOLATED? */ 5283 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 5284 return (-1); 5285 } 5286 5287 5288 r = scf_parse_svc_fmri(local, &scope, &service, &instance, &pg, 5289 &property); 5290 if (r != 0) 5291 return (-1); 5292 5293 len = strlcpy(buf, "svc:/", bufsz); 5294 5295 if (scope != NULL && strcmp(scope, SCF_SCOPE_LOCAL) != 0) { 5296 len += strlcat(buf, "/", bufsz); 5297 len += strlcat(buf, scope, bufsz); 5298 } 5299 5300 if (service) 5301 len += strlcat(buf, service, bufsz); 5302 5303 if (instance) { 5304 len += strlcat(buf, ":", bufsz); 5305 len += strlcat(buf, instance, bufsz); 5306 } 5307 5308 if (pg) { 5309 len += strlcat(buf, "/:properties/", bufsz); 5310 len += strlcat(buf, pg, bufsz); 5311 } 5312 5313 if (property) { 5314 len += strlcat(buf, "/", bufsz); 5315 len += strlcat(buf, property, bufsz); 5316 } 5317 5318 return (len); 5319 } 5320 5321 /* 5322 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _CONSTRAINT_VIOLATED, 5323 * _NOT_FOUND, _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, 5324 * _NO_RESOURCES, _BACKEND_ACCESS. 5325 */ 5326 int 5327 scf_handle_decode_fmri(scf_handle_t *h, const char *fmri, scf_scope_t *sc, 5328 scf_service_t *svc, scf_instance_t *inst, scf_propertygroup_t *pg, 5329 scf_property_t *prop, int flags) 5330 { 5331 const char *scope, *service, *instance, *propertygroup, *property; 5332 int last; 5333 char local[6 * REP_PROTOCOL_NAME_LEN]; 5334 int ret; 5335 const uint32_t holds = RH_HOLD_SCOPE | RH_HOLD_SERVICE | 5336 RH_HOLD_INSTANCE | RH_HOLD_PG | RH_HOLD_PROPERTY; 5337 5338 /* 5339 * verify that all handles match 5340 */ 5341 if ((sc != NULL && h != sc->rd_d.rd_handle) || 5342 (svc != NULL && h != svc->rd_d.rd_handle) || 5343 (inst != NULL && h != inst->rd_d.rd_handle) || 5344 (pg != NULL && h != pg->rd_d.rd_handle) || 5345 (prop != NULL && h != prop->rd_d.rd_handle)) 5346 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH)); 5347 5348 if (strlcpy(local, fmri, sizeof (local)) >= sizeof (local)) { 5349 ret = scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 5350 goto reset_args; 5351 } 5352 5353 /* 5354 * We can simply return from an error in parsing, because 5355 * scf_parse_fmri sets the error code correctly. 5356 */ 5357 if (scf_parse_svc_fmri(local, &scope, &service, &instance, 5358 &propertygroup, &property) == -1) { 5359 ret = -1; 5360 goto reset_args; 5361 } 5362 5363 /* 5364 * the FMRI looks valid at this point -- do constraint checks. 5365 */ 5366 5367 if (instance != NULL && (flags & SCF_DECODE_FMRI_REQUIRE_NO_INSTANCE)) { 5368 ret = scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED); 5369 goto reset_args; 5370 } 5371 if (instance == NULL && (flags & SCF_DECODE_FMRI_REQUIRE_INSTANCE)) { 5372 ret = scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED); 5373 goto reset_args; 5374 } 5375 5376 if (prop != NULL) 5377 last = REP_PROTOCOL_ENTITY_PROPERTY; 5378 else if (pg != NULL) 5379 last = REP_PROTOCOL_ENTITY_PROPERTYGRP; 5380 else if (inst != NULL) 5381 last = REP_PROTOCOL_ENTITY_INSTANCE; 5382 else if (svc != NULL) 5383 last = REP_PROTOCOL_ENTITY_SERVICE; 5384 else if (sc != NULL) 5385 last = REP_PROTOCOL_ENTITY_SCOPE; 5386 else 5387 last = REP_PROTOCOL_ENTITY_NONE; 5388 5389 if (flags & SCF_DECODE_FMRI_EXACT) { 5390 int last_fmri; 5391 5392 if (property != NULL) 5393 last_fmri = REP_PROTOCOL_ENTITY_PROPERTY; 5394 else if (propertygroup != NULL) 5395 last_fmri = REP_PROTOCOL_ENTITY_PROPERTYGRP; 5396 else if (instance != NULL) 5397 last_fmri = REP_PROTOCOL_ENTITY_INSTANCE; 5398 else if (service != NULL) 5399 last_fmri = REP_PROTOCOL_ENTITY_SERVICE; 5400 else if (scope != NULL) 5401 last_fmri = REP_PROTOCOL_ENTITY_SCOPE; 5402 else 5403 last_fmri = REP_PROTOCOL_ENTITY_NONE; 5404 5405 if (last != last_fmri) { 5406 ret = scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED); 5407 goto reset_args; 5408 } 5409 } 5410 5411 if ((flags & SCF_DECODE_FMRI_TRUNCATE) && 5412 last == REP_PROTOCOL_ENTITY_NONE) { 5413 ret = 0; /* nothing to do */ 5414 goto reset_args; 5415 } 5416 5417 if (!(flags & SCF_DECODE_FMRI_TRUNCATE)) 5418 last = REP_PROTOCOL_ENTITY_NONE; /* never stop */ 5419 5420 /* 5421 * passed the constraint checks -- try to grab the thing itself. 5422 */ 5423 5424 handle_hold_subhandles(h, holds); 5425 if (sc == NULL) 5426 sc = h->rh_scope; 5427 else 5428 datael_reset(&sc->rd_d); 5429 5430 if (svc == NULL) 5431 svc = h->rh_service; 5432 else 5433 datael_reset(&svc->rd_d); 5434 5435 if (inst == NULL) 5436 inst = h->rh_instance; 5437 else 5438 datael_reset(&inst->rd_d); 5439 5440 if (pg == NULL) 5441 pg = h->rh_pg; 5442 else 5443 datael_reset(&pg->rd_d); 5444 5445 if (prop == NULL) 5446 prop = h->rh_property; 5447 else 5448 datael_reset(&prop->rd_d); 5449 5450 /* 5451 * We only support local scopes, but we check *after* getting 5452 * the local scope, so that any repository-related errors take 5453 * precedence. 5454 */ 5455 if (scf_handle_get_scope(h, SCF_SCOPE_LOCAL, sc) == -1) { 5456 handle_rele_subhandles(h, holds); 5457 ret = -1; 5458 goto reset_args; 5459 } 5460 5461 if (scope != NULL && strcmp(scope, SCF_FMRI_LOCAL_SCOPE) != 0) { 5462 handle_rele_subhandles(h, holds); 5463 ret = scf_set_error(SCF_ERROR_NOT_FOUND); 5464 goto reset_args; 5465 } 5466 5467 5468 if (service == NULL || last == REP_PROTOCOL_ENTITY_SCOPE) { 5469 handle_rele_subhandles(h, holds); 5470 return (0); 5471 } 5472 5473 if (scf_scope_get_service(sc, service, svc) == -1) { 5474 handle_rele_subhandles(h, holds); 5475 ret = -1; 5476 assert(scf_error() != SCF_ERROR_NOT_SET); 5477 if (scf_error() == SCF_ERROR_DELETED) 5478 (void) scf_set_error(SCF_ERROR_NOT_FOUND); 5479 goto reset_args; 5480 } 5481 5482 if (last == REP_PROTOCOL_ENTITY_SERVICE) { 5483 handle_rele_subhandles(h, holds); 5484 return (0); 5485 } 5486 5487 if (instance == NULL) { 5488 if (propertygroup == NULL || 5489 last == REP_PROTOCOL_ENTITY_INSTANCE) { 5490 handle_rele_subhandles(h, holds); 5491 return (0); 5492 } 5493 5494 if (scf_service_get_pg(svc, propertygroup, pg) == -1) { 5495 handle_rele_subhandles(h, holds); 5496 ret = -1; 5497 assert(scf_error() != SCF_ERROR_NOT_SET); 5498 if (scf_error() == SCF_ERROR_DELETED) 5499 (void) scf_set_error(SCF_ERROR_NOT_FOUND); 5500 goto reset_args; 5501 } 5502 } else { 5503 if (scf_service_get_instance(svc, instance, inst) == -1) { 5504 handle_rele_subhandles(h, holds); 5505 ret = -1; 5506 assert(scf_error() != SCF_ERROR_NOT_SET); 5507 if (scf_error() == SCF_ERROR_DELETED) 5508 (void) scf_set_error(SCF_ERROR_NOT_FOUND); 5509 goto reset_args; 5510 } 5511 5512 if (propertygroup == NULL || 5513 last == REP_PROTOCOL_ENTITY_INSTANCE) { 5514 handle_rele_subhandles(h, holds); 5515 return (0); 5516 } 5517 5518 if (scf_instance_get_pg(inst, propertygroup, pg) == -1) { 5519 handle_rele_subhandles(h, holds); 5520 ret = -1; 5521 assert(scf_error() != SCF_ERROR_NOT_SET); 5522 if (scf_error() == SCF_ERROR_DELETED) 5523 (void) scf_set_error(SCF_ERROR_NOT_FOUND); 5524 goto reset_args; 5525 } 5526 } 5527 5528 if (property == NULL || last == REP_PROTOCOL_ENTITY_PROPERTYGRP) { 5529 handle_rele_subhandles(h, holds); 5530 return (0); 5531 } 5532 5533 if (scf_pg_get_property(pg, property, prop) == -1) { 5534 handle_rele_subhandles(h, holds); 5535 ret = -1; 5536 assert(scf_error() != SCF_ERROR_NOT_SET); 5537 if (scf_error() == SCF_ERROR_DELETED) 5538 (void) scf_set_error(SCF_ERROR_NOT_FOUND); 5539 goto reset_args; 5540 } 5541 5542 handle_rele_subhandles(h, holds); 5543 return (0); 5544 5545 reset_args: 5546 if (sc != NULL) 5547 datael_reset(&sc->rd_d); 5548 if (svc != NULL) 5549 datael_reset(&svc->rd_d); 5550 if (inst != NULL) 5551 datael_reset(&inst->rd_d); 5552 if (pg != NULL) 5553 datael_reset(&pg->rd_d); 5554 if (prop != NULL) 5555 datael_reset(&prop->rd_d); 5556 5557 return (ret); 5558 } 5559 5560 /* 5561 * Fails with _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response too 5562 * big, bad entity id, request not applicable to entity, name too long for 5563 * buffer), _NOT_SET, or _DELETED. 5564 */ 5565 ssize_t 5566 scf_scope_to_fmri(const scf_scope_t *scope, char *out, size_t sz) 5567 { 5568 ssize_t r, len; 5569 5570 char tmp[REP_PROTOCOL_NAME_LEN]; 5571 5572 r = scf_scope_get_name(scope, tmp, sizeof (tmp)); 5573 5574 if (r <= 0) 5575 return (r); 5576 5577 len = strlcpy(out, SCF_FMRI_SVC_PREFIX, sz); 5578 if (strcmp(tmp, SCF_FMRI_LOCAL_SCOPE) != 0) { 5579 if (len >= sz) 5580 return (len + r + sizeof (SCF_FMRI_SCOPE_SUFFIX) - 1); 5581 5582 len = strlcat(out, tmp, sz); 5583 if (len >= sz) 5584 return (len + sizeof (SCF_FMRI_SCOPE_SUFFIX) - 1); 5585 len = strlcat(out, 5586 SCF_FMRI_SCOPE_SUFFIX SCF_FMRI_SERVICE_PREFIX, sz); 5587 } 5588 5589 return (len); 5590 } 5591 5592 /* 5593 * Fails with _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response too 5594 * big, bad element id, bad ids, bad types, scope has no parent, request not 5595 * applicable to entity, name too long), _NOT_SET, _DELETED, 5596 */ 5597 ssize_t 5598 scf_service_to_fmri(const scf_service_t *svc, char *out, size_t sz) 5599 { 5600 scf_handle_t *h = svc->rd_d.rd_handle; 5601 scf_scope_t *scope = HANDLE_HOLD_SCOPE(h); 5602 ssize_t r, len; 5603 5604 char tmp[REP_PROTOCOL_NAME_LEN]; 5605 5606 r = datael_get_parent(&svc->rd_d, &scope->rd_d); 5607 if (r != SCF_SUCCESS) { 5608 HANDLE_RELE_SCOPE(h); 5609 5610 assert(scf_error() != SCF_ERROR_HANDLE_MISMATCH); 5611 return (-1); 5612 } 5613 if (out != NULL && sz > 0) 5614 len = scf_scope_to_fmri(scope, out, sz); 5615 else 5616 len = scf_scope_to_fmri(scope, tmp, 2); 5617 5618 HANDLE_RELE_SCOPE(h); 5619 5620 if (len < 0) 5621 return (-1); 5622 5623 if (out == NULL || len >= sz) 5624 len += sizeof (SCF_FMRI_SERVICE_PREFIX) - 1; 5625 else 5626 len = strlcat(out, SCF_FMRI_SERVICE_PREFIX, sz); 5627 5628 r = scf_service_get_name(svc, tmp, sizeof (tmp)); 5629 if (r < 0) 5630 return (r); 5631 5632 if (out == NULL || len >= sz) 5633 len += r; 5634 else 5635 len = strlcat(out, tmp, sz); 5636 5637 return (len); 5638 } 5639 5640 ssize_t 5641 scf_instance_to_fmri(const scf_instance_t *inst, char *out, size_t sz) 5642 { 5643 scf_handle_t *h = inst->rd_d.rd_handle; 5644 scf_service_t *svc = HANDLE_HOLD_SERVICE(h); 5645 ssize_t r, len; 5646 5647 char tmp[REP_PROTOCOL_NAME_LEN]; 5648 5649 r = datael_get_parent(&inst->rd_d, &svc->rd_d); 5650 if (r != SCF_SUCCESS) { 5651 HANDLE_RELE_SERVICE(h); 5652 return (-1); 5653 } 5654 5655 len = scf_service_to_fmri(svc, out, sz); 5656 5657 HANDLE_RELE_SERVICE(h); 5658 5659 if (len < 0) 5660 return (len); 5661 5662 if (len >= sz) 5663 len += sizeof (SCF_FMRI_INSTANCE_PREFIX) - 1; 5664 else 5665 len = strlcat(out, SCF_FMRI_INSTANCE_PREFIX, sz); 5666 5667 r = scf_instance_get_name(inst, tmp, sizeof (tmp)); 5668 if (r < 0) 5669 return (r); 5670 5671 if (len >= sz) 5672 len += r; 5673 else 5674 len = strlcat(out, tmp, sz); 5675 5676 return (len); 5677 } 5678 5679 ssize_t 5680 scf_pg_to_fmri(const scf_propertygroup_t *pg, char *out, size_t sz) 5681 { 5682 scf_handle_t *h = pg->rd_d.rd_handle; 5683 5684 struct rep_protocol_entity_parent_type request; 5685 struct rep_protocol_integer_response response; 5686 5687 char tmp[REP_PROTOCOL_NAME_LEN]; 5688 ssize_t len, r; 5689 5690 (void) pthread_mutex_lock(&h->rh_lock); 5691 request.rpr_request = REP_PROTOCOL_ENTITY_PARENT_TYPE; 5692 request.rpr_entityid = pg->rd_d.rd_entity; 5693 5694 datael_finish_reset(&pg->rd_d); 5695 r = make_door_call(h, &request, sizeof (request), 5696 &response, sizeof (response)); 5697 (void) pthread_mutex_unlock(&h->rh_lock); 5698 5699 if (r < 0) 5700 DOOR_ERRORS_BLOCK(r); 5701 5702 if (response.rpr_response != REP_PROTOCOL_SUCCESS || 5703 r < sizeof (response)) { 5704 return (scf_set_error(proto_error(response.rpr_response))); 5705 } 5706 5707 switch (response.rpr_value) { 5708 case REP_PROTOCOL_ENTITY_SERVICE: { 5709 scf_service_t *svc; 5710 5711 svc = HANDLE_HOLD_SERVICE(h); 5712 5713 r = datael_get_parent(&pg->rd_d, &svc->rd_d); 5714 5715 if (r == SCF_SUCCESS) 5716 len = scf_service_to_fmri(svc, out, sz); 5717 5718 HANDLE_RELE_SERVICE(h); 5719 break; 5720 } 5721 5722 case REP_PROTOCOL_ENTITY_INSTANCE: { 5723 scf_instance_t *inst; 5724 5725 inst = HANDLE_HOLD_INSTANCE(h); 5726 5727 r = datael_get_parent(&pg->rd_d, &inst->rd_d); 5728 5729 if (r == SCF_SUCCESS) 5730 len = scf_instance_to_fmri(inst, out, sz); 5731 5732 HANDLE_RELE_INSTANCE(h); 5733 break; 5734 } 5735 5736 case REP_PROTOCOL_ENTITY_SNAPLEVEL: { 5737 scf_instance_t *inst = HANDLE_HOLD_INSTANCE(h); 5738 scf_snapshot_t *snap = HANDLE_HOLD_SNAPSHOT(h); 5739 scf_snaplevel_t *level = HANDLE_HOLD_SNAPLVL(h); 5740 5741 r = datael_get_parent(&pg->rd_d, &level->rd_d); 5742 5743 if (r == SCF_SUCCESS) 5744 r = datael_get_parent(&level->rd_d, &snap->rd_d); 5745 5746 if (r == SCF_SUCCESS) 5747 r = datael_get_parent(&snap->rd_d, &inst->rd_d); 5748 5749 if (r == SCF_SUCCESS) 5750 len = scf_instance_to_fmri(inst, out, sz); 5751 5752 HANDLE_RELE_INSTANCE(h); 5753 HANDLE_RELE_SNAPSHOT(h); 5754 HANDLE_RELE_SNAPLVL(h); 5755 break; 5756 } 5757 5758 default: 5759 return (scf_set_error(SCF_ERROR_INTERNAL)); 5760 } 5761 5762 if (r != SCF_SUCCESS) 5763 return (r); 5764 5765 if (len >= sz) 5766 len += sizeof (SCF_FMRI_PROPERTYGRP_PREFIX) - 1; 5767 else 5768 len = strlcat(out, SCF_FMRI_PROPERTYGRP_PREFIX, sz); 5769 5770 r = scf_pg_get_name(pg, tmp, sizeof (tmp)); 5771 5772 if (r < 0) 5773 return (r); 5774 5775 if (len >= sz) 5776 len += r; 5777 else 5778 len = strlcat(out, tmp, sz); 5779 5780 return (len); 5781 } 5782 5783 ssize_t 5784 scf_property_to_fmri(const scf_property_t *prop, char *out, size_t sz) 5785 { 5786 scf_handle_t *h = prop->rd_d.rd_handle; 5787 scf_propertygroup_t *pg = HANDLE_HOLD_PG(h); 5788 5789 char tmp[REP_PROTOCOL_NAME_LEN]; 5790 ssize_t len; 5791 int r; 5792 5793 r = datael_get_parent(&prop->rd_d, &pg->rd_d); 5794 if (r != SCF_SUCCESS) { 5795 HANDLE_RELE_PG(h); 5796 return (-1); 5797 } 5798 5799 len = scf_pg_to_fmri(pg, out, sz); 5800 5801 HANDLE_RELE_PG(h); 5802 5803 if (len >= sz) 5804 len += sizeof (SCF_FMRI_PROPERTY_PREFIX) - 1; 5805 else 5806 len = strlcat(out, SCF_FMRI_PROPERTY_PREFIX, sz); 5807 5808 r = scf_property_get_name(prop, tmp, sizeof (tmp)); 5809 5810 if (r < 0) 5811 return (r); 5812 5813 if (len >= sz) 5814 len += r; 5815 else 5816 len = strlcat(out, tmp, sz); 5817 5818 return (len); 5819 } 5820 5821 /* 5822 * Fails with _HANDLE_MISMATCH, _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL 5823 * (server response too big, bad entity id, request not applicable to entity, 5824 * name too long for buffer, bad element id, iter already exists, element 5825 * cannot have children of type, type is invalid, iter was reset, sequence 5826 * was bad, iter walks values, iter does not walk type entities), 5827 * _NOT_SET, _DELETED, or _CONSTRAINT_VIOLATED, 5828 * _NOT_FOUND (scope has no parent), _INVALID_ARGUMENT, _NO_RESOURCES, 5829 * _BACKEND_ACCESS. 5830 */ 5831 int 5832 scf_pg_get_underlying_pg(const scf_propertygroup_t *pg, 5833 scf_propertygroup_t *out) 5834 { 5835 scf_handle_t *h = pg->rd_d.rd_handle; 5836 scf_service_t *svc; 5837 scf_instance_t *inst; 5838 5839 char me[REP_PROTOCOL_NAME_LEN]; 5840 int r; 5841 5842 if (h != out->rd_d.rd_handle) 5843 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH)); 5844 5845 r = scf_pg_get_name(pg, me, sizeof (me)); 5846 5847 if (r < 0) 5848 return (r); 5849 5850 svc = HANDLE_HOLD_SERVICE(h); 5851 inst = HANDLE_HOLD_INSTANCE(h); 5852 5853 r = datael_get_parent(&pg->rd_d, &inst->rd_d); 5854 5855 if (r == SCF_SUCCESS) { 5856 r = datael_get_parent(&inst->rd_d, &svc->rd_d); 5857 if (r != SCF_SUCCESS) { 5858 goto out; 5859 } 5860 r = scf_service_get_pg(svc, me, out); 5861 } else { 5862 r = scf_set_error(SCF_ERROR_NOT_FOUND); 5863 } 5864 5865 out: 5866 HANDLE_RELE_SERVICE(h); 5867 HANDLE_RELE_INSTANCE(h); 5868 return (r); 5869 } 5870 5871 #define LEGACY_SCHEME "lrc:" 5872 #define LEGACY_UNKNOWN "unknown" 5873 5874 /* 5875 * Implementation of scf_walk_fmri() 5876 * 5877 * This is a little tricky due to the many-to-many relationship between patterns 5878 * and matches. We need to be able to satisfy the following requirements: 5879 * 5880 * 1) Detect patterns which match more than one FMRI, and be able to 5881 * report which FMRIs have been matched. 5882 * 2) Detect patterns which have not matched any FMRIs 5883 * 3) Visit each matching FMRI exactly once across all patterns 5884 * 4) Ignore FMRIs which have only been matched due to multiply-matching 5885 * patterns. 5886 * 5887 * We maintain an array of scf_pattern_t structures, one for each argument, and 5888 * maintain a linked list of scf_match_t structures for each one. We first 5889 * qualify each pattern's type: 5890 * 5891 * PATTERN_INVALID The argument is invalid (too long). 5892 * 5893 * PATTERN_EXACT The pattern is a complete FMRI. The list of 5894 * matches contains only a single entry. 5895 * 5896 * PATTERN_GLOB The pattern will be matched against all 5897 * FMRIs via fnmatch() in the second phase. 5898 * Matches will be added to the pattern's list 5899 * as they are found. 5900 * 5901 * PATTERN_PARTIAL Everything else. We will assume that this is 5902 * an abbreviated FMRI, and match according to 5903 * our abbreviated FMRI rules. Matches will be 5904 * added to the pattern's list as they are found. 5905 * 5906 * The first pass searches for arguments that are complete FMRIs. These are 5907 * classified as EXACT patterns and do not necessitate searching the entire 5908 * tree. 5909 * 5910 * Once this is done, if we have any GLOB or PARTIAL patterns (or if no 5911 * arguments were given), we iterate over all services and instances in the 5912 * repository, looking for matches. 5913 * 5914 * When a match is found, we add the match to the pattern's list. We also enter 5915 * the match into a hash table, resulting in something like this: 5916 * 5917 * scf_pattern_t scf_match_t 5918 * +---------------+ +-------+ +-------+ 5919 * | pattern 'foo' |----->| match |---->| match | 5920 * +---------------+ +-------+ +-------+ 5921 * | | 5922 * scf_match_key_t | | 5923 * +--------------+ | | 5924 * | FMRI bar/foo |<----+ | 5925 * +--------------+ | 5926 * | FMRI baz/foo |<------------------+ 5927 * +--------------+ 5928 * 5929 * Once we have all of this set up, we do one pass to report patterns matching 5930 * multiple FMRIs (if SCF_WALK_MULTIPLE is not set) and patterns for which no 5931 * match was found. 5932 * 5933 * Finally, we walk through all valid patterns, and for each match, if we 5934 * haven't already seen the match (as recorded in the hash table), then we 5935 * execute the callback. 5936 */ 5937 5938 struct scf_matchkey; 5939 struct scf_match; 5940 5941 /* 5942 * scf_matchkey_t 5943 */ 5944 typedef struct scf_matchkey { 5945 char *sk_fmri; /* Matching FMRI */ 5946 char *sk_legacy; /* Legacy name */ 5947 int sk_seen; /* If we've been seen */ 5948 struct scf_matchkey *sk_next; /* Next in hash chain */ 5949 } scf_matchkey_t; 5950 5951 /* 5952 * scf_match_t 5953 */ 5954 typedef struct scf_match { 5955 scf_matchkey_t *sm_key; 5956 struct scf_match *sm_next; 5957 } scf_match_t; 5958 5959 #define WALK_HTABLE_SIZE 123 5960 5961 /* 5962 * scf_get_key() 5963 * 5964 * Given an FMRI and a hash table, returns the scf_matchkey_t corresponding to 5965 * this FMRI. If the FMRI does not exist, it is added to the hash table. If a 5966 * new entry cannot be allocated due to lack of memory, NULL is returned. 5967 */ 5968 static scf_matchkey_t * 5969 scf_get_key(scf_matchkey_t **htable, const char *fmri, const char *legacy) 5970 { 5971 uint_t h = 0, g; 5972 const char *p, *k; 5973 scf_matchkey_t *key; 5974 5975 k = strstr(fmri, ":/"); 5976 assert(k != NULL); 5977 k += 2; 5978 5979 /* 5980 * Generic hash function from uts/common/os/modhash.c. 5981 */ 5982 for (p = k; *p != '\0'; ++p) { 5983 h = (h << 4) + *p; 5984 if ((g = (h & 0xf0000000)) != 0) { 5985 h ^= (g >> 24); 5986 h ^= g; 5987 } 5988 } 5989 5990 h %= WALK_HTABLE_SIZE; 5991 5992 /* 5993 * Search for an existing key 5994 */ 5995 for (key = htable[h]; key != NULL; key = key->sk_next) { 5996 if (strcmp(key->sk_fmri, fmri) == 0) 5997 return (key); 5998 } 5999 6000 if ((key = calloc(sizeof (scf_matchkey_t), 1)) == NULL) 6001 return (NULL); 6002 6003 /* 6004 * Add new key to hash table. 6005 */ 6006 if ((key->sk_fmri = strdup(fmri)) == NULL) { 6007 free(key); 6008 return (NULL); 6009 } 6010 6011 if (legacy == NULL) { 6012 key->sk_legacy = NULL; 6013 } else if ((key->sk_legacy = strdup(legacy)) == NULL) { 6014 free(key->sk_fmri); 6015 free(key); 6016 return (NULL); 6017 } 6018 6019 key->sk_next = htable[h]; 6020 htable[h] = key; 6021 6022 return (key); 6023 } 6024 6025 /* 6026 * Given an FMRI, insert it into the pattern's list appropriately. 6027 * svc_explicit indicates whether matching services should take 6028 * precedence over matching instances. 6029 */ 6030 static scf_error_t 6031 scf_add_match(scf_matchkey_t **htable, const char *fmri, const char *legacy, 6032 scf_pattern_t *pattern, int svc_explicit) 6033 { 6034 scf_match_t *match; 6035 6036 /* 6037 * If svc_explicit is set, enforce the constaint that matching 6038 * instances take precedence over matching services. Otherwise, 6039 * matching services take precedence over matching instances. 6040 */ 6041 if (svc_explicit) { 6042 scf_match_t *next, *prev; 6043 /* 6044 * If we match an instance, check to see if we must remove 6045 * any matching services (for SCF_WALK_EXPLICIT). 6046 */ 6047 for (prev = match = pattern->sp_matches; match != NULL; 6048 match = next) { 6049 size_t len = strlen(match->sm_key->sk_fmri); 6050 next = match->sm_next; 6051 if (strncmp(match->sm_key->sk_fmri, fmri, len) == 0 && 6052 fmri[len] == ':') { 6053 if (prev == match) 6054 pattern->sp_matches = match->sm_next; 6055 else 6056 prev->sm_next = match->sm_next; 6057 pattern->sp_matchcount--; 6058 free(match); 6059 } else 6060 prev = match; 6061 } 6062 } else { 6063 /* 6064 * If we've matched a service don't add any instances (for 6065 * SCF_WALK_SERVICE). 6066 */ 6067 for (match = pattern->sp_matches; match != NULL; 6068 match = match->sm_next) { 6069 size_t len = strlen(match->sm_key->sk_fmri); 6070 if (strncmp(match->sm_key->sk_fmri, fmri, len) == 0 && 6071 fmri[len] == ':') 6072 return (0); 6073 } 6074 } 6075 6076 if ((match = malloc(sizeof (scf_match_t))) == NULL) 6077 return (SCF_ERROR_NO_MEMORY); 6078 6079 if ((match->sm_key = scf_get_key(htable, fmri, legacy)) == NULL) { 6080 free(match); 6081 return (SCF_ERROR_NO_MEMORY); 6082 } 6083 6084 match->sm_next = pattern->sp_matches; 6085 pattern->sp_matches = match; 6086 pattern->sp_matchcount++; 6087 6088 return (0); 6089 } 6090 6091 /* 6092 * Returns 1 if the fmri matches the given pattern, 0 otherwise. 6093 */ 6094 int 6095 scf_cmp_pattern(char *fmri, scf_pattern_t *pattern) 6096 { 6097 char *tmp; 6098 6099 if (pattern->sp_type == PATTERN_GLOB) { 6100 if (fnmatch(pattern->sp_arg, fmri, 0) == 0) 6101 return (1); 6102 } else if (pattern->sp_type == PATTERN_PARTIAL && 6103 (tmp = strstr(fmri, pattern->sp_arg)) != NULL) { 6104 /* 6105 * We only allow partial matches anchored on the end of 6106 * a service or instance, and beginning on an element 6107 * boundary. 6108 */ 6109 if (tmp != fmri && tmp[-1] != '/' && tmp[-1] != ':' && 6110 tmp[0] != ':') 6111 return (0); 6112 tmp += strlen(pattern->sp_arg); 6113 if (tmp != fmri + strlen(fmri) && tmp[0] != ':' && 6114 tmp[-1] != ':') 6115 return (0); 6116 6117 /* 6118 * If the user has supplied a short pattern that matches 6119 * 'svc:/' or 'lrc:/', ignore it. 6120 */ 6121 if (tmp <= fmri + 4) 6122 return (0); 6123 6124 return (1); 6125 } 6126 6127 return (0); 6128 } 6129 6130 /* 6131 * Attempts to match the given FMRI against a set of patterns, keeping track of 6132 * the results. 6133 */ 6134 static scf_error_t 6135 scf_pattern_match(scf_matchkey_t **htable, char *fmri, const char *legacy, 6136 int npattern, scf_pattern_t *pattern, int svc_explicit) 6137 { 6138 int i; 6139 int ret = 0; 6140 6141 for (i = 0; i < npattern; i++) { 6142 if (scf_cmp_pattern(fmri, &pattern[i]) && 6143 (ret = scf_add_match(htable, fmri, 6144 legacy, &pattern[i], svc_explicit)) != 0) 6145 return (ret); 6146 } 6147 6148 return (0); 6149 } 6150 6151 /* 6152 * Fails with _INVALID_ARGUMENT, _HANDLE_DESTROYED, _INTERNAL (bad server 6153 * response or id in use), _NO_MEMORY, _HANDLE_MISMATCH, _CONSTRAINT_VIOLATED, 6154 * _NOT_FOUND, _NOT_BOUND, _CONNECTION_BROKEN, _NOT_SET, _DELETED, 6155 * _NO_RESOURCES, _BACKEND_ACCESS, _TYPE_MISMATCH. 6156 */ 6157 scf_error_t 6158 scf_walk_fmri(scf_handle_t *h, int argc, char **argv, int flags, 6159 scf_walk_callback callback, void *data, int *err, 6160 void (*errfunc)(const char *, ...)) 6161 { 6162 scf_pattern_t *pattern = NULL; 6163 int i; 6164 char *fmri = NULL; 6165 ssize_t max_fmri_length; 6166 scf_service_t *svc = NULL; 6167 scf_instance_t *inst = NULL; 6168 scf_iter_t *iter = NULL, *sciter = NULL, *siter = NULL; 6169 scf_scope_t *scope = NULL; 6170 scf_propertygroup_t *pg = NULL; 6171 scf_property_t *prop = NULL; 6172 scf_value_t *value = NULL; 6173 int ret = 0; 6174 scf_matchkey_t **htable = NULL; 6175 int pattern_search = 0; 6176 ssize_t max_name_length; 6177 char *pgname = NULL; 6178 scf_walkinfo_t info; 6179 6180 #ifndef NDEBUG 6181 if (flags & SCF_WALK_EXPLICIT) 6182 assert(flags & SCF_WALK_SERVICE); 6183 if (flags & SCF_WALK_NOINSTANCE) 6184 assert(flags & SCF_WALK_SERVICE); 6185 if (flags & SCF_WALK_PROPERTY) 6186 assert(!(flags & SCF_WALK_LEGACY)); 6187 #endif 6188 6189 /* 6190 * Setup initial variables 6191 */ 6192 max_fmri_length = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH); 6193 assert(max_fmri_length != -1); 6194 max_name_length = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH); 6195 assert(max_name_length != -1); 6196 6197 if ((fmri = malloc(max_fmri_length + 1)) == NULL || 6198 (pgname = malloc(max_name_length + 1)) == NULL) { 6199 ret = SCF_ERROR_NO_MEMORY; 6200 goto error; 6201 } 6202 6203 if (argc == 0) { 6204 pattern = NULL; 6205 } else if ((pattern = calloc(argc, sizeof (scf_pattern_t))) 6206 == NULL) { 6207 ret = SCF_ERROR_NO_MEMORY; 6208 goto error; 6209 } 6210 6211 if ((htable = calloc(WALK_HTABLE_SIZE, sizeof (void *))) == NULL) { 6212 ret = SCF_ERROR_NO_MEMORY; 6213 goto error; 6214 } 6215 6216 if ((inst = scf_instance_create(h)) == NULL || 6217 (svc = scf_service_create(h)) == NULL || 6218 (iter = scf_iter_create(h)) == NULL || 6219 (sciter = scf_iter_create(h)) == NULL || 6220 (siter = scf_iter_create(h)) == NULL || 6221 (scope = scf_scope_create(h)) == NULL || 6222 (pg = scf_pg_create(h)) == NULL || 6223 (prop = scf_property_create(h)) == NULL || 6224 (value = scf_value_create(h)) == NULL) { 6225 ret = scf_error(); 6226 goto error; 6227 } 6228 6229 /* 6230 * For each fmri given, we first check to see if it's a full service, 6231 * instance, property group, or property FMRI. This avoids having to do 6232 * the (rather expensive) walk of all instances. Any element which does 6233 * not match a full fmri is identified as a globbed pattern or a partial 6234 * fmri and stored in a private array when walking instances. 6235 */ 6236 for (i = 0; i < argc; i++) { 6237 const char *scope_name, *svc_name, *inst_name, *pg_name; 6238 const char *prop_name; 6239 6240 if (strlen(argv[i]) > max_fmri_length) { 6241 errfunc(scf_get_msg(SCF_MSG_ARGTOOLONG), argv[i]); 6242 if (err != NULL) 6243 *err = UU_EXIT_FATAL; 6244 continue; 6245 } 6246 6247 (void) strcpy(fmri, argv[i]); 6248 if (scf_parse_svc_fmri(fmri, &scope_name, &svc_name, &inst_name, 6249 &pg_name, &prop_name) != SCF_SUCCESS) 6250 goto badfmri; 6251 6252 /* 6253 * If the user has specified SCF_WALK_PROPERTY, allow property 6254 * groups and properties. 6255 */ 6256 if (pg_name != NULL || prop_name != NULL) { 6257 if (!(flags & SCF_WALK_PROPERTY)) 6258 goto badfmri; 6259 6260 if (scf_handle_decode_fmri(h, argv[i], NULL, NULL, 6261 NULL, pg, prop, 0) != 0) 6262 goto badfmri; 6263 6264 if (scf_pg_get_name(pg, NULL, 0) < 0 && 6265 scf_property_get_name(prop, NULL, 0) < 0) 6266 goto badfmri; 6267 6268 if (scf_canonify_fmri(argv[i], fmri, max_fmri_length) 6269 <= 0) { 6270 /* 6271 * scf_parse_fmri() should have caught this. 6272 */ 6273 abort(); 6274 } 6275 6276 if ((ret = scf_add_match(htable, fmri, NULL, 6277 &pattern[i], flags & SCF_WALK_EXPLICIT)) != 0) 6278 goto error; 6279 6280 if ((pattern[i].sp_arg = strdup(argv[i])) == NULL) { 6281 ret = SCF_ERROR_NO_MEMORY; 6282 goto error; 6283 } 6284 pattern[i].sp_type = PATTERN_EXACT; 6285 } 6286 6287 /* 6288 * We need at least a service name 6289 */ 6290 if (scope_name == NULL || svc_name == NULL) 6291 goto badfmri; 6292 6293 /* 6294 * If we have a fully qualified instance, add it to our list of 6295 * fmris to watch. 6296 */ 6297 if (inst_name != NULL) { 6298 if (flags & SCF_WALK_NOINSTANCE) 6299 goto badfmri; 6300 6301 if (scf_handle_decode_fmri(h, argv[i], NULL, NULL, 6302 inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != 0) 6303 goto badfmri; 6304 6305 if (scf_canonify_fmri(argv[i], fmri, max_fmri_length) 6306 <= 0) 6307 goto badfmri; 6308 6309 if ((ret = scf_add_match(htable, fmri, NULL, 6310 &pattern[i], flags & SCF_WALK_EXPLICIT)) != 0) 6311 goto error; 6312 6313 if ((pattern[i].sp_arg = strdup(argv[i])) == NULL) { 6314 ret = SCF_ERROR_NO_MEMORY; 6315 goto error; 6316 } 6317 pattern[i].sp_type = PATTERN_EXACT; 6318 6319 continue; 6320 } 6321 6322 if (scf_handle_decode_fmri(h, argv[i], NULL, svc, 6323 NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != 6324 SCF_SUCCESS) 6325 goto badfmri; 6326 6327 /* 6328 * If the user allows for bare services, then simply 6329 * pass this service on. 6330 */ 6331 if (flags & SCF_WALK_SERVICE) { 6332 if (scf_service_to_fmri(svc, fmri, 6333 max_fmri_length + 1) <= 0) { 6334 ret = scf_error(); 6335 goto error; 6336 } 6337 6338 if ((ret = scf_add_match(htable, fmri, NULL, 6339 &pattern[i], flags & SCF_WALK_EXPLICIT)) != 0) 6340 goto error; 6341 6342 if ((pattern[i].sp_arg = strdup(argv[i])) 6343 == NULL) { 6344 ret = SCF_ERROR_NO_MEMORY; 6345 goto error; 6346 } 6347 pattern[i].sp_type = PATTERN_EXACT; 6348 continue; 6349 } 6350 6351 if (flags & SCF_WALK_NOINSTANCE) 6352 goto badfmri; 6353 6354 /* 6355 * Otherwise, iterate over all instances in the service. 6356 */ 6357 if (scf_iter_service_instances(iter, svc) != 6358 SCF_SUCCESS) { 6359 ret = scf_error(); 6360 goto error; 6361 } 6362 6363 for (;;) { 6364 ret = scf_iter_next_instance(iter, inst); 6365 if (ret == 0) 6366 break; 6367 if (ret != 1) { 6368 ret = scf_error(); 6369 goto error; 6370 } 6371 6372 if (scf_instance_to_fmri(inst, fmri, 6373 max_fmri_length + 1) == -1) 6374 goto badfmri; 6375 6376 if ((ret = scf_add_match(htable, fmri, NULL, 6377 &pattern[i], flags & SCF_WALK_EXPLICIT)) != 0) 6378 goto error; 6379 } 6380 6381 if ((pattern[i].sp_arg = strdup(argv[i])) == NULL) { 6382 ret = SCF_ERROR_NO_MEMORY; 6383 goto error; 6384 } 6385 pattern[i].sp_type = PATTERN_EXACT; 6386 6387 continue; 6388 6389 badfmri: 6390 6391 /* 6392 * If we got here because of a fatal error, bail out 6393 * immediately. 6394 */ 6395 if (scf_error() == SCF_ERROR_CONNECTION_BROKEN) { 6396 ret = scf_error(); 6397 goto error; 6398 } 6399 6400 /* 6401 * At this point we failed to interpret the argument as a 6402 * complete fmri, so mark it as a partial or globbed FMRI for 6403 * later processing. 6404 */ 6405 if (strpbrk(argv[i], "*?[") != NULL) { 6406 /* 6407 * Prepend svc:/ to patterns which don't begin with * or 6408 * svc: or lrc:. 6409 */ 6410 pattern[i].sp_type = PATTERN_GLOB; 6411 if (argv[i][0] == '*' || 6412 (strlen(argv[i]) >= 4 && argv[i][3] == ':')) 6413 pattern[i].sp_arg = strdup(argv[i]); 6414 else { 6415 pattern[i].sp_arg = malloc(strlen(argv[i]) + 6); 6416 if (pattern[i].sp_arg != NULL) 6417 (void) snprintf(pattern[i].sp_arg, 6418 strlen(argv[i]) + 6, "svc:/%s", 6419 argv[i]); 6420 } 6421 } else { 6422 pattern[i].sp_type = PATTERN_PARTIAL; 6423 pattern[i].sp_arg = strdup(argv[i]); 6424 } 6425 pattern_search = 1; 6426 if (pattern[i].sp_arg == NULL) { 6427 ret = SCF_ERROR_NO_MEMORY; 6428 goto error; 6429 } 6430 } 6431 6432 if (pattern_search || argc == 0) { 6433 /* 6434 * We have a set of patterns to search for. Iterate over all 6435 * instances and legacy services searching for matches. 6436 */ 6437 if (scf_handle_get_local_scope(h, scope) != 0) { 6438 ret = scf_error(); 6439 goto error; 6440 } 6441 6442 if (scf_iter_scope_services(sciter, scope) != 0) { 6443 ret = scf_error(); 6444 goto error; 6445 } 6446 6447 for (;;) { 6448 ret = scf_iter_next_service(sciter, svc); 6449 if (ret == 0) 6450 break; 6451 if (ret != 1) { 6452 ret = scf_error(); 6453 goto error; 6454 } 6455 6456 if (flags & SCF_WALK_SERVICE) { 6457 /* 6458 * If the user is requesting bare services, try 6459 * to match the service first. 6460 */ 6461 if (scf_service_to_fmri(svc, fmri, 6462 max_fmri_length + 1) < 0) { 6463 ret = scf_error(); 6464 goto error; 6465 } 6466 6467 if (argc == 0) { 6468 info.fmri = fmri; 6469 info.scope = scope; 6470 info.svc = svc; 6471 info.inst = NULL; 6472 info.pg = NULL; 6473 info.prop = NULL; 6474 if ((ret = callback(data, &info)) != 0) 6475 goto error; 6476 continue; 6477 } else if ((ret = scf_pattern_match(htable, 6478 fmri, NULL, argc, pattern, 6479 flags & SCF_WALK_EXPLICIT)) != 0) { 6480 goto error; 6481 } 6482 } 6483 6484 if (flags & SCF_WALK_NOINSTANCE) 6485 continue; 6486 6487 /* 6488 * Iterate over all instances in the service. 6489 */ 6490 if (scf_iter_service_instances(siter, svc) != 0) { 6491 if (scf_error() != SCF_ERROR_DELETED) { 6492 ret = scf_error(); 6493 goto error; 6494 } 6495 continue; 6496 } 6497 6498 for (;;) { 6499 ret = scf_iter_next_instance(siter, inst); 6500 if (ret == 0) 6501 break; 6502 if (ret != 1) { 6503 if (scf_error() != SCF_ERROR_DELETED) { 6504 ret = scf_error(); 6505 goto error; 6506 } 6507 break; 6508 } 6509 6510 if (scf_instance_to_fmri(inst, fmri, 6511 max_fmri_length + 1) < 0) { 6512 ret = scf_error(); 6513 goto error; 6514 } 6515 6516 /* 6517 * Without arguments, execute the callback 6518 * immediately. 6519 */ 6520 if (argc == 0) { 6521 info.fmri = fmri; 6522 info.scope = scope; 6523 info.svc = svc; 6524 info.inst = inst; 6525 info.pg = NULL; 6526 info.prop = NULL; 6527 if ((ret = callback(data, &info)) != 0) 6528 goto error; 6529 } else if ((ret = scf_pattern_match(htable, 6530 fmri, NULL, argc, pattern, 6531 flags & SCF_WALK_EXPLICIT)) != 0) { 6532 goto error; 6533 } 6534 } 6535 } 6536 6537 /* 6538 * Search legacy services 6539 */ 6540 if ((flags & SCF_WALK_LEGACY)) { 6541 if (scf_scope_get_service(scope, SCF_LEGACY_SERVICE, 6542 svc) != 0) { 6543 if (scf_error() != SCF_ERROR_NOT_FOUND) { 6544 ret = scf_error(); 6545 goto error; 6546 } 6547 6548 goto nolegacy; 6549 } 6550 6551 if (scf_iter_service_pgs_typed(iter, svc, 6552 SCF_GROUP_FRAMEWORK) != SCF_SUCCESS) { 6553 ret = scf_error(); 6554 goto error; 6555 } 6556 6557 (void) strcpy(fmri, LEGACY_SCHEME); 6558 6559 for (;;) { 6560 ret = scf_iter_next_pg(iter, pg); 6561 if (ret == -1) { 6562 ret = scf_error(); 6563 goto error; 6564 } 6565 if (ret == 0) 6566 break; 6567 6568 if (scf_pg_get_property(pg, 6569 SCF_LEGACY_PROPERTY_NAME, prop) == -1) { 6570 ret = scf_error(); 6571 if (ret == SCF_ERROR_DELETED || 6572 ret == SCF_ERROR_NOT_FOUND) { 6573 ret = 0; 6574 continue; 6575 } 6576 goto error; 6577 } 6578 6579 if (scf_property_is_type(prop, SCF_TYPE_ASTRING) 6580 != SCF_SUCCESS) { 6581 if (scf_error() == SCF_ERROR_DELETED) 6582 continue; 6583 ret = scf_error(); 6584 goto error; 6585 } 6586 6587 if (scf_property_get_value(prop, value) != 6588 SCF_SUCCESS) 6589 continue; 6590 6591 if (scf_value_get_astring(value, 6592 fmri + sizeof (LEGACY_SCHEME) - 1, 6593 max_fmri_length + 2 - 6594 sizeof (LEGACY_SCHEME)) <= 0) 6595 continue; 6596 6597 if (scf_pg_get_name(pg, pgname, 6598 max_name_length + 1) <= 0) { 6599 if (scf_error() == SCF_ERROR_DELETED) 6600 continue; 6601 ret = scf_error(); 6602 goto error; 6603 } 6604 6605 if (argc == 0) { 6606 info.fmri = fmri; 6607 info.scope = scope; 6608 info.svc = NULL; 6609 info.inst = NULL; 6610 info.pg = pg; 6611 info.prop = NULL; 6612 if ((ret = callback(data, &info)) != 0) 6613 goto error; 6614 } else if ((ret = scf_pattern_match(htable, 6615 fmri, pgname, argc, pattern, 6616 flags & SCF_WALK_EXPLICIT)) != 0) 6617 goto error; 6618 } 6619 6620 } 6621 } 6622 nolegacy: 6623 ret = 0; 6624 6625 if (argc == 0) 6626 goto error; 6627 6628 /* 6629 * Check all patterns, and see if we have that any that didn't match 6630 * or any that matched multiple instances. For svcprop, add up the 6631 * total number of matching keys. 6632 */ 6633 info.count = 0; 6634 for (i = 0; i < argc; i++) { 6635 scf_match_t *match; 6636 6637 if (pattern[i].sp_type == PATTERN_INVALID) 6638 continue; 6639 if (pattern[i].sp_matchcount == 0) { 6640 scf_msg_t msgid; 6641 /* 6642 * Provide a useful error message based on the argument 6643 * and the type of entity requested. 6644 */ 6645 if (!(flags & SCF_WALK_LEGACY) && 6646 strncmp(pattern[i].sp_arg, "lrc:/", 5) == 0) 6647 msgid = SCF_MSG_PATTERN_LEGACY; 6648 else if (flags & SCF_WALK_PROPERTY) 6649 msgid = SCF_MSG_PATTERN_NOENTITY; 6650 else if (flags & SCF_WALK_NOINSTANCE) 6651 msgid = SCF_MSG_PATTERN_NOSERVICE; 6652 else if (flags & SCF_WALK_SERVICE) 6653 msgid = SCF_MSG_PATTERN_NOINSTSVC; 6654 else 6655 msgid = SCF_MSG_PATTERN_NOINSTANCE; 6656 6657 errfunc(scf_get_msg(msgid), pattern[i].sp_arg); 6658 if (err) 6659 *err = UU_EXIT_FATAL; 6660 } else if (!(flags & SCF_WALK_MULTIPLE) && 6661 pattern[i].sp_matchcount > 1) { 6662 size_t len, off; 6663 char *msg; 6664 6665 /* 6666 * Construct a message with all possible FMRIs before 6667 * passing off to error handling function. 6668 * 6669 * Note that strlen(scf_get_msg(...)) includes the 6670 * length of '%s', which accounts for the terminating 6671 * null byte. 6672 */ 6673 len = strlen(scf_get_msg(SCF_MSG_PATTERN_MULTIMATCH)) + 6674 strlen(pattern[i].sp_arg); 6675 for (match = pattern[i].sp_matches; match != NULL; 6676 match = match->sm_next) { 6677 len += strlen(match->sm_key->sk_fmri) + 2; 6678 } 6679 if ((msg = malloc(len)) == NULL) { 6680 ret = SCF_ERROR_NO_MEMORY; 6681 goto error; 6682 } 6683 6684 /* LINTED - format argument */ 6685 (void) snprintf(msg, len, 6686 scf_get_msg(SCF_MSG_PATTERN_MULTIMATCH), 6687 pattern[i].sp_arg); 6688 off = strlen(msg); 6689 for (match = pattern[i].sp_matches; match != NULL; 6690 match = match->sm_next) { 6691 off += snprintf(msg + off, len - off, "\t%s\n", 6692 match->sm_key->sk_fmri); 6693 } 6694 6695 errfunc(msg); 6696 if (err != NULL) 6697 *err = UU_EXIT_FATAL; 6698 6699 free(msg); 6700 } else { 6701 for (match = pattern[i].sp_matches; match != NULL; 6702 match = match->sm_next) { 6703 if (!match->sm_key->sk_seen) 6704 info.count++; 6705 match->sm_key->sk_seen = 1; 6706 } 6707 } 6708 } 6709 6710 /* 6711 * Clear 'sk_seen' for all keys. 6712 */ 6713 for (i = 0; i < WALK_HTABLE_SIZE; i++) { 6714 scf_matchkey_t *key; 6715 for (key = htable[i]; key != NULL; key = key->sk_next) 6716 key->sk_seen = 0; 6717 } 6718 6719 /* 6720 * Iterate over all the FMRIs in our hash table and execute the 6721 * callback. 6722 */ 6723 for (i = 0; i < argc; i++) { 6724 scf_match_t *match; 6725 scf_matchkey_t *key; 6726 6727 /* 6728 * Ignore patterns which didn't match anything or matched too 6729 * many FMRIs. 6730 */ 6731 if (pattern[i].sp_matchcount == 0 || 6732 (!(flags & SCF_WALK_MULTIPLE) && 6733 pattern[i].sp_matchcount > 1)) 6734 continue; 6735 6736 for (match = pattern[i].sp_matches; match != NULL; 6737 match = match->sm_next) { 6738 6739 key = match->sm_key; 6740 if (key->sk_seen) 6741 continue; 6742 6743 key->sk_seen = 1; 6744 6745 if (key->sk_legacy != NULL) { 6746 if (scf_scope_get_service(scope, 6747 "smf/legacy_run", svc) != 0) { 6748 ret = scf_error(); 6749 goto error; 6750 } 6751 6752 if (scf_service_get_pg(svc, key->sk_legacy, 6753 pg) != 0) 6754 continue; 6755 6756 info.fmri = key->sk_fmri; 6757 info.scope = scope; 6758 info.svc = NULL; 6759 info.inst = NULL; 6760 info.pg = pg; 6761 info.prop = NULL; 6762 if ((ret = callback(data, &info)) != 0) 6763 goto error; 6764 } else { 6765 if (scf_handle_decode_fmri(h, key->sk_fmri, 6766 scope, svc, inst, pg, prop, 0) != 6767 SCF_SUCCESS) 6768 continue; 6769 6770 info.fmri = key->sk_fmri; 6771 info.scope = scope; 6772 info.svc = svc; 6773 if (scf_instance_get_name(inst, NULL, 0) < 0) { 6774 if (scf_error() == 6775 SCF_ERROR_CONNECTION_BROKEN) { 6776 ret = scf_error(); 6777 goto error; 6778 } 6779 info.inst = NULL; 6780 } else { 6781 info.inst = inst; 6782 } 6783 if (scf_pg_get_name(pg, NULL, 0) < 0) { 6784 if (scf_error() == 6785 SCF_ERROR_CONNECTION_BROKEN) { 6786 ret = scf_error(); 6787 goto error; 6788 } 6789 info.pg = NULL; 6790 } else { 6791 info.pg = pg; 6792 } 6793 if (scf_property_get_name(prop, NULL, 0) < 0) { 6794 if (scf_error() == 6795 SCF_ERROR_CONNECTION_BROKEN) { 6796 ret = scf_error(); 6797 goto error; 6798 } 6799 info.prop = NULL; 6800 } else { 6801 info.prop = prop; 6802 } 6803 6804 if ((ret = callback(data, &info)) != 0) 6805 goto error; 6806 } 6807 } 6808 } 6809 6810 error: 6811 if (htable) { 6812 scf_matchkey_t *key, *next; 6813 6814 for (i = 0; i < WALK_HTABLE_SIZE; i++) { 6815 6816 for (key = htable[i]; key != NULL; 6817 key = next) { 6818 6819 next = key->sk_next; 6820 6821 if (key->sk_fmri != NULL) 6822 free(key->sk_fmri); 6823 if (key->sk_legacy != NULL) 6824 free(key->sk_legacy); 6825 free(key); 6826 } 6827 } 6828 free(htable); 6829 } 6830 if (pattern != NULL) { 6831 for (i = 0; i < argc; i++) { 6832 scf_match_t *match, *next; 6833 6834 if (pattern[i].sp_arg != NULL) 6835 free(pattern[i].sp_arg); 6836 6837 for (match = pattern[i].sp_matches; match != NULL; 6838 match = next) { 6839 6840 next = match->sm_next; 6841 6842 free(match); 6843 } 6844 } 6845 free(pattern); 6846 } 6847 6848 free(fmri); 6849 free(pgname); 6850 6851 scf_value_destroy(value); 6852 scf_property_destroy(prop); 6853 scf_pg_destroy(pg); 6854 scf_scope_destroy(scope); 6855 scf_iter_destroy(siter); 6856 scf_iter_destroy(sciter); 6857 scf_iter_destroy(iter); 6858 scf_instance_destroy(inst); 6859 scf_service_destroy(svc); 6860 6861 return (ret); 6862 } 6863 6864 /* 6865 * scf_encode32() is an implementation of Base32 encoding as described in 6866 * section 6 of RFC 4648 - "The Base16, Base32, and Base64 Data 6867 * Encodings". See http://www.ietf.org/rfc/rfc4648.txt?number=4648. The 6868 * input stream is divided into groups of 5 characters (40 bits). Each 6869 * group is encoded into 8 output characters where each output character 6870 * represents 5 bits of input. 6871 * 6872 * If the input is not an even multiple of 5 characters, the output will be 6873 * padded so that the output is an even multiple of 8 characters. The 6874 * standard specifies that the pad character is '='. Unfortunately, '=' is 6875 * not a legal character in SMF property names. Thus, the caller can 6876 * specify an alternate pad character with the pad argument. If pad is 0, 6877 * scf_encode32() will use '='. Note that use of anything other than '=' 6878 * produces output that is not in conformance with RFC 4648. It is 6879 * suitable, however, for internal use of SMF software. When the encoded 6880 * data is used as part of an SMF property name, SCF_ENCODE32_PAD should be 6881 * used as the pad character. 6882 * 6883 * Arguments: 6884 * input - Address of the buffer to be encoded. 6885 * inlen - Number of characters at input. 6886 * output - Address of the buffer to receive the encoded data. 6887 * outmax - Size of the buffer at output. 6888 * outlen - If it is not NULL, outlen receives the number of 6889 * bytes placed in output. 6890 * pad - Alternate padding character. 6891 * 6892 * Returns: 6893 * 0 Buffer was successfully encoded. 6894 * -1 Indicates output buffer too small, or pad is one of the 6895 * standard encoding characters. 6896 */ 6897 int 6898 scf_encode32(const char *input, size_t inlen, char *output, size_t outmax, 6899 size_t *outlen, char pad) 6900 { 6901 uint_t group_size = 5; 6902 uint_t i; 6903 const unsigned char *in = (const unsigned char *)input; 6904 size_t olen; 6905 uchar_t *out = (uchar_t *)output; 6906 uint_t oval; 6907 uint_t pad_count; 6908 6909 /* Verify that there is enough room for the output. */ 6910 olen = ((inlen + (group_size - 1)) / group_size) * 8; 6911 if (outlen) 6912 *outlen = olen; 6913 if (olen > outmax) 6914 return (-1); 6915 6916 /* If caller did not provide pad character, use the default. */ 6917 if (pad == 0) { 6918 pad = '='; 6919 } else { 6920 /* 6921 * Make sure that caller's pad is not one of the encoding 6922 * characters. 6923 */ 6924 for (i = 0; i < sizeof (base32) - 1; i++) { 6925 if (pad == base32[i]) 6926 return (-1); 6927 } 6928 } 6929 6930 /* Process full groups capturing 5 bits per output character. */ 6931 for (; inlen >= group_size; in += group_size, inlen -= group_size) { 6932 /* 6933 * The comments in this section number the bits in an 6934 * 8 bit byte 0 to 7. The high order bit is bit 7 and 6935 * the low order bit is bit 0. 6936 */ 6937 6938 /* top 5 bits (7-3) from in[0] */ 6939 *out++ = base32[in[0] >> 3]; 6940 /* bits 2-0 from in[0] and top 2 (7-6) from in[1] */ 6941 *out++ = base32[((in[0] << 2) & 0x1c) | (in[1] >> 6)]; 6942 /* 5 bits (5-1) from in[1] */ 6943 *out++ = base32[(in[1] >> 1) & 0x1f]; 6944 /* low bit (0) from in[1] and top 4 (7-4) from in[2] */ 6945 *out++ = base32[((in[1] << 4) & 0x10) | ((in[2] >> 4) & 0xf)]; 6946 /* low 4 (3-0) from in[2] and top bit (7) from in[3] */ 6947 *out++ = base32[((in[2] << 1) & 0x1e) | (in[3] >> 7)]; 6948 /* 5 bits (6-2) from in[3] */ 6949 *out++ = base32[(in[3] >> 2) & 0x1f]; 6950 /* low 2 (1-0) from in[3] and top 3 (7-5) from in[4] */ 6951 *out++ = base32[((in[3] << 3) & 0x18) | (in[4] >> 5)]; 6952 /* low 5 (4-0) from in[4] */ 6953 *out++ = base32[in[4] & 0x1f]; 6954 } 6955 6956 /* Take care of final input bytes. */ 6957 pad_count = 0; 6958 if (inlen) { 6959 /* top 5 bits (7-3) from in[0] */ 6960 *out++ = base32[in[0] >> 3]; 6961 /* 6962 * low 3 (2-0) from in[0] and top 2 (7-6) from in[1] if 6963 * available. 6964 */ 6965 oval = (in[0] << 2) & 0x1c; 6966 if (inlen == 1) { 6967 *out++ = base32[oval]; 6968 pad_count = 6; 6969 goto padout; 6970 } 6971 oval |= in[1] >> 6; 6972 *out++ = base32[oval]; 6973 /* 5 bits (5-1) from in[1] */ 6974 *out++ = base32[(in[1] >> 1) & 0x1f]; 6975 /* 6976 * low bit (0) from in[1] and top 4 (7-4) from in[2] if 6977 * available. 6978 */ 6979 oval = (in[1] << 4) & 0x10; 6980 if (inlen == 2) { 6981 *out++ = base32[oval]; 6982 pad_count = 4; 6983 goto padout; 6984 } 6985 oval |= in[2] >> 4; 6986 *out++ = base32[oval]; 6987 /* 6988 * low 4 (3-0) from in[2] and top 1 (7) from in[3] if 6989 * available. 6990 */ 6991 oval = (in[2] << 1) & 0x1e; 6992 if (inlen == 3) { 6993 *out++ = base32[oval]; 6994 pad_count = 3; 6995 goto padout; 6996 } 6997 oval |= in[3] >> 7; 6998 *out++ = base32[oval]; 6999 /* 5 bits (6-2) from in[3] */ 7000 *out++ = base32[(in[3] >> 2) & 0x1f]; 7001 /* low 2 bits (1-0) from in[3] */ 7002 *out++ = base32[(in[3] << 3) & 0x18]; 7003 pad_count = 1; 7004 } 7005 padout: 7006 /* 7007 * Pad the output so that it is a multiple of 8 bytes. 7008 */ 7009 for (; pad_count > 0; pad_count--) { 7010 *out++ = pad; 7011 } 7012 7013 /* 7014 * Null terminate the output if there is enough room. 7015 */ 7016 if (olen < outmax) 7017 *out = 0; 7018 7019 return (0); 7020 } 7021 7022 /* 7023 * scf_decode32() is an implementation of Base32 decoding as described in 7024 * section 6 of RFC 4648 - "The Base16, Base32, and Base64 Data 7025 * Encodings". See http://www.ietf.org/rfc/rfc4648.txt?number=4648. The 7026 * input stream is divided into groups of 8 encoded characters. Each 7027 * encoded character represents 5 bits of data. Thus, the 8 encoded 7028 * characters are used to produce 40 bits or 5 bytes of unencoded data in 7029 * outbuf. 7030 * 7031 * If the encoder did not have enough data to generate a mulitple of 8 7032 * characters of encoded data, it used a pad character to get to the 8 7033 * character boundry. The standard specifies that the pad character is '='. 7034 * Unfortunately, '=' is not a legal character in SMF property names. 7035 * Thus, the caller can specify an alternate pad character with the pad 7036 * argument. If pad is 0, scf_decode32() will use '='. Note that use of 7037 * anything other than '=' is not in conformance with RFC 4648. It is 7038 * suitable, however, for internal use of SMF software. When the encoded 7039 * data is used in SMF property names, SCF_ENCODE32_PAD should be used as 7040 * the pad character. 7041 * 7042 * Arguments: 7043 * in - Buffer of encoded characters. 7044 * inlen - Number of characters at in. 7045 * outbuf - Buffer to receive the decoded bytes. It can be the 7046 * same buffer as in. 7047 * outmax - Size of the buffer at outbuf. 7048 * outlen - If it is not NULL, outlen receives the number of 7049 * bytes placed in output. 7050 * pad - Alternate padding character. 7051 * 7052 * Returns: 7053 * 0 Buffer was successfully decoded. 7054 * -1 Indicates an invalid input character, output buffer too 7055 * small, or pad is one of the standard encoding characters. 7056 */ 7057 int 7058 scf_decode32(const char *in, size_t inlen, char *outbuf, size_t outmax, 7059 size_t *outlen, char pad) 7060 { 7061 char *bufend = outbuf + outmax; 7062 char c; 7063 uint_t count; 7064 uint32_t g[DECODE32_GS]; 7065 size_t i; 7066 uint_t j; 7067 char *out = outbuf; 7068 boolean_t pad_seen = B_FALSE; 7069 7070 /* If caller did not provide pad character, use the default. */ 7071 if (pad == 0) { 7072 pad = '='; 7073 } else { 7074 /* 7075 * Make sure that caller's pad is not one of the encoding 7076 * characters. 7077 */ 7078 for (i = 0; i < sizeof (base32) - 1; i++) { 7079 if (pad == base32[i]) 7080 return (-1); 7081 } 7082 } 7083 7084 i = 0; 7085 while ((i < inlen) && (out < bufend)) { 7086 /* Get a group of input characters. */ 7087 for (j = 0, count = 0; 7088 (j < DECODE32_GS) && (i < inlen); 7089 i++) { 7090 c = in[i]; 7091 /* 7092 * RFC 4648 allows for the encoded data to be split 7093 * into multiple lines, so skip carriage returns 7094 * and new lines. 7095 */ 7096 if ((c == '\r') || (c == '\n')) 7097 continue; 7098 if ((pad_seen == B_TRUE) && (c != pad)) { 7099 /* Group not completed by pads */ 7100 return (-1); 7101 } 7102 if ((c < 0) || (c >= sizeof (index32))) { 7103 /* Illegal character. */ 7104 return (-1); 7105 } 7106 if (c == pad) { 7107 pad_seen = B_TRUE; 7108 continue; 7109 } 7110 if ((g[j++] = index32[c]) == 0xff) { 7111 /* Illegal character */ 7112 return (-1); 7113 } 7114 count++; 7115 } 7116 7117 /* Pack the group into five 8 bit bytes. */ 7118 if ((count >= 2) && (out < bufend)) { 7119 /* 7120 * Output byte 0: 7121 * 5 bits (7-3) from g[0] 7122 * 3 bits (2-0) from g[1] (4-2) 7123 */ 7124 *out++ = (g[0] << 3) | ((g[1] >> 2) & 0x7); 7125 } 7126 if ((count >= 4) && (out < bufend)) { 7127 /* 7128 * Output byte 1: 7129 * 2 bits (7-6) from g[1] (1-0) 7130 * 5 bits (5-1) from g[2] (4-0) 7131 * 1 bit (0) from g[3] (4) 7132 */ 7133 *out++ = (g[1] << 6) | (g[2] << 1) | \ 7134 ((g[3] >> 4) & 0x1); 7135 } 7136 if ((count >= 5) && (out < bufend)) { 7137 /* 7138 * Output byte 2: 7139 * 4 bits (7-4) from g[3] (3-0) 7140 * 4 bits (3-0) from g[4] (4-1) 7141 */ 7142 *out++ = (g[3] << 4) | ((g[4] >> 1) & 0xf); 7143 } 7144 if ((count >= 7) && (out < bufend)) { 7145 /* 7146 * Output byte 3: 7147 * 1 bit (7) from g[4] (0) 7148 * 5 bits (6-2) from g[5] (4-0) 7149 * 2 bits (0-1) from g[6] (4-3) 7150 */ 7151 *out++ = (g[4] << 7) | (g[5] << 2) | 7152 ((g[6] >> 3) & 0x3); 7153 } 7154 if ((count == 8) && (out < bufend)) { 7155 /* 7156 * Output byte 4; 7157 * 3 bits (7-5) from g[6] (2-0) 7158 * 5 bits (4-0) from g[7] (4-0) 7159 */ 7160 *out++ = (g[6] << 5) | g[7]; 7161 } 7162 } 7163 if (i < inlen) { 7164 /* Did not process all input characters. */ 7165 return (-1); 7166 } 7167 if (outlen) 7168 *outlen = out - outbuf; 7169 /* Null terminate the output if there is room. */ 7170 if (out < bufend) 7171 *out = 0; 7172 return (0); 7173 } 7174 7175 7176 /* 7177 * _scf_request_backup: a simple wrapper routine 7178 */ 7179 int 7180 _scf_request_backup(scf_handle_t *h, const char *name) 7181 { 7182 struct rep_protocol_backup_request request; 7183 struct rep_protocol_response response; 7184 7185 int r; 7186 7187 if (strlcpy(request.rpr_name, name, sizeof (request.rpr_name)) >= 7188 sizeof (request.rpr_name)) 7189 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 7190 7191 (void) pthread_mutex_lock(&h->rh_lock); 7192 request.rpr_request = REP_PROTOCOL_BACKUP; 7193 request.rpr_changeid = handle_next_changeid(h); 7194 7195 r = make_door_call(h, &request, sizeof (request), 7196 &response, sizeof (response)); 7197 (void) pthread_mutex_unlock(&h->rh_lock); 7198 7199 if (r < 0) { 7200 DOOR_ERRORS_BLOCK(r); 7201 } 7202 7203 if (response.rpr_response != REP_PROTOCOL_SUCCESS) 7204 return (scf_set_error(proto_error(response.rpr_response))); 7205 return (SCF_SUCCESS); 7206 } 7207 7208 /* 7209 * Request svc.configd daemon to switch repository database. 7210 * 7211 * Can fail: 7212 * 7213 * _NOT_BOUND handle is not bound 7214 * _CONNECTION_BROKEN server is not reachable 7215 * _INTERNAL file operation error 7216 * the server response is too big 7217 * _PERMISSION_DENIED not enough privileges to do request 7218 * _BACKEND_READONLY backend is not writable 7219 * _BACKEND_ACCESS backend access fails 7220 * _NO_RESOURCES svc.configd is out of memory 7221 */ 7222 int 7223 _scf_repository_switch(scf_handle_t *h, int scf_sw) 7224 { 7225 struct rep_protocol_switch_request request; 7226 struct rep_protocol_response response; 7227 int r; 7228 7229 /* 7230 * Setup request protocol and make door call 7231 * Hold rh_lock lock before handle_next_changeid call 7232 */ 7233 (void) pthread_mutex_lock(&h->rh_lock); 7234 7235 request.rpr_flag = scf_sw; 7236 request.rpr_request = REP_PROTOCOL_SWITCH; 7237 request.rpr_changeid = handle_next_changeid(h); 7238 7239 r = make_door_call(h, &request, sizeof (request), 7240 &response, sizeof (response)); 7241 7242 (void) pthread_mutex_unlock(&h->rh_lock); 7243 7244 if (r < 0) { 7245 DOOR_ERRORS_BLOCK(r); 7246 } 7247 7248 /* 7249 * Pass protocol error up 7250 */ 7251 if (response.rpr_response != REP_PROTOCOL_SUCCESS) 7252 return (scf_set_error(proto_error(response.rpr_response))); 7253 7254 return (SCF_SUCCESS); 7255 } 7256 7257 int 7258 _scf_pg_is_read_protected(const scf_propertygroup_t *pg, boolean_t *out) 7259 { 7260 char buf[REP_PROTOCOL_NAME_LEN]; 7261 ssize_t res; 7262 7263 res = datael_get_name(&pg->rd_d, buf, sizeof (buf), 7264 RP_ENTITY_NAME_PGREADPROT); 7265 7266 if (res == -1) 7267 return (-1); 7268 7269 if (uu_strtouint(buf, out, sizeof (*out), 0, 0, 1) == -1) 7270 return (scf_set_error(SCF_ERROR_INTERNAL)); 7271 return (SCF_SUCCESS); 7272 } 7273 7274 /* 7275 * _scf_set_annotation: a wrapper to set the annotation fields for SMF 7276 * security auditing. 7277 * 7278 * Fails with following in scf_error_key thread specific data: 7279 * _INVALID_ARGUMENT - operation or file too large 7280 * _NOT_BOUND 7281 * _CONNECTION_BROKEN 7282 * _INTERNAL 7283 * _NO_RESOURCES 7284 */ 7285 int 7286 _scf_set_annotation(scf_handle_t *h, const char *operation, const char *file) 7287 { 7288 struct rep_protocol_annotation request; 7289 struct rep_protocol_response response; 7290 size_t copied; 7291 int r; 7292 7293 if (h == NULL) { 7294 /* We can't do anything if the handle is destroyed. */ 7295 return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED)); 7296 } 7297 7298 request.rpr_request = REP_PROTOCOL_SET_AUDIT_ANNOTATION; 7299 copied = strlcpy(request.rpr_operation, 7300 (operation == NULL) ? "" : operation, 7301 sizeof (request.rpr_operation)); 7302 if (copied >= sizeof (request.rpr_operation)) 7303 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 7304 7305 copied = strlcpy(request.rpr_file, 7306 (file == NULL) ? "" : file, 7307 sizeof (request.rpr_file)); 7308 if (copied >= sizeof (request.rpr_file)) 7309 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 7310 7311 (void) pthread_mutex_lock(&h->rh_lock); 7312 r = make_door_call(h, &request, sizeof (request), 7313 &response, sizeof (response)); 7314 (void) pthread_mutex_unlock(&h->rh_lock); 7315 7316 if (r < 0) { 7317 DOOR_ERRORS_BLOCK(r); 7318 } 7319 7320 if (response.rpr_response != REP_PROTOCOL_SUCCESS) 7321 return (scf_set_error(proto_error(response.rpr_response))); 7322 return (0); 7323 } 7324