Soit la séquence de commandes suivantes (rien d'autre ne se passe dans le système pendant cette séquence) :
$ ls rep f1 f2 $ ls -l rep rep/f1: Autorisation refusée rep/f2: Autorisation refusée
Soit l'exécutable a obtenu après compilation du code source suivant :
int main(int argc,char *argv[]) { int d, i; d = open("f",O_WRONLY|O_TRUNC); if (d==-1) exit(EXIT_FAILURE); for (i=0; i<100000; i++) { if (write(d,argv[0],1)==-1) { close(d); exit(EXIT_FAILURE); } } close(d); return EXIT_SUCCESS; }
Soit l'exécutable c obtenu après compilation du code source suivant :
#define LG 2 int main(int argc,char *argv[]) { int d, l, t; char c[LG]; l = t = 0; d = open("f",O_RDONLY); if (d==-1) exit(EXIT_FAILURE); while ( (l=read(d,c,LG))>0 ) t += l; close(d); printf("J'ai lu %d octets\n",t); return EXIT_SUCCESS; }
On pourra supposer qu'avant toute commande le fichier f est vide.
Soit le programme p obtenu après compilation du code source suivant :
int main(int argc,char *argv[]) { int d1, d2; ssize_t r; char c; if (argc<3) exit(EXIT_FAILURE); d1 = open(argv[1],O_RDONLY); if (d1==-1) exit(EXIT_FAILURE); d2 = open(argv[2],O_WRONLY); if (d2==-1) { close(d1); exit(EXIT_FAILURE); } while ( (r=read(d1,&c,1))==1 ) { if ( write(d2,&c,1)!=1 ) { close(d1); close(d2); exit(EXIT_FAILURE); } } close(d1); close(d2); return r==0?EXIT_SUCCESS:EXIT_FAILURE; }
Avant toute exécution on effectue les commandes suivantes :
$ echo "Il était une fois..." > f1 # Création d'un fichier f1 $ touch f2 # Création d'un fichier vide de nom f2 $ mkfifo t t1 t2 # Création de trois tubes nommés t t1 et t2 $
Il s'agit d'écrire une application de messagerie interactive contruite sur un modèle client/serveur. Il existe deux types de clients : les lecteurs (qui se contentent de recevoir des messages du serveur) et les écrivains (qui se contentent d'envoyer des messages au serveur).
Le serveur utilise un tube nommé de nom /tmp/tube_serveur sur lequel il reçoit des requêtes de quatre types :
Le lecteur reçoit sur un tube nommé qu'il a choisi les réponses suivantes :
On vous donne le fichier d'entête suivant :
/* Types des messages client -> serveur */ #define CNX 0 #define BRDCST 1 #define SHUT -1 /* Types des messages serveur -> client */ #define MSG 1 /* Types des messages serveur et client */ #define CLO 2 struct msg { int type; char msg[MSGLEN]; // Message â diffuser ou nom du tube };
Écrire le code de la commande serveur.
Écrire le code de la commande lecteur.
Cette commande se contente de créer un tube nommé dont le nom sera obtenu par un appel à la fonction char *tmpnam(NULL);, puis d'indiquer au serveur qu'il doit maintenant diffuser les messages sur ce tube. Ensuite elle se contente de réceptionner les messages en provenance du serveur, de les interpréter et d'afficher leur contenu sous forme lisible à l'utilisateur.
Écrire le code de la commande ecrivain.
Cette commande est destinée à envoyer des messages au serveur. Elle prend divers paramètres :