Créez des données aléatoires avec dd et obtenez un «avertissement de lecture partielle». Les données après l'avertissement sont-elles désormais vraiment aléatoires?

16

Je crée un fichier de 1 To avec des données aléatoires avec dd if=/dev/urandom of=file bs=1M count=1000000. Maintenant, je vérifie kill -SIGUSR1 <PID>la progression et j'obtiens ce qui suit:

691581+0 Datensätze ein
691580+0 Datensätze aus
725174190080 Bytes (725 GB) kopiert, 86256,9 s, 8,4 MB/s
800950+1 Datensätze ein
800950+0 Datensätze aus
839856947200 Bytes (840 GB) kopiert, 99429,5 s, 8,4 MB/s
dd: warning: partial read (809620 bytes); suggest iflag=fullblock
803432+1 Datensätze ein
803431+1 Datensätze aus
842459273876 Bytes (842 GB) kopiert, 99791,3 s, 8,4 MB/s

Je ne peux pas interpréter l'avertissement. Ça dit quoi? Mon fichier est-il vraiment aléatoire après l'avertissement ou y a-t-il un problème? Que signifie +0 ou +1 800950+1 Datensätze einet 800950+0 Datensätze aussignifie? Après l'avertissement, c'est +1. Est-ce un nombre erroné?

supprimer
la source
Il serait plus facile de répondre si vous pouviez traduire les messages en anglais. Définissez également "vraiment aléatoire". De quel niveau de hasard avez-vous besoin, à quoi allez-vous l'utiliser?
terdon
Pour obtenir des messages en anglais, utilisez LC_ALL=Cdevant la commande, commeLC_ALL=C dd if=...
Volker Siegel

Réponses:

38

Résumé: ddest un outil grincheux qui est difficile à utiliser correctement. Ne l'utilisez pas, malgré les nombreux tutoriels qui vous le disent. dda une ambiance «credo unix street» qui y est attachée - mais si vous comprenez vraiment ce que vous faites, vous saurez que vous ne devriez pas le toucher avec un poteau de 10 pieds.

ddeffectue un seul appel à l' readappel système par bloc (défini par la valeur de bs). Il n'y a aucune garantie que l' readappel système renvoie autant de données que la taille de mémoire tampon spécifiée. Cela a tendance à fonctionner pour les fichiers normaux et les périphériques de bloc, mais pas pour les canaux et certains périphériques de caractères. Voir Quand dd convient-il pour copier des données? (ou, quand sont read () et write () partial) pour plus d'informations. Si l' readappel système renvoie moins d'un bloc complet, ddtransfère alors un bloc partiel. Il copie toujours le nombre spécifié de blocs, de sorte que le nombre total d'octets transférés est inférieur à celui demandé.

L'avertissement concernant une «lecture partielle» vous dit exactement ceci: l'une des lectures était partielle, donc ddtransféré un bloc incomplet. Dans le nombre de blocs, +1signifie qu'un bloc a été lu partiellement; puisque le nombre de sorties est +0, tous les blocs ont été écrits comme lus.

Cela n'affecte pas le caractère aléatoire des données: tous les octets qui sont ddécrits sont des octets de lecture /dev/urandom. Mais vous avez obtenu moins d'octets que prévu.

Linux /dev/urandomaccepte des requêtes arbitraires de grande taille (source: extract_entropy_userin drivers/char/random.c), il ddest donc normalement sûr lors de la lecture. Cependant, la lecture de grandes quantités de données prend du temps. Si le processus reçoit un signal, l' readappel système revient avant de remplir son tampon de sortie. Il s'agit d'un comportement normal et les applications sont censées appeler readen boucle; ddne le fait pas, pour des raisons historiques ( ddles origines de sombres, mais il semble avoir commencé comme un outil pour accéder aux bandes, qui ont des exigences particulières, et n'a jamais été adapté pour être un outil à usage général). Lorsque vous vérifiez la progression, cela envoie au ddprocessus un signal qui interrompt la lecture. Vous avez le choix entre savoir combien d'octetsddcopiera au total (assurez-vous de ne pas l'interrompre - pas de vérification de progression, pas de suspension), ou sachez combien d'octets ddont été copiés jusqu'à présent, auquel cas vous ne pouvez pas savoir combien d'octets de plus il copiera.

La version de dddans GNU coreutils (comme on le trouve sur Linux non embarqué et sur Cygwin) a un drapeau fullblockqui indique ddd'appeler readen boucle (et idem pour write) et donc de toujours transférer des blocs entiers. Le message d'erreur suggère que vous l'utilisiez; vous devez toujours l'utiliser (à la fois dans les drapeaux d'entrée et de sortie), sauf dans des circonstances très spéciales (principalement lors de l'accès aux bandes) - si vous l'utilisez dd, c'est-à-dire: il existe généralement de meilleures solutions (voir ci-dessous).

dd if=/dev/urandom iflag=fullblock oflag=fullblock of=file bs=1M count=1000000

Une autre façon possible d'être sûr de ce qui ddva faire est de passer une taille de bloc de 1. Ensuite, vous pouvez dire combien d'octets ont été copiés à partir du nombre de blocs, mais je ne sais pas ce qui se passera si a readest interrompu avant de lire le premier octet (ce qui n'est pas très probable dans la pratique mais peut se produire). Cependant, même si cela fonctionne, c'est très lent.

Le conseil général sur l'utilisation ddest de ne pas utiliserdd . Bien qu'il ddsoit souvent annoncé comme une commande de bas niveau pour accéder aux appareils, ce n'est en fait rien de tel: toute la magie se produit dans la partie du fichier de l'appareil (la /dev/…) partie, ddest juste un outil ordinaire avec un potentiel élevé d'utilisation abusive entraînant une perte de données . Dans la plupart des cas, il existe un moyen plus simple et plus sûr de faire ce que vous voulez, au moins sous Linux.

Par exemple, pour lire un certain nombre d'octets au début d'un fichier, il suffit d'appeler head:

head -c 1000000m </dev/urandom >file

J'ai fait un point de repère rapide sur ma machine et n'ai observé aucune différence de performance entre ddavec une grande taille de bloc et head.

Si vous devez ignorer certains octets au début, dirigez-le tailvers head:

dd if=input of=output count=C bs=B seek=S
<input tail -c +$((S*B+1)) | head -c $((C*B)) >output

Si vous voulez voir la progression, appelez lsofpour voir le décalage du fichier. Cela ne fonctionne que sur un fichier standard (le fichier de sortie de votre exemple), pas sur un périphérique de caractères.

lsof -a -p 1234 -d 1
cat /proc/1234/fdinfo/1

Vous pouvez appeler pvpour obtenir un rapport d'avancement (meilleur que ddle sien), au détriment d'un élément supplémentaire dans le pipeline (en termes de performances, il est à peine perceptible).

Gilles 'SO- arrête d'être méchant'
la source
2
+1. C'est l'un des articles les plus recherchés que j'ai lus sur le réseau StackExchange depuis longtemps. Il est succinct mais contient tous les détails (historiques et actuels) sur la ddcommande que je ne savais pas que je devais connaître. Merci.
Cosmic Ossifrage
4
Je suis désolé mais je ne suis pas d'accord avec votre affirmation selon laquelle dd est un "outil grincheux difficile à utiliser correctement" et "n'utilisez pas dd". C'est un très bon utilitaire lorsqu'il est utilisé correctement par quelqu'un qui a pris le temps de le comprendre. En effet, les boîtes à outils médico-légales sur disque dépendent presque toutes de dd ou d'un dérivé tel que dcfldd.
fpmurphy
1
@ fpmurphy1 GNU ddpeut être utilisé en toute sécurité, grâce à son fullblockoption. Mais si vous avez des coreutils GNU, vous n'avez pas besoin de ddbeaucoup. Les «dérivés» tels qu'ils ne le dcflddsont pas dd , ils ne souffrent pas de ses défauts de conception, donc ma réponse ne s'applique pas à eux. Une très grande majorité de personnes qui l'utilisent ddn'ont pas pris suffisamment de temps pour le comprendre (tout au plus, elles ont pris le temps de penser qu'elles le comprennent) et la façon dont elles l'utilisent entraîne une perte de données.
Gilles 'SO- arrête d'être méchant'
1
@Gilles Il ne faut donc pas utiliser "echo" b / c de son potentiel d'abus (sudo echo hello world> / dev / sda)?
whitey04
2
@ whitey04 Je recommande de ne pas manipuler de barils de nitroglycérine. Je n'ai pas dit que vous ne devriez pas utiliser de correspondances.
Gilles 'SO- arrête d'être méchant'
9

L'avertissement se produit lorsqu'il ddn'a pas pu obtenir suffisamment de données pour remplir un bloc en une seule lecture. Cela se produit avec des sources de données erratiques ou lentes, ou des sources qui écrivent des données dans des unités plus petites que la taille de bloc demandée.

Il n'y a aucun problème avec l'intégrité des données, mais le problème est que ddla lecture partielle est toujours considérée comme un bloc de lecture.

Si vous n'utilisez pas l' countoption, l'avertissement n'a pas d'importance, c'est juste une considération de performance. Mais avec count, vous n'obtiendrez pas la quantité de données que vous avez demandée. En raison de lectures partielles, ofsera plus petit qu'à count*bsla fin.

Donc, lorsque vous utilisez count, techniquement, vous devriez toujours l'utiliser iflag=fullblockégalement.

Le +xdevrait être le nombre de blocs partiels.

frostschutz
la source
-3
< /dev/urandom \
dd ibs=4k obs=64k |
dd bs=64k count=16000000 >file

^ Ça va marcher. La désinformation que nous avions autrement ici est manifestement fausse. ddLes tampons sont explicites et donc, pour tamponner les entrées pour compter les occurrences, vous devez les tamponner explicitement. C'est tout. N'achetez pas le fud.

mikeserv
la source