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/* Porting from Crackerjack to LTP is done by */ 7/* Manas Kumar Nayak maknayak@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 51char *TCID = "mq_notify01"; 52int testno; 53int TST_TOTAL = 1; 54 55static void cleanup(void) 56{ 57 tst_rmdir(); 58} 59 60static void setup(void) 61{ 62 TEST_PAUSE; 63 tst_tmpdir(); 64} 65 66#define SYSCALL_NAME "mq_notify" 67 68static int opt_debug; 69static char *progname; 70static int notified; 71static int cmp_ok; 72 73enum test_type { 74 NORMAL, 75 FD_NONE, 76 FD_NOT_EXIST, 77 FD_FILE, 78 ALREADY_REGISTERED, 79}; 80 81struct 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 92static 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 137static 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 156static void tfunc(union sigval sv) 157{ 158 cmp_ok = sv.sival_int == USER_DATA; 159 notified = 1; 160} 161 162static 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 270TEST_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 278EXIT: 279 if (fd >= 0) { 280 close(fd); 281 mq_unlink(QUEUE_NAME); 282 } 283 284 return result; 285} 286 287static 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 297int 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