Warum hört `tar` in` dd` nicht auf, bis die Platte voll ist?

18

Ich habe ein Tar-Archiv eines einzelnen Disk-Image. Das Bild in dieser Teer-Datei ist ungefähr 4 GB groß. Ich leite die Ausgabe von tar xfin ddum das Disk-Image auf eine SD-Karte zu schreiben. Der Speicherauszug stoppt nie, bis die Karte voll ist. Hier ist meine Shell-Sitzung:

$ ls -l disk.img.tgz
-rw-r--r-- 1 confus confus 192M Okt  5 00:53

$ tar -tvf disk.img.tgz
-rw-r--r-- root/root 4294968320 2018-10-05 00:52 disk.img

$ lsblk -lb /dev/sdc
NAME MAJ:MIN RM        SIZE RO TYPE MOUNTPOINT
sdc    8:32   1 16022241280  0 disk

$ tar zxf disk.img.tgz -O | sudo dd status=progress conv=sync bs=1M of=/dev/sdc
[sudo] password for user: 
15992881152 bytes (16 GB, 15 GiB) copied, 212 s, 75,4 MB/s 
dd: error writing '/dev/sdc': No space left on device
0+15281 records in
15280+0 records out
16022241280 bytes (16 GB, 15 GiB) copied, 217,67 s, 73,6 MB/s

Warum? Es sollte aufhören, nachdem ein Treffer das 4 GB-Image auf den 16 GB-Wagen geschrieben hat, und es sollte nie der Platz ausgehen!

verwechseln
quelle
Verfügen Sie über ausreichend Speicherplatz, um dies auszuführen ddund in eine andere Datei zu schreiben? tar zxf disk.img.tgz -O | dd status=progress conv=sync bs=1M of=/path/to/some/file/on/disk? Wenn ja, erhalten Sie dann eine genaue Kopie der Originaldatei?
Andy Dalton
2
Warum haben Sie conv=sync? Meinten Sie conv=fsyncvielleicht verwenden?
Ralph Rönnquist
Sind Sie sicher, dass dies die wahre Größe der Datei ist? Ich weiß, dass gzip nur 32 Bits hat, in denen Dateigrößen gespeichert werden können, so dass die Dateigröße über 4 GB falsch ist. Ich bin mir nicht sicher, ob tar eine ähnliche Einschränkung hat.
David Conrad

Antworten:

50

Es ist, weil du es falsch machst.

Sie verwenden, bs=1Maber das Lesen von stdin, pipe, führt zu kleineren Lesungen. Tatsächlich haben Sie laut dd keinen vollständigen Lesevorgang erhalten.

Und dann haben Sie conv=syncwelche Ergänzungen unvollständig mit Nullen gelesen.

0+15281 records in
15280+0 records out

ddErhielt 0 vollständige und 15281 unvollständige Lesevorgänge und schrieb 15280 vollständige Blöcke (conv = Sync zero filled). Die Ausgabe ist also viel größer als die Eingabe, bis Sie keinen Platz mehr haben.

   sync   pad  every  input  block  with  NULs to ibs-size; when used with
          block or unblock, pad with spaces rather than NULs

Um dies zu lösen, können Sie entfernen conv=syncund hinzufügen iflag=fullblock.


Betrachten Sie zur Veranschaulichung, yeswelche standardmäßig unendlich "y \ ny \ ny \ n" ausspuckt.

$ yes
y
y
y
^C
$ yes | hexdump -C
00000000  79 0a 79 0a 79 0a 79 0a  79 0a 79 0a 79 0a 79 0a  |y.y.y.y.y.y.y.y.|
*

Damit dd bs=1M conv=syncsieht es so aus:

$ yes | dd bs=1M conv=sync | hexdump -C
00000000  79 0a 79 0a 79 0a 79 0a  79 0a 79 0a 79 0a 79 0a  |y.y.y.y.y.y.y.y.|
*
0001e000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00100000  79 0a 79 0a 79 0a 79 0a  79 0a 79 0a 79 0a 79 0a  |y.y.y.y.y.y.y.y.|
*
00112000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*

Daher wird ein unvollständiger Block mit "y \ ny \ ny \ n" (0x00000 - 0x1e000, 122880 Bytes) abgerufen, und die verbleibenden 1 MB werden als Nullen (0x01e000 - 0x100000, 925696 Bytes) geschrieben. In den meisten Fällen möchten Sie dies nicht. Das Ergebnis ist ohnehin zufällig, da Sie keine wirkliche Kontrolle darüber haben, wie unvollständig die einzelnen Lesevorgänge werden. Wie hier ist der zweite Lesevorgang nicht länger 122880 Bytes, sondern 73728 Bytes.

dd conv=syncist selten nützlich und selbst in Fällen, in denen es erwünscht wäre, Nullen zu schreiben, wenn Lesefehler auftreten, wird dies furchtbar schief gehen.

Frostschutz
quelle
In diesem Fall hätte das Ausführen des ddBefehls unter strace(Linux vorausgesetzt) ​​gezeigt, dass auf jeden kurzen Lesevorgang von der Pipe ein vollständiger 1-MB-Schreibvorgang folgte.
Andrew Henle
2
@AndrewHenle braucht dafür nicht einmal ein bisschen Kraft, nur die Ausgabe zu betrachten reicht aus. Illustration
hinzugefügt
Dies zeigt auch, warum der ddBefehl grundsätzlich fehlerhaft und unbrauchbar ist. Es ist angegeben, in einzelnen reads und writes zu arbeiten, aber diese Operationen sind so angegeben, dass sie immer kurze Lese- oder Schreibvorgänge erzeugen können, und es ist kein Fehler. Infolgedessen ddhängt das Verhalten von von nicht spezifiziertem Verhalten ab.
R ..
Vielen Dank für die sehr lehrreiche Antwort. Wie jemand anderes vorschlug, war ich ein Arsch und vermischte die vielen Möglichkeiten dd, aber es führte mich dazu, etwas von dir zu lernen. Was ich mir noch nicht ganz sicher bin ist, ob und wann ddich gekündigt hätte. Ich gehe davon aus, dass dies der Fall wäre, aber da tatsächlich 1 Teil tatsächliche Daten und 9 Teil Nullen geschrieben wurden, hätte es nach dem Schreiben von etwa 40 G aufgehört. Ist das korrekt?
con-f-use
@R .., diese Funktion ist sehr nützlich bei Gerätetreibern, die sich um die Blockgröße von Lese- und Schreibvorgängen kümmern. Ich erinnere mich, einige Bandlaufwerke verwendet zu haben, die sich darum kümmerten. Obwohl in diesem Fall ist es offensichtlich nicht notwendig, könnte man leitet es einfach direkt auf die Festplatte (nicht einen Live - Fortschrittsbericht bekommen, obwohl)
ilkkachu