t_sysv.c revision 1.6 1 1.6 christos /* $NetBSD: t_sysv.c,v 1.6 2022/05/14 14:02:03 christos Exp $ */
2 1.1 pgoyette
3 1.1 pgoyette /*-
4 1.1 pgoyette * Copyright (c) 1999, 2007 The NetBSD Foundation, Inc.
5 1.1 pgoyette * All rights reserved.
6 1.1 pgoyette *
7 1.1 pgoyette * This code is derived from software contributed to The NetBSD Foundation
8 1.1 pgoyette * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9 1.1 pgoyette * NASA Ames Research Center, and by Andrew Doran.
10 1.1 pgoyette *
11 1.1 pgoyette * Redistribution and use in source and binary forms, with or without
12 1.1 pgoyette * modification, are permitted provided that the following conditions
13 1.1 pgoyette * are met:
14 1.1 pgoyette * 1. Redistributions of source code must retain the above copyright
15 1.1 pgoyette * notice, this list of conditions and the following disclaimer.
16 1.1 pgoyette * 2. Redistributions in binary form must reproduce the above copyright
17 1.1 pgoyette * notice, this list of conditions and the following disclaimer in the
18 1.1 pgoyette * documentation and/or other materials provided with the distribution.
19 1.1 pgoyette *
20 1.1 pgoyette * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 1.1 pgoyette * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 1.1 pgoyette * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 1.1 pgoyette * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 1.1 pgoyette * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 1.1 pgoyette * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 1.1 pgoyette * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 1.1 pgoyette * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 1.1 pgoyette * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 1.1 pgoyette * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 1.1 pgoyette * POSSIBILITY OF SUCH DAMAGE.
31 1.1 pgoyette */
32 1.1 pgoyette
33 1.1 pgoyette /*
34 1.1 pgoyette * Test the SVID-compatible Message Queue facility.
35 1.1 pgoyette */
36 1.1 pgoyette
37 1.1 pgoyette #include <atf-c.h>
38 1.1 pgoyette
39 1.1 pgoyette #include <err.h>
40 1.1 pgoyette #include <errno.h>
41 1.1 pgoyette #include <fcntl.h>
42 1.1 pgoyette #include <signal.h>
43 1.1 pgoyette #include <stdio.h>
44 1.1 pgoyette #include <stdlib.h>
45 1.1 pgoyette #include <string.h>
46 1.1 pgoyette #include <time.h>
47 1.1 pgoyette #include <unistd.h>
48 1.1 pgoyette
49 1.1 pgoyette #include <sys/ipc.h>
50 1.1 pgoyette #include <sys/msg.h>
51 1.1 pgoyette #include <sys/param.h>
52 1.1 pgoyette #include <sys/sem.h>
53 1.1 pgoyette #include <sys/shm.h>
54 1.1 pgoyette #include <sys/wait.h>
55 1.1 pgoyette
56 1.6 christos volatile int did_sigsys;
57 1.1 pgoyette
58 1.1 pgoyette void sigsys_handler(int);
59 1.1 pgoyette
60 1.2 pgoyette key_t get_ftok(int);
61 1.2 pgoyette
62 1.1 pgoyette void print_msqid_ds(struct msqid_ds *, mode_t);
63 1.1 pgoyette void receiver(void);
64 1.1 pgoyette
65 1.1 pgoyette void print_semid_ds(struct semid_ds *, mode_t);
66 1.1 pgoyette void waiter(void);
67 1.1 pgoyette
68 1.1 pgoyette void print_shmid_ds(struct shmid_ds *, mode_t);
69 1.1 pgoyette void sharer(void);
70 1.1 pgoyette
71 1.1 pgoyette #define MESSAGE_TEXT_LEN 256
72 1.1 pgoyette
73 1.5 pgoyette struct testmsg {
74 1.1 pgoyette long mtype;
75 1.1 pgoyette char mtext[MESSAGE_TEXT_LEN];
76 1.1 pgoyette };
77 1.1 pgoyette
78 1.1 pgoyette const char *m1_str = "California is overrated.";
79 1.1 pgoyette const char *m2_str = "The quick brown fox jumped over the lazy dog.";
80 1.1 pgoyette
81 1.1 pgoyette size_t pgsize;
82 1.1 pgoyette
83 1.1 pgoyette #define MTYPE_1 1
84 1.1 pgoyette #define MTYPE_1_ACK 2
85 1.1 pgoyette
86 1.1 pgoyette #define MTYPE_2 3
87 1.1 pgoyette #define MTYPE_2_ACK 4
88 1.1 pgoyette
89 1.1 pgoyette pid_t child_pid;
90 1.1 pgoyette
91 1.1 pgoyette key_t msgkey, semkey, shmkey;
92 1.1 pgoyette
93 1.1 pgoyette int maxloop = 1;
94 1.1 pgoyette
95 1.1 pgoyette union semun {
96 1.1 pgoyette int val; /* value for SETVAL */
97 1.1 pgoyette struct semid_ds *buf; /* buffer for IPC_{STAT,SET} */
98 1.1 pgoyette u_short *array; /* array for GETALL & SETALL */
99 1.1 pgoyette };
100 1.1 pgoyette
101 1.1 pgoyette
102 1.4 jmmv /* Writes an integer to a file. To be used from the body of the test
103 1.4 jmmv * cases below to pass any global identifiers to the cleanup routine. */
104 1.4 jmmv static void
105 1.4 jmmv write_int(const char *path, const int value)
106 1.4 jmmv {
107 1.4 jmmv int output;
108 1.4 jmmv
109 1.4 jmmv output = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0600);
110 1.4 jmmv ATF_REQUIRE_MSG(output != -1, "Failed to create %s", path);
111 1.4 jmmv write(output, &value, sizeof(value));
112 1.4 jmmv close(output);
113 1.4 jmmv }
114 1.4 jmmv
115 1.4 jmmv
116 1.4 jmmv /* Reads an integer from a file. To be used from the cleanup routines
117 1.4 jmmv * of the test cases below. */
118 1.4 jmmv static int
119 1.4 jmmv read_int(const char *path)
120 1.4 jmmv {
121 1.6 christos int input, value;
122 1.4 jmmv
123 1.4 jmmv input = open(path, O_RDONLY);
124 1.4 jmmv if (input == -1)
125 1.4 jmmv return -1;
126 1.6 christos
127 1.6 christos read(input, &value, sizeof(value));
128 1.6 christos return value;
129 1.4 jmmv }
130 1.4 jmmv
131 1.4 jmmv
132 1.1 pgoyette void
133 1.1 pgoyette sigsys_handler(int signo)
134 1.1 pgoyette {
135 1.1 pgoyette
136 1.1 pgoyette did_sigsys = 1;
137 1.1 pgoyette }
138 1.1 pgoyette
139 1.2 pgoyette key_t get_ftok(int id)
140 1.2 pgoyette {
141 1.2 pgoyette int fd;
142 1.2 pgoyette char token_key[64], token_dir[64];
143 1.2 pgoyette char *tmpdir;
144 1.2 pgoyette key_t key;
145 1.2 pgoyette
146 1.2 pgoyette strlcpy(token_key, "/tmp/t_sysv.XXXXXX", sizeof(token_key));
147 1.2 pgoyette tmpdir = mkdtemp(token_key);
148 1.2 pgoyette ATF_REQUIRE_MSG(tmpdir != NULL, "mkdtemp() failed: %d", errno);
149 1.2 pgoyette
150 1.2 pgoyette strlcpy(token_dir, tmpdir, sizeof(token_dir));
151 1.2 pgoyette strlcpy(token_key, tmpdir, sizeof(token_key));
152 1.2 pgoyette strlcat(token_key, "/token_key", sizeof(token_key));
153 1.2 pgoyette
154 1.2 pgoyette /* Create the file, since ftok() requires it to exist! */
155 1.2 pgoyette
156 1.5 pgoyette fd = open(token_key, O_RDWR | O_CREAT | O_EXCL, 0600);
157 1.2 pgoyette if (fd == -1) {
158 1.2 pgoyette rmdir(tmpdir);
159 1.2 pgoyette atf_tc_fail("open() of temp file failed: %d", errno);
160 1.2 pgoyette return (key_t)-1;
161 1.6 christos }
162 1.6 christos
163 1.6 christos close(fd);
164 1.2 pgoyette
165 1.2 pgoyette key = ftok(token_key, id);
166 1.5 pgoyette ATF_REQUIRE_MSG(key != (key_t)-1, "ftok() failed");
167 1.2 pgoyette
168 1.2 pgoyette ATF_REQUIRE_MSG(unlink(token_key) != -1, "unlink() failed: %d", errno);
169 1.2 pgoyette ATF_REQUIRE_MSG(rmdir(token_dir) != -1, "rmdir() failed: %d", errno);
170 1.2 pgoyette
171 1.2 pgoyette return key;
172 1.2 pgoyette }
173 1.2 pgoyette
174 1.2 pgoyette ATF_TC_WITH_CLEANUP(msg);
175 1.1 pgoyette ATF_TC_HEAD(msg, tc)
176 1.1 pgoyette {
177 1.1 pgoyette
178 1.1 pgoyette atf_tc_set_md_var(tc, "timeout", "3");
179 1.1 pgoyette atf_tc_set_md_var(tc, "descr", "Checks sysvmsg passing");
180 1.1 pgoyette }
181 1.1 pgoyette
182 1.1 pgoyette ATF_TC_BODY(msg, tc)
183 1.1 pgoyette {
184 1.1 pgoyette struct sigaction sa;
185 1.1 pgoyette struct msqid_ds m_ds;
186 1.5 pgoyette struct testmsg m;
187 1.4 jmmv int sender_msqid;
188 1.1 pgoyette int loop;
189 1.1 pgoyette int c_status;
190 1.6 christos pid_t wait_result;
191 1.1 pgoyette
192 1.1 pgoyette /*
193 1.1 pgoyette * Install a SIGSYS handler so that we can exit gracefully if
194 1.1 pgoyette * System V Message Queue support isn't in the kernel.
195 1.1 pgoyette */
196 1.1 pgoyette did_sigsys = 0;
197 1.1 pgoyette sa.sa_handler = sigsys_handler;
198 1.1 pgoyette sigemptyset(&sa.sa_mask);
199 1.1 pgoyette sa.sa_flags = 0;
200 1.1 pgoyette ATF_REQUIRE_MSG(sigaction(SIGSYS, &sa, NULL) != -1,
201 1.1 pgoyette "sigaction SIGSYS: %d", errno);
202 1.1 pgoyette
203 1.2 pgoyette msgkey = get_ftok(4160);
204 1.2 pgoyette ATF_REQUIRE_MSG(msgkey != (key_t)-1, "get_ftok failed");
205 1.1 pgoyette
206 1.1 pgoyette sender_msqid = msgget(msgkey, IPC_CREAT | 0640);
207 1.1 pgoyette ATF_REQUIRE_MSG(sender_msqid != -1, "msgget: %d", errno);
208 1.4 jmmv write_int("sender_msqid", sender_msqid);
209 1.1 pgoyette
210 1.1 pgoyette if (did_sigsys) {
211 1.1 pgoyette atf_tc_skip("SYSV Message Queue not supported");
212 1.1 pgoyette return;
213 1.1 pgoyette }
214 1.1 pgoyette
215 1.1 pgoyette ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds) != -1,
216 1.1 pgoyette "msgctl IPC_STAT 1: %d", errno);
217 1.1 pgoyette
218 1.1 pgoyette print_msqid_ds(&m_ds, 0640);
219 1.1 pgoyette
220 1.1 pgoyette m_ds.msg_perm.mode = (m_ds.msg_perm.mode & ~0777) | 0600;
221 1.1 pgoyette
222 1.1 pgoyette ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_SET, &m_ds) != -1,
223 1.1 pgoyette "msgctl IPC_SET: %d", errno);
224 1.1 pgoyette
225 1.1 pgoyette memset(&m_ds, 0, sizeof(m_ds));
226 1.1 pgoyette
227 1.1 pgoyette ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds) != -1,
228 1.1 pgoyette "msgctl IPC_STAT 2: %d", errno);
229 1.1 pgoyette
230 1.1 pgoyette ATF_REQUIRE_MSG((m_ds.msg_perm.mode & 0777) == 0600,
231 1.1 pgoyette "IPC_SET of mode didn't hold");
232 1.1 pgoyette
233 1.1 pgoyette print_msqid_ds(&m_ds, 0600);
234 1.1 pgoyette
235 1.6 christos fflush(stdout);
236 1.6 christos
237 1.1 pgoyette switch ((child_pid = fork())) {
238 1.1 pgoyette case -1:
239 1.1 pgoyette atf_tc_fail("fork: %d", errno);
240 1.1 pgoyette return;
241 1.1 pgoyette
242 1.1 pgoyette case 0:
243 1.1 pgoyette receiver();
244 1.1 pgoyette break;
245 1.1 pgoyette
246 1.1 pgoyette default:
247 1.1 pgoyette break;
248 1.1 pgoyette }
249 1.1 pgoyette
250 1.1 pgoyette for (loop = 0; loop < maxloop; loop++) {
251 1.1 pgoyette /*
252 1.1 pgoyette * Send the first message to the receiver and wait for the ACK.
253 1.1 pgoyette */
254 1.1 pgoyette m.mtype = MTYPE_1;
255 1.1 pgoyette strcpy(m.mtext, m1_str);
256 1.3 skrll ATF_REQUIRE_MSG(msgsnd(sender_msqid, &m, MESSAGE_TEXT_LEN,
257 1.3 skrll 0) != -1, "sender: msgsnd 1: %d", errno);
258 1.1 pgoyette
259 1.3 skrll ATF_REQUIRE_MSG(msgrcv(sender_msqid, &m, MESSAGE_TEXT_LEN,
260 1.6 christos MTYPE_1_ACK, 0) == MESSAGE_TEXT_LEN,
261 1.1 pgoyette "sender: msgrcv 1 ack: %d", errno);
262 1.1 pgoyette
263 1.1 pgoyette print_msqid_ds(&m_ds, 0600);
264 1.1 pgoyette
265 1.1 pgoyette /*
266 1.1 pgoyette * Send the second message to the receiver and wait for the ACK.
267 1.1 pgoyette */
268 1.1 pgoyette m.mtype = MTYPE_2;
269 1.1 pgoyette strcpy(m.mtext, m2_str);
270 1.6 christos ATF_REQUIRE_MSG(msgsnd(sender_msqid, &m, MESSAGE_TEXT_LEN, 0)
271 1.6 christos != -1, "sender: msgsnd 2: %d", errno);
272 1.1 pgoyette
273 1.3 skrll ATF_REQUIRE_MSG(msgrcv(sender_msqid, &m, MESSAGE_TEXT_LEN,
274 1.6 christos MTYPE_2_ACK, 0) == MESSAGE_TEXT_LEN,
275 1.1 pgoyette "sender: msgrcv 2 ack: %d", errno);
276 1.1 pgoyette }
277 1.1 pgoyette
278 1.1 pgoyette /*
279 1.1 pgoyette * Wait for child to finish
280 1.1 pgoyette */
281 1.6 christos wait_result = wait(&c_status);
282 1.6 christos ATF_REQUIRE_EQ_MSG(wait_result, child_pid, "wait returned %d (%s)",
283 1.6 christos wait_result, wait_result == -1 ? strerror(errno) : "");
284 1.6 christos ATF_REQUIRE_MSG(WIFEXITED(c_status), "child abnormal exit: %d (sig %d)",
285 1.6 christos c_status, WTERMSIG(c_status));
286 1.6 christos ATF_REQUIRE_EQ_MSG(WEXITSTATUS(c_status), 0, "child status: %d",
287 1.6 christos WEXITSTATUS(c_status));
288 1.1 pgoyette
289 1.6 christos ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds) != -1,
290 1.6 christos "msgctl IPC_STAT: %d", errno);
291 1.1 pgoyette
292 1.6 christos print_msqid_ds(&m_ds, 0600);
293 1.1 pgoyette }
294 1.1 pgoyette
295 1.2 pgoyette ATF_TC_CLEANUP(msg, tc)
296 1.1 pgoyette {
297 1.4 jmmv int sender_msqid;
298 1.1 pgoyette
299 1.1 pgoyette /*
300 1.2 pgoyette * Remove the message queue if it exists.
301 1.1 pgoyette */
302 1.4 jmmv sender_msqid = read_int("sender_msqid");
303 1.6 christos if (sender_msqid == -1)
304 1.6 christos return;
305 1.6 christos if (msgctl(sender_msqid, IPC_RMID, NULL) == -1)
306 1.6 christos err(EXIT_FAILURE, "msgctl IPC_RMID");
307 1.1 pgoyette }
308 1.1 pgoyette
309 1.1 pgoyette void
310 1.5 pgoyette print_msqid_ds(struct msqid_ds *mp, mode_t mode)
311 1.1 pgoyette {
312 1.1 pgoyette uid_t uid = geteuid();
313 1.1 pgoyette gid_t gid = getegid();
314 1.1 pgoyette
315 1.1 pgoyette printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n",
316 1.1 pgoyette mp->msg_perm.uid, mp->msg_perm.gid,
317 1.1 pgoyette mp->msg_perm.cuid, mp->msg_perm.cgid,
318 1.1 pgoyette mp->msg_perm.mode & 0777);
319 1.1 pgoyette
320 1.6 christos printf("qnum %lu, qbytes %ju, lspid %d, lrpid %d\n",
321 1.6 christos mp->msg_qnum, (uintmax_t)mp->msg_qbytes, mp->msg_lspid,
322 1.1 pgoyette mp->msg_lrpid);
323 1.1 pgoyette
324 1.1 pgoyette printf("stime: %s", ctime(&mp->msg_stime));
325 1.1 pgoyette printf("rtime: %s", ctime(&mp->msg_rtime));
326 1.1 pgoyette printf("ctime: %s", ctime(&mp->msg_ctime));
327 1.1 pgoyette
328 1.1 pgoyette /*
329 1.1 pgoyette * Sanity check a few things.
330 1.1 pgoyette */
331 1.1 pgoyette
332 1.1 pgoyette ATF_REQUIRE_MSG(mp->msg_perm.uid == uid && mp->msg_perm.cuid == uid,
333 1.1 pgoyette "uid mismatch");
334 1.1 pgoyette
335 1.1 pgoyette ATF_REQUIRE_MSG(mp->msg_perm.gid == gid && mp->msg_perm.cgid == gid,
336 1.1 pgoyette "gid mismatch");
337 1.1 pgoyette
338 1.1 pgoyette ATF_REQUIRE_MSG((mp->msg_perm.mode & 0777) == mode, "mode mismatch");
339 1.1 pgoyette }
340 1.1 pgoyette
341 1.1 pgoyette void
342 1.5 pgoyette receiver(void)
343 1.1 pgoyette {
344 1.5 pgoyette struct testmsg m;
345 1.1 pgoyette int msqid, loop;
346 1.1 pgoyette
347 1.1 pgoyette if ((msqid = msgget(msgkey, 0)) == -1)
348 1.6 christos err(EXIT_FAILURE, "receiver: msgget");
349 1.1 pgoyette
350 1.1 pgoyette for (loop = 0; loop < maxloop; loop++) {
351 1.1 pgoyette /*
352 1.1 pgoyette * Receive the first message, print it, and send an ACK.
353 1.1 pgoyette */
354 1.6 christos if (msgrcv(msqid, &m, MESSAGE_TEXT_LEN, MTYPE_1, 0)
355 1.6 christos != MESSAGE_TEXT_LEN)
356 1.6 christos err(EXIT_FAILURE, "receiver: msgrcv 1");
357 1.1 pgoyette
358 1.1 pgoyette printf("%s\n", m.mtext);
359 1.1 pgoyette if (strcmp(m.mtext, m1_str) != 0)
360 1.6 christos errx(EXIT_FAILURE,
361 1.6 christos "receiver: message 1 data isn't correct");
362 1.1 pgoyette
363 1.1 pgoyette m.mtype = MTYPE_1_ACK;
364 1.1 pgoyette
365 1.3 skrll if (msgsnd(msqid, &m, MESSAGE_TEXT_LEN, 0) == -1)
366 1.6 christos err(EXIT_FAILURE, "receiver: msgsnd ack 1");
367 1.1 pgoyette
368 1.1 pgoyette /*
369 1.1 pgoyette * Receive the second message, print it, and send an ACK.
370 1.1 pgoyette */
371 1.1 pgoyette
372 1.6 christos if (msgrcv(msqid, &m, MESSAGE_TEXT_LEN, MTYPE_2, 0)
373 1.6 christos != MESSAGE_TEXT_LEN)
374 1.6 christos err(EXIT_FAILURE, "receiver: msgrcv 2");
375 1.1 pgoyette
376 1.1 pgoyette printf("%s\n", m.mtext);
377 1.1 pgoyette if (strcmp(m.mtext, m2_str) != 0)
378 1.6 christos errx(EXIT_FAILURE,
379 1.6 christos "receiver: message 2 data isn't correct");
380 1.1 pgoyette
381 1.1 pgoyette m.mtype = MTYPE_2_ACK;
382 1.1 pgoyette
383 1.3 skrll if (msgsnd(msqid, &m, MESSAGE_TEXT_LEN, 0) == -1)
384 1.6 christos err(EXIT_FAILURE, "receiver: msgsnd ack 2");
385 1.1 pgoyette }
386 1.1 pgoyette
387 1.6 christos exit(EXIT_SUCCESS);
388 1.1 pgoyette }
389 1.1 pgoyette
390 1.1 pgoyette /*
391 1.1 pgoyette * Test the SVID-compatible Semaphore facility.
392 1.1 pgoyette */
393 1.1 pgoyette
394 1.2 pgoyette ATF_TC_WITH_CLEANUP(sem);
395 1.1 pgoyette ATF_TC_HEAD(sem, tc)
396 1.1 pgoyette {
397 1.1 pgoyette
398 1.1 pgoyette atf_tc_set_md_var(tc, "timeout", "3");
399 1.1 pgoyette atf_tc_set_md_var(tc, "descr", "Checks sysvmsg passing");
400 1.1 pgoyette }
401 1.1 pgoyette
402 1.1 pgoyette ATF_TC_BODY(sem, tc)
403 1.1 pgoyette {
404 1.1 pgoyette struct sigaction sa;
405 1.1 pgoyette union semun sun;
406 1.1 pgoyette struct semid_ds s_ds;
407 1.4 jmmv int sender_semid;
408 1.1 pgoyette int i;
409 1.1 pgoyette int c_status;
410 1.6 christos int child_count;
411 1.6 christos pid_t wait_result;
412 1.1 pgoyette
413 1.1 pgoyette /*
414 1.1 pgoyette * Install a SIGSYS handler so that we can exit gracefully if
415 1.1 pgoyette * System V Semaphore support isn't in the kernel.
416 1.1 pgoyette */
417 1.1 pgoyette did_sigsys = 0;
418 1.1 pgoyette sa.sa_handler = sigsys_handler;
419 1.1 pgoyette sigemptyset(&sa.sa_mask);
420 1.1 pgoyette sa.sa_flags = 0;
421 1.1 pgoyette ATF_REQUIRE_MSG(sigaction(SIGSYS, &sa, NULL) != -1,
422 1.1 pgoyette "sigaction SIGSYS: %d", errno);
423 1.1 pgoyette
424 1.2 pgoyette semkey = get_ftok(4160);
425 1.2 pgoyette ATF_REQUIRE_MSG(semkey != (key_t)-1, "get_ftok failed");
426 1.1 pgoyette
427 1.1 pgoyette sender_semid = semget(semkey, 1, IPC_CREAT | 0640);
428 1.1 pgoyette ATF_REQUIRE_MSG(sender_semid != -1, "semget: %d", errno);
429 1.4 jmmv write_int("sender_semid", sender_semid);
430 1.1 pgoyette
431 1.1 pgoyette if (did_sigsys) {
432 1.1 pgoyette atf_tc_skip("SYSV Semaphore not supported");
433 1.1 pgoyette return;
434 1.1 pgoyette }
435 1.1 pgoyette
436 1.1 pgoyette sun.buf = &s_ds;
437 1.1 pgoyette ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_STAT, sun) != -1,
438 1.1 pgoyette "semctl IPC_STAT: %d", errno);
439 1.1 pgoyette
440 1.1 pgoyette print_semid_ds(&s_ds, 0640);
441 1.1 pgoyette
442 1.1 pgoyette s_ds.sem_perm.mode = (s_ds.sem_perm.mode & ~0777) | 0600;
443 1.1 pgoyette
444 1.1 pgoyette sun.buf = &s_ds;
445 1.1 pgoyette ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_SET, sun) != -1,
446 1.1 pgoyette "semctl IPC_SET: %d", errno);
447 1.1 pgoyette
448 1.1 pgoyette memset(&s_ds, 0, sizeof(s_ds));
449 1.1 pgoyette
450 1.1 pgoyette sun.buf = &s_ds;
451 1.1 pgoyette ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_STAT, sun) != -1,
452 1.1 pgoyette "semctl IPC_STAT: %d", errno);
453 1.1 pgoyette
454 1.1 pgoyette ATF_REQUIRE_MSG((s_ds.sem_perm.mode & 0777) == 0600,
455 1.1 pgoyette "IPC_SET of mode didn't hold");
456 1.1 pgoyette
457 1.1 pgoyette print_semid_ds(&s_ds, 0600);
458 1.1 pgoyette
459 1.6 christos fflush(stdout);
460 1.6 christos
461 1.1 pgoyette for (child_count = 0; child_count < 5; child_count++) {
462 1.1 pgoyette switch ((child_pid = fork())) {
463 1.1 pgoyette case -1:
464 1.1 pgoyette atf_tc_fail("fork: %d", errno);
465 1.1 pgoyette return;
466 1.1 pgoyette
467 1.1 pgoyette case 0:
468 1.1 pgoyette waiter();
469 1.1 pgoyette break;
470 1.1 pgoyette
471 1.1 pgoyette default:
472 1.1 pgoyette break;
473 1.1 pgoyette }
474 1.1 pgoyette }
475 1.1 pgoyette
476 1.1 pgoyette /*
477 1.1 pgoyette * Wait for all of the waiters to be attempting to acquire the
478 1.1 pgoyette * semaphore.
479 1.1 pgoyette */
480 1.1 pgoyette for (;;) {
481 1.1 pgoyette i = semctl(sender_semid, 0, GETNCNT);
482 1.1 pgoyette if (i == -1)
483 1.1 pgoyette atf_tc_fail("semctl GETNCNT: %d", i);
484 1.1 pgoyette if (i == 5)
485 1.1 pgoyette break;
486 1.1 pgoyette }
487 1.1 pgoyette
488 1.1 pgoyette /*
489 1.1 pgoyette * Now set the thundering herd in motion by initializing the
490 1.1 pgoyette * semaphore to the value 1.
491 1.1 pgoyette */
492 1.1 pgoyette sun.val = 1;
493 1.1 pgoyette ATF_REQUIRE_MSG(semctl(sender_semid, 0, SETVAL, sun) != -1,
494 1.1 pgoyette "sender: semctl SETVAL to 1: %d", errno);
495 1.1 pgoyette
496 1.1 pgoyette /*
497 1.1 pgoyette * Wait for all children to finish
498 1.1 pgoyette */
499 1.6 christos while (child_count-- > 0) {
500 1.6 christos wait_result = wait(&c_status);
501 1.6 christos ATF_REQUIRE_MSG(wait_result != -1, "wait failed: %s",
502 1.6 christos strerror(errno));
503 1.6 christos ATF_REQUIRE_MSG(WIFEXITED(c_status),
504 1.6 christos "child abnormal exit: %d (sig %d)",
505 1.6 christos c_status, WTERMSIG(c_status));
506 1.6 christos ATF_REQUIRE_EQ_MSG(WEXITSTATUS(c_status), 0, "child status: %d",
507 1.6 christos WEXITSTATUS(c_status));
508 1.6 christos
509 1.6 christos sun.buf = &s_ds;
510 1.6 christos ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_STAT, sun) != -1,
511 1.6 christos "semctl IPC_STAT: %d", errno);
512 1.6 christos
513 1.6 christos print_semid_ds(&s_ds, 0600);
514 1.1 pgoyette }
515 1.1 pgoyette }
516 1.1 pgoyette
517 1.2 pgoyette ATF_TC_CLEANUP(sem, tc)
518 1.1 pgoyette {
519 1.4 jmmv int sender_semid;
520 1.1 pgoyette
521 1.1 pgoyette /*
522 1.2 pgoyette * Remove the semaphore if it exists
523 1.1 pgoyette */
524 1.4 jmmv sender_semid = read_int("sender_semid");
525 1.6 christos if (sender_semid == -1)
526 1.6 christos return;
527 1.6 christos if (semctl(sender_semid, 0, IPC_RMID) == -1)
528 1.6 christos err(EXIT_FAILURE, "semctl IPC_RMID");
529 1.1 pgoyette }
530 1.1 pgoyette
531 1.1 pgoyette void
532 1.5 pgoyette print_semid_ds(struct semid_ds *sp, mode_t mode)
533 1.1 pgoyette {
534 1.1 pgoyette uid_t uid = geteuid();
535 1.1 pgoyette gid_t gid = getegid();
536 1.1 pgoyette
537 1.1 pgoyette printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n",
538 1.1 pgoyette sp->sem_perm.uid, sp->sem_perm.gid,
539 1.1 pgoyette sp->sem_perm.cuid, sp->sem_perm.cgid,
540 1.1 pgoyette sp->sem_perm.mode & 0777);
541 1.1 pgoyette
542 1.1 pgoyette printf("nsems %u\n", sp->sem_nsems);
543 1.1 pgoyette
544 1.1 pgoyette printf("otime: %s", ctime(&sp->sem_otime));
545 1.1 pgoyette printf("ctime: %s", ctime(&sp->sem_ctime));
546 1.1 pgoyette
547 1.1 pgoyette /*
548 1.1 pgoyette * Sanity check a few things.
549 1.1 pgoyette */
550 1.1 pgoyette
551 1.1 pgoyette ATF_REQUIRE_MSG(sp->sem_perm.uid == uid && sp->sem_perm.cuid == uid,
552 1.1 pgoyette "uid mismatch");
553 1.1 pgoyette
554 1.1 pgoyette ATF_REQUIRE_MSG(sp->sem_perm.gid == gid && sp->sem_perm.cgid == gid,
555 1.1 pgoyette "gid mismatch");
556 1.1 pgoyette
557 1.1 pgoyette ATF_REQUIRE_MSG((sp->sem_perm.mode & 0777) == mode,
558 1.1 pgoyette "mode mismatch %o != %o", (sp->sem_perm.mode & 0777), mode);
559 1.1 pgoyette }
560 1.1 pgoyette
561 1.1 pgoyette void
562 1.5 pgoyette waiter(void)
563 1.1 pgoyette {
564 1.1 pgoyette struct sembuf s;
565 1.1 pgoyette int semid;
566 1.1 pgoyette
567 1.1 pgoyette if ((semid = semget(semkey, 1, 0)) == -1)
568 1.6 christos err(EXIT_FAILURE, "waiter: semget");
569 1.1 pgoyette
570 1.1 pgoyette /*
571 1.1 pgoyette * Attempt to acquire the semaphore.
572 1.1 pgoyette */
573 1.1 pgoyette s.sem_num = 0;
574 1.1 pgoyette s.sem_op = -1;
575 1.1 pgoyette s.sem_flg = SEM_UNDO;
576 1.1 pgoyette
577 1.1 pgoyette if (semop(semid, &s, 1) == -1)
578 1.6 christos err(EXIT_FAILURE, "waiter: semop -1");
579 1.1 pgoyette
580 1.1 pgoyette printf("WOO! GOT THE SEMAPHORE!\n");
581 1.6 christos usleep(10000);
582 1.1 pgoyette
583 1.1 pgoyette /*
584 1.1 pgoyette * Release the semaphore and exit.
585 1.1 pgoyette */
586 1.1 pgoyette s.sem_num = 0;
587 1.1 pgoyette s.sem_op = 1;
588 1.1 pgoyette s.sem_flg = SEM_UNDO;
589 1.1 pgoyette
590 1.1 pgoyette if (semop(semid, &s, 1) == -1)
591 1.6 christos err(EXIT_FAILURE, "waiter: semop +1");
592 1.1 pgoyette
593 1.6 christos exit(EXIT_SUCCESS);
594 1.1 pgoyette }
595 1.1 pgoyette
596 1.1 pgoyette /*
597 1.1 pgoyette * Test the SVID-compatible Shared Memory facility.
598 1.1 pgoyette */
599 1.1 pgoyette
600 1.2 pgoyette ATF_TC_WITH_CLEANUP(shm);
601 1.1 pgoyette ATF_TC_HEAD(shm, tc)
602 1.1 pgoyette {
603 1.1 pgoyette
604 1.1 pgoyette atf_tc_set_md_var(tc, "timeout", "3");
605 1.1 pgoyette atf_tc_set_md_var(tc, "descr", "Checks sysv shared memory");
606 1.1 pgoyette }
607 1.1 pgoyette
608 1.1 pgoyette ATF_TC_BODY(shm, tc)
609 1.1 pgoyette {
610 1.1 pgoyette struct sigaction sa;
611 1.1 pgoyette struct shmid_ds s_ds;
612 1.1 pgoyette char *shm_buf;
613 1.4 jmmv int sender_shmid;
614 1.1 pgoyette int c_status;
615 1.6 christos pid_t wait_result;
616 1.1 pgoyette
617 1.1 pgoyette /*
618 1.1 pgoyette * Install a SIGSYS handler so that we can exit gracefully if
619 1.1 pgoyette * System V Shared Memory support isn't in the kernel.
620 1.1 pgoyette */
621 1.1 pgoyette did_sigsys = 0;
622 1.1 pgoyette sa.sa_handler = sigsys_handler;
623 1.1 pgoyette sigemptyset(&sa.sa_mask);
624 1.1 pgoyette sa.sa_flags = 0;
625 1.1 pgoyette ATF_REQUIRE_MSG(sigaction(SIGSYS, &sa, NULL) != -1,
626 1.1 pgoyette "sigaction SIGSYS: %d", errno);
627 1.1 pgoyette
628 1.1 pgoyette pgsize = sysconf(_SC_PAGESIZE);
629 1.1 pgoyette
630 1.2 pgoyette shmkey = get_ftok(4160);
631 1.2 pgoyette ATF_REQUIRE_MSG(shmkey != (key_t)-1, "get_ftok failed");
632 1.1 pgoyette
633 1.1 pgoyette ATF_REQUIRE_MSG((sender_shmid = shmget(shmkey, pgsize,
634 1.1 pgoyette IPC_CREAT | 0640)) != -1,
635 1.1 pgoyette "shmget: %d", errno);
636 1.4 jmmv write_int("sender_shmid", sender_shmid);
637 1.1 pgoyette
638 1.1 pgoyette ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_STAT, &s_ds) != -1,
639 1.1 pgoyette "shmctl IPC_STAT: %d", errno);
640 1.1 pgoyette
641 1.1 pgoyette print_shmid_ds(&s_ds, 0640);
642 1.1 pgoyette
643 1.1 pgoyette s_ds.shm_perm.mode = (s_ds.shm_perm.mode & ~0777) | 0600;
644 1.1 pgoyette
645 1.1 pgoyette ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_SET, &s_ds) != -1,
646 1.1 pgoyette "shmctl IPC_SET: %d", errno);
647 1.1 pgoyette
648 1.1 pgoyette memset(&s_ds, 0, sizeof(s_ds));
649 1.1 pgoyette
650 1.1 pgoyette ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_STAT, &s_ds) != -1,
651 1.1 pgoyette "shmctl IPC_STAT: %d", errno);
652 1.1 pgoyette
653 1.1 pgoyette ATF_REQUIRE_MSG((s_ds.shm_perm.mode & 0777) == 0600,
654 1.1 pgoyette "IPC_SET of mode didn't hold");
655 1.1 pgoyette
656 1.1 pgoyette print_shmid_ds(&s_ds, 0600);
657 1.1 pgoyette
658 1.1 pgoyette shm_buf = shmat(sender_shmid, NULL, 0);
659 1.1 pgoyette ATF_REQUIRE_MSG(shm_buf != (void *) -1, "sender: shmat: %d", errno);
660 1.1 pgoyette
661 1.1 pgoyette /*
662 1.1 pgoyette * Write the test pattern into the shared memory buffer.
663 1.1 pgoyette */
664 1.1 pgoyette strcpy(shm_buf, m2_str);
665 1.1 pgoyette
666 1.6 christos fflush(stdout);
667 1.6 christos
668 1.1 pgoyette switch ((child_pid = fork())) {
669 1.1 pgoyette case -1:
670 1.1 pgoyette atf_tc_fail("fork: %d", errno);
671 1.1 pgoyette return;
672 1.1 pgoyette
673 1.1 pgoyette case 0:
674 1.1 pgoyette sharer();
675 1.1 pgoyette break;
676 1.1 pgoyette
677 1.1 pgoyette default:
678 1.1 pgoyette break;
679 1.1 pgoyette }
680 1.1 pgoyette
681 1.1 pgoyette /*
682 1.1 pgoyette * Wait for child to finish
683 1.1 pgoyette */
684 1.6 christos wait_result = wait(&c_status);
685 1.6 christos ATF_REQUIRE_EQ_MSG(wait_result, child_pid, "wait returned %d (%s)",
686 1.6 christos wait_result, wait_result == -1 ? strerror(errno) : "");
687 1.6 christos ATF_REQUIRE_MSG(WIFEXITED(c_status), "child abnormal exit: %d (sig %d)",
688 1.6 christos c_status, WTERMSIG(c_status));
689 1.6 christos ATF_REQUIRE_EQ_MSG(WEXITSTATUS(c_status), 0, "child status: %d",
690 1.6 christos WEXITSTATUS(c_status));
691 1.1 pgoyette
692 1.6 christos ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_STAT, &s_ds) != -1,
693 1.6 christos "shmctl IPC_STAT: %d", errno);
694 1.1 pgoyette
695 1.6 christos print_shmid_ds(&s_ds, 0600);
696 1.1 pgoyette }
697 1.1 pgoyette
698 1.2 pgoyette ATF_TC_CLEANUP(shm, tc)
699 1.1 pgoyette {
700 1.4 jmmv int sender_shmid;
701 1.1 pgoyette
702 1.1 pgoyette /*
703 1.2 pgoyette * Remove the shared memory area if it exists.
704 1.1 pgoyette */
705 1.4 jmmv sender_shmid = read_int("sender_shmid");
706 1.6 christos if (sender_shmid == -1)
707 1.6 christos return;
708 1.6 christos if (shmctl(sender_shmid, IPC_RMID, NULL) == -1)
709 1.6 christos err(EXIT_FAILURE, "shmctl IPC_RMID");
710 1.1 pgoyette }
711 1.1 pgoyette
712 1.1 pgoyette void
713 1.5 pgoyette print_shmid_ds(struct shmid_ds *sp, mode_t mode)
714 1.1 pgoyette {
715 1.1 pgoyette uid_t uid = geteuid();
716 1.1 pgoyette gid_t gid = getegid();
717 1.1 pgoyette
718 1.1 pgoyette printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n",
719 1.1 pgoyette sp->shm_perm.uid, sp->shm_perm.gid,
720 1.1 pgoyette sp->shm_perm.cuid, sp->shm_perm.cgid,
721 1.1 pgoyette sp->shm_perm.mode & 0777);
722 1.1 pgoyette
723 1.6 christos printf("segsz %ju, lpid %d, cpid %d, nattch %u\n",
724 1.6 christos (uintmax_t)sp->shm_segsz, sp->shm_lpid, sp->shm_cpid,
725 1.1 pgoyette sp->shm_nattch);
726 1.1 pgoyette
727 1.1 pgoyette printf("atime: %s", ctime(&sp->shm_atime));
728 1.1 pgoyette printf("dtime: %s", ctime(&sp->shm_dtime));
729 1.1 pgoyette printf("ctime: %s", ctime(&sp->shm_ctime));
730 1.1 pgoyette
731 1.1 pgoyette /*
732 1.1 pgoyette * Sanity check a few things.
733 1.1 pgoyette */
734 1.1 pgoyette
735 1.1 pgoyette ATF_REQUIRE_MSG(sp->shm_perm.uid == uid && sp->shm_perm.cuid == uid,
736 1.1 pgoyette "uid mismatch");
737 1.1 pgoyette
738 1.1 pgoyette ATF_REQUIRE_MSG(sp->shm_perm.gid == gid && sp->shm_perm.cgid == gid,
739 1.1 pgoyette "gid mismatch");
740 1.1 pgoyette
741 1.5 pgoyette ATF_REQUIRE_MSG((sp->shm_perm.mode & 0777) == mode,
742 1.5 pgoyette "mode mismatch %o != %o", sp->shm_perm.mode & 0777, mode);
743 1.1 pgoyette }
744 1.1 pgoyette
745 1.1 pgoyette void
746 1.5 pgoyette sharer(void)
747 1.1 pgoyette {
748 1.1 pgoyette int shmid;
749 1.1 pgoyette void *shm_buf;
750 1.1 pgoyette
751 1.1 pgoyette shmid = shmget(shmkey, pgsize, 0);
752 1.6 christos if (shmid == -1)
753 1.6 christos err(EXIT_FAILURE, "receiver: shmget");
754 1.1 pgoyette
755 1.1 pgoyette shm_buf = shmat(shmid, NULL, 0);
756 1.6 christos if (shm_buf == (void *) -1)
757 1.6 christos err(EXIT_FAILURE, "receiver: shmat");
758 1.1 pgoyette
759 1.1 pgoyette printf("%s\n", (const char *)shm_buf);
760 1.1 pgoyette
761 1.6 christos if (strcmp((const char *)shm_buf, m2_str) != 0)
762 1.6 christos errx(EXIT_FAILURE, "receiver: data isn't correct");
763 1.6 christos
764 1.6 christos exit(EXIT_SUCCESS);
765 1.1 pgoyette }
766 1.1 pgoyette
767 1.1 pgoyette ATF_TP_ADD_TCS(tp)
768 1.1 pgoyette {
769 1.1 pgoyette
770 1.1 pgoyette ATF_TP_ADD_TC(tp, msg);
771 1.1 pgoyette ATF_TP_ADD_TC(tp, sem);
772 1.1 pgoyette ATF_TP_ADD_TC(tp, shm);
773 1.1 pgoyette
774 1.1 pgoyette return atf_no_error();
775 1.1 pgoyette }
776