/* * 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-scan.c,v 1.13 2006/04/13 19:00:15 ca Exp $") #if SM_LIBCONF_ALONE #include #include "sm-conf.h" #else /* SM_LIBCONF_ALONE */ #include "sm/string.h" #include "sm/memops.h" #include "sm/sm-conf.h" #endif /* SM_LIBCONF_ALONE */ #include "sm-conf-scan.h" #include "sm-conf-state.h" #include "sm-conf-type.h" /* ** SM_CONF_SCAN_VALUE_CHECK -- an error with a name, if one is there. ** ** Parameters: ** handle -- the overall handle of the configuration file ** node -- current node ** name -- name of option ** name_n -- # of bytes pointed to by ** errstring -- error string ** ** Returns: ** none */ static void named_error( sm_conf_T *handle, sm_conf_node_T const *node, char const *name, size_t name_n, char const *errstring) { char loc[SM_CONF_ERROR_BUFFER_SIZE]; if (name_n > 0 && name != NULL) sm_conf_error_add(handle, "%s: %*s: %s", sm_conf_node_location(handle, node, loc, sizeof loc), (int)name_n, name, errstring); else sm_conf_error_add(handle, "%s: %s", sm_conf_node_location(handle, node, loc, sizeof loc), errstring); } /* ** SM_CONF_SCAN_VALUE_CHECK -- check validity of value (via callback) ** ** Parameters: ** handle -- the overall handle of the configuration file ** name -- name of option ** name_n -- # of bytes pointed to by ** def -- definition ** node -- the node we're checking ** data -- user data (element itself), or NULL ** ** Returns: ** 0 on success, an error value on error. */ int sm_conf_scan_value_check( sm_conf_T *handle, char const *name, size_t name_n, sm_conf_definition_T const *def, sm_conf_node_T const *node, void *data) { size_t n_err_before; int err; SM_IS_CONF_DEF(def); /* Don't check if there's nothing to check. */ if (data == NULL) return 0; n_err_before = handle->smc_error_n; err = (* def->scd_type->sctp_value_check)(handle, def, data); /* there was an error, but it wasn't logged? */ if (err && n_err_before == handle->smc_error_n) { char errbuf[SM_CONF_ERROR_BUFFER_SIZE]; /* log it ourselves. */ named_error(handle, node, name, name_n, sm_conf_strerror(err, errbuf, sizeof errbuf)); } return err; } /* ** SM_CONF_SCAN_NODE_TO_VALUE -- convert content of node into a value ** ** Parameters: ** handle -- the overall handle of the configuration file ** name -- name of option ** name_n -- # of bytes pointed to by , need ** not be '\0'-terminated. ** def -- definition ** node -- the node we're scanning ** data -- user data (element itself), or NULL ** ** Returns: ** 0 on success, an error value on error. */ int sm_conf_scan_node_to_value( sm_conf_T *handle, char const *name, size_t name_n, sm_conf_definition_T const *def, sm_conf_node_T *node, void *data) { size_t n_err_before; int err; SM_IS_CONF_DEF(def); n_err_before = handle->smc_error_n; err = (* def->scd_type->sctp_node_to_value)(handle, def, node, data); /* there was an error, but it wasn't logged? */ if (err && n_err_before == handle->smc_error_n) { char errbuf[SM_CONF_ERROR_BUFFER_SIZE]; /* log it ourselves. */ named_error(handle, node, name, name_n, sm_conf_strerror(err, errbuf, sizeof errbuf)); } return err; } /* ** SM_CONF_SCAN_NODE -- fill out a structure according to definitions ** ** Use the data and callbacks in to translate ** the parse tree in into values assigned to the ** struct(s) pointed to by . ** ** Parameters: ** handle -- the overall handle of the configuration file ** definitions -- list of names and their meanings. ** node -- the node we're scanning ** data -- base pointer of a structure into which ** values are copied. ** ** Returns: ** 0 on success, an error value on error. */ int sm_conf_scan_node( sm_conf_T *handle, sm_conf_definition_T const *def, sm_conf_node_T *node, void *data) { int err; if (handle == NULL || def == NULL) return SM_CONF_ERR_INVALID; if (def->scd_name == NULL) { char loc[SM_CONF_ERROR_BUFFER_SIZE]; sm_conf_error_add(handle, "%s: unexpected value " "(NULL definition list)", sm_conf_node_location(handle, node, loc, sizeof loc)); return SM_CONF_ERR_INVALID; } SM_IS_CONF_DEF(def); err = sm_conf_scan_node_to_value(handle, def->scd_name, strlen(def->scd_name), def, node, data); if (err != 0) return err; return sm_conf_scan_value_check(handle, def->scd_name, strlen(def->scd_name), def, node, data); } /* ** SM_CONF_SCAN -- fill out a structure according to definitions ** ** Use the data and callbacks in to translate ** the parse tree in into values assigned to the ** struct(s) pointed to by . ** ** Parameters: ** handle -- the overall handle of the configuration file ** definitions -- list of names and their meanings. ** If it starts with a node whose name is "", ** it's a definition for the whole node; ** otherwise, the node must be a section, and ** the definitions are for the section contents. ** flags -- parameters of the node as a whole ** data -- base pointer of a structure into which ** values are copied. */ int sm_conf_scan( sm_conf_T *handle, sm_conf_definition_T const *definitions, unsigned int flags, void *data) { sm_conf_definition_T section_def[2]; if (handle == NULL) return SM_CONF_ERR_INVALID; if (definitions == NULL || definitions->scd_name == NULL) return SM_CONF_ERR_INVALID; if (definitions->scd_name[0] != '\0') { sm_memset(§ion_def, 0, sizeof section_def); section_def[0].sm_magic = SM_CONF_DEF_MAGIC; section_def[0].scd_name = ""; section_def[0].scd_type = sm_conf_type_section; section_def[0].scd_default = NULL; section_def[0].scd_flags = flags; section_def[0].scd_contents = definitions; section_def[1].scd_name = NULL; definitions = section_def; } return sm_conf_scan_node(handle, definitions, handle->smc_root, data); }