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 \
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
471 REMOUNTFS_CONF_DIR=/etc/systemd/system/systemd-remount-fs.service.d
472 mkdir -p "\$REMOUNTFS_CONF_DIR"
473 printf "[Service]\nUnsetEnvironment=LD_PRELOAD\n" >"\$REMOUNTFS_CONF_DIR/env.conf"
475 export ASAN_OPTIONS=\$DEFAULT_ASAN_OPTIONS:log_path=/systemd.asan.log UBSAN_OPTIONS=\$DEFAULT_UBSAN_OPTIONS
476 exec $ROOTLIBDIR/systemd "\$@"
479 chmod 0755 $_asan_wrapper
482 create_strace_wrapper
() {
483 local _strace_wrapper
=$initdir/$ROOTLIBDIR/systemd-under-strace
484 ddebug
"Create $_strace_wrapper"
485 cat >$_strace_wrapper <<EOF
488 exec strace -D -o /strace.out $ROOTLIBDIR/systemd "\$@"
490 chmod 0755 $_strace_wrapper
494 dracut_install
/sbin
/fsck
*
495 dracut_install
-o /bin
/fsck
*
497 # fskc.reiserfs calls reiserfsck. so, install it
498 dracut_install
-o reiserfsck
502 instmods dm_crypt
=crypto
504 if [[ "$LOOKS_LIKE_DEBIAN" ]]; then
505 # dmsetup installs 55-dm and 60-persistent-storage-dm on Debian/Ubuntu
506 # and since buster/bionic 95-dm-notify.rules
507 # see https://gitlab.com/debian-lvm/lvm2/blob/master/debian/patches/udev.patch
508 inst_rules
55-dm.rules
60-persistent-storage-dm.rules
95-dm-notify.rules
510 inst_rules
10-dm.rules
13-dm-disk.rules
95-dm-notify.rules
515 # install compiled files
516 local _ninja_bin
=$
(type -P ninja ||
type -P ninja-build
)
517 if [[ -z "$_ninja_bin" ]]; then
518 dfatal
"ninja was not found"
521 (set -x; DESTDIR
=$initdir "$_ninja_bin" -C $BUILD_DIR install)
522 # remove unneeded documentation
523 rm -fr $initdir/usr
/share
/{man
,doc
}
524 # we strip binaries since debug symbols increase binaries size a lot
525 # and it could fill the available space
528 [[ "$LOOKS_LIKE_SUSE" ]] && setup_suse
530 # enable debug logging in PID1
531 echo LogLevel
=debug
>> $initdir/etc
/systemd
/system.conf
532 # store coredumps in journal
533 echo Storage
=journal
>> $initdir/etc
/systemd
/coredump.conf
538 objdump
-p "$_bin" 2>/dev
/null |
awk "/R(UN)?PATH/ { print \"$initdir\" \$2 }" |
paste -sd :
541 install_missing_libraries
() {
542 # install possible missing libraries
543 for i
in $initdir{,/usr
}/{sbin
,bin
}/* $initdir{,/usr
}/lib
/systemd
/{,tests
/{,manual
/,unsafe
/}}*; do
544 LD_LIBRARY_PATH
="${LD_LIBRARY_PATH:+$LD_LIBRARY_PATH:}$(get_ldpath $i)" inst_libs
$i
548 create_empty_image
() {
550 if [[ "$STRIP_BINARIES" = "no" ]]; then
553 rm -f "$TESTDIR/rootdisk.img"
554 # Create the blank file to use as a root filesystem
555 truncate
-s "${_size}M" "$TESTDIR/rootdisk.img"
556 LOOPDEV
=$
(losetup
--show -P -f $TESTDIR/rootdisk.img
)
557 [ -b "$LOOPDEV" ] ||
return 1
558 echo "LOOPDEV=$LOOPDEV" >> $STATEFILE
559 sfdisk
"$LOOPDEV" <<EOF
566 local _label
="-L systemd"
567 # mkfs.reiserfs doesn't know -L. so, use --label instead
568 [[ "$FSTYPE" == "reiserfs" ]] && _label
="--label systemd"
569 if ! mkfs
-t "${FSTYPE}" ${_label} "${LOOPDEV}p1" -q; then
570 dfatal
"Failed to mkfs -t ${FSTYPE}"
575 create_empty_image_rootdir
() {
578 mount
${LOOPDEV}p1
$initdir
579 TEST_SETUP_CLEANUP_ROOTDIR
=1
582 check_asan_reports
() {
586 if [[ "$IS_BUILT_WITH_ASAN" = "yes" ]]; then
588 if [[ -e "$root/systemd.asan.log.1" ]]; then
589 cat "$root/systemd.asan.log.1"
593 journald_report
=$
(find "$root" -name "systemd-journald.*san.log*" -exec cat {} \
;)
594 if [[ ! -z "$journald_report" ]]; then
595 printf "%s\n" "$journald_report"
596 cat "$root/systemd-journald.out" ||
:
601 "$JOURNALCTL" -D "$root/var/log/journal" | perl
-alne '
603 %services_to_ignore = (
604 "dbus-daemon" => undef,
607 print $2 if /\s(\S*)\[(\d+)\]:\s*SUMMARY:\s+\w+Sanitizer/ && !exists $services_to_ignore{$1}'
609 if [[ ! -z "$pids" ]]; then
612 "$JOURNALCTL" -D "$root/var/log/journal" _PID
=$pid --no-pager
620 check_result_nspawn
() {
622 local journald_report
=""
624 [[ -e $TESTDIR/$1/testok
]] && ret
=0
625 [[ -f $TESTDIR/$1/failed
]] && cp -a $TESTDIR/$1/failed
$TESTDIR
626 cp -a $TESTDIR/$1/var
/log
/journal
$TESTDIR
627 [[ -f $TESTDIR/failed
]] && cat $TESTDIR/failed
628 ls -l $TESTDIR/journal
/*/*.journal
629 test -s $TESTDIR/failed
&& ret
=$
(($ret+1))
630 [ -n "$TIMED_OUT" ] && ret
=$
(($ret+1))
631 check_asan_reports
"$TESTDIR/$1" || ret
=$
(($ret+1))
635 # can be overridden in specific test
636 check_result_qemu
() {
639 mount
${LOOPDEV}p1
$initdir
640 [[ -e $initdir/testok
]] && ret
=0
641 [[ -f $initdir/failed
]] && cp -a $initdir/failed
$TESTDIR
642 cp -a $initdir/var
/log
/journal
$TESTDIR
643 check_asan_reports
"$initdir" || ret
=$
(($ret+1))
645 [[ -f $TESTDIR/failed
]] && cat $TESTDIR/failed
646 ls -l $TESTDIR/journal
/*/*.journal
647 test -s $TESTDIR/failed
&& ret
=$
(($ret+1))
648 [ -n "$TIMED_OUT" ] && ret
=$
(($ret+1))
653 if [[ "$STRIP_BINARIES" = "no" ]]; then
654 ddebug
"Don't strip binaries"
657 ddebug
"Strip binaries"
658 find "$initdir" -executable -not -path '*/lib/modules/*.ko' -type f | \
659 xargs strip
--strip-unneeded |
& \
660 grep -vi 'file format not recognized' | \
665 mkdir
-p $initdir/etc
/rc.d
666 cat >$initdir/etc
/rc.d
/rc.
local <<EOF
670 chmod 0755 $initdir/etc
/rc.d
/rc.
local
674 ddebug
"install any Execs from the service files"
676 export PKG_CONFIG_PATH
=$BUILD_DIR/src
/core
/
677 systemdsystemunitdir
=$
(pkg-config
--variable=systemdsystemunitdir systemd
)
678 systemduserunitdir
=$
(pkg-config
--variable=systemduserunitdir systemd
)
679 sed -r -n 's|^Exec[a-zA-Z]*=[@+!-]*([^ ]+).*|\1|gp' $initdir/{$systemdsystemunitdir,$systemduserunitdir}/*.service \
680 |
sort -u |
while read i
; do
681 # some {rc,halt}.local scripts and programs are okay to not exist, the rest should
682 # also, plymouth is pulled in by rescue.service, but even there the exit code
683 # is ignored; as it's not present on some distros, don't fail if it doesn't exist
684 dinfo
"Attempting to install $i"
685 inst
$i ||
[ "${i%.local}" != "$i" ] ||
[ "${i%systemd-update-done}" != "$i" ] ||
[ "/bin/plymouth" == "$i" ]
690 generate_module_dependencies
() {
691 if [[ -d $initdir/lib
/modules
/$KERNEL_VER ]] && \
692 ! depmod
-a -b "$initdir" $KERNEL_VER; then
693 dfatal
"\"depmod -a $KERNEL_VER\" failed."
698 install_depmod_files
() {
699 inst
/lib
/modules
/$KERNEL_VER/modules.order
700 inst
/lib
/modules
/$KERNEL_VER/modules.
builtin
704 # install plymouth, if found... else remove plymouth service files
705 # if [ -x /usr/libexec/plymouth/plymouth-populate-initrd ]; then
706 # PLYMOUTH_POPULATE_SOURCE_FUNCTIONS="$TEST_BASE_DIR/test-functions" \
707 # /usr/libexec/plymouth/plymouth-populate-initrd -t $initdir
708 # dracut_install plymouth plymouthd
710 rm -f $initdir/{usr
/lib
,etc
}/systemd
/system
/plymouth
* $initdir/{usr
/lib
,etc
}/systemd
/system
/*/plymouth
*
714 install_ld_so_conf
() {
715 cp -a /etc
/ld.so.conf
* $initdir/etc
716 ldconfig
-r "$initdir"
719 install_config_files
() {
720 inst
/etc
/sysconfig
/init ||
:
726 inst
/etc
/nsswitch.conf
727 inst
/etc
/pam.conf ||
:
728 inst
/etc
/securetty ||
:
731 # we want an empty environment
732 > $initdir/etc
/environment
733 > $initdir/etc
/machine-id
735 echo systemd-testsuite
> $initdir/etc
/hostname
737 if [[ "$LOOKS_LIKE_SUSE" ]]; then
738 ROOTMOUNT
="/dev/sda1 / ${FSTYPE} rw 0 1"
740 ROOTMOUNT
="LABEL=systemd / ${FSTYPE} rw 0 1"
743 cat >$initdir/etc
/fstab
<<EOF
748 install_basic_tools
() {
749 [[ $BASICTOOLS ]] && dracut_install
$BASICTOOLS
750 dracut_install
-o sushell
751 # in Debian ldconfig is just a shell script wrapper around ldconfig.real
752 dracut_install
-o ldconfig.real
755 install_debug_tools
() {
756 [[ $DEBUGTOOLS ]] && dracut_install
$DEBUGTOOLS
758 if [[ $INTERACTIVE_DEBUG ]]; then
759 # Set default TERM from vt220 to linux, so at least basic key shortcuts work
760 local _getty_override
="$initdir/etc/systemd/system/serial-getty@.service.d"
761 mkdir
-p "$_getty_override"
762 echo -e "[Service]\nEnvironment=TERM=linux" > "$_getty_override/default-TERM.conf"
764 cat > "$initdir/etc/motd" << EOF
765 To adjust the terminal size use:
775 # install libnss_files for login
776 NSS_LIBS
=$
(LD_DEBUG
=files getent passwd
2>&1 >/dev
/null |
sed -n '/calling init: .*libnss_/ {s!^.* /!/!; p}')
777 dracut_install
$NSS_LIBS
781 inst
$ROOTLIBDIR/system
/dbus.socket
783 # Newer Fedora versions use dbus-broker by default. Let's install it is available.
784 if [ -f $ROOTLIBDIR/system
/dbus-broker.service
]; then
785 inst
$ROOTLIBDIR/system
/dbus-broker.service
786 inst_symlink
/etc
/systemd
/system
/dbus.service
787 inst
/usr
/bin
/dbus-broker
788 inst
/usr
/bin
/dbus-broker-launch
789 elif [ -f $ROOTLIBDIR/system
/dbus-daemon.service
]; then
790 # Fedora rawhide replaced dbus.service with dbus-daemon.service
791 inst
$ROOTLIBDIR/system
/dbus-daemon.service
793 inst_symlink
/etc
/systemd
/system
/dbus.service
795 inst
$ROOTLIBDIR/system
/dbus.service
799 /etc
/dbus-1
/usr
/share
/dbus-1
-xtype f \
800 |
while read file; do
807 if [[ "$LOOKS_LIKE_DEBIAN" ]] && type -p dpkg-architecture
&>/dev
/null
; then
808 find "/lib/$(dpkg-architecture -qDEB_HOST_MULTIARCH)/security" -xtype f
810 find /lib
*/security
-xtype f
812 find /etc
/pam.d
/etc
/security
-xtype f
813 ) |
while read file; do
817 # pam_unix depends on unix_chkpwd.
818 # see http://www.linux-pam.org/Linux-PAM-html/sag-pam_unix.html
819 dracut_install
-o unix_chkpwd
821 [[ "$LOOKS_LIKE_DEBIAN" ]] &&
822 cp /etc
/pam.d
/systemd-user
$initdir/etc
/pam.d
/
824 # set empty root password for easy debugging
825 sed -i 's/^root:x:/root::/' $initdir/etc
/passwd
829 # The first three paths may be deprecated.
830 # It seems now the last two paths are used by many distributions.
832 /usr
/lib
/kbd
/keymaps
/include
/* \
833 /usr
/lib
/kbd
/keymaps
/i386
/include
/* \
834 /usr
/lib
/kbd
/keymaps
/i386
/qwerty
/us.
* \
835 /usr
/lib
/kbd
/keymaps
/legacy
/include
/* \
836 /usr
/lib
/kbd
/keymaps
/legacy
/i386
/qwerty
/us.
*; do
837 [[ -f $i ]] ||
continue
841 # When it takes any argument, then install more keymaps.
844 /usr
/lib
/kbd
/keymaps
/i386
/*/* \
845 /usr
/lib
/kbd
/keymaps
/legacy
/i386
/*/*; do
846 [[ -f $i ]] ||
continue
853 for i
in /usr
/share
/zoneinfo
/{,*/,*/*/}*; do
854 [[ -f $i ]] ||
continue
861 /usr
/lib
/kbd
/consolefonts
/eurlatgr
* \
862 /usr
/lib
/kbd
/consolefonts
/latarcyrheb-sun16
*; do
863 [[ -f $i ]] ||
continue
869 for _terminfodir
in /lib
/terminfo
/etc
/terminfo
/usr
/share
/terminfo
; do
870 [ -f ${_terminfodir}/l
/linux
] && break
872 dracut_install
-o ${_terminfodir}/l
/linux
876 cp $TEST_BASE_DIR/testsuite.target
$initdir/etc
/systemd
/system
/
877 cp $TEST_BASE_DIR/end.service
$initdir/etc
/systemd
/system
/
879 mkdir
-p $initdir/etc
/systemd
/system
/testsuite.target.wants
880 ln -fs $TEST_BASE_DIR/testsuite.service
$initdir/etc
/systemd
/system
/testsuite.target.wants
/testsuite.service
881 # Don't shutdown the machine after running the test when INTERACTIVE_DEBUG is set
882 [[ -z $INTERACTIVE_DEBUG ]] && ln -fs $TEST_BASE_DIR/end.service
$initdir/etc
/systemd
/system
/testsuite.target.wants
/end.service
884 # make the testsuite the default target
885 ln -fs testsuite.target
$initdir/etc
/systemd
/system
/default.target
888 setup_nspawn_root
() {
889 rm -fr $TESTDIR/nspawn-root
890 ddebug
"cp -ar $initdir $TESTDIR/nspawn-root"
891 cp -ar $initdir $TESTDIR/nspawn-root
892 # we don't mount in the nspawn root
893 rm -f $TESTDIR/nspawn-root
/etc
/fstab
894 if [[ "$RUN_IN_UNPRIVILEGED_CONTAINER" = "yes" ]]; then
895 cp -ar $TESTDIR/nspawn-root
$TESTDIR/unprivileged-nspawn-root
900 mkdir
-p $initdir/run
901 mkdir
-p $initdir/etc
/systemd
/system
902 mkdir
-p $initdir/var
/log
/journal
904 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
905 if [ -L "/$d" ]; then
912 ln -sfn /run
"$initdir/var/run"
913 ln -sfn /run
/lock
"$initdir/var/lock"
916 mask_supporting_services
() {
917 # mask some services that we do not want to run in these tests
918 ln -fs /dev
/null
$initdir/etc
/systemd
/system
/systemd-hwdb-update.service
919 ln -fs /dev
/null
$initdir/etc
/systemd
/system
/systemd-journal-catalog-update.service
920 ln -fs /dev
/null
$initdir/etc
/systemd
/system
/systemd-networkd.service
921 ln -fs /dev
/null
$initdir/etc
/systemd
/system
/systemd-networkd.socket
922 ln -fs /dev
/null
$initdir/etc
/systemd
/system
/systemd-resolved.service
927 local _so_regex
='([^ ]*/lib[^/]*/[^ ]*\.so[^ ]*)'
930 LC_ALL
=C ldd
"$_bin" 2>/dev
/null |
while read _line
; do
931 [[ $_line = 'not a dynamic executable' ]] && break
933 if [[ $_line =~
$_so_regex ]]; then
934 _file
=${BASH_REMATCH[1]}
935 [[ -e ${initdir}/$_file ]] && continue
936 inst_library
"$_file"
940 if [[ $_line =~ not\ found
]]; then
941 dfatal
"Missing a shared library required by $_bin."
942 dfatal
"Run \"ldd $_bin\" to find out what it is."
944 dfatal
"dracut cannot create an initrd."
951 [[ -e $STATEFILE ]] && .
$STATEFILE
952 if [[ ! -d "$TESTDIR" ]]; then
953 if [[ -z "$TESTDIR" ]]; then
954 TESTDIR
=$
(mktemp
--tmpdir=/var
/tmp
-d -t systemd-test.XXXXXX
)
959 echo "TESTDIR=\"$TESTDIR\"" > $STATEFILE
965 initdir
=$TESTDIR/root
970 ## @brief Converts numeric logging level to the first letter of level name.
972 # @param lvl Numeric logging level in range from 1 to 6.
973 # @retval 1 if @a lvl is out of range.
974 # @retval 0 if @a lvl is correct.
975 # @result Echoes first letter of level name.
988 ## @brief Internal helper function for _do_dlog()
990 # @param lvl Numeric logging level.
991 # @param msg Message.
992 # @retval 0 It's always returned, even if logging failed.
994 # @note This function is not supposed to be called manually. Please use
995 # dtrace(), ddebug(), or others instead which wrap this one.
997 # This function calls _do_dlog() either with parameter msg, or if
998 # none is given, it will read standard input and will use every line as
1002 # dwarn "This is a warning"
1003 # echo "This is a warning" | dwarn
1004 LOG_LEVEL
=${LOG_LEVEL:-4}
1007 [ -z "$LOG_LEVEL" ] && return 0
1008 [ $1 -le $LOG_LEVEL ] ||
return 0
1009 local lvl
="$1"; shift
1010 local lvlc
=$
(_lvl2char
"$lvl") ||
return 0
1012 if [ $# -ge 1 ]; then
1016 echo "$lvlc: " "$line"
1021 ## @brief Logs message at TRACE level (6)
1023 # @param msg Message.
1024 # @retval 0 It's always returned, even if logging failed.
1028 [ -n "$debug" ] && set -x ||
:
1031 ## @brief Logs message at DEBUG level (5)
1033 # @param msg Message.
1034 # @retval 0 It's always returned, even if logging failed.
1038 # [ -n "$debug" ] && set -x || :
1041 ## @brief Logs message at INFO level (4)
1043 # @param msg Message.
1044 # @retval 0 It's always returned, even if logging failed.
1048 [ -n "$debug" ] && set -x ||
:
1051 ## @brief Logs message at WARN level (3)
1053 # @param msg Message.
1054 # @retval 0 It's always returned, even if logging failed.
1058 [ -n "$debug" ] && set -x ||
:
1061 ## @brief Logs message at ERROR level (2)
1063 # @param msg Message.
1064 # @retval 0 It's always returned, even if logging failed.
1068 # [ -n "$debug" ] && set -x || :
1071 ## @brief Logs message at FATAL level (1)
1073 # @param msg Message.
1074 # @retval 0 It's always returned, even if logging failed.
1078 [ -n "$debug" ] && set -x ||
:
1082 # Generic substring function. If $2 is in $1, return 0.
1083 strstr
() { [ "${1#*$2*}" != "$1" ]; }
1085 # normalize_path <path>
1086 # Prints the normalized path, where it removes any duplicated
1087 # and trailing slashes.
1089 # $ normalize_path ///test/test//
1093 set -- "${1//+(\/)//}"
1098 # convert_abs_rel <from> <to>
1099 # Prints the relative path, when creating a symlink to <to> from <from>.
1101 # $ convert_abs_rel /usr/bin/test /bin/test-2
1103 # $ ln -s $(convert_abs_rel /usr/bin/test /bin/test-2) /usr/bin/test
1105 local __current __absolute __abssize __cursize __newpath
1106 local -i __i __level
1108 set -- "$(normalize_path "$1")" "$(normalize_path "$2")"
1110 # corner case #1 - self looping link
1111 [[ "$1" == "$2" ]] && { echo "${1##*/}"; return; }
1113 # corner case #2 - own dir link
1114 [[ "${1%/*}" == "$2" ]] && { echo "."; return; }
1116 IFS
="/" __current
=($1)
1117 IFS
="/" __absolute
=($2)
1119 __abssize
=${#__absolute[@]}
1120 __cursize
=${#__current[@]}
1122 while [[ ${__absolute[__level]} == ${__current[__level]} ]]
1125 if (( __level
> __abssize || __level
> __cursize
))
1131 for ((__i
= __level
; __i
< __cursize-1
; __i
++))
1133 if ((__i
> __level
))
1135 __newpath
=$__newpath"/"
1137 __newpath
=$__newpath".."
1140 for ((__i
= __level
; __i
< __abssize
; __i
++))
1142 if [[ -n $__newpath ]]
1144 __newpath
=$__newpath"/"
1146 __newpath
=$__newpath${__absolute[__i]}
1153 # Install a directory, keeping symlinks as on the original system.
1154 # Example: if /lib points to /lib64 on the host, "inst_dir /lib/file"
1155 # will create ${initdir}/lib64, ${initdir}/lib64/file,
1156 # and a symlink ${initdir}/lib -> lib64.
1158 [[ -e ${initdir}/"$1" ]] && return 0 # already there
1160 local _dir
="$1" _part
="${1%/*}" _file
1161 while [[ "$_part" != "${_part%/*}" ]] && ! [[ -e "${initdir}/${_part}" ]]; do
1166 # iterate over parent directories
1167 for _file
in $_dir; do
1168 [[ -e "${initdir}/$_file" ]] && continue
1169 if [[ -L $_file ]]; then
1170 inst_symlink
"$_file"
1173 mkdir
-m 0755 -p "${initdir}/$_file" ||
return 1
1174 [[ -e "$_file" ]] && chmod --reference="$_file" "${initdir}/$_file"
1175 chmod u
+w
"${initdir}/$_file"
1180 # $1 = file to copy to ramdisk
1181 # $2 (optional) Name for the file on the ramdisk
1182 # Location of the image dir is assumed to be $initdir
1183 # We never overwrite the target if it exists.
1185 [[ -f "$1" ]] ||
return 1
1186 strstr
"$1" "/" ||
return 1
1188 local _src
=$1 target
="${2:-$1}"
1189 if ! [[ -d ${initdir}/$target ]]; then
1190 [[ -e ${initdir}/$target ]] && return 0
1191 [[ -L ${initdir}/$target ]] && return 0
1192 [[ -d "${initdir}/${target%/*}" ]] || inst_dir "${target%/*}"
1194 # install checksum files also
1195 if [[ -e "${_src%/*}/.${_src##*/}.hmac" ]]; then
1196 inst
"${_src%/*}/.${_src##*/}.hmac" "${target%/*}/.${target##*/}.hmac"
1198 ddebug
"Installing $_src"
1199 cp --sparse=always
-pfL "$_src" "${initdir}/$target"
1202 # find symlinks linked to given library file
1204 # Function searches for symlinks by stripping version numbers appended to
1205 # library filename, checks if it points to the same target and finally
1206 # prints the list of symlinks to stdout.
1209 # rev_lib_symlinks libfoo.so.8.1
1210 # output: libfoo.so.8 libfoo.so
1211 # (Only if libfoo.so.8 and libfoo.so exists on host system.)
1212 rev_lib_symlinks
() {
1213 [[ ! $1 ]] && return 0
1215 local fn
="$1" orig
="$(readlink -f "$1")" links
=''
1217 [[ ${fn} =~ .
*\.so\..
* ]] ||
return 1
1219 until [[ ${fn##*.} == so
]]; do
1221 [[ -L ${fn} && $(readlink -f "${fn}") == ${orig} ]] && links+=" ${fn}"
1227 # Same as above, but specialized to handle dynamic libraries.
1228 # It handles making symlinks according to how the original library
1231 local _src="$1" _dest=${2:-$1} _lib _reallib _symlink
1232 strstr "$1" "/" || return 1
1233 [[ -e $initdir/$_dest ]] && return 0
1234 if [[ -L $_src ]]; then
1235 # install checksum files also
1236 if [[ -e "${_src%/*}/.
${_src##*/}.hmac
" ]]; then
1237 inst "${_src%/*}/.${_src##*/}.hmac" "${_dest%/*}/.${_dest##*/}.hmac
"
1239 _reallib=$(readlink -f "$_src")
1240 inst_simple "$_reallib" "$_reallib"
1241 inst_dir "${_dest%/*}"
1242 [[ -d "${_dest%/*}" ]] && _dest=$(readlink -f "${_dest%/*}")/${_dest##*/}
1243 ln -sfn $
(convert_abs_rel
"${_dest}" "${_reallib}") "${initdir}/${_dest}"
1245 inst_simple
"$_src" "$_dest"
1248 # Create additional symlinks. See rev_symlinks description.
1249 for _symlink
in $
(rev_lib_symlinks
$_src) $
(rev_lib_symlinks
$_reallib); do
1250 [[ -e $initdir/$_symlink ]] ||
{
1251 ddebug
"Creating extra symlink: $_symlink"
1252 inst_symlink
$_symlink
1257 # find a binary. If we were not passed the full path directly,
1258 # search in the usual places to find the binary.
1260 if [[ -z ${1##/*} ]]; then
1261 if [[ -x $1 ]] ||
{ strstr
"$1" ".so" && ldd
$1 &>/dev
/null
; }; then
1270 # Same as above, but specialized to install binary executables.
1271 # Install binary executable, and all shared library dependencies, if any.
1275 # In certain cases we might attempt to install a binary which is already
1276 # present in the test image, yet it's missing from the host system.
1277 # In such cases, let's check if the binary indeed exists in the image
1278 # before doing any other chcecks. If it does, immediately return with
1280 [[ $# -eq 1 && -e $initdir/$1 ]] && return 0
1282 _bin
=$
(find_binary
"$1") ||
return 1
1284 [[ -e $initdir/$_target ]] && return 0
1285 [[ -L $_bin ]] && inst_symlink
$_bin $_target && return 0
1287 local _so_regex
='([^ ]*/lib[^/]*/[^ ]*\.so[^ ]*)'
1289 LC_ALL
=C ldd
"$_bin" 2>/dev
/null |
while read _line
; do
1290 [[ $_line = 'not a dynamic executable' ]] && break
1292 if [[ $_line =~
$_so_regex ]]; then
1293 _file
=${BASH_REMATCH[1]}
1294 [[ -e ${initdir}/$_file ]] && continue
1295 inst_library
"$_file"
1299 if [[ $_line =~ not\ found
]]; then
1300 dfatal
"Missing a shared library required by $_bin."
1301 dfatal
"Run \"ldd $_bin\" to find out what it is."
1303 dfatal
"dracut cannot create an initrd."
1307 inst_simple
"$_bin" "$_target"
1310 # same as above, except for shell scripts.
1311 # If your shell script does not start with shebang, it is not a shell script.
1314 _bin
=$
(find_binary
"$1") ||
return 1
1316 local _line _shebang_regex
1317 read -r -n 80 _line
<"$_bin"
1318 # If debug is set, clean unprintable chars to prevent messing up the term
1319 [[ $debug ]] && _line
=$
(echo -n "$_line" |
tr -c -d '[:print:][:space:]')
1320 _shebang_regex
='(#! *)(/[^ ]+).*'
1321 [[ $_line =~
$_shebang_regex ]] ||
return 1
1322 inst
"${BASH_REMATCH[2]}" && inst_simple
"$_bin" "$@"
1325 # same as above, but specialized for symlinks
1327 local _src
=$1 _target
=${2:-$1} _realsrc
1328 strstr
"$1" "/" ||
return 1
1329 [[ -L $1 ]] ||
return 1
1330 [[ -L $initdir/$_target ]] && return 0
1331 _realsrc
=$
(readlink
-f "$_src")
1332 if ! [[ -e $initdir/$_realsrc ]]; then
1333 if [[ -d $_realsrc ]]; then
1334 inst_dir
"$_realsrc"
1339 [[ ! -e $initdir/${_target%/*} ]] && inst_dir
"${_target%/*}"
1340 [[ -d ${_target%/*} ]] && _target=$(readlink -f ${_target%/*})/${_target##*/}
1341 ln -sfn $
(convert_abs_rel
"${_target}" "${_realsrc}") "$initdir/$_target"
1344 # attempt to install any programs specified in a udev rule
1345 inst_rule_programs
() {
1348 if grep -qE 'PROGRAM==?"[^ "]+' "$1"; then
1349 for _prog
in $
(grep -E 'PROGRAM==?"[^ "]+' "$1" |
sed -r 's/.*PROGRAM==?"([^ "]+).*/\1/'); do
1350 if [ -x /lib
/udev
/$_prog ]; then
1351 _bin
=/lib
/udev
/$_prog
1353 _bin
=$
(find_binary
"$_prog") ||
{
1354 dinfo
"Skipping program $_prog using in udev rule $(basename $1) as it cannot be found"
1359 #dinfo "Installing $_bin due to it's use in the udev rule $(basename $1)"
1360 dracut_install
"$_bin"
1365 # udev rules always get installed in the same place, so
1366 # create a function to install them to make life simpler.
1368 local _target
=/etc
/udev
/rules.d _rule _found
1370 inst_dir
"/lib/udev/rules.d"
1372 for _rule
in "$@"; do
1373 if [ "${rule#/}" = "$rule" ]; then
1374 for r
in /lib
/udev
/rules.d
/etc
/udev
/rules.d
; do
1375 if [[ -f $r/$_rule ]]; then
1377 inst_simple
"$_found"
1378 inst_rule_programs
"$_found"
1382 for r
in '' .
/ $dracutbasedir/rules.d
/; do
1383 if [[ -f ${r}$_rule ]]; then
1385 inst_simple
"$_found" "$_target/${_found##*/}"
1386 inst_rule_programs
"$_found"
1389 [[ $_found ]] || dinfo
"Skipping udev rule: $_rule"
1394 # general purpose installation function
1395 # Same args as above.
1401 2) [[ ! $initdir && -d $2 ]] && export initdir
=$2
1402 [[ $initdir = $2 ]] && set $1;;
1403 3) [[ -z $initdir ]] && export initdir
=$2
1405 *) dfatal
"inst only takes 1 or 2 or 3 arguments"
1408 for _x
in inst_symlink inst_script inst_binary inst_simple
; do
1409 $_x "$@" && return 0
1414 # install any of listed files
1416 # If first argument is '-d' and second some destination path, first accessible
1417 # source is installed into this path, otherwise it will installed in the same
1418 # path as source. If none of listed files was installed, function return 1.
1419 # On first successful installation it returns with 0 status.
1423 # inst_any -d /bin/foo /bin/bar /bin/baz
1425 # Lets assume that /bin/baz exists, so it will be installed as /bin/foo in
1430 [[ $1 = '-d' ]] && to
="$2" && shift 2
1433 if [[ -e $f ]]; then
1434 [[ $to ]] && inst
"$f" "$to" && return 0
1435 inst
"$f" && return 0
1442 # dracut_install [-o ] <file> [<file> ... ]
1443 # Install <file> to the initramfs image
1444 # -o optionally install the <file> and don't fail, if it is not there
1447 if [[ $1 = '-o' ]]; then
1451 while (($# > 0)); do
1452 if ! inst
"$1" ; then
1453 if [[ $_optional = yes ]]; then
1454 dinfo
"Skipping program $1 as it cannot be found and is" \
1455 "flagged to be optional"
1457 dfatal
"Failed to install $1"
1465 # Install a single kernel module along with any firmware it may require.
1466 # $1 = full path to kernel module to install
1467 install_kmod_with_fw
() {
1468 # no need to go further if the module is already installed
1470 [[ -e "${initdir}/lib/modules/$KERNEL_VER/${1##*/lib/modules/$KERNEL_VER/}" ]] \
1473 [[ -e "$initdir/.kernelmodseen/${1##*/}" ]] && return 0
1475 if [[ $omit_drivers ]]; then
1476 local _kmod
=${1##*/}
1479 if [[ "$_kmod" =~
$omit_drivers ]]; then
1480 dinfo
"Omitting driver $_kmod"
1483 if [[ "${1##*/lib/modules/$KERNEL_VER/}" =~
$omit_drivers ]]; then
1484 dinfo
"Omitting driver $_kmod"
1489 [ -d "$initdir/.kernelmodseen" ] && \
1490 > "$initdir/.kernelmodseen/${1##*/}"
1492 inst_simple
"$1" "/lib/modules/$KERNEL_VER/${1##*/lib/modules/$KERNEL_VER/}" \
1495 local _modname
=${1##*/} _fwdir _found _fw
1496 _modname
=${_modname%.ko*}
1497 for _fw
in $
(modinfo
-k $KERNEL_VER -F firmware
$1 2>/dev
/null
); do
1499 for _fwdir
in $fw_dir; do
1500 if [[ -d $_fwdir && -f $_fwdir/$_fw ]]; then
1501 inst_simple
"$_fwdir/$_fw" "/lib/firmware/$_fw"
1505 if [[ $_found != yes ]]; then
1506 if ! grep -qe "\<${_modname//-/_}\>" /proc
/modules
; then
1507 dinfo
"Possible missing firmware \"${_fw}\" for kernel module" \
1508 "\"${_modname}.ko\""
1510 dwarn
"Possible missing firmware \"${_fw}\" for kernel module" \
1511 "\"${_modname}.ko\""
1518 # Do something with all the dependencies of a kernel module.
1519 # Note that kernel modules depend on themselves using the technique we use
1520 # $1 = function to call for each dependency we find
1521 # It will be passed the full path to the found kernel module
1522 # $2 = module to get dependencies for
1523 # rest of args = arguments to modprobe
1524 # _fderr specifies FD passed from surrounding scope
1525 for_each_kmod_dep
() {
1526 local _func
=$1 _kmod
=$2 _cmd _modpath _options _found
=0
1528 modprobe
"$@" --ignore-install --show-depends $_kmod 2>&${_fderr} |
(
1529 while read _cmd _modpath _options
; do
1530 [[ $_cmd = insmod
]] ||
continue
1531 $_func ${_modpath} ||
exit $?
1534 [[ $_found -eq 0 ]] && exit 1
1539 # filter kernel modules to install certain modules that meet specific
1541 # $1 = search only in subdirectory of /kernel/$1
1542 # $2 = function to call with module name to filter.
1543 # This function will be passed the full path to the module to test.
1544 # The behavior of this function can vary depending on whether $hostonly is set.
1545 # If it is, we will only look at modules that are already in memory.
1546 # If it is not, we will look at all kernel modules
1547 # This function returns the full filenames of modules that match $1
1548 filter_kernel_modules_by_path
() (
1549 local _modname _filtercmd
1550 if ! [[ $hostonly ]]; then
1551 _filtercmd
='find "$KERNEL_MODS/kernel/$1" "$KERNEL_MODS/extra"'
1552 _filtercmd
+=' "$KERNEL_MODS/weak-updates" -name "*.ko" -o -name "*.ko.gz"'
1553 _filtercmd
+=' -o -name "*.ko.xz"'
1554 _filtercmd
+=' 2>/dev/null'
1556 _filtercmd
='cut -d " " -f 1 </proc/modules|xargs modinfo -F filename '
1557 _filtercmd
+='-k $KERNEL_VER 2>/dev/null'
1559 for _modname
in $
(eval $_filtercmd); do
1561 *.ko
) "$2" "$_modname" && echo "$_modname";;
1562 *.ko.gz
) gzip -dc "$_modname" > $initdir/$$.ko
1563 $2 $initdir/$$.ko
&& echo "$_modname"
1564 rm -f $initdir/$$.ko
1566 *.ko.xz
) xz
-dc "$_modname" > $initdir/$$.ko
1567 $2 $initdir/$$.ko
&& echo "$_modname"
1568 rm -f $initdir/$$.ko
1573 find_kernel_modules_by_path
() (
1574 if ! [[ $hostonly ]]; then
1575 find "$KERNEL_MODS/kernel/$1" "$KERNEL_MODS/extra" "$KERNEL_MODS/weak-updates" \
1576 -name "*.ko" -o -name "*.ko.gz" -o -name "*.ko.xz" 2>/dev
/null
1578 cut
-d " " -f 1 </proc
/modules \
1579 |
xargs modinfo
-F filename
-k $KERNEL_VER 2>/dev
/null
1583 filter_kernel_modules
() {
1584 filter_kernel_modules_by_path drivers
"$1"
1587 find_kernel_modules
() {
1588 find_kernel_modules_by_path drivers
1591 # instmods [-c] <kernel module> [<kernel module> ... ]
1592 # instmods [-c] <kernel subsystem>
1593 # install kernel modules along with all their dependencies.
1594 # <kernel subsystem> can be e.g. "=block" or "=drivers/usb/storage"
1596 [[ $no_kernel = yes ]] && return
1597 # called [sub]functions inherit _fderr
1600 if [[ $1 = '-c' ]]; then
1605 function inst1mod
() {
1606 local _ret
=0 _mod
="$1"
1609 if [ -f $KERNEL_MODS/modules.
${_mod#=} ]; then
1610 ( [[ "$_mpargs" ]] && echo $_mpargs
1611 cat "${KERNEL_MODS}/modules.${_mod#=}" ) \
1614 ( [[ "$_mpargs" ]] && echo $_mpargs
1615 find "$KERNEL_MODS" -path "*/${_mod#=}/*" -type f
-printf '%f\n' ) \
1619 --*) _mpargs
+=" $_mod" ;;
1620 i2o_scsi
) return ;; # Do not load this diagnostic-only module
1623 # if we are already installed, skip this module and go on
1625 [[ -f "$initdir/.kernelmodseen/${_mod%.ko}.ko" ]] && return
1627 if [[ $omit_drivers ]] && [[ "$1" =~
$omit_drivers ]]; then
1628 dinfo
"Omitting driver ${_mod##$KERNEL_MODS}"
1631 # If we are building a host-specific initramfs and this
1632 # module is not already loaded, move on to the next one.
1633 [[ $hostonly ]] && ! grep -qe "\<${_mod//-/_}\>" /proc
/modules \
1634 && ! echo $add_drivers |
grep -qe "\<${_mod}\>" \
1637 # We use '-d' option in modprobe only if modules prefix path
1638 # differs from default '/'. This allows us to use Dracut with
1639 # old version of modprobe which doesn't have '-d' option.
1640 local _moddirname
=${KERNEL_MODS%%/lib/modules/*}
1641 [[ -n ${_moddirname} ]] && _moddirname
="-d ${_moddirname}/"
1643 # ok, load the module, all its dependencies, and any firmware
1645 for_each_kmod_dep install_kmod_with_fw
$_mod \
1646 --set-version $KERNEL_VER ${_moddirname} $_mpargs
1653 function instmods_1
() {
1655 if (($# == 0)); then # filenames from stdin
1657 inst1mod
"${_mod%.ko*}" ||
{
1658 if [ "$_check" = "yes" ]; then
1659 dfatal
"Failed to install $_mod"
1665 while (($# > 0)); do # filenames as arguments
1666 inst1mod
${1%.ko*} ||
{
1667 if [ "$_check" = "yes" ]; then
1668 dfatal
"Failed to install $1"
1677 local _ret _filter_not_found
='FATAL: Module .* not found.'
1679 # Capture all stderr from modprobe to _fderr. We could use {var}>...
1680 # redirections, but that would make dracut require bash4 at least.
1681 eval "( instmods_1 \"\$@\" ) ${_fderr}>&1" \
1682 |
while read line
; do [[ "$line" =~
$_filter_not_found ]] && echo $line ||
echo $line >&2 ;done | derror
1689 ln -fs ..
/usr
/bin
/systemctl
$initdir/bin
/
1690 ln -fs ..
/usr
/lib
/systemd
$initdir/lib
/
1691 inst_simple
"/usr/lib/systemd/system/haveged.service"
1695 if mountpoint
-q $1; then
1701 _test_setup_cleanup
() {
1702 # only umount if create_empty_image_rootdir() was called to mount it
1703 [[ -z $TEST_SETUP_CLEANUP_ROOTDIR ]] || _umount_dir
$initdir
1706 # can be overridden in specific test
1707 test_setup_cleanup
() {
1712 # (post-test) cleanup should always ignore failure and cleanup as much as possible
1715 _umount_dir
$initdir
1716 if [[ $LOOPDEV && -b $LOOPDEV ]]; then
1717 ddebug
"losetup -d $LOOPDEV"
1725 # can be overridden in specific test
1731 if [ -z "$TEST_NO_QEMU" ]; then
1733 check_result_qemu ||
return 1
1735 dwarn
"can't run QEMU, skipping"
1738 if [ -z "$TEST_NO_NSPAWN" ]; then
1739 if run_nspawn
"nspawn-root"; then
1740 check_result_nspawn
"nspawn-root" ||
return 1
1742 dwarn
"can't run systemd-nspawn, skipping"
1745 if [[ "$RUN_IN_UNPRIVILEGED_CONTAINER" = "yes" ]]; then
1746 if NSPAWN_ARGUMENTS
="-U --private-network $NSPAWN_ARGUMENTS" run_nspawn
"unprivileged-nspawn-root"; then
1747 check_result_nspawn
"unprivileged-nspawn-root" ||
return 1
1749 dwarn
"can't run systemd-nspawn, skipping"
1757 if [[ $UID != "0" ]]; then
1758 echo "TEST: $TEST_DESCRIPTION [SKIPPED]: not root" >&2
1763 [[ $libdir ]] ||
for libdir
in /lib64
/lib
; do
1764 [[ -d $libdir ]] && libdirs
+=" $libdir" && break
1767 [[ $usrlibdir ]] ||
for usrlibdir
in /usr
/lib64
/usr
/lib
; do
1768 [[ -d $usrlibdir ]] && libdirs
+=" $usrlibdir" && break
1771 mkdir
-p "$STATEDIR"
1776 while (($# > 0)); do
1779 echo "TEST RUN: $TEST_DESCRIPTION"
1782 if (( $ret == 0 )); then
1783 echo "TEST RUN: $TEST_DESCRIPTION [OK]"
1785 echo "TEST RUN: $TEST_DESCRIPTION [FAILED]"
1789 echo "TEST SETUP: $TEST_DESCRIPTION"
1794 echo "TEST CLEANUP: $TEST_DESCRIPTION"
1799 echo -n "TEST: $TEST_DESCRIPTION "
1804 ) </dev
/null
>"$TESTLOG" 2>&1 || ret
=$?
1806 if [ $ret -eq 0 ]; then