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