Hi,
the patch below teaches httpd's "include" keyword how to handle file
patterns via glob(3) by introducing a new function "pushglob()".
This allows something like the following in httpd.conf:
include "/etc/httpd/sites-enabled/*.conf"
If the pattern passed to pushglob() contains no globbing characters
(e.g. a file path), the absence of the file is an error. In contrast,
if the pattern contains globbing character and the pattern matches no
files, it is NOT an error.
pushglob() also supports the "secret" flag though it is not used in httpd.
This should make it reuseable in other parse.y files in the tree.
If secret equals true all matched files must be "valid" or pushglob()
returns NULL.
No change in existing behaviour intended.
If you like this feature, i can prepare a diff for httpd.conf(5).
Cheers,
Fabian
Index: parse.y
===================================================================
RCS file: /cvs/src/usr.sbin/httpd/parse.y,v
retrieving revision 1.77
diff -u -p -r1.77 parse.y
--- parse.y 22 Nov 2015 13:27:13 -0000 1.77
+++ parse.y 28 May 2016 13:38:03 -0000
@@ -42,6 +42,7 @@
#include <unistd.h>
#include <err.h>
#include <errno.h>
+#include <glob.h>
#include <limits.h>
#include <stdint.h>
#include <stdarg.h>
@@ -62,6 +63,7 @@ static struct file {
int lineno;
int errors;
} *file, *topfile;
+struct file *pushglob(const char *, int, int *);
struct file *pushfile(const char *, int);
int popfile(void);
int check_file_secrecy(int, const char *);
@@ -157,15 +159,19 @@ grammar : /* empty */
include : INCLUDE STRING {
struct file *nfile;
+ int magchar, secret = 0;
- if ((nfile = pushfile($2, 0)) == NULL) {
- yyerror("failed to include file %s", $2);
- free($2);
- YYERROR;
- }
- free($2);
+ if ((nfile = pushglob($2, secret, &magchar)) == NULL) {
+ if (secret || !magchar) {
+ yyerror("failed to include %s %s",
+ magchar ? "pattern" : "file", $2);
+ free($2);
+ YYERROR;
+ }
+ } else
+ file = nfile;
- file = nfile;
+ free($2);
lungetc('\n');
}
;
@@ -1471,6 +1477,33 @@ check_file_secrecy(int fd, const char *f
return (-1);
}
return (0);
+}
+
+struct file *
+pushglob(const char *pattern, int secret, int *magchar)
+{
+ struct file *nfile = NULL, *tmp;
+ glob_t g;
+ int failed = 0, i;
+
+ if (glob(pattern, GLOB_NOCHECK, NULL, &g) != 0) {
+ log_warn("cannot glob %s", pattern);
+ *magchar = 0;
+ return (NULL);
+ }
+
+ for (i = 0; i < g.gl_matchc; i++) {
+ tmp = pushfile(g.gl_pathv[i], secret);
+ if (tmp == NULL) {
+ if (secret)
+ failed = 1;
+ } else
+ nfile = tmp;
+ }
+
+ *magchar = g.gl_flags & GLOB_MAGCHAR ? 1 : 0;
+ globfree(&g);
+ return (failed ? NULL : nfile);
}
struct file *