17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 594501b61Sskamm * Common Development and Distribution License (the "License"). 694501b61Sskamm * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 227c478bd9Sstevel@tonic-gate * 23*eed64e98Sgm209912 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate /* 307c478bd9Sstevel@tonic-gate * This file contains routines to manipulate lists of repository values that 317c478bd9Sstevel@tonic-gate * are used to store process ids and the internal state. There are routines 327c478bd9Sstevel@tonic-gate * to read/write the lists from/to the repository and routines to modify or 337c478bd9Sstevel@tonic-gate * inspect the lists. It also contains routines that deal with the 347c478bd9Sstevel@tonic-gate * repository side of contract ids. 357c478bd9Sstevel@tonic-gate */ 367c478bd9Sstevel@tonic-gate 377c478bd9Sstevel@tonic-gate #include <errno.h> 387c478bd9Sstevel@tonic-gate #include <stdlib.h> 397c478bd9Sstevel@tonic-gate #include <libintl.h> 407c478bd9Sstevel@tonic-gate #include <unistd.h> 417c478bd9Sstevel@tonic-gate #include <string.h> 427c478bd9Sstevel@tonic-gate #include <signal.h> 4394501b61Sskamm #include <sys/param.h> 4494501b61Sskamm #include <sys/types.h> 4594501b61Sskamm #include <sys/stat.h> 4694501b61Sskamm #include <libscf_priv.h> 477c478bd9Sstevel@tonic-gate #include "inetd_impl.h" 487c478bd9Sstevel@tonic-gate 497c478bd9Sstevel@tonic-gate /* 507c478bd9Sstevel@tonic-gate * Number of consecutive repository bind retries performed by bind_to_rep() 517c478bd9Sstevel@tonic-gate * before failing. 527c478bd9Sstevel@tonic-gate */ 537c478bd9Sstevel@tonic-gate #define BIND_TO_REP_RETRIES 10 547c478bd9Sstevel@tonic-gate 557c478bd9Sstevel@tonic-gate /* Name of property group where inetd's state for a service is stored. */ 567c478bd9Sstevel@tonic-gate #define PG_NAME_INSTANCE_STATE (const char *) "inetd_state" 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate /* uu_list repval list pool */ 597c478bd9Sstevel@tonic-gate static uu_list_pool_t *rep_val_pool = NULL; 607c478bd9Sstevel@tonic-gate 617c478bd9Sstevel@tonic-gate /* 627c478bd9Sstevel@tonic-gate * Repository object pointers that get set-up in repval_init() and closed down 637c478bd9Sstevel@tonic-gate * in repval_fini(). They're used in _retrieve_rep_vals(), _store_rep_vals(), 647c478bd9Sstevel@tonic-gate * add_remove_contract_norebind(), and adopt_repository_contracts(). They're 657c478bd9Sstevel@tonic-gate * global so they can be initialized once on inetd startup, and re-used 667c478bd9Sstevel@tonic-gate * there-after in the referenced functions. 677c478bd9Sstevel@tonic-gate */ 687c478bd9Sstevel@tonic-gate static scf_handle_t *rep_handle = NULL; 697c478bd9Sstevel@tonic-gate static scf_propertygroup_t *pg = NULL; 707c478bd9Sstevel@tonic-gate static scf_instance_t *inst = NULL; 717c478bd9Sstevel@tonic-gate static scf_transaction_t *trans = NULL; 727c478bd9Sstevel@tonic-gate static scf_transaction_entry_t *entry = NULL; 737c478bd9Sstevel@tonic-gate static scf_property_t *prop = NULL; 747c478bd9Sstevel@tonic-gate 757c478bd9Sstevel@tonic-gate /* 7694501b61Sskamm * Pathname storage for paths generated from the fmri. 7794501b61Sskamm * Used when updating the ctid and (start) pid files for an inetd service. 7894501b61Sskamm */ 7994501b61Sskamm static char genfmri_filename[MAXPATHLEN] = ""; 8094501b61Sskamm static char genfmri_temp_filename[MAXPATHLEN] = ""; 8194501b61Sskamm 8294501b61Sskamm /* 837c478bd9Sstevel@tonic-gate * Try and make the given handle bind be bound to the repository. If 847c478bd9Sstevel@tonic-gate * it's already bound, or we succeed a new bind return 0; else return 857c478bd9Sstevel@tonic-gate * -1 on failure, with the SCF error set to one of the following: 867c478bd9Sstevel@tonic-gate * SCF_ERROR_NO_SERVER 877c478bd9Sstevel@tonic-gate * SCF_ERROR_NO_RESOURCES 887c478bd9Sstevel@tonic-gate */ 897c478bd9Sstevel@tonic-gate int 907c478bd9Sstevel@tonic-gate make_handle_bound(scf_handle_t *hdl) 917c478bd9Sstevel@tonic-gate { 927c478bd9Sstevel@tonic-gate uint_t retries; 937c478bd9Sstevel@tonic-gate 947c478bd9Sstevel@tonic-gate for (retries = 0; retries <= BIND_TO_REP_RETRIES; retries++) { 957c478bd9Sstevel@tonic-gate if ((scf_handle_bind(hdl) == 0) || 967c478bd9Sstevel@tonic-gate (scf_error() == SCF_ERROR_IN_USE)) 977c478bd9Sstevel@tonic-gate return (0); 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate assert(scf_error() != SCF_ERROR_INVALID_ARGUMENT); 1007c478bd9Sstevel@tonic-gate } 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate return (-1); 1037c478bd9Sstevel@tonic-gate } 1047c478bd9Sstevel@tonic-gate 1057c478bd9Sstevel@tonic-gate int 1067c478bd9Sstevel@tonic-gate repval_init(void) 1077c478bd9Sstevel@tonic-gate { 1087c478bd9Sstevel@tonic-gate /* 1097c478bd9Sstevel@tonic-gate * Create the repval list pool. 1107c478bd9Sstevel@tonic-gate */ 1117c478bd9Sstevel@tonic-gate rep_val_pool = uu_list_pool_create("rep_val_pool", sizeof (rep_val_t), 1127c478bd9Sstevel@tonic-gate offsetof(rep_val_t, link), NULL, UU_LIST_POOL_DEBUG); 1137c478bd9Sstevel@tonic-gate if (rep_val_pool == NULL) { 1147c478bd9Sstevel@tonic-gate error_msg("%s: %s", gettext("Failed to create rep_val pool"), 1157c478bd9Sstevel@tonic-gate uu_strerror(uu_error())); 1167c478bd9Sstevel@tonic-gate return (-1); 1177c478bd9Sstevel@tonic-gate } 1187c478bd9Sstevel@tonic-gate 1197c478bd9Sstevel@tonic-gate /* 1207c478bd9Sstevel@tonic-gate * Create and bind a repository handle, and create all repository 1217c478bd9Sstevel@tonic-gate * objects that we'll use later that are associated with it. On any 1227c478bd9Sstevel@tonic-gate * errors we simply return -1 and let repval_fini() clean-up after 1237c478bd9Sstevel@tonic-gate * us. 1247c478bd9Sstevel@tonic-gate */ 1257c478bd9Sstevel@tonic-gate if ((rep_handle = scf_handle_create(SCF_VERSION)) == NULL) { 1267c478bd9Sstevel@tonic-gate error_msg("%s: %s", 1277c478bd9Sstevel@tonic-gate gettext("Failed to create repository handle"), 1287c478bd9Sstevel@tonic-gate scf_strerror(scf_error())); 1297c478bd9Sstevel@tonic-gate goto cleanup; 1307c478bd9Sstevel@tonic-gate } else if (make_handle_bound(rep_handle) == -1) { 1317c478bd9Sstevel@tonic-gate goto cleanup; 1327c478bd9Sstevel@tonic-gate } else if (((pg = scf_pg_create(rep_handle)) == NULL) || 1337c478bd9Sstevel@tonic-gate ((inst = scf_instance_create(rep_handle)) == NULL) || 1347c478bd9Sstevel@tonic-gate ((trans = scf_transaction_create(rep_handle)) == NULL) || 1357c478bd9Sstevel@tonic-gate ((entry = scf_entry_create(rep_handle)) == NULL) || 1367c478bd9Sstevel@tonic-gate ((prop = scf_property_create(rep_handle)) == NULL)) { 1377c478bd9Sstevel@tonic-gate error_msg("%s: %s", 1387c478bd9Sstevel@tonic-gate gettext("Failed to create repository object"), 1397c478bd9Sstevel@tonic-gate scf_strerror(scf_error())); 1407c478bd9Sstevel@tonic-gate goto cleanup; 1417c478bd9Sstevel@tonic-gate } 1427c478bd9Sstevel@tonic-gate 1437c478bd9Sstevel@tonic-gate return (0); 1447c478bd9Sstevel@tonic-gate cleanup: 1457c478bd9Sstevel@tonic-gate repval_fini(); 1467c478bd9Sstevel@tonic-gate return (-1); 1477c478bd9Sstevel@tonic-gate } 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate void 1507c478bd9Sstevel@tonic-gate repval_fini(void) 1517c478bd9Sstevel@tonic-gate { 1527c478bd9Sstevel@tonic-gate if (rep_handle != NULL) { 1537c478bd9Sstevel@tonic-gate /* 1547c478bd9Sstevel@tonic-gate * We unbind from the repository before we free the repository 1557c478bd9Sstevel@tonic-gate * objects for efficiency reasons. 1567c478bd9Sstevel@tonic-gate */ 1577c478bd9Sstevel@tonic-gate (void) scf_handle_unbind(rep_handle); 1587c478bd9Sstevel@tonic-gate 1597c478bd9Sstevel@tonic-gate scf_pg_destroy(pg); 1607c478bd9Sstevel@tonic-gate pg = NULL; 1617c478bd9Sstevel@tonic-gate scf_instance_destroy(inst); 1627c478bd9Sstevel@tonic-gate inst = NULL; 1637c478bd9Sstevel@tonic-gate scf_transaction_destroy(trans); 1647c478bd9Sstevel@tonic-gate trans = NULL; 1657c478bd9Sstevel@tonic-gate scf_entry_destroy(entry); 1667c478bd9Sstevel@tonic-gate entry = NULL; 1677c478bd9Sstevel@tonic-gate scf_property_destroy(prop); 1687c478bd9Sstevel@tonic-gate prop = NULL; 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate scf_handle_destroy(rep_handle); 1717c478bd9Sstevel@tonic-gate rep_handle = NULL; 1727c478bd9Sstevel@tonic-gate } 1737c478bd9Sstevel@tonic-gate 1747c478bd9Sstevel@tonic-gate if (rep_val_pool != NULL) { 1757c478bd9Sstevel@tonic-gate uu_list_pool_destroy(rep_val_pool); 1767c478bd9Sstevel@tonic-gate rep_val_pool = NULL; 1777c478bd9Sstevel@tonic-gate } 1787c478bd9Sstevel@tonic-gate } 1797c478bd9Sstevel@tonic-gate 1807c478bd9Sstevel@tonic-gate uu_list_t * 1817c478bd9Sstevel@tonic-gate create_rep_val_list(void) 1827c478bd9Sstevel@tonic-gate { 1837c478bd9Sstevel@tonic-gate uu_list_t *ret; 1847c478bd9Sstevel@tonic-gate 1857c478bd9Sstevel@tonic-gate if ((ret = uu_list_create(rep_val_pool, NULL, 0)) == NULL) 1867c478bd9Sstevel@tonic-gate assert(uu_error() == UU_ERROR_NO_MEMORY); 1877c478bd9Sstevel@tonic-gate 1887c478bd9Sstevel@tonic-gate return (ret); 1897c478bd9Sstevel@tonic-gate } 1907c478bd9Sstevel@tonic-gate 1917c478bd9Sstevel@tonic-gate void 1927c478bd9Sstevel@tonic-gate destroy_rep_val_list(uu_list_t *list) 1937c478bd9Sstevel@tonic-gate { 1947c478bd9Sstevel@tonic-gate if (list != NULL) { 1957c478bd9Sstevel@tonic-gate empty_rep_val_list(list); 1967c478bd9Sstevel@tonic-gate uu_list_destroy(list); 1977c478bd9Sstevel@tonic-gate } 1987c478bd9Sstevel@tonic-gate } 1997c478bd9Sstevel@tonic-gate 2007c478bd9Sstevel@tonic-gate rep_val_t * 2017c478bd9Sstevel@tonic-gate find_rep_val(uu_list_t *list, int64_t val) 2027c478bd9Sstevel@tonic-gate { 2037c478bd9Sstevel@tonic-gate rep_val_t *rv; 2047c478bd9Sstevel@tonic-gate 2057c478bd9Sstevel@tonic-gate for (rv = uu_list_first(list); rv != NULL; 2067c478bd9Sstevel@tonic-gate rv = uu_list_next(list, rv)) { 2077c478bd9Sstevel@tonic-gate if (rv->val == val) 2087c478bd9Sstevel@tonic-gate break; 2097c478bd9Sstevel@tonic-gate } 2107c478bd9Sstevel@tonic-gate return (rv); 2117c478bd9Sstevel@tonic-gate } 2127c478bd9Sstevel@tonic-gate 2137c478bd9Sstevel@tonic-gate int 2147c478bd9Sstevel@tonic-gate add_rep_val(uu_list_t *list, int64_t val) 2157c478bd9Sstevel@tonic-gate { 2167c478bd9Sstevel@tonic-gate rep_val_t *rv; 2177c478bd9Sstevel@tonic-gate 2187c478bd9Sstevel@tonic-gate if ((rv = malloc(sizeof (rep_val_t))) == NULL) 2197c478bd9Sstevel@tonic-gate return (-1); 2207c478bd9Sstevel@tonic-gate 2217c478bd9Sstevel@tonic-gate uu_list_node_init(rv, &rv->link, rep_val_pool); 2227c478bd9Sstevel@tonic-gate rv->val = val; 2237c478bd9Sstevel@tonic-gate rv->scf_val = NULL; 2247c478bd9Sstevel@tonic-gate (void) uu_list_insert_after(list, NULL, rv); 2257c478bd9Sstevel@tonic-gate 2267c478bd9Sstevel@tonic-gate return (0); 2277c478bd9Sstevel@tonic-gate } 2287c478bd9Sstevel@tonic-gate 2297c478bd9Sstevel@tonic-gate void 2307c478bd9Sstevel@tonic-gate remove_rep_val(uu_list_t *list, int64_t val) 2317c478bd9Sstevel@tonic-gate { 2327c478bd9Sstevel@tonic-gate rep_val_t *rv; 2337c478bd9Sstevel@tonic-gate 2347c478bd9Sstevel@tonic-gate if ((rv = find_rep_val(list, val)) != NULL) { 2357c478bd9Sstevel@tonic-gate uu_list_remove(list, rv); 2367c478bd9Sstevel@tonic-gate assert(rv->scf_val == NULL); 2377c478bd9Sstevel@tonic-gate free(rv); 2387c478bd9Sstevel@tonic-gate } 2397c478bd9Sstevel@tonic-gate } 2407c478bd9Sstevel@tonic-gate 2417c478bd9Sstevel@tonic-gate void 2427c478bd9Sstevel@tonic-gate empty_rep_val_list(uu_list_t *list) 2437c478bd9Sstevel@tonic-gate { 2447c478bd9Sstevel@tonic-gate void *cookie = NULL; 2457c478bd9Sstevel@tonic-gate rep_val_t *rv; 2467c478bd9Sstevel@tonic-gate 2477c478bd9Sstevel@tonic-gate while ((rv = uu_list_teardown(list, &cookie)) != NULL) { 2487c478bd9Sstevel@tonic-gate if (rv->scf_val != NULL) 2497c478bd9Sstevel@tonic-gate scf_value_destroy(rv->scf_val); 2507c478bd9Sstevel@tonic-gate free(rv); 2517c478bd9Sstevel@tonic-gate } 2527c478bd9Sstevel@tonic-gate } 2537c478bd9Sstevel@tonic-gate 2547c478bd9Sstevel@tonic-gate int64_t 2557c478bd9Sstevel@tonic-gate get_single_rep_val(uu_list_t *list) 2567c478bd9Sstevel@tonic-gate { 2577c478bd9Sstevel@tonic-gate rep_val_t *rv = uu_list_first(list); 2587c478bd9Sstevel@tonic-gate 2597c478bd9Sstevel@tonic-gate assert(rv != NULL); 2607c478bd9Sstevel@tonic-gate return (rv->val); 2617c478bd9Sstevel@tonic-gate } 2627c478bd9Sstevel@tonic-gate 2637c478bd9Sstevel@tonic-gate int 2647c478bd9Sstevel@tonic-gate set_single_rep_val(uu_list_t *list, int64_t val) 2657c478bd9Sstevel@tonic-gate { 2667c478bd9Sstevel@tonic-gate rep_val_t *rv = uu_list_first(list); 2677c478bd9Sstevel@tonic-gate 2687c478bd9Sstevel@tonic-gate if (rv == NULL) { 2697c478bd9Sstevel@tonic-gate if (add_rep_val(list, val) == -1) 2707c478bd9Sstevel@tonic-gate return (-1); 2717c478bd9Sstevel@tonic-gate } else { 2727c478bd9Sstevel@tonic-gate rv->val = val; 2737c478bd9Sstevel@tonic-gate } 2747c478bd9Sstevel@tonic-gate 2757c478bd9Sstevel@tonic-gate return (0); 2767c478bd9Sstevel@tonic-gate } 2777c478bd9Sstevel@tonic-gate 2787c478bd9Sstevel@tonic-gate /* 2797c478bd9Sstevel@tonic-gate * Partner to add_tr_entry_values. This function frees the scf_values created 2807c478bd9Sstevel@tonic-gate * in add_tr_entry_values() in the list 'vals'. 2817c478bd9Sstevel@tonic-gate */ 2827c478bd9Sstevel@tonic-gate static void 2837c478bd9Sstevel@tonic-gate remove_tr_entry_values(uu_list_t *vals) 2847c478bd9Sstevel@tonic-gate { 2857c478bd9Sstevel@tonic-gate rep_val_t *rval; 2867c478bd9Sstevel@tonic-gate 2877c478bd9Sstevel@tonic-gate for (rval = uu_list_first(vals); rval != NULL; 2887c478bd9Sstevel@tonic-gate rval = uu_list_next(vals, rval)) { 2897c478bd9Sstevel@tonic-gate if (rval->scf_val != NULL) { 2907c478bd9Sstevel@tonic-gate scf_value_destroy(rval->scf_val); 2917c478bd9Sstevel@tonic-gate rval->scf_val = NULL; 2927c478bd9Sstevel@tonic-gate } 2937c478bd9Sstevel@tonic-gate } 2947c478bd9Sstevel@tonic-gate } 2957c478bd9Sstevel@tonic-gate 2967c478bd9Sstevel@tonic-gate /* 2977c478bd9Sstevel@tonic-gate * This function creates and associates with transaction entry 'entry' an 2987c478bd9Sstevel@tonic-gate * scf value for each value in 'vals'. The pointers to the scf values 2997c478bd9Sstevel@tonic-gate * are stored in the list for later cleanup by remove_tr_entry_values. 3007c478bd9Sstevel@tonic-gate * Returns 0 on success, else -1 on error with scf_error() set to: 3017c478bd9Sstevel@tonic-gate * SCF_ERROR_NO_MEMORY if memory allocation failed. 3027c478bd9Sstevel@tonic-gate * SCF_ERROR_CONNECTION_BROKEN if the connection to the repository was broken. 3037c478bd9Sstevel@tonic-gate */ 3047c478bd9Sstevel@tonic-gate static int 3057c478bd9Sstevel@tonic-gate add_tr_entry_values(scf_handle_t *hdl, scf_transaction_entry_t *entry, 3067c478bd9Sstevel@tonic-gate uu_list_t *vals) 3077c478bd9Sstevel@tonic-gate { 3087c478bd9Sstevel@tonic-gate rep_val_t *rval; 3097c478bd9Sstevel@tonic-gate 3107c478bd9Sstevel@tonic-gate for (rval = uu_list_first(vals); rval != NULL; 3117c478bd9Sstevel@tonic-gate rval = uu_list_next(vals, rval)) { 3127c478bd9Sstevel@tonic-gate 3137c478bd9Sstevel@tonic-gate assert(rval->scf_val == NULL); 3147c478bd9Sstevel@tonic-gate if ((rval->scf_val = scf_value_create(hdl)) == NULL) { 3157c478bd9Sstevel@tonic-gate remove_tr_entry_values(vals); 3167c478bd9Sstevel@tonic-gate return (-1); 3177c478bd9Sstevel@tonic-gate } 3187c478bd9Sstevel@tonic-gate 3197c478bd9Sstevel@tonic-gate scf_value_set_integer(rval->scf_val, rval->val); 3207c478bd9Sstevel@tonic-gate 3217c478bd9Sstevel@tonic-gate if (scf_entry_add_value(entry, rval->scf_val) < 0) { 3227c478bd9Sstevel@tonic-gate remove_tr_entry_values(vals); 3237c478bd9Sstevel@tonic-gate return (-1); 3247c478bd9Sstevel@tonic-gate } 3257c478bd9Sstevel@tonic-gate } 3267c478bd9Sstevel@tonic-gate 3277c478bd9Sstevel@tonic-gate return (0); 3287c478bd9Sstevel@tonic-gate } 3297c478bd9Sstevel@tonic-gate 3307c478bd9Sstevel@tonic-gate /* 3317c478bd9Sstevel@tonic-gate * Stores the values contained in the list 'vals' into the property 'prop_name' 3327c478bd9Sstevel@tonic-gate * of the instance with fmri 'inst_fmri', within the instance's instance 3337c478bd9Sstevel@tonic-gate * state property group. 3347c478bd9Sstevel@tonic-gate * 3357c478bd9Sstevel@tonic-gate * Returns 0 on success, else one of the following on failure: 3367c478bd9Sstevel@tonic-gate * SCF_ERROR_NO_MEMORY if memory allocation failed. 3377c478bd9Sstevel@tonic-gate * SCF_ERROR_NO_RESOURCES if the server doesn't have required resources. 3387c478bd9Sstevel@tonic-gate * SCF_ERROR_VERSION_MISMATCH if program compiled against a newer libscf 3397c478bd9Sstevel@tonic-gate * than on system. 3407c478bd9Sstevel@tonic-gate * SCF_ERROR_PERMISSION_DENIED if insufficient privileges to modify pg. 3417c478bd9Sstevel@tonic-gate * SCF_ERROR_BACKEND_ACCESS if the repository back-end refused the pg modify. 3427c478bd9Sstevel@tonic-gate * SCF_ERROR_CONNECTION_BROKEN if the connection to the repository was broken. 3437c478bd9Sstevel@tonic-gate */ 3447c478bd9Sstevel@tonic-gate static scf_error_t 3457c478bd9Sstevel@tonic-gate _store_rep_vals(uu_list_t *vals, const char *inst_fmri, const char *prop_name) 3467c478bd9Sstevel@tonic-gate { 3477c478bd9Sstevel@tonic-gate int cret; 3487c478bd9Sstevel@tonic-gate int ret; 3497c478bd9Sstevel@tonic-gate 3507c478bd9Sstevel@tonic-gate if (scf_handle_decode_fmri(rep_handle, inst_fmri, NULL, NULL, inst, 3517c478bd9Sstevel@tonic-gate NULL, NULL, SCF_DECODE_FMRI_EXACT) == -1) 3527c478bd9Sstevel@tonic-gate return (scf_error()); 3537c478bd9Sstevel@tonic-gate 3547c478bd9Sstevel@tonic-gate /* 3557c478bd9Sstevel@tonic-gate * Fetch the instance state pg, and if it doesn't exist try and 3567c478bd9Sstevel@tonic-gate * create it. 3577c478bd9Sstevel@tonic-gate */ 3587c478bd9Sstevel@tonic-gate if (scf_instance_get_pg(inst, PG_NAME_INSTANCE_STATE, pg) < 0) { 3597c478bd9Sstevel@tonic-gate if (scf_error() != SCF_ERROR_NOT_FOUND) 3607c478bd9Sstevel@tonic-gate return (scf_error()); 3617c478bd9Sstevel@tonic-gate if (scf_instance_add_pg(inst, PG_NAME_INSTANCE_STATE, 3627c478bd9Sstevel@tonic-gate SCF_GROUP_FRAMEWORK, SCF_PG_FLAG_NONPERSISTENT, pg) < 0) 3637c478bd9Sstevel@tonic-gate return (scf_error()); 3647c478bd9Sstevel@tonic-gate } 3657c478bd9Sstevel@tonic-gate 3667c478bd9Sstevel@tonic-gate /* 3677c478bd9Sstevel@tonic-gate * Perform a transaction to write the values to the requested property. 3687c478bd9Sstevel@tonic-gate * If someone got there before us, loop and retry. 3697c478bd9Sstevel@tonic-gate */ 3707c478bd9Sstevel@tonic-gate do { 3717c478bd9Sstevel@tonic-gate if (scf_transaction_start(trans, pg) < 0) 3727c478bd9Sstevel@tonic-gate return (scf_error()); 3737c478bd9Sstevel@tonic-gate 3747c478bd9Sstevel@tonic-gate if ((scf_transaction_property_new(trans, entry, 3757c478bd9Sstevel@tonic-gate prop_name, SCF_TYPE_INTEGER) < 0) && 3767c478bd9Sstevel@tonic-gate (scf_transaction_property_change_type(trans, entry, 3777c478bd9Sstevel@tonic-gate prop_name, SCF_TYPE_INTEGER) < 0)) { 3787c478bd9Sstevel@tonic-gate ret = scf_error(); 3797c478bd9Sstevel@tonic-gate goto cleanup; 3807c478bd9Sstevel@tonic-gate } 3817c478bd9Sstevel@tonic-gate 3827c478bd9Sstevel@tonic-gate if (add_tr_entry_values(rep_handle, entry, vals) < 0) { 3837c478bd9Sstevel@tonic-gate ret = scf_error(); 3847c478bd9Sstevel@tonic-gate goto cleanup; 3857c478bd9Sstevel@tonic-gate } 3867c478bd9Sstevel@tonic-gate 3877c478bd9Sstevel@tonic-gate if ((cret = scf_transaction_commit(trans)) < 0) { 3887c478bd9Sstevel@tonic-gate ret = scf_error(); 3897c478bd9Sstevel@tonic-gate goto cleanup; 3907c478bd9Sstevel@tonic-gate } else if (cret == 0) { 3917c478bd9Sstevel@tonic-gate scf_transaction_reset(trans); 3927c478bd9Sstevel@tonic-gate scf_entry_reset(entry); 3937c478bd9Sstevel@tonic-gate remove_tr_entry_values(vals); 3947c478bd9Sstevel@tonic-gate if (scf_pg_update(pg) < 0) { 3957c478bd9Sstevel@tonic-gate ret = scf_error(); 3967c478bd9Sstevel@tonic-gate goto cleanup; 3977c478bd9Sstevel@tonic-gate } 3987c478bd9Sstevel@tonic-gate } 3997c478bd9Sstevel@tonic-gate } while (cret == 0); 4007c478bd9Sstevel@tonic-gate 4017c478bd9Sstevel@tonic-gate ret = 0; 4027c478bd9Sstevel@tonic-gate cleanup: 4037c478bd9Sstevel@tonic-gate scf_transaction_reset(trans); 4047c478bd9Sstevel@tonic-gate scf_entry_reset(entry); 4057c478bd9Sstevel@tonic-gate remove_tr_entry_values(vals); 4067c478bd9Sstevel@tonic-gate return (ret); 4077c478bd9Sstevel@tonic-gate } 4087c478bd9Sstevel@tonic-gate 4097c478bd9Sstevel@tonic-gate /* 4107c478bd9Sstevel@tonic-gate * Retrieves the repository values of property 'prop_name', of the instance 4117c478bd9Sstevel@tonic-gate * with fmri 'fmri', from within the instance's instance state property 4127c478bd9Sstevel@tonic-gate * group and adds them to the value list 'list'. 4137c478bd9Sstevel@tonic-gate * 4147c478bd9Sstevel@tonic-gate * Returns 0 on success, else one of the following values on error: 4157c478bd9Sstevel@tonic-gate * SCF_ERROR_NOT_FOUND if the property doesn't exist. 4167c478bd9Sstevel@tonic-gate * SCF_ERROR_NO_MEMORY if memory allocation failed. 4177c478bd9Sstevel@tonic-gate * SCF_ERROR_CONNECTION_BROKEN if the connection to the repository was broken. 4187c478bd9Sstevel@tonic-gate * SCF_ERROR_TYPE_MISMATCH if the property was of an unexpected type. 4197c478bd9Sstevel@tonic-gate * 4207c478bd9Sstevel@tonic-gate */ 4217c478bd9Sstevel@tonic-gate static scf_error_t 4227c478bd9Sstevel@tonic-gate _retrieve_rep_vals(uu_list_t *list, const char *fmri, const char *prop_name) 4237c478bd9Sstevel@tonic-gate { 4247c478bd9Sstevel@tonic-gate scf_simple_prop_t *sp; 4257c478bd9Sstevel@tonic-gate int64_t *ip; 4267c478bd9Sstevel@tonic-gate 4277c478bd9Sstevel@tonic-gate if ((sp = scf_simple_prop_get(rep_handle, fmri, PG_NAME_INSTANCE_STATE, 4287c478bd9Sstevel@tonic-gate prop_name)) == NULL) 4297c478bd9Sstevel@tonic-gate return (scf_error()); 4307c478bd9Sstevel@tonic-gate 4317c478bd9Sstevel@tonic-gate while ((ip = scf_simple_prop_next_integer(sp)) != NULL) { 4327c478bd9Sstevel@tonic-gate if (add_rep_val(list, *ip) == -1) { 4337c478bd9Sstevel@tonic-gate empty_rep_val_list(list); 4347c478bd9Sstevel@tonic-gate scf_simple_prop_free(sp); 4357c478bd9Sstevel@tonic-gate return (SCF_ERROR_NO_MEMORY); 4367c478bd9Sstevel@tonic-gate } 4377c478bd9Sstevel@tonic-gate } 4387c478bd9Sstevel@tonic-gate if (scf_error() != SCF_ERROR_NONE) { 4397c478bd9Sstevel@tonic-gate assert(scf_error() == SCF_ERROR_TYPE_MISMATCH); 4407c478bd9Sstevel@tonic-gate empty_rep_val_list(list); 4417c478bd9Sstevel@tonic-gate scf_simple_prop_free(sp); 4427c478bd9Sstevel@tonic-gate return (scf_error()); 4437c478bd9Sstevel@tonic-gate } 4447c478bd9Sstevel@tonic-gate 4457c478bd9Sstevel@tonic-gate scf_simple_prop_free(sp); 4467c478bd9Sstevel@tonic-gate return (0); 4477c478bd9Sstevel@tonic-gate } 4487c478bd9Sstevel@tonic-gate 4497c478bd9Sstevel@tonic-gate /* 45094501b61Sskamm * Writes the repository values in the vals list to 45194501b61Sskamm * a file that is generated based on the passed in fmri and name. 45294501b61Sskamm * Returns 0 on success, 45394501b61Sskamm * ENAMETOOLONG if unable to generate filename from fmri (including 45494501b61Sskamm * the inability to create the directory for the generated filename) and 45594501b61Sskamm * ENOENT on all other failures. 45694501b61Sskamm */ 45794501b61Sskamm static int 45894501b61Sskamm repvals_to_file(const char *fmri, const char *name, uu_list_t *vals) 45994501b61Sskamm { 46094501b61Sskamm int tfd; 46194501b61Sskamm FILE *tfp; /* temp fp */ 46294501b61Sskamm rep_val_t *spval; /* Contains a start_pid or ctid */ 46394501b61Sskamm int ret = 0; 46494501b61Sskamm 46594501b61Sskamm if (gen_filenms_from_fmri(fmri, name, genfmri_filename, 46694501b61Sskamm genfmri_temp_filename) != 0) { 46794501b61Sskamm /* Failure either from fmri too long or mkdir failure */ 46894501b61Sskamm return (ENAMETOOLONG); 46994501b61Sskamm } 47094501b61Sskamm 47194501b61Sskamm if ((tfd = mkstemp(genfmri_temp_filename)) == -1) { 47294501b61Sskamm return (ENOENT); 47394501b61Sskamm } 47494501b61Sskamm 47594501b61Sskamm if (fchmod(tfd, (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1) { 47694501b61Sskamm (void) close(tfd); 47794501b61Sskamm ret = ENOENT; 47894501b61Sskamm goto unlink_out; 47994501b61Sskamm } 48094501b61Sskamm 48194501b61Sskamm if ((tfp = fdopen(tfd, "w")) == NULL) { 48294501b61Sskamm (void) close(tfd); 48394501b61Sskamm ret = ENOENT; 48494501b61Sskamm goto unlink_out; 48594501b61Sskamm } 48694501b61Sskamm 48794501b61Sskamm for (spval = uu_list_first(vals); spval != NULL; 48894501b61Sskamm spval = uu_list_next(vals, spval)) { 48994501b61Sskamm if (fprintf(tfp, "%lld\n", spval->val) <= 0) { 49094501b61Sskamm (void) fclose(tfp); 49194501b61Sskamm ret = ENOENT; 49294501b61Sskamm goto unlink_out; 49394501b61Sskamm } 49494501b61Sskamm } 49594501b61Sskamm if (fclose(tfp) != 0) { 49694501b61Sskamm ret = ENOENT; 49794501b61Sskamm goto unlink_out; 49894501b61Sskamm } 49994501b61Sskamm if (rename(genfmri_temp_filename, genfmri_filename) != 0) { 50094501b61Sskamm ret = ENOENT; 50194501b61Sskamm goto unlink_out; 50294501b61Sskamm } 50394501b61Sskamm return (0); 50494501b61Sskamm 50594501b61Sskamm unlink_out: 50694501b61Sskamm if (unlink(genfmri_temp_filename) != 0) { 50794501b61Sskamm warn_msg(gettext("Removal of temp file " 50894501b61Sskamm "%s failed. Please remove manually."), 50994501b61Sskamm genfmri_temp_filename); 51094501b61Sskamm } 51194501b61Sskamm return (ret); 51294501b61Sskamm } 51394501b61Sskamm 51494501b61Sskamm /* 51594501b61Sskamm * A routine that loops trying to read/write values until either success, 51694501b61Sskamm * an error other than a broken repository connection or 5177c478bd9Sstevel@tonic-gate * the number of retries reaches REP_OP_RETRIES. 51894501b61Sskamm * This action is used to read/write the values: 51994501b61Sskamm * reads/writes to a file for the START_PIDS property due to scalability 52094501b61Sskamm * problems with libscf 52194501b61Sskamm * reads/writes to the repository for all other properties. 5227c478bd9Sstevel@tonic-gate * Returns 0 on success, else the error value from either _store_rep_vals or 52394501b61Sskamm * _retrieve_rep_vals (based on whether 'store' was set or not), or one of the 52494501b61Sskamm * following: 52594501b61Sskamm * SCF_ERROR_NO_RESOURCES if the server doesn't have adequate resources 52694501b61Sskamm * SCF_ERROR_NO_MEMORY if a memory allocation failure 5277c478bd9Sstevel@tonic-gate * SCF_ERROR_NO_SERVER if the server isn't running. 52894501b61Sskamm * SCF_ERROR_CONSTRAINT_VIOLATED if an error in dealing with the speedy files 5297c478bd9Sstevel@tonic-gate */ 5307c478bd9Sstevel@tonic-gate static scf_error_t 5317c478bd9Sstevel@tonic-gate store_retrieve_rep_vals(uu_list_t *vals, const char *fmri, 5327c478bd9Sstevel@tonic-gate const char *prop, boolean_t store) 5337c478bd9Sstevel@tonic-gate { 53494501b61Sskamm scf_error_t ret = 0; 5357c478bd9Sstevel@tonic-gate uint_t retries; 53694501b61Sskamm FILE *tfp; /* temp fp */ 53794501b61Sskamm int64_t tval; /* temp val holder */ 53894501b61Sskamm int fscanf_ret; 53994501b61Sskamm int fopen_retry_cnt = 2; 5407c478bd9Sstevel@tonic-gate 54194501b61Sskamm /* inetd specific action for START_PIDS property */ 54294501b61Sskamm if (strcmp(prop, PR_NAME_START_PIDS) == 0) { 54394501b61Sskamm /* 54494501b61Sskamm * Storage performance of START_PIDS is important, 54594501b61Sskamm * so each instance has its own file and all start_pids 54694501b61Sskamm * in the list are written to a temp file and then 54794501b61Sskamm * moved (renamed). 54894501b61Sskamm */ 54994501b61Sskamm if (store) { 55094501b61Sskamm /* Write all values in list to file */ 55194501b61Sskamm if (repvals_to_file(fmri, "pid", vals)) { 55294501b61Sskamm return (SCF_ERROR_CONSTRAINT_VIOLATED); 55394501b61Sskamm } 55494501b61Sskamm } else { 55594501b61Sskamm /* no temp name needed */ 55694501b61Sskamm if (gen_filenms_from_fmri(fmri, "pid", genfmri_filename, 55794501b61Sskamm NULL) != 0) 55894501b61Sskamm return (SCF_ERROR_CONSTRAINT_VIOLATED); 5597c478bd9Sstevel@tonic-gate 56094501b61Sskamm retry_fopen: 56194501b61Sskamm /* It's ok if no file, there are just no pids */ 56294501b61Sskamm if ((tfp = fopen(genfmri_filename, "r")) == NULL) { 56394501b61Sskamm if ((errno == EINTR) && (fopen_retry_cnt > 0)) { 56494501b61Sskamm fopen_retry_cnt--; 56594501b61Sskamm goto retry_fopen; 56694501b61Sskamm } 56794501b61Sskamm return (0); 56894501b61Sskamm } 56994501b61Sskamm /* fscanf may not set errno, so clear it first */ 57094501b61Sskamm errno = 0; 57194501b61Sskamm while ((fscanf_ret = fscanf(tfp, "%lld", &tval)) == 1) { 57294501b61Sskamm /* If tval isn't a valid pid, then fail. */ 57394501b61Sskamm if ((tval > MAXPID) || (tval <= 0)) { 57494501b61Sskamm empty_rep_val_list(vals); 57594501b61Sskamm return (SCF_ERROR_CONSTRAINT_VIOLATED); 57694501b61Sskamm } 57794501b61Sskamm if (add_rep_val(vals, tval) == -1) { 57894501b61Sskamm empty_rep_val_list(vals); 57994501b61Sskamm return (SCF_ERROR_NO_MEMORY); 58094501b61Sskamm } 58194501b61Sskamm errno = 0; 58294501b61Sskamm } 58394501b61Sskamm /* EOF is ok when no errno */ 58494501b61Sskamm if ((fscanf_ret != EOF) || (errno != 0)) { 58594501b61Sskamm empty_rep_val_list(vals); 58694501b61Sskamm return (SCF_ERROR_CONSTRAINT_VIOLATED); 58794501b61Sskamm } 58894501b61Sskamm if (fclose(tfp) != 0) { 58994501b61Sskamm /* for close failure just log a message */ 59094501b61Sskamm warn_msg(gettext("Close of file %s failed."), 59194501b61Sskamm genfmri_filename); 59294501b61Sskamm } 59394501b61Sskamm } 59494501b61Sskamm } else { 5957c478bd9Sstevel@tonic-gate for (retries = 0; retries <= REP_OP_RETRIES; retries++) { 5967c478bd9Sstevel@tonic-gate if (make_handle_bound(rep_handle) == -1) { 5977c478bd9Sstevel@tonic-gate ret = scf_error(); 5987c478bd9Sstevel@tonic-gate break; 5997c478bd9Sstevel@tonic-gate } 6007c478bd9Sstevel@tonic-gate 6017c478bd9Sstevel@tonic-gate if ((ret = (store ? _store_rep_vals(vals, fmri, prop) : 6027c478bd9Sstevel@tonic-gate _retrieve_rep_vals(vals, fmri, prop))) != 6037c478bd9Sstevel@tonic-gate SCF_ERROR_CONNECTION_BROKEN) 6047c478bd9Sstevel@tonic-gate break; 6057c478bd9Sstevel@tonic-gate 6067c478bd9Sstevel@tonic-gate (void) scf_handle_unbind(rep_handle); 6077c478bd9Sstevel@tonic-gate } 60894501b61Sskamm } 6097c478bd9Sstevel@tonic-gate 61094501b61Sskamm out: 6117c478bd9Sstevel@tonic-gate return (ret); 6127c478bd9Sstevel@tonic-gate } 6137c478bd9Sstevel@tonic-gate 6147c478bd9Sstevel@tonic-gate scf_error_t 6157c478bd9Sstevel@tonic-gate store_rep_vals(uu_list_t *vals, const char *fmri, const char *prop) 6167c478bd9Sstevel@tonic-gate { 6177c478bd9Sstevel@tonic-gate return (store_retrieve_rep_vals(vals, fmri, prop, B_TRUE)); 6187c478bd9Sstevel@tonic-gate } 6197c478bd9Sstevel@tonic-gate 6207c478bd9Sstevel@tonic-gate scf_error_t 6217c478bd9Sstevel@tonic-gate retrieve_rep_vals(uu_list_t *vals, const char *fmri, const char *prop) 6227c478bd9Sstevel@tonic-gate { 6237c478bd9Sstevel@tonic-gate return (store_retrieve_rep_vals(vals, fmri, prop, B_FALSE)); 6247c478bd9Sstevel@tonic-gate } 6257c478bd9Sstevel@tonic-gate 6267c478bd9Sstevel@tonic-gate /* 62794501b61Sskamm * Adds/removes a contract id to/from the cached list kept in the instance. 62894501b61Sskamm * Then the cached list is written to a file named "ctid" in a directory 62994501b61Sskamm * based on the fmri. Cached list is written to a file due to scalability 63094501b61Sskamm * problems in libscf. The file "ctid" is used when inetd is restarted 63194501b61Sskamm * so that inetd can adopt the contracts that it had previously. 63294501b61Sskamm * Returns: 63394501b61Sskamm * 0 on success 63494501b61Sskamm * ENAMETOOLONG if unable to generate filename from fmri (including 63594501b61Sskamm * the inability to create the directory for the generated filename) 63694501b61Sskamm * ENOENT - failure accessing file 63794501b61Sskamm * ENOMEM - memory allocation failure 6387c478bd9Sstevel@tonic-gate */ 6397c478bd9Sstevel@tonic-gate int 64094501b61Sskamm add_remove_contract(instance_t *inst, boolean_t add, ctid_t ctid) 6417c478bd9Sstevel@tonic-gate { 64294501b61Sskamm FILE *tfp; /* temp fp */ 6437c478bd9Sstevel@tonic-gate int ret = 0; 64494501b61Sskamm int repval_ret = 0; 64594501b61Sskamm int fopen_retry_cnt = 2; 6467c478bd9Sstevel@tonic-gate 64794501b61Sskamm /* 64894501b61Sskamm * Storage performance of contract ids is important, 64994501b61Sskamm * so each instance has its own file. An add of a 65094501b61Sskamm * ctid will be appended to the ctid file. 65194501b61Sskamm * The removal of a ctid will result in the remaining 65294501b61Sskamm * ctids in the list being written to a temp file and then 65394501b61Sskamm * moved (renamed). 65494501b61Sskamm */ 65594501b61Sskamm if (add) { 65694501b61Sskamm if (gen_filenms_from_fmri(inst->fmri, "ctid", genfmri_filename, 65794501b61Sskamm NULL) != 0) { 65894501b61Sskamm /* Failure either from fmri too long or mkdir failure */ 65994501b61Sskamm return (ENAMETOOLONG); 66094501b61Sskamm } 6617c478bd9Sstevel@tonic-gate 66294501b61Sskamm retry_fopen: 66394501b61Sskamm if ((tfp = fopen(genfmri_filename, "a")) == NULL) { 66494501b61Sskamm if ((errno == EINTR) && (fopen_retry_cnt > 0)) { 66594501b61Sskamm fopen_retry_cnt--; 66694501b61Sskamm goto retry_fopen; 66794501b61Sskamm } 66894501b61Sskamm ret = ENOENT; 66994501b61Sskamm goto out; 67094501b61Sskamm } 67194501b61Sskamm 67294501b61Sskamm /* Always store ctids as long long */ 67394501b61Sskamm if (fprintf(tfp, "%llu\n", (uint64_t)ctid) <= 0) { 67494501b61Sskamm (void) fclose(tfp); 67594501b61Sskamm ret = ENOENT; 67694501b61Sskamm goto out; 67794501b61Sskamm } 67894501b61Sskamm 67994501b61Sskamm if (fclose(tfp) != 0) { 68094501b61Sskamm ret = ENOENT; 68194501b61Sskamm goto out; 68294501b61Sskamm } 68394501b61Sskamm 68494501b61Sskamm if (add_rep_val(inst->start_ctids, ctid) != 0) { 6857c478bd9Sstevel@tonic-gate ret = ENOMEM; 6867c478bd9Sstevel@tonic-gate goto out; 6877c478bd9Sstevel@tonic-gate } 6887c478bd9Sstevel@tonic-gate } else { 68994501b61Sskamm remove_rep_val(inst->start_ctids, ctid); 69094501b61Sskamm 69194501b61Sskamm /* Write all values in list to file */ 69294501b61Sskamm if ((repval_ret = repvals_to_file(inst->fmri, "ctid", 69394501b61Sskamm inst->start_ctids)) != 0) { 69494501b61Sskamm ret = repval_ret; 69594501b61Sskamm goto out; 6967c478bd9Sstevel@tonic-gate } 6977c478bd9Sstevel@tonic-gate } 6987c478bd9Sstevel@tonic-gate 6997c478bd9Sstevel@tonic-gate out: 70094501b61Sskamm return (ret); 70194501b61Sskamm } 70294501b61Sskamm 70394501b61Sskamm /* 70494501b61Sskamm * If sig !=0, iterate over all contracts in the cached list of contract 70594501b61Sskamm * ids kept in the instance. Send each contract the specified signal. 70694501b61Sskamm * If sig == 0, read in the contract ids that were last associated 70794501b61Sskamm * with this instance (reload the cache) and call adopt_contract() 70894501b61Sskamm * to take ownership. 70994501b61Sskamm * 71094501b61Sskamm * Returns 0 on success; 71194501b61Sskamm * ENAMETOOLONG if unable to generate filename from fmri (including 71294501b61Sskamm * the inability to create the directory for the generated filename) and 71394501b61Sskamm * ENXIO if a failure accessing the file 71494501b61Sskamm * ENOMEM if there was a memory allocation failure 71594501b61Sskamm * ENOENT if the instance, its restarter property group, or its 71694501b61Sskamm * contract property don't exist 71794501b61Sskamm * EIO if invalid data read from the file 71894501b61Sskamm */ 71994501b61Sskamm int 72094501b61Sskamm iterate_repository_contracts(instance_t *inst, int sig) 72194501b61Sskamm { 72294501b61Sskamm int ret = 0; 72394501b61Sskamm FILE *fp; 72494501b61Sskamm rep_val_t *spval = NULL; /* Contains a start_pid */ 72594501b61Sskamm uint64_t tval; /* temp val holder */ 72694501b61Sskamm uu_list_t *uup = NULL; 72794501b61Sskamm int fscanf_ret; 72894501b61Sskamm int fopen_retry_cnt = 2; 72994501b61Sskamm 73094501b61Sskamm if (sig != 0) { 73194501b61Sskamm /* 73294501b61Sskamm * Send a signal to all in the contract; ESRCH just 73394501b61Sskamm * means they all exited before we could kill them 73494501b61Sskamm */ 73594501b61Sskamm for (spval = uu_list_first(inst->start_ctids); spval != NULL; 73694501b61Sskamm spval = uu_list_next(inst->start_ctids, spval)) { 73794501b61Sskamm if (sigsend(P_CTID, (ctid_t)spval->val, sig) == -1 && 73894501b61Sskamm errno != ESRCH) { 73994501b61Sskamm warn_msg(gettext("Unable to signal all " 74094501b61Sskamm "contract members of instance %s: %s"), 74194501b61Sskamm inst->fmri, strerror(errno)); 74294501b61Sskamm } 74394501b61Sskamm } 74494501b61Sskamm return (0); 74594501b61Sskamm } 74694501b61Sskamm 74794501b61Sskamm /* 74894501b61Sskamm * sig == 0 case. 74994501b61Sskamm * Attempt to adopt the contract for each ctid. 75094501b61Sskamm */ 75194501b61Sskamm if (gen_filenms_from_fmri(inst->fmri, "ctid", genfmri_filename, 75294501b61Sskamm NULL) != 0) { 75394501b61Sskamm /* Failure either from fmri too long or mkdir failure */ 75494501b61Sskamm return (ENAMETOOLONG); 75594501b61Sskamm } 75694501b61Sskamm 75794501b61Sskamm retry_fopen: 75894501b61Sskamm /* It's ok if no file, there are no ctids to adopt */ 75994501b61Sskamm if ((fp = fopen(genfmri_filename, "r")) == NULL) { 76094501b61Sskamm if ((errno == EINTR) && (fopen_retry_cnt > 0)) { 76194501b61Sskamm fopen_retry_cnt--; 76294501b61Sskamm goto retry_fopen; 76394501b61Sskamm } 76494501b61Sskamm return (0); 76594501b61Sskamm } 76694501b61Sskamm 76794501b61Sskamm /* 76894501b61Sskamm * Read ctids from file into 2 lists: 76994501b61Sskamm * - temporary list to be traversed (uup) 77094501b61Sskamm * - cached list that can be modified if adoption of 77194501b61Sskamm * contract fails (inst->start_ctids). 77294501b61Sskamm * Always treat ctids as long longs. 77394501b61Sskamm */ 77494501b61Sskamm uup = create_rep_val_list(); 77594501b61Sskamm /* fscanf may not set errno, so clear it first */ 77694501b61Sskamm errno = 0; 77794501b61Sskamm while ((fscanf_ret = fscanf(fp, "%llu", &tval)) == 1) { 77894501b61Sskamm /* If tval isn't a valid ctid, then fail. */ 77994501b61Sskamm if (tval == 0) { 78094501b61Sskamm (void) fclose(fp); 78194501b61Sskamm ret = EIO; 78294501b61Sskamm goto out; 78394501b61Sskamm } 78494501b61Sskamm if ((add_rep_val(uup, tval) == -1) || 78594501b61Sskamm (add_rep_val(inst->start_ctids, tval) == -1)) { 78694501b61Sskamm (void) fclose(fp); 78794501b61Sskamm ret = ENOMEM; 78894501b61Sskamm goto out; 78994501b61Sskamm } 79094501b61Sskamm errno = 0; 79194501b61Sskamm } 79294501b61Sskamm /* EOF is not a failure when no errno */ 79394501b61Sskamm if ((fscanf_ret != EOF) || (errno != 0)) { 79494501b61Sskamm ret = EIO; 79594501b61Sskamm goto out; 79694501b61Sskamm } 79794501b61Sskamm 79894501b61Sskamm if (fclose(fp) != 0) { 79994501b61Sskamm ret = ENXIO; 80094501b61Sskamm goto out; 80194501b61Sskamm } 80294501b61Sskamm 80394501b61Sskamm for (spval = uu_list_first(uup); spval != NULL; 80494501b61Sskamm spval = uu_list_next(uup, spval)) { 80594501b61Sskamm /* Try to adopt the contract */ 80694501b61Sskamm if (adopt_contract((ctid_t)spval->val, 80794501b61Sskamm inst->fmri) != 0) { 80894501b61Sskamm /* 80994501b61Sskamm * Adoption failed. No reason to think it'll 81094501b61Sskamm * work later, so remove the id from our list 81194501b61Sskamm * in the instance. 81294501b61Sskamm */ 81394501b61Sskamm remove_rep_val(inst->start_ctids, spval->val); 81494501b61Sskamm } 81594501b61Sskamm } 81694501b61Sskamm out: 81794501b61Sskamm if (uup) { 81894501b61Sskamm empty_rep_val_list(uup); 81994501b61Sskamm destroy_rep_val_list(uup); 82094501b61Sskamm } 82194501b61Sskamm 82294501b61Sskamm if (ret != 0) 82394501b61Sskamm empty_rep_val_list(inst->start_ctids); 82494501b61Sskamm 8257c478bd9Sstevel@tonic-gate return (ret); 8267c478bd9Sstevel@tonic-gate } 827