463 lines
10 KiB
Bash
463 lines
10 KiB
Bash
#!/bin/sh
|
|
|
|
fslist="proc sys dev run"
|
|
rodir=run/initramfs/ro
|
|
rwdir=run/initramfs/rw
|
|
upper=$rwdir/cow
|
|
work=$rwdir/work
|
|
|
|
cd /
|
|
for f in $fslist
|
|
do
|
|
mkdir -p "$f"
|
|
done
|
|
mount dev dev -tdevtmpfs
|
|
mount sys sys -tsysfs
|
|
mount proc proc -tproc
|
|
if ! grep run proc/mounts
|
|
then
|
|
mount tmpfs run -t tmpfs -o mode=755,nodev
|
|
fi
|
|
|
|
mkdir -p $rodir $rwdir
|
|
|
|
cp -rp init shutdown update whitelist bin sbin usr lib etc var run/initramfs
|
|
|
|
# To start a interactive shell with job control at this point, run
|
|
# getty 38400 ttyS4
|
|
|
|
findmtd() {
|
|
m=$(grep -xl "$1" /sys/class/mtd/*/name)
|
|
m=${m%/name}
|
|
m=${m##*/}
|
|
echo "$m"
|
|
}
|
|
|
|
blkid_fs_type() {
|
|
# Emulate util-linux's `blkid -s TYPE -o value $1`
|
|
# Example busybox blkid output:
|
|
# # blkid /dev/mtdblock5
|
|
# /dev/mtdblock5: TYPE="squashfs"
|
|
# Process output to extract TYPE value "squashfs".
|
|
blkid "$1" | sed -e 's/^.*TYPE="//' -e 's/".*$//'
|
|
}
|
|
|
|
probe_fs_type() {
|
|
fst=$(blkid_fs_type "$1")
|
|
echo "${fst:=jffs2}"
|
|
}
|
|
|
|
# This fw_get_env_var is a possibly broken version of fw_printenv that
|
|
# does not check the crc or flag byte.
|
|
# The u-boot environment starts with a crc32, followed by a flag byte
|
|
# when a redundannt environment is configured, followed by var=value\0 sets.
|
|
# The flag byte for nand is a 1 byte counter; for nor it is a 1 or 0 byte.
|
|
|
|
get_fw_env_var() {
|
|
# do we have 1 or 2 copies of the environment?
|
|
# count non-blank non-comment lines
|
|
# copies=$(grep -v ^# /etc/fw_env.config | grep -c [::alnum::])
|
|
# ... we could if we had the fw_env.config in the initramfs
|
|
copies=2
|
|
|
|
# * Change \n to \r and \0 to \n
|
|
# * Skip to the 5th byte to skip over crc
|
|
# * then skip to the first or 2nd byte to skip over flag if it exists
|
|
# * stop parsing at first empty line corresponding to the
|
|
# double \0 at the end of the environment.
|
|
# * print the value of the variable name passed as argument
|
|
|
|
envdev=$(findmtd u-boot-env)
|
|
if test -n "$envdev"
|
|
then
|
|
tr '\n\000' '\r\n' < "/dev/$envdev" |
|
|
tail -c +5 | tail -c +${copies-1} |
|
|
sed -ne '/^$/,$d' -e "s/^$1=//p"
|
|
fi
|
|
}
|
|
|
|
setup_resolv() {
|
|
runresolv=/run/systemd/resolve/resolv.conf
|
|
etcresolv=/etc/resolv.conf
|
|
|
|
if test ! -e $etcresolv -a ! -L $etcresolv
|
|
then
|
|
mkdir -p ${runresolv%/*}
|
|
ln -s $runresolv $etcresolv
|
|
fi
|
|
if test ! -f $runresolv
|
|
then
|
|
cat /proc/net/pnp > $runresolv
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
try_tftp() {
|
|
# split into tftp:// host:port/ path/on/remote
|
|
# then spilt off / and then :port from the end of host:port/
|
|
# and : from the beginning of port
|
|
|
|
rest="${1#tftp://}"
|
|
path=${rest#*/}
|
|
host=${rest%"$path"}
|
|
host="${host%/}"
|
|
port="${host#"${host%:*}"}"
|
|
host="${host%"$port"}"
|
|
port="${port#:}"
|
|
|
|
setup_resolv
|
|
|
|
if test -z "$host" -o -z "$path"
|
|
then
|
|
debug_takeover "Invalid tftp download url '$url'."
|
|
elif echo "Downloading '$url' from $host ..." &&
|
|
! tftp -g -r "$path" -l /run/image-rofs "$host" ${port+"$port"}
|
|
then
|
|
debug_takeover "Download of '$url' failed."
|
|
fi
|
|
}
|
|
|
|
try_wget() {
|
|
setup_resolv
|
|
|
|
echo "Downloading '$1' ..."
|
|
if ! wget -O /run/image-rofs "$1"
|
|
then
|
|
debug_takeover "Download of '$url' failed."
|
|
fi
|
|
}
|
|
|
|
getch() {
|
|
old=$(stty -g)
|
|
stty raw -echo min 0 time 50
|
|
printf '%s' "$(dd bs=1 count=1 2>/dev/null)"
|
|
stty "$old"
|
|
}
|
|
|
|
debug_takeover() {
|
|
echo "$@"
|
|
echo "Press (Y/y) to log in and try to manually fix, force recovery in 5 seconds"
|
|
answer=$(getch)
|
|
if [ "$answer" != "y" ] && [ "$answer" != "Y" ] ;
|
|
then
|
|
mkdir -p /var/lock
|
|
envdev=$(findmtd u-boot-env)
|
|
echo "/dev/${envdev} 0x00000 0x10000" > /etc/fw_env.config
|
|
echo "/dev/${envdev} 0x10000 0x10000" >> /etc/fw_env.config
|
|
fw_setenv force_recovery 1
|
|
fw_setenv last_booterrmsg "$@"
|
|
devmem 0xc0000000 32 0x01
|
|
fi
|
|
cat << HERE
|
|
After fixing run exit to continue this script, or reboot -f to retry, or
|
|
touch /takeover and exit to become PID 1 allowing editing of this script.
|
|
HERE
|
|
|
|
while ! sulogin && ! test -f /takeover
|
|
do
|
|
echo getty failed, retrying
|
|
done
|
|
|
|
# Touch /takeover in the above getty to become pid 1
|
|
if test -e /takeover
|
|
then
|
|
cat << HERE
|
|
|
|
Takeover of init requested. Executing /bin/sh as PID 1.
|
|
When finished exec new init or cleanup and run reboot -f.
|
|
|
|
Warning: No job control! Shell exit will panic the system!
|
|
HERE
|
|
export PS1=init#\
|
|
exec /bin/sh
|
|
fi
|
|
}
|
|
|
|
# Check System Maintenace Switch 7 and load factory default
|
|
check_dip() {
|
|
devmem 0x800000b8 16 0xFF
|
|
dip=$(devmem 0x800000b8 16)
|
|
|
|
value1=$((( dip & 0xFF00 ) >> 8 ))
|
|
value2=$((( dip & 0x0040 ) >> 6 ))
|
|
|
|
if [ $value1 -eq 0 ] && [ $value2 -eq 1 ]
|
|
then
|
|
echo "Detect System Maintenace Switch 7 on. Will load factory default"
|
|
return 0
|
|
fi
|
|
return 1
|
|
}
|
|
|
|
rofs=$(findmtd rofs)
|
|
rwfs=$(findmtd rwfs)
|
|
|
|
rodev=/dev/mtdblock${rofs#mtd}
|
|
rwdev=/dev/mtdblock${rwfs#mtd}
|
|
|
|
# Set to y for yes, anything else for no.
|
|
force_rwfst_jffs2=y
|
|
flash_images_before_init=n
|
|
consider_download_files=y
|
|
consider_download_tftp=y
|
|
consider_download_http=y
|
|
consider_download_ftp=y
|
|
|
|
rofst=squashfs
|
|
rwfst=$(probe_fs_type "$rwdev")
|
|
roopts=ro
|
|
rwopts=rw
|
|
|
|
image=/run/initramfs/image-
|
|
trigger=${image}rwfs
|
|
|
|
init=/sbin/init
|
|
fsckbase=/sbin/fsck.
|
|
fsck=$fsckbase$rwfst
|
|
fsckopts=-a
|
|
optfile=/run/initramfs/init-options
|
|
optbase=/run/initramfs/init-options-base
|
|
urlfile=/run/initramfs/init-download-url
|
|
update=/run/initramfs/update
|
|
|
|
if test -e /${optfile##*/}
|
|
then
|
|
cp /${optfile##*/} $optfile
|
|
fi
|
|
|
|
if test -e /${optbase##*/}
|
|
then
|
|
cp /${optbase##*/} $optbase
|
|
else
|
|
touch $optbase
|
|
fi
|
|
|
|
if test ! -f $optfile
|
|
then
|
|
cat /proc/cmdline $optbase > $optfile
|
|
get_fw_env_var openbmcinit >> $optfile
|
|
get_fw_env_var openbmconce >> $optfile
|
|
fi
|
|
|
|
echo "rofs = $rofs $rofst rwfs = $rwfs $rwfst"
|
|
|
|
if grep -w debug-init-sh $optfile
|
|
then
|
|
debug_takeover "Debug initial shell requested by command line."
|
|
fi
|
|
|
|
if test "$consider_download_files" = "y" &&
|
|
grep -w openbmc-init-download-files $optfile
|
|
then
|
|
if test -f ${urlfile##*/}
|
|
then
|
|
cp ${urlfile##*/} $urlfile
|
|
fi
|
|
if test ! -f $urlfile
|
|
then
|
|
get_fw_env_var openbmcinitdownloadurl > $urlfile
|
|
fi
|
|
url="$(cat $urlfile)"
|
|
rest="${url#*://}"
|
|
proto="${url%"$rest"}"
|
|
|
|
if test -z "$url"
|
|
then
|
|
echo "Download url empty. Ignoring download request."
|
|
elif test -z "$proto"
|
|
then
|
|
echo "Download failed."
|
|
elif test "$proto" = tftp://
|
|
then
|
|
if test "$consider_download_tftp" = "y"
|
|
then
|
|
try_tftp "$url"
|
|
else
|
|
echo "Download failed."
|
|
fi
|
|
elif test "$proto" = http://
|
|
then
|
|
if test "$consider_download_http" = "y"
|
|
then
|
|
try_wget "$url"
|
|
else
|
|
echo "Download failed."
|
|
fi
|
|
elif test "$proto" = ftp://
|
|
then
|
|
if test "$consider_download_ftp" = "y"
|
|
then
|
|
try_wget "$url"
|
|
else
|
|
echo "Download failed."
|
|
fi
|
|
else
|
|
echo "Download failed."
|
|
fi
|
|
fi
|
|
|
|
# If there are images in root move them to /run/initramfs/ or /run/ now.
|
|
imagebasename=${image##*/}
|
|
if test -n "${imagebasename}" && ls /"${imagebasename}"* > /dev/null 2>&1
|
|
then
|
|
if test "$flash_images_before_init" = "y"
|
|
then
|
|
echo "Flash images found, will update before starting init."
|
|
mv /"${imagebasename}"* ${image%"$imagebasename"}
|
|
else
|
|
echo "Flash images found, will use but deferring flash update."
|
|
mv /"${imagebasename}"* /run/
|
|
fi
|
|
fi
|
|
|
|
if grep -w clean-rwfs-filesystem $optfile
|
|
then
|
|
echo "Cleaning of read-write overlay filesystem requested."
|
|
touch $trigger
|
|
fi
|
|
|
|
if grep -w factory-reset $optfile || check_dip
|
|
then
|
|
echo "Factory reset requested."
|
|
touch $trigger
|
|
do_save=--no-save-files
|
|
else
|
|
do_save=--save-files
|
|
fi
|
|
|
|
if test "$force_rwfst_jffs2" = "y" -a "$rwfst" != jffs2 -a ! -f $trigger
|
|
then
|
|
echo "Converting read-write overlay filesystem to jffs2 forced."
|
|
touch $trigger
|
|
fi
|
|
|
|
if ls $image* > /dev/null 2>&1
|
|
then
|
|
if ! test -x $update
|
|
then
|
|
debug_takeover "Flash update requested but $update missing!"
|
|
elif test -f $trigger -a ! -s $trigger
|
|
then
|
|
if [ $do_save = "--save-files" ]
|
|
then
|
|
echo "Saving selected files from read-write overlay filesystem."
|
|
else
|
|
echo "No files will be selected for save."
|
|
fi
|
|
$update --no-restore-files $do_save
|
|
echo "Clearing read-write overlay filesystem."
|
|
flash_eraseall "/dev/$rwfs"
|
|
echo "Restoring saved files to read-write overlay filesystem."
|
|
touch $trigger
|
|
$update --no-save-files --clean-saved-files
|
|
else
|
|
$update --clean-saved-files $do_save
|
|
fi
|
|
|
|
rwfst=$(probe_fs_type "$rwdev")
|
|
fsck=$fsckbase$rwfst
|
|
fi
|
|
|
|
if grep -w overlay-filesystem-in-ram $optfile
|
|
then
|
|
rwfst=none
|
|
fi
|
|
|
|
copyfiles=
|
|
if grep -w copy-files-to-ram $optfile
|
|
then
|
|
rwfst=none
|
|
copyfiles=y
|
|
fi
|
|
|
|
# It would be nice to do this after fsck but that mean rofs is mounted
|
|
# which triggers the mtd is mounted check
|
|
if test "$rwfst$copyfiles" = noney
|
|
then
|
|
touch $trigger
|
|
$update --copy-files --clean-saved-files --no-restore-files
|
|
fi
|
|
|
|
if grep -w copy-base-filesystem-to-ram $optfile &&
|
|
test ! -e /run/image-rofs && ! cp "$rodev" /run/image-rofs
|
|
then
|
|
# Remove any partial copy to avoid attempted usage later
|
|
if test -e /run/image-rofs
|
|
then
|
|
ls -l /run/image-rofs
|
|
rm -f /run/image-rofs
|
|
fi
|
|
debug_takeover "Copying $rodev to /run/image-rofs failed."
|
|
fi
|
|
|
|
if test -s /run/image-rofs
|
|
then
|
|
rodev=/run/image-rofs
|
|
roopts=$roopts,loop
|
|
fi
|
|
|
|
mount "$rodev" $rodir -t $rofst -o $roopts
|
|
|
|
if test -x "$rodir$fsck"
|
|
then
|
|
for fs in $fslist
|
|
do
|
|
mount --bind "$fs" "$rodir/$fs"
|
|
done
|
|
chroot $rodir "$fsck" $fsckopts "$rwdev"
|
|
rc=$?
|
|
for fs in $fslist
|
|
do
|
|
umount "$rodir/$fs"
|
|
done
|
|
if test $rc -gt 1
|
|
then
|
|
debug_takeover "fsck of read-write fs on $rwdev failed (rc=$rc)"
|
|
fi
|
|
elif test "$rwfst" != jffs2 -a "$rwfst" != none
|
|
then
|
|
echo "No '$fsck' in read only fs, skipping fsck."
|
|
fi
|
|
|
|
if test "$rwfst" = none
|
|
then
|
|
echo "Running with read-write overlay in RAM for this boot."
|
|
echo "No state will be preserved unless flash update performed."
|
|
elif ! mount "$rwdev" $rwdir -t "$rwfst" -o $rwopts
|
|
then
|
|
msg="$(cat)" << HERE
|
|
|
|
Mounting read-write $rwdev filesystem failed. Please fix and run
|
|
mount $rwdev $rwdir -t $rwfst -o $rwopts
|
|
to to continue, or do change nothing to run from RAM for this boot.
|
|
HERE
|
|
debug_takeover "$msg"
|
|
fi
|
|
|
|
rm -rf $work
|
|
mkdir -p $upper $work
|
|
|
|
mount -t overlay -o lowerdir=$rodir,upperdir=$upper,workdir=$work cow /root
|
|
|
|
while ! chroot /root /bin/sh -c "test -x '$init' -a -s '$init'"
|
|
do
|
|
msg="$(cat)" << HERE
|
|
|
|
Unable to confirm /sbin/init is an executable non-empty file
|
|
in merged file system mounted at /root.
|
|
|
|
Change Root test failed! Invoking emergency shell.
|
|
HERE
|
|
debug_takeover "$msg"
|
|
done
|
|
|
|
for f in $fslist
|
|
do
|
|
mount --move "$f" "root/$f"
|
|
done
|
|
|
|
# switch_root /root $init
|
|
exec chroot /root $init
|
|
|