]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/netbsd-tests/kernel/t_sysv.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.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 mymsg {
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                 read(input, &value, sizeof(value));
131                 return value;
132         }
133 }
134
135
136 void
137 sigsys_handler(int signo)
138 {
139
140         did_sigsys = 1;
141 }
142
143 void
144 sigchld_handler(int signo)
145 {
146         int c_status;
147
148         did_sigchild = 1;
149         /*
150          * Reap the child and return its status
151          */
152         if (wait(&c_status) == -1)
153                 child_status = -errno;
154         else
155                 child_status = c_status;
156
157         child_count--;
158 }
159
160 key_t get_ftok(int id)
161 {
162         int fd;
163         char token_key[64], token_dir[64];
164         char *tmpdir;
165         key_t key;
166
167         strlcpy(token_key, "/tmp/t_sysv.XXXXXX", sizeof(token_key));
168         tmpdir = mkdtemp(token_key);
169         ATF_REQUIRE_MSG(tmpdir != NULL, "mkdtemp() failed: %d", errno);
170
171         strlcpy(token_dir, tmpdir, sizeof(token_dir));
172         strlcpy(token_key, tmpdir, sizeof(token_key));
173         strlcat(token_key, "/token_key", sizeof(token_key));
174
175         /* Create the file, since ftok() requires it to exist! */
176
177         fd = open(token_key, O_RDWR | O_CREAT | O_EXCL);
178         if (fd == -1) {
179                 rmdir(tmpdir);
180                 atf_tc_fail("open() of temp file failed: %d", errno);
181                 return (key_t)-1;
182         } else
183                 close(fd);
184
185         key = ftok(token_key, id);
186
187         ATF_REQUIRE_MSG(unlink(token_key) != -1, "unlink() failed: %d", errno);
188         ATF_REQUIRE_MSG(rmdir(token_dir) != -1, "rmdir() failed: %d", errno);
189
190         return key;
191 }
192
193 ATF_TC_WITH_CLEANUP(msg);
194 ATF_TC_HEAD(msg, tc)
195 {  
196
197         atf_tc_set_md_var(tc, "timeout", "3");
198         atf_tc_set_md_var(tc, "descr", "Checks sysvmsg passing");
199 }
200
201 ATF_TC_BODY(msg, tc)
202 {
203         struct sigaction sa;
204         struct msqid_ds m_ds;
205         struct mymsg m;
206         sigset_t sigmask;
207         int sender_msqid;
208         int loop;
209         int c_status;
210
211         /*
212          * Install a SIGSYS handler so that we can exit gracefully if
213          * System V Message Queue support isn't in the kernel.
214          */
215         did_sigsys = 0;
216         sa.sa_handler = sigsys_handler;
217         sigemptyset(&sa.sa_mask);
218         sa.sa_flags = 0;
219         ATF_REQUIRE_MSG(sigaction(SIGSYS, &sa, NULL) != -1,
220             "sigaction SIGSYS: %d", errno);
221
222         /*
223          * Install a SIGCHLD handler to deal with all possible exit
224          * conditions of the receiver.
225          */
226         did_sigchild = 0;
227         child_count = 0;
228         sa.sa_handler = sigchld_handler;
229         sigemptyset(&sa.sa_mask);
230         sa.sa_flags = 0;
231         ATF_REQUIRE_MSG(sigaction(SIGCHLD, &sa, NULL) != -1,
232             "sigaction SIGCHLD: %d", errno);
233
234         msgkey = get_ftok(4160);
235         ATF_REQUIRE_MSG(msgkey != (key_t)-1, "get_ftok failed");
236
237         sender_msqid = msgget(msgkey, IPC_CREAT | 0640);
238         ATF_REQUIRE_MSG(sender_msqid != -1, "msgget: %d", errno);
239         write_int("sender_msqid", sender_msqid);
240
241         if (did_sigsys) {
242                 atf_tc_skip("SYSV Message Queue not supported");
243                 return;
244         }
245
246         ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds) != -1,
247         "msgctl IPC_STAT 1: %d", errno);
248
249         print_msqid_ds(&m_ds, 0640);
250
251         m_ds.msg_perm.mode = (m_ds.msg_perm.mode & ~0777) | 0600;
252
253         ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_SET, &m_ds) != -1,
254             "msgctl IPC_SET: %d", errno);
255
256         memset(&m_ds, 0, sizeof(m_ds));
257
258         ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds) != -1,
259             "msgctl IPC_STAT 2: %d", errno);
260
261         ATF_REQUIRE_MSG((m_ds.msg_perm.mode & 0777) == 0600,
262             "IPC_SET of mode didn't hold");
263
264         print_msqid_ds(&m_ds, 0600);
265
266         switch ((child_pid = fork())) {
267         case -1:
268                 atf_tc_fail("fork: %d", errno);
269                 return;
270
271         case 0:
272                 child_count++;
273                 receiver();
274                 break;
275
276         default:
277                 break;
278         }
279
280         for (loop = 0; loop < maxloop; loop++) {
281                 /*
282                  * Send the first message to the receiver and wait for the ACK.
283                  */
284                 m.mtype = MTYPE_1;
285                 strcpy(m.mtext, m1_str);
286                 ATF_REQUIRE_MSG(msgsnd(sender_msqid, &m, MESSAGE_TEXT_LEN,
287                     0) != -1, "sender: msgsnd 1: %d", errno);
288
289                 ATF_REQUIRE_MSG(msgrcv(sender_msqid, &m, MESSAGE_TEXT_LEN,
290                                        MTYPE_1_ACK, 0) == MESSAGE_TEXT_LEN,
291                     "sender: msgrcv 1 ack: %d", errno);
292
293                 print_msqid_ds(&m_ds, 0600);
294
295                 /*
296                  * Send the second message to the receiver and wait for the ACK.
297                  */
298                 m.mtype = MTYPE_2;
299                 strcpy(m.mtext, m2_str);
300                 ATF_REQUIRE_MSG(msgsnd(sender_msqid, &m, MESSAGE_TEXT_LEN, 0) != -1,
301                     "sender: msgsnd 2: %d", errno);
302
303                 ATF_REQUIRE_MSG(msgrcv(sender_msqid, &m, MESSAGE_TEXT_LEN,
304                                        MTYPE_2_ACK, 0) == MESSAGE_TEXT_LEN,
305                     "sender: msgrcv 2 ack: %d", errno);
306         }
307
308         /*
309          * Wait for child to finish
310          */
311         sigemptyset(&sigmask);
312         (void) sigsuspend(&sigmask);
313
314         /*
315          * ...and any other signal is an unexpected error.
316          */
317         if (did_sigchild) {
318                 c_status = child_status;
319                 if (c_status < 0)
320                         atf_tc_fail("waitpid: %d", -c_status);
321                 else if (WIFEXITED(c_status) == 0)
322                         atf_tc_fail("child abnormal exit: %d", c_status);
323                 else if (WEXITSTATUS(c_status) != 0)
324                         atf_tc_fail("c status: %d", WEXITSTATUS(c_status));
325                 else {
326                         ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds)
327                             != -1, "msgctl IPC_STAT: %d", errno);
328
329                         print_msqid_ds(&m_ds, 0600);
330                         atf_tc_pass();
331                 }
332         } else
333                 atf_tc_fail("sender: received unexpected signal");
334 }
335
336 ATF_TC_CLEANUP(msg, tc)
337 {
338         int sender_msqid;
339
340         /*
341          * Remove the message queue if it exists.
342          */
343         sender_msqid = read_int("sender_msqid");
344         if (sender_msqid != -1)
345                 if (msgctl(sender_msqid, IPC_RMID, NULL) == -1)
346                         err(1, "msgctl IPC_RMID");
347 }
348
349 void
350 print_msqid_ds(mp, mode)
351         struct msqid_ds *mp;
352         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()
385 {
386         struct mymsg 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(sp, mode)
592         struct semid_ds *sp;
593         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()
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 ATF_TC_CLEANUP(shm, tc)
779 {
780         int sender_shmid;
781
782         /*
783          * Remove the shared memory area if it exists.
784          */
785         sender_shmid = read_int("sender_shmid");
786         if (sender_shmid != -1)
787                 if (shmctl(sender_shmid, IPC_RMID, NULL) == -1)
788                         err(1, "shmctl IPC_RMID");
789 }
790
791 void
792 print_shmid_ds(sp, mode)
793         struct shmid_ds *sp;
794         mode_t mode;
795 {
796         uid_t uid = geteuid();
797         gid_t gid = getegid();
798
799         printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n",
800             sp->shm_perm.uid, sp->shm_perm.gid,
801             sp->shm_perm.cuid, sp->shm_perm.cgid,
802             sp->shm_perm.mode & 0777);
803
804         printf("segsz %lu, lpid %d, cpid %d, nattch %u\n",
805             (u_long)sp->shm_segsz, sp->shm_lpid, sp->shm_cpid,
806             sp->shm_nattch);
807
808         printf("atime: %s", ctime(&sp->shm_atime));
809         printf("dtime: %s", ctime(&sp->shm_dtime));
810         printf("ctime: %s", ctime(&sp->shm_ctime));
811
812         /*
813          * Sanity check a few things.
814          */
815
816         ATF_REQUIRE_MSG(sp->shm_perm.uid == uid && sp->shm_perm.cuid == uid,
817             "uid mismatch");
818
819         ATF_REQUIRE_MSG(sp->shm_perm.gid == gid && sp->shm_perm.cgid == gid,
820             "gid mismatch");
821
822         ATF_REQUIRE_MSG((sp->shm_perm.mode & 0777) == mode, "mode mismatch");
823 }
824
825 void
826 sharer()
827 {
828         int shmid;
829         void *shm_buf;
830
831         shmid = shmget(shmkey, pgsize, 0);
832         ATF_REQUIRE_MSG(shmid != -1, "receiver: shmget:%d", errno);
833
834         shm_buf = shmat(shmid, NULL, 0);
835         ATF_REQUIRE_MSG(shm_buf != (void *) -1, "receiver: shmat: %d", errno);
836
837         printf("%s\n", (const char *)shm_buf);
838         
839         ATF_REQUIRE_MSG(strcmp((const char *)shm_buf, m2_str) == 0,
840             "receiver: data isn't correct");
841
842         exit(0);
843 }
844
845 ATF_TP_ADD_TCS(tp)
846 {
847
848         ATF_TP_ADD_TC(tp, msg); 
849         ATF_TP_ADD_TC(tp, sem); 
850         ATF_TP_ADD_TC(tp, shm); 
851
852         return atf_no_error();
853 }
854