+una directory (il numero dei file contenuti, la dimensione totale, quante
+directory, link simbolici, file normali, ecc.) che saranno salvati in un
+segmento di memoria condivisa cui altri processi potranno accedere per
+ricavare la parte di informazione che interessa.
+
+In \figref{fig:ipc_dirmonitor_main} si è riportata la sezione principale del
+corpo del programma server, insieme alle definizioni delle altre funzioni
+usate nel programma e delle variabili globali, omettendo tutto quello che
+riguarda la gestione delle opzioni e la stampa delle istruzioni di uso a
+video; al solito il codice completo si trova con i sorgenti allegati nel file
+\file{DirMonitor.c}.
+
+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \begin{lstlisting}{}
+/* global variables for shared memory segment */
+struct DirProp {
+ int tot_size;
+ int tot_files;
+ int tot_regular;
+ int tot_fifo;
+ int tot_link;
+ int tot_dir;
+ int tot_block;
+ int tot_char;
+ int tot_sock;
+} *shmptr;
+int shmid;
+int mutex;
+/* main body */
+int main(int argc, char *argv[])
+{
+ int i;
+ key_t key;
+ ...
+ if ((argc - optind) != 1) { /* There must be remaing parameters */
+ printf("Wrong number of arguments %d\n", argc - optind);
+ usage();
+ }
+ if (chdir(argv[1])) { /* chdir to be sure dir exist */
+ perror("Cannot find directory to monitor");
+ }
+ Signal(SIGTERM, HandSIGTERM); /* set handlers for termination */
+ Signal(SIGINT, HandSIGTERM);
+ Signal(SIGQUIT, HandSIGTERM);
+ key = ftok("~/gapil/sources/DirMonitor.c", 1); /* define a key */
+ shmid = shmget(key, 4096, IPC_CREAT|0666); /* get a shared memory */
+ if (shmid < 0) {
+ perror("Cannot create shared memory");
+ exit(1);
+ }
+ if ( (shmptr = shmat(shmid, NULL, 0)) == NULL ) { /* attach to process */
+ perror("Cannot attach segment");
+ exit(1);
+ }
+ if ((mutex = MutexCreate(key)) == -1) { /* get a Mutex */
+ perror("Cannot create mutex");
+ exit(1);
+ }
+ /* main loop, monitor directory properties each 10 sec */
+ daemon(1, 0); /* demonize process, staying in monitored dir */
+ while (1) {
+ MutexLock(mutex); /* lock shared memory */
+ memset(shmptr, 0, sizeof(struct DirProp)); /* erase previous data */
+ DirScan(argv[1], ComputeValues); /* execute scan */
+ MutexUnlock(mutex); /* unlock shared memory */
+ sleep(pause); /* sleep until next watch */
+ }
+}
+ \end{lstlisting}
+ \end{minipage}
+ \normalsize
+ \caption{Codice della funzione principale del programma \file{DirMonitor.c}.}
+ \label{fig:ipc_dirmonitor_main}
+\end{figure}
+
+Il programma usa delle variabili globali (\texttt{\small 2--14}) per mantenere
+i valori relativi agli oggetti usati per la comunicazione inter-processo; si è
+definita inoltre una apposita struttura \struct{DirProp} che contiene i dati
+relativi alle proprietà che si vogliono mantenere nella memoria condivisa, per
+l'accesso da parte dei client.
+
+Il programma, dopo la sezione, omessa, relativa alla gestione delle opzioni da
+riga di comando (che si limitano alla eventuale stampa di un messaggio di
+aiuto a video ed all'impostazione della durata dell'intervallo con cui viene
+ripetuto il calcolo delle proprietà della directory) controlla (\texttt{\small
+ 21--24}) che sia stato specificato il parametro necessario contenente il
+nome della directory da tenere sotto controllo, senza il quale esce
+immediatamente con un messaggio di errore.
+
+Poi, per verificare che il parametro specifichi effettivamente una directory,
+si esegue (\texttt{\small 25--27}) su di esso una \func{chdir}, uscendo
+immediatamente in caso di errore. Questa funzione serve anche per impostare
+la directory di lavoro del programma nella directory da tenere sotto
+controllo, in vista del successivo uso della funzione
+\func{daemon}.\footnote{Si noti come si è potuta fare questa scelta,
+ nonostante le indicazioni illustrate in \secref{sec:sess_daemon}, per il
+ particolare scopo del programma, che necessita comunque di restare
+ all'interno di una directory.} Infine (\texttt{\small 28--30}) si installano
+i gestori per i vari segnali di terminazione che, avendo a che fare con un
+programma che deve essere eseguito come server, sono il solo strumento
+disponibile per concluderne l'esecuzione.
+
+Il passo successivo (\texttt{\small 31--44}) è quello di creare gli oggetti di
+intercomunicazione necessari. Si inizia costruendo (\texttt{\small 31}) la
+chiave da usare come riferimento con il nome del programma,\footnote{si è
+ usato un riferimento relativo alla home dell'utente, supposto che i sorgenti
+ di GaPiL siano stati installati direttamente in essa. Qualora si effettui
+ una installazione diversa si dovrà correggere il programma.} dopo di che si
+richiede (\texttt{\small 32}) la creazione di un segmento di memoria condivisa
+con \func{shmget} (una pagina di memoria è sufficiente per i dati che
+useremo), uscendo (\texttt{\small 33--36}) qualora la creazione non abbia
+successo.
+
+Una volta ottenutone l'identificatore in \var{shmid}, si può agganciare
+(\texttt{\small 37--40}) il segmento al processo con \func{shmat} anche in
+questo caso si esce qualora la funzione non abbia successo. Con l'indirizzo
+\var{shmptr} così ottenuto potremo poi accedere alla memoria condivisa, che,
+per come abbiamo lo abbiamo definito, sarà vista nella forma data da
+\struct{DirProp}. Infine (\texttt{\small 41--44}) utilizzando sempre la stessa
+chiave, si crea, tramite le funzioni di interfaccia già descritte in
+\secref{sec:ipc_sysv_sem}, anche un mutex, che utilizzeremo per regolare
+l'accesso alla memoria condivisa.
+
+Una volta completata l'inizializzazione e la creazione degli oggetti di
+intercomunicazione il programma entra nel ciclo principale (\texttt{\small
+ 45--54}) dove vengono eseguite indefinitamente le attività di monitoraggio.
+Il primo passo (\texttt{\small 46}) è eseguire \func{daemon} per proseguire con
+l'esecuzione in background come si conviene ad un programma demone; si noti
+che si è mantenuta, usando un valore non nullo del primo argomento, la
+directory di lavoro corrente.
+
+Una volta che il programma è andato in background l'esecuzione prosegue
+(\texttt{\small 47--53}) all'interno di un ciclo infinito: si inizia
+(\texttt{\small 48}) bloccando il mutex con \func{MutexLock} per poter
+accedere alla memoria condivisa (la funzione si bloccherà automaticamente se
+qualche client sta leggendo), poi (\texttt{\small 49}) si cancellano i valori
+precedentemente immagazzinati nella memoria condivisa con \func{memset}, e si
+esegue (\texttt{\small 50}) un nuovo calcolo degli stessi utilizzando la
+funzione \func{DirScan}; infine (\texttt{\small 51}) si sblocca il mutex con
+\func{MutexUnlock}, e si attende (\texttt{\small 52}) per il periodo di tempo
+specificato a riga di comando con l'opzione \code{-p} con una \func{sleep}.
+
+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \begin{lstlisting}{}
+/* Routine to compute directory properties inside DirScan */
+int ComputeValues(struct dirent * direntry)
+{
+ struct stat data;
+ stat(direntry->d_name, &data); /* get stat data */
+ shmptr->tot_size += data.st_size;
+ shmptr->tot_files++;
+ if (S_ISREG(data.st_mode)) shmptr->tot_regular++;
+ if (S_ISFIFO(data.st_mode)) shmptr->tot_fifo++;
+ if (S_ISLNK(data.st_mode)) shmptr->tot_link++;
+ if (S_ISDIR(data.st_mode)) shmptr->tot_dir++;
+ if (S_ISBLK(data.st_mode)) shmptr->tot_block++;
+ if (S_ISCHR(data.st_mode)) shmptr->tot_char++;
+ if (S_ISSOCK(data.st_mode)) shmptr->tot_sock++;
+ return 0;
+}
+/* Signal Handler to manage termination */
+void HandSIGTERM(int signo) {
+ MutexLock(mutex);
+ if (shmdt(shmptr)) {
+ perror("Error detaching shared memory");
+ exit(1);
+ }
+ if (shmctl(shmid, IPC_RMID, NULL)) {
+ perror("Cannot remove shared memory segment");
+ exit(1);
+ }
+ MutexRemove(mutex);
+ exit(0);
+}
+ \end{lstlisting}
+ \end{minipage}
+ \normalsize
+ \caption{Codice delle funzione ausiliarie usate da \file{DirMonitor.c}.}
+ \label{fig:ipc_dirmonitor_sub}
+\end{figure}