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 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 \
220 QEMU_OPTIONS
="-smp $QEMU_SMP \
224 -kernel $KERNEL_BIN \
225 -drive format=raw,cache=unsafe,file=${TESTDIR}/rootdisk.img \
229 if [[ "$INITRD" && "$SKIP_INITRD" != "yes" ]]; then
230 QEMU_OPTIONS
="$QEMU_OPTIONS -initrd $INITRD"
233 # Let's use KVM if possible
234 if [[ -c /dev
/kvm
&& $QEMU_KVM == "yes" ]]; then
235 QEMU_OPTIONS
="$QEMU_OPTIONS -machine accel=kvm -enable-kvm -cpu host"
238 if [[ "$QEMU_TIMEOUT" != "infinity" ]]; then
239 QEMU_BIN
="timeout --foreground $QEMU_TIMEOUT $QEMU_BIN"
241 (set -x; $QEMU_BIN $QEMU_OPTIONS -append "$KERNEL_APPEND")
243 if [ "$rc" = 124 ] && [ "$QEMU_TIMEOUT" != "infinity" ]; then
244 derror
"test timed out after $QEMU_TIMEOUT s"
247 [ "$rc" != 0 ] && derror
"QEMU failed with exit code $rc"
252 # Return 0 if nspawn did run (then you must check the result state/logs for actual
253 # success), or 1 if nspawn is not available.
255 [[ -d /run
/systemd
/system
]] ||
return 1
257 local _nspawn_cmd
="$SYSTEMD_NSPAWN $NSPAWN_ARGUMENTS --register=no --kill-signal=SIGKILL --directory=$TESTDIR/$1 $PATH_TO_INIT $KERNEL_APPEND"
258 if [[ "$NSPAWN_TIMEOUT" != "infinity" ]]; then
259 _nspawn_cmd
="timeout --foreground $NSPAWN_TIMEOUT $_nspawn_cmd"
262 if [[ "$UNIFIED_CGROUP_HIERARCHY" = "hybrid" ]]; then
263 dwarn
"nspawn doesn't support SYSTEMD_NSPAWN_UNIFIED_HIERARCHY=hybrid, skipping"
265 elif [[ "$UNIFIED_CGROUP_HIERARCHY" = "yes" ||
"$UNIFIED_CGROUP_HIERARCHY" = "no" ]]; then
266 _nspawn_cmd
="env SYSTEMD_NSPAWN_UNIFIED_HIERARCHY=$UNIFIED_CGROUP_HIERARCHY $_nspawn_cmd"
267 elif [[ "$UNIFIED_CGROUP_HIERARCHY" = "default" ]]; then
268 _nspawn_cmd
="env --unset=UNIFIED_CGROUP_HIERARCHY --unset=SYSTEMD_NSPAWN_UNIFIED_HIERARCHY $_nspawn_cmd"
270 dfatal
"Unknown UNIFIED_CGROUP_HIERARCHY. Got $UNIFIED_CGROUP_HIERARCHY, expected [yes|no|hybrid|default]"
274 (set -x; $_nspawn_cmd)
276 if [ "$rc" = 124 ] && [ "$NSPAWN_TIMEOUT" != "infinity" ]; then
277 derror
"test timed out after $NSPAWN_TIMEOUT s"
280 [ "$rc" != 0 ] && derror
"nspawn failed with exit code $rc"
285 setup_basic_environment
() {
286 # create the basic filesystem layout
290 install_missing_libraries
308 generate_module_dependencies
309 if [[ "$IS_BUILT_WITH_ASAN" = "yes" ]]; then
315 # don't forget KERNEL_APPEND='... selinux=1 ...'
316 if [[ "$SETUP_SELINUX" != "yes" ]]; then
317 ddebug
"Don't setup SELinux"
320 ddebug
"Setup SELinux"
321 local _conf_dir
=/etc
/selinux
322 local _fixfiles_tools
="bash uname cat sort uniq awk grep egrep head expr find rm secon setfiles"
324 rm -rf $initdir/$_conf_dir
325 if ! cp -ar $_conf_dir $initdir/$_conf_dir; then
326 dfatal
"Failed to copy $_conf_dir"
330 cat <<EOF >$initdir/etc/systemd/system/autorelabel.service
332 Description=Relabel all filesystems
333 DefaultDependencies=no
334 Requires=local-fs.target
335 Conflicts=shutdown.target
336 After=local-fs.target
337 Before=sysinit.target shutdown.target
338 ConditionSecurity=selinux
339 ConditionPathExists=|/.autorelabel
342 ExecStart=/bin/sh -x -c 'echo 0 >/sys/fs/selinux/enforce && fixfiles -f -F relabel && rm /.autorelabel && systemctl --force reboot'
348 touch $initdir/.autorelabel
349 mkdir
-p $initdir/etc
/systemd
/system
/basic.target.wants
350 ln -fs autorelabel.service
$initdir/etc
/systemd
/system
/basic.target.wants
/autorelabel.service
352 dracut_install
$_fixfiles_tools
353 dracut_install fixfiles
354 dracut_install sestatus
358 if ! type -p valgrind
; then
359 dfatal
"Failed to install valgrind"
363 local _valgrind_bins
=$
(strace
-e execve valgrind
/bin
/true
2>&1 >/dev
/null | perl
-lne 'print $1 if /^execve\("([^"]+)"/')
364 dracut_install
$_valgrind_bins
366 local _valgrind_libs
=$
(LD_DEBUG
=files valgrind
/bin
/true
2>&1 >/dev
/null | perl
-lne 'print $1 if m{calling init: (/.*vgpreload_.*)}')
367 dracut_install
$_valgrind_libs
369 local _valgrind_dbg_and_supp
=$
(
370 strace
-e open valgrind
/bin
/true
2>&1 >/dev
/null |
371 perl
-lne 'if (my ($fname) = /^open\("([^"]+).*= (?!-)\d+/) { print $fname if $fname =~ /debug|\.supp$/ }'
373 dracut_install
$_valgrind_dbg_and_supp
376 create_valgrind_wrapper
() {
377 local _valgrind_wrapper
=$initdir/$ROOTLIBDIR/systemd-under-valgrind
378 ddebug
"Create $_valgrind_wrapper"
379 cat >$_valgrind_wrapper <<EOF
382 mount -t proc proc /proc
383 exec valgrind --leak-check=full --log-file=/valgrind.out $ROOTLIBDIR/systemd "\$@"
385 chmod 0755 $_valgrind_wrapper
388 create_asan_wrapper
() {
389 local _asan_wrapper
=$initdir/$ROOTLIBDIR/systemd-under-asan
390 local _asan_rt_pattern
391 ddebug
"Create $_asan_wrapper"
393 case "$ASAN_COMPILER" in
395 _asan_rt_pattern
="*libasan*"
398 _asan_rt_pattern
="libclang_rt.asan-*"
399 # Install llvm-symbolizer to generate useful reports
400 # See: https://clang.llvm.org/docs/AddressSanitizer.html#symbolizing-the-reports
401 dracut_install
"llvm-symbolizer"
404 dfail
"Unsupported compiler: $ASAN_COMPILER"
408 cat >$_asan_wrapper <<EOF
413 DEFAULT_ASAN_OPTIONS=${ASAN_OPTIONS:-strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1}
414 DEFAULT_UBSAN_OPTIONS=${UBSAN_OPTIONS:-print_stacktrace=1:print_summary=1:halt_on_error=1}
415 DEFAULT_ENVIRONMENT="ASAN_OPTIONS=\$DEFAULT_ASAN_OPTIONS UBSAN_OPTIONS=\$DEFAULT_UBSAN_OPTIONS"
417 # As right now bash is the PID 1, we can't expect PATH to have a sane value.
418 # Let's make one to prevent unexpected "<bin> not found" issues in the future
419 export PATH="/sbin:/bin:/usr/sbin:/usr/bin"
421 mount -t proc proc /proc
422 mount -t sysfs sysfs /sys
423 mount -o remount,rw /
425 PATH_TO_ASAN=\$(find / -name '$_asan_rt_pattern' | sed 1q)
426 if [[ "\$PATH_TO_ASAN" ]]; then
427 # A lot of services (most notably dbus) won't start without preloading libasan
428 # See https://github.com/systemd/systemd/issues/5004
429 DEFAULT_ENVIRONMENT="\$DEFAULT_ENVIRONMENT LD_PRELOAD=\$PATH_TO_ASAN"
430 # Let's add the ASan DSO's path to the dynamic linker's cache. This is pretty
431 # unnecessary for gcc & libasan, however, for clang this is crucial, as its
432 # runtime ASan DSO is in a non-standard (library) path.
433 echo \${PATH_TO_ASAN%/*} > /etc/ld.so.conf.d/asan-path-override.conf
436 echo DefaultEnvironment=\$DEFAULT_ENVIRONMENT >>/etc/systemd/system.conf
437 echo DefaultTimeoutStartSec=180s >>/etc/systemd/system.conf
438 echo DefaultStandardOutput=journal+console >>/etc/systemd/system.conf
440 # ASAN and syscall filters aren't compatible with each other.
441 find / -name '*.service' -type f | xargs sed -i 's/^\\(MemoryDeny\\|SystemCall\\)/#\\1/'
443 # The redirection of ASAN reports to a file prevents them from ending up in /dev/null.
444 # But, apparently, sometimes it doesn't work: https://github.com/google/sanitizers/issues/886.
445 JOURNALD_CONF_DIR=/etc/systemd/system/systemd-journald.service.d
446 mkdir -p "\$JOURNALD_CONF_DIR"
447 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"
449 # Sometimes UBSan sends its reports to stderr regardless of what is specified in log_path
450 # Let's try to catch them by redirecting stderr (and stdout just in case) to a file
451 # See https://github.com/systemd/systemd/pull/12524#issuecomment-491108821
452 printf "[Service]\nStandardOutput=file:/systemd-journald.out\n" >"\$JOURNALD_CONF_DIR/out.conf"
454 # 90s isn't enough for some services to finish when literally everything is run
455 # under ASan+UBSan in containers, which, in turn, are run in VMs.
456 # Let's limit which environments such services should be executed in.
457 mkdir -p /etc/systemd/system/systemd-hwdb-update.service.d
458 printf "[Unit]\nConditionVirtualization=container\n\n[Service]\nTimeoutSec=180s\n" >/etc/systemd/system/systemd-hwdb-update.service.d/env-override.conf
460 # Let's override another hard-coded timeout that kicks in too early
461 mkdir -p /etc/systemd/system/systemd-journal-flush.service.d
462 printf "[Service]\nTimeoutSec=180s\n" >/etc/systemd/system/systemd-journal-flush.service.d/timeout.conf
464 # The 'mount' utility doesn't behave well under libasan, causing unexpected
465 # fails during boot and subsequent test results check:
466 # bash-5.0# mount -o remount,rw -v /
467 # mount: /dev/sda1 mounted on /.
470 # Let's workaround this by clearing the previously set LD_PRELOAD env variable,
471 # so the libasan library is not loaded for this particular service
472 REMOUNTFS_CONF_DIR=/etc/systemd/system/systemd-remount-fs.service.d
473 mkdir -p "\$REMOUNTFS_CONF_DIR"
474 printf "[Service]\nUnsetEnvironment=LD_PRELOAD\n" >"\$REMOUNTFS_CONF_DIR/env.conf"
476 export ASAN_OPTIONS=\$DEFAULT_ASAN_OPTIONS:log_path=/systemd.asan.log UBSAN_OPTIONS=\$DEFAULT_UBSAN_OPTIONS
477 exec $ROOTLIBDIR/systemd "\$@"
480 chmod 0755 $_asan_wrapper
483 create_strace_wrapper
() {
484 local _strace_wrapper
=$initdir/$ROOTLIBDIR/systemd-under-strace
485 ddebug
"Create $_strace_wrapper"
486 cat >$_strace_wrapper <<EOF
489 exec strace -D -o /strace.out $ROOTLIBDIR/systemd "\$@"
491 chmod 0755 $_strace_wrapper
495 dracut_install
/sbin
/fsck
*
496 dracut_install
-o /bin
/fsck
*
498 # fskc.reiserfs calls reiserfsck. so, install it
499 dracut_install
-o reiserfsck
503 instmods dm_crypt
=crypto
505 if [[ "$LOOKS_LIKE_DEBIAN" ]]; then
506 # dmsetup installs 55-dm and 60-persistent-storage-dm on Debian/Ubuntu
507 # and since buster/bionic 95-dm-notify.rules
508 # see https://gitlab.com/debian-lvm/lvm2/blob/master/debian/patches/udev.patch
509 inst_rules
55-dm.rules
60-persistent-storage-dm.rules
95-dm-notify.rules
511 inst_rules
10-dm.rules
13-dm-disk.rules
95-dm-notify.rules
516 # install compiled files
517 local _ninja_bin
=$
(type -P ninja ||
type -P ninja-build
)
518 if [[ -z "$_ninja_bin" ]]; then
519 dfatal
"ninja was not found"
522 (set -x; DESTDIR
=$initdir "$_ninja_bin" -C $BUILD_DIR install)
523 # remove unneeded documentation
524 rm -fr $initdir/usr
/share
/{man
,doc
}
525 # we strip binaries since debug symbols increase binaries size a lot
526 # and it could fill the available space
529 [[ "$LOOKS_LIKE_SUSE" ]] && setup_suse
531 # enable debug logging in PID1
532 echo LogLevel
=debug
>> $initdir/etc
/systemd
/system.conf
533 # store coredumps in journal
534 echo Storage
=journal
>> $initdir/etc
/systemd
/coredump.conf
539 local rpath
=$
(objdump
-p "$_bin" 2>/dev
/null |
awk "/R(UN)?PATH/ { print \"$initdir\" \$2 }" |
paste -sd :)
541 if [ -z "$rpath" ] ; then
548 install_missing_libraries
() {
549 # install possible missing libraries
550 for i
in $initdir{,/usr
}/{sbin
,bin
}/* $initdir{,/usr
}/lib
/systemd
/{,tests
/{,manual
/,unsafe
/}}*; do
551 LD_LIBRARY_PATH
="${LD_LIBRARY_PATH:+$LD_LIBRARY_PATH:}$(get_ldpath $i)" inst_libs
$i
555 create_empty_image
() {
557 if [[ "$STRIP_BINARIES" = "no" ]]; then
560 rm -f "$TESTDIR/rootdisk.img"
561 # Create the blank file to use as a root filesystem
562 truncate
-s "${_size}M" "$TESTDIR/rootdisk.img"
563 LOOPDEV
=$
(losetup
--show -P -f $TESTDIR/rootdisk.img
)
564 [ -b "$LOOPDEV" ] ||
return 1
565 echo "LOOPDEV=$LOOPDEV" >> $STATEFILE
566 sfdisk
"$LOOPDEV" <<EOF
573 local _label
="-L systemd"
574 # mkfs.reiserfs doesn't know -L. so, use --label instead
575 [[ "$FSTYPE" == "reiserfs" ]] && _label
="--label systemd"
576 if ! mkfs
-t "${FSTYPE}" ${_label} "${LOOPDEV}p1" -q; then
577 dfatal
"Failed to mkfs -t ${FSTYPE}"
582 create_empty_image_rootdir
() {
585 mount
${LOOPDEV}p1
$initdir
586 TEST_SETUP_CLEANUP_ROOTDIR
=1
589 check_asan_reports
() {
593 if [[ "$IS_BUILT_WITH_ASAN" = "yes" ]]; then
595 if [[ -e "$root/systemd.asan.log.1" ]]; then
596 cat "$root/systemd.asan.log.1"
600 journald_report
=$
(find "$root" -name "systemd-journald.*san.log*" -exec cat {} \
;)
601 if [[ ! -z "$journald_report" ]]; then
602 printf "%s\n" "$journald_report"
603 cat "$root/systemd-journald.out" ||
:
608 "$JOURNALCTL" -D "$root/var/log/journal" | perl
-alne '
610 %services_to_ignore = (
611 "dbus-daemon" => undef,
614 print $2 if /\s(\S*)\[(\d+)\]:\s*SUMMARY:\s+\w+Sanitizer/ && !exists $services_to_ignore{$1}'
616 if [[ ! -z "$pids" ]]; then
619 "$JOURNALCTL" -D "$root/var/log/journal" _PID
=$pid --no-pager
627 check_result_nspawn
() {
629 local journald_report
=""
631 [[ -e $TESTDIR/$1/testok
]] && ret
=0
632 [[ -f $TESTDIR/$1/failed
]] && cp -a $TESTDIR/$1/failed
$TESTDIR
633 cp -a $TESTDIR/$1/var
/log
/journal
$TESTDIR
634 [[ -f $TESTDIR/failed
]] && cat $TESTDIR/failed
635 ls -l $TESTDIR/journal
/*/*.journal
636 test -s $TESTDIR/failed
&& ret
=$
(($ret+1))
637 [ -n "$TIMED_OUT" ] && ret
=$
(($ret+1))
638 check_asan_reports
"$TESTDIR/$1" || ret
=$
(($ret+1))
642 # can be overridden in specific test
643 check_result_qemu
() {
646 mount
${LOOPDEV}p1
$initdir
647 [[ -e $initdir/testok
]] && ret
=0
648 [[ -f $initdir/failed
]] && cp -a $initdir/failed
$TESTDIR
649 cp -a $initdir/var
/log
/journal
$TESTDIR
650 check_asan_reports
"$initdir" || ret
=$
(($ret+1))
652 [[ -f $TESTDIR/failed
]] && cat $TESTDIR/failed
653 ls -l $TESTDIR/journal
/*/*.journal
654 test -s $TESTDIR/failed
&& ret
=$
(($ret+1))
655 [ -n "$TIMED_OUT" ] && ret
=$
(($ret+1))
660 if [[ "$STRIP_BINARIES" = "no" ]]; then
661 ddebug
"Don't strip binaries"
664 ddebug
"Strip binaries"
665 find "$initdir" -executable -not -path '*/lib/modules/*.ko' -type f | \
666 xargs strip
--strip-unneeded |
& \
667 grep -vi 'file format not recognized' | \
672 mkdir
-p $initdir/etc
/rc.d
673 cat >$initdir/etc
/rc.d
/rc.
local <<EOF
677 chmod 0755 $initdir/etc
/rc.d
/rc.
local
681 ddebug
"install any Execs from the service files"
683 export PKG_CONFIG_PATH
=$BUILD_DIR/src
/core
/
684 systemdsystemunitdir
=$
(pkg-config
--variable=systemdsystemunitdir systemd
)
685 systemduserunitdir
=$
(pkg-config
--variable=systemduserunitdir systemd
)
686 sed -r -n 's|^Exec[a-zA-Z]*=[@+!-]*([^ ]+).*|\1|gp' $initdir/{$systemdsystemunitdir,$systemduserunitdir}/*.service \
687 |
sort -u |
while read i
; do
688 # some {rc,halt}.local scripts and programs are okay to not exist, the rest should
689 # also, plymouth is pulled in by rescue.service, but even there the exit code
690 # is ignored; as it's not present on some distros, don't fail if it doesn't exist
691 dinfo
"Attempting to install $i"
692 inst
$i ||
[ "${i%.local}" != "$i" ] ||
[ "${i%systemd-update-done}" != "$i" ] ||
[ "/bin/plymouth" == "$i" ]
697 generate_module_dependencies
() {
698 if [[ -d $initdir/lib
/modules
/$KERNEL_VER ]] && \
699 ! depmod
-a -b "$initdir" $KERNEL_VER; then
700 dfatal
"\"depmod -a $KERNEL_VER\" failed."
705 install_depmod_files
() {
706 inst
/lib
/modules
/$KERNEL_VER/modules.order
707 inst
/lib
/modules
/$KERNEL_VER/modules.
builtin
711 # install plymouth, if found... else remove plymouth service files
712 # if [ -x /usr/libexec/plymouth/plymouth-populate-initrd ]; then
713 # PLYMOUTH_POPULATE_SOURCE_FUNCTIONS="$TEST_BASE_DIR/test-functions" \
714 # /usr/libexec/plymouth/plymouth-populate-initrd -t $initdir
715 # dracut_install plymouth plymouthd
717 rm -f $initdir/{usr
/lib
,etc
}/systemd
/system
/plymouth
* $initdir/{usr
/lib
,etc
}/systemd
/system
/*/plymouth
*
721 install_ld_so_conf
() {
722 cp -a /etc
/ld.so.conf
* $initdir/etc
723 ldconfig
-r "$initdir"
726 install_config_files
() {
727 inst
/etc
/sysconfig
/init ||
:
733 inst
/etc
/nsswitch.conf
734 inst
/etc
/pam.conf ||
:
735 inst
/etc
/securetty ||
:
738 # we want an empty environment
739 > $initdir/etc
/environment
740 > $initdir/etc
/machine-id
742 echo systemd-testsuite
> $initdir/etc
/hostname
744 if [[ "$LOOKS_LIKE_SUSE" ]]; then
745 ROOTMOUNT
="/dev/sda1 / ${FSTYPE} rw 0 1"
747 ROOTMOUNT
="LABEL=systemd / ${FSTYPE} rw 0 1"
750 cat >$initdir/etc
/fstab
<<EOF
755 install_basic_tools
() {
756 [[ $BASICTOOLS ]] && dracut_install
$BASICTOOLS
757 dracut_install
-o sushell
758 # in Debian ldconfig is just a shell script wrapper around ldconfig.real
759 dracut_install
-o ldconfig.real
762 install_debug_tools
() {
763 [[ $DEBUGTOOLS ]] && dracut_install
$DEBUGTOOLS
765 if [[ $INTERACTIVE_DEBUG ]]; then
766 # Set default TERM from vt220 to linux, so at least basic key shortcuts work
767 local _getty_override
="$initdir/etc/systemd/system/serial-getty@.service.d"
768 mkdir
-p "$_getty_override"
769 echo -e "[Service]\nEnvironment=TERM=linux" > "$_getty_override/default-TERM.conf"
771 cat > "$initdir/etc/motd" << EOF
772 To adjust the terminal size use:
782 # install libnss_files for login
783 NSS_LIBS
=$
(LD_DEBUG
=files getent passwd
2>&1 >/dev
/null |
sed -n '/calling init: .*libnss_/ {s!^.* /!/!; p}')
784 dracut_install
$NSS_LIBS
788 inst
$ROOTLIBDIR/system
/dbus.socket
790 # Newer Fedora versions use dbus-broker by default. Let's install it is available.
791 if [ -f $ROOTLIBDIR/system
/dbus-broker.service
]; then
792 inst
$ROOTLIBDIR/system
/dbus-broker.service
793 inst_symlink
/etc
/systemd
/system
/dbus.service
794 inst
/usr
/bin
/dbus-broker
795 inst
/usr
/bin
/dbus-broker-launch
796 elif [ -f $ROOTLIBDIR/system
/dbus-daemon.service
]; then
797 # Fedora rawhide replaced dbus.service with dbus-daemon.service
798 inst
$ROOTLIBDIR/system
/dbus-daemon.service
800 inst_symlink
/etc
/systemd
/system
/dbus.service
802 inst
$ROOTLIBDIR/system
/dbus.service
806 /etc
/dbus-1
/usr
/share
/dbus-1
-xtype f \
807 |
while read file; do
814 if [[ "$LOOKS_LIKE_DEBIAN" ]] && type -p dpkg-architecture
&>/dev
/null
; then
815 find "/lib/$(dpkg-architecture -qDEB_HOST_MULTIARCH)/security" -xtype f
817 find /lib
*/security
-xtype f
819 find /etc
/pam.d
/etc
/security
-xtype f
820 ) |
while read file; do
824 # pam_unix depends on unix_chkpwd.
825 # see http://www.linux-pam.org/Linux-PAM-html/sag-pam_unix.html
826 dracut_install
-o unix_chkpwd
828 [[ "$LOOKS_LIKE_DEBIAN" ]] &&
829 cp /etc
/pam.d
/systemd-user
$initdir/etc
/pam.d
/
831 # set empty root password for easy debugging
832 sed -i 's/^root:x:/root::/' $initdir/etc
/passwd
836 # The first three paths may be deprecated.
837 # It seems now the last two paths are used by many distributions.
839 /usr
/lib
/kbd
/keymaps
/include
/* \
840 /usr
/lib
/kbd
/keymaps
/i386
/include
/* \
841 /usr
/lib
/kbd
/keymaps
/i386
/qwerty
/us.
* \
842 /usr
/lib
/kbd
/keymaps
/legacy
/include
/* \
843 /usr
/lib
/kbd
/keymaps
/legacy
/i386
/qwerty
/us.
*; do
844 [[ -f $i ]] ||
continue
848 # When it takes any argument, then install more keymaps.
851 /usr
/lib
/kbd
/keymaps
/i386
/*/* \
852 /usr
/lib
/kbd
/keymaps
/legacy
/i386
/*/*; do
853 [[ -f $i ]] ||
continue
860 for i
in /usr
/share
/zoneinfo
/{,*/,*/*/}*; do
861 [[ -f $i ]] ||
continue
868 /usr
/lib
/kbd
/consolefonts
/eurlatgr
* \
869 /usr
/lib
/kbd
/consolefonts
/latarcyrheb-sun16
*; do
870 [[ -f $i ]] ||
continue
876 for _terminfodir
in /lib
/terminfo
/etc
/terminfo
/usr
/share
/terminfo
; do
877 [ -f ${_terminfodir}/l
/linux
] && break
879 dracut_install
-o ${_terminfodir}/l
/linux
883 cp $TEST_BASE_DIR/testsuite.target
$initdir/etc
/systemd
/system
/
884 cp $TEST_BASE_DIR/end.service
$initdir/etc
/systemd
/system
/
886 mkdir
-p $initdir/etc
/systemd
/system
/testsuite.target.wants
887 ln -fs $TEST_BASE_DIR/testsuite.service
$initdir/etc
/systemd
/system
/testsuite.target.wants
/testsuite.service
888 # Don't shutdown the machine after running the test when INTERACTIVE_DEBUG is set
889 [[ -z $INTERACTIVE_DEBUG ]] && ln -fs $TEST_BASE_DIR/end.service
$initdir/etc
/systemd
/system
/testsuite.target.wants
/end.service
891 # make the testsuite the default target
892 ln -fs testsuite.target
$initdir/etc
/systemd
/system
/default.target
895 setup_nspawn_root
() {
896 rm -fr $TESTDIR/nspawn-root
897 ddebug
"cp -ar $initdir $TESTDIR/nspawn-root"
898 cp -ar $initdir $TESTDIR/nspawn-root
899 # we don't mount in the nspawn root
900 rm -f $TESTDIR/nspawn-root
/etc
/fstab
901 if [[ "$RUN_IN_UNPRIVILEGED_CONTAINER" = "yes" ]]; then
902 cp -ar $TESTDIR/nspawn-root
$TESTDIR/unprivileged-nspawn-root
907 mkdir
-p $initdir/run
908 mkdir
-p $initdir/etc
/systemd
/system
909 mkdir
-p $initdir/var
/log
/journal
911 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
912 if [ -L "/$d" ]; then
919 ln -sfn /run
"$initdir/var/run"
920 ln -sfn /run
/lock
"$initdir/var/lock"
923 mask_supporting_services
() {
924 # mask some services that we do not want to run in these tests
925 ln -fs /dev
/null
$initdir/etc
/systemd
/system
/systemd-hwdb-update.service
926 ln -fs /dev
/null
$initdir/etc
/systemd
/system
/systemd-journal-catalog-update.service
927 ln -fs /dev
/null
$initdir/etc
/systemd
/system
/systemd-networkd.service
928 ln -fs /dev
/null
$initdir/etc
/systemd
/system
/systemd-networkd.socket
929 ln -fs /dev
/null
$initdir/etc
/systemd
/system
/systemd-resolved.service
934 local _so_regex
='([^ ]*/lib[^/]*/[^ ]*\.so[^ ]*)'
937 LC_ALL
=C ldd
"$_bin" 2>/dev
/null |
while read _line
; do
938 [[ $_line = 'not a dynamic executable' ]] && break
940 if [[ $_line =~
$_so_regex ]]; then
941 _file
=${BASH_REMATCH[1]}
942 [[ -e ${initdir}/$_file ]] && continue
943 inst_library
"$_file"
947 if [[ $_line =~ not\ found
]]; then
948 dfatal
"Missing a shared library required by $_bin."
949 dfatal
"Run \"ldd $_bin\" to find out what it is."
951 dfatal
"dracut cannot create an initrd."
958 [[ -e $STATEFILE ]] && .
$STATEFILE
959 if [[ ! -d "$TESTDIR" ]]; then
960 if [[ -z "$TESTDIR" ]]; then
961 TESTDIR
=$
(mktemp
--tmpdir=/var
/tmp
-d -t systemd-test.XXXXXX
)
966 echo "TESTDIR=\"$TESTDIR\"" > $STATEFILE
972 initdir
=$TESTDIR/root
977 ## @brief Converts numeric logging level to the first letter of level name.
979 # @param lvl Numeric logging level in range from 1 to 6.
980 # @retval 1 if @a lvl is out of range.
981 # @retval 0 if @a lvl is correct.
982 # @result Echoes first letter of level name.
995 ## @brief Internal helper function for _do_dlog()
997 # @param lvl Numeric logging level.
998 # @param msg Message.
999 # @retval 0 It's always returned, even if logging failed.
1001 # @note This function is not supposed to be called manually. Please use
1002 # dtrace(), ddebug(), or others instead which wrap this one.
1004 # This function calls _do_dlog() either with parameter msg, or if
1005 # none is given, it will read standard input and will use every line as
1009 # dwarn "This is a warning"
1010 # echo "This is a warning" | dwarn
1011 LOG_LEVEL
=${LOG_LEVEL:-4}
1014 [ -z "$LOG_LEVEL" ] && return 0
1015 [ $1 -le $LOG_LEVEL ] ||
return 0
1016 local lvl
="$1"; shift
1017 local lvlc
=$
(_lvl2char
"$lvl") ||
return 0
1019 if [ $# -ge 1 ]; then
1023 echo "$lvlc: " "$line"
1028 ## @brief Logs message at TRACE level (6)
1030 # @param msg Message.
1031 # @retval 0 It's always returned, even if logging failed.
1035 [ -n "$debug" ] && set -x ||
:
1038 ## @brief Logs message at DEBUG level (5)
1040 # @param msg Message.
1041 # @retval 0 It's always returned, even if logging failed.
1045 # [ -n "$debug" ] && set -x || :
1048 ## @brief Logs message at INFO level (4)
1050 # @param msg Message.
1051 # @retval 0 It's always returned, even if logging failed.
1055 [ -n "$debug" ] && set -x ||
:
1058 ## @brief Logs message at WARN level (3)
1060 # @param msg Message.
1061 # @retval 0 It's always returned, even if logging failed.
1065 [ -n "$debug" ] && set -x ||
:
1068 ## @brief Logs message at ERROR level (2)
1070 # @param msg Message.
1071 # @retval 0 It's always returned, even if logging failed.
1075 # [ -n "$debug" ] && set -x || :
1078 ## @brief Logs message at FATAL level (1)
1080 # @param msg Message.
1081 # @retval 0 It's always returned, even if logging failed.
1085 [ -n "$debug" ] && set -x ||
:
1089 # Generic substring function. If $2 is in $1, return 0.
1090 strstr
() { [ "${1#*$2*}" != "$1" ]; }
1092 # normalize_path <path>
1093 # Prints the normalized path, where it removes any duplicated
1094 # and trailing slashes.
1096 # $ normalize_path ///test/test//
1100 set -- "${1//+(\/)//}"
1105 # convert_abs_rel <from> <to>
1106 # Prints the relative path, when creating a symlink to <to> from <from>.
1108 # $ convert_abs_rel /usr/bin/test /bin/test-2
1110 # $ ln -s $(convert_abs_rel /usr/bin/test /bin/test-2) /usr/bin/test
1112 local __current __absolute __abssize __cursize __newpath
1113 local -i __i __level
1115 set -- "$(normalize_path "$1")" "$(normalize_path "$2")"
1117 # corner case #1 - self looping link
1118 [[ "$1" == "$2" ]] && { echo "${1##*/}"; return; }
1120 # corner case #2 - own dir link
1121 [[ "${1%/*}" == "$2" ]] && { echo "."; return; }
1123 IFS
="/" __current
=($1)
1124 IFS
="/" __absolute
=($2)
1126 __abssize
=${#__absolute[@]}
1127 __cursize
=${#__current[@]}
1129 while [[ ${__absolute[__level]} == ${__current[__level]} ]]
1132 if (( __level
> __abssize || __level
> __cursize
))
1138 for ((__i
= __level
; __i
< __cursize-1
; __i
++))
1140 if ((__i
> __level
))
1142 __newpath
=$__newpath"/"
1144 __newpath
=$__newpath".."
1147 for ((__i
= __level
; __i
< __abssize
; __i
++))
1149 if [[ -n $__newpath ]]
1151 __newpath
=$__newpath"/"
1153 __newpath
=$__newpath${__absolute[__i]}
1160 # Install a directory, keeping symlinks as on the original system.
1161 # Example: if /lib points to /lib64 on the host, "inst_dir /lib/file"
1162 # will create ${initdir}/lib64, ${initdir}/lib64/file,
1163 # and a symlink ${initdir}/lib -> lib64.
1165 [[ -e ${initdir}/"$1" ]] && return 0 # already there
1167 local _dir
="$1" _part
="${1%/*}" _file
1168 while [[ "$_part" != "${_part%/*}" ]] && ! [[ -e "${initdir}/${_part}" ]]; do
1173 # iterate over parent directories
1174 for _file
in $_dir; do
1175 [[ -e "${initdir}/$_file" ]] && continue
1176 if [[ -L $_file ]]; then
1177 inst_symlink
"$_file"
1180 mkdir
-m 0755 -p "${initdir}/$_file" ||
return 1
1181 [[ -e "$_file" ]] && chmod --reference="$_file" "${initdir}/$_file"
1182 chmod u
+w
"${initdir}/$_file"
1187 # $1 = file to copy to ramdisk
1188 # $2 (optional) Name for the file on the ramdisk
1189 # Location of the image dir is assumed to be $initdir
1190 # We never overwrite the target if it exists.
1192 [[ -f "$1" ]] ||
return 1
1193 strstr
"$1" "/" ||
return 1
1195 local _src
=$1 target
="${2:-$1}"
1196 if ! [[ -d ${initdir}/$target ]]; then
1197 [[ -e ${initdir}/$target ]] && return 0
1198 [[ -L ${initdir}/$target ]] && return 0
1199 [[ -d "${initdir}/${target%/*}" ]] || inst_dir "${target%/*}"
1201 # install checksum files also
1202 if [[ -e "${_src%/*}/.${_src##*/}.hmac" ]]; then
1203 inst
"${_src%/*}/.${_src##*/}.hmac" "${target%/*}/.${target##*/}.hmac"
1205 ddebug
"Installing $_src"
1206 cp --sparse=always
-pfL "$_src" "${initdir}/$target"
1209 # find symlinks linked to given library file
1211 # Function searches for symlinks by stripping version numbers appended to
1212 # library filename, checks if it points to the same target and finally
1213 # prints the list of symlinks to stdout.
1216 # rev_lib_symlinks libfoo.so.8.1
1217 # output: libfoo.so.8 libfoo.so
1218 # (Only if libfoo.so.8 and libfoo.so exists on host system.)
1219 rev_lib_symlinks
() {
1220 [[ ! $1 ]] && return 0
1222 local fn
="$1" orig
="$(readlink -f "$1")" links
=''
1224 [[ ${fn} =~ .
*\.so\..
* ]] ||
return 1
1226 until [[ ${fn##*.} == so
]]; do
1228 [[ -L ${fn} && $(readlink -f "${fn}") == ${orig} ]] && links+=" ${fn}"
1234 # Same as above, but specialized to handle dynamic libraries.
1235 # It handles making symlinks according to how the original library
1238 local _src="$1" _dest=${2:-$1} _lib _reallib _symlink
1239 strstr "$1" "/" || return 1
1240 [[ -e $initdir/$_dest ]] && return 0
1241 if [[ -L $_src ]]; then
1242 # install checksum files also
1243 if [[ -e "${_src%/*}/.
${_src##*/}.hmac
" ]]; then
1244 inst "${_src%/*}/.${_src##*/}.hmac" "${_dest%/*}/.${_dest##*/}.hmac
"
1246 _reallib=$(readlink -f "$_src")
1247 inst_simple "$_reallib" "$_reallib"
1248 inst_dir "${_dest%/*}"
1249 [[ -d "${_dest%/*}" ]] && _dest=$(readlink -f "${_dest%/*}")/${_dest##*/}
1250 ln -sfn $
(convert_abs_rel
"${_dest}" "${_reallib}") "${initdir}/${_dest}"
1252 inst_simple
"$_src" "$_dest"
1255 # Create additional symlinks. See rev_symlinks description.
1256 for _symlink
in $
(rev_lib_symlinks
$_src) $
(rev_lib_symlinks
$_reallib); do
1257 [[ -e $initdir/$_symlink ]] ||
{
1258 ddebug
"Creating extra symlink: $_symlink"
1259 inst_symlink
$_symlink
1264 # find a binary. If we were not passed the full path directly,
1265 # search in the usual places to find the binary.
1267 if [[ -z ${1##/*} ]]; then
1268 if [[ -x $1 ]] ||
{ strstr
"$1" ".so" && ldd
$1 &>/dev
/null
; }; then
1277 # Same as above, but specialized to install binary executables.
1278 # Install binary executable, and all shared library dependencies, if any.
1282 # In certain cases we might attempt to install a binary which is already
1283 # present in the test image, yet it's missing from the host system.
1284 # In such cases, let's check if the binary indeed exists in the image
1285 # before doing any other chcecks. If it does, immediately return with
1287 [[ $# -eq 1 && -e $initdir/$1 ]] && return 0
1289 _bin
=$
(find_binary
"$1") ||
return 1
1291 [[ -e $initdir/$_target ]] && return 0
1292 [[ -L $_bin ]] && inst_symlink
$_bin $_target && return 0
1294 local _so_regex
='([^ ]*/lib[^/]*/[^ ]*\.so[^ ]*)'
1296 LC_ALL
=C ldd
"$_bin" 2>/dev
/null |
while read _line
; do
1297 [[ $_line = 'not a dynamic executable' ]] && break
1299 if [[ $_line =~
$_so_regex ]]; then
1300 _file
=${BASH_REMATCH[1]}
1301 [[ -e ${initdir}/$_file ]] && continue
1302 inst_library
"$_file"
1306 if [[ $_line =~ not\ found
]]; then
1307 dfatal
"Missing a shared library required by $_bin."
1308 dfatal
"Run \"ldd $_bin\" to find out what it is."
1310 dfatal
"dracut cannot create an initrd."
1314 inst_simple
"$_bin" "$_target"
1317 # same as above, except for shell scripts.
1318 # If your shell script does not start with shebang, it is not a shell script.
1321 _bin
=$
(find_binary
"$1") ||
return 1
1323 local _line _shebang_regex
1324 read -r -n 80 _line
<"$_bin"
1325 # If debug is set, clean unprintable chars to prevent messing up the term
1326 [[ $debug ]] && _line
=$
(echo -n "$_line" |
tr -c -d '[:print:][:space:]')
1327 _shebang_regex
='(#! *)(/[^ ]+).*'
1328 [[ $_line =~
$_shebang_regex ]] ||
return 1
1329 inst
"${BASH_REMATCH[2]}" && inst_simple
"$_bin" "$@"
1332 # same as above, but specialized for symlinks
1334 local _src
=$1 _target
=${2:-$1} _realsrc
1335 strstr
"$1" "/" ||
return 1
1336 [[ -L $1 ]] ||
return 1
1337 [[ -L $initdir/$_target ]] && return 0
1338 _realsrc
=$
(readlink
-f "$_src")
1339 if ! [[ -e $initdir/$_realsrc ]]; then
1340 if [[ -d $_realsrc ]]; then
1341 inst_dir
"$_realsrc"
1346 [[ ! -e $initdir/${_target%/*} ]] && inst_dir
"${_target%/*}"
1347 [[ -d ${_target%/*} ]] && _target=$(readlink -f ${_target%/*})/${_target##*/}
1348 ln -sfn $
(convert_abs_rel
"${_target}" "${_realsrc}") "$initdir/$_target"
1351 # attempt to install any programs specified in a udev rule
1352 inst_rule_programs
() {
1355 if grep -qE 'PROGRAM==?"[^ "]+' "$1"; then
1356 for _prog
in $
(grep -E 'PROGRAM==?"[^ "]+' "$1" |
sed -r 's/.*PROGRAM==?"([^ "]+).*/\1/'); do
1357 if [ -x /lib
/udev
/$_prog ]; then
1358 _bin
=/lib
/udev
/$_prog
1360 _bin
=$
(find_binary
"$_prog") ||
{
1361 dinfo
"Skipping program $_prog using in udev rule $(basename $1) as it cannot be found"
1366 #dinfo "Installing $_bin due to it's use in the udev rule $(basename $1)"
1367 dracut_install
"$_bin"
1372 # udev rules always get installed in the same place, so
1373 # create a function to install them to make life simpler.
1375 local _target
=/etc
/udev
/rules.d _rule _found
1377 inst_dir
"/lib/udev/rules.d"
1379 for _rule
in "$@"; do
1380 if [ "${rule#/}" = "$rule" ]; then
1381 for r
in /lib
/udev
/rules.d
/etc
/udev
/rules.d
; do
1382 if [[ -f $r/$_rule ]]; then
1384 inst_simple
"$_found"
1385 inst_rule_programs
"$_found"
1389 for r
in '' .
/ $dracutbasedir/rules.d
/; do
1390 if [[ -f ${r}$_rule ]]; then
1392 inst_simple
"$_found" "$_target/${_found##*/}"
1393 inst_rule_programs
"$_found"
1396 [[ $_found ]] || dinfo
"Skipping udev rule: $_rule"
1401 # general purpose installation function
1402 # Same args as above.
1408 2) [[ ! $initdir && -d $2 ]] && export initdir
=$2
1409 [[ $initdir = $2 ]] && set $1;;
1410 3) [[ -z $initdir ]] && export initdir
=$2
1412 *) dfatal
"inst only takes 1 or 2 or 3 arguments"
1415 for _x
in inst_symlink inst_script inst_binary inst_simple
; do
1416 $_x "$@" && return 0
1421 # install any of listed files
1423 # If first argument is '-d' and second some destination path, first accessible
1424 # source is installed into this path, otherwise it will installed in the same
1425 # path as source. If none of listed files was installed, function return 1.
1426 # On first successful installation it returns with 0 status.
1430 # inst_any -d /bin/foo /bin/bar /bin/baz
1432 # Lets assume that /bin/baz exists, so it will be installed as /bin/foo in
1437 [[ $1 = '-d' ]] && to
="$2" && shift 2
1440 if [[ -e $f ]]; then
1441 [[ $to ]] && inst
"$f" "$to" && return 0
1442 inst
"$f" && return 0
1449 # dracut_install [-o ] <file> [<file> ... ]
1450 # Install <file> to the initramfs image
1451 # -o optionally install the <file> and don't fail, if it is not there
1454 if [[ $1 = '-o' ]]; then
1458 while (($# > 0)); do
1459 if ! inst
"$1" ; then
1460 if [[ $_optional = yes ]]; then
1461 dinfo
"Skipping program $1 as it cannot be found and is" \
1462 "flagged to be optional"
1464 dfatal
"Failed to install $1"
1472 # Install a single kernel module along with any firmware it may require.
1473 # $1 = full path to kernel module to install
1474 install_kmod_with_fw
() {
1475 # no need to go further if the module is already installed
1477 [[ -e "${initdir}/lib/modules/$KERNEL_VER/${1##*/lib/modules/$KERNEL_VER/}" ]] \
1480 [[ -e "$initdir/.kernelmodseen/${1##*/}" ]] && return 0
1482 if [[ $omit_drivers ]]; then
1483 local _kmod
=${1##*/}
1486 if [[ "$_kmod" =~
$omit_drivers ]]; then
1487 dinfo
"Omitting driver $_kmod"
1490 if [[ "${1##*/lib/modules/$KERNEL_VER/}" =~
$omit_drivers ]]; then
1491 dinfo
"Omitting driver $_kmod"
1496 [ -d "$initdir/.kernelmodseen" ] && \
1497 > "$initdir/.kernelmodseen/${1##*/}"
1499 inst_simple
"$1" "/lib/modules/$KERNEL_VER/${1##*/lib/modules/$KERNEL_VER/}" \
1502 local _modname
=${1##*/} _fwdir _found _fw
1503 _modname
=${_modname%.ko*}
1504 for _fw
in $
(modinfo
-k $KERNEL_VER -F firmware
$1 2>/dev
/null
); do
1506 for _fwdir
in $fw_dir; do
1507 if [[ -d $_fwdir && -f $_fwdir/$_fw ]]; then
1508 inst_simple
"$_fwdir/$_fw" "/lib/firmware/$_fw"
1512 if [[ $_found != yes ]]; then
1513 if ! grep -qe "\<${_modname//-/_}\>" /proc
/modules
; then
1514 dinfo
"Possible missing firmware \"${_fw}\" for kernel module" \
1515 "\"${_modname}.ko\""
1517 dwarn
"Possible missing firmware \"${_fw}\" for kernel module" \
1518 "\"${_modname}.ko\""
1525 # Do something with all the dependencies of a kernel module.
1526 # Note that kernel modules depend on themselves using the technique we use
1527 # $1 = function to call for each dependency we find
1528 # It will be passed the full path to the found kernel module
1529 # $2 = module to get dependencies for
1530 # rest of args = arguments to modprobe
1531 # _fderr specifies FD passed from surrounding scope
1532 for_each_kmod_dep
() {
1533 local _func
=$1 _kmod
=$2 _cmd _modpath _options _found
=0
1535 modprobe
"$@" --ignore-install --show-depends $_kmod 2>&${_fderr} |
(
1536 while read _cmd _modpath _options
; do
1537 [[ $_cmd = insmod
]] ||
continue
1538 $_func ${_modpath} ||
exit $?
1541 [[ $_found -eq 0 ]] && exit 1
1546 # filter kernel modules to install certain modules that meet specific
1548 # $1 = search only in subdirectory of /kernel/$1
1549 # $2 = function to call with module name to filter.
1550 # This function will be passed the full path to the module to test.
1551 # The behavior of this function can vary depending on whether $hostonly is set.
1552 # If it is, we will only look at modules that are already in memory.
1553 # If it is not, we will look at all kernel modules
1554 # This function returns the full filenames of modules that match $1
1555 filter_kernel_modules_by_path
() (
1556 local _modname _filtercmd
1557 if ! [[ $hostonly ]]; then
1558 _filtercmd
='find "$KERNEL_MODS/kernel/$1" "$KERNEL_MODS/extra"'
1559 _filtercmd
+=' "$KERNEL_MODS/weak-updates" -name "*.ko" -o -name "*.ko.gz"'
1560 _filtercmd
+=' -o -name "*.ko.xz"'
1561 _filtercmd
+=' 2>/dev/null'
1563 _filtercmd
='cut -d " " -f 1 </proc/modules|xargs modinfo -F filename '
1564 _filtercmd
+='-k $KERNEL_VER 2>/dev/null'
1566 for _modname
in $
(eval $_filtercmd); do
1568 *.ko
) "$2" "$_modname" && echo "$_modname";;
1569 *.ko.gz
) gzip -dc "$_modname" > $initdir/$$.ko
1570 $2 $initdir/$$.ko
&& echo "$_modname"
1571 rm -f $initdir/$$.ko
1573 *.ko.xz
) xz
-dc "$_modname" > $initdir/$$.ko
1574 $2 $initdir/$$.ko
&& echo "$_modname"
1575 rm -f $initdir/$$.ko
1580 find_kernel_modules_by_path
() (
1581 if ! [[ $hostonly ]]; then
1582 find "$KERNEL_MODS/kernel/$1" "$KERNEL_MODS/extra" "$KERNEL_MODS/weak-updates" \
1583 -name "*.ko" -o -name "*.ko.gz" -o -name "*.ko.xz" 2>/dev
/null
1585 cut
-d " " -f 1 </proc
/modules \
1586 |
xargs modinfo
-F filename
-k $KERNEL_VER 2>/dev
/null
1590 filter_kernel_modules
() {
1591 filter_kernel_modules_by_path drivers
"$1"
1594 find_kernel_modules
() {
1595 find_kernel_modules_by_path drivers
1598 # instmods [-c] <kernel module> [<kernel module> ... ]
1599 # instmods [-c] <kernel subsystem>
1600 # install kernel modules along with all their dependencies.
1601 # <kernel subsystem> can be e.g. "=block" or "=drivers/usb/storage"
1603 [[ $no_kernel = yes ]] && return
1604 # called [sub]functions inherit _fderr
1607 if [[ $1 = '-c' ]]; then
1612 function inst1mod
() {
1613 local _ret
=0 _mod
="$1"
1616 if [ -f $KERNEL_MODS/modules.
${_mod#=} ]; then
1617 ( [[ "$_mpargs" ]] && echo $_mpargs
1618 cat "${KERNEL_MODS}/modules.${_mod#=}" ) \
1621 ( [[ "$_mpargs" ]] && echo $_mpargs
1622 find "$KERNEL_MODS" -path "*/${_mod#=}/*" -type f
-printf '%f\n' ) \
1626 --*) _mpargs
+=" $_mod" ;;
1627 i2o_scsi
) return ;; # Do not load this diagnostic-only module
1630 # if we are already installed, skip this module and go on
1632 [[ -f "$initdir/.kernelmodseen/${_mod%.ko}.ko" ]] && return
1634 if [[ $omit_drivers ]] && [[ "$1" =~
$omit_drivers ]]; then
1635 dinfo
"Omitting driver ${_mod##$KERNEL_MODS}"
1638 # If we are building a host-specific initramfs and this
1639 # module is not already loaded, move on to the next one.
1640 [[ $hostonly ]] && ! grep -qe "\<${_mod//-/_}\>" /proc
/modules \
1641 && ! echo $add_drivers |
grep -qe "\<${_mod}\>" \
1644 # We use '-d' option in modprobe only if modules prefix path
1645 # differs from default '/'. This allows us to use Dracut with
1646 # old version of modprobe which doesn't have '-d' option.
1647 local _moddirname
=${KERNEL_MODS%%/lib/modules/*}
1648 [[ -n ${_moddirname} ]] && _moddirname
="-d ${_moddirname}/"
1650 # ok, load the module, all its dependencies, and any firmware
1652 for_each_kmod_dep install_kmod_with_fw
$_mod \
1653 --set-version $KERNEL_VER ${_moddirname} $_mpargs
1660 function instmods_1
() {
1662 if (($# == 0)); then # filenames from stdin
1664 inst1mod
"${_mod%.ko*}" ||
{
1665 if [ "$_check" = "yes" ]; then
1666 dfatal
"Failed to install $_mod"
1672 while (($# > 0)); do # filenames as arguments
1673 inst1mod
${1%.ko*} ||
{
1674 if [ "$_check" = "yes" ]; then
1675 dfatal
"Failed to install $1"
1684 local _ret _filter_not_found
='FATAL: Module .* not found.'
1686 # Capture all stderr from modprobe to _fderr. We could use {var}>...
1687 # redirections, but that would make dracut require bash4 at least.
1688 eval "( instmods_1 \"\$@\" ) ${_fderr}>&1" \
1689 |
while read line
; do [[ "$line" =~
$_filter_not_found ]] && echo $line ||
echo $line >&2 ;done | derror
1696 ln -fs ..
/usr
/bin
/systemctl
$initdir/bin
/
1697 ln -fs ..
/usr
/lib
/systemd
$initdir/lib
/
1698 inst_simple
"/usr/lib/systemd/system/haveged.service"
1702 if mountpoint
-q $1; then
1708 _test_setup_cleanup
() {
1709 # only umount if create_empty_image_rootdir() was called to mount it
1710 [[ -z $TEST_SETUP_CLEANUP_ROOTDIR ]] || _umount_dir
$initdir
1713 # can be overridden in specific test
1714 test_setup_cleanup
() {
1719 # (post-test) cleanup should always ignore failure and cleanup as much as possible
1722 _umount_dir
$initdir
1723 if [[ $LOOPDEV && -b $LOOPDEV ]]; then
1724 ddebug
"losetup -d $LOOPDEV"
1732 # can be overridden in specific test
1738 if [ -z "$TEST_NO_QEMU" ]; then
1740 check_result_qemu ||
return 1
1742 dwarn
"can't run QEMU, skipping"
1745 if [ -z "$TEST_NO_NSPAWN" ]; then
1746 if run_nspawn
"nspawn-root"; then
1747 check_result_nspawn
"nspawn-root" ||
return 1
1749 dwarn
"can't run systemd-nspawn, skipping"
1752 if [[ "$RUN_IN_UNPRIVILEGED_CONTAINER" = "yes" ]]; then
1753 if NSPAWN_ARGUMENTS
="-U --private-network $NSPAWN_ARGUMENTS" run_nspawn
"unprivileged-nspawn-root"; then
1754 check_result_nspawn
"unprivileged-nspawn-root" ||
return 1
1756 dwarn
"can't run systemd-nspawn, skipping"
1764 if [[ $UID != "0" ]]; then
1765 echo "TEST: $TEST_DESCRIPTION [SKIPPED]: not root" >&2
1770 [[ $libdir ]] ||
for libdir
in /lib64
/lib
; do
1771 [[ -d $libdir ]] && libdirs
+=" $libdir" && break
1774 [[ $usrlibdir ]] ||
for usrlibdir
in /usr
/lib64
/usr
/lib
; do
1775 [[ -d $usrlibdir ]] && libdirs
+=" $usrlibdir" && break
1778 mkdir
-p "$STATEDIR"
1783 while (($# > 0)); do
1786 echo "TEST RUN: $TEST_DESCRIPTION"
1789 if (( $ret == 0 )); then
1790 echo "TEST RUN: $TEST_DESCRIPTION [OK]"
1792 echo "TEST RUN: $TEST_DESCRIPTION [FAILED]"
1796 echo "TEST SETUP: $TEST_DESCRIPTION"
1801 echo "TEST CLEANUP: $TEST_DESCRIPTION"
1806 echo -n "TEST: $TEST_DESCRIPTION "
1811 ) </dev
/null
>"$TESTLOG" 2>&1 || ret
=$?
1813 if [ $ret -eq 0 ]; then