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 <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 
50 typedef void (*sighandler_t) (int);
51 volatile int ready;
52 
53 #define BYTES 100
54 #define SECS 10
55 
56 void setup();
57 void cleanup();
58 void do_child_1();
59 void do_child_2();
60 
61 char *TCID = "msgctl07";
62 int TST_TOTAL = 1;
63 
64 /* Used by main() and do_child_1(): */
65 static int msqid;
66 struct my_msgbuf {
67 	long type;
68 	char text[BYTES];
69 } p1_msgp, p2_msgp, p3_msgp, c1_msgp, c2_msgp, c3_msgp;
70 
main(void)71 int main(void)
72 {
73 	key_t key;
74 	int pid, status;
75 	int i, j, k;
76 	sighandler_t alrm();
77 
78 #ifdef UCLINUX
79 
80 	tst_parse_opts(argc, argv, NULL, NULL);
81 
82 	maybe_run_child(&do_child_1, "ndd", 1, &msqid, &c1_msgp.type);
83 	maybe_run_child(&do_child_2, "ndddd", 2, &msqid, &c1_msgp.type,
84 			&c2_msgp.type, &c3_msgp.type);
85 #endif
86 
87 	setup();
88 
89 	key = getipckey();
90 	if ((msqid = msgget(key, IPC_CREAT | IPC_EXCL)) == -1) {
91 		tst_brkm(TFAIL | TERRNO, NULL, "msgget() failed");
92 
93 	}
94 
95 	pid = FORK_OR_VFORK();
96 	if (pid < 0) {
97 		(void)msgctl(msqid, IPC_RMID, NULL);
98 		tst_brkm(TFAIL, NULL,
99 			 "\tFork failed (may be OK if under stress)");
100 	} else if (pid == 0) {
101 #ifdef UCLINUX
102 		if (self_exec(argv[0], "ndd", 1, msqid, c1_msgp.type) < 0) {
103 			tst_brkm(TFAIL, NULL, "\tself_exec failed");
104 		}
105 #else
106 		do_child_1();
107 #endif
108 	} else {
109 		struct sigaction act;
110 
111 		memset(&act, 0, sizeof(act));
112 		act.sa_handler = (sighandler_t) alrm;
113 		sigemptyset(&act.sa_mask);
114 		sigaddset(&act.sa_mask, SIGALRM);
115 		if ((sigaction(SIGALRM, &act, NULL)) < 0) {
116 			tst_resm(TFAIL | TERRNO, "signal failed");
117 			kill(pid, SIGKILL);
118 			(void)msgctl(msqid, IPC_RMID, NULL);
119 			tst_exit();
120 		}
121 		ready = 0;
122 		alarm(SECS);
123 		while (!ready)	/* make the child wait */
124 			usleep(50000);
125 		for (i = 0; i < BYTES; i++)
126 			p1_msgp.text[i] = 'i';
127 		p1_msgp.type = 1;
128 		if (msgsnd(msqid, &p1_msgp, BYTES, 0) == -1) {
129 			tst_resm(TFAIL | TERRNO, "msgsnd() failed");
130 			kill(pid, SIGKILL);
131 			(void)msgctl(msqid, IPC_RMID, NULL);
132 			tst_exit();
133 		}
134 		wait(&status);
135 	}
136 	if ((status >> 8) == 1) {
137 		tst_brkm(TFAIL, NULL, "test failed. status = %d",
138 			 (status >> 8));
139 	}
140 
141 	pid = FORK_OR_VFORK();
142 	if (pid < 0) {
143 		(void)msgctl(msqid, IPC_RMID, NULL);
144 		tst_brkm(TFAIL, NULL,
145 			 "\tFork failed (may be OK if under stress)");
146 	} else if (pid == 0) {
147 #ifdef UCLINUX
148 		if (self_exec(argv[0], "ndddd", 1, msqid, c1_msgp.type,
149 			      c2_msgp.type, c3_msgp.type) < 0) {
150 			tst_brkm(TFAIL, NULL, "\tself_exec failed");
151 		}
152 #else
153 		do_child_2();
154 #endif
155 	} else {
156 		struct sigaction act;
157 
158 		memset(&act, 0, sizeof(act));
159 		act.sa_handler = (sighandler_t) alrm;
160 		sigemptyset(&act.sa_mask);
161 		sigaddset(&act.sa_mask, SIGALRM);
162 		if ((sigaction(SIGALRM, &act, NULL)) < 0) {
163 			tst_resm(TFAIL | TERRNO, "signal failed");
164 			kill(pid, SIGKILL);
165 			(void)msgctl(msqid, IPC_RMID, NULL);
166 			tst_exit();
167 		}
168 		ready = 0;
169 		alarm(SECS);
170 		while (!ready)	/* make the child wait */
171 			usleep(50000);
172 		for (i = 0; i < BYTES; i++)
173 			p1_msgp.text[i] = 'i';
174 		p1_msgp.type = 1;
175 		if (msgsnd(msqid, &p1_msgp, BYTES, 0) == -1) {
176 			tst_resm(TFAIL | TERRNO, "msgsnd() failed");
177 			kill(pid, SIGKILL);
178 			(void)msgctl(msqid, IPC_RMID, NULL);
179 			tst_exit();
180 		}
181 		for (j = 0; j < BYTES; j++)
182 			p2_msgp.text[j] = 'j';
183 		p2_msgp.type = 2;
184 		if (msgsnd(msqid, &p2_msgp, BYTES, 0) == -1) {
185 			tst_resm(TFAIL | TERRNO, "msgsnd() failed");
186 			kill(pid, SIGKILL);
187 			(void)msgctl(msqid, IPC_RMID, NULL);
188 			tst_exit();
189 		}
190 		for (k = 0; k < BYTES; k++)
191 			p3_msgp.text[k] = 'k';
192 		p3_msgp.type = 3;
193 		if (msgsnd(msqid, &p3_msgp, BYTES, 0) == -1) {
194 			tst_resm(TFAIL | TERRNO, "msgsnd() failed");
195 			kill(pid, SIGKILL);
196 			(void)msgctl(msqid, IPC_RMID, NULL);
197 			tst_exit();
198 		}
199 		wait(&status);
200 	}
201 	if ((status >> 8) == 1) {
202 		tst_brkm(TFAIL, NULL, "test failed. status = %d",
203 			 (status >> 8));
204 	}
205 	/*
206 	 * Remove the message queue from the system
207 	 */
208 #ifdef DEBUG
209 	tst_resm(TINFO, "Removing the message queue");
210 #endif
211 	fflush(stdout);
212 	(void)msgctl(msqid, IPC_RMID, NULL);
213 	if ((status = msgctl(msqid, IPC_STAT, NULL)) != -1) {
214 		(void)msgctl(msqid, IPC_RMID, NULL);
215 		tst_brkm(TFAIL, NULL, "msgctl(msqid, IPC_RMID) failed");
216 
217 	}
218 
219 	fflush(stdout);
220 	tst_resm(TPASS, "msgctl07 ran successfully!");
221 
222 	cleanup();
223 
224 	tst_exit();
225 }
226 
alrm(int sig LTP_ATTRIBUTE_UNUSED)227 sighandler_t alrm(int sig LTP_ATTRIBUTE_UNUSED)
228 {
229 	ready++;
230 	return 0;
231 }
232 
do_child_1(void)233 void do_child_1(void)
234 {
235 	int i;
236 	int size;
237 
238 	if ((size = msgrcv(msqid, &c1_msgp, BYTES, 0, 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 (i = 0; i < BYTES; i++)
247 		if (c1_msgp.text[i] != 'i') {
248 			tst_brkm(TFAIL, NULL, "error: corrup message");
249 		}
250 	exit(0);
251 }
252 
do_child_2(void)253 void do_child_2(void)
254 {
255 	int i, j, k;
256 	int size;
257 
258 	if ((size = msgrcv(msqid, &c3_msgp, BYTES, 3, 0)) == -1) {
259 		tst_brkm(TFAIL | TERRNO, NULL, "msgrcv() failed");
260 	}
261 	if (size != BYTES) {
262 		tst_brkm(TFAIL, NULL, "error: received %d bytes expected %d",
263 			 size,
264 			 BYTES);
265 	}
266 	for (k = 0; k < BYTES; k++)
267 		if (c3_msgp.text[k] != 'k') {
268 			tst_brkm(TFAIL, NULL, "error: corrupt message");
269 		}
270 	if ((size = msgrcv(msqid, &c2_msgp, BYTES, 2, 0)) == -1) {
271 		tst_brkm(TFAIL | TERRNO, NULL, "msgrcv() failed");
272 	}
273 	if (size != BYTES) {
274 		tst_brkm(TFAIL, NULL, "error: received %d bytes expected %d",
275 			 size,
276 			 BYTES);
277 	}
278 	for (j = 0; j < BYTES; j++)
279 		if (c2_msgp.text[j] != 'j') {
280 			tst_brkm(TFAIL, NULL, "error: corrupt message");
281 		}
282 	if ((size = msgrcv(msqid, &c1_msgp, BYTES, 1, 0)) == -1) {
283 		tst_brkm(TFAIL | TERRNO, NULL, "msgrcv() failed");
284 	}
285 	if (size != BYTES) {
286 		tst_brkm(TFAIL, NULL, "error: received %d bytes expected %d",
287 			 size,
288 			 BYTES);
289 	}
290 	for (i = 0; i < BYTES; i++)
291 		if (c1_msgp.text[i] != 'i') {
292 			tst_brkm(TFAIL, NULL, "error: corrupt message");
293 		}
294 
295 	exit(0);
296 }
297 
setup(void)298 void setup(void)
299 {
300 	tst_sig(FORK, DEF_HANDLER, cleanup);
301 
302 	tst_require_root();
303 
304 	TEST_PAUSE;
305 
306 	tst_tmpdir();
307 }
308 
cleanup(void)309 void cleanup(void)
310 {
311 	tst_rmdir();
312 }
313