똑같은 ext2 파일 시스템을 만드세요

똑같은 ext2 파일 시스템을 만드세요

Linux 시스템용 이미지 파일을 준비 중입니다. 이미지를 생성하고 출력이 매번 동일하게 비트 단위로 표시되도록 하는 스크립트를 실행할 수 있어야 합니다.

저는 큰 바이너리 파일을 만들고, 파티션을 나누고, 해당 파티션을 사용하여 루프 장치를 만든 다음, I 파일 시스템을 만드는 일반적인 과정을 거칩니다. 그런 다음 mount파일 시스템을시스템리눅스그리고초기화 프로그램물건을 포장하고, 파티션을 마운트 해제하고, 루프 장치를 삭제하고 이미지 파일을 갖게 되었습니다. 이를 디스크에 복사 하면 ddLinux 시스템이 올바르게 부팅됩니다. 그래서 파일 시스템을 올바르게 만들고 있습니다.

위 단계를 수행하는 스크립트를 실행하지만 출력은 매번 다릅니다. 그 중 일부는 타임스탬프입니다.외부 2데이터 구조. 나는 읽는 프로그램을 작성했습니다.외부 2구조는 타임스탬프 tune2fs등을 지우지만 비트맵 데이터 중 일부는 심지어 다르며 파일 데이터가 매번 같은 위치에 있는 것 같지 않습니다.

그렇다면 동일한 파일 시스템을 어떻게 만들 수 있습니까?

다음은 파일 시스템을 생성하고, 여기에 파일을 배치하고, 마운트 해제하는 데 사용하는 명령입니다. 출력을 저장하고 다시 실행하여 출력을 비교하면 파일이 a.txt다른 위치에 배치됩니다.

dd if=/dev/zero bs=1024 count=46112 of=cf.bin
parted cf.bin <<EOF
unit
s
mklabel
msdos
mkpart
p
ext2
63s
45119s
set
1
boot
on
q
EOF

losetup -o $(expr 63 \* 512) /dev/loop0 cf.bin

mke2fs -b 1024 -t ext2 /dev/loop0 22528

#clear some parameters
tune2fs -i 0 /dev/loop0 # interval between check
tune2fs -L LABEL /dev/loop0
tune2fs -U 00000000-0000-0000-0000-000000000000 /dev/loop0 #uuid
tune2fs -c 0 /dev/loop0 #mount count

mount /dev/loop0 mnt
# make a dummy file
echo HELLO > mnt/a.txt
umount mnt

losetup -d /dev/loop0

업데이트
위 명령을 스크립트에 넣으면 복사하여 붙여넣어 두 번째로 실행하고(그 사이에 출력을 저장함) 명령을 두 번째 실행하기 전에 날짜를 변경한 다음( 명령 사용 date)a.txt동일한 디스크 위치에 배치됩니다. 그러나 스크립트를 실행하는 경우 출력을 저장한 다음 명령줄에서 다시 실행하고 출력을 비교하고a.txt다양한 위치에 위치해 있습니다. 매우 호기심이 많은 행동입니다. 파일 위치를 생성하는 데 어떤 데이터가 사용됩니까? 분명히 지금은 그럴 때가 아니다. 제가 생각할 수 있는 유일한 것은 스크립트를 두 번 호출하여 명령을 두 번 호출하는 것과 동일한 스크립트에서 명령을 두 번 실행하는 것의 차이점은 호출 프로세스의 프로세스 ID와 같다는 것입니다. 누구든지 어떤 아이디어가 있습니까?

업데이트 #2
ext2 사용을 포기했습니다. 따라서 ext2에 대한 귀하의 원래 질문에 답할 수는 없지만 기본 Linux 시스템의 완전히 재현 가능한 빌드를 얻기 위해 수행한 작업에 대해 설명하겠습니다.

  1. ext2 대신 FAT 변형 또는 ISO9660을 사용하십시오. 32MB보다 작은 파티션이 필요한 경우 Linux 시스템 파티션용 FAT16을 사용하고, 그렇지 않으면 FAT32를 사용하세요. FAT16 또는 FAT32는 동일한 위치에 파일을 복제합니다. 그러나 디렉토리 항목에는 일부 타임스탬프가 있습니다.
  2. 시작에 필요한 Linux 시스템 파일을 추가합니다.
  3. FAT16/32 파일 시스템 디렉터리 구조를 탐색하고 모든 타임스탬프를 0으로 설정하는 프로그램을 작성하세요.
  4. MBR에서 디스크 서명을 지웁니다. 타임스탬프를 지우는 프로그램에서 이를 수행하거나 dd를 사용하십시오.
  5. FAT 파일 시스템이기 때문에 부트로더로 syslinux를 사용하고 있습니다. cpio는 실행될 때마다 동일한 initrd를 생성하므로 아무런 문제가 없습니다. 이것이 기본적인 비트 단위의 동일한 Linux 시스템에 필요한 전부입니다.

FAT 파일 시스템 문제

Linux 시스템을 부팅하는 경우에는 FAT가 문제를 일으키지 않습니다. 그러나 더 큰 데이터 파티션의 경우 FAT32로 인해 몇 가지 문제가 발생할 수 있습니다.

  1. 디렉터리에서 최대 파일 수에 도달할 수 있습니다. 이는 문제가 되지 않을 것입니다. (물론 내 경우에는)
  2. FAT32는 각 파일에 대해 8.3 파일 이름을 저장합니다. 긴 파일 이름은 물결표와 숫자가 추가된 어간으로 단축됩니다. 그러나 동일한 짧은 줄기에 매핑된 파일이 9개 이상인 경우 FAT32는 문서화되지 않은 프로세스를 사용하여 파일 이름에 추가할 일종의 해시 값을 생성합니다. 시간을 해시 시드로 사용하는 FAT32용 Linux 커널 코드를 살펴봤습니다(파일 이름 i_vfat.c 의 함수 vfat_create_shortname()). 따라서 이 필드는 재현할 수 없습니다. Microsoft의 구현이 어떻게 작동하는지 모르겠습니다. 8.3 이름은 DOS 이외의 다른 용도로 사용되지 않는다고 생각하므로 이 필드만 지우면 됩니다. 또는 복사할 수 있는 고유한 번호를 생성할 수 있습니다. 고유한 번호라면 무엇이든 상관없습니다.

ISO9660을 추가 파티션으로 사용

  1. genisoimage를 사용하여 iso를 만듭니다. 타임스탬프를 제외하고는 모든 실행에서 동일한 출력을 생성합니다. -l 옵션을 사용하면 파일 이름에 최대 31자를 포함할 수 있습니다. 이보다 긴 파일 이름이 필요하면 rock ridge 확장자를 사용하세요. 명령은

    genisoimage -o gfx.iso -R -l -f assets/files/
    
  2. iso9660 파일 시스템을 탐색하고 Rock Ridge 항목의 TF 필드를 포함하여 모든 타임스탬프를 지우는 프로그램을 작성하세요.

  3. fdisk 또는 parted를 사용하여 디스크 이미지에 파티션을 만듭니다. 96h는 ISO9660의 MBR ID 번호입니다.
  4. 필요한 경우 파티션 테이블을 패치합니다. Parted는 iso9660 유형 파티션 생성을 지원하지 않습니다. 불행하게도 저는 이전 버전의 parted와 fdisk를 사용해왔는데, parted가 훨씬 사용하기 쉽습니다. 그래서 나는 parted를 사용하여 두 번째 파티션을 fat32로 설정했습니다. 그런 다음 fdisk를 사용하여 유형을 96으로 변경합니다.
  5. 파티션을 생성할 때 사용한 것과 동일한 번호를 사용하여 dd를 사용하여 iso를 디스크 이미지에 포함합니다. 나는 사용했다

    dd bs=512 seek=$part2_start_lba conv=notrunc if=gfx.iso of=cf.bin
    

여기서 cf.bin은 내 디스크 이미지 파일입니다. 6. Linux가 시작된 후 iso 파티션을 마운트합니다. iso가 두 번째 파티션인 경우 /dev/sda2가 됩니다. 먼저 /dev에 올바른 장치 파일을 생성하려면 mknod를 사용해야 할 수도 있습니다.

답변1

IMHO 모든 것이 지나치게 복잡해지는 것 같습니다. 언제아스팔트혼자서는 분명한 해결책처럼 보입니다. tar는 cdfs(--options cd9660:*)를 포함한 거의 모든 파일 시스템을 만들 수 있습니다. 또한 출력 파일에 -m || --modification-time가장 최근,,,, --gid id || --gname name... 중 하나로 타임스탬프를 지정할 수 있습니다.--acls || --no-acls--same-owner || --no-same-owner

또는 파일 시스템을 생성할 수도 있습니다. chown -Rh someone:somegroup .파일 트리에서 chmod원하는 대로 실행하여 사용 tar하거나동기화파일 트리를 준비된 파일 시스템에 배치합니다. 그러면 날짜, 소유자/그룹, 권한 등 모든 것이 일관되게 유지됩니다.

글쎄요, 그게 제가 그런 일에 접근하는 방식이에요. :)

화타이

답변2

원래 질문에 대한 답은 다음과 같은 프로그램입니다.제넥스트2fs. -f 스위치를 제공하면 동일한 입력에 대해 비트 단위로 동일한 출력이 생성됩니다. 이는 생성된 이미지를 올바르게 출력되는 미리 계산된 md5sum과 비교하는 자체 테스트 모음이나 이 테스트(소스 디렉터리 내에서 실행됨)를 통해 입증될 수 있습니다.

$ ./genext2fs -f -B 1024 -b 40 -d m4 rootfs.img
$ md5sum rootfs.img
322053a8962acc599eaabb2dfde28783  rootfs.img
$ rm rootfs.img
$ ./genext2fs -f -B 1024 -b 40 -d m4 rootfs.img
$ md5sum rootfs.img
322053a8962acc599eaabb2dfde28783  rootfs.img

생성된 이미지를 마운트하고 해당 내용이 실제로 패키징 디렉터리와 동일한지 확인할 수 있습니다.

$ sudo mount rootfs.img /mnt
$ ls -lha /mnt
total 27K
drwxr-xr-x  3 root  root  1.0K Jan  1  1970 .
drwxr-xr-x 25 root  root  4.0K Mar 22 14:56 ..
-rw-r--r--  1 josch josch 1.5K Mar 22 23:05 ac_func_scanf_can_malloc.m4
-rw-r--r--  1 josch josch 2.4K Mar 22 14:24 ac_func_snprintf.m4
drwx------  2 root  root   16K Jan  1  1970 lost+found
$ rmdir /mnt/lost+found
$ diff -rq m4 /mnt
$ echo $?
0

재미있게 보내세요!

답변3

노트: 이것은 완전한 답변이 아니며 단지 일부이거나 적어도 힌트입니다.


이미지를 생성하고 출력이 매번 동일하게 비트 단위로 표시되도록 하는 스크립트를 실행할 수 있어야 합니다.

가장 먼저 깨달아야 할 문제는 분할된 테이블 (분할된 테이블의 오프셋 440) disk signatures에 있습니다.msdos막 생물 반응기,4바이트 길이). MBR이 다른 경우 첫 번째 섹터에서만 목표가 누락됩니다. mklabelinside 를 실행할 때 마다 parted새로운 것이 생성됩니다 disk signature. 다음과 같이 이 4바이트를 동일한 무작위 서명으로 덮어쓰면 이 문제를 극복할 수 있습니다.

printf RAMDOM_SIGNATURE | xxd -p -r | dd bs=1 count=4 seek=440 of=YOUR_DOT_BIN conv=notrunc 2> /dev/null

RANDOM_SIGNATURE이럴 수도 있지'73396992'

다음 문제를 해결하기 위해 스크립트를 일부 수정했습니다.

dd if=/dev/zero bs=1024 count=46112 of="$1"
parted "$1" <<EOF
unit
s
mklabel
msdos
mkpart
p
ext2
63s
45119s
set
1
boot
on
q
EOF

printf "$2" | xxd -p -r | dd bs=1 count=4 seek=440 of="$1" conv=notrunc 2> /dev/null

losetup -o $(expr 63 \* 512) /dev/loop0 "$1"

mke2fs -b 1024 -t ext2 /dev/loop0 22528

#clear some parameters
tune2fs -i 0 /dev/loop0 # interval between check
tune2fs -L LABEL /dev/loop0
tune2fs -U 00000000-0000-0000-0000-000000000000 /dev/loop0 #uuid
tune2fs -c 0 /dev/loop0 #mount count

#mount /dev/loop0 mnt
## make a dummy file
#echo HELLO > mnt/a.txt
#umount mnt

losetup -d /dev/loop0

이제 다음과 같이 스크립트를 호출할 수 있습니다.

./script_name BIN_FILE_NAME RANDOM_SIGNATURE

이제 이렇게 하면:

./test.sh cf00.bin '73396992'
./test.sh cf01.bin '73396992'
./test.sh cf02.bin '73396992'
./test.sh cf03.bin '73396992'

그런 다음 이:

dd if=cf00.bin count=63 2>/dev/null | sha1sum
dd if=cf01.bin count=63 2>/dev/null | sha1sum
dd if=cf02.bin count=63 2>/dev/null | sha1sum
dd if=cf03.bin count=63 2>/dev/null | sha1sum

첫 번째 파티션의 파일 시스템 이전에 이러한 모든 파일이 동일하다는 것을 알 수 있습니다(원본 스크립트와 동일하게 시도하면 합계가 서로 달라집니다).

내 버전의 스크립트에서는 파일에 쓰는 줄을 주석 처리했음을 알 수 있습니다 a.txt. 파일 시스템에 파일이 없더라도 파일 시스템을 동일하게 만들 수 없으면 문제를 해결하려고 노력할 필요가 없기 때문에 이렇게 합니다. 문제는 파일이 없어도 파일 시스템이 다르기 때문에 먼저 이를 수정해야 한다는 것입니다.

각 이미지의 파일 시스템 파티션에 대해 실행 dumpe2fs하고 이를 파일에 덤프한 다음 diff덤프 쌍에 대해 사용하면 다음과 같은 내용이 표시됩니다.

25c25
< Filesystem created:       Sat Jun 15 07:37:32 2019
---
> Filesystem created:       Sat Jun 15 07:37:40 2019
27c27
< Last write time:          Sat Jun 15 07:37:33 2019
---
> Last write time:          Sat Jun 15 07:37:40 2019
30c30
< Last checked:             Sat Jun 15 07:37:32 2019
---
> Last checked:             Sat Jun 15 07:37:40 2019
37c37
< Directory Hash Seed:      603130ae-82de-4530-9772-f68ae3d6df5f
---
> Directory Hash Seed:      1d9c5af8-a48e-4221-9e70-8fa2ccc6936f

그러니 적어도,매우 높은 수준에서(이후에는 가장 낮은 수준, 즉 실제바이트 단위비교) 파일 시스템은 위에 표시된 세부 사항이 다릅니다. 먼저 이 문제를 해결하세요.

기계에서 날짜를 변경하더라도 프로그램 실행에는 제어할 수 있는 시간 차이가 있기 때문에 타임스탬프를 성공적으로 변조하고 동일하게 만들 수 없습니다. 이 경우에는 다음이 필요합니다.꼭 매달리게 하다적어도 파일 시스템을 생성한 프로그램의 관점에서 보면 그것은 여러분의 시계입니다. 이에 대해 더 깊이 파고들 수 있지만 컴퓨터에서 스크립트를 실행해야 한다고 말했기 때문에 이것이 올바른 접근 방식이라고 생각하지 않습니다.당신은 그들의 시계를 엉망으로 만들고 싶지 않습니다. 그래서 IMHO, 갈 길은 아마도 내가 disk signature검색한 것처럼 파일 시스템의 올바른 바이트를 조작하는 것입니다.

또한... 추적하는 것도 잊지 마세요 Superblock backups. 각 파일 시스템에 서로 다른 데이터가 포함되어 있으면 해당 파일이 있는 바이트 범위의 차이가 전파됩니다.

마지막으로, 파일을 복사할 때 파일 시스템 내에서 파일 바이트의 "분배"를 직접 제어할 수 없다는 점을 기억하십시오. 복제할 수 없는 경우 다음과 같이 이를 제어할 수 있는 방법을 찾아야 합니다. 잘.

답변4

당신은 또한 시도할 수 있습니다e2image:

e2image 프로그램은 장치의 중요한 ext2, ext3 또는 ext4 파일 시스템 메타데이터를 파일에 저장합니다.

기본적으로 e2image메타데이터만 저장되지만 , -a옵션을 이용하여 데이터를 저장할 수도 있습니다. (링크의 "포함된 데이터" 섹션 참조)

-a 옵션을 지정하여 모든 데이터를 포함할 수 있습니다. 이는 전체 FS 복제 또는 백업 목적에 적합한 이미지를 제공합니다. 이 옵션은 원시 또는 QCOW2 형식에서만 작동합니다.

QCOW2 형식은 원본 형식보다 백업에 더 적합합니다. QCOW2 이미지는 백업 중인 파티션의 사용 공간과 크기가 비슷한 일반 파일입니다. 원본 이미지는 모든 의미에서 희소 파일입니다. 희소 파일을 구체적으로 처리하지 않는 도구는 사용된 공간뿐만 아니라 여유 공간도 처리합니다.

따라서 사용 예는 다음과 같습니다.

  • sda1파일 및 메타데이터를 포함한 파티션을 파일에 백업합니다 boot-part.qcow2.
sudo mount -o remount,ro /dev/sda1
sudo e2image -a -Q /dev/sda1 boot-part.qcow2

백업 프로세스 중에 누구도 파티션에 쓰지 않도록 하려면 읽기 전용으로 다시 마운트해야 합니다. 결국 sudo mount -o remount,rw /dev/sda1필요한 경우 읽기-쓰기 모드로 다시 설치할 수 있습니다.

  • /dev/sda1QCOW2 이미지 파일에서 파티션 복구 boot-part.qcow2:
sudo umount /dev/sda1
sudo e2image -r boot-part.qcow2 /dev/sda1

umount마운트된 파티션의 슈퍼블록을 덮어쓸 수 없기 때문에 이 작업이 필요하다는 점에 유의하세요 . /dev/sda1당시 마운트되지 않은 경우 이 단계를 건너뛸 수 있습니다. :)

복구 시나리오에서는 크기가 /dev/sda1이미지 파일 내부의 파티션과 같거나 커야 한다는 점도 주목할 가치가 있습니다. 그렇지 않으면 오류가 발생합니다: e2image: Invalid argument while trying to convert qcow2 image (boot-part.qcow2) into raw image (/dev/sda1).

관련 정보