7
7
# This will create one or more out-dir/rootfs-N directories that contain the contents of the initramfs.
8
8
9
9
set -euo pipefail
10
- # check for unzstd. Will abort the script with an error message if the tool is not present.
11
- unzstd -V > /dev/null
10
+
11
+ # check for xzcat. Will abort the script with an error message if the tool is not present.
12
+ xzcat -V > /dev/null
13
+
12
14
fail () {
13
15
echo " ${* } " >&2
14
16
exit 1
15
17
}
16
18
17
- # Stolen from extract-vmlinux and modified.
18
- try_decompress () {
19
- local header=" ${1} "
20
- local no_idea=" ${2} "
21
- local tool=" ${3} "
22
- local image=" ${4} "
23
- local tmp=" ${5} "
24
- local output_basename=" ${6} "
25
-
26
- local pos
27
- local tool_filename=$( echo " ${tool} " | cut -f1 -d' ' )
28
- # The obscure use of the "tr" filter is to work around older versions of
29
- # "grep" that report the byte offset of the line instead of the pattern.
19
+ find_xz_headers () {
20
+ grep --fixed-strings --text --byte-offset --only-matching $' \xFD\x37\x7A\x58\x5A\x00 ' " $1 " | cut -d: -f1
21
+ }
30
22
31
- # Try to find the header and decompress from here.
32
- for pos in $( tr " ${header} \n${no_idea} " " \n${no_idea} =" < " ${image} " |
33
- grep --text --byte-offset --only-matching " ^${no_idea} " )
34
- do
35
- pos=${pos%%:* }
36
- # Disable error handling, because we will be potentially
37
- # giving the tool garbage or a valid archive with some garbage
38
- # appended to it. So let the tool extract the valid archive
39
- # and then complain about the garbage at the end, but don't
40
- # fail the script because of it.
41
- set +e; tail " -c+${pos} " " ${image} " | " ${tool} " > " ${tmp} /out" 2> /dev/null; set -e;
42
- if [ -s " ${tmp} /out" ]; then
43
- mv " ${tmp} /out" " ${output_basename} -${tool_filename} -at-${pos} "
44
- else
45
- rm -f " ${tmp} /out"
46
- fi
47
- done
23
+ decompress_at () {
24
+ # Data may not really be a valid xz, so allow for errors.
25
+ tail " -c+$(( ${2%:* } + 1 )) " " $1 " | xzcat 2> /dev/null || true
48
26
}
49
27
50
- try_unzstd_decompress () {
51
- local image=" ${1} "
52
- local tmp=" ${2} "
53
- local output_basename=" ${3} "
54
- try_decompress ' (\265/\375' xxx unzstd " ${image} " " ${tmp} " " ${output_basename} "
28
+ try_extract () {
29
+ # cpio can do strange things when given garbage, so do a basic check.
30
+ [[ $( head -c6 " $1 " ) == 070701 ]] || return 0
31
+
32
+ # There may be multiple concatenated archives so try cpio till it fails.
33
+ while cpio --quiet --extract --make-directories --directory=" ${out} /rootfs-${ROOTFS_IDX} " --nonmatching ' dev/*' 2> /dev/null; do
34
+ ROOTFS_IDX=$(( ROOTFS_IDX + 1 ))
35
+ done < " $1 "
36
+
37
+ # Last cpio attempt may or may not leave an empty directory.
38
+ rmdir " ${out} /rootfs-${ROOTFS_IDX} " 2> /dev/null || ROOTFS_IDX=$(( ROOTFS_IDX + 1 ))
55
39
}
56
40
57
41
me=" ${0##*/ } "
@@ -65,37 +49,22 @@ if [[ ! -s "${image}" ]]; then
65
49
fi
66
50
mkdir -p " ${out} "
67
51
68
- tmp=$( mktemp --directory /tmp/eifv-XXXXXX)
69
- trap " rm -rf ${tmp} " EXIT
52
+ tmp=$( mktemp --directory eifv-XXXXXX)
53
+ trap ' rm -rf -- "${tmp}"' EXIT
54
+ ROOTFS_IDX=0
70
55
71
- tmp_dec=" ${tmp} /decompress"
72
- mkdir " ${tmp_dec} "
73
- fr_prefix=" ${tmp} /first-round"
56
+ # arm64 kernels are not compressed, so try decompressing once.
57
+ # Other kernels are compressed, so also try decompressing twice.
58
+ for OFF1 in $( find_xz_headers " ${image} " )
59
+ do
60
+ decompress_at " ${image} " " ${OFF1} " > " ${tmp} /initrd.maybe_cpio_or_elf"
61
+ try_extract " ${tmp} /initrd.maybe_cpio_or_elf"
74
62
75
- ROOTFS_IDX=0
76
- perform_round () {
77
- local image=" ${1} "
78
- local tmp_dec=" ${2} "
79
- local round_prefix=" ${3} "
80
- try_unzstd_decompress " ${image} " " ${tmp_dec} " " ${round_prefix} "
81
- for rnd in " ${round_prefix} " * ; do
82
- if [[ $( file --brief " ${rnd} " ) =~ ' cpio archive' ]]; then
83
- mkdir -p " ${out} /rootfs-${ROOTFS_IDX} "
84
- # On Linux 6.10, the first rootfs is an extra ghost rootfs of 336K, that has a corrupted CPIO
85
- cpio --quiet --extract --make-directories --directory=" ${out} /rootfs-${ROOTFS_IDX} " --nonmatching ' dev/*' < $rnd || true
86
- ROOTFS_IDX=$(( ROOTFS_IDX + 1 ))
87
- fi
63
+ for OFF2 in $( find_xz_headers " ${tmp} /initrd.maybe_cpio_or_elf" )
64
+ do
65
+ decompress_at " ${tmp} /initrd.maybe_cpio_or_elf" " ${OFF2} " > " ${tmp} /initrd.maybe_cpio"
66
+ try_extract " ${tmp} /initrd.maybe_cpio"
88
67
done
89
- }
90
-
91
- shopt -s nullglob
92
- perform_round " ${image} " " ${tmp_dec} " " ${fr_prefix} "
93
- for fr in " ${fr_prefix} " * ; do
94
- fr_files=" ${fr} -files"
95
- fr_dec=" ${fr_files} /decompress"
96
- mkdir -p " ${fr_dec} "
97
- sr_prefix=" ${fr_files} /second-round"
98
- perform_round " ${fr} " " ${fr_dec} " " ${sr_prefix} "
99
68
done
100
69
101
70
if [[ ${ROOTFS_IDX} -eq 0 ]]; then
0 commit comments