• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
42 struct tst_test *tst_test;
43 
44 static const char *tid;
45 static int iterations = 1;
46 static float duration = -1;
47 static pid_t main_pid, lib_pid;
48 static int mntpoint_mounted;
49 
50 struct results {
51 	int passed;
52 	int skipped;
53 	int failed;
54 	int warnings;
55 	unsigned int timeout;
56 };
57 
58 static struct results *results;
59 
60 static int ipc_fd;
61 
62 extern void *tst_futexes;
63 extern unsigned int tst_max_futexes;
64 
65 #define IPC_ENV_VAR "LTP_IPC_PATH"
66 
67 static char ipc_path[1024];
68 const char *tst_ipc_path = ipc_path;
69 
70 static char shm_path[1024];
71 
72 static void do_cleanup(void);
73 static void do_exit(int ret) __attribute__ ((noreturn));
74 
setup_ipc(void)75 static 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 
cleanup_ipc(void)119 static 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 
tst_reinit(void)135 void 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 
update_results(int ttype)157 static 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 
print_result(const char * file,const int lineno,int ttype,const char * fmt,va_list va)178 static 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 
tst_vres_(const char * file,const int lineno,int ttype,const char * fmt,va_list va)251 void 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 
259 void tst_vbrk_(const char *file, const int lineno, int ttype,
260                const char *fmt, va_list va);
261 
262 static void (*tst_brk_handler)(const char *file, const int lineno, int ttype,
263 			       const char *fmt, va_list va) = tst_vbrk_;
264 
tst_cvres(const char * file,const int lineno,int ttype,const char * fmt,va_list va)265 static 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 
do_test_cleanup(void)277 static 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 
tst_vbrk_(const char * file,const int lineno,int ttype,const char * fmt,va_list va)287 void 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 
tst_res_(const char * file,const int lineno,int ttype,const char * fmt,...)307 void 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 
tst_brk_(const char * file,const int lineno,int ttype,const char * fmt,...)317 void 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 
check_child_status(pid_t pid,int status)327 static 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 
tst_reap_children(void)351 void 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 
safe_fork(const char * filename,unsigned int lineno)375 pid_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 
391 static 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 
print_help(void)401 static 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 
check_option_collision(void)415 static 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 
count_options(void)433 static 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 
parse_topt(unsigned int topts_len,int opt,char * optarg)445 static 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
463 extern char *child_args;
464 #endif
465 
parse_opts(int argc,char * argv[])466 static 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 
tst_parse_int(const char * str,int * val,int min,int max)510 int 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 
tst_parse_long(const char * str,long * val,long min,long max)526 int 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 
tst_parse_float(const char * str,float * val,float min,float max)550 int 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 
do_exit(int ret)574 static 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 
check_kver(void)601 void 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 
results_equal(struct results * a,struct results * b)617 static 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 
needs_tmpdir(void)631 static 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 
copy_resources(void)639 static 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 
get_tid(char * argv[])647 static 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 
663 static struct tst_device tdev;
664 struct tst_device *tst_device;
665 
assert_test_fn(void)666 static 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 
prepare_device(void)692 static 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 
do_setup(int argc,char * argv[])706 static 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 
do_test_setup(void)791 static 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 
do_cleanup(void)802 static 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 
run_tests(void)819 static 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 
get_time_ms(void)854 static 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 
add_paths(void)863 static 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 
heartbeat(void)880 static void heartbeat(void)
881 {
882 	kill(getppid(), SIGUSR1);
883 }
884 
testrun(void)885 static 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 
919 static pid_t test_pid;
920 
921 
922 static 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 
alarm_handler(int sig LTP_ATTRIBUTE_UNUSED)930 static 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 
heartbeat_handler(int sig LTP_ATTRIBUTE_UNUSED)944 static void heartbeat_handler(int sig LTP_ATTRIBUTE_UNUSED)
945 {
946 	alarm(results->timeout);
947 	sigkill_retries = 0;
948 }
949 
sigint_handler(int sig LTP_ATTRIBUTE_UNUSED)950 static 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 
tst_set_timeout(int timeout)958 void 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 
fork_testrun(void)988 static 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 
run_tcases_per_fs(void)1030 static 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 
tst_run_tcases(int argc,char * argv[],struct tst_test * self)1065 void 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