diff --git a/src/shrpx.cc b/src/shrpx.cc index 26326e2f..7160bf6c 100644 --- a/src/shrpx.cc +++ b/src/shrpx.cc @@ -2030,11 +2030,13 @@ int main(int argc, char **argv) { } if (conf_exists(get_config()->conf_path.get())) { - if (load_config(get_config()->conf_path.get()) == -1) { + std::set include_set; + if (load_config(get_config()->conf_path.get(), include_set) == -1) { LOG(FATAL) << "Failed to load configuration from " << get_config()->conf_path.get(); exit(EXIT_FAILURE); } + assert(include_set.empty()); } if (argc - optind >= 2) { @@ -2046,11 +2048,18 @@ int main(int argc, char **argv) { // parsing option values. reopen_log_files(); - for (size_t i = 0, len = cmdcfgs.size(); i < len; ++i) { - if (parse_config(cmdcfgs[i].first, cmdcfgs[i].second) == -1) { - LOG(FATAL) << "Failed to parse command-line argument."; - exit(EXIT_FAILURE); + { + std::set include_set; + + for (size_t i = 0, len = cmdcfgs.size(); i < len; ++i) { + if (parse_config(cmdcfgs[i].first, cmdcfgs[i].second, include_set) == + -1) { + LOG(FATAL) << "Failed to parse command-line argument."; + exit(EXIT_FAILURE); + } } + + assert(include_set.empty()); } if (get_config()->accesslog_syslog || get_config()->errorlog_syslog) { diff --git a/src/shrpx_config.cc b/src/shrpx_config.cc index 49ad49a8..6a978b1c 100644 --- a/src/shrpx_config.cc +++ b/src/shrpx_config.cc @@ -505,7 +505,8 @@ void parse_mapping(const DownstreamAddr &addr, const char *src) { } } // namespace -int parse_config(const char *opt, const char *optarg) { +int parse_config(const char *opt, const char *optarg, + std::set &included_set) { char host[NI_MAXHOST]; uint16_t port; @@ -1220,7 +1221,20 @@ int parse_config(const char *opt, const char *optarg) { } if (util::strieq(opt, SHRPX_OPT_INCLUDE)) { - return load_config(optarg); + if (included_set.count(optarg)) { + LOG(ERROR) << opt << ": " << optarg << " has already been included"; + return -1; + } + + included_set.emplace(optarg); + auto rv = load_config(optarg, included_set); + included_set.erase(optarg); + + if (rv != 0) { + return -1; + } + + return 0; } if (util::strieq(opt, "conf")) { @@ -1234,7 +1248,7 @@ int parse_config(const char *opt, const char *optarg) { return -1; } -int load_config(const char *filename) { +int load_config(const char *filename, std::set &include_set) { std::ifstream in(filename, std::ios::binary); if (!in) { LOG(ERROR) << "Could not open config file " << filename; @@ -1258,7 +1272,7 @@ int load_config(const char *filename) { } line[i] = '\0'; auto s = line.c_str(); - if (parse_config(s, s + i + 1) == -1) { + if (parse_config(s, s + i + 1, include_set) == -1) { return -1; } } diff --git a/src/shrpx_config.h b/src/shrpx_config.h index 5f23c5b3..ea455f02 100644 --- a/src/shrpx_config.h +++ b/src/shrpx_config.h @@ -42,6 +42,7 @@ #include #include #include +#include #include @@ -379,13 +380,16 @@ void create_config(); // Parses option name |opt| and value |optarg|. The results are // stored into statically allocated Config object. This function -// returns 0 if it succeeds, or -1. -int parse_config(const char *opt, const char *optarg); +// returns 0 if it succeeds, or -1. The |included_set| contains the +// all paths already included while processing this configuration, to +// avoid loop in --include option. +int parse_config(const char *opt, const char *optarg, + std::set &included_set); // Loads configurations from |filename| and stores them in statically // allocated Config object. This function returns 0 if it succeeds, or -// -1. -int load_config(const char *filename); +// -1. See parse_config() for |include_set|. +int load_config(const char *filename, std::set &include_set); // Read passwd from |filename| std::string read_passwd_from_file(const char *filename);