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 * 24 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 #pragma ident "%Z%%M% %I% %E% SMI" 29 30 /* 31 * This file contains routines to manipulate lists of repository values that 32 * are used to store process ids and the internal state. There are routines 33 * to read/write the lists from/to the repository and routines to modify or 34 * inspect the lists. It also contains routines that deal with the 35 * repository side of contract ids. 36 */ 37 38 #include <errno.h> 39 #include <stdlib.h> 40 #include <libintl.h> 41 #include <unistd.h> 42 #include <string.h> 43 #include <signal.h> 44 #include "inetd_impl.h" 45 46 47 /* 48 * Number of consecutive repository bind retries performed by bind_to_rep() 49 * before failing. 50 */ 51 #define BIND_TO_REP_RETRIES 10 52 53 /* Name of property group where inetd's state for a service is stored. */ 54 #define PG_NAME_INSTANCE_STATE (const char *) "inetd_state" 55 56 /* uu_list repval list pool */ 57 static uu_list_pool_t *rep_val_pool = NULL; 58 59 /* 60 * Repository object pointers that get set-up in repval_init() and closed down 61 * in repval_fini(). They're used in _retrieve_rep_vals(), _store_rep_vals(), 62 * add_remove_contract_norebind(), and adopt_repository_contracts(). They're 63 * global so they can be initialized once on inetd startup, and re-used 64 * there-after in the referenced functions. 65 */ 66 static scf_handle_t *rep_handle = NULL; 67 static scf_propertygroup_t *pg = NULL; 68 static scf_instance_t *inst = NULL; 69 static scf_transaction_t *trans = NULL; 70 static scf_transaction_entry_t *entry = NULL; 71 static scf_property_t *prop = NULL; 72 73 /* 74 * Try and make the given handle bind be bound to the repository. If 75 * it's already bound, or we succeed a new bind return 0; else return 76 * -1 on failure, with the SCF error set to one of the following: 77 * SCF_ERROR_NO_SERVER 78 * SCF_ERROR_NO_RESOURCES 79 */ 80 int 81 make_handle_bound(scf_handle_t *hdl) 82 { 83 uint_t retries; 84 85 for (retries = 0; retries <= BIND_TO_REP_RETRIES; retries++) { 86 if ((scf_handle_bind(hdl) == 0) || 87 (scf_error() == SCF_ERROR_IN_USE)) 88 return (0); 89 90 assert(scf_error() != SCF_ERROR_INVALID_ARGUMENT); 91 } 92 93 return (-1); 94 } 95 96 int 97 repval_init(void) 98 { 99 debug_msg("Entering repval_init"); 100 101 /* 102 * Create the repval list pool. 103 */ 104 rep_val_pool = uu_list_pool_create("rep_val_pool", sizeof (rep_val_t), 105 offsetof(rep_val_t, link), NULL, UU_LIST_POOL_DEBUG); 106 if (rep_val_pool == NULL) { 107 error_msg("%s: %s", gettext("Failed to create rep_val pool"), 108 uu_strerror(uu_error())); 109 return (-1); 110 } 111 112 /* 113 * Create and bind a repository handle, and create all repository 114 * objects that we'll use later that are associated with it. On any 115 * errors we simply return -1 and let repval_fini() clean-up after 116 * us. 117 */ 118 if ((rep_handle = scf_handle_create(SCF_VERSION)) == NULL) { 119 error_msg("%s: %s", 120 gettext("Failed to create repository handle"), 121 scf_strerror(scf_error())); 122 goto cleanup; 123 } else if (make_handle_bound(rep_handle) == -1) { 124 goto cleanup; 125 } else if (((pg = scf_pg_create(rep_handle)) == NULL) || 126 ((inst = scf_instance_create(rep_handle)) == NULL) || 127 ((trans = scf_transaction_create(rep_handle)) == NULL) || 128 ((entry = scf_entry_create(rep_handle)) == NULL) || 129 ((prop = scf_property_create(rep_handle)) == NULL)) { 130 error_msg("%s: %s", 131 gettext("Failed to create repository object"), 132 scf_strerror(scf_error())); 133 goto cleanup; 134 } 135 136 return (0); 137 cleanup: 138 repval_fini(); 139 return (-1); 140 } 141 142 void 143 repval_fini(void) 144 { 145 debug_msg("Entering repval_fini"); 146 147 if (rep_handle != NULL) { 148 /* 149 * We unbind from the repository before we free the repository 150 * objects for efficiency reasons. 151 */ 152 (void) scf_handle_unbind(rep_handle); 153 154 scf_pg_destroy(pg); 155 pg = NULL; 156 scf_instance_destroy(inst); 157 inst = NULL; 158 scf_transaction_destroy(trans); 159 trans = NULL; 160 scf_entry_destroy(entry); 161 entry = NULL; 162 scf_property_destroy(prop); 163 prop = NULL; 164 165 scf_handle_destroy(rep_handle); 166 rep_handle = NULL; 167 } 168 169 if (rep_val_pool != NULL) { 170 uu_list_pool_destroy(rep_val_pool); 171 rep_val_pool = NULL; 172 } 173 } 174 175 uu_list_t * 176 create_rep_val_list(void) 177 { 178 uu_list_t *ret; 179 180 debug_msg("Entering create_rep_val_list"); 181 182 if ((ret = uu_list_create(rep_val_pool, NULL, 0)) == NULL) 183 assert(uu_error() == UU_ERROR_NO_MEMORY); 184 185 return (ret); 186 } 187 188 void 189 destroy_rep_val_list(uu_list_t *list) 190 { 191 debug_msg("Entering destroy_rep_val_list"); 192 193 if (list != NULL) { 194 empty_rep_val_list(list); 195 uu_list_destroy(list); 196 } 197 } 198 199 rep_val_t * 200 find_rep_val(uu_list_t *list, int64_t val) 201 { 202 rep_val_t *rv; 203 204 debug_msg("Entering find_rep_val: val: %lld", val); 205 206 for (rv = uu_list_first(list); rv != NULL; 207 rv = uu_list_next(list, rv)) { 208 if (rv->val == val) 209 break; 210 } 211 return (rv); 212 } 213 214 int 215 add_rep_val(uu_list_t *list, int64_t val) 216 { 217 rep_val_t *rv; 218 219 debug_msg("Entering add_rep_val: val: %lld", val); 220 221 if ((rv = malloc(sizeof (rep_val_t))) == NULL) 222 return (-1); 223 224 uu_list_node_init(rv, &rv->link, rep_val_pool); 225 rv->val = val; 226 rv->scf_val = NULL; 227 (void) uu_list_insert_after(list, NULL, rv); 228 229 return (0); 230 } 231 232 void 233 remove_rep_val(uu_list_t *list, int64_t val) 234 { 235 rep_val_t *rv; 236 237 debug_msg("Entering remove_rep_val: val: %lld", val); 238 239 if ((rv = find_rep_val(list, val)) != NULL) { 240 uu_list_remove(list, rv); 241 assert(rv->scf_val == NULL); 242 free(rv); 243 } 244 } 245 246 void 247 empty_rep_val_list(uu_list_t *list) 248 { 249 void *cookie = NULL; 250 rep_val_t *rv; 251 252 debug_msg("Entering empty_rep_val_list"); 253 254 while ((rv = uu_list_teardown(list, &cookie)) != NULL) { 255 if (rv->scf_val != NULL) 256 scf_value_destroy(rv->scf_val); 257 free(rv); 258 } 259 } 260 261 int64_t 262 get_single_rep_val(uu_list_t *list) 263 { 264 rep_val_t *rv = uu_list_first(list); 265 266 debug_msg("Entering get_single_rep_val"); 267 268 assert(rv != NULL); 269 return (rv->val); 270 } 271 272 int 273 set_single_rep_val(uu_list_t *list, int64_t val) 274 { 275 rep_val_t *rv = uu_list_first(list); 276 277 debug_msg("Entering set_single_rep_val"); 278 279 if (rv == NULL) { 280 if (add_rep_val(list, val) == -1) 281 return (-1); 282 } else { 283 rv->val = val; 284 } 285 286 return (0); 287 } 288 289 /* 290 * Partner to add_tr_entry_values. This function frees the scf_values created 291 * in add_tr_entry_values() in the list 'vals'. 292 */ 293 static void 294 remove_tr_entry_values(uu_list_t *vals) 295 { 296 rep_val_t *rval; 297 298 debug_msg("Entering remove_tr_entry_values"); 299 300 for (rval = uu_list_first(vals); rval != NULL; 301 rval = uu_list_next(vals, rval)) { 302 if (rval->scf_val != NULL) { 303 scf_value_destroy(rval->scf_val); 304 rval->scf_val = NULL; 305 } 306 } 307 } 308 309 /* 310 * This function creates and associates with transaction entry 'entry' an 311 * scf value for each value in 'vals'. The pointers to the scf values 312 * are stored in the list for later cleanup by remove_tr_entry_values. 313 * Returns 0 on success, else -1 on error with scf_error() set to: 314 * SCF_ERROR_NO_MEMORY if memory allocation failed. 315 * SCF_ERROR_CONNECTION_BROKEN if the connection to the repository was broken. 316 */ 317 static int 318 add_tr_entry_values(scf_handle_t *hdl, scf_transaction_entry_t *entry, 319 uu_list_t *vals) 320 { 321 rep_val_t *rval; 322 323 debug_msg("Entering add_tr_entry_values"); 324 325 for (rval = uu_list_first(vals); rval != NULL; 326 rval = uu_list_next(vals, rval)) { 327 328 assert(rval->scf_val == NULL); 329 if ((rval->scf_val = scf_value_create(hdl)) == NULL) { 330 remove_tr_entry_values(vals); 331 return (-1); 332 } 333 334 scf_value_set_integer(rval->scf_val, rval->val); 335 336 if (scf_entry_add_value(entry, rval->scf_val) < 0) { 337 remove_tr_entry_values(vals); 338 return (-1); 339 } 340 } 341 342 return (0); 343 } 344 345 /* 346 * Stores the values contained in the list 'vals' into the property 'prop_name' 347 * of the instance with fmri 'inst_fmri', within the instance's instance 348 * state property group. 349 * 350 * Returns 0 on success, else one of the following on failure: 351 * SCF_ERROR_NO_MEMORY if memory allocation failed. 352 * SCF_ERROR_NO_RESOURCES if the server doesn't have required resources. 353 * SCF_ERROR_VERSION_MISMATCH if program compiled against a newer libscf 354 * than on system. 355 * SCF_ERROR_PERMISSION_DENIED if insufficient privileges to modify pg. 356 * SCF_ERROR_BACKEND_ACCESS if the repository back-end refused the pg modify. 357 * SCF_ERROR_CONNECTION_BROKEN if the connection to the repository was broken. 358 */ 359 static scf_error_t 360 _store_rep_vals(uu_list_t *vals, const char *inst_fmri, const char *prop_name) 361 { 362 int cret; 363 int ret; 364 365 debug_msg("Entering _store_rep_vals: fmri: %s, prop: %s", inst_fmri, 366 prop_name); 367 368 if (scf_handle_decode_fmri(rep_handle, inst_fmri, NULL, NULL, inst, 369 NULL, NULL, SCF_DECODE_FMRI_EXACT) == -1) 370 return (scf_error()); 371 372 /* 373 * Fetch the instance state pg, and if it doesn't exist try and 374 * create it. 375 */ 376 if (scf_instance_get_pg(inst, PG_NAME_INSTANCE_STATE, pg) < 0) { 377 if (scf_error() != SCF_ERROR_NOT_FOUND) 378 return (scf_error()); 379 if (scf_instance_add_pg(inst, PG_NAME_INSTANCE_STATE, 380 SCF_GROUP_FRAMEWORK, SCF_PG_FLAG_NONPERSISTENT, pg) < 0) 381 return (scf_error()); 382 } 383 384 /* 385 * Perform a transaction to write the values to the requested property. 386 * If someone got there before us, loop and retry. 387 */ 388 do { 389 if (scf_transaction_start(trans, pg) < 0) 390 return (scf_error()); 391 392 if ((scf_transaction_property_new(trans, entry, 393 prop_name, SCF_TYPE_INTEGER) < 0) && 394 (scf_transaction_property_change_type(trans, entry, 395 prop_name, SCF_TYPE_INTEGER) < 0)) { 396 ret = scf_error(); 397 goto cleanup; 398 } 399 400 if (add_tr_entry_values(rep_handle, entry, vals) < 0) { 401 ret = scf_error(); 402 goto cleanup; 403 } 404 405 if ((cret = scf_transaction_commit(trans)) < 0) { 406 ret = scf_error(); 407 goto cleanup; 408 } else if (cret == 0) { 409 scf_transaction_reset(trans); 410 scf_entry_reset(entry); 411 remove_tr_entry_values(vals); 412 if (scf_pg_update(pg) < 0) { 413 ret = scf_error(); 414 goto cleanup; 415 } 416 } 417 } while (cret == 0); 418 419 ret = 0; 420 cleanup: 421 scf_transaction_reset(trans); 422 scf_entry_reset(entry); 423 remove_tr_entry_values(vals); 424 return (ret); 425 } 426 427 /* 428 * Retrieves the repository values of property 'prop_name', of the instance 429 * with fmri 'fmri', from within the instance's instance state property 430 * group and adds them to the value list 'list'. 431 * 432 * Returns 0 on success, else one of the following values on error: 433 * SCF_ERROR_NOT_FOUND if the property doesn't exist. 434 * SCF_ERROR_NO_MEMORY if memory allocation failed. 435 * SCF_ERROR_CONNECTION_BROKEN if the connection to the repository was broken. 436 * SCF_ERROR_TYPE_MISMATCH if the property was of an unexpected type. 437 * 438 */ 439 static scf_error_t 440 _retrieve_rep_vals(uu_list_t *list, const char *fmri, const char *prop_name) 441 { 442 scf_simple_prop_t *sp; 443 int64_t *ip; 444 445 debug_msg("Entering _retrieve_rep_vals: fmri: %s, prop: %s", fmri, 446 prop_name); 447 448 if ((sp = scf_simple_prop_get(rep_handle, fmri, PG_NAME_INSTANCE_STATE, 449 prop_name)) == NULL) 450 return (scf_error()); 451 452 while ((ip = scf_simple_prop_next_integer(sp)) != NULL) { 453 if (add_rep_val(list, *ip) == -1) { 454 empty_rep_val_list(list); 455 scf_simple_prop_free(sp); 456 return (SCF_ERROR_NO_MEMORY); 457 } 458 } 459 if (scf_error() != SCF_ERROR_NONE) { 460 assert(scf_error() == SCF_ERROR_TYPE_MISMATCH); 461 empty_rep_val_list(list); 462 scf_simple_prop_free(sp); 463 return (scf_error()); 464 } 465 466 scf_simple_prop_free(sp); 467 return (0); 468 } 469 470 /* 471 * A routine that loops trying to read/write repository values until 472 * either success, an error other that a broken repository connection or 473 * the number of retries reaches REP_OP_RETRIES. 474 * Returns 0 on success, else the error value from either _store_rep_vals or 475 * retrieve_rep_vals (based on whether 'store' was set or not), or one of the 476 * following if a rebind failed: 477 * SCF_ERROR_NO_RESOURCES if the server doesn't have adequate resources. 478 * SCF_ERROR_NO_SERVER if the server isn't running. 479 */ 480 static scf_error_t 481 store_retrieve_rep_vals(uu_list_t *vals, const char *fmri, 482 const char *prop, boolean_t store) 483 { 484 scf_error_t ret; 485 uint_t retries; 486 487 debug_msg("Entering store_retrieve_rep_vals, store: %d", store); 488 489 490 for (retries = 0; retries <= REP_OP_RETRIES; retries++) { 491 if (make_handle_bound(rep_handle) == -1) { 492 ret = scf_error(); 493 break; 494 } 495 496 if ((ret = (store ? _store_rep_vals(vals, fmri, prop) : 497 _retrieve_rep_vals(vals, fmri, prop))) != 498 SCF_ERROR_CONNECTION_BROKEN) 499 break; 500 501 (void) scf_handle_unbind(rep_handle); 502 } 503 504 return (ret); 505 } 506 507 scf_error_t 508 store_rep_vals(uu_list_t *vals, const char *fmri, const char *prop) 509 { 510 return (store_retrieve_rep_vals(vals, fmri, prop, B_TRUE)); 511 } 512 513 scf_error_t 514 retrieve_rep_vals(uu_list_t *vals, const char *fmri, const char *prop) 515 { 516 return (store_retrieve_rep_vals(vals, fmri, prop, B_FALSE)); 517 } 518 519 /* 520 * Fails with ECONNABORTED, ENOENT, EACCES, EROFS, ENOMEM, or EPERM. 521 */ 522 static int 523 add_remove_contract_norebind(const char *fmri, boolean_t add, ctid_t ctid) 524 { 525 int err; 526 527 if (scf_handle_decode_fmri(rep_handle, fmri, NULL, NULL, inst, NULL, 528 NULL, SCF_DECODE_FMRI_EXACT) != 0) { 529 switch (scf_error()) { 530 case SCF_ERROR_CONNECTION_BROKEN: 531 return (ECONNABORTED); 532 533 case SCF_ERROR_NOT_FOUND: 534 return (ENOENT); 535 536 case SCF_ERROR_CONSTRAINT_VIOLATED: 537 case SCF_ERROR_INVALID_ARGUMENT: 538 case SCF_ERROR_HANDLE_MISMATCH: 539 default: 540 assert(0); 541 abort(); 542 } 543 } 544 545 redo: 546 if (add) 547 err = restarter_store_contract(inst, ctid, 548 RESTARTER_CONTRACT_PRIMARY); 549 else 550 err = restarter_remove_contract(inst, ctid, 551 RESTARTER_CONTRACT_PRIMARY); 552 switch (err) { 553 case 0: 554 case ENOMEM: 555 case ECONNABORTED: 556 return (err); 557 558 case ECANCELED: 559 return (ENOENT); 560 561 case EPERM: 562 assert(0); 563 return (err); 564 565 case EACCES: 566 error_msg(add ? gettext("Failed to write contract id %ld for " 567 "instance %s to repository: backend access denied.") : 568 gettext("Failed to remove contract id %ld for instance %s " 569 "from repository: backend access denied."), ctid, fmri); 570 return (err); 571 572 case EROFS: 573 error_msg(add ? gettext("Failed to write contract id %ld for " 574 "instance %s to repository: backend is read-only.") : 575 gettext("Failed to remove contract id %ld for instance %s " 576 "from repository: backend is read-only."), ctid, fmri); 577 return (err); 578 579 case EINVAL: 580 case EBADF: 581 default: 582 assert(0); 583 abort(); 584 /* NOTREACHED */ 585 } 586 } 587 588 /* 589 * Tries to add/remove (dependent on the value of 'add') the specified 590 * contract id to the specified instance until either success, an error 591 * other that connection broken occurs, or the number of bind retries reaches 592 * REP_OP_RETRIES. 593 * Returns 0 on success else fails with one of ENOENT, EACCES, EROFS, EPERM, 594 * ECONNABORTED or ENOMEM. 595 */ 596 int 597 add_remove_contract(const char *fmri, boolean_t add, ctid_t ctid) 598 { 599 uint_t retries; 600 int err; 601 602 for (retries = 0; retries <= REP_OP_RETRIES; retries++) { 603 if (make_handle_bound(rep_handle) == -1) { 604 err = ECONNABORTED; 605 break; 606 } 607 608 if ((err = add_remove_contract_norebind(fmri, add, ctid)) != 609 ECONNABORTED) 610 break; 611 612 (void) scf_handle_unbind(rep_handle); 613 } 614 615 return (err); 616 } 617 618 /* 619 * Iterate over all contracts associated with the instance specified by 620 * fmri; if sig !=0, we send each contract the specified signal, otherwise 621 * we call adopt_contract() to take ownership. This really ought to be 622 * reworked to use a callback mechanism if more functionality is added. 623 * 624 * Returns 0 on success or ENOENT if the instance, its restarter property 625 * group, or its contract property don't exist, or EINVAL if the property 626 * is not of the correct type, ENOMEM if there was a memory allocation 627 * failure, EPERM if there were permission problems accessing the repository, 628 * or ECONNABORTED if the connection with the repository was broken. 629 */ 630 int 631 iterate_repository_contracts(const char *fmri, int sig) 632 { 633 scf_iter_t *iter; 634 scf_value_t *val = NULL; 635 uint64_t c; 636 int err; 637 int ret = 0; 638 uint_t retries = 0; 639 640 debug_msg("Entering iterate_repository_contracts"); 641 642 if (make_handle_bound(rep_handle) == -1) 643 return (ECONNABORTED); 644 645 if (((iter = scf_iter_create(rep_handle)) == NULL) || 646 ((val = scf_value_create(rep_handle)) == NULL)) { 647 ret = ENOMEM; 648 goto out; 649 } 650 651 rep_retry: 652 if (scf_handle_decode_fmri(rep_handle, fmri, NULL, NULL, inst, NULL, 653 NULL, SCF_DECODE_FMRI_EXACT) != 0) { 654 switch (scf_error()) { 655 case SCF_ERROR_CONNECTION_BROKEN: 656 rebind: 657 (void) scf_handle_unbind(rep_handle); 658 659 if (retries++ == REP_OP_RETRIES) { 660 ret = ECONNABORTED; 661 goto out; 662 } 663 664 if (make_handle_bound(rep_handle) == -1) { 665 ret = ECONNABORTED; 666 goto out; 667 } 668 669 goto rep_retry; 670 671 case SCF_ERROR_NOT_FOUND: 672 ret = ENOENT; 673 goto out; 674 675 case SCF_ERROR_CONSTRAINT_VIOLATED: 676 case SCF_ERROR_INVALID_ARGUMENT: 677 case SCF_ERROR_HANDLE_MISMATCH: 678 default: 679 assert(0); 680 abort(); 681 } 682 } 683 684 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != 0) { 685 switch (scf_error()) { 686 case SCF_ERROR_CONNECTION_BROKEN: 687 goto rebind; 688 689 case SCF_ERROR_NOT_SET: 690 ret = 0; 691 goto out; 692 693 case SCF_ERROR_NOT_FOUND: 694 ret = ENOENT; 695 goto out; 696 697 case SCF_ERROR_INVALID_ARGUMENT: 698 case SCF_ERROR_HANDLE_MISMATCH: 699 default: 700 assert(0); 701 abort(); 702 } 703 } 704 705 if (scf_pg_get_property(pg, SCF_PROPERTY_CONTRACT, prop) != 0) { 706 switch (scf_error()) { 707 case SCF_ERROR_CONNECTION_BROKEN: 708 goto rebind; 709 710 case SCF_ERROR_NOT_SET: 711 ret = 0; 712 goto out; 713 714 case SCF_ERROR_NOT_FOUND: 715 ret = ENOENT; 716 goto out; 717 718 case SCF_ERROR_INVALID_ARGUMENT: 719 case SCF_ERROR_HANDLE_MISMATCH: 720 default: 721 assert(0); 722 abort(); 723 } 724 } 725 726 if (scf_property_is_type(prop, SCF_TYPE_COUNT) != 0) { 727 switch (scf_error()) { 728 case SCF_ERROR_CONNECTION_BROKEN: 729 goto rebind; 730 731 case SCF_ERROR_NOT_SET: 732 ret = ENOENT; 733 goto out; 734 735 case SCF_ERROR_TYPE_MISMATCH: 736 ret = EINVAL; 737 goto out; 738 739 default: 740 assert(0); 741 abort(); 742 } 743 } 744 745 if (scf_iter_property_values(iter, prop) != 0) { 746 switch (scf_error()) { 747 case SCF_ERROR_CONNECTION_BROKEN: 748 goto rebind; 749 750 case SCF_ERROR_NOT_SET: 751 ret = ENOENT; 752 goto out; 753 754 case SCF_ERROR_HANDLE_MISMATCH: 755 default: 756 assert(0); 757 abort(); 758 } 759 } 760 761 for (;;) { 762 err = scf_iter_next_value(iter, val); 763 if (err == 0) { 764 break; 765 } else if (err != 1) { 766 assert(scf_error() == SCF_ERROR_CONNECTION_BROKEN); 767 goto rebind; 768 } 769 770 err = scf_value_get_count(val, &c); 771 assert(err == 0); 772 773 if (sig == 0) { 774 /* Try to adopt the contract */ 775 if (adopt_contract((ctid_t)c, fmri) != 0) { 776 /* 777 * Adoption failed. No reason to think it'll 778 * work later, so remove the id from our list 779 * in the repository. 780 * 781 * Beware: add_remove_contract_norebind() uses 782 * the global scf_ handles. Fortunately we're 783 * done with them. We need to be cognizant of 784 * repository disconnection, though. 785 */ 786 switch (add_remove_contract_norebind(fmri, 787 B_FALSE, (ctid_t)c)) { 788 case 0: 789 case ENOENT: 790 case EACCES: 791 case EROFS: 792 break; 793 794 case ECONNABORTED: 795 goto rebind; 796 797 default: 798 assert(0); 799 abort(); 800 } 801 } 802 } else { 803 /* 804 * Send a signal to all in the contract; ESRCH just 805 * means they all exited before we could kill them 806 */ 807 if (sigsend(P_CTID, (ctid_t)c, sig) == -1 && 808 errno != ESRCH) { 809 warn_msg(gettext("Unable to signal all contract" 810 "members of instance %s: %s"), fmri, 811 strerror(errno)); 812 } 813 } 814 } 815 816 out: 817 scf_value_destroy(val); 818 scf_iter_destroy(iter); 819 return (ret); 820 } 821