Linuxシステム用のイメージファイルを準備しています。イメージを作成し、出力を毎回ビットごとに同一にするスクリプトを実行できる必要があります。
私は通常の手順を実行します。大きなバイナリファイルを作成してパーティションを作成し、そのパーティションを使用してループデバイスを作成してから、Iファイルシステムを作成します。次に、ファイルシステムをmount
し、syslinuxとinitrdのものをコピーし、パーティションをアンマウントし、ループデバイスを削除すると、イメージファイルが作成されます。ディスクにdd
することができ、Linuxシステムは正しく起動します。だから私はファイルシステムを正しく作っています。
上記の手順を実行するスクリプトを実行しますが、出力が異なるたびに実行します。その一部はext2データ構造のタイムスタンプです。 ext2構造体を読み込み、タイムスタンプをクリアできるプログラムを作成しました。_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
_
更新
上記のコマンドをスクリプトに挿入した場合は、それらをコピーして貼り付けて2回目に実行し(ただし、出力を保存します)、コマンドを2回実行する前に日付を変更します(date
command)、a.txtは同じディスクの場所に配置されます。ただし、スクリプトを実行して出力を保存し、コマンドラインから再度実行する場合は、出力を比較すると、a.txtは別の場所にあります。非常に奇妙な行動。ファイルの場所を生成するためにどのようなデータが使用されていますか?明らかにそれは時間ではありません。私が考えることができる唯一のことは、スクリプトを2回呼び出すことによってコマンドを2回呼び出すことと、同じスクリプトでコマンドを2回実行することの違いは、呼び出し元のプロセスのプロセスIDのようなものです。アイデアは誰ですか?
アップデート#2
ext2の使用をあきらめました。そのため、ext2に関する最初の質問に答えることはできませんが、基本的なLinuxシステムの完全に再現可能なビルドを取得するために何をしたかについて説明します。
Linuxシステムを起動するだけの場合、FATによって問題が発生することはありません。ただし、より大きなデータパーティションの場合、FAT32にはいくつかの問題が発生する可能性があります。
vfat_create_shortname()
)。したがって、このフィールドは再現できません。 Microsoftの実装がどのようにそれを行うのかわかりません。 8.3の名前はDOS以外には使用されていないと思うので、このフィールドをクリアするだけでうまくいくかもしれません。または、再現できる独自の一意の番号を生成することもできます。番号が何であるかは関係ありません。一意であるだけです。追加のパーティションにISO9660を使用する
Genisoimageを使用してisoを作成します。タイムスタンプを除いて、実行ごとに同じ出力を生成します。 -lオプションを使用すると、最大31文字のファイル名を使用できます。それより長いファイル名が必要な場合は、ロックリッジ拡張子を使用してください。コマンドは
_genisoimage -o gfx.iso -R -l -f assets/files/
_
Iso9660ファイルシステムをウォークし、ロックリッジエントリのTFフィールドを含むすべてのタイムスタンプをクリアするプログラムを作成します。
Ddを使用して、パーティションの作成に使用したのと同じ番号を使用して、ディスクイメージにisoを埋め込みます。使った
_dd bs=512 seek=$part2_start_lba conv=notrunc if=gfx.iso of=cf.bin
_
ここで、cf.binは私のディスクイメージファイルです。 6. Linuxが起動した後、isoパーティションをマウントします。 isoが2番目のパーティションの場合、/ dev/sda2になります。最初に/ devに適切なデバイスファイルを作成するには、mknodを使用する必要がある場合があります。
私見これはすべて過度に複雑になっているようです。 tar だけが明らかな解決策のように思われる場合。 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
または rsync を使用して、準備したファイルツリーを配置します。ファイルシステム。そうすれば、すべてが一貫します-同じ日付、同じ所有者/グループ&&パーマ。
さて、それは私がこのようなものにアプローチする方法です。 :)
HTH
_e2image
_ を試すこともできます:
E2imageプログラムは、デバイス上にある重要なext2、ext3、またはext4ファイルシステムのメタデータをファイルに保存します。
デフォルトでは、_e2image
_はメタデータのみを保存しますが、_-a
_オプションを使用すると、データも保存できます。 (リンクの「データを含める」セクションを参照してください)
-aオプションを指定して、すべてのデータを含めることができます。これにより、FS全体のクローンを作成するため、またはバックアップの目的で使用するのに適したイメージが得られます。このオプションは、raw形式またはQCOW2形式でのみ機能することに注意してください。
バックアップには、raw形式よりも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/sda1
_からパーティション_boot-part.qcow2
_を復元します。_Sudo umount /dev/sda1
Sudo e2image -r boot-part.qcow2 /dev/sdd1
_
マウントされたパーティションのスーパーブロックを書き換えることはできないため、umount
は必須であることに注意してください。その時点で_/dev/sda1
_がマウントされていない場合は、この手順をスキップできます。 :)
シナリオの復元では、_/dev/sda1
_のサイズがイメージファイル内のパーティション以上である必要があることにも注意してください。そうでない場合、エラーe2image: Invalid argument while trying to convert qcow2 image (boot-part.qcow2) into raw image (/dev/sda1)
が発生します。
注:これは完全な答えではありません。部分的なもの、または少なくともヒント
イメージを作成し、出力を毎回ビットごとに同一にするスクリプトを実行できる必要があります。
それを達成するために必要な最初の問題は、msdos
パーティションテーブルのdisk signatures
です([〜#〜] mbr [〜#〜]の440のオフセット、4バイト長)。 MBRが異なる場合、最初のセクターだけで目標を達成できません。 mklabel
内で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
...を忘れないでください。ファイルシステムごとに異なるデータが含まれている場合、それらが存在するバイト範囲の違いを伝播します。
最後に、ファイルをコピーするときは、ファイルシステム内のファイルバイトの「配布」を直接制御できないことを覚えておいてください...クローンを作成できない場合は、それを制御する方法を見つける必要があります。あまりにも。
元の質問に対する答えは、 genext2fs というツールです。 -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
楽しんで!