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
write_int(const char * path,const int value)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
read_int(const char * path)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
sigsys_handler(int signo)137 sigsys_handler(int signo)
138 {
139
140 did_sigsys = 1;
141 }
142
143 void
sigchld_handler(int signo)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
get_ftok(int id)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);
ATF_TC_HEAD(msg,tc)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
ATF_TC_BODY(msg,tc)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
ATF_TC_CLEANUP(msg,tc)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
print_msqid_ds(mp,mode)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
receiver()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);
ATF_TC_HEAD(sem,tc)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
ATF_TC_BODY(sem,tc)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
ATF_TC_CLEANUP(sem,tc)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
print_semid_ds(sp,mode)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
waiter()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);
ATF_TC_HEAD(shm,tc)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
ATF_TC_BODY(shm,tc)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
ATF_TC_CLEANUP(shm,tc)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
print_shmid_ds(sp,mode)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
sharer()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
ATF_TP_ADD_TCS(tp)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
855