Skip to content

Commit 45696a4

Browse files
authored
Merge pull request #1860 from tlaurion/fix_initrd_unpack_for_repacking
initrd/bin/unpack_initramfs.sh: add xz unpacking support.
2 parents 573f48d + 95c6eb5 commit 45696a4

1 file changed

Lines changed: 91 additions & 64 deletions

File tree

initrd/bin/unpack_initramfs.sh

Lines changed: 91 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -31,78 +31,105 @@ CPIO_ARGS=("$@")
3131

3232
# Consume zero bytes, the first nonzero byte read (if any) is repeated on stdout
3333
consume_zeros() {
34-
TRACE_FUNC
35-
next_byte='00'
36-
while [ "$next_byte" = "00" ]; do
37-
# if we reach EOF, next_byte becomes empty (dd does not fail)
38-
next_byte="$(dd bs=1 count=1 status=none | xxd -p | tr -d ' ')"
39-
done
40-
# if we finished due to nonzero byte (not EOF), then carry that byte
41-
if [ -n "$next_byte" ]; then
42-
echo -n "$next_byte" | xxd -p -r
43-
fi
34+
TRACE_FUNC
35+
next_byte='00'
36+
while [ "$next_byte" = "00" ]; do
37+
# if we reach EOF, next_byte becomes empty (dd does not fail)
38+
next_byte="$(dd bs=1 count=1 status=none | xxd -p | tr -d ' ')"
39+
done
40+
# if we finished due to nonzero byte (not EOF), then carry that byte
41+
if [ -n "$next_byte" ]; then
42+
echo -n "$next_byte" | xxd -p -r
43+
fi
4444
}
4545

4646
unpack_cpio() {
47-
TRACE_FUNC
48-
(cd "$dest_dir"; cpio -i "${CPIO_ARGS[@]}" 2>/dev/null)
47+
TRACE_FUNC
48+
(
49+
cd "$dest_dir"
50+
cpio -i "${CPIO_ARGS[@]}" 2>/dev/null
51+
)
4952
}
5053

5154
# unpack the first segment of an archive, then write the rest to another file
5255
unpack_first_segment() {
53-
TRACE_FUNC
54-
unpack_archive="$1"
55-
dest_dir="$2"
56-
rest_archive="$3"
56+
TRACE_FUNC
57+
unpack_archive="$1"
58+
dest_dir="$2"
59+
rest_archive="$3"
5760

58-
mkdir -p "$dest_dir"
61+
mkdir -p "$dest_dir"
5962

60-
# peek the beginning of the file to determine what type of content is next
61-
magic="$(dd if="$unpack_archive" bs=6 count=1 status=none | xxd -p)"
63+
# peek the beginning of the file to determine what type of content is next
64+
magic="$(dd if="$unpack_archive" bs=6 count=1 status=none | xxd -p)"
6265

63-
# read this segment of the archive, then write the rest to the next file
64-
(
65-
# Magic values correspond to Linux init/initramfs.c (zero, cpio) and
66-
# lib/decompress.c (gzip)
67-
case "$magic" in
68-
00*)
69-
DEBUG "archive segment $magic: uncompressed cpio"
70-
# Skip zero bytes and copy the first nonzero byte
71-
consume_zeros
72-
# Copy the remaining data
73-
cat
74-
;;
75-
303730373031*|303730373032*) # plain cpio
76-
DEBUG "archive segment $magic: plain cpio"
77-
# Unpack the plain cpio, this stops reading after the trailer
78-
unpack_cpio
79-
# Copy the remaining data
80-
cat
81-
;;
82-
1f8b*|1f9e*) # gzip
83-
DEBUG "archive segment $magic: gzip"
84-
# gunzip won't stop when reaching the end of the gzipped member,
85-
# so we can't read another segment after this. We can't
86-
# reasonably determine the member length either, this requires
87-
# walking all the compressed blocks.
88-
gunzip | unpack_cpio
89-
;;
90-
28b5*) # zstd
91-
DEBUG "archive segment $magic: zstd"
92-
# Like gunzip, this will not stop when reaching the end of the
93-
# frame, and determining the frame length requires walking all
94-
# of its blocks.
95-
(zstd-decompress -d || true) | unpack_cpio
96-
;;
97-
*) # unknown
98-
die "Can't decompress initramfs archive, unknown type: $magic"
99-
;;
100-
esac
101-
) <"$unpack_archive" >"$rest_archive"
66+
# read this segment of the archive, then write the rest to the next file
67+
(
68+
# Magic values correspond to Linux init/initramfs.c (zero, cpio) and
69+
# lib/decompress.c (gzip)
70+
case "$magic" in
71+
00*)
72+
DEBUG "archive segment $magic: uncompressed cpio"
73+
# Skip zero bytes and copy the first nonzero byte
74+
consume_zeros
75+
# Copy the remaining data
76+
cat
77+
;;
78+
303730373031* | 303730373032*) # plain cpio
79+
DEBUG "archive segment $magic: plain cpio"
80+
# Unpack the plain cpio, this stops reading after the trailer
81+
unpack_cpio
82+
# Copy the remaining data
83+
cat
84+
;;
85+
1f8b* | 1f9e*) # gzip
86+
DEBUG "archive segment $magic: gzip"
87+
# gunzip won't stop when reaching the end of the gzipped member,
88+
# so we can't read another segment after this. We can't
89+
# reasonably determine the member length either, this requires
90+
# walking all the compressed blocks.
91+
gunzip | unpack_cpio
92+
;;
93+
fd37*) # xz
94+
DEBUG "archive segment $magic: xz"
95+
unxz | unpack_cpio
96+
;;
97+
28b5*) # zstd
98+
DEBUG "archive segment $magic: zstd"
99+
# Like gunzip, this will not stop when reaching the end of the
100+
# frame, and determining the frame length requires walking all
101+
# of its blocks.
102+
(zstd-decompress -d || true) | unpack_cpio
103+
;;
104+
*) # unknown
105+
die "Can't decompress initramfs archive, unknown type: $magic"
106+
# The following are magic values for other compression formats
107+
# but not added because not tested.
108+
# TODO: open an issue for unsupported magic number reported on die.
109+
#
110+
#425a*) # bzip2
111+
# DEBUG "archive segment $magic: bzip2"
112+
# bunzip2 | unpack_cpio
113+
#;;
114+
#5d00*) # lzma
115+
# DEBUG "archive segment $magic: lzma"
116+
# unlzma | unpack_cpio
117+
#;;
118+
#894c*) # lzo
119+
# DEBUG "archive segment $magic: lzo"
120+
# lzop -d | unpack_cpio
121+
#;;
122+
#0221*) # lz4
123+
# DEBUG "archive segment $magic: lz4"
124+
# lz4 -d | unpack_cpio
125+
# ;;
126+
;;
127+
esac
128+
) <"$unpack_archive" >"$rest_archive"
102129

103-
orig_size="$(stat -c %s "$unpack_archive")"
104-
rest_size="$(stat -c %s "$rest_archive")"
105-
DEBUG "archive segment $magic: $((orig_size - rest_size)) bytes"
130+
orig_size="$(stat -c %s "$unpack_archive")"
131+
rest_size="$(stat -c %s "$rest_archive")"
132+
DEBUG "archive segment $magic: $((orig_size - rest_size)) bytes"
106133
}
107134

108135
DEBUG "Unpacking $INITRAMFS_ARCHIVE to $DEST_DIR"
@@ -112,7 +139,7 @@ rest_archive="/tmp/unpack_initramfs_rest"
112139

113140
# Break when there is no remaining data
114141
while [ -s "$next_archive" ]; do
115-
unpack_first_segment "$next_archive" "$DEST_DIR" "$rest_archive"
116-
next_archive="/tmp/unpack_initramfs_next"
117-
mv "$rest_archive" "$next_archive"
142+
unpack_first_segment "$next_archive" "$DEST_DIR" "$rest_archive"
143+
next_archive="/tmp/unpack_initramfs_next"
144+
mv "$rest_archive" "$next_archive"
118145
done

0 commit comments

Comments
 (0)