3

Я пытаюсь получить только последние 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), что «блочные устройства обычно доступны для поиска, "так чего мне не хватает?

1 ответ1

7

Вот один из способов получить последние 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, {st_dev=makedev(0, 22), st_ino=4715, st_mode=S_IFREG|0640, st_nlink=1, st_uid=104, st_gid=4, st_blksize=131072, st_blocks=54, st_size=175500, st_atime=2017/11/10-21:28:39.243133398, st_mtime=2017/11/10-21:30:20.438031639, st_ctime=2017/11/10-21:30:20.438031639}) = 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, {st_dev=makedev(0, 6), st_ino=17488, st_mode=S_IFBLK|0660, st_nlink=1, st_uid=0, st_gid=6, st_blksize=4096, st_blocks=0, st_rdev=makedev(8, 0), st_atime=2017/11/10-09:21:15.643998960, st_mtime=2017/11/10-09:21:15.555998962, st_ctime=2017/11/10-09:21:15.555998962}) = 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 поддержку блочных устройств.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .