mq_timedreceive01.c revision 45e285d46ab47b0ff76c88acb5ba97b0bd5f753d
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 <stdlib.h>
55#include <errno.h>
56#include <stdio.h>
57#include <unistd.h>
58#include <string.h>
59#include <mqueue.h>
60#include <time.h>
61#include <signal.h>
62#include <limits.h>
63
64
65#include "../utils/include_j_h.h"
66#include "../utils/common_j_h.c"
67
68/* Harness Specific Include Files. */
69#include "test.h"
70#include "usctest.h"
71#include "linux_syscall_numbers.h"
72
73/* Extern Global Variables */
74extern int Tst_count;           /* counter for tst_xxx routines.         */
75extern char *TESTDIR;           /* temporary dir created by tst_tmpdir() */
76
77/* Global Variables */
78char *TCID = "mq_timedreceive01";  /* Test program identifier.*/
79int  testno;
80int  TST_TOTAL = 1;                   /* total number of tests in this file.   */
81struct sigaction act;
82
83/*
84 * sighandler()
85 */
86void sighandler(int sig)
87{
88        if (sig == SIGINT)
89                return;
90        // NOTREACHED
91        return;
92}
93
94/* Extern Global Functions */
95/******************************************************************************/
96/*                                                                            */
97/* Function:    cleanup                                                       */
98/*                                                                            */
99/* Description: Performs all one time clean up for this test on successful    */
100/*              completion,  premature exit or  failure. Closes all temporary */
101/*              files, removes all temporary directories exits the test with  */
102/*              appropriate return code by calling tst_exit() function.       */
103/*                                                                            */
104/* Input:       None.                                                         */
105/*                                                                            */
106/* Output:      None.                                                         */
107/*                                                                            */
108/* Return:      On failure - Exits calling tst_exit(). Non '0' return code.   */
109/*              On success - Exits calling tst_exit(). With '0' return code.  */
110/*                                                                            */
111/******************************************************************************/
112extern void cleanup() {
113        /* Remove tmp dir and all files in it */
114        TEST_CLEANUP;
115        tst_rmdir();
116
117        /* Exit with appropriate return code. */
118        tst_exit();
119}
120
121
122/* Local  Functions */
123/******************************************************************************/
124/*                                                                            */
125/* Function:    setup                                                         */
126/*                                                                            */
127/* Description: Performs all one time setup for this test. This function is   */
128/*              typically used to capture signals, create temporary dirs      */
129/*              and temporary files that may be used in the course of this    */
130/*              test.                                                         */
131/*                                                                            */
132/* Input:       None.                                                         */
133/*                                                                            */
134/* Output:      None.                                                         */
135/*                                                                            */
136/* Return:      On failure - Exits by calling cleanup().                      */
137/*              On success - returns 0.                                       */
138/*                                                                            */
139/******************************************************************************/
140void setup() {
141	    /* Capture signals if any */
142        act.sa_handler = sighandler;
143        sigfillset(&act.sa_mask);
144        sigaction(SIGINT, &act, NULL);
145        /* Create temporary directories */
146        TEST_PAUSE;
147        tst_tmpdir();
148}
149
150
151/*
152 * Macros
153 */
154#define SYSCALL_NAME    "mq_timedreceive"
155
156
157/*
158 * Global variables
159 */
160static int opt_debug;
161static char *progname;
162
163enum test_type {
164	NORMAL,
165        FD_NONE,
166        FD_NOT_EXIST,
167        FD_FILE,
168        INVALID_MSG_LEN,
169        EMPTY_QUEUE,
170        SEND_SIGINT,
171};
172
173
174/*
175 * Data Structure
176 */
177struct test_case {
178	int ttype;
179        int non_block;
180        int len;
181        unsigned prio;
182        time_t sec;
183        long nsec;
184        int ret;
185        int err;
186};
187
188#define MAX_MSG         10
189#define MAX_MSGSIZE     8192
190
191/* Test cases
192 *
193 *   test status of errors on man page
194 *
195 *   EAGAIN             v (would block)
196 *   EBADF              v (not a valid descriptor)
197 *   EINTR              v (interrupted by a signal)
198 *   EINVAL             v (invalid timeout value)
199 *   ETIMEDOUT          v (not block and timeout occured)
200 *   EMSGSIZE           v ('msg_len' is less than the message size of the queue)
201 *   EBADMSG            can't check because this error never occur
202 */
203static struct test_case tcase[] = {
204        { // case00
205                .ttype          = NORMAL,
206                .len            = 0,    // also success when size equals zero
207                .ret            = 0,
208                .err            = 0,
209        },
210	{ // case01
211                .ttype          = NORMAL,
212                .len            = 1,
213                .ret            = 0,
214                .err            = 0,
215        },
216        { // case02
217                .ttype          = NORMAL,
218                .len            = MAX_MSGSIZE,
219                .ret            = 0,
220                .err            = 0,
221        },
222        { // case03
223                .ttype          = NORMAL,
224                .len            = 1,
225                .prio           = 32767, // max priority
226                .ret            = 0,
227                .err            = 0,
228        },
229	{ // case04
230                .ttype          = INVALID_MSG_LEN,
231                .len            = 0,
232                .ret            = -1,
233                .err            = EMSGSIZE,
234        },
235        { // case05
236                .ttype          = FD_NONE,
237                .len            = 0,
238                .ret            = -1,
239                .err            = EBADF,
240        },
241        { // case06
242                .ttype          = FD_NOT_EXIST,
243                .len            = 0,
244                .ret            = -1,
245                .err            = EBADF,
246        },
247        { // case07
248                .ttype          = FD_FILE,
249                .len            = 0,
250                .ret            = -1,
251                .err            = EBADF,
252        },
253        { // case08
254                .ttype          = EMPTY_QUEUE,
255                .non_block      = 1,
256                .len            = 16,
257                .ret            = -1,
258                .err            = EAGAIN,
259        },
260        { // case09
261                .ttype          = EMPTY_QUEUE,
262                .len            = 16,
263                .sec            = -1,
264                .nsec           = 0,
265                .ret            = -1,
266                .err            = EINVAL,
267        },
268	{ // case10
269                .ttype          = EMPTY_QUEUE,
270                .len            = 16,
271                .sec            = 0,
272                .nsec           = -1,
273                .ret            = -1,
274                .err            = EINVAL,
275        },
276        { // case11
277                .ttype          = EMPTY_QUEUE,
278                .len            = 16,
279                .sec            = 0,
280                .nsec           = 1000000000,
281                .ret            = -1,
282                .err            = EINVAL,
283        },
284        { // case12
285                .ttype          = EMPTY_QUEUE,
286                .len            = 16,
287                .sec            = 0,
288                .nsec           = 999999999,
289                .ret            = -1,
290                .err            = ETIMEDOUT,
291        },
292        { // case13
293                .ttype          = SEND_SIGINT,
294                .len            = 16,
295                .sec            = 3,
296                .nsec           = 0,
297                .ret            = -1,
298                .err            = EINTR,
299        },
300};
301
302
303
304
305#define MEM_LENGTH              (4 * 1024 * 1024)
306/*
307 * do_test()
308 *
309 *   Input  : TestCase Data
310 *   Return : RESULT_OK(0), RESULT_NG(1)
311 *
312 */
313
314static int do_test(struct test_case *tc)
315{
316        int sys_ret;
317        int sys_errno;
318        int result = RESULT_OK;
319        int oflag;
320        int i, rc, cmp_ok = 1, fd = -1;
321        char smsg[MAX_MSGSIZE], rmsg[MAX_MSGSIZE];
322        struct timespec ts = {0,0};
323        pid_t pid = 0;
324        unsigned prio;
325        size_t msg_len;
326
327	/*
328         * When test ended with SIGTERM etc, mq discriptor is left remains.
329         * So we delete it first.
330         */
331        TEST(mq_unlink(QUEUE_NAME));
332
333switch (tc->ttype) {
334        case FD_NOT_EXIST:
335                fd = INT_MAX - 1;
336                /* fallthrough */
337        case FD_NONE:
338                break;
339        case FD_FILE:
340                TEST(fd = open("/", O_RDONLY));
341                if (TEST_RETURN < 0) {
342                 	tst_resm(TFAIL, "can't open \"/\". - errno = %d : %s",TEST_ERRNO, strerror(TEST_ERRNO));
343                        result = 1;
344                        goto EXIT;
345                }
346                break;
347        default:
348                /*
349                 * Open message queue
350                 */
351                oflag = O_CREAT|O_EXCL|O_RDWR;
352                if (tc->non_block)
353                        oflag |= O_NONBLOCK;
354
355                TEST(fd = mq_open(QUEUE_NAME, oflag, S_IRWXU, NULL));
356                if (TEST_RETURN < 0) {
357                 	tst_resm(TFAIL, "mq_open failed - errno = %d : %s",TEST_ERRNO, strerror(TEST_ERRNO));
358                        result = 1;
359                        goto EXIT;
360                }
361
362		 if (tc->ttype == SEND_SIGINT) {
363                        pid = create_sig_proc(200000, SIGINT, UINT_MAX);
364                        if (pid < 0) {
365                                result = 1;
366                                goto EXIT;
367                        }
368                }
369                break;
370           }
371
372	/*
373         * Prepare send message
374         */
375        for (i = 0; i < tc->len; i++)
376                smsg[i] = i;
377
378        /*
379         * Send message
380         */
381        switch (tc->ttype) {
382        case EMPTY_QUEUE:
383        case SEND_SIGINT:
384        case FD_NONE:
385        case FD_NOT_EXIST:
386        case FD_FILE:
387                break;
388        default:
389                TEST(rc = mq_timedsend(fd, smsg, tc->len, tc->prio, &ts));
390                if (TEST_RETURN < 0) {
391                 	tst_resm(TFAIL, "mq_timedsend failed - errno = %d : %s",TEST_ERRNO, strerror(TEST_ERRNO));
392                        result = 1;
393                        goto EXIT;
394                }
395                break;
396        }
397
398        /*
399         * Set the message length and timeout value
400         */
401        msg_len = MAX_MSGSIZE;
402        if (tc->ttype == INVALID_MSG_LEN)
403                msg_len -= 1;
404        ts.tv_sec = tc->sec;
405        ts.tv_nsec = tc->nsec;
406        if (tc->sec >= 0 || tc->nsec != 0)
407                ts.tv_sec += time(NULL);
408
409	/*
410         * Execute system call
411         */
412        errno = 0;
413        TEST(sys_ret = mq_timedreceive(fd, rmsg, msg_len, &prio, &ts));
414        sys_errno = errno;
415        if (sys_ret < 0)
416                goto TEST_END;
417
418	 /*
419         * Compare received message
420         */
421        if (sys_ret != tc->len || tc->prio != prio)
422                cmp_ok = 0;
423        else {
424                for (i = 0; i < tc->len; i++)
425                        if (rmsg[i] != smsg[i]) {
426                                cmp_ok = 0;
427                                break;
428                        }
429        }
430
431
432	TEST_END:
433        /*
434         * Check results
435         */
436        result |= (sys_errno != tc->err) || !cmp_ok;
437        PRINT_RESULT_CMP(0, tc->ret == 0 ? tc->len : tc->ret, tc->err,sys_ret, sys_errno, cmp_ok);
438
439EXIT:
440        if (fd >= 0) {
441                TEST(close(fd));
442                TEST(mq_unlink(QUEUE_NAME));
443        }
444        if (pid > 0) {
445                int st;
446                TEST(kill(pid, SIGTERM));
447                TEST(wait(&st));
448        }
449        return result;
450}
451
452
453
454/*
455 * usage()
456 */
457
458static void usage(const char *progname)
459{
460        tst_resm(TINFO,"usage: %s [options]", progname);
461        tst_resm(TINFO,"This is a regression test program of %s system call.",SYSCALL_NAME);
462        tst_resm(TINFO,"options:");
463        tst_resm(TINFO,"    -d --debug           Show debug messages");
464        tst_resm(TINFO,"    -h --help            Show this message");
465        tst_resm(TINFO,"NG");
466        exit(1);
467}
468
469
470/*
471 * main()
472 */
473
474
475
476int main(int ac, char **av) {
477	int result = RESULT_OK;
478        int c;
479        int i;
480        int lc;                 /* loop counter */
481        char *msg;              /* message returned from parse_opts */
482
483	struct option long_options[] = {
484                { "debug", no_argument, 0, 'd' },
485                { "help",  no_argument, 0, 'h' },
486                { NULL, 0, NULL, 0 }
487        };
488
489	progname = strchr(av[0], '/');
490        progname = progname ? progname + 1 : av[0];
491
492        /* parse standard options */
493        if ((msg = parse_opts(ac, av, NULL, NULL)) != NULL){
494             tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
495             tst_exit();
496           }
497
498        setup();
499
500        /* Check looping state if -i option given */
501        for (lc = 0; TEST_LOOPING(lc); ++lc) {
502                Tst_count = 0;
503                for (testno = 0; testno < TST_TOTAL; ++testno) {
504			 TEST(c = getopt_long(ac, av, "dh", long_options, NULL));
505			 while(TEST_RETURN != -1) {
506		                switch (c) {
507                		case 'd':
508		                        opt_debug = 1;
509                		        break;
510		                default:
511                		        usage(progname);
512                        		// NOTREACHED
513                		}
514		        }
515
516
517		if (ac != optind) {
518        	        tst_resm(TINFO,"Options are not match.");
519                	usage(progname);
520                	// NOTREACHED
521	        }
522
523		/*
524		* Execute test
525         	*/
526	        for (i = 0; i < (int)(sizeof(tcase) / sizeof(tcase[0])); i++) {
527        	        int ret;
528	                tst_resm(TINFO,"(case%02d) START", i);
529	                ret = do_test(&tcase[i]);
530	                tst_resm(TINFO,"(case%02d) END => %s", i, (ret == 0) ? "OK" : "NG");
531	                result |= ret;
532        	}
533
534		/*
535        	 * Check results
536         	*/
537        	switch(result) {
538	        case RESULT_OK:
539        			tst_resm(TPASS, "mq_timedreceive call succeeded");
540		                break;
541
542	        default:
543                 	   	tst_resm(TFAIL, "%s failed - errno = %d : %s", TCID, TEST_ERRNO, strerror(TEST_ERRNO));
544        		        tst_resm(TINFO,"NG");
545				cleanup();
546				tst_exit();
547		                break;
548        	}
549
550                }
551        }
552        cleanup();
553	tst_exit();
554}
555
556