jueves, 30 de abril de 2009

Diferencia entre /dev/null y /dev/zero

Quizás muchos de los que recién inician en Linux piensan que /dev/null y /dev/zero (la zona de la muerte en Linux y Unix) son lo mismo, pero aunque paresca que si por el nombre la verdad es que son dos cosas opuestas, los dos archivos difieren mucho.

1. Escribiendo a /dev/null y /dev/zero:
Puedes escribir ambos en la misma forma. Por ejemplo, si deseas eliminar una salida desde un comando, cualquiera de los dos lo hará. Esto es:

host # echo hi >/dev/null
y

host # echo hi >/dev/zero

ambos enviaran la salida a la "nada". Ejecutando cualquiera de los dos comandos satisfará tu requerimiento de mandar al "tacho" o "vertedero" una salida. Estos deberían ser carácter.

2. Leyendo desde /dev/null y /dev/zero:
Aquí es donde la diferencia entre los dos archivos viene a ser aparente. La diferencia mas significativa esta expuesta en la "lectura" desde que esta acción subraya la mayor forma en la cual los dos difieren.

básicamente /dev/null es un "agujero negro". Escribir en el (como se hizo arriba) básicamente es como drenar o vaciar. Estos se van a la nada, se quedan ahí y no puedes volver a recuperar nada. Cuando lees desde /dev/null, la misma regla mantiene verdadero. /dev/null es virtualmente nada, cualquier lectura a este producirá ninguna salida. Por ejemplo, strace cat /dev/null, muestra que es lo que pasa cuando /dev/null es leído:

host # cat /dev/null
host #
host # strace cat /dev/null
...
open("/usr/lib/locale/en_US.UTF-8/LC_CTYPE", O_RDONLY) = -1 ENOENT
(No such file or directory)
open("/usr/lib/locale/en_US.utf8/LC_CTYPE", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=254076, ...}) = 0
mmap2(NULL, 254076, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7c8f000
close(3) = 0
fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...})
= 0
open("/dev/null", O_RDONLY|O_LARGEFILE) = 3
fstat64(3, {st_mode=S_IFCHR|0666, st_rdev=makedev(1, 3), ...}) = 0
read(3, "", 4096) = 0
close(3) = 0
close(1) = 0
close(2) = 0
exit_group(0) = ?
Process 3376 detached

literalmente, el dispositivo es abierto, leído (lo cual no produce nada) y es cerrado, cada EOF es enviado inmediatamente después abierto.

Por el otro lado, /dev/zero, no es un "agujero negro". Cuando lees desde /dev/zero, obtienes un resultado muy diferente al obtenido cuando lees desde /dev/null. Esto se debe a que /dev/zero retorna "cero" hasta que pares de leerlo y no devuelve un EOF como lo hace /dev/null. Lo que devuelve es el carácter nulo ASCII (0x00).

A continuación, ve que es lo que sucede en el terminal:

host # cat /dev/zero
^C
host #

nota que debes presionar CTRL + C para detener el comando y obtener el cursor de nuevo.

host # strace cat /dev/zero

write(1, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
..., 4096) = 4096
read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
..., 4096) = 4096
write(1, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
..., 4096) = 4096
read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
..., 4096) = 4096
write(1, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
..., 4096

Esta es, básicamente, la diferencia entre los dos archivos. Sin embargo debería ser notado que hay dos cosas que puedes hacer con /dev/zero que no puedes hacer con /dev/null una que puede ser muy útil o práctica y la otra peligrosa si no sabes lo que estas haciendo.

1.
/dev/null puede ser usado para crear facilmente un archivo de 0 byte. Esto es util cuando quieres crear un archivo contenedor, etc:

host # cat /dev/null >FILE
host # ls -l FILE
-rw-r--r-- 1 pubuntu pubuntu 0 2009-04-30 13:40 FILE

por supuesto que el mismo resultado se puede lograr de una manera mas eficiente. El mecanismo es el mismo, pero el tipeado es mas rápido:

host # >FILE
host # ls -l FILE
-rw-r--r-- 1 pubuntu pubuntu 0 2009-04-30 13:40 FILE

2.
Lo bueno que puedes hacer con /dev/zero es crear un archivo con ceros, con el cual después podrás crear un archivo de sistema. Usando un simple comando como dd puedes configurar /dev/zero como tu archivo de entrada ("if") y tu dispositivo de bloque (o archivo regular) como la salida ("of") y luego hacer un archivo de sistema con este. Esta es una manera rápida de configurar espacio adicional en el sistema de archivo:

host # dd if=/dev/zero of=nuevoarchivo

los argumentos de tamaño de bloque ("bs") y "count" diferiran dependiendo de tu fs y cuales son tus necesidades particulares.

host # mkfs ARGS nuevoarchivo

Esta parte, la creación del nuevo sistema de archivo, pude tener varias variables, el componente mas significativo en este ejemplo es el nombre del archivo con ceros que creaste con dd.

3.
Lo malo que puedes hacer o el error que podrías cometer, si no tienes cuidado, esta relacionado con lo bueno que se puede hacer. Así como puedes crear un archivo llenos de ceros, podrías llenar completamente una partición con ceros y posiblemente harías que el sistema colapse y perder toda la data. por supuesto esto no lo puedes hacer con un usuario regular:

host # cd /var
host # cat /dev/zero >FILE
cat: output error (0/8192 characters written)
No space left on device
host # df -k /var
Filesystem kbytes used avail capacity Mounted on
/dev/dsk/c0t0d0s4 4130238 4120138 0 100% /var

Así es en solo 100 segundos puedes invalidar /var.

Esto también sería una forma de borrar un disco e impedir que se recuperen los datos borrados.

Fuente.

3 comentarios:

Anónimo dijo...

Un artículo interesante.

Yo para crear un fichero NUEVO con tamaño 0, utilizo touch:

$ touch FICHERO-NUEVO

Saludos.

Anónimo dijo...

Eś válido "touch" para crear un archivo nuevo vacío. Sin embargo ese comando fue oficialmente creado para ponerle a un archivo la fecha actual : )

Anónimo dijo...

Muy buen articulo, gracias