Aqui está uma maneira de obter os últimos 1024 bytes de um dispositivo de bloco:
last_bytes() { sudo dd if=$2 iflag=skip_bytes skip=$(($(sudo blockdev --getsize64 $2) - $1)) bs=1M ; } ; last_bytes 1024 DEVICE
Substitua DEVICE
pelo caminho do dispositivo. No seu caso, você usaria /dev/sda2
.
Agora, uma pergunta mais interessante para responder ...
Por que o tail -c 1024 /dev/sda2
pesquisa o disco inteiro?
O motivo é como tail
é implementado. Quando tail
sabe o tamanho do arquivo que está lendo, ele sabe exatamente quanto procurar. Caso contrário, ele tem que ler o arquivo ou transmitir todo o caminho para descobrir até que ponto contar de volta.
Com pipes, faz sentido, como cat /dev/sda2 | tail -c 1024
. tail
está recebendo o conteúdo como um fluxo e não tem como saber quando os dados terminarão.
Você pode esperar que tail -c 1024 /dev/sda2
consiga descobrir o tamanho de /dev/sda2
, mas, na verdade, quando tail
procurar /dev/sda2
, ele será aberto como um dispositivo de bloco em vez de um arquivo normal.
O detalhe da implementação é que tail
chama fstat()
para obter informações sobre o arquivo.
tail
em um arquivo normal
Veja a parte relevante de um strace
de um exemplo de tail
abrindo um arquivo:
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()
fornece st_size=175500
. Agora tail
só precisa contar 1024 bytes:
175500 - 1024 = 174476
… and this is exactly what
tail
does:lseek(3, 174476, SEEK_SET) = 174476
tail
em um dispositivo de bloco
fstat()
não retorna o tamanho desta vez!:
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
Sem st_size
, tail
não pode saber até onde procurar, por isso, o padrão é ler todo o dispositivo de bloco até o final.
É por isso que você deve usar ferramentas de dispositivos de bloco como dd
para manipular dispositivos de bloco em vez de ferramentas destinadas a arquivos comuns como tail
.
Você pode perguntar: "Como blockdev --getsize64
obtém rapidamente o tamanho do dispositivo de bloco?"
Aqui está o 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
destina-se a obter ioctls de dispositivo de bloco e BLKGETSIZE64
obtém o tamanho do dispositivo de bloco.
Quanto a por que tail
não faz BLKGETSIZE64
, não sei. O código-fonte mostra:
#define IS_TAILABLE_FILE_TYPE(Mode) \
(S_ISREG (Mode) || S_ISFIFO (Mode) || S_ISSOCK (Mode) || S_ISCHR (Mode))
Eu só sei dessa linha que sem S_ISBLK()
, os autores não quiseram que tail
suportasse dispositivos de bloco.