Чому так, що мій initrd має лише один каталог, а саме "ядро"?


29

Я використовую debian live-build для роботи над завантажувальною системою. В кінці процесу я отримую типові файли, які використовуються для завантаження живої системи: файл squashfs, деякі модулі GRUB та конфігураційні файли та файл initrd.img.

Я можу завантажуватись добре за допомогою цих файлів, передаючи initrd до ядра через

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

у командному рядку завантажувача. Але коли я намагаюся вивчити вміст свого initrd-зображення, так:

$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'.
граф

Відповіді:


32

Даний метод пропускання блоку cpio не працює надійно. Це тому, що у зображеннях initrd, які я отримував сам, не було обох архівів, об'єднаних на межі 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.
користувач986730

Як повернути його назад (перепакувати до початкового стану) після зміни, з тією ж ієрархією папок?
ЕдіД

2
Просто cdв директорію , куди ви розпакували свій архів CPIO, біг find | cpio -H newc -o > /tmp/my_archive.cpio, потім GZIP його gzip /tmp/my_archive.cpioі , нарешті, зчепити його з з микрокода зображенням, якщо у вас один: cat my_microcode_image.cpio /tmp/my_archive.cpio.gz > mynewinitrd.img. Якщо у вас не було зображення мікрокоду, ви можете просто використовувати gzipped файл, як у вашому завантажувачі
user986730

Читаючи цю відповідь, здається очевидним, що це спрацює лише в тому випадку, якщо вміст gzipped вмісту пройде в половині файлу. В іншому випадку слід змінити розмір блоку на 1 і встановити пропуск на кількість байтів, які можна пропустити. Будь-яка причина не завжди робити це?
TamaMcGlinn

по-друге, щоб насправді записати файли, а не просто перелічити деякі з них, змініть остаточну команду в трубі на cpio -i, а не cpio -tdv | head.
TamaMcGlinn

22

Якщо ви знаєте, що ваш 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

Таємничо, що тонка відповідь @oopool є єдиною відповіддю, яку користувач коли-небудь публікував. Це стиль. Якщо ви збиралися опублікувати лише одну відповідь протягом усієї своєї кар'єри в StackExchange, навряд чи ви могли б зробити краще, ніж опублікувати таку, як ця. ОП може розглянути можливість зміни прийнятої відповіді на цю.
вт

16

Виявляється, initrd, породжений живою побудовою Debian (і, на мій подив, прийнято ядром) - це насправді об'єднання двох зображень:

  • архів CPIO, що містить оновлення мікрокоду, що застосовуються до процесора;
  • архів cpio gzip-ed, який фактично містить дерево файлів initrd (з каталогами / etc / bin / sbin / dev ..., які очікувались).

Витягнувши оригінал initrd.img, прямо з виводу живої збірки, я отримав такий вихід:

$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 Кб:

$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

Виходячи з ідеї у відповіді @oopool, я написав рекурсивну функцію, яка буде працювати для будь-якого архіву cpio незалежно від розташування об'єднаних даних і не потребує спеціальних інструментів, таких як binwalk. Наприклад, мій mkinitramfs створював файл cpio; cpio; gzip. Він працює, витягуючи кожну частину зв'язаного initrd-файлу, зберігаючи решту в tempfile, а потім використовуючи програму «файл», щоб вирішити, що робити з наступною частиною.

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

Якщо вам потрібно часто виконувати це завдання, можливо, ви захочете створити невелику функцію bash на зразок наступної (і, можливо, додати її до свого .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 $@
}

Код заснований на відповіді Марка, але він значно швидший, оскільки binwalk шукатиме лише файли gzip. Ви можете викликати його так:

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

Вам потрібно буде binwalkвстановити, щоб він працював.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.