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