Kurzfassung: Unter welchen Umständen ist dd
die Verwendung zum Kopieren von Daten sicher, dh es besteht keine Gefahr der Beschädigung durch teilweises Lesen oder Schreiben?
Lange Version - Präambel: Wird dd
häufig zum Kopieren von Daten verwendet, insbesondere von oder auf ein Gerät ( Beispiel ). Es wird manchmal mystischen Eigenschaften zugeschrieben, auf Geräte auf einer niedrigeren Ebene als andere Tools zugreifen zu können (obwohl es tatsächlich die Gerätedatei ist, die die Magie ausübt) - und doch dd if=/dev/sda
ist es dasselbe wie cat /dev/sda
. dd
wird manchmal für schneller gehalten, cat
kann es aber in der Praxis übertreffen . Trotzdem dd
hat es einzigartige Eigenschaften, die es manchmal wirklich nützlich machen .
Problem: dd if=foo of=bar
ist in der Tat nicht das gleiche wie cat <foo >bar
. Bei den meisten Geräten dd
wird ein einzelner Anruf an getätigt read()
. (Ich finde POSIX unscharf, wenn es sich um das Einlesen eines Eingabeblocks handelt dd
.) Wenn read()
ein Teilergebnis zurückgegeben wird (das laut POSIX und anderen Referenzdokumenten zulässig ist, sofern in der Implementierungsdokumentation nichts anderes angegeben ist), wird ein Teilblock kopiert. Genau das gleiche Problem besteht für write()
.
Beobachtungen : In der Praxis habe ich festgestellt, dass dd
mit Blockgeräten und regulären Dateien umgegangen werden kann, aber das kann nur sein, dass ich nicht viel damit gemacht habe. Wenn es um Rohre geht, ist es nicht schwer, dd
Fehler zu machen. Versuchen Sie zum Beispiel diesen Code :
yes | dd of=out bs=1024k count=10
und überprüfen Sie die Größe der out
Datei (es ist wahrscheinlich deutlich unter 10 MB).
Frage : Unter welchen Umständen ist dd
die Verwendung zum Kopieren von Daten sicher? Mit anderen Worten, welche Bedingungen bezüglich der Blockgrößen, der Implementierung, der Dateitypen usw. können sicherstellen, dass dd
alle Daten kopiert werden?
( GNU dd hat ein fullblock
Flag, das es aufruft read()
oder sich write()
in einer Schleife befindet, um einen vollständigen Block zu übertragen. Das dd iflag=fullblock
ist also immer sicher. Meine Frage bezieht sich auf den Fall, dass diese Flags (die in anderen Implementierungen nicht vorhanden sind) nicht verwendet werden .)
¹ Ich habe OpenBSD, GNU Coreutils und BusyBox überprüft.
count
ist dasiflag=fullblock
obligatorisch (oder alternativiflag=count_bytes
). Es gibt keineoflag=fullblock
.Antworten:
Aus der Spezifikation :
bs=
expr
Operand angegeben ist und keine Konvertierungen ausgenommensync
,noerror
odernotrunc
angefordert werden , die von jedem Eingangsblock zurückgegebenen Daten werden als separater Ausgangsblock geschrieben werden; Wenn derread()
Rückgabewert kleiner als ein vollständiger Block ist und diesync
Konvertierung nicht angegeben ist, muss der resultierende Ausgabeblock dieselbe Größe wie der Eingabeblock haben.Das ist wahrscheinlich der Grund für Ihre Verwirrung. Ja, denn
dd
ist ausgelegt für die Sperrung, die standardmäßig Teilread()
s wird abgebildet 1: 1 zu Teil-write()
s, oder auchsync
auf Schwanz Polsterung NUL oder Raum Zeichen auf d outbs=
Größe , wennconv=sync
angegeben wird.Dies bedeutet, dass die Verwendung zum Kopieren von Daten sicher
dd
ist (ohne Verfälschungsrisiko aufgrund eines teilweisen Lese- oder Schreibvorgangs), jedoch in jedem Fall, in dem sie willkürlich durch eincount=
Argument begrenzt werden , da ansonstendd
diewrite()
Ausgabe gerne in gleich großen Blöcken erfolgt zu denen, in denen seine Eingabe war,read()
bis esread()
vollständig durch es ist. Und selbst diese Einschränkung nur wahr , wennbs=
angegeben wird , oderobs=
wird nicht angegeben, wie der nächste Satz in dem spec heißt es :bs=
expr
Operand nicht angegeben, oder eine Umwandlung außersync
,noerror
odernotrunc
beantragt wird, muss der Eingang verarbeitet und wird in volle Größe Ausgabeblocks gesammelt , bis das Ende der Eingabe erreicht ist.Ohne
ibs=
und / oderobs=
Argument kann dies keine Rolle - daibs
undobs
beide die gleiche Größe in der Standardeinstellung. Sie können sich jedoch explizit über die Eingabepufferung informieren, indem Sie entweder unterschiedliche Größen angeben oder keine angebenbs=
(da dies Vorrang hat) .Zum Beispiel, wenn Sie:
... dann ein POSIX
dd
wirdwrite()
in Blöcken von 512 Bytes , die durch das Sammeln jeden einzelnread()
Byte in einen einzigen Ausgangsblock.Ansonsten, wenn Sie tun ...
... a POSIX
dd
wirdread()
bei maximal 512 Byte zu einer Zeit, aberwrite()
jeder Megabyte-sized Ausgabeblock (kernel ermöglicht und mit Ausnahme vielleicht die letzten - weil das EOF ist) vollständig durch Eingabe in dem Sammeln voller Größe Ausgangsblocks .Aber auch aus der Spezifikation:
count=n
count=
Ordneti?bs=
Blöcke zu, und um eine willkürliche Beschränkung fürcount=
portabel zu handhaben, benötigen Sie zweidd
s. Der praktischste Weg, dies mit zweidd
s zu tun, besteht darin, die Ausgabe von einem in die Eingabe eines anderen zu leiten, was uns sicherlich in den Bereich des Lesens / Schreibens einer speziellen Datei versetzt, unabhängig vom ursprünglichen Eingabetyp.Eine IPC-Pipe bedeutet, dass Sie bei der Angabe von
[io]bs=
Argumenten, um dies sicher zu tun, diese Werte innerhalb des vom System festgelegtenPIPE_BUF
Grenzwerts halten müssen. POSIX besagt, dass der Systemkern nur Atomeread()
undwrite()
Atome innerhalb derPIPE_BUF
in definierten Grenzen garantieren darflimits.h
. POSIX garantiert,PIPE_BUF
dass mindestens ...{_POSIX_PIPE_BUF}
... (was auch die Standard-
dd
E / A-Blockgröße ist) , aber der tatsächliche Wert beträgt normalerweise mindestens 4 KB . Auf einem aktuellen Linux-System sind es standardmäßig 64 KB.Wenn Sie also Ihre
dd
Prozesse einrichten, sollten Sie einen Blockfaktor verwenden , der auf drei Werten basiert:PIPE_BUF
oder kleiner)Mögen:
Sie müssen i / ow / synchronisieren
dd
, um nicht suchbare Eingaben zu verarbeiten. Mit anderen Worten, machen Sie Pipe-Puffer explizit und sie hören auf, ein Problem zu sein. Dafürdd
ist es da. Die unbekannte Größe ist hieryes
die Puffergröße - aber wenn Sie diese mit einer anderen auf eine bekannte Größe beschränken,dd
kann ein wenig informierte Multiplikationdd
sicheres Kopieren von Daten ermöglichen (ohne Verfälschungsrisiko aufgrund eines teilweisen Lese- oder Schreibvorgangs). Selbst wenn die Eingabe mitcount=
einem beliebigen Eingabetyp auf einem beliebigen POSIX-System willkürlich eingeschränkt wird und kein einziges Byte fehlt.Hier ist ein Ausschnitt aus der POSIX-Spezifikation :
ibs=
expr
expr
obs=
expr
expr
bs=
expr
expr
Bytes ein und ersetzen Sieibs=
undobs=
. Wenn keine andere Konvertierung alssync
,noerror
undnotrunc
angegeben ist, wird jeder Eingabeblock als einzelner Block in die Ausgabe kopiert, ohne kurze Blöcke zu aggregieren.Einige Erklärungen dazu finden Sie auch hier .
quelle
Mit Sockets, Pipes oder ttys können read () und write () weniger als die angeforderte Größe übertragen. Wenn Sie dd für diese verwenden, benötigen Sie das Fullblock-Flag. Bei regulären Dateien und Blockgeräten gibt es jedoch nur zwei Fälle, in denen sie einen kurzen Lese- / Schreibvorgang ausführen können: Wenn Sie EOF erreichen oder wenn ein Fehler auftritt. Aus diesem Grund konnten ältere Implementierungen von dd ohne das Fullblock-Flag sicher für die Datenträgerduplizierung verwendet werden.
quelle
mke2fs
andernfalls still , weil es genanntwrite()
mit einigem nicht-Power-of-2 Größe (3kB IIRC) und die Kernel gerundet bis auf eine Potenz von 2.)cat </dev/sda >/dev/sdb
funktioniert gut, um eine Festplatte zu klonen.cat
wählt eine Puffergröße für die Leistung aus; Es werden keine gerätebezogenen Informationen vom Kernel abgerufen. Abgesehen von Bändern können Sieread()
undwrite()
zu einem Blockgerät mit beliebiger Größe. Zumindest unter Linuxst_blksize
hängt dies nur vom Dateisystem ab, in dem sich der Blockgeräte-Inode befindet, nicht vom zugrunde liegenden Gerät.