Как мне подключить блочное устройство в Linux?

656
clearcom0

Я пытаюсь получить только последние 1024 байта / dev / sda2. Когда я это делаю sudo tail -c 1024 /dev/sda2 | hd, приглашение просто зависает, пока я не нажму Ctrl-C. Однако, когда я tail -c 1024 ddfilecopyofsda2 | hd, я немедленно получаю хороший вывод из последних 1024 байтов файла. Я прочитал здесь ( https://unix.stackexchange.com/questions/60034/what-are-character-special-and-block-special-files-in-a-unix-system ), что «блочные устройства обычно доступны для поиска, "так чего мне не хватает?

3

1 ответ на вопрос

7
Deltik

Вот один из способов получить последние 1024 байта блочного устройства:

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

Замените DEVICEпуть устройства. В вашем случае вы бы использовали /dev/sda2.


Теперь на более интересный вопрос, чтобы ответить ...

Почему tail -c 1024 /dev/sda2поиск по всему диску?

Причина в том, как tailэто реализовано. Когда tailзнает размер файла, который он читает, он точно знает, сколько искать. В противном случае, он должен прочитать файл или поток полностью, чтобы выяснить, как далеко отсчитывать.

С трубами это имеет смысл, вроде cat /dev/sda2 | tail -c 1024. tailполучает содержимое в виде потока и не может знать, когда данные закончатся.

Вы можете ожидать, tail -c 1024 /dev/sda2что сможете определить размер /dev/sda2, но на самом деле, когда вы tailсмотрите вверх /dev/sda2, он открывается как блочное устройство вместо обычного файла.

Детали реализации - это tailвызовы fstat()для получения информации о файле.

tail на обычном файле

Вот соответствующая часть straceпримера tailоткрытия файла:

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()обеспечивает st_size=175500. Теперь tailпросто нужно отсчитать 1024 байта:

175500 - 1024 = 174476

... и это именно то, что tailделает:

lseek(3, 174476, SEEK_SET) = 174476 

tail на блочном устройстве

fstat() не возвращает размер на этот раз!

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

С нет st_size, tailне может знать, как далеко искать, поэтому по умолчанию он читает через все блочное устройство до конца.

Вот почему вы должны обычно использовать инструменты блочных устройств, например, ddдля управления блочными устройствами, а не инструменты, предназначенные для обычных файлов, таких как tail.


Вы можете спросить: «Как blockdev --getsize64быстро получить размер блочного устройства?»

Вот sudo strace -vvvfts1000 blockdev --getsize64 /dev/sda:

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

blockdevпредназначен для получения ioctls блочного устройства и BLKGETSIZE64получения размера блочного устройства.


Что касается почему tail не делает BLKGETSIZE64, я не знаю. Исходный код показывает:

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

Из этой строки я знаю только то, что без них S_ISBLK()авторы не имели в виду tailподдержку блочных устройств.

Хотелось бы, чтобы я проголосовал за этот ответ примерно 5 раз! Спасибо за такое подробное объяснение! clearcom0 7 лет назад 2
Примечание GNU dd начиная с 8.16 (2012-03-26) поддерживает параметр `iflag = skip_bytes`. Это позволяет эффективно пропускать произвольную часть ввода, будучи независимым от размера блока, используемого для ввода / вывода. Часто хочется использовать большое «bs» для эффективности. pixelbeat 6 лет назад 1
Спасибо @pixelbeat! Я обновил свой ответ, чтобы использовать вместо него `dd iflag = skip_bytes`. Deltik 6 лет назад 0

Похожие вопросы