Skip to content

Commit 2d45743

Browse files
authored
Merge pull request #19 from netbootxyz/fix/multi-layer-initrd-extraction
Fix multi-layer initrd extraction for modern distros
2 parents 00ffba5 + 7262fb8 commit 2d45743

File tree

2 files changed

+91
-58
lines changed

2 files changed

+91
-58
lines changed

Dockerfile

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,27 +7,28 @@ RUN \
77
echo "**** install deps ****" && \
88
apt-get update && \
99
apt-get install -y \
10-
cpio \
11-
curl \
10+
cpio \
11+
curl \
1212
file \
13-
jq \
13+
initramfs-tools-core \
14+
jq \
1415
libarchive-tools \
15-
liblz4-tool \
16-
p7zip-full \
17-
psmisc \
18-
transmission-cli \
16+
liblz4-tool \
17+
p7zip-full \
18+
psmisc \
19+
transmission-cli \
1920
xxd \
20-
xz-utils \
21-
zstd && \
21+
xz-utils \
22+
zstd && \
2223
echo "**** directories ****" && \
2324
mkdir -p \
24-
/buildout \
25-
/root/Downloads && \
25+
/buildout \
26+
/root/Downloads && \
2627
echo "**** clean up ****" && \
2728
rm -rf \
28-
/tmp/* \
29-
/var/lib/apt/lists/* \
30-
/var/tmp/*
29+
/tmp/* \
30+
/var/lib/apt/lists/* \
31+
/var/tmp/*
3132

3233
# add local files
3334
COPY /root /

root/build.sh

Lines changed: 76 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -83,56 +83,88 @@ rm *.iso
8383
echo "Extracting initrd..."
8484

8585
# initrd extraction
86-
if [[ "${EXTRACT_INITRD}" == "true" ]] && [[ "${INITRD_TYPE}" != "lz4" ]];then
86+
if [[ "${EXTRACT_INITRD}" == "true" ]];then
8787
INITRD_ORG=${INITRD_NAME}
88-
COUNTER=1
8988
cd /buildout
90-
while :
91-
do
92-
# strip microcode from initrd if it has it
93-
LAYERCOUNT=$(cat ${INITRD_NAME} | cpio -tdmv 2>&1 >/dev/null | wc -c)
94-
if [[ ${LAYERCOUNT} -lt 5000 ]] && [[ "${INITRD_TYPE}" != "uncomp" ]];then
95-
# This is a microcode cpio wrapper
96-
BLOCKCOUNT=$(cat ${INITRD_NAME} | cpio -tdmv 2>&1 >/dev/null | awk 'END{print $1}')
97-
dd if=${INITRD_NAME} of=${INITRD_NAME}${COUNTER} bs=512 skip=${BLOCKCOUNT}
98-
INITRD_NAME=${INITRD_NAME}${COUNTER}
89+
90+
# Try using unmkinitramfs first (handles multi-layer initrds properly)
91+
# Modern distros (Ubuntu, Debian, Clonezilla, etc.) use multi-layer initrds with:
92+
# - early: microcode
93+
# - early2: kernel modules/drivers
94+
# - main: actual initramfs
95+
if command -v unmkinitramfs >/dev/null 2>&1; then
96+
echo "Using unmkinitramfs for proper multi-layer extraction..."
97+
mkdir -p initrd_extracted
98+
if unmkinitramfs ${INITRD_NAME} initrd_extracted/ 2>/dev/null; then
99+
mkdir -p initrd_files
100+
# Merge all layers (early, early2, main, etc.) preserving drivers and modules
101+
for layer in initrd_extracted/*/; do
102+
if [ -d "$layer" ]; then
103+
echo "Merging layer: $(basename $layer)"
104+
rsync -a "$layer" initrd_files/
105+
fi
106+
done
107+
rm -rf initrd_extracted
108+
echo "Successfully extracted multi-layer initrd"
99109
else
100-
# this is a compressed archive
101-
mkdir initrd_files
102-
cd initrd_files
103-
# display file type
104-
file ../${INITRD_NAME}
105-
if [[ "${INITRD_TYPE}" == "xz" ]] || [[ "${INITRD_TYPE}" == "arch-xz" ]] ;then
106-
cat ../${INITRD_NAME} | xz -d | cpio -i -d
107-
elif [[ "${INITRD_TYPE}" == "zstd" ]];then
108-
cat ../${INITRD_NAME} | zstd -d | cpio -i -d
109-
elif [[ "${INITRD_TYPE}" == "gz" ]];then
110-
zcat ../${INITRD_NAME} | cpio -i -d
111-
elif [[ "${INITRD_TYPE}" == "uncomp" ]];then
112-
cat ../${INITRD_NAME} | cpio -i -d
113-
fi
114-
break
110+
echo "unmkinitramfs failed, falling back to manual extraction"
111+
EXTRACT_MANUALLY=true
115112
fi
116-
COUNTER=$((COUNTER+1))
117-
done
118-
elif [[ "${EXTRACT_INITRD}" == "true" ]] && [[ "${INITRD_TYPE}" == "lz4" ]];then
119-
INITRD_ORG=${INITRD_NAME}
120-
cd /buildout
121-
if [[ "${LZ4_SINGLE}" == "true" ]];then
122-
BLOCKCOUNT=$(cat ${INITRD_NAME} | cpio -tdmv 2>&1 >/dev/null | awk 'END{print $1}')
123-
dd if=${INITRD_NAME} of=${INITRD_NAME}1 bs=512 skip=${BLOCKCOUNT}
124-
INITRD_NAME=${INITRD_NAME}1
125113
else
126-
# lz4 extraction detection is a clusterfuck here we just assume we drill twice for gold
127-
for COUNTER in 1 2;do
128-
BLOCKCOUNT=$(cat ${INITRD_NAME} | cpio -tdmv 2>&1 >/dev/null | awk 'END{print $1}')
129-
dd if=${INITRD_NAME} of=${INITRD_NAME}${COUNTER} bs=512 skip=${BLOCKCOUNT}
130-
INITRD_NAME=${INITRD_NAME}${COUNTER}
131-
done
114+
echo "unmkinitramfs not available, using manual extraction"
115+
EXTRACT_MANUALLY=true
116+
fi
117+
118+
# Fallback: manual extraction for simple single-layer initrds or when unmkinitramfs fails
119+
if [[ "${EXTRACT_MANUALLY}" == "true" ]]; then
120+
if [[ "${INITRD_TYPE}" != "lz4" ]]; then
121+
COUNTER=1
122+
while :
123+
do
124+
# strip microcode from initrd if it has it
125+
LAYERCOUNT=$(cat ${INITRD_NAME} | cpio -tdmv 2>&1 >/dev/null | wc -c)
126+
if [[ ${LAYERCOUNT} -lt 5000 ]] && [[ "${INITRD_TYPE}" != "uncomp" ]];then
127+
# This is a microcode cpio wrapper
128+
BLOCKCOUNT=$(cat ${INITRD_NAME} | cpio -tdmv 2>&1 >/dev/null | awk 'END{print $1}')
129+
dd if=${INITRD_NAME} of=${INITRD_NAME}${COUNTER} bs=512 skip=${BLOCKCOUNT} 2>/dev/null
130+
INITRD_NAME=${INITRD_NAME}${COUNTER}
131+
else
132+
# this is a compressed archive
133+
mkdir -p initrd_files
134+
cd initrd_files
135+
# display file type
136+
file ../${INITRD_NAME}
137+
if [[ "${INITRD_TYPE}" == "xz" ]] || [[ "${INITRD_TYPE}" == "arch-xz" ]] ;then
138+
cat ../${INITRD_NAME} | xz -d | cpio -i -d
139+
elif [[ "${INITRD_TYPE}" == "zstd" ]];then
140+
cat ../${INITRD_NAME} | zstd -d | cpio -i -d
141+
elif [[ "${INITRD_TYPE}" == "gz" ]];then
142+
zcat ../${INITRD_NAME} | cpio -i -d
143+
elif [[ "${INITRD_TYPE}" == "uncomp" ]];then
144+
cat ../${INITRD_NAME} | cpio -i -d
145+
fi
146+
break
147+
fi
148+
COUNTER=$((COUNTER+1))
149+
done
150+
elif [[ "${INITRD_TYPE}" == "lz4" ]]; then
151+
if [[ "${LZ4_SINGLE}" == "true" ]];then
152+
BLOCKCOUNT=$(cat ${INITRD_NAME} | cpio -tdmv 2>&1 >/dev/null | awk 'END{print $1}')
153+
dd if=${INITRD_NAME} of=${INITRD_NAME}1 bs=512 skip=${BLOCKCOUNT} 2>/dev/null
154+
INITRD_NAME=${INITRD_NAME}1
155+
else
156+
# lz4 extraction detection is a clusterfuck here we just assume we drill twice for gold
157+
for COUNTER in 1 2;do
158+
BLOCKCOUNT=$(cat ${INITRD_NAME} | cpio -tdmv 2>&1 >/dev/null | awk 'END{print $1}')
159+
dd if=${INITRD_NAME} of=${INITRD_NAME}${COUNTER} bs=512 skip=${BLOCKCOUNT} 2>/dev/null
160+
INITRD_NAME=${INITRD_NAME}${COUNTER}
161+
done
162+
fi
163+
mkdir -p initrd_files
164+
cd initrd_files
165+
cat ../${INITRD_NAME} | lz4 -d - | cpio -i -d
166+
fi
132167
fi
133-
mkdir initrd_files
134-
cd initrd_files
135-
cat ../${INITRD_NAME} | lz4 -d - | cpio -i -d
136168
fi
137169

138170
exit 0

0 commit comments

Comments
 (0)