Initial commit

This commit is contained in:
Your Name
2026-04-23 17:07:55 +08:00
commit b7e39e063b
16725 changed files with 1625565 additions and 0 deletions
@@ -0,0 +1,453 @@
#!/bin/sh
fslist="proc sys dev run"
rodir=run/initramfs/ro
rwdir=run/initramfs/rw
upper=$rwdir/cow
work=$rwdir/work
cd /
# shellcheck disable=SC2086
mkdir -p $fslist
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
}
debug_takeover() {
echo "$@"
if ! grep -w enable-initrd-debug-sh "$optfile"
then
echo "Fatal error, triggering kernel panic!"
exit 1
fi
test -n "$@" && echo Try to manually fix.
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 ! /bin/sh && ! test -f /takeover
do
echo /bin/sh failed, retrying
done
# Touch /takeover in the above shell 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
}
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
if grep -w enable-initrd-debug-sh "$optfile"
then
debug_takeover "Debug initial shell requested by command line."
else
echo "Need to also add enable-initrd-debug-sh for debug shell."
fi
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
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
or perform a factory reset with the clean-rwfs-filesystem option.
HERE
debug_takeover "$msg"
fi
# Empty workdir; do not remove workdir itself for it will fail to recreate it if
# RWFS is full
if [ -d $work ]
then
find $work -maxdepth 1 -mindepth 1 -exec rm -rf '{}' +
fi
mkdir -p $upper $work
# Opportunisticly set a sane BMC date based on a file that gets
# written right before rebooting or powercycling. If none exists,
# use the image build date.
files="$upper/var/lib/systemd/random-seed $rodir/etc/os-release"
# shellcheck disable=SC2086
time=$(find $files -exec stat -c %Y {} \; | sort -n | tail -n 1)
# Allow RTC coordinated time to supersede this setting
if [ "$(date +%s)" -lt "$time" ]; then
date -s @$((time + 5)) || true
fi
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!
HERE
debug_takeover "$msg"
done
for f in $fslist
do
mount --move "$f" "root/$f"
done
exec switch_root /root $init
@@ -0,0 +1,103 @@
#!/bin/sh
echo shutdown: "$@"
export PS1="shutdown-sh# "
# exec bin/sh
cd /
if [ ! -e /proc/mounts ]
then
mkdir -p /proc
mount proc /proc -tproc
umount_proc=1
else
umount_proc=
fi
# Remove an empty oldroot, that means we are not invoked from systemd-shutdown
rmdir /oldroot 2>/dev/null
# Move /oldroot/run to /mnt in case it has the underlying rofs loop mounted.
# Ordered before /oldroot the overlay is unmounted before the loop mount
mkdir -p /mnt
mount --move /oldroot/run /mnt
set -x
awk '/oldroot|mnt/ { print $2 }' < /proc/mounts | sort -r | while IFS= read -r f
do
umount "$f"
done
set +x
update=/run/initramfs/update
image=/run/initramfs/image-
wdt="-t 1 -T 5"
wdrst="-T 15"
if ls $image* > /dev/null 2>&1
then
if test -x $update
then
if test -c /dev/watchdog
then
echo Pinging watchdog ${wdt+with args $wdt}
# shellcheck disable=SC2086
watchdog $wdt -F /dev/watchdog &
wd=$!
else
wd=
fi
$update --clean-saved-files
remaining=$(ls $image*)
if test -n "$remaining"
then
echo 1>&2 "Flash update failed to flash these images:"
echo 1>&2 "$remaining"
else
echo "Flash update completed."
fi
if test -n "$wd"
then
kill -9 $wd
if test -n "$wdrst"
then
echo "Resetting watchdog timeouts to $wdrst"
watchdog "$wdrst" -F /dev/watchdog &
sleep 1
# Kill the watchdog daemon, setting a timeout
# for the remaining shutdown work
kill -9 $!
fi
fi
else
echo 1>&2 "Flash update requested but $update program missing!"
fi
fi
echo Remaining mounts:
cat /proc/mounts
test "$umount_proc" && umount /proc && rmdir /proc
# tcsattr(tty, TIOCDRAIN, mode) to drain tty messages to console
test -t 1 && stty cooked 0<&1
# Execute the command systemd told us to ...
if test -d /oldroot && test "$1"
then
if test "$1" = kexec
then
$1 -f -e
else
$1 -f
fi
fi
echo "Execute ${1-reboot} -f if all unmounted ok, or exec /init"
export PS1=shutdown-sh#\
exec /bin/sh
@@ -0,0 +1,274 @@
#!/bin/sh
echo update: "$@"
echoerr() {
echo 1>&2 "ERROR: $*"
}
cd /
if ! test -r /proc/mounts || ! test -f /proc/mounts
then
mkdir -p /proc
mount -t proc proc proc
fi
if ! test -d /sys/class
then
mkdir -p /sys
mount -t sysfs sys sys
fi
if ! test -c /dev/null
then
mkdir -p /dev
mount -t devtmpfs dev dev
fi
# mtd number N with mtd name Name can be mounted via mtdN, or mtd:Name
# (with a mtd aware fs) or by /dev/mtdblockN (with a mtd or block fs).
mtdismounted() {
m=${1##mtd}
if grep -s "mtdblock$m " /proc/mounts || grep -s "mtd$m " /proc/mounts
then
return 0
fi
n=$(cat "/sys/class/mtd/mtd$m/name")
if test -n "$n" && grep -s "mtd:$n " /proc/mounts
then
return 0
fi
return 1
}
# Detect child partitions when the whole flash is to be updated.
# Ignore mtdNro and mtdblockN names in the class subsystem directory.
childmtds() {
for m in "/sys/class/mtd/$1/mtd"*
do
m=${m##*/}
if test "${m%ro}" = "${m#mtdblock}"
then
echo "$m"
fi
done
}
toobig() {
if test "$(stat -L -c "%s" "$1")" -gt "$(cat "/sys/class/mtd/$2/size")"
then
return 0
fi
return 1
}
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}"
}
rwfs=$(findmtd rwfs)
rwdev=/dev/mtdblock${rwfs#mtd}
rwopts=rw
rorwopts=ro${rwopts#rw}
rwdir=/run/initramfs/rw
upper=$rwdir/cow
save=/run/save/${upper##*/}
mounted=
doflash=y
doclean=
dosave=y
dorestore=y
toram=
checksize=y
checkmount=y
whitelist=/run/initramfs/whitelist
image=/run/initramfs/image-
imglist=
while test "$1" != "${1#-}"
do
case "$1" in
--help)
cat <<HERE
Usage: $0 [options] -- Write images in /run/initramfs to flash (/dev/mtd*)
--help Show this message
--no-flash Don't attempt to write images to flash
--ignore-size Don't compare image size to mtd device size
--ignore-mount Don't check if destination is mounted
--save-files Copy whitelisted files to save directory in RAM
--no-save-files Don't copy whitelisted files to save directory
--copy-files Copy files from save directory to rwfs mountpoint
--restore-files Restore files from save directory to rwfs layer
--no-restore-files Don't restore saved files from ram to rwfs layer
--clean-saved-files Delete saved whitelisted files from RAM
--no-clean-saved-files Retain saved whitelisted files in RAM
HERE
exit 0 ;;
--no-clean-saved-files)
doclean=
shift ;;
--clean-saved-files)
doclean=y
shift ;;
--no-save-files)
dosave=
shift ;;
--save-files)
dosave=y
shift ;;
--no-restore-files)
dorestore=
shift ;;
--restore-files)
dorestore=y
shift ;;
--no-flash)
doflash=
shift ;;
--ignore-size)
checksize=
shift ;;
--ignore-mount)
checkmount=
doflash=
shift ;;
--copy-files)
toram=y
shift ;;
*)
echoerr "Unknown option $1. Try $0 --help."
exit 1 ;;
esac
done
if test "$dosave" = "y"
then
if test ! -d $upper -a -n "$rwfs"
then
mkdir -p $rwdir
mount "$rwdev" $rwdir -t "$(probe_fs_type "$rwdev")" -o "$rorwopts"
mounted=$rwdir
fi
while read -r f
do
# Entries shall start with /, no trailing /.. or embedded /../
if test "/${f#/}" != "$f" -o "${f%/..}" != "${f#*/../}"
then
echo 1>&2 "WARNING: Skipping bad whitelist entry $f."
continue
fi
if ! test -e "$upper/$f"
then
continue
fi
d="$save/$f"
while test "${d%/}" != "${d%/.}"
do
d="${d%/.}"
d="${d%/}"
done
mkdir -p "${d%/*}"
cp -rp "$upper/$f" "${d%/*}/"
done < $whitelist
if test -n "$mounted"
then
umount $mounted
fi
fi
imglist=$(echo $image*)
if test "$imglist" = "$image*" -a ! -e "$imglist"
then
# shell didn't expand the wildcard, so no files exist
echo "No images found to update."
imglist=
fi
for f in $imglist
do
m=$(findmtd "${f#"$image"}")
if test -z "$m"
then
echoerr "Unable to find mtd partition for ${f##*/}."
exit 1
fi
if test -n "$checksize" && toobig "$f" "$m"
then
echoerr "Image ${f##*/} too big for $m."
exit 1
fi
for s in $m $(childmtds "$m")
do
if test -n "$checkmount" && mtdismounted "$s"
then
echoerr "Device $s is mounted, ${f##*/} is busy."
exit 1
fi
done
done
if test -n "$doflash"
then
for f in $imglist
do
if test ! -s "$f"
then
echo "Skipping empty update of ${f#"$image"}."
rm "$f"
continue
fi
m=$(findmtd "${f#"$image"}")
echo "Updating ${f#"$image"}..."
flashcp -v "$f" "/dev/$m" && rm "$f"
done
fi
if test -d "$save" -a "$toram" = "y"
then
mkdir -p $upper
cp -rp "$save/." "$upper/"
fi
if test -d "$save" -a "$dorestore" = "y"
then
odir=$rwdir
rwdir=/run/rw
upper=$rwdir${upper#"$odir"}
mkdir -p $rwdir
mount "$rwdev" $rwdir -t "$(probe_fs_type "$rwdev")" -o $rwopts
mkdir -p "$upper"
cp -rp "$save/." "$upper/"
umount $rwdir
rmdir $rwdir
fi
if test "$doclean" = "y"
then
rm -rf "$save"
fi
exit
@@ -0,0 +1,14 @@
/etc/dropbear/dropbear_rsa_host_key
/etc/group
/etc/gshadow
/etc/ipmi_pass
/etc/machine-id
/etc/passwd
/etc/resolv.conf
/etc/shadow
/etc/systemd/network
/var/cache/obmc
/var/lib/obmc
/var/lib/phosphor-inventory-manager
/var/lib/phosphor-settings-manager
/var/lib/phosphor-state-manager