• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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