Mengapa initrd saya hanya memiliki satu direktori, yaitu, 'kernel'?

29

Saya menggunakan debian live-build untuk bekerja pada sistem yang dapat di-boot. Pada akhir proses saya mendapatkan file-file khas yang digunakan untuk mem-boot sistem langsung: file squashfs, beberapa modul GRUB dan file konfigurasi, dan file initrd.img.

Saya bisa boot dengan baik menggunakan file-file itu, meneruskan initrd ke kernel melalui

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

pada baris perintah bootloader. Tetapi ketika saya mencoba memeriksa isi gambar initrd saya, seperti:

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

pohon file yang saya dapat terlihat seperti ini:

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

Di mana pohon sistem file aktual, dengan tipikal / bin, / etc, / sbin ... berisi file aktual yang digunakan saat boot?

pengguna986730
sumber
1
Perintah 'lsinitramfs' dirancang untuk ini.
earlgrey

Jawaban:

32

Metode lewati blok cpio yang diberikan tidak berfungsi dengan baik. Itu karena gambar initrd yang saya peroleh sendiri tidak memiliki kedua arsip yang disatukan pada batas 512 byte.

Sebaliknya, lakukan ini:

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

Gunakan nomor terakhir (21136) yang tidak pada batas 512 byte untuk saya:

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
Marc Merlin
sumber
Memang, jawaban Anda mengalahkan milik saya. Saya tidak pernah berpikir bahwa perataan akan menjadi masalah. Saya bertanya-tanya, apakah cpio akan memberikan beberapa output yang lebih menarik jika gambar pertama yang terkandung dalam file multi-gambar itu tidak berbaris 512B.
user986730
Bagaimana cara mengembalikannya kembali (mengemas kembali ke keadaan semula) setelah memodifikasi, dengan hierarki folder yang sama?
EdiD
2
Hanya cdke direktori di mana Anda diekstrak arsip cpio Anda, run find | cpio -H newc -o > /tmp/my_archive.cpio, kemudian gzip dengan gzip /tmp/my_archive.cpiodan akhirnya, menggabungkan dengan dengan gambar microcode, jika Anda memiliki satu: cat my_microcode_image.cpio /tmp/my_archive.cpio.gz > mynewinitrd.img. Jika Anda tidak memiliki gambar mikrokode, maka Anda bisa menggunakan file gzipped seperti di bootloader Anda
user986730
Dalam membaca jawaban ini tampaknya jelas ini hanya akan berfungsi jika konten yang di-gzp sudah melewati separuh file. Jika tidak, Anda harus mengubah ukuran blok ke 1 dan mengatur lompat ke jumlah byte untuk dilewati. Adakah alasan untuk tidak selalu melakukan itu?
TamaMcGlinn
kedua, untuk benar-benar menulis file alih-alih hanya mencantumkan beberapa di antaranya, ubah perintah terakhir di dalam pipa menjadi cpio -i, alih-alih cpio -tdv | head.
TamaMcGlinn
22

Jika Anda tahu bahwa Anda initrd.imgterdiri dari arsip cpio terkompresi diikuti oleh arsip cpio terkompresi gz, Anda dapat menggunakan yang berikut ini untuk mengekstrak semua file (dari kedua arsip) ke direktori kerja Anda saat ini (diuji dalam bash):

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

Baris perintah di atas meneruskan isi initrd.imgsebagai input standar ke dalam subkulit yang mengeksekusi dua perintah cpio -iddan zcat | cpio -idsecara berurutan. Perintah pertama ( cpio -id) berakhir setelah ia membaca semua data milik arsip cpio pertama. Konten yang tersisa kemudian diteruskan ke zcat | cpio -id, yang mendekompresi dan membongkar arsip kedua.

kolam wol
sumber
1
Ini sepertinya solusi terbersih sejauh ini
velis
1
Ini bekerja dengan indah
TurboHz
Misterius, jawaban bagus woolpool adalah satu-satunya jawaban yang pernah diposting pengguna. Itu gaya. Jika Anda akan memposting hanya satu jawaban selama seluruh karir StackExchange Anda, maka Anda hampir tidak bisa berbuat lebih baik daripada memposting satu jawaban seperti ini. OP mungkin mempertimbangkan untuk mengubah jawaban yang diterima untuk yang ini.
thb
16

Ternyata initrd yang dihasilkan oleh live-build Debian (dan yang mengejutkan saya, diterima oleh kernel) sebenarnya adalah gabungan dari dua gambar:

  • arsip CPIO yang berisi pembaruan mikrokode untuk diterapkan pada prosesor;
  • arsip cpio gzip-ed, yang sebenarnya berisi pohon file initrd (dengan direktori / etc / bin / sbin / dev ... yang diharapkan).

Setelah mengekstrak initrd.img asli, langsung dari output live-build, saya mendapatkan output ini:

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

Yang berarti bahwa ekstraksi cpio berakhir setelah parsing 896 blok masing-masing 512 Bytes. Tetapi initrd.img asli jauh lebih besar dari 896 * 512 = 458752B = 448 KB:

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

Jadi gambar initrd aktual yang saya cari ditambahkan tepat setelah arsip cpio pertama (yang berisi pembaruan mikrokode) dan dapat diakses menggunakan dd:

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

Anda dapat menggunakan unmkinitramfsdari initramfs-tools> = 0.126, yang disertakan sejak Debian 9 (stretch) dan Ubuntu 18.04 (bionic).

Benjamin Drung
sumber
1

Berdasarkan ide yang diberikan dalam jawaban @ woolpool, saya menulis fungsi rekursif yang akan bekerja untuk arsip cpio apa pun terlepas dari pengaturan data gabungan dan tidak memerlukan alat khusus seperti binwalk. Misalnya mkinitramfs saya menghasilkan file cpio; cpio; gzip. Ini bekerja dengan mengekstraksi setiap bagian dari file initrd bersambung, menyimpan sisanya ke tempfile dan kemudian menggunakan program "file" untuk memutuskan apa yang harus dilakukan dengan bagian selanjutnya.

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
}

Untuk menggunakan ketik: uncpio initrdfilename

SurpriseDog
sumber
0

Jika Anda perlu sering melakukan tugas ini, Anda mungkin ingin membuat fungsi bash kecil seperti berikut (dan mungkin menambahkannya ke .bashrc Anda):

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 $@
}

Kode ini didasarkan pada jawaban Marc, tetapi secara signifikan lebih cepat karena binwalk hanya akan mencari file gzip. Anda dapat memintanya, seperti ini:

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

Anda perlu binwalkdiinstal untuk membuatnya bekerja.

tyrion
sumber