From 2010ab333f2b03c470a78da4d607e79c6de5e944 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Wed, 19 Nov 2003 18:51:18 +0000 Subject: [PATCH] * winsup.api/msgtest.c: New file derived from FreeBSD, testing XSI Message Queue support. * winsup.api/semtest.c: Ditto, testing XSI Semaphore support. * winsup.api/shmtest.c: Ditto, testing XSI Shared Memory support. --- winsup/testsuite/ChangeLog | 7 + winsup/testsuite/winsup.api/msgtest.c | 362 ++++++++++++++++++++++++++ winsup/testsuite/winsup.api/semtest.c | 353 +++++++++++++++++++++++++ winsup/testsuite/winsup.api/shmtest.c | 298 +++++++++++++++++++++ 4 files changed, 1020 insertions(+) create mode 100644 winsup/testsuite/winsup.api/msgtest.c create mode 100644 winsup/testsuite/winsup.api/semtest.c create mode 100644 winsup/testsuite/winsup.api/shmtest.c diff --git a/winsup/testsuite/ChangeLog b/winsup/testsuite/ChangeLog index 03df98595..f39650bd8 100644 --- a/winsup/testsuite/ChangeLog +++ b/winsup/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2003-11-19 Corinna Vinschen + + * winsup.api/msgtest.c: New file derived from FreeBSD, testing + XSI Message Queue support. + * winsup.api/semtest.c: Ditto, testing XSI Semaphore support. + * winsup.api/shmtest.c: Ditto, testing XSI Shared Memory support. + 2003-07-06 Christopher Faylor * winsup.api/known_bugs.tcl: Remove gethostid01 from list of known diff --git a/winsup/testsuite/winsup.api/msgtest.c b/winsup/testsuite/winsup.api/msgtest.c new file mode 100644 index 000000000..6fc69bfec --- /dev/null +++ b/winsup/testsuite/winsup.api/msgtest.c @@ -0,0 +1,362 @@ +/*- + * Copyright (c) 1999 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Obtained from: $NetBSD: msgtest.c,v 1.7 2002/07/20 08:36:25 grant Exp $ + * $FreeBSD: /repoman/r/ncvs/src/tools/regression/sysvmsg/msgtest.c,v 1.1 2002/08/15 06:34:37 alfred Exp $ + */ + +/* + * Test the SVID-compatible Message Queue facility. + */ + +/* + * CV, 2003-11-17: Add to Cygwin testsuite. + */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "test.h" +#include "usctest.h" + +const char *TCID = "msgtest"; /* Test program identifier. */ +int TST_TOTAL = 31; /* Total number of test cases. */ +extern int Tst_count; /* Test Case counter for tst_* routines */ + +void print_msqid_ds (struct msqid_ds *, mode_t); +void sigsys_handler(int); +void sigchld_handler (int); +void cleanup (void); +void receiver (void); + +#define MESSAGE_TEXT_LEN 255 + +/* + * Define it as test_mymsg because we already have struct mymsg and we dont + * want to conflict with it. Also, regression fails when the default mymsg + * struct is used, because mtext[] array is '1', so the passed string cannot + * be processed. + */ +struct test_mymsg { + long mtype; + char mtext[MESSAGE_TEXT_LEN]; +}; + +const char *m1_str = "California is overrated."; +const char *m2_str = "The quick brown fox jumped over the lazy dog."; + +#define MTYPE_1 1 +#define MTYPE_1_ACK 2 + +#define MTYPE_2 3 +#define MTYPE_2_ACK 4 + +int sender_msqid = -1; +pid_t child_pid; + +key_t msgkey; + +int +main(int argc, char *argv[]) +{ + struct sigaction sa; + struct msqid_ds m_ds; + struct test_mymsg m; + sigset_t sigmask; + + Tst_count = 0; + +#if 0 + /* + * Install a SIGSYS handler so that we can exit gracefully if + * System V Message Queue support isn't in the kernel. + */ + sa.sa_handler = sigsys_handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + if (sigaction(SIGSYS, &sa, NULL) == -1) + err(1, "sigaction SIGSYS"); +#endif + + /* + * Install and SIGCHLD handler to deal with all possible exit + * conditions of the receiver. + */ + sa.sa_handler = sigchld_handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + if (sigaction(SIGCHLD, &sa, NULL) == -1) + tst_brkm (TBROK, cleanup, "sigaction SIGCHLD"); + + msgkey = ftok("/", 4160); + tst_resm (msgkey == (key_t)-1 ? TFAIL : TPASS, + "ftok(\"/\") returns valid value"); + + /* + * Initialize child_pid to ourselves to that the cleanup function + * works before we create the receiver. + */ + child_pid = getpid(); + +#if 0 + /* + * Make sure that when the sender exits, the message queue is + * removed. + */ + if (atexit(cleanup) == -1) + err(1, "atexit"); +#endif + + sender_msqid = msgget(msgkey, IPC_CREAT | 0640); + if (sender_msqid == -1 && errno == ENOSYS) + tst_brkm (TRETR, cleanup, + "System V Message Queue support is not present in the kernel"); + tst_resm (sender_msqid == -1 ? TFAIL : TPASS, "sender calls msgget"); + + tst_resm (msgctl(sender_msqid, IPC_STAT, &m_ds) == -1 ? TFAIL : TPASS, + "msgctl IPC_STAT"); + + print_msqid_ds(&m_ds, 0640); + + m_ds.msg_perm.mode = (m_ds.msg_perm.mode & ~0777) | 0600; + + tst_resm (msgctl(sender_msqid, IPC_SET, &m_ds) == -1 ? TFAIL : TPASS, + "msgctl IPC_SET"); + + bzero(&m_ds, sizeof m_ds); + + tst_resm (msgctl(sender_msqid, IPC_STAT, &m_ds) == -1 ? TFAIL : TPASS, + "msgctl IPC_STAT"); + + tst_resm ((m_ds.msg_perm.mode & 0777) != 0600 ? TFAIL : TPASS, + "IPC_SET of mode holds"); + + print_msqid_ds(&m_ds, 0600); + + switch ((child_pid = fork())) { + case -1: + tst_brkm (TBROK, cleanup, "fork"); + /* NOTREACHED */ + + case 0: + tst_resm (TPASS, "fork"); + receiver(); + break; + + default: + Tst_count += 8; + break; + } + + /* + * Send the first message to the receiver and wait for the ACK. + */ + m.mtype = MTYPE_1; + strcpy(m.mtext, m1_str); + tst_resm (msgsnd(sender_msqid, &m, sizeof(m), 0) == -1 ? TFAIL : TPASS, + "sender: msgsnd 1"); + + tst_resm (msgrcv(sender_msqid, &m, sizeof(m), MTYPE_1_ACK, 0) + != sizeof(m) ? TFAIL : TPASS, "sender: msgrcv 1 ack"); + + print_msqid_ds(&m_ds, 0600); + + /* + * Send the second message to the receiver and wait for the ACK. + */ + m.mtype = MTYPE_2; + strcpy(m.mtext, m2_str); + tst_resm (msgsnd(sender_msqid, &m, sizeof(m), 0) == -1 ? TFAIL : TPASS, + "sender: msgsnd 2"); + + tst_resm (msgrcv(sender_msqid, &m, sizeof(m), MTYPE_2_ACK, 0) + != sizeof(m) ? TFAIL : TPASS, "sender: msgrcv 2 ack"); + + /* + * Suspend forever; when we get SIGCHLD, the handler will exit. + */ + sigemptyset(&sigmask); + (void) sigsuspend(&sigmask); + + /* + * ...and any other signal is an unexpected error. + */ + tst_brkm (TBROK, cleanup, "sender: received unexpected signal"); + exit (1); +} + +void +sigsys_handler(int signo) +{ + + tst_brkm (TBROK, cleanup, + "System V Message Queue support is not present in the kernel"); +} + +void +sigchld_handler(int signo) +{ + struct msqid_ds m_ds; + int cstatus; + + /* + * Reap the child; if it exited successfully, then the test passed! + */ + if (waitpid(child_pid, &cstatus, 0) != child_pid) + tst_brkm (TBROK, cleanup, "waitpid"); + + if (WIFEXITED(cstatus) == 0) + tst_brkm (TBROK, cleanup, "receiver exited abnormally"); + + if (WEXITSTATUS(cstatus) != 0) + tst_brkm (TBROK, cleanup, "receiver exited with status %d", + WEXITSTATUS(cstatus)); + + /* + * If we get here, the child has exited normally, and thus + * we should exit normally too. First, tho, we print out + * the final stats for the message queue. + */ + + tst_resm (msgctl(sender_msqid, IPC_STAT, &m_ds) == -1 ? TFAIL : TPASS, + "msgctl IPC_STAT"); + + print_msqid_ds(&m_ds, 0600); + + cleanup (); +} + +void +cleanup() +{ + + /* + * If we're the sender, and it exists, remove the message queue. + */ + if (child_pid != 0 && sender_msqid != -1) { + tst_resm (msgctl(sender_msqid, IPC_RMID, NULL) == -1 + ? TFAIL : TPASS, "msgctl IPC_RMID"); + } + tst_exit (); +} + +void +print_msqid_ds(struct msqid_ds *mp, mode_t mode) +{ + uid_t uid = geteuid(); + gid_t gid = getegid(); + + printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n", + (int)mp->msg_perm.uid, (int)mp->msg_perm.gid, + (int)mp->msg_perm.cuid, (int)mp->msg_perm.cgid, + mp->msg_perm.mode & 0777); + + printf("qnum %lu, qbytes %lu, lspid %d, lrpid %d\n", + mp->msg_qnum, (u_long)mp->msg_qbytes, mp->msg_lspid, + mp->msg_lrpid); + + printf("stime: %s", ctime(&mp->msg_stime)); + printf("rtime: %s", ctime(&mp->msg_rtime)); + printf("ctime: %s", ctime(&mp->msg_ctime)); + + /* + * Sanity check a few things. + */ + + tst_resm (mp->msg_perm.uid != uid || mp->msg_perm.cuid != uid + ? TFAIL : TPASS, "uid matches"); + + tst_resm (mp->msg_perm.gid != gid || mp->msg_perm.cgid != gid + ? TFAIL : TPASS, "gid matches"); + + tst_resm ((mp->msg_perm.mode & 0777) != mode ? TFAIL : TPASS, + "mode matches"); +} + +void +receiver() +{ + struct test_mymsg m; + int msqid; + + tst_resm ((msqid = msgget(msgkey, 0)) == -1 ? TFAIL : TPASS, + "receiver: msgget"); + + /* + * Receive the first message, print it, and send an ACK. + */ + + tst_resm (msgrcv(msqid, &m, sizeof(m), MTYPE_1, 0) != sizeof(m) + ? TFAIL : TPASS, "receiver: msgrcv 1"); + + printf("%s\n", m.mtext); + tst_resm (strcmp(m.mtext, m1_str) != 0 ? TFAIL : TPASS, + "receiver: message 1 data is correct"); + + m.mtype = MTYPE_1_ACK; + + tst_resm (msgsnd(msqid, &m, sizeof(m), 0) == -1 ? TFAIL : TPASS, + "receiver: msgsnd ack 1"); + + /* + * Receive the second message, print it, and send an ACK. + */ + + tst_resm (msgrcv(msqid, &m, sizeof(m), MTYPE_2, 0) != sizeof(m) + ? TFAIL : TPASS, "receiver: msgrcv 2"); + + printf("%s\n", m.mtext); + tst_resm (strcmp(m.mtext, m2_str) != 0 ? TFAIL : TPASS, + "receiver: message 2 data is correct"); + + m.mtype = MTYPE_2_ACK; + + tst_resm (msgsnd(msqid, &m, sizeof(m), 0) == -1 ? TFAIL : TPASS, + "receiver: msgsnd ack 2"); + + /* Allow parent to receive message before getting SIGCHLD. */ + sleep (1); + exit(0); +} diff --git a/winsup/testsuite/winsup.api/semtest.c b/winsup/testsuite/winsup.api/semtest.c new file mode 100644 index 000000000..7f1f75e7a --- /dev/null +++ b/winsup/testsuite/winsup.api/semtest.c @@ -0,0 +1,353 @@ +/*- + * Copyright (c) 1999 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Obtained from: $NetBSD: semtest.c,v 1.4 2002/07/20 08:36:25 grant Exp $ + * $FreeBSD: /repoman/r/ncvs/src/tools/regression/sysvsem/semtest.c,v 1.1 2002/08/15 06:34:37 alfred Exp $ + */ + +/* + * Test the SVID-compatible Semaphore facility. + */ + +/* + * CV, 2003-11-17: Add to Cygwin testsuite. + */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "test.h" +#include "usctest.h" + +const char *TCID = "semtest"; /* Test program identifier. */ +int TST_TOTAL = 54; /* Total number of test cases. */ +extern int Tst_count; /* Test Case counter for tst_* routines */ + +int main (int, char *[]); +void print_semid_ds (struct semid_ds *, mode_t); +void sigsys_handler (int); +void sigchld_handler(int); +void cleanup (void); +void waiter (void); + +int sender_semid = -1; +pid_t child_pid; +int child_count; +int signal_was_sigchld; + +key_t semkey; + +/* + * This is the original semun union used by the sysvsem utility. + * It is deliberately kept here under #if 0'ed condition for future + * reference. PLEASE DO NOT REMOVE. The {SET,GET}ALL in FreeBSD + * are signed values, so the default version in sys/sem.h suffices. + */ +#if 1 /*0*/ +union semun { + int val; /* value for SETVAL */ + struct semid_ds *buf; /* buffer for IPC_{STAT,SET} */ + u_short *array; /* array for GETALL & SETALL */ +}; +#endif + +int +main(int argc, char *argv[]) +{ + struct sigaction sa; + union semun sun; + struct semid_ds s_ds; + sigset_t sigmask; + int i; + + Tst_count = 0; + +#if 0 + /* + * Install a SIGSYS handler so that we can exit gracefully if + * System V Semaphore support isn't in the kernel. + */ + sa.sa_handler = sigsys_handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + if (sigaction(SIGSYS, &sa, NULL) == -1) + err(1, "sigaction SIGSYS"); +#endif + + /* + * Install and SIGCHLD handler to deal with all possible exit + * conditions of the receiver. + */ + sa.sa_handler = sigchld_handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + if (sigaction(SIGCHLD, &sa, NULL) == -1) + tst_brkm (TBROK, cleanup, "sigaction SIGCHLD"); + + semkey = ftok("/", 4160); + tst_resm (semkey == (key_t)-1 ? TFAIL : TPASS, + "ftok(\"/\") returns valid value"); + + /* + * Initialize child_pid to ourselves to that the cleanup function + * works before we create the receiver. + */ + child_pid = getpid(); + + sender_semid = semget(semkey, 1, IPC_CREAT | 0640); + if (sender_semid == -1 && errno == ENOSYS) + tst_brkm (TRETR, cleanup, + "System V Semaphore support is not present in the kernel"); + tst_resm (sender_semid == -1 ? TFAIL : TPASS, "sender calls semget"); + + sun.buf = &s_ds; + tst_resm (semctl(sender_semid, 0, IPC_STAT, sun) == -1 ? TFAIL : TPASS, + "semctl IPC_STAT"); + + print_semid_ds(&s_ds, 0640); + + s_ds.sem_perm.mode = (s_ds.sem_perm.mode & ~0777) | 0600; + + sun.buf = &s_ds; + tst_resm (semctl(sender_semid, 0, IPC_SET, sun) == -1 ? TFAIL : TPASS, + "semctl IPC_SET"); + + memset(&s_ds, 0, sizeof(s_ds)); + + sun.buf = &s_ds; + tst_resm (semctl(sender_semid, 0, IPC_STAT, sun) == -1 ? TFAIL : TPASS, + "semctl IPC_STAT"); + + tst_resm ((s_ds.sem_perm.mode & 0777) != 0600 ? TFAIL : TPASS, + "IPC_SET of mode holds"); + + print_semid_ds(&s_ds, 0600); + + for (child_count = 0; child_count < 5; child_count++) { + switch ((child_pid = fork())) { + case -1: + tst_brkm (TBROK, cleanup, "fork"); + /* NOTREACHED */ + + case 0: + Tst_count += 22 + child_count * 4; + tst_resm (TPASS, "fork"); + waiter(); + break; + + default: + break; + } + } + + /* + * Wait for all of the waiters to be attempting to acquire the + * semaphore. + */ + for (;;) { + i = semctl(sender_semid, 0, GETNCNT); + if (i == -1) + tst_brkm (TBROK, cleanup, "semctl GETNCNT"); + if (i == 5) + break; + } + + /* + * Now set the thundering herd in motion by initializing the + * semaphore to the value 1. + */ + sun.val = 1; + tst_resm (semctl(sender_semid, 0, SETVAL, sun) == -1 ? TFAIL : TPASS, + "sender: semctl SETVAL to 1"); + + /* + * Suspend forever; when we get SIGCHLD, the handler will exit. + */ + sigemptyset(&sigmask); + for (;;) { + (void) sigsuspend(&sigmask); + if (signal_was_sigchld) + signal_was_sigchld = 0; + else + break; + } + + /* + * ...and any other signal is an unexpected error. + */ + + tst_brkm (TBROK, cleanup, "sender: received unexpected signal"); + exit (1); +} + +void +sigsys_handler(int signo) +{ + + tst_brkm (TBROK, cleanup, + "System V Semaphore support is not present in the kernel"); +} + +void +sigchld_handler(int signo) +{ + union semun sun; + struct semid_ds s_ds; + int cstatus; + + /* + * Reap the child; if it exited successfully, then we're on the + * right track! + */ + if (wait(&cstatus) == -1) + tst_brkm (TBROK, cleanup, "wait"); + + if (WIFEXITED(cstatus) == 0) + tst_brkm (TBROK, cleanup, "receiver exited abnormally"); + + if (WEXITSTATUS(cstatus) != 0) + tst_brkm (TBROK, cleanup, "receiver exited with status %d", + WEXITSTATUS(cstatus)); + + /* + * If we get here, the child has exited normally, and we should + * decrement the child count. If the child_count reaches 0, we + * should exit. + */ + + sun.buf = &s_ds; + tst_resm (semctl(sender_semid, 0, IPC_STAT, sun) == -1 ? TFAIL : TPASS, + "semctl IPC_STAT"); + + print_semid_ds(&s_ds, 0600); + + if (--child_count != 0) { + signal_was_sigchld = 1; + return; + } + + cleanup (); +} + +void +cleanup() +{ + + /* + * If we're the sender, and it exists, remove the message queue. + */ + if (child_pid != 0 && sender_semid != -1) { + tst_resm (semctl(sender_semid, 0, IPC_RMID) == -1 + ? TFAIL : TPASS, "semctl IPC_RMID"); + } + tst_exit (); +} + +void +print_semid_ds(struct semid_ds *sp, mode_t mode) +{ + uid_t uid = geteuid(); + gid_t gid = getegid(); + + printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n", + (int)sp->sem_perm.uid, (int)sp->sem_perm.gid, + (int)sp->sem_perm.cuid, (int)sp->sem_perm.cgid, + sp->sem_perm.mode & 0777); + + printf("nsems %u\n", sp->sem_nsems); + + printf("otime: %s", ctime(&sp->sem_otime)); + printf("ctime: %s", ctime(&sp->sem_ctime)); + + /* + * Sanity check a few things. + */ + + tst_resm (sp->sem_perm.uid != uid || sp->sem_perm.cuid != uid + ? TFAIL : TPASS, "uid matches"); + + tst_resm (sp->sem_perm.gid != gid || sp->sem_perm.cgid != gid + ? TFAIL : TPASS, "gid matches"); + + tst_resm ((sp->sem_perm.mode & 0777) != mode + ? TFAIL : TPASS, "mode matches"); +} + +void +waiter() +{ + struct sembuf s; + int semid; + + tst_resm ((semid = semget(semkey, 1, 0)) == -1 ? TFAIL : TPASS, + "waiter: semget"); + + /* + * Attempt to acquire the semaphore. + */ + s.sem_num = 0; + s.sem_op = -1; + s.sem_flg = SEM_UNDO; + + tst_resm (semop(semid, &s, 1) == -1 ? TFAIL : TPASS, + "waiter: semop -1"); + + printf("WOO! GOT THE SEMAPHORE!\n"); + sleep(1); + + /* + * Release the semaphore and exit. + */ + s.sem_num = 0; + s.sem_op = 1; + s.sem_flg = SEM_UNDO; + + tst_resm (semop(semid, &s, 1) == -1 ? TFAIL : TPASS, + "waiter: semop +1"); + + /* Allow parent to receive message before getting SIGCHLD. */ + sleep (1); + exit(0); +} diff --git a/winsup/testsuite/winsup.api/shmtest.c b/winsup/testsuite/winsup.api/shmtest.c new file mode 100644 index 000000000..e1f381664 --- /dev/null +++ b/winsup/testsuite/winsup.api/shmtest.c @@ -0,0 +1,298 @@ +/*- + * Copyright (c) 1999 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Obtained from: $NetBSD: shmtest.c,v 1.3 2002/07/20 08:36:26 grant Exp $ + * $FreeBSD: /repoman/r/ncvs/src/tools/regression/sysvshm/shmtest.c,v 1.1 2002/08/15 06:34:37 alfred Exp $ + */ + +/* + * Test the SVID-compatible Shared Memory facility. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "test.h" +#include "usctest.h" + +const char *TCID = "shmtest"; /* Test program identifier. */ +int TST_TOTAL = 22; /* Total number of test cases. */ +extern int Tst_count; /* Test Case counter for tst_* routines */ + +int main __P((int, char *[])); +void print_shmid_ds __P((struct shmid_ds *, mode_t)); +void sigsys_handler __P((int)); +void sigchld_handler __P((int)); +void cleanup __P((void)); +void receiver __P((void)); + +const char *m_str = "The quick brown fox jumped over the lazy dog."; + +int sender_shmid = -1; +pid_t child_pid; + +key_t shmkey; + +size_t pgsize; + +int +main(argc, argv) + int argc; + char *argv[]; +{ + struct sigaction sa; + struct shmid_ds s_ds; + sigset_t sigmask; + char *shm_buf; + + Tst_count = 0; + +#if 0 + /* + * Install a SIGSYS handler so that we can exit gracefully if + * System V Shared Memory support isn't in the kernel. + */ + sa.sa_handler = sigsys_handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + if (sigaction(SIGSYS, &sa, NULL) == -1) + err(1, "sigaction SIGSYS"); +#endif + + /* + * Install and SIGCHLD handler to deal with all possible exit + * conditions of the receiver. + */ + sa.sa_handler = sigchld_handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + if (sigaction(SIGCHLD, &sa, NULL) == -1) + tst_brkm (TBROK, cleanup, "sigaction SIGCHLD"); + + pgsize = sysconf(_SC_PAGESIZE); + + shmkey = ftok("/", 4160); + tst_resm (shmkey == (key_t)-1 ? TFAIL : TPASS, + "ftok(\"/\") returns valid value"); + + /* + * Initialize child_pid to ourselves to that the cleanup function + * works before we create the receiver. + */ + child_pid = getpid(); + + sender_shmid = shmget(shmkey, pgsize, IPC_CREAT | 0640); + if (sender_shmid == -1 && errno == ENOSYS) + tst_brkm (TRETR, cleanup, + "System V Shared Memory support is not present in the kernel"); + tst_resm (sender_shmid == -1 ? TFAIL : TPASS, "sender calls shmget"); + + tst_resm (shmctl(sender_shmid, IPC_STAT, &s_ds) == -1 ? TFAIL : TPASS, + "shmctl IPC_STAT"); + + print_shmid_ds(&s_ds, 0640); + + s_ds.shm_perm.mode = (s_ds.shm_perm.mode & ~0777) | 0600; + + tst_resm (shmctl(sender_shmid, IPC_SET, &s_ds) == -1 ? TFAIL : TPASS, + "shmctl IPC_SET"); + + memset(&s_ds, 0, sizeof(s_ds)); + + tst_resm (shmctl(sender_shmid, IPC_STAT, &s_ds) == -1 ? TFAIL : TPASS, + "shmctl IPC_STAT"); + + tst_resm ((s_ds.shm_perm.mode & 0777) != 0600 ? TFAIL : TPASS, + "IPC_SET of mode holds"); + + print_shmid_ds(&s_ds, 0600); + + tst_resm ((shm_buf = shmat(sender_shmid, NULL, 0)) == (void *) -1 + ? TFAIL : TPASS, "sender: shmat"); + + /* + * Write the test pattern into the shared memory buffer. + */ + strcpy(shm_buf, m_str); + + switch ((child_pid = fork())) { + case -1: + tst_brkm (TBROK, cleanup, "fork"); + /* NOTREACHED */ + + case 0: + tst_resm (TPASS, "fork"); + receiver(); + break; + + default: + Tst_count += 4; + break; + } + + /* + * Suspend forever; when we get SIGCHLD, the handler will exit. + */ + sigemptyset(&sigmask); + (void) sigsuspend(&sigmask); + + /* + * ...and any other signal is an unexpected error. + */ + tst_brkm (TBROK, cleanup, "sender: received unexpected signal"); + exit (1); +} + +void +sigsys_handler(signo) + int signo; +{ + + tst_brkm (TBROK, cleanup, + "System V Shared Memory support is not present in the kernel"); +} + +void +sigchld_handler(signo) + int signo; +{ + struct shmid_ds s_ds; + int cstatus; + + /* + * Reap the child; if it exited successfully, then the test passed! + */ + if (waitpid(child_pid, &cstatus, 0) != child_pid) + tst_brkm (TBROK, cleanup, "waitpid"); + + if (WIFEXITED(cstatus) == 0) + tst_brkm (TBROK, cleanup, "receiver exited abnormally"); + + if (WEXITSTATUS(cstatus) != 0) + tst_brkm (TBROK, cleanup, "receiver exited with status %d", + WEXITSTATUS(cstatus)); + + /* + * If we get here, the child has exited normally, and thus + * we should exit normally too. First, tho, we print out + * the final stats for the message queue. + */ + + tst_resm (shmctl(sender_shmid, IPC_STAT, &s_ds) == -1 ? TFAIL : TPASS, + "shmctl IPC_STAT"); + + print_shmid_ds(&s_ds, 0600); + + cleanup (); +} + +void +cleanup() +{ + + /* + * If we're the sender, and it exists, remove the shared memory area. + */ + if (child_pid != 0 && sender_shmid != -1) { + tst_resm (shmctl(sender_shmid, IPC_RMID, NULL) == -1 + ? TFAIL : TPASS, "shmctl IPC_RMID"); + } + tst_exit (); +} + +void +print_shmid_ds(sp, mode) + struct shmid_ds *sp; + mode_t mode; +{ + uid_t uid = geteuid(); + gid_t gid = getegid(); + + printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n", + (int)sp->shm_perm.uid, (int)sp->shm_perm.gid, + (int)sp->shm_perm.cuid, (int)sp->shm_perm.cgid, + sp->shm_perm.mode & 0777); + + printf("segsz %lu, lpid %d, cpid %d, nattch %u\n", + (u_long)sp->shm_segsz, sp->shm_lpid, sp->shm_cpid, + sp->shm_nattch); + + printf("atime: %s", ctime(&sp->shm_atime)); + printf("dtime: %s", ctime(&sp->shm_dtime)); + printf("ctime: %s", ctime(&sp->shm_ctime)); + + /* + * Sanity check a few things. + */ + + tst_resm (sp->shm_perm.uid != uid || sp->shm_perm.cuid != uid + ? TFAIL : TPASS, "uid matches"); + + tst_resm (sp->shm_perm.gid != gid || sp->shm_perm.cgid != gid + ? TFAIL : TPASS, "gid matches"); + + tst_resm ((sp->shm_perm.mode & 0777) != mode ? TFAIL : TPASS, + "mode matches"); +} + +void +receiver() +{ + int shmid; + void *shm_buf; + + tst_resm ((shmid = shmget(shmkey, pgsize, 0)) == -1 ? TFAIL : TPASS, + "receiver: shmget"); + + tst_resm ((shm_buf = shmat(shmid, NULL, 0)) == (void *) -1 + ? TFAIL : TPASS, "receiver: shmat"); + + printf("%s\n", (const char *)shm_buf); + tst_resm (strcmp((const char *)shm_buf, m_str) != 0 ? TFAIL : TPASS, + "receiver: data is correct"); + + exit(0); +} -- 2.43.5