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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * Routines used by inetd to read inetd's configuration from the repository, 31 * to validate it and setup inetd's data structures appropriately based on 32 * in. 33 */ 34 35 #include <stdlib.h> 36 #include <string.h> 37 #include <errno.h> 38 #include <unistd.h> 39 #include <netdb.h> 40 #include <netinet/in.h> 41 #include <libintl.h> 42 #include <nss_dbdefs.h> 43 #include <signal.h> 44 #include <wait.h> 45 #include "inetd_impl.h" 46 47 48 /* method timeout used if one isn't explicitly specified */ 49 #define DEFAULT_METHOD_TIMEOUT 10 50 51 52 /* supported method properties and their attributes */ 53 static inetd_prop_t method_props[] = { 54 {PR_EXEC_NAME, "", INET_TYPE_STRING, B_FALSE, IVE_UNSET, NULL, B_FALSE}, 55 {PR_ARG0_NAME, "", INET_TYPE_STRING, B_TRUE, IVE_UNSET, NULL, B_FALSE}, 56 {SCF_PROPERTY_TIMEOUT, "", INET_TYPE_COUNT, B_TRUE, IVE_UNSET, NULL, B_FALSE}, 57 {NULL}, 58 }; 59 60 /* enumeration of method properties; used to index into method_props[] */ 61 typedef enum { 62 MP_EXEC, 63 MP_ARG0, 64 MP_TIMEOUT 65 } method_prop_t; 66 67 68 /* handle used for repository access in read_prop() */ 69 static scf_handle_t *rep_handle = NULL; 70 71 /* pool used to create proto_info_t lists (generic proto info structure) */ 72 static uu_list_pool_t *proto_info_pool = NULL; 73 74 static void destroy_method_props(inetd_prop_t *); 75 static int proto_info_compare(const void *, const void *, void *); 76 77 int 78 config_init(void) 79 { 80 if ((rep_handle = scf_handle_create(SCF_VERSION)) == NULL) { 81 error_msg("%s: %s", 82 gettext("Failed to create repository handle"), 83 scf_strerror(scf_error())); 84 return (-1); 85 } else if (make_handle_bound(rep_handle) == -1) { 86 /* let config_fini clean-up */ 87 return (-1); 88 } 89 90 if ((proto_info_pool = uu_list_pool_create("proto_info_pool", 91 sizeof (proto_info_t), offsetof(proto_info_t, link), 92 proto_info_compare, UU_LIST_POOL_DEBUG)) == NULL) { 93 error_msg(gettext("Failed to create uu list pool: %s"), 94 uu_strerror(uu_error())); 95 return (-1); 96 } 97 98 return (0); 99 } 100 101 void 102 config_fini(void) 103 { 104 if (rep_handle == NULL) 105 return; 106 107 if (proto_info_pool != NULL) { 108 uu_list_pool_destroy(proto_info_pool); 109 proto_info_pool = NULL; 110 } 111 112 (void) scf_handle_unbind(rep_handle); 113 scf_handle_destroy(rep_handle); 114 rep_handle = NULL; 115 } 116 117 static void 118 destroy_method_info(method_info_t *mi) 119 { 120 if (mi == NULL) 121 return; 122 123 if (mi->wordexp_arg0_backup != NULL) { 124 /* 125 * Return the wordexp structure back to its original 126 * state so it can be consumed by wordfree. 127 */ 128 free(mi->exec_args_we.we_wordv[0]); 129 mi->exec_args_we.we_wordv[0] = 130 (char *)mi->wordexp_arg0_backup; 131 } 132 133 free(mi->exec_path); 134 135 wordfree(&mi->exec_args_we); 136 137 free(mi); 138 } 139 140 /* 141 * Transforms the properties read from the repository for a method into a 142 * method_info_t and returns a pointer to it. If expansion of the exec 143 * property fails, due to an invalid string or memory allocation failure, 144 * NULL is returned and exec_invalid is set appropriately to indicate whether 145 * it was a memory allocation failure or an invalid exec string. 146 */ 147 static method_info_t * 148 create_method_info(const inetd_prop_t *mprops, boolean_t *exec_invalid) 149 { 150 method_info_t *ret; 151 int i; 152 153 debug_msg("Entering create_method_info"); 154 155 if ((ret = calloc(1, sizeof (method_info_t))) == NULL) 156 goto alloc_fail; 157 158 /* Expand the exec string. */ 159 if ((i = wordexp(get_prop_value_string(mprops, PR_EXEC_NAME), 160 &ret->exec_args_we, WRDE_NOCMD|WRDE_UNDEF)) != 0) { 161 if (i == WRDE_NOSPACE) 162 goto alloc_fail; 163 164 *exec_invalid = B_TRUE; 165 free(ret); 166 return (NULL); 167 } 168 169 if ((ret->exec_path = strdup(ret->exec_args_we.we_wordv[0])) == NULL) 170 goto alloc_fail; 171 172 if (mprops[MP_ARG0].ip_error == IVE_VALID) { /* arg0 is set */ 173 /* 174 * Keep a copy of arg0 of the wordexp structure so that 175 * wordfree() gets passed what wordexp() originally returned, 176 * as documented as required in the man page. 177 */ 178 ret->wordexp_arg0_backup = ret->exec_args_we.we_wordv[0]; 179 if ((ret->exec_args_we.we_wordv[0] = 180 strdup(get_prop_value_string(mprops, PR_ARG0_NAME))) 181 == NULL) 182 goto alloc_fail; 183 } 184 185 if (mprops[MP_TIMEOUT].ip_error == IVE_VALID) { 186 ret->timeout = get_prop_value_count(mprops, 187 SCF_PROPERTY_TIMEOUT); 188 } else { 189 ret->timeout = DEFAULT_METHOD_TIMEOUT; 190 } 191 192 /* exec_invalid not set on success */ 193 194 return (ret); 195 196 alloc_fail: 197 error_msg(strerror(errno)); 198 destroy_method_info(ret); 199 *exec_invalid = B_FALSE; 200 return (NULL); 201 } 202 203 /* 204 * Returns B_TRUE if the contents of the 2 method_info_t structures are 205 * equivalent, else B_FALSE. 206 */ 207 boolean_t 208 method_info_equal(const method_info_t *mi, const method_info_t *mi2) 209 { 210 int i; 211 212 debug_msg("Entering method_info_equal"); 213 214 if ((mi == NULL) && (mi2 == NULL)) { 215 return (B_TRUE); 216 } else if (((mi == NULL) || (mi2 == NULL)) || 217 (mi->exec_args_we.we_wordc != mi2->exec_args_we.we_wordc) || 218 (strcmp(mi->exec_path, mi2->exec_path) != 0)) { 219 return (B_FALSE); 220 } 221 222 for (i = 0; i < mi->exec_args_we.we_wordc; i++) { 223 if (strcmp(mi->exec_args_we.we_wordv[i], 224 mi2->exec_args_we.we_wordv[i]) != 0) { 225 return (B_FALSE); 226 } 227 } 228 229 return (B_TRUE); 230 } 231 232 /* 233 * Checks if the contents of the 2 socket_info_t structures are equivalent. 234 * If 'isrpc' is false, the address components of the two structures are 235 * compared for equality as part of this. If the two structures are 236 * equivalent B_TRUE is returned, else B_FALSE. 237 */ 238 boolean_t 239 socket_info_equal(const socket_info_t *si, const socket_info_t *si2, 240 boolean_t isrpc) 241 { 242 return ((isrpc || (memcmp(&si->local_addr, &si2->local_addr, 243 sizeof (si->local_addr)) == 0)) && 244 (si->type == si2->type)); 245 246 } 247 248 /* 249 * proto_info_t comparison function. Returns 0 on match, else -1, as required 250 * by uu_list_find(). 251 */ 252 static int 253 proto_info_compare(const void *lv, const void *rv, void *istlx) 254 { 255 proto_info_t *pi = (proto_info_t *)lv; 256 proto_info_t *pi2 = (proto_info_t *)rv; 257 258 /* check their RPC configuration matches */ 259 if (pi->ri != NULL) { 260 if ((pi2->ri == NULL) || !rpc_info_equal(pi->ri, pi2->ri)) 261 return (-1); 262 } else if (pi2->ri != NULL) { 263 return (-1); 264 } 265 266 if (pi->v6only != pi2->v6only) 267 return (-1); 268 269 if (*(boolean_t *)istlx) { 270 if (tlx_info_equal((tlx_info_t *)lv, (tlx_info_t *)rv, 271 pi->ri != NULL)) 272 return (0); 273 } else { 274 if (socket_info_equal((socket_info_t *)lv, 275 (socket_info_t *)rv, pi->ri != NULL)) 276 return (0); 277 } 278 return (-1); 279 } 280 281 /* 282 * Returns B_TRUE if the bind configuration of the two instance_cfg_t 283 * structures are equivalent, else B_FALSE. 284 */ 285 boolean_t 286 bind_config_equal(const basic_cfg_t *c1, const basic_cfg_t *c2) 287 { 288 proto_info_t *pi; 289 290 debug_msg("Entering bind_config_equal"); 291 292 if ((c1->iswait != c2->iswait) || 293 (c1->istlx != c2->istlx)) 294 return (B_FALSE); 295 296 if (uu_list_numnodes(c1->proto_list) != 297 uu_list_numnodes(c2->proto_list)) 298 return (B_FALSE); 299 /* 300 * For each element in the first configuration's socket/tlx list, 301 * check there's a matching one in the other list. 302 */ 303 for (pi = uu_list_first(c1->proto_list); pi != NULL; 304 pi = uu_list_next(c1->proto_list, pi)) { 305 uu_list_index_t idx; 306 307 if (uu_list_find(c2->proto_list, pi, (void *)&c1->istlx, 308 &idx) == NULL) 309 return (B_FALSE); 310 } 311 312 return (B_TRUE); 313 } 314 315 /* 316 * Write the default values contained in 'bprops', read by 317 * read_instance_props(), into 'cfg'. 318 * Returns -1 if memory allocation fails, else 0. 319 */ 320 static int 321 populate_defaults(inetd_prop_t *bprops, basic_cfg_t *cfg) 322 { 323 debug_msg("Entering populate_defaults"); 324 325 cfg->do_tcp_wrappers = get_prop_value_boolean(bprops, 326 PR_DO_TCP_WRAPPERS_NAME); 327 cfg->do_tcp_trace = get_prop_value_boolean(bprops, 328 PR_DO_TCP_TRACE_NAME); 329 cfg->inherit_env = get_prop_value_boolean(bprops, PR_INHERIT_ENV_NAME); 330 cfg->wait_fail_cnt = get_prop_value_int(bprops, 331 PR_MAX_FAIL_RATE_CNT_NAME); 332 cfg->wait_fail_interval = get_prop_value_int(bprops, 333 PR_MAX_FAIL_RATE_INTVL_NAME); 334 cfg->max_copies = get_prop_value_int(bprops, PR_MAX_COPIES_NAME); 335 cfg->conn_rate_offline = get_prop_value_int(bprops, 336 PR_CON_RATE_OFFLINE_NAME); 337 cfg->conn_rate_max = get_prop_value_int(bprops, PR_CON_RATE_MAX_NAME); 338 cfg->bind_fail_interval = get_prop_value_int(bprops, 339 PR_BIND_FAIL_INTVL_NAME); 340 cfg->bind_fail_max = get_prop_value_int(bprops, PR_BIND_FAIL_MAX_NAME); 341 if ((cfg->bind_addr = 342 strdup(get_prop_value_string(bprops, PR_BIND_ADDR_NAME))) == NULL) { 343 error_msg(strerror(errno)); 344 return (-1); 345 } 346 return (0); 347 } 348 349 void 350 destroy_method_infos(method_info_t **mis) 351 { 352 int i; 353 354 for (i = 0; i < NUM_METHODS; i++) { 355 destroy_method_info(mis[i]); 356 mis[i] = NULL; 357 } 358 } 359 360 /* 361 * For each method, if it was specifed convert its entry in 'mprops', 362 * into an entry in 'mis'. Returns -1 if memory allocation fails or one of the 363 * exec strings was invalid, else 0. 364 */ 365 static int 366 create_method_infos(const char *fmri, inetd_prop_t **mprops, 367 method_info_t **mis) 368 { 369 int i; 370 371 debug_msg("Entering create_method_infos, inst: %s", fmri); 372 373 for (i = 0; i < NUM_METHODS; i++) { 374 /* 375 * Only create a method info structure if the method properties 376 * contain an exec string, which we take to mean the method 377 * is specified. 378 */ 379 if (mprops[i][MP_EXEC].ip_error == IVE_VALID) { 380 boolean_t exec_invalid; 381 382 if ((mis[i] = create_method_info(mprops[i], 383 &exec_invalid)) == NULL) { 384 if (exec_invalid) { 385 error_msg(gettext("Property %s for " 386 "method %s of instance %s is " 387 "invalid"), PR_EXEC_NAME, 388 methods[i].name, fmri); 389 } 390 return (-1); 391 } 392 } 393 } 394 return (0); 395 } 396 397 /* 398 * Try and read each of the method properties for the method 'method' of 399 * instance 'inst', and return a table containing all method properties. If an 400 * error occurs, NULL is returned, with 'err' set to indicate the cause. 401 * Otherwise, a pointer to an inetd_prop_t table is returned containing all 402 * the method properties, and each of the properties is flagged according to 403 * whether it was present or not, and if it was present its value is set in 404 * the property's entry in the table. 405 */ 406 static inetd_prop_t * 407 read_method_props(const char *inst, instance_method_t method, scf_error_t *err) 408 { 409 inetd_prop_t *ret; 410 int i; 411 412 debug_msg("Entering read_method_props"); 413 414 if ((ret = calloc(1, sizeof (method_props))) == NULL) { 415 *err = SCF_ERROR_NO_MEMORY; 416 return (NULL); 417 } 418 419 (void) memcpy(ret, method_props, sizeof (method_props)); 420 for (i = 0; ret[i].ip_name != NULL; i++) { 421 *err = read_prop(rep_handle, &ret[i], i, inst, 422 methods[method].name); 423 if ((*err != 0) && (*err != SCF_ERROR_NOT_FOUND)) { 424 destroy_method_props(ret); 425 return (NULL); 426 } 427 } 428 429 return (ret); 430 } 431 432 static void 433 destroy_method_props(inetd_prop_t *mprop) 434 { 435 int i; 436 437 if (mprop == NULL) 438 return; 439 440 for (i = 0; mprop[i].ip_name != NULL; i++) { 441 if (mprop[i].ip_type == INET_TYPE_STRING && 442 mprop[i].ip_error == IVE_VALID) 443 free(mprop[i].ip_value.iv_string); 444 } 445 446 free(mprop); 447 } 448 449 /* 450 * Destroy the basic and method properties returned by read_inst_props(). 451 */ 452 static void 453 destroy_inst_props(inetd_prop_t *bprops, inetd_prop_t **mprops) 454 { 455 int i; 456 457 free_instance_props(bprops); 458 for (i = 0; i < NUM_METHODS; i++) 459 destroy_method_props(mprops[i]); 460 } 461 462 /* 463 * Read all the basic and method properties for instance 'inst', as inetd_prop_t 464 * tables, into the spaces referenced by 'bprops' and 'mprops' respectively. 465 * Each of the properties in the tables are flagged to indicate if the 466 * property was present or not, and if it was the value is stored within it. 467 * If an error occurs at any time -1 is returned and 'err' is set to 468 * indicate the reason, else 0 is returned. 469 */ 470 static int 471 read_inst_props(const char *fmri, inetd_prop_t **bprops, 472 inetd_prop_t **mprops, scf_error_t *err) 473 { 474 size_t nprops; 475 int i; 476 477 debug_msg("Entering read_inst_props"); 478 479 if ((*bprops = read_instance_props(rep_handle, (char *)fmri, &nprops, 480 err)) == NULL) 481 return (-1); 482 483 for (i = 0; i < NUM_METHODS; i++) { 484 if ((mprops[i] = 485 read_method_props(fmri, (instance_method_t)i, err)) == 486 NULL) { 487 for (i--; i >= 0; i--) 488 destroy_method_props(mprops[i]); 489 free_instance_props(*bprops); 490 return (-1); 491 } 492 } 493 494 return (0); 495 } 496 497 /* 498 * Returns B_TRUE if all required properties were read from the repository 499 * (whether taken from the defaults or directly from the instance), they 500 * all had valid values, all the required methods were present, and they 501 * each had the required properties with valid values. Else, returns B_FALSE. 502 * If the function returns B_TRUE, the storage referenced by 'cfg' is set 503 * to point at an allocated instance_cfg_t initialized based on the basic 504 * properties (not method or defaults). 505 */ 506 static boolean_t 507 valid_inst_props(const char *fmri, inetd_prop_t *bprops, inetd_prop_t **mprops, 508 basic_cfg_t **cfg) 509 { 510 boolean_t valid; 511 size_t num_bprops; 512 int i; 513 514 debug_msg("Entering valid_inst_props: inst: %s, bprops: %x, mprops: %x", 515 fmri, bprops, *mprops); 516 517 valid = valid_props(bprops, fmri, cfg, proto_info_pool, conn_ind_pool); 518 519 /* 520 * Double check we've got all necessary properties (valid_props() 521 * doesn't enforce the presence of defaults), and output error messages 522 * for each invalid/ missing property. 523 */ 524 (void) get_prop_table(&num_bprops); 525 for (i = 0; bprops[i].ip_name != NULL; i++) { 526 switch (bprops[i].ip_error) { 527 case IVE_UNSET: 528 if (!bprops[i].ip_default) 529 continue; 530 if ((i == PT_ARG0_INDEX) || (i == PT_EXEC_INDEX)) 531 continue; 532 /* FALLTHROUGH */ 533 case IVE_INVALID: 534 error_msg(gettext("Property '%s' of instance " 535 "%s is missing, inconsistent or invalid"), 536 bprops[i].ip_name, fmri); 537 valid = B_FALSE; 538 } 539 } 540 541 for (i = 0; i < NUM_METHODS; i++) { 542 int j; 543 544 /* check if any properties are set */ 545 for (j = 0; mprops[i][j].ip_name != NULL; j++) { 546 if (mprops[i][j].ip_error != IVE_UNSET) 547 break; 548 } 549 550 if (mprops[i][j].ip_name == NULL) { 551 /* an unspecified method */ 552 if ((instance_method_t)i == IM_START) { 553 error_msg(gettext( 554 "Unspecified %s method for instance %s"), 555 START_METHOD_NAME, fmri); 556 valid = B_FALSE; 557 } 558 } else if (mprops[i][MP_EXEC].ip_error == IVE_UNSET) { 559 error_msg(gettext("Missing %s property from method %s " 560 "of instance %s"), PR_EXEC_NAME, 561 methods[(instance_method_t)i].name, fmri); 562 valid = B_FALSE; 563 } 564 } 565 566 if (!valid) 567 destroy_basic_cfg(*cfg); 568 569 return (valid); 570 } 571 572 void 573 destroy_instance_cfg(instance_cfg_t *cfg) 574 { 575 if (cfg != NULL) { 576 destroy_basic_cfg(cfg->basic); 577 destroy_method_infos(cfg->methods); 578 free(cfg); 579 } 580 } 581 582 /* 583 * Returns an allocated instance_cfg_t representation of an instance's 584 * configuration read from the repository. If the configuration is invalid, a 585 * repository error occurred, or a memory allocation occurred returns NULL, 586 * else returns a pointer to the allocated instance_cfg_t. 587 */ 588 instance_cfg_t * 589 read_instance_cfg(const char *fmri) 590 { 591 uint_t retries; 592 inetd_prop_t *bprops; 593 inetd_prop_t *mprops[NUM_METHODS]; 594 instance_cfg_t *ret = NULL; 595 scf_error_t err; 596 597 debug_msg("Entering read_instance_cfg"); 598 599 if ((ret = calloc(1, sizeof (instance_cfg_t))) == NULL) 600 return (NULL); 601 602 for (retries = 0; retries <= REP_OP_RETRIES; retries++) { 603 if (make_handle_bound(rep_handle) == -1) { 604 err = scf_error(); 605 goto read_error; 606 } 607 608 if (read_inst_props(fmri, &bprops, mprops, &err) == 0) 609 break; 610 if (err != SCF_ERROR_CONNECTION_BROKEN) 611 goto read_error; 612 (void) scf_handle_unbind(rep_handle); 613 } 614 if (retries > REP_OP_RETRIES) 615 goto read_error; 616 617 /* 618 * Switch off validation of the start method's exec string, since 619 * during boot the filesystem it resides on may not have been 620 * mounted yet, which would result in a false validation failure. 621 * We'll catch any real errors when the start method is first run 622 * in passes_basic_exec_checks(). 623 */ 624 bprops[PT_EXEC_INDEX].ip_error = IVE_UNSET; 625 626 if ((!valid_inst_props(fmri, bprops, mprops, &ret->basic)) || 627 (populate_defaults(bprops, ret->basic) != 0) || 628 (create_method_infos(fmri, mprops, ret->methods) != 0)) { 629 destroy_instance_cfg(ret); 630 ret = NULL; 631 } 632 633 destroy_inst_props(bprops, mprops); 634 return (ret); 635 636 read_error: 637 error_msg(gettext( 638 "Failed to read the configuration of instance %s: %s"), fmri, 639 scf_strerror(err)); 640 free(ret); 641 return (NULL); 642 } 643 644 /* 645 * Returns a pointer to an allocated method context for the specified method 646 * of the specified instance if it could retrieve it. Else, if there were 647 * errors retrieving it, NULL is returned and the pointer referenced by 648 * 'errstr' is set to point at an appropriate error string. 649 */ 650 struct method_context * 651 read_method_context(const char *inst_fmri, const char *method, const char *path, 652 const char **errstr) 653 { 654 scf_instance_t *scf_inst = NULL; 655 struct method_context *ret; 656 uint_t retries; 657 const char *tmpstr; 658 659 debug_msg("Entering read_method_context: inst: %s, method: %s, " 660 "path: %s", inst_fmri, method, path); 661 662 for (retries = 0; retries <= REP_OP_RETRIES; retries++) { 663 if (make_handle_bound(rep_handle) == -1) 664 goto inst_failure; 665 666 if (((scf_inst = scf_instance_create(rep_handle)) != NULL) && 667 (scf_handle_decode_fmri(rep_handle, inst_fmri, NULL, NULL, 668 scf_inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) == 0)) 669 break; 670 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN) { 671 scf_instance_destroy(scf_inst); 672 goto inst_failure; 673 } 674 675 (void) scf_instance_destroy(scf_inst); 676 scf_inst = NULL; 677 678 (void) scf_handle_unbind(rep_handle); 679 } 680 if (retries > REP_OP_RETRIES) 681 goto inst_failure; 682 683 if ((tmpstr = restarter_get_method_context( 684 RESTARTER_METHOD_CONTEXT_VERSION, scf_inst, NULL, method, path, 685 &ret)) != NULL) { 686 ret = NULL; 687 *errstr = tmpstr; 688 } 689 690 scf_instance_destroy(scf_inst); 691 return (ret); 692 693 inst_failure: 694 /* 695 * We can rely on this string not becoming invalid 696 * since we don't call bind_textdomain_codeset() or 697 * setlocale(3C) after initialization. 698 */ 699 *errstr = gettext("failed to get instance from repository"); 700 return (NULL); 701 } 702 703 /* 704 * Reads the value of the enabled property from the named property group 705 * of the given instance. 706 * If an error occurs, the SCF error code is returned. The possible errors are: 707 * - SCF_ERROR_INVALID_ARGUMENT: The enabled property is not a boolean. 708 * - SCF_ERROR_NONE: No value exists for the enabled property. 709 * - SCF_ERROR_CONNECTION_BROKEN: Repository connection broken. 710 * - SCF_ERROR_NOT_FOUND: The property wasn't found. 711 * - SCF_ERROR_NO_MEMORY: allocation failure. 712 * Else 0 is returned and 'enabled' set appropriately. 713 */ 714 static scf_error_t 715 read_enable_prop(const char *fmri, boolean_t *enabled, const char *pg) 716 { 717 scf_simple_prop_t *sp; 718 uint8_t *u8p; 719 720 if ((sp = scf_simple_prop_get(rep_handle, fmri, pg, 721 SCF_PROPERTY_ENABLED)) == NULL) 722 return (scf_error()); 723 724 if ((u8p = scf_simple_prop_next_boolean(sp)) == NULL) { 725 scf_simple_prop_free(sp); 726 return (scf_error()); 727 } 728 729 *enabled = (*u8p != 0); 730 scf_simple_prop_free(sp); 731 return (0); 732 } 733 734 /* 735 * Reads the enabled value for the given instance FMRI. The read value 736 * is based on a merge of the 'standard' enabled property, and the temporary 737 * override one; the merge involves using the latter properties value if 738 * present, else resporting to the formers. If an error occurs -1 is returned, 739 * else 0 is returned and 'enabled' set approriately. 740 */ 741 int 742 read_enable_merged(const char *fmri, boolean_t *enabled) 743 { 744 uint_t retries; 745 746 debug_msg("Entering read_enabled_prop: inst: %s", fmri); 747 748 for (retries = 0; retries <= REP_OP_RETRIES; retries++) { 749 if (make_handle_bound(rep_handle) == -1) 750 goto gen_fail; 751 752 switch (read_enable_prop(fmri, enabled, SCF_PG_GENERAL_OVR)) { 753 case 0: 754 debug_msg("read %d from override", *enabled); 755 return (0); 756 case SCF_ERROR_CONNECTION_BROKEN: 757 break; 758 case SCF_ERROR_NOT_FOUND: 759 case SCF_ERROR_NONE: 760 case SCF_ERROR_INVALID_ARGUMENT: 761 switch (read_enable_prop(fmri, enabled, 762 SCF_PG_GENERAL)) { 763 case 0: 764 debug_msg("read %d from non_override", 765 *enabled); 766 return (0); 767 case SCF_ERROR_CONNECTION_BROKEN: 768 break; 769 case SCF_ERROR_NOT_FOUND: 770 case SCF_ERROR_NONE: 771 case SCF_ERROR_INVALID_ARGUMENT: 772 error_msg(gettext("Missing %s property/value " 773 "for instance %s"), SCF_PROPERTY_ENABLED, 774 fmri); 775 return (-1); 776 default: 777 goto gen_fail; 778 } 779 break; 780 default: 781 goto gen_fail; 782 } 783 784 (void) scf_handle_unbind(rep_handle); 785 continue; 786 } 787 788 gen_fail: 789 error_msg(gettext("Failed to read the %s property of instance %s: %s"), 790 SCF_PROPERTY_ENABLED, fmri, scf_strerror(scf_error())); 791 return (-1); 792 } 793