Como faço para ligar um dispositivo de bloco no Linux?

3

Estou tentando obter apenas os últimos 1024 bytes de / dev / sda2. Quando eu faço sudo tail -c 1024 /dev/sda2 | hd , o prompt apenas trava até que eu pressione Ctrl-C. No entanto, quando eu tail -c 1024 ddfilecopyofsda2 | hd , eu recebo imediatamente uma boa saída dos últimos 1024 bytes do arquivo. Eu li aqui ( link ) que "dispositivos de bloco são normalmente procurados", então o que estou faltando?

    
por clearcom0 11.11.2017 / 03:55

1 resposta

7

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.

    
por 11.11.2017 / 05:07

Tags