02-tp1-fork-exec-correction.pdf

4
CORRECTION CORRECTION TP1 : fork, exec et signaux RS : R´ eseaux et Syst` emes Deuxi` eme ann´ ee F Exercice 1. Appel syst` eme fork. . Question 1. ´ Ecrire un programme qui cr´ ee 10 processus fils. Chacun d’entre eux devra afficher dix fois d’affil´ e son num´ ero d’ordre entre 0 et 9. V´ erifiez que votre programme affiche 100 caract` eres. eponse 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 r´ eponse . Question 2. Reprise de la Question 4 du TD1 On consid` ere les deux structures de filiation (chaˆ ıne et arbre) repr´ esent´ ees ci-apr` es. ´ Ecrire un programme qui r´ ealise une chaˆ ıne de n processus, o` u n est pass´ e en param` etre de l’ex´ ecution de la commande (par exemple, n = 3 sur la figure ci-dessus). Faire imprimer le num´ ero de chaque processus et celui de son p` ere. Mˆ eme 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 eponse 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++)

Upload: hamza-zouhair

Post on 19-Jul-2016

46 views

Category:

Documents


3 download

TRANSCRIPT

Page 1: 02-tp1-fork-exec-correction.pdf

CORRECTION

CORRECTION

TP1 : fork, exec et signauxRS : Reseaux et Systemes

Deuxieme annee

F Exercice 1. Appel systeme fork.

. Question 1. Ecrire un programme qui cree 10 processus fils. Chacun d’entre eux devra afficher dixfois d’affile son numero d’ordre entre 0 et 9. Verifiez que votre programme affiche 100 caracteres.

Reponse

1 #include <stdio.h>23 int main() {4 int i, j;56 for (i=0; i < 10; i++) {7 switch (fork()) {8 case -1: fprintf(stderr, "Erreur dans %d\n", getpid());9 exit(1);

1011 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);1718 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 TD1On considere les deux structures de filiation (chaıne et arbre) representees ci-apres. Ecrire un programmequi realise une chaıne de n processus, ou n est passe en parametre de l’execution de la commande (parexemple, n = 3 sur la figure ci-dessus). Faire imprimer le numero de chaque processus et celui de sonpere. 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 */56 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 }1920 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());2425 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 }3132 for (i=0; i<n; i++)

Page 2: 02-tp1-fork-exec-correction.pdf

TP1 : fork, exec et signaux

CORRECTION

CORRECTION

33 wait(NULL);34 }3536 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

F Exercice 2. Appel systeme exec.

. Question 1. Reprise de la Question 8 du TD1 Ecrire un programme doit qui execute une commandeUnix que l’on lui passe en parametre. Exemple :

1 doit ls -lt /

Reponse

Reponse utilisant argv en place :

1 #include <unistd.h>2 #include <stdio.h>34 int main(int argc,char *argv[ ]) {56 if (argc < 2) {7 fprintf(stderr,"Necessite au moins un argument\n");8 exit(1);9 }

1011 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 l’on lui passe en parametre. Si l’une des executions provoque une erreur, il nefaut pas realiser les executions suivantes.

Reponse

1 #include <stdio.h>2 #include <errno.h>3 #include <wait.h>45 int main(int argc,char *argv[]) {6 int i;7 int status;89 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]);2021 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;3233 }

Exemple de programme qui plante (pour tester) :

2

Page 3: 02-tp1-fork-exec-correction.pdf

TP1 : fork, exec et signaux

CORRECTION

CORRECTION

– La premiere fois : cd titi– La deuxieme fois : mkdir toto

Fin reponse

F Exercice 3. Signaux. Rappel : nous utilisons cette annee l’interface POSIX des signaux.

. Question 1. Ecrire un programme ne se terminant qu’au cinquieme Ctrl-C.

Reponse

1 #include <signal.h>2 #include <stdio.h>34 void Recuperation(int sig) {5 static compt = 0;67 if (++compt == 5) {8 printf("J’en ai assez!!\n");9 exit(0);

10 } else {11 printf("OK je recupere le signal SIGINT\n");12 }13 }1415 int main() {16 struct sigaction nvt, old;17 memset(&nvt,0,sizeof(nvt)); /* memset necessaire pour flags=0 */1819 nvt.sa_handler = Recuperation;2021 sigaction(SIGINT, &nvt, &old);2223 printf("Taper 5 ^C pour arreter le programme\n");24 while(1);25 }26

Fin reponse

. Question 2. Ecrire un programme creant deux fils, en envoyant le signal SIGUSR1 a son fils cadet.A la reception de ce signal, le fils cadet devra envoyer le signal SIGUSR2 au fils aine (qui provoque saterminaison) avant de s’arreter.Indication : il est tres difficile d’interchanger les roles des deux fils.

Reponse

1 #include <signal.h>23 int aine, cadet;45 void cadet_sigusr1() {6 printf("Reception du signal SIGUSR1 dans %d\n", getpid());7 kill(aine, SIGUSR2);8 exit(0);9 }

1011 void aine_sigusr2() {12 printf("Reception du signal SIGUSR2 dans %d\n", getpid());13 exit(0);14 }1516 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);2425 pause();26 }2728 /* 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);3435 pause();36 }3738 /* 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

Page 4: 02-tp1-fork-exec-correction.pdf

TP1 : fork, exec et signaux

CORRECTION

CORRECTION

Fin reponse

F Exercice 4. Reimplementer if.

. Question 1. Ecrire une version simplifiee 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.c1 #include <stdlib.h>2 #include <stdio.h>3 #include <string.h>4 #include <unistd.h>5 #include <sys/wait.h>67 int main(int argc, char **argv) {8 int alors_pos = 0;9 int sinon_pos = 0;

10 int i = 0;11 int status;1213 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;1819 argv[alors_pos] = NULL;2021 if (sinon_pos)22 argv[sinon_pos] = NULL;2324 if(!(alors_pos)) {25 printf("Syntaxe : ./si expr alors expr [sinon expr]\n");26 return -1;27 }2829 if(fork()==0) {30 execvp(argv[1],&argv[1]);31 perror("execvp casse !");32 return -1;33 }3435 wait(&status);3637 if(WIFEXITED(status)) {38 if(!WEXITSTATUS(status)) {39 if(!sinon_pos)40 sinon_pos=argc;4142 execvp(argv[alors_pos+1],&argv[alors_pos+1]);4344 perror("execvp casse !");45 return -1;4647 } else if(sinon_pos) {4849 execvp(argv[sinon_pos+1],&argv[sinon_pos+1]);5051 perror("execvp casse !");52 return -1;53 }54 // test "si" faux, pas de "sinon"55 return 0;5657 } else {58 // test "si" pas sorti par exit59 return -1;60 }61 }62

Fin reponse

4