/*
* Copyright (c) 2004-2006 Sendmail, Inc. and its suppliers.
* All rights reserved.
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the sendmail distribution.
*/
#include "sm/generic.h"
SM_RCSID("@(#)$Id: sm-conf-prtcnf.c,v 1.25 2006/04/21 17:52:02 ca Exp $")
#include "sm/string.h"
#include "sm/sm-conf.h"
#include "sm/sm-conf-prt.h"
#include "sm-conf-type.h"
#include "sm/io.h"
#include "sm/str.h"
#include "sm/util.h"
#include "sm/sm-conf-prt.h"
#include "prtcnf.h"
/*
** Show configuration data.
** This shows the data that is actually read from a configuration file
** and stored in a structure.
*/
#define PRT_COMMENT(fp) \
do \
{ \
if (def->scd_description != NULL && \
*(def->scd_description) != '\0') \
{ \
prt_fmtted((fp), indent, "# ", def->scd_description); \
} \
} while (0)
/*
** SM_CONF_SUB2DEF -- convert a value into its string representation
**
** Parameters:
** def -- sentinel-terminated array of subdefinitions.
** type -- if non-NULL, only entries of this type are
** taken into account
** val -- (choice) value to convert
** prefix -- print before value
** postfix -- print after value
** fp -- file for output
**
** Returns:
** SM_SUCCESS
*/
int
sm_conf_sub2valbit(sm_conf_definition_T const *def, sm_conf_type_T const *type, uint32_t val, const char *prefix, const char *postfix, int indent, sm_file_T *fp)
{
SM_IS_CONF_DEF(def);
while (def->scd_name != NULL)
{
if ((type == NULL || def->scd_type == type) &&
(val & def->scd_offset) != 0 &&
!SM_IS_FLAG(SM_CONF_FLAG_DONTPRINT, def->scd_flags)
)
{
PRT_COMMENT(fp);
sm_io_fprintf(fp, "%*s%s%s%s", indent, "",
prefix, def->scd_name, postfix);
}
def++;
}
return SM_SUCCESS;
}
/*
** SM_CONF_SUB2DEF -- convert a value into its string representation
**
** Parameters:
** def -- sentinel-terminated array of subdefinitions.
** type -- if non-NULL, only entries of this type are
** taken into account
** val -- (choice) value to convert
** fp -- file for output
**
** Returns:
** SM_SUCCESS
*/
int
sm_conf_sub2valeq(sm_conf_definition_T const *def, sm_conf_type_T const *type, uint32_t val, sm_file_T *fp)
{
SM_IS_CONF_DEF(def);
while (def->scd_name != NULL)
{
if ((type == NULL || def->scd_type == type) &&
val == def->scd_offset)
{
sm_io_fprintf(fp, "%s", def->scd_name);
break;
}
def++;
}
return SM_SUCCESS;
}
#define PRT_TEXT \
do \
{ \
if (text != NULL && sm_str_getlen(text) > 0) \
{ \
sm_io_fprintf(fp, "%S", text); \
sm_str_clr(text); \
} \
} while (0)
/*
** SM_CONF_PRT_UNION -- print content of one node
**
** Parameters:
** def -- configuration definition.
** cnf -- pointer to structure holding the configuration data
** offset -- current offset in struct (cnf)
** fp -- file for output
** indent -- current indentation
** prefix -- prefix to print (if not NULL)
** in case of a section: append section name (+ delimiter)
** text -- if not NULL: print this if something is printed
** in this invocation
**
** Returns:
** 0: didn't print anything
** >0: something has been printed
*/
static int
sm_conf_prt_union(const sm_conf_definition_T *def, const sm_conf_definition_T *union_def, const void *cnf, sm_file_T *fp, int indent, sm_str_P prefix, sm_str_P text)
{
int ret, choice_type;
bool printed;
printed = false;
ret = 0;
choice_type = 0;
if (union_def != NULL
&& union_def->scd_type == sm_conf_type_union_type)
{
bool found;
ptrdiff_t offtype;
const sm_conf_definition_T *union_choice_def;
offtype = union_def->scd_offset;
/* fixme: how to find the right size for the type?? */
choice_type = *(int *)(((char *)cnf) + offtype);
found = false;
union_choice_def = union_def + 1;
while (union_choice_def != NULL
&& union_choice_def->sm_magic == SM_CONF_DEF_MAGIC
&& union_choice_def->scd_name != NULL
&& union_choice_def->scd_type
== sm_conf_type_union_choice
&& !found
)
{
if ((int) union_choice_def->scd_offset == choice_type)
found = true;
else
++union_choice_def;
}
if (found)
{
const char *name;
PRT_TEXT;
PRT_COMMENT(fp);
name = NULL;
if (union_choice_def->scd_contents->scd_type ==
sm_conf_type_section_title)
{
ptrdiff_t off;
off = union_choice_def->scd_contents->scd_offset;
name = (char *)*((char **)(((char *)cnf) + off));
}
sm_io_fprintf(fp, "%*s%s %s%s{\n"
, indent, ""
, def->scd_name
, name != NULL ? name : ""
, name != NULL ? " " : ""
);
sm_conf_prt_cnfs(union_choice_def->scd_contents,
cnf, 0, fp, indent + 2, prefix, text);
sm_io_fprintf(fp, "%*s}\n"
, indent, "");
printed = true;
ret = 1;
}
}
if (!printed && choice_type != 0)
{
sm_io_fprintf(fp,
"%*s# %s=union-COULD-NOT-BE-PRINTED;\n"
, indent, ""
, def->scd_name);
}
return ret;
}
/*
** SM_CONF_PRT_CNF -- print content of one node
**
** Parameters:
** def -- configuration definition.
** cnf -- pointer to structure holding the configuration data
** offset -- current offset in struct (cnf)
** fp -- file for output
** indent -- current indentation
** prefix -- prefix to print (if not NULL)
** in case of a section: append section name (+ delimiter)
** text -- if not NULL: print this if something is printed
** in this invocation
**
** Returns:
** 0: didn't print anything
** >0: something has been printed
*/
#define SM_C_DELIM '.'
#define SM_S_OPEN '['
#define SM_S_CLOSE ']'
static int
sm_conf_prt_cnf(const sm_conf_definition_T *def, const void *cnf, ptrdiff_t offset, sm_file_T *fp, int indent, sm_str_P prefix, sm_str_P text)
{
const sm_conf_type_T *scdtype;
ptrdiff_t off;
int ret;
char *s;
SM_IS_CONF_DEF(def);
scdtype = def->scd_type;
if (scdtype == NULL)
return 0;
ret = 0;
#define PRT_PREFIX \
do \
{ \
if (prefix != NULL) \
sm_io_fprintf(fp, "%S", prefix); \
} while (0)
off = offset + def->scd_offset;
#define CNF_VAL (((char *)cnf) + off)
if (SM_IS_FLAG(def->scd_flags, SM_CONF_FLAG_DPRCD))
return 0;
if (scdtype == sm_conf_type_section)
{
if (prefix != NULL)
{
sm_ret_T ret;
size_t oldlen;
PRT_COMMENT(fp);
oldlen = sm_str_getlen(prefix);
ret = sm_str_scat(prefix, def->scd_name);
if (sm_is_err(ret))
return ret;
#if 0
if (def->scn_section.scns_keyword != NULL)
{
ret = sm_str_scat0(prefix,
def->scd_name);
if (sm_is_err(ret))
return ret;
}
#endif /* 0 */
ret = sm_str_put(prefix, SM_C_DELIM);
if (sm_is_err(ret))
return ret;
sm_conf_prt_cnfs(def->scd_contents, cnf,
off, fp, indent + 2, prefix, text);
SM_STR_SETLEN(prefix, oldlen);
}
else
{
int r;
if (text != NULL)
{
sm_file_T text_fp;
/* currently doesn't fail; check?? */
(void) sm_str2file(text, &text_fp);
PRT_COMMENT(&text_fp);
sm_strprintf(text, "%*s%s {\n"
, indent, ""
, def->scd_name);
}
else
{
PRT_TEXT;
PRT_COMMENT(fp);
sm_io_fprintf(fp, "%*s%s {\n"
, indent, ""
, def->scd_name);
}
r = sm_conf_prt_cnfs(def->scd_contents, cnf, off,
fp, indent + 2, prefix, text);
if (r > 0)
{
sm_io_fprintf(fp, "%*s}\n"
, indent, "");
ret += r;
}
/*
** This doesn't work for nested sections!
** we "just" need to get back to the old text
** (see above how prefix is handled).
*/
if (text != NULL)
sm_str_clr(text);
}
}
else if (scdtype == sm_conf_type_section_title)
{
#if 0
/*
** this shouldn't be printed here as it belongs
** in the section header
*/
s = (char *)*((char **)CNF_VAL);
if (s != NULL)
{
PRT_TEXT;
PRT_COMMENT(fp);
sm_io_fprintf(fp, "%*s", indent, "");
PRT_PREFIX;
sm_io_fprintf(fp, "%s" , s);
ret = 1;
}
#endif
}
else if (scdtype == sm_conf_type_string)
{
s = (char *)*((char **)CNF_VAL);
if (s != NULL)
{
PRT_TEXT;
PRT_COMMENT(fp);
sm_io_fprintf(fp, "%*s", indent, "");
PRT_PREFIX;
sm_io_fprintf(fp, "%s=\"%s\";\n"
, def->scd_name
, s);
ret = 1;
}
}
else if (scdtype == sm_conf_type_char)
{
uchar c;
c = *((uchar *)CNF_VAL);
if (c != '\0')
{
PRT_TEXT;
PRT_COMMENT(fp);
sm_io_fprintf(fp, "%*s", indent, "");
PRT_PREFIX;
sm_io_fprintf(fp, "%s=\"%c\";\n"
, def->scd_name
, c);
ret = 1;
}
}
else if (scdtype == sm_conf_type_u32)
{
PRT_TEXT;
PRT_COMMENT(fp);
sm_io_fprintf(fp, "%*s", indent, "");
PRT_PREFIX;
if (def->scd_contents != NULL &&
def->scd_contents->scd_type ==
sm_conf_type_u32_suffix &&
def->scd_size == sizeof(uint32_t))
{
sm_io_fprintf(fp, "%s=", def->scd_name);
sm_u32totxtwsuffix(def, *(uint32_t *)CNF_VAL,
fp);
sm_io_fprintf(fp, ";\n");
ret = 1;
}
else if (def->scd_size == sizeof(uint32_t))
{
sm_io_fprintf(fp,
((def->scd_flags & SM_CONF_FLAG_HEX) == 0)
? "%s=%lu;\n" : "%s=%#lx;\n"
, def->scd_name
, (unsigned long)*(uint32_t *)CNF_VAL);
ret = 1;
}
else if (def->scd_size == sizeof(uint16_t))
{
sm_io_fprintf(fp,
((def->scd_flags & SM_CONF_FLAG_HEX) == 0)
? "%s=%u;\n" : "%s=%#x;\n"
, def->scd_name
, (unsigned int)*(uint16_t *)CNF_VAL);
ret = 1;
}
else if (def->scd_size == sizeof(uint8_t))
{
sm_io_fprintf(fp,
((def->scd_flags & SM_CONF_FLAG_HEX) == 0)
? "%s=%hu;\n" : "%s=%#hx;\n"
, def->scd_name
, (unsigned short)*(uint8_t *)CNF_VAL);
ret = 1;
}
}
else if (scdtype == sm_conf_type_bool)
{
uint val;
PRT_TEXT;
PRT_COMMENT(fp);
sm_io_fprintf(fp, "%*s", indent, "");
PRT_PREFIX;
val = 0;
if (def->scd_size == sizeof(uint32_t))
val = (uint)*(uint32_t *)CNF_VAL;
else if (def->scd_size == sizeof(uint16_t))
val = (uint)*(uint16_t *)CNF_VAL;
else if (def->scd_size == sizeof(uint8_t))
val = (uint)*(uint8_t *)CNF_VAL;
sm_io_fprintf(fp, "%s=%s;\n"
, def->scd_name
, val ? "true" : "false");
ret = 1;
}
else if (scdtype == sm_conf_type_ipv4)
{
PRT_TEXT;
PRT_COMMENT(fp);
sm_io_fprintf(fp, "%*s", indent, "");
PRT_PREFIX;
sm_io_fprintf(fp, "%s=%A;\n"
, def->scd_name
, *(uint32_t *)CNF_VAL);
ret = 1;
}
else if (scdtype == sm_conf_type_argv)
{
size_t i;
char **argv;
argv = (char **)CNF_VAL;
if (argv != NULL && argv[0] != NULL)
{
PRT_TEXT;
PRT_COMMENT(fp);
sm_io_fprintf(fp, "%*s%s={"
, indent, ""
, def->scd_name);
for (i = 0; (s = argv[i]) != NULL; i++)
sm_io_fprintf(fp, "%s, ", s);
sm_io_fprintf(fp, "}\n");
ret = i;
}
}
else if (scdtype == sm_conf_type_choice)
{
uint32_t u;
u = *(uint32_t *)CNF_VAL;
if (u != 0 &&
(def->scd_flags & SM_CONF_FLAG_MULTIPLE) != 0)
{
PRT_TEXT;
PRT_COMMENT(fp);
sm_io_fprintf(fp, "%*s%s={\n"
, indent, ""
, def->scd_name);
(void) sm_conf_sub2valbit(def->scd_contents,
NULL, u, "", ",\n", indent + 2, fp);
sm_io_fprintf(fp, "%*s}\n", indent, "");
ret = 1;
}
else if (u != 0 &&
(def->scd_flags & SM_CONF_FLAG_OR) != 0)
{
PRT_TEXT;
PRT_COMMENT(fp);
sm_io_fprintf(fp, "%*s%s="
, indent, ""
, def->scd_name);
(void) sm_conf_sub2valbit(def->scd_contents,
NULL, u, "", "", indent, fp);
sm_io_fprintf(fp, ";\n");
ret = 1;
}
else if (u != 0)
{
PRT_TEXT;
PRT_COMMENT(fp);
sm_io_fprintf(fp, "%*s%s="
, indent, ""
, def->scd_name);
(void) sm_conf_sub2valeq(def->scd_contents,
NULL, u, fp);
sm_io_fprintf(fp, ";\n");
ret = 1;
}
}
else if (scdtype == sm_conf_type_array)
{
unsigned int n, i;
ptrdiff_t offn;
char *ptr;
const sm_conf_definition_T *array = def->scd_contents;
if (array[0].scd_name != NULL &&
array[0].scd_type == sm_conf_type_section &&
array[1].scd_name != NULL &&
array[1].scd_type == sm_conf_type_array_n
)
{
const char *name;
name = NULL;
PRT_TEXT;
PRT_COMMENT(fp);
offn = offset + array[1].scd_offset;
n = *(unsigned int *) (((char *)cnf) + offn);
ret = n;
offn = offset + array[0].scd_offset;
if (def->scd_size > 0)
ptr = ((char *)cnf) + offn;
else
ptr = *(char **) (((char *)cnf) + offn);
for (i = 0; i < n; i++)
{
offn = i * array[0].scd_size;
if (array[0].scd_contents->scd_type ==
sm_conf_type_section_title)
{
ptrdiff_t offl;
offl = array[0].scd_contents->scd_offset
+ offn;
name = (char *)*((char **)(((char *)ptr)
+ offl));
}
sm_io_fprintf(fp, "%*s%s %s%s{\n"
, indent, ""
, def->scd_name
, name != NULL ? name : ""
, name != NULL ? " " : ""
);
sm_conf_prt_cnfs(array[0].scd_contents,
ptr, offn,
fp, indent + 2, prefix, text);
sm_io_fprintf(fp, "%*s}\n"
, indent, "");
}
}
else if (array[0].scd_name != NULL &&
array[0].scd_type == sm_conf_type_union &&
array[1].scd_name != NULL &&
array[1].scd_type == sm_conf_type_array_n
)
{
PRT_TEXT;
/* PRT_COMMENT(fp); */
/* get number of elements in array */
offn = offset + array[1].scd_offset;
n = *(unsigned int *) (((char *)cnf) + offn);
/* get pointer to array */
offn = offset + array[0].scd_offset;
if (def->scd_size > 0)
ptr = ((char *)cnf) + offn;
else
ptr = *(char **) (((char *)cnf) + offn);
ret = n;
for (i = 0; i < n; i++)
{
ret = sm_conf_prt_union(def,
array[0].scd_contents,
ptr + i * array[0].scd_size,
fp, indent + 2, prefix, text);
}
}
}
else if (scdtype == sm_conf_type_union)
{
ret = sm_conf_prt_union(def, def->scd_contents,
(char *)cnf + off, fp,
indent, prefix, text);
}
else if (scdtype == sm_conf_type_union_choice)
{
sm_io_fprintf(fp,
"%*s# %s=union-choice-COULD-NOT-BE-PRINTED;\n"
, indent, ""
, def->scd_name);
}
else
{
sm_io_fprintf(fp, "%*s# %s=unknown-%p-COULD-NOT-BE-PRINTED;\n"
, indent, ""
, def->scd_name, scdtype);
}
return ret;
}
/*
** SM_CONF_PRT_CNFS -- print content of configuration tree
**
** Parameters:
** def -- configuration definition.
** cnf -- pointer to structure holding the configuration data
** offset -- current offset in struct (cnf)
** fp -- file for output
** indent -- current indentation
** prefix -- prefix to print (if not NULL)
** in case of a section: append section name (+ delimiter)
** text -- if not NULL: print this if something is printed
** in this invocation
**
** Returns:
** SM_SUCCESS
*/
int
sm_conf_prt_cnfs(const sm_conf_definition_T *defs, const void *cnf, ptrdiff_t offset, sm_file_T *fp, int indent, sm_str_P prefix, sm_str_P text)
{
const sm_conf_definition_T *def;
int r;
r = 0;
while ((def = defs++) != NULL && def->scd_name != NULL)
{
SM_IS_CONF_DEF(def);
r += sm_conf_prt_cnf(def, cnf, offset, fp, indent, prefix,
text);
}
return r;
}
/*
** SM_CONF_PRT_CONF -- print content of configuration tree
** (wrapper for sm_conf_prt_cnfs())
**
** Parameters:
** def -- configuration definition.
** cnf -- pointer to structure holding the configuration data
** fp -- file for output
**
** Returns:
** SM_SUCCESS or ENOMEM
*/
int
sm_conf_prt_conf(const sm_conf_definition_T *defs, const void *cnf, sm_file_T *fp)
{
int ret;
sm_str_P sect_text;
sect_text = sm_str_new(NULL, 256, 8 * 1024);
if (sect_text == NULL)
return sm_err_temp(ENOMEM);
ret = sm_conf_prt_cnfs(defs, cnf, 0, fp, 0, NULL, sect_text);
SM_STR_FREE(sect_text);
return ret;
}
syntax highlighted by Code2HTML, v. 0.9.1