t_sysv.c revision 362658
1/* $NetBSD: t_sysv.c,v 1.4 2014/03/02 20:13:12 jmmv Exp $ */ 2 3/*- 4 * Copyright (c) 1999, 2007 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 9 * NASA Ames Research Center, and by Andrew Doran. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33/* 34 * Test the SVID-compatible Message Queue facility. 35 */ 36 37#include <atf-c.h> 38 39#include <err.h> 40#include <errno.h> 41#include <fcntl.h> 42#include <signal.h> 43#include <stdio.h> 44#include <stdlib.h> 45#include <string.h> 46#include <time.h> 47#include <unistd.h> 48 49#include <sys/ipc.h> 50#include <sys/mman.h> 51#include <sys/msg.h> 52#include <sys/param.h> 53#include <sys/sem.h> 54#include <sys/shm.h> 55#include <sys/wait.h> 56 57volatile int did_sigsys, did_sigchild; 58volatile int child_status, child_count; 59 60void sigsys_handler(int); 61void sigchld_handler(int); 62 63key_t get_ftok(int); 64 65void print_msqid_ds(struct msqid_ds *, mode_t); 66void receiver(void); 67 68void print_semid_ds(struct semid_ds *, mode_t); 69void waiter(void); 70 71void print_shmid_ds(struct shmid_ds *, mode_t); 72void sharer(void); 73 74#define MESSAGE_TEXT_LEN 256 75 76struct testmsg { 77 long mtype; 78 char mtext[MESSAGE_TEXT_LEN]; 79}; 80 81const char *m1_str = "California is overrated."; 82const char *m2_str = "The quick brown fox jumped over the lazy dog."; 83 84size_t pgsize; 85 86#define MTYPE_1 1 87#define MTYPE_1_ACK 2 88 89#define MTYPE_2 3 90#define MTYPE_2_ACK 4 91 92pid_t child_pid; 93 94key_t msgkey, semkey, shmkey; 95 96int maxloop = 1; 97 98#ifndef __FreeBSD__ 99union semun { 100 int val; /* value for SETVAL */ 101 struct semid_ds *buf; /* buffer for IPC_{STAT,SET} */ 102 u_short *array; /* array for GETALL & SETALL */ 103}; 104#endif 105 106 107/* Writes an integer to a file. To be used from the body of the test 108 * cases below to pass any global identifiers to the cleanup routine. */ 109static void 110write_int(const char *path, const int value) 111{ 112 int output; 113 114 output = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0600); 115 ATF_REQUIRE_MSG(output != -1, "Failed to create %s", path); 116 write(output, &value, sizeof(value)); 117 close(output); 118} 119 120 121/* Reads an integer from a file. To be used from the cleanup routines 122 * of the test cases below. */ 123static int 124read_int(const char *path) 125{ 126 int input; 127 128 input = open(path, O_RDONLY); 129 if (input == -1) 130 return -1; 131 else { 132 int value; 133 ATF_REQUIRE_EQ(read(input, &value, sizeof(value)), sizeof(value)); 134 close(input); 135 return value; 136 } 137} 138 139 140void 141sigsys_handler(int signo) 142{ 143 144 did_sigsys = 1; 145} 146 147void 148sigchld_handler(int signo) 149{ 150 int c_status; 151 152 did_sigchild = 1; 153 /* 154 * Reap the child and return its status 155 */ 156 if (wait(&c_status) == -1) 157 child_status = -errno; 158 else 159 child_status = c_status; 160 161 child_count--; 162} 163 164key_t get_ftok(int id) 165{ 166 int fd; 167 char token_key[64], token_dir[64]; 168 char *tmpdir; 169 key_t key; 170 171 strlcpy(token_key, "/tmp/t_sysv.XXXXXX", sizeof(token_key)); 172 tmpdir = mkdtemp(token_key); 173 ATF_REQUIRE_MSG(tmpdir != NULL, "mkdtemp() failed: %d", errno); 174 175 strlcpy(token_dir, tmpdir, sizeof(token_dir)); 176 strlcpy(token_key, tmpdir, sizeof(token_key)); 177 strlcat(token_key, "/token_key", sizeof(token_key)); 178 179 /* Create the file, since ftok() requires it to exist! */ 180 181 fd = open(token_key, O_RDWR | O_CREAT | O_EXCL, 0600); 182 if (fd == -1) { 183 rmdir(tmpdir); 184 atf_tc_fail("open() of temp file failed: %d", errno); 185 return (key_t)-1; 186 } else 187 close(fd); 188 189 key = ftok(token_key, id); 190 191 ATF_REQUIRE_MSG(unlink(token_key) != -1, "unlink() failed: %d", errno); 192 ATF_REQUIRE_MSG(rmdir(token_dir) != -1, "rmdir() failed: %d", errno); 193 194 return key; 195} 196 197ATF_TC_WITH_CLEANUP(msg); 198ATF_TC_HEAD(msg, tc) 199{ 200 201 atf_tc_set_md_var(tc, "timeout", "3"); 202 atf_tc_set_md_var(tc, "descr", "Checks sysvmsg passing"); 203} 204 205ATF_TC_BODY(msg, tc) 206{ 207 struct sigaction sa; 208 struct msqid_ds m_ds; 209 struct testmsg m; 210 sigset_t sigmask; 211 int sender_msqid; 212 int loop; 213 int c_status; 214 215 if (atf_tc_get_config_var_as_bool_wd(tc, "ci", false)) 216 atf_tc_skip("https://bugs.freebsd.org/233649"); 217 218 /* 219 * Install a SIGSYS handler so that we can exit gracefully if 220 * System V Message Queue support isn't in the kernel. 221 */ 222 did_sigsys = 0; 223 sa.sa_handler = sigsys_handler; 224 sigemptyset(&sa.sa_mask); 225 sa.sa_flags = 0; 226 ATF_REQUIRE_MSG(sigaction(SIGSYS, &sa, NULL) != -1, 227 "sigaction SIGSYS: %d", errno); 228 229 /* 230 * Install a SIGCHLD handler to deal with all possible exit 231 * conditions of the receiver. 232 */ 233 did_sigchild = 0; 234 child_count = 0; 235 sa.sa_handler = sigchld_handler; 236 sigemptyset(&sa.sa_mask); 237 sa.sa_flags = 0; 238 ATF_REQUIRE_MSG(sigaction(SIGCHLD, &sa, NULL) != -1, 239 "sigaction SIGCHLD: %d", errno); 240 241 msgkey = get_ftok(4160); 242 ATF_REQUIRE_MSG(msgkey != (key_t)-1, "get_ftok failed"); 243 244 sender_msqid = msgget(msgkey, IPC_CREAT | 0640); 245 ATF_REQUIRE_MSG(sender_msqid != -1, "msgget: %d", errno); 246 write_int("sender_msqid", sender_msqid); 247 248 if (did_sigsys) { 249 atf_tc_skip("SYSV Message Queue not supported"); 250 return; 251 } 252 253 ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds) != -1, 254 "msgctl IPC_STAT 1: %d", errno); 255 256 print_msqid_ds(&m_ds, 0640); 257 258 m_ds.msg_perm.mode = (m_ds.msg_perm.mode & ~0777) | 0600; 259 260 ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_SET, &m_ds) != -1, 261 "msgctl IPC_SET: %d", errno); 262 263 memset(&m_ds, 0, sizeof(m_ds)); 264 265 ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds) != -1, 266 "msgctl IPC_STAT 2: %d", errno); 267 268 ATF_REQUIRE_MSG((m_ds.msg_perm.mode & 0777) == 0600, 269 "IPC_SET of mode didn't hold"); 270 271 print_msqid_ds(&m_ds, 0600); 272 273 switch ((child_pid = fork())) { 274 case -1: 275 atf_tc_fail("fork: %d", errno); 276 return; 277 278 case 0: 279 child_count++; 280 receiver(); 281 break; 282 283 default: 284 break; 285 } 286 287 for (loop = 0; loop < maxloop; loop++) { 288 /* 289 * Send the first message to the receiver and wait for the ACK. 290 */ 291 m.mtype = MTYPE_1; 292 strlcpy(m.mtext, m1_str, sizeof(m.mtext)); 293 ATF_REQUIRE_MSG(msgsnd(sender_msqid, &m, MESSAGE_TEXT_LEN, 294 0) != -1, "sender: msgsnd 1: %d", errno); 295 296 ATF_REQUIRE_MSG(msgrcv(sender_msqid, &m, MESSAGE_TEXT_LEN, 297 MTYPE_1_ACK, 0) == MESSAGE_TEXT_LEN, 298 "sender: msgrcv 1 ack: %d", errno); 299 300 print_msqid_ds(&m_ds, 0600); 301 302 /* 303 * Send the second message to the receiver and wait for the ACK. 304 */ 305 m.mtype = MTYPE_2; 306 strlcpy(m.mtext, m2_str, sizeof(m.mtext)); 307 ATF_REQUIRE_MSG(msgsnd(sender_msqid, &m, MESSAGE_TEXT_LEN, 0) != -1, 308 "sender: msgsnd 2: %d", errno); 309 310 ATF_REQUIRE_MSG(msgrcv(sender_msqid, &m, MESSAGE_TEXT_LEN, 311 MTYPE_2_ACK, 0) == MESSAGE_TEXT_LEN, 312 "sender: msgrcv 2 ack: %d", errno); 313 } 314 315 /* 316 * Wait for child to finish 317 */ 318 sigemptyset(&sigmask); 319 (void) sigsuspend(&sigmask); 320 321 /* 322 * ...and any other signal is an unexpected error. 323 */ 324 if (did_sigchild) { 325 c_status = child_status; 326 if (c_status < 0) 327 atf_tc_fail("waitpid: %d", -c_status); 328 else if (WIFEXITED(c_status) == 0) 329 atf_tc_fail("child abnormal exit: %d", c_status); 330 else if (WEXITSTATUS(c_status) != 0) 331 atf_tc_fail("c status: %d", WEXITSTATUS(c_status)); 332 else { 333 ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds) 334 != -1, "msgctl IPC_STAT: %d", errno); 335 336 print_msqid_ds(&m_ds, 0600); 337 atf_tc_pass(); 338 } 339 } else 340 atf_tc_fail("sender: received unexpected signal"); 341} 342 343ATF_TC_CLEANUP(msg, tc) 344{ 345 int sender_msqid; 346 347 /* 348 * Remove the message queue if it exists. 349 */ 350 sender_msqid = read_int("sender_msqid"); 351 if (sender_msqid != -1) 352 if (msgctl(sender_msqid, IPC_RMID, NULL) == -1) 353 err(1, "msgctl IPC_RMID"); 354} 355 356void 357print_msqid_ds(struct msqid_ds *mp, mode_t mode) 358{ 359 uid_t uid = geteuid(); 360 gid_t gid = getegid(); 361 362 printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n", 363 mp->msg_perm.uid, mp->msg_perm.gid, 364 mp->msg_perm.cuid, mp->msg_perm.cgid, 365 mp->msg_perm.mode & 0777); 366 367 printf("qnum %lu, qbytes %lu, lspid %d, lrpid %d\n", 368 mp->msg_qnum, (u_long)mp->msg_qbytes, mp->msg_lspid, 369 mp->msg_lrpid); 370 371 printf("stime: %s", ctime(&mp->msg_stime)); 372 printf("rtime: %s", ctime(&mp->msg_rtime)); 373 printf("ctime: %s", ctime(&mp->msg_ctime)); 374 375 /* 376 * Sanity check a few things. 377 */ 378 379 ATF_REQUIRE_MSG(mp->msg_perm.uid == uid && mp->msg_perm.cuid == uid, 380 "uid mismatch"); 381 382 ATF_REQUIRE_MSG(mp->msg_perm.gid == gid && mp->msg_perm.cgid == gid, 383 "gid mismatch"); 384 385 ATF_REQUIRE_MSG((mp->msg_perm.mode & 0777) == mode, "mode mismatch"); 386} 387 388void 389receiver(void) 390{ 391 struct testmsg m; 392 int msqid, loop; 393 394 if ((msqid = msgget(msgkey, 0)) == -1) 395 err(1, "receiver: msgget"); 396 397 for (loop = 0; loop < maxloop; loop++) { 398 /* 399 * Receive the first message, print it, and send an ACK. 400 */ 401 if (msgrcv(msqid, &m, MESSAGE_TEXT_LEN, MTYPE_1, 0) != MESSAGE_TEXT_LEN) 402 err(1, "receiver: msgrcv 1"); 403 404 printf("%s\n", m.mtext); 405 if (strcmp(m.mtext, m1_str) != 0) 406 err(1, "receiver: message 1 data isn't correct"); 407 408 m.mtype = MTYPE_1_ACK; 409 410 if (msgsnd(msqid, &m, MESSAGE_TEXT_LEN, 0) == -1) 411 err(1, "receiver: msgsnd ack 1"); 412 413 /* 414 * Receive the second message, print it, and send an ACK. 415 */ 416 417 if (msgrcv(msqid, &m, MESSAGE_TEXT_LEN, MTYPE_2, 0) != MESSAGE_TEXT_LEN) 418 err(1, "receiver: msgrcv 2"); 419 420 printf("%s\n", m.mtext); 421 if (strcmp(m.mtext, m2_str) != 0) 422 err(1, "receiver: message 2 data isn't correct"); 423 424 m.mtype = MTYPE_2_ACK; 425 426 if (msgsnd(msqid, &m, MESSAGE_TEXT_LEN, 0) == -1) 427 err(1, "receiver: msgsnd ack 2"); 428 } 429 430 exit(0); 431} 432 433/* 434 * Test the SVID-compatible Semaphore facility. 435 */ 436 437ATF_TC_WITH_CLEANUP(sem); 438ATF_TC_HEAD(sem, tc) 439{ 440 441 atf_tc_set_md_var(tc, "timeout", "3"); 442 atf_tc_set_md_var(tc, "descr", "Checks sysvmsg passing"); 443} 444 445ATF_TC_BODY(sem, tc) 446{ 447 struct sigaction sa; 448 union semun sun; 449 struct semid_ds s_ds; 450 sigset_t sigmask; 451 int sender_semid; 452 int i; 453 int c_status; 454 455 /* 456 * Install a SIGSYS handler so that we can exit gracefully if 457 * System V Semaphore support isn't in the kernel. 458 */ 459 did_sigsys = 0; 460 sa.sa_handler = sigsys_handler; 461 sigemptyset(&sa.sa_mask); 462 sa.sa_flags = 0; 463 ATF_REQUIRE_MSG(sigaction(SIGSYS, &sa, NULL) != -1, 464 "sigaction SIGSYS: %d", errno); 465 466 /* 467 * Install a SIGCHLD handler to deal with all possible exit 468 * conditions of the receiver. 469 */ 470 did_sigchild = 0; 471 child_count = 0; 472 sa.sa_handler = sigchld_handler; 473 sigemptyset(&sa.sa_mask); 474 sa.sa_flags = 0; 475 ATF_REQUIRE_MSG(sigaction(SIGCHLD, &sa, NULL) != -1, 476 "sigaction SIGCHLD: %d", errno); 477 478 semkey = get_ftok(4160); 479 ATF_REQUIRE_MSG(semkey != (key_t)-1, "get_ftok failed"); 480 481 sender_semid = semget(semkey, 1, IPC_CREAT | 0640); 482 ATF_REQUIRE_MSG(sender_semid != -1, "semget: %d", errno); 483 write_int("sender_semid", sender_semid); 484 485 if (did_sigsys) { 486 atf_tc_skip("SYSV Semaphore not supported"); 487 return; 488 } 489 490 sun.buf = &s_ds; 491 ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_STAT, sun) != -1, 492 "semctl IPC_STAT: %d", errno); 493 494 print_semid_ds(&s_ds, 0640); 495 496 s_ds.sem_perm.mode = (s_ds.sem_perm.mode & ~0777) | 0600; 497 498 sun.buf = &s_ds; 499 ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_SET, sun) != -1, 500 "semctl IPC_SET: %d", errno); 501 502 memset(&s_ds, 0, sizeof(s_ds)); 503 504 sun.buf = &s_ds; 505 ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_STAT, sun) != -1, 506 "semctl IPC_STAT: %d", errno); 507 508 ATF_REQUIRE_MSG((s_ds.sem_perm.mode & 0777) == 0600, 509 "IPC_SET of mode didn't hold"); 510 511 print_semid_ds(&s_ds, 0600); 512 513 for (child_count = 0; child_count < 5; child_count++) { 514 switch ((child_pid = fork())) { 515 case -1: 516 atf_tc_fail("fork: %d", errno); 517 return; 518 519 case 0: 520 waiter(); 521 break; 522 523 default: 524 break; 525 } 526 } 527 528 /* 529 * Wait for all of the waiters to be attempting to acquire the 530 * semaphore. 531 */ 532 for (;;) { 533 i = semctl(sender_semid, 0, GETNCNT); 534 if (i == -1) 535 atf_tc_fail("semctl GETNCNT: %d", i); 536 if (i == 5) 537 break; 538 } 539 540 /* 541 * Now set the thundering herd in motion by initializing the 542 * semaphore to the value 1. 543 */ 544 sun.val = 1; 545 ATF_REQUIRE_MSG(semctl(sender_semid, 0, SETVAL, sun) != -1, 546 "sender: semctl SETVAL to 1: %d", errno); 547 548 /* 549 * Wait for all children to finish 550 */ 551 sigemptyset(&sigmask); 552 for (;;) { 553 (void) sigsuspend(&sigmask); 554 if (did_sigchild) { 555 c_status = child_status; 556 if (c_status < 0) 557 atf_tc_fail("waitpid: %d", -c_status); 558 else if (WIFEXITED(c_status) == 0) 559 atf_tc_fail("c abnormal exit: %d", c_status); 560 else if (WEXITSTATUS(c_status) != 0) 561 atf_tc_fail("c status: %d", 562 WEXITSTATUS(c_status)); 563 else { 564 sun.buf = &s_ds; 565 ATF_REQUIRE_MSG(semctl(sender_semid, 0, 566 IPC_STAT, sun) != -1, 567 "semctl IPC_STAT: %d", errno); 568 569 print_semid_ds(&s_ds, 0600); 570 atf_tc_pass(); 571 } 572 if (child_count <= 0) 573 break; 574 did_sigchild = 0; 575 } else { 576 atf_tc_fail("sender: received unexpected signal"); 577 break; 578 } 579 } 580} 581 582ATF_TC_CLEANUP(sem, tc) 583{ 584 int sender_semid; 585 586 /* 587 * Remove the semaphore if it exists 588 */ 589 sender_semid = read_int("sender_semid"); 590 if (sender_semid != -1) 591 if (semctl(sender_semid, 0, IPC_RMID) == -1) 592 err(1, "semctl IPC_RMID"); 593} 594 595void 596print_semid_ds(struct semid_ds *sp, mode_t mode) 597{ 598 uid_t uid = geteuid(); 599 gid_t gid = getegid(); 600 601 printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n", 602 sp->sem_perm.uid, sp->sem_perm.gid, 603 sp->sem_perm.cuid, sp->sem_perm.cgid, 604 sp->sem_perm.mode & 0777); 605 606 printf("nsems %u\n", sp->sem_nsems); 607 608 printf("otime: %s", ctime(&sp->sem_otime)); 609 printf("ctime: %s", ctime(&sp->sem_ctime)); 610 611 /* 612 * Sanity check a few things. 613 */ 614 615 ATF_REQUIRE_MSG(sp->sem_perm.uid == uid && sp->sem_perm.cuid == uid, 616 "uid mismatch"); 617 618 ATF_REQUIRE_MSG(sp->sem_perm.gid == gid && sp->sem_perm.cgid == gid, 619 "gid mismatch"); 620 621 ATF_REQUIRE_MSG((sp->sem_perm.mode & 0777) == mode, 622 "mode mismatch %o != %o", (sp->sem_perm.mode & 0777), mode); 623} 624 625void 626waiter(void) 627{ 628 struct sembuf s; 629 int semid; 630 631 if ((semid = semget(semkey, 1, 0)) == -1) 632 err(1, "waiter: semget"); 633 634 /* 635 * Attempt to acquire the semaphore. 636 */ 637 s.sem_num = 0; 638 s.sem_op = -1; 639 s.sem_flg = SEM_UNDO; 640 641 if (semop(semid, &s, 1) == -1) 642 err(1, "waiter: semop -1"); 643 644 printf("WOO! GOT THE SEMAPHORE!\n"); 645 sleep(1); 646 647 /* 648 * Release the semaphore and exit. 649 */ 650 s.sem_num = 0; 651 s.sem_op = 1; 652 s.sem_flg = SEM_UNDO; 653 654 if (semop(semid, &s, 1) == -1) 655 err(1, "waiter: semop +1"); 656 657 exit(0); 658} 659 660/* 661 * Test the SVID-compatible Shared Memory facility. 662 */ 663 664ATF_TC_WITH_CLEANUP(shm); 665ATF_TC_HEAD(shm, tc) 666{ 667 668 atf_tc_set_md_var(tc, "timeout", "3"); 669 atf_tc_set_md_var(tc, "descr", "Checks sysv shared memory"); 670} 671 672ATF_TC_BODY(shm, tc) 673{ 674 struct sigaction sa; 675 struct shmid_ds s_ds; 676 sigset_t sigmask; 677 char *shm_buf; 678 int sender_shmid; 679 int c_status; 680 681 /* 682 * Install a SIGSYS handler so that we can exit gracefully if 683 * System V Shared Memory support isn't in the kernel. 684 */ 685 did_sigsys = 0; 686 sa.sa_handler = sigsys_handler; 687 sigemptyset(&sa.sa_mask); 688 sa.sa_flags = 0; 689 ATF_REQUIRE_MSG(sigaction(SIGSYS, &sa, NULL) != -1, 690 "sigaction SIGSYS: %d", errno); 691 692 /* 693 * Install a SIGCHLD handler to deal with all possible exit 694 * conditions of the sharer. 695 */ 696 did_sigchild = 0; 697 child_count = 0; 698 sa.sa_handler = sigchld_handler; 699 sigemptyset(&sa.sa_mask); 700 sa.sa_flags = 0; 701 ATF_REQUIRE_MSG(sigaction(SIGCHLD, &sa, NULL) != -1, 702 "sigaction SIGCHLD: %d", errno); 703 704 pgsize = sysconf(_SC_PAGESIZE); 705 706 shmkey = get_ftok(4160); 707 ATF_REQUIRE_MSG(shmkey != (key_t)-1, "get_ftok failed"); 708 709 ATF_REQUIRE_MSG((sender_shmid = shmget(shmkey, pgsize, 710 IPC_CREAT | 0640)) != -1, 711 "shmget: %d", errno); 712 write_int("sender_shmid", sender_shmid); 713 714 ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_STAT, &s_ds) != -1, 715 "shmctl IPC_STAT: %d", errno); 716 717 print_shmid_ds(&s_ds, 0640); 718 719 s_ds.shm_perm.mode = (s_ds.shm_perm.mode & ~0777) | 0600; 720 721 ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_SET, &s_ds) != -1, 722 "shmctl IPC_SET: %d", errno); 723 724 memset(&s_ds, 0, sizeof(s_ds)); 725 726 ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_STAT, &s_ds) != -1, 727 "shmctl IPC_STAT: %d", errno); 728 729 ATF_REQUIRE_MSG((s_ds.shm_perm.mode & 0777) == 0600, 730 "IPC_SET of mode didn't hold"); 731 732 print_shmid_ds(&s_ds, 0600); 733 734 shm_buf = shmat(sender_shmid, NULL, 0); 735 ATF_REQUIRE_MSG(shm_buf != (void *) -1, "sender: shmat: %d", errno); 736 737 /* 738 * Write the test pattern into the shared memory buffer. 739 */ 740 strcpy(shm_buf, m2_str); 741 742 switch ((child_pid = fork())) { 743 case -1: 744 atf_tc_fail("fork: %d", errno); 745 return; 746 747 case 0: 748 sharer(); 749 break; 750 751 default: 752 break; 753 } 754 755 /* 756 * Wait for child to finish 757 */ 758 sigemptyset(&sigmask); 759 (void) sigsuspend(&sigmask); 760 761 if (did_sigchild) { 762 c_status = child_status; 763 if (c_status < 0) 764 atf_tc_fail("waitpid: %d", -c_status); 765 else if (WIFEXITED(c_status) == 0) 766 atf_tc_fail("c abnormal exit: %d", c_status); 767 else if (WEXITSTATUS(c_status) != 0) 768 atf_tc_fail("c status: %d", WEXITSTATUS(c_status)); 769 else { 770 ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_STAT, 771 &s_ds) != -1, 772 "shmctl IPC_STAT: %d", errno); 773 774 print_shmid_ds(&s_ds, 0600); 775 atf_tc_pass(); 776 } 777 } else 778 atf_tc_fail("sender: received unexpected signal"); 779} 780 781static void 782shmid_cleanup(const char *name) 783{ 784 int shmid; 785 786 /* 787 * Remove the shared memory area if it exists. 788 */ 789 shmid = read_int(name); 790 if (shmid != -1) { 791 if (shmctl(shmid, IPC_RMID, NULL) == -1) 792 err(1, "shmctl IPC_RMID"); 793 } 794} 795 796ATF_TC_CLEANUP(shm, tc) 797{ 798 799 shmid_cleanup("sender_shmid"); 800} 801 802void 803print_shmid_ds(struct shmid_ds *sp, mode_t mode) 804{ 805 uid_t uid = geteuid(); 806 gid_t gid = getegid(); 807 808 printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n", 809 sp->shm_perm.uid, sp->shm_perm.gid, 810 sp->shm_perm.cuid, sp->shm_perm.cgid, 811 sp->shm_perm.mode & 0777); 812 813 printf("segsz %lu, lpid %d, cpid %d, nattch %u\n", 814 (u_long)sp->shm_segsz, sp->shm_lpid, sp->shm_cpid, 815 sp->shm_nattch); 816 817 printf("atime: %s", ctime(&sp->shm_atime)); 818 printf("dtime: %s", ctime(&sp->shm_dtime)); 819 printf("ctime: %s", ctime(&sp->shm_ctime)); 820 821 /* 822 * Sanity check a few things. 823 */ 824 825 ATF_REQUIRE_MSG(sp->shm_perm.uid == uid && sp->shm_perm.cuid == uid, 826 "uid mismatch"); 827 828 ATF_REQUIRE_MSG(sp->shm_perm.gid == gid && sp->shm_perm.cgid == gid, 829 "gid mismatch"); 830 831 ATF_REQUIRE_MSG((sp->shm_perm.mode & 0777) == mode, "mode mismatch"); 832} 833 834void 835sharer(void) 836{ 837 int shmid; 838 void *shm_buf; 839 840 shmid = shmget(shmkey, pgsize, 0); 841 ATF_REQUIRE_MSG(shmid != -1, "receiver: shmget:%d", errno); 842 843 shm_buf = shmat(shmid, NULL, 0); 844 ATF_REQUIRE_MSG(shm_buf != (void *) -1, "receiver: shmat: %d", errno); 845 846 printf("%s\n", (const char *)shm_buf); 847 848 ATF_REQUIRE_MSG(strcmp((const char *)shm_buf, m2_str) == 0, 849 "receiver: data isn't correct"); 850 851 exit(0); 852} 853 854#ifdef SHM_REMAP 855ATF_TC_WITH_CLEANUP(shm_remap); 856ATF_TC_HEAD(shm_remap, tc) 857{ 858 859 atf_tc_set_md_var(tc, "descr", "Checks SHM_REMAP"); 860} 861 862ATF_TC_BODY(shm_remap, tc) 863{ 864 char *shm_buf; 865 int shmid_remap; 866 867 pgsize = sysconf(_SC_PAGESIZE); 868 869 shmkey = get_ftok(4160); 870 ATF_REQUIRE_MSG(shmkey != (key_t)-1, "get_ftok failed"); 871 872 ATF_REQUIRE_MSG((shmid_remap = shmget(shmkey, pgsize, 873 IPC_CREAT | 0640)) != -1, "shmget: %d", errno); 874 write_int("shmid_remap", shmid_remap); 875 876 ATF_REQUIRE_MSG((shm_buf = mmap(NULL, pgsize, PROT_READ | PROT_WRITE, 877 MAP_ANON | MAP_PRIVATE, -1, 0)) != MAP_FAILED, "mmap: %d", errno); 878 879 ATF_REQUIRE_MSG(shmat(shmid_remap, shm_buf, 0) == (void *)-1, 880 "shmat without MAP_REMAP succeeded"); 881 ATF_REQUIRE_MSG(shmat(shmid_remap, shm_buf, SHM_REMAP) == shm_buf, 882 "shmat(SHM_REMAP): %d", errno); 883} 884 885ATF_TC_CLEANUP(shm_remap, tc) 886{ 887 888 shmid_cleanup("shmid_remap"); 889} 890#endif /* SHM_REMAP */ 891 892ATF_TP_ADD_TCS(tp) 893{ 894 895 ATF_TP_ADD_TC(tp, msg); 896 ATF_TP_ADD_TC(tp, sem); 897 ATF_TP_ADD_TC(tp, shm); 898#ifdef SHM_REMAP 899 ATF_TP_ADD_TC(tp, shm_remap); 900#endif 901 902 return atf_no_error(); 903} 904 905