Kévin Subileau

Espace personnel

tux-disc

Images disques sous Linux en ligne de commande

Aujourd'hui je vous propose ce petit mémo des différentes commandes utiles à la création et à la gravure des fichiers ISO sous Linux, qui, contrairement à d'autres (suivez mon regard...), dispose à portée de main de tous les outils utiles pour gérer les images disques !

Création d'un ISO à partir d'un disque physique

Tout d'abord, insérez le disque dans le lecteur :P (non je ne suis pas en train de me moquez de vous...), puis tapez la commande suivante :

dd if=/dev/cdrom of=~/image.iso

La commande dd permet simplement d'effectuer une copie brute des données d'un point à un autre. Ici, on indique comme source (if pour input file) le fichier représentant le lecteur de DVD. Au passage, ajustez ce paramètre en fonction de votre distribution Linux. Sur certaines d’entre elles, ce fichier peut se nommer cdrom0, cdrom1, sr0 ou sr1 par exemple. Enfin, le paramètre of (pour output file) permet d'indiquer le chemin du fichier ISO de sortie. Là encore, adaptez ce chemin en fonction de ce que vous souhaitez.

Simplissime, non ? :D

Création d'un ISO à partir d'un dossier

La création d'une image disque à partir d'un dossier de fichiers est tout aussi simple. Cela s'effectue à l'aide de la commande mkisofs. Toutefois, sur certaines distributions, cette commande s’appelle désormais genisoimage suite à des problèmes de licences. Adaptez donc selon votre cas. Si aucune des deux commandes n'est présente, installez le paquet genisoimage.

Voici la syntaxe de la commande :

mkisofs -o ~/image.iso ~/dossier_source

Il vous suffit donc d'indiquer le chemin du fichier ISO en sortie ainsi que le chemin du dossier contenant les éléments à inclure dans l'image disque. La syntaxe de la commande genisoimage est identique, il vous suffit donc de remplacer le nom de la commande.

Monter une image

Pas besoin d'un Daemon tools vérolé pour monter une image disque sous Linux. Il vous suffit pour cela d'utiliser la commande.... mount bien sûr ! Voici la syntaxe à utiliser :

mount -t iso9660 -o loop image.iso /mnt/point_de_montage

On utilise ici le montage en boucle locale (loop), qui doit être activé dans les options de compilation du noyau pour que cette commande fonctionne, ce qui est fort heureusement le cas dans la plupart des distributions.

Gravure d'un ISO

La gravure est une opération un  peu plus délicate car il faut contrôler correctement les paramètres du graveur. Pour cette opération, il faut utiliser la commande wodim, fournie par le paquet du même nom. Pour les mêmes raisons que la commande mkisofs, cette commande se nomme cdrecord sur certaines distributions. Encore une fois, c'est à vous d'adapter. Voici la ligne de commande à utiliser :

wodim -v speed=4 dev=/dev/cdrom image.iso

Ici encore il faut modifier le nom du pseudo-fichier représentant votre graveur en fonction de votre système. Sachez également que la commande wodim permet également d'obtenir des informations sur votre graveur, de graver un CD audio ou encore d'effacer un DVD-RW. Consulter votre meilleur ami le man pour en savoir plus, ou votre second meilleur ami Google :D .

Convertir une image Nero (NRG) en ISO

Les précédentes astuces ne fonctionnent qu'avec des images au format ISO. Si vous avez des images disques issues de Nero au format propriétaire NRG, vous pouvez toutefois les convertir en ISO par deux méthodes. La méthode fainéante consiste à utiliser la commande nrg2iso du paquet éponyme.

nrg2iso image.nrg image.iso

La méthode un peu plus élaborée, mais qui reste assez simple, utilise la commande dd pour retirer simplement l'en-tête que Nero ajoute (c'est exactement ce que fait la commande nrg2iso, et rien de plus !) :

dd if=image.nrg of=image.iso bs=2048 skip=150

A noter que l'utilitaire nrg2iso existe aussi sous une version graphique pour Windows sur ce site.

Voilà, j'espère que ce mémo vous sera utile ! N'hésitez pas à le partager et à le commenter en ajoutant vos propres astuces autour de ce sujet :D

C++

C++ : Déclarer une variable dans un switch

En C++, il est possible de déclarer une nouvelle variable à tout moment dans le code... ou presque !

Ainsi, l'extrait de code ci-dessous est évidemment parfaitement valide et compile sans erreur :

for (int i = 0; i < 10; ++i) {
    std::cout << "Itération n°" << i << std::endl;
    int dummy;
    dummy = i * i;
    std::cout << "Le carré de " << i << " est " << dummy  << std::endl;
}

On note que la variable dummy est définie au milieu du code, sans que cela ne pose problème. Partant de ce constat, on pourrait croire que le code suivant compile également sans problème (en supposant que la variable choix est définie) :

switch (choix) {
    case 1:
        std::cout << "Choix 1." << std::endl;
        int dummy = time(NULL); // Erreur !!
        std::cout << "Il est " << dummy << std::endl;
        break;
    default:
        std::cout << "Choix inconnu." << std::endl;
        // std::cout << "Il est " << dummy << std::endl;
        break;
}

Et bien non ! Si vous compiler un code de ce genre, le compilateur le refusera en indiquant une erreur du type :

error: jump to case label
   crosses initialization of 'int dummy'

ou encore, selon les cas :

error: initialization of 'dummy' is skipped by 'case' label

La raison de cette erreur est que la portée de la variable définie à l'intérieur d'un case s'étend à l'ensemble du switch, et pas seulement à ce case. Le case n'est qu'un label, et ne limite pas la portée de la variable, qui n'est limitée que par les accolades englobantes du switch. Que se passerait il alors si le compilateur ne disait rien et que je décommentais la ligne 9 du code précédent ? Et bien, dans le cas où choix serait différent de 1, l'initialisation de la variable faite à la ligne 4 serait sautée puisque seul le bloc default serait exécuté. La variable dummy serait donc définie (puisque sa portée est globale à tout le switch) mais non initialisée (puisque l'initialisation n'a pas été exécutée). Dans cet exemple, dummy est un entier, il contiendrait simplement une valeur indéterminée. Mais ce pourrait tout aussi bien être un objet, et dans ce cas, le constructeur ne serait pas appelé si choix est différent de 1 ! Ce comportement risqué est donc interdit par le compilateur.

Pour résoudre ce problème, il faut explicitement limiter la portée de la variable en entourant le code du case par une paire d'accolades, comme ci-dessous :

switch (choix) {
    case 1:
    {
        std::cout << "Choix 1." << std::endl;
        int dummy = time(NULL); // Ok !!
        std::cout << "Il est " << dummy << std::endl;
        break;
    }
    default:
        std::cout << "Choix inconnu." << std::endl;
        // Désormais interdit car la variable est hors de portée !
        // std::cout << "Il est " << dummy << std::endl;
        break;
}

La portée de la variable dummy est ainsi limitée au case, et il devient impossible de l'utiliser dans un autre case.

Voilà pour cette petite astuce de programmation en C++ assez simple, il suffit juste d'y penser ! A noter que ce problème et sa solution s'applique aussi lorsque l'on déclare une variable entre un goto et le label ciblé par ce goto. Mais bon, c'est bien connu, plus personne n'utilise le goto de nos jours...

Source