¿Por qué la tubería 'tar' en 'dd' no se detiene hasta que el disco está lleno?


18

Tengo un archivo tar de una sola imagen de disco. La imagen dentro de este archivo tar es de aproximadamente 4 GB de tamaño. Tubería que la salida de tar xfal ddescribir la imagen de disco en una tarjeta SD. El diskdump nunca se detiene hasta que la tarjeta está llena. Aquí está mi sesión de 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é? ¡Debería detenerse después de que Hit haya escrito la imagen de 4GB en el carrito de 16GB y nunca quedarse sin espacio!


¿Tiene espacio en disco para intentar ejecutar esto ddy escribirlo en otro archivo? tar zxf disk.img.tgz -O | dd status=progress conv=sync bs=1M of=/path/to/some/file/on/disk? Si es así, ¿te da una copia exacta del archivo original?
Andy Dalton

2
¿Por qué tienes conv=sync? ¿Quisiste usar conv=fsynctal vez?
Ralph Rönnquist

¿Estás seguro de que ese es el tamaño real del archivo? Sé que gzip solo tiene 32 bits para almacenar tamaños de archivo, por lo que obtiene un tamaño incorrecto de más de 4 GB. No estoy seguro si el alquitrán tiene una limitación similar.
David Conrad el

Respuestas:


50

Es porque lo estás haciendo mal.

Estás usando bs=1Mpero leer desde stdin, pipe, tendrá lecturas más pequeñas. De hecho, según dd, no obtuvo una sola lectura completa.

Y luego tienes conv=syncque complementa las lecturas incompletas con ceros.

0+15281 records in
15280+0 records out

ddrecibió 0 lecturas completas y 15281 incompletas, y escribió 15280 bloques completos (conv = sincronización llena). Por lo tanto, la salida es mucho más grande que la entrada, hasta que no quede espacio.

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

Para resolver esto, puede eliminar conv=syncy agregar iflag=fullblock.


Para ilustrar, considere yes, que por defecto arroja infinito "y \ ny \ ny \ n".

$ 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.|
*

Con dd bs=1M conv=syncesto se ve así:

$ 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  |................|
*

Entonces obtiene un bloque incompleto de "y \ ny \ ny \ n" (0x00000 - 0x1e000, 122880 Bytes) y luego escribe el 1M restante como ceros (0x01e000 - 0x100000, 925696 Bytes). En la mayoría de los casos, no desea que esto suceda. El resultado es aleatorio de todos modos ya que no tienes control real sobre cuán incompleta resultaría ser cada lectura. Como aquí, la segunda lectura ya no es 122880 Bytes sino 73728 Bytes.

dd conv=syncrara vez es útil e incluso en los casos en que sería bienvenido, como escribir ceros cuando recibes errores de lectura, las cosas saldrán terriblemente mal.


En este caso, ejecutar el ddcomando bajo strace(suponiendo Linux) habría demostrado que cada lectura corta de la tubería fue seguida por una escritura completa de 1 MB.
Andrew Henle

2
@AndrewHenle ni siquiera necesita strace para esto, solo mirar la salida será suficiente. Se agregó una ilustración
frostschutz el

Esto también ilustra por qué el ddcomando está fundamentalmente roto e inutilizable. Se especifica para operar en individuales reads y writes, pero esas operaciones se especifican de forma que siempre se puede producir a corto lee o escribe, y no es un error. Como consecuencia, el comportamiento de dddepende del comportamiento no especificado.
R ..

Gracias por la respuesta muy educativa. Como alguien más sugirió que estaba siendo un imbécil y mezclé las muchas opciones para hacerlo dd, pero me llevó a aprender algo de ti. De lo que todavía no estoy completamente seguro es, si y cuándo ddhabría terminado. Supongo que sí, pero como en realidad estaba escribiendo 1 parte de datos reales y 9 partes de ceros, se habría detenido después de escribir aproximadamente 40G. ¿Es eso correcto?
con-f-use

@R .., esa característica es muy útil con controladores de dispositivos que se preocupan por el tamaño de bloque de lecturas y escrituras. Recuerdo haber usado algunas unidades de cinta que se preocuparon por eso. Aunque en este caso, obviamente no es necesario, se podría simplemente redirigir directamente en el disco (no conseguir un informe de situación en vivo, sin embargo)
ilkkachu
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.