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