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