1272343Sngie/* $NetBSD: t_sysv.c,v 1.4 2014/03/02 20:13:12 jmmv Exp $ */ 2272343Sngie 3272343Sngie/*- 4272343Sngie * Copyright (c) 1999, 2007 The NetBSD Foundation, Inc. 5272343Sngie * All rights reserved. 6272343Sngie * 7272343Sngie * This code is derived from software contributed to The NetBSD Foundation 8272343Sngie * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 9272343Sngie * NASA Ames Research Center, and by Andrew Doran. 10272343Sngie * 11272343Sngie * Redistribution and use in source and binary forms, with or without 12272343Sngie * modification, are permitted provided that the following conditions 13272343Sngie * are met: 14272343Sngie * 1. Redistributions of source code must retain the above copyright 15272343Sngie * notice, this list of conditions and the following disclaimer. 16272343Sngie * 2. Redistributions in binary form must reproduce the above copyright 17272343Sngie * notice, this list of conditions and the following disclaimer in the 18272343Sngie * documentation and/or other materials provided with the distribution. 19272343Sngie * 20272343Sngie * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21272343Sngie * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22272343Sngie * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23272343Sngie * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24272343Sngie * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25272343Sngie * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26272343Sngie * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27272343Sngie * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28272343Sngie * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29272343Sngie * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30272343Sngie * POSSIBILITY OF SUCH DAMAGE. 31272343Sngie */ 32272343Sngie 33272343Sngie/* 34272343Sngie * Test the SVID-compatible Message Queue facility. 35272343Sngie */ 36272343Sngie 37272343Sngie#include <atf-c.h> 38272343Sngie 39272343Sngie#include <err.h> 40272343Sngie#include <errno.h> 41272343Sngie#include <fcntl.h> 42272343Sngie#include <signal.h> 43272343Sngie#include <stdio.h> 44272343Sngie#include <stdlib.h> 45272343Sngie#include <string.h> 46272343Sngie#include <time.h> 47272343Sngie#include <unistd.h> 48272343Sngie 49272343Sngie#include <sys/ipc.h> 50272343Sngie#include <sys/msg.h> 51272343Sngie#include <sys/param.h> 52272343Sngie#include <sys/sem.h> 53272343Sngie#include <sys/shm.h> 54272343Sngie#include <sys/wait.h> 55272343Sngie 56272343Sngievolatile int did_sigsys, did_sigchild; 57272343Sngievolatile int child_status, child_count; 58272343Sngie 59272343Sngievoid sigsys_handler(int); 60272343Sngievoid sigchld_handler(int); 61272343Sngie 62272343Sngiekey_t get_ftok(int); 63272343Sngie 64272343Sngievoid print_msqid_ds(struct msqid_ds *, mode_t); 65272343Sngievoid receiver(void); 66272343Sngie 67272343Sngievoid print_semid_ds(struct semid_ds *, mode_t); 68272343Sngievoid waiter(void); 69272343Sngie 70272343Sngievoid print_shmid_ds(struct shmid_ds *, mode_t); 71272343Sngievoid sharer(void); 72272343Sngie 73272343Sngie#define MESSAGE_TEXT_LEN 256 74272343Sngie 75272343Sngiestruct mymsg { 76272343Sngie long mtype; 77272343Sngie char mtext[MESSAGE_TEXT_LEN]; 78272343Sngie}; 79272343Sngie 80272343Sngieconst char *m1_str = "California is overrated."; 81272343Sngieconst char *m2_str = "The quick brown fox jumped over the lazy dog."; 82272343Sngie 83272343Sngiesize_t pgsize; 84272343Sngie 85272343Sngie#define MTYPE_1 1 86272343Sngie#define MTYPE_1_ACK 2 87272343Sngie 88272343Sngie#define MTYPE_2 3 89272343Sngie#define MTYPE_2_ACK 4 90272343Sngie 91272343Sngiepid_t child_pid; 92272343Sngie 93272343Sngiekey_t msgkey, semkey, shmkey; 94272343Sngie 95272343Sngieint maxloop = 1; 96272343Sngie 97272343Sngieunion semun { 98272343Sngie int val; /* value for SETVAL */ 99272343Sngie struct semid_ds *buf; /* buffer for IPC_{STAT,SET} */ 100272343Sngie u_short *array; /* array for GETALL & SETALL */ 101272343Sngie}; 102272343Sngie 103272343Sngie 104272343Sngie/* Writes an integer to a file. To be used from the body of the test 105272343Sngie * cases below to pass any global identifiers to the cleanup routine. */ 106272343Sngiestatic void 107272343Sngiewrite_int(const char *path, const int value) 108272343Sngie{ 109272343Sngie int output; 110272343Sngie 111272343Sngie output = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0600); 112272343Sngie ATF_REQUIRE_MSG(output != -1, "Failed to create %s", path); 113272343Sngie write(output, &value, sizeof(value)); 114272343Sngie close(output); 115272343Sngie} 116272343Sngie 117272343Sngie 118272343Sngie/* Reads an integer from a file. To be used from the cleanup routines 119272343Sngie * of the test cases below. */ 120272343Sngiestatic int 121272343Sngieread_int(const char *path) 122272343Sngie{ 123272343Sngie int input; 124272343Sngie 125272343Sngie input = open(path, O_RDONLY); 126272343Sngie if (input == -1) 127272343Sngie return -1; 128272343Sngie else { 129272343Sngie int value; 130272343Sngie read(input, &value, sizeof(value)); 131272343Sngie return value; 132272343Sngie } 133272343Sngie} 134272343Sngie 135272343Sngie 136272343Sngievoid 137272343Sngiesigsys_handler(int signo) 138272343Sngie{ 139272343Sngie 140272343Sngie did_sigsys = 1; 141272343Sngie} 142272343Sngie 143272343Sngievoid 144272343Sngiesigchld_handler(int signo) 145272343Sngie{ 146272343Sngie int c_status; 147272343Sngie 148272343Sngie did_sigchild = 1; 149272343Sngie /* 150272343Sngie * Reap the child and return its status 151272343Sngie */ 152272343Sngie if (wait(&c_status) == -1) 153272343Sngie child_status = -errno; 154272343Sngie else 155272343Sngie child_status = c_status; 156272343Sngie 157272343Sngie child_count--; 158272343Sngie} 159272343Sngie 160272343Sngiekey_t get_ftok(int id) 161272343Sngie{ 162272343Sngie int fd; 163272343Sngie char token_key[64], token_dir[64]; 164272343Sngie char *tmpdir; 165272343Sngie key_t key; 166272343Sngie 167272343Sngie strlcpy(token_key, "/tmp/t_sysv.XXXXXX", sizeof(token_key)); 168272343Sngie tmpdir = mkdtemp(token_key); 169272343Sngie ATF_REQUIRE_MSG(tmpdir != NULL, "mkdtemp() failed: %d", errno); 170272343Sngie 171272343Sngie strlcpy(token_dir, tmpdir, sizeof(token_dir)); 172272343Sngie strlcpy(token_key, tmpdir, sizeof(token_key)); 173272343Sngie strlcat(token_key, "/token_key", sizeof(token_key)); 174272343Sngie 175272343Sngie /* Create the file, since ftok() requires it to exist! */ 176272343Sngie 177272343Sngie fd = open(token_key, O_RDWR | O_CREAT | O_EXCL); 178272343Sngie if (fd == -1) { 179272343Sngie rmdir(tmpdir); 180272343Sngie atf_tc_fail("open() of temp file failed: %d", errno); 181272343Sngie return (key_t)-1; 182272343Sngie } else 183272343Sngie close(fd); 184272343Sngie 185272343Sngie key = ftok(token_key, id); 186272343Sngie 187272343Sngie ATF_REQUIRE_MSG(unlink(token_key) != -1, "unlink() failed: %d", errno); 188272343Sngie ATF_REQUIRE_MSG(rmdir(token_dir) != -1, "rmdir() failed: %d", errno); 189272343Sngie 190272343Sngie return key; 191272343Sngie} 192272343Sngie 193272343SngieATF_TC_WITH_CLEANUP(msg); 194272343SngieATF_TC_HEAD(msg, tc) 195272343Sngie{ 196272343Sngie 197272343Sngie atf_tc_set_md_var(tc, "timeout", "3"); 198272343Sngie atf_tc_set_md_var(tc, "descr", "Checks sysvmsg passing"); 199272343Sngie} 200272343Sngie 201272343SngieATF_TC_BODY(msg, tc) 202272343Sngie{ 203272343Sngie struct sigaction sa; 204272343Sngie struct msqid_ds m_ds; 205272343Sngie struct mymsg m; 206272343Sngie sigset_t sigmask; 207272343Sngie int sender_msqid; 208272343Sngie int loop; 209272343Sngie int c_status; 210272343Sngie 211272343Sngie /* 212272343Sngie * Install a SIGSYS handler so that we can exit gracefully if 213272343Sngie * System V Message Queue support isn't in the kernel. 214272343Sngie */ 215272343Sngie did_sigsys = 0; 216272343Sngie sa.sa_handler = sigsys_handler; 217272343Sngie sigemptyset(&sa.sa_mask); 218272343Sngie sa.sa_flags = 0; 219272343Sngie ATF_REQUIRE_MSG(sigaction(SIGSYS, &sa, NULL) != -1, 220272343Sngie "sigaction SIGSYS: %d", errno); 221272343Sngie 222272343Sngie /* 223272343Sngie * Install a SIGCHLD handler to deal with all possible exit 224272343Sngie * conditions of the receiver. 225272343Sngie */ 226272343Sngie did_sigchild = 0; 227272343Sngie child_count = 0; 228272343Sngie sa.sa_handler = sigchld_handler; 229272343Sngie sigemptyset(&sa.sa_mask); 230272343Sngie sa.sa_flags = 0; 231272343Sngie ATF_REQUIRE_MSG(sigaction(SIGCHLD, &sa, NULL) != -1, 232272343Sngie "sigaction SIGCHLD: %d", errno); 233272343Sngie 234272343Sngie msgkey = get_ftok(4160); 235272343Sngie ATF_REQUIRE_MSG(msgkey != (key_t)-1, "get_ftok failed"); 236272343Sngie 237272343Sngie sender_msqid = msgget(msgkey, IPC_CREAT | 0640); 238272343Sngie ATF_REQUIRE_MSG(sender_msqid != -1, "msgget: %d", errno); 239272343Sngie write_int("sender_msqid", sender_msqid); 240272343Sngie 241272343Sngie if (did_sigsys) { 242272343Sngie atf_tc_skip("SYSV Message Queue not supported"); 243272343Sngie return; 244272343Sngie } 245272343Sngie 246272343Sngie ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds) != -1, 247272343Sngie "msgctl IPC_STAT 1: %d", errno); 248272343Sngie 249272343Sngie print_msqid_ds(&m_ds, 0640); 250272343Sngie 251272343Sngie m_ds.msg_perm.mode = (m_ds.msg_perm.mode & ~0777) | 0600; 252272343Sngie 253272343Sngie ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_SET, &m_ds) != -1, 254272343Sngie "msgctl IPC_SET: %d", errno); 255272343Sngie 256272343Sngie memset(&m_ds, 0, sizeof(m_ds)); 257272343Sngie 258272343Sngie ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds) != -1, 259272343Sngie "msgctl IPC_STAT 2: %d", errno); 260272343Sngie 261272343Sngie ATF_REQUIRE_MSG((m_ds.msg_perm.mode & 0777) == 0600, 262272343Sngie "IPC_SET of mode didn't hold"); 263272343Sngie 264272343Sngie print_msqid_ds(&m_ds, 0600); 265272343Sngie 266272343Sngie switch ((child_pid = fork())) { 267272343Sngie case -1: 268272343Sngie atf_tc_fail("fork: %d", errno); 269272343Sngie return; 270272343Sngie 271272343Sngie case 0: 272272343Sngie child_count++; 273272343Sngie receiver(); 274272343Sngie break; 275272343Sngie 276272343Sngie default: 277272343Sngie break; 278272343Sngie } 279272343Sngie 280272343Sngie for (loop = 0; loop < maxloop; loop++) { 281272343Sngie /* 282272343Sngie * Send the first message to the receiver and wait for the ACK. 283272343Sngie */ 284272343Sngie m.mtype = MTYPE_1; 285272343Sngie strcpy(m.mtext, m1_str); 286272343Sngie ATF_REQUIRE_MSG(msgsnd(sender_msqid, &m, MESSAGE_TEXT_LEN, 287272343Sngie 0) != -1, "sender: msgsnd 1: %d", errno); 288272343Sngie 289272343Sngie ATF_REQUIRE_MSG(msgrcv(sender_msqid, &m, MESSAGE_TEXT_LEN, 290272343Sngie MTYPE_1_ACK, 0) == MESSAGE_TEXT_LEN, 291272343Sngie "sender: msgrcv 1 ack: %d", errno); 292272343Sngie 293272343Sngie print_msqid_ds(&m_ds, 0600); 294272343Sngie 295272343Sngie /* 296272343Sngie * Send the second message to the receiver and wait for the ACK. 297272343Sngie */ 298272343Sngie m.mtype = MTYPE_2; 299272343Sngie strcpy(m.mtext, m2_str); 300272343Sngie ATF_REQUIRE_MSG(msgsnd(sender_msqid, &m, MESSAGE_TEXT_LEN, 0) != -1, 301272343Sngie "sender: msgsnd 2: %d", errno); 302272343Sngie 303272343Sngie ATF_REQUIRE_MSG(msgrcv(sender_msqid, &m, MESSAGE_TEXT_LEN, 304272343Sngie MTYPE_2_ACK, 0) == MESSAGE_TEXT_LEN, 305272343Sngie "sender: msgrcv 2 ack: %d", errno); 306272343Sngie } 307272343Sngie 308272343Sngie /* 309272343Sngie * Wait for child to finish 310272343Sngie */ 311272343Sngie sigemptyset(&sigmask); 312272343Sngie (void) sigsuspend(&sigmask); 313272343Sngie 314272343Sngie /* 315272343Sngie * ...and any other signal is an unexpected error. 316272343Sngie */ 317272343Sngie if (did_sigchild) { 318272343Sngie c_status = child_status; 319272343Sngie if (c_status < 0) 320272343Sngie atf_tc_fail("waitpid: %d", -c_status); 321272343Sngie else if (WIFEXITED(c_status) == 0) 322272343Sngie atf_tc_fail("child abnormal exit: %d", c_status); 323272343Sngie else if (WEXITSTATUS(c_status) != 0) 324272343Sngie atf_tc_fail("c status: %d", WEXITSTATUS(c_status)); 325272343Sngie else { 326272343Sngie ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds) 327272343Sngie != -1, "msgctl IPC_STAT: %d", errno); 328272343Sngie 329272343Sngie print_msqid_ds(&m_ds, 0600); 330272343Sngie atf_tc_pass(); 331272343Sngie } 332272343Sngie } else 333272343Sngie atf_tc_fail("sender: received unexpected signal"); 334272343Sngie} 335272343Sngie 336272343SngieATF_TC_CLEANUP(msg, tc) 337272343Sngie{ 338272343Sngie int sender_msqid; 339272343Sngie 340272343Sngie /* 341272343Sngie * Remove the message queue if it exists. 342272343Sngie */ 343272343Sngie sender_msqid = read_int("sender_msqid"); 344272343Sngie if (sender_msqid != -1) 345272343Sngie if (msgctl(sender_msqid, IPC_RMID, NULL) == -1) 346272343Sngie err(1, "msgctl IPC_RMID"); 347272343Sngie} 348272343Sngie 349272343Sngievoid 350272343Sngieprint_msqid_ds(mp, mode) 351272343Sngie struct msqid_ds *mp; 352272343Sngie mode_t mode; 353272343Sngie{ 354272343Sngie uid_t uid = geteuid(); 355272343Sngie gid_t gid = getegid(); 356272343Sngie 357272343Sngie printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n", 358272343Sngie mp->msg_perm.uid, mp->msg_perm.gid, 359272343Sngie mp->msg_perm.cuid, mp->msg_perm.cgid, 360272343Sngie mp->msg_perm.mode & 0777); 361272343Sngie 362272343Sngie printf("qnum %lu, qbytes %lu, lspid %d, lrpid %d\n", 363272343Sngie mp->msg_qnum, (u_long)mp->msg_qbytes, mp->msg_lspid, 364272343Sngie mp->msg_lrpid); 365272343Sngie 366272343Sngie printf("stime: %s", ctime(&mp->msg_stime)); 367272343Sngie printf("rtime: %s", ctime(&mp->msg_rtime)); 368272343Sngie printf("ctime: %s", ctime(&mp->msg_ctime)); 369272343Sngie 370272343Sngie /* 371272343Sngie * Sanity check a few things. 372272343Sngie */ 373272343Sngie 374272343Sngie ATF_REQUIRE_MSG(mp->msg_perm.uid == uid && mp->msg_perm.cuid == uid, 375272343Sngie "uid mismatch"); 376272343Sngie 377272343Sngie ATF_REQUIRE_MSG(mp->msg_perm.gid == gid && mp->msg_perm.cgid == gid, 378272343Sngie "gid mismatch"); 379272343Sngie 380272343Sngie ATF_REQUIRE_MSG((mp->msg_perm.mode & 0777) == mode, "mode mismatch"); 381272343Sngie} 382272343Sngie 383272343Sngievoid 384272343Sngiereceiver() 385272343Sngie{ 386272343Sngie struct mymsg m; 387272343Sngie int msqid, loop; 388272343Sngie 389272343Sngie if ((msqid = msgget(msgkey, 0)) == -1) 390272343Sngie err(1, "receiver: msgget"); 391272343Sngie 392272343Sngie for (loop = 0; loop < maxloop; loop++) { 393272343Sngie /* 394272343Sngie * Receive the first message, print it, and send an ACK. 395272343Sngie */ 396272343Sngie if (msgrcv(msqid, &m, MESSAGE_TEXT_LEN, MTYPE_1, 0) != MESSAGE_TEXT_LEN) 397272343Sngie err(1, "receiver: msgrcv 1"); 398272343Sngie 399272343Sngie printf("%s\n", m.mtext); 400272343Sngie if (strcmp(m.mtext, m1_str) != 0) 401272343Sngie err(1, "receiver: message 1 data isn't correct"); 402272343Sngie 403272343Sngie m.mtype = MTYPE_1_ACK; 404272343Sngie 405272343Sngie if (msgsnd(msqid, &m, MESSAGE_TEXT_LEN, 0) == -1) 406272343Sngie err(1, "receiver: msgsnd ack 1"); 407272343Sngie 408272343Sngie /* 409272343Sngie * Receive the second message, print it, and send an ACK. 410272343Sngie */ 411272343Sngie 412272343Sngie if (msgrcv(msqid, &m, MESSAGE_TEXT_LEN, MTYPE_2, 0) != MESSAGE_TEXT_LEN) 413272343Sngie err(1, "receiver: msgrcv 2"); 414272343Sngie 415272343Sngie printf("%s\n", m.mtext); 416272343Sngie if (strcmp(m.mtext, m2_str) != 0) 417272343Sngie err(1, "receiver: message 2 data isn't correct"); 418272343Sngie 419272343Sngie m.mtype = MTYPE_2_ACK; 420272343Sngie 421272343Sngie if (msgsnd(msqid, &m, MESSAGE_TEXT_LEN, 0) == -1) 422272343Sngie err(1, "receiver: msgsnd ack 2"); 423272343Sngie } 424272343Sngie 425272343Sngie exit(0); 426272343Sngie} 427272343Sngie 428272343Sngie/* 429272343Sngie * Test the SVID-compatible Semaphore facility. 430272343Sngie */ 431272343Sngie 432272343SngieATF_TC_WITH_CLEANUP(sem); 433272343SngieATF_TC_HEAD(sem, tc) 434272343Sngie{ 435272343Sngie 436272343Sngie atf_tc_set_md_var(tc, "timeout", "3"); 437272343Sngie atf_tc_set_md_var(tc, "descr", "Checks sysvmsg passing"); 438272343Sngie} 439272343Sngie 440272343SngieATF_TC_BODY(sem, tc) 441272343Sngie{ 442272343Sngie struct sigaction sa; 443272343Sngie union semun sun; 444272343Sngie struct semid_ds s_ds; 445272343Sngie sigset_t sigmask; 446272343Sngie int sender_semid; 447272343Sngie int i; 448272343Sngie int c_status; 449272343Sngie 450272343Sngie /* 451272343Sngie * Install a SIGSYS handler so that we can exit gracefully if 452272343Sngie * System V Semaphore support isn't in the kernel. 453272343Sngie */ 454272343Sngie did_sigsys = 0; 455272343Sngie sa.sa_handler = sigsys_handler; 456272343Sngie sigemptyset(&sa.sa_mask); 457272343Sngie sa.sa_flags = 0; 458272343Sngie ATF_REQUIRE_MSG(sigaction(SIGSYS, &sa, NULL) != -1, 459272343Sngie "sigaction SIGSYS: %d", errno); 460272343Sngie 461272343Sngie /* 462272343Sngie * Install a SIGCHLD handler to deal with all possible exit 463272343Sngie * conditions of the receiver. 464272343Sngie */ 465272343Sngie did_sigchild = 0; 466272343Sngie child_count = 0; 467272343Sngie sa.sa_handler = sigchld_handler; 468272343Sngie sigemptyset(&sa.sa_mask); 469272343Sngie sa.sa_flags = 0; 470272343Sngie ATF_REQUIRE_MSG(sigaction(SIGCHLD, &sa, NULL) != -1, 471272343Sngie "sigaction SIGCHLD: %d", errno); 472272343Sngie 473272343Sngie semkey = get_ftok(4160); 474272343Sngie ATF_REQUIRE_MSG(semkey != (key_t)-1, "get_ftok failed"); 475272343Sngie 476272343Sngie sender_semid = semget(semkey, 1, IPC_CREAT | 0640); 477272343Sngie ATF_REQUIRE_MSG(sender_semid != -1, "semget: %d", errno); 478272343Sngie write_int("sender_semid", sender_semid); 479272343Sngie 480272343Sngie if (did_sigsys) { 481272343Sngie atf_tc_skip("SYSV Semaphore not supported"); 482272343Sngie return; 483272343Sngie } 484272343Sngie 485272343Sngie sun.buf = &s_ds; 486272343Sngie ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_STAT, sun) != -1, 487272343Sngie "semctl IPC_STAT: %d", errno); 488272343Sngie 489272343Sngie print_semid_ds(&s_ds, 0640); 490272343Sngie 491272343Sngie s_ds.sem_perm.mode = (s_ds.sem_perm.mode & ~0777) | 0600; 492272343Sngie 493272343Sngie sun.buf = &s_ds; 494272343Sngie ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_SET, sun) != -1, 495272343Sngie "semctl IPC_SET: %d", errno); 496272343Sngie 497272343Sngie memset(&s_ds, 0, sizeof(s_ds)); 498272343Sngie 499272343Sngie sun.buf = &s_ds; 500272343Sngie ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_STAT, sun) != -1, 501272343Sngie "semctl IPC_STAT: %d", errno); 502272343Sngie 503272343Sngie ATF_REQUIRE_MSG((s_ds.sem_perm.mode & 0777) == 0600, 504272343Sngie "IPC_SET of mode didn't hold"); 505272343Sngie 506272343Sngie print_semid_ds(&s_ds, 0600); 507272343Sngie 508272343Sngie for (child_count = 0; child_count < 5; child_count++) { 509272343Sngie switch ((child_pid = fork())) { 510272343Sngie case -1: 511272343Sngie atf_tc_fail("fork: %d", errno); 512272343Sngie return; 513272343Sngie 514272343Sngie case 0: 515272343Sngie waiter(); 516272343Sngie break; 517272343Sngie 518272343Sngie default: 519272343Sngie break; 520272343Sngie } 521272343Sngie } 522272343Sngie 523272343Sngie /* 524272343Sngie * Wait for all of the waiters to be attempting to acquire the 525272343Sngie * semaphore. 526272343Sngie */ 527272343Sngie for (;;) { 528272343Sngie i = semctl(sender_semid, 0, GETNCNT); 529272343Sngie if (i == -1) 530272343Sngie atf_tc_fail("semctl GETNCNT: %d", i); 531272343Sngie if (i == 5) 532272343Sngie break; 533272343Sngie } 534272343Sngie 535272343Sngie /* 536272343Sngie * Now set the thundering herd in motion by initializing the 537272343Sngie * semaphore to the value 1. 538272343Sngie */ 539272343Sngie sun.val = 1; 540272343Sngie ATF_REQUIRE_MSG(semctl(sender_semid, 0, SETVAL, sun) != -1, 541272343Sngie "sender: semctl SETVAL to 1: %d", errno); 542272343Sngie 543272343Sngie /* 544272343Sngie * Wait for all children to finish 545272343Sngie */ 546272343Sngie sigemptyset(&sigmask); 547272343Sngie for (;;) { 548272343Sngie (void) sigsuspend(&sigmask); 549272343Sngie if (did_sigchild) { 550272343Sngie c_status = child_status; 551272343Sngie if (c_status < 0) 552272343Sngie atf_tc_fail("waitpid: %d", -c_status); 553272343Sngie else if (WIFEXITED(c_status) == 0) 554272343Sngie atf_tc_fail("c abnormal exit: %d", c_status); 555272343Sngie else if (WEXITSTATUS(c_status) != 0) 556272343Sngie atf_tc_fail("c status: %d", 557272343Sngie WEXITSTATUS(c_status)); 558272343Sngie else { 559272343Sngie sun.buf = &s_ds; 560272343Sngie ATF_REQUIRE_MSG(semctl(sender_semid, 0, 561272343Sngie IPC_STAT, sun) != -1, 562272343Sngie "semctl IPC_STAT: %d", errno); 563272343Sngie 564272343Sngie print_semid_ds(&s_ds, 0600); 565272343Sngie atf_tc_pass(); 566272343Sngie } 567272343Sngie if (child_count <= 0) 568272343Sngie break; 569272343Sngie did_sigchild = 0; 570272343Sngie } else { 571272343Sngie atf_tc_fail("sender: received unexpected signal"); 572272343Sngie break; 573272343Sngie } 574272343Sngie } 575272343Sngie} 576272343Sngie 577272343SngieATF_TC_CLEANUP(sem, tc) 578272343Sngie{ 579272343Sngie int sender_semid; 580272343Sngie 581272343Sngie /* 582272343Sngie * Remove the semaphore if it exists 583272343Sngie */ 584272343Sngie sender_semid = read_int("sender_semid"); 585272343Sngie if (sender_semid != -1) 586272343Sngie if (semctl(sender_semid, 0, IPC_RMID) == -1) 587272343Sngie err(1, "semctl IPC_RMID"); 588272343Sngie} 589272343Sngie 590272343Sngievoid 591272343Sngieprint_semid_ds(sp, mode) 592272343Sngie struct semid_ds *sp; 593272343Sngie mode_t mode; 594272343Sngie{ 595272343Sngie uid_t uid = geteuid(); 596272343Sngie gid_t gid = getegid(); 597272343Sngie 598272343Sngie printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n", 599272343Sngie sp->sem_perm.uid, sp->sem_perm.gid, 600272343Sngie sp->sem_perm.cuid, sp->sem_perm.cgid, 601272343Sngie sp->sem_perm.mode & 0777); 602272343Sngie 603272343Sngie printf("nsems %u\n", sp->sem_nsems); 604272343Sngie 605272343Sngie printf("otime: %s", ctime(&sp->sem_otime)); 606272343Sngie printf("ctime: %s", ctime(&sp->sem_ctime)); 607272343Sngie 608272343Sngie /* 609272343Sngie * Sanity check a few things. 610272343Sngie */ 611272343Sngie 612272343Sngie ATF_REQUIRE_MSG(sp->sem_perm.uid == uid && sp->sem_perm.cuid == uid, 613272343Sngie "uid mismatch"); 614272343Sngie 615272343Sngie ATF_REQUIRE_MSG(sp->sem_perm.gid == gid && sp->sem_perm.cgid == gid, 616272343Sngie "gid mismatch"); 617272343Sngie 618272343Sngie ATF_REQUIRE_MSG((sp->sem_perm.mode & 0777) == mode, 619272343Sngie "mode mismatch %o != %o", (sp->sem_perm.mode & 0777), mode); 620272343Sngie} 621272343Sngie 622272343Sngievoid 623272343Sngiewaiter() 624272343Sngie{ 625272343Sngie struct sembuf s; 626272343Sngie int semid; 627272343Sngie 628272343Sngie if ((semid = semget(semkey, 1, 0)) == -1) 629272343Sngie err(1, "waiter: semget"); 630272343Sngie 631272343Sngie /* 632272343Sngie * Attempt to acquire the semaphore. 633272343Sngie */ 634272343Sngie s.sem_num = 0; 635272343Sngie s.sem_op = -1; 636272343Sngie s.sem_flg = SEM_UNDO; 637272343Sngie 638272343Sngie if (semop(semid, &s, 1) == -1) 639272343Sngie err(1, "waiter: semop -1"); 640272343Sngie 641272343Sngie printf("WOO! GOT THE SEMAPHORE!\n"); 642272343Sngie sleep(1); 643272343Sngie 644272343Sngie /* 645272343Sngie * Release the semaphore and exit. 646272343Sngie */ 647272343Sngie s.sem_num = 0; 648272343Sngie s.sem_op = 1; 649272343Sngie s.sem_flg = SEM_UNDO; 650272343Sngie 651272343Sngie if (semop(semid, &s, 1) == -1) 652272343Sngie err(1, "waiter: semop +1"); 653272343Sngie 654272343Sngie exit(0); 655272343Sngie} 656272343Sngie 657272343Sngie/* 658272343Sngie * Test the SVID-compatible Shared Memory facility. 659272343Sngie */ 660272343Sngie 661272343SngieATF_TC_WITH_CLEANUP(shm); 662272343SngieATF_TC_HEAD(shm, tc) 663272343Sngie{ 664272343Sngie 665272343Sngie atf_tc_set_md_var(tc, "timeout", "3"); 666272343Sngie atf_tc_set_md_var(tc, "descr", "Checks sysv shared memory"); 667272343Sngie} 668272343Sngie 669272343SngieATF_TC_BODY(shm, tc) 670272343Sngie{ 671272343Sngie struct sigaction sa; 672272343Sngie struct shmid_ds s_ds; 673272343Sngie sigset_t sigmask; 674272343Sngie char *shm_buf; 675272343Sngie int sender_shmid; 676272343Sngie int c_status; 677272343Sngie 678272343Sngie /* 679272343Sngie * Install a SIGSYS handler so that we can exit gracefully if 680272343Sngie * System V Shared Memory support isn't in the kernel. 681272343Sngie */ 682272343Sngie did_sigsys = 0; 683272343Sngie sa.sa_handler = sigsys_handler; 684272343Sngie sigemptyset(&sa.sa_mask); 685272343Sngie sa.sa_flags = 0; 686272343Sngie ATF_REQUIRE_MSG(sigaction(SIGSYS, &sa, NULL) != -1, 687272343Sngie "sigaction SIGSYS: %d", errno); 688272343Sngie 689272343Sngie /* 690272343Sngie * Install a SIGCHLD handler to deal with all possible exit 691272343Sngie * conditions of the sharer. 692272343Sngie */ 693272343Sngie did_sigchild = 0; 694272343Sngie child_count = 0; 695272343Sngie sa.sa_handler = sigchld_handler; 696272343Sngie sigemptyset(&sa.sa_mask); 697272343Sngie sa.sa_flags = 0; 698272343Sngie ATF_REQUIRE_MSG(sigaction(SIGCHLD, &sa, NULL) != -1, 699272343Sngie "sigaction SIGCHLD: %d", errno); 700272343Sngie 701272343Sngie pgsize = sysconf(_SC_PAGESIZE); 702272343Sngie 703272343Sngie shmkey = get_ftok(4160); 704272343Sngie ATF_REQUIRE_MSG(shmkey != (key_t)-1, "get_ftok failed"); 705272343Sngie 706272343Sngie ATF_REQUIRE_MSG((sender_shmid = shmget(shmkey, pgsize, 707272343Sngie IPC_CREAT | 0640)) != -1, 708272343Sngie "shmget: %d", errno); 709272343Sngie write_int("sender_shmid", sender_shmid); 710272343Sngie 711272343Sngie ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_STAT, &s_ds) != -1, 712272343Sngie "shmctl IPC_STAT: %d", errno); 713272343Sngie 714272343Sngie print_shmid_ds(&s_ds, 0640); 715272343Sngie 716272343Sngie s_ds.shm_perm.mode = (s_ds.shm_perm.mode & ~0777) | 0600; 717272343Sngie 718272343Sngie ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_SET, &s_ds) != -1, 719272343Sngie "shmctl IPC_SET: %d", errno); 720272343Sngie 721272343Sngie memset(&s_ds, 0, sizeof(s_ds)); 722272343Sngie 723272343Sngie ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_STAT, &s_ds) != -1, 724272343Sngie "shmctl IPC_STAT: %d", errno); 725272343Sngie 726272343Sngie ATF_REQUIRE_MSG((s_ds.shm_perm.mode & 0777) == 0600, 727272343Sngie "IPC_SET of mode didn't hold"); 728272343Sngie 729272343Sngie print_shmid_ds(&s_ds, 0600); 730272343Sngie 731272343Sngie shm_buf = shmat(sender_shmid, NULL, 0); 732272343Sngie ATF_REQUIRE_MSG(shm_buf != (void *) -1, "sender: shmat: %d", errno); 733272343Sngie 734272343Sngie /* 735272343Sngie * Write the test pattern into the shared memory buffer. 736272343Sngie */ 737272343Sngie strcpy(shm_buf, m2_str); 738272343Sngie 739272343Sngie switch ((child_pid = fork())) { 740272343Sngie case -1: 741272343Sngie atf_tc_fail("fork: %d", errno); 742272343Sngie return; 743272343Sngie 744272343Sngie case 0: 745272343Sngie sharer(); 746272343Sngie break; 747272343Sngie 748272343Sngie default: 749272343Sngie break; 750272343Sngie } 751272343Sngie 752272343Sngie /* 753272343Sngie * Wait for child to finish 754272343Sngie */ 755272343Sngie sigemptyset(&sigmask); 756272343Sngie (void) sigsuspend(&sigmask); 757272343Sngie 758272343Sngie if (did_sigchild) { 759272343Sngie c_status = child_status; 760272343Sngie if (c_status < 0) 761272343Sngie atf_tc_fail("waitpid: %d", -c_status); 762272343Sngie else if (WIFEXITED(c_status) == 0) 763272343Sngie atf_tc_fail("c abnormal exit: %d", c_status); 764272343Sngie else if (WEXITSTATUS(c_status) != 0) 765272343Sngie atf_tc_fail("c status: %d", WEXITSTATUS(c_status)); 766272343Sngie else { 767272343Sngie ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_STAT, 768272343Sngie &s_ds) != -1, 769272343Sngie "shmctl IPC_STAT: %d", errno); 770272343Sngie 771272343Sngie print_shmid_ds(&s_ds, 0600); 772272343Sngie atf_tc_pass(); 773272343Sngie } 774272343Sngie } else 775272343Sngie atf_tc_fail("sender: received unexpected signal"); 776272343Sngie} 777272343Sngie 778272343SngieATF_TC_CLEANUP(shm, tc) 779272343Sngie{ 780272343Sngie int sender_shmid; 781272343Sngie 782272343Sngie /* 783272343Sngie * Remove the shared memory area if it exists. 784272343Sngie */ 785272343Sngie sender_shmid = read_int("sender_shmid"); 786272343Sngie if (sender_shmid != -1) 787272343Sngie if (shmctl(sender_shmid, IPC_RMID, NULL) == -1) 788272343Sngie err(1, "shmctl IPC_RMID"); 789272343Sngie} 790272343Sngie 791272343Sngievoid 792272343Sngieprint_shmid_ds(sp, mode) 793272343Sngie struct shmid_ds *sp; 794272343Sngie mode_t mode; 795272343Sngie{ 796272343Sngie uid_t uid = geteuid(); 797272343Sngie gid_t gid = getegid(); 798272343Sngie 799272343Sngie printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n", 800272343Sngie sp->shm_perm.uid, sp->shm_perm.gid, 801272343Sngie sp->shm_perm.cuid, sp->shm_perm.cgid, 802272343Sngie sp->shm_perm.mode & 0777); 803272343Sngie 804272343Sngie printf("segsz %lu, lpid %d, cpid %d, nattch %u\n", 805272343Sngie (u_long)sp->shm_segsz, sp->shm_lpid, sp->shm_cpid, 806272343Sngie sp->shm_nattch); 807272343Sngie 808272343Sngie printf("atime: %s", ctime(&sp->shm_atime)); 809272343Sngie printf("dtime: %s", ctime(&sp->shm_dtime)); 810272343Sngie printf("ctime: %s", ctime(&sp->shm_ctime)); 811272343Sngie 812272343Sngie /* 813272343Sngie * Sanity check a few things. 814272343Sngie */ 815272343Sngie 816272343Sngie ATF_REQUIRE_MSG(sp->shm_perm.uid == uid && sp->shm_perm.cuid == uid, 817272343Sngie "uid mismatch"); 818272343Sngie 819272343Sngie ATF_REQUIRE_MSG(sp->shm_perm.gid == gid && sp->shm_perm.cgid == gid, 820272343Sngie "gid mismatch"); 821272343Sngie 822272343Sngie ATF_REQUIRE_MSG((sp->shm_perm.mode & 0777) == mode, "mode mismatch"); 823272343Sngie} 824272343Sngie 825272343Sngievoid 826272343Sngiesharer() 827272343Sngie{ 828272343Sngie int shmid; 829272343Sngie void *shm_buf; 830272343Sngie 831272343Sngie shmid = shmget(shmkey, pgsize, 0); 832272343Sngie ATF_REQUIRE_MSG(shmid != -1, "receiver: shmget:%d", errno); 833272343Sngie 834272343Sngie shm_buf = shmat(shmid, NULL, 0); 835272343Sngie ATF_REQUIRE_MSG(shm_buf != (void *) -1, "receiver: shmat: %d", errno); 836272343Sngie 837272343Sngie printf("%s\n", (const char *)shm_buf); 838272343Sngie 839272343Sngie ATF_REQUIRE_MSG(strcmp((const char *)shm_buf, m2_str) == 0, 840272343Sngie "receiver: data isn't correct"); 841272343Sngie 842272343Sngie exit(0); 843272343Sngie} 844272343Sngie 845272343SngieATF_TP_ADD_TCS(tp) 846272343Sngie{ 847272343Sngie 848272343Sngie ATF_TP_ADD_TC(tp, msg); 849272343Sngie ATF_TP_ADD_TC(tp, sem); 850272343Sngie ATF_TP_ADD_TC(tp, shm); 851272343Sngie 852272343Sngie return atf_no_error(); 853272343Sngie} 854272343Sngie 855