tar 등을 설득하여 블록 장치 내용을 보관하는 방법은 무엇입니까?


13

가상 머신을 함께 백업하는 6 개의 Linux 논리 볼륨이 있습니다. 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 : 여분의 온 디스크 복사본을 만들지 않고 여러 디스크 이미지를 함께 (원시 장치에서 가져온) 압축 하고 출력을 스트리밍하는 아카이버가 있습니까? 내 환경 설정은 POSIX 또는 GNU tar와 같은 일반적인 형식으로 출력됩니다.


나는 그것을 확신했다.
mikeserv

답변:


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을 계산합니다. 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\n채워져 있으므로 가독성을 위해 ewlines 로 바꿉니다. 그리고 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:.

나는 그것이 목적 이 아니기 때문에 일종의 위로 말합니다 . 벌써 아름답게합니다. 방금 작동 방식을 보여주고 싶었습니다 . 그게 아니라면 파일 의 머리 부분에서 벗어나서 끝낼 것입니다. 때로는 작동 할 수도 있지만 아카이브에 여러 구성원이 있으면 지저분 해집니다. 여전히 chksum은 정말 쉽습니다.shitartarchksumddtar

먼저 7 개의 공백을 만드십시오 (스펙이 8이라고 말한 것처럼 이상한 gnu 일 것입니다.하지만 해킹은 해킹입니다) . 그런 다음 헤더의 모든 바이트의 8 진 값을 더하십시오. 그게 당신의 chksum입니다. 따라서 헤더를 수행하기 전에 파일 메타 데이터가 필요하거나 chksum이 없습니다. 그리고 그것은 ustar대부분 아카이브입니다.

확인. 이제해야 할 일 :

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.

에서 의사 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 커널이며, 바닐라 커널 지원 파일 시스템입니다. 이런 식으로 바닐라 리눅스 커널만큼 흔합니다. 따라서 tar프로그램이 설치되지 않은 바닐라 리눅스 시스템을 실행하고 있다고 말하면 모호 할 것입니다.하지만 아마 당신을 믿을 것입니다. 그러나 squashfs파일 시스템이 지원되지 않는 바닐라 리눅스 시스템을 실행하고 있다고 말하면 나는 당신을 믿지 않을 것입니다.


마이크, 사람들이 실험 해 볼 수 있도록 작은 독립형 예제를 만들어 보시겠습니까? 위의 적어도 일부를 수행하고있는 것 같지만 확실하지 않습니다. 이어 input f 444 root root dd if=/dev/sda1 bs=1024 count=10파일 f를 입력? 아마도 장난감 장치를 만들어서 데이터로 채우고 쓰는 것이 더 좋을까요? 그리고이 모든 루트가 필요합니까?
Faheem Mitha

@FaheemMitha-네, 할 수는 있지만 여기서는하지 않았습니다. 공식 문서에 대한 링크는 바로 그것에서 가져온 것입니다. 그래도 명령 예제를 수행하면 더 좋을 것입니다. 나는 전에 그것을 한 적이있다 – 그것은 꽤 시원하다. 어쨌든- input파일은 squashfs아카이브 의 파일입니다 -명령을 실행 한 결과 파일 시스템 이미지입니다. 수행 mksquash할 때 stdout압축 시간에 실행되고 캡처 되는 명령에 이러한 의사 파일 명령을 지정할 수 있습니다 .
mikeserv

@FaheemMitha-아, 그리고 마운트를 수행 할 수도 있지만 압축 을하기 위해 루트가 필요하지는 않습니다 . 결과는 파일 시스템 이미지입니다. 모든 Linux Live 디스크가 사용하는 것과 동일한 파일 시스템입니다. 실제로 매우 멋진 점 중 하나는 장치 파일과 임의의 MAJ : MIN 숫자를 설정하는 것과 같이 루트가 아닌 의사 파일을 사용하여 루트 소유 이미지를 만들 수 있다는 것입니다.
mikeserv

장치 파일을 작성하고 기록 한 다음 마운트하지 않고 장치 파일을 만들 수 있어야한다고 생각합니까? 따라서 루트가 필요하지 않을 수도 있습니다.
Faheem Mitha

글쎄, 여기에 관련된 btrfs가 없으므로 작동하지 않습니다. 그러나 squashfs는 작동하기에 충분히 미쳤습니다. 일반적인 아카이브 형식이 아닌 단점이 있지만.
derobert

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

편집 : 고양이의 쓸모없는 사용을 제거


사람들이 시험해 볼 수있는 작은 모범을 갖는 것이 도움이 될 것입니다. 예를 들어 블록 장치를 만들어서 쓰고 쓴다. 루트를 요구하지 않는 것은 플러스 일 것입니다.
Faheem Mitha

이 예에서 / dev / sda1은 블록 장치입니다. cat 명령은 장치의 내용을 stdout에 덤프하는 데 사용됩니다. 그런 다음 7z는 아카이브를 작성 (또는 업데이트)하고 stdin의 -si 매개 변수로 지정된 파일 이름으로 데이터를 저장합니다. 아카이브 내의 결과는 각 블록 장치의 내용입니다. "cat"명령은 장치에서 데이터를 읽으려면 루트가 필요합니다.
Tony

그것은 쓸모없는 고양이 사용 이지만, 그렇지 않으면 법안에 잘 맞습니다. 이상하게도 내 7z맨 페이지에는 -si에 대해 언급하지 않지만 파일 이름을 사용할 수는 있지만 작동합니다. 완벽하지는 않지만 (어딘가에 출력을 파이프 할 수는 없지만) 공통 형식으로 출력하는 것이 가장 좋습니다.
derobert

루트가 필요한 @FaheemMitha는 시스템의 권한 설정에 의존하지만 루트 만 새 블록 장치를 만들 수 있습니다.
derobert

@derobert 고양이를 제거 :)
Tony
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.