12

У меня жесткий диск заполнен нулями.

Как проверить, что все биты на жестком диске являются нулями, используя bash?

7 ответов7

22

od заменит запуск одной и той же вещи на * , так что вы можете легко использовать ее для поиска ненулевых байтов:

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

Я написал короткую C++ программу для этого, источник доступен здесь.

Чтобы построить это:

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

Чтобы запустить это:

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

Он выведет позицию и значение любых ненулевых байтов. Вы можете перенаправить этот вывод в файл с помощью > , например:

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

Вы можете попробовать изменить BUFFER_SIZE для повышения эффективности. Я не уверен, какое оптимальное значение может быть. Обратите внимание, что это также влияет на частоту выполнения печати, что несколько влияет на скорость (печать выводится на консоль медленно). Добавьте 2>/dev/null чтобы избавиться от результатов выполнения.

Я знаю, что это не использует стандартный Bash, ни даже встроенные, но это не должно требовать каких-либо дополнительных привилегий. Решение @Hennes все еще быстрее (я ничего не оптимизировал - это наивное решение); тем не менее, эта небольшая программа может дать вам лучшее представление о том, сколько байтов пропал ваш очиститель и в каком месте. Если вы отключите вывод хода выполнения, он все равно будет быстрее, чем может прочитать большинство потребительских жестких дисков (> 150 МБ / с), так что это не является большой проблемой.

Более быстрая версия с менее подробным выводом доступна здесь. Тем не менее, это все еще немного медленнее, чем решение @Hennes. Этот, однако, завершит работу с первым ненулевым символом, с которым он сталкивается, так что он потенциально намного быстрее, если ненулевой символ находится в начале потока.


Добавление источника к сообщению, чтобы держать ответ лучше самодостаточным:

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

Расширяя ответ Гордона, pv показывает, как далеко продвинулся процесс:

$ 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
5

Это кажется уродливым неэффективным решением, но если вам нужно проверить только один раз:

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

Использование dd для чтения с диска sdX . (замените X на диск, который вы хотите прочитать),
Затем переводим все непечатаемые нулевые байты в то, что мы можем обработать.

Затем мы либо подсчитываем байты, которые можем обработать, и проверяем, является ли это правильным числом (для этого используем wc -c ), либо пропускаем подсчет и используем -s или --squeeze-repeats чтобы сжать все множественные вхождения в один символ ,

Таким образом, dd if=/dev/sdX | tr --squeeze-repeats "\000" "T" должен печатать только один T.

Если вы хотите делать это регулярно, то вы хотите что-то более эффективное.
Если вы хотите сделать это только один раз, тогда этот клудж может проверить, работает ли ваш обычный стеклоочиститель и можете ли вы доверять ему.

2

Только для проверки вы увидите все блоки, которые не соответствуют перечисленным

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

Или используйте badblocks, чтобы написать их, а также проверить:

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

Разрушающий тест по умолчанию - мое безопасное стирание выбора

sudo badblocks -svw /dev/sdX

Если кто-нибудь может извлечь что-либо после заполнения диска чередующимися 0 и 1, то их дополнение, затем все 1, затем все 0, с каждым проверенным проходом, сработавшим, удачи им!

Хорошая проверка перед развертыванием на новых дисках

man badblocks

для других вариантов

Не сказать, что это быстро, но это работает ...

1

Лучшее из обоих миров. Эта команда пропустит плохие сектора:

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

Используйте kill -USR1 <pid of dd> чтобы увидеть прогресс.

0

Некоторое время назад мне было интересно узнать об AIO . Результатом стала тестовая программа, которая проверяет сектора (блоки 512 байт), которые имеют значение NUL . Вы можете видеть это как вариант детектора разреженных областей файла . Я думаю, что источник говорит все это.

  • Если весь файл / диск имеет значение NUL вывод будет выглядеть как 0000000000-eof . Обратите внимание, что в программе есть хитрость, функция fin() не вызывается в строке 107 специально для получения показанного результата.
  • Не проверено, поэтому может содержать ошибки
  • Код немного длиннее, так как AIO не так прост, как другие способы,
  • однако AIO , вероятно, является самым быстрым способом сохранить занятость чтения диска , потому что сравнение NUL выполняется во время чтения следующего блока данных. (Мы могли бы выжать еще несколько миллисекунд, сделав AIO перекрытием, но я действительно не думаю, что это стоит усилий.)
  • Он всегда возвращает true если файл доступен для чтения и все работает. Он не возвращает false если файл не NUL .
  • Предполагается, что размер файла кратен 512. В последнем секторе есть ошибка, однако для файла, полностью NUL он все еще работает, поскольку буферы памяти уже содержат NUL . Если кто-то считает, что это нужно исправить, в строке 95 memcmp(nullblock, buf+off, SECTOR) может прочитать memcmp(nullblock, buf+off, len-off<SECTOR : len-off : SECTOR) . Но единственное отличие состоит в том, что "отчет об окончании", возможно, немного случайный (не для файла, который является полностью NUL).
  • Измененный memcmp() также исправляет другую проблему на платформах, которые не выделяют NUL alloc() память, поскольку код этого не делает. Но это может быть видно только для файлов размером менее 4 МБ, но checknul вероятно, просто излишне для такой небольшой задачи;)

НТН

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

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .