--- /dev/null
+Projet système
+==============
+
+Partie 1 :
+----------
+- sources
+- dossier programmation
+- dossier utilisateur
+
+Partie 2 :
+----------
+- sources
+- dossier programmation
+- dossier utilisateur
+
+musique :
+---------
+- programme lisant un fichier de musique sur le haut parleur du pc. Je n'ai pas pu l'inclure par manque de temps pour chercher un équivalent à la fonction beep, qui était obsolète sous linux à l'époque.
+
+Note :
+------
+
+Ceci n'est pas la version finale : il y a encore un petit bug dans la gestion des pages. Il manque une condition dans un for que j'avais bricolé à la dernière minute (remplacé un while + if en fait). Quand j'aurai le temps je corrigerai.
--- /dev/null
+100 \r
+C3 C \r
+C3 C \r
+C3 C \r
+D3 C \r
+E3 N \r
+D3 N \r
+C3 C \r
+E3 C \r
+D3 C \r
+D3 C \r
+C3 B
\ No newline at end of file
--- /dev/null
+100 C1 TC CD1 TC D1 TC DD1 TC E1 TC F1 TC FD1 TC G1 TC GD1 TC A1 TC AD1 TC B1 TC C2 TC CD2 TC D2 TC DD2 TC E2 TC F2 TC FD2 TC G2 TC GD2 TC A2 TC AD2 TC B2 TC C3 TC CD3 TC D3 TC DD3 TC E3 TC F3 TC FD3 TC G3 TC GD3 TC A3 TC AD3 TC B3 TC C4 TC CD4 TC D4 TC DD4 TC E4 TC F4 TC FD4 TC G4 TC GD4 TC A4 TC AD4 TC B4 TC C5 TC CD5 TC D5 TC DD5 TC E5 TC F5 TC FD5 TC G5 TC GD5 TC A5 TC AD5 TC B5 TC
\ No newline at end of file
--- /dev/null
+120 \r
+A3 C \r
+B3 C \r
+C4 N \r
+B3 C \r
+A3 C \r
+G3 C \r
+A3 C \r
+B3 C \r
+A3 B \r
+P N \r
+B3 C \r
+G3 B \r
+P N \r
+B3 C \r
+A3 B
\ No newline at end of file
--- /dev/null
+#define DO1 65\r
+#define DOD1 69\r
+#define RE1 74\r
+#define RED1 78\r
+#define MI1 83\r
+#define FA1 87\r
+#define FAD1 92\r
+#define SOL1 98\r
+#define SOLD1 104\r
+#define LA1 110\r
+#define LAD1 117\r
+#define SI1 123\r
+#define DO2 131\r
+#define DOD2 139\r
+#define RE2 147\r
+#define RED2 156\r
+#define MI2 165\r
+#define FA2 175\r
+#define FAD2 185\r
+#define SOL2 196\r
+#define SOLD2 208\r
+#define LA2 220\r
+#define LAD2 233\r
+#define SI2 247\r
+#define DO3 262\r
+#define DOD3 277\r
+#define RE3 294\r
+#define RED3 311\r
+#define MI3 330\r
+#define FA3 349\r
+#define FAD3 370\r
+#define SOL3 392\r
+#define SOLD3 415\r
+#define LA3 440\r
+#define LAD3 466\r
+#define SI3 494\r
+#define DO4 523\r
+#define DOD4 554\r
+#define RE4 587\r
+#define RED4 622\r
+#define MI4 659\r
+#define FA4 698\r
+#define FAD4 740\r
+#define SOL4 784\r
+#define SOLD4 831\r
+#define LA4 880\r
+#define LAD4 932\r
+#define SI4 988\r
+#define DO5 1046\r
+#define DOD5 1109\r
+#define RE5 1175\r
+#define RED5 1244\r
+#define MI5 1318\r
+#define FA5 1397\r
+#define FAD5 1480\r
+#define SOL5 1568\r
+#define SOLD5 1661\r
+#define LA5 1760\r
+#define LAD5 1865\r
+#define SI5 1975\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+\r
+#define MS_PAR_MIN 60000\r
+\r
+unsigned int freq_of_note (char *note)\r
+{\r
+ //Octave 1\r
+ if (strcmp ("C1",note)==0) //DO\r
+ return DO1;\r
+ else if (strcmp ("CD1",note)==0) //DO #\r
+ return DOD1;\r
+ else if (strcmp ("D1",note)==0) //RE\r
+ return RE1;\r
+ else if (strcmp ("DD1",note)==0) //RE #\r
+ return RED1;\r
+ else if (strcmp ("E1",note)==0) //MI\r
+ return MI1;\r
+ else if (strcmp ("F1",note)==0) //FA\r
+ return FA1;\r
+ else if (strcmp ("FD1",note)==0) //FA #\r
+ return FAD1;\r
+ else if (strcmp ("G1",note)==0) //SOL\r
+ return SOL1;\r
+ else if (strcmp ("GD1",note)==0) //SOL #\r
+ return SOLD1;\r
+ else if (strcmp ("A1",note)==0) //LA\r
+ return LA1;\r
+ else if (strcmp ("AD1",note)==0) //LA #\r
+ return LAD1;\r
+ else if (strcmp ("B1",note)==0) //SI\r
+ return SI1;\r
+ //Octave 2\r
+ else if (strcmp ("C2",note)==0) //DO\r
+ return DO2;\r
+ else if (strcmp ("CD2",note)==0) //DO #\r
+ return DOD2;\r
+ else if (strcmp ("D2",note)==0) //RE\r
+ return RE2;\r
+ else if (strcmp ("DD2",note)==0) //RE #\r
+ return RED2;\r
+ else if (strcmp ("E2",note)==0) //MI\r
+ return MI2;\r
+ else if (strcmp ("F2",note)==0) //FA\r
+ return FA2;\r
+ else if (strcmp ("FD2",note)==0) //FA #\r
+ return FAD2;\r
+ else if (strcmp ("G2",note)==0) //SOL\r
+ return SOL2;\r
+ else if (strcmp ("GD2",note)==0) //SOL #\r
+ return SOLD2;\r
+ else if (strcmp ("A2",note)==0) //LA\r
+ return LA2;\r
+ else if (strcmp ("AD2",note)==0) //LA #\r
+ return LAD2;\r
+ else if (strcmp ("B2",note)==0) //SI\r
+ return SI2;\r
+ //Octave 3\r
+ else if (strcmp ("C3",note)==0) //DO\r
+ return DO3;\r
+ else if (strcmp ("CD3",note)==0) //DO #\r
+ return DOD3;\r
+ else if (strcmp ("D3",note)==0) //RE\r
+ return RE3;\r
+ else if (strcmp ("DD3",note)==0) //RE #\r
+ return RED3;\r
+ else if (strcmp ("E3",note)==0) //MI\r
+ return MI3;\r
+ else if (strcmp ("F3",note)==0) //FA\r
+ return FA3;\r
+ else if (strcmp ("FD3",note)==0) //FA #\r
+ return FAD3;\r
+ else if (strcmp ("G3",note)==0) //SOL\r
+ return SOL3;\r
+ else if (strcmp ("GD3",note)==0) //SOL #\r
+ return SOLD3;\r
+ else if (strcmp ("A3",note)==0) //LA\r
+ return LA3;\r
+ else if (strcmp ("AD3",note)==0) //LA #\r
+ return LAD3;\r
+ else if (strcmp ("B3",note)==0) //SI\r
+ return SI3;\r
+ //Octave 4\r
+ else if (strcmp ("C4",note)==0) //DO\r
+ return DO4;\r
+ else if (strcmp ("CD4",note)==0) //DO #\r
+ return DOD4;\r
+ else if (strcmp ("D4",note)==0) //RE\r
+ return RE4;\r
+ else if (strcmp ("DD4",note)==0) //RE #\r
+ return RED4;\r
+ else if (strcmp ("E4",note)==0) //MI\r
+ return MI4;\r
+ else if (strcmp ("F4",note)==0) //FA\r
+ return FA4;\r
+ else if (strcmp ("FD4",note)==0) //FA #\r
+ return FAD4;\r
+ else if (strcmp ("G4",note)==0) //SOL\r
+ return SOL4;\r
+ else if (strcmp ("GD4",note)==0) //SOL #\r
+ return SOLD4;\r
+ else if (strcmp ("A4",note)==0) //LA\r
+ return LA4;\r
+ else if (strcmp ("AD4",note)==0) //LA #\r
+ return LAD4;\r
+ else if (strcmp ("B4",note)==0) //SI\r
+ return SI4;\r
+ //Octave 5\r
+ else if (strcmp ("C5",note)==0) //DO\r
+ return DO5;\r
+ else if (strcmp ("CD5",note)==0) //DO #\r
+ return DOD5;\r
+ else if (strcmp ("D5",note)==0) //RE\r
+ return RE5;\r
+ else if (strcmp ("DD5",note)==0) //RE #\r
+ return RED5;\r
+ else if (strcmp ("E5",note)==0) //MI\r
+ return MI5;\r
+ else if (strcmp ("F5",note)==0) //FA\r
+ return FA5;\r
+ else if (strcmp ("FD5",note)==0) //FA #\r
+ return FAD5;\r
+ else if (strcmp ("G5",note)==0) //SOL\r
+ return SOL5;\r
+ else if (strcmp ("GD5",note)==0) //SOL #\r
+ return SOLD5;\r
+ else if (strcmp ("A5",note)==0) //LA\r
+ return LA5;\r
+ else if (strcmp ("AD5",note)==0) //LA #\r
+ return LAD5;\r
+ else if (strcmp ("B5",note)==0) //SI\r
+ return SI5;\r
+ else return 0;\r
+}\r
+\r
+unsigned int duree_of_type (char *type, int temps_noire)\r
+{\r
+ if (strcmp(type,"N")==0) //noire\r
+ return temps_noire;\r
+ else if (strcmp(type,"NP")==0) //noire pointée\r
+ return (3*temps_noire)/2;\r
+ else if (strcmp(type,"B")==0) //blanche\r
+ return 2*temps_noire;\r
+ else if (strcmp(type,"BP")==0) //blanche pointée\r
+ return 3*temps_noire;\r
+ else if (strcmp(type,"R")==0) //ronde\r
+ return 4*temps_noire;\r
+ else if (strcmp(type,"RP")==0) //ronde pointée\r
+ return 6*temps_noire;\r
+ else if (strcmp(type,"C")==0) //croche\r
+ return temps_noire/2;\r
+ else if (strcmp(type,"CP")==0) //croche pointée\r
+ return (3*temps_noire)/4;\r
+ else if (strcmp(type,"DC")==0) //double croche\r
+ return temps_noire/4;\r
+ else if (strcmp(type,"DCP")==0) //double croche pointée\r
+ return (3*temps_noire)/8;\r
+ else if (strcmp(type,"TC")==0) //triple croche\r
+ return temps_noire/8;\r
+ else if (strcmp(type,"TCP")==0) //triple croche pointée\r
+ return (3*temps_noire)/16;\r
+ else if (strcmp(type,"C")==0) //quadruple croche\r
+ return temps_noire/16;\r
+ else if (strcmp(type,"C")==0) //quadruple croche pointée\r
+ return (3*temps_noire)/32;\r
+ else return 0;\r
+}\r
+\r
+\r
+void jouer (char *morceau)\r
+{\r
+ FILE *fichier;\r
+ int tempo;\r
+ char note[8];\r
+ char type[8];\r
+ int duree = 0;\r
+ int temps_noire = 0;\r
+\r
+ //ouverture du fichier\r
+ if ((fichier = fopen(morceau, "r")) == NULL)\r
+ { \r
+ fprintf(stderr,"fichier inconnu\n");\r
+ exit(1);\r
+ }\r
+\r
+ //lecture du tempo\r
+ if (fscanf(fichier, "%d", &tempo) != 1)\r
+ { \r
+ perror("lecture du tempo");\r
+ exit(1);\r
+ }\r
+\r
+ //tempo = (int) *tp;\r
+\r
+ //détermination de la durée d'une noire\r
+ temps_noire = MS_PAR_MIN / tempo;\r
+ \r
+ fprintf(stdout,"Tempo : %d à la noire\n", tempo);\r
+\r
+ //lecture des notes\r
+ while (fscanf(fichier, "%s %s",note, type) == 2)\r
+ {\r
+ if (strcmp(note,"P")==0)\r
+ {\r
+ fprintf(stdout,"PAUSE duree=%d\n",duree_of_type(type, temps_noire));\r
+ _sleep((unsigned long)duree_of_type(type, temps_noire));\r
+ }\r
+ else \r
+ {\r
+ fprintf(stdout,"freq=%d duree=%d\n",freq_of_note(note),duree_of_type(type, temps_noire));\r
+ _beep(freq_of_note(note),duree_of_type(type, temps_noire));\r
+ } \r
+ }\r
+\r
+}\r
+\r
+int main (void)\r
+{\r
+ char morceau[128];\r
+ \r
+ fprintf(stdout, "Entrez le nom du morceau :");\r
+\r
+ fscanf(stdin,"%s",morceau);\r
+\r
+ jouer(morceau);\r
+\r
+}
\ No newline at end of file
--- /dev/null
+210\r
+E4 DC\r
+F4 DC\r
+E4 DC\r
+D4 DC\r
+E4 DC\r
+D4 DC\r
+CD3 DC\r
+D4 DC\r
+E4 DC\r
+D4 DC\r
+CD3 DC\r
+D4 DC\r
+E4 DC\r
+F4 DC\r
+E4 DC\r
+D4 DC\r
+E4 DC\r
+D4 DC\r
+CD3 DC\r
+D4 DC\r
+E4 DC\r
+D4 DC\r
+CD3 DC\r
+D4 DC\r
+E4 DC\r
+F4 DC\r
+E4 DC\r
+D4 DC\r
+E4 DC\r
+D4 DC\r
+CD3 DC\r
+D4 DC\r
+E4 DC\r
+D4 DC\r
+CD3 DC\r
+D4 DC\r
+G4 DC\r
+F4 DC\r
+D4 DC\r
+C3 DC\r
+AD3 DC\r
+G3 DC\r
+AD3 DC\r
+C3 DC\r
+CD3 DC\r
+C3 DC\r
+AD3 DC\r
+G3 DC\r
+F3 DC\r
+D3 DC\r
+AD3 DC\r
+G3 DC\r
+F3 DC\r
+D3 DC\r
+C2 DC\r
+AD2 DC\r
+D3 DC\r
+C2 DC\r
+AD2 DC\r
+G2 DC\r
+P B\r
+P C\r
+G2 C\r
+AD2 DC\r
+G2 DC\r
+G2 DC\r
+AD2 DC\r
+G2 DC\r
+G2 DC\r
+AD2 DC\r
+G2 DC\r
+G2 DC\r
+AD2 DC\r
+G2 DC\r
+G2 DC\r
+AD2 DC\r
+G2 DC\r
+C3 DC\r
+G2 DC\r
+AD2 DC\r
+G2 DC\r
+G2 DC\r
+AD2 DC\r
+G2 DC\r
+G2 DC\r
+AD2 DC\r
+G2 DC\r
+G2 DC\r
+AD2 DC\r
+G2 DC\r
+G2 DC\r
+F2 DC\r
+D2 DC\r
+F2 DC\r
+D2 DC\r
+AD2 DC\r
+G2 DC\r
+G2 DC\r
+AD2 DC\r
+G2 DC\r
+G2 DC\r
+AD2 DC\r
+G2 DC\r
+G2 DC\r
+AD2 DC\r
+G2 DC\r
+G2 DC\r
+AD2 DC\r
+G2 DC\r
+C3 DC\r
+G2 DC\r
+CD3 DC\r
+G2 DC\r
+C3 DC\r
+G2 DC\r
+AD2 DC\r
+G2 DC\r
+G2 DC\r
+AD2 DC\r
+G2 DC\r
+G2 DC\r
+D2 DC\r
+D2 DC\r
+G2 DC\r
+D2 DC\r
+F2 DC\r
+D2 DC\r
+AD2 DC\r
+G2 DC\r
+G2 DC\r
+AD2 DC\r
+G2 DC\r
+G2 DC\r
+AD2 DC\r
+G2 DC\r
+G2 DC\r
+AD2 DC\r
+G2 DC\r
+G2 DC\r
+AD2 DC\r
+G2 DC\r
+C3 DC\r
+G2 DC\r
+AD2 DC\r
+G2 DC\r
+G2 DC\r
+AD2 DC\r
+G2 DC\r
+G2 DC\r
+AD2 DC\r
+G2 DC\r
+G2 DC\r
+AD2 DC\r
+G2 DC\r
+G2 DC\r
+F2 DC\r
+D2 DC\r
+F2 DC\r
+D2 DC\r
+AD2 DC\r
+G2 DC\r
+G2 DC\r
+AD2 DC\r
+G2 DC\r
+G2 DC\r
+AD2 DC\r
+G2 DC\r
+G2 DC\r
+AD2 DC\r
+G2 DC\r
+G2 DC\r
+AD2 DC\r
+G2 DC\r
+C3 DC\r
+G2 DC\r
+G3 DC\r
+D3 DC\r
+F3 DC\r
+C3 DC\r
+AD2 DC\r
+G2 DC\r
+C3 DC\r
+G2 DC\r
+C3 DC\r
+AD2 DC\r
+G2 DC\r
+F2 DC\r
+D2 DC\r
+C2 DC\r
+AD1 DC\r
+G1 DC\r
+\r
+F1 CP\r
+G1 NP\r
+G1 DC\r
+F1 CP\r
+G1 CP\r
+AD1 NP\r
+F1 CP\r
+G1 NP\r
+G1 DC\r
+E1 B\r
+F1 B\r
+F1 CP\r
+G1 NP\r
+G1 DC\r
+F1 CP\r
+G1 CP\r
+C2 NP\r
+AD1 B\r
+C2 B\r
+DD B\r
+FD B\r
+\r
+\r
+F1 DC\r
+G1 DC\r
+G1 DC\r
+G1 DC\r
+G1 DC\r
+G1 DC\r
+G1 CP\r
+G1 DC\r
+P DC\r
+G1 DC\r
+G1 N\r
+\r
+F1 DC\r
+G1 DC\r
+G1 DC\r
+G1 DC\r
+G1 DC\r
+G1 DC\r
+AD1 N\r
+B1 DC\r
+B1 DC\r
+C2 C\r
+D2 C\r
+\r
+F1 DC\r
+G1 DC\r
+G1 DC\r
+G1 DC\r
+G1 DC\r
+G1 DC\r
+G1 CP\r
+G1 DC\r
+P DC\r
+G1 DC\r
+G1 N\r
+\r
+F1 DC\r
+G1 DC\r
+G1 DC\r
+G1 DC\r
+G1 DC\r
+G1 DC\r
+AD1 N\r
+B1 DC\r
+B1 DC\r
+C2 C\r
+AD1 C\r
+\r
+F1 DC\r
+G1 DC\r
+G1 DC\r
+G1 DC\r
+G1 DC\r
+G1 DC\r
+G1 CP\r
+G1 DC\r
+P DC\r
+G1 DC\r
+G1 N\r
+\r
+F1 DC\r
+G1 DC\r
+G1 DC\r
+G1 DC\r
+G1 DC\r
+G1 DC\r
+AD1 N\r
+B1 DC\r
+B1 DC\r
+C2 C\r
+D2 C\r
+\r
+F1 DC\r
+G1 DC\r
+G1 DC\r
+G1 DC\r
+G1 DC\r
+G1 DC\r
+G1 CP\r
+G1 DC\r
+P DC\r
+G1 DC\r
+G1 N\r
+\r
+F1 DC\r
+G1 DC\r
+G1 DC\r
+G1 DC\r
+G1 DC\r
+G1 DC\r
+AD1 N\r
+B1 DC\r
+B1 DC\r
+C2 C\r
+AD1 C\r
+\r
+F1 DC\r
+G1 DC\r
+G1 DC\r
+G1 DC\r
+G1 DC\r
+G1 DC\r
+AD1 N\r
+B1 DC\r
+B1 DC\r
+C2 C\r
+D2 C\r
+\r
+F1 DC\r
+G1 DC\r
+G1 DC\r
+G1 DC\r
+G1 DC\r
+G1 DC\r
+AD1 N\r
+B1 DC\r
+B1 DC\r
+C2 C\r
+D2 C\r
+\r
+F1 DC\r
+G1 DC\r
+G1 DC\r
+G1 DC\r
+G1 DC\r
+G1 DC\r
+AD1 N\r
+B1 DC\r
+B1 DC\r
+C2 C\r
+D2 C\r
+\r
+F1 DC\r
+G1 DC\r
+G1 DC\r
+G1 DC\r
+G1 DC\r
+G1 DC\r
+AD1 N\r
+B1 DC\r
+B1 DC\r
+C2 C\r
+D2 C\r
+\r
+F3 DC\r
+G3 DC\r
+G3 DC\r
+G3 CP\r
+AD3 CP\r
+G3 DC\r
+AD3 DC\r
+G3 DC\r
+C4 DC\r
+G3 DC\r
+D4 DC\r
+G3 DC\r
+\r
+F3 DC\r
+G3 DC\r
+G3 DC\r
+G3 CP\r
+AD3 CP\r
+G3 DC\r
+C4 DC\r
+G3 DC\r
+AD3 DC\r
+G3 DC\r
+F3 DC\r
+D3 DC\r
+\r
+F3 DC\r
+G3 DC\r
+G3 DC\r
+G3 CP\r
+AD3 CP\r
+G3 DC\r
+AD3 DC\r
+G3 DC\r
+C4 DC\r
+G3 DC\r
+D4 DC\r
+G3 DC\r
+\r
+G4 DC\r
+D4 DC\r
+F4 DC\r
+C4 DC\r
+D4 DC\r
+C4 DC\r
+AD3 DC\r
+C4 C\r
+G3 DC\r
+CD4 DC\r
+G3 DC\r
+C4 DC\r
+AD3 DC\r
+G3 DC\r
+F3 DC\r
+\r
+F3 DC\r
+G3 DC\r
+G3 DC\r
+G3 CP\r
+AD3 CP\r
+G3 DC\r
+AD3 DC\r
+G3 DC\r
+C4 DC\r
+G3 DC\r
+D4 DC\r
+G3 DC\r
+\r
+F3 DC\r
+G3 DC\r
+G3 DC\r
+G3 CP\r
+AD3 CP\r
+G3 DC\r
+C4 DC\r
+G3 DC\r
+AD3 DC\r
+G3 DC\r
+F3 DC\r
+D3 DC\r
+\r
+D3 DC\r
+G3 DC\r
+G3 DC\r
+G3 CP\r
+AD3 CP\r
+G3 DC\r
+AD3 DC\r
+G3 DC\r
+C4 DC\r
+G3 DC\r
+D4 DC\r
+C4 DC\r
+\r
+G4 DC\r
+D4 DC\r
+F4 DC\r
+C4 DC\r
+D4 DC\r
+C4 C\r
+AD3 DC\r
+C4 DC\r
+G3 DC\r
+CD4 DC\r
+G3 DC\r
+C4 DC\r
+AD3 DC\r
+G3 DC\r
+F3 DC\r
+\r
+F1 N\r
+G1 R
\ No newline at end of file
--- /dev/null
+#ifndef _DEF_
+ #define _DEF_
+
+ #define TAILLE_STR 128
+ #define NB_LECT_MAX 3
+ #define MAX_TABLES 20
+ #define MAX_CHAMPS 7
+
+ #define CONNECTE 1
+ #define DECONNECTE 0
+
+ #define TUBE_CONNEXION "TubeConnexion"
+ #define LISTE_PASS "pwl"
+ #define LOG_FILE "log"
+
+ #define PROMPT "\n@xx}:::> "
+ #define CLE "e£$r*µ%t?"
+ #define MP_SERV "e£LlkQRhyFDuc"
+#endif
--- /dev/null
+#include "exc.h"
+
+//*********************************************************************************************
+//code
+//*********************************************************************************************
+int main (void)
+{
+ FILE * requete;
+ FILE * reponse;
+
+ int fd;
+
+ char tuberep[TAILLE_STR];
+ char *tubereq;
+ char rep[TAILLE_STR];
+ char login[TAILLE_STR];
+ char mp[TAILLE_STR];
+ char req[TAILLE_STR];
+
+ pthread_t aff_rep;
+ aff_rep_t params;
+
+ //demande le login
+ fprintf (stdout, "Login : ");
+ if (fgets (login, TAILLE_STR, stdin) == NULL)
+ exit(0);
+ if (login [strlen (login) - 1] == '\n')
+ login [strlen (login) - 1] = '\0';
+
+ //demande le mot de passe
+ fprintf (stdout, "Mot de passe : ");
+ if (fgets (mp, TAILLE_STR, stdin) == NULL)
+ exit(0);
+
+ //détermine le nom du tube de réponse
+ //c'est celui dans lequel il recevra la réponse de connexion et
+ //les réponses à ses requêtes
+ sprintf (tuberep, "Client.%u", getpid());
+
+ //crée le tube de réponse
+ if (mkfifo (tuberep, 0666) != 0)
+ {
+ fprintf (stderr, "Impossible de créer le tube\n");
+ exit (1);
+ }
+
+ //ouvre le tube de connexion en écriture
+ if ((fd = open (TUBE_CONNEXION, O_WRONLY)) < 0)
+ {
+ perror ("Impossible d'ouvrir le tube de connexion");
+ unlink(tuberep);
+ exit (1);
+ }
+ requete = fdopen (fd, "w");
+
+ //envoie la demande de connexion
+ fprintf (requete, "%s\n%s\n%s", tuberep, login, mp);
+ //ferme le tube
+ fclose (requete);
+
+ //ouvre le tube de réponse en lecture
+ if ((fd = open (tuberep, O_RDONLY)) < 0)
+ {
+ perror ("Impossible d'ouvrir le tube de réponse");
+ exit (1);
+ }
+ reponse = fdopen (fd, "r");
+
+ //lit la réponse
+ if (fgets (rep, TAILLE_STR, reponse) == NULL)
+ {
+ perror ("fgets");
+ fclose(reponse);
+ unlink(tuberep);
+ return(0);
+ }
+ //ferme le tube
+ fclose(reponse);
+ //enlève l'éventuel caractère le fin de ligne
+ if (rep [strlen (rep) - 1] == '\n')
+ rep [strlen (rep) - 1] = '\0';
+
+ //quitte si le mot de passe n'est pas bon
+ if (strcasecmp(rep,"non") == 0)
+ {
+ fprintf (stdout, "Login ou mot de passe incorrect\n");
+ unlink(tuberep);
+ return(0);
+ }
+
+ //si c'est bon, la réponse c'est le nom du tube de requêtes
+ //c'est le tube par lequel le client va envoyer les requêtes
+ tubereq = strdup(rep);
+ //connecté
+
+ //Message Perso
+ fprintf(stdout,"\n********************************************************************************\n");
+ fprintf(stdout,"Vous êtes connecté au serveur NSQL- de eXs\n");
+ fprintf(stdout,"\n ______\n");
+ fprintf(stdout," X X /||||||\\\n");
+ fprintf(stdout," eee X X cccc /\\' \"\" '/\\\n");
+ fprintf(stdout," e e X X c |\\-- --/|\n");
+ fprintf(stdout," eeeeee X c F| o o |\n");
+ fprintf(stdout," e X X c || | |\n");
+ fprintf(stdout," eeee X X cccc L\\ _| /\\\n");
+ fprintf(stdout," X X //|\\ --- /|\\\\\n");
+ fprintf(stdout," ||||\\___/||||\n");
+ fprintf(stdout,"Par TOM compilé le ");
+ fprintf(stdout, __DATE__);
+ fprintf(stdout, " à ");
+ fprintf(stdout, __TIME__);
+ fprintf(stdout,"********************************************************************************\n");
+
+ //lance la thread qui reçoit les résultats et les affiche
+ params.tube = strdup(tuberep);
+ params.login = strdup(login);
+ pthread_create(&aff_rep, NULL,affiche_reponses, (void *)¶ms);
+
+ //boucle dans laquelle on lit la ligne de commande
+ while(1)
+ {
+ //affichage du prompt
+ fprintf(stdout,"%s =# ", login);
+
+ //lecture de la requête à partir de l'entrée standard
+ if (fgets(req, TAILLE_STR, stdin) == NULL)
+ perror("Problème de lecture de la requête");
+
+ //ouverture du tube de requetes
+ if ((fd = open (tubereq, O_WRONLY)) < 0)
+ {
+ fprintf (stdout,"Le serveur est fermé\n Déconnexion...\n");
+ break;
+ }
+ requete = fdopen (fd, "w");
+
+ //ecriture dans le tube de requetes
+ fprintf(requete, "%s", req);
+ //fermeture du tube
+ fclose(requete);
+
+ if(strcmp(req,"DISCONNECT\n") == 0)
+ {
+ pthread_join(&aff_rep, NULL);
+ break;
+ }
+
+ }
+
+ //destruction du tube de reponses
+ unlink (tuberep);
+ //libération de la chaîne
+ free(tubereq);
+ return (0);
+}
+
+void *affiche_reponses(void *tube)
+{
+ FILE *reponse;
+
+ int fd;
+
+ char *tuberep;
+ char *login;
+ char rep[TAILLE_STR];
+
+ //récupération du nom du tube et du login
+ tuberep = strdup(((aff_rep_t *) tube)->tube);
+ login = strdup(((aff_rep_t *) tube)->login);
+
+ //ouverture du tube de reponsesen lecture/écriture
+ if ((fd = open (tuberep, O_RDWR)) < 0)
+ {
+ perror ("Impossible d'ouvrir le tube de réponse : déconnectez vous");
+ pthread_exit ((void *)NULL);
+ }
+ reponse = fdopen (fd, "r");
+
+ //boucle dans laquelle on va regarder dans le tube de réponse
+ while(1)
+ {
+ //lecture de la réponse
+ if (fgets(rep, TAILLE_STR, reponse) == NULL)
+ {
+ perror("Impossible de lire dans le tube de réponse");
+ break;
+ }
+
+ //si la requête était DISCONNECT on quitte la thread
+ if(strcmp(rep,"FIN\n") == 0)
+ break;
+
+ //affiche la réponse
+ fprintf(stdout, "%s", rep);
+
+ //affichage du prompt
+ fprintf(stdout,"%s =# ", login);
+ //force l'affichage
+ fflush(stdout);
+ }
+
+ //Confirme la déconnexion
+ fprintf(stdout,"Déconnecté\n");
+
+ //ferme le tube de réponse
+ fclose (reponse);
+
+ //libère les pointeurs
+ free(login);
+ free(tuberep);
+
+ //quitte -->la fonction main peut continuer après le pthread_join
+ pthread_exit((void *)NULL);
+}
--- /dev/null
+//*********************************************************************************************
+//includes
+//*********************************************************************************************
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+//*********************************************************************************************
+//defines
+//*********************************************************************************************
+#define TAILLE_STR 128
+#define TUBE_CONNEXION "TubeConnexion"
+//*********************************************************************************************
+//types
+//*********************************************************************************************
+typedef struct
+ {
+ char *tube;
+ char *login;
+ }aff_rep_t;
+
+//*********************************************************************************************
+//fonctions
+//*********************************************************************************************
+void *affiche_reponses(void *);
--- /dev/null
+#include "exs.h"
+
+//*********************************************************************************************
+//Programme
+//*********************************************************************************************
+
+//*********************************************************************************************
+//fonction principale : Meta Serveur
+//lance une thread qui va écouter le tube de connexion et gère la ligne de commande servant à
+//gérer les mots de passe
+//*********************************************************************************************
+int main (void)
+{
+ FILE *deconnexion; //flux sur le tube de connexion
+ FILE *logs; //flus sur le fichier de logs (connexions)
+ int fd; //descripteur de fichiers
+
+ char *ligne;
+ char *login;
+ char *mp;
+ char *vlogin;
+ char *crlogin;
+ char *crmp;
+ char *type_requete;
+ char *tube;
+
+ int position;
+
+ pthread_t ana_connect;
+
+ //allocation des chaînes
+ if ((ligne = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL)
+ {
+ fprintf (stderr,"Problème d'allocation mémoire\n");
+ exit(1);
+ }
+ if ((login = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL)
+ {
+ fprintf (stderr,"Problème d'allocation mémoire\n");
+ exit(1);
+ }
+ if ((mp = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL)
+ {
+ fprintf (stderr,"Problème d'allocation mémoire\n");
+ exit(1);
+ }
+ if ((type_requete = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL)
+ {
+ fprintf (stderr,"Problème d'allocation mémoire\n");
+ exit(1);
+ }
+ if ((vlogin = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL)
+ {
+ fprintf (stderr,"Problème d'allocation mémoire\n");
+ exit(1);
+ }
+ if ((tube = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL)
+ {
+ fprintf (stderr,"Problème d'allocation mémoire\n");
+ exit(1);
+ }
+
+ //lancement de la requête qui va écouter le tube de connexion
+ pthread_create (&ana_connect, NULL, ana_connexions, NULL);
+
+ //Message Perso
+ fprintf(stdout,"\n********************************************************************************\n");
+ fprintf(stdout,"eXs : Serveur NSQL- activé\n");
+ fprintf(stdout,"\n ______\n");
+ fprintf(stdout," X X /||||||\\\n");
+ fprintf(stdout," eee X X ssss /\\' \"\" '/\\\n");
+ fprintf(stdout," e e X X s |\\-- --/|\n");
+ fprintf(stdout," eeeeee X s F| o o |\n");
+ fprintf(stdout," e X X s || | |\n");
+ fprintf(stdout," eeee X X ssss L\\ _| /\\\n");
+ fprintf(stdout," X X //|\\ --- /|\\\\\n");
+ fprintf(stdout," ||||\\___/||||\n");
+ fprintf(stdout,"Par TOM compilé le ");
+ fprintf(stdout, __DATE__);
+ fprintf(stdout, " à ");
+ fprintf(stdout, __TIME__);
+ fprintf(stdout,"********************************************************************************\n");
+
+ //bocle dans laquelle on s'occupe de la ligne de commande
+ while(1)
+ {
+ //imprime le prompt
+ fprintf(stdout, PROMPT);
+
+ //lit la ligne de commande
+ if ( fgets(ligne, TAILLE_STR, stdin) == NULL )
+ {
+ //problème avec la ligne de commande
+ fprintf(stderr,"Impossible de lire la commande\n");
+ continue;
+ }
+
+ //cherche le type de requête
+ if (sscanf(ligne, "%s %n", type_requete, &position) !=1)
+ {
+ //aucune commande n'a été tapée
+ fprintf(stderr,"Tapez une commande SVP\n");
+ continue;
+ }
+
+ //si c'est un DISCONNECT
+ if (strcmp(type_requete,"DISCONNECT")==0)
+ {
+ //mise à jour de la valeur servok => le meta serveur sort de sa boucle
+ fprintf(stdout,"Déconnection\n");
+ pthread_cancel(ana_connect);
+ break;
+ }
+
+ //ajour d'un client
+ else if (strcmp(type_requete,"ADD")==0)
+ {
+ //analyse des arguments de la requête
+ if (sscanf(&(ligne[position]), "%s %s", login, mp) != 2)
+ {
+ fprintf(stderr,"Utilisation : ADD <login> <mot de passe>\n");
+ continue;
+ }
+ //enlève les éventuels caractères de fin de ligne
+ if (login[strlen(login) - 1] == '\n')
+ login[strlen(login) - 1] = '\0';
+ if (mp[strlen(mp) - 1] == '\n')
+ mp[strlen(mp) - 1] = '\0';
+
+ //crypte le login et le mot de passe
+ crlogin = strdup(crypt(login,CLE));
+ crmp = strdup(crypt(mp,CLE));
+
+ //insertion du client
+ if (inserermp (crlogin, crmp, LISTE_PASS) == 1)
+ {
+ //crée le fichier de la liste des tables du client
+ sprintf(ligne,"%s.tables",login);
+ if (mknod(ligne,0666|S_IFREG,0) == -1)
+ fprintf(stderr,"Erreur lors de la création de la table des tables du client %s\n", login);
+ else
+ {
+ //crée le fichier contenant les tables du client
+ sprintf(ligne,"%s.data",ligne);
+ if (mknod(ligne,0666|S_IFREG,0) == -1)
+ fprintf(stderr,"Erreur lors de la création du fichier de données du client %s\n", login);
+ else
+ fprintf(stdout,"Client %s inséré\n", login);
+ }
+ }
+ else
+ fprintf(stderr,"Erreur lors de l'insertion du client %s\n", login);
+ }
+
+ //supprime un client de la liste
+ else if (strcmp(type_requete,"SUPPR")==0)
+ {
+ //analyse des arguments de la requête
+ if (sscanf(&(ligne[position]), "%s", login) != 1)
+ {
+ fprintf(stderr,"Utilisation : SUPPR <login>\n");
+ continue;
+ }
+ //enlève les éventuels caractères de fin de ligne
+ if (login[strlen(login) - 1] == '\n')
+ login[strlen(login) - 1] = '\0';
+ //crypte le login
+ crlogin = strdup(crypt(login,CLE));
+ //suppression du client
+ if (supprimermp (crlogin, LISTE_PASS) == 1)
+ {
+ //supprime le fichier des tables du client
+ sprintf(ligne,"%s.tables",login);
+ unlink(ligne);
+ //supprime la liste des tables du client
+ sprintf(ligne,"%s.data",ligne);
+ unlink(ligne);
+ fprintf(stdout,"Client %s supprimé\n", login);
+ }
+ else
+ fprintf(stderr,"Erreur lors de la suppression du client %s (client probablement inexistant)\n", login);
+ }
+
+ //Modification du mot de passe
+ else if (strcmp(type_requete,"CHPW")==0)
+ {
+ //lit le login et le mot de passe
+ if (sscanf(&(ligne[position]), "%s %s", login, mp) != 2)
+ {
+ fprintf(stderr,"Utilisation : CHPW <login> <nouveau mot de passe>\n");
+ continue;
+ }
+ //enlève les éventuels caractères de fin de ligne
+ if (login[strlen(login) - 1] == '\n')
+ login[strlen(login) - 1] = '\0';
+ if (mp[strlen(mp) - 1] == '\n')
+ mp[strlen(mp) - 1] = '\0';
+
+ //crypte le login et le mot de passe
+ crlogin = strdup(crypt(login,CLE));
+ crmp = strdup(crypt(mp,CLE));
+
+ //suppression puis insertion du client --> modifie le mot de passe
+ if (supprimermp (crlogin, LISTE_PASS) == 1)
+ if (inserermp (crlogin, crmp, LISTE_PASS) == 1)
+ fprintf(stdout,"Changement du mot de passe du client %s\n", login);
+ else
+ fprintf(stderr,"Erreur lors de la modification du mot de passe du client %s\n", login);
+ else
+ fprintf(stderr,"Erreur lors de la modification du mot de passe du client %s (client probablement inexistant)\n", login);
+ }
+
+ //Crypte la chaine en argument
+ //Pas important
+ else if (strcmp(type_requete,"CRYPT")==0)
+ {
+ if (sscanf(&(ligne[position]), "%s", login) != 1)
+ {
+ fprintf(stderr,"Utilisation : CRYPT <mot>\n");
+ continue;
+ }
+ //enlève l'éventuel caractère de fin de ligne
+ if (login[strlen(login) - 1] == '\n')
+ login[strlen(login) - 1] = '\0';
+ //suppression puis insertion du client
+ crlogin = strdup(crypt(login,CLE)); //duplication du login
+ fprintf(stderr,"%s\n", crlogin);
+ }
+
+ //Bloque la ligne de commande tant que le mot de passe n'est pas bon
+ else if (strcmp(type_requete,"BLOCK") == 0)
+ {
+ fprintf(stdout,"Ligne de commande bloquée\n");
+ //boucle
+ do
+ {
+ //demande le mot de passe
+ fprintf(stdout,"Mot de passe : ");
+ fflush(stdout);
+ if (fgets (mp, TAILLE_STR, stdin) == NULL)
+ exit(0);
+ //enlève l'éventuel caractère de fin de ligne
+ if (mp [strlen (login) - 1] == '\n')
+ mp [strlen (login) - 1] = '\0';
+
+ //crypte le motde passe
+ crmp = strdup(crypt(mp,CLE)); //duplication du login
+ }//boucle tant que le mot de passe n'est pas celui défini dans defines.h
+ while(strcmp(crmp, MP_SERV) != 0);
+
+ //la ligne de commande est débloquée
+ fprintf(stdout,"Ligne de commande débloquée\n");
+ }
+
+ //Affiche le dernier log du client
+ //je l'ai juste fait à titre d'exercice sur les flux
+ //mais au niveau administrateur ça peut avoir une utilité
+ else if (strcmp(type_requete,"LAST") == 0)
+ {
+ if (sscanf(&(ligne[position]), "%s", login) != 1)
+ {
+ fprintf(stderr,"Utilisation : LAST <login>\n");
+ continue;
+ }
+ //enlève l'éventuel caractère de fin de ligne
+ if (login[strlen(login) - 1] == '\n')
+ login[strlen(login) - 1] = '\0';
+ //ouvre le fichier de logs en lecture
+ if ((logs = fopen(LOG_FILE, "r")) == NULL)
+ {
+ fprintf (stderr,"Problème à l'ouverture du fichiers de login\n");
+ exit(0);
+ }
+ //lit une ligne du fichier de logs
+ while (fgets(ligne, TAILLE_STR, logs) != NULL)
+ //on lit le premier mot de la ligne : c'est le login
+ if (sscanf(ligne, "%s %*n", vlogin) == 1)
+ {
+ //si le login correspond à celui du début dela ligneon le mémorise
+ if (strcmp(vlogin,login) == 0)
+ mp = strdup(ligne);
+ }
+ else break;
+ //affiche la dernière ligne dont le login ést celui qui étati passé en argument
+ fprintf(stdout, "%s", mp);
+ //fermeture du fichier de log
+ fclose (logs);
+ }
+
+ //Affiche tous les logs du client
+ //il y a juste une petite modification par rapport à la précédente
+ else if (strcmp(type_requete,"LOGS") == 0)
+ {
+ if (sscanf(&(ligne[position]), "%s", login) != 1)
+ {
+ fprintf(stderr,"Utilisation : LOGS <login>\n");
+ continue;
+ }
+ //enlève les éventuels caractères de fin de ligne
+ if (login[strlen(login) - 1] == '\n')
+ login[strlen(login) - 1] = '\0';
+ //ouvre le fichier de logs en lecture
+ if ((logs = fopen(LOG_FILE, "r")) == NULL)
+ {
+ fprintf (stderr,"Problème à l'ouverture du fichiers de login\n");
+ exit(0);
+ }
+ //lit une ligne du fichier
+ while (fgets(ligne, TAILLE_STR, logs) != NULL)
+ //mémorise le login qui est en début de ligne
+ if (sscanf(ligne, "%s %*n", vlogin) == 1)
+ {
+ //si le login est celui en argument...
+ if (strcmp(vlogin,login) == 0)
+ //... on affiche la ligne
+ fprintf(stdout, "%s", ligne);
+ }
+ else break;
+ //fermeture du fichier de log
+ fclose (logs);
+ }
+
+ //Déconnecte le client
+ //pas sur que ça marche
+ //c'est resté au stade expérimental. C'était pas une priorité, j'ai fait ça quand je
+ //me donnais une pause. pfiouuu c'est laborieux ... :-)
+ else if (strcmp(type_requete,"KILL") == 0)
+ {
+ if (sscanf(&(ligne[position]), "%s", login) != 1)
+ {
+ fprintf(stderr,"Utilisation : KILL <login>\n");
+ continue;
+ }
+ //enlève les éventuels caractères de fin de ligne
+ if (login[strlen(login) - 1] == '\n')
+ login[strlen(login) - 1] = '\0';
+ //ouvre le fichier de logs en lecture
+ if ((logs = fopen(LOG_FILE, "r")) == NULL)
+ {
+ fprintf (stderr,"Problème à l'ouverture du fichiers de login\n");
+ exit(0);
+ }
+ //cherche la dernière connexion du client
+ while (fgets(ligne, TAILLE_STR, logs) != NULL)
+ {
+ //prend le login et le nom du tube de requêtes du client à déconnecter
+ if (sscanf(ligne, "%s %*s %*s %*s %*s %s", vlogin, tube) == 2)
+ {
+ //si le login est le bon on mémorise le nom du tube
+ if (strcmp(vlogin,login) == 0)
+ mp = strdup(tube);
+ }
+ else break;
+ }
+ //fermeture du fichier de log
+ fclose (logs);
+ //envoie le message de déconnexion au serveur => celui ci va en théorie faire
+ //quitter le client. J'ai pas cherché à débugger ce truc. J'avais d'autres choses
+ //à faire dans ce programme ...
+ if (mp[strlen(mp) - 1] == '\n')
+ mp[strlen(mp) - 1] = '\0';
+ if ((deconnexion = fopen(mp, "w")) == NULL)
+ fprintf (stdout,"Le client n'est plus connecté\n");
+ else fprintf(deconnexion, "DISCONNECT\n");
+ //Rq : quel feinteur ce Meta Serveur ... il se fait passer pour le client :-)
+ }
+
+ //Aide
+ //ça sert pour le gars qui va copier le logiciel à la place de l'acheter. Au moins il saura s'en servir sans
+ //avoir la doc.
+ //d'un côté qui va acheter ça ? cça sera même pas en vente.
+ else if ((strcmp(type_requete,"?") == 0)||(strcmp(type_requete,"HELP") == 0))
+ {
+ //affichage des commandes possibles
+ fprintf(stdout,"ADD <login> <mot de passe> : ajoute un client\nSUPPR <login> : supprime un client\nCHPW <login> <nouveau mot de passe> : change le mot de passe\nCRYPT <mot> : crypte le mot et l'affiche\nLAST <login> : affiche la dernière connexion du client\nLOGS <login> : affiche toutes les connexions du client\nKILL <login> : déconnecte un client\nDISCONNECT : déconnecte le serveur\n? ou HELP : affiche les commandes\n");
+ }
+
+ //L'utilisateur a tapé nimp
+ //on reste quand même gentil avec lui. Si j'avais eu le temps j'aurais pu
+ //mettre un truc sympa à ce niveau là. Genre un générateur de messages avec un tableau de messages
+ //et un tirage aléatoire du message à afficher. Mais bon...
+ else
+ {
+ fprintf(stderr,"Commande inconnue\n");
+ continue;
+ }
+
+ position = 0;
+
+ }
+
+ //ferme la thread d'analyse de connexion de façon à ce qu'elle finisse son travail
+
+ //ouvre le tube de connexion
+ if ((fd = open (TUBE_CONNEXION, O_WRONLY)) < 0)
+ fprintf (stderr, "Tube déjà supprimé\n");
+ else
+ {
+ if ((deconnexion = fdopen (fd, "w")) == NULL)
+ perror("Ouverture du tube de connexion");
+ else
+ {
+ //envoi du message de fin à la requête d'analyse des demandes de connexions
+ fprintf (deconnexion, "FIN\nFIN\nFIN\n");
+ //ferme le tube
+ fclose(deconnexion);
+ }
+ }
+
+ //libération des chaînes (mais pas des esclaves :-(
+ //désolé mais je ne suis pas venu ici pour affranchir les esclaves
+ // Qui Gon Jinn (Star Wars Episode I : La Menace Fantôme)
+ free (ligne);
+ free (login);
+ free (mp);
+ free (type_requete);
+
+ //destruction du tube de connection
+ unlink(tubeconnexion);
+
+ return(0);
+}
+
+//*********************************************************************************************
+//vérification du mot de passe
+//cette thread reçoit le login et le mot de passe crypté et va vérifier si le client peut se connecter
+//*********************************************************************************************
+void * verif (void * params)
+{
+ FILE *reponse;
+ int fd;
+ char tuberequetes[TAILLE_STR];
+
+ int rep;
+
+ verif_pw_t * v_pw;
+
+ if ((v_pw = (verif_pw_t *) malloc (sizeof(verif_pw_t))) == NULL)
+ {
+ fprintf (stderr,"Problème d'allocation mémoire\n");
+ pthread_exit(NULL);
+ }
+
+ //récupération des paramètres de la thread
+ v_pw = (verif_pw_t *)params;
+
+ //vérifie le login et le mot de passe
+ rep = verifier ( strdup(crypt(v_pw->login, CLE)) , strdup(crypt(v_pw->mp, CLE)) );
+
+ //ouverture du tube de réponse
+ if ((fd = open (v_pw->tuberep, O_WRONLY)) < 0)
+ {
+ perror("Impossible d'ouvrir le rube de reponse");
+ pthread_exit(NULL);
+ }
+ reponse = fdopen (fd, "w");
+
+ //si le client n'est pas autorisé à se connecter
+ if (rep == DECONNECTE)
+ {
+ //envoi du message négatif
+ fprintf(reponse, "non\n");
+ //fermeture du tube de réponse
+ fclose (reponse);
+ }
+ else //rep == CONNECTE
+ {
+ //recopiage du nom du tube et création de celui-ci
+ sprintf( tuberequetes, "%s.R", v_pw->tuberep);
+ //creation du tube de requetes
+ if (mkfifo (tuberequetes, 0666) != 0)
+ {
+ fprintf (stderr, "Impossible de créer le tube\n");
+ exit (1);
+ }
+
+ //crée le serveur dédié
+ switch(fork())
+ {
+ case -1 : //y'a eu un binz... merde
+ fprintf(stderr, "Erreur à la création du Serveur dédié\n");
+ fprintf(reponse, "non\n"); //désolé mais y'a pas moyen
+ fclose(reponse);
+ unlink(tuberequetes);
+ case 0 : //tout va bien, ça roule Raoul
+ //lancement de la procédure du serveur dédié
+ serveurdedie(v_pw->tuberep, tuberequetes, v_pw->login);
+ //quitte la thread après avoir effectué le travail
+ pthread_exit(NULL);
+ }
+ }
+ //le processus père (la thread) peut finir tranquillement
+ pthread_exit(NULL);
+}
+
+//*********************************************************************************************
+//fonction qui vérifie le login et le mot de passe
+//le login et le mot de passe sont cryptés, comme ceux dans la liste
+//"liste" pasée dans la structure paramètre.
+//*********************************************************************************************
+int verifier (char * login, char * mp)
+{
+ FILE *liste;
+
+ char *vl; //login de la liste \_ ceux auxquels on va comparer
+ char *vmp; //mot de passe de la liste / celui en paramètres
+
+ int rep = DECONNECTE; //état du client
+ int filedes;
+
+ //allocation des chaines de login, mp
+ if ((vl = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL)
+ { fprintf (stderr,"Problème d'allocation mémoire\n");
+ exit(1);
+ }
+
+ if ((vmp = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL)
+ {
+ fprintf (stderr,"Problème d'allocation mémoire\n");
+ exit(1);
+ }
+
+ //ouvre le fichier de mots de passe (cryptés)
+ if ((filedes = open(LISTE_PASS,O_RDONLY)) < 0)
+ {
+ fprintf (stderr,"Problème à l'ouverture du fichier de mots de passe\n");
+ exit(0);
+ }
+ //ouverture du flux sur le fichier de mots de passe
+ if ((liste = fdopen(filedes, "r")) == NULL)
+ {
+ fprintf (stderr,"Problème à l'ouverture du descripteur de fichiers de mots de passe\n");
+ close(filedes);
+ exit(0);
+ }
+
+ //lecture du fichier des mots de passe ligne par ligne
+ while ( fscanf(liste, "%s %s",vl,vmp) == 2)
+ {
+ //si le login est bon il faut vérifier le mot de passe
+ if ( strcmp(login, vl) == 0 )
+ //si le mot de passe est bon on marque le client comme connecté
+ if ( strcmp(mp, vmp) == 0)
+ {
+ fprintf (stdout,"Mot de passe OK\n");
+ rep = CONNECTE;
+ break;
+ }
+ //sinon ça sert à rien de chercher dans la suite de la liste
+ else
+ {
+ rep = DECONNECTE;
+ break;
+ }
+ }
+ //fermeture du fichier de mots de passe
+ fclose (liste);
+
+ //libère les pointeurs : ouaaaaaais
+ free(vl);
+ free(vmp);
+
+ //on renvoie la réponse... ça peut servir ...
+ return (rep);
+}
+
+//**************************************************************************************
+//ANA_CONNECTION
+//cette thread crée le tube de connexion et l'écoute en boucle jusqu'à ce que le Meta Serveur lui dit d'arrêter
+//*************************************************************************************
+void * ana_connexions (void * inutile)
+{
+ FILE * connexion;
+ int fd;
+ char tuberep[TAILLE_STR];
+ char login[TAILLE_STR];
+ char mp[TAILLE_STR];
+
+ pthread_t verif_pw;
+ verif_pw_t *v_pw;
+ //allocation de la mémoire pour les paramètres
+ if ((v_pw = (verif_pw_t *) malloc (sizeof(verif_pw_t))) == NULL)
+ {
+ fprintf (stderr,"Problème d'allocation mémoire\n");
+ pthread_exit((void *)0);
+ }
+
+ //supprime le tube de connexion au cas ou il existe déjà !!!
+ //ça arrive le plantage... Même si c'est pas censé tourner sur Windows
+ unlink(tubeconnexion);
+
+ //crée le tube de connexion
+ if (mkfifo (tubeconnexion, 0666 |O_CREAT) != 0)
+ {
+ fprintf(stderr, "Impossible de créer le tube\n");
+ exit(1);
+ }
+
+ //ouvre le tube de connexion
+ fd = open (tubeconnexion, O_RDWR);
+ if ((connexion = fdopen(fd, "r")) == NULL)
+ {
+ perror("Erreur à l'ouverture du tube\n");
+ close(fd);
+ unlink(tubeconnexion);
+ exit(1);
+ }
+
+ //on analyse les demandes de connexion
+ while (1)
+ {
+ //récupère le nom du tube de réponse
+ if (fgets (tuberep, TAILLE_STR, connexion) == NULL)
+ {
+ perror("fgets");
+ break;
+ }
+ //on enlève le caractère de fin de ligne qui fait chier
+ if (tuberep [strlen (tuberep) - 1] == '\n')
+ tuberep [strlen (tuberep) - 1] = '\0';
+
+ //récupère le login
+ if (fgets (login, TAILLE_STR, connexion) == NULL)
+ {
+ perror("fgets");
+ break;
+ }
+ //on fait comme avant
+ if (login [strlen (login) - 1] == '\n')
+ login [strlen (login) - 1] = '\0';
+
+ //récupère le mot de passe
+ if (fgets (mp, TAILLE_STR, connexion) == NULL)
+ {
+ perror("fgets");
+ break;
+ }
+ //toujours la même
+ if (mp [strlen (mp) - 1] == '\n')
+ mp [strlen (mp) - 1] = '\0';
+
+ //quitte si c'est le meta qui envoie un message d'explosion
+ if (strcasecmp (tuberep, "FIN") == 0)
+ {
+ fprintf(stdout, "quitte\n");
+ break;
+ }
+
+ //on enregistre les paramètres de la thread
+ v_pw->tuberep = strdup(tuberep);
+ v_pw->login = strdup (login);
+ v_pw->mp = strdup(mp);
+
+ fprintf(stdout, "\nVérification du mot de passe de %s\n", login);
+
+ //vérification du login et du mot de passe
+ pthread_create (&verif_pw, NULL, verif, (void *)v_pw);
+ }
+ //ferme le tube de de connexion
+ fclose(connexion);
+
+ //on quitte la thread dans les règles
+ pthread_exit (NULL);
+}
+
+//*********************************************************************************************
+//chercher : cherche "login" dans la liste des mots de passe "liste"
+//renvoie 1 si il y est et 0 sinon
+//*********************************************************************************************
+int cherchermp (const char * login, const char * liste)
+{
+ FILE *lmp;
+
+ char *vlogin; //login de la table
+ char *ligne; //ligne de la table
+
+ //ouverture du fichier
+ if ((lmp = fopen(liste, "r")) == NULL) //écriture
+ {
+ perror("ouverture du fichier de mots de passe");
+ return(0);
+ }
+
+ //allocation patati patata
+ if ((vlogin = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL)
+ {
+ fprintf (stderr,"Problème d'allocation mémoire\n");
+ return(0);
+ }
+ if ((ligne = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL)
+ {
+ fprintf (stderr,"Problème d'allocation mémoire\n");
+ return(0);
+ }
+
+ //on lit une ligne du fichier de mots de passe
+ while (fgets(ligne, TAILLE_STR, lmp) != NULL)
+ //on enregistre le login qui s'y trouve
+ if (sscanf(ligne, "%s %*s",vlogin) == 1)
+ {
+ //on le compare avec celui qui est donné en argument
+ if (strcmp(vlogin,login) == 0)
+ {
+ //c'est le bon !!!
+ //la classe
+
+ //libération de la chaîne allouée
+ free(vlogin);
+ free(ligne);
+
+ //fermeture du fichier
+ fclose(lmp);
+ //on a trouvé
+ return (1);
+ }
+ }
+ else break; //il n'y a plus rien à lire d'intéressant
+
+ //libération de la chaîne allouée
+ free(vlogin);
+ free(ligne);
+
+ //fermeture du fichier
+ fclose(lmp);
+ return (0);
+}
+
+//*********************************************************************************************
+//inserer : insère "login" avec son mot de passe "mp" dans la liste
+//de mots de passe "liste"
+//renvoie 1 si le login a été inséré et 0 sinon
+//*********************************************************************************************
+int inserermp (const char * login, const char * mp, const char * liste)
+{
+ FILE *lmp;
+ char *ligne; //ligne de la table
+
+ //allocation mémoire
+ if ((ligne = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL)
+ {
+ fprintf (stderr,"Problème d'allocation mémoire\n");
+ return(0);
+ }
+
+ //ouverture du fichier des mots de passe en ajout
+ if ((lmp = fopen(liste, "a+")) == NULL) //écriture
+ {
+ perror("ouverture du fichier de mots de passe");
+ return(0);
+ }
+
+ //vérification que le login est unique
+ if (cherchermp(login, liste) == 1)
+ {
+ fprintf(stderr, "login déjà existant\n");
+
+ //et on ferme le fichier
+ fclose(lmp);
+
+ return(0);
+ }
+
+ //insertion du nouveau login
+ fprintf(lmp, "%s %s\n",login, mp);
+ //on s'assure que ça a été rajouté
+ fflush(lmp);
+
+ //et on ferme le fichier
+ fclose(lmp);
+
+ return (1);
+}
+
+//*********************************************************************************************
+//supprimer : supprime le login "login" ainsi que le mot de passe
+//associé de la liste de mots de passe "liste"
+//retourne 1 si il n'y a pas eu d'erreurs et 0 sinon
+//*********************************************************************************************
+int supprimermp (const char * login, const char * liste)
+{
+ FILE *lmp; //liste de mots de passe
+ FILE *tmpfile; //fichier temporaire
+
+ char *tmp_login; //login temporaire
+ char *tmp_mp; //mot de passe temporaire
+ char *ligne; //ligne de la table
+ int c; //caractère temporaire pour la copie
+
+ int retour = 0;
+
+ //allocation mémoire
+ if ((ligne = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL)
+ {
+ fprintf (stderr,"Problème d'allocation mémoire\n");
+ return(0);
+ }
+
+ //allocation des chaînes
+ if ((tmp_login = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL)
+ {
+ fprintf (stderr,"Problème d'allocation mémoire\n");
+ exit(1);
+ }
+ if ((tmp_mp = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL)
+ {
+ fprintf (stderr,"Problème d'allocation mémoire\n");
+ exit(1);
+ }
+
+ //création du fichier temporaire
+ if ((tmpfile = fopen("tmpfile", "w")) == NULL)
+ {
+ perror("création du fichier temporaire");
+ return(0);
+ }
+
+ //ouverture de la liste des mots de passe lecture
+ if ((lmp = fopen(liste, "r")) == NULL)
+ {
+ perror("ouverture du fichier de mots de passe en lecture");
+ return(0);
+ }
+
+ //recherche du login a supprimer
+ while (fgets(ligne, TAILLE_STR, lmp) != NULL)
+ if (sscanf(ligne, "%s %s",tmp_login, tmp_mp) == 2)
+ { //Si ce n'est pas le bon login, rajouter la ligne au fichier temporaire
+ if (strcmp(tmp_login, login) != 0)
+ {
+ //insertion du login et du mot de passe dans le fichier temporaire
+ //car c'était pas celui à supprimer
+ fprintf(tmpfile, "%s %s\n",tmp_login, tmp_mp);
+ }
+ else
+ //sinon le login a supprimer y était on continue pour effacer les éventuels doublons
+ //cela peut arriver si quelqu'un modifie le fichier manuellement
+ retour = 1;
+ }
+ else break;
+
+ //fermeture des flux
+ fclose(lmp);
+ fclose(tmpfile);
+
+ //ouverture des flux pour la copie
+ if ((lmp = fopen(liste, "w")) == NULL)
+ {
+ perror("ouverture du fichier de mots de passe en écriture");
+ return(0);
+ }
+ if ((tmpfile = fopen("tmpfile", "r")) == NULL)
+ {
+ perror("ouverture du fichier temporaire en lecture");
+ return(0);
+ }
+
+ //copie de tmpfile dans lmp
+ while ((c = getc(tmpfile)) != EOF)
+ putc(c, lmp);
+
+ //libération des chaines
+ free(tmp_login);
+ free(tmp_mp);
+
+ //fermeture des flux
+ fclose(lmp);
+ fclose(tmpfile);
+
+ //suppression du fichier temporaire
+ unlink("tmpfile");
+
+ return retour;
+}
--- /dev/null
+#ifndef _EXS_
+ #define _EXS_
+ #include <fcntl.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include <unistd.h>
+ #include <crypt.h>
+ #include <time.h>
+ #include <pthread.h>
+ #include <sys/stat.h>
+ #include <sys/types.h>
+
+ #include "serveurdedie.h"
+ #include "defines.h"
+
+
+ //*********************************************************************************************
+ //structures de données
+ //*********************************************************************************************
+ typedef struct verif_pw //pour 'verif'
+ {
+ char *login; //login crypté
+ char *mp; //mot de passe crypté
+ const char *tuberep; //tube de réponse du client
+ }verif_pw_t;
+
+ //*********************************************************************************************
+ //fonctions
+ //*********************************************************************************************
+ void * ana_connexions (void *);
+ void * verif (void *); //verif_pw_t
+ int verifier (char *, char *); //login mp
+ int cherchermp (const char *, const char *); //login liste
+ int inserermp (const char *, const char *, const char *); //login mp liste
+ int supprimermp (const char *, const char *); //login liste
+
+ //*********************************************************************************************
+ //Variables
+ //*********************************************************************************************
+ static char * tubeconnexion = TUBE_CONNEXION;
+
+#endif
--- /dev/null
+COMP = gcc\r
+OBJ = exc.o\r
+\r
+eXc : $(OBJ)\r
+ $(COMP) -lpthread -lcrypt -o eXc $(OBJ)\r
+\r
+exc.o :\r
+ $(COMP) -c exc.c\r
--- /dev/null
+COMP = gcc
+RM = rm -f
+OBJ = exs.o verrou.o tables.o serveurdedie.o
+
+eXs : $(OBJ)
+ $(COMP) -lpthread -lcrypt -Wall -o eXs $(OBJ)
+
+nettoyage : $(OBJ)
+ $(RM) $(OBJ)
+
+exs.o : defines.h
+
+serveurdedie.o : defines.h tables.c
+
+tables.o : verrou.c
+
+verrou.o :
--- /dev/null
+make -f makefiles
+make -f makefilec
--- /dev/null
+#include "serveurdedie.h"
+
+//*********************************************************************************************
+//code du SERVEUR DEDIE
+//*********************************************************************************************
+void serveurdedie (const char *tuberep, const char *tubereq, const char *login)
+{
+ FILE *reponse;
+ FILE *requete;
+ FILE *logs;
+
+ char ligne[TAILLE_STR];
+
+ int filedes;
+
+ //variables pour les fonctions de temps
+ time_t temps;
+ struct tm *tm;
+
+ //liste des tables chargées en mémoire
+ ls_table_t *liste_tb_ch = init_liste_tb_ch();
+
+ //variable des threads (analyse des requêtes)
+ pthread_t analyse;
+ ana_req_t *params;
+
+ //allocation des paramètres de la thread
+ if ((params = (ana_req_t *) malloc (sizeof(ana_req_t))) == NULL)
+ {
+ fprintf (stderr,"Problème d'allocation mémoire\n");
+ return((void)NULL);
+ }
+ if ((params->req = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL)
+ {
+ fprintf (stderr,"Problème d'allocation mémoire\n");
+ free(params);
+ return((void)NULL);
+ }
+ if ((params->tables = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL)
+ {
+ fprintf (stderr,"Problème d'allocation mémoire\n");
+ free(params);
+ free(params->req);
+ return((void)NULL);
+ }
+
+ //ouverture du tube de réponse en écriture
+ if ((filedes = open (tuberep, O_WRONLY)) < 0)
+ {
+ perror ("Impossible d'ouvrir le tube de reponse");
+ free(params->tables);
+ free(params->req);
+ free(params);
+ return ((void)NULL);
+ }
+ reponse = fdopen (filedes, "w");
+
+ //envoi du nom du tube de réponses : c'est la réponse à la demande de connexion du client
+ fprintf (reponse, "%s\n", tubereq);
+ //ferme le tube de réponse
+ fclose (reponse);
+
+ //Ajoute les informations de la connection du client dans le fichier de logs
+
+ //ouvre le fichier de logs
+ if ((logs = fopen(LOG_FILE, "a+")) == NULL)
+ {
+ fprintf (stderr,"Problème à l'ouverture du descripteur de fichiers de mots de passe\n");
+ return((void)NULL);
+ }
+ time(&temps);
+ tm = localtime(&temps);
+ //ajoute <client> jj/mm/aa XXh XXmin XXs <tubereq>
+ fprintf(logs, "%-10s %02d/%02d/%02d %02dh %02dmin %02ds %s\n", login, tm->tm_mday, tm->tm_mon+1, tm->tm_year %100, tm->tm_hour, tm->tm_min, tm->tm_sec, tubereq);
+ //fermeture du fichier de log
+ fclose (logs);
+
+ //imprime un nouveau prompt sur la console du meta serveur
+ fprintf (stdout, PROMPT);
+ fflush(stdout);
+
+ //ouvre le tube de requêtes en lecture
+ if ((filedes = open (tubereq, O_RDONLY)) < 0)
+ {
+ perror ("Impossible d'ouvrir le tube de requetes");
+ return ((void)NULL);
+ }
+ requete = fdopen (filedes, "r");
+
+ //détermine les paramètres inchangeant de la thread
+ params->tuberep = strdup(tuberep); //nom du tube de réponse
+ params->liste = liste_tb_ch; //liste des tables chargées en mémoire
+ sprintf(params->tables,"%s.tables", login); //nom du fichier où se trouve la liste des tables
+
+ //lit le tube de requêtes en boucle
+ while(1)
+ {
+ //lecture de la requête
+ if (fgets(ligne, TAILLE_STR, requete) != NULL)
+ {
+ //si c'est une requête de déconnexion, il s'en charge lui même
+ //ça sert à rien de créer une thread pour ça parce qu'il faudra
+ //la fermer etc et puis c'est la fin alors on fait le tout pour le tout
+ if (strcmp(ligne,"DISCONNECT\n") == 0)
+ {
+ //envoi du message de fin au client
+
+ //ouvre le tube de réponse en écriture
+ if ((filedes = open (tuberep, O_WRONLY)) < 0)
+ break;
+ else
+ {
+ if ((reponse = fdopen (filedes, "w")) != NULL )
+ {
+ //envoi du message de fin.
+ fprintf(reponse,"FIN\n");
+ fclose(reponse);
+ }
+ }
+ break;
+ }
+ //détermine la ligne à analyser par la thread
+ sprintf(params->req, "%s", ligne);
+
+ //lance la thread d'analyse
+ pthread_create(&analyse, NULL, analyser, (void *)params);
+ }
+ }
+ //enregistre les tables chargées en mémoire et les décharge
+ sprintf(ligne, "%s.tables.data", login);
+ decharger_tables (liste_tb_ch, ligne);
+
+ //libère les pointeurs
+ free(params->tuberep);
+ free(params->tables);
+ free(params->req);
+ free(params);
+
+ //ferme le tube de requêtes
+ fclose(requete);
+
+ //détruit le tube : boum
+ //comme en Irak : on pète les pipelines !
+ unlink(tubereq);
+
+ //et on sort gentillement, les mains sur la tête
+ return ((void)NULL);
+}
+
+//*********************************************************************************************
+//analyse d'une requête
+//dans un premier temps la thread lit le premier mot de la requête
+//afin d'identifier son type (DISCONNECT, SELECT, CREATE, UPDATE, ...)
+//DISCONNECT n'a aucun paramètre : il sert juste à dire que le client désire se déconnecter du système
+//CREATE a un seul paramètre : le nom de la table à créer
+//SELECT a quatre paramètres : le nom du champ et le nom de la table à afficher. Ainsi que le nom du champ et
+//la valeur qu'il doit prendre pour que la ligne soit affichée
+//UPDATE sert à modifier le champ d'une table. Il y a cinq arguments le nom de la table, le champ et la valeur
+//à mettre là où champ2 = valeur2
+//*********************************************************************************************
+void *analyser (void *params)
+{
+ FILE *reponse;
+
+ char tuberep[TAILLE_STR]; //tube de réponse
+ char ligne[TAILLE_STR]; //ligne lue
+ char table[TAILLE_STR]; //paramètre table dans la requête
+ char champ[TAILLE_STR]; //paramètre champ dans la requête
+ char champ2[TAILLE_STR]; //paramètre 2e champ dans la requête
+ char valeur[TAILLE_STR]; //paramètre valeur dans la requête
+ char valeur2[TAILLE_STR]; //paramètre 2e valeur dans la requête
+ char type_requete[TAILLE_STR]; //type de requête effectuée
+
+ char c[1];
+
+ int position,position1, position2; //"curseurs" de lecture sur la ligne de la requête
+ int filedes; //descripteur de fichier
+ int tableok = 0; //booléen définissant si la table est correctement définie (pour CREATE)
+
+ table_t *tb; //table résultat
+
+ //on récupère le nom du tube de réponse et la requête
+ sprintf(tuberep,"%s",((ana_req_t *)params)->tuberep);
+ sprintf(ligne,"%s",((ana_req_t *)params)->req);
+
+ //ouverture du tube de reponse en écriture
+ if ( (filedes = open(tuberep, O_WRONLY)) < 0 )
+ {
+ fprintf (stderr,"Impossible d'écrire dans le tube de réponse %s\n", tuberep);
+ pthread_exit((void *)NULL);
+ }
+ reponse = fdopen(filedes, "w");
+
+ //Détermination du type de la requête en analysant le premier mot
+ if (sscanf(ligne, "%s %n", type_requete, &position) !=1)
+ {
+ //Aucun mot n'a été tapé
+ fprintf(reponse,"Tapez une commande SVP\n");
+ }
+
+ //CREATE
+ else if (strcmp(type_requete,"CREATE") == 0)
+ {
+ //vérification des paramètres de la commande CREATE
+ if ((sscanf(&(ligne[position]), "%s %s %n", table, c, &position1) != 2))
+ //le nombre d'arguments n'est pas bon
+ fprintf(reponse,"Utilisation : CREATE <Table> ( <champ1> <type1> , ... , <champ n> <type n> )\n");
+ else
+ {
+ //vérifie que l'utilisateur n'a pas oublié la parenthèse avant la liste des noms de champs
+ if (strcmp( c, "(") != 0)
+ //le nombre d'arguments n'est pas bon
+ fprintf(reponse,"N'oubliez pas ( avant la liste des champs\n");
+ else
+ {
+ //calcule la position du "curseur" de lecture de la chaine
+ position1 += position;
+
+ //alloue la mémoire de la nouvelle table
+ if ((tb = allouer_table (table)) == NULL)
+ fprintf(stderr,"Impossible d'allouer la table\n");
+ else
+
+ //boucle qui va lire les champs
+ while(1)
+ {
+ //lecture d'un nom de champ
+ if (sscanf(&(ligne[position1]), "%s %n", champ, &position2) != 1)
+ {
+ //le nombre d'arguments n'est pas bon
+ fprintf(reponse,"Tapez un nom de champ\n");
+ desallouer_table (tb);
+ break;
+ }
+ else
+ {
+ //calcule la position du "curseur" de lecture de la chaine
+ position2 += position1;
+
+ //lecture du type de champ (et la virgule ou la parenthèse fermante)
+ if (sscanf(&(ligne[position2]), "%s %s %n", valeur, c, &position1) != 2)
+ {
+ //le nombre d'arguments n'est pas bon
+ fprintf(reponse,"Tapez un nom de type\n");
+ desallouer_table (tb);
+ break;
+ }
+ else
+ {
+ //calcule la position du "curseur" de lecture de la chaine
+ position1 += position2;
+ //vérification du type
+ if ((strcmp(valeur,"INT") != 0 ) && (strcmp(valeur,"CHAR") != 0)) //vérifie si le type est bon
+ {
+ //le type n'est ni INT ni CHAR
+ fprintf(reponse,"Type inconnu : %s\n", valeur);
+ desallouer_table (tb);
+ break;
+ }
+ else
+ {
+ inserer_champ(tb, champ, valeur);
+ if (strcmp(c,")") == 0) //c'est la fin de la table
+ {
+ tableok = 1;
+ break;
+ }
+ else if (strcmp(c,",") != 0) //vérifie que le champ suivant vient après une virgule !
+ {
+ //le champ ne se termine pas apr une virgule
+ fprintf(reponse,"Séparez les champs par une virgule et n'oubliez pas les espaces\n");
+ desallouer_table (tb);
+ break;
+ }
+ }
+ }
+ }
+ }
+ //affiche un message si la table a bien été créée
+ if (tableok == 1)
+ {
+ //regarde si la table est en mémoire principale (l'index dans la table sera > 0 dans ce cas)
+ if (ch_table_dans_tables (tb->nom, ((ana_req_t *)params)->liste) >= 0)
+ {
+ fprintf(reponse,"la table %s existe déjà (ch)\n",table); //elle est même en mémoire !
+ desallouer_table(tb);
+ }
+ else //la table n'est pas en mémoire principale
+ {
+ //cherche la table dans la liste des tables (si elle y est la fonction retourne le nom du fichier dans lequel
+ //elle se trouve. Donc si elle existe déjà, le résultat n'est pas NULL
+ if (ch_table_dans_liste (tb->nom, ((ana_req_t *)params)->tables) != NULL)
+ {
+ fprintf(reponse,"la table %s existe déjà(fich)\n",table); //elle n'est pas chargée mais c'est pas une raison
+ desallouer_table(tb);
+ }
+ else //la table n'existe pas ==> on peut l'ajouter
+ {
+ //ajoute la table dans la table des tables chargées en mémoire
+ if (ajouter_table_ds_tables (tb,((ana_req_t *)params)->liste, ((ana_req_t *)params)->tables) == -1)
+ fprintf(reponse,"impossible de charger la table %s en mémoire\n",table);
+ else
+ {
+ //inserer la table dans la liste des tables du client
+ sprintf(valeur2, "%s.data", ((ana_req_t *)params)->tables);
+ ins_table_dans_liste (strdup(tb->nom),((ana_req_t *)params)->tables, valeur2);
+ //envoie un message de confirmation de création
+ fprintf(reponse,"table %s créée\n",table);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ //SELECT
+ else if (strcmp(type_requete,"SELECT")==0)
+ {
+ //vérification du nombre d'arguments
+ if (sscanf(&(ligne[position]), "%s FROM %s WHERE %s = %s", champ, table, champ2, valeur) != 4)
+ //le nombre d'arguments n'est pas bon
+ fprintf(reponse,"Utilisation : SELECT <champ> FROM <table> WHERE <champ2> = <valeur>\n");
+ else
+ {
+ //traitement de la requête
+ if ((tb = sel_champs(table, champ, champ2, valeur, ((ana_req_t *)params)->tables, ((ana_req_t *)params)->liste)) != NULL)
+ {
+ //affiche la table sur le tube de sortie
+ afficher_table (tb, reponse);
+ //désalloue la réponse
+ desallouer_table(tb);
+ }
+ else //le pointeur retourné est NULL ==> au moins un des paramètres est erroné
+ fprintf(reponse,"Paramètres erronés\n");
+ }
+ }
+
+ //UPDATE
+ else if (strcmp(type_requete,"UPDATE") == 0)
+ {
+ //vérification du nombre d'arguments
+ if (sscanf(&(ligne[position]), "%s SET %s = %s WHERE %s = %s", table, champ, valeur, champ2, valeur2) != 5)
+ //le nombre d'arguments n'est pas bon
+ fprintf(reponse,"Utilisation : UPDATE <Table> SET <Champ1> = <Valeur1> WHERE <Champ2> = <Valeur2>\n");
+ else
+ {
+ //traitement de la requête
+ if ((update_table(table, champ, champ2, valeur, valeur2, ((ana_req_t *)params)->tables, ((ana_req_t *)params)->liste)) == 1)
+ //envoie une confirmation sur le tube de réponse
+ fprintf(reponse,"Table %s mise à jour\n", table);
+ else
+ fprintf(reponse,"Paramètres erronés vérifiez les types des valeurs à changer\n");
+ }
+ }
+
+ //Aide
+ else if ((strcmp(type_requete,"?") == 0)||(strcmp(type_requete,"HELP") == 0))
+ {
+ //vérification du nombre d'arguments
+ if (sscanf(&(ligne[position]), "%s", champ) == 1)
+ {
+ if (strcmp(champ,"CREATE") == 0)
+ fprintf(reponse,"CREATE <Table> ( <champ1> <table1> , ... , <champn> <typen> ) : crée une table\n");
+ else if (strcmp(champ,"SELECT") == 0)
+ fprintf(reponse,"SELECT <Champ> FROM <Table> WHERE <champ2> = <valeur> : affiche les champs d'une table sous certaines conditions\n");
+ else if (strcmp(champ,"UPDATE") == 0)
+ fprintf(reponse,"UPDATE <Table> <indice> SET <Champ> = <Valeur> : modifie le champ n°<indice> d'une table\n");
+ else if (strcmp(champ,"DISCONNECT") == 0)
+ fprintf(reponse,"DISCONNECT : se déconnecter du système\n");
+ else
+ //les arguments sont pas les bons
+ fprintf(reponse,"Utilisation : HELP (ou ?) <commande> avec commande :\n- CREATE\n- SELECT\n- UPDATE\n- DISCONNECT\n");
+ }
+ else
+ //le nombre d'arguments n'est pas bon
+ fprintf(reponse,"Utilisation : HELP (ou ?) <commande> avec commande :\n- CREATE\n- SELECT\n- UPDATE\n- DISCONNECT\n");
+ }
+
+ //L'utilisateur a tapé nimp
+ else
+ fprintf(reponse,"Commande inconnue\n");
+
+ //fermeture du tube de réponse
+ fclose(reponse);
+
+ //Au revoir
+ pthread_exit((void *)NULL);
+}
--- /dev/null
+#ifndef _SERDED_
+ #define _SERDED_
+ #include <fcntl.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include <unistd.h>
+ #include <crypt.h>
+ #include <time.h>
+ #include <pthread.h>
+ #include <sys/stat.h>
+ #include <sys/types.h>
+
+ #include "tables.h"
+ #include "defines.h"
+
+ //*********************************************************************************************
+ //structures de données
+ //*********************************************************************************************
+ typedef struct //pour 'analyser'
+ {
+ char *req; //requete
+ char *tuberep; //tube de réponse
+ ls_table_t *liste; //liste des tables du client chargées en mémoire
+ char *tables; //nom de la liste des tables du client
+ }ana_req_t;
+
+
+ //*********************************************************************************************
+ //fonctions
+ //*********************************************************************************************
+ void *analyser (void *); //ana_req_t
+ void serveurdedie (const char *, const char *, const char *);//tuberep tubereq login
+
+#endif
--- /dev/null
+#include "tables.h"
+
+//*****************************************************************************************
+//Code
+//*****************************************************************************************
+
+//*********************************************************************************************
+//Alloue une table
+//prend en paramètre un nom de table et retourne un pointeur sur une table vide (sans champs et sans n-uplets)
+//*********************************************************************************************
+table_t * allouer_table (const char * tb)
+{
+ table_t * table;
+ //alloue la structure
+ if ( (table = (table_t *) malloc (sizeof (table_t))) == NULL)
+ {
+ fprintf(stderr, "erreur d'allocation de la table\n");
+ return NULL;
+ }
+ //copie le nom
+ table->nom = strdup(tb);
+ //initialise le nombre de champs et le nombre de n-uplets
+ table->nbchamps = 0;
+ table->nbnuplets = 0;
+
+ //initialise le verrou
+ init_verrou(&table->verrou);
+
+ //retourne le pointeur sur la table
+ return (table);
+}
+
+//*********************************************************************************************
+//Désalloue une table
+//prend en argument un pointeur sur la table à désallouer
+//*********************************************************************************************
+void desallouer_table (table_t * tb)
+{
+ int i,j;
+
+ //bloque l'accès à la table
+ DownEcriture(&tb->verrou);
+
+ //libère le nom de la table
+ free(tb->nom);
+
+ //libération des champs
+ for (i=0 ; i < tb->nbchamps ; i++)
+ {
+ //libère le nom du champ
+ free(tb->champ[i].nom);
+ //libère le type du champ
+ free(tb->champ[i].type);
+ }
+
+ //libération des n-uplets
+ for (i=0 ; i < tb->nbnuplets ; i++)
+ {
+ //pour chaque ligne supprime chaque champ
+ for (j=0 ; j < tb->nbchamps ; j++)
+ free(tb->ligne[i].donnees[j]);
+
+ //détruit le verrou du n-uplet
+ detruire_verrou(&tb->ligne[i].verrou);
+ }
+
+ //si il y avait des n-uplets, libère le pointeur sur le tableau de n-uplets
+ if (tb->nbnuplets > 0)
+ free(tb->ligne);
+
+ //déverouille le verrou
+ Up(&tb->verrou);
+
+ //détruit le verrou
+ detruire_verrou(&tb->verrou);
+
+ //libère la structure
+ free(tb);
+}
+
+//*********************************************************************************************
+//Insère un champ dans une table
+//prend en argument un pointeur sur une table, un nom et un type de champ
+//renvoie un pointeur sur la table
+//*********************************************************************************************
+table_t * inserer_champ (table_t * table, char * champ, char * type)
+{
+ //verrouille la table
+ DownEcriture(&table->verrou);
+
+ //incrémente le nombre de champs
+ table->nbchamps++;
+
+ //vérifie si on ne dépasse pas le nombre max de champs
+ if (table->nbchamps > MAX_CHAMPS)
+ {
+ fprintf(stderr, "Trop de champs\n");
+
+ //remet le nombre de champs en place
+ table->nbchamps++;
+
+ //déverrouille la table
+ Up(&table->verrou);
+ return NULL;
+ }
+
+ //Met le nom et le type du champ dans le nouveau champ
+ table->champ[table->nbchamps -1].nom = strdup(champ);
+ table->champ[table->nbchamps -1].type = strdup(type);
+
+ //déverouille la table
+ Up(&table->verrou);
+
+ //retourne un pointeur vers la table
+ return table;
+}
+
+//*********************************************************************************************
+//Insère un n-uplet dans une table
+//prend en argument un pointeur sur une table et une ligne
+//renvoie 0 si le n-uplet n'a pas pu être ajouté et 1 sinon
+//*********************************************************************************************
+int inserer_nuplet(table_t * table, char * ligne)
+{
+ int i, j;
+ int position = 0;
+ int position2 = 0;
+ int valeur;
+ char champ[TAILLE_STR];
+ char intvaleur[TAILLE_STR];
+
+ //vérouille la table
+ DownEcriture(&table->verrou);
+
+ //incrémente le nombre de n-uplets
+ table->nbnuplets++;
+
+ //si c'est le premier n-uplet il faut allouer un n-uplet
+ if (table->nbnuplets == 1)
+ if ((table->ligne = (nuplet_t *) malloc(sizeof(nuplet_t))) == NULL)
+ {
+ fprintf(stderr,"erreur à l'allocation d'un n-uplet\n");
+ free(champ);
+ free(intvaleur);
+ //remet le nombre de n-uplets comme il était
+ table->nbnuplets--;
+ //déverouille la table
+ Up(&table->verrou);
+ return 0;
+ }
+ else
+ if ((table->ligne = (nuplet_t *) realloc(table->ligne, table->nbnuplets * sizeof(nuplet_t))) == NULL)
+ {
+ fprintf(stderr,"erreur à l'allocation d'un n-uplet\n");
+ free(champ);
+ free(intvaleur);
+ //remet le nombre de n-uplets comme il était
+ table->nbnuplets--;
+ //déverouille la table
+ Up(&table->verrou);
+ return 0;
+ }
+
+ //initialise le verrou du n-uplet
+ init_verrou(&table->ligne[table->nbnuplets - 1].verrou);
+
+ //lecture des champs
+ for (i=0 ; i< table->nbchamps ; i++)
+ {
+ //si le champ suivant est un INT
+ if (strcmp(table->champ[i].type,"INT") == 0)
+ {
+ //lit un int
+ if (sscanf (&ligne[position],"%d %n", &valeur, &position2) !=1)
+ {
+ //c'était pas un INT
+ fprintf(stderr,"erreur à l'insertion d'un n-uplet\n");
+ //libère les champs ajoutés
+ for (j=0 ; j<i ; j++)
+ free(table->ligne[table->nbnuplets - 1].donnees[j]);
+
+ //décrémente le nombre de n-uplets
+ table->nbnuplets--;
+
+ free(champ);
+ free(intvaleur);
+
+ //déverouille la table
+ Up(&table->verrou);
+ return 0;
+ }
+ //avance le "curseur"
+ position += position2;
+
+ //ajoute la valeur dans le n-uplet
+ sprintf(intvaleur,"%d",valeur);
+ table->ligne[table->nbnuplets - 1].donnees[i] = strdup(intvaleur);
+ }
+ //si le champ suivant est un CHAR
+ else if (strcmp(table->champ[i].type,"CHAR") == 0)
+ {
+ //lit un champ
+ if (sscanf (&ligne[position],"%s %n", champ, &position2) !=1)
+ {
+ fprintf(stderr,"erreur à l'insertion d'un n-uplet\n");
+ //libère les champs ajoutés
+ for (j=0 ; j<i ; j++)
+ free(table->ligne[table->nbnuplets - 1].donnees[j]);
+
+ //décrémente le nombre de n-uplet
+ table->nbnuplets--;
+
+ free(champ);
+ free(intvaleur);
+
+ //déverouille la table
+ Up(&table->verrou);
+ return 0;
+ }
+
+ //avance le "curseur"
+ position += position2;
+
+ //ajout de la donnée
+ table->ligne[table->nbnuplets - 1].donnees[i] = strdup(champ);
+ }
+ else //y'a une erreur de type dans la table elle même. Ca c'est pas bien
+ {
+ fprintf(stderr,"erreur de type\n");
+
+ //décrémente le nombre de n-uplets
+ table->nbnuplets--;
+
+ free(champ);
+ free(intvaleur);
+
+ //déverouille la table
+ Up(&table->verrou);
+ return 0;
+ }
+ }
+
+ //déverouille la table
+ Up(&table->verrou);
+
+ //retourne une réponse positive
+ return 1;
+}
+
+//*********************************************************************************************
+//Cherche la table passée en paramètre dans la liste des tables de l'utilisateur passée en argument
+//retourne le nom du fichier contenant la table
+//*********************************************************************************************
+char *ch_table_dans_liste (const char * table, const char * liste)
+{
+ FILE *ls;
+
+ char *vt; //nom de table lu dans le fichier
+ char *fichier; //nom du fichier où se trouve la table
+ char *ligne; //ligne de la table
+
+ //ouverture de la liste des tables en lecture
+ if ((ls = fopen(liste, "r")) == NULL)
+ {
+ perror("ouverture du fichier de mots de passe");
+ return NULL;
+ }
+
+ //allocations
+ if ((vt = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL)
+ {
+ fprintf (stderr,"Problème d'allocation mémoire\n");
+ return NULL;
+ }
+ if ((ligne = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL)
+ {
+ fprintf (stderr,"Problème d'allocation mémoire\n");
+ return NULL;
+ }
+ if ((fichier = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL)
+ {
+ fprintf (stderr,"Problème d'allocation mémoire\n");
+ return NULL;
+ }
+
+ //lit une ligne dans la liste
+ while (fgets(ligne, TAILLE_STR, ls) != NULL)
+ {
+ //enlève l'éventuel caractère de fin de ligne
+ if (ligne[strlen(ligne) - 1] == '\n')
+ ligne[strlen(ligne) - 1] = '\0';
+
+ //enregistre le nom de table et le nom de fichier
+ if (sscanf(ligne, "%s %s",vt, fichier) >= 0)
+ {
+ //compare les noms de tables
+ if (strcmp(vt,table) == 0)
+ {
+ //libération de la chaîne allouée
+ free(vt);
+ free(ligne);
+
+ //fermeture du fichier
+ fclose(ls);
+
+ //on retourne le nom du fichier contenant la table
+ return (fichier);
+ }
+ }
+ else break; //plus rien d'intéresssant à lire
+ }
+
+ //libération de la chaîne allouée
+ free(vt);
+ free(ligne);
+
+ //fermeture du fichier
+ fclose(ls);
+
+ //retourne NULL : on n'a pas trouvé la table
+ return NULL;
+}
+
+//*********************************************************************************************
+//Cherche la table passée en paramètre dans les tables chargées en mémoire (pointées dans
+//la table des tables passée en paramètre
+//retourne -1 si la talbe n'est pas trouvée et son index sinon
+//*********************************************************************************************
+int ch_table_dans_tables (const char * table, ls_table_t * liste_tab)
+{
+ int i;
+
+ //On pose le verrou en lecture sur la table
+ DownLecture (&liste_tab->verrou);
+
+ //Section critique
+ for (i=0 ; i < liste_tab->nbtables ; i++)
+ { //si la table n'a pas été déchargée (ça arrive qu'elle soit déchargée avec decharger_tables)
+ if ( liste_tab->table[i] != NULL)
+ {
+ //si c'est la bonne table
+ if (strcmp( liste_tab->table[i]->nom, table) == 0)
+ {
+ //on relache le verrou
+ Up(&liste_tab->verrou);
+
+ //on a trouvé : on retourne l'index de la table dans la liste des tables chargées
+ return(i);
+ }
+ }
+ }
+
+ //on relache le verrou
+ Up(&liste_tab->verrou);
+
+ //on a pas trouvé
+ return(-1);
+}
+
+//*********************************************************************************************
+//Ajoute la table dans la table des tables chargées en mémoire
+//prend en argument un pointeur sur une table, une liste de tables et le nom du fichier contenant la table
+//*********************************************************************************************
+int ajouter_table_ds_tables (table_t * table, ls_table_t * liste_tab, const char * fichier)
+{
+
+ //protection le la liste des tables en lecture pour lire le nombre de tables chargées
+ DownLecture(&liste_tab->verrou);
+
+ //Si il y a trop de tables chargées, on en décharge une
+ if ( (liste_tab->nbtables + 1) > MAX_TABLES)
+ {
+
+ //on relache le mutex sur la liste sinon le déchargement va bloquer
+ Up(&liste_tab->verrou);
+
+ //on décharge une table
+ if (decharger_une_table (liste_tab, fichier) == 0)
+ return (-1);
+
+ //on pose le verrou en écriture cette fois
+ DownEcriture(&liste_tab->verrou);
+ }
+ else
+ {
+
+ //on relache le mutex de lecture
+ Up(&liste_tab->verrou);
+
+ //et on le pose en écriture
+ DownEcriture(&liste_tab->verrou);
+ }
+
+ //incrémentation du nombre de tables
+ liste_tab->nbtables++;
+
+ //on fait pointer la nouvelle table de la liste sur la structure passée en param
+ liste_tab->table[liste_tab->nbtables - 1] = table;
+
+ //déverouillage de la table
+ Up(&liste_tab->verrou);
+
+ //on retourne l'index de la table dans la liste
+ return (liste_tab->nbtables - 1);
+
+}
+
+//*********************************************************************************************
+//initialise une liste de tables
+//retourne un pointeur sur une liste de tables
+//*********************************************************************************************
+ls_table_t * init_liste_tb_ch(void)
+{
+ ls_table_t * liste;
+
+ //alloue la liste
+ if ((liste = (ls_table_t *)malloc(sizeof(ls_table_t))) == NULL)
+ {
+ fprintf(stderr, "erreur d'allocation mémoire\n");
+ return NULL;
+ }
+
+ //initialise le nombre de tables
+ liste->nbtables = 0;
+
+ //initialise le verrou
+ init_verrou(&liste->verrou);
+
+ //retourne un pointeur sur la liste
+ return (liste);
+}
+
+//*********************************************************************************************
+//Charge une table en mémoire. Retourne l'index de la table dans la liste des tables chargées en mémoire.
+//retourne -1 si la table n'a pas pu être chargée
+//*********************************************************************************************
+int charger_table (const char * table, const char * liste, ls_table_t * tb)
+{
+ FILE *flux;
+ char *fichier;
+ int index;
+
+ table_t * a_inserer;
+
+ //allocation
+ if ((fichier = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL)
+ {
+ fprintf (stderr,"Problème d'allocation mémoire\n");
+ return (-1);
+ }
+
+ //cherche le fichier dans lequel se trouve la table
+ if ((fichier = ch_table_dans_liste(table, liste)) == NULL)
+ {
+ //la table n'est pas dans la liste : on ne peut pas la charger
+ return (-1);
+ }
+ //recherche la table dans la liste des tables chargées en mémoire
+ if ((index = ch_table_dans_tables(table, tb)) != -1)
+ //retourne l'index où la table est déjà chargée
+ return (index);
+
+ //ouverture du flux sur le fichier contenant la table
+ flux = fopen(fichier,"r");
+ //recherche les tables les unes après les autres dans le fichier
+ while(1)
+ {
+ //charge la première table du flux
+ //on lit séquentiellement les tables dans le flux
+ if ((a_inserer = fichier2table (flux)) == NULL)
+ {
+ desallouer_table(a_inserer);
+ //fermeture du flux
+ fclose(flux);
+ return (0);
+ }
+ //si c'est la bonne table, on sort de la boucle
+ if (strcmp(a_inserer->nom,table) != 0)
+ break;
+ //sinon on désalloue et on recommence
+ else
+ desallouer_table(a_inserer);
+ }
+
+ //fermeture du flux
+ fclose(flux);
+
+ //a_inserer contient la table que nous voulons
+ //--> on l'ajoute dans la table des tables chargées en mémoire
+ if ((index = ajouter_table_ds_tables (a_inserer, tb, liste)) == -1)
+ {
+ fprintf(stderr, "erreur au chargement de la table %s\n",a_inserer->nom);
+ return(-1);
+ }
+
+ //retourne la place de la table dans la table des tables
+ return (index);
+}
+
+//*********************************************************************************************
+//Lit la première table trouvée dans le flux et construit une structure contenant la table et renvoie un pointeur sur
+//cette structure
+//*********************************************************************************************
+table_t * fichier2table (FILE * fichier)
+{
+ table_t * table;
+ char *nom;
+ char *ligne;
+ char *champ;
+ char *type;
+ int nbchamps, nbnuplets, i;
+
+ //alloue les pointeurs
+ if ((nom = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL)
+ {
+ fprintf (stderr,"Problème d'allocation mémoire\n");
+ return ((table_t *)NULL);
+ }
+ if ((champ = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL)
+ {
+ fprintf (stderr,"Problème d'allocation mémoire\n");
+ free(nom);
+ return ((table_t *)NULL);
+ }
+ if ((type = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL)
+ {
+ fprintf (stderr,"Problème d'allocation mémoire\n");
+ free(nom);
+ free(champ);
+ return ((table_t *)NULL);
+ }
+ if ((ligne = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL)
+ {
+ fprintf (stderr,"Problème d'allocation mémoire\n");
+ free(nom);
+ free(champ);
+ free(type);
+ return ((table_t *)NULL);
+ }
+
+ //lecture de la première ligne du flux
+ if (fgets(ligne,TAILLE_STR,fichier) == NULL)
+ {
+ free(nom);
+ free(champ);
+ free(type);
+ free(ligne);
+ return ((table_t *)NULL);
+ }
+
+ //Lecture du nom de la table, du nombre de champs et de n-uplets
+ if (sscanf(ligne, "%s %d %d\n", nom, &nbchamps, &nbnuplets) !=3)
+ {
+ free(nom);
+ free(champ);
+ free(type);
+ free(ligne);
+ return ((table_t *)NULL);
+ }
+
+ //allocation de la table
+ if ((table = allouer_table(nom)) == NULL)
+ {
+ fprintf (stderr,"Problème d'allocation de la table\n");
+ free(nom);
+ free(champ);
+ free(type);
+ free(ligne);
+ return ((table_t *)NULL);
+ }
+
+ //lit les champs
+ for (i=0 ; i < nbchamps ; i++)
+ {
+ //lecture du nom du champ et du type
+ if (fscanf(fichier, "%s %s\n", champ, type) !=2)
+ {
+ fprintf(stderr,"erreur à la lecture des champs\n");
+ desallouer_table (table);
+ free(nom);
+ free(champ);
+ free(type);
+ free(ligne);
+ return ((table_t *)NULL);
+ }
+ //insère le champ
+ if (inserer_champ (table, champ, type) == 0)
+ {
+ fprintf(stderr,"erreur à l'insertion des champs\n");
+ desallouer_table (table);
+ free(nom);
+ free(champ);
+ free(type);
+ free(ligne);
+ return ((table_t *)NULL);
+ }
+ }
+
+ //lit les n-uplets
+ for (i = 0 ; i < nbnuplets ; i++)
+ {
+ //lecture d'un n-uplet
+ if (fgets(ligne, TAILLE_STR, fichier) == NULL)
+ {
+ fprintf(stderr,"erreur à la lecture des n-uplets\n");
+ desallouer_table (table);
+ free(nom);
+ free(champ);
+ free(type);
+ free(ligne);
+ return ((table_t *)NULL);
+ }
+ //tradition oblige : on enlève l'éventuel caractère de fin de ligne
+ if (ligne[strlen(ligne) - 1] == '\n')
+ ligne[strlen(ligne) - 1] = '\0';
+
+ //insertion du nuplet dans la table
+ if (inserer_nuplet(table,ligne) == 0)
+ {
+ fprintf(stderr,"erreur à l'insertion des n-uplets\n");
+ desallouer_table (table);
+ free(nom);
+ free(champ);
+ free(type);
+ free(ligne);
+ return ((table_t *)NULL);
+ }
+ }
+
+ //libération ...
+ free(nom);
+ free(champ);
+ free(type);
+ free(ligne);
+
+ //retourneun pointeru sur la table
+ return table;
+}
+
+//*********************************************************************************************
+//écrit les données de la table (y compris le nom, les champs etc..) dans le flux passé en paramètre
+//*********************************************************************************************
+int table2fichier (table_t * table, FILE * fichier)
+{
+ int i, j;
+
+ //pose le verrou de la table en lecture
+ DownLecture(&table->verrou);
+
+ //Enregistrement du nom de la table, du nombre de champs et de n-uplets
+ fprintf(fichier, "%s %d %d\n", table->nom, table->nbchamps, table->nbnuplets);
+
+ //Enregistrement des champs et de leur type
+ for (i=0 ; i < table->nbchamps ; i++)
+ fprintf(fichier, "%s %s\n", table->champ[i].nom, table->champ[i].type);
+
+ //enregistrement des n-uplets...
+ for (i = 0 ; i < table->nbnuplets ; i++)
+ {
+ //...champ par champ
+ for (j = 0 ; j < table->nbchamps ; j++)
+ {
+ //verouille le n-uplet en lecture
+ DownLecture(&table->ligne[i].verrou);
+
+ //écriture de la donnée
+ fprintf (fichier, "%s ", table->ligne[i].donnees[j]);
+
+ //déverouille le n-uplet
+ Up(&table->ligne[i].verrou);
+ }
+ //passe à la ligne à la fin du n-uplet
+ fprintf (fichier, "\n");
+ }
+
+ //relache le verrou sur la table
+ Up(&table->verrou);
+
+ //retourne une réponse positive
+ return 1;
+}
+
+//*********************************************************************************************
+//Renvoie un pointeur sur une table issue de celle passée en paramètre. Le champ est le premier passé en paramètre
+//et les n-uplets doivent satisfaire l'égalité champ2 = valeur dans la table d'origine pour figurer dans celle ci
+//c'est le résultat de la requête : SELECT champ1 FROM table WHERE champ2 = valeur
+//*********************************************************************************************
+table_t * sel_champs(const char * table, const char * champ1, const char * champ2, const char * valeur, const char * liste, ls_table_t * tb)
+{
+ int index, i = 0;
+ int c1 = -1;
+ int c2 = -1;
+ char *ligne;
+
+ //allocation (pas de chômage en tout cas parce qu'il va travailler le gaillard !)
+ if ((ligne = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL)
+ {
+ fprintf (stderr,"Problème d'allocation mémoire\n");
+ return NULL;
+ }
+
+ //table contenant le résultat de la requête
+ table_t * table_resultat;
+
+ //allocation de table résultat
+ table_resultat = allouer_table("resultat");
+
+ //recherche de la table
+ if ((index = charger_table (table, liste, tb)) == -1)
+ {
+ //la table n'existe pas
+ free(ligne);
+ //on libère la table de résultat
+ desallouer_table(table_resultat);
+
+ //retourne un pointeur nul
+ return NULL;
+ }
+
+ //recherche des indices des champs en paramètre
+ for (i=0 ; i < tb->table[index]->nbchamps ; i++)
+ {
+ //est-ce le champ1 ?
+ if (strcmp(tb->table[index]->champ[i].nom,champ1) == 0)
+ c1 = i;
+ //est-ce le champ2 ?
+ if (strcmp(tb->table[index]->champ[i].nom,champ2) == 0)
+ c2 = i;
+ }
+
+ //si au moins l'un des deux n'existe pas...
+ if ((c1 == -1) || (c2 == -1))
+ {
+ //...on libère tout
+ free(ligne);
+ desallouer_table(table_resultat);
+ //on reourne un pointeur nul
+ return NULL;
+ }
+
+ //ajout du champ1 dans la table
+ if ((table_resultat = inserer_champ (table_resultat, strdup(champ1),tb->table[index]->champ[c1].type)) == NULL)
+ {
+ fprintf(stderr, "erreur à l'insertion du champ1\n");
+ free(ligne);
+ desallouer_table(table_resultat);
+ }
+
+ //recherche des enregistrement tels que "champ2 = valeur"
+
+ //on parcourt tous les nuplets de la table
+ for (i=0 ; i < tb->table[index]->nbnuplets ; i++)
+ {
+ //on compare les données du champ2 avec valeur
+ if (strcmp(tb->table[index]->ligne[i].donnees[c2], valeur) == 0)
+ {
+ //si c'estbon, on ajoute le nuplet à la table
+ sprintf(ligne,"%s %s",tb->table[index]->ligne[i].donnees[c1], tb->table[index]->champ[c1].type);
+ if (inserer_nuplet(table_resultat, ligne) == 0)
+ fprintf(stderr,"erreur à l'insertion du n-uplet\n");
+ }
+ }
+
+ //on libère la ligne
+ free (ligne);
+
+ //on retourne un pointeur vers la table de résultat
+ return table_resultat;
+}
+
+//*********************************************************************************************
+//Met à "valeur1" les champs "champ1" de la table "table" pous lesquels le champ "champ2" vaut "valeur2"
+//retourne 1 si ça se passe bien et 0 sinon
+//*********************************************************************************************
+int update_table(const char * table, const char * champ1, const char * champ2, const char * valeur1, const char * valeur2, const char * liste, ls_table_t * tb)
+{
+ int index, i = 0;
+ int c1 = -1;
+ int c2 = -1;
+
+ //recherche de la table
+ if ((index = charger_table (table, liste, tb)) == -1)
+ {
+ //la table n'existe pas
+ return 0;
+ }
+
+ //recherche des indices des champs en paramètre
+ for (i=0 ; i < tb->table[index]->nbchamps ; i++)
+ {
+ //est-ce le champ1 ?
+ if (strcmp(tb->table[index]->champ[i].nom,champ1) == 0)
+ c1 = i;
+ //est-ce le champ2 ?
+ if (strcmp(tb->table[index]->champ[i].nom,champ2) == 0)
+ c2 = i;
+ }
+
+ //si au moins un des champs n'existe pas
+ if ((c1 == -1) || (c2 == -1))
+ //on repart la tête basse
+ return 0;
+
+ //recherche des enregistrement tels que "champ2 = valeur2"
+
+ //on parcourt les n-uplets
+ for (i=0 ; i < tb->table[index]->nbnuplets ; i++)
+ {
+ //on compare la valeur de champ2 avec valeur2
+ if (strcmp(tb->table[index]->ligne[i].donnees[c2], valeur2) == 0)
+ {
+ //on regarde le type
+ //si c'est un INT
+ if (strcmp(tb->table[index]->champ[c1].type,"INT") == 0)
+ {
+ //on bloque la ligne en écriture
+ DownEcriture(&tb->table[index]->ligne[i].verrou);
+
+ //on s'assure que le champ sera un INT, et on copie
+ sprintf(tb->table[index]->ligne[i].donnees[c1],"%d",atoi(valeur1));
+
+ //on relache le verrou
+ Up(&tb->table[index]->ligne[i].verrou);
+ }
+ else
+ {
+ //on bloque la ligne en écriture
+ DownEcriture(&tb->table[index]->ligne[i].verrou);
+
+ //on recopie la donnée
+ sprintf(tb->table[index]->ligne[i].donnees[c1],"%s",valeur1);
+
+ //on relache le verrou
+ Up(&tb->table[index]->ligne[i].verrou);
+ }
+ }
+ }
+
+ //on renvoit une bonne nouvelle
+ return 1;
+}
+
+//*********************************************************************************************
+//Insère la table passée en paramètre dans la liste des tables de l'utilisateur passée en argument
+//fichier désigne le fichier où est placée la table
+//*********************************************************************************************
+int ins_table_dans_liste (const char * table, const char * liste, const char * fichier)
+{
+ FILE *ls;
+
+ char *vt; //nom de table lu dans le fichier
+ char *ligne; //ligne de la table
+
+ //allocation
+ if ((vt = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL)
+ {
+ fprintf (stderr,"Problème d'allocation mémoire\n");
+ return 0;
+ }
+ if ((ligne = (char *) malloc (TAILLE_STR * sizeof(char))) == NULL)
+ {
+ fprintf (stderr,"Problème d'allocation mémoire\n");
+ return 0;
+ }
+
+ //ouverture de la liste en lecture / écriture
+ if ((ls = fopen(liste, "r+")) == NULL)
+ {
+ perror("ouverture du fichier des tables");
+ return 0;
+ }
+
+ //lit une ligne
+ while (fgets(ligne, TAILLE_STR, ls) != NULL)
+ //enregistre le nom de la table
+ if (sscanf(ligne, "%s %*s",vt) == 1)
+ {
+ //compare le nom de la table et celui du nom trouvé dans le fichier
+ if (strcmp(vt,table) == 0)
+ {
+ //fermeture du fichier
+ fclose(ls);
+ //libération de la chaîne allouée
+ free(vt);
+ free(ligne);
+
+ //la table était déjà dans la liste --> on ne l'ajoute pas
+ return 0;
+ }
+ }
+ else break;
+
+ //la table n'y est pas déjà -> on l'ajoute
+ fprintf(ls,"%s %s\n",table, fichier);
+
+ //fermeture du fichier
+ fclose(ls);
+
+ //libération de la chaîne allouée
+ free(vt);
+ free(ligne);
+
+ //et on signale que la table a été ajoutée
+ return 1;
+}
+
+//*********************************************************************************************
+//affiche un table passée en paramètre sur le flux désigné
+//*********************************************************************************************
+void afficher_table (table_t * table, FILE * sortie)
+{
+ int i,j;
+
+ //pose le verrou de la table en lecture
+ DownLecture(&table->verrou);
+
+ //affiche le nom de la table
+ fprintf(sortie,"\nTable %s\n",table->nom);
+
+ //affiche le haut du tableau
+ for (i=0 ; i<table->nbchamps ; i++)
+ fprintf(sortie, "_____________");
+ fprintf(sortie,"_\n");
+
+ //affiche les noms des champs
+ for (i=0 ; i<table->nbchamps ; i++)
+ fprintf(sortie, "| %10s ",table->champ[i]);
+ fprintf(sortie,"|\n");
+
+ //affiche le milieu du tableau
+ for (i=0 ; i<table->nbchamps ; i++)
+ fprintf(sortie, "|------------");
+ fprintf(sortie,"|\n");
+
+ //affiche les n-uplets
+ for (i=0 ; i<table->nbnuplets ; i++)
+ {
+ //verouille le n-uplet en lecture
+ DownLecture(&table->ligne[i].verrou);
+
+ //affiche n-uplet par n-uplet
+ for (j=0 ; j<table->nbchamps ; j++)
+ fprintf(sortie, "| %10s ",table->ligne[i].donnees[j]);
+ fprintf(sortie,"|\n");
+
+ //déverouille le n-uplet
+ Up(&table->ligne[i].verrou);
+ }
+
+ //affiche le bas du tableau
+ for (i=0 ; i<table->nbchamps ; i++)
+ fprintf(sortie, "|------------");
+ fprintf(sortie,"|\n");
+
+ //déverouille la table
+ Up(&table->verrou);
+}
+
+//*********************************************************************************************
+//décharge les tables de la liste passée en argument et les enregistre dans le fichier indiqué
+//*********************************************************************************************
+int decharger_tables (ls_table_t * tables, const char * fichier)
+{
+ FILE *fich_temp;
+ FILE *liste;
+
+ table_t * table_temp;
+
+ int index, i, test;
+
+ char c;
+
+ //lit les tables du fichier et regarde si elles sont chargées en mémoire. Si elles y sont on enregistre la version
+ //en mémoire sionon on enregistre la version qui était déjà dans le fichier
+
+ //ouvre la liste en lecture
+ if ((liste = fopen(fichier,"r")) == NULL)
+ {
+ perror("lecture des données");
+ return 0;
+ }
+
+ //ouvre (et crée un fichier temporaire) en écriture
+ if ((fich_temp = fopen("fich_temp","w")) == NULL)
+ {
+ perror("lecture des données");
+ fclose(liste);
+ return 0;
+ }
+
+ //charge les tables du fichier
+ while ((table_temp = fichier2table (liste)) != NULL)
+ {
+ //si la table n'est pas chargée
+ if ((index = ch_table_dans_tables(table_temp->nom, tables)) == -1)
+ {
+ //on l'enregistre dans le fichier
+ if ((test = table2fichier(table_temp, fich_temp)) == 0)
+ {
+ perror("écriture de la table");
+ fclose(liste);
+ fclose(fich_temp);
+ return 0;
+ }
+ }
+ else //la table est la table No index dans la liste des tables
+ {
+ //enregistrement de la table qui est en mémoire principale
+ //(écrasement de la table qui se trouvait dans le fichier)
+ if ((test = table2fichier(tables->table[index], fich_temp)) == 0)
+ {
+ perror("écriture de la table");
+ fclose(liste);
+ fclose(fich_temp);
+ return 0;
+ }
+ //désallocation de la table
+ desallouer_table(tables->table[index]);
+ //met le pointeur à NULL
+ //pour éviter de la réenregistrer dans la phase suivante
+ tables->table[index] = NULL;
+ }
+ desallouer_table(table_temp);
+ }
+
+ //enregistrement des nouvelles tables (elles sont juste en mémoire et pas dans un fichier)
+ for (i=0 ; i < tables->nbtables ; i++)
+ {
+ //si la table n'a pas été déchargée
+ if (tables->table[i] != NULL)
+ {
+ //enregistrement de la table
+ if ((test = table2fichier(tables->table[i], fich_temp)) == 0)
+ {
+ perror("écriture de la table");
+ fclose(liste);
+ fclose(fich_temp);
+ return 0;
+ }
+ //désallocation de la table
+ desallouer_table(tables->table[i]);
+ //marque la table comme déchargée
+ tables->table[i] = NULL;
+ }
+ }
+
+ //ferme les flux
+ fclose(liste);
+ fclose(fich_temp);
+
+ //ouverture des flux pour la copie
+ if ((liste = fopen(fichier, "w")) == NULL)
+ {
+ perror("ouverture du fichier de mots de passe en écriture");
+ return 0;
+ }
+ if ((fich_temp = fopen("fich_temp", "r")) == NULL)
+ {
+ perror("ouverture du fichier temporaire en lecture");
+ fclose(liste);
+ return 0;
+ }
+
+ //copie de fich_tmp dans liste
+ while ((c = getc(fich_temp)) != EOF)
+ {
+ putc(c, liste);
+ }
+
+ //ferme les flux
+ fclose(liste);
+ fclose(fich_temp);
+
+ //supprime le fichier temporaire
+ unlink ("fich_temp");
+
+ //retourne la réponse
+ return 1;
+}
+
+//*********************************************************************************************
+//décharge une table. L'algorithme utilisé enlève tout simplement la première table chargée
+//puis décale les autres dans la table
+//*********************************************************************************************
+int decharger_une_table (ls_table_t * tables, const char * fichier)
+{
+ FILE *fich_temp;
+ FILE *liste;
+
+ table_t * table_temp;
+
+ int index, i, test;
+
+ char c;
+
+ //ouvre le fichier contenant les tables en lecture
+ if ((liste = fopen(fichier,"r")) == NULL)
+ {
+ perror("lecture des données");
+ return 0;
+ }
+
+ //ouvre (et crée) un fichier temporaire
+ if ((fich_temp = fopen("fich_temp","w")) == NULL)
+ {
+ perror("lecture des données");
+ fclose(liste);
+ return 0;
+ }
+
+ //charge les tables
+ while ((table_temp = fichier2table (liste)) != NULL)
+ {
+ //si la table n'est pas chargée
+ if ((index = ch_table_dans_tables(table_temp->nom, tables)) == -1)
+ {
+ //on la remet dans le fichier (en passant par le fichier temporaire)
+ if ((test = table2fichier(table_temp, fich_temp)) == 0)
+ {
+ perror("écriture de la table");
+ fclose(liste);
+ fclose(fich_temp);
+ //Up(&tables->verrou);
+ return 0;
+ }
+ }
+ else //la table est la table No index dans la liste des tables
+ {
+ //si c'est la première table
+ if (index == 0)
+ {
+ //enregistrement de la table qui est en mémoire
+ if ((test = table2fichier(tables->table[index], fich_temp)) == 0)
+ {
+ perror("écriture de la table");
+ fclose(liste);
+ fclose(fich_temp);
+ //Up(&tables->verrou);
+ return 0;
+ }
+ }
+ //désallocation de la table
+ desallouer_table(tables->table[index]);
+ //marque la table comme déchargée
+ tables->table[index] = NULL;
+ }
+ //désallocation de la table qui vient d'être chargée
+ desallouer_table(table_temp);
+ }
+
+ //verrouille la liste des tables
+ DownEcriture(&tables->verrou);
+
+ //décalage des tables dans la liste
+ for (i=0 ; i < tables->nbtables - 1; i++)
+ tables->table[i] = tables->table[i + 1];
+
+ //marque comme non lue la dernière table
+ tables->table[tables->nbtables - 1] = NULL;
+ tables->nbtables--;
+
+ //on déverouille la liste
+ Up(&tables->verrou);
+
+ //ferme les flux
+ fclose(liste);
+ fclose(fich_temp);
+
+ //ouverture des flux pour la copie
+ if ((liste = fopen(fichier, "w")) == NULL)
+ {
+ perror("ouverture du fichier de mots de passe en écriture");
+ return 0;
+ }
+ if ((fich_temp = fopen("fich_temp", "r")) == NULL)
+ {
+ perror("ouverture du fichier temporaire en lecture");
+ fclose(liste);
+ return 0;
+ }
+ //copie de fich_tmp dans liste
+ while ((c = getc(fich_temp)) != EOF)
+ putc(c, liste);
+
+ //ferme les flux
+ fclose(liste);
+ fclose(fich_temp);
+
+ //supprime le fichier temporaire
+ unlink ("fich_temp");
+
+ //et donne une bonne réponse
+ return 1;
+}
--- /dev/null
+//*****************************************************************************************
+//Includes
+//*****************************************************************************************
+
+#ifndef _TABL_
+ #define _TABL_
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <pthread.h>
+ #include <string.h>
+
+ #include "defines.h"
+ #include "verrou.h"
+
+ #define TAILLE_STR 128
+ #define TAILLE_INT sizeof(int)
+ #define TAILLE_CHAR (10*sizeof(char))
+
+ //*****************************************************************************************
+ //Types
+ //*****************************************************************************************
+ typedef struct champ
+ {
+ char *nom; //nom du champ
+ char *type; //type de la donnée (restreint à INT et CHAR)
+ }champ_t;
+
+ typedef struct nuplet
+ {
+ verrou_t verrou; //verrou protégeant l'accès à la ressource
+ char *donnees[MAX_CHAMPS]; //données de l'enregistrement
+ }nuplet_t;
+
+ typedef struct table
+ {
+ char *nom; //nom de la table
+ int nbchamps; //nombre de champs dans la table (colonnes)
+ int nbnuplets; //nombres de N-uplets de la table (lignes)
+ verrou_t verrou; //verrou protégeant l'accès à la table
+ champ_t champ[MAX_CHAMPS]; //définition des champs
+ nuplet_t * ligne; //enregistrements
+ }table_t;
+
+ typedef struct ls_table
+ {
+ int nbtables; //nombre de tables chargées en mémoire
+ verrou_t verrou; //verrous protégeant l'accès à la table
+ table_t * table[MAX_TABLES]; //pointeurs sur les tables chargées en mémoire
+ }ls_table_t;
+
+ //*****************************************************************************************
+ //fonctions
+ ///****************************************************************************************
+
+ table_t * allouer_table (const char *); //nom de la table //alloue la structure d'une table
+ void desallouer_table (table_t *); //table //désalloue une table, les champs ...
+ table_t * inserer_champ (table_t *, char *, char *); //Table, Champ, Type //Insère un champ dans une table
+ int inserer_nuplet(table_t *, char *); //Table, ligne //Insère un n-uplet dans une table
+
+ ls_table_t * init_liste_tb_ch(void); //initialise et alloue une liste de tables
+
+ char * ch_table_dans_liste (const char *, const char *); //nom table, liste //Cherche une table dans une liste de tables
+ int ch_table_dans_tables (const char *, ls_table_t *); //nom table, table tables //Cherche une table dans les tables chargées
+ int ajouter_table_ds_tables (table_t *, ls_table_t *, const char * ); //table, liste, tables //ajoute une table dans la table des tables chargées
+ int charger_table (const char *, const char *, ls_table_t *); //table, liste, tab de tab //charge une table en mémoire
+
+ table_t * fichier2table (FILE *); //flux //prend la première table du flux et la met dans une structure
+ int table2fichier (table_t *, FILE *); //table, fichier //met la talbe dans le flux
+
+ table_t * sel_champs(const char *, const char *, const char *, const char *, const char *, ls_table_t *); //voir fichier .c
+
+ int ins_table_dans_liste (const char *, const char *, const char *); //table, liste, fichier //insère la table dans la liste
+
+ void afficher_table (table_t *, FILE *); //table, flux //affiche la table sur le flux
+ int decharger_tables (ls_table_t *, const char *); //liste, tables //décharge et enregistre les tables du client
+ int decharger_une_table (ls_table_t *, const char *); //liste, tables //décharge et enregistre la première table du client
+#endif
--- /dev/null
+#include "verrou.h"
+
+//*********************************************************************************************
+//DownLecture(&verrrou) : pose le verrou en lecture (NB_LECT_MAX lecteurs permis en même temps)
+//*********************************************************************************************
+void DownLecture (verrou_t* verrou)
+{
+ //bloque l'accès à la structure
+ pthread_mutex_lock(&verrou->mutex);
+
+ //tant qu'il y a un écrivain en SC ou 3 lecteurs (NB_LECT_MAX) ou qu'il y a des ecrivains
+ //en attente d'écriture
+ while (verrou->verouilles < 0 || verrou->verouilles >= NB_LECT_MAX || verrou->ecrivains > 0)
+ {
+ //incrémente le nombre de lecteurs en attente de lecture
+ verrou->lecteurs++;
+ //relache le mutex en attente de cond_r
+ pthread_cond_wait(&verrou->cond_r, &verrou->mutex);
+ //décrémente le nombre de lecteurs en attente de lecture
+ verrou->lecteurs--;
+ }
+ //incrémente le nombre de lecteurs en section critique
+ verrou->verouilles++;
+ //relache le mutex ==> un autre processus pourra tenter d'entrer
+ pthread_mutex_unlock(&verrou->mutex);
+}
+
+//*********************************************************************************************
+//DownEcriture(&verrrou) : pose le verrou en écriture (aucun lecteur ou autre écrivain n'est permis)
+//*********************************************************************************************
+void DownEcriture (verrou_t* verrou)
+{
+ //bloque l'accès à la structure
+ pthread_mutex_lock(&verrou->mutex);
+ //tant qu'il y a un écrivain ou des lecteurs en SC
+ while (verrou->verouilles != 0)
+ {
+ //incrémente le nombre d'écrivains en attente de lecture
+ verrou->ecrivains++; //permet de privilégier les écrivains
+ //relache le mutex en attente de cond_w
+ pthread_cond_wait(&verrou->cond_r, &verrou->mutex);
+ //décrémente le nombre d'écriture en attente de lecture
+ verrou->ecrivains--;
+ }
+ //signifie qu'il y a un écrivain en section critique
+ verrou->verouilles = -1;
+ //relache le mutex ==> un autre processus pourra tenter d'entrer
+ pthread_mutex_unlock(&verrou->mutex);
+}
+
+//*********************************************************************************************
+//Up(&verrrou) : relache un verrou
+//*********************************************************************************************
+void Up (verrou_t* verrou)
+{
+ //permet d'éviter de réveiller plus de 3 lecteurs
+ //on stocke le min de verrou->lecteurs et NB_LECT_MAX
+ int i;
+ if (verrou->lecteurs >= NB_LECT_MAX)
+ i = NB_LECT_MAX;
+ else i = verrou->lecteurs;
+
+ //bloque l'accès à la structure
+ pthread_mutex_lock(&verrou->mutex);
+ //Si c'est un écrivain qui déverouille
+ if (verrou->verouilles < 0)
+ {
+ //signifie qu'il n'y a plus personne en SC
+ verrou->verouilles = 0;
+ //réveille un écrivain si il y en a en attente
+ if (verrou->ecrivains > 0)
+ pthread_cond_signal(&verrou->cond_w);
+ //sinon réveille les lecteurs
+ else
+ while (i>0)
+ {
+ pthread_cond_signal(&verrou->cond_r);
+ i--;
+ }
+ }
+ //si c'est un lecteur qui déverouille
+ else
+ {
+ //décrémente le nombr de lecteurs en section critique
+ verrou->verouilles --;
+ //si il y avait 1 seul lecteur
+ if (verrou->verouilles == 0)
+ //si il y a un ou des écrivains en attente d'écriture : réveille un écrivain
+ //NB : il ne pouvait pas y avoir de lecteurs vu qu'ils pouvaient rentrer en SC
+ if (verrou->ecrivains > 0)
+ pthread_cond_signal(&verrou->cond_w);
+ //Si il y avait 3 lecteurs (NB_LECT_MAX) on peut réveiller un lecteur si il y en a en attente
+ else if ((verrou->verouilles == NB_LECT_MAX - 1) && (verrou->lecteurs > 0))
+ pthread_cond_signal(&verrou->cond_r);
+ }
+ //relache le mutex
+ pthread_mutex_unlock(&verrou->mutex);
+}
+
+//*********************************************************************************************
+//Détruit un verrou
+//*********************************************************************************************
+void detruire_verrou (verrou_t *verrou)
+{
+ //détruit le mutex et les variables conditionnelles
+ pthread_mutex_destroy(&verrou->mutex);
+ pthread_cond_destroy(&verrou->cond_r);
+ pthread_cond_destroy(&verrou->cond_w);
+}
+
+//*********************************************************************************************
+//initialise un verrou
+//*********************************************************************************************
+void init_verrou(verrou_t *verrou)
+{
+ //initialise le mutex
+ pthread_mutex_init(&verrou->mutex, NULL);
+ //initialise les variables
+ verrou->verouilles = 0;
+ verrou->lecteurs = 0;
+ verrou->ecrivains = 0;
+ //initialise les variables conditionnelles
+ pthread_cond_init (&verrou->cond_r, NULL);
+ pthread_cond_init (&verrou->cond_w, NULL);
+}
--- /dev/null
+//*****************************************************************************************
+//Includes
+//*****************************************************************************************
+
+#ifndef _VERROU_
+ #define _VERROU_
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <pthread.h>
+
+ #include "defines.h"
+
+ //*****************************************************************************************
+ //Types
+ //*****************************************************************************************
+ typedef struct
+ {
+ pthread_mutex_t mutex; //bloque l'accès aux variables de condition
+ int verouilles; //nombre de lecteurs en section critique (-1 si il y a un écrivain)
+ int lecteurs; //nombre de lecteurs en attente d'écriture
+ int ecrivains; //nombre d'écrivains en attente d'écriture
+ pthread_cond_t cond_r; //attente de lecture
+ pthread_cond_t cond_w; //attente d'écriture
+ }verrou_t;
+
+ //*****************************************************************************************
+ //fonctions
+ ///****************************************************************************************
+
+ void DownLecture (verrou_t*); //Pose le verrou en LECTURE
+ void DownEcriture (verrou_t*); //Pose le verrou en ECRITURE
+ void Up (verrou_t*); //Relache le verrou
+ void init_verrou(verrou_t *); //initialise et alloue un verrou
+ void detruire_verrou(verrou_t *); //détruit un verrou
+
+#endif
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<!-- saved from url=(0052)http://www.lita.univ-metz.fr/~paris/OS/projetII.html -->
+<HTML><HEAD><TITLE>ProJet OS, un SGBD le retour</TITLE><!-- creation date: 09/12/2002 -->
+<META http-equiv=Content-Type content="text/html; charset=iso-8859-1">
+<META content="" name=Description>
+<META content="" name=Keywords>
+<META content=theta name=Author>
+<META content="MSHTML 6.00.2719.2200" name=GENERATOR></HEAD>
+<BODY lang=fr>
+<H1 align=center>Projet système<BR>Licence Informatique</H1><FONT
+face="Book Antiqua">La deuxième partie du projet concerne la <B>gestion de la
+mémoire principale</B>.
+<P>Seul le stockage en mémoire des tables utiles pour répondre aux requêtes nous
+intéresse dans le cadre de la simulation. Autrement dit les processus ne sont
+représentés que par les tables qu'ils manipulent.
+<P>Je vous laisse choisir la <B>taille</B> de la mémoire. Mais veillez à ce
+qu'elle correspondent aux besoins des simulations que l'on va détailler. Il faut
+en effet que cette mémoire soit suffisamment grande pour contenir plusieurs
+tables (qui sont implicitement associées aux processus prêts) tout en s'assurant
+qu'elle ne soit pas trop grande afin de ne pas avoir toutes les tables
+nécessaires en mémoire. Il faut bien que l'ordannanceur de <B>haut niveau</B>
+est du travail!
+<P>Le <I>partitionnement</I> sera votre premier cadre d'étude de cette mémoire.
+Puis vous étudirez cette dernière sous l'angle merveilleux et passionnant de la
+<I>pagination</I>.
+<P>Vous devez maintenant utiliser obligatoirement l'instruction <FONT
+face="Times New Roman, Arial Black"><B><BLINK>INSERT</BLINK></B></FONT> aussi
+bien dans le cas du partitionnement que dans le cas de la pagination.
+<H2>I Partionnement</H2>L'ordonnaceur de haut niveau, ou <I>swapper</I>, utilise
+l'algorithme du PAPS <I>intelligent</I> avec des <I>partitions variables</I>.
+<P><B>Remarque :</B> le partionnement ne fait intervenir le swapper que dans sa
+fonction <I>swap in</I>!
+<H2>II Pagination</H2>Dans cette deuxième partie, le système doit permettre
+d'expérienter la fonction <I>swap out</I> du swapper.
+<P>Le swap out est déclenché quand les processus sont découpés en pages de
+taille fixe. Lors de l'execution sur l'UCT d'une page celle-ci peut faire appel
+à une référence se trouvant sur une autre page. Dans ce cas la page est
+recherchée dans la <B>table des pages</B> du processus. Si celle-ci est marquée
+<B>invalide</B> il faut alors aller la chercher en mémoire secondaire :<I>défaut
+de page</I>. Si de plus au moment de ce défaut de pages tous les cadres sont
+occupés alors il y a une <I>demande de page</I>. Le swap out va alors rapatrier
+en mémoire secondaire (il faut contrôler le <I>bit de modification</I>) une page
+occupant un cadre pour pouvoir charger la page faisant défaut. Le swap out
+fonctionne suivant l'algorithme de la seconde chance.
+<P><B>Remarques :</B>
+<OL type=a>
+ <LI>Encore une fois je ne fixe pas de taile de mémoire. Mais vous l'avez déjà
+ sûrement compris, toutes les pages ne doivent pas se trouver en mémoire en
+ même temps. Et ce afin de permettre la mise en \9cuvre du swap out !!!
+ <LI>Je rappelle que les pages ne contiennent que les entités des tables. Ainsi
+ les défauts de page surviendront uniquement lors d'une concultation,
+ modification ou création d'une table. </LI></OL>
+<H2>III Plus qu'une conclusion</H2>Ce qui est obligatoire c'est évidemment le
+<B>partionnement</B>, son <I><B>binding</B></I> et sa <I><B>représentation
+physique</B></I> que je vous laisse, encore une fois, choisir.
+<P>Je suis conscient que la charge de travail est imposante. Aussi je considère
+que la pagination doit être faite que si vous avez franchi toutes les étapes
+précédentes avec succès et de manière élégante. Autrement dit, si vous me
+présentez un projet avec une implantation de la pagination mais un
+partitionnement <I>boiteux</I> cela vous désservira! </P></FONT></BODY></HTML>