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