1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) Crackerjack Project., 2007-2008, Hitachi, Ltd
4 * Copyright (c) 2017 Petr Vorel <pvorel@suse.cz>
5 *
6 * Authors:
7 * Takahiro Yasui <takahiro.yasui.mp@hitachi.com>,
8 * Yumiko Sugita <yumiko.sugita.yf@hitachi.com>,
9 * Satoshi Fujiwara <sa-fuji@sdl.hitachi.co.jp>
10 */
11
12 #include <errno.h>
13 #include <limits.h>
14
15 static int fd, fd_root, fd_nonblock, fd_maxint = INT_MAX - 1, fd_invalid = -1;
16
17 #include "mq_timed.h"
18
19 static struct tst_ts ts;
20 static void *bad_addr;
21
22 static struct test_case tcase[] = {
23 {
24 .fd = &fd,
25 },
26 {
27 .fd = &fd,
28 .len = 1,
29 },
30 {
31 .fd = &fd,
32 .len = MAX_MSGSIZE,
33 },
34 {
35 .fd = &fd,
36 .len = 1,
37 .prio = MQ_PRIO_MAX - 1,
38 },
39 {
40 .fd = &fd,
41 .len = MAX_MSGSIZE + 1,
42 .ret = -1,
43 .err = EMSGSIZE,
44 },
45 {
46 .fd = &fd_invalid,
47 .ret = -1,
48 .err = EBADF,
49 },
50 {
51 .fd = &fd_maxint,
52 .ret = -1,
53 .err = EBADF,
54 },
55 {
56 .fd = &fd_root,
57 .ret = -1,
58 .err = EBADF,
59 },
60 {
61 .fd = &fd_nonblock,
62 .len = 16,
63 .ret = -1,
64 .err = EAGAIN,
65 },
66 {
67 .fd = &fd,
68 .len = 1,
69 .prio = MQ_PRIO_MAX,
70 .ret = -1,
71 .err = EINVAL,
72 },
73 {
74 .fd = &fd,
75 .len = 16,
76 .tv_sec = -1,
77 .rq = &ts,
78 .send = 1,
79 .ret = -1,
80 .err = EINVAL,
81 },
82 {
83 .fd = &fd,
84 .len = 16,
85 .tv_nsec = -1,
86 .rq = &ts,
87 .send = 1,
88 .ret = -1,
89 .err = EINVAL,
90 },
91 {
92 .fd = &fd,
93 .len = 16,
94 .tv_nsec = 1000000000,
95 .rq = &ts,
96 .send = 1,
97 .ret = -1,
98 .err = EINVAL,
99 },
100 {
101 .fd = &fd,
102 .len = 16,
103 .rq = &ts,
104 .send = 1,
105 .timeout = 1,
106 .ret = -1,
107 .err = ETIMEDOUT,
108 },
109 {
110 .fd = &fd,
111 .len = 16,
112 .send = 1,
113 .signal = 1,
114 .rq = &ts,
115 .ret = -1,
116 .err = EINTR,
117 },
118 {
119 .fd = &fd,
120 .len = 16,
121 .bad_msg_addr = 1,
122 .ret = -1,
123 .err = EFAULT,
124 },
125 {
126 .fd = &fd,
127 .len = 16,
128 .bad_ts_addr = 1,
129 .ret = -1,
130 .err = EFAULT,
131 }
132 };
133
setup(void)134 static void setup(void)
135 {
136 struct time64_variants *tv = &variants[tst_variant];
137
138 tst_res(TINFO, "Testing variant: %s", tv->desc);
139 ts.type = tv->ts_type;
140
141 bad_addr = tst_get_bad_addr(cleanup_common);
142
143 setup_common();
144 }
145
verify_mqt_send_receive(unsigned int i,pid_t pid)146 static void verify_mqt_send_receive(unsigned int i, pid_t pid)
147 {
148 struct time64_variants *tv = &variants[tst_variant];
149 const struct test_case *tc = &tcase[i];
150 unsigned int j;
151 unsigned int prio;
152 char rmsg[MAX_MSGSIZE];
153 void *msg_ptr, *abs_timeout;
154
155 if (tc->bad_msg_addr)
156 msg_ptr = bad_addr;
157 else
158 msg_ptr = smsg;
159
160 if (tc->bad_ts_addr)
161 abs_timeout = bad_addr;
162 else
163 abs_timeout = tst_ts_get(tc->rq);
164
165 TEST(tv->mqt_send(*tc->fd, msg_ptr, tc->len, tc->prio, abs_timeout));
166
167 if (pid > 0)
168 kill_pid(pid);
169
170 if (TST_RET < 0) {
171 if (tc->err != TST_ERR)
172 tst_res(TFAIL | TTERRNO,
173 "mq_timedsend() failed unexpectedly, expected %s",
174 tst_strerrno(tc->err));
175 else
176 tst_res(TPASS | TTERRNO, "mq_timedsend() failed expectedly");
177
178 if (*tc->fd == fd)
179 cleanup_queue(fd);
180
181 return;
182 }
183
184 TEST(tv->mqt_receive(*tc->fd, rmsg, MAX_MSGSIZE, &prio, tst_ts_get(tc->rq)));
185
186 if (*tc->fd == fd)
187 cleanup_queue(fd);
188
189 if (TST_RET < 0) {
190 if (tc->err != TST_ERR) {
191 tst_res(TFAIL | TTERRNO,
192 "mq_timedreceive() failed unexpectedly, expected %s",
193 tst_strerrno(tc->err));
194 return;
195 }
196
197 if (tc->ret >= 0) {
198 tst_res(TFAIL | TTERRNO, "mq_timedreceive() returned %ld, expected %d",
199 TST_RET, tc->ret);
200 return;
201 }
202 }
203
204 if ((long)tc->len != TST_RET) {
205 tst_res(TFAIL, "mq_timedreceive() wrong length %ld, expected %u",
206 TST_RET, tc->len);
207 return;
208 }
209
210 if (tc->prio != prio) {
211 tst_res(TFAIL, "mq_timedreceive() wrong prio %d, expected %d",
212 prio, tc->prio);
213 return;
214 }
215
216 for (j = 0; j < tc->len; j++) {
217 if (rmsg[j] != smsg[j]) {
218 tst_res(TFAIL,
219 "mq_timedreceive() wrong data %d in %u, expected %d",
220 rmsg[j], i, smsg[j]);
221 return;
222 }
223 }
224
225 tst_res(TPASS, "mq_timedreceive() returned %ld, priority %u, length: %i",
226 TST_RET, prio, MAX_MSGSIZE);
227 }
228
test_bad_addr(unsigned int i)229 static void test_bad_addr(unsigned int i)
230 {
231 struct time64_variants *tv = &variants[tst_variant];
232 pid_t pid;
233 int status;
234
235 pid = SAFE_FORK();
236 if (!pid) {
237 verify_mqt_send_receive(i, pid);
238 _exit(0);
239 }
240
241 SAFE_WAITPID(pid, &status, 0);
242
243 if (WIFEXITED(status) && !WEXITSTATUS(status))
244 return;
245
246 if (tv->ts_type == TST_LIBC_TIMESPEC &&
247 WIFSIGNALED(status) && WTERMSIG(status) == SIGSEGV) {
248 tst_res(TPASS, "Child killed by expected signal");
249 return;
250 }
251
252 tst_res(TFAIL, "Child %s", tst_strstatus(status));
253 }
254
do_test(unsigned int i)255 static void do_test(unsigned int i)
256 {
257 struct time64_variants *tv = &variants[tst_variant];
258 const struct test_case *tc = &tcase[i];
259 unsigned int j;
260 pid_t pid = -1;
261
262 tst_ts_set_sec(&ts, tc->tv_sec);
263 tst_ts_set_nsec(&ts, tc->tv_nsec);
264
265 if (tc->bad_ts_addr || tc->bad_msg_addr) {
266 test_bad_addr(i);
267 return;
268 }
269
270 if (tc->signal)
271 pid = set_sig(tc->rq, tv->clock_gettime);
272
273 if (tc->timeout)
274 set_timeout(tc->rq, tv->clock_gettime);
275
276 if (tc->send) {
277 for (j = 0; j < MSG_LENGTH; j++)
278 if (tv->mqt_send(*tc->fd, smsg, tc->len, tc->prio, NULL) < 0) {
279 tst_res(TFAIL | TTERRNO, "mq_timedsend() failed");
280 return;
281 }
282 }
283
284 verify_mqt_send_receive(i, pid);
285 }
286
287 static struct tst_test test = {
288 .tcnt = ARRAY_SIZE(tcase),
289 .test = do_test,
290 .test_variants = ARRAY_SIZE(variants),
291 .setup = setup,
292 .cleanup = cleanup_common,
293 .forks_child = 1,
294 };
295