Home | History | Annotate | Download | only in mq_open
      1 /******************************************************************************/
      2 /* Copyright (c) Crackerjack Project., 2007-2008 ,Hitachi, Ltd		*/
      3 /*	  Author(s): Takahiro Yasui <takahiro.yasui.mp (at) hitachi.com>,	      */
      4 /*		       Yumiko Sugita <yumiko.sugita.yf (at) hitachi.com>, 	      */
      5 /*		       Satoshi Fujiwara <sa-fuji (at) 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_open01.c						   */
     25 /*									    */
     26 /* Description: This tests the mq_open() syscall			      */
     27 /*									      */
     28 /* 									      */
     29 /*									      */
     30 /*									      */
     31 /*									      */
     32 /*									    */
     33 /* Usage:  <for command-line>						 */
     34 /* mq_open01 [-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_open01						     */
     45 /* History:     Porting from Crackerjack to LTP is done by		    */
     46 /*	      Manas Kumar Nayak maknayak (at) in.ibm.com>			*/
     47 /******************************************************************************/
     48 #include <sys/syscall.h>
     49 #include <sys/types.h>
     50 #include <sys/stat.h>
     51 #include <sys/uio.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 <limits.h>
     60 
     61 #include "../utils/include_j_h.h"
     62 #include "../utils/common_j_h.c"
     63 
     64 #include "test.h"
     65 #include "linux_syscall_numbers.h"
     66 
     67 char *TCID = "mq_open01";
     68 int testno;
     69 int TST_TOTAL = 1;
     70 
     71 /* Extern Global Functions */
     72 /******************************************************************************/
     73 /*									    */
     74 /* Function:    cleanup						       */
     75 /*									    */
     76 /* Description: Performs all one time clean up for this test on successful    */
     77 /*	      completion,  premature exit or  failure. Closes all temporary */
     78 /*	      files, removes all temporary directories exits the test with  */
     79 /*	      appropriate return code by calling tst_exit() function.       */
     80 /*									    */
     81 /* Input:       None.							 */
     82 /*									    */
     83 /* Output:      None.							 */
     84 /*									    */
     85 /* Return:      On failure - Exits calling tst_exit(). Non '0' return code.   */
     86 /*	      On success - Exits calling tst_exit(). With '0' return code.  */
     87 /*									    */
     88 /******************************************************************************/
     89 void cleanup(void)
     90 {
     91 
     92 	tst_rmdir();
     93 }
     94 
     95 /* Local  Functions */
     96 /******************************************************************************/
     97 /*									    */
     98 /* Function:    setup							 */
     99 /*									    */
    100 /* Description: Performs all one time setup for this test. This function is   */
    101 /*	      typically used to capture signals, create temporary dirs      */
    102 /*	      and temporary files that may be used in the course of this    */
    103 /*	      test.							 */
    104 /*									    */
    105 /* Input:       None.							 */
    106 /*									    */
    107 /* Output:      None.							 */
    108 /*									    */
    109 /* Return:      On failure - Exits by calling cleanup().		      */
    110 /*	      On success - returns 0.				       */
    111 /*									    */
    112 /******************************************************************************/
    113 void setup(void)
    114 {
    115 	tst_require_root();
    116 
    117 	/* Capture signals if any */
    118 	/* Create temporary directories */
    119 	TEST_PAUSE;
    120 	tst_tmpdir();
    121 }
    122 
    123 /*
    124  * Macros
    125  */
    126 #define SYSCALL_NAME    "mq_open"
    127 
    128 enum test_type {
    129 	NORMAL,
    130 	NO_FILE,
    131 	NO_SPACE,
    132 };
    133 
    134 /*
    135  * Data Structure
    136  */
    137 struct test_case {
    138 	int ttype;
    139 	char *user;
    140 	char *qname;
    141 	int oflag;
    142 	long mq_maxmsg;		// Maximum numebr of messages.
    143 	long mq_msgsize;	// Maximum message size.
    144 	int ret;
    145 	int err;
    146 };
    147 
    148 #define ULIMIT_FNUM     0
    149 #define PROC_MAX_QUEUES "/proc/sys/fs/mqueue/queues_max"
    150 
    151 /* Test cases
    152  *
    153  *   test status of errors on man page
    154  *
    155  *   EACCES	     v (permission is denied)
    156  *   EEXIST	     v (named message queue already exists)
    157  *   EINTR	      --- (interrupted by a signal)
    158  *   EINVAL	     v (not supported for the given name, or invalid
    159  *			 arguments)
    160  *   EMFILE	     v (process file table overflow)
    161  *   ENAMETOOLONG       v (too long name length)
    162  *   ENFILE	     can't check because it's difficult to create no-fd
    163  *   ENOENT	     v (O_CREAT is not set and the named message queue
    164  *			 does not exist)
    165  *   ENOSPC	     v (no space for the new message queue)
    166  */
    167 
    168 static struct test_case tcase[] = {
    169 #if 1
    170 	{			// case00
    171 	 .ttype = NORMAL,
    172 	 .qname = QUEUE_NAME,
    173 	 .oflag = O_CREAT,
    174 	 .mq_maxmsg = 20,
    175 	 .mq_msgsize = 16384,
    176 	 .ret = 0,
    177 	 .err = 0,
    178 	 },
    179 #else
    180 	{			// case00
    181 	 .ttype = NORMAL,
    182 	 .qname = QUEUE_NAME,
    183 	 .oflag = O_CREAT,
    184 	 .ret = 0,
    185 	 .err = 0,
    186 	 },
    187 	{			// case01
    188 	 .ttype = NORMAL,
    189 	 //  0    1       2       3
    190 	 //  0123456789012345678901234567890123456789
    191 	 "aaaaaaaaaaaaaaa",
    192 	 .oflag = O_CREAT,
    193 	 .ret = 0,
    194 	 .err = 0,
    195 	 },
    196 	{			// case02
    197 	 .ttype = NORMAL,
    198 	 //  0    1       2       3
    199 	 //  0123456789012345678901234567890123456789
    200 	 "aaaaaaaaaaaaaaaa",
    201 	 .oflag = O_CREAT,
    202 	 .ret = -1,
    203 	 .err = ENAMETOOLONG,
    204 	 },
    205 
    206 	{			// case03
    207 	 .ttype = NORMAL,
    208 	 .qname = "",
    209 	 .oflag = O_CREAT,
    210 	 .ret = -1,
    211 	 .err = EINVAL,
    212 	 },
    213 	{			// case04
    214 	 .ttype = NORMAL,
    215 	 .user = "nobody",
    216 	 .qname = QUEUE_NAME,
    217 	 .ret = -1,
    218 	 .err = EACCES,
    219 	 },
    220 	{			// case05
    221 	 .ttype = NORMAL,
    222 	 .qname = QUEUE_NAME,
    223 	 .oflag = O_CREAT | O_EXCL,
    224 	 .ret = -1,
    225 	 .err = EEXIST,
    226 	 },
    227 	{			// case06
    228 	 .ttype = NO_FILE,
    229 	 .qname = QUEUE_NAME,
    230 	 .oflag = O_CREAT,
    231 	 .ret = -1,
    232 	 .err = EMFILE,
    233 	 },
    234 	{			// case07
    235 	 .ttype = NORMAL,
    236 	 .qname = "/notexist",
    237 	 .oflag = 0,
    238 	 .ret = -1,
    239 	 .err = ENOENT,
    240 	 },
    241 
    242 	{			// case08
    243 	 .ttype = NO_SPACE,
    244 	 .user = "nobody",
    245 	 .qname = QUEUE_NAME,
    246 	 .oflag = O_CREAT,
    247 	 .ret = -1,
    248 	 .err = ENOSPC,
    249 	 },
    250 #endif
    251 };
    252 
    253 /*
    254  * do_test()
    255  *
    256  *   Input  : TestCase Data
    257  *   Return : RESULT_OK(0), RESULT_NG(1)
    258  *
    259  */
    260 
    261 static int do_test(struct test_case *tc)
    262 {
    263 	int sys_ret;
    264 	int sys_errno;
    265 	int result = RESULT_OK;
    266 	int rc, fd1 = -1, fd2 = -1, cmp_ok = 1;
    267 	uid_t old_uid = -1;
    268 	rlim_t oldlim = -1;
    269 	int oldval = -1;
    270 	struct mq_attr new, old, *p_attr;
    271 
    272 	/*
    273 	 * When test ended with SIGTERM etc, mq discriptor is left remains.
    274 	 * So we delete it first.
    275 	 */
    276 	TEST(mq_unlink(QUEUE_NAME));
    277 
    278 	/*
    279 	 * Execute system call
    280 	 */
    281 
    282 	if (tc->ttype != NO_SPACE && !(tc->oflag & O_CREAT)) {
    283 		errno = 0;
    284 		TEST(sys_ret =
    285 		     mq_open(QUEUE_NAME, O_CREAT | O_EXCL | O_RDWR, S_IRWXU,
    286 			     NULL));
    287 		sys_errno = errno;
    288 		if (sys_ret < 0)
    289 			goto TEST_END;
    290 		fd1 = sys_ret;
    291 	}
    292 	if (tc->ttype == NO_FILE) {
    293 		TEST(rc = setup_ulimit_fnum(ULIMIT_FNUM, &oldlim));
    294 		if (rc < 0) {
    295 			result = 1;
    296 			goto EXIT;
    297 		}
    298 	}
    299 
    300 	/*
    301 	 * Change /proc/sys/fs/mqueue/queues_max
    302 	 */
    303 	if (tc->ttype == NO_SPACE) {
    304 		TEST(rc = setup_proc_fs(PROC_MAX_QUEUES, 0, &oldval));
    305 		if (rc < 0) {
    306 			result = 1;
    307 			goto EXIT;
    308 		}
    309 	}
    310 
    311 	/*
    312 	 * Change effective user id
    313 	 */
    314 	if (tc->user != NULL) {
    315 		TEST(rc = setup_euid(tc->user, &old_uid));
    316 		if (rc < 0) {
    317 			result = 1;
    318 			goto EXIT;
    319 		}
    320 	}
    321 
    322 	/*
    323 	 * Execute system call
    324 	 */
    325 	//tst_resm(TINFO,"PATH_MAX: %d\n", PATH_MAX);
    326 	//tst_resm(TINFO,"NAME_MAX: %d", NAME_MAX);
    327 	p_attr = NULL;
    328 	if (tc->mq_maxmsg || tc->mq_msgsize) {
    329 		new.mq_maxmsg = tc->mq_maxmsg;
    330 		new.mq_msgsize = tc->mq_msgsize;
    331 		p_attr = &new;
    332 	}
    333 	errno = 0;
    334 	if (tc->oflag & O_CREAT)
    335 		TEST(sys_ret = mq_open(tc->qname, tc->oflag, S_IRWXU, p_attr));
    336 	else
    337 		TEST(sys_ret = mq_open(tc->qname, tc->oflag));
    338 	sys_errno = errno;
    339 	if (sys_ret < 0)
    340 		goto TEST_END;
    341 	fd2 = sys_ret;
    342 
    343 	if (p_attr) {
    344 		TEST(rc = ltp_syscall(__NR_mq_getsetattr, fd2, NULL, &old));
    345 		if (TEST_RETURN < 0) {
    346 			tst_resm(TFAIL,
    347 				 "mq_getsetattr failed - errno = %d : %s",
    348 				 TEST_ERRNO, strerror(TEST_ERRNO));
    349 			result = 1;
    350 			goto EXIT;
    351 		}
    352 		tst_resm(TINFO, "mq_maxmsg E:%ld,\tR:%ld", new.mq_maxmsg,
    353 			 old.mq_maxmsg);
    354 		tst_resm(TINFO, "mq_msgsize E:%ld,\tR:%ld", new.mq_msgsize,
    355 			 old.mq_msgsize);
    356 		cmp_ok = old.mq_maxmsg == new.mq_maxmsg
    357 		    && old.mq_msgsize == new.mq_msgsize;
    358 	}
    359 
    360 TEST_END:
    361 	/*
    362 	 * Check results
    363 	 */
    364 	result |= (sys_errno != tc->err) || !cmp_ok;
    365 	PRINT_RESULT_CMP(sys_ret >= 0, tc->ret, tc->err, sys_ret, sys_errno,
    366 			 cmp_ok);
    367 
    368 EXIT:
    369 	if (tc->user != NULL && old_uid != -1)
    370 		TEST(cleanup_euid(old_uid));
    371 
    372 	if (tc->ttype == NO_SPACE && oldval != -1)
    373 		TEST(cleanup_proc_fs(PROC_MAX_QUEUES, oldval));
    374 
    375 	if (tc->ttype == NO_FILE && oldlim != -1)
    376 		TEST(cleanup_ulimit_fnum(oldlim));
    377 	if (fd1 >= 0)
    378 		TEST(close(fd1));
    379 	if (fd2 >= 0)
    380 		TEST(close(fd2));
    381 	if (fd1 >= 0)
    382 		TEST(mq_unlink(QUEUE_NAME));
    383 	if (fd2 >= 0 && strcmp(tc->qname, QUEUE_NAME) != 0)
    384 		TEST(mq_unlink(tc->qname));
    385 
    386 	return result;
    387 }
    388 
    389 /*
    390  * main()
    391  */
    392 
    393 int main(int ac, char **av)
    394 {
    395 	int result = RESULT_OK;
    396 	int i;
    397 	int lc;
    398 
    399 	tst_parse_opts(ac, av, NULL, NULL);
    400 
    401 	setup();
    402 
    403 	for (lc = 0; TEST_LOOPING(lc); ++lc) {
    404 		tst_count = 0;
    405 		for (testno = 0; testno < TST_TOTAL; ++testno) {
    406 
    407 			/*
    408 			 * Execute test
    409 			 */
    410 			for (i = 0; i < (int)ARRAY_SIZE(tcase); i++) {
    411 				int ret;
    412 				tst_resm(TINFO, "(case%02d) START", i);
    413 				ret = do_test(&tcase[i]);
    414 				tst_resm(TINFO, "(case%02d) END => %s", i,
    415 					 (ret == 0) ? "OK" : "NG");
    416 				result |= ret;
    417 			}
    418 
    419 			/*
    420 			 * Check results
    421 			 */
    422 			switch (result) {
    423 			case RESULT_OK:
    424 				tst_resm(TPASS, "mq_open call succeeded ");
    425 				break;
    426 
    427 			default:
    428 				tst_brkm(TFAIL | TTERRNO, cleanup,
    429 					 "mq_open failed");
    430 				break;
    431 			}
    432 
    433 		}
    434 	}
    435 	cleanup();
    436 	tst_exit();
    437 }
    438