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