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