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 * 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * This file contains routines to manipulate lists of repository values that 29 * are used to store process ids and the internal state. There are routines 30 * to read/write the lists from/to the repository and routines to modify or 31 * inspect the lists. It also contains routines that deal with the 32 * repository side of contract ids. 33 */ 34 35 #include <errno.h> 36 #include <stdlib.h> 37 #include <libintl.h> 38 #include <unistd.h> 39 #include <string.h> 40 #include <signal.h> 41 #include <sys/param.h> 42 #include <sys/types.h> 43 #include <sys/stat.h> 44 #include <libscf_priv.h> 45 #include "inetd_impl.h" 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 * Pathname storage for paths generated from the fmri. 75 * Used when updating the ctid and (start) pid files for an inetd service. 76 */ 77 static char genfmri_filename[MAXPATHLEN] = ""; 78 static char genfmri_temp_filename[MAXPATHLEN] = ""; 79 80 /* 81 * Try and make the given handle bind be bound to the repository. If 82 * it's already bound, or we succeed a new bind return 0; else return 83 * -1 on failure, with the SCF error set to one of the following: 84 * SCF_ERROR_NO_SERVER 85 * SCF_ERROR_NO_RESOURCES 86 */ 87 int 88 make_handle_bound(scf_handle_t *hdl) 89 { 90 uint_t retries; 91 92 for (retries = 0; retries <= BIND_TO_REP_RETRIES; retries++) { 93 if ((scf_handle_bind(hdl) == 0) || 94 (scf_error() == SCF_ERROR_IN_USE)) 95 return (0); 96 97 assert(scf_error() != SCF_ERROR_INVALID_ARGUMENT); 98 } 99 100 return (-1); 101 } 102 103 int 104 repval_init(void) 105 { 106 /* 107 * Create the repval list pool. 108 */ 109 rep_val_pool = uu_list_pool_create("rep_val_pool", sizeof (rep_val_t), 110 offsetof(rep_val_t, link), NULL, UU_LIST_POOL_DEBUG); 111 if (rep_val_pool == NULL) { 112 error_msg("%s: %s", gettext("Failed to create rep_val pool"), 113 uu_strerror(uu_error())); 114 return (-1); 115 } 116 117 /* 118 * Create and bind a repository handle, and create all repository 119 * objects that we'll use later that are associated with it. On any 120 * errors we simply return -1 and let repval_fini() clean-up after 121 * us. 122 */ 123 if ((rep_handle = scf_handle_create(SCF_VERSION)) == NULL) { 124 error_msg("%s: %s", 125 gettext("Failed to create repository handle"), 126 scf_strerror(scf_error())); 127 goto cleanup; 128 } else if (make_handle_bound(rep_handle) == -1) { 129 goto cleanup; 130 } else if (((pg = scf_pg_create(rep_handle)) == NULL) || 131 ((inst = scf_instance_create(rep_handle)) == NULL) || 132 ((trans = scf_transaction_create(rep_handle)) == NULL) || 133 ((entry = scf_entry_create(rep_handle)) == NULL) || 134 ((prop = scf_property_create(rep_handle)) == NULL)) { 135 error_msg("%s: %s", 136 gettext("Failed to create repository object"), 137 scf_strerror(scf_error())); 138 goto cleanup; 139 } 140 141 return (0); 142 cleanup: 143 repval_fini(); 144 return (-1); 145 } 146 147 void 148 repval_fini(void) 149 { 150 if (rep_handle != NULL) { 151 /* 152 * We unbind from the repository before we free the repository 153 * objects for efficiency reasons. 154 */ 155 (void) scf_handle_unbind(rep_handle); 156 157 scf_pg_destroy(pg); 158 pg = NULL; 159 scf_instance_destroy(inst); 160 inst = NULL; 161 scf_transaction_destroy(trans); 162 trans = NULL; 163 scf_entry_destroy(entry); 164 entry = NULL; 165 scf_property_destroy(prop); 166 prop = NULL; 167 168 scf_handle_destroy(rep_handle); 169 rep_handle = NULL; 170 } 171 172 if (rep_val_pool != NULL) { 173 uu_list_pool_destroy(rep_val_pool); 174 rep_val_pool = NULL; 175 } 176 } 177 178 uu_list_t * 179 create_rep_val_list(void) 180 { 181 uu_list_t *ret; 182 183 if ((ret = uu_list_create(rep_val_pool, NULL, 0)) == NULL) 184 assert(uu_error() == UU_ERROR_NO_MEMORY); 185 186 return (ret); 187 } 188 189 void 190 destroy_rep_val_list(uu_list_t *list) 191 { 192 if (list != NULL) { 193 empty_rep_val_list(list); 194 uu_list_destroy(list); 195 } 196 } 197 198 rep_val_t * 199 find_rep_val(uu_list_t *list, int64_t val) 200 { 201 rep_val_t *rv; 202 203 for (rv = uu_list_first(list); rv != NULL; 204 rv = uu_list_next(list, rv)) { 205 if (rv->val == val) 206 break; 207 } 208 return (rv); 209 } 210 211 int 212 add_rep_val(uu_list_t *list, int64_t val) 213 { 214 rep_val_t *rv; 215 216 if ((rv = malloc(sizeof (rep_val_t))) == NULL) 217 return (-1); 218 219 uu_list_node_init(rv, &rv->link, rep_val_pool); 220 rv->val = val; 221 rv->scf_val = NULL; 222 (void) uu_list_insert_after(list, NULL, rv); 223 224 return (0); 225 } 226 227 void 228 remove_rep_val(uu_list_t *list, int64_t val) 229 { 230 rep_val_t *rv; 231 232 if ((rv = find_rep_val(list, val)) != NULL) { 233 uu_list_remove(list, rv); 234 assert(rv->scf_val == NULL); 235 free(rv); 236 } 237 } 238 239 void 240 empty_rep_val_list(uu_list_t *list) 241 { 242 void *cookie = NULL; 243 rep_val_t *rv; 244 245 while ((rv = uu_list_teardown(list, &cookie)) != NULL) { 246 if (rv->scf_val != NULL) 247 scf_value_destroy(rv->scf_val); 248 free(rv); 249 } 250 } 251 252 int64_t 253 get_single_rep_val(uu_list_t *list) 254 { 255 rep_val_t *rv = uu_list_first(list); 256 257 assert(rv != NULL); 258 return (rv->val); 259 } 260 261 int 262 set_single_rep_val(uu_list_t *list, int64_t val) 263 { 264 rep_val_t *rv = uu_list_first(list); 265 266 if (rv == NULL) { 267 if (add_rep_val(list, val) == -1) 268 return (-1); 269 } else { 270 rv->val = val; 271 } 272 273 return (0); 274 } 275 276 /* 277 * Partner to add_tr_entry_values. This function frees the scf_values created 278 * in add_tr_entry_values() in the list 'vals'. 279 */ 280 static void 281 remove_tr_entry_values(uu_list_t *vals) 282 { 283 rep_val_t *rval; 284 285 for (rval = uu_list_first(vals); rval != NULL; 286 rval = uu_list_next(vals, rval)) { 287 if (rval->scf_val != NULL) { 288 scf_value_destroy(rval->scf_val); 289 rval->scf_val = NULL; 290 } 291 } 292 } 293 294 /* 295 * This function creates and associates with transaction entry 'entry' an 296 * scf value for each value in 'vals'. The pointers to the scf values 297 * are stored in the list for later cleanup by remove_tr_entry_values. 298 * Returns 0 on success, else -1 on error with scf_error() set to: 299 * SCF_ERROR_NO_MEMORY if memory allocation failed. 300 * SCF_ERROR_CONNECTION_BROKEN if the connection to the repository was broken. 301 */ 302 static int 303 add_tr_entry_values(scf_handle_t *hdl, scf_transaction_entry_t *entry, 304 uu_list_t *vals) 305 { 306 rep_val_t *rval; 307 308 for (rval = uu_list_first(vals); rval != NULL; 309 rval = uu_list_next(vals, rval)) { 310 311 assert(rval->scf_val == NULL); 312 if ((rval->scf_val = scf_value_create(hdl)) == NULL) { 313 remove_tr_entry_values(vals); 314 return (-1); 315 } 316 317 scf_value_set_integer(rval->scf_val, rval->val); 318 319 if (scf_entry_add_value(entry, rval->scf_val) < 0) { 320 remove_tr_entry_values(vals); 321 return (-1); 322 } 323 } 324 325 return (0); 326 } 327 328 /* 329 * Stores the values contained in the list 'vals' into the property 'prop_name' 330 * of the instance with fmri 'inst_fmri', within the instance's instance 331 * state property group. 332 * 333 * Returns 0 on success, else one of the following on failure: 334 * SCF_ERROR_NO_MEMORY if memory allocation failed. 335 * SCF_ERROR_NO_RESOURCES if the server doesn't have required resources. 336 * SCF_ERROR_VERSION_MISMATCH if program compiled against a newer libscf 337 * than on system. 338 * SCF_ERROR_PERMISSION_DENIED if insufficient privileges to modify pg. 339 * SCF_ERROR_BACKEND_ACCESS if the repository back-end refused the pg modify. 340 * SCF_ERROR_CONNECTION_BROKEN if the connection to the repository was broken. 341 */ 342 static scf_error_t 343 _store_rep_vals(uu_list_t *vals, const char *inst_fmri, const char *prop_name) 344 { 345 int cret; 346 int ret; 347 348 if (scf_handle_decode_fmri(rep_handle, inst_fmri, NULL, NULL, inst, 349 NULL, NULL, SCF_DECODE_FMRI_EXACT) == -1) 350 return (scf_error()); 351 352 /* 353 * Fetch the instance state pg, and if it doesn't exist try and 354 * create it. 355 */ 356 if (scf_instance_get_pg(inst, PG_NAME_INSTANCE_STATE, pg) < 0) { 357 if (scf_error() != SCF_ERROR_NOT_FOUND) 358 return (scf_error()); 359 if (scf_instance_add_pg(inst, PG_NAME_INSTANCE_STATE, 360 SCF_GROUP_FRAMEWORK, SCF_PG_FLAG_NONPERSISTENT, pg) < 0) 361 return (scf_error()); 362 } 363 364 /* 365 * Perform a transaction to write the values to the requested property. 366 * If someone got there before us, loop and retry. 367 */ 368 do { 369 if (scf_transaction_start(trans, pg) < 0) 370 return (scf_error()); 371 372 if ((scf_transaction_property_new(trans, entry, 373 prop_name, SCF_TYPE_INTEGER) < 0) && 374 (scf_transaction_property_change_type(trans, entry, 375 prop_name, SCF_TYPE_INTEGER) < 0)) { 376 ret = scf_error(); 377 goto cleanup; 378 } 379 380 if (add_tr_entry_values(rep_handle, entry, vals) < 0) { 381 ret = scf_error(); 382 goto cleanup; 383 } 384 385 if ((cret = scf_transaction_commit(trans)) < 0) { 386 ret = scf_error(); 387 goto cleanup; 388 } else if (cret == 0) { 389 scf_transaction_reset(trans); 390 scf_entry_reset(entry); 391 remove_tr_entry_values(vals); 392 if (scf_pg_update(pg) < 0) { 393 ret = scf_error(); 394 goto cleanup; 395 } 396 } 397 } while (cret == 0); 398 399 ret = 0; 400 cleanup: 401 scf_transaction_reset(trans); 402 scf_entry_reset(entry); 403 remove_tr_entry_values(vals); 404 return (ret); 405 } 406 407 /* 408 * Retrieves the repository values of property 'prop_name', of the instance 409 * with fmri 'fmri', from within the instance's instance state property 410 * group and adds them to the value list 'list'. 411 * 412 * Returns 0 on success, else one of the following values on error: 413 * SCF_ERROR_NOT_FOUND if the property doesn't exist. 414 * SCF_ERROR_NO_MEMORY if memory allocation failed. 415 * SCF_ERROR_CONNECTION_BROKEN if the connection to the repository was broken. 416 * SCF_ERROR_TYPE_MISMATCH if the property was of an unexpected type. 417 * 418 */ 419 static scf_error_t 420 _retrieve_rep_vals(uu_list_t *list, const char *fmri, const char *prop_name) 421 { 422 scf_simple_prop_t *sp; 423 int64_t *ip; 424 425 if ((sp = scf_simple_prop_get(rep_handle, fmri, PG_NAME_INSTANCE_STATE, 426 prop_name)) == NULL) 427 return (scf_error()); 428 429 while ((ip = scf_simple_prop_next_integer(sp)) != NULL) { 430 if (add_rep_val(list, *ip) == -1) { 431 empty_rep_val_list(list); 432 scf_simple_prop_free(sp); 433 return (SCF_ERROR_NO_MEMORY); 434 } 435 } 436 if (scf_error() != SCF_ERROR_NONE) { 437 assert(scf_error() == SCF_ERROR_TYPE_MISMATCH); 438 empty_rep_val_list(list); 439 scf_simple_prop_free(sp); 440 return (scf_error()); 441 } 442 443 scf_simple_prop_free(sp); 444 return (0); 445 } 446 447 /* 448 * Writes the repository values in the vals list to 449 * a file that is generated based on the passed in fmri and name. 450 * Returns 0 on success, 451 * ENAMETOOLONG if unable to generate filename from fmri (including 452 * the inability to create the directory for the generated filename) and 453 * ENOENT on all other failures. 454 */ 455 static int 456 repvals_to_file(const char *fmri, const char *name, uu_list_t *vals) 457 { 458 int tfd; 459 FILE *tfp; /* temp fp */ 460 rep_val_t *spval; /* Contains a start_pid or ctid */ 461 int ret = 0; 462 463 if (gen_filenms_from_fmri(fmri, name, genfmri_filename, 464 genfmri_temp_filename) != 0) { 465 /* Failure either from fmri too long or mkdir failure */ 466 return (ENAMETOOLONG); 467 } 468 469 if ((tfd = mkstemp(genfmri_temp_filename)) == -1) { 470 return (ENOENT); 471 } 472 473 if (fchmod(tfd, (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1) { 474 (void) close(tfd); 475 ret = ENOENT; 476 goto unlink_out; 477 } 478 479 if ((tfp = fdopen(tfd, "w")) == NULL) { 480 (void) close(tfd); 481 ret = ENOENT; 482 goto unlink_out; 483 } 484 485 for (spval = uu_list_first(vals); spval != NULL; 486 spval = uu_list_next(vals, spval)) { 487 if (fprintf(tfp, "%lld\n", spval->val) <= 0) { 488 (void) fclose(tfp); 489 ret = ENOENT; 490 goto unlink_out; 491 } 492 } 493 if (fclose(tfp) != 0) { 494 ret = ENOENT; 495 goto unlink_out; 496 } 497 if (rename(genfmri_temp_filename, genfmri_filename) != 0) { 498 ret = ENOENT; 499 goto unlink_out; 500 } 501 return (0); 502 503 unlink_out: 504 if (unlink(genfmri_temp_filename) != 0) { 505 warn_msg(gettext("Removal of temp file " 506 "%s failed. Please remove manually."), 507 genfmri_temp_filename); 508 } 509 return (ret); 510 } 511 512 /* 513 * A routine that loops trying to read/write values until either success, 514 * an error other than a broken repository connection or 515 * the number of retries reaches REP_OP_RETRIES. 516 * This action is used to read/write the values: 517 * reads/writes to a file for the START_PIDS property due to scalability 518 * problems with libscf 519 * reads/writes to the repository for all other properties. 520 * Returns 0 on success, else the error value from either _store_rep_vals or 521 * _retrieve_rep_vals (based on whether 'store' was set or not), or one of the 522 * following: 523 * SCF_ERROR_NO_RESOURCES if the server doesn't have adequate resources 524 * SCF_ERROR_NO_MEMORY if a memory allocation failure 525 * SCF_ERROR_NO_SERVER if the server isn't running. 526 * SCF_ERROR_CONSTRAINT_VIOLATED if an error in dealing with the speedy files 527 */ 528 static scf_error_t 529 store_retrieve_rep_vals(uu_list_t *vals, const char *fmri, 530 const char *prop, boolean_t store) 531 { 532 scf_error_t ret = 0; 533 uint_t retries; 534 FILE *tfp; /* temp fp */ 535 int64_t tval; /* temp val holder */ 536 int fscanf_ret; 537 int fopen_retry_cnt = 2; 538 539 /* inetd specific action for START_PIDS property */ 540 if (strcmp(prop, PR_NAME_START_PIDS) == 0) { 541 /* 542 * Storage performance of START_PIDS is important, 543 * so each instance has its own file and all start_pids 544 * in the list are written to a temp file and then 545 * moved (renamed). 546 */ 547 if (store) { 548 /* Write all values in list to file */ 549 if (repvals_to_file(fmri, "pid", vals)) { 550 return (SCF_ERROR_CONSTRAINT_VIOLATED); 551 } 552 } else { 553 /* no temp name needed */ 554 if (gen_filenms_from_fmri(fmri, "pid", genfmri_filename, 555 NULL) != 0) 556 return (SCF_ERROR_CONSTRAINT_VIOLATED); 557 558 retry_fopen: 559 /* It's ok if no file, there are just no pids */ 560 if ((tfp = fopen(genfmri_filename, "r")) == NULL) { 561 if ((errno == EINTR) && (fopen_retry_cnt > 0)) { 562 fopen_retry_cnt--; 563 goto retry_fopen; 564 } 565 return (0); 566 } 567 /* fscanf may not set errno, so clear it first */ 568 errno = 0; 569 while ((fscanf_ret = fscanf(tfp, "%lld", &tval)) == 1) { 570 /* If tval isn't a valid pid, then fail. */ 571 if ((tval > MAXPID) || (tval <= 0)) { 572 empty_rep_val_list(vals); 573 return (SCF_ERROR_CONSTRAINT_VIOLATED); 574 } 575 if (add_rep_val(vals, tval) == -1) { 576 empty_rep_val_list(vals); 577 return (SCF_ERROR_NO_MEMORY); 578 } 579 errno = 0; 580 } 581 /* EOF is ok when no errno */ 582 if ((fscanf_ret != EOF) || (errno != 0)) { 583 empty_rep_val_list(vals); 584 return (SCF_ERROR_CONSTRAINT_VIOLATED); 585 } 586 if (fclose(tfp) != 0) { 587 /* for close failure just log a message */ 588 warn_msg(gettext("Close of file %s failed."), 589 genfmri_filename); 590 } 591 } 592 } else { 593 for (retries = 0; retries <= REP_OP_RETRIES; retries++) { 594 if (make_handle_bound(rep_handle) == -1) { 595 ret = scf_error(); 596 break; 597 } 598 599 if ((ret = (store ? _store_rep_vals(vals, fmri, prop) : 600 _retrieve_rep_vals(vals, fmri, prop))) != 601 SCF_ERROR_CONNECTION_BROKEN) 602 break; 603 604 (void) scf_handle_unbind(rep_handle); 605 } 606 } 607 608 out: 609 return (ret); 610 } 611 612 scf_error_t 613 store_rep_vals(uu_list_t *vals, const char *fmri, const char *prop) 614 { 615 return (store_retrieve_rep_vals(vals, fmri, prop, B_TRUE)); 616 } 617 618 scf_error_t 619 retrieve_rep_vals(uu_list_t *vals, const char *fmri, const char *prop) 620 { 621 return (store_retrieve_rep_vals(vals, fmri, prop, B_FALSE)); 622 } 623 624 /* 625 * Adds/removes a contract id to/from the cached list kept in the instance. 626 * Then the cached list is written to a file named "ctid" in a directory 627 * based on the fmri. Cached list is written to a file due to scalability 628 * problems in libscf. The file "ctid" is used when inetd is restarted 629 * so that inetd can adopt the contracts that it had previously. 630 * Returns: 631 * 0 on success 632 * ENAMETOOLONG if unable to generate filename from fmri (including 633 * the inability to create the directory for the generated filename) 634 * ENOENT - failure accessing file 635 * ENOMEM - memory allocation failure 636 */ 637 int 638 add_remove_contract(instance_t *inst, boolean_t add, ctid_t ctid) 639 { 640 FILE *tfp; /* temp fp */ 641 int ret = 0; 642 int repval_ret = 0; 643 int fopen_retry_cnt = 2; 644 645 /* 646 * Storage performance of contract ids is important, 647 * so each instance has its own file. An add of a 648 * ctid will be appended to the ctid file. 649 * The removal of a ctid will result in the remaining 650 * ctids in the list being written to a temp file and then 651 * moved (renamed). 652 */ 653 if (add) { 654 if (gen_filenms_from_fmri(inst->fmri, "ctid", genfmri_filename, 655 NULL) != 0) { 656 /* Failure either from fmri too long or mkdir failure */ 657 return (ENAMETOOLONG); 658 } 659 660 retry_fopen: 661 if ((tfp = fopen(genfmri_filename, "a")) == NULL) { 662 if ((errno == EINTR) && (fopen_retry_cnt > 0)) { 663 fopen_retry_cnt--; 664 goto retry_fopen; 665 } 666 ret = ENOENT; 667 goto out; 668 } 669 670 /* Always store ctids as long long */ 671 if (fprintf(tfp, "%llu\n", (uint64_t)ctid) <= 0) { 672 (void) fclose(tfp); 673 ret = ENOENT; 674 goto out; 675 } 676 677 if (fclose(tfp) != 0) { 678 ret = ENOENT; 679 goto out; 680 } 681 682 if (add_rep_val(inst->start_ctids, ctid) != 0) { 683 ret = ENOMEM; 684 goto out; 685 } 686 } else { 687 remove_rep_val(inst->start_ctids, ctid); 688 689 /* Write all values in list to file */ 690 if ((repval_ret = repvals_to_file(inst->fmri, "ctid", 691 inst->start_ctids)) != 0) { 692 ret = repval_ret; 693 goto out; 694 } 695 } 696 697 out: 698 return (ret); 699 } 700 701 /* 702 * If sig !=0, iterate over all contracts in the cached list of contract 703 * ids kept in the instance. Send each contract the specified signal. 704 * If sig == 0, read in the contract ids that were last associated 705 * with this instance (reload the cache) and call adopt_contract() 706 * to take ownership. 707 * 708 * Returns 0 on success; 709 * ENAMETOOLONG if unable to generate filename from fmri (including 710 * the inability to create the directory for the generated filename) and 711 * ENXIO if a failure accessing the file 712 * ENOMEM if there was a memory allocation failure 713 * ENOENT if the instance, its restarter property group, or its 714 * contract property don't exist 715 * EIO if invalid data read from the file 716 */ 717 int 718 iterate_repository_contracts(instance_t *inst, int sig) 719 { 720 int ret = 0; 721 FILE *fp; 722 rep_val_t *spval = NULL; /* Contains a start_pid */ 723 uint64_t tval; /* temp val holder */ 724 uu_list_t *uup = NULL; 725 int fscanf_ret; 726 int fopen_retry_cnt = 2; 727 728 if (sig != 0) { 729 /* 730 * Send a signal to all in the contract; ESRCH just 731 * means they all exited before we could kill them 732 */ 733 for (spval = uu_list_first(inst->start_ctids); spval != NULL; 734 spval = uu_list_next(inst->start_ctids, spval)) { 735 if (sigsend(P_CTID, (ctid_t)spval->val, sig) == -1 && 736 errno != ESRCH) { 737 warn_msg(gettext("Unable to signal all " 738 "contract members of instance %s: %s"), 739 inst->fmri, strerror(errno)); 740 } 741 } 742 return (0); 743 } 744 745 /* 746 * sig == 0 case. 747 * Attempt to adopt the contract for each ctid. 748 */ 749 if (gen_filenms_from_fmri(inst->fmri, "ctid", genfmri_filename, 750 NULL) != 0) { 751 /* Failure either from fmri too long or mkdir failure */ 752 return (ENAMETOOLONG); 753 } 754 755 retry_fopen: 756 /* It's ok if no file, there are no ctids to adopt */ 757 if ((fp = fopen(genfmri_filename, "r")) == NULL) { 758 if ((errno == EINTR) && (fopen_retry_cnt > 0)) { 759 fopen_retry_cnt--; 760 goto retry_fopen; 761 } 762 return (0); 763 } 764 765 /* 766 * Read ctids from file into 2 lists: 767 * - temporary list to be traversed (uup) 768 * - cached list that can be modified if adoption of 769 * contract fails (inst->start_ctids). 770 * Always treat ctids as long longs. 771 */ 772 uup = create_rep_val_list(); 773 /* fscanf may not set errno, so clear it first */ 774 errno = 0; 775 while ((fscanf_ret = fscanf(fp, "%llu", &tval)) == 1) { 776 /* If tval isn't a valid ctid, then fail. */ 777 if (tval == 0) { 778 (void) fclose(fp); 779 ret = EIO; 780 goto out; 781 } 782 if ((add_rep_val(uup, tval) == -1) || 783 (add_rep_val(inst->start_ctids, tval) == -1)) { 784 (void) fclose(fp); 785 ret = ENOMEM; 786 goto out; 787 } 788 errno = 0; 789 } 790 /* EOF is not a failure when no errno */ 791 if ((fscanf_ret != EOF) || (errno != 0)) { 792 ret = EIO; 793 goto out; 794 } 795 796 if (fclose(fp) != 0) { 797 ret = ENXIO; 798 goto out; 799 } 800 801 for (spval = uu_list_first(uup); spval != NULL; 802 spval = uu_list_next(uup, spval)) { 803 /* Try to adopt the contract */ 804 if (adopt_contract((ctid_t)spval->val, 805 inst->fmri) != 0) { 806 /* 807 * Adoption failed. No reason to think it'll 808 * work later, so remove the id from our list 809 * in the instance. 810 */ 811 remove_rep_val(inst->start_ctids, spval->val); 812 } 813 } 814 out: 815 if (uup) { 816 empty_rep_val_list(uup); 817 destroy_rep_val_list(uup); 818 } 819 820 if (ret != 0) 821 empty_rep_val_list(inst->start_ctids); 822 823 return (ret); 824 } 825