diff options
author | ngie <ngie@FreeBSD.org> | 2014-10-02 23:26:49 +0000 |
---|---|---|
committer | ngie <ngie@FreeBSD.org> | 2014-10-02 23:26:49 +0000 |
commit | 3f09b8d0af642c2aeb96a4d667cefb7fe3bce443 (patch) | |
tree | 544932e2a2c5a5a202b752beefba0b3e327b3858 /contrib/netbsd-tests/kernel/t_sysv.c | |
parent | b941fec92da62b0eab650295f4e8a381dbbc04b4 (diff) | |
parent | e1f2d32c0e0678782c353c48364cddedfae58b0a (diff) | |
download | FreeBSD-src-3f09b8d0af642c2aeb96a4d667cefb7fe3bce443.zip FreeBSD-src-3f09b8d0af642c2aeb96a4d667cefb7fe3bce443.tar.gz |
Import the NetBSD test suite from ^/vendor/NetBSD/tests/09.30.2014_20.45 ,
minus the vendor Makefiles
Provide directions for how to bootstrap the vendor sources in
FREEBSD-upgrade
MFC after 2 weeks
Discussed with: rpaulo
Sponsored by: EMC / Isilon Storage Division
Diffstat (limited to 'contrib/netbsd-tests/kernel/t_sysv.c')
-rw-r--r-- | contrib/netbsd-tests/kernel/t_sysv.c | 854 |
1 files changed, 854 insertions, 0 deletions
diff --git a/contrib/netbsd-tests/kernel/t_sysv.c b/contrib/netbsd-tests/kernel/t_sysv.c new file mode 100644 index 0000000..0860d4b --- /dev/null +++ b/contrib/netbsd-tests/kernel/t_sysv.c @@ -0,0 +1,854 @@ +/* $NetBSD: t_sysv.c,v 1.4 2014/03/02 20:13:12 jmmv Exp $ */ + +/*- + * Copyright (c) 1999, 2007 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, and by Andrew Doran. + * + * 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. + * + * 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. + */ + +/* + * Test the SVID-compatible Message Queue facility. + */ + +#include <atf-c.h> + +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> + +#include <sys/ipc.h> +#include <sys/msg.h> +#include <sys/param.h> +#include <sys/sem.h> +#include <sys/shm.h> +#include <sys/wait.h> + +volatile int did_sigsys, did_sigchild; +volatile int child_status, child_count; + +void sigsys_handler(int); +void sigchld_handler(int); + +key_t get_ftok(int); + +void print_msqid_ds(struct msqid_ds *, mode_t); +void receiver(void); + +void print_semid_ds(struct semid_ds *, mode_t); +void waiter(void); + +void print_shmid_ds(struct shmid_ds *, mode_t); +void sharer(void); + +#define MESSAGE_TEXT_LEN 256 + +struct 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."; + +size_t pgsize; + +#define MTYPE_1 1 +#define MTYPE_1_ACK 2 + +#define MTYPE_2 3 +#define MTYPE_2_ACK 4 + +pid_t child_pid; + +key_t msgkey, semkey, shmkey; + +int maxloop = 1; + +union semun { + int val; /* value for SETVAL */ + struct semid_ds *buf; /* buffer for IPC_{STAT,SET} */ + u_short *array; /* array for GETALL & SETALL */ +}; + + +/* Writes an integer to a file. To be used from the body of the test + * cases below to pass any global identifiers to the cleanup routine. */ +static void +write_int(const char *path, const int value) +{ + int output; + + output = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0600); + ATF_REQUIRE_MSG(output != -1, "Failed to create %s", path); + write(output, &value, sizeof(value)); + close(output); +} + + +/* Reads an integer from a file. To be used from the cleanup routines + * of the test cases below. */ +static int +read_int(const char *path) +{ + int input; + + input = open(path, O_RDONLY); + if (input == -1) + return -1; + else { + int value; + read(input, &value, sizeof(value)); + return value; + } +} + + +void +sigsys_handler(int signo) +{ + + did_sigsys = 1; +} + +void +sigchld_handler(int signo) +{ + int c_status; + + did_sigchild = 1; + /* + * Reap the child and return its status + */ + if (wait(&c_status) == -1) + child_status = -errno; + else + child_status = c_status; + + child_count--; +} + +key_t get_ftok(int id) +{ + int fd; + char token_key[64], token_dir[64]; + char *tmpdir; + key_t key; + + strlcpy(token_key, "/tmp/t_sysv.XXXXXX", sizeof(token_key)); + tmpdir = mkdtemp(token_key); + ATF_REQUIRE_MSG(tmpdir != NULL, "mkdtemp() failed: %d", errno); + + strlcpy(token_dir, tmpdir, sizeof(token_dir)); + strlcpy(token_key, tmpdir, sizeof(token_key)); + strlcat(token_key, "/token_key", sizeof(token_key)); + + /* Create the file, since ftok() requires it to exist! */ + + fd = open(token_key, O_RDWR | O_CREAT | O_EXCL); + if (fd == -1) { + rmdir(tmpdir); + atf_tc_fail("open() of temp file failed: %d", errno); + return (key_t)-1; + } else + close(fd); + + key = ftok(token_key, id); + + ATF_REQUIRE_MSG(unlink(token_key) != -1, "unlink() failed: %d", errno); + ATF_REQUIRE_MSG(rmdir(token_dir) != -1, "rmdir() failed: %d", errno); + + return key; +} + +ATF_TC_WITH_CLEANUP(msg); +ATF_TC_HEAD(msg, tc) +{ + + atf_tc_set_md_var(tc, "timeout", "3"); + atf_tc_set_md_var(tc, "descr", "Checks sysvmsg passing"); +} + +ATF_TC_BODY(msg, tc) +{ + struct sigaction sa; + struct msqid_ds m_ds; + struct mymsg m; + sigset_t sigmask; + int sender_msqid; + int loop; + int c_status; + + /* + * Install a SIGSYS handler so that we can exit gracefully if + * System V Message Queue support isn't in the kernel. + */ + did_sigsys = 0; + sa.sa_handler = sigsys_handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + ATF_REQUIRE_MSG(sigaction(SIGSYS, &sa, NULL) != -1, + "sigaction SIGSYS: %d", errno); + + /* + * Install a SIGCHLD handler to deal with all possible exit + * conditions of the receiver. + */ + did_sigchild = 0; + child_count = 0; + sa.sa_handler = sigchld_handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + ATF_REQUIRE_MSG(sigaction(SIGCHLD, &sa, NULL) != -1, + "sigaction SIGCHLD: %d", errno); + + msgkey = get_ftok(4160); + ATF_REQUIRE_MSG(msgkey != (key_t)-1, "get_ftok failed"); + + sender_msqid = msgget(msgkey, IPC_CREAT | 0640); + ATF_REQUIRE_MSG(sender_msqid != -1, "msgget: %d", errno); + write_int("sender_msqid", sender_msqid); + + if (did_sigsys) { + atf_tc_skip("SYSV Message Queue not supported"); + return; + } + + ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds) != -1, + "msgctl IPC_STAT 1: %d", errno); + + print_msqid_ds(&m_ds, 0640); + + m_ds.msg_perm.mode = (m_ds.msg_perm.mode & ~0777) | 0600; + + ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_SET, &m_ds) != -1, + "msgctl IPC_SET: %d", errno); + + memset(&m_ds, 0, sizeof(m_ds)); + + ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds) != -1, + "msgctl IPC_STAT 2: %d", errno); + + ATF_REQUIRE_MSG((m_ds.msg_perm.mode & 0777) == 0600, + "IPC_SET of mode didn't hold"); + + print_msqid_ds(&m_ds, 0600); + + switch ((child_pid = fork())) { + case -1: + atf_tc_fail("fork: %d", errno); + return; + + case 0: + child_count++; + receiver(); + break; + + default: + break; + } + + for (loop = 0; loop < maxloop; loop++) { + /* + * Send the first message to the receiver and wait for the ACK. + */ + m.mtype = MTYPE_1; + strcpy(m.mtext, m1_str); + ATF_REQUIRE_MSG(msgsnd(sender_msqid, &m, MESSAGE_TEXT_LEN, + 0) != -1, "sender: msgsnd 1: %d", errno); + + ATF_REQUIRE_MSG(msgrcv(sender_msqid, &m, MESSAGE_TEXT_LEN, + MTYPE_1_ACK, 0) == MESSAGE_TEXT_LEN, + "sender: msgrcv 1 ack: %d", errno); + + 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); + ATF_REQUIRE_MSG(msgsnd(sender_msqid, &m, MESSAGE_TEXT_LEN, 0) != -1, + "sender: msgsnd 2: %d", errno); + + ATF_REQUIRE_MSG(msgrcv(sender_msqid, &m, MESSAGE_TEXT_LEN, + MTYPE_2_ACK, 0) == MESSAGE_TEXT_LEN, + "sender: msgrcv 2 ack: %d", errno); + } + + /* + * Wait for child to finish + */ + sigemptyset(&sigmask); + (void) sigsuspend(&sigmask); + + /* + * ...and any other signal is an unexpected error. + */ + if (did_sigchild) { + c_status = child_status; + if (c_status < 0) + atf_tc_fail("waitpid: %d", -c_status); + else if (WIFEXITED(c_status) == 0) + atf_tc_fail("child abnormal exit: %d", c_status); + else if (WEXITSTATUS(c_status) != 0) + atf_tc_fail("c status: %d", WEXITSTATUS(c_status)); + else { + ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds) + != -1, "msgctl IPC_STAT: %d", errno); + + print_msqid_ds(&m_ds, 0600); + atf_tc_pass(); + } + } else + atf_tc_fail("sender: received unexpected signal"); +} + +ATF_TC_CLEANUP(msg, tc) +{ + int sender_msqid; + + /* + * Remove the message queue if it exists. + */ + sender_msqid = read_int("sender_msqid"); + if (sender_msqid != -1) + if (msgctl(sender_msqid, IPC_RMID, NULL) == -1) + err(1, "msgctl IPC_RMID"); +} + +void +print_msqid_ds(mp, mode) + 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", + mp->msg_perm.uid, mp->msg_perm.gid, + mp->msg_perm.cuid, 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. + */ + + ATF_REQUIRE_MSG(mp->msg_perm.uid == uid && mp->msg_perm.cuid == uid, + "uid mismatch"); + + ATF_REQUIRE_MSG(mp->msg_perm.gid == gid && mp->msg_perm.cgid == gid, + "gid mismatch"); + + ATF_REQUIRE_MSG((mp->msg_perm.mode & 0777) == mode, "mode mismatch"); +} + +void +receiver() +{ + struct mymsg m; + int msqid, loop; + + if ((msqid = msgget(msgkey, 0)) == -1) + err(1, "receiver: msgget"); + + for (loop = 0; loop < maxloop; loop++) { + /* + * Receive the first message, print it, and send an ACK. + */ + if (msgrcv(msqid, &m, MESSAGE_TEXT_LEN, MTYPE_1, 0) != MESSAGE_TEXT_LEN) + err(1, "receiver: msgrcv 1"); + + printf("%s\n", m.mtext); + if (strcmp(m.mtext, m1_str) != 0) + err(1, "receiver: message 1 data isn't correct"); + + m.mtype = MTYPE_1_ACK; + + if (msgsnd(msqid, &m, MESSAGE_TEXT_LEN, 0) == -1) + err(1, "receiver: msgsnd ack 1"); + + /* + * Receive the second message, print it, and send an ACK. + */ + + if (msgrcv(msqid, &m, MESSAGE_TEXT_LEN, MTYPE_2, 0) != MESSAGE_TEXT_LEN) + err(1, "receiver: msgrcv 2"); + + printf("%s\n", m.mtext); + if (strcmp(m.mtext, m2_str) != 0) + err(1, "receiver: message 2 data isn't correct"); + + m.mtype = MTYPE_2_ACK; + + if (msgsnd(msqid, &m, MESSAGE_TEXT_LEN, 0) == -1) + err(1, "receiver: msgsnd ack 2"); + } + + exit(0); +} + +/* + * Test the SVID-compatible Semaphore facility. + */ + +ATF_TC_WITH_CLEANUP(sem); +ATF_TC_HEAD(sem, tc) +{ + + atf_tc_set_md_var(tc, "timeout", "3"); + atf_tc_set_md_var(tc, "descr", "Checks sysvmsg passing"); +} + +ATF_TC_BODY(sem, tc) +{ + struct sigaction sa; + union semun sun; + struct semid_ds s_ds; + sigset_t sigmask; + int sender_semid; + int i; + int c_status; + + /* + * Install a SIGSYS handler so that we can exit gracefully if + * System V Semaphore support isn't in the kernel. + */ + did_sigsys = 0; + sa.sa_handler = sigsys_handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + ATF_REQUIRE_MSG(sigaction(SIGSYS, &sa, NULL) != -1, + "sigaction SIGSYS: %d", errno); + + /* + * Install a SIGCHLD handler to deal with all possible exit + * conditions of the receiver. + */ + did_sigchild = 0; + child_count = 0; + sa.sa_handler = sigchld_handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + ATF_REQUIRE_MSG(sigaction(SIGCHLD, &sa, NULL) != -1, + "sigaction SIGCHLD: %d", errno); + + semkey = get_ftok(4160); + ATF_REQUIRE_MSG(semkey != (key_t)-1, "get_ftok failed"); + + sender_semid = semget(semkey, 1, IPC_CREAT | 0640); + ATF_REQUIRE_MSG(sender_semid != -1, "semget: %d", errno); + write_int("sender_semid", sender_semid); + + if (did_sigsys) { + atf_tc_skip("SYSV Semaphore not supported"); + return; + } + + sun.buf = &s_ds; + ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_STAT, sun) != -1, + "semctl IPC_STAT: %d", errno); + + print_semid_ds(&s_ds, 0640); + + s_ds.sem_perm.mode = (s_ds.sem_perm.mode & ~0777) | 0600; + + sun.buf = &s_ds; + ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_SET, sun) != -1, + "semctl IPC_SET: %d", errno); + + memset(&s_ds, 0, sizeof(s_ds)); + + sun.buf = &s_ds; + ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_STAT, sun) != -1, + "semctl IPC_STAT: %d", errno); + + ATF_REQUIRE_MSG((s_ds.sem_perm.mode & 0777) == 0600, + "IPC_SET of mode didn't hold"); + + print_semid_ds(&s_ds, 0600); + + for (child_count = 0; child_count < 5; child_count++) { + switch ((child_pid = fork())) { + case -1: + atf_tc_fail("fork: %d", errno); + return; + + case 0: + 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) + atf_tc_fail("semctl GETNCNT: %d", i); + if (i == 5) + break; + } + + /* + * Now set the thundering herd in motion by initializing the + * semaphore to the value 1. + */ + sun.val = 1; + ATF_REQUIRE_MSG(semctl(sender_semid, 0, SETVAL, sun) != -1, + "sender: semctl SETVAL to 1: %d", errno); + + /* + * Wait for all children to finish + */ + sigemptyset(&sigmask); + for (;;) { + (void) sigsuspend(&sigmask); + if (did_sigchild) { + c_status = child_status; + if (c_status < 0) + atf_tc_fail("waitpid: %d", -c_status); + else if (WIFEXITED(c_status) == 0) + atf_tc_fail("c abnormal exit: %d", c_status); + else if (WEXITSTATUS(c_status) != 0) + atf_tc_fail("c status: %d", + WEXITSTATUS(c_status)); + else { + sun.buf = &s_ds; + ATF_REQUIRE_MSG(semctl(sender_semid, 0, + IPC_STAT, sun) != -1, + "semctl IPC_STAT: %d", errno); + + print_semid_ds(&s_ds, 0600); + atf_tc_pass(); + } + if (child_count <= 0) + break; + did_sigchild = 0; + } else { + atf_tc_fail("sender: received unexpected signal"); + break; + } + } +} + +ATF_TC_CLEANUP(sem, tc) +{ + int sender_semid; + + /* + * Remove the semaphore if it exists + */ + sender_semid = read_int("sender_semid"); + if (sender_semid != -1) + if (semctl(sender_semid, 0, IPC_RMID) == -1) + err(1, "semctl IPC_RMID"); +} + +void +print_semid_ds(sp, mode) + 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", + sp->sem_perm.uid, sp->sem_perm.gid, + sp->sem_perm.cuid, 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. + */ + + ATF_REQUIRE_MSG(sp->sem_perm.uid == uid && sp->sem_perm.cuid == uid, + "uid mismatch"); + + ATF_REQUIRE_MSG(sp->sem_perm.gid == gid && sp->sem_perm.cgid == gid, + "gid mismatch"); + + ATF_REQUIRE_MSG((sp->sem_perm.mode & 0777) == mode, + "mode mismatch %o != %o", (sp->sem_perm.mode & 0777), mode); +} + +void +waiter() +{ + struct sembuf s; + int semid; + + if ((semid = semget(semkey, 1, 0)) == -1) + err(1, "waiter: semget"); + + /* + * Attempt to acquire the semaphore. + */ + s.sem_num = 0; + s.sem_op = -1; + s.sem_flg = SEM_UNDO; + + if (semop(semid, &s, 1) == -1) + err(1, "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; + + if (semop(semid, &s, 1) == -1) + err(1, "waiter: semop +1"); + + exit(0); +} + +/* + * Test the SVID-compatible Shared Memory facility. + */ + +ATF_TC_WITH_CLEANUP(shm); +ATF_TC_HEAD(shm, tc) +{ + + atf_tc_set_md_var(tc, "timeout", "3"); + atf_tc_set_md_var(tc, "descr", "Checks sysv shared memory"); +} + +ATF_TC_BODY(shm, tc) +{ + struct sigaction sa; + struct shmid_ds s_ds; + sigset_t sigmask; + char *shm_buf; + int sender_shmid; + int c_status; + + /* + * Install a SIGSYS handler so that we can exit gracefully if + * System V Shared Memory support isn't in the kernel. + */ + did_sigsys = 0; + sa.sa_handler = sigsys_handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + ATF_REQUIRE_MSG(sigaction(SIGSYS, &sa, NULL) != -1, + "sigaction SIGSYS: %d", errno); + + /* + * Install a SIGCHLD handler to deal with all possible exit + * conditions of the sharer. + */ + did_sigchild = 0; + child_count = 0; + sa.sa_handler = sigchld_handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + ATF_REQUIRE_MSG(sigaction(SIGCHLD, &sa, NULL) != -1, + "sigaction SIGCHLD: %d", errno); + + pgsize = sysconf(_SC_PAGESIZE); + + shmkey = get_ftok(4160); + ATF_REQUIRE_MSG(shmkey != (key_t)-1, "get_ftok failed"); + + ATF_REQUIRE_MSG((sender_shmid = shmget(shmkey, pgsize, + IPC_CREAT | 0640)) != -1, + "shmget: %d", errno); + write_int("sender_shmid", sender_shmid); + + ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_STAT, &s_ds) != -1, + "shmctl IPC_STAT: %d", errno); + + print_shmid_ds(&s_ds, 0640); + + s_ds.shm_perm.mode = (s_ds.shm_perm.mode & ~0777) | 0600; + + ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_SET, &s_ds) != -1, + "shmctl IPC_SET: %d", errno); + + memset(&s_ds, 0, sizeof(s_ds)); + + ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_STAT, &s_ds) != -1, + "shmctl IPC_STAT: %d", errno); + + ATF_REQUIRE_MSG((s_ds.shm_perm.mode & 0777) == 0600, + "IPC_SET of mode didn't hold"); + + print_shmid_ds(&s_ds, 0600); + + shm_buf = shmat(sender_shmid, NULL, 0); + ATF_REQUIRE_MSG(shm_buf != (void *) -1, "sender: shmat: %d", errno); + + /* + * Write the test pattern into the shared memory buffer. + */ + strcpy(shm_buf, m2_str); + + switch ((child_pid = fork())) { + case -1: + atf_tc_fail("fork: %d", errno); + return; + + case 0: + sharer(); + break; + + default: + break; + } + + /* + * Wait for child to finish + */ + sigemptyset(&sigmask); + (void) sigsuspend(&sigmask); + + if (did_sigchild) { + c_status = child_status; + if (c_status < 0) + atf_tc_fail("waitpid: %d", -c_status); + else if (WIFEXITED(c_status) == 0) + atf_tc_fail("c abnormal exit: %d", c_status); + else if (WEXITSTATUS(c_status) != 0) + atf_tc_fail("c status: %d", WEXITSTATUS(c_status)); + else { + ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_STAT, + &s_ds) != -1, + "shmctl IPC_STAT: %d", errno); + + print_shmid_ds(&s_ds, 0600); + atf_tc_pass(); + } + } else + atf_tc_fail("sender: received unexpected signal"); +} + +ATF_TC_CLEANUP(shm, tc) +{ + int sender_shmid; + + /* + * Remove the shared memory area if it exists. + */ + sender_shmid = read_int("sender_shmid"); + if (sender_shmid != -1) + if (shmctl(sender_shmid, IPC_RMID, NULL) == -1) + err(1, "shmctl IPC_RMID"); +} + +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", + sp->shm_perm.uid, sp->shm_perm.gid, + sp->shm_perm.cuid, 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. + */ + + ATF_REQUIRE_MSG(sp->shm_perm.uid == uid && sp->shm_perm.cuid == uid, + "uid mismatch"); + + ATF_REQUIRE_MSG(sp->shm_perm.gid == gid && sp->shm_perm.cgid == gid, + "gid mismatch"); + + ATF_REQUIRE_MSG((sp->shm_perm.mode & 0777) == mode, "mode mismatch"); +} + +void +sharer() +{ + int shmid; + void *shm_buf; + + shmid = shmget(shmkey, pgsize, 0); + ATF_REQUIRE_MSG(shmid != -1, "receiver: shmget:%d", errno); + + shm_buf = shmat(shmid, NULL, 0); + ATF_REQUIRE_MSG(shm_buf != (void *) -1, "receiver: shmat: %d", errno); + + printf("%s\n", (const char *)shm_buf); + + ATF_REQUIRE_MSG(strcmp((const char *)shm_buf, m2_str) == 0, + "receiver: data isn't correct"); + + exit(0); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, msg); + ATF_TP_ADD_TC(tp, sem); + ATF_TP_ADD_TC(tp, shm); + + return atf_no_error(); +} + |