]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tests/sys/posixshm/posixshm_test.c
Update to bmake-20200710
[FreeBSD/FreeBSD.git] / tests / sys / posixshm / posixshm_test.c
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 }