mirror of
https://github.com/openglow-org/forgefirm.git
synced 2026-09-27 16:51:12 -07:00
install: the factory archive is written aside and verified before it is trusted
The archive was written straight to its final name and a rerun accepted any non-empty file as complete, so a run interrupted mid-archive left a truncated image that the next run kept and then overwrote the slot. The archive is now written as .part and renamed on success; an existing archive counts only with its manifest line present and a whole gzip stream, otherwise it is archived again.
This commit is contained in:
@@ -50,25 +50,46 @@ stop_gf_services () {
|
|||||||
# archive_dev <src-device> <out.img.gz>: dd|gzip with a live progress
|
# archive_dev <src-device> <out.img.gz>: dd|gzip with a live progress
|
||||||
# line (compressed MB so far - old busybox dd has no status=progress).
|
# line (compressed MB so far - old busybox dd has no status=progress).
|
||||||
# dd's exit status is captured via a file so a read failure is not
|
# dd's exit status is captured via a file so a read failure is not
|
||||||
# masked by gzip succeeding on truncated input.
|
# masked by gzip succeeding on truncated input. The archive is written
|
||||||
|
# as <out>.part and renamed only when both ends succeeded: a run that
|
||||||
|
# dies mid-archive (power, a dropped SSH session) leaves nothing under
|
||||||
|
# the final name for a rerun to mistake for a complete archive.
|
||||||
archive_dev () {
|
archive_dev () {
|
||||||
RC_FILE=$(mktemp /tmp/ffinstall.rc.XXXXXX) || return 1
|
RC_FILE=$(mktemp /tmp/ffinstall.rc.XXXXXX) || return 1
|
||||||
rm -f "$RC_FILE"
|
rm -f "$RC_FILE"
|
||||||
( dd if="$1" bs=1M 2>/dev/null; echo $? > "$RC_FILE" ) | gzip -1 > "$2" &
|
PART="$2.part"
|
||||||
|
rm -f "$PART"
|
||||||
|
( dd if="$1" bs=1M 2>/dev/null; echo $? > "$RC_FILE" ) | gzip -1 > "$PART" &
|
||||||
GZPID=$!
|
GZPID=$!
|
||||||
while kill -0 "$GZPID" 2>/dev/null; do
|
while kill -0 "$GZPID" 2>/dev/null; do
|
||||||
sleep 3
|
sleep 3
|
||||||
SZ=$(wc -c < "$2" 2>/dev/null)
|
SZ=$(wc -c < "$PART" 2>/dev/null)
|
||||||
printf '\r %s MB compressed...' "$((${SZ:-0} / 1048576))"
|
printf '\r %s MB compressed...' "$((${SZ:-0} / 1048576))"
|
||||||
done
|
done
|
||||||
wait "$GZPID"
|
wait "$GZPID"
|
||||||
GZRC=$?
|
GZRC=$?
|
||||||
DDRC=$(cat "$RC_FILE" 2>/dev/null)
|
DDRC=$(cat "$RC_FILE" 2>/dev/null)
|
||||||
rm -f "$RC_FILE"
|
rm -f "$RC_FILE"
|
||||||
printf '\r %s MB compressed. \n' "$(($(wc -c < "$2") / 1048576))"
|
printf '\r %s MB compressed. \n' "$(($(wc -c < "$PART") / 1048576))"
|
||||||
[ "$GZRC" = "0" ] && [ "$DDRC" = "0" ]
|
if [ "$GZRC" = "0" ] && [ "$DDRC" = "0" ]; then
|
||||||
|
mv "$PART" "$2"
|
||||||
|
else
|
||||||
|
rm -f "$PART"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# archived_ok <out.img.gz>: an existing archive counts only when the
|
||||||
|
# manifest records it and the gzip stream is whole. Anything else (a file
|
||||||
|
# left by an older installer's interrupted run, a manifest line that
|
||||||
|
# never got written) is archived again.
|
||||||
|
archived_ok () {
|
||||||
|
[ -s "$1" ] || return 1
|
||||||
|
grep -q " $(basename "$1") md5=" "$ARCHIVE_DIR/manifest" 2>/dev/null || return 1
|
||||||
|
gzip -t "$1" 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
# slot_probe <1|2>: sets S_TYPE (factory|forgefirm|empty|unknown),
|
# slot_probe <1|2>: sets S_TYPE (factory|forgefirm|empty|unknown),
|
||||||
# S_VER (the build datetime, used for archive naming), and S_FWVER (the
|
# S_VER (the build datetime, used for archive naming), and S_FWVER (the
|
||||||
# semantic FIRMWARE_VERSION, for display; factory only). The active slot
|
# semantic FIRMWARE_VERSION, for display; factory only). The active slot
|
||||||
@@ -245,10 +266,11 @@ for N in 1 2; do
|
|||||||
slot_probe $N
|
slot_probe $N
|
||||||
[ "$S_TYPE" = "factory" ] || continue
|
[ "$S_TYPE" = "factory" ] || continue
|
||||||
ARC="$ARCHIVE_DIR/factory-rootfs-$S_VER.img.gz"
|
ARC="$ARCHIVE_DIR/factory-rootfs-$S_VER.img.gz"
|
||||||
if [ -s "$ARC" ]; then
|
if archived_ok "$ARC"; then
|
||||||
echo -e "${ASTERISK}Slot $N (factory $S_VER) already archived."
|
echo -e "${ASTERISK}Slot $N (factory $S_VER) already archived."
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
|
[ -e "$ARC" ] && echo -e "${ASTERISK}Slot $N: the archive on disk is incomplete; archiving again."
|
||||||
echo -e "${ASTERISK}Archiving slot $N ($(slot_desc)) - takes a few minutes:"
|
echo -e "${ASTERISK}Archiving slot $N ($(slot_desc)) - takes a few minutes:"
|
||||||
archive_dev /dev/mmcblk2p$N "$ARC" \
|
archive_dev /dev/mmcblk2p$N "$ARC" \
|
||||||
|| { rm -f "$ARC"; die "archiving slot $N failed"; }
|
|| { rm -f "$ARC"; die "archiving slot $N failed"; }
|
||||||
@@ -256,7 +278,7 @@ for N in 1 2; do
|
|||||||
done
|
done
|
||||||
for B in 0 1; do
|
for B in 0 1; do
|
||||||
ARC="$ARCHIVE_DIR/recovery-boot$B.img.gz"
|
ARC="$ARCHIVE_DIR/recovery-boot$B.img.gz"
|
||||||
[ -s "$ARC" ] && continue
|
archived_ok "$ARC" && continue
|
||||||
echo -e "${ASTERISK}Archiving recovery boot$B:"
|
echo -e "${ASTERISK}Archiving recovery boot$B:"
|
||||||
archive_dev /dev/mmcblk2boot$B "$ARC" \
|
archive_dev /dev/mmcblk2boot$B "$ARC" \
|
||||||
|| { rm -f "$ARC"; die "archiving boot$B failed"; }
|
|| { rm -f "$ARC"; die "archiving boot$B failed"; }
|
||||||
|
|||||||
Reference in New Issue
Block a user