1 | /* Test message queue passing. |
2 | Copyright (C) 2004-2024 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 <limits.h> |
23 | #include <signal.h> |
24 | #include <stdio.h> |
25 | #include <stdint.h> |
26 | #include <stdlib.h> |
27 | #include <string.h> |
28 | #include <sys/time.h> |
29 | #include <sys/wait.h> |
30 | #include <time.h> |
31 | #include <unistd.h> |
32 | #include <support/check.h> |
33 | #include "tst-mqueue.h" |
34 | |
35 | #define TEST_FUNCTION do_test () |
36 | static int |
37 | do_test (void) |
38 | { |
39 | int result = 0; |
40 | |
41 | char name[sizeof "/tst-mqueue4-" + sizeof (pid_t) * 3 + NAME_MAX]; |
42 | char *p; |
43 | p = name + snprintf (s: name, maxlen: sizeof (name), format: "/tst-mqueue4-%u" , getpid ()); |
44 | struct mq_attr attr = { .mq_maxmsg = 2, .mq_msgsize = 2 }; |
45 | mqd_t q = mq_open (name: name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr); |
46 | |
47 | if (q == (mqd_t) -1) |
48 | { |
49 | if (errno == ENOSYS) |
50 | FAIL_UNSUPPORTED ("mq_open not supported" ); |
51 | |
52 | printf (format: "mq_open failed with: %m\n" ); |
53 | return 1; |
54 | } |
55 | |
56 | add_temp_mq (name); |
57 | |
58 | *p = '.'; |
59 | memset (p + 1, 'x', NAME_MAX + 1 - (p - name)); |
60 | name[NAME_MAX + 1] = '\0'; |
61 | |
62 | mqd_t q2 = mq_open (name: name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr); |
63 | if (q2 == (mqd_t) -1) |
64 | { |
65 | printf (format: "mq_open with NAME_MAX long name component failed with: %m\n" ); |
66 | result = 1; |
67 | } |
68 | |
69 | if (mq_unlink (name: name) != 0) |
70 | { |
71 | printf (format: "mq_unlink failed: %m\n" ); |
72 | result = 1; |
73 | } |
74 | |
75 | if (mq_close (mqdes: q2) != 0) |
76 | { |
77 | printf (format: "mq_close failed: %m\n" ); |
78 | result = 1; |
79 | } |
80 | |
81 | name[NAME_MAX + 1] = 'x'; |
82 | name[NAME_MAX + 2] = '\0'; |
83 | q2 = mq_open (name: name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr); |
84 | if (q2 != (mqd_t) -1) |
85 | { |
86 | puts (s: "mq_open with too long name component unexpectedly succeeded" ); |
87 | mq_unlink (name: name); |
88 | mq_close (mqdes: q2); |
89 | result = 1; |
90 | } |
91 | else if (errno != ENAMETOOLONG) |
92 | { |
93 | printf (format: "mq_open with too long name component did not fail with " |
94 | "ENAMETOOLONG: %m\n" ); |
95 | result = 1; |
96 | } |
97 | |
98 | if (mq_unlink (name: name) == 0) |
99 | { |
100 | puts (s: "mq_unlink with too long name component unexpectedly succeeded" ); |
101 | result = 1; |
102 | } |
103 | else if (errno != ENAMETOOLONG) |
104 | { |
105 | printf (format: "mq_unlink with too long name component did not fail with " |
106 | "ENAMETOOLONG: %m\n" ); |
107 | result = 1; |
108 | } |
109 | |
110 | *p = '\0'; |
111 | attr.mq_maxmsg = 1; |
112 | attr.mq_msgsize = 3; |
113 | q2 = mq_open (name: name, O_CREAT | O_RDWR, 0600, &attr); |
114 | if (q2 == (mqd_t) -1) |
115 | { |
116 | printf (format: "mq_open without O_EXCL failed with %m\n" ); |
117 | result = 1; |
118 | } |
119 | |
120 | char buf[3]; |
121 | strcpy (buf, "jk" ); |
122 | if (mq_send (mqdes: q, msg_ptr: buf, msg_len: 2, msg_prio: 4) != 0) |
123 | { |
124 | printf (format: "mq_send failed: %m\n" ); |
125 | result = 1; |
126 | } |
127 | |
128 | if (mq_send (mqdes: q, msg_ptr: buf + 1, msg_len: 1, msg_prio: 5) != 0) |
129 | { |
130 | printf (format: "mq_send failed: %m\n" ); |
131 | result = 1; |
132 | } |
133 | |
134 | if (mq_getattr (mqdes: q2, mqstat: &attr) != 0) |
135 | { |
136 | printf (format: "mq_getattr failed: %m\n" ); |
137 | result = 1; |
138 | } |
139 | |
140 | if ((attr.mq_flags & O_NONBLOCK) |
141 | || attr.mq_maxmsg != 2 |
142 | || attr.mq_msgsize != 2 |
143 | || attr.mq_curmsgs != 2) |
144 | { |
145 | printf (format: "mq_getattr returned unexpected { .mq_flags = %jd,\n" |
146 | ".mq_maxmsg = %jd, .mq_msgsize = %jd, .mq_curmsgs = %jd }\n" , |
147 | (intmax_t) attr.mq_flags, (intmax_t) attr.mq_maxmsg, |
148 | (intmax_t) attr.mq_msgsize, (intmax_t) attr.mq_curmsgs); |
149 | result = 1; |
150 | } |
151 | |
152 | struct timespec ts; |
153 | if (clock_gettime (CLOCK_REALTIME, tp: &ts) == 0) |
154 | ++ts.tv_sec; |
155 | else |
156 | { |
157 | ts.tv_sec = time (NULL) + 1; |
158 | ts.tv_nsec = 0; |
159 | } |
160 | |
161 | if (mq_timedsend (mqdes: q2, msg_ptr: buf, msg_len: 1, msg_prio: 1, abs_timeout: &ts) == 0) |
162 | { |
163 | puts (s: "mq_timedsend unexpectedly succeeded" ); |
164 | result = 1; |
165 | } |
166 | else if (errno != ETIMEDOUT) |
167 | { |
168 | printf (format: "mq_timedsend did not fail with ETIMEDOUT: %m\n" ); |
169 | result = 1; |
170 | } |
171 | |
172 | if (mq_close (mqdes: q2) != 0) |
173 | { |
174 | printf (format: "mq_close failed: %m\n" ); |
175 | result = 1; |
176 | } |
177 | |
178 | q2 = mq_open (name: name, O_RDONLY); |
179 | if (q2 == (mqd_t) -1) |
180 | { |
181 | printf (format: "mq_open without O_CREAT failed with %m\n" ); |
182 | result = 1; |
183 | } |
184 | |
185 | mqd_t q3 = mq_open (name: name, O_RDONLY); |
186 | if (q3 == (mqd_t) -1) |
187 | { |
188 | printf (format: "mq_open without O_CREAT failed with %m\n" ); |
189 | result = 1; |
190 | } |
191 | |
192 | memset (buf, ' ', sizeof (buf)); |
193 | |
194 | unsigned int prio; |
195 | ssize_t rets = mq_receive (mqdes: q2, msg_ptr: buf, msg_len: 2, msg_prio: &prio); |
196 | if (rets != 1) |
197 | { |
198 | if (rets == -1) |
199 | printf (format: "mq_receive failed with: %m\n" ); |
200 | else |
201 | printf (format: "mq_receive returned %zd != 1\n" , rets); |
202 | result = 1; |
203 | } |
204 | else if (prio != 5 || memcmp (buf, "k " , 3) != 0) |
205 | { |
206 | printf (format: "mq_receive returned prio %u (2) buf \"%c%c%c\" (\"k \")\n" , |
207 | prio, buf[0], buf[1], buf[2]); |
208 | result = 1; |
209 | } |
210 | |
211 | if (mq_getattr (mqdes: q3, mqstat: &attr) != 0) |
212 | { |
213 | printf (format: "mq_getattr failed: %m\n" ); |
214 | result = 1; |
215 | } |
216 | |
217 | if ((attr.mq_flags & O_NONBLOCK) |
218 | || attr.mq_maxmsg != 2 |
219 | || attr.mq_msgsize != 2 |
220 | || attr.mq_curmsgs != 1) |
221 | { |
222 | printf (format: "mq_getattr returned unexpected { .mq_flags = %jd,\n" |
223 | ".mq_maxmsg = %jd, .mq_msgsize = %jd, .mq_curmsgs = %jd }\n" , |
224 | (intmax_t) attr.mq_flags, (intmax_t) attr.mq_maxmsg, |
225 | (intmax_t) attr.mq_msgsize, (intmax_t) attr.mq_curmsgs); |
226 | result = 1; |
227 | } |
228 | |
229 | rets = mq_receive (mqdes: q3, msg_ptr: buf, msg_len: 2, NULL); |
230 | if (rets != 2) |
231 | { |
232 | if (rets == -1) |
233 | printf (format: "mq_receive failed with: %m\n" ); |
234 | else |
235 | printf (format: "mq_receive returned %zd != 2\n" , rets); |
236 | result = 1; |
237 | } |
238 | else if (memcmp (buf, "jk " , 3) != 0) |
239 | { |
240 | printf (format: "mq_receive returned buf \"%c%c%c\" != \"jk \"\n" , |
241 | buf[0], buf[1], buf[2]); |
242 | result = 1; |
243 | } |
244 | |
245 | if (clock_gettime (CLOCK_REALTIME, tp: &ts) == 0) |
246 | ++ts.tv_sec; |
247 | else |
248 | { |
249 | ts.tv_sec = time (NULL) + 1; |
250 | ts.tv_nsec = 0; |
251 | } |
252 | |
253 | if (mq_timedreceive (mqdes: q2, msg_ptr: buf, msg_len: 2, NULL, abs_timeout: &ts) != -1) |
254 | { |
255 | puts (s: "mq_timedreceive on empty queue unexpectedly succeeded" ); |
256 | result = 1; |
257 | } |
258 | else if (errno != ETIMEDOUT) |
259 | { |
260 | printf (format: "mq_timedreceive on empty queue did not fail with " |
261 | "ETIMEDOUT: %m\n" ); |
262 | result = 1; |
263 | } |
264 | |
265 | if (mq_unlink (name: name) != 0) |
266 | { |
267 | printf (format: "mq_unlink failed: %m\n" ); |
268 | result = 1; |
269 | } |
270 | |
271 | if (mq_close (mqdes: q) != 0) |
272 | { |
273 | printf (format: "mq_close failed: %m\n" ); |
274 | result = 1; |
275 | } |
276 | |
277 | if (mq_close (mqdes: q2) != 0) |
278 | { |
279 | printf (format: "mq_close failed: %m\n" ); |
280 | result = 1; |
281 | } |
282 | |
283 | if (mq_close (mqdes: q3) != 0) |
284 | { |
285 | printf (format: "mq_close failed: %m\n" ); |
286 | result = 1; |
287 | } |
288 | |
289 | return result; |
290 | } |
291 | |
292 | #include "../test-skeleton.c" |
293 | |