diff --git a/doc/arm/Bv9ARM-book.xml b/doc/arm/Bv9ARM-book.xml index 135b32086d..89c54f9654 100644 --- a/doc/arm/Bv9ARM-book.xml +++ b/doc/arm/Bv9ARM-book.xml @@ -3497,7 +3497,8 @@ $ORIGIN 0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa. The include statement inserts the - specified file at the point where the include + specified file (or files if a valid glob expression is detected) + at the point where the include statement is encountered. The include statement facilitates the administration of configuration files diff --git a/lib/isccfg/parser.c b/lib/isccfg/parser.c index 7c80f214bd..f538ce7abd 100644 --- a/lib/isccfg/parser.c +++ b/lib/isccfg/parser.c @@ -15,9 +15,13 @@ #include #include #include +#include +#include +#include #include #include +#include #include #include #include @@ -106,6 +110,9 @@ static void parser_complain(cfg_parser_t *pctx, bool is_warning, unsigned int flags, const char *format, va_list args); +static isc_result_t +glob_include(const char * restrict pattern, glob_t * restrict pglob); + #if defined(HAVE_GEOIP2) static isc_result_t parse_geoip(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret); @@ -2387,9 +2394,17 @@ cfg_parse_mapbody(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { CHECK(cfg_parse_obj(pctx, &cfg_type_qstring, &includename)); CHECK(parse_semicolon(pctx)); - CHECK(parser_openfile(pctx, - includename->value.string.base)); + + /* Allow include to specify a pattern that follows + * the same rules as the shell e.g "/path/zone*.conf" */ + glob_t glob_obj; + CHECK(glob_include(includename->value.string.base, &glob_obj)); cfg_obj_destroy(pctx, &includename); + + for (size_t i = 0; i < glob_obj.gl_pathc; ++i) { + CHECK(parser_openfile(pctx, glob_obj.gl_pathv[i])); + } + goto redo; } @@ -4080,3 +4095,27 @@ cfg_pluginlist_foreach(const cfg_obj_t *config, const cfg_obj_t *list, return (result); } + + +static isc_result_t +glob_include(const char * restrict pattern, glob_t * restrict pglob) +{ + int rc = glob(pattern, GLOB_ERR, NULL, pglob); + + switch (rc) { + case 0: + return (ISC_R_SUCCESS); + case GLOB_NOMATCH: + /* if a magic char (*?[]) was in pattern + * and no path matched we report error early, + * otherwise proceed as normal */ + return (strpbrk(pattern, "[]*?")) ? + (ISC_R_FILENOTFOUND) : (ISC_R_SUCCESS); + + case GLOB_NOSPACE: + return (ISC_R_NOMEMORY); + default: + return (errno != 0 ? isc_errno_toresult(errno) : ISC_R_IOERROR); + } + +}