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
="${EFI_MOUNT:-$(bootctl -x 2>/dev/null || echo /boot)}"
18 QEMU_MEM
="${QEMU_MEM:-512M}"
20 # Decide if we can (and want to) run QEMU with KVM acceleration.
21 # Check if nested KVM is explicitly enabled (TEST_NESTED_KVM). If not,
22 # check if it's not explicitly disabled (TEST_NO_KVM) and we're not already
23 # running under KVM. If these conditions are met, enable KVM (and possibly
24 # nested KVM), otherwise disable it.
25 if [[ -n "$TEST_NESTED_KVM" ||
( -z "$TEST_NO_KVM" && $
(systemd-detect-virt
-v) != kvm
) ]]; then
31 if ! ROOTLIBDIR
=$
(pkg-config
--variable=systemdutildir systemd
); then
32 echo "WARNING! Cannot determine rootlibdir from pkg-config, assuming /usr/lib/systemd" >&2
33 ROOTLIBDIR
=/usr
/lib
/systemd
36 PATH_TO_INIT
=$ROOTLIBDIR/systemd
37 [ "$SYSTEMD_JOURNALD" ] || SYSTEMD_JOURNALD
=$
(which -a $BUILD_DIR/systemd-journald
$ROOTLIBDIR/systemd-journald
2>/dev
/null |
grep '^/' -m1)
38 [ "$SYSTEMD" ] || SYSTEMD
=$
(which -a $BUILD_DIR/systemd
$ROOTLIBDIR/systemd
2>/dev
/null |
grep '^/' -m1)
39 [ "$SYSTEMD_NSPAWN" ] || SYSTEMD_NSPAWN
=$
(which -a $BUILD_DIR/systemd-nspawn systemd-nspawn
2>/dev
/null |
grep '^/' -m1)
40 [ "$JOURNALCTL" ] || JOURNALCTL
=$
(which -a $BUILD_DIR/journalctl journalctl
2>/dev
/null |
grep '^/' -m1)
42 BASICTOOLS
="test env sh bash setsid loadkeys setfont login sulogin gzip sleep echo head tail cat mount umount cryptsetup date dmsetup modprobe sed cmp tee rm true false chmod chown ln xargs"
43 DEBUGTOOLS
="df free ls stty ps ln ip route dmesg dhclient mkdir cp ping dhclient strace less grep id tty touch du sort hostname find vi mv"
45 STATEDIR
="${BUILD_DIR:-.}/test/$(basename $(dirname $(realpath $0)))"
46 STATEFILE
="$STATEDIR/.testdir"
47 TESTLOG
="$STATEDIR/test.log"
49 is_built_with_asan
() {
50 if ! type -P objdump
>/dev
/null
; then
51 ddebug
"Failed to find objdump. Assuming systemd hasn't been built with ASAN."
55 # Borrowed from https://github.com/google/oss-fuzz/blob/cd9acd02f9d3f6e80011cc1e9549be526ce5f270/infra/base-images/base-runner/bad_build_check#L182
56 local _asan_calls
=$
(objdump
-dC $SYSTEMD_JOURNALD |
egrep "callq\s+[0-9a-f]+\s+<__asan" -c)
57 if (( $_asan_calls < 1000 )); then
64 IS_BUILT_WITH_ASAN
=$
(is_built_with_asan
&& echo yes ||
echo no
)
66 if [[ "$IS_BUILT_WITH_ASAN" = "yes" ]]; then
68 SKIP_INITRD
="${SKIP_INITRD:-yes}"
69 PATH_TO_INIT
=$ROOTLIBDIR/systemd-under-asan
73 # We need to correctly distinguish between gcc's and clang's ASan DSOs.
74 if ldd
$SYSTEMD |
grep -q libasan.so
; then
76 elif ldd
$SYSTEMD |
grep -q libclang_rt.asan
; then
79 # As clang's ASan DSO is usually in a non-standard path, let's check if
80 # the environment is set accordingly. If not, warn the user and exit.
81 # We're not setting the LD_LIBRARY_PATH automagically here, because
82 # user should encounter (and fix) the same issue when running the unit
84 if ldd
"$SYSTEMD" |
grep -q "libclang_rt.asan.*not found"; then
85 _asan_rt_name
="$(ldd $SYSTEMD | awk '/libclang_rt.asan/ {print $1; exit}')"
86 _asan_rt_path
="$(find /usr/lib* /usr/local/lib* -type f -name "$_asan_rt_name" 2>/dev/null | sed 1q)"
87 echo >&2 "clang's ASan DSO ($_asan_rt_name) is not present in the runtime library path"
88 echo >&2 "Consider setting LD_LIBRARY_PATH=${_asan_rt_path%/*}"
92 echo >&2 "systemd is not linked against the ASan DSO"
93 echo >&2 "gcc does this by default, for clang compile with -shared-libasan"
98 function find_qemu_bin
() {
99 # SUSE and Red Hat call the binary qemu-kvm. Debian and Gentoo call it kvm.
100 if [[ $QEMU_KVM == "yes" ]]; then
101 [ "$QEMU_BIN" ] || QEMU_BIN
=$
(which -a kvm qemu-kvm
2>/dev
/null |
grep '^/' -m1)
104 [ "$ARCH" ] || ARCH
=$
(uname
-m)
107 # QEMU's own build system calls it qemu-system-x86_64
108 [ "$QEMU_BIN" ] || QEMU_BIN
=$
(which -a qemu-system-x86_64
2>/dev
/null |
grep '^/' -m1)
111 # new i386 version of QEMU
112 [ "$QEMU_BIN" ] || QEMU_BIN
=$
(which -a qemu-system-i386
2>/dev
/null |
grep '^/' -m1)
114 # i386 version of QEMU
115 [ "$QEMU_BIN" ] || QEMU_BIN
=$
(which -a qemu
2>/dev
/null |
grep '^/' -m1)
118 [ "$QEMU_BIN" ] || QEMU_BIN
=$
(which -a qemu-system-ppc64
2>/dev
/null |
grep '^/' -m1)
122 if [ ! -e "$QEMU_BIN" ]; then
123 echo "Could not find a suitable QEMU binary" >&2
128 # Return 0 if QEMU did run (then you must check the result state/logs for actual
129 # success), or 1 if QEMU is not available.
131 if [ -f /etc
/machine-id
]; then
132 read MACHINE_ID
< /etc
/machine-id
133 [ -z "$INITRD" ] && [ -e "$EFI_MOUNT/$MACHINE_ID/$KERNEL_VER/initrd" ] \
134 && INITRD
="$EFI_MOUNT/$MACHINE_ID/$KERNEL_VER/initrd"
135 [ -z "$KERNEL_BIN" ] && [ -e "$EFI_MOUNT/$MACHINE_ID/$KERNEL_VER/linux" ] \
136 && KERNEL_BIN
="$EFI_MOUNT/$MACHINE_ID/$KERNEL_VER/linux"
141 if [[ ! "$KERNEL_BIN" ]]; then
142 if [[ "$LOOKS_LIKE_ARCH" ]]; then
143 KERNEL_BIN
=/boot
/vmlinuz-linux
145 [ "$ARCH" ] || ARCH
=$
(uname
-m)
148 KERNEL_BIN
=/boot
/vmlinux-
$KERNEL_VER
152 KERNEL_BIN
=/boot
/vmlinuz-
$KERNEL_VER
158 default_fedora_initrd
=/boot
/initramfs-
${KERNEL_VER}.img
159 default_debian_initrd
=/boot
/initrd.img-
${KERNEL_VER}
160 default_arch_initrd
=/boot
/initramfs-linux-fallback.img
161 default_suse_initrd
=/boot
/initrd-
${KERNEL_VER}
162 if [[ ! "$INITRD" ]]; then
163 if [[ -e "$default_fedora_initrd" ]]; then
164 INITRD
="$default_fedora_initrd"
165 elif [[ "$LOOKS_LIKE_DEBIAN" && -e "$default_debian_initrd" ]]; then
166 INITRD
="$default_debian_initrd"
167 elif [[ "$LOOKS_LIKE_ARCH" && -e "$default_arch_initrd" ]]; then
168 INITRD
="$default_arch_initrd"
169 elif [[ "$LOOKS_LIKE_SUSE" && -e "$default_suse_initrd" ]]; then
170 INITRD
="$default_suse_initrd"
174 # If QEMU_SMP was not explicitly set, try to determine the value 'dynamically'
175 # i.e. use the number of online CPUs on the host machine. If the nproc utility
176 # is not installed or there's some other error when calling it, fall back
177 # to the original value (QEMU_SMP=1).
178 if ! [ "$QEMU_SMP" ]; then
179 if ! QEMU_SMP
=$
(nproc
); then
180 dwarn
"nproc utility is not installed, falling back to QEMU_SMP=1"
185 find_qemu_bin ||
return 1
188 if [[ "$UNIFIED_CGROUP_HIERARCHY" = "yes" ]]; then
189 _cgroup_args
="systemd.unified_cgroup_hierarchy=yes"
190 elif [[ "$UNIFIED_CGROUP_HIERARCHY" = "no" ]]; then
191 _cgroup_args
="systemd.unified_cgroup_hierarchy=no systemd.legacy_systemd_cgroup_controller=yes"
192 elif [[ "$UNIFIED_CGROUP_HIERARCHY" = "hybrid" ]]; then
193 _cgroup_args
="systemd.unified_cgroup_hierarchy=no systemd.legacy_systemd_cgroup_controller=no"
194 elif [[ "$UNIFIED_CGROUP_HIERARCHY" != "default" ]]; then
195 dfatal
"Unknown UNIFIED_CGROUP_HIERARCHY. Got $UNIFIED_CGROUP_HIERARCHY, expected [yes|no|hybrid|default]"
199 if [[ "$LOOKS_LIKE_SUSE" ]]; then
200 PARAMS
+="rd.hostonly=0"
201 elif [[ "$LOOKS_LIKE_ARCH" ]]; then
208 if [[ ! "$INTERACTIVE_DEBUG" ]]; then
209 _end
="systemd.wants=end.service"
214 KERNEL_APPEND
="$PARAMS \
223 SYSTEMD_UNIT_PATH=/usr/lib/systemd/tests/testdata/testsuite-$1.units:/usr/lib/systemd/tests/testdata/units: \
224 systemd.unit=testsuite.target \
225 systemd.wants=testsuite-$1.service ${_end}
229 QEMU_OPTIONS
="-smp $QEMU_SMP \
233 -kernel $KERNEL_BIN \
234 -drive format=raw,cache=unsafe,file=${TESTDIR}/rootdisk.img \
238 if [[ "$INITRD" && "$SKIP_INITRD" != "yes" ]]; then
239 QEMU_OPTIONS
="$QEMU_OPTIONS -initrd $INITRD"
242 # Let's use KVM if possible
243 if [[ -c /dev
/kvm
&& $QEMU_KVM == "yes" ]]; then
244 QEMU_OPTIONS
="$QEMU_OPTIONS -machine accel=kvm -enable-kvm -cpu host"
247 if [[ "$QEMU_TIMEOUT" != "infinity" ]]; then
248 QEMU_BIN
="timeout --foreground $QEMU_TIMEOUT $QEMU_BIN"
250 (set -x; $QEMU_BIN $QEMU_OPTIONS -append "$KERNEL_APPEND")
252 if [ "$rc" = 124 ] && [ "$QEMU_TIMEOUT" != "infinity" ]; then
253 derror
"test timed out after $QEMU_TIMEOUT s"
256 [ "$rc" != 0 ] && derror
"QEMU failed with exit code $rc"
261 # Return 0 if nspawn did run (then you must check the result state/logs for actual
262 # success), or 1 if nspawn is not available.
264 [[ -d /run
/systemd
/system
]] ||
return 1
268 --kill-signal=SIGKILL
269 --directory=$TESTDIR/$1
270 --setenv=SYSTEMD_UNIT_PATH
=/usr
/lib
/systemd
/tests
/testdata
/testsuite-
$2.units
:/usr
/lib
/systemd
/tests
/testdata
/units
:
273 systemd.unit
=testsuite.target
274 systemd.wants
=testsuite-
$2.service
277 if [[ ! "$INTERACTIVE_DEBUG" ]]; then
278 _nspawn_cmd
+=( systemd.wants
=end.service
)
282 if [[ "$NSPAWN_TIMEOUT" != "infinity" ]]; then
283 _nspawn_pre
=(timeout
--foreground $NSPAWN_TIMEOUT)
288 if [[ "$UNIFIED_CGROUP_HIERARCHY" = "hybrid" ]]; then
289 dwarn
"nspawn doesn't support SYSTEMD_NSPAWN_UNIFIED_HIERARCHY=hybrid, skipping"
291 elif [[ "$UNIFIED_CGROUP_HIERARCHY" = "yes" ||
"$UNIFIED_CGROUP_HIERARCHY" = "no" ]]; then
292 _nspawn_pre
=("${nspawn_pre[@]}" env SYSTEMD_NSPAWN_UNIFIED_HIERARCHY
=$UNIFIED_CGROUP_HIERARCHY)
293 elif [[ "$UNIFIED_CGROUP_HIERARCHY" = "default" ]]; then
294 _nspawn_pre
=("${nspawn_pre[@]}" env
--unset=UNIFIED_CGROUP_HIERARCHY
--unset=SYSTEMD_NSPAWN_UNIFIED_HIERARCHY
)
296 dfatal
"Unknown UNIFIED_CGROUP_HIERARCHY. Got $UNIFIED_CGROUP_HIERARCHY, expected [yes|no|hybrid|default]"
300 (set -x; "${_nspawn_pre[@]}" "$SYSTEMD_NSPAWN" $NSPAWN_ARGUMENTS "${_nspawn_cmd[@]}")
302 if [ "$rc" = 124 ] && [ "$NSPAWN_TIMEOUT" != "infinity" ]; then
303 derror
"test timed out after $NSPAWN_TIMEOUT s"
306 [ "$rc" != 0 ] && derror
"nspawn failed with exit code $rc"
311 setup_basic_environment
() {
312 # create the basic filesystem layout
316 install_missing_libraries
334 generate_module_dependencies
335 if [[ "$IS_BUILT_WITH_ASAN" = "yes" ]]; then
341 # don't forget KERNEL_APPEND='... selinux=1 ...'
342 if [[ "$SETUP_SELINUX" != "yes" ]]; then
343 ddebug
"Don't setup SELinux"
346 ddebug
"Setup SELinux"
347 local _conf_dir
=/etc
/selinux
348 local _fixfiles_tools
="bash uname cat sort uniq awk grep egrep head expr find rm secon setfiles"
350 rm -rf $initdir/$_conf_dir
351 if ! cp -ar $_conf_dir $initdir/$_conf_dir; then
352 dfatal
"Failed to copy $_conf_dir"
356 touch $initdir/.autorelabel
357 mkdir
-p $initdir/usr
/lib
/systemd
/tests
/testdata
/units
/basic.target.wants
358 ln -sf ..
/autorelabel.service
$initdir/usr
/lib
/systemd
/tests
/testdata
/units
/basic.target.wants
/
360 dracut_install
$_fixfiles_tools
361 dracut_install fixfiles
362 dracut_install sestatus
366 if ! type -p valgrind
; then
367 dfatal
"Failed to install valgrind"
371 local _valgrind_bins
=$
(strace
-e execve valgrind
/bin
/true
2>&1 >/dev
/null | perl
-lne 'print $1 if /^execve\("([^"]+)"/')
372 dracut_install
$_valgrind_bins
374 local _valgrind_libs
=$
(LD_DEBUG
=files valgrind
/bin
/true
2>&1 >/dev
/null | perl
-lne 'print $1 if m{calling init: (/.*vgpreload_.*)}')
375 dracut_install
$_valgrind_libs
377 local _valgrind_dbg_and_supp
=$
(
378 strace
-e open valgrind
/bin
/true
2>&1 >/dev
/null |
379 perl
-lne 'if (my ($fname) = /^open\("([^"]+).*= (?!-)\d+/) { print $fname if $fname =~ /debug|\.supp$/ }'
381 dracut_install
$_valgrind_dbg_and_supp
384 create_valgrind_wrapper
() {
385 local _valgrind_wrapper
=$initdir/$ROOTLIBDIR/systemd-under-valgrind
386 ddebug
"Create $_valgrind_wrapper"
387 cat >$_valgrind_wrapper <<EOF
390 mount -t proc proc /proc
391 exec valgrind --leak-check=full --log-file=/valgrind.out $ROOTLIBDIR/systemd "\$@"
393 chmod 0755 $_valgrind_wrapper
396 create_asan_wrapper
() {
397 local _asan_wrapper
=$initdir/$ROOTLIBDIR/systemd-under-asan
398 local _asan_rt_pattern
399 ddebug
"Create $_asan_wrapper"
401 case "$ASAN_COMPILER" in
403 _asan_rt_pattern
="*libasan*"
406 _asan_rt_pattern
="libclang_rt.asan-*"
407 # Install llvm-symbolizer to generate useful reports
408 # See: https://clang.llvm.org/docs/AddressSanitizer.html#symbolizing-the-reports
409 dracut_install
"llvm-symbolizer"
412 dfail
"Unsupported compiler: $ASAN_COMPILER"
416 cat >$_asan_wrapper <<EOF
421 DEFAULT_ASAN_OPTIONS=${ASAN_OPTIONS:-strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1}
422 DEFAULT_UBSAN_OPTIONS=${UBSAN_OPTIONS:-print_stacktrace=1:print_summary=1:halt_on_error=1}
423 DEFAULT_ENVIRONMENT="ASAN_OPTIONS=\$DEFAULT_ASAN_OPTIONS UBSAN_OPTIONS=\$DEFAULT_UBSAN_OPTIONS"
425 # As right now bash is the PID 1, we can't expect PATH to have a sane value.
426 # Let's make one to prevent unexpected "<bin> not found" issues in the future
427 export PATH="/sbin:/bin:/usr/sbin:/usr/bin"
429 mount -t proc proc /proc
430 mount -t sysfs sysfs /sys
431 mount -o remount,rw /
433 PATH_TO_ASAN=\$(find / -name '$_asan_rt_pattern' | sed 1q)
434 if [[ "\$PATH_TO_ASAN" ]]; then
435 # A lot of services (most notably dbus) won't start without preloading libasan
436 # See https://github.com/systemd/systemd/issues/5004
437 DEFAULT_ENVIRONMENT="\$DEFAULT_ENVIRONMENT LD_PRELOAD=\$PATH_TO_ASAN"
438 # Let's add the ASan DSO's path to the dynamic linker's cache. This is pretty
439 # unnecessary for gcc & libasan, however, for clang this is crucial, as its
440 # runtime ASan DSO is in a non-standard (library) path.
441 echo \${PATH_TO_ASAN%/*} > /etc/ld.so.conf.d/asan-path-override.conf
444 echo DefaultEnvironment=\$DEFAULT_ENVIRONMENT >>/etc/systemd/system.conf
445 echo DefaultTimeoutStartSec=180s >>/etc/systemd/system.conf
446 echo DefaultStandardOutput=journal+console >>/etc/systemd/system.conf
448 # ASAN and syscall filters aren't compatible with each other.
449 find / -name '*.service' -type f | xargs sed -i 's/^\\(MemoryDeny\\|SystemCall\\)/#\\1/'
451 # The redirection of ASAN reports to a file prevents them from ending up in /dev/null.
452 # But, apparently, sometimes it doesn't work: https://github.com/google/sanitizers/issues/886.
453 JOURNALD_CONF_DIR=/etc/systemd/system/systemd-journald.service.d
454 mkdir -p "\$JOURNALD_CONF_DIR"
455 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"
457 # Sometimes UBSan sends its reports to stderr regardless of what is specified in log_path
458 # Let's try to catch them by redirecting stderr (and stdout just in case) to a file
459 # See https://github.com/systemd/systemd/pull/12524#issuecomment-491108821
460 printf "[Service]\nStandardOutput=file:/systemd-journald.out\n" >"\$JOURNALD_CONF_DIR/out.conf"
462 # 90s isn't enough for some services to finish when literally everything is run
463 # under ASan+UBSan in containers, which, in turn, are run in VMs.
464 # Let's limit which environments such services should be executed in.
465 mkdir -p /etc/systemd/system/systemd-hwdb-update.service.d
466 printf "[Unit]\nConditionVirtualization=container\n\n[Service]\nTimeoutSec=180s\n" >/etc/systemd/system/systemd-hwdb-update.service.d/env-override.conf
468 # Let's override another hard-coded timeout that kicks in too early
469 mkdir -p /etc/systemd/system/systemd-journal-flush.service.d
470 printf "[Service]\nTimeoutSec=180s\n" >/etc/systemd/system/systemd-journal-flush.service.d/timeout.conf
472 # The 'mount' utility doesn't behave well under libasan, causing unexpected
473 # fails during boot and subsequent test results check:
474 # bash-5.0# mount -o remount,rw -v /
475 # mount: /dev/sda1 mounted on /.
478 # Let's workaround this by clearing the previously set LD_PRELOAD env variable,
479 # so the libasan library is not loaded for this particular service
481 local _dropin_dir="/etc/systemd/system/\$1.service.d"
482 mkdir -p "\$_dropin_dir"
483 printf "[Service]\nUnsetEnvironment=LD_PRELOAD\n" >"\$_dropin_dir/unset_ld_preload.conf"
486 unset_ld_preload systemd-remount-fs
487 unset_ld_preload testsuite-
489 export ASAN_OPTIONS=\$DEFAULT_ASAN_OPTIONS:log_path=/systemd.asan.log UBSAN_OPTIONS=\$DEFAULT_UBSAN_OPTIONS
490 exec $ROOTLIBDIR/systemd "\$@"
493 chmod 0755 $_asan_wrapper
496 create_strace_wrapper
() {
497 local _strace_wrapper
=$initdir/$ROOTLIBDIR/systemd-under-strace
498 ddebug
"Create $_strace_wrapper"
499 cat >$_strace_wrapper <<EOF
502 exec strace -D -o /strace.out $ROOTLIBDIR/systemd "\$@"
504 chmod 0755 $_strace_wrapper
508 dracut_install
/sbin
/fsck
*
509 dracut_install
-o /bin
/fsck
*
511 # fskc.reiserfs calls reiserfsck. so, install it
512 dracut_install
-o reiserfsck
516 instmods dm_crypt
=crypto
518 if [[ "$LOOKS_LIKE_DEBIAN" ]]; then
519 # dmsetup installs 55-dm and 60-persistent-storage-dm on Debian/Ubuntu
520 # and since buster/bionic 95-dm-notify.rules
521 # see https://gitlab.com/debian-lvm/lvm2/blob/master/debian/patches/udev.patch
522 inst_rules
55-dm.rules
60-persistent-storage-dm.rules
95-dm-notify.rules
524 inst_rules
10-dm.rules
13-dm-disk.rules
95-dm-notify.rules
529 # install compiled files
530 local _ninja_bin
=$
(type -P ninja ||
type -P ninja-build
)
531 if [[ -z "$_ninja_bin" ]]; then
532 dfatal
"ninja was not found"
535 (set -x; DESTDIR
=$initdir "$_ninja_bin" -C $BUILD_DIR install)
536 # remove unneeded documentation
537 rm -fr $initdir/usr
/share
/{man
,doc
}
538 # we strip binaries since debug symbols increase binaries size a lot
539 # and it could fill the available space
542 [[ "$LOOKS_LIKE_SUSE" ]] && setup_suse
544 # enable debug logging in PID1
545 echo LogLevel
=debug
>> $initdir/etc
/systemd
/system.conf
546 # store coredumps in journal
547 echo Storage
=journal
>> $initdir/etc
/systemd
/coredump.conf
552 local rpath
=$
(objdump
-p "$_bin" 2>/dev
/null |
awk "/R(UN)?PATH/ { print \"$initdir\" \$2 }" |
paste -sd :)
554 if [ -z "$rpath" ] ; then
561 install_missing_libraries
() {
562 # install possible missing libraries
563 for i
in $initdir{,/usr
}/{sbin
,bin
}/* $initdir{,/usr
}/lib
/systemd
/{,tests
/{,manual
/,unsafe
/}}*; do
564 LD_LIBRARY_PATH
="${LD_LIBRARY_PATH:+$LD_LIBRARY_PATH:}$(get_ldpath $i)" inst_libs
$i
568 create_empty_image
() {
570 if [[ "$STRIP_BINARIES" = "no" ]]; then
573 rm -f "$TESTDIR/rootdisk.img"
574 # Create the blank file to use as a root filesystem
575 truncate
-s "${_size}M" "$TESTDIR/rootdisk.img"
576 LOOPDEV
=$
(losetup
--show -P -f $TESTDIR/rootdisk.img
)
577 [ -b "$LOOPDEV" ] ||
return 1
578 echo "LOOPDEV=$LOOPDEV" >> $STATEFILE
579 sfdisk
"$LOOPDEV" <<EOF
586 local _label
="-L systemd"
587 # mkfs.reiserfs doesn't know -L. so, use --label instead
588 [[ "$FSTYPE" == "reiserfs" ]] && _label
="--label systemd"
589 if ! mkfs
-t "${FSTYPE}" ${_label} "${LOOPDEV}p1" -q; then
590 dfatal
"Failed to mkfs -t ${FSTYPE}"
595 create_empty_image_rootdir
() {
598 mount
${LOOPDEV}p1
$initdir
599 TEST_SETUP_CLEANUP_ROOTDIR
=1
602 check_asan_reports
() {
606 if [[ "$IS_BUILT_WITH_ASAN" = "yes" ]]; then
608 if [[ -e "$root/systemd.asan.log.1" ]]; then
609 cat "$root/systemd.asan.log.1"
613 journald_report
=$
(find "$root" -name "systemd-journald.*san.log*" -exec cat {} \
;)
614 if [[ ! -z "$journald_report" ]]; then
615 printf "%s\n" "$journald_report"
616 cat "$root/systemd-journald.out" ||
:
621 "$JOURNALCTL" -D "$root/var/log/journal" | perl
-alne '
623 %services_to_ignore = (
624 "dbus-daemon" => undef,
627 print $2 if /\s(\S*)\[(\d+)\]:\s*SUMMARY:\s+\w+Sanitizer/ && !exists $services_to_ignore{$1}'
629 if [[ ! -z "$pids" ]]; then
632 "$JOURNALCTL" -D "$root/var/log/journal" _PID
=$pid --no-pager
640 check_result_nspawn
() {
642 local journald_report
=""
644 [[ -e $TESTDIR/$1/testok
]] && ret
=0
645 [[ -f $TESTDIR/$1/failed
]] && cp -a $TESTDIR/$1/failed
$TESTDIR
646 cp -a $TESTDIR/$1/var
/log
/journal
$TESTDIR
647 [[ -f $TESTDIR/failed
]] && cat $TESTDIR/failed
648 ls -l $TESTDIR/journal
/*/*.journal
649 test -s $TESTDIR/failed
&& ret
=$
(($ret+1))
650 [ -n "$TIMED_OUT" ] && ret
=$
(($ret+1))
651 check_asan_reports
"$TESTDIR/$1" || ret
=$
(($ret+1))
655 # can be overridden in specific test
656 check_result_qemu
() {
659 mount
${LOOPDEV}p1
$initdir
660 [[ -e $initdir/testok
]] && ret
=0
661 [[ -f $initdir/failed
]] && cp -a $initdir/failed
$TESTDIR
662 cp -a $initdir/var
/log
/journal
$TESTDIR
663 check_asan_reports
"$initdir" || ret
=$
(($ret+1))
665 [[ -f $TESTDIR/failed
]] && cat $TESTDIR/failed
666 ls -l $TESTDIR/journal
/*/*.journal
667 test -s $TESTDIR/failed
&& ret
=$
(($ret+1))
668 [ -n "$TIMED_OUT" ] && ret
=$
(($ret+1))
673 if [[ "$STRIP_BINARIES" = "no" ]]; then
674 ddebug
"Don't strip binaries"
677 ddebug
"Strip binaries"
678 find "$initdir" -executable -not -path '*/lib/modules/*.ko' -type f | \
679 xargs strip
--strip-unneeded |
& \
680 grep -vi 'file format not recognized' | \
685 mkdir
-p $initdir/etc
/rc.d
686 cat >$initdir/etc
/rc.d
/rc.
local <<EOF
690 chmod 0755 $initdir/etc
/rc.d
/rc.
local
694 ddebug
"install any Execs from the service files"
696 export PKG_CONFIG_PATH
=$BUILD_DIR/src
/core
/
697 systemdsystemunitdir
=$
(pkg-config
--variable=systemdsystemunitdir systemd
)
698 systemduserunitdir
=$
(pkg-config
--variable=systemduserunitdir systemd
)
699 sed -r -n 's|^Exec[a-zA-Z]*=[@+!-]*([^ ]+).*|\1|gp' $initdir/{$systemdsystemunitdir,$systemduserunitdir}/*.service \
700 |
sort -u |
while read i
; do
701 # some {rc,halt}.local scripts and programs are okay to not exist, the rest should
702 # also, plymouth is pulled in by rescue.service, but even there the exit code
703 # is ignored; as it's not present on some distros, don't fail if it doesn't exist
704 dinfo
"Attempting to install $i"
705 inst
$i ||
[ "${i%.local}" != "$i" ] ||
[ "${i%systemd-update-done}" != "$i" ] ||
[ "/bin/plymouth" == "$i" ]
710 generate_module_dependencies
() {
711 if [[ -d $initdir/lib
/modules
/$KERNEL_VER ]] && \
712 ! depmod
-a -b "$initdir" $KERNEL_VER; then
713 dfatal
"\"depmod -a $KERNEL_VER\" failed."
718 install_depmod_files
() {
719 inst
/lib
/modules
/$KERNEL_VER/modules.order
720 inst
/lib
/modules
/$KERNEL_VER/modules.
builtin
724 # install plymouth, if found... else remove plymouth service files
725 # if [ -x /usr/libexec/plymouth/plymouth-populate-initrd ]; then
726 # PLYMOUTH_POPULATE_SOURCE_FUNCTIONS="$TEST_BASE_DIR/test-functions" \
727 # /usr/libexec/plymouth/plymouth-populate-initrd -t $initdir
728 # dracut_install plymouth plymouthd
730 rm -f $initdir/{usr
/lib
,etc
}/systemd
/system
/plymouth
* $initdir/{usr
/lib
,etc
}/systemd
/system
/*/plymouth
*
734 install_ld_so_conf
() {
735 cp -a /etc
/ld.so.conf
* $initdir/etc
736 ldconfig
-r "$initdir"
739 install_config_files
() {
740 inst
/etc
/sysconfig
/init ||
:
746 inst
/etc
/nsswitch.conf
747 inst
/etc
/pam.conf ||
:
750 # we want an empty environment
751 > $initdir/etc
/environment
752 > $initdir/etc
/machine-id
754 echo systemd-testsuite
> $initdir/etc
/hostname
756 if [[ "$LOOKS_LIKE_SUSE" ]]; then
757 ROOTMOUNT
="/dev/sda1 / ${FSTYPE} rw 0 1"
759 ROOTMOUNT
="LABEL=systemd / ${FSTYPE} rw 0 1"
762 cat >$initdir/etc
/fstab
<<EOF
767 install_basic_tools
() {
768 [[ $BASICTOOLS ]] && dracut_install
$BASICTOOLS
769 dracut_install
-o sushell
770 # in Debian ldconfig is just a shell script wrapper around ldconfig.real
771 dracut_install
-o ldconfig.real
774 install_debug_tools
() {
775 [[ $DEBUGTOOLS ]] && dracut_install
$DEBUGTOOLS
777 if [[ $INTERACTIVE_DEBUG ]]; then
778 # Set default TERM from vt220 to linux, so at least basic key shortcuts work
779 local _getty_override
="$initdir/etc/systemd/system/serial-getty@.service.d"
780 mkdir
-p "$_getty_override"
781 echo -e "[Service]\nEnvironment=TERM=linux" > "$_getty_override/default-TERM.conf"
783 cat > "$initdir/etc/motd" << EOF
784 To adjust the terminal size use:
794 # install libnss_files for login
795 NSS_LIBS
=$
(LD_DEBUG
=files getent passwd
2>&1 >/dev
/null |
sed -n '/calling init: .*libnss_/ {s!^.* /!/!; p}')
796 dracut_install
$NSS_LIBS
800 inst
$ROOTLIBDIR/system
/dbus.socket
802 # Newer Fedora versions use dbus-broker by default. Let's install it if it's available.
803 if [ -f $ROOTLIBDIR/system
/dbus-broker.service
]; then
804 inst
$ROOTLIBDIR/system
/dbus-broker.service
805 inst_symlink
/etc
/systemd
/system
/dbus.service
806 inst
/usr
/bin
/dbus-broker
807 inst
/usr
/bin
/dbus-broker-launch
808 elif [ -f $ROOTLIBDIR/system
/dbus-daemon.service
]; then
809 # Fedora rawhide replaced dbus.service with dbus-daemon.service
810 inst
$ROOTLIBDIR/system
/dbus-daemon.service
812 inst_symlink
/etc
/systemd
/system
/dbus.service
814 inst
$ROOTLIBDIR/system
/dbus.service
818 /etc
/dbus-1
/usr
/share
/dbus-1
-xtype f \
819 |
while read file; do
824 install_user_dbus
() {
825 inst
$ROOTLIBDIR/user
/dbus.socket
826 inst_symlink
/usr
/lib
/systemd
/user
/sockets.target.wants
/dbus.socket || inst_symlink
/etc
/systemd
/user
/sockets.target.wants
/dbus.socket
828 # Append the After= dependency on dbus in case it isn't already set up
829 mkdir
-p "$initdir/etc/systemd/system/user@.service.d/"
830 cat <<EOF >"$initdir/etc/systemd/system/user@.service.d/dbus.conf"
835 # Newer Fedora versions use dbus-broker by default. Let's install it if it's available.
836 if [ -f $ROOTLIBDIR/user
/dbus-broker.service
]; then
837 inst
$ROOTLIBDIR/user
/dbus-broker.service
838 inst_symlink
/etc
/systemd
/user
/dbus.service
839 elif [ -f $ROOTLIBDIR/system
/dbus-daemon.service
]; then
840 # Fedora rawhide replaced dbus.service with dbus-daemon.service
841 inst
$ROOTLIBDIR/user
/dbus-daemon.service
843 inst_symlink
/etc
/systemd
/user
/dbus.service
845 inst
$ROOTLIBDIR/user
/dbus.service
851 if [[ "$LOOKS_LIKE_DEBIAN" ]] && type -p dpkg-architecture
&>/dev
/null
; then
852 find "/lib/$(dpkg-architecture -qDEB_HOST_MULTIARCH)/security" -xtype f
854 find /lib
*/security
-xtype f
856 find /etc
/pam.d
/etc
/security
-xtype f
857 ) |
while read file; do
861 # pam_unix depends on unix_chkpwd.
862 # see http://www.linux-pam.org/Linux-PAM-html/sag-pam_unix.html
863 dracut_install
-o unix_chkpwd
865 [[ "$LOOKS_LIKE_DEBIAN" ]] &&
866 cp /etc
/pam.d
/systemd-user
$initdir/etc
/pam.d
/
868 # set empty root password for easy debugging
869 sed -i 's/^root:x:/root::/' $initdir/etc
/passwd
873 # The first three paths may be deprecated.
874 # It seems now the last two paths are used by many distributions.
876 /usr
/lib
/kbd
/keymaps
/include
/* \
877 /usr
/lib
/kbd
/keymaps
/i386
/include
/* \
878 /usr
/lib
/kbd
/keymaps
/i386
/qwerty
/us.
* \
879 /usr
/lib
/kbd
/keymaps
/legacy
/include
/* \
880 /usr
/lib
/kbd
/keymaps
/legacy
/i386
/qwerty
/us.
*; do
881 [[ -f $i ]] ||
continue
885 # When it takes any argument, then install more keymaps.
888 /usr
/lib
/kbd
/keymaps
/i386
/*/* \
889 /usr
/lib
/kbd
/keymaps
/legacy
/i386
/*/*; do
890 [[ -f $i ]] ||
continue
897 for i
in /usr
/share
/zoneinfo
/{,*/,*/*/}*; do
898 [[ -f $i ]] ||
continue
905 /usr
/lib
/kbd
/consolefonts
/eurlatgr
* \
906 /usr
/lib
/kbd
/consolefonts
/latarcyrheb-sun16
*; do
907 [[ -f $i ]] ||
continue
913 for _terminfodir
in /lib
/terminfo
/etc
/terminfo
/usr
/share
/terminfo
; do
914 [ -f ${_terminfodir}/l
/linux
] && break
916 dracut_install
-o ${_terminfodir}/l
/linux
919 has_user_dbus_socket
() {
920 if [ -f /usr
/lib
/systemd
/user
/dbus.socket
] ||
[ -f /etc
/systemd
/user
/dbus.socket
]; then
923 echo "Per-user instances are not supported. Skipping..."
928 enable_user_manager
() {
929 has_user_dbus_socket ||
return 0
932 [[ $# -gt 0 ]] ||
set -- nobody
933 mkdir
-p "$initdir/var/lib/systemd/linger"
935 touch "$initdir/var/lib/systemd/linger/$_userid"
941 setup_nspawn_root
() {
942 rm -fr $TESTDIR/nspawn-root
943 ddebug
"cp -ar $initdir $TESTDIR/nspawn-root"
944 cp -ar $initdir $TESTDIR/nspawn-root
945 # we don't mount in the nspawn root
946 rm -f $TESTDIR/nspawn-root
/etc
/fstab
947 if [[ "$RUN_IN_UNPRIVILEGED_CONTAINER" = "yes" ]]; then
948 cp -ar $TESTDIR/nspawn-root
$TESTDIR/unprivileged-nspawn-root
953 mkdir
-p $initdir/run
954 mkdir
-p $initdir/etc
/systemd
/system
955 mkdir
-p $initdir/var
/log
/journal
957 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
958 if [ -L "/$d" ]; then
965 ln -sfn /run
"$initdir/var/run"
966 ln -sfn /run
/lock
"$initdir/var/lock"
969 mask_supporting_services
() {
970 # mask some services that we do not want to run in these tests
971 ln -fs /dev
/null
$initdir/etc
/systemd
/system
/systemd-hwdb-update.service
972 ln -fs /dev
/null
$initdir/etc
/systemd
/system
/systemd-journal-catalog-update.service
973 ln -fs /dev
/null
$initdir/etc
/systemd
/system
/systemd-networkd.service
974 ln -fs /dev
/null
$initdir/etc
/systemd
/system
/systemd-networkd.socket
975 ln -fs /dev
/null
$initdir/etc
/systemd
/system
/systemd-resolved.service
980 local _so_regex
='([^ ]*/lib[^/]*/[^ ]*\.so[^ ]*)'
983 LC_ALL
=C ldd
"$_bin" 2>/dev
/null |
while read _line
; do
984 [[ $_line = 'not a dynamic executable' ]] && break
986 if [[ $_line =~
$_so_regex ]]; then
987 _file
=${BASH_REMATCH[1]}
988 [[ -e ${initdir}/$_file ]] && continue
989 inst_library
"$_file"
993 if [[ $_line =~ not\ found
]]; then
994 dfatal
"Missing a shared library required by $_bin."
995 dfatal
"Run \"ldd $_bin\" to find out what it is."
997 dfatal
"dracut cannot create an initrd."
1004 [[ -e $STATEFILE ]] && .
$STATEFILE
1005 if [[ ! -d "$TESTDIR" ]]; then
1006 if [[ -z "$TESTDIR" ]]; then
1007 TESTDIR
=$
(mktemp
--tmpdir=/var
/tmp
-d -t systemd-test.XXXXXX
)
1012 echo "TESTDIR=\"$TESTDIR\"" > $STATEFILE
1018 initdir
=$TESTDIR/root
1023 ## @brief Converts numeric logging level to the first letter of level name.
1025 # @param lvl Numeric logging level in range from 1 to 6.
1026 # @retval 1 if @a lvl is out of range.
1027 # @retval 0 if @a lvl is correct.
1028 # @result Echoes first letter of level name.
1041 ## @brief Internal helper function for _do_dlog()
1043 # @param lvl Numeric logging level.
1044 # @param msg Message.
1045 # @retval 0 It's always returned, even if logging failed.
1047 # @note This function is not supposed to be called manually. Please use
1048 # dtrace(), ddebug(), or others instead which wrap this one.
1050 # This function calls _do_dlog() either with parameter msg, or if
1051 # none is given, it will read standard input and will use every line as
1055 # dwarn "This is a warning"
1056 # echo "This is a warning" | dwarn
1057 LOG_LEVEL
=${LOG_LEVEL:-4}
1060 [ -z "$LOG_LEVEL" ] && return 0
1061 [ $1 -le $LOG_LEVEL ] ||
return 0
1062 local lvl
="$1"; shift
1063 local lvlc
=$
(_lvl2char
"$lvl") ||
return 0
1065 if [ $# -ge 1 ]; then
1069 echo "$lvlc: " "$line"
1074 ## @brief Logs message at TRACE level (6)
1076 # @param msg Message.
1077 # @retval 0 It's always returned, even if logging failed.
1081 [ -n "$debug" ] && set -x ||
:
1084 ## @brief Logs message at DEBUG level (5)
1086 # @param msg Message.
1087 # @retval 0 It's always returned, even if logging failed.
1091 # [ -n "$debug" ] && set -x || :
1094 ## @brief Logs message at INFO level (4)
1096 # @param msg Message.
1097 # @retval 0 It's always returned, even if logging failed.
1101 [ -n "$debug" ] && set -x ||
:
1104 ## @brief Logs message at WARN level (3)
1106 # @param msg Message.
1107 # @retval 0 It's always returned, even if logging failed.
1111 [ -n "$debug" ] && set -x ||
:
1114 ## @brief Logs message at ERROR level (2)
1116 # @param msg Message.
1117 # @retval 0 It's always returned, even if logging failed.
1121 # [ -n "$debug" ] && set -x || :
1124 ## @brief Logs message at FATAL level (1)
1126 # @param msg Message.
1127 # @retval 0 It's always returned, even if logging failed.
1131 [ -n "$debug" ] && set -x ||
:
1135 # Generic substring function. If $2 is in $1, return 0.
1136 strstr
() { [ "${1#*$2*}" != "$1" ]; }
1138 # normalize_path <path>
1139 # Prints the normalized path, where it removes any duplicated
1140 # and trailing slashes.
1142 # $ normalize_path ///test/test//
1146 set -- "${1//+(\/)//}"
1151 # convert_abs_rel <from> <to>
1152 # Prints the relative path, when creating a symlink to <to> from <from>.
1154 # $ convert_abs_rel /usr/bin/test /bin/test-2
1156 # $ ln -s $(convert_abs_rel /usr/bin/test /bin/test-2) /usr/bin/test
1158 local __current __absolute __abssize __cursize __newpath
1159 local -i __i __level
1161 set -- "$(normalize_path "$1")" "$(normalize_path "$2")"
1163 # corner case #1 - self looping link
1164 [[ "$1" == "$2" ]] && { echo "${1##*/}"; return; }
1166 # corner case #2 - own dir link
1167 [[ "${1%/*}" == "$2" ]] && { echo "."; return; }
1169 IFS
="/" __current
=($1)
1170 IFS
="/" __absolute
=($2)
1172 __abssize
=${#__absolute[@]}
1173 __cursize
=${#__current[@]}
1175 while [[ ${__absolute[__level]} == ${__current[__level]} ]]
1178 if (( __level
> __abssize || __level
> __cursize
))
1184 for ((__i
= __level
; __i
< __cursize-1
; __i
++))
1186 if ((__i
> __level
))
1188 __newpath
=$__newpath"/"
1190 __newpath
=$__newpath".."
1193 for ((__i
= __level
; __i
< __abssize
; __i
++))
1195 if [[ -n $__newpath ]]
1197 __newpath
=$__newpath"/"
1199 __newpath
=$__newpath${__absolute[__i]}
1206 # Install a directory, keeping symlinks as on the original system.
1207 # Example: if /lib points to /lib64 on the host, "inst_dir /lib/file"
1208 # will create ${initdir}/lib64, ${initdir}/lib64/file,
1209 # and a symlink ${initdir}/lib -> lib64.
1211 [[ -e ${initdir}/"$1" ]] && return 0 # already there
1213 local _dir
="$1" _part
="${1%/*}" _file
1214 while [[ "$_part" != "${_part%/*}" ]] && ! [[ -e "${initdir}/${_part}" ]]; do
1219 # iterate over parent directories
1220 for _file
in $_dir; do
1221 [[ -e "${initdir}/$_file" ]] && continue
1222 if [[ -L $_file ]]; then
1223 inst_symlink
"$_file"
1226 mkdir
-m 0755 -p "${initdir}/$_file" ||
return 1
1227 [[ -e "$_file" ]] && chmod --reference="$_file" "${initdir}/$_file"
1228 chmod u
+w
"${initdir}/$_file"
1233 # $1 = file to copy to ramdisk
1234 # $2 (optional) Name for the file on the ramdisk
1235 # Location of the image dir is assumed to be $initdir
1236 # We never overwrite the target if it exists.
1238 [[ -f "$1" ]] ||
return 1
1239 strstr
"$1" "/" ||
return 1
1241 local _src
=$1 target
="${2:-$1}"
1242 if ! [[ -d ${initdir}/$target ]]; then
1243 [[ -e ${initdir}/$target ]] && return 0
1244 [[ -L ${initdir}/$target ]] && return 0
1245 [[ -d "${initdir}/${target%/*}" ]] || inst_dir "${target%/*}"
1247 # install checksum files also
1248 if [[ -e "${_src%/*}/.${_src##*/}.hmac" ]]; then
1249 inst
"${_src%/*}/.${_src##*/}.hmac" "${target%/*}/.${target##*/}.hmac"
1251 ddebug
"Installing $_src"
1252 cp --sparse=always
-pfL "$_src" "${initdir}/$target"
1255 # find symlinks linked to given library file
1257 # Function searches for symlinks by stripping version numbers appended to
1258 # library filename, checks if it points to the same target and finally
1259 # prints the list of symlinks to stdout.
1262 # rev_lib_symlinks libfoo.so.8.1
1263 # output: libfoo.so.8 libfoo.so
1264 # (Only if libfoo.so.8 and libfoo.so exists on host system.)
1265 rev_lib_symlinks
() {
1266 [[ ! $1 ]] && return 0
1268 local fn
="$1" orig
="$(readlink -f "$1")" links
=''
1270 [[ ${fn} =~ .
*\.so\..
* ]] ||
return 1
1272 until [[ ${fn##*.} == so
]]; do
1274 [[ -L ${fn} && $(readlink -f "${fn}") == ${orig} ]] && links+=" ${fn}"
1280 # Same as above, but specialized to handle dynamic libraries.
1281 # It handles making symlinks according to how the original library
1284 local _src="$1" _dest=${2:-$1} _lib _reallib _symlink
1285 strstr "$1" "/" || return 1
1286 [[ -e $initdir/$_dest ]] && return 0
1287 if [[ -L $_src ]]; then
1288 # install checksum files also
1289 if [[ -e "${_src%/*}/.
${_src##*/}.hmac
" ]]; then
1290 inst "${_src%/*}/.${_src##*/}.hmac" "${_dest%/*}/.${_dest##*/}.hmac
"
1292 _reallib=$(readlink -f "$_src")
1293 inst_simple "$_reallib" "$_reallib"
1294 inst_dir "${_dest%/*}"
1295 [[ -d "${_dest%/*}" ]] && _dest=$(readlink -f "${_dest%/*}")/${_dest##*/}
1296 ln -sfn $
(convert_abs_rel
"${_dest}" "${_reallib}") "${initdir}/${_dest}"
1298 inst_simple
"$_src" "$_dest"
1301 # Create additional symlinks. See rev_symlinks description.
1302 for _symlink
in $
(rev_lib_symlinks
$_src) $
(rev_lib_symlinks
$_reallib); do
1303 [[ -e $initdir/$_symlink ]] ||
{
1304 ddebug
"Creating extra symlink: $_symlink"
1305 inst_symlink
$_symlink
1310 # find a binary. If we were not passed the full path directly,
1311 # search in the usual places to find the binary.
1313 if [[ -z ${1##/*} ]]; then
1314 if [[ -x $1 ]] ||
{ strstr
"$1" ".so" && ldd
$1 &>/dev
/null
; }; then
1323 # Same as above, but specialized to install binary executables.
1324 # Install binary executable, and all shared library dependencies, if any.
1328 # In certain cases we might attempt to install a binary which is already
1329 # present in the test image, yet it's missing from the host system.
1330 # In such cases, let's check if the binary indeed exists in the image
1331 # before doing any other chcecks. If it does, immediately return with
1333 [[ $# -eq 1 && -e $initdir/$1 ]] && return 0
1335 _bin
=$
(find_binary
"$1") ||
return 1
1337 [[ -e $initdir/$_target ]] && return 0
1338 [[ -L $_bin ]] && inst_symlink
$_bin $_target && return 0
1340 local _so_regex
='([^ ]*/lib[^/]*/[^ ]*\.so[^ ]*)'
1342 LC_ALL
=C ldd
"$_bin" 2>/dev
/null |
while read _line
; do
1343 [[ $_line = 'not a dynamic executable' ]] && break
1345 if [[ $_line =~
$_so_regex ]]; then
1346 _file
=${BASH_REMATCH[1]}
1347 [[ -e ${initdir}/$_file ]] && continue
1348 inst_library
"$_file"
1352 if [[ $_line =~ not\ found
]]; then
1353 dfatal
"Missing a shared library required by $_bin."
1354 dfatal
"Run \"ldd $_bin\" to find out what it is."
1356 dfatal
"dracut cannot create an initrd."
1360 inst_simple
"$_bin" "$_target"
1363 # same as above, except for shell scripts.
1364 # If your shell script does not start with shebang, it is not a shell script.
1367 _bin
=$
(find_binary
"$1") ||
return 1
1369 local _line _shebang_regex
1370 read -r -n 80 _line
<"$_bin"
1371 # If debug is set, clean unprintable chars to prevent messing up the term
1372 [[ $debug ]] && _line
=$
(echo -n "$_line" |
tr -c -d '[:print:][:space:]')
1373 _shebang_regex
='(#! *)(/[^ ]+).*'
1374 [[ $_line =~
$_shebang_regex ]] ||
return 1
1375 inst
"${BASH_REMATCH[2]}" && inst_simple
"$_bin" "$@"
1378 # same as above, but specialized for symlinks
1380 local _src
=$1 _target
=${2:-$1} _realsrc
1381 strstr
"$1" "/" ||
return 1
1382 [[ -L $1 ]] ||
return 1
1383 [[ -L $initdir/$_target ]] && return 0
1384 _realsrc
=$
(readlink
-f "$_src")
1385 if ! [[ -e $initdir/$_realsrc ]]; then
1386 if [[ -d $_realsrc ]]; then
1387 inst_dir
"$_realsrc"
1392 [[ ! -e $initdir/${_target%/*} ]] && inst_dir
"${_target%/*}"
1393 [[ -d ${_target%/*} ]] && _target=$(readlink -f ${_target%/*})/${_target##*/}
1394 ln -sfn $
(convert_abs_rel
"${_target}" "${_realsrc}") "$initdir/$_target"
1397 # attempt to install any programs specified in a udev rule
1398 inst_rule_programs
() {
1401 if grep -qE 'PROGRAM==?"[^ "]+' "$1"; then
1402 for _prog
in $
(grep -E 'PROGRAM==?"[^ "]+' "$1" |
sed -r 's/.*PROGRAM==?"([^ "]+).*/\1/'); do
1403 if [ -x /lib
/udev
/$_prog ]; then
1404 _bin
=/lib
/udev
/$_prog
1406 _bin
=$
(find_binary
"$_prog") ||
{
1407 dinfo
"Skipping program $_prog using in udev rule $(basename $1) as it cannot be found"
1412 #dinfo "Installing $_bin due to it's use in the udev rule $(basename $1)"
1413 dracut_install
"$_bin"
1418 # udev rules always get installed in the same place, so
1419 # create a function to install them to make life simpler.
1421 local _target
=/etc
/udev
/rules.d _rule _found
1423 inst_dir
"/lib/udev/rules.d"
1425 for _rule
in "$@"; do
1426 if [ "${rule#/}" = "$rule" ]; then
1427 for r
in /lib
/udev
/rules.d
/etc
/udev
/rules.d
; do
1428 if [[ -f $r/$_rule ]]; then
1430 inst_simple
"$_found"
1431 inst_rule_programs
"$_found"
1435 for r
in '' .
/ $dracutbasedir/rules.d
/; do
1436 if [[ -f ${r}$_rule ]]; then
1438 inst_simple
"$_found" "$_target/${_found##*/}"
1439 inst_rule_programs
"$_found"
1442 [[ $_found ]] || dinfo
"Skipping udev rule: $_rule"
1447 # general purpose installation function
1448 # Same args as above.
1454 2) [[ ! $initdir && -d $2 ]] && export initdir
=$2
1455 [[ $initdir = $2 ]] && set $1;;
1456 3) [[ -z $initdir ]] && export initdir
=$2
1458 *) dfatal
"inst only takes 1 or 2 or 3 arguments"
1461 for _x
in inst_symlink inst_script inst_binary inst_simple
; do
1462 $_x "$@" && return 0
1467 # install any of listed files
1469 # If first argument is '-d' and second some destination path, first accessible
1470 # source is installed into this path, otherwise it will installed in the same
1471 # path as source. If none of listed files was installed, function return 1.
1472 # On first successful installation it returns with 0 status.
1476 # inst_any -d /bin/foo /bin/bar /bin/baz
1478 # Lets assume that /bin/baz exists, so it will be installed as /bin/foo in
1483 [[ $1 = '-d' ]] && to
="$2" && shift 2
1486 if [[ -e $f ]]; then
1487 [[ $to ]] && inst
"$f" "$to" && return 0
1488 inst
"$f" && return 0
1495 # dracut_install [-o ] <file> [<file> ... ]
1496 # Install <file> to the initramfs image
1497 # -o optionally install the <file> and don't fail, if it is not there
1500 if [[ $1 = '-o' ]]; then
1504 while (($# > 0)); do
1505 if ! inst
"$1" ; then
1506 if [[ $_optional = yes ]]; then
1507 dinfo
"Skipping program $1 as it cannot be found and is" \
1508 "flagged to be optional"
1510 dfatal
"Failed to install $1"
1518 # Install a single kernel module along with any firmware it may require.
1519 # $1 = full path to kernel module to install
1520 install_kmod_with_fw
() {
1521 # no need to go further if the module is already installed
1523 [[ -e "${initdir}/lib/modules/$KERNEL_VER/${1##*/lib/modules/$KERNEL_VER/}" ]] \
1526 [[ -e "$initdir/.kernelmodseen/${1##*/}" ]] && return 0
1528 if [[ $omit_drivers ]]; then
1529 local _kmod
=${1##*/}
1532 if [[ "$_kmod" =~
$omit_drivers ]]; then
1533 dinfo
"Omitting driver $_kmod"
1536 if [[ "${1##*/lib/modules/$KERNEL_VER/}" =~
$omit_drivers ]]; then
1537 dinfo
"Omitting driver $_kmod"
1542 [ -d "$initdir/.kernelmodseen" ] && \
1543 > "$initdir/.kernelmodseen/${1##*/}"
1545 inst_simple
"$1" "/lib/modules/$KERNEL_VER/${1##*/lib/modules/$KERNEL_VER/}" \
1548 local _modname
=${1##*/} _fwdir _found _fw
1549 _modname
=${_modname%.ko*}
1550 for _fw
in $
(modinfo
-k $KERNEL_VER -F firmware
$1 2>/dev
/null
); do
1552 for _fwdir
in $fw_dir; do
1553 if [[ -d $_fwdir && -f $_fwdir/$_fw ]]; then
1554 inst_simple
"$_fwdir/$_fw" "/lib/firmware/$_fw"
1558 if [[ $_found != yes ]]; then
1559 if ! grep -qe "\<${_modname//-/_}\>" /proc
/modules
; then
1560 dinfo
"Possible missing firmware \"${_fw}\" for kernel module" \
1561 "\"${_modname}.ko\""
1563 dwarn
"Possible missing firmware \"${_fw}\" for kernel module" \
1564 "\"${_modname}.ko\""
1571 # Do something with all the dependencies of a kernel module.
1572 # Note that kernel modules depend on themselves using the technique we use
1573 # $1 = function to call for each dependency we find
1574 # It will be passed the full path to the found kernel module
1575 # $2 = module to get dependencies for
1576 # rest of args = arguments to modprobe
1577 # _fderr specifies FD passed from surrounding scope
1578 for_each_kmod_dep
() {
1579 local _func
=$1 _kmod
=$2 _cmd _modpath _options _found
=0
1581 modprobe
"$@" --ignore-install --show-depends $_kmod 2>&${_fderr} |
(
1582 while read _cmd _modpath _options
; do
1583 [[ $_cmd = insmod
]] ||
continue
1584 $_func ${_modpath} ||
exit $?
1587 [[ $_found -eq 0 ]] && exit 1
1592 # filter kernel modules to install certain modules that meet specific
1594 # $1 = search only in subdirectory of /kernel/$1
1595 # $2 = function to call with module name to filter.
1596 # This function will be passed the full path to the module to test.
1597 # The behavior of this function can vary depending on whether $hostonly is set.
1598 # If it is, we will only look at modules that are already in memory.
1599 # If it is not, we will look at all kernel modules
1600 # This function returns the full filenames of modules that match $1
1601 filter_kernel_modules_by_path
() (
1602 local _modname _filtercmd
1603 if ! [[ $hostonly ]]; then
1604 _filtercmd
='find "$KERNEL_MODS/kernel/$1" "$KERNEL_MODS/extra"'
1605 _filtercmd
+=' "$KERNEL_MODS/weak-updates" -name "*.ko" -o -name "*.ko.gz"'
1606 _filtercmd
+=' -o -name "*.ko.xz"'
1607 _filtercmd
+=' 2>/dev/null'
1609 _filtercmd
='cut -d " " -f 1 </proc/modules|xargs modinfo -F filename '
1610 _filtercmd
+='-k $KERNEL_VER 2>/dev/null'
1612 for _modname
in $
(eval $_filtercmd); do
1614 *.ko
) "$2" "$_modname" && echo "$_modname";;
1615 *.ko.gz
) gzip -dc "$_modname" > $initdir/$$.ko
1616 $2 $initdir/$$.ko
&& echo "$_modname"
1617 rm -f $initdir/$$.ko
1619 *.ko.xz
) xz
-dc "$_modname" > $initdir/$$.ko
1620 $2 $initdir/$$.ko
&& echo "$_modname"
1621 rm -f $initdir/$$.ko
1626 find_kernel_modules_by_path
() (
1627 if ! [[ $hostonly ]]; then
1628 find "$KERNEL_MODS/kernel/$1" "$KERNEL_MODS/extra" "$KERNEL_MODS/weak-updates" \
1629 -name "*.ko" -o -name "*.ko.gz" -o -name "*.ko.xz" 2>/dev
/null
1631 cut
-d " " -f 1 </proc
/modules \
1632 |
xargs modinfo
-F filename
-k $KERNEL_VER 2>/dev
/null
1636 filter_kernel_modules
() {
1637 filter_kernel_modules_by_path drivers
"$1"
1640 find_kernel_modules
() {
1641 find_kernel_modules_by_path drivers
1644 # instmods [-c] <kernel module> [<kernel module> ... ]
1645 # instmods [-c] <kernel subsystem>
1646 # install kernel modules along with all their dependencies.
1647 # <kernel subsystem> can be e.g. "=block" or "=drivers/usb/storage"
1649 [[ $no_kernel = yes ]] && return
1650 # called [sub]functions inherit _fderr
1653 if [[ $1 = '-c' ]]; then
1658 function inst1mod
() {
1659 local _ret
=0 _mod
="$1"
1662 if [ -f $KERNEL_MODS/modules.
${_mod#=} ]; then
1663 ( [[ "$_mpargs" ]] && echo $_mpargs
1664 cat "${KERNEL_MODS}/modules.${_mod#=}" ) \
1667 ( [[ "$_mpargs" ]] && echo $_mpargs
1668 find "$KERNEL_MODS" -path "*/${_mod#=}/*" -type f
-printf '%f\n' ) \
1672 --*) _mpargs
+=" $_mod" ;;
1673 i2o_scsi
) return ;; # Do not load this diagnostic-only module
1676 # if we are already installed, skip this module and go on
1678 [[ -f "$initdir/.kernelmodseen/${_mod%.ko}.ko" ]] && return
1680 if [[ $omit_drivers ]] && [[ "$1" =~
$omit_drivers ]]; then
1681 dinfo
"Omitting driver ${_mod##$KERNEL_MODS}"
1684 # If we are building a host-specific initramfs and this
1685 # module is not already loaded, move on to the next one.
1686 [[ $hostonly ]] && ! grep -qe "\<${_mod//-/_}\>" /proc
/modules \
1687 && ! echo $add_drivers |
grep -qe "\<${_mod}\>" \
1690 # We use '-d' option in modprobe only if modules prefix path
1691 # differs from default '/'. This allows us to use Dracut with
1692 # old version of modprobe which doesn't have '-d' option.
1693 local _moddirname
=${KERNEL_MODS%%/lib/modules/*}
1694 [[ -n ${_moddirname} ]] && _moddirname
="-d ${_moddirname}/"
1696 # ok, load the module, all its dependencies, and any firmware
1698 for_each_kmod_dep install_kmod_with_fw
$_mod \
1699 --set-version $KERNEL_VER ${_moddirname} $_mpargs
1706 function instmods_1
() {
1708 if (($# == 0)); then # filenames from stdin
1710 inst1mod
"${_mod%.ko*}" ||
{
1711 if [ "$_check" = "yes" ]; then
1712 dfatal
"Failed to install $_mod"
1718 while (($# > 0)); do # filenames as arguments
1719 inst1mod
${1%.ko*} ||
{
1720 if [ "$_check" = "yes" ]; then
1721 dfatal
"Failed to install $1"
1730 local _ret _filter_not_found
='FATAL: Module .* not found.'
1732 # Capture all stderr from modprobe to _fderr. We could use {var}>...
1733 # redirections, but that would make dracut require bash4 at least.
1734 eval "( instmods_1 \"\$@\" ) ${_fderr}>&1" \
1735 |
while read line
; do [[ "$line" =~
$_filter_not_found ]] && echo $line ||
echo $line >&2 ;done | derror
1742 ln -fs ..
/usr
/bin
/systemctl
$initdir/bin
/
1743 ln -fs ..
/usr
/lib
/systemd
$initdir/lib
/
1744 inst_simple
"/usr/lib/systemd/system/haveged.service"
1748 if mountpoint
-q $1; then
1754 _test_setup_cleanup
() {
1755 # only umount if create_empty_image_rootdir() was called to mount it
1756 [[ -z $TEST_SETUP_CLEANUP_ROOTDIR ]] || _umount_dir
$initdir
1759 # can be overridden in specific test
1760 test_setup_cleanup
() {
1765 # (post-test) cleanup should always ignore failure and cleanup as much as possible
1768 _umount_dir
$initdir
1769 if [[ $LOOPDEV && -b $LOOPDEV ]]; then
1770 ddebug
"losetup -d $LOOPDEV"
1778 # can be overridden in specific test
1784 if [ -z "$TEST_NO_QEMU" ]; then
1785 if run_qemu
"$1"; then
1786 check_result_qemu ||
return 1
1788 dwarn
"can't run QEMU, skipping"
1791 if [ -z "$TEST_NO_NSPAWN" ]; then
1792 if run_nspawn
"nspawn-root" "$1"; then
1793 check_result_nspawn
"nspawn-root" ||
return 1
1795 dwarn
"can't run systemd-nspawn, skipping"
1798 if [[ "$RUN_IN_UNPRIVILEGED_CONTAINER" = "yes" ]]; then
1799 if NSPAWN_ARGUMENTS
="-U --private-network $NSPAWN_ARGUMENTS" run_nspawn
"unprivileged-nspawn-root" "$1"; then
1800 check_result_nspawn
"unprivileged-nspawn-root" ||
return 1
1802 dwarn
"can't run systemd-nspawn, skipping"
1810 if [[ $UID != "0" ]]; then
1811 echo "TEST: $TEST_DESCRIPTION [SKIPPED]: not root" >&2
1816 [[ $libdir ]] ||
for libdir
in /lib64
/lib
; do
1817 [[ -d $libdir ]] && libdirs
+=" $libdir" && break
1820 [[ $usrlibdir ]] ||
for usrlibdir
in /usr
/lib64
/usr
/lib
; do
1821 [[ -d $usrlibdir ]] && libdirs
+=" $usrlibdir" && break
1824 mkdir
-p "$STATEDIR"
1829 while (($# > 0)); do
1832 echo "TEST RUN: $TEST_DESCRIPTION"
1835 if (( $ret == 0 )); then
1836 echo "TEST RUN: $TEST_DESCRIPTION [OK]"
1838 echo "TEST RUN: $TEST_DESCRIPTION [FAILED]"
1842 echo "TEST SETUP: $TEST_DESCRIPTION"
1847 echo "TEST CLEANUP: $TEST_DESCRIPTION"
1852 echo -n "TEST: $TEST_DESCRIPTION "
1857 ) </dev
/null
>"$TESTLOG" 2>&1 || ret
=$?
1859 if [ $ret -eq 0 ]; then