Merge pull request #109 from ifupdown-ng/feature/include-loop-detection
refactor config file management
This commit is contained in:
commit
086eca2b4e
5 changed files with 150 additions and 87 deletions
|
@ -247,6 +247,9 @@ ifquery_main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
struct lif_dict state = {};
|
struct lif_dict state = {};
|
||||||
struct lif_dict collection = {};
|
struct lif_dict collection = {};
|
||||||
|
struct lif_interface_file_parse_state parse_state = {
|
||||||
|
.collection = &collection,
|
||||||
|
};
|
||||||
|
|
||||||
lif_interface_collection_init(&collection);
|
lif_interface_collection_init(&collection);
|
||||||
|
|
||||||
|
@ -256,7 +259,7 @@ ifquery_main(int argc, char *argv[])
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!lif_interface_file_parse(&collection, exec_opts.interfaces_file))
|
if (!lif_interface_file_parse(&parse_state, exec_opts.interfaces_file))
|
||||||
{
|
{
|
||||||
fprintf(stderr, "%s: could not parse %s\n", argv0, exec_opts.interfaces_file);
|
fprintf(stderr, "%s: could not parse %s\n", argv0, exec_opts.interfaces_file);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
|
|
|
@ -237,6 +237,9 @@ ifupdown_main(int argc, char *argv[])
|
||||||
|
|
||||||
struct lif_dict state = {};
|
struct lif_dict state = {};
|
||||||
struct lif_dict collection = {};
|
struct lif_dict collection = {};
|
||||||
|
struct lif_interface_file_parse_state parse_state = {
|
||||||
|
.collection = &collection,
|
||||||
|
};
|
||||||
|
|
||||||
lif_interface_collection_init(&collection);
|
lif_interface_collection_init(&collection);
|
||||||
|
|
||||||
|
@ -246,7 +249,7 @@ ifupdown_main(int argc, char *argv[])
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!lif_interface_file_parse(&collection, exec_opts.interfaces_file))
|
if (!lif_interface_file_parse(&parse_state, exec_opts.interfaces_file))
|
||||||
{
|
{
|
||||||
fprintf(stderr, "%s: could not parse %s\n", argv0, exec_opts.interfaces_file);
|
fprintf(stderr, "%s: could not parse %s\n", argv0, exec_opts.interfaces_file);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
|
|
|
@ -47,6 +47,12 @@ with an address of *203.0.113.2* and gateway of *203.0.113.1*.
|
||||||
associated with the declaration will be stored inside
|
associated with the declaration will be stored inside
|
||||||
_object_.
|
_object_.
|
||||||
|
|
||||||
|
*source* _filename_
|
||||||
|
Includes the file _filename_ as configuration data.
|
||||||
|
|
||||||
|
*source-directory* _directory_
|
||||||
|
Includes the files in _directory_ as configuration data.
|
||||||
|
|
||||||
*template* _object_
|
*template* _object_
|
||||||
Begins a new declaration for _object_, like *iface*, except
|
Begins a new declaration for _object_, like *iface*, except
|
||||||
that _object_ is defined as a *template*.
|
that _object_ is defined as a *template*.
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <errno.h>
|
||||||
#include "libifupdown/libifupdown.h"
|
#include "libifupdown/libifupdown.h"
|
||||||
|
|
||||||
/* internally rewrite problematic ifupdown2 tokens to ifupdown-ng equivalents */
|
/* internally rewrite problematic ifupdown2 tokens to ifupdown-ng equivalents */
|
||||||
|
@ -117,11 +119,8 @@ maybe_remap_token(const char *token)
|
||||||
return tokbuf;
|
return tokbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XXX: remove this global variable somehow */
|
|
||||||
static struct lif_interface *cur_iface = NULL;
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
report_error(const char *filename, size_t lineno, const char *errfmt, ...)
|
report_error(struct lif_interface_file_parse_state *state, const char *errfmt, ...)
|
||||||
{
|
{
|
||||||
char errbuf[4096];
|
char errbuf[4096];
|
||||||
|
|
||||||
|
@ -130,84 +129,76 @@ report_error(const char *filename, size_t lineno, const char *errfmt, ...)
|
||||||
vsnprintf(errbuf, sizeof errbuf, errfmt, va);
|
vsnprintf(errbuf, sizeof errbuf, errfmt, va);
|
||||||
va_end(va);
|
va_end(va);
|
||||||
|
|
||||||
fprintf(stderr, "%s:%zu: %s\n", filename, lineno, errbuf);
|
fprintf(stderr, "%s:%zu: %s\n", state->cur_filename, state->cur_lineno, errbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
handle_address(struct lif_dict *collection, const char *filename, size_t lineno, char *token, char *bufp)
|
handle_address(struct lif_interface_file_parse_state *state, char *token, char *bufp)
|
||||||
{
|
{
|
||||||
(void) collection;
|
|
||||||
(void) token;
|
(void) token;
|
||||||
|
|
||||||
char *addr = lif_next_token(&bufp);
|
char *addr = lif_next_token(&bufp);
|
||||||
|
|
||||||
if (cur_iface == NULL)
|
if (state->cur_iface == NULL)
|
||||||
{
|
{
|
||||||
report_error(filename, lineno, "%s '%s' without interface", token, addr);
|
report_error(state, "%s '%s' without interface", token, addr);
|
||||||
/* Ignore this address, but don't fail hard */
|
/* Ignore this address, but don't fail hard */
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
lif_interface_address_add(cur_iface, addr);
|
lif_interface_address_add(state->cur_iface, addr);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
handle_auto(struct lif_dict *collection, const char *filename, size_t lineno, char *token, char *bufp)
|
handle_auto(struct lif_interface_file_parse_state *state, char *token, char *bufp)
|
||||||
{
|
{
|
||||||
(void) filename;
|
|
||||||
(void) lineno;
|
|
||||||
(void) token;
|
(void) token;
|
||||||
|
|
||||||
char *ifname = lif_next_token(&bufp);
|
char *ifname = lif_next_token(&bufp);
|
||||||
if (!*ifname && cur_iface == NULL)
|
if (!*ifname && state->cur_iface == NULL)
|
||||||
{
|
{
|
||||||
report_error(filename, lineno, "auto without interface");
|
report_error(state, "auto without interface");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cur_iface = lif_interface_collection_find(collection, ifname);
|
state->cur_iface = lif_interface_collection_find(state->collection, ifname);
|
||||||
if (cur_iface == NULL)
|
if (state->cur_iface == NULL)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cur_iface->is_template)
|
if (!state->cur_iface->is_template)
|
||||||
cur_iface->is_auto = true;
|
state->cur_iface->is_auto = true;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
handle_gateway(struct lif_dict *collection, const char *filename, size_t lineno, char *token, char *bufp)
|
handle_gateway(struct lif_interface_file_parse_state *state, char *token, char *bufp)
|
||||||
{
|
{
|
||||||
(void) collection;
|
|
||||||
(void) token;
|
(void) token;
|
||||||
|
|
||||||
char *addr = lif_next_token(&bufp);
|
char *addr = lif_next_token(&bufp);
|
||||||
|
|
||||||
if (cur_iface == NULL)
|
if (state->cur_iface == NULL)
|
||||||
{
|
{
|
||||||
report_error(filename, lineno, "%s '%s' without interface", token, addr);
|
report_error(state, "%s '%s' without interface", token, addr);
|
||||||
/* Ignore this gateway, but don't fail hard */
|
/* Ignore this gateway, but don't fail hard */
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
lif_interface_use_executor(cur_iface, "static");
|
lif_interface_use_executor(state->cur_iface, "static");
|
||||||
lif_dict_add(&cur_iface->vars, token, strdup(addr));
|
lif_dict_add(&state->cur_iface->vars, token, strdup(addr));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
handle_generic(struct lif_dict *collection, const char *filename, size_t lineno, char *token, char *bufp)
|
handle_generic(struct lif_interface_file_parse_state *state, char *token, char *bufp)
|
||||||
{
|
{
|
||||||
(void) collection;
|
if (state->cur_iface == NULL)
|
||||||
(void) filename;
|
|
||||||
(void) lineno;
|
|
||||||
|
|
||||||
if (cur_iface == NULL)
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
token = maybe_remap_token(token);
|
token = maybe_remap_token(token);
|
||||||
|
@ -216,7 +207,7 @@ handle_generic(struct lif_dict *collection, const char *filename, size_t lineno,
|
||||||
while (isspace (*bufp))
|
while (isspace (*bufp))
|
||||||
bufp++;
|
bufp++;
|
||||||
|
|
||||||
lif_dict_add(&cur_iface->vars, token, strdup(bufp));
|
lif_dict_add(&state->cur_iface->vars, token, strdup(bufp));
|
||||||
|
|
||||||
/* Check if token looks like <word1>-<word*> and assume <word1> is an addon */
|
/* Check if token looks like <word1>-<word*> and assume <word1> is an addon */
|
||||||
char *word_end = strchr(token, '-');
|
char *word_end = strchr(token, '-');
|
||||||
|
@ -224,40 +215,40 @@ handle_generic(struct lif_dict *collection, const char *filename, size_t lineno,
|
||||||
{
|
{
|
||||||
/* Copy word1 to not mangle *token */
|
/* Copy word1 to not mangle *token */
|
||||||
char *addon = strndup(token, word_end - token);
|
char *addon = strndup(token, word_end - token);
|
||||||
lif_interface_use_executor(cur_iface, addon);
|
lif_interface_use_executor(state->cur_iface, addon);
|
||||||
free(addon);
|
free(addon);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool handle_inherit(struct lif_dict *collection, const char *filename, size_t lineno, char *token, char *bufp);
|
static bool handle_inherit(struct lif_interface_file_parse_state *state, char *token, char *bufp);
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
handle_iface(struct lif_dict *collection, const char *filename, size_t lineno, char *token, char *bufp)
|
handle_iface(struct lif_interface_file_parse_state *state, char *token, char *bufp)
|
||||||
{
|
{
|
||||||
char *ifname = lif_next_token(&bufp);
|
char *ifname = lif_next_token(&bufp);
|
||||||
if (!*ifname)
|
if (!*ifname)
|
||||||
{
|
{
|
||||||
report_error(filename, lineno, "%s without any other tokens", token);
|
report_error(state, "%s without any other tokens", token);
|
||||||
/* This is broken but not fatal */
|
/* This is broken but not fatal */
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
cur_iface = lif_interface_collection_find(collection, ifname);
|
state->cur_iface = lif_interface_collection_find(state->collection, ifname);
|
||||||
if (cur_iface == NULL)
|
if (state->cur_iface == NULL)
|
||||||
{
|
{
|
||||||
report_error(filename, lineno, "could not upsert interface %s", ifname);
|
report_error(state, "could not upsert interface %s", ifname);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* mark the cur_iface as a template iface if `template` keyword
|
/* mark the state->cur_iface as a template iface if `template` keyword
|
||||||
* is used.
|
* is used.
|
||||||
*/
|
*/
|
||||||
if (!strcmp(token, "template"))
|
if (!strcmp(token, "template"))
|
||||||
{
|
{
|
||||||
cur_iface->is_auto = false;
|
state->cur_iface->is_auto = false;
|
||||||
cur_iface->is_template = true;
|
state->cur_iface->is_template = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* in original ifupdown config, we can have "inet loopback"
|
/* in original ifupdown config, we can have "inet loopback"
|
||||||
|
@ -268,12 +259,12 @@ handle_iface(struct lif_dict *collection, const char *filename, size_t lineno, c
|
||||||
while (*token)
|
while (*token)
|
||||||
{
|
{
|
||||||
if (!strcmp(token, "dhcp"))
|
if (!strcmp(token, "dhcp"))
|
||||||
lif_interface_use_executor(cur_iface, "dhcp");
|
lif_interface_use_executor(state->cur_iface, "dhcp");
|
||||||
else if (!strcmp(token, "ppp"))
|
else if (!strcmp(token, "ppp"))
|
||||||
lif_interface_use_executor(cur_iface, "ppp");
|
lif_interface_use_executor(state->cur_iface, "ppp");
|
||||||
else if (!strcmp(token, "inherits"))
|
else if (!strcmp(token, "inherits"))
|
||||||
{
|
{
|
||||||
if (!handle_inherit(collection, filename, lineno, token, bufp))
|
if (!handle_inherit(state, token, bufp))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -284,50 +275,50 @@ handle_iface(struct lif_dict *collection, const char *filename, size_t lineno, c
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
handle_inherit(struct lif_dict *collection, const char *filename, size_t lineno, char *token, char *bufp)
|
handle_inherit(struct lif_interface_file_parse_state *state, char *token, char *bufp)
|
||||||
{
|
{
|
||||||
char *target = lif_next_token(&bufp);
|
char *target = lif_next_token(&bufp);
|
||||||
|
|
||||||
if (cur_iface == NULL)
|
if (state->cur_iface == NULL)
|
||||||
{
|
{
|
||||||
report_error(filename, lineno, "%s '%s' without interface", token, target);
|
report_error(state, "%s '%s' without interface", token, target);
|
||||||
/* This is broken but not fatal */
|
/* This is broken but not fatal */
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!*target)
|
if (!*target)
|
||||||
{
|
{
|
||||||
report_error(filename, lineno, "iface %s: unspecified inherit target", cur_iface->ifname);
|
report_error(state, "iface %s: unspecified inherit target", state->cur_iface->ifname);
|
||||||
/* Mark this interface as errornous but carry on */
|
/* Mark this interface as errornous but carry on */
|
||||||
cur_iface->has_config_error = true;
|
state->cur_iface->has_config_error = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct lif_interface *parent = lif_interface_collection_find(collection, target);
|
struct lif_interface *parent = lif_interface_collection_find(state->collection, target);
|
||||||
if (parent == NULL)
|
if (parent == NULL)
|
||||||
{
|
{
|
||||||
report_error(filename, lineno, "iface %s: could not inherit from %s: not found",
|
report_error(state, "iface %s: could not inherit from %s: not found",
|
||||||
cur_iface->ifname, target);
|
state->cur_iface->ifname, target);
|
||||||
/* Mark this interface as errornous but carry on */
|
/* Mark this interface as errornous but carry on */
|
||||||
cur_iface->has_config_error = true;
|
state->cur_iface->has_config_error = true;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!lif_config.allow_any_iface_as_template && !parent->is_template)
|
if (!lif_config.allow_any_iface_as_template && !parent->is_template)
|
||||||
{
|
{
|
||||||
report_error(filename, lineno, "iface %s: could not inherit from %ss: inheritence from non-template interface not allowed",
|
report_error(state, "iface %s: could not inherit from %ss: inheritence from non-template interface not allowed",
|
||||||
cur_iface->ifname, target);
|
state->cur_iface->ifname, target);
|
||||||
/* Mark this interface as errornous but carry on */
|
/* Mark this interface as errornous but carry on */
|
||||||
cur_iface->has_config_error = true;
|
state->cur_iface->has_config_error = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!lif_interface_collection_inherit(cur_iface, parent))
|
if (!lif_interface_collection_inherit(state->cur_iface, parent))
|
||||||
{
|
{
|
||||||
report_error(filename, lineno, "iface %s: could not inherit from %s", cur_iface->ifname, target);
|
report_error(state, "iface %s: could not inherit from %s", state->cur_iface->ifname, target);
|
||||||
/* Mark this interface as errornous but carry on */
|
/* Mark this interface as errornous but carry on */
|
||||||
cur_iface->has_config_error = true;
|
state->cur_iface->has_config_error = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -335,51 +326,82 @@ handle_inherit(struct lif_dict *collection, const char *filename, size_t lineno,
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
handle_source(struct lif_dict *collection, const char *filename, size_t lineno, char *token, char *bufp)
|
handle_source(struct lif_interface_file_parse_state *state, char *token, char *bufp)
|
||||||
{
|
{
|
||||||
(void) token;
|
(void) token;
|
||||||
|
|
||||||
char *source_filename = lif_next_token(&bufp);
|
char *source_filename = lif_next_token(&bufp);
|
||||||
if (!*source_filename)
|
if (!*source_filename)
|
||||||
{
|
{
|
||||||
report_error(filename, lineno, "missing filename to source");
|
report_error(state, "missing filename to source");
|
||||||
/* Broken but not fatal */
|
/* Broken but not fatal */
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strcmp(filename, source_filename))
|
return lif_interface_file_parse(state, source_filename);
|
||||||
{
|
|
||||||
report_error(filename, lineno, "attempt to source %s would create infinite loop",
|
|
||||||
source_filename);
|
|
||||||
/* Broken but not fatal */
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return lif_interface_file_parse(collection, source_filename);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
handle_use(struct lif_dict *collection, const char *filename, size_t lineno, char *token, char *bufp)
|
handle_source_directory(struct lif_interface_file_parse_state *state, char *token, char *bufp)
|
||||||
{
|
{
|
||||||
(void) collection;
|
(void) token;
|
||||||
|
|
||||||
char *executor = lif_next_token(&bufp);
|
char *source_directory = lif_next_token(&bufp);
|
||||||
|
if (!*source_directory)
|
||||||
if (cur_iface == NULL)
|
|
||||||
{
|
{
|
||||||
report_error(filename, lineno, "%s '%s' without interface", token, executor);
|
report_error(state, "missing directory to source");
|
||||||
/* Broken but not fatal */
|
/* Broken but not fatal */
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
lif_interface_use_executor(cur_iface, executor);
|
DIR *source_dir = opendir(source_directory);
|
||||||
|
if (source_dir == NULL)
|
||||||
|
{
|
||||||
|
report_error(state, "while opening directory %s: %s", source_directory, strerror(errno));
|
||||||
|
/* Broken but not fatal */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct dirent *dirent_p;
|
||||||
|
for (dirent_p = readdir(source_dir); dirent_p != NULL; dirent_p = readdir(source_dir))
|
||||||
|
{
|
||||||
|
if (dirent_p->d_type != DT_REG)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
char pathbuf[4096];
|
||||||
|
snprintf(pathbuf, sizeof pathbuf, "%s/%s", source_directory, dirent_p->d_name);
|
||||||
|
|
||||||
|
if (!lif_interface_file_parse(state, pathbuf))
|
||||||
|
{
|
||||||
|
closedir(source_dir);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir(source_dir);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
handle_use(struct lif_interface_file_parse_state *state, char *token, char *bufp)
|
||||||
|
{
|
||||||
|
char *executor = lif_next_token(&bufp);
|
||||||
|
|
||||||
|
if (state->cur_iface == NULL)
|
||||||
|
{
|
||||||
|
report_error(state, "%s '%s' without interface", token, executor);
|
||||||
|
/* Broken but not fatal */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
lif_interface_use_executor(state->cur_iface, executor);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* map keywords to parser functions */
|
/* map keywords to parser functions */
|
||||||
struct parser_keyword {
|
struct parser_keyword {
|
||||||
const char *token;
|
const char *token;
|
||||||
bool (*handle)(struct lif_dict *collection, const char *filename, size_t lineno, char *token, char *bufp);
|
bool (*handle)(struct lif_interface_file_parse_state *state, char *token, char *bufp);
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct parser_keyword keywords[] = {
|
static const struct parser_keyword keywords[] = {
|
||||||
|
@ -390,6 +412,7 @@ static const struct parser_keyword keywords[] = {
|
||||||
{"inherit", handle_inherit},
|
{"inherit", handle_inherit},
|
||||||
{"interface", handle_iface},
|
{"interface", handle_iface},
|
||||||
{"source", handle_source},
|
{"source", handle_source},
|
||||||
|
{"source-directory", handle_source_directory},
|
||||||
{"template", handle_iface},
|
{"template", handle_iface},
|
||||||
{"use", handle_use},
|
{"use", handle_use},
|
||||||
};
|
};
|
||||||
|
@ -404,17 +427,31 @@ keyword_cmp(const void *a, const void *b)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
lif_interface_file_parse(struct lif_dict *collection, const char *filename)
|
lif_interface_file_parse(struct lif_interface_file_parse_state *state, const char *filename)
|
||||||
{
|
{
|
||||||
|
struct lif_dict_entry *entry = lif_dict_find(&state->loaded, filename);
|
||||||
|
if (entry != NULL)
|
||||||
|
{
|
||||||
|
report_error(state, "skipping already included file %s", filename);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
FILE *f = fopen(filename, "r");
|
FILE *f = fopen(filename, "r");
|
||||||
if (f == NULL)
|
if (f == NULL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
const char *old_filename = state->cur_filename;
|
||||||
|
state->cur_filename = filename;
|
||||||
|
|
||||||
|
size_t old_lineno = state->cur_lineno;
|
||||||
|
state->cur_lineno = 0;
|
||||||
|
|
||||||
|
lif_dict_add(&state->loaded, filename, NULL);
|
||||||
|
|
||||||
char linebuf[4096];
|
char linebuf[4096];
|
||||||
size_t lineno = 0;
|
|
||||||
while (lif_fgetline(linebuf, sizeof linebuf, f) != NULL)
|
while (lif_fgetline(linebuf, sizeof linebuf, f) != NULL)
|
||||||
{
|
{
|
||||||
lineno++;
|
state->cur_lineno++;
|
||||||
|
|
||||||
char *bufp = linebuf;
|
char *bufp = linebuf;
|
||||||
char *token = lif_next_token(&bufp);
|
char *token = lif_next_token(&bufp);
|
||||||
|
@ -427,17 +464,21 @@ lif_interface_file_parse(struct lif_dict *collection, const char *filename)
|
||||||
|
|
||||||
if (parserkw != NULL)
|
if (parserkw != NULL)
|
||||||
{
|
{
|
||||||
if (!parserkw->handle(collection, filename, lineno, token, bufp))
|
if (!parserkw->handle(state, token, bufp))
|
||||||
goto parse_error;
|
goto parse_error;
|
||||||
}
|
}
|
||||||
else if (!handle_generic(collection, filename, lineno, token, bufp))
|
else if (!handle_generic(state, token, bufp))
|
||||||
goto parse_error;
|
goto parse_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
state->cur_filename = old_filename;
|
||||||
|
state->cur_lineno = old_lineno;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
parse_error:
|
parse_error:
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
state->cur_filename = old_filename;
|
||||||
|
state->cur_lineno = old_lineno;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,17 @@
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include "libifupdown/interface.h"
|
#include "libifupdown/interface.h"
|
||||||
|
#include "libifupdown/dict.h"
|
||||||
|
|
||||||
extern bool lif_interface_file_parse(struct lif_dict *collection, const char *filename);
|
struct lif_interface_file_parse_state {
|
||||||
|
struct lif_interface *cur_iface;
|
||||||
|
struct lif_dict *collection;
|
||||||
|
const char *cur_filename;
|
||||||
|
size_t cur_lineno;
|
||||||
|
|
||||||
|
struct lif_dict loaded;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern bool lif_interface_file_parse(struct lif_interface_file_parse_state *state, const char *filename);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue