¿Cómo verificar que el disco duro esté lleno de ceros en Linux?

15

Tengo un disco duro lleno de ceros.

¿Cómo verificar si todos los bits en el disco duro son ceros usando bash?

gkfvbnhjh2
fuente
¿Sería aceptable sobrescribir toda la unidad con ceros? ¿O realmente necesita confirmar el contenido actual?
Bob
Quiero verificar que el disco duro esté lleno de ceros.
gkfvbnhjh2
1
En teoría, podría haber un error en las herramientas de desinfección de datos que deja algunos datos intactos. No quiero estar seguro de que cada bit es cero. Entonces, ¿cómo verifico si el disco duro está lleno de ceros?
gkfvbnhjh2
¿Por qué ceros? ¿No escribirías al azar ceros y 1s varias veces?
13
Debido a que los 1 son más estrechos que los 0, puede ver los datos antiguos entre ellos más fácilmente.
ChrisA

Respuestas:

28

odreemplazará las ejecuciones de lo mismo *, por lo que puede usarlo fácilmente para buscar bytes distintos de cero:

$ sudo od /dev/disk2 | head
0000000    000000  000000  000000  000000  000000  000000  000000  000000
*
234250000
Gordon Davisson
fuente
8
Añadiría | headal final de eso, de modo que si resulta que la unidad no está puesta a cero, se detiene después de producir la salida suficiente para mostrar el hecho, en lugar de volcar toda la unidad en la pantalla.
Wyzard
2
@Wyzard: Excelente idea; Lo agregaré a mi respuesta.
Gordon Davisson el
8

He escrito un breve programa en C ++ para hacerlo, fuente disponible aquí .

Para construirlo:

wget -O iszero.cpp https://gist.github.com/BobVul/5070989/raw/2aba8075f8ccd7eb72a718be040bb6204f70404a/iszero.cpp
g++ -o iszero iszero.cpp

Para ejecutarlo:

dd if=/dev/sdX 2>/dev/null | ./iszero

Producirá la posición y el valor de cualquier byte distinto de cero. Puede redirigir esta salida a un archivo con >, por ejemplo:

dd if=/dev/sdX 2>/dev/null | ./iszero >nonzerochars.txt

Es posible que desee intentar cambiar BUFFER_SIZEpara una mejor eficiencia. No estoy seguro de cuál podría ser un valor óptimo. Tenga en cuenta que esto también afecta la frecuencia con la que imprime el progreso, lo que afectará un poco la velocidad (la salida de impresión a la consola es lenta ). Agregue 2>/dev/nullpara deshacerse de la salida de progreso.

Soy consciente de que esto no está utilizando bash estándar, ni siquiera incorporados, pero no debería requerir ningún privilegio adicional. La solución de @Hennes es aún más rápida (realmente no he optimizado nada, esta es la solución ingenua); sin embargo, este pequeño programa puede darle una mejor idea de cuántos bytes ha perdido su limpiador y en qué ubicación. Si deshabilita la salida de progreso, seguirá siendo más rápido de lo que la mayoría de los discos duros de consumo pueden leer (> 150 MB / s), por lo que no es un gran problema.

Una versión más rápida con una salida menos detallada está disponible aquí . Sin embargo, todavía es un poco más lento que la solución de @Hennes. Sin embargo, este se cerrará en el primer personaje distinto de cero que encuentre, por lo que es potencialmente mucho más rápido si hay un distinto de cero cerca del comienzo de la transmisión.


Agregar fuente a la publicación para mantener la respuesta mejor autocontenida:

#include <cstdio>

#define BUFFER_SIZE 1024

int main() {
    FILE* file = stdin;
    char buffer[BUFFER_SIZE];
    long long bytes_read = 0;
    long long progress = 0;
    long long nonzero = 0;

    while (bytes_read = fread(buffer, 1, BUFFER_SIZE, file)) {
        for (long long i = 0; i < bytes_read; i++) {
            progress++;
            if (buffer[i] != 0) {
                nonzero++;
                printf("%lld: %x\n", progress, buffer[i]);
            }
        }
        fprintf(stderr, "%lld bytes processed\r", progress);
    }

    fprintf(stderr, "\n");

    int error = 0;
    if (error = ferror(file)) {
        fprintf(stderr, "Error reading file, code: %d\n", error);
        return -1;
    }

    printf("%lld nonzero characters encountered.\n", nonzero);
    return nonzero;
}
Beto
fuente
Esta es una gran respuesta, pero ¿hay alguna forma de hacer que el script funcione más como un comando normal, utilizando en iszero /dev/sdalugar de requerir que se canalice con algo como iszero < /dev/sda?
Hashim
1
@Hashim Esto se escribió más o menos como un programa de usar y tirar hace bastante tiempo (hoy en día al menos lo haría en un lenguaje de script como Python en lugar de compilar C) ... dicho eso, si querías tomar argumentos en el de la manera más simple, sería en algún lugar a lo largo de las líneas de fabricación int main(int argc, char *argv[])y luego FILE* file = fopen(argv[1], "r");. Hecho correctamente, incluiría verificar si el argumento realmente existe, la verificación de error se abrió con éxito (hacer una ferrorverificación adicional después de fopen), etc., pero demasiados problemas para un programa desechable.
Bob
1
@Hashim Sospecho que las operaciones vectorizadas SIMD en numpy estarían cerca de las instrucciones vectorizadas en C. Y suponiendo que el compilador de C sea lo suficientemente inteligente como para vectorizar el bucle en el ingenuo programa de C. Tendría que comparar para estar seguro; desafortunadamente no tengo tiempo para hacerlo ahora. La principal ventaja de Python (et al.) Es que generalmente está disponible y se puede ejecutar sin un compilador, mientras gccque no está necesariamente disponible en todas las distribuciones de Linux sin extraer paquetes adicionales. Por otra parte, numpy tampoco forma parte de los paquetes estándar de Python ...
Bob
1
@Hashim Si compila -O3y -march=nativepuede ver algunas aceleraciones; eso debería asegurarse de que GCC habilite la vectorización automática y utilice el mejor disponible para su CPU actual (AVX, SSE2 / SSE3, etc.). Junto con eso puedes jugar con el tamaño del búfer; diferentes tamaños de búfer pueden ser más óptimos con bucles vectorizados (jugaría con 1MB +, el actual es 1kB).
Bob
1
@Hashim Arriba comentario editado, en caso de que no lo haya visto. Más allá de eso, si desea discutir más, puede enviarme un ping ( @Bob) en el chat: chat.stackexchange.com/rooms/118/root-access
Bob
6

Ampliando la respuesta de Gordon, pvproporciona una indicación de qué tan avanzado está el proceso:

$ sudo pv -tpreb /dev/sda | od | head
0000000 000000 000000 000000 000000 000000 000000 000000 000000
*
9.76GiB 0:06:30 [25.3MiB/s] [=================>               ] 59% ETA 0:04:56
Chris
fuente
¡Esto es muy útil con un gran disco duro!
Martin Hansen
5

Esto parece una solución fea e ineficiente, pero si tiene que verificar solo una vez:

dd if=/dev/sdX | tr --squeeze-repeats "\000" "T"

Usando dd para leer desde el disco sdX. (reemplace la X con la unidad desde la que desea leer),
luego traduzca todos los bytes cero no imprimibles a algo que podamos manejar.

Luego, contamos los bytes que podemos manejar y verificamos si es el número correcto ( wc -cpara eso), o saltamos el conteo y usamos -so --squeeze-repeatspara exprimir todas las ocurrencias múltiples en un solo carácter.

Por dd if=/dev/sdX | tr --squeeze-repeats "\000" "T"lo tanto, debe imprimir solo una T.

Si quieres hacer esto regularmente, entonces quieres algo más eficiente.
Si desea hacer esto solo una vez, este kludge puede verificar que su limpiador normal esté funcionando y que puede confiar en él.

Hennes
fuente
¿Por qué considera que esta solución es ineficiente? ¿Hay algún almacenamiento intermedio que requiera leer mucho más allá de la primera ubicación que no sea NUL?
Daniel Beck
¿Hay algún problema potencial donde una 'T' literal esté presente en el vapor como el único carácter distinto de cero?
Bob
Cierto. Esa es una falla en el diseño. Tampoco estoy usando bash (el shell en sí), pero supuse que con "Bash" querías decir "No desde bash, por usar cualquier indicador de shell y herramientas de modo de texto estándar".
Hennes
3
@daniel: Un simple programa en C debería poder leer todos los datos sin cambiar cada byte de lectura. Lo que sería más eficiente y estéticamente agradable. También podría tomar mucho más tiempo escribir un programa de este tipo que simplemente usar las herramientas disponibles de una manera ineficiente.
Hennes
3

Para verificar solo, verá los bloques que no coinciden en la lista

sudo badblocks -sv -t 0x00 /dev/sdX

O use badblocks para escribirlos y también verifique:

sudo badblocks -svw -t 0x00 /dev/sdX

La prueba de destrucción predeterminada es mi borrado seguro de elección

sudo badblocks -svw /dev/sdX

Si alguien puede recuperar algo después de llenar el disco con 0s y 1s alternativos, entonces su complemento, luego todos los 1s, luego todos los 0s, con cada pase verificado que funcionó, ¡buena suerte para ellos!

También realiza una buena comprobación previa a la implementación en unidades nuevas

man badblocks

para otras opciones

No digo que sea rápido, pero funciona ...

Beardy
fuente
2

Lo mejor de ambos mundos. Este comando omitirá sectores defectuosos:

sudo dd if=/dev/sdX conv=noerror,sync | od | head

Use kill -USR1 <pid of dd>para ver el progreso.

jiveformation
fuente
0

Hace algún tiempo tenía curiosidad AIO. El resultado fue un programa de prueba de muestra que comprueba los sectores (bloques de 512 bytes) que están NUL. Puede ver esto como una variante de un detector de regiones de archivos dispersos . Creo que la fuente dice todo.

  • Si todo el archivo / unidad se muestra como NULsalida 0000000000-eof. Tenga en cuenta que hay un truco en el programa, la función fin()no se llama en la línea 107 a propósito para dar la salida mostrada.
  • No se ha probado mucho, por lo que puede contener errores
  • El código es un poco más largo, ya AIOque no es tan sencillo como otras formas,
  • sin embargo, AIOes probablemente la forma más rápida de mantener un disco ocupado leyendo , porque elNUL comparar se realiza con el siguiente bloque de datos se lee en. (Podríamos exprima un poco más milisegundos haciendo superposición AIO, pero realmente no creo que esto vale la pena el esfuerzo.)
  • Siempre regresa truesi el archivo es legible y todo funcionó. No regresa falsesi el archivo no esNUL .
  • Se supone que el tamaño del archivo es un múltiplo de 512. Hay un error en el último sector, sin embargo, en un archivo NULtodavía funciona, ya que los búferes de memoria ya contienen NUL. Si alguien piensa que esto necesita una solución, en la línea 95 memcmp(nullblock, buf+off, SECTOR)podría leer memcmp(nullblock, buf+off, len-off<SECTOR : len-off : SECTOR). Pero la única diferencia es que el "informe final" quizás sea un poco aleatorio (no para un archivo que es completamente NUL).
  • El cambio memcmp()también soluciona otro problema en las plataformas, que no NUL alloc()editan la memoria, porque el código no lo hace. Pero esto solo puede verse en archivos de menos de 4 MiB, pero checknulprobablemente sea una exageración para una tarea tan pequeña;)

HTH

/* Output offset of NUL sector spans on disk/partition/file
 *
 * This uses an AIO recipe to speed up reading,
 * so "processing" can take place while data is read into the buffers.
 *
 * usage: ./checknul device_or_file
 *
 * This Works is placed under the terms of the Copyright Less License,
 * see file COPYRIGHT.CLL.  USE AT OWN RISK, ABSOLUTELY NO WARRANTY.
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

#include <malloc.h>
#include <aio.h>

#define SECTOR  512
#define SECTORS 40960
#define BUFFERLEN   (SECTOR*SECTORS)

static void
oops(const char *s)
{
  perror(s);
  exit(1);
}

static void *
my_memalign(size_t len)
{
  void      *ptr;
  static size_t pagesize;

  if (!pagesize)
    pagesize = sysconf(_SC_PAGESIZE);
  if (len%pagesize)
    oops("alignment?");
  ptr = memalign(pagesize, len);
  if (!ptr)
    oops("OOM");
  return ptr;
}

static struct aiocb aio;

static void
my_aio_read(void *buf)
{
  int   ret;

  aio.aio_buf = buf;
  ret = aio_read(&aio);
  if (ret<0)
    oops("aio_read");
}

static int
my_aio_wait(void)
{
  const struct aiocb    *cb;
  int           ret;

  cb = &aio;
  ret = aio_suspend(&cb, 1, NULL);
  if (ret<0)
    oops("aio_suspend");
  if (aio_error(&aio))
    return -1;
  return aio_return(&aio);
}

static unsigned long long   nul_last;
static int          nul_was;

static void
fin(void)
{
  if (!nul_was)
    return;
  printf("%010llx\n", nul_last);
  fflush(stdout);
  nul_was   = 0;
}

static void
checknul(unsigned long long pos, unsigned char *buf, int len)
{
  static unsigned char  nullblock[SECTOR];
  int           off;

  for (off=0; off<len; off+=SECTOR)
    if (memcmp(nullblock, buf+off, SECTOR))
      fin();
    else
      {
        if (!nul_was)
          {
            printf("%010llx-", pos+off);
            fflush(stdout);
            nul_was = 1;
          }
        nul_last    = pos+off+SECTOR-1;
      }
}

int
main(int argc, char **argv)
{
  unsigned char *buf[2];
  int       fd;
  int       io, got;

  buf[0] = my_memalign(BUFFERLEN);
  buf[1] = my_memalign(BUFFERLEN);

  if (argc!=2)
    oops("Usage: checknul file");
  if ((fd=open(argv[1], O_RDONLY))<0)
    oops(argv[1]);

  aio.aio_nbytes    = BUFFERLEN;
  aio.aio_fildes    = fd;
  aio.aio_offset    = 0;

  io = 0;
  my_aio_read(buf[io]);
  while ((got=my_aio_wait())>0)
    {
      unsigned long long    pos;

      pos   = aio.aio_offset;

      aio.aio_offset += got;
      my_aio_read(buf[1-io]);

      checknul(pos, buf[io], got);

      io    = 1-io;
    }
  if (got<0)
    oops("read error");
  printf("eof\n");
  close(fd);
  return 0;
}
Tino
fuente
0

Quería publicar esta solución inteligente a partir de una pregunta similar pero anterior, publicada por un usuario que no ha iniciado sesión por un tiempo:

Hay un dispositivo /dev/zero en un sistema Linux que siempre da ceros cuando se lee.

Entonces, ¿qué hay de comparar su disco duro con este dispositivo:

cmp /dev/sdX /dev/zero

Si todo está bien al poner a cero su disco duro, terminará con:

cmp: EOF on /dev/sdb

diciéndole que los dos archivos son iguales hasta que llegó al final del disco duro. Si hay un bit distinto de cero en el disco durocmp le indicará dónde está en el archivo.

Si tiene el pvpaquete instalado, entonces:

pv /dev/sdX | cmp /dev/zero

hará lo mismo con una barra de progreso para mantenerte entretenido mientras revisa tu disco (el EOF ahora estará en STDIN en lugar de sdX).

Hashim
fuente