1/*
2 *
3 *   Copyright (c) International Business Machines  Corp., 2002
4 *
5 *   This program is free software;  you can redistribute it and/or modify
6 *   it under the terms of the GNU General Public License as published by
7 *   the Free Software Foundation; either version 2 of the License, or
8 *   (at your option) any later version.
9 *
10 *   This program is distributed in the hope that it will be useful,
11 *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
12 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
13 *   the GNU General Public License for more details.
14 *
15 *   You should have received a copy of the GNU General Public License
16 *   along with this program;  if not, write to the Free Software
17 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20/* 06/30/2001	Port to Linux	nsharoff@us.ibm.com */
21/* 11/06/2002   Port to LTP     dbarrera@us.ibm.com */
22/* 12/03/2008   Fix concurrency issue     mfertre@irisa.fr */
23
24/*
25 * NAME
26 *	msgctl07
27 *
28 * CALLS
29 *	msgget(2) msgctl(2) msgop(2)
30 *
31 * ALGORITHM
32 *	Get and manipulate a message queue.
33 *
34 * RESTRICTIONS
35 *
36 */
37
38#include <sys/types.h>
39#include <sys/ipc.h>
40#include <sys/msg.h>
41#include <signal.h>
42#include <sys/wait.h>
43#include <stdio.h>
44#include "test.h"
45#include "ipcmsg.h"
46#include <stdlib.h>
47#include <unistd.h>
48#include <errno.h>
49
50typedef void (*sighandler_t) (int);
51volatile int ready;
52
53#define BYTES 100
54#define SECS 10
55
56void setup();
57void cleanup();
58void do_child_1();
59void do_child_2();
60
61char *TCID = "msgctl07";
62int TST_TOTAL = 1;
63
64/* Used by main() and do_child_1(): */
65static int msqid;
66struct my_msgbuf {
67	long type;
68	char text[BYTES];
69} p1_msgp, p2_msgp, p3_msgp, c1_msgp, c2_msgp, c3_msgp;
70
71int main(int argc, char *argv[])
72{
73	key_t key;
74	int pid, status;
75	int i, j, k;
76	sighandler_t alrm();
77
78	tst_parse_opts(argc, argv, NULL, NULL);
79
80	setup();
81
82	key = getipckey();
83	if ((msqid = msgget(key, IPC_CREAT | IPC_EXCL)) == -1) {
84		tst_brkm(TFAIL | TERRNO, NULL, "msgget() failed");
85
86	}
87
88	pid = FORK_OR_VFORK();
89	if (pid < 0) {
90		(void)msgctl(msqid, IPC_RMID, NULL);
91		tst_brkm(TFAIL, NULL,
92			 "\tFork failed (may be OK if under stress)");
93	} else if (pid == 0) {
94		do_child_1();
95	} else {
96		struct sigaction act;
97
98		memset(&act, 0, sizeof(act));
99		act.sa_handler = (sighandler_t) alrm;
100		sigemptyset(&act.sa_mask);
101		sigaddset(&act.sa_mask, SIGALRM);
102		if ((sigaction(SIGALRM, &act, NULL)) < 0) {
103			tst_resm(TFAIL | TERRNO, "signal failed");
104			kill(pid, SIGKILL);
105			(void)msgctl(msqid, IPC_RMID, NULL);
106			tst_exit();
107		}
108		ready = 0;
109		alarm(SECS);
110		while (!ready)	/* make the child wait */
111			usleep(50000);
112		for (i = 0; i < BYTES; i++)
113			p1_msgp.text[i] = 'i';
114		p1_msgp.type = 1;
115		if (msgsnd(msqid, &p1_msgp, BYTES, 0) == -1) {
116			tst_resm(TFAIL | TERRNO, "msgsnd() failed");
117			kill(pid, SIGKILL);
118			(void)msgctl(msqid, IPC_RMID, NULL);
119			tst_exit();
120		}
121		wait(&status);
122	}
123	if ((status >> 8) == 1) {
124		tst_brkm(TFAIL, NULL, "test failed. status = %d",
125			 (status >> 8));
126	}
127
128	pid = FORK_OR_VFORK();
129	if (pid < 0) {
130		(void)msgctl(msqid, IPC_RMID, NULL);
131		tst_brkm(TFAIL, NULL,
132			 "\tFork failed (may be OK if under stress)");
133	} else if (pid == 0) {
134		do_child_2();
135	} else {
136		struct sigaction act;
137
138		memset(&act, 0, sizeof(act));
139		act.sa_handler = (sighandler_t) alrm;
140		sigemptyset(&act.sa_mask);
141		sigaddset(&act.sa_mask, SIGALRM);
142		if ((sigaction(SIGALRM, &act, NULL)) < 0) {
143			tst_resm(TFAIL | TERRNO, "signal failed");
144			kill(pid, SIGKILL);
145			(void)msgctl(msqid, IPC_RMID, NULL);
146			tst_exit();
147		}
148		ready = 0;
149		alarm(SECS);
150		while (!ready)	/* make the child wait */
151			usleep(50000);
152		for (i = 0; i < BYTES; i++)
153			p1_msgp.text[i] = 'i';
154		p1_msgp.type = 1;
155		if (msgsnd(msqid, &p1_msgp, BYTES, 0) == -1) {
156			tst_resm(TFAIL | TERRNO, "msgsnd() failed");
157			kill(pid, SIGKILL);
158			(void)msgctl(msqid, IPC_RMID, NULL);
159			tst_exit();
160		}
161		for (j = 0; j < BYTES; j++)
162			p2_msgp.text[j] = 'j';
163		p2_msgp.type = 2;
164		if (msgsnd(msqid, &p2_msgp, BYTES, 0) == -1) {
165			tst_resm(TFAIL | TERRNO, "msgsnd() failed");
166			kill(pid, SIGKILL);
167			(void)msgctl(msqid, IPC_RMID, NULL);
168			tst_exit();
169		}
170		for (k = 0; k < BYTES; k++)
171			p3_msgp.text[k] = 'k';
172		p3_msgp.type = 3;
173		if (msgsnd(msqid, &p3_msgp, BYTES, 0) == -1) {
174			tst_resm(TFAIL | TERRNO, "msgsnd() failed");
175			kill(pid, SIGKILL);
176			(void)msgctl(msqid, IPC_RMID, NULL);
177			tst_exit();
178		}
179		wait(&status);
180	}
181	if ((status >> 8) == 1) {
182		tst_brkm(TFAIL, NULL, "test failed. status = %d",
183			 (status >> 8));
184	}
185	/*
186	 * Remove the message queue from the system
187	 */
188#ifdef DEBUG
189	tst_resm(TINFO, "Removing the message queue");
190#endif
191	fflush(stdout);
192	(void)msgctl(msqid, IPC_RMID, NULL);
193	if ((status = msgctl(msqid, IPC_STAT, NULL)) != -1) {
194		(void)msgctl(msqid, IPC_RMID, NULL);
195		tst_brkm(TFAIL, NULL, "msgctl(msqid, IPC_RMID) failed");
196
197	}
198
199	fflush(stdout);
200	tst_resm(TPASS, "msgctl07 ran successfully!");
201
202	cleanup();
203
204	tst_exit();
205}
206
207sighandler_t alrm(int sig LTP_ATTRIBUTE_UNUSED)
208{
209	ready++;
210	return 0;
211}
212
213void do_child_1(void)
214{
215	int i;
216	int size;
217
218	if ((size = msgrcv(msqid, &c1_msgp, BYTES, 0, 0)) == -1) {
219		tst_brkm(TFAIL | TERRNO, NULL, "msgrcv() failed");
220	}
221	if (size != BYTES) {
222		tst_brkm(TFAIL, NULL, "error: received %d bytes expected %d",
223			 size,
224			 BYTES);
225	}
226	for (i = 0; i < BYTES; i++)
227		if (c1_msgp.text[i] != 'i') {
228			tst_brkm(TFAIL, NULL, "error: corrup message");
229		}
230	exit(0);
231}
232
233void do_child_2(void)
234{
235	int i, j, k;
236	int size;
237
238	if ((size = msgrcv(msqid, &c3_msgp, BYTES, 3, 0)) == -1) {
239		tst_brkm(TFAIL | TERRNO, NULL, "msgrcv() failed");
240	}
241	if (size != BYTES) {
242		tst_brkm(TFAIL, NULL, "error: received %d bytes expected %d",
243			 size,
244			 BYTES);
245	}
246	for (k = 0; k < BYTES; k++)
247		if (c3_msgp.text[k] != 'k') {
248			tst_brkm(TFAIL, NULL, "error: corrupt message");
249		}
250	if ((size = msgrcv(msqid, &c2_msgp, BYTES, 2, 0)) == -1) {
251		tst_brkm(TFAIL | TERRNO, NULL, "msgrcv() failed");
252	}
253	if (size != BYTES) {
254		tst_brkm(TFAIL, NULL, "error: received %d bytes expected %d",
255			 size,
256			 BYTES);
257	}
258	for (j = 0; j < BYTES; j++)
259		if (c2_msgp.text[j] != 'j') {
260			tst_brkm(TFAIL, NULL, "error: corrupt message");
261		}
262	if ((size = msgrcv(msqid, &c1_msgp, BYTES, 1, 0)) == -1) {
263		tst_brkm(TFAIL | TERRNO, NULL, "msgrcv() failed");
264	}
265	if (size != BYTES) {
266		tst_brkm(TFAIL, NULL, "error: received %d bytes expected %d",
267			 size,
268			 BYTES);
269	}
270	for (i = 0; i < BYTES; i++)
271		if (c1_msgp.text[i] != 'i') {
272			tst_brkm(TFAIL, NULL, "error: corrupt message");
273		}
274
275	exit(0);
276}
277
278void setup(void)
279{
280	tst_sig(FORK, DEF_HANDLER, cleanup);
281
282	tst_require_root();
283
284	TEST_PAUSE;
285
286	tst_tmpdir();
287}
288
289void cleanup(void)
290{
291	tst_rmdir();
292}
293