Làm thế nào để thuyết phục tar (vv) để lưu trữ nội dung khối thiết bị?


13

Tôi có sáu khối logic Linux cùng với một máy ảo. VM hiện đang tắt máy, vì vậy thật dễ dàng để có được những hình ảnh nhất quán về chúng.

Tôi muốn gói tất cả sáu hình ảnh lại với nhau trong một kho lưu trữ. Một cách tầm thường, tôi có thể làm một cái gì đó như thế này:

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

Nhưng điều đó tất nhiên tạo ra một bản sao thêm. Tôi muốn tránh các bản sao thêm.

Cách tiếp cận rõ ràng:

tar c /dev/Zia/vm_lvraid_* | whatever

không hoạt động, vì tar nhận ra các tệp đặc biệt (symlink trong trường hợp này) và về cơ bản lưu trữ ln -strong kho lưu trữ. Hoặc, với --dereferencehoặc chỉ trực tiếp vào /dev/dm-X, nó nhận ra chúng là đặc biệt (tệp thiết bị) và về cơ bản lưu trữ mknodtrong kho lưu trữ.

Tôi đã tìm kiếm các tùy chọn dòng lệnh để tar để ghi đè hành vi này và không thể tìm thấy bất kỳ. Tôi cũng đã thử cpio, cùng một vấn đề và không thể tìm thấy bất kỳ tùy chọn nào để ghi đè lên đó. Tôi cũng đã thử 7z(ditto). Tương tự với pax. Tôi thậm chí đã thử zip, mà chỉ có chính nó bối rối.

chỉnh sửa: Nhìn vào mã nguồn của GNU tar và GNU cpio, có vẻ như không ai trong số họ có thể làm điều này. Ít nhất, không phải không có mánh khóe nghiêm trọng (việc xử lý đặc biệt các tệp thiết bị không thể bị vô hiệu hóa). Vì vậy, các đề xuất về thủ thuật nghiêm trọng sẽ được đánh giá cao hoặc các tiện ích thay thế.

TLDR: Có một số trình lưu trữ sẽ đóng gói nhiều hình ảnh đĩa với nhau (được lấy từ các thiết bị thô) và truyền phát ra mà không tạo thêm các bản sao trên đĩa? Sở thích của tôi sẽ là đầu ra ở định dạng phổ biến, như POSIX hoặc GNU tar.


Tôi đã thuyết phục nó.
mikeerv

Câu trả lời:


11

Vì vậy, gần đây tôi muốn làm điều này với tar. Một số điều tra chỉ ra cho tôi rằng nó không hơn một chút vô nghĩa mà tôi không thể. Tôi đã nghĩ ra điều kỳ lạ split --filter="cat >file; tar -r ..."này, nhưng, tốt, nó rất chậm. Và tôi càng đọc về tarnó dường như vô nghĩa hơn.

Bạn thấy đấy, tarchỉ là một danh sách các hồ sơ được kết hợp. Các tập tin cấu thành không bị thay đổi theo bất kỳ cách nào - chúng là toàn bộ trong kho lưu trữ. Nhưng chúng bị chặn trên ranh giới khối 512 byte và trước mỗi tệp đều có tiêu đề . Đó là nó. Các định dạng tiêu đề là thực sự, rất đơn giản là tốt.

Vì vậy, tôi đã viết của riêng tôi tar. Tôi gọi nó là ... 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"
}

Đó là thịt và khoai tây, thực sự. Nó viết các tiêu đề và tính toán chksum - mà, nói một cách tương đối, là phần khó duy nhất. Nó có ustarđịnh dạng tiêu đề ... có thể . Ít nhất, nó mô phỏng những gì GNU tardường như nghĩ là ustarđịnh dạng tiêu đề đến điểm mà nó không phàn nàn. Và còn hơn thế nữa, chỉ là tôi chưa thực sự đông máu nó. Ở đây, tôi sẽ chỉ cho bạn:

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

Đó là tar. Mọi thứ đều được đệm bằng \0null nên tôi chỉ chuyển emthành \newlines để dễ đọc. Và 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 .

ĐẦU RA

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:.

Tôi nói loại lên ở đó vì đó không phải là shitar's mục đích - tarđã thực hiện điều đó thật đẹp. Tôi chỉ muốn cho thấy nó hoạt động như thế nào - có nghĩa là tôi cần phải chạm vào chksum. Nếu không, tôi sẽ chỉ ddlấy phần đầu của tartập tin và thực hiện với nó. Điều đó thậm chí có thể hoạt động đôi khi, nhưng nó trở nên lộn xộn khi có nhiều thành viên trong kho lưu trữ. Tuy nhiên, chksum thực sự dễ dàng.

Đầu tiên, làm cho nó có 7 khoảng trắng - (đó là một điều kỳ quặc, tôi nghĩ, như thông số kỹ thuật nói 8, nhưng bất cứ điều gì - một hack là một hack) . Sau đó cộng các giá trị bát phân của mỗi byte trong tiêu đề. Đó là chksum của bạn. Vì vậy, bạn cần siêu dữ liệu tệp trước khi bạn thực hiện tiêu đề hoặc bạn không có chksum. Và đó là một ustarkho lưu trữ, chủ yếu.

Đồng ý. Bây giờ, những gì nó có nghĩa là để làm:

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

Điều đó tạo ra ba hình ảnh đĩa 500M, định dạng và gắn kết mỗi cái, và ghi một tệp vào mỗi tệp.

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

Lưu ý - rõ ràng các thiết bị khối sẽ luôn luôn chặn chính xác. Khá tiện dụng.

Đó tarlà nội dung của các tệp thiết bị đĩa trong luồng và dẫn đầu ra 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

Giờ đây, khoảnh khắc của sự thật ...

 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

Hoan hô! Khai thác...

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

So sánh ...

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

Và thú cưỡi ...

sudo mount disk13 mnt
cat mnt/*
disk3 file3

Và vì vậy, trong trường hợp này, shitarthực hiện ok, tôi đoán. Tôi thà không đi sâu vào tất cả những điều mà nó sẽ không làm tốt. Nhưng, tôi sẽ nói - ít nhất đừng làm những dòng mới trong tên tập tin.

Bạn cũng có thể làm - và có lẽ nên, xem xét các lựa chọn thay thế mà tôi đã đưa ra - đây là squashfs. Bạn không chỉ nhận được kho lưu trữ duy nhất được xây dựng từ luồng - mà còn mountcó thể và được tích hợp vào kernel vfs:

Từ giả tệp. Ví dụ :

# 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

Bạn cũng có thể sử dụng btrfs (send|receive)để truyền phát một subvolume vào bất kỳ stdinmáy nén nào có thể sử dụng được mà bạn thích. Subvolume này không cần tồn tại trước khi bạn quyết định sử dụng nó làm thùng chứa nén, tất nhiên.

Tuy nhiên, về squashfs...

Tôi không tin rằng tôi đang làm công lý này. Đây là một ví dụ rất đơn giản:

 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

Đó chỉ là -pđối số nội tuyến cho mksquash. Bạn có thể nguồn một tệp có -pfchứa nhiều tệp như bạn muốn. Định dạng rất đơn giản - bạn xác định tên / đường dẫn của tệp mục tiêu trong hệ thống tệp của kho lưu trữ mới, bạn cung cấp cho nó chế độ và chủ sở hữu, sau đó bạn cho nó biết quá trình nào để thực thi và đọc thiết bị xuất chuẩn. Bạn có thể tạo bao nhiêu tùy thích - và bạn có thể sử dụng LZMA, GZIP, LZ4, XZ ... hmm có nhiều ... định dạng nén tùy thích. Và kết quả cuối cùng là một kho lưu trữ mà bạn cd.

Thêm về định dạng mặc dù:

Tất nhiên, đây không chỉ là một kho lưu trữ - nó là một hình ảnh hệ thống tệp Linux có thể nén, có thể gắn kết. Định dạng của nó là kernel Linux - nó là một hệ thống tập tin được hỗ trợ kernel vanilla. Theo cách này, nó phổ biến như nhân Linux vanilla. Vì vậy, nếu bạn nói với tôi rằng bạn đang chạy một hệ thống Linux vanilla mà tarchương trình chưa được cài đặt thì tôi sẽ nghi ngờ - nhưng tôi có thể sẽ tin bạn. Nhưng nếu bạn nói với tôi rằng bạn đang chạy một hệ thống vanilla Linux mà squashfshệ thống tập tin không được hỗ trợ thì tôi sẽ không tin bạn.


Mike, chúng tôi có thể gây rắc rối cho bạn để tạo một ví dụ nhỏ khép kín để mọi người có thể thử nghiệm nó không? Có vẻ như bạn có thể đang làm ít nhất một phần của điều đó ở trên, nhưng tôi không chắc chắn. Trong input f 444 root root dd if=/dev/sda1 bs=1024 count=10là f đầu vào tập tin? Có lẽ sẽ tốt hơn nếu tạo ra một thiết bị đồ chơi, điền dữ liệu và viết từ nó? Và tất cả điều này đòi hỏi phải root?
Faheem Mitha

@FaheemMitha - vâng tôi có thể làm điều đó, nhưng tôi đã không làm điều đó ở đây. Liên kết là tài liệu chính thức - nó được lấy thẳng từ nó. Nó sẽ tốt hơn nếu tôi làm một ví dụ lệnh mặc dù. Tôi đã làm nó trước đây - nó khá tuyệt. Dù sao - inputtệp là một tệp trong squashfskho lưu trữ - hình ảnh hệ thống tệp kết quả từ việc chạy lệnh. Khi bạn làm, mksquashbạn có thể chỉ định các lệnh giả này cho các lệnh đang chạy và từ đó lệnh stdoutđược bắt tại thời điểm nén.
mikeerv

@FaheemMitha - oh, và nó không yêu cầu root để thực hiện việc nén , mặc dù nó có thể thực hiện việc gắn kết - đó là một hình ảnh hệ thống tập tin có kết quả. Đó là cùng một hệ thống tệp mà tất cả các đĩa Linux Live sử dụng. Trong thực tế - một điều rất thú vị - là bạn có thể tạo một hình ảnh sở hữu gốc bằng cách sử dụng các tệp giả đó mà không phải là root - như cài đặt các tệp thiết bị của bạn và các số MAJ: MIN tùy ý.
mikeerv

Tôi đoán nó có thể tạo một tập tin thiết bị, ghi vào nó, và sau đó từ nó mà không bao giờ gắn nó, phải không? Vì vậy, có lẽ nó không yêu cầu root, điều này rõ ràng sẽ thích hợp hơn.
Faheem Mitha

Chà, không có btrfs nào ở đây, nên sẽ không hoạt động. Nhưng squashfs là đủ điên rồ nó có thể làm việc. Mặc dù nó có nhược điểm là không phải là một định dạng lưu trữ phổ biến.
derobert

4

Bạn gặp vấn đề khiến tôi bối rối một thời gian và tôi nghĩ rằng tôi đã tìm ra giải pháp hiệu quả.

Tôi nghĩ bạn có thể đạt được những gì bạn muốn với 7z bằng cách sử dụng -si{NAME}cờ.

Bạn sẽ có thể thích ứng với nhu cầu của bạn.

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

EDIT : Loại bỏ việc sử dụng mèo vô dụng


Sẽ rất hữu ích khi có một ví dụ nhỏ mà mọi người có thể thử. Ví dụ: tạo một thiết bị khối, viết cho nó, sau đó viết ra từ nó. Không yêu cầu root sẽ là một cộng.
Faheem Mitha

Trong ví dụ / dev / sda1 là một thiết bị khối. Lệnh cat có mục đích đưa nội dung của thiết bị vào stdout. Sau đó, 7z tạo (hoặc cập nhật) kho lưu trữ và lưu trữ dữ liệu trong tên tệp được chỉ định bởi tham số -si từ stdin. Kết quả trong kho lưu trữ là nội dung của từng thiết bị khối. Lệnh "cat" cần root để đọc dữ liệu từ thiết bị.
Tony

Đó là một cách sử dụng mèo vô dụng , nhưng mặt khác thì phù hợp với hóa đơn khá tốt. Điều kỳ lạ là 7ztrang của tôi không đề cập đến -si có thể lấy tên tệp, nhưng nó hoạt động. Nó không hoàn hảo (đầu ra không thể được dẫn ở đâu đó), nhưng chắc chắn là tốt nhất cho đến nay đầu ra ở định dạng chung.
derobert

@FaheemMitha yêu cầu root hay không sẽ phụ thuộc vào cài đặt quyền trên hệ thống của bạn, mặc dù chỉ root mới có thể tạo các thiết bị khối mới.
derobert

@derobert Đã gỡ con mèo :)
Tony
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.