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