1410 lines
38 KiB
Bash
Executable file
1410 lines
38 KiB
Bash
Executable file
#!/bin/sh
|
|
|
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
# Copyright (C) 2010-2011 Roman Weber (roman@openelec.tv)
|
|
# Copyright (C) 2012 Yann Cézard (eesprit@free.fr)
|
|
# Copyright (C) 2009-2014 Stephan Raue (stephan@openelec.tv)
|
|
# Copyright (C) 2016-2018 Team LibreELEC (https://libreelec.tv)
|
|
# Copyright (C) 2018-present Team CoreELEC (https://coreelec.org)
|
|
# Copyright (C) 2020-present Fewtarius
|
|
|
|
# create directories
|
|
/usr/bin/busybox mkdir -p /dev
|
|
/usr/bin/busybox mkdir -p /proc
|
|
/usr/bin/busybox mkdir -p /sys
|
|
/usr/bin/busybox mkdir -p /tmp
|
|
/usr/bin/busybox mkdir -p /flash
|
|
/usr/bin/busybox mkdir -p /sysroot
|
|
/usr/bin/busybox mkdir -p /storage
|
|
|
|
# temp mountpoint for updates
|
|
/usr/bin/busybox mkdir -p /update
|
|
|
|
# mount all needed special filesystems
|
|
/usr/bin/busybox mount -t devtmpfs devtmpfs /dev
|
|
/usr/bin/busybox mount -t proc proc /proc
|
|
/usr/bin/busybox mount -t sysfs sysfs /sys
|
|
|
|
# set needed variables
|
|
MODULE_DIR=/usr/lib/modules
|
|
|
|
UPDATE_ROOT=/storage/.update
|
|
UPDATE_DIR="$UPDATE_ROOT"
|
|
|
|
UPDATE_KERNEL="@KERNEL_NAME@"
|
|
UPDATE_SYSTEM="SYSTEM"
|
|
IMAGE_KERNEL="@KERNEL_NAME@"
|
|
IMAGE_SYSTEM="SYSTEM"
|
|
|
|
BOOT_STEP="start"
|
|
MD5_FAILED="0"
|
|
RUN_FSCK="yes"
|
|
RUN_FSCK_DISKS=""
|
|
SYSLINUX_DEFAULT=""
|
|
GRUB_DEFAULT=""
|
|
|
|
NBD_DEVS="0"
|
|
FLASH_FREE_MIN="5"
|
|
|
|
LIVE="no"
|
|
|
|
BREAK_TRIPPED="no"
|
|
|
|
BIGFONT="1080"
|
|
|
|
TEE_PID=""
|
|
|
|
# common functions
|
|
. /functions 2>/dev/null
|
|
. /device.init 2>/dev/null
|
|
|
|
# Get a serial number if present (eg. RPi) otherwise use MAC address from eth0
|
|
MACHINE_UID="$(awk '/^Serial/{s='0000000' $3; print substr(s, length(s) - 7)}' /proc/cpuinfo 2>/dev/null)"
|
|
[ -z "$MACHINE_UID" ] && MACHINE_UID="$(cat /sys/class/net/eth0/address 2>/dev/null | tr -d :)"
|
|
|
|
clear >/dev/console
|
|
|
|
# script functions
|
|
progress() {
|
|
if test "$PROGRESS" = "yes"; then
|
|
echo "### $1 ###" >&2
|
|
fi
|
|
}
|
|
|
|
debug_msg() {
|
|
echo "$1" >&$SILENT_OUT
|
|
}
|
|
|
|
debug_shell() {
|
|
redirect_output_to_screen # restore output to a screen
|
|
echo "### Starting debugging shell for boot step: $BOOT_STEP... type exit to quit ###"
|
|
showcursor
|
|
setsid cttyhack sh
|
|
}
|
|
|
|
error() {
|
|
# Display fatal error message
|
|
# $1:action which caused error, $2:message
|
|
# Send debug_shell output to stderr, in case caller is redirecting/consuming stdout
|
|
# Return exitcode=1 so that called may detect when an error has occurred
|
|
echo "*** Error in $BOOT_STEP: $1: $2 ***" >&2
|
|
debug_shell >&2
|
|
return 1
|
|
}
|
|
|
|
break_after() {
|
|
# Start debug shell after boot step $1, and all subsequent steps
|
|
if [ $BREAK_TRIPPED == yes ]; then
|
|
debug_shell
|
|
else
|
|
case $BREAK in
|
|
all|*$1*)
|
|
BREAK_TRIPPED=yes
|
|
debug_shell
|
|
;;
|
|
esac
|
|
fi
|
|
}
|
|
|
|
# Mount handlers
|
|
# All handlers take the following parameters:
|
|
# $1:target, $2:mountpoint, $3:mount options, [$4:fs type]
|
|
mount_common() {
|
|
# Common mount handler, handles block devices and filesystem images
|
|
MOUNT_OPTIONS="-o $3"
|
|
[ -n "$4" ] && MOUNT_OPTIONS="-t $4 $MOUNT_OPTIONS"
|
|
|
|
for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; do
|
|
ERR_ENV=1
|
|
|
|
mount $MOUNT_OPTIONS $1 $2 >&$SILENT_OUT 2>&1
|
|
[ "$?" -eq "0" ] && ERR_ENV=0 && break
|
|
|
|
usleep 1000000
|
|
done
|
|
[ "$ERR_ENV" -eq "0" ] && return 0
|
|
echo "Unable to find $1, powering off and on should correct it." >/dev/console
|
|
StartProgress countdown "Power off in 3s... " 3 "NOW"
|
|
poweroff
|
|
}
|
|
|
|
get_iscsistart_options() {
|
|
# Convert kernel commandline ISCSI= options to iscsistart options
|
|
IFS_SAVE="$IFS"
|
|
IFS=,
|
|
|
|
for arg in $1; do
|
|
val="${arg#*=}"
|
|
case "$arg" in
|
|
iscsi_initiator=*)
|
|
option="-i"
|
|
;;
|
|
iscsi_target_name=*)
|
|
option="-t"
|
|
;;
|
|
iscsi_target_ip=*)
|
|
option="-a"
|
|
;;
|
|
iscsi_target_port=*)
|
|
option="-p"
|
|
;;
|
|
iscsi_target_group=*)
|
|
option="-g"
|
|
;;
|
|
iscsi_username=*)
|
|
option="-u"
|
|
;;
|
|
iscsi_password=*)
|
|
option="-w"
|
|
;;
|
|
iscsi_in_username=*)
|
|
option="-U"
|
|
;;
|
|
iscsi_in_password=*)
|
|
option="-W"
|
|
;;
|
|
esac
|
|
echo "$option $val"
|
|
done
|
|
|
|
IFS="$IFS_SAVE"
|
|
}
|
|
|
|
mount_iscsi() {
|
|
# Mount iSCSI target
|
|
ISCSI_DEV="${1##*,}"
|
|
ISCSI_OPTIONS="${1%,*}"
|
|
|
|
if [ ! -f "/usr/sbin/iscsistart" ]; then
|
|
error "iscsistart" "iSCSI support not available"
|
|
fi
|
|
|
|
if [ "$ISCSI_OPTIONS" = "auto" ]; then
|
|
progress "Network configuration based on iBFT"
|
|
/usr/sbin/iscsistart -N >&$SILENT_OUT 2>&1 || error "iscsistart" "Unable to configure network"
|
|
progress "iSCSI auto connect based on iBFT"
|
|
/usr/sbin/iscsistart -b >&$SILENT_OUT 2>&1 || error "iscsistart" "Unable to auto connect"
|
|
else
|
|
/usr/sbin/iscsistart $(get_iscsistart_options "$ISCSI_OPTIONS") >&$SILENT_OUT 2>&1 || error "iscsistart" "Unable to connect to ISCSI target"
|
|
fi
|
|
|
|
mount_common "$ISCSI_DEV" "$2" "$3" "$4"
|
|
}
|
|
|
|
mount_nbd() {
|
|
# Mount NBD device
|
|
NBD_SERVER="${1%%:*}"
|
|
NBD_PORT="${1#*:}"
|
|
NBD_DEV="/dev/nbd$NBD_DEVS"
|
|
|
|
nbd-client $NBD_SERVER $NBD_PORT $NBD_DEV >&$SILENT_OUT 2>&1 || error "nbd-client" "Could not connect to NBD server $1"
|
|
|
|
mount_common "$NBD_DEV" "$2" "$3" "$4"
|
|
|
|
NBD_DEVS=$(( NBD_DEVS + 1 ))
|
|
}
|
|
|
|
mount_nfs() {
|
|
# Mount NFS export
|
|
NFS_EXPORT="${1%%,*}"
|
|
NFS_OPTIONS="${1#*,}"
|
|
|
|
[ "$NFS_OPTIONS" = "$1" ] && NFS_OPTIONS=
|
|
|
|
mount_common "$NFS_EXPORT" "$2" "$3,nolock,rsize=32768,wsize=32768,$NFS_OPTIONS" "nfs"
|
|
}
|
|
|
|
mount_ubifs() {
|
|
mount_common "$1" "$2" "$3" "ubifs"
|
|
}
|
|
|
|
# mount_folder "$boot" "/flash" "ro,noatime"
|
|
# $1:[TYPE=]target, $2:mountpoint, $3:mount options, [$4:fs type]
|
|
mount_folder() {
|
|
local target="${1#*=}"
|
|
|
|
mkdir -p /dev/bind_tmp
|
|
mount_common "$target" "/dev/bind_tmp" "rw,noatime"
|
|
mount_common "/dev/bind_tmp/coreelec_$(basename $2)" "$2" "bind"
|
|
umount /dev/bind_tmp &>/dev/null
|
|
|
|
[ "$2" = "/flash" ] && mount -o remount,ro /flash
|
|
[ -z "$(ls -A /dev/bind_tmp)" ] && rm -rf /dev/bind_tmp
|
|
}
|
|
|
|
mount_part() {
|
|
# Mount a local or network filesystem
|
|
# $1:[TYPE=]target, $2:mountpoint, $3:mount options, [$4:fs type]
|
|
progress "mount filesystem $1 ..."
|
|
|
|
MOUNT_TARGET="${1#*=}"
|
|
case $1 in
|
|
/dev/ubi*)
|
|
MOUNT_CMD="mount_ubifs"
|
|
MOUNT_TARGET="$1"
|
|
RUN_FSCK="no"
|
|
;;
|
|
LABEL=*|UUID=*|/*)
|
|
MOUNT_CMD="mount_common"
|
|
MOUNT_TARGET="$1"
|
|
;;
|
|
ISCSI=*)
|
|
MOUNT_CMD="mount_iscsi"
|
|
;;
|
|
NBD=*)
|
|
MOUNT_CMD="mount_nbd"
|
|
;;
|
|
NFS=*)
|
|
MOUNT_CMD="mount_nfs"
|
|
;;
|
|
FOLDER=*)
|
|
MOUNT_CMD="mount_folder"
|
|
MOUNT_TARGET="$1"
|
|
;;
|
|
*)
|
|
error "mount_part" "Unknown filesystem $1"
|
|
;;
|
|
esac
|
|
|
|
# Substitute unique identifier if available or remove placeholder
|
|
MOUNT_TARGET="${MOUNT_TARGET//@UID@/$MACHINE_UID}"
|
|
|
|
$MOUNT_CMD "$MOUNT_TARGET" "$2" "$3" "$4"
|
|
}
|
|
|
|
mount_sysroot() {
|
|
if [ "$SYSTEM_TORAM" = "yes" ]; then
|
|
cp /flash/$IMAGE_SYSTEM /dev/$IMAGE_SYSTEM
|
|
mount_part "/dev/$IMAGE_SYSTEM" "/sysroot" "ro,loop"
|
|
else
|
|
mount_part "/flash/$IMAGE_SYSTEM" "/sysroot" "ro,loop"
|
|
fi
|
|
|
|
if [ -f /flash/post-sysroot.sh ]; then
|
|
. /flash/post-sysroot.sh
|
|
fi
|
|
|
|
}
|
|
|
|
# mount the specified SYSTEM file and output arch from /etc/os-release
|
|
get_project_arch() {
|
|
if [ -f ${1}/etc/os-release ]; then
|
|
. ${1}/etc/os-release
|
|
echo "${COREELEC_ARCH:-${LIBREELEC_ARCH}}"
|
|
fi
|
|
}
|
|
|
|
# mount the specified SYSTEM file and output version from /etc/os-release
|
|
get_project_version() {
|
|
if [ -f ${1}/etc/os-release ]; then
|
|
. ${1}/etc/os-release
|
|
echo "${VERSION}"
|
|
fi
|
|
}
|
|
|
|
# If the project/arch of current matches the update, then it is considered compatible.
|
|
# Otherwise, mount the update SYSTEM partition and, if canupdate.sh is available,
|
|
# call the script to determine if the current update file can be applied on to the
|
|
# current system - 0 means it is compatible, non-zero that it is not compatible.
|
|
is_compatible() {
|
|
local result=1
|
|
|
|
if [ "${1}" = "${2}" ]; then
|
|
result=0
|
|
else
|
|
if [ -f /update/usr/share/bootloader/canupdate.sh ]; then
|
|
sh /update/usr/share/bootloader/canupdate.sh "${1}" "${2}" && result=0
|
|
fi
|
|
fi
|
|
|
|
return ${result}
|
|
}
|
|
|
|
# determine if the new SYSTEM file is compatible with the current SYSTEM file
|
|
check_is_compatible() {
|
|
local update_filename="${1}"
|
|
local old_project_arch new_project_arch
|
|
|
|
old_project_arch="$(get_project_arch "/sysroot")" || return
|
|
new_project_arch="$(get_project_arch "/update")" || return
|
|
|
|
# If old or new project/arch isn't available then could be very old (pre-/etc/os-release) build - have to trust it
|
|
if [ -n "${old_project_arch}" -a -n "${new_project_arch}" ]; then
|
|
# If the old project/arch is not compatible with the new project/arch then abort...
|
|
if ! is_compatible "${old_project_arch}" "${new_project_arch}"; then
|
|
echo ""
|
|
echo "ERROR: $(basename "${update_filename}") is not compatible with ${old_project_arch} hardware - update cancelled."
|
|
echo ""
|
|
echo "Current system: ${old_project_arch}"
|
|
echo "Update system: ${new_project_arch}"
|
|
echo ""
|
|
echo "Create $UPDATE_ROOT/.nocompat to disable compatibility checks and risk a non-booting system."
|
|
echo ""
|
|
return 1
|
|
fi
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
display_versions() {
|
|
local old_project_version new_project_version
|
|
|
|
old_project_version="$(get_project_version "/sysroot")" || return
|
|
new_project_version="$(get_project_version "/update")" || return
|
|
|
|
if [ -n "${old_project_version}" -a -n "${new_project_version}" ]; then
|
|
echo ""
|
|
echo "Updating from ${old_project_version} to ${new_project_version}"
|
|
echo ""
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
update_file() {
|
|
if [ -f "$UPDATE_DIR/$2" -a -f "$3" ]; then
|
|
mount -o remount,rw /flash
|
|
|
|
StartProgress percent "Updating $1... " "$3" $(stat -t "$UPDATE_DIR/$2" | awk '{print $2}')
|
|
# use dd here with conv=fsync so that all writes are non-buffered
|
|
# ensuring accurate progress - take the sync hit during the
|
|
# transfer, rather than when flushing file buffers after the progress
|
|
# meter declares the transfer already complete
|
|
dd if=$UPDATE_DIR/$2 of=$3 bs=1M conv=fsync 2>/dev/null
|
|
|
|
StopProgress
|
|
|
|
# loopback file needs writable /flash all the time
|
|
if [ "${disk%%=*}" != "FILE" ]; then
|
|
mount -o remount,ro /flash
|
|
fi
|
|
sync
|
|
fi
|
|
}
|
|
|
|
update_partition() {
|
|
local result
|
|
|
|
if [ -f "$UPDATE_DIR/$2" -a -b "$3" ]; then
|
|
StartProgress spinner "Updating $1... "
|
|
result="$(dd if="$UPDATE_DIR/$2" of="$3" 2>&1)"
|
|
StopProgress "done"
|
|
sync
|
|
echo "${result}"
|
|
fi
|
|
}
|
|
|
|
update_bootloader() {
|
|
local result
|
|
|
|
export BOOT_ROOT="/flash"
|
|
export SYSTEM_ROOT="/update"
|
|
|
|
if [ -f $SYSTEM_ROOT/usr/share/bootloader/update.sh ]; then
|
|
echo ""
|
|
echo "Updating Boot Files... "
|
|
sh $SYSTEM_ROOT/usr/share/bootloader/update.sh
|
|
sync
|
|
echo "Boot Files Updated."
|
|
echo ""
|
|
fi
|
|
}
|
|
|
|
load_modules() {
|
|
progress "Loading kernel modules"
|
|
|
|
[ ! -f "/etc/modules" ] && return
|
|
for module in $(cat /etc/modules); do
|
|
progress "Loading kernel module $module"
|
|
insmod "$MODULE_DIR/$module.ko" || progress "... Failed to load kernel module $module, skipping"
|
|
done
|
|
}
|
|
|
|
set_consolefont() {
|
|
local hres
|
|
|
|
progress "Set console font"
|
|
if [ -e /dev/fb0 ]; then
|
|
hres="$(fbset 2>/dev/null | awk '/geometry/ { print $2 }')"
|
|
if [ "${hres}" -lt "1152" ]
|
|
then
|
|
setfont -C /dev/tty0 ter-v14n.psf
|
|
else
|
|
setfont -C /dev/tty0 ter-v32n.psf
|
|
fi
|
|
fi
|
|
}
|
|
|
|
load_splash() {
|
|
local set_default_res=no
|
|
local vres
|
|
|
|
if [ ! "$SPLASH" = "no" ]; then
|
|
progress "Loading bootsplash"
|
|
|
|
# load uvesafb module if needed
|
|
if [ -f "$MODULE_DIR/uvesafb.ko" -a ! -e /dev/fb0 ]; then
|
|
progress "Loading kernel module uvesafb.ko"
|
|
insmod "$MODULE_DIR/uvesafb.ko" && set_default_res=yes || progress "... Failed to load kernel module uvesafb, skipping"
|
|
fi
|
|
|
|
if [ -e /dev/fb0 ]; then
|
|
# Set framebuffer to a custom resolution and/or fallback to default resolution (1024x768-32), if required.
|
|
if [ ! "$SWITCH_FRAMEBUFFER" = "no" ]; then
|
|
if [ "$SWITCH_FRAMEBUFFER" = "1080" ]; then
|
|
SWITCH_FRAMEBUFFER="1920 1080 1920 1080 32"
|
|
elif [ "$SWITCH_FRAMEBUFFER" = "720" ]; then
|
|
SWITCH_FRAMEBUFFER="1280 720 1280 720 32"
|
|
fi
|
|
|
|
# Try setting a custom framebuffer resolution
|
|
if [ ! "${SWITCH_FRAMEBUFFER:-yes}" = "yes" ]; then
|
|
fbset -g $SWITCH_FRAMEBUFFER 2>/dev/null && set_default_res=no
|
|
fi
|
|
|
|
# Set a default resolution if required
|
|
if [ "$set_default_res" = "yes" ]; then
|
|
fbset -g 1024 768 1024 768 32 2>/dev/null
|
|
fi
|
|
fi
|
|
|
|
# load splash
|
|
if [ -f /splash/splash.conf ]; then
|
|
. /splash/splash.conf
|
|
fi
|
|
|
|
# Select splash image based on current native resolution
|
|
if [ -z "$SPLASHIMAGE" ]; then
|
|
vres="$(fbset 2>/dev/null | awk '/geometry/ { print $3 }')"
|
|
hres="$(fbset 2>/dev/null | awk '/geometry/ { print $2 }')"
|
|
RES="${hres}"
|
|
|
|
|
|
# Test to determine if the display is rotated
|
|
# and set the splash to suit.
|
|
if [ ${vres} -gt ${hres} ]
|
|
then
|
|
RES="${RES}l"
|
|
if [ ! -f "/splash/splash-${RES}.png" ]
|
|
then
|
|
RES="1080l"
|
|
fi
|
|
else
|
|
if [ ! -f "/splash/splash-${RES}.png" ]
|
|
then
|
|
RES="1080"
|
|
fi
|
|
fi
|
|
|
|
SPLASHIMAGE="/splash/splash-${RES}.png"
|
|
|
|
fi
|
|
|
|
if [ -n "$SPLASHIMAGE" -a -f "$SPLASHIMAGE" ]; then
|
|
ply-image ${SPLASHIMAGE} > /dev/null 2>&1
|
|
fi
|
|
|
|
debug_msg "Framebuffer vertical res: $vres"
|
|
debug_msg "Framebuffer splash image: $SPLASHIMAGE"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
do_reboot() {
|
|
echo "System reboots now..."
|
|
|
|
# stop output redirection
|
|
[ -n "$TEE_PID" ] && kill $TEE_PID &>/dev/null
|
|
if [ -s /dev/init.log ]; then
|
|
mv /dev/init.log /storage/init-previous.log
|
|
fi
|
|
redirect_output_to_screen
|
|
delete_descriptors
|
|
|
|
# syncing filesystem
|
|
sync
|
|
|
|
# unmount filesystems
|
|
if /usr/bin/busybox mountpoint -q /flash ; then
|
|
/usr/bin/busybox umount /flash &>/dev/null
|
|
fi
|
|
|
|
if /usr/bin/busybox mountpoint -q /storage ; then
|
|
/usr/bin/busybox umount /storage &>/dev/null
|
|
fi
|
|
|
|
usleep 2000000
|
|
/usr/bin/busybox reboot
|
|
}
|
|
|
|
force_fsck() {
|
|
echo "Filesystem corruption has been detected!"
|
|
echo "To prevent an automatic repair attempt continuing,"
|
|
echo "press any key or power off your system within the next 120 seconds"
|
|
echo ""
|
|
read -t120 -n1
|
|
# The exit status is 0 if input is available
|
|
# The exit status is greater than 128 if the timeout is exceeded
|
|
if [ $? -ne 0 -o $? -gt 128 ]; then
|
|
echo "Repairing filesystem..."
|
|
echo ""
|
|
/usr/sbin/fsck -T -M -y $RUN_FSCK_DISKS
|
|
FSCK_RET=$?
|
|
if [ $(( $FSCK_RET & 8 )) -eq 8 ]; then
|
|
# fubar
|
|
echo "Forced fsck failed. Your system is broken beyond repair"
|
|
echo "Please re-install @DISTRONAME@"
|
|
echo ""
|
|
echo "Press enter to shutdown now"
|
|
echo ""
|
|
read fubar
|
|
poweroff
|
|
fi
|
|
do_reboot
|
|
else
|
|
echo "Shutting down..."
|
|
sleep 5
|
|
sync
|
|
poweroff
|
|
fi
|
|
}
|
|
|
|
check_disks() {
|
|
if [ "$RUN_FSCK" = "yes" -a -n "$RUN_FSCK_DISKS" ]; then
|
|
progress "Checking disk(s): $RUN_FSCK_DISKS"
|
|
echo "Checking disk(s): $RUN_FSCK_DISKS" >/dev/kmsg
|
|
for i in 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0; do
|
|
/usr/sbin/fsck -T -M -p -a $RUN_FSCK_DISKS >/dev/fsck.latest 2>&1
|
|
FSCK_RET=$?
|
|
cat /dev/fsck.latest >>/dev/fsck.log
|
|
|
|
# FSCK_RET is the bit-wise OR of the exit codes for each filesystem that is checked.
|
|
if [ $FSCK_RET -ge 16 ]; then
|
|
progress "General error, continuing..."
|
|
break
|
|
elif [ $(( $FSCK_RET & 8 )) -eq 8 ]; then
|
|
# device not found
|
|
if [ $i -eq 0 ]; then
|
|
progress "Device not found, continuing..."
|
|
else
|
|
usleep 500000
|
|
fi
|
|
elif [ $(( $FSCK_RET & 4 )) -eq 4 ]; then
|
|
# errors left
|
|
force_fsck
|
|
elif [ $(( $FSCK_RET & 2 )) -eq 2 ]; then
|
|
# reboot needed
|
|
echo "Filesystem repaired, reboot needed..."
|
|
do_reboot
|
|
elif [ $(( $FSCK_RET & 1 )) -eq 1 ]; then
|
|
# filesystem errors corrected
|
|
progress "Filesystem errors corrected , continuing..."
|
|
break
|
|
elif [ $FSCK_RET -eq 0 ]; then
|
|
# no errors found
|
|
progress "No filesystem errors found, continuing..."
|
|
break
|
|
fi
|
|
done
|
|
while read line; do
|
|
[ -n "$line" ] && echo "fsck: ${line::160}" >/dev/kmsg
|
|
done </dev/fsck.latest
|
|
rm -f /dev/fsck.latest
|
|
fi
|
|
}
|
|
|
|
wakeonlan() {
|
|
if [ "$STORAGE_NETBOOT" = "yes" ]; then
|
|
wol_ip=${disk%:*}
|
|
wol_ip=${wol_ip#*=}
|
|
elif [ "$FLASH_NETBOOT" = "yes" ]; then
|
|
wol_ip=${boot%:*}
|
|
wol_ip=${wol_ip#*=}
|
|
else
|
|
return 0
|
|
fi
|
|
|
|
if [ -n "$wol_ip" -a -n "$wol_mac" -a -n "$wol_wait" ]; then
|
|
progress "Sending Magic Packet (WOL) if needed"
|
|
|
|
if ! ping -q -c 2 "$wol_ip" &>/dev/null; then
|
|
ether-wake "$wol_mac"
|
|
StartProgress countdown "WOL magic packet sent to $wol_ip, waiting $wol_wait seconds... " $wol_wait "done"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
mount_flash() {
|
|
progress "Mounting flash"
|
|
|
|
wakeonlan
|
|
|
|
mount_part "$boot" "/flash" "ro,noatime"
|
|
|
|
if [ -f /flash/post-flash.sh ]; then
|
|
. /flash/post-flash.sh
|
|
fi
|
|
}
|
|
|
|
cleanup_flash() {
|
|
progress "Cleaning up flash (if required)"
|
|
|
|
if [ -f /flash/pieeprom.bin -o -f /flash/pieeprom.upd -o -f /flash/vl805.bin ]; then
|
|
mount -o remount,rw /flash
|
|
|
|
rm -f /flash/pieeprom.bin /flash/pieeprom.upd /flash/pieeprom.sig
|
|
rm -f /flash/vl805.bin /flash/vl805.sig
|
|
rm -f /flash/recovery.bin /flash/recovery.[0-9][0-9][0-9] /flash/RECOVERY.[0-9][0-9][0-9]
|
|
|
|
mount -o remount,ro /flash
|
|
fi
|
|
}
|
|
|
|
mount_storage() {
|
|
progress "Mounting storage"
|
|
|
|
if [ "$LIVE" = "yes" ]; then
|
|
# mount tmpfs and exit early. disk=xx is not allowed in live mode
|
|
mount -t tmpfs none /storage
|
|
return
|
|
fi
|
|
|
|
wakeonlan
|
|
|
|
if [ -n "$disk" ]; then
|
|
if [ -n "$OVERLAY" ]; then
|
|
OVERLAY_DIR=$(cat /sys/class/net/eth0/address | tr -d :)
|
|
|
|
mount_part "$disk" "/storage" "rw,noatime"
|
|
mkdir -p /storage/$OVERLAY_DIR
|
|
umount /storage &>/dev/null
|
|
|
|
# split $disk into $target,$options so we can append $OVERLAY_DIR
|
|
options="${disk#*,}"
|
|
target="${disk%%,*}"
|
|
if [ "$options" = "$disk" ]; then
|
|
disk="$target/$OVERLAY_DIR"
|
|
else
|
|
disk="$target/$OVERLAY_DIR,$options"
|
|
fi
|
|
fi
|
|
|
|
if [ -f /flash/mount-storage.sh ]; then
|
|
. /flash/mount-storage.sh
|
|
else
|
|
mount_part "$disk" "/storage" "rw,noatime"
|
|
fi
|
|
else
|
|
# /storage should always be writable
|
|
mount -t tmpfs none /storage
|
|
fi
|
|
}
|
|
|
|
mount_games() {
|
|
if /usr/bin/busybox mountpoint -q /storage ; then
|
|
progress "Mounting games"
|
|
if [ ! -d "/storage/roms" ]
|
|
then
|
|
/usr/bin/busybox mkdir -p /storage/roms >/dev/null 2>&1
|
|
fi
|
|
|
|
for DEV in $(blkid | awk 'BEGIN {FS=":"}; /ext4/ || /fat/ {print $1}' | sort -r)
|
|
do
|
|
ROOTDEV=$(echo ${DEV} | sed -e "s#^/.*/##g" -e "s#p[0-9].*\$##g")
|
|
if [ -L "/sys/class/block/${ROOTDEV}boot0" ]
|
|
then
|
|
# Assume this is an android boot device and ignore it.
|
|
continue
|
|
fi
|
|
NULL=$(grep ${DEV} /proc/mounts >/dev/null 2>&1)
|
|
if [ ! "$?" = "0" ] && [ -e "${DEV}" ] && [ ! -e "/storage/.please_resize_me" ]
|
|
then
|
|
mount ${DEV} /storage/roms >/dev/null 2>&1
|
|
break
|
|
fi
|
|
done
|
|
|
|
if [ -d "/storage/.update" ] && [ ! -e "/storage/.please_resize_me" ]
|
|
then
|
|
/usr/bin/busybox rm -rf /storage/.update >/dev/null 2>&1
|
|
/usr/bin/busybox mkdir -p /storage/.update >/dev/null 2>&1
|
|
fi
|
|
|
|
if [ ! -d "/storage/roms/update" ]
|
|
then
|
|
/usr/bin/busybox mkdir -p /storage/roms/update >/dev/null 2>&1
|
|
fi
|
|
|
|
if [ ! -e "/storage/.please_resize_me" ]
|
|
then
|
|
/usr/bin/busybox mkdir -p "$UPDATE_ROOT" >/dev/null 2>&1
|
|
mount --bind /storage/roms/update "$UPDATE_ROOT" >/dev/null 2>&1
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# Make last bootloader label (installer, live, run etc.) as the new default
|
|
update_bootmenu() {
|
|
local crnt_default
|
|
|
|
if [ -n "$SYSLINUX_DEFAULT" -a -f /flash/syslinux.cfg ]; then
|
|
if grep -q "^LABEL $SYSLINUX_DEFAULT\$" /flash/syslinux.cfg 2>/dev/null; then
|
|
crnt_default="$(awk '/^DEFAULT/ {print $2}' /flash/syslinux.cfg)"
|
|
if [ ! "$crnt_default" = "$SYSLINUX_DEFAULT" ]; then
|
|
progress "Updating /flash/syslinux.cfg [$crnt_default -> $SYSLINUX_DEFAULT]"
|
|
|
|
mount -o remount,rw /flash
|
|
sed -e "s/^SAY Wait for .* mode/SAY Wait for ${SYSLINUX_DEFAULT} mode/" -i /flash/syslinux.cfg
|
|
sed -e "s/^DEFAULT .*/DEFAULT $SYSLINUX_DEFAULT/" -i /flash/syslinux.cfg
|
|
rm -f /flash/EFI/BOOT/syslinux.cfg
|
|
mount -o remount,ro /flash
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
if [ -n "$GRUB_DEFAULT" -a -f /flash/EFI/BOOT/grub.cfg ]; then
|
|
if grep -q "^menuentry \"$GRUB_DEFAULT\"" /flash/EFI/BOOT/grub.cfg 2>/dev/null; then
|
|
crnt_default="$(awk '/^set default/ {print substr($2,9,19)}' /flash/EFI/BOOT/grub.cfg)"
|
|
if [ ! "$crnt_default" = "\"$GRUB_DEFAULT\"" ]; then
|
|
progress "Updating /flash/EFI/BOOT/grub.cfg [$crnt_default -> \"$GRUB_DEFAULT\"]"
|
|
|
|
mount -o remount,rw /flash
|
|
sed -e "s/^set default=.*/set default=\"$GRUB_DEFAULT\"/" -i /flash/EFI/BOOT/grub.cfg
|
|
rm -f /flash/grub.cfg
|
|
mount -o remount,ro /flash
|
|
fi
|
|
fi
|
|
fi
|
|
}
|
|
|
|
check_out_of_space() {
|
|
if [ "$(df /storage | awk '/[0-9]%/{print $4}')" -eq "0" ]; then
|
|
echo ""
|
|
echo "The $1 is corrupt, or there is not enough"
|
|
echo "free space on /storage to complete the update!"
|
|
echo ""
|
|
echo "Please free up space on your /storage partition"
|
|
echo "by deleting unecessary files, then try again."
|
|
echo ""
|
|
return 0
|
|
else
|
|
echo ""
|
|
echo "The $1 is corrupt/invalid!"
|
|
echo ""
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
do_cleanup() {
|
|
StartProgress spinner "Cleaning up... "
|
|
|
|
if mountpoint -q /storage/roms; then
|
|
umount /storage/roms &>/dev/null
|
|
fi
|
|
|
|
if mountpoint -q /storage; then
|
|
umount /storage &>/dev/null
|
|
fi
|
|
|
|
if mountpoint -q /update; then
|
|
umount /update &>/dev/null
|
|
fi
|
|
|
|
if [ -d $UPDATE_ROOT/.tmp/mnt ]; then
|
|
if mountpoint -q $UPDATE_ROOT/.tmp/mnt ; then
|
|
# busybox umount deletes loop device automatically
|
|
umount $UPDATE_ROOT/.tmp/mnt &>/dev/null
|
|
fi
|
|
|
|
[ -n $LOOP ] && losetup -d $LOOP &>/dev/null
|
|
fi
|
|
|
|
[ -f "$UPDATE_TAR" ] && rm -f "$UPDATE_TAR" &>/dev/null
|
|
[ -f "$UPDATE_IMG_GZ" ] && rm -f "$UPDATE_IMG_GZ" &>/dev/null
|
|
[ -f "$UPDATE_IMG" ] && rm -f "$UPDATE_IMG" &>/dev/null
|
|
|
|
rm -rf $UPDATE_ROOT/[0-9a-zA-Z]* &>/dev/null
|
|
rm -f $UPDATE_ROOT/* &>/dev/null
|
|
rm -f $UPDATE_ROOT/.nocheck $UPDATE_ROOT/.nocompat &>/dev/null
|
|
rm -rf $UPDATE_ROOT/.tmp &>/dev/null
|
|
|
|
sync
|
|
|
|
StopProgress "done"
|
|
}
|
|
|
|
check_update() {
|
|
progress "Checking for updates"
|
|
UPDATE_TAR=$(ls -1 "$UPDATE_DIR"/*.tar 2>/dev/null | head -n 1)
|
|
UPDATE_IMG_GZ=$(ls -1 "$UPDATE_DIR"/*.img.gz 2>/dev/null | head -n 1)
|
|
UPDATE_IMG=$(ls -1 "$UPDATE_DIR"/*.img 2>/dev/null | head -n 1)
|
|
|
|
if ! [ -f "$UPDATE_DIR/$UPDATE_KERNEL" -a -f "$UPDATE_DIR/$UPDATE_SYSTEM" ] &&
|
|
! [ -f "$UPDATE_TAR" -o -f "$UPDATE_IMG_GZ" -o -f "$UPDATE_IMG" ]; then
|
|
return 0
|
|
fi
|
|
|
|
echo "${UPDATE_TAR} ${UPDATE_IMG} ${UPDATE_IMG_GZ}" 2>&1 | grep @DISTRONAME@ 2>&1 >/dev/null
|
|
if [ "$?" -ne "0" ]
|
|
then
|
|
echo "Unsupported operating system update. Please only use @DISTRONAME@ update packages with this distribution."
|
|
do_cleanup
|
|
StartProgress countdown "Reboot in 5s... " 5 "now"
|
|
reboot
|
|
fi
|
|
|
|
if [ "$UPDATE_DISABLED" = "yes" ]; then
|
|
echo "Updating is not supported on netboot"
|
|
do_cleanup
|
|
StartProgress countdown "Normal startup in 5s... " 5 "NOW"
|
|
return 0
|
|
fi
|
|
|
|
if [ -d $UPDATE_DIR/.tmp ]; then
|
|
# This isn't really a failed update, it's just a failure to clean up after updating.
|
|
#echo "Failed update detected - performing recovery."
|
|
#echo ""
|
|
do_cleanup
|
|
StartProgress countdown "Reboot in 5... " 5 "NOW"
|
|
sync
|
|
reboot
|
|
#return 0
|
|
fi
|
|
|
|
mkdir -p $UPDATE_DIR/.tmp &>/dev/null
|
|
sync
|
|
|
|
clear >/dev/console
|
|
echo "UPDATE IN PROGRESS"
|
|
echo ""
|
|
echo "Please do not reboot or turn off your device!"
|
|
echo ""
|
|
|
|
if [ -f "$UPDATE_TAR" ]; then
|
|
TARRESULT="0"
|
|
|
|
echo "Found new .tar archive"
|
|
UPDATE_FILENAME="$UPDATE_TAR"
|
|
StartProgress spinner "Extracting contents of archive... "
|
|
tar -xf "$UPDATE_TAR" -C $UPDATE_DIR/.tmp 1>/dev/null 2>/tmp/tarresult.txt || TARRESULT="1"
|
|
|
|
if [ "${TARRESULT}" -eq "0" ]; then
|
|
mv $UPDATE_DIR/.tmp/*/target/* $UPDATE_DIR &>/dev/null
|
|
sync
|
|
StopProgress "done"
|
|
else
|
|
StopProgress "FAILED"
|
|
|
|
echo "Failed to extract contents of archive file!"
|
|
echo "tar result: '$(cat /tmp/tarresult.txt)'"
|
|
|
|
check_out_of_space "archive"
|
|
|
|
do_cleanup
|
|
StartProgress countdown "Reboot in 5... " 5 "NOW"
|
|
sync
|
|
reboot
|
|
fi
|
|
elif [ -f "$UPDATE_IMG_GZ" -o -f "$UPDATE_IMG" ]; then
|
|
mkdir -p $UPDATE_DIR/.tmp/mnt &>/dev/null
|
|
IMG_FILE="$UPDATE_DIR/.tmp/update.img"
|
|
GZRESULT="0"
|
|
|
|
if [ -f "$UPDATE_IMG_GZ" ]; then
|
|
echo "Found new compressed image file"
|
|
UPDATE_FILENAME="$UPDATE_IMG_GZ"
|
|
StartProgress spinner "Decompressing image file... "
|
|
gunzip -d -c "$UPDATE_IMG_GZ" 1>$IMG_FILE 2>/tmp/gzresult.txt || GZRESULT="1"
|
|
sync
|
|
[ "${GZRESULT}" -eq "0" ] && StopProgress "OK" || StopProgress "FAILED"
|
|
|
|
if [ "${GZRESULT}" -eq "1" ]; then
|
|
echo "Failed to decompress image file!"
|
|
echo "gunzip result: '$(cat /tmp/gzresult.txt)'"
|
|
|
|
check_out_of_space "compressed image"
|
|
|
|
do_cleanup
|
|
StartProgress countdown "Reboot in 5... " 5 "NOW"
|
|
sync
|
|
reboot
|
|
fi
|
|
else
|
|
echo "Found new image file"
|
|
UPDATE_FILENAME="$UPDATE_IMG"
|
|
mv "$UPDATE_IMG" $IMG_FILE
|
|
fi
|
|
|
|
LOOP=$(losetup -f)
|
|
LOOP_NUM=$(echo $LOOP | sed 's|/dev/loop||')
|
|
mknod $LOOP b 7 $LOOP_NUM &>/dev/null
|
|
losetup $LOOP $IMG_FILE
|
|
|
|
# check for MBR partititon
|
|
OFFSET=$(fdisk -u -l $LOOP 2>/dev/null | awk '/^[ ]*Device/{part=1; next}; part{if ($2 == "*") {print $5} else {print $4} ; exit}')
|
|
if [ -z "$OFFSET" ]; then
|
|
# check for GPT partititon
|
|
OFFSET=$(fdisk -u -l $LOOP 2>/dev/null | awk '/^Number/{part=1; next}; part{print $2; exit}')
|
|
if [ -z "$OFFSET" ]; then
|
|
echo "Could not find a valid system partition in image file!"
|
|
do_cleanup
|
|
StartProgress countdown "Normal startup in 5s... " 5 "NOW"
|
|
return 0
|
|
fi
|
|
fi
|
|
|
|
SECTOR_SIZE=$(cat /sys/devices/virtual/block/loop${LOOP_NUM}/queue/hw_sector_size)
|
|
losetup -d $LOOP
|
|
sync
|
|
|
|
OFFSET=$(($OFFSET * $SECTOR_SIZE))
|
|
|
|
# use losetup because busybox mount does not support the -o offset option
|
|
echo "Mounting system partition..."
|
|
losetup -o $OFFSET $LOOP $IMG_FILE
|
|
mount -o ro,loop $LOOP $UPDATE_DIR/.tmp/mnt
|
|
|
|
# don't make temporary files but instead copy
|
|
# directly from mountpoint to /flash
|
|
UPDATE_DIR=$UPDATE_ROOT/.tmp/mnt
|
|
UPDATE_KERNEL="@KERNEL_NAME@"
|
|
else
|
|
UPDATE_FILENAME="$UPDATE_DIR/$UPDATE_SYSTEM"
|
|
fi
|
|
|
|
sync
|
|
|
|
if [ ! -b "/$IMAGE_KERNEL" -a ! -f "/flash/$IMAGE_KERNEL" ] || [ ! -f "/flash/$IMAGE_SYSTEM" ]; then
|
|
echo "Missing (target) ${IMAGE_KERNEL} or ${IMAGE_SYSTEM}!"
|
|
do_cleanup
|
|
StartProgress countdown "Normal startup in 30s... " 30 "NOW"
|
|
return 0
|
|
fi
|
|
|
|
if [ ! -f "$UPDATE_DIR/$UPDATE_KERNEL" -o ! -f "$UPDATE_DIR/$UPDATE_SYSTEM" ]; then
|
|
echo "Missing (source) ${UPDATE_KERNEL} or ${UPDATE_SYSTEM}!"
|
|
do_cleanup
|
|
StartProgress countdown "Normal startup in 30s... " 30 "NOW"
|
|
return 0
|
|
fi
|
|
|
|
# check md5 sums if .nocheck doesn't exist
|
|
if [ ! -f "$UPDATE_ROOT/.nocheck" ]; then
|
|
if [ -f "$UPDATE_DIR/${UPDATE_KERNEL}.md5" -a -f "$UPDATE_DIR/${UPDATE_SYSTEM}.md5" ]; then
|
|
# *.md5 size-check
|
|
if [ ! -s "$UPDATE_DIR/${UPDATE_KERNEL}.md5" -o ! -s "$UPDATE_DIR/${UPDATE_SYSTEM}.md5" ]; then
|
|
echo "Zero-sized .md5 file!"
|
|
MD5_FAILED="1"
|
|
else
|
|
sed "s#target/KERNEL#$UPDATE_DIR/$UPDATE_KERNEL#g" "$UPDATE_DIR/${UPDATE_KERNEL}.md5" >"$UPDATE_ROOT/${UPDATE_KERNEL}.check.md5"
|
|
sed "s#target#$UPDATE_DIR#g" "$UPDATE_DIR/${UPDATE_SYSTEM}.md5" >"$UPDATE_ROOT/${UPDATE_SYSTEM}.check.md5"
|
|
|
|
StartProgress spinner "Checking ${UPDATE_KERNEL}.md5... "
|
|
if md5sum -sc "$UPDATE_ROOT/${UPDATE_KERNEL}.check.md5"; then
|
|
StopProgress "OK"
|
|
else
|
|
StopProgress "FAILED"
|
|
MD5_FAILED="1"
|
|
fi
|
|
|
|
StartProgress spinner "Checking ${UPDATE_SYSTEM}.md5... "
|
|
if md5sum -sc "$UPDATE_ROOT/${UPDATE_SYSTEM}.check.md5"; then
|
|
StopProgress "OK"
|
|
else
|
|
StopProgress "FAILED"
|
|
MD5_FAILED="1"
|
|
fi
|
|
fi
|
|
else
|
|
echo "Missing ${UPDATE_KERNEL}.md5 or ${UPDATE_SYSTEM}.md5!"
|
|
MD5_FAILED="1"
|
|
fi
|
|
|
|
if [ "$MD5_FAILED" -eq "1" ]; then
|
|
echo "md5 check failed!"
|
|
do_cleanup
|
|
StartProgress countdown "Normal startup in 30s... " 30 "NOW"
|
|
return 0
|
|
fi
|
|
fi
|
|
|
|
mount_part "$UPDATE_DIR/$UPDATE_SYSTEM" "/update" "ro,loop"
|
|
|
|
# Verify that the new update is compatible with the current system - this should avoid creating
|
|
# non-booting systems after (for example) an RPi tar is incorrectly applied to an RPi2 system.
|
|
if [ ! -f "$UPDATE_ROOT/.nocompat" ]; then
|
|
if ! check_is_compatible "$UPDATE_FILENAME"; then
|
|
do_cleanup
|
|
StartProgress countdown "Normal startup in 60s... " 60 "NOW"
|
|
return 0
|
|
fi
|
|
fi
|
|
|
|
# get sizes
|
|
FLASH_FREE=$(df /flash/ | awk '/[0-9]%/{print $4}')
|
|
FLASH_FREE=$(( $FLASH_FREE * 1024 ))
|
|
|
|
# Disregard kernel size if it's a a block device
|
|
if [ ! -b "/$IMAGE_KERNEL" ]; then
|
|
OLD_KERNEL=$(stat -t "/flash/$IMAGE_KERNEL" | awk '{print $2}')
|
|
else
|
|
OLD_KERNEL="0"
|
|
fi
|
|
|
|
OLD_SYSTEM=$(stat -t "/flash/$IMAGE_SYSTEM" | awk '{print $2}')
|
|
NEW_KERNEL=$(stat -t "$UPDATE_DIR/$UPDATE_KERNEL" | awk '{print $2}')
|
|
NEW_SYSTEM=$(stat -t "$UPDATE_DIR/$UPDATE_SYSTEM" | awk '{print $2}')
|
|
|
|
# old KERNEL+SYSTEM+free space - new KERNEL+SYSTEM must be higher than 5MB
|
|
# at least 5MB free after update
|
|
|
|
TMP_SIZE=$((OLD_KERNEL + OLD_SYSTEM + FLASH_FREE - NEW_KERNEL - NEW_SYSTEM))
|
|
FLASH_FREE_MIN=$((FLASH_FREE_MIN * 1024 * 1024))
|
|
|
|
if [ $TMP_SIZE -ge $FLASH_FREE_MIN ]; then
|
|
echo "Checking size: OK"
|
|
else
|
|
echo "Checking size: FAILED"
|
|
echo ""
|
|
echo "Your System (FAT) partition is too small for this update,"
|
|
echo "and there is not enough space for the update to be installed!"
|
|
echo ""
|
|
echo "You must re-install your system using the disk image of a"
|
|
echo "current release, or you must re-size your existing partitions"
|
|
echo "so that the System (FAT) partition is at least 512MB in size."
|
|
echo ""
|
|
do_cleanup
|
|
StartProgress countdown "Normal startup in 60s... " 60 "NOW"
|
|
return 0
|
|
fi
|
|
|
|
# all ok, update
|
|
display_versions
|
|
if [ -b "/$IMAGE_KERNEL" ]; then
|
|
update_partition "Kernel" "$UPDATE_KERNEL" "/$IMAGE_KERNEL"
|
|
else
|
|
update_file "Kernel" "$UPDATE_KERNEL" "/flash/$IMAGE_KERNEL"
|
|
fi
|
|
umount /sysroot &>/dev/null
|
|
update_file "System" "$UPDATE_SYSTEM" "/flash/$IMAGE_SYSTEM"
|
|
update_bootloader
|
|
sync
|
|
StartProgress countdown "Update complete. Reboot in 5s... " 5 "NOW"
|
|
do_cleanup
|
|
sync
|
|
do_reboot
|
|
}
|
|
|
|
prepare_sysroot() {
|
|
progress "Preparing system"
|
|
|
|
mount --move /flash /sysroot/flash
|
|
mount --move /storage /sysroot/storage
|
|
|
|
if [ ! -d "/sysroot/usr/lib/kernel-overlays/base/lib/modules/$(uname -r)/" -a -f "/sysroot/usr/lib/systemd/systemd" ]; then
|
|
echo ""
|
|
echo "NEVER TOUCH boot= in syslinux.conf / cmdline.txt!"
|
|
echo "If you don't know what you are doing,"
|
|
echo "your installation is now broken."
|
|
echo ""
|
|
StartProgress countdown "Normal startup in 60s... " 60 "NOW"
|
|
fi
|
|
|
|
[ -f "/sysroot/usr/lib/systemd/systemd" ] || error "final_check" "Could not find systemd!"
|
|
|
|
if [ ! -f "/sysroot/storage/.configured" ]
|
|
then
|
|
echo -ne "\033[1000H\033[2K==> Initializing system, please wait.." >/dev/console
|
|
else
|
|
echo -ne "\033[1000H\033[2K==> Loading, please wait.." >/dev/console
|
|
fi
|
|
}
|
|
|
|
check_amlogic_dtb() {
|
|
if grep -q "amlogic" /proc/device-tree/compatible 2>/dev/null; then
|
|
if grep -q "official" /sysroot/etc/os-release 2>/dev/null; then
|
|
progress "Checking Amlogic DTB"
|
|
if [ "$(uname -r)" = "3.14.29" ]; then
|
|
DT_ID=$(cat /proc/device-tree/le-dt-id 2>/dev/null)
|
|
else
|
|
DT_ID=$(cat /proc/device-tree/coreelec-dt-id 2>/dev/null)
|
|
fi
|
|
DT_FILE=$(ls -1 /sysroot/usr/share/bootloader/device_trees/${DT_ID}.dtb 2>/dev/null | head -n 1)
|
|
|
|
if [ -f "/proc/device-tree/coreelec" ] &&
|
|
[ -n "${DT_ID}" ] &&
|
|
[ -f "${DT_FILE}" ]; then
|
|
return 0
|
|
fi
|
|
|
|
echo "WARNING: Your device-tree is out-of-date!"
|
|
echo ""
|
|
echo "Please update it to resume normal startup."
|
|
echo ""
|
|
|
|
StartProgress countdown "Normal startup in 30s... " 30 "NOW"
|
|
echo ""
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# create pipe and save original descriptors
|
|
create_output_pipe() {
|
|
# save original stdout and stderr descriptors
|
|
exec 4>&1
|
|
exec 5>&2
|
|
|
|
# create pipe and use it with tee
|
|
mknod /tmp/output_pipe p
|
|
tee </tmp/output_pipe /dev/init.log &
|
|
TEE_PID=$!
|
|
}
|
|
|
|
# redirect stdout and stderr
|
|
redirect_output_to_pipe() {
|
|
exec 1>/tmp/output_pipe
|
|
exec 2>/tmp/output_pipe
|
|
}
|
|
|
|
# restore original descriptors
|
|
redirect_output_to_screen() {
|
|
exec 1>&4
|
|
exec 2>&5
|
|
}
|
|
|
|
# delete descriptor
|
|
delete_descriptors() {
|
|
exec 4>&-
|
|
exec 5>&-
|
|
}
|
|
|
|
# Do init tasks to bring up system
|
|
|
|
# run platform_init script if exists
|
|
if [ -f "./platform_init" ]; then
|
|
./platform_init
|
|
fi
|
|
|
|
# clear screen and hide cursor
|
|
clear
|
|
hidecursor
|
|
|
|
create_output_pipe
|
|
redirect_output_to_pipe
|
|
|
|
# parse command line arguments
|
|
for arg in $(cat /proc/cmdline); do
|
|
case $arg in
|
|
BOOT_IMAGE=*)
|
|
IMAGE_KERNEL="${arg#*=}"
|
|
[ "${IMAGE_KERNEL:0:1}" = "/" ] && IMAGE_KERNEL="${IMAGE_KERNEL:1}"
|
|
;;
|
|
SYSTEM_IMAGE=*)
|
|
IMAGE_SYSTEM="${arg#*=}"
|
|
[ "${IMAGE_SYSTEM:0:1}" = "/" ] && IMAGE_SYSTEM="${IMAGE_SYSTEM:1}"
|
|
;;
|
|
boot=*)
|
|
boot="${arg#*=}"
|
|
case $boot in
|
|
ISCSI=*|NBD=*|NFS=*)
|
|
UPDATE_DISABLED=yes
|
|
FLASH_NETBOOT=yes
|
|
;;
|
|
/dev/*|LABEL=*|UUID=*)
|
|
RUN_FSCK_DISKS="$RUN_FSCK_DISKS $boot"
|
|
;;
|
|
FOLDER=*)
|
|
RUN_FSCK_DISKS="$RUN_FSCK_DISKS ${boot#*=}"
|
|
;;
|
|
esac
|
|
;;
|
|
disk=*)
|
|
disk="${arg#*=}"
|
|
case $disk in
|
|
ISCSI=*|NBD=*|NFS=*)
|
|
STORAGE_NETBOOT=yes
|
|
;;
|
|
/dev/*|LABEL=*|UUID=*)
|
|
RUN_FSCK_DISKS="$RUN_FSCK_DISKS $disk"
|
|
;;
|
|
FOLDER=*)
|
|
RUN_FSCK_DISKS="$RUN_FSCK_DISKS ${disk#*=}"
|
|
;;
|
|
esac
|
|
;;
|
|
wol_mac=*)
|
|
wol_mac="${arg#*=}"
|
|
;;
|
|
wol_wait=*)
|
|
wol_wait="${arg#*=}"
|
|
;;
|
|
textmode)
|
|
INIT_UNIT="--unit=textmode.target"
|
|
;;
|
|
installer)
|
|
INIT_UNIT="--unit=installer.target"
|
|
SYSLINUX_DEFAULT="installer"
|
|
;;
|
|
debugging)
|
|
DEBUG=yes
|
|
;;
|
|
nopkmute)
|
|
MUTE_PRINTK=no
|
|
;;
|
|
progress)
|
|
PROGRESS=yes
|
|
INIT_ARGS="$INIT_ARGS --show-status=1"
|
|
;;
|
|
nofsck)
|
|
RUN_FSCK=no
|
|
;;
|
|
nosplash)
|
|
SPLASH=no
|
|
;;
|
|
toram)
|
|
SYSTEM_TORAM=yes
|
|
;;
|
|
live)
|
|
LIVE=yes
|
|
SYSLINUX_DEFAULT="live"
|
|
;;
|
|
portable)
|
|
SYSLINUX_DEFAULT="run"
|
|
;;
|
|
grub_live)
|
|
LIVE=yes
|
|
GRUB_DEFAULT="Live"
|
|
;;
|
|
grub_portable)
|
|
GRUB_DEFAULT="Run"
|
|
;;
|
|
overlay)
|
|
OVERLAY=yes
|
|
;;
|
|
setfbres=*)
|
|
SWITCH_FRAMEBUFFER="${arg#*=}"
|
|
SWITCH_FRAMEBUFFER="${SWITCH_FRAMEBUFFER//,/ }"
|
|
;;
|
|
break=*)
|
|
BREAK="${arg#*=}"
|
|
;;
|
|
bigfont=*)
|
|
BIGFONT="${arg#*=}"
|
|
;;
|
|
ip=*)
|
|
KERNEL_IPCONFIG="yes"
|
|
;;
|
|
esac
|
|
done
|
|
|
|
# hide kernel log messages on console
|
|
if [ ! "$MUTE_PRINTK" = "no" ]; then
|
|
echo '1 4 1 7' > /proc/sys/kernel/printk
|
|
fi
|
|
|
|
if test "$DEBUG" = "yes"; then
|
|
exec 3>&1
|
|
else
|
|
exec 3>/dev/null
|
|
fi
|
|
SILENT_OUT=3
|
|
|
|
# If the network is up (due to the use of the "ip" kernel parameter) and a DNS
|
|
# server is known, allow the libc resolver to use it
|
|
grep '^\(nameserver\|domain\) ' /proc/net/pnp 2>/dev/null | grep -v '^nameserver 0\.0\.0\.0$' > /etc/resolv.conf
|
|
|
|
if [ "${boot%%=*}" = "FILE" ]; then
|
|
error "check arguments" "boot argument can't be FILE type..."
|
|
fi
|
|
|
|
debug_msg "Unique identifier for this client: ${MACHINE_UID:-NOT AVAILABLE}"
|
|
|
|
# main boot sequence
|
|
for BOOT_STEP in \
|
|
load_modules \
|
|
check_disks \
|
|
mount_flash \
|
|
set_consolefont \
|
|
cleanup_flash \
|
|
update_bootmenu \
|
|
load_splash \
|
|
mount_sysroot \
|
|
mount_storage \
|
|
mount_games \
|
|
check_update \
|
|
prepare_sysroot \
|
|
check_amlogic_dtb; do
|
|
$BOOT_STEP
|
|
[ -n "$DEBUG" ] && break_after $BOOT_STEP
|
|
done
|
|
|
|
BOOT_STEP=final
|
|
|
|
# log if booting from usb / removable storage
|
|
STORAGE=$(cat /proc/mounts | grep " /sysroot/storage " 2>/dev/null | awk '{print $1}' | awk -F '/' '{print $3}')
|
|
FLASH=$(cat /proc/mounts | grep " /sysroot/flash " 2>/dev/null | awk '{print $1}' | awk -F '/' '{print $3}')
|
|
for i in $STORAGE $FLASH ; do
|
|
if [ -n "$i" ]; then
|
|
removable="/sys/class/block/*/$i/../removable"
|
|
if [ -e $removable ]; then
|
|
if [ "$(cat $removable 2>/dev/null)" = "1" ]; then
|
|
echo "### BIG FAT WARNING" > /dev/kmsg
|
|
echo "### $i is removable. suspend/resume may not work" > /dev/kmsg
|
|
fi
|
|
fi
|
|
fi
|
|
done
|
|
# move some special filesystems
|
|
/usr/bin/busybox mount --move /dev /sysroot/dev
|
|
/usr/bin/busybox mount --move /proc /sysroot/proc
|
|
/usr/bin/busybox mount --move /sys /sysroot/sys
|
|
/usr/bin/busybox rm -fr /tmp
|
|
|
|
# tell OE settings addon to disable updates
|
|
if [ "$UPDATE_DISABLED" = "yes" ]; then
|
|
echo "" > /sysroot/dev/.update_disabled
|
|
fi
|
|
|
|
if [ "$FLASH_NETBOOT" = "yes" ]; then
|
|
echo "" > /sysroot/dev/.flash_netboot
|
|
fi
|
|
|
|
if [ "$KERNEL_IPCONFIG" = "yes" ]; then
|
|
echo "" > /sysroot/dev/.kernel_ipconfig
|
|
fi
|
|
|
|
# swap can not be used over nfs.(see scripts/mount-swap)
|
|
if [ "$STORAGE_NETBOOT" = "yes" ]; then
|
|
echo "" > /sysroot/dev/.storage_netboot
|
|
fi
|
|
|
|
BACKUP_FILE=$(ls -1 /sysroot/storage/.restore/??????????????.tar 2>/dev/null | head -n 1)
|
|
|
|
if [ -f /sysroot/storage/.please_resize_me ]; then
|
|
INIT_UNIT="--unit=fs-resize.target"
|
|
elif [ -f /sysroot/storage/.cache/reset_oe -o -f /sysroot/storage/.cache/reset_xbmc ]; then
|
|
INIT_UNIT="--unit=factory-reset.target"
|
|
elif [ -f "$BACKUP_FILE" ]; then
|
|
INIT_UNIT="--unit=backup-restore.target"
|
|
elif [ -f /sysroot/storage/.rpi_flash_firmware ]; then
|
|
INIT_UNIT="--unit=rpi-flash-firmware.target"
|
|
fi
|
|
|
|
# stop output redirection
|
|
[ -n "$TEE_PID" ] && kill $TEE_PID &>/dev/null
|
|
if [ -s /sysroot/dev/init.log ]; then
|
|
mv /sysroot/dev/init.log /sysroot/storage/init.log
|
|
else
|
|
rm -f /sysroot/dev/init.log
|
|
rm -f /sysroot/storage/init.log
|
|
fi
|
|
|
|
# restore original descriptors and delete descriptors
|
|
redirect_output_to_screen
|
|
delete_descriptors
|
|
|
|
# switch to new sysroot and start real init
|
|
exec /usr/bin/busybox switch_root /sysroot /usr/lib/systemd/systemd $INIT_ARGS $INIT_UNIT
|
|
|
|
error "switch_root" "Error in initramfs. Could not switch to new root"
|