4 # Copyright (c) 2012 Peter Holm
7 # Redistribution and use in source and binary forms, with or without
8 # modification, are permitted provided that the following conditions
10 # 1. Redistributions of source code must retain the above copyright
11 # notice, this list of conditions and the following disclaimer.
12 # 2. Redistributions in binary form must reproduce the above copyright
13 # notice, this list of conditions and the following disclaimer in the
14 # documentation and/or other materials provided with the distribution.
16 # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 # Demonstrate that close() of an flock'd file is not atomic.
30 # Fails with "flock_open_close: execv(/mnt/test): Text file busy"
32 # Test scenario by: jhb
34 [ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1
40 sed '1,/^EOF/d' < $odir/$0 > flock_open_close.c
41 rm -f /tmp/flock_open_close
42 mycc -o flock_open_close -Wall -Wextra -O2 -g flock_open_close.c -lpthread || exit 1
43 rm -f flock_open_close.c
45 mount | grep $mntpoint | grep -q /dev/md && umount -f $mntpoint
46 mdconfig -l | grep -q md$mdstart && mdconfig -d -u $mdstart
48 mdconfig -a -t swap -s 1g -u $mdstart || exit 1
49 bsdlabel -w md$mdstart auto
50 newfs $newfs_flags md${mdstart}$part > /dev/null
51 mount /dev/md${mdstart}$part $mntpoint
54 cp /bin/test $mntpoint
55 chown $testuser $mntpoint/test
56 chmod +w $mntpoint/test
58 su $testuser -c "/tmp/flock_open_close $mntpoint/test" &
60 while kill -0 $! 2>/dev/null; do
61 mksnap_ffs $mntpoint $mntpoint/.snap/snap
63 rm -f $mntpoint/.snap/snap
70 mount | grep -q md${mdstart}$part && \
71 umount $mntpoint && mdconfig -d -u $mdstart && break
74 if mount | grep -q md${mdstart}$part; then
76 echo "umount $mntpoint failed"
79 rm -f /tmp/flock_open_close
83 #include <sys/types.h>
96 fprintf(stderr, "Usage: flock_close_race <binary> [args]\n");
101 child(const char *binary)
105 /* Exit as soon as our parent exits. */
106 while (getppid() != 1) {
107 fd = open(binary, O_RDWR | O_EXLOCK);
110 * This may get ETXTBSY since exit() will
111 * close its open fd's (thus releasing the
112 * lock), before it releases the vmspace (and
113 * mapping of the binary).
115 if (errno == ETXTBSY)
117 err(2, "can't open %s", binary);
125 exec_child(char **av)
129 fd = open(av[0], O_RDONLY | O_SHLOCK);
131 /* "flock_open_close: execv(/mnt/test): Text file busy" seen */
132 err(127, "execv(%s)", av[0]);
136 main(int ac, char **av)
144 if (stat(av[1], &sb) != 0)
145 err(1, "stat(%s)", av[1]);
146 if (!S_ISREG(sb.st_mode))
147 errx(1, "%s not an executable", av[1]);
155 for (i = 0; i < 200000; i++) {
162 if (WIFEXITED(status) && WEXITSTATUS(status) == 127) {
163 fprintf(stderr, "FAIL\n");
167 if (WIFEXITED(status) && WEXITSTATUS(status) != 1) {
168 /* /bin/test returns 1 */