1/*
2 * Copyright (c) 2014 Fujitsu Ltd.
3 * Author: Xiaoguang Wang <wangxg.fnst@cn.fujitsu.com>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it would be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16 */
17
18/*
19 * Description:
20 *     Basic test for msgrcv(2) using MSG_EXCEPT, MSG_NOERROR
21 */
22
23#define  _GNU_SOURCE
24#include <sys/wait.h>
25#include "test.h"
26#include "ipcmsg.h"
27
28
29#define MSGTYPE1	1
30#define MSGTYPE2	2
31#define MSG1	"message type1"
32#define MSG2	"message type2"
33
34static void wait4child(pid_t child, char *tst_flag);
35
36static void test_msg_except(void);
37static void test_msg_noerror(void);
38
39static void (*testfunc[])(void) = { test_msg_except, test_msg_noerror };
40
41char *TCID = "msgrcv07";
42int TST_TOTAL = ARRAY_SIZE(testfunc);
43
44int main(int ac, char **av)
45{
46	int lc;
47	int i;
48
49	tst_parse_opts(ac, av, NULL, NULL);
50
51	setup();
52
53	for (lc = 0; TEST_LOOPING(lc); lc++) {
54		tst_count = 0;
55
56		for (i = 0; i < TST_TOTAL; i++)
57			(*testfunc[i])();
58	}
59
60	cleanup();
61	tst_exit();
62}
63
64void setup(void)
65{
66	tst_sig(FORK, DEF_HANDLER, cleanup);
67
68	TEST_PAUSE;
69}
70
71static void test_msg_except(void)
72{
73	pid_t child_pid;
74	int msgq_id;
75	MSGBUF snd_buf1 = {.mtype = MSGTYPE1, .mtext = MSG1};
76	MSGBUF snd_buf2 = {.mtype = MSGTYPE2, .mtext = MSG2};
77	MSGBUF rcv_buf;
78
79	msgq_id = msgget(IPC_PRIVATE, MSG_RW);
80	if (msgq_id == -1)
81		tst_brkm(TBROK | TERRNO, cleanup, "Can't create message queue");
82
83	if (msgsnd(msgq_id, &snd_buf1, MSGSIZE, 0) == -1)
84		tst_brkm(TBROK | TERRNO, cleanup, "Can't enqueue message");
85
86	if (msgsnd(msgq_id, &snd_buf2, MSGSIZE, 0) == -1)
87		tst_brkm(TBROK | TERRNO, cleanup, "Can't enqueue message");
88
89	child_pid = tst_fork();
90	if (child_pid == -1) {
91		tst_brkm(TBROK, cleanup, "fork failed");
92	} else if (child_pid > 0) {
93		wait4child(child_pid, "MSG_EXCEPT");
94	} else {
95		memset(&rcv_buf, 0, sizeof(rcv_buf));
96		TEST(msgrcv(msgq_id, &rcv_buf, MSGSIZE, MSGTYPE2, MSG_EXCEPT));
97		if (TEST_RETURN == -1) {
98			fprintf(stderr, "msgrcv(MSG_EXCEPT) failed\n");
99			exit(TBROK);
100		}
101		/* check the received message */
102		if (strcmp(rcv_buf.mtext, MSG1) == 0 &&
103		    rcv_buf.mtype == MSGTYPE1)
104			exit(TPASS);
105		else
106			exit(TFAIL);
107	}
108
109	rm_queue(msgq_id);
110}
111
112
113static void test_msg_noerror(void)
114{
115	pid_t child_pid;
116	int msg_len, msgq_id;
117	MSGBUF snd_buf1 = {.mtype = MSGTYPE1, .mtext = MSG1};
118	MSGBUF rcv_buf;
119
120	msgq_id = msgget(IPC_PRIVATE, MSG_RW);
121	if (msgq_id == -1)
122		tst_brkm(TBROK | TERRNO, cleanup, "Can't create message queue");
123
124	if (msgsnd(msgq_id, &snd_buf1, MSGSIZE, 0) == -1)
125		tst_brkm(TBROK | TERRNO, cleanup, "Can't enqueue message");
126
127	child_pid = tst_fork();
128	if (child_pid == -1) {
129		tst_brkm(TBROK, cleanup, "fork failed");
130	} else if (child_pid > 0) {
131		wait4child(child_pid, "MSG_NOERROR");
132	} else {
133		msg_len = sizeof(MSG1) / 2;
134		memset(&rcv_buf, 0, sizeof(rcv_buf));
135
136		TEST(msgrcv(msgq_id, &rcv_buf, msg_len, MSGTYPE1, MSG_NOERROR));
137		if (TEST_RETURN == -1)
138			exit(TFAIL);
139
140		if (strncmp(rcv_buf.mtext, MSG1, msg_len) == 0 &&
141		    rcv_buf.mtype == MSGTYPE1)
142			exit(TPASS);
143		exit(TFAIL);
144	}
145
146	rm_queue(msgq_id);
147}
148
149static void wait4child(pid_t child, char *tst_flag)
150{
151	int status;
152	int ret;
153
154	if (waitpid(child, &status, 0) == -1)
155		tst_resm(TBROK | TERRNO, "waitpid");
156	if (WIFEXITED(status)) {
157		ret = WEXITSTATUS(status);
158		if (ret == 0)
159			tst_resm(TPASS, "test %s success", tst_flag);
160		else if (ret == 1)
161			tst_resm(TFAIL, "test %s failed", tst_flag);
162		else
163			tst_brkm(TBROK, cleanup, "msgrcv failed unexpectedly");
164	} else {
165		tst_brkm(TBROK, cleanup, "child process terminated "
166			 "abnormally. status: %d", status);
167	}
168}
169
170void cleanup(void)
171{
172}
173