Home | History | Annotate | Download | only in mq_notify
      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 /* Porting from Crackerjack to LTP is done by		                      */
      7 /*         Manas Kumar Nayak maknayak (at) in.ibm.com>			      */
      8 /*								              */
      9 /* This program is free software;  you can redistribute it and/or modify      */
     10 /* it under the terms of the GNU General Public License as published by       */
     11 /* the Free Software Foundation; either version 2 of the License, or	      */
     12 /* (at your option) any later version.					      */
     13 /*									      */
     14 /* This program is distributed in the hope that it will be useful,	      */
     15 /* but WITHOUT ANY WARRANTY;  without even the implied warranty of	      */
     16 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See		      */
     17 /* the GNU General Public License for more details.			      */
     18 /*									      */
     19 /* You should have received a copy of the GNU General Public License	      */
     20 /* along with this program;  if not, write to the Free Software Foundation,   */
     21 /* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA           */
     22 /*									      */
     23 /******************************************************************************/
     24 /******************************************************************************/
     25 /*									      */
     26 /* Description: This tests the mq_notify() syscall			      */
     27 /*									      */
     28 /******************************************************************************/
     29 #define _XOPEN_SOURCE 600
     30 #include <sys/syscall.h>
     31 #include <sys/types.h>
     32 #include <sys/stat.h>
     33 #include <sys/uio.h>
     34 #include <getopt.h>
     35 #include <libgen.h>
     36 #include <limits.h>
     37 #include <errno.h>
     38 #include <stdio.h>
     39 #include <unistd.h>
     40 #include <string.h>
     41 #include <mqueue.h>
     42 #include <signal.h>
     43 #include <stdlib.h>
     44 #include <fcntl.h>
     45 
     46 #include "../utils/include_j_h.h"
     47 
     48 #include "test.h"
     49 #include "linux_syscall_numbers.h"
     50 
     51 char *TCID = "mq_notify01";
     52 int testno;
     53 int TST_TOTAL = 1;
     54 
     55 static void cleanup(void)
     56 {
     57 	tst_rmdir();
     58 }
     59 
     60 static void setup(void)
     61 {
     62 	TEST_PAUSE;
     63 	tst_tmpdir();
     64 }
     65 
     66 #define SYSCALL_NAME    "mq_notify"
     67 
     68 static int opt_debug;
     69 static char *progname;
     70 static int notified;
     71 static int cmp_ok;
     72 
     73 enum test_type {
     74 	NORMAL,
     75 	FD_NONE,
     76 	FD_NOT_EXIST,
     77 	FD_FILE,
     78 	ALREADY_REGISTERED,
     79 };
     80 
     81 struct test_case {
     82 	int notify;
     83 	int ttype;
     84 	int ret;
     85 	int err;
     86 };
     87 
     88 #define MAX_MSGSIZE     8192
     89 #define MSG_SIZE	16
     90 #define USER_DATA       0x12345678
     91 
     92 static struct test_case tcase[] = {
     93 	{			// case00
     94 	 .ttype = NORMAL,
     95 	 .notify = SIGEV_NONE,
     96 	 .ret = 0,
     97 	 .err = 0,
     98 	 },
     99 	{			// case01
    100 	 .ttype = NORMAL,
    101 	 .notify = SIGEV_SIGNAL,
    102 	 .ret = 0,
    103 	 .err = 0,
    104 	 },
    105 	{			// case02
    106 	 .ttype = NORMAL,
    107 	 .notify = SIGEV_THREAD,
    108 	 .ret = 0,
    109 	 .err = 0,
    110 	 },
    111 	{			// case03
    112 	 .ttype = FD_NONE,
    113 	 .notify = SIGEV_NONE,
    114 	 .ret = -1,
    115 	 .err = EBADF,
    116 	 },
    117 	{			// case04
    118 	 .ttype = FD_NOT_EXIST,
    119 	 .notify = SIGEV_NONE,
    120 	 .ret = -1,
    121 	 .err = EBADF,
    122 	 },
    123 	{			// case05
    124 	 .ttype = FD_FILE,
    125 	 .notify = SIGEV_NONE,
    126 	 .ret = -1,
    127 	 .err = EBADF,
    128 	 },
    129 	{			// case06
    130 	 .ttype = ALREADY_REGISTERED,
    131 	 .notify = SIGEV_NONE,
    132 	 .ret = -1,
    133 	 .err = EBUSY,
    134 	 },
    135 };
    136 
    137 static void sigfunc(int signo, siginfo_t * info, void *data)
    138 {
    139 	if (opt_debug) {
    140 		tst_resm(TINFO, "si_code  E:%d,\tR:%d", info->si_code,
    141 			 SI_MESGQ);
    142 		tst_resm(TINFO, "si_signo E:%d,\tR:%d", info->si_signo,
    143 			 SIGUSR1);
    144 		tst_resm(TINFO, "si_value E:0x%x,\tR:0x%x",
    145 			 info->si_value.sival_int, USER_DATA);
    146 		tst_resm(TINFO, "si_pid   E:%d,\tR:%d", info->si_pid, getpid());
    147 		tst_resm(TINFO, "si_uid   E:%d,\tR:%d", info->si_uid, getuid());
    148 	}
    149 	cmp_ok = info->si_code == SI_MESGQ &&
    150 	    info->si_signo == SIGUSR1 &&
    151 	    info->si_value.sival_int == USER_DATA &&
    152 	    info->si_pid == getpid() && info->si_uid == getuid();
    153 	notified = 1;
    154 }
    155 
    156 static void tfunc(union sigval sv)
    157 {
    158 	cmp_ok = sv.sival_int == USER_DATA;
    159 	notified = 1;
    160 }
    161 
    162 static int do_test(struct test_case *tc)
    163 {
    164 	int sys_ret;
    165 	int sys_errno;
    166 	int result = RESULT_OK;
    167 	int rc, i, fd = -1;
    168 	struct sigevent ev;
    169 	struct sigaction sigact;
    170 	struct timespec abs_timeout;
    171 	char smsg[MAX_MSGSIZE];
    172 
    173 	notified = cmp_ok = 1;
    174 
    175 	/* Don't timeout. */
    176 	abs_timeout.tv_sec = 0;
    177 	abs_timeout.tv_nsec = 0;
    178 
    179 	/*
    180 	 * When test ended with SIGTERM etc, mq discriptor is left remains.
    181 	 * So we delete it first.
    182 	 */
    183 	mq_unlink(QUEUE_NAME);
    184 
    185 	switch (tc->ttype) {
    186 	case FD_NOT_EXIST:
    187 		fd = INT_MAX - 1;
    188 		/* fallthrough */
    189 	case FD_NONE:
    190 		break;
    191 	case FD_FILE:
    192 		TEST(fd = open("/", O_RDONLY));
    193 		if (TEST_RETURN < 0) {
    194 			tst_resm(TFAIL, "can't open \"/\".");
    195 			result = 1;
    196 			goto EXIT;
    197 		}
    198 		break;
    199 	default:
    200 		/*
    201 		 * Open message queue
    202 		 */
    203 		TEST(fd =
    204 		     mq_open(QUEUE_NAME, O_CREAT | O_EXCL | O_RDWR, S_IRWXU,
    205 			     NULL));
    206 		if (TEST_RETURN < 0) {
    207 			tst_resm(TFAIL | TTERRNO, "mq_open failed");
    208 			result = 1;
    209 			goto EXIT;
    210 		}
    211 	}
    212 
    213 	/*
    214 	 * Set up struct sigevent
    215 	 */
    216 	ev.sigev_notify = tc->notify;
    217 
    218 	switch (tc->notify) {
    219 	case SIGEV_SIGNAL:
    220 		notified = cmp_ok = 0;
    221 		ev.sigev_signo = SIGUSR1;
    222 		ev.sigev_value.sival_int = USER_DATA;
    223 
    224 		memset(&sigact, 0, sizeof(sigact));
    225 		sigact.sa_sigaction = sigfunc;
    226 		sigact.sa_flags = SA_SIGINFO;
    227 		TEST(rc = sigaction(SIGUSR1, &sigact, NULL));
    228 		break;
    229 	case SIGEV_THREAD:
    230 		notified = cmp_ok = 0;
    231 		ev.sigev_notify_function = tfunc;
    232 		ev.sigev_notify_attributes = NULL;
    233 		ev.sigev_value.sival_int = USER_DATA;
    234 		break;
    235 	}
    236 
    237 	if (tc->ttype == ALREADY_REGISTERED) {
    238 		TEST(rc = mq_notify(fd, &ev));
    239 		if (TEST_RETURN < 0) {
    240 			tst_resm(TFAIL | TTERRNO, "mq_notify failed");
    241 			result = 1;
    242 			goto EXIT;
    243 		}
    244 	}
    245 
    246 	/*
    247 	 * Execute system call
    248 	 */
    249 	errno = 0;
    250 	sys_ret = mq_notify(fd, &ev);
    251 	sys_errno = errno;
    252 	if (sys_ret < 0)
    253 		goto TEST_END;
    254 
    255 	/*
    256 	 * Prepare send message
    257 	 */
    258 	for (i = 0; i < MSG_SIZE; i++)
    259 		smsg[i] = i;
    260 	TEST(rc = mq_timedsend(fd, smsg, MSG_SIZE, 0, &abs_timeout));
    261 	if (rc < 0) {
    262 		tst_resm(TFAIL | TTERRNO, "mq_timedsend failed");
    263 		result = 1;
    264 		goto EXIT;
    265 	}
    266 
    267 	while (!notified)
    268 		usleep(10000);
    269 
    270 TEST_END:
    271 	/*
    272 	 * Check results
    273 	 */
    274 	result |= (sys_ret != 0 && sys_errno != tc->err) || !cmp_ok;
    275 	PRINT_RESULT_CMP(sys_ret >= 0, tc->ret, tc->err, sys_ret, sys_errno,
    276 			 cmp_ok);
    277 
    278 EXIT:
    279 	if (fd >= 0) {
    280 		close(fd);
    281 		mq_unlink(QUEUE_NAME);
    282 	}
    283 
    284 	return result;
    285 }
    286 
    287 static void usage(const char *progname)
    288 {
    289 	tst_resm(TINFO, "usage: %s [options]", progname);
    290 	tst_resm(TINFO, "This is a regression test program of %s system call.",
    291 		 SYSCALL_NAME);
    292 	tst_resm(TINFO, "options:");
    293 	tst_resm(TINFO, "    -d --debug	   Show debug messages");
    294 	tst_resm(TINFO, "    -h --help	    Show this message");
    295 }
    296 
    297 int main(int ac, char **av)
    298 {
    299 	int result = RESULT_OK;
    300 	int c;
    301 	int i;
    302 	int lc;
    303 
    304 	struct option long_options[] = {
    305 		{"debug", no_argument, 0, 'd'},
    306 		{"help", no_argument, 0, 'h'},
    307 		{NULL, 0, NULL, 0}
    308 	};
    309 
    310 	progname = basename(av[0]);
    311 
    312 	tst_parse_opts(ac, av, NULL, NULL);
    313 
    314 	setup();
    315 
    316 	for (lc = 0; TEST_LOOPING(lc); ++lc) {
    317 		tst_count = 0;
    318 		for (testno = 0; testno < TST_TOTAL; ++testno) {
    319 			TEST(c = getopt_long(ac, av, "dh", long_options, NULL));
    320 			while (TEST_RETURN != -1) {
    321 				switch (c) {
    322 				case 'd':
    323 					opt_debug = 1;
    324 					break;
    325 				default:
    326 					usage(progname);
    327 				}
    328 			}
    329 
    330 			if (ac != optind) {
    331 				tst_resm(TINFO, "Options are not match.");
    332 				usage(progname);
    333 			}
    334 
    335 			for (i = 0; i < (int)(sizeof(tcase) / sizeof(tcase[0]));
    336 			     i++) {
    337 				int ret;
    338 				tst_resm(TINFO, "(case%02d) START", i);
    339 				ret = do_test(&tcase[i]);
    340 				tst_resm(TINFO, "(case%02d) END => %s",
    341 					 i, (ret == 0) ? "OK" : "NG");
    342 				result |= ret;
    343 			}
    344 
    345 			switch (result) {
    346 			case RESULT_OK:
    347 				tst_resm(TPASS, "mq_notify call succeeded");
    348 				break;
    349 
    350 			default:
    351 				tst_brkm(TFAIL, cleanup, "mq_notify failed");
    352 				break;
    353 			}
    354 
    355 		}
    356 	}
    357 	cleanup();
    358 	tst_exit();
    359 }
    360