1 /* $NetBSD: t_sysv.c,v 1.3 2013/07/24 11:44:10 skrll Exp $ */
4 * Copyright (c) 1999, 2007 The NetBSD Foundation, Inc.
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.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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.
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.
34 * Test the SVID-compatible Message Queue facility.
51 #include <sys/param.h>
56 volatile int did_sigsys
, did_sigchild
;
57 volatile int child_status
, child_count
;
59 void sigsys_handler(int);
60 void sigchld_handler(int);
64 void print_msqid_ds(struct msqid_ds
*, mode_t
);
67 void print_semid_ds(struct semid_ds
*, mode_t
);
70 void print_shmid_ds(struct shmid_ds
*, mode_t
);
73 #define MESSAGE_TEXT_LEN 256
77 char mtext
[MESSAGE_TEXT_LEN
];
80 const char *m1_str
= "California is overrated.";
81 const char *m2_str
= "The quick brown fox jumped over the lazy dog.";
91 int sender_msqid
= -1;
92 int sender_semid
= -1;
93 int sender_shmid
= -1;
96 key_t msgkey
, semkey
, shmkey
;
101 int val
; /* value for SETVAL */
102 struct semid_ds
*buf
; /* buffer for IPC_{STAT,SET} */
103 u_short
*array
; /* array for GETALL & SETALL */
108 sigsys_handler(int signo
)
115 sigchld_handler(int signo
)
121 * Reap the child and return its status
123 if (wait(&c_status
) == -1)
124 child_status
= -errno
;
126 child_status
= c_status
;
131 key_t
get_ftok(int id
)
134 char token_key
[64], token_dir
[64];
138 strlcpy(token_key
, "/tmp/t_sysv.XXXXXX", sizeof(token_key
));
139 tmpdir
= mkdtemp(token_key
);
140 ATF_REQUIRE_MSG(tmpdir
!= NULL
, "mkdtemp() failed: %d", errno
);
142 strlcpy(token_dir
, tmpdir
, sizeof(token_dir
));
143 strlcpy(token_key
, tmpdir
, sizeof(token_key
));
144 strlcat(token_key
, "/token_key", sizeof(token_key
));
146 /* Create the file, since ftok() requires it to exist! */
148 fd
= open(token_key
, O_RDWR
| O_CREAT
| O_EXCL
);
151 atf_tc_fail("open() of temp file failed: %d", errno
);
156 key
= ftok(token_key
, id
);
158 ATF_REQUIRE_MSG(unlink(token_key
) != -1, "unlink() failed: %d", errno
);
159 ATF_REQUIRE_MSG(rmdir(token_dir
) != -1, "rmdir() failed: %d", errno
);
164 ATF_TC_WITH_CLEANUP(msg
);
168 atf_tc_set_md_var(tc
, "timeout", "3");
169 atf_tc_set_md_var(tc
, "descr", "Checks sysvmsg passing");
175 struct msqid_ds m_ds
;
182 * Install a SIGSYS handler so that we can exit gracefully if
183 * System V Message Queue support isn't in the kernel.
186 sa
.sa_handler
= sigsys_handler
;
187 sigemptyset(&sa
.sa_mask
);
189 ATF_REQUIRE_MSG(sigaction(SIGSYS
, &sa
, NULL
) != -1,
190 "sigaction SIGSYS: %d", errno
);
193 * Install a SIGCHLD handler to deal with all possible exit
194 * conditions of the receiver.
198 sa
.sa_handler
= sigchld_handler
;
199 sigemptyset(&sa
.sa_mask
);
201 ATF_REQUIRE_MSG(sigaction(SIGCHLD
, &sa
, NULL
) != -1,
202 "sigaction SIGCHLD: %d", errno
);
204 msgkey
= get_ftok(4160);
205 ATF_REQUIRE_MSG(msgkey
!= (key_t
)-1, "get_ftok failed");
207 sender_msqid
= msgget(msgkey
, IPC_CREAT
| 0640);
208 ATF_REQUIRE_MSG(sender_msqid
!= -1, "msgget: %d", errno
);
211 atf_tc_skip("SYSV Message Queue not supported");
215 ATF_REQUIRE_MSG(msgctl(sender_msqid
, IPC_STAT
, &m_ds
) != -1,
216 "msgctl IPC_STAT 1: %d", errno
);
218 print_msqid_ds(&m_ds
, 0640);
220 m_ds
.msg_perm
.mode
= (m_ds
.msg_perm
.mode
& ~0777) | 0600;
222 ATF_REQUIRE_MSG(msgctl(sender_msqid
, IPC_SET
, &m_ds
) != -1,
223 "msgctl IPC_SET: %d", errno
);
225 memset(&m_ds
, 0, sizeof(m_ds
));
227 ATF_REQUIRE_MSG(msgctl(sender_msqid
, IPC_STAT
, &m_ds
) != -1,
228 "msgctl IPC_STAT 2: %d", errno
);
230 ATF_REQUIRE_MSG((m_ds
.msg_perm
.mode
& 0777) == 0600,
231 "IPC_SET of mode didn't hold");
233 print_msqid_ds(&m_ds
, 0600);
235 switch ((child_pid
= fork())) {
237 atf_tc_fail("fork: %d", errno
);
249 for (loop
= 0; loop
< maxloop
; loop
++) {
251 * Send the first message to the receiver and wait for the ACK.
254 strcpy(m
.mtext
, m1_str
);
255 ATF_REQUIRE_MSG(msgsnd(sender_msqid
, &m
, MESSAGE_TEXT_LEN
,
256 0) != -1, "sender: msgsnd 1: %d", errno
);
258 ATF_REQUIRE_MSG(msgrcv(sender_msqid
, &m
, MESSAGE_TEXT_LEN
,
259 MTYPE_1_ACK
, 0) == MESSAGE_TEXT_LEN
,
260 "sender: msgrcv 1 ack: %d", errno
);
262 print_msqid_ds(&m_ds
, 0600);
265 * Send the second message to the receiver and wait for the ACK.
268 strcpy(m
.mtext
, m2_str
);
269 ATF_REQUIRE_MSG(msgsnd(sender_msqid
, &m
, MESSAGE_TEXT_LEN
, 0) != -1,
270 "sender: msgsnd 2: %d", errno
);
272 ATF_REQUIRE_MSG(msgrcv(sender_msqid
, &m
, MESSAGE_TEXT_LEN
,
273 MTYPE_2_ACK
, 0) == MESSAGE_TEXT_LEN
,
274 "sender: msgrcv 2 ack: %d", errno
);
278 * Wait for child to finish
280 sigemptyset(&sigmask
);
281 (void) sigsuspend(&sigmask
);
284 * ...and any other signal is an unexpected error.
287 c_status
= child_status
;
289 atf_tc_fail("waitpid: %d", -c_status
);
290 else if (WIFEXITED(c_status
) == 0)
291 atf_tc_fail("child abnormal exit: %d", c_status
);
292 else if (WEXITSTATUS(c_status
) != 0)
293 atf_tc_fail("c status: %d", WEXITSTATUS(c_status
));
295 ATF_REQUIRE_MSG(msgctl(sender_msqid
, IPC_STAT
, &m_ds
)
296 != -1, "msgctl IPC_STAT: %d", errno
);
298 print_msqid_ds(&m_ds
, 0600);
302 atf_tc_fail("sender: received unexpected signal");
305 ATF_TC_CLEANUP(msg
, tc
)
309 * Remove the message queue if it exists.
311 if (sender_msqid
!= -1)
312 ATF_REQUIRE_MSG(msgctl(sender_msqid
, IPC_RMID
, NULL
) != -1,
313 "msgctl IPC_RMID: %d", errno
);
318 print_msqid_ds(mp
, mode
)
322 uid_t uid
= geteuid();
323 gid_t gid
= getegid();
325 printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n",
326 mp
->msg_perm
.uid
, mp
->msg_perm
.gid
,
327 mp
->msg_perm
.cuid
, mp
->msg_perm
.cgid
,
328 mp
->msg_perm
.mode
& 0777);
330 printf("qnum %lu, qbytes %lu, lspid %d, lrpid %d\n",
331 mp
->msg_qnum
, (u_long
)mp
->msg_qbytes
, mp
->msg_lspid
,
334 printf("stime: %s", ctime(&mp
->msg_stime
));
335 printf("rtime: %s", ctime(&mp
->msg_rtime
));
336 printf("ctime: %s", ctime(&mp
->msg_ctime
));
339 * Sanity check a few things.
342 ATF_REQUIRE_MSG(mp
->msg_perm
.uid
== uid
&& mp
->msg_perm
.cuid
== uid
,
345 ATF_REQUIRE_MSG(mp
->msg_perm
.gid
== gid
&& mp
->msg_perm
.cgid
== gid
,
348 ATF_REQUIRE_MSG((mp
->msg_perm
.mode
& 0777) == mode
, "mode mismatch");
357 if ((msqid
= msgget(msgkey
, 0)) == -1)
358 err(1, "receiver: msgget");
360 for (loop
= 0; loop
< maxloop
; loop
++) {
362 * Receive the first message, print it, and send an ACK.
364 if (msgrcv(msqid
, &m
, MESSAGE_TEXT_LEN
, MTYPE_1
, 0) != MESSAGE_TEXT_LEN
)
365 err(1, "receiver: msgrcv 1");
367 printf("%s\n", m
.mtext
);
368 if (strcmp(m
.mtext
, m1_str
) != 0)
369 err(1, "receiver: message 1 data isn't correct");
371 m
.mtype
= MTYPE_1_ACK
;
373 if (msgsnd(msqid
, &m
, MESSAGE_TEXT_LEN
, 0) == -1)
374 err(1, "receiver: msgsnd ack 1");
377 * Receive the second message, print it, and send an ACK.
380 if (msgrcv(msqid
, &m
, MESSAGE_TEXT_LEN
, MTYPE_2
, 0) != MESSAGE_TEXT_LEN
)
381 err(1, "receiver: msgrcv 2");
383 printf("%s\n", m
.mtext
);
384 if (strcmp(m
.mtext
, m2_str
) != 0)
385 err(1, "receiver: message 2 data isn't correct");
387 m
.mtype
= MTYPE_2_ACK
;
389 if (msgsnd(msqid
, &m
, MESSAGE_TEXT_LEN
, 0) == -1)
390 err(1, "receiver: msgsnd ack 2");
397 * Test the SVID-compatible Semaphore facility.
400 ATF_TC_WITH_CLEANUP(sem
);
404 atf_tc_set_md_var(tc
, "timeout", "3");
405 atf_tc_set_md_var(tc
, "descr", "Checks sysvmsg passing");
412 struct semid_ds s_ds
;
418 * Install a SIGSYS handler so that we can exit gracefully if
419 * System V Semaphore support isn't in the kernel.
422 sa
.sa_handler
= sigsys_handler
;
423 sigemptyset(&sa
.sa_mask
);
425 ATF_REQUIRE_MSG(sigaction(SIGSYS
, &sa
, NULL
) != -1,
426 "sigaction SIGSYS: %d", errno
);
429 * Install a SIGCHLD handler to deal with all possible exit
430 * conditions of the receiver.
434 sa
.sa_handler
= sigchld_handler
;
435 sigemptyset(&sa
.sa_mask
);
437 ATF_REQUIRE_MSG(sigaction(SIGCHLD
, &sa
, NULL
) != -1,
438 "sigaction SIGCHLD: %d", errno
);
440 semkey
= get_ftok(4160);
441 ATF_REQUIRE_MSG(semkey
!= (key_t
)-1, "get_ftok failed");
443 sender_semid
= semget(semkey
, 1, IPC_CREAT
| 0640);
444 ATF_REQUIRE_MSG(sender_semid
!= -1, "semget: %d", errno
);
447 atf_tc_skip("SYSV Semaphore not supported");
452 ATF_REQUIRE_MSG(semctl(sender_semid
, 0, IPC_STAT
, sun
) != -1,
453 "semctl IPC_STAT: %d", errno
);
455 print_semid_ds(&s_ds
, 0640);
457 s_ds
.sem_perm
.mode
= (s_ds
.sem_perm
.mode
& ~0777) | 0600;
460 ATF_REQUIRE_MSG(semctl(sender_semid
, 0, IPC_SET
, sun
) != -1,
461 "semctl IPC_SET: %d", errno
);
463 memset(&s_ds
, 0, sizeof(s_ds
));
466 ATF_REQUIRE_MSG(semctl(sender_semid
, 0, IPC_STAT
, sun
) != -1,
467 "semctl IPC_STAT: %d", errno
);
469 ATF_REQUIRE_MSG((s_ds
.sem_perm
.mode
& 0777) == 0600,
470 "IPC_SET of mode didn't hold");
472 print_semid_ds(&s_ds
, 0600);
474 for (child_count
= 0; child_count
< 5; child_count
++) {
475 switch ((child_pid
= fork())) {
477 atf_tc_fail("fork: %d", errno
);
490 * Wait for all of the waiters to be attempting to acquire the
494 i
= semctl(sender_semid
, 0, GETNCNT
);
496 atf_tc_fail("semctl GETNCNT: %d", i
);
502 * Now set the thundering herd in motion by initializing the
503 * semaphore to the value 1.
506 ATF_REQUIRE_MSG(semctl(sender_semid
, 0, SETVAL
, sun
) != -1,
507 "sender: semctl SETVAL to 1: %d", errno
);
510 * Wait for all children to finish
512 sigemptyset(&sigmask
);
514 (void) sigsuspend(&sigmask
);
516 c_status
= child_status
;
518 atf_tc_fail("waitpid: %d", -c_status
);
519 else if (WIFEXITED(c_status
) == 0)
520 atf_tc_fail("c abnormal exit: %d", c_status
);
521 else if (WEXITSTATUS(c_status
) != 0)
522 atf_tc_fail("c status: %d",
523 WEXITSTATUS(c_status
));
526 ATF_REQUIRE_MSG(semctl(sender_semid
, 0,
527 IPC_STAT
, sun
) != -1,
528 "semctl IPC_STAT: %d", errno
);
530 print_semid_ds(&s_ds
, 0600);
533 if (child_count
<= 0)
537 atf_tc_fail("sender: received unexpected signal");
543 ATF_TC_CLEANUP(sem
, tc
)
547 * Remove the semaphore if it exists
549 if (sender_semid
!= -1)
550 ATF_REQUIRE_MSG(semctl(sender_semid
, 0, IPC_RMID
) != -1,
551 "semctl IPC_RMID: %d", errno
);
556 print_semid_ds(sp
, mode
)
560 uid_t uid
= geteuid();
561 gid_t gid
= getegid();
563 printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n",
564 sp
->sem_perm
.uid
, sp
->sem_perm
.gid
,
565 sp
->sem_perm
.cuid
, sp
->sem_perm
.cgid
,
566 sp
->sem_perm
.mode
& 0777);
568 printf("nsems %u\n", sp
->sem_nsems
);
570 printf("otime: %s", ctime(&sp
->sem_otime
));
571 printf("ctime: %s", ctime(&sp
->sem_ctime
));
574 * Sanity check a few things.
577 ATF_REQUIRE_MSG(sp
->sem_perm
.uid
== uid
&& sp
->sem_perm
.cuid
== uid
,
580 ATF_REQUIRE_MSG(sp
->sem_perm
.gid
== gid
&& sp
->sem_perm
.cgid
== gid
,
583 ATF_REQUIRE_MSG((sp
->sem_perm
.mode
& 0777) == mode
,
584 "mode mismatch %o != %o", (sp
->sem_perm
.mode
& 0777), mode
);
593 if ((semid
= semget(semkey
, 1, 0)) == -1)
594 err(1, "waiter: semget");
597 * Attempt to acquire the semaphore.
601 s
.sem_flg
= SEM_UNDO
;
603 if (semop(semid
, &s
, 1) == -1)
604 err(1, "waiter: semop -1");
606 printf("WOO! GOT THE SEMAPHORE!\n");
610 * Release the semaphore and exit.
614 s
.sem_flg
= SEM_UNDO
;
616 if (semop(semid
, &s
, 1) == -1)
617 err(1, "waiter: semop +1");
623 * Test the SVID-compatible Shared Memory facility.
626 ATF_TC_WITH_CLEANUP(shm
);
630 atf_tc_set_md_var(tc
, "timeout", "3");
631 atf_tc_set_md_var(tc
, "descr", "Checks sysv shared memory");
637 struct shmid_ds s_ds
;
643 * Install a SIGSYS handler so that we can exit gracefully if
644 * System V Shared Memory support isn't in the kernel.
647 sa
.sa_handler
= sigsys_handler
;
648 sigemptyset(&sa
.sa_mask
);
650 ATF_REQUIRE_MSG(sigaction(SIGSYS
, &sa
, NULL
) != -1,
651 "sigaction SIGSYS: %d", errno
);
654 * Install a SIGCHLD handler to deal with all possible exit
655 * conditions of the sharer.
659 sa
.sa_handler
= sigchld_handler
;
660 sigemptyset(&sa
.sa_mask
);
662 ATF_REQUIRE_MSG(sigaction(SIGCHLD
, &sa
, NULL
) != -1,
663 "sigaction SIGCHLD: %d", errno
);
665 pgsize
= sysconf(_SC_PAGESIZE
);
667 shmkey
= get_ftok(4160);
668 ATF_REQUIRE_MSG(shmkey
!= (key_t
)-1, "get_ftok failed");
670 ATF_REQUIRE_MSG((sender_shmid
= shmget(shmkey
, pgsize
,
671 IPC_CREAT
| 0640)) != -1,
672 "shmget: %d", errno
);
674 ATF_REQUIRE_MSG(shmctl(sender_shmid
, IPC_STAT
, &s_ds
) != -1,
675 "shmctl IPC_STAT: %d", errno
);
677 print_shmid_ds(&s_ds
, 0640);
679 s_ds
.shm_perm
.mode
= (s_ds
.shm_perm
.mode
& ~0777) | 0600;
681 ATF_REQUIRE_MSG(shmctl(sender_shmid
, IPC_SET
, &s_ds
) != -1,
682 "shmctl IPC_SET: %d", errno
);
684 memset(&s_ds
, 0, sizeof(s_ds
));
686 ATF_REQUIRE_MSG(shmctl(sender_shmid
, IPC_STAT
, &s_ds
) != -1,
687 "shmctl IPC_STAT: %d", errno
);
689 ATF_REQUIRE_MSG((s_ds
.shm_perm
.mode
& 0777) == 0600,
690 "IPC_SET of mode didn't hold");
692 print_shmid_ds(&s_ds
, 0600);
694 shm_buf
= shmat(sender_shmid
, NULL
, 0);
695 ATF_REQUIRE_MSG(shm_buf
!= (void *) -1, "sender: shmat: %d", errno
);
698 * Write the test pattern into the shared memory buffer.
700 strcpy(shm_buf
, m2_str
);
702 switch ((child_pid
= fork())) {
704 atf_tc_fail("fork: %d", errno
);
716 * Wait for child to finish
718 sigemptyset(&sigmask
);
719 (void) sigsuspend(&sigmask
);
722 c_status
= child_status
;
724 atf_tc_fail("waitpid: %d", -c_status
);
725 else if (WIFEXITED(c_status
) == 0)
726 atf_tc_fail("c abnormal exit: %d", c_status
);
727 else if (WEXITSTATUS(c_status
) != 0)
728 atf_tc_fail("c status: %d", WEXITSTATUS(c_status
));
730 ATF_REQUIRE_MSG(shmctl(sender_shmid
, IPC_STAT
,
732 "shmctl IPC_STAT: %d", errno
);
734 print_shmid_ds(&s_ds
, 0600);
738 atf_tc_fail("sender: received unexpected signal");
741 ATF_TC_CLEANUP(shm
, tc
)
745 * Remove the shared memory area if it exists.
747 if (sender_shmid
!= -1)
748 ATF_REQUIRE_MSG(shmctl(sender_shmid
, IPC_RMID
, NULL
) != -1,
749 "shmctl IPC_RMID: %d", errno
);
754 print_shmid_ds(sp
, mode
)
758 uid_t uid
= geteuid();
759 gid_t gid
= getegid();
761 printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n",
762 sp
->shm_perm
.uid
, sp
->shm_perm
.gid
,
763 sp
->shm_perm
.cuid
, sp
->shm_perm
.cgid
,
764 sp
->shm_perm
.mode
& 0777);
766 printf("segsz %lu, lpid %d, cpid %d, nattch %u\n",
767 (u_long
)sp
->shm_segsz
, sp
->shm_lpid
, sp
->shm_cpid
,
770 printf("atime: %s", ctime(&sp
->shm_atime
));
771 printf("dtime: %s", ctime(&sp
->shm_dtime
));
772 printf("ctime: %s", ctime(&sp
->shm_ctime
));
775 * Sanity check a few things.
778 ATF_REQUIRE_MSG(sp
->shm_perm
.uid
== uid
&& sp
->shm_perm
.cuid
== uid
,
781 ATF_REQUIRE_MSG(sp
->shm_perm
.gid
== gid
&& sp
->shm_perm
.cgid
== gid
,
784 ATF_REQUIRE_MSG((sp
->shm_perm
.mode
& 0777) == mode
, "mode mismatch");
793 shmid
= shmget(shmkey
, pgsize
, 0);
794 ATF_REQUIRE_MSG(shmid
!= -1, "receiver: shmget:%d", errno
);
796 shm_buf
= shmat(shmid
, NULL
, 0);
797 ATF_REQUIRE_MSG(shm_buf
!= (void *) -1, "receiver: shmat: %d", errno
);
799 printf("%s\n", (const char *)shm_buf
);
801 ATF_REQUIRE_MSG(strcmp((const char *)shm_buf
, m2_str
) == 0,
802 "receiver: data isn't correct");
810 ATF_TP_ADD_TC(tp
, msg
);
811 ATF_TP_ADD_TC(tp
, sem
);
812 ATF_TP_ADD_TC(tp
, shm
);
814 return atf_no_error();