GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Wann ist Dd zum Kopieren von Daten geeignet? (oder wann sind Read() und Write() partiell)?

Kurzfassung: Unter welchen Umständen ist dd sicher zum Kopieren von Daten zu verwenden, sicher bedeutet, dass kein Risiko einer Beschädigung aufgrund eines teilweisen Lesens oder Schreibens besteht?

Langfassung – Präambel: dd wird häufig verwendet, um Daten zu kopieren, insbesondere von oder zu einem Gerät (Beispiel). Ihm wird manchmal die mystische Eigenschaft zugeschrieben, auf Geräte auf einer niedrigeren Ebene als andere Tools zugreifen zu können (wobei tatsächlich die Gerätedatei die Magie ausübt) – dennoch dd if=/dev/sda ist dasselbe wie cat /dev/sda . dd wird manchmal für schneller gehalten, aber cat kann es in der Praxis schlagen. Trotzdem dd hat einzigartige Eigenschaften, die es manchmal wirklich nützlich machen.

Problem: dd if=foo of=bar ist tatsächlich nicht dasselbe wie cat <foo >bar . Auf den meisten Unices¹, dd führt einen einzelnen Aufruf von read() durch . (Ich finde POSIX verschwommen, was das „Lesen eines Eingabeblocks“ in dd ausmacht .) Wenn read() ein Teilergebnis zurückgibt (was laut POSIX und anderen Referenzdokumenten erlaubt ist, sofern die Implementierungsdokumentation nichts anderes sagt), wird ein Teilblock kopiert. Genau das gleiche Problem besteht für write() .

Beobachtungen :In der Praxis habe ich das dd gefunden kann mit Blockgeräten und regulären Dateien umgehen, aber das kann nur daran liegen, dass ich es nicht viel trainiert habe. Wenn es um Pipes geht, ist es nicht schwierig, dd zu setzen schuld; Versuchen Sie zum Beispiel diesen Code:

yes | dd of=out bs=1024k count=10

und überprüfen Sie die Größe des out Datei (es ist wahrscheinlich weit unter 10 MB).

Frage :Unter welchen Umständen ist dd sicher zum Kopieren von Daten? Mit anderen Worten, welche Bedingungen an die Blockgrößen, an die Implementierung, an die Dateitypen usw. können dafür sorgen, dass dd werden alle Daten kopiert?

(GNU dd hat einen fullblock -Flag, um es anzuweisen, read() aufzurufen oder write() in einer Schleife, um einen ganzen Block zu übertragen. Also dd iflag=fullblock ist immer sicher. Meine Frage bezieht sich auf den Fall, wenn diese Flags (die in anderen Implementierungen nicht vorhanden sind) nicht verwendet werden.)

¹
Ich habe OpenBSD, GNU Coreutils und BusyBox überprüft.

Akzeptierte Antwort:

Aus der Spezifikation:

  • Falls bs= expr Operand ist angegeben und keine anderen Konvertierungen als sync , noerror , oder notrunc angefordert werden, müssen die von jedem Eingangsblock zurückgegebenen Daten als separater Ausgangsblock geschrieben werden; wenn der read() gibt weniger als einen vollen Block und den sync zurück Konvertierung nicht angegeben ist, muss der resultierende Ausgabeblock die gleiche Größe wie der Eingabeblock haben.

Das ist also wahrscheinlich der Grund für Ihre Verwirrung. Ja, weil dd ist entworfen zum Blockieren standardmäßig teilweise read() s werden 1:1 auf partielles write() abgebildet s oder sync d out on tail padding NUL oder space chars to bs= Größe, wenn conv=sync angegeben ist.

Das bedeutet, dass dd ist sicher zum Kopieren von Daten (ohne Risiko einer Beschädigung durch teilweises Lesen oder Schreiben) in jedem Fall außer einem, in dem es willkürlich durch count= begrenzt wird Argument, weil sonst dd wird gerne write() seine Ausgabe in gleichgroßen Blöcken zu denen, in denen seine Eingabe read() war bis es read() ist komplett durch. Und selbst dieser Vorbehalt ist nur wahr wenn bs= angegeben ist oder obs= ist nicht angegeben, wie der nächste Satz in der Spezifikation besagt:

  • Falls bs= expr Operand ist nicht angegeben, oder eine andere Konvertierung als sync , noerror , oder notrunc angefordert wird, wird die Eingabe verarbeitet und in Ausgabeblöcken voller Größe gesammelt bis das Ende der Eingabe erreicht ist.
Verwandte:Debian – wiederkehrender Verlust der drahtlosen Verbindung?

Ohne ibs= und/oder obs= Argumenten kann das egal sein – weil ibs und obs sind beide standardmäßig gleich groß. Sie können jedoch explizit werden über die Eingabepufferung durch Angabe verschiedener Größen für entweder und nicht Angabe von bs= (weil es Vorrang hat) .

Wenn Sie beispielsweise Folgendes tun:

IN| dd ibs=1| OUT

…dann ein POSIX dd wird write() in Blöcken von 512 Byte durch Sammeln jedes einzelne read() Byte in einen einzelnen Ausgabeblock.

Andernfalls, falls doch …

IN| dd obs=1kx1k| OUT

…ein POSIX dd wird read() maximal 512 Bytes auf einmal, aber write() jeden Megabyte großen Ausgabeblock (Kernel erlaubt und ausgenommen möglicherweise den letzten – weil das EOF ist) vollständig durch Sammeln von Eingaben in Ausgabeblöcken in voller Größe .

Aber auch aus der Spezifikation:

  • count=n
    • Nur n kopieren Eingabeblöcke.

count= wird auf i?bs= abgebildet Blöcke usw., um eine willkürliche Begrenzung von count= zu handhaben portabel benötigen Sie zwei dd s. Am praktischsten geht das mit zwei dd s besteht darin, die Ausgabe des einen in die Eingabe des 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 bei Angabe von [io]bs= argumentiert, dass Sie, um dies sicher zu tun, solche Werte innerhalb des vom System definierten PIPE_BUF halten müssen Grenze. POSIX gibt an, dass der Systemkern nur atomisches read() garantieren muss s und write() s innerhalb der Grenzen von PIPE_BUF wie in limits.h definiert . POSIX garantiert, dass PIPE_BUF mindestens sein …

  • {_POSIX_PIPE_BUF}
    • Maximale Anzahl von Bytes, die beim Schreiben in eine Pipe garantiert atomar sind.
    • Wert:512

(was auch der voreingestellte dd ist I/O-Blockgröße) , aber der tatsächliche Wert beträgt normalerweise mindestens 4k. Auf einem aktuellen Linux-System sind es standardmäßig 64 KB.

Wenn Sie also Ihren dd einrichten Prozesse sollten Sie es auf einem Block Faktor tun basierend auf drei Werten:

  1. bs =( obs =PIPE_BUF oder weniger )
  2. n =gewünschte Gesamtzahl gelesener Bytes
  3. count =n / bs

Wie:

yes | dd obs=1k | dd bs=1k count=10k of=/dev/null
10240+0 records in
10240+0 records out
10485760 bytes (10 MB) copied, 0.1143 s, 91.7 MB/s

Sie müssen i/o mit dd synchronisieren um nicht durchsuchbare Eingaben zu behandeln. Mit anderen Worten, machen Sie Pipe-Puffer explizit und sie stellen kein Problem mehr dar. Das ist dd ist für. Die unbekannte Größe ist hier yes Puffergröße – aber wenn Sie das für einen bekannten ausschließen Menge mit einem anderen dd dann kann eine wenig informierte Multiplikation dd ergeben sicher zum Kopieren von Daten (ohne Risiko der Beschädigung durch teilweises Lesen oder Schreiben) selbst wenn die Eingabe willkürlich mit count= eingeschränkt wird mit jedem beliebigen Eingabetyp auf jedem POSIX-System und ohne ein einziges Byte zu verpassen.

Hier ist ein Ausschnitt aus der POSIX-Spezifikation:

  • ibs= expr
    • Geben Sie die Eingangsblockgröße in Bytes mit expr an (Standard ist 512) .
  • obs= expr
    • Geben Sie die Ausgabeblockgröße in Bytes mit expr an (Standard ist 512) .
  • bs= expr
    • Stellen Sie sowohl die Eingangs- als auch die Ausgangsblockgröße auf expr ein Bytes, ersetzt ibs= und obs= . Wenn keine Konvertierung außer sync , noerror , und notrunc angegeben ist, wird jeder Eingabeblock als einzelner Block in die Ausgabe kopiert, ohne kurze Blöcke zu aggregieren.
Verwandte:Wie kann das Terminal [email protected] in Fettschrift anzeigen?

Einiges davon wird hier auch besser erklärt.


Linux
  1. Verwenden Sie den Netcat-Befehl zum Lesen und Schreiben von Daten über das Netzwerk unter Ubuntu 20.04

  2. Wann soll in Bash ein Alias, wann ein Skript und wann eine Funktion geschrieben werden?

  3. Wann sollte ich TCP_NODELAY und wann TCP_CORK verwenden?

  4. Wann auf EINTR prüfen und den Funktionsaufruf wiederholen?

  5. Wie kann ich von der seriellen Schnittstelle in C öffnen, lesen und schreiben?

So verwenden Sie den Netcat-Befehl zum Lesen und Schreiben von Daten über das Netzwerk

Süßes und Saures für Sysadmins und Ops

So installieren und verwenden Sie Okteta für RAW-Datendateien unter Linux

Pay-per-Click-Textanzeigen für Anwälte und Rechtsanwälte

Was ist eine verteilte Datenbank und wozu dienen verteilte Datensysteme?

Die 15 besten ökonometrischen und statistischen Software für Linux-Systeme