Ugh, this is awkward.
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:21:31 -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:21:31 -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 },