xref: /freebsd/tests/sys/posixshm/posixshm_test.c (revision 4f775512)
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 <ctype.h>
38 #include <errno.h>
39 #include <fcntl.h>
40 #include <signal.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <unistd.h>
45 
46 #include <atf-c.h>
47 
48 #define	TEST_PATH_LEN	256
49 static char test_path[TEST_PATH_LEN];
50 static char test_path2[TEST_PATH_LEN];
51 static unsigned int test_path_idx = 0;
52 
53 static void
54 gen_a_test_path(char *path)
55 {
56 	snprintf(path, TEST_PATH_LEN, "%s/tmp.XXXXXX%d",
57 	    getenv("TMPDIR") == NULL ? "/tmp" : getenv("TMPDIR"),
58 	    test_path_idx);
59 
60 	test_path_idx++;
61 
62 	ATF_REQUIRE_MSG(mkstemp(path) != -1,
63 	    "mkstemp failed; errno=%d", errno);
64 	ATF_REQUIRE_MSG(unlink(path) == 0,
65 	    "unlink failed; errno=%d", errno);
66 }
67 
68 static void
69 gen_test_path(void)
70 {
71 	gen_a_test_path(test_path);
72 }
73 
74 static void
75 gen_test_path2(void)
76 {
77 	gen_a_test_path(test_path2);
78 }
79 
80 /*
81  * Attempt a shm_open() that should fail with an expected error of 'error'.
82  */
83 static void
84 shm_open_should_fail(const char *path, int flags, mode_t mode, int error)
85 {
86 	int fd;
87 
88 	fd = shm_open(path, flags, mode);
89 	ATF_CHECK_MSG(fd == -1, "shm_open didn't fail");
90 	ATF_CHECK_MSG(error == errno,
91 	    "shm_open didn't fail with expected errno; errno=%d; expected "
92 	    "errno=%d", errno, error);
93 }
94 
95 /*
96  * Attempt a shm_unlink() that should fail with an expected error of 'error'.
97  */
98 static void
99 shm_unlink_should_fail(const char *path, int error)
100 {
101 
102 	ATF_CHECK_MSG(shm_unlink(path) == -1, "shm_unlink didn't fail");
103 	ATF_CHECK_MSG(error == errno,
104 	    "shm_unlink didn't fail with expected errno; errno=%d; expected "
105 	    "errno=%d", errno, error);
106 }
107 
108 /*
109  * Open the test object and write a value to the first byte.  Returns valid fd
110  * on success and -1 on failure.
111  */
112 static int
113 scribble_object(const char *path, char value)
114 {
115 	char *page;
116 	int fd, pagesize;
117 
118 	ATF_REQUIRE(0 < (pagesize = getpagesize()));
119 
120 	fd = shm_open(path, O_CREAT|O_EXCL|O_RDWR, 0777);
121 	if (fd < 0 && errno == EEXIST) {
122 		if (shm_unlink(test_path) < 0)
123 			atf_tc_fail("shm_unlink");
124 		fd = shm_open(test_path, O_CREAT | O_EXCL | O_RDWR, 0777);
125 	}
126 	if (fd < 0)
127 		atf_tc_fail("shm_open failed; errno=%d", errno);
128 	if (ftruncate(fd, pagesize) < 0)
129 		atf_tc_fail("ftruncate failed; errno=%d", errno);
130 
131 	page = mmap(0, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
132 	if (page == MAP_FAILED)
133 		atf_tc_fail("mmap failed; errno=%d", errno);
134 
135 	page[0] = value;
136 	ATF_REQUIRE_MSG(munmap(page, pagesize) == 0, "munmap failed; errno=%d",
137 	    errno);
138 
139 	return (fd);
140 }
141 
142 /*
143  * Fail the test case if the 'path' does not refer to an shm whose first byte
144  * is equal to expected_value
145  */
146 static void
147 verify_object(const char *path, char expected_value)
148 {
149 	int fd;
150 	int pagesize;
151 	char *page;
152 
153 	ATF_REQUIRE(0 < (pagesize = getpagesize()));
154 
155 	fd = shm_open(path, O_RDONLY, 0777);
156 	if (fd < 0)
157 		atf_tc_fail("shm_open failed in verify_object; errno=%d, path=%s",
158 		    errno, path);
159 
160 	page = mmap(0, pagesize, PROT_READ, MAP_SHARED, fd, 0);
161 	if (page == MAP_FAILED)
162 		atf_tc_fail("mmap(1)");
163 	if (page[0] != expected_value)
164 		atf_tc_fail("Renamed object has incorrect value; has"
165 		    "%d (0x%x, '%c'), expected %d (0x%x, '%c')\n",
166 		    page[0], page[0], isprint(page[0]) ? page[0] : ' ',
167 		    expected_value, expected_value,
168 		    isprint(expected_value) ? expected_value : ' ');
169 	ATF_REQUIRE_MSG(munmap(page, pagesize) == 0, "munmap failed; errno=%d",
170 	    errno);
171 	close(fd);
172 }
173 
174 ATF_TC_WITHOUT_HEAD(remap_object);
175 ATF_TC_BODY(remap_object, tc)
176 {
177 	char *page;
178 	int fd, pagesize;
179 
180 	ATF_REQUIRE(0 < (pagesize = getpagesize()));
181 
182 	gen_test_path();
183 	fd = scribble_object(test_path, '1');
184 
185 	page = mmap(0, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
186 	if (page == MAP_FAILED)
187 		atf_tc_fail("mmap(2) failed; errno=%d", errno);
188 
189 	if (page[0] != '1')
190 		atf_tc_fail("missing data ('%c' != '1')", page[0]);
191 
192 	close(fd);
193 	ATF_REQUIRE_MSG(munmap(page, pagesize) == 0, "munmap failed; errno=%d",
194 	    errno);
195 
196 	ATF_REQUIRE_MSG(shm_unlink(test_path) != -1,
197 	    "shm_unlink failed; errno=%d", errno);
198 }
199 
200 ATF_TC_WITHOUT_HEAD(rename_from_anon);
201 ATF_TC_BODY(rename_from_anon, tc)
202 {
203 	int rc;
204 
205 	gen_test_path();
206 	rc = shm_rename(SHM_ANON, test_path, 0);
207 	if (rc != -1)
208 		atf_tc_fail("shm_rename from SHM_ANON succeeded unexpectedly");
209 }
210 
211 ATF_TC_WITHOUT_HEAD(rename_bad_path_pointer);
212 ATF_TC_BODY(rename_bad_path_pointer, tc)
213 {
214 	const char *bad_path;
215 	int rc;
216 
217 	bad_path = (const char *)0x1;
218 
219 	gen_test_path();
220 	rc = shm_rename(test_path, bad_path, 0);
221 	if (rc != -1)
222 		atf_tc_fail("shm_rename of nonexisting shm succeeded unexpectedly");
223 
224 	rc = shm_rename(bad_path, test_path, 0);
225 	if (rc != -1)
226 		atf_tc_fail("shm_rename of nonexisting shm succeeded unexpectedly");
227 }
228 
229 ATF_TC_WITHOUT_HEAD(rename_from_nonexisting);
230 ATF_TC_BODY(rename_from_nonexisting, tc)
231 {
232 	int rc;
233 
234 	gen_test_path();
235 	rc = shm_rename(test_path, test_path2, 0);
236 	if (rc != -1)
237 		atf_tc_fail("shm_rename of nonexisting shm succeeded unexpectedly");
238 
239 	if (errno != ENOENT)
240 		atf_tc_fail("Expected ENOENT to rename of nonexistent shm");
241 }
242 
243 ATF_TC_WITHOUT_HEAD(rename_to_anon);
244 ATF_TC_BODY(rename_to_anon, tc)
245 {
246 	int rc;
247 
248 	gen_test_path();
249 	rc = shm_rename(test_path, SHM_ANON, 0);
250 	if (rc != -1)
251 		atf_tc_fail("shm_rename to SHM_ANON succeeded unexpectedly");
252 }
253 
254 ATF_TC_WITHOUT_HEAD(rename_to_replace);
255 ATF_TC_BODY(rename_to_replace, tc)
256 {
257 	char expected_value;
258 	int fd;
259 	int fd2;
260 
261 	// Some contents we can verify later
262 	expected_value = 'g';
263 
264 	gen_test_path();
265 	fd = scribble_object(test_path, expected_value);
266 	close(fd);
267 
268 	// Give the other some different value so we can detect success
269 	gen_test_path2();
270 	fd2 = scribble_object(test_path2, 'h');
271 	close(fd2);
272 
273 	ATF_REQUIRE_MSG(shm_rename(test_path, test_path2, 0) == 0,
274 	    "shm_rename failed; errno=%d", errno);
275 
276 	// Read back renamed; verify contents
277 	verify_object(test_path2, expected_value);
278 }
279 
280 ATF_TC_WITHOUT_HEAD(rename_to_noreplace);
281 ATF_TC_BODY(rename_to_noreplace, tc)
282 {
283 	char expected_value_from;
284 	char expected_value_to;
285 	int fd_from;
286 	int fd_to;
287 	int rc;
288 
289 	// Some contents we can verify later
290 	expected_value_from = 'g';
291 	gen_test_path();
292 	fd_from = scribble_object(test_path, expected_value_from);
293 	close(fd_from);
294 
295 	// Give the other some different value so we can detect success
296 	expected_value_to = 'h';
297 	gen_test_path2();
298 	fd_to = scribble_object(test_path2, expected_value_to);
299 	close(fd_to);
300 
301 	rc = shm_rename(test_path, test_path2, SHM_RENAME_NOREPLACE);
302 	ATF_REQUIRE_MSG((rc == -1) && (errno == EEXIST),
303 	    "shm_rename didn't fail as expected; errno: %d; return: %d", errno,
304 	    rc);
305 
306 	// Read back renamed; verify contents
307 	verify_object(test_path2, expected_value_to);
308 }
309 
310 ATF_TC_WITHOUT_HEAD(rename_to_exchange);
311 ATF_TC_BODY(rename_to_exchange, tc)
312 {
313 	char expected_value_from;
314 	char expected_value_to;
315 	int fd_from;
316 	int fd_to;
317 
318 	// Some contents we can verify later
319 	expected_value_from = 'g';
320 	gen_test_path();
321 	fd_from = scribble_object(test_path, expected_value_from);
322 	close(fd_from);
323 
324 	// Give the other some different value so we can detect success
325 	expected_value_to = 'h';
326 	gen_test_path2();
327 	fd_to = scribble_object(test_path2, expected_value_to);
328 	close(fd_to);
329 
330 	ATF_REQUIRE_MSG(shm_rename(test_path, test_path2,
331 	    SHM_RENAME_EXCHANGE) == 0,
332 	    "shm_rename failed; errno=%d", errno);
333 
334 	// Read back renamed; verify contents
335 	verify_object(test_path, expected_value_to);
336 	verify_object(test_path2, expected_value_from);
337 }
338 
339 ATF_TC_WITHOUT_HEAD(rename_to_exchange_nonexisting);
340 ATF_TC_BODY(rename_to_exchange_nonexisting, tc)
341 {
342 	char expected_value_from;
343 	int fd_from;
344 
345 	// Some contents we can verify later
346 	expected_value_from = 'g';
347 	gen_test_path();
348 	fd_from = scribble_object(test_path, expected_value_from);
349 	close(fd_from);
350 
351 	gen_test_path2();
352 
353 	ATF_REQUIRE_MSG(shm_rename(test_path, test_path2,
354 	    SHM_RENAME_EXCHANGE) == 0,
355 	    "shm_rename failed; errno=%d", errno);
356 
357 	// Read back renamed; verify contents
358 	verify_object(test_path2, expected_value_from);
359 }
360 
361 ATF_TC_WITHOUT_HEAD(rename_to_self);
362 ATF_TC_BODY(rename_to_self, tc)
363 {
364 	int fd;
365 	char expected_value;
366 
367 	expected_value = 't';
368 
369 	gen_test_path();
370 	fd = scribble_object(test_path, expected_value);
371 	close(fd);
372 
373 	ATF_REQUIRE_MSG(shm_rename(test_path, test_path, 0) == 0,
374 	    "shm_rename failed; errno=%d", errno);
375 
376 	verify_object(test_path, expected_value);
377 }
378 
379 ATF_TC_WITHOUT_HEAD(rename_bad_flag);
380 ATF_TC_BODY(rename_bad_flag, tc)
381 {
382 	int fd;
383 	int rc;
384 
385 	/* Make sure we don't fail out due to ENOENT */
386 	gen_test_path();
387 	gen_test_path2();
388 	fd = scribble_object(test_path, 'd');
389 	close(fd);
390 	fd = scribble_object(test_path2, 'd');
391 	close(fd);
392 
393 	/*
394 	 * Note: if we end up with enough flags that we use all the bits,
395 	 * then remove this test completely.
396 	 */
397 	rc = shm_rename(test_path, test_path2, INT_MIN);
398 	ATF_REQUIRE_MSG((rc == -1) && (errno == EINVAL),
399 	    "shm_rename should have failed with EINVAL; got: return=%d, "
400 	    "errno=%d", rc, errno);
401 }
402 
403 ATF_TC_WITHOUT_HEAD(reopen_object);
404 ATF_TC_BODY(reopen_object, tc)
405 {
406 	char *page;
407 	int fd, pagesize;
408 
409 	ATF_REQUIRE(0 < (pagesize = getpagesize()));
410 
411 	gen_test_path();
412 	fd = scribble_object(test_path, '1');
413 	close(fd);
414 
415 	fd = shm_open(test_path, O_RDONLY, 0777);
416 	if (fd < 0)
417 		atf_tc_fail("shm_open(2) failed; errno=%d", errno);
418 
419 	page = mmap(0, pagesize, PROT_READ, MAP_SHARED, fd, 0);
420 	if (page == MAP_FAILED)
421 		atf_tc_fail("mmap(2) failed; errno=%d", errno);
422 
423 	if (page[0] != '1')
424 		atf_tc_fail("missing data ('%c' != '1')", page[0]);
425 
426 	ATF_REQUIRE_MSG(munmap(page, pagesize) == 0, "munmap failed; errno=%d",
427 	    errno);
428 	close(fd);
429 	ATF_REQUIRE_MSG(shm_unlink(test_path) != -1,
430 	    "shm_unlink failed; errno=%d", errno);
431 }
432 
433 ATF_TC_WITHOUT_HEAD(readonly_mmap_write);
434 ATF_TC_BODY(readonly_mmap_write, tc)
435 {
436 	char *page;
437 	int fd, pagesize;
438 
439 	ATF_REQUIRE(0 < (pagesize = getpagesize()));
440 
441 	gen_test_path();
442 
443 	fd = shm_open(test_path, O_RDONLY | O_CREAT, 0777);
444 	ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno);
445 
446 	/* PROT_WRITE should fail with EACCES. */
447 	page = mmap(0, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
448 	if (page != MAP_FAILED)
449 		atf_tc_fail("mmap(PROT_WRITE) succeeded unexpectedly");
450 
451 	if (errno != EACCES)
452 		atf_tc_fail("mmap(PROT_WRITE) didn't fail with EACCES; "
453 		    "errno=%d", errno);
454 
455 	close(fd);
456 	ATF_REQUIRE_MSG(shm_unlink(test_path) != -1,
457 	    "shm_unlink failed; errno=%d", errno);
458 }
459 
460 ATF_TC_WITHOUT_HEAD(open_after_link);
461 ATF_TC_BODY(open_after_link, tc)
462 {
463 	int fd;
464 
465 	gen_test_path();
466 
467 	fd = shm_open(test_path, O_RDONLY | O_CREAT, 0777);
468 	ATF_REQUIRE_MSG(fd >= 0, "shm_open(1) failed; errno=%d", errno);
469 	close(fd);
470 
471 	ATF_REQUIRE_MSG(shm_unlink(test_path) != -1, "shm_unlink failed: %d",
472 	    errno);
473 
474 	shm_open_should_fail(test_path, O_RDONLY, 0777, ENOENT);
475 }
476 
477 ATF_TC_WITHOUT_HEAD(open_invalid_path);
478 ATF_TC_BODY(open_invalid_path, tc)
479 {
480 
481 	shm_open_should_fail("blah", O_RDONLY, 0777, EINVAL);
482 }
483 
484 ATF_TC_WITHOUT_HEAD(open_write_only);
485 ATF_TC_BODY(open_write_only, tc)
486 {
487 
488 	gen_test_path();
489 
490 	shm_open_should_fail(test_path, O_WRONLY, 0777, EINVAL);
491 }
492 
493 ATF_TC_WITHOUT_HEAD(open_extra_flags);
494 ATF_TC_BODY(open_extra_flags, tc)
495 {
496 
497 	gen_test_path();
498 
499 	shm_open_should_fail(test_path, O_RDONLY | O_DIRECT, 0777, EINVAL);
500 }
501 
502 ATF_TC_WITHOUT_HEAD(open_anon);
503 ATF_TC_BODY(open_anon, tc)
504 {
505 	int fd;
506 
507 	fd = shm_open(SHM_ANON, O_RDWR, 0777);
508 	ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno);
509 	close(fd);
510 }
511 
512 ATF_TC_WITHOUT_HEAD(open_anon_readonly);
513 ATF_TC_BODY(open_anon_readonly, tc)
514 {
515 
516 	shm_open_should_fail(SHM_ANON, O_RDONLY, 0777, EINVAL);
517 }
518 
519 ATF_TC_WITHOUT_HEAD(open_bad_path_pointer);
520 ATF_TC_BODY(open_bad_path_pointer, tc)
521 {
522 
523 	shm_open_should_fail((char *)1024, O_RDONLY, 0777, EFAULT);
524 }
525 
526 ATF_TC_WITHOUT_HEAD(open_path_too_long);
527 ATF_TC_BODY(open_path_too_long, tc)
528 {
529 	char *page;
530 
531 	page = malloc(MAXPATHLEN + 1);
532 	memset(page, 'a', MAXPATHLEN);
533 	page[MAXPATHLEN] = '\0';
534 	shm_open_should_fail(page, O_RDONLY, 0777, ENAMETOOLONG);
535 	free(page);
536 }
537 
538 ATF_TC_WITHOUT_HEAD(open_nonexisting_object);
539 ATF_TC_BODY(open_nonexisting_object, tc)
540 {
541 
542 	shm_open_should_fail("/notreallythere", O_RDONLY, 0777, ENOENT);
543 }
544 
545 ATF_TC_WITHOUT_HEAD(open_create_existing_object);
546 ATF_TC_BODY(open_create_existing_object, tc)
547 {
548 	int fd;
549 
550 	gen_test_path();
551 
552 	fd = shm_open(test_path, O_RDONLY|O_CREAT, 0777);
553 	ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno);
554 	close(fd);
555 
556 	shm_open_should_fail(test_path, O_RDONLY|O_CREAT|O_EXCL,
557 	    0777, EEXIST);
558 
559 	ATF_REQUIRE_MSG(shm_unlink(test_path) != -1,
560 	    "shm_unlink failed; errno=%d", errno);
561 }
562 
563 ATF_TC_WITHOUT_HEAD(trunc_resets_object);
564 ATF_TC_BODY(trunc_resets_object, tc)
565 {
566 	struct stat sb;
567 	int fd;
568 
569 	gen_test_path();
570 
571 	/* Create object and set size to 1024. */
572 	fd = shm_open(test_path, O_RDWR | O_CREAT, 0777);
573 	ATF_REQUIRE_MSG(fd >= 0, "shm_open(1) failed; errno=%d", errno);
574 	ATF_REQUIRE_MSG(ftruncate(fd, 1024) != -1,
575 	    "ftruncate failed; errno=%d", errno);
576 	ATF_REQUIRE_MSG(fstat(fd, &sb) != -1,
577 	    "fstat(1) failed; errno=%d", errno);
578 	ATF_REQUIRE_MSG(sb.st_size == 1024, "size %d != 1024", (int)sb.st_size);
579 	close(fd);
580 
581 	/* Open with O_TRUNC which should reset size to 0. */
582 	fd = shm_open(test_path, O_RDWR | O_TRUNC, 0777);
583 	ATF_REQUIRE_MSG(fd >= 0, "shm_open(2) failed; errno=%d", errno);
584 	ATF_REQUIRE_MSG(fstat(fd, &sb) != -1,
585 	    "fstat(2) failed; errno=%d", errno);
586 	ATF_REQUIRE_MSG(sb.st_size == 0,
587 	    "size was not 0 after truncation: %d", (int)sb.st_size);
588 	close(fd);
589 	ATF_REQUIRE_MSG(shm_unlink(test_path) != -1,
590 	    "shm_unlink failed; errno=%d", errno);
591 }
592 
593 ATF_TC_WITHOUT_HEAD(unlink_bad_path_pointer);
594 ATF_TC_BODY(unlink_bad_path_pointer, tc)
595 {
596 
597 	shm_unlink_should_fail((char *)1024, EFAULT);
598 }
599 
600 ATF_TC_WITHOUT_HEAD(unlink_path_too_long);
601 ATF_TC_BODY(unlink_path_too_long, tc)
602 {
603 	char *page;
604 
605 	page = malloc(MAXPATHLEN + 1);
606 	memset(page, 'a', MAXPATHLEN);
607 	page[MAXPATHLEN] = '\0';
608 	shm_unlink_should_fail(page, ENAMETOOLONG);
609 	free(page);
610 }
611 
612 ATF_TC_WITHOUT_HEAD(object_resize);
613 ATF_TC_BODY(object_resize, tc)
614 {
615 	pid_t pid;
616 	struct stat sb;
617 	char *page;
618 	int fd, pagesize, status;
619 
620 	ATF_REQUIRE(0 < (pagesize = getpagesize()));
621 
622 	/* Start off with a size of a single page. */
623 	fd = shm_open(SHM_ANON, O_CREAT|O_RDWR, 0777);
624 	if (fd < 0)
625 		atf_tc_fail("shm_open failed; errno=%d", errno);
626 
627 	if (ftruncate(fd, pagesize) < 0)
628 		atf_tc_fail("ftruncate(1) failed; errno=%d", errno);
629 
630 	if (fstat(fd, &sb) < 0)
631 		atf_tc_fail("fstat(1) failed; errno=%d", errno);
632 
633 	if (sb.st_size != pagesize)
634 		atf_tc_fail("first resize failed (%d != %d)",
635 		    (int)sb.st_size, pagesize);
636 
637 	/* Write a '1' to the first byte. */
638 	page = mmap(0, pagesize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
639 	if (page == MAP_FAILED)
640 		atf_tc_fail("mmap(1)");
641 
642 	page[0] = '1';
643 
644 	ATF_REQUIRE_MSG(munmap(page, pagesize) == 0, "munmap failed; errno=%d",
645 	    errno);
646 
647 	/* Grow the object to 2 pages. */
648 	if (ftruncate(fd, pagesize * 2) < 0)
649 		atf_tc_fail("ftruncate(2) failed; errno=%d", errno);
650 
651 	if (fstat(fd, &sb) < 0)
652 		atf_tc_fail("fstat(2) failed; errno=%d", errno);
653 
654 	if (sb.st_size != pagesize * 2)
655 		atf_tc_fail("second resize failed (%d != %d)",
656 		    (int)sb.st_size, pagesize * 2);
657 
658 	/* Check for '1' at the first byte. */
659 	page = mmap(0, pagesize * 2, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
660 	if (page == MAP_FAILED)
661 		atf_tc_fail("mmap(2) failed; errno=%d", errno);
662 
663 	if (page[0] != '1')
664 		atf_tc_fail("'%c' != '1'", page[0]);
665 
666 	/* Write a '2' at the start of the second page. */
667 	page[pagesize] = '2';
668 
669 	/* Shrink the object back to 1 page. */
670 	if (ftruncate(fd, pagesize) < 0)
671 		atf_tc_fail("ftruncate(3) failed; errno=%d", errno);
672 
673 	if (fstat(fd, &sb) < 0)
674 		atf_tc_fail("fstat(3) failed; errno=%d", errno);
675 
676 	if (sb.st_size != pagesize)
677 		atf_tc_fail("third resize failed (%d != %d)",
678 		    (int)sb.st_size, pagesize);
679 
680 	/*
681 	 * Fork a child process to make sure the second page is no
682 	 * longer valid.
683 	 */
684 	pid = fork();
685 	if (pid == -1)
686 		atf_tc_fail("fork failed; errno=%d", errno);
687 
688 	if (pid == 0) {
689 		struct rlimit lim;
690 		char c;
691 
692 		/* Don't generate a core dump. */
693 		ATF_REQUIRE(getrlimit(RLIMIT_CORE, &lim) == 0);
694 		lim.rlim_cur = 0;
695 		ATF_REQUIRE(setrlimit(RLIMIT_CORE, &lim) == 0);
696 
697 		/*
698 		 * The previous ftruncate(2) shrunk the backing object
699 		 * so that this address is no longer valid, so reading
700 		 * from it should trigger a SIGBUS.
701 		 */
702 		c = page[pagesize];
703 		fprintf(stderr, "child: page 1: '%c'\n", c);
704 		exit(0);
705 	}
706 
707 	if (wait(&status) < 0)
708 		atf_tc_fail("wait failed; errno=%d", errno);
709 
710 	if (!WIFSIGNALED(status) || WTERMSIG(status) != SIGBUS)
711 		atf_tc_fail("child terminated with status %x", status);
712 
713 	/* Grow the object back to 2 pages. */
714 	if (ftruncate(fd, pagesize * 2) < 0)
715 		atf_tc_fail("ftruncate(2) failed; errno=%d", errno);
716 
717 	if (fstat(fd, &sb) < 0)
718 		atf_tc_fail("fstat(2) failed; errno=%d", errno);
719 
720 	if (sb.st_size != pagesize * 2)
721 		atf_tc_fail("fourth resize failed (%d != %d)",
722 		    (int)sb.st_size, pagesize);
723 
724 	/*
725 	 * Note that the mapping at 'page' for the second page is
726 	 * still valid, and now that the shm object has been grown
727 	 * back up to 2 pages, there is now memory backing this page
728 	 * so the read will work.  However, the data should be zero
729 	 * rather than '2' as the old data was thrown away when the
730 	 * object was shrunk and the new pages when an object are
731 	 * grown are zero-filled.
732 	 */
733 	if (page[pagesize] != 0)
734 		atf_tc_fail("invalid data at %d: %x != 0",
735 		    pagesize, (int)page[pagesize]);
736 
737 	close(fd);
738 }
739 
740 /* Signal handler which does nothing. */
741 static void
742 ignoreit(int sig __unused)
743 {
744 	;
745 }
746 
747 ATF_TC_WITHOUT_HEAD(shm_functionality_across_fork);
748 ATF_TC_BODY(shm_functionality_across_fork, tc)
749 {
750 	char *cp, c;
751 	int error, desc, rv;
752 	long scval;
753 	sigset_t ss;
754 	struct sigaction sa;
755 	void *region;
756 	size_t i, psize;
757 
758 #ifndef _POSIX_SHARED_MEMORY_OBJECTS
759 	printf("_POSIX_SHARED_MEMORY_OBJECTS is undefined\n");
760 #else
761 	printf("_POSIX_SHARED_MEMORY_OBJECTS is defined as %ld\n",
762 	       (long)_POSIX_SHARED_MEMORY_OBJECTS - 0);
763 	if (_POSIX_SHARED_MEMORY_OBJECTS - 0 == -1)
764 		printf("***Indicates this feature may be unsupported!\n");
765 #endif
766 	errno = 0;
767 	scval = sysconf(_SC_SHARED_MEMORY_OBJECTS);
768 	if (scval == -1 && errno != 0) {
769 		atf_tc_fail("sysconf(_SC_SHARED_MEMORY_OBJECTS) failed; "
770 		    "errno=%d", errno);
771 	} else {
772 		printf("sysconf(_SC_SHARED_MEMORY_OBJECTS) returns %ld\n",
773 		       scval);
774 		if (scval == -1)
775 			printf("***Indicates this feature is unsupported!\n");
776 	}
777 
778 	errno = 0;
779 	scval = sysconf(_SC_PAGESIZE);
780 	if (scval == -1 && errno != 0) {
781 		atf_tc_fail("sysconf(_SC_PAGESIZE) failed; errno=%d", errno);
782 	} else if (scval <= 0) {
783 		fprintf(stderr, "bogus return from sysconf(_SC_PAGESIZE): %ld",
784 		    scval);
785 		psize = 4096;
786 	} else {
787 		printf("sysconf(_SC_PAGESIZE) returns %ld\n", scval);
788 		psize = scval;
789 	}
790 
791 	gen_test_path();
792 	desc = shm_open(test_path, O_EXCL | O_CREAT | O_RDWR, 0600);
793 
794 	ATF_REQUIRE_MSG(desc >= 0, "shm_open failed; errno=%d", errno);
795 	ATF_REQUIRE_MSG(shm_unlink(test_path) == 0,
796 	    "shm_unlink failed; errno=%d", errno);
797 	ATF_REQUIRE_MSG(ftruncate(desc, (off_t)psize) != -1,
798 	    "ftruncate failed; errno=%d", errno);
799 
800 	region = mmap(NULL, psize, PROT_READ | PROT_WRITE, MAP_SHARED, desc, 0);
801 	ATF_REQUIRE_MSG(region != MAP_FAILED, "mmap failed; errno=%d", errno);
802 	memset(region, '\377', psize);
803 
804 	sa.sa_flags = 0;
805 	sa.sa_handler = ignoreit;
806 	sigemptyset(&sa.sa_mask);
807 	ATF_REQUIRE_MSG(sigaction(SIGUSR1, &sa, (struct sigaction *)0) == 0,
808 	    "sigaction failed; errno=%d", errno);
809 
810 	sigemptyset(&ss);
811 	sigaddset(&ss, SIGUSR1);
812 	ATF_REQUIRE_MSG(sigprocmask(SIG_BLOCK, &ss, (sigset_t *)0) == 0,
813 	    "sigprocmask failed; errno=%d", errno);
814 
815 	rv = fork();
816 	ATF_REQUIRE_MSG(rv != -1, "fork failed; errno=%d", errno);
817 	if (rv == 0) {
818 		sigemptyset(&ss);
819 		sigsuspend(&ss);
820 
821 		for (cp = region; cp < (char *)region + psize; cp++) {
822 			if (*cp != '\151')
823 				_exit(1);
824 		}
825 		if (lseek(desc, 0, SEEK_SET) == -1)
826 			_exit(1);
827 		for (i = 0; i < psize; i++) {
828 			error = read(desc, &c, 1);
829 			if (c != '\151')
830 				_exit(1);
831 		}
832 		_exit(0);
833 	} else {
834 		int status;
835 
836 		memset(region, '\151', psize - 2);
837 		error = pwrite(desc, region, 2, psize - 2);
838 		if (error != 2) {
839 			if (error >= 0)
840 				atf_tc_fail("short write; %d bytes written",
841 				    error);
842 			else
843 				atf_tc_fail("shmfd write");
844 		}
845 		kill(rv, SIGUSR1);
846 		waitpid(rv, &status, 0);
847 
848 		if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
849 			printf("Functionality test successful\n");
850 		} else if (WIFEXITED(status)) {
851 			atf_tc_fail("Child process exited with status %d",
852 			    WEXITSTATUS(status));
853 		} else {
854 			atf_tc_fail("Child process terminated with %s",
855 			    strsignal(WTERMSIG(status)));
856 		}
857 	}
858 
859 	ATF_REQUIRE_MSG(munmap(region, psize) == 0, "munmap failed; errno=%d",
860 	    errno);
861 	shm_unlink(test_path);
862 }
863 
864 ATF_TC_WITHOUT_HEAD(cloexec);
865 ATF_TC_BODY(cloexec, tc)
866 {
867 	int fd;
868 
869 	gen_test_path();
870 
871 	/* shm_open(2) is required to set FD_CLOEXEC */
872 	fd = shm_open(SHM_ANON, O_RDWR, 0777);
873 	ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno);
874 	ATF_REQUIRE((fcntl(fd, F_GETFD) & FD_CLOEXEC) != 0);
875 	close(fd);
876 
877 	/* Also make sure that named shm is correct */
878 	fd = shm_open(test_path, O_CREAT | O_RDWR, 0600);
879 	ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno);
880 	ATF_REQUIRE((fcntl(fd, F_GETFD) & FD_CLOEXEC) != 0);
881 	close(fd);
882 }
883 
884 
885 ATF_TP_ADD_TCS(tp)
886 {
887 
888 	ATF_TP_ADD_TC(tp, remap_object);
889 	ATF_TP_ADD_TC(tp, rename_from_anon);
890 	ATF_TP_ADD_TC(tp, rename_bad_path_pointer);
891 	ATF_TP_ADD_TC(tp, rename_from_nonexisting);
892 	ATF_TP_ADD_TC(tp, rename_to_anon);
893 	ATF_TP_ADD_TC(tp, rename_to_replace);
894 	ATF_TP_ADD_TC(tp, rename_to_noreplace);
895 	ATF_TP_ADD_TC(tp, rename_to_exchange);
896 	ATF_TP_ADD_TC(tp, rename_to_exchange_nonexisting);
897 	ATF_TP_ADD_TC(tp, rename_to_self);
898 	ATF_TP_ADD_TC(tp, rename_bad_flag);
899 	ATF_TP_ADD_TC(tp, reopen_object);
900 	ATF_TP_ADD_TC(tp, readonly_mmap_write);
901 	ATF_TP_ADD_TC(tp, open_after_link);
902 	ATF_TP_ADD_TC(tp, open_invalid_path);
903 	ATF_TP_ADD_TC(tp, open_write_only);
904 	ATF_TP_ADD_TC(tp, open_extra_flags);
905 	ATF_TP_ADD_TC(tp, open_anon);
906 	ATF_TP_ADD_TC(tp, open_anon_readonly);
907 	ATF_TP_ADD_TC(tp, open_bad_path_pointer);
908 	ATF_TP_ADD_TC(tp, open_path_too_long);
909 	ATF_TP_ADD_TC(tp, open_nonexisting_object);
910 	ATF_TP_ADD_TC(tp, open_create_existing_object);
911 	ATF_TP_ADD_TC(tp, shm_functionality_across_fork);
912 	ATF_TP_ADD_TC(tp, trunc_resets_object);
913 	ATF_TP_ADD_TC(tp, unlink_bad_path_pointer);
914 	ATF_TP_ADD_TC(tp, unlink_path_too_long);
915 	ATF_TP_ADD_TC(tp, object_resize);
916 	ATF_TP_ADD_TC(tp, cloexec);
917 
918 	return (atf_no_error());
919 }
920