내 initrd에 "kernel"이라는 하나의 디렉토리만 있는 이유는 무엇입니까?

내 initrd에 "kernel"이라는 하나의 디렉토리만 있는 이유는 무엇입니까?

저는 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

주어진 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

답변2

파일이 압축되지 않은 cpio 아카이브와 gz로 압축된 cpio 아카이브로 구성되어 있다는 것을 알고 있는 경우 initrd.img다음 명령을 사용하여 두 아카이브의 모든 파일을 현재 작업 디렉터리(bash에서 테스트)로 추출할 수 있습니다.

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

위의 명령줄은 initrd.img의 내용을 표준 입력으로 하위 쉘에 전달하고 하위 쉘은 두 cpio -id명령을 순서대로 실행합니다 zcat | cpio -id. 첫 번째 명령( cpio -id)은 첫 번째 cpio 아카이브에 속한 모든 데이터를 읽은 후 종료됩니다. 그런 다음 나머지 콘텐츠가 로 전달되어 zcat | cpio -id두 번째 아카이브의 압축이 풀립니다.

답변3

데비안의 라이브 빌드(놀랍게도 커널에서 허용됨)에 의해 생성된 initrd는 실제로 두 이미지를 연결한 것으로 밝혀졌습니다.

  • 프로세서에 적용될 마이크로코드 업데이트가 포함된 CPIO 아카이브.
  • 실제로 initrd 파일 트리(및 예상되는 /etc /bin /sbin /dev ... 디렉터리)를 포함하는 gzip으로 압축된 cpio 아카이브입니다.

라이브 빌드 출력에서 ​​직접 원본 initrd.img를 추출한 후 다음과 같은 출력을 얻었습니다.

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

이는 896개 블록(각각 512바이트)을 구문 분석한 후 cpio 추출이 종료된다는 의미입니다. 그러나 원본 initrd.img는 896*512 = 458752B = 448KB보다 훨씬 큽니다.

$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

답변4

@woolpool의 답변에 제공된 아이디어에 따라 연결 데이터 배열에 관계없이 모든 cpio 아카이브에서 작동하고 특별한 도구(예: binwalk)가 필요하지 않은 재귀 함수를 작성했습니다. 예를 들어, 내 mkinitramfs는 cpio;cpio;gzip 파일을 생성하고 있습니다. 연결된 initrd 파일의 각 부분을 추출하고 나머지 부분을 임시 파일에 저장한 후 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초기화 파일 이름

관련 정보