config.c revision eed64e98ce34ec2844d4c68b7e5af30cf962e9c8
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (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 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Routines used by inetd to read inetd's configuration from the repository,
* to validate it and setup inetd's data structures appropriately based on
* in.
*/
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <netdb.h>
#include <libintl.h>
#include <nss_dbdefs.h>
#include <signal.h>
#include <wait.h>
#include "inetd_impl.h"
/* method timeout used if one isn't explicitly specified */
#define DEFAULT_METHOD_TIMEOUT 10
/* supported method properties and their attributes */
static inetd_prop_t method_props[] = {
{NULL},
};
/* enumeration of method properties; used to index into method_props[] */
typedef enum {
/* handle used for repository access in read_prop() */
/* pool used to create proto_info_t lists (generic proto info structure) */
static void destroy_method_props(inetd_prop_t *);
static int proto_info_compare(const void *, const void *, void *);
int
config_init(void)
{
error_msg("%s: %s",
gettext("Failed to create repository handle"),
scf_strerror(scf_error()));
return (-1);
/* let config_fini clean-up */
return (-1);
}
uu_strerror(uu_error()));
return (-1);
}
return (0);
}
void
config_fini(void)
{
if (rep_handle == NULL)
return;
if (proto_info_pool != NULL) {
}
(void) scf_handle_unbind(rep_handle);
rep_handle = NULL;
}
static void
{
return;
/*
* Return the wordexp structure back to its original
* state so it can be consumed by wordfree.
*/
(char *)mi->wordexp_arg0_backup;
}
}
/*
* Transforms the properties read from the repository for a method into a
* method_info_t and returns a pointer to it. If expansion of the exec
* property fails, due to an invalid string or memory allocation failure,
* NULL is returned and exec_invalid is set appropriately to indicate whether
* it was a memory allocation failure or an invalid exec string.
*/
static method_info_t *
{
int i;
goto alloc_fail;
/* Expand the exec string. */
if (i == WRDE_NOSPACE)
goto alloc_fail;
*exec_invalid = B_TRUE;
return (NULL);
}
goto alloc_fail;
/*
* Keep a copy of arg0 of the wordexp structure so that
* wordfree() gets passed what wordexp() originally returned,
* as documented as required in the man page.
*/
== NULL)
goto alloc_fail;
}
} else {
}
/* exec_invalid not set on success */
return (ret);
*exec_invalid = B_FALSE;
return (NULL);
}
/*
* Returns B_TRUE if the contents of the 2 method_info_t structures are
* equivalent, else B_FALSE.
*/
{
int i;
return (B_TRUE);
return (B_FALSE);
}
return (B_FALSE);
}
}
return (B_TRUE);
}
/*
* Checks if the contents of the 2 socket_info_t structures are equivalent.
* If 'isrpc' is false, the address components of the two structures are
* compared for equality as part of this. If the two structures are
* equivalent B_TRUE is returned, else B_FALSE.
*/
{
sizeof (si->local_addr)) == 0)) &&
}
/*
* proto_info_t comparison function. Returns 0 on match, else -1, as required
* by uu_list_find().
*/
static int
{
/* check their RPC configuration matches */
return (-1);
return (-1);
}
return (-1);
return (0);
} else {
return (0);
}
return (-1);
}
/*
* Returns B_TRUE if the bind configuration of the two instance_cfg_t
* structures are equivalent, else B_FALSE.
*/
{
return (B_FALSE);
return (B_FALSE);
/*
* check there's a matching one in the other list.
*/
return (B_FALSE);
}
return (B_TRUE);
}
/*
* Write the default values contained in 'bprops', read by
* read_instance_props(), into 'cfg'.
* Returns -1 if memory allocation fails, else 0.
*/
static int
{
return (-1);
}
return (0);
}
void
{
int i;
for (i = 0; i < NUM_METHODS; i++) {
destroy_method_info(mis[i]);
}
}
/*
* For each method, if it was specifed convert its entry in 'mprops',
* into an entry in 'mis'. Returns -1 if memory allocation fails or one of the
* exec strings was invalid, else 0.
*/
static int
method_info_t **mis)
{
int i;
for (i = 0; i < NUM_METHODS; i++) {
/*
* Only create a method info structure if the method properties
* contain an exec string, which we take to mean the method
* is specified.
*/
&exec_invalid)) == NULL) {
if (exec_invalid) {
"method %s of instance %s is "
"invalid"), PR_EXEC_NAME,
}
return (-1);
}
}
}
return (0);
}
/*
* Try and read each of the method properties for the method 'method' of
* instance 'inst', and return a table containing all method properties. If an
* error occurs, NULL is returned, with 'err' set to indicate the cause.
* Otherwise, a pointer to an inetd_prop_t table is returned containing all
* the method properties, and each of the properties is flagged according to
* whether it was present or not, and if it was present its value is set in
* the property's entry in the table.
*/
static inetd_prop_t *
{
int i;
return (NULL);
}
return (NULL);
}
}
return (ret);
}
static void
{
int i;
return;
}
}
/*
* Destroy the basic and method properties returned by read_inst_props().
*/
static void
{
int i;
for (i = 0; i < NUM_METHODS; i++)
}
/*
* Read all the basic and method properties for instance 'inst', as inetd_prop_t
* tables, into the spaces referenced by 'bprops' and 'mprops' respectively.
* Each of the properties in the tables are flagged to indicate if the
* property was present or not, and if it was the value is stored within it.
* If an error occurs at any time -1 is returned and 'err' is set to
* indicate the reason, else 0 is returned.
*/
static int
{
int i;
return (-1);
for (i = 0; i < NUM_METHODS; i++) {
if ((mprops[i] =
NULL) {
for (i--; i >= 0; i--)
return (-1);
}
}
return (0);
}
/*
* Returns B_TRUE if all required properties were read from the repository
* (whether taken from the defaults or directly from the instance), they
* all had valid values, all the required methods were present, and they
* each had the required properties with valid values. Else, returns B_FALSE.
* If the function returns B_TRUE, the storage referenced by 'cfg' is set
* to point at an allocated instance_cfg_t initialized based on the basic
* properties (not method or defaults).
*/
static boolean_t
basic_cfg_t **cfg)
{
int i;
/*
* Double check we've got all necessary properties (valid_props()
* doesn't enforce the presence of defaults), and output error messages
* for each invalid/ missing property.
*/
(void) get_prop_table(&num_bprops);
case IVE_UNSET:
if (!bprops[i].ip_default)
continue;
if ((i == PT_ARG0_INDEX) || (i == PT_EXEC_INDEX))
continue;
/* FALLTHROUGH */
case IVE_INVALID:
"%s is missing, inconsistent or invalid"),
}
}
for (i = 0; i < NUM_METHODS; i++) {
int j;
/* check if any properties are set */
break;
}
/* an unspecified method */
if ((instance_method_t)i == IM_START) {
"Unspecified %s method for instance %s"),
}
"of instance %s"), PR_EXEC_NAME,
}
}
if (!valid)
return (valid);
}
void
{
}
}
/*
* Returns an allocated instance_cfg_t representation of an instance's
* configuration read from the repository. If the configuration is invalid, a
* repository error occurred, or a memory allocation occurred returns NULL,
* else returns a pointer to the allocated instance_cfg_t.
*/
read_instance_cfg(const char *fmri)
{
return (NULL);
goto read_error;
}
break;
if (err != SCF_ERROR_CONNECTION_BROKEN)
goto read_error;
(void) scf_handle_unbind(rep_handle);
}
if (retries > REP_OP_RETRIES)
goto read_error;
/*
* Switch off validation of the start method's exec string, since
* during boot the filesystem it resides on may not have been
* mounted yet, which would result in a false validation failure.
* We'll catch any real errors when the start method is first run
* in passes_basic_exec_checks().
*/
}
return (ret);
"Failed to read the configuration of instance %s: %s"), fmri,
scf_strerror(err));
return (NULL);
}
/*
* Returns a pointer to an allocated method context for the specified method
* of the specified instance if it could retrieve it. Else, if there were
* errors retrieving it, NULL is returned and the pointer referenced by
* 'errstr' is set to point at an appropriate error string.
*/
struct method_context *
const char **errstr)
{
struct method_context *ret;
const char *tmpstr;
goto inst_failure;
break;
if (scf_error() != SCF_ERROR_CONNECTION_BROKEN) {
goto inst_failure;
}
(void) scf_instance_destroy(scf_inst);
(void) scf_handle_unbind(rep_handle);
}
if (retries > REP_OP_RETRIES)
goto inst_failure;
if ((tmpstr = restarter_get_method_context(
}
return (ret);
/*
* We can rely on this string not becoming invalid
* since we don't call bind_textdomain_codeset() or
* setlocale(3C) after initialization.
*/
return (NULL);
}
/*
* Reads the value of the enabled property from the named property group
* of the given instance.
* If an error occurs, the SCF error code is returned. The possible errors are:
* - SCF_ERROR_INVALID_ARGUMENT: The enabled property is not a boolean.
* - SCF_ERROR_NONE: No value exists for the enabled property.
* - SCF_ERROR_CONNECTION_BROKEN: Repository connection broken.
* - SCF_ERROR_NOT_FOUND: The property wasn't found.
* - SCF_ERROR_NO_MEMORY: allocation failure.
* Else 0 is returned and 'enabled' set appropriately.
*/
static scf_error_t
{
SCF_PROPERTY_ENABLED)) == NULL)
return (scf_error());
return (scf_error());
}
return (0);
}
/*
* Reads the enabled value for the given instance FMRI. The read value
* is based on a merge of the 'standard' enabled property, and the temporary
* override one; the merge involves using the latter properties value if
* present, else resporting to the formers. If an error occurs -1 is returned,
* else 0 is returned and 'enabled' set approriately.
*/
int
{
goto gen_fail;
case 0:
return (0);
break;
case SCF_ERROR_NOT_FOUND:
case SCF_ERROR_NONE:
SCF_PG_GENERAL)) {
case 0:
debug_msg("read %d from non_override",
*enabled);
return (0);
break;
case SCF_ERROR_NOT_FOUND:
case SCF_ERROR_NONE:
"for instance %s"), SCF_PROPERTY_ENABLED,
fmri);
return (-1);
default:
goto gen_fail;
}
break;
default:
goto gen_fail;
}
(void) scf_handle_unbind(rep_handle);
continue;
}
return (-1);
}
/*
* Refresh the value of debug property under the property group "config"
*/
void
refresh_debug_flag(void)
{
"group. scf_simple_prop_get() failed: %s"),
scf_strerror(scf_error()));
return;
"scf_simple_prop_next_boolean() failed: %s"),
scf_strerror(scf_error()));
} else {
}
}