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