diff --git a/initrd/bin/unpack_initramfs.sh b/initrd/bin/unpack_initramfs.sh index db176fd6..12ce32b8 100755 --- a/initrd/bin/unpack_initramfs.sh +++ b/initrd/bin/unpack_initramfs.sh @@ -31,78 +31,81 @@ CPIO_ARGS=("$@") # Consume zero bytes, the first nonzero byte read (if any) is repeated on stdout consume_zeros() { - TRACE_FUNC - next_byte='00' - while [ "$next_byte" = "00" ]; do - # 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 ' ')" - done - # if we finished due to nonzero byte (not EOF), then carry that byte - if [ -n "$next_byte" ]; then - echo -n "$next_byte" | xxd -p -r - fi + TRACE_FUNC + next_byte='00' + while [ "$next_byte" = "00" ]; do + # 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 ' ')" + done + # if we finished due to nonzero byte (not EOF), then carry that byte + if [ -n "$next_byte" ]; then + echo -n "$next_byte" | xxd -p -r + fi } unpack_cpio() { - TRACE_FUNC - (cd "$dest_dir"; cpio -i "${CPIO_ARGS[@]}" 2>/dev/null) + TRACE_FUNC + ( + 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_first_segment() { - TRACE_FUNC - unpack_archive="$1" - dest_dir="$2" - rest_archive="$3" + TRACE_FUNC + unpack_archive="$1" + dest_dir="$2" + 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 - magic="$(dd if="$unpack_archive" bs=6 count=1 status=none | xxd -p)" + # 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)" - # 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 - # lib/decompress.c (gzip) - case "$magic" in - 00*) - DEBUG "archive segment $magic: uncompressed cpio" - # Skip zero bytes and copy the first nonzero byte - consume_zeros - # Copy the remaining data - cat - ;; - 303730373031*|303730373032*) # plain cpio - DEBUG "archive segment $magic: plain cpio" - # Unpack the plain cpio, this stops reading after the trailer - unpack_cpio - # Copy the remaining data - cat - ;; - 1f8b*|1f9e*) # gzip - DEBUG "archive segment $magic: gzip" - # gunzip won't stop when reaching the end of the gzipped member, - # so we can't read another segment after this. We can't - # reasonably determine the member length either, this requires - # walking all the compressed blocks. - gunzip | unpack_cpio - ;; - 28b5*) # zstd - DEBUG "archive segment $magic: zstd" - # Like gunzip, this will not stop when reaching the end of the - # frame, and determining the frame length requires walking all - # of its blocks. - (zstd-decompress -d || true) | unpack_cpio - ;; - *) # unknown - die "Can't decompress initramfs archive, unknown type: $magic" - ;; - esac - ) <"$unpack_archive" >"$rest_archive" + # 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 + # lib/decompress.c (gzip) + case "$magic" in + 00*) + DEBUG "archive segment $magic: uncompressed cpio" + # Skip zero bytes and copy the first nonzero byte + consume_zeros + # Copy the remaining data + cat + ;; + 303730373031* | 303730373032*) # plain cpio + DEBUG "archive segment $magic: plain cpio" + # Unpack the plain cpio, this stops reading after the trailer + unpack_cpio + # Copy the remaining data + cat + ;; + 1f8b* | 1f9e*) # gzip + DEBUG "archive segment $magic: gzip" + # gunzip won't stop when reaching the end of the gzipped member, + # so we can't read another segment after this. We can't + # reasonably determine the member length either, this requires + # walking all the compressed blocks. + gunzip | unpack_cpio + ;; + 28b5*) # zstd + DEBUG "archive segment $magic: zstd" + # Like gunzip, this will not stop when reaching the end of the + # frame, and determining the frame length requires walking all + # of its blocks. + (zstd-decompress -d || true) | unpack_cpio + ;; + *) # unknown + die "Can't decompress initramfs archive, unknown type: $magic" + ;; + esac + ) <"$unpack_archive" >"$rest_archive" - orig_size="$(stat -c %s "$unpack_archive")" - rest_size="$(stat -c %s "$rest_archive")" - DEBUG "archive segment $magic: $((orig_size - rest_size)) bytes" + orig_size="$(stat -c %s "$unpack_archive")" + rest_size="$(stat -c %s "$rest_archive")" + DEBUG "archive segment $magic: $((orig_size - rest_size)) bytes" } DEBUG "Unpacking $INITRAMFS_ARCHIVE to $DEST_DIR" @@ -112,7 +115,7 @@ rest_archive="/tmp/unpack_initramfs_rest" # Break when there is no remaining data while [ -s "$next_archive" ]; do - unpack_first_segment "$next_archive" "$DEST_DIR" "$rest_archive" - next_archive="/tmp/unpack_initramfs_next" - mv "$rest_archive" "$next_archive" + unpack_first_segment "$next_archive" "$DEST_DIR" "$rest_archive" + next_archive="/tmp/unpack_initramfs_next" + mv "$rest_archive" "$next_archive" done