todo: Add notes on inspecting ISO images.
[libguestfs.git] / fuse / test-fuse.sh
1 #!/bin/bash -
2 # libguestfs
3 # Copyright (C) 2009 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 [ -z "$top_builddir" ]; then
24     echo "$0: error: environment variable \$top_builddir must be set"
25     exit 1
26 fi
27
28 nr_stages=$(grep "^stage " $0 | wc -l)
29
30 # Allow top_builddir to be a relative path, but also make it absolute,
31 # and move to that directory for the initial phase of the script.
32 top_builddir=$(cd "$top_builddir" > /dev/null; pwd)
33
34 # Set libguestfs up for running locally.
35 export LIBGUESTFS_PATH="$top_builddir/appliance"
36
37 # Paths to the other programs and files.  NB: Must be absolute paths.
38 guestfish="$top_builddir/fish/guestfish"
39 guestmount="$top_builddir/fuse/guestmount"
40 image="$top_builddir/fuse/test.img"
41 mp="$top_builddir/fuse/test-mp"
42
43 if [ ! -x "$guestfish" -o ! -x "$guestmount" ]; then
44     echo "$0: error: guestfish or guestmount are not available"
45     exit 1
46 fi
47
48 # Ensure everything is cleaned up on exit.
49 rm -f "$image"
50 mkdir -p "$mp"
51 fusermount -u "$mp" >/dev/null 2>&1 ||:
52 function cleanup ()
53 {
54     status=$?
55     set +e
56     [ $status = 0 ] || echo "*** FAILED ***"
57     echo "Unmounting filesystem and cleaning up."
58
59     # Move out of the mountpoint (otherwise our cwd will prevent the
60     # mountpoint from being unmounted).
61     cd "$top_builddir"
62
63     # Who's using this?  Should be no one, but see below.
64     if [ -x /sbin/fuser ]; then /sbin/fuser "$mp"; fi
65
66     # If you run this and you have GNOME running at the same time,
67     # then randomly /usr/libexec/gvfs-gdu-volume-monitor will decide
68     # to do whatever it does in the mountpoint directory, preventing
69     # you from unmounting it!  Hence the need for this loop.
70     count=10
71     while ! fusermount -u "$mp" && [ $count -gt 0 ]; do
72         sleep 1
73         ((count--))
74     done
75
76     rm -f "$image"
77     rm -rf "$mp"
78     exit $status
79 }
80 trap cleanup INT TERM QUIT EXIT
81
82 s=1
83 function stage ()
84 {
85     echo "test-fuse: $s/$nr_stages:" "$@" "..."
86     ((s++))
87 }
88
89 stage Create filesystem with some initial content
90 $guestfish <<EOF
91   sparse "$image" 10M
92   run
93   part-disk /dev/sda mbr
94   mkfs ext2 /dev/sda1
95   mount /dev/sda1 /
96   write /hello.txt hello
97   write /world.txt "hello world"
98   touch /empty
99 EOF
100
101 stage Mounting the filesystem
102 $guestmount \
103     -a "$image" -m /dev/sda1 \
104     -o uid="$(id -u)" -o gid="$(id -g)" "$mp"
105 # To debug guestmount, add this to the end of the preceding command:
106 # -v -x & sleep 60
107
108 stage Changing into mounted directory
109 cd "$mp"
110
111 stage Checking initial files exist
112 [ -n "$(echo *)" ]
113 [ "$(ls empty hello.txt world.txt)" = "empty
114 hello.txt
115 world.txt" ]
116
117 stage Checking initial files contain expected content
118 [ "$(cat hello.txt)" = "hello" ]
119 [ "$(cat world.txt)" = "hello world" ]
120 cat empty ;# should print nothing
121 [ -z "$(cat empty)" ]
122
123 stage Checking file modes of initial content
124 [ "$(stat -c %a empty)" = "644" ]
125 [ "$(stat -c %a hello.txt)" = "644" ]
126 [ "$(stat -c %a world.txt)" = "644" ]
127
128 stage Checking sizes of initial content
129 [ "$(stat -c %s empty)" -eq 0 ]
130 [ "$(stat -c %s hello.txt)" -eq 5 ]
131 [ "$(stat -c %s world.txt)" -eq 11 ]
132
133 stage Checking unlink
134 touch new
135 rm -f new ;# force because file is "owned" by root
136
137 stage Checking symbolic link
138 ln -s hello.txt symlink
139 [ -L symlink ]
140
141 stage Checking readlink
142 [ "$(readlink symlink)" = "hello.txt" ]
143
144 stage Checking hard link
145 [ "$(stat -c %h hello.txt)" -eq 1 ]
146 ln hello.txt link
147 [ "$(stat -c %h link)" -eq 2 ]
148 [ "$(stat -c %h hello.txt)" -eq 2 ]
149 rm -f link
150 [ ! -e link ]
151
152 # This fails because of caching.  The problem is that the linked file
153 # ("hello.txt") is cached with a link count of 2.  unlink("link")
154 # invalidates the cache for "link", but _not_ for "hello.txt" which
155 # still has the now-incorrect cached value.  However there's not much
156 # we can do about this since searching for all linked inodes of a file
157 # is an O(n) operation.
158 #[ "$(stat -c %h hello.txt)" -eq 1 ]
159
160 stage Checking mkdir
161 mkdir newdir
162 [ -d newdir ]
163
164 stage Checking rmdir
165 rmdir newdir
166 [ ! -e newdir ]
167
168 stage Checking rename
169 touch old
170 mv old new
171 [ -f new ]
172 [ ! -e old ]
173 rm -f new
174
175 stage Checking chmod
176 touch new
177 chmod a+x new
178 [ -x new ]
179 chmod a-x new
180 [ ! -x new ]
181 chmod a-w new
182 [ ! -w new ]
183 chmod a+w new
184 [ -w new ]
185 chmod a-r new
186 [ ! -r new ]
187 chmod a+r new
188 [ -r new ]
189 rm -f new
190
191 stage Checking truncate
192 truncate -s 10000 truncated
193 [ "$(stat -c %s truncated)" -eq 10000 ]
194 truncate -c -s 1000 truncated
195 [ "$(stat -c %s truncated)" -eq 1000 ]
196 truncate -c -s 10 truncated
197 [ "$(stat -c %s truncated)" -eq 10 ]
198 truncate -c -s 0 truncated
199 [ "$(stat -c %s truncated)" -eq 0 ]
200 rm -f truncated
201
202 # Disabled because of RHBZ#660687 on Debian.
203 # stage Checking utimens and timestamps
204 # for ts in 12345 1234567 987654321; do
205 #     # NB: It's not possible to set the ctime with touch.
206 #     touch -a -d @$ts timestamp
207 #     [ "$(stat -c %X timestamp)" -eq $ts ]
208 #     touch -m -d @$ts timestamp
209 #     [ "$(stat -c %Y timestamp)" -eq $ts ]
210 #     touch    -d @$ts timestamp
211 #     [ "$(stat -c %X timestamp)" -eq $ts ]
212 #     [ "$(stat -c %Y timestamp)" -eq $ts ]
213 # done
214
215 stage Checking writes
216 cp hello.txt copy.txt
217 echo >> copy.txt
218 echo world >> copy.txt
219 echo bigger >> copy.txt
220 echo biggest >> copy.txt
221 [ "$(cat copy.txt)" = "hello
222 world
223 bigger
224 biggest" ]
225
226 # These ones are not yet tested by the current script:
227 #stage XXX statfs/statvfs
228 #stage XXX xattr operations
229
230 # These ones cannot easily be tested by the current script, eg because
231 # this script doesn't run as root:
232 #stage XXX fsync
233 #stage XXX chown
234 #stage XXX mknod