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