Cree datos aleatorios con dd y obtenga una "advertencia de lectura parcial". ¿Los datos después de la advertencia ahora son realmente aleatorios?

16

Creo un archivo de 1TB con datos aleatorios con dd if=/dev/urandom of=file bs=1M count=1000000. Ahora verifico kill -SIGUSR1 <PID>el progreso y obtengo lo siguiente:

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

No puedo interpretar la advertencia. ¿Qué dice? ¿Mi archivo es realmente aleatorio después de la advertencia o hay algún problema? ¿Qué significa +0 o +1 en800950+1 Datensätze ein y 800950+0 Datensätze aussignifica? Después de la advertencia es +1. ¿Es una cuenta de errores?

Eliminar
fuente
Esto sería más fácil de responder si pudiera traducir los mensajes al inglés. Además, defina "realmente aleatorio". ¿Qué nivel de aleatoriedad requiere, para qué lo usará?
terdon
Para recibir mensajes en inglés, use LC_ALL=Cdelante del comando, comoLC_ALL=C dd if=...
Volker Siegel

Respuestas:

38

Resumen: ddes una herramienta irritable que es difícil de usar correctamente. No lo uses, a pesar de los numerosos tutoriales que te lo dicen.ddtiene un ambiente de "credibilidad callejera unix", pero si realmente entiendes lo que estás haciendo, sabrás que no deberías tocarlo con un poste de 10 pies.

ddrealiza una sola llamada a la llamada del readsistema por bloque (definida por el valor de bs). No hay garantía de que la readllamada al sistema devuelva tantos datos como el tamaño de búfer especificado. Esto tiende a funcionar para archivos normales y dispositivos de bloque, pero no para tuberías y algunos dispositivos de caracteres. Consulte ¿ Cuándo es adecuado dd para copiar datos? (o, cuando se lee () y escribe () parcial) para obtener más información. Si la readllamada del sistema devuelve menos de un bloque completo, ddtransfiere un bloque parcial. Todavía copia el número especificado de bloques, por lo que la cantidad total de bytes transferidos es inferior a la solicitada.

La advertencia sobre una "lectura parcial" le dice exactamente esto: una de las lecturas fue parcial, por lo que ddtransfirió un bloque incompleto. En los recuentos de bloques, +1significa que un bloque se leyó parcialmente; +0Como el recuento de salida es , todos los bloques se escribieron como leídos.

Esto no afecta la aleatoriedad de los datos: todos los bytes que se ddescriben son bytes de los que se lee /dev/urandom. Pero tienes menos bytes de lo esperado.

Linux /dev/urandomacomoda solicitudes grandes arbitrarias (fuente: extract_entropy_userin drivers/char/random.c), por ddlo que normalmente es seguro cuando se lee. Sin embargo, leer grandes cantidades de datos lleva tiempo. Si el proceso recibe una señal, la readllamada al sistema regresa antes de llenar su búfer de salida. Este es un comportamiento normal, y se supone que las aplicaciones llaman readen un bucle; ddno hace esto, por razones históricas ( ddlos orígenes son turbios, pero parece haber comenzado como una herramienta para acceder a las cintas, que tienen requisitos particulares, y nunca fue adaptada para ser una herramienta de uso general). Cuando verifica el progreso, esto envía al ddproceso una señal que interrumpe la lectura. Puedes elegir entre saber cuántos bytesddcopiará en total (asegúrese de no interrumpirlo, sin verificación de progreso, sin suspensión), o saber cuántos bytes se ddhan copiado hasta el momento, en cuyo caso no puede saber cuántos bytes más copiará.

La versión de dden GNU coreutils (como se encuentra en Linux no incrustado y en Cygwin) tiene una bandera fullblockque le dice ddque llame readen un bucle (y lo mismo para write) y, por lo tanto, siempre transfiera bloques completos. El mensaje de error sugiere que lo use; siempre debe usarlo (tanto en los indicadores de entrada como en los de salida), excepto en circunstancias muy especiales (principalmente al acceder a cintas); si lo usa dd, es decir: generalmente hay mejores soluciones (consulte a continuación).

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

Otra forma posible de estar seguro de lo ddque hará es pasar un tamaño de bloque de 1. Luego, puede saber cuántos bytes se copiaron del recuento de bloques, aunque no estoy seguro de qué sucederá si readse interrumpe un antes de leer el primero. byte (que no es muy probable en la práctica pero puede suceder). Sin embargo, incluso si funciona, esto es muy lento.

El consejo general sobre el uso ddes no usardd . Aunque a ddmenudo se anuncia como un comando de bajo nivel para acceder a dispositivos, de hecho no es tal cosa: toda la magia ocurre en la parte del archivo del dispositivo (la /dev/…), ddes solo una herramienta ordinaria con un alto potencial de mal uso que resulta en la pérdida de datos . En la mayoría de los casos, hay una manera más simple y segura de hacer lo que quiere, al menos en Linux.

Por ejemplo, para leer un cierto número de bytes al comienzo de un archivo, simplemente llame head:

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

Hice un punto de referencia rápido en mi máquina y no observé ninguna diferencia de rendimiento entre ddun gran tamaño de bloque y head.

Si necesita omitir algunos bytes al principio, diríjase taila head:

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

Si desea ver el progreso, llame lsofpara ver el desplazamiento del archivo. Esto solo funciona en un archivo normal (el archivo de salida en su ejemplo), no en un dispositivo de caracteres.

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

Puede llamar pvpara obtener un informe de progreso (mejor que dd's), a expensas de un elemento adicional en la tubería (en cuanto al rendimiento, es apenas perceptible).

Gilles 'SO- deja de ser malvado'
fuente
2
+1. Esta es una de las publicaciones mejor investigadas que he leído en la red StackExchange en mucho tiempo. Es breve pero contiene todos los detalles (históricos y actuales) sobre el ddcomando que no me di cuenta que necesitaba saber. Gracias.
Ossifrage cósmico
44
Lo siento, pero no estoy de acuerdo con su afirmación de que dd es una "herramienta irritable que es difícil de usar correctamente" y "no use dd". Es una utilidad perfectamente buena cuando es utilizada correctamente por alguien que se ha tomado el tiempo de comprenderla. De hecho, los kits de herramientas forenses de disco dependen casi todos de dd o un derivado como dcfldd.
fpmurphy
1
@ fpmurphy1 GNU ddse puede utilizar de forma segura, gracias a su fullblockopción. Pero si tienes GNU coreutils no necesitas ddmucho. Los "derivados" como no lodcfldd son , no sufren sus defectos de diseño, por lo que mi respuesta no se aplica a ellos. Una vasta, gran mayoría de las personas que lo usan no se han tomado el tiempo suficiente para entenderlo (a lo sumo, se han tomado el tiempo para pensar que lo entienden) y la forma en que lo usan conduce a la pérdida de datos. dddd
Gilles 'SO- deja de ser malvado'
1
@Gilles ¿Entonces no deberíamos usar "echo" b / c de su potencial de mal uso (sudo echo hello world> / dev / sda)?
whitey04
2
@ whitey04 Recomiendo no manipular barriles de nitroglicerina. No dije que no deberías usar fósforos.
Gilles 'SO- deja de ser malvado'
9

La advertencia se produce cuando ddno se pueden obtener suficientes datos para llenar un bloque en una sola lectura. Esto sucede con fuentes de datos erráticas o lentas, o fuentes que escriben datos en unidades más pequeñas que el tamaño de bloque solicitado.

No hay ningún problema con la integridad de los datos, pero el problema es que ddtodavía se considera una lectura parcial como un bloque de lectura.

Si no está utilizando la countopción, la advertencia no importa, es solo una consideración de rendimiento. Pero con count, no obtendrá la cantidad de datos que solicitó. Debido a lecturas parciales, ofserá más pequeño que count*bsal final.

Entonces, cuando lo usa count, técnicamente siempre debe usarlo iflag=fullblocktambién.

El +xdebería ser el número de bloques parciales.

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

^ Eso solo funcionará. La información errónea que de otro modo tenía aquí es manifiestamente falsa. ddLos almacenamientos intermedios son explícitos y, por lo tanto, para almacenar la entrada para contar las ocurrencias, debe almacenar explícitamente. Eso es todo. No compres el fud.

mikeserv
fuente