/* * 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; }