1 /* Test message queue passing.
2    Copyright (C) 2004-2022 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4 
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9 
10    The GNU C Library 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 the GNU
13    Lesser General Public License for more details.
14 
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <https://www.gnu.org/licenses/>.  */
18 
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <mqueue.h>
22 #include <signal.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/time.h>
27 #include <sys/wait.h>
28 #include <time.h>
29 #include <unistd.h>
30 #include <support/check.h>
31 #include "tst-mqueue.h"
32 
33 static void
alrm_handler(int sig)34 alrm_handler (int sig)
35 {
36 }
37 
38 #define TEST_FUNCTION do_test ()
39 static int
do_test(void)40 do_test (void)
41 {
42   int result = 0;
43 
44   char name[sizeof "/tst-mqueue2-" + sizeof (pid_t) * 3];
45   snprintf (name, sizeof (name), "/tst-mqueue2-%u", getpid ());
46 
47   struct mq_attr attr = { .mq_maxmsg = 2, .mq_msgsize = 2 };
48   mqd_t q = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr);
49 
50   if (q == (mqd_t) -1)
51     {
52       if (errno == ENOSYS)
53 	FAIL_UNSUPPORTED ("mq_open not supported");
54 
55       printf ("mq_open failed with: %m\n");
56       return 1;
57     }
58 
59   add_temp_mq (name);
60 
61   mqd_t q2 = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr);
62   if (q2 != (mqd_t) -1)
63     {
64       puts ("mq_open with O_EXCL unexpectedly succeeded");
65       result = 1;
66     }
67   else if (errno != EEXIST)
68     {
69       printf ("mq_open did not fail with EEXIST: %m\n");
70       result = 1;
71     }
72 
73   char name2[sizeof "/tst-mqueue2-2-" + sizeof (pid_t) * 3];
74   snprintf (name2, sizeof (name2), "/tst-mqueue2-2-%u", getpid ());
75 
76   attr.mq_maxmsg = -2;
77   q2 = mq_open (name2, O_CREAT | O_EXCL | O_RDWR, 0600, &attr);
78   if (q2 != (mqd_t) -1)
79     {
80       puts ("mq_open with invalid mq_maxmsg unexpectedly succeeded");
81       add_temp_mq (name2);
82       result = 1;
83     }
84   else if (errno != EINVAL)
85     {
86       printf ("mq_open with invalid mq_maxmsg did not fail with "
87 	      "EINVAL: %m\n");
88       result = 1;
89     }
90 
91   attr.mq_maxmsg = 2;
92   attr.mq_msgsize = -56;
93   q2 = mq_open (name2, O_CREAT | O_EXCL | O_RDWR, 0600, &attr);
94   if (q2 != (mqd_t) -1)
95     {
96       puts ("mq_open with invalid mq_msgsize unexpectedly succeeded");
97       add_temp_mq (name2);
98       result = 1;
99     }
100   else if (errno != EINVAL)
101     {
102       printf ("mq_open with invalid mq_msgsize did not fail with "
103 	      "EINVAL: %m\n");
104       result = 1;
105     }
106 
107   char buf[3];
108   struct timespec ts;
109   if (clock_gettime (CLOCK_REALTIME, &ts) == 0)
110     ts.tv_sec += 10;
111   else
112     {
113       ts.tv_sec = time (NULL) + 10;
114       ts.tv_nsec = 0;
115     }
116 
117   if (mq_timedreceive (q, buf, 1, NULL, &ts) == 0)
118     {
119       puts ("mq_timedreceive with too small msg_len did not fail");
120       result = 1;
121     }
122   else if (errno != EMSGSIZE)
123     {
124       printf ("mq_timedreceive with too small msg_len did not fail with "
125 	      "EMSGSIZE: %m\n");
126       result = 1;
127     }
128 
129   ts.tv_nsec = -1;
130   if (mq_timedreceive (q, buf, 2, NULL, &ts) == 0)
131     {
132       puts ("mq_timedreceive with negative tv_nsec did not fail");
133       result = 1;
134     }
135   else if (errno != EINVAL)
136     {
137       printf ("mq_timedreceive with negative tv_nsec did not fail with "
138 	      "EINVAL: %m\n");
139       result = 1;
140     }
141 
142   ts.tv_nsec = 1000000000;
143   if (mq_timedreceive (q, buf, 2, NULL, &ts) == 0)
144     {
145       puts ("mq_timedreceive with tv_nsec >= 1000000000 did not fail");
146       result = 1;
147     }
148   else if (errno != EINVAL)
149     {
150       printf ("mq_timedreceive with tv_nsec >= 1000000000 did not fail with "
151 	      "EINVAL: %m\n");
152       result = 1;
153     }
154 
155   struct sigaction sa = { .sa_handler = alrm_handler, .sa_flags = 0 };
156   sigemptyset (&sa.sa_mask);
157   sigaction (SIGALRM, &sa, NULL);
158 
159   struct itimerval it = { .it_value = { .tv_sec = 1 } };
160   setitimer (ITIMER_REAL, &it, NULL);
161 
162   if (mq_receive (q, buf, 2, NULL) == 0)
163     {
164       puts ("mq_receive on empty queue did not block");
165       result = 1;
166     }
167   else if (errno != EINTR)
168     {
169       printf ("mq_receive on empty queue did not fail with EINTR: %m\n");
170       result = 1;
171     }
172 
173   setitimer (ITIMER_REAL, &it, NULL);
174 
175   ts.tv_nsec = 0;
176   if (mq_timedreceive (q, buf, 2, NULL, &ts) == 0)
177     {
178       puts ("mq_timedreceive on empty queue did not block");
179       result = 1;
180     }
181   else if (errno != EINTR)
182     {
183       printf ("mq_timedreceive on empty queue did not fail with EINTR: %m\n");
184       result = 1;
185     }
186 
187   buf[0] = '6';
188   buf[1] = '7';
189   if (mq_send (q, buf, 2, 3) != 0
190       || (buf[0] = '8', mq_send (q, buf, 1, 4) != 0))
191     {
192       printf ("mq_send failed: %m\n");
193       result = 1;
194     }
195 
196   memset (buf, ' ', sizeof (buf));
197 
198   unsigned int prio;
199   ssize_t rets = mq_receive (q, buf, 3, &prio);
200   if (rets != 1)
201     {
202       if (rets == -1)
203 	printf ("mq_receive failed: %m\n");
204       else
205 	printf ("mq_receive returned %zd != 1\n", rets);
206       result = 1;
207     }
208   else if (prio != 4 || memcmp (buf, "8  ", 3) != 0)
209     {
210       printf ("mq_receive prio %u (4) buf \"%c%c%c\" (\"8  \")\n",
211 	      prio, buf[0], buf[1], buf[2]);
212       result = 1;
213     }
214 
215   rets = mq_receive (q, buf, 2, NULL);
216   if (rets != 2)
217     {
218       if (rets == -1)
219 	printf ("mq_receive failed: %m\n");
220       else
221 	printf ("mq_receive returned %zd != 2\n", rets);
222       result = 1;
223     }
224   else if (memcmp (buf, "67 ", 3) != 0)
225     {
226       printf ("mq_receive buf \"%c%c%c\" != \"67 \"\n",
227 	      buf[0], buf[1], buf[2]);
228       result = 1;
229     }
230 
231   buf[0] = '2';
232   buf[1] = '1';
233   if (clock_gettime (CLOCK_REALTIME, &ts) != 0)
234     ts.tv_sec = time (NULL);
235   ts.tv_nsec = -1000000001;
236   if ((mq_timedsend (q, buf, 2, 5, &ts) != 0
237        && (errno != EINVAL || mq_send (q, buf, 2, 5) != 0))
238       || (buf[0] = '3', ts.tv_nsec = -ts.tv_nsec,
239 	  (mq_timedsend (q, buf, 1, 4, &ts) != 0
240 	   && (errno != EINVAL || mq_send (q, buf, 1, 4) != 0))))
241     {
242       printf ("mq_timedsend failed: %m\n");
243       result = 1;
244     }
245 
246   buf[0] = '-';
247   ts.tv_nsec = 1000000001;
248   if (mq_timedsend (q, buf, 1, 6, &ts) == 0)
249     {
250       puts ("mq_timedsend with tv_nsec >= 1000000000 did not fail");
251       result = 1;
252     }
253   else if (errno != EINVAL)
254     {
255       printf ("mq_timedsend with tv_nsec >= 1000000000 did not fail with "
256 	      "EINVAL: %m\n");
257       result = 1;
258     }
259 
260   ts.tv_nsec = -2;
261   if (mq_timedsend (q, buf, 1, 6, &ts) == 0)
262     {
263       puts ("mq_timedsend with negative tv_nsec did not fail");
264       result = 1;
265     }
266   else if (errno != EINVAL)
267     {
268       printf ("mq_timedsend with megatove tv_nsec did not fail with "
269 	      "EINVAL: %m\n");
270       result = 1;
271     }
272 
273   setitimer (ITIMER_REAL, &it, NULL);
274 
275   if (mq_send (q, buf, 2, 8) == 0)
276     {
277       puts ("mq_send on full queue did not block");
278       result = 1;
279     }
280   else if (errno != EINTR)
281     {
282       printf ("mq_send on full queue did not fail with EINTR: %m\n");
283       result = 1;
284     }
285 
286   setitimer (ITIMER_REAL, &it, NULL);
287 
288   ts.tv_sec += 10;
289   ts.tv_nsec = 0;
290   if (mq_timedsend (q, buf, 2, 7, &ts) == 0)
291     {
292       puts ("mq_timedsend on full queue did not block");
293       result = 1;
294     }
295   else if (errno != EINTR)
296     {
297       printf ("mq_timedsend on full queue did not fail with EINTR: %m\n");
298       result = 1;
299     }
300 
301   memset (buf, ' ', sizeof (buf));
302 
303   if (clock_gettime (CLOCK_REALTIME, &ts) != 0)
304     ts.tv_sec = time (NULL);
305   ts.tv_nsec = -1000000001;
306   rets = mq_timedreceive (q, buf, 2, &prio, &ts);
307   if (rets == -1 && errno == EINVAL)
308     rets = mq_receive (q, buf, 2, &prio);
309   if (rets != 2)
310     {
311       if (rets == -1)
312 	printf ("mq_timedreceive failed: %m\n");
313       else
314 	printf ("mq_timedreceive returned %zd != 2\n", rets);
315       result = 1;
316     }
317   else if (prio != 5 || memcmp (buf, "21 ", 3) != 0)
318     {
319       printf ("mq_timedreceive prio %u (5) buf \"%c%c%c\" (\"21 \")\n",
320 	      prio, buf[0], buf[1], buf[2]);
321       result = 1;
322     }
323 
324   if (mq_receive (q, buf, 1, NULL) == 0)
325     {
326       puts ("mq_receive with too small msg_len did not fail");
327       result = 1;
328     }
329   else if (errno != EMSGSIZE)
330     {
331       printf ("mq_receive with too small msg_len did not fail with "
332 	      "EMSGSIZE: %m\n");
333       result = 1;
334     }
335 
336   ts.tv_nsec = -ts.tv_nsec;
337   rets = mq_timedreceive (q, buf, 2, NULL, &ts);
338   if (rets == -1 && errno == EINVAL)
339     rets = mq_receive (q, buf, 2, NULL);
340   if (rets != 1)
341     {
342       if (rets == -1)
343 	printf ("mq_timedreceive failed: %m\n");
344       else
345 	printf ("mq_timedreceive returned %zd != 1\n", rets);
346       result = 1;
347     }
348   else if (memcmp (buf, "31 ", 3) != 0)
349     {
350       printf ("mq_timedreceive buf \"%c%c%c\" != \"31 \"\n",
351 	      buf[0], buf[1], buf[2]);
352       result = 1;
353     }
354 
355   if (mq_send (q, "", 0, 2) != 0)
356     {
357       printf ("mq_send with msg_len 0 failed: %m\n");
358       result = 1;
359     }
360 
361   rets = mq_receive (q, buf, 2, &prio);
362   if (rets)
363     {
364       if (rets == -1)
365 	printf ("mq_receive failed: %m\n");
366       else
367 	printf ("mq_receive returned %zd != 0\n", rets);
368       result = 1;
369     }
370 
371   long mq_prio_max = sysconf (_SC_MQ_PRIO_MAX);
372   if (mq_prio_max > 0 && (unsigned int) mq_prio_max == mq_prio_max)
373     {
374       if (mq_send (q, buf, 1, mq_prio_max) == 0)
375 	{
376 	  puts ("mq_send with MQ_PRIO_MAX priority unpexpectedly succeeded");
377 	  result = 1;
378 	}
379       else if (errno != EINVAL)
380 	{
381 	  printf ("mq_send with MQ_PRIO_MAX priority did not fail with "
382 		  "EINVAL: %m\n");
383 	  result = 1;
384 	}
385 
386       if (mq_send (q, buf, 1, mq_prio_max - 1) != 0)
387 	{
388 	  printf ("mq_send with MQ_PRIO_MAX-1 priority failed: %m\n");
389 	  result = 1;
390 	}
391     }
392 
393   if (mq_unlink (name) != 0)
394     {
395       printf ("mq_unlink failed: %m\n");
396       result = 1;
397     }
398 
399   q2 = mq_open (name, O_RDWR);
400   if (q2 != (mqd_t) -1)
401     {
402       printf ("mq_open of unlinked %s without O_CREAT unexpectedly"
403 	      "succeeded\n", name);
404       result = 1;
405     }
406   else if (errno != ENOENT)
407     {
408       printf ("mq_open of unlinked %s without O_CREAT did not fail with "
409 	      "ENOENT: %m\n", name);
410       result = 1;
411     }
412 
413   if (mq_close (q) != 0)
414     {
415       printf ("mq_close in parent failed: %m\n");
416       result = 1;
417     }
418 
419   if (mq_receive (q, buf, 2, NULL) == 0)
420     {
421       puts ("mq_receive on invalid mqd_t did not fail");
422       result = 1;
423     }
424   else if (errno != EBADF)
425     {
426       printf ("mq_receive on invalid mqd_t did not fail with EBADF: %m\n");
427       result = 1;
428     }
429 
430   if (mq_send (q, buf, 1, 2) == 0)
431     {
432       puts ("mq_send on invalid mqd_t did not fail");
433       result = 1;
434     }
435   else if (errno != EBADF)
436     {
437       printf ("mq_send on invalid mqd_t did not fail with EBADF: %m\n");
438       result = 1;
439     }
440 
441   if (mq_getattr (q, &attr) == 0)
442     {
443       puts ("mq_getattr on invalid mqd_t did not fail");
444       result = 1;
445     }
446   else if (errno != EBADF)
447     {
448       printf ("mq_getattr on invalid mqd_t did not fail with EBADF: %m\n");
449       result = 1;
450     }
451 
452   memset (&attr, 0, sizeof (attr));
453   if (mq_setattr (q, &attr, NULL) == 0)
454     {
455       puts ("mq_setattr on invalid mqd_t did not fail");
456       result = 1;
457     }
458   else if (errno != EBADF)
459     {
460       printf ("mq_setattr on invalid mqd_t did not fail with EBADF: %m\n");
461       result = 1;
462     }
463 
464   if (mq_unlink ("/tst-mqueue2-which-should-never-exist") != -1)
465     {
466       puts ("mq_unlink of non-existant message queue unexpectedly succeeded");
467       result = 1;
468     }
469   else if (errno != ENOENT)
470     {
471       printf ("mq_unlink of non-existant message queue did not fail with "
472 	      "ENOENT: %m\n");
473       result = 1;
474     }
475   return result;
476 }
477 
478 #include "../test-skeleton.c"
479