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