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