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