You are on page 1of 4

C

O
R
R
E
C
T
I
O
N
C
O
R
R
E
C
T
I
O
N
TP1 : fork, exec et signaux
RS : Reseaux et Syst`emes
Deuxi`eme annee
Exercice 1. Appel syst`eme fork.
Question 1.

Ecrire un programme qui cree 10 processus ls. Chacun dentre eux devra acher dix
fois dale son numero dordre entre 0 et 9. Veriez que votre programme ache 100 caract`eres.
Reponse
1 #include <stdio.h>
2
3 int main() {
4 int i, j;
5
6 for (i=0; i < 10; i++) {
7 switch (fork()) {
8 case -1: fprintf(stderr, "Erreur dans %d\n", getpid());
9 exit(1);
10
11 case 0: /* On est dans un fils */
12 for (j = 0; j < 10; j++) {
13 printf("%d",i);
14 }
15 /* Ne pas oublier de sortir sinon on cree fact(10) processus */
16 exit(0);
17
18 default: /* On est dans le pere; ne rien faire */ ;
19 }
20 }
21 exit(0);
22 }
Fin reponse
Question 2. Reprise de la Question 4 du TD1
On consid`ere les deux structures de liation (chane et arbre) representees ci-apr`es.

Ecrire un programme
qui realise une chane de n processus, o` u n est passe en param`etre de lexecution de la commande (par
exemple, n = 3 sur la gure ci-dessus). Faire imprimer le numero de chaque processus et celui de son
p`ere. Meme question avec la structure en arbre.
exit
exit
exit
exit
exit
pid,
ppid
pid,
ppid
pid,
ppid
pid,
ppid
pid,
ppid
pid,
ppid
exit
pid,
ppid
exit
pid,
ppid
exit
Reponse
1 #include <stdlib.h> /* exit, atoi */
2 #include <stdio.h> /* printf */
3 #include <unistd.h> /* getpid, fork */
4 #include <wait.h> /* wait */
5
6 void arbre(int n) {
7 int i;
8 printf("Lance %d processus en arbre\n\n",n);
9 printf("proc %d fils de %d (shell)\n",getpid(),getppid());
10 for (i=0; i<n; i++) {
11 if (fork() == 0) { /* fils */
12 printf("proc %d fils de %d\n",getpid(),getppid());
13 } else {
14 wait(NULL);
15 exit(0);
16 }
17 }
18 }
19
20 void chaine(int n) {
21 int i;
22 printf("Lance %d processus en chaine\n\n",n);
23 printf("proc %d fils de %d (shell)\n",getpid(),getppid());
24
25 for (i=0; i<n; i++) {
26 if (fork() == 0) { /* fils */
27 printf("proc %d fils de %d\n",getpid(),getppid());
28 exit(0);
29 }
30 }
31
32 for (i=0; i<n; i++)
TP1 : fork, exec et signaux
C
O
R
R
E
C
T
I
O
N
C
O
R
R
E
C
T
I
O
N
33 wait(NULL);
34 }
35
36 int main(int argc, char *argv[ ]) {
37 if (argc<2) {
38 printf("Usage:\n%s 1 <n> pour lancer <n> processus en arbre\n%s 2 <n> pour lancer <n> processus en chaine\n",
39 argv[0], argv[0]);
40 exit(1);
41 }
42 switch(atoi(argv[1])) {
43 case 1: arbre(atoi(argv[2])); break;
44 case 2: chaine(atoi(argv[2])); break;
45 }
46 return 0;
47 }
Fin reponse
Exercice 2. Appel syst`eme exec.
Question 1. Reprise de la Question 8 du TD1

Ecrire un programme doit qui execute une commande
Unix que lon lui passe en param`etre. Exemple :
1 doit ls -lt /
Reponse
Reponse utilisant argv en place :
1 #include <unistd.h>
2 #include <stdio.h>
3
4 int main(int argc,char *argv[ ]) {
5
6 if (argc < 2) {
7 fprintf(stderr,"Necessite au moins un argument\n");
8 exit(1);
9 }
10
11 execvp(argv[1],&argv[1]);
12 return 0;
13 }
Fin reponse
Question 2.

Ecrire un programme multido qui execute au plus cinq fois (dans des processus separes)
une commande Unix que lon lui passe en param`etre. Si lune des executions provoque une erreur, il ne
faut pas realiser les executions suivantes.
Reponse
1 #include <stdio.h>
2 #include <errno.h>
3 #include <wait.h>
4
5 int main(int argc,char *argv[]) {
6 int i;
7 int status;
8
9 if (argc < 2) {
10 printf("Necessite au moins un argument\n");
11 exit(1);
12 }
13 for (i=0; i<5; i++) {
14 switch (fork()) {
15 case -1:
16 perror("pb de fork");
17 exit(1);
18 case 0:
19 execvp(argv[1],&argv[1]);
20
21 default:
22 if (waitpid(-1, &status, 0) > 0) {
23 if (WIFEXITED(status) != 0 && WEXITSTATUS(status) != 0) {
24 printf("Child returned an error (code:%d). Balling out\n",
25 WEXITSTATUS(status));
26 exit(1);
27 }
28 }
29 }
30 }
31 return 0;
32
33 }
Exemple de programme qui plante (pour tester) :
2
TP1 : fork, exec et signaux
C
O
R
R
E
C
T
I
O
N
C
O
R
R
E
C
T
I
O
N
La premi`ere fois : cd titi
La deuxi`eme fois : mkdir toto
Fin reponse
Exercice 3. Signaux. Rappel : nous utilisons cette annee linterface POSIX des signaux.
Question 1.

Ecrire un programme ne se terminant quau cinqui`eme Ctrl-C.
Reponse
1 #include <signal.h>
2 #include <stdio.h>
3
4 void Recuperation(int sig) {
5 static compt = 0;
6
7 if (++compt == 5) {
8 printf("Jen ai assez!!\n");
9 exit(0);
10 } else {
11 printf("OK je recupere le signal SIGINT\n");
12 }
13 }
14
15 int main() {
16 struct sigaction nvt, old;
17 memset(&nvt,0,sizeof(nvt)); /* memset necessaire pour flags=0 */
18
19 nvt.sa_handler = Recuperation;
20
21 sigaction(SIGINT, &nvt, &old);
22
23 printf("Taper 5 ^C pour arreter le programme\n");
24 while(1);
25 }
26
Fin reponse
Question 2.

Ecrire un programme creant deux ls, en envoyant le signal SIGUSR1 `a son ls cadet.
`
A la reception de ce signal, le ls cadet devra envoyer le signal SIGUSR2 au ls aine (qui provoque sa
terminaison) avant de sarreter.
Indication : il est tr`es dicile dinterchanger les roles des deux ls.
Reponse
1 #include <signal.h>
2
3 int aine, cadet;
4
5 void cadet_sigusr1() {
6 printf("Reception du signal SIGUSR1 dans %d\n", getpid());
7 kill(aine, SIGUSR2);
8 exit(0);
9 }
10
11 void aine_sigusr2() {
12 printf("Reception du signal SIGUSR2 dans %d\n", getpid());
13 exit(0);
14 }
15
16 int main(int argc, char **argv) {
17 /* Lancer le fils aine */
18 if ((aine=fork()) == 0) {
19 /* fils */
20 struct sigaction nvt, old;
21 memset(&nvt,0,sizeof(nvt));
22 nvt.sa_handler = aine_sigusr2;
23 sigaction(SIGUSR2, &nvt, &old);
24
25 pause();
26 }
27
28 /* Lancer le fils cadet */
29 if ((cadet=fork()) == 0) {
30 struct sigaction nvt, old;
31 memset(&nvt,0,sizeof(nvt));
32 nvt.sa_handler = cadet_sigusr1;
33 sigaction(SIGUSR1, &nvt, &old);
34
35 pause();
36 }
37
38 /* On est dans le pere */
39 sleep(1); /* pour etre sur que les signaux sont bien detournes */
40 printf("Aine=%d Cadet=%d\n", aine, cadet);
41 kill(cadet, SIGUSR1);
42 sleep(2); /* pour attendre les affichages */
43 return 0;
44 }
3
TP1 : fork, exec et signaux
C
O
R
R
E
C
T
I
O
N
C
O
R
R
E
C
T
I
O
N
Fin reponse
Exercice 4. Reimplementer if.
Question 1.

Ecrire une version simpliee du programme if que vous nommerez si.
Testez votre travail avec la commande suivante : ./si test -e toto alors echo present sinon echo absent
Reponse
si.c
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include <sys/wait.h>
6
7 int main(int argc, char **argv) {
8 int alors_pos = 0;
9 int sinon_pos = 0;
10 int i = 0;
11 int status;
12
13 while(argv[++i]!=NULL)
14 if (!strcmp(argv[i],"alors"))
15 alors_pos = i;
16 else if(!strcmp(argv[i],"sinon"))
17 sinon_pos = i;
18
19 argv[alors_pos] = NULL;
20
21 if (sinon_pos)
22 argv[sinon_pos] = NULL;
23
24 if(!(alors_pos)) {
25 printf("Syntaxe : ./si expr alors expr [sinon expr]\n");
26 return -1;
27 }
28
29 if(fork()==0) {
30 execvp(argv[1],&argv[1]);
31 perror("execvp cass e !");
32 return -1;
33 }
34
35 wait(&status);
36
37 if(WIFEXITED(status)) {
38 if(!WEXITSTATUS(status)) {
39 if(!sinon_pos)
40 sinon_pos=argc;
41
42 execvp(argv[alors_pos+1],&argv[alors_pos+1]);
43
44 perror("execvp casse !");
45 return -1;
46
47 } else if(sinon_pos) {
48
49 execvp(argv[sinon_pos+1],&argv[sinon_pos+1]);
50
51 perror("execvp casse !");
52 return -1;
53 }
54 // test "si" faux, pas de "sinon"
55 return 0;
56
57 } else {
58 // test "si" pas sorti par exit
59 return -1;
60 }
61 }
62
Fin reponse
4