Crie dados aleatórios com o dd e obtenha "aviso de leitura parcial". Os dados após o aviso agora são realmente aleatórios?

16

Eu crio um arquivo de 1 TB com dados aleatórios com dd if=/dev/urandom of=file bs=1M count=1000000. Agora eu verifico kill -SIGUSR1 <PID>o progresso e obtenho o seguinte:

691581+0 Datensätze ein
691580+0 Datensätze aus
725174190080 Bytes (725 GB) kopiert, 86256,9 s, 8,4 MB/s
800950+1 Datensätze ein
800950+0 Datensätze aus
839856947200 Bytes (840 GB) kopiert, 99429,5 s, 8,4 MB/s
dd: warning: partial read (809620 bytes); suggest iflag=fullblock
803432+1 Datensätze ein
803431+1 Datensätze aus
842459273876 Bytes (842 GB) kopiert, 99791,3 s, 8,4 MB/s

Não consigo interpretar o aviso. O que diz isso? Meu arquivo é realmente aleatório após o aviso ou há algum problema? O que significa +0 ou +1 in 800950+1 Datensätze eine 800950+0 Datensätze aussignifica? Após o aviso, é +1. É uma contagem de erros?

excluir
fonte
Seria mais fácil responder se você pudesse traduzir as mensagens para o inglês. Além disso, defina "realmente aleatório". Para que nível de aleatoriedade você precisa, para que irá usá-la?
terdon
Para receber mensagens em inglês, use LC_ALL=Cna frente do comando, comoLC_ALL=C dd if=...
Volker Siegel

Respostas:

38

Resumo: ddé uma ferramenta irritante que é difícil de usar corretamente. Não o use, apesar dos inúmeros tutoriais que lhe dizem isso. ddtem uma vibração de "unix street cred", mas se você realmente entende o que está fazendo, saberá que não deve tocá-lo com uma vara de três metros.

ddfaz uma única chamada para a chamada do readsistema por bloco (definida pelo valor de bs). Não há garantia de que a readchamada do sistema retorne tantos dados quanto o tamanho do buffer especificado. Isso costuma funcionar para arquivos regulares e dispositivos de bloco, mas não para pipes e alguns dispositivos de caracteres. Consulte Quando o dd é adequado para copiar dados? (ou, quando são lidos () e gravados () parciais) para obter mais informações. Se a readchamada do sistema retornar menos de um bloco completo, ddtransferirá um bloco parcial. Ele ainda copia o número especificado de blocos, portanto, a quantidade total de bytes transferidos é menor que o solicitado.

O aviso sobre uma "leitura parcial" diz exatamente isso: uma das leituras foi parcial, portanto ddtransferiu um bloco incompleto. Na contagem de blocos, +1significa que um bloco foi lido parcialmente; como a contagem de saída é +0, todos os blocos foram gravados como lidos.

Isso não afeta a aleatoriedade dos dados: todos os bytes ddgravados são bytes dos quais eles são lidos /dev/urandom. Mas você tem menos bytes do que o esperado.

O Linux /dev/urandomacomoda solicitações grandes e arbitrárias (fonte: extract_entropy_userin drivers/char/random.c), portanto ddnormalmente é seguro ao ler a partir dele. No entanto, a leitura de grandes quantidades de dados leva tempo. Se o processo receber um sinal, a readchamada do sistema retornará antes de preencher seu buffer de saída. Esse é um comportamento normal, e os aplicativos devem chamar readem um loop; ddnão faz isso, por razões históricas ( ddas origens são obscuras, mas parece ter começado como uma ferramenta para acessar fitas, que têm requisitos peculiares e nunca foi adaptada para ser uma ferramenta de uso geral). Quando você verifica o progresso, isso envia ao ddprocesso um sinal que interrompe a leitura. Você pode escolher entre saber quantos bytesddserá copiado no total (lembre-se de não interrompê-lo - sem verificação de progresso, sem suspensão) ou sabendo quantos bytes ddforam copiados até agora; nesse caso, você não pode saber quantos bytes serão copiados.

A versão do ddGNU coreutils (como encontrada no Linux não incorporado e no Cygwin) possui uma flag fullblockque diz ddpara chamar readum loop (e o mesmo para write) e, portanto, sempre transfere blocos completos. A mensagem de erro sugere que você o use; você deve sempre usá-lo (nos sinalizadores de entrada e de saída), exceto em circunstâncias muito especiais (principalmente ao acessar fitas) - se você usar dd, ou seja: geralmente existem soluções melhores (veja abaixo).

dd if=/dev/urandom iflag=fullblock oflag=fullblock of=file bs=1M count=1000000

Outra maneira possível de ter certeza do que ddfará é passar o tamanho de um bloco de 1. Então, você pode dizer quantos bytes foram copiados da contagem de blocos, embora não tenha certeza do que acontecerá se um readfor interrompido antes de ler o primeiro byte (o que não é muito provável na prática, mas pode acontecer). No entanto, mesmo que funcione, isso é muito lento.

O conselho geral sobre o uso ddé não usardd . Embora ddseja frequentemente anunciado como um comando de baixo nível para acessar dispositivos, na verdade não existe: toda a mágica acontece na parte do arquivo do dispositivo /dev/…, ddé apenas uma ferramenta comum com um alto potencial de uso indevido, resultando em perda de dados . Na maioria dos casos, existe uma maneira mais simples e segura de fazer o que você deseja, pelo menos no Linux.

Por exemplo, para ler um certo número de bytes no início de um arquivo, basta chamar head:

head -c 1000000m </dev/urandom >file

Fiz uma referência rápida na minha máquina e não observei nenhuma diferença de desempenho entre ddum tamanho de bloco grande e head.

Se você precisar pular alguns bytes no início, entre tailem head:

dd if=input of=output count=C bs=B seek=S
<input tail -c +$((S*B+1)) | head -c $((C*B)) >output

Se você quiser ver o progresso, ligue lsofpara ver o deslocamento do arquivo. Isso funciona apenas em um arquivo regular (o arquivo de saída no seu exemplo), não em um dispositivo de caractere.

lsof -a -p 1234 -d 1
cat /proc/1234/fdinfo/1

Você pode ligar pvpara obter um relatório de progresso (melhor que ddo), às custas de um item adicional no pipeline (em termos de desempenho, é quase imperceptível).

Gilles 'SO- parar de ser mau'
fonte
2
+1. Esta é uma das postagens mais pesquisadas que li na rede StackExchange há muito tempo. É sucinto, mas contém todos os detalhes (históricos e atuais) sobre o ddcomando que eu não sabia que precisava conhecer. Obrigado.
Ossifrage Cósmica
4
Sinto muito, mas discordo da sua afirmação de que o dd é uma "ferramenta irritante que é difícil de usar corretamente" e "não use o dd". É um utilitário perfeitamente perfeito quando usado corretamente por alguém que dedicou algum tempo para entendê-lo. De fato, os kits de ferramentas forenses em disco quase todos dependem do dd ou de um derivado como o dcfldd.
fpmurphy
1
@ fpmurphy1 O GNU ddpode ser usado com segurança, graças à sua fullblockopção. Mas se você tem coreutils GNU, não precisa de ddmuito. “Derivativos” como dcflddeles não são dd, eles não sofrem com seus defeitos de design, portanto minha resposta não se aplica a eles. Uma vasta e vasta maioria das pessoas que usam ddnão levou tempo suficiente para entendê-lo (no máximo, gastou um tempo para pensar que o entendeu) e a maneira como elas o usam leva à perda de dados.
Gilles 'SO- stop being evil'
1
@Gilles Então, não devemos usar "echo" b / c do seu potencial para uso indevido (sudo echo olá mundo> / dev / sda)?
whitey04
2
@ whitey04 Eu recomendo não manusear barris de nitroglicerina. Eu não disse que você não deveria usar fósforos.
Gilles 'SO- stop being evil'
9

O aviso ocorre quando ddnão foi possível obter dados suficientes para preencher um bloco em uma única leitura. Isso acontece com fontes de dados erráticas ou lentas, ou fontes que gravam dados em unidades menores que o tamanho do bloco solicitado.

Não há problema com a integridade dos dados, mas o problema é que ddconta uma leitura parcial ainda como um bloco de leitura.

Se você não estiver usando a countopção, o aviso dificilmente importa, é apenas uma consideração de desempenho. Mas com count, você não receberá a quantidade de dados solicitada. Devido a leituras parciais, ofserá menor que count*bsno final.

Então, quando você usa count, tecnicamente você deve sempre usar iflag=fullblocktambém.

O +xdeve ser o número de blocos parciais.

frostschutz
fonte
-3
< /dev/urandom \
dd ibs=4k obs=64k |
dd bs=64k count=16000000 >file

^ Isso simplesmente funcionará. A desinformação de outra maneira aqui apresentada é manifestamente falsa. dd's buffers são explícita e por isso, para o buffer de entrada para contar as ocorrências que você precisa para o buffer de forma explícita. Isso é tudo. Não compre o fud.

mikeserv
fonte