1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
| #include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <pthread.h>
#include <signal.h>
#include "file_synchronisee/file_sync.h"
#include "lanceur_de_commande.h"
typedef struct {
char *path_fonction;
char *argv[];
} arg_execv;
/*
* Lance la commande en fonction de arg, un type elem.
*/
void *lance_commande(void *arg);
/*
* Prend en argument un espace mémoire partagé de char codée
* selon notre définition et renvoie une structure arg_execv permettant
* d'éxecuter la commande.
*/
arg_execv *string_arg_execv(char *tab);
/*
* Permet d'intercepter le signal SIGQUIT mettant proprement fin au
* programme.
*/
void gestionnaire(int sig);
/*
* Met fin au serveur et signal l'erreur.
*/
void fin_serveur_echec();
/*
* Met fin au serveur et signal la réussite.
*/
void fin_serveur_succes();
int main(void) {
// Création de l'espace de mémoire partagée pour la file
int shm_fd = shm_open(NOM_FILE, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
if (shm_fd == -1) {
perror("shm_open");
exit(EXIT_FAILURE);
}
// Redéfinition de la taille de cet espace mémoire.
if (ftruncate(shm_fd, sizeof(file)) == -1) {
perror("ftruncate");
fin_serveur_echec();
}
// Mapage de cet espace mémoire sur le processus.
file *file_sync = mmap(NULL, sizeof(file), PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
if (file_sync == MAP_FAILED) {
perror("sem_open");
fin_serveur_echec();
}
// On ferme le descripteur désormais inutilisé.
if (close(shm_fd) == -1) {
perror("close shm_fd");
fin_serveur_echec();
}
// Initialisation de la file.
*file_sync = file_vide();
// Initialisation de l'action.
struct sigaction action;
action.sa_handler = gestionnaire;
action.sa_flags = 0;
if (sigfillset(&action.sa_mask) == -1) {
perror("sigfilltset");
fin_serveur_echec();
}
// On change la fonction éxecuté à la réception du signal
// SIGQUIT afin qu'elle mette fin au serveur proprement.
if (sigaction(SIGINT, &action, NULL) != 0) {
perror("Sigaction");
fin_serveur_echec();
}
while (1) {
// On malloc un nouvelle element e à chaque fois pour éviter tous
// problème si plusieur thread travaille sur le même e.
elem *e = malloc(sizeof(elem));
if (e == NULL) {
perror("Probleme de malloc");
fin_serveur_echec();
}
// On tente de défiler un élèment de la file. Cet opération ne sera
// effectué que lorsque qu'au moin un élèment sera présent dans la
// file.
if (file_sync == NULL) {
fin_serveur_echec();
}
*e = defiler(file_sync);
// On averti que l'on a bien recus la demande.
printf("J'ai recus une commande\n");
pthread_t th;
if (pthread_create(&th, NULL, lance_commande, e) != 0) {
perror("pthread_create");
fin_serveur_echec();
}
// Cela garantit que les ressources mémoire consommées par th seront
// immédiatement libérées lorsque l'exécution de th s'achèvera.
if (pthread_detach(th) != 0) {
perror("pthread_detach");
fin_serveur_echec();
}
}
}
void *lance_commande(void *arg) {
elem *e = (elem *) arg;
printf("Commande en cours de lancement...\n");
int sortie;
switch (fork()) {
case -1:
perror("fork");
fin_serveur_echec();
break;
// Traitement des erreurs différents dans le fils.
// On n'appelera pas fin_serveur_echec(). (processus indépendant)
case 0:
// Gestion de la sortie standart du programme prochainement
// executé
if ((sortie = open(e->tube_sortie, O_WRONLY) == -1)) {
perror("open");
exit(EXIT_FAILURE);
}
// Redirection de la sortie
if (dup2(sortie, STDOUT_FILENO) == -1) {
perror("dup2");
exit(EXIT_FAILURE);
}
if (dup2(sortie, STDERR_FILENO) == -1) {
perror("dup2");
exit(EXIT_FAILURE);
}
fprintf(stdout, "Voila, aucune redirection\n");
// Fermeture des descripteurs inutilisés
if (close(sortie) == -1) {
perror("close(sortie)");
exit(EXIT_FAILURE);
}
// Ouverture de l'espace mémoire partager de e contenant la
// commande à éxecuter.
int shm_fd = shm_open(e->nom, O_RDWR, S_IRUSR | S_IWUSR);
if (shm_fd == -1) {
perror("shm_open");
exit(EXIT_FAILURE);
}
// Mapage de cet espace mémoire partager sur le processus.
char *shm_ptr = mmap(NULL, e->taille, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
if (shm_ptr == MAP_FAILED) {
perror("sem_open");
exit(EXIT_FAILURE);
}
arg_execv *tampon = string_arg_execv(shm_ptr);
execv(tampon->path_fonction, tampon->argv);
free(tampon);
free(e);
perror("execv");
exit(EXIT_FAILURE);
default:
break;
}
free(e);
printf("Tache terminer.\n");
pthread_exit(NULL);
}
arg_execv *string_arg_execv(char *tab) {
arg_execv *resultat = malloc(sizeof(arg_execv));
if (resultat == NULL) {
perror("Malloc");
exit(EXIT_FAILURE);
}
resultat->path_fonction = tab;
resultat->argv[0] = tab;
int condition = 0;
int i = 1;
while (!condition) {
if (*tab == '\0') {
if (*(tab + 1) == '\0') {
resultat->argv[i] = NULL;
condition = 1;
} else {
resultat->argv[i] = tab + 1;
++i;
}
}
tab += 1;
}
return resultat;
}
void gestionnaire(int sig) {
if (sig < 0) {
fprintf(stderr, "Signal incorrecte");
fin_serveur_echec();
}
printf("\nServeur fermer correctement...\n");
fin_serveur_succes();
}
void fin_serveur_echec() {
// On supprime l'espace réservé à la file.
if (shm_unlink(NOM_FILE) == -1) {
perror("shm_unlink");
}
exit(EXIT_FAILURE);
}
void fin_serveur_succes() {
// On supprime l'espace réservé à la file.
if (shm_unlink(NOM_FILE) == -1) {
perror("shm_unlink");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
} |