1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
2f08c3bdfSopenharmony_ci/*
3f08c3bdfSopenharmony_ci * Copyright (c) 2014 Fujitsu Ltd.
4f08c3bdfSopenharmony_ci * Author: Zeng Linggang <zenglg.jy@cn.fujitsu.com>
5f08c3bdfSopenharmony_ci *
6f08c3bdfSopenharmony_ci * DESCRIPTION
7f08c3bdfSopenharmony_ci *  Verify that,
8f08c3bdfSopenharmony_ci *   1. fd is not a valid file descriptor, EBADF would return.
9f08c3bdfSopenharmony_ci *   2. old_value is not valid a pointer, EFAULT would return.
10f08c3bdfSopenharmony_ci *   3. fd is not a valid timerfd file descriptor, EINVAL would return.
11f08c3bdfSopenharmony_ci *   4. flags is invalid, EINVAL would return.
12f08c3bdfSopenharmony_ci */
13f08c3bdfSopenharmony_ci
14f08c3bdfSopenharmony_ci#define _GNU_SOURCE
15f08c3bdfSopenharmony_ci
16f08c3bdfSopenharmony_ci#include "time64_variants.h"
17f08c3bdfSopenharmony_ci#include "tst_timer.h"
18f08c3bdfSopenharmony_ci#include "lapi/timerfd.h"
19f08c3bdfSopenharmony_ci
20f08c3bdfSopenharmony_cistatic int bad_clockfd = -1;
21f08c3bdfSopenharmony_cistatic int clockfd;
22f08c3bdfSopenharmony_cistatic int fd;
23f08c3bdfSopenharmony_cistatic void *bad_addr;
24f08c3bdfSopenharmony_ci
25f08c3bdfSopenharmony_cistatic struct test_case_t {
26f08c3bdfSopenharmony_ci	int *fd;
27f08c3bdfSopenharmony_ci	int flags;
28f08c3bdfSopenharmony_ci	struct tst_its *old_value;
29f08c3bdfSopenharmony_ci	int exp_errno;
30f08c3bdfSopenharmony_ci} test_cases[] = {
31f08c3bdfSopenharmony_ci	{&bad_clockfd, 0, NULL, EBADF},
32f08c3bdfSopenharmony_ci	{&clockfd, 0, NULL, EFAULT},
33f08c3bdfSopenharmony_ci	{&fd, 0, NULL, EINVAL},
34f08c3bdfSopenharmony_ci	{&clockfd, -1, NULL, EINVAL},
35f08c3bdfSopenharmony_ci};
36f08c3bdfSopenharmony_ci
37f08c3bdfSopenharmony_cistatic struct tst_its new_value;
38f08c3bdfSopenharmony_ci
39f08c3bdfSopenharmony_cistatic struct time64_variants variants[] = {
40f08c3bdfSopenharmony_ci#if (__NR_timerfd_settime != __LTP__NR_INVALID_SYSCALL)
41f08c3bdfSopenharmony_ci	{ .tfd_settime = sys_timerfd_settime, .ts_type = TST_KERN_OLD_TIMESPEC, .desc = "syscall with old kernel spec"},
42f08c3bdfSopenharmony_ci#endif
43f08c3bdfSopenharmony_ci
44f08c3bdfSopenharmony_ci#if (__NR_timerfd_settime64 != __LTP__NR_INVALID_SYSCALL)
45f08c3bdfSopenharmony_ci	{ .tfd_settime = sys_timerfd_settime64, .ts_type = TST_KERN_TIMESPEC, .desc = "syscall time64 with kernel spec"},
46f08c3bdfSopenharmony_ci#endif
47f08c3bdfSopenharmony_ci};
48f08c3bdfSopenharmony_ci
49f08c3bdfSopenharmony_cistatic void setup(void)
50f08c3bdfSopenharmony_ci{
51f08c3bdfSopenharmony_ci	struct time64_variants *tv = &variants[tst_variant];
52f08c3bdfSopenharmony_ci
53f08c3bdfSopenharmony_ci	tst_res(TINFO, "Testing variant: %s", tv->desc);
54f08c3bdfSopenharmony_ci	bad_addr = tst_get_bad_addr(NULL);
55f08c3bdfSopenharmony_ci	new_value.type = tv->ts_type;
56f08c3bdfSopenharmony_ci
57f08c3bdfSopenharmony_ci	clockfd = timerfd_create(CLOCK_REALTIME, 0);
58f08c3bdfSopenharmony_ci	if (clockfd == -1) {
59f08c3bdfSopenharmony_ci		tst_brk(TFAIL | TERRNO, "timerfd_create() fail");
60f08c3bdfSopenharmony_ci		return;
61f08c3bdfSopenharmony_ci	}
62f08c3bdfSopenharmony_ci
63f08c3bdfSopenharmony_ci	fd = SAFE_OPEN("test_file", O_RDWR | O_CREAT, 0644);
64f08c3bdfSopenharmony_ci}
65f08c3bdfSopenharmony_ci
66f08c3bdfSopenharmony_cistatic void cleanup(void)
67f08c3bdfSopenharmony_ci{
68f08c3bdfSopenharmony_ci	if (clockfd > 0)
69f08c3bdfSopenharmony_ci		close(clockfd);
70f08c3bdfSopenharmony_ci
71f08c3bdfSopenharmony_ci	if (fd > 0)
72f08c3bdfSopenharmony_ci		close(fd);
73f08c3bdfSopenharmony_ci}
74f08c3bdfSopenharmony_ci
75f08c3bdfSopenharmony_cistatic void run(unsigned int n)
76f08c3bdfSopenharmony_ci{
77f08c3bdfSopenharmony_ci	struct time64_variants *tv = &variants[tst_variant];
78f08c3bdfSopenharmony_ci	struct test_case_t *test = &test_cases[n];
79f08c3bdfSopenharmony_ci	void *its;
80f08c3bdfSopenharmony_ci
81f08c3bdfSopenharmony_ci	if (test->exp_errno == EFAULT)
82f08c3bdfSopenharmony_ci		its = bad_addr;
83f08c3bdfSopenharmony_ci	else
84f08c3bdfSopenharmony_ci		its = tst_its_get(test->old_value);
85f08c3bdfSopenharmony_ci
86f08c3bdfSopenharmony_ci	TEST(tv->tfd_settime(*test->fd, test->flags, tst_its_get(&new_value),
87f08c3bdfSopenharmony_ci			     its));
88f08c3bdfSopenharmony_ci
89f08c3bdfSopenharmony_ci	if (TST_RET != -1) {
90f08c3bdfSopenharmony_ci		tst_res(TFAIL, "timerfd_settime() succeeded unexpectedly");
91f08c3bdfSopenharmony_ci		return;
92f08c3bdfSopenharmony_ci	}
93f08c3bdfSopenharmony_ci
94f08c3bdfSopenharmony_ci	if (TST_ERR == test->exp_errno) {
95f08c3bdfSopenharmony_ci		tst_res(TPASS | TTERRNO,
96f08c3bdfSopenharmony_ci			"timerfd_settime() failed as expected");
97f08c3bdfSopenharmony_ci	} else {
98f08c3bdfSopenharmony_ci		tst_res(TFAIL | TTERRNO,
99f08c3bdfSopenharmony_ci			"timerfd_settime() failed unexpectedly; expected: "
100f08c3bdfSopenharmony_ci			"%d - %s", test->exp_errno, strerror(test->exp_errno));
101f08c3bdfSopenharmony_ci	}
102f08c3bdfSopenharmony_ci}
103f08c3bdfSopenharmony_ci
104f08c3bdfSopenharmony_cistatic struct tst_test test = {
105f08c3bdfSopenharmony_ci	.test = run,
106f08c3bdfSopenharmony_ci	.tcnt = ARRAY_SIZE(test_cases),
107f08c3bdfSopenharmony_ci	.test_variants = ARRAY_SIZE(variants),
108f08c3bdfSopenharmony_ci	.setup = setup,
109f08c3bdfSopenharmony_ci	.cleanup = cleanup,
110f08c3bdfSopenharmony_ci	.needs_tmpdir = 1,
111f08c3bdfSopenharmony_ci};
112