Esercizio 2 esame 29/05/2014
Parte 1:
Scrivere un programma con un solo parametro.
Come prima cosa il programma deve creare una directory con il path specificato nel parametro. Se la directory esiste gia' o si
verifica un errore nella creazione, il programma deve terminare. Chiameremo questa directory “directory-base”
Il programma usando inotify rimane in attesa e stampa una riga di log per ogni file o directory creato o cancellato nella
directory-base. (solo nella directory-base, non nelle sottodirectory).
Quando viene cancellata la directory-base il programma termina.
Parte 2:
Si estenda il programma dell'esercizio 1 per operare anche nelle sottodirectory. Quindi il programma “dovrebbe” stampare una
riga di log per ogni file o directory creata o cancellata in tutto il sottoalbero che ha nella directory-base la radice.
Nota: se necessario, usate strutture dati molto semplici come vettori o liste semplici, non preoccupatevi dell'efficienza.
In realta' per un problema nel design dell'API inotify, alcuni eventi di creazione di directory nidificate troppo vicini nel tempo
possono venir perduti.
Soluzione di Quadrelli
Risoluzione parte 1
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/inotify.h>
#define EVENT_SIZE (sizeof(struct inotify_event))
#define BUFFER_SIZE (100*(EVENT_SIZE+16))
/*dichiarazione di spy*/
void spy(char *path);
int main(int argc, char * argv[]){
if(argc!=2){
printf("Numero argomenti sbagliato\n");
return -1;
}else{
int res=mkdir(argv[1],(mode_t)0777);
if(res!=0)exit(-1);
else spy(argv[1]);
}
return 0;
}
/*metodo che utilizza la inotify*/
void spy(char *path){
int again=1;
int fd;
char buffer[BUFFER_SIZE];
/*inizializzo il File Descriptor dell inotify*/
fd=inotify_init();
/*aggiungo "handler" per creazioni, eliminazioni all'interno della cartella path e per la sua eliminazione*/
inotify_add_watch(fd,path, IN_CREATE | IN_DELETE | IN_DELETE_SELF);
/*ciclo del programma di attesa dei valori*/
printf("Entro in ascolto della cartella %s\n",path);
while(again){
int i=0;
int len=read(fd,buffer,BUFFER_SIZE);
while(i<len){
/*gestisco un evento alla volta*/
struct inotify_event *event =(struct inotify_event*)&buffer[i];
/*controllo eventuale creazione di un file o di una cartella*/
if(event->mask & IN_CREATE) {
/*distinguo i due casi distinti*/
if(event->mask & IN_ISDIR)
printf( "Cartella %s creata\n", event->name );
else
printf( "File %s creato\n", event->name );
}
/*controllo eventuale eliminazione di un file o di una cartella*/
else if(event->mask & IN_DELETE){
/*distinguo i due casi distinti*/
if(event->mask & IN_ISDIR)
printf( "Cartella %s eliminata\n", event->name );
else
printf( "File %s eliminato\n", event->name );
}
/*controllo eventuale eliminazione della cartella che sto controllando*/
else if(event->mask & IN_DELETE_SELF){
printf("Cartella in listening %s eliminata\n",path);
again=0; /*fermo il ciclo più esterno che esegue le read*/
}
/*avanzo all'evento successivo, se c'è*/
i += EVENT_SIZE + event->len;
}
}
}
Risoluzione Parte 2
Ho risolto l'esercizio senza utilizzare vettori o liste, come consigliato nel testo, ma utilizzando la fork.
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/inotify.h>
#define EVENT_SIZE (sizeof(struct inotify_event))
#define BUFFER_SIZE (100*(EVENT_SIZE+16))
/*dichiarazione di spy*/
int spy(char *path);
int main(int argc, char * argv[]){
if(argc!=2){
printf("Numero argomenti sbagliato\n");
return -1;
}else{
int res=mkdir(argv[1],(mode_t)0777);
if(res!=0)exit(-1);
else return spy(argv[1]);
}
}
/*metodo che utilizza la inotify*/
int spy(char *path){
int again=1;
int fd;
char buffer[BUFFER_SIZE];
/*inizializzo il File Descriptor dell inotify*/
fd=inotify_init();
/*aggiungo "handler" per creazioni, eliminazioni all'interno della cartella path e per la sua eliminazione*/
inotify_add_watch(fd,path, IN_CREATE | IN_DELETE | IN_DELETE_SELF);
/*ciclo del programma di attesa dei valori*/
printf("Entro in ascolto della cartella %s\n",path);
while(again){
int i=0;
int len=read(fd,buffer,BUFFER_SIZE);
while(i<len){
/*gestisco un evento alla volta*/
struct inotify_event *event =(struct inotify_event*)&buffer[i];
/*controllo eventuale creazione di un file o di una cartella*/
if(event->mask & IN_CREATE){
/*distinguo i due casi distinti*/
if(event->mask & IN_ISDIR){
int pid;
printf( "Cartella %s creata in %s\n",event->name,path);
pid=fork();
if(!pid){
char *newpath=malloc((strlen(path))+event->len+1); /*sommo 1 alla fine per lo /*/
strcpy(newpath,path);
strcat(newpath,"/");
strcat(newpath,event->name);
return spy(newpath);
}
}
else
printf("File %s creato in %s\n",event->name,path);
}
/*controllo eventuale eliminazione di un file o di una cartella*/
else if(event->mask & IN_DELETE){
/*distinguo i due casi distinti*/
if(!(event->mask & IN_ISDIR))
printf("File %s eliminato in %s\n",event->name,path);
}
/*controllo eventuale eliminazione della cartella che sto controllando*/
else if(event->mask & IN_DELETE_SELF){
printf("Cartella %s eliminata.\n",path);
again=0; /*fermo il ciclo più esterno che esegue le read*/
}
/*avanzo all'evento successivo, se c'è*/
i += EVENT_SIZE + event->len;
}
}
return 0;
}
Sfrutto la struttura gerarchica del filesystem per non preoccuparmi di possibili processi zombie. Il padre controlla la radice e ritornerà solo quando la radice sarà eliminata. Per eliminarla, bisogna prima "svuotarla", eliminando ogni file e directory al suo interno. Ciò mi assicura che ogni processo figlio (che sta controllando una sotto-cartella) terminerà prima del suo processo padre.