initrdに「カーネル」というディレクトリが1つしかないのはなぜですか?


28

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」コマンドはこのために設計されました。
アールグレイ

回答:


31

指定されたcpioブロックのskipメソッドは、確実に機能しません。それは、私が手に入れていた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

私のために512バイトの境界上にない最後の番号(21136)を使用してください:

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

確かに、あなたの答えは私のものを打ち負かしています。アライメントが問題になるとは思っていませんでした。ただし、マルチイメージファイルに含まれる最初のイメージが512Bで裏打ちされていない場合にcpioがさらに興味深い出力を提供するかどうかは疑問です。
user986730

同じフォルダ階層で、変更後に元に戻す(元の状態に再パックする)方法は?
EdiD

2
ちょうどcdあなたがあなたのcpioアーカイブ、実行を抽出したディレクトリにfind | cpio -H newc -o > /tmp/my_archive.cpio、その後でそれをgzip gzip /tmp/my_archive.cpio:あなたは1を持っていた場合、最終的には、マイクロコードイメージを持つとそれを連結しますcat my_microcode_image.cpio /tmp/my_archive.cpio.gz > mynewinitrd.img。マイクロコードイメージがない場合は、ブートローダーにあるgzip圧縮されたファイルをそのまま使用できます
-user986730

この答えを読むと、gzipされたコンテンツがファイルの半分を過ぎている場合にのみ機能することが明らかです。それ以外の場合は、ブロックサイズを1に変更し、skipをスキップするバイト数に設定する必要があります。常にそうしない理由はありますか?
TamaMcGlinn

次に、ファイルの一部をリストするのではなく、実際にファイルを書き込むには、パイプの最後のコマンドをcpio -iでなくに変更しcpio -tdv | headます。
TamaMcGlinn

21

initrd.img圧縮されていないcpioアーカイブとそれに続くgz圧縮されたcpioアーカイブで構成されていることがわかっている場合は、次を使用して(両方のアーカイブから)すべてのファイルを現在の作業ディレクトリ(bashでテスト済み)に抽出できます:

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

上記のコマンドラインは、の内容をinitrd.img標準入力としてサブシェルに渡し、サブシェルは2つのコマンドcpio -idzcat | cpio -id順番に実行します。最初のコマンド(cpio -id)は、最初のcpioアーカイブに属するすべてのデータを読み取ると終了します。次に、残りのコンテンツがに渡されzcat | cpio -id、2番目のアーカイブが解凍および解凍されます。


1
これは最もクリーンなソリューションのように見えます
ヴェリス

1
それは美しく動作します
TurboHz

不思議なことに、@ woolpoolのすばらしい答えは、ユーザーがこれまでに投稿した唯一の答えです。それがスタイルです。StackExchangeのキャリア全体で1つの回答のみを投稿する場合、このような回答を投稿するよりも良い結果は得られません。OPは、これに対する受け入れられた回答の変更を検討する場合があります。
thb

16

Debianのlive-buildによって生成された(そして驚いたことに、カーネルによって受け入れられた)initrdは、実際には2つのイメージの連結であることがわかりました。

  • プロセッサに適用されるマイクロコードの更新を含むCPIOアーカイブ。
  • gzipで圧縮されたcpioアーカイブ。これには、実際にはinitrdファイルツリーが含まれています(/ etc / bin / sbin / dev ...ディレクトリが必要でした)。

live-build出力から元のinitrd.imgを抽出すると、次の出力が得られました。

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

これは、それぞれ512バイトの896ブロックを解析した後、cpioの抽出が終了したことを意味します。しかし、元の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

したがって、探していた実際のinitrdイメージは、最初のcpioアーカイブ(マイクロコードの更新を含むアーカイブ)の直後に追加され、ddを使用してアクセスできました。

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

2

unmkinitramfsDebian 9(ストレッチ)およびUbuntu 18.04(バイオニック)以降に含まれているinitramfs-tools> = 0.126から使用できます。


1

@woolpoolの答えで与えられたアイデアに基づいて、連結されたデータの配置に関係なくcpioアーカイブで機能し、binwalkのような特別なツールを必要としない再帰関数を作成しました。たとえば、私のmkinitramfsはcpio; cpio; gzipファイルを生成していました。これは、連結されたinitrdファイルの各部分を抽出し、残りを一時ファイルに保存し、「ファイル」プログラムを使用して次の部分の処理を決定することにより機能します。

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

コードはMarcの答えに基づいていますが、binwalkはgzipファイルのみを検索するため、非常に高速です。次のように呼び出すことができます。

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

binwalk動作させるにはインストールする必要があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.