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 53175Sskamm * Common Development and Distribution License (the "License"). 63175Sskamm * 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*6435Sgm209912 * Copyright 2008 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> 433175Sskamm #include <sys/param.h> 443175Sskamm #include <sys/types.h> 453175Sskamm #include <sys/stat.h> 463175Sskamm #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 /* 763175Sskamm * Pathname storage for paths generated from the fmri. 773175Sskamm * Used when updating the ctid and (start) pid files for an inetd service. 783175Sskamm */ 793175Sskamm static char genfmri_filename[MAXPATHLEN] = ""; 803175Sskamm static char genfmri_temp_filename[MAXPATHLEN] = ""; 813175Sskamm 823175Sskamm /* 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 /* 1090Sstevel@tonic-gate * Create the repval list pool. 1100Sstevel@tonic-gate */ 1110Sstevel@tonic-gate rep_val_pool = uu_list_pool_create("rep_val_pool", sizeof (rep_val_t), 1120Sstevel@tonic-gate offsetof(rep_val_t, link), NULL, UU_LIST_POOL_DEBUG); 1130Sstevel@tonic-gate if (rep_val_pool == NULL) { 1140Sstevel@tonic-gate error_msg("%s: %s", gettext("Failed to create rep_val pool"), 1150Sstevel@tonic-gate uu_strerror(uu_error())); 1160Sstevel@tonic-gate return (-1); 1170Sstevel@tonic-gate } 1180Sstevel@tonic-gate 1190Sstevel@tonic-gate /* 1200Sstevel@tonic-gate * Create and bind a repository handle, and create all repository 1210Sstevel@tonic-gate * objects that we'll use later that are associated with it. On any 1220Sstevel@tonic-gate * errors we simply return -1 and let repval_fini() clean-up after 1230Sstevel@tonic-gate * us. 1240Sstevel@tonic-gate */ 1250Sstevel@tonic-gate if ((rep_handle = scf_handle_create(SCF_VERSION)) == NULL) { 1260Sstevel@tonic-gate error_msg("%s: %s", 1270Sstevel@tonic-gate gettext("Failed to create repository handle"), 1280Sstevel@tonic-gate scf_strerror(scf_error())); 1290Sstevel@tonic-gate goto cleanup; 1300Sstevel@tonic-gate } else if (make_handle_bound(rep_handle) == -1) { 1310Sstevel@tonic-gate goto cleanup; 1320Sstevel@tonic-gate } else if (((pg = scf_pg_create(rep_handle)) == NULL) || 1330Sstevel@tonic-gate ((inst = scf_instance_create(rep_handle)) == NULL) || 1340Sstevel@tonic-gate ((trans = scf_transaction_create(rep_handle)) == NULL) || 1350Sstevel@tonic-gate ((entry = scf_entry_create(rep_handle)) == NULL) || 1360Sstevel@tonic-gate ((prop = scf_property_create(rep_handle)) == NULL)) { 1370Sstevel@tonic-gate error_msg("%s: %s", 1380Sstevel@tonic-gate gettext("Failed to create repository object"), 1390Sstevel@tonic-gate scf_strerror(scf_error())); 1400Sstevel@tonic-gate goto cleanup; 1410Sstevel@tonic-gate } 1420Sstevel@tonic-gate 1430Sstevel@tonic-gate return (0); 1440Sstevel@tonic-gate cleanup: 1450Sstevel@tonic-gate repval_fini(); 1460Sstevel@tonic-gate return (-1); 1470Sstevel@tonic-gate } 1480Sstevel@tonic-gate 1490Sstevel@tonic-gate void 1500Sstevel@tonic-gate repval_fini(void) 1510Sstevel@tonic-gate { 1520Sstevel@tonic-gate if (rep_handle != NULL) { 1530Sstevel@tonic-gate /* 1540Sstevel@tonic-gate * We unbind from the repository before we free the repository 1550Sstevel@tonic-gate * objects for efficiency reasons. 1560Sstevel@tonic-gate */ 1570Sstevel@tonic-gate (void) scf_handle_unbind(rep_handle); 1580Sstevel@tonic-gate 1590Sstevel@tonic-gate scf_pg_destroy(pg); 1600Sstevel@tonic-gate pg = NULL; 1610Sstevel@tonic-gate scf_instance_destroy(inst); 1620Sstevel@tonic-gate inst = NULL; 1630Sstevel@tonic-gate scf_transaction_destroy(trans); 1640Sstevel@tonic-gate trans = NULL; 1650Sstevel@tonic-gate scf_entry_destroy(entry); 1660Sstevel@tonic-gate entry = NULL; 1670Sstevel@tonic-gate scf_property_destroy(prop); 1680Sstevel@tonic-gate prop = NULL; 1690Sstevel@tonic-gate 1700Sstevel@tonic-gate scf_handle_destroy(rep_handle); 1710Sstevel@tonic-gate rep_handle = NULL; 1720Sstevel@tonic-gate } 1730Sstevel@tonic-gate 1740Sstevel@tonic-gate if (rep_val_pool != NULL) { 1750Sstevel@tonic-gate uu_list_pool_destroy(rep_val_pool); 1760Sstevel@tonic-gate rep_val_pool = NULL; 1770Sstevel@tonic-gate } 1780Sstevel@tonic-gate } 1790Sstevel@tonic-gate 1800Sstevel@tonic-gate uu_list_t * 1810Sstevel@tonic-gate create_rep_val_list(void) 1820Sstevel@tonic-gate { 1830Sstevel@tonic-gate uu_list_t *ret; 1840Sstevel@tonic-gate 1850Sstevel@tonic-gate if ((ret = uu_list_create(rep_val_pool, NULL, 0)) == NULL) 1860Sstevel@tonic-gate assert(uu_error() == UU_ERROR_NO_MEMORY); 1870Sstevel@tonic-gate 1880Sstevel@tonic-gate return (ret); 1890Sstevel@tonic-gate } 1900Sstevel@tonic-gate 1910Sstevel@tonic-gate void 1920Sstevel@tonic-gate destroy_rep_val_list(uu_list_t *list) 1930Sstevel@tonic-gate { 1940Sstevel@tonic-gate if (list != NULL) { 1950Sstevel@tonic-gate empty_rep_val_list(list); 1960Sstevel@tonic-gate uu_list_destroy(list); 1970Sstevel@tonic-gate } 1980Sstevel@tonic-gate } 1990Sstevel@tonic-gate 2000Sstevel@tonic-gate rep_val_t * 2010Sstevel@tonic-gate find_rep_val(uu_list_t *list, int64_t val) 2020Sstevel@tonic-gate { 2030Sstevel@tonic-gate rep_val_t *rv; 2040Sstevel@tonic-gate 2050Sstevel@tonic-gate for (rv = uu_list_first(list); rv != NULL; 2060Sstevel@tonic-gate rv = uu_list_next(list, rv)) { 2070Sstevel@tonic-gate if (rv->val == val) 2080Sstevel@tonic-gate break; 2090Sstevel@tonic-gate } 2100Sstevel@tonic-gate return (rv); 2110Sstevel@tonic-gate } 2120Sstevel@tonic-gate 2130Sstevel@tonic-gate int 2140Sstevel@tonic-gate add_rep_val(uu_list_t *list, int64_t val) 2150Sstevel@tonic-gate { 2160Sstevel@tonic-gate rep_val_t *rv; 2170Sstevel@tonic-gate 2180Sstevel@tonic-gate if ((rv = malloc(sizeof (rep_val_t))) == NULL) 2190Sstevel@tonic-gate return (-1); 2200Sstevel@tonic-gate 2210Sstevel@tonic-gate uu_list_node_init(rv, &rv->link, rep_val_pool); 2220Sstevel@tonic-gate rv->val = val; 2230Sstevel@tonic-gate rv->scf_val = NULL; 2240Sstevel@tonic-gate (void) uu_list_insert_after(list, NULL, rv); 2250Sstevel@tonic-gate 2260Sstevel@tonic-gate return (0); 2270Sstevel@tonic-gate } 2280Sstevel@tonic-gate 2290Sstevel@tonic-gate void 2300Sstevel@tonic-gate remove_rep_val(uu_list_t *list, int64_t val) 2310Sstevel@tonic-gate { 2320Sstevel@tonic-gate rep_val_t *rv; 2330Sstevel@tonic-gate 2340Sstevel@tonic-gate if ((rv = find_rep_val(list, val)) != NULL) { 2350Sstevel@tonic-gate uu_list_remove(list, rv); 2360Sstevel@tonic-gate assert(rv->scf_val == NULL); 2370Sstevel@tonic-gate free(rv); 2380Sstevel@tonic-gate } 2390Sstevel@tonic-gate } 2400Sstevel@tonic-gate 2410Sstevel@tonic-gate void 2420Sstevel@tonic-gate empty_rep_val_list(uu_list_t *list) 2430Sstevel@tonic-gate { 2440Sstevel@tonic-gate void *cookie = NULL; 2450Sstevel@tonic-gate rep_val_t *rv; 2460Sstevel@tonic-gate 2470Sstevel@tonic-gate while ((rv = uu_list_teardown(list, &cookie)) != NULL) { 2480Sstevel@tonic-gate if (rv->scf_val != NULL) 2490Sstevel@tonic-gate scf_value_destroy(rv->scf_val); 2500Sstevel@tonic-gate free(rv); 2510Sstevel@tonic-gate } 2520Sstevel@tonic-gate } 2530Sstevel@tonic-gate 2540Sstevel@tonic-gate int64_t 2550Sstevel@tonic-gate get_single_rep_val(uu_list_t *list) 2560Sstevel@tonic-gate { 2570Sstevel@tonic-gate rep_val_t *rv = uu_list_first(list); 2580Sstevel@tonic-gate 2590Sstevel@tonic-gate assert(rv != NULL); 2600Sstevel@tonic-gate return (rv->val); 2610Sstevel@tonic-gate } 2620Sstevel@tonic-gate 2630Sstevel@tonic-gate int 2640Sstevel@tonic-gate set_single_rep_val(uu_list_t *list, int64_t val) 2650Sstevel@tonic-gate { 2660Sstevel@tonic-gate rep_val_t *rv = uu_list_first(list); 2670Sstevel@tonic-gate 2680Sstevel@tonic-gate if (rv == NULL) { 2690Sstevel@tonic-gate if (add_rep_val(list, val) == -1) 2700Sstevel@tonic-gate return (-1); 2710Sstevel@tonic-gate } else { 2720Sstevel@tonic-gate rv->val = val; 2730Sstevel@tonic-gate } 2740Sstevel@tonic-gate 2750Sstevel@tonic-gate return (0); 2760Sstevel@tonic-gate } 2770Sstevel@tonic-gate 2780Sstevel@tonic-gate /* 2790Sstevel@tonic-gate * Partner to add_tr_entry_values. This function frees the scf_values created 2800Sstevel@tonic-gate * in add_tr_entry_values() in the list 'vals'. 2810Sstevel@tonic-gate */ 2820Sstevel@tonic-gate static void 2830Sstevel@tonic-gate remove_tr_entry_values(uu_list_t *vals) 2840Sstevel@tonic-gate { 2850Sstevel@tonic-gate rep_val_t *rval; 2860Sstevel@tonic-gate 2870Sstevel@tonic-gate for (rval = uu_list_first(vals); rval != NULL; 2880Sstevel@tonic-gate rval = uu_list_next(vals, rval)) { 2890Sstevel@tonic-gate if (rval->scf_val != NULL) { 2900Sstevel@tonic-gate scf_value_destroy(rval->scf_val); 2910Sstevel@tonic-gate rval->scf_val = NULL; 2920Sstevel@tonic-gate } 2930Sstevel@tonic-gate } 2940Sstevel@tonic-gate } 2950Sstevel@tonic-gate 2960Sstevel@tonic-gate /* 2970Sstevel@tonic-gate * This function creates and associates with transaction entry 'entry' an 2980Sstevel@tonic-gate * scf value for each value in 'vals'. The pointers to the scf values 2990Sstevel@tonic-gate * are stored in the list for later cleanup by remove_tr_entry_values. 3000Sstevel@tonic-gate * Returns 0 on success, else -1 on error with scf_error() set to: 3010Sstevel@tonic-gate * SCF_ERROR_NO_MEMORY if memory allocation failed. 3020Sstevel@tonic-gate * SCF_ERROR_CONNECTION_BROKEN if the connection to the repository was broken. 3030Sstevel@tonic-gate */ 3040Sstevel@tonic-gate static int 3050Sstevel@tonic-gate add_tr_entry_values(scf_handle_t *hdl, scf_transaction_entry_t *entry, 3060Sstevel@tonic-gate uu_list_t *vals) 3070Sstevel@tonic-gate { 3080Sstevel@tonic-gate rep_val_t *rval; 3090Sstevel@tonic-gate 3100Sstevel@tonic-gate for (rval = uu_list_first(vals); rval != NULL; 3110Sstevel@tonic-gate rval = uu_list_next(vals, rval)) { 3120Sstevel@tonic-gate 3130Sstevel@tonic-gate assert(rval->scf_val == NULL); 3140Sstevel@tonic-gate if ((rval->scf_val = scf_value_create(hdl)) == NULL) { 3150Sstevel@tonic-gate remove_tr_entry_values(vals); 3160Sstevel@tonic-gate return (-1); 3170Sstevel@tonic-gate } 3180Sstevel@tonic-gate 3190Sstevel@tonic-gate scf_value_set_integer(rval->scf_val, rval->val); 3200Sstevel@tonic-gate 3210Sstevel@tonic-gate if (scf_entry_add_value(entry, rval->scf_val) < 0) { 3220Sstevel@tonic-gate remove_tr_entry_values(vals); 3230Sstevel@tonic-gate return (-1); 3240Sstevel@tonic-gate } 3250Sstevel@tonic-gate } 3260Sstevel@tonic-gate 3270Sstevel@tonic-gate return (0); 3280Sstevel@tonic-gate } 3290Sstevel@tonic-gate 3300Sstevel@tonic-gate /* 3310Sstevel@tonic-gate * Stores the values contained in the list 'vals' into the property 'prop_name' 3320Sstevel@tonic-gate * of the instance with fmri 'inst_fmri', within the instance's instance 3330Sstevel@tonic-gate * state property group. 3340Sstevel@tonic-gate * 3350Sstevel@tonic-gate * Returns 0 on success, else one of the following on failure: 3360Sstevel@tonic-gate * SCF_ERROR_NO_MEMORY if memory allocation failed. 3370Sstevel@tonic-gate * SCF_ERROR_NO_RESOURCES if the server doesn't have required resources. 3380Sstevel@tonic-gate * SCF_ERROR_VERSION_MISMATCH if program compiled against a newer libscf 3390Sstevel@tonic-gate * than on system. 3400Sstevel@tonic-gate * SCF_ERROR_PERMISSION_DENIED if insufficient privileges to modify pg. 3410Sstevel@tonic-gate * SCF_ERROR_BACKEND_ACCESS if the repository back-end refused the pg modify. 3420Sstevel@tonic-gate * SCF_ERROR_CONNECTION_BROKEN if the connection to the repository was broken. 3430Sstevel@tonic-gate */ 3440Sstevel@tonic-gate static scf_error_t 3450Sstevel@tonic-gate _store_rep_vals(uu_list_t *vals, const char *inst_fmri, const char *prop_name) 3460Sstevel@tonic-gate { 3470Sstevel@tonic-gate int cret; 3480Sstevel@tonic-gate int ret; 3490Sstevel@tonic-gate 3500Sstevel@tonic-gate if (scf_handle_decode_fmri(rep_handle, inst_fmri, NULL, NULL, inst, 3510Sstevel@tonic-gate NULL, NULL, SCF_DECODE_FMRI_EXACT) == -1) 3520Sstevel@tonic-gate return (scf_error()); 3530Sstevel@tonic-gate 3540Sstevel@tonic-gate /* 3550Sstevel@tonic-gate * Fetch the instance state pg, and if it doesn't exist try and 3560Sstevel@tonic-gate * create it. 3570Sstevel@tonic-gate */ 3580Sstevel@tonic-gate if (scf_instance_get_pg(inst, PG_NAME_INSTANCE_STATE, pg) < 0) { 3590Sstevel@tonic-gate if (scf_error() != SCF_ERROR_NOT_FOUND) 3600Sstevel@tonic-gate return (scf_error()); 3610Sstevel@tonic-gate if (scf_instance_add_pg(inst, PG_NAME_INSTANCE_STATE, 3620Sstevel@tonic-gate SCF_GROUP_FRAMEWORK, SCF_PG_FLAG_NONPERSISTENT, pg) < 0) 3630Sstevel@tonic-gate return (scf_error()); 3640Sstevel@tonic-gate } 3650Sstevel@tonic-gate 3660Sstevel@tonic-gate /* 3670Sstevel@tonic-gate * Perform a transaction to write the values to the requested property. 3680Sstevel@tonic-gate * If someone got there before us, loop and retry. 3690Sstevel@tonic-gate */ 3700Sstevel@tonic-gate do { 3710Sstevel@tonic-gate if (scf_transaction_start(trans, pg) < 0) 3720Sstevel@tonic-gate return (scf_error()); 3730Sstevel@tonic-gate 3740Sstevel@tonic-gate if ((scf_transaction_property_new(trans, entry, 3750Sstevel@tonic-gate prop_name, SCF_TYPE_INTEGER) < 0) && 3760Sstevel@tonic-gate (scf_transaction_property_change_type(trans, entry, 3770Sstevel@tonic-gate prop_name, SCF_TYPE_INTEGER) < 0)) { 3780Sstevel@tonic-gate ret = scf_error(); 3790Sstevel@tonic-gate goto cleanup; 3800Sstevel@tonic-gate } 3810Sstevel@tonic-gate 3820Sstevel@tonic-gate if (add_tr_entry_values(rep_handle, entry, vals) < 0) { 3830Sstevel@tonic-gate ret = scf_error(); 3840Sstevel@tonic-gate goto cleanup; 3850Sstevel@tonic-gate } 3860Sstevel@tonic-gate 3870Sstevel@tonic-gate if ((cret = scf_transaction_commit(trans)) < 0) { 3880Sstevel@tonic-gate ret = scf_error(); 3890Sstevel@tonic-gate goto cleanup; 3900Sstevel@tonic-gate } else if (cret == 0) { 3910Sstevel@tonic-gate scf_transaction_reset(trans); 3920Sstevel@tonic-gate scf_entry_reset(entry); 3930Sstevel@tonic-gate remove_tr_entry_values(vals); 3940Sstevel@tonic-gate if (scf_pg_update(pg) < 0) { 3950Sstevel@tonic-gate ret = scf_error(); 3960Sstevel@tonic-gate goto cleanup; 3970Sstevel@tonic-gate } 3980Sstevel@tonic-gate } 3990Sstevel@tonic-gate } while (cret == 0); 4000Sstevel@tonic-gate 4010Sstevel@tonic-gate ret = 0; 4020Sstevel@tonic-gate cleanup: 4030Sstevel@tonic-gate scf_transaction_reset(trans); 4040Sstevel@tonic-gate scf_entry_reset(entry); 4050Sstevel@tonic-gate remove_tr_entry_values(vals); 4060Sstevel@tonic-gate return (ret); 4070Sstevel@tonic-gate } 4080Sstevel@tonic-gate 4090Sstevel@tonic-gate /* 4100Sstevel@tonic-gate * Retrieves the repository values of property 'prop_name', of the instance 4110Sstevel@tonic-gate * with fmri 'fmri', from within the instance's instance state property 4120Sstevel@tonic-gate * group and adds them to the value list 'list'. 4130Sstevel@tonic-gate * 4140Sstevel@tonic-gate * Returns 0 on success, else one of the following values on error: 4150Sstevel@tonic-gate * SCF_ERROR_NOT_FOUND if the property doesn't exist. 4160Sstevel@tonic-gate * SCF_ERROR_NO_MEMORY if memory allocation failed. 4170Sstevel@tonic-gate * SCF_ERROR_CONNECTION_BROKEN if the connection to the repository was broken. 4180Sstevel@tonic-gate * SCF_ERROR_TYPE_MISMATCH if the property was of an unexpected type. 4190Sstevel@tonic-gate * 4200Sstevel@tonic-gate */ 4210Sstevel@tonic-gate static scf_error_t 4220Sstevel@tonic-gate _retrieve_rep_vals(uu_list_t *list, const char *fmri, const char *prop_name) 4230Sstevel@tonic-gate { 4240Sstevel@tonic-gate scf_simple_prop_t *sp; 4250Sstevel@tonic-gate int64_t *ip; 4260Sstevel@tonic-gate 4270Sstevel@tonic-gate if ((sp = scf_simple_prop_get(rep_handle, fmri, PG_NAME_INSTANCE_STATE, 4280Sstevel@tonic-gate prop_name)) == NULL) 4290Sstevel@tonic-gate return (scf_error()); 4300Sstevel@tonic-gate 4310Sstevel@tonic-gate while ((ip = scf_simple_prop_next_integer(sp)) != NULL) { 4320Sstevel@tonic-gate if (add_rep_val(list, *ip) == -1) { 4330Sstevel@tonic-gate empty_rep_val_list(list); 4340Sstevel@tonic-gate scf_simple_prop_free(sp); 4350Sstevel@tonic-gate return (SCF_ERROR_NO_MEMORY); 4360Sstevel@tonic-gate } 4370Sstevel@tonic-gate } 4380Sstevel@tonic-gate if (scf_error() != SCF_ERROR_NONE) { 4390Sstevel@tonic-gate assert(scf_error() == SCF_ERROR_TYPE_MISMATCH); 4400Sstevel@tonic-gate empty_rep_val_list(list); 4410Sstevel@tonic-gate scf_simple_prop_free(sp); 4420Sstevel@tonic-gate return (scf_error()); 4430Sstevel@tonic-gate } 4440Sstevel@tonic-gate 4450Sstevel@tonic-gate scf_simple_prop_free(sp); 4460Sstevel@tonic-gate return (0); 4470Sstevel@tonic-gate } 4480Sstevel@tonic-gate 4490Sstevel@tonic-gate /* 4503175Sskamm * Writes the repository values in the vals list to 4513175Sskamm * a file that is generated based on the passed in fmri and name. 4523175Sskamm * Returns 0 on success, 4533175Sskamm * ENAMETOOLONG if unable to generate filename from fmri (including 4543175Sskamm * the inability to create the directory for the generated filename) and 4553175Sskamm * ENOENT on all other failures. 4563175Sskamm */ 4573175Sskamm static int 4583175Sskamm repvals_to_file(const char *fmri, const char *name, uu_list_t *vals) 4593175Sskamm { 4603175Sskamm int tfd; 4613175Sskamm FILE *tfp; /* temp fp */ 4623175Sskamm rep_val_t *spval; /* Contains a start_pid or ctid */ 4633175Sskamm int ret = 0; 4643175Sskamm 4653175Sskamm if (gen_filenms_from_fmri(fmri, name, genfmri_filename, 4663175Sskamm genfmri_temp_filename) != 0) { 4673175Sskamm /* Failure either from fmri too long or mkdir failure */ 4683175Sskamm return (ENAMETOOLONG); 4693175Sskamm } 4703175Sskamm 4713175Sskamm if ((tfd = mkstemp(genfmri_temp_filename)) == -1) { 4723175Sskamm return (ENOENT); 4733175Sskamm } 4743175Sskamm 4753175Sskamm if (fchmod(tfd, (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1) { 4763175Sskamm (void) close(tfd); 4773175Sskamm ret = ENOENT; 4783175Sskamm goto unlink_out; 4793175Sskamm } 4803175Sskamm 4813175Sskamm if ((tfp = fdopen(tfd, "w")) == NULL) { 4823175Sskamm (void) close(tfd); 4833175Sskamm ret = ENOENT; 4843175Sskamm goto unlink_out; 4853175Sskamm } 4863175Sskamm 4873175Sskamm for (spval = uu_list_first(vals); spval != NULL; 4883175Sskamm spval = uu_list_next(vals, spval)) { 4893175Sskamm if (fprintf(tfp, "%lld\n", spval->val) <= 0) { 4903175Sskamm (void) fclose(tfp); 4913175Sskamm ret = ENOENT; 4923175Sskamm goto unlink_out; 4933175Sskamm } 4943175Sskamm } 4953175Sskamm if (fclose(tfp) != 0) { 4963175Sskamm ret = ENOENT; 4973175Sskamm goto unlink_out; 4983175Sskamm } 4993175Sskamm if (rename(genfmri_temp_filename, genfmri_filename) != 0) { 5003175Sskamm ret = ENOENT; 5013175Sskamm goto unlink_out; 5023175Sskamm } 5033175Sskamm return (0); 5043175Sskamm 5053175Sskamm unlink_out: 5063175Sskamm if (unlink(genfmri_temp_filename) != 0) { 5073175Sskamm warn_msg(gettext("Removal of temp file " 5083175Sskamm "%s failed. Please remove manually."), 5093175Sskamm genfmri_temp_filename); 5103175Sskamm } 5113175Sskamm return (ret); 5123175Sskamm } 5133175Sskamm 5143175Sskamm /* 5153175Sskamm * A routine that loops trying to read/write values until either success, 5163175Sskamm * an error other than a broken repository connection or 5170Sstevel@tonic-gate * the number of retries reaches REP_OP_RETRIES. 5183175Sskamm * This action is used to read/write the values: 5193175Sskamm * reads/writes to a file for the START_PIDS property due to scalability 5203175Sskamm * problems with libscf 5213175Sskamm * reads/writes to the repository for all other properties. 5220Sstevel@tonic-gate * Returns 0 on success, else the error value from either _store_rep_vals or 5233175Sskamm * _retrieve_rep_vals (based on whether 'store' was set or not), or one of the 5243175Sskamm * following: 5253175Sskamm * SCF_ERROR_NO_RESOURCES if the server doesn't have adequate resources 5263175Sskamm * SCF_ERROR_NO_MEMORY if a memory allocation failure 5270Sstevel@tonic-gate * SCF_ERROR_NO_SERVER if the server isn't running. 5283175Sskamm * SCF_ERROR_CONSTRAINT_VIOLATED if an error in dealing with the speedy files 5290Sstevel@tonic-gate */ 5300Sstevel@tonic-gate static scf_error_t 5310Sstevel@tonic-gate store_retrieve_rep_vals(uu_list_t *vals, const char *fmri, 5320Sstevel@tonic-gate const char *prop, boolean_t store) 5330Sstevel@tonic-gate { 5343175Sskamm scf_error_t ret = 0; 5350Sstevel@tonic-gate uint_t retries; 5363175Sskamm FILE *tfp; /* temp fp */ 5373175Sskamm int64_t tval; /* temp val holder */ 5383175Sskamm int fscanf_ret; 5393175Sskamm int fopen_retry_cnt = 2; 5400Sstevel@tonic-gate 5413175Sskamm /* inetd specific action for START_PIDS property */ 5423175Sskamm if (strcmp(prop, PR_NAME_START_PIDS) == 0) { 5433175Sskamm /* 5443175Sskamm * Storage performance of START_PIDS is important, 5453175Sskamm * so each instance has its own file and all start_pids 5463175Sskamm * in the list are written to a temp file and then 5473175Sskamm * moved (renamed). 5483175Sskamm */ 5493175Sskamm if (store) { 5503175Sskamm /* Write all values in list to file */ 5513175Sskamm if (repvals_to_file(fmri, "pid", vals)) { 5523175Sskamm return (SCF_ERROR_CONSTRAINT_VIOLATED); 5533175Sskamm } 5543175Sskamm } else { 5553175Sskamm /* no temp name needed */ 5563175Sskamm if (gen_filenms_from_fmri(fmri, "pid", genfmri_filename, 5573175Sskamm NULL) != 0) 5583175Sskamm return (SCF_ERROR_CONSTRAINT_VIOLATED); 5590Sstevel@tonic-gate 5603175Sskamm retry_fopen: 5613175Sskamm /* It's ok if no file, there are just no pids */ 5623175Sskamm if ((tfp = fopen(genfmri_filename, "r")) == NULL) { 5633175Sskamm if ((errno == EINTR) && (fopen_retry_cnt > 0)) { 5643175Sskamm fopen_retry_cnt--; 5653175Sskamm goto retry_fopen; 5663175Sskamm } 5673175Sskamm return (0); 5683175Sskamm } 5693175Sskamm /* fscanf may not set errno, so clear it first */ 5703175Sskamm errno = 0; 5713175Sskamm while ((fscanf_ret = fscanf(tfp, "%lld", &tval)) == 1) { 5723175Sskamm /* If tval isn't a valid pid, then fail. */ 5733175Sskamm if ((tval > MAXPID) || (tval <= 0)) { 5743175Sskamm empty_rep_val_list(vals); 5753175Sskamm return (SCF_ERROR_CONSTRAINT_VIOLATED); 5763175Sskamm } 5773175Sskamm if (add_rep_val(vals, tval) == -1) { 5783175Sskamm empty_rep_val_list(vals); 5793175Sskamm return (SCF_ERROR_NO_MEMORY); 5803175Sskamm } 5813175Sskamm errno = 0; 5823175Sskamm } 5833175Sskamm /* EOF is ok when no errno */ 5843175Sskamm if ((fscanf_ret != EOF) || (errno != 0)) { 5853175Sskamm empty_rep_val_list(vals); 5863175Sskamm return (SCF_ERROR_CONSTRAINT_VIOLATED); 5873175Sskamm } 5883175Sskamm if (fclose(tfp) != 0) { 5893175Sskamm /* for close failure just log a message */ 5903175Sskamm warn_msg(gettext("Close of file %s failed."), 5913175Sskamm genfmri_filename); 5923175Sskamm } 5933175Sskamm } 5943175Sskamm } else { 5953175Sskamm for (retries = 0; retries <= REP_OP_RETRIES; retries++) { 5963175Sskamm if (make_handle_bound(rep_handle) == -1) { 5973175Sskamm ret = scf_error(); 5983175Sskamm break; 5993175Sskamm } 6000Sstevel@tonic-gate 6013175Sskamm if ((ret = (store ? _store_rep_vals(vals, fmri, prop) : 6023175Sskamm _retrieve_rep_vals(vals, fmri, prop))) != 6033175Sskamm SCF_ERROR_CONNECTION_BROKEN) 6043175Sskamm break; 6053175Sskamm 6063175Sskamm (void) scf_handle_unbind(rep_handle); 6073175Sskamm } 6080Sstevel@tonic-gate } 6090Sstevel@tonic-gate 6103175Sskamm out: 6110Sstevel@tonic-gate return (ret); 6120Sstevel@tonic-gate } 6130Sstevel@tonic-gate 6140Sstevel@tonic-gate scf_error_t 6150Sstevel@tonic-gate store_rep_vals(uu_list_t *vals, const char *fmri, const char *prop) 6160Sstevel@tonic-gate { 6170Sstevel@tonic-gate return (store_retrieve_rep_vals(vals, fmri, prop, B_TRUE)); 6180Sstevel@tonic-gate } 6190Sstevel@tonic-gate 6200Sstevel@tonic-gate scf_error_t 6210Sstevel@tonic-gate retrieve_rep_vals(uu_list_t *vals, const char *fmri, const char *prop) 6220Sstevel@tonic-gate { 6230Sstevel@tonic-gate return (store_retrieve_rep_vals(vals, fmri, prop, B_FALSE)); 6240Sstevel@tonic-gate } 6250Sstevel@tonic-gate 6260Sstevel@tonic-gate /* 6273175Sskamm * Adds/removes a contract id to/from the cached list kept in the instance. 6283175Sskamm * Then the cached list is written to a file named "ctid" in a directory 6293175Sskamm * based on the fmri. Cached list is written to a file due to scalability 6303175Sskamm * problems in libscf. The file "ctid" is used when inetd is restarted 6313175Sskamm * so that inetd can adopt the contracts that it had previously. 6323175Sskamm * Returns: 6333175Sskamm * 0 on success 6343175Sskamm * ENAMETOOLONG if unable to generate filename from fmri (including 6353175Sskamm * the inability to create the directory for the generated filename) 6363175Sskamm * ENOENT - failure accessing file 6373175Sskamm * ENOMEM - memory allocation failure 6380Sstevel@tonic-gate */ 6390Sstevel@tonic-gate int 6403175Sskamm add_remove_contract(instance_t *inst, boolean_t add, ctid_t ctid) 6410Sstevel@tonic-gate { 6423175Sskamm FILE *tfp; /* temp fp */ 6430Sstevel@tonic-gate int ret = 0; 6443175Sskamm int repval_ret = 0; 6453175Sskamm int fopen_retry_cnt = 2; 6460Sstevel@tonic-gate 6473175Sskamm /* 6483175Sskamm * Storage performance of contract ids is important, 6493175Sskamm * so each instance has its own file. An add of a 6503175Sskamm * ctid will be appended to the ctid file. 6513175Sskamm * The removal of a ctid will result in the remaining 6523175Sskamm * ctids in the list being written to a temp file and then 6533175Sskamm * moved (renamed). 6543175Sskamm */ 6553175Sskamm if (add) { 6563175Sskamm if (gen_filenms_from_fmri(inst->fmri, "ctid", genfmri_filename, 6573175Sskamm NULL) != 0) { 6583175Sskamm /* Failure either from fmri too long or mkdir failure */ 6593175Sskamm return (ENAMETOOLONG); 6600Sstevel@tonic-gate } 6610Sstevel@tonic-gate 6623175Sskamm retry_fopen: 6633175Sskamm if ((tfp = fopen(genfmri_filename, "a")) == NULL) { 6643175Sskamm if ((errno == EINTR) && (fopen_retry_cnt > 0)) { 6653175Sskamm fopen_retry_cnt--; 6663175Sskamm goto retry_fopen; 6673175Sskamm } 6680Sstevel@tonic-gate ret = ENOENT; 6690Sstevel@tonic-gate goto out; 6703175Sskamm } 6710Sstevel@tonic-gate 6723175Sskamm /* Always store ctids as long long */ 6733175Sskamm if (fprintf(tfp, "%llu\n", (uint64_t)ctid) <= 0) { 6743175Sskamm (void) fclose(tfp); 6750Sstevel@tonic-gate ret = ENOENT; 6760Sstevel@tonic-gate goto out; 6773175Sskamm } 6780Sstevel@tonic-gate 6793175Sskamm if (fclose(tfp) != 0) { 6800Sstevel@tonic-gate ret = ENOENT; 6810Sstevel@tonic-gate goto out; 6820Sstevel@tonic-gate } 6830Sstevel@tonic-gate 6843175Sskamm if (add_rep_val(inst->start_ctids, ctid) != 0) { 6853175Sskamm ret = ENOMEM; 6863175Sskamm goto out; 6873175Sskamm } 6883175Sskamm } else { 6893175Sskamm remove_rep_val(inst->start_ctids, ctid); 6900Sstevel@tonic-gate 6913175Sskamm /* Write all values in list to file */ 6923175Sskamm if ((repval_ret = repvals_to_file(inst->fmri, "ctid", 6933175Sskamm inst->start_ctids)) != 0) { 6943175Sskamm ret = repval_ret; 6953175Sskamm goto out; 6960Sstevel@tonic-gate } 6970Sstevel@tonic-gate } 6980Sstevel@tonic-gate 6990Sstevel@tonic-gate out: 7000Sstevel@tonic-gate return (ret); 7010Sstevel@tonic-gate } 7023175Sskamm 7033175Sskamm /* 7043175Sskamm * If sig !=0, iterate over all contracts in the cached list of contract 7053175Sskamm * ids kept in the instance. Send each contract the specified signal. 7063175Sskamm * If sig == 0, read in the contract ids that were last associated 7073175Sskamm * with this instance (reload the cache) and call adopt_contract() 7083175Sskamm * to take ownership. 7093175Sskamm * 7103175Sskamm * Returns 0 on success; 7113175Sskamm * ENAMETOOLONG if unable to generate filename from fmri (including 7123175Sskamm * the inability to create the directory for the generated filename) and 7133175Sskamm * ENXIO if a failure accessing the file 7143175Sskamm * ENOMEM if there was a memory allocation failure 7153175Sskamm * ENOENT if the instance, its restarter property group, or its 7163175Sskamm * contract property don't exist 7173175Sskamm * EIO if invalid data read from the file 7183175Sskamm */ 7193175Sskamm int 7203175Sskamm iterate_repository_contracts(instance_t *inst, int sig) 7213175Sskamm { 7223175Sskamm int ret = 0; 7233175Sskamm FILE *fp; 7243175Sskamm rep_val_t *spval = NULL; /* Contains a start_pid */ 7253175Sskamm uint64_t tval; /* temp val holder */ 7263175Sskamm uu_list_t *uup = NULL; 7273175Sskamm int fscanf_ret; 7283175Sskamm int fopen_retry_cnt = 2; 7293175Sskamm 7303175Sskamm if (sig != 0) { 7313175Sskamm /* 7323175Sskamm * Send a signal to all in the contract; ESRCH just 7333175Sskamm * means they all exited before we could kill them 7343175Sskamm */ 7353175Sskamm for (spval = uu_list_first(inst->start_ctids); spval != NULL; 7363175Sskamm spval = uu_list_next(inst->start_ctids, spval)) { 7373175Sskamm if (sigsend(P_CTID, (ctid_t)spval->val, sig) == -1 && 7383175Sskamm errno != ESRCH) { 7393175Sskamm warn_msg(gettext("Unable to signal all " 7403175Sskamm "contract members of instance %s: %s"), 7413175Sskamm inst->fmri, strerror(errno)); 7423175Sskamm } 7433175Sskamm } 7443175Sskamm return (0); 7453175Sskamm } 7463175Sskamm 7473175Sskamm /* 7483175Sskamm * sig == 0 case. 7493175Sskamm * Attempt to adopt the contract for each ctid. 7503175Sskamm */ 7513175Sskamm if (gen_filenms_from_fmri(inst->fmri, "ctid", genfmri_filename, 7523175Sskamm NULL) != 0) { 7533175Sskamm /* Failure either from fmri too long or mkdir failure */ 7543175Sskamm return (ENAMETOOLONG); 7553175Sskamm } 7563175Sskamm 7573175Sskamm retry_fopen: 7583175Sskamm /* It's ok if no file, there are no ctids to adopt */ 7593175Sskamm if ((fp = fopen(genfmri_filename, "r")) == NULL) { 7603175Sskamm if ((errno == EINTR) && (fopen_retry_cnt > 0)) { 7613175Sskamm fopen_retry_cnt--; 7623175Sskamm goto retry_fopen; 7633175Sskamm } 7643175Sskamm return (0); 7653175Sskamm } 7663175Sskamm 7673175Sskamm /* 7683175Sskamm * Read ctids from file into 2 lists: 7693175Sskamm * - temporary list to be traversed (uup) 7703175Sskamm * - cached list that can be modified if adoption of 7713175Sskamm * contract fails (inst->start_ctids). 7723175Sskamm * Always treat ctids as long longs. 7733175Sskamm */ 7743175Sskamm uup = create_rep_val_list(); 7753175Sskamm /* fscanf may not set errno, so clear it first */ 7763175Sskamm errno = 0; 7773175Sskamm while ((fscanf_ret = fscanf(fp, "%llu", &tval)) == 1) { 7783175Sskamm /* If tval isn't a valid ctid, then fail. */ 7793175Sskamm if (tval == 0) { 7803175Sskamm (void) fclose(fp); 7813175Sskamm ret = EIO; 7823175Sskamm goto out; 7833175Sskamm } 7843175Sskamm if ((add_rep_val(uup, tval) == -1) || 7853175Sskamm (add_rep_val(inst->start_ctids, tval) == -1)) { 7863175Sskamm (void) fclose(fp); 7873175Sskamm ret = ENOMEM; 7883175Sskamm goto out; 7893175Sskamm } 7903175Sskamm errno = 0; 7913175Sskamm } 7923175Sskamm /* EOF is not a failure when no errno */ 7933175Sskamm if ((fscanf_ret != EOF) || (errno != 0)) { 7943175Sskamm ret = EIO; 7953175Sskamm goto out; 7963175Sskamm } 7973175Sskamm 7983175Sskamm if (fclose(fp) != 0) { 7993175Sskamm ret = ENXIO; 8003175Sskamm goto out; 8013175Sskamm } 8023175Sskamm 8033175Sskamm for (spval = uu_list_first(uup); spval != NULL; 8043175Sskamm spval = uu_list_next(uup, spval)) { 8053175Sskamm /* Try to adopt the contract */ 8063175Sskamm if (adopt_contract((ctid_t)spval->val, 8073175Sskamm inst->fmri) != 0) { 8083175Sskamm /* 8093175Sskamm * Adoption failed. No reason to think it'll 8103175Sskamm * work later, so remove the id from our list 8113175Sskamm * in the instance. 8123175Sskamm */ 8133175Sskamm remove_rep_val(inst->start_ctids, spval->val); 8143175Sskamm } 8153175Sskamm } 8163175Sskamm out: 8173175Sskamm if (uup) { 8183175Sskamm empty_rep_val_list(uup); 8193175Sskamm destroy_rep_val_list(uup); 8203175Sskamm } 8213175Sskamm 8223175Sskamm if (ret != 0) 8233175Sskamm empty_rep_val_list(inst->start_ctids); 8243175Sskamm 8253175Sskamm return (ret); 8263175Sskamm } 827