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