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 inst
$i ||
[ "${i%.local}" != "$i" ] ||
[ "${i%systemd-update-done}" != "$i" ] ||
[ "/bin/plymouth" == "$i" ]
667 generate_module_dependencies
() {
668 if [[ -d $initdir/lib
/modules
/$KERNEL_VER ]] && \
669 ! depmod
-a -b "$initdir" $KERNEL_VER; then
670 dfatal
"\"depmod -a $KERNEL_VER\" failed."
675 install_depmod_files
() {
676 inst
/lib
/modules
/$KERNEL_VER/modules.order
677 inst
/lib
/modules
/$KERNEL_VER/modules.
builtin
681 # install plymouth, if found... else remove plymouth service files
682 # if [ -x /usr/libexec/plymouth/plymouth-populate-initrd ]; then
683 # PLYMOUTH_POPULATE_SOURCE_FUNCTIONS="$TEST_BASE_DIR/test-functions" \
684 # /usr/libexec/plymouth/plymouth-populate-initrd -t $initdir
685 # dracut_install plymouth plymouthd
687 rm -f $initdir/{usr
/lib
,etc
}/systemd
/system
/plymouth
* $initdir/{usr
/lib
,etc
}/systemd
/system
/*/plymouth
*
691 install_ld_so_conf
() {
692 cp -a /etc
/ld.so.conf
* $initdir/etc
693 ldconfig
-r "$initdir"
696 install_config_files
() {
697 inst
/etc
/sysconfig
/init || true
703 inst
/etc
/nsswitch.conf
704 inst
/etc
/pam.conf || true
705 inst
/etc
/securetty || true
708 # we want an empty environment
709 > $initdir/etc
/environment
710 > $initdir/etc
/machine-id
712 echo systemd-testsuite
> $initdir/etc
/hostname
714 if [[ "$LOOKS_LIKE_SUSE" ]]; then
715 ROOTMOUNT
="/dev/sda1 / ${FSTYPE} rw 0 1"
717 ROOTMOUNT
="LABEL=systemd / ${FSTYPE} rw 0 1"
720 cat >$initdir/etc
/fstab
<<EOF
725 install_basic_tools
() {
726 [[ $BASICTOOLS ]] && dracut_install
$BASICTOOLS
727 dracut_install
-o sushell
728 # in Debian ldconfig is just a shell script wrapper around ldconfig.real
729 dracut_install
-o ldconfig.real
732 install_debug_tools
() {
733 [[ $DEBUGTOOLS ]] && dracut_install
$DEBUGTOOLS
735 if [[ $INTERACTIVE_DEBUG ]]; then
736 # Set default TERM from vt220 to linux, so at least basic key shortcuts work
737 local _getty_override
="$initdir/etc/systemd/system/serial-getty@.service.d"
738 mkdir
-p "$_getty_override"
739 echo -e "[Service]\nEnvironment=TERM=linux" > "$_getty_override/default-TERM.conf"
741 cat > "$initdir/etc/motd" << EOF
742 To adjust the terminal size use:
752 # install libnss_files for login
753 NSS_LIBS
=$
(LD_DEBUG
=files getent passwd
2>&1 >/dev
/null |
sed -n '/calling init: .*libnss_/ {s!^.* /!/!; p}')
754 dracut_install
$NSS_LIBS
758 inst
$ROOTLIBDIR/system
/dbus.socket
760 # Newer Fedora versions use dbus-broker by default. Let's install it is available.
761 if [ -f $ROOTLIBDIR/system
/dbus-broker.service
]; then
762 inst
$ROOTLIBDIR/system
/dbus-broker.service
763 inst_symlink
/etc
/systemd
/system
/dbus.service
764 inst
/usr
/bin
/dbus-broker
765 inst
/usr
/bin
/dbus-broker-launch
766 elif [ -f $ROOTLIBDIR/system
/dbus-daemon.service
]; then
767 # Fedora rawhide replaced dbus.service with dbus-daemon.service
768 inst
$ROOTLIBDIR/system
/dbus-daemon.service
770 inst_symlink
/etc
/systemd
/system
/dbus.service
772 inst
$ROOTLIBDIR/system
/dbus.service
776 /etc
/dbus-1
/usr
/share
/dbus-1
-xtype f \
777 |
while read file; do
784 if [[ "$LOOKS_LIKE_DEBIAN" ]] && type -p dpkg-architecture
&>/dev
/null
; then
785 find "/lib/$(dpkg-architecture -qDEB_HOST_MULTIARCH)/security" -xtype f
787 find /lib
*/security
-xtype f
789 find /etc
/pam.d
/etc
/security
-xtype f
790 ) |
while read file; do
794 # pam_unix depends on unix_chkpwd.
795 # see http://www.linux-pam.org/Linux-PAM-html/sag-pam_unix.html
796 dracut_install
-o unix_chkpwd
798 [[ "$LOOKS_LIKE_DEBIAN" ]] &&
799 cp /etc
/pam.d
/systemd-user
$initdir/etc
/pam.d
/
801 # set empty root password for easy debugging
802 sed -i 's/^root:x:/root::/' $initdir/etc
/passwd
806 # The first three paths may be deprecated.
807 # It seems now the last two paths are used by many distributions.
809 /usr
/lib
/kbd
/keymaps
/include
/* \
810 /usr
/lib
/kbd
/keymaps
/i386
/include
/* \
811 /usr
/lib
/kbd
/keymaps
/i386
/qwerty
/us.
* \
812 /usr
/lib
/kbd
/keymaps
/legacy
/include
/* \
813 /usr
/lib
/kbd
/keymaps
/legacy
/i386
/qwerty
/us.
*; do
814 [[ -f $i ]] ||
continue
818 # When it takes any argument, then install more keymaps.
821 /usr
/lib
/kbd
/keymaps
/i386
/*/* \
822 /usr
/lib
/kbd
/keymaps
/legacy
/i386
/*/*; do
823 [[ -f $i ]] ||
continue
830 for i
in /usr
/share
/zoneinfo
/{,*/,*/*/}*; do
831 [[ -f $i ]] ||
continue
838 /usr
/lib
/kbd
/consolefonts
/eurlatgr
* \
839 /usr
/lib
/kbd
/consolefonts
/latarcyrheb-sun16
*; do
840 [[ -f $i ]] ||
continue
846 for _terminfodir
in /lib
/terminfo
/etc
/terminfo
/usr
/share
/terminfo
; do
847 [ -f ${_terminfodir}/l
/linux
] && break
849 dracut_install
-o ${_terminfodir}/l
/linux
853 cp $TEST_BASE_DIR/testsuite.target
$initdir/etc
/systemd
/system
/
854 cp $TEST_BASE_DIR/end.service
$initdir/etc
/systemd
/system
/
856 mkdir
-p $initdir/etc
/systemd
/system
/testsuite.target.wants
857 ln -fs $TEST_BASE_DIR/testsuite.service
$initdir/etc
/systemd
/system
/testsuite.target.wants
/testsuite.service
858 # Don't shutdown the machine after running the test when INTERACTIVE_DEBUG is set
859 [[ -z $INTERACTIVE_DEBUG ]] && ln -fs $TEST_BASE_DIR/end.service
$initdir/etc
/systemd
/system
/testsuite.target.wants
/end.service
861 # make the testsuite the default target
862 ln -fs testsuite.target
$initdir/etc
/systemd
/system
/default.target
865 setup_nspawn_root
() {
866 rm -fr $TESTDIR/nspawn-root
867 ddebug
"cp -ar $initdir $TESTDIR/nspawn-root"
868 cp -ar $initdir $TESTDIR/nspawn-root
869 # we don't mount in the nspawn root
870 rm -f $TESTDIR/nspawn-root
/etc
/fstab
871 if [[ "$RUN_IN_UNPRIVILEGED_CONTAINER" = "yes" ]]; then
872 cp -ar $TESTDIR/nspawn-root
$TESTDIR/unprivileged-nspawn-root
877 mkdir
-p $initdir/run
878 mkdir
-p $initdir/etc
/systemd
/system
879 mkdir
-p $initdir/var
/log
/journal
881 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
882 if [ -L "/$d" ]; then
889 ln -sfn /run
"$initdir/var/run"
890 ln -sfn /run
/lock
"$initdir/var/lock"
895 local _so_regex
='([^ ]*/lib[^/]*/[^ ]*\.so[^ ]*)'
898 LC_ALL
=C ldd
"$_bin" 2>/dev
/null |
while read _line
; do
899 [[ $_line = 'not a dynamic executable' ]] && break
901 if [[ $_line =~
$_so_regex ]]; then
902 _file
=${BASH_REMATCH[1]}
903 [[ -e ${initdir}/$_file ]] && continue
904 inst_library
"$_file"
908 if [[ $_line =~ not\ found
]]; then
909 dfatal
"Missing a shared library required by $_bin."
910 dfatal
"Run \"ldd $_bin\" to find out what it is."
912 dfatal
"dracut cannot create an initrd."
919 [[ -e $STATEFILE ]] && .
$STATEFILE
920 if [[ ! -d "$TESTDIR" ]]; then
921 if [[ -z "$TESTDIR" ]]; then
922 TESTDIR
=$
(mktemp
--tmpdir=/var
/tmp
-d -t systemd-test.XXXXXX
)
927 echo "TESTDIR=\"$TESTDIR\"" > $STATEFILE
933 initdir
=$TESTDIR/root
937 ## @brief Converts numeric logging level to the first letter of level name.
939 # @param lvl Numeric logging level in range from 1 to 6.
940 # @retval 1 if @a lvl is out of range.
941 # @retval 0 if @a lvl is correct.
942 # @result Echoes first letter of level name.
955 ## @brief Internal helper function for _do_dlog()
957 # @param lvl Numeric logging level.
958 # @param msg Message.
959 # @retval 0 It's always returned, even if logging failed.
961 # @note This function is not supposed to be called manually. Please use
962 # dtrace(), ddebug(), or others instead which wrap this one.
964 # This function calls _do_dlog() either with parameter msg, or if
965 # none is given, it will read standard input and will use every line as
969 # dwarn "This is a warning"
970 # echo "This is a warning" | dwarn
971 LOG_LEVEL
=${LOG_LEVEL:-4}
974 [ -z "$LOG_LEVEL" ] && return 0
975 [ $1 -le $LOG_LEVEL ] ||
return 0
976 local lvl
="$1"; shift
977 local lvlc
=$
(_lvl2char
"$lvl") ||
return 0
979 if [ $# -ge 1 ]; then
983 echo "$lvlc: " "$line"
988 ## @brief Logs message at TRACE level (6)
990 # @param msg Message.
991 # @retval 0 It's always returned, even if logging failed.
995 [ -n "$debug" ] && set -x ||
:
998 ## @brief Logs message at DEBUG level (5)
1000 # @param msg Message.
1001 # @retval 0 It's always returned, even if logging failed.
1005 # [ -n "$debug" ] && set -x || :
1008 ## @brief Logs message at INFO level (4)
1010 # @param msg Message.
1011 # @retval 0 It's always returned, even if logging failed.
1015 [ -n "$debug" ] && set -x ||
:
1018 ## @brief Logs message at WARN level (3)
1020 # @param msg Message.
1021 # @retval 0 It's always returned, even if logging failed.
1025 [ -n "$debug" ] && set -x ||
:
1028 ## @brief Logs message at ERROR level (2)
1030 # @param msg Message.
1031 # @retval 0 It's always returned, even if logging failed.
1035 # [ -n "$debug" ] && set -x || :
1038 ## @brief Logs message at FATAL level (1)
1040 # @param msg Message.
1041 # @retval 0 It's always returned, even if logging failed.
1045 [ -n "$debug" ] && set -x ||
:
1049 # Generic substring function. If $2 is in $1, return 0.
1050 strstr
() { [ "${1#*$2*}" != "$1" ]; }
1052 # normalize_path <path>
1053 # Prints the normalized path, where it removes any duplicated
1054 # and trailing slashes.
1056 # $ normalize_path ///test/test//
1060 set -- "${1//+(\/)//}"
1065 # convert_abs_rel <from> <to>
1066 # Prints the relative path, when creating a symlink to <to> from <from>.
1068 # $ convert_abs_rel /usr/bin/test /bin/test-2
1070 # $ ln -s $(convert_abs_rel /usr/bin/test /bin/test-2) /usr/bin/test
1072 local __current __absolute __abssize __cursize __newpath
1073 local -i __i __level
1075 set -- "$(normalize_path "$1")" "$(normalize_path "$2")"
1077 # corner case #1 - self looping link
1078 [[ "$1" == "$2" ]] && { echo "${1##*/}"; return; }
1080 # corner case #2 - own dir link
1081 [[ "${1%/*}" == "$2" ]] && { echo "."; return; }
1083 IFS
="/" __current
=($1)
1084 IFS
="/" __absolute
=($2)
1086 __abssize
=${#__absolute[@]}
1087 __cursize
=${#__current[@]}
1089 while [[ ${__absolute[__level]} == ${__current[__level]} ]]
1092 if (( __level
> __abssize || __level
> __cursize
))
1098 for ((__i
= __level
; __i
< __cursize-1
; __i
++))
1100 if ((__i
> __level
))
1102 __newpath
=$__newpath"/"
1104 __newpath
=$__newpath".."
1107 for ((__i
= __level
; __i
< __abssize
; __i
++))
1109 if [[ -n $__newpath ]]
1111 __newpath
=$__newpath"/"
1113 __newpath
=$__newpath${__absolute[__i]}
1120 # Install a directory, keeping symlinks as on the original system.
1121 # Example: if /lib points to /lib64 on the host, "inst_dir /lib/file"
1122 # will create ${initdir}/lib64, ${initdir}/lib64/file,
1123 # and a symlink ${initdir}/lib -> lib64.
1125 [[ -e ${initdir}/"$1" ]] && return 0 # already there
1127 local _dir
="$1" _part
="${1%/*}" _file
1128 while [[ "$_part" != "${_part%/*}" ]] && ! [[ -e "${initdir}/${_part}" ]]; do
1133 # iterate over parent directories
1134 for _file
in $_dir; do
1135 [[ -e "${initdir}/$_file" ]] && continue
1136 if [[ -L $_file ]]; then
1137 inst_symlink
"$_file"
1140 mkdir
-m 0755 -p "${initdir}/$_file" ||
return 1
1141 [[ -e "$_file" ]] && chmod --reference="$_file" "${initdir}/$_file"
1142 chmod u
+w
"${initdir}/$_file"
1147 # $1 = file to copy to ramdisk
1148 # $2 (optional) Name for the file on the ramdisk
1149 # Location of the image dir is assumed to be $initdir
1150 # We never overwrite the target if it exists.
1152 [[ -f "$1" ]] ||
return 1
1153 strstr
"$1" "/" ||
return 1
1155 local _src
=$1 target
="${2:-$1}"
1156 if ! [[ -d ${initdir}/$target ]]; then
1157 [[ -e ${initdir}/$target ]] && return 0
1158 [[ -L ${initdir}/$target ]] && return 0
1159 [[ -d "${initdir}/${target%/*}" ]] || inst_dir "${target%/*}"
1161 # install checksum files also
1162 if [[ -e "${_src%/*}/.${_src##*/}.hmac" ]]; then
1163 inst
"${_src%/*}/.${_src##*/}.hmac" "${target%/*}/.${target##*/}.hmac"
1165 ddebug
"Installing $_src"
1166 cp --sparse=always
-pfL "$_src" "${initdir}/$target"
1169 # find symlinks linked to given library file
1171 # Function searches for symlinks by stripping version numbers appended to
1172 # library filename, checks if it points to the same target and finally
1173 # prints the list of symlinks to stdout.
1176 # rev_lib_symlinks libfoo.so.8.1
1177 # output: libfoo.so.8 libfoo.so
1178 # (Only if libfoo.so.8 and libfoo.so exists on host system.)
1179 rev_lib_symlinks
() {
1180 [[ ! $1 ]] && return 0
1182 local fn
="$1" orig
="$(readlink -f "$1")" links
=''
1184 [[ ${fn} =~ .
*\.so\..
* ]] ||
return 1
1186 until [[ ${fn##*.} == so
]]; do
1188 [[ -L ${fn} && $(readlink -f "${fn}") == ${orig} ]] && links+=" ${fn}"
1194 # Same as above, but specialized to handle dynamic libraries.
1195 # It handles making symlinks according to how the original library
1198 local _src="$1" _dest=${2:-$1} _lib _reallib _symlink
1199 strstr "$1" "/" || return 1
1200 [[ -e $initdir/$_dest ]] && return 0
1201 if [[ -L $_src ]]; then
1202 # install checksum files also
1203 if [[ -e "${_src%/*}/.
${_src##*/}.hmac
" ]]; then
1204 inst "${_src%/*}/.${_src##*/}.hmac" "${_dest%/*}/.${_dest##*/}.hmac
"
1206 _reallib=$(readlink -f "$_src")
1207 inst_simple "$_reallib" "$_reallib"
1208 inst_dir "${_dest%/*}"
1209 [[ -d "${_dest%/*}" ]] && _dest=$(readlink -f "${_dest%/*}")/${_dest##*/}
1210 ln -sfn $
(convert_abs_rel
"${_dest}" "${_reallib}") "${initdir}/${_dest}"
1212 inst_simple
"$_src" "$_dest"
1215 # Create additional symlinks. See rev_symlinks description.
1216 for _symlink
in $
(rev_lib_symlinks
$_src) $
(rev_lib_symlinks
$_reallib); do
1217 [[ -e $initdir/$_symlink ]] ||
{
1218 ddebug
"Creating extra symlink: $_symlink"
1219 inst_symlink
$_symlink
1224 # find a binary. If we were not passed the full path directly,
1225 # search in the usual places to find the binary.
1227 if [[ -z ${1##/*} ]]; then
1228 if [[ -x $1 ]] ||
{ strstr
"$1" ".so" && ldd
$1 &>/dev
/null
; }; then
1237 # Same as above, but specialized to install binary executables.
1238 # Install binary executable, and all shared library dependencies, if any.
1241 _bin
=$
(find_binary
"$1") ||
return 1
1243 [[ -e $initdir/$_target ]] && return 0
1244 [[ -L $_bin ]] && inst_symlink
$_bin $_target && return 0
1246 local _so_regex
='([^ ]*/lib[^/]*/[^ ]*\.so[^ ]*)'
1248 LC_ALL
=C ldd
"$_bin" 2>/dev
/null |
while read _line
; do
1249 [[ $_line = 'not a dynamic executable' ]] && break
1251 if [[ $_line =~
$_so_regex ]]; then
1252 _file
=${BASH_REMATCH[1]}
1253 [[ -e ${initdir}/$_file ]] && continue
1254 inst_library
"$_file"
1258 if [[ $_line =~ not\ found
]]; then
1259 dfatal
"Missing a shared library required by $_bin."
1260 dfatal
"Run \"ldd $_bin\" to find out what it is."
1262 dfatal
"dracut cannot create an initrd."
1266 inst_simple
"$_bin" "$_target"
1269 # same as above, except for shell scripts.
1270 # If your shell script does not start with shebang, it is not a shell script.
1273 _bin
=$
(find_binary
"$1") ||
return 1
1275 local _line _shebang_regex
1276 read -r -n 80 _line
<"$_bin"
1277 # If debug is set, clean unprintable chars to prevent messing up the term
1278 [[ $debug ]] && _line
=$
(echo -n "$_line" |
tr -c -d '[:print:][:space:]')
1279 _shebang_regex
='(#! *)(/[^ ]+).*'
1280 [[ $_line =~
$_shebang_regex ]] ||
return 1
1281 inst
"${BASH_REMATCH[2]}" && inst_simple
"$_bin" "$@"
1284 # same as above, but specialized for symlinks
1286 local _src
=$1 _target
=${2:-$1} _realsrc
1287 strstr
"$1" "/" ||
return 1
1288 [[ -L $1 ]] ||
return 1
1289 [[ -L $initdir/$_target ]] && return 0
1290 _realsrc
=$
(readlink
-f "$_src")
1291 if ! [[ -e $initdir/$_realsrc ]]; then
1292 if [[ -d $_realsrc ]]; then
1293 inst_dir
"$_realsrc"
1298 [[ ! -e $initdir/${_target%/*} ]] && inst_dir
"${_target%/*}"
1299 [[ -d ${_target%/*} ]] && _target=$(readlink -f ${_target%/*})/${_target##*/}
1300 ln -sfn $
(convert_abs_rel
"${_target}" "${_realsrc}") "$initdir/$_target"
1303 # attempt to install any programs specified in a udev rule
1304 inst_rule_programs
() {
1307 if grep -qE 'PROGRAM==?"[^ "]+' "$1"; then
1308 for _prog
in $
(grep -E 'PROGRAM==?"[^ "]+' "$1" |
sed -r 's/.*PROGRAM==?"([^ "]+).*/\1/'); do
1309 if [ -x /lib
/udev
/$_prog ]; then
1310 _bin
=/lib
/udev
/$_prog
1312 _bin
=$
(find_binary
"$_prog") ||
{
1313 dinfo
"Skipping program $_prog using in udev rule $(basename $1) as it cannot be found"
1318 #dinfo "Installing $_bin due to it's use in the udev rule $(basename $1)"
1319 dracut_install
"$_bin"
1324 # udev rules always get installed in the same place, so
1325 # create a function to install them to make life simpler.
1327 local _target
=/etc
/udev
/rules.d _rule _found
1329 inst_dir
"/lib/udev/rules.d"
1331 for _rule
in "$@"; do
1332 if [ "${rule#/}" = "$rule" ]; then
1333 for r
in /lib
/udev
/rules.d
/etc
/udev
/rules.d
; do
1334 if [[ -f $r/$_rule ]]; then
1336 inst_simple
"$_found"
1337 inst_rule_programs
"$_found"
1341 for r
in '' .
/ $dracutbasedir/rules.d
/; do
1342 if [[ -f ${r}$_rule ]]; then
1344 inst_simple
"$_found" "$_target/${_found##*/}"
1345 inst_rule_programs
"$_found"
1348 [[ $_found ]] || dinfo
"Skipping udev rule: $_rule"
1353 # general purpose installation function
1354 # Same args as above.
1360 2) [[ ! $initdir && -d $2 ]] && export initdir
=$2
1361 [[ $initdir = $2 ]] && set $1;;
1362 3) [[ -z $initdir ]] && export initdir
=$2
1364 *) dfatal
"inst only takes 1 or 2 or 3 arguments"
1367 for _x
in inst_symlink inst_script inst_binary inst_simple
; do
1368 $_x "$@" && return 0
1373 # install any of listed files
1375 # If first argument is '-d' and second some destination path, first accessible
1376 # source is installed into this path, otherwise it will installed in the same
1377 # path as source. If none of listed files was installed, function return 1.
1378 # On first successful installation it returns with 0 status.
1382 # inst_any -d /bin/foo /bin/bar /bin/baz
1384 # Lets assume that /bin/baz exists, so it will be installed as /bin/foo in
1389 [[ $1 = '-d' ]] && to
="$2" && shift 2
1392 if [[ -e $f ]]; then
1393 [[ $to ]] && inst
"$f" "$to" && return 0
1394 inst
"$f" && return 0
1401 # dracut_install [-o ] <file> [<file> ... ]
1402 # Install <file> to the initramfs image
1403 # -o optionally install the <file> and don't fail, if it is not there
1406 if [[ $1 = '-o' ]]; then
1410 while (($# > 0)); do
1411 if ! inst
"$1" ; then
1412 if [[ $_optional = yes ]]; then
1413 dinfo
"Skipping program $1 as it cannot be found and is" \
1414 "flagged to be optional"
1416 dfatal
"Failed to install $1"
1424 # Install a single kernel module along with any firmware it may require.
1425 # $1 = full path to kernel module to install
1426 install_kmod_with_fw
() {
1427 # no need to go further if the module is already installed
1429 [[ -e "${initdir}/lib/modules/$KERNEL_VER/${1##*/lib/modules/$KERNEL_VER/}" ]] \
1432 [[ -e "$initdir/.kernelmodseen/${1##*/}" ]] && return 0
1434 if [[ $omit_drivers ]]; then
1435 local _kmod
=${1##*/}
1438 if [[ "$_kmod" =~
$omit_drivers ]]; then
1439 dinfo
"Omitting driver $_kmod"
1442 if [[ "${1##*/lib/modules/$KERNEL_VER/}" =~
$omit_drivers ]]; then
1443 dinfo
"Omitting driver $_kmod"
1448 [ -d "$initdir/.kernelmodseen" ] && \
1449 > "$initdir/.kernelmodseen/${1##*/}"
1451 inst_simple
"$1" "/lib/modules/$KERNEL_VER/${1##*/lib/modules/$KERNEL_VER/}" \
1454 local _modname
=${1##*/} _fwdir _found _fw
1455 _modname
=${_modname%.ko*}
1456 for _fw
in $
(modinfo
-k $KERNEL_VER -F firmware
$1 2>/dev
/null
); do
1458 for _fwdir
in $fw_dir; do
1459 if [[ -d $_fwdir && -f $_fwdir/$_fw ]]; then
1460 inst_simple
"$_fwdir/$_fw" "/lib/firmware/$_fw"
1464 if [[ $_found != yes ]]; then
1465 if ! grep -qe "\<${_modname//-/_}\>" /proc
/modules
; then
1466 dinfo
"Possible missing firmware \"${_fw}\" for kernel module" \
1467 "\"${_modname}.ko\""
1469 dwarn
"Possible missing firmware \"${_fw}\" for kernel module" \
1470 "\"${_modname}.ko\""
1477 # Do something with all the dependencies of a kernel module.
1478 # Note that kernel modules depend on themselves using the technique we use
1479 # $1 = function to call for each dependency we find
1480 # It will be passed the full path to the found kernel module
1481 # $2 = module to get dependencies for
1482 # rest of args = arguments to modprobe
1483 # _fderr specifies FD passed from surrounding scope
1484 for_each_kmod_dep
() {
1485 local _func
=$1 _kmod
=$2 _cmd _modpath _options _found
=0
1487 modprobe
"$@" --ignore-install --show-depends $_kmod 2>&${_fderr} |
(
1488 while read _cmd _modpath _options
; do
1489 [[ $_cmd = insmod
]] ||
continue
1490 $_func ${_modpath} ||
exit $?
1493 [[ $_found -eq 0 ]] && exit 1
1498 # filter kernel modules to install certain modules that meet specific
1500 # $1 = search only in subdirectory of /kernel/$1
1501 # $2 = function to call with module name to filter.
1502 # This function will be passed the full path to the module to test.
1503 # The behavior of this function can vary depending on whether $hostonly is set.
1504 # If it is, we will only look at modules that are already in memory.
1505 # If it is not, we will look at all kernel modules
1506 # This function returns the full filenames of modules that match $1
1507 filter_kernel_modules_by_path
() (
1508 local _modname _filtercmd
1509 if ! [[ $hostonly ]]; then
1510 _filtercmd
='find "$KERNEL_MODS/kernel/$1" "$KERNEL_MODS/extra"'
1511 _filtercmd
+=' "$KERNEL_MODS/weak-updates" -name "*.ko" -o -name "*.ko.gz"'
1512 _filtercmd
+=' -o -name "*.ko.xz"'
1513 _filtercmd
+=' 2>/dev/null'
1515 _filtercmd
='cut -d " " -f 1 </proc/modules|xargs modinfo -F filename '
1516 _filtercmd
+='-k $KERNEL_VER 2>/dev/null'
1518 for _modname
in $
(eval $_filtercmd); do
1520 *.ko
) "$2" "$_modname" && echo "$_modname";;
1521 *.ko.gz
) gzip -dc "$_modname" > $initdir/$$.ko
1522 $2 $initdir/$$.ko
&& echo "$_modname"
1523 rm -f $initdir/$$.ko
1525 *.ko.xz
) xz
-dc "$_modname" > $initdir/$$.ko
1526 $2 $initdir/$$.ko
&& echo "$_modname"
1527 rm -f $initdir/$$.ko
1532 find_kernel_modules_by_path
() (
1533 if ! [[ $hostonly ]]; then
1534 find "$KERNEL_MODS/kernel/$1" "$KERNEL_MODS/extra" "$KERNEL_MODS/weak-updates" \
1535 -name "*.ko" -o -name "*.ko.gz" -o -name "*.ko.xz" 2>/dev
/null
1537 cut
-d " " -f 1 </proc
/modules \
1538 |
xargs modinfo
-F filename
-k $KERNEL_VER 2>/dev
/null
1542 filter_kernel_modules
() {
1543 filter_kernel_modules_by_path drivers
"$1"
1546 find_kernel_modules
() {
1547 find_kernel_modules_by_path drivers
1550 # instmods [-c] <kernel module> [<kernel module> ... ]
1551 # instmods [-c] <kernel subsystem>
1552 # install kernel modules along with all their dependencies.
1553 # <kernel subsystem> can be e.g. "=block" or "=drivers/usb/storage"
1555 [[ $no_kernel = yes ]] && return
1556 # called [sub]functions inherit _fderr
1559 if [[ $1 = '-c' ]]; then
1564 function inst1mod
() {
1565 local _ret
=0 _mod
="$1"
1568 if [ -f $KERNEL_MODS/modules.
${_mod#=} ]; then
1569 ( [[ "$_mpargs" ]] && echo $_mpargs
1570 cat "${KERNEL_MODS}/modules.${_mod#=}" ) \
1573 ( [[ "$_mpargs" ]] && echo $_mpargs
1574 find "$KERNEL_MODS" -path "*/${_mod#=}/*" -printf '%f\n' ) \
1578 --*) _mpargs
+=" $_mod" ;;
1579 i2o_scsi
) return ;; # Do not load this diagnostic-only module
1582 # if we are already installed, skip this module and go on
1584 [[ -f "$initdir/.kernelmodseen/${_mod%.ko}.ko" ]] && return
1586 if [[ $omit_drivers ]] && [[ "$1" =~
$omit_drivers ]]; then
1587 dinfo
"Omitting driver ${_mod##$KERNEL_MODS}"
1590 # If we are building a host-specific initramfs and this
1591 # module is not already loaded, move on to the next one.
1592 [[ $hostonly ]] && ! grep -qe "\<${_mod//-/_}\>" /proc
/modules \
1593 && ! echo $add_drivers |
grep -qe "\<${_mod}\>" \
1596 # We use '-d' option in modprobe only if modules prefix path
1597 # differs from default '/'. This allows us to use Dracut with
1598 # old version of modprobe which doesn't have '-d' option.
1599 local _moddirname
=${KERNEL_MODS%%/lib/modules/*}
1600 [[ -n ${_moddirname} ]] && _moddirname
="-d ${_moddirname}/"
1602 # ok, load the module, all its dependencies, and any firmware
1604 for_each_kmod_dep install_kmod_with_fw
$_mod \
1605 --set-version $KERNEL_VER ${_moddirname} $_mpargs
1612 function instmods_1
() {
1614 if (($# == 0)); then # filenames from stdin
1616 inst1mod
"${_mod%.ko*}" ||
{
1617 if [ "$_check" = "yes" ]; then
1618 dfatal
"Failed to install $_mod"
1624 while (($# > 0)); do # filenames as arguments
1625 inst1mod
${1%.ko*} ||
{
1626 if [ "$_check" = "yes" ]; then
1627 dfatal
"Failed to install $1"
1636 local _ret _filter_not_found
='FATAL: Module .* not found.'
1638 # Capture all stderr from modprobe to _fderr. We could use {var}>...
1639 # redirections, but that would make dracut require bash4 at least.
1640 eval "( instmods_1 \"\$@\" ) ${_fderr}>&1" \
1641 |
while read line
; do [[ "$line" =~
$_filter_not_found ]] && echo $line ||
echo $line >&2 ;done | derror
1647 # inst_libdir_file [-n <pattern>] <file> [<file>...]
1648 # Install a <file> located on a lib directory to the initramfs image
1649 # -n <pattern> install non-matching files
1650 inst_libdir_file
() {
1651 if [[ "$1" == "-n" ]]; then
1654 for _dir
in $libdirs; do
1656 for _f
in "$_dir"/$_i; do
1657 [[ "$_i" =~
$_pattern ]] ||
continue
1658 [[ -e "$_i" ]] && dracut_install
"$_i"
1663 for _dir
in $libdirs; do
1665 for _f
in "$_dir"/$_i; do
1666 [[ -e "$_f" ]] && dracut_install
"$_f"
1674 ln -fs ..
/usr
/bin
/systemctl
$initdir/bin
/
1675 ln -fs ..
/usr
/lib
/systemd
$initdir/lib
/
1676 inst_simple
"/usr/lib/systemd/system/haveged.service"
1679 # can be overridden in specific test
1681 umount
$TESTDIR/root
2>/dev
/null || true
1682 [[ $LOOPDEV ]] && losetup
-d $LOOPDEV || true
1687 if [ -z "$TEST_NO_QEMU" ]; then
1689 check_result_qemu ||
return 1
1691 dwarn
"can't run QEMU, skipping"
1694 if [ -z "$TEST_NO_NSPAWN" ]; then
1695 if run_nspawn
"nspawn-root"; then
1696 check_result_nspawn
"nspawn-root" ||
return 1
1698 dwarn
"can't run systemd-nspawn, skipping"
1701 if [[ "$RUN_IN_UNPRIVILEGED_CONTAINER" = "yes" ]]; then
1702 if NSPAWN_ARGUMENTS
="-U --private-network $NSPAWN_ARGUMENTS" run_nspawn
"unprivileged-nspawn-root"; then
1703 check_result_nspawn
"unprivileged-nspawn-root" ||
return 1
1705 dwarn
"can't run systemd-nspawn, skipping"
1713 if [[ $UID != "0" ]]; then
1714 echo "TEST: $TEST_DESCRIPTION [SKIPPED]: not root" >&2
1719 [[ $libdir ]] ||
for libdir
in /lib64
/lib
; do
1720 [[ -d $libdir ]] && libdirs
+=" $libdir" && break
1723 [[ $usrlibdir ]] ||
for usrlibdir
in /usr
/lib64
/usr
/lib
; do
1724 [[ -d $usrlibdir ]] && libdirs
+=" $usrlibdir" && break
1727 mkdir
-p "$STATEDIR"
1732 while (($# > 0)); do
1735 echo "TEST RUN: $TEST_DESCRIPTION"
1738 if (( $ret == 0 )); then
1739 echo "TEST RUN: $TEST_DESCRIPTION [OK]"
1741 echo "TEST RUN: $TEST_DESCRIPTION [FAILED]"
1745 echo "TEST SETUP: $TEST_DESCRIPTION"
1749 echo "TEST CLEANUP: $TEST_DESCRIPTION"
1756 echo -n "TEST: $TEST_DESCRIPTION ";
1758 test_setup
&& test_run
1764 ) </dev
/null
>"$TESTLOG" 2>&1 || ret
=$?
1765 if [ $ret -eq 0 ]; then