t_sysv.c revision 1.1 1 1.1 pgoyette /* $NetBSD: t_sysv.c,v 1.1 2012/11/05 04:09:14 pgoyette 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.1 pgoyette volatile int did_sigsys, did_sigchild;
57 1.1 pgoyette volatile int child_status, child_count;
58 1.1 pgoyette
59 1.1 pgoyette void sigsys_handler(int);
60 1.1 pgoyette void sigchld_handler(int);
61 1.1 pgoyette
62 1.1 pgoyette void print_msqid_ds(struct msqid_ds *, mode_t);
63 1.1 pgoyette void cleanup_msg(void);
64 1.1 pgoyette void receiver(void);
65 1.1 pgoyette
66 1.1 pgoyette void print_semid_ds(struct semid_ds *, mode_t);
67 1.1 pgoyette void cleanup_sem(void);
68 1.1 pgoyette void waiter(void);
69 1.1 pgoyette
70 1.1 pgoyette void print_shmid_ds(struct shmid_ds *, mode_t);
71 1.1 pgoyette void cleanup_shm(void);
72 1.1 pgoyette void sharer(void);
73 1.1 pgoyette
74 1.1 pgoyette #define MESSAGE_TEXT_LEN 256
75 1.1 pgoyette
76 1.1 pgoyette struct mymsg {
77 1.1 pgoyette long mtype;
78 1.1 pgoyette char mtext[MESSAGE_TEXT_LEN];
79 1.1 pgoyette };
80 1.1 pgoyette
81 1.1 pgoyette const char *m1_str = "California is overrated.";
82 1.1 pgoyette const char *m2_str = "The quick brown fox jumped over the lazy dog.";
83 1.1 pgoyette
84 1.1 pgoyette size_t pgsize;
85 1.1 pgoyette
86 1.1 pgoyette #define MTYPE_1 1
87 1.1 pgoyette #define MTYPE_1_ACK 2
88 1.1 pgoyette
89 1.1 pgoyette #define MTYPE_2 3
90 1.1 pgoyette #define MTYPE_2_ACK 4
91 1.1 pgoyette
92 1.1 pgoyette int sender_msqid = -1;
93 1.1 pgoyette int sender_semid = -1;
94 1.1 pgoyette int sender_shmid = -1;
95 1.1 pgoyette pid_t child_pid;
96 1.1 pgoyette
97 1.1 pgoyette char token_key[64];
98 1.1 pgoyette
99 1.1 pgoyette key_t msgkey, semkey, shmkey;
100 1.1 pgoyette
101 1.1 pgoyette int maxloop = 1;
102 1.1 pgoyette
103 1.1 pgoyette union semun {
104 1.1 pgoyette int val; /* value for SETVAL */
105 1.1 pgoyette struct semid_ds *buf; /* buffer for IPC_{STAT,SET} */
106 1.1 pgoyette u_short *array; /* array for GETALL & SETALL */
107 1.1 pgoyette };
108 1.1 pgoyette
109 1.1 pgoyette
110 1.1 pgoyette void
111 1.1 pgoyette sigsys_handler(int signo)
112 1.1 pgoyette {
113 1.1 pgoyette
114 1.1 pgoyette did_sigsys = 1;
115 1.1 pgoyette }
116 1.1 pgoyette
117 1.1 pgoyette void
118 1.1 pgoyette sigchld_handler(int signo)
119 1.1 pgoyette {
120 1.1 pgoyette int c_status;
121 1.1 pgoyette
122 1.1 pgoyette did_sigchild = 1;
123 1.1 pgoyette /*
124 1.1 pgoyette * Reap the child and return its status
125 1.1 pgoyette */
126 1.1 pgoyette if (wait(&c_status) == -1)
127 1.1 pgoyette child_status = -errno;
128 1.1 pgoyette else
129 1.1 pgoyette child_status = c_status;
130 1.1 pgoyette
131 1.1 pgoyette child_count--;
132 1.1 pgoyette }
133 1.1 pgoyette
134 1.1 pgoyette ATF_TC(msg);
135 1.1 pgoyette ATF_TC_HEAD(msg, tc)
136 1.1 pgoyette {
137 1.1 pgoyette
138 1.1 pgoyette atf_tc_set_md_var(tc, "timeout", "3");
139 1.1 pgoyette atf_tc_set_md_var(tc, "descr", "Checks sysvmsg passing");
140 1.1 pgoyette }
141 1.1 pgoyette
142 1.1 pgoyette ATF_TC_BODY(msg, tc)
143 1.1 pgoyette {
144 1.1 pgoyette struct sigaction sa;
145 1.1 pgoyette struct msqid_ds m_ds;
146 1.1 pgoyette struct mymsg m;
147 1.1 pgoyette sigset_t sigmask;
148 1.1 pgoyette int loop;
149 1.1 pgoyette int c_status;
150 1.1 pgoyette
151 1.1 pgoyette /*
152 1.1 pgoyette * Install a SIGSYS handler so that we can exit gracefully if
153 1.1 pgoyette * System V Message Queue support isn't in the kernel.
154 1.1 pgoyette */
155 1.1 pgoyette did_sigsys = 0;
156 1.1 pgoyette sa.sa_handler = sigsys_handler;
157 1.1 pgoyette sigemptyset(&sa.sa_mask);
158 1.1 pgoyette sa.sa_flags = 0;
159 1.1 pgoyette ATF_REQUIRE_MSG(sigaction(SIGSYS, &sa, NULL) != -1,
160 1.1 pgoyette "sigaction SIGSYS: %d", errno);
161 1.1 pgoyette
162 1.1 pgoyette /*
163 1.1 pgoyette * Install a SIGCHLD handler to deal with all possible exit
164 1.1 pgoyette * conditions of the receiver.
165 1.1 pgoyette */
166 1.1 pgoyette did_sigchild = 0;
167 1.1 pgoyette child_count = 0;
168 1.1 pgoyette sa.sa_handler = sigchld_handler;
169 1.1 pgoyette sigemptyset(&sa.sa_mask);
170 1.1 pgoyette sa.sa_flags = 0;
171 1.1 pgoyette ATF_REQUIRE_MSG(sigaction(SIGCHLD, &sa, NULL) != -1,
172 1.1 pgoyette "sigaction SIGCHLD: %d", errno);
173 1.1 pgoyette
174 1.1 pgoyette msgkey = ftok(token_key, 4160);
175 1.1 pgoyette ATF_REQUIRE_MSG(msgkey != (key_t)-1, "ftok failed");
176 1.1 pgoyette
177 1.1 pgoyette /*
178 1.1 pgoyette * Initialize child_pid to ourselves so that the cleanup function
179 1.1 pgoyette * works before we create the receiver.
180 1.1 pgoyette */
181 1.1 pgoyette child_pid = getpid();
182 1.1 pgoyette
183 1.1 pgoyette /*
184 1.1 pgoyette * Make sure that when the sender exits, the message queue is
185 1.1 pgoyette * removed.
186 1.1 pgoyette */
187 1.1 pgoyette ATF_REQUIRE_MSG(atexit(cleanup_msg) != -1, "atexit:%d", errno);
188 1.1 pgoyette
189 1.1 pgoyette sender_msqid = msgget(msgkey, IPC_CREAT | 0640);
190 1.1 pgoyette ATF_REQUIRE_MSG(sender_msqid != -1, "msgget: %d", errno);
191 1.1 pgoyette
192 1.1 pgoyette if (did_sigsys) {
193 1.1 pgoyette atf_tc_skip("SYSV Message Queue not supported");
194 1.1 pgoyette return;
195 1.1 pgoyette }
196 1.1 pgoyette
197 1.1 pgoyette ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds) != -1,
198 1.1 pgoyette "msgctl IPC_STAT 1: %d", errno);
199 1.1 pgoyette
200 1.1 pgoyette print_msqid_ds(&m_ds, 0640);
201 1.1 pgoyette
202 1.1 pgoyette m_ds.msg_perm.mode = (m_ds.msg_perm.mode & ~0777) | 0600;
203 1.1 pgoyette
204 1.1 pgoyette ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_SET, &m_ds) != -1,
205 1.1 pgoyette "msgctl IPC_SET: %d", errno);
206 1.1 pgoyette
207 1.1 pgoyette memset(&m_ds, 0, sizeof(m_ds));
208 1.1 pgoyette
209 1.1 pgoyette ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds) != -1,
210 1.1 pgoyette "msgctl IPC_STAT 2: %d", errno);
211 1.1 pgoyette
212 1.1 pgoyette ATF_REQUIRE_MSG((m_ds.msg_perm.mode & 0777) == 0600,
213 1.1 pgoyette "IPC_SET of mode didn't hold");
214 1.1 pgoyette
215 1.1 pgoyette print_msqid_ds(&m_ds, 0600);
216 1.1 pgoyette
217 1.1 pgoyette switch ((child_pid = fork())) {
218 1.1 pgoyette case -1:
219 1.1 pgoyette atf_tc_fail("fork: %d", errno);
220 1.1 pgoyette return;
221 1.1 pgoyette
222 1.1 pgoyette case 0:
223 1.1 pgoyette child_count++;
224 1.1 pgoyette receiver();
225 1.1 pgoyette break;
226 1.1 pgoyette
227 1.1 pgoyette default:
228 1.1 pgoyette break;
229 1.1 pgoyette }
230 1.1 pgoyette
231 1.1 pgoyette for (loop = 0; loop < maxloop; loop++) {
232 1.1 pgoyette /*
233 1.1 pgoyette * Send the first message to the receiver and wait for the ACK.
234 1.1 pgoyette */
235 1.1 pgoyette m.mtype = MTYPE_1;
236 1.1 pgoyette strcpy(m.mtext, m1_str);
237 1.1 pgoyette ATF_REQUIRE_MSG(msgsnd(sender_msqid, &m, sizeof(m), 0) != -1,
238 1.1 pgoyette "sender: msgsnd 1: %d", errno);
239 1.1 pgoyette
240 1.1 pgoyette ATF_REQUIRE_MSG(msgrcv(sender_msqid, &m, sizeof(m),
241 1.1 pgoyette MTYPE_1_ACK, 0) == sizeof(m),
242 1.1 pgoyette "sender: msgrcv 1 ack: %d", errno);
243 1.1 pgoyette
244 1.1 pgoyette print_msqid_ds(&m_ds, 0600);
245 1.1 pgoyette
246 1.1 pgoyette /*
247 1.1 pgoyette * Send the second message to the receiver and wait for the ACK.
248 1.1 pgoyette */
249 1.1 pgoyette m.mtype = MTYPE_2;
250 1.1 pgoyette strcpy(m.mtext, m2_str);
251 1.1 pgoyette ATF_REQUIRE_MSG(msgsnd(sender_msqid, &m, sizeof(m), 0) != -1,
252 1.1 pgoyette "sender: msgsnd 2: %d", errno);
253 1.1 pgoyette
254 1.1 pgoyette ATF_REQUIRE_MSG(msgrcv(sender_msqid, &m, sizeof(m),
255 1.1 pgoyette MTYPE_2_ACK, 0) == sizeof(m),
256 1.1 pgoyette "sender: msgrcv 2 ack: %d", errno);
257 1.1 pgoyette }
258 1.1 pgoyette
259 1.1 pgoyette /*
260 1.1 pgoyette * Wait for child to finish
261 1.1 pgoyette */
262 1.1 pgoyette sigemptyset(&sigmask);
263 1.1 pgoyette (void) sigsuspend(&sigmask);
264 1.1 pgoyette
265 1.1 pgoyette /*
266 1.1 pgoyette * ...and any other signal is an unexpected error.
267 1.1 pgoyette */
268 1.1 pgoyette if (did_sigchild) {
269 1.1 pgoyette c_status = child_status;
270 1.1 pgoyette if (c_status < 0)
271 1.1 pgoyette atf_tc_fail("waitpid: %d", -c_status);
272 1.1 pgoyette else if (WIFEXITED(c_status) == 0)
273 1.1 pgoyette atf_tc_fail("child abnormal exit: %d", c_status);
274 1.1 pgoyette else if (WEXITSTATUS(c_status) != 0)
275 1.1 pgoyette atf_tc_fail("c status: %d", WEXITSTATUS(c_status));
276 1.1 pgoyette else {
277 1.1 pgoyette ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds)
278 1.1 pgoyette != -1, "msgctl IPC_STAT: %d", errno);
279 1.1 pgoyette
280 1.1 pgoyette print_msqid_ds(&m_ds, 0600);
281 1.1 pgoyette atf_tc_pass();
282 1.1 pgoyette }
283 1.1 pgoyette } else
284 1.1 pgoyette atf_tc_fail("sender: received unexpected signal");
285 1.1 pgoyette }
286 1.1 pgoyette
287 1.1 pgoyette void
288 1.1 pgoyette cleanup_msg()
289 1.1 pgoyette {
290 1.1 pgoyette
291 1.1 pgoyette /*
292 1.1 pgoyette * If we're the sender, and it exists, remove the message queue.
293 1.1 pgoyette */
294 1.1 pgoyette if (child_pid != 0 && sender_msqid != -1) {
295 1.1 pgoyette if (msgctl(sender_msqid, IPC_RMID, NULL) == -1)
296 1.1 pgoyette warn("msgctl IPC_RMID");
297 1.1 pgoyette }
298 1.1 pgoyette }
299 1.1 pgoyette
300 1.1 pgoyette void
301 1.1 pgoyette print_msqid_ds(mp, mode)
302 1.1 pgoyette struct msqid_ds *mp;
303 1.1 pgoyette mode_t mode;
304 1.1 pgoyette {
305 1.1 pgoyette uid_t uid = geteuid();
306 1.1 pgoyette gid_t gid = getegid();
307 1.1 pgoyette
308 1.1 pgoyette printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n",
309 1.1 pgoyette mp->msg_perm.uid, mp->msg_perm.gid,
310 1.1 pgoyette mp->msg_perm.cuid, mp->msg_perm.cgid,
311 1.1 pgoyette mp->msg_perm.mode & 0777);
312 1.1 pgoyette
313 1.1 pgoyette printf("qnum %lu, qbytes %lu, lspid %d, lrpid %d\n",
314 1.1 pgoyette mp->msg_qnum, (u_long)mp->msg_qbytes, mp->msg_lspid,
315 1.1 pgoyette mp->msg_lrpid);
316 1.1 pgoyette
317 1.1 pgoyette printf("stime: %s", ctime(&mp->msg_stime));
318 1.1 pgoyette printf("rtime: %s", ctime(&mp->msg_rtime));
319 1.1 pgoyette printf("ctime: %s", ctime(&mp->msg_ctime));
320 1.1 pgoyette
321 1.1 pgoyette /*
322 1.1 pgoyette * Sanity check a few things.
323 1.1 pgoyette */
324 1.1 pgoyette
325 1.1 pgoyette ATF_REQUIRE_MSG(mp->msg_perm.uid == uid && mp->msg_perm.cuid == uid,
326 1.1 pgoyette "uid mismatch");
327 1.1 pgoyette
328 1.1 pgoyette ATF_REQUIRE_MSG(mp->msg_perm.gid == gid && mp->msg_perm.cgid == gid,
329 1.1 pgoyette "gid mismatch");
330 1.1 pgoyette
331 1.1 pgoyette ATF_REQUIRE_MSG((mp->msg_perm.mode & 0777) == mode, "mode mismatch");
332 1.1 pgoyette }
333 1.1 pgoyette
334 1.1 pgoyette void
335 1.1 pgoyette receiver()
336 1.1 pgoyette {
337 1.1 pgoyette struct mymsg m;
338 1.1 pgoyette int msqid, loop;
339 1.1 pgoyette
340 1.1 pgoyette if ((msqid = msgget(msgkey, 0)) == -1)
341 1.1 pgoyette err(1, "receiver: msgget");
342 1.1 pgoyette
343 1.1 pgoyette for (loop = 0; loop < maxloop; loop++) {
344 1.1 pgoyette /*
345 1.1 pgoyette * Receive the first message, print it, and send an ACK.
346 1.1 pgoyette */
347 1.1 pgoyette if (msgrcv(msqid, &m, sizeof(m), MTYPE_1, 0) != sizeof(m))
348 1.1 pgoyette err(1, "receiver: msgrcv 1");
349 1.1 pgoyette
350 1.1 pgoyette printf("%s\n", m.mtext);
351 1.1 pgoyette if (strcmp(m.mtext, m1_str) != 0)
352 1.1 pgoyette err(1, "receiver: message 1 data isn't correct");
353 1.1 pgoyette
354 1.1 pgoyette m.mtype = MTYPE_1_ACK;
355 1.1 pgoyette
356 1.1 pgoyette if (msgsnd(msqid, &m, sizeof(m), 0) == -1)
357 1.1 pgoyette err(1, "receiver: msgsnd ack 1");
358 1.1 pgoyette
359 1.1 pgoyette /*
360 1.1 pgoyette * Receive the second message, print it, and send an ACK.
361 1.1 pgoyette */
362 1.1 pgoyette
363 1.1 pgoyette if (msgrcv(msqid, &m, sizeof(m), MTYPE_2, 0) != sizeof(m))
364 1.1 pgoyette err(1, "receiver: msgrcv 2");
365 1.1 pgoyette
366 1.1 pgoyette printf("%s\n", m.mtext);
367 1.1 pgoyette if (strcmp(m.mtext, m2_str) != 0)
368 1.1 pgoyette err(1, "receiver: message 2 data isn't correct");
369 1.1 pgoyette
370 1.1 pgoyette m.mtype = MTYPE_2_ACK;
371 1.1 pgoyette
372 1.1 pgoyette if (msgsnd(msqid, &m, sizeof(m), 0) == -1)
373 1.1 pgoyette err(1, "receiver: msgsnd ack 2");
374 1.1 pgoyette }
375 1.1 pgoyette
376 1.1 pgoyette exit(0);
377 1.1 pgoyette }
378 1.1 pgoyette
379 1.1 pgoyette /*
380 1.1 pgoyette * Test the SVID-compatible Semaphore facility.
381 1.1 pgoyette */
382 1.1 pgoyette
383 1.1 pgoyette ATF_TC(sem);
384 1.1 pgoyette ATF_TC_HEAD(sem, tc)
385 1.1 pgoyette {
386 1.1 pgoyette
387 1.1 pgoyette atf_tc_set_md_var(tc, "timeout", "3");
388 1.1 pgoyette atf_tc_set_md_var(tc, "descr", "Checks sysvmsg passing");
389 1.1 pgoyette }
390 1.1 pgoyette
391 1.1 pgoyette ATF_TC_BODY(sem, tc)
392 1.1 pgoyette {
393 1.1 pgoyette struct sigaction sa;
394 1.1 pgoyette union semun sun;
395 1.1 pgoyette struct semid_ds s_ds;
396 1.1 pgoyette sigset_t sigmask;
397 1.1 pgoyette int i;
398 1.1 pgoyette int c_status;
399 1.1 pgoyette
400 1.1 pgoyette /*
401 1.1 pgoyette * Install a SIGSYS handler so that we can exit gracefully if
402 1.1 pgoyette * System V Semaphore support isn't in the kernel.
403 1.1 pgoyette */
404 1.1 pgoyette did_sigsys = 0;
405 1.1 pgoyette sa.sa_handler = sigsys_handler;
406 1.1 pgoyette sigemptyset(&sa.sa_mask);
407 1.1 pgoyette sa.sa_flags = 0;
408 1.1 pgoyette ATF_REQUIRE_MSG(sigaction(SIGSYS, &sa, NULL) != -1,
409 1.1 pgoyette "sigaction SIGSYS: %d", errno);
410 1.1 pgoyette
411 1.1 pgoyette /*
412 1.1 pgoyette * Install a SIGCHLD handler to deal with all possible exit
413 1.1 pgoyette * conditions of the receiver.
414 1.1 pgoyette */
415 1.1 pgoyette did_sigchild = 0;
416 1.1 pgoyette child_count = 0;
417 1.1 pgoyette sa.sa_handler = sigchld_handler;
418 1.1 pgoyette sigemptyset(&sa.sa_mask);
419 1.1 pgoyette sa.sa_flags = 0;
420 1.1 pgoyette ATF_REQUIRE_MSG(sigaction(SIGCHLD, &sa, NULL) != -1,
421 1.1 pgoyette "sigaction SIGCHLD: %d", errno);
422 1.1 pgoyette
423 1.1 pgoyette semkey = ftok(token_key, 4160);
424 1.1 pgoyette ATF_REQUIRE_MSG(semkey != (key_t)-1, "ftok failed");
425 1.1 pgoyette
426 1.1 pgoyette /*
427 1.1 pgoyette * Initialize child_pid to ourselves to that the cleanup function
428 1.1 pgoyette * works before we create the receiver.
429 1.1 pgoyette */
430 1.1 pgoyette child_pid = getpid();
431 1.1 pgoyette
432 1.1 pgoyette /*
433 1.1 pgoyette * Make sure that when the sender exits, the message queue is
434 1.1 pgoyette * removed.
435 1.1 pgoyette */
436 1.1 pgoyette ATF_REQUIRE_MSG(atexit(cleanup_sem) != -1, "atexit: %d", errno);
437 1.1 pgoyette
438 1.1 pgoyette sender_semid = semget(semkey, 1, IPC_CREAT | 0640);
439 1.1 pgoyette ATF_REQUIRE_MSG(sender_semid != -1, "semget: %d", errno);
440 1.1 pgoyette
441 1.1 pgoyette if (did_sigsys) {
442 1.1 pgoyette atf_tc_skip("SYSV Semaphore not supported");
443 1.1 pgoyette return;
444 1.1 pgoyette }
445 1.1 pgoyette
446 1.1 pgoyette sun.buf = &s_ds;
447 1.1 pgoyette ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_STAT, sun) != -1,
448 1.1 pgoyette "semctl IPC_STAT: %d", errno);
449 1.1 pgoyette
450 1.1 pgoyette print_semid_ds(&s_ds, 0640);
451 1.1 pgoyette
452 1.1 pgoyette s_ds.sem_perm.mode = (s_ds.sem_perm.mode & ~0777) | 0600;
453 1.1 pgoyette
454 1.1 pgoyette sun.buf = &s_ds;
455 1.1 pgoyette ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_SET, sun) != -1,
456 1.1 pgoyette "semctl IPC_SET: %d", errno);
457 1.1 pgoyette
458 1.1 pgoyette memset(&s_ds, 0, sizeof(s_ds));
459 1.1 pgoyette
460 1.1 pgoyette sun.buf = &s_ds;
461 1.1 pgoyette ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_STAT, sun) != -1,
462 1.1 pgoyette "semctl IPC_STAT: %d", errno);
463 1.1 pgoyette
464 1.1 pgoyette ATF_REQUIRE_MSG((s_ds.sem_perm.mode & 0777) == 0600,
465 1.1 pgoyette "IPC_SET of mode didn't hold");
466 1.1 pgoyette
467 1.1 pgoyette print_semid_ds(&s_ds, 0600);
468 1.1 pgoyette
469 1.1 pgoyette for (child_count = 0; child_count < 5; child_count++) {
470 1.1 pgoyette switch ((child_pid = fork())) {
471 1.1 pgoyette case -1:
472 1.1 pgoyette atf_tc_fail("fork: %d", errno);
473 1.1 pgoyette return;
474 1.1 pgoyette
475 1.1 pgoyette case 0:
476 1.1 pgoyette waiter();
477 1.1 pgoyette break;
478 1.1 pgoyette
479 1.1 pgoyette default:
480 1.1 pgoyette break;
481 1.1 pgoyette }
482 1.1 pgoyette }
483 1.1 pgoyette
484 1.1 pgoyette /*
485 1.1 pgoyette * Wait for all of the waiters to be attempting to acquire the
486 1.1 pgoyette * semaphore.
487 1.1 pgoyette */
488 1.1 pgoyette for (;;) {
489 1.1 pgoyette i = semctl(sender_semid, 0, GETNCNT);
490 1.1 pgoyette if (i == -1)
491 1.1 pgoyette atf_tc_fail("semctl GETNCNT: %d", i);
492 1.1 pgoyette if (i == 5)
493 1.1 pgoyette break;
494 1.1 pgoyette }
495 1.1 pgoyette
496 1.1 pgoyette /*
497 1.1 pgoyette * Now set the thundering herd in motion by initializing the
498 1.1 pgoyette * semaphore to the value 1.
499 1.1 pgoyette */
500 1.1 pgoyette sun.val = 1;
501 1.1 pgoyette ATF_REQUIRE_MSG(semctl(sender_semid, 0, SETVAL, sun) != -1,
502 1.1 pgoyette "sender: semctl SETVAL to 1: %d", errno);
503 1.1 pgoyette
504 1.1 pgoyette /*
505 1.1 pgoyette * Wait for all children to finish
506 1.1 pgoyette */
507 1.1 pgoyette sigemptyset(&sigmask);
508 1.1 pgoyette for (;;) {
509 1.1 pgoyette (void) sigsuspend(&sigmask);
510 1.1 pgoyette if (did_sigchild) {
511 1.1 pgoyette c_status = child_status;
512 1.1 pgoyette if (c_status < 0)
513 1.1 pgoyette atf_tc_fail("waitpid: %d", -c_status);
514 1.1 pgoyette else if (WIFEXITED(c_status) == 0)
515 1.1 pgoyette atf_tc_fail("c abnormal exit: %d", c_status);
516 1.1 pgoyette else if (WEXITSTATUS(c_status) != 0)
517 1.1 pgoyette atf_tc_fail("c status: %d",
518 1.1 pgoyette WEXITSTATUS(c_status));
519 1.1 pgoyette else {
520 1.1 pgoyette sun.buf = &s_ds;
521 1.1 pgoyette ATF_REQUIRE_MSG(semctl(sender_semid, 0,
522 1.1 pgoyette IPC_STAT, sun) != -1,
523 1.1 pgoyette "semctl IPC_STAT: %d", errno);
524 1.1 pgoyette
525 1.1 pgoyette print_semid_ds(&s_ds, 0600);
526 1.1 pgoyette atf_tc_pass();
527 1.1 pgoyette }
528 1.1 pgoyette if (child_count <= 0)
529 1.1 pgoyette break;
530 1.1 pgoyette did_sigchild = 0;
531 1.1 pgoyette } else {
532 1.1 pgoyette atf_tc_fail("sender: received unexpected signal");
533 1.1 pgoyette break;
534 1.1 pgoyette }
535 1.1 pgoyette }
536 1.1 pgoyette }
537 1.1 pgoyette
538 1.1 pgoyette void
539 1.1 pgoyette cleanup_sem()
540 1.1 pgoyette {
541 1.1 pgoyette
542 1.1 pgoyette /*
543 1.1 pgoyette * If we're the sender, and it exists, remove the message queue.
544 1.1 pgoyette */
545 1.1 pgoyette if (child_pid != 0 && sender_semid != -1) {
546 1.1 pgoyette ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_RMID) != -1,
547 1.1 pgoyette "semctl IPC_RMID: %d", errno);
548 1.1 pgoyette }
549 1.1 pgoyette }
550 1.1 pgoyette
551 1.1 pgoyette void
552 1.1 pgoyette print_semid_ds(sp, mode)
553 1.1 pgoyette struct semid_ds *sp;
554 1.1 pgoyette mode_t mode;
555 1.1 pgoyette {
556 1.1 pgoyette uid_t uid = geteuid();
557 1.1 pgoyette gid_t gid = getegid();
558 1.1 pgoyette
559 1.1 pgoyette printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n",
560 1.1 pgoyette sp->sem_perm.uid, sp->sem_perm.gid,
561 1.1 pgoyette sp->sem_perm.cuid, sp->sem_perm.cgid,
562 1.1 pgoyette sp->sem_perm.mode & 0777);
563 1.1 pgoyette
564 1.1 pgoyette printf("nsems %u\n", sp->sem_nsems);
565 1.1 pgoyette
566 1.1 pgoyette printf("otime: %s", ctime(&sp->sem_otime));
567 1.1 pgoyette printf("ctime: %s", ctime(&sp->sem_ctime));
568 1.1 pgoyette
569 1.1 pgoyette /*
570 1.1 pgoyette * Sanity check a few things.
571 1.1 pgoyette */
572 1.1 pgoyette
573 1.1 pgoyette ATF_REQUIRE_MSG(sp->sem_perm.uid == uid && sp->sem_perm.cuid == uid,
574 1.1 pgoyette "uid mismatch");
575 1.1 pgoyette
576 1.1 pgoyette ATF_REQUIRE_MSG(sp->sem_perm.gid == gid && sp->sem_perm.cgid == gid,
577 1.1 pgoyette "gid mismatch");
578 1.1 pgoyette
579 1.1 pgoyette ATF_REQUIRE_MSG((sp->sem_perm.mode & 0777) == mode,
580 1.1 pgoyette "mode mismatch %o != %o", (sp->sem_perm.mode & 0777), mode);
581 1.1 pgoyette }
582 1.1 pgoyette
583 1.1 pgoyette void
584 1.1 pgoyette waiter()
585 1.1 pgoyette {
586 1.1 pgoyette struct sembuf s;
587 1.1 pgoyette int semid;
588 1.1 pgoyette
589 1.1 pgoyette if ((semid = semget(semkey, 1, 0)) == -1)
590 1.1 pgoyette err(1, "waiter: semget");
591 1.1 pgoyette
592 1.1 pgoyette /*
593 1.1 pgoyette * Attempt to acquire the semaphore.
594 1.1 pgoyette */
595 1.1 pgoyette s.sem_num = 0;
596 1.1 pgoyette s.sem_op = -1;
597 1.1 pgoyette s.sem_flg = SEM_UNDO;
598 1.1 pgoyette
599 1.1 pgoyette if (semop(semid, &s, 1) == -1)
600 1.1 pgoyette err(1, "waiter: semop -1");
601 1.1 pgoyette
602 1.1 pgoyette printf("WOO! GOT THE SEMAPHORE!\n");
603 1.1 pgoyette sleep(1);
604 1.1 pgoyette
605 1.1 pgoyette /*
606 1.1 pgoyette * Release the semaphore and exit.
607 1.1 pgoyette */
608 1.1 pgoyette s.sem_num = 0;
609 1.1 pgoyette s.sem_op = 1;
610 1.1 pgoyette s.sem_flg = SEM_UNDO;
611 1.1 pgoyette
612 1.1 pgoyette if (semop(semid, &s, 1) == -1)
613 1.1 pgoyette err(1, "waiter: semop +1");
614 1.1 pgoyette
615 1.1 pgoyette exit(0);
616 1.1 pgoyette }
617 1.1 pgoyette
618 1.1 pgoyette /*
619 1.1 pgoyette * Test the SVID-compatible Shared Memory facility.
620 1.1 pgoyette */
621 1.1 pgoyette
622 1.1 pgoyette ATF_TC(shm);
623 1.1 pgoyette ATF_TC_HEAD(shm, tc)
624 1.1 pgoyette {
625 1.1 pgoyette
626 1.1 pgoyette atf_tc_set_md_var(tc, "timeout", "3");
627 1.1 pgoyette atf_tc_set_md_var(tc, "descr", "Checks sysv shared memory");
628 1.1 pgoyette }
629 1.1 pgoyette
630 1.1 pgoyette ATF_TC_BODY(shm, tc)
631 1.1 pgoyette {
632 1.1 pgoyette struct sigaction sa;
633 1.1 pgoyette struct shmid_ds s_ds;
634 1.1 pgoyette sigset_t sigmask;
635 1.1 pgoyette char *shm_buf;
636 1.1 pgoyette int c_status;
637 1.1 pgoyette
638 1.1 pgoyette /*
639 1.1 pgoyette * Install a SIGSYS handler so that we can exit gracefully if
640 1.1 pgoyette * System V Shared Memory support isn't in the kernel.
641 1.1 pgoyette */
642 1.1 pgoyette did_sigsys = 0;
643 1.1 pgoyette sa.sa_handler = sigsys_handler;
644 1.1 pgoyette sigemptyset(&sa.sa_mask);
645 1.1 pgoyette sa.sa_flags = 0;
646 1.1 pgoyette ATF_REQUIRE_MSG(sigaction(SIGSYS, &sa, NULL) != -1,
647 1.1 pgoyette "sigaction SIGSYS: %d", errno);
648 1.1 pgoyette
649 1.1 pgoyette /*
650 1.1 pgoyette * Install a SIGCHLD handler to deal with all possible exit
651 1.1 pgoyette * conditions of the sharer.
652 1.1 pgoyette */
653 1.1 pgoyette did_sigchild = 0;
654 1.1 pgoyette child_count = 0;
655 1.1 pgoyette sa.sa_handler = sigchld_handler;
656 1.1 pgoyette sigemptyset(&sa.sa_mask);
657 1.1 pgoyette sa.sa_flags = 0;
658 1.1 pgoyette ATF_REQUIRE_MSG(sigaction(SIGCHLD, &sa, NULL) != -1,
659 1.1 pgoyette "sigaction SIGCHLD: %d", errno);
660 1.1 pgoyette
661 1.1 pgoyette pgsize = sysconf(_SC_PAGESIZE);
662 1.1 pgoyette
663 1.1 pgoyette shmkey = ftok(token_key, 4160);
664 1.1 pgoyette ATF_REQUIRE_MSG(shmkey != (key_t)-1, "ftok failed");
665 1.1 pgoyette
666 1.1 pgoyette /*
667 1.1 pgoyette * Initialize child_pid to ourselves to that the cleanup function
668 1.1 pgoyette * works before we create the receiver.
669 1.1 pgoyette */
670 1.1 pgoyette child_pid = getpid();
671 1.1 pgoyette
672 1.1 pgoyette /*
673 1.1 pgoyette * Make sure that when the sender exits, the message queue is
674 1.1 pgoyette * removed.
675 1.1 pgoyette */
676 1.1 pgoyette ATF_REQUIRE_MSG(atexit(cleanup_shm) != -1,
677 1.1 pgoyette "atexit: %d", errno);
678 1.1 pgoyette
679 1.1 pgoyette ATF_REQUIRE_MSG((sender_shmid = shmget(shmkey, pgsize,
680 1.1 pgoyette IPC_CREAT | 0640)) != -1,
681 1.1 pgoyette "shmget: %d", errno);
682 1.1 pgoyette
683 1.1 pgoyette ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_STAT, &s_ds) != -1,
684 1.1 pgoyette "shmctl IPC_STAT: %d", errno);
685 1.1 pgoyette
686 1.1 pgoyette print_shmid_ds(&s_ds, 0640);
687 1.1 pgoyette
688 1.1 pgoyette s_ds.shm_perm.mode = (s_ds.shm_perm.mode & ~0777) | 0600;
689 1.1 pgoyette
690 1.1 pgoyette ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_SET, &s_ds) != -1,
691 1.1 pgoyette "shmctl IPC_SET: %d", errno);
692 1.1 pgoyette
693 1.1 pgoyette memset(&s_ds, 0, sizeof(s_ds));
694 1.1 pgoyette
695 1.1 pgoyette ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_STAT, &s_ds) != -1,
696 1.1 pgoyette "shmctl IPC_STAT: %d", errno);
697 1.1 pgoyette
698 1.1 pgoyette ATF_REQUIRE_MSG((s_ds.shm_perm.mode & 0777) == 0600,
699 1.1 pgoyette "IPC_SET of mode didn't hold");
700 1.1 pgoyette
701 1.1 pgoyette print_shmid_ds(&s_ds, 0600);
702 1.1 pgoyette
703 1.1 pgoyette shm_buf = shmat(sender_shmid, NULL, 0);
704 1.1 pgoyette ATF_REQUIRE_MSG(shm_buf != (void *) -1, "sender: shmat: %d", errno);
705 1.1 pgoyette
706 1.1 pgoyette /*
707 1.1 pgoyette * Write the test pattern into the shared memory buffer.
708 1.1 pgoyette */
709 1.1 pgoyette strcpy(shm_buf, m2_str);
710 1.1 pgoyette
711 1.1 pgoyette switch ((child_pid = fork())) {
712 1.1 pgoyette case -1:
713 1.1 pgoyette atf_tc_fail("fork: %d", errno);
714 1.1 pgoyette return;
715 1.1 pgoyette
716 1.1 pgoyette case 0:
717 1.1 pgoyette sharer();
718 1.1 pgoyette break;
719 1.1 pgoyette
720 1.1 pgoyette default:
721 1.1 pgoyette break;
722 1.1 pgoyette }
723 1.1 pgoyette
724 1.1 pgoyette /*
725 1.1 pgoyette * Wait for child to finish
726 1.1 pgoyette */
727 1.1 pgoyette sigemptyset(&sigmask);
728 1.1 pgoyette (void) sigsuspend(&sigmask);
729 1.1 pgoyette
730 1.1 pgoyette if (did_sigchild) {
731 1.1 pgoyette c_status = child_status;
732 1.1 pgoyette if (c_status < 0)
733 1.1 pgoyette atf_tc_fail("waitpid: %d", -c_status);
734 1.1 pgoyette else if (WIFEXITED(c_status) == 0)
735 1.1 pgoyette atf_tc_fail("c abnormal exit: %d", c_status);
736 1.1 pgoyette else if (WEXITSTATUS(c_status) != 0)
737 1.1 pgoyette atf_tc_fail("c status: %d", WEXITSTATUS(c_status));
738 1.1 pgoyette else {
739 1.1 pgoyette ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_STAT,
740 1.1 pgoyette &s_ds) != -1,
741 1.1 pgoyette "shmctl IPC_STAT: %d", errno);
742 1.1 pgoyette
743 1.1 pgoyette print_shmid_ds(&s_ds, 0600);
744 1.1 pgoyette atf_tc_pass();
745 1.1 pgoyette }
746 1.1 pgoyette } else
747 1.1 pgoyette atf_tc_fail("sender: received unexpected signal");
748 1.1 pgoyette }
749 1.1 pgoyette
750 1.1 pgoyette void
751 1.1 pgoyette cleanup_shm()
752 1.1 pgoyette {
753 1.1 pgoyette
754 1.1 pgoyette /*
755 1.1 pgoyette * If we're the sender, and it exists, remove the shared memory area.
756 1.1 pgoyette */
757 1.1 pgoyette if (child_pid != 0 && sender_shmid != -1) {
758 1.1 pgoyette if (shmctl(sender_shmid, IPC_RMID, NULL) == -1)
759 1.1 pgoyette warn("shmctl IPC_RMID");
760 1.1 pgoyette }
761 1.1 pgoyette }
762 1.1 pgoyette
763 1.1 pgoyette void
764 1.1 pgoyette print_shmid_ds(sp, mode)
765 1.1 pgoyette struct shmid_ds *sp;
766 1.1 pgoyette mode_t mode;
767 1.1 pgoyette {
768 1.1 pgoyette uid_t uid = geteuid();
769 1.1 pgoyette gid_t gid = getegid();
770 1.1 pgoyette
771 1.1 pgoyette printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n",
772 1.1 pgoyette sp->shm_perm.uid, sp->shm_perm.gid,
773 1.1 pgoyette sp->shm_perm.cuid, sp->shm_perm.cgid,
774 1.1 pgoyette sp->shm_perm.mode & 0777);
775 1.1 pgoyette
776 1.1 pgoyette printf("segsz %lu, lpid %d, cpid %d, nattch %u\n",
777 1.1 pgoyette (u_long)sp->shm_segsz, sp->shm_lpid, sp->shm_cpid,
778 1.1 pgoyette sp->shm_nattch);
779 1.1 pgoyette
780 1.1 pgoyette printf("atime: %s", ctime(&sp->shm_atime));
781 1.1 pgoyette printf("dtime: %s", ctime(&sp->shm_dtime));
782 1.1 pgoyette printf("ctime: %s", ctime(&sp->shm_ctime));
783 1.1 pgoyette
784 1.1 pgoyette /*
785 1.1 pgoyette * Sanity check a few things.
786 1.1 pgoyette */
787 1.1 pgoyette
788 1.1 pgoyette ATF_REQUIRE_MSG(sp->shm_perm.uid == uid && sp->shm_perm.cuid == uid,
789 1.1 pgoyette "uid mismatch");
790 1.1 pgoyette
791 1.1 pgoyette ATF_REQUIRE_MSG(sp->shm_perm.gid == gid && sp->shm_perm.cgid == gid,
792 1.1 pgoyette "gid mismatch");
793 1.1 pgoyette
794 1.1 pgoyette ATF_REQUIRE_MSG((sp->shm_perm.mode & 0777) == mode, "mode mismatch");
795 1.1 pgoyette }
796 1.1 pgoyette
797 1.1 pgoyette void
798 1.1 pgoyette sharer()
799 1.1 pgoyette {
800 1.1 pgoyette int shmid;
801 1.1 pgoyette void *shm_buf;
802 1.1 pgoyette
803 1.1 pgoyette shmid = shmget(shmkey, pgsize, 0);
804 1.1 pgoyette ATF_REQUIRE_MSG(shmid != -1, "receiver: shmget:%d", errno);
805 1.1 pgoyette
806 1.1 pgoyette shm_buf = shmat(shmid, NULL, 0);
807 1.1 pgoyette ATF_REQUIRE_MSG(shm_buf != (void *) -1, "receiver: shmat: %d", errno);
808 1.1 pgoyette
809 1.1 pgoyette printf("%s\n", (const char *)shm_buf);
810 1.1 pgoyette
811 1.1 pgoyette ATF_REQUIRE_MSG(strcmp((const char *)shm_buf, m2_str) == 0,
812 1.1 pgoyette "receiver: data isn't correct");
813 1.1 pgoyette
814 1.1 pgoyette exit(0);
815 1.1 pgoyette }
816 1.1 pgoyette
817 1.1 pgoyette ATF_TP_ADD_TCS(tp)
818 1.1 pgoyette {
819 1.1 pgoyette int fd;
820 1.1 pgoyette char *tmpdir;
821 1.1 pgoyette
822 1.1 pgoyette strlcpy(token_key, "/tmp/t_sysv.XXXXXX", sizeof(token_key));
823 1.1 pgoyette if ((tmpdir = mkdtemp(token_key)) == NULL)
824 1.1 pgoyette errx(1,"Failed to get a temp dirname for use as a key!");
825 1.1 pgoyette strlcpy(token_key, tmpdir, sizeof(token_key));
826 1.1 pgoyette strlcat(token_key, "token_key", sizeof(token_key));
827 1.1 pgoyette
828 1.1 pgoyette /* Create the file, since ftok() requires it to exist! */
829 1.1 pgoyette
830 1.1 pgoyette if ((fd = open(token_key, O_RDWR | O_CREAT | O_EXCL)) == -1)
831 1.1 pgoyette errx(1, "Failed to create ftok file: %s\n", strerror(errno));
832 1.1 pgoyette else
833 1.1 pgoyette close(fd);
834 1.1 pgoyette
835 1.1 pgoyette ATF_TP_ADD_TC(tp, msg);
836 1.1 pgoyette ATF_TP_ADD_TC(tp, sem);
837 1.1 pgoyette ATF_TP_ADD_TC(tp, shm);
838 1.1 pgoyette
839 1.1 pgoyette return atf_no_error();
840 1.1 pgoyette }
841 1.1 pgoyette
842