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