Comment savoir si dd fonctionne toujours?

147

Je n'ai pas ddbeaucoup utilisé , mais jusqu'à présent, cela ne m'a pas encore manqué. En ce moment, je vis dddepuis plus de 12 heures - je réécris une image sur le disque d'où il provient - et je m'inquiète un peu, car j'ai pu passer dddu disque à l'image dans environ 7 heures.

J'utilise OSX 10.6.6 sur un MacBook avec un Core 2 Duo à 2,1 GHz / noyau avec 4 Go de RAM. Je lis un fichier .dmg sur un disque dur à 7 200 tr / min (le lecteur de démarrage) et j'écris sur un lecteur à 7 200 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 tout ddfonctionnait parfaitement après tout. La prochaine fois, cependant, je vais le parcourir pvet le suivre strace. Merci à tous pour votre aide.

eckza
la source
7
Ne répondez pas à votre question, mais vos temps sont assez élevés, OMI. Avez-vous pensé à transmettre une taille de bloc plus grande à dd, différente des 512 octets par défaut? dd ... bs=16Mest ma suggestion, compte tenu de votre RAM, la taille du disque et la vitesse.
Juliano
Je ne l'ai pas fait, simplement parce que je voulais jouer la sécurité. Je vais essayer cela la prochaine fois, cependant. Merci.
eckza
D'après mon expérience, ddMac OS X a tendance à se bloquer au point que je ne peux même pas tuer le processus, mais que je dois redémarrer le système. Je commence alors à travailler sur une machine virtuelle Linux.
SSC

Réponses:

173

Vous pouvez envoyer ddun certain signal en utilisant la killcommande pour lui faire afficher son statut actuel. Le signal est INFOsur les systèmes BSD (y compris OSX) et USR1sur Linux. Dans ton cas:

kill -INFO $PID

Vous pouvez trouver l'ID de processus ( $PIDci-dessus) avec la pscommande; ou consultez les alternatives pgrep et pkill sur mac os x pour des méthodes plus pratiques.

Plus simplement, comme le souligne Antoine G dans sa réponse , vous pouvez taper ctrl-Tsur le shell qui exécute dd pour lui envoyer le INFOsignal.

À titre d’exemple sous Linux, vous pouvez dddéfinir l’état de sortie de tous les processus actifs comme suit:

pkill -USR1 -x dd

Après la sortie de son statut, ddcontinuera à faire face.

Caleb
la source
9
Oh, très cool. Vous pouvez les combiner avecpkill -USR1 -x dd
Michael Mrozek
9
@kivetros: sur les systèmes BSD, vous devez envoyer le INFOsignal. Linux n'a pas de SIGINFO et utilise à la USR1place.
Gilles
5
Les signaux SIGUSRx permettent aux programmes de faire ce qu’ils veulent, au lieu d’avoir une signification normalisée. SIGWINCH, par exemple, est déclenché lorsque le terminal a changé de taille et que le programme peut avoir besoin de redessiner son écran. Le système d'exploitation n'envoie pas les SIGUSRx, ils sont donc disponibles pour des utilisations personnalisées.
LawrenceC
11
L'envoi de dd le signal USR1 trop tôt après son démarrage (c'est-à-dire dans un script bash, la ligne postérieure à son démarrage) le terminera en fait. Mettez un sommeil de 0,1 seconde entre les deux et il affichera sa progression correctement. A propos, une très belle commande dd pour tester USR1 / INFO est dd if=/dev/zero of=/dev/null. :)
Lauritz V. Thaulow Le
11
En passant, tous les "vrais" BSD envoient SIGINFO au groupe de processus de premier plan si le caractère de statut (Ctrl + T par défaut) est envoyé au terminal. Mais je ne sais pas si cela est vrai pour MacOSX.
Netch
100

Sous OS X (sans essayer sous Linux), vous pouvez simplement taper Ctrl+ Tdans le terminal en cours d'exécution dd. Il imprimera le même résultat 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 en mélangeant + Tavec Ctrl+ T.

AntoineG
la source
1
Oh, d'accord, loadl'utilisation du processeur l'est-elle aussi ?
pje
c'était tellement une meilleure solution!
Stephn_R
J'ai essayé en dd sous Linux, ça fait écho ^Tau terminal.
Mwfearnley
1
assurez-vous que vous faites ctrl + shift + T dans le terminal mac
JBaczuk
26

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, dirigez les données pv.

Gilles
la source
1
pv semble incroyable - je vais certainement l'utiliser la prochaine fois. Merci beaucoup.
eckza
1
+1 - pvsemble juste le billet.
boehj
17

Une méthode plus générale consiste à utiliser iotopla quantité actuelle de lecture / écriture sur disque par programme.

EDIT: iotop -oaffiche uniquement les programmes qui effectuent actuellement des opérations d’E / S (merci à Jason C pour ce commentaire).

jofel
la source
1
C'est aussi ma méthode de vérification rapide préférée. iotop -omasquera les processus qui ne font pas d’IO et facilitera la lecture en un coup d’œil de ce qui se passe.
Jason C
13

J'attache habituellement straceà un tel processus en cours (avec l' -p $PIDoption) pour voir s'il reste bloqué dans un appel système ou s'il est toujours actif.

Ou, si vous ne souhaitez pas envoyer un signal au disque en marche, démarrez-en un autre pour valider si cela fonctionne.

philfr
la source
2
Comment voulez-vous vous y prendre strace? De plus, j'en ai démarré un autre ddet envoyé l'un des signaux suggérés, et ... ça l'a tué.
eckza
2
Si vous connaissez le pid du processus en cours d'exécution, faites simplement strace -p <pid>. Vous devriez voir le journal de tous les appels système appelés par le processus (principalement en lecture et en écriture)
philfr
11

Pour la prochaine fois, vous pourrez simplement l'utiliser pvdès le début (installez-le s'il est disponible via votre gestionnaire de paquets). Il s’agit d’un utilitaire ayant pour seul objectif de canaliser les entrées vers les sorties et de suivre les progrès et la rapidité.

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

En plus de la mise en mémoire tampon initiale (compensée par une synchronisation finale, qui peut être effectuée ddsi vous le souhaitez), cela vous indiquera une barre de progression, la vitesse moyenne, la vitesse actuelle et l’ETA.

L' iflag=fullblockoption force dd à saisir des blocs entiers d'entrée pv, sinon vous êtes à la merci du tuyau pour les tailles de bloc.

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 en mode 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, par exemple:

dd if=/dev/whatever bs=4M | pv -ptearb -s `blockdev --getsize64 /dev/whatever` > /path/to/image.bin

Il n'a pas d' importance ce que pour vous faire ddet pv, c'est entièrement liée à la performance - si l'appareil que vous lisez ou de a des performances optimales pour certains blocksizes vous souhaitez utiliser au ddlieu d' pvaccéder à ce dispositif. Vous pouvez même en coller un ddaux deux bouts si vous voulez, ou pas du tout si vous vous en fichez:

pv -ptearb /path/to/image.bin > /dev/whatever
sync
Jason C
la source
10

À partir de la version coreutils8.24, ddsupporte en natif les progrès réalisés. Ajoutez simplement l'option status=progress.

Exemple:

dd if=arch.iso of=/dev/sdb bs=4M status=progress

La source

Chirag Bhatia - chirag64
la source
5

ddrescue vous donnera des statistiques pendant son exécution.

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

Ben Preston
la source
3
Cela pourrait être utile pour la prochaine fois, mais cela n’aidera pas le PO à comprendre si la commande en cours est gelée ou non.
Francesco Turco
4

Parfois, vous ne pourrez peut-être pas utiliser le signal INFO ou USR1 car le flux stderr du ddprocessus 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 de contournement consiste à effectuer les opérations suivantes (testé sous FreeBSD, il peut être légèrement différent sous Linux):

  1. Utilisez iostatpour estimer le taux d'écriture moyen (Mo / s) sur le périphérique cible, par exemple:

    iostat -d -w30 ada0

    Remplacez ada0ici le nom de votre périphérique cible et attendez une minute qu'il donne quelques résultats. Le paramètre "w" détermine le nombre de secondes entre les échantillons. En l'augmentant, vous obtiendrez une meilleure estimation moyenne avec moins de variance, mais vous devrez attendre plus longtemps.

  2. Utilisez pspour déterminer combien de temps dda fonctionné:

    ps -xo etime,command | grep dd

    Convertissez cette valeur en secondes pour obtenir le nombre 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 périphérique cible par ada0. Divisez le résultat par le taux d'écriture moyen pour obtenir le temps total de transfert en secondes. Soustrayez le temps écoulé pour obtenir le temps restant.

Cette stratégie ne fonctionne que si ddelle écrit en continu au taux d’écriture moyen actuel depuis le début. Si d'autres processus se font concurrence pour les ressources de la CPU ou d'E / S (y compris le bus d'E / S), le taux de transfert peut alors être réduit.

D Coetzee
la source
4

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

Kartik M
la source
2

Pendant ddson exécution, je lance ceci dans un autre terminal en tant que root:

while pgrep ^dd; do pkill -INFO dd; sleep 1; done

Il imprime l’ ddétat toutes les 1 secondes dans la fenêtre du terminal d’origine où il dds’exécute et se ferme lorsque la commande est terminée.

ccpizza
la source
Trop cool. Ca a très bien marché ici sous El Capitan
Stefano Mtangoo Le
2

Vous pouvez utiliser progressce qui, en particulier, montre la progression d'une course dd. Il utilise /proc/$pid/fdet /proc/$pid/fdinfo que vous pouvez également surveiller à la main.

jofel
la source
1

La wcharligne (caractères écrits) dans /proc/$pid/iopeut vous donner des informations précises sur le ddprocessus. Tant que cela change, votre ddfonctionne toujours!

Voici un joli petit script php, que vous pouvez sauvegarder puis exécuter avec php filename.phppendant l' ddaffichage des octets écrits. Le bel avantage de regarder /proc/$pid/ioplus kill -USR1 $(pidof dd)est que vous ne devez pas passer entre les bornes, ce qui 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";
}
Leon Kramer
la source