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