Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions .github/scripts/test_sysupgrade.sh
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,7 @@ case "$applet" in
kill|ubirmvol|ubirsvol|ubimkvol)
echo "$applet $*" >> "$FLASH_LOG" ;;
umount) echo "$applet $*" >> "$FLASH_LOG"
case "$*" in *overlay.old*) [ "1" = "$STUB_OVL_UMOUNT_FAIL" ] && exit 1 ;; esac
exit "${STUB_BB_UMOUNT_RC:-0}" ;;
# The applet list enter_ramfs links into the RAM root, and the RAM-root
# reservation counts. Silent unless a test asks for one.
Expand Down Expand Up @@ -388,6 +389,18 @@ case " $* " in
rm -rf "$target"; mkdir -p "$target" ;;
esac
exit 0 ;;
# On the split layout the handed-off RAM phase mounts the jffs2 overlay
# read-only to copy the settings out, since its own mount has gone
# with the old root. It finds the marker the camera had.
# The files come from STUB_JFFS2_DIR/<device name>, so a mount of any
# other device finds nothing and fails, as a wrong partition would.
*" -t jffs2 "*)
[ "1" = "$STUB_JFFS2_RO_FAIL" ] && exit 255
dev=${@: -2:1}; src=$STUB_JFFS2_DIR/${dev##*/}
[ -d "$src" ] || exit 255
echo "mount jffs2 ro $dev $target" >> "$FLASH_LOG"
mkdir -p "$target" && cp -a "$src/." "$target/"
exit 0 ;;
esac
case "${STUB_MOUNT:-ok}" in
ok)
Expand Down Expand Up @@ -3382,6 +3395,74 @@ else
bad "split layout -n, rc=$RC len='$(blob_len 2 "$OVL" 0x50000)' out='$OUT'"
fi

# Handed off: the RAM phase runs as PID 1, release_old_root has let go of the
# old root and the overlay's mount with it, so /proc/mounts no longer shows
# rootfs_data. The settings are still on it, and must still be carried: an
# empty blob here is the camera starting from defaults after every NOR upgrade
# since the hand-off (#2648).
split_handed_off() {
split_env split
printf 'tmpfs %s/tmp tmpfs rw 0 0\n' "$SB" > "$SB/proc/mounts"
# What is on rootfs_data (mtdblock5): the settings, unlike anything the
# stub could make up.
rm -rf "$SB/jffs2"; mkdir -p "$SB/jffs2/mtdblock5/etc"
echo "from-rootfs_data" > "$SB/jffs2/mtdblock5/etc/carried"
RUN_ENV="$RUN_ENV STUB_JFFS2_DIR=$SB/jffs2 _ramfs_phase=1 _handoff=1 split_overlay_mounted=1 image_combined=1 update_kernel=1 update_rootfs=1 model=gk7205v200 skip_soc=1 skip_ver=1 root_on_flash=1 ram_root_shipped=1"
tar -xzf "$SB/tmp/fw.tgz" -C "$SB/tmp"
}
split_handed_off
run
u=$(logged_at "umount -l /mnt"); m=$(logged_at "mount jffs2 ro")
if [ "$(flash_at 2 0x50000 0x50000 8)" = "$FW_HEAD" ] &&
blob_files 2 "$OVL" 0x50000 | grep -q 'etc/carried' &&
grep -q "mount jffs2 ro .*mtdblock5 " "$SB/tmp/flash.log" &&
[ -n "$u" ] && [ -n "$m" ] && [ "$u" -lt "$m" ] && rebooted; then
ok "split layout, handed off: the overlay is mounted read-only and the settings carried"
else
bad "split layout handed off must carry the settings, len='$(blob_len 2 "$OVL" 0x50000)' log='$(cat "$SB/tmp/flash.log")' out='$OUT'"
fi

# The overlay cannot be read: refused before the write, not upgraded to defaults.
split_handed_off
STUB_JFFS2_RO_FAIL=1 run
if printf '%s' "$OUT" | grep -q "Could not read the settings" &&
[ "$(xxd -p -l 4 "$SB/dev/mtdblock2")" = 00000000 ] && ! printf '%s' "$OUT" | grep -q "Firmware updated"; then
ok "split layout, handed off: an overlay that will not mount stops the run, nothing written"
else
bad "split layout handed off, unreadable overlay must refuse, rc=$RC out='$OUT'"
fi

# The copy is made but the partition will not let go: refused before the write.
split_handed_off
STUB_OVL_UMOUNT_FAIL=1 run
if printf '%s' "$OUT" | grep -q "Could not release the settings partition" &&
[ "$(xxd -p -l 4 "$SB/dev/mtdblock2")" = 00000000 ] && ! printf '%s' "$OUT" | grep -q "Firmware updated"; then
ok "split layout, handed off: a settings mount that will not unmount stops the run, nothing written"
else
bad "split layout handed off, stuck settings mount must refuse, rc=$RC out='$OUT'"
fi

# -n handed off: nothing to carry, nothing mounted.
split_handed_off
RUN_ENV="$RUN_ENV clear_overlay=1"
run
if [ "$(blob_len 2 "$OVL" 0x50000)" = 000000000000 ] && ! grep -q "mount jffs2" "$SB/tmp/flash.log"; then
ok "split layout, handed off, -n: an empty blob, the overlay left unmounted"
else
bad "split layout handed off -n, len='$(blob_len 2 "$OVL" 0x50000)' out='$OUT'"
fi

# The first phase records that there are settings, for the RAM phase to look for.
split_env split
STUB_PIVOT_RC=0
run -z --archive="$SB/tmp/fw.tgz"
if grep -q "^kill -QUIT 1" "$SB/tmp/flash.log" &&
grep -q "split_overlay_mounted=.1" "$SB/ram/sysupgrade.env" 2>/dev/null; then
ok "split layout: the hand-off carries that the overlay was mounted"
else
bad "split layout hand-off must record the mounted overlay, log='$(cat "$SB/tmp/flash.log")' env='$(grep overlay "$SB/ram/sysupgrade.env" 2>/dev/null)' out='$OUT'"
fi

# From fixed slots: the image runs on from the kernel slot into the rootfs one,
# and the settings land in the old rootfs, where the new rootfs_data starts.
split_env fixed
Expand Down
39 changes: 35 additions & 4 deletions general/overlay/usr/sbin/sysupgrade
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/bin/sh
# OpenIPC.org | 2025
scr_version=1.0.76
scr_version=1.0.77

args="$@"
LOCK_FILE=/tmp/sysupgrade.lock
Expand Down Expand Up @@ -341,6 +341,10 @@ check_combined_fits() {
[ $(($(nor_split_base) + $(stat -c %s "$x"))) -le "$ovl" ] ||
die "$x runs past the end of its squashfs ($(printf 0x%x "$ovl")): not a firmware.bin as the build packs it. Nothing was written."
blob=$(nor_split_blob_size)
# Whether there are settings to carry: the hand-off takes the overlay's
# mount away before the write (release_old_root), so the RAM phase cannot
# tell from /proc/mounts any more. See do_update_firmware_split.
[ -n "$(nor_split_overlay_mp)" ] && split_overlay_mounted=1
[ $((ovl + blob)) -le "$end" ] ||
die "$x and the settings do not fit the flash: the image ends at $(printf 0x%x "$ovl"), the settings need $((blob / 1024)) KB, the flash ends at $(printf 0x%x "$end"). Nothing was written; -n upgrades without the settings."
}
Expand Down Expand Up @@ -914,11 +918,16 @@ nor_split_url() {
fi
}

# Where the jffs2 overlay on rootfs_data is mounted, if it is.
nor_split_overlay_mp() {
awk -v d="$(get_device rootfs_data | sed 's|/dev/mtd|/dev/mtdblock|')" '$1 == d { print $2; exit }' /proc/mounts
}

# The settings blob this run will write, in bytes: the header, the gzipped tar
# of the overlay, whole 64 KiB blocks; one block for -n.
nor_split_blob_size() {
local mp n=0
mp=$(awk -v d="$(get_device rootfs_data | sed 's|/dev/mtd|/dev/mtdblock|')" '$1 == d { print $2; exit }' /proc/mounts)
mp=$(nor_split_overlay_mp)
if [ "1" != "$clear_overlay" ] && [ -n "$mp" ]; then
n=$(tar -C "$mp" -cf - . 2>&3 | gzip | wc -c)
fi
Expand All @@ -944,10 +953,32 @@ do_update_firmware_split() {
[ -n "$end" ] || die "The flash layout is neither the split one nor fixed slots this upgrade can turn into it. Nothing was written."
rm -f "$blob" "$tgz"
quiesce_overlay
mp=$(awk -v d="$(get_device rootfs_data | sed 's|/dev/mtd|/dev/mtdblock|')" '$1 == d { print $2; exit }' /proc/mounts)
mp=$(nor_split_overlay_mp)
# Handed off, the overlay is no longer mounted: release_old_root let go of
# everything behind /mnt, the overlay with it. Reading /proc/mounts alone
# then took the camera for one without settings and staged an empty blob,
# which the first boot honours by starting from defaults -- every NOR
# upgrade since the hand-off (#2648). Nothing holds rootfs_data any more,
# so mount it read-only here and copy the settings from that, as
# rewrite_ubifs does on UBI. Refusing costs a reboot with nothing written;
# going on would cost the settings.
if [ "1" != "$clear_overlay" ] && [ -z "$mp" ] && [ "1" = "$split_overlay_mounted" ]; then
mp=/tmp/overlay.old
mkdir -p "$mp" &&
mount -t jffs2 -o ro "$(get_device rootfs_data | sed 's|/dev/mtd|/dev/mtdblock|')" "$mp" 2>&3 ||
die "Could not read the settings to carry them over. Nothing was written; -n upgrades without them."
Comment thread
widgetii marked this conversation as resolved.
Resolved
overlay_mounted_here=1
fi
if [ "1" != "$clear_overlay" ] && [ -n "$mp" ]; then
tar -C "$mp" -cf - . 2>&3 | gzip > "$tgz" ||
die "Could not copy the settings into RAM. Nothing was written; -n upgrades without them."
# Read-only, but still a filesystem on the flash about to be
# rewritten: let go of it before the write, or do not write.
if [ "1" = "$overlay_mounted_here" ]; then
busybox umount "$mp" 2>&3 ||
die "Could not release the settings partition after copying it. Nothing was written."
rmdir "$mp" 2>&3
fi
else
# Length 0: the first boot erases the overlay and restores nothing.
: > "$tgz"
Expand Down Expand Up @@ -2584,7 +2615,7 @@ enter_ramfs() {
export live_flash_dirty root_on_flash flash_touched services_stopped
# remote_update: verify_rootfs branches on it for an unmountable rootfs.
# lock_owned: die() needs it to know the lock is ours to remove.
export remote_update lock_owned
export remote_update lock_owned split_overlay_mounted
# wdog_userspace_owned: watchdog_keep must not claim a device nobody was
# petting, and the scan behind that answer needs a /proc this pivot is about
# to move and a majestic it is about to leave behind /mnt.
Expand Down
Loading