blob: 26414e31ca77e7d8e0702b63dc732a912bd51667 [file] [log] [blame]
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +01001/*
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>
Sandeep Patilc9a7def2017-09-19 12:49:58 -070024#include <sys/mount.h>
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +010025#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"
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +010031#include "tst_device.h"
32#include "lapi/futex.h"
Steve Mucklec20831d2017-09-20 13:23:06 -070033#include "lapi/syscalls.h"
Petr Vorel3a0ef862017-03-01 15:31:08 +010034#include "tst_ansi_color.h"
Cyril Hrubisc4596542017-06-20 15:42:18 +020035#include "tst_timer_test.h"
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +010036
37#include "old_resource.h"
38#include "old_device.h"
39#include "old_tmpdir.h"
40
41struct tst_test *tst_test;
42
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +010043static int iterations = 1;
44static float duration = -1;
Jan Stanceke0bfa7d2016-06-08 15:27:55 +020045static pid_t main_pid, lib_pid;
Sandeep Patilc9a7def2017-09-19 12:49:58 -070046static int mntpoint_mounted;
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +010047
48struct results {
Jan Stancekc54ca052016-04-13 12:31:13 +020049 int passed;
50 int skipped;
51 int failed;
52 int warnings;
Cyril Hrubis2ad59b72016-08-03 15:53:55 +020053 unsigned int timeout;
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +010054};
55
56static struct results *results;
57
58static int ipc_fd;
59
60extern void *tst_futexes;
61extern unsigned int tst_max_futexes;
62
63#define IPC_ENV_VAR "LTP_IPC_PATH"
64
65static char ipc_path[1024];
66const char *tst_ipc_path = ipc_path;
67char *const tst_ipc_envp[] = {ipc_path, NULL};
68
69static char shm_path[1024];
70
Jan Stancek332540e2016-06-08 16:48:22 +020071static void do_cleanup(void);
Cyril Hrubisfa495172016-06-08 16:06:35 +020072static void do_exit(int ret) __attribute__ ((noreturn));
Jan Stanceke0bfa7d2016-06-08 15:27:55 +020073
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +010074static void setup_ipc(void)
75{
76 size_t size = getpagesize();
77
Steven Jackson9f41dcf2016-12-21 20:09:01 +000078 if (access("/dev/shm", F_OK) == 0) {
79 snprintf(shm_path, sizeof(shm_path), "/dev/shm/ltp_%s_%d",
80 tst_test->tid, getpid());
81 } else {
82 char *tmpdir;
83
84 if (!tst_tmpdir_created())
85 tst_tmpdir();
86
87 tmpdir = tst_get_tmpdir();
88 snprintf(shm_path, sizeof(shm_path), "%s/ltp_%s_%d",
89 tmpdir, tst_test->tid, getpid());
90 free(tmpdir);
91 }
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +010092
93 ipc_fd = open(shm_path, O_CREAT | O_EXCL | O_RDWR, 0600);
94 if (ipc_fd < 0)
95 tst_brk(TBROK | TERRNO, "open(%s)", shm_path);
96
97 SAFE_FTRUNCATE(ipc_fd, size);
98
99 results = SAFE_MMAP(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, ipc_fd, 0);
100
101 /* Checkpoints needs to be accessible from processes started by exec() */
102 if (tst_test->needs_checkpoints)
103 sprintf(ipc_path, IPC_ENV_VAR "=%s", shm_path);
104 else
105 SAFE_UNLINK(shm_path);
106
107 SAFE_CLOSE(ipc_fd);
108
109 if (tst_test->needs_checkpoints) {
110 tst_futexes = (char*)results + sizeof(struct results);
111 tst_max_futexes = (size - sizeof(struct results))/sizeof(futex_t);
112 }
113}
114
115static void cleanup_ipc(void)
116{
117 size_t size = getpagesize();
118
119 if (ipc_fd > 0 && close(ipc_fd))
120 tst_res(TWARN | TERRNO, "close(ipc_fd) failed");
121
Cyril Hrubis9726b902017-07-27 11:28:50 +0200122 if (shm_path[0] && !access(shm_path, F_OK) && unlink(shm_path))
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100123 tst_res(TWARN | TERRNO, "unlink(%s) failed", shm_path);
124
Cyril Hrubis9726b902017-07-27 11:28:50 +0200125 if (results) {
126 msync((void*)results, size, MS_SYNC);
127 munmap((void*)results, size);
128 }
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100129}
130
131void tst_reinit(void)
132{
133 const char *path = getenv("LTP_IPC_PATH");
134 size_t size = getpagesize();
135 int fd;
136 void *ptr;
137
138 if (!path)
139 tst_brk(TBROK, "LTP_IPC_PATH is not defined");
140
141 if (access(path, F_OK))
142 tst_brk(TBROK, "File %s does not exist!", path);
143
144 fd = SAFE_OPEN(path, O_RDWR);
145
146 ptr = SAFE_MMAP(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
147 tst_futexes = (char*)ptr + sizeof(struct results);
148 tst_max_futexes = (size - sizeof(struct results))/sizeof(futex_t);
149
150 SAFE_CLOSE(fd);
151}
152
Cyril Hrubis160ffcc2017-02-14 10:21:08 +0100153static void update_results(int ttype)
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100154{
Cyril Hrubisd97debf2017-02-13 12:37:39 +0100155 if (!results)
156 return;
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100157
158 switch (ttype) {
159 case TCONF:
160 tst_atomic_inc(&results->skipped);
161 break;
162 case TPASS:
163 tst_atomic_inc(&results->passed);
164 break;
165 case TWARN:
166 tst_atomic_inc(&results->warnings);
167 break;
168 case TFAIL:
169 tst_atomic_inc(&results->failed);
170 break;
171 }
172}
173
174static void print_result(const char *file, const int lineno, int ttype,
175 const char *fmt, va_list va)
176{
177 char buf[1024];
178 char *str = buf;
179 int ret, size = sizeof(buf);
180 const char *str_errno = NULL;
181 const char *res;
182
183 switch (TTYPE_RESULT(ttype)) {
184 case TPASS:
185 res = "PASS";
186 break;
187 case TFAIL:
188 res = "FAIL";
189 break;
190 case TBROK:
191 res = "BROK";
192 break;
193 case TCONF:
194 res = "CONF";
195 break;
196 case TWARN:
197 res = "WARN";
198 break;
199 case TINFO:
200 res = "INFO";
201 break;
202 default:
203 tst_brk(TBROK, "Invalid ttype value %i", ttype);
Cyril Hrubis6440c5d2017-02-09 15:41:24 +0100204 abort();
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100205 }
206
207 if (ttype & TERRNO)
208 str_errno = tst_strerrno(errno);
209
210 if (ttype & TTERRNO)
211 str_errno = tst_strerrno(TEST_ERRNO);
212
Petr Vorela7f61332017-01-24 20:47:30 +0100213 ret = snprintf(str, size, "%s:%i: ", file, lineno);
214 str += ret;
215 size -= ret;
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100216
Cyril Hrubis047c7272017-02-13 16:23:36 +0100217 if (tst_color_enabled(STDERR_FILENO))
Petr Vorela7f61332017-01-24 20:47:30 +0100218 ret = snprintf(str, size, "%s%s: %s", tst_ttype2color(ttype),
219 res, ANSI_COLOR_RESET);
220 else
221 ret = snprintf(str, size, "%s: ", res);
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100222 str += ret;
223 size -= ret;
224
225 ret = vsnprintf(str, size, fmt, va);
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100226 str += ret;
227 size -= ret;
228
Petr Vorela7f61332017-01-24 20:47:30 +0100229 if (str_errno) {
230 ret = snprintf(str, size, ": %s", str_errno);
231 str += ret;
232 size -= ret;
233 }
234
235 snprintf(str, size, "\n");
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100236
237 fputs(buf, stderr);
238}
239
240void tst_vres_(const char *file, const int lineno, int ttype,
241 const char *fmt, va_list va)
242{
243 print_result(file, lineno, ttype, fmt, va);
244
Cyril Hrubis160ffcc2017-02-14 10:21:08 +0100245 update_results(TTYPE_RESULT(ttype));
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100246}
247
248void tst_vbrk_(const char *file, const int lineno, int ttype,
Cyril Hrubis6440c5d2017-02-09 15:41:24 +0100249 const char *fmt, va_list va);
250
251static void (*tst_brk_handler)(const char *file, const int lineno, int ttype,
252 const char *fmt, va_list va) = tst_vbrk_;
253
254static void tst_cvres(const char *file, const int lineno, int ttype,
255 const char *fmt, va_list va)
256{
257 if (TTYPE_RESULT(ttype) == TBROK) {
258 ttype &= ~TTYPE_MASK;
259 ttype |= TWARN;
260 }
261
262 print_result(file, lineno, ttype, fmt, va);
263 update_results(TTYPE_RESULT(ttype));
264}
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100265
Cyril Hrubis4aebb6c2016-06-07 13:40:41 +0200266static void do_test_cleanup(void)
267{
Cyril Hrubis6440c5d2017-02-09 15:41:24 +0100268 tst_brk_handler = tst_cvres;
269
Cyril Hrubis4aebb6c2016-06-07 13:40:41 +0200270 if (tst_test->cleanup)
271 tst_test->cleanup();
Cyril Hrubis6440c5d2017-02-09 15:41:24 +0100272
273 tst_brk_handler = tst_vbrk_;
Cyril Hrubis4aebb6c2016-06-07 13:40:41 +0200274}
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100275
276void tst_vbrk_(const char *file, const int lineno, int ttype,
277 const char *fmt, va_list va)
278{
279 print_result(file, lineno, ttype, fmt, va);
280
Steve Mucklec20831d2017-09-20 13:23:06 -0700281 /*
282 * The getpid implementation in some C library versions may cause cloned
283 * test threads to show the same pid as their parent when CLONE_VM is
284 * specified but CLONE_THREAD is not. Use direct syscall to avoid
285 * cleanup running in the child.
286 */
287 if (syscall(SYS_getpid) == main_pid)
Cyril Hrubis4aebb6c2016-06-07 13:40:41 +0200288 do_test_cleanup();
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100289
Jan Stanceke0bfa7d2016-06-08 15:27:55 +0200290 if (getpid() == lib_pid)
Cyril Hrubisfa495172016-06-08 16:06:35 +0200291 do_exit(TTYPE_RESULT(ttype));
Jan Stanceke0bfa7d2016-06-08 15:27:55 +0200292
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100293 exit(TTYPE_RESULT(ttype));
294}
295
296void tst_res_(const char *file, const int lineno, int ttype,
297 const char *fmt, ...)
298{
299 va_list va;
300
301 va_start(va, fmt);
302 tst_vres_(file, lineno, ttype, fmt, va);
303 va_end(va);
304}
305
306void tst_brk_(const char *file, const int lineno, int ttype,
307 const char *fmt, ...)
308{
309 va_list va;
310
311 va_start(va, fmt);
Cyril Hrubis6440c5d2017-02-09 15:41:24 +0100312 tst_brk_handler(file, lineno, ttype, fmt, va);
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100313 va_end(va);
314}
315
316static void check_child_status(pid_t pid, int status)
317{
318 int ret;
319
320 if (WIFSIGNALED(status)) {
321 tst_brk(TBROK, "Child (%i) killed by signal %s",
322 pid, tst_strsig(WTERMSIG(status)));
323 }
324
325 if (!(WIFEXITED(status)))
326 tst_brk(TBROK, "Child (%i) exitted abnormaly", pid);
327
328 ret = WEXITSTATUS(status);
329 switch (ret) {
330 case TPASS:
331 break;
332 case TBROK:
333 case TCONF:
334 tst_brk(ret, "Reported by child (%i)", pid);
335 default:
336 tst_brk(TBROK, "Invalid child (%i) exit value %i", pid, ret);
337 }
338}
339
Stanislav Kholmanskikh6b56aa72016-08-04 17:16:31 +0300340void tst_reap_children(void)
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100341{
342 int status;
343 pid_t pid;
344
345 for (;;) {
346 pid = wait(&status);
347
348 if (pid > 0) {
349 check_child_status(pid, status);
350 continue;
351 }
352
353 if (errno == ECHILD)
354 break;
355
356 if (errno == EINTR)
357 continue;
358
359 tst_brk(TBROK | TERRNO, "wait() failed");
360 }
361}
362
363
364pid_t safe_fork(const char *filename, unsigned int lineno)
365{
366 pid_t pid;
367
368 if (!tst_test->forks_child)
369 tst_brk(TBROK, "test.forks_child must be set!");
370
371 fflush(stdout);
372
373 pid = fork();
374 if (pid < 0)
375 tst_brk_(filename, lineno, TBROK | TERRNO, "fork() failed");
376
377 return pid;
378}
379
380static struct option {
381 char *optstr;
382 char *help;
383} options[] = {
Cyril Hrubisb819c222016-08-03 14:36:07 +0200384 {"h", "-h Prints this help"},
385 {"i:", "-i n Execute test n times"},
386 {"I:", "-I x Execute test for n seconds"},
387 {"C:", "-C ARG Run child process with ARG arguments (used internally)"},
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100388};
389
390static void print_help(void)
391{
392 unsigned int i;
393
394 for (i = 0; i < ARRAY_SIZE(options); i++)
395 fprintf(stderr, "%s\n", options[i].help);
396
397 if (!tst_test->options)
398 return;
399
400 for (i = 0; tst_test->options[i].optstr; i++)
Cyril Hrubisb819c222016-08-03 14:36:07 +0200401 fprintf(stderr, "%s\n", tst_test->options[i].help);
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100402}
403
404static void check_option_collision(void)
405{
406 unsigned int i, j;
407 struct tst_option *toptions = tst_test->options;
408
409 if (!toptions)
410 return;
411
412 for (i = 0; toptions[i].optstr; i++) {
413 for (j = 0; j < ARRAY_SIZE(options); j++) {
414 if (toptions[i].optstr[0] == options[j].optstr[0]) {
415 tst_brk(TBROK, "Option collision '%s'",
416 options[j].help);
417 }
418 }
419 }
420}
421
422static unsigned int count_options(void)
423{
424 unsigned int i;
425
426 if (!tst_test->options)
427 return 0;
428
429 for (i = 0; tst_test->options[i].optstr; i++);
430
431 return i;
432}
433
434static void parse_topt(unsigned int topts_len, int opt, char *optarg)
435{
436 unsigned int i;
437 struct tst_option *toptions = tst_test->options;
438
439 for (i = 0; i < topts_len; i++) {
440 if (toptions[i].optstr[0] == opt)
441 break;
442 }
443
444 if (i >= topts_len)
445 tst_brk(TBROK, "Invalid option '%c' (should not happen)", opt);
446
Jan Stancekc07d36c2016-08-01 11:44:55 +0200447 *(toptions[i].arg) = optarg ? optarg : "";
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100448}
449
450/* see self_exec.c */
451#ifdef UCLINUX
452extern char *child_args;
453#endif
454
455static void parse_opts(int argc, char *argv[])
456{
457 unsigned int i, topts_len = count_options();
458 char optstr[2 * ARRAY_SIZE(options) + 2 * topts_len];
459 int opt;
460
461 check_option_collision();
462
463 optstr[0] = 0;
464
465 for (i = 0; i < ARRAY_SIZE(options); i++)
466 strcat(optstr, options[i].optstr);
467
468 for (i = 0; i < topts_len; i++)
469 strcat(optstr, tst_test->options[i].optstr);
470
471 while ((opt = getopt(argc, argv, optstr)) > 0) {
472 switch (opt) {
473 case '?':
474 print_help();
475 tst_brk(TBROK, "Invalid option");
476 case 'h':
477 print_help();
478 exit(0);
479 case 'i':
480 iterations = atoi(optarg);
481 break;
482 case 'I':
483 duration = atof(optarg);
484 break;
485 case 'C':
486#ifdef UCLINUX
487 child_args = optarg;
488#endif
489 break;
490 default:
491 parse_topt(topts_len, opt, optarg);
492 }
493 }
Cyril Hrubis9dc07e02017-10-02 11:11:04 +0200494
495 if (optind < argc)
496 tst_brk(TBROK, "Unexpected argument(s) '%s'...", argv[optind]);
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100497}
498
Cyril Hrubis1e92d8a2016-08-03 16:31:46 +0200499int tst_parse_int(const char *str, int *val, int min, int max)
500{
501 long rval;
Alexey Kodanevdd90c002016-12-18 00:36:00 +0300502
503 if (!str)
504 return 0;
505
506 int ret = tst_parse_long(str, &rval, min, max);
507
508 if (ret)
509 return ret;
510
511 *val = (int)rval;
512 return 0;
513}
514
515int tst_parse_long(const char *str, long *val, long min, long max)
516{
517 long rval;
Cyril Hrubis1e92d8a2016-08-03 16:31:46 +0200518 char *end;
519
520 if (!str)
521 return 0;
522
523 errno = 0;
524 rval = strtol(str, &end, 10);
525
526 if (str == end || *end != '\0')
527 return EINVAL;
528
529 if (errno)
530 return errno;
531
Alexey Kodanevdd90c002016-12-18 00:36:00 +0300532 if (rval > max || rval < min)
Cyril Hrubis1e92d8a2016-08-03 16:31:46 +0200533 return ERANGE;
534
Alexey Kodanevdd90c002016-12-18 00:36:00 +0300535 *val = rval;
Cyril Hrubis1e92d8a2016-08-03 16:31:46 +0200536 return 0;
537}
538
539int tst_parse_float(const char *str, float *val, float min, float max)
540{
541 double rval;
542 char *end;
543
544 if (!str)
545 return 0;
546
547 errno = 0;
548 rval = strtod(str, &end);
549
550 if (str == end || *end != '\0')
551 return EINVAL;
552
553 if (errno)
554 return errno;
555
556 if (rval > (double)max || rval < (double)min)
557 return ERANGE;
558
559 *val = (float)rval;
560 return 0;
561}
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100562
Cyril Hrubisfa495172016-06-08 16:06:35 +0200563static void do_exit(int ret)
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100564{
Xiao Yang11dfc322016-06-16 15:52:04 +0800565 if (results) {
566 printf("\nSummary:\n");
567 printf("passed %d\n", results->passed);
568 printf("failed %d\n", results->failed);
569 printf("skipped %d\n", results->skipped);
570 printf("warnings %d\n", results->warnings);
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100571
Xiao Yang11dfc322016-06-16 15:52:04 +0800572 if (results->failed)
573 ret |= TFAIL;
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100574
Cyril Hrubis5390d6e2017-09-07 15:47:22 +0200575 if (results->skipped && !results->passed)
Xiao Yang11dfc322016-06-16 15:52:04 +0800576 ret |= TCONF;
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100577
Xiao Yang11dfc322016-06-16 15:52:04 +0800578 if (results->warnings)
579 ret |= TWARN;
580 }
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100581
Jan Stancek332540e2016-06-08 16:48:22 +0200582 do_cleanup();
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100583
584 exit(ret);
585}
586
587void check_kver(void)
588{
589 int v1, v2, v3;
590
Cyril Hrubis4dcfd282016-11-01 15:07:12 +0100591 if (tst_parse_kver(tst_test->min_kver, &v1, &v2, &v3)) {
592 tst_res(TWARN,
593 "Invalid kernel version %s, expected %%d.%%d.%%d",
594 tst_test->min_kver);
595 }
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100596
597 if (tst_kvercmp(v1, v2, v3) < 0) {
598 tst_brk(TCONF, "The test requires kernel %s or newer",
599 tst_test->min_kver);
600 }
601}
602
603static int results_equal(struct results *a, struct results *b)
604{
605 if (a->passed != b->passed)
606 return 0;
607
608 if (a->failed != b->failed)
609 return 0;
610
611 if (a->skipped != b->skipped)
612 return 0;
613
614 return 1;
615}
616
617static int needs_tmpdir(void)
618{
619 return tst_test->needs_tmpdir ||
620 tst_test->needs_device ||
621 tst_test->resource_files ||
622 tst_test->needs_checkpoints;
623}
624
625static void copy_resources(void)
626{
627 unsigned int i;
628
629 for (i = 0; tst_test->resource_files[i]; i++)
630 TST_RESOURCE_COPY(NULL, tst_test->resource_files[i], NULL);
631}
632
Cyril Hrubisa5bf5252017-03-14 15:25:29 +0800633static const char *get_tid(char *argv[])
634{
635 char *p;
636
637 if (!argv[0] || !argv[0][0]) {
638 tst_res(TINFO, "argv[0] is empty!");
639 return "ltp_empty_argv";
640 }
641
642 p = strrchr(argv[0], '/');
643 if (p)
644 return p+1;
645
646 return argv[0];
647}
648
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100649static struct tst_device tdev;
650struct tst_device *tst_device;
651
Cyril Hrubisc4596542017-06-20 15:42:18 +0200652static void assert_test_fn(void)
653{
654 int cnt = 0;
655
656 if (tst_test->test)
657 cnt++;
658
659 if (tst_test->test_all)
660 cnt++;
661
662 if (tst_test->sample)
663 cnt++;
664
665 if (!cnt)
666 tst_brk(TBROK, "No test function speficied");
667
668 if (cnt != 1)
669 tst_brk(TBROK, "You can define only one test function");
670
671 if (tst_test->test && !tst_test->tcnt)
672 tst_brk(TBROK, "Number of tests (tcnt) must not be > 0");
673
674 if (!tst_test->test && tst_test->tcnt)
675 tst_brk(TBROK, "You can define tcnt only for test()");
676}
677
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100678static void do_setup(int argc, char *argv[])
679{
680 if (!tst_test)
681 tst_brk(TBROK, "No tests to run");
682
Cyril Hrubisf706a2f2017-08-01 17:31:30 +0200683 if (tst_test->tconf_msg)
684 tst_brk(TCONF, "%s", tst_test->tconf_msg);
685
Cyril Hrubisc4596542017-06-20 15:42:18 +0200686 assert_test_fn();
687
688 if (tst_test->sample)
689 tst_test = tst_timer_test_setup(tst_test);
690
Cyril Hrubisf5f208b2016-08-04 16:10:21 +0200691 if (!tst_test->tid)
Cyril Hrubisa5bf5252017-03-14 15:25:29 +0800692 tst_test->tid = get_tid(argv);
Cyril Hrubisf5f208b2016-08-04 16:10:21 +0200693
Cyril Hrubis88c220d2017-07-27 11:16:39 +0200694 parse_opts(argc, argv);
695
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100696 if (tst_test->needs_root && geteuid() != 0)
697 tst_brk(TCONF, "Test needs to be run as root");
698
699 if (tst_test->min_kver)
700 check_kver();
701
Cyril Hrubis874326d2017-02-14 15:59:40 +0100702 if (tst_test->format_device)
703 tst_test->needs_device = 1;
704
705 if (tst_test->mount_device) {
706 tst_test->needs_device = 1;
707 tst_test->format_device = 1;
708 }
709
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100710 setup_ipc();
711
Steven Jackson9f41dcf2016-12-21 20:09:01 +0000712 if (needs_tmpdir() && !tst_tmpdir_created())
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100713 tst_tmpdir();
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100714
Sandeep Patilc9a7def2017-09-19 12:49:58 -0700715 if (tst_test->mntpoint)
716 SAFE_MKDIR(tst_test->mntpoint, 0777);
717
718 if ((tst_test->needs_rofs || tst_test->mount_device) &&
719 !tst_test->mntpoint) {
720 tst_brk(TBROK, "tst_test->mntpoint must be set!");
721 }
722
723 if (tst_test->needs_rofs) {
724 /* If we failed to mount read-only tmpfs. Fallback to
725 * using a device with empty read-only filesystem.
726 */
727 if (mount(NULL, tst_test->mntpoint, "tmpfs", MS_RDONLY, NULL)) {
728 tst_res(TINFO | TERRNO, "Can't mount tmpfs read-only"
729 " at %s, setting up a device instead\n",
730 tst_test->mntpoint);
731 tst_test->mount_device = 1;
732 tst_test->needs_device = 1;
733 tst_test->format_device = 1;
734 tst_test->mnt_flags = MS_RDONLY;
735 } else {
736 mntpoint_mounted = 1;
737 }
738 }
739
740 if (tst_test->needs_device && !mntpoint_mounted) {
Cyril Hrubis874326d2017-02-14 15:59:40 +0100741 tdev.dev = tst_acquire_device_(NULL, tst_test->dev_min_size);
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100742
743 if (!tdev.dev)
744 tst_brk(TCONF, "Failed to acquire device");
745
746 tst_device = &tdev;
Cyril Hrubis874326d2017-02-14 15:59:40 +0100747
748 if (tst_test->dev_fs_type)
749 tdev.fs_type = tst_test->dev_fs_type;
750 else
751 tdev.fs_type = tst_dev_fs_type();
752
753 if (tst_test->format_device) {
754 SAFE_MKFS(tdev.dev, tdev.fs_type,
755 tst_test->dev_fs_opts,
756 tst_test->dev_extra_opt);
757 }
758
759 if (tst_test->mount_device) {
Cyril Hrubis874326d2017-02-14 15:59:40 +0100760 SAFE_MOUNT(tdev.dev, tst_test->mntpoint, tdev.fs_type,
761 tst_test->mnt_flags, tst_test->mnt_data);
Sandeep Patilc9a7def2017-09-19 12:49:58 -0700762 mntpoint_mounted = 1;
Cyril Hrubis874326d2017-02-14 15:59:40 +0100763 }
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100764 }
765
766 if (tst_test->resource_files)
767 copy_resources();
Cyril Hrubis4aebb6c2016-06-07 13:40:41 +0200768}
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100769
Cyril Hrubis4aebb6c2016-06-07 13:40:41 +0200770static void do_test_setup(void)
771{
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100772 main_pid = getpid();
773
774 if (tst_test->setup)
775 tst_test->setup();
776
777 if (main_pid != getpid())
778 tst_brk(TBROK, "Runaway child in setup()!");
779}
780
781static void do_cleanup(void)
782{
Sandeep Patilc9a7def2017-09-19 12:49:58 -0700783 if (mntpoint_mounted)
Cyril Hrubis874326d2017-02-14 15:59:40 +0100784 tst_umount(tst_test->mntpoint);
785
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100786 if (tst_test->needs_device && tdev.dev)
787 tst_release_device(tdev.dev);
788
Steven Jackson9f41dcf2016-12-21 20:09:01 +0000789 if (tst_tmpdir_created()) {
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100790 /* avoid munmap() on wrong pointer in tst_rmdir() */
791 tst_futexes = NULL;
792 tst_rmdir();
793 }
Jan Stancek332540e2016-06-08 16:48:22 +0200794
795 cleanup_ipc();
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100796}
797
798static void run_tests(void)
799{
800 unsigned int i;
801 struct results saved_results;
802
803 if (!tst_test->test) {
804 saved_results = *results;
805 tst_test->test_all();
806
807 if (getpid() != main_pid) {
808 exit(0);
809 }
810
Stanislav Kholmanskikh6b56aa72016-08-04 17:16:31 +0300811 tst_reap_children();
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100812
813 if (results_equal(&saved_results, results))
814 tst_brk(TBROK, "Test haven't reported results!");
815 return;
816 }
817
818 for (i = 0; i < tst_test->tcnt; i++) {
819 saved_results = *results;
820 tst_test->test(i);
821
822 if (getpid() != main_pid) {
823 exit(0);
824 }
825
Stanislav Kholmanskikh6b56aa72016-08-04 17:16:31 +0300826 tst_reap_children();
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100827
828 if (results_equal(&saved_results, results))
829 tst_brk(TBROK, "Test %i haven't reported results!", i);
830 }
831}
832
833static unsigned long long get_time_ms(void)
834{
835 struct timeval tv;
836
837 gettimeofday(&tv, NULL);
838
839 return tv.tv_sec * 1000 + tv.tv_usec / 1000;
840}
841
Cyril Hrubis4aebb6c2016-06-07 13:40:41 +0200842static void testrun(void)
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100843{
844 unsigned int i = 0;
845 unsigned long long stop_time = 0;
846 int cont = 1;
847
Cyril Hrubis4aebb6c2016-06-07 13:40:41 +0200848 do_test_setup();
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100849
850 if (duration > 0)
851 stop_time = get_time_ms() + (unsigned long long)(duration * 1000);
852
853 for (;;) {
854 cont = 0;
855
856 if (i < (unsigned int)iterations) {
857 i++;
858 cont = 1;
859 }
860
861 if (stop_time && get_time_ms() < stop_time)
862 cont = 1;
863
864 if (!cont)
865 break;
866
867 run_tests();
Cyril Hrubis4aebb6c2016-06-07 13:40:41 +0200868
869 kill(getppid(), SIGUSR1);
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100870 }
871
Cyril Hrubis4aebb6c2016-06-07 13:40:41 +0200872 do_test_cleanup();
873 exit(0);
874}
875
876static pid_t test_pid;
Cyril Hrubis4aebb6c2016-06-07 13:40:41 +0200877
Cyril Hrubis79163172017-05-18 10:57:07 +0200878
879static volatile sig_atomic_t sigkill_retries;
880
881#define WRITE_MSG(msg) do { \
882 if (write(2, msg, sizeof(msg) - 1)) { \
883 /* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66425 */ \
884 } \
885} while (0)
886
Cyril Hrubis4aebb6c2016-06-07 13:40:41 +0200887static void alarm_handler(int sig LTP_ATTRIBUTE_UNUSED)
888{
Cyril Hrubis79163172017-05-18 10:57:07 +0200889 WRITE_MSG("Test timeouted, sending SIGKILL!\n");
Cyril Hrubis0f053c82016-06-07 14:29:39 +0200890 kill(-test_pid, SIGKILL);
Cyril Hrubis79163172017-05-18 10:57:07 +0200891 alarm(5);
892
893 if (++sigkill_retries > 10) {
894 WRITE_MSG("Cannot kill test processes!\n");
895 WRITE_MSG("Congratulation, likely test hit a kernel bug.\n");
896 WRITE_MSG("Exitting uncleanly...\n");
897 _exit(TFAIL);
898 }
Cyril Hrubis4aebb6c2016-06-07 13:40:41 +0200899}
900
901static void heartbeat_handler(int sig LTP_ATTRIBUTE_UNUSED)
902{
Cyril Hrubis2ad59b72016-08-03 15:53:55 +0200903 alarm(results->timeout);
Cyril Hrubis79163172017-05-18 10:57:07 +0200904 sigkill_retries = 0;
Cyril Hrubis2ad59b72016-08-03 15:53:55 +0200905}
906
Cyril Hrubisa41e9942016-08-04 16:31:06 +0200907static void sigint_handler(int sig LTP_ATTRIBUTE_UNUSED)
908{
909 if (test_pid > 0) {
Cyril Hrubis79163172017-05-18 10:57:07 +0200910 WRITE_MSG("Sending SIGKILL to test process...\n");
Cyril Hrubisa41e9942016-08-04 16:31:06 +0200911 kill(-test_pid, SIGKILL);
912 }
913}
914
Li Wang94823cf2017-07-18 16:23:00 +0800915void tst_set_timeout(int timeout)
Cyril Hrubis2ad59b72016-08-03 15:53:55 +0200916{
917 char *mul = getenv("LTP_TIMEOUT_MUL");
918
Li Wang94823cf2017-07-18 16:23:00 +0800919 if (timeout == -1) {
920 tst_res(TINFO, "Timeout per run is disabled");
921 return;
922 }
923
Cyril Hrubis2ad59b72016-08-03 15:53:55 +0200924 results->timeout = timeout;
925
926 if (mul) {
927 float m = atof(mul);
928
929 if (m < 1)
930 tst_brk(TBROK, "Invalid timeout multiplier '%s'", mul);
931
932 results->timeout = results->timeout * m + 0.5;
933 }
934
935 tst_res(TINFO, "Timeout per run is %uh %02um %02us",
936 results->timeout/3600, (results->timeout%3600)/60,
937 results->timeout % 60);
938
939 if (getpid() == lib_pid)
940 alarm(results->timeout);
941 else
942 kill(getppid(), SIGUSR1);
Cyril Hrubis4aebb6c2016-06-07 13:40:41 +0200943}
944
945void tst_run_tcases(int argc, char *argv[], struct tst_test *self)
946{
947 int status;
Cyril Hrubis4aebb6c2016-06-07 13:40:41 +0200948
Jan Stanceke0bfa7d2016-06-08 15:27:55 +0200949 lib_pid = getpid();
Cyril Hrubis4aebb6c2016-06-07 13:40:41 +0200950 tst_test = self;
Cyril Hrubis4aebb6c2016-06-07 13:40:41 +0200951
952 do_setup(argc, argv);
953
Cyril Hrubisa5bf5252017-03-14 15:25:29 +0800954 TCID = tst_test->tid;
955
Cyril Hrubis4aebb6c2016-06-07 13:40:41 +0200956 SAFE_SIGNAL(SIGALRM, alarm_handler);
957 SAFE_SIGNAL(SIGUSR1, heartbeat_handler);
958
Cyril Hrubis2ad59b72016-08-03 15:53:55 +0200959 if (tst_test->timeout)
960 tst_set_timeout(tst_test->timeout);
961 else
962 tst_set_timeout(300);
Cyril Hrubis4aebb6c2016-06-07 13:40:41 +0200963
Cyril Hrubisa41e9942016-08-04 16:31:06 +0200964 SAFE_SIGNAL(SIGINT, sigint_handler);
965
Cyril Hrubis4aebb6c2016-06-07 13:40:41 +0200966 test_pid = fork();
967 if (test_pid < 0)
968 tst_brk(TBROK | TERRNO, "fork()");
969
Cyril Hrubis0f053c82016-06-07 14:29:39 +0200970 if (!test_pid) {
Cyril Hrubisa41e9942016-08-04 16:31:06 +0200971 SAFE_SIGNAL(SIGALRM, SIG_DFL);
972 SAFE_SIGNAL(SIGUSR1, SIG_DFL);
973 SAFE_SIGNAL(SIGINT, SIG_DFL);
Cyril Hrubis0f053c82016-06-07 14:29:39 +0200974 SAFE_SETPGID(0, 0);
Cyril Hrubis4aebb6c2016-06-07 13:40:41 +0200975 testrun();
Cyril Hrubis0f053c82016-06-07 14:29:39 +0200976 }
Cyril Hrubis4aebb6c2016-06-07 13:40:41 +0200977
978 SAFE_WAITPID(test_pid, &status, 0);
Cyril Hrubis4aebb6c2016-06-07 13:40:41 +0200979 alarm(0);
Cyril Hrubisa41e9942016-08-04 16:31:06 +0200980 SAFE_SIGNAL(SIGINT, SIG_DFL);
Cyril Hrubis4aebb6c2016-06-07 13:40:41 +0200981
Cyril Hrubis4aebb6c2016-06-07 13:40:41 +0200982 if (WIFEXITED(status) && WEXITSTATUS(status))
Cyril Hrubisfa495172016-06-08 16:06:35 +0200983 do_exit(WEXITSTATUS(status));
Cyril Hrubis4aebb6c2016-06-07 13:40:41 +0200984
985 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGKILL) {
986 tst_res(TINFO, "If you are running on slow machine, "
987 "try exporting LTP_TIMEOUT_MUL > 1");
988 tst_brk(TBROK, "Test killed! (timeout?)");
989 }
990
991 if (WIFSIGNALED(status))
992 tst_brk(TBROK, "Test killed by %s!", tst_strsig(WTERMSIG(status)));
993
Cyril Hrubisfa495172016-06-08 16:06:35 +0200994 do_exit(0);
Cyril Hrubisbbdb9f72016-03-16 15:53:57 +0100995}