]> git.ipfire.org Git - thirdparty/systemd.git/blame - test/test-functions
Merge pull request #12066 from yuwata/fix-network-tunnel-12041
[thirdparty/systemd.git] / test / test-functions
CommitLineData
898720b7
HH
1#!/bin/bash
2# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
3# ex: ts=8 sw=4 sts=4 et filetype=sh
4PATH=/sbin:/bin:/usr/sbin:/usr/bin
5export PATH
6
c2f32f61
SLM
7LOOKS_LIKE_DEBIAN=$(source /etc/os-release && [[ "$ID" = "debian" || " $ID_LIKE " = *" debian "* ]] && echo yes || true)
8LOOKS_LIKE_ARCH=$(source /etc/os-release && [[ "$ID" = "arch" || " $ID_LIKE " = *" arch "* ]] && echo yes || true)
9LOOKS_LIKE_SUSE=$(source /etc/os-release && [[ " $ID_LIKE " = *" suse "* ]] && echo yes || true)
0d6e798a
HH
10KERNEL_VER=${KERNEL_VER-$(uname -r)}
11KERNEL_MODS="/lib/modules/$KERNEL_VER/"
91f9f8f1 12QEMU_TIMEOUT="${QEMU_TIMEOUT:-infinity}"
43bbb8f0 13NSPAWN_TIMEOUT="${NSPAWN_TIMEOUT:-infinity}"
b2ecd099 14TIMED_OUT= # will be 1 after run_* if *_TIMEOUT is set and test timed out
4b742c8a 15[[ "$LOOKS_LIKE_SUSE" ]] && FSTYPE="${FSTYPE:-btrfs}" || FSTYPE="${FSTYPE:-ext4}"
22f1f8f2 16UNIFIED_CGROUP_HIERARCHY="${UNIFIED_CGROUP_HIERARCHY:-default}"
7624e721 17EFI_MOUNT="$(bootctl -p 2>/dev/null || echo /boot)"
3071b3ff 18QEMU_MEM="${QEMU_MEM:-512M}"
898720b7 19
3486cb6c
MP
20if ! ROOTLIBDIR=$(pkg-config --variable=systemdutildir systemd); then
21 echo "WARNING! Cannot determine rootlibdir from pkg-config, assuming /usr/lib/systemd" >&2
22 ROOTLIBDIR=/usr/lib/systemd
23fi
24
016fa3b9
EV
25PATH_TO_INIT=$ROOTLIBDIR/systemd
26
1e460470 27BASICTOOLS="test sh bash setsid loadkeys setfont login sulogin gzip sleep echo head tail cat mount umount cryptsetup date dmsetup modprobe sed cmp tee rm true false chmod chown ln xargs"
c81a46b9 28DEBUGTOOLS="df free ls stty ps ln ip route dmesg dhclient mkdir cp ping dhclient strace less grep id tty touch du sort hostname find vi mv"
889a9042 29
22077c9c
MP
30STATEDIR="${BUILD_DIR:-.}/test/$(basename $(dirname $(realpath $0)))"
31STATEFILE="$STATEDIR/.testdir"
32TESTLOG="$STATEDIR/test.log"
33
ec9181d2
EV
34is_built_with_asan() {
35 if ! type -P objdump >/dev/null; then
36 ddebug "Failed to find objdump. Assuming systemd hasn't been built with ASAN."
37 return 1
38 fi
39
40 # Borrowed from https://github.com/google/oss-fuzz/blob/cd9acd02f9d3f6e80011cc1e9549be526ce5f270/infra/base-images/base-runner/bad_build_check#L182
b4a450d8 41 local _asan_calls=$(objdump -dC $BUILD_DIR/systemd-journald | egrep "callq\s+[0-9a-f]+\s+<__asan" -c)
ec9181d2
EV
42 if (( $_asan_calls < 1000 )); then
43 return 1
44 else
45 return 0
46 fi
47}
48
49IS_BUILT_WITH_ASAN=$(is_built_with_asan && echo yes || echo no)
50
51if [[ "$IS_BUILT_WITH_ASAN" = "yes" ]]; then
52 STRIP_BINARIES=no
016fa3b9
EV
53 SKIP_INITRD=yes
54 PATH_TO_INIT=$ROOTLIBDIR/systemd-under-asan
670bec2b 55 QEMU_MEM="1536M"
5b2172ee 56 QEMU_SMP=4
ec9181d2
EV
57fi
58
c6a77179 59function find_qemu_bin() {
3e7aa2ed
LP
60 # SUSE and Red Hat call the binary qemu-kvm. Debian and Gentoo call it kvm.
61 # Either way, only use this version if we aren't running in KVM, because
62 # nested KVM is flaky still.
b43c2c01 63 if [[ $(systemd-detect-virt -v) != kvm && -z $TEST_NO_KVM ]] ; then
3e7aa2ed
LP
64 [ "$QEMU_BIN" ] || QEMU_BIN=$(which -a kvm qemu-kvm 2>/dev/null | grep '^/' -m1)
65 fi
c6a77179
RC
66
67 [ "$ARCH" ] || ARCH=$(uname -m)
68 case $ARCH in
69 x86_64)
70 # QEMU's own build system calls it qemu-system-x86_64
71 [ "$QEMU_BIN" ] || QEMU_BIN=$(which -a qemu-system-x86_64 2>/dev/null | grep '^/' -m1)
72 ;;
73 i*86)
74 # new i386 version of QEMU
75 [ "$QEMU_BIN" ] || QEMU_BIN=$(which -a qemu-system-i386 2>/dev/null | grep '^/' -m1)
76
77 # i386 version of QEMU
78 [ "$QEMU_BIN" ] || QEMU_BIN=$(which -a qemu 2>/dev/null | grep '^/' -m1)
79 ;;
cf5f9bb8
ZJS
80 ppc64*)
81 [ "$QEMU_BIN" ] || QEMU_BIN=$(which -a qemu-system-$ARCH 2>/dev/null | grep '^/' -m1)
82 ;;
c6a77179
RC
83 esac
84
85 if [ ! -e "$QEMU_BIN" ]; then
86 echo "Could not find a suitable QEMU binary" >&2
87 return 1
88 fi
89}
90
b2ecd099
MP
91# Return 0 if QEMU did run (then you must check the result state/logs for actual
92# success), or 1 if QEMU is not available.
889a9042 93run_qemu() {
b6f0c419
HH
94 if [ -f /etc/machine-id ]; then
95 read MACHINE_ID < /etc/machine-id
906bbac4
ZJS
96 [ -z "$INITRD" ] && [ -e "$EFI_MOUNT/$MACHINE_ID/$KERNEL_VER/initrd" ] \
97 && INITRD="$EFI_MOUNT/$MACHINE_ID/$KERNEL_VER/initrd"
98 [ -z "$KERNEL_BIN" ] && [ -e "$EFI_MOUNT/$MACHINE_ID/$KERNEL_VER/linux" ] \
99 && KERNEL_BIN="$EFI_MOUNT/$MACHINE_ID/$KERNEL_VER/linux"
b6f0c419
HH
100 fi
101
9a2e265b
DJL
102 CONSOLE=ttyS0
103
e1a27318
EV
104 if [[ ! "$KERNEL_BIN" ]]; then
105 if [[ "$LOOKS_LIKE_ARCH" ]]; then
106 KERNEL_BIN=/boot/vmlinuz-linux
107 else
eaa602cb
DJL
108 [ "$ARCH" ] || ARCH=$(uname -m)
109 case $ARCH in
110 ppc64*)
111 KERNEL_BIN=/boot/vmlinux-$KERNEL_VER
9a2e265b 112 CONSOLE=hvc0
eaa602cb
DJL
113 ;;
114 *)
115 KERNEL_BIN=/boot/vmlinuz-$KERNEL_VER
116 ;;
117 esac
e1a27318
EV
118 fi
119 fi
120
61fea35e
EV
121 default_fedora_initrd=/boot/initramfs-${KERNEL_VER}.img
122 default_debian_initrd=/boot/initrd.img-${KERNEL_VER}
19632f6d 123 default_arch_initrd=/boot/initramfs-linux-fallback.img
85393d8f 124 default_suse_initrd=/boot/initrd-${KERNEL_VER}
e1a27318
EV
125 if [[ ! "$INITRD" ]]; then
126 if [[ -e "$default_fedora_initrd" ]]; then
127 INITRD="$default_fedora_initrd"
128 elif [[ "$LOOKS_LIKE_DEBIAN" && -e "$default_debian_initrd" ]]; then
129 INITRD="$default_debian_initrd"
130 elif [[ "$LOOKS_LIKE_ARCH" && -e "$default_arch_initrd" ]]; then
131 INITRD="$default_arch_initrd"
85393d8f
TB
132 elif [[ "$LOOKS_LIKE_SUSE" && -e "$default_suse_initrd" ]]; then
133 INITRD="$default_suse_initrd"
e1a27318
EV
134 fi
135 fi
136
5bfb2a93
FS
137 # If QEMU_SMP was not explicitly set, try to determine the value 'dynamically'
138 # i.e. use the number of online CPUs on the host machine. If the nproc utility
139 # is not installed or there's some other error when calling it, fall back
140 # to the original value (QEMU_SMP=1).
141 if ! [ "$QEMU_SMP" ]; then
142 if ! QEMU_SMP=$(nproc); then
143 dwarn "nproc utility is not installed, falling back to QEMU_SMP=1"
144 QEMU_SMP=1
145 fi
146 fi
c6a77179
RC
147
148 find_qemu_bin || return 1
149
22f1f8f2
EV
150 local _cgroup_args
151 if [[ "$UNIFIED_CGROUP_HIERARCHY" = "yes" ]]; then
152 _cgroup_args="systemd.unified_cgroup_hierarchy=yes"
153 elif [[ "$UNIFIED_CGROUP_HIERARCHY" = "no" ]]; then
154 _cgroup_args="systemd.unified_cgroup_hierarchy=no systemd.legacy_systemd_cgroup_controller=yes"
155 elif [[ "$UNIFIED_CGROUP_HIERARCHY" = "hybrid" ]]; then
156 _cgroup_args="systemd.unified_cgroup_hierarchy=no systemd.legacy_systemd_cgroup_controller=no"
157 elif [[ "$UNIFIED_CGROUP_HIERARCHY" != "default" ]]; then
158 dfatal "Unknown UNIFIED_CGROUP_HIERARCHY. Got $UNIFIED_CGROUP_HIERARCHY, expected [yes|no|hybrid|default]"
159 exit 1
160 fi
161
85393d8f
TB
162if [[ "$LOOKS_LIKE_SUSE" ]]; then
163 PARAMS+="rd.hostonly=0"
0ae4456c
FS
164elif [[ "$LOOKS_LIKE_ARCH" ]]; then
165 PARAMS+="rw"
85393d8f
TB
166else
167 PARAMS+="ro"
168fi
169
170KERNEL_APPEND="$PARAMS \
171root=/dev/sda1 \
c6a77179
RC
172raid=noautodetect \
173loglevel=2 \
016fa3b9 174init=$PATH_TO_INIT \
9a2e265b 175console=$CONSOLE \
c6a77179 176selinux=0 \
b2ad25d3 177printk.devkmsg=on \
22f1f8f2 178$_cgroup_args \
c6a77179
RC
179$KERNEL_APPEND \
180"
181
dbf43a42 182 QEMU_OPTIONS="-smp $QEMU_SMP \
c6a77179 183-net none \
3071b3ff 184-m $QEMU_MEM \
c6a77179
RC
185-nographic \
186-kernel $KERNEL_BIN \
5b23cef0 187-drive format=raw,cache=unsafe,file=${TESTDIR}/rootdisk.img \
c6a77179
RC
188"
189
91f9f8f1 190 if [[ "$INITRD" && "$SKIP_INITRD" != "yes" ]]; then
c6a77179
RC
191 QEMU_OPTIONS="$QEMU_OPTIONS -initrd $INITRD"
192 fi
193
3e7aa2ed 194 # Let's use KVM if it is available, but let's avoid using nested KVM as that is still flaky
b43c2c01 195 if [[ -c /dev/kvm && $(systemd-detect-virt -v) != kvm && -z $TEST_NO_KVM ]] ; then
dbf43a42
DM
196 QEMU_OPTIONS="$QEMU_OPTIONS -machine accel=kvm -enable-kvm -cpu host"
197 fi
198
91f9f8f1
EV
199 if [[ "$QEMU_TIMEOUT" != "infinity" ]]; then
200 QEMU_BIN="timeout --foreground $QEMU_TIMEOUT $QEMU_BIN"
201 fi
b2ecd099
MP
202 (set -x; $QEMU_BIN $QEMU_OPTIONS -append "$KERNEL_APPEND")
203 rc=$?
204 if [ "$rc" = 124 ] && [ "$QEMU_TIMEOUT" != "infinity" ]; then
205 derror "test timed out after $QEMU_TIMEOUT s"
206 TIMED_OUT=1
207 else
208 [ "$rc" != 0 ] && derror "QEMU failed with exit code $rc"
209 fi
210 return 0
889a9042
RC
211}
212
7cad32bb
MP
213# Return 0 if nspawn did run (then you must check the result state/logs for actual
214# success), or 1 if nspawn is not available.
889a9042 215run_nspawn() {
7cad32bb
MP
216 [[ -d /run/systemd/system ]] || return 1
217
746fbd9c 218 local _nspawn_cmd="$BUILD_DIR/systemd-nspawn $NSPAWN_ARGUMENTS --register=no --kill-signal=SIGKILL --directory=$TESTDIR/$1 $PATH_TO_INIT $KERNEL_APPEND"
43bbb8f0
EV
219 if [[ "$NSPAWN_TIMEOUT" != "infinity" ]]; then
220 _nspawn_cmd="timeout --foreground $NSPAWN_TIMEOUT $_nspawn_cmd"
221 fi
856ca72b 222
22f1f8f2
EV
223 if [[ "$UNIFIED_CGROUP_HIERARCHY" = "hybrid" ]]; then
224 dwarn "nspawn doesn't support UNIFIED_CGROUP_HIERARCHY=hybrid, skipping"
225 exit
226 elif [[ "$UNIFIED_CGROUP_HIERARCHY" = "yes" || "$UNIFIED_CGROUP_HIERARCHY" = "no" ]]; then
227 _nspawn_cmd="env UNIFIED_CGROUP_HIERARCHY=$UNIFIED_CGROUP_HIERARCHY $_nspawn_cmd"
228 elif [[ "$UNIFIED_CGROUP_HIERARCHY" = "default" ]]; then
229 _nspawn_cmd="env --unset=UNIFIED_CGROUP_HIERARCHY $_nspawn_cmd"
230 else
231 dfatal "Unknown UNIFIED_CGROUP_HIERARCHY. Got $UNIFIED_CGROUP_HIERARCHY, expected [yes|no|hybrid|default]"
232 exit 1
233 fi
856ca72b 234
b2ecd099
MP
235 (set -x; $_nspawn_cmd)
236 rc=$?
237 if [ "$rc" = 124 ] && [ "$NSPAWN_TIMEOUT" != "infinity" ]; then
238 derror "test timed out after $NSPAWN_TIMEOUT s"
239 TIMED_OUT=1
240 else
241 [ "$rc" != 0 ] && derror "nspawn failed with exit code $rc"
242 fi
243 return 0
889a9042
RC
244}
245
246setup_basic_environment() {
247 # create the basic filesystem layout
248 setup_basic_dirs
249
250 install_systemd
251 install_missing_libraries
252 install_config_files
253 create_rc_local
254 install_basic_tools
255 install_libnss
256 install_pam
257 install_dbus
258 install_fonts
259 install_keymaps
260 install_terminfo
261 install_execs
9974ff63 262 install_fsck
889a9042
RC
263 install_plymouth
264 install_debug_tools
265 install_ld_so_conf
e3ce42e7 266 setup_selinux
889a9042
RC
267 strip_binaries
268 install_depmod_files
269 generate_module_dependencies
ec9181d2
EV
270 if [[ "$IS_BUILT_WITH_ASAN" = "yes" ]]; then
271 create_asan_wrapper
272 fi
889a9042
RC
273}
274
e3ce42e7
EV
275setup_selinux() {
276 # don't forget KERNEL_APPEND='... selinux=1 ...'
277 if [[ "$SETUP_SELINUX" != "yes" ]]; then
278 ddebug "Don't setup SELinux"
279 return 0
280 fi
281 ddebug "Setup SELinux"
282 local _conf_dir=/etc/selinux
283 local _fixfiles_tools="bash uname cat sort uniq awk grep egrep head expr find rm secon setfiles"
284
285 rm -rf $initdir/$_conf_dir
286 if ! cp -ar $_conf_dir $initdir/$_conf_dir; then
287 dfatal "Failed to copy $_conf_dir"
288 exit 1
289 fi
290
291 cat <<EOF >$initdir/etc/systemd/system/autorelabel.service
292[Unit]
293Description=Relabel all filesystems
294DefaultDependencies=no
295Requires=local-fs.target
296Conflicts=shutdown.target
297After=local-fs.target
298Before=sysinit.target shutdown.target
299ConditionSecurity=selinux
300ConditionPathExists=|/.autorelabel
301
302[Service]
303ExecStart=/bin/sh -x -c 'echo 0 >/sys/fs/selinux/enforce && fixfiles -f -F relabel && rm /.autorelabel && systemctl --force reboot'
304Type=oneshot
305TimeoutSec=0
306RemainAfterExit=yes
307EOF
308
309 touch $initdir/.autorelabel
310 mkdir -p $initdir/etc/systemd/system/basic.target.wants
311 ln -fs autorelabel.service $initdir/etc/systemd/system/basic.target.wants/autorelabel.service
312
313 dracut_install $_fixfiles_tools
314 dracut_install fixfiles
315 dracut_install sestatus
316}
317
a2fbff31
EV
318install_valgrind() {
319 if ! type -p valgrind; then
320 dfatal "Failed to install valgrind"
321 exit 1
322 fi
323
324 local _valgrind_bins=$(strace -e execve valgrind /bin/true 2>&1 >/dev/null | perl -lne 'print $1 if /^execve\("([^"]+)"/')
325 dracut_install $_valgrind_bins
326
327 local _valgrind_libs=$(LD_DEBUG=files valgrind /bin/true 2>&1 >/dev/null | perl -lne 'print $1 if m{calling init: (/.*vgpreload_.*)}')
328 dracut_install $_valgrind_libs
329
330 local _valgrind_dbg_and_supp=$(
331 strace -e open valgrind /bin/true 2>&1 >/dev/null |
332 perl -lne 'if (my ($fname) = /^open\("([^"]+).*= (?!-)\d+/) { print $fname if $fname =~ /debug|\.supp$/ }'
333 )
334 dracut_install $_valgrind_dbg_and_supp
335}
336
cb2f9d3f
EV
337create_valgrind_wrapper() {
338 local _valgrind_wrapper=$initdir/$ROOTLIBDIR/systemd-under-valgrind
339 ddebug "Create $_valgrind_wrapper"
340 cat >$_valgrind_wrapper <<EOF
341#!/bin/bash
342
23cabb68 343mount -t proc proc /proc
cb2f9d3f
EV
344exec valgrind --leak-check=full --log-file=/valgrind.out $ROOTLIBDIR/systemd "\$@"
345EOF
346 chmod 0755 $_valgrind_wrapper
347}
348
1786fae3
EV
349create_asan_wrapper() {
350 local _asan_wrapper=$initdir/$ROOTLIBDIR/systemd-under-asan
351 ddebug "Create $_asan_wrapper"
352 cat >$_asan_wrapper <<EOF
353#!/bin/bash
354
355set -x
356
357DEFAULT_ASAN_OPTIONS=strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1
a19f909b
EV
358DEFAULT_UBSAN_OPTIONS=print_stacktrace=1:print_summary=1:halt_on_error=1
359DEFAULT_ENVIRONMENT="ASAN_OPTIONS=\$DEFAULT_ASAN_OPTIONS UBSAN_OPTIONS=\$DEFAULT_UBSAN_OPTIONS"
1786fae3
EV
360
361mount -t proc proc /proc
362mount -t sysfs sysfs /sys
363mount -o remount,rw /
364
365PATH_TO_ASAN=\$(find / -name '*libasan*' | sed 1q)
366if [[ "\$PATH_TO_ASAN" ]]; then
367 # A lot of services (most notably dbus) won't start without preloading libasan
368 # See https://github.com/systemd/systemd/issues/5004
369 DEFAULT_ENVIRONMENT="\$DEFAULT_ENVIRONMENT LD_PRELOAD=\$PATH_TO_ASAN"
370fi
371echo DefaultEnvironment=\$DEFAULT_ENVIRONMENT >>/etc/systemd/system.conf
9688fccc 372echo DefaultTimeoutStartSec=180s >>/etc/systemd/system.conf
1786fae3
EV
373
374# ASAN and syscall filters aren't compatible with each other.
375find / -name '*.service' -type f | xargs sed -i 's/^\\(MemoryDeny\\|SystemCall\\)/#\\1/'
376
88ed0f26
EV
377# The redirection of ASAN reports to a file prevents them from ending up in /dev/null.
378# But, apparently, sometimes it doesn't work: https://github.com/google/sanitizers/issues/886.
379JOURNALD_CONF_DIR=/etc/systemd/system/systemd-journald.service.d
380mkdir -p "\$JOURNALD_CONF_DIR"
381printf "[Service]\nEnvironment=ASAN_OPTIONS=\$DEFAULT_ASAN_OPTIONS:log_path=/systemd-journald.asan.log\n" >"\$JOURNALD_CONF_DIR/env.conf"
382
082bcdca
EV
383# 90s isn't enough for some services to finish when literally everything is run
384# under ASan+UBSan in containers, which, in turn, are run in VMs.
d7283fc1 385# Let's limit which environments such services should be executed in.
082bcdca 386mkdir -p /etc/systemd/system/systemd-hwdb-update.service.d
d7283fc1 387printf "[Unit]\nConditionVirtualization=container\n\n[Service]\nTimeoutSec=180s\n" >/etc/systemd/system/systemd-hwdb-update.service.d/env-override.conf
082bcdca 388
c1342d55 389export ASAN_OPTIONS=\$DEFAULT_ASAN_OPTIONS:log_path=/systemd.asan.log UBSAN_OPTIONS=\$DEFAULT_UBSAN_OPTIONS
1786fae3
EV
390exec $ROOTLIBDIR/systemd "\$@"
391EOF
392
393 chmod 0755 $_asan_wrapper
394}
395
45dbd7b6
EV
396create_strace_wrapper() {
397 local _strace_wrapper=$initdir/$ROOTLIBDIR/systemd-under-strace
398 ddebug "Create $_strace_wrapper"
399 cat >$_strace_wrapper <<EOF
400#!/bin/bash
401
402exec strace -D -o /strace.out $ROOTLIBDIR/systemd "\$@"
403EOF
404 chmod 0755 $_strace_wrapper
405}
406
9974ff63
EV
407install_fsck() {
408 dracut_install /sbin/fsck*
409 dracut_install -o /bin/fsck*
331fb4ca
EV
410
411 # fskc.reiserfs calls reiserfsck. so, install it
412 dracut_install -o reiserfsck
9974ff63
EV
413}
414
889a9042
RC
415install_dmevent() {
416 instmods dm_crypt =crypto
417 type -P dmeventd >/dev/null && dracut_install dmeventd
418 inst_libdir_file "libdevmapper-event.so*"
ac289ce3
EV
419 if [[ "$LOOKS_LIKE_DEBIAN" ]]; then
420 # dmsetup installs 55-dm and 60-persistent-storage-dm on Debian/Ubuntu
9c869ff6
DJL
421 # and since buster/bionic 95-dm-notify.rules
422 # see https://gitlab.com/debian-lvm/lvm2/blob/master/debian/patches/udev.patch
423 inst_rules 55-dm.rules 60-persistent-storage-dm.rules 95-dm-notify.rules
ac289ce3
EV
424 else
425 inst_rules 10-dm.rules 13-dm-disk.rules 95-dm-notify.rules
426 fi
889a9042
RC
427}
428
429install_systemd() {
430 # install compiled files
ca992ecf
EV
431 local _ninja_bin=$(type -P ninja || type -P ninja-build)
432 if [[ -z "$_ninja_bin" ]]; then
433 dfatal "ninja was not found"
434 exit 1
435 fi
436 (set -x; DESTDIR=$initdir "$_ninja_bin" -C $BUILD_DIR install)
889a9042 437 # remove unneeded documentation
23756070 438 rm -fr $initdir/usr/share/{man,doc}
889a9042
RC
439 # we strip binaries since debug symbols increase binaries size a lot
440 # and it could fill the available space
441 strip_binaries
61b480b6 442
85393d8f
TB
443 [[ "$LOOKS_LIKE_SUSE" ]] && setup_suse
444
61b480b6
ZJS
445 # enable debug logging in PID1
446 echo LogLevel=debug >> $initdir/etc/systemd/system.conf
889a9042
RC
447}
448
d7a4278d
FS
449get_ldpath() {
450 local _bin="$1"
451 objdump -p "$_bin" 2>/dev/null | awk "/R(UN)?PATH/ { print \"$initdir\" \$2 }" | paste -sd :
452}
453
889a9042
RC
454install_missing_libraries() {
455 # install possible missing libraries
e3d3dada 456 for i in $initdir{,/usr}/{sbin,bin}/* $initdir{,/usr}/lib/systemd/{,tests/{,manual/,unsafe/}}*; do
d7a4278d 457 LD_LIBRARY_PATH=$(get_ldpath $i) inst_libs $i
889a9042
RC
458 done
459}
460
461create_empty_image() {
28c7474e
EV
462 local _size=500
463 if [[ "$STRIP_BINARIES" = "no" ]]; then
464 _size=$((2*_size))
465 fi
739d81dd 466 rm -f "$TESTDIR/rootdisk.img"
889a9042 467 # Create the blank file to use as a root filesystem
28c7474e 468 dd if=/dev/null of="$TESTDIR/rootdisk.img" bs=1M seek="$_size"
889a9042 469 LOOPDEV=$(losetup --show -P -f $TESTDIR/rootdisk.img)
739d81dd 470 [ -b "$LOOPDEV" ] || return 1
889a9042 471 echo "LOOPDEV=$LOOPDEV" >> $STATEFILE
edbced8a 472 sfdisk "$LOOPDEV" <<EOF
32983312 473,$((_size-50))M
889a9042
RC
474,
475EOF
476
053edc5b
EV
477 udevadm settle
478
331fb4ca
EV
479 local _label="-L systemd"
480 # mkfs.reiserfs doesn't know -L. so, use --label instead
481 [[ "$FSTYPE" == "reiserfs" ]] && _label="--label systemd"
482 if ! mkfs -t "${FSTYPE}" ${_label} "${LOOPDEV}p1" -q; then
483 dfatal "Failed to mkfs -t ${FSTYPE}"
484 exit 1
485 fi
889a9042
RC
486}
487
0d6e61d6
EV
488check_asan_reports() {
489 local ret=0
490 local root="$1"
491
7e11a95e 492 if [[ "$IS_BUILT_WITH_ASAN" = "yes" ]]; then
0d6e61d6
EV
493 ls -l "$root"
494 if [[ -e "$root/systemd.asan.log.1" ]]; then
495 cat "$root/systemd.asan.log.1"
7e11a95e
EV
496 ret=$(($ret+1))
497 fi
998445fd 498
d56db495
EV
499 journald_report=$(find "$root" -name "systemd-journald.asan.log*" -exec cat {} \;)
500 if [[ ! -z "$journald_report" ]]; then
998445fd
EV
501 printf "%s" "$journald_report"
502 ret=$(($ret+1))
d56db495 503 fi
ed4f303f 504
d56db495
EV
505 pids=$(
506 "$BUILD_DIR/journalctl" -D "$root/var/log/journal" | perl -alne '
507 BEGIN {
508 %services_to_ignore = (
509 "dbus-daemon" => undef,
510 );
511 }
6d67286f 512 print $2 if /\s(\S*)\[(\d+)\]:\s*SUMMARY:\s+\w+Sanitizer/ && !exists $services_to_ignore{$1}'
d56db495
EV
513 )
514 if [[ ! -z "$pids" ]]; then
ed4f303f
EV
515 ret=$(($ret+1))
516 for pid in $pids; do
0d6e61d6 517 "$BUILD_DIR/journalctl" -D "$root/var/log/journal" _PID=$pid --no-pager
ed4f303f 518 done
d56db495 519 fi
7e11a95e
EV
520 fi
521
889a9042
RC
522 return $ret
523}
524
0d6e61d6
EV
525check_result_nspawn() {
526 local ret=1
527 local journald_report=""
528 local pids=""
529 [[ -e $TESTDIR/$1/testok ]] && ret=0
530 [[ -f $TESTDIR/$1/failed ]] && cp -a $TESTDIR/$1/failed $TESTDIR
531 cp -a $TESTDIR/$1/var/log/journal $TESTDIR
532 [[ -f $TESTDIR/failed ]] && cat $TESTDIR/failed
533 ls -l $TESTDIR/journal/*/*.journal
534 test -s $TESTDIR/failed && ret=$(($ret+1))
535 [ -n "$TIMED_OUT" ] && ret=$(($ret+1))
536 check_asan_reports "$TESTDIR/$1" || ret=$(($ret+1))
537 return $ret
538}
539
054ee249
MP
540# can be overridden in specific test
541check_result_qemu() {
0013fac2 542 local ret=1
054ee249
MP
543 mkdir -p $TESTDIR/root
544 mount ${LOOPDEV}p1 $TESTDIR/root
545 [[ -e $TESTDIR/root/testok ]] && ret=0
546 [[ -f $TESTDIR/root/failed ]] && cp -a $TESTDIR/root/failed $TESTDIR
547 cp -a $TESTDIR/root/var/log/journal $TESTDIR
0d6e61d6 548 check_asan_reports "$TESTDIR/root" || ret=$(($ret+1))
054ee249
MP
549 umount $TESTDIR/root
550 [[ -f $TESTDIR/failed ]] && cat $TESTDIR/failed
551 ls -l $TESTDIR/journal/*/*.journal
552 test -s $TESTDIR/failed && ret=$(($ret+1))
553 [ -n "$TIMED_OUT" ] && ret=$(($ret+1))
554 return $ret
555}
556
889a9042 557strip_binaries() {
5a613464
EV
558 if [[ "$STRIP_BINARIES" = "no" ]]; then
559 ddebug "Don't strip binaries"
560 return 0
561 fi
889a9042
RC
562 ddebug "Strip binaries"
563 find "$initdir" -executable -not -path '*/lib/modules/*.ko' -type f | xargs strip --strip-unneeded | ddebug
564}
565
566create_rc_local() {
567 mkdir -p $initdir/etc/rc.d
568 cat >$initdir/etc/rc.d/rc.local <<EOF
569#!/bin/bash
570exit 0
571EOF
572 chmod 0755 $initdir/etc/rc.d/rc.local
573}
574
575install_execs() {
c7eda013
EV
576 ddebug "install any Execs from the service files"
577 (
209f4b9e 578 export PKG_CONFIG_PATH=$BUILD_DIR/src/core/
c7eda013
EV
579 systemdsystemunitdir=$(pkg-config --variable=systemdsystemunitdir systemd)
580 systemduserunitdir=$(pkg-config --variable=systemduserunitdir systemd)
fe4bd4e5 581 sed -r -n 's|^Exec[a-zA-Z]*=[@+!-]*([^ ]+).*|\1|gp' $initdir/{$systemdsystemunitdir,$systemduserunitdir}/*.service \
e180bdb5 582 | sort -u | while read i; do
818567fc 583 # some {rc,halt}.local scripts and programs are okay to not exist, the rest should
e4e039bc
FS
584 # also, plymouth is pulled in by rescue.service, but even there the exit code
585 # is ignored; as it's not present on some distros, don't fail if it doesn't exist
586 inst $i || [ "${i%.local}" != "$i" ] || [ "${i%systemd-update-done}" != "$i" ] || [ "/bin/plymouth" == "$i" ]
c7eda013
EV
587 done
588 )
889a9042
RC
589}
590
591generate_module_dependencies() {
592 if [[ -d $initdir/lib/modules/$KERNEL_VER ]] && \
593 ! depmod -a -b "$initdir" $KERNEL_VER; then
594 dfatal "\"depmod -a $KERNEL_VER\" failed."
595 exit 1
596 fi
597}
598
599install_depmod_files() {
600 inst /lib/modules/$KERNEL_VER/modules.order
601 inst /lib/modules/$KERNEL_VER/modules.builtin
602}
603
604install_plymouth() {
605 # install plymouth, if found... else remove plymouth service files
606 # if [ -x /usr/libexec/plymouth/plymouth-populate-initrd ]; then
607 # PLYMOUTH_POPULATE_SOURCE_FUNCTIONS="$TEST_BASE_DIR/test-functions" \
608 # /usr/libexec/plymouth/plymouth-populate-initrd -t $initdir
609 # dracut_install plymouth plymouthd
610 # else
611 rm -f $initdir/{usr/lib,etc}/systemd/system/plymouth* $initdir/{usr/lib,etc}/systemd/system/*/plymouth*
612 # fi
613}
614
615install_ld_so_conf() {
616 cp -a /etc/ld.so.conf* $initdir/etc
617 ldconfig -r "$initdir"
618}
619
620install_config_files() {
818567fc 621 inst /etc/sysconfig/init || true
889a9042
RC
622 inst /etc/passwd
623 inst /etc/shadow
bf3a947c 624 inst /etc/login.defs
889a9042
RC
625 inst /etc/group
626 inst /etc/shells
627 inst /etc/nsswitch.conf
818567fc
MP
628 inst /etc/pam.conf || true
629 inst /etc/securetty || true
889a9042
RC
630 inst /etc/os-release
631 inst /etc/localtime
632 # we want an empty environment
633 > $initdir/etc/environment
634 > $initdir/etc/machine-id
635 # set the hostname
636 echo systemd-testsuite > $initdir/etc/hostname
637 # fstab
85393d8f
TB
638 if [[ "$LOOKS_LIKE_SUSE" ]]; then
639 ROOTMOUNT="/dev/sda1 / ${FSTYPE} rw 0 1"
640 else
641 ROOTMOUNT="LABEL=systemd / ${FSTYPE} rw 0 1"
642 fi
643
889a9042 644 cat >$initdir/etc/fstab <<EOF
85393d8f 645$ROOTMOUNT
889a9042
RC
646EOF
647}
648
649install_basic_tools() {
650 [[ $BASICTOOLS ]] && dracut_install $BASICTOOLS
4be4833e 651 dracut_install -o sushell
7d023341
MP
652 # in Debian ldconfig is just a shell script wrapper around ldconfig.real
653 dracut_install -o ldconfig.real
889a9042
RC
654}
655
656install_debug_tools() {
657 [[ $DEBUGTOOLS ]] && dracut_install $DEBUGTOOLS
c81a46b9
FS
658
659 if [[ $INTERACTIVE_DEBUG ]]; then
660 # Set default TERM from vt220 to linux, so at least basic key shortcuts work
661 local _getty_override="$initdir/etc/systemd/system/serial-getty@.service.d"
662 mkdir -p "$_getty_override"
663 echo -e "[Service]\nEnvironment=TERM=linux" > "$_getty_override/default-TERM.conf"
664
665 cat > "$initdir/etc/motd" << EOF
666To adjust the terminal size use:
667 export COLUMNS=xx
668 export LINES=yy
669or
670 stty cols xx rows yy
671EOF
672 fi
889a9042
RC
673}
674
675install_libnss() {
676 # install libnss_files for login
cffae62b 677 NSS_LIBS=$(LD_DEBUG=files getent passwd 2>&1 >/dev/null |sed -n '/calling init: .*libnss_/ {s!^.* /!/!; p}')
99877b7e 678 dracut_install $NSS_LIBS
889a9042
RC
679}
680
681install_dbus() {
3486cb6c 682 inst $ROOTLIBDIR/system/dbus.socket
a978c9f2
FS
683
684 # Fedora rawhide replaced dbus.service with dbus-daemon.service
685 if [ -f $ROOTLIBDIR/system/dbus-daemon.service ]; then
686 inst $ROOTLIBDIR/system/dbus-daemon.service
687 # Alias symlink
688 inst_symlink /etc/systemd/system/dbus.service
689 else
690 inst $ROOTLIBDIR/system/dbus.service
691 fi
98b0439f
ZJS
692 # Newer Fedora versions use dbus-broker by default. Let's install it is available.
693 [ -f /usr/bin/dbus-broker ] && inst /usr/bin/dbus-broker
694 [ -f /usr/bin/dbus-broker-launch ] && inst /usr/bin/dbus-broker-launch
889a9042
RC
695
696 find \
e63b61be 697 /etc/dbus-1 /usr/share/dbus-1 -xtype f \
889a9042
RC
698 | while read file; do
699 inst $file
700 done
701}
702
703install_pam() {
0fe15dc8 704 (
818567fc
MP
705 if [[ "$LOOKS_LIKE_DEBIAN" ]] && type -p dpkg-architecture &>/dev/null; then
706 find "/lib/$(dpkg-architecture -qDEB_HOST_MULTIARCH)/security" -xtype f
707 else
708 find /lib*/security -xtype f
709 fi
710 find /etc/pam.d /etc/security -xtype f
0fe15dc8 711 ) | while read file; do
889a9042
RC
712 inst $file
713 done
417491f1 714
d5172c79
EV
715 # pam_unix depends on unix_chkpwd.
716 # see http://www.linux-pam.org/Linux-PAM-html/sag-pam_unix.html
717 dracut_install -o unix_chkpwd
718
417491f1
EV
719 [[ "$LOOKS_LIKE_DEBIAN" ]] &&
720 cp /etc/pam.d/systemd-user $initdir/etc/pam.d/
e14b866b
ZJS
721
722 # set empty root password for easy debugging
723 sed -i 's/^root:x:/root::/' $initdir/etc/passwd
889a9042
RC
724}
725
726install_keymaps() {
83a7051e
YW
727 # The first three paths may be deprecated.
728 # It seems now the last two paths are used by many distributions.
889a9042
RC
729 for i in \
730 /usr/lib/kbd/keymaps/include/* \
731 /usr/lib/kbd/keymaps/i386/include/* \
83a7051e
YW
732 /usr/lib/kbd/keymaps/i386/qwerty/us.* \
733 /usr/lib/kbd/keymaps/legacy/include/* \
734 /usr/lib/kbd/keymaps/legacy/i386/qwerty/us.*; do
889a9042
RC
735 [[ -f $i ]] || continue
736 inst $i
737 done
ad931fee
YW
738
739 # When it takes any argument, then install more keymaps.
740 if [[ -n $1 ]]; then
741 for i in \
742 /usr/lib/kbd/keymaps/i386/*/* \
743 /usr/lib/kbd/keymaps/legacy/i386/*/*; do
744 [[ -f $i ]] || continue
745 inst $i
746 done
747 fi
889a9042
RC
748}
749
7d10ec1c
YW
750install_zoneinfo() {
751 for i in /usr/share/zoneinfo/{,*/,*/*/}*; do
752 [[ -f $i ]] || continue
753 inst $i
754 done
755}
756
889a9042
RC
757install_fonts() {
758 for i in \
25b47f96 759 /usr/lib/kbd/consolefonts/eurlatgr* \
889a9042
RC
760 /usr/lib/kbd/consolefonts/latarcyrheb-sun16*; do
761 [[ -f $i ]] || continue
762 inst $i
763 done
764}
765
766install_terminfo() {
767 for _terminfodir in /lib/terminfo /etc/terminfo /usr/share/terminfo; do
768 [ -f ${_terminfodir}/l/linux ] && break
769 done
770 dracut_install -o ${_terminfodir}/l/linux
771}
772
773setup_testsuite() {
53d90f95 774 cp $TEST_BASE_DIR/testsuite.target $initdir/etc/systemd/system/
5c404f1a 775 cp $TEST_BASE_DIR/end.service $initdir/etc/systemd/system/
889a9042
RC
776
777 mkdir -p $initdir/etc/systemd/system/testsuite.target.wants
778 ln -fs $TEST_BASE_DIR/testsuite.service $initdir/etc/systemd/system/testsuite.target.wants/testsuite.service
c81a46b9
FS
779 # Don't shutdown the machine after running the test when INTERACTIVE_DEBUG is set
780 [[ -z $INTERACTIVE_DEBUG ]] && ln -fs $TEST_BASE_DIR/end.service $initdir/etc/systemd/system/testsuite.target.wants/end.service
889a9042
RC
781
782 # make the testsuite the default target
783 ln -fs testsuite.target $initdir/etc/systemd/system/default.target
784}
785
786setup_nspawn_root() {
787 rm -fr $TESTDIR/nspawn-root
788 ddebug "cp -ar $initdir $TESTDIR/nspawn-root"
789 cp -ar $initdir $TESTDIR/nspawn-root
790 # we don't mount in the nspawn root
791 rm -f $TESTDIR/nspawn-root/etc/fstab
746fbd9c
EV
792 if [[ "$RUN_IN_UNPRIVILEGED_CONTAINER" = "yes" ]]; then
793 cp -ar $TESTDIR/nspawn-root $TESTDIR/unprivileged-nspawn-root
794 fi
889a9042
RC
795}
796
0d6e798a 797setup_basic_dirs() {
889a9042
RC
798 mkdir -p $initdir/run
799 mkdir -p $initdir/etc/systemd/system
800 mkdir -p $initdir/var/log/journal
801
0d6e798a 802 for d in usr/bin usr/sbin bin etc lib "$libdir" sbin tmp usr var var/log dev proc sys sysroot root run run/lock run/initramfs; do
898720b7
HH
803 if [ -L "/$d" ]; then
804 inst_symlink "/$d"
805 else
0d6e798a 806 inst_dir "/$d"
898720b7
HH
807 fi
808 done
809
810 ln -sfn /run "$initdir/var/run"
811 ln -sfn /run/lock "$initdir/var/lock"
812}
813
814inst_libs() {
815 local _bin=$1
816 local _so_regex='([^ ]*/lib[^/]*/[^ ]*\.so[^ ]*)'
817 local _file _line
818
819 LC_ALL=C ldd "$_bin" 2>/dev/null | while read _line; do
820 [[ $_line = 'not a dynamic executable' ]] && break
821
822 if [[ $_line =~ $_so_regex ]]; then
823 _file=${BASH_REMATCH[1]}
824 [[ -e ${initdir}/$_file ]] && continue
825 inst_library "$_file"
826 continue
827 fi
828
829 if [[ $_line =~ not\ found ]]; then
830 dfatal "Missing a shared library required by $_bin."
831 dfatal "Run \"ldd $_bin\" to find out what it is."
832 dfatal "$_line"
833 dfatal "dracut cannot create an initrd."
834 exit 1
835 fi
836 done
837}
838
839import_testdir() {
898720b7 840 [[ -e $STATEFILE ]] && . $STATEFILE
3f50fff5
FS
841 if [[ ! -d "$TESTDIR" ]]; then
842 if [[ -z "$TESTDIR" ]]; then
843 TESTDIR=$(mktemp --tmpdir=/var/tmp -d -t systemd-test.XXXXXX)
844 else
845 mkdir -p "$TESTDIR"
846 fi
847
898720b7
HH
848 echo "TESTDIR=\"$TESTDIR\"" > $STATEFILE
849 export TESTDIR
850 fi
851}
852
889a9042
RC
853import_initdir() {
854 initdir=$TESTDIR/root
855 export initdir
856}
857
898720b7
HH
858## @brief Converts numeric logging level to the first letter of level name.
859#
860# @param lvl Numeric logging level in range from 1 to 6.
861# @retval 1 if @a lvl is out of range.
862# @retval 0 if @a lvl is correct.
863# @result Echoes first letter of level name.
864_lvl2char() {
865 case "$1" in
866 1) echo F;;
867 2) echo E;;
868 3) echo W;;
869 4) echo I;;
870 5) echo D;;
871 6) echo T;;
872 *) return 1;;
873 esac
874}
875
876## @brief Internal helper function for _do_dlog()
877#
878# @param lvl Numeric logging level.
879# @param msg Message.
880# @retval 0 It's always returned, even if logging failed.
881#
882# @note This function is not supposed to be called manually. Please use
883# dtrace(), ddebug(), or others instead which wrap this one.
884#
885# This function calls _do_dlog() either with parameter msg, or if
886# none is given, it will read standard input and will use every line as
887# a message.
888#
889# This enables:
890# dwarn "This is a warning"
891# echo "This is a warning" | dwarn
20fc56c0 892LOG_LEVEL=${LOG_LEVEL:-4}
898720b7
HH
893
894dlog() {
895 [ -z "$LOG_LEVEL" ] && return 0
896 [ $1 -le $LOG_LEVEL ] || return 0
897 local lvl="$1"; shift
898 local lvlc=$(_lvl2char "$lvl") || return 0
899
900 if [ $# -ge 1 ]; then
901 echo "$lvlc: $*"
902 else
903 while read line; do
904 echo "$lvlc: " "$line"
905 done
906 fi
907}
908
909## @brief Logs message at TRACE level (6)
910#
911# @param msg Message.
912# @retval 0 It's always returned, even if logging failed.
913dtrace() {
914 set +x
915 dlog 6 "$@"
916 [ -n "$debug" ] && set -x || :
917}
918
919## @brief Logs message at DEBUG level (5)
920#
921# @param msg Message.
922# @retval 0 It's always returned, even if logging failed.
923ddebug() {
0d6e798a 924# set +x
898720b7 925 dlog 5 "$@"
0d6e798a 926# [ -n "$debug" ] && set -x || :
898720b7
HH
927}
928
929## @brief Logs message at INFO level (4)
930#
931# @param msg Message.
932# @retval 0 It's always returned, even if logging failed.
933dinfo() {
934 set +x
935 dlog 4 "$@"
936 [ -n "$debug" ] && set -x || :
937}
938
939## @brief Logs message at WARN level (3)
940#
941# @param msg Message.
942# @retval 0 It's always returned, even if logging failed.
943dwarn() {
944 set +x
945 dlog 3 "$@"
946 [ -n "$debug" ] && set -x || :
947}
948
949## @brief Logs message at ERROR level (2)
950#
951# @param msg Message.
952# @retval 0 It's always returned, even if logging failed.
953derror() {
0d6e798a 954# set +x
898720b7 955 dlog 2 "$@"
0d6e798a 956# [ -n "$debug" ] && set -x || :
898720b7
HH
957}
958
959## @brief Logs message at FATAL level (1)
960#
961# @param msg Message.
962# @retval 0 It's always returned, even if logging failed.
963dfatal() {
964 set +x
965 dlog 1 "$@"
966 [ -n "$debug" ] && set -x || :
967}
968
969
970# Generic substring function. If $2 is in $1, return 0.
971strstr() { [ "${1#*$2*}" != "$1" ]; }
972
973# normalize_path <path>
974# Prints the normalized path, where it removes any duplicated
975# and trailing slashes.
976# Example:
977# $ normalize_path ///test/test//
978# /test/test
979normalize_path() {
980 shopt -q -s extglob
981 set -- "${1//+(\/)//}"
982 shopt -q -u extglob
983 echo "${1%/}"
984}
985
986# convert_abs_rel <from> <to>
987# Prints the relative path, when creating a symlink to <to> from <from>.
988# Example:
989# $ convert_abs_rel /usr/bin/test /bin/test-2
990# ../../bin/test-2
991# $ ln -s $(convert_abs_rel /usr/bin/test /bin/test-2) /usr/bin/test
992convert_abs_rel() {
993 local __current __absolute __abssize __cursize __newpath
994 local -i __i __level
995
996 set -- "$(normalize_path "$1")" "$(normalize_path "$2")"
997
998 # corner case #1 - self looping link
999 [[ "$1" == "$2" ]] && { echo "${1##*/}"; return; }
1000
1001 # corner case #2 - own dir link
1002 [[ "${1%/*}" == "$2" ]] && { echo "."; return; }
1003
1004 IFS="/" __current=($1)
1005 IFS="/" __absolute=($2)
1006
1007 __abssize=${#__absolute[@]}
1008 __cursize=${#__current[@]}
1009
1010 while [[ ${__absolute[__level]} == ${__current[__level]} ]]
1011 do
1012 (( __level++ ))
1013 if (( __level > __abssize || __level > __cursize ))
1014 then
1015 break
1016 fi
1017 done
1018
1019 for ((__i = __level; __i < __cursize-1; __i++))
1020 do
1021 if ((__i > __level))
1022 then
1023 __newpath=$__newpath"/"
1024 fi
1025 __newpath=$__newpath".."
1026 done
1027
1028 for ((__i = __level; __i < __abssize; __i++))
1029 do
1030 if [[ -n $__newpath ]]
1031 then
1032 __newpath=$__newpath"/"
1033 fi
1034 __newpath=$__newpath${__absolute[__i]}
1035 done
1036
1037 echo "$__newpath"
1038}
1039
1040
1041# Install a directory, keeping symlinks as on the original system.
1042# Example: if /lib points to /lib64 on the host, "inst_dir /lib/file"
1043# will create ${initdir}/lib64, ${initdir}/lib64/file,
1044# and a symlink ${initdir}/lib -> lib64.
1045inst_dir() {
1046 [[ -e ${initdir}/"$1" ]] && return 0 # already there
1047
1048 local _dir="$1" _part="${1%/*}" _file
1049 while [[ "$_part" != "${_part%/*}" ]] && ! [[ -e "${initdir}/${_part}" ]]; do
1050 _dir="$_part $_dir"
1051 _part=${_part%/*}
1052 done
1053
1054 # iterate over parent directories
1055 for _file in $_dir; do
1056 [[ -e "${initdir}/$_file" ]] && continue
1057 if [[ -L $_file ]]; then
1058 inst_symlink "$_file"
1059 else
1060 # create directory
1061 mkdir -m 0755 -p "${initdir}/$_file" || return 1
1062 [[ -e "$_file" ]] && chmod --reference="$_file" "${initdir}/$_file"
1063 chmod u+w "${initdir}/$_file"
1064 fi
1065 done
1066}
1067
1068# $1 = file to copy to ramdisk
1069# $2 (optional) Name for the file on the ramdisk
1070# Location of the image dir is assumed to be $initdir
1071# We never overwrite the target if it exists.
1072inst_simple() {
1073 [[ -f "$1" ]] || return 1
1074 strstr "$1" "/" || return 1
1075
1076 local _src=$1 target="${2:-$1}"
1077 if ! [[ -d ${initdir}/$target ]]; then
1078 [[ -e ${initdir}/$target ]] && return 0
1079 [[ -L ${initdir}/$target ]] && return 0
1080 [[ -d "${initdir}/${target%/*}" ]] || inst_dir "${target%/*}"
1081 fi
1082 # install checksum files also
1083 if [[ -e "${_src%/*}/.${_src##*/}.hmac" ]]; then
1084 inst "${_src%/*}/.${_src##*/}.hmac" "${target%/*}/.${target##*/}.hmac"
1085 fi
1086 ddebug "Installing $_src"
1087 cp --sparse=always -pfL "$_src" "${initdir}/$target"
1088}
1089
1090# find symlinks linked to given library file
1091# $1 = library file
1092# Function searches for symlinks by stripping version numbers appended to
1093# library filename, checks if it points to the same target and finally
1094# prints the list of symlinks to stdout.
1095#
1096# Example:
1097# rev_lib_symlinks libfoo.so.8.1
1098# output: libfoo.so.8 libfoo.so
1099# (Only if libfoo.so.8 and libfoo.so exists on host system.)
1100rev_lib_symlinks() {
1101 [[ ! $1 ]] && return 0
1102
1103 local fn="$1" orig="$(readlink -f "$1")" links=''
1104
1105 [[ ${fn} =~ .*\.so\..* ]] || return 1
1106
1107 until [[ ${fn##*.} == so ]]; do
1108 fn="${fn%.*}"
1109 [[ -L ${fn} && $(readlink -f "${fn}") == ${orig} ]] && links+=" ${fn}"
1110 done
1111
1112 echo "${links}"
1113}
1114
1115# Same as above, but specialized to handle dynamic libraries.
1116# It handles making symlinks according to how the original library
1117# is referenced.
1118inst_library() {
1119 local _src="$1" _dest=${2:-$1} _lib _reallib _symlink
1120 strstr "$1" "/" || return 1
1121 [[ -e $initdir/$_dest ]] && return 0
1122 if [[ -L $_src ]]; then
1123 # install checksum files also
1124 if [[ -e "${_src%/*}/.${_src##*/}.hmac" ]]; then
1125 inst "${_src%/*}/.${_src##*/}.hmac" "${_dest%/*}/.${_dest##*/}.hmac"
1126 fi
1127 _reallib=$(readlink -f "$_src")
1128 inst_simple "$_reallib" "$_reallib"
1129 inst_dir "${_dest%/*}"
1130 [[ -d "${_dest%/*}" ]] && _dest=$(readlink -f "${_dest%/*}")/${_dest##*/}
1131 ln -sfn $(convert_abs_rel "${_dest}" "${_reallib}") "${initdir}/${_dest}"
1132 else
1133 inst_simple "$_src" "$_dest"
1134 fi
1135
1136 # Create additional symlinks. See rev_symlinks description.
1137 for _symlink in $(rev_lib_symlinks $_src) $(rev_lib_symlinks $_reallib); do
818567fc 1138 [[ -e $initdir/$_symlink ]] || {
898720b7
HH
1139 ddebug "Creating extra symlink: $_symlink"
1140 inst_symlink $_symlink
1141 }
1142 done
1143}
1144
1145# find a binary. If we were not passed the full path directly,
1146# search in the usual places to find the binary.
1147find_binary() {
1148 if [[ -z ${1##/*} ]]; then
1149 if [[ -x $1 ]] || { strstr "$1" ".so" && ldd $1 &>/dev/null; }; then
1150 echo $1
1151 return 0
1152 fi
1153 fi
1154
1155 type -P $1
1156}
1157
1158# Same as above, but specialized to install binary executables.
1159# Install binary executable, and all shared library dependencies, if any.
1160inst_binary() {
1161 local _bin _target
1162 _bin=$(find_binary "$1") || return 1
1163 _target=${2:-$_bin}
1164 [[ -e $initdir/$_target ]] && return 0
1165 [[ -L $_bin ]] && inst_symlink $_bin $_target && return 0
1166 local _file _line
1167 local _so_regex='([^ ]*/lib[^/]*/[^ ]*\.so[^ ]*)'
1168 # I love bash!
1169 LC_ALL=C ldd "$_bin" 2>/dev/null | while read _line; do
1170 [[ $_line = 'not a dynamic executable' ]] && break
1171
1172 if [[ $_line =~ $_so_regex ]]; then
1173 _file=${BASH_REMATCH[1]}
1174 [[ -e ${initdir}/$_file ]] && continue
1175 inst_library "$_file"
1176 continue
1177 fi
1178
1179 if [[ $_line =~ not\ found ]]; then
1180 dfatal "Missing a shared library required by $_bin."
1181 dfatal "Run \"ldd $_bin\" to find out what it is."
1182 dfatal "$_line"
1183 dfatal "dracut cannot create an initrd."
1184 exit 1
1185 fi
1186 done
1187 inst_simple "$_bin" "$_target"
1188}
1189
1190# same as above, except for shell scripts.
1191# If your shell script does not start with shebang, it is not a shell script.
1192inst_script() {
1193 local _bin
1194 _bin=$(find_binary "$1") || return 1
1195 shift
1196 local _line _shebang_regex
1197 read -r -n 80 _line <"$_bin"
1198 # If debug is set, clean unprintable chars to prevent messing up the term
1199 [[ $debug ]] && _line=$(echo -n "$_line" | tr -c -d '[:print:][:space:]')
1200 _shebang_regex='(#! *)(/[^ ]+).*'
1201 [[ $_line =~ $_shebang_regex ]] || return 1
1202 inst "${BASH_REMATCH[2]}" && inst_simple "$_bin" "$@"
1203}
1204
1205# same as above, but specialized for symlinks
1206inst_symlink() {
1207 local _src=$1 _target=${2:-$1} _realsrc
1208 strstr "$1" "/" || return 1
1209 [[ -L $1 ]] || return 1
1210 [[ -L $initdir/$_target ]] && return 0
1211 _realsrc=$(readlink -f "$_src")
1212 if ! [[ -e $initdir/$_realsrc ]]; then
1213 if [[ -d $_realsrc ]]; then
1214 inst_dir "$_realsrc"
1215 else
1216 inst "$_realsrc"
1217 fi
1218 fi
1219 [[ ! -e $initdir/${_target%/*} ]] && inst_dir "${_target%/*}"
1220 [[ -d ${_target%/*} ]] && _target=$(readlink -f ${_target%/*})/${_target##*/}
1221 ln -sfn $(convert_abs_rel "${_target}" "${_realsrc}") "$initdir/$_target"
1222}
1223
1224# attempt to install any programs specified in a udev rule
1225inst_rule_programs() {
1226 local _prog _bin
1227
1228 if grep -qE 'PROGRAM==?"[^ "]+' "$1"; then
1229 for _prog in $(grep -E 'PROGRAM==?"[^ "]+' "$1" | sed -r 's/.*PROGRAM==?"([^ "]+).*/\1/'); do
1230 if [ -x /lib/udev/$_prog ]; then
1231 _bin=/lib/udev/$_prog
1232 else
1233 _bin=$(find_binary "$_prog") || {
1234 dinfo "Skipping program $_prog using in udev rule $(basename $1) as it cannot be found"
1235 continue;
1236 }
1237 fi
1238
1239 #dinfo "Installing $_bin due to it's use in the udev rule $(basename $1)"
1240 dracut_install "$_bin"
1241 done
1242 fi
1243}
1244
1245# udev rules always get installed in the same place, so
1246# create a function to install them to make life simpler.
1247inst_rules() {
1248 local _target=/etc/udev/rules.d _rule _found
1249
1250 inst_dir "/lib/udev/rules.d"
1251 inst_dir "$_target"
1252 for _rule in "$@"; do
1253 if [ "${rule#/}" = "$rule" ]; then
1254 for r in /lib/udev/rules.d /etc/udev/rules.d; do
1255 if [[ -f $r/$_rule ]]; then
1256 _found="$r/$_rule"
1257 inst_simple "$_found"
1258 inst_rule_programs "$_found"
1259 fi
1260 done
1261 fi
1262 for r in '' ./ $dracutbasedir/rules.d/; do
1263 if [[ -f ${r}$_rule ]]; then
1264 _found="${r}$_rule"
1265 inst_simple "$_found" "$_target/${_found##*/}"
1266 inst_rule_programs "$_found"
1267 fi
1268 done
1269 [[ $_found ]] || dinfo "Skipping udev rule: $_rule"
31ce89e7 1270 _found=
898720b7
HH
1271 done
1272}
1273
1274# general purpose installation function
1275# Same args as above.
1276inst() {
1277 local _x
1278
1279 case $# in
1280 1) ;;
1281 2) [[ ! $initdir && -d $2 ]] && export initdir=$2
1282 [[ $initdir = $2 ]] && set $1;;
1283 3) [[ -z $initdir ]] && export initdir=$2
1284 set $1 $3;;
1285 *) dfatal "inst only takes 1 or 2 or 3 arguments"
1286 exit 1;;
1287 esac
1288 for _x in inst_symlink inst_script inst_binary inst_simple; do
1289 $_x "$@" && return 0
1290 done
1291 return 1
1292}
1293
1294# install any of listed files
1295#
1296# If first argument is '-d' and second some destination path, first accessible
1297# source is installed into this path, otherwise it will installed in the same
1298# path as source. If none of listed files was installed, function return 1.
1299# On first successful installation it returns with 0 status.
1300#
1301# Example:
1302#
1303# inst_any -d /bin/foo /bin/bar /bin/baz
1304#
1305# Lets assume that /bin/baz exists, so it will be installed as /bin/foo in
1306# initramfs.
1307inst_any() {
1308 local to f
1309
1310 [[ $1 = '-d' ]] && to="$2" && shift 2
1311
1312 for f in "$@"; do
1313 if [[ -e $f ]]; then
1314 [[ $to ]] && inst "$f" "$to" && return 0
1315 inst "$f" && return 0
1316 fi
1317 done
1318
1319 return 1
1320}
1321
1322# dracut_install [-o ] <file> [<file> ... ]
1323# Install <file> to the initramfs image
1324# -o optionally install the <file> and don't fail, if it is not there
1325dracut_install() {
1326 local _optional=no
1327 if [[ $1 = '-o' ]]; then
1328 _optional=yes
1329 shift
1330 fi
1331 while (($# > 0)); do
1332 if ! inst "$1" ; then
1333 if [[ $_optional = yes ]]; then
1334 dinfo "Skipping program $1 as it cannot be found and is" \
1335 "flagged to be optional"
1336 else
1337 dfatal "Failed to install $1"
1338 exit 1
1339 fi
1340 fi
1341 shift
1342 done
1343}
1344
0d6e798a
HH
1345# Install a single kernel module along with any firmware it may require.
1346# $1 = full path to kernel module to install
1347install_kmod_with_fw() {
1348 # no need to go further if the module is already installed
1349
1350 [[ -e "${initdir}/lib/modules/$KERNEL_VER/${1##*/lib/modules/$KERNEL_VER/}" ]] \
1351 && return 0
1352
1353 [[ -e "$initdir/.kernelmodseen/${1##*/}" ]] && return 0
1354
1355 if [[ $omit_drivers ]]; then
1356 local _kmod=${1##*/}
1357 _kmod=${_kmod%.ko}
1358 _kmod=${_kmod/-/_}
1359 if [[ "$_kmod" =~ $omit_drivers ]]; then
1360 dinfo "Omitting driver $_kmod"
1361 return 1
1362 fi
1363 if [[ "${1##*/lib/modules/$KERNEL_VER/}" =~ $omit_drivers ]]; then
1364 dinfo "Omitting driver $_kmod"
1365 return 1
1366 fi
1367 fi
1368
1369 [ -d "$initdir/.kernelmodseen" ] && \
1370 > "$initdir/.kernelmodseen/${1##*/}"
1371
1372 inst_simple "$1" "/lib/modules/$KERNEL_VER/${1##*/lib/modules/$KERNEL_VER/}" \
1373 || return $?
1374
1375 local _modname=${1##*/} _fwdir _found _fw
1376 _modname=${_modname%.ko*}
1377 for _fw in $(modinfo -k $KERNEL_VER -F firmware $1 2>/dev/null); do
1378 _found=''
1379 for _fwdir in $fw_dir; do
1380 if [[ -d $_fwdir && -f $_fwdir/$_fw ]]; then
1381 inst_simple "$_fwdir/$_fw" "/lib/firmware/$_fw"
1382 _found=yes
1383 fi
1384 done
1385 if [[ $_found != yes ]]; then
1386 if ! grep -qe "\<${_modname//-/_}\>" /proc/modules; then
1387 dinfo "Possible missing firmware \"${_fw}\" for kernel module" \
1388 "\"${_modname}.ko\""
1389 else
1390 dwarn "Possible missing firmware \"${_fw}\" for kernel module" \
1391 "\"${_modname}.ko\""
1392 fi
1393 fi
1394 done
1395 return 0
1396}
1397
1398# Do something with all the dependencies of a kernel module.
1399# Note that kernel modules depend on themselves using the technique we use
1400# $1 = function to call for each dependency we find
1401# It will be passed the full path to the found kernel module
1402# $2 = module to get dependencies for
1403# rest of args = arguments to modprobe
1404# _fderr specifies FD passed from surrounding scope
1405for_each_kmod_dep() {
1406 local _func=$1 _kmod=$2 _cmd _modpath _options _found=0
1407 shift 2
1408 modprobe "$@" --ignore-install --show-depends $_kmod 2>&${_fderr} | (
1409 while read _cmd _modpath _options; do
1410 [[ $_cmd = insmod ]] || continue
1411 $_func ${_modpath} || exit $?
1412 _found=1
1413 done
1414 [[ $_found -eq 0 ]] && exit 1
1415 exit 0
1416 )
1417}
1418
1419# filter kernel modules to install certain modules that meet specific
1420# requirements.
1421# $1 = search only in subdirectory of /kernel/$1
1422# $2 = function to call with module name to filter.
1423# This function will be passed the full path to the module to test.
c5315881 1424# The behavior of this function can vary depending on whether $hostonly is set.
0d6e798a
HH
1425# If it is, we will only look at modules that are already in memory.
1426# If it is not, we will look at all kernel modules
1427# This function returns the full filenames of modules that match $1
1428filter_kernel_modules_by_path () (
1429 local _modname _filtercmd
1430 if ! [[ $hostonly ]]; then
1431 _filtercmd='find "$KERNEL_MODS/kernel/$1" "$KERNEL_MODS/extra"'
1432 _filtercmd+=' "$KERNEL_MODS/weak-updates" -name "*.ko" -o -name "*.ko.gz"'
1433 _filtercmd+=' -o -name "*.ko.xz"'
1434 _filtercmd+=' 2>/dev/null'
1435 else
1436 _filtercmd='cut -d " " -f 1 </proc/modules|xargs modinfo -F filename '
1437 _filtercmd+='-k $KERNEL_VER 2>/dev/null'
1438 fi
1439 for _modname in $(eval $_filtercmd); do
1440 case $_modname in
1441 *.ko) "$2" "$_modname" && echo "$_modname";;
1442 *.ko.gz) gzip -dc "$_modname" > $initdir/$$.ko
1443 $2 $initdir/$$.ko && echo "$_modname"
1444 rm -f $initdir/$$.ko
1445 ;;
1446 *.ko.xz) xz -dc "$_modname" > $initdir/$$.ko
1447 $2 $initdir/$$.ko && echo "$_modname"
1448 rm -f $initdir/$$.ko
1449 ;;
1450 esac
1451 done
1452)
1453find_kernel_modules_by_path () (
1454 if ! [[ $hostonly ]]; then
1455 find "$KERNEL_MODS/kernel/$1" "$KERNEL_MODS/extra" "$KERNEL_MODS/weak-updates" \
1456 -name "*.ko" -o -name "*.ko.gz" -o -name "*.ko.xz" 2>/dev/null
1457 else
1458 cut -d " " -f 1 </proc/modules \
1459 | xargs modinfo -F filename -k $KERNEL_VER 2>/dev/null
1460 fi
1461)
1462
1463filter_kernel_modules () {
1464 filter_kernel_modules_by_path drivers "$1"
1465}
1466
1467find_kernel_modules () {
1468 find_kernel_modules_by_path drivers
1469}
1470
1471# instmods [-c] <kernel module> [<kernel module> ... ]
1472# instmods [-c] <kernel subsystem>
1473# install kernel modules along with all their dependencies.
1474# <kernel subsystem> can be e.g. "=block" or "=drivers/usb/storage"
1475instmods() {
1476 [[ $no_kernel = yes ]] && return
1477 # called [sub]functions inherit _fderr
1478 local _fderr=9
1479 local _check=no
1480 if [[ $1 = '-c' ]]; then
1481 _check=yes
1482 shift
1483 fi
1484
1485 function inst1mod() {
1486 local _ret=0 _mod="$1"
1487 case $_mod in
1488 =*)
1489 if [ -f $KERNEL_MODS/modules.${_mod#=} ]; then
1490 ( [[ "$_mpargs" ]] && echo $_mpargs
1491 cat "${KERNEL_MODS}/modules.${_mod#=}" ) \
1492 | instmods
1493 else
1494 ( [[ "$_mpargs" ]] && echo $_mpargs
1495 find "$KERNEL_MODS" -path "*/${_mod#=}/*" -printf '%f\n' ) \
1496 | instmods
1497 fi
1498 ;;
1499 --*) _mpargs+=" $_mod" ;;
1500 i2o_scsi) return ;; # Do not load this diagnostic-only module
1501 *)
1502 _mod=${_mod##*/}
1503 # if we are already installed, skip this module and go on
1504 # to the next one.
1505 [[ -f "$initdir/.kernelmodseen/${_mod%.ko}.ko" ]] && return
1506
1507 if [[ $omit_drivers ]] && [[ "$1" =~ $omit_drivers ]]; then
1508 dinfo "Omitting driver ${_mod##$KERNEL_MODS}"
1509 return
1510 fi
1511 # If we are building a host-specific initramfs and this
1512 # module is not already loaded, move on to the next one.
1513 [[ $hostonly ]] && ! grep -qe "\<${_mod//-/_}\>" /proc/modules \
1514 && ! echo $add_drivers | grep -qe "\<${_mod}\>" \
1515 && return
1516
1517 # We use '-d' option in modprobe only if modules prefix path
1518 # differs from default '/'. This allows us to use Dracut with
1519 # old version of modprobe which doesn't have '-d' option.
1520 local _moddirname=${KERNEL_MODS%%/lib/modules/*}
1521 [[ -n ${_moddirname} ]] && _moddirname="-d ${_moddirname}/"
1522
1523 # ok, load the module, all its dependencies, and any firmware
1524 # it may require
1525 for_each_kmod_dep install_kmod_with_fw $_mod \
1526 --set-version $KERNEL_VER ${_moddirname} $_mpargs
1527 ((_ret+=$?))
1528 ;;
1529 esac
1530 return $_ret
1531 }
1532
1533 function instmods_1() {
1534 local _mod _mpargs
1535 if (($# == 0)); then # filenames from stdin
1536 while read _mod; do
1537 inst1mod "${_mod%.ko*}" || {
1538 if [ "$_check" = "yes" ]; then
1539 dfatal "Failed to install $_mod"
1540 return 1
1541 fi
1542 }
1543 done
1544 fi
1545 while (($# > 0)); do # filenames as arguments
1546 inst1mod ${1%.ko*} || {
1547 if [ "$_check" = "yes" ]; then
1548 dfatal "Failed to install $1"
1549 return 1
1550 fi
1551 }
1552 shift
1553 done
1554 return 0
1555 }
1556
1557 local _ret _filter_not_found='FATAL: Module .* not found.'
1558 set -o pipefail
1559 # Capture all stderr from modprobe to _fderr. We could use {var}>...
1560 # redirections, but that would make dracut require bash4 at least.
1561 eval "( instmods_1 \"\$@\" ) ${_fderr}>&1" \
1562 | while read line; do [[ "$line" =~ $_filter_not_found ]] && echo $line || echo $line >&2 ;done | derror
1563 _ret=$?
1564 set +o pipefail
1565 return $_ret
1566}
898720b7
HH
1567
1568# inst_libdir_file [-n <pattern>] <file> [<file>...]
1569# Install a <file> located on a lib directory to the initramfs image
1570# -n <pattern> install non-matching files
1571inst_libdir_file() {
1572 if [[ "$1" == "-n" ]]; then
1573 local _pattern=$1
1574 shift 2
1575 for _dir in $libdirs; do
1576 for _i in "$@"; do
1577 for _f in "$_dir"/$_i; do
1578 [[ "$_i" =~ $_pattern ]] || continue
1579 [[ -e "$_i" ]] && dracut_install "$_i"
1580 done
1581 done
1582 done
1583 else
1584 for _dir in $libdirs; do
1585 for _i in "$@"; do
1586 for _f in "$_dir"/$_i; do
1587 [[ -e "$_f" ]] && dracut_install "$_f"
1588 done
1589 done
1590 done
1591 fi
1592}
1593
85393d8f 1594setup_suse() {
caced732
FB
1595 ln -fs ../usr/bin/systemctl $initdir/bin/
1596 ln -fs ../usr/lib/systemd $initdir/lib/
85393d8f
TB
1597 inst_simple "/usr/lib/systemd/system/haveged.service"
1598}
1599
054ee249
MP
1600# can be overridden in specific test
1601test_cleanup() {
1602 umount $TESTDIR/root 2>/dev/null || true
818567fc 1603 [[ $LOOPDEV ]] && losetup -d $LOOPDEV || true
054ee249
MP
1604 return 0
1605}
1606
1607test_run() {
1608 if [ -z "$TEST_NO_QEMU" ]; then
1609 if run_qemu; then
1610 check_result_qemu || return 1
1611 else
1612 dwarn "can't run QEMU, skipping"
1613 fi
1614 fi
1615 if [ -z "$TEST_NO_NSPAWN" ]; then
746fbd9c
EV
1616 if run_nspawn "nspawn-root"; then
1617 check_result_nspawn "nspawn-root" || return 1
054ee249
MP
1618 else
1619 dwarn "can't run systemd-nspawn, skipping"
1620 fi
746fbd9c
EV
1621
1622 if [[ "$RUN_IN_UNPRIVILEGED_CONTAINER" = "yes" ]]; then
1623 if NSPAWN_ARGUMENTS="-U --private-network $NSPAWN_ARGUMENTS" run_nspawn "unprivileged-nspawn-root"; then
1624 check_result_nspawn "unprivileged-nspawn-root" || return 1
1625 else
1626 dwarn "can't run systemd-nspawn, skipping"
1627 fi
d56db495 1628 fi
054ee249
MP
1629 fi
1630 return 0
1631}
1632
898720b7 1633do_test() {
33a5e20f
HH
1634 if [[ $UID != "0" ]]; then
1635 echo "TEST: $TEST_DESCRIPTION [SKIPPED]: not root" >&2
1636 exit 0
1637 fi
1638
898720b7
HH
1639# Detect lib paths
1640 [[ $libdir ]] || for libdir in /lib64 /lib; do
1641 [[ -d $libdir ]] && libdirs+=" $libdir" && break
1642 done
1643
1644 [[ $usrlibdir ]] || for usrlibdir in /usr/lib64 /usr/lib; do
1645 [[ -d $usrlibdir ]] && libdirs+=" $usrlibdir" && break
1646 done
1647
22077c9c
MP
1648 mkdir -p "$STATEDIR"
1649
898720b7 1650 import_testdir
889a9042 1651 import_initdir
898720b7
HH
1652
1653 while (($# > 0)); do
1654 case $1 in
1655 --run)
1656 echo "TEST RUN: $TEST_DESCRIPTION"
0013fac2
YW
1657 test_run
1658 ret=$?
1659 if (( $ret == 0 )); then
898720b7
HH
1660 echo "TEST RUN: $TEST_DESCRIPTION [OK]"
1661 else
1662 echo "TEST RUN: $TEST_DESCRIPTION [FAILED]"
1663 fi
1664 exit $ret;;
1665 --setup)
1666 echo "TEST SETUP: $TEST_DESCRIPTION"
1667 test_setup
818567fc 1668 ;;
898720b7
HH
1669 --clean)
1670 echo "TEST CLEANUP: $TEST_DESCRIPTION"
1671 test_cleanup
1672 rm -fr "$TESTDIR"
22077c9c 1673 rm -f "$STATEFILE"
818567fc 1674 ;;
898720b7 1675 --all)
818567fc 1676 ret=0
898720b7
HH
1677 echo -n "TEST: $TEST_DESCRIPTION ";
1678 (
1679 test_setup && test_run
1680 ret=$?
1681 test_cleanup
1682 rm -fr "$TESTDIR"
22077c9c 1683 rm -f "$STATEFILE"
898720b7 1684 exit $ret
818567fc 1685 ) </dev/null >"$TESTLOG" 2>&1 || ret=$?
898720b7 1686 if [ $ret -eq 0 ]; then
22077c9c 1687 rm "$TESTLOG"
898720b7
HH
1688 echo "[OK]"
1689 else
1690 echo "[FAILED]"
22077c9c 1691 echo "see $TESTLOG"
898720b7
HH
1692 fi
1693 exit $ret;;
1694 *) break ;;
1695 esac
1696 shift
1697 done
1698}