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