ブロックデバイスの内容をアーカイブするようにtar(など)を説得する方法は?


13

仮想マシンを一緒にバックアップする6つのLinux論理ボリュームがあります。VMは現在シャットダウンされているため、VMの一貫したイメージを簡単に取得できます。

6つの画像すべてをアーカイブにまとめたいと思います。簡単に、私はこのようなことをすることができます:

cp /dev/Zia/vm_lvraid_* /tmp/somedir
tar c /tmp/somedir | whatever

しかし、それはもちろん余分なコピーを作成します。余分なコピーは避けたいです。

明らかなアプローチ:

tar c /dev/Zia/vm_lvraid_* | whatever

tarは特殊なファイル(この場合はシンボリックリンク)を認識し、基本的ln -sにアーカイブに保存するため、動作しません。または、で、--dereferenceまたは直接ポイントされて/dev/dm-X、それらを特別な(デバイスファイル)として認識し、基本的mknodにアーカイブに保存します。

この動作をオーバーライドするためにtarのコマンドラインオプションを検索しましたが、見つかりませんでした。私もcpio同じ問題を試みましたが、そこでそれをオーバーライドするオプションも見つかりませんでした。私も試しました7z(同じ)。と同じpax。私も試してみましたがzip、混乱してしまいました。

編集:GNU tarとGNU cpioのソースコードを見ると、どちらもこれができないようです。少なくとも、深刻な策略がないわけではありません(デバイスファイルの特別な処理を無効にすることはできません)。そのため、深刻な策略の提案または代替ユーティリティをいただければ幸いです。

TLDR:複数のディスクイメージを(rawデバイスから取得して)まとめてパックし、余分なディスク上のコピーを作成せずにその出力をストリーミングするアーカイバはありますか?私の好みは、POSIXやGNU tarのような一般的な形式で出力されます。


私はそれを確信しました。
mikeserv 14

回答:


11

だから最近、これをでやりたかったtar。いくつかの調査は、それが私ができなかったことは少し無意味ではないことを私に示しました。私はこの奇妙なsplit --filter="cat >file; tar -r ..."ことを思いついたが、まあ、それはひどく遅かった。そして、私tarはそれがより無意味であると思われるほど読んだ。

ご覧のtarとおり、レコードの連結リストです。構成ファイルはいかなる方法でも変更されません-それらは全体がアーカイブ内にあります。しかし、彼らはされているブロックされた 512バイトにオフブロック境界、およびすべてのファイルに先行するがあるヘッダー。それでおしまい。ヘッダー形式も実際には非常に単純です。

だから、私は自分で書いたtar。私はそれを呼び出します... shitar

z() (IFS=0; printf '%.s\\0' $(printf "%.$(($1-${#2}))d"))
chk() (IFS=${IFS#??}; set -f; set -- $(     
        printf "$(fmt)" "$n" "$@" '' "$un" "$gn"               
);  IFS=; a="$*"; printf %06o "$(($(
        while printf %d+ "'${a:?}"; do a=${a#?}; done 2>/dev/null
)0))")                                                                 
fmt() { printf '%s\\'"${1:-n}" %s "${1:+$(z 99 "$n")}%07d" \
    %07o %07o %011o %011o "%-${1:-7}s" ' 0' "${1:+$(z 99)}ustar  " %s \
    "${1:+$(z 31 "$un")}%s"
}

それは本当に肉とジャガイモです。ヘッダーを記述し、chksumを計算します-これは、相対的に言えば、唯一の難しい部分です。それはありませんustar...ヘッダフォーマットを多分。少なくとも、GNU が文句を言わない程度までヘッダー形式であるtarと考えるように見えるものをエミュレートしますustar。そして、それだけではありません。それは、私がまだそれをまだ凝固させていないということです。ここでは、以下を紹介します。

for f in 1 2; do echo hey > file$f; done
{ tar -cf - file[123]; echo .; } | tr \\0 \\n | grep -b .

0:file1                      #filename - first 100 bytes
100:0000644                  #octal mode - next 8
108:0001750                  #octal uid,
116:0001750                  #gid - next 16
124:00000000004              #octal filesize - next 12
136:12401536267              #octal epoch mod time - next 12
148:012235                   #chksum - more on this
155: 0                       #file type - gnu is weird here - so is shitar
257:ustar                    #magic string - header type
265:mikeserv                 #owner
297:mikeserv                 #group - link name... others shitar doesnt do
512:hey                      #512-bytes - start of file   
1024:file2                   #512 more - start of header 2
1124:0000644
1132:0001750
1140:0001750
1148:00000000004
1160:12401536267
1172:012236
1179: 0
1281:ustar  
1289:mikeserv
1321:mikeserv
1536:hey
10240:.                     #default blocking factor 20 * 512

それがありますtar。すべてが\0nullで埋められているので、読みやすくemするために単に\newlinesにします。そしてshitar

#the rest, kind of, calls z(), fmt(), chk() + gets $mdata and blocks w/ dd
for n in file[123]
do d=$n; un=$USER; gn=$(id --group --name)
   set -- $(stat --printf "%a\n%u\n%g\n%s\n%Y" "$n")
   printf "$(fmt 0)" "$n" "$@" "$(chk "$@")" "$un" "$gn"
   printf "$(z $((512-298)) "$gn")"; cat "$d"  
   printf "$(x=$(($4%512));z $(($4>512?($x>0?$x:512):512-$4)))"
done |
{ dd iflag=fullblock conv=sync bs=10240 2>/dev/null; echo .; } |
tr \\0 \\n | grep -b .

出力

0:file1                 #it's the same. I shortened it.
100:0000644             #but the whole first file is here
108:0001750
116:0001750
124:00000000004
136:12401536267
148:012235              #including its checksum
155: 0
257:ustar  
265:mikeserv
297:mikeserv
512:hey
1024:file2
...
1172:012236             #and file2s checksum
...
1536:hey
10240:.

私が言う種類のものがないため、最大shitarの目的- tarすでに美しくことを行います。それがどのように働くかを見せたかっただけchksumです。それがなかったらddtarファイルの先頭から飛び出し、それで終わりです。それはときどきうまくいくかもしれませんが、アーカイブに複数のメンバーがいると面倒になります。それでも、chksumは本当に簡単です。

最初に、それを7スペースにします(仕様書では8と言っていますが、ハックはハックです)。次に、ヘッダーの各バイトの8進数値を合計します。それがあなたのchksumです。そのため、ヘッダーを実行する前にファイルのメタデータが必要です。または、chksumがありません。そして、それustarはほとんどアーカイブです。

OK。さて、それが何をするつもりなのか:

cd /tmp; mkdir -p mnt     
for d in 1 2 3                                                
do  fallocate -l $((1024*1024*500)) disk$d
    lp=$(sudo losetup -f --show disk$d)
    sync
    sudo mkfs.vfat -n disk$d "$lp"
    sudo mount  "$lp" mnt
    echo disk$d file$d | sudo tee mnt/file$d
    sudo umount mnt
    sudo losetup -d "$lp"
done

3つの500Mディスクイメージを作成し、それぞれをフォーマットしてマウントし、それぞれにファイルを書き込みます。

for n in disk[123]
do d=$(sudo losetup -f --show "$n")
   un=$USER; gn=$(id --group --name)
   set -- $(stat --printf "%a\n%u\n%g\n$(lsblk -bno SIZE "$d")\n%Y" "$n")
   printf "$(fmt 0)" "$n" "$@" "$(chk "$@")" "$un" "$gn"
   printf "$(z $((512-298)) "$gn")"
   sudo cat "$d"
   sudo losetup -d "$d"
done | 
dd iflag=fullblock conv=sync bs=10240 2>/dev/null |
xz >disks.tar.xz

-明らかにブロックされたデバイスは常に正しくブロックされます。かなり便利です。

これtarがディスクデバイスファイルのコンテンツであり、ストリームを出力しxzます。

ls -l disk*
-rw-r--r-- 1 mikeserv mikeserv 524288000 Sep  3 01:01 disk1
-rw-r--r-- 1 mikeserv mikeserv 524288000 Sep  3 01:01 disk2
-rw-r--r-- 1 mikeserv mikeserv 524288000 Sep  3 01:01 disk3
-rw-r--r-- 1 mikeserv mikeserv    229796 Sep  3 01:05 disks.tar.xz

今、真実の瞬間...

 xz -d <./disks.tar.xz| tar -tvf -
-rw-r--r-- mikeserv/mikeserv 524288000 2014-09-03 01:01 disk1
-rw-r--r-- mikeserv/mikeserv 524288000 2014-09-03 01:01 disk2
-rw-r--r-- mikeserv/mikeserv 524288000 2014-09-03 01:01 disk3

やった!抽出...

xz -d <./disks.tar.xz| tar -xf - --xform='s/[123]/1&/'  
ls -l disk*
-rw-r--r-- 1 mikeserv mikeserv 524288000 Sep  3 01:01 disk1
-rw-r--r-- 1 mikeserv mikeserv 524288000 Sep  3 01:01 disk11
-rw-r--r-- 1 mikeserv mikeserv 524288000 Sep  3 01:01 disk12
-rw-r--r-- 1 mikeserv mikeserv 524288000 Sep  3 01:01 disk13
-rw-r--r-- 1 mikeserv mikeserv 524288000 Sep  3 01:01 disk2
-rw-r--r-- 1 mikeserv mikeserv 524288000 Sep  3 01:01 disk3
-rw-r--r-- 1 mikeserv mikeserv    229796 Sep  3 01:05 disks.tar.xz

比較...

cmp disk1 disk11 && echo yay || echo shite
yay

そして、マウント...

sudo mount disk13 mnt
cat mnt/*
disk3 file3

したがって、この場合、問題なくshitar実行されます。私はむしろ、それはすべてのものに入らないと思いませんよく行います。しかし、私は言う-少なくともファイル名に改行をしないでください。

また、私が提供した代替案を考慮して、これを行うこともできsquashfsます。だけでなく、あなたは、ストリームから構築された単一のアーカイブを取得しない- しかし、それはだmountことが、カーネルのにおよび組み込みvfs

pseudo-file.exampleから:

# Copy 10K from the device /dev/sda1 into the file input.  Ordinarily
# Mksquashfs given a device, fifo, or named socket will place that special file
# within the Squashfs filesystem, this allows input from these special
# files to be captured and placed in the Squashfs filesystem.
input f 444 root root dd if=/dev/sda1 bs=1024 count=10

# Creating a block or character device examples

# Create a character device "chr_dev" with major:minor 100:1 and
# a block device "blk_dev" with major:minor 200:200, both with root
# uid/gid and a mode of rw-rw-rw.
chr_dev c 666 root root 100 1
blk_dev b 666 0 0 200 200

またbtrfs (send|receive)、サブボリュームを任意の機能のあるstdinコンプレッサーにストリームするために使用することもできます。もちろん、このサブボリュームは、圧縮コンテナとして使用する前に存在する必要はありません。

それでも、約squashfs...

私はこの正義をしているとは思わない。これは非常に簡単な例です:

 cd /tmp; mkdir ./emptydir
 mksquashfs ./emptydir /tmp/tmp.sfs -p \
    'file f 644 mikeserv mikeserv echo "this is the contents of file"'                             

Parallel mksquashfs: Using 6 processors
Creating 4.0 filesystem on /tmp/tmp.sfs, block size 131072.
[==================================================================================|] 1/1 100%
Exportable Squashfs 4.0 filesystem, gzip compressed, data block size 131072
        compressed data, compressed metadata, compressed fragments,... 
###...
###AND SO ON
###...

echo '/tmp/tmp.sfs /tmp/imgmnt squashfs loop,defaults,user 0 0'|
    sudo tee -a /etc/fstab >/dev/null

mount ./tmp.sfs     
cd ./imgmnt
ls

total 1
-rw-r--r-- 1 mikeserv mikeserv 29 Aug 20 11:34 file

cat file

this is the contents of file

cd ..
umount ./imgmnt

それはのインライン-p引数のみですmksquash-pf好きなだけそれらを含むファイルを入手できます。形式は簡単です。新しいアーカイブのファイルシステムでターゲットファイルの名前/パスを定義し、モードと所有者を指定してから、どのプロセスを実行してstdoutを読み込むかを指定します。好きなだけ作成できます。LZMA、GZIP、LZ4、XZを使用できます。そして、最終的な結果はあなたがそこにアーカイブですcd

ただし、フォーマットの詳細:

もちろん、これは単なるアーカイブではなく、圧縮されたマウント可能なLinuxファイルシステムイメージです。そのフォーマットはLinuxカーネルのものです-それはバニラカーネルがサポートするファイルシステムです。このように、一般的なLinuxカーネルと同じくらい一般的です。したがって、tarプログラムがインストールされていないバニラLinuxシステムを実行していると言ったら、私は疑わしいでしょう-しかし、おそらくあなたを信じているでしょう。しかし、squashfsファイルシステムがサポートされていないバニラLinuxシステムを実行していると言われたら、私はあなたを信じません。


マイク、小さな自己完結型の例を作成して、人々がそれを試せるようにしたいですか?上記の少なくとも一部を実行しているように見えますが、わかりません。中には、input f 444 root root dd if=/dev/sda1 bs=1024 count=10ファイル入力fのでしょうか?おもちゃのデバイスを作成し、データを入力し、そこから書き込む方が良いでしょうか?そして、これにはすべてルートが必要ですか?
ファヒムミタ

@FaheemMitha-はい、できますが、ここではしませんでした。リンクは公式ドキュメントへのリンクです-それはそのままです。ただし、コマンドの例を実行した方が良いでしょう。私は前にそれをやった-それはかなりクールです。とにかく- inputファイルはsquashfsアーカイブ内のファイル-コマンドを実行した結果のファイルシステムイメージです。実行するときmksquash、実行stdoutされ、圧縮時にキャプチャされるコマンドに対してこれらの擬似ファイルコマンドを指定できます。
mikeserv 14

@FaheemMitha-ああ、それはマウントを行うかもしれませんが、圧縮を行うためにルートを必要としません-それは結果として生じるファイルシステムイメージです。すべてのLinux Liveディスクが使用するファイルシステムと同じです。実際、非常にクールなことの1つは、デバイスファイルと任意のMAJ:MIN番号の設定のように、ルートにならずにそれらの擬似ファイルを使用してルート所有のイメージを作成できることです。
mikeserv 14

デバイスファイルを作成して書き込み、それからマウントせずにそこからファイルを作成することは可能だと思いますか?そのため、おそらくrootを必要とせず、明らかに望ましいでしょう。
ファヒムミタ14

さて、ここにはbtrfsが関与していないため、機能しません。しかし、squashfsはそれがうまくいくかもしれないほどクレイジーです。ただし、一般的なアーカイブ形式ではないという欠点があります。
デロバート14

4

あなたの問題はしばらくの間私を困惑させました、そして、私は働くだろう解決策を見つけたと思います。

-si{NAME}フラグを使用して7zで目的を達成できると思います。

あなたのニーズに適応することができます。

7z a test.7z -siSDA2.txt < /dev/sda1
7z a test.7z -siSDA2.txt < /dev/sda2

7z l test.7z 

7-Zip [64] 9.20  Copyright (c) 1999-2010 Igor Pavlov  2010-11-18
p7zip Version 9.20 (locale=en_US.UTF-8,Utf16=on,HugeFiles=on,8 CPUs)

Listing archive: test.7z

--
Path = test.7z
Type = 7z
Method = LZMA
Solid = -
Blocks = 2
Physical Size = 1770
Headers Size = 162

   Date      Time    Attr         Size   Compressed  Name
------------------- ----- ------------ ------------  ------------------------
2014-08-19 22:01:08 .....         6314          804  SDA1.txt
2014-08-19 22:01:11 .....         6314          804  SDA2.txt
------------------- ----- ------------ ------------  ------------------------
                                 12628         1608  2 files, 0 folders

編集:猫の無駄な使用を削除


人々が試用できる小さな例を用意しておくと役立ちます。例えば、ブロックデバイスを作成し、それに書き込み、そしてそこから書き出す。ルートを必要としないことはプラスになります。
ファヒームミサ14

例では、/ dev / sda1はブロックデバイスです。catコマンドの目的は、デバイスのコンテンツをstdoutにダンプすることです。その後、7zはアーカイブを作成(または更新)し、stdinの-siパラメーターで指定されたファイル名にデータを保存します。アーカイブ内の結果は、各ブロックデバイスのコンテンツです。「cat」コマンドには、デバイスからデータを読み取るためのルートが必要です。
トニー14

これはCatの役に立たない使用ですが、それ以外の場合は法案にかなり適合します。奇妙なことに、私の7zマンページでは-siがファイル名を取ることができるとは言っていませんが、動作します。これは完全ではありません(出力をどこかにパイプすることはできません)が、これまでのところ、一般的な形式の出力としては間違いなく最高です。
デロバート14

ルートを必要とする@FaheemMithaは、システムの権限設定に依存しますが、新しいブロックデバイスを作成できるのはルートのみです。
デロバート14

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