Versión corta: ¿En qué circunstancias es ddseguro usar para copiar datos, lo que significa que no hay riesgo de corrupción debido a una lectura o escritura parcial?
Versión larga - preámbulo: a dd menudo se usa para copiar datos, especialmente desde o hacia un dispositivo ( ejemplo ). A veces se le atribuyen propiedades místicas de poder acceder a dispositivos en un nivel más bajo que otras herramientas (cuando en realidad es el archivo del dispositivo el que está haciendo la magia), pero dd if=/dev/sdaes lo mismo cat /dev/sda. dda veces se piensa que es más rápido, pero catpuede vencerlo en la práctica . Sin embargo, ddtiene propiedades únicas que lo hacen realmente útil a veces .
Problema: dd if=foo of=bar no es, de hecho, lo mismo que cat <foo >bar. En la mayoría de las unidades¹, ddrealiza una sola llamada a read(). (Encuentro POSIX borroso en lo que constituye "leer un bloque de entrada" en dd). Si read()devuelve un resultado parcial (que, según POSIX y otros documentos de referencia, está permitido a menos que la documentación de implementación indique lo contrario), se copia un bloque parcial. Exactamente el mismo problema existe para write().
Observaciones : en la práctica, he descubierto que ddpuede hacer frente a dispositivos de bloque y archivos normales, pero puede ser que no lo haya ejercitado demasiado. Cuando se trata de tuberías, no es difícil ddculpar; por ejemplo prueba este código :
yes | dd of=out bs=1024k count=10
y verifique el tamaño del outarchivo (es probable que sea muy inferior a 10 MB).
Pregunta : ¿En qué circunstancias es ddseguro usar para copiar datos? En otras palabras, ¿qué condiciones en los tamaños de bloque, en la implementación, en los tipos de archivo, etc., pueden garantizar que ddse copiarán todos los datos?
( GNU dd tiene una fullblockbandera para decirle que llame read()o write()en un bucle para transferir un bloque completo. Por dd iflag=fullblocklo tanto, siempre es seguro. Mi pregunta es sobre el caso cuando estas banderas (que no existen en otras implementaciones) no se usan .)
Checked He comprobado OpenBSD, GNU coreutils y BusyBox.

count,iflag=fullblockes obligatorio (o, alternativamente,iflag=count_bytes). No hay ningunaoflag=fullblock.Respuestas:
De la especificación :
bs=exprse especifica el operando y no se solicitan conversiones que no seansync,noerroronotruncse soliciten, los datos devueltos de cada bloque de entrada se escribirán como un bloque de salida separado; Si elread()retorno es inferior a un bloque completo ysyncno se especifica la conversión, el bloque de salida resultante será del mismo tamaño que el bloque de entrada.Entonces esto es probablemente lo que causa tu confusión. Sí, debido a que
ddestá diseñado para el bloqueo, de manera predeterminada, losread()s parciales se asignarán 1: 1 awrite()s parciales , o bien sesyncdotarán de NUL de relleno de cola o caracteres de espaciobs=cuandoconv=syncse especifique.Esto significa que
ddes seguro de usar para copiar datos (sin riesgo de corrupción debido a una lectura o escritura parcial) en todos los casos, excepto uno en el que está limitado arbitrariamente por uncount=argumento, porque de lo contrarioddfelizmentewrite()su salida en bloques de tamaño idéntico a aquellos en los que su entrada fueread()hasta queread()la atravesó por completo. E incluso esta advertencia es sólo es cierto cuandobs=se especifica oobs=se no se especifica, como el siguiente oración en los estados de especificaciones:bs=exprno se especifica el operando , o si se solicita una conversión diferente async,noerroronotruncse solicita, la entrada se procesará y se recopilará en bloques de salida de tamaño completo hasta llegar al final de la entrada.Sin
ibs=y / oobs=argumentos esto no puede importa - porqueibsyobsson a la vez el mismo tamaño por defecto. Sin embargo, puede ser explícito sobre el almacenamiento en búfer de entrada especificando diferentes tamaños para cualquiera y no especificandobs=(porque tiene prioridad) .Por ejemplo, si haces:
... entonces un POSIX lo
ddharáwrite()en fragmentos de 512 bytes al recopilar cadaread()byte individualmente en un solo bloque de salida.De lo contrario, si lo haces ...
... un POSIX
ddtendráread()un máximo de 512 bytes a la vez, perowrite()cada bloque de salida de un tamaño de megabyte (el kernel permite y exceptúa posiblemente el último, porque eso es EOF) completo al recopilar la entrada en bloques de salida de tamaño completo .Sin embargo, también de la especificación:
count=ncount=asigna ai?bs=bloques, por lo que para manejar un límite arbitrario de formacount=portátil necesitarás dosdds. La forma más práctica de hacerlo con dosdds es canalizando la salida de uno en la entrada de otro, lo que seguramente nos coloca en el ámbito de la lectura / escritura de un archivo especial independientemente del tipo de entrada original.Una tubería IPC significa que al especificar
[io]bs=argumentos que, para hacerlo de manera segura, debe mantener dichos valores dentro delPIPE_BUFlímite definido del sistema . POSIX establece que el núcleo del sistema sólo debe garantizar atómicasread()s ywrite()s dentro de los límites dePIPE_BUFcomo se define enlimits.h. POSIX garantiza quePIPE_BUFsea al menos ...{_POSIX_PIPE_BUF}... (que también es el
ddtamaño de bloque de E / S predeterminado ) , pero el valor real suele ser al menos 4k. En un sistema Linux actualizado es, por defecto, 64k.Entonces, cuando configura sus
ddprocesos, debe hacerlo en un factor de bloque basado en tres valores:PIPE_BUFo menor)Me gusta:
Tiene que sincronizar i / ow /
ddpara manejar entradas no buscables. En otras palabras, haga explícitos los amortiguadores de tubería y dejarán de ser un problema. Para esoddes eso . La cantidad desconocida aquí esyesel tamaño del búfer, pero si bloquea eso a una cantidad conocida con otra,ddentonces una pequeña multiplicación informada puede serddsegura de usar para copiar datos (sin riesgo de corrupción debido a una lectura o escritura parcial) incluso cuando limite arbitrariamente la entrada concount=cualquier tipo de entrada arbitraria en cualquier sistema POSIX y sin perder un solo byte.Aquí hay un fragmento de la especificación POSIX :
ibs=exprexprobs=exprexprbs=exprexprbytes, reemplazandoibs=yobs=. Si no se especifica otra conversión quesync,noerrorynotruncse especifica, cada bloque de entrada se copiará a la salida como un bloque único sin agregar bloques cortos.También encontrarás algo de esto mejor explicado aquí .
fuente
Con sockets, tuberías o ttys, read () y write () pueden transferir menos del tamaño solicitado, por lo que cuando se usa dd en estos, necesita el indicador de bloque completo. Sin embargo, con los archivos normales y los dispositivos de bloqueo, solo hay dos veces cuando pueden hacer una lectura / escritura corta: cuando llega a EOF, o si hay un error. Esta es la razón por la cual las implementaciones anteriores de dd sin el indicador de bloque completo eran seguras de usar para la duplicación de disco.
fuente
mke2fsfalló en silencio porque llamówrite()con un tamaño no potenciado de 2 (3kB IIRC) y el núcleo redondeado hasta un poder de 2.)cat </dev/sda >/dev/sdbfunciona bien para clonar un disco.catselecciona un tamaño de búfer para el rendimiento; no obtiene ninguna información relacionada con el dispositivo del núcleo. Aparte de las cintas, se puederead()ywrite()a un dispositivo de bloque con cualquier tamaño. Al menos en Linux,st_blksizedepende solo del sistema de archivos donde se encuentra el inodo del dispositivo de bloque, no del dispositivo subyacente.