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