xref: /freebsd/tests/sys/posixshm/posixshm_test.c (revision 8bcb0991864975618c09697b1aca10683346d9f0)
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 	gen_test_path2();
236 	rc = shm_rename(test_path, test_path2, 0);
237 	if (rc != -1)
238 		atf_tc_fail("shm_rename of nonexisting shm succeeded unexpectedly");
239 
240 	if (errno != ENOENT)
241 		atf_tc_fail("Expected ENOENT to rename of nonexistent shm; got %d",
242 		    errno);
243 }
244 
245 ATF_TC_WITHOUT_HEAD(rename_to_anon);
246 ATF_TC_BODY(rename_to_anon, tc)
247 {
248 	int rc;
249 
250 	gen_test_path();
251 	rc = shm_rename(test_path, SHM_ANON, 0);
252 	if (rc != -1)
253 		atf_tc_fail("shm_rename to SHM_ANON succeeded unexpectedly");
254 }
255 
256 ATF_TC_WITHOUT_HEAD(rename_to_replace);
257 ATF_TC_BODY(rename_to_replace, tc)
258 {
259 	char expected_value;
260 	int fd;
261 	int fd2;
262 
263 	// Some contents we can verify later
264 	expected_value = 'g';
265 
266 	gen_test_path();
267 	fd = scribble_object(test_path, expected_value);
268 	close(fd);
269 
270 	// Give the other some different value so we can detect success
271 	gen_test_path2();
272 	fd2 = scribble_object(test_path2, 'h');
273 	close(fd2);
274 
275 	ATF_REQUIRE_MSG(shm_rename(test_path, test_path2, 0) == 0,
276 	    "shm_rename failed; errno=%d", errno);
277 
278 	// Read back renamed; verify contents
279 	verify_object(test_path2, expected_value);
280 }
281 
282 ATF_TC_WITHOUT_HEAD(rename_to_noreplace);
283 ATF_TC_BODY(rename_to_noreplace, tc)
284 {
285 	char expected_value_from;
286 	char expected_value_to;
287 	int fd_from;
288 	int fd_to;
289 	int rc;
290 
291 	// Some contents we can verify later
292 	expected_value_from = 'g';
293 	gen_test_path();
294 	fd_from = scribble_object(test_path, expected_value_from);
295 	close(fd_from);
296 
297 	// Give the other some different value so we can detect success
298 	expected_value_to = 'h';
299 	gen_test_path2();
300 	fd_to = scribble_object(test_path2, expected_value_to);
301 	close(fd_to);
302 
303 	rc = shm_rename(test_path, test_path2, SHM_RENAME_NOREPLACE);
304 	ATF_REQUIRE_MSG((rc == -1) && (errno == EEXIST),
305 	    "shm_rename didn't fail as expected; errno: %d; return: %d", errno,
306 	    rc);
307 
308 	// Read back renamed; verify contents
309 	verify_object(test_path2, expected_value_to);
310 }
311 
312 ATF_TC_WITHOUT_HEAD(rename_to_exchange);
313 ATF_TC_BODY(rename_to_exchange, tc)
314 {
315 	char expected_value_from;
316 	char expected_value_to;
317 	int fd_from;
318 	int fd_to;
319 
320 	// Some contents we can verify later
321 	expected_value_from = 'g';
322 	gen_test_path();
323 	fd_from = scribble_object(test_path, expected_value_from);
324 	close(fd_from);
325 
326 	// Give the other some different value so we can detect success
327 	expected_value_to = 'h';
328 	gen_test_path2();
329 	fd_to = scribble_object(test_path2, expected_value_to);
330 	close(fd_to);
331 
332 	ATF_REQUIRE_MSG(shm_rename(test_path, test_path2,
333 	    SHM_RENAME_EXCHANGE) == 0,
334 	    "shm_rename failed; errno=%d", errno);
335 
336 	// Read back renamed; verify contents
337 	verify_object(test_path, expected_value_to);
338 	verify_object(test_path2, expected_value_from);
339 }
340 
341 ATF_TC_WITHOUT_HEAD(rename_to_exchange_nonexisting);
342 ATF_TC_BODY(rename_to_exchange_nonexisting, tc)
343 {
344 	char expected_value_from;
345 	int fd_from;
346 
347 	// Some contents we can verify later
348 	expected_value_from = 'g';
349 	gen_test_path();
350 	fd_from = scribble_object(test_path, expected_value_from);
351 	close(fd_from);
352 
353 	gen_test_path2();
354 
355 	ATF_REQUIRE_MSG(shm_rename(test_path, test_path2,
356 	    SHM_RENAME_EXCHANGE) == 0,
357 	    "shm_rename failed; errno=%d", errno);
358 
359 	// Read back renamed; verify contents
360 	verify_object(test_path2, expected_value_from);
361 }
362 
363 ATF_TC_WITHOUT_HEAD(rename_to_self);
364 ATF_TC_BODY(rename_to_self, tc)
365 {
366 	int fd;
367 	char expected_value;
368 
369 	expected_value = 't';
370 
371 	gen_test_path();
372 	fd = scribble_object(test_path, expected_value);
373 	close(fd);
374 
375 	ATF_REQUIRE_MSG(shm_rename(test_path, test_path, 0) == 0,
376 	    "shm_rename failed; errno=%d", errno);
377 
378 	verify_object(test_path, expected_value);
379 }
380 
381 ATF_TC_WITHOUT_HEAD(rename_bad_flag);
382 ATF_TC_BODY(rename_bad_flag, tc)
383 {
384 	int fd;
385 	int rc;
386 
387 	/* Make sure we don't fail out due to ENOENT */
388 	gen_test_path();
389 	gen_test_path2();
390 	fd = scribble_object(test_path, 'd');
391 	close(fd);
392 	fd = scribble_object(test_path2, 'd');
393 	close(fd);
394 
395 	/*
396 	 * Note: if we end up with enough flags that we use all the bits,
397 	 * then remove this test completely.
398 	 */
399 	rc = shm_rename(test_path, test_path2, INT_MIN);
400 	ATF_REQUIRE_MSG((rc == -1) && (errno == EINVAL),
401 	    "shm_rename should have failed with EINVAL; got: return=%d, "
402 	    "errno=%d", rc, errno);
403 }
404 
405 ATF_TC_WITHOUT_HEAD(reopen_object);
406 ATF_TC_BODY(reopen_object, tc)
407 {
408 	char *page;
409 	int fd, pagesize;
410 
411 	ATF_REQUIRE(0 < (pagesize = getpagesize()));
412 
413 	gen_test_path();
414 	fd = scribble_object(test_path, '1');
415 	close(fd);
416 
417 	fd = shm_open(test_path, O_RDONLY, 0777);
418 	if (fd < 0)
419 		atf_tc_fail("shm_open(2) failed; errno=%d", errno);
420 
421 	page = mmap(0, pagesize, PROT_READ, MAP_SHARED, fd, 0);
422 	if (page == MAP_FAILED)
423 		atf_tc_fail("mmap(2) failed; errno=%d", errno);
424 
425 	if (page[0] != '1')
426 		atf_tc_fail("missing data ('%c' != '1')", page[0]);
427 
428 	ATF_REQUIRE_MSG(munmap(page, pagesize) == 0, "munmap failed; errno=%d",
429 	    errno);
430 	close(fd);
431 	ATF_REQUIRE_MSG(shm_unlink(test_path) != -1,
432 	    "shm_unlink failed; errno=%d", errno);
433 }
434 
435 ATF_TC_WITHOUT_HEAD(readonly_mmap_write);
436 ATF_TC_BODY(readonly_mmap_write, tc)
437 {
438 	char *page;
439 	int fd, pagesize;
440 
441 	ATF_REQUIRE(0 < (pagesize = getpagesize()));
442 
443 	gen_test_path();
444 
445 	fd = shm_open(test_path, O_RDONLY | O_CREAT, 0777);
446 	ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno);
447 
448 	/* PROT_WRITE should fail with EACCES. */
449 	page = mmap(0, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
450 	if (page != MAP_FAILED)
451 		atf_tc_fail("mmap(PROT_WRITE) succeeded unexpectedly");
452 
453 	if (errno != EACCES)
454 		atf_tc_fail("mmap(PROT_WRITE) didn't fail with EACCES; "
455 		    "errno=%d", errno);
456 
457 	close(fd);
458 	ATF_REQUIRE_MSG(shm_unlink(test_path) != -1,
459 	    "shm_unlink failed; errno=%d", errno);
460 }
461 
462 ATF_TC_WITHOUT_HEAD(open_after_link);
463 ATF_TC_BODY(open_after_link, tc)
464 {
465 	int fd;
466 
467 	gen_test_path();
468 
469 	fd = shm_open(test_path, O_RDONLY | O_CREAT, 0777);
470 	ATF_REQUIRE_MSG(fd >= 0, "shm_open(1) failed; errno=%d", errno);
471 	close(fd);
472 
473 	ATF_REQUIRE_MSG(shm_unlink(test_path) != -1, "shm_unlink failed: %d",
474 	    errno);
475 
476 	shm_open_should_fail(test_path, O_RDONLY, 0777, ENOENT);
477 }
478 
479 ATF_TC_WITHOUT_HEAD(open_invalid_path);
480 ATF_TC_BODY(open_invalid_path, tc)
481 {
482 
483 	shm_open_should_fail("blah", O_RDONLY, 0777, EINVAL);
484 }
485 
486 ATF_TC_WITHOUT_HEAD(open_write_only);
487 ATF_TC_BODY(open_write_only, tc)
488 {
489 
490 	gen_test_path();
491 
492 	shm_open_should_fail(test_path, O_WRONLY, 0777, EINVAL);
493 }
494 
495 ATF_TC_WITHOUT_HEAD(open_extra_flags);
496 ATF_TC_BODY(open_extra_flags, tc)
497 {
498 
499 	gen_test_path();
500 
501 	shm_open_should_fail(test_path, O_RDONLY | O_DIRECT, 0777, EINVAL);
502 }
503 
504 ATF_TC_WITHOUT_HEAD(open_anon);
505 ATF_TC_BODY(open_anon, tc)
506 {
507 	int fd;
508 
509 	fd = shm_open(SHM_ANON, O_RDWR, 0777);
510 	ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno);
511 	close(fd);
512 }
513 
514 ATF_TC_WITHOUT_HEAD(open_anon_readonly);
515 ATF_TC_BODY(open_anon_readonly, tc)
516 {
517 
518 	shm_open_should_fail(SHM_ANON, O_RDONLY, 0777, EINVAL);
519 }
520 
521 ATF_TC_WITHOUT_HEAD(open_bad_path_pointer);
522 ATF_TC_BODY(open_bad_path_pointer, tc)
523 {
524 
525 	shm_open_should_fail((char *)1024, O_RDONLY, 0777, EFAULT);
526 }
527 
528 ATF_TC_WITHOUT_HEAD(open_path_too_long);
529 ATF_TC_BODY(open_path_too_long, tc)
530 {
531 	char *page;
532 
533 	page = malloc(MAXPATHLEN + 1);
534 	memset(page, 'a', MAXPATHLEN);
535 	page[MAXPATHLEN] = '\0';
536 	shm_open_should_fail(page, O_RDONLY, 0777, ENAMETOOLONG);
537 	free(page);
538 }
539 
540 ATF_TC_WITHOUT_HEAD(open_nonexisting_object);
541 ATF_TC_BODY(open_nonexisting_object, tc)
542 {
543 
544 	shm_open_should_fail("/notreallythere", O_RDONLY, 0777, ENOENT);
545 }
546 
547 ATF_TC_WITHOUT_HEAD(open_create_existing_object);
548 ATF_TC_BODY(open_create_existing_object, tc)
549 {
550 	int fd;
551 
552 	gen_test_path();
553 
554 	fd = shm_open(test_path, O_RDONLY|O_CREAT, 0777);
555 	ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno);
556 	close(fd);
557 
558 	shm_open_should_fail(test_path, O_RDONLY|O_CREAT|O_EXCL,
559 	    0777, EEXIST);
560 
561 	ATF_REQUIRE_MSG(shm_unlink(test_path) != -1,
562 	    "shm_unlink failed; errno=%d", errno);
563 }
564 
565 ATF_TC_WITHOUT_HEAD(trunc_resets_object);
566 ATF_TC_BODY(trunc_resets_object, tc)
567 {
568 	struct stat sb;
569 	int fd;
570 
571 	gen_test_path();
572 
573 	/* Create object and set size to 1024. */
574 	fd = shm_open(test_path, O_RDWR | O_CREAT, 0777);
575 	ATF_REQUIRE_MSG(fd >= 0, "shm_open(1) failed; errno=%d", errno);
576 	ATF_REQUIRE_MSG(ftruncate(fd, 1024) != -1,
577 	    "ftruncate failed; errno=%d", errno);
578 	ATF_REQUIRE_MSG(fstat(fd, &sb) != -1,
579 	    "fstat(1) failed; errno=%d", errno);
580 	ATF_REQUIRE_MSG(sb.st_size == 1024, "size %d != 1024", (int)sb.st_size);
581 	close(fd);
582 
583 	/* Open with O_TRUNC which should reset size to 0. */
584 	fd = shm_open(test_path, O_RDWR | O_TRUNC, 0777);
585 	ATF_REQUIRE_MSG(fd >= 0, "shm_open(2) failed; errno=%d", errno);
586 	ATF_REQUIRE_MSG(fstat(fd, &sb) != -1,
587 	    "fstat(2) failed; errno=%d", errno);
588 	ATF_REQUIRE_MSG(sb.st_size == 0,
589 	    "size was not 0 after truncation: %d", (int)sb.st_size);
590 	close(fd);
591 	ATF_REQUIRE_MSG(shm_unlink(test_path) != -1,
592 	    "shm_unlink failed; errno=%d", errno);
593 }
594 
595 ATF_TC_WITHOUT_HEAD(unlink_bad_path_pointer);
596 ATF_TC_BODY(unlink_bad_path_pointer, tc)
597 {
598 
599 	shm_unlink_should_fail((char *)1024, EFAULT);
600 }
601 
602 ATF_TC_WITHOUT_HEAD(unlink_path_too_long);
603 ATF_TC_BODY(unlink_path_too_long, tc)
604 {
605 	char *page;
606 
607 	page = malloc(MAXPATHLEN + 1);
608 	memset(page, 'a', MAXPATHLEN);
609 	page[MAXPATHLEN] = '\0';
610 	shm_unlink_should_fail(page, ENAMETOOLONG);
611 	free(page);
612 }
613 
614 ATF_TC_WITHOUT_HEAD(object_resize);
615 ATF_TC_BODY(object_resize, tc)
616 {
617 	pid_t pid;
618 	struct stat sb;
619 	char *page;
620 	int fd, pagesize, status;
621 
622 	ATF_REQUIRE(0 < (pagesize = getpagesize()));
623 
624 	/* Start off with a size of a single page. */
625 	fd = shm_open(SHM_ANON, O_CREAT|O_RDWR, 0777);
626 	if (fd < 0)
627 		atf_tc_fail("shm_open failed; errno=%d", errno);
628 
629 	if (ftruncate(fd, pagesize) < 0)
630 		atf_tc_fail("ftruncate(1) failed; errno=%d", errno);
631 
632 	if (fstat(fd, &sb) < 0)
633 		atf_tc_fail("fstat(1) failed; errno=%d", errno);
634 
635 	if (sb.st_size != pagesize)
636 		atf_tc_fail("first resize failed (%d != %d)",
637 		    (int)sb.st_size, pagesize);
638 
639 	/* Write a '1' to the first byte. */
640 	page = mmap(0, pagesize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
641 	if (page == MAP_FAILED)
642 		atf_tc_fail("mmap(1)");
643 
644 	page[0] = '1';
645 
646 	ATF_REQUIRE_MSG(munmap(page, pagesize) == 0, "munmap failed; errno=%d",
647 	    errno);
648 
649 	/* Grow the object to 2 pages. */
650 	if (ftruncate(fd, pagesize * 2) < 0)
651 		atf_tc_fail("ftruncate(2) failed; errno=%d", errno);
652 
653 	if (fstat(fd, &sb) < 0)
654 		atf_tc_fail("fstat(2) failed; errno=%d", errno);
655 
656 	if (sb.st_size != pagesize * 2)
657 		atf_tc_fail("second resize failed (%d != %d)",
658 		    (int)sb.st_size, pagesize * 2);
659 
660 	/* Check for '1' at the first byte. */
661 	page = mmap(0, pagesize * 2, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
662 	if (page == MAP_FAILED)
663 		atf_tc_fail("mmap(2) failed; errno=%d", errno);
664 
665 	if (page[0] != '1')
666 		atf_tc_fail("'%c' != '1'", page[0]);
667 
668 	/* Write a '2' at the start of the second page. */
669 	page[pagesize] = '2';
670 
671 	/* Shrink the object back to 1 page. */
672 	if (ftruncate(fd, pagesize) < 0)
673 		atf_tc_fail("ftruncate(3) failed; errno=%d", errno);
674 
675 	if (fstat(fd, &sb) < 0)
676 		atf_tc_fail("fstat(3) failed; errno=%d", errno);
677 
678 	if (sb.st_size != pagesize)
679 		atf_tc_fail("third resize failed (%d != %d)",
680 		    (int)sb.st_size, pagesize);
681 
682 	/*
683 	 * Fork a child process to make sure the second page is no
684 	 * longer valid.
685 	 */
686 	pid = fork();
687 	if (pid == -1)
688 		atf_tc_fail("fork failed; errno=%d", errno);
689 
690 	if (pid == 0) {
691 		struct rlimit lim;
692 		char c;
693 
694 		/* Don't generate a core dump. */
695 		ATF_REQUIRE(getrlimit(RLIMIT_CORE, &lim) == 0);
696 		lim.rlim_cur = 0;
697 		ATF_REQUIRE(setrlimit(RLIMIT_CORE, &lim) == 0);
698 
699 		/*
700 		 * The previous ftruncate(2) shrunk the backing object
701 		 * so that this address is no longer valid, so reading
702 		 * from it should trigger a SIGBUS.
703 		 */
704 		c = page[pagesize];
705 		fprintf(stderr, "child: page 1: '%c'\n", c);
706 		exit(0);
707 	}
708 
709 	if (wait(&status) < 0)
710 		atf_tc_fail("wait failed; errno=%d", errno);
711 
712 	if (!WIFSIGNALED(status) || WTERMSIG(status) != SIGBUS)
713 		atf_tc_fail("child terminated with status %x", status);
714 
715 	/* Grow the object back to 2 pages. */
716 	if (ftruncate(fd, pagesize * 2) < 0)
717 		atf_tc_fail("ftruncate(2) failed; errno=%d", errno);
718 
719 	if (fstat(fd, &sb) < 0)
720 		atf_tc_fail("fstat(2) failed; errno=%d", errno);
721 
722 	if (sb.st_size != pagesize * 2)
723 		atf_tc_fail("fourth resize failed (%d != %d)",
724 		    (int)sb.st_size, pagesize);
725 
726 	/*
727 	 * Note that the mapping at 'page' for the second page is
728 	 * still valid, and now that the shm object has been grown
729 	 * back up to 2 pages, there is now memory backing this page
730 	 * so the read will work.  However, the data should be zero
731 	 * rather than '2' as the old data was thrown away when the
732 	 * object was shrunk and the new pages when an object are
733 	 * grown are zero-filled.
734 	 */
735 	if (page[pagesize] != 0)
736 		atf_tc_fail("invalid data at %d: %x != 0",
737 		    pagesize, (int)page[pagesize]);
738 
739 	close(fd);
740 }
741 
742 /* Signal handler which does nothing. */
743 static void
744 ignoreit(int sig __unused)
745 {
746 	;
747 }
748 
749 ATF_TC_WITHOUT_HEAD(shm_functionality_across_fork);
750 ATF_TC_BODY(shm_functionality_across_fork, tc)
751 {
752 	char *cp, c;
753 	int error, desc, rv;
754 	long scval;
755 	sigset_t ss;
756 	struct sigaction sa;
757 	void *region;
758 	size_t i, psize;
759 
760 #ifndef _POSIX_SHARED_MEMORY_OBJECTS
761 	printf("_POSIX_SHARED_MEMORY_OBJECTS is undefined\n");
762 #else
763 	printf("_POSIX_SHARED_MEMORY_OBJECTS is defined as %ld\n",
764 	       (long)_POSIX_SHARED_MEMORY_OBJECTS - 0);
765 	if (_POSIX_SHARED_MEMORY_OBJECTS - 0 == -1)
766 		printf("***Indicates this feature may be unsupported!\n");
767 #endif
768 	errno = 0;
769 	scval = sysconf(_SC_SHARED_MEMORY_OBJECTS);
770 	if (scval == -1 && errno != 0) {
771 		atf_tc_fail("sysconf(_SC_SHARED_MEMORY_OBJECTS) failed; "
772 		    "errno=%d", errno);
773 	} else {
774 		printf("sysconf(_SC_SHARED_MEMORY_OBJECTS) returns %ld\n",
775 		       scval);
776 		if (scval == -1)
777 			printf("***Indicates this feature is unsupported!\n");
778 	}
779 
780 	errno = 0;
781 	scval = sysconf(_SC_PAGESIZE);
782 	if (scval == -1 && errno != 0) {
783 		atf_tc_fail("sysconf(_SC_PAGESIZE) failed; errno=%d", errno);
784 	} else if (scval <= 0) {
785 		fprintf(stderr, "bogus return from sysconf(_SC_PAGESIZE): %ld",
786 		    scval);
787 		psize = 4096;
788 	} else {
789 		printf("sysconf(_SC_PAGESIZE) returns %ld\n", scval);
790 		psize = scval;
791 	}
792 
793 	gen_test_path();
794 	desc = shm_open(test_path, O_EXCL | O_CREAT | O_RDWR, 0600);
795 
796 	ATF_REQUIRE_MSG(desc >= 0, "shm_open failed; errno=%d", errno);
797 	ATF_REQUIRE_MSG(shm_unlink(test_path) == 0,
798 	    "shm_unlink failed; errno=%d", errno);
799 	ATF_REQUIRE_MSG(ftruncate(desc, (off_t)psize) != -1,
800 	    "ftruncate failed; errno=%d", errno);
801 
802 	region = mmap(NULL, psize, PROT_READ | PROT_WRITE, MAP_SHARED, desc, 0);
803 	ATF_REQUIRE_MSG(region != MAP_FAILED, "mmap failed; errno=%d", errno);
804 	memset(region, '\377', psize);
805 
806 	sa.sa_flags = 0;
807 	sa.sa_handler = ignoreit;
808 	sigemptyset(&sa.sa_mask);
809 	ATF_REQUIRE_MSG(sigaction(SIGUSR1, &sa, (struct sigaction *)0) == 0,
810 	    "sigaction failed; errno=%d", errno);
811 
812 	sigemptyset(&ss);
813 	sigaddset(&ss, SIGUSR1);
814 	ATF_REQUIRE_MSG(sigprocmask(SIG_BLOCK, &ss, (sigset_t *)0) == 0,
815 	    "sigprocmask failed; errno=%d", errno);
816 
817 	rv = fork();
818 	ATF_REQUIRE_MSG(rv != -1, "fork failed; errno=%d", errno);
819 	if (rv == 0) {
820 		sigemptyset(&ss);
821 		sigsuspend(&ss);
822 
823 		for (cp = region; cp < (char *)region + psize; cp++) {
824 			if (*cp != '\151')
825 				_exit(1);
826 		}
827 		if (lseek(desc, 0, SEEK_SET) == -1)
828 			_exit(1);
829 		for (i = 0; i < psize; i++) {
830 			error = read(desc, &c, 1);
831 			if (c != '\151')
832 				_exit(1);
833 		}
834 		_exit(0);
835 	} else {
836 		int status;
837 
838 		memset(region, '\151', psize - 2);
839 		error = pwrite(desc, region, 2, psize - 2);
840 		if (error != 2) {
841 			if (error >= 0)
842 				atf_tc_fail("short write; %d bytes written",
843 				    error);
844 			else
845 				atf_tc_fail("shmfd write");
846 		}
847 		kill(rv, SIGUSR1);
848 		waitpid(rv, &status, 0);
849 
850 		if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
851 			printf("Functionality test successful\n");
852 		} else if (WIFEXITED(status)) {
853 			atf_tc_fail("Child process exited with status %d",
854 			    WEXITSTATUS(status));
855 		} else {
856 			atf_tc_fail("Child process terminated with %s",
857 			    strsignal(WTERMSIG(status)));
858 		}
859 	}
860 
861 	ATF_REQUIRE_MSG(munmap(region, psize) == 0, "munmap failed; errno=%d",
862 	    errno);
863 	shm_unlink(test_path);
864 }
865 
866 ATF_TC_WITHOUT_HEAD(cloexec);
867 ATF_TC_BODY(cloexec, tc)
868 {
869 	int fd;
870 
871 	gen_test_path();
872 
873 	/* shm_open(2) is required to set FD_CLOEXEC */
874 	fd = shm_open(SHM_ANON, O_RDWR, 0777);
875 	ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno);
876 	ATF_REQUIRE((fcntl(fd, F_GETFD) & FD_CLOEXEC) != 0);
877 	close(fd);
878 
879 	/* Also make sure that named shm is correct */
880 	fd = shm_open(test_path, O_CREAT | O_RDWR, 0600);
881 	ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno);
882 	ATF_REQUIRE((fcntl(fd, F_GETFD) & FD_CLOEXEC) != 0);
883 	close(fd);
884 }
885 
886 ATF_TC_WITHOUT_HEAD(mode);
887 ATF_TC_BODY(mode, tc)
888 {
889 	struct stat st;
890 	int fd;
891 	mode_t restore_mask;
892 
893 	gen_test_path();
894 
895 	/* Remove inhibitions from umask */
896 	restore_mask = umask(0);
897 	fd = shm_open(test_path, O_CREAT | O_RDWR, 0600);
898 	ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno);
899 	ATF_REQUIRE(fstat(fd, &st) == 0);
900 	ATF_REQUIRE((st.st_mode & ACCESSPERMS) == 0600);
901 	close(fd);
902 	ATF_REQUIRE(shm_unlink(test_path) == 0);
903 
904 	fd = shm_open(test_path, O_CREAT | O_RDWR, 0660);
905 	ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno);
906 	ATF_REQUIRE(fstat(fd, &st) == 0);
907 	ATF_REQUIRE((st.st_mode & ACCESSPERMS) == 0660);
908 	close(fd);
909 	ATF_REQUIRE(shm_unlink(test_path) == 0);
910 
911 	fd = shm_open(test_path, O_CREAT | O_RDWR, 0666);
912 	ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno);
913 	ATF_REQUIRE(fstat(fd, &st) == 0);
914 	ATF_REQUIRE((st.st_mode & ACCESSPERMS) == 0666);
915 	close(fd);
916 	ATF_REQUIRE(shm_unlink(test_path) == 0);
917 
918 	umask(restore_mask);
919 }
920 
921 ATF_TC_WITHOUT_HEAD(fallocate);
922 ATF_TC_BODY(fallocate, tc)
923 {
924 	struct stat st;
925 	int error, fd, sz;
926 
927 	/*
928 	 * Primitive test case for posix_fallocate with shmd.  Effectively
929 	 * expected to work like a smarter ftruncate that will grow the region
930 	 * as needed in a race-free way.
931 	 */
932 	fd = shm_open(SHM_ANON, O_RDWR, 0666);
933 	ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno);
934 	/* Set the initial size. */
935 	sz = 32;
936 	ATF_REQUIRE(ftruncate(fd, sz) == 0);
937 
938 	/* Now grow it. */
939 	error = 0;
940 	sz *= 2;
941 	ATF_REQUIRE_MSG((error = posix_fallocate(fd, 0, sz)) == 0,
942 	    "posix_fallocate failed; error=%d", error);
943 	ATF_REQUIRE(fstat(fd, &st) == 0);
944 	ATF_REQUIRE(st.st_size == sz);
945 	/* Attempt to shrink it; should succeed, but not change the size. */
946 	ATF_REQUIRE_MSG((error = posix_fallocate(fd, 0, sz / 2)) == 0,
947 	    "posix_fallocate failed; error=%d", error);
948 	ATF_REQUIRE(fstat(fd, &st) == 0);
949 	ATF_REQUIRE(st.st_size == sz);
950 	/* Grow it using an offset of sz and len of sz. */
951 	ATF_REQUIRE_MSG((error = posix_fallocate(fd, sz, sz)) == 0,
952 	    "posix_fallocate failed; error=%d", error);
953 	ATF_REQUIRE(fstat(fd, &st) == 0);
954 	ATF_REQUIRE(st.st_size == (sz * 2));
955 
956 	close(fd);
957 }
958 
959 ATF_TP_ADD_TCS(tp)
960 {
961 
962 	ATF_TP_ADD_TC(tp, remap_object);
963 	ATF_TP_ADD_TC(tp, rename_from_anon);
964 	ATF_TP_ADD_TC(tp, rename_bad_path_pointer);
965 	ATF_TP_ADD_TC(tp, rename_from_nonexisting);
966 	ATF_TP_ADD_TC(tp, rename_to_anon);
967 	ATF_TP_ADD_TC(tp, rename_to_replace);
968 	ATF_TP_ADD_TC(tp, rename_to_noreplace);
969 	ATF_TP_ADD_TC(tp, rename_to_exchange);
970 	ATF_TP_ADD_TC(tp, rename_to_exchange_nonexisting);
971 	ATF_TP_ADD_TC(tp, rename_to_self);
972 	ATF_TP_ADD_TC(tp, rename_bad_flag);
973 	ATF_TP_ADD_TC(tp, reopen_object);
974 	ATF_TP_ADD_TC(tp, readonly_mmap_write);
975 	ATF_TP_ADD_TC(tp, open_after_link);
976 	ATF_TP_ADD_TC(tp, open_invalid_path);
977 	ATF_TP_ADD_TC(tp, open_write_only);
978 	ATF_TP_ADD_TC(tp, open_extra_flags);
979 	ATF_TP_ADD_TC(tp, open_anon);
980 	ATF_TP_ADD_TC(tp, open_anon_readonly);
981 	ATF_TP_ADD_TC(tp, open_bad_path_pointer);
982 	ATF_TP_ADD_TC(tp, open_path_too_long);
983 	ATF_TP_ADD_TC(tp, open_nonexisting_object);
984 	ATF_TP_ADD_TC(tp, open_create_existing_object);
985 	ATF_TP_ADD_TC(tp, shm_functionality_across_fork);
986 	ATF_TP_ADD_TC(tp, trunc_resets_object);
987 	ATF_TP_ADD_TC(tp, unlink_bad_path_pointer);
988 	ATF_TP_ADD_TC(tp, unlink_path_too_long);
989 	ATF_TP_ADD_TC(tp, object_resize);
990 	ATF_TP_ADD_TC(tp, cloexec);
991 	ATF_TP_ADD_TC(tp, mode);
992 	ATF_TP_ADD_TC(tp, fallocate);
993 
994 	return (atf_no_error());
995 }
996