mirror of
https://github.com/libguestfs/libguestfs.git
synced 2026-03-21 22:53:37 +00:00
bash can read input from a spawned process, and even provide input to such process. This feature relies on /dev/fd/ being present. In the past udev silently created this symlink, so this bash feature worked more or less by accident. With recent systemd versions, such as 246 which is included in Leap 15.3, the symlink is not created anymore. As a result scripts, such as /sbin/dhclient-script, fail to work properly. This symlink should have been created in version 1 of this variant of /init. https://bugzilla.opensuse.org/show_bug.cgi?id=1190501 Signed-off-by: Olaf Hering <olaf@aepfle.de>
267 lines
7.0 KiB
Bash
Executable File
267 lines
7.0 KiB
Bash
Executable File
#!/bin/bash
|
||
|
||
echo Starting /init script ...
|
||
|
||
PATH=/sbin:/usr/sbin:/bin:/usr/bin
|
||
export PATH
|
||
|
||
# Debian bug 606622.
|
||
RUNLEVEL=S
|
||
PREVLEVEL=N
|
||
export RUNLEVEL PREVLEVEL
|
||
|
||
# Make sure /tmp /var/tmp are real directories, not symlinks.
|
||
if [ ! -d /tmp ] || [ ! -d /var/tmp ]; then
|
||
rm -f /tmp /var/tmp
|
||
mkdir /tmp /var/tmp
|
||
chmod 1777 /tmp /var/tmp
|
||
fi
|
||
|
||
# Try to print a stack trace for segfaults inside the appliance.
|
||
for d in /lib64 /lib; do
|
||
f=$d/libSegFault.so
|
||
if [ -f "$f" ]; then
|
||
LD_PRELOAD=$f
|
||
export LD_PRELOAD
|
||
break
|
||
fi
|
||
done
|
||
|
||
mkdir -p /sysroot
|
||
|
||
# Mount /proc.
|
||
if [ ! -d /proc ]; then rm -f /proc; fi
|
||
mkdir -p /proc
|
||
mount -t proc /proc /proc
|
||
|
||
# Parse the kernel command line early (must be after /proc is mounted).
|
||
cmdline=$(</proc/cmdline)
|
||
|
||
if [[ $cmdline == *guestfs_verbose=1* ]]; then
|
||
guestfs_verbose=1
|
||
set -x
|
||
fi
|
||
if [[ $cmdline == *guestfs_network=1* ]]; then
|
||
guestfs_network=1
|
||
fi
|
||
if [[ $cmdline == *guestfs_rescue=1* ]]; then
|
||
guestfs_rescue=1
|
||
fi
|
||
if [[ $cmdline == *guestfs_noreboot=1* ]]; then
|
||
guestfs_noreboot=1
|
||
fi
|
||
if [[ $cmdline == *guestfs_boot_analysis=1* ]]; then
|
||
guestfs_boot_analysis=1
|
||
fi
|
||
|
||
# Mount the other special filesystems.
|
||
if [ ! -d /sys ]; then rm -f /sys; fi
|
||
mkdir -p /sys
|
||
mount -t sysfs /sys /sys
|
||
# taken from initramfs-tools/init --Hilko Bengen
|
||
mkdir -p /run
|
||
mount -t tmpfs -o "nosuid,size=20%,mode=0755" tmpfs /run
|
||
mkdir -p /run/lock
|
||
ln -s ../run/lock /var/lock
|
||
|
||
# On Fedora 23, util-linux creates /etc/mtab in %post .. stupid
|
||
# and e2fsprogs fails if the link doesn't exist .. stupid stupid
|
||
if ! test -e /etc/mtab; then
|
||
ln -s /proc/mounts /etc/mtab
|
||
fi
|
||
|
||
# devtmpfs is required since udev 176
|
||
mount -t devtmpfs /dev /dev
|
||
ln -s /proc/self/fd /dev/fd
|
||
mkdir -p /dev/pts
|
||
mount -t devpts /dev/pts /dev/pts
|
||
mkdir -p /dev/shm
|
||
mount -t tmpfs -o mode=1777 shmfs /dev/shm
|
||
|
||
if [[ $cmdline == *selinux=1* ]]; then
|
||
mount -t selinuxfs none /sys/fs/selinux
|
||
fi
|
||
|
||
# Static nodes must happen before udev is started.
|
||
|
||
# Set up kmod static-nodes (RHBZ#1011907).
|
||
mkdir -p /run/tmpfiles.d
|
||
kmod static-nodes --format=tmpfiles --output=/run/tmpfiles.d/kmod.conf
|
||
|
||
# Create a machine-id with a random UUID
|
||
machine_id=$(dd if=/dev/urandom bs=16 count=1 status=none | od -x -A n)
|
||
echo "${machine_id// /}" > /etc/machine-id
|
||
|
||
# Set up tmpfiles (must run after kmod.conf is created above).
|
||
systemd-tmpfiles --prefix=/dev --prefix=/run --prefix=/var/run --create --boot
|
||
|
||
# Find udevd and run it directly.
|
||
for f in /lib/systemd/systemd-udevd /usr/lib/systemd/systemd-udevd \
|
||
/sbin/udevd /lib/udev/udevd \
|
||
/usr/lib/udev/udevd; do
|
||
if [ -x "$f" ]; then UDEVD="$f"; break; fi
|
||
done
|
||
if [ -z "$UDEVD" ]; then
|
||
echo "error: udev not found! Things will probably not work ..."
|
||
fi
|
||
|
||
$UDEVD --daemon #--debug
|
||
udevadm trigger
|
||
udevadm settle --timeout=600
|
||
|
||
# Disk optimizations.
|
||
# Increase the SCSI timeout so we can read remote images.
|
||
shopt -s nullglob
|
||
for f in /sys/block/sd*/device/timeout; do echo 300 > $f; done
|
||
# https://access.redhat.com/site/solutions/5427
|
||
for f in /sys/block/{h,s,ub,v}d*/queue/scheduler; do echo noop > $f; done
|
||
shopt -u nullglob
|
||
|
||
# Set up the network.
|
||
ip addr add 127.0.0.1/8 brd + dev lo scope host
|
||
ip link set dev lo up
|
||
|
||
if test "$guestfs_network" = 1; then
|
||
iface=$(ls -I all -I default -I lo /proc/sys/net/ipv4/conf)
|
||
# Two workarounds for Ubuntu:
|
||
touch /etc/fstab
|
||
rm -f /etc/dhcp/dhclient-enter-hooks.d/resolved
|
||
if dhclient --version >/dev/null 2>&1; then
|
||
dhclient $iface
|
||
else
|
||
dhcpcd $iface
|
||
fi
|
||
fi
|
||
|
||
# Scan for MDs but don't run arrays unless all expected drives are present
|
||
mdadm -As --auto=yes --no-degraded
|
||
|
||
# Set up a clean LVM environment.
|
||
# Empty LVM configuration file means "all defaults".
|
||
mkdir -p /tmp/lvm
|
||
touch /tmp/lvm/lvm.conf
|
||
LVM_SYSTEM_DIR=/tmp/lvm
|
||
export LVM_SYSTEM_DIR
|
||
lvmetad
|
||
|
||
# Scan for LVM.
|
||
modprobe dm_mod ||:
|
||
lvm pvscan --cache --activate ay
|
||
|
||
# Scan for MDs and run all found arrays even they are in degraded state
|
||
mdadm -As --auto=yes --run
|
||
|
||
# Scan for Windows dynamic disks.
|
||
ldmtool create all
|
||
|
||
# These are useful when debugging.
|
||
if test "$guestfs_verbose" = 1 && test "$guestfs_boot_analysis" != 1; then
|
||
uname -a
|
||
ls -lR /dev
|
||
cat /proc/mounts
|
||
cat /proc/mdstat
|
||
lvm config
|
||
lvm pvs
|
||
lvm vgs
|
||
lvm lvs
|
||
ip a
|
||
ip r
|
||
cat /etc/resolv.conf
|
||
lsmod
|
||
#hwclock -r
|
||
date
|
||
echo -n "clocksource: "
|
||
cat /sys/devices/system/clocksource/clocksource0/current_clocksource
|
||
#ping -n -v -c 5 8.8.8.8
|
||
|
||
echo -n "uptime: "; cat /proc/uptime
|
||
fi
|
||
|
||
# Run the daemon.
|
||
cmd="guestfsd"
|
||
eval `grep -Eo 'guestfs_channel=[^[:space:]]+' /proc/cmdline`
|
||
if test "x$guestfs_channel" != "x"; then
|
||
cmd="$cmd --channel $guestfs_channel"
|
||
fi
|
||
if test "$guestfs_verbose" = 1; then
|
||
cmd="$cmd --verbose"
|
||
fi
|
||
if test "$guestfs_network" = 1; then
|
||
cmd="$cmd --network"
|
||
fi
|
||
if false; then
|
||
# To get a stack trace if the daemon crashes:
|
||
# (1) change this section to 'if true'
|
||
# (2) add 'gdb' to 'appliance/packagelist.in'
|
||
unset LD_PRELOAD
|
||
echo set pagination off > /tmp/gdb-script
|
||
echo run >> /tmp/gdb-script
|
||
echo info registers >> /tmp/gdb-script
|
||
echo 'x/16i $pc' >> /tmp/gdb-script
|
||
echo t a a bt >> /tmp/gdb-script
|
||
echo quit >> /tmp/gdb-script
|
||
cmd="gdb -batch -x /tmp/gdb-script --args $cmd"
|
||
fi
|
||
if ! test "$guestfs_rescue" = 1; then
|
||
echo $cmd
|
||
$cmd
|
||
else
|
||
# Run virt-rescue shell.
|
||
|
||
# We need a daemon, even in virt-rescue.
|
||
$cmd &
|
||
|
||
# XXX This gives a bit of time for virt-rescue to connect to the
|
||
# daemon and mount any filesystems.
|
||
sleep 2
|
||
|
||
# Get name of the serial port, from console= passed by libguestfs.
|
||
# XXX Consider using /proc/consoles
|
||
guestfs_serial=$(grep -Eo 'console=[^[:space:]]+' /proc/cmdline |
|
||
sed s/console=//)
|
||
|
||
# Remove LD_PRELOAD=libSegFault set above.
|
||
unset LD_PRELOAD
|
||
|
||
:> $HOME/.bashrc
|
||
grep -Eo 'TERM=[^[:space:]]+' /proc/cmdline >> $HOME/.bashrc
|
||
echo "PS1='><rescue> '" >> $HOME/.bashrc
|
||
echo "export TERM PS1" >> $HOME/.bashrc
|
||
|
||
# The shell is opened by default on /dev/console, which (on Linux)
|
||
# is not a controlling terminal, causing job control to fail. For
|
||
# how we work around this, see:
|
||
# https://busybox.net/FAQ.html#job_control
|
||
run_bash_with_ctty ()
|
||
{
|
||
setsid bash -c \
|
||
"exec bash </dev/$guestfs_serial >/dev/$guestfs_serial 2>&1"
|
||
}
|
||
|
||
echo
|
||
echo "------------------------------------------------------------"
|
||
echo
|
||
echo "Welcome to virt-rescue, the libguestfs rescue shell."
|
||
echo
|
||
echo "Note: The contents of / (root) are the rescue appliance."
|
||
if ! test -d "/sysroot/dev"; then
|
||
echo "You have to mount the guest’s partitions under /sysroot"
|
||
echo "before you can examine them."
|
||
else
|
||
echo "Use 'cd /sysroot' or 'chroot /sysroot' to see guest filesystems."
|
||
fi
|
||
echo
|
||
run_bash_with_ctty
|
||
echo
|
||
echo "virt-rescue: Syncing the disk now before exiting ..."
|
||
echo
|
||
fi
|
||
|
||
sync
|
||
|
||
if ! test "$guestfs_noreboot" = 1; then
|
||
# qemu has the -no-reboot flag, so issuing a reboot here actually
|
||
# causes qemu to exit gracefully.
|
||
reboot -f
|
||
fi
|