1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
2f08c3bdfSopenharmony_ci/*
3f08c3bdfSopenharmony_ci * Copyright (c) 2014-2020 Fujitsu Ltd.
4f08c3bdfSopenharmony_ci * Author: Xiaoguang Wang <wangxg.fnst@cn.fujitsu.com>
5f08c3bdfSopenharmony_ci * Author: Yang Xu <xuyang2018.jy@cn.fujitsu.com>
6f08c3bdfSopenharmony_ci *
7f08c3bdfSopenharmony_ci * Basic test for msgrcv(2) using MSG_EXCEPT, MSG_NOERROR, MSG_COPY and
8f08c3bdfSopenharmony_ci * different msg_typ(zero,positive,negative).
9f08c3bdfSopenharmony_ci *
10f08c3bdfSopenharmony_ci * * With MSG_EXCEPT flag any message type but the one passed to the function
11f08c3bdfSopenharmony_ci *   is received.
12f08c3bdfSopenharmony_ci *
13f08c3bdfSopenharmony_ci * * With MSG_NOERROR and buffer size less than message size only part of the
14f08c3bdfSopenharmony_ci *   buffer is received.
15f08c3bdfSopenharmony_ci *
16f08c3bdfSopenharmony_ci * * With MSG_COPY and IPC_NOWAIT flag read the msg but don't destroy it in
17f08c3bdfSopenharmony_ci *   msg queue.
18f08c3bdfSopenharmony_ci *
19f08c3bdfSopenharmony_ci * * With msgtyp is 0, then the first message in the queue is read.
20f08c3bdfSopenharmony_ci *
21f08c3bdfSopenharmony_ci * * With msgtyp is greater than 0, then the first message in the queue of type
22f08c3bdfSopenharmony_ci *   msgtyp is read.
23f08c3bdfSopenharmony_ci *
24f08c3bdfSopenharmony_ci * * With msgtyp is less than 0, then the first message in the queue with the
25f08c3bdfSopenharmony_ci *   lowest type less than or equal to absolute value of msgtyp is received.
26f08c3bdfSopenharmony_ci */
27f08c3bdfSopenharmony_ci
28f08c3bdfSopenharmony_ci#define  _GNU_SOURCE
29f08c3bdfSopenharmony_ci#include <sys/wait.h>
30f08c3bdfSopenharmony_ci#include "tst_test.h"
31f08c3bdfSopenharmony_ci#include "tst_safe_sysv_ipc.h"
32f08c3bdfSopenharmony_ci#include "libnewipc.h"
33f08c3bdfSopenharmony_ci#include "lapi/msg.h"
34f08c3bdfSopenharmony_ci
35f08c3bdfSopenharmony_ci#define MSGTYPE1	1
36f08c3bdfSopenharmony_ci#define MSGTYPE2	2
37f08c3bdfSopenharmony_ci#define MSG1	"messagetype1"
38f08c3bdfSopenharmony_ci#define MSG2	"messagetype2"
39f08c3bdfSopenharmony_ci
40f08c3bdfSopenharmony_cistatic key_t msgkey;
41f08c3bdfSopenharmony_cistatic int queue_id = -1, msg_copy_sup;
42f08c3bdfSopenharmony_cistatic struct buf {
43f08c3bdfSopenharmony_ci	long type;
44f08c3bdfSopenharmony_ci	char mtext[MSGSIZE];
45f08c3bdfSopenharmony_ci} rcv_buf, snd_buf[2] = {
46f08c3bdfSopenharmony_ci	{MSGTYPE1, MSG1},
47f08c3bdfSopenharmony_ci	{MSGTYPE2, MSG2}
48f08c3bdfSopenharmony_ci};
49f08c3bdfSopenharmony_ci
50f08c3bdfSopenharmony_cistatic void prepare_queue(void)
51f08c3bdfSopenharmony_ci{
52f08c3bdfSopenharmony_ci	queue_id = SAFE_MSGGET(msgkey, IPC_CREAT | IPC_EXCL | MSG_RW);
53f08c3bdfSopenharmony_ci	SAFE_MSGSND(queue_id, &snd_buf[0], MSGSIZE, 0);
54f08c3bdfSopenharmony_ci	SAFE_MSGSND(queue_id, &snd_buf[1], MSGSIZE, 0);
55f08c3bdfSopenharmony_ci	memset(&rcv_buf, 0, sizeof(rcv_buf));
56f08c3bdfSopenharmony_ci}
57f08c3bdfSopenharmony_ci
58f08c3bdfSopenharmony_cistatic void test_msg_except(void)
59f08c3bdfSopenharmony_ci{
60f08c3bdfSopenharmony_ci	prepare_queue();
61f08c3bdfSopenharmony_ci
62f08c3bdfSopenharmony_ci	TEST(msgrcv(queue_id, &rcv_buf, MSGSIZE, MSGTYPE2, MSG_EXCEPT));
63f08c3bdfSopenharmony_ci	if (TST_RET == -1) {
64f08c3bdfSopenharmony_ci		tst_res(TFAIL | TTERRNO, "msgrcv(MSG_EXCEPT) failed");
65f08c3bdfSopenharmony_ci		goto exit;
66f08c3bdfSopenharmony_ci	}
67f08c3bdfSopenharmony_ci
68f08c3bdfSopenharmony_ci	tst_res(TPASS, "msgrcv(MSG_EXCEPT) succeeded");
69f08c3bdfSopenharmony_ci
70f08c3bdfSopenharmony_ci	if (strcmp(rcv_buf.mtext, MSG1) == 0 && rcv_buf.type == MSGTYPE1)
71f08c3bdfSopenharmony_ci		tst_res(TPASS, "MSG_EXCEPT excepted MSGTYPE2 and got MSGTYPE1");
72f08c3bdfSopenharmony_ci	else
73f08c3bdfSopenharmony_ci		tst_res(TFAIL, "MSG_EXCEPT didn't get MSGTYPE1 message");
74f08c3bdfSopenharmony_ci
75f08c3bdfSopenharmony_ciexit:
76f08c3bdfSopenharmony_ci	SAFE_MSGCTL(queue_id, IPC_RMID, NULL);
77f08c3bdfSopenharmony_ci	queue_id = -1;
78f08c3bdfSopenharmony_ci}
79f08c3bdfSopenharmony_ci
80f08c3bdfSopenharmony_cistatic void test_msg_noerror(void)
81f08c3bdfSopenharmony_ci{
82f08c3bdfSopenharmony_ci	int msg_len;
83f08c3bdfSopenharmony_ci
84f08c3bdfSopenharmony_ci	queue_id = SAFE_MSGGET(msgkey, IPC_CREAT | IPC_EXCL | MSG_RW);
85f08c3bdfSopenharmony_ci	SAFE_MSGSND(queue_id, &snd_buf[0], MSGSIZE, 0);
86f08c3bdfSopenharmony_ci	msg_len = sizeof(MSG1) / 2;
87f08c3bdfSopenharmony_ci	memset(&rcv_buf, 0, sizeof(rcv_buf));
88f08c3bdfSopenharmony_ci
89f08c3bdfSopenharmony_ci	TEST(msgrcv(queue_id, &rcv_buf, msg_len, MSGTYPE1, MSG_NOERROR));
90f08c3bdfSopenharmony_ci	if (TST_RET == -1) {
91f08c3bdfSopenharmony_ci		tst_res(TFAIL | TTERRNO, "msgrcv(MSG_NOERROR) failed");
92f08c3bdfSopenharmony_ci		goto exit;
93f08c3bdfSopenharmony_ci	}
94f08c3bdfSopenharmony_ci
95f08c3bdfSopenharmony_ci	tst_res(TPASS, "msgrcv(MSG_NOERROR) succeeded");
96f08c3bdfSopenharmony_ci
97f08c3bdfSopenharmony_ci	if (strncmp(rcv_buf.mtext, MSG1, msg_len) == 0 && rcv_buf.type == MSGTYPE1)
98f08c3bdfSopenharmony_ci		tst_res(TPASS, "MSG_NOERROR truncated message correctly");
99f08c3bdfSopenharmony_ci	else
100f08c3bdfSopenharmony_ci		tst_res(TFAIL, "MSG_NOERROR truncated message incorrectly");
101f08c3bdfSopenharmony_ci
102f08c3bdfSopenharmony_ciexit:
103f08c3bdfSopenharmony_ci	SAFE_MSGCTL(queue_id, IPC_RMID, NULL);
104f08c3bdfSopenharmony_ci	queue_id = -1;
105f08c3bdfSopenharmony_ci}
106f08c3bdfSopenharmony_ci
107f08c3bdfSopenharmony_cistatic void test_msg_copy(void)
108f08c3bdfSopenharmony_ci{
109f08c3bdfSopenharmony_ci	struct msqid_ds buf = {0};
110f08c3bdfSopenharmony_ci
111f08c3bdfSopenharmony_ci	if (!msg_copy_sup) {
112f08c3bdfSopenharmony_ci		tst_res(TCONF, "MSG_COPY not supported");
113f08c3bdfSopenharmony_ci		return;
114f08c3bdfSopenharmony_ci	}
115f08c3bdfSopenharmony_ci
116f08c3bdfSopenharmony_ci	prepare_queue();
117f08c3bdfSopenharmony_ci
118f08c3bdfSopenharmony_ci	/*
119f08c3bdfSopenharmony_ci	 * If MSG_COPY flag was specified, then mtype is interpreted as number
120f08c3bdfSopenharmony_ci	 * of the message to copy.
121f08c3bdfSopenharmony_ci	 */
122f08c3bdfSopenharmony_ci	TEST(msgrcv(queue_id, &rcv_buf, MSGSIZE, 0, MSG_COPY | IPC_NOWAIT));
123f08c3bdfSopenharmony_ci	if (TST_RET == -1) {
124f08c3bdfSopenharmony_ci		if (TST_ERR == ENOSYS) {
125f08c3bdfSopenharmony_ci			tst_res(TCONF,
126f08c3bdfSopenharmony_ci				"MSG_COPY needs CONFIG_CHECKPORINT_RESTORE");
127f08c3bdfSopenharmony_ci			msg_copy_sup = 0;
128f08c3bdfSopenharmony_ci		} else {
129f08c3bdfSopenharmony_ci			tst_res(TFAIL | TTERRNO, "msgrcv(0, MSG_COPY) failed");
130f08c3bdfSopenharmony_ci		}
131f08c3bdfSopenharmony_ci		goto exit;
132f08c3bdfSopenharmony_ci	}
133f08c3bdfSopenharmony_ci
134f08c3bdfSopenharmony_ci	tst_res(TPASS, "msgrcv(0, MSG_COPY) succeeded");
135f08c3bdfSopenharmony_ci
136f08c3bdfSopenharmony_ci	if (strcmp(rcv_buf.mtext, MSG1) == 0 && rcv_buf.type == MSGTYPE1)
137f08c3bdfSopenharmony_ci		tst_res(TPASS, "MSG_COPY got MSGTYPE1 data correctly");
138f08c3bdfSopenharmony_ci	else
139f08c3bdfSopenharmony_ci		tst_res(TFAIL, "MSG_COPY got MSGTYPE1 data incorrectly");
140f08c3bdfSopenharmony_ci
141f08c3bdfSopenharmony_ci	memset(&rcv_buf, 0, sizeof(rcv_buf));
142f08c3bdfSopenharmony_ci	TEST(msgrcv(queue_id, &rcv_buf, MSGSIZE, 1, MSG_COPY | IPC_NOWAIT));
143f08c3bdfSopenharmony_ci	if (TST_RET == -1) {
144f08c3bdfSopenharmony_ci		tst_res(TFAIL | TTERRNO, "msgrcv(1, MSG_COPY) failed");
145f08c3bdfSopenharmony_ci		goto exit;
146f08c3bdfSopenharmony_ci	}
147f08c3bdfSopenharmony_ci
148f08c3bdfSopenharmony_ci	tst_res(TPASS, "msgrcv(1, MSG_COPY) succeeded");
149f08c3bdfSopenharmony_ci
150f08c3bdfSopenharmony_ci	if (strcmp(rcv_buf.mtext, MSG2) == 0 && rcv_buf.type == MSGTYPE2)
151f08c3bdfSopenharmony_ci		tst_res(TPASS, "MSG_COPY got MSGTYPE2 data correctly");
152f08c3bdfSopenharmony_ci	else
153f08c3bdfSopenharmony_ci		tst_res(TFAIL, "MSG_COPY got MSGTYPE2 data incorrectly");
154f08c3bdfSopenharmony_ci
155f08c3bdfSopenharmony_ci	SAFE_MSGCTL(queue_id, IPC_STAT, &buf);
156f08c3bdfSopenharmony_ci	if (buf.msg_qnum == 2) {
157f08c3bdfSopenharmony_ci		tst_res(TPASS, "Two messages still in queue");
158f08c3bdfSopenharmony_ci	} else {
159f08c3bdfSopenharmony_ci		tst_res(TFAIL, "Expected 2 msgs in queue got %d",
160f08c3bdfSopenharmony_ci		       (int)buf.msg_qnum);
161f08c3bdfSopenharmony_ci	}
162f08c3bdfSopenharmony_ci
163f08c3bdfSopenharmony_ciexit:
164f08c3bdfSopenharmony_ci	SAFE_MSGCTL(queue_id, IPC_RMID, NULL);
165f08c3bdfSopenharmony_ci	queue_id = -1;
166f08c3bdfSopenharmony_ci}
167f08c3bdfSopenharmony_ci
168f08c3bdfSopenharmony_cistatic void test_zero_msgtyp(void)
169f08c3bdfSopenharmony_ci{
170f08c3bdfSopenharmony_ci	prepare_queue();
171f08c3bdfSopenharmony_ci
172f08c3bdfSopenharmony_ci	TEST(msgrcv(queue_id, &rcv_buf, MSGSIZE, 0, 0));
173f08c3bdfSopenharmony_ci	if (TST_RET == -1) {
174f08c3bdfSopenharmony_ci		tst_res(TFAIL | TTERRNO, "msgrcv(zero_msgtyp) failed");
175f08c3bdfSopenharmony_ci		goto exit;
176f08c3bdfSopenharmony_ci	}
177f08c3bdfSopenharmony_ci
178f08c3bdfSopenharmony_ci	tst_res(TPASS, "msgrcv(zero_msgtyp) succeeded");
179f08c3bdfSopenharmony_ci
180f08c3bdfSopenharmony_ci	if (strcmp(rcv_buf.mtext, MSG1) == 0 && rcv_buf.type == MSGTYPE1)
181f08c3bdfSopenharmony_ci		tst_res(TPASS, "zero_msgtyp got the first message");
182f08c3bdfSopenharmony_ci	else
183f08c3bdfSopenharmony_ci		tst_res(TFAIL, "zero_msgtyp didn't get the first message");
184f08c3bdfSopenharmony_ci
185f08c3bdfSopenharmony_ciexit:
186f08c3bdfSopenharmony_ci	SAFE_MSGCTL(queue_id, IPC_RMID, NULL);
187f08c3bdfSopenharmony_ci	queue_id = -1;
188f08c3bdfSopenharmony_ci}
189f08c3bdfSopenharmony_ci
190f08c3bdfSopenharmony_cistatic void test_positive_msgtyp(void)
191f08c3bdfSopenharmony_ci{
192f08c3bdfSopenharmony_ci	prepare_queue();
193f08c3bdfSopenharmony_ci
194f08c3bdfSopenharmony_ci	TEST(msgrcv(queue_id, &rcv_buf, MSGSIZE, MSGTYPE2, 0));
195f08c3bdfSopenharmony_ci	if (TST_RET == -1) {
196f08c3bdfSopenharmony_ci		tst_res(TFAIL | TTERRNO, "msgrcv(positive_msgtyp) failed");
197f08c3bdfSopenharmony_ci		goto exit;
198f08c3bdfSopenharmony_ci	}
199f08c3bdfSopenharmony_ci
200f08c3bdfSopenharmony_ci	tst_res(TPASS, "msgrcv(positive_msgtyp) succeeded");
201f08c3bdfSopenharmony_ci
202f08c3bdfSopenharmony_ci	if (strcmp(rcv_buf.mtext, MSG2) == 0 && rcv_buf.type == MSGTYPE2) {
203f08c3bdfSopenharmony_ci		tst_res(TPASS,
204f08c3bdfSopenharmony_ci			"msgtyp got the first message in the queue of type msgtyp");
205f08c3bdfSopenharmony_ci	} else {
206f08c3bdfSopenharmony_ci		tst_res(TFAIL,
207f08c3bdfSopenharmony_ci			"msgtyp didn't get the first message in the queue of type msgtyp");
208f08c3bdfSopenharmony_ci	}
209f08c3bdfSopenharmony_ci
210f08c3bdfSopenharmony_ciexit:
211f08c3bdfSopenharmony_ci	SAFE_MSGCTL(queue_id, IPC_RMID, NULL);
212f08c3bdfSopenharmony_ci	queue_id = -1;
213f08c3bdfSopenharmony_ci}
214f08c3bdfSopenharmony_ci
215f08c3bdfSopenharmony_cistatic void test_negative_msgtyp(void)
216f08c3bdfSopenharmony_ci{
217f08c3bdfSopenharmony_ci	prepare_queue();
218f08c3bdfSopenharmony_ci
219f08c3bdfSopenharmony_ci	TEST(msgrcv(queue_id, &rcv_buf, MSGSIZE, -MSGTYPE2, 0));
220f08c3bdfSopenharmony_ci	if (TST_RET == -1) {
221f08c3bdfSopenharmony_ci		tst_res(TFAIL | TTERRNO, "msgrcv(negative_msgtyp) failed");
222f08c3bdfSopenharmony_ci		goto exit;
223f08c3bdfSopenharmony_ci	}
224f08c3bdfSopenharmony_ci
225f08c3bdfSopenharmony_ci	tst_res(TPASS, "msgrcv(negative_msgtyp) succeeded");
226f08c3bdfSopenharmony_ci
227f08c3bdfSopenharmony_ci	if (strcmp(rcv_buf.mtext, MSG1) == 0 && rcv_buf.type == MSGTYPE1) {
228f08c3bdfSopenharmony_ci		tst_res(TPASS,
229f08c3bdfSopenharmony_ci			"-msgtyp got the first message in the queue with the lowest type");
230f08c3bdfSopenharmony_ci	} else {
231f08c3bdfSopenharmony_ci		tst_res(TFAIL,
232f08c3bdfSopenharmony_ci			"-msgtyp didn't get the first message in the queue with the lowest type");
233f08c3bdfSopenharmony_ci	}
234f08c3bdfSopenharmony_ci
235f08c3bdfSopenharmony_ciexit:
236f08c3bdfSopenharmony_ci	SAFE_MSGCTL(queue_id, IPC_RMID, NULL);
237f08c3bdfSopenharmony_ci	queue_id = -1;
238f08c3bdfSopenharmony_ci}
239f08c3bdfSopenharmony_ci
240f08c3bdfSopenharmony_cistatic void cleanup(void)
241f08c3bdfSopenharmony_ci{
242f08c3bdfSopenharmony_ci	if (queue_id != -1)
243f08c3bdfSopenharmony_ci		SAFE_MSGCTL(queue_id, IPC_RMID, NULL);
244f08c3bdfSopenharmony_ci}
245f08c3bdfSopenharmony_ci
246f08c3bdfSopenharmony_cistatic void setup(void)
247f08c3bdfSopenharmony_ci{
248f08c3bdfSopenharmony_ci	msgkey = GETIPCKEY();
249f08c3bdfSopenharmony_ci
250f08c3bdfSopenharmony_ci	msg_copy_sup = 1;
251f08c3bdfSopenharmony_ci}
252f08c3bdfSopenharmony_ci
253f08c3bdfSopenharmony_cistatic void (*testfunc[])(void) = {test_msg_except, test_msg_noerror,
254f08c3bdfSopenharmony_ci				   test_msg_copy, test_zero_msgtyp,
255f08c3bdfSopenharmony_ci				   test_positive_msgtyp, test_negative_msgtyp};
256f08c3bdfSopenharmony_ci
257f08c3bdfSopenharmony_cistatic void verify_msgcrv(unsigned int n)
258f08c3bdfSopenharmony_ci{
259f08c3bdfSopenharmony_ci	(*testfunc[n])();
260f08c3bdfSopenharmony_ci}
261f08c3bdfSopenharmony_ci
262f08c3bdfSopenharmony_cistatic struct tst_test test = {
263f08c3bdfSopenharmony_ci	.needs_tmpdir = 1,
264f08c3bdfSopenharmony_ci	.setup = setup,
265f08c3bdfSopenharmony_ci	.cleanup = cleanup,
266f08c3bdfSopenharmony_ci	.test = verify_msgcrv,
267f08c3bdfSopenharmony_ci	.tcnt = ARRAY_SIZE(testfunc),
268f08c3bdfSopenharmony_ci};
269