1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) Crackerjack Project., 2007-2008 ,Hitachi, Ltd
4 * Author(s): Takahiro Yasui <takahiro.yasui.mp@hitachi.com>,
5 * Yumiko Sugita <yumiko.sugita.yf@hitachi.com>,
6 * Satoshi Fujiwara <sa-fuji@sdl.hitachi.co.jp>
7 * Copyright (c) 2016 Linux Test Project
8 */
9 /*
10 * test status of errors on man page
11 * EINTR v (function was interrupted by a signal)
12 * EINVAL v (invalid tv_nsec, etc.)
13 * ENOTSUP v (sleep not supported against the specified clock_id)
14 * EFAULT v (Invalid request pointer)
15 * EFAULT V (Invalid remain pointer when interrupted by a signal)
16 */
17
18 #include <limits.h>
19
20 #include "time64_variants.h"
21 #include "tst_safe_clocks.h"
22 #include "tst_sig_proc.h"
23 #include "tst_timer.h"
24
sighandler(int sig LTP_ATTRIBUTE_UNUSED)25 static void sighandler(int sig LTP_ATTRIBUTE_UNUSED)
26 {
27 }
28
29 enum test_type {
30 NORMAL,
31 SEND_SIGINT,
32 BAD_TS_ADDR_REQ,
33 BAD_TS_ADDR_REM,
34 };
35
36 #define TYPE_NAME(x) .ttype = x, .desc = #x
37
38 static void *bad_addr;
39
40 struct test_case {
41 clockid_t clk_id; /* clock_* clock type parameter */
42 int ttype; /* test type (enum) */
43 const char *desc; /* test description (name) */
44 int flags; /* clock_nanosleep flags parameter */
45 long tv_sec;
46 long tv_nsec;
47 int exp_ret;
48 int exp_err;
49 };
50
51 static struct test_case tcase[] = {
52 {
53 TYPE_NAME(NORMAL),
54 .clk_id = CLOCK_REALTIME,
55 .flags = 0,
56 .tv_sec = 0,
57 .tv_nsec = -1,
58 .exp_ret = -1,
59 .exp_err = EINVAL,
60 },
61 {
62 TYPE_NAME(NORMAL),
63 .clk_id = CLOCK_REALTIME,
64 .flags = 0,
65 .tv_sec = 0,
66 .tv_nsec = 1000000000,
67 .exp_ret = -1,
68 .exp_err = EINVAL,
69 },
70 {
71 TYPE_NAME(NORMAL),
72 .clk_id = CLOCK_THREAD_CPUTIME_ID,
73 .flags = 0,
74 .tv_sec = 0,
75 .tv_nsec = 500000000,
76 .exp_ret = -1,
77 .exp_err = ENOTSUP,
78 },
79 {
80 TYPE_NAME(SEND_SIGINT),
81 .clk_id = CLOCK_REALTIME,
82 .flags = 0,
83 .tv_sec = 10,
84 .tv_nsec = 0,
85 .exp_ret = -1,
86 .exp_err = EINTR,
87 },
88 {
89 TYPE_NAME(BAD_TS_ADDR_REQ),
90 .clk_id = CLOCK_REALTIME,
91 .flags = 0,
92 .exp_ret = -1,
93 .exp_err = EFAULT,
94 },
95 {
96 TYPE_NAME(BAD_TS_ADDR_REM),
97 .clk_id = CLOCK_REALTIME,
98 .flags = 0,
99 .tv_sec = 10,
100 .tv_nsec = 0,
101 .exp_ret = -1,
102 .exp_err = EFAULT,
103 },
104 };
105
106 static struct tst_ts *rq;
107 static struct tst_ts *rm;
108
109 static struct time64_variants variants[] = {
110 { .clock_nanosleep = libc_clock_nanosleep, .ts_type = TST_LIBC_TIMESPEC, .desc = "vDSO or syscall with libc spec"},
111
112 #if (__NR_clock_nanosleep != __LTP__NR_INVALID_SYSCALL)
113 { .clock_nanosleep = sys_clock_nanosleep, .ts_type = TST_KERN_OLD_TIMESPEC, .desc = "syscall with old kernel spec"},
114 #endif
115
116 #if (__NR_clock_nanosleep_time64 != __LTP__NR_INVALID_SYSCALL)
117 { .clock_nanosleep = sys_clock_nanosleep64, .ts_type = TST_KERN_TIMESPEC, .desc = "syscall time64 with kernel spec"},
118 #endif
119 };
120
setup(void)121 void setup(void)
122 {
123 rq->type = variants[tst_variant].ts_type;
124 tst_res(TINFO, "Testing variant: %s", variants[tst_variant].desc);
125 SAFE_SIGNAL(SIGINT, sighandler);
126 bad_addr = tst_get_bad_addr(NULL);
127 }
128
do_test(unsigned int i)129 static void do_test(unsigned int i)
130 {
131 struct time64_variants *tv = &variants[tst_variant];
132 struct test_case *tc = &tcase[i];
133 pid_t pid = 0;
134 void *request, *remain;
135
136 memset(rm, 0, sizeof(*rm));
137 rm->type = rq->type;
138
139 tst_res(TINFO, "case %s", tc->desc);
140
141 if (tc->ttype == SEND_SIGINT || tc->ttype == BAD_TS_ADDR_REM)
142 pid = create_sig_proc(SIGINT, 40, 500000);
143
144 tst_ts_set_sec(rq, tc->tv_sec);
145 tst_ts_set_nsec(rq, tc->tv_nsec);
146
147 if (tc->ttype == BAD_TS_ADDR_REQ)
148 request = bad_addr;
149 else
150 request = tst_ts_get(rq);
151
152 if (tc->ttype == BAD_TS_ADDR_REM)
153 remain = bad_addr;
154 else
155 remain = tst_ts_get(rm);
156
157 TEST(tv->clock_nanosleep(tc->clk_id, tc->flags, request, remain));
158
159 if (tv->clock_nanosleep == libc_clock_nanosleep) {
160 /*
161 * The return value and error number are differently set for
162 * libc syscall as compared to kernel syscall.
163 */
164 if (TST_RET) {
165 TST_ERR = TST_RET;
166 TST_RET = -1;
167 }
168
169 /*
170 * nsleep isn't implemented by kernelf or
171 * CLOCK_THREAD_CPUTIME_ID and it returns ENOTSUP, but libc
172 * changes that error value to EINVAL.
173 */
174 if (tc->clk_id == CLOCK_THREAD_CPUTIME_ID)
175 tc->exp_err = EINVAL;
176 }
177
178 if (pid) {
179 SAFE_KILL(pid, SIGTERM);
180 SAFE_WAIT(NULL);
181 }
182
183 if (tc->ttype == SEND_SIGINT) {
184 long long expect_ms = tst_ts_to_ms(*rq);
185 long long remain_ms = tst_ts_to_ms(*rm);
186
187 if (tst_ts_valid(rm)) {
188 tst_res(TFAIL | TTERRNO,
189 "The clock_nanosleep() haven't updated"
190 " timespec or it's not valid");
191 return;
192 }
193
194 if (remain_ms > expect_ms) {
195 tst_res(TFAIL| TTERRNO,
196 "remaining time > requested time (%lld > %lld)",
197 remain_ms, expect_ms);
198 return;
199 }
200
201 tst_res(TPASS, "Timespec updated correctly");
202 }
203
204 if ((TST_RET != tc->exp_ret) || (TST_ERR != tc->exp_err)) {
205 tst_res(TFAIL | TTERRNO, "returned %ld, expected %d,"
206 " expected errno: %s (%d)", TST_RET,
207 tc->exp_ret, tst_strerrno(tc->exp_err), tc->exp_err);
208 return;
209 }
210
211 tst_res(TPASS | TTERRNO, "clock_nanosleep() failed with");
212 }
213
214 static struct tst_test test = {
215 .tcnt = ARRAY_SIZE(tcase),
216 .test = do_test,
217 .test_variants = ARRAY_SIZE(variants),
218 .setup = setup,
219 .forks_child = 1,
220 .bufs = (struct tst_buffers []) {
221 {&rq, .size = sizeof(*rq)},
222 {&rm, .size = sizeof(*rm)},
223 {},
224 }
225 };
226