]> git.ipfire.org Git - thirdparty/systemd.git/blame - test/test-functions
test-functions: follow fedora dbus-daemon/dbus-broker rearrangements
[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
cc5549ca
ZJS
162 if [[ "$LOOKS_LIKE_SUSE" ]]; then
163 PARAMS+="rd.hostonly=0"
164 elif [[ "$LOOKS_LIKE_ARCH" ]]; then
165 PARAMS+="rw"
166 else
167 PARAMS+="ro"
168 fi
85393d8f 169
cc5549ca 170 KERNEL_APPEND="$PARAMS \
85393d8f 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 562 ddebug "Strip binaries"
408c9a07
ZJS
563 find "$initdir" -executable -not -path '*/lib/modules/*.ko' -type f | \
564 xargs strip --strip-unneeded |& \
565 grep -v 'file format not recognized' | \
566 ddebug
889a9042
RC
567}
568
569create_rc_local() {
570 mkdir -p $initdir/etc/rc.d
571 cat >$initdir/etc/rc.d/rc.local <<EOF
572#!/bin/bash
573exit 0
574EOF
575 chmod 0755 $initdir/etc/rc.d/rc.local
576}
577
578install_execs() {
c7eda013
EV
579 ddebug "install any Execs from the service files"
580 (
209f4b9e 581 export PKG_CONFIG_PATH=$BUILD_DIR/src/core/
c7eda013
EV
582 systemdsystemunitdir=$(pkg-config --variable=systemdsystemunitdir systemd)
583 systemduserunitdir=$(pkg-config --variable=systemduserunitdir systemd)
fe4bd4e5 584 sed -r -n 's|^Exec[a-zA-Z]*=[@+!-]*([^ ]+).*|\1|gp' $initdir/{$systemdsystemunitdir,$systemduserunitdir}/*.service \
e180bdb5 585 | sort -u | while read i; do
818567fc 586 # some {rc,halt}.local scripts and programs are okay to not exist, the rest should
e4e039bc
FS
587 # also, plymouth is pulled in by rescue.service, but even there the exit code
588 # is ignored; as it's not present on some distros, don't fail if it doesn't exist
589 inst $i || [ "${i%.local}" != "$i" ] || [ "${i%systemd-update-done}" != "$i" ] || [ "/bin/plymouth" == "$i" ]
c7eda013
EV
590 done
591 )
889a9042
RC
592}
593
594generate_module_dependencies() {
595 if [[ -d $initdir/lib/modules/$KERNEL_VER ]] && \
596 ! depmod -a -b "$initdir" $KERNEL_VER; then
597 dfatal "\"depmod -a $KERNEL_VER\" failed."
598 exit 1
599 fi
600}
601
602install_depmod_files() {
603 inst /lib/modules/$KERNEL_VER/modules.order
604 inst /lib/modules/$KERNEL_VER/modules.builtin
605}
606
607install_plymouth() {
608 # install plymouth, if found... else remove plymouth service files
609 # if [ -x /usr/libexec/plymouth/plymouth-populate-initrd ]; then
610 # PLYMOUTH_POPULATE_SOURCE_FUNCTIONS="$TEST_BASE_DIR/test-functions" \
611 # /usr/libexec/plymouth/plymouth-populate-initrd -t $initdir
612 # dracut_install plymouth plymouthd
613 # else
614 rm -f $initdir/{usr/lib,etc}/systemd/system/plymouth* $initdir/{usr/lib,etc}/systemd/system/*/plymouth*
615 # fi
616}
617
618install_ld_so_conf() {
619 cp -a /etc/ld.so.conf* $initdir/etc
620 ldconfig -r "$initdir"
621}
622
623install_config_files() {
818567fc 624 inst /etc/sysconfig/init || true
889a9042
RC
625 inst /etc/passwd
626 inst /etc/shadow
bf3a947c 627 inst /etc/login.defs
889a9042
RC
628 inst /etc/group
629 inst /etc/shells
630 inst /etc/nsswitch.conf
818567fc
MP
631 inst /etc/pam.conf || true
632 inst /etc/securetty || true
889a9042
RC
633 inst /etc/os-release
634 inst /etc/localtime
635 # we want an empty environment
636 > $initdir/etc/environment
637 > $initdir/etc/machine-id
638 # set the hostname
639 echo systemd-testsuite > $initdir/etc/hostname
640 # fstab
85393d8f
TB
641 if [[ "$LOOKS_LIKE_SUSE" ]]; then
642 ROOTMOUNT="/dev/sda1 / ${FSTYPE} rw 0 1"
643 else
644 ROOTMOUNT="LABEL=systemd / ${FSTYPE} rw 0 1"
645 fi
646
889a9042 647 cat >$initdir/etc/fstab <<EOF
85393d8f 648$ROOTMOUNT
889a9042
RC
649EOF
650}
651
652install_basic_tools() {
653 [[ $BASICTOOLS ]] && dracut_install $BASICTOOLS
4be4833e 654 dracut_install -o sushell
7d023341
MP
655 # in Debian ldconfig is just a shell script wrapper around ldconfig.real
656 dracut_install -o ldconfig.real
889a9042
RC
657}
658
659install_debug_tools() {
660 [[ $DEBUGTOOLS ]] && dracut_install $DEBUGTOOLS
c81a46b9
FS
661
662 if [[ $INTERACTIVE_DEBUG ]]; then
663 # Set default TERM from vt220 to linux, so at least basic key shortcuts work
664 local _getty_override="$initdir/etc/systemd/system/serial-getty@.service.d"
665 mkdir -p "$_getty_override"
666 echo -e "[Service]\nEnvironment=TERM=linux" > "$_getty_override/default-TERM.conf"
667
668 cat > "$initdir/etc/motd" << EOF
669To adjust the terminal size use:
670 export COLUMNS=xx
671 export LINES=yy
672or
673 stty cols xx rows yy
674EOF
675 fi
889a9042
RC
676}
677
678install_libnss() {
679 # install libnss_files for login
cffae62b 680 NSS_LIBS=$(LD_DEBUG=files getent passwd 2>&1 >/dev/null |sed -n '/calling init: .*libnss_/ {s!^.* /!/!; p}')
99877b7e 681 dracut_install $NSS_LIBS
889a9042
RC
682}
683
684install_dbus() {
3486cb6c 685 inst $ROOTLIBDIR/system/dbus.socket
a978c9f2 686
908665f4
LP
687 # Newer Fedora versions use dbus-broker by default. Let's install it is available.
688 if [ -f $ROOTLIBDIR/system/dbus-broker.service ]; then
689 inst $ROOTLIBDIR/system/dbus-broker.service
690 inst_symlink /etc/systemd/system/dbus.service
691 inst /usr/bin/dbus-broker
692 inst /usr/bin/dbus-broker-launch
693 elif [ -f $ROOTLIBDIR/system/dbus-daemon.service ]; then
694 # Fedora rawhide replaced dbus.service with dbus-daemon.service
a978c9f2
FS
695 inst $ROOTLIBDIR/system/dbus-daemon.service
696 # Alias symlink
697 inst_symlink /etc/systemd/system/dbus.service
698 else
699 inst $ROOTLIBDIR/system/dbus.service
700 fi
889a9042
RC
701
702 find \
e63b61be 703 /etc/dbus-1 /usr/share/dbus-1 -xtype f \
889a9042
RC
704 | while read file; do
705 inst $file
706 done
707}
708
709install_pam() {
0fe15dc8 710 (
818567fc
MP
711 if [[ "$LOOKS_LIKE_DEBIAN" ]] && type -p dpkg-architecture &>/dev/null; then
712 find "/lib/$(dpkg-architecture -qDEB_HOST_MULTIARCH)/security" -xtype f
713 else
714 find /lib*/security -xtype f
715 fi
716 find /etc/pam.d /etc/security -xtype f
0fe15dc8 717 ) | while read file; do
889a9042
RC
718 inst $file
719 done
417491f1 720
d5172c79
EV
721 # pam_unix depends on unix_chkpwd.
722 # see http://www.linux-pam.org/Linux-PAM-html/sag-pam_unix.html
723 dracut_install -o unix_chkpwd
724
417491f1
EV
725 [[ "$LOOKS_LIKE_DEBIAN" ]] &&
726 cp /etc/pam.d/systemd-user $initdir/etc/pam.d/
e14b866b
ZJS
727
728 # set empty root password for easy debugging
729 sed -i 's/^root:x:/root::/' $initdir/etc/passwd
889a9042
RC
730}
731
732install_keymaps() {
83a7051e
YW
733 # The first three paths may be deprecated.
734 # It seems now the last two paths are used by many distributions.
889a9042
RC
735 for i in \
736 /usr/lib/kbd/keymaps/include/* \
737 /usr/lib/kbd/keymaps/i386/include/* \
83a7051e
YW
738 /usr/lib/kbd/keymaps/i386/qwerty/us.* \
739 /usr/lib/kbd/keymaps/legacy/include/* \
740 /usr/lib/kbd/keymaps/legacy/i386/qwerty/us.*; do
889a9042
RC
741 [[ -f $i ]] || continue
742 inst $i
743 done
ad931fee
YW
744
745 # When it takes any argument, then install more keymaps.
746 if [[ -n $1 ]]; then
747 for i in \
748 /usr/lib/kbd/keymaps/i386/*/* \
749 /usr/lib/kbd/keymaps/legacy/i386/*/*; do
750 [[ -f $i ]] || continue
751 inst $i
752 done
753 fi
889a9042
RC
754}
755
7d10ec1c
YW
756install_zoneinfo() {
757 for i in /usr/share/zoneinfo/{,*/,*/*/}*; do
758 [[ -f $i ]] || continue
759 inst $i
760 done
761}
762
889a9042
RC
763install_fonts() {
764 for i in \
25b47f96 765 /usr/lib/kbd/consolefonts/eurlatgr* \
889a9042
RC
766 /usr/lib/kbd/consolefonts/latarcyrheb-sun16*; do
767 [[ -f $i ]] || continue
768 inst $i
769 done
770}
771
772install_terminfo() {
773 for _terminfodir in /lib/terminfo /etc/terminfo /usr/share/terminfo; do
774 [ -f ${_terminfodir}/l/linux ] && break
775 done
776 dracut_install -o ${_terminfodir}/l/linux
777}
778
779setup_testsuite() {
53d90f95 780 cp $TEST_BASE_DIR/testsuite.target $initdir/etc/systemd/system/
5c404f1a 781 cp $TEST_BASE_DIR/end.service $initdir/etc/systemd/system/
889a9042
RC
782
783 mkdir -p $initdir/etc/systemd/system/testsuite.target.wants
784 ln -fs $TEST_BASE_DIR/testsuite.service $initdir/etc/systemd/system/testsuite.target.wants/testsuite.service
c81a46b9
FS
785 # Don't shutdown the machine after running the test when INTERACTIVE_DEBUG is set
786 [[ -z $INTERACTIVE_DEBUG ]] && ln -fs $TEST_BASE_DIR/end.service $initdir/etc/systemd/system/testsuite.target.wants/end.service
889a9042
RC
787
788 # make the testsuite the default target
789 ln -fs testsuite.target $initdir/etc/systemd/system/default.target
790}
791
792setup_nspawn_root() {
793 rm -fr $TESTDIR/nspawn-root
794 ddebug "cp -ar $initdir $TESTDIR/nspawn-root"
795 cp -ar $initdir $TESTDIR/nspawn-root
796 # we don't mount in the nspawn root
797 rm -f $TESTDIR/nspawn-root/etc/fstab
746fbd9c
EV
798 if [[ "$RUN_IN_UNPRIVILEGED_CONTAINER" = "yes" ]]; then
799 cp -ar $TESTDIR/nspawn-root $TESTDIR/unprivileged-nspawn-root
800 fi
889a9042
RC
801}
802
0d6e798a 803setup_basic_dirs() {
889a9042
RC
804 mkdir -p $initdir/run
805 mkdir -p $initdir/etc/systemd/system
806 mkdir -p $initdir/var/log/journal
807
0d6e798a 808 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
809 if [ -L "/$d" ]; then
810 inst_symlink "/$d"
811 else
0d6e798a 812 inst_dir "/$d"
898720b7
HH
813 fi
814 done
815
816 ln -sfn /run "$initdir/var/run"
817 ln -sfn /run/lock "$initdir/var/lock"
818}
819
820inst_libs() {
821 local _bin=$1
822 local _so_regex='([^ ]*/lib[^/]*/[^ ]*\.so[^ ]*)'
823 local _file _line
824
825 LC_ALL=C ldd "$_bin" 2>/dev/null | while read _line; do
826 [[ $_line = 'not a dynamic executable' ]] && break
827
828 if [[ $_line =~ $_so_regex ]]; then
829 _file=${BASH_REMATCH[1]}
830 [[ -e ${initdir}/$_file ]] && continue
831 inst_library "$_file"
832 continue
833 fi
834
835 if [[ $_line =~ not\ found ]]; then
836 dfatal "Missing a shared library required by $_bin."
837 dfatal "Run \"ldd $_bin\" to find out what it is."
838 dfatal "$_line"
839 dfatal "dracut cannot create an initrd."
840 exit 1
841 fi
842 done
843}
844
845import_testdir() {
898720b7 846 [[ -e $STATEFILE ]] && . $STATEFILE
3f50fff5
FS
847 if [[ ! -d "$TESTDIR" ]]; then
848 if [[ -z "$TESTDIR" ]]; then
849 TESTDIR=$(mktemp --tmpdir=/var/tmp -d -t systemd-test.XXXXXX)
850 else
851 mkdir -p "$TESTDIR"
852 fi
853
898720b7
HH
854 echo "TESTDIR=\"$TESTDIR\"" > $STATEFILE
855 export TESTDIR
856 fi
857}
858
889a9042
RC
859import_initdir() {
860 initdir=$TESTDIR/root
861 export initdir
862}
863
898720b7
HH
864## @brief Converts numeric logging level to the first letter of level name.
865#
866# @param lvl Numeric logging level in range from 1 to 6.
867# @retval 1 if @a lvl is out of range.
868# @retval 0 if @a lvl is correct.
869# @result Echoes first letter of level name.
870_lvl2char() {
871 case "$1" in
872 1) echo F;;
873 2) echo E;;
874 3) echo W;;
875 4) echo I;;
876 5) echo D;;
877 6) echo T;;
878 *) return 1;;
879 esac
880}
881
882## @brief Internal helper function for _do_dlog()
883#
884# @param lvl Numeric logging level.
885# @param msg Message.
886# @retval 0 It's always returned, even if logging failed.
887#
888# @note This function is not supposed to be called manually. Please use
889# dtrace(), ddebug(), or others instead which wrap this one.
890#
891# This function calls _do_dlog() either with parameter msg, or if
892# none is given, it will read standard input and will use every line as
893# a message.
894#
895# This enables:
896# dwarn "This is a warning"
897# echo "This is a warning" | dwarn
20fc56c0 898LOG_LEVEL=${LOG_LEVEL:-4}
898720b7
HH
899
900dlog() {
901 [ -z "$LOG_LEVEL" ] && return 0
902 [ $1 -le $LOG_LEVEL ] || return 0
903 local lvl="$1"; shift
904 local lvlc=$(_lvl2char "$lvl") || return 0
905
906 if [ $# -ge 1 ]; then
907 echo "$lvlc: $*"
908 else
909 while read line; do
910 echo "$lvlc: " "$line"
911 done
912 fi
913}
914
915## @brief Logs message at TRACE level (6)
916#
917# @param msg Message.
918# @retval 0 It's always returned, even if logging failed.
919dtrace() {
920 set +x
921 dlog 6 "$@"
922 [ -n "$debug" ] && set -x || :
923}
924
925## @brief Logs message at DEBUG level (5)
926#
927# @param msg Message.
928# @retval 0 It's always returned, even if logging failed.
929ddebug() {
0d6e798a 930# set +x
898720b7 931 dlog 5 "$@"
0d6e798a 932# [ -n "$debug" ] && set -x || :
898720b7
HH
933}
934
935## @brief Logs message at INFO level (4)
936#
937# @param msg Message.
938# @retval 0 It's always returned, even if logging failed.
939dinfo() {
940 set +x
941 dlog 4 "$@"
942 [ -n "$debug" ] && set -x || :
943}
944
945## @brief Logs message at WARN level (3)
946#
947# @param msg Message.
948# @retval 0 It's always returned, even if logging failed.
949dwarn() {
950 set +x
951 dlog 3 "$@"
952 [ -n "$debug" ] && set -x || :
953}
954
955## @brief Logs message at ERROR level (2)
956#
957# @param msg Message.
958# @retval 0 It's always returned, even if logging failed.
959derror() {
0d6e798a 960# set +x
898720b7 961 dlog 2 "$@"
0d6e798a 962# [ -n "$debug" ] && set -x || :
898720b7
HH
963}
964
965## @brief Logs message at FATAL level (1)
966#
967# @param msg Message.
968# @retval 0 It's always returned, even if logging failed.
969dfatal() {
970 set +x
971 dlog 1 "$@"
972 [ -n "$debug" ] && set -x || :
973}
974
975
976# Generic substring function. If $2 is in $1, return 0.
977strstr() { [ "${1#*$2*}" != "$1" ]; }
978
979# normalize_path <path>
980# Prints the normalized path, where it removes any duplicated
981# and trailing slashes.
982# Example:
983# $ normalize_path ///test/test//
984# /test/test
985normalize_path() {
986 shopt -q -s extglob
987 set -- "${1//+(\/)//}"
988 shopt -q -u extglob
989 echo "${1%/}"
990}
991
992# convert_abs_rel <from> <to>
993# Prints the relative path, when creating a symlink to <to> from <from>.
994# Example:
995# $ convert_abs_rel /usr/bin/test /bin/test-2
996# ../../bin/test-2
997# $ ln -s $(convert_abs_rel /usr/bin/test /bin/test-2) /usr/bin/test
998convert_abs_rel() {
999 local __current __absolute __abssize __cursize __newpath
1000 local -i __i __level
1001
1002 set -- "$(normalize_path "$1")" "$(normalize_path "$2")"
1003
1004 # corner case #1 - self looping link
1005 [[ "$1" == "$2" ]] && { echo "${1##*/}"; return; }
1006
1007 # corner case #2 - own dir link
1008 [[ "${1%/*}" == "$2" ]] && { echo "."; return; }
1009
1010 IFS="/" __current=($1)
1011 IFS="/" __absolute=($2)
1012
1013 __abssize=${#__absolute[@]}
1014 __cursize=${#__current[@]}
1015
1016 while [[ ${__absolute[__level]} == ${__current[__level]} ]]
1017 do
1018 (( __level++ ))
1019 if (( __level > __abssize || __level > __cursize ))
1020 then
1021 break
1022 fi
1023 done
1024
1025 for ((__i = __level; __i < __cursize-1; __i++))
1026 do
1027 if ((__i > __level))
1028 then
1029 __newpath=$__newpath"/"
1030 fi
1031 __newpath=$__newpath".."
1032 done
1033
1034 for ((__i = __level; __i < __abssize; __i++))
1035 do
1036 if [[ -n $__newpath ]]
1037 then
1038 __newpath=$__newpath"/"
1039 fi
1040 __newpath=$__newpath${__absolute[__i]}
1041 done
1042
1043 echo "$__newpath"
1044}
1045
1046
1047# Install a directory, keeping symlinks as on the original system.
1048# Example: if /lib points to /lib64 on the host, "inst_dir /lib/file"
1049# will create ${initdir}/lib64, ${initdir}/lib64/file,
1050# and a symlink ${initdir}/lib -> lib64.
1051inst_dir() {
1052 [[ -e ${initdir}/"$1" ]] && return 0 # already there
1053
1054 local _dir="$1" _part="${1%/*}" _file
1055 while [[ "$_part" != "${_part%/*}" ]] && ! [[ -e "${initdir}/${_part}" ]]; do
1056 _dir="$_part $_dir"
1057 _part=${_part%/*}
1058 done
1059
1060 # iterate over parent directories
1061 for _file in $_dir; do
1062 [[ -e "${initdir}/$_file" ]] && continue
1063 if [[ -L $_file ]]; then
1064 inst_symlink "$_file"
1065 else
1066 # create directory
1067 mkdir -m 0755 -p "${initdir}/$_file" || return 1
1068 [[ -e "$_file" ]] && chmod --reference="$_file" "${initdir}/$_file"
1069 chmod u+w "${initdir}/$_file"
1070 fi
1071 done
1072}
1073
1074# $1 = file to copy to ramdisk
1075# $2 (optional) Name for the file on the ramdisk
1076# Location of the image dir is assumed to be $initdir
1077# We never overwrite the target if it exists.
1078inst_simple() {
1079 [[ -f "$1" ]] || return 1
1080 strstr "$1" "/" || return 1
1081
1082 local _src=$1 target="${2:-$1}"
1083 if ! [[ -d ${initdir}/$target ]]; then
1084 [[ -e ${initdir}/$target ]] && return 0
1085 [[ -L ${initdir}/$target ]] && return 0
1086 [[ -d "${initdir}/${target%/*}" ]] || inst_dir "${target%/*}"
1087 fi
1088 # install checksum files also
1089 if [[ -e "${_src%/*}/.${_src##*/}.hmac" ]]; then
1090 inst "${_src%/*}/.${_src##*/}.hmac" "${target%/*}/.${target##*/}.hmac"
1091 fi
1092 ddebug "Installing $_src"
1093 cp --sparse=always -pfL "$_src" "${initdir}/$target"
1094}
1095
1096# find symlinks linked to given library file
1097# $1 = library file
1098# Function searches for symlinks by stripping version numbers appended to
1099# library filename, checks if it points to the same target and finally
1100# prints the list of symlinks to stdout.
1101#
1102# Example:
1103# rev_lib_symlinks libfoo.so.8.1
1104# output: libfoo.so.8 libfoo.so
1105# (Only if libfoo.so.8 and libfoo.so exists on host system.)
1106rev_lib_symlinks() {
1107 [[ ! $1 ]] && return 0
1108
1109 local fn="$1" orig="$(readlink -f "$1")" links=''
1110
1111 [[ ${fn} =~ .*\.so\..* ]] || return 1
1112
1113 until [[ ${fn##*.} == so ]]; do
1114 fn="${fn%.*}"
1115 [[ -L ${fn} && $(readlink -f "${fn}") == ${orig} ]] && links+=" ${fn}"
1116 done
1117
1118 echo "${links}"
1119}
1120
1121# Same as above, but specialized to handle dynamic libraries.
1122# It handles making symlinks according to how the original library
1123# is referenced.
1124inst_library() {
1125 local _src="$1" _dest=${2:-$1} _lib _reallib _symlink
1126 strstr "$1" "/" || return 1
1127 [[ -e $initdir/$_dest ]] && return 0
1128 if [[ -L $_src ]]; then
1129 # install checksum files also
1130 if [[ -e "${_src%/*}/.${_src##*/}.hmac" ]]; then
1131 inst "${_src%/*}/.${_src##*/}.hmac" "${_dest%/*}/.${_dest##*/}.hmac"
1132 fi
1133 _reallib=$(readlink -f "$_src")
1134 inst_simple "$_reallib" "$_reallib"
1135 inst_dir "${_dest%/*}"
1136 [[ -d "${_dest%/*}" ]] && _dest=$(readlink -f "${_dest%/*}")/${_dest##*/}
1137 ln -sfn $(convert_abs_rel "${_dest}" "${_reallib}") "${initdir}/${_dest}"
1138 else
1139 inst_simple "$_src" "$_dest"
1140 fi
1141
1142 # Create additional symlinks. See rev_symlinks description.
1143 for _symlink in $(rev_lib_symlinks $_src) $(rev_lib_symlinks $_reallib); do
818567fc 1144 [[ -e $initdir/$_symlink ]] || {
898720b7
HH
1145 ddebug "Creating extra symlink: $_symlink"
1146 inst_symlink $_symlink
1147 }
1148 done
1149}
1150
1151# find a binary. If we were not passed the full path directly,
1152# search in the usual places to find the binary.
1153find_binary() {
1154 if [[ -z ${1##/*} ]]; then
1155 if [[ -x $1 ]] || { strstr "$1" ".so" && ldd $1 &>/dev/null; }; then
1156 echo $1
1157 return 0
1158 fi
1159 fi
1160
1161 type -P $1
1162}
1163
1164# Same as above, but specialized to install binary executables.
1165# Install binary executable, and all shared library dependencies, if any.
1166inst_binary() {
1167 local _bin _target
1168 _bin=$(find_binary "$1") || return 1
1169 _target=${2:-$_bin}
1170 [[ -e $initdir/$_target ]] && return 0
1171 [[ -L $_bin ]] && inst_symlink $_bin $_target && return 0
1172 local _file _line
1173 local _so_regex='([^ ]*/lib[^/]*/[^ ]*\.so[^ ]*)'
1174 # I love bash!
1175 LC_ALL=C ldd "$_bin" 2>/dev/null | while read _line; do
1176 [[ $_line = 'not a dynamic executable' ]] && break
1177
1178 if [[ $_line =~ $_so_regex ]]; then
1179 _file=${BASH_REMATCH[1]}
1180 [[ -e ${initdir}/$_file ]] && continue
1181 inst_library "$_file"
1182 continue
1183 fi
1184
1185 if [[ $_line =~ not\ found ]]; then
1186 dfatal "Missing a shared library required by $_bin."
1187 dfatal "Run \"ldd $_bin\" to find out what it is."
1188 dfatal "$_line"
1189 dfatal "dracut cannot create an initrd."
1190 exit 1
1191 fi
1192 done
1193 inst_simple "$_bin" "$_target"
1194}
1195
1196# same as above, except for shell scripts.
1197# If your shell script does not start with shebang, it is not a shell script.
1198inst_script() {
1199 local _bin
1200 _bin=$(find_binary "$1") || return 1
1201 shift
1202 local _line _shebang_regex
1203 read -r -n 80 _line <"$_bin"
1204 # If debug is set, clean unprintable chars to prevent messing up the term
1205 [[ $debug ]] && _line=$(echo -n "$_line" | tr -c -d '[:print:][:space:]')
1206 _shebang_regex='(#! *)(/[^ ]+).*'
1207 [[ $_line =~ $_shebang_regex ]] || return 1
1208 inst "${BASH_REMATCH[2]}" && inst_simple "$_bin" "$@"
1209}
1210
1211# same as above, but specialized for symlinks
1212inst_symlink() {
1213 local _src=$1 _target=${2:-$1} _realsrc
1214 strstr "$1" "/" || return 1
1215 [[ -L $1 ]] || return 1
1216 [[ -L $initdir/$_target ]] && return 0
1217 _realsrc=$(readlink -f "$_src")
1218 if ! [[ -e $initdir/$_realsrc ]]; then
1219 if [[ -d $_realsrc ]]; then
1220 inst_dir "$_realsrc"
1221 else
1222 inst "$_realsrc"
1223 fi
1224 fi
1225 [[ ! -e $initdir/${_target%/*} ]] && inst_dir "${_target%/*}"
1226 [[ -d ${_target%/*} ]] && _target=$(readlink -f ${_target%/*})/${_target##*/}
1227 ln -sfn $(convert_abs_rel "${_target}" "${_realsrc}") "$initdir/$_target"
1228}
1229
1230# attempt to install any programs specified in a udev rule
1231inst_rule_programs() {
1232 local _prog _bin
1233
1234 if grep -qE 'PROGRAM==?"[^ "]+' "$1"; then
1235 for _prog in $(grep -E 'PROGRAM==?"[^ "]+' "$1" | sed -r 's/.*PROGRAM==?"([^ "]+).*/\1/'); do
1236 if [ -x /lib/udev/$_prog ]; then
1237 _bin=/lib/udev/$_prog
1238 else
1239 _bin=$(find_binary "$_prog") || {
1240 dinfo "Skipping program $_prog using in udev rule $(basename $1) as it cannot be found"
1241 continue;
1242 }
1243 fi
1244
1245 #dinfo "Installing $_bin due to it's use in the udev rule $(basename $1)"
1246 dracut_install "$_bin"
1247 done
1248 fi
1249}
1250
1251# udev rules always get installed in the same place, so
1252# create a function to install them to make life simpler.
1253inst_rules() {
1254 local _target=/etc/udev/rules.d _rule _found
1255
1256 inst_dir "/lib/udev/rules.d"
1257 inst_dir "$_target"
1258 for _rule in "$@"; do
1259 if [ "${rule#/}" = "$rule" ]; then
1260 for r in /lib/udev/rules.d /etc/udev/rules.d; do
1261 if [[ -f $r/$_rule ]]; then
1262 _found="$r/$_rule"
1263 inst_simple "$_found"
1264 inst_rule_programs "$_found"
1265 fi
1266 done
1267 fi
1268 for r in '' ./ $dracutbasedir/rules.d/; do
1269 if [[ -f ${r}$_rule ]]; then
1270 _found="${r}$_rule"
1271 inst_simple "$_found" "$_target/${_found##*/}"
1272 inst_rule_programs "$_found"
1273 fi
1274 done
1275 [[ $_found ]] || dinfo "Skipping udev rule: $_rule"
31ce89e7 1276 _found=
898720b7
HH
1277 done
1278}
1279
1280# general purpose installation function
1281# Same args as above.
1282inst() {
1283 local _x
1284
1285 case $# in
1286 1) ;;
1287 2) [[ ! $initdir && -d $2 ]] && export initdir=$2
1288 [[ $initdir = $2 ]] && set $1;;
1289 3) [[ -z $initdir ]] && export initdir=$2
1290 set $1 $3;;
1291 *) dfatal "inst only takes 1 or 2 or 3 arguments"
1292 exit 1;;
1293 esac
1294 for _x in inst_symlink inst_script inst_binary inst_simple; do
1295 $_x "$@" && return 0
1296 done
1297 return 1
1298}
1299
1300# install any of listed files
1301#
1302# If first argument is '-d' and second some destination path, first accessible
1303# source is installed into this path, otherwise it will installed in the same
1304# path as source. If none of listed files was installed, function return 1.
1305# On first successful installation it returns with 0 status.
1306#
1307# Example:
1308#
1309# inst_any -d /bin/foo /bin/bar /bin/baz
1310#
1311# Lets assume that /bin/baz exists, so it will be installed as /bin/foo in
1312# initramfs.
1313inst_any() {
1314 local to f
1315
1316 [[ $1 = '-d' ]] && to="$2" && shift 2
1317
1318 for f in "$@"; do
1319 if [[ -e $f ]]; then
1320 [[ $to ]] && inst "$f" "$to" && return 0
1321 inst "$f" && return 0
1322 fi
1323 done
1324
1325 return 1
1326}
1327
1328# dracut_install [-o ] <file> [<file> ... ]
1329# Install <file> to the initramfs image
1330# -o optionally install the <file> and don't fail, if it is not there
1331dracut_install() {
1332 local _optional=no
1333 if [[ $1 = '-o' ]]; then
1334 _optional=yes
1335 shift
1336 fi
1337 while (($# > 0)); do
1338 if ! inst "$1" ; then
1339 if [[ $_optional = yes ]]; then
1340 dinfo "Skipping program $1 as it cannot be found and is" \
1341 "flagged to be optional"
1342 else
1343 dfatal "Failed to install $1"
1344 exit 1
1345 fi
1346 fi
1347 shift
1348 done
1349}
1350
0d6e798a
HH
1351# Install a single kernel module along with any firmware it may require.
1352# $1 = full path to kernel module to install
1353install_kmod_with_fw() {
1354 # no need to go further if the module is already installed
1355
1356 [[ -e "${initdir}/lib/modules/$KERNEL_VER/${1##*/lib/modules/$KERNEL_VER/}" ]] \
1357 && return 0
1358
1359 [[ -e "$initdir/.kernelmodseen/${1##*/}" ]] && return 0
1360
1361 if [[ $omit_drivers ]]; then
1362 local _kmod=${1##*/}
1363 _kmod=${_kmod%.ko}
1364 _kmod=${_kmod/-/_}
1365 if [[ "$_kmod" =~ $omit_drivers ]]; then
1366 dinfo "Omitting driver $_kmod"
1367 return 1
1368 fi
1369 if [[ "${1##*/lib/modules/$KERNEL_VER/}" =~ $omit_drivers ]]; then
1370 dinfo "Omitting driver $_kmod"
1371 return 1
1372 fi
1373 fi
1374
1375 [ -d "$initdir/.kernelmodseen" ] && \
1376 > "$initdir/.kernelmodseen/${1##*/}"
1377
1378 inst_simple "$1" "/lib/modules/$KERNEL_VER/${1##*/lib/modules/$KERNEL_VER/}" \
1379 || return $?
1380
1381 local _modname=${1##*/} _fwdir _found _fw
1382 _modname=${_modname%.ko*}
1383 for _fw in $(modinfo -k $KERNEL_VER -F firmware $1 2>/dev/null); do
1384 _found=''
1385 for _fwdir in $fw_dir; do
1386 if [[ -d $_fwdir && -f $_fwdir/$_fw ]]; then
1387 inst_simple "$_fwdir/$_fw" "/lib/firmware/$_fw"
1388 _found=yes
1389 fi
1390 done
1391 if [[ $_found != yes ]]; then
1392 if ! grep -qe "\<${_modname//-/_}\>" /proc/modules; then
1393 dinfo "Possible missing firmware \"${_fw}\" for kernel module" \
1394 "\"${_modname}.ko\""
1395 else
1396 dwarn "Possible missing firmware \"${_fw}\" for kernel module" \
1397 "\"${_modname}.ko\""
1398 fi
1399 fi
1400 done
1401 return 0
1402}
1403
1404# Do something with all the dependencies of a kernel module.
1405# Note that kernel modules depend on themselves using the technique we use
1406# $1 = function to call for each dependency we find
1407# It will be passed the full path to the found kernel module
1408# $2 = module to get dependencies for
1409# rest of args = arguments to modprobe
1410# _fderr specifies FD passed from surrounding scope
1411for_each_kmod_dep() {
1412 local _func=$1 _kmod=$2 _cmd _modpath _options _found=0
1413 shift 2
1414 modprobe "$@" --ignore-install --show-depends $_kmod 2>&${_fderr} | (
1415 while read _cmd _modpath _options; do
1416 [[ $_cmd = insmod ]] || continue
1417 $_func ${_modpath} || exit $?
1418 _found=1
1419 done
1420 [[ $_found -eq 0 ]] && exit 1
1421 exit 0
1422 )
1423}
1424
1425# filter kernel modules to install certain modules that meet specific
1426# requirements.
1427# $1 = search only in subdirectory of /kernel/$1
1428# $2 = function to call with module name to filter.
1429# This function will be passed the full path to the module to test.
c5315881 1430# The behavior of this function can vary depending on whether $hostonly is set.
0d6e798a
HH
1431# If it is, we will only look at modules that are already in memory.
1432# If it is not, we will look at all kernel modules
1433# This function returns the full filenames of modules that match $1
1434filter_kernel_modules_by_path () (
1435 local _modname _filtercmd
1436 if ! [[ $hostonly ]]; then
1437 _filtercmd='find "$KERNEL_MODS/kernel/$1" "$KERNEL_MODS/extra"'
1438 _filtercmd+=' "$KERNEL_MODS/weak-updates" -name "*.ko" -o -name "*.ko.gz"'
1439 _filtercmd+=' -o -name "*.ko.xz"'
1440 _filtercmd+=' 2>/dev/null'
1441 else
1442 _filtercmd='cut -d " " -f 1 </proc/modules|xargs modinfo -F filename '
1443 _filtercmd+='-k $KERNEL_VER 2>/dev/null'
1444 fi
1445 for _modname in $(eval $_filtercmd); do
1446 case $_modname in
1447 *.ko) "$2" "$_modname" && echo "$_modname";;
1448 *.ko.gz) gzip -dc "$_modname" > $initdir/$$.ko
1449 $2 $initdir/$$.ko && echo "$_modname"
1450 rm -f $initdir/$$.ko
1451 ;;
1452 *.ko.xz) xz -dc "$_modname" > $initdir/$$.ko
1453 $2 $initdir/$$.ko && echo "$_modname"
1454 rm -f $initdir/$$.ko
1455 ;;
1456 esac
1457 done
1458)
1459find_kernel_modules_by_path () (
1460 if ! [[ $hostonly ]]; then
1461 find "$KERNEL_MODS/kernel/$1" "$KERNEL_MODS/extra" "$KERNEL_MODS/weak-updates" \
1462 -name "*.ko" -o -name "*.ko.gz" -o -name "*.ko.xz" 2>/dev/null
1463 else
1464 cut -d " " -f 1 </proc/modules \
1465 | xargs modinfo -F filename -k $KERNEL_VER 2>/dev/null
1466 fi
1467)
1468
1469filter_kernel_modules () {
1470 filter_kernel_modules_by_path drivers "$1"
1471}
1472
1473find_kernel_modules () {
1474 find_kernel_modules_by_path drivers
1475}
1476
1477# instmods [-c] <kernel module> [<kernel module> ... ]
1478# instmods [-c] <kernel subsystem>
1479# install kernel modules along with all their dependencies.
1480# <kernel subsystem> can be e.g. "=block" or "=drivers/usb/storage"
1481instmods() {
1482 [[ $no_kernel = yes ]] && return
1483 # called [sub]functions inherit _fderr
1484 local _fderr=9
1485 local _check=no
1486 if [[ $1 = '-c' ]]; then
1487 _check=yes
1488 shift
1489 fi
1490
1491 function inst1mod() {
1492 local _ret=0 _mod="$1"
1493 case $_mod in
1494 =*)
1495 if [ -f $KERNEL_MODS/modules.${_mod#=} ]; then
1496 ( [[ "$_mpargs" ]] && echo $_mpargs
1497 cat "${KERNEL_MODS}/modules.${_mod#=}" ) \
1498 | instmods
1499 else
1500 ( [[ "$_mpargs" ]] && echo $_mpargs
1501 find "$KERNEL_MODS" -path "*/${_mod#=}/*" -printf '%f\n' ) \
1502 | instmods
1503 fi
1504 ;;
1505 --*) _mpargs+=" $_mod" ;;
1506 i2o_scsi) return ;; # Do not load this diagnostic-only module
1507 *)
1508 _mod=${_mod##*/}
1509 # if we are already installed, skip this module and go on
1510 # to the next one.
1511 [[ -f "$initdir/.kernelmodseen/${_mod%.ko}.ko" ]] && return
1512
1513 if [[ $omit_drivers ]] && [[ "$1" =~ $omit_drivers ]]; then
1514 dinfo "Omitting driver ${_mod##$KERNEL_MODS}"
1515 return
1516 fi
1517 # If we are building a host-specific initramfs and this
1518 # module is not already loaded, move on to the next one.
1519 [[ $hostonly ]] && ! grep -qe "\<${_mod//-/_}\>" /proc/modules \
1520 && ! echo $add_drivers | grep -qe "\<${_mod}\>" \
1521 && return
1522
1523 # We use '-d' option in modprobe only if modules prefix path
1524 # differs from default '/'. This allows us to use Dracut with
1525 # old version of modprobe which doesn't have '-d' option.
1526 local _moddirname=${KERNEL_MODS%%/lib/modules/*}
1527 [[ -n ${_moddirname} ]] && _moddirname="-d ${_moddirname}/"
1528
1529 # ok, load the module, all its dependencies, and any firmware
1530 # it may require
1531 for_each_kmod_dep install_kmod_with_fw $_mod \
1532 --set-version $KERNEL_VER ${_moddirname} $_mpargs
1533 ((_ret+=$?))
1534 ;;
1535 esac
1536 return $_ret
1537 }
1538
1539 function instmods_1() {
1540 local _mod _mpargs
1541 if (($# == 0)); then # filenames from stdin
1542 while read _mod; do
1543 inst1mod "${_mod%.ko*}" || {
1544 if [ "$_check" = "yes" ]; then
1545 dfatal "Failed to install $_mod"
1546 return 1
1547 fi
1548 }
1549 done
1550 fi
1551 while (($# > 0)); do # filenames as arguments
1552 inst1mod ${1%.ko*} || {
1553 if [ "$_check" = "yes" ]; then
1554 dfatal "Failed to install $1"
1555 return 1
1556 fi
1557 }
1558 shift
1559 done
1560 return 0
1561 }
1562
1563 local _ret _filter_not_found='FATAL: Module .* not found.'
1564 set -o pipefail
1565 # Capture all stderr from modprobe to _fderr. We could use {var}>...
1566 # redirections, but that would make dracut require bash4 at least.
1567 eval "( instmods_1 \"\$@\" ) ${_fderr}>&1" \
1568 | while read line; do [[ "$line" =~ $_filter_not_found ]] && echo $line || echo $line >&2 ;done | derror
1569 _ret=$?
1570 set +o pipefail
1571 return $_ret
1572}
898720b7
HH
1573
1574# inst_libdir_file [-n <pattern>] <file> [<file>...]
1575# Install a <file> located on a lib directory to the initramfs image
1576# -n <pattern> install non-matching files
1577inst_libdir_file() {
1578 if [[ "$1" == "-n" ]]; then
1579 local _pattern=$1
1580 shift 2
1581 for _dir in $libdirs; do
1582 for _i in "$@"; do
1583 for _f in "$_dir"/$_i; do
1584 [[ "$_i" =~ $_pattern ]] || continue
1585 [[ -e "$_i" ]] && dracut_install "$_i"
1586 done
1587 done
1588 done
1589 else
1590 for _dir in $libdirs; do
1591 for _i in "$@"; do
1592 for _f in "$_dir"/$_i; do
1593 [[ -e "$_f" ]] && dracut_install "$_f"
1594 done
1595 done
1596 done
1597 fi
1598}
1599
85393d8f 1600setup_suse() {
caced732
FB
1601 ln -fs ../usr/bin/systemctl $initdir/bin/
1602 ln -fs ../usr/lib/systemd $initdir/lib/
85393d8f
TB
1603 inst_simple "/usr/lib/systemd/system/haveged.service"
1604}
1605
054ee249
MP
1606# can be overridden in specific test
1607test_cleanup() {
1608 umount $TESTDIR/root 2>/dev/null || true
818567fc 1609 [[ $LOOPDEV ]] && losetup -d $LOOPDEV || true
054ee249
MP
1610 return 0
1611}
1612
1613test_run() {
1614 if [ -z "$TEST_NO_QEMU" ]; then
1615 if run_qemu; then
1616 check_result_qemu || return 1
1617 else
1618 dwarn "can't run QEMU, skipping"
1619 fi
1620 fi
1621 if [ -z "$TEST_NO_NSPAWN" ]; then
746fbd9c
EV
1622 if run_nspawn "nspawn-root"; then
1623 check_result_nspawn "nspawn-root" || return 1
054ee249
MP
1624 else
1625 dwarn "can't run systemd-nspawn, skipping"
1626 fi
746fbd9c
EV
1627
1628 if [[ "$RUN_IN_UNPRIVILEGED_CONTAINER" = "yes" ]]; then
1629 if NSPAWN_ARGUMENTS="-U --private-network $NSPAWN_ARGUMENTS" run_nspawn "unprivileged-nspawn-root"; then
1630 check_result_nspawn "unprivileged-nspawn-root" || return 1
1631 else
1632 dwarn "can't run systemd-nspawn, skipping"
1633 fi
d56db495 1634 fi
054ee249
MP
1635 fi
1636 return 0
1637}
1638
898720b7 1639do_test() {
33a5e20f
HH
1640 if [[ $UID != "0" ]]; then
1641 echo "TEST: $TEST_DESCRIPTION [SKIPPED]: not root" >&2
1642 exit 0
1643 fi
1644
cc5549ca 1645 # Detect lib paths
898720b7
HH
1646 [[ $libdir ]] || for libdir in /lib64 /lib; do
1647 [[ -d $libdir ]] && libdirs+=" $libdir" && break
1648 done
1649
1650 [[ $usrlibdir ]] || for usrlibdir in /usr/lib64 /usr/lib; do
1651 [[ -d $usrlibdir ]] && libdirs+=" $usrlibdir" && break
1652 done
1653
22077c9c
MP
1654 mkdir -p "$STATEDIR"
1655
898720b7 1656 import_testdir
889a9042 1657 import_initdir
898720b7
HH
1658
1659 while (($# > 0)); do
1660 case $1 in
1661 --run)
1662 echo "TEST RUN: $TEST_DESCRIPTION"
0013fac2
YW
1663 test_run
1664 ret=$?
1665 if (( $ret == 0 )); then
898720b7
HH
1666 echo "TEST RUN: $TEST_DESCRIPTION [OK]"
1667 else
1668 echo "TEST RUN: $TEST_DESCRIPTION [FAILED]"
1669 fi
1670 exit $ret;;
1671 --setup)
1672 echo "TEST SETUP: $TEST_DESCRIPTION"
1673 test_setup
818567fc 1674 ;;
898720b7
HH
1675 --clean)
1676 echo "TEST CLEANUP: $TEST_DESCRIPTION"
1677 test_cleanup
1678 rm -fr "$TESTDIR"
22077c9c 1679 rm -f "$STATEFILE"
818567fc 1680 ;;
898720b7 1681 --all)
818567fc 1682 ret=0
898720b7
HH
1683 echo -n "TEST: $TEST_DESCRIPTION ";
1684 (
1685 test_setup && test_run
1686 ret=$?
1687 test_cleanup
1688 rm -fr "$TESTDIR"
22077c9c 1689 rm -f "$STATEFILE"
898720b7 1690 exit $ret
818567fc 1691 ) </dev/null >"$TESTLOG" 2>&1 || ret=$?
898720b7 1692 if [ $ret -eq 0 ]; then
22077c9c 1693 rm "$TESTLOG"
898720b7
HH
1694 echo "[OK]"
1695 else
1696 echo "[FAILED]"
22077c9c 1697 echo "see $TESTLOG"
898720b7
HH
1698 fi
1699 exit $ret;;
1700 *) break ;;
1701 esac
1702 shift
1703 done
1704}