Por que colocar o `tar` no` dd` não pára até que o disco esteja cheio?

18

Eu tenho um arquivo tar de uma única imagem de disco. A imagem dentro deste arquivo tar tem cerca de 4 GB de tamanho. Eu canalizo a saída tar xfpara ddpara gravar a imagem do disco em um cartão SD. O despejo de disco nunca para até que o cartão esteja cheio. Aqui está minha sessão shell:

$ ls -l disk.img.tgz
-rw-r--r-- 1 confus confus 192M Okt  5 00:53

$ tar -tvf disk.img.tgz
-rw-r--r-- root/root 4294968320 2018-10-05 00:52 disk.img

$ lsblk -lb /dev/sdc
NAME MAJ:MIN RM        SIZE RO TYPE MOUNTPOINT
sdc    8:32   1 16022241280  0 disk

$ tar zxf disk.img.tgz -O | sudo dd status=progress conv=sync bs=1M of=/dev/sdc
[sudo] password for user: 
15992881152 bytes (16 GB, 15 GiB) copied, 212 s, 75,4 MB/s 
dd: error writing '/dev/sdc': No space left on device
0+15281 records in
15280+0 records out
16022241280 bytes (16 GB, 15 GiB) copied, 217,67 s, 73,6 MB/s

Por quê? Ele deve parar após o hit gravar a imagem de 4 GB no carrinho de 16 GB e nunca ficar sem espaço!

confundir
fonte
Você tem espaço em disco para tentar executar isso dde gravá-lo em outro arquivo? tar zxf disk.img.tgz -O | dd status=progress conv=sync bs=1M of=/path/to/some/file/on/disk? Em caso afirmativo, isso fornece uma cópia exata do arquivo original?
Andy Dalton
2
Por que você tem conv=sync? Você quis usar conv=fsynctalvez?
Ralph Rönnquist 5/10/19
Você tem certeza de que é o tamanho real do arquivo? Eu sei que o gzip tem apenas 32 bits para armazenar tamanhos de arquivo, portanto, o tamanho dos arquivos com mais de 4 GB está errado. Não tenho certeza se o alcatrão tem uma limitação semelhante.
David Conrad

Respostas:

50

É porque você está fazendo errado.

Você está usando, bs=1Mmas a leitura de stdin, pipe, terá leituras menores. De fato, de acordo com o dd, você não obteve uma única leitura completa.

E então você tem conv=syncquais complementos leituras incompletas com zeros.

0+15281 records in
15280+0 records out

ddrecebeu 0 leituras completas e 15281 incompletas e escreveu 15280 blocos completos (conv = sincronização zero preenchida). Portanto, a saída é muito maior do que a entrada, até que você não tenha mais espaço.

   sync   pad  every  input  block  with  NULs to ibs-size; when used with
          block or unblock, pad with spaces rather than NULs

Para resolver isso, você pode remover conv=synce adicionar iflag=fullblock.


Para ilustrar, considere yesque, por padrão, exibe "y \ ny \ ny \ n" infinito.

$ yes
y
y
y
^C
$ yes | hexdump -C
00000000  79 0a 79 0a 79 0a 79 0a  79 0a 79 0a 79 0a 79 0a  |y.y.y.y.y.y.y.y.|
*

Com dd bs=1M conv=syncisso fica assim:

$ yes | dd bs=1M conv=sync | hexdump -C
00000000  79 0a 79 0a 79 0a 79 0a  79 0a 79 0a 79 0a 79 0a  |y.y.y.y.y.y.y.y.|
*
0001e000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00100000  79 0a 79 0a 79 0a 79 0a  79 0a 79 0a 79 0a 79 0a  |y.y.y.y.y.y.y.y.|
*
00112000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*

Portanto, ele obtém um bloco incompleto de "y \ ny \ ny \ n" (0x00000 - 0x1e000, 122880 bytes) e grava o 1M restante como zeros (0x01e000 - 0x100000, 925696 bytes). Na maioria dos casos, você não deseja que isso aconteça. De qualquer forma, o resultado é aleatório, pois você não tem controle real sobre o quão incompleta cada leitura se tornaria. Como aqui, a segunda leitura não é mais 122880 bytes, mas 73728 bytes.

dd conv=syncraramente é útil e, mesmo nos casos em que seria bem-vindo, como escrever zeros quando você obtém erros de leitura, as coisas vão dar terrivelmente errado.

frostschutz
fonte
Nesse caso, executar o ddcomando em strace(assumindo Linux) mostraria que cada leitura curta do canal era seguida por uma gravação completa de 1 MB.
Andrew Henle
2
O @AndrewHenle nem precisa de strace para isso, basta olhar para a saída. Adicionada uma ilustração
frostschutz 5/1018
Isso também ilustra por que o ddcomando é fundamentalmente quebrado e inutilizável. Ele é especificado para operar em reads e s individuais write, mas essas operações são especificadas para que possam sempre produzir leituras ou gravações curtas, e isso não é um erro. Como conseqüência, o comportamento de dddepende de um comportamento não especificado.
R ..
Obrigado pela resposta muito educacional. Como alguém sugeriu, eu estava sendo um idiota e misturei muitas opções dd, mas isso me levou a aprender algo com você. O que ainda não tenho certeza absoluta é se e quando ddterminariam. Eu suponho que sim, mas como na verdade ele estava gravando 1 parte de dados reais e 9 partes de zeros, teria parado depois de escrever sobre 40G. Isso está correto?
con-f-use
@R .., esse recurso é muito útil com drivers de dispositivo que se preocupam com o tamanho do bloco de leituras e gravações. Lembro-me de usar algumas unidades de fita que se importavam com isso. Embora, neste caso, não é obviamente necessário, apenas um poderia redirecionar diretamente para o disco (não recebendo um relatório de progresso ao vivo, embora)
ilkkachu