Wie bereite ich ein Blockgerät in Linux vor?

624
clearcom0

Ich versuche gerade die letzten 1024 Bytes von / dev / sda2 zu bekommen. Wenn ich dies tue sudo tail -c 1024 /dev/sda2 | hd, bleibt die Aufforderung so lange hängen, bis ich Strg-C drücke. Wenn ich jedoch tail -c 1024 ddfilecopyofsda2 | hdbekomme ich sofort eine schöne Ausgabe der letzten 1024 Bytes der Datei. Ich habe hier ( https://unix.stackexchange.com/questions/60034/what-are-character-special-and-block-special-files-in-a-unix-system ) gelesen, dass "Block-Geräte normalerweise gesucht werden können. "also was vermisse ich?

3

1 Antwort auf die Frage

7
Deltik

So können Sie die letzten 1024 Bytes eines Blockgeräts abrufen:

last_bytes() { sudo dd if=$2 iflag=skip_bytes skip=$(($(sudo blockdev --getsize64 $2) - $1)) bs=1M ; } ; last_bytes 1024 DEVICE 

Ersetzen Sie DEVICEdurch den Gerätepfad. In Ihrem Fall würden Sie verwenden /dev/sda2.


Nun zu einer interessanteren Frage zu beantworten ...

Warum wird tail -c 1024 /dev/sda2die gesamte Festplatte durchsucht?

Der Grund ist, wie tailumgesetzt wird. Wenn taildie Größe der zu lesenden Datei bekannt ist, weiß sie genau, wie viel sie suchen muss. Andernfalls muss die Datei oder der Stream vollständig gelesen werden, um herauszufinden, wie weit zurückgezählt wird.

Bei Rohren macht es Sinn, wie cat /dev/sda2 | tail -c 1024. tailempfängt den Inhalt als Stream und hat keine Möglichkeit zu wissen, wann die Daten enden.

Sie können davon ausgehen tail -c 1024 /dev/sda2, dass Sie die Größe ermitteln können /dev/sda2, aber wenn Sie tailnachschlagen /dev/sda2, wird sie als Blockgerät anstelle einer regulären Datei geöffnet.

Das Implementierungsdetail ist das tailAufrufen fstat(), um Informationen über die Datei abzurufen.

tail in einer regulären Datei

Hier ist der relevante Teil straceeines Beispiels für das tailÖffnen einer Datei:

21:30:27 open("/var/log/syslog", O_RDONLY) = 3 21:30:27 fstat(3, ) = 0 21:30:27 lseek(3, 0, SEEK_CUR) = 0 21:30:27 lseek(3, 174476, SEEK_SET) = 174476 

fstat()bietet st_size=175500. Jetzt müssen tailnur noch 1024 Bytes gezählt werden:

175500 - 1024 = 174476

… Und genau das tailmacht es:

lseek(3, 174476, SEEK_SET) = 174476 

tail auf einem Blockgerät

fstat() gibt die Größe dieses Mal nicht zurück !:

21:29:43 open("/dev/sda", O_RDONLY) = 3 21:29:43 fstat(3, ) = 0 

Ohne st_size, tailkann nicht wissen, wie weit zu suchen, so wird standardmäßig das Lesen durch das gesamte Block - Gerät bis zum Ende.

Aus diesem Grund sollten Sie generell Blockgerätetools verwenden dd, um Blockgeräte zu manipulieren, anstatt Werkzeuge für normale Dateien wie tail.


Sie fragen sich vielleicht: "Wie bekommt man blockdev --getsize64schnell die Größe des Blockgerätes?"

Hier ist sudo strace -vvvfts1000 blockdev --getsize64 /dev/sda:

21:53:15 open("/dev/sda", O_RDONLY) = 3 21:53:15 ioctl(3, BLKGETSIZE64, [512110190592]) = 0 

blockdevsoll Blockgerät-Ioctls erhalten und BLKGETSIZE64erhält die Größe des Blockgeräts.


Was, warum tail nicht tut BLKGETSIZE64, weiß ich nicht. Der Quellcode zeigt:

#define IS_TAILABLE_FILE_TYPE(Mode) \ (S_ISREG (Mode) || S_ISFIFO (Mode) || S_ISSOCK (Mode) || S_ISCHR (Mode)) 

Ich weiß nur aus dieser Zeile, dass ohne S_ISBLK()die Autoren keine tailBlockgeräte unterstützt werden sollen.

Ich wünschte, ich könnte diese Antwort etwa fünfmal bestätigen! Vielen Dank für diese ausführliche Erklärung! clearcom0 vor 7 Jahren 2
Hinweis GNU dd seit 8.16 (2012-03-26) unterstützt die Option "iflag = skip_bytes". Dies ermöglicht es einem, einen beliebigen Teil der Eingabe effizient zu überspringen, während er unabhängig von der für E / A verwendeten Blockgröße ist. Oft möchte man aus Effizienzgründen ein großes "bs" verwenden. pixelbeat vor 6 Jahren 1
Danke @pixelbeat! Ich habe meine Antwort so aktualisiert, dass stattdessen `dd iflag = skip_bytes` verwendet wird. Deltik vor 6 Jahren 0