10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*3175Sskamm * Common Development and Distribution License (the "License"). 6*3175Sskamm * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 220Sstevel@tonic-gate * 23*3175Sskamm * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate /* 300Sstevel@tonic-gate * This file contains routines to manipulate lists of repository values that 310Sstevel@tonic-gate * are used to store process ids and the internal state. There are routines 320Sstevel@tonic-gate * to read/write the lists from/to the repository and routines to modify or 330Sstevel@tonic-gate * inspect the lists. It also contains routines that deal with the 340Sstevel@tonic-gate * repository side of contract ids. 350Sstevel@tonic-gate */ 360Sstevel@tonic-gate 370Sstevel@tonic-gate #include <errno.h> 380Sstevel@tonic-gate #include <stdlib.h> 390Sstevel@tonic-gate #include <libintl.h> 400Sstevel@tonic-gate #include <unistd.h> 410Sstevel@tonic-gate #include <string.h> 420Sstevel@tonic-gate #include <signal.h> 43*3175Sskamm #include <sys/param.h> 44*3175Sskamm #include <sys/types.h> 45*3175Sskamm #include <sys/stat.h> 46*3175Sskamm #include <libscf_priv.h> 470Sstevel@tonic-gate #include "inetd_impl.h" 480Sstevel@tonic-gate 490Sstevel@tonic-gate /* 500Sstevel@tonic-gate * Number of consecutive repository bind retries performed by bind_to_rep() 510Sstevel@tonic-gate * before failing. 520Sstevel@tonic-gate */ 530Sstevel@tonic-gate #define BIND_TO_REP_RETRIES 10 540Sstevel@tonic-gate 550Sstevel@tonic-gate /* Name of property group where inetd's state for a service is stored. */ 560Sstevel@tonic-gate #define PG_NAME_INSTANCE_STATE (const char *) "inetd_state" 570Sstevel@tonic-gate 580Sstevel@tonic-gate /* uu_list repval list pool */ 590Sstevel@tonic-gate static uu_list_pool_t *rep_val_pool = NULL; 600Sstevel@tonic-gate 610Sstevel@tonic-gate /* 620Sstevel@tonic-gate * Repository object pointers that get set-up in repval_init() and closed down 630Sstevel@tonic-gate * in repval_fini(). They're used in _retrieve_rep_vals(), _store_rep_vals(), 640Sstevel@tonic-gate * add_remove_contract_norebind(), and adopt_repository_contracts(). They're 650Sstevel@tonic-gate * global so they can be initialized once on inetd startup, and re-used 660Sstevel@tonic-gate * there-after in the referenced functions. 670Sstevel@tonic-gate */ 680Sstevel@tonic-gate static scf_handle_t *rep_handle = NULL; 690Sstevel@tonic-gate static scf_propertygroup_t *pg = NULL; 700Sstevel@tonic-gate static scf_instance_t *inst = NULL; 710Sstevel@tonic-gate static scf_transaction_t *trans = NULL; 720Sstevel@tonic-gate static scf_transaction_entry_t *entry = NULL; 730Sstevel@tonic-gate static scf_property_t *prop = NULL; 740Sstevel@tonic-gate 750Sstevel@tonic-gate /* 76*3175Sskamm * Pathname storage for paths generated from the fmri. 77*3175Sskamm * Used when updating the ctid and (start) pid files for an inetd service. 78*3175Sskamm */ 79*3175Sskamm static char genfmri_filename[MAXPATHLEN] = ""; 80*3175Sskamm static char genfmri_temp_filename[MAXPATHLEN] = ""; 81*3175Sskamm 82*3175Sskamm /* 830Sstevel@tonic-gate * Try and make the given handle bind be bound to the repository. If 840Sstevel@tonic-gate * it's already bound, or we succeed a new bind return 0; else return 850Sstevel@tonic-gate * -1 on failure, with the SCF error set to one of the following: 860Sstevel@tonic-gate * SCF_ERROR_NO_SERVER 870Sstevel@tonic-gate * SCF_ERROR_NO_RESOURCES 880Sstevel@tonic-gate */ 890Sstevel@tonic-gate int 900Sstevel@tonic-gate make_handle_bound(scf_handle_t *hdl) 910Sstevel@tonic-gate { 920Sstevel@tonic-gate uint_t retries; 930Sstevel@tonic-gate 940Sstevel@tonic-gate for (retries = 0; retries <= BIND_TO_REP_RETRIES; retries++) { 950Sstevel@tonic-gate if ((scf_handle_bind(hdl) == 0) || 960Sstevel@tonic-gate (scf_error() == SCF_ERROR_IN_USE)) 970Sstevel@tonic-gate return (0); 980Sstevel@tonic-gate 990Sstevel@tonic-gate assert(scf_error() != SCF_ERROR_INVALID_ARGUMENT); 1000Sstevel@tonic-gate } 1010Sstevel@tonic-gate 1020Sstevel@tonic-gate return (-1); 1030Sstevel@tonic-gate } 1040Sstevel@tonic-gate 1050Sstevel@tonic-gate int 1060Sstevel@tonic-gate repval_init(void) 1070Sstevel@tonic-gate { 1080Sstevel@tonic-gate debug_msg("Entering repval_init"); 1090Sstevel@tonic-gate 1100Sstevel@tonic-gate /* 1110Sstevel@tonic-gate * Create the repval list pool. 1120Sstevel@tonic-gate */ 1130Sstevel@tonic-gate rep_val_pool = uu_list_pool_create("rep_val_pool", sizeof (rep_val_t), 1140Sstevel@tonic-gate offsetof(rep_val_t, link), NULL, UU_LIST_POOL_DEBUG); 1150Sstevel@tonic-gate if (rep_val_pool == NULL) { 1160Sstevel@tonic-gate error_msg("%s: %s", gettext("Failed to create rep_val pool"), 1170Sstevel@tonic-gate uu_strerror(uu_error())); 1180Sstevel@tonic-gate return (-1); 1190Sstevel@tonic-gate } 1200Sstevel@tonic-gate 1210Sstevel@tonic-gate /* 1220Sstevel@tonic-gate * Create and bind a repository handle, and create all repository 1230Sstevel@tonic-gate * objects that we'll use later that are associated with it. On any 1240Sstevel@tonic-gate * errors we simply return -1 and let repval_fini() clean-up after 1250Sstevel@tonic-gate * us. 1260Sstevel@tonic-gate */ 1270Sstevel@tonic-gate if ((rep_handle = scf_handle_create(SCF_VERSION)) == NULL) { 1280Sstevel@tonic-gate error_msg("%s: %s", 1290Sstevel@tonic-gate gettext("Failed to create repository handle"), 1300Sstevel@tonic-gate scf_strerror(scf_error())); 1310Sstevel@tonic-gate goto cleanup; 1320Sstevel@tonic-gate } else if (make_handle_bound(rep_handle) == -1) { 1330Sstevel@tonic-gate goto cleanup; 1340Sstevel@tonic-gate } else if (((pg = scf_pg_create(rep_handle)) == NULL) || 1350Sstevel@tonic-gate ((inst = scf_instance_create(rep_handle)) == NULL) || 1360Sstevel@tonic-gate ((trans = scf_transaction_create(rep_handle)) == NULL) || 1370Sstevel@tonic-gate ((entry = scf_entry_create(rep_handle)) == NULL) || 1380Sstevel@tonic-gate ((prop = scf_property_create(rep_handle)) == NULL)) { 1390Sstevel@tonic-gate error_msg("%s: %s", 1400Sstevel@tonic-gate gettext("Failed to create repository object"), 1410Sstevel@tonic-gate scf_strerror(scf_error())); 1420Sstevel@tonic-gate goto cleanup; 1430Sstevel@tonic-gate } 1440Sstevel@tonic-gate 1450Sstevel@tonic-gate return (0); 1460Sstevel@tonic-gate cleanup: 1470Sstevel@tonic-gate repval_fini(); 1480Sstevel@tonic-gate return (-1); 1490Sstevel@tonic-gate } 1500Sstevel@tonic-gate 1510Sstevel@tonic-gate void 1520Sstevel@tonic-gate repval_fini(void) 1530Sstevel@tonic-gate { 1540Sstevel@tonic-gate debug_msg("Entering repval_fini"); 1550Sstevel@tonic-gate 1560Sstevel@tonic-gate if (rep_handle != NULL) { 1570Sstevel@tonic-gate /* 1580Sstevel@tonic-gate * We unbind from the repository before we free the repository 1590Sstevel@tonic-gate * objects for efficiency reasons. 1600Sstevel@tonic-gate */ 1610Sstevel@tonic-gate (void) scf_handle_unbind(rep_handle); 1620Sstevel@tonic-gate 1630Sstevel@tonic-gate scf_pg_destroy(pg); 1640Sstevel@tonic-gate pg = NULL; 1650Sstevel@tonic-gate scf_instance_destroy(inst); 1660Sstevel@tonic-gate inst = NULL; 1670Sstevel@tonic-gate scf_transaction_destroy(trans); 1680Sstevel@tonic-gate trans = NULL; 1690Sstevel@tonic-gate scf_entry_destroy(entry); 1700Sstevel@tonic-gate entry = NULL; 1710Sstevel@tonic-gate scf_property_destroy(prop); 1720Sstevel@tonic-gate prop = NULL; 1730Sstevel@tonic-gate 1740Sstevel@tonic-gate scf_handle_destroy(rep_handle); 1750Sstevel@tonic-gate rep_handle = NULL; 1760Sstevel@tonic-gate } 1770Sstevel@tonic-gate 1780Sstevel@tonic-gate if (rep_val_pool != NULL) { 1790Sstevel@tonic-gate uu_list_pool_destroy(rep_val_pool); 1800Sstevel@tonic-gate rep_val_pool = NULL; 1810Sstevel@tonic-gate } 1820Sstevel@tonic-gate } 1830Sstevel@tonic-gate 1840Sstevel@tonic-gate uu_list_t * 1850Sstevel@tonic-gate create_rep_val_list(void) 1860Sstevel@tonic-gate { 1870Sstevel@tonic-gate uu_list_t *ret; 1880Sstevel@tonic-gate 1890Sstevel@tonic-gate debug_msg("Entering create_rep_val_list"); 1900Sstevel@tonic-gate 1910Sstevel@tonic-gate if ((ret = uu_list_create(rep_val_pool, NULL, 0)) == NULL) 1920Sstevel@tonic-gate assert(uu_error() == UU_ERROR_NO_MEMORY); 1930Sstevel@tonic-gate 1940Sstevel@tonic-gate return (ret); 1950Sstevel@tonic-gate } 1960Sstevel@tonic-gate 1970Sstevel@tonic-gate void 1980Sstevel@tonic-gate destroy_rep_val_list(uu_list_t *list) 1990Sstevel@tonic-gate { 2000Sstevel@tonic-gate debug_msg("Entering destroy_rep_val_list"); 2010Sstevel@tonic-gate 2020Sstevel@tonic-gate if (list != NULL) { 2030Sstevel@tonic-gate empty_rep_val_list(list); 2040Sstevel@tonic-gate uu_list_destroy(list); 2050Sstevel@tonic-gate } 2060Sstevel@tonic-gate } 2070Sstevel@tonic-gate 2080Sstevel@tonic-gate rep_val_t * 2090Sstevel@tonic-gate find_rep_val(uu_list_t *list, int64_t val) 2100Sstevel@tonic-gate { 2110Sstevel@tonic-gate rep_val_t *rv; 2120Sstevel@tonic-gate 2130Sstevel@tonic-gate debug_msg("Entering find_rep_val: val: %lld", val); 2140Sstevel@tonic-gate 2150Sstevel@tonic-gate for (rv = uu_list_first(list); rv != NULL; 2160Sstevel@tonic-gate rv = uu_list_next(list, rv)) { 2170Sstevel@tonic-gate if (rv->val == val) 2180Sstevel@tonic-gate break; 2190Sstevel@tonic-gate } 2200Sstevel@tonic-gate return (rv); 2210Sstevel@tonic-gate } 2220Sstevel@tonic-gate 2230Sstevel@tonic-gate int 2240Sstevel@tonic-gate add_rep_val(uu_list_t *list, int64_t val) 2250Sstevel@tonic-gate { 2260Sstevel@tonic-gate rep_val_t *rv; 2270Sstevel@tonic-gate 2280Sstevel@tonic-gate debug_msg("Entering add_rep_val: val: %lld", val); 2290Sstevel@tonic-gate 2300Sstevel@tonic-gate if ((rv = malloc(sizeof (rep_val_t))) == NULL) 2310Sstevel@tonic-gate return (-1); 2320Sstevel@tonic-gate 2330Sstevel@tonic-gate uu_list_node_init(rv, &rv->link, rep_val_pool); 2340Sstevel@tonic-gate rv->val = val; 2350Sstevel@tonic-gate rv->scf_val = NULL; 2360Sstevel@tonic-gate (void) uu_list_insert_after(list, NULL, rv); 2370Sstevel@tonic-gate 2380Sstevel@tonic-gate return (0); 2390Sstevel@tonic-gate } 2400Sstevel@tonic-gate 2410Sstevel@tonic-gate void 2420Sstevel@tonic-gate remove_rep_val(uu_list_t *list, int64_t val) 2430Sstevel@tonic-gate { 2440Sstevel@tonic-gate rep_val_t *rv; 2450Sstevel@tonic-gate 2460Sstevel@tonic-gate debug_msg("Entering remove_rep_val: val: %lld", val); 2470Sstevel@tonic-gate 2480Sstevel@tonic-gate if ((rv = find_rep_val(list, val)) != NULL) { 2490Sstevel@tonic-gate uu_list_remove(list, rv); 2500Sstevel@tonic-gate assert(rv->scf_val == NULL); 2510Sstevel@tonic-gate free(rv); 2520Sstevel@tonic-gate } 2530Sstevel@tonic-gate } 2540Sstevel@tonic-gate 2550Sstevel@tonic-gate void 2560Sstevel@tonic-gate empty_rep_val_list(uu_list_t *list) 2570Sstevel@tonic-gate { 2580Sstevel@tonic-gate void *cookie = NULL; 2590Sstevel@tonic-gate rep_val_t *rv; 2600Sstevel@tonic-gate 2610Sstevel@tonic-gate debug_msg("Entering empty_rep_val_list"); 2620Sstevel@tonic-gate 2630Sstevel@tonic-gate while ((rv = uu_list_teardown(list, &cookie)) != NULL) { 2640Sstevel@tonic-gate if (rv->scf_val != NULL) 2650Sstevel@tonic-gate scf_value_destroy(rv->scf_val); 2660Sstevel@tonic-gate free(rv); 2670Sstevel@tonic-gate } 2680Sstevel@tonic-gate } 2690Sstevel@tonic-gate 2700Sstevel@tonic-gate int64_t 2710Sstevel@tonic-gate get_single_rep_val(uu_list_t *list) 2720Sstevel@tonic-gate { 2730Sstevel@tonic-gate rep_val_t *rv = uu_list_first(list); 2740Sstevel@tonic-gate 2750Sstevel@tonic-gate debug_msg("Entering get_single_rep_val"); 2760Sstevel@tonic-gate 2770Sstevel@tonic-gate assert(rv != NULL); 2780Sstevel@tonic-gate return (rv->val); 2790Sstevel@tonic-gate } 2800Sstevel@tonic-gate 2810Sstevel@tonic-gate int 2820Sstevel@tonic-gate set_single_rep_val(uu_list_t *list, int64_t val) 2830Sstevel@tonic-gate { 2840Sstevel@tonic-gate rep_val_t *rv = uu_list_first(list); 2850Sstevel@tonic-gate 2860Sstevel@tonic-gate debug_msg("Entering set_single_rep_val"); 2870Sstevel@tonic-gate 2880Sstevel@tonic-gate if (rv == NULL) { 2890Sstevel@tonic-gate if (add_rep_val(list, val) == -1) 2900Sstevel@tonic-gate return (-1); 2910Sstevel@tonic-gate } else { 2920Sstevel@tonic-gate rv->val = val; 2930Sstevel@tonic-gate } 2940Sstevel@tonic-gate 2950Sstevel@tonic-gate return (0); 2960Sstevel@tonic-gate } 2970Sstevel@tonic-gate 2980Sstevel@tonic-gate /* 2990Sstevel@tonic-gate * Partner to add_tr_entry_values. This function frees the scf_values created 3000Sstevel@tonic-gate * in add_tr_entry_values() in the list 'vals'. 3010Sstevel@tonic-gate */ 3020Sstevel@tonic-gate static void 3030Sstevel@tonic-gate remove_tr_entry_values(uu_list_t *vals) 3040Sstevel@tonic-gate { 3050Sstevel@tonic-gate rep_val_t *rval; 3060Sstevel@tonic-gate 3070Sstevel@tonic-gate debug_msg("Entering remove_tr_entry_values"); 3080Sstevel@tonic-gate 3090Sstevel@tonic-gate for (rval = uu_list_first(vals); rval != NULL; 3100Sstevel@tonic-gate rval = uu_list_next(vals, rval)) { 3110Sstevel@tonic-gate if (rval->scf_val != NULL) { 3120Sstevel@tonic-gate scf_value_destroy(rval->scf_val); 3130Sstevel@tonic-gate rval->scf_val = NULL; 3140Sstevel@tonic-gate } 3150Sstevel@tonic-gate } 3160Sstevel@tonic-gate } 3170Sstevel@tonic-gate 3180Sstevel@tonic-gate /* 3190Sstevel@tonic-gate * This function creates and associates with transaction entry 'entry' an 3200Sstevel@tonic-gate * scf value for each value in 'vals'. The pointers to the scf values 3210Sstevel@tonic-gate * are stored in the list for later cleanup by remove_tr_entry_values. 3220Sstevel@tonic-gate * Returns 0 on success, else -1 on error with scf_error() set to: 3230Sstevel@tonic-gate * SCF_ERROR_NO_MEMORY if memory allocation failed. 3240Sstevel@tonic-gate * SCF_ERROR_CONNECTION_BROKEN if the connection to the repository was broken. 3250Sstevel@tonic-gate */ 3260Sstevel@tonic-gate static int 3270Sstevel@tonic-gate add_tr_entry_values(scf_handle_t *hdl, scf_transaction_entry_t *entry, 3280Sstevel@tonic-gate uu_list_t *vals) 3290Sstevel@tonic-gate { 3300Sstevel@tonic-gate rep_val_t *rval; 3310Sstevel@tonic-gate 3320Sstevel@tonic-gate debug_msg("Entering add_tr_entry_values"); 3330Sstevel@tonic-gate 3340Sstevel@tonic-gate for (rval = uu_list_first(vals); rval != NULL; 3350Sstevel@tonic-gate rval = uu_list_next(vals, rval)) { 3360Sstevel@tonic-gate 3370Sstevel@tonic-gate assert(rval->scf_val == NULL); 3380Sstevel@tonic-gate if ((rval->scf_val = scf_value_create(hdl)) == NULL) { 3390Sstevel@tonic-gate remove_tr_entry_values(vals); 3400Sstevel@tonic-gate return (-1); 3410Sstevel@tonic-gate } 3420Sstevel@tonic-gate 3430Sstevel@tonic-gate scf_value_set_integer(rval->scf_val, rval->val); 3440Sstevel@tonic-gate 3450Sstevel@tonic-gate if (scf_entry_add_value(entry, rval->scf_val) < 0) { 3460Sstevel@tonic-gate remove_tr_entry_values(vals); 3470Sstevel@tonic-gate return (-1); 3480Sstevel@tonic-gate } 3490Sstevel@tonic-gate } 3500Sstevel@tonic-gate 3510Sstevel@tonic-gate return (0); 3520Sstevel@tonic-gate } 3530Sstevel@tonic-gate 3540Sstevel@tonic-gate /* 3550Sstevel@tonic-gate * Stores the values contained in the list 'vals' into the property 'prop_name' 3560Sstevel@tonic-gate * of the instance with fmri 'inst_fmri', within the instance's instance 3570Sstevel@tonic-gate * state property group. 3580Sstevel@tonic-gate * 3590Sstevel@tonic-gate * Returns 0 on success, else one of the following on failure: 3600Sstevel@tonic-gate * SCF_ERROR_NO_MEMORY if memory allocation failed. 3610Sstevel@tonic-gate * SCF_ERROR_NO_RESOURCES if the server doesn't have required resources. 3620Sstevel@tonic-gate * SCF_ERROR_VERSION_MISMATCH if program compiled against a newer libscf 3630Sstevel@tonic-gate * than on system. 3640Sstevel@tonic-gate * SCF_ERROR_PERMISSION_DENIED if insufficient privileges to modify pg. 3650Sstevel@tonic-gate * SCF_ERROR_BACKEND_ACCESS if the repository back-end refused the pg modify. 3660Sstevel@tonic-gate * SCF_ERROR_CONNECTION_BROKEN if the connection to the repository was broken. 3670Sstevel@tonic-gate */ 3680Sstevel@tonic-gate static scf_error_t 3690Sstevel@tonic-gate _store_rep_vals(uu_list_t *vals, const char *inst_fmri, const char *prop_name) 3700Sstevel@tonic-gate { 3710Sstevel@tonic-gate int cret; 3720Sstevel@tonic-gate int ret; 3730Sstevel@tonic-gate 3740Sstevel@tonic-gate debug_msg("Entering _store_rep_vals: fmri: %s, prop: %s", inst_fmri, 3750Sstevel@tonic-gate prop_name); 3760Sstevel@tonic-gate 3770Sstevel@tonic-gate if (scf_handle_decode_fmri(rep_handle, inst_fmri, NULL, NULL, inst, 3780Sstevel@tonic-gate NULL, NULL, SCF_DECODE_FMRI_EXACT) == -1) 3790Sstevel@tonic-gate return (scf_error()); 3800Sstevel@tonic-gate 3810Sstevel@tonic-gate /* 3820Sstevel@tonic-gate * Fetch the instance state pg, and if it doesn't exist try and 3830Sstevel@tonic-gate * create it. 3840Sstevel@tonic-gate */ 3850Sstevel@tonic-gate if (scf_instance_get_pg(inst, PG_NAME_INSTANCE_STATE, pg) < 0) { 3860Sstevel@tonic-gate if (scf_error() != SCF_ERROR_NOT_FOUND) 3870Sstevel@tonic-gate return (scf_error()); 3880Sstevel@tonic-gate if (scf_instance_add_pg(inst, PG_NAME_INSTANCE_STATE, 3890Sstevel@tonic-gate SCF_GROUP_FRAMEWORK, SCF_PG_FLAG_NONPERSISTENT, pg) < 0) 3900Sstevel@tonic-gate return (scf_error()); 3910Sstevel@tonic-gate } 3920Sstevel@tonic-gate 3930Sstevel@tonic-gate /* 3940Sstevel@tonic-gate * Perform a transaction to write the values to the requested property. 3950Sstevel@tonic-gate * If someone got there before us, loop and retry. 3960Sstevel@tonic-gate */ 3970Sstevel@tonic-gate do { 3980Sstevel@tonic-gate if (scf_transaction_start(trans, pg) < 0) 3990Sstevel@tonic-gate return (scf_error()); 4000Sstevel@tonic-gate 4010Sstevel@tonic-gate if ((scf_transaction_property_new(trans, entry, 4020Sstevel@tonic-gate prop_name, SCF_TYPE_INTEGER) < 0) && 4030Sstevel@tonic-gate (scf_transaction_property_change_type(trans, entry, 4040Sstevel@tonic-gate prop_name, SCF_TYPE_INTEGER) < 0)) { 4050Sstevel@tonic-gate ret = scf_error(); 4060Sstevel@tonic-gate goto cleanup; 4070Sstevel@tonic-gate } 4080Sstevel@tonic-gate 4090Sstevel@tonic-gate if (add_tr_entry_values(rep_handle, entry, vals) < 0) { 4100Sstevel@tonic-gate ret = scf_error(); 4110Sstevel@tonic-gate goto cleanup; 4120Sstevel@tonic-gate } 4130Sstevel@tonic-gate 4140Sstevel@tonic-gate if ((cret = scf_transaction_commit(trans)) < 0) { 4150Sstevel@tonic-gate ret = scf_error(); 4160Sstevel@tonic-gate goto cleanup; 4170Sstevel@tonic-gate } else if (cret == 0) { 4180Sstevel@tonic-gate scf_transaction_reset(trans); 4190Sstevel@tonic-gate scf_entry_reset(entry); 4200Sstevel@tonic-gate remove_tr_entry_values(vals); 4210Sstevel@tonic-gate if (scf_pg_update(pg) < 0) { 4220Sstevel@tonic-gate ret = scf_error(); 4230Sstevel@tonic-gate goto cleanup; 4240Sstevel@tonic-gate } 4250Sstevel@tonic-gate } 4260Sstevel@tonic-gate } while (cret == 0); 4270Sstevel@tonic-gate 4280Sstevel@tonic-gate ret = 0; 4290Sstevel@tonic-gate cleanup: 4300Sstevel@tonic-gate scf_transaction_reset(trans); 4310Sstevel@tonic-gate scf_entry_reset(entry); 4320Sstevel@tonic-gate remove_tr_entry_values(vals); 4330Sstevel@tonic-gate return (ret); 4340Sstevel@tonic-gate } 4350Sstevel@tonic-gate 4360Sstevel@tonic-gate /* 4370Sstevel@tonic-gate * Retrieves the repository values of property 'prop_name', of the instance 4380Sstevel@tonic-gate * with fmri 'fmri', from within the instance's instance state property 4390Sstevel@tonic-gate * group and adds them to the value list 'list'. 4400Sstevel@tonic-gate * 4410Sstevel@tonic-gate * Returns 0 on success, else one of the following values on error: 4420Sstevel@tonic-gate * SCF_ERROR_NOT_FOUND if the property doesn't exist. 4430Sstevel@tonic-gate * SCF_ERROR_NO_MEMORY if memory allocation failed. 4440Sstevel@tonic-gate * SCF_ERROR_CONNECTION_BROKEN if the connection to the repository was broken. 4450Sstevel@tonic-gate * SCF_ERROR_TYPE_MISMATCH if the property was of an unexpected type. 4460Sstevel@tonic-gate * 4470Sstevel@tonic-gate */ 4480Sstevel@tonic-gate static scf_error_t 4490Sstevel@tonic-gate _retrieve_rep_vals(uu_list_t *list, const char *fmri, const char *prop_name) 4500Sstevel@tonic-gate { 4510Sstevel@tonic-gate scf_simple_prop_t *sp; 4520Sstevel@tonic-gate int64_t *ip; 4530Sstevel@tonic-gate 4540Sstevel@tonic-gate debug_msg("Entering _retrieve_rep_vals: fmri: %s, prop: %s", fmri, 4550Sstevel@tonic-gate prop_name); 4560Sstevel@tonic-gate 4570Sstevel@tonic-gate if ((sp = scf_simple_prop_get(rep_handle, fmri, PG_NAME_INSTANCE_STATE, 4580Sstevel@tonic-gate prop_name)) == NULL) 4590Sstevel@tonic-gate return (scf_error()); 4600Sstevel@tonic-gate 4610Sstevel@tonic-gate while ((ip = scf_simple_prop_next_integer(sp)) != NULL) { 4620Sstevel@tonic-gate if (add_rep_val(list, *ip) == -1) { 4630Sstevel@tonic-gate empty_rep_val_list(list); 4640Sstevel@tonic-gate scf_simple_prop_free(sp); 4650Sstevel@tonic-gate return (SCF_ERROR_NO_MEMORY); 4660Sstevel@tonic-gate } 4670Sstevel@tonic-gate } 4680Sstevel@tonic-gate if (scf_error() != SCF_ERROR_NONE) { 4690Sstevel@tonic-gate assert(scf_error() == SCF_ERROR_TYPE_MISMATCH); 4700Sstevel@tonic-gate empty_rep_val_list(list); 4710Sstevel@tonic-gate scf_simple_prop_free(sp); 4720Sstevel@tonic-gate return (scf_error()); 4730Sstevel@tonic-gate } 4740Sstevel@tonic-gate 4750Sstevel@tonic-gate scf_simple_prop_free(sp); 4760Sstevel@tonic-gate return (0); 4770Sstevel@tonic-gate } 4780Sstevel@tonic-gate 4790Sstevel@tonic-gate /* 480*3175Sskamm * Writes the repository values in the vals list to 481*3175Sskamm * a file that is generated based on the passed in fmri and name. 482*3175Sskamm * Returns 0 on success, 483*3175Sskamm * ENAMETOOLONG if unable to generate filename from fmri (including 484*3175Sskamm * the inability to create the directory for the generated filename) and 485*3175Sskamm * ENOENT on all other failures. 486*3175Sskamm */ 487*3175Sskamm static int 488*3175Sskamm repvals_to_file(const char *fmri, const char *name, uu_list_t *vals) 489*3175Sskamm { 490*3175Sskamm int tfd; 491*3175Sskamm FILE *tfp; /* temp fp */ 492*3175Sskamm rep_val_t *spval; /* Contains a start_pid or ctid */ 493*3175Sskamm int ret = 0; 494*3175Sskamm 495*3175Sskamm debug_msg("Entering repvals_to_file, fmri:%s, name=%s\n", 496*3175Sskamm fmri, name); 497*3175Sskamm 498*3175Sskamm if (gen_filenms_from_fmri(fmri, name, genfmri_filename, 499*3175Sskamm genfmri_temp_filename) != 0) { 500*3175Sskamm /* Failure either from fmri too long or mkdir failure */ 501*3175Sskamm return (ENAMETOOLONG); 502*3175Sskamm } 503*3175Sskamm 504*3175Sskamm if ((tfd = mkstemp(genfmri_temp_filename)) == -1) { 505*3175Sskamm return (ENOENT); 506*3175Sskamm } 507*3175Sskamm 508*3175Sskamm if (fchmod(tfd, (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1) { 509*3175Sskamm (void) close(tfd); 510*3175Sskamm ret = ENOENT; 511*3175Sskamm goto unlink_out; 512*3175Sskamm } 513*3175Sskamm 514*3175Sskamm if ((tfp = fdopen(tfd, "w")) == NULL) { 515*3175Sskamm (void) close(tfd); 516*3175Sskamm ret = ENOENT; 517*3175Sskamm goto unlink_out; 518*3175Sskamm } 519*3175Sskamm 520*3175Sskamm for (spval = uu_list_first(vals); spval != NULL; 521*3175Sskamm spval = uu_list_next(vals, spval)) { 522*3175Sskamm if (fprintf(tfp, "%lld\n", spval->val) <= 0) { 523*3175Sskamm (void) fclose(tfp); 524*3175Sskamm ret = ENOENT; 525*3175Sskamm goto unlink_out; 526*3175Sskamm } 527*3175Sskamm } 528*3175Sskamm if (fclose(tfp) != 0) { 529*3175Sskamm ret = ENOENT; 530*3175Sskamm goto unlink_out; 531*3175Sskamm } 532*3175Sskamm if (rename(genfmri_temp_filename, genfmri_filename) != 0) { 533*3175Sskamm ret = ENOENT; 534*3175Sskamm goto unlink_out; 535*3175Sskamm } 536*3175Sskamm return (0); 537*3175Sskamm 538*3175Sskamm unlink_out: 539*3175Sskamm if (unlink(genfmri_temp_filename) != 0) { 540*3175Sskamm warn_msg(gettext("Removal of temp file " 541*3175Sskamm "%s failed. Please remove manually."), 542*3175Sskamm genfmri_temp_filename); 543*3175Sskamm } 544*3175Sskamm return (ret); 545*3175Sskamm } 546*3175Sskamm 547*3175Sskamm /* 548*3175Sskamm * A routine that loops trying to read/write values until either success, 549*3175Sskamm * an error other than a broken repository connection or 5500Sstevel@tonic-gate * the number of retries reaches REP_OP_RETRIES. 551*3175Sskamm * This action is used to read/write the values: 552*3175Sskamm * reads/writes to a file for the START_PIDS property due to scalability 553*3175Sskamm * problems with libscf 554*3175Sskamm * reads/writes to the repository for all other properties. 5550Sstevel@tonic-gate * Returns 0 on success, else the error value from either _store_rep_vals or 556*3175Sskamm * _retrieve_rep_vals (based on whether 'store' was set or not), or one of the 557*3175Sskamm * following: 558*3175Sskamm * SCF_ERROR_NO_RESOURCES if the server doesn't have adequate resources 559*3175Sskamm * SCF_ERROR_NO_MEMORY if a memory allocation failure 5600Sstevel@tonic-gate * SCF_ERROR_NO_SERVER if the server isn't running. 561*3175Sskamm * SCF_ERROR_CONSTRAINT_VIOLATED if an error in dealing with the speedy files 5620Sstevel@tonic-gate */ 5630Sstevel@tonic-gate static scf_error_t 5640Sstevel@tonic-gate store_retrieve_rep_vals(uu_list_t *vals, const char *fmri, 5650Sstevel@tonic-gate const char *prop, boolean_t store) 5660Sstevel@tonic-gate { 567*3175Sskamm scf_error_t ret = 0; 5680Sstevel@tonic-gate uint_t retries; 569*3175Sskamm FILE *tfp; /* temp fp */ 570*3175Sskamm int64_t tval; /* temp val holder */ 571*3175Sskamm int fscanf_ret; 572*3175Sskamm int fopen_retry_cnt = 2; 5730Sstevel@tonic-gate 5740Sstevel@tonic-gate debug_msg("Entering store_retrieve_rep_vals, store: %d", store); 5750Sstevel@tonic-gate 576*3175Sskamm /* inetd specific action for START_PIDS property */ 577*3175Sskamm if (strcmp(prop, PR_NAME_START_PIDS) == 0) { 578*3175Sskamm /* 579*3175Sskamm * Storage performance of START_PIDS is important, 580*3175Sskamm * so each instance has its own file and all start_pids 581*3175Sskamm * in the list are written to a temp file and then 582*3175Sskamm * moved (renamed). 583*3175Sskamm */ 584*3175Sskamm if (store) { 585*3175Sskamm /* Write all values in list to file */ 586*3175Sskamm if (repvals_to_file(fmri, "pid", vals)) { 587*3175Sskamm return (SCF_ERROR_CONSTRAINT_VIOLATED); 588*3175Sskamm } 589*3175Sskamm } else { 590*3175Sskamm /* no temp name needed */ 591*3175Sskamm if (gen_filenms_from_fmri(fmri, "pid", genfmri_filename, 592*3175Sskamm NULL) != 0) 593*3175Sskamm return (SCF_ERROR_CONSTRAINT_VIOLATED); 5940Sstevel@tonic-gate 595*3175Sskamm retry_fopen: 596*3175Sskamm /* It's ok if no file, there are just no pids */ 597*3175Sskamm if ((tfp = fopen(genfmri_filename, "r")) == NULL) { 598*3175Sskamm if ((errno == EINTR) && (fopen_retry_cnt > 0)) { 599*3175Sskamm fopen_retry_cnt--; 600*3175Sskamm goto retry_fopen; 601*3175Sskamm } 602*3175Sskamm return (0); 603*3175Sskamm } 604*3175Sskamm /* fscanf may not set errno, so clear it first */ 605*3175Sskamm errno = 0; 606*3175Sskamm while ((fscanf_ret = fscanf(tfp, "%lld", &tval)) == 1) { 607*3175Sskamm /* If tval isn't a valid pid, then fail. */ 608*3175Sskamm if ((tval > MAXPID) || (tval <= 0)) { 609*3175Sskamm empty_rep_val_list(vals); 610*3175Sskamm return (SCF_ERROR_CONSTRAINT_VIOLATED); 611*3175Sskamm } 612*3175Sskamm if (add_rep_val(vals, tval) == -1) { 613*3175Sskamm empty_rep_val_list(vals); 614*3175Sskamm return (SCF_ERROR_NO_MEMORY); 615*3175Sskamm } 616*3175Sskamm errno = 0; 617*3175Sskamm } 618*3175Sskamm /* EOF is ok when no errno */ 619*3175Sskamm if ((fscanf_ret != EOF) || (errno != 0)) { 620*3175Sskamm empty_rep_val_list(vals); 621*3175Sskamm return (SCF_ERROR_CONSTRAINT_VIOLATED); 622*3175Sskamm } 623*3175Sskamm if (fclose(tfp) != 0) { 624*3175Sskamm /* for close failure just log a message */ 625*3175Sskamm warn_msg(gettext("Close of file %s failed."), 626*3175Sskamm genfmri_filename); 627*3175Sskamm } 628*3175Sskamm } 629*3175Sskamm } else { 630*3175Sskamm for (retries = 0; retries <= REP_OP_RETRIES; retries++) { 631*3175Sskamm if (make_handle_bound(rep_handle) == -1) { 632*3175Sskamm ret = scf_error(); 633*3175Sskamm break; 634*3175Sskamm } 6350Sstevel@tonic-gate 636*3175Sskamm if ((ret = (store ? _store_rep_vals(vals, fmri, prop) : 637*3175Sskamm _retrieve_rep_vals(vals, fmri, prop))) != 638*3175Sskamm SCF_ERROR_CONNECTION_BROKEN) 639*3175Sskamm break; 640*3175Sskamm 641*3175Sskamm (void) scf_handle_unbind(rep_handle); 642*3175Sskamm } 6430Sstevel@tonic-gate } 6440Sstevel@tonic-gate 645*3175Sskamm out: 6460Sstevel@tonic-gate return (ret); 6470Sstevel@tonic-gate } 6480Sstevel@tonic-gate 6490Sstevel@tonic-gate scf_error_t 6500Sstevel@tonic-gate store_rep_vals(uu_list_t *vals, const char *fmri, const char *prop) 6510Sstevel@tonic-gate { 6520Sstevel@tonic-gate return (store_retrieve_rep_vals(vals, fmri, prop, B_TRUE)); 6530Sstevel@tonic-gate } 6540Sstevel@tonic-gate 6550Sstevel@tonic-gate scf_error_t 6560Sstevel@tonic-gate retrieve_rep_vals(uu_list_t *vals, const char *fmri, const char *prop) 6570Sstevel@tonic-gate { 6580Sstevel@tonic-gate return (store_retrieve_rep_vals(vals, fmri, prop, B_FALSE)); 6590Sstevel@tonic-gate } 6600Sstevel@tonic-gate 6610Sstevel@tonic-gate /* 662*3175Sskamm * Adds/removes a contract id to/from the cached list kept in the instance. 663*3175Sskamm * Then the cached list is written to a file named "ctid" in a directory 664*3175Sskamm * based on the fmri. Cached list is written to a file due to scalability 665*3175Sskamm * problems in libscf. The file "ctid" is used when inetd is restarted 666*3175Sskamm * so that inetd can adopt the contracts that it had previously. 667*3175Sskamm * Returns: 668*3175Sskamm * 0 on success 669*3175Sskamm * ENAMETOOLONG if unable to generate filename from fmri (including 670*3175Sskamm * the inability to create the directory for the generated filename) 671*3175Sskamm * ENOENT - failure accessing file 672*3175Sskamm * ENOMEM - memory allocation failure 6730Sstevel@tonic-gate */ 6740Sstevel@tonic-gate int 675*3175Sskamm add_remove_contract(instance_t *inst, boolean_t add, ctid_t ctid) 6760Sstevel@tonic-gate { 677*3175Sskamm FILE *tfp; /* temp fp */ 6780Sstevel@tonic-gate int ret = 0; 679*3175Sskamm int repval_ret = 0; 680*3175Sskamm int fopen_retry_cnt = 2; 6810Sstevel@tonic-gate 682*3175Sskamm debug_msg("Entering add_remove_contract, add: %d\n", add); 6830Sstevel@tonic-gate 684*3175Sskamm /* 685*3175Sskamm * Storage performance of contract ids is important, 686*3175Sskamm * so each instance has its own file. An add of a 687*3175Sskamm * ctid will be appended to the ctid file. 688*3175Sskamm * The removal of a ctid will result in the remaining 689*3175Sskamm * ctids in the list being written to a temp file and then 690*3175Sskamm * moved (renamed). 691*3175Sskamm */ 692*3175Sskamm if (add) { 693*3175Sskamm if (gen_filenms_from_fmri(inst->fmri, "ctid", genfmri_filename, 694*3175Sskamm NULL) != 0) { 695*3175Sskamm /* Failure either from fmri too long or mkdir failure */ 696*3175Sskamm return (ENAMETOOLONG); 6970Sstevel@tonic-gate } 6980Sstevel@tonic-gate 699*3175Sskamm retry_fopen: 700*3175Sskamm if ((tfp = fopen(genfmri_filename, "a")) == NULL) { 701*3175Sskamm if ((errno == EINTR) && (fopen_retry_cnt > 0)) { 702*3175Sskamm fopen_retry_cnt--; 703*3175Sskamm goto retry_fopen; 704*3175Sskamm } 7050Sstevel@tonic-gate ret = ENOENT; 7060Sstevel@tonic-gate goto out; 707*3175Sskamm } 7080Sstevel@tonic-gate 709*3175Sskamm /* Always store ctids as long long */ 710*3175Sskamm if (fprintf(tfp, "%llu\n", (uint64_t)ctid) <= 0) { 711*3175Sskamm (void) fclose(tfp); 7120Sstevel@tonic-gate ret = ENOENT; 7130Sstevel@tonic-gate goto out; 714*3175Sskamm } 7150Sstevel@tonic-gate 716*3175Sskamm if (fclose(tfp) != 0) { 7170Sstevel@tonic-gate ret = ENOENT; 7180Sstevel@tonic-gate goto out; 7190Sstevel@tonic-gate } 7200Sstevel@tonic-gate 721*3175Sskamm if (add_rep_val(inst->start_ctids, ctid) != 0) { 722*3175Sskamm ret = ENOMEM; 723*3175Sskamm goto out; 724*3175Sskamm } 725*3175Sskamm } else { 726*3175Sskamm remove_rep_val(inst->start_ctids, ctid); 7270Sstevel@tonic-gate 728*3175Sskamm /* Write all values in list to file */ 729*3175Sskamm if ((repval_ret = repvals_to_file(inst->fmri, "ctid", 730*3175Sskamm inst->start_ctids)) != 0) { 731*3175Sskamm ret = repval_ret; 732*3175Sskamm goto out; 7330Sstevel@tonic-gate } 7340Sstevel@tonic-gate } 7350Sstevel@tonic-gate 7360Sstevel@tonic-gate out: 7370Sstevel@tonic-gate return (ret); 7380Sstevel@tonic-gate } 739*3175Sskamm 740*3175Sskamm /* 741*3175Sskamm * If sig !=0, iterate over all contracts in the cached list of contract 742*3175Sskamm * ids kept in the instance. Send each contract the specified signal. 743*3175Sskamm * If sig == 0, read in the contract ids that were last associated 744*3175Sskamm * with this instance (reload the cache) and call adopt_contract() 745*3175Sskamm * to take ownership. 746*3175Sskamm * 747*3175Sskamm * Returns 0 on success; 748*3175Sskamm * ENAMETOOLONG if unable to generate filename from fmri (including 749*3175Sskamm * the inability to create the directory for the generated filename) and 750*3175Sskamm * ENXIO if a failure accessing the file 751*3175Sskamm * ENOMEM if there was a memory allocation failure 752*3175Sskamm * ENOENT if the instance, its restarter property group, or its 753*3175Sskamm * contract property don't exist 754*3175Sskamm * EIO if invalid data read from the file 755*3175Sskamm */ 756*3175Sskamm int 757*3175Sskamm iterate_repository_contracts(instance_t *inst, int sig) 758*3175Sskamm { 759*3175Sskamm int ret = 0; 760*3175Sskamm FILE *fp; 761*3175Sskamm rep_val_t *spval = NULL; /* Contains a start_pid */ 762*3175Sskamm uint64_t tval; /* temp val holder */ 763*3175Sskamm uu_list_t *uup = NULL; 764*3175Sskamm int fscanf_ret; 765*3175Sskamm int fopen_retry_cnt = 2; 766*3175Sskamm 767*3175Sskamm debug_msg("Entering iterate_repository_contracts, sig: %d", sig); 768*3175Sskamm 769*3175Sskamm if (sig != 0) { 770*3175Sskamm /* 771*3175Sskamm * Send a signal to all in the contract; ESRCH just 772*3175Sskamm * means they all exited before we could kill them 773*3175Sskamm */ 774*3175Sskamm for (spval = uu_list_first(inst->start_ctids); spval != NULL; 775*3175Sskamm spval = uu_list_next(inst->start_ctids, spval)) { 776*3175Sskamm if (sigsend(P_CTID, (ctid_t)spval->val, sig) == -1 && 777*3175Sskamm errno != ESRCH) { 778*3175Sskamm warn_msg(gettext("Unable to signal all " 779*3175Sskamm "contract members of instance %s: %s"), 780*3175Sskamm inst->fmri, strerror(errno)); 781*3175Sskamm } 782*3175Sskamm } 783*3175Sskamm return (0); 784*3175Sskamm } 785*3175Sskamm 786*3175Sskamm /* 787*3175Sskamm * sig == 0 case. 788*3175Sskamm * Attempt to adopt the contract for each ctid. 789*3175Sskamm */ 790*3175Sskamm if (gen_filenms_from_fmri(inst->fmri, "ctid", genfmri_filename, 791*3175Sskamm NULL) != 0) { 792*3175Sskamm /* Failure either from fmri too long or mkdir failure */ 793*3175Sskamm return (ENAMETOOLONG); 794*3175Sskamm } 795*3175Sskamm 796*3175Sskamm retry_fopen: 797*3175Sskamm /* It's ok if no file, there are no ctids to adopt */ 798*3175Sskamm if ((fp = fopen(genfmri_filename, "r")) == NULL) { 799*3175Sskamm if ((errno == EINTR) && (fopen_retry_cnt > 0)) { 800*3175Sskamm fopen_retry_cnt--; 801*3175Sskamm goto retry_fopen; 802*3175Sskamm } 803*3175Sskamm return (0); 804*3175Sskamm } 805*3175Sskamm 806*3175Sskamm /* 807*3175Sskamm * Read ctids from file into 2 lists: 808*3175Sskamm * - temporary list to be traversed (uup) 809*3175Sskamm * - cached list that can be modified if adoption of 810*3175Sskamm * contract fails (inst->start_ctids). 811*3175Sskamm * Always treat ctids as long longs. 812*3175Sskamm */ 813*3175Sskamm uup = create_rep_val_list(); 814*3175Sskamm /* fscanf may not set errno, so clear it first */ 815*3175Sskamm errno = 0; 816*3175Sskamm while ((fscanf_ret = fscanf(fp, "%llu", &tval)) == 1) { 817*3175Sskamm /* If tval isn't a valid ctid, then fail. */ 818*3175Sskamm if (tval == 0) { 819*3175Sskamm (void) fclose(fp); 820*3175Sskamm ret = EIO; 821*3175Sskamm goto out; 822*3175Sskamm } 823*3175Sskamm if ((add_rep_val(uup, tval) == -1) || 824*3175Sskamm (add_rep_val(inst->start_ctids, tval) == -1)) { 825*3175Sskamm (void) fclose(fp); 826*3175Sskamm ret = ENOMEM; 827*3175Sskamm goto out; 828*3175Sskamm } 829*3175Sskamm errno = 0; 830*3175Sskamm } 831*3175Sskamm /* EOF is not a failure when no errno */ 832*3175Sskamm if ((fscanf_ret != EOF) || (errno != 0)) { 833*3175Sskamm ret = EIO; 834*3175Sskamm goto out; 835*3175Sskamm } 836*3175Sskamm 837*3175Sskamm if (fclose(fp) != 0) { 838*3175Sskamm ret = ENXIO; 839*3175Sskamm goto out; 840*3175Sskamm } 841*3175Sskamm 842*3175Sskamm for (spval = uu_list_first(uup); spval != NULL; 843*3175Sskamm spval = uu_list_next(uup, spval)) { 844*3175Sskamm /* Try to adopt the contract */ 845*3175Sskamm if (adopt_contract((ctid_t)spval->val, 846*3175Sskamm inst->fmri) != 0) { 847*3175Sskamm /* 848*3175Sskamm * Adoption failed. No reason to think it'll 849*3175Sskamm * work later, so remove the id from our list 850*3175Sskamm * in the instance. 851*3175Sskamm */ 852*3175Sskamm remove_rep_val(inst->start_ctids, spval->val); 853*3175Sskamm } 854*3175Sskamm } 855*3175Sskamm out: 856*3175Sskamm if (uup) { 857*3175Sskamm empty_rep_val_list(uup); 858*3175Sskamm destroy_rep_val_list(uup); 859*3175Sskamm } 860*3175Sskamm 861*3175Sskamm if (ret != 0) 862*3175Sskamm empty_rep_val_list(inst->start_ctids); 863*3175Sskamm 864*3175Sskamm return (ret); 865*3175Sskamm } 866