summaryrefslogtreecommitdiffstats
path: root/fuse/test-fuse.sh
blob: 60a32122e8ad52ab182d6671a9c669855b60d958 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
#!/bin/bash -
# libguestfs
# Copyright (C) 2009-2012 Red Hat Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

unset CDPATH
set -e
#set -v

if [ -n "$SKIP_TEST_FUSE_SH" ]; then
    echo "$0: test skipped because environment variable is set."
    exit 77
fi

if [ ! -w /dev/fuse ]; then
    echo "SKIPPING guestmount test, because there is no /dev/fuse."
    exit 77
fi

if ! setfacl --help >/dev/null 2>&1; then
    echo "SKIPPING guestmount test, because setfacl is not installed."
    exit 77
fi

if [ -z "$top_builddir" ]; then
    echo "$0: error: environment variable \$top_builddir must be set"
    exit 1
fi

nr_stages=$(grep "^stage " $0 | wc -l)

# Allow top_builddir to be a relative path, but also make it absolute,
# and move to that directory for the initial phase of the script.
top_builddir=$(cd "$top_builddir" > /dev/null; pwd)

# Paths to the other programs and files.  NB: Must be absolute paths.
guestfish="$top_builddir/fish/guestfish"
guestmount="$top_builddir/fuse/guestmount"
image="$top_builddir/fuse/test.img"
mp="$top_builddir/fuse/test-mp"

if [ ! -x "$guestfish" -o ! -x "$guestmount" ]; then
    echo "$0: error: guestfish or guestmount are not available"
    exit 1
fi

# Ensure everything is cleaned up on exit.
rm -f "$image"
mkdir -p "$mp"
fusermount -u "$mp" >/dev/null 2>&1 ||:
function cleanup ()
{
    status=$?
    set +e
    [ $status = 0 ] || echo "*** FAILED ***"
    echo "Unmounting filesystem and cleaning up."

    # Move out of the mountpoint (otherwise our cwd will prevent the
    # mountpoint from being unmounted).
    cd "$top_builddir"

    # Who's using this?  Should be no one, but see below.
    if [ -x /sbin/fuser ]; then /sbin/fuser "$mp"; fi

    # If you run this and you have GNOME running at the same time,
    # then randomly /usr/libexec/gvfs-gdu-volume-monitor will decide
    # to do whatever it does in the mountpoint directory, preventing
    # you from unmounting it!  Hence the need for this loop.
    count=10
    while ! fusermount -u "$mp" && [ $count -gt 0 ]; do
        sleep 1
        ((count--))
    done

    rm -f "$image"
    rm -rf "$mp"
    exit $status
}
trap cleanup INT TERM QUIT EXIT

s=1
function stage ()
{
    echo "test-fuse: $s/$nr_stages:" "$@" "..."
    ((s++))
}

stage Create filesystem with some initial content
$guestfish <<EOF
  sparse "$image" 10M
  run
  part-disk /dev/sda mbr
  mkfs ext2 /dev/sda1
  mount_options acl,user_xattr /dev/sda1 /
  write /hello.txt hello
  write /world.txt "hello world"
  touch /empty
  touch /user_xattr
  setxattr user.test hello123 8 /user_xattr
  touch /acl
  # XXX hack until libguestfs gets ACL support
  debug sh "setfacl -m u:500:r /sysroot/acl" | cat > /dev/null
EOF

stage Mounting the filesystem
$guestmount \
    -a "$image" -m /dev/sda1:/:acl,user_xattr \
    -o uid="$(id -u)" -o gid="$(id -g)" "$mp"
# To debug guestmount, add this to the end of the preceding command:
# -v -x & sleep 60

stage Changing into mounted directory
cd "$mp"

stage Checking initial files exist
[ -n "$(echo *)" ]
[ "$(ls empty hello.txt world.txt)" = "empty
hello.txt
world.txt" ]

stage Checking initial files contain expected content
[ "$(cat hello.txt)" = "hello" ]
[ "$(cat world.txt)" = "hello world" ]
cat empty ;# should print nothing
[ -z "$(cat empty)" ]

stage Checking file modes of initial content
[ "$(stat -c %a empty)" = "644" ]
[ "$(stat -c %a hello.txt)" = "644" ]
[ "$(stat -c %a world.txt)" = "644" ]

stage Checking sizes of initial content
[ "$(stat -c %s empty)" -eq 0 ]
[ "$(stat -c %s hello.txt)" -eq 5 ]
[ "$(stat -c %s world.txt)" -eq 11 ]

stage Checking unlink
touch new
rm -f new ;# force because file is "owned" by root

stage Checking symbolic link
ln -s hello.txt symlink
[ -L symlink ]

stage Checking readlink
[ "$(readlink symlink)" = "hello.txt" ]

stage Checking hard link
[ "$(stat -c %h hello.txt)" -eq 1 ]
ln hello.txt link
[ "$(stat -c %h link)" -eq 2 ]
[ "$(stat -c %h hello.txt)" -eq 2 ]
rm -f link
[ ! -e link ]

# This fails because of caching.  The problem is that the linked file
# ("hello.txt") is cached with a link count of 2.  unlink("link")
# invalidates the cache for "link", but _not_ for "hello.txt" which
# still has the now-incorrect cached value.  However there's not much
# we can do about this since searching for all linked inodes of a file
# is an O(n) operation.
#[ "$(stat -c %h hello.txt)" -eq 1 ]

stage Checking mkdir
mkdir newdir
[ -d newdir ]

stage Checking rmdir
rmdir newdir
[ ! -e newdir ]

stage Checking rename
touch old
mv old new
[ -f new ]
[ ! -e old ]
rm -f new

stage Checking chmod
touch new
chmod a+x new
[ -x new ]
chmod a-x new
[ ! -x new ]
chmod a-w new
[ ! -w new ]
chmod a+w new
[ -w new ]
chmod a-r new
[ ! -r new ]
chmod a+r new
[ -r new ]
rm -f new

stage Checking truncate
# RHEL 5 didn't have the truncate command.
if truncate --help >/dev/null 2>&1; then
    truncate -s 10000 truncated
    [ "$(stat -c %s truncated)" -eq 10000 ]
    truncate -c -s 1000 truncated
    [ "$(stat -c %s truncated)" -eq 1000 ]
    truncate -c -s 10 truncated
    [ "$(stat -c %s truncated)" -eq 10 ]
    truncate -c -s 0 truncated
    [ "$(stat -c %s truncated)" -eq 0 ]
    rm -f truncated
fi

# Disabled because of RHBZ#660687 on Debian.
# stage Checking utimens and timestamps
# for ts in 12345 1234567 987654321; do
#     # NB: It's not possible to set the ctime with touch.
#     touch -a -d @$ts timestamp
#     [ "$(stat -c %X timestamp)" -eq $ts ]
#     touch -m -d @$ts timestamp
#     [ "$(stat -c %Y timestamp)" -eq $ts ]
#     touch    -d @$ts timestamp
#     [ "$(stat -c %X timestamp)" -eq $ts ]
#     [ "$(stat -c %Y timestamp)" -eq $ts ]
# done

stage Checking writes
cp hello.txt copy.txt
echo >> copy.txt
echo world >> copy.txt
echo bigger >> copy.txt
echo biggest >> copy.txt
[ "$(cat copy.txt)" = "hello
world
bigger
biggest" ]

stage 'Checking extended attribute (xattr) read operation'
if getfattr --help > /dev/null 2>&1 ; then
  [ "$(getfattr -d user_xattr | grep -v ^#)" = 'user.test="hello123"' ]
fi

stage Checking POSIX ACL read operation
if getfacl --help > /dev/null 2>&1 ; then
  [ "$(getfacl -n acl | grep -v ^#)" = "user::rw-
user:500:r--
group::r--
mask::r--
other::r--" ]
fi

# These ones are not yet tested by the current script:
#stage XXX statfs/statvfs

# These ones cannot easily be tested by the current script, eg because
# this script doesn't run as root:
#stage XXX fsync
#stage XXX chown
#stage XXX mknod