web-dev-qa-db-fra.com

Comment savoir si dd fonctionne toujours?

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.

150
eckza

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.

176
Caleb

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.

104
AntoineG

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 .

Une manière plus générale consiste à utiliser iotop qui affiche la quantité actuelle de lecture/écriture sur le disque par programme.

ÉDITER: iotop -o affiche uniquement les programmes qui effectuent actuellement des opérations d'E/S (merci Jason C pour ce commentaire).

17
jofel

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.

13
philfr

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
11
Jason C

À 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

Source

10

ddrescue vous donnera des statistiques pendant son fonctionnement.

démo: http://www.youtube.com/watch?v=vqq9A01geeA#t=144s

5
Ben Preston

J'ai commencé à utiliser dcfldd (1), qui montre mieux les opérations dd.

4
Kartik M

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):

  1. 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.

  2. 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.

  3. Multipliez le nombre total de secondes d'exécution par le taux d'écriture moyen pour obtenir le total des Mo transférés.
  4. 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.

4
D Coetzee

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.

3
jofel

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'originedd s'exécute et se ferme lorsque la commande est terminée.

2
ccpizza

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";
}
1
Leon Kramer