Как проверить, что жесткий диск заполнен нулями в Linux?

15

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

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

gkfvbnhjh2
источник
Было бы приемлемо просто перезаписать весь диск нулями? Или вам действительно нужно подтвердить текущее содержание?
Боб
Я хочу убедиться, что жесткий диск заполнен нулями.
gkfvbnhjh2
1
Теоретически в инструментах очистки данных может быть ошибка, из-за которой некоторые данные остаются нетронутыми. Я не хочу быть уверенным, что каждый бит равен нулю. Итак, как я могу проверить, заполнен ли жесткий диск нулями?
gkfvbnhjh2
Почему нули? Разве вы не случайно напишите нули и 1, несколько раз?
13
Поскольку 1 меньше 0, вы можете легко увидеть старые данные между ними.
ChrisA

Ответы:

28

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

$ sudo od /dev/disk2 | head
0000000    000000  000000  000000  000000  000000  000000  000000  000000
*
234250000
Гордон Дэвиссон
источник
8
Я бы добавил | headк концу этого, чтобы, если окажется, что диск не обнулен, он остановится после того, как выдаст достаточно информации, чтобы показать факт, вместо того, чтобы вывести весь диск на экран.
Wyzard
2
@Wyzard: отличная идея; Я добавлю это к моему ответу.
Гордон Дэвиссон
8

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

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

wget -O iszero.cpp https://gist.github.com/BobVul/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;
}
боб
источник
Это отличный ответ, но есть ли способ заставить скрипт работать больше как обычная команда - iszero /dev/sdaвместо того, чтобы требовать, чтобы он был передан с чем-то вроде iszero < /dev/sda?
Хашим
1
@Hashim Это было написано как более или менее одноразовая программа довольно давно (в настоящее время я бы, по крайней мере, сделал это на языке сценариев, таких как Python, а не скомпилированный C) ... то есть, если вы хотите принимать аргументы в Самый простой способ, это было бы где-то по линии создания этого, int main(int argc, char *argv[])а затем FILE* file = fopen(argv[1], "r");. Если все сделано правильно, это будет включать проверку, действительно ли аргумент существует, проверку на успешное открытие (выполните дополнительную ferrorпроверку после fopen) и т. Д., Но слишком много проблем для одноразовой программы.
Боб
1
@Hashim Я подозреваю, что векторизованные операции SIMD в numpy будут близки к векторизованным инструкциям в C. И это при условии, что компилятор C достаточно умен, чтобы векторизовать цикл в наивной C-программе. Надо бы ориентироваться, чтобы быть уверенным; к сожалению, у меня нет времени, чтобы сделать это прямо сейчас. Основное преимущество Python (и др.) Заключается в том, что он обычно доступен и работает без компилятора, хотя gccне обязательно доступен во всех дистрибутивах Linux без удаления дополнительных пакетов. С другой стороны, numpy также не является частью стандартных пакетов Python ...
Боб
1
@Hashim Если вы скомпилируете, -O3и -march=nativeвы можете увидеть некоторые ускорения; это должно гарантировать, что GCC включает автоматическую векторизацию и использует лучшие из доступных для вашего текущего процессора (AVX, SSE2 / SSE3 и т. д.). Наряду с этим вы можете играть с размером буфера; Различные размеры буфера могут быть более оптимальными для векторизованных циклов (я бы играл с 1 МБ +, текущий 1 КБ).
Боб
1
@Hashim Выше комментарий отредактирован, если вы не видели. Кроме того, если вы хотите обсудить дальше, вы можете пинговать меня ( @Bob) в чате: chat.stackexchange.com/rooms/118/root-access
Боб
6

Расширяя ответ Гордона, он 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.

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

Hennes
источник
Почему вы считаете это решение неэффективным? Есть ли какая-то буферизация, которая требует чтения далеко за пределами первого не-NUL местоположения?
Даниэль Бек
Есть ли потенциальная проблема, когда в паре присутствует буквально «Т» как единственный ненулевой символ?
Боб
Правда. Это недостаток в дизайне. Я также не использую bash (сама оболочка), но я предположил, что под «Bash» вы имели в виду «не из bash, из использования любых подсказок оболочки и стандартных инструментов текстового режима».
Хеннес
3
@daniel: простая программа на C должна иметь возможность читать все данные без изменения каждого прочитанного байта. Что было бы более эффективным и эстетически приятным. Для написания такой программы может потребоваться гораздо больше времени, чем для неэффективного использования доступных инструментов.
Хеннес
3

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

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

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

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

бородачей
источник
2

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

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

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

jiveformation
источник
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()редактируют память, потому что код этого не делает. Но это может быть видно только для файлов checknulразмером менее 4 МБ, но, вероятно, это просто излишество для такой маленькой задачи;)

НТН

/* 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
источник
0

Хотел опубликовать это умное решение по аналогичному, но более раннему вопросу, опубликованному пользователем, который давно не вошел в систему:

В /dev/zeroсистеме Linux есть устройство, которое всегда дает нули при чтении.

Итак, как насчет сравнения вашего жесткого диска с этим устройством:

cmp /dev/sdX /dev/zero

Если все хорошо с обнулением вашего жесткого диска, он закончится с:

cmp: EOF on /dev/sdb

говорю вам, что два файла одинаковы, пока не дойдут до конца жесткого диска. Если на жестком диске есть ненулевой бит, cmpон сообщит вам, где он находится в файле.

Если у вас установлен pvпакет, то:

pv /dev/sdX | cmp /dev/zero

будет делать то же самое с индикатором выполнения, чтобы вы были удивлены, пока он проверяет ваш диск (хотя EOF теперь будет на STDIN, а не на sdX).

Хашим
источник