• 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/types.h>
25 #include <sys/wait.h>
26 #include <sys/time.h>
27 
28 #define TST_NO_DEFAULT_MAIN
29 #include "tst_test.h"
30 #include "tst_device.h"
31 #include "lapi/futex.h"
32 #include "tst_ansi_color.h"
33 
34 #include "old_resource.h"
35 #include "old_device.h"
36 #include "old_tmpdir.h"
37 
38 struct tst_test *tst_test;
39 
40 static int iterations = 1;
41 static float duration = -1;
42 static pid_t main_pid, lib_pid;
43 static int device_mounted;
44 
45 struct results {
46 	int passed;
47 	int skipped;
48 	int failed;
49 	int warnings;
50 	unsigned int timeout;
51 };
52 
53 static struct results *results;
54 
55 static int ipc_fd;
56 
57 extern void *tst_futexes;
58 extern unsigned int tst_max_futexes;
59 
60 #define IPC_ENV_VAR "LTP_IPC_PATH"
61 
62 static char ipc_path[1024];
63 const char *tst_ipc_path = ipc_path;
64 char *const tst_ipc_envp[] = {ipc_path, NULL};
65 
66 static char shm_path[1024];
67 
68 static void do_cleanup(void);
69 static void do_exit(int ret) __attribute__ ((noreturn));
70 
setup_ipc(void)71 static void setup_ipc(void)
72 {
73 	size_t size = getpagesize();
74 
75 	if (access("/dev/shm", F_OK) == 0) {
76 		snprintf(shm_path, sizeof(shm_path), "/dev/shm/ltp_%s_%d",
77 		         tst_test->tid, getpid());
78 	} else {
79 		char *tmpdir;
80 
81 		if (!tst_tmpdir_created())
82 			tst_tmpdir();
83 
84 		tmpdir = tst_get_tmpdir();
85 		snprintf(shm_path, sizeof(shm_path), "%s/ltp_%s_%d",
86 		         tmpdir, tst_test->tid, getpid());
87 		free(tmpdir);
88 	}
89 
90 	ipc_fd = open(shm_path, O_CREAT | O_EXCL | O_RDWR, 0600);
91 	if (ipc_fd < 0)
92 		tst_brk(TBROK | TERRNO, "open(%s)", shm_path);
93 
94 	SAFE_FTRUNCATE(ipc_fd, size);
95 
96 	results = SAFE_MMAP(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, ipc_fd, 0);
97 
98 	/* Checkpoints needs to be accessible from processes started by exec() */
99 	if (tst_test->needs_checkpoints)
100 		sprintf(ipc_path, IPC_ENV_VAR "=%s", shm_path);
101 	else
102 		SAFE_UNLINK(shm_path);
103 
104 	SAFE_CLOSE(ipc_fd);
105 
106 	if (tst_test->needs_checkpoints) {
107 		tst_futexes = (char*)results + sizeof(struct results);
108 		tst_max_futexes = (size - sizeof(struct results))/sizeof(futex_t);
109 	}
110 }
111 
cleanup_ipc(void)112 static void cleanup_ipc(void)
113 {
114 	size_t size = getpagesize();
115 
116 	if (ipc_fd > 0 && close(ipc_fd))
117 		tst_res(TWARN | TERRNO, "close(ipc_fd) failed");
118 
119 	if (!access(shm_path, F_OK) && unlink(shm_path))
120 		tst_res(TWARN | TERRNO, "unlink(%s) failed", shm_path);
121 
122 	msync((void*)results, size, MS_SYNC);
123 	munmap((void*)results, size);
124 }
125 
tst_reinit(void)126 void tst_reinit(void)
127 {
128 	const char *path = getenv("LTP_IPC_PATH");
129 	size_t size = getpagesize();
130 	int fd;
131 	void *ptr;
132 
133 	if (!path)
134 		tst_brk(TBROK, "LTP_IPC_PATH is not defined");
135 
136 	if (access(path, F_OK))
137 		tst_brk(TBROK, "File %s does not exist!", path);
138 
139 	fd = SAFE_OPEN(path, O_RDWR);
140 
141 	ptr = SAFE_MMAP(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
142 	tst_futexes = (char*)ptr + sizeof(struct results);
143 	tst_max_futexes = (size - sizeof(struct results))/sizeof(futex_t);
144 
145 	SAFE_CLOSE(fd);
146 }
147 
update_results(int ttype)148 static void update_results(int ttype)
149 {
150 	if (!results)
151 		return;
152 
153 	switch (ttype) {
154 	case TCONF:
155 		tst_atomic_inc(&results->skipped);
156 	break;
157 	case TPASS:
158 		tst_atomic_inc(&results->passed);
159 	break;
160 	case TWARN:
161 		tst_atomic_inc(&results->warnings);
162 	break;
163 	case TFAIL:
164 		tst_atomic_inc(&results->failed);
165 	break;
166 	}
167 }
168 
print_result(const char * file,const int lineno,int ttype,const char * fmt,va_list va)169 static void print_result(const char *file, const int lineno, int ttype,
170                          const char *fmt, va_list va)
171 {
172 	char buf[1024];
173 	char *str = buf;
174 	int ret, size = sizeof(buf);
175 	const char *str_errno = NULL;
176 	const char *res;
177 
178 	switch (TTYPE_RESULT(ttype)) {
179 	case TPASS:
180 		res = "PASS";
181 	break;
182 	case TFAIL:
183 		res = "FAIL";
184 	break;
185 	case TBROK:
186 		res = "BROK";
187 	break;
188 	case TCONF:
189 		res = "CONF";
190 	break;
191 	case TWARN:
192 		res = "WARN";
193 	break;
194 	case TINFO:
195 		res = "INFO";
196 	break;
197 	default:
198 		tst_brk(TBROK, "Invalid ttype value %i", ttype);
199 		abort();
200 	}
201 
202 	if (ttype & TERRNO)
203 		str_errno = tst_strerrno(errno);
204 
205 	if (ttype & TTERRNO)
206 		str_errno = tst_strerrno(TEST_ERRNO);
207 
208 	ret = snprintf(str, size, "%s:%i: ", file, lineno);
209 	str += ret;
210 	size -= ret;
211 
212 	if (tst_color_enabled(STDERR_FILENO))
213 		ret = snprintf(str, size, "%s%s: %s", tst_ttype2color(ttype),
214 			       res, ANSI_COLOR_RESET);
215 	else
216 		ret = snprintf(str, size, "%s: ", res);
217 	str += ret;
218 	size -= ret;
219 
220 	ret = vsnprintf(str, size, fmt, va);
221 	str += ret;
222 	size -= ret;
223 
224 	if (str_errno) {
225 		ret = snprintf(str, size, ": %s", str_errno);
226 		str += ret;
227 		size -= ret;
228 	}
229 
230 	snprintf(str, size, "\n");
231 
232 	fputs(buf, stderr);
233 }
234 
tst_vres_(const char * file,const int lineno,int ttype,const char * fmt,va_list va)235 void tst_vres_(const char *file, const int lineno, int ttype,
236                const char *fmt, va_list va)
237 {
238 	print_result(file, lineno, ttype, fmt, va);
239 
240 	update_results(TTYPE_RESULT(ttype));
241 }
242 
243 void tst_vbrk_(const char *file, const int lineno, int ttype,
244                const char *fmt, va_list va);
245 
246 static void (*tst_brk_handler)(const char *file, const int lineno, int ttype,
247 			       const char *fmt, va_list va) = tst_vbrk_;
248 
tst_cvres(const char * file,const int lineno,int ttype,const char * fmt,va_list va)249 static void tst_cvres(const char *file, const int lineno, int ttype,
250 		      const char *fmt, va_list va)
251 {
252 	if (TTYPE_RESULT(ttype) == TBROK) {
253 		ttype &= ~TTYPE_MASK;
254 		ttype |= TWARN;
255 	}
256 
257 	print_result(file, lineno, ttype, fmt, va);
258 	update_results(TTYPE_RESULT(ttype));
259 }
260 
do_test_cleanup(void)261 static void do_test_cleanup(void)
262 {
263 	tst_brk_handler = tst_cvres;
264 
265 	if (tst_test->cleanup)
266 		tst_test->cleanup();
267 
268 	tst_brk_handler = tst_vbrk_;
269 }
270 
tst_vbrk_(const char * file,const int lineno,int ttype,const char * fmt,va_list va)271 void tst_vbrk_(const char *file, const int lineno, int ttype,
272                const char *fmt, va_list va)
273 {
274 	print_result(file, lineno, ttype, fmt, va);
275 
276 	if (getpid() == main_pid)
277 		do_test_cleanup();
278 
279 	if (getpid() == lib_pid)
280 		do_exit(TTYPE_RESULT(ttype));
281 
282 	exit(TTYPE_RESULT(ttype));
283 }
284 
tst_res_(const char * file,const int lineno,int ttype,const char * fmt,...)285 void tst_res_(const char *file, const int lineno, int ttype,
286               const char *fmt, ...)
287 {
288 	va_list va;
289 
290 	va_start(va, fmt);
291 	tst_vres_(file, lineno, ttype, fmt, va);
292 	va_end(va);
293 }
294 
tst_brk_(const char * file,const int lineno,int ttype,const char * fmt,...)295 void tst_brk_(const char *file, const int lineno, int ttype,
296               const char *fmt, ...)
297 {
298 	va_list va;
299 
300 	va_start(va, fmt);
301 	tst_brk_handler(file, lineno, ttype, fmt, va);
302 	va_end(va);
303 }
304 
check_child_status(pid_t pid,int status)305 static void check_child_status(pid_t pid, int status)
306 {
307 	int ret;
308 
309 	if (WIFSIGNALED(status)) {
310 		tst_brk(TBROK, "Child (%i) killed by signal %s",
311 		        pid, tst_strsig(WTERMSIG(status)));
312 	}
313 
314 	if (!(WIFEXITED(status)))
315 		tst_brk(TBROK, "Child (%i) exitted abnormaly", pid);
316 
317 	ret = WEXITSTATUS(status);
318 	switch (ret) {
319 	case TPASS:
320 	break;
321 	case TBROK:
322 	case TCONF:
323 		tst_brk(ret, "Reported by child (%i)", pid);
324 	default:
325 		tst_brk(TBROK, "Invalid child (%i) exit value %i", pid, ret);
326 	}
327 }
328 
tst_reap_children(void)329 void tst_reap_children(void)
330 {
331 	int status;
332 	pid_t pid;
333 
334 	for (;;) {
335 		pid = wait(&status);
336 
337 		if (pid > 0) {
338 			check_child_status(pid, status);
339 			continue;
340 		}
341 
342 		if (errno == ECHILD)
343 			break;
344 
345 		if (errno == EINTR)
346 			continue;
347 
348 		tst_brk(TBROK | TERRNO, "wait() failed");
349 	}
350 }
351 
352 
safe_fork(const char * filename,unsigned int lineno)353 pid_t safe_fork(const char *filename, unsigned int lineno)
354 {
355 	pid_t pid;
356 
357 	if (!tst_test->forks_child)
358 		tst_brk(TBROK, "test.forks_child must be set!");
359 
360 	fflush(stdout);
361 
362 	pid = fork();
363 	if (pid < 0)
364 		tst_brk_(filename, lineno, TBROK | TERRNO, "fork() failed");
365 
366 	return pid;
367 }
368 
369 static struct option {
370 	char *optstr;
371 	char *help;
372 } options[] = {
373 	{"h",  "-h       Prints this help"},
374 	{"i:", "-i n     Execute test n times"},
375 	{"I:", "-I x     Execute test for n seconds"},
376 	{"C:", "-C ARG   Run child process with ARG arguments (used internally)"},
377 };
378 
print_help(void)379 static void print_help(void)
380 {
381 	unsigned int i;
382 
383 	for (i = 0; i < ARRAY_SIZE(options); i++)
384 		fprintf(stderr, "%s\n", options[i].help);
385 
386 	if (!tst_test->options)
387 		return;
388 
389 	for (i = 0; tst_test->options[i].optstr; i++)
390 		fprintf(stderr, "%s\n", tst_test->options[i].help);
391 }
392 
check_option_collision(void)393 static void check_option_collision(void)
394 {
395 	unsigned int i, j;
396 	struct tst_option *toptions = tst_test->options;
397 
398 	if (!toptions)
399 		return;
400 
401 	for (i = 0; toptions[i].optstr; i++) {
402 		for (j = 0; j < ARRAY_SIZE(options); j++) {
403 			if (toptions[i].optstr[0] == options[j].optstr[0]) {
404 				tst_brk(TBROK, "Option collision '%s'",
405 				        options[j].help);
406 			}
407 		}
408 	}
409 }
410 
count_options(void)411 static unsigned int count_options(void)
412 {
413 	unsigned int i;
414 
415 	if (!tst_test->options)
416 		return 0;
417 
418 	for (i = 0; tst_test->options[i].optstr; i++);
419 
420 	return i;
421 }
422 
parse_topt(unsigned int topts_len,int opt,char * optarg)423 static void parse_topt(unsigned int topts_len, int opt, char *optarg)
424 {
425 	unsigned int i;
426 	struct tst_option *toptions = tst_test->options;
427 
428 	for (i = 0; i < topts_len; i++) {
429 		if (toptions[i].optstr[0] == opt)
430 			break;
431 	}
432 
433 	if (i >= topts_len)
434 		tst_brk(TBROK, "Invalid option '%c' (should not happen)", opt);
435 
436 	*(toptions[i].arg) = optarg ? optarg : "";
437 }
438 
439 /* see self_exec.c */
440 #ifdef UCLINUX
441 extern char *child_args;
442 #endif
443 
parse_opts(int argc,char * argv[])444 static void parse_opts(int argc, char *argv[])
445 {
446 	unsigned int i, topts_len = count_options();
447 	char optstr[2 * ARRAY_SIZE(options) + 2 * topts_len];
448 	int opt;
449 
450 	check_option_collision();
451 
452 	optstr[0] = 0;
453 
454 	for (i = 0; i < ARRAY_SIZE(options); i++)
455 		strcat(optstr, options[i].optstr);
456 
457 	for (i = 0; i < topts_len; i++)
458 		strcat(optstr, tst_test->options[i].optstr);
459 
460 	while ((opt = getopt(argc, argv, optstr)) > 0) {
461 		switch (opt) {
462 		case '?':
463 			print_help();
464 			tst_brk(TBROK, "Invalid option");
465 		case 'h':
466 			print_help();
467 			exit(0);
468 		case 'i':
469 			iterations = atoi(optarg);
470 		break;
471 		case 'I':
472 			duration = atof(optarg);
473 		break;
474 		case 'C':
475 #ifdef UCLINUX
476 			child_args = optarg;
477 #endif
478 		break;
479 		default:
480 			parse_topt(topts_len, opt, optarg);
481 		}
482 	}
483 }
484 
tst_parse_int(const char * str,int * val,int min,int max)485 int tst_parse_int(const char *str, int *val, int min, int max)
486 {
487 	long rval;
488 
489 	if (!str)
490 		return 0;
491 
492 	int ret = tst_parse_long(str, &rval, min, max);
493 
494 	if (ret)
495 		return ret;
496 
497 	*val = (int)rval;
498 	return 0;
499 }
500 
tst_parse_long(const char * str,long * val,long min,long max)501 int tst_parse_long(const char *str, long *val, long min, long max)
502 {
503 	long rval;
504 	char *end;
505 
506 	if (!str)
507 		return 0;
508 
509 	errno = 0;
510 	rval = strtol(str, &end, 10);
511 
512 	if (str == end || *end != '\0')
513 		return EINVAL;
514 
515 	if (errno)
516 		return errno;
517 
518 	if (rval > max || rval < min)
519 		return ERANGE;
520 
521 	*val = rval;
522 	return 0;
523 }
524 
tst_parse_float(const char * str,float * val,float min,float max)525 int tst_parse_float(const char *str, float *val, float min, float max)
526 {
527 	double rval;
528 	char *end;
529 
530 	if (!str)
531 		return 0;
532 
533 	errno = 0;
534 	rval = strtod(str, &end);
535 
536 	if (str == end || *end != '\0')
537 		return EINVAL;
538 
539 	if (errno)
540 		return errno;
541 
542 	if (rval > (double)max || rval < (double)min)
543 		return ERANGE;
544 
545 	*val = (float)rval;
546 	return 0;
547 }
548 
do_exit(int ret)549 static void do_exit(int ret)
550 {
551 	if (results) {
552 		printf("\nSummary:\n");
553 		printf("passed   %d\n", results->passed);
554 		printf("failed   %d\n", results->failed);
555 		printf("skipped  %d\n", results->skipped);
556 		printf("warnings %d\n", results->warnings);
557 
558 		if (results->failed)
559 			ret |= TFAIL;
560 
561 		if (results->skipped)
562 			ret |= TCONF;
563 
564 		if (results->warnings)
565 			ret |= TWARN;
566 	}
567 
568 	do_cleanup();
569 
570 	exit(ret);
571 }
572 
check_kver(void)573 void check_kver(void)
574 {
575 	int v1, v2, v3;
576 
577 	if (tst_parse_kver(tst_test->min_kver, &v1, &v2, &v3)) {
578 		tst_res(TWARN,
579 		        "Invalid kernel version %s, expected %%d.%%d.%%d",
580 		        tst_test->min_kver);
581 	}
582 
583 	if (tst_kvercmp(v1, v2, v3) < 0) {
584 		tst_brk(TCONF, "The test requires kernel %s or newer",
585 		        tst_test->min_kver);
586 	}
587 }
588 
results_equal(struct results * a,struct results * b)589 static int results_equal(struct results *a, struct results *b)
590 {
591 	if (a->passed != b->passed)
592 		return 0;
593 
594 	if (a->failed != b->failed)
595 		return 0;
596 
597 	if (a->skipped != b->skipped)
598 		return 0;
599 
600 	return 1;
601 }
602 
needs_tmpdir(void)603 static int needs_tmpdir(void)
604 {
605 	return tst_test->needs_tmpdir ||
606 	       tst_test->needs_device ||
607 	       tst_test->resource_files ||
608 	       tst_test->needs_checkpoints;
609 }
610 
copy_resources(void)611 static void copy_resources(void)
612 {
613 	unsigned int i;
614 
615 	for (i = 0; tst_test->resource_files[i]; i++)
616 		TST_RESOURCE_COPY(NULL, tst_test->resource_files[i], NULL);
617 }
618 
619 static struct tst_device tdev;
620 struct tst_device *tst_device;
621 
do_setup(int argc,char * argv[])622 static void do_setup(int argc, char *argv[])
623 {
624 	if (!tst_test)
625 		tst_brk(TBROK, "No tests to run");
626 
627 	if (!tst_test->tid)
628 		tst_brk(TBROK, "No tid set in test structure");
629 
630 	if (!tst_test->test && !tst_test->test_all)
631 		tst_brk(TBROK, "No test function speficied");
632 
633 	if (tst_test->test && tst_test->test_all)
634 		tst_brk(TBROK, "You can define either test() or test_all()");
635 
636 	if (tst_test->test && !tst_test->tcnt)
637 		tst_brk(TBROK, "Number of tests (tcnt) must not be > 0");
638 
639 	if (tst_test->test_all && tst_test->tcnt)
640 		tst_brk(TBROK, "You can't define tcnt for test_all()");
641 
642 	if (tst_test->needs_root && geteuid() != 0)
643 		tst_brk(TCONF, "Test needs to be run as root");
644 
645 	if (tst_test->min_kver)
646 		check_kver();
647 
648 	if (tst_test->format_device)
649 		tst_test->needs_device = 1;
650 
651 	if (tst_test->mount_device) {
652 		tst_test->needs_device = 1;
653 		tst_test->format_device = 1;
654 	}
655 
656 	parse_opts(argc, argv);
657 
658 	setup_ipc();
659 
660 	if (needs_tmpdir() && !tst_tmpdir_created())
661 		tst_tmpdir();
662 
663 	if (tst_test->needs_device) {
664 		tdev.dev = tst_acquire_device_(NULL, tst_test->dev_min_size);
665 
666 		if (!tdev.dev)
667 			tst_brk(TCONF, "Failed to acquire device");
668 
669 		tst_device = &tdev;
670 
671 		if (tst_test->dev_fs_type)
672 			tdev.fs_type = tst_test->dev_fs_type;
673 		else
674 			tdev.fs_type = tst_dev_fs_type();
675 
676 		if (tst_test->format_device) {
677 			SAFE_MKFS(tdev.dev, tdev.fs_type,
678 			          tst_test->dev_fs_opts,
679 				  tst_test->dev_extra_opt);
680 		}
681 
682 		if (tst_test->mount_device) {
683 
684 			if (!tst_test->mntpoint) {
685 				tst_brk(TBROK,
686 					"tst_test->mntpoint must be set!");
687 			}
688 
689 			SAFE_MKDIR(tst_test->mntpoint, 0777);
690 			SAFE_MOUNT(tdev.dev, tst_test->mntpoint, tdev.fs_type,
691 				   tst_test->mnt_flags, tst_test->mnt_data);
692 			device_mounted = 1;
693 		}
694 	}
695 
696 	if (tst_test->resource_files)
697 		copy_resources();
698 }
699 
do_test_setup(void)700 static void do_test_setup(void)
701 {
702 	main_pid = getpid();
703 
704 	if (tst_test->setup)
705 		tst_test->setup();
706 
707 	if (main_pid != getpid())
708 		tst_brk(TBROK, "Runaway child in setup()!");
709 }
710 
do_cleanup(void)711 static void do_cleanup(void)
712 {
713 	if (device_mounted)
714 		tst_umount(tst_test->mntpoint);
715 
716 	if (tst_test->needs_device && tdev.dev)
717 		tst_release_device(tdev.dev);
718 
719 	if (tst_tmpdir_created()) {
720 		/* avoid munmap() on wrong pointer in tst_rmdir() */
721 		tst_futexes = NULL;
722 		tst_rmdir();
723 	}
724 
725 	cleanup_ipc();
726 }
727 
run_tests(void)728 static void run_tests(void)
729 {
730 	unsigned int i;
731 	struct results saved_results;
732 
733 	if (!tst_test->test) {
734 		saved_results = *results;
735 		tst_test->test_all();
736 
737 		if (getpid() != main_pid) {
738 			exit(0);
739 		}
740 
741 		tst_reap_children();
742 
743 		if (results_equal(&saved_results, results))
744 			tst_brk(TBROK, "Test haven't reported results!");
745 		return;
746 	}
747 
748 	for (i = 0; i < tst_test->tcnt; i++) {
749 		saved_results = *results;
750 		tst_test->test(i);
751 
752 		if (getpid() != main_pid) {
753 			exit(0);
754 		}
755 
756 		tst_reap_children();
757 
758 		if (results_equal(&saved_results, results))
759 			tst_brk(TBROK, "Test %i haven't reported results!", i);
760 	}
761 }
762 
get_time_ms(void)763 static unsigned long long get_time_ms(void)
764 {
765 	struct timeval tv;
766 
767 	gettimeofday(&tv, NULL);
768 
769 	return tv.tv_sec * 1000 + tv.tv_usec / 1000;
770 }
771 
testrun(void)772 static void testrun(void)
773 {
774 	unsigned int i = 0;
775 	unsigned long long stop_time = 0;
776 	int cont = 1;
777 
778 	do_test_setup();
779 
780 	if (duration > 0)
781 		stop_time = get_time_ms() + (unsigned long long)(duration * 1000);
782 
783 	for (;;) {
784 		cont = 0;
785 
786 		if (i < (unsigned int)iterations) {
787 			i++;
788 			cont = 1;
789 		}
790 
791 		if (stop_time && get_time_ms() < stop_time)
792 			cont = 1;
793 
794 		if (!cont)
795 			break;
796 
797 		run_tests();
798 
799 		kill(getppid(), SIGUSR1);
800 	}
801 
802 	do_test_cleanup();
803 	exit(0);
804 }
805 
806 static pid_t test_pid;
807 
alarm_handler(int sig LTP_ATTRIBUTE_UNUSED)808 static void alarm_handler(int sig LTP_ATTRIBUTE_UNUSED)
809 {
810 	kill(-test_pid, SIGKILL);
811 }
812 
heartbeat_handler(int sig LTP_ATTRIBUTE_UNUSED)813 static void heartbeat_handler(int sig LTP_ATTRIBUTE_UNUSED)
814 {
815 	alarm(results->timeout);
816 }
817 
818 #define SIGINT_MSG "Sending SIGKILL to test process...\n"
819 
sigint_handler(int sig LTP_ATTRIBUTE_UNUSED)820 static void sigint_handler(int sig LTP_ATTRIBUTE_UNUSED)
821 {
822 	if (test_pid > 0) {
823 		if (write(2, SIGINT_MSG, sizeof(SIGINT_MSG) - 1)) {
824 			/* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66425 */
825 		}
826 		kill(-test_pid, SIGKILL);
827 	}
828 }
829 
tst_set_timeout(unsigned int timeout)830 void tst_set_timeout(unsigned int timeout)
831 {
832 	char *mul = getenv("LTP_TIMEOUT_MUL");
833 
834 	results->timeout = timeout;
835 
836 	if (mul) {
837 		float m = atof(mul);
838 
839 		if (m < 1)
840 			tst_brk(TBROK, "Invalid timeout multiplier '%s'", mul);
841 
842 		results->timeout = results->timeout * m + 0.5;
843 	}
844 
845 	tst_res(TINFO, "Timeout per run is %uh %02um %02us",
846 		results->timeout/3600, (results->timeout%3600)/60,
847 		results->timeout % 60);
848 
849 	if (getpid() == lib_pid)
850 		alarm(results->timeout);
851 	else
852 		kill(getppid(), SIGUSR1);
853 }
854 
tst_run_tcases(int argc,char * argv[],struct tst_test * self)855 void tst_run_tcases(int argc, char *argv[], struct tst_test *self)
856 {
857 	int status;
858 
859 	lib_pid = getpid();
860 	tst_test = self;
861 	TCID = tst_test->tid;
862 
863 	do_setup(argc, argv);
864 
865 	SAFE_SIGNAL(SIGALRM, alarm_handler);
866 	SAFE_SIGNAL(SIGUSR1, heartbeat_handler);
867 
868 	if (tst_test->timeout)
869 		tst_set_timeout(tst_test->timeout);
870 	else
871 		tst_set_timeout(300);
872 
873 	SAFE_SIGNAL(SIGINT, sigint_handler);
874 
875 	test_pid = fork();
876 	if (test_pid < 0)
877 		tst_brk(TBROK | TERRNO, "fork()");
878 
879 	if (!test_pid) {
880 		SAFE_SIGNAL(SIGALRM, SIG_DFL);
881 		SAFE_SIGNAL(SIGUSR1, SIG_DFL);
882 		SAFE_SIGNAL(SIGINT, SIG_DFL);
883 		SAFE_SETPGID(0, 0);
884 		testrun();
885 	}
886 
887 	SAFE_WAITPID(test_pid, &status, 0);
888 	alarm(0);
889 	SAFE_SIGNAL(SIGINT, SIG_DFL);
890 
891 	if (WIFEXITED(status) && WEXITSTATUS(status))
892 		do_exit(WEXITSTATUS(status));
893 
894 	if (WIFSIGNALED(status) && WTERMSIG(status) == SIGKILL) {
895 		tst_res(TINFO, "If you are running on slow machine, "
896 			       "try exporting LTP_TIMEOUT_MUL > 1");
897 		tst_brk(TBROK, "Test killed! (timeout?)");
898 	}
899 
900 	if (WIFSIGNALED(status))
901 		tst_brk(TBROK, "Test killed by %s!", tst_strsig(WTERMSIG(status)));
902 
903 	do_exit(0);
904 }
905