Wie überprüfe ich, ob die Festplatte unter Linux mit Nullen gefüllt ist?

15

Ich habe eine Festplatte mit Nullen gefüllt.

Wie kann man mit bash überprüfen, ob alle Bits auf der Festplatte Nullen sind?

gkfvbnhjh2
quelle
Wäre es akzeptabel, nur das gesamte Laufwerk mit Nullen zu überschreiben? Oder müssen Sie den aktuellen Inhalt tatsächlich bestätigen?
Bob
Ich möchte überprüfen, ob die Festplatte mit Nullen gefüllt ist.
gkfvbnhjh2
1
Theoretisch könnte es einen Fehler in den Datenbereinigungstools geben, der einige Daten intakt lässt. Ich will nicht sicher sein, dass jedes Bit Null ist. Wie überprüfe ich, ob die Festplatte mit Nullen gefüllt ist?
gkfvbnhjh2
Warum Nullen? Würden Sie nicht mehrmals zufällig Nullen und Einsen schreiben?
13
Da Einsen schmaler als Nullen sind, können Sie die alten Daten zwischen ihnen leichter sehen.
ChrisA

Antworten:

28

odersetzt Läufe derselben Sache durch *, sodass Sie problemlos nach Bytes ungleich Null suchen können:

$ sudo od /dev/disk2 | head
0000000    000000  000000  000000  000000  000000  000000  000000  000000
*
234250000
Gordon Davisson
quelle
8
Ich füge noch hinzu | head, dass, wenn sich herausstellt, dass das Laufwerk nicht auf Null gesetzt ist, es stoppt, nachdem gerade genug Ausgabe erzeugt wurde, um die Tatsache zu zeigen, anstatt das gesamte Laufwerk auf dem Bildschirm auszugeben.
Wyzard
2
@ Wyzard: Ausgezeichnete Idee; Ich werde es zu meiner Antwort hinzufügen.
Gordon Davisson
8

Ich habe dazu ein kurzes C ++ - Programm geschrieben, den Quellcode finden Sie hier .

Um es zu bauen:

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

Um es auszuführen:

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

Es wird die Position und den Wert aller Bytes ungleich Null ausgegeben. Sie können diese Ausgabe in eine Datei umleiten >, z. B .:

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

Möglicherweise möchten Sie Änderungen BUFFER_SIZEvornehmen, um die Effizienz zu verbessern. Ich bin nicht sicher, was ein optimaler Wert sein könnte. Beachten Sie, dass dies auch die Häufigkeit des Druckvorgangs beeinflusst, was sich etwas auf die Geschwindigkeit auswirkt (die Druckausgabe an die Konsole ist langsam ). Hinzufügen 2>/dev/null, um die Fortschrittsausgabe zu entfernen.

Mir ist bewusst, dass dies weder Standard-Bash noch integrierte Funktionen verwendet, es sollten jedoch keine zusätzlichen Berechtigungen erforderlich sein. Die Lösung von @Hennes ist immer noch schneller (ich habe nichts wirklich optimiert - das ist die naive Lösung); Dieses kleine Programm kann Ihnen jedoch eine bessere Vorstellung davon geben, wie viele Bytes Ihr Wischer verpasst hat und an welcher Stelle. Wenn Sie die Fortschrittsausgabe deaktivieren, ist sie immer noch schneller als die meisten herkömmlichen Festplatten (> 150 MB / s). Dies ist also kein großes Problem.

Eine schnellere Version mit weniger ausführlicher Ausgabe ist hier verfügbar . Es ist jedoch immer noch etwas langsamer als die Lösung von @Hennes. Dieses wird jedoch beim ersten Zeichen, das nicht Null ist, beendet, sodass es möglicherweise viel schneller ist, wenn sich am Anfang des Streams ein Wert ungleich Null befindet.


Hinzufügen einer Quelle zum Posten, um die Antwort in sich geschlossener zu halten:

#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;
}
Bob
quelle
Dies ist eine großartige Antwort, aber gibt es eine Möglichkeit, das Skript so zu gestalten, iszero /dev/sdadass es eher wie ein normaler Befehl funktioniert - mit etwas anderem als mit etwas, das mit etwas weitergeleitet werden muss iszero < /dev/sda?
Hashim
1
@Hashim Dies wurde vor einiger Zeit mehr oder weniger als ein Wegwerfprogramm geschrieben (heutzutage würde ich es zumindest in einer Skriptsprache wie Python machen, anstatt C zu kompilieren) am einfachsten wäre es irgendwo in der Art, wie man es macht int main(int argc, char *argv[])und dann FILE* file = fopen(argv[1], "r");. Bei ordnungsgemäßer Ausführung wird u. A. Überprüft, ob das Argument tatsächlich vorhanden ist, ob das Öffnen erfolgreich war (führen ferrorSie nach dem eine zusätzliche Überprüfung durch fopen) usw. Für ein Wegwerfprogramm ist dies jedoch zu schwierig.
Bob
1
@Hashim Ich vermute, dass SIMD-vektorisierte Operationen in numpy in der Nähe von vektorisierten Anweisungen in C liegen. Und das unter der Annahme, dass der C-Compiler intelligent genug ist, um die Schleife im naiven C-Programm zu vektorisieren. Müsste ein Benchmarking durchführen, um sicher zu sein; Leider habe ich momentan nicht wirklich die Zeit dafür. Der Hauptvorteil von Python (et al.) gccIst, dass es im Allgemeinen ohne Compiler verfügbar und lauffähig ist, während es nicht unbedingt auf allen Linux-Distributionen verfügbar ist, ohne dass zusätzliche Pakete heruntergeladen werden müssen. Andererseits ist numpy auch nicht Teil von Standard-Python-Paketen ...
Bob
1
@Hashim Wenn Sie mit kompilieren -O3und -march=nativemöglicherweise einige Beschleunigungen sehen; Das sollte sicherstellen, dass GCC die automatische Vektorisierung aktiviert und das Beste für Ihre aktuelle CPU verwendet (AVX, SSE2 / SSE3 usw.). Außerdem können Sie mit der Puffergröße spielen. Unterschiedliche Puffergrößen sind bei vektorisierten Schleifen möglicherweise optimaler (ich würde mit 1 MB + spielen, die aktuelle Größe ist 1 KB).
Bob
1
@Hashim Über Kommentar bearbeitet, falls Sie nicht gesehen haben. Wenn Sie darüber hinaus weiter diskutieren möchten , können Sie mich ( @Bob) im Chat anpingen
Bob
6

Die Antwort von Gordon gibt Aufschluss darüber, pvwie weit der Prozess fortgeschritten ist:

$ 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
quelle
Dies ist sehr nützlich bei einer großen Festplatte!
Martin Hansen
5

Dies scheint eine hässliche ineffiziente Lösung zu sein, aber wenn Sie nur einmal prüfen müssen:

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

Verwenden von dd zum Lesen von der Festplatte sdX. (ersetzen Sie die X mit dem Laufwerk , von dem Sie lesen wollen),
dann übersetzen alle nicht druckbaren Null - Bytes zu etwas , das wir verarbeiten kann.

Als Nächstes zählen wir entweder die Bytes, die wir verarbeiten können, und prüfen, ob es die richtige Zahl ist (verwenden Sie sie wc -cdafür), oder wir überspringen die Zählung und verwenden -soder --squeeze-repeats, um alle mehrfachen Vorkommen zu einem einzelnen Zeichen zusammenzufassen.

Daher dd if=/dev/sdX | tr --squeeze-repeats "\000" "T"sollte nur ein einziges T ausgegeben werden.

Wenn Sie dies regelmäßig tun möchten, möchten Sie etwas effizienteres.
Wenn Sie dies nur einmal tun möchten, kann dieser Fehler bestätigen, dass Ihr normaler Wischer funktioniert und Sie ihm vertrauen können.

Hennes
quelle
Warum halten Sie diese Lösung für ineffizient? Gibt es eine Pufferung, die ein Lesen weit hinter der ersten Nicht-NUL-Position erfordert?
Daniel Beck
Gibt es ein potenzielles Problem, bei dem ein buchstäbliches "T" als einziges Zeichen ungleich Null im Steam vorhanden ist?
Bob
Wahr. Das ist ein Designfehler. Ich benutze auch nicht bash (die Shell selbst), aber ich nahm an, dass Sie mit "Bash" "Nicht von bash, von der Verwendung von Shell-Eingabeaufforderungen und Standard-Textmodustools" meinten.
Hennes
3
@daniel: Ein einfaches C-Programm sollte in der Lage sein, alle Daten zu lesen, ohne jedes gelesene Byte zu ändern. Welches wäre effizienter und ästhetisch ansprechend. Es kann auch viel länger dauern, ein solches Programm zu schreiben, als nur die verfügbaren Tools ineffizient zu verwenden.
Hennes
3

Um nur zu überprüfen, sehen Sie alle Blöcke, die nicht übereinstimmen, aufgelistet

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

Oder benutze Badblocks, um sie zu schreiben und zu überprüfen:

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

Der voreingestellte destruktive Test ist das sichere Löschen meiner Wahl

sudo badblocks -svw /dev/sdX

Wenn irgendjemand etwas abrufen kann, nachdem er das Laufwerk mit abwechselnden Nullen und Einsen gefüllt hat, dann sein Komplement, dann alle Einsen, dann alle Nullen, und bei jedem bestätigten Durchgang hat es funktioniert, viel Glück für sie!

Führt auch bei neuen Laufwerken eine gute Überprüfung vor der Bereitstellung durch

man badblocks

für andere Optionen

Das heißt nicht, dass es schnell ist, aber es funktioniert ...

Beardy
quelle
2

Beste aus beiden Welten. Dieser Befehl überspringt fehlerhafte Sektoren:

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

Verwenden Sie kill -USR1 <pid of dd>, um den Fortschritt zu sehen.

Jiveformation
quelle
0

Vor einiger Zeit war ich neugierig AIO. Das Ergebnis war ein Probentestprogramm , das für die Sektoren (512 - Byte - Blöcke) , die zu überprüfen sind passiert NUL. Sie können dies als eine Variante eines Detektors für dünn besetzte Dateibereiche betrachten . Ich denke, die Quelle sagt alles.

  • Wenn die gesamte Datei / das gesamte Laufwerk NULausgegeben wird, sieht das so aus 0000000000-eof. Beachten Sie, dass das Programm einen Trick enthält. Die Funktion fin()wird in Zeile 107 nicht absichtlich aufgerufen, um die angezeigte Ausgabe zu erhalten.
  • Nicht stark getestet, kann daher Fehler enthalten
  • Der Code ist etwas länger, da er AIOnicht so einfach ist wie andere Möglichkeiten.
  • Dies AIOist jedoch wahrscheinlich der schnellste Weg, um ein Laufwerk mit dem Lesen zu beschäftigen , da der NULVergleich ausgeführt wird, während der nächste Datenblock eingelesen AIOwird Anstrengung.)
  • Es wird immer zurückgegeben, truewenn die Datei lesbar ist und alles funktioniert hat. Es wird nicht zurückgegeben, falsewenn die Datei nicht vorhanden ist NUL.
  • Es wird davon ausgegangen, dass die Dateigröße ein Vielfaches von 512 ist. Es gibt einen Fehler im letzten Sektor, bei einer Datei NULfunktioniert er jedoch weiterhin, da die Speicherpuffer bereits enthalten NUL. Wenn jemand der Meinung ist, dass dies behoben werden muss, könnte in Zeile 95 memcmp(nullblock, buf+off, SECTOR)gelesen werden memcmp(nullblock, buf+off, len-off<SECTOR : len-off : SECTOR). Der einzige Unterschied ist jedoch, dass die "Endberichterstattung" möglicherweise etwas zufällig ist (nicht für eine Datei, die vollständig ist NUL).
  • Die Änderung memcmp()behebt auch ein anderes Problem auf Plattformen, die keinen NUL alloc()Arbeitsspeicher haben, da der Code dies nicht tut. Dies kann aber nur bei Dateien mit weniger als 4 MiB auftreten, ist aber checknulfür eine so kleine Aufgabe wahrscheinlich ein reiner Overkill.

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
quelle
0

Wollte diese clevere Lösung aus einer ähnlichen, aber früheren Frage posten , die von einem Benutzer gestellt wurde, der sich längere Zeit nicht angemeldet hat:

Auf /dev/zeroeinem Linux-System gibt es ein Gerät , das beim Lesen immer Nullen gibt.

Wie wäre es also mit einem Vergleich Ihrer Festplatte mit diesem Gerät:

cmp /dev/sdX /dev/zero

Wenn alles in Ordnung ist, wenn Sie Ihre Festplatte auf Null setzen, wird sie beendet mit:

cmp: EOF on /dev/sdb

Sie werden darauf hingewiesen, dass die beiden Dateien bis zum Ende der Festplatte identisch sind. Wenn sich auf der Festplatte ein Bit ungleich Null befindet, cmpwerden Sie darüber informiert, wo es sich in der Datei befindet.

Wenn Sie das pvPaket installiert haben, dann:

pv /dev/sdX | cmp /dev/zero

Das Gleiche geschieht mit einem Fortschrittsbalken, um Sie bei der Überprüfung Ihres Laufwerks zu unterhalten (das EOF befindet sich jetzt jedoch auf STDIN und nicht auf sdX).

Hashim
quelle