Como verificar se o disco rígido está cheio de zeros no Linux?


15

Eu tenho disco rígido cheio de zeros.

Como verificar se todos os bits no disco rígido são zeros usando o bash?


Seria aceitável sobrescrever toda a unidade com zeros? Ou você realmente precisa confirmar o conteúdo atual?
Bob

Quero verificar se o disco rígido está cheio de zeros.
precisa saber é o seguinte

1
Em teoria, pode haver um erro nas ferramentas de higienização de dados que deixam alguns dados intactos. Não quero ter certeza de que cada bit é zero. Então, como verifico se o disco rígido está cheio de zeros?
precisa saber é o seguinte

Por que zeros? Você não escreveria zeros e 1s aleatoriamente, várias vezes?

13
Como os 1s são mais estreitos que os 0s, é possível ver os dados antigos entre eles mais facilmente.
ChrisA

Respostas:


28

odsubstituirá as execuções da mesma coisa por *, para que você possa usá-lo facilmente para verificar bytes diferentes de zero:

$ sudo od /dev/disk2 | head
0000000    000000  000000  000000  000000  000000  000000  000000  000000
*
234250000

8
Eu acrescentaria | headao final disso, para que, se a unidade não estiver zerada, pare após produzir apenas o suficiente para mostrar o fato, em vez de colocar a unidade inteira na tela.
wyzard

2
@ Wyzard: Excelente ideia; Vou adicioná-lo à minha resposta.
Gordon Davisson

8

Eu escrevi um programa C ++ curto para fazer isso, fonte disponível aqui .

Para construí-lo:

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

Para executá-lo:

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

Ele exibirá a posição e o valor de quaisquer bytes diferentes de zero. Você pode redirecionar esta saída para um arquivo com >, por exemplo:

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

Você pode tentar mudar BUFFER_SIZEpara obter melhor eficiência. Não tenho certeza do valor ideal. Observe que isso também afeta a frequência com que imprime o progresso, o que afetará um pouco a velocidade (a saída de impressão no console é lenta ). Adicione 2>/dev/nullpara se livrar da saída do progresso.

Estou ciente de que isso não está usando o bash padrão, nem mesmo os internos, mas não deve exigir privilégios extras. A solução da @Hennes ainda é mais rápida (eu realmente não otimizei nada - esta é a solução ingênua); no entanto, este pequeno programa pode lhe dar uma idéia melhor de quantos bytes seu limpador perdeu e em que local. Se você desabilitar a saída de progresso, ainda será mais rápido do que a maioria dos discos rígidos de consumo pode ler (> 150 MB / s), então isso não é um grande problema.

Uma versão mais rápida com saída menos detalhada está disponível aqui . No entanto, ainda é um pouco mais lento que a solução da @Hennes. Este, no entanto, será encerrado no primeiro caractere diferente de zero que encontrar, por isso é potencialmente muito mais rápido se houver um diferente de zero próximo ao início do fluxo.


Adicionando fonte à postagem para manter a resposta melhor independente:

#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;
}

Essa é uma ótima resposta, mas existe alguma maneira de fazer o script funcionar mais como um comando normal - usando, em iszero /dev/sdavez de exigir que ele seja canalizado com algo parecido iszero < /dev/sda?
Hashim

1
@Hashim Isso foi escrito como um programa descartável há algum tempo (hoje em dia eu pelo menos faria isso em uma linguagem de script como Python, em vez de compilada em C) ... que dizia: se você quiser usar argumentos no maneira mais simples, seria em algum lugar ao longo das linhas de fazê-lo int main(int argc, char *argv[])e depois FILE* file = fopen(argv[1], "r");. Feito corretamente, incluiria a verificação se o argumento realmente existe, a verificação de erros com êxito (faça uma ferrorverificação adicional após a fopen), etc., mas muitos problemas para um programa descartável.
Bob

1
@Hashim Eu suspeito que operações vetorizadas SIMD em numpy estariam próximas das instruções vetorizadas em C. E isso pressupõe que o compilador C seja inteligente o suficiente para vetorizar o loop no programa C ingênuo. Teria que fazer benchmark para ter certeza; infelizmente não tenho tempo para fazer isso agora. A principal vantagem do Python (et al.) É que ele geralmente está disponível e pode ser executado sem um compilador, enquanto gccnão está necessariamente disponível em todas as distros do Linux sem a necessidade de baixar pacotes adicionais. Então, novamente numpy não é parte de pacotes Python padrão ou ...
Bob

1
@Hashim Se você compilar -O3e -march=nativepoderá ver algumas acelerações; isso deve garantir que o GCC habilite a vetorização automática e use o melhor disponível para sua CPU atual (AVX, SSE2 / SSE3, etc.). Junto com isso você pode jogar com o tamanho do buffer; tamanhos de buffer diferentes podem ser mais ideais com loops vetorizados (eu jogaria com 1 MB +, o atual é 1 kB).
Bob

1
@Hashim Acima do comentário editado, caso você não tenha visto. Além disso, se você quiser discutir mais, você pode me enviar um ping ( @Bob) no chat: chat.stackexchange.com/rooms/118/root-access
Bob

6

Expandindo a resposta de Gordon, pvfornece uma indicação de quão longe o processo está:

$ 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

Isso é muito útil com um grande disco rígido!
Martin Hansen

5

Parece uma solução feia e ineficiente, mas se você precisar verificar apenas uma vez:

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

Usando dd para ler do disco sdX. (substitua o X pela unidade da qual você deseja ler) e
depois traduza todos os zero bytes não imprimíveis em algo que possamos manipular.

Em seguida, contamos os bytes que podemos manipular e verificamos se é o número certo (use wc -cpara isso) ou pulamos a contagem e usamos o -sou--squeeze-repeats para espremer todas as múltiplas ocorrências em um único caractere.

Assim, dd if=/dev/sdX | tr --squeeze-repeats "\000" "T"deve imprimir apenas um único T.

Se você deseja fazer isso regularmente, deseja algo mais eficiente.
Se você quiser fazer isso apenas uma vez, esse kludge poderá verificar se o limpador normal está funcionando e se você pode confiar nele.


Por que você considera esta solução ineficiente? Existe algum buffer que requer leitura muito além do primeiro local não NUL?
Daniel Beck

Existe um problema em potencial onde um 'T' literal está presente no vapor como o único caractere diferente de zero?
Bob

Verdade. Essa é uma falha no design. Também não estou usando o bash (o próprio shell), mas assumi que com "Bash" você quis dizer "Não do bash, usando qualquer prompt de shell e ferramentas padrão de modo de texto".
Hennes 02/03

3
@daniel: Um programa C simples deve ser capaz de ler todos os dados sem alterar todos os bytes de leitura. O que seria mais eficiente e esteticamente agradável. Também pode levar muito mais tempo para escrever um programa desse tipo do que apenas usar as ferramentas disponíveis de maneira ineficiente.
Hennes 02/03

3

Para verificar apenas, você verá todos os blocos que não correspondem listados

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

Ou use badblocks para escrevê-los e verificar:

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

O teste destrutivo padrão é minha opção segura de exclusão

sudo badblocks -svw /dev/sdX

Se alguém puder recuperar alguma coisa depois de encher a unidade com 0s e 1s alternados, então o complemento, todos os 1s e todos os 0s, com cada passe verificado, funcionou, boa sorte para eles!

Também faz uma boa verificação pré-implantação em novas unidades

man badblocks

para outras opções

Não estou dizendo que é rápido, mas funciona ...


2

Melhor dos dois mundos. Este comando irá pular setores defeituosos:

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

Use kill -USR1 <pid of dd>para ver o progresso.


0

Algum tempo atrás, eu estava curioso AIO. O resultado foi um programa de teste de amostra que verifica os setores (blocos de 512 bytes) que são NUL. Você pode ver isso como uma variante de um detector de regiões de arquivo esparsas . Eu acho que a fonte diz tudo.

  • Se o arquivo / unidade inteiro for NULexibido, será semelhante 0000000000-eof. Observe que há um truque no programa, a função fin()não é chamada na linha 107 de propósito para fornecer a saída mostrada.
  • Não é muito testado, portanto pode conter bugs
  • O código é um pouco mais longo, pois AIOnão é tão direto quanto outras formas,
  • Contudo AIO é provavelmente a maneira mais rápida de manter uma unidade ocupada lendo , porque a NULcomparação é feita enquanto o próximo bloco de dados é lido. (Podemos espremer mais alguns milissegundos fazendo sobreposiçõesAIO , mas eu realmente não acho que isso vale a pena o esforço.)
  • Sempre retorna true se o arquivo é legível e tudo funcionou. Ele não retorna falsese o arquivo não for NUL.
  • Ele pressupõe que o tamanho do arquivo seja múltiplo de 512. Há um erro no último setor; no entanto, em um arquivo completamente NULele ainda funciona, pois os buffers de memória já contêmNUL . Se alguém acha que isso precisa de uma correção, na linha 95 memcmp(nullblock, buf+off, SECTOR)pode ler-se memcmp(nullblock, buf+off, len-off<SECTOR : len-off : SECTOR). Mas a única diferença é que o "relatório final" talvez seja um pouco aleatório (não para um arquivo que é inteiramente NUL).
  • A alteração memcmp()também corrige outro problema nas plataformas, que nãoNUL alloc() editam memória, porque o código não faz isso. Mas isso só pode ser visto em arquivos com menos de 4 MiB, mas checknulprovavelmente é um exagero para uma tarefa tão pequena;)

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;
}

0

Queria postar esta solução inteligente a partir de uma pergunta semelhante, mas anterior, postada por um usuário que não faz login há um tempo:

Existe um dispositivo /dev/zero em um sistema Linux que sempre dá zeros quando lido.

Então, que tal comparar seu disco rígido com este dispositivo:

cmp /dev/sdX /dev/zero

Se tudo estiver bem em zerar o disco rígido, ele terminará com:

cmp: EOF on /dev/sdb

dizendo que os dois arquivos são os mesmos até o final do disco rígido. Se houver um bit diferente de zero no disco rígido, cmpserá informado onde está o arquivo.

Se você tiver o pvpacote instalado, então:

pv /dev/sdX | cmp /dev/zero

fará o mesmo com uma barra de progresso para mantê-lo divertido enquanto verifica sua unidade (o EOF agora estará no STDIN, e não no sdX).

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.