fuse: Skip guestmount test if setfacl is not installed.
[libguestfs.git] / fuse / test-fuse.sh
1 #!/bin/bash -
2 # libguestfs
3 # Copyright (C) 2009-2011 Red Hat Inc.
4 #
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
19 unset CDPATH
20 set -e
21 #set -v
22
23 if [ ! -w /dev/fuse ]; then
24     echo "SKIPPING guestmount test, because there is no /dev/fuse."
25     exit 0
26 fi
27
28 if ! setfacl --help >/dev/null 2>&1; then
29     echo "SKIPPING guestmount test, because setfacl is not installed."
30     exit 0
31 fi
32
33 if [ -z "$top_builddir" ]; then
34     echo "$0: error: environment variable \$top_builddir must be set"
35     exit 1
36 fi
37
38 nr_stages=$(grep "^stage " $0 | wc -l)
39
40 # Allow top_builddir to be a relative path, but also make it absolute,
41 # and move to that directory for the initial phase of the script.
42 top_builddir=$(cd "$top_builddir" > /dev/null; pwd)
43
44 # Set TMPDIR so the appliance doesn't conflict with globally
45 # installed libguestfs.
46 export TMPDIR=$top_builddir
47
48 # Set libguestfs up for running locally.
49 export LIBGUESTFS_PATH="$top_builddir/appliance"
50
51 # Paths to the other programs and files.  NB: Must be absolute paths.
52 guestfish="$top_builddir/fish/guestfish"
53 guestmount="$top_builddir/fuse/guestmount"
54 image="$top_builddir/fuse/test.img"
55 mp="$top_builddir/fuse/test-mp"
56
57 if [ ! -x "$guestfish" -o ! -x "$guestmount" ]; then
58     echo "$0: error: guestfish or guestmount are not available"
59     exit 1
60 fi
61
62 # Ensure everything is cleaned up on exit.
63 rm -f "$image"
64 mkdir -p "$mp"
65 fusermount -u "$mp" >/dev/null 2>&1 ||:
66 function cleanup ()
67 {
68     status=$?
69     set +e
70     [ $status = 0 ] || echo "*** FAILED ***"
71     echo "Unmounting filesystem and cleaning up."
72
73     # Move out of the mountpoint (otherwise our cwd will prevent the
74     # mountpoint from being unmounted).
75     cd "$top_builddir"
76
77     # Who's using this?  Should be no one, but see below.
78     if [ -x /sbin/fuser ]; then /sbin/fuser "$mp"; fi
79
80     # If you run this and you have GNOME running at the same time,
81     # then randomly /usr/libexec/gvfs-gdu-volume-monitor will decide
82     # to do whatever it does in the mountpoint directory, preventing
83     # you from unmounting it!  Hence the need for this loop.
84     count=10
85     while ! fusermount -u "$mp" && [ $count -gt 0 ]; do
86         sleep 1
87         ((count--))
88     done
89
90     rm -f "$image"
91     rm -rf "$mp"
92     exit $status
93 }
94 trap cleanup INT TERM QUIT EXIT
95
96 s=1
97 function stage ()
98 {
99     echo "test-fuse: $s/$nr_stages:" "$@" "..."
100     ((s++))
101 }
102
103 stage Create filesystem with some initial content
104 $guestfish <<EOF
105   sparse "$image" 10M
106   run
107   part-disk /dev/sda mbr
108   mkfs ext2 /dev/sda1
109   mount_options acl,user_xattr /dev/sda1 /
110   write /hello.txt hello
111   write /world.txt "hello world"
112   touch /empty
113   touch /user_xattr
114   setxattr user.test hello123 8 /user_xattr
115   touch /acl
116   # XXX hack until libguestfs gets ACL support
117   debug sh "setfacl -m u:500:r /sysroot/acl" | cat > /dev/null
118 EOF
119
120 stage Mounting the filesystem
121 $guestmount \
122     -a "$image" -m /dev/sda1:/:acl,user_xattr \
123     -o uid="$(id -u)" -o gid="$(id -g)" "$mp"
124 # To debug guestmount, add this to the end of the preceding command:
125 # -v -x & sleep 60
126
127 stage Changing into mounted directory
128 cd "$mp"
129
130 stage Checking initial files exist
131 [ -n "$(echo *)" ]
132 [ "$(ls empty hello.txt world.txt)" = "empty
133 hello.txt
134 world.txt" ]
135
136 stage Checking initial files contain expected content
137 [ "$(cat hello.txt)" = "hello" ]
138 [ "$(cat world.txt)" = "hello world" ]
139 cat empty ;# should print nothing
140 [ -z "$(cat empty)" ]
141
142 stage Checking file modes of initial content
143 [ "$(stat -c %a empty)" = "644" ]
144 [ "$(stat -c %a hello.txt)" = "644" ]
145 [ "$(stat -c %a world.txt)" = "644" ]
146
147 stage Checking sizes of initial content
148 [ "$(stat -c %s empty)" -eq 0 ]
149 [ "$(stat -c %s hello.txt)" -eq 5 ]
150 [ "$(stat -c %s world.txt)" -eq 11 ]
151
152 stage Checking unlink
153 touch new
154 rm -f new ;# force because file is "owned" by root
155
156 stage Checking symbolic link
157 ln -s hello.txt symlink
158 [ -L symlink ]
159
160 stage Checking readlink
161 [ "$(readlink symlink)" = "hello.txt" ]
162
163 stage Checking hard link
164 [ "$(stat -c %h hello.txt)" -eq 1 ]
165 ln hello.txt link
166 [ "$(stat -c %h link)" -eq 2 ]
167 [ "$(stat -c %h hello.txt)" -eq 2 ]
168 rm -f link
169 [ ! -e link ]
170
171 # This fails because of caching.  The problem is that the linked file
172 # ("hello.txt") is cached with a link count of 2.  unlink("link")
173 # invalidates the cache for "link", but _not_ for "hello.txt" which
174 # still has the now-incorrect cached value.  However there's not much
175 # we can do about this since searching for all linked inodes of a file
176 # is an O(n) operation.
177 #[ "$(stat -c %h hello.txt)" -eq 1 ]
178
179 stage Checking mkdir
180 mkdir newdir
181 [ -d newdir ]
182
183 stage Checking rmdir
184 rmdir newdir
185 [ ! -e newdir ]
186
187 stage Checking rename
188 touch old
189 mv old new
190 [ -f new ]
191 [ ! -e old ]
192 rm -f new
193
194 stage Checking chmod
195 touch new
196 chmod a+x new
197 [ -x new ]
198 chmod a-x new
199 [ ! -x new ]
200 chmod a-w new
201 [ ! -w new ]
202 chmod a+w new
203 [ -w new ]
204 chmod a-r new
205 [ ! -r new ]
206 chmod a+r new
207 [ -r new ]
208 rm -f new
209
210 stage Checking truncate
211 truncate -s 10000 truncated
212 [ "$(stat -c %s truncated)" -eq 10000 ]
213 truncate -c -s 1000 truncated
214 [ "$(stat -c %s truncated)" -eq 1000 ]
215 truncate -c -s 10 truncated
216 [ "$(stat -c %s truncated)" -eq 10 ]
217 truncate -c -s 0 truncated
218 [ "$(stat -c %s truncated)" -eq 0 ]
219 rm -f truncated
220
221 # Disabled because of RHBZ#660687 on Debian.
222 # stage Checking utimens and timestamps
223 # for ts in 12345 1234567 987654321; do
224 #     # NB: It's not possible to set the ctime with touch.
225 #     touch -a -d @$ts timestamp
226 #     [ "$(stat -c %X timestamp)" -eq $ts ]
227 #     touch -m -d @$ts timestamp
228 #     [ "$(stat -c %Y timestamp)" -eq $ts ]
229 #     touch    -d @$ts timestamp
230 #     [ "$(stat -c %X timestamp)" -eq $ts ]
231 #     [ "$(stat -c %Y timestamp)" -eq $ts ]
232 # done
233
234 stage Checking writes
235 cp hello.txt copy.txt
236 echo >> copy.txt
237 echo world >> copy.txt
238 echo bigger >> copy.txt
239 echo biggest >> copy.txt
240 [ "$(cat copy.txt)" = "hello
241 world
242 bigger
243 biggest" ]
244
245 stage 'Checking extended attribute (xattr) read operation'
246 if getfattr --help > /dev/null 2>&1 ; then
247   [ "$(getfattr -d user_xattr | grep -v ^#)" = 'user.test="hello123"' ]
248 fi
249
250 stage Checking POSIX ACL read operation
251 if getfacl --help > /dev/null 2>&1 ; then
252   [ "$(getfacl -n acl | grep -v ^#)" = "user::rw-
253 user:500:r--
254 group::r--
255 mask::r--
256 other::r--" ]
257 fi
258
259 # These ones are not yet tested by the current script:
260 #stage XXX statfs/statvfs
261
262 # These ones cannot easily be tested by the current script, eg because
263 # this script doesn't run as root:
264 #stage XXX fsync
265 #stage XXX chown
266 #stage XXX mknod