1 /******************************************************************************/
2 /* Copyright (c) Crackerjack Project., 2007-2008 ,Hitachi, Ltd */
3 /* Author(s): Takahiro Yasui <takahiro.yasui.mp@hitachi.com>, */
4 /* Yumiko Sugita <yumiko.sugita.yf@hitachi.com>, */
5 /* Satoshi Fujiwara <sa-fuji@sdl.hitachi.co.jp> */
6 /* */
7 /* This program is free software; you can redistribute it and/or modify */
8 /* it under the terms of the GNU General Public License as published by */
9 /* the Free Software Foundation; either version 2 of the License, or */
10 /* (at your option) any later version. */
11 /* */
12 /* This program is distributed in the hope that it will be useful, */
13 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
14 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See */
15 /* the GNU General Public License for more details. */
16 /* */
17 /* You should have received a copy of the GNU General Public License */
18 /* along with this program; if not, write to the Free Software */
19 /* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
20 /* */
21 /******************************************************************************/
22 /******************************************************************************/
23 /* */
24 /* File: mq_timedreceive01.c */
25 /* */
26 /* Description: This tests the mq_timedreceive() syscall */
27 /* */
28 /* */
29 /* */
30 /* */
31 /* */
32 /* */
33 /* Usage: <for command-line> */
34 /* mq_timedreceive01 [-c n] [-e][-i n] [-I x] [-p x] [-t] */
35 /* where, -c n : Run n copies concurrently. */
36 /* -e : Turn on errno logging. */
37 /* -i n : Execute test n times. */
38 /* -I x : Execute test for x seconds. */
39 /* -P x : Pause for x seconds between iterations. */
40 /* -t : Turn on syscall timing. */
41 /* */
42 /* Total Tests: 1 */
43 /* */
44 /* Test Name: mq_timedreceive01 */
45 /* History: Porting from Crackerjack to LTP is done by */
46 /* Manas Kumar Nayak maknayak@in.ibm.com> */
47 /******************************************************************************/
48 #define _XOPEN_SOURCE 600
49 #include <sys/syscall.h>
50 #include <sys/types.h>
51 #include <sys/stat.h>
52 #include <sys/wait.h>
53 #include <getopt.h>
54 #include <libgen.h>
55 #include <stdlib.h>
56 #include <errno.h>
57 #include <stdio.h>
58 #include <unistd.h>
59 #include <string.h>
60 #include <mqueue.h>
61 #include <time.h>
62 #include <signal.h>
63 #include <limits.h>
64
65 #include "../utils/include_j_h.h"
66 #include "../utils/common_j_h.c"
67
68 #include "test.h"
69 #include "linux_syscall_numbers.h"
70
71 char *TCID = "mq_timedreceive01";
72 int testno;
73 int TST_TOTAL = 1;
74 struct sigaction act;
75
76 /*
77 * sighandler()
78 */
sighandler(int sig)79 void sighandler(int sig)
80 {
81 if (sig == SIGINT)
82 return;
83
84 return;
85 }
86
87 /* Extern Global Functions */
88 /******************************************************************************/
89 /* */
90 /* Function: cleanup */
91 /* */
92 /* Description: Performs all one time clean up for this test on successful */
93 /* completion, premature exit or failure. Closes all temporary */
94 /* files, removes all temporary directories exits the test with */
95 /* appropriate return code by calling tst_exit() function. */
96 /* */
97 /* Input: None. */
98 /* */
99 /* Output: None. */
100 /* */
101 /* Return: On failure - Exits calling tst_exit(). Non '0' return code. */
102 /* On success - Exits calling tst_exit(). With '0' return code. */
103 /* */
104 /******************************************************************************/
cleanup(void)105 void cleanup(void)
106 {
107
108 tst_rmdir();
109
110 }
111
112 /* Local Functions */
113 /******************************************************************************/
114 /* */
115 /* Function: setup */
116 /* */
117 /* Description: Performs all one time setup for this test. This function is */
118 /* typically used to capture signals, create temporary dirs */
119 /* and temporary files that may be used in the course of this */
120 /* test. */
121 /* */
122 /* Input: None. */
123 /* */
124 /* Output: None. */
125 /* */
126 /* Return: On failure - Exits by calling cleanup(). */
127 /* On success - returns 0. */
128 /* */
129 /******************************************************************************/
setup(void)130 void setup(void)
131 {
132 /* Capture signals if any */
133 act.sa_handler = sighandler;
134 sigfillset(&act.sa_mask);
135 sigaction(SIGINT, &act, NULL);
136 /* Create temporary directories */
137 TEST_PAUSE;
138 tst_tmpdir();
139 }
140
141 /*
142 * Macros
143 */
144 #define SYSCALL_NAME "mq_timedreceive"
145
146 enum test_type {
147 NORMAL,
148 FD_NONE,
149 FD_NOT_EXIST,
150 FD_FILE,
151 INVALID_MSG_LEN,
152 EMPTY_QUEUE,
153 SEND_SIGINT,
154 };
155
156 /*
157 * Data Structure
158 */
159 struct test_case {
160 int ttype;
161 int non_block;
162 int len;
163 unsigned prio;
164 time_t sec;
165 long nsec;
166 int ret;
167 int err;
168 };
169
170 #define MAX_MSG 10
171 #define MAX_MSGSIZE 8192
172
173 /* Test cases
174 *
175 * test status of errors on man page
176 *
177 * EAGAIN v (would block)
178 * EBADF v (not a valid descriptor)
179 * EINTR v (interrupted by a signal)
180 * EINVAL v (invalid timeout value)
181 * ETIMEDOUT v (not block and timeout occured)
182 * EMSGSIZE v ('msg_len' is less than the message size of the queue)
183 * EBADMSG can't check because this error never occur
184 */
185 static struct test_case tcase[] = {
186 { // case00
187 .ttype = NORMAL,
188 .len = 0, // also success when size equals zero
189 .ret = 0,
190 .err = 0,
191 },
192 { // case01
193 .ttype = NORMAL,
194 .len = 1,
195 .ret = 0,
196 .err = 0,
197 },
198 { // case02
199 .ttype = NORMAL,
200 .len = MAX_MSGSIZE,
201 .ret = 0,
202 .err = 0,
203 },
204 { // case03
205 .ttype = NORMAL,
206 .len = 1,
207 .prio = 32767, // max priority
208 .ret = 0,
209 .err = 0,
210 },
211 { // case04
212 .ttype = INVALID_MSG_LEN,
213 .len = 0,
214 .ret = -1,
215 .err = EMSGSIZE,
216 },
217 { // case05
218 .ttype = FD_NONE,
219 .len = 0,
220 .ret = -1,
221 .err = EBADF,
222 },
223 { // case06
224 .ttype = FD_NOT_EXIST,
225 .len = 0,
226 .ret = -1,
227 .err = EBADF,
228 },
229 { // case07
230 .ttype = FD_FILE,
231 .len = 0,
232 .ret = -1,
233 .err = EBADF,
234 },
235 { // case08
236 .ttype = EMPTY_QUEUE,
237 .non_block = 1,
238 .len = 16,
239 .ret = -1,
240 .err = EAGAIN,
241 },
242 { // case09
243 .ttype = EMPTY_QUEUE,
244 .len = 16,
245 .sec = -1,
246 .nsec = 0,
247 .ret = -1,
248 .err = EINVAL,
249 },
250 { // case10
251 .ttype = EMPTY_QUEUE,
252 .len = 16,
253 .sec = 0,
254 .nsec = -1,
255 .ret = -1,
256 .err = EINVAL,
257 },
258 { // case11
259 .ttype = EMPTY_QUEUE,
260 .len = 16,
261 .sec = 0,
262 .nsec = 1000000000,
263 .ret = -1,
264 .err = EINVAL,
265 },
266 { // case12
267 .ttype = EMPTY_QUEUE,
268 .len = 16,
269 .sec = 0,
270 .nsec = 999999999,
271 .ret = -1,
272 .err = ETIMEDOUT,
273 },
274 { // case13
275 .ttype = SEND_SIGINT,
276 .len = 16,
277 .sec = 3,
278 .nsec = 0,
279 .ret = -1,
280 .err = EINTR,
281 },
282 };
283
284 #define MEM_LENGTH (4 * 1024 * 1024)
285 /*
286 * do_test()
287 *
288 * Input : TestCase Data
289 * Return : RESULT_OK(0), RESULT_NG(1)
290 *
291 */
292
do_test(struct test_case * tc)293 static int do_test(struct test_case *tc)
294 {
295 int sys_ret;
296 int sys_errno;
297 int result = RESULT_OK;
298 int oflag;
299 int i, rc, cmp_ok = 1, fd = -1;
300 char smsg[MAX_MSGSIZE], rmsg[MAX_MSGSIZE];
301 struct timespec ts = { 0, 0 };
302 pid_t pid = 0;
303 unsigned prio;
304 size_t msg_len;
305
306 /*
307 * When test ended with SIGTERM etc, mq discriptor is left remains.
308 * So we delete it first.
309 */
310 TEST(mq_unlink(QUEUE_NAME));
311
312 switch (tc->ttype) {
313 case FD_NOT_EXIST:
314 fd = INT_MAX - 1;
315 /* fallthrough */
316 case FD_NONE:
317 break;
318 case FD_FILE:
319 TEST(fd = open("/", O_RDONLY));
320 if (TEST_RETURN < 0) {
321 tst_resm(TFAIL | TTERRNO, "can't open \"/\".");
322 result = 1;
323 goto EXIT;
324 }
325 break;
326 default:
327 /*
328 * Open message queue
329 */
330 oflag = O_CREAT | O_EXCL | O_RDWR;
331 if (tc->non_block)
332 oflag |= O_NONBLOCK;
333
334 TEST(fd = mq_open(QUEUE_NAME, oflag, S_IRWXU, NULL));
335 if (TEST_RETURN < 0) {
336 tst_resm(TFAIL | TTERRNO, "mq_open failed");
337 result = 1;
338 goto EXIT;
339 }
340
341 if (tc->ttype == SEND_SIGINT) {
342 pid = create_sig_proc(200000, SIGINT, UINT_MAX);
343 if (pid < 0) {
344 result = 1;
345 goto EXIT;
346 }
347 }
348 break;
349 }
350
351 /*
352 * Prepare send message
353 */
354 for (i = 0; i < tc->len; i++)
355 smsg[i] = i;
356
357 /*
358 * Send message
359 */
360 switch (tc->ttype) {
361 case EMPTY_QUEUE:
362 case SEND_SIGINT:
363 case FD_NONE:
364 case FD_NOT_EXIST:
365 case FD_FILE:
366 break;
367 default:
368 TEST(rc = mq_timedsend(fd, smsg, tc->len, tc->prio, &ts));
369 if (TEST_RETURN < 0) {
370 tst_resm(TFAIL | TTERRNO, "mq_timedsend failed");
371 result = 1;
372 goto EXIT;
373 }
374 break;
375 }
376
377 /*
378 * Set the message length and timeout value
379 */
380 msg_len = MAX_MSGSIZE;
381 if (tc->ttype == INVALID_MSG_LEN)
382 msg_len -= 1;
383 ts.tv_sec = tc->sec;
384 ts.tv_nsec = tc->nsec;
385 if (tc->sec >= 0 || tc->nsec != 0)
386 ts.tv_sec += time(NULL);
387
388 /*
389 * Execute system call
390 */
391 errno = 0;
392 TEST(sys_ret = mq_timedreceive(fd, rmsg, msg_len, &prio, &ts));
393 sys_errno = errno;
394 if (sys_ret < 0)
395 goto TEST_END;
396
397 /*
398 * Compare received message
399 */
400 if (sys_ret != tc->len || tc->prio != prio)
401 cmp_ok = 0;
402 else {
403 for (i = 0; i < tc->len; i++)
404 if (rmsg[i] != smsg[i]) {
405 cmp_ok = 0;
406 break;
407 }
408 }
409
410 TEST_END:
411 /*
412 * Check results
413 */
414 result |= (sys_errno != tc->err) || !cmp_ok;
415 PRINT_RESULT_CMP(0, tc->ret == 0 ? tc->len : tc->ret, tc->err, sys_ret,
416 sys_errno, cmp_ok);
417
418 EXIT:
419 if (fd >= 0) {
420 TEST(close(fd));
421 TEST(mq_unlink(QUEUE_NAME));
422 }
423 if (pid > 0) {
424 int st;
425 TEST(kill(pid, SIGTERM));
426 TEST(wait(&st));
427 }
428 return result;
429 }
430
431 /*
432 * main()
433 */
434
main(int ac,char ** av)435 int main(int ac, char **av)
436 {
437 int result = RESULT_OK;
438 int i;
439 int lc;
440
441 tst_parse_opts(ac, av, NULL, NULL);
442
443 setup();
444
445 for (lc = 0; TEST_LOOPING(lc); ++lc) {
446 tst_count = 0;
447 for (testno = 0; testno < TST_TOTAL; ++testno) {
448
449 /*
450 * Execute test
451 */
452 for (i = 0; i < (int)ARRAY_SIZE(tcase); i++) {
453 int ret;
454 tst_resm(TINFO, "(case%02d) START", i);
455 ret = do_test(&tcase[i]);
456 tst_resm(TINFO, "(case%02d) END => %s",
457 i, (ret == 0) ? "OK" : "NG");
458 result |= ret;
459 }
460
461 /*
462 * Check results
463 */
464 switch (result) {
465 case RESULT_OK:
466 tst_resm(TPASS,
467 "mq_timedreceive call succeeded");
468 break;
469
470 default:
471 tst_brkm(TFAIL | TTERRNO, cleanup,
472 "mq_timedreceive failed");
473 }
474 }
475 }
476 cleanup();
477 tst_exit();
478 }
479