Commit 696f6f15 authored by Nick Mathewson's avatar Nick Mathewson 🏃
Browse files

Split confline into confline and conffile.

The "conffile" module knows about includes and filesystem access,
whereas confline doesn't.  This will make it possible to put these
functions into libraries without introducing a cycle.
parent 0a9d8dcf
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2018, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "common/compat.h"
#include "common/confline.h"
#include "common/conffile.h"
#include "lib/log/torlog.h"
#include "common/util.h"
#include "lib/container/smartlist.h"
static smartlist_t *config_get_file_list(const char *path,
smartlist_t *opened_files);
static int config_get_included_config(const char *path, int recursion_level,
int extended, config_line_t **config,
config_line_t **config_last,
smartlist_t *opened_lst);
static int config_process_include(const char *path, int recursion_level,
int extended, config_line_t **list,
config_line_t **list_last,
smartlist_t *opened_lst);
/** Helper: parse the config string and strdup into key/value
* strings. Set *result to the list, or NULL if parsing the string
* failed. Set *has_include to 1 if <b>result</b> has values from
* %included files. <b>opened_lst</b> will have a list of opened files if
* provided. Return 0 on success, -1 on failure. Warn and ignore any
* misformatted lines.
*
* If <b>extended</b> is set, then treat keys beginning with / and with + as
* indicating "clear" and "append" respectively. */
int
config_get_lines_include(const char *string, config_line_t **result,
int extended, int *has_include,
smartlist_t *opened_lst)
{
return config_get_lines_aux(string, result, extended, 1, has_include,
opened_lst, 1, NULL, config_process_include);
}
/** Adds a list of configuration files present on <b>path</b> to
* <b>file_list</b>. <b>path</b> can be a file or a directory. If it is a file,
* only that file will be added to <b>file_list</b>. If it is a directory,
* all paths for files on that directory root (no recursion) except for files
* whose name starts with a dot will be added to <b>file_list</b>.
* <b>opened_files</b> will have a list of files opened by this function
* if provided. Return 0 on success, -1 on failure. Ignores empty files.
*/
static smartlist_t *
config_get_file_list(const char *path, smartlist_t *opened_files)
{
smartlist_t *file_list = smartlist_new();
if (opened_files) {
smartlist_add_strdup(opened_files, path);
}
file_status_t file_type = file_status(path);
if (file_type == FN_FILE) {
smartlist_add_strdup(file_list, path);
return file_list;
} else if (file_type == FN_DIR) {
smartlist_t *all_files = tor_listdir(path);
if (!all_files) {
smartlist_free(file_list);
return NULL;
}
smartlist_sort_strings(all_files);
SMARTLIST_FOREACH_BEGIN(all_files, char *, f) {
if (f[0] == '.') {
tor_free(f);
continue;
}
char *fullname;
tor_asprintf(&fullname, "%s"PATH_SEPARATOR"%s", path, f);
tor_free(f);
if (opened_files) {
smartlist_add_strdup(opened_files, fullname);
}
if (file_status(fullname) != FN_FILE) {
tor_free(fullname);
continue;
}
smartlist_add(file_list, fullname);
} SMARTLIST_FOREACH_END(f);
smartlist_free(all_files);
return file_list;
} else if (file_type == FN_EMPTY) {
return file_list;
} else {
smartlist_free(file_list);
return NULL;
}
}
/** Creates a list of config lines present on included <b>path</b>.
* Set <b>config</b> to the list and <b>config_last</b> to the last element of
* <b>config</b>. <b>opened_lst</b> will have a list of opened files if
* provided. Return 0 on success, -1 on failure. */
static int
config_get_included_config(const char *path, int recursion_level, int extended,
config_line_t **config, config_line_t **config_last,
smartlist_t *opened_lst)
{
char *included_conf = read_file_to_str(path, 0, NULL);
if (!included_conf) {
return -1;
}
if (config_get_lines_aux(included_conf, config, extended, 1, NULL,
opened_lst, recursion_level+1, config_last,
config_process_include) < 0) {
tor_free(included_conf);
return -1;
}
tor_free(included_conf);
return 0;
}
/** Process an %include <b>path</b> in a config file. Set <b>list</b> to the
* list of configuration settings obtained and <b>list_last</b> to the last
* element of the same list. <b>opened_lst</b> will have a list of opened
* files if provided. Return 0 on success, -1 on failure. */
static int
config_process_include(const char *path, int recursion_level, int extended,
config_line_t **list, config_line_t **list_last,
smartlist_t *opened_lst)
{
config_line_t *ret_list = NULL;
config_line_t **next = &ret_list;
smartlist_t *config_files = config_get_file_list(path, opened_lst);
if (!config_files) {
return -1;
}
int rv = -1;
SMARTLIST_FOREACH_BEGIN(config_files, const char *, config_file) {
config_line_t *included_config = NULL;
if (config_get_included_config(config_file, recursion_level, extended,
&included_config, list_last,
opened_lst) < 0) {
goto done;
}
*next = included_config;
if (*list_last)
next = &(*list_last)->next;
} SMARTLIST_FOREACH_END(config_file);
*list = ret_list;
rv = 0;
done:
SMARTLIST_FOREACH(config_files, char *, f, tor_free(f));
smartlist_free(config_files);
return rv;
}
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2018, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_CONFFILE_H
#define TOR_CONFFILE_H
struct smartlist_t;
struct config_line_t;
int config_get_lines_include(const char *string, struct config_line_t **result,
int extended, int *has_include,
struct smartlist_t *opened_lst);
#endif /* !defined(TOR_CONFLINE_H) */
......@@ -10,21 +10,6 @@
#include "common/util.h"
#include "lib/container/smartlist.h"
static int config_get_lines_aux(const char *string, config_line_t **result,
int extended, int allow_include,
int *has_include, smartlist_t *opened_lst,
int recursion_level, config_line_t **last);
static smartlist_t *config_get_file_list(const char *path,
smartlist_t *opened_files);
static int config_get_included_config(const char *path, int recursion_level,
int extended, config_line_t **config,
config_line_t **config_last,
smartlist_t *opened_lst);
static int config_process_include(const char *path, int recursion_level,
int extended, config_line_t **list,
config_line_t **list_last,
smartlist_t *opened_lst);
/** Helper: allocate a new configuration option mapping 'key' to 'val',
* append it to *<b>lst</b>. */
void
......@@ -86,11 +71,12 @@ config_line_find(const config_line_t *lines,
* <b>opened_lst</b> will have a list of opened files if provided.
* Returns the a pointer to the last element of the <b>result</b> in
* <b>last</b>. */
static int
int
config_get_lines_aux(const char *string, config_line_t **result, int extended,
int allow_include, int *has_include,
smartlist_t *opened_lst, int recursion_level,
config_line_t **last)
config_line_t **last,
include_handler_fn handle_include)
{
config_line_t *list = NULL, **next, *list_last = NULL;
char *k, *v;
......@@ -133,13 +119,13 @@ config_get_lines_aux(const char *string, config_line_t **result, int extended,
}
}
if (allow_include && !strcmp(k, "%include")) {
if (allow_include && !strcmp(k, "%include") && handle_include) {
tor_free(k);
include_used = 1;
config_line_t *include_list;
if (config_process_include(v, recursion_level, extended, &include_list,
&list_last, opened_lst) < 0) {
if (handle_include(v, recursion_level, extended, &include_list,
&list_last, opened_lst) < 0) {
log_warn(LD_CONFIG, "Error reading included configuration "
"file or directory: \"%s\".", v);
config_free_lines(list);
......@@ -178,152 +164,12 @@ config_get_lines_aux(const char *string, config_line_t **result, int extended,
return 0;
}
/** Helper: parse the config string and strdup into key/value
* strings. Set *result to the list, or NULL if parsing the string
* failed. Set *has_include to 1 if <b>result</b> has values from
* %included files. <b>opened_lst</b> will have a list of opened files if
* provided. Return 0 on success, -1 on failure. Warn and ignore any
* misformatted lines.
*
* If <b>extended</b> is set, then treat keys beginning with / and with + as
* indicating "clear" and "append" respectively. */
int
config_get_lines_include(const char *string, config_line_t **result,
int extended, int *has_include,
smartlist_t *opened_lst)
{
return config_get_lines_aux(string, result, extended, 1, has_include,
opened_lst, 1, NULL);
}
/** Same as config_get_lines_include but does not allow %include */
int
config_get_lines(const char *string, config_line_t **result, int extended)
{
return config_get_lines_aux(string, result, extended, 0, NULL, NULL, 1,
NULL);
}
/** Adds a list of configuration files present on <b>path</b> to
* <b>file_list</b>. <b>path</b> can be a file or a directory. If it is a file,
* only that file will be added to <b>file_list</b>. If it is a directory,
* all paths for files on that directory root (no recursion) except for files
* whose name starts with a dot will be added to <b>file_list</b>.
* <b>opened_files</b> will have a list of files opened by this function
* if provided. Return 0 on success, -1 on failure. Ignores empty files.
*/
static smartlist_t *
config_get_file_list(const char *path, smartlist_t *opened_files)
{
smartlist_t *file_list = smartlist_new();
if (opened_files) {
smartlist_add_strdup(opened_files, path);
}
file_status_t file_type = file_status(path);
if (file_type == FN_FILE) {
smartlist_add_strdup(file_list, path);
return file_list;
} else if (file_type == FN_DIR) {
smartlist_t *all_files = tor_listdir(path);
if (!all_files) {
smartlist_free(file_list);
return NULL;
}
smartlist_sort_strings(all_files);
SMARTLIST_FOREACH_BEGIN(all_files, char *, f) {
if (f[0] == '.') {
tor_free(f);
continue;
}
char *fullname;
tor_asprintf(&fullname, "%s"PATH_SEPARATOR"%s", path, f);
tor_free(f);
if (opened_files) {
smartlist_add_strdup(opened_files, fullname);
}
if (file_status(fullname) != FN_FILE) {
tor_free(fullname);
continue;
}
smartlist_add(file_list, fullname);
} SMARTLIST_FOREACH_END(f);
smartlist_free(all_files);
return file_list;
} else if (file_type == FN_EMPTY) {
return file_list;
} else {
smartlist_free(file_list);
return NULL;
}
}
/** Creates a list of config lines present on included <b>path</b>.
* Set <b>config</b> to the list and <b>config_last</b> to the last element of
* <b>config</b>. <b>opened_lst</b> will have a list of opened files if
* provided. Return 0 on success, -1 on failure. */
static int
config_get_included_config(const char *path, int recursion_level, int extended,
config_line_t **config, config_line_t **config_last,
smartlist_t *opened_lst)
{
char *included_conf = read_file_to_str(path, 0, NULL);
if (!included_conf) {
return -1;
}
if (config_get_lines_aux(included_conf, config, extended, 1, NULL,
opened_lst, recursion_level+1, config_last) < 0) {
tor_free(included_conf);
return -1;
}
tor_free(included_conf);
return 0;
}
/** Process an %include <b>path</b> in a config file. Set <b>list</b> to the
* list of configuration settings obtained and <b>list_last</b> to the last
* element of the same list. <b>opened_lst</b> will have a list of opened
* files if provided. Return 0 on success, -1 on failure. */
static int
config_process_include(const char *path, int recursion_level, int extended,
config_line_t **list, config_line_t **list_last,
smartlist_t *opened_lst)
{
config_line_t *ret_list = NULL;
config_line_t **next = &ret_list;
smartlist_t *config_files = config_get_file_list(path, opened_lst);
if (!config_files) {
return -1;
}
int rv = -1;
SMARTLIST_FOREACH_BEGIN(config_files, const char *, config_file) {
config_line_t *included_config = NULL;
if (config_get_included_config(config_file, recursion_level, extended,
&included_config, list_last,
opened_lst) < 0) {
goto done;
}
*next = included_config;
if (*list_last)
next = &(*list_last)->next;
} SMARTLIST_FOREACH_END(config_file);
*list = ret_list;
rv = 0;
done:
SMARTLIST_FOREACH(config_files, char *, f, tor_free(f));
smartlist_free(config_files);
return rv;
NULL, NULL);
}
/**
......
......@@ -44,10 +44,6 @@ const config_line_t *config_line_find(const config_line_t *lines,
const char *key);
int config_lines_eq(config_line_t *a, config_line_t *b);
int config_count_key(const config_line_t *a, const char *key);
int config_get_lines(const char *string, config_line_t **result, int extended);
int config_get_lines_include(const char *string, config_line_t **result,
int extended, int *has_include,
struct smartlist_t *opened_lst);
void config_free_lines_(config_line_t *front);
#define config_free_lines(front) \
do { \
......@@ -57,4 +53,20 @@ void config_free_lines_(config_line_t *front);
const char *parse_config_line_from_str_verbose(const char *line,
char **key_out, char **value_out,
const char **err_out);
int config_get_lines(const char *string, struct config_line_t **result,
int extended);
typedef int (*include_handler_fn)(const char *, int, int,
struct config_line_t **,
struct config_line_t **,
struct smartlist_t *);
int config_get_lines_aux(const char *string, struct config_line_t **result,
int extended,
int allow_include, int *has_include,
struct smartlist_t *opened_lst, int recursion_level,
config_line_t **last,
include_handler_fn handle_include);
#endif /* !defined(TOR_CONFLINE_H) */
......@@ -37,6 +37,7 @@ LIBOR_A_SRC = \
src/common/compat_threads.c \
src/common/compat_time.c \
src/common/confline.c \
src/common/conffile.c \
src/common/memarea.c \
src/common/util.c \
src/common/util_process.c \
......@@ -79,6 +80,7 @@ COMMONHEADERS = \
src/common/compat_libevent.h \
src/common/compat_threads.h \
src/common/compat_time.h \
src/common/conffile.h \
src/common/confline.h \
src/common/handles.h \
src/common/memarea.h \
......
......@@ -111,6 +111,7 @@
#include <shlobj.h>
#endif
#include "common/conffile.h"
#include "common/procmon.h"
#include "or/dirauth/dirvote.h"
......
......@@ -48,6 +48,8 @@
#include "or/port_cfg_st.h"
#include "or/routerinfo_st.h"
#include "common/conffile.h"
static void
test_config_addressmap(void *arg)
{
......@@ -5731,4 +5733,3 @@ struct testcase_t config_tests[] = {
CONFIG_TEST(compute_max_mem_in_queues, 0),
END_OF_TESTCASES
};
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment