1 /*- 2 * Copyright (c) 2006 Robert N. M. Watson 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <sys/param.h> 31 #include <sys/mman.h> 32 #include <sys/resource.h> 33 #include <sys/stat.h> 34 #include <sys/syscall.h> 35 #include <sys/wait.h> 36 37 #include <errno.h> 38 #include <fcntl.h> 39 #include <signal.h> 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <unistd.h> 44 45 #include <atf-c.h> 46 47 #define TEST_PATH_LEN 256 48 static char test_path[TEST_PATH_LEN]; 49 50 static void 51 gen_test_path(void) 52 { 53 char *tmpdir = getenv("TMPDIR"); 54 55 if (tmpdir == NULL) 56 tmpdir = "/tmp"; 57 58 snprintf(test_path, sizeof(test_path), "%s/tmp.XXXXXX", tmpdir); 59 test_path[sizeof(test_path) - 1] = '\0'; 60 ATF_REQUIRE_MSG(mkstemp(test_path) != -1, 61 "mkstemp failed; errno=%d", errno); 62 ATF_REQUIRE_MSG(unlink(test_path) == 0, 63 "unlink failed; errno=%d", errno); 64 } 65 66 /* 67 * Attempt a shm_open() that should fail with an expected error of 'error'. 68 */ 69 static void 70 shm_open_should_fail(const char *path, int flags, mode_t mode, int error) 71 { 72 int fd; 73 74 fd = shm_open(path, flags, mode); 75 ATF_CHECK_MSG(fd == -1, "shm_open didn't fail"); 76 ATF_CHECK_MSG(error == errno, 77 "shm_open didn't fail with expected errno; errno=%d; expected " 78 "errno=%d", errno, error); 79 } 80 81 /* 82 * Attempt a shm_unlink() that should fail with an expected error of 'error'. 83 */ 84 static void 85 shm_unlink_should_fail(const char *path, int error) 86 { 87 88 ATF_CHECK_MSG(shm_unlink(path) == -1, "shm_unlink didn't fail"); 89 ATF_CHECK_MSG(error == errno, 90 "shm_unlink didn't fail with expected errno; errno=%d; expected " 91 "errno=%d", errno, error); 92 } 93 94 /* 95 * Open the test object and write '1' to the first byte. Returns valid fd 96 * on success and -1 on failure. 97 */ 98 static int 99 scribble_object(void) 100 { 101 char *page; 102 int fd; 103 104 gen_test_path(); 105 106 fd = shm_open(test_path, O_CREAT|O_EXCL|O_RDWR, 0777); 107 if (fd < 0 && errno == EEXIST) { 108 if (shm_unlink(test_path) < 0) 109 atf_tc_fail("shm_unlink"); 110 fd = shm_open(test_path, O_CREAT | O_EXCL | O_RDWR, 0777); 111 } 112 if (fd < 0) 113 atf_tc_fail("shm_open failed; errno=%d", errno); 114 if (ftruncate(fd, getpagesize()) < 0) 115 atf_tc_fail("ftruncate failed; errno=%d", errno); 116 117 page = mmap(0, getpagesize(), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 118 0); 119 if (page == MAP_FAILED) 120 atf_tc_fail("mmap failed; errno=%d", errno); 121 122 page[0] = '1'; 123 if (munmap(page, getpagesize()) < 0) 124 atf_tc_fail("munmap failed; errno=%d", errno); 125 126 return (fd); 127 } 128 129 ATF_TC_WITHOUT_HEAD(remap_object); 130 ATF_TC_BODY(remap_object, tc) 131 { 132 char *page; 133 int fd; 134 135 fd = scribble_object(); 136 137 page = mmap(0, getpagesize(), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 138 0); 139 if (page == MAP_FAILED) 140 atf_tc_fail("mmap(2) failed; errno=%d", errno); 141 142 if (page[0] != '1') 143 atf_tc_fail("missing data ('%c' != '1')", page[0]); 144 145 close(fd); 146 if (munmap(page, getpagesize()) < 0) 147 atf_tc_fail("munmap failed; errno=%d", errno); 148 149 ATF_REQUIRE_MSG(shm_unlink(test_path) != -1, 150 "shm_unlink failed; errno=%d", errno); 151 } 152 153 ATF_TC_WITHOUT_HEAD(reopen_object); 154 ATF_TC_BODY(reopen_object, tc) 155 { 156 char *page; 157 int fd; 158 159 fd = scribble_object(); 160 close(fd); 161 162 fd = shm_open(test_path, O_RDONLY, 0777); 163 if (fd < 0) 164 atf_tc_fail("shm_open(2) failed; errno=%d", errno); 165 166 page = mmap(0, getpagesize(), PROT_READ, MAP_SHARED, fd, 0); 167 if (page == MAP_FAILED) 168 atf_tc_fail("mmap(2) failed; errno=%d", errno); 169 170 if (page[0] != '1') 171 atf_tc_fail("missing data ('%c' != '1')", page[0]); 172 173 munmap(page, getpagesize()); 174 close(fd); 175 ATF_REQUIRE_MSG(shm_unlink(test_path) != -1, 176 "shm_unlink failed; errno=%d", errno); 177 } 178 179 ATF_TC_WITHOUT_HEAD(readonly_mmap_write); 180 ATF_TC_BODY(readonly_mmap_write, tc) 181 { 182 char *page; 183 int fd; 184 185 gen_test_path(); 186 187 fd = shm_open(test_path, O_RDONLY | O_CREAT, 0777); 188 ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno); 189 190 /* PROT_WRITE should fail with EACCES. */ 191 page = mmap(0, getpagesize(), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 192 0); 193 if (page != MAP_FAILED) 194 atf_tc_fail("mmap(PROT_WRITE) succeeded unexpectedly"); 195 196 if (errno != EACCES) 197 atf_tc_fail("mmap(PROT_WRITE) didn't fail with EACCES; " 198 "errno=%d", errno); 199 200 close(fd); 201 ATF_REQUIRE_MSG(shm_unlink(test_path) != -1, 202 "shm_unlink failed; errno=%d", errno); 203 } 204 205 ATF_TC_WITHOUT_HEAD(open_after_link); 206 ATF_TC_BODY(open_after_link, tc) 207 { 208 int fd; 209 210 gen_test_path(); 211 212 fd = shm_open(test_path, O_RDONLY | O_CREAT, 0777); 213 ATF_REQUIRE_MSG(fd >= 0, "shm_open(1) failed; errno=%d", errno); 214 close(fd); 215 216 ATF_REQUIRE_MSG(shm_unlink(test_path) != -1, "shm_unlink failed: %d", 217 errno); 218 219 shm_open_should_fail(test_path, O_RDONLY, 0777, ENOENT); 220 } 221 222 ATF_TC_WITHOUT_HEAD(open_invalid_path); 223 ATF_TC_BODY(open_invalid_path, tc) 224 { 225 226 shm_open_should_fail("blah", O_RDONLY, 0777, EINVAL); 227 } 228 229 ATF_TC_WITHOUT_HEAD(open_write_only); 230 ATF_TC_BODY(open_write_only, tc) 231 { 232 233 gen_test_path(); 234 235 shm_open_should_fail(test_path, O_WRONLY, 0777, EINVAL); 236 } 237 238 ATF_TC_WITHOUT_HEAD(open_extra_flags); 239 ATF_TC_BODY(open_extra_flags, tc) 240 { 241 242 gen_test_path(); 243 244 shm_open_should_fail(test_path, O_RDONLY | O_DIRECT, 0777, EINVAL); 245 } 246 247 ATF_TC_WITHOUT_HEAD(open_anon); 248 ATF_TC_BODY(open_anon, tc) 249 { 250 int fd; 251 252 fd = shm_open(SHM_ANON, O_RDWR, 0777); 253 ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno); 254 close(fd); 255 } 256 257 ATF_TC_WITHOUT_HEAD(open_anon_readonly); 258 ATF_TC_BODY(open_anon_readonly, tc) 259 { 260 261 shm_open_should_fail(SHM_ANON, O_RDONLY, 0777, EINVAL); 262 } 263 264 ATF_TC_WITHOUT_HEAD(open_bad_path_pointer); 265 ATF_TC_BODY(open_bad_path_pointer, tc) 266 { 267 268 shm_open_should_fail((char *)1024, O_RDONLY, 0777, EFAULT); 269 } 270 271 ATF_TC_WITHOUT_HEAD(open_path_too_long); 272 ATF_TC_BODY(open_path_too_long, tc) 273 { 274 char *page; 275 276 page = malloc(MAXPATHLEN + 1); 277 memset(page, 'a', MAXPATHLEN); 278 page[MAXPATHLEN] = '\0'; 279 shm_open_should_fail(page, O_RDONLY, 0777, ENAMETOOLONG); 280 free(page); 281 } 282 283 ATF_TC_WITHOUT_HEAD(open_nonexisting_object); 284 ATF_TC_BODY(open_nonexisting_object, tc) 285 { 286 287 shm_open_should_fail("/notreallythere", O_RDONLY, 0777, ENOENT); 288 } 289 290 ATF_TC_WITHOUT_HEAD(open_create_existing_object); 291 ATF_TC_BODY(open_create_existing_object, tc) 292 { 293 int fd; 294 295 gen_test_path(); 296 297 fd = shm_open(test_path, O_RDONLY|O_CREAT, 0777); 298 ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno); 299 close(fd); 300 301 shm_open_should_fail(test_path, O_RDONLY|O_CREAT|O_EXCL, 302 0777, EEXIST); 303 304 ATF_REQUIRE_MSG(shm_unlink(test_path) != -1, 305 "shm_unlink failed; errno=%d", errno); 306 } 307 308 ATF_TC_WITHOUT_HEAD(trunc_resets_object); 309 ATF_TC_BODY(trunc_resets_object, tc) 310 { 311 struct stat sb; 312 int fd; 313 314 gen_test_path(); 315 316 /* Create object and set size to 1024. */ 317 fd = shm_open(test_path, O_RDWR | O_CREAT, 0777); 318 ATF_REQUIRE_MSG(fd >= 0, "shm_open(1) failed; errno=%d", errno); 319 ATF_REQUIRE_MSG(ftruncate(fd, 1024) != -1, 320 "ftruncate failed; errno=%d", errno); 321 ATF_REQUIRE_MSG(fstat(fd, &sb) != -1, 322 "fstat(1) failed; errno=%d", errno); 323 ATF_REQUIRE_MSG(sb.st_size == 1024, "size %d != 1024", (int)sb.st_size); 324 close(fd); 325 326 /* Open with O_TRUNC which should reset size to 0. */ 327 fd = shm_open(test_path, O_RDWR | O_TRUNC, 0777); 328 ATF_REQUIRE_MSG(fd >= 0, "shm_open(2) failed; errno=%d", errno); 329 ATF_REQUIRE_MSG(fstat(fd, &sb) != -1, 330 "fstat(2) failed; errno=%d", errno); 331 ATF_REQUIRE_MSG(sb.st_size == 0, 332 "size was not 0 after truncation: %d", (int)sb.st_size); 333 close(fd); 334 ATF_REQUIRE_MSG(shm_unlink(test_path) != -1, 335 "shm_unlink failed; errno=%d", errno); 336 } 337 338 ATF_TC_WITHOUT_HEAD(unlink_bad_path_pointer); 339 ATF_TC_BODY(unlink_bad_path_pointer, tc) 340 { 341 342 shm_unlink_should_fail((char *)1024, EFAULT); 343 } 344 345 ATF_TC_WITHOUT_HEAD(unlink_path_too_long); 346 ATF_TC_BODY(unlink_path_too_long, tc) 347 { 348 char *page; 349 350 page = malloc(MAXPATHLEN + 1); 351 memset(page, 'a', MAXPATHLEN); 352 page[MAXPATHLEN] = '\0'; 353 shm_unlink_should_fail(page, ENAMETOOLONG); 354 free(page); 355 } 356 357 ATF_TC_WITHOUT_HEAD(object_resize); 358 ATF_TC_BODY(object_resize, tc) 359 { 360 pid_t pid; 361 struct stat sb; 362 char err_buf[1024], *page; 363 int fd, status; 364 365 /* Start off with a size of a single page. */ 366 fd = shm_open(SHM_ANON, O_CREAT|O_RDWR, 0777); 367 if (fd < 0) 368 atf_tc_fail("shm_open failed; errno=%d", errno); 369 370 if (ftruncate(fd, getpagesize()) < 0) 371 atf_tc_fail("ftruncate(1) failed; errno=%d", errno); 372 373 if (fstat(fd, &sb) < 0) 374 atf_tc_fail("fstat(1) failed; errno=%d", errno); 375 376 if (sb.st_size != getpagesize()) 377 atf_tc_fail("first resize failed (%d != %d)", 378 (int)sb.st_size, getpagesize()); 379 380 /* Write a '1' to the first byte. */ 381 page = mmap(0, getpagesize(), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 382 0); 383 if (page == MAP_FAILED) 384 atf_tc_fail("mmap(1)"); 385 386 page[0] = '1'; 387 388 if (munmap(page, getpagesize()) < 0) 389 atf_tc_fail("munmap(1) failed; errno=%d", errno); 390 391 /* Grow the object to 2 pages. */ 392 if (ftruncate(fd, getpagesize() * 2) < 0) 393 atf_tc_fail("ftruncate(2) failed; errno=%d", errno); 394 395 if (fstat(fd, &sb) < 0) 396 atf_tc_fail("fstat(2) failed; errno=%d", errno); 397 398 if (sb.st_size != getpagesize() * 2) 399 atf_tc_fail("second resize failed (%d != %d)", 400 (int)sb.st_size, getpagesize() * 2); 401 402 /* Check for '1' at the first byte. */ 403 page = mmap(0, getpagesize() * 2, PROT_READ|PROT_WRITE, MAP_SHARED, 404 fd, 0); 405 if (page == MAP_FAILED) 406 atf_tc_fail("mmap(2) failed; errno=%d", errno); 407 408 if (page[0] != '1') 409 atf_tc_fail("'%c' != '1'", page[0]); 410 411 /* Write a '2' at the start of the second page. */ 412 page[getpagesize()] = '2'; 413 414 /* Shrink the object back to 1 page. */ 415 if (ftruncate(fd, getpagesize()) < 0) 416 atf_tc_fail("ftruncate(3) failed; errno=%d", errno); 417 418 if (fstat(fd, &sb) < 0) 419 atf_tc_fail("fstat(3) failed; errno=%d", errno); 420 421 if (sb.st_size != getpagesize()) 422 atf_tc_fail("third resize failed (%d != %d)", 423 (int)sb.st_size, getpagesize()); 424 425 /* 426 * Fork a child process to make sure the second page is no 427 * longer valid. 428 */ 429 pid = fork(); 430 if (pid == -1) 431 atf_tc_fail("fork failed; errno=%d", errno); 432 433 if (pid == 0) { 434 struct rlimit lim; 435 char c; 436 437 /* Don't generate a core dump. */ 438 getrlimit(RLIMIT_CORE, &lim); 439 lim.rlim_cur = 0; 440 setrlimit(RLIMIT_CORE, &lim); 441 442 /* 443 * The previous ftruncate(2) shrunk the backing object 444 * so that this address is no longer valid, so reading 445 * from it should trigger a SIGSEGV. 446 */ 447 c = page[getpagesize()]; 448 fprintf(stderr, "child: page 1: '%c'\n", c); 449 exit(0); 450 } 451 452 if (wait(&status) < 0) 453 atf_tc_fail("wait failed; errno=%d", errno); 454 455 if (!WIFSIGNALED(status) || WTERMSIG(status) != SIGSEGV) 456 atf_tc_fail("child terminated with status %x", status); 457 458 /* Grow the object back to 2 pages. */ 459 if (ftruncate(fd, getpagesize() * 2) < 0) 460 atf_tc_fail("ftruncate(2) failed; errno=%d", errno); 461 462 if (fstat(fd, &sb) < 0) 463 atf_tc_fail("fstat(2) failed; errno=%d", errno); 464 465 if (sb.st_size != getpagesize() * 2) 466 atf_tc_fail("fourth resize failed (%d != %d)", 467 (int)sb.st_size, getpagesize()); 468 469 /* 470 * Note that the mapping at 'page' for the second page is 471 * still valid, and now that the shm object has been grown 472 * back up to 2 pages, there is now memory backing this page 473 * so the read will work. However, the data should be zero 474 * rather than '2' as the old data was thrown away when the 475 * object was shrunk and the new pages when an object are 476 * grown are zero-filled. 477 */ 478 if (page[getpagesize()] != 0) 479 atf_tc_fail("invalid data at %d: %x != 0", 480 getpagesize(), (int)page[getpagesize()]); 481 482 close(fd); 483 } 484 485 /* Signal handler which does nothing. */ 486 static void 487 ignoreit(int sig __unused) 488 { 489 ; 490 } 491 492 ATF_TC_WITHOUT_HEAD(shm_functionality_across_fork); 493 ATF_TC_BODY(shm_functionality_across_fork, tc) 494 { 495 char *cp, c; 496 int error, desc, rv; 497 long scval; 498 sigset_t ss; 499 struct sigaction sa; 500 void *region; 501 size_t i, psize; 502 503 #ifndef _POSIX_SHARED_MEMORY_OBJECTS 504 printf("_POSIX_SHARED_MEMORY_OBJECTS is undefined\n"); 505 #else 506 printf("_POSIX_SHARED_MEMORY_OBJECTS is defined as %ld\n", 507 (long)_POSIX_SHARED_MEMORY_OBJECTS - 0); 508 if (_POSIX_SHARED_MEMORY_OBJECTS - 0 == -1) 509 printf("***Indicates this feature may be unsupported!\n"); 510 #endif 511 errno = 0; 512 scval = sysconf(_SC_SHARED_MEMORY_OBJECTS); 513 if (scval == -1 && errno != 0) { 514 atf_tc_fail("sysconf(_SC_SHARED_MEMORY_OBJECTS) failed; " 515 "errno=%d", errno); 516 } else { 517 printf("sysconf(_SC_SHARED_MEMORY_OBJECTS) returns %ld\n", 518 scval); 519 if (scval == -1) 520 printf("***Indicates this feature is unsupported!\n"); 521 } 522 523 errno = 0; 524 scval = sysconf(_SC_PAGESIZE); 525 if (scval == -1 && errno != 0) { 526 atf_tc_fail("sysconf(_SC_PAGESIZE) failed; errno=%d", errno); 527 } else if (scval <= 0 || (size_t)psize != psize) { 528 fprintf(stderr, "bogus return from sysconf(_SC_PAGESIZE): %ld", 529 scval); 530 psize = 4096; 531 } else { 532 printf("sysconf(_SC_PAGESIZE) returns %ld\n", scval); 533 psize = scval; 534 } 535 536 gen_test_path(); 537 desc = shm_open(test_path, O_EXCL | O_CREAT | O_RDWR, 0600); 538 539 ATF_REQUIRE_MSG(desc >= 0, "shm_open failed; errno=%d", errno); 540 ATF_REQUIRE_MSG(shm_unlink(test_path) == 0, 541 "shm_unlink failed; errno=%d", errno); 542 ATF_REQUIRE_MSG(ftruncate(desc, (off_t)psize) != -1, 543 "ftruncate failed; errno=%d", errno); 544 545 region = mmap((void *)0, psize, PROT_READ | PROT_WRITE, MAP_SHARED, 546 desc, (off_t)0); 547 ATF_REQUIRE_MSG(region != MAP_FAILED, "mmap failed; errno=%d", errno); 548 memset(region, '\377', psize); 549 550 sa.sa_flags = 0; 551 sa.sa_handler = ignoreit; 552 sigemptyset(&sa.sa_mask); 553 ATF_REQUIRE_MSG(sigaction(SIGUSR1, &sa, (struct sigaction *)0) == 0, 554 "sigaction failed; errno=%d", errno); 555 556 sigemptyset(&ss); 557 sigaddset(&ss, SIGUSR1); 558 ATF_REQUIRE_MSG(sigprocmask(SIG_BLOCK, &ss, (sigset_t *)0) == 0, 559 "sigprocmask failed; errno=%d", errno); 560 561 rv = fork(); 562 ATF_REQUIRE_MSG(rv != -1, "fork failed; errno=%d", errno); 563 if (rv == 0) { 564 sigemptyset(&ss); 565 sigsuspend(&ss); 566 567 for (cp = region; cp < (char *)region + psize; cp++) { 568 if (*cp != '\151') 569 _exit(1); 570 } 571 if (lseek(desc, 0, SEEK_SET) == -1) 572 _exit(1); 573 for (i = 0; i < psize; i++) { 574 error = read(desc, &c, 1); 575 if (c != '\151') 576 _exit(1); 577 } 578 _exit(0); 579 } else { 580 int status; 581 582 memset(region, '\151', psize - 2); 583 error = pwrite(desc, region, 2, psize - 2); 584 if (error != 2) { 585 if (error >= 0) 586 atf_tc_fail("short write; %d bytes written", 587 error); 588 else 589 atf_tc_fail("shmfd write"); 590 } 591 kill(rv, SIGUSR1); 592 waitpid(rv, &status, 0); 593 594 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { 595 printf("Functionality test successful\n"); 596 } else if (WIFEXITED(status)) { 597 atf_tc_fail("Child process exited with status %d", 598 WEXITSTATUS(status)); 599 } else { 600 atf_tc_fail("Child process terminated with %s", 601 strsignal(WTERMSIG(status))); 602 } 603 } 604 } 605 606 ATF_TP_ADD_TCS(tp) 607 { 608 609 ATF_TP_ADD_TC(tp, remap_object); 610 ATF_TP_ADD_TC(tp, reopen_object); 611 ATF_TP_ADD_TC(tp, readonly_mmap_write); 612 ATF_TP_ADD_TC(tp, open_after_link); 613 ATF_TP_ADD_TC(tp, open_invalid_path); 614 ATF_TP_ADD_TC(tp, open_write_only); 615 ATF_TP_ADD_TC(tp, open_extra_flags); 616 ATF_TP_ADD_TC(tp, open_anon); 617 ATF_TP_ADD_TC(tp, open_anon_readonly); 618 ATF_TP_ADD_TC(tp, open_bad_path_pointer); 619 ATF_TP_ADD_TC(tp, open_path_too_long); 620 ATF_TP_ADD_TC(tp, open_nonexisting_object); 621 ATF_TP_ADD_TC(tp, open_create_existing_object); 622 ATF_TP_ADD_TC(tp, shm_functionality_across_fork); 623 ATF_TP_ADD_TC(tp, trunc_resets_object); 624 ATF_TP_ADD_TC(tp, unlink_bad_path_pointer); 625 ATF_TP_ADD_TC(tp, unlink_path_too_long); 626 ATF_TP_ADD_TC(tp, object_resize); 627 628 return (atf_no_error()); 629 } 630