1/* $NetBSD: t_sysv.c,v 1.6 2022/05/14 14:02:03 christos 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/msg.h> 51#include <sys/param.h> 52#include <sys/sem.h> 53#include <sys/shm.h> 54#include <sys/wait.h> 55 56volatile int did_sigsys; 57 58void sigsys_handler(int); 59 60key_t get_ftok(int); 61 62void print_msqid_ds(struct msqid_ds *, mode_t); 63void receiver(void); 64 65void print_semid_ds(struct semid_ds *, mode_t); 66void waiter(void); 67 68void print_shmid_ds(struct shmid_ds *, mode_t); 69void sharer(void); 70 71#define MESSAGE_TEXT_LEN 256 72 73struct testmsg { 74 long mtype; 75 char mtext[MESSAGE_TEXT_LEN]; 76}; 77 78const char *m1_str = "California is overrated."; 79const char *m2_str = "The quick brown fox jumped over the lazy dog."; 80 81size_t pgsize; 82 83#define MTYPE_1 1 84#define MTYPE_1_ACK 2 85 86#define MTYPE_2 3 87#define MTYPE_2_ACK 4 88 89pid_t child_pid; 90 91key_t msgkey, semkey, shmkey; 92 93int maxloop = 1; 94 95union semun { 96 int val; /* value for SETVAL */ 97 struct semid_ds *buf; /* buffer for IPC_{STAT,SET} */ 98 u_short *array; /* array for GETALL & SETALL */ 99}; 100 101 102/* Writes an integer to a file. To be used from the body of the test 103 * cases below to pass any global identifiers to the cleanup routine. */ 104static void 105write_int(const char *path, const int value) 106{ 107 int output; 108 109 output = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0600); 110 ATF_REQUIRE_MSG(output != -1, "Failed to create %s", path); 111 write(output, &value, sizeof(value)); 112 close(output); 113} 114 115 116/* Reads an integer from a file. To be used from the cleanup routines 117 * of the test cases below. */ 118static int 119read_int(const char *path) 120{ 121 int input, value; 122 123 input = open(path, O_RDONLY); 124 if (input == -1) 125 return -1; 126 127 read(input, &value, sizeof(value)); 128 return value; 129} 130 131 132void 133sigsys_handler(int signo) 134{ 135 136 did_sigsys = 1; 137} 138 139key_t get_ftok(int id) 140{ 141 int fd; 142 char token_key[64], token_dir[64]; 143 char *tmpdir; 144 key_t key; 145 146 strlcpy(token_key, "/tmp/t_sysv.XXXXXX", sizeof(token_key)); 147 tmpdir = mkdtemp(token_key); 148 ATF_REQUIRE_MSG(tmpdir != NULL, "mkdtemp() failed: %d", errno); 149 150 strlcpy(token_dir, tmpdir, sizeof(token_dir)); 151 strlcpy(token_key, tmpdir, sizeof(token_key)); 152 strlcat(token_key, "/token_key", sizeof(token_key)); 153 154 /* Create the file, since ftok() requires it to exist! */ 155 156 fd = open(token_key, O_RDWR | O_CREAT | O_EXCL, 0600); 157 if (fd == -1) { 158 rmdir(tmpdir); 159 atf_tc_fail("open() of temp file failed: %d", errno); 160 return (key_t)-1; 161 } 162 163 close(fd); 164 165 key = ftok(token_key, id); 166 ATF_REQUIRE_MSG(key != (key_t)-1, "ftok() failed"); 167 168 ATF_REQUIRE_MSG(unlink(token_key) != -1, "unlink() failed: %d", errno); 169 ATF_REQUIRE_MSG(rmdir(token_dir) != -1, "rmdir() failed: %d", errno); 170 171 return key; 172} 173 174ATF_TC_WITH_CLEANUP(msg); 175ATF_TC_HEAD(msg, tc) 176{ 177 178 atf_tc_set_md_var(tc, "timeout", "3"); 179 atf_tc_set_md_var(tc, "descr", "Checks sysvmsg passing"); 180} 181 182ATF_TC_BODY(msg, tc) 183{ 184 struct sigaction sa; 185 struct msqid_ds m_ds; 186 struct testmsg m; 187 int sender_msqid; 188 int loop; 189 int c_status; 190 pid_t wait_result; 191 192 /* 193 * Install a SIGSYS handler so that we can exit gracefully if 194 * System V Message Queue support isn't in the kernel. 195 */ 196 did_sigsys = 0; 197 sa.sa_handler = sigsys_handler; 198 sigemptyset(&sa.sa_mask); 199 sa.sa_flags = 0; 200 ATF_REQUIRE_MSG(sigaction(SIGSYS, &sa, NULL) != -1, 201 "sigaction SIGSYS: %d", errno); 202 203 msgkey = get_ftok(4160); 204 ATF_REQUIRE_MSG(msgkey != (key_t)-1, "get_ftok failed"); 205 206 sender_msqid = msgget(msgkey, IPC_CREAT | 0640); 207 ATF_REQUIRE_MSG(sender_msqid != -1, "msgget: %d", errno); 208 write_int("sender_msqid", sender_msqid); 209 210 if (did_sigsys) { 211 atf_tc_skip("SYSV Message Queue not supported"); 212 return; 213 } 214 215 ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds) != -1, 216 "msgctl IPC_STAT 1: %d", errno); 217 218 print_msqid_ds(&m_ds, 0640); 219 220 m_ds.msg_perm.mode = (m_ds.msg_perm.mode & ~0777) | 0600; 221 222 ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_SET, &m_ds) != -1, 223 "msgctl IPC_SET: %d", errno); 224 225 memset(&m_ds, 0, sizeof(m_ds)); 226 227 ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds) != -1, 228 "msgctl IPC_STAT 2: %d", errno); 229 230 ATF_REQUIRE_MSG((m_ds.msg_perm.mode & 0777) == 0600, 231 "IPC_SET of mode didn't hold"); 232 233 print_msqid_ds(&m_ds, 0600); 234 235 fflush(stdout); 236 237 switch ((child_pid = fork())) { 238 case -1: 239 atf_tc_fail("fork: %d", errno); 240 return; 241 242 case 0: 243 receiver(); 244 break; 245 246 default: 247 break; 248 } 249 250 for (loop = 0; loop < maxloop; loop++) { 251 /* 252 * Send the first message to the receiver and wait for the ACK. 253 */ 254 m.mtype = MTYPE_1; 255 strcpy(m.mtext, m1_str); 256 ATF_REQUIRE_MSG(msgsnd(sender_msqid, &m, MESSAGE_TEXT_LEN, 257 0) != -1, "sender: msgsnd 1: %d", errno); 258 259 ATF_REQUIRE_MSG(msgrcv(sender_msqid, &m, MESSAGE_TEXT_LEN, 260 MTYPE_1_ACK, 0) == MESSAGE_TEXT_LEN, 261 "sender: msgrcv 1 ack: %d", errno); 262 263 print_msqid_ds(&m_ds, 0600); 264 265 /* 266 * Send the second message to the receiver and wait for the ACK. 267 */ 268 m.mtype = MTYPE_2; 269 strcpy(m.mtext, m2_str); 270 ATF_REQUIRE_MSG(msgsnd(sender_msqid, &m, MESSAGE_TEXT_LEN, 0) 271 != -1, "sender: msgsnd 2: %d", errno); 272 273 ATF_REQUIRE_MSG(msgrcv(sender_msqid, &m, MESSAGE_TEXT_LEN, 274 MTYPE_2_ACK, 0) == MESSAGE_TEXT_LEN, 275 "sender: msgrcv 2 ack: %d", errno); 276 } 277 278 /* 279 * Wait for child to finish 280 */ 281 wait_result = wait(&c_status); 282 ATF_REQUIRE_EQ_MSG(wait_result, child_pid, "wait returned %d (%s)", 283 wait_result, wait_result == -1 ? strerror(errno) : ""); 284 ATF_REQUIRE_MSG(WIFEXITED(c_status), "child abnormal exit: %d (sig %d)", 285 c_status, WTERMSIG(c_status)); 286 ATF_REQUIRE_EQ_MSG(WEXITSTATUS(c_status), 0, "child status: %d", 287 WEXITSTATUS(c_status)); 288 289 ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds) != -1, 290 "msgctl IPC_STAT: %d", errno); 291 292 print_msqid_ds(&m_ds, 0600); 293} 294 295ATF_TC_CLEANUP(msg, tc) 296{ 297 int sender_msqid; 298 299 /* 300 * Remove the message queue if it exists. 301 */ 302 sender_msqid = read_int("sender_msqid"); 303 if (sender_msqid == -1) 304 return; 305 if (msgctl(sender_msqid, IPC_RMID, NULL) == -1) 306 err(EXIT_FAILURE, "msgctl IPC_RMID"); 307} 308 309void 310print_msqid_ds(struct msqid_ds *mp, mode_t mode) 311{ 312 uid_t uid = geteuid(); 313 gid_t gid = getegid(); 314 315 printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n", 316 mp->msg_perm.uid, mp->msg_perm.gid, 317 mp->msg_perm.cuid, mp->msg_perm.cgid, 318 mp->msg_perm.mode & 0777); 319 320 printf("qnum %lu, qbytes %ju, lspid %d, lrpid %d\n", 321 mp->msg_qnum, (uintmax_t)mp->msg_qbytes, mp->msg_lspid, 322 mp->msg_lrpid); 323 324 printf("stime: %s", ctime(&mp->msg_stime)); 325 printf("rtime: %s", ctime(&mp->msg_rtime)); 326 printf("ctime: %s", ctime(&mp->msg_ctime)); 327 328 /* 329 * Sanity check a few things. 330 */ 331 332 ATF_REQUIRE_MSG(mp->msg_perm.uid == uid && mp->msg_perm.cuid == uid, 333 "uid mismatch"); 334 335 ATF_REQUIRE_MSG(mp->msg_perm.gid == gid && mp->msg_perm.cgid == gid, 336 "gid mismatch"); 337 338 ATF_REQUIRE_MSG((mp->msg_perm.mode & 0777) == mode, "mode mismatch"); 339} 340 341void 342receiver(void) 343{ 344 struct testmsg m; 345 int msqid, loop; 346 347 if ((msqid = msgget(msgkey, 0)) == -1) 348 err(EXIT_FAILURE, "receiver: msgget"); 349 350 for (loop = 0; loop < maxloop; loop++) { 351 /* 352 * Receive the first message, print it, and send an ACK. 353 */ 354 if (msgrcv(msqid, &m, MESSAGE_TEXT_LEN, MTYPE_1, 0) 355 != MESSAGE_TEXT_LEN) 356 err(EXIT_FAILURE, "receiver: msgrcv 1"); 357 358 printf("%s\n", m.mtext); 359 if (strcmp(m.mtext, m1_str) != 0) 360 errx(EXIT_FAILURE, 361 "receiver: message 1 data isn't correct"); 362 363 m.mtype = MTYPE_1_ACK; 364 365 if (msgsnd(msqid, &m, MESSAGE_TEXT_LEN, 0) == -1) 366 err(EXIT_FAILURE, "receiver: msgsnd ack 1"); 367 368 /* 369 * Receive the second message, print it, and send an ACK. 370 */ 371 372 if (msgrcv(msqid, &m, MESSAGE_TEXT_LEN, MTYPE_2, 0) 373 != MESSAGE_TEXT_LEN) 374 err(EXIT_FAILURE, "receiver: msgrcv 2"); 375 376 printf("%s\n", m.mtext); 377 if (strcmp(m.mtext, m2_str) != 0) 378 errx(EXIT_FAILURE, 379 "receiver: message 2 data isn't correct"); 380 381 m.mtype = MTYPE_2_ACK; 382 383 if (msgsnd(msqid, &m, MESSAGE_TEXT_LEN, 0) == -1) 384 err(EXIT_FAILURE, "receiver: msgsnd ack 2"); 385 } 386 387 exit(EXIT_SUCCESS); 388} 389 390/* 391 * Test the SVID-compatible Semaphore facility. 392 */ 393 394ATF_TC_WITH_CLEANUP(sem); 395ATF_TC_HEAD(sem, tc) 396{ 397 398 atf_tc_set_md_var(tc, "timeout", "3"); 399 atf_tc_set_md_var(tc, "descr", "Checks sysvmsg passing"); 400} 401 402ATF_TC_BODY(sem, tc) 403{ 404 struct sigaction sa; 405 union semun sun; 406 struct semid_ds s_ds; 407 int sender_semid; 408 int i; 409 int c_status; 410 int child_count; 411 pid_t wait_result; 412 413 /* 414 * Install a SIGSYS handler so that we can exit gracefully if 415 * System V Semaphore support isn't in the kernel. 416 */ 417 did_sigsys = 0; 418 sa.sa_handler = sigsys_handler; 419 sigemptyset(&sa.sa_mask); 420 sa.sa_flags = 0; 421 ATF_REQUIRE_MSG(sigaction(SIGSYS, &sa, NULL) != -1, 422 "sigaction SIGSYS: %d", errno); 423 424 semkey = get_ftok(4160); 425 ATF_REQUIRE_MSG(semkey != (key_t)-1, "get_ftok failed"); 426 427 sender_semid = semget(semkey, 1, IPC_CREAT | 0640); 428 ATF_REQUIRE_MSG(sender_semid != -1, "semget: %d", errno); 429 write_int("sender_semid", sender_semid); 430 431 if (did_sigsys) { 432 atf_tc_skip("SYSV Semaphore not supported"); 433 return; 434 } 435 436 sun.buf = &s_ds; 437 ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_STAT, sun) != -1, 438 "semctl IPC_STAT: %d", errno); 439 440 print_semid_ds(&s_ds, 0640); 441 442 s_ds.sem_perm.mode = (s_ds.sem_perm.mode & ~0777) | 0600; 443 444 sun.buf = &s_ds; 445 ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_SET, sun) != -1, 446 "semctl IPC_SET: %d", errno); 447 448 memset(&s_ds, 0, sizeof(s_ds)); 449 450 sun.buf = &s_ds; 451 ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_STAT, sun) != -1, 452 "semctl IPC_STAT: %d", errno); 453 454 ATF_REQUIRE_MSG((s_ds.sem_perm.mode & 0777) == 0600, 455 "IPC_SET of mode didn't hold"); 456 457 print_semid_ds(&s_ds, 0600); 458 459 fflush(stdout); 460 461 for (child_count = 0; child_count < 5; child_count++) { 462 switch ((child_pid = fork())) { 463 case -1: 464 atf_tc_fail("fork: %d", errno); 465 return; 466 467 case 0: 468 waiter(); 469 break; 470 471 default: 472 break; 473 } 474 } 475 476 /* 477 * Wait for all of the waiters to be attempting to acquire the 478 * semaphore. 479 */ 480 for (;;) { 481 i = semctl(sender_semid, 0, GETNCNT); 482 if (i == -1) 483 atf_tc_fail("semctl GETNCNT: %d", i); 484 if (i == 5) 485 break; 486 } 487 488 /* 489 * Now set the thundering herd in motion by initializing the 490 * semaphore to the value 1. 491 */ 492 sun.val = 1; 493 ATF_REQUIRE_MSG(semctl(sender_semid, 0, SETVAL, sun) != -1, 494 "sender: semctl SETVAL to 1: %d", errno); 495 496 /* 497 * Wait for all children to finish 498 */ 499 while (child_count-- > 0) { 500 wait_result = wait(&c_status); 501 ATF_REQUIRE_MSG(wait_result != -1, "wait failed: %s", 502 strerror(errno)); 503 ATF_REQUIRE_MSG(WIFEXITED(c_status), 504 "child abnormal exit: %d (sig %d)", 505 c_status, WTERMSIG(c_status)); 506 ATF_REQUIRE_EQ_MSG(WEXITSTATUS(c_status), 0, "child status: %d", 507 WEXITSTATUS(c_status)); 508 509 sun.buf = &s_ds; 510 ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_STAT, sun) != -1, 511 "semctl IPC_STAT: %d", errno); 512 513 print_semid_ds(&s_ds, 0600); 514 } 515} 516 517ATF_TC_CLEANUP(sem, tc) 518{ 519 int sender_semid; 520 521 /* 522 * Remove the semaphore if it exists 523 */ 524 sender_semid = read_int("sender_semid"); 525 if (sender_semid == -1) 526 return; 527 if (semctl(sender_semid, 0, IPC_RMID) == -1) 528 err(EXIT_FAILURE, "semctl IPC_RMID"); 529} 530 531void 532print_semid_ds(struct semid_ds *sp, mode_t mode) 533{ 534 uid_t uid = geteuid(); 535 gid_t gid = getegid(); 536 537 printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n", 538 sp->sem_perm.uid, sp->sem_perm.gid, 539 sp->sem_perm.cuid, sp->sem_perm.cgid, 540 sp->sem_perm.mode & 0777); 541 542 printf("nsems %u\n", sp->sem_nsems); 543 544 printf("otime: %s", ctime(&sp->sem_otime)); 545 printf("ctime: %s", ctime(&sp->sem_ctime)); 546 547 /* 548 * Sanity check a few things. 549 */ 550 551 ATF_REQUIRE_MSG(sp->sem_perm.uid == uid && sp->sem_perm.cuid == uid, 552 "uid mismatch"); 553 554 ATF_REQUIRE_MSG(sp->sem_perm.gid == gid && sp->sem_perm.cgid == gid, 555 "gid mismatch"); 556 557 ATF_REQUIRE_MSG((sp->sem_perm.mode & 0777) == mode, 558 "mode mismatch %o != %o", (sp->sem_perm.mode & 0777), mode); 559} 560 561void 562waiter(void) 563{ 564 struct sembuf s; 565 int semid; 566 567 if ((semid = semget(semkey, 1, 0)) == -1) 568 err(EXIT_FAILURE, "waiter: semget"); 569 570 /* 571 * Attempt to acquire the semaphore. 572 */ 573 s.sem_num = 0; 574 s.sem_op = -1; 575 s.sem_flg = SEM_UNDO; 576 577 if (semop(semid, &s, 1) == -1) 578 err(EXIT_FAILURE, "waiter: semop -1"); 579 580 printf("WOO! GOT THE SEMAPHORE!\n"); 581 usleep(10000); 582 583 /* 584 * Release the semaphore and exit. 585 */ 586 s.sem_num = 0; 587 s.sem_op = 1; 588 s.sem_flg = SEM_UNDO; 589 590 if (semop(semid, &s, 1) == -1) 591 err(EXIT_FAILURE, "waiter: semop +1"); 592 593 exit(EXIT_SUCCESS); 594} 595 596/* 597 * Test the SVID-compatible Shared Memory facility. 598 */ 599 600ATF_TC_WITH_CLEANUP(shm); 601ATF_TC_HEAD(shm, tc) 602{ 603 604 atf_tc_set_md_var(tc, "timeout", "3"); 605 atf_tc_set_md_var(tc, "descr", "Checks sysv shared memory"); 606} 607 608ATF_TC_BODY(shm, tc) 609{ 610 struct sigaction sa; 611 struct shmid_ds s_ds; 612 char *shm_buf; 613 int sender_shmid; 614 int c_status; 615 pid_t wait_result; 616 617 /* 618 * Install a SIGSYS handler so that we can exit gracefully if 619 * System V Shared Memory support isn't in the kernel. 620 */ 621 did_sigsys = 0; 622 sa.sa_handler = sigsys_handler; 623 sigemptyset(&sa.sa_mask); 624 sa.sa_flags = 0; 625 ATF_REQUIRE_MSG(sigaction(SIGSYS, &sa, NULL) != -1, 626 "sigaction SIGSYS: %d", errno); 627 628 pgsize = sysconf(_SC_PAGESIZE); 629 630 shmkey = get_ftok(4160); 631 ATF_REQUIRE_MSG(shmkey != (key_t)-1, "get_ftok failed"); 632 633 ATF_REQUIRE_MSG((sender_shmid = shmget(shmkey, pgsize, 634 IPC_CREAT | 0640)) != -1, 635 "shmget: %d", errno); 636 write_int("sender_shmid", sender_shmid); 637 638 ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_STAT, &s_ds) != -1, 639 "shmctl IPC_STAT: %d", errno); 640 641 print_shmid_ds(&s_ds, 0640); 642 643 s_ds.shm_perm.mode = (s_ds.shm_perm.mode & ~0777) | 0600; 644 645 ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_SET, &s_ds) != -1, 646 "shmctl IPC_SET: %d", errno); 647 648 memset(&s_ds, 0, sizeof(s_ds)); 649 650 ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_STAT, &s_ds) != -1, 651 "shmctl IPC_STAT: %d", errno); 652 653 ATF_REQUIRE_MSG((s_ds.shm_perm.mode & 0777) == 0600, 654 "IPC_SET of mode didn't hold"); 655 656 print_shmid_ds(&s_ds, 0600); 657 658 shm_buf = shmat(sender_shmid, NULL, 0); 659 ATF_REQUIRE_MSG(shm_buf != (void *) -1, "sender: shmat: %d", errno); 660 661 /* 662 * Write the test pattern into the shared memory buffer. 663 */ 664 strcpy(shm_buf, m2_str); 665 666 fflush(stdout); 667 668 switch ((child_pid = fork())) { 669 case -1: 670 atf_tc_fail("fork: %d", errno); 671 return; 672 673 case 0: 674 sharer(); 675 break; 676 677 default: 678 break; 679 } 680 681 /* 682 * Wait for child to finish 683 */ 684 wait_result = wait(&c_status); 685 ATF_REQUIRE_EQ_MSG(wait_result, child_pid, "wait returned %d (%s)", 686 wait_result, wait_result == -1 ? strerror(errno) : ""); 687 ATF_REQUIRE_MSG(WIFEXITED(c_status), "child abnormal exit: %d (sig %d)", 688 c_status, WTERMSIG(c_status)); 689 ATF_REQUIRE_EQ_MSG(WEXITSTATUS(c_status), 0, "child status: %d", 690 WEXITSTATUS(c_status)); 691 692 ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_STAT, &s_ds) != -1, 693 "shmctl IPC_STAT: %d", errno); 694 695 print_shmid_ds(&s_ds, 0600); 696} 697 698ATF_TC_CLEANUP(shm, tc) 699{ 700 int sender_shmid; 701 702 /* 703 * Remove the shared memory area if it exists. 704 */ 705 sender_shmid = read_int("sender_shmid"); 706 if (sender_shmid == -1) 707 return; 708 if (shmctl(sender_shmid, IPC_RMID, NULL) == -1) 709 err(EXIT_FAILURE, "shmctl IPC_RMID"); 710} 711 712void 713print_shmid_ds(struct shmid_ds *sp, mode_t mode) 714{ 715 uid_t uid = geteuid(); 716 gid_t gid = getegid(); 717 718 printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n", 719 sp->shm_perm.uid, sp->shm_perm.gid, 720 sp->shm_perm.cuid, sp->shm_perm.cgid, 721 sp->shm_perm.mode & 0777); 722 723 printf("segsz %ju, lpid %d, cpid %d, nattch %u\n", 724 (uintmax_t)sp->shm_segsz, sp->shm_lpid, sp->shm_cpid, 725 sp->shm_nattch); 726 727 printf("atime: %s", ctime(&sp->shm_atime)); 728 printf("dtime: %s", ctime(&sp->shm_dtime)); 729 printf("ctime: %s", ctime(&sp->shm_ctime)); 730 731 /* 732 * Sanity check a few things. 733 */ 734 735 ATF_REQUIRE_MSG(sp->shm_perm.uid == uid && sp->shm_perm.cuid == uid, 736 "uid mismatch"); 737 738 ATF_REQUIRE_MSG(sp->shm_perm.gid == gid && sp->shm_perm.cgid == gid, 739 "gid mismatch"); 740 741 ATF_REQUIRE_MSG((sp->shm_perm.mode & 0777) == mode, 742 "mode mismatch %o != %o", sp->shm_perm.mode & 0777, mode); 743} 744 745void 746sharer(void) 747{ 748 int shmid; 749 void *shm_buf; 750 751 shmid = shmget(shmkey, pgsize, 0); 752 if (shmid == -1) 753 err(EXIT_FAILURE, "receiver: shmget"); 754 755 shm_buf = shmat(shmid, NULL, 0); 756 if (shm_buf == (void *) -1) 757 err(EXIT_FAILURE, "receiver: shmat"); 758 759 printf("%s\n", (const char *)shm_buf); 760 761 if (strcmp((const char *)shm_buf, m2_str) != 0) 762 errx(EXIT_FAILURE, "receiver: data isn't correct"); 763 764 exit(EXIT_SUCCESS); 765} 766 767ATF_TP_ADD_TCS(tp) 768{ 769 770 ATF_TP_ADD_TC(tp, msg); 771 ATF_TP_ADD_TC(tp, sem); 772 ATF_TP_ADD_TC(tp, shm); 773 774 return atf_no_error(); 775} 776