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