• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "settings.h"
2 
3 #include <ctype.h>
4 #include <errno.h>
5 #include <fcntl.h>
6 #include <getopt.h>
7 #include <libgen.h>
8 #include <limits.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <sys/types.h>
13 #include <sys/stat.h>
14 #include <unistd.h>
15 
16 enum {
17 	OPT_ABORT_ON_ERROR,
18 	OPT_TEST_LIST,
19 	OPT_IGNORE_MISSING,
20 	OPT_PIGLIT_DMESG,
21 	OPT_DMESG_WARN_LEVEL,
22 	OPT_OVERALL_TIMEOUT,
23 	OPT_HELP = 'h',
24 	OPT_NAME = 'n',
25 	OPT_DRY_RUN = 'd',
26 	OPT_INCLUDE = 't',
27 	OPT_EXCLUDE = 'x',
28 	OPT_SYNC = 's',
29 	OPT_LOG_LEVEL = 'l',
30 	OPT_OVERWRITE = 'o',
31 	OPT_MULTIPLE = 'm',
32 	OPT_TIMEOUT = 'c',
33 	OPT_WATCHDOG = 'g',
34 	OPT_BLACKLIST = 'b',
35 	OPT_LIST_ALL = 'L',
36 };
37 
38 static struct {
39 	int level;
40 	const char *name;
41 } log_levels[] = {
42 	{ LOG_LEVEL_NORMAL, "normal" },
43 	{ LOG_LEVEL_QUIET, "quiet" },
44 	{ LOG_LEVEL_VERBOSE, "verbose" },
45 	{ 0, 0 },
46 };
47 
48 static struct {
49 	int value;
50 	const char *name;
51 } abort_conditions[] = {
52 	{ ABORT_TAINT, "taint" },
53 	{ ABORT_LOCKDEP, "lockdep" },
54 	{ ABORT_ALL, "all" },
55 	{ 0, 0 },
56 };
57 
set_log_level(struct settings * settings,const char * level)58 static bool set_log_level(struct settings* settings, const char *level)
59 {
60 	typeof(*log_levels) *it;
61 
62 	for (it = log_levels; it->name; it++) {
63 		if (!strcmp(level, it->name)) {
64 			settings->log_level = it->level;
65 			return true;
66 		}
67 	}
68 
69 	return false;
70 }
71 
set_abort_condition(struct settings * settings,const char * cond)72 static bool set_abort_condition(struct settings* settings, const char *cond)
73 {
74 	typeof(*abort_conditions) *it;
75 
76 	if (!cond) {
77 		settings->abort_mask = ABORT_ALL;
78 		return true;
79 	}
80 
81 	if (strlen(cond) == 0) {
82 		settings->abort_mask = 0;
83 		return true;
84 	}
85 
86 	for (it = abort_conditions; it->name; it++) {
87 		if (!strcmp(cond, it->name)) {
88 			settings->abort_mask |= it->value;
89 			return true;
90 		}
91 	}
92 
93 	return false;
94 }
95 
parse_abort_conditions(struct settings * settings,const char * optarg)96 static bool parse_abort_conditions(struct settings *settings, const char *optarg)
97 {
98 	char *dup, *origdup, *p;
99 	if (!optarg)
100 		return set_abort_condition(settings, NULL);
101 
102 	origdup = dup = strdup(optarg);
103 	while (dup) {
104 		if ((p = strchr(dup, ',')) != NULL) {
105 			*p = '\0';
106 			p++;
107 		}
108 
109 		if (!set_abort_condition(settings, dup)) {
110 			free(origdup);
111 			return false;
112 		}
113 
114 		dup = p;
115 	}
116 
117 	free(origdup);
118 
119 	return true;
120 }
121 
122 static const char *usage_str =
123 	"usage: runner [options] [test_root] results-path\n"
124 	"   or: runner --list-all [options] [test_root]\n\n"
125 	"Options:\n"
126 	" Piglit compatible:\n"
127 	"  -h, --help            Show this help message and exit\n"
128 	"  -n <test name>, --name <test name>\n"
129 	"                        Name of this test run\n"
130 	"  -d, --dry-run         Do not execute the tests\n"
131 	"  -t <regex>, --include-tests <regex>\n"
132 	"                        Run only matching tests (can be used more than once)\n"
133 	"  -x <regex>, --exclude-tests <regex>\n"
134 	"                        Exclude matching tests (can be used more than once)\n"
135 	"  --abort-on-monitored-error[=list]\n"
136 	"                        Abort execution when a fatal condition is detected.\n"
137 	"                        A comma-separated list of conditions to check can be\n"
138 	"                        given. If not given, all conditions are checked. An\n"
139 	"                        empty string as a condition disables aborting\n"
140 	"                        Possible conditions:\n"
141 	"                         lockdep - abort when kernel lockdep has been angered.\n"
142 	"                         taint   - abort when kernel becomes fatally tainted.\n"
143 	"                         all     - abort for all of the above.\n"
144 	"  -s, --sync            Sync results to disk after every test\n"
145 	"  -l {quiet,verbose,dummy}, --log-level {quiet,verbose,dummy}\n"
146 	"                        Set the logger verbosity level\n"
147 	"  --test-list TEST_LIST\n"
148 	"                        A file containing a list of tests to run\n"
149 	"  -o, --overwrite       If the results-path already exists, delete it\n"
150 	"  --ignore-missing      Ignored but accepted, for piglit compatibility\n"
151 	"\n"
152 	" Incompatible options:\n"
153 	"  -m, --multiple-mode   Run multiple subtests in the same binary execution.\n"
154 	"                        If a testlist file is given, consecutive subtests are\n"
155 	"                        run in the same execution if they are from the same\n"
156 	"                        binary. Note that in that case relative ordering of the\n"
157 	"                        subtest execution is dictated by the test binary, not\n"
158 	"                        the testlist\n"
159 	"  --inactivity-timeout <seconds>\n"
160 	"                        Kill the running test after <seconds> of inactivity in\n"
161 	"                        the test's stdout, stderr, or dmesg\n"
162 	"  --overall-timeout <seconds>\n"
163 	"                        Don't execute more tests after <seconds> has elapsed\n"
164 	"  --use-watchdog        Use hardware watchdog for lethal enforcement of the\n"
165 	"                        above timeout. Killing the test process is still\n"
166 	"                        attempted at timeout trigger.\n"
167 	"  --dmesg-warn-level <level>\n"
168 	"                        Messages with log level equal or lower (more serious)\n"
169 	"                        to the given one will override the test result to\n"
170 	"                        dmesg-warn/dmesg-fail, assuming they go through filtering.\n"
171 	"                        Defaults to 4 (KERN_WARNING).\n"
172 	"  --piglit-style-dmesg  Filter dmesg like piglit does. Piglit considers matches\n"
173 	"                        against a short filter list to mean the test result\n"
174 	"                        should be changed to dmesg-warn/dmesg-fail. Without\n"
175 	"                        this option everything except matches against a\n"
176 	"                        (longer) filter list means the test result should\n"
177 	"                        change. KERN_NOTICE dmesg level is treated as warn,\n"
178 	"                        unless overridden with --dmesg-warn-level.\n"
179 	"  -b, --blacklist FILENAME\n"
180 	"                        Exclude all test matching to regexes from FILENAME\n"
181 	"                        (can be used more than once)\n"
182 	"  -L, --list-all        List all matching subtests instead of running\n"
183 	"  [test_root]           Directory that contains the IGT tests. The environment\n"
184 	"                        variable IGT_TEST_ROOT will be used if set, overriding\n"
185 	"                        this option if given.\n"
186 	;
187 
usage(const char * extra_message,FILE * f)188 static void usage(const char *extra_message, FILE *f)
189 {
190 	if (extra_message)
191 		fprintf(f, "%s\n\n", extra_message);
192 
193 	fputs(usage_str, f);
194 }
195 
add_regex(struct regex_list * list,char * new)196 static bool add_regex(struct regex_list *list, char *new)
197 {
198 	GRegex *regex;
199 	GError *error = NULL;
200 
201 	regex = g_regex_new(new, G_REGEX_OPTIMIZE, 0, &error);
202 	if (error) {
203 		char *buf = malloc(snprintf(NULL, 0, "Invalid regex '%s': %s", new, error->message) + 1);
204 
205 		sprintf(buf, "Invalid regex '%s': %s", new, error->message);
206 		usage(buf, stderr);
207 
208 		free(buf);
209 		g_error_free(error);
210 		return false;
211 	}
212 
213 	list->regexes = realloc(list->regexes,
214 				(list->size + 1) * sizeof(*list->regexes));
215 	list->regex_strings = realloc(list->regex_strings,
216 				      (list->size + 1) * sizeof(*list->regex_strings));
217 	list->regexes[list->size] = regex;
218 	list->regex_strings[list->size] = new;
219 	list->size++;
220 
221 	return true;
222 }
223 
parse_blacklist(struct regex_list * exclude_regexes,char * blacklist_filename)224 static bool parse_blacklist(struct regex_list *exclude_regexes,
225 			    char *blacklist_filename)
226 {
227 	FILE *f;
228 	char *line = NULL;
229 	size_t line_len = 0;
230 	bool status = false;
231 
232 	if ((f = fopen(blacklist_filename, "r")) == NULL) {
233 		fprintf(stderr, "Cannot open blacklist file %s\n", blacklist_filename);
234 		return false;
235 	}
236 	while (1) {
237 		size_t str_size = 0, idx = 0;
238 
239 		if (getline(&line, &line_len, f) == -1) {
240 			if (errno == EINTR)
241 				continue;
242 			else
243 				break;
244 		}
245 
246 		while (true) {
247 			if (line[idx] == '\n' ||
248 			    line[idx] == '\0' ||
249 			    line[idx] == '#')   /* # starts a comment */
250 				break;
251 			if (!isspace(line[idx]))
252 				str_size = idx + 1;
253 			idx++;
254 		}
255 		if (str_size > 0) {
256 			char *test_regex = strndup(line, str_size);
257 
258 			status = add_regex(exclude_regexes, test_regex);
259 			if (!status)
260 				break;
261 		}
262 	}
263 
264 	free(line);
265 	fclose(f);
266 	return status;
267 }
268 
free_regexes(struct regex_list * regexes)269 static void free_regexes(struct regex_list *regexes)
270 {
271 	size_t i;
272 
273 	for (i = 0; i < regexes->size; i++) {
274 		free(regexes->regex_strings[i]);
275 		g_regex_unref(regexes->regexes[i]);
276 	}
277 	free(regexes->regex_strings);
278 	free(regexes->regexes);
279 }
280 
readable_file(char * filename)281 static bool readable_file(char *filename)
282 {
283 	return !access(filename, R_OK);
284 }
285 
init_settings(struct settings * settings)286 void init_settings(struct settings *settings)
287 {
288 	memset(settings, 0, sizeof(*settings));
289 }
290 
free_settings(struct settings * settings)291 void free_settings(struct settings *settings)
292 {
293 	free(settings->test_list);
294 	free(settings->name);
295 	free(settings->test_root);
296 	free(settings->results_path);
297 
298 	free_regexes(&settings->include_regexes);
299 	free_regexes(&settings->exclude_regexes);
300 
301 	init_settings(settings);
302 }
303 
parse_options(int argc,char ** argv,struct settings * settings)304 bool parse_options(int argc, char **argv,
305 		   struct settings *settings)
306 {
307 	int c;
308 	char *env_test_root;
309 
310 	static struct option long_options[] = {
311 		{"help", no_argument, NULL, OPT_HELP},
312 		{"name", required_argument, NULL, OPT_NAME},
313 		{"dry-run", no_argument, NULL, OPT_DRY_RUN},
314 		{"include-tests", required_argument, NULL, OPT_INCLUDE},
315 		{"exclude-tests", required_argument, NULL, OPT_EXCLUDE},
316 		{"abort-on-monitored-error", optional_argument, NULL, OPT_ABORT_ON_ERROR},
317 		{"sync", no_argument, NULL, OPT_SYNC},
318 		{"log-level", required_argument, NULL, OPT_LOG_LEVEL},
319 		{"test-list", required_argument, NULL, OPT_TEST_LIST},
320 		{"overwrite", no_argument, NULL, OPT_OVERWRITE},
321 		{"ignore-missing", no_argument, NULL, OPT_IGNORE_MISSING},
322 		{"multiple-mode", no_argument, NULL, OPT_MULTIPLE},
323 		{"inactivity-timeout", required_argument, NULL, OPT_TIMEOUT},
324 		{"overall-timeout", required_argument, NULL, OPT_OVERALL_TIMEOUT},
325 		{"use-watchdog", no_argument, NULL, OPT_WATCHDOG},
326 		{"piglit-style-dmesg", no_argument, NULL, OPT_PIGLIT_DMESG},
327 		{"dmesg-warn-level", required_argument, NULL, OPT_DMESG_WARN_LEVEL},
328 		{"blacklist", required_argument, NULL, OPT_BLACKLIST},
329 		{"list-all", no_argument, NULL, OPT_LIST_ALL},
330 		{ 0, 0, 0, 0},
331 	};
332 
333 	free_settings(settings);
334 
335 	optind = 1;
336 
337 	settings->dmesg_warn_level = -1;
338 
339 	while ((c = getopt_long(argc, argv, "hn:dt:x:sl:omb:L",
340 				long_options, NULL)) != -1) {
341 		switch (c) {
342 		case OPT_HELP:
343 			usage(NULL, stdout);
344 			goto error;
345 		case OPT_NAME:
346 			settings->name = strdup(optarg);
347 			break;
348 		case OPT_DRY_RUN:
349 			settings->dry_run = true;
350 			break;
351 		case OPT_INCLUDE:
352 			if (!add_regex(&settings->include_regexes, strdup(optarg)))
353 				goto error;
354 			break;
355 		case OPT_EXCLUDE:
356 			if (!add_regex(&settings->exclude_regexes, strdup(optarg)))
357 				goto error;
358 			break;
359 		case OPT_ABORT_ON_ERROR:
360 			if (!parse_abort_conditions(settings, optarg))
361 				goto error;
362 			break;
363 		case OPT_SYNC:
364 			settings->sync = true;
365 			break;
366 		case OPT_LOG_LEVEL:
367 			if (!set_log_level(settings, optarg)) {
368 				usage("Cannot parse log level", stderr);
369 				goto error;
370 			}
371 			break;
372 		case OPT_TEST_LIST:
373 			settings->test_list = absolute_path(optarg);
374 			break;
375 		case OPT_OVERWRITE:
376 			settings->overwrite = true;
377 			break;
378 		case OPT_IGNORE_MISSING:
379 			/* Ignored, piglit compatibility */
380 			break;
381 		case OPT_MULTIPLE:
382 			settings->multiple_mode = true;
383 			break;
384 		case OPT_TIMEOUT:
385 			settings->inactivity_timeout = atoi(optarg);
386 			break;
387 		case OPT_OVERALL_TIMEOUT:
388 			settings->overall_timeout = atoi(optarg);
389 			break;
390 		case OPT_WATCHDOG:
391 			settings->use_watchdog = true;
392 			break;
393 		case OPT_PIGLIT_DMESG:
394 			settings->piglit_style_dmesg = true;
395 			if (settings->dmesg_warn_level < 0)
396 				settings->dmesg_warn_level = 5; /* KERN_NOTICE */
397 			break;
398 		case OPT_DMESG_WARN_LEVEL:
399 			settings->dmesg_warn_level = atoi(optarg);
400 			break;
401 		case OPT_BLACKLIST:
402 			if (!parse_blacklist(&settings->exclude_regexes,
403 					     absolute_path(optarg)))
404 				goto error;
405 			break;
406 		case OPT_LIST_ALL:
407 			settings->list_all = true;
408 			break;
409 		case '?':
410 			usage(NULL, stderr);
411 			goto error;
412 		default:
413 			usage("Cannot parse options", stderr);
414 			goto error;
415 		}
416 	}
417 
418 	if (settings->dmesg_warn_level < 0)
419 		settings->dmesg_warn_level = 4; /* KERN_WARN */
420 
421 	if (settings->list_all) { /* --list-all doesn't require results path */
422 		switch (argc - optind) {
423 		case 1:
424 			settings->test_root = absolute_path(argv[optind]);
425 			++optind;
426 			/* fallthrough */
427 		case 0:
428 			break;
429 		default:
430 			usage("Too many arguments for --list-all", stderr);
431 			goto error;
432 		}
433 	} else {
434 		switch (argc - optind) {
435 		case 2:
436 			settings->test_root = absolute_path(argv[optind]);
437 			++optind;
438 			/* fallthrough */
439 		case 1:
440 			settings->results_path = absolute_path(argv[optind]);
441 			break;
442 		case 0:
443 			usage("Results-path missing", stderr);
444 			goto error;
445 		default:
446 			usage("Extra arguments after results-path", stderr);
447 			goto error;
448 		}
449 		if (!settings->name) {
450 			char *name = strdup(settings->results_path);
451 
452 			settings->name = strdup(basename(name));
453 			free(name);
454 		}
455 	}
456 
457 	if ((env_test_root = getenv("IGT_TEST_ROOT")) != NULL) {
458 		free(settings->test_root);
459 		settings->test_root = absolute_path(env_test_root);
460 	}
461 
462 	if (!settings->test_root) {
463 		usage("Test root not set", stderr);
464 		goto error;
465 	}
466 
467 
468 	return true;
469 
470  error:
471 	free_settings(settings);
472 	return false;
473 }
474 
validate_settings(struct settings * settings)475 bool validate_settings(struct settings *settings)
476 {
477 	int dirfd, fd;
478 
479 	if (settings->test_list && !readable_file(settings->test_list)) {
480 		usage("Cannot open test-list file", stderr);
481 		return false;
482 	}
483 
484 	if (!settings->results_path) {
485 		usage("No results-path set; this shouldn't happen", stderr);
486 		return false;
487 	}
488 
489 	if (!settings->test_root) {
490 		usage("No test root set; this shouldn't happen", stderr);
491 		return false;
492 	}
493 
494 	dirfd = open(settings->test_root, O_DIRECTORY | O_RDONLY);
495 	if (dirfd < 0) {
496 		fprintf(stderr, "Test directory %s cannot be opened\n", settings->test_root);
497 		return false;
498 	}
499 
500 	fd = openat(dirfd, "test-list.txt", O_RDONLY);
501 	if (fd < 0) {
502 		fprintf(stderr, "Cannot open %s/test-list.txt\n", settings->test_root);
503 		close(dirfd);
504 		return false;
505 	}
506 
507 	close(fd);
508 	close(dirfd);
509 
510 	return true;
511 }
512 
_dirname(const char * path)513 static char *_dirname(const char *path)
514 {
515 	char *tmppath = strdup(path);
516 	char *tmpname = dirname(tmppath);
517 	tmpname = strdup(tmpname);
518 	free(tmppath);
519 	return tmpname;
520 }
521 
_basename(const char * path)522 static char *_basename(const char *path)
523 {
524 	char *tmppath = strdup(path);
525 	char *tmpname = basename(tmppath);
526 	tmpname = strdup(tmpname);
527 	free(tmppath);
528 	return tmpname;
529 }
530 
absolute_path(char * path)531 char *absolute_path(char *path)
532 {
533 	char *result = NULL;
534 	char *base, *dir;
535 	char *ret;
536 
537 	result = realpath(path, NULL);
538 	if (result != NULL)
539 		return result;
540 
541 	dir = _dirname(path);
542 	ret = absolute_path(dir);
543 	free(dir);
544 
545 	base = _basename(path);
546 	asprintf(&result, "%s/%s", ret, base);
547 	free(base);
548 	free(ret);
549 
550 	return result;
551 }
552 
553 static char settings_filename[] = "metadata.txt";
serialize_settings(struct settings * settings)554 bool serialize_settings(struct settings *settings)
555 {
556 #define SERIALIZE_LINE(f, s, name, format) fprintf(f, "%s : " format "\n", #name, s->name)
557 
558 	int dirfd, fd;
559 	FILE *f;
560 
561 	if (!settings->results_path) {
562 		usage("No results-path set; this shouldn't happen", stderr);
563 		return false;
564 	}
565 
566 	if ((dirfd = open(settings->results_path, O_DIRECTORY | O_RDONLY)) < 0) {
567 		mkdir(settings->results_path, 0755);
568 		if ((dirfd = open(settings->results_path, O_DIRECTORY | O_RDONLY)) < 0) {
569 			usage("Creating results-path failed", stderr);
570 			return false;
571 		}
572 	}
573 
574 	if (!settings->overwrite &&
575 	    faccessat(dirfd, settings_filename, F_OK, 0) == 0) {
576 		usage("Settings metadata already exists and not overwriting", stderr);
577 		return false;
578 	}
579 
580 	if (settings->overwrite &&
581 	    unlinkat(dirfd, settings_filename, 0) != 0 &&
582 	    errno != ENOENT) {
583 		usage("Error removing old settings metadata", stderr);
584 		return false;
585 	}
586 
587 	if ((fd = openat(dirfd, settings_filename, O_CREAT | O_EXCL | O_WRONLY, 0666)) < 0) {
588 		char *msg;
589 
590 		asprintf(&msg, "Creating settings serialization file failed: %s", strerror(errno));
591 		usage(msg, stderr);
592 
593 		free(msg);
594 		close(dirfd);
595 		return false;
596 	}
597 
598 	f = fdopen(fd, "w");
599 	if (!f) {
600 		close(fd);
601 		close(dirfd);
602 		return false;
603 	}
604 
605 	SERIALIZE_LINE(f, settings, abort_mask, "%d");
606 	if (settings->test_list)
607 		SERIALIZE_LINE(f, settings, test_list, "%s");
608 	if (settings->name)
609 		SERIALIZE_LINE(f, settings, name, "%s");
610 	SERIALIZE_LINE(f, settings, dry_run, "%d");
611 	SERIALIZE_LINE(f, settings, sync, "%d");
612 	SERIALIZE_LINE(f, settings, log_level, "%d");
613 	SERIALIZE_LINE(f, settings, overwrite, "%d");
614 	SERIALIZE_LINE(f, settings, multiple_mode, "%d");
615 	SERIALIZE_LINE(f, settings, inactivity_timeout, "%d");
616 	SERIALIZE_LINE(f, settings, overall_timeout, "%d");
617 	SERIALIZE_LINE(f, settings, use_watchdog, "%d");
618 	SERIALIZE_LINE(f, settings, piglit_style_dmesg, "%d");
619 	SERIALIZE_LINE(f, settings, dmesg_warn_level, "%d");
620 	SERIALIZE_LINE(f, settings, test_root, "%s");
621 	SERIALIZE_LINE(f, settings, results_path, "%s");
622 
623 	if (settings->sync) {
624 		fsync(fd);
625 		fsync(dirfd);
626 	}
627 
628 	fclose(f);
629 	close(dirfd);
630 	return true;
631 
632 #undef SERIALIZE_LINE
633 }
634 
read_settings_from_file(struct settings * settings,FILE * f)635 bool read_settings_from_file(struct settings *settings, FILE *f)
636 {
637 #define PARSE_LINE(s, name, val, field, write) \
638 	if (!strcmp(name, #field)) {	       \
639 		s->field = write;	       \
640 		free(name);		       \
641 		free(val);		       \
642 		name = val = NULL;	       \
643 		continue;		       \
644 	}
645 
646 	char *name = NULL, *val = NULL;
647 
648 	settings->dmesg_warn_level = -1;
649 
650 	while (fscanf(f, "%ms : %ms", &name, &val) == 2) {
651 		int numval = atoi(val);
652 		PARSE_LINE(settings, name, val, abort_mask, numval);
653 		PARSE_LINE(settings, name, val, test_list, val ? strdup(val) : NULL);
654 		PARSE_LINE(settings, name, val, name, val ? strdup(val) : NULL);
655 		PARSE_LINE(settings, name, val, dry_run, numval);
656 		PARSE_LINE(settings, name, val, sync, numval);
657 		PARSE_LINE(settings, name, val, log_level, numval);
658 		PARSE_LINE(settings, name, val, overwrite, numval);
659 		PARSE_LINE(settings, name, val, multiple_mode, numval);
660 		PARSE_LINE(settings, name, val, inactivity_timeout, numval);
661 		PARSE_LINE(settings, name, val, overall_timeout, numval);
662 		PARSE_LINE(settings, name, val, use_watchdog, numval);
663 		PARSE_LINE(settings, name, val, piglit_style_dmesg, numval);
664 		PARSE_LINE(settings, name, val, dmesg_warn_level, numval);
665 		PARSE_LINE(settings, name, val, test_root, val ? strdup(val) : NULL);
666 		PARSE_LINE(settings, name, val, results_path, val ? strdup(val) : NULL);
667 
668 		printf("Warning: Unknown field in settings file: %s = %s\n",
669 		       name, val);
670 		free(name);
671 		free(val);
672 		name = val = NULL;
673 	}
674 
675 	if (settings->dmesg_warn_level < 0) {
676 		if (settings->piglit_style_dmesg)
677 			settings->dmesg_warn_level = 5;
678 		else
679 			settings->dmesg_warn_level = 4;
680 	}
681 
682 	free(name);
683 	free(val);
684 
685 	return true;
686 
687 #undef PARSE_LINE
688 }
689 
read_settings_from_dir(struct settings * settings,int dirfd)690 bool read_settings_from_dir(struct settings *settings, int dirfd)
691 {
692 	int fd;
693 	FILE *f;
694 
695 	free_settings(settings);
696 
697 	if ((fd = openat(dirfd, settings_filename, O_RDONLY)) < 0)
698 		return false;
699 
700 	f = fdopen(fd, "r");
701 	if (!f) {
702 		close(fd);
703 		return false;
704 	}
705 
706 	if (!read_settings_from_file(settings, f)) {
707 		fclose(f);
708 		return false;
709 	}
710 
711 	fclose(f);
712 
713 	return true;
714 }
715