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> 50343426Skib#include <sys/mman.h> 51272343Sngie#include <sys/msg.h> 52272343Sngie#include <sys/param.h> 53272343Sngie#include <sys/sem.h> 54272343Sngie#include <sys/shm.h> 55272343Sngie#include <sys/wait.h> 56272343Sngie 57272343Sngievolatile int did_sigsys, did_sigchild; 58272343Sngievolatile int child_status, child_count; 59272343Sngie 60272343Sngievoid sigsys_handler(int); 61272343Sngievoid sigchld_handler(int); 62272343Sngie 63272343Sngiekey_t get_ftok(int); 64272343Sngie 65272343Sngievoid print_msqid_ds(struct msqid_ds *, mode_t); 66272343Sngievoid receiver(void); 67272343Sngie 68272343Sngievoid print_semid_ds(struct semid_ds *, mode_t); 69272343Sngievoid waiter(void); 70272343Sngie 71272343Sngievoid print_shmid_ds(struct shmid_ds *, mode_t); 72272343Sngievoid sharer(void); 73272343Sngie 74272343Sngie#define MESSAGE_TEXT_LEN 256 75272343Sngie 76330731Sasomersstruct testmsg { 77272343Sngie long mtype; 78272343Sngie char mtext[MESSAGE_TEXT_LEN]; 79272343Sngie}; 80272343Sngie 81272343Sngieconst char *m1_str = "California is overrated."; 82272343Sngieconst char *m2_str = "The quick brown fox jumped over the lazy dog."; 83272343Sngie 84272343Sngiesize_t pgsize; 85272343Sngie 86272343Sngie#define MTYPE_1 1 87272343Sngie#define MTYPE_1_ACK 2 88272343Sngie 89272343Sngie#define MTYPE_2 3 90272343Sngie#define MTYPE_2_ACK 4 91272343Sngie 92272343Sngiepid_t child_pid; 93272343Sngie 94272343Sngiekey_t msgkey, semkey, shmkey; 95272343Sngie 96272343Sngieint maxloop = 1; 97272343Sngie 98330731Sasomers#ifndef __FreeBSD__ 99272343Sngieunion semun { 100272343Sngie int val; /* value for SETVAL */ 101272343Sngie struct semid_ds *buf; /* buffer for IPC_{STAT,SET} */ 102272343Sngie u_short *array; /* array for GETALL & SETALL */ 103272343Sngie}; 104330731Sasomers#endif 105272343Sngie 106272343Sngie 107272343Sngie/* Writes an integer to a file. To be used from the body of the test 108272343Sngie * cases below to pass any global identifiers to the cleanup routine. */ 109272343Sngiestatic void 110272343Sngiewrite_int(const char *path, const int value) 111272343Sngie{ 112272343Sngie int output; 113272343Sngie 114272343Sngie output = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0600); 115272343Sngie ATF_REQUIRE_MSG(output != -1, "Failed to create %s", path); 116272343Sngie write(output, &value, sizeof(value)); 117272343Sngie close(output); 118272343Sngie} 119272343Sngie 120272343Sngie 121272343Sngie/* Reads an integer from a file. To be used from the cleanup routines 122272343Sngie * of the test cases below. */ 123272343Sngiestatic int 124272343Sngieread_int(const char *path) 125272343Sngie{ 126272343Sngie int input; 127272343Sngie 128272343Sngie input = open(path, O_RDONLY); 129272343Sngie if (input == -1) 130272343Sngie return -1; 131272343Sngie else { 132272343Sngie int value; 133330731Sasomers ATF_REQUIRE_EQ(read(input, &value, sizeof(value)), sizeof(value)); 134330731Sasomers close(input); 135272343Sngie return value; 136272343Sngie } 137272343Sngie} 138272343Sngie 139272343Sngie 140272343Sngievoid 141272343Sngiesigsys_handler(int signo) 142272343Sngie{ 143272343Sngie 144272343Sngie did_sigsys = 1; 145272343Sngie} 146272343Sngie 147272343Sngievoid 148272343Sngiesigchld_handler(int signo) 149272343Sngie{ 150272343Sngie int c_status; 151272343Sngie 152272343Sngie did_sigchild = 1; 153272343Sngie /* 154272343Sngie * Reap the child and return its status 155272343Sngie */ 156272343Sngie if (wait(&c_status) == -1) 157272343Sngie child_status = -errno; 158272343Sngie else 159272343Sngie child_status = c_status; 160272343Sngie 161272343Sngie child_count--; 162272343Sngie} 163272343Sngie 164272343Sngiekey_t get_ftok(int id) 165272343Sngie{ 166272343Sngie int fd; 167272343Sngie char token_key[64], token_dir[64]; 168272343Sngie char *tmpdir; 169272343Sngie key_t key; 170272343Sngie 171272343Sngie strlcpy(token_key, "/tmp/t_sysv.XXXXXX", sizeof(token_key)); 172272343Sngie tmpdir = mkdtemp(token_key); 173272343Sngie ATF_REQUIRE_MSG(tmpdir != NULL, "mkdtemp() failed: %d", errno); 174272343Sngie 175272343Sngie strlcpy(token_dir, tmpdir, sizeof(token_dir)); 176272343Sngie strlcpy(token_key, tmpdir, sizeof(token_key)); 177272343Sngie strlcat(token_key, "/token_key", sizeof(token_key)); 178272343Sngie 179272343Sngie /* Create the file, since ftok() requires it to exist! */ 180272343Sngie 181330731Sasomers fd = open(token_key, O_RDWR | O_CREAT | O_EXCL, 0600); 182272343Sngie if (fd == -1) { 183272343Sngie rmdir(tmpdir); 184272343Sngie atf_tc_fail("open() of temp file failed: %d", errno); 185272343Sngie return (key_t)-1; 186272343Sngie } else 187272343Sngie close(fd); 188272343Sngie 189272343Sngie key = ftok(token_key, id); 190272343Sngie 191272343Sngie ATF_REQUIRE_MSG(unlink(token_key) != -1, "unlink() failed: %d", errno); 192272343Sngie ATF_REQUIRE_MSG(rmdir(token_dir) != -1, "rmdir() failed: %d", errno); 193272343Sngie 194272343Sngie return key; 195272343Sngie} 196272343Sngie 197272343SngieATF_TC_WITH_CLEANUP(msg); 198272343SngieATF_TC_HEAD(msg, tc) 199272343Sngie{ 200272343Sngie 201272343Sngie atf_tc_set_md_var(tc, "timeout", "3"); 202272343Sngie atf_tc_set_md_var(tc, "descr", "Checks sysvmsg passing"); 203272343Sngie} 204272343Sngie 205272343SngieATF_TC_BODY(msg, tc) 206272343Sngie{ 207272343Sngie struct sigaction sa; 208272343Sngie struct msqid_ds m_ds; 209330731Sasomers struct testmsg m; 210272343Sngie sigset_t sigmask; 211272343Sngie int sender_msqid; 212272343Sngie int loop; 213272343Sngie int c_status; 214272343Sngie 215362658Slwhsu if (atf_tc_get_config_var_as_bool_wd(tc, "ci", false)) 216362658Slwhsu atf_tc_skip("https://bugs.freebsd.org/233649"); 217362658Slwhsu 218272343Sngie /* 219272343Sngie * Install a SIGSYS handler so that we can exit gracefully if 220272343Sngie * System V Message Queue support isn't in the kernel. 221272343Sngie */ 222272343Sngie did_sigsys = 0; 223272343Sngie sa.sa_handler = sigsys_handler; 224272343Sngie sigemptyset(&sa.sa_mask); 225272343Sngie sa.sa_flags = 0; 226272343Sngie ATF_REQUIRE_MSG(sigaction(SIGSYS, &sa, NULL) != -1, 227272343Sngie "sigaction SIGSYS: %d", errno); 228272343Sngie 229272343Sngie /* 230272343Sngie * Install a SIGCHLD handler to deal with all possible exit 231272343Sngie * conditions of the receiver. 232272343Sngie */ 233272343Sngie did_sigchild = 0; 234272343Sngie child_count = 0; 235272343Sngie sa.sa_handler = sigchld_handler; 236272343Sngie sigemptyset(&sa.sa_mask); 237272343Sngie sa.sa_flags = 0; 238272343Sngie ATF_REQUIRE_MSG(sigaction(SIGCHLD, &sa, NULL) != -1, 239272343Sngie "sigaction SIGCHLD: %d", errno); 240272343Sngie 241272343Sngie msgkey = get_ftok(4160); 242272343Sngie ATF_REQUIRE_MSG(msgkey != (key_t)-1, "get_ftok failed"); 243272343Sngie 244272343Sngie sender_msqid = msgget(msgkey, IPC_CREAT | 0640); 245272343Sngie ATF_REQUIRE_MSG(sender_msqid != -1, "msgget: %d", errno); 246272343Sngie write_int("sender_msqid", sender_msqid); 247272343Sngie 248272343Sngie if (did_sigsys) { 249272343Sngie atf_tc_skip("SYSV Message Queue not supported"); 250272343Sngie return; 251272343Sngie } 252272343Sngie 253272343Sngie ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds) != -1, 254272343Sngie "msgctl IPC_STAT 1: %d", errno); 255272343Sngie 256272343Sngie print_msqid_ds(&m_ds, 0640); 257272343Sngie 258272343Sngie m_ds.msg_perm.mode = (m_ds.msg_perm.mode & ~0777) | 0600; 259272343Sngie 260272343Sngie ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_SET, &m_ds) != -1, 261272343Sngie "msgctl IPC_SET: %d", errno); 262272343Sngie 263272343Sngie memset(&m_ds, 0, sizeof(m_ds)); 264272343Sngie 265272343Sngie ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds) != -1, 266272343Sngie "msgctl IPC_STAT 2: %d", errno); 267272343Sngie 268272343Sngie ATF_REQUIRE_MSG((m_ds.msg_perm.mode & 0777) == 0600, 269272343Sngie "IPC_SET of mode didn't hold"); 270272343Sngie 271272343Sngie print_msqid_ds(&m_ds, 0600); 272272343Sngie 273272343Sngie switch ((child_pid = fork())) { 274272343Sngie case -1: 275272343Sngie atf_tc_fail("fork: %d", errno); 276272343Sngie return; 277272343Sngie 278272343Sngie case 0: 279272343Sngie child_count++; 280272343Sngie receiver(); 281272343Sngie break; 282272343Sngie 283272343Sngie default: 284272343Sngie break; 285272343Sngie } 286272343Sngie 287272343Sngie for (loop = 0; loop < maxloop; loop++) { 288272343Sngie /* 289272343Sngie * Send the first message to the receiver and wait for the ACK. 290272343Sngie */ 291272343Sngie m.mtype = MTYPE_1; 292330731Sasomers strlcpy(m.mtext, m1_str, sizeof(m.mtext)); 293272343Sngie ATF_REQUIRE_MSG(msgsnd(sender_msqid, &m, MESSAGE_TEXT_LEN, 294272343Sngie 0) != -1, "sender: msgsnd 1: %d", errno); 295272343Sngie 296272343Sngie ATF_REQUIRE_MSG(msgrcv(sender_msqid, &m, MESSAGE_TEXT_LEN, 297272343Sngie MTYPE_1_ACK, 0) == MESSAGE_TEXT_LEN, 298272343Sngie "sender: msgrcv 1 ack: %d", errno); 299272343Sngie 300272343Sngie print_msqid_ds(&m_ds, 0600); 301272343Sngie 302272343Sngie /* 303272343Sngie * Send the second message to the receiver and wait for the ACK. 304272343Sngie */ 305272343Sngie m.mtype = MTYPE_2; 306330731Sasomers strlcpy(m.mtext, m2_str, sizeof(m.mtext)); 307272343Sngie ATF_REQUIRE_MSG(msgsnd(sender_msqid, &m, MESSAGE_TEXT_LEN, 0) != -1, 308272343Sngie "sender: msgsnd 2: %d", errno); 309272343Sngie 310272343Sngie ATF_REQUIRE_MSG(msgrcv(sender_msqid, &m, MESSAGE_TEXT_LEN, 311272343Sngie MTYPE_2_ACK, 0) == MESSAGE_TEXT_LEN, 312272343Sngie "sender: msgrcv 2 ack: %d", errno); 313272343Sngie } 314272343Sngie 315272343Sngie /* 316272343Sngie * Wait for child to finish 317272343Sngie */ 318272343Sngie sigemptyset(&sigmask); 319272343Sngie (void) sigsuspend(&sigmask); 320272343Sngie 321272343Sngie /* 322272343Sngie * ...and any other signal is an unexpected error. 323272343Sngie */ 324272343Sngie if (did_sigchild) { 325272343Sngie c_status = child_status; 326272343Sngie if (c_status < 0) 327272343Sngie atf_tc_fail("waitpid: %d", -c_status); 328272343Sngie else if (WIFEXITED(c_status) == 0) 329272343Sngie atf_tc_fail("child abnormal exit: %d", c_status); 330272343Sngie else if (WEXITSTATUS(c_status) != 0) 331272343Sngie atf_tc_fail("c status: %d", WEXITSTATUS(c_status)); 332272343Sngie else { 333272343Sngie ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds) 334272343Sngie != -1, "msgctl IPC_STAT: %d", errno); 335272343Sngie 336272343Sngie print_msqid_ds(&m_ds, 0600); 337272343Sngie atf_tc_pass(); 338272343Sngie } 339272343Sngie } else 340272343Sngie atf_tc_fail("sender: received unexpected signal"); 341272343Sngie} 342272343Sngie 343272343SngieATF_TC_CLEANUP(msg, tc) 344272343Sngie{ 345272343Sngie int sender_msqid; 346272343Sngie 347272343Sngie /* 348272343Sngie * Remove the message queue if it exists. 349272343Sngie */ 350272343Sngie sender_msqid = read_int("sender_msqid"); 351272343Sngie if (sender_msqid != -1) 352272343Sngie if (msgctl(sender_msqid, IPC_RMID, NULL) == -1) 353272343Sngie err(1, "msgctl IPC_RMID"); 354272343Sngie} 355272343Sngie 356272343Sngievoid 357330731Sasomersprint_msqid_ds(struct msqid_ds *mp, mode_t mode) 358272343Sngie{ 359272343Sngie uid_t uid = geteuid(); 360272343Sngie gid_t gid = getegid(); 361272343Sngie 362272343Sngie printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n", 363272343Sngie mp->msg_perm.uid, mp->msg_perm.gid, 364272343Sngie mp->msg_perm.cuid, mp->msg_perm.cgid, 365272343Sngie mp->msg_perm.mode & 0777); 366272343Sngie 367272343Sngie printf("qnum %lu, qbytes %lu, lspid %d, lrpid %d\n", 368272343Sngie mp->msg_qnum, (u_long)mp->msg_qbytes, mp->msg_lspid, 369272343Sngie mp->msg_lrpid); 370272343Sngie 371272343Sngie printf("stime: %s", ctime(&mp->msg_stime)); 372272343Sngie printf("rtime: %s", ctime(&mp->msg_rtime)); 373272343Sngie printf("ctime: %s", ctime(&mp->msg_ctime)); 374272343Sngie 375272343Sngie /* 376272343Sngie * Sanity check a few things. 377272343Sngie */ 378272343Sngie 379272343Sngie ATF_REQUIRE_MSG(mp->msg_perm.uid == uid && mp->msg_perm.cuid == uid, 380272343Sngie "uid mismatch"); 381272343Sngie 382272343Sngie ATF_REQUIRE_MSG(mp->msg_perm.gid == gid && mp->msg_perm.cgid == gid, 383272343Sngie "gid mismatch"); 384272343Sngie 385272343Sngie ATF_REQUIRE_MSG((mp->msg_perm.mode & 0777) == mode, "mode mismatch"); 386272343Sngie} 387272343Sngie 388272343Sngievoid 389330731Sasomersreceiver(void) 390272343Sngie{ 391330731Sasomers struct testmsg m; 392272343Sngie int msqid, loop; 393272343Sngie 394272343Sngie if ((msqid = msgget(msgkey, 0)) == -1) 395272343Sngie err(1, "receiver: msgget"); 396272343Sngie 397272343Sngie for (loop = 0; loop < maxloop; loop++) { 398272343Sngie /* 399272343Sngie * Receive the first message, print it, and send an ACK. 400272343Sngie */ 401272343Sngie if (msgrcv(msqid, &m, MESSAGE_TEXT_LEN, MTYPE_1, 0) != MESSAGE_TEXT_LEN) 402272343Sngie err(1, "receiver: msgrcv 1"); 403272343Sngie 404272343Sngie printf("%s\n", m.mtext); 405272343Sngie if (strcmp(m.mtext, m1_str) != 0) 406272343Sngie err(1, "receiver: message 1 data isn't correct"); 407272343Sngie 408272343Sngie m.mtype = MTYPE_1_ACK; 409272343Sngie 410272343Sngie if (msgsnd(msqid, &m, MESSAGE_TEXT_LEN, 0) == -1) 411272343Sngie err(1, "receiver: msgsnd ack 1"); 412272343Sngie 413272343Sngie /* 414272343Sngie * Receive the second message, print it, and send an ACK. 415272343Sngie */ 416272343Sngie 417272343Sngie if (msgrcv(msqid, &m, MESSAGE_TEXT_LEN, MTYPE_2, 0) != MESSAGE_TEXT_LEN) 418272343Sngie err(1, "receiver: msgrcv 2"); 419272343Sngie 420272343Sngie printf("%s\n", m.mtext); 421272343Sngie if (strcmp(m.mtext, m2_str) != 0) 422272343Sngie err(1, "receiver: message 2 data isn't correct"); 423272343Sngie 424272343Sngie m.mtype = MTYPE_2_ACK; 425272343Sngie 426272343Sngie if (msgsnd(msqid, &m, MESSAGE_TEXT_LEN, 0) == -1) 427272343Sngie err(1, "receiver: msgsnd ack 2"); 428272343Sngie } 429272343Sngie 430272343Sngie exit(0); 431272343Sngie} 432272343Sngie 433272343Sngie/* 434272343Sngie * Test the SVID-compatible Semaphore facility. 435272343Sngie */ 436272343Sngie 437272343SngieATF_TC_WITH_CLEANUP(sem); 438272343SngieATF_TC_HEAD(sem, tc) 439272343Sngie{ 440272343Sngie 441272343Sngie atf_tc_set_md_var(tc, "timeout", "3"); 442272343Sngie atf_tc_set_md_var(tc, "descr", "Checks sysvmsg passing"); 443272343Sngie} 444272343Sngie 445272343SngieATF_TC_BODY(sem, tc) 446272343Sngie{ 447272343Sngie struct sigaction sa; 448272343Sngie union semun sun; 449272343Sngie struct semid_ds s_ds; 450272343Sngie sigset_t sigmask; 451272343Sngie int sender_semid; 452272343Sngie int i; 453272343Sngie int c_status; 454272343Sngie 455272343Sngie /* 456272343Sngie * Install a SIGSYS handler so that we can exit gracefully if 457272343Sngie * System V Semaphore support isn't in the kernel. 458272343Sngie */ 459272343Sngie did_sigsys = 0; 460272343Sngie sa.sa_handler = sigsys_handler; 461272343Sngie sigemptyset(&sa.sa_mask); 462272343Sngie sa.sa_flags = 0; 463272343Sngie ATF_REQUIRE_MSG(sigaction(SIGSYS, &sa, NULL) != -1, 464272343Sngie "sigaction SIGSYS: %d", errno); 465272343Sngie 466272343Sngie /* 467272343Sngie * Install a SIGCHLD handler to deal with all possible exit 468272343Sngie * conditions of the receiver. 469272343Sngie */ 470272343Sngie did_sigchild = 0; 471272343Sngie child_count = 0; 472272343Sngie sa.sa_handler = sigchld_handler; 473272343Sngie sigemptyset(&sa.sa_mask); 474272343Sngie sa.sa_flags = 0; 475272343Sngie ATF_REQUIRE_MSG(sigaction(SIGCHLD, &sa, NULL) != -1, 476272343Sngie "sigaction SIGCHLD: %d", errno); 477272343Sngie 478272343Sngie semkey = get_ftok(4160); 479272343Sngie ATF_REQUIRE_MSG(semkey != (key_t)-1, "get_ftok failed"); 480272343Sngie 481272343Sngie sender_semid = semget(semkey, 1, IPC_CREAT | 0640); 482272343Sngie ATF_REQUIRE_MSG(sender_semid != -1, "semget: %d", errno); 483272343Sngie write_int("sender_semid", sender_semid); 484272343Sngie 485272343Sngie if (did_sigsys) { 486272343Sngie atf_tc_skip("SYSV Semaphore not supported"); 487272343Sngie return; 488272343Sngie } 489272343Sngie 490272343Sngie sun.buf = &s_ds; 491272343Sngie ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_STAT, sun) != -1, 492272343Sngie "semctl IPC_STAT: %d", errno); 493272343Sngie 494272343Sngie print_semid_ds(&s_ds, 0640); 495272343Sngie 496272343Sngie s_ds.sem_perm.mode = (s_ds.sem_perm.mode & ~0777) | 0600; 497272343Sngie 498272343Sngie sun.buf = &s_ds; 499272343Sngie ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_SET, sun) != -1, 500272343Sngie "semctl IPC_SET: %d", errno); 501272343Sngie 502272343Sngie memset(&s_ds, 0, sizeof(s_ds)); 503272343Sngie 504272343Sngie sun.buf = &s_ds; 505272343Sngie ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_STAT, sun) != -1, 506272343Sngie "semctl IPC_STAT: %d", errno); 507272343Sngie 508272343Sngie ATF_REQUIRE_MSG((s_ds.sem_perm.mode & 0777) == 0600, 509272343Sngie "IPC_SET of mode didn't hold"); 510272343Sngie 511272343Sngie print_semid_ds(&s_ds, 0600); 512272343Sngie 513272343Sngie for (child_count = 0; child_count < 5; child_count++) { 514272343Sngie switch ((child_pid = fork())) { 515272343Sngie case -1: 516272343Sngie atf_tc_fail("fork: %d", errno); 517272343Sngie return; 518272343Sngie 519272343Sngie case 0: 520272343Sngie waiter(); 521272343Sngie break; 522272343Sngie 523272343Sngie default: 524272343Sngie break; 525272343Sngie } 526272343Sngie } 527272343Sngie 528272343Sngie /* 529272343Sngie * Wait for all of the waiters to be attempting to acquire the 530272343Sngie * semaphore. 531272343Sngie */ 532272343Sngie for (;;) { 533272343Sngie i = semctl(sender_semid, 0, GETNCNT); 534272343Sngie if (i == -1) 535272343Sngie atf_tc_fail("semctl GETNCNT: %d", i); 536272343Sngie if (i == 5) 537272343Sngie break; 538272343Sngie } 539272343Sngie 540272343Sngie /* 541272343Sngie * Now set the thundering herd in motion by initializing the 542272343Sngie * semaphore to the value 1. 543272343Sngie */ 544272343Sngie sun.val = 1; 545272343Sngie ATF_REQUIRE_MSG(semctl(sender_semid, 0, SETVAL, sun) != -1, 546272343Sngie "sender: semctl SETVAL to 1: %d", errno); 547272343Sngie 548272343Sngie /* 549272343Sngie * Wait for all children to finish 550272343Sngie */ 551272343Sngie sigemptyset(&sigmask); 552272343Sngie for (;;) { 553272343Sngie (void) sigsuspend(&sigmask); 554272343Sngie if (did_sigchild) { 555272343Sngie c_status = child_status; 556272343Sngie if (c_status < 0) 557272343Sngie atf_tc_fail("waitpid: %d", -c_status); 558272343Sngie else if (WIFEXITED(c_status) == 0) 559272343Sngie atf_tc_fail("c abnormal exit: %d", c_status); 560272343Sngie else if (WEXITSTATUS(c_status) != 0) 561272343Sngie atf_tc_fail("c status: %d", 562272343Sngie WEXITSTATUS(c_status)); 563272343Sngie else { 564272343Sngie sun.buf = &s_ds; 565272343Sngie ATF_REQUIRE_MSG(semctl(sender_semid, 0, 566272343Sngie IPC_STAT, sun) != -1, 567272343Sngie "semctl IPC_STAT: %d", errno); 568272343Sngie 569272343Sngie print_semid_ds(&s_ds, 0600); 570272343Sngie atf_tc_pass(); 571272343Sngie } 572272343Sngie if (child_count <= 0) 573272343Sngie break; 574272343Sngie did_sigchild = 0; 575272343Sngie } else { 576272343Sngie atf_tc_fail("sender: received unexpected signal"); 577272343Sngie break; 578272343Sngie } 579272343Sngie } 580272343Sngie} 581272343Sngie 582272343SngieATF_TC_CLEANUP(sem, tc) 583272343Sngie{ 584272343Sngie int sender_semid; 585272343Sngie 586272343Sngie /* 587272343Sngie * Remove the semaphore if it exists 588272343Sngie */ 589272343Sngie sender_semid = read_int("sender_semid"); 590272343Sngie if (sender_semid != -1) 591272343Sngie if (semctl(sender_semid, 0, IPC_RMID) == -1) 592272343Sngie err(1, "semctl IPC_RMID"); 593272343Sngie} 594272343Sngie 595272343Sngievoid 596330731Sasomersprint_semid_ds(struct semid_ds *sp, mode_t mode) 597272343Sngie{ 598272343Sngie uid_t uid = geteuid(); 599272343Sngie gid_t gid = getegid(); 600272343Sngie 601272343Sngie printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n", 602272343Sngie sp->sem_perm.uid, sp->sem_perm.gid, 603272343Sngie sp->sem_perm.cuid, sp->sem_perm.cgid, 604272343Sngie sp->sem_perm.mode & 0777); 605272343Sngie 606272343Sngie printf("nsems %u\n", sp->sem_nsems); 607272343Sngie 608272343Sngie printf("otime: %s", ctime(&sp->sem_otime)); 609272343Sngie printf("ctime: %s", ctime(&sp->sem_ctime)); 610272343Sngie 611272343Sngie /* 612272343Sngie * Sanity check a few things. 613272343Sngie */ 614272343Sngie 615272343Sngie ATF_REQUIRE_MSG(sp->sem_perm.uid == uid && sp->sem_perm.cuid == uid, 616272343Sngie "uid mismatch"); 617272343Sngie 618272343Sngie ATF_REQUIRE_MSG(sp->sem_perm.gid == gid && sp->sem_perm.cgid == gid, 619272343Sngie "gid mismatch"); 620272343Sngie 621272343Sngie ATF_REQUIRE_MSG((sp->sem_perm.mode & 0777) == mode, 622272343Sngie "mode mismatch %o != %o", (sp->sem_perm.mode & 0777), mode); 623272343Sngie} 624272343Sngie 625272343Sngievoid 626330731Sasomerswaiter(void) 627272343Sngie{ 628272343Sngie struct sembuf s; 629272343Sngie int semid; 630272343Sngie 631272343Sngie if ((semid = semget(semkey, 1, 0)) == -1) 632272343Sngie err(1, "waiter: semget"); 633272343Sngie 634272343Sngie /* 635272343Sngie * Attempt to acquire the semaphore. 636272343Sngie */ 637272343Sngie s.sem_num = 0; 638272343Sngie s.sem_op = -1; 639272343Sngie s.sem_flg = SEM_UNDO; 640272343Sngie 641272343Sngie if (semop(semid, &s, 1) == -1) 642272343Sngie err(1, "waiter: semop -1"); 643272343Sngie 644272343Sngie printf("WOO! GOT THE SEMAPHORE!\n"); 645272343Sngie sleep(1); 646272343Sngie 647272343Sngie /* 648272343Sngie * Release the semaphore and exit. 649272343Sngie */ 650272343Sngie s.sem_num = 0; 651272343Sngie s.sem_op = 1; 652272343Sngie s.sem_flg = SEM_UNDO; 653272343Sngie 654272343Sngie if (semop(semid, &s, 1) == -1) 655272343Sngie err(1, "waiter: semop +1"); 656272343Sngie 657272343Sngie exit(0); 658272343Sngie} 659272343Sngie 660272343Sngie/* 661272343Sngie * Test the SVID-compatible Shared Memory facility. 662272343Sngie */ 663272343Sngie 664272343SngieATF_TC_WITH_CLEANUP(shm); 665272343SngieATF_TC_HEAD(shm, tc) 666272343Sngie{ 667272343Sngie 668272343Sngie atf_tc_set_md_var(tc, "timeout", "3"); 669272343Sngie atf_tc_set_md_var(tc, "descr", "Checks sysv shared memory"); 670272343Sngie} 671272343Sngie 672272343SngieATF_TC_BODY(shm, tc) 673272343Sngie{ 674272343Sngie struct sigaction sa; 675272343Sngie struct shmid_ds s_ds; 676272343Sngie sigset_t sigmask; 677272343Sngie char *shm_buf; 678272343Sngie int sender_shmid; 679272343Sngie int c_status; 680272343Sngie 681272343Sngie /* 682272343Sngie * Install a SIGSYS handler so that we can exit gracefully if 683272343Sngie * System V Shared Memory support isn't in the kernel. 684272343Sngie */ 685272343Sngie did_sigsys = 0; 686272343Sngie sa.sa_handler = sigsys_handler; 687272343Sngie sigemptyset(&sa.sa_mask); 688272343Sngie sa.sa_flags = 0; 689272343Sngie ATF_REQUIRE_MSG(sigaction(SIGSYS, &sa, NULL) != -1, 690272343Sngie "sigaction SIGSYS: %d", errno); 691272343Sngie 692272343Sngie /* 693272343Sngie * Install a SIGCHLD handler to deal with all possible exit 694272343Sngie * conditions of the sharer. 695272343Sngie */ 696272343Sngie did_sigchild = 0; 697272343Sngie child_count = 0; 698272343Sngie sa.sa_handler = sigchld_handler; 699272343Sngie sigemptyset(&sa.sa_mask); 700272343Sngie sa.sa_flags = 0; 701272343Sngie ATF_REQUIRE_MSG(sigaction(SIGCHLD, &sa, NULL) != -1, 702272343Sngie "sigaction SIGCHLD: %d", errno); 703272343Sngie 704272343Sngie pgsize = sysconf(_SC_PAGESIZE); 705272343Sngie 706272343Sngie shmkey = get_ftok(4160); 707272343Sngie ATF_REQUIRE_MSG(shmkey != (key_t)-1, "get_ftok failed"); 708272343Sngie 709272343Sngie ATF_REQUIRE_MSG((sender_shmid = shmget(shmkey, pgsize, 710272343Sngie IPC_CREAT | 0640)) != -1, 711272343Sngie "shmget: %d", errno); 712272343Sngie write_int("sender_shmid", sender_shmid); 713272343Sngie 714272343Sngie ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_STAT, &s_ds) != -1, 715272343Sngie "shmctl IPC_STAT: %d", errno); 716272343Sngie 717272343Sngie print_shmid_ds(&s_ds, 0640); 718272343Sngie 719272343Sngie s_ds.shm_perm.mode = (s_ds.shm_perm.mode & ~0777) | 0600; 720272343Sngie 721272343Sngie ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_SET, &s_ds) != -1, 722272343Sngie "shmctl IPC_SET: %d", errno); 723272343Sngie 724272343Sngie memset(&s_ds, 0, sizeof(s_ds)); 725272343Sngie 726272343Sngie ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_STAT, &s_ds) != -1, 727272343Sngie "shmctl IPC_STAT: %d", errno); 728272343Sngie 729272343Sngie ATF_REQUIRE_MSG((s_ds.shm_perm.mode & 0777) == 0600, 730272343Sngie "IPC_SET of mode didn't hold"); 731272343Sngie 732272343Sngie print_shmid_ds(&s_ds, 0600); 733272343Sngie 734272343Sngie shm_buf = shmat(sender_shmid, NULL, 0); 735272343Sngie ATF_REQUIRE_MSG(shm_buf != (void *) -1, "sender: shmat: %d", errno); 736272343Sngie 737272343Sngie /* 738272343Sngie * Write the test pattern into the shared memory buffer. 739272343Sngie */ 740272343Sngie strcpy(shm_buf, m2_str); 741272343Sngie 742272343Sngie switch ((child_pid = fork())) { 743272343Sngie case -1: 744272343Sngie atf_tc_fail("fork: %d", errno); 745272343Sngie return; 746272343Sngie 747272343Sngie case 0: 748272343Sngie sharer(); 749272343Sngie break; 750272343Sngie 751272343Sngie default: 752272343Sngie break; 753272343Sngie } 754272343Sngie 755272343Sngie /* 756272343Sngie * Wait for child to finish 757272343Sngie */ 758272343Sngie sigemptyset(&sigmask); 759272343Sngie (void) sigsuspend(&sigmask); 760272343Sngie 761272343Sngie if (did_sigchild) { 762272343Sngie c_status = child_status; 763272343Sngie if (c_status < 0) 764272343Sngie atf_tc_fail("waitpid: %d", -c_status); 765272343Sngie else if (WIFEXITED(c_status) == 0) 766272343Sngie atf_tc_fail("c abnormal exit: %d", c_status); 767272343Sngie else if (WEXITSTATUS(c_status) != 0) 768272343Sngie atf_tc_fail("c status: %d", WEXITSTATUS(c_status)); 769272343Sngie else { 770272343Sngie ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_STAT, 771272343Sngie &s_ds) != -1, 772272343Sngie "shmctl IPC_STAT: %d", errno); 773272343Sngie 774272343Sngie print_shmid_ds(&s_ds, 0600); 775272343Sngie atf_tc_pass(); 776272343Sngie } 777272343Sngie } else 778272343Sngie atf_tc_fail("sender: received unexpected signal"); 779272343Sngie} 780272343Sngie 781343426Skibstatic void 782343426Skibshmid_cleanup(const char *name) 783272343Sngie{ 784343426Skib int shmid; 785272343Sngie 786272343Sngie /* 787272343Sngie * Remove the shared memory area if it exists. 788272343Sngie */ 789343426Skib shmid = read_int(name); 790343426Skib if (shmid != -1) { 791343426Skib if (shmctl(shmid, IPC_RMID, NULL) == -1) 792272343Sngie err(1, "shmctl IPC_RMID"); 793343426Skib } 794272343Sngie} 795272343Sngie 796343426SkibATF_TC_CLEANUP(shm, tc) 797343426Skib{ 798343426Skib 799343426Skib shmid_cleanup("sender_shmid"); 800343426Skib} 801343426Skib 802272343Sngievoid 803330731Sasomersprint_shmid_ds(struct shmid_ds *sp, mode_t mode) 804272343Sngie{ 805272343Sngie uid_t uid = geteuid(); 806272343Sngie gid_t gid = getegid(); 807272343Sngie 808272343Sngie printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n", 809272343Sngie sp->shm_perm.uid, sp->shm_perm.gid, 810272343Sngie sp->shm_perm.cuid, sp->shm_perm.cgid, 811272343Sngie sp->shm_perm.mode & 0777); 812272343Sngie 813272343Sngie printf("segsz %lu, lpid %d, cpid %d, nattch %u\n", 814272343Sngie (u_long)sp->shm_segsz, sp->shm_lpid, sp->shm_cpid, 815272343Sngie sp->shm_nattch); 816272343Sngie 817272343Sngie printf("atime: %s", ctime(&sp->shm_atime)); 818272343Sngie printf("dtime: %s", ctime(&sp->shm_dtime)); 819272343Sngie printf("ctime: %s", ctime(&sp->shm_ctime)); 820272343Sngie 821272343Sngie /* 822272343Sngie * Sanity check a few things. 823272343Sngie */ 824272343Sngie 825272343Sngie ATF_REQUIRE_MSG(sp->shm_perm.uid == uid && sp->shm_perm.cuid == uid, 826272343Sngie "uid mismatch"); 827272343Sngie 828272343Sngie ATF_REQUIRE_MSG(sp->shm_perm.gid == gid && sp->shm_perm.cgid == gid, 829272343Sngie "gid mismatch"); 830272343Sngie 831272343Sngie ATF_REQUIRE_MSG((sp->shm_perm.mode & 0777) == mode, "mode mismatch"); 832272343Sngie} 833272343Sngie 834272343Sngievoid 835330731Sasomerssharer(void) 836272343Sngie{ 837272343Sngie int shmid; 838272343Sngie void *shm_buf; 839272343Sngie 840272343Sngie shmid = shmget(shmkey, pgsize, 0); 841272343Sngie ATF_REQUIRE_MSG(shmid != -1, "receiver: shmget:%d", errno); 842272343Sngie 843272343Sngie shm_buf = shmat(shmid, NULL, 0); 844272343Sngie ATF_REQUIRE_MSG(shm_buf != (void *) -1, "receiver: shmat: %d", errno); 845272343Sngie 846272343Sngie printf("%s\n", (const char *)shm_buf); 847272343Sngie 848272343Sngie ATF_REQUIRE_MSG(strcmp((const char *)shm_buf, m2_str) == 0, 849272343Sngie "receiver: data isn't correct"); 850272343Sngie 851272343Sngie exit(0); 852272343Sngie} 853272343Sngie 854343426Skib#ifdef SHM_REMAP 855343426SkibATF_TC_WITH_CLEANUP(shm_remap); 856343426SkibATF_TC_HEAD(shm_remap, tc) 857343426Skib{ 858343426Skib 859343426Skib atf_tc_set_md_var(tc, "descr", "Checks SHM_REMAP"); 860343426Skib} 861343426Skib 862343426SkibATF_TC_BODY(shm_remap, tc) 863343426Skib{ 864343426Skib char *shm_buf; 865343426Skib int shmid_remap; 866343426Skib 867343426Skib pgsize = sysconf(_SC_PAGESIZE); 868343426Skib 869343426Skib shmkey = get_ftok(4160); 870343426Skib ATF_REQUIRE_MSG(shmkey != (key_t)-1, "get_ftok failed"); 871343426Skib 872343426Skib ATF_REQUIRE_MSG((shmid_remap = shmget(shmkey, pgsize, 873343426Skib IPC_CREAT | 0640)) != -1, "shmget: %d", errno); 874343426Skib write_int("shmid_remap", shmid_remap); 875343426Skib 876343426Skib ATF_REQUIRE_MSG((shm_buf = mmap(NULL, pgsize, PROT_READ | PROT_WRITE, 877343426Skib MAP_ANON | MAP_PRIVATE, -1, 0)) != MAP_FAILED, "mmap: %d", errno); 878343426Skib 879343426Skib ATF_REQUIRE_MSG(shmat(shmid_remap, shm_buf, 0) == (void *)-1, 880343426Skib "shmat without MAP_REMAP succeeded"); 881343426Skib ATF_REQUIRE_MSG(shmat(shmid_remap, shm_buf, SHM_REMAP) == shm_buf, 882343426Skib "shmat(SHM_REMAP): %d", errno); 883343426Skib} 884343426Skib 885343426SkibATF_TC_CLEANUP(shm_remap, tc) 886343426Skib{ 887343426Skib 888343426Skib shmid_cleanup("shmid_remap"); 889343426Skib} 890343426Skib#endif /* SHM_REMAP */ 891343426Skib 892272343SngieATF_TP_ADD_TCS(tp) 893272343Sngie{ 894272343Sngie 895343357Skib ATF_TP_ADD_TC(tp, msg); 896343357Skib ATF_TP_ADD_TC(tp, sem); 897343357Skib ATF_TP_ADD_TC(tp, shm); 898343426Skib#ifdef SHM_REMAP 899343426Skib ATF_TP_ADD_TC(tp, shm_remap); 900343426Skib#endif 901272343Sngie 902272343Sngie return atf_no_error(); 903272343Sngie} 904272343Sngie 905