2 # -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
3 # ex: ts=8 sw=4 sts=4 et filetype=sh
4 PATH
=/sbin
:/bin
:/usr
/sbin
:/usr
/bin
7 LOOKS_LIKE_DEBIAN
=$
(source /etc
/os-release
&& [[ "$ID" = "debian" ||
" $ID_LIKE " = *" debian "* ]] && echo yes ||
:)
8 LOOKS_LIKE_ARCH
=$
(source /etc
/os-release
&& [[ "$ID" = "arch" ||
" $ID_LIKE " = *" arch "* ]] && echo yes ||
:)
9 LOOKS_LIKE_SUSE
=$
(source /etc
/os-release
&& [[ " $ID_LIKE " = *" suse "* ]] && echo yes ||
:)
10 KERNEL_VER
=${KERNEL_VER-$(uname -r)}
11 KERNEL_MODS
="/lib/modules/$KERNEL_VER/"
12 QEMU_TIMEOUT
="${QEMU_TIMEOUT:-infinity}"
13 NSPAWN_TIMEOUT
="${NSPAWN_TIMEOUT:-infinity}"
14 TIMED_OUT
= # will be 1 after run_* if *_TIMEOUT is set and test timed out
15 [[ "$LOOKS_LIKE_SUSE" ]] && FSTYPE
="${FSTYPE:-btrfs}" || FSTYPE
="${FSTYPE:-ext4}"
16 UNIFIED_CGROUP_HIERARCHY
="${UNIFIED_CGROUP_HIERARCHY:-default}"
17 EFI_MOUNT
="$(bootctl -x 2>/dev/null || echo /boot)"
18 QEMU_MEM
="${QEMU_MEM:-512M}"
20 # Decide if we can (and want to) run QEMU with KVM acceleration.
21 # Check if nested KVM is explicitly enabled (TEST_NESTED_KVM). If not,
22 # check if it's not explicitly disabled (TEST_NO_KVM) and we're not already
23 # running under KVM. If these conditions are met, enable KVM (and possibly
24 # nested KVM), otherwise disable it.
25 if [[ -n "$TEST_NESTED_KVM" ||
( -z "$TEST_NO_KVM" && $
(systemd-detect-virt
-v) != kvm
) ]]; then
31 if ! ROOTLIBDIR
=$
(pkg-config
--variable=systemdutildir systemd
); then
32 echo "WARNING! Cannot determine rootlibdir from pkg-config, assuming /usr/lib/systemd" >&2
33 ROOTLIBDIR
=/usr
/lib
/systemd
36 PATH_TO_INIT
=$ROOTLIBDIR/systemd
37 [ "$SYSTEMD_JOURNALD" ] || SYSTEMD_JOURNALD
=$
(which -a $BUILD_DIR/systemd-journald
$ROOTLIBDIR/systemd-journald
2>/dev
/null |
grep '^/' -m1)
38 [ "$SYSTEMD" ] || SYSTEMD
=$
(which -a $BUILD_DIR/systemd
$ROOTLIBDIR/systemd
2>/dev
/null |
grep '^/' -m1)
39 [ "$SYSTEMD_NSPAWN" ] || SYSTEMD_NSPAWN
=$
(which -a $BUILD_DIR/systemd-nspawn systemd-nspawn
2>/dev
/null |
grep '^/' -m1)
40 [ "$JOURNALCTL" ] || JOURNALCTL
=$
(which -a $BUILD_DIR/journalctl journalctl
2>/dev
/null |
grep '^/' -m1)
42 BASICTOOLS
="test env 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"
43 DEBUGTOOLS
="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"
45 STATEDIR
="${BUILD_DIR:-.}/test/$(basename $(dirname $(realpath $0)))"
46 STATEFILE
="$STATEDIR/.testdir"
47 TESTLOG
="$STATEDIR/test.log"
49 is_built_with_asan
() {
50 if ! type -P objdump
>/dev
/null
; then
51 ddebug
"Failed to find objdump. Assuming systemd hasn't been built with ASAN."
55 # Borrowed from https://github.com/google/oss-fuzz/blob/cd9acd02f9d3f6e80011cc1e9549be526ce5f270/infra/base-images/base-runner/bad_build_check#L182
56 local _asan_calls
=$
(objdump
-dC $SYSTEMD_JOURNALD |
egrep "callq\s+[0-9a-f]+\s+<__asan" -c)
57 if (( $_asan_calls < 1000 )); then
64 IS_BUILT_WITH_ASAN
=$
(is_built_with_asan
&& echo yes ||
echo no
)
66 if [[ "$IS_BUILT_WITH_ASAN" = "yes" ]]; then
68 SKIP_INITRD
="${SKIP_INITRD:-yes}"
69 PATH_TO_INIT
=$ROOTLIBDIR/systemd-under-asan
73 # We need to correctly distinguish between gcc's and clang's ASan DSOs.
74 if ldd
$SYSTEMD |
grep -q libasan.so
; then
76 elif ldd
$SYSTEMD |
grep -q libclang_rt.asan
; then
79 # As clang's ASan DSO is usually in a non-standard path, let's check if
80 # the environment is set accordingly. If not, warn the user and exit.
81 # We're not setting the LD_LIBRARY_PATH automagically here, because
82 # user should encounter (and fix) the same issue when running the unit
84 if ldd
"$SYSTEMD" |
grep -q "libclang_rt.asan.*not found"; then
85 _asan_rt_name
="$(ldd $SYSTEMD | awk '/libclang_rt.asan/ {print $1; exit}')"
86 _asan_rt_path
="$(find /usr/lib* /usr/local/lib* -type f -name "$_asan_rt_name" 2>/dev/null | sed 1q)"
87 echo >&2 "clang's ASan DSO ($_asan_rt_name) is not present in the runtime library path"
88 echo >&2 "Consider setting LD_LIBRARY_PATH=${_asan_rt_path%/*}"
92 echo >&2 "systemd is not linked against the ASan DSO"
93 echo >&2 "gcc does this by default, for clang compile with -shared-libasan"
98 function find_qemu_bin
() {
99 # SUSE and Red Hat call the binary qemu-kvm. Debian and Gentoo call it kvm.
100 if [[ $QEMU_KVM == "yes" ]]; then
101 [ "$QEMU_BIN" ] || QEMU_BIN
=$
(which -a kvm qemu-kvm
2>/dev
/null |
grep '^/' -m1)
104 [ "$ARCH" ] || ARCH
=$
(uname
-m)
107 # QEMU's own build system calls it qemu-system-x86_64
108 [ "$QEMU_BIN" ] || QEMU_BIN
=$
(which -a qemu-system-x86_64
2>/dev
/null |
grep '^/' -m1)
111 # new i386 version of QEMU
112 [ "$QEMU_BIN" ] || QEMU_BIN
=$
(which -a qemu-system-i386
2>/dev
/null |
grep '^/' -m1)
114 # i386 version of QEMU
115 [ "$QEMU_BIN" ] || QEMU_BIN
=$
(which -a qemu
2>/dev
/null |
grep '^/' -m1)
118 [ "$QEMU_BIN" ] || QEMU_BIN
=$
(which -a qemu-system-ppc64
2>/dev
/null |
grep '^/' -m1)
122 if [ ! -e "$QEMU_BIN" ]; then
123 echo "Could not find a suitable QEMU binary" >&2
128 # Return 0 if QEMU did run (then you must check the result state/logs for actual
129 # success), or 1 if QEMU is not available.
131 if [ -f /etc
/machine-id
]; then
132 read MACHINE_ID
< /etc
/machine-id
133 [ -z "$INITRD" ] && [ -e "$EFI_MOUNT/$MACHINE_ID/$KERNEL_VER/initrd" ] \
134 && INITRD
="$EFI_MOUNT/$MACHINE_ID/$KERNEL_VER/initrd"
135 [ -z "$KERNEL_BIN" ] && [ -e "$EFI_MOUNT/$MACHINE_ID/$KERNEL_VER/linux" ] \
136 && KERNEL_BIN
="$EFI_MOUNT/$MACHINE_ID/$KERNEL_VER/linux"
141 if [[ ! "$KERNEL_BIN" ]]; then
142 if [[ "$LOOKS_LIKE_ARCH" ]]; then
143 KERNEL_BIN
=/boot
/vmlinuz-linux
145 [ "$ARCH" ] || ARCH
=$
(uname
-m)
148 KERNEL_BIN
=/boot
/vmlinux-
$KERNEL_VER
152 KERNEL_BIN
=/boot
/vmlinuz-
$KERNEL_VER
158 default_fedora_initrd
=/boot
/initramfs-
${KERNEL_VER}.img
159 default_debian_initrd
=/boot
/initrd.img-
${KERNEL_VER}
160 default_arch_initrd
=/boot
/initramfs-linux-fallback.img
161 default_suse_initrd
=/boot
/initrd-
${KERNEL_VER}
162 if [[ ! "$INITRD" ]]; then
163 if [[ -e "$default_fedora_initrd" ]]; then
164 INITRD
="$default_fedora_initrd"
165 elif [[ "$LOOKS_LIKE_DEBIAN" && -e "$default_debian_initrd" ]]; then
166 INITRD
="$default_debian_initrd"
167 elif [[ "$LOOKS_LIKE_ARCH" && -e "$default_arch_initrd" ]]; then
168 INITRD
="$default_arch_initrd"
169 elif [[ "$LOOKS_LIKE_SUSE" && -e "$default_suse_initrd" ]]; then
170 INITRD
="$default_suse_initrd"
174 # If QEMU_SMP was not explicitly set, try to determine the value 'dynamically'
175 # i.e. use the number of online CPUs on the host machine. If the nproc utility
176 # is not installed or there's some other error when calling it, fall back
177 # to the original value (QEMU_SMP=1).
178 if ! [ "$QEMU_SMP" ]; then
179 if ! QEMU_SMP
=$
(nproc
); then
180 dwarn
"nproc utility is not installed, falling back to QEMU_SMP=1"
185 find_qemu_bin ||
return 1
188 if [[ "$UNIFIED_CGROUP_HIERARCHY" = "yes" ]]; then
189 _cgroup_args
="systemd.unified_cgroup_hierarchy=yes"
190 elif [[ "$UNIFIED_CGROUP_HIERARCHY" = "no" ]]; then
191 _cgroup_args
="systemd.unified_cgroup_hierarchy=no systemd.legacy_systemd_cgroup_controller=yes"
192 elif [[ "$UNIFIED_CGROUP_HIERARCHY" = "hybrid" ]]; then
193 _cgroup_args
="systemd.unified_cgroup_hierarchy=no systemd.legacy_systemd_cgroup_controller=no"
194 elif [[ "$UNIFIED_CGROUP_HIERARCHY" != "default" ]]; then
195 dfatal
"Unknown UNIFIED_CGROUP_HIERARCHY. Got $UNIFIED_CGROUP_HIERARCHY, expected [yes|no|hybrid|default]"
199 if [[ "$LOOKS_LIKE_SUSE" ]]; then
200 PARAMS
+="rd.hostonly=0"
201 elif [[ "$LOOKS_LIKE_ARCH" ]]; then
207 KERNEL_APPEND
="$PARAMS \
219 QEMU_OPTIONS
="-smp $QEMU_SMP \
223 -kernel $KERNEL_BIN \
224 -drive format=raw,cache=unsafe,file=${TESTDIR}/rootdisk.img \
228 if [[ "$INITRD" && "$SKIP_INITRD" != "yes" ]]; then
229 QEMU_OPTIONS
="$QEMU_OPTIONS -initrd $INITRD"
232 # Let's use KVM if possible
233 if [[ -c /dev
/kvm
&& $QEMU_KVM == "yes" ]]; then
234 QEMU_OPTIONS
="$QEMU_OPTIONS -machine accel=kvm -enable-kvm -cpu host"
237 if [[ "$QEMU_TIMEOUT" != "infinity" ]]; then
238 QEMU_BIN
="timeout --foreground $QEMU_TIMEOUT $QEMU_BIN"
240 (set -x; $QEMU_BIN $QEMU_OPTIONS -append "$KERNEL_APPEND")
242 if [ "$rc" = 124 ] && [ "$QEMU_TIMEOUT" != "infinity" ]; then
243 derror
"test timed out after $QEMU_TIMEOUT s"
246 [ "$rc" != 0 ] && derror
"QEMU failed with exit code $rc"
251 # Return 0 if nspawn did run (then you must check the result state/logs for actual
252 # success), or 1 if nspawn is not available.
254 [[ -d /run
/systemd
/system
]] ||
return 1
256 local _nspawn_cmd
="$SYSTEMD_NSPAWN $NSPAWN_ARGUMENTS --register=no --kill-signal=SIGKILL --directory=$TESTDIR/$1 $PATH_TO_INIT $KERNEL_APPEND"
257 if [[ "$NSPAWN_TIMEOUT" != "infinity" ]]; then
258 _nspawn_cmd
="timeout --foreground $NSPAWN_TIMEOUT $_nspawn_cmd"
261 if [[ "$UNIFIED_CGROUP_HIERARCHY" = "hybrid" ]]; then
262 dwarn
"nspawn doesn't support SYSTEMD_NSPAWN_UNIFIED_HIERARCHY=hybrid, skipping"
264 elif [[ "$UNIFIED_CGROUP_HIERARCHY" = "yes" ||
"$UNIFIED_CGROUP_HIERARCHY" = "no" ]]; then
265 _nspawn_cmd
="env SYSTEMD_NSPAWN_UNIFIED_HIERARCHY=$UNIFIED_CGROUP_HIERARCHY $_nspawn_cmd"
266 elif [[ "$UNIFIED_CGROUP_HIERARCHY" = "default" ]]; then
267 _nspawn_cmd
="env --unset=UNIFIED_CGROUP_HIERARCHY --unset=SYSTEMD_NSPAWN_UNIFIED_HIERARCHY $_nspawn_cmd"
269 dfatal
"Unknown UNIFIED_CGROUP_HIERARCHY. Got $UNIFIED_CGROUP_HIERARCHY, expected [yes|no|hybrid|default]"
273 (set -x; $_nspawn_cmd)
275 if [ "$rc" = 124 ] && [ "$NSPAWN_TIMEOUT" != "infinity" ]; then
276 derror
"test timed out after $NSPAWN_TIMEOUT s"
279 [ "$rc" != 0 ] && derror
"nspawn failed with exit code $rc"
284 setup_basic_environment
() {
285 # create the basic filesystem layout
289 install_missing_libraries
307 generate_module_dependencies
308 if [[ "$IS_BUILT_WITH_ASAN" = "yes" ]]; then
314 # don't forget KERNEL_APPEND='... selinux=1 ...'
315 if [[ "$SETUP_SELINUX" != "yes" ]]; then
316 ddebug
"Don't setup SELinux"
319 ddebug
"Setup SELinux"
320 local _conf_dir
=/etc
/selinux
321 local _fixfiles_tools
="bash uname cat sort uniq awk grep egrep head expr find rm secon setfiles"
323 rm -rf $initdir/$_conf_dir
324 if ! cp -ar $_conf_dir $initdir/$_conf_dir; then
325 dfatal
"Failed to copy $_conf_dir"
329 cat <<EOF >$initdir/etc/systemd/system/autorelabel.service
331 Description=Relabel all filesystems
332 DefaultDependencies=no
333 Requires=local-fs.target
334 Conflicts=shutdown.target
335 After=local-fs.target
336 Before=sysinit.target shutdown.target
337 ConditionSecurity=selinux
338 ConditionPathExists=|/.autorelabel
341 ExecStart=/bin/sh -x -c 'echo 0 >/sys/fs/selinux/enforce && fixfiles -f -F relabel && rm /.autorelabel && systemctl --force reboot'
347 touch $initdir/.autorelabel
348 mkdir
-p $initdir/etc
/systemd
/system
/basic.target.wants
349 ln -fs autorelabel.service
$initdir/etc
/systemd
/system
/basic.target.wants
/autorelabel.service
351 dracut_install
$_fixfiles_tools
352 dracut_install fixfiles
353 dracut_install sestatus
357 if ! type -p valgrind
; then
358 dfatal
"Failed to install valgrind"
362 local _valgrind_bins
=$
(strace
-e execve valgrind
/bin
/true
2>&1 >/dev
/null | perl
-lne 'print $1 if /^execve\("([^"]+)"/')
363 dracut_install
$_valgrind_bins
365 local _valgrind_libs
=$
(LD_DEBUG
=files valgrind
/bin
/true
2>&1 >/dev
/null | perl
-lne 'print $1 if m{calling init: (/.*vgpreload_.*)}')
366 dracut_install
$_valgrind_libs
368 local _valgrind_dbg_and_supp
=$
(
369 strace
-e open valgrind
/bin
/true
2>&1 >/dev
/null |
370 perl
-lne 'if (my ($fname) = /^open\("([^"]+).*= (?!-)\d+/) { print $fname if $fname =~ /debug|\.supp$/ }'
372 dracut_install
$_valgrind_dbg_and_supp
375 create_valgrind_wrapper
() {
376 local _valgrind_wrapper
=$initdir/$ROOTLIBDIR/systemd-under-valgrind
377 ddebug
"Create $_valgrind_wrapper"
378 cat >$_valgrind_wrapper <<EOF
381 mount -t proc proc /proc
382 exec valgrind --leak-check=full --log-file=/valgrind.out $ROOTLIBDIR/systemd "\$@"
384 chmod 0755 $_valgrind_wrapper
387 create_asan_wrapper
() {
388 local _asan_wrapper
=$initdir/$ROOTLIBDIR/systemd-under-asan
389 local _asan_rt_pattern
390 ddebug
"Create $_asan_wrapper"
392 case "$ASAN_COMPILER" in
394 _asan_rt_pattern
="*libasan*"
397 _asan_rt_pattern
="libclang_rt.asan-*"
398 # Install llvm-symbolizer to generate useful reports
399 # See: https://clang.llvm.org/docs/AddressSanitizer.html#symbolizing-the-reports
400 dracut_install
"llvm-symbolizer"
403 dfail
"Unsupported compiler: $ASAN_COMPILER"
407 cat >$_asan_wrapper <<EOF
412 DEFAULT_ASAN_OPTIONS=${ASAN_OPTIONS:-strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1}
413 DEFAULT_UBSAN_OPTIONS=${UBSAN_OPTIONS:-print_stacktrace=1:print_summary=1:halt_on_error=1}
414 DEFAULT_ENVIRONMENT="ASAN_OPTIONS=\$DEFAULT_ASAN_OPTIONS UBSAN_OPTIONS=\$DEFAULT_UBSAN_OPTIONS"
416 # As right now bash is the PID 1, we can't expect PATH to have a sane value.
417 # Let's make one to prevent unexpected "<bin> not found" issues in the future
418 export PATH="/sbin:/bin:/usr/sbin:/usr/bin"
420 mount -t proc proc /proc
421 mount -t sysfs sysfs /sys
422 mount -o remount,rw /
424 PATH_TO_ASAN=\$(find / -name '$_asan_rt_pattern' | sed 1q)
425 if [[ "\$PATH_TO_ASAN" ]]; then
426 # A lot of services (most notably dbus) won't start without preloading libasan
427 # See https://github.com/systemd/systemd/issues/5004
428 DEFAULT_ENVIRONMENT="\$DEFAULT_ENVIRONMENT LD_PRELOAD=\$PATH_TO_ASAN"
429 # Let's add the ASan DSO's path to the dynamic linker's cache. This is pretty
430 # unnecessary for gcc & libasan, however, for clang this is crucial, as its
431 # runtime ASan DSO is in a non-standard (library) path.
432 echo \${PATH_TO_ASAN%/*} > /etc/ld.so.conf.d/asan-path-override.conf
435 echo DefaultEnvironment=\$DEFAULT_ENVIRONMENT >>/etc/systemd/system.conf
436 echo DefaultTimeoutStartSec=180s >>/etc/systemd/system.conf
437 echo DefaultStandardOutput=journal+console >>/etc/systemd/system.conf
439 # ASAN and syscall filters aren't compatible with each other.
440 find / -name '*.service' -type f | xargs sed -i 's/^\\(MemoryDeny\\|SystemCall\\)/#\\1/'
442 # The redirection of ASAN reports to a file prevents them from ending up in /dev/null.
443 # But, apparently, sometimes it doesn't work: https://github.com/google/sanitizers/issues/886.
444 JOURNALD_CONF_DIR=/etc/systemd/system/systemd-journald.service.d
445 mkdir -p "\$JOURNALD_CONF_DIR"
446 printf "[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"
448 # Sometimes UBSan sends its reports to stderr regardless of what is specified in log_path
449 # Let's try to catch them by redirecting stderr (and stdout just in case) to a file
450 # See https://github.com/systemd/systemd/pull/12524#issuecomment-491108821
451 printf "[Service]\nStandardOutput=file:/systemd-journald.out\n" >"\$JOURNALD_CONF_DIR/out.conf"
453 # 90s isn't enough for some services to finish when literally everything is run
454 # under ASan+UBSan in containers, which, in turn, are run in VMs.
455 # Let's limit which environments such services should be executed in.
456 mkdir -p /etc/systemd/system/systemd-hwdb-update.service.d
457 printf "[Unit]\nConditionVirtualization=container\n\n[Service]\nTimeoutSec=180s\n" >/etc/systemd/system/systemd-hwdb-update.service.d/env-override.conf
459 # Let's override another hard-coded timeout that kicks in too early
460 mkdir -p /etc/systemd/system/systemd-journal-flush.service.d
461 printf "[Service]\nTimeoutSec=180s\n" >/etc/systemd/system/systemd-journal-flush.service.d/timeout.conf
463 # The 'mount' utility doesn't behave well under libasan, causing unexpected
464 # fails during boot and subsequent test results check:
465 # bash-5.0# mount -o remount,rw -v /
466 # mount: /dev/sda1 mounted on /.
469 # Let's workaround this by clearing the previously set LD_PRELOAD env variable,
470 # so the libasan library is not loaded for this particular service
472 local _dropin_dir="/etc/systemd/system/\$1.service.d"
473 mkdir -p "\$_dropin_dir"
474 printf "[Service]\nUnsetEnvironment=LD_PRELOAD\n" >"\$_dropin_dir/unset_ld_preload.conf"
477 unset_ld_preload systemd-remount-fs
478 unset_ld_preload testsuite
480 export ASAN_OPTIONS=\$DEFAULT_ASAN_OPTIONS:log_path=/systemd.asan.log UBSAN_OPTIONS=\$DEFAULT_UBSAN_OPTIONS
481 exec $ROOTLIBDIR/systemd "\$@"
484 chmod 0755 $_asan_wrapper
487 create_strace_wrapper
() {
488 local _strace_wrapper
=$initdir/$ROOTLIBDIR/systemd-under-strace
489 ddebug
"Create $_strace_wrapper"
490 cat >$_strace_wrapper <<EOF
493 exec strace -D -o /strace.out $ROOTLIBDIR/systemd "\$@"
495 chmod 0755 $_strace_wrapper
499 dracut_install
/sbin
/fsck
*
500 dracut_install
-o /bin
/fsck
*
502 # fskc.reiserfs calls reiserfsck. so, install it
503 dracut_install
-o reiserfsck
507 instmods dm_crypt
=crypto
509 if [[ "$LOOKS_LIKE_DEBIAN" ]]; then
510 # dmsetup installs 55-dm and 60-persistent-storage-dm on Debian/Ubuntu
511 # and since buster/bionic 95-dm-notify.rules
512 # see https://gitlab.com/debian-lvm/lvm2/blob/master/debian/patches/udev.patch
513 inst_rules
55-dm.rules
60-persistent-storage-dm.rules
95-dm-notify.rules
515 inst_rules
10-dm.rules
13-dm-disk.rules
95-dm-notify.rules
520 # install compiled files
521 local _ninja_bin
=$
(type -P ninja ||
type -P ninja-build
)
522 if [[ -z "$_ninja_bin" ]]; then
523 dfatal
"ninja was not found"
526 (set -x; DESTDIR
=$initdir "$_ninja_bin" -C $BUILD_DIR install)
527 # remove unneeded documentation
528 rm -fr $initdir/usr
/share
/{man
,doc
}
529 # we strip binaries since debug symbols increase binaries size a lot
530 # and it could fill the available space
533 [[ "$LOOKS_LIKE_SUSE" ]] && setup_suse
535 # enable debug logging in PID1
536 echo LogLevel
=debug
>> $initdir/etc
/systemd
/system.conf
537 # store coredumps in journal
538 echo Storage
=journal
>> $initdir/etc
/systemd
/coredump.conf
543 local rpath
=$
(objdump
-p "$_bin" 2>/dev
/null |
awk "/R(UN)?PATH/ { print \"$initdir\" \$2 }" |
paste -sd :)
545 if [ -z "$rpath" ] ; then
552 install_missing_libraries
() {
553 # install possible missing libraries
554 for i
in $initdir{,/usr
}/{sbin
,bin
}/* $initdir{,/usr
}/lib
/systemd
/{,tests
/{,manual
/,unsafe
/}}*; do
555 LD_LIBRARY_PATH
="${LD_LIBRARY_PATH:+$LD_LIBRARY_PATH:}$(get_ldpath $i)" inst_libs
$i
559 create_empty_image
() {
561 if [[ "$STRIP_BINARIES" = "no" ]]; then
564 rm -f "$TESTDIR/rootdisk.img"
565 # Create the blank file to use as a root filesystem
566 truncate
-s "${_size}M" "$TESTDIR/rootdisk.img"
567 LOOPDEV
=$
(losetup
--show -P -f $TESTDIR/rootdisk.img
)
568 [ -b "$LOOPDEV" ] ||
return 1
569 echo "LOOPDEV=$LOOPDEV" >> $STATEFILE
570 sfdisk
"$LOOPDEV" <<EOF
577 local _label
="-L systemd"
578 # mkfs.reiserfs doesn't know -L. so, use --label instead
579 [[ "$FSTYPE" == "reiserfs" ]] && _label
="--label systemd"
580 if ! mkfs
-t "${FSTYPE}" ${_label} "${LOOPDEV}p1" -q; then
581 dfatal
"Failed to mkfs -t ${FSTYPE}"
586 create_empty_image_rootdir
() {
589 mount
${LOOPDEV}p1
$initdir
590 TEST_SETUP_CLEANUP_ROOTDIR
=1
593 check_asan_reports
() {
597 if [[ "$IS_BUILT_WITH_ASAN" = "yes" ]]; then
599 if [[ -e "$root/systemd.asan.log.1" ]]; then
600 cat "$root/systemd.asan.log.1"
604 journald_report
=$
(find "$root" -name "systemd-journald.*san.log*" -exec cat {} \
;)
605 if [[ ! -z "$journald_report" ]]; then
606 printf "%s\n" "$journald_report"
607 cat "$root/systemd-journald.out" ||
:
612 "$JOURNALCTL" -D "$root/var/log/journal" | perl
-alne '
614 %services_to_ignore = (
615 "dbus-daemon" => undef,
618 print $2 if /\s(\S*)\[(\d+)\]:\s*SUMMARY:\s+\w+Sanitizer/ && !exists $services_to_ignore{$1}'
620 if [[ ! -z "$pids" ]]; then
623 "$JOURNALCTL" -D "$root/var/log/journal" _PID
=$pid --no-pager
631 check_result_nspawn
() {
633 local journald_report
=""
635 [[ -e $TESTDIR/$1/testok
]] && ret
=0
636 [[ -f $TESTDIR/$1/failed
]] && cp -a $TESTDIR/$1/failed
$TESTDIR
637 cp -a $TESTDIR/$1/var
/log
/journal
$TESTDIR
638 [[ -f $TESTDIR/failed
]] && cat $TESTDIR/failed
639 ls -l $TESTDIR/journal
/*/*.journal
640 test -s $TESTDIR/failed
&& ret
=$
(($ret+1))
641 [ -n "$TIMED_OUT" ] && ret
=$
(($ret+1))
642 check_asan_reports
"$TESTDIR/$1" || ret
=$
(($ret+1))
646 # can be overridden in specific test
647 check_result_qemu
() {
650 mount
${LOOPDEV}p1
$initdir
651 [[ -e $initdir/testok
]] && ret
=0
652 [[ -f $initdir/failed
]] && cp -a $initdir/failed
$TESTDIR
653 cp -a $initdir/var
/log
/journal
$TESTDIR
654 check_asan_reports
"$initdir" || ret
=$
(($ret+1))
656 [[ -f $TESTDIR/failed
]] && cat $TESTDIR/failed
657 ls -l $TESTDIR/journal
/*/*.journal
658 test -s $TESTDIR/failed
&& ret
=$
(($ret+1))
659 [ -n "$TIMED_OUT" ] && ret
=$
(($ret+1))
664 if [[ "$STRIP_BINARIES" = "no" ]]; then
665 ddebug
"Don't strip binaries"
668 ddebug
"Strip binaries"
669 find "$initdir" -executable -not -path '*/lib/modules/*.ko' -type f | \
670 xargs strip
--strip-unneeded |
& \
671 grep -vi 'file format not recognized' | \
676 mkdir
-p $initdir/etc
/rc.d
677 cat >$initdir/etc
/rc.d
/rc.
local <<EOF
681 chmod 0755 $initdir/etc
/rc.d
/rc.
local
685 ddebug
"install any Execs from the service files"
687 export PKG_CONFIG_PATH
=$BUILD_DIR/src
/core
/
688 systemdsystemunitdir
=$
(pkg-config
--variable=systemdsystemunitdir systemd
)
689 systemduserunitdir
=$
(pkg-config
--variable=systemduserunitdir systemd
)
690 sed -r -n 's|^Exec[a-zA-Z]*=[@+!-]*([^ ]+).*|\1|gp' $initdir/{$systemdsystemunitdir,$systemduserunitdir}/*.service \
691 |
sort -u |
while read i
; do
692 # some {rc,halt}.local scripts and programs are okay to not exist, the rest should
693 # also, plymouth is pulled in by rescue.service, but even there the exit code
694 # is ignored; as it's not present on some distros, don't fail if it doesn't exist
695 dinfo
"Attempting to install $i"
696 inst
$i ||
[ "${i%.local}" != "$i" ] ||
[ "${i%systemd-update-done}" != "$i" ] ||
[ "/bin/plymouth" == "$i" ]
701 generate_module_dependencies
() {
702 if [[ -d $initdir/lib
/modules
/$KERNEL_VER ]] && \
703 ! depmod
-a -b "$initdir" $KERNEL_VER; then
704 dfatal
"\"depmod -a $KERNEL_VER\" failed."
709 install_depmod_files
() {
710 inst
/lib
/modules
/$KERNEL_VER/modules.order
711 inst
/lib
/modules
/$KERNEL_VER/modules.
builtin
715 # install plymouth, if found... else remove plymouth service files
716 # if [ -x /usr/libexec/plymouth/plymouth-populate-initrd ]; then
717 # PLYMOUTH_POPULATE_SOURCE_FUNCTIONS="$TEST_BASE_DIR/test-functions" \
718 # /usr/libexec/plymouth/plymouth-populate-initrd -t $initdir
719 # dracut_install plymouth plymouthd
721 rm -f $initdir/{usr
/lib
,etc
}/systemd
/system
/plymouth
* $initdir/{usr
/lib
,etc
}/systemd
/system
/*/plymouth
*
725 install_ld_so_conf
() {
726 cp -a /etc
/ld.so.conf
* $initdir/etc
727 ldconfig
-r "$initdir"
730 install_config_files
() {
731 inst
/etc
/sysconfig
/init ||
:
737 inst
/etc
/nsswitch.conf
738 inst
/etc
/pam.conf ||
:
741 # we want an empty environment
742 > $initdir/etc
/environment
743 > $initdir/etc
/machine-id
745 echo systemd-testsuite
> $initdir/etc
/hostname
747 if [[ "$LOOKS_LIKE_SUSE" ]]; then
748 ROOTMOUNT
="/dev/sda1 / ${FSTYPE} rw 0 1"
750 ROOTMOUNT
="LABEL=systemd / ${FSTYPE} rw 0 1"
753 cat >$initdir/etc
/fstab
<<EOF
758 install_basic_tools
() {
759 [[ $BASICTOOLS ]] && dracut_install
$BASICTOOLS
760 dracut_install
-o sushell
761 # in Debian ldconfig is just a shell script wrapper around ldconfig.real
762 dracut_install
-o ldconfig.real
765 install_debug_tools
() {
766 [[ $DEBUGTOOLS ]] && dracut_install
$DEBUGTOOLS
768 if [[ $INTERACTIVE_DEBUG ]]; then
769 # Set default TERM from vt220 to linux, so at least basic key shortcuts work
770 local _getty_override
="$initdir/etc/systemd/system/serial-getty@.service.d"
771 mkdir
-p "$_getty_override"
772 echo -e "[Service]\nEnvironment=TERM=linux" > "$_getty_override/default-TERM.conf"
774 cat > "$initdir/etc/motd" << EOF
775 To adjust the terminal size use:
785 # install libnss_files for login
786 NSS_LIBS
=$
(LD_DEBUG
=files getent passwd
2>&1 >/dev
/null |
sed -n '/calling init: .*libnss_/ {s!^.* /!/!; p}')
787 dracut_install
$NSS_LIBS
791 inst
$ROOTLIBDIR/system
/dbus.socket
793 # Newer Fedora versions use dbus-broker by default. Let's install it if it's available.
794 if [ -f $ROOTLIBDIR/system
/dbus-broker.service
]; then
795 inst
$ROOTLIBDIR/system
/dbus-broker.service
796 inst_symlink
/etc
/systemd
/system
/dbus.service
797 inst
/usr
/bin
/dbus-broker
798 inst
/usr
/bin
/dbus-broker-launch
799 elif [ -f $ROOTLIBDIR/system
/dbus-daemon.service
]; then
800 # Fedora rawhide replaced dbus.service with dbus-daemon.service
801 inst
$ROOTLIBDIR/system
/dbus-daemon.service
803 inst_symlink
/etc
/systemd
/system
/dbus.service
805 inst
$ROOTLIBDIR/system
/dbus.service
809 /etc
/dbus-1
/usr
/share
/dbus-1
-xtype f \
810 |
while read file; do
815 install_user_dbus
() {
816 inst
$ROOTLIBDIR/user
/dbus.socket
817 inst_symlink
/usr
/lib
/systemd
/user
/sockets.target.wants
/dbus.socket || inst_symlink
/etc
/systemd
/user
/sockets.target.wants
/dbus.socket
819 # Append the After= dependency on dbus in case it isn't already set up
820 mkdir
-p "$initdir/etc/systemd/system/user@.service.d/"
821 cat <<EOF >"$initdir/etc/systemd/system/user@.service.d/dbus.conf"
826 # Newer Fedora versions use dbus-broker by default. Let's install it if it's available.
827 if [ -f $ROOTLIBDIR/user
/dbus-broker.service
]; then
828 inst
$ROOTLIBDIR/user
/dbus-broker.service
829 inst_symlink
/etc
/systemd
/user
/dbus.service
830 elif [ -f $ROOTLIBDIR/system
/dbus-daemon.service
]; then
831 # Fedora rawhide replaced dbus.service with dbus-daemon.service
832 inst
$ROOTLIBDIR/user
/dbus-daemon.service
834 inst_symlink
/etc
/systemd
/user
/dbus.service
836 inst
$ROOTLIBDIR/user
/dbus.service
842 if [[ "$LOOKS_LIKE_DEBIAN" ]] && type -p dpkg-architecture
&>/dev
/null
; then
843 find "/lib/$(dpkg-architecture -qDEB_HOST_MULTIARCH)/security" -xtype f
845 find /lib
*/security
-xtype f
847 find /etc
/pam.d
/etc
/security
-xtype f
848 ) |
while read file; do
852 # pam_unix depends on unix_chkpwd.
853 # see http://www.linux-pam.org/Linux-PAM-html/sag-pam_unix.html
854 dracut_install
-o unix_chkpwd
856 [[ "$LOOKS_LIKE_DEBIAN" ]] &&
857 cp /etc
/pam.d
/systemd-user
$initdir/etc
/pam.d
/
859 # set empty root password for easy debugging
860 sed -i 's/^root:x:/root::/' $initdir/etc
/passwd
864 # The first three paths may be deprecated.
865 # It seems now the last two paths are used by many distributions.
867 /usr
/lib
/kbd
/keymaps
/include
/* \
868 /usr
/lib
/kbd
/keymaps
/i386
/include
/* \
869 /usr
/lib
/kbd
/keymaps
/i386
/qwerty
/us.
* \
870 /usr
/lib
/kbd
/keymaps
/legacy
/include
/* \
871 /usr
/lib
/kbd
/keymaps
/legacy
/i386
/qwerty
/us.
*; do
872 [[ -f $i ]] ||
continue
876 # When it takes any argument, then install more keymaps.
879 /usr
/lib
/kbd
/keymaps
/i386
/*/* \
880 /usr
/lib
/kbd
/keymaps
/legacy
/i386
/*/*; do
881 [[ -f $i ]] ||
continue
888 for i
in /usr
/share
/zoneinfo
/{,*/,*/*/}*; do
889 [[ -f $i ]] ||
continue
896 /usr
/lib
/kbd
/consolefonts
/eurlatgr
* \
897 /usr
/lib
/kbd
/consolefonts
/latarcyrheb-sun16
*; do
898 [[ -f $i ]] ||
continue
904 for _terminfodir
in /lib
/terminfo
/etc
/terminfo
/usr
/share
/terminfo
; do
905 [ -f ${_terminfodir}/l
/linux
] && break
907 dracut_install
-o ${_terminfodir}/l
/linux
910 has_user_dbus_socket
() {
911 if [ -f /usr
/lib
/systemd
/user
/dbus.socket
] ||
[ -f /etc
/systemd
/user
/dbus.socket
]; then
914 echo "Per-user instances are not supported. Skipping..."
919 enable_user_manager
() {
920 has_user_dbus_socket ||
return 0
923 [[ $# -gt 0 ]] ||
set -- nobody
924 mkdir
-p "$initdir/var/lib/systemd/linger"
926 touch "$initdir/var/lib/systemd/linger/$_userid"
933 cp $TEST_BASE_DIR/testsuite.target
$initdir/etc
/systemd
/system
/
934 cp $TEST_BASE_DIR/end.service
$initdir/etc
/systemd
/system
/
936 mkdir
-p $initdir/etc
/systemd
/system
/testsuite.target.wants
937 ln -fs $TEST_BASE_DIR/testsuite.service
$initdir/etc
/systemd
/system
/testsuite.target.wants
/testsuite.service
938 # Don't shutdown the machine after running the test when INTERACTIVE_DEBUG is set
939 [[ -z $INTERACTIVE_DEBUG ]] && ln -fs $TEST_BASE_DIR/end.service
$initdir/etc
/systemd
/system
/testsuite.target.wants
/end.service
941 # make the testsuite the default target
942 ln -fs testsuite.target
$initdir/etc
/systemd
/system
/default.target
945 setup_nspawn_root
() {
946 rm -fr $TESTDIR/nspawn-root
947 ddebug
"cp -ar $initdir $TESTDIR/nspawn-root"
948 cp -ar $initdir $TESTDIR/nspawn-root
949 # we don't mount in the nspawn root
950 rm -f $TESTDIR/nspawn-root
/etc
/fstab
951 if [[ "$RUN_IN_UNPRIVILEGED_CONTAINER" = "yes" ]]; then
952 cp -ar $TESTDIR/nspawn-root
$TESTDIR/unprivileged-nspawn-root
957 mkdir
-p $initdir/run
958 mkdir
-p $initdir/etc
/systemd
/system
959 mkdir
-p $initdir/var
/log
/journal
961 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
962 if [ -L "/$d" ]; then
969 ln -sfn /run
"$initdir/var/run"
970 ln -sfn /run
/lock
"$initdir/var/lock"
973 mask_supporting_services
() {
974 # mask some services that we do not want to run in these tests
975 ln -fs /dev
/null
$initdir/etc
/systemd
/system
/systemd-hwdb-update.service
976 ln -fs /dev
/null
$initdir/etc
/systemd
/system
/systemd-journal-catalog-update.service
977 ln -fs /dev
/null
$initdir/etc
/systemd
/system
/systemd-networkd.service
978 ln -fs /dev
/null
$initdir/etc
/systemd
/system
/systemd-networkd.socket
979 ln -fs /dev
/null
$initdir/etc
/systemd
/system
/systemd-resolved.service
984 local _so_regex
='([^ ]*/lib[^/]*/[^ ]*\.so[^ ]*)'
987 LC_ALL
=C ldd
"$_bin" 2>/dev
/null |
while read _line
; do
988 [[ $_line = 'not a dynamic executable' ]] && break
990 if [[ $_line =~
$_so_regex ]]; then
991 _file
=${BASH_REMATCH[1]}
992 [[ -e ${initdir}/$_file ]] && continue
993 inst_library
"$_file"
997 if [[ $_line =~ not\ found
]]; then
998 dfatal
"Missing a shared library required by $_bin."
999 dfatal
"Run \"ldd $_bin\" to find out what it is."
1001 dfatal
"dracut cannot create an initrd."
1008 [[ -e $STATEFILE ]] && .
$STATEFILE
1009 if [[ ! -d "$TESTDIR" ]]; then
1010 if [[ -z "$TESTDIR" ]]; then
1011 TESTDIR
=$
(mktemp
--tmpdir=/var
/tmp
-d -t systemd-test.XXXXXX
)
1016 echo "TESTDIR=\"$TESTDIR\"" > $STATEFILE
1022 initdir
=$TESTDIR/root
1027 ## @brief Converts numeric logging level to the first letter of level name.
1029 # @param lvl Numeric logging level in range from 1 to 6.
1030 # @retval 1 if @a lvl is out of range.
1031 # @retval 0 if @a lvl is correct.
1032 # @result Echoes first letter of level name.
1045 ## @brief Internal helper function for _do_dlog()
1047 # @param lvl Numeric logging level.
1048 # @param msg Message.
1049 # @retval 0 It's always returned, even if logging failed.
1051 # @note This function is not supposed to be called manually. Please use
1052 # dtrace(), ddebug(), or others instead which wrap this one.
1054 # This function calls _do_dlog() either with parameter msg, or if
1055 # none is given, it will read standard input and will use every line as
1059 # dwarn "This is a warning"
1060 # echo "This is a warning" | dwarn
1061 LOG_LEVEL
=${LOG_LEVEL:-4}
1064 [ -z "$LOG_LEVEL" ] && return 0
1065 [ $1 -le $LOG_LEVEL ] ||
return 0
1066 local lvl
="$1"; shift
1067 local lvlc
=$
(_lvl2char
"$lvl") ||
return 0
1069 if [ $# -ge 1 ]; then
1073 echo "$lvlc: " "$line"
1078 ## @brief Logs message at TRACE level (6)
1080 # @param msg Message.
1081 # @retval 0 It's always returned, even if logging failed.
1085 [ -n "$debug" ] && set -x ||
:
1088 ## @brief Logs message at DEBUG level (5)
1090 # @param msg Message.
1091 # @retval 0 It's always returned, even if logging failed.
1095 # [ -n "$debug" ] && set -x || :
1098 ## @brief Logs message at INFO level (4)
1100 # @param msg Message.
1101 # @retval 0 It's always returned, even if logging failed.
1105 [ -n "$debug" ] && set -x ||
:
1108 ## @brief Logs message at WARN level (3)
1110 # @param msg Message.
1111 # @retval 0 It's always returned, even if logging failed.
1115 [ -n "$debug" ] && set -x ||
:
1118 ## @brief Logs message at ERROR level (2)
1120 # @param msg Message.
1121 # @retval 0 It's always returned, even if logging failed.
1125 # [ -n "$debug" ] && set -x || :
1128 ## @brief Logs message at FATAL level (1)
1130 # @param msg Message.
1131 # @retval 0 It's always returned, even if logging failed.
1135 [ -n "$debug" ] && set -x ||
:
1139 # Generic substring function. If $2 is in $1, return 0.
1140 strstr
() { [ "${1#*$2*}" != "$1" ]; }
1142 # normalize_path <path>
1143 # Prints the normalized path, where it removes any duplicated
1144 # and trailing slashes.
1146 # $ normalize_path ///test/test//
1150 set -- "${1//+(\/)//}"
1155 # convert_abs_rel <from> <to>
1156 # Prints the relative path, when creating a symlink to <to> from <from>.
1158 # $ convert_abs_rel /usr/bin/test /bin/test-2
1160 # $ ln -s $(convert_abs_rel /usr/bin/test /bin/test-2) /usr/bin/test
1162 local __current __absolute __abssize __cursize __newpath
1163 local -i __i __level
1165 set -- "$(normalize_path "$1")" "$(normalize_path "$2")"
1167 # corner case #1 - self looping link
1168 [[ "$1" == "$2" ]] && { echo "${1##*/}"; return; }
1170 # corner case #2 - own dir link
1171 [[ "${1%/*}" == "$2" ]] && { echo "."; return; }
1173 IFS
="/" __current
=($1)
1174 IFS
="/" __absolute
=($2)
1176 __abssize
=${#__absolute[@]}
1177 __cursize
=${#__current[@]}
1179 while [[ ${__absolute[__level]} == ${__current[__level]} ]]
1182 if (( __level
> __abssize || __level
> __cursize
))
1188 for ((__i
= __level
; __i
< __cursize-1
; __i
++))
1190 if ((__i
> __level
))
1192 __newpath
=$__newpath"/"
1194 __newpath
=$__newpath".."
1197 for ((__i
= __level
; __i
< __abssize
; __i
++))
1199 if [[ -n $__newpath ]]
1201 __newpath
=$__newpath"/"
1203 __newpath
=$__newpath${__absolute[__i]}
1210 # Install a directory, keeping symlinks as on the original system.
1211 # Example: if /lib points to /lib64 on the host, "inst_dir /lib/file"
1212 # will create ${initdir}/lib64, ${initdir}/lib64/file,
1213 # and a symlink ${initdir}/lib -> lib64.
1215 [[ -e ${initdir}/"$1" ]] && return 0 # already there
1217 local _dir
="$1" _part
="${1%/*}" _file
1218 while [[ "$_part" != "${_part%/*}" ]] && ! [[ -e "${initdir}/${_part}" ]]; do
1223 # iterate over parent directories
1224 for _file
in $_dir; do
1225 [[ -e "${initdir}/$_file" ]] && continue
1226 if [[ -L $_file ]]; then
1227 inst_symlink
"$_file"
1230 mkdir
-m 0755 -p "${initdir}/$_file" ||
return 1
1231 [[ -e "$_file" ]] && chmod --reference="$_file" "${initdir}/$_file"
1232 chmod u
+w
"${initdir}/$_file"
1237 # $1 = file to copy to ramdisk
1238 # $2 (optional) Name for the file on the ramdisk
1239 # Location of the image dir is assumed to be $initdir
1240 # We never overwrite the target if it exists.
1242 [[ -f "$1" ]] ||
return 1
1243 strstr
"$1" "/" ||
return 1
1245 local _src
=$1 target
="${2:-$1}"
1246 if ! [[ -d ${initdir}/$target ]]; then
1247 [[ -e ${initdir}/$target ]] && return 0
1248 [[ -L ${initdir}/$target ]] && return 0
1249 [[ -d "${initdir}/${target%/*}" ]] || inst_dir "${target%/*}"
1251 # install checksum files also
1252 if [[ -e "${_src%/*}/.${_src##*/}.hmac" ]]; then
1253 inst
"${_src%/*}/.${_src##*/}.hmac" "${target%/*}/.${target##*/}.hmac"
1255 ddebug
"Installing $_src"
1256 cp --sparse=always
-pfL "$_src" "${initdir}/$target"
1259 # find symlinks linked to given library file
1261 # Function searches for symlinks by stripping version numbers appended to
1262 # library filename, checks if it points to the same target and finally
1263 # prints the list of symlinks to stdout.
1266 # rev_lib_symlinks libfoo.so.8.1
1267 # output: libfoo.so.8 libfoo.so
1268 # (Only if libfoo.so.8 and libfoo.so exists on host system.)
1269 rev_lib_symlinks
() {
1270 [[ ! $1 ]] && return 0
1272 local fn
="$1" orig
="$(readlink -f "$1")" links
=''
1274 [[ ${fn} =~ .
*\.so\..
* ]] ||
return 1
1276 until [[ ${fn##*.} == so
]]; do
1278 [[ -L ${fn} && $(readlink -f "${fn}") == ${orig} ]] && links+=" ${fn}"
1284 # Same as above, but specialized to handle dynamic libraries.
1285 # It handles making symlinks according to how the original library
1288 local _src="$1" _dest=${2:-$1} _lib _reallib _symlink
1289 strstr "$1" "/" || return 1
1290 [[ -e $initdir/$_dest ]] && return 0
1291 if [[ -L $_src ]]; then
1292 # install checksum files also
1293 if [[ -e "${_src%/*}/.
${_src##*/}.hmac
" ]]; then
1294 inst "${_src%/*}/.${_src##*/}.hmac" "${_dest%/*}/.${_dest##*/}.hmac
"
1296 _reallib=$(readlink -f "$_src")
1297 inst_simple "$_reallib" "$_reallib"
1298 inst_dir "${_dest%/*}"
1299 [[ -d "${_dest%/*}" ]] && _dest=$(readlink -f "${_dest%/*}")/${_dest##*/}
1300 ln -sfn $
(convert_abs_rel
"${_dest}" "${_reallib}") "${initdir}/${_dest}"
1302 inst_simple
"$_src" "$_dest"
1305 # Create additional symlinks. See rev_symlinks description.
1306 for _symlink
in $
(rev_lib_symlinks
$_src) $
(rev_lib_symlinks
$_reallib); do
1307 [[ -e $initdir/$_symlink ]] ||
{
1308 ddebug
"Creating extra symlink: $_symlink"
1309 inst_symlink
$_symlink
1314 # find a binary. If we were not passed the full path directly,
1315 # search in the usual places to find the binary.
1317 if [[ -z ${1##/*} ]]; then
1318 if [[ -x $1 ]] ||
{ strstr
"$1" ".so" && ldd
$1 &>/dev
/null
; }; then
1327 # Same as above, but specialized to install binary executables.
1328 # Install binary executable, and all shared library dependencies, if any.
1332 # In certain cases we might attempt to install a binary which is already
1333 # present in the test image, yet it's missing from the host system.
1334 # In such cases, let's check if the binary indeed exists in the image
1335 # before doing any other chcecks. If it does, immediately return with
1337 [[ $# -eq 1 && -e $initdir/$1 ]] && return 0
1339 _bin
=$
(find_binary
"$1") ||
return 1
1341 [[ -e $initdir/$_target ]] && return 0
1342 [[ -L $_bin ]] && inst_symlink
$_bin $_target && return 0
1344 local _so_regex
='([^ ]*/lib[^/]*/[^ ]*\.so[^ ]*)'
1346 LC_ALL
=C ldd
"$_bin" 2>/dev
/null |
while read _line
; do
1347 [[ $_line = 'not a dynamic executable' ]] && break
1349 if [[ $_line =~
$_so_regex ]]; then
1350 _file
=${BASH_REMATCH[1]}
1351 [[ -e ${initdir}/$_file ]] && continue
1352 inst_library
"$_file"
1356 if [[ $_line =~ not\ found
]]; then
1357 dfatal
"Missing a shared library required by $_bin."
1358 dfatal
"Run \"ldd $_bin\" to find out what it is."
1360 dfatal
"dracut cannot create an initrd."
1364 inst_simple
"$_bin" "$_target"
1367 # same as above, except for shell scripts.
1368 # If your shell script does not start with shebang, it is not a shell script.
1371 _bin
=$
(find_binary
"$1") ||
return 1
1373 local _line _shebang_regex
1374 read -r -n 80 _line
<"$_bin"
1375 # If debug is set, clean unprintable chars to prevent messing up the term
1376 [[ $debug ]] && _line
=$
(echo -n "$_line" |
tr -c -d '[:print:][:space:]')
1377 _shebang_regex
='(#! *)(/[^ ]+).*'
1378 [[ $_line =~
$_shebang_regex ]] ||
return 1
1379 inst
"${BASH_REMATCH[2]}" && inst_simple
"$_bin" "$@"
1382 # same as above, but specialized for symlinks
1384 local _src
=$1 _target
=${2:-$1} _realsrc
1385 strstr
"$1" "/" ||
return 1
1386 [[ -L $1 ]] ||
return 1
1387 [[ -L $initdir/$_target ]] && return 0
1388 _realsrc
=$
(readlink
-f "$_src")
1389 if ! [[ -e $initdir/$_realsrc ]]; then
1390 if [[ -d $_realsrc ]]; then
1391 inst_dir
"$_realsrc"
1396 [[ ! -e $initdir/${_target%/*} ]] && inst_dir
"${_target%/*}"
1397 [[ -d ${_target%/*} ]] && _target=$(readlink -f ${_target%/*})/${_target##*/}
1398 ln -sfn $
(convert_abs_rel
"${_target}" "${_realsrc}") "$initdir/$_target"
1401 # attempt to install any programs specified in a udev rule
1402 inst_rule_programs
() {
1405 if grep -qE 'PROGRAM==?"[^ "]+' "$1"; then
1406 for _prog
in $
(grep -E 'PROGRAM==?"[^ "]+' "$1" |
sed -r 's/.*PROGRAM==?"([^ "]+).*/\1/'); do
1407 if [ -x /lib
/udev
/$_prog ]; then
1408 _bin
=/lib
/udev
/$_prog
1410 _bin
=$
(find_binary
"$_prog") ||
{
1411 dinfo
"Skipping program $_prog using in udev rule $(basename $1) as it cannot be found"
1416 #dinfo "Installing $_bin due to it's use in the udev rule $(basename $1)"
1417 dracut_install
"$_bin"
1422 # udev rules always get installed in the same place, so
1423 # create a function to install them to make life simpler.
1425 local _target
=/etc
/udev
/rules.d _rule _found
1427 inst_dir
"/lib/udev/rules.d"
1429 for _rule
in "$@"; do
1430 if [ "${rule#/}" = "$rule" ]; then
1431 for r
in /lib
/udev
/rules.d
/etc
/udev
/rules.d
; do
1432 if [[ -f $r/$_rule ]]; then
1434 inst_simple
"$_found"
1435 inst_rule_programs
"$_found"
1439 for r
in '' .
/ $dracutbasedir/rules.d
/; do
1440 if [[ -f ${r}$_rule ]]; then
1442 inst_simple
"$_found" "$_target/${_found##*/}"
1443 inst_rule_programs
"$_found"
1446 [[ $_found ]] || dinfo
"Skipping udev rule: $_rule"
1451 # general purpose installation function
1452 # Same args as above.
1458 2) [[ ! $initdir && -d $2 ]] && export initdir
=$2
1459 [[ $initdir = $2 ]] && set $1;;
1460 3) [[ -z $initdir ]] && export initdir
=$2
1462 *) dfatal
"inst only takes 1 or 2 or 3 arguments"
1465 for _x
in inst_symlink inst_script inst_binary inst_simple
; do
1466 $_x "$@" && return 0
1471 # install any of listed files
1473 # If first argument is '-d' and second some destination path, first accessible
1474 # source is installed into this path, otherwise it will installed in the same
1475 # path as source. If none of listed files was installed, function return 1.
1476 # On first successful installation it returns with 0 status.
1480 # inst_any -d /bin/foo /bin/bar /bin/baz
1482 # Lets assume that /bin/baz exists, so it will be installed as /bin/foo in
1487 [[ $1 = '-d' ]] && to
="$2" && shift 2
1490 if [[ -e $f ]]; then
1491 [[ $to ]] && inst
"$f" "$to" && return 0
1492 inst
"$f" && return 0
1499 # dracut_install [-o ] <file> [<file> ... ]
1500 # Install <file> to the initramfs image
1501 # -o optionally install the <file> and don't fail, if it is not there
1504 if [[ $1 = '-o' ]]; then
1508 while (($# > 0)); do
1509 if ! inst
"$1" ; then
1510 if [[ $_optional = yes ]]; then
1511 dinfo
"Skipping program $1 as it cannot be found and is" \
1512 "flagged to be optional"
1514 dfatal
"Failed to install $1"
1522 # Install a single kernel module along with any firmware it may require.
1523 # $1 = full path to kernel module to install
1524 install_kmod_with_fw
() {
1525 # no need to go further if the module is already installed
1527 [[ -e "${initdir}/lib/modules/$KERNEL_VER/${1##*/lib/modules/$KERNEL_VER/}" ]] \
1530 [[ -e "$initdir/.kernelmodseen/${1##*/}" ]] && return 0
1532 if [[ $omit_drivers ]]; then
1533 local _kmod
=${1##*/}
1536 if [[ "$_kmod" =~
$omit_drivers ]]; then
1537 dinfo
"Omitting driver $_kmod"
1540 if [[ "${1##*/lib/modules/$KERNEL_VER/}" =~
$omit_drivers ]]; then
1541 dinfo
"Omitting driver $_kmod"
1546 [ -d "$initdir/.kernelmodseen" ] && \
1547 > "$initdir/.kernelmodseen/${1##*/}"
1549 inst_simple
"$1" "/lib/modules/$KERNEL_VER/${1##*/lib/modules/$KERNEL_VER/}" \
1552 local _modname
=${1##*/} _fwdir _found _fw
1553 _modname
=${_modname%.ko*}
1554 for _fw
in $
(modinfo
-k $KERNEL_VER -F firmware
$1 2>/dev
/null
); do
1556 for _fwdir
in $fw_dir; do
1557 if [[ -d $_fwdir && -f $_fwdir/$_fw ]]; then
1558 inst_simple
"$_fwdir/$_fw" "/lib/firmware/$_fw"
1562 if [[ $_found != yes ]]; then
1563 if ! grep -qe "\<${_modname//-/_}\>" /proc
/modules
; then
1564 dinfo
"Possible missing firmware \"${_fw}\" for kernel module" \
1565 "\"${_modname}.ko\""
1567 dwarn
"Possible missing firmware \"${_fw}\" for kernel module" \
1568 "\"${_modname}.ko\""
1575 # Do something with all the dependencies of a kernel module.
1576 # Note that kernel modules depend on themselves using the technique we use
1577 # $1 = function to call for each dependency we find
1578 # It will be passed the full path to the found kernel module
1579 # $2 = module to get dependencies for
1580 # rest of args = arguments to modprobe
1581 # _fderr specifies FD passed from surrounding scope
1582 for_each_kmod_dep
() {
1583 local _func
=$1 _kmod
=$2 _cmd _modpath _options _found
=0
1585 modprobe
"$@" --ignore-install --show-depends $_kmod 2>&${_fderr} |
(
1586 while read _cmd _modpath _options
; do
1587 [[ $_cmd = insmod
]] ||
continue
1588 $_func ${_modpath} ||
exit $?
1591 [[ $_found -eq 0 ]] && exit 1
1596 # filter kernel modules to install certain modules that meet specific
1598 # $1 = search only in subdirectory of /kernel/$1
1599 # $2 = function to call with module name to filter.
1600 # This function will be passed the full path to the module to test.
1601 # The behavior of this function can vary depending on whether $hostonly is set.
1602 # If it is, we will only look at modules that are already in memory.
1603 # If it is not, we will look at all kernel modules
1604 # This function returns the full filenames of modules that match $1
1605 filter_kernel_modules_by_path
() (
1606 local _modname _filtercmd
1607 if ! [[ $hostonly ]]; then
1608 _filtercmd
='find "$KERNEL_MODS/kernel/$1" "$KERNEL_MODS/extra"'
1609 _filtercmd
+=' "$KERNEL_MODS/weak-updates" -name "*.ko" -o -name "*.ko.gz"'
1610 _filtercmd
+=' -o -name "*.ko.xz"'
1611 _filtercmd
+=' 2>/dev/null'
1613 _filtercmd
='cut -d " " -f 1 </proc/modules|xargs modinfo -F filename '
1614 _filtercmd
+='-k $KERNEL_VER 2>/dev/null'
1616 for _modname
in $
(eval $_filtercmd); do
1618 *.ko
) "$2" "$_modname" && echo "$_modname";;
1619 *.ko.gz
) gzip -dc "$_modname" > $initdir/$$.ko
1620 $2 $initdir/$$.ko
&& echo "$_modname"
1621 rm -f $initdir/$$.ko
1623 *.ko.xz
) xz
-dc "$_modname" > $initdir/$$.ko
1624 $2 $initdir/$$.ko
&& echo "$_modname"
1625 rm -f $initdir/$$.ko
1630 find_kernel_modules_by_path
() (
1631 if ! [[ $hostonly ]]; then
1632 find "$KERNEL_MODS/kernel/$1" "$KERNEL_MODS/extra" "$KERNEL_MODS/weak-updates" \
1633 -name "*.ko" -o -name "*.ko.gz" -o -name "*.ko.xz" 2>/dev
/null
1635 cut
-d " " -f 1 </proc
/modules \
1636 |
xargs modinfo
-F filename
-k $KERNEL_VER 2>/dev
/null
1640 filter_kernel_modules
() {
1641 filter_kernel_modules_by_path drivers
"$1"
1644 find_kernel_modules
() {
1645 find_kernel_modules_by_path drivers
1648 # instmods [-c] <kernel module> [<kernel module> ... ]
1649 # instmods [-c] <kernel subsystem>
1650 # install kernel modules along with all their dependencies.
1651 # <kernel subsystem> can be e.g. "=block" or "=drivers/usb/storage"
1653 [[ $no_kernel = yes ]] && return
1654 # called [sub]functions inherit _fderr
1657 if [[ $1 = '-c' ]]; then
1662 function inst1mod
() {
1663 local _ret
=0 _mod
="$1"
1666 if [ -f $KERNEL_MODS/modules.
${_mod#=} ]; then
1667 ( [[ "$_mpargs" ]] && echo $_mpargs
1668 cat "${KERNEL_MODS}/modules.${_mod#=}" ) \
1671 ( [[ "$_mpargs" ]] && echo $_mpargs
1672 find "$KERNEL_MODS" -path "*/${_mod#=}/*" -type f
-printf '%f\n' ) \
1676 --*) _mpargs
+=" $_mod" ;;
1677 i2o_scsi
) return ;; # Do not load this diagnostic-only module
1680 # if we are already installed, skip this module and go on
1682 [[ -f "$initdir/.kernelmodseen/${_mod%.ko}.ko" ]] && return
1684 if [[ $omit_drivers ]] && [[ "$1" =~
$omit_drivers ]]; then
1685 dinfo
"Omitting driver ${_mod##$KERNEL_MODS}"
1688 # If we are building a host-specific initramfs and this
1689 # module is not already loaded, move on to the next one.
1690 [[ $hostonly ]] && ! grep -qe "\<${_mod//-/_}\>" /proc
/modules \
1691 && ! echo $add_drivers |
grep -qe "\<${_mod}\>" \
1694 # We use '-d' option in modprobe only if modules prefix path
1695 # differs from default '/'. This allows us to use Dracut with
1696 # old version of modprobe which doesn't have '-d' option.
1697 local _moddirname
=${KERNEL_MODS%%/lib/modules/*}
1698 [[ -n ${_moddirname} ]] && _moddirname
="-d ${_moddirname}/"
1700 # ok, load the module, all its dependencies, and any firmware
1702 for_each_kmod_dep install_kmod_with_fw
$_mod \
1703 --set-version $KERNEL_VER ${_moddirname} $_mpargs
1710 function instmods_1
() {
1712 if (($# == 0)); then # filenames from stdin
1714 inst1mod
"${_mod%.ko*}" ||
{
1715 if [ "$_check" = "yes" ]; then
1716 dfatal
"Failed to install $_mod"
1722 while (($# > 0)); do # filenames as arguments
1723 inst1mod
${1%.ko*} ||
{
1724 if [ "$_check" = "yes" ]; then
1725 dfatal
"Failed to install $1"
1734 local _ret _filter_not_found
='FATAL: Module .* not found.'
1736 # Capture all stderr from modprobe to _fderr. We could use {var}>...
1737 # redirections, but that would make dracut require bash4 at least.
1738 eval "( instmods_1 \"\$@\" ) ${_fderr}>&1" \
1739 |
while read line
; do [[ "$line" =~
$_filter_not_found ]] && echo $line ||
echo $line >&2 ;done | derror
1746 ln -fs ..
/usr
/bin
/systemctl
$initdir/bin
/
1747 ln -fs ..
/usr
/lib
/systemd
$initdir/lib
/
1748 inst_simple
"/usr/lib/systemd/system/haveged.service"
1752 if mountpoint
-q $1; then
1758 _test_setup_cleanup
() {
1759 # only umount if create_empty_image_rootdir() was called to mount it
1760 [[ -z $TEST_SETUP_CLEANUP_ROOTDIR ]] || _umount_dir
$initdir
1763 # can be overridden in specific test
1764 test_setup_cleanup
() {
1769 # (post-test) cleanup should always ignore failure and cleanup as much as possible
1772 _umount_dir
$initdir
1773 if [[ $LOOPDEV && -b $LOOPDEV ]]; then
1774 ddebug
"losetup -d $LOOPDEV"
1782 # can be overridden in specific test
1788 if [ -z "$TEST_NO_QEMU" ]; then
1790 check_result_qemu ||
return 1
1792 dwarn
"can't run QEMU, skipping"
1795 if [ -z "$TEST_NO_NSPAWN" ]; then
1796 if run_nspawn
"nspawn-root"; then
1797 check_result_nspawn
"nspawn-root" ||
return 1
1799 dwarn
"can't run systemd-nspawn, skipping"
1802 if [[ "$RUN_IN_UNPRIVILEGED_CONTAINER" = "yes" ]]; then
1803 if NSPAWN_ARGUMENTS
="-U --private-network $NSPAWN_ARGUMENTS" run_nspawn
"unprivileged-nspawn-root"; then
1804 check_result_nspawn
"unprivileged-nspawn-root" ||
return 1
1806 dwarn
"can't run systemd-nspawn, skipping"
1814 if [[ $UID != "0" ]]; then
1815 echo "TEST: $TEST_DESCRIPTION [SKIPPED]: not root" >&2
1820 [[ $libdir ]] ||
for libdir
in /lib64
/lib
; do
1821 [[ -d $libdir ]] && libdirs
+=" $libdir" && break
1824 [[ $usrlibdir ]] ||
for usrlibdir
in /usr
/lib64
/usr
/lib
; do
1825 [[ -d $usrlibdir ]] && libdirs
+=" $usrlibdir" && break
1828 mkdir
-p "$STATEDIR"
1833 while (($# > 0)); do
1836 echo "TEST RUN: $TEST_DESCRIPTION"
1839 if (( $ret == 0 )); then
1840 echo "TEST RUN: $TEST_DESCRIPTION [OK]"
1842 echo "TEST RUN: $TEST_DESCRIPTION [FAILED]"
1846 echo "TEST SETUP: $TEST_DESCRIPTION"
1851 echo "TEST CLEANUP: $TEST_DESCRIPTION"
1856 echo -n "TEST: $TEST_DESCRIPTION "
1861 ) </dev
/null
>"$TESTLOG" 2>&1 || ret
=$?
1863 if [ $ret -eq 0 ]; then