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