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
69char *TCID = "mq_timedsend01";
70int testno;
71int TST_TOTAL = 1;
72struct sigaction act;
73
74/*
75 * sighandler()
76 */
77void 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/******************************************************************************/
102void 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/******************************************************************************/
126void 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
144enum 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 */
156struct 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
183static 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
297static 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	}
413TEST_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
421EXIT:
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
438int 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