ทำไม initrd ของฉันมีเพียงไดเรกทอรีเดียวนั่นคือ 'เคอร์เนล'


28

ฉันใช้ debian live-build เพื่อทำงานบนระบบที่สามารถบูตได้ ในตอนท้ายของกระบวนการฉันได้รับไฟล์ทั่วไปที่ใช้ในการบูตระบบจริง: ไฟล์ squashfs, โมดูล GRUB และไฟล์ config บางไฟล์และไฟล์ initrd.img

ฉันสามารถบู๊ตได้ดีโดยใช้ไฟล์เหล่านั้นส่งผ่าน initrd ไปยังเคอร์เนลผ่าน

initrd=/path/to/my/initrd.img

บนบรรทัดคำสั่ง bootloader แต่เมื่อฉันพยายามตรวจสอบเนื้อหาของภาพเริ่มต้นของฉันเช่น:

$file initrd.img
initrd.img: ASCII cpio archive (SVR4 with no CRC)
$mkdir initTree && cd initTree
$cpio -idv < ../initrd.img

ต้นไม้ไฟล์ฉันได้รับเช่นนี้:

$tree --charset=ASCII
.
`-- kernel
    `-- x86
        `-- microcode
            `-- GenuineIntel.bin

ทรีระบบไฟล์ที่แท้จริงมีที่ไหน / bin, / etc, / sbin ... ที่มีไฟล์จริงที่ใช้ในระหว่างการบูท?


1
คำสั่ง 'lsinitramfs' ถูกออกแบบมาสำหรับสิ่งนี้
earlgrey

คำตอบ:


31

วิธีการข้ามบล็อก cpio ที่ให้นั้นไม่สามารถทำงานได้อย่างน่าเชื่อถือ นั่นเป็นเพราะภาพเริ่มต้นที่ฉันได้รับตัวเองไม่ได้มีการจัดเก็บทั้งสองอย่างร่วมกันในขอบเขต 512 ไบต์

ให้ทำสิ่งนี้แทน:

apt-get install binwalk
legolas [mc]# binwalk initrd.img 
DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             ASCII cpio archive (SVR4 with no CRC), file name: "kernel", file name length: "0x00000007", file size: "0x00000000"
120           0x78            ASCII cpio archive (SVR4 with no CRC), file name: "kernel/x86", file name length: "0x0000000B", file size: "0x00000000"
244           0xF4            ASCII cpio archive (SVR4 with no CRC), file name: "kernel/x86/microcode", file name length: "0x00000015", file size: "0x00000000"
376           0x178           ASCII cpio archive (SVR4 with no CRC), file name: "kernel/x86/microcode/GenuineIntel.bin", file name length: "0x00000026", file size: "0x00005000"
21004         0x520C          ASCII cpio archive (SVR4 with no CRC), file name: "TRAILER!!!", file name length: "0x0000000B", file size: "0x00000000"
21136         0x5290          gzip compressed data, from Unix, last modified: Sat Feb 28 09:46:24 2015

ใช้หมายเลขสุดท้าย (21136) ซึ่งไม่ได้อยู่ในขอบเขต 512 ไบต์สำหรับฉัน:

legolas [mc]# dd if=initrd.img bs=21136 skip=1 | gunzip | cpio -tdv | head
drwxr-xr-x   1 root     root            0 Feb 28 09:46 .
drwxr-xr-x   1 root     root            0 Feb 28 09:46 bin
-rwxr-xr-x   1 root     root       554424 Dec 17  2011 bin/busybox
lrwxrwxrwx   1 root     root            7 Feb 28 09:46 bin/sh -> busybox
-rwxr-xr-x   1 root     root       111288 Sep 23  2011 bin/loadkeys
-rwxr-xr-x   1 root     root         2800 Aug 19  2013 bin/cat
-rwxr-xr-x   1 root     root          856 Aug 19  2013 bin/chroot
-rwxr-xr-x   1 root     root         5224 Aug 19  2013 bin/cpio
-rwxr-xr-x   1 root     root         3936 Aug 19  2013 bin/dd
-rwxr-xr-x   1 root     root          984 Aug 19  2013 bin/dmesg

แน่นอนคำตอบของคุณคือของฉัน ฉันไม่เคยคิดว่าการจัดตำแหน่งจะเป็นปัญหา ฉันสงสัยว่าถ้า cpio จะให้ผลลัพธ์ที่น่าสนใจมากกว่านี้หากภาพแรกที่อยู่ในไฟล์หลายภาพนั้นไม่ได้มีเส้น 512B
user986730

วิธีการย้อนกลับ (บรรจุหีบห่อกลับสู่สถานะดั้งเดิม) หลังจากแก้ไขด้วยลำดับชั้นโฟลเดอร์เดียวกัน
EdiD

2
เพียงแค่cdเข้าไปในไดเรกทอรีที่คุณสกัด cpio เก็บของวิ่งfind | cpio -H newc -o > /tmp/my_archive.cpioแล้ว gzip ด้วยgzip /tmp/my_archive.cpioและสุดท้าย concatenate cat my_microcode_image.cpio /tmp/my_archive.cpio.gz > mynewinitrd.imgกับที่มีภาพเฟิร์มแวถ้าคุณมีหนึ่ง: หากคุณไม่มีภาพไมโครโค้ดคุณสามารถใช้ไฟล์ gzipped ตามที่อยู่ใน bootloader ของคุณ
user986730

ในการอ่านคำตอบนี้ดูเหมือนว่าจะใช้ได้เฉพาะเมื่อเนื้อหา gzipped ผ่านไปครึ่งทางในไฟล์ มิฉะนั้นคุณควรเปลี่ยนขนาดบล็อกเป็น 1 และตั้งค่าข้ามเป็นจำนวนไบต์เป็นข้าม มีเหตุผลอะไรที่จะไม่ทำอย่างนั้นตลอด?
TamaMcGlinn

สองจริงเขียนไฟล์แทนเพียงรายชื่อบางส่วนของพวกเขาเปลี่ยนคำสั่งสุดท้ายในท่อมากกว่าcpio -i cpio -tdv | head
TamaMcGlinn

21

หากคุณรู้ว่าinitrd.imgประกอบด้วยไฟล์เก็บถาวร cpio ที่ไม่บีบอัดตามด้วยไฟล์บีบอัด cpio ที่บีบอัดด้วย gz คุณสามารถใช้รายการต่อไปนี้เพื่อแยกไฟล์ทั้งหมด (จากไฟล์เก็บถาวรทั้งสอง) ลงในไดเรกทอรีทำงานปัจจุบันของคุณ (ทดสอบใน bash):

(cpio -id; zcat | cpio -id) < /path/to/initrd.img

บรรทัดคำสั่งด้านบนส่งเนื้อหาของinitrd.imgเป็นอินพุตมาตรฐานไปยังเชลล์ย่อยซึ่งดำเนินการคำสั่งสองคำสั่งcpio -idและzcat | cpio -idเรียงตามลำดับ คำสั่งแรก ( cpio -id) สิ้นสุดลงเมื่อได้อ่านข้อมูลทั้งหมดที่เป็นของไฟล์เก็บถาวร cpio แรก เนื้อหาที่เหลือจะถูกส่งไปยังzcat | cpio -idซึ่งจะขยายและคลายการบีบอัดไฟล์ที่สอง


1
ลักษณะเช่นนี้ทางออกที่สะอาดโดยไกล
Velis

1
มันใช้งานได้อย่างสวยงาม
TurboHz

คำตอบที่ดีของ @ woolpool เป็นคำตอบเดียวที่ผู้ใช้โพสต์ไว้ นั่นเป็นสไตล์ หากคุณกำลังจะโพสต์คำตอบเพียงคำตอบเดียวตลอดอาชีพการงานของคุณทั้งหมดของ StackExchange คุณอาจทำได้ดีกว่าโพสต์เดียวเช่นนี้ OP อาจพิจารณาเปลี่ยนคำตอบที่ยอมรับให้เป็นคำตอบนี้
บาท

16

ปรากฎว่าตัวเริ่มต้นที่สร้างโดย live-build ของ Debian (และสำหรับความประหลาดใจของฉันที่เคอร์เนลยอมรับ) จริง ๆ แล้วเป็นการต่อภาพสองภาพ:

  • ที่เก็บถาวร CPIO ที่มีการอัปเดตไมโครโค้ดที่จะนำไปใช้กับโปรเซสเซอร์
  • ไฟล์เก็บถาวร gzip-ed cpio ซึ่งจริงๆแล้วมีต้นไม้ไฟล์ initrd (พร้อมกับไดเรกทอรี / etc / bin / sbin / dev ... ที่คาดว่าจะมี)

เมื่อดึง initrd.img ดั้งเดิมออกมาตรงๆจากผลลัพธ์ live-build ฉันได้รับผลลัพธ์นี้:

$cpio -idv ../initrd.img
kernel
kernel/x86
kernel/x86/microcode
kernel/x86/microcode/GenuineIntel.bin
896 blocks

ซึ่งหมายความว่าการสกัด cpio สิ้นสุดลงหลังจากแยกวิเคราะห์ 896 บล็อกแต่ละ 512 ไบต์ แต่ initrd.img ดั้งเดิมนั้นใหญ่กว่า 896 * 512 = 458752B = 448 KB:

$ls -liah initrd.img
3933924 -r--r--r-- 1 root root 21M Oct 21 10:05 initrd.img

ดังนั้นภาพเริ่มต้นที่แท้จริงที่ฉันกำลังมองหาจึงถูกผนวกเข้ากับไฟล์เก็บถาวร cpio แรก (ภาพที่มีการอัปเดตไมโครโค้ด) และสามารถเข้าถึงได้โดยใช้ dd:

$dd if=initrd.img of=myActualInitrdImage.img.gz bs=512 skip=896


1

จากความคิดที่ให้ไว้ในคำตอบของ @ woolpool ฉันได้เขียนฟังก์ชั่นวนซ้ำซึ่งจะทำงานกับไฟล์เก็บถาวร cpio ใด ๆ โดยไม่คำนึงถึงการจัดเรียงข้อมูลที่ต่อกันและไม่ต้องใช้เครื่องมือพิเศษใด ๆ เช่น binwalk ตัวอย่างเช่น mkinitramfs ของฉันสร้างไฟล์ cpio; cpio; gzip มันทำงานได้โดยการแยกแต่ละส่วนของไฟล์ initrd concatenated บันทึกส่วนที่เหลือลงใน tempfile แล้วใช้โปรแกรม "file" เพื่อตัดสินใจว่าจะทำอย่างไรกับส่วนถัดไป

uncpio(){
if [[ $(wc -c $1 | cut -d ' ' -f1) -eq 0 ]]; then
    return
fi

type=$(cat $1 | file -)
local tmpfile=$(date +%s.%N)
echo -e "\n$type"
if [[ $type =~ .*cpio.* ]]; then
    cat $1 | (cpio -id; cat >$tmpfile)
elif [[ $type =~ .*gzip.* ]]; then
    zcat $1 | (cpio -id; cat >$tmpfile)
else
    return
fi
uncpio $tmpfile 
rm $tmpfile
}

ในการใช้ประเภท: uncpio initrdfilename


0

หากคุณต้องการทำงานนี้บ่อยครั้งคุณอาจต้องการสร้างฟังก์ชั่นทุบตีเล็ก ๆ ดังต่อไปนี้ (และอาจเพิ่มลงใน. bashrc ของคุณ):

initramfs-extract() {
    local target=$1
    local offset=$(binwalk -y gzip $1 | awk '$3 ~ /gzip/ { print $1; exit }')
    shift
    dd if=$target bs=$offset skip=1 | zcat | cpio -id --no-absolute-filenames $@
}

รหัสจะขึ้นอยู่กับคำตอบของ Marc แต่จะเร็วกว่ามากเนื่องจาก binwalk จะค้นหาเฉพาะไฟล์ gzip คุณสามารถเรียกใช้เช่นนี้

$ initramfs-extract /boot/initrd.img -v

คุณจะต้องbinwalkติดตั้งเพื่อให้มันใช้งานได้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.