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