- 1.
void ajoute_commande(int *n,struct commande **tc,struct commande *c) {
int i, j;
/* On alloue de la place pour une commande supplémentaire */
(*n)++;
*tc = realloc(*tc,*n * sizeof(struct commande));
/* On recherche la position de la nouvelle commande */
for (i=0; i<(*n)-1 && (*tc)[i].quand<=c->quand; i++);
/* On décale les commandes suivantes */
for (j=(*n); j>i; j--)
(*tc)[j] = (*tc)[j-1];
/* On insère la nouvelle commande à sa place */
(*tc)[i] = *c;
}
void enleve_premier(int *n,struct commande **tc) {
int i;
/* On libère la mémoire utilisée par la première commande */
for (i=0; i<(*tc)[0].argc; i++)
free((*tc)[0].argv[i]);
free((*tc)[0].argv);
/* On décale les élements d'indice 1 à n-1 en 0 à n-2 */
for (i=1; i<*n; i++) (*tc)[i-1] = (*tc)[i];
/* On libère la place inutilement occupée */
*tc = realloc(*tc, *n * sizeof(struct commande));
(*n)--;
}
- 2.
void lance(char *argv[]) {
switch(fork()) {
case -1:
fprintf(stderr,"fork() raté\n");
break;
case 0:
execvp(argv[0],argv);
fprintf(stderr,"exec() raté\n");
exit(EXIT_FAILURE);
}
}
- 3.
struct entete_requete_tube {
size_t taille;
};
struct requete_tube {
time_t quand;
int argc;
};
void cree_requete(int *tr,int quand,char **buffer,int argc,char *argv[]) {
struct entete_requete_tube *ert;
struct requete_tube *rt;
int i;
*tr = sizeof(struct entete_requete_tube)+sizeof(struct requete_tube);
*buffer = malloc(*tr);
for (i=0; i<argc; i++) {
*buffer = realloc(*buffer,*tr+strlen(argv[i])+1);
strcpy((*buffer)+*tr,argv[i]);
*tr += strlen(argv[i])+1;
}
ert = (struct entete_requete_tube *)(*buffer);
rt = (struct requete_tube *)(ert+1);
ert->taille = *tr-sizeof(struct entete_requete_tube);
rt->quand = quand;
rt->argc = argc;
}
- 4.
int main(int argc,char *argv[]) {
int tube;
char *buffer;
int quand;
size_t taille;
if (argc<3) {
fprintf(stderr,"Il manque des arguments\n");
exit(EXIT_FAILURE);
}
quand = -1;
sscanf(argv[1],"%d",&quand);
if (quand<1) {
fprintf(stderr,"%d valeur impossible\n",quand);
exit(EXIT_FAILURE);
}
tube = open(TUBE_SERVEUR,O_WRONLY);
if (tube==-1) {
fprintf(stderr,"Erreur ouverture de %s\n",TUBE_SERVEUR);
exit(EXIT_FAILURE);
}
cree_requete(&taille,quand,&buffer,argc-2,argv+2);
if (write(tube,buffer,taille)!=taille) {
fprintf(stderr,"Probleme d'ecriture\n");
free(buffer);
close(tube);
exit(EXIT_FAILURE);
}
free(buffer);
close(tube);
exit(EXIT_SUCCESS);
}
- 5.
void a_faire(int signal) {
int i;
time_t reference;
/* On exécute toutes les commandes qui devaient l'être */
reference = liste_commandes[0].quand;
while (n_requetes && liste_commandes[0].quand==reference) {
lance(liste_commandes[0].argv);
enleve_premier(&n_requetes,&liste_commandes);
}
/* On modifie le délai des requêtes suivantes car une partie
du délai a été consommé */
for (i=0; i<n_requetes; i++) {
liste_commandes[i].quand -= reference;
}
/* S'il reste des requêtes on enregistre une alarme */
if (n_requetes) alarm(liste_commandes[0].quand);
}
int main(int argc,char *argv[]) {
int tube, i;
ssize_t lu;
struct entete_requete_tube ert;
struct requete_tube *rt;
char *argv_tube;
char *buffer;
struct sigaction action;
unsigned int reste;
struct commande c;
if ( access(TUBE_SERVEUR,F_OK)==0 ) {
fprintf(stderr,"Le tube %s existe deja. Y a t'il un serveur ?\n",
TUBE_SERVEUR);
exit(EXIT_FAILURE);
}
if ( mkfifo(TUBE_SERVEUR,S_IRUSR|S_IWUSR)!=0 ) {
fprintf(stderr,"Impossible de créer %s\n",TUBE_SERVEUR);
exit(EXIT_FAILURE);
}
tube = open(TUBE_SERVEUR,O_RDONLY);
if ( tube==-1 ) {
fprintf(stderr,"Impossible d'ouvrir %s\n",TUBE_SERVEUR);
unlink(TUBE_SERVEUR);
exit(EXIT_FAILURE);
}
buffer = NULL;
liste_commandes = NULL;
n_requetes = 0;
/* On enregistre l'action à réaliser à l'épuisement d'une alarme */
action.sa_handler = a_faire;
sigemptyset(&(action.sa_mask));
action.sa_flags = 0;
sigaction(SIGALRM,&action,NULL);
/* Ce pauvre serveur est condammé */
while (1) {
/* On tente de lire une requête (sa longueur) */
do {
lu = read(tube,&ert,sizeof(struct entete_requete_tube));
} while (lu==-1 && errno==EINTR);
/* S'il n'y a plus d'écrivain on resynchronize sur l'ouverture */
if (lu==0) {
close(tube);
do {
tube = open(TUBE_SERVEUR,O_RDONLY);
} while (tube==-1 && errno==EINTR);
if ( tube==-1 ) {
fprintf(stderr,"Impossible d'ouvrir %s dans la boucle\n",TUBE_SERVEUR);
unlink(TUBE_SERVEUR);
exit(EXIT_FAILURE);
}
continue;
}
if (lu!=sizeof(struct entete_requete_tube)) {
fprintf(stderr,"Erreur de lecture entete\n");
break;
}
/* On annule l'alarme précédente */
reste = alarm(0);
/* On met à jour les délais */
for (i=0; i<n_requetes; i++) {
liste_commandes[i].quand -= liste_commandes[0].quand-reste;
}
/* On lit le reste */
buffer = malloc(ert.taille);
if ( buffer== NULL ) {
fprintf(stderr,"Erreur d'allocation buffer\n");
break;
}
if ( read(tube,buffer,ert.taille)!=ert.taille ) {
fprintf(stderr,"Erreur de lecture des donnees %d\n",ert.taille);
break;
}
/* On décode la requête pour fabriquer la structure adéquate */
rt = (struct requete_tube *)buffer;
buffer += sizeof(struct requete_tube);
c.quand = rt->quand;
c.argc = rt->argc;
c.argv = malloc((c.argc+1)*sizeof(char *));
if ( c.argv==NULL ) {
fprintf(stderr,"Erreur allocation argv\n");
break;
}
for (i=0; i<c.argc; i++) {
c.argv[i] = malloc(strlen(buffer)+1);
strcpy(c.argv[i],buffer);
buffer += strlen(buffer)+1;
}
free(rt);
c.argv[c.argc] = NULL;
/* Une commande de plus à faire */
ajoute_commande(&n_requetes,&liste_commandes,&c);
/* On enregistre la nouvelle alarme */
alarm(liste_commandes[0].quand);
}
fprintf(stderr,"Échec\n");
close(tube);
unlink(TUBE_SERVEUR);
exit(EXIT_FAILURE);
}