Neden initrd'imin tek bir dizini, yani 'çekirdeği' var?


28

Önyüklenebilir bir sistem üzerinde çalışmak için debian live-build kullanıyorum. Sürecin sonunda, canlı bir sistemi başlatmak için kullanılan tipik dosyaları alıyorum: bir squashfs dosyası, bazı GRUB modülleri ve config dosyaları ve bir initrd.img dosyası.

İnitrd'yi çekirdeğe geçirerek bu dosyaları kullanarak sadece önyükleme yapabilirim

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

bootloader komut satırında. Ancak initrd imajımın içeriğini incelemeye çalıştığımda, şöyle:

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

anladığım dosya ağacı şöyle görünüyor:

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

Önyükleme sırasında kullanılan gerçek dosyaları içeren tipik / bin, / etc, / sbin ... öğesinin bulunduğu gerçek dosya sistemi ağacı nerede?


1
'Lsinitramfs' komutu bunun için tasarlandı.
earlgrey

Yanıtlar:


31

Verilen cpio blok atlama yöntemi güvenilir şekilde çalışmıyor. Bunun sebebi, kendimi edindiğim initrd görüntülerinin 512 baytlık bir sınırda birleştirilmiş iki arşivi olmamasıydı.

Bunun yerine, şunu yapın:

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

Benim için 512 bayt sınırında olmayan son numarayı (21136) kullanın:

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

Aslında, cevabınız benimkileri atar. Uyumun bir sorun olacağını hiç düşünmedim. Yine de, eğer çoklu resim dosyasındaki ilk resim 512B-çizgisi olmasaydı eğer cpio biraz daha ilginç bir çıktı verirse, merak ediyorum.
user986730

Aynı klasör hiyerarşisi ile değiştirdikten sonra nasıl geri döndürülür (orijinal durumuna geri gönderilir)?
EdiD

2
Sadece cdsize cpio arşivi, koşmak çıkarılan dizine find | cpio -H newc -o > /tmp/my_archive.cpio, sonra onu gziplemek gzip /tmp/my_archive.cpiove birini olsaydı nihayet, mikrokodu görüntüyle ile bitiştirmek: cat my_microcode_image.cpio /tmp/my_archive.cpio.gz > mynewinitrd.img. Bir mikro kod resminiz yoksa,
gzipped

Bu cevabı okuduğunuzda, bunun sadece gzipli içeriğin dosyada yarıda kalması durumunda işe yarayacağı açıktır. Aksi takdirde, blok büyüklüğünü 1 olarak değiştirmelisiniz ve atlanacak bayt sayısını atlatmalısınız. Bunu her zaman yapmamak için bir sebep var mı?
TamaMcGlinn

ikincisi, aslında sadece bazılarını listelemek yerine dosyaları yazmak için, pipetteki son komutu cpio -iyerine, yerine değiştirin cpio -tdv | head.
TamaMcGlinn

21

Eğer initrd.imgsıkıştırılmamış bir cpio arşivinden ve ardından gz-sıkıştırılmış cpio arşivinden oluştuğunu biliyorsanız, tüm dosyaları (her iki arşivden de) mevcut çalışma dizininize (bash olarak test edilmiştir) çıkarmak için aşağıdakileri kullanabilirsiniz:

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

Yukarıdaki komut satırı initrd.img, standart giriş içeriğini iki komutu yürüten cpio -idve zcat | cpio -idsırayla bir alt kabuğa geçirir . İlk komut ( cpio -id) ilk cpio arşivine ait tüm verileri okuduğunda biter. Kalan içerik daha sonra zcat | cpio -id, ikinci arşivi açıp açan paketlere iletilir .


1
Bu şimdiye kadarki en temiz çözüm gibi gözüküyor
velis

1
Güzel çalışıyor
TurboHz

Gizemli bir şekilde, @ woolpool'un iyi cevabı, kullanıcının gönderdiği tek cevaptır. Bu stil Tüm StackExchange kariyeri boyunca sadece bir cevap gönderecekseniz, böyle bir şey göndermekten daha iyisini yapamazsınız. OP değiştirmeyi düşünebilirsiniz kabul Bu sorunun cevabını.
thb

16

Debian'ın canlı yapımı (ve çekirdeğim tarafından kabul edilen sürprizlerimin) yarattığı initrd aslında iki görüntünün birleşimidir:

  • İşlemciye uygulanacak mikro kod güncellemelerini içeren bir CPIO arşivi;
  • aslında initrd dosya ağacını içeren bir gzip-ed cpio arşivi (beklenen / etc / bin / sbin / dev ... dizinleriyle birlikte).

Orijinal initrd.img dosyasını çıkardıktan hemen sonra, canlı derleme çıktısının dışına çıktıktan sonra şu çıktıyı elde ettim:

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

Bu, cpio çıkarma işleminin, her biri 512 Baytlık 896 blok ayrıştırıldıktan sonra sona erdiği anlamına gelir. Ancak orijinal initrd.img 896 * 512 = 458752B = 448 KB'den çok daha büyüktü:

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

Böylece aradığım gerçek initrd görüntüsü ilk cpio arşivinden hemen sonra eklenmiş (mikro kod güncellemelerini içeren resim) ve dd kullanılarak erişilebilir:

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

2

unmkinitramfsDebian 9 (stretch) ve Ubuntu 18.04 (biyonik) 'ten beri kullanılan initramfs-alet> = 0.126'dan kullanabilirsiniz .


1

@ Woolpool'un cevabında verilen fikre dayanarak, birleştirilmiş verilerin düzenlenmesine bakılmaksızın herhangi bir cpio arşivi için çalışacak ve binwalk gibi herhangi bir özel araç gerektirmeyen özyinelemeli bir fonksiyon yazdım. Örneğin, benim mkinitramfs bir cpio; cpio; gzip dosyası üretiyordu. Birleştirilen initrd dosyasının her bir bölümünü ayıklayarak, geri kalanını bir tempfile içine kaydederek ve ardından bir sonraki bölümle ne yapacağınıza karar vermek için "dosya" programını kullanarak çalışır.

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
}

Türünü kullanmak için: uncpio initrdfilename


0

Bu görevi sık sık yapmanız gerekiyorsa, aşağıdaki gibi küçük bir bash işlevi oluşturmak isteyebilirsiniz (ve belki de .bashrc'inize ekleyin):

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

Kod, Marc'ın cevabına dayanmaktadır, ancak binwalk yalnızca gzip dosyalarını arayacağından önemli ölçüde daha hızlıdır. Bu şekilde, onu çağırabilirsiniz:

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

binwalkÇalışması için yüklü olması gerekir .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.