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$");
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
54299058Sngie	snprintf(test_path, sizeof(test_path), "%s/tmp.XXXXXX",
55299058Sngie	    getenv("TMPDIR") == NULL ? "/tmp" : getenv("TMPDIR"));
56289437Sngie	test_path[sizeof(test_path) - 1] = '\0';
57289437Sngie	ATF_REQUIRE_MSG(mkstemp(test_path) != -1,
58289437Sngie	    "mkstemp failed; errno=%d", errno);
59289437Sngie	ATF_REQUIRE_MSG(unlink(test_path) == 0,
60289437Sngie	    "unlink failed; errno=%d", errno);
61289437Sngie}
62289437Sngie
63175383Sjhb/*
64175383Sjhb * Attempt a shm_open() that should fail with an expected error of 'error'.
65175383Sjhb */
66175383Sjhbstatic void
67175383Sjhbshm_open_should_fail(const char *path, int flags, mode_t mode, int error)
68175383Sjhb{
69175383Sjhb	int fd;
70175383Sjhb
71175383Sjhb	fd = shm_open(path, flags, mode);
72289437Sngie	ATF_CHECK_MSG(fd == -1, "shm_open didn't fail");
73289437Sngie	ATF_CHECK_MSG(error == errno,
74289437Sngie	    "shm_open didn't fail with expected errno; errno=%d; expected "
75289437Sngie	    "errno=%d", errno, error);
76175383Sjhb}
77175383Sjhb
78175383Sjhb/*
79175383Sjhb * Attempt a shm_unlink() that should fail with an expected error of 'error'.
80175383Sjhb */
81175383Sjhbstatic void
82175383Sjhbshm_unlink_should_fail(const char *path, int error)
83175383Sjhb{
84175383Sjhb
85289437Sngie	ATF_CHECK_MSG(shm_unlink(path) == -1, "shm_unlink didn't fail");
86289437Sngie	ATF_CHECK_MSG(error == errno,
87289437Sngie	    "shm_unlink didn't fail with expected errno; errno=%d; expected "
88289437Sngie	    "errno=%d", errno, error);
89175383Sjhb}
90175383Sjhb
91175383Sjhb/*
92175383Sjhb * Open the test object and write '1' to the first byte.  Returns valid fd
93175383Sjhb * on success and -1 on failure.
94175383Sjhb */
95175383Sjhbstatic int
96175383Sjhbscribble_object(void)
97175383Sjhb{
98175383Sjhb	char *page;
99299058Sngie	int fd, pagesize;
100175383Sjhb
101289437Sngie	gen_test_path();
102289437Sngie
103299058Sngie	ATF_REQUIRE(0 < (pagesize = getpagesize()));
104299058Sngie
105289437Sngie	fd = shm_open(test_path, O_CREAT|O_EXCL|O_RDWR, 0777);
106175383Sjhb	if (fd < 0 && errno == EEXIST) {
107289437Sngie		if (shm_unlink(test_path) < 0)
108289437Sngie			atf_tc_fail("shm_unlink");
109289437Sngie		fd = shm_open(test_path, O_CREAT | O_EXCL | O_RDWR, 0777);
110175383Sjhb	}
111289437Sngie	if (fd < 0)
112289441Sngie		atf_tc_fail("shm_open failed; errno=%d", errno);
113299058Sngie	if (ftruncate(fd, pagesize) < 0)
114289441Sngie		atf_tc_fail("ftruncate failed; errno=%d", errno);
115175383Sjhb
116299058Sngie	page = mmap(0, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
117289437Sngie	if (page == MAP_FAILED)
118289441Sngie		atf_tc_fail("mmap failed; errno=%d", errno);
119175383Sjhb
120175383Sjhb	page[0] = '1';
121299058Sngie	ATF_REQUIRE_MSG(munmap(page, pagesize) == 0, "munmap failed; errno=%d",
122299058Sngie	    errno);
123175383Sjhb
124175383Sjhb	return (fd);
125175383Sjhb}
126175383Sjhb
127289437SngieATF_TC_WITHOUT_HEAD(remap_object);
128289437SngieATF_TC_BODY(remap_object, tc)
129175383Sjhb{
130175383Sjhb	char *page;
131299058Sngie	int fd, pagesize;
132175383Sjhb
133299058Sngie	ATF_REQUIRE(0 < (pagesize = getpagesize()));
134299058Sngie
135175383Sjhb	fd = scribble_object();
136175383Sjhb
137299058Sngie	page = mmap(0, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
138289441Sngie	if (page == MAP_FAILED)
139289441Sngie		atf_tc_fail("mmap(2) failed; errno=%d", errno);
140175383Sjhb
141289441Sngie	if (page[0] != '1')
142289441Sngie		atf_tc_fail("missing data ('%c' != '1')", page[0]);
143175383Sjhb
144175383Sjhb	close(fd);
145299058Sngie	ATF_REQUIRE_MSG(munmap(page, pagesize) == 0, "munmap failed; errno=%d",
146299058Sngie	    errno);
147175383Sjhb
148289441Sngie	ATF_REQUIRE_MSG(shm_unlink(test_path) != -1,
149289441Sngie	    "shm_unlink failed; errno=%d", errno);
150175383Sjhb}
151175383Sjhb
152289437SngieATF_TC_WITHOUT_HEAD(reopen_object);
153289437SngieATF_TC_BODY(reopen_object, tc)
154175383Sjhb{
155175383Sjhb	char *page;
156299058Sngie	int fd, pagesize;
157175383Sjhb
158299058Sngie	ATF_REQUIRE(0 < (pagesize = getpagesize()));
159299058Sngie
160175383Sjhb	fd = scribble_object();
161175383Sjhb	close(fd);
162175383Sjhb
163289437Sngie	fd = shm_open(test_path, O_RDONLY, 0777);
164289441Sngie	if (fd < 0)
165289441Sngie		atf_tc_fail("shm_open(2) failed; errno=%d", errno);
166289441Sngie
167299058Sngie	page = mmap(0, pagesize, PROT_READ, MAP_SHARED, fd, 0);
168289441Sngie	if (page == MAP_FAILED)
169289441Sngie		atf_tc_fail("mmap(2) failed; errno=%d", errno);
170175383Sjhb
171289441Sngie	if (page[0] != '1')
172289441Sngie		atf_tc_fail("missing data ('%c' != '1')", page[0]);
173175383Sjhb
174299058Sngie	ATF_REQUIRE_MSG(munmap(page, pagesize) == 0, "munmap failed; errno=%d",
175299058Sngie	    errno);
176175383Sjhb	close(fd);
177289441Sngie	ATF_REQUIRE_MSG(shm_unlink(test_path) != -1,
178289441Sngie	    "shm_unlink failed; errno=%d", errno);
179175383Sjhb}
180175383Sjhb
181289437SngieATF_TC_WITHOUT_HEAD(readonly_mmap_write);
182289437SngieATF_TC_BODY(readonly_mmap_write, tc)
183175383Sjhb{
184175383Sjhb	char *page;
185299058Sngie	int fd, pagesize;
186175383Sjhb
187299058Sngie	ATF_REQUIRE(0 < (pagesize = getpagesize()));
188299058Sngie
189289437Sngie	gen_test_path();
190289437Sngie
191289437Sngie	fd = shm_open(test_path, O_RDONLY | O_CREAT, 0777);
192289441Sngie	ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno);
193175383Sjhb
194175383Sjhb	/* PROT_WRITE should fail with EACCES. */
195299058Sngie	page = mmap(0, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
196289441Sngie	if (page != MAP_FAILED)
197289441Sngie		atf_tc_fail("mmap(PROT_WRITE) succeeded unexpectedly");
198175383Sjhb
199289441Sngie	if (errno != EACCES)
200289441Sngie		atf_tc_fail("mmap(PROT_WRITE) didn't fail with EACCES; "
201289441Sngie		    "errno=%d", errno);
202289441Sngie
203175383Sjhb	close(fd);
204289441Sngie	ATF_REQUIRE_MSG(shm_unlink(test_path) != -1,
205289441Sngie	    "shm_unlink failed; errno=%d", errno);
206175383Sjhb}
207175383Sjhb
208289437SngieATF_TC_WITHOUT_HEAD(open_after_link);
209289437SngieATF_TC_BODY(open_after_link, tc)
210175383Sjhb{
211175383Sjhb	int fd;
212175383Sjhb
213289437Sngie	gen_test_path();
214289437Sngie
215289437Sngie	fd = shm_open(test_path, O_RDONLY | O_CREAT, 0777);
216289441Sngie	ATF_REQUIRE_MSG(fd >= 0, "shm_open(1) failed; errno=%d", errno);
217175383Sjhb	close(fd);
218175383Sjhb
219289441Sngie	ATF_REQUIRE_MSG(shm_unlink(test_path) != -1, "shm_unlink failed: %d",
220289441Sngie	    errno);
221175383Sjhb
222289437Sngie	shm_open_should_fail(test_path, O_RDONLY, 0777, ENOENT);
223175383Sjhb}
224175383Sjhb
225289437SngieATF_TC_WITHOUT_HEAD(open_invalid_path);
226289437SngieATF_TC_BODY(open_invalid_path, tc)
227175383Sjhb{
228175383Sjhb
229175383Sjhb	shm_open_should_fail("blah", O_RDONLY, 0777, EINVAL);
230175383Sjhb}
231175383Sjhb
232289437SngieATF_TC_WITHOUT_HEAD(open_write_only);
233289437SngieATF_TC_BODY(open_write_only, tc)
234175383Sjhb{
235175383Sjhb
236289437Sngie	gen_test_path();
237289437Sngie
238289437Sngie	shm_open_should_fail(test_path, O_WRONLY, 0777, EINVAL);
239175383Sjhb}
240175383Sjhb
241289437SngieATF_TC_WITHOUT_HEAD(open_extra_flags);
242289437SngieATF_TC_BODY(open_extra_flags, tc)
243175383Sjhb{
244175383Sjhb
245289437Sngie	gen_test_path();
246289437Sngie
247289437Sngie	shm_open_should_fail(test_path, O_RDONLY | O_DIRECT, 0777, EINVAL);
248175383Sjhb}
249175383Sjhb
250289437SngieATF_TC_WITHOUT_HEAD(open_anon);
251289437SngieATF_TC_BODY(open_anon, tc)
252175383Sjhb{
253175383Sjhb	int fd;
254175383Sjhb
255175383Sjhb	fd = shm_open(SHM_ANON, O_RDWR, 0777);
256289441Sngie	ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno);
257175383Sjhb	close(fd);
258175383Sjhb}
259175383Sjhb
260289437SngieATF_TC_WITHOUT_HEAD(open_anon_readonly);
261289437SngieATF_TC_BODY(open_anon_readonly, tc)
262175383Sjhb{
263175383Sjhb
264175383Sjhb	shm_open_should_fail(SHM_ANON, O_RDONLY, 0777, EINVAL);
265175383Sjhb}
266175383Sjhb
267289437SngieATF_TC_WITHOUT_HEAD(open_bad_path_pointer);
268289437SngieATF_TC_BODY(open_bad_path_pointer, tc)
269175383Sjhb{
270175383Sjhb
271175383Sjhb	shm_open_should_fail((char *)1024, O_RDONLY, 0777, EFAULT);
272175383Sjhb}
273175383Sjhb
274289437SngieATF_TC_WITHOUT_HEAD(open_path_too_long);
275289437SngieATF_TC_BODY(open_path_too_long, tc)
276175383Sjhb{
277175383Sjhb	char *page;
278175383Sjhb
279175383Sjhb	page = malloc(MAXPATHLEN + 1);
280175383Sjhb	memset(page, 'a', MAXPATHLEN);
281175383Sjhb	page[MAXPATHLEN] = '\0';
282175383Sjhb	shm_open_should_fail(page, O_RDONLY, 0777, ENAMETOOLONG);
283175383Sjhb	free(page);
284175383Sjhb}
285175383Sjhb
286289437SngieATF_TC_WITHOUT_HEAD(open_nonexisting_object);
287289437SngieATF_TC_BODY(open_nonexisting_object, tc)
288175383Sjhb{
289175383Sjhb
290175383Sjhb	shm_open_should_fail("/notreallythere", O_RDONLY, 0777, ENOENT);
291175383Sjhb}
292175383Sjhb
293289437SngieATF_TC_WITHOUT_HEAD(open_create_existing_object);
294289437SngieATF_TC_BODY(open_create_existing_object, tc)
295175383Sjhb{
296175383Sjhb	int fd;
297175383Sjhb
298289437Sngie	gen_test_path();
299289437Sngie
300289437Sngie	fd = shm_open(test_path, O_RDONLY|O_CREAT, 0777);
301289441Sngie	ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno);
302175383Sjhb	close(fd);
303175383Sjhb
304289437Sngie	shm_open_should_fail(test_path, O_RDONLY|O_CREAT|O_EXCL,
305175383Sjhb	    0777, EEXIST);
306175383Sjhb
307289441Sngie	ATF_REQUIRE_MSG(shm_unlink(test_path) != -1,
308289441Sngie	    "shm_unlink failed; errno=%d", errno);
309175383Sjhb}
310175383Sjhb
311289437SngieATF_TC_WITHOUT_HEAD(trunc_resets_object);
312289437SngieATF_TC_BODY(trunc_resets_object, tc)
313175383Sjhb{
314175383Sjhb	struct stat sb;
315175383Sjhb	int fd;
316175383Sjhb
317289437Sngie	gen_test_path();
318289437Sngie
319175383Sjhb	/* Create object and set size to 1024. */
320289437Sngie	fd = shm_open(test_path, O_RDWR | O_CREAT, 0777);
321289441Sngie	ATF_REQUIRE_MSG(fd >= 0, "shm_open(1) failed; errno=%d", errno);
322289441Sngie	ATF_REQUIRE_MSG(ftruncate(fd, 1024) != -1,
323289441Sngie	    "ftruncate failed; errno=%d", errno);
324289441Sngie	ATF_REQUIRE_MSG(fstat(fd, &sb) != -1,
325289441Sngie	    "fstat(1) failed; errno=%d", errno);
326289441Sngie	ATF_REQUIRE_MSG(sb.st_size == 1024, "size %d != 1024", (int)sb.st_size);
327175383Sjhb	close(fd);
328175383Sjhb
329175383Sjhb	/* Open with O_TRUNC which should reset size to 0. */
330289437Sngie	fd = shm_open(test_path, O_RDWR | O_TRUNC, 0777);
331289441Sngie	ATF_REQUIRE_MSG(fd >= 0, "shm_open(2) failed; errno=%d", errno);
332289441Sngie	ATF_REQUIRE_MSG(fstat(fd, &sb) != -1,
333289441Sngie	    "fstat(2) failed; errno=%d", errno);
334289441Sngie	ATF_REQUIRE_MSG(sb.st_size == 0,
335289441Sngie	    "size was not 0 after truncation: %d", (int)sb.st_size);
336175383Sjhb	close(fd);
337289441Sngie	ATF_REQUIRE_MSG(shm_unlink(test_path) != -1,
338289441Sngie	    "shm_unlink failed; errno=%d", errno);
339175383Sjhb}
340175383Sjhb
341289437SngieATF_TC_WITHOUT_HEAD(unlink_bad_path_pointer);
342289437SngieATF_TC_BODY(unlink_bad_path_pointer, tc)
343175383Sjhb{
344175383Sjhb
345175383Sjhb	shm_unlink_should_fail((char *)1024, EFAULT);
346175383Sjhb}
347175383Sjhb
348289437SngieATF_TC_WITHOUT_HEAD(unlink_path_too_long);
349289437SngieATF_TC_BODY(unlink_path_too_long, tc)
350175383Sjhb{
351175383Sjhb	char *page;
352175383Sjhb
353175383Sjhb	page = malloc(MAXPATHLEN + 1);
354175383Sjhb	memset(page, 'a', MAXPATHLEN);
355175383Sjhb	page[MAXPATHLEN] = '\0';
356175383Sjhb	shm_unlink_should_fail(page, ENAMETOOLONG);
357175383Sjhb	free(page);
358175383Sjhb}
359175383Sjhb
360289437SngieATF_TC_WITHOUT_HEAD(object_resize);
361289437SngieATF_TC_BODY(object_resize, tc)
362175383Sjhb{
363175383Sjhb	pid_t pid;
364175383Sjhb	struct stat sb;
365299058Sngie	char *page;
366299058Sngie	int fd, pagesize, status;
367175383Sjhb
368299058Sngie	ATF_REQUIRE(0 < (pagesize = getpagesize()));
369299058Sngie
370175383Sjhb	/* Start off with a size of a single page. */
371289441Sngie	fd = shm_open(SHM_ANON, O_CREAT|O_RDWR, 0777);
372289441Sngie	if (fd < 0)
373289441Sngie		atf_tc_fail("shm_open failed; errno=%d", errno);
374175383Sjhb
375299058Sngie	if (ftruncate(fd, pagesize) < 0)
376289441Sngie		atf_tc_fail("ftruncate(1) failed; errno=%d", errno);
377289441Sngie
378289441Sngie	if (fstat(fd, &sb) < 0)
379289441Sngie		atf_tc_fail("fstat(1) failed; errno=%d", errno);
380289441Sngie
381299058Sngie	if (sb.st_size != pagesize)
382289441Sngie		atf_tc_fail("first resize failed (%d != %d)",
383299058Sngie		    (int)sb.st_size, pagesize);
384289441Sngie
385175383Sjhb	/* Write a '1' to the first byte. */
386299058Sngie	page = mmap(0, pagesize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
387289441Sngie	if (page == MAP_FAILED)
388289437Sngie		atf_tc_fail("mmap(1)");
389175383Sjhb
390175383Sjhb	page[0] = '1';
391175383Sjhb
392299058Sngie	ATF_REQUIRE_MSG(munmap(page, pagesize) == 0, "munmap failed; errno=%d",
393299058Sngie	    errno);
394175383Sjhb
395175383Sjhb	/* Grow the object to 2 pages. */
396299058Sngie	if (ftruncate(fd, pagesize * 2) < 0)
397289441Sngie		atf_tc_fail("ftruncate(2) failed; errno=%d", errno);
398175383Sjhb
399289441Sngie	if (fstat(fd, &sb) < 0)
400289441Sngie		atf_tc_fail("fstat(2) failed; errno=%d", errno);
401289441Sngie
402299058Sngie	if (sb.st_size != pagesize * 2)
403289441Sngie		atf_tc_fail("second resize failed (%d != %d)",
404299058Sngie		    (int)sb.st_size, pagesize * 2);
405289441Sngie
406175383Sjhb	/* Check for '1' at the first byte. */
407299058Sngie	page = mmap(0, pagesize * 2, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
408289441Sngie	if (page == MAP_FAILED)
409289441Sngie		atf_tc_fail("mmap(2) failed; errno=%d", errno);
410175383Sjhb
411289441Sngie	if (page[0] != '1')
412289441Sngie		atf_tc_fail("'%c' != '1'", page[0]);
413175383Sjhb
414175383Sjhb	/* Write a '2' at the start of the second page. */
415299058Sngie	page[pagesize] = '2';
416175383Sjhb
417175383Sjhb	/* Shrink the object back to 1 page. */
418299058Sngie	if (ftruncate(fd, pagesize) < 0)
419289441Sngie		atf_tc_fail("ftruncate(3) failed; errno=%d", errno);
420175383Sjhb
421289441Sngie	if (fstat(fd, &sb) < 0)
422289441Sngie		atf_tc_fail("fstat(3) failed; errno=%d", errno);
423289441Sngie
424299058Sngie	if (sb.st_size != pagesize)
425289441Sngie		atf_tc_fail("third resize failed (%d != %d)",
426299058Sngie		    (int)sb.st_size, pagesize);
427289441Sngie
428175383Sjhb	/*
429175383Sjhb	 * Fork a child process to make sure the second page is no
430175383Sjhb	 * longer valid.
431175383Sjhb	 */
432175383Sjhb	pid = fork();
433289441Sngie	if (pid == -1)
434289441Sngie		atf_tc_fail("fork failed; errno=%d", errno);
435175383Sjhb
436175383Sjhb	if (pid == 0) {
437175383Sjhb		struct rlimit lim;
438175383Sjhb		char c;
439175383Sjhb
440175383Sjhb		/* Don't generate a core dump. */
441299058Sngie		ATF_REQUIRE(getrlimit(RLIMIT_CORE, &lim) == 0);
442175383Sjhb		lim.rlim_cur = 0;
443299058Sngie		ATF_REQUIRE(setrlimit(RLIMIT_CORE, &lim) == 0);
444175383Sjhb
445175383Sjhb		/*
446175383Sjhb		 * The previous ftruncate(2) shrunk the backing object
447175383Sjhb		 * so that this address is no longer valid, so reading
448175383Sjhb		 * from it should trigger a SIGSEGV.
449175383Sjhb		 */
450299058Sngie		c = page[pagesize];
451175383Sjhb		fprintf(stderr, "child: page 1: '%c'\n", c);
452175383Sjhb		exit(0);
453175383Sjhb	}
454289441Sngie
455289441Sngie	if (wait(&status) < 0)
456289441Sngie		atf_tc_fail("wait failed; errno=%d", errno);
457289441Sngie
458289441Sngie	if (!WIFSIGNALED(status) || WTERMSIG(status) != SIGSEGV)
459289437Sngie		atf_tc_fail("child terminated with status %x", status);
460175383Sjhb
461175383Sjhb	/* Grow the object back to 2 pages. */
462299058Sngie	if (ftruncate(fd, pagesize * 2) < 0)
463289441Sngie		atf_tc_fail("ftruncate(2) failed; errno=%d", errno);
464175383Sjhb
465289441Sngie	if (fstat(fd, &sb) < 0)
466289441Sngie		atf_tc_fail("fstat(2) failed; errno=%d", errno);
467289441Sngie
468299058Sngie	if (sb.st_size != pagesize * 2)
469289441Sngie		atf_tc_fail("fourth resize failed (%d != %d)",
470299058Sngie		    (int)sb.st_size, pagesize);
471289441Sngie
472175383Sjhb	/*
473175383Sjhb	 * Note that the mapping at 'page' for the second page is
474175383Sjhb	 * still valid, and now that the shm object has been grown
475175383Sjhb	 * back up to 2 pages, there is now memory backing this page
476175383Sjhb	 * so the read will work.  However, the data should be zero
477175383Sjhb	 * rather than '2' as the old data was thrown away when the
478175383Sjhb	 * object was shrunk and the new pages when an object are
479175383Sjhb	 * grown are zero-filled.
480175383Sjhb	 */
481299058Sngie	if (page[pagesize] != 0)
482289441Sngie		atf_tc_fail("invalid data at %d: %x != 0",
483299058Sngie		    pagesize, (int)page[pagesize]);
484175383Sjhb
485175383Sjhb	close(fd);
486175383Sjhb}
487175383Sjhb
488289437Sngie/* Signal handler which does nothing. */
489289437Sngiestatic void
490289437Sngieignoreit(int sig __unused)
491175383Sjhb{
492289437Sngie	;
493289437Sngie}
494175383Sjhb
495289437SngieATF_TC_WITHOUT_HEAD(shm_functionality_across_fork);
496289437SngieATF_TC_BODY(shm_functionality_across_fork, tc)
497289437Sngie{
498289437Sngie	char *cp, c;
499289437Sngie	int error, desc, rv;
500289437Sngie	long scval;
501289437Sngie	sigset_t ss;
502289437Sngie	struct sigaction sa;
503289437Sngie	void *region;
504289437Sngie	size_t i, psize;
505289437Sngie
506289437Sngie#ifndef _POSIX_SHARED_MEMORY_OBJECTS
507289437Sngie	printf("_POSIX_SHARED_MEMORY_OBJECTS is undefined\n");
508289437Sngie#else
509289437Sngie	printf("_POSIX_SHARED_MEMORY_OBJECTS is defined as %ld\n",
510289437Sngie	       (long)_POSIX_SHARED_MEMORY_OBJECTS - 0);
511289437Sngie	if (_POSIX_SHARED_MEMORY_OBJECTS - 0 == -1)
512289437Sngie		printf("***Indicates this feature may be unsupported!\n");
513289437Sngie#endif
514289437Sngie	errno = 0;
515289437Sngie	scval = sysconf(_SC_SHARED_MEMORY_OBJECTS);
516289437Sngie	if (scval == -1 && errno != 0) {
517289437Sngie		atf_tc_fail("sysconf(_SC_SHARED_MEMORY_OBJECTS) failed; "
518289437Sngie		    "errno=%d", errno);
519289437Sngie	} else {
520289437Sngie		printf("sysconf(_SC_SHARED_MEMORY_OBJECTS) returns %ld\n",
521289437Sngie		       scval);
522289437Sngie		if (scval == -1)
523289437Sngie			printf("***Indicates this feature is unsupported!\n");
524289437Sngie	}
525289437Sngie
526289437Sngie	errno = 0;
527289437Sngie	scval = sysconf(_SC_PAGESIZE);
528289437Sngie	if (scval == -1 && errno != 0) {
529289437Sngie		atf_tc_fail("sysconf(_SC_PAGESIZE) failed; errno=%d", errno);
530299058Sngie	} else if (scval <= 0) {
531289437Sngie		fprintf(stderr, "bogus return from sysconf(_SC_PAGESIZE): %ld",
532289437Sngie		    scval);
533289437Sngie		psize = 4096;
534289437Sngie	} else {
535289437Sngie		printf("sysconf(_SC_PAGESIZE) returns %ld\n", scval);
536289437Sngie		psize = scval;
537289437Sngie	}
538289437Sngie
539289437Sngie	gen_test_path();
540289437Sngie	desc = shm_open(test_path, O_EXCL | O_CREAT | O_RDWR, 0600);
541289437Sngie
542289437Sngie	ATF_REQUIRE_MSG(desc >= 0, "shm_open failed; errno=%d", errno);
543289437Sngie	ATF_REQUIRE_MSG(shm_unlink(test_path) == 0,
544289437Sngie	    "shm_unlink failed; errno=%d", errno);
545289437Sngie	ATF_REQUIRE_MSG(ftruncate(desc, (off_t)psize) != -1,
546289437Sngie	    "ftruncate failed; errno=%d", errno);
547289437Sngie
548299058Sngie	region = mmap(NULL, psize, PROT_READ | PROT_WRITE, MAP_SHARED, desc, 0);
549289437Sngie	ATF_REQUIRE_MSG(region != MAP_FAILED, "mmap failed; errno=%d", errno);
550289437Sngie	memset(region, '\377', psize);
551289437Sngie
552289437Sngie	sa.sa_flags = 0;
553289437Sngie	sa.sa_handler = ignoreit;
554289437Sngie	sigemptyset(&sa.sa_mask);
555289437Sngie	ATF_REQUIRE_MSG(sigaction(SIGUSR1, &sa, (struct sigaction *)0) == 0,
556289437Sngie	    "sigaction failed; errno=%d", errno);
557289437Sngie
558289437Sngie	sigemptyset(&ss);
559289437Sngie	sigaddset(&ss, SIGUSR1);
560289437Sngie	ATF_REQUIRE_MSG(sigprocmask(SIG_BLOCK, &ss, (sigset_t *)0) == 0,
561289437Sngie	    "sigprocmask failed; errno=%d", errno);
562289437Sngie
563289437Sngie	rv = fork();
564289437Sngie	ATF_REQUIRE_MSG(rv != -1, "fork failed; errno=%d", errno);
565289437Sngie	if (rv == 0) {
566289437Sngie		sigemptyset(&ss);
567289437Sngie		sigsuspend(&ss);
568289437Sngie
569289437Sngie		for (cp = region; cp < (char *)region + psize; cp++) {
570289437Sngie			if (*cp != '\151')
571289437Sngie				_exit(1);
572289437Sngie		}
573289437Sngie		if (lseek(desc, 0, SEEK_SET) == -1)
574289437Sngie			_exit(1);
575289437Sngie		for (i = 0; i < psize; i++) {
576289437Sngie			error = read(desc, &c, 1);
577289437Sngie			if (c != '\151')
578289437Sngie				_exit(1);
579289437Sngie		}
580289437Sngie		_exit(0);
581289437Sngie	} else {
582289437Sngie		int status;
583289437Sngie
584289437Sngie		memset(region, '\151', psize - 2);
585289437Sngie		error = pwrite(desc, region, 2, psize - 2);
586289437Sngie		if (error != 2) {
587289437Sngie			if (error >= 0)
588289437Sngie				atf_tc_fail("short write; %d bytes written",
589289437Sngie				    error);
590289437Sngie			else
591289437Sngie				atf_tc_fail("shmfd write");
592289437Sngie		}
593289437Sngie		kill(rv, SIGUSR1);
594289437Sngie		waitpid(rv, &status, 0);
595289437Sngie
596289437Sngie		if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
597289437Sngie			printf("Functionality test successful\n");
598289437Sngie		} else if (WIFEXITED(status)) {
599289437Sngie			atf_tc_fail("Child process exited with status %d",
600289437Sngie			    WEXITSTATUS(status));
601289437Sngie		} else {
602289437Sngie			atf_tc_fail("Child process terminated with %s",
603289437Sngie			    strsignal(WTERMSIG(status)));
604289437Sngie		}
605289437Sngie	}
606299058Sngie
607299058Sngie	ATF_REQUIRE_MSG(munmap(region, psize) == 0, "munmap failed; errno=%d",
608299058Sngie	    errno);
609299058Sngie	shm_unlink(test_path);
610175383Sjhb}
611289437Sngie
612289437SngieATF_TP_ADD_TCS(tp)
613289437Sngie{
614289437Sngie
615289437Sngie	ATF_TP_ADD_TC(tp, remap_object);
616289437Sngie	ATF_TP_ADD_TC(tp, reopen_object);
617289437Sngie	ATF_TP_ADD_TC(tp, readonly_mmap_write);
618289437Sngie	ATF_TP_ADD_TC(tp, open_after_link);
619289437Sngie	ATF_TP_ADD_TC(tp, open_invalid_path);
620289437Sngie	ATF_TP_ADD_TC(tp, open_write_only);
621289437Sngie	ATF_TP_ADD_TC(tp, open_extra_flags);
622289437Sngie	ATF_TP_ADD_TC(tp, open_anon);
623289437Sngie	ATF_TP_ADD_TC(tp, open_anon_readonly);
624289437Sngie	ATF_TP_ADD_TC(tp, open_bad_path_pointer);
625289437Sngie	ATF_TP_ADD_TC(tp, open_path_too_long);
626289437Sngie	ATF_TP_ADD_TC(tp, open_nonexisting_object);
627289437Sngie	ATF_TP_ADD_TC(tp, open_create_existing_object);
628289437Sngie	ATF_TP_ADD_TC(tp, shm_functionality_across_fork);
629289437Sngie	ATF_TP_ADD_TC(tp, trunc_resets_object);
630289437Sngie	ATF_TP_ADD_TC(tp, unlink_bad_path_pointer);
631289437Sngie	ATF_TP_ADD_TC(tp, unlink_path_too_long);
632289437Sngie	ATF_TP_ADD_TC(tp, object_resize);
633289437Sngie
634289437Sngie	return (atf_no_error());
635289437Sngie}
636