]> arthur.barton.de Git - bup.git/blob - t/test-meta.sh
Handle the possibility of a sgid/suid parent dir in one of the meta tests.
[bup.git] / t / test-meta.sh
1 #!/usr/bin/env bash
2 . wvtest.sh
3
4 TOP="$(pwd)"
5 export BUP_DIR="$TOP/buptest.tmp"
6
7 bup()
8 {
9     "$TOP/bup" "$@"
10 }
11
12 # Very simple metadata tests -- create a test tree then check that bup
13 # meta can reproduce the metadata correctly (according to bup xstat)
14 # via create, extract, start-extract, and finish-extract.  The current
15 # tests are crude, and this does not fully test devices, varying
16 # users/groups, acls, attrs, etc.
17
18 genstat()
19 {
20     (
21         export PATH="$TOP:$PATH" # pick up bup
22         # Skip atime (test elsewhere) to avoid the observer effect.
23         find . | sort | xargs bup xstat --exclude-fields ctime,atime,size
24     )
25 }
26
27 actually-root()
28 {
29     test "$(whoami)" == root -a -z "$FAKEROOTKEY"
30 }
31
32 force-delete()
33 {
34     if ! actually-root; then
35         rm -rf "$@"
36     else
37         # Go to greater lengths to deal with any test detritus.
38         for f in "$@"; do
39             test -e "$@" || continue
40             chattr -fR = "$@" || true
41             setfacl -Rb "$@"
42             rm -r "$@"
43         done
44     fi
45 }
46
47 compare-trees()
48 {
49     (
50         set -e
51         set -o pipefail
52         tmpfile="$(mktemp)"
53         trap "rm -rf '${tmpfile}'" EXIT
54         rsync -ni -aHAX "$1" "$2" > "${tmpfile}"
55         if test $(wc -l < "${tmpfile}") != 0; then
56             echo "ERROR: detected differences between $1 and $2"
57             cat "${tmpfile}"
58             false
59         fi
60     )
61 }
62
63 test-src-create-extract()
64 {
65     # Test bup meta create/extract for ./src -> ./src-restore.
66     # Also writes to ./src-stat and ./src-restore-stat.
67     (
68         (cd src && WVPASS genstat) > src-stat
69         WVPASS bup meta --create --recurse --file src.meta src
70         # Test extract.
71         force-delete src-restore
72         mkdir src-restore
73         cd src-restore
74         WVPASS bup meta --extract --file ../src.meta
75         WVPASS test -d src
76         (cd src && genstat >../../src-restore-stat) || WVFAIL
77         WVPASS diff -U5 ../src-stat ../src-restore-stat
78         # Test start/finish extract.
79         force-delete src
80         WVPASS bup meta --start-extract --file ../src.meta
81         WVPASS test -d src
82         WVPASS bup meta --finish-extract --file ../src.meta
83         (cd src && genstat >../../src-restore-stat) || WVFAIL
84         WVPASS diff -U5 ../src-stat ../src-restore-stat
85     )
86 }
87
88 test-src-save-restore()
89 {
90     # Test bup save/restore metadata for ./src -> ./src-restore.  Also
91     # writes to ./src.bup.  Note that for now this just tests the
92     # restore below src/, in order to avoid having to worry about
93     # operations that require root (like chown /home).
94     (
95         set -x
96         rm -rf src.bup
97         mkdir src.bup
98         export BUP_DIR=$(pwd)/src.bup
99         WVPASS bup init
100         WVPASS bup index src
101         WVPASS bup save -t -n src src
102         # Test extract.
103         force-delete src-restore
104         mkdir src-restore
105         WVPASS bup restore -C src-restore "/src/latest$(pwd)/"
106         WVPASS test -d src-restore/src
107         WVPASS compare-trees src/ src-restore/src/
108         rm -rf src.bup
109         set +x
110     )
111 }
112
113 if actually-root; then
114     umount "$TOP/bupmeta.tmp/testfs" || true
115 fi
116
117 setup-test-tree()
118 (
119     set -e
120     force-delete "$BUP_DIR"
121     force-delete "$TOP/bupmeta.tmp"
122     mkdir -p "$TOP/bupmeta.tmp/src"
123     cp -pPR Documentation cmd lib t "$TOP/bupmeta.tmp"/src
124
125     # Regression test for metadata sort order.  Previously, these two
126     # entries would sort in the wrong order because the metadata
127     # entries were being sorted by mangled name, but the index isn't.
128     dd if=/dev/zero of="$TOP/bupmeta.tmp"/src/foo bs=1k count=33
129     touch -d 2011-11-11 "$TOP/bupmeta.tmp"/src/foo
130     touch -d 2011-12-12 "$TOP/bupmeta.tmp"/src/foo-bar
131
132     t/mksock "$TOP/bupmeta.tmp/src/test-socket" || true
133 ) || WVFAIL
134
135 # Use the test tree to check bup meta.
136 WVSTART 'meta --create/--extract'
137 (
138     setup-test-tree
139     cd "$TOP/bupmeta.tmp"
140     test-src-create-extract
141
142     # Test a top-level file (not dir).
143     touch src-file
144     WVPASS bup meta -cf src-file.meta src-file
145     mkdir dest
146     cd dest
147     WVPASS bup meta -xf ../src-file.meta
148 )
149
150 # Use the test tree to check bup save/restore metadata.
151 WVSTART 'metadata save/restore (general)'
152 (
153     setup-test-tree
154     cd "$TOP/bupmeta.tmp"
155     test-src-save-restore
156 )
157
158 WVSTART 'meta --edit'
159 (
160     force-delete "$TOP/bupmeta.tmp"
161     mkdir "$TOP/bupmeta.tmp"
162     cd "$TOP/bupmeta.tmp"
163     mkdir src
164     WVPASS bup meta -cf src.meta src
165
166     WVPASS bup meta --edit --set-uid 0 src.meta | WVPASS bup meta -tvvf - \
167         | WVPASS grep -qE '^uid: 0'
168     WVPASS bup meta --edit --set-uid 1000 src.meta | WVPASS bup meta -tvvf - \
169         | WVPASS grep -qE '^uid: 1000'
170
171     WVPASS bup meta --edit --set-gid 0 src.meta | WVPASS bup meta -tvvf - \
172         | WVPASS grep -qE '^gid: 0'
173     WVPASS bup meta --edit --set-gid 1000 src.meta | WVPASS bup meta -tvvf - \
174         | WVPASS grep -qE '^gid: 1000'
175
176     WVPASS bup meta --edit --set-user foo src.meta | WVPASS bup meta -tvvf - \
177         | WVPASS grep -qE '^user: foo'
178     WVPASS bup meta --edit --set-user bar src.meta | WVPASS bup meta -tvvf - \
179         | WVPASS grep -qE '^user: bar'
180     WVPASS bup meta --edit --unset-user src.meta | WVPASS bup meta -tvvf - \
181         | WVPASS grep -qE '^user:'
182     WVPASS bup meta --edit --set-user bar --unset-user src.meta \
183         | WVPASS bup meta -tvvf - | WVPASS grep -qE '^user:'
184     WVPASS bup meta --edit --unset-user --set-user bar src.meta \
185         | WVPASS bup meta -tvvf - | WVPASS grep -qE '^user: bar'
186
187     WVPASS bup meta --edit --set-group foo src.meta | WVPASS bup meta -tvvf - \
188         | WVPASS grep -qE '^group: foo'
189     WVPASS bup meta --edit --set-group bar src.meta | WVPASS bup meta -tvvf - \
190         | WVPASS grep -qE '^group: bar'
191     WVPASS bup meta --edit --unset-group src.meta | WVPASS bup meta -tvvf - \
192         | WVPASS grep -qE '^group:'
193     WVPASS bup meta --edit --set-group bar --unset-group src.meta \
194         | WVPASS bup meta -tvvf - | WVPASS grep -qE '^group:'
195     WVPASS bup meta --edit --unset-group --set-group bar src.meta \
196         | WVPASS bup meta -tvvf - | grep -qE '^group: bar'
197 )
198
199 # Test ownership restoration (when not root or fakeroot).
200 (
201     if test "$(whoami)" == root; then
202         exit 0
203     fi
204
205     WVSTART 'metadata (restoration of ownership)'
206     force-delete "$TOP/bupmeta.tmp"
207     mkdir "$TOP/bupmeta.tmp"
208     cd "$TOP/bupmeta.tmp"
209     touch src
210     WVPASS bup meta -cf src.meta src
211
212     mkdir dest
213     cd dest
214     # Make sure we don't change (or try to change) the user when not root.
215     WVPASS bup meta --edit --set-user root ../src.meta | WVPASS bup meta -x
216     WVPASS bup xstat src | WVPASS grep -qvE '^user: root'
217     rm -rf src
218     WVPASS bup meta --edit --unset-user --set-uid 0 ../src.meta \
219         | WVPASS bup meta -x
220     WVPASS bup xstat src | grep -qvE '^user: root'
221
222     # Make sure we can restore one of the user's groups.
223     last_group="$(python -c 'import os,grp; \
224       print grp.getgrgid(os.getgroups()[0])[0]')"
225     rm -rf src
226     WVPASS bup meta --edit --set-group "$last_group" ../src.meta \
227         | WVPASS bup meta -x
228     WVPASS bup xstat src | WVPASS grep -qE "^group: $last_group"
229
230     # Make sure we can restore one of the user's gids.
231     user_gids="$(id -G)"
232     last_gid="$(echo ${user_gids/* /})"
233     rm -rf src
234     WVPASS bup meta --edit --unset-group --set-gid "$last_gid" ../src.meta \
235         | WVPASS bup meta -x
236     WVPASS bup xstat src | WVPASS grep -qE "^gid: $last_gid"
237
238     # Test --numeric-ids (gid).
239     rm -rf src
240     current_gidx=$(bup meta -tvvf ../src.meta | grep -e '^gid:')
241     WVPASS bup meta --edit --set-group "$last_group" ../src.meta \
242         | WVPASS bup meta -x --numeric-ids
243     new_gidx=$(bup xstat src | grep -e '^gid:')
244     WVPASSEQ "$current_gidx" "$new_gidx"
245
246     # Test that restoring an unknown user works.
247     unknown_user=$("$TOP"/t/unknown-owner --user)
248     rm -rf src
249     current_uidx=$(bup meta -tvvf ../src.meta | grep -e '^uid:')
250     WVPASS bup meta --edit --set-user "$unknown_user" ../src.meta \
251         | WVPASS bup meta -x
252     new_uidx=$(bup xstat src | grep -e '^uid:')
253     WVPASSEQ "$current_uidx" "$new_uidx"
254
255     # Test that restoring an unknown group works.
256     unknown_group=$("$TOP"/t/unknown-owner --group)
257     rm -rf src
258     current_gidx=$(bup meta -tvvf ../src.meta | grep -e '^gid:')
259     WVPASS bup meta --edit --set-group "$unknown_group" ../src.meta \
260         | WVPASS bup meta -x
261     new_gidx=$(bup xstat src | grep -e '^gid:')
262     WVPASSEQ "$current_gidx" "$new_gidx"
263 )
264
265 # Test ownership restoration (when root or fakeroot).
266 (
267     if test "$(whoami)" != root; then
268         exit 0
269     fi
270
271     WVSTART 'metadata (restoration of ownership as root)'
272     force-delete "$TOP/bupmeta.tmp"
273     mkdir "$TOP/bupmeta.tmp"
274     cd "$TOP/bupmeta.tmp"
275     touch src
276     chown 0:0 src # In case the parent dir is sgid, etc.
277     WVPASS bup meta -cf src.meta src
278
279     mkdir dest
280     chmod 700 dest # so we can't accidentally do something insecure
281     cd dest
282
283     # Make sure we can restore a uid.
284     WVPASS bup meta --edit --unset-user --set-uid 42 ../src.meta \
285         | WVPASS bup meta -x
286     WVPASS bup xstat src | WVPASS grep -qE '^uid: 42'
287
288     # Make sure we can restore a gid.
289     WVPASS bup meta --edit --unset-group --set-gid 42 ../src.meta \
290         | WVPASS bup meta -x
291     WVPASS bup xstat src | WVPASS grep -qE '^gid: 42'
292
293     some_user=$("$TOP"/t/some-owner --user)
294     some_group=$("$TOP"/t/some-owner --group)
295
296     # Try to restore a user (and see that user trumps uid when uid is not 0).
297     WVPASS bup meta --edit --set-uid 42 --set-user "$some_user" ../src.meta \
298         | WVPASS bup meta -x
299     WVPASS bup xstat src | WVPASS grep -qE "^user: $some_user"
300
301     # Try to restore a group (and see that group trumps gid when gid is not 0).
302     WVPASS bup meta --edit --set-gid 42 --set-group "$some_group" ../src.meta \
303         | WVPASS bup meta -x
304     WVPASS bup xstat src | WVPASS grep -qE "^group: $some_user"
305
306     # Make sure a uid of 0 trumps a non-root user.
307     WVPASS bup meta --edit --set-user "$some_user" ../src.meta \
308         | WVPASS bup meta -x
309     WVPASS bup xstat src | WVPASS grep -qvE "^user: $some_user"
310     WVPASS bup xstat src | WVPASS grep -qE "^uid: 0"
311
312     # Make sure a gid of 0 trumps a non-root group.
313     WVPASS bup meta --edit --set-group "$some_user" ../src.meta \
314         | WVPASS bup meta -x
315     WVPASS bup xstat src | WVPASS grep -qvE "^group: $some_group"
316     WVPASS bup xstat src | WVPASS grep -qE "^gid: 0"
317
318     # Test --numeric-ids (gid).  Note the name 'root' is not handled
319     # specially, so we use that here as the test group name.  We
320     # assume that the root group's gid is never 42.
321     rm -rf src
322     WVPASS bup meta --edit --set-group root --set-gid 42 ../src.meta \
323         | WVPASS bup meta -x --numeric-ids
324     new_gidx=$(bup xstat src | grep -e '^gid:')
325     WVPASSEQ "$new_gidx" 'gid: 42'
326
327     # Test --numeric-ids (uid).  Note the name 'root' is not handled
328     # specially, so we use that here as the test user name.  We assume
329     # that the root user's uid is never 42.
330     rm -rf src
331     WVPASS bup meta --edit --set-user root --set-uid 42 ../src.meta \
332         | WVPASS bup meta -x --numeric-ids
333     new_uidx=$(bup xstat src | grep -e '^uid:')
334     WVPASSEQ "$new_uidx" 'uid: 42'
335
336     # Test that restoring an unknown user works.
337     unknown_user=$("$TOP"/t/unknown-owners --user)
338     rm -rf src
339     WVPASS bup meta --edit --set-uid 42 --set-user "$unknown_user" ../src.meta \
340         | WVPASS bup meta -x
341     new_uidx=$(bup xstat src | grep -e '^uid:')
342     WVPASSEQ "$new_uidx" 'uid: 42'
343
344     # Test that restoring an unknown group works.
345     unknown_group=$("$TOP"/t/unknown-owners --group)
346     rm -rf src
347     WVPASS bup meta --edit \
348         --set-gid 42 --set-group "$unknown_group" ../src.meta \
349         | WVPASS bup meta -x
350     new_gidx=$(bup xstat src | grep -e '^gid:')
351     WVPASSEQ "$new_gidx" 'gid: 42'
352 )
353
354 # Root-only tests that require an FS with all the trimmings: ACLs,
355 # Linux attr, Linux xattr, etc.
356 if actually-root; then
357     (
358         # These tests are only likely to work under Linux for now
359         # (patches welcome).
360         [[ $(uname) =~ Linux ]] || exit 0
361
362         cleanup_at_exit()
363         {
364             cd "$TOP"
365             umount "$TOP/bupmeta.tmp/testfs" || true
366         }
367
368         trap cleanup_at_exit EXIT
369
370         WVSTART 'meta - general (as root)'
371         setup-test-tree
372         cd "$TOP/bupmeta.tmp"
373
374         umount testfs || true
375         dd if=/dev/zero of=testfs.img bs=1M count=32
376         mke2fs -F -j -m 0 testfs.img
377         mkdir testfs
378         mount -o loop,acl,user_xattr testfs.img testfs
379         # Hide, so that tests can't create risks.
380         chown root:root testfs
381         chmod 0700 testfs
382
383         #cp -a src testfs/src
384         cp -pPR src testfs/src
385         (cd testfs && test-src-create-extract)
386
387         WVSTART 'meta - atime (as root)'
388         force-delete testfs/src
389         mkdir testfs/src
390         (
391             mkdir testfs/src/foo
392             touch testfs/src/bar
393             PYTHONPATH="$TOP/lib" \
394                 python -c "from bup import xstat; \
395                 x = xstat.timespec_to_nsecs((42, 0));\
396                    xstat.utime('testfs/src/foo', (x, x));\
397                    xstat.utime('testfs/src/bar', (x, x));"
398             cd testfs
399             WVPASS bup meta -v --create --recurse --file src.meta src
400             bup meta -tvf src.meta
401             # Test extract.
402             force-delete src-restore
403             mkdir src-restore
404             cd src-restore
405             WVPASS bup meta --extract --file ../src.meta
406             WVPASSEQ "$(bup xstat --include-fields=atime src/foo)" "atime: 42"
407             WVPASSEQ "$(bup xstat --include-fields=atime src/bar)" "atime: 42"
408             # Test start/finish extract.
409             force-delete src
410             WVPASS bup meta --start-extract --file ../src.meta
411             WVPASS test -d src
412             WVPASS bup meta --finish-extract --file ../src.meta
413             WVPASSEQ "$(bup xstat --include-fields=atime src/foo)" "atime: 42"
414             WVPASSEQ "$(bup xstat --include-fields=atime src/bar)" "atime: 42"
415         )
416
417         WVSTART 'meta - Linux attr (as root)'
418         force-delete testfs/src
419         mkdir testfs/src
420         (
421             touch testfs/src/foo
422             mkdir testfs/src/bar
423             chattr +acdeijstuADST testfs/src/foo
424             chattr +acdeijstuADST testfs/src/bar
425             (cd testfs && test-src-create-extract)
426         )
427
428         WVSTART 'meta - Linux xattr (as root)'
429         force-delete testfs/src
430         mkdir testfs/src
431         (
432             touch testfs/src/foo
433             mkdir testfs/src/bar
434             attr -s foo -V bar testfs/src/foo
435             attr -s foo -V bar testfs/src/bar
436             (cd testfs && test-src-create-extract)
437         )
438
439         WVSTART 'meta - POSIX.1e ACLs (as root)'
440         force-delete testfs/src
441         mkdir testfs/src
442         (
443             touch testfs/src/foo
444             mkdir testfs/src/bar
445             setfacl -m u:root:r testfs/src/foo
446             setfacl -m u:root:r testfs/src/bar
447             (cd testfs && test-src-create-extract)
448         )
449     )
450 fi
451
452 exit 0