Esempio di inotify, e qualche correzione sui sysctl dei socket
authorSimone Piccardi <piccardi@gnulinux.it>
Fri, 20 Jul 2007 23:08:51 +0000 (23:08 +0000)
committerSimone Piccardi <piccardi@gnulinux.it>
Fri, 20 Jul 2007 23:08:51 +0000 (23:08 +0000)
fileadv.tex
sockctrl.tex
sources/inotify_monitor.c

index 2f9e795232e9c9d9489dcabb63887cd080f3b3cb..9da4c618f0d58531839af6058641e4b933e0afb2 100644 (file)
@@ -1309,10 +1309,10 @@ modifiche con una qualunque delle modalit
 illustrate in sez.~\ref{sec:file_multiplexing}.
 
 Infine l'interfaccia di \textit{inotify} consente di mettere sotto
-osservazione, oltre che una directory anche singoli file.  Una volta creata la
-coda di notifica si devono definire gli eventi da tenere sotto osservazione;
-questo viene fatto attraverso una \textsl{lista di osservazione} (o
-\textit{watch list}) che è associata alla coda. Per gestire la lista di
+osservazione, oltre che una directory, anche singoli file.  Una volta creata
+la coda di notifica si devono definire gli eventi da tenere sotto
+osservazione; questo viene fatto attraverso una \textsl{lista di osservazione}
+(o \textit{watch list}) che è associata alla coda. Per gestire la lista di
 osservazione l'interfaccia fornisce due funzioni, la prima di queste è
 \funcd{inotify\_add\_watch}, il cui prototipo è:
 \begin{prototype}{sys/inotify.h}
@@ -1325,7 +1325,7 @@ osservazione l'interfaccia fornisce due funzioni, la prima di queste 
   \begin{errlist}
   \item[\errcode{EACCESS}] non si ha accesso in lettura al file indicato.
   \item[\errcode{EINVAL}] \param{mask} non contiene eventi legali o \param{fd}
-    non è un filesystem di \textit{inotify}.
+    non è un file descriptor di \textit{inotify}.
   \item[\errcode{ENOSPC}] si è raggiunto il numero massimo di voci di
     osservazione o il kernel non ha potuto allocare una risorsa necessaria.
   \end{errlist}
@@ -1383,7 +1383,7 @@ flag della prima parte.
     \const{IN\_DELETE\_SELF}  &       &   È stato cancellato il file (o la
                                           directory) sotto osservazione.\\ 
     \const{IN\_MODIFY}        &$\bullet$& È stato modificato il file.\\ 
-    \const{IN\_MOVE\_SELF}    &         & è stato rinominato il file (o la
+    \const{IN\_MOVE\_SELF}    &         & È stato rinominato il file (o la
                                           directory) sotto osservazione.\\ 
     \const{IN\_MOVED\_FROM}   &$\bullet$& Un file è stato spostato fuori dalla
                                           directory sotto osservazione.\\ 
@@ -1468,12 +1468,14 @@ automaticamente rimosso dalla lista di osservazione e nessun ulteriore evento
 sarà più notificato.
 
 In caso di successo \func{inotify\_add\_watch} ritorna un intero positivo,
-detto \textit{watch descriptor}; è tramite questo valore che si identifica
-univocamente un \textsl{osservatore} su una coda di notifica, sia per quanto
-riguarda i risultati restituiti da \textit{inotify}, che per quanto riguarda
-la eventuale rimozione dello stesso; la seconda funzione per la gestione delle
-liste di osservazione è infatti \funcd{inotify\_rm\_watch}, che permette di
-rimuovere un \textsl{osservatore}; il suo prototipo è:
+detto \textit{watch descriptor}, che identifica univocamente un
+\textsl{osservatore} su una coda di notifica; esso viene usato per farvi
+riferimento sia riguardo i risultati restituiti da \textit{inotify}, che per
+la eventuale rimozione dello stesso. 
+
+La seconda funzione per la gestione delle code di notifica, che permette di
+rimuovere un \textsl{osservatore}, è \funcd{inotify\_rm\_watch}, ed il suo
+prototipo è:
 \begin{prototype}{sys/inotify.h}
   {int inotify\_rm\_watch(int fd, uint32\_t wd)}
 
@@ -1494,17 +1496,23 @@ La funzione rimuove dalla coda di notifica identificata dall'argomento
 \param{fd} l'osservatore identificato dal \textit{watch descriptor}
 \param{wd};\footnote{ovviamente deve essere usato per questo argomento un
   valore ritornato da \func{inotify\_add\_watch}, altrimenti si avrà un errore
-  di \errval{EINVAL}.} inoltre, contemporaneamente alla rimozione
-dell'osservatore, sulla coda di notifica verrà generato un evento di tipo
-\const{IN\_IGNORED} (vedi tab.~\ref{tab:inotify_read_event_flag}).
-
-
-Oltre che per la rimozione, il \textit{watch descriptor} viene usato anche per
-identificare l'evento a cui si fa riferimento nella lista dei risultati
-restituiti da \textit{inotify}; questi ultimi infatti vengono notificati alle
-applicazioni che usano l'interfaccia di \textit{inotify} come dati presenti in
-lettura su file descriptor creato con \func{inotify\_init}. 
-
+  di \errval{EINVAL}.} in caso di successo della rimozione, contemporaneamente
+alla cancellazione dell'osservatore, sulla coda di notifica verrà generato un
+evento di tipo \const{IN\_IGNORED} (vedi
+tab.~\ref{tab:inotify_read_event_flag}). Si tenga presente che se un file
+viene cancellato o un filesystem viene smontato i relativi osservatori vengono
+rimossi automaticamente e non è necessario utilizzare
+\func{inotify\_rm\_watch}.
+
+
+Come accennato l'interfaccia di \textit{inotify} prevede che gli eventi siano
+notificati come dati presenti in lettura sul file descriptor associato alla
+coda di notifica. Una applicazione pertanto dovrà leggere i dati da detto file
+con una \func{read}, che ritornerà sul buffer i dati presenti nella forma di
+una o più strutture di tipo \struct{inotify\_event} (la cui definizione è
+riportata in fig.~\ref{fig:inotify_event}). Qualora non siano presenti dati la
+\func{read} si bloccherà (a meno di non aver impostato il file descriptor in
+modalità non bloccante) fino all'arrivo di almeno un evento.
 
 \begin{figure}[!htb]
   \footnotesize \centering
@@ -1512,24 +1520,33 @@ lettura su file descriptor creato con \func{inotify\_init}.
     \includestruct{listati/inotify_event.h}
   \end{minipage} 
   \normalsize 
-  \caption{La struttura \structd{inotify\_event}.}
+  \caption{La struttura \structd{inotify\_event} usata dall'interfaccia di
+    \textit{inotify} per riportare gli eventi.}
   \label{fig:inotify_event}
 \end{figure}
 
-
-Inoltre l'interfaccia di \textit{inotify} permette di conoscere, come avviene
-per i file descriptor associati ai socket (si veda al proposito quanto
-trattato in sez.~\ref{sec:sock_ioctl_IP}) il numero di byte disponibili in
-lettura sul nostro file descriptor, utilizzando su di esso l'operazione
-\const{FIONREAD} con \func{ioctl}.\footnote{questa è una delle operazioni
-  speciali (che abbiamo visto in sez.~\ref{sec:file_ioctl}) che nel caso è
-  disponibile solo per i socket e per i file descriptor creati con
-  \func{inotify\_init}.} Questo consente anche di ottenere rapidamente il
-numero di file che sono cambiati.
-
-
-
-
+Una ulteriore caratteristica dell'interfaccia di \textit{inotify} è che essa
+permette di ottenere con \func{ioctl}, come per i file descriptor associati ai
+socket (si veda sez.~\ref{sec:sock_ioctl_IP}) il numero di byte disponibili in
+lettura sul file descriptor, utilizzando su di esso l'operazione
+\const{FIONREAD}.\footnote{questa è una delle operazioni speciali per i file
+  (vedi sez.~\ref{sec:file_ioctl}), che è disponibile solo per i socket e per
+  i file descriptor creati con \func{inotify\_init}.} Si può così utilizzare
+questa operazione, oltre che per predisporre una operazione di lettura con un
+buffer di dimensioni adeguate, anche per ottenere rapidamente il numero di
+file che sono cambiati.
+
+Una volta effettuata la lettura con \func{read} a ciascun evento sarà
+associata una struttura \struct{inotify\_event} contenente i rispettivi dati.
+Per identificare a quale file o directory l'evento corrisponde viene
+restituito nel campo \var{wd} il \textit{watch descriptor} con cui il relativo
+osservatore è stato registrato. Il campo \var{mask} contiene invece una
+maschera di bit che identifica il tipo di evento verificatosi; in essa
+compariranno sia i bit elencati nella prima parte di
+tab.~\ref{tab:inotify_event_watch}, che gli eventuali valori
+aggiuntivi\footnote{questi compaiono solo nel campo \var{maks} di
+  \struct{inotify\_event}, e  non utilizzabili in fase di registrazione
+  dell'osservatore.} di tab.~\ref{tab:inotify_read_event_flag}.
 
 \begin{table}[htb]
   \centering
@@ -1539,17 +1556,56 @@ numero di file che sono cambiati.
     \textbf{Flag}  & \textbf{Significato} \\
     \hline
     \hline
-    \const{IN\_IGNORED}    & .\\
-    \const{IN\_ISDIR}      & .\\
-    \const{IN\_Q\_OVERFLOW}& .\\
-    \const{IN\_UNMOUNT}    & .\\
+    \const{IN\_IGNORED}    & L'osservatore è stato rimosso, sia in maniera 
+                             esplicita con l'uso di \func{inotify\_rm\_watch}, 
+                             che in maniera implicita per la rimozione 
+                             dell'oggetto osservato o per lo smontaggio del
+                             filesystem su cui questo si trova.\\
+    \const{IN\_ISDIR}      & L'evento avvenuto fa riferimento ad una directory
+                             (consente così di distinguere, quando si pone
+                             sotto osservazione una directory, fra gli eventi
+                             relativi ad essa e quelli relativi ai file che
+                             essa contiene).\\
+    \const{IN\_Q\_OVERFLOW}& Si sono eccedute le dimensioni della coda degli
+                             eventi (\textit{overflow} della coda); in questo
+                             caso il valore di \var{wd} è $-1$.\footnotemark\\
+    \const{IN\_UNMOUNT}    & Il filesystem contenente l'oggetto posto sotto
+                             osservazione è stato smontato.\\
     \hline    
   \end{tabular}
   \caption{Le costanti che identificano i flag aggiuntivi usati nella maschera
-    binaria del campo \var{mask} di \structd{inotify\_event}.} 
+    binaria del campo \var{mask} di \struct{inotify\_event}.} 
   \label{tab:inotify_read_event_flag}
 \end{table}
 
+\footnotetext{la coda di notifica ha una dimensione massima specificata dal
+  parametro di sistema \procfile{/proc/sys/fs/inotify/max\_queued\_events} che
+  indica il numero massimo di eventi che possono essere mantenuti sulla
+  stessa; quando detto valore viene ecceduto gli ulteriori eventi vengono
+  scartati, ma viene comunque generato un evento di tipo
+  \const{IN\_Q\_OVERFLOW}.}
+
+Il campo \var{cookie} contiene invece un intero univoco che permette di
+identificare eventi correlati (per i quali avrà lo stesso valore), al momento
+viene utilizzato soltanto per rilevare lo spostamento di un file, consentendo
+così all'applicazione di collegare la corrispondente coppia di eventi
+\const{IN\_MOVED\_TO} e \const{IN\_MOVED\_FROM}.
+
+Infine due campi \var{name} e \var{len} sono utilizzati soltanto quando
+l'evento è relativo ad un file presente in una directory posta sotto
+osservazione, in tal caso essi contengono rispettivamente il nome del file
+(come pathname relativo alla directory osservata) e la relativa dimensione in
+byte. Il campo \var{name} viene sempre restituito come stringa terminata da
+NUL, con uno o più zeri di terminazione, a seconda di eventuali necessità di
+allineamento del risultato, ed il valore di \var{len} corrisponde al totale
+della dimensione di \var{name}, zeri aggiuntivi compresi. Questo significa che
+le dimensioni di ciascun evento di \textit{inotify} saranno pari al valore
+\code{sizeof(\struct{inotify\_event}) + len}.
+
+Vediamo allora un esempio dell'uso dell'interfaccia di \textit{inotify} con un
+semplice programma che permette di mettere sotto osservazione un file o una
+directory. 
+
 
 
 % TODO inserire anche inotify, vedi http://www.linuxjournal.com/article/8478
index 1c5bef9fad0e089d5ff1347285884206a166d4ff..85c26fa288373b8aaad2245a8c73b70a3367f159 100644 (file)
@@ -4190,11 +4190,20 @@ pagina di manuale (accessibile con \texttt{man 7 tcp}), sono i seguenti:
     che consente di diminuire il numero di pacchetti scambiati.}
 
 \item[\procrelfile{/proc/sys/net/ipv4}{tcp\_ecn}] Abilita il meccanismo della
-  \textit{Explicit Congestion Notification} (o ECN) definito
-  nell'\href{http://www.ietf.org/rfc/rfc2884.txt}{RFC~2884}. Si tenga presente
-  che se si abilita questa opzione si possono avere dei malfunzionamenti
-  apparentemente casuali dipendenti dalla destinazione, dovuti al fatto che
-  alcuni vecchi router non supportano il meccanismo ed alla sua attivazione
+  \textit{Explicit Congestion Notification} (in breve ECN) nelle connessioni
+  TCP. Questo è un meccanismo (è descritto in dettaglio
+  nell'\href{http://www.ietf.org/rfc/rfc3168.txt}{RFC~3168} mentre gli effetti
+  sulle prestazioni del suo utilizzo sono documentate
+  nell'\href{http://www.ietf.org/rfc/rfc2884.txt}{RFC~2884} ) che consente di
+  notificare quando una rotta o una rete è congestionata da un eccesso di
+  traffico, si può così essere avvisati e cercare rotte alternative oppure
+  diminuire l'emissione di pacchetti (in 
+
+
+  Si tenga presente che se si abilita questa opzione si possono avere dei
+  malfunzionamenti apparentemente casuali dipendenti dalla destinazione,
+  dovuti al fatto che alcuni vecchi router non supportano il meccanismo ed
+  alla sua attivazione
   scartano i relativi pacchetti.\\
 
 \item[\procrelfile{/proc/sys/net/ipv4}{tcp\_fack}] è un valore logico che
index d2c4f2dd543b684d340442327ff94297349782f9..92391cf39b5133c8ab49435f6c76a1878f0f8dee 100644 (file)
 
 /* Help printing routine */
 void usage(void);
+void printevent(unsigned int mask);
 
 int main(int argc, char *argv[]) 
 {
-    int i;
-    int fd;
+    int i, size;
+    int fd, wd;
+    char buffer[128*sizeof(struct inotify_event)];
     unsigned int mask=0;
+    struct inotify_event * event;
     /*
      * Input section: decode command line parameters 
      * Use getopt function
@@ -55,30 +58,28 @@ int main(int argc, char *argv[])
        /* 
         * Handling options 
         */ 
-       case 'h':                                             /* help option */
+       case 'h':       /* help option */
            printf("Wrong -h option use\n");
            usage();
-           return -1;
-           break;
-       case 'r':                                             /* read access */
+       case 'r':       /* read access */
            mask |= IN_ACCESS;
            break;
-       case 'w':                                            /* write access */
+       case 'w':       /* write access */
            mask |= IN_MODIFY;
            break;
-       case 'c':                                                /* creation */
+       case 'c':       /* creation */
            mask |= IN_CREATE;
            break;
-       case 'd':                                                /* deletion */
+       case 'd':       /* deletion */
            mask |= IN_DELETE;
            break;
-       case 'a':                                              /* all events */
+       case 'a':       /* all events */
            mask |= IN_ALL_EVENTS;
            break;
-       case '?':                                    /* unrecognized options */
+       case '?':       /* unrecognized options */
            printf("Unrecognized options -%c\n",optopt);
            usage();
-       default:                                       /* should not reached */
+       default:        /* should not reached */
            usage();
        }
     }
@@ -89,22 +90,40 @@ int main(int argc, char *argv[])
      *               Main code beginning
      * 
      * ***********************************************************/
-    if ((argc - optind) != 1) {          /* There must be remaing parameters */
+    /* There must be one argument */
+    if ((argc - optind) != 1) {  
        printf("Wrong number of arguments %d\n", argc - optind);
         usage();
     }
-    /* initalialize */
+    /* initalialize inotify */
     fd = inotify_init ();
     if (fd < 0)
         perror("Failing on inotify_init");
 
     /* add watch */
-    if (inotify_add_watch(fd, argv[1], mask) != 0) {
-       printf("Failing to add watched file %s; %s\n", 
-             argv[1], strerror(errno));
+    wd = inotify_add_watch(fd, argv[optind], mask);
+    if ( wd <= 0) {
+       printf("Failing to add watched file %s, mask %i; %s\n", 
+             argv[optind], mask, strerror(errno));
        exit(-1);
+    }    
+    /* 
+     * Main Loop: read events and print them
+     */
+    while (1) {
+       size = read(fd, buffer, sizeof(buffer));
+       
+       event = (struct inotify_event *) buffer;
+        if (wd != event->wd) {
+           printf("Error, getting different watch descriptor, %i and %i\n",
+                  wd, event->wd); 
+           exit(1);
+       }
+       printf("Observed event on %s\n", argv[optind-1+event->wd]);
+       if (event->name != NULL)
+           printf("On file %s\n", event->name);
+       printevent(event->mask);
     }
-
     return 0;
 
 }
@@ -114,7 +133,7 @@ int main(int argc, char *argv[])
 void usage(void) {
     printf("Program inotify_monitor: monitor file changes \n");
     printf("Usage:\n");
-    printf(" inotify_monitor [-h] -rwcd dirname/filename \n");
+    printf(" inotify_monitor [-h] -rwcd dirname/filename dir/file ... \n");
     printf("  -h          print this help\n");
     printf("  -w          watch write\n");
     printf("  -r          watch read\n");
@@ -123,3 +142,34 @@ void usage(void) {
     printf("  -a          watch all\n");
     exit(1);
 }
+
+void printevent(unsigned int mask) {
+    int i;
+    int val;
+    char * inotify_event[] = {
+       "IN_ACCESS", 
+       "IN_MODIFY", 
+       "IN_ATTRIB", 
+       "IN_CLOSE_WRITE", 
+       "IN_CLOSE_NOWRITE", 
+       "IN_OPEN", 
+       "IN_MOVED_FROM", 
+       "IN_MOVED_TO",
+       "IN_CREATE", 
+       "IN_DELETE", 
+       "IN_DELETE_SELF", 
+       "IN_MOVE_SELF", 
+       "ERROR!!!", 
+       "IN_UNMOUNT", 
+       "IN_Q_OVERFLOW", 
+       "IN_IGNORED"
+    };
+    
+    val=1;
+    for (i=0; i<16; i++) {
+       if (mask & val) 
+           printf("%s, ", inotify_event[i]); 
+       val = val << 1;
+    }
+    printf("\n");
+}