Ignore that last patch. It has a wrong indentation in an if block.
Index: httpd.conf.5 =================================================================== RCS file: /cvs/src/usr.sbin/httpd/httpd.conf.5,v retrieving revision 1.121 diff -u -p -u -p -r1.121 httpd.conf.5 --- httpd.conf.5 9 Mar 2022 13:50:41 -0000 1.121 +++ httpd.conf.5 2 Jun 2022 11:02:21 -0000 @@ -84,6 +84,12 @@ keyword, for example: .Bd -literal -offset indent include "/etc/httpd.conf.local" .Ed +A directory with configuration files can be included with the +.Ic include_dir +keyword, for example: +.Bd -literal -offset indent +include_dir "directory" +.Ed .Sh MACROS Macros can be defined that will later be expanded in context. Macro names must start with a letter, digit, or underscore, Index: parse.y =================================================================== RCS file: /cvs/src/usr.sbin/httpd/parse.y,v retrieving revision 1.128 diff -u -p -u -p -r1.128 parse.y --- parse.y 27 Feb 2022 20:30:30 -0000 1.128 +++ parse.y 2 Jun 2022 11:02:21 -0000 @@ -52,6 +52,7 @@ #include <string.h> #include <ifaddrs.h> #include <syslog.h> +#include <dirent.h> #include "httpd.h" #include "http.h" @@ -139,7 +140,7 @@ typedef struct { %token LISTEN LOCATION LOG LOGDIR MATCH MAXIMUM NO NODELAY OCSP ON PORT PREFORK %token PROTOCOLS REQUESTS ROOT SACK SERVER SOCKET STRIP STYLE SYSLOG TCP TICKET %token TIMEOUT TLS TYPE TYPES HSTS MAXAGE SUBDOMAINS DEFAULT PRELOAD REQUEST -%token ERROR INCLUDE AUTHENTICATE WITH BLOCK DROP RETURN PASS REWRITE +%token ERROR INCLUDE INCLUDE_DIR AUTHENTICATE WITH BLOCK DROP RETURN PASS REWRITE %token CA CLIENT CRL OPTIONAL PARAM FORWARDED FOUND NOT %token ERRDOCS GZIPSTATIC %token <v.string> STRING @@ -155,6 +156,7 @@ typedef struct { grammar : /* empty */ | grammar include '\n' + | grammar include_dir '\n' | grammar '\n' | grammar varset '\n' | grammar main '\n' @@ -165,7 +167,6 @@ grammar : /* empty */ include : INCLUDE STRING { struct file *nfile; - if ((nfile = pushfile($2, 0)) == NULL) { yyerror("failed to include file %s", $2); free($2); @@ -178,6 +179,48 @@ include : INCLUDE STRING { } ; +include_dir : INCLUDE_DIR STRING { + char absolute_path[PATH_MAX]; + char dir[PATH_MAX]; + struct file *nfile; + DIR *opened_dir; + opened_dir = openddir($2); + struct dirent *entry; + size_t len = 0; + + if(opened_dir == NULL) { + free($2); + yyerror("Failed to open directory %s", $2); + YYERROR; + } + + len = strlcpy(dir, $2, PATH_MAX); + + if(len >= sizeof(dir)) { + free($2); + yyerror("too long"); + YYERROR; + } + + while((entry = readdir(opened_dir))) { + if(entry->d_name[0] == '.') + continue; + len = snprintf(absolute_path, PATH_MAX, "%s%s", dir, entry->d_name); + if(len < 0 || len >= sizeof(absolute_path)) { + yyerror("too long"); + YYERROR; + } + if((nfile = pushfile(absolute_path, 0)) == NULL) { + yyerror("failed to include file %s", $2); + YYERROR; + } + } + + file = nfile; + lungetc('\n'); +} +; + varset : STRING '=' STRING { char *s = $1; while (*s++) { @@ -1453,6 +1496,7 @@ lookup(char *s) { "gzip-static", GZIPSTATIC }, { "hsts", HSTS }, { "include", INCLUDE }, + { "include_dir", INCLUDE_DIR}, { "index", INDEX }, { "ip", IP }, { "key", KEY },