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 || true
)
8 LOOKS_LIKE_ARCH
=$
(source /etc
/os-release
&& [[ "$ID" = "arch" ||
" $ID_LIKE " = *" arch "* ]] && echo yes || true
)
9 LOOKS_LIKE_SUSE
=$
(source /etc
/os-release
&& [[ " $ID_LIKE " = *" suse "* ]] && echo yes || true
)
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 if ! ROOTLIBDIR
=$
(pkg-config
--variable=systemdutildir systemd
); then
21 echo "WARNING! Cannot determine rootlibdir from pkg-config, assuming /usr/lib/systemd" >&2
22 ROOTLIBDIR
=/usr
/lib
/systemd
25 PATH_TO_INIT
=$ROOTLIBDIR/systemd
27 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"
28 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"
30 STATEDIR
="${BUILD_DIR:-.}/test/$(basename $(dirname $(realpath $0)))"
31 STATEFILE
="$STATEDIR/.testdir"
32 TESTLOG
="$STATEDIR/test.log"
34 is_built_with_asan
() {
35 if ! type -P objdump
>/dev
/null
; then
36 ddebug
"Failed to find objdump. Assuming systemd hasn't been built with ASAN."
40 # Borrowed from https://github.com/google/oss-fuzz/blob/cd9acd02f9d3f6e80011cc1e9549be526ce5f270/infra/base-images/base-runner/bad_build_check#L182
41 local _asan_calls
=$
(objdump
-dC $BUILD_DIR/systemd-journald |
egrep "callq\s+[0-9a-f]+\s+<__asan" -c)
42 if (( $_asan_calls < 1000 )); then
49 IS_BUILT_WITH_ASAN
=$
(is_built_with_asan
&& echo yes ||
echo no
)
51 if [[ "$IS_BUILT_WITH_ASAN" = "yes" ]]; then
53 SKIP_INITRD
="${SKIP_INITRD:-yes}"
54 PATH_TO_INIT
=$ROOTLIBDIR/systemd-under-asan
58 # We need to correctly distinguish between gcc's and clang's ASan DSOs.
59 if ldd
$BUILD_DIR/systemd |
grep -q libasan.so
; then
61 elif ldd
$BUILD_DIR/systemd |
grep -q libclang_rt.asan
; then
64 # As clang's ASan DSO is usually in a non-standard path, let's check if
65 # the environment is set accordingly. If not, warn the user and exit.
66 # We're not setting the LD_LIBRARY_PATH automagically here, because
67 # user should encounter (and fix) the same issue when running the unit
69 if ldd
"$BUILD_DIR/systemd" |
grep -q "libclang_rt.asan.*not found"; then
70 _asan_rt_name
="$(ldd $BUILD_DIR/systemd | awk '/libclang_rt.asan/ {print $1; exit}')"
71 _asan_rt_path
="$(find /usr/lib* /usr/local/lib* -type f -name "$_asan_rt_name" 2>/dev/null | sed 1q)"
72 echo >&2 "clang's ASan DSO ($_asan_rt_name) is not present in the runtime library path"
73 echo >&2 "Consider setting LD_LIBRARY_PATH=${_asan_rt_path%/*}"
77 echo >&2 "systemd is not linked against the ASan DSO"
78 echo >&2 "gcc does this by default, for clang compile with -shared-libasan"
83 function find_qemu_bin
() {
84 # SUSE and Red Hat call the binary qemu-kvm. Debian and Gentoo call it kvm.
85 # Either way, only use this version if we aren't running in KVM, because
86 # nested KVM is flaky still.
87 if [[ $
(systemd-detect-virt
-v) != kvm
&& -z $TEST_NO_KVM ]] ; then
88 [ "$QEMU_BIN" ] || QEMU_BIN
=$
(which -a kvm qemu-kvm
2>/dev
/null |
grep '^/' -m1)
91 [ "$ARCH" ] || ARCH
=$
(uname
-m)
94 # QEMU's own build system calls it qemu-system-x86_64
95 [ "$QEMU_BIN" ] || QEMU_BIN
=$
(which -a qemu-system-x86_64
2>/dev
/null |
grep '^/' -m1)
98 # new i386 version of QEMU
99 [ "$QEMU_BIN" ] || QEMU_BIN
=$
(which -a qemu-system-i386
2>/dev
/null |
grep '^/' -m1)
101 # i386 version of QEMU
102 [ "$QEMU_BIN" ] || QEMU_BIN
=$
(which -a qemu
2>/dev
/null |
grep '^/' -m1)
105 [ "$QEMU_BIN" ] || QEMU_BIN
=$
(which -a qemu-system-
$ARCH 2>/dev
/null |
grep '^/' -m1)
109 if [ ! -e "$QEMU_BIN" ]; then
110 echo "Could not find a suitable QEMU binary" >&2
115 # Return 0 if QEMU did run (then you must check the result state/logs for actual
116 # success), or 1 if QEMU is not available.
118 if [ -f /etc
/machine-id
]; then
119 read MACHINE_ID
< /etc
/machine-id
120 [ -z "$INITRD" ] && [ -e "$EFI_MOUNT/$MACHINE_ID/$KERNEL_VER/initrd" ] \
121 && INITRD
="$EFI_MOUNT/$MACHINE_ID/$KERNEL_VER/initrd"
122 [ -z "$KERNEL_BIN" ] && [ -e "$EFI_MOUNT/$MACHINE_ID/$KERNEL_VER/linux" ] \
123 && KERNEL_BIN
="$EFI_MOUNT/$MACHINE_ID/$KERNEL_VER/linux"
128 if [[ ! "$KERNEL_BIN" ]]; then
129 if [[ "$LOOKS_LIKE_ARCH" ]]; then
130 KERNEL_BIN
=/boot
/vmlinuz-linux
132 [ "$ARCH" ] || ARCH
=$
(uname
-m)
135 KERNEL_BIN
=/boot
/vmlinux-
$KERNEL_VER
139 KERNEL_BIN
=/boot
/vmlinuz-
$KERNEL_VER
145 default_fedora_initrd
=/boot
/initramfs-
${KERNEL_VER}.img
146 default_debian_initrd
=/boot
/initrd.img-
${KERNEL_VER}
147 default_arch_initrd
=/boot
/initramfs-linux-fallback.img
148 default_suse_initrd
=/boot
/initrd-
${KERNEL_VER}
149 if [[ ! "$INITRD" ]]; then
150 if [[ -e "$default_fedora_initrd" ]]; then
151 INITRD
="$default_fedora_initrd"
152 elif [[ "$LOOKS_LIKE_DEBIAN" && -e "$default_debian_initrd" ]]; then
153 INITRD
="$default_debian_initrd"
154 elif [[ "$LOOKS_LIKE_ARCH" && -e "$default_arch_initrd" ]]; then
155 INITRD
="$default_arch_initrd"
156 elif [[ "$LOOKS_LIKE_SUSE" && -e "$default_suse_initrd" ]]; then
157 INITRD
="$default_suse_initrd"
161 # If QEMU_SMP was not explicitly set, try to determine the value 'dynamically'
162 # i.e. use the number of online CPUs on the host machine. If the nproc utility
163 # is not installed or there's some other error when calling it, fall back
164 # to the original value (QEMU_SMP=1).
165 if ! [ "$QEMU_SMP" ]; then
166 if ! QEMU_SMP
=$
(nproc
); then
167 dwarn
"nproc utility is not installed, falling back to QEMU_SMP=1"
172 find_qemu_bin ||
return 1
175 if [[ "$UNIFIED_CGROUP_HIERARCHY" = "yes" ]]; then
176 _cgroup_args
="systemd.unified_cgroup_hierarchy=yes"
177 elif [[ "$UNIFIED_CGROUP_HIERARCHY" = "no" ]]; then
178 _cgroup_args
="systemd.unified_cgroup_hierarchy=no systemd.legacy_systemd_cgroup_controller=yes"
179 elif [[ "$UNIFIED_CGROUP_HIERARCHY" = "hybrid" ]]; then
180 _cgroup_args
="systemd.unified_cgroup_hierarchy=no systemd.legacy_systemd_cgroup_controller=no"
181 elif [[ "$UNIFIED_CGROUP_HIERARCHY" != "default" ]]; then
182 dfatal
"Unknown UNIFIED_CGROUP_HIERARCHY. Got $UNIFIED_CGROUP_HIERARCHY, expected [yes|no|hybrid|default]"
186 if [[ "$LOOKS_LIKE_SUSE" ]]; then
187 PARAMS
+="rd.hostonly=0"
188 elif [[ "$LOOKS_LIKE_ARCH" ]]; then
194 KERNEL_APPEND
="$PARAMS \
206 QEMU_OPTIONS
="-smp $QEMU_SMP \
210 -kernel $KERNEL_BIN \
211 -drive format=raw,cache=unsafe,file=${TESTDIR}/rootdisk.img \
214 if [[ "$INITRD" && "$SKIP_INITRD" != "yes" ]]; then
215 QEMU_OPTIONS
="$QEMU_OPTIONS -initrd $INITRD"
218 # Let's use KVM if it is available, but let's avoid using nested KVM as that is still flaky
219 if [[ -c /dev
/kvm
&& $
(systemd-detect-virt
-v) != kvm
&& -z $TEST_NO_KVM ]] ; then
220 QEMU_OPTIONS
="$QEMU_OPTIONS -machine accel=kvm -enable-kvm -cpu host"
223 if [[ "$QEMU_TIMEOUT" != "infinity" ]]; then
224 QEMU_BIN
="timeout --foreground $QEMU_TIMEOUT $QEMU_BIN"
226 (set -x; $QEMU_BIN $QEMU_OPTIONS -append "$KERNEL_APPEND")
228 if [ "$rc" = 124 ] && [ "$QEMU_TIMEOUT" != "infinity" ]; then
229 derror
"test timed out after $QEMU_TIMEOUT s"
232 [ "$rc" != 0 ] && derror
"QEMU failed with exit code $rc"
237 # Return 0 if nspawn did run (then you must check the result state/logs for actual
238 # success), or 1 if nspawn is not available.
240 [[ -d /run
/systemd
/system
]] ||
return 1
242 local _nspawn_cmd
="$BUILD_DIR/systemd-nspawn $NSPAWN_ARGUMENTS --register=no --kill-signal=SIGKILL --directory=$TESTDIR/$1 $PATH_TO_INIT $KERNEL_APPEND"
243 if [[ "$NSPAWN_TIMEOUT" != "infinity" ]]; then
244 _nspawn_cmd
="timeout --foreground $NSPAWN_TIMEOUT $_nspawn_cmd"
247 if [[ "$UNIFIED_CGROUP_HIERARCHY" = "hybrid" ]]; then
248 dwarn
"nspawn doesn't support UNIFIED_CGROUP_HIERARCHY=hybrid, skipping"
250 elif [[ "$UNIFIED_CGROUP_HIERARCHY" = "yes" ||
"$UNIFIED_CGROUP_HIERARCHY" = "no" ]]; then
251 _nspawn_cmd
="env UNIFIED_CGROUP_HIERARCHY=$UNIFIED_CGROUP_HIERARCHY $_nspawn_cmd"
252 elif [[ "$UNIFIED_CGROUP_HIERARCHY" = "default" ]]; then
253 _nspawn_cmd
="env --unset=UNIFIED_CGROUP_HIERARCHY $_nspawn_cmd"
255 dfatal
"Unknown UNIFIED_CGROUP_HIERARCHY. Got $UNIFIED_CGROUP_HIERARCHY, expected [yes|no|hybrid|default]"
259 (set -x; $_nspawn_cmd)
261 if [ "$rc" = 124 ] && [ "$NSPAWN_TIMEOUT" != "infinity" ]; then
262 derror
"test timed out after $NSPAWN_TIMEOUT s"
265 [ "$rc" != 0 ] && derror
"nspawn failed with exit code $rc"
270 setup_basic_environment
() {
271 # create the basic filesystem layout
275 install_missing_libraries
293 generate_module_dependencies
294 if [[ "$IS_BUILT_WITH_ASAN" = "yes" ]]; then
300 # don't forget KERNEL_APPEND='... selinux=1 ...'
301 if [[ "$SETUP_SELINUX" != "yes" ]]; then
302 ddebug
"Don't setup SELinux"
305 ddebug
"Setup SELinux"
306 local _conf_dir
=/etc
/selinux
307 local _fixfiles_tools
="bash uname cat sort uniq awk grep egrep head expr find rm secon setfiles"
309 rm -rf $initdir/$_conf_dir
310 if ! cp -ar $_conf_dir $initdir/$_conf_dir; then
311 dfatal
"Failed to copy $_conf_dir"
315 cat <<EOF >$initdir/etc/systemd/system/autorelabel.service
317 Description=Relabel all filesystems
318 DefaultDependencies=no
319 Requires=local-fs.target
320 Conflicts=shutdown.target
321 After=local-fs.target
322 Before=sysinit.target shutdown.target
323 ConditionSecurity=selinux
324 ConditionPathExists=|/.autorelabel
327 ExecStart=/bin/sh -x -c 'echo 0 >/sys/fs/selinux/enforce && fixfiles -f -F relabel && rm /.autorelabel && systemctl --force reboot'
333 touch $initdir/.autorelabel
334 mkdir
-p $initdir/etc
/systemd
/system
/basic.target.wants
335 ln -fs autorelabel.service
$initdir/etc
/systemd
/system
/basic.target.wants
/autorelabel.service
337 dracut_install
$_fixfiles_tools
338 dracut_install fixfiles
339 dracut_install sestatus
343 if ! type -p valgrind
; then
344 dfatal
"Failed to install valgrind"
348 local _valgrind_bins
=$
(strace
-e execve valgrind
/bin
/true
2>&1 >/dev
/null | perl
-lne 'print $1 if /^execve\("([^"]+)"/')
349 dracut_install
$_valgrind_bins
351 local _valgrind_libs
=$
(LD_DEBUG
=files valgrind
/bin
/true
2>&1 >/dev
/null | perl
-lne 'print $1 if m{calling init: (/.*vgpreload_.*)}')
352 dracut_install
$_valgrind_libs
354 local _valgrind_dbg_and_supp
=$
(
355 strace
-e open valgrind
/bin
/true
2>&1 >/dev
/null |
356 perl
-lne 'if (my ($fname) = /^open\("([^"]+).*= (?!-)\d+/) { print $fname if $fname =~ /debug|\.supp$/ }'
358 dracut_install
$_valgrind_dbg_and_supp
361 create_valgrind_wrapper
() {
362 local _valgrind_wrapper
=$initdir/$ROOTLIBDIR/systemd-under-valgrind
363 ddebug
"Create $_valgrind_wrapper"
364 cat >$_valgrind_wrapper <<EOF
367 mount -t proc proc /proc
368 exec valgrind --leak-check=full --log-file=/valgrind.out $ROOTLIBDIR/systemd "\$@"
370 chmod 0755 $_valgrind_wrapper
373 create_asan_wrapper
() {
374 local _asan_wrapper
=$initdir/$ROOTLIBDIR/systemd-under-asan
375 local _asan_rt_pattern
376 ddebug
"Create $_asan_wrapper"
378 case "$ASAN_COMPILER" in
380 _asan_rt_pattern
="*libasan*"
383 _asan_rt_pattern
="libclang_rt.asan-*"
384 # Install llvm-symbolizer to generate useful reports
385 # See: https://clang.llvm.org/docs/AddressSanitizer.html#symbolizing-the-reports
386 dracut_install
"llvm-symbolizer"
389 dfail
"Unsupported compiler: $ASAN_COMPILER"
393 cat >$_asan_wrapper <<EOF
398 DEFAULT_ASAN_OPTIONS=strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1
399 DEFAULT_UBSAN_OPTIONS=print_stacktrace=1:print_summary=1:halt_on_error=1
400 DEFAULT_ENVIRONMENT="ASAN_OPTIONS=\$DEFAULT_ASAN_OPTIONS UBSAN_OPTIONS=\$DEFAULT_UBSAN_OPTIONS"
402 # As right now bash is the PID 1, we can't expect PATH to have a sane value.
403 # Let's make one to prevent unexpected "<bin> not found" issues in the future
404 export PATH="/sbin:/bin:/usr/sbin:/usr/bin"
406 mount -t proc proc /proc
407 mount -t sysfs sysfs /sys
408 mount -o remount,rw /
410 PATH_TO_ASAN=\$(find / -name '$_asan_rt_pattern' | sed 1q)
411 if [[ "\$PATH_TO_ASAN" ]]; then
412 # A lot of services (most notably dbus) won't start without preloading libasan
413 # See https://github.com/systemd/systemd/issues/5004
414 DEFAULT_ENVIRONMENT="\$DEFAULT_ENVIRONMENT LD_PRELOAD=\$PATH_TO_ASAN"
415 # Let's add the ASan DSO's path to the dynamic linker's cache. This is pretty
416 # unnecessary for gcc & libasan, however, for clang this is crucial, as its
417 # runtime ASan DSO is in a non-standard (library) path.
418 echo \${PATH_TO_ASAN%/*} > /etc/ld.so.conf.d/asan-path-override.conf
421 echo DefaultEnvironment=\$DEFAULT_ENVIRONMENT >>/etc/systemd/system.conf
422 echo DefaultTimeoutStartSec=180s >>/etc/systemd/system.conf
423 echo DefaultStandardOutput=journal+console >>/etc/systemd/system.conf
425 # ASAN and syscall filters aren't compatible with each other.
426 find / -name '*.service' -type f | xargs sed -i 's/^\\(MemoryDeny\\|SystemCall\\)/#\\1/'
428 # The redirection of ASAN reports to a file prevents them from ending up in /dev/null.
429 # But, apparently, sometimes it doesn't work: https://github.com/google/sanitizers/issues/886.
430 JOURNALD_CONF_DIR=/etc/systemd/system/systemd-journald.service.d
431 mkdir -p "\$JOURNALD_CONF_DIR"
432 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"
434 # Sometimes UBSan sends its reports to stderr regardless of what is specified in log_path
435 # Let's try to catch them by redirecting stderr (and stdout just in case) to a file
436 # See https://github.com/systemd/systemd/pull/12524#issuecomment-491108821
437 printf "[Service]\nStandardOutput=file:/systemd-journald.out\n" >"\$JOURNALD_CONF_DIR/out.conf"
439 # 90s isn't enough for some services to finish when literally everything is run
440 # under ASan+UBSan in containers, which, in turn, are run in VMs.
441 # Let's limit which environments such services should be executed in.
442 mkdir -p /etc/systemd/system/systemd-hwdb-update.service.d
443 printf "[Unit]\nConditionVirtualization=container\n\n[Service]\nTimeoutSec=180s\n" >/etc/systemd/system/systemd-hwdb-update.service.d/env-override.conf
445 # Let's override another hard-coded timeout that kicks in too early
446 mkdir -p /etc/systemd/system/systemd-journal-flush.service.d
447 printf "[Service]\nTimeoutSec=180s\n" >/etc/systemd/system/systemd-journal-flush.service.d/timeout.conf
449 # The 'mount' utility doesn't behave well under libasan, causing unexpected
450 # fails during boot and subsequent test results check:
451 # bash-5.0# mount -o remount,rw -v /
452 # mount: /dev/sda1 mounted on /.
455 # Let's workaround this by clearing the previously set LD_PRELOAD env variable,
456 # so the libasan library is not loaded for this particular service
457 REMOUNTFS_CONF_DIR=/etc/systemd/system/systemd-remount-fs.service.d
458 mkdir -p "\$REMOUNTFS_CONF_DIR"
459 printf "[Service]\nUnsetEnvironment=LD_PRELOAD\n" >"\$REMOUNTFS_CONF_DIR/env.conf"
461 export ASAN_OPTIONS=\$DEFAULT_ASAN_OPTIONS:log_path=/systemd.asan.log UBSAN_OPTIONS=\$DEFAULT_UBSAN_OPTIONS
462 exec $ROOTLIBDIR/systemd "\$@"
465 chmod 0755 $_asan_wrapper
468 create_strace_wrapper
() {
469 local _strace_wrapper
=$initdir/$ROOTLIBDIR/systemd-under-strace
470 ddebug
"Create $_strace_wrapper"
471 cat >$_strace_wrapper <<EOF
474 exec strace -D -o /strace.out $ROOTLIBDIR/systemd "\$@"
476 chmod 0755 $_strace_wrapper
480 dracut_install
/sbin
/fsck
*
481 dracut_install
-o /bin
/fsck
*
483 # fskc.reiserfs calls reiserfsck. so, install it
484 dracut_install
-o reiserfsck
488 instmods dm_crypt
=crypto
489 type -P dmeventd
>/dev
/null
&& dracut_install dmeventd
490 inst_libdir_file
"libdevmapper-event.so*"
491 if [[ "$LOOKS_LIKE_DEBIAN" ]]; then
492 # dmsetup installs 55-dm and 60-persistent-storage-dm on Debian/Ubuntu
493 # and since buster/bionic 95-dm-notify.rules
494 # see https://gitlab.com/debian-lvm/lvm2/blob/master/debian/patches/udev.patch
495 inst_rules
55-dm.rules
60-persistent-storage-dm.rules
95-dm-notify.rules
497 inst_rules
10-dm.rules
13-dm-disk.rules
95-dm-notify.rules
502 # install compiled files
503 local _ninja_bin
=$
(type -P ninja ||
type -P ninja-build
)
504 if [[ -z "$_ninja_bin" ]]; then
505 dfatal
"ninja was not found"
508 (set -x; DESTDIR
=$initdir "$_ninja_bin" -C $BUILD_DIR install)
509 # remove unneeded documentation
510 rm -fr $initdir/usr
/share
/{man
,doc
}
511 # we strip binaries since debug symbols increase binaries size a lot
512 # and it could fill the available space
515 [[ "$LOOKS_LIKE_SUSE" ]] && setup_suse
517 # enable debug logging in PID1
518 echo LogLevel
=debug
>> $initdir/etc
/systemd
/system.conf
523 objdump
-p "$_bin" 2>/dev
/null |
awk "/R(UN)?PATH/ { print \"$initdir\" \$2 }" |
paste -sd :
526 install_missing_libraries
() {
527 # install possible missing libraries
528 for i
in $initdir{,/usr
}/{sbin
,bin
}/* $initdir{,/usr
}/lib
/systemd
/{,tests
/{,manual
/,unsafe
/}}*; do
529 LD_LIBRARY_PATH
="${LD_LIBRARY_PATH:+$LD_LIBRARY_PATH:}$(get_ldpath $i)" inst_libs
$i
533 create_empty_image
() {
535 if [[ "$STRIP_BINARIES" = "no" ]]; then
538 rm -f "$TESTDIR/rootdisk.img"
539 # Create the blank file to use as a root filesystem
540 dd if=/dev
/null of
="$TESTDIR/rootdisk.img" bs
=1M seek
="$_size"
541 LOOPDEV
=$
(losetup
--show -P -f $TESTDIR/rootdisk.img
)
542 [ -b "$LOOPDEV" ] ||
return 1
543 echo "LOOPDEV=$LOOPDEV" >> $STATEFILE
544 sfdisk
"$LOOPDEV" <<EOF
551 local _label
="-L systemd"
552 # mkfs.reiserfs doesn't know -L. so, use --label instead
553 [[ "$FSTYPE" == "reiserfs" ]] && _label
="--label systemd"
554 if ! mkfs
-t "${FSTYPE}" ${_label} "${LOOPDEV}p1" -q; then
555 dfatal
"Failed to mkfs -t ${FSTYPE}"
560 check_asan_reports
() {
564 if [[ "$IS_BUILT_WITH_ASAN" = "yes" ]]; then
566 if [[ -e "$root/systemd.asan.log.1" ]]; then
567 cat "$root/systemd.asan.log.1"
571 journald_report
=$
(find "$root" -name "systemd-journald.*san.log*" -exec cat {} \
;)
572 if [[ ! -z "$journald_report" ]]; then
573 printf "%s\n" "$journald_report"
574 cat "$root/systemd-journald.out" || true
579 "$BUILD_DIR/journalctl" -D "$root/var/log/journal" | perl
-alne '
581 %services_to_ignore = (
582 "dbus-daemon" => undef,
585 print $2 if /\s(\S*)\[(\d+)\]:\s*SUMMARY:\s+\w+Sanitizer/ && !exists $services_to_ignore{$1}'
587 if [[ ! -z "$pids" ]]; then
590 "$BUILD_DIR/journalctl" -D "$root/var/log/journal" _PID
=$pid --no-pager
598 check_result_nspawn
() {
600 local journald_report
=""
602 [[ -e $TESTDIR/$1/testok
]] && ret
=0
603 [[ -f $TESTDIR/$1/failed
]] && cp -a $TESTDIR/$1/failed
$TESTDIR
604 cp -a $TESTDIR/$1/var
/log
/journal
$TESTDIR
605 [[ -f $TESTDIR/failed
]] && cat $TESTDIR/failed
606 ls -l $TESTDIR/journal
/*/*.journal
607 test -s $TESTDIR/failed
&& ret
=$
(($ret+1))
608 [ -n "$TIMED_OUT" ] && ret
=$
(($ret+1))
609 check_asan_reports
"$TESTDIR/$1" || ret
=$
(($ret+1))
613 # can be overridden in specific test
614 check_result_qemu
() {
616 mkdir
-p $TESTDIR/root
617 mount
${LOOPDEV}p1
$TESTDIR/root
618 [[ -e $TESTDIR/root
/testok
]] && ret
=0
619 [[ -f $TESTDIR/root
/failed
]] && cp -a $TESTDIR/root
/failed
$TESTDIR
620 cp -a $TESTDIR/root
/var
/log
/journal
$TESTDIR
621 check_asan_reports
"$TESTDIR/root" || ret
=$
(($ret+1))
623 [[ -f $TESTDIR/failed
]] && cat $TESTDIR/failed
624 ls -l $TESTDIR/journal
/*/*.journal
625 test -s $TESTDIR/failed
&& ret
=$
(($ret+1))
626 [ -n "$TIMED_OUT" ] && ret
=$
(($ret+1))
631 if [[ "$STRIP_BINARIES" = "no" ]]; then
632 ddebug
"Don't strip binaries"
635 ddebug
"Strip binaries"
636 find "$initdir" -executable -not -path '*/lib/modules/*.ko' -type f | \
637 xargs strip
--strip-unneeded |
& \
638 grep -v 'file format not recognized' | \
643 mkdir
-p $initdir/etc
/rc.d
644 cat >$initdir/etc
/rc.d
/rc.
local <<EOF
648 chmod 0755 $initdir/etc
/rc.d
/rc.
local
652 ddebug
"install any Execs from the service files"
654 export PKG_CONFIG_PATH
=$BUILD_DIR/src
/core
/
655 systemdsystemunitdir
=$
(pkg-config
--variable=systemdsystemunitdir systemd
)
656 systemduserunitdir
=$
(pkg-config
--variable=systemduserunitdir systemd
)
657 sed -r -n 's|^Exec[a-zA-Z]*=[@+!-]*([^ ]+).*|\1|gp' $initdir/{$systemdsystemunitdir,$systemduserunitdir}/*.service \
658 |
sort -u |
while read i
; do
659 # some {rc,halt}.local scripts and programs are okay to not exist, the rest should
660 # also, plymouth is pulled in by rescue.service, but even there the exit code
661 # is ignored; as it's not present on some distros, don't fail if it doesn't exist
662 dinfo
"Attempting to install $i"
663 inst
$i ||
[ "${i%.local}" != "$i" ] ||
[ "${i%systemd-update-done}" != "$i" ] ||
[ "/bin/plymouth" == "$i" ]
668 generate_module_dependencies
() {
669 if [[ -d $initdir/lib
/modules
/$KERNEL_VER ]] && \
670 ! depmod
-a -b "$initdir" $KERNEL_VER; then
671 dfatal
"\"depmod -a $KERNEL_VER\" failed."
676 install_depmod_files
() {
677 inst
/lib
/modules
/$KERNEL_VER/modules.order
678 inst
/lib
/modules
/$KERNEL_VER/modules.
builtin
682 # install plymouth, if found... else remove plymouth service files
683 # if [ -x /usr/libexec/plymouth/plymouth-populate-initrd ]; then
684 # PLYMOUTH_POPULATE_SOURCE_FUNCTIONS="$TEST_BASE_DIR/test-functions" \
685 # /usr/libexec/plymouth/plymouth-populate-initrd -t $initdir
686 # dracut_install plymouth plymouthd
688 rm -f $initdir/{usr
/lib
,etc
}/systemd
/system
/plymouth
* $initdir/{usr
/lib
,etc
}/systemd
/system
/*/plymouth
*
692 install_ld_so_conf
() {
693 cp -a /etc
/ld.so.conf
* $initdir/etc
694 ldconfig
-r "$initdir"
697 install_config_files
() {
698 inst
/etc
/sysconfig
/init || true
704 inst
/etc
/nsswitch.conf
705 inst
/etc
/pam.conf || true
706 inst
/etc
/securetty || true
709 # we want an empty environment
710 > $initdir/etc
/environment
711 > $initdir/etc
/machine-id
713 echo systemd-testsuite
> $initdir/etc
/hostname
715 if [[ "$LOOKS_LIKE_SUSE" ]]; then
716 ROOTMOUNT
="/dev/sda1 / ${FSTYPE} rw 0 1"
718 ROOTMOUNT
="LABEL=systemd / ${FSTYPE} rw 0 1"
721 cat >$initdir/etc
/fstab
<<EOF
726 install_basic_tools
() {
727 [[ $BASICTOOLS ]] && dracut_install
$BASICTOOLS
728 dracut_install
-o sushell
729 # in Debian ldconfig is just a shell script wrapper around ldconfig.real
730 dracut_install
-o ldconfig.real
733 install_debug_tools
() {
734 [[ $DEBUGTOOLS ]] && dracut_install
$DEBUGTOOLS
736 if [[ $INTERACTIVE_DEBUG ]]; then
737 # Set default TERM from vt220 to linux, so at least basic key shortcuts work
738 local _getty_override
="$initdir/etc/systemd/system/serial-getty@.service.d"
739 mkdir
-p "$_getty_override"
740 echo -e "[Service]\nEnvironment=TERM=linux" > "$_getty_override/default-TERM.conf"
742 cat > "$initdir/etc/motd" << EOF
743 To adjust the terminal size use:
753 # install libnss_files for login
754 NSS_LIBS
=$
(LD_DEBUG
=files getent passwd
2>&1 >/dev
/null |
sed -n '/calling init: .*libnss_/ {s!^.* /!/!; p}')
755 dracut_install
$NSS_LIBS
759 inst
$ROOTLIBDIR/system
/dbus.socket
761 # Newer Fedora versions use dbus-broker by default. Let's install it is available.
762 if [ -f $ROOTLIBDIR/system
/dbus-broker.service
]; then
763 inst
$ROOTLIBDIR/system
/dbus-broker.service
764 inst_symlink
/etc
/systemd
/system
/dbus.service
765 inst
/usr
/bin
/dbus-broker
766 inst
/usr
/bin
/dbus-broker-launch
767 elif [ -f $ROOTLIBDIR/system
/dbus-daemon.service
]; then
768 # Fedora rawhide replaced dbus.service with dbus-daemon.service
769 inst
$ROOTLIBDIR/system
/dbus-daemon.service
771 inst_symlink
/etc
/systemd
/system
/dbus.service
773 inst
$ROOTLIBDIR/system
/dbus.service
777 /etc
/dbus-1
/usr
/share
/dbus-1
-xtype f \
778 |
while read file; do
785 if [[ "$LOOKS_LIKE_DEBIAN" ]] && type -p dpkg-architecture
&>/dev
/null
; then
786 find "/lib/$(dpkg-architecture -qDEB_HOST_MULTIARCH)/security" -xtype f
788 find /lib
*/security
-xtype f
790 find /etc
/pam.d
/etc
/security
-xtype f
791 ) |
while read file; do
795 # pam_unix depends on unix_chkpwd.
796 # see http://www.linux-pam.org/Linux-PAM-html/sag-pam_unix.html
797 dracut_install
-o unix_chkpwd
799 [[ "$LOOKS_LIKE_DEBIAN" ]] &&
800 cp /etc
/pam.d
/systemd-user
$initdir/etc
/pam.d
/
802 # set empty root password for easy debugging
803 sed -i 's/^root:x:/root::/' $initdir/etc
/passwd
807 # The first three paths may be deprecated.
808 # It seems now the last two paths are used by many distributions.
810 /usr
/lib
/kbd
/keymaps
/include
/* \
811 /usr
/lib
/kbd
/keymaps
/i386
/include
/* \
812 /usr
/lib
/kbd
/keymaps
/i386
/qwerty
/us.
* \
813 /usr
/lib
/kbd
/keymaps
/legacy
/include
/* \
814 /usr
/lib
/kbd
/keymaps
/legacy
/i386
/qwerty
/us.
*; do
815 [[ -f $i ]] ||
continue
819 # When it takes any argument, then install more keymaps.
822 /usr
/lib
/kbd
/keymaps
/i386
/*/* \
823 /usr
/lib
/kbd
/keymaps
/legacy
/i386
/*/*; do
824 [[ -f $i ]] ||
continue
831 for i
in /usr
/share
/zoneinfo
/{,*/,*/*/}*; do
832 [[ -f $i ]] ||
continue
839 /usr
/lib
/kbd
/consolefonts
/eurlatgr
* \
840 /usr
/lib
/kbd
/consolefonts
/latarcyrheb-sun16
*; do
841 [[ -f $i ]] ||
continue
847 for _terminfodir
in /lib
/terminfo
/etc
/terminfo
/usr
/share
/terminfo
; do
848 [ -f ${_terminfodir}/l
/linux
] && break
850 dracut_install
-o ${_terminfodir}/l
/linux
854 cp $TEST_BASE_DIR/testsuite.target
$initdir/etc
/systemd
/system
/
855 cp $TEST_BASE_DIR/end.service
$initdir/etc
/systemd
/system
/
857 mkdir
-p $initdir/etc
/systemd
/system
/testsuite.target.wants
858 ln -fs $TEST_BASE_DIR/testsuite.service
$initdir/etc
/systemd
/system
/testsuite.target.wants
/testsuite.service
859 # Don't shutdown the machine after running the test when INTERACTIVE_DEBUG is set
860 [[ -z $INTERACTIVE_DEBUG ]] && ln -fs $TEST_BASE_DIR/end.service
$initdir/etc
/systemd
/system
/testsuite.target.wants
/end.service
862 # make the testsuite the default target
863 ln -fs testsuite.target
$initdir/etc
/systemd
/system
/default.target
866 setup_nspawn_root
() {
867 rm -fr $TESTDIR/nspawn-root
868 ddebug
"cp -ar $initdir $TESTDIR/nspawn-root"
869 cp -ar $initdir $TESTDIR/nspawn-root
870 # we don't mount in the nspawn root
871 rm -f $TESTDIR/nspawn-root
/etc
/fstab
872 if [[ "$RUN_IN_UNPRIVILEGED_CONTAINER" = "yes" ]]; then
873 cp -ar $TESTDIR/nspawn-root
$TESTDIR/unprivileged-nspawn-root
878 mkdir
-p $initdir/run
879 mkdir
-p $initdir/etc
/systemd
/system
880 mkdir
-p $initdir/var
/log
/journal
882 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
883 if [ -L "/$d" ]; then
890 ln -sfn /run
"$initdir/var/run"
891 ln -sfn /run
/lock
"$initdir/var/lock"
896 local _so_regex
='([^ ]*/lib[^/]*/[^ ]*\.so[^ ]*)'
899 LC_ALL
=C ldd
"$_bin" 2>/dev
/null |
while read _line
; do
900 [[ $_line = 'not a dynamic executable' ]] && break
902 if [[ $_line =~
$_so_regex ]]; then
903 _file
=${BASH_REMATCH[1]}
904 [[ -e ${initdir}/$_file ]] && continue
905 inst_library
"$_file"
909 if [[ $_line =~ not\ found
]]; then
910 dfatal
"Missing a shared library required by $_bin."
911 dfatal
"Run \"ldd $_bin\" to find out what it is."
913 dfatal
"dracut cannot create an initrd."
920 [[ -e $STATEFILE ]] && .
$STATEFILE
921 if [[ ! -d "$TESTDIR" ]]; then
922 if [[ -z "$TESTDIR" ]]; then
923 TESTDIR
=$
(mktemp
--tmpdir=/var
/tmp
-d -t systemd-test.XXXXXX
)
928 echo "TESTDIR=\"$TESTDIR\"" > $STATEFILE
934 initdir
=$TESTDIR/root
938 ## @brief Converts numeric logging level to the first letter of level name.
940 # @param lvl Numeric logging level in range from 1 to 6.
941 # @retval 1 if @a lvl is out of range.
942 # @retval 0 if @a lvl is correct.
943 # @result Echoes first letter of level name.
956 ## @brief Internal helper function for _do_dlog()
958 # @param lvl Numeric logging level.
959 # @param msg Message.
960 # @retval 0 It's always returned, even if logging failed.
962 # @note This function is not supposed to be called manually. Please use
963 # dtrace(), ddebug(), or others instead which wrap this one.
965 # This function calls _do_dlog() either with parameter msg, or if
966 # none is given, it will read standard input and will use every line as
970 # dwarn "This is a warning"
971 # echo "This is a warning" | dwarn
972 LOG_LEVEL
=${LOG_LEVEL:-4}
975 [ -z "$LOG_LEVEL" ] && return 0
976 [ $1 -le $LOG_LEVEL ] ||
return 0
977 local lvl
="$1"; shift
978 local lvlc
=$
(_lvl2char
"$lvl") ||
return 0
980 if [ $# -ge 1 ]; then
984 echo "$lvlc: " "$line"
989 ## @brief Logs message at TRACE level (6)
991 # @param msg Message.
992 # @retval 0 It's always returned, even if logging failed.
996 [ -n "$debug" ] && set -x ||
:
999 ## @brief Logs message at DEBUG level (5)
1001 # @param msg Message.
1002 # @retval 0 It's always returned, even if logging failed.
1006 # [ -n "$debug" ] && set -x || :
1009 ## @brief Logs message at INFO level (4)
1011 # @param msg Message.
1012 # @retval 0 It's always returned, even if logging failed.
1016 [ -n "$debug" ] && set -x ||
:
1019 ## @brief Logs message at WARN level (3)
1021 # @param msg Message.
1022 # @retval 0 It's always returned, even if logging failed.
1026 [ -n "$debug" ] && set -x ||
:
1029 ## @brief Logs message at ERROR level (2)
1031 # @param msg Message.
1032 # @retval 0 It's always returned, even if logging failed.
1036 # [ -n "$debug" ] && set -x || :
1039 ## @brief Logs message at FATAL level (1)
1041 # @param msg Message.
1042 # @retval 0 It's always returned, even if logging failed.
1046 [ -n "$debug" ] && set -x ||
:
1050 # Generic substring function. If $2 is in $1, return 0.
1051 strstr
() { [ "${1#*$2*}" != "$1" ]; }
1053 # normalize_path <path>
1054 # Prints the normalized path, where it removes any duplicated
1055 # and trailing slashes.
1057 # $ normalize_path ///test/test//
1061 set -- "${1//+(\/)//}"
1066 # convert_abs_rel <from> <to>
1067 # Prints the relative path, when creating a symlink to <to> from <from>.
1069 # $ convert_abs_rel /usr/bin/test /bin/test-2
1071 # $ ln -s $(convert_abs_rel /usr/bin/test /bin/test-2) /usr/bin/test
1073 local __current __absolute __abssize __cursize __newpath
1074 local -i __i __level
1076 set -- "$(normalize_path "$1")" "$(normalize_path "$2")"
1078 # corner case #1 - self looping link
1079 [[ "$1" == "$2" ]] && { echo "${1##*/}"; return; }
1081 # corner case #2 - own dir link
1082 [[ "${1%/*}" == "$2" ]] && { echo "."; return; }
1084 IFS
="/" __current
=($1)
1085 IFS
="/" __absolute
=($2)
1087 __abssize
=${#__absolute[@]}
1088 __cursize
=${#__current[@]}
1090 while [[ ${__absolute[__level]} == ${__current[__level]} ]]
1093 if (( __level
> __abssize || __level
> __cursize
))
1099 for ((__i
= __level
; __i
< __cursize-1
; __i
++))
1101 if ((__i
> __level
))
1103 __newpath
=$__newpath"/"
1105 __newpath
=$__newpath".."
1108 for ((__i
= __level
; __i
< __abssize
; __i
++))
1110 if [[ -n $__newpath ]]
1112 __newpath
=$__newpath"/"
1114 __newpath
=$__newpath${__absolute[__i]}
1121 # Install a directory, keeping symlinks as on the original system.
1122 # Example: if /lib points to /lib64 on the host, "inst_dir /lib/file"
1123 # will create ${initdir}/lib64, ${initdir}/lib64/file,
1124 # and a symlink ${initdir}/lib -> lib64.
1126 [[ -e ${initdir}/"$1" ]] && return 0 # already there
1128 local _dir
="$1" _part
="${1%/*}" _file
1129 while [[ "$_part" != "${_part%/*}" ]] && ! [[ -e "${initdir}/${_part}" ]]; do
1134 # iterate over parent directories
1135 for _file
in $_dir; do
1136 [[ -e "${initdir}/$_file" ]] && continue
1137 if [[ -L $_file ]]; then
1138 inst_symlink
"$_file"
1141 mkdir
-m 0755 -p "${initdir}/$_file" ||
return 1
1142 [[ -e "$_file" ]] && chmod --reference="$_file" "${initdir}/$_file"
1143 chmod u
+w
"${initdir}/$_file"
1148 # $1 = file to copy to ramdisk
1149 # $2 (optional) Name for the file on the ramdisk
1150 # Location of the image dir is assumed to be $initdir
1151 # We never overwrite the target if it exists.
1153 [[ -f "$1" ]] ||
return 1
1154 strstr
"$1" "/" ||
return 1
1156 local _src
=$1 target
="${2:-$1}"
1157 if ! [[ -d ${initdir}/$target ]]; then
1158 [[ -e ${initdir}/$target ]] && return 0
1159 [[ -L ${initdir}/$target ]] && return 0
1160 [[ -d "${initdir}/${target%/*}" ]] || inst_dir "${target%/*}"
1162 # install checksum files also
1163 if [[ -e "${_src%/*}/.${_src##*/}.hmac" ]]; then
1164 inst
"${_src%/*}/.${_src##*/}.hmac" "${target%/*}/.${target##*/}.hmac"
1166 ddebug
"Installing $_src"
1167 cp --sparse=always
-pfL "$_src" "${initdir}/$target"
1170 # find symlinks linked to given library file
1172 # Function searches for symlinks by stripping version numbers appended to
1173 # library filename, checks if it points to the same target and finally
1174 # prints the list of symlinks to stdout.
1177 # rev_lib_symlinks libfoo.so.8.1
1178 # output: libfoo.so.8 libfoo.so
1179 # (Only if libfoo.so.8 and libfoo.so exists on host system.)
1180 rev_lib_symlinks
() {
1181 [[ ! $1 ]] && return 0
1183 local fn
="$1" orig
="$(readlink -f "$1")" links
=''
1185 [[ ${fn} =~ .
*\.so\..
* ]] ||
return 1
1187 until [[ ${fn##*.} == so
]]; do
1189 [[ -L ${fn} && $(readlink -f "${fn}") == ${orig} ]] && links+=" ${fn}"
1195 # Same as above, but specialized to handle dynamic libraries.
1196 # It handles making symlinks according to how the original library
1199 local _src="$1" _dest=${2:-$1} _lib _reallib _symlink
1200 strstr "$1" "/" || return 1
1201 [[ -e $initdir/$_dest ]] && return 0
1202 if [[ -L $_src ]]; then
1203 # install checksum files also
1204 if [[ -e "${_src%/*}/.
${_src##*/}.hmac
" ]]; then
1205 inst "${_src%/*}/.${_src##*/}.hmac" "${_dest%/*}/.${_dest##*/}.hmac
"
1207 _reallib=$(readlink -f "$_src")
1208 inst_simple "$_reallib" "$_reallib"
1209 inst_dir "${_dest%/*}"
1210 [[ -d "${_dest%/*}" ]] && _dest=$(readlink -f "${_dest%/*}")/${_dest##*/}
1211 ln -sfn $
(convert_abs_rel
"${_dest}" "${_reallib}") "${initdir}/${_dest}"
1213 inst_simple
"$_src" "$_dest"
1216 # Create additional symlinks. See rev_symlinks description.
1217 for _symlink
in $
(rev_lib_symlinks
$_src) $
(rev_lib_symlinks
$_reallib); do
1218 [[ -e $initdir/$_symlink ]] ||
{
1219 ddebug
"Creating extra symlink: $_symlink"
1220 inst_symlink
$_symlink
1225 # find a binary. If we were not passed the full path directly,
1226 # search in the usual places to find the binary.
1228 if [[ -z ${1##/*} ]]; then
1229 if [[ -x $1 ]] ||
{ strstr
"$1" ".so" && ldd
$1 &>/dev
/null
; }; then
1238 # Same as above, but specialized to install binary executables.
1239 # Install binary executable, and all shared library dependencies, if any.
1243 # In certain cases we might attempt to install a binary which is already
1244 # present in the test image, yet it's missing from the host system.
1245 # In such cases, let's check if the binary indeed exists in the image
1246 # before doing any other chcecks. If it does, immediately return with
1248 [[ $# -eq 1 && -e $initdir/$1 ]] && return 0
1250 _bin
=$
(find_binary
"$1") ||
return 1
1252 [[ -e $initdir/$_target ]] && return 0
1253 [[ -L $_bin ]] && inst_symlink
$_bin $_target && return 0
1255 local _so_regex
='([^ ]*/lib[^/]*/[^ ]*\.so[^ ]*)'
1257 LC_ALL
=C ldd
"$_bin" 2>/dev
/null |
while read _line
; do
1258 [[ $_line = 'not a dynamic executable' ]] && break
1260 if [[ $_line =~
$_so_regex ]]; then
1261 _file
=${BASH_REMATCH[1]}
1262 [[ -e ${initdir}/$_file ]] && continue
1263 inst_library
"$_file"
1267 if [[ $_line =~ not\ found
]]; then
1268 dfatal
"Missing a shared library required by $_bin."
1269 dfatal
"Run \"ldd $_bin\" to find out what it is."
1271 dfatal
"dracut cannot create an initrd."
1275 inst_simple
"$_bin" "$_target"
1278 # same as above, except for shell scripts.
1279 # If your shell script does not start with shebang, it is not a shell script.
1282 _bin
=$
(find_binary
"$1") ||
return 1
1284 local _line _shebang_regex
1285 read -r -n 80 _line
<"$_bin"
1286 # If debug is set, clean unprintable chars to prevent messing up the term
1287 [[ $debug ]] && _line
=$
(echo -n "$_line" |
tr -c -d '[:print:][:space:]')
1288 _shebang_regex
='(#! *)(/[^ ]+).*'
1289 [[ $_line =~
$_shebang_regex ]] ||
return 1
1290 inst
"${BASH_REMATCH[2]}" && inst_simple
"$_bin" "$@"
1293 # same as above, but specialized for symlinks
1295 local _src
=$1 _target
=${2:-$1} _realsrc
1296 strstr
"$1" "/" ||
return 1
1297 [[ -L $1 ]] ||
return 1
1298 [[ -L $initdir/$_target ]] && return 0
1299 _realsrc
=$
(readlink
-f "$_src")
1300 if ! [[ -e $initdir/$_realsrc ]]; then
1301 if [[ -d $_realsrc ]]; then
1302 inst_dir
"$_realsrc"
1307 [[ ! -e $initdir/${_target%/*} ]] && inst_dir
"${_target%/*}"
1308 [[ -d ${_target%/*} ]] && _target=$(readlink -f ${_target%/*})/${_target##*/}
1309 ln -sfn $
(convert_abs_rel
"${_target}" "${_realsrc}") "$initdir/$_target"
1312 # attempt to install any programs specified in a udev rule
1313 inst_rule_programs
() {
1316 if grep -qE 'PROGRAM==?"[^ "]+' "$1"; then
1317 for _prog
in $
(grep -E 'PROGRAM==?"[^ "]+' "$1" |
sed -r 's/.*PROGRAM==?"([^ "]+).*/\1/'); do
1318 if [ -x /lib
/udev
/$_prog ]; then
1319 _bin
=/lib
/udev
/$_prog
1321 _bin
=$
(find_binary
"$_prog") ||
{
1322 dinfo
"Skipping program $_prog using in udev rule $(basename $1) as it cannot be found"
1327 #dinfo "Installing $_bin due to it's use in the udev rule $(basename $1)"
1328 dracut_install
"$_bin"
1333 # udev rules always get installed in the same place, so
1334 # create a function to install them to make life simpler.
1336 local _target
=/etc
/udev
/rules.d _rule _found
1338 inst_dir
"/lib/udev/rules.d"
1340 for _rule
in "$@"; do
1341 if [ "${rule#/}" = "$rule" ]; then
1342 for r
in /lib
/udev
/rules.d
/etc
/udev
/rules.d
; do
1343 if [[ -f $r/$_rule ]]; then
1345 inst_simple
"$_found"
1346 inst_rule_programs
"$_found"
1350 for r
in '' .
/ $dracutbasedir/rules.d
/; do
1351 if [[ -f ${r}$_rule ]]; then
1353 inst_simple
"$_found" "$_target/${_found##*/}"
1354 inst_rule_programs
"$_found"
1357 [[ $_found ]] || dinfo
"Skipping udev rule: $_rule"
1362 # general purpose installation function
1363 # Same args as above.
1369 2) [[ ! $initdir && -d $2 ]] && export initdir
=$2
1370 [[ $initdir = $2 ]] && set $1;;
1371 3) [[ -z $initdir ]] && export initdir
=$2
1373 *) dfatal
"inst only takes 1 or 2 or 3 arguments"
1376 for _x
in inst_symlink inst_script inst_binary inst_simple
; do
1377 $_x "$@" && return 0
1382 # install any of listed files
1384 # If first argument is '-d' and second some destination path, first accessible
1385 # source is installed into this path, otherwise it will installed in the same
1386 # path as source. If none of listed files was installed, function return 1.
1387 # On first successful installation it returns with 0 status.
1391 # inst_any -d /bin/foo /bin/bar /bin/baz
1393 # Lets assume that /bin/baz exists, so it will be installed as /bin/foo in
1398 [[ $1 = '-d' ]] && to
="$2" && shift 2
1401 if [[ -e $f ]]; then
1402 [[ $to ]] && inst
"$f" "$to" && return 0
1403 inst
"$f" && return 0
1410 # dracut_install [-o ] <file> [<file> ... ]
1411 # Install <file> to the initramfs image
1412 # -o optionally install the <file> and don't fail, if it is not there
1415 if [[ $1 = '-o' ]]; then
1419 while (($# > 0)); do
1420 if ! inst
"$1" ; then
1421 if [[ $_optional = yes ]]; then
1422 dinfo
"Skipping program $1 as it cannot be found and is" \
1423 "flagged to be optional"
1425 dfatal
"Failed to install $1"
1433 # Install a single kernel module along with any firmware it may require.
1434 # $1 = full path to kernel module to install
1435 install_kmod_with_fw
() {
1436 # no need to go further if the module is already installed
1438 [[ -e "${initdir}/lib/modules/$KERNEL_VER/${1##*/lib/modules/$KERNEL_VER/}" ]] \
1441 [[ -e "$initdir/.kernelmodseen/${1##*/}" ]] && return 0
1443 if [[ $omit_drivers ]]; then
1444 local _kmod
=${1##*/}
1447 if [[ "$_kmod" =~
$omit_drivers ]]; then
1448 dinfo
"Omitting driver $_kmod"
1451 if [[ "${1##*/lib/modules/$KERNEL_VER/}" =~
$omit_drivers ]]; then
1452 dinfo
"Omitting driver $_kmod"
1457 [ -d "$initdir/.kernelmodseen" ] && \
1458 > "$initdir/.kernelmodseen/${1##*/}"
1460 inst_simple
"$1" "/lib/modules/$KERNEL_VER/${1##*/lib/modules/$KERNEL_VER/}" \
1463 local _modname
=${1##*/} _fwdir _found _fw
1464 _modname
=${_modname%.ko*}
1465 for _fw
in $
(modinfo
-k $KERNEL_VER -F firmware
$1 2>/dev
/null
); do
1467 for _fwdir
in $fw_dir; do
1468 if [[ -d $_fwdir && -f $_fwdir/$_fw ]]; then
1469 inst_simple
"$_fwdir/$_fw" "/lib/firmware/$_fw"
1473 if [[ $_found != yes ]]; then
1474 if ! grep -qe "\<${_modname//-/_}\>" /proc
/modules
; then
1475 dinfo
"Possible missing firmware \"${_fw}\" for kernel module" \
1476 "\"${_modname}.ko\""
1478 dwarn
"Possible missing firmware \"${_fw}\" for kernel module" \
1479 "\"${_modname}.ko\""
1486 # Do something with all the dependencies of a kernel module.
1487 # Note that kernel modules depend on themselves using the technique we use
1488 # $1 = function to call for each dependency we find
1489 # It will be passed the full path to the found kernel module
1490 # $2 = module to get dependencies for
1491 # rest of args = arguments to modprobe
1492 # _fderr specifies FD passed from surrounding scope
1493 for_each_kmod_dep
() {
1494 local _func
=$1 _kmod
=$2 _cmd _modpath _options _found
=0
1496 modprobe
"$@" --ignore-install --show-depends $_kmod 2>&${_fderr} |
(
1497 while read _cmd _modpath _options
; do
1498 [[ $_cmd = insmod
]] ||
continue
1499 $_func ${_modpath} ||
exit $?
1502 [[ $_found -eq 0 ]] && exit 1
1507 # filter kernel modules to install certain modules that meet specific
1509 # $1 = search only in subdirectory of /kernel/$1
1510 # $2 = function to call with module name to filter.
1511 # This function will be passed the full path to the module to test.
1512 # The behavior of this function can vary depending on whether $hostonly is set.
1513 # If it is, we will only look at modules that are already in memory.
1514 # If it is not, we will look at all kernel modules
1515 # This function returns the full filenames of modules that match $1
1516 filter_kernel_modules_by_path
() (
1517 local _modname _filtercmd
1518 if ! [[ $hostonly ]]; then
1519 _filtercmd
='find "$KERNEL_MODS/kernel/$1" "$KERNEL_MODS/extra"'
1520 _filtercmd
+=' "$KERNEL_MODS/weak-updates" -name "*.ko" -o -name "*.ko.gz"'
1521 _filtercmd
+=' -o -name "*.ko.xz"'
1522 _filtercmd
+=' 2>/dev/null'
1524 _filtercmd
='cut -d " " -f 1 </proc/modules|xargs modinfo -F filename '
1525 _filtercmd
+='-k $KERNEL_VER 2>/dev/null'
1527 for _modname
in $
(eval $_filtercmd); do
1529 *.ko
) "$2" "$_modname" && echo "$_modname";;
1530 *.ko.gz
) gzip -dc "$_modname" > $initdir/$$.ko
1531 $2 $initdir/$$.ko
&& echo "$_modname"
1532 rm -f $initdir/$$.ko
1534 *.ko.xz
) xz
-dc "$_modname" > $initdir/$$.ko
1535 $2 $initdir/$$.ko
&& echo "$_modname"
1536 rm -f $initdir/$$.ko
1541 find_kernel_modules_by_path
() (
1542 if ! [[ $hostonly ]]; then
1543 find "$KERNEL_MODS/kernel/$1" "$KERNEL_MODS/extra" "$KERNEL_MODS/weak-updates" \
1544 -name "*.ko" -o -name "*.ko.gz" -o -name "*.ko.xz" 2>/dev
/null
1546 cut
-d " " -f 1 </proc
/modules \
1547 |
xargs modinfo
-F filename
-k $KERNEL_VER 2>/dev
/null
1551 filter_kernel_modules
() {
1552 filter_kernel_modules_by_path drivers
"$1"
1555 find_kernel_modules
() {
1556 find_kernel_modules_by_path drivers
1559 # instmods [-c] <kernel module> [<kernel module> ... ]
1560 # instmods [-c] <kernel subsystem>
1561 # install kernel modules along with all their dependencies.
1562 # <kernel subsystem> can be e.g. "=block" or "=drivers/usb/storage"
1564 [[ $no_kernel = yes ]] && return
1565 # called [sub]functions inherit _fderr
1568 if [[ $1 = '-c' ]]; then
1573 function inst1mod
() {
1574 local _ret
=0 _mod
="$1"
1577 if [ -f $KERNEL_MODS/modules.
${_mod#=} ]; then
1578 ( [[ "$_mpargs" ]] && echo $_mpargs
1579 cat "${KERNEL_MODS}/modules.${_mod#=}" ) \
1582 ( [[ "$_mpargs" ]] && echo $_mpargs
1583 find "$KERNEL_MODS" -path "*/${_mod#=}/*" -printf '%f\n' ) \
1587 --*) _mpargs
+=" $_mod" ;;
1588 i2o_scsi
) return ;; # Do not load this diagnostic-only module
1591 # if we are already installed, skip this module and go on
1593 [[ -f "$initdir/.kernelmodseen/${_mod%.ko}.ko" ]] && return
1595 if [[ $omit_drivers ]] && [[ "$1" =~
$omit_drivers ]]; then
1596 dinfo
"Omitting driver ${_mod##$KERNEL_MODS}"
1599 # If we are building a host-specific initramfs and this
1600 # module is not already loaded, move on to the next one.
1601 [[ $hostonly ]] && ! grep -qe "\<${_mod//-/_}\>" /proc
/modules \
1602 && ! echo $add_drivers |
grep -qe "\<${_mod}\>" \
1605 # We use '-d' option in modprobe only if modules prefix path
1606 # differs from default '/'. This allows us to use Dracut with
1607 # old version of modprobe which doesn't have '-d' option.
1608 local _moddirname
=${KERNEL_MODS%%/lib/modules/*}
1609 [[ -n ${_moddirname} ]] && _moddirname
="-d ${_moddirname}/"
1611 # ok, load the module, all its dependencies, and any firmware
1613 for_each_kmod_dep install_kmod_with_fw
$_mod \
1614 --set-version $KERNEL_VER ${_moddirname} $_mpargs
1621 function instmods_1
() {
1623 if (($# == 0)); then # filenames from stdin
1625 inst1mod
"${_mod%.ko*}" ||
{
1626 if [ "$_check" = "yes" ]; then
1627 dfatal
"Failed to install $_mod"
1633 while (($# > 0)); do # filenames as arguments
1634 inst1mod
${1%.ko*} ||
{
1635 if [ "$_check" = "yes" ]; then
1636 dfatal
"Failed to install $1"
1645 local _ret _filter_not_found
='FATAL: Module .* not found.'
1647 # Capture all stderr from modprobe to _fderr. We could use {var}>...
1648 # redirections, but that would make dracut require bash4 at least.
1649 eval "( instmods_1 \"\$@\" ) ${_fderr}>&1" \
1650 |
while read line
; do [[ "$line" =~
$_filter_not_found ]] && echo $line ||
echo $line >&2 ;done | derror
1656 # inst_libdir_file [-n <pattern>] <file> [<file>...]
1657 # Install a <file> located on a lib directory to the initramfs image
1658 # -n <pattern> install non-matching files
1659 inst_libdir_file
() {
1660 if [[ "$1" == "-n" ]]; then
1663 for _dir
in $libdirs; do
1665 for _f
in "$_dir"/$_i; do
1666 [[ "$_i" =~
$_pattern ]] ||
continue
1667 [[ -e "$_i" ]] && dracut_install
"$_i"
1672 for _dir
in $libdirs; do
1674 for _f
in "$_dir"/$_i; do
1675 [[ -e "$_f" ]] && dracut_install
"$_f"
1683 ln -fs ..
/usr
/bin
/systemctl
$initdir/bin
/
1684 ln -fs ..
/usr
/lib
/systemd
$initdir/lib
/
1685 inst_simple
"/usr/lib/systemd/system/haveged.service"
1688 # can be overridden in specific test
1690 umount
$TESTDIR/root
2>/dev
/null || true
1691 [[ $LOOPDEV ]] && losetup
-d $LOOPDEV || true
1696 if [ -z "$TEST_NO_QEMU" ]; then
1698 check_result_qemu ||
return 1
1700 dwarn
"can't run QEMU, skipping"
1703 if [ -z "$TEST_NO_NSPAWN" ]; then
1704 if run_nspawn
"nspawn-root"; then
1705 check_result_nspawn
"nspawn-root" ||
return 1
1707 dwarn
"can't run systemd-nspawn, skipping"
1710 if [[ "$RUN_IN_UNPRIVILEGED_CONTAINER" = "yes" ]]; then
1711 if NSPAWN_ARGUMENTS
="-U --private-network $NSPAWN_ARGUMENTS" run_nspawn
"unprivileged-nspawn-root"; then
1712 check_result_nspawn
"unprivileged-nspawn-root" ||
return 1
1714 dwarn
"can't run systemd-nspawn, skipping"
1722 if [[ $UID != "0" ]]; then
1723 echo "TEST: $TEST_DESCRIPTION [SKIPPED]: not root" >&2
1728 [[ $libdir ]] ||
for libdir
in /lib64
/lib
; do
1729 [[ -d $libdir ]] && libdirs
+=" $libdir" && break
1732 [[ $usrlibdir ]] ||
for usrlibdir
in /usr
/lib64
/usr
/lib
; do
1733 [[ -d $usrlibdir ]] && libdirs
+=" $usrlibdir" && break
1736 mkdir
-p "$STATEDIR"
1741 while (($# > 0)); do
1744 echo "TEST RUN: $TEST_DESCRIPTION"
1747 if (( $ret == 0 )); then
1748 echo "TEST RUN: $TEST_DESCRIPTION [OK]"
1750 echo "TEST RUN: $TEST_DESCRIPTION [FAILED]"
1754 echo "TEST SETUP: $TEST_DESCRIPTION"
1758 echo "TEST CLEANUP: $TEST_DESCRIPTION"
1765 echo -n "TEST: $TEST_DESCRIPTION ";
1767 test_setup
&& test_run
1773 ) </dev
/null
>"$TESTLOG" 2>&1 || ret
=$?
1774 if [ $ret -eq 0 ]; then