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