Je n'ai pas beaucoup utilisé dd
, mais jusqu'à présent, cela ne m'a pas encore échoué. En ce moment, j'ai un dd
en cours depuis plus de 12 heures - j'écris une image sur le disque dont elle est issue - et je suis un peu inquiet, car j'ai pu dd
du disque à l'image dans environ 7 heures.
J'utilise OSX 10.6.6 sur un MacBook avec un Core 2 Duo à 2,1 GHz/cœur avec 4 Go de RAM. Je lis à partir d'un fichier .dmg sur un disque dur à 7200 tr/min (le lecteur de démarrage) et j'écris sur un lecteur à 7200 tr/min connecté via un connecteur SATA-USB. J'ai laissé la taille de bloc par défaut et l'image est d'environ 160 Go.
EDIT: Et, après 14 heures de stress pur, le dd
fonctionnait parfaitement après tout. La prochaine fois, cependant, je vais l'exécuter via pv
et le suivre avec strace
. Merci à tous pour votre aide.
Vous pouvez envoyer dd
un certain signal en utilisant la commande kill
pour lui faire afficher son état actuel. Le signal est INFO
sur les systèmes BSD (y compris OSX) et USR1
sous Linux. Dans ton cas:
kill -INFO $PID
Vous pouvez trouver l'ID de processus ($PID
ci-dessus) avec la commande ps
; ou voir alternatives pgrep et pkill sur mac os x pour des méthodes plus pratiques.
Plus simplement, comme AntoineG le souligne dans sa réponse , vous pouvez taper ctrl-T
sur le shell exécutant dd pour lui envoyer le signal INFO
.
À titre d'exemple sous Linux, vous pouvez rendre l'état de sortie de tous les processus dd
actifs comme suit:
pkill -USR1 -x dd
Après avoir sorti son état, dd
continuera la copie.
Sous OS X (n'a pas essayé sous Linux), vous pouvez simplement taper Ctrl+T dans le terminal exécutant dd
. Il imprimera la même sortie que kill -INFO $PID
, plus l'utilisation du processeur:
load: 1.40 cmd: dd 34536 uninterruptible 3.49u 64.58s
5020305+0 records in
5020304+0 records out
2570395648 bytes transferred in 4284.349974 secs (599950 bytes/sec)
Je l'ai découvert en lisant ce fil et en essayant d'ouvrir un nouvel onglet dans mon terminal mais en mélangeant ⌘+T avec Ctrl+T.
Pour dd
, vous pouvez envoyer un signal . Pour les autres commandes qui lisent ou écrivent dans un fichier, vous pouvez regarder leur position dans le fichier avec lsof
.
lsof -o -p1234 # where 1234 is the process ID of the command
lsof -o /path/to/file
Si vous planifiez à l'avance, canalisez les données via pv
.
J'attache généralement strace
à un tel processus en cours (avec le -p $PID
option) pour voir s'il reste bloqué lors d'un appel système ou s'il est toujours actif.
Ou, si vous vous sentez nerveux à l'idée d'envoyer un signal au DD en cours, démarrez un autre DD pour valider si cela fonctionne.
Pour la prochaine fois, vous pouvez simplement utiliser pv
dès le début (s'il est disponible via votre gestionnaire de paquets, installez-le). Il s'agit d'un utilitaire dans le seul but de canaliser l'entrée à la sortie et de surveiller la progression et la vitesse.
Ensuite, pour écrire une image sur un lecteur, disons avec une taille de bloc de 4 Mo:
pv -ptearb /path/to/image.bin | dd iflag=fullblock of=/dev/whatever bs=4M
Mis à part la mise en mémoire tampon initiale (compensée par une synchronisation finale, qui peut être effectuée via dd
si vous le souhaitez), cela vous montrera une barre de progression, la vitesse moyenne, la vitesse actuelle et ETA.
Le iflag=fullblock
option force dd à récupérer des blocs entiers d'entrée via pv
, sinon vous êtes à la merci du canal pour les tailles de blocs.
Pour aller dans l'autre sens, utilisez dd pour lire et pv pour écrire, bien que vous deviez spécifier explicitement la taille si la source est un périphérique bloc. Pour un appareil de 4 Go:
dd if=/dev/whatever bs=4M | pv -ptearb -s 4096m > /path/to/image.bin
Vous pouvez également déterminer automatiquement la taille, quelque chose comme:
dd if=/dev/whatever bs=4M | pv -ptearb -s `blockdev --getsize64 /dev/whatever` > /path/to/image.bin
Peu importe l'ordre dans lequel vous effectuez dd
et pv
, c'est entièrement lié aux performances - si l'appareil que vous lisez vers ou depuis a des performances optimales pour certaines tailles de blocs que vous souhaitez utilisez dd
au lieu de pv
pour accéder à ce périphérique. Vous pouvez même coller un dd
aux deux extrémités si vous le souhaitez, ou pas du tout si cela vous est égal:
pv -ptearb /path/to/image.bin > /dev/whatever
sync
À partir de coreutils
v8.24, dd
a un support natif pour afficher la progression. Ajoutez simplement l'option status=progress
.
Exemple:
dd if=Arch.iso of=/dev/sdb bs=4M status=progress
ddrescue
vous donnera des statistiques pendant son fonctionnement.
J'ai commencé à utiliser dcfldd (1), qui montre mieux les opérations dd.
Parfois, vous ne pourrez peut-être pas utiliser le signal INFO ou USR1 parce que le flux stderr du processus dd
n'est pas accessible (par exemple parce que le terminal dans lequel il a été exécuté était déjà fermé). Dans ce cas, une solution consiste à effectuer les opérations suivantes (testé sur FreeBSD, peut être légèrement différent sur Linux):
Utilisez iostat
pour estimer le taux d'écriture moyen (Mo/s) vers le périphérique cible, par exemple:
iostat -d -w30 ada0
Remplacez le nom de votre appareil cible par ada0
ici, et attendez une minute qu'il donne quelques résultats. Le paramètre "w" détermine le nombre de secondes entre les échantillons. L'augmenter donnera une meilleure estimation moyenne avec moins de variance, mais vous devrez attendre plus longtemps.
Utilisez ps
pour déterminer depuis combien de temps dd
fonctionne:
ps -xo etime,command | grep dd
Convertissez cela en secondes pour obtenir un total de secondes d'exécution.
Obtenez la taille de l'appareil en Mo avec:
grep ada0 /var/run/dmesg.boot
Remplacez le nom de votre appareil cible par ada0
. Divisez le résultat par le taux d'écriture moyen pour obtenir le temps de transfert total en secondes. Soustrayez le temps écoulé jusqu'à présent pour gagner du temps.
Cette stratégie ne fonctionne que si dd
écrit depuis le début à la vitesse d'écriture moyenne actuelle. Si d'autres processus sont en concurrence pour les ressources CPU ou d'E/S (y compris le bus d'E/S), cela peut réduire le taux de transfert.
Vous pouvez utiliser progress
qui, en particulier, montre la progression d'un dd
en cours d'exécution. Il utilise /proc/$pid/fd
et /proc/$pid/fdinfo
que vous pouvez également surveiller à la main.
Pendant que dd
est en cours d'exécution, je l'exécute dans un autre terminal en tant que root:
while pgrep ^dd; do pkill -INFO dd; sleep 1; done
Il affiche le statut dd
toutes les 1 seconde dans la fenêtre du terminal d'origine où dd
s'exécute et se ferme lorsque la commande est terminée.
La ligne wchar
(caractères écrits) dans /proc/$pid/io
Peut vous donner des informations précises sur le processus dd
. Tant qu'il change, votre dd
fonctionne toujours!
Voici un petit script PHP soigné, que vous pouvez enregistrer puis exécuter avec php filename.php
Pendant le dd
pour afficher les octets écrits. L'avantage de regarder /proc/$pid/io
Sur kill -USR1 $(pidof dd)
est que vous n'avez pas à basculer entre les terminaux, ce qui n'est pas toujours une option.
<?php
/** Time between refreshs in seconds */
$refresh = 1;
/**
* Start of Script
*/
if (!($pid = exec('pidof dd')))
exit("no dd running\n");
$history = array();
$break_ms = $refresh * 1000000;
$start_time = exec("ls -ld /proc/$pid --time-style=+\"%s\" | egrep -o [0-9]{10}");
fprintf(STDOUT, "PID: %s\n", $pid);
fprintf(STDOUT, "START TIME: %s\n\n", date("Y-m-d H:i:s", $start_time));
while (true) {
if (isset($curr))
array_Push($history, $curr);
if (count($history) > 10) array_shift($history);
$oldest = reset($history);
$latest = end($history);
/**
* get number of written bytes from /proc/$pid/io
*/
#if (!($curr = exec("cat /proc/$pid/io | grep ^write_bytes | sed 's/write_bytes: //g'")))
# break;
/* prepare proc_open() parameter */
$descriptorspec = array(
0 => array('pipe', 'r'), // stdin
1 => array('pipe', 'w'), // stdout
2 => array('pipe', 'w'), // stderr
);
$process = proc_open("cat /proc/$pid/io | grep ^write_bytes | sed 's/write_bytes: //g'", $descriptorspec, $pipes);
if (!is_resource($process)) break;
$stdout = stream_get_contents($pipes[1]);
$stderr = stream_get_contents($pipes[2]);
proc_close($process);
if (!empty($stderr)) break;
$curr = trim($stdout);
/**
* caculate elapsed time from start */
$time_elapsed = time() - $start_time;
/**
* avg speed since start */
$avg = $time_elapsed > 0 ? round($curr / $time_elapsed) : 0;
/**
* avg speed of last 10 updates */
if (count($history) > 0)
$speed = human_file_size(round(($latest - $oldest) / count($history) / $refresh));
$output = sprintf("\rBYTES WRITTEN: %s [%s] :: CURRENT: %s/s :: AVERAGE: %s/s :: ELAPSED: %s", $curr, human_file_size($curr), isset($speed) ? $speed : 0, human_file_size($avg), gmdate("H:i:s", $time_elapsed));
printf("%s%s", $output, str_repeat(" ", exec("tput cols") - strlen($output)));
usleep($break_ms);
}
fprintf(STDOUT, "\ndd has finished!\n\n");
function human_file_size($size,$unit="") {
if( (!$unit && $size >= 1<<30) || $unit == "GB")
return number_format($size/(1<<30),2)." GB";
if( (!$unit && $size >= 1<<20) || $unit == "MB")
return number_format($size/(1<<20),2)." MB";
if( (!$unit && $size >= 1<<10) || $unit == "kB")
return number_format($size/(1<<10),2)." kB";
return number_format($size)." bytes";
}