Linuxシステム用のイメージファイルを準備しています。イメージを生成し、出力が毎回同じビット単位で表示されるようにするスクリプトを実行できる必要があります。
私は大きなバイナリファイルを作成し、パーティションを分割し、そのパーティションを使用してループデバイスを作成し、Iファイルシステムを作成する一般的なプロセスを経ます。その後、mount
ファイルシステムシステムLinuxそして初期化プログラム物を梱包し、パーティションをマウント解除し、ループデバイスを削除し、イメージファイルを持つようになりました。これをディスクにコピーすると、dd
Linuxシステムが正しく起動します。だからファイルシステムを正しく作成しています。
上記の手順を実行するスクリプトを実行しますが、出力は毎回異なります。そのうちのいくつかはタイムスタンプです。外部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
更新
上記のコマンドをスクリプトに入れたら、コピーして貼り付けて2回目に実行し(その間に出力を保存します)、2回目のコマンドを実行する前に日付を変更してから(コマンドを使用date
)a.txt同じディスク位置に配置されます。ただし、スクリプトを実行している場合は、出力を保存してコマンドラインから再度実行して出力を比較します。a.txtさまざまな場所に位置しています。とても好奇心旺盛な行動です。ファイルの場所を生成するためにどのデータが使用されますか?どうやら今はそんな時ではない。私が考えることができる唯一のことは、スクリプトを2回呼び出してコマンドを2回呼び出すのと同じスクリプトでコマンドを2回実行することの違いは、呼び出しプロセスのプロセスIDと同じです。誰でもどんなアイデアがありますか?
更新#2
ext2の使用を放棄しました。したがって、ext2に関するあなたの元の質問に答えることはできませんが、基本的なLinuxシステムの完全に再現可能なビルドを得るために行ったことについて説明します。
- ext2の代わりにFATバリアントまたはISO9660を使用してください。 32MB未満のパーティションが必要な場合は、LinuxシステムパーティションにFAT16を使用し、それ以外の場合はFAT32を使用してください。 FAT16 または FAT32 は同じ場所にファイルを複製します。ただし、ディレクトリエントリにはいくつかのタイムスタンプがあります。
- 起動に必要なLinuxシステムファイルを追加します。
- FAT16/32ファイルシステムのディレクトリ構造を参照し、すべてのタイムスタンプを0に設定するプログラムを作成します。
- MBRからディスク署名を消去します。タイムスタンプを消去するプログラムでこれを実行するか、ddを使用してください。
- FATファイルシステムなので、ブートローダとしてsyslinuxを使用しています。 cpioは実行されるたびに同じinitrdを生成するので、問題はありません。これは基本的なビット単位の同じLinuxシステムに必要なすべてです。
FATファイルシステムの問題
Linuxシステムを起動しても、FATは問題を引き起こしません。しかし、より大きなデータ・パーティションの場合、FAT32 によっていくつかの問題が発生する可能性があります。
- ディレクトリ内の最大ファイル数に達することができます。これは問題ではありません。 (もちろん私の場合)
- FAT32 はファイルごとに 8.3 ファイル名を保存します。長いファイル名は、チルダと数字が追加された語幹に短縮されます。ただし、同じ短い行にマップされたファイルが9つ以上の場合、FAT32は文書化されていないプロセスを使用してファイル名に追加するハッシュ値の一種を生成します。時間をハッシュシードとして使用するFAT32用のLinuxカーネルコードを見ました(ファイル名i_vfat.cの関数
vfat_create_shortname()
)。したがって、このフィールドは再現できません。 Microsoftの実装がどのように機能するかわかりません。 8.3名前はDOS以外の用途には使用されないと思うので、このフィールドを消去するだけです。または、コピーできる一意の番号を生成できます。一意の番号なら何でも構いません。
ISO9660を追加パーティションとして使用
genisoimageを使用してisoを作成します。タイムスタンプを除いて、すべての実行で同じ出力を生成します。 -lオプションを使用すると、ファイル名に最大31文字を含めることができます。これより長いファイル名が必要な場合は、rock ridge拡張子を使用してください。コマンドは
genisoimage -o gfx.iso -R -l -f assets/files/
iso9660ファイルシステムに移動し、Rock RidgeエントリのTFフィールドを含むすべてのタイムスタンプを消去するプログラムを作成します。
- fdisk または parted を使用してディスクイメージにパーティションを作成します。 96hはISO9660のMBR ID番号です。
- 必要に応じてパーティションテーブルをパッチします。 Parted は iso9660 型パーティションの作成をサポートしていません。残念ながら、私は以前のバージョンのpartedとfdiskを使用してきましたが、partedははるかに使いやすいです。だから私はpartedを使って2番目のパーティションをfat32に設定しました。次に、fdiskを使用してタイプを96に変更します。
パーティションの作成に使用したのと同じ番号を使用して、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を使用する必要があります。
答え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が異なる場合、最初のセクタだけが目標を失います。mklabel
insideを実行するたびに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/sda1
QCOW2イメージファイルからパーティションを回復する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)
。