1 /* $OpenBSD: globtest.c,v 1.4 2019/01/25 00:19:26 millert Exp $ */
2
3 /*
4 * Public domain, 2008, Todd C. Miller <millert@openbsd.org>
5 */
6
7 #include <err.h>
8 #include <glob.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12
13 #define MAX_RESULTS 256
14
15 struct gl_entry {
16 int flags;
17 int nresults;
18 char pattern[1024];
19 char *results[MAX_RESULTS];
20 mode_t modes[MAX_RESULTS];
21 };
22
23 int test_glob(struct gl_entry *);
24
25 int
main(int argc,char ** argv)26 main(int argc, char **argv)
27 {
28 FILE *fp = stdin;
29 char *buf, *cp;
30 int errors = 0, lineno, mode;
31 struct gl_entry entry;
32 size_t len;
33
34 if (argc > 1) {
35 if ((fp = fopen(argv[1], "r")) == NULL)
36 err(1, "%s", argv[1]);
37 }
38
39 /*
40 * Read in test file, which is formatted thusly:
41 *
42 * [pattern] <flags>
43 * result1 [mode]
44 * result2 [mode]
45 * result3 [mode]
46 * ...
47 *
48 */
49 lineno = 0;
50 memset(&entry, 0, sizeof(entry));
51 while ((buf = fgetln(fp, &len)) != NULL) {
52 lineno++;
53 if (buf[len - 1] != '\n')
54 errx(1, "missing newline at EOF");
55 buf[--len] = '\0';
56 if (len == 0)
57 continue; /* blank line */
58
59 if (buf[0] == '[') {
60 /* check previous pattern */
61 if (entry.pattern[0])
62 errors += test_glob(&entry);
63
64 /* start new entry */
65 if ((cp = strrchr(buf + 1, ']')) == NULL)
66 errx(1, "invalid entry on line %d", lineno);
67 len = cp - buf - 1;
68 if (len >= sizeof(entry.pattern))
69 errx(1, "pattern too big on line %d", lineno);
70 memcpy(entry.pattern, buf + 1, len);
71 entry.pattern[len] = '\0';
72
73 buf = cp + 2;
74 if (*buf++ != '<')
75 errx(1, "invalid entry on line %d", lineno);
76 if ((cp = strchr(buf, '>')) == NULL)
77 errx(1, "invalid entry on line %d", lineno);
78 entry.flags = (int)strtol(buf, &cp, 0);
79 if (*cp != '>' || entry.flags < 0 || entry.flags > 0x4000)
80 errx(1, "invalid flags: %s", buf);
81 entry.nresults = 0;
82 continue;
83 }
84 if (!entry.pattern[0])
85 errx(1, "missing entry on line %d", lineno);
86
87 if (entry.nresults + 1 > MAX_RESULTS) {
88 errx(1, "too many results for %s, max %d",
89 entry.pattern, MAX_RESULTS);
90 }
91 if ((cp = strchr(buf, ' ')) != NULL) {
92 *cp++ = '\0';
93 mode = strtol(cp, NULL, 8);
94 } else
95 mode = -1;
96 entry.modes[entry.nresults] = (mode_t)mode;
97 entry.results[entry.nresults++] = strdup(buf);
98 }
99 if (entry.pattern[0])
100 errors += test_glob(&entry); /* test last pattern */
101 exit(errors);
102 }
103
test_glob(struct gl_entry * entry)104 int test_glob(struct gl_entry *entry)
105 {
106 glob_t gl;
107 int i = 0;
108
109 if (glob(entry->pattern, entry->flags, NULL, &gl) != 0)
110 errx(1, "glob failed: %s", entry->pattern);
111
112 if (gl.gl_matchc != entry->nresults)
113 goto mismatch;
114
115 for (i = 0; i < gl.gl_matchc; i++) {
116 if (strcmp(gl.gl_pathv[i], entry->results[i]) != 0)
117 goto mismatch;
118 if ((entry->flags & GLOB_KEEPSTAT) != 0) {
119 if (entry->modes[i] == -1 ||
120 gl.gl_statv[i] == NULL ||
121 entry->modes[i] != gl.gl_statv[i]->st_mode)
122 goto badmode;
123 }
124 free(entry->results[i]);
125 }
126 return (0);
127 badmode:
128 warnx("mismatch mode for pattern %s, flags 0x%x, file \"%s\" "
129 "(found %07o, expected %07o)", entry->pattern, entry->flags,
130 gl.gl_pathv[i], gl.gl_statv[i] ? gl.gl_statv[i]->st_mode : 0,
131 entry->modes[i]);
132 goto cleanup;
133 mismatch:
134 warnx("mismatch for pattern %s, flags 0x%x "
135 "(found \"%s\", expected \"%s\")", entry->pattern, entry->flags,
136 gl.gl_pathv[i], entry->results[i]);
137 cleanup:
138 while (i < gl.gl_matchc) {
139 free(entry->results[i++]);
140 }
141 return (1);
142 }
143