Merge pull request #1860 from tlaurion/fix_initrd_unpack_for_repacking

initrd/bin/unpack_initramfs.sh: add xz unpacking support.
This commit is contained in:
Thierry Laurion 2024-11-22 17:50:23 -05:00 committed by GitHub
commit 45696a4c8a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -31,78 +31,105 @@ CPIO_ARGS=("$@")
# Consume zero bytes, the first nonzero byte read (if any) is repeated on stdout # Consume zero bytes, the first nonzero byte read (if any) is repeated on stdout
consume_zeros() { consume_zeros() {
TRACE_FUNC TRACE_FUNC
next_byte='00' next_byte='00'
while [ "$next_byte" = "00" ]; do while [ "$next_byte" = "00" ]; do
# if we reach EOF, next_byte becomes empty (dd does not fail) # if we reach EOF, next_byte becomes empty (dd does not fail)
next_byte="$(dd bs=1 count=1 status=none | xxd -p | tr -d ' ')" next_byte="$(dd bs=1 count=1 status=none | xxd -p | tr -d ' ')"
done done
# if we finished due to nonzero byte (not EOF), then carry that byte # if we finished due to nonzero byte (not EOF), then carry that byte
if [ -n "$next_byte" ]; then if [ -n "$next_byte" ]; then
echo -n "$next_byte" | xxd -p -r echo -n "$next_byte" | xxd -p -r
fi fi
} }
unpack_cpio() { unpack_cpio() {
TRACE_FUNC TRACE_FUNC
(cd "$dest_dir"; cpio -i "${CPIO_ARGS[@]}" 2>/dev/null) (
cd "$dest_dir"
cpio -i "${CPIO_ARGS[@]}" 2>/dev/null
)
} }
# unpack the first segment of an archive, then write the rest to another file # unpack the first segment of an archive, then write the rest to another file
unpack_first_segment() { unpack_first_segment() {
TRACE_FUNC TRACE_FUNC
unpack_archive="$1" unpack_archive="$1"
dest_dir="$2" dest_dir="$2"
rest_archive="$3" rest_archive="$3"
mkdir -p "$dest_dir" mkdir -p "$dest_dir"
# peek the beginning of the file to determine what type of content is next # peek the beginning of the file to determine what type of content is next
magic="$(dd if="$unpack_archive" bs=6 count=1 status=none | xxd -p)" magic="$(dd if="$unpack_archive" bs=6 count=1 status=none | xxd -p)"
# read this segment of the archive, then write the rest to the next file # read this segment of the archive, then write the rest to the next file
( (
# Magic values correspond to Linux init/initramfs.c (zero, cpio) and # Magic values correspond to Linux init/initramfs.c (zero, cpio) and
# lib/decompress.c (gzip) # lib/decompress.c (gzip)
case "$magic" in case "$magic" in
00*) 00*)
DEBUG "archive segment $magic: uncompressed cpio" DEBUG "archive segment $magic: uncompressed cpio"
# Skip zero bytes and copy the first nonzero byte # Skip zero bytes and copy the first nonzero byte
consume_zeros consume_zeros
# Copy the remaining data # Copy the remaining data
cat cat
;; ;;
303730373031*|303730373032*) # plain cpio 303730373031* | 303730373032*) # plain cpio
DEBUG "archive segment $magic: plain cpio" DEBUG "archive segment $magic: plain cpio"
# Unpack the plain cpio, this stops reading after the trailer # Unpack the plain cpio, this stops reading after the trailer
unpack_cpio unpack_cpio
# Copy the remaining data # Copy the remaining data
cat cat
;; ;;
1f8b*|1f9e*) # gzip 1f8b* | 1f9e*) # gzip
DEBUG "archive segment $magic: gzip" DEBUG "archive segment $magic: gzip"
# gunzip won't stop when reaching the end of the gzipped member, # gunzip won't stop when reaching the end of the gzipped member,
# so we can't read another segment after this. We can't # so we can't read another segment after this. We can't
# reasonably determine the member length either, this requires # reasonably determine the member length either, this requires
# walking all the compressed blocks. # walking all the compressed blocks.
gunzip | unpack_cpio gunzip | unpack_cpio
;; ;;
28b5*) # zstd fd37*) # xz
DEBUG "archive segment $magic: zstd" DEBUG "archive segment $magic: xz"
# Like gunzip, this will not stop when reaching the end of the unxz | unpack_cpio
# frame, and determining the frame length requires walking all ;;
# of its blocks. 28b5*) # zstd
(zstd-decompress -d || true) | unpack_cpio DEBUG "archive segment $magic: zstd"
;; # Like gunzip, this will not stop when reaching the end of the
*) # unknown # frame, and determining the frame length requires walking all
die "Can't decompress initramfs archive, unknown type: $magic" # of its blocks.
;; (zstd-decompress -d || true) | unpack_cpio
esac ;;
) <"$unpack_archive" >"$rest_archive" *) # unknown
die "Can't decompress initramfs archive, unknown type: $magic"
# The following are magic values for other compression formats
# but not added because not tested.
# TODO: open an issue for unsupported magic number reported on die.
#
#425a*) # bzip2
# DEBUG "archive segment $magic: bzip2"
# bunzip2 | unpack_cpio
#;;
#5d00*) # lzma
# DEBUG "archive segment $magic: lzma"
# unlzma | unpack_cpio
#;;
#894c*) # lzo
# DEBUG "archive segment $magic: lzo"
# lzop -d | unpack_cpio
#;;
#0221*) # lz4
# DEBUG "archive segment $magic: lz4"
# lz4 -d | unpack_cpio
# ;;
;;
esac
) <"$unpack_archive" >"$rest_archive"
orig_size="$(stat -c %s "$unpack_archive")" orig_size="$(stat -c %s "$unpack_archive")"
rest_size="$(stat -c %s "$rest_archive")" rest_size="$(stat -c %s "$rest_archive")"
DEBUG "archive segment $magic: $((orig_size - rest_size)) bytes" DEBUG "archive segment $magic: $((orig_size - rest_size)) bytes"
} }
DEBUG "Unpacking $INITRAMFS_ARCHIVE to $DEST_DIR" DEBUG "Unpacking $INITRAMFS_ARCHIVE to $DEST_DIR"
@ -112,7 +139,7 @@ rest_archive="/tmp/unpack_initramfs_rest"
# Break when there is no remaining data # Break when there is no remaining data
while [ -s "$next_archive" ]; do while [ -s "$next_archive" ]; do
unpack_first_segment "$next_archive" "$DEST_DIR" "$rest_archive" unpack_first_segment "$next_archive" "$DEST_DIR" "$rest_archive"
next_archive="/tmp/unpack_initramfs_next" next_archive="/tmp/unpack_initramfs_next"
mv "$rest_archive" "$next_archive" mv "$rest_archive" "$next_archive"
done done