• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2015-2016 Cyril Hrubis <chrubis@suse.cz>
4  */
5 
6 #include <limits.h>
7 #include <stdio.h>
8 #include <stdarg.h>
9 #include <unistd.h>
10 #include <string.h>
11 #include <stdlib.h>
12 #include <errno.h>
13 #include <sys/mount.h>
14 #include <sys/types.h>
15 #include <sys/wait.h>
16 
17 #define TST_NO_DEFAULT_MAIN
18 #include "tst_test.h"
19 #include "tst_device.h"
20 #include "lapi/futex.h"
21 #include "lapi/syscalls.h"
22 #include "tst_ansi_color.h"
23 #include "tst_safe_stdio.h"
24 #include "tst_timer_test.h"
25 #include "tst_clocks.h"
26 #include "tst_timer.h"
27 #include "tst_wallclock.h"
28 #include "tst_sys_conf.h"
29 #include "tst_kconfig.h"
30 
31 #include "old_resource.h"
32 #include "old_device.h"
33 #include "old_tmpdir.h"
34 
35 /*
36  * Hack to get TCID defined in newlib tests
37  */
38 const char *TCID __attribute__((weak));
39 
40 #define LINUX_GIT_URL "https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id="
41 #define CVE_DB_URL "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-"
42 
43 struct tst_test *tst_test;
44 
45 static const char *tid;
46 static int iterations = 1;
47 static float duration = -1;
48 static float timeout_mul = -1;
49 static pid_t main_pid, lib_pid;
50 static int mntpoint_mounted;
51 static int ovl_mounted;
52 static struct timespec tst_start_time; /* valid only for test pid */
53 
54 struct results {
55 	int passed;
56 	int skipped;
57 	int failed;
58 	int warnings;
59 	unsigned int timeout;
60 };
61 
62 static struct results *results;
63 
64 static int ipc_fd;
65 
66 extern void *tst_futexes;
67 extern unsigned int tst_max_futexes;
68 
69 #define IPC_ENV_VAR "LTP_IPC_PATH"
70 
71 static char ipc_path[1064];
72 const char *tst_ipc_path = ipc_path;
73 
74 static char shm_path[1024];
75 
76 int TST_ERR;
77 long TST_RET;
78 
79 static void do_cleanup(void);
80 static void do_exit(int ret) __attribute__ ((noreturn));
81 
setup_ipc(void)82 static void setup_ipc(void)
83 {
84 	size_t size = getpagesize();
85 
86 	if (access("/dev/shm", F_OK) == 0) {
87 		snprintf(shm_path, sizeof(shm_path), "/dev/shm/ltp_%s_%d",
88 		         tid, getpid());
89 	} else {
90 		char *tmpdir;
91 
92 		if (!tst_tmpdir_created())
93 			tst_tmpdir();
94 
95 		tmpdir = tst_get_tmpdir();
96 		snprintf(shm_path, sizeof(shm_path), "%s/ltp_%s_%d",
97 		         tmpdir, tid, getpid());
98 		free(tmpdir);
99 	}
100 
101 	ipc_fd = open(shm_path, O_CREAT | O_EXCL | O_RDWR, 0600);
102 	if (ipc_fd < 0)
103 		tst_brk(TBROK | TERRNO, "open(%s)", shm_path);
104 	SAFE_CHMOD(shm_path, 0666);
105 
106 	SAFE_FTRUNCATE(ipc_fd, size);
107 
108 	results = SAFE_MMAP(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, ipc_fd, 0);
109 
110 	/* Checkpoints needs to be accessible from processes started by exec() */
111 	if (tst_test->needs_checkpoints || tst_test->child_needs_reinit) {
112 		sprintf(ipc_path, IPC_ENV_VAR "=%s", shm_path);
113 		putenv(ipc_path);
114 	} else {
115 		SAFE_UNLINK(shm_path);
116 	}
117 
118 	SAFE_CLOSE(ipc_fd);
119 
120 	if (tst_test->needs_checkpoints) {
121 		tst_futexes = (char*)results + sizeof(struct results);
122 		tst_max_futexes = (size - sizeof(struct results))/sizeof(futex_t);
123 	}
124 }
125 
cleanup_ipc(void)126 static void cleanup_ipc(void)
127 {
128 	size_t size = getpagesize();
129 
130 	if (ipc_fd > 0 && close(ipc_fd))
131 		tst_res(TWARN | TERRNO, "close(ipc_fd) failed");
132 
133 	if (shm_path[0] && !access(shm_path, F_OK) && unlink(shm_path))
134 		tst_res(TWARN | TERRNO, "unlink(%s) failed", shm_path);
135 
136 	if (results) {
137 		msync((void*)results, size, MS_SYNC);
138 		munmap((void*)results, size);
139 		results = NULL;
140 	}
141 }
142 
tst_reinit(void)143 void tst_reinit(void)
144 {
145 	const char *path = getenv(IPC_ENV_VAR);
146 	size_t size = getpagesize();
147 	int fd;
148 
149 	if (!path)
150 		tst_brk(TBROK, IPC_ENV_VAR" is not defined");
151 
152 	if (access(path, F_OK))
153 		tst_brk(TBROK, "File %s does not exist!", path);
154 
155 	fd = SAFE_OPEN(path, O_RDWR);
156 
157 	results = SAFE_MMAP(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
158 	tst_futexes = (char*)results + sizeof(struct results);
159 	tst_max_futexes = (size - sizeof(struct results))/sizeof(futex_t);
160 
161 	SAFE_CLOSE(fd);
162 }
163 
update_results(int ttype)164 static void update_results(int ttype)
165 {
166 	if (!results)
167 		return;
168 
169 	switch (ttype) {
170 	case TCONF:
171 		tst_atomic_inc(&results->skipped);
172 	break;
173 	case TPASS:
174 		tst_atomic_inc(&results->passed);
175 	break;
176 	case TWARN:
177 		tst_atomic_inc(&results->warnings);
178 	break;
179 	case TFAIL:
180 		tst_atomic_inc(&results->failed);
181 	break;
182 	}
183 }
184 
print_result(const char * file,const int lineno,int ttype,const char * fmt,va_list va)185 static void print_result(const char *file, const int lineno, int ttype,
186                          const char *fmt, va_list va)
187 {
188 	char buf[1024];
189 	char *str = buf;
190 	int ret, size = sizeof(buf), ssize, int_errno, buflen;
191 	const char *str_errno = NULL;
192 	const char *res;
193 
194 	switch (TTYPE_RESULT(ttype)) {
195 	case TPASS:
196 		res = "PASS";
197 	break;
198 	case TFAIL:
199 		res = "FAIL";
200 	break;
201 	case TBROK:
202 		res = "BROK";
203 	break;
204 	case TCONF:
205 		res = "CONF";
206 	break;
207 	case TWARN:
208 		res = "WARN";
209 	break;
210 	case TINFO:
211 		res = "INFO";
212 	break;
213 	default:
214 		tst_brk(TBROK, "Invalid ttype value %i", ttype);
215 		abort();
216 	}
217 
218 	if (ttype & TERRNO) {
219 		str_errno = tst_strerrno(errno);
220 		int_errno = errno;
221 	}
222 
223 	if (ttype & TTERRNO) {
224 		str_errno = tst_strerrno(TST_ERR);
225 		int_errno = TST_ERR;
226 	}
227 
228 	if (ttype & TRERRNO) {
229 		int_errno = TST_RET < 0 ? -(int)TST_RET : (int)TST_RET;
230 		str_errno = tst_strerrno(int_errno);
231 	}
232 
233 	ret = snprintf(str, size, "%s:%i: ", file, lineno);
234 	str += ret;
235 	size -= ret;
236 
237 	if (tst_color_enabled(STDERR_FILENO))
238 		ret = snprintf(str, size, "%s%s: %s", tst_ttype2color(ttype),
239 			       res, ANSI_COLOR_RESET);
240 	else
241 		ret = snprintf(str, size, "%s: ", res);
242 	str += ret;
243 	size -= ret;
244 
245 	ssize = size - 2;
246 	ret = vsnprintf(str, size, fmt, va);
247 	str += MIN(ret, ssize);
248 	size -= MIN(ret, ssize);
249 	if (ret >= ssize) {
250 		tst_res_(file, lineno, TWARN,
251 				"Next message is too long and truncated:");
252 	} else if (str_errno) {
253 		ssize = size - 2;
254 		ret = snprintf(str, size, ": %s (%d)", str_errno, int_errno);
255 		str += MIN(ret, ssize);
256 		size -= MIN(ret, ssize);
257 		if (ret >= ssize)
258 			tst_res_(file, lineno, TWARN,
259 				"Next message is too long and truncated:");
260 	}
261 
262 	snprintf(str, size, "\n");
263 
264 	/* we might be called from signal handler, so use write() */
265 	buflen = str - buf + 1;
266 	str = buf;
267 	while (buflen) {
268 		ret = write(STDERR_FILENO, str, buflen);
269 		if (ret <= 0)
270 			break;
271 
272 		str += ret;
273 		buflen -= ret;
274 	}
275 }
276 
tst_vres_(const char * file,const int lineno,int ttype,const char * fmt,va_list va)277 void tst_vres_(const char *file, const int lineno, int ttype,
278                const char *fmt, va_list va)
279 {
280 	print_result(file, lineno, ttype, fmt, va);
281 
282 	update_results(TTYPE_RESULT(ttype));
283 }
284 
285 void tst_vbrk_(const char *file, const int lineno, int ttype,
286                const char *fmt, va_list va);
287 
288 static void (*tst_brk_handler)(const char *file, const int lineno, int ttype,
289 			       const char *fmt, va_list va) = tst_vbrk_;
290 
tst_cvres(const char * file,const int lineno,int ttype,const char * fmt,va_list va)291 static void tst_cvres(const char *file, const int lineno, int ttype,
292 		      const char *fmt, va_list va)
293 {
294 	if (TTYPE_RESULT(ttype) == TBROK) {
295 		ttype &= ~TTYPE_MASK;
296 		ttype |= TWARN;
297 	}
298 
299 	print_result(file, lineno, ttype, fmt, va);
300 	update_results(TTYPE_RESULT(ttype));
301 }
302 
do_test_cleanup(void)303 static void do_test_cleanup(void)
304 {
305 	tst_brk_handler = tst_cvres;
306 
307 	if (tst_test->cleanup)
308 		tst_test->cleanup();
309 
310 	tst_free_all();
311 
312 	tst_brk_handler = tst_vbrk_;
313 }
314 
tst_vbrk_(const char * file,const int lineno,int ttype,const char * fmt,va_list va)315 void tst_vbrk_(const char *file, const int lineno, int ttype,
316                const char *fmt, va_list va)
317 {
318 	print_result(file, lineno, ttype, fmt, va);
319 
320 	/*
321 	 * The getpid implementation in some C library versions may cause cloned
322 	 * test threads to show the same pid as their parent when CLONE_VM is
323 	 * specified but CLONE_THREAD is not. Use direct syscall to avoid
324 	 * cleanup running in the child.
325 	 */
326 	if (syscall(SYS_getpid) == main_pid)
327 		do_test_cleanup();
328 
329 	if (getpid() == lib_pid)
330 		do_exit(TTYPE_RESULT(ttype));
331 
332 	exit(TTYPE_RESULT(ttype));
333 }
334 
tst_res_(const char * file,const int lineno,int ttype,const char * fmt,...)335 void tst_res_(const char *file, const int lineno, int ttype,
336               const char *fmt, ...)
337 {
338 	va_list va;
339 
340 	va_start(va, fmt);
341 	tst_vres_(file, lineno, ttype, fmt, va);
342 	va_end(va);
343 }
344 
tst_brk_(const char * file,const int lineno,int ttype,const char * fmt,...)345 void tst_brk_(const char *file, const int lineno, int ttype,
346               const char *fmt, ...)
347 {
348 	va_list va;
349 
350 	va_start(va, fmt);
351 	tst_brk_handler(file, lineno, ttype, fmt, va);
352 	va_end(va);
353 }
354 
check_child_status(pid_t pid,int status)355 static void check_child_status(pid_t pid, int status)
356 {
357 	int ret;
358 
359 	if (WIFSIGNALED(status)) {
360 		tst_brk(TBROK, "Child (%i) killed by signal %s",
361 		        pid, tst_strsig(WTERMSIG(status)));
362 	}
363 
364 	if (!(WIFEXITED(status)))
365 		tst_brk(TBROK, "Child (%i) exited abnormaly", pid);
366 
367 	ret = WEXITSTATUS(status);
368 	switch (ret) {
369 	case TPASS:
370 	break;
371 	case TBROK:
372 	case TCONF:
373 		tst_brk(ret, "Reported by child (%i)", pid);
374 	break;
375 	default:
376 		tst_brk(TBROK, "Invalid child (%i) exit value %i", pid, ret);
377 	}
378 }
379 
tst_reap_children(void)380 void tst_reap_children(void)
381 {
382 	int status;
383 	pid_t pid;
384 
385 	for (;;) {
386 		pid = wait(&status);
387 
388 		if (pid > 0) {
389 			check_child_status(pid, status);
390 			continue;
391 		}
392 
393 		if (errno == ECHILD)
394 			break;
395 
396 		if (errno == EINTR)
397 			continue;
398 
399 		tst_brk(TBROK | TERRNO, "wait() failed");
400 	}
401 }
402 
403 
safe_fork(const char * filename,unsigned int lineno)404 pid_t safe_fork(const char *filename, unsigned int lineno)
405 {
406 	pid_t pid;
407 
408 	if (!tst_test->forks_child)
409 		tst_brk(TBROK, "test.forks_child must be set!");
410 
411 	tst_flush();
412 
413 	pid = fork();
414 	if (pid < 0)
415 		tst_brk_(filename, lineno, TBROK | TERRNO, "fork() failed");
416 
417 	if (!pid)
418 		atexit(tst_free_all);
419 
420 	return pid;
421 }
422 
423 static struct option {
424 	char *optstr;
425 	char *help;
426 } options[] = {
427 	{"h",  "-h       Prints this help"},
428 	{"i:", "-i n     Execute test n times"},
429 	{"I:", "-I x     Execute test for n seconds"},
430 	{"C:", "-C ARG   Run child process with ARG arguments (used internally)"},
431 };
432 
print_help(void)433 static void print_help(void)
434 {
435 	unsigned int i;
436 
437 	fprintf(stderr, "Options\n");
438 	fprintf(stderr, "-------\n");
439 
440 	for (i = 0; i < ARRAY_SIZE(options); i++)
441 		fprintf(stderr, "%s\n", options[i].help);
442 
443 	if (!tst_test->options)
444 		return;
445 
446 	for (i = 0; tst_test->options[i].optstr; i++)
447 		fprintf(stderr, "%s\n", tst_test->options[i].help);
448 }
449 
print_test_tags(void)450 static void print_test_tags(void)
451 {
452 	unsigned int i;
453 	const struct tst_tag *tags = tst_test->tags;
454 
455 	if (!tags)
456 		return;
457 
458 	printf("\nTags\n");
459 	printf("----\n");
460 
461 	for (i = 0; tags[i].name; i++) {
462 		if (!strcmp(tags[i].name, "CVE"))
463 			printf(CVE_DB_URL "%s\n", tags[i].value);
464 		else if (!strcmp(tags[i].name, "linux-git"))
465 			printf(LINUX_GIT_URL "%s\n", tags[i].value);
466 		else
467 			printf("%s: %s\n", tags[i].name, tags[i].value);
468 	}
469 
470 	printf("\n");
471 }
472 
check_option_collision(void)473 static void check_option_collision(void)
474 {
475 	unsigned int i, j;
476 	struct tst_option *toptions = tst_test->options;
477 
478 	if (!toptions)
479 		return;
480 
481 	for (i = 0; toptions[i].optstr; i++) {
482 		for (j = 0; j < ARRAY_SIZE(options); j++) {
483 			if (toptions[i].optstr[0] == options[j].optstr[0]) {
484 				tst_brk(TBROK, "Option collision '%s'",
485 				        options[j].help);
486 			}
487 		}
488 	}
489 }
490 
count_options(void)491 static unsigned int count_options(void)
492 {
493 	unsigned int i;
494 
495 	if (!tst_test->options)
496 		return 0;
497 
498 	for (i = 0; tst_test->options[i].optstr; i++);
499 
500 	return i;
501 }
502 
parse_topt(unsigned int topts_len,int opt,char * optarg)503 static void parse_topt(unsigned int topts_len, int opt, char *optarg)
504 {
505 	unsigned int i;
506 	struct tst_option *toptions = tst_test->options;
507 
508 	for (i = 0; i < topts_len; i++) {
509 		if (toptions[i].optstr[0] == opt)
510 			break;
511 	}
512 
513 	if (i >= topts_len)
514 		tst_brk(TBROK, "Invalid option '%c' (should not happen)", opt);
515 
516 	if (*toptions[i].arg)
517 		tst_res(TWARN, "Option -%c passed multiple times", opt);
518 
519 	*(toptions[i].arg) = optarg ? optarg : "";
520 }
521 
522 /* see self_exec.c */
523 #ifdef UCLINUX
524 extern char *child_args;
525 #endif
526 
parse_opts(int argc,char * argv[])527 static void parse_opts(int argc, char *argv[])
528 {
529 	unsigned int i, topts_len = count_options();
530 	char optstr[2 * ARRAY_SIZE(options) + 2 * topts_len];
531 	int opt;
532 
533 	check_option_collision();
534 
535 	optstr[0] = 0;
536 
537 	for (i = 0; i < ARRAY_SIZE(options); i++)
538 		strcat(optstr, options[i].optstr);
539 
540 	for (i = 0; i < topts_len; i++)
541 		strcat(optstr, tst_test->options[i].optstr);
542 
543 	while ((opt = getopt(argc, argv, optstr)) > 0) {
544 		switch (opt) {
545 		case '?':
546 			print_help();
547 			tst_brk(TBROK, "Invalid option");
548 		break;
549 		case 'h':
550 			print_help();
551 			print_test_tags();
552 			exit(0);
553 		case 'i':
554 			iterations = atoi(optarg);
555 		break;
556 		case 'I':
557 			duration = atof(optarg);
558 		break;
559 		case 'C':
560 #ifdef UCLINUX
561 			child_args = optarg;
562 #endif
563 		break;
564 		default:
565 			parse_topt(topts_len, opt, optarg);
566 		}
567 	}
568 
569 	if (optind < argc)
570 		tst_brk(TBROK, "Unexpected argument(s) '%s'...", argv[optind]);
571 }
572 
tst_parse_int(const char * str,int * val,int min,int max)573 int tst_parse_int(const char *str, int *val, int min, int max)
574 {
575 	long rval;
576 
577 	if (!str)
578 		return 0;
579 
580 	int ret = tst_parse_long(str, &rval, min, max);
581 
582 	if (ret)
583 		return ret;
584 
585 	*val = (int)rval;
586 	return 0;
587 }
588 
tst_parse_long(const char * str,long * val,long min,long max)589 int tst_parse_long(const char *str, long *val, long min, long max)
590 {
591 	long rval;
592 	char *end;
593 
594 	if (!str)
595 		return 0;
596 
597 	errno = 0;
598 	rval = strtol(str, &end, 10);
599 
600 	if (str == end || *end != '\0')
601 		return EINVAL;
602 
603 	if (errno)
604 		return errno;
605 
606 	if (rval > max || rval < min)
607 		return ERANGE;
608 
609 	*val = rval;
610 	return 0;
611 }
612 
tst_parse_float(const char * str,float * val,float min,float max)613 int tst_parse_float(const char *str, float *val, float min, float max)
614 {
615 	double rval;
616 	char *end;
617 
618 	if (!str)
619 		return 0;
620 
621 	errno = 0;
622 	rval = strtod(str, &end);
623 
624 	if (str == end || *end != '\0')
625 		return EINVAL;
626 
627 	if (errno)
628 		return errno;
629 
630 	if (rval > (double)max || rval < (double)min)
631 		return ERANGE;
632 
633 	*val = (float)rval;
634 	return 0;
635 }
636 
print_colored(const char * str)637 static void print_colored(const char *str)
638 {
639 	if (tst_color_enabled(STDOUT_FILENO))
640 		printf("%s%s%s", ANSI_COLOR_YELLOW, str, ANSI_COLOR_RESET);
641 	else
642 		printf("%s", str);
643 }
644 
print_failure_hints(void)645 static void print_failure_hints(void)
646 {
647 	unsigned int i;
648 	const struct tst_tag *tags = tst_test->tags;
649 
650 	if (!tags)
651 		return;
652 
653 	int hint_printed = 0;
654 	for (i = 0; tags[i].name; i++) {
655 		if (!strcmp(tags[i].name, "linux-git")) {
656 			if (!hint_printed) {
657 				hint_printed = 1;
658 				printf("\n");
659 				print_colored("HINT: ");
660 				printf("You _MAY_ be missing kernel fixes, see:\n\n");
661 			}
662 
663 			printf(LINUX_GIT_URL "%s\n", tags[i].value);
664 		}
665 
666 	}
667 
668 	hint_printed = 0;
669 	for (i = 0; tags[i].name; i++) {
670 		if (!strcmp(tags[i].name, "CVE")) {
671 			if (!hint_printed) {
672 				hint_printed = 1;
673 				printf("\n");
674 				print_colored("HINT: ");
675 				printf("You _MAY_ be vunerable to CVE(s), see:\n\n");
676 			}
677 
678 			printf(CVE_DB_URL "%s\n", tags[i].value);
679 		}
680 	}
681 }
682 
do_exit(int ret)683 static void do_exit(int ret)
684 {
685 	if (results) {
686 		if (results->passed && ret == TCONF)
687 			ret = 0;
688 
689 		if (results->failed) {
690 			ret |= TFAIL;
691 			print_failure_hints();
692 		}
693 
694 		if (results->skipped && !results->passed)
695 			ret |= TCONF;
696 
697 		if (results->warnings)
698 			ret |= TWARN;
699 
700 		printf("\nSummary:\n");
701 		printf("passed   %d\n", results->passed);
702 		printf("failed   %d\n", results->failed);
703 		printf("skipped  %d\n", results->skipped);
704 		printf("warnings %d\n", results->warnings);
705 	}
706 
707 	do_cleanup();
708 
709 	exit(ret);
710 }
711 
check_kver(void)712 void check_kver(void)
713 {
714 	int v1, v2, v3;
715 
716 	if (tst_parse_kver(tst_test->min_kver, &v1, &v2, &v3)) {
717 		tst_res(TWARN,
718 		        "Invalid kernel version %s, expected %%d.%%d.%%d",
719 		        tst_test->min_kver);
720 	}
721 
722 	if (tst_kvercmp(v1, v2, v3) < 0) {
723 		tst_brk(TCONF, "The test requires kernel %s or newer",
724 		        tst_test->min_kver);
725 	}
726 }
727 
results_equal(struct results * a,struct results * b)728 static int results_equal(struct results *a, struct results *b)
729 {
730 	if (a->passed != b->passed)
731 		return 0;
732 
733 	if (a->failed != b->failed)
734 		return 0;
735 
736 	if (a->skipped != b->skipped)
737 		return 0;
738 
739 	return 1;
740 }
741 
needs_tmpdir(void)742 static int needs_tmpdir(void)
743 {
744 	return tst_test->needs_tmpdir ||
745 	       tst_test->needs_device ||
746 	       tst_test->mntpoint ||
747 	       tst_test->resource_files ||
748 	       tst_test->needs_checkpoints;
749 }
750 
copy_resources(void)751 static void copy_resources(void)
752 {
753 	unsigned int i;
754 
755 	for (i = 0; tst_test->resource_files[i]; i++)
756 		TST_RESOURCE_COPY(NULL, tst_test->resource_files[i], NULL);
757 }
758 
get_tid(char * argv[])759 static const char *get_tid(char *argv[])
760 {
761 	char *p;
762 
763 	if (!argv[0] || !argv[0][0]) {
764 		tst_res(TINFO, "argv[0] is empty!");
765 		return "ltp_empty_argv";
766 	}
767 
768 	p = strrchr(argv[0], '/');
769 	if (p)
770 		return p+1;
771 
772 	return argv[0];
773 }
774 
775 static struct tst_device tdev;
776 struct tst_device *tst_device;
777 
assert_test_fn(void)778 static void assert_test_fn(void)
779 {
780 	int cnt = 0;
781 
782 	if (tst_test->test)
783 		cnt++;
784 
785 	if (tst_test->test_all)
786 		cnt++;
787 
788 	if (tst_test->sample)
789 		cnt++;
790 
791 	if (!cnt)
792 		tst_brk(TBROK, "No test function speficied");
793 
794 	if (cnt != 1)
795 		tst_brk(TBROK, "You can define only one test function");
796 
797 	if (tst_test->test && !tst_test->tcnt)
798 		tst_brk(TBROK, "Number of tests (tcnt) must be > 0");
799 
800 	if (!tst_test->test && tst_test->tcnt)
801 		tst_brk(TBROK, "You can define tcnt only for test()");
802 }
803 
prepare_and_mount_ro_fs(const char * dev,const char * mntpoint,const char * fs_type)804 static int prepare_and_mount_ro_fs(const char *dev,
805                                    const char *mntpoint,
806                                    const char *fs_type)
807 {
808 	char buf[PATH_MAX];
809 
810 	if (mount(dev, mntpoint, fs_type, 0, NULL)) {
811 		tst_res(TINFO | TERRNO, "Can't mount %s at %s (%s)",
812 			dev, mntpoint, fs_type);
813 		return 1;
814 	}
815 
816 	mntpoint_mounted = 1;
817 
818 	snprintf(buf, sizeof(buf), "%s/dir/", mntpoint);
819 	SAFE_MKDIR(buf, 0777);
820 
821 	snprintf(buf, sizeof(buf), "%s/file", mntpoint);
822 	SAFE_FILE_PRINTF(buf, "file content");
823 	SAFE_CHMOD(buf, 0777);
824 
825 	SAFE_MOUNT(dev, mntpoint, fs_type, MS_REMOUNT | MS_RDONLY, NULL);
826 
827 	return 0;
828 }
829 
prepare_and_mount_dev_fs(const char * mntpoint)830 static void prepare_and_mount_dev_fs(const char *mntpoint)
831 {
832 	const char *flags[] = {"nodev", NULL};
833 	int mounted_nodev;
834 
835 	mounted_nodev = tst_path_has_mnt_flags(NULL, flags);
836 	if (mounted_nodev) {
837 		tst_res(TINFO, "tmpdir isn't suitable for creating devices, "
838 			"mounting tmpfs without nodev on %s", mntpoint);
839 		SAFE_MOUNT(NULL, mntpoint, "tmpfs", 0, NULL);
840 		mntpoint_mounted = 1;
841 	}
842 }
843 
prepare_device(void)844 static void prepare_device(void)
845 {
846 	if (tst_test->format_device) {
847 		SAFE_MKFS(tdev.dev, tdev.fs_type, tst_test->dev_fs_opts,
848 			  tst_test->dev_extra_opts);
849 	}
850 
851 	if (tst_test->needs_rofs) {
852 		prepare_and_mount_ro_fs(tdev.dev, tst_test->mntpoint,
853 		                        tdev.fs_type);
854 		return;
855 	}
856 
857 	if (tst_test->mount_device) {
858 		SAFE_MOUNT(tdev.dev, tst_test->mntpoint, tdev.fs_type,
859 			   tst_test->mnt_flags, tst_test->mnt_data);
860 		mntpoint_mounted = 1;
861 	}
862 }
863 
do_setup(int argc,char * argv[])864 static void do_setup(int argc, char *argv[])
865 {
866 	if (!tst_test)
867 		tst_brk(TBROK, "No tests to run");
868 
869 	if (tst_test->tconf_msg)
870 		tst_brk(TCONF, "%s", tst_test->tconf_msg);
871 
872 	if (tst_test->needs_kconfigs)
873 		tst_kconfig_check(tst_test->needs_kconfigs);
874 
875 	assert_test_fn();
876 
877 	tid = get_tid(argv);
878 
879 	if (tst_test->sample)
880 		tst_test = tst_timer_test_setup(tst_test);
881 
882 	parse_opts(argc, argv);
883 
884 	if (tst_test->needs_root && geteuid() != 0)
885 		tst_brk(TCONF, "Test needs to be run as root");
886 
887 	if (tst_test->min_kver)
888 		check_kver();
889 
890 	if (tst_test->needs_cmds) {
891 		const char *cmd;
892 		char path[PATH_MAX];
893 		int i;
894 
895 		for (i = 0; (cmd = tst_test->needs_cmds[i]); ++i)
896 			if (tst_get_path(cmd, path, sizeof(path)))
897 				tst_brk(TCONF, "Couldn't find '%s' in $PATH", cmd);
898 	}
899 
900 	if (tst_test->needs_drivers) {
901 		const char *name;
902 		int i;
903 
904 		for (i = 0; (name = tst_test->needs_drivers[i]); ++i)
905 			if (tst_check_driver(name))
906 				tst_brk(TCONF, "%s driver not available", name);
907 	}
908 
909 	if (tst_test->format_device)
910 		tst_test->needs_device = 1;
911 
912 	if (tst_test->mount_device) {
913 		tst_test->needs_device = 1;
914 		tst_test->format_device = 1;
915 	}
916 
917 	if (tst_test->all_filesystems)
918 		tst_test->needs_device = 1;
919 
920 	if (tst_test->request_hugepages)
921 		tst_request_hugepages(tst_test->request_hugepages);
922 
923 	setup_ipc();
924 
925 	if (tst_test->bufs)
926 		tst_buffers_alloc(tst_test->bufs);
927 
928 	if (needs_tmpdir() && !tst_tmpdir_created())
929 		tst_tmpdir();
930 
931 	if (tst_test->save_restore) {
932 		const char * const *name = tst_test->save_restore;
933 
934 		while (*name) {
935 			tst_sys_conf_save(*name);
936 			name++;
937 		}
938 	}
939 
940 	if (tst_test->mntpoint)
941 		SAFE_MKDIR(tst_test->mntpoint, 0777);
942 
943 	if ((tst_test->needs_devfs || tst_test->needs_rofs ||
944 	     tst_test->mount_device || tst_test->all_filesystems) &&
945 	     !tst_test->mntpoint) {
946 		tst_brk(TBROK, "tst_test->mntpoint must be set!");
947 	}
948 
949 	if (!!tst_test->needs_rofs + !!tst_test->needs_devfs +
950 	    !!tst_test->needs_device > 1) {
951 		tst_brk(TBROK,
952 			"Two or more of needs_{rofs, devfs, device} are set");
953 	}
954 
955 	if (tst_test->needs_devfs)
956 		prepare_and_mount_dev_fs(tst_test->mntpoint);
957 
958 	if (tst_test->needs_rofs) {
959 		/* If we failed to mount read-only tmpfs. Fallback to
960 		 * using a device with read-only filesystem.
961 		 */
962 		if (prepare_and_mount_ro_fs(NULL, tst_test->mntpoint, "tmpfs")) {
963 			tst_res(TINFO, "Can't mount tmpfs read-only, "
964 			        "falling back to block device...");
965 			tst_test->needs_device = 1;
966 			tst_test->format_device = 1;
967 		}
968 	}
969 
970 	if (tst_test->needs_device && !mntpoint_mounted) {
971 		tdev.dev = tst_acquire_device_(NULL, tst_test->dev_min_size);
972 
973 		if (!tdev.dev)
974 			tst_brk(TCONF, "Failed to acquire device");
975 
976 		tst_device = &tdev;
977 
978 		if (tst_test->dev_fs_type)
979 			tdev.fs_type = tst_test->dev_fs_type;
980 		else
981 			tdev.fs_type = tst_dev_fs_type();
982 
983 		if (!tst_test->all_filesystems)
984 			prepare_device();
985 	}
986 
987 	if (tst_test->needs_overlay && !tst_test->mount_device) {
988 		tst_brk(TBROK, "tst_test->mount_device must be set");
989 	}
990 	if (tst_test->needs_overlay && !mntpoint_mounted) {
991 		tst_brk(TBROK, "tst_test->mntpoint must be mounted");
992 	}
993 	if (tst_test->needs_overlay && !ovl_mounted) {
994 		SAFE_MOUNT_OVERLAY();
995 		ovl_mounted = 1;
996 	}
997 
998 	if (tst_test->resource_files)
999 		copy_resources();
1000 
1001 	if (tst_test->restore_wallclock)
1002 		tst_wallclock_save();
1003 }
1004 
do_test_setup(void)1005 static void do_test_setup(void)
1006 {
1007 	main_pid = getpid();
1008 
1009 	if (tst_test->caps)
1010 		tst_cap_setup(tst_test->caps, TST_CAP_REQ);
1011 
1012 	if (tst_test->setup)
1013 		tst_test->setup();
1014 
1015 	if (main_pid != getpid())
1016 		tst_brk(TBROK, "Runaway child in setup()!");
1017 
1018 	if (tst_test->caps)
1019 		tst_cap_setup(tst_test->caps, TST_CAP_DROP);
1020 }
1021 
do_cleanup(void)1022 static void do_cleanup(void)
1023 {
1024 	if (ovl_mounted)
1025 		SAFE_UMOUNT(OVL_MNT);
1026 
1027 	if (mntpoint_mounted)
1028 		tst_umount(tst_test->mntpoint);
1029 
1030 	if (tst_test->needs_device && tdev.dev)
1031 		tst_release_device(tdev.dev);
1032 
1033 	if (tst_tmpdir_created()) {
1034 		/* avoid munmap() on wrong pointer in tst_rmdir() */
1035 		tst_futexes = NULL;
1036 		tst_rmdir();
1037 	}
1038 
1039 	tst_sys_conf_restore(0);
1040 
1041 	if (tst_test->restore_wallclock)
1042 		tst_wallclock_restore();
1043 
1044 	cleanup_ipc();
1045 }
1046 
run_tests(void)1047 static void run_tests(void)
1048 {
1049 	unsigned int i;
1050 	struct results saved_results;
1051 
1052 	if (!tst_test->test) {
1053 		saved_results = *results;
1054 		tst_test->test_all();
1055 
1056 		if (getpid() != main_pid) {
1057 			exit(0);
1058 		}
1059 
1060 		tst_reap_children();
1061 
1062 		if (results_equal(&saved_results, results))
1063 			tst_brk(TBROK, "Test haven't reported results!");
1064 		return;
1065 	}
1066 
1067 	for (i = 0; i < tst_test->tcnt; i++) {
1068 		saved_results = *results;
1069 		tst_test->test(i);
1070 
1071 		if (getpid() != main_pid) {
1072 			exit(0);
1073 		}
1074 
1075 		tst_reap_children();
1076 
1077 		if (results_equal(&saved_results, results))
1078 			tst_brk(TBROK, "Test %i haven't reported results!", i);
1079 	}
1080 }
1081 
get_time_ms(void)1082 static unsigned long long get_time_ms(void)
1083 {
1084 	struct timespec ts;
1085 
1086 	if (tst_clock_gettime(CLOCK_MONOTONIC, &ts))
1087 		tst_brk(TBROK | TERRNO, "tst_clock_gettime()");
1088 
1089 	return tst_timespec_to_ms(ts);
1090 }
1091 
add_paths(void)1092 static void add_paths(void)
1093 {
1094 	char *old_path = getenv("PATH");
1095 	const char *start_dir;
1096 	char *new_path;
1097 
1098 	start_dir = tst_get_startwd();
1099 
1100 	if (old_path)
1101 		SAFE_ASPRINTF(&new_path, "%s::%s", old_path, start_dir);
1102 	else
1103 		SAFE_ASPRINTF(&new_path, "::%s", start_dir);
1104 
1105 	SAFE_SETENV("PATH", new_path, 1);
1106 	free(new_path);
1107 }
1108 
heartbeat(void)1109 static void heartbeat(void)
1110 {
1111 	if (tst_clock_gettime(CLOCK_MONOTONIC, &tst_start_time))
1112 		tst_res(TWARN | TERRNO, "tst_clock_gettime() failed");
1113 
1114 	kill(getppid(), SIGUSR1);
1115 }
1116 
testrun(void)1117 static void testrun(void)
1118 {
1119 	unsigned int i = 0;
1120 	unsigned long long stop_time = 0;
1121 	int cont = 1;
1122 
1123 	heartbeat();
1124 	add_paths();
1125 	do_test_setup();
1126 
1127 	if (duration > 0)
1128 		stop_time = get_time_ms() + (unsigned long long)(duration * 1000);
1129 
1130 	for (;;) {
1131 		cont = 0;
1132 
1133 		if (i < (unsigned int)iterations) {
1134 			i++;
1135 			cont = 1;
1136 		}
1137 
1138 		if (stop_time && get_time_ms() < stop_time)
1139 			cont = 1;
1140 
1141 		if (!cont)
1142 			break;
1143 
1144 		run_tests();
1145 		heartbeat();
1146 	}
1147 
1148 	do_test_cleanup();
1149 	exit(0);
1150 }
1151 
1152 static pid_t test_pid;
1153 
1154 
1155 static volatile sig_atomic_t sigkill_retries;
1156 
1157 #define WRITE_MSG(msg) do { \
1158 	if (write(2, msg, sizeof(msg) - 1)) { \
1159 		/* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66425 */ \
1160 	} \
1161 } while (0)
1162 
alarm_handler(int sig LTP_ATTRIBUTE_UNUSED)1163 static void alarm_handler(int sig LTP_ATTRIBUTE_UNUSED)
1164 {
1165 	WRITE_MSG("Test timeouted, sending SIGKILL!\n");
1166 	kill(-test_pid, SIGKILL);
1167 	alarm(5);
1168 
1169 	if (++sigkill_retries > 10) {
1170 		WRITE_MSG("Cannot kill test processes!\n");
1171 		WRITE_MSG("Congratulation, likely test hit a kernel bug.\n");
1172 		WRITE_MSG("Exitting uncleanly...\n");
1173 		_exit(TFAIL);
1174 	}
1175 }
1176 
heartbeat_handler(int sig LTP_ATTRIBUTE_UNUSED)1177 static void heartbeat_handler(int sig LTP_ATTRIBUTE_UNUSED)
1178 {
1179 	alarm(results->timeout);
1180 	sigkill_retries = 0;
1181 }
1182 
sigint_handler(int sig LTP_ATTRIBUTE_UNUSED)1183 static void sigint_handler(int sig LTP_ATTRIBUTE_UNUSED)
1184 {
1185 	if (test_pid > 0) {
1186 		WRITE_MSG("Sending SIGKILL to test process...\n");
1187 		kill(-test_pid, SIGKILL);
1188 	}
1189 }
1190 
tst_timeout_remaining(void)1191 unsigned int tst_timeout_remaining(void)
1192 {
1193 	static struct timespec now;
1194 	unsigned int elapsed;
1195 
1196 	if (tst_clock_gettime(CLOCK_MONOTONIC, &now))
1197 		tst_res(TWARN | TERRNO, "tst_clock_gettime() failed");
1198 
1199 	elapsed = (tst_timespec_diff_ms(now, tst_start_time) + 500) / 1000;
1200 	if (results->timeout > elapsed)
1201 		return results->timeout - elapsed;
1202 
1203 	return 0;
1204 }
1205 
tst_multiply_timeout(unsigned int timeout)1206 unsigned int tst_multiply_timeout(unsigned int timeout)
1207 {
1208 	char *mul;
1209 	int ret;
1210 
1211 	if (timeout_mul == -1) {
1212 		mul = getenv("LTP_TIMEOUT_MUL");
1213 		if (mul) {
1214 			if ((ret = tst_parse_float(mul, &timeout_mul, 1, 10000))) {
1215 				tst_brk(TBROK, "Failed to parse LTP_TIMEOUT_MUL: %s",
1216 						tst_strerrno(ret));
1217 			}
1218 		} else {
1219 			timeout_mul = 1;
1220 		}
1221 	}
1222 	if (timeout_mul < 1)
1223 		tst_brk(TBROK, "LTP_TIMEOUT_MUL must to be int >= 1! (%.2f)",
1224 				timeout_mul);
1225 
1226 	if (timeout < 1)
1227 		tst_brk(TBROK, "timeout must to be >= 1! (%d)", timeout);
1228 
1229 	return timeout * timeout_mul;
1230 }
1231 
tst_set_timeout(int timeout)1232 void tst_set_timeout(int timeout)
1233 {
1234 	if (timeout == -1) {
1235 		tst_res(TINFO, "Timeout per run is disabled");
1236 		return;
1237 	}
1238 
1239 	if (timeout < 1)
1240 		tst_brk(TBROK, "timeout must to be >= 1! (%d)", timeout);
1241 
1242 	results->timeout = tst_multiply_timeout(timeout);
1243 
1244 	tst_res(TINFO, "Timeout per run is %uh %02um %02us",
1245 		results->timeout/3600, (results->timeout%3600)/60,
1246 		results->timeout % 60);
1247 
1248 	if (getpid() == lib_pid)
1249 		alarm(results->timeout);
1250 	else
1251 		heartbeat();
1252 }
1253 
fork_testrun(void)1254 static int fork_testrun(void)
1255 {
1256 	int status;
1257 
1258 	if (tst_test->timeout)
1259 		tst_set_timeout(tst_test->timeout);
1260 	else
1261 		tst_set_timeout(300);
1262 
1263 	SAFE_SIGNAL(SIGINT, sigint_handler);
1264 
1265 	test_pid = fork();
1266 	if (test_pid < 0)
1267 		tst_brk(TBROK | TERRNO, "fork()");
1268 
1269 	if (!test_pid) {
1270 		SAFE_SIGNAL(SIGALRM, SIG_DFL);
1271 		SAFE_SIGNAL(SIGUSR1, SIG_DFL);
1272 		SAFE_SIGNAL(SIGINT, SIG_DFL);
1273 		SAFE_SETPGID(0, 0);
1274 		testrun();
1275 	}
1276 
1277 	SAFE_WAITPID(test_pid, &status, 0);
1278 	alarm(0);
1279 	SAFE_SIGNAL(SIGINT, SIG_DFL);
1280 
1281 	if (WIFEXITED(status) && WEXITSTATUS(status))
1282 		return WEXITSTATUS(status);
1283 
1284 	if (WIFSIGNALED(status) && WTERMSIG(status) == SIGKILL) {
1285 		tst_res(TINFO, "If you are running on slow machine, "
1286 			       "try exporting LTP_TIMEOUT_MUL > 1");
1287 		tst_brk(TBROK, "Test killed! (timeout?)");
1288 	}
1289 
1290 	if (WIFSIGNALED(status))
1291 		tst_brk(TBROK, "Test killed by %s!", tst_strsig(WTERMSIG(status)));
1292 
1293 	return 0;
1294 }
1295 
run_tcases_per_fs(void)1296 static int run_tcases_per_fs(void)
1297 {
1298 	int ret = 0;
1299 	unsigned int i;
1300 	const char *const *filesystems = tst_get_supported_fs_types(tst_test->dev_fs_flags);
1301 
1302 	if (!filesystems[0])
1303 		tst_brk(TCONF, "There are no supported filesystems");
1304 
1305 	for (i = 0; filesystems[i]; i++) {
1306 
1307 		tst_res(TINFO, "Testing on %s", filesystems[i]);
1308 		tdev.fs_type = filesystems[i];
1309 
1310 		prepare_device();
1311 
1312 		ret = fork_testrun();
1313 
1314 		if (mntpoint_mounted) {
1315 			tst_umount(tst_test->mntpoint);
1316 			mntpoint_mounted = 0;
1317 		}
1318 
1319 		if (ret == TCONF) {
1320 			update_results(ret);
1321 			continue;
1322 		}
1323 
1324 		if (ret == 0)
1325 			continue;
1326 
1327 		do_exit(ret);
1328 	}
1329 
1330 	return ret;
1331 }
1332 
1333 unsigned int tst_variant;
1334 
tst_run_tcases(int argc,char * argv[],struct tst_test * self)1335 void tst_run_tcases(int argc, char *argv[], struct tst_test *self)
1336 {
1337 	int ret = 0;
1338 	unsigned int test_variants = 1;
1339 
1340 	lib_pid = getpid();
1341 	tst_test = self;
1342 
1343 	do_setup(argc, argv);
1344 
1345 	TCID = tid;
1346 
1347 	SAFE_SIGNAL(SIGALRM, alarm_handler);
1348 	SAFE_SIGNAL(SIGUSR1, heartbeat_handler);
1349 
1350 	if (tst_test->test_variants)
1351 		test_variants = tst_test->test_variants;
1352 
1353 	for (tst_variant = 0; tst_variant < test_variants; tst_variant++) {
1354 		if (tst_test->all_filesystems)
1355 			ret |= run_tcases_per_fs();
1356 		else
1357 			ret |= fork_testrun();
1358 
1359 		if (ret & ~(TCONF))
1360 			goto exit;
1361 	}
1362 
1363 exit:
1364 	do_exit(ret);
1365 }
1366 
1367 
tst_flush(void)1368 void tst_flush(void)
1369 {
1370 	int rval;
1371 
1372 	rval = fflush(stderr);
1373 	if (rval != 0)
1374 		tst_brk(TBROK | TERRNO, "fflush(stderr) failed");
1375 
1376 	rval = fflush(stderr);
1377 	if (rval != 0)
1378 		tst_brk(TBROK | TERRNO, "fflush(stdout) failed");
1379 
1380 }
1381