TD 2 : Entrées-Sorties - Primitives Système

Introduction      FAQ   TD 1   TD 2   TD 3   TD 4   TD 5   TD 6   TD 7   TD 8

1.  Lecture d'un répertoire (last_num)

Le serveur utilise un répertoire contenant tous les articles. Chaque fichier contenant un article a comme nom le numéro de l'article. Pour nommer les nouveaux articles, le serveur a donc besoin de connaître le dernier numéro utilisé pour un article.

Pour cela, le serveur utilise une fonction last_num(),

extern int last_num (char *directory);

qu'il exécute au démarrage. Cette fonction parcourt le répertoire directory contenant les articles et retourne l'entier correspondant au plus grand d'entre eux.

Cette fonction est actuellement fournie par la librairie libforumserver.a. Implantez votre propre version de cette fonction dans le fichier server.c.

Fonctions à utiliser (man): opendir, readdir, closedir.

Solution: last_num.c

Est-ce possible de tracer les appels systèmes lors de l'exécution d'un processus ?

Il peut parfois être utile pour diagnostiquer les problèmes d'un programme de tracer les appels systèmes effectués par un processus. Sans lancer un dévermineur, il existe une commande pour cela, la commande strace:

 strace ./client 

Cette commande va afficher tous les appels systèmes effectués, en indiquant à chaque fois les paramètres fournis, ainsi que les résultats et erreurs. Vous pouvez ainsi découvrir quel appel système n'a pas fonctionné, ou espionner le comportement d'un programme pour en imiter le fonctionnement.

strace ne trace que le processus courant, mais pas ses fils. Il est possible de modifier ce comportement avec l'option -f, en particulier si on veut tracer notre processus serveur:

strace -f ./server 

2.  Nettoyage d'un répertoire (remove_expired)

Les articles ne sont pas conservés éternellement sur le serveur. Celui-ci nettoie régulièrement son répertoire d'articles pour en supprimer les articles trop vieux (sauf le dernier article posté qui doit être conservé pour que last_num() fonctionne).

Pour cela, il utilise une fonction remove_expired(),

extern void remove_expired (char *directory,
   int delay, int last_num);

qu'il exécute à chaque fois qu'un nouveau message est posté. Cette fonction supprime tous les fichiers du répertoire directory dont l'age dépasse le délai d'expiration delay. Le dernier article last_num est lui toujours conservé.

Cette fonction est actuellement fournie par le fichier libforumserver.a. Implantez votre propre version de cette fonction dans le fichier server.c.

Nouvelles fonctions à utiliser: time, stat, unlink.

Solution: remove_expired.c

3.  Lecture d'un entête (read_header)

Dans cette question, on utilisera les appels systèmes d'accès aux fichiers (open, read et close) et non les fonctions de la bibliothèque C (fopen, ...). Il ne sera donc pas possible d'utiliser la fonction read_line du TD1.

Dans le client, l'utilisateur peut demander l'affichage des entêtes de tous les articles qu'il n'a pas encore lus. Pour cela, le client maintient en mémoire une liste des articles, contenant pour chacun certaines informations importantes, telles que l'auteur et le sujet. Ces informations sont obtenues en lisant les premières lignes de l'article:

From: cohen (Albert Cohen)
Date: Mon Jan 12 12:34:00 MET 2007
Subject: Exemple

Ce message est un bel exemple d'article,
n'est-ce pas ?
Comment une fonction C peut-elle retourner plusieurs valeurs ?

Contrairement à certains langages (Objective-Caml par exemple) qui permettent de renvoyer un n-uplet comme valeur de retour d'une fonction, le langage C ne permet que de retourner une seule valeur.

Pour palier ce problème, l'astuce consiste à fournir des arguments supplémentaires à la fonction: ces arguments sont des pointeurs vers des variables définies avant l'appel de la fonction, que celle-ci va aller modifier pour y placer les valeurs qu'elle voudrait retourner. Ainsi, dans la fonction:

  void convert(float radius, float angle, float *x, float *y)
  {
    *x = radius * cos(angle);
    *y = radius * sin(angle);
  }

les deux premiers arguments sont de vrais arguments, tandis que les deux suivants servent uniquement à placer les valeurs de retour chez l'appelant. A l'utilisation, cela donne:

  float r = 1.2;
  float a = 0.3; 
  float xx;
  float yy;

  convert(r, a, &xx, &yy);

  printf("Coordinates for %.3f : %.3f = (%.3f, %.3f) \n", r, a, xx, yy);

Pour cela, le client utilise une fonction read_header(),

int read_header (char *directory, int num, 
  char **author, char **date, char **subject);

qu'il appelle en générant la liste des articles. La fonction lit le fichier de l'article num dans le répertoire directory, et alloue les chaînes de caractères à retourner via les arguments author, date et subject (voir apparté), à partir des trois premières lignes de l'article, et de leur contenu, préfixé par les titres "From:", "Date:" et Subject:.

Cette fonction est actuellement fournie par le fichier libforumclient.a. Implantez votre propre version de cette fonction dans le fichier client.c.

Nouvelles fonctions à utiliser: open, read, close.

4.  Déplacement d'un message (new_message)

Lorsqu'un client veut poster un nouvel article, il place son contenu dans un fichier, puis transmet le nom de ce fichier au serveur (par un mécanisme que nous verrons dans un TD ultérieur). Le serveur affecte alors un numéro à l'article, renomme alors le fichier en utilisant ce numéro. Il vérifie aussi que l'article ne peut être modifié par les autres utilisateurs.

Pour cela, le serveur utilise une fonction new_message(filename, last_num),

extern int new_message(char *filename, int last_num);

qui effectue ces opérations. Cette fonction est appelée par le serveur, sans indiquer le répertoire des articles, car il s'agit simplement du répertoire courant, dans lequel le serveur s'exécute habituellement.

Cette fonction est actuellement fournie par le fichier libforumserver.a. Implantez votre propre version de cette fonction dans le fichier server.c.

Nouvelles fonctions à utiliser: chmod, rename.