Mis à jour le 7 mars 2006
TD 5

TD 5

Mardi 5 février 2006

1  Récupération du résultat d'une commande dans une chaîne de caractères

Dans cet exercice, on souhaite écrire une variante de execvp qui exécute une commande avec ses arguments dans un autre processus et qui permet de récupérer, à terme, le résultat de la commande dans le processus courant sous la forme d'une liste de chaînes de caractères contenant les lignes retournées par la commande sur sa sortie standard.

Par exemple, execvp_to_list "cat" [| "/tmp/foo" |] va retourner sous la forme d'une liste de lignes le contenu du fichier /tmp/foo.

Pour se protéger contre les signaux, écrire une fonction do_not_interrupt qui prend deux arguments f et x et effectue l'appel f x en le relançant s'il a été interrompu.

(corrigé)
Écrire une fonction input_lines qui lit des lignes sur un in_channel passé en argument et les place au fur et à mesure dans une liste, puis renvoie cette dernière. On utilisera la fonction input_line qui est protégée contre l'arrivée des signaux pour lire les lignes.

(corrigé)
Écrire la fonction execvp_to_list qui prend en argument le nom de la commande à exécuter ainsi qu'un tableau contenant ses arguments. Cette fonction utilise un tube pour lire les résultats envoyés par la commande sur sa sortir standard et attend la terminaison du fils avant de retourner.

On pensera à bien refermer tous les descripteurs qui ne sont plus utilisés.

Pour cette fonction on utilisera entre autres les fonctions, input_lines et do_not_interrupt écrites plus haut et les fonctions fork, dup2, execvp, waitpid in_channel_of_descr et close_in de la bibliothèque Unix.
(corrigé)
Inversement, écrire une fonction execvp_from_list lines cmd args qui exécute la commande cmd avec les arguments args et envoie sur son entrée standard la liste de lignes lines. Attention à la levée du signal sigpipe en cas d´écriture sur un descripteur fermé.

(corrigé)
Quel problème va-t-on rencontrer si on veut combiner les deux fonctionnalités : donner l'entrée dans une liste de chaînes et récupérer la sortie dans une liste de chaînes de caractères ? Comment peut-on s'en sortir ?
(corrigé)

2  Pipeline

Dans cet exercice on cherche à écrire une commande Unix pipeline qui prend, sur la ligne de commande, une suite de sous-commandes séparées par : et les exécute en pipeline. Par exemple :
      
        ./pipeline grep foo : grep bar : wc -l
calcule le nombre de lignes reçues sur l'entrée standard qui contiennent à la fois le mot foo et le mot bar, de façon comparable à la commande
      
        /bin/sh -c 'grep foo | grep bar | wc -l'
ou plus simplement dans un shell interactif
      
        bash$ grep foo | grep bar | wc
En fait, on généralise le problème pour écrire d'abord une fonction de bibliothèque pipeline qui prend une liste de couples (cmd, args) et qui redirige la sortie standard de la première commande vers l'entrée de la seconde et ainsi de suite.

L'exemple précédent se ramenera à l'appel de fonction
      
    pipeline [ "grep", [| "foo" |]; "grep", [| "bar" |]; "wc", [| "-l" |] ]
Écrire une fonction de bibliothèque wait_for_children (i.e. qui ne peut rien supposer sur le contexte dans lequel elle est appelée) qui prend une liste de processus (fils du processus courant), attend leur terminaison et retourne un entier correspondant à un “ou logique” (opérateur binaire lor) sur les valeurs de retour de chacune des commandes qui se sont terminées. La valeur 127 sera retournée si l'un des fils se termine suite à l'arrivée d'un signal.
(corrigé)
Écrire une fonction end_pipeline input cmd args qui lance la commande de nom cmd avec les arguments présents dans le tableau args et retourne le pid du fils. L'entrée standard de la commande sera au préalable redirigée sur le descripteur input. (On pensera à bien fermer tous les descripteurs inutiles.)
(corrigé)
Écrire une fonction pipeline_with input cmd args qui lance la commande de nom cmd avec les arguments présents dans le tableau args. L'entrée standard de la commande sera au préalable redirigée sur le descripteur input et sa sortie standard vers un tube dont le descripteur en lecture est retourné par la fonction pipeline_with; le pid du processus créé sera également retourné.

On pensera à bien fermer tous les descripteurs inutiles.
(corrigé)
Écrire la fonction pipeline cmd_list qui prend en argument une liste de couples (commande, arguments) à exécuter en « chaîne » et retourne la valeur de retour calculée par la fonction wait_for_children.

On supposera que si l'appel fork échoue, l'erreur est fatale.
(corrigé)
Que faudrait-il faire pour prendre en compte l'échec possible de la commande fork?
(corrigé)
Écrire la commande Unix pipeline.
(corrigé)

3  Redirections

Soit le type suivant :
      
type redirection =
    In_from_file of string        (* < file *)
  | Out_to_file of string         (* > file *)
  | Err_to_file of string         (* 2> file *)
  | Out_append_to_file of string  (* >> file *)
  | Err_to_out ;;                 (* 2>&1 *)
Écrire une commande command_fg_redirect qui prend en argument une commande, ses arguments sous forme d'un tableau et une liste de redirections et qui exécute la commande après avoir effectué les redirections nécessaires puis attend sa terminaison.

Par exemple, command_fg_redirect cat [||] [ In_to_file input; Out_append_file output] redirige l'entrée standard de la commande cat vers le fichier de nom input et la sortie standard vers le fichier de nom output.

Les redirections sont effectuées dans l'ordre où elles apparaissent. Par exemple, command_fg_redirect cmd [||] [ Out_to_file /tmp/foo; Err_to_out] redirige la sortie standard et la sortie d'erreur vers le fichier /tmp/foo et command_fg_redirect cmd [||] [ Err_to_out ; Out_to_file /tmp/foo ] redirige la sortie d'erreur vers le stdout d'origine et redirige stdout vers /tmp/foo.

N'oubliez pas de tester votre fonction !

Pour répondre à cette question, on utilisera les fonctions Unix.fork, Unix.dup2, Unix.dup2, Unix.openfile et Unix.close.

(corrigé)



This document was translated from LATEX by HEVEA and HACHA.