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