xref: /openbsd/regress/lib/libc/glob/globtest.c (revision 3cab2bb3)
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
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 
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