1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) Crackerjack Project., 2007-2008, Hitachi, Ltd
4 * Copyright (c) 2017 Petr Vorel <pvorel@suse.cz>
5 *
6 * Authors:
7 * Takahiro Yasui <takahiro.yasui.mp@hitachi.com>,
8 * Yumiko Sugita <yumiko.sugita.yf@hitachi.com>,
9 * Satoshi Fujiwara <sa-fuji@sdl.hitachi.co.jp>
10 */
11
12 #include <limits.h>
13 #include <errno.h>
14
15 #include "tst_test.h"
16 #include "tst_safe_posix_ipc.h"
17
18 static int fd, fd_root, fd_nonblock, fd_maxint = INT_MAX - 1, fd_invalid = -1;
19
20 #include "mq.h"
21
22 #define USER_DATA 0x12345678
23
24 static char *str_debug;
25
26 static volatile sig_atomic_t notified, cmp_ok;
27 static siginfo_t info;
28
29 struct test_case {
30 int *fd;
31 int already_registered;
32 int notify;
33 int ret;
34 int err;
35 };
36
37 static struct test_case tcase[] = {
38 {
39 .fd = &fd,
40 .notify = SIGEV_NONE,
41 .ret = 0,
42 .err = 0,
43 },
44 {
45 .fd = &fd,
46 .notify = SIGEV_SIGNAL,
47 .ret = 0,
48 .err = 0,
49 },
50 {
51 .fd = &fd,
52 .notify = SIGEV_THREAD,
53 .ret = 0,
54 .err = 0,
55 },
56 {
57 .fd = &fd_invalid,
58 .notify = SIGEV_NONE,
59 .ret = -1,
60 .err = EBADF,
61 },
62 {
63 .fd = &fd_maxint,
64 .notify = SIGEV_NONE,
65 .ret = -1,
66 .err = EBADF,
67 },
68 {
69 .fd = &fd_root,
70 .notify = SIGEV_NONE,
71 .ret = -1,
72 .err = EBADF,
73 },
74 {
75 .fd = &fd,
76 .notify = SIGEV_NONE,
77 .already_registered = 1,
78 .ret = -1,
79 .err = EBUSY,
80 },
81 };
82
sigfunc(int signo LTP_ATTRIBUTE_UNUSED,siginfo_t * si,void * data LTP_ATTRIBUTE_UNUSED)83 static void sigfunc(int signo LTP_ATTRIBUTE_UNUSED, siginfo_t *si,
84 void *data LTP_ATTRIBUTE_UNUSED)
85 {
86 if (str_debug)
87 memcpy(&info, si, sizeof(info));
88
89 cmp_ok = si->si_code == SI_MESGQ &&
90 si->si_signo == SIGUSR1 &&
91 si->si_value.sival_int == USER_DATA &&
92 si->si_pid == getpid() && si->si_uid == getuid();
93 notified = 1;
94 }
95
tfunc(union sigval sv)96 static void tfunc(union sigval sv)
97 {
98 cmp_ok = sv.sival_int == USER_DATA;
99 notified = 1;
100 }
101
do_test(unsigned int i)102 static void do_test(unsigned int i)
103 {
104 struct sigaction sigact;
105 struct test_case *tc = &tcase[i];
106 struct sigevent ev;
107
108 ev.sigev_notify = tc->notify;
109 notified = cmp_ok = 1;
110
111 switch (tc->notify) {
112 case SIGEV_SIGNAL:
113 notified = cmp_ok = 0;
114 ev.sigev_signo = SIGUSR1;
115 ev.sigev_value.sival_int = USER_DATA;
116
117 memset(&sigact, 0, sizeof(sigact));
118 sigact.sa_sigaction = sigfunc;
119 sigact.sa_flags = SA_SIGINFO;
120 if (sigaction(SIGUSR1, &sigact, NULL) == -1) {
121 tst_res(TFAIL | TTERRNO, "sigaction failed");
122 return;
123 }
124 break;
125 case SIGEV_THREAD:
126 notified = cmp_ok = 0;
127 ev.sigev_notify_function = tfunc;
128 ev.sigev_notify_attributes = NULL;
129 ev.sigev_value.sival_int = USER_DATA;
130 break;
131 }
132
133 if (tc->already_registered && mq_notify(*tc->fd, &ev) == -1) {
134 tst_res(TFAIL | TERRNO, "mq_notify(%d, %p) failed", fd, &ev);
135 return;
136 }
137
138 TEST(mq_notify(*tc->fd, &ev));
139
140 if (TST_RET < 0) {
141 if (tc->err != TST_ERR)
142 tst_res(TFAIL | TTERRNO,
143 "mq_notify failed unexpectedly, expected %s",
144 tst_strerrno(tc->err));
145 else
146 tst_res(TPASS | TTERRNO, "mq_notify failed expectedly");
147
148 /* unregister notification */
149 if (*tc->fd == fd)
150 mq_notify(*tc->fd, NULL);
151
152 return;
153 }
154
155 TEST(mq_timedsend(*tc->fd, smsg, MSG_LENGTH, 0,
156 &((struct timespec){0})));
157
158 if (*tc->fd == fd)
159 cleanup_queue(fd);
160
161 if (TST_RET < 0) {
162 tst_res(TFAIL | TTERRNO, "mq_timedsend failed");
163 return;
164 }
165
166 while (!notified)
167 usleep(10000);
168
169 if (str_debug && tc->notify == SIGEV_SIGNAL) {
170 tst_res(TINFO, "si_code E:%d,\tR:%d",
171 info.si_code, SI_MESGQ);
172 tst_res(TINFO, "si_signo E:%d,\tR:%d",
173 info.si_signo, SIGUSR1);
174 tst_res(TINFO, "si_value E:0x%x,\tR:0x%x",
175 info.si_value.sival_int, USER_DATA);
176 tst_res(TINFO, "si_pid E:%d,\tR:%d",
177 info.si_pid, getpid());
178 tst_res(TINFO, "si_uid E:%d,\tR:%d",
179 info.si_uid, getuid());
180 }
181
182 if (TST_RET < 0) {
183 if (tc->err != TST_ERR)
184 tst_res(TFAIL | TTERRNO,
185 "mq_timedsend failed unexpectedly, expected %s",
186 tst_strerrno(tc->err));
187 else
188 tst_res(TPASS | TTERRNO, "mq_timedsend failed expectedly");
189 return;
190 }
191
192 if (tc->ret != TST_RET) {
193 tst_res(TFAIL, "mq_timedsend returned %ld, expected %d",
194 TST_RET, tc->ret);
195 return;
196 }
197
198 tst_res(TPASS, "mq_notify and mq_timedsend exited expectedly");
199 }
200
201 static struct tst_test test = {
202 .tcnt = ARRAY_SIZE(tcase),
203 .test = do_test,
204 .options = (struct tst_option[]) {
205 {"d", &str_debug, "Print debug messages"},
206 {}
207 },
208 .setup = setup_common,
209 .cleanup = cleanup_common,
210 };
211