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