#!/bin/sh # this is the init script version VERSION=@VERSION@ SINGLEMODE=no sysroot="$ROOT"/sysroot splashfile=/.splash.ctrl repofile="$ROOT"/tmp/repositories # some helpers ebegin() { last_emsg="$*" echo "$last_emsg..." > "$ROOT"/dev/kmsg [ "$KOPT_quiet" = yes ] && return 0 echo -n " * $last_emsg: " } eend() { local msg if [ "$1" = 0 ] || [ $# -lt 1 ] ; then echo "$last_emsg: ok." > "$ROOT"/dev/kmsg [ "$KOPT_quiet" = yes ] && return 0 echo "ok." else shift echo "$last_emsg: failed. $*" > "$ROOT"/dev/kmsg if [ "$KOPT_quiet" = "yes" ]; then echo -n "$last_emsg " fi echo "failed. $*" echo "initramfs emergency recovery shell launched. Type 'exit' to continue boot" /bin/busybox sh fi } unpack_apkovl() { local ovl="$1" local dest="$2" local suffix=${ovl##*.} local i ovlfiles=/tmp/ovlfiles if [ "$suffix" = "gz" ]; then tar -C "$dest" -zxvf "$ovl" > $ovlfiles return $? fi # we need openssl. let apk handle deps apk add --quiet --initdb --repositories-file $repofile openssl || return 1 if ! openssl list -1 -cipher-commands | grep "^$suffix$" > /dev/null; then errstr="Cipher $suffix is not supported" return 1 fi local count=0 # beep echo -e "\007" while [ $count -lt 3 ]; do openssl enc -d -$suffix -in "$ovl" | tar --numeric-owner \ -C "$dest" -zxv >$ovlfiles 2>/dev/null && return 0 count=$(( $count + 1 )) done ovlfiles= return 1 } # find mount dir and mount opts for given device in an fstab get_fstab_mount_info() { local search_dev="$1" local fstab="$2" local mntopts= case "$search_dev" in UUID*|LABEL*) search_dev=$(findfs "$search_dev");; esac [ -r "$fstab" ] || return 1 local search_maj_min=$(stat -L -c '%t,%T' $search_dev) while read dev mnt fs mntopts chk; do case "$dev" in UUID*|LABEL*) dev=$(findfs "$dev");; esac if [ -b "$dev" ] || [ -n "$ROOT" ]; then local maj_min=$(stat -L -c '%t,%T' $dev) if [ "$maj_min" = "$search_maj_min" ]; then echo "$mnt $mntopts" return fi fi done < $fstab } # add a boot service to $sysroot rc_add() { mkdir -p $sysroot/etc/runlevels/$2 ln -sf /etc/init.d/$1 $sysroot/etc/runlevels/$2/$1 } # Recursively resolve tty aliases like console or tty0 list_console_devices() { if ! [ -e "$ROOT"/sys/class/tty/$1/active ]; then echo $1 return fi for dev in $(cat "$ROOT"/sys/class/tty/$1/active); do list_console_devices $dev done } detect_serial_consoles() { if [ -f "$ovl" ] || [ "$KOPT_autodetect_serial" = "no" ]; then return fi local n=$(awk '$7 ~ /CTS/ || $7 ~ /DSR/ { print $1 }' "$ROOT"/proc/tty/driver/serial 2>/dev/null) if [ -n "$n" ]; then echo ttyS${n%:} fi for i in "$ROOT"/sys/class/tty/*; do if [ -e "$i"/device ]; then echo ${i##*/} fi done } setup_inittab_console() { term=vt100 # Inquire the kernel for list of console= devices consoles="$(for c in console $KOPT_consoles $(detect_serial_consoles); do list_console_devices $c; done)" for tty in $consoles; do # ignore tty devices that gives I/O error if ! stty -g -F /dev/$tty >/dev/null 2>/dev/null; then continue fi # do nothing if inittab already have the tty set up if ! grep -q "^$tty:" $sysroot/etc/inittab 2>/dev/null; then echo "# enable login on alternative console" \ >> $sysroot/etc/inittab # Baudrate of 0 keeps settings from kernel echo "$tty::respawn:/sbin/getty -L 0 $tty $term" \ >> $sysroot/etc/inittab fi if [ -e "$sysroot"/etc/securetty ] && ! grep -q -w "$tty" "$sysroot"/etc/securetty; then echo "$tty" >> "$sysroot"/etc/securetty fi done } # collect ethernet interfaces, sorted by index ethernets() { for i in "$ROOT/sys/class/net/"*; do local iface="${i##*/}" if [ -d "$i/device" ]; then echo "$(cat "$i/ifindex") $iface" fi done | sort -n | awk '{print $2}' } # find the interface that is has operstate up find_first_interface_up() { local n=0 [ $# -eq 0 ] && return 0 while [ "$n" -le "${LINK_WAIT_MAX:-40}" ]; do for i in "$@"; do if grep -q -F -x "up" "$ROOT/sys/class/net/$i/operstate"; then echo "$i" return fi done sleep 0.1 n=$((n+1)) done return 1 } # if "ip=dhcp" is specified on the command line, we obtain an IP address # using udhcpc. we do this now and not by enabling kernel-mode DHCP because # kernel-model DHCP appears to require that network drivers be built into # the kernel rather than as modules. At this point all applicable modules # in the initrd should have been loaded. # # You need af_packet.ko available as well modules for your Ethernet card. # # See https://www.kernel.org/doc/Documentation/filesystems/nfs/nfsroot.txt # for documentation on the format. # # Valid syntaxes: # ip=client-ip:server-ip:gw-ip:netmask:hostname:device:autoconf: # :dns0-ip:dns1-ip:ntp0-ip # ip=dhcp # "server-ip", "hostname" and "ntp0-ip" are not supported here. # Default (when configure_ip is called without setting ip=): # ip=dhcp # configure_ip() { [ -n "$MAC_ADDRESS" ] && return local IFS=':' # shellcheck disable=SC2086 set -- ${KOPT_ip:-dhcp} unset IFS local client_ip="$1" local gw_ip="$3" local netmask="$4" local iface="$6" local autoconf="$7" local dns1="$8" local dns2="$9" case "$client_ip" in off|none) return;; dhcp) autoconf="dhcp";; esac if [ -e "$ROOT"/etc/mactab ]; then $MOCK nameif -s fi if [ -z "$iface" ] && [ -n "$KOPT_BOOTIF" ]; then mac=$(printf "%s\n" "$KOPT_BOOTIF"|sed 's/^01-//;s/-/:/g') iface=$(grep -l "$mac" "$ROOT"/sys/class/net/*/address | awk -F/ '{print $(NF-1); exit}') fi if [ -z "$iface" ]; then # shellcheck disable=SC2046 set -- $(ethernets) for i in "$@"; do $MOCK ip link set dev "$i" up done iface=$(find_first_interface_up "$@") || iface="$1" # we will use the found interface later so lets keep it up for i in "$@"; do if [ "$i" != "$iface" ]; then $MOCK ip link set dev "$i" down fi done fi if [ -z "$iface" ]; then echo "ERROR: IP requested but no network interface was found" return 1 fi if [ "$autoconf" = "dhcp" ]; then # automatic configuration if [ ! -e "$ROOT"/usr/share/udhcpc/default.script ]; then echo "ERROR: DHCP requested but not present in initrd" return 1 fi ebegin "Obtaining IP via DHCP ($iface)" $MOCK ip link set dev "$iface" up $MOCK udhcpc -i "$iface" -f -q eend $? else # manual configuration if [ -z "$client_ip" ] && [ -z "$netmask" ]; then return fi ebegin "Setting IP ($iface)" if ifconfig "$iface" "$client_ip" netmask "$netmask"; then [ -z "$gw_ip" ] || ip route add 0.0.0.0/0 via "$gw_ip" dev "$iface" fi eend $? fi # Never executes if variables are empty for i in $dns1 $dns2; do echo "nameserver $i" >> /etc/resolv.conf done MAC_ADDRESS=$(cat "$ROOT/sys/class/net/$iface/address") } # configure ipv6 on initramfs # Valid syntaxes: # ip6=client-ip/gateway-ip/interface/dns1/dns2 # configure_ip6() { [ -n "$MAC_ADDRESS" ] && return $MOCK modprobe -a ipv6 local IFS='/' # shellcheck disable=SC2086 set -- ${KOPT_ip6} unset IFS local client6_ip="$1" local gw6_ip="$2" local iface="$3" local dns1="$4" local dns2="$5" if [ -e "$ROOT"/etc/mactab ]; then $MOCK nameif -s fi if [ -z "$iface" ] && [ -n "$KOPT_BOOTIF" ]; then mac=$(printf "%s\n" "$KOPT_BOOTIF"|sed 's/^01-//;s/-/:/g') iface=$(grep -l "$mac" "$ROOT"/sys/class/net/*/address | awk -F/ '{print $(NF-1); exit}') fi # Bring interface up if [ -n "$iface" ]; then $MOCK ip link set dev "$iface" up sleep 3 # wait for interface to fully up. fi if [ -z "$iface" ]; then # shellcheck disable=SC2046 set -- $(ethernets) for i in "$@"; do $MOCK ip link set dev "$i" up done iface=$(find_first_interface_up "$@") || iface="$1" # we will use the found interface later so lets keep it up for i in "$@"; do if [ "$i" != "$iface" ]; then $MOCK ip link set dev "$i" down fi done fi if [ -z "$iface" ]; then echo "ERROR: IP requested but no network interface was found" return 1 fi if [ -z "$client6_ip" ] && [ -z "$netmask" ]; then return fi ebegin "Setting IP ($iface)" if ip -6 addr add $client6_ip dev $iface; then # this is definitely not required by all ipv6 implementation # but it's better to keep things working for all deployment possible # # metric is mandatory! [ -z "$gw6_ip" ] || ip -6 route add "$gw6_ip" dev $iface metric 256 [ -z "$gw6_ip" ] || ip -6 route add ::0/0 via "$gw6_ip" dev "$iface" metric 128 fi eend $? # Never executes if variables are empty for i in $dns1 $dns2; do echo "nameserver $i" >> /etc/resolv.conf done MAC_ADDRESS=$(cat "$ROOT/sys/class/net/$iface/address") } # relocate mountpoint according given fstab and set mount options remount_fstab_entry() { local fstab="${1}" local dir= if ! [ -e "$repofile" ]; then return fi echo "$ovl" | cat - "$repofile" | while read dir; do # skip http(s)/ftp repos for netboot if [ -z "$dir" ] || ! [ -d "$ROOT/$dir" -o -f "$ROOT/$dir" ]; then continue fi local dev=$(df -P "$dir" | tail -1 | awk '{print $1}') local mntinfo="$(get_fstab_mount_info "$dev" "$fstab")" local mnt="${mntinfo% *}" local mntopts="${mntinfo#* }" if [ -n "$mnt" ]; then local oldmnt=$(awk -v d=$ROOT$dev '$1==d {print $2}' "$ROOT"/proc/mounts 2>/dev/null) if [ "$oldmnt" != "$mnt" ]; then mkdir -p "$mnt" $MOCK mount -o move "$oldmnt" "$mnt" fi if [ -n "$mntopts" ]; then $MOCK mount -o remount,"$mntopts" "$mnt" fi fi done } # find the dirs under ALPINE_MNT that are boot repositories find_boot_repositories() { if [ -n "$ALPINE_REPO" ]; then echo "$ALPINE_REPO" | tr ',' '\n' else find "$ROOT"/media/* -maxdepth 3 -name .boot_repository -type f \ | sed 's:/.boot_repository$::' fi } setup_nbd() { $MOCK modprobe -q nbd max_part=8 || return 1 local IFS=, n=0 set -- $KOPT_nbd unset IFS for ops; do local server="${ops%:*}" local port="${ops#*:}" local device="/dev/nbd${n}" [ -b "$device" ] || continue nbd-client "$server" "$port" "$device" && n=$((n+1)) done [ "$n" != 0 ] || return 1 } setup_dropbear() { local port="${KOPT_dropbear}" local keys="" # set the unlock_disc script as shell for root sed -i 's|\(root:x:0:0:root:/root:\).*$|\1/etc/dropbear/unlock_disk|' /etc/passwd echo '/etc/dropbear/unlock_disk' > /etc/shells # transfer authorized_keys mkdir /root/.ssh cp /etc/dropbear/authorized_keys /root/.ssh/authorized_keys dropbear -R -E -s -j -k -p $port } setup_wireguard() { $MOCK modprobe -q wireguard || return 1 local IFS=';' set -- $KOPT_wireguard unset IFS local device="$1" local ips="$2" local config="${3:-/etc/wireguard/initrd.conf}" local IFS=',' set -- $ips unset IFS $MOCK ip link add "$device" type wireguard $MOCK wg setconf "$device" "$config" $MOCK ip link set dev "$device" up for addr in $@; do $MOCK ip addr add dev "$device" "$addr" done } rtc_exists() { local rtc= for rtc in /dev/rtc /dev/rtc[0-9]*; do [ -e "$rtc" ] && break done [ -e "$rtc" ] } # This is used to predict if network access will be necessary is_url() { case "$1" in http://*|https://*|ftp://*) return 0;; *) return 1;; esac } # Do some tasks to make sure mounting the ZFS pool is A-OK prepare_zfs_root() { local _root_vol=${KOPT_root#ZFS=} local _root_pool=${_root_vol%%/*} # Force import if this has been imported on a different system previously. # Import normally otherwise if [ "$KOPT_zfs_force" = 1 ]; then zpool import -N -d /dev -f $_root_pool else zpool import -N -d /dev $_root_pool fi # Ask for encryption password if [ $(zpool list -H -o feature@encryption $_root_pool) = "active" ]; then local _encryption_root=$(zfs get -H -o value encryptionroot $_root_vol) if [ "$_encryption_root" != "-" ]; then eval zfs load-key $_encryption_root fi fi } want_tiny_cloud() { if [ -f "$sysroot/etc/tiny-cloud.disabled" ]; then return 1 fi if [ -n "$KOPT_ds" ] || [ "$KOPT_tinycloud" ]; then return 0 fi if grep -q "^ds=" "$ROOT"/sys/class/dmi/id/product_serial 2>/dev/null; then return 0 fi findfs LABEL=cidata >/dev/null 2>&1 || findfs LABEL=CIDATA >/dev/null 2>&1 } resume_from_disk () { if [ -z "$KOPT_resume" ]; then return fi if [ ! -e "$ROOT"/sys/power/resume ]; then echo "resume: no hibernation support found" return fi echo "Resume from disk" case "$KOPT_resume" in UUID*|LABEL*) resume_dev=$(findfs "$KOPT_resume");; *) resume_dev="$KOPT_resume";; esac printf "%d:%d" $(stat -Lc "0x%t 0x%T" "$resume_dev") > "$ROOT"/sys/power/resume if [ -n "$KOPT_resume_offset" ]; then echo "$KOPT_resume_offset" > "$ROOT"/sys/power/resume_offset fi } /bin/busybox mkdir -p \ "$ROOT"/bin \ "$ROOT"/sbin \ "$ROOT"/usr/bin \ "$ROOT"/usr/sbin \ "$ROOT"/proc \ "$ROOT"/sys \ "$ROOT"/dev \ "$sysroot" \ "$ROOT"/media/cdrom \ "$ROOT"/media/usb \ "$ROOT"/tmp \ "$ROOT"/etc \ "$ROOT"/run/cryptsetup # Spread out busybox symlinks and make them available without full path /bin/busybox --install -s export PATH="$PATH:/usr/bin:/bin:/usr/sbin:/sbin" # Make sure /dev/null is a device node. If /dev/null does not exist yet, the command # mounting the devtmpfs will create it implicitly as an file with the "2>" redirection. # The -c check is required to deal with initramfs with pre-seeded device nodes without # error message. [ -c /dev/null ] || $MOCK mknod -m 666 /dev/null c 1 3 $MOCK mount -t sysfs -o noexec,nosuid,nodev sysfs /sys $MOCK mount -t devtmpfs -o exec,nosuid,mode=0755,size=2M devtmpfs /dev 2>/dev/null \ || $MOCK mount -t tmpfs -o exec,nosuid,mode=0755,size=2M tmpfs /dev # Make sure /dev/kmsg is a device node. Writing to /dev/kmsg allows the use of the # earlyprintk kernel option to monitor early init progress. As above, the -c check # prevents an error if the device node has already been seeded. [ -c /dev/kmsg ] || $MOCK mknod -m 660 /dev/kmsg c 1 11 $MOCK mount -t proc -o noexec,nosuid,nodev proc /proc # pty device nodes (later system will need it) [ -c /dev/ptmx ] || $MOCK mknod -m 666 /dev/ptmx c 5 2 [ -d /dev/pts ] || $MOCK mkdir -m 755 /dev/pts $MOCK mount -t devpts -o gid=5,mode=0620,noexec,nosuid devpts /dev/pts # shared memory area (later system will need it) mkdir -p "$ROOT"/dev/shm $MOCK mount -t tmpfs -o nodev,nosuid,noexec shm /dev/shm # read the kernel options. we need surve things like: # acpi_osi="!Windows 2006" xen-pciback.hide=(01:00.0) set -- $(cat "$ROOT"/proc/cmdline) myopts="BOOTIF alpine_repo aoe aoe_iflist aoe_mtu apkovl autodetect_serial blacklist chart cryptdiscards cryptdm cryptheader cryptkey cryptoffset cryptroot dasd debug_init ds init init_args ip keep_apk_new modules nbd overlaytmpfs overlaytmpfsflags pkgs quiet resume resume_offset root root_size rootflags rootfstype s390x_net splash ssh_key tinycloud uevent_buf_size usbdelay usrflags wireguard zfcp dropbear ip6 " for opt; do case "$opt" in s|single|1) SINGLEMODE=yes continue ;; console=*) opt="${opt#*=}" KOPT_consoles="${opt%%,*} $KOPT_consoles" switch_root_opts="-c /dev/${opt%%,*}" continue ;; esac for i in $myopts; do case "$opt" in $i=*) eval "KOPT_${i}"='${opt#*=}';; $i) eval "KOPT_${i}=yes";; no$i) eval "KOPT_${i}=no";; esac done done echo "Alpine Init $VERSION" > "$ROOT"/dev/kmsg [ "$KOPT_quiet" = yes ] || echo "Alpine Init $VERSION" # enable debugging if requested [ -n "$KOPT_debug_init" ] && set -x # set default values : ${KOPT_init:=/sbin/init} # pick first keymap if found for map in "$ROOT"/etc/keymap/*; do if [ -f "$map" ]; then ebegin "Setting keymap ${map##*/}" zcat "$map" | loadkmap eend break fi done # start bootcharting if wanted if [ "$KOPT_chart" = yes ]; then ebegin "Starting bootchart logging" $MOCK /sbin/bootchartd start-initfs eend 0 fi # The following values are supported: # alpine_repo=auto -- default, search for .boot_repository # alpine_repo=http://... -- network repository ALPINE_REPO=${KOPT_alpine_repo} [ "$ALPINE_REPO" = "auto" ] && ALPINE_REPO= # hide kernel messages [ "$KOPT_quiet" = yes ] && dmesg -n 1 # optional blacklist if [ -n "$KOPT_blacklist" ]; then mkdir -p "$ROOT"/etc/modprobe.d for i in $(echo "$KOPT_blacklist" | tr ',' ' '); do echo "blacklist $i" >> "$ROOT"/etc/modprobe.d/boot-opt-blacklist.conf done fi # determine if we are going to need networking if [ -n "$KOPT_ip" ] || [ -n "$KOPT_nbd" ] || \ is_url "$KOPT_apkovl" || is_url "$ALPINE_REPO"; then do_networking=true else do_networking=false fi if [ -n "$KOPT_zfcp" ]; then $MOCK modprobe zfcp for _zfcp in $(echo "$KOPT_zfcp" | tr ',' ' ' | tr [A-Z] [a-z]); do echo 1 > /sys/bus/ccw/devices/"${_zfcp%%:*}"/online done fi if [ -n "$KOPT_dasd" ]; then for mod in dasd_mod dasd_eckd_mod dasd_fba_mod; do $MOCK modprobe $mod done for _dasd in $(echo "$KOPT_dasd" | tr ',' ' ' | tr [A-Z] [a-z]); do echo 1 > /sys/bus/ccw/devices/"${_dasd%%:*}"/online done fi if [ "${KOPT_s390x_net%%,*}" = "qeth_l2" ]; then for mod in qeth qeth_l2 qeth_l3; do $MOCK modprobe $mod done _channel="$(echo ${KOPT_s390x_net#*,} | tr [A-Z] [a-z])" echo "$_channel" > /sys/bus/ccwgroup/drivers/qeth/group echo 1 > /sys/bus/ccwgroup/drivers/qeth/"${_channel%%,*}"/layer2 echo 1 > /sys/bus/ccwgroup/drivers/qeth/"${_channel%%,*}"/online fi # make sure we load zfs module if root=ZFS=... rootfstype=${KOPT_rootfstype} if [ -z "$rootfstype" ]; then case "$KOPT_root" in ZFS=*) rootfstype=zfs ;; esac fi # load available drivers to get access to modloop media ebegin "Loading boot drivers" $MOCK modprobe -a $(echo "$KOPT_modules $rootfstype" | tr ',' ' ' ) loop squashfs simpledrm 2> /dev/null if [ -f "$ROOT"/etc/modules ] ; then sed 's/\#.*//g' < /etc/modules | while read module args; do $MOCK modprobe -q $module $args done fi eend 0 # workaround for vmware if grep -q VMware "$ROOT"/sys/devices/virtual/dmi/id/sys_vendor 2>/dev/null; then $MOCK modprobe -a ata_piix mptspi sr-mod fi if [ -n "$KOPT_dropbear" ]; then if [ -n "$KOPT_cryptroot" ]; then configure_ip6 setup_dropbear fi fi # Add Workaround for dropbear if [ -n "$KOPT_cryptroot" ] && [ ! -b /dev/mapper/"${KOPT_cryptdm}" ]; then cryptopts="-c ${KOPT_cryptroot}" if [ "$KOPT_cryptdiscards" = "yes" ]; then cryptopts="$cryptopts -D" fi if [ -n "$KOPT_cryptdm" ]; then cryptopts="$cryptopts -m ${KOPT_cryptdm}" fi if [ -n "$KOPT_cryptheader" ]; then cryptopts="$cryptopts -H ${KOPT_cryptheader}" fi if [ -n "$KOPT_cryptoffset" ]; then cryptopts="$cryptopts -o ${KOPT_cryptoffset}" fi if [ "$KOPT_cryptkey" = "yes" ]; then cryptopts="$cryptopts -k /crypto_keyfile.bin" elif [ -n "$KOPT_cryptkey" ]; then cryptopts="$cryptopts -k ${KOPT_cryptkey}" fi fi if [ -n "$KOPT_wireguard" ]; then configure_ip setup_wireguard || echo "Failed to setup wireguard tunnel." fi if [ -n "$KOPT_nbd" ]; then # TODO: Might fail because nlplug-findfs hasn't plugged eth0 yet configure_ip setup_nbd || echo "Failed to setup nbd device." fi if [ -n "$KOPT_aoe" ]; then if [ -n "$KOPT_aoe_iflist" ]; then for iface in $(echo "$KOPT_aoe_iflist" | tr ',' ' '); do $MOCK ip link set dev "$iface" up if [ -n "$KOPT_aoe_mtu" ]; then $MOCK ip link set dev "$iface" mtu "$KOPT_aoe_mtu" fi done $MOCK modprobe aoe aoe_iflist="$KOPT_aoe_iflist" else $MOCK modprobe aoe fi if [ "$KOPT_aoe" != "yes" ]; then for target in $(echo "$KOPT_aoe" | tr ',' ' '); do while [ ! -e /dev/etherd/e$target ]; do echo discover "$target" >>/dev/etherd/discover sleep 1 done done fi fi # zpool reports /dev/zfs missing if it can't read /etc/mtab ln -s /proc/mounts "$ROOT"/etc/mtab # check if root=... was set if [ -n "$KOPT_root" ]; then # run nlplug-findfs before SINGLEMODE so we load keyboard drivers ebegin "Mounting root" $MOCK nlplug-findfs $cryptopts -p /sbin/mdev ${KOPT_debug_init:+-d} \ ${KOPT_uevent_buf_size:+-U $KOPT_uevent_buf_size} \ $KOPT_root # Kill all struck nlplug-findfs jobs and dropbear killall -9 nlplug-findfs killall -9 dropbear if [ "$SINGLEMODE" = "yes" ]; then echo "Entering single mode. Type 'exit' to continue booting." sh fi if echo "$KOPT_modules $rootfstype" | grep -qw btrfs; then /sbin/btrfs device scan >/dev/null || \ echo "Failed to scan devices for btrfs filesystem." fi resume_from_disk if [ "$KOPT_overlaytmpfs" = "yes" ]; then # Create mountpoints mkdir -p /media/root-ro /media/root-rw $sysroot/media/root-ro \ $sysroot/media/root-rw # Mount read-only underlying rootfs rootflags="${KOPT_rootflags:+$KOPT_rootflags,}ro" $MOCK mount ${KOPT_rootfstype:+-t $KOPT_rootfstype} -o $rootflags \ $KOPT_root /media/root-ro # Mount writable overlay tmpfs overlaytmpfsflags="mode=0755,${KOPT_overlaytmpfsflags:+$KOPT_overlaytmpfsflags,}rw" $MOCK mount -t tmpfs -o $overlaytmpfsflags root-tmpfs /media/root-rw # Create additional mountpoints and do the overlay mount mkdir -p /media/root-rw/work /media/root-rw/root $MOCK mount -t overlay -o \ lowerdir=/media/root-ro,upperdir=/media/root-rw/root,workdir=/media/root-rw/work \ overlayfs $sysroot else if [ "$rootfstype" = "zfs" ]; then prepare_zfs_root fi $MOCK mount ${rootfstype:+-t} ${rootfstype} \ -o ${KOPT_rootflags:-ro} \ ${KOPT_root#ZFS=} $sysroot fi eend $? if [ -r "$sysroot/etc/fstab" ] && [ "$KOPT_usrflags" != "disable" ]; then while read dev mnt fs mntopts chk; do if [ "$mnt" = "/usr" ]; then ebegin "Mounting /usr" $MOCK modprobe -a $fs 2> /dev/null $MOCK nlplug-findfs \ -p /sbin/mdev \ ${KOPT_debug_init:+-d} \ ${KOPT_uevent_buf_size:+-U $KOPT_uevent_buf_size} \ $dev $MOCK mount -t $fs \ -o ${KOPT_usrflags:-ro} \ $dev $sysroot/usr eend $? fi done < $sysroot/etc/fstab fi cat "$ROOT"/proc/mounts 2>/dev/null | while read DEV DIR TYPE OPTS ; do if [ "$DIR" != "/" -a "$DIR" != "$sysroot" -a "$DIR" != "$sysroot/usr" -a -d "$DIR" ]; then mkdir -p $sysroot/$DIR $MOCK mount -o move $DIR $sysroot/$DIR fi done $MOCK sync exec switch_root $switch_root_opts $sysroot $chart_init "$KOPT_init" $KOPT_init_args echo "initramfs emergency recovery shell launched" exec /bin/busybox sh fi resume_from_disk if $do_networking; then repoopts="-n" else repoopts="-b $repofile" fi # locate boot media and mount it ebegin "Mounting boot media" $MOCK nlplug-findfs $cryptopts -p /sbin/mdev ${KOPT_debug_init:+-d} \ ${KOPT_usbdelay:+-t $(( $KOPT_usbdelay * 1000 ))} \ ${KOPT_uevent_buf_size:+-U $KOPT_uevent_buf_size} \ $repoopts -a "$ROOT"/tmp/apkovls # Kill all struck nlplug-findfs jobs and dropbear killall -9 nlplug-findfs killall -9 dropbear eend $? # Setup network interfaces if $do_networking; then configure_ip fi # early console? if [ "$SINGLEMODE" = "yes" ]; then echo "Entering single mode. Type 'exit' to continue booting." sh fi # mount tmpfs sysroot rootflags="mode=0755" if [ -n "$KOPT_root_size" ]; then echo "WARNING: the boot option root_size is deprecated. Use rootflags instead" rootflags="$rootflags,size=$KOPT_root_size" fi if [ -n "$KOPT_rootflags" ]; then rootflags="$rootflags,$KOPT_rootflags" fi $MOCK mount -t tmpfs -o $rootflags tmpfs $sysroot if [ -z "$KOPT_apkovl" ]; then # Not manually set, use the apkovl found by nlplug if [ -e "$ROOT"/tmp/apkovls ]; then ovl=$(head -n 1 "$ROOT"/tmp/apkovls) fi elif is_url "$KOPT_apkovl"; then # Fetch apkovl via network MACHINE_UUID=$(cat "$ROOT"/sys/class/dmi/id/product_uuid 2>/dev/null) url="$(echo "$KOPT_apkovl" | sed -e "s/{MAC}/$MAC_ADDRESS/" -e "s/{UUID}/$MACHINE_UUID/")" ovl="/tmp/${url##*/}" ovl="${ovl%%\?*}" $MOCK wget -O "$ovl" "$url" || ovl= else ovl="$KOPT_apkovl" fi # parse pkgs=pkg1,pkg2 if [ -n "$KOPT_pkgs" ]; then pkgs=$(echo "$KOPT_pkgs" | tr ',' ' ' ) fi # load apkovl or set up a minimal system if [ -f "$ovl" ]; then ebegin "Loading user settings from $ovl" # create apk db and needed /dev/null and /tmp first apk add --root $sysroot --initdb --quiet unpack_apkovl "$ovl" $sysroot eend $? $errstr || ovlfiles= # hack, incase /root/.ssh was included in apkovl [ -d "$sysroot/root" ] && chmod 700 "$sysroot/root" pkgs="$pkgs $(cat $sysroot/etc/apk/world 2>/dev/null)" fi if [ -f "$sysroot/etc/.default_boot_services" -o ! -f "$ovl" ]; then # add some boot services by default rc_add devfs sysinit rc_add dmesg sysinit rc_add mdev sysinit rc_add hwdrivers sysinit rc_add modloop sysinit rc_add modules boot rc_add sysctl boot rc_add hostname boot rc_add bootmisc boot rc_add syslog boot rc_add mount-ro shutdown rc_add killprocs shutdown rc_add savecache shutdown rc_add firstboot default # add openssh if [ -n "$KOPT_ssh_key" ]; then pkgs="$pkgs openssh" rc_add sshd default fi if want_tiny_cloud; then pkgs="$pkgs tiny-cloud ifupdown-ng doas" rc_add tiny-cloud-boot boot rc_add tiny-cloud-early default rc_add tiny-cloud-main default rc_add tiny-cloud-final default fi rm -f "$sysroot/etc/.default_boot_services" fi if [ "$KOPT_splash" != "no" ]; then echo "IMG_ALIGN=CM" > /tmp/fbsplash.cfg for fbdev in /dev/fb[0-9]; do [ -e "$fbdev" ] || break num="${fbdev#/dev/fb}" for img in /media/*/fbsplash$num.ppm; do [ -e "$img" ] || break config="${img%.*}.cfg" [ -e "$config" ] || config=/tmp/fbsplash.cfg fbsplash -s "$img" -d "$fbdev" -i "$config" break done done for fbsplash in /media/*/fbsplash.ppm; do [ -e "$fbsplash" ] && break done fi if [ -n "$fbsplash" ] && [ -e "$fbsplash" ]; then ebegin "Starting bootsplash" mkfifo $sysroot/$splashfile config="${fbsplash%.*}.cfg" [ -e "$config" ] || config=/tmp/fbsplash.cfg setsid fbsplash -T 16 -s "$fbsplash" -i $config -f $sysroot/$splashfile & eend 0 else KOPT_splash="no" fi if [ -f $sysroot/etc/fstab ]; then has_fstab=1 fstab=$sysroot/etc/fstab # let user override tmpfs size in fstab in apkovl mountopts=$(awk '$2 == "/" && $3 == "tmpfs" { print $4 }' $sysroot/etc/fstab) if [ -n "$mountopts" ]; then $MOCK mount -o remount,$mountopts $sysroot fi # relocate mounts and adjust mount options # this is so a generated /etc/apk/repositories will use correct # mount dir remount_fstab_entry "$sysroot"/etc/fstab elif [ -f "$ROOT"/etc/fstab ]; then remount_fstab_entry "$ROOT"/etc/fstab fi # hack so we get openrc pkgs="$pkgs alpine-base" # copy keys so apk finds them. apk looks for stuff relative --root mkdir -p $sysroot/etc/apk/keys/ $MOCK cp -a /etc/apk/keys $sysroot/etc/apk # generate apk repositories file. needs to be done after relocation find_boot_repositories > $repofile # silently fix apk arch in case the apkovl does not match if [ -r "$sysroot"/etc/apk/arch ]; then apk_arch="$(apk --print-arch)" if [ -n "$apk_arch" ]; then echo "$apk_arch" > "$sysroot"/etc/apk/arch fi fi # generate repo opts for apk for i in $(cat $repofile); do repo_opt="$repo_opt --repository $i" done # install new root ebegin "Installing packages to root filesystem" if [ "$KOPT_chart" = yes ]; then pkgs="$pkgs acct" fi # use swclock if no RTC is found if rtc_exists || [ "$(uname -m)" = "s390x" ]; then rc_add hwclock boot else rc_add swclock boot fi # enable support for modloop verification for _pubkey in "$ROOT"/var/cache/misc/*modloop*.SIGN.RSA.*.pub; do # check only if the glob matched something [ -f "$_pubkey" ] || continue # then do it in one iteration anyway mkdir -p "$sysroot"/var/cache/misc cp "$ROOT"/var/cache/misc/*modloop*.SIGN.RSA.*.pub "$sysroot"/var/cache/misc pkgs="$pkgs openssl" break done apkflags="--initramfs-diskless-boot --progress" if [ -z "$MAC_ADDRESS" ]; then apkflags="$apkflags --no-network" else apkflags="$apkflags --update-cache" fi if [ "$KOPT_quiet" = yes ]; then apkflags="$apkflags --quiet" fi if [ "$KOPT_keep_apk_new" != yes ]; then apkflags="$apkflags --clean-protected" [ -n "$ovlfiles" ] && apkflags="$apkflags --overlay-from-stdin" fi mkdir -p $sysroot/sys $sysroot/proc $sysroot/dev $MOCK mount -o bind /sys $sysroot/sys $MOCK mount -o bind /proc $sysroot/proc $MOCK mount -o bind /dev $sysroot/dev if [ -n "$ovlfiles" ]; then apk add --root $sysroot $repo_opt $apkflags $pkgs <$ovlfiles else apk add --root $sysroot $repo_opt $apkflags $pkgs fi $MOCK umount $sysroot/sys $sysroot/proc $sysroot/dev eend $? # unmount ovl mount if needed if [ -n "$ovl_unmount" ]; then $MOCK umount $ovl_unmount 2>/dev/null fi # remount according default fstab from package if [ -z "$has_fstab" ] && [ -f "$sysroot"/etc/fstab ]; then remount_fstab_entry "$sysroot"/etc/fstab fi # generate repositories if none exists. this needs to be done after relocation if ! [ -f "$sysroot"/etc/apk/repositories ]; then find_boot_repositories > "$sysroot"/etc/apk/repositories fi # fix inittab if alternative console setup_inittab_console ! [ -f "$sysroot"/etc/resolv.conf ] && [ -f /etc/resolv.conf ] && \ cp /etc/resolv.conf "$sysroot"/etc # setup bootchart for switch_root chart_init="" if [ "$KOPT_chart" = yes ]; then /sbin/bootchartd stop-initfs "$sysroot" chart_init="/sbin/bootchartd start-rootfs" fi if [ ! -x "${sysroot}${KOPT_init}" ]; then [ "$KOPT_splash" != "no" ] && echo exit > $sysroot/$splashfile echo "$KOPT_init not found in new root. Launching emergency recovery shell" echo "Type exit to continue boot." /bin/busybox sh fi # switch over to new root cat "$ROOT"/proc/mounts 2>/dev/null | while read DEV DIR TYPE OPTS ; do if [ "$DIR" != "/" -a "$DIR" != "$sysroot" -a -d "$DIR" ]; then mkdir -p $sysroot/$DIR $MOCK mount -o move $DIR $sysroot/$DIR fi done sync [ "$KOPT_splash" = "init" ] && echo exit > $sysroot/$splashfile echo "" exec switch_root $switch_root_opts $sysroot $chart_init "$KOPT_init" $KOPT_init_args [ "$KOPT_splash" != "no" ] && echo exit > $sysroot/$splashfile echo "initramfs emergency recovery shell launched" exec /bin/busybox sh reboot