repval.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* This file contains routines to manipulate lists of repository values that
* are used to store process ids and the internal state. There are routines
* inspect the lists. It also contains routines that deal with the
* repository side of contract ids.
*/
#include <errno.h>
#include <stdlib.h>
#include <libintl.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include "inetd_impl.h"
/*
* Number of consecutive repository bind retries performed by bind_to_rep()
* before failing.
*/
#define BIND_TO_REP_RETRIES 10
/* Name of property group where inetd's state for a service is stored. */
#define PG_NAME_INSTANCE_STATE (const char *) "inetd_state"
/* uu_list repval list pool */
/*
* Repository object pointers that get set-up in repval_init() and closed down
* in repval_fini(). They're used in _retrieve_rep_vals(), _store_rep_vals(),
* add_remove_contract_norebind(), and adopt_repository_contracts(). They're
* global so they can be initialized once on inetd startup, and re-used
* there-after in the referenced functions.
*/
/*
* Try and make the given handle bind be bound to the repository. If
* it's already bound, or we succeed a new bind return 0; else return
* -1 on failure, with the SCF error set to one of the following:
* SCF_ERROR_NO_SERVER
* SCF_ERROR_NO_RESOURCES
*/
int
{
if ((scf_handle_bind(hdl) == 0) ||
(scf_error() == SCF_ERROR_IN_USE))
return (0);
}
return (-1);
}
int
repval_init(void)
{
debug_msg("Entering repval_init");
/*
* Create the repval list pool.
*/
if (rep_val_pool == NULL) {
uu_strerror(uu_error()));
return (-1);
}
/*
* Create and bind a repository handle, and create all repository
* objects that we'll use later that are associated with it. On any
* errors we simply return -1 and let repval_fini() clean-up after
* us.
*/
error_msg("%s: %s",
gettext("Failed to create repository handle"),
scf_strerror(scf_error()));
goto cleanup;
goto cleanup;
error_msg("%s: %s",
gettext("Failed to create repository object"),
scf_strerror(scf_error()));
goto cleanup;
}
return (0);
repval_fini();
return (-1);
}
void
repval_fini(void)
{
debug_msg("Entering repval_fini");
if (rep_handle != NULL) {
/*
* We unbind from the repository before we free the repository
* objects for efficiency reasons.
*/
(void) scf_handle_unbind(rep_handle);
rep_handle = NULL;
}
if (rep_val_pool != NULL) {
rep_val_pool = NULL;
}
}
create_rep_val_list(void)
{
debug_msg("Entering create_rep_val_list");
return (ret);
}
void
{
debug_msg("Entering destroy_rep_val_list");
}
}
{
break;
}
return (rv);
}
int
{
return (-1);
return (0);
}
void
{
}
}
void
{
debug_msg("Entering empty_rep_val_list");
}
}
{
debug_msg("Entering get_single_rep_val");
}
int
{
debug_msg("Entering set_single_rep_val");
return (-1);
} else {
}
return (0);
}
/*
* Partner to add_tr_entry_values. This function frees the scf_values created
* in add_tr_entry_values() in the list 'vals'.
*/
static void
{
debug_msg("Entering remove_tr_entry_values");
}
}
}
/*
* This function creates and associates with transaction entry 'entry' an
* scf value for each value in 'vals'. The pointers to the scf values
* are stored in the list for later cleanup by remove_tr_entry_values.
* Returns 0 on success, else -1 on error with scf_error() set to:
* SCF_ERROR_NO_MEMORY if memory allocation failed.
* SCF_ERROR_CONNECTION_BROKEN if the connection to the repository was broken.
*/
static int
{
debug_msg("Entering add_tr_entry_values");
return (-1);
}
return (-1);
}
}
return (0);
}
/*
* Stores the values contained in the list 'vals' into the property 'prop_name'
* of the instance with fmri 'inst_fmri', within the instance's instance
* state property group.
*
* Returns 0 on success, else one of the following on failure:
* SCF_ERROR_NO_MEMORY if memory allocation failed.
* SCF_ERROR_NO_RESOURCES if the server doesn't have required resources.
* SCF_ERROR_VERSION_MISMATCH if program compiled against a newer libscf
* than on system.
* SCF_ERROR_PERMISSION_DENIED if insufficient privileges to modify pg.
* SCF_ERROR_BACKEND_ACCESS if the repository back-end refused the pg modify.
* SCF_ERROR_CONNECTION_BROKEN if the connection to the repository was broken.
*/
static scf_error_t
{
int cret;
int ret;
return (scf_error());
/*
* Fetch the instance state pg, and if it doesn't exist try and
* create it.
*/
if (scf_error() != SCF_ERROR_NOT_FOUND)
return (scf_error());
return (scf_error());
}
/*
* Perform a transaction to write the values to the requested property.
* If someone got there before us, loop and retry.
*/
do {
return (scf_error());
prop_name, SCF_TYPE_INTEGER) < 0) &&
prop_name, SCF_TYPE_INTEGER) < 0)) {
goto cleanup;
}
goto cleanup;
}
goto cleanup;
} else if (cret == 0) {
if (scf_pg_update(pg) < 0) {
goto cleanup;
}
}
} while (cret == 0);
ret = 0;
return (ret);
}
/*
* Retrieves the repository values of property 'prop_name', of the instance
* with fmri 'fmri', from within the instance's instance state property
* group and adds them to the value list 'list'.
*
* Returns 0 on success, else one of the following values on error:
* SCF_ERROR_NOT_FOUND if the property doesn't exist.
* SCF_ERROR_NO_MEMORY if memory allocation failed.
* SCF_ERROR_CONNECTION_BROKEN if the connection to the repository was broken.
* SCF_ERROR_TYPE_MISMATCH if the property was of an unexpected type.
*
*/
static scf_error_t
{
return (scf_error());
return (SCF_ERROR_NO_MEMORY);
}
}
if (scf_error() != SCF_ERROR_NONE) {
return (scf_error());
}
return (0);
}
/*
* either success, an error other that a broken repository connection or
* the number of retries reaches REP_OP_RETRIES.
* Returns 0 on success, else the error value from either _store_rep_vals or
* retrieve_rep_vals (based on whether 'store' was set or not), or one of the
* following if a rebind failed:
* SCF_ERROR_NO_RESOURCES if the server doesn't have adequate resources.
* SCF_ERROR_NO_SERVER if the server isn't running.
*/
static scf_error_t
{
break;
}
break;
(void) scf_handle_unbind(rep_handle);
}
return (ret);
}
{
}
{
}
/*
* Fails with ECONNABORTED, ENOENT, EACCES, EROFS, ENOMEM, or EPERM.
*/
static int
{
int err;
NULL, SCF_DECODE_FMRI_EXACT) != 0) {
switch (scf_error()) {
return (ECONNABORTED);
case SCF_ERROR_NOT_FOUND:
return (ENOENT);
default:
assert(0);
abort();
}
}
redo:
if (add)
else
switch (err) {
case 0:
case ENOMEM:
case ECONNABORTED:
return (err);
case ECANCELED:
return (ENOENT);
case EPERM:
assert(0);
return (err);
case EACCES:
"instance %s to repository: backend access denied.") :
gettext("Failed to remove contract id %ld for instance %s "
return (err);
case EROFS:
"instance %s to repository: backend is read-only.") :
gettext("Failed to remove contract id %ld for instance %s "
return (err);
case EINVAL:
case EBADF:
default:
assert(0);
abort();
/* NOTREACHED */
}
}
/*
* contract id to the specified instance until either success, an error
* other that connection broken occurs, or the number of bind retries reaches
* REP_OP_RETRIES.
* Returns 0 on success else fails with one of ENOENT, EACCES, EROFS, EPERM,
* ECONNABORTED or ENOMEM.
*/
int
{
int err;
err = ECONNABORTED;
break;
}
break;
(void) scf_handle_unbind(rep_handle);
}
return (err);
}
/*
* Iterate over all contracts associated with the instance specified by
* fmri; if sig !=0, we send each contract the specified signal, otherwise
* we call adopt_contract() to take ownership. This really ought to be
* reworked to use a callback mechanism if more functionality is added.
*
* Returns 0 on success or ENOENT if the instance, its restarter property
* group, or its contract property don't exist, or EINVAL if the property
* is not of the correct type, ENOMEM if there was a memory allocation
* failure, EPERM if there were permission problems accessing the repository,
* or ECONNABORTED if the connection with the repository was broken.
*/
int
{
uint64_t c;
int err;
int ret = 0;
debug_msg("Entering iterate_repository_contracts");
return (ECONNABORTED);
goto out;
}
NULL, SCF_DECODE_FMRI_EXACT) != 0) {
switch (scf_error()) {
(void) scf_handle_unbind(rep_handle);
if (retries++ == REP_OP_RETRIES) {
ret = ECONNABORTED;
goto out;
}
ret = ECONNABORTED;
goto out;
}
goto rep_retry;
case SCF_ERROR_NOT_FOUND:
goto out;
default:
assert(0);
abort();
}
}
switch (scf_error()) {
goto rebind;
case SCF_ERROR_NOT_SET:
ret = 0;
goto out;
case SCF_ERROR_NOT_FOUND:
goto out;
default:
assert(0);
abort();
}
}
switch (scf_error()) {
goto rebind;
case SCF_ERROR_NOT_SET:
ret = 0;
goto out;
case SCF_ERROR_NOT_FOUND:
goto out;
default:
assert(0);
abort();
}
}
switch (scf_error()) {
goto rebind;
case SCF_ERROR_NOT_SET:
goto out;
case SCF_ERROR_TYPE_MISMATCH:
goto out;
default:
assert(0);
abort();
}
}
switch (scf_error()) {
goto rebind;
case SCF_ERROR_NOT_SET:
goto out;
default:
assert(0);
abort();
}
}
for (;;) {
if (err == 0) {
break;
} else if (err != 1) {
goto rebind;
}
if (sig == 0) {
/* Try to adopt the contract */
/*
* Adoption failed. No reason to think it'll
* work later, so remove the id from our list
* in the repository.
*
* Beware: add_remove_contract_norebind() uses
* the global scf_ handles. Fortunately we're
* done with them. We need to be cognizant of
* repository disconnection, though.
*/
switch (add_remove_contract_norebind(fmri,
case 0:
case ENOENT:
case EACCES:
case EROFS:
break;
case ECONNABORTED:
goto rebind;
default:
assert(0);
abort();
}
}
} else {
/*
* Send a signal to all in the contract; ESRCH just
* means they all exited before we could kill them
*/
"members of instance %s: %s"), fmri,
}
}
}
out:
return (ret);
}