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
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(int argc,char * argv[])71 int 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
alrm(int sig LTP_ATTRIBUTE_UNUSED)207 sighandler_t alrm(int sig LTP_ATTRIBUTE_UNUSED)
208 {
209 ready++;
210 return 0;
211 }
212
do_child_1(void)213 void 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
do_child_2(void)233 void 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
setup(void)278 void 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
cleanup(void)289 void cleanup(void)
290 {
291 tst_rmdir();
292 }
293