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
make_handle_bound(scf_handle_t * hdl)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
repval_init(void)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
repval_fini(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 *
create_rep_val_list(void)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
destroy_rep_val_list(uu_list_t * list)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 *
find_rep_val(uu_list_t * list,int64_t val)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
add_rep_val(uu_list_t * list,int64_t val)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
remove_rep_val(uu_list_t * list,int64_t val)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
empty_rep_val_list(uu_list_t * list)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
get_single_rep_val(uu_list_t * list)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
set_single_rep_val(uu_list_t * list,int64_t val)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
remove_tr_entry_values(uu_list_t * vals)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
add_tr_entry_values(scf_handle_t * hdl,scf_transaction_entry_t * entry,uu_list_t * vals)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
_store_rep_vals(uu_list_t * vals,const char * inst_fmri,const char * prop_name)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
_retrieve_rep_vals(uu_list_t * list,const char * fmri,const char * prop_name)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
repvals_to_file(const char * fmri,const char * name,uu_list_t * vals)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
store_retrieve_rep_vals(uu_list_t * vals,const char * fmri,const char * prop,boolean_t store)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
store_rep_vals(uu_list_t * vals,const char * fmri,const char * prop)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
retrieve_rep_vals(uu_list_t * vals,const char * fmri,const char * prop)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
add_remove_contract(instance_t * inst,boolean_t add,ctid_t ctid)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
iterate_repository_contracts(instance_t * inst,int sig)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