• Aucun résultat trouvé

TP n°2

N/A
N/A
Protected

Academic year: 2022

Partager "TP n°2"

Copied!
7
0
0

Texte intégral

(1)

TP n°2

Exercice 1.

protection des fichiers

1. Dans votre répertoire courant, créer un répertoire essai_droit. Quels sont les droits par défaut de ce répertoire ?

Quelles sont les commandes (en notation symbolique et en notation octale) pour lui donner les droits suivants :

Propriétaire Groupe Autres

lect écrit exé lect écrit exé lect écrit exé

Commande 1 Oui Oui Oui Oui Non Oui Non Non Oui

Commande 2 Oui Non Oui Non Oui Non Non Non Oui

Commande 3 Non Oui Non Non Non Oui Oui Non Non

Commande 4 Non Non Oui Oui Non Oui Non Non Non

Tester ces commandes et vérifier les droits d’accès obtenus à chaque étape.

2. Créer un fichier droit dans le répertoire essai_droit, quels sont ses droits par défaut ? En partant du répertoire courant, pour chaque commande de la question précédente, essayer d’accéder au répertoire essai_droit (commande cd), de lister le contenu du répertoire essai_droit (commande ls) et de modifier le fichier droit avec un éditeur quelconque (emacs par exemple).

Exercice 2.

System monitoring

Ajouter au tableau construit lors de la dernière séance de TP les commandes suivantes (avec ou sans option).

vmstat, iostat, mpstat, top, ps

Pour chacune de ces commandes, étudier la page d’aide et donner une description de la commande.

Tester chacune de ces commandes sur des exemples concrets et analyser la réponse du système.

Exercice 3.

1. Primitive fork()

int fork(void) - Créer le programme fork.c suivant:

#include <stdio.h>

main()

if (fork() == 0) 

printf("processus fils %d\n", getpid()); 

else 

printf("processus pere %d\n", getpid()); 

}

- Compiler et exécuter.

- Faire afficher aussi et pour chaque processus, le n° pid du processus père. Primitive getppid() - Quel est ce processus père ?

- Constater avec la commande ps, le n° pid du shell.

(2)

#include <stdio.h>

main()

if (fork() == 0) 

printf("Un processus fils %d\n", getpid()); 

else 

/* Creer un autre fils ici. */ 

if (fork() == 0) 

printf("Un autre processus fils %d\n", getpid()); 

else 

printf("processus pere %d\n", getpid()); 

- Tester et commenter le programme suivant :

#include <stdio.h>

main() {

printf(“A\n”);

fork();

printf(“B\n”);

}

- Idem pour le programme suivant

#include <stdio.h>

main()

printf("A\n"); 

fork();

printf("B\n"); 

fork(); 

printf("C\n"); 

}

2. Le Couple fork() / exec()

int execl (char *ref, char *arg0, …, char *argn, 0) int execv (char *ref, char *argv [ ]);

La création d’un nouveau processus ne peut se faire que par le « recouvrement » du code d’un processus existant. Cela se fait à l’aide d’une des fonctions de la famille exec qui permet de faire exécuter par un processus un autre programme que celui d’origine.

Lorsqu'un processus exécute un appel exec, il charge un autre programme exécutable en conservant le même environnement système :

• Du point de vue du système, il s'agit toujours du même processus : il a conservé le même pid.

• Du point de vue de l'utilisateur, le processus qui exécute exec disparaît, au profit d’un nouveau processus disposant du même environnement système et qui débute alors son exécution.

- Créer le programme prog.c suivant:

#include <stdio.h>

main(int argc, char* argv[])

printf("Le programme %s lancé par un autre\n", argv[0]); 

}

(3)

- Compiler par:

$ cc ­o prog prog.c

- Exécuter par:

$ prog

- Quel est cet «autre » programme dans ce cas ? - Créer le programme ForkExec.c suivant:

#include <stdio.h>

main()

if (fork() == 0) 

execl("prog", "prog", NULL); 

else 

printf("Le programme normal\n"); 

}

- Compiler et exécuter. Constater le résultat.

- Transformer prog.c en progParam.c suivant. Compiler le vers prog.

#include <stdio.h>

main(int argc, char* argv[])

int i; 

printf("Le programme (%s) lancé et parametres recus:\n", argv[0]); 

for(i=1; i<argc; i++) 

printf("%s\n",argv[i]); 

}

- Modifier le programme ForkExec.c en remplaçant la ligne execl par:

execl("prog", "prog", "Jean", "Paris", "21", NULL);

- Compiler et exécuter. Constater le résultat.

- Faites exec ps. Que se passe-t-il ? Donnez une explication.

- Vérifiez votre explication en étudiant la commande shell exec sh. (Quel est le pid de ce shell ?) 4. La primitive exit()

#include <stdlib.h>

void exit (int status)

La fonction exit met fin au processus qui l’a émis, avec un code de retour status. Tous les descripteurs de fichiers ouverts sont fermés ainsi que tous les flots de la bibliothèque d’E/S standard. Si le processus à des fils lorsque exit est appelé, ils ne sont pas modifiés mais comme le processus père prend fin, le nom de leur processus père est changé en 1, qui est l’identifiant du processus init.

Ce processus init est l’ancêtre de tous les processus du système excepté le processus 1 lui-même ainsi que le processus 0 chargé de l’ordonnancement des processus. En d’autres termes, c’est l’ancêtre de tous les processus qui adopte tous les orphelins. Par convention, un code de retour égal à zéro signifie que le processus s’est terminé correctement, et un code non nul (généralement 1) signifie qu’une erreur s’est produite. Seul l’octet de droite de l’entier status est remonté au processus père. On est donc limité à 256 valeurs pour communiquer un code retour à son processus père. Le père du processus qui effectue un exit reçoit son code retour à travers un appel à wait.

(4)

3. Appel système wait() et waitpid()

#include <sys/types.h>

#include <sys/wait.h>

int wait (int * terminaison)

int waitpid (int pid, int *terminaison, int options)

Lorsque le fils se termine, si son père ne l’attend pas, le fils passe à l’état defunct (ou zombi) dans la table des processus. L’élimination d’un processus terminé de la table ne peut se faire que par son père, grâce à la fonction wait. Avec cette instruction :

• Le père se bloque en attente de la fin d’un fils.

• Elle rendra le n° ( PID) du premier fils mort trouvé.

• La valeur du code de sortie est reliée au paramètre d’exit de ce fils. On peut donc utiliser l’instruction wait pour connaître la valeur éventuelle de retour, fournie par exit(), d’un processus. Ce mode d’utilisation est analogue à celui d’une fonction. wait() rend –1 en cas d’erreur.

L’appel système waitpid permet de tester la terminaison d’un processus particulier, dont on connaît le PID.

La primitive permet de tester, en bloquant ou non le processus appelant, la terminaison d’un processus particulier ou appartenant à un groupe de processus donné et de récupérer les informations relatives à sa terminaison à l’adresse terminaison.

Plus précisément le paramètre pid permet de sélectionner le processus attendu de la manière suivante :

• <-1 tout processus fils dans le groupe | pid |

• -1 tout processus fils

• 0 tout processus fils du même groupe que l’appelant

• >0 processus fils d’identité pid

Le paramètre options est une combinaison bit à bit des valeurs suivantes. La valeur WNOHANG permet au processus appelant de ne pas être bloqué si le processus demandé n’est pas terminé.

La fonction renvoie : -1 en cas d’erreur,

0 en cas d’échec (processus demandé existant mais non terminé) en mode non bloquant,

> 0 le numéro du processus fils zombi pris en compte.

- En se reférant au deuxième code du point 1. de ce même exercice, ajouter les instructions qui permettront au processus père d’attendre la terminaison de son fils et qui afficheront le code retour de celui-ci.

Processus zombie

Lorsqu'un programme se termine, un processus spécial hérite de ses fils, le programme init, qui s'exécute toujours avec un identifiant de processus valant 1 (il s'agit du premier processus lancé lorsque Linux démarre). Le processus init libère automatiquement les ressources de tout processus zombie dont il hérite.

Exercice 5.

Les deux programmes ci-dessous proposent une première approche de synchronisation entre deux processus père et fils. Dans le second, il y a deux fils. Le père est synchronisé de telle sorte qu'il se termine après la terminaison du deuxième fils. Ecrire ces deux programmes. Les exécuter et en analyser le fonctionnement.

(5)

// premier programme

#include <stdio.h>

#include <unistd.h>

main() 

int pid; 

int status; 

switch(pid=fork())

case ­1 : perror("création de processus\n"); 

exit(2); 

case 0: printf("Je suis le fils\n"); 

printf("valeur de fork = %d\n", pid); 

printf("je suis le processus %d de père %d\n",  getpid(),getppid()); 

printf("fin du fils\n"); 

exit(0); 

default : wait(&status); 

printf("Je suis le père\n"); 

printf("valeur de fork = %d\n", pid); 

printf("je suis le processus %d de père %d\n",  getpid(),getppid()); 

printf("fin du père\n");

exit(128); 

}

// deuxième programme

#include <stdio.h>

#include <unistd.h>

main()  {

int pid_fils1, pid_fils2, pid_courant; 

int status; pid_fils1=fork(); 

pid_courant=getpid(); 

switch(pid_fils1)

case ­1: perror("Pb dans la création du 1er fils\n");

exit(2); 

case 0: printf("%d: je suis le 1er fils du processus %d\n",  pid_courant,getppid()); 

printf("%d: fin du processus\n",pid_courant); 

exit(0); 

default : switch(pid_fils2=fork())

case ­1: perror("Pb dans la création du 2ème fils\n"); 

exit(3); case 0: printf("%d: Je suis le 2nd fils du processus 

%d\n",getpid(),getppid()); 

sleep(2); 

printf("%d: fin du processus\n",getpid()); 

exit(1); 

default : printf("%d: je suis le père et j'attends mon  fils de pid %d\n",pid_courant,pid_fils2); 

waitpid(pid_fils2,&status,0); 

printf("%d: fin du père\n",pid_courant); 

exit(128); 

} }

}

(6)

Exercice 6.

La primitive system()

La fonction system lance l’exécution d’un processus SHELL interprétant la commande passée en argument dans la chaîne de caractères ch. Cette fonction crée pour cela un nouveau processus, qui se termine avec la fin de la commande. Le processus à l'origine de l'appel de system est suspendu jusqu'à la fin de la commande.

int system (char *ch)

- Ecrire un programme qui débute par l'affichage de BONJOUR, se poursuit par l'exécution de la commande "ls -l" et se termine par l'affichage de BONSOIR.

- Ecrire un programme qui lance la commande shell « sleep 60 » à l’aide de la primitive system.

Lancer l’exécutable correspondant en arrière plan et taper la commande ‘ps –l’. Expliquer le résultat obtenu.

- Effectuer la même opération en lançant la commande shell en arrière plan : sleep 60 &. Que se passe-t-il ?

Exercice 7.

popen()

L'inconvénient majeur de la fonction system() est que le programme appelant ne contrôle ni en entrée ni en sortie, les données traîtées par la commande. La fonction popen() permet de pallier cette insuffisance. De manière transparente, popen() ouvre un pipe avant d'appeler la commande, permettant ainsi au programme appelant de communiquer avec le programme appelé grâce à ce pipe.

La syntaxe est la suivante:

FILE * popen(char * commande, char * mode)

1. où FILE * indique que la fonction popen() retourne un pointeur sur une structure de type FILE, comme le fait la fonction fopen().

2. où commande représente la chaîne de caractères associée au nom de la commande Unix, éventuellement suivie de ses arguments, exactement comme pour la fonction system().

3. où mode correspond au mode d'entrée/sortie choisi:

◦ "r" lecture

◦ "w" ecriture

Ce mode a la même signification que celui qui est généralement utilisé dans la fonction fopen(filename, mode.

Exemple de lecture de données d'une commande restituées sur l'écran:

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

void main() {

FILE *pp;

char buf[128];

if ((pp = popen("ps aux", "r")) == NULL)  {

  perror("popen");

  exit(1);

}

while (fgets(buf, sizeof(buf), pp))   fputs(buf, stdout);

pclose(pp);

}

La fonction pclose() permet de fermer le pipe, avec en argument le pointeur de fichier rendu initialement par popen().

(7)

Exercice 8.

(homework)

Pour chacune de ces commandes, étudier la page d’aide et donner une description de la commande.

Tester chacune de ces commandes sur des exemples concrets et analyser la réponse du système.

mount, umount, printenv, set

Références

Documents relatifs

Exécutez puis commentez le résultat de l’exécution de ce code.. Que représente la valeur de returnWait et celle

– au standard POSIX pthread largement mis en oeuvre sur les systèmes UNIX/Linux – à l’API WIN32 threads fournie par Microsoft ©Windows pour les processus légers Les pages man

Formation certifiante IB: ○ Formation Cat 1 2015, 2016, 2017, 2018 ○ Formation Cat 2 3 février au 3 mars 2021 ○ Formation Cat 3 2016, 2020 Formation SEBIQ sur le PP 2015,

Les membres de la famille à l’étranger d’une personne réfugiée/protégée peuvent être inclus dans la demande de résidence permanente, et obtenir la résidence sans passer par

[r]

Pour simplifier un script lors de la répétition d’un même bloc de commande, on peut utiliser ce que l’on appelle en programmation une boucle grâce au bloc de commande ci-contre.

de commande, on peut utiliser ce que l’on appelle en programmation une boucle grâce au bloc de commande ci-contre. a) Modifie ton premier script pour utiliser une boucle

Pour approfondir la performance du processus de gestion de commandes, Johanne décide dans un premier temps de décrire le processus actuel et d’en mesurer sa performance actuelle.