TD 4 - Fork et tubes non nommés

Ressources annexes

1. Création d’un tube non nommé

Écrire un programme qui:

  1. crée un tube en utilisant pipe(2).
  2. se duplique (fork(2)).
  3. le père:
    1. écrit 10 fois "Hello World" dans le tube
    2. affiche sur la sortie d’erreur "Je suis le pere et je quitte"
    3. retourne
  4. le fils:
    1. lit au plus 500 octets depuis le tube (en une fois), les affiche sur sa sortie standard
    2. affiche sur la sortie d’erreur "Je suis le fils et je quitte"
    3. retourne

Note: comme tout bon programmeur, vous utiliserez des macros pour les constantes.

2. Règles pour les tubes

Reprendre le premier exercice et tester dans le cas où le père écrit 50 fois son message, 100 fois, 500 fois, 1000 fois, 5000 fois, 10000 fois… On passera le nombre de fois en paramètre du programme.

Si votre programme semble bloqué, vérifier le statut des processus. Sur une feuille blanche, faire une représentation des processus (père et fils) ainsi que de leurs tables des descripteurs. Trouver le problème et corriger votre programme.

Une fois que tout marche bien, lancer votre programme comme suit: ./mypipe xx &. Lorsqu’on lance un processus en tâche de fond dans le shell, celui-ci nous affiche des informations sur le statut de complétion du processus. Quel est le statut de complétion de votre programme ?

3. Mise en majuscules

Reprendre l’exercice précédent et modifier le fils pour qu’il lise les données en continu depuis le tube et les passe en majuscules avant de les afficher sur sa sortie standard.

Dans le père, faire en sorte que la sortie standard soit associée au tube (dup2) et exécuter le programme ps en utilisant execlp.

4. Fork, exec et pipe /commandes composées

Écrire un programme qui exécute un pipeline de commandes comme le fait le shell, lorsque vous tapez une commande composée. Le programme aura une variable commandes qui contiendra la liste des commandes à exécuter, chaque commande consiste en un tableau de chaînes de caractères terminé par NULL:

Exemple d’enchaînement de commandes:

char  *ls[] = { "ls", "-l", NULL};
char  *tr[] = { "tr", "-d", "[:blank:]", NULL};
char **commandes[] = { ls, tr };
int nb_commandes = sizeof(commandes) / sizeof(char*);

La commande se terminera juste après la terminaison du dernier processus du pipeline (tr dans l’exemple). Si ce dernier processus s’est terminé normalement, sa valeur de retour devra être propagée dans celle du processus pipeline. Autrement un message devra donner la raison de la terminaison du processus et retourner la valeur EXIT_FAILURE.

On étudiera aussi le cas où il y a plus de 2 commandes.

5. Fork, exec et pipe /commandes composées (suite)

Reprendre l’exercice précédent et faites en sorte que la liste des commandes qui constituent le pipeline soit fournie sur la ligne de commande.

On utilisera la chaîne "--" comme séparateur de commandes, et la fonction split_args fournie pour découper la série d’arguments.

Par exemple,

$ pipeline ls -l -- grep toto -- less

devra produire le même effet que

$ ls -l | grep toto | less