posixshm_test.c revision 289441
1175383Sjhb/*-
2175383Sjhb * Copyright (c) 2006 Robert N. M. Watson
3175383Sjhb * All rights reserved.
4175383Sjhb *
5175383Sjhb * Redistribution and use in source and binary forms, with or without
6175383Sjhb * modification, are permitted provided that the following conditions
7175383Sjhb * are met:
8175383Sjhb * 1. Redistributions of source code must retain the above copyright
9175383Sjhb *    notice, this list of conditions and the following disclaimer.
10175383Sjhb * 2. Redistributions in binary form must reproduce the above copyright
11175383Sjhb *    notice, this list of conditions and the following disclaimer in the
12175383Sjhb *    documentation and/or other materials provided with the distribution.
13175383Sjhb *
14175383Sjhb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15175383Sjhb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16175383Sjhb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17175383Sjhb * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18175383Sjhb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19175383Sjhb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20175383Sjhb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21175383Sjhb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22175383Sjhb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23175383Sjhb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24175383Sjhb * SUCH DAMAGE.
25175383Sjhb */
26175383Sjhb
27175383Sjhb#include <sys/cdefs.h>
28175383Sjhb__FBSDID("$FreeBSD: head/tests/sys/posixshm/posixshm_test.c 289441 2015-10-17 04:32:21Z ngie $");
29175383Sjhb
30175383Sjhb#include <sys/param.h>
31175383Sjhb#include <sys/mman.h>
32175383Sjhb#include <sys/resource.h>
33175383Sjhb#include <sys/stat.h>
34175383Sjhb#include <sys/syscall.h>
35175383Sjhb#include <sys/wait.h>
36175383Sjhb
37175383Sjhb#include <errno.h>
38175383Sjhb#include <fcntl.h>
39289437Sngie#include <signal.h>
40175383Sjhb#include <stdio.h>
41175383Sjhb#include <stdlib.h>
42175383Sjhb#include <string.h>
43175383Sjhb#include <unistd.h>
44175383Sjhb
45289437Sngie#include <atf-c.h>
46175383Sjhb
47289437Sngie#define	TEST_PATH_LEN	256
48289437Sngiestatic char test_path[TEST_PATH_LEN];
49175383Sjhb
50289437Sngiestatic void
51289437Sngiegen_test_path(void)
52289437Sngie{
53289437Sngie	char *tmpdir = getenv("TMPDIR");
54289437Sngie
55289437Sngie	if (tmpdir == NULL)
56289437Sngie		tmpdir = "/tmp";
57289437Sngie
58289437Sngie	snprintf(test_path, sizeof(test_path), "%s/tmp.XXXXXX", tmpdir);
59289437Sngie	test_path[sizeof(test_path) - 1] = '\0';
60289437Sngie	ATF_REQUIRE_MSG(mkstemp(test_path) != -1,
61289437Sngie	    "mkstemp failed; errno=%d", errno);
62289437Sngie	ATF_REQUIRE_MSG(unlink(test_path) == 0,
63289437Sngie	    "unlink failed; errno=%d", errno);
64289437Sngie}
65289437Sngie
66175383Sjhb/*
67175383Sjhb * Attempt a shm_open() that should fail with an expected error of 'error'.
68175383Sjhb */
69175383Sjhbstatic void
70175383Sjhbshm_open_should_fail(const char *path, int flags, mode_t mode, int error)
71175383Sjhb{
72175383Sjhb	int fd;
73175383Sjhb
74175383Sjhb	fd = shm_open(path, flags, mode);
75289437Sngie	ATF_CHECK_MSG(fd == -1, "shm_open didn't fail");
76289437Sngie	ATF_CHECK_MSG(error == errno,
77289437Sngie	    "shm_open didn't fail with expected errno; errno=%d; expected "
78289437Sngie	    "errno=%d", errno, error);
79175383Sjhb}
80175383Sjhb
81175383Sjhb/*
82175383Sjhb * Attempt a shm_unlink() that should fail with an expected error of 'error'.
83175383Sjhb */
84175383Sjhbstatic void
85175383Sjhbshm_unlink_should_fail(const char *path, int error)
86175383Sjhb{
87175383Sjhb
88289437Sngie	ATF_CHECK_MSG(shm_unlink(path) == -1, "shm_unlink didn't fail");
89289437Sngie	ATF_CHECK_MSG(error == errno,
90289437Sngie	    "shm_unlink didn't fail with expected errno; errno=%d; expected "
91289437Sngie	    "errno=%d", errno, error);
92175383Sjhb}
93175383Sjhb
94175383Sjhb/*
95175383Sjhb * Open the test object and write '1' to the first byte.  Returns valid fd
96175383Sjhb * on success and -1 on failure.
97175383Sjhb */
98175383Sjhbstatic int
99175383Sjhbscribble_object(void)
100175383Sjhb{
101175383Sjhb	char *page;
102175383Sjhb	int fd;
103175383Sjhb
104289437Sngie	gen_test_path();
105289437Sngie
106289437Sngie	fd = shm_open(test_path, O_CREAT|O_EXCL|O_RDWR, 0777);
107175383Sjhb	if (fd < 0 && errno == EEXIST) {
108289437Sngie		if (shm_unlink(test_path) < 0)
109289437Sngie			atf_tc_fail("shm_unlink");
110289437Sngie		fd = shm_open(test_path, O_CREAT | O_EXCL | O_RDWR, 0777);
111175383Sjhb	}
112289437Sngie	if (fd < 0)
113289441Sngie		atf_tc_fail("shm_open failed; errno=%d", errno);
114289437Sngie	if (ftruncate(fd, getpagesize()) < 0)
115289441Sngie		atf_tc_fail("ftruncate failed; errno=%d", errno);
116175383Sjhb
117175383Sjhb	page = mmap(0, getpagesize(), PROT_READ | PROT_WRITE, MAP_SHARED, fd,
118175383Sjhb	    0);
119289437Sngie	if (page == MAP_FAILED)
120289441Sngie		atf_tc_fail("mmap failed; errno=%d", errno);
121175383Sjhb
122175383Sjhb	page[0] = '1';
123289437Sngie	if (munmap(page, getpagesize()) < 0)
124289441Sngie		atf_tc_fail("munmap failed; errno=%d", errno);
125175383Sjhb
126175383Sjhb	return (fd);
127175383Sjhb}
128175383Sjhb
129289437SngieATF_TC_WITHOUT_HEAD(remap_object);
130289437SngieATF_TC_BODY(remap_object, tc)
131175383Sjhb{
132175383Sjhb	char *page;
133175383Sjhb	int fd;
134175383Sjhb
135175383Sjhb	fd = scribble_object();
136175383Sjhb
137175383Sjhb	page = mmap(0, getpagesize(), PROT_READ | PROT_WRITE, MAP_SHARED, fd,
138175383Sjhb	    0);
139289441Sngie	if (page == MAP_FAILED)
140289441Sngie		atf_tc_fail("mmap(2) failed; errno=%d", errno);
141175383Sjhb
142289441Sngie	if (page[0] != '1')
143289441Sngie		atf_tc_fail("missing data ('%c' != '1')", page[0]);
144175383Sjhb
145175383Sjhb	close(fd);
146289441Sngie	if (munmap(page, getpagesize()) < 0)
147289441Sngie		atf_tc_fail("munmap failed; errno=%d", errno);
148175383Sjhb
149289441Sngie	ATF_REQUIRE_MSG(shm_unlink(test_path) != -1,
150289441Sngie	    "shm_unlink failed; errno=%d", errno);
151175383Sjhb}
152175383Sjhb
153289437SngieATF_TC_WITHOUT_HEAD(reopen_object);
154289437SngieATF_TC_BODY(reopen_object, tc)
155175383Sjhb{
156175383Sjhb	char *page;
157175383Sjhb	int fd;
158175383Sjhb
159175383Sjhb	fd = scribble_object();
160175383Sjhb	close(fd);
161175383Sjhb
162289437Sngie	fd = shm_open(test_path, O_RDONLY, 0777);
163289441Sngie	if (fd < 0)
164289441Sngie		atf_tc_fail("shm_open(2) failed; errno=%d", errno);
165289441Sngie
166175383Sjhb	page = mmap(0, getpagesize(), PROT_READ, MAP_SHARED, fd, 0);
167289441Sngie	if (page == MAP_FAILED)
168289441Sngie		atf_tc_fail("mmap(2) failed; errno=%d", errno);
169175383Sjhb
170289441Sngie	if (page[0] != '1')
171289441Sngie		atf_tc_fail("missing data ('%c' != '1')", page[0]);
172175383Sjhb
173175383Sjhb	munmap(page, getpagesize());
174175383Sjhb	close(fd);
175289441Sngie	ATF_REQUIRE_MSG(shm_unlink(test_path) != -1,
176289441Sngie	    "shm_unlink failed; errno=%d", errno);
177175383Sjhb}
178175383Sjhb
179289437SngieATF_TC_WITHOUT_HEAD(readonly_mmap_write);
180289437SngieATF_TC_BODY(readonly_mmap_write, tc)
181175383Sjhb{
182175383Sjhb	char *page;
183175383Sjhb	int fd;
184175383Sjhb
185289437Sngie	gen_test_path();
186289437Sngie
187289437Sngie	fd = shm_open(test_path, O_RDONLY | O_CREAT, 0777);
188289441Sngie	ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno);
189175383Sjhb
190175383Sjhb	/* PROT_WRITE should fail with EACCES. */
191175383Sjhb	page = mmap(0, getpagesize(), PROT_READ | PROT_WRITE, MAP_SHARED, fd,
192175383Sjhb	    0);
193289441Sngie	if (page != MAP_FAILED)
194289441Sngie		atf_tc_fail("mmap(PROT_WRITE) succeeded unexpectedly");
195175383Sjhb
196289441Sngie	if (errno != EACCES)
197289441Sngie		atf_tc_fail("mmap(PROT_WRITE) didn't fail with EACCES; "
198289441Sngie		    "errno=%d", errno);
199289441Sngie
200175383Sjhb	close(fd);
201289441Sngie	ATF_REQUIRE_MSG(shm_unlink(test_path) != -1,
202289441Sngie	    "shm_unlink failed; errno=%d", errno);
203175383Sjhb}
204175383Sjhb
205289437SngieATF_TC_WITHOUT_HEAD(open_after_link);
206289437SngieATF_TC_BODY(open_after_link, tc)
207175383Sjhb{
208175383Sjhb	int fd;
209175383Sjhb
210289437Sngie	gen_test_path();
211289437Sngie
212289437Sngie	fd = shm_open(test_path, O_RDONLY | O_CREAT, 0777);
213289441Sngie	ATF_REQUIRE_MSG(fd >= 0, "shm_open(1) failed; errno=%d", errno);
214175383Sjhb	close(fd);
215175383Sjhb
216289441Sngie	ATF_REQUIRE_MSG(shm_unlink(test_path) != -1, "shm_unlink failed: %d",
217289441Sngie	    errno);
218175383Sjhb
219289437Sngie	shm_open_should_fail(test_path, O_RDONLY, 0777, ENOENT);
220175383Sjhb}
221175383Sjhb
222289437SngieATF_TC_WITHOUT_HEAD(open_invalid_path);
223289437SngieATF_TC_BODY(open_invalid_path, tc)
224175383Sjhb{
225175383Sjhb
226175383Sjhb	shm_open_should_fail("blah", O_RDONLY, 0777, EINVAL);
227175383Sjhb}
228175383Sjhb
229289437SngieATF_TC_WITHOUT_HEAD(open_write_only);
230289437SngieATF_TC_BODY(open_write_only, tc)
231175383Sjhb{
232175383Sjhb
233289437Sngie	gen_test_path();
234289437Sngie
235289437Sngie	shm_open_should_fail(test_path, O_WRONLY, 0777, EINVAL);
236175383Sjhb}
237175383Sjhb
238289437SngieATF_TC_WITHOUT_HEAD(open_extra_flags);
239289437SngieATF_TC_BODY(open_extra_flags, tc)
240175383Sjhb{
241175383Sjhb
242289437Sngie	gen_test_path();
243289437Sngie
244289437Sngie	shm_open_should_fail(test_path, O_RDONLY | O_DIRECT, 0777, EINVAL);
245175383Sjhb}
246175383Sjhb
247289437SngieATF_TC_WITHOUT_HEAD(open_anon);
248289437SngieATF_TC_BODY(open_anon, tc)
249175383Sjhb{
250175383Sjhb	int fd;
251175383Sjhb
252175383Sjhb	fd = shm_open(SHM_ANON, O_RDWR, 0777);
253289441Sngie	ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno);
254175383Sjhb	close(fd);
255175383Sjhb}
256175383Sjhb
257289437SngieATF_TC_WITHOUT_HEAD(open_anon_readonly);
258289437SngieATF_TC_BODY(open_anon_readonly, tc)
259175383Sjhb{
260175383Sjhb
261175383Sjhb	shm_open_should_fail(SHM_ANON, O_RDONLY, 0777, EINVAL);
262175383Sjhb}
263175383Sjhb
264289437SngieATF_TC_WITHOUT_HEAD(open_bad_path_pointer);
265289437SngieATF_TC_BODY(open_bad_path_pointer, tc)
266175383Sjhb{
267175383Sjhb
268175383Sjhb	shm_open_should_fail((char *)1024, O_RDONLY, 0777, EFAULT);
269175383Sjhb}
270175383Sjhb
271289437SngieATF_TC_WITHOUT_HEAD(open_path_too_long);
272289437SngieATF_TC_BODY(open_path_too_long, tc)
273175383Sjhb{
274175383Sjhb	char *page;
275175383Sjhb
276175383Sjhb	page = malloc(MAXPATHLEN + 1);
277175383Sjhb	memset(page, 'a', MAXPATHLEN);
278175383Sjhb	page[MAXPATHLEN] = '\0';
279175383Sjhb	shm_open_should_fail(page, O_RDONLY, 0777, ENAMETOOLONG);
280175383Sjhb	free(page);
281175383Sjhb}
282175383Sjhb
283289437SngieATF_TC_WITHOUT_HEAD(open_nonexisting_object);
284289437SngieATF_TC_BODY(open_nonexisting_object, tc)
285175383Sjhb{
286175383Sjhb
287175383Sjhb	shm_open_should_fail("/notreallythere", O_RDONLY, 0777, ENOENT);
288175383Sjhb}
289175383Sjhb
290289437SngieATF_TC_WITHOUT_HEAD(open_create_existing_object);
291289437SngieATF_TC_BODY(open_create_existing_object, tc)
292175383Sjhb{
293175383Sjhb	int fd;
294175383Sjhb
295289437Sngie	gen_test_path();
296289437Sngie
297289437Sngie	fd = shm_open(test_path, O_RDONLY|O_CREAT, 0777);
298289441Sngie	ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno);
299175383Sjhb	close(fd);
300175383Sjhb
301289437Sngie	shm_open_should_fail(test_path, O_RDONLY|O_CREAT|O_EXCL,
302175383Sjhb	    0777, EEXIST);
303175383Sjhb
304289441Sngie	ATF_REQUIRE_MSG(shm_unlink(test_path) != -1,
305289441Sngie	    "shm_unlink failed; errno=%d", errno);
306175383Sjhb}
307175383Sjhb
308289437SngieATF_TC_WITHOUT_HEAD(trunc_resets_object);
309289437SngieATF_TC_BODY(trunc_resets_object, tc)
310175383Sjhb{
311175383Sjhb	struct stat sb;
312175383Sjhb	int fd;
313175383Sjhb
314289437Sngie	gen_test_path();
315289437Sngie
316175383Sjhb	/* Create object and set size to 1024. */
317289437Sngie	fd = shm_open(test_path, O_RDWR | O_CREAT, 0777);
318289441Sngie	ATF_REQUIRE_MSG(fd >= 0, "shm_open(1) failed; errno=%d", errno);
319289441Sngie	ATF_REQUIRE_MSG(ftruncate(fd, 1024) != -1,
320289441Sngie	    "ftruncate failed; errno=%d", errno);
321289441Sngie	ATF_REQUIRE_MSG(fstat(fd, &sb) != -1,
322289441Sngie	    "fstat(1) failed; errno=%d", errno);
323289441Sngie	ATF_REQUIRE_MSG(sb.st_size == 1024, "size %d != 1024", (int)sb.st_size);
324175383Sjhb	close(fd);
325175383Sjhb
326175383Sjhb	/* Open with O_TRUNC which should reset size to 0. */
327289437Sngie	fd = shm_open(test_path, O_RDWR | O_TRUNC, 0777);
328289441Sngie	ATF_REQUIRE_MSG(fd >= 0, "shm_open(2) failed; errno=%d", errno);
329289441Sngie	ATF_REQUIRE_MSG(fstat(fd, &sb) != -1,
330289441Sngie	    "fstat(2) failed; errno=%d", errno);
331289441Sngie	ATF_REQUIRE_MSG(sb.st_size == 0,
332289441Sngie	    "size was not 0 after truncation: %d", (int)sb.st_size);
333175383Sjhb	close(fd);
334289441Sngie	ATF_REQUIRE_MSG(shm_unlink(test_path) != -1,
335289441Sngie	    "shm_unlink failed; errno=%d", errno);
336175383Sjhb}
337175383Sjhb
338289437SngieATF_TC_WITHOUT_HEAD(unlink_bad_path_pointer);
339289437SngieATF_TC_BODY(unlink_bad_path_pointer, tc)
340175383Sjhb{
341175383Sjhb
342175383Sjhb	shm_unlink_should_fail((char *)1024, EFAULT);
343175383Sjhb}
344175383Sjhb
345289437SngieATF_TC_WITHOUT_HEAD(unlink_path_too_long);
346289437SngieATF_TC_BODY(unlink_path_too_long, tc)
347175383Sjhb{
348175383Sjhb	char *page;
349175383Sjhb
350175383Sjhb	page = malloc(MAXPATHLEN + 1);
351175383Sjhb	memset(page, 'a', MAXPATHLEN);
352175383Sjhb	page[MAXPATHLEN] = '\0';
353175383Sjhb	shm_unlink_should_fail(page, ENAMETOOLONG);
354175383Sjhb	free(page);
355175383Sjhb}
356175383Sjhb
357289437SngieATF_TC_WITHOUT_HEAD(object_resize);
358289437SngieATF_TC_BODY(object_resize, tc)
359175383Sjhb{
360175383Sjhb	pid_t pid;
361175383Sjhb	struct stat sb;
362289441Sngie	char err_buf[1024], *page;
363175383Sjhb	int fd, status;
364175383Sjhb
365175383Sjhb	/* Start off with a size of a single page. */
366289441Sngie	fd = shm_open(SHM_ANON, O_CREAT|O_RDWR, 0777);
367289441Sngie	if (fd < 0)
368289441Sngie		atf_tc_fail("shm_open failed; errno=%d", errno);
369175383Sjhb
370289441Sngie	if (ftruncate(fd, getpagesize()) < 0)
371289441Sngie		atf_tc_fail("ftruncate(1) failed; errno=%d", errno);
372289441Sngie
373289441Sngie	if (fstat(fd, &sb) < 0)
374289441Sngie		atf_tc_fail("fstat(1) failed; errno=%d", errno);
375289441Sngie
376289441Sngie	if (sb.st_size != getpagesize())
377289441Sngie		atf_tc_fail("first resize failed (%d != %d)",
378289441Sngie		    (int)sb.st_size, getpagesize());
379289441Sngie
380175383Sjhb	/* Write a '1' to the first byte. */
381289441Sngie	page = mmap(0, getpagesize(), PROT_READ|PROT_WRITE, MAP_SHARED, fd,
382175383Sjhb	    0);
383289441Sngie	if (page == MAP_FAILED)
384289437Sngie		atf_tc_fail("mmap(1)");
385175383Sjhb
386175383Sjhb	page[0] = '1';
387175383Sjhb
388289441Sngie	if (munmap(page, getpagesize()) < 0)
389289441Sngie		atf_tc_fail("munmap(1) failed; errno=%d", errno);
390175383Sjhb
391175383Sjhb	/* Grow the object to 2 pages. */
392289441Sngie	if (ftruncate(fd, getpagesize() * 2) < 0)
393289441Sngie		atf_tc_fail("ftruncate(2) failed; errno=%d", errno);
394175383Sjhb
395289441Sngie	if (fstat(fd, &sb) < 0)
396289441Sngie		atf_tc_fail("fstat(2) failed; errno=%d", errno);
397289441Sngie
398289441Sngie	if (sb.st_size != getpagesize() * 2)
399289441Sngie		atf_tc_fail("second resize failed (%d != %d)",
400289441Sngie		    (int)sb.st_size, getpagesize() * 2);
401289441Sngie
402175383Sjhb	/* Check for '1' at the first byte. */
403289441Sngie	page = mmap(0, getpagesize() * 2, PROT_READ|PROT_WRITE, MAP_SHARED,
404175383Sjhb	    fd, 0);
405289441Sngie	if (page == MAP_FAILED)
406289441Sngie		atf_tc_fail("mmap(2) failed; errno=%d", errno);
407175383Sjhb
408289441Sngie	if (page[0] != '1')
409289441Sngie		atf_tc_fail("'%c' != '1'", page[0]);
410175383Sjhb
411175383Sjhb	/* Write a '2' at the start of the second page. */
412175383Sjhb	page[getpagesize()] = '2';
413175383Sjhb
414175383Sjhb	/* Shrink the object back to 1 page. */
415289441Sngie	if (ftruncate(fd, getpagesize()) < 0)
416289441Sngie		atf_tc_fail("ftruncate(3) failed; errno=%d", errno);
417175383Sjhb
418289441Sngie	if (fstat(fd, &sb) < 0)
419289441Sngie		atf_tc_fail("fstat(3) failed; errno=%d", errno);
420289441Sngie
421289441Sngie	if (sb.st_size != getpagesize())
422289441Sngie		atf_tc_fail("third resize failed (%d != %d)",
423289441Sngie		    (int)sb.st_size, getpagesize());
424289441Sngie
425175383Sjhb	/*
426175383Sjhb	 * Fork a child process to make sure the second page is no
427175383Sjhb	 * longer valid.
428175383Sjhb	 */
429175383Sjhb	pid = fork();
430289441Sngie	if (pid == -1)
431289441Sngie		atf_tc_fail("fork failed; errno=%d", errno);
432175383Sjhb
433175383Sjhb	if (pid == 0) {
434175383Sjhb		struct rlimit lim;
435175383Sjhb		char c;
436175383Sjhb
437175383Sjhb		/* Don't generate a core dump. */
438175383Sjhb		getrlimit(RLIMIT_CORE, &lim);
439175383Sjhb		lim.rlim_cur = 0;
440175383Sjhb		setrlimit(RLIMIT_CORE, &lim);
441175383Sjhb
442175383Sjhb		/*
443175383Sjhb		 * The previous ftruncate(2) shrunk the backing object
444175383Sjhb		 * so that this address is no longer valid, so reading
445175383Sjhb		 * from it should trigger a SIGSEGV.
446175383Sjhb		 */
447175383Sjhb		c = page[getpagesize()];
448175383Sjhb		fprintf(stderr, "child: page 1: '%c'\n", c);
449175383Sjhb		exit(0);
450175383Sjhb	}
451289441Sngie
452289441Sngie	if (wait(&status) < 0)
453289441Sngie		atf_tc_fail("wait failed; errno=%d", errno);
454289441Sngie
455289441Sngie	if (!WIFSIGNALED(status) || WTERMSIG(status) != SIGSEGV)
456289437Sngie		atf_tc_fail("child terminated with status %x", status);
457175383Sjhb
458175383Sjhb	/* Grow the object back to 2 pages. */
459289441Sngie	if (ftruncate(fd, getpagesize() * 2) < 0)
460289441Sngie		atf_tc_fail("ftruncate(2) failed; errno=%d", errno);
461175383Sjhb
462289441Sngie	if (fstat(fd, &sb) < 0)
463289441Sngie		atf_tc_fail("fstat(2) failed; errno=%d", errno);
464289441Sngie
465289441Sngie	if (sb.st_size != getpagesize() * 2)
466289441Sngie		atf_tc_fail("fourth resize failed (%d != %d)",
467289441Sngie		    (int)sb.st_size, getpagesize());
468289441Sngie
469175383Sjhb	/*
470175383Sjhb	 * Note that the mapping at 'page' for the second page is
471175383Sjhb	 * still valid, and now that the shm object has been grown
472175383Sjhb	 * back up to 2 pages, there is now memory backing this page
473175383Sjhb	 * so the read will work.  However, the data should be zero
474175383Sjhb	 * rather than '2' as the old data was thrown away when the
475175383Sjhb	 * object was shrunk and the new pages when an object are
476175383Sjhb	 * grown are zero-filled.
477175383Sjhb	 */
478289441Sngie	if (page[getpagesize()] != 0)
479289441Sngie		atf_tc_fail("invalid data at %d: %x != 0",
480289441Sngie		    getpagesize(), (int)page[getpagesize()]);
481175383Sjhb
482175383Sjhb	close(fd);
483175383Sjhb}
484175383Sjhb
485289437Sngie/* Signal handler which does nothing. */
486289437Sngiestatic void
487289437Sngieignoreit(int sig __unused)
488175383Sjhb{
489289437Sngie	;
490289437Sngie}
491175383Sjhb
492289437SngieATF_TC_WITHOUT_HEAD(shm_functionality_across_fork);
493289437SngieATF_TC_BODY(shm_functionality_across_fork, tc)
494289437Sngie{
495289437Sngie	char *cp, c;
496289437Sngie	int error, desc, rv;
497289437Sngie	long scval;
498289437Sngie	sigset_t ss;
499289437Sngie	struct sigaction sa;
500289437Sngie	void *region;
501289437Sngie	size_t i, psize;
502289437Sngie
503289437Sngie#ifndef _POSIX_SHARED_MEMORY_OBJECTS
504289437Sngie	printf("_POSIX_SHARED_MEMORY_OBJECTS is undefined\n");
505289437Sngie#else
506289437Sngie	printf("_POSIX_SHARED_MEMORY_OBJECTS is defined as %ld\n",
507289437Sngie	       (long)_POSIX_SHARED_MEMORY_OBJECTS - 0);
508289437Sngie	if (_POSIX_SHARED_MEMORY_OBJECTS - 0 == -1)
509289437Sngie		printf("***Indicates this feature may be unsupported!\n");
510289437Sngie#endif
511289437Sngie	errno = 0;
512289437Sngie	scval = sysconf(_SC_SHARED_MEMORY_OBJECTS);
513289437Sngie	if (scval == -1 && errno != 0) {
514289437Sngie		atf_tc_fail("sysconf(_SC_SHARED_MEMORY_OBJECTS) failed; "
515289437Sngie		    "errno=%d", errno);
516289437Sngie	} else {
517289437Sngie		printf("sysconf(_SC_SHARED_MEMORY_OBJECTS) returns %ld\n",
518289437Sngie		       scval);
519289437Sngie		if (scval == -1)
520289437Sngie			printf("***Indicates this feature is unsupported!\n");
521289437Sngie	}
522289437Sngie
523289437Sngie	errno = 0;
524289437Sngie	scval = sysconf(_SC_PAGESIZE);
525289437Sngie	if (scval == -1 && errno != 0) {
526289437Sngie		atf_tc_fail("sysconf(_SC_PAGESIZE) failed; errno=%d", errno);
527289437Sngie	} else if (scval <= 0 || (size_t)psize != psize) {
528289437Sngie		fprintf(stderr, "bogus return from sysconf(_SC_PAGESIZE): %ld",
529289437Sngie		    scval);
530289437Sngie		psize = 4096;
531289437Sngie	} else {
532289437Sngie		printf("sysconf(_SC_PAGESIZE) returns %ld\n", scval);
533289437Sngie		psize = scval;
534289437Sngie	}
535289437Sngie
536289437Sngie	gen_test_path();
537289437Sngie	desc = shm_open(test_path, O_EXCL | O_CREAT | O_RDWR, 0600);
538289437Sngie
539289437Sngie	ATF_REQUIRE_MSG(desc >= 0, "shm_open failed; errno=%d", errno);
540289437Sngie	ATF_REQUIRE_MSG(shm_unlink(test_path) == 0,
541289437Sngie	    "shm_unlink failed; errno=%d", errno);
542289437Sngie	ATF_REQUIRE_MSG(ftruncate(desc, (off_t)psize) != -1,
543289437Sngie	    "ftruncate failed; errno=%d", errno);
544289437Sngie
545289437Sngie	region = mmap((void *)0, psize, PROT_READ | PROT_WRITE, MAP_SHARED,
546289437Sngie		      desc, (off_t)0);
547289437Sngie	ATF_REQUIRE_MSG(region != MAP_FAILED, "mmap failed; errno=%d", errno);
548289437Sngie	memset(region, '\377', psize);
549289437Sngie
550289437Sngie	sa.sa_flags = 0;
551289437Sngie	sa.sa_handler = ignoreit;
552289437Sngie	sigemptyset(&sa.sa_mask);
553289437Sngie	ATF_REQUIRE_MSG(sigaction(SIGUSR1, &sa, (struct sigaction *)0) == 0,
554289437Sngie	    "sigaction failed; errno=%d", errno);
555289437Sngie
556289437Sngie	sigemptyset(&ss);
557289437Sngie	sigaddset(&ss, SIGUSR1);
558289437Sngie	ATF_REQUIRE_MSG(sigprocmask(SIG_BLOCK, &ss, (sigset_t *)0) == 0,
559289437Sngie	    "sigprocmask failed; errno=%d", errno);
560289437Sngie
561289437Sngie	rv = fork();
562289437Sngie	ATF_REQUIRE_MSG(rv != -1, "fork failed; errno=%d", errno);
563289437Sngie	if (rv == 0) {
564289437Sngie		sigemptyset(&ss);
565289437Sngie		sigsuspend(&ss);
566289437Sngie
567289437Sngie		for (cp = region; cp < (char *)region + psize; cp++) {
568289437Sngie			if (*cp != '\151')
569289437Sngie				_exit(1);
570289437Sngie		}
571289437Sngie		if (lseek(desc, 0, SEEK_SET) == -1)
572289437Sngie			_exit(1);
573289437Sngie		for (i = 0; i < psize; i++) {
574289437Sngie			error = read(desc, &c, 1);
575289437Sngie			if (c != '\151')
576289437Sngie				_exit(1);
577289437Sngie		}
578289437Sngie		_exit(0);
579289437Sngie	} else {
580289437Sngie		int status;
581289437Sngie
582289437Sngie		memset(region, '\151', psize - 2);
583289437Sngie		error = pwrite(desc, region, 2, psize - 2);
584289437Sngie		if (error != 2) {
585289437Sngie			if (error >= 0)
586289437Sngie				atf_tc_fail("short write; %d bytes written",
587289437Sngie				    error);
588289437Sngie			else
589289437Sngie				atf_tc_fail("shmfd write");
590289437Sngie		}
591289437Sngie		kill(rv, SIGUSR1);
592289437Sngie		waitpid(rv, &status, 0);
593289437Sngie
594289437Sngie		if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
595289437Sngie			printf("Functionality test successful\n");
596289437Sngie		} else if (WIFEXITED(status)) {
597289437Sngie			atf_tc_fail("Child process exited with status %d",
598289437Sngie			    WEXITSTATUS(status));
599289437Sngie		} else {
600289437Sngie			atf_tc_fail("Child process terminated with %s",
601289437Sngie			    strsignal(WTERMSIG(status)));
602289437Sngie		}
603289437Sngie	}
604175383Sjhb}
605289437Sngie
606289437SngieATF_TP_ADD_TCS(tp)
607289437Sngie{
608289437Sngie
609289437Sngie	ATF_TP_ADD_TC(tp, remap_object);
610289437Sngie	ATF_TP_ADD_TC(tp, reopen_object);
611289437Sngie	ATF_TP_ADD_TC(tp, readonly_mmap_write);
612289437Sngie	ATF_TP_ADD_TC(tp, open_after_link);
613289437Sngie	ATF_TP_ADD_TC(tp, open_invalid_path);
614289437Sngie	ATF_TP_ADD_TC(tp, open_write_only);
615289437Sngie	ATF_TP_ADD_TC(tp, open_extra_flags);
616289437Sngie	ATF_TP_ADD_TC(tp, open_anon);
617289437Sngie	ATF_TP_ADD_TC(tp, open_anon_readonly);
618289437Sngie	ATF_TP_ADD_TC(tp, open_bad_path_pointer);
619289437Sngie	ATF_TP_ADD_TC(tp, open_path_too_long);
620289437Sngie	ATF_TP_ADD_TC(tp, open_nonexisting_object);
621289437Sngie	ATF_TP_ADD_TC(tp, open_create_existing_object);
622289437Sngie	ATF_TP_ADD_TC(tp, shm_functionality_across_fork);
623289437Sngie	ATF_TP_ADD_TC(tp, trunc_resets_object);
624289437Sngie	ATF_TP_ADD_TC(tp, unlink_bad_path_pointer);
625289437Sngie	ATF_TP_ADD_TC(tp, unlink_path_too_long);
626289437Sngie	ATF_TP_ADD_TC(tp, object_resize);
627289437Sngie
628289437Sngie	return (atf_no_error());
629289437Sngie}
630