Utilisation de tubes anonymes et des signaux en C

Ce WE en voulant aider une amie à faire ses TP de système. Je me suis rendu compte que c’était difficile de trouver sur le net des exemples de code (qui marchent !) illustrant l’utilisation des pipes ou tubes anonymes en C. J’ai mis du temps à comprendre comment ça marchait car j’en avais fait mais très peu et il y a longtemps. Cependant, une fois qu’on a le principe ça marche tout seul !

Ce premier programme montre l’utilisation des tubes anonymes en exécutant les tâches suivantes: – ls -l | wc -l et affiche le résultat – ls -l : affichage de la 2ème et 4ème ligne dans un fichier qui s’appelle “2eme_et_4eme_ligne”

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include <sys/wait.h>
#include<unistd.h>

int main(int argc, char* argv[]) {
int pfd[4];
int status;
int i = 0;
if(argc != 2)     {
fprintf(stderr, "Veuillez saisir un nom de répertoire\n");
return EXIT_FAILURE;
}
if(pipe(pfd) == -1) {
perror("pipe");
exit(EXIT_FAILURE);
}
if(pipe(pfd+2) == -1) {
perror("pipe");
exit(EXIT_FAILURE);
}
if(fork() == 0) {
dup2(pfd[1], 1);
close(pfd[0]);
close(pfd[1]);
close(pfd[2]);
close(pfd[3]);
execlp("/bin/ls","ls","-l", argv[1], (char *)NULL);
}
else {
if(fork() == 0) {
dup2(pfd[0], 0);
close(pfd[1]);
close(pfd[1]);
close(pfd[2]);
close(pfd[3]);
execlp("/usr/bin/wc", "wc", "-w", (char *)NULL);
}
else {
if(fork() == 0) {
FILE *out;
char lsline[256];
char *ptr = NULL;
char *nptr = NULL;
int nbread = 0;
close(pfd[0]);
close(pfd[1]);
close(pfd[3]);
if( !(out=fopen("2eme_et_4eme_ligne", "w")) ) {
perror("fopen");
return EXIT_FAILURE;
}
i = 0;
while( (nbread = read(pfd[2], &lsline, sizeof(lsline))) > 0) {
ptr = lsline;
while( (nptr = strchr(ptr, '\n')) ) {
i++;
*nptr = 0;
if(i == 2 || i == 4) {
fprintf(out, "%s\n", ptr);
}
if(nptr + 1 < lsline+sizeof(lsline))
ptr = nptr + 1;
}
if( i + 1 = 2 || i + 1 = 4) {
fprintf(out, "%s", ptr);
}
}
fclose(out);
close(pfd[2]);
}
else {
dup2(pfd[3], 1);
close(pfd[0]);
close(pfd[1]);
close(pfd[2]);
close(pfd[3]);
execlp("/bin/ls","ls","-l", argv[1], (char *)NULL);
}
}
}     // pere
close (pfd[1]);
close (pfd[1]);
close (pfd[2]);
close (pfd[3]);
for(i = 0 ; i < 3 ; i++) {
wait(&status);
}
return EXIT_SUCCESS;

}

Ce deuxième programme écrit dans un tube le caractère “.” jusqu’a ce qu’un signal de temps SIGALRM programmé par un timer l’arrête. Il affiche le nombre de caractères écrits dans le tube.

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/time.h>
#include <signal.h>

static int written = 0;

void machin(int sig_num) {
fprintf(stderr, "%d written in the tube ! You are really happy to know that aren't you ;) ?\n", written);
fflush(stdout);
exit(EXIT_SUCCESS);
}

int main(void) {
int pfd[2];
pid_t cpid;
if( (pipe(pfd)) == -1) {
perror("pipe");
exit(EXIT_FAILURE);
}
cpid = fork();
if(cpid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if(cpid == 0) {
struct itimerval timer;
memset(&timer, (char)0, sizeof(timer));
timer.it_value.tv_sec = 0;
timer.it_value.tv_usec = 1;
setitimer(ITIMER_REAL, &timer, 0);
signal(SIGALRM, machin);
close(pfd[0]);
while(1) {
if( (write(pfd[1], ".", 1)) != 1 ) {
perror("write");
exit(EXIT_FAILURE);
}
written++;
}
close(pfd[1]);
}
else {
close(pfd[0]);
close(pfd[1]);
wait(NULL);
}
return EXIT_SUCCESS;
}

C’est surement très môche, pas commenté et ça sert à rien 🙂 mais ça compile et ça marche. Je pense que c’est clair aussi ! Une question ? Un mail !