t_sysv.c revision 1.5 1 /* $NetBSD: t_sysv.c,v 1.5 2018/02/03 02:57:15 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 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 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, 0600);
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 ATF_REQUIRE_MSG(key != (key_t)-1, "ftok() failed");
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 strcpy(m.mtext, m1_str);
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 strcpy(m.mtext, m2_str);
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,
818 "mode mismatch %o != %o", sp->shm_perm.mode & 0777, mode);
819 }
820
821 void
822 sharer(void)
823 {
824 int shmid;
825 void *shm_buf;
826
827 shmid = shmget(shmkey, pgsize, 0);
828 ATF_REQUIRE_MSG(shmid != -1, "receiver: shmget:%d", errno);
829
830 shm_buf = shmat(shmid, NULL, 0);
831 ATF_REQUIRE_MSG(shm_buf != (void *) -1, "receiver: shmat: %d", errno);
832
833 printf("%s\n", (const char *)shm_buf);
834
835 ATF_REQUIRE_MSG(strcmp((const char *)shm_buf, m2_str) == 0,
836 "receiver: data isn't correct");
837
838 exit(0);
839 }
840
841 ATF_TP_ADD_TCS(tp)
842 {
843
844 ATF_TP_ADD_TC(tp, msg);
845 ATF_TP_ADD_TC(tp, sem);
846 ATF_TP_ADD_TC(tp, shm);
847
848 return atf_no_error();
849 }
850
851