1/*
2 * Copyright (c) 2015-2016 Cyril Hrubis <chrubis@suse.cz>
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include <stdio.h>
19#include <stdarg.h>
20#include <unistd.h>
21#include <string.h>
22#include <stdlib.h>
23#include <errno.h>
24#include <sys/mount.h>
25#include <sys/types.h>
26#include <sys/wait.h>
27#include <sys/time.h>
28
29#define TST_NO_DEFAULT_MAIN
30#include "tst_test.h"
31#include "tst_device.h"
32#include "lapi/futex.h"
33#include "lapi/syscalls.h"
34#include "tst_ansi_color.h"
35#include "tst_safe_stdio.h"
36#include "tst_timer_test.h"
37
38#include "old_resource.h"
39#include "old_device.h"
40#include "old_tmpdir.h"
41
42struct tst_test *tst_test;
43
44static const char *tid;
45static int iterations = 1;
46static float duration = -1;
47static pid_t main_pid, lib_pid;
48static int mntpoint_mounted;
49
50struct results {
51	int passed;
52	int skipped;
53	int failed;
54	int warnings;
55	unsigned int timeout;
56};
57
58static struct results *results;
59
60static int ipc_fd;
61
62extern void *tst_futexes;
63extern unsigned int tst_max_futexes;
64
65#define IPC_ENV_VAR "LTP_IPC_PATH"
66
67static char ipc_path[1024];
68const char *tst_ipc_path = ipc_path;
69
70static char shm_path[1024];
71
72static void do_cleanup(void);
73static void do_exit(int ret) __attribute__ ((noreturn));
74
75static void setup_ipc(void)
76{
77	size_t size = getpagesize();
78
79	if (access("/dev/shm", F_OK) == 0) {
80		snprintf(shm_path, sizeof(shm_path), "/dev/shm/ltp_%s_%d",
81		         tid, getpid());
82	} else {
83		char *tmpdir;
84
85		if (!tst_tmpdir_created())
86			tst_tmpdir();
87
88		tmpdir = tst_get_tmpdir();
89		snprintf(shm_path, sizeof(shm_path), "%s/ltp_%s_%d",
90		         tmpdir, tid, getpid());
91		free(tmpdir);
92	}
93
94	ipc_fd = open(shm_path, O_CREAT | O_EXCL | O_RDWR, 0600);
95	if (ipc_fd < 0)
96		tst_brk(TBROK | TERRNO, "open(%s)", shm_path);
97	SAFE_CHMOD(shm_path, 0666);
98
99	SAFE_FTRUNCATE(ipc_fd, size);
100
101	results = SAFE_MMAP(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, ipc_fd, 0);
102
103	/* Checkpoints needs to be accessible from processes started by exec() */
104	if (tst_test->needs_checkpoints) {
105		sprintf(ipc_path, IPC_ENV_VAR "=%s", shm_path);
106		putenv(ipc_path);
107	} else {
108		SAFE_UNLINK(shm_path);
109	}
110
111	SAFE_CLOSE(ipc_fd);
112
113	if (tst_test->needs_checkpoints) {
114		tst_futexes = (char*)results + sizeof(struct results);
115		tst_max_futexes = (size - sizeof(struct results))/sizeof(futex_t);
116	}
117}
118
119static void cleanup_ipc(void)
120{
121	size_t size = getpagesize();
122
123	if (ipc_fd > 0 && close(ipc_fd))
124		tst_res(TWARN | TERRNO, "close(ipc_fd) failed");
125
126	if (shm_path[0] && !access(shm_path, F_OK) && unlink(shm_path))
127		tst_res(TWARN | TERRNO, "unlink(%s) failed", shm_path);
128
129	if (results) {
130		msync((void*)results, size, MS_SYNC);
131		munmap((void*)results, size);
132	}
133}
134
135void tst_reinit(void)
136{
137	const char *path = getenv(IPC_ENV_VAR);
138	size_t size = getpagesize();
139	int fd;
140	void *ptr;
141
142	if (!path)
143		tst_brk(TBROK, IPC_ENV_VAR" is not defined");
144
145	if (access(path, F_OK))
146		tst_brk(TBROK, "File %s does not exist!", path);
147
148	fd = SAFE_OPEN(path, O_RDWR);
149
150	ptr = SAFE_MMAP(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
151	tst_futexes = (char*)ptr + sizeof(struct results);
152	tst_max_futexes = (size - sizeof(struct results))/sizeof(futex_t);
153
154	SAFE_CLOSE(fd);
155}
156
157static void update_results(int ttype)
158{
159	if (!results)
160		return;
161
162	switch (ttype) {
163	case TCONF:
164		tst_atomic_inc(&results->skipped);
165	break;
166	case TPASS:
167		tst_atomic_inc(&results->passed);
168	break;
169	case TWARN:
170		tst_atomic_inc(&results->warnings);
171	break;
172	case TFAIL:
173		tst_atomic_inc(&results->failed);
174	break;
175	}
176}
177
178static void print_result(const char *file, const int lineno, int ttype,
179                         const char *fmt, va_list va)
180{
181	char buf[1024];
182	char *str = buf;
183	int ret, size = sizeof(buf), ssize;
184	const char *str_errno = NULL;
185	const char *res;
186
187	switch (TTYPE_RESULT(ttype)) {
188	case TPASS:
189		res = "PASS";
190	break;
191	case TFAIL:
192		res = "FAIL";
193	break;
194	case TBROK:
195		res = "BROK";
196	break;
197	case TCONF:
198		res = "CONF";
199	break;
200	case TWARN:
201		res = "WARN";
202	break;
203	case TINFO:
204		res = "INFO";
205	break;
206	default:
207		tst_brk(TBROK, "Invalid ttype value %i", ttype);
208		abort();
209	}
210
211	if (ttype & TERRNO)
212		str_errno = tst_strerrno(errno);
213
214	if (ttype & TTERRNO)
215		str_errno = tst_strerrno(TEST_ERRNO);
216
217	ret = snprintf(str, size, "%s:%i: ", file, lineno);
218	str += ret;
219	size -= ret;
220
221	if (tst_color_enabled(STDERR_FILENO))
222		ret = snprintf(str, size, "%s%s: %s", tst_ttype2color(ttype),
223			       res, ANSI_COLOR_RESET);
224	else
225		ret = snprintf(str, size, "%s: ", res);
226	str += ret;
227	size -= ret;
228
229	ssize = size - 2;
230	ret = vsnprintf(str, size, fmt, va);
231	str += MIN(ret, ssize);
232	size -= MIN(ret, ssize);
233	if (ret >= ssize) {
234		tst_res_(file, lineno, TWARN,
235				"Next message is too long and truncated:");
236	} else if (str_errno) {
237		ssize = size - 2;
238		ret = snprintf(str, size, ": %s", str_errno);
239		str += MIN(ret, ssize);
240		size -= MIN(ret, ssize);
241		if (ret >= ssize)
242			tst_res_(file, lineno, TWARN,
243				"Next message is too long and truncated:");
244	}
245
246	snprintf(str, size, "\n");
247
248	fputs(buf, stderr);
249}
250
251void tst_vres_(const char *file, const int lineno, int ttype,
252               const char *fmt, va_list va)
253{
254	print_result(file, lineno, ttype, fmt, va);
255
256	update_results(TTYPE_RESULT(ttype));
257}
258
259void tst_vbrk_(const char *file, const int lineno, int ttype,
260               const char *fmt, va_list va);
261
262static void (*tst_brk_handler)(const char *file, const int lineno, int ttype,
263			       const char *fmt, va_list va) = tst_vbrk_;
264
265static void tst_cvres(const char *file, const int lineno, int ttype,
266		      const char *fmt, va_list va)
267{
268	if (TTYPE_RESULT(ttype) == TBROK) {
269		ttype &= ~TTYPE_MASK;
270		ttype |= TWARN;
271	}
272
273	print_result(file, lineno, ttype, fmt, va);
274	update_results(TTYPE_RESULT(ttype));
275}
276
277static void do_test_cleanup(void)
278{
279	tst_brk_handler = tst_cvres;
280
281	if (tst_test->cleanup)
282		tst_test->cleanup();
283
284	tst_brk_handler = tst_vbrk_;
285}
286
287void tst_vbrk_(const char *file, const int lineno, int ttype,
288               const char *fmt, va_list va)
289{
290	print_result(file, lineno, ttype, fmt, va);
291
292	/*
293	 * The getpid implementation in some C library versions may cause cloned
294	 * test threads to show the same pid as their parent when CLONE_VM is
295	 * specified but CLONE_THREAD is not. Use direct syscall to avoid
296	 * cleanup running in the child.
297	 */
298	if (syscall(SYS_getpid) == main_pid)
299		do_test_cleanup();
300
301	if (getpid() == lib_pid)
302		do_exit(TTYPE_RESULT(ttype));
303
304	exit(TTYPE_RESULT(ttype));
305}
306
307void tst_res_(const char *file, const int lineno, int ttype,
308              const char *fmt, ...)
309{
310	va_list va;
311
312	va_start(va, fmt);
313	tst_vres_(file, lineno, ttype, fmt, va);
314	va_end(va);
315}
316
317void tst_brk_(const char *file, const int lineno, int ttype,
318              const char *fmt, ...)
319{
320	va_list va;
321
322	va_start(va, fmt);
323	tst_brk_handler(file, lineno, ttype, fmt, va);
324	va_end(va);
325}
326
327static void check_child_status(pid_t pid, int status)
328{
329	int ret;
330
331	if (WIFSIGNALED(status)) {
332		tst_brk(TBROK, "Child (%i) killed by signal %s",
333		        pid, tst_strsig(WTERMSIG(status)));
334	}
335
336	if (!(WIFEXITED(status)))
337		tst_brk(TBROK, "Child (%i) exited abnormaly", pid);
338
339	ret = WEXITSTATUS(status);
340	switch (ret) {
341	case TPASS:
342	break;
343	case TBROK:
344	case TCONF:
345		tst_brk(ret, "Reported by child (%i)", pid);
346	default:
347		tst_brk(TBROK, "Invalid child (%i) exit value %i", pid, ret);
348	}
349}
350
351void tst_reap_children(void)
352{
353	int status;
354	pid_t pid;
355
356	for (;;) {
357		pid = wait(&status);
358
359		if (pid > 0) {
360			check_child_status(pid, status);
361			continue;
362		}
363
364		if (errno == ECHILD)
365			break;
366
367		if (errno == EINTR)
368			continue;
369
370		tst_brk(TBROK | TERRNO, "wait() failed");
371	}
372}
373
374
375pid_t safe_fork(const char *filename, unsigned int lineno)
376{
377	pid_t pid;
378
379	if (!tst_test->forks_child)
380		tst_brk(TBROK, "test.forks_child must be set!");
381
382	fflush(stdout);
383
384	pid = fork();
385	if (pid < 0)
386		tst_brk_(filename, lineno, TBROK | TERRNO, "fork() failed");
387
388	return pid;
389}
390
391static struct option {
392	char *optstr;
393	char *help;
394} options[] = {
395	{"h",  "-h       Prints this help"},
396	{"i:", "-i n     Execute test n times"},
397	{"I:", "-I x     Execute test for n seconds"},
398	{"C:", "-C ARG   Run child process with ARG arguments (used internally)"},
399};
400
401static void print_help(void)
402{
403	unsigned int i;
404
405	for (i = 0; i < ARRAY_SIZE(options); i++)
406		fprintf(stderr, "%s\n", options[i].help);
407
408	if (!tst_test->options)
409		return;
410
411	for (i = 0; tst_test->options[i].optstr; i++)
412		fprintf(stderr, "%s\n", tst_test->options[i].help);
413}
414
415static void check_option_collision(void)
416{
417	unsigned int i, j;
418	struct tst_option *toptions = tst_test->options;
419
420	if (!toptions)
421		return;
422
423	for (i = 0; toptions[i].optstr; i++) {
424		for (j = 0; j < ARRAY_SIZE(options); j++) {
425			if (toptions[i].optstr[0] == options[j].optstr[0]) {
426				tst_brk(TBROK, "Option collision '%s'",
427				        options[j].help);
428			}
429		}
430	}
431}
432
433static unsigned int count_options(void)
434{
435	unsigned int i;
436
437	if (!tst_test->options)
438		return 0;
439
440	for (i = 0; tst_test->options[i].optstr; i++);
441
442	return i;
443}
444
445static void parse_topt(unsigned int topts_len, int opt, char *optarg)
446{
447	unsigned int i;
448	struct tst_option *toptions = tst_test->options;
449
450	for (i = 0; i < topts_len; i++) {
451		if (toptions[i].optstr[0] == opt)
452			break;
453	}
454
455	if (i >= topts_len)
456		tst_brk(TBROK, "Invalid option '%c' (should not happen)", opt);
457
458	*(toptions[i].arg) = optarg ? optarg : "";
459}
460
461/* see self_exec.c */
462#ifdef UCLINUX
463extern char *child_args;
464#endif
465
466static void parse_opts(int argc, char *argv[])
467{
468	unsigned int i, topts_len = count_options();
469	char optstr[2 * ARRAY_SIZE(options) + 2 * topts_len];
470	int opt;
471
472	check_option_collision();
473
474	optstr[0] = 0;
475
476	for (i = 0; i < ARRAY_SIZE(options); i++)
477		strcat(optstr, options[i].optstr);
478
479	for (i = 0; i < topts_len; i++)
480		strcat(optstr, tst_test->options[i].optstr);
481
482	while ((opt = getopt(argc, argv, optstr)) > 0) {
483		switch (opt) {
484		case '?':
485			print_help();
486			tst_brk(TBROK, "Invalid option");
487		case 'h':
488			print_help();
489			exit(0);
490		case 'i':
491			iterations = atoi(optarg);
492		break;
493		case 'I':
494			duration = atof(optarg);
495		break;
496		case 'C':
497#ifdef UCLINUX
498			child_args = optarg;
499#endif
500		break;
501		default:
502			parse_topt(topts_len, opt, optarg);
503		}
504	}
505
506	if (optind < argc)
507		tst_brk(TBROK, "Unexpected argument(s) '%s'...", argv[optind]);
508}
509
510int tst_parse_int(const char *str, int *val, int min, int max)
511{
512	long rval;
513
514	if (!str)
515		return 0;
516
517	int ret = tst_parse_long(str, &rval, min, max);
518
519	if (ret)
520		return ret;
521
522	*val = (int)rval;
523	return 0;
524}
525
526int tst_parse_long(const char *str, long *val, long min, long max)
527{
528	long rval;
529	char *end;
530
531	if (!str)
532		return 0;
533
534	errno = 0;
535	rval = strtol(str, &end, 10);
536
537	if (str == end || *end != '\0')
538		return EINVAL;
539
540	if (errno)
541		return errno;
542
543	if (rval > max || rval < min)
544		return ERANGE;
545
546	*val = rval;
547	return 0;
548}
549
550int tst_parse_float(const char *str, float *val, float min, float max)
551{
552	double rval;
553	char *end;
554
555	if (!str)
556		return 0;
557
558	errno = 0;
559	rval = strtod(str, &end);
560
561	if (str == end || *end != '\0')
562		return EINVAL;
563
564	if (errno)
565		return errno;
566
567	if (rval > (double)max || rval < (double)min)
568		return ERANGE;
569
570	*val = (float)rval;
571	return 0;
572}
573
574static void do_exit(int ret)
575{
576	if (results) {
577		printf("\nSummary:\n");
578		printf("passed   %d\n", results->passed);
579		printf("failed   %d\n", results->failed);
580		printf("skipped  %d\n", results->skipped);
581		printf("warnings %d\n", results->warnings);
582
583		if (results->passed && ret == TCONF)
584			ret = 0;
585
586		if (results->failed)
587			ret |= TFAIL;
588
589		if (results->skipped && !results->passed)
590			ret |= TCONF;
591
592		if (results->warnings)
593			ret |= TWARN;
594	}
595
596	do_cleanup();
597
598	exit(ret);
599}
600
601void check_kver(void)
602{
603	int v1, v2, v3;
604
605	if (tst_parse_kver(tst_test->min_kver, &v1, &v2, &v3)) {
606		tst_res(TWARN,
607		        "Invalid kernel version %s, expected %%d.%%d.%%d",
608		        tst_test->min_kver);
609	}
610
611	if (tst_kvercmp(v1, v2, v3) < 0) {
612		tst_brk(TCONF, "The test requires kernel %s or newer",
613		        tst_test->min_kver);
614	}
615}
616
617static int results_equal(struct results *a, struct results *b)
618{
619	if (a->passed != b->passed)
620		return 0;
621
622	if (a->failed != b->failed)
623		return 0;
624
625	if (a->skipped != b->skipped)
626		return 0;
627
628	return 1;
629}
630
631static int needs_tmpdir(void)
632{
633	return tst_test->needs_tmpdir ||
634	       tst_test->needs_device ||
635	       tst_test->resource_files ||
636	       tst_test->needs_checkpoints;
637}
638
639static void copy_resources(void)
640{
641	unsigned int i;
642
643	for (i = 0; tst_test->resource_files[i]; i++)
644		TST_RESOURCE_COPY(NULL, tst_test->resource_files[i], NULL);
645}
646
647static const char *get_tid(char *argv[])
648{
649	char *p;
650
651	if (!argv[0] || !argv[0][0]) {
652		tst_res(TINFO, "argv[0] is empty!");
653		return "ltp_empty_argv";
654	}
655
656	p = strrchr(argv[0], '/');
657	if (p)
658		return p+1;
659
660	return argv[0];
661}
662
663static struct tst_device tdev;
664struct tst_device *tst_device;
665
666static void assert_test_fn(void)
667{
668	int cnt = 0;
669
670	if (tst_test->test)
671		cnt++;
672
673	if (tst_test->test_all)
674		cnt++;
675
676	if (tst_test->sample)
677		cnt++;
678
679	if (!cnt)
680		tst_brk(TBROK, "No test function speficied");
681
682	if (cnt != 1)
683		tst_brk(TBROK, "You can define only one test function");
684
685	if (tst_test->test && !tst_test->tcnt)
686		tst_brk(TBROK, "Number of tests (tcnt) must not be > 0");
687
688	if (!tst_test->test && tst_test->tcnt)
689		tst_brk(TBROK, "You can define tcnt only for test()");
690}
691
692static void prepare_device(void)
693{
694	if (tst_test->format_device) {
695		SAFE_MKFS(tdev.dev, tdev.fs_type, tst_test->dev_fs_opts,
696			  tst_test->dev_extra_opt);
697	}
698
699	if (tst_test->mount_device) {
700		SAFE_MOUNT(tdev.dev, tst_test->mntpoint, tdev.fs_type,
701			   tst_test->mnt_flags, tst_test->mnt_data);
702		mntpoint_mounted = 1;
703	}
704}
705
706static void do_setup(int argc, char *argv[])
707{
708	if (!tst_test)
709		tst_brk(TBROK, "No tests to run");
710
711	if (tst_test->tconf_msg)
712		tst_brk(TCONF, "%s", tst_test->tconf_msg);
713
714	assert_test_fn();
715
716	tid = get_tid(argv);
717
718	if (tst_test->sample)
719		tst_test = tst_timer_test_setup(tst_test);
720
721	parse_opts(argc, argv);
722
723	if (tst_test->needs_root && geteuid() != 0)
724		tst_brk(TCONF, "Test needs to be run as root");
725
726	if (tst_test->min_kver)
727		check_kver();
728
729	if (tst_test->format_device)
730		tst_test->needs_device = 1;
731
732	if (tst_test->mount_device) {
733		tst_test->needs_device = 1;
734		tst_test->format_device = 1;
735	}
736
737	if (tst_test->all_filesystems)
738		tst_test->needs_device = 1;
739
740	setup_ipc();
741
742	if (needs_tmpdir() && !tst_tmpdir_created())
743		tst_tmpdir();
744
745	if (tst_test->mntpoint)
746		SAFE_MKDIR(tst_test->mntpoint, 0777);
747
748	if ((tst_test->needs_rofs || tst_test->mount_device ||
749	     tst_test->all_filesystems) && !tst_test->mntpoint) {
750		tst_brk(TBROK, "tst_test->mntpoint must be set!");
751	}
752
753	if (tst_test->needs_rofs) {
754		/* If we failed to mount read-only tmpfs. Fallback to
755		 * using a device with empty read-only filesystem.
756		 */
757		if (mount(NULL, tst_test->mntpoint, "tmpfs", MS_RDONLY, NULL)) {
758			tst_res(TINFO | TERRNO, "Can't mount tmpfs read-only"
759				" at %s, setting up a device instead\n",
760				tst_test->mntpoint);
761			tst_test->mount_device = 1;
762			tst_test->needs_device = 1;
763			tst_test->format_device = 1;
764			tst_test->mnt_flags = MS_RDONLY;
765		} else {
766			mntpoint_mounted = 1;
767		}
768	}
769
770	if (tst_test->needs_device && !mntpoint_mounted) {
771		tdev.dev = tst_acquire_device_(NULL, tst_test->dev_min_size);
772
773		if (!tdev.dev)
774			tst_brk(TCONF, "Failed to acquire device");
775
776		tst_device = &tdev;
777
778		if (tst_test->dev_fs_type)
779			tdev.fs_type = tst_test->dev_fs_type;
780		else
781			tdev.fs_type = tst_dev_fs_type();
782
783		if (!tst_test->all_filesystems)
784			prepare_device();
785	}
786
787	if (tst_test->resource_files)
788		copy_resources();
789}
790
791static void do_test_setup(void)
792{
793	main_pid = getpid();
794
795	if (tst_test->setup)
796		tst_test->setup();
797
798	if (main_pid != getpid())
799		tst_brk(TBROK, "Runaway child in setup()!");
800}
801
802static void do_cleanup(void)
803{
804	if (mntpoint_mounted)
805		tst_umount(tst_test->mntpoint);
806
807	if (tst_test->needs_device && tdev.dev)
808		tst_release_device(tdev.dev);
809
810	if (tst_tmpdir_created()) {
811		/* avoid munmap() on wrong pointer in tst_rmdir() */
812		tst_futexes = NULL;
813		tst_rmdir();
814	}
815
816	cleanup_ipc();
817}
818
819static void run_tests(void)
820{
821	unsigned int i;
822	struct results saved_results;
823
824	if (!tst_test->test) {
825		saved_results = *results;
826		tst_test->test_all();
827
828		if (getpid() != main_pid) {
829			exit(0);
830		}
831
832		tst_reap_children();
833
834		if (results_equal(&saved_results, results))
835			tst_brk(TBROK, "Test haven't reported results!");
836		return;
837	}
838
839	for (i = 0; i < tst_test->tcnt; i++) {
840		saved_results = *results;
841		tst_test->test(i);
842
843		if (getpid() != main_pid) {
844			exit(0);
845		}
846
847		tst_reap_children();
848
849		if (results_equal(&saved_results, results))
850			tst_brk(TBROK, "Test %i haven't reported results!", i);
851	}
852}
853
854static unsigned long long get_time_ms(void)
855{
856	struct timeval tv;
857
858	gettimeofday(&tv, NULL);
859
860	return tv.tv_sec * 1000 + tv.tv_usec / 1000;
861}
862
863static void add_paths(void)
864{
865	char *old_path = getenv("PATH");
866	const char *start_dir;
867	char *new_path;
868
869	start_dir = tst_get_startwd();
870
871	if (old_path)
872		SAFE_ASPRINTF(&new_path, "%s::%s", old_path, start_dir);
873	else
874		SAFE_ASPRINTF(&new_path, "::%s", start_dir);
875
876	SAFE_SETENV("PATH", new_path, 1);
877	free(new_path);
878}
879
880static void heartbeat(void)
881{
882	kill(getppid(), SIGUSR1);
883}
884
885static void testrun(void)
886{
887	unsigned int i = 0;
888	unsigned long long stop_time = 0;
889	int cont = 1;
890
891	add_paths();
892	do_test_setup();
893
894	if (duration > 0)
895		stop_time = get_time_ms() + (unsigned long long)(duration * 1000);
896
897	for (;;) {
898		cont = 0;
899
900		if (i < (unsigned int)iterations) {
901			i++;
902			cont = 1;
903		}
904
905		if (stop_time && get_time_ms() < stop_time)
906			cont = 1;
907
908		if (!cont)
909			break;
910
911		run_tests();
912		heartbeat();
913	}
914
915	do_test_cleanup();
916	exit(0);
917}
918
919static pid_t test_pid;
920
921
922static volatile sig_atomic_t sigkill_retries;
923
924#define WRITE_MSG(msg) do { \
925	if (write(2, msg, sizeof(msg) - 1)) { \
926		/* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66425 */ \
927	} \
928} while (0)
929
930static void alarm_handler(int sig LTP_ATTRIBUTE_UNUSED)
931{
932	WRITE_MSG("Test timeouted, sending SIGKILL!\n");
933	kill(-test_pid, SIGKILL);
934	alarm(5);
935
936	if (++sigkill_retries > 10) {
937		WRITE_MSG("Cannot kill test processes!\n");
938		WRITE_MSG("Congratulation, likely test hit a kernel bug.\n");
939		WRITE_MSG("Exitting uncleanly...\n");
940		_exit(TFAIL);
941	}
942}
943
944static void heartbeat_handler(int sig LTP_ATTRIBUTE_UNUSED)
945{
946	alarm(results->timeout);
947	sigkill_retries = 0;
948}
949
950static void sigint_handler(int sig LTP_ATTRIBUTE_UNUSED)
951{
952	if (test_pid > 0) {
953		WRITE_MSG("Sending SIGKILL to test process...\n");
954		kill(-test_pid, SIGKILL);
955	}
956}
957
958void tst_set_timeout(int timeout)
959{
960	char *mul = getenv("LTP_TIMEOUT_MUL");
961
962	if (timeout == -1) {
963		tst_res(TINFO, "Timeout per run is disabled");
964		return;
965	}
966
967	results->timeout = timeout;
968
969	if (mul) {
970		float m = atof(mul);
971
972		if (m < 1)
973			tst_brk(TBROK, "Invalid timeout multiplier '%s'", mul);
974
975		results->timeout = results->timeout * m + 0.5;
976	}
977
978	tst_res(TINFO, "Timeout per run is %uh %02um %02us",
979		results->timeout/3600, (results->timeout%3600)/60,
980		results->timeout % 60);
981
982	if (getpid() == lib_pid)
983		alarm(results->timeout);
984	else
985		heartbeat();
986}
987
988static int fork_testrun(void)
989{
990	int status;
991
992	if (tst_test->timeout)
993		tst_set_timeout(tst_test->timeout);
994	else
995		tst_set_timeout(300);
996
997	SAFE_SIGNAL(SIGINT, sigint_handler);
998
999	test_pid = fork();
1000	if (test_pid < 0)
1001		tst_brk(TBROK | TERRNO, "fork()");
1002
1003	if (!test_pid) {
1004		SAFE_SIGNAL(SIGALRM, SIG_DFL);
1005		SAFE_SIGNAL(SIGUSR1, SIG_DFL);
1006		SAFE_SIGNAL(SIGINT, SIG_DFL);
1007		SAFE_SETPGID(0, 0);
1008		testrun();
1009	}
1010
1011	SAFE_WAITPID(test_pid, &status, 0);
1012	alarm(0);
1013	SAFE_SIGNAL(SIGINT, SIG_DFL);
1014
1015	if (WIFEXITED(status) && WEXITSTATUS(status))
1016		return WEXITSTATUS(status);
1017
1018	if (WIFSIGNALED(status) && WTERMSIG(status) == SIGKILL) {
1019		tst_res(TINFO, "If you are running on slow machine, "
1020			       "try exporting LTP_TIMEOUT_MUL > 1");
1021		tst_brk(TBROK, "Test killed! (timeout?)");
1022	}
1023
1024	if (WIFSIGNALED(status))
1025		tst_brk(TBROK, "Test killed by %s!", tst_strsig(WTERMSIG(status)));
1026
1027	return 0;
1028}
1029
1030static int run_tcases_per_fs(void)
1031{
1032	int ret = 0;
1033	unsigned int i;
1034	const char *const *filesystems = tst_get_supported_fs_types();
1035
1036	if (!filesystems[0])
1037		tst_brk(TCONF, "There are no supported filesystems");
1038
1039	for (i = 0; filesystems[i]; i++) {
1040		tdev.fs_type = filesystems[i];
1041
1042		prepare_device();
1043
1044		ret = fork_testrun();
1045
1046		if (mntpoint_mounted) {
1047			tst_umount(tst_test->mntpoint);
1048			mntpoint_mounted = 0;
1049		}
1050
1051		if (ret == TCONF) {
1052			update_results(ret);
1053			continue;
1054		}
1055
1056		if (ret == 0)
1057			continue;
1058
1059		do_exit(ret);
1060	}
1061
1062	return ret;
1063}
1064
1065void tst_run_tcases(int argc, char *argv[], struct tst_test *self)
1066{
1067	int ret;
1068
1069	lib_pid = getpid();
1070	tst_test = self;
1071
1072	do_setup(argc, argv);
1073
1074	TCID = tid;
1075
1076	SAFE_SIGNAL(SIGALRM, alarm_handler);
1077	SAFE_SIGNAL(SIGUSR1, heartbeat_handler);
1078
1079	if (tst_test->all_filesystems)
1080		ret = run_tcases_per_fs();
1081	else
1082		ret = fork_testrun();
1083
1084	do_exit(ret);
1085}
1086