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