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