Comment vérifier que le disque dur est rempli de zéros sous Linux?

15

J'ai un disque dur rempli de zéros.

Comment vérifier si tous les bits du disque dur sont des zéros en utilisant bash?

gkfvbnhjh2
la source
Serait-il acceptable de simplement écraser le lecteur entier avec des zéros? Ou avez-vous réellement besoin de confirmer le contenu actuel?
Bob
Je veux vérifier que le disque dur est rempli de zéros.
gkfvbnhjh2
1
En théorie, il pourrait y avoir un bug dans les outils de nettoyage des données qui laisse certaines données intactes. Je ne veux pas être sûr que chaque bit est nul. Alors, comment puis-je vérifier si le disque dur est plein de zéros?
gkfvbnhjh2
Pourquoi des zéros? N'écririez-vous pas au hasard plusieurs fois des zéros et des 1?
13
Parce que les 1 sont plus étroits que les 0, vous pouvez voir plus facilement les anciennes données entre eux.
ChrisA

Réponses:

28

odremplacera les exécutions de la même chose *, vous pouvez donc facilement l'utiliser pour rechercher des octets non nuls:

$ sudo od /dev/disk2 | head
0000000    000000  000000  000000  000000  000000  000000  000000  000000
*
234250000
Gordon Davisson
la source
8
J'ajouterais | headà la fin de cela, de sorte que s'il s'avère que le lecteur n'est pas mis à zéro, il s'arrête après avoir produit juste assez de sortie pour montrer le fait, au lieu de vider le lecteur entier à l'écran.
Wyzard
2
@Wyzard: Excellente idée; Je vais l'ajouter à ma réponse.
Gordon Davisson
8

J'ai écrit un petit programme C ++ pour le faire, source disponible ici .

Pour le construire:

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

Pour l'exécuter:

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

Il affichera la position et la valeur de tout octet différent de zéro. Vous pouvez rediriger cette sortie vers un fichier avec >, par exemple:

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

Vous voudrez peut-être essayer de changer BUFFER_SIZEpour une meilleure efficacité. Je ne sais pas quelle valeur optimale pourrait être. Notez que cela affecte également la fréquence d'impression de la progression, ce qui affectera quelque peu la vitesse (la sortie d'impression vers la console est lente ). Ajouter 2>/dev/nullpour se débarrasser de la sortie de progression.

Je suis conscient que cela n'utilise pas bash standard, ni même des commandes intégrées, mais cela ne devrait pas nécessiter de privilèges supplémentaires. La solution de @Hennes est encore plus rapide (je n'ai vraiment rien optimisé - c'est la solution naïve); cependant, ce petit programme peut vous donner une meilleure idée du nombre d'octets manquants dans votre essuie-glace et de son emplacement. Si vous désactivez la sortie de progression, elle sera toujours plus rapide que la plupart des disques durs grand public peuvent lire (> 150 Mo / s), ce n'est donc pas un gros problème.

Une version plus rapide avec une sortie moins verbeuse est disponible ici . Cependant, elle est encore un peu plus lente que la solution @Hennes. Celui-ci, cependant, se fermera sur le premier caractère non nul qu'il rencontre, il est donc potentiellement beaucoup plus rapide s'il y a un non nul près du début du flux.


Ajout de la source au message pour garder la réponse mieux autonome:

#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
la source
C'est une excellente réponse, mais existe-t-il un moyen de faire fonctionner le script plus comme une commande normale - en utilisant iszero /dev/sdaplutôt qu'en exigeant qu'il soit canalisé avec quelque chose comme iszero < /dev/sda?
Hashim
1
@Hashim Cela a été écrit comme un programme jetable il y a un certain temps (de nos jours je le ferais au moins dans un langage de script comme Python plutôt que C compilé) ... cela dit, si vous vouliez prendre des arguments dans le la manière la plus simple, ce serait quelque part le long de la façon de le faire int main(int argc, char *argv[])et puis FILE* file = fopen(argv[1], "r");. Fait correctement, il comprendrait la vérification si l'argument existe réellement, la vérification des erreurs réussie (faites une ferrorvérification supplémentaire après le fopen), etc., mais trop de problèmes pour un programme jetable.
Bob
1
@Hashim Je soupçonne que les opérations vectorisées SIMD dans numpy seraient proches des instructions vectorisées en C. Et cela suppose que le compilateur C est assez intelligent pour vectoriser la boucle dans le programme C naïf. Il faudrait comparer pour être sûr; malheureusement, je n'ai pas vraiment le temps de le faire en ce moment. Le principal avantage de Python (et al.) Est qu'il est généralement disponible et exécutable sans compilateur, alors qu'il gccn'est pas nécessairement disponible sur toutes les distributions Linux sans retirer des packages supplémentaires. Là encore, numpy ne fait pas non plus partie des packages Python standard ...
Bob
1
@Hashim Si vous compilez avec -O3et -march=nativevous pourriez voir des accélérations; cela devrait garantir que GCC active la vectorisation automatique et utilise le meilleur disponible pour votre CPU actuel (AVX, SSE2 / SSE3, etc.). Parallèlement à cela, vous pouvez jouer avec la taille du tampon; différentes tailles de mémoire tampon peuvent être plus optimales avec des boucles vectorisées (je jouerais avec 1 Mo +, la valeur actuelle est de 1 Ko).
Bob
1
@Hashim Le commentaire ci-dessus a été modifié, au cas où vous ne l'auriez pas vu. Au-delà de cela, si vous souhaitez en discuter davantage, vous pouvez me cingler ( @Bob) dans le chat: chat.stackexchange.com/rooms/118/root-access
Bob
6

Élargissant la réponse de Gordon, pvfournit une indication de la longueur du processus:

$ 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
la source
C'est très utile avec un gros disque dur!
Martin Hansen
5

Cela semble une mauvaise solution inefficace, mais si vous ne devez vérifier qu'une seule fois:

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

Utilisation de dd pour lire à partir du disque sdX. (remplacez le X par le lecteur à partir duquel vous voulez lire),
puis traduisez tous les octets zéro non imprimables en quelque chose que nous pouvons gérer.

Ensuite, soit nous comptons les octets que nous pouvons gérer et vérifions s'il s'agit du bon nombre (à utiliser wc -cpour cela), soit nous ignorons le comptage et utilisons le -sou --squeeze-repeatspour compresser toutes les occurrences multiples en un seul caractère.

Il dd if=/dev/sdX | tr --squeeze-repeats "\000" "T"ne faut donc imprimer qu'un seul T.

Si vous voulez le faire régulièrement, vous voulez quelque chose de plus efficace.
Si vous ne voulez faire cela qu'une seule fois, alors ce kludge peut vérifier que votre essuie-glace normal fonctionne et que vous pouvez lui faire confiance.

Hennes
la source
Pourquoi considérez-vous cette solution comme inefficace? Y a-t-il une mise en mémoire tampon qui nécessite une lecture bien au-delà du premier emplacement non NUL?
Daniel Beck
Y a-t-il un problème potentiel où un «T» littéral est présent dans la vapeur en tant que seul caractère non nul?
Bob
Vrai. C'est un défaut de conception. Je n'utilise pas non plus bash (le shell lui-même), mais j'ai supposé qu'avec "Bash" vous vouliez dire "Pas de bash, en utilisant une invite de shell et des outils en mode texte standard".
Hennes
3
@daniel: Un programme C simple devrait être capable de lire toutes les données sans changer chaque octet de lecture. Ce qui serait plus efficace et plus esthétique. L'écriture d'un tel programme peut également prendre beaucoup plus de temps que l'utilisation inefficace des outils disponibles.
Hennes
3

Pour vérifier uniquement, vous verrez tous les blocs qui ne correspondent pas répertoriés

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

Ou utilisez des badblocks pour les écrire ainsi que pour vérifier:

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

Le test destructif par défaut est mon effacement sécurisé de choix

sudo badblocks -svw /dev/sdX

Si quelqu'un peut récupérer quoi que ce soit après avoir rempli le lecteur avec une alternance de 0 et de 1, alors leur complément, puis tous les 1, puis tous les 0, avec chaque passe vérifiée, cela a fonctionné, bonne chance à eux!

Effectue également une bonne vérification de pré-déploiement sur les nouveaux disques

man badblocks

pour d'autres options

Je ne dis pas que c'est rapide, mais ça marche ...

Beardy
la source
2

Le meilleur des deux mondes. Cette commande sautera les secteurs défectueux:

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

Utilisez kill -USR1 <pid of dd>pour voir les progrès.

jiveformation
la source
0

Il y a quelque temps, j'étais curieux de savoir AIO. Le résultat a été un exemple de programme de test qui vérifie les secteurs (blocs de 512 octets) qui le sont NUL. Vous pouvez voir cela comme une variante d'un détecteur de régions de fichiers épars . Je pense que la source dit tout.

  • Si la totalité du fichier / lecteur est NULsortie, cela ressemble 0000000000-eof. Notez qu'il y a une astuce dans le programme, fonctionfin() n'est pas appelée à la ligne 107 pour donner la sortie affichée.
  • Non fortement testé, peut donc contenir des bugs
  • Le code est un peu plus long, car AIO n'est pas aussi simple que d'autres façons,
  • Cependant, AIOc'est probablement le moyen le plus rapide de garder un lecteur occupé à lire , car la NULcomparaison est effectuée pendant la lecture du bloc de données suivant. (Nous pourrions extraire quelques millisecondes supplémentaires en faisant un chevauchementAIO , mais je ne pense vraiment pas que cela vaut la effort.)
  • Il revient toujours truesi le fichier est lisible et que tout a fonctionné. Il ne revient pasfalse si le fichier est non NUL.
  • Il suppose que la taille du fichier est un multiple de 512. Il y a un bogue sur le dernier secteur, mais sur un fichier entièrement, NULil fonctionne toujours, car les tampons de mémoire contiennent déjà NUL. Si quelqu'un pense que cela a besoin d'un correctif, à la ligne 95, le memcmp(nullblock, buf+off, SECTOR)pourrait lirememcmp(nullblock, buf+off, len-off<SECTOR : len-off : SECTOR) . Mais la seule différence est que le "rapport final" est peut-être un peu aléatoire (pas pour un fichier qui l'est entièrement NUL).
  • La modification memcmp()corrige également un autre problème sur les plates-formes, qui ne NUL alloc()réduisent pas la mémoire, car le code ne le fait pas. Mais cela ne peut être vu que par des fichiers de moins de 4 Mo, mais c'est checknulprobablement une surpuissance pour une si petite tâche;)

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
la source
0

Je voulais publier cette solution intelligente à partir d'une question similaire mais antérieure, publiée par un utilisateur qui ne s'est pas connecté depuis un certain temps:

Il y a un appareil /dev/zero sur un système Linux qui donne toujours des zéros lors de la lecture.

Alors, que diriez-vous de comparer votre disque dur avec cet appareil:

cmp /dev/sdX /dev/zero

Si tout va bien avec la remise à zéro de votre disque dur, cela se terminera par:

cmp: EOF on /dev/sdb

vous indiquant que les deux fichiers sont les mêmes jusqu'à ce qu'ils arrivent à la fin du disque dur. S'il y a un bit différent de zéro sur le disque durcmp il vous indiquera où il se trouve dans le fichier.

Si le pvpackage est installé, alors:

pv /dev/sdX | cmp /dev/zero

fera la même chose avec une barre de progression pour vous amuser pendant qu'il vérifie votre lecteur (le EOF sera désormais sur STDIN plutôt que sur sdX).

Hashim
la source