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