]> git.ipfire.org Git - thirdparty/systemd.git/blame - test/test-functions
Merge pull request #7256 from keszybz/add-cii-badge
[thirdparty/systemd.git] / test / test-functions
CommitLineData
898720b7
HH
1#!/bin/bash
2# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
3# ex: ts=8 sw=4 sts=4 et filetype=sh
4PATH=/sbin:/bin:/usr/sbin:/usr/bin
5export PATH
6
818567fc
MP
7LOOKS_LIKE_DEBIAN=$(source /etc/os-release && [[ "$ID" = "debian" || "$ID_LIKE" = "debian" ]] && echo yes || true)
8LOOKS_LIKE_ARCH=$(source /etc/os-release && [[ "$ID" = "arch" ]] && echo yes || true)
9LOOKS_LIKE_SUSE=$(source /etc/os-release && [[ "$ID_LIKE" = "suse" ]] && echo yes || true)
0d6e798a
HH
10KERNEL_VER=${KERNEL_VER-$(uname -r)}
11KERNEL_MODS="/lib/modules/$KERNEL_VER/"
91f9f8f1 12QEMU_TIMEOUT="${QEMU_TIMEOUT:-infinity}"
43bbb8f0 13NSPAWN_TIMEOUT="${NSPAWN_TIMEOUT:-infinity}"
b2ecd099 14TIMED_OUT= # will be 1 after run_* if *_TIMEOUT is set and test timed out
85393d8f 15[[ "$LOOKS_LIKE_SUSE" ]] && FSTYPE="${FSTYPE:-btrfs}" || FSTYPE="${FSTYPE:-ext3}"
22f1f8f2 16UNIFIED_CGROUP_HIERARCHY="${UNIFIED_CGROUP_HIERARCHY:-default}"
898720b7 17
3486cb6c
MP
18if ! ROOTLIBDIR=$(pkg-config --variable=systemdutildir systemd); then
19 echo "WARNING! Cannot determine rootlibdir from pkg-config, assuming /usr/lib/systemd" >&2
20 ROOTLIBDIR=/usr/lib/systemd
21fi
22
09f6f45a
EV
23BASICTOOLS="sh bash setsid loadkeys setfont login sulogin gzip sleep echo mount umount cryptsetup date dmsetup modprobe sed cmp tee rm"
24DEBUGTOOLS="df free ls stty cat ps ln ip route dmesg dhclient mkdir cp ping dhclient strace less grep id tty touch du sort hostname find"
889a9042 25
22077c9c
MP
26STATEDIR="${BUILD_DIR:-.}/test/$(basename $(dirname $(realpath $0)))"
27STATEFILE="$STATEDIR/.testdir"
28TESTLOG="$STATEDIR/test.log"
29
c6a77179
RC
30function find_qemu_bin() {
31 # SUSE and Red Hat call the binary qemu-kvm
32 # Debian and Gentoo call it kvm
33 [ "$QEMU_BIN" ] || QEMU_BIN=$(which -a kvm qemu-kvm 2>/dev/null | grep '^/' -m1)
34
35 [ "$ARCH" ] || ARCH=$(uname -m)
36 case $ARCH in
37 x86_64)
38 # QEMU's own build system calls it qemu-system-x86_64
39 [ "$QEMU_BIN" ] || QEMU_BIN=$(which -a qemu-system-x86_64 2>/dev/null | grep '^/' -m1)
40 ;;
41 i*86)
42 # new i386 version of QEMU
43 [ "$QEMU_BIN" ] || QEMU_BIN=$(which -a qemu-system-i386 2>/dev/null | grep '^/' -m1)
44
45 # i386 version of QEMU
46 [ "$QEMU_BIN" ] || QEMU_BIN=$(which -a qemu 2>/dev/null | grep '^/' -m1)
47 ;;
cf5f9bb8
ZJS
48 ppc64*)
49 [ "$QEMU_BIN" ] || QEMU_BIN=$(which -a qemu-system-$ARCH 2>/dev/null | grep '^/' -m1)
50 ;;
c6a77179
RC
51 esac
52
53 if [ ! -e "$QEMU_BIN" ]; then
54 echo "Could not find a suitable QEMU binary" >&2
55 return 1
56 fi
57}
58
b2ecd099
MP
59# Return 0 if QEMU did run (then you must check the result state/logs for actual
60# success), or 1 if QEMU is not available.
889a9042 61run_qemu() {
b6f0c419
HH
62 if [ -f /etc/machine-id ]; then
63 read MACHINE_ID < /etc/machine-id
64 [ -z "$INITRD" ] && [ -e "/boot/$MACHINE_ID/$KERNEL_VER/initrd" ] \
65 && INITRD="/boot/$MACHINE_ID/$KERNEL_VER/initrd"
66 [ -z "$KERNEL_BIN" ] && [ -e "/boot/$MACHINE_ID/$KERNEL_VER/linux" ] \
67 && KERNEL_BIN="/boot/$MACHINE_ID/$KERNEL_VER/linux"
68 fi
69
e1a27318
EV
70 if [[ ! "$KERNEL_BIN" ]]; then
71 if [[ "$LOOKS_LIKE_ARCH" ]]; then
72 KERNEL_BIN=/boot/vmlinuz-linux
73 else
74 KERNEL_BIN=/boot/vmlinuz-$KERNEL_VER
75 fi
76 fi
77
61fea35e
EV
78 default_fedora_initrd=/boot/initramfs-${KERNEL_VER}.img
79 default_debian_initrd=/boot/initrd.img-${KERNEL_VER}
e1a27318 80 default_arch_initrd=/boot/initramfs-linux.img
85393d8f 81 default_suse_initrd=/boot/initrd-${KERNEL_VER}
e1a27318
EV
82 if [[ ! "$INITRD" ]]; then
83 if [[ -e "$default_fedora_initrd" ]]; then
84 INITRD="$default_fedora_initrd"
85 elif [[ "$LOOKS_LIKE_DEBIAN" && -e "$default_debian_initrd" ]]; then
86 INITRD="$default_debian_initrd"
87 elif [[ "$LOOKS_LIKE_ARCH" && -e "$default_arch_initrd" ]]; then
88 INITRD="$default_arch_initrd"
85393d8f
TB
89 elif [[ "$LOOKS_LIKE_SUSE" && -e "$default_suse_initrd" ]]; then
90 INITRD="$default_suse_initrd"
e1a27318
EV
91 fi
92 fi
93
c6a77179
RC
94 [ "$QEMU_SMP" ] || QEMU_SMP=1
95
96 find_qemu_bin || return 1
97
22f1f8f2
EV
98 local _cgroup_args
99 if [[ "$UNIFIED_CGROUP_HIERARCHY" = "yes" ]]; then
100 _cgroup_args="systemd.unified_cgroup_hierarchy=yes"
101 elif [[ "$UNIFIED_CGROUP_HIERARCHY" = "no" ]]; then
102 _cgroup_args="systemd.unified_cgroup_hierarchy=no systemd.legacy_systemd_cgroup_controller=yes"
103 elif [[ "$UNIFIED_CGROUP_HIERARCHY" = "hybrid" ]]; then
104 _cgroup_args="systemd.unified_cgroup_hierarchy=no systemd.legacy_systemd_cgroup_controller=no"
105 elif [[ "$UNIFIED_CGROUP_HIERARCHY" != "default" ]]; then
106 dfatal "Unknown UNIFIED_CGROUP_HIERARCHY. Got $UNIFIED_CGROUP_HIERARCHY, expected [yes|no|hybrid|default]"
107 exit 1
108 fi
109
85393d8f
TB
110if [[ "$LOOKS_LIKE_SUSE" ]]; then
111 PARAMS+="rd.hostonly=0"
112else
113 PARAMS+="ro"
114fi
115
116KERNEL_APPEND="$PARAMS \
117root=/dev/sda1 \
c6a77179
RC
118raid=noautodetect \
119loglevel=2 \
3486cb6c 120init=$ROOTLIBDIR/systemd \
c6a77179
RC
121console=ttyS0 \
122selinux=0 \
22f1f8f2 123$_cgroup_args \
c6a77179
RC
124$KERNEL_APPEND \
125"
126
dbf43a42 127 QEMU_OPTIONS="-smp $QEMU_SMP \
c6a77179
RC
128-net none \
129-m 512M \
130-nographic \
131-kernel $KERNEL_BIN \
5b23cef0 132-drive format=raw,cache=unsafe,file=${TESTDIR}/rootdisk.img \
c6a77179
RC
133"
134
91f9f8f1 135 if [[ "$INITRD" && "$SKIP_INITRD" != "yes" ]]; then
c6a77179
RC
136 QEMU_OPTIONS="$QEMU_OPTIONS -initrd $INITRD"
137 fi
138
dbf43a42
DM
139 if [ -c /dev/kvm ]; then
140 QEMU_OPTIONS="$QEMU_OPTIONS -machine accel=kvm -enable-kvm -cpu host"
141 fi
142
91f9f8f1
EV
143 if [[ "$QEMU_TIMEOUT" != "infinity" ]]; then
144 QEMU_BIN="timeout --foreground $QEMU_TIMEOUT $QEMU_BIN"
145 fi
b2ecd099
MP
146 (set -x; $QEMU_BIN $QEMU_OPTIONS -append "$KERNEL_APPEND")
147 rc=$?
148 if [ "$rc" = 124 ] && [ "$QEMU_TIMEOUT" != "infinity" ]; then
149 derror "test timed out after $QEMU_TIMEOUT s"
150 TIMED_OUT=1
151 else
152 [ "$rc" != 0 ] && derror "QEMU failed with exit code $rc"
153 fi
154 return 0
889a9042
RC
155}
156
7cad32bb
MP
157# Return 0 if nspawn did run (then you must check the result state/logs for actual
158# success), or 1 if nspawn is not available.
889a9042 159run_nspawn() {
7cad32bb
MP
160 [[ -d /run/systemd/system ]] || return 1
161
209f4b9e 162 local _nspawn_cmd="$BUILD_DIR/systemd-nspawn --register=no --kill-signal=SIGKILL --directory=$TESTDIR/nspawn-root $ROOTLIBDIR/systemd $KERNEL_APPEND"
43bbb8f0
EV
163 if [[ "$NSPAWN_TIMEOUT" != "infinity" ]]; then
164 _nspawn_cmd="timeout --foreground $NSPAWN_TIMEOUT $_nspawn_cmd"
165 fi
856ca72b 166
22f1f8f2
EV
167 if [[ "$UNIFIED_CGROUP_HIERARCHY" = "hybrid" ]]; then
168 dwarn "nspawn doesn't support UNIFIED_CGROUP_HIERARCHY=hybrid, skipping"
169 exit
170 elif [[ "$UNIFIED_CGROUP_HIERARCHY" = "yes" || "$UNIFIED_CGROUP_HIERARCHY" = "no" ]]; then
171 _nspawn_cmd="env UNIFIED_CGROUP_HIERARCHY=$UNIFIED_CGROUP_HIERARCHY $_nspawn_cmd"
172 elif [[ "$UNIFIED_CGROUP_HIERARCHY" = "default" ]]; then
173 _nspawn_cmd="env --unset=UNIFIED_CGROUP_HIERARCHY $_nspawn_cmd"
174 else
175 dfatal "Unknown UNIFIED_CGROUP_HIERARCHY. Got $UNIFIED_CGROUP_HIERARCHY, expected [yes|no|hybrid|default]"
176 exit 1
177 fi
856ca72b 178
b2ecd099
MP
179 (set -x; $_nspawn_cmd)
180 rc=$?
181 if [ "$rc" = 124 ] && [ "$NSPAWN_TIMEOUT" != "infinity" ]; then
182 derror "test timed out after $NSPAWN_TIMEOUT s"
183 TIMED_OUT=1
184 else
185 [ "$rc" != 0 ] && derror "nspawn failed with exit code $rc"
186 fi
187 return 0
889a9042
RC
188}
189
190setup_basic_environment() {
191 # create the basic filesystem layout
192 setup_basic_dirs
193
194 install_systemd
195 install_missing_libraries
196 install_config_files
197 create_rc_local
198 install_basic_tools
199 install_libnss
200 install_pam
201 install_dbus
202 install_fonts
203 install_keymaps
204 install_terminfo
205 install_execs
9974ff63 206 install_fsck
889a9042
RC
207 install_plymouth
208 install_debug_tools
209 install_ld_so_conf
e3ce42e7 210 setup_selinux
889a9042
RC
211 strip_binaries
212 install_depmod_files
213 generate_module_dependencies
889a9042
RC
214}
215
e3ce42e7
EV
216setup_selinux() {
217 # don't forget KERNEL_APPEND='... selinux=1 ...'
218 if [[ "$SETUP_SELINUX" != "yes" ]]; then
219 ddebug "Don't setup SELinux"
220 return 0
221 fi
222 ddebug "Setup SELinux"
223 local _conf_dir=/etc/selinux
224 local _fixfiles_tools="bash uname cat sort uniq awk grep egrep head expr find rm secon setfiles"
225
226 rm -rf $initdir/$_conf_dir
227 if ! cp -ar $_conf_dir $initdir/$_conf_dir; then
228 dfatal "Failed to copy $_conf_dir"
229 exit 1
230 fi
231
232 cat <<EOF >$initdir/etc/systemd/system/autorelabel.service
233[Unit]
234Description=Relabel all filesystems
235DefaultDependencies=no
236Requires=local-fs.target
237Conflicts=shutdown.target
238After=local-fs.target
239Before=sysinit.target shutdown.target
240ConditionSecurity=selinux
241ConditionPathExists=|/.autorelabel
242
243[Service]
244ExecStart=/bin/sh -x -c 'echo 0 >/sys/fs/selinux/enforce && fixfiles -f -F relabel && rm /.autorelabel && systemctl --force reboot'
245Type=oneshot
246TimeoutSec=0
247RemainAfterExit=yes
248EOF
249
250 touch $initdir/.autorelabel
251 mkdir -p $initdir/etc/systemd/system/basic.target.wants
252 ln -fs autorelabel.service $initdir/etc/systemd/system/basic.target.wants/autorelabel.service
253
254 dracut_install $_fixfiles_tools
255 dracut_install fixfiles
256 dracut_install sestatus
257}
258
a2fbff31
EV
259install_valgrind() {
260 if ! type -p valgrind; then
261 dfatal "Failed to install valgrind"
262 exit 1
263 fi
264
265 local _valgrind_bins=$(strace -e execve valgrind /bin/true 2>&1 >/dev/null | perl -lne 'print $1 if /^execve\("([^"]+)"/')
266 dracut_install $_valgrind_bins
267
268 local _valgrind_libs=$(LD_DEBUG=files valgrind /bin/true 2>&1 >/dev/null | perl -lne 'print $1 if m{calling init: (/.*vgpreload_.*)}')
269 dracut_install $_valgrind_libs
270
271 local _valgrind_dbg_and_supp=$(
272 strace -e open valgrind /bin/true 2>&1 >/dev/null |
273 perl -lne 'if (my ($fname) = /^open\("([^"]+).*= (?!-)\d+/) { print $fname if $fname =~ /debug|\.supp$/ }'
274 )
275 dracut_install $_valgrind_dbg_and_supp
276}
277
cb2f9d3f
EV
278create_valgrind_wrapper() {
279 local _valgrind_wrapper=$initdir/$ROOTLIBDIR/systemd-under-valgrind
280 ddebug "Create $_valgrind_wrapper"
281 cat >$_valgrind_wrapper <<EOF
282#!/bin/bash
283
23cabb68 284mount -t proc proc /proc
cb2f9d3f
EV
285exec valgrind --leak-check=full --log-file=/valgrind.out $ROOTLIBDIR/systemd "\$@"
286EOF
287 chmod 0755 $_valgrind_wrapper
288}
289
45dbd7b6
EV
290create_strace_wrapper() {
291 local _strace_wrapper=$initdir/$ROOTLIBDIR/systemd-under-strace
292 ddebug "Create $_strace_wrapper"
293 cat >$_strace_wrapper <<EOF
294#!/bin/bash
295
296exec strace -D -o /strace.out $ROOTLIBDIR/systemd "\$@"
297EOF
298 chmod 0755 $_strace_wrapper
299}
300
9974ff63
EV
301install_fsck() {
302 dracut_install /sbin/fsck*
303 dracut_install -o /bin/fsck*
331fb4ca
EV
304
305 # fskc.reiserfs calls reiserfsck. so, install it
306 dracut_install -o reiserfsck
9974ff63
EV
307}
308
889a9042
RC
309install_dmevent() {
310 instmods dm_crypt =crypto
311 type -P dmeventd >/dev/null && dracut_install dmeventd
312 inst_libdir_file "libdevmapper-event.so*"
ac289ce3
EV
313 if [[ "$LOOKS_LIKE_DEBIAN" ]]; then
314 # dmsetup installs 55-dm and 60-persistent-storage-dm on Debian/Ubuntu
315 # see https://anonscm.debian.org/cgit/pkg-lvm/lvm2.git/tree/debian/patches/0007-udev.patch
316 inst_rules 55-dm.rules 60-persistent-storage-dm.rules
317 else
318 inst_rules 10-dm.rules 13-dm-disk.rules 95-dm-notify.rules
319 fi
889a9042
RC
320}
321
322install_systemd() {
323 # install compiled files
ca992ecf
EV
324 local _ninja_bin=$(type -P ninja || type -P ninja-build)
325 if [[ -z "$_ninja_bin" ]]; then
326 dfatal "ninja was not found"
327 exit 1
328 fi
329 (set -x; DESTDIR=$initdir "$_ninja_bin" -C $BUILD_DIR install)
889a9042 330 # remove unneeded documentation
23756070 331 rm -fr $initdir/usr/share/{man,doc}
889a9042
RC
332 # we strip binaries since debug symbols increase binaries size a lot
333 # and it could fill the available space
334 strip_binaries
61b480b6 335
85393d8f
TB
336 [[ "$LOOKS_LIKE_SUSE" ]] && setup_suse
337
61b480b6
ZJS
338 # enable debug logging in PID1
339 echo LogLevel=debug >> $initdir/etc/systemd/system.conf
889a9042
RC
340}
341
d7a4278d
FS
342get_ldpath() {
343 local _bin="$1"
344 objdump -p "$_bin" 2>/dev/null | awk "/R(UN)?PATH/ { print \"$initdir\" \$2 }" | paste -sd :
345}
346
889a9042
RC
347install_missing_libraries() {
348 # install possible missing libraries
11ea3431 349 for i in $initdir{,/usr}/{sbin,bin}/* $initdir{,/usr}/lib/systemd/*; do
d7a4278d 350 LD_LIBRARY_PATH=$(get_ldpath $i) inst_libs $i
889a9042
RC
351 done
352}
353
354create_empty_image() {
739d81dd 355 rm -f "$TESTDIR/rootdisk.img"
889a9042 356 # Create the blank file to use as a root filesystem
1b1eae69 357 dd if=/dev/null of="$TESTDIR/rootdisk.img" bs=1M seek=400
889a9042 358 LOOPDEV=$(losetup --show -P -f $TESTDIR/rootdisk.img)
739d81dd 359 [ -b "$LOOPDEV" ] || return 1
889a9042 360 echo "LOOPDEV=$LOOPDEV" >> $STATEFILE
edbced8a 361 sfdisk "$LOOPDEV" <<EOF
1b1eae69 362,390M
889a9042
RC
363,
364EOF
365
331fb4ca
EV
366 local _label="-L systemd"
367 # mkfs.reiserfs doesn't know -L. so, use --label instead
368 [[ "$FSTYPE" == "reiserfs" ]] && _label="--label systemd"
369 if ! mkfs -t "${FSTYPE}" ${_label} "${LOOPDEV}p1" -q; then
370 dfatal "Failed to mkfs -t ${FSTYPE}"
371 exit 1
372 fi
889a9042
RC
373}
374
375check_result_nspawn() {
376 ret=1
377 [[ -e $TESTDIR/nspawn-root/testok ]] && ret=0
378 [[ -f $TESTDIR/nspawn-root/failed ]] && cp -a $TESTDIR/nspawn-root/failed $TESTDIR
379 cp -a $TESTDIR/nspawn-root/var/log/journal $TESTDIR
380 [[ -f $TESTDIR/failed ]] && cat $TESTDIR/failed
381 ls -l $TESTDIR/journal/*/*.journal
382 test -s $TESTDIR/failed && ret=$(($ret+1))
b2ecd099 383 [ -n "$TIMED_OUT" ] && ret=$(($ret+1))
889a9042
RC
384 return $ret
385}
386
054ee249
MP
387# can be overridden in specific test
388check_result_qemu() {
389 ret=1
390 mkdir -p $TESTDIR/root
391 mount ${LOOPDEV}p1 $TESTDIR/root
392 [[ -e $TESTDIR/root/testok ]] && ret=0
393 [[ -f $TESTDIR/root/failed ]] && cp -a $TESTDIR/root/failed $TESTDIR
394 cp -a $TESTDIR/root/var/log/journal $TESTDIR
395 umount $TESTDIR/root
396 [[ -f $TESTDIR/failed ]] && cat $TESTDIR/failed
397 ls -l $TESTDIR/journal/*/*.journal
398 test -s $TESTDIR/failed && ret=$(($ret+1))
399 [ -n "$TIMED_OUT" ] && ret=$(($ret+1))
400 return $ret
401}
402
889a9042 403strip_binaries() {
5a613464
EV
404 if [[ "$STRIP_BINARIES" = "no" ]]; then
405 ddebug "Don't strip binaries"
406 return 0
407 fi
889a9042
RC
408 ddebug "Strip binaries"
409 find "$initdir" -executable -not -path '*/lib/modules/*.ko' -type f | xargs strip --strip-unneeded | ddebug
410}
411
412create_rc_local() {
413 mkdir -p $initdir/etc/rc.d
414 cat >$initdir/etc/rc.d/rc.local <<EOF
415#!/bin/bash
416exit 0
417EOF
418 chmod 0755 $initdir/etc/rc.d/rc.local
419}
420
421install_execs() {
c7eda013
EV
422 ddebug "install any Execs from the service files"
423 (
209f4b9e 424 export PKG_CONFIG_PATH=$BUILD_DIR/src/core/
c7eda013
EV
425 systemdsystemunitdir=$(pkg-config --variable=systemdsystemunitdir systemd)
426 systemduserunitdir=$(pkg-config --variable=systemduserunitdir systemd)
427 egrep -ho '^Exec[^ ]*=[^ ]+' $initdir/{$systemdsystemunitdir,$systemduserunitdir}/*.service \
428 | while read i; do
5ed0dcf4 429 i=${i##Exec*=}; i=${i##[@+\!-]}; i=${i##\!}
818567fc
MP
430 # some {rc,halt}.local scripts and programs are okay to not exist, the rest should
431 inst $i || [ "${i%.local}" != "$i" ] || [ "${i%systemd-update-done}" != "$i" ]
c7eda013
EV
432 done
433 )
889a9042
RC
434}
435
436generate_module_dependencies() {
437 if [[ -d $initdir/lib/modules/$KERNEL_VER ]] && \
438 ! depmod -a -b "$initdir" $KERNEL_VER; then
439 dfatal "\"depmod -a $KERNEL_VER\" failed."
440 exit 1
441 fi
442}
443
444install_depmod_files() {
445 inst /lib/modules/$KERNEL_VER/modules.order
446 inst /lib/modules/$KERNEL_VER/modules.builtin
447}
448
449install_plymouth() {
450 # install plymouth, if found... else remove plymouth service files
451 # if [ -x /usr/libexec/plymouth/plymouth-populate-initrd ]; then
452 # PLYMOUTH_POPULATE_SOURCE_FUNCTIONS="$TEST_BASE_DIR/test-functions" \
453 # /usr/libexec/plymouth/plymouth-populate-initrd -t $initdir
454 # dracut_install plymouth plymouthd
455 # else
456 rm -f $initdir/{usr/lib,etc}/systemd/system/plymouth* $initdir/{usr/lib,etc}/systemd/system/*/plymouth*
457 # fi
458}
459
460install_ld_so_conf() {
461 cp -a /etc/ld.so.conf* $initdir/etc
462 ldconfig -r "$initdir"
463}
464
465install_config_files() {
818567fc 466 inst /etc/sysconfig/init || true
889a9042
RC
467 inst /etc/passwd
468 inst /etc/shadow
bf3a947c 469 inst /etc/login.defs
889a9042
RC
470 inst /etc/group
471 inst /etc/shells
472 inst /etc/nsswitch.conf
818567fc
MP
473 inst /etc/pam.conf || true
474 inst /etc/securetty || true
889a9042
RC
475 inst /etc/os-release
476 inst /etc/localtime
477 # we want an empty environment
478 > $initdir/etc/environment
479 > $initdir/etc/machine-id
480 # set the hostname
481 echo systemd-testsuite > $initdir/etc/hostname
482 # fstab
85393d8f
TB
483 if [[ "$LOOKS_LIKE_SUSE" ]]; then
484 ROOTMOUNT="/dev/sda1 / ${FSTYPE} rw 0 1"
485 else
486 ROOTMOUNT="LABEL=systemd / ${FSTYPE} rw 0 1"
487 fi
488
889a9042 489 cat >$initdir/etc/fstab <<EOF
85393d8f 490$ROOTMOUNT
889a9042
RC
491EOF
492}
493
494install_basic_tools() {
495 [[ $BASICTOOLS ]] && dracut_install $BASICTOOLS
4be4833e 496 dracut_install -o sushell
7d023341
MP
497 # in Debian ldconfig is just a shell script wrapper around ldconfig.real
498 dracut_install -o ldconfig.real
889a9042
RC
499}
500
501install_debug_tools() {
502 [[ $DEBUGTOOLS ]] && dracut_install $DEBUGTOOLS
503}
504
505install_libnss() {
506 # install libnss_files for login
cffae62b 507 NSS_LIBS=$(LD_DEBUG=files getent passwd 2>&1 >/dev/null |sed -n '/calling init: .*libnss_/ {s!^.* /!/!; p}')
99877b7e 508 dracut_install $NSS_LIBS
889a9042
RC
509}
510
511install_dbus() {
3486cb6c
MP
512 inst $ROOTLIBDIR/system/dbus.socket
513 inst $ROOTLIBDIR/system/dbus.service
889a9042
RC
514
515 find \
e63b61be 516 /etc/dbus-1 /usr/share/dbus-1 -xtype f \
889a9042
RC
517 | while read file; do
518 inst $file
519 done
520}
521
522install_pam() {
0fe15dc8 523 (
818567fc
MP
524 if [[ "$LOOKS_LIKE_DEBIAN" ]] && type -p dpkg-architecture &>/dev/null; then
525 find "/lib/$(dpkg-architecture -qDEB_HOST_MULTIARCH)/security" -xtype f
526 else
527 find /lib*/security -xtype f
528 fi
529 find /etc/pam.d /etc/security -xtype f
0fe15dc8 530 ) | while read file; do
889a9042
RC
531 inst $file
532 done
417491f1 533
d5172c79
EV
534 # pam_unix depends on unix_chkpwd.
535 # see http://www.linux-pam.org/Linux-PAM-html/sag-pam_unix.html
536 dracut_install -o unix_chkpwd
537
417491f1
EV
538 [[ "$LOOKS_LIKE_DEBIAN" ]] &&
539 cp /etc/pam.d/systemd-user $initdir/etc/pam.d/
e14b866b
ZJS
540
541 # set empty root password for easy debugging
542 sed -i 's/^root:x:/root::/' $initdir/etc/passwd
889a9042
RC
543}
544
545install_keymaps() {
546 for i in \
547 /usr/lib/kbd/keymaps/include/* \
548 /usr/lib/kbd/keymaps/i386/include/* \
549 /usr/lib/kbd/keymaps/i386/qwerty/us.*; do
550 [[ -f $i ]] || continue
551 inst $i
552 done
553}
554
555install_fonts() {
556 for i in \
25b47f96 557 /usr/lib/kbd/consolefonts/eurlatgr* \
889a9042
RC
558 /usr/lib/kbd/consolefonts/latarcyrheb-sun16*; do
559 [[ -f $i ]] || continue
560 inst $i
561 done
562}
563
564install_terminfo() {
565 for _terminfodir in /lib/terminfo /etc/terminfo /usr/share/terminfo; do
566 [ -f ${_terminfodir}/l/linux ] && break
567 done
568 dracut_install -o ${_terminfodir}/l/linux
569}
570
571setup_testsuite() {
53d90f95 572 cp $TEST_BASE_DIR/testsuite.target $initdir/etc/systemd/system/
5c404f1a 573 cp $TEST_BASE_DIR/end.service $initdir/etc/systemd/system/
889a9042
RC
574
575 mkdir -p $initdir/etc/systemd/system/testsuite.target.wants
576 ln -fs $TEST_BASE_DIR/testsuite.service $initdir/etc/systemd/system/testsuite.target.wants/testsuite.service
577 ln -fs $TEST_BASE_DIR/end.service $initdir/etc/systemd/system/testsuite.target.wants/end.service
578
579 # make the testsuite the default target
580 ln -fs testsuite.target $initdir/etc/systemd/system/default.target
581}
582
583setup_nspawn_root() {
584 rm -fr $TESTDIR/nspawn-root
585 ddebug "cp -ar $initdir $TESTDIR/nspawn-root"
586 cp -ar $initdir $TESTDIR/nspawn-root
587 # we don't mount in the nspawn root
588 rm -f $TESTDIR/nspawn-root/etc/fstab
589}
590
0d6e798a 591setup_basic_dirs() {
889a9042
RC
592 mkdir -p $initdir/run
593 mkdir -p $initdir/etc/systemd/system
594 mkdir -p $initdir/var/log/journal
595
0d6e798a 596 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
898720b7
HH
597 if [ -L "/$d" ]; then
598 inst_symlink "/$d"
599 else
0d6e798a 600 inst_dir "/$d"
898720b7
HH
601 fi
602 done
603
604 ln -sfn /run "$initdir/var/run"
605 ln -sfn /run/lock "$initdir/var/lock"
606}
607
608inst_libs() {
609 local _bin=$1
610 local _so_regex='([^ ]*/lib[^/]*/[^ ]*\.so[^ ]*)'
611 local _file _line
612
613 LC_ALL=C ldd "$_bin" 2>/dev/null | while read _line; do
614 [[ $_line = 'not a dynamic executable' ]] && break
615
616 if [[ $_line =~ $_so_regex ]]; then
617 _file=${BASH_REMATCH[1]}
618 [[ -e ${initdir}/$_file ]] && continue
619 inst_library "$_file"
620 continue
621 fi
622
623 if [[ $_line =~ not\ found ]]; then
624 dfatal "Missing a shared library required by $_bin."
625 dfatal "Run \"ldd $_bin\" to find out what it is."
626 dfatal "$_line"
627 dfatal "dracut cannot create an initrd."
628 exit 1
629 fi
630 done
631}
632
633import_testdir() {
898720b7
HH
634 [[ -e $STATEFILE ]] && . $STATEFILE
635 if [[ -z "$TESTDIR" ]] || [[ ! -d "$TESTDIR" ]]; then
636 TESTDIR=$(mktemp --tmpdir=/var/tmp -d -t systemd-test.XXXXXX)
637 echo "TESTDIR=\"$TESTDIR\"" > $STATEFILE
638 export TESTDIR
639 fi
640}
641
889a9042
RC
642import_initdir() {
643 initdir=$TESTDIR/root
644 export initdir
645}
646
898720b7
HH
647## @brief Converts numeric logging level to the first letter of level name.
648#
649# @param lvl Numeric logging level in range from 1 to 6.
650# @retval 1 if @a lvl is out of range.
651# @retval 0 if @a lvl is correct.
652# @result Echoes first letter of level name.
653_lvl2char() {
654 case "$1" in
655 1) echo F;;
656 2) echo E;;
657 3) echo W;;
658 4) echo I;;
659 5) echo D;;
660 6) echo T;;
661 *) return 1;;
662 esac
663}
664
665## @brief Internal helper function for _do_dlog()
666#
667# @param lvl Numeric logging level.
668# @param msg Message.
669# @retval 0 It's always returned, even if logging failed.
670#
671# @note This function is not supposed to be called manually. Please use
672# dtrace(), ddebug(), or others instead which wrap this one.
673#
674# This function calls _do_dlog() either with parameter msg, or if
675# none is given, it will read standard input and will use every line as
676# a message.
677#
678# This enables:
679# dwarn "This is a warning"
680# echo "This is a warning" | dwarn
681LOG_LEVEL=4
682
683dlog() {
684 [ -z "$LOG_LEVEL" ] && return 0
685 [ $1 -le $LOG_LEVEL ] || return 0
686 local lvl="$1"; shift
687 local lvlc=$(_lvl2char "$lvl") || return 0
688
689 if [ $# -ge 1 ]; then
690 echo "$lvlc: $*"
691 else
692 while read line; do
693 echo "$lvlc: " "$line"
694 done
695 fi
696}
697
698## @brief Logs message at TRACE level (6)
699#
700# @param msg Message.
701# @retval 0 It's always returned, even if logging failed.
702dtrace() {
703 set +x
704 dlog 6 "$@"
705 [ -n "$debug" ] && set -x || :
706}
707
708## @brief Logs message at DEBUG level (5)
709#
710# @param msg Message.
711# @retval 0 It's always returned, even if logging failed.
712ddebug() {
0d6e798a 713# set +x
898720b7 714 dlog 5 "$@"
0d6e798a 715# [ -n "$debug" ] && set -x || :
898720b7
HH
716}
717
718## @brief Logs message at INFO level (4)
719#
720# @param msg Message.
721# @retval 0 It's always returned, even if logging failed.
722dinfo() {
723 set +x
724 dlog 4 "$@"
725 [ -n "$debug" ] && set -x || :
726}
727
728## @brief Logs message at WARN level (3)
729#
730# @param msg Message.
731# @retval 0 It's always returned, even if logging failed.
732dwarn() {
733 set +x
734 dlog 3 "$@"
735 [ -n "$debug" ] && set -x || :
736}
737
738## @brief Logs message at ERROR level (2)
739#
740# @param msg Message.
741# @retval 0 It's always returned, even if logging failed.
742derror() {
0d6e798a 743# set +x
898720b7 744 dlog 2 "$@"
0d6e798a 745# [ -n "$debug" ] && set -x || :
898720b7
HH
746}
747
748## @brief Logs message at FATAL level (1)
749#
750# @param msg Message.
751# @retval 0 It's always returned, even if logging failed.
752dfatal() {
753 set +x
754 dlog 1 "$@"
755 [ -n "$debug" ] && set -x || :
756}
757
758
759# Generic substring function. If $2 is in $1, return 0.
760strstr() { [ "${1#*$2*}" != "$1" ]; }
761
762# normalize_path <path>
763# Prints the normalized path, where it removes any duplicated
764# and trailing slashes.
765# Example:
766# $ normalize_path ///test/test//
767# /test/test
768normalize_path() {
769 shopt -q -s extglob
770 set -- "${1//+(\/)//}"
771 shopt -q -u extglob
772 echo "${1%/}"
773}
774
775# convert_abs_rel <from> <to>
776# Prints the relative path, when creating a symlink to <to> from <from>.
777# Example:
778# $ convert_abs_rel /usr/bin/test /bin/test-2
779# ../../bin/test-2
780# $ ln -s $(convert_abs_rel /usr/bin/test /bin/test-2) /usr/bin/test
781convert_abs_rel() {
782 local __current __absolute __abssize __cursize __newpath
783 local -i __i __level
784
785 set -- "$(normalize_path "$1")" "$(normalize_path "$2")"
786
787 # corner case #1 - self looping link
788 [[ "$1" == "$2" ]] && { echo "${1##*/}"; return; }
789
790 # corner case #2 - own dir link
791 [[ "${1%/*}" == "$2" ]] && { echo "."; return; }
792
793 IFS="/" __current=($1)
794 IFS="/" __absolute=($2)
795
796 __abssize=${#__absolute[@]}
797 __cursize=${#__current[@]}
798
799 while [[ ${__absolute[__level]} == ${__current[__level]} ]]
800 do
801 (( __level++ ))
802 if (( __level > __abssize || __level > __cursize ))
803 then
804 break
805 fi
806 done
807
808 for ((__i = __level; __i < __cursize-1; __i++))
809 do
810 if ((__i > __level))
811 then
812 __newpath=$__newpath"/"
813 fi
814 __newpath=$__newpath".."
815 done
816
817 for ((__i = __level; __i < __abssize; __i++))
818 do
819 if [[ -n $__newpath ]]
820 then
821 __newpath=$__newpath"/"
822 fi
823 __newpath=$__newpath${__absolute[__i]}
824 done
825
826 echo "$__newpath"
827}
828
829
830# Install a directory, keeping symlinks as on the original system.
831# Example: if /lib points to /lib64 on the host, "inst_dir /lib/file"
832# will create ${initdir}/lib64, ${initdir}/lib64/file,
833# and a symlink ${initdir}/lib -> lib64.
834inst_dir() {
835 [[ -e ${initdir}/"$1" ]] && return 0 # already there
836
837 local _dir="$1" _part="${1%/*}" _file
838 while [[ "$_part" != "${_part%/*}" ]] && ! [[ -e "${initdir}/${_part}" ]]; do
839 _dir="$_part $_dir"
840 _part=${_part%/*}
841 done
842
843 # iterate over parent directories
844 for _file in $_dir; do
845 [[ -e "${initdir}/$_file" ]] && continue
846 if [[ -L $_file ]]; then
847 inst_symlink "$_file"
848 else
849 # create directory
850 mkdir -m 0755 -p "${initdir}/$_file" || return 1
851 [[ -e "$_file" ]] && chmod --reference="$_file" "${initdir}/$_file"
852 chmod u+w "${initdir}/$_file"
853 fi
854 done
855}
856
857# $1 = file to copy to ramdisk
858# $2 (optional) Name for the file on the ramdisk
859# Location of the image dir is assumed to be $initdir
860# We never overwrite the target if it exists.
861inst_simple() {
862 [[ -f "$1" ]] || return 1
863 strstr "$1" "/" || return 1
864
865 local _src=$1 target="${2:-$1}"
866 if ! [[ -d ${initdir}/$target ]]; then
867 [[ -e ${initdir}/$target ]] && return 0
868 [[ -L ${initdir}/$target ]] && return 0
869 [[ -d "${initdir}/${target%/*}" ]] || inst_dir "${target%/*}"
870 fi
871 # install checksum files also
872 if [[ -e "${_src%/*}/.${_src##*/}.hmac" ]]; then
873 inst "${_src%/*}/.${_src##*/}.hmac" "${target%/*}/.${target##*/}.hmac"
874 fi
875 ddebug "Installing $_src"
876 cp --sparse=always -pfL "$_src" "${initdir}/$target"
877}
878
879# find symlinks linked to given library file
880# $1 = library file
881# Function searches for symlinks by stripping version numbers appended to
882# library filename, checks if it points to the same target and finally
883# prints the list of symlinks to stdout.
884#
885# Example:
886# rev_lib_symlinks libfoo.so.8.1
887# output: libfoo.so.8 libfoo.so
888# (Only if libfoo.so.8 and libfoo.so exists on host system.)
889rev_lib_symlinks() {
890 [[ ! $1 ]] && return 0
891
892 local fn="$1" orig="$(readlink -f "$1")" links=''
893
894 [[ ${fn} =~ .*\.so\..* ]] || return 1
895
896 until [[ ${fn##*.} == so ]]; do
897 fn="${fn%.*}"
898 [[ -L ${fn} && $(readlink -f "${fn}") == ${orig} ]] && links+=" ${fn}"
899 done
900
901 echo "${links}"
902}
903
904# Same as above, but specialized to handle dynamic libraries.
905# It handles making symlinks according to how the original library
906# is referenced.
907inst_library() {
908 local _src="$1" _dest=${2:-$1} _lib _reallib _symlink
909 strstr "$1" "/" || return 1
910 [[ -e $initdir/$_dest ]] && return 0
911 if [[ -L $_src ]]; then
912 # install checksum files also
913 if [[ -e "${_src%/*}/.${_src##*/}.hmac" ]]; then
914 inst "${_src%/*}/.${_src##*/}.hmac" "${_dest%/*}/.${_dest##*/}.hmac"
915 fi
916 _reallib=$(readlink -f "$_src")
917 inst_simple "$_reallib" "$_reallib"
918 inst_dir "${_dest%/*}"
919 [[ -d "${_dest%/*}" ]] && _dest=$(readlink -f "${_dest%/*}")/${_dest##*/}
920 ln -sfn $(convert_abs_rel "${_dest}" "${_reallib}") "${initdir}/${_dest}"
921 else
922 inst_simple "$_src" "$_dest"
923 fi
924
925 # Create additional symlinks. See rev_symlinks description.
926 for _symlink in $(rev_lib_symlinks $_src) $(rev_lib_symlinks $_reallib); do
818567fc 927 [[ -e $initdir/$_symlink ]] || {
898720b7
HH
928 ddebug "Creating extra symlink: $_symlink"
929 inst_symlink $_symlink
930 }
931 done
932}
933
934# find a binary. If we were not passed the full path directly,
935# search in the usual places to find the binary.
936find_binary() {
937 if [[ -z ${1##/*} ]]; then
938 if [[ -x $1 ]] || { strstr "$1" ".so" && ldd $1 &>/dev/null; }; then
939 echo $1
940 return 0
941 fi
942 fi
943
944 type -P $1
945}
946
947# Same as above, but specialized to install binary executables.
948# Install binary executable, and all shared library dependencies, if any.
949inst_binary() {
950 local _bin _target
951 _bin=$(find_binary "$1") || return 1
952 _target=${2:-$_bin}
953 [[ -e $initdir/$_target ]] && return 0
954 [[ -L $_bin ]] && inst_symlink $_bin $_target && return 0
955 local _file _line
956 local _so_regex='([^ ]*/lib[^/]*/[^ ]*\.so[^ ]*)'
957 # I love bash!
958 LC_ALL=C ldd "$_bin" 2>/dev/null | while read _line; do
959 [[ $_line = 'not a dynamic executable' ]] && break
960
961 if [[ $_line =~ $_so_regex ]]; then
962 _file=${BASH_REMATCH[1]}
963 [[ -e ${initdir}/$_file ]] && continue
964 inst_library "$_file"
965 continue
966 fi
967
968 if [[ $_line =~ not\ found ]]; then
969 dfatal "Missing a shared library required by $_bin."
970 dfatal "Run \"ldd $_bin\" to find out what it is."
971 dfatal "$_line"
972 dfatal "dracut cannot create an initrd."
973 exit 1
974 fi
975 done
976 inst_simple "$_bin" "$_target"
977}
978
979# same as above, except for shell scripts.
980# If your shell script does not start with shebang, it is not a shell script.
981inst_script() {
982 local _bin
983 _bin=$(find_binary "$1") || return 1
984 shift
985 local _line _shebang_regex
986 read -r -n 80 _line <"$_bin"
987 # If debug is set, clean unprintable chars to prevent messing up the term
988 [[ $debug ]] && _line=$(echo -n "$_line" | tr -c -d '[:print:][:space:]')
989 _shebang_regex='(#! *)(/[^ ]+).*'
990 [[ $_line =~ $_shebang_regex ]] || return 1
991 inst "${BASH_REMATCH[2]}" && inst_simple "$_bin" "$@"
992}
993
994# same as above, but specialized for symlinks
995inst_symlink() {
996 local _src=$1 _target=${2:-$1} _realsrc
997 strstr "$1" "/" || return 1
998 [[ -L $1 ]] || return 1
999 [[ -L $initdir/$_target ]] && return 0
1000 _realsrc=$(readlink -f "$_src")
1001 if ! [[ -e $initdir/$_realsrc ]]; then
1002 if [[ -d $_realsrc ]]; then
1003 inst_dir "$_realsrc"
1004 else
1005 inst "$_realsrc"
1006 fi
1007 fi
1008 [[ ! -e $initdir/${_target%/*} ]] && inst_dir "${_target%/*}"
1009 [[ -d ${_target%/*} ]] && _target=$(readlink -f ${_target%/*})/${_target##*/}
1010 ln -sfn $(convert_abs_rel "${_target}" "${_realsrc}") "$initdir/$_target"
1011}
1012
1013# attempt to install any programs specified in a udev rule
1014inst_rule_programs() {
1015 local _prog _bin
1016
1017 if grep -qE 'PROGRAM==?"[^ "]+' "$1"; then
1018 for _prog in $(grep -E 'PROGRAM==?"[^ "]+' "$1" | sed -r 's/.*PROGRAM==?"([^ "]+).*/\1/'); do
1019 if [ -x /lib/udev/$_prog ]; then
1020 _bin=/lib/udev/$_prog
1021 else
1022 _bin=$(find_binary "$_prog") || {
1023 dinfo "Skipping program $_prog using in udev rule $(basename $1) as it cannot be found"
1024 continue;
1025 }
1026 fi
1027
1028 #dinfo "Installing $_bin due to it's use in the udev rule $(basename $1)"
1029 dracut_install "$_bin"
1030 done
1031 fi
1032}
1033
1034# udev rules always get installed in the same place, so
1035# create a function to install them to make life simpler.
1036inst_rules() {
1037 local _target=/etc/udev/rules.d _rule _found
1038
1039 inst_dir "/lib/udev/rules.d"
1040 inst_dir "$_target"
1041 for _rule in "$@"; do
1042 if [ "${rule#/}" = "$rule" ]; then
1043 for r in /lib/udev/rules.d /etc/udev/rules.d; do
1044 if [[ -f $r/$_rule ]]; then
1045 _found="$r/$_rule"
1046 inst_simple "$_found"
1047 inst_rule_programs "$_found"
1048 fi
1049 done
1050 fi
1051 for r in '' ./ $dracutbasedir/rules.d/; do
1052 if [[ -f ${r}$_rule ]]; then
1053 _found="${r}$_rule"
1054 inst_simple "$_found" "$_target/${_found##*/}"
1055 inst_rule_programs "$_found"
1056 fi
1057 done
1058 [[ $_found ]] || dinfo "Skipping udev rule: $_rule"
1059 done
1060}
1061
1062# general purpose installation function
1063# Same args as above.
1064inst() {
1065 local _x
1066
1067 case $# in
1068 1) ;;
1069 2) [[ ! $initdir && -d $2 ]] && export initdir=$2
1070 [[ $initdir = $2 ]] && set $1;;
1071 3) [[ -z $initdir ]] && export initdir=$2
1072 set $1 $3;;
1073 *) dfatal "inst only takes 1 or 2 or 3 arguments"
1074 exit 1;;
1075 esac
1076 for _x in inst_symlink inst_script inst_binary inst_simple; do
1077 $_x "$@" && return 0
1078 done
1079 return 1
1080}
1081
1082# install any of listed files
1083#
1084# If first argument is '-d' and second some destination path, first accessible
1085# source is installed into this path, otherwise it will installed in the same
1086# path as source. If none of listed files was installed, function return 1.
1087# On first successful installation it returns with 0 status.
1088#
1089# Example:
1090#
1091# inst_any -d /bin/foo /bin/bar /bin/baz
1092#
1093# Lets assume that /bin/baz exists, so it will be installed as /bin/foo in
1094# initramfs.
1095inst_any() {
1096 local to f
1097
1098 [[ $1 = '-d' ]] && to="$2" && shift 2
1099
1100 for f in "$@"; do
1101 if [[ -e $f ]]; then
1102 [[ $to ]] && inst "$f" "$to" && return 0
1103 inst "$f" && return 0
1104 fi
1105 done
1106
1107 return 1
1108}
1109
1110# dracut_install [-o ] <file> [<file> ... ]
1111# Install <file> to the initramfs image
1112# -o optionally install the <file> and don't fail, if it is not there
1113dracut_install() {
1114 local _optional=no
1115 if [[ $1 = '-o' ]]; then
1116 _optional=yes
1117 shift
1118 fi
1119 while (($# > 0)); do
1120 if ! inst "$1" ; then
1121 if [[ $_optional = yes ]]; then
1122 dinfo "Skipping program $1 as it cannot be found and is" \
1123 "flagged to be optional"
1124 else
1125 dfatal "Failed to install $1"
1126 exit 1
1127 fi
1128 fi
1129 shift
1130 done
1131}
1132
0d6e798a
HH
1133# Install a single kernel module along with any firmware it may require.
1134# $1 = full path to kernel module to install
1135install_kmod_with_fw() {
1136 # no need to go further if the module is already installed
1137
1138 [[ -e "${initdir}/lib/modules/$KERNEL_VER/${1##*/lib/modules/$KERNEL_VER/}" ]] \
1139 && return 0
1140
1141 [[ -e "$initdir/.kernelmodseen/${1##*/}" ]] && return 0
1142
1143 if [[ $omit_drivers ]]; then
1144 local _kmod=${1##*/}
1145 _kmod=${_kmod%.ko}
1146 _kmod=${_kmod/-/_}
1147 if [[ "$_kmod" =~ $omit_drivers ]]; then
1148 dinfo "Omitting driver $_kmod"
1149 return 1
1150 fi
1151 if [[ "${1##*/lib/modules/$KERNEL_VER/}" =~ $omit_drivers ]]; then
1152 dinfo "Omitting driver $_kmod"
1153 return 1
1154 fi
1155 fi
1156
1157 [ -d "$initdir/.kernelmodseen" ] && \
1158 > "$initdir/.kernelmodseen/${1##*/}"
1159
1160 inst_simple "$1" "/lib/modules/$KERNEL_VER/${1##*/lib/modules/$KERNEL_VER/}" \
1161 || return $?
1162
1163 local _modname=${1##*/} _fwdir _found _fw
1164 _modname=${_modname%.ko*}
1165 for _fw in $(modinfo -k $KERNEL_VER -F firmware $1 2>/dev/null); do
1166 _found=''
1167 for _fwdir in $fw_dir; do
1168 if [[ -d $_fwdir && -f $_fwdir/$_fw ]]; then
1169 inst_simple "$_fwdir/$_fw" "/lib/firmware/$_fw"
1170 _found=yes
1171 fi
1172 done
1173 if [[ $_found != yes ]]; then
1174 if ! grep -qe "\<${_modname//-/_}\>" /proc/modules; then
1175 dinfo "Possible missing firmware \"${_fw}\" for kernel module" \
1176 "\"${_modname}.ko\""
1177 else
1178 dwarn "Possible missing firmware \"${_fw}\" for kernel module" \
1179 "\"${_modname}.ko\""
1180 fi
1181 fi
1182 done
1183 return 0
1184}
1185
1186# Do something with all the dependencies of a kernel module.
1187# Note that kernel modules depend on themselves using the technique we use
1188# $1 = function to call for each dependency we find
1189# It will be passed the full path to the found kernel module
1190# $2 = module to get dependencies for
1191# rest of args = arguments to modprobe
1192# _fderr specifies FD passed from surrounding scope
1193for_each_kmod_dep() {
1194 local _func=$1 _kmod=$2 _cmd _modpath _options _found=0
1195 shift 2
1196 modprobe "$@" --ignore-install --show-depends $_kmod 2>&${_fderr} | (
1197 while read _cmd _modpath _options; do
1198 [[ $_cmd = insmod ]] || continue
1199 $_func ${_modpath} || exit $?
1200 _found=1
1201 done
1202 [[ $_found -eq 0 ]] && exit 1
1203 exit 0
1204 )
1205}
1206
1207# filter kernel modules to install certain modules that meet specific
1208# requirements.
1209# $1 = search only in subdirectory of /kernel/$1
1210# $2 = function to call with module name to filter.
1211# This function will be passed the full path to the module to test.
c5315881 1212# The behavior of this function can vary depending on whether $hostonly is set.
0d6e798a
HH
1213# If it is, we will only look at modules that are already in memory.
1214# If it is not, we will look at all kernel modules
1215# This function returns the full filenames of modules that match $1
1216filter_kernel_modules_by_path () (
1217 local _modname _filtercmd
1218 if ! [[ $hostonly ]]; then
1219 _filtercmd='find "$KERNEL_MODS/kernel/$1" "$KERNEL_MODS/extra"'
1220 _filtercmd+=' "$KERNEL_MODS/weak-updates" -name "*.ko" -o -name "*.ko.gz"'
1221 _filtercmd+=' -o -name "*.ko.xz"'
1222 _filtercmd+=' 2>/dev/null'
1223 else
1224 _filtercmd='cut -d " " -f 1 </proc/modules|xargs modinfo -F filename '
1225 _filtercmd+='-k $KERNEL_VER 2>/dev/null'
1226 fi
1227 for _modname in $(eval $_filtercmd); do
1228 case $_modname in
1229 *.ko) "$2" "$_modname" && echo "$_modname";;
1230 *.ko.gz) gzip -dc "$_modname" > $initdir/$$.ko
1231 $2 $initdir/$$.ko && echo "$_modname"
1232 rm -f $initdir/$$.ko
1233 ;;
1234 *.ko.xz) xz -dc "$_modname" > $initdir/$$.ko
1235 $2 $initdir/$$.ko && echo "$_modname"
1236 rm -f $initdir/$$.ko
1237 ;;
1238 esac
1239 done
1240)
1241find_kernel_modules_by_path () (
1242 if ! [[ $hostonly ]]; then
1243 find "$KERNEL_MODS/kernel/$1" "$KERNEL_MODS/extra" "$KERNEL_MODS/weak-updates" \
1244 -name "*.ko" -o -name "*.ko.gz" -o -name "*.ko.xz" 2>/dev/null
1245 else
1246 cut -d " " -f 1 </proc/modules \
1247 | xargs modinfo -F filename -k $KERNEL_VER 2>/dev/null
1248 fi
1249)
1250
1251filter_kernel_modules () {
1252 filter_kernel_modules_by_path drivers "$1"
1253}
1254
1255find_kernel_modules () {
1256 find_kernel_modules_by_path drivers
1257}
1258
1259# instmods [-c] <kernel module> [<kernel module> ... ]
1260# instmods [-c] <kernel subsystem>
1261# install kernel modules along with all their dependencies.
1262# <kernel subsystem> can be e.g. "=block" or "=drivers/usb/storage"
1263instmods() {
1264 [[ $no_kernel = yes ]] && return
1265 # called [sub]functions inherit _fderr
1266 local _fderr=9
1267 local _check=no
1268 if [[ $1 = '-c' ]]; then
1269 _check=yes
1270 shift
1271 fi
1272
1273 function inst1mod() {
1274 local _ret=0 _mod="$1"
1275 case $_mod in
1276 =*)
1277 if [ -f $KERNEL_MODS/modules.${_mod#=} ]; then
1278 ( [[ "$_mpargs" ]] && echo $_mpargs
1279 cat "${KERNEL_MODS}/modules.${_mod#=}" ) \
1280 | instmods
1281 else
1282 ( [[ "$_mpargs" ]] && echo $_mpargs
1283 find "$KERNEL_MODS" -path "*/${_mod#=}/*" -printf '%f\n' ) \
1284 | instmods
1285 fi
1286 ;;
1287 --*) _mpargs+=" $_mod" ;;
1288 i2o_scsi) return ;; # Do not load this diagnostic-only module
1289 *)
1290 _mod=${_mod##*/}
1291 # if we are already installed, skip this module and go on
1292 # to the next one.
1293 [[ -f "$initdir/.kernelmodseen/${_mod%.ko}.ko" ]] && return
1294
1295 if [[ $omit_drivers ]] && [[ "$1" =~ $omit_drivers ]]; then
1296 dinfo "Omitting driver ${_mod##$KERNEL_MODS}"
1297 return
1298 fi
1299 # If we are building a host-specific initramfs and this
1300 # module is not already loaded, move on to the next one.
1301 [[ $hostonly ]] && ! grep -qe "\<${_mod//-/_}\>" /proc/modules \
1302 && ! echo $add_drivers | grep -qe "\<${_mod}\>" \
1303 && return
1304
1305 # We use '-d' option in modprobe only if modules prefix path
1306 # differs from default '/'. This allows us to use Dracut with
1307 # old version of modprobe which doesn't have '-d' option.
1308 local _moddirname=${KERNEL_MODS%%/lib/modules/*}
1309 [[ -n ${_moddirname} ]] && _moddirname="-d ${_moddirname}/"
1310
1311 # ok, load the module, all its dependencies, and any firmware
1312 # it may require
1313 for_each_kmod_dep install_kmod_with_fw $_mod \
1314 --set-version $KERNEL_VER ${_moddirname} $_mpargs
1315 ((_ret+=$?))
1316 ;;
1317 esac
1318 return $_ret
1319 }
1320
1321 function instmods_1() {
1322 local _mod _mpargs
1323 if (($# == 0)); then # filenames from stdin
1324 while read _mod; do
1325 inst1mod "${_mod%.ko*}" || {
1326 if [ "$_check" = "yes" ]; then
1327 dfatal "Failed to install $_mod"
1328 return 1
1329 fi
1330 }
1331 done
1332 fi
1333 while (($# > 0)); do # filenames as arguments
1334 inst1mod ${1%.ko*} || {
1335 if [ "$_check" = "yes" ]; then
1336 dfatal "Failed to install $1"
1337 return 1
1338 fi
1339 }
1340 shift
1341 done
1342 return 0
1343 }
1344
1345 local _ret _filter_not_found='FATAL: Module .* not found.'
1346 set -o pipefail
1347 # Capture all stderr from modprobe to _fderr. We could use {var}>...
1348 # redirections, but that would make dracut require bash4 at least.
1349 eval "( instmods_1 \"\$@\" ) ${_fderr}>&1" \
1350 | while read line; do [[ "$line" =~ $_filter_not_found ]] && echo $line || echo $line >&2 ;done | derror
1351 _ret=$?
1352 set +o pipefail
1353 return $_ret
1354}
898720b7
HH
1355
1356# inst_libdir_file [-n <pattern>] <file> [<file>...]
1357# Install a <file> located on a lib directory to the initramfs image
1358# -n <pattern> install non-matching files
1359inst_libdir_file() {
1360 if [[ "$1" == "-n" ]]; then
1361 local _pattern=$1
1362 shift 2
1363 for _dir in $libdirs; do
1364 for _i in "$@"; do
1365 for _f in "$_dir"/$_i; do
1366 [[ "$_i" =~ $_pattern ]] || continue
1367 [[ -e "$_i" ]] && dracut_install "$_i"
1368 done
1369 done
1370 done
1371 else
1372 for _dir in $libdirs; do
1373 for _i in "$@"; do
1374 for _f in "$_dir"/$_i; do
1375 [[ -e "$_f" ]] && dracut_install "$_f"
1376 done
1377 done
1378 done
1379 fi
1380}
1381
85393d8f
TB
1382setup_suse() {
1383 ln -s ../usr/bin/systemctl $initdir/bin/systemctl
1384 ln -s ../usr/lib/systemd $initdir/lib/systemd
1385 inst_simple "/usr/lib/systemd/system/haveged.service"
1386}
1387
054ee249
MP
1388# can be overridden in specific test
1389test_cleanup() {
1390 umount $TESTDIR/root 2>/dev/null || true
818567fc 1391 [[ $LOOPDEV ]] && losetup -d $LOOPDEV || true
054ee249
MP
1392 return 0
1393}
1394
1395test_run() {
1396 if [ -z "$TEST_NO_QEMU" ]; then
1397 if run_qemu; then
1398 check_result_qemu || return 1
1399 else
1400 dwarn "can't run QEMU, skipping"
1401 fi
1402 fi
1403 if [ -z "$TEST_NO_NSPAWN" ]; then
1404 if run_nspawn; then
1405 check_result_nspawn || return 1
1406 else
1407 dwarn "can't run systemd-nspawn, skipping"
1408 fi
1409 fi
1410 return 0
1411}
1412
898720b7 1413do_test() {
33a5e20f
HH
1414 if [[ $UID != "0" ]]; then
1415 echo "TEST: $TEST_DESCRIPTION [SKIPPED]: not root" >&2
1416 exit 0
1417 fi
1418
898720b7
HH
1419# Detect lib paths
1420 [[ $libdir ]] || for libdir in /lib64 /lib; do
1421 [[ -d $libdir ]] && libdirs+=" $libdir" && break
1422 done
1423
1424 [[ $usrlibdir ]] || for usrlibdir in /usr/lib64 /usr/lib; do
1425 [[ -d $usrlibdir ]] && libdirs+=" $usrlibdir" && break
1426 done
1427
22077c9c
MP
1428 mkdir -p "$STATEDIR"
1429
898720b7 1430 import_testdir
889a9042 1431 import_initdir
898720b7
HH
1432
1433 while (($# > 0)); do
1434 case $1 in
1435 --run)
1436 echo "TEST RUN: $TEST_DESCRIPTION"
818567fc 1437 if test_run; then
898720b7
HH
1438 echo "TEST RUN: $TEST_DESCRIPTION [OK]"
1439 else
1440 echo "TEST RUN: $TEST_DESCRIPTION [FAILED]"
1441 fi
1442 exit $ret;;
1443 --setup)
1444 echo "TEST SETUP: $TEST_DESCRIPTION"
1445 test_setup
818567fc 1446 ;;
898720b7
HH
1447 --clean)
1448 echo "TEST CLEANUP: $TEST_DESCRIPTION"
1449 test_cleanup
1450 rm -fr "$TESTDIR"
22077c9c 1451 rm -f "$STATEFILE"
818567fc 1452 ;;
898720b7 1453 --all)
818567fc 1454 ret=0
898720b7
HH
1455 echo -n "TEST: $TEST_DESCRIPTION ";
1456 (
1457 test_setup && test_run
1458 ret=$?
1459 test_cleanup
1460 rm -fr "$TESTDIR"
22077c9c 1461 rm -f "$STATEFILE"
898720b7 1462 exit $ret
818567fc 1463 ) </dev/null >"$TESTLOG" 2>&1 || ret=$?
898720b7 1464 if [ $ret -eq 0 ]; then
22077c9c 1465 rm "$TESTLOG"
898720b7
HH
1466 echo "[OK]"
1467 else
1468 echo "[FAILED]"
22077c9c 1469 echo "see $TESTLOG"
898720b7
HH
1470 fi
1471 exit $ret;;
1472 *) break ;;
1473 esac
1474 shift
1475 done
1476}