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


16

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

Як перевірити, чи всі біти на жорсткому диску є нулями з використанням bash?


Чи було б прийнятним просто перезаписати весь диск з нулями? Або вам насправді потрібно підтвердити поточний вміст?
Боб

Хочу переконатися, що вінчестер заповнений нулями.
gkfvbnhjh2

1
Теоретично може бути помилка в інструментах санітарії даних, яка залишає деякі дані недоторканими. Я не хочу бути впевненим, що кожен біт дорівнює нулю. Тож як я можу перевірити, чи HDD заповнений нулями?
gkfvbnhjh2

Чому нулі? Ви не випадково кілька разів записуєте нулі та 1s?

13
Оскільки значення 1 є вужчим ніж 0, ви можете переглядати старі дані між ними легше.
ChrisA

Відповіді:


29

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, не знімаючи додаткових пакетів. Тоді знову нуме не входить до стандартних пакетів Python ...
Боб

1
@Hashim Якщо ви компілюєте -O3і -march=native, можливо, ви побачите деякі прискорення; це повинно переконатися, що GCC дозволяє автоматичну векторизацію та використовує найкращі для вашого поточного процесора (AVX, SSE2 / SSE3 тощо). Поряд з цим ви можете грати з розміром буфера; різні розміри буфера можуть бути більш оптимальними для векторизованих циклів (я б грав з 1 МБ +, поточний - 1 КБ).
Боб

1
@Hashim Вище відредагований коментар, якщо ви його не бачили. Крім того, якщо ви хочете обговорити далі, ви можете пінг-мене ( @Bob) у чаті: chat.stackexchange.com/rooms/118/root-access
Боб

7

Розширюючи відповідь Гордона, 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"слід надрукувати лише одну Т.

Якщо ви хочете робити це регулярно, тоді ви хочете щось ефективніше.
Якщо ви хочете зробити це лише один раз, тоді ця шахрайство може перевірити, чи працює ваш звичайний склоочисник і що ви можете йому довіряти.


Чому ви вважаєте це рішення неефективним? Чи є якась буферизація, яка потребує читання далеко поза першим місцем, яке не стосується NUL?
Даніель Бек

Чи є потенційна проблема, коли буквальне «Т» присутнє в парі як єдиний ненульовий символ?
Боб

Правда. Це недолік у дизайні. Я також не використовую bash (сама оболонка), але я припустив, що під "Bash" ви мали на увазі "Not from bash, з використання будь-яких підказок оболонки та стандартних інструментів текстового режиму".
Геннес

3
@daniel: Проста програма C повинна мати можливість читати всі дані, не змінюючи кожен байт читання. Що було б більш ефективно та естетично. Також може знадобитися набагато більше часу, щоб написати таку програму, ніж просто використовувати наявні інструменти неефективно.
Геннес

3

Щоб лише перевірити, ви побачите блоки, які не відповідають переліченому

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

Або використовуйте чорні блоки, щоб написати їх, а також перевірити:

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>щоб побачити прогрес.


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()éd пам'яті, тому що код не робить. Але це може бути помічено лише файлами, меншими за 4 Мб, але, checknulймовірно, це зайвий надмір для такої невеликої задачі;)

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

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

У /dev/zeroсистемі Linux є пристрій, який завжди дає нулі при читанні.

Отже, як щодо порівняння вашого жорсткого диска з цим пристроєм:

cmp /dev/sdX /dev/zero

Якщо все добре з нулюванням вашого жорсткого диска, воно закінчиться:

cmp: EOF on /dev/sdb

повідомляють вам, що два файли однакові, поки він не дійшов до кінця жорсткого диска. Якщо на жорсткому диску є нульовий біт, cmpвам підкажуть, де він знаходиться у файлі.

Якщо у вас встановлений pvпакет, виконайте вказані нижче дії .

pv /dev/sdX | cmp /dev/zero

зробимо те саме, що і з панеллю прогресу, щоб не розважатись під час перевірки вашого накопичувача (EOF тепер буде на STDIN, а не на sdX).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.