delle costanti sono definiti da macro di preprocessore nel file citato, e
possono variare da architettura a architettura; è pertanto necessario
riferirsi ad essi tramite i nomi simbolici. Le funzioni \func{perror} e
-\func{strerror} (vedi \secref{sec:sys_strerror}) possono essere usate per
+\func{strerror} (vedi sez.~\ref{sec:sys_strerror}) possono essere usate per
ottenere dei messaggi di errore più espliciti.
filesystem read-only.
\item \errcode{EMLINK} \textit{Too many links}. Ci sono troppi link al file (il
numero massimo è specificato dalla variabile \const{LINK\_MAX}, vedi
- \secref{sec:sys_limits}).
+ sez.~\ref{sec:sys_limits}).
\item \errcode{EPIPE} \textit{Broken pipe}. Non c'è un processo che stia
leggendo l'altro capo della pipe. Ogni funzione che restituisce questo
errore genera anche un segnale \const{SIGPIPE}, la cui azione predefinita è
Uno dei problemi che si presentano quando si deve operare contemporaneamente
su molti file usando le funzioni illustrate in
-\capref{cha:file_unix_interface} e \capref{cha:files_std_interface} è che si
-può essere bloccati nelle operazioni su un file mentre un altro potrebbe
+cap.~\ref{cha:file_unix_interface} e cap.~\ref{cha:files_std_interface} è che
+si può essere bloccati nelle operazioni su un file mentre un altro potrebbe
essere disponibile. L'\textit{I/O multiplexing} nasce risposta a questo
problema. In questa sezione forniremo una introduzione a questa problematica
ed analizzeremo le varie funzioni usate per implementare questa modalità di
\subsection{La problematica dell'\textit{I/O multiplexing}}
\label{sec:file_noblocking}
-Abbiamo visto in \secref{sec:sig_gen_beha}, affrontando la suddivisione fra
+Abbiamo visto in sez.~\ref{sec:sig_gen_beha}, affrontando la suddivisione fra
\textit{fast} e \textit{slow} system call,\index{system call lente} che in
certi casi le funzioni di I/O possono bloccarsi indefinitamente.\footnote{si
ricordi però che questo può accadere solo per le pipe, i
da quanto si otterrebbe dal file descriptor ``\textsl{disponibile}'') si
potrebbe addirittura arrivare ad un \textit{deadlock}\index{deadlock}.
-Abbiamo già accennato in \secref{sec:file_open} che è possibile prevenire
+Abbiamo già accennato in sez.~\ref{sec:file_open} che è possibile prevenire
questo tipo di comportamento delle funzioni di I/O aprendo un file in quella
che viene chiamata \textsl{modalità non-bloccante}, attraverso l'uso del flag
\const{O\_NONBLOCK} nella chiamata di \func{open}. In questo caso le funzioni
mai un accesso bloccante, l'uso più comune delle funzioni che esamineremo nei
prossimi paragrafi è per i server di rete, in cui esse vengono utilizzate per
tenere sotto controllo dei socket; pertanto ritorneremo su di esse con
-ulteriori dettagli e qualche esempio in \secref{sec:TCP_sock_multiplexing}.
+ulteriori dettagli e qualche esempio in sez.~\ref{sec:TCP_sock_multiplexing}.
\subsection{Le funzioni \func{select} e \func{pselect}}
\end{functions}
La funzione mette il processo in stato di \textit{sleep} (vedi
-\tabref{tab:proc_proc_states}) fintanto che almeno uno dei file descriptor
+tab.~\ref{tab:proc_proc_states}) fintanto che almeno uno dei file descriptor
degli insiemi specificati (\param{readfds}, \param{writefds} e
\param{exceptfds}), non diventa attivo, per un tempo massimo specificato da
\param{timeout}.
funzione usa un particolare oggetto, il \textit{file descriptor set},
identificato dal tipo \type{fd\_set}, che serve ad identificare un insieme di
file descriptor, in maniera analoga a come un \textit{signal set} (vedi
-\secref{sec:sig_sigset}) identifica un insieme di segnali. Per la
+sez.~\ref{sec:sig_sigset}) identifica un insieme di segnali. Per la
manipolazione di questi \textit{file descriptor set} si possono usare delle
opportune macro di preprocessore:
\begin{functions}
\param{writefds}, per verificare la possibilità effettuare una scrittura ed il
terzo, \param{exceptfds}, per verificare l'esistenza di eccezioni (come i
messaggi urgenti su un \textit{socket}\index{socket}, vedi
-\secref{sec:TCP_urgent_data}).
+sez.~\ref{sec:TCP_urgent_data}).
Dato che in genere non si tengono mai sotto controllo fino a
\const{FD\_SETSIZE} file contemporaneamente la funzione richiede di
\end{prototype}
La funzione è sostanzialmente identica a \func{select}, solo che usa una
-struttura \struct{timespec} (vedi \figref{fig:sys_timeval_struct}) per
+struttura \struct{timespec} (vedi fig.~\ref{fig:sys_timeval_struct}) per
indicare con maggiore precisione il timeout e non ne aggiorna il valore in
caso di interruzione. Inoltre prende un argomento aggiuntivo \param{sigmask}
che è il puntatore ad una maschera di segnali (si veda
-\secref{sec:sig_sigmask}). La maschera corrente viene sostituita da questa
+sez.~\ref{sec:sig_sigmask}). La maschera corrente viene sostituita da questa
immediatamente prima di eseguire l'attesa, e ripristinata al ritorno della
funzione.
\acr{glibc} attraverso \func{select} e la possibilità di race condition
permane.} La tecnica classica è quella di utilizzare il gestore per
impostare una variabile globale e controllare questa nel corpo principale del
-programma; abbiamo visto in \secref{sec:sig_example} come questo lasci spazio
+programma; abbiamo visto in sez.~\ref{sec:sig_example} come questo lasci spazio
a possibili race condition, per cui diventa essenziale utilizzare
\func{sigprocmask} per disabilitare la ricezione del segnale prima di eseguire
il controllo e riabilitarlo dopo l'esecuzione delle relative operazioni, onde
Per questo è stata introdotta \func{pselect}, che attraverso l'argomento
\param{sigmask} permette di riabilitare la ricezione il segnale
contestualmente all'esecuzione della funzione, e ribloccandolo non appena essa
-ritorna. In questo modo il precedente codice potrebbe essere essere modificato
+ritorna. In questo modo il precedente codice potrebbe essere modificato
nel seguente modo:
\includecodesnip{listati/pselect_norace.c}
in questo caso utilizzando \var{oldmask} durante l'esecuzione di
Per ciascun file da controllare deve essere inizializzata una struttura
\struct{pollfd} nel vettore indicato dall'argomento \param{ufds}. La
-struttura, la cui definizione è riportata in \figref{fig:file_pollfd}, prevede
-tre campi: in \var{fd} deve essere indicato il numero del file descriptor da
-controllare, in \var{events} deve essere specificata una maschera binaria di
-flag che indichino il tipo di evento che si vuole controllare, mentre in
-\var{revents} il kernel restituirà il relativo risultato. Usando un valore
-negativo per \param{fd} la corrispondente struttura sarà ignorata da
-\func{poll}. Dato che i dati in ingresso sono del tutto indipendenti da quelli
-in uscita (che vengono restituiti in \var{revents}) non è necessario
-reinizializzare tutte le volte il valore delle strutture \struct{pollfd} a
-meno di non voler cambiare qualche condizione.
+struttura, la cui definizione è riportata in fig.~\ref{fig:file_pollfd},
+prevede tre campi: in \var{fd} deve essere indicato il numero del file
+descriptor da controllare, in \var{events} deve essere specificata una
+maschera binaria di flag che indichino il tipo di evento che si vuole
+controllare, mentre in \var{revents} il kernel restituirà il relativo
+risultato. Usando un valore negativo per \param{fd} la corrispondente
+struttura sarà ignorata da \func{poll}. Dato che i dati in ingresso sono del
+tutto indipendenti da quelli in uscita (che vengono restituiti in
+\var{revents}) non è necessario reinizializzare tutte le volte il valore delle
+strutture \struct{pollfd} a meno di non voler cambiare qualche condizione.
Le costanti che definiscono i valori relativi ai bit usati nelle maschere
binarie dei campi \var{events} e \var{revents} sono riportati in
-\tabref{tab:file_pollfd_flags}, insieme al loro significato. Le si sono
+tab.~\ref{tab:file_pollfd_flags}, insieme al loro significato. Le si sono
suddivise in tre gruppi, nel primo gruppo si sono indicati i bit utilizzati
per controllare l'attività in ingresso, nel secondo quelli per l'attività in
uscita, mentre il terzo gruppo contiene dei valori che vengono utilizzati solo
costanti, in quanto per essi sono definite tre classi di dati:
\textsl{normali}, \textit{prioritari} ed \textit{urgenti}. In Linux la
distinzione ha senso solo per i dati \textit{out-of-band} dei socket (vedi
-\secref{sec:TCP_urgent_data}), ma su questo e su come \func{poll} reagisce
-alle varie condizioni dei socket torneremo in \secref{sec:TCP_serv_poll}, dove
-vedremo anche un esempio del suo utilizzo. Si tenga conto comunque che le
+sez.~\ref{sec:TCP_urgent_data}), ma su questo e su come \func{poll} reagisce
+alle varie condizioni dei socket torneremo in sez.~\ref{sec:TCP_serv_poll},
+dove vedremo anche un esempio del suo utilizzo. Si tenga conto comunque che le
costanti relative ai diversi tipi di dati (come \macro{POLLRDNORM} e
\macro{POLLRDBAND}) sono utilizzabili soltanto qualora si sia definita la
macro \macro{\_XOPEN\_SOURCE}.\footnote{e ci si ricordi di farlo sempre in
In caso di successo funzione ritorna restituendo il numero di file (un valore
positivo) per i quali si è verificata una delle condizioni di attesa richieste
o per i quali si è verificato un errore (nel qual caso vengono utilizzati i
-valori di \tabref{tab:file_pollfd_flags} esclusivi di \var{revents}). Un
+valori di tab.~\ref{tab:file_pollfd_flags} esclusivi di \var{revents}). Un
valore nullo indica che si è raggiunto il timeout, mentre un valore negativo
indica un errore nella chiamata, il cui codice viene riportato al solito
tramite \var{errno}.
\subsection{Operazioni asincrone sui file}
\label{sec:file_asyncronous_operation}
-Abbiamo accennato in \secref{sec:file_open} che è possibile, attraverso l'uso
+Abbiamo accennato in sez.~\ref{sec:file_open} che è possibile, attraverso l'uso
del flag \const{O\_ASYNC},\footnote{l'uso del flag di \const{O\_ASYNC} e dei
comandi \const{F\_SETOWN} e \const{F\_GETOWN} per \func{fcntl} è specifico
di Linux e BSD.} aprire un file in modalità asincrona, così come è possibile
attivare in un secondo tempo questa modalità impostando questo flag attraverso
l'uso di \func{fcntl} con il comando \const{F\_SETFL} (vedi
-\secref{sec:file_fcntl}).
+sez.~\ref{sec:file_fcntl}).
In realtà in questo caso non si tratta di eseguire delle operazioni di lettura
o scrittura del file in modo asincrono (tratteremo questo, che più
propriamente è detto \textsl{I/O asincrono} in
-\secref{sec:file_asyncronous_io}), quanto di un meccanismo asincrono di
+sez.~\ref{sec:file_asyncronous_io}), quanto di un meccanismo asincrono di
notifica delle variazione dello stato del file descriptor aperto in questo
modo.
riconoscere il file descriptor che li ha emessi. In questo caso infatti si può
fare ricorso alle informazioni aggiuntive restituite attraverso la struttura
\struct{siginfo\_t}, utilizzando la forma estesa \var{sa\_sigaction} del
-gestore (si riveda quanto illustrato in \secref{sec:sig_sigaction}).
+gestore (si riveda quanto illustrato in sez.~\ref{sec:sig_sigaction}).
Per far questo però occorre utilizzare le funzionalità dei segnali real-time
-(vedi \secref{sec:sig_real_time}) impostando esplicitamente con il comando
+(vedi sez.~\ref{sec:sig_real_time}) impostando esplicitamente con il comando
\const{F\_SETSIG} di \func{fcntl} un segnale real-time da inviare in caso di
I/O asincrono (il segnale predefinito è \const{SIGIO}). In questo caso il
gestore, tutte le volte che riceverà \const{SI\_SIGIO} come valore del
attraverso l'uso di una apposita struttura \struct{aiocb} (il cui nome sta per
\textit{asyncronous I/O control block}), che viene passata come argomento a
tutte le funzioni dell'interfaccia. La sua definizione, come effettuata in
-\file{aio.h}, è riportata in \figref{fig:file_aiocb}. Nello steso file è
+\file{aio.h}, è riportata in fig.~\ref{fig:file_aiocb}. Nello steso file è
definita la macro \macro{\_POSIX\_ASYNCHRONOUS\_IO}, che dichiara la
disponibilità dell'interfaccia per l'I/O asincrono.
piattaforma supporti questa caratteristica, questo viene indicato definendo
le macro \macro{\_POSIX\_PRIORITIZED\_IO}, e
\macro{\_POSIX\_PRIORITY\_SCHEDULING}.} La priorità viene impostata a
-partire da quella del processo chiamante (vedi \secref{sec:proc_priority}),
+partire da quella del processo chiamante (vedi sez.~\ref{sec:proc_priority}),
cui viene sottratto il valore di questo campo. Il campo
\var{aio\_lio\_opcode} è usato solo dalla funzione \func{lio\_listio}, che,
come vedremo, permette di eseguire con una sola chiamata una serie di
Infine il campo \var{aio\_sigevent} è una struttura di tipo \struct{sigevent}
che serve a specificare il modo in cui si vuole che venga effettuata la
notifica del completamento delle operazioni richieste. La struttura è
-riportata in \secref{fig:file_sigevent}; il campo \var{sigev\_notify} è quello
-che indica le modalità della notifica, esso può assumere i tre valori:
+riportata in fig.~\ref{fig:file_sigevent}; il campo \var{sigev\_notify} è
+quello che indica le modalità della notifica, esso può assumere i tre valori:
\begin{basedescript}{\desclabelwidth{2.6cm}}
\item[\const{SIGEV\_NONE}] Non viene inviata nessuna notifica.
\item[\const{SIGEV\_SIGNAL}] La notifica viene effettuata inviando al processo
chiamante il segnale specificato da \var{sigev\_signo}; se il gestore di
questo è stato installato con \const{SA\_SIGINFO} gli verrà restituito il
valore di \var{sigev\_value} (la cui definizione è in
- \figref{fig:sig_sigval}) come valore del campo \var{si\_value} di
+ fig.~\ref{fig:sig_sigval}) come valore del campo \var{si\_value} di
\struct{siginfo\_t}.
\item[\const{SIGEV\_THREAD}] La notifica viene effettuata creando un nuovo
thread che esegue la funzione specificata da \var{sigev\_notify\_function}
potrebbero anche emergere nelle fasi successive delle operazioni. Lettura e
scrittura avvengono alla posizione indicata da \var{aio\_offset}, a meno che
il file non sia stato aperto in \textit{append mode} (vedi
-\secref{sec:file_open}), nel qual caso le scritture vengono effettuate
+sez.~\ref{sec:file_open}), nel qual caso le scritture vengono effettuate
comunque alla fine de file, nell'ordine delle chiamate a \func{aio\_write}.
Si tenga inoltre presente che deallocare la memoria indirizzata da
modalità di esecuzione, se si specifica il valore \const{O\_DSYNC} le
operazioni saranno completate con una chiamata a \func{fdatasync}, se si
specifica \const{O\_SYNC} con una chiamata a \func{fsync} (per i dettagli vedi
-\secref{sec:file_sync}).
+sez.~\ref{sec:file_sync}).
Il successo della chiamata assicura la sincronizzazione delle operazioni fino
allora richieste, niente è garantito riguardo la sincronizzazione dei dati
Oltre alle precedenti modalità di \textit{I/O multiplexing} e \textsl{I/O
asincrono}, esistono altre funzioni che implementano delle modalità di
accesso ai file più evolute rispetto alle normali funzioni di lettura e
-scrittura che abbiamo esaminato in \secref{sec:file_base_func}. In questa
+scrittura che abbiamo esaminato in sez.~\ref{sec:file_base_func}. In questa
sezione allora prenderemo in esame le interfacce per l'\textsl{I/O
vettorizzato} e per l'\textsl{I/O mappato in memoria}.
\end{functions}
Entrambe le funzioni usano una struttura \struct{iovec}, definita in
-\figref{fig:file_iovec}, che definisce dove i dati devono essere letti o
+fig.~\ref{fig:file_iovec}, che definisce dove i dati devono essere letti o
scritti. Il primo campo, \var{iov\_base}, contiene l'indirizzo del buffer ed
il secondo, \var{iov\_len}, la dimensione dello stesso.
\label{sec:file_memory_map}
Una modalità alternativa di I/O, che usa una interfaccia completamente diversa
-rispetto a quella classica vista in \capref{cha:file_unix_interface}, è il
+rispetto a quella classica vista in cap.~\ref{cha:file_unix_interface}, è il
cosiddetto \textit{memory-mapped I/O}, che, attraverso il meccanismo della
\textsl{paginazione}\index{paginazione} usato dalla memoria virtuale (vedi
-\secref{sec:proc_mem_gen}), permette di \textsl{mappare} il contenuto di un
+sez.~\ref{sec:proc_mem_gen}), permette di \textsl{mappare} il contenuto di un
file in una sezione dello spazio di indirizzi del processo. Il meccanismo è
-illustrato in \figref{fig:file_mmap_layout}, una sezione del file viene
+illustrato in fig.~\ref{fig:file_mmap_layout}, una sezione del file viene
riportata direttamente nello spazio degli indirizzi del programma. Tutte le
operazioni su questa zona verranno riportate indietro sul file dal meccanismo
della memoria virtuale\index{memoria virtuale} che trasferirà il contenuto di
\textit{segment violation}, e la relativa emissione del segnale
\const{SIGSEGV}.} da applicare al segmento di memoria e deve essere
specificato come maschera binaria ottenuta dall'OR di uno o più dei valori
-riportati in \tabref{tab:file_mmap_flag}; il valore specificato deve essere
+riportati in tab.~\ref{tab:file_mmap_flag}; il valore specificato deve essere
compatibile con la modalità di accesso con cui si è aperto il file.
L'argomento \param{flags} specifica infine qual'è il tipo di oggetto mappato,
modalità con cui le modifiche alla memoria mappata vengono condivise o
mantenute private al processo che le ha effettuate. Deve essere specificato
come maschera binaria ottenuta dall'OR di uno o più dei valori riportati in
-\tabref{tab:file_mmap_flag}.
+tab.~\ref{tab:file_mmap_flag}.
\begin{table}[htb]
\centering
eseguita su un segmento di dimensioni rigorosamente multiple di quelle di una
pagina, ed in generale queste potranno non corrispondere alle dimensioni
effettive del file o della sezione che si vuole mappare. Il caso più comune è
-quello illustrato in \figref{fig:file_mmap_boundary}, in cui la sezione di
+quello illustrato in fig.~\ref{fig:file_mmap_boundary}, in cui la sezione di
file non rientra nei confini di una pagina: in tal caso verrà il file sarà
mappato su un segmento di memoria che si estende fino al bordo della pagina
successiva.
contenuto del file, vale esattamente quanto visto in precedenza; invece per la
parte che eccede, fino alle dimensioni date da \param{length}, l'accesso non
sarà più possibile, ma il segnale emesso non sarà \const{SIGSEGV}, ma
-\const{SIGBUS}, come illustrato in \figref{fig:file_mmap_exceed}.
+\const{SIGBUS}, come illustrato in fig.~\ref{fig:file_mmap_exceed}.
Non tutti i file possono venire mappati in memoria, dato che, come illustrato
-in \figref{fig:file_mmap_layout}, la mappatura introduce una corrispondenza
+in fig.~\ref{fig:file_mmap_layout}, la mappatura introduce una corrispondenza
biunivoca fra una sezione di un file ed una sezione di memoria. Questo
comporta che ad esempio non è possibile mappare in memoria file descriptor
relativi a pipe, socket e fifo, per i quali non ha senso parlare di
\textsl{sezione}. Lo stesso vale anche per alcuni file di dispositivo, che non
dispongono della relativa operazione \func{mmap} (si ricordi quanto esposto in
-\secref{sec:file_vfs_work}). Si tenga presente però che esistono anche casi di
-dispositivi (un esempio è l'interfaccia al ponte PCI-VME del chip Universe)
+sez.~\ref{sec:file_vfs_work}). Si tenga presente però che esistono anche casi
+di dispositivi (un esempio è l'interfaccia al ponte PCI-VME del chip Universe)
che sono utilizzabili solo con questa interfaccia.
Dato che passando attraverso una \func{fork} lo spazio di indirizzi viene
nuovo programma.
Quando si effettua la mappatura di un file vengono pure modificati i tempi ad
-esso associati (di cui si è trattato in \secref{sec:file_file_times}). Il
+esso associati (di cui si è trattato in sez.~\ref{sec:file_file_times}). Il
valore di \var{st\_atime} può venir cambiato in qualunque istante a partire
dal momento in cui la mappatura è stata effettuata: il primo riferimento ad
una pagina mappata su un file aggiorna questo tempo. I valori di
Dato per i file mappati in memoria le operazioni di I/O sono gestite
direttamente dalla memoria virtuale, occorre essere consapevoli delle
interazioni che possono esserci con operazioni effettuate con l'interfaccia
-standard dei file di \capref{cha:file_unix_interface}. Il problema è che una
+standard dei file di cap.~\ref{cha:file_unix_interface}. Il problema è che una
volta che si è mappato un file, le operazioni di lettura e scrittura saranno
eseguite sulla memoria, e riportate su disco in maniera autonoma dal sistema
della memoria virtuale.
\end{table}
L'argomento \param{flag} è specificato come maschera binaria composta da un OR
-dei valori riportati in \tabref{tab:file_mmap_rsync}, di questi però
+dei valori riportati in tab.~\ref{tab:file_mmap_rsync}, di questi però
\const{MS\_ASYNC} e \const{MS\_SYNC} sono incompatibili; con il primo valore
infatti la funzione si limita ad inoltrare la richiesta di sincronizzazione al
meccanismo della memoria virtuale, ritornando subito, mentre con il secondo
\label{sec:file_locking}
\index{file!locking|(}
-In \secref{sec:file_sharing} abbiamo preso in esame le modalità in cui un
+In sez.~\ref{sec:file_sharing} abbiamo preso in esame le modalità in cui un
sistema unix-like gestisce la condivisione dei file da parte di processi
diversi. In quell'occasione si è visto come, con l'eccezione dei file aperti
in \textit{append mode}, quando più processi scrivono contemporaneamente sullo
il processo prosegue l'esecuzione, altrimenti (a meno di non aver richiesto un
comportamento non bloccante) viene posto in stato di sleep. Una volta finite
le operazioni sul file si deve provvedere a rimuovere il lock. La situazione
-delle varie possibilità è riassunta in \tabref{tab:file_file_lock}, dove si
+delle varie possibilità è riassunta in tab.~\ref{tab:file_file_lock}, dove si
sono riportati, per le varie tipologie di lock presenti su un file, il
risultato che si ha in corrispondenza alle due tipologie di \textit{file lock}
menzionate, nel successo della richiesta.
a seconda di quanto specificato tramite il valore dell'argomento
\param{operation}, questo viene interpretato come maschera binaria, e deve
essere passato utilizzando le costanti riportate in
-\tabref{tab:file_flock_operation}.
+tab.~\ref{tab:file_flock_operation}.
\begin{table}[htb]
\centering
differenze occorre descrivere con maggiore dettaglio come viene realizzato il
file locking nel kernel in entrambe le interfacce.
-In \figref{fig:file_flock_struct} si è riportato uno schema essenziale
+In fig.~\ref{fig:file_flock_struct} si è riportato uno schema essenziale
dell'implementazione del file locking in stile BSD in Linux; il punto
fondamentale da capire è che un lock, qualunque sia l'interfaccia che si usa,
anche se richiesto attraverso un file descriptor, agisce sempre su un file;
perciò le informazioni relative agli eventuali \textit{file lock} sono
mantenute a livello di inode\index{inode},\footnote{in particolare, come
- accennato in \figref{fig:file_flock_struct}, i \textit{file lock} sono
+ accennato in fig.~\ref{fig:file_flock_struct}, i \textit{file lock} sono
mantenuti un una \textit{linked list}\index{linked list} di strutture
\struct{file\_lock}. La lista è referenziata dall'indirizzo di partenza
mantenuto dal campo \var{i\_flock} della struttura \struct{inode} (per le
dei lock creati con \func{flock} la semantica della funzione prevede che sia
\func{dup} che \func{fork} non creino ulteriori istanze di un file lock quanto
piuttosto degli ulteriori riferimenti allo stesso. Questo viene realizzato dal
-kernel secondo lo schema di \figref{fig:file_flock_struct}, associando ad ogni
-nuovo \textit{file lock} un puntatore\footnote{il puntatore è mantenuto nel
- campo \var{fl\_file} di \struct{file\_lock}, e viene utilizzato solo per i
- lock creati con la semantica BSD.} alla voce nella \textit{file table} da
+kernel secondo lo schema di fig.~\ref{fig:file_flock_struct}, associando ad
+ogni nuovo \textit{file lock} un puntatore\footnote{il puntatore è mantenuto
+ nel campo \var{fl\_file} di \struct{file\_lock}, e viene utilizzato solo per
+ i lock creati con la semantica BSD.} alla voce nella \textit{file table} da
cui si è richiesto il lock, che così ne identifica il titolare.
Questa struttura prevede che, quando si richiede la rimozione di un file lock,
il kernel acconsenta solo se la richiesta proviene da un file descriptor che
fa riferimento ad una voce nella file table corrispondente a quella registrata
-nel lock. Allora se ricordiamo quanto visto in \secref{sec:file_dup} e
-\secref{sec:file_sharing}, e cioè che i file descriptor duplicati e quelli
+nel lock. Allora se ricordiamo quanto visto in sez.~\ref{sec:file_dup} e
+sez.~\ref{sec:file_sharing}, e cioè che i file descriptor duplicati e quelli
ereditati in un processo figlio puntano sempre alla stessa voce nella file
table, si può capire immediatamente quali sono le conseguenze nei confronti
delle funzioni \func{dup} e \func{fork}.
La seconda interfaccia per l'\textit{advisory locking} disponibile in Linux è
quella standardizzata da POSIX, basata sulla funzione \func{fcntl}. Abbiamo
già trattato questa funzione nelle sue molteplici possibilità di utilizzo in
-\secref{sec:file_fcntl}. Quando la si impiega per il \textit{file locking}
+sez.~\ref{sec:file_fcntl}. Quando la si impiega per il \textit{file locking}
essa viene usata solo secondo il prototipo:
\begin{prototype}{fcntl.h}{int fcntl(int fd, int cmd, struct flock *lock)}
al singolo byte. Inoltre la funzione permette di ottenere alcune informazioni
relative agli eventuali lock preesistenti. Per poter fare tutto questo la
funzione utilizza come terzo argomento una apposita struttura \struct{flock}
-(la cui definizione è riportata in \figref{fig:struct_flock}) nella quale
+(la cui definizione è riportata in fig.~\ref{fig:struct_flock}) nella quale
inserire tutti i dati relativi ad un determinato lock. Si tenga presente poi
che un lock fa sempre riferimento ad una regione, per cui si potrà avere un
conflitto anche se c'è soltanto una sovrapposizione parziale con un'altra
contare \var{l\_start}. Il valore di \var{l\_whence} segue la stessa semantica
dell'omonimo argomento di \func{lseek}, coi tre possibili valori
\const{SEEK\_SET}, \const{SEEK\_CUR} e \const{SEEK\_END}, (si vedano le
-relative descrizioni in \secref{sec:file_lseek}).
+relative descrizioni in sez.~\ref{sec:file_lseek}).
Si tenga presente che un lock può essere richiesto anche per una regione al di
là della corrente fine del file, così che una eventuale estensione dello
Il tipo di file lock richiesto viene specificato dal campo \var{l\_type}, esso
può assumere i tre valori definiti dalle costanti riportate in
-\tabref{tab:file_flock_type}, che permettono di richiedere rispettivamente uno
-\textit{shared lock}, un \textit{esclusive lock}, e la rimozione di un lock
-precedentemente acquisito. Infine il campo \var{l\_pid} viene usato solo in
-caso di lettura, quando si chiama \func{fcntl} con \const{F\_GETLK}, e riporta
-il \acr{pid} del processo che detiene il lock.
+tab.~\ref{tab:file_flock_type}, che permettono di richiedere rispettivamente
+uno \textit{shared lock}, un \textit{esclusive lock}, e la rimozione di un
+lock precedentemente acquisito. Infine il campo \var{l\_pid} viene usato solo
+in caso di lettura, quando si chiama \func{fcntl} con \const{F\_GETLK}, e
+riporta il \acr{pid} del processo che detiene il lock.
Oltre a quanto richiesto tramite i campi di \struct{flock}, l'operazione
effettivamente svolta dalla funzione è stabilita dal valore dall'argomento
-\param{cmd} che, come già riportato in \secref{sec:file_fcntl}, specifica
+\param{cmd} che, come già riportato in sez.~\ref{sec:file_fcntl}, specifica
l'azione da compiere; i valori relativi al file locking sono tre:
\begin{basedescript}{\desclabelwidth{2.0cm}}
\item[\const{F\_GETLK}] verifica se il file lock specificato dalla struttura
Non operando a livello di interi file, il file locking POSIX introduce
un'ulteriore complicazione; consideriamo la situazione illustrata in
-\figref{fig:file_flock_dead}, in cui il processo A blocca la regione 1 e il
+fig.~\ref{fig:file_flock_dead}, in cui il processo A blocca la regione 1 e il
processo B la regione 2. Supponiamo che successivamente il processo A richieda
un lock sulla regione 2 che non può essere acquisito per il preesistente lock
del processo 2; il processo 1 si bloccherà fintanto che il processo 2 non
Per capire meglio il funzionamento del file locking in semantica POSIX (che
-differisce alquanto rispetto da quello di BSD, visto \secref{sec:file_flock})
-esaminiamo più in dettaglio come viene gestito dal kernel. Lo schema delle
-strutture utilizzate è riportato in \figref{fig:file_posix_lock}; come si vede
-esso è molto simile all'analogo di \figref{fig:file_flock_struct}:\footnote{in
- questo caso nella figura si sono evidenziati solo i campi di
- \struct{file\_lock} significativi per la semantica POSIX, in particolare
- adesso ciascuna struttura contiene, oltre al \acr{pid} del processo in
- \var{fl\_pid}, la sezione di file che viene bloccata grazie ai campi
- \var{fl\_start} e \var{fl\_end}. La struttura è comunque la stessa, solo
- che in questo caso nel campo \var{fl\_flags} è impostato il bit
- \const{FL\_POSIX} ed il campo \var{fl\_file} non viene usato.} il lock è
-sempre associato all'inode\index{inode}, solo che in questo caso la titolarità
-non viene identificata con il riferimento ad una voce nella file table, ma con
-il valore del \acr{pid} del processo.
+differisce alquanto rispetto da quello di BSD, visto
+sez.~\ref{sec:file_flock}) esaminiamo più in dettaglio come viene gestito dal
+kernel. Lo schema delle strutture utilizzate è riportato in
+fig.~\ref{fig:file_posix_lock}; come si vede esso è molto simile all'analogo
+di fig.~\ref{fig:file_flock_struct}:\footnote{in questo caso nella figura si
+ sono evidenziati solo i campi di \struct{file\_lock} significativi per la
+ semantica POSIX, in particolare adesso ciascuna struttura contiene, oltre al
+ \acr{pid} del processo in \var{fl\_pid}, la sezione di file che viene
+ bloccata grazie ai campi \var{fl\_start} e \var{fl\_end}. La struttura è
+ comunque la stessa, solo che in questo caso nel campo \var{fl\_flags} è
+ impostato il bit \const{FL\_POSIX} ed il campo \var{fl\_file} non viene
+ usato.} il lock è sempre associato all'inode\index{inode}, solo che in
+questo caso la titolarità non viene identificata con il riferimento ad una
+voce nella file table, ma con il valore del \acr{pid} del processo.
Quando si richiede un lock il kernel effettua una scansione di tutti i lock
presenti sul file\footnote{scandisce cioè la linked list delle strutture
Per fare qualche esempio sul file locking si è scritto un programma che
permette di bloccare una sezione di un file usando la semantica POSIX, o un
-intero file usando la semantica BSD; in \figref{fig:file_flock_code} è
+intero file usando la semantica BSD; in fig.~\ref{fig:file_flock_code} è
riportata il corpo principale del codice del programma, (il testo completo è
allegato nella directory dei sorgenti).
Il comportamento della funzione dipende dal valore dell'argomento \param{cmd},
che specifica quale azione eseguire; i valori possibili sono riportati in
-\tabref{tab:file_lockf_type}.
+tab.~\ref{tab:file_lockf_type}.
\begin{table}[htb]
\centering
Per poter utilizzare il \textit{mandatory locking} è stato introdotto un
utilizzo particolare del bit \acr{sgid}. Se si ricorda quanto esposto in
-\secref{sec:file_suid_sgid}), esso viene di norma utilizzato per cambiare il
+sez.~\ref{sec:file_suid_sgid}), esso viene di norma utilizzato per cambiare il
group-ID effettivo con cui viene eseguito un programma, ed è pertanto sempre
associato alla presenza del permesso di esecuzione per il gruppo. Impostando
questo bit su un file senza permesso di esecuzione in un sistema che supporta
originariamente non contemplata, in quanto senza significato, diventa
l'indicazione della presenza o meno del \textit{mandatory
locking}.\footnote{un lettore attento potrebbe ricordare quanto detto in
- \secref{sec:file_chmod} e cioè che il bit \acr{sgid} viene cancellato (come
+ sez.~\ref{sec:file_chmod} e cioè che il bit \acr{sgid} viene cancellato (come
misura di sicurezza) quando di scrive su un file, questo non vale quando
esso viene utilizzato per attivare il \textit{mandatory locking}.}
su un file su cui è attivo un lock. Per questo motivo l'abilitazione del
mandatory locking è di norma disabilitata, e deve essere attivata filesystem
per filesystem in fase di montaggio (specificando l'apposita opzione di
-\func{mount} riportata in \tabref{tab:sys_mount_flags}, o con l'opzione
+\func{mount} riportata in tab.~\ref{tab:sys_mount_flags}, o con l'opzione
\cmd{mand} per il comando).
Si tenga presente inoltre che il \textit{mandatory locking} funziona solo
L'ultimo aspetto della interazione del \textit{mandatory locking} con le
funzioni di accesso ai file è quello relativo ai file mappati in memoria (che
-abbiamo trattato in \secref{sec:file_memory_map}); anche in tal caso infatti,
+abbiamo trattato in sez.~\ref{sec:file_memory_map}); anche in tal caso infatti,
quando si esegue la mappatura con l'opzione \const{MAP\_SHARED}, si ha un
accesso al contenuto del file. Lo standard SVID prevede che sia impossibile
eseguire il memory mapping di un file su cui sono presenti dei
\section{La gestione di file e directory}
\label{sec:file_dir}
-Come già accennato in \secref{sec:file_filesystem} in un sistema unix-like la
+Come già accennato in sez.~\ref{sec:file_filesystem} in un sistema unix-like la
gestione dei file ha delle caratteristiche specifiche che derivano
direttamente dall'architettura del sistema.
Questo è possibile anche in ambiente Unix, dove tali collegamenti sono
usualmente chiamati \textit{link}; ma data l'architettura del sistema riguardo
la gestione dei file (ed in particolare quanto trattato in
-\secref{sec:file_arch_func}) ci sono due metodi sostanzialmente diversi per
+sez.~\ref{sec:file_arch_func}) ci sono due metodi sostanzialmente diversi per
fare questa operazione.
-Come spiegato in \secref{sec:file_filesystem} l'accesso al contenuto di un
+Come spiegato in sez.~\ref{sec:file_filesystem} l'accesso al contenuto di un
file su disco avviene passando attraverso il suo inode\index{inode}, che è la
struttura usata dal kernel che lo identifica univocamente all'interno di un
singolo filesystem. Il nome del file che si trova nella voce di una directory
già.
\item[\errcode{EMLINK}] ci sono troppi link al file \param{oldpath} (il
numero massimo è specificato dalla variabile \const{LINK\_MAX}, vedi
- \secref{sec:sys_limits}).
+ sez.~\ref{sec:sys_limits}).
\end{errlist}
ed inoltre \errval{EACCES}, \errval{ENAMETOOLONG}, \errval{ENOTDIR},
\errval{EFAULT}, \errval{ENOMEM}, \errval{EROFS}, \errval{ELOOP},
collegamento diretto non copia il contenuto del file, ma si limita a creare
una voce nella directory specificata da \param{newpath} e ad aumentare di uno
il numero di riferimenti al file (riportato nel campo \var{st\_nlink} della
-struttura \struct{stat}, vedi \secref{sec:file_stat}) aggiungendo il nuovo
+struttura \struct{stat}, vedi sez.~\ref{sec:file_stat}) aggiungendo il nuovo
nome ai precedenti. Si noti che uno stesso file può essere così chiamato con
vari nomi in diverse directory.
-Per quanto dicevamo in \secref{sec:file_filesystem} la creazione di un
+Per quanto dicevamo in sez.~\ref{sec:file_filesystem} la creazione di un
collegamento diretto è possibile solo se entrambi i pathname sono nello stesso
filesystem; inoltre il filesystem deve supportare i collegamenti diretti (il
meccanismo non è disponibile ad esempio con il filesystem \acr{vfat} di
l'amministratore è in grado di creare un collegamento diretto ad un'altra
directory: questo viene fatto perché con una tale operazione è possibile
creare dei \textit{loop} nel filesystem (vedi l'esempio mostrato in
-\secref{sec:file_symlink}, dove riprenderemo il discorso) che molti programmi
+sez.~\ref{sec:file_symlink}, dove riprenderemo il discorso) che molti programmi
non sono in grado di gestire e la cui rimozione diventerebbe estremamente
complicata (in genere per questo tipo di errori occorre far girare il
programma \cmd{fsck} per riparare il filesystem).
\end{prototype}
\footnotetext{questo è un valore specifico ritornato da Linux che non consente
- l'uso di \func{unlink} con le directory (vedi \secref{sec:file_remove}). Non
- è conforme allo standard POSIX, che prescrive invece l'uso di
+ l'uso di \func{unlink} con le directory (vedi sez.~\ref{sec:file_remove}).
+ Non è conforme allo standard POSIX, che prescrive invece l'uso di
\errcode{EPERM} in caso l'operazione non sia consentita o il processo non
abbia privilegi sufficienti.}
scrittura su di essa, dato che si va a rimuovere una voce dal suo contenuto, e
il diritto di esecuzione sulla directory che la contiene (affronteremo in
dettaglio l'argomento dei permessi di file e directory in
-\secref{sec:file_access_control}). Se inoltre lo \textit{sticky} bit (vedi
-\secref{sec:file_sticky}) è impostato occorrerà anche essere proprietari del
+sez.~\ref{sec:file_access_control}). Se inoltre lo \textit{sticky} bit (vedi
+sez.~\ref{sec:file_sticky}) è impostato occorrerà anche essere proprietari del
file o proprietari della directory (o root, per cui nessuna delle restrizioni
è applicata).
Una delle caratteristiche di queste funzioni è che la creazione/rimozione del
nome dalla directory e l'incremento/decremento del numero di riferimenti
nell'inode\index{inode} devono essere effettuati in maniera atomica (si veda
-\secref{sec:proc_atom_oper}) senza possibili interruzioni fra le due
+sez.~\ref{sec:proc_atom_oper}) senza possibili interruzioni fra le due
operazioni. Per questo entrambe queste funzioni sono realizzate tramite una
singola system call.
count} mantenuto nell'inode\index{inode} diventa zero lo spazio occupato su
disco viene rimosso (si ricordi comunque che a questo si aggiunge sempre
un'ulteriore condizione,\footnote{come vedremo in
- \secref{cha:file_unix_interface} il kernel mantiene anche una tabella dei
+ cap.~\ref{cha:file_unix_interface} il kernel mantiene anche una tabella dei
file aperti nei vari processi, che a sua volta contiene i riferimenti agli
inode ad essi relativi. Prima di procedere alla cancellazione dello spazio
occupato su disco dal contenuto di un file il kernel controlla anche questa
temporanei su disco in caso di crash dei programmi; la tecnica è quella di
aprire il file e chiamare \func{unlink} subito dopo, in questo modo il
contenuto del file è sempre disponibile all'interno del processo attraverso il
-suo file descriptor (vedi \secref{sec:file_fd}) fintanto che il processo non
+suo file descriptor (vedi sez.~\ref{sec:file_fd}) fintanto che il processo non
chiude il file, ma non ne resta traccia in nessuna directory, e lo spazio
occupato su disco viene immediatamente rilasciato alla conclusione del
processo (quando tutti i file vengono chiusi).
Al contrario di quanto avviene con altri Unix, in Linux non è possibile usare
\func{unlink} sulle directory; per cancellare una directory si può usare la
-funzione \func{rmdir} (vedi \secref{sec:file_dir_creat_rem}), oppure la
+funzione \func{rmdir} (vedi sez.~\ref{sec:file_dir_creat_rem}), oppure la
funzione \funcd{remove}.
Questa è la funzione prevista dallo standard ANSI C per cancellare un file o
\subsection{I link simbolici}
\label{sec:file_symlink}
-Come abbiamo visto in \secref{sec:file_link} la funzione \func{link} crea
+Come abbiamo visto in sez.~\ref{sec:file_link} la funzione \func{link} crea
riferimenti agli inode\index{inode}, pertanto può funzionare soltanto per file
che risiedono sullo stesso filesystem e solo per un filesystem di tipo Unix.
Inoltre abbiamo visto che in Linux non è consentito eseguire un link diretto
Il sistema funziona in quanto i link simbolici sono riconosciuti come tali dal
kernel\footnote{è uno dei diversi tipi di file visti in
- \tabref{tab:file_file_types}, contrassegnato come tale nell'inode, e
+ tab.~\ref{tab:file_file_types}, contrassegnato come tale nell'inode, e
riconoscibile dal valore del campo \var{st\_mode} della struttura
- \struct{stat} (vedi \secref{sec:file_stat}).} per cui alcune funzioni di
+ \struct{stat} (vedi sez.~\ref{sec:file_stat}).} per cui alcune funzioni di
libreria (come \func{open} o \func{stat}) quando ricevono come argomento un
link simbolico vengono automaticamente applicate al file da esso specificato.
La funzione che permette di creare un nuovo link simbolico è \funcd{symlink},
\textit{dangling link}, letteralmente un \textsl{link ciondolante}.
Come accennato i link simbolici sono risolti automaticamente dal kernel
-all'invocazione delle varie system call; in \tabref{tab:file_symb_effect} si è
-riportato un elenco dei comportamenti delle varie funzioni di libreria che
+all'invocazione delle varie system call; in tab.~\ref{tab:file_symb_effect} si
+è riportato un elenco dei comportamenti delle varie funzioni di libreria che
operano sui file nei confronti della risoluzione dei link simbolici,
specificando quali seguono il link simbolico e quali invece possono operare
direttamente sul suo contenuto.
Si noti che non si è specificato il comportamento delle funzioni che operano
con i file descriptor, in quanto la risoluzione del link simbolico viene in
genere effettuata dalla funzione che restituisce il file descriptor
-(normalmente la \func{open}, vedi \secref{sec:file_open}) e tutte le
+(normalmente la \func{open}, vedi sez.~\ref{sec:file_open}) e tutte le
operazioni seguenti fanno riferimento solo a quest'ultimo.
-Dato che, come indicato in \tabref{tab:file_symb_effect}, funzioni come la
+Dato che, come indicato in tab.~\ref{tab:file_symb_effect}, funzioni come la
\func{open} seguono i link simbolici, occorrono funzioni apposite per accedere
alle informazioni del link invece che a quelle del file a cui esso fa
riferimento. Quando si vuole leggere il contenuto di un link simbolico si usa
Un caso comune che si può avere con i link simbolici è la creazione dei
cosiddetti \textit{loop}. La situazione è illustrata in
-\figref{fig:file_link_loop}, che riporta la struttura della directory
+fig.~\ref{fig:file_link_loop}, che riporta la struttura della directory
\file{/boot}. Come si vede si è creato al suo interno un link simbolico che
punta di nuovo a \file{/boot}.\footnote{il loop mostrato in
- \figref{fig:file_link_loop} è un usato per poter permettere a \cmd{grub} (un
- bootloader in grado di leggere direttamente da vari filesystem il file da
- lanciare come sistema operativo) di vedere i file contenuti nella directory
- \file{/boot} con lo stesso pathname con cui verrebbero visti dal sistema
- operativo, anche se essi si trovano, come accade spesso, su una partizione
- separata (che \cmd{grub}, all'avvio, vede come radice).}
+ fig.~\ref{fig:file_link_loop} è un usato per poter permettere a \cmd{grub}
+ (un bootloader in grado di leggere direttamente da vari filesystem il file
+ da lanciare come sistema operativo) di vedere i file contenuti nella
+ directory \file{/boot} con lo stesso pathname con cui verrebbero visti dal
+ sistema operativo, anche se essi si trovano, come accade spesso, su una
+ partizione separata (che \cmd{grub}, all'avvio, vede come radice).}
Questo può causare problemi per tutti quei programmi che effettuano la
scansione di una directory senza tener conto dei link simbolici, ad esempio se
\param{dirname}. Il nome può essere indicato sia come pathname assoluto che
relativo.
-I permessi di accesso alla directory (vedi \secref{sec:file_access_control})
+I permessi di accesso alla directory (vedi sez.~\ref{sec:file_access_control})
sono specificati da \param{mode}, i cui possibili valori sono riportati in
-\tabref{tab:file_permission_const}; questi sono modificati dalla maschera di
-creazione dei file (si veda \secref{sec:file_umask}). La titolarità della
+tab.~\ref{tab:file_permission_const}; questi sono modificati dalla maschera di
+creazione dei file (si veda sez.~\ref{sec:file_umask}). La titolarità della
nuova directory è impostata secondo quanto riportato in
-\secref{sec:file_ownership}.
+sez.~\ref{sec:file_ownership}.
La funzione per la cancellazione di una directory è \funcd{rmdir}, il suo
prototipo è:
\label{sec:file_mknod}
Finora abbiamo parlato esclusivamente di file, directory e link simbolici; in
-\secref{sec:file_file_types} abbiamo visto però che il sistema prevede pure
+sez.~\ref{sec:file_file_types} abbiamo visto però che il sistema prevede pure
degli altri tipi di file speciali, come i file di dispositivo
\index{file!di dispositivo}
e le fifo (i socket\index{socket} sono un caso a parte, che
-vedremo in \capref{cha:socket_intro}).
+vedremo in cap.~\ref{cha:socket_intro}).
La manipolazione delle caratteristiche di questi file e la loro cancellazione
può essere effettuata con le stesse funzioni che operano sui file regolari; ma
La funzione permette di creare un file speciale, ma si può usare anche per
creare file regolari e fifo; l'argomento \param{mode} specifica il tipo di
file che si vuole creare ed i relativi permessi, secondo i valori riportati in
-\tabref{tab:file_mode_flags}, che vanno combinati con un OR binario. I
+tab.~\ref{tab:file_mode_flags}, che vanno combinati con un OR binario. I
permessi sono comunque modificati nella maniera usuale dal valore di
-\var{umask} (si veda \secref{sec:file_umask}).
+\var{umask} (si veda sez.~\ref{sec:file_umask}).
Per il tipo di file può essere specificato solo uno fra: \const{S\_IFREG} per
un file regolare (che sarà creato vuoto), \const{S\_IFBLK} per un device a
I nuovi inode\index{inode} creati con \func{mknod} apparterranno al
proprietario e al gruppo del processo che li ha creati, a meno che non si sia
attivato il bit \acr{sgid} per la directory o sia stata attivata la semantica
-BSD per il filesystem (si veda \secref{sec:file_ownership}) in cui si va a
+BSD per il filesystem (si veda sez.~\ref{sec:file_ownership}) in cui si va a
creare l'inode\index{inode}.
Per creare una fifo (un file speciale, su cui torneremo in dettaglio in
-\secref{sec:ipc_named_pipe}) lo standard POSIX specifica l'uso della funzione
+sez.~\ref{sec:ipc_named_pipe}) lo standard POSIX specifica l'uso della funzione
\funcd{mkfifo}, il cui prototipo è:
\begin{functions}
\headdecl{sys/types.h} \headdecl{sys/stat.h}
Ma se la scrittura e l'aggiornamento dei dati delle directory è compito del
kernel, sono molte le situazioni in cui i processi necessitano di poterne
leggere il contenuto. Benché questo possa essere fatto direttamente (vedremo
-in \secref{sec:file_open} che è possibile aprire una directory come se fosse
+in sez.~\ref{sec:file_open} che è possibile aprire una directory come se fosse
un file, anche se solo in sola lettura) in generale il formato con cui esse
sono scritte può dipendere dal tipo di filesystem, tanto che, come riportato
-in \tabref{tab:file_file_operations}, il VFS del kernel prevede una apposita
+in tab.~\ref{tab:file_file_operations}, il VFS del kernel prevede una apposita
funzione per la lettura delle directory.
Tutto questo si riflette nello standard POSIX\footnote{le funzioni sono
previste pure in BSD e SVID.} che ha introdotto una apposita interfaccia per
la lettura delle directory, basata sui cosiddetti \textit{directory stream}
(chiamati così per l'analogia con i file stream dell'interfaccia standard di
-\capref{cha:files_std_interface}). La prima funzione di questa interfaccia è
+cap.~\ref{cha:files_std_interface}). La prima funzione di questa interfaccia è
\funcd{opendir}, il cui prototipo è:
\begin{functions}
\headdecl{sys/types.h} \headdecl{dirent.h}
descriptor associato al \textit{directory stream} \param{dir}, essa è
disponibile solo definendo \macro{\_BSD\_SOURCE} o \macro{\_SVID\_SOURCE}. Di
solito si utilizza questa funzione in abbinamento alla funzione \func{fchdir}
-per cambiare la directory di lavoro (vedi \secref{sec:file_work_dir}) a quella
-relativa allo stream che si sta esaminando.
+per cambiare la directory di lavoro (vedi sez.~\ref{sec:file_work_dir}) a
+quella relativa allo stream che si sta esaminando.
La lettura di una voce della directory viene effettuata attraverso la funzione
\funcd{readdir}; il suo prototipo è:
nel file \file{/usr/include/bits/dirent.h}, essa non contempla la presenza
del campo \var{d\_namlen} che indica la lunghezza del nome del file (ed
infatti la macro \macro{\_DIRENT\_HAVE\_D\_NAMLEN} non è definita).} è
-riportata in \figref{fig:file_dirent_struct}). La funzione restituisce il
+riportata in fig.~\ref{fig:file_dirent_struct}). La funzione restituisce il
puntatore alla struttura; si tenga presente però che quest'ultima è allocata
staticamente, per cui viene sovrascritta tutte le volte che si ripete la
lettura di una voce sullo stesso stream.
possibili valori\footnote{fino alla versione 2.1 delle \acr{glibc} questo
campo, pur presente nella struttura, non è implementato, e resta sempre al
valore \const{DT\_UNKNOWN}.} sono riportati in
-\tabref{tab:file_dtype_macro}; per la conversione da e verso l'analogo valore
+tab.~\ref{tab:file_dtype_macro}; per la conversione da e verso l'analogo valore
mantenuto dentro il campo \var{st\_mode} di \struct{stat} sono definite anche
due macro di conversione \macro{IFTODT} e \macro{DTTOIF}:
\begin{functions}
dopo \func{file4}.)
Un semplice esempio dell'uso di queste funzioni è riportato in
-\figref{fig:file_my_ls}, dove si è riportata la sezione principale di un
+fig.~\ref{fig:file_my_ls}, dove si è riportata la sezione principale di un
programma che, usando la routine di scansione illustrata in
-\figref{fig:file_dirscan}, stampa i nomi dei file contenuti in una directory e
-la relativa dimensione (in sostanza una versione semplificata del comando
+fig.~\ref{fig:file_dirscan}, stampa i nomi dei file contenuti in una directory
+e la relativa dimensione (in sostanza una versione semplificata del comando
\cmd{ls}).
\begin{figure}[!htb]
\label{fig:file_my_ls}
\end{figure}
-Il programma è estremamente semplice; in \figref{fig:file_my_ls} si è omessa
+Il programma è estremamente semplice; in fig.~\ref{fig:file_my_ls} si è omessa
la parte di gestione delle opzioni (che prevede solo l'uso di una funzione per
la stampa della sintassi, anch'essa omessa) ma il codice completo potrà essere
trovato coi sorgenti allegati nel file \file{myls.c}.
\end{figure}
Tutto il grosso del lavoro è svolto dalla funzione \func{DirScan}, riportata
-in \figref{fig:file_dirscan}. La funzione è volutamente generica e permette di
-eseguire una funzione, passata come secondo argomento, su tutte le voci di una
-directory. La funzione inizia con l'aprire (\texttt{\small 19--23}) uno
+in fig.~\ref{fig:file_dirscan}. La funzione è volutamente generica e permette
+di eseguire una funzione, passata come secondo argomento, su tutte le voci di
+una directory. La funzione inizia con l'aprire (\texttt{\small 19--23}) uno
stream sulla directory passata come primo argomento, stampando un messaggio in
caso di errore.
Il passo successivo (\texttt{\small 24--25}) è cambiare directory di lavoro
-(vedi \secref{sec:file_work_dir}), usando in sequenza le funzione \func{dirfd}
-e \func{fchdir} (in realtà si sarebbe potuto usare direttamente \func{chdir}
-su \var{dirname}), in modo che durante il successivo ciclo (\texttt{\small
- 27--31}) sulle singole voci dello stream ci si trovi all'interno della
-directory.\footnote{questo è essenziale al funzionamento della funzione
- \code{do\_ls} (e ad ogni funzione che debba usare il campo \var{d\_name}, in
- quanto i nomi dei file memorizzati all'interno di una struttura
- \struct{dirent} sono sempre relativi alla directory in questione, e senza
- questo posizionamento non si sarebbe potuto usare \func{stat} per ottenere
- le dimensioni.}
+(vedi sez.~\ref{sec:file_work_dir}), usando in sequenza le funzione
+\func{dirfd} e \func{fchdir} (in realtà si sarebbe potuto usare direttamente
+\func{chdir} su \var{dirname}), in modo che durante il successivo ciclo
+(\texttt{\small 27--31}) sulle singole voci dello stream ci si trovi
+all'interno della directory.\footnote{questo è essenziale al funzionamento
+ della funzione \code{do\_ls} (e ad ogni funzione che debba usare il campo
+ \var{d\_name}, in quanto i nomi dei file memorizzati all'interno di una
+ struttura \struct{dirent} sono sempre relativi alla directory in questione,
+ e senza questo posizionamento non si sarebbe potuto usare \func{stat} per
+ ottenere le dimensioni.}
Avendo usato lo stratagemma di fare eseguire tutte le manipolazioni necessarie
alla funzione passata come secondo argomento, il ciclo di scansione della
consente di cambiarla a piacere, spostandosi da una directory ad un'altra, il
comando \cmd{pwd} la stampa sul terminale. Siccome la directory corrente
resta la stessa quando viene creato un processo figlio (vedi
-\secref{sec:proc_fork}), la directory corrente della shell diventa anche la
+sez.~\ref{sec:proc_fork}), la directory corrente della shell diventa anche la
directory corrente di qualunque comando da essa lanciato.
In genere il kernel tiene traccia per ciascun processo dell'inode\index{inode}
della lunghezza esatta del pathname altrimenti. In questo caso ci si deve
ricordare di disallocare la stringa una volta cessato il suo utilizzo.
-Di questa funzione esiste una versione \code{char *getwd(char *buffer)}
-fatta per compatibilità all'indietro con BSD, che non consente di specificare
-la dimensione del buffer; esso deve essere allocato in precedenza ed avere una
+Di questa funzione esiste una versione \code{char *getwd(char *buffer)} fatta
+per compatibilità all'indietro con BSD, che non consente di specificare la
+dimensione del buffer; esso deve essere allocato in precedenza ed avere una
dimensione superiore a \const{PATH\_MAX} (di solito 256 byte, vedi
-\secref{sec:sys_limits}); il problema è che in Linux non esiste una dimensione
-superiore per un pathname, per cui non è detto che il buffer sia sufficiente a
-contenere il nome del file, e questa è la ragione principale per cui questa
-funzione è deprecata.
+sez.~\ref{sec:sys_limits}); il problema è che in Linux non esiste una
+dimensione superiore per un pathname, per cui non è detto che il buffer sia
+sufficiente a contenere il nome del file, e questa è la ragione principale per
+cui questa funzione è deprecata.
Una seconda funzione simile è \code{char *get\_current\_dir\_name(void)} che è
sostanzialmente equivalente ad una \code{getcwd(NULL, 0)}, con la sola
creare il file dopo aver controllato che questo non esista, nel momento fra il
controllo e la creazione si ha giusto lo spazio per una possibile \textit{race
condition}\index{race condition} (si ricordi quanto visto in
-\secref{sec:proc_race_cond}).
+sez.~\ref{sec:proc_race_cond}).
Le \acr{glibc} provvedono varie funzioni per generare nomi di file temporanei,
di cui si abbia certezza di unicità (al momento della generazione); la prima
\begin{itemize*}
\item La variabile di ambiente \const{TMPNAME} (non ha effetto se non è
definita o se il programma chiamante è \acr{suid} o \acr{sgid}, vedi
- \secref{sec:file_suid_sgid}).
+ sez.~\ref{sec:file_suid_sgid}).
\item il valore dell'argomento \param{dir} (se diverso da \val{NULL}).
\item Il valore della costante \const{P\_tmpdir}.
\item la directory \file{/tmp}.
\errval{ENOSPC}, \errval{EROFS} e \errval{EACCES}.}
\end{prototype}
\noindent essa restituisce direttamente uno stream già aperto (in modalità
-\code{r+b}, si veda \secref{sec:file_fopen}) e pronto per l'uso, che viene
+\code{r+b}, si veda sez.~\ref{sec:file_fopen}) e pronto per l'uso, che viene
automaticamente cancellato alla sua chiusura o all'uscita dal programma. Lo
standard non specifica in quale directory verrà aperto il file, ma le
\acr{glibc} prima tentano con \const{P\_tmpdir} e poi con \file{/tmp}. Questa
\noindent come per \func{mktemp} anche in questo caso \param{template} non può
essere una stringa costante. La funzione apre un file in lettura/scrittura con
la funzione \func{open}, usando l'opzione \const{O\_EXCL} (si veda
-\secref{sec:file_open}), in questo modo al ritorno della funzione si ha la
+sez.~\ref{sec:file_open}), in questo modo al ritorno della funzione si ha la
certezza di essere i soli utenti del file. I permessi sono impostati al valore
\code{0600}\footnote{questo è vero a partire dalle \acr{glibc} 2.0.7, le
versioni precedenti delle \acr{glibc} e le vecchie \acr{libc5} e \acr{libc4}
usavano il valore \code{0666} che permetteva a chiunque di leggere i
- contenuti del file.} (si veda \secref{sec:file_perm_overview}).
+ contenuti del file.} (si veda sez.~\ref{sec:file_perm_overview}).
In OpenBSD è stata introdotta un'altra funzione\footnote{introdotta anche in
Linux a partire dalle \acr{glibc} 2.1.91.} simile alle precedenti,
più gli altri eventuali codici di errore di \func{mkdir}.}
\end{prototype}
\noindent la directory è creata con permessi \code{0700} (al solito si veda
-\capref{cha:file_unix_interface} per i dettagli); dato che la creazione della
+cap.~\ref{cha:file_unix_interface} per i dettagli); dato che la creazione della
directory è sempre esclusiva i precedenti problemi di \textit{race
condition}\index{race condition} non si pongono.
\section{La manipolazione delle caratteristiche dei files}
\label{sec:file_infos}
-Come spiegato in \secref{sec:file_filesystem} tutte le informazioni generali
+Come spiegato in sez.~\ref{sec:file_filesystem} tutte le informazioni generali
relative alle caratteristiche di ciascun file, a partire dalle informazioni
relative al controllo di accesso, sono mantenute nell'inode\index{inode}.
memorizzati nell'inode\index{inode}; esamineremo poi le varie funzioni usate
per manipolare tutte queste informazioni (eccetto quelle che riguardano la
gestione del controllo di accesso, trattate in in
-\secref{sec:file_access_control}).
+sez.~\ref{sec:file_access_control}).
\subsection{Le funzioni \func{stat}, \func{fstat} e \func{lstat}}
La struttura \struct{stat} usata da queste funzioni è definita nell'header
\file{sys/stat.h} e in generale dipende dall'implementazione; la versione
-usata da Linux è mostrata in \figref{fig:file_stat_struct}, così come
+usata da Linux è mostrata in fig.~\ref{fig:file_stat_struct}, così come
riportata dalla pagina di manuale di \func{stat} (in realtà la definizione
effettivamente usata nel kernel dipende dall'architettura e ha altri campi
riservati per estensioni come tempi più precisi, o per il padding dei campi).
Si noti come i vari membri della struttura siano specificati come tipi
primitivi del sistema (di quelli definiti in
-\tabref{tab:intro_primitive_types}, e dichiarati in \file{sys/types.h}).
+tab.~\ref{tab:intro_primitive_types}, e dichiarati in \file{sys/types.h}).
\subsection{I tipi di file}
\label{sec:file_types}
-Come riportato in \tabref{tab:file_file_types} in Linux oltre ai file e alle
+Come riportato in tab.~\ref{tab:file_file_types} in Linux oltre ai file e alle
directory esistono altri oggetti che possono stare su un filesystem. Il tipo
di file è ritornato dalla \func{stat} come maschera binaria nel campo
\var{st\_mode} (che contiene anche le informazioni relative ai permessi).
queste vengono usate anche da Linux che supporta pure le estensioni allo
standard per i link simbolici e i socket\index{socket} definite da BSD;
l'elenco completo delle macro con cui è possibile estrarre l'informazione da
-\var{st\_mode} è riportato in \tabref{tab:file_type_macro}.
+\var{st\_mode} è riportato in tab.~\ref{tab:file_type_macro}.
\begin{table}[htb]
\centering
\footnotesize
\label{tab:file_type_macro}
\end{table}
-Oltre alle macro di \tabref{tab:file_type_macro} è possibile usare
+Oltre alle macro di tab.~\ref{tab:file_type_macro} è possibile usare
direttamente il valore di \var{st\_mode} per ricavare il tipo di file
controllando direttamente i vari bit in esso memorizzati. Per questo sempre in
\file{sys/stat.h} sono definite le costanti numeriche riportate in
-\tabref{tab:file_mode_flags}.
+tab.~\ref{tab:file_mode_flags}.
-Il primo valore dell'elenco di \tabref{tab:file_mode_flags} è la maschera
+Il primo valore dell'elenco di tab.~\ref{tab:file_mode_flags} è la maschera
binaria che permette di estrarre i bit nei quali viene memorizzato il tipo di
file, i valori successivi sono le costanti corrispondenti ai singoli bit, e
possono essere usati per effettuare la selezione sul tipo di file voluto, con
detto che corrisponda all'occupazione dello spazio su disco per via della
possibile esistenza dei cosiddetti \textit{holes} (letteralmente
\textsl{buchi}) che si formano tutte le volte che si va a scrivere su un file
-dopo aver eseguito una \func{lseek} (vedi \secref{sec:file_lseek}) oltre la
+dopo aver eseguito una \func{lseek} (vedi sez.~\ref{sec:file_lseek}) oltre la
sua fine.
In questo caso si avranno risultati differenti a seconda del modo in cui si
Il sistema mantiene per ciascun file tre tempi. Questi sono registrati
nell'inode\index{inode} insieme agli altri attributi del file e possono essere
letti tramite la funzione \func{stat}, che li restituisce attraverso tre campi
-della struttura \struct{stat} di \figref{fig:file_stat_struct}. Il significato
-di detti tempi e dei relativi campi è riportato nello schema in
-\tabref{tab:file_file_times}, dove è anche riportato un esempio delle funzioni
-che effettuano cambiamenti su di essi.
+della struttura \struct{stat} di fig.~\ref{fig:file_stat_struct}. Il
+significato di detti tempi e dei relativi campi è riportato nello schema in
+tab.~\ref{tab:file_file_times}, dove è anche riportato un esempio delle
+funzioni che effettuano cambiamenti su di essi.
\begin{table}[htb]
\centering
tempo di cambiamento di stato) per decidere quali file devono essere
archiviati per il backup. Il comando \cmd{ls} (quando usato con le opzioni
\cmd{-l} o \cmd{-t}) mostra i tempi dei file secondo lo schema riportato
-nell'ultima colonna di \tabref{tab:file_file_times}.
+nell'ultima colonna di tab.~\ref{tab:file_file_times}.
\begin{table}[htb]
\centering
\end{table}
L'effetto delle varie funzioni di manipolazione dei file sui tempi è
-illustrato in \tabref{tab:file_times_effects}. Si sono riportati gli effetti
+illustrato in tab.~\ref{tab:file_times_effects}. Si sono riportati gli effetti
sia per il file a cui si fa riferimento, sia per la directory che lo contiene;
questi ultimi possono essere capiti se si tiene conto di quanto già detto, e
cioè che anche le directory sono file (che contengono una lista di nomi) che
La funzione prende come argomento \param{times} una struttura
\struct{utimebuf}, la cui definizione è riportata in
-\figref{fig:struct_utimebuf}, con la quale si possono specificare i nuovi
+fig.~\ref{fig:struct_utimebuf}, con la quale si possono specificare i nuovi
valori che si vogliono impostare per tempi.
\begin{figure}[!htb]
degli identificatori di utente e gruppo (\acr{uid} e \acr{gid}). Questi valori
sono accessibili da programma tramite la funzione \func{stat}, e sono
mantenuti nei campi \var{st\_uid} e \var{st\_gid} della struttura
-\struct{stat} (si veda \secref{sec:file_stat}).\footnote{Questo è vero solo
+\struct{stat} (si veda sez.~\ref{sec:file_stat}).\footnote{Questo è vero solo
per filesystem di tipo Unix, ad esempio non è vero per il filesystem vfat di
Windows, che non fornisce nessun supporto per l'accesso multiutente, e per
il quale i permessi vengono assegnati in maniera fissa con un opzione in
I restanti tre bit (noti come \acr{suid}, \acr{sgid}, e \textsl{sticky}) sono
usati per indicare alcune caratteristiche più complesse del meccanismo del
controllo di accesso su cui torneremo in seguito (in
-\secref{sec:file_suid_sgid} e \secref{sec:file_sticky}); lo schema di
-allocazione dei bit è riportato in \figref{fig:file_perm_bit}.
+sez.~\ref{sec:file_suid_sgid} e sez.~\ref{sec:file_sticky}); lo schema di
+allocazione dei bit è riportato in fig.~\ref{fig:file_perm_bit}.
Anche i permessi, come tutte le altre informazioni pertinenti al file, sono
memorizzati nell'inode\index{inode}; in particolare essi sono contenuti in
alcuni bit del campo \var{st\_mode} della struttura \struct{stat} (si veda di
-nuovo \figref{fig:file_stat_struct}).
+nuovo fig.~\ref{fig:file_stat_struct}).
In genere ci si riferisce ai tre livelli dei privilegi usando le lettere
\cmd{u} (per \textit{user}), \cmd{g} (per \textit{group}) e \cmd{o} (per
si parla dei permessi base come di permessi per \textit{owner}, \textit{group}
ed \textit{all}, le cui iniziali possono dar luogo a confusione. Le costanti
che permettono di accedere al valore numerico di questi bit nel campo
-\var{st\_mode} sono riportate in \tabref{tab:file_bit_perm}.
+\var{st\_mode} sono riportate in tab.~\ref{tab:file_bit_perm}.
\begin{table}[htb]
\centering
directory).
Avere il permesso di lettura per un file consente di aprirlo con le opzioni
-(si veda quanto riportato in \tabref{tab:file_open_flags}) di sola lettura o
+(si veda quanto riportato in tab.~\ref{tab:file_open_flags}) di sola lettura o
di lettura/scrittura e leggerne il contenuto. Avere il permesso di scrittura
consente di aprire un file in sola scrittura o lettura/scrittura e modificarne
il contenuto, lo stesso permesso è necessario per poter troncare il file.
appartiene vengono pure ignorati quando il link viene risolto, vengono
controllati solo quando viene richiesta la rimozione del link e quest'ultimo è
in una directory con lo \textsl{sticky bit} impostato (si veda
-\secref{sec:file_sticky}).
+sez.~\ref{sec:file_sticky}).
La procedura con cui il kernel stabilisce se un processo possiede un certo
permesso (di lettura, scrittura o esecuzione) si basa sul confronto fra
effettivo e gli eventuali group-ID supplementari del processo.\footnote{in
realtà Linux, per quanto riguarda l'accesso ai file, utilizza gli gli
identificatori del gruppo \textit{filesystem} (si ricordi quanto esposto in
- \secref{sec:proc_perms}), ma essendo questi del tutto equivalenti ai primi,
+ sez.~\ref{sec:proc_perms}), ma essendo questi del tutto equivalenti ai primi,
eccetto il caso in cui si voglia scrivere un server NFS, ignoreremo questa
differenza.}
Per una spiegazione dettagliata degli identificatori associati ai processi si
-veda \secref{sec:proc_perms}; normalmente, a parte quanto vedremo in
-\secref{sec:file_suid_sgid}, l'user-ID effettivo e il group-ID effettivo
+veda sez.~\ref{sec:proc_perms}; normalmente, a parte quanto vedremo in
+sez.~\ref{sec:file_suid_sgid}, l'user-ID effettivo e il group-ID effettivo
corrispondono ai valori dell'\acr{uid} e del \acr{gid} dell'utente che ha
lanciato il processo, mentre i group-ID supplementari sono quelli dei gruppi
cui l'utente appartiene.
\subsection{I bit \acr{suid} e \acr{sgid}}
\label{sec:file_suid_sgid}
-Come si è accennato (in \secref{sec:file_perm_overview}) nei dodici bit del
+Come si è accennato (in sez.~\ref{sec:file_perm_overview}) nei dodici bit del
campo \var{st\_mode} di \struct{stat} che vengono usati per il controllo di
accesso oltre ai bit dei permessi veri e propri, ci sono altri tre bit che
vengono usati per indicare alcune proprietà speciali dei file. Due di questi
\textit{set-group-ID bit}) che sono identificati dalle costanti
\const{S\_ISUID} e \const{S\_ISGID}.
-Come spiegato in dettaglio in \secref{sec:proc_exec}, quando si lancia un
+Come spiegato in dettaglio in sez.~\ref{sec:proc_exec}, quando si lancia un
programma il comportamento normale del kernel è quello di impostare gli
identificatori del gruppo \textit{effective} del nuovo processo al valore dei
corrispondenti del gruppo \textit{real} del processo corrente, che normalmente
normalmente l'utente che lo ha lanciato comporta vari rischi, e questo tipo di
programmi devono essere scritti accuratamente per evitare che possano essere
usati per guadagnare privilegi non consentiti (l'argomento è affrontato in
-dettaglio in \secref{sec:proc_perms}).
+dettaglio in sez.~\ref{sec:proc_perms}).
La presenza dei bit \acr{suid} e \acr{sgid} su un file può essere rilevata con
il comando \cmd{ls -l}, che visualizza una lettera \cmd{s} al posto della
\cmd{s} può essere usata nel comando \cmd{chmod} per impostare questi bit.
Infine questi bit possono essere controllati all'interno di \var{st\_mode} con
l'uso delle due costanti \const{S\_ISUID} e \const{S\_IGID}, i cui valori sono
-riportati in \tabref{tab:file_mode_flags}.
+riportati in tab.~\ref{tab:file_mode_flags}.
Gli stessi bit vengono ad assumere in significato completamente diverso per le
directory, normalmente infatti Linux usa la convenzione di SVr4 per indicare
con questi bit l'uso della semantica BSD nella creazione di nuovi file (si
-veda \secref{sec:file_ownership} per una spiegazione dettagliata al
+veda sez.~\ref{sec:file_ownership} per una spiegazione dettagliata al
proposito).
Infine Linux utilizza il bit \acr{sgid} per una ulteriore estensione mutuata
da SVr4. Il caso in cui un file ha il bit \acr{sgid} impostato senza che lo
sia anche il corrispondente bit di esecuzione viene utilizzato per attivare
per quel file il \textit{mandatory locking} (affronteremo questo argomento in
-dettaglio più avanti, in \secref{sec:file_mand_locking}).
+dettaglio più avanti, in sez.~\ref{sec:file_mand_locking}).
\subsection{Il bit \textsl{sticky}}
si poteva impostare questo bit.
L'effetto di questo bit era che il segmento di testo del programma (si veda
-\secref{sec:proc_mem_layout} per i dettagli) veniva scritto nella swap la
+sez.~\ref{sec:proc_mem_layout} per i dettagli) veniva scritto nella swap la
prima volta che questo veniva lanciato, e vi permaneva fino al riavvio della
macchina (da questo il nome di \textsl{sticky bit}); essendo la swap un file
continuo indicizzato direttamente in questo modo si poteva risparmiare in
\subsection{La titolarità di nuovi file e directory}
\label{sec:file_ownership}
-Vedremo in \secref{sec:file_base_func} con quali funzioni si possono creare
+Vedremo in sez.~\ref{sec:file_base_func} con quali funzioni si possono creare
nuovi file, in tale occasione vedremo che è possibile specificare in sede di
creazione quali permessi applicare ad un file, però non si può indicare a
quale utente e gruppo esso deve appartenere. Lo stesso problema si presenta
per la creazione di nuove directory (procedimento descritto in
-\secref{sec:file_dir_creat_rem}).
+sez.~\ref{sec:file_dir_creat_rem}).
Lo standard POSIX prescrive che l'\acr{uid} del nuovo file corrisponda
all'user-ID effettivo del processo che lo crea; per il \acr{gid} invece prevede
\subsection{La funzione \func{access}}
\label{sec:file_access}
-Come visto in \secref{sec:file_access_control} il controllo di accesso ad un
-file viene fatto utilizzando l'user-ID ed il group-ID effettivo del processo; ci
-sono casi però in cui si può voler effettuare il controllo con l'user-ID reale
-ed il group-ID reale, vale a dire usando i valori di \acr{uid} e \acr{gid}
-relativi all'utente che ha lanciato il programma, e che, come accennato in
-\secref{sec:file_suid_sgid} e spiegato in dettaglio in
-\secref{sec:proc_perms}, non è detto siano uguali a quelli effettivi.
+Come visto in sez.~\ref{sec:file_access_control} il controllo di accesso ad un
+file viene fatto utilizzando l'user-ID ed il group-ID effettivo del processo;
+ci sono casi però in cui si può voler effettuare il controllo con l'user-ID
+reale ed il group-ID reale, vale a dire usando i valori di \acr{uid} e
+\acr{gid} relativi all'utente che ha lanciato il programma, e che, come
+accennato in sez.~\ref{sec:file_suid_sgid} e spiegato in dettaglio in
+sez.~\ref{sec:proc_perms}, non è detto siano uguali a quelli effettivi.
Per far questo si può usare la funzione \funcd{access}, il cui prototipo è:
\begin{prototype}{unistd.h}
La funzione verifica i permessi di accesso, indicati da \param{mode}, per il
file indicato da \param{pathname}. I valori possibili per l'argomento
\param{mode} sono esprimibili come combinazione delle costanti numeriche
-riportate in \tabref{tab:file_access_mode_val} (attraverso un OR binario delle
-stesse). I primi tre valori implicano anche la verifica dell'esistenza del
-file, se si vuole verificare solo quest'ultima si può usare \const{F\_OK}, o
-anche direttamente \func{stat}. Nel caso in cui \param{pathname} si riferisca
-ad un link simbolico, questo viene seguito ed il controllo è fatto sul file a
-cui esso fa riferimento.
+riportate in tab.~\ref{tab:file_access_mode_val} (attraverso un OR binario
+delle stesse). I primi tre valori implicano anche la verifica dell'esistenza
+del file, se si vuole verificare solo quest'ultima si può usare \const{F\_OK},
+o anche direttamente \func{stat}. Nel caso in cui \param{pathname} si
+riferisca ad un link simbolico, questo viene seguito ed il controllo è fatto
+sul file a cui esso fa riferimento.
La funzione controlla solo i bit dei permessi di accesso, si ricordi che il
fatto che una directory abbia permesso di scrittura non significa che ci si
Entrambe le funzioni utilizzano come secondo argomento \param{mode}, una
variabile dell'apposito tipo primitivo \type{mode\_t} (vedi
-\tabref{tab:intro_primitive_types}) utilizzato per specificare i permessi sui
+tab.~\ref{tab:intro_primitive_types}) utilizzato per specificare i permessi sui
file.
\begin{table}[!htb]
\end{table}
Le costanti con cui specificare i singoli bit di \param{mode} sono riportate
-in \tabref{tab:file_permission_const}. Il valore di \param{mode} può essere
+in tab.~\ref{tab:file_permission_const}. Il valore di \param{mode} può essere
ottenuto combinando fra loro con un OR binario le costanti simboliche relative
ai vari bit, o specificato direttamente, come per l'omonimo comando di shell,
con un valore numerico (la shell lo vuole in ottale, dato che i bit dei
permessi sono divisibili in gruppi di tre), che si può calcolare direttamente
-usando lo schema si utilizzo dei bit illustrato in \figref{fig:file_perm_bit}.
+usando lo schema si utilizzo dei bit illustrato in
+fig.~\ref{fig:file_perm_bit}.
Ad esempio i permessi standard assegnati ai nuovi file (lettura e scrittura
per il proprietario, sola lettura per il gruppo e gli altri) sono
l'user-ID effettivo del processo non è zero esso viene automaticamente
cancellato (senza notifica di errore) qualora sia stato indicato in
\param{mode}.
-\item per quanto detto in \secref{sec:file_ownership} riguardo la creazione
+\item per quanto detto in sez.~\ref{sec:file_ownership} riguardo la creazione
dei nuovi file, si può avere il caso in cui il file creato da un processo è
assegnato a un gruppo per il quale il processo non ha privilegi. Per evitare
che si possa assegnare il bit \acr{sgid} ad un file appartenente a un gruppo
Le funzioni \func{chmod} e \func{fchmod} ci permettono di modificare i
permessi di un file, resta però il problema di quali sono i permessi assegnati
quando il file viene creato. Le funzioni dell'interfaccia nativa di Unix, come
-vedremo in \secref{sec:file_open}, permettono di indicare esplicitamente i
+vedremo in sez.~\ref{sec:file_open}, permettono di indicare esplicitamente i
permessi di creazione di un file, ma questo non è possibile per le funzioni
dell'interfaccia standard ANSI C che non prevede l'esistenza di utenti e
gruppi, ed inoltre il problema si pone anche per l'interfaccia nativa quando i
In tutti questi casi l'unico riferimento possibile è quello della modalità di
apertura del nuovo file (lettura/scrittura o sola lettura), che però può
fornire un valore che è lo stesso per tutti e tre i permessi di
-\secref{sec:file_perm_overview} (cioè $666$ nel primo caso e $222$ nel
+sez.~\ref{sec:file_perm_overview} (cioè $666$ nel primo caso e $222$ nel
secondo). Per questo motivo il sistema associa ad ogni processo\footnote{è
infatti contenuta nel campo \var{umask} della struttura \struct{fs\_struct},
- vedi \figref{fig:proc_task_struct}.} una maschera di bit, la cosiddetta
+ vedi fig.~\ref{fig:proc_task_struct}.} una maschera di bit, la cosiddetta
\textit{umask}, che viene utilizzata per impedire che alcuni permessi possano
essere assegnati ai nuovi file in sede di creazione. I bit indicati nella
maschera vengono infatti cancellati dai permessi quando un nuovo file viene
%La struttura fondamentale che contiene i dati essenziali relativi ai file è il
%cosiddetto \textit{inode}; questo conterrà informazioni come il
%tipo di file (file di dispositivo, directory, file di dati, per un elenco
-%completo vedi \ntab), i permessi (vedi \secref{sec:file_perms}), le date (vedi
-%\secref{sec:file_times}).
+%completo vedi \ntab), i permessi (vedi sez.~\ref{sec:file_perms}), le date (vedi
+%sez.~\ref{sec:file_times}).
\subsection{Un quadro d'insieme sui permessi}
riepilogo in cui si riassumono le caratteristiche di ciascuno di essi, in modo
da poter fornire un quadro d'insieme.
-In \tabref{tab:file_fileperm_bits} si sono riassunti gli effetti dei vari bit
-per un file; per quanto riguarda l'applicazione dei permessi per proprietario,
-gruppo ed altri si ricordi quanto illustrato in
-\secref{sec:file_perm_overview}. Si rammenti che il valore dei permessi non ha
-alcun effetto qualora il processo possieda i privilegi di amministratore.
+In tab.~\ref{tab:file_fileperm_bits} si sono riassunti gli effetti dei vari
+bit per un file; per quanto riguarda l'applicazione dei permessi per
+proprietario, gruppo ed altri si ricordi quanto illustrato in
+sez.~\ref{sec:file_perm_overview}. Si rammenti che il valore dei permessi non
+ha alcun effetto qualora il processo possieda i privilegi di amministratore.
\begin{table}[!htb]
\centering
Per compattezza, nella tabella si sono specificati i bit di \acr{suid},
\acr{sgid} e \acr{sticky} con la notazione illustrata anche in
-\figref{fig:file_perm_bit}.
+fig.~\ref{fig:file_perm_bit}.
-In \tabref{tab:file_dirperm_bits} si sono invece riassunti gli effetti dei
+In tab.~\ref{tab:file_dirperm_bits} si sono invece riassunti gli effetti dei
vari bit dei permessi per una directory; anche in questo caso si sono
specificati i bit di \acr{suid}, \acr{sgid} e \acr{sticky} con la notazione
-compatta illustrata in \figref{fig:file_perm_bit}.
+compatta illustrata in fig.~\ref{fig:file_perm_bit}.
\begin{table}[!htb]
\centering
programma ad una sezione limitata del filesystem, per cui ne parleremo in
questa sezione.
-Come accennato in \secref{sec:proc_fork} ogni processo oltre ad una directory
+Come accennato in sez.~\ref{sec:proc_fork} ogni processo oltre ad una directory
di lavoro, ha anche una directory \textsl{radice}\footnote{entrambe sono
contenute in due campi (rispettivamente \var{pwd} e \var{root}) di
- \struct{fs\_struct}; vedi \figref{fig:proc_task_struct}.} che, pur essendo
+ \struct{fs\_struct}; vedi fig.~\ref{fig:proc_task_struct}.} che, pur essendo
di norma corrispondente alla radice dell'albero di file e directory come visto
-dal kernel (ed illustrato in \secref{sec:file_organization}), ha per il
+dal kernel (ed illustrato in sez.~\ref{sec:file_organization}), ha per il
processo il significato specifico di directory rispetto alla quale vengono
risolti i pathname assoluti.\footnote{cioè quando un processo chiede la
risoluzione di un pathname, il kernel usa sempre questa directory come punto
\textsl{imprigionato}.
Solo un processo con i privilegi di amministratore può usare questa funzione,
-e la nuova radice, per quanto detto in \secref{sec:proc_fork}, sarà ereditata
+e la nuova radice, per quanto detto in sez.~\ref{sec:proc_fork}, sarà ereditata
da tutti i suoi processi figli. Si tenga presente però che la funzione non
cambia la directory di lavoro, che potrebbe restare fuori dalla \textit{chroot
jail}.
\section{Introduzione}
\label{sec:file_stream_intro}
-Come visto in \capref{cha:file_unix_interface} le operazioni di I/O sui file
+Come visto in cap.~\ref{cha:file_unix_interface} le operazioni di I/O sui file
sono gestibili a basso livello con l'interfaccia standard unix, che ricorre
direttamente alle system call messe a disposizione dal kernel.
scrittura (sia per quel che riguarda la bufferizzazione, che le
formattazioni), i file stream restano del tutto equivalenti ai file descriptor
(sui quali sono basati), ed in particolare continua a valere quanto visto in
-\secref{sec:file_sharing} a proposito dell'accesso condiviso ed in
-\secref{sec:file_access_control} per il controllo di accesso.
+sez.~\ref{sec:file_sharing} a proposito dell'accesso condiviso ed in
+sez.~\ref{sec:file_access_control} per il controllo di accesso.
\index{file!stream|)}
\subsection{Gli stream standard}
\label{sec:file_std_stream}
-Ai tre file descriptor standard (vedi \secref{sec:file_std_descr})
+Ai tre file descriptor standard (vedi sez.~\ref{sec:file_std_descr})
aperti per ogni processo, corrispondono altrettanti stream, che
rappresentano i canali standard di input/output prestabiliti; anche
questi tre stream sono identificabili attraverso dei nomi simbolici
legge è in modalità \textit{unbuffered}.} viene anche eseguito lo scarico di
tutti i buffer degli stream in scrittura.
-In \secref{sec:file_buffering_ctrl} vedremo come la libreria definisca delle
+In sez.~\ref{sec:file_buffering_ctrl} vedremo come la libreria definisca delle
opportune funzioni per controllare le modalità di bufferizzazione e lo scarico
dei dati.
\label{sec:file_ansi_base_func}
Esamineremo in questa sezione le funzioni base dell'interfaccia degli stream,
-analoghe a quelle di \secref{sec:file_base_func} per i file descriptor. In
+analoghe a quelle di sez.~\ref{sec:file_base_func} per i file descriptor. In
particolare vedremo come aprire, leggere, scrivere e cambiare la posizione
corrente in uno stream.
Normalmente la funzione che si usa per aprire uno stream è \func{fopen},
essa apre il file specificato nella modalità specificata da
\param{mode}, che è una stringa che deve iniziare con almeno uno dei
-valori indicati in \tabref{tab:file_fopen_mode} (sono possibili varie
+valori indicati in tab.~\ref{tab:file_fopen_mode} (sono possibili varie
estensioni che vedremo in seguito).
L'uso più comune di \func{freopen} è per redirigere uno dei tre file
-standard (vedi \secref{sec:file_std_stream}): il file \param{path} viene
+standard (vedi sez.~\ref{sec:file_std_stream}): il file \param{path} viene
associato a \param{stream} e se questo è uno stream già aperto viene
preventivamente chiuso.
\end{table}
In realtà lo standard ANSI C prevede un totale di 15 possibili valori
-diversi per \param{mode}, ma in \tabref{tab:file_fopen_mode} si sono
+diversi per \param{mode}, ma in tab.~\ref{tab:file_fopen_mode} si sono
riportati solo i sei valori effettivi, ad essi può essere aggiunto pure
il carattere \texttt{b} (come ultimo carattere o nel mezzo agli altri per
le stringhe di due caratteri) che in altri sistemi operativi serve a
Le \acr{glibc} supportano alcune estensioni, queste devono essere sempre
indicate dopo aver specificato il \param{mode} con uno dei valori di
-\tabref{tab:file_fopen_mode}. L'uso del carattere \texttt{x} serve per
+tab.~\ref{tab:file_fopen_mode}. L'uso del carattere \texttt{x} serve per
evitare di sovrascrivere un file già esistente (è analoga all'uso
dell'opzione \const{O\_EXCL} in \func{open}), se il file specificato già
esiste e si aggiunge questo carattere a \param{mode} la \func{fopen}
Nel caso si usi \func{fdopen} i valori specificati da \param{mode} devono
essere compatibili con quelli con cui il file descriptor è stato aperto.
Inoltre i modi \cmd{w} e \cmd{w+} non troncano il file. La posizione nello
-stream viene impostata a quella corrente nel file descriptor, e le variabili di
-errore e di fine del file (vedi \secref{sec:file_io}) sono cancellate. Il file
-non viene duplicato e verrà chiuso alla chiusura dello stream.
+stream viene impostata a quella corrente nel file descriptor, e le variabili
+di errore e di fine del file (vedi sez.~\ref{sec:file_io}) sono cancellate. Il
+file non viene duplicato e verrà chiuso alla chiusura dello stream.
I nuovi file saranno creati secondo quanto visto in
-\secref{sec:file_ownership} ed avranno i permessi di accesso impostati al
+sez.~\ref{sec:file_ownership} ed avranno i permessi di accesso impostati al
valore \code{S\_IRUSR|S\_IWUSR|S\_IRGRP|S\_IWGRP|S\_IROTH|S\_IWOTH} (pari a
\val{0666}) modificato secondo il valore di \acr{umask} per il processo (si
-veda \secref{sec:file_umask}).
+veda sez.~\ref{sec:file_umask}).
In caso di file aperti in lettura e scrittura occorre ricordarsi che c'è
di mezzo una bufferizzazione; per questo motivo lo standard ANSI C
sufficiente a garantire la sincronizzazione.
Una volta aperto lo stream, si può cambiare la modalità di bufferizzazione
-(si veda \secref{sec:file_buffering_ctrl}) fintanto che non si è effettuato
+(si veda sez.~\ref{sec:file_buffering_ctrl}) fintanto che non si è effettuato
alcuna operazione di I/O sul file.
Uno stream viene chiuso con la funzione \funcd{fclose} il cui prototipo è:
stream questo verrà rilasciato. La funzione effettua lo scarico solo per i
dati presenti nei buffer in user space usati dalle \acr{glibc}; se si vuole
essere sicuri che il kernel forzi la scrittura su disco occorrerà effettuare
-una \func{sync} (vedi \secref{sec:file_sync}).
+una \func{sync} (vedi sez.~\ref{sec:file_sync}).
Linux supporta anche una altra funzione, \funcd{fcloseall}, come estensione
GNU implementata dalle \acr{glibc}, accessibile avendo definito
provvista solo per i casi di emergenza, quando si è verificato un errore
ed il programma deve essere abortito, ma si vuole compiere qualche altra
operazione dopo aver chiuso i file e prima di uscire (si ricordi quanto
-visto in \secref{sec:proc_exit}).
+visto in sez.~\ref{sec:proc_exit}).
\subsection{Lettura e scrittura su uno stream}
modalità di input/output non formattato:
\begin{enumerate*}
\item\textsl{binario} in cui legge/scrive un blocco di dati alla
- volta, vedi \secref{sec:file_binary_io}.
+ volta, vedi sez.~\ref{sec:file_binary_io}.
\item\textsl{a caratteri} in cui si legge/scrive un carattere alla
volta (con la bufferizzazione gestita automaticamente dalla libreria),
- vedi \secref{sec:file_char_io}.
+ vedi sez.~\ref{sec:file_char_io}.
\item\textsl{di linea} in cui si legge/scrive una linea alla volta (terminata
- dal carattere di newline \verb|'\n'|), vedi \secref{sec:file_line_io}.
+ dal carattere di newline \verb|'\n'|), vedi sez.~\ref{sec:file_line_io}.
\end{enumerate*}
ed inoltre la modalità di input/output formattato.
il problema di come distinguerla da un errore effettivo; basarsi solo sul
valore di ritorno della funzione e controllare il valore di \var{errno}
infatti non basta, dato che quest'ultimo potrebbe essere stato impostato in
-una altra occasione, (si veda \secref{sec:sys_errno} per i dettagli del
+una altra occasione, (si veda sez.~\ref{sec:sys_errno} per i dettagli del
funzionamento di \var{errno}).
Per questo motivo tutte le implementazioni delle librerie standard
corretta la causa di un errore per evitare di mantenere i flag attivi, così da
poter rilevare una successiva ulteriore condizione di errore. Di questa
funzione esiste una analoga \func{clearerr\_unlocked} che non esegue il blocco
-dello stream (vedi \secref{sec:file_stream_thread}).
+dello stream (vedi sez.~\ref{sec:file_stream_thread}).
\subsection{Input/output binario}
Le \acr{glibc} definiscono altre due funzioni per l'I/O binario,
\funcd{fread\_unlocked} e \funcd{fwrite\_unlocked} che evitano il lock
implicito dello stream, usato per dalla librerie per la gestione delle
-applicazioni multi-thread (si veda \secref{sec:file_stream_thread} per i
+applicazioni multi-thread (si veda sez.~\ref{sec:file_stream_thread} per i
dettagli), i loro prototipi sono:
\begin{functions}
\headdecl{stdio.h}
viene implementata con una macro, per cui occorre stare attenti a cosa
le si passa come argomento, infatti \param{stream} può essere valutato
più volte nell'esecuzione, e non viene passato in copia con il
-meccanismo visto in \secref{sec:proc_var_passing}; per questo motivo se
+meccanismo visto in sez.~\ref{sec:proc_var_passing}; per questo motivo se
si passa un'espressione si possono avere effetti indesiderati.
Invece \func{fgetc} è assicurata essere sempre una funzione, per questo
Infine si tenga presente che \func{ungetc} non altera il contenuto del
file, ma opera esclusivamente sul buffer interno. Se si esegue una
qualunque delle operazioni di riposizionamento (vedi
-\secref{sec:file_fseek}) i caratteri rimandati indietro vengono
+sez.~\ref{sec:file_fseek}) i caratteri rimandati indietro vengono
scartati.
\acr{glibc} supportano una serie di altre funzioni, estensioni di tutte quelle
illustrate finora (eccetto \func{gets} e \func{puts}), che eseguono
esattamente le stesse operazioni delle loro equivalenti, evitando però il lock
-implicito dello stream (vedi \secref{sec:file_stream_thread}). Come per le
+implicito dello stream (vedi sez.~\ref{sec:file_stream_thread}). Come per le
altre forma di I/O, dette funzioni hanno lo stesso nome della loro analoga
normale, con l'aggiunta dell'estensione \code{\_unlocked}.
passata indietro (si noti infatti come per entrambi i parametri si siano
usati dei \textit{value result argument}, passando dei puntatori anziché
i valori delle variabili, secondo la tecnica spiegata in
-\secref{sec:proc_var_passing}).
+sez.~\ref{sec:proc_var_passing}).
Se si passa alla funzione l'indirizzo di un puntatore impostato a \val{NULL}
e \var{*n} è zero, la funzione provvede da sola all'allocazione della memoria
vengono passati invariati all'output, e da direttive di conversione, in cui
devono essere sempre presenti il carattere \texttt{\%}, che introduce la
direttiva, ed uno degli specificatori di conversione (riportati in
-\tabref{tab:file_format_spec}) che la conclude.
+tab.~\ref{tab:file_format_spec}) che la conclude.
\begin{table}[htb]
\centering
\begin{itemize*}
\item uno specificatore del parametro da usare (terminato da un \val{\$}),
\item uno o più flag (i cui valori possibili sono riassunti in
- \tabref{tab:file_format_flag}) che controllano il formato di stampa della
+ tab.~\ref{tab:file_format_flag}) che controllano il formato di stampa della
conversione,
\item uno specificatore di larghezza (un numero decimale), eventualmente
seguito (per i numeri in virgola mobile) da un specificatore di precisione
(un altro numero decimale),
\item uno specificatore del tipo di dato, che ne indica la dimensione (i cui
- valori possibili sono riassunti in \tabref{tab:file_format_type}).
+ valori possibili sono riassunti in tab.~\ref{tab:file_format_type}).
\end{itemize*}
Una versione alternativa delle funzioni di output formattato, che permettono
di usare il puntatore ad una lista di argomenti (vedi
-\secref{sec:proc_variadic}), sono \funcd{vprintf}, \funcd{vfprintf} e
+sez.~\ref{sec:proc_variadic}), sono \funcd{vprintf}, \funcd{vfprintf} e
\funcd{vsprintf}, i cui prototipi sono:
\begin{functions}
\headdecl{stdio.h}
si vogliono passare ad una routine di stampa, passando direttamente la lista
tramite il parametro \param{ap}. Per poter far questo ovviamente la lista dei
parametri dovrà essere opportunamente trattata (l'argomento è esaminato in
-\secref{sec:proc_variadic}), e dopo l'esecuzione della funzione l'argomento
+sez.~\ref{sec:proc_variadic}), e dopo l'esecuzione della funzione l'argomento
\param{ap} non sarà più utilizzabile (in generale dovrebbe essere eseguito un
\code{va\_end(ap)} ma in Linux questo non è necessario).
\end{functions}
Entrambe le funzioni prendono come parametro \param{strptr} che deve essere
l'indirizzo di un puntatore ad una stringa di caratteri, in cui verrà
-restituito (si ricordi quanto detto in \secref{sec:proc_var_passing} a
+restituito (si ricordi quanto detto in sez.~\ref{sec:proc_var_passing} a
proposito dei \textit{value result argument}) l'indirizzo della stringa
allocata automaticamente dalle funzioni. Occorre inoltre ricordarsi di
invocare \func{free} per liberare detto puntatore quando la stringa non serve
L'uso di \func{fseek} è del tutto analogo a quello di \func{lseek} per i file
descriptor, ed i parametri, a parte il tipo, hanno lo stesso significato; in
particolare \param{whence} assume gli stessi valori già visti in
-\secref{sec:file_lseek}. La funzione restituisce 0 in caso di successo e -1
+sez.~\ref{sec:file_lseek}. La funzione restituisce 0 in caso di successo e -1
in caso di errore. La funzione \func{rewind} riporta semplicemente la
posizione corrente all'inizio dello stream, ma non esattamente equivalente ad
una \code{fseek(stream, 0L, SEEK\_SET)} in quanto vengono cancellati anche i
\subsection{Il controllo della bufferizzazione}
\label{sec:file_buffering_ctrl}
-Come accennato in \secref{sec:file_buffering} le librerie definiscono una
+Come accennato in sez.~\ref{sec:file_buffering} le librerie definiscono una
serie di funzioni che permettono di controllare il comportamento degli stream;
se non si è specificato nulla, la modalità di buffering viene decisa
autonomamente sulla base del tipo di file sottostante, ed i buffer vengono
\val{NULL} per \param{buf} e la funzione ignorerà il parametro \param{size}
usando il buffer allocato automaticamente dal sistema. Si potrà comunque
modificare la modalità di bufferizzazione, passando in \param{mode} uno degli
-opportuni valori elencati in \tabref{tab:file_stream_buf_mode}. Qualora si
+opportuni valori elencati in tab.~\ref{tab:file_stream_buf_mode}. Qualora si
specifichi la modalità non bufferizzata i valori di \param{buf} e \param{size}
vengono sempre ignorati.
Si ricordi comunque che lo scarico dei dati dai buffer effettuato da queste
funzioni non comporta la scrittura di questi su disco; se si vuole che il
kernel dia effettivamente avvio alle operazioni di scrittura su disco occorre
-usare \func{sync} o \func{fsync} (si veda~\secref{sec:file_sync}).
+usare \func{sync} o \func{fsync} (si veda~sez.~\ref{sec:file_sync}).
Infine esistono anche circostanze in cui si vuole scartare tutto l'output
pendente; per questo si può usare \funcd{fpurge}, il cui prototipo è:
dalle system call, che non prevede funzionalità evolute come la
bufferizzazione o funzioni di lettura o scrittura formattata, e sulla quale è
costruita anche l'interfaccia definita dallo standard ANSI C che affronteremo
-al \capref{cha:files_std_interface}.
+al cap.~\ref{cha:files_std_interface}.
\index{file!descriptor|(} Per poter accedere al contenuto di un file occorre
creare un canale di comunicazione con il kernel che renda possibile operare su
-di esso (si ricordi quanto visto in \secref{sec:file_vfs_work}). Questo si fa
-aprendo il file con la funzione \func{open} che provvederà a localizzare
+di esso (si ricordi quanto visto in sez.~\ref{sec:file_vfs_work}). Questo si
+fa aprendo il file con la funzione \func{open} che provvederà a localizzare
l'inode\index{inode} del file e inizializzare i puntatori che rendono
disponibili le funzioni che il VFS mette a disposizione (riportate in
-\tabref{tab:file_file_operations}). Una volta terminate le operazioni, il file
-dovrà essere chiuso, e questo chiuderà il canale di comunicazione impedendo
-ogni ulteriore operazione.
+tab.~\ref{tab:file_file_operations}). Una volta terminate le operazioni, il
+file dovrà essere chiuso, e questo chiuderà il canale di comunicazione
+impedendo ogni ulteriore operazione.
All'interno di ogni processo i file aperti sono identificati da un intero non
negativo, chiamato appunto \textit{file descriptor}.
sua volta all'inode\index{inode} passando per la nuova struttura del VFS.}
del file.
%\item un puntatore alla tabella delle funzioni \footnote{la struttura
-% \var{f\_op} descritta in \secref{sec:file_vfs_work}} che si possono usare
+% \var{f\_op} descritta in sez.~\ref{sec:file_vfs_work}} che si possono usare
% sul file.
\end{itemize*}
-In \figref{fig:file_proc_file} si è riportato uno schema in cui è illustrata
+In fig.~\ref{fig:file_proc_file} si è riportato uno schema in cui è illustrata
questa architettura, ed in cui si sono evidenziate le interrelazioni fra le
varie strutture di dati sulla quale essa è basata.
\begin{figure}[htb]
\label{tab:file_std_files}
\end{table}
-In \figref{tab:file_std_files} si è utilizzata questa situazione come esempio,
-facendo riferimento ad un programma in cui lo \textit{standard input} è
-associato ad un file mentre lo \textit{standard output} e lo \textit{standard
- error} sono entrambi associati ad un altro file (e quindi utilizzano lo
-stesso inode\index{inode}).
+In tab.~\ref{tab:file_std_files} si è utilizzata questa situazione come
+esempio, facendo riferimento ad un programma in cui lo \textit{standard input}
+è associato ad un file mentre lo \textit{standard output} e lo
+\textit{standard error} sono entrambi associati ad un altro file (e quindi
+utilizzano lo stesso inode\index{inode}).
Nelle vecchie versioni di Unix (ed anche in Linux fino al kernel 2.0.x) il
numero di file aperti era anche soggetto ad un limite massimo dato dalle
descriptor dentro \struct{file\_struct}; questo limite intrinseco nei kernel
più recenti non sussiste più, dato che si è passati da un vettore ad una
lista, ma restano i limiti imposti dall'amministratore (vedi
-\secref{sec:sys_limits}).
+sez.~\ref{sec:sys_limits}).
\hline % modalità di apertura del file
\hline
\const{O\_CREAT} & se il file non esiste verrà creato, con le regole di
- titolarità del file viste in \secref{sec:file_ownership}. L'argomento
+ titolarità del file viste in sez.~\ref{sec:file_ownership}. L'argomento
\param{mode} deve essere specificato. \\
\const{O\_EXCL} & usato in congiunzione con \const{O\_CREAT} fa sì che
l'esistenza del file diventi un errore\protect\footnotemark\ che fa fallire
\const{O\_NONBLOCK} & apre il file in modalità non bloccante. Questo
valore specifica anche una modalità di operazione (vedi sotto), e
comporta che \func{open} ritorni immediatamente (l'opzione ha senso
- solo per le fifo, torneremo questo in \secref{sec:ipc_named_pipe}). \\
+ solo per le fifo, torneremo questo in sez.~\ref{sec:ipc_named_pipe}). \\
\const{O\_NOCTTY} & se \param{pathname} si riferisce ad un dispositivo di
terminale, questo non diventerà il terminale di controllo, anche se il
- processo non ne ha ancora uno (si veda \secref{sec:sess_ctrl_term}). \\
+ processo non ne ha ancora uno (si veda sez.~\ref{sec:sess_ctrl_term}). \\
\const{O\_SHLOCK} & opzione di BSD, acquisisce uno shared lock (vedi
- \secref{sec:file_locking}) sul file. Non è disponibile in Linux. \\
+ sez.~\ref{sec:file_locking}) sul file. Non è disponibile in Linux. \\
\const{O\_EXLOCK} & opzione di BSD, acquisisce uno lock esclusivo (vedi
- \secref{sec:file_locking}) sul file. Non è disponibile in Linux. \\
+ sez.~\ref{sec:file_locking}) sul file. Non è disponibile in Linux. \\
\const{O\_TRUNC} & se il file esiste ed è un file di dati e la modalità di
apertura consente la scrittura, allora la sua lunghezza verrà troncata a
zero. Se il file è un terminale o una fifo il flag verrà ignorato, negli
file. Può causare corruzione del file con NFS se più di un processo scrive
allo stesso tempo.\footnotemark\\
\const{O\_NONBLOCK} & il file viene aperto in modalità non bloccante per
- le operazioni di I/O (che tratteremo in \secref{sec:file_noblocking}):
+ le operazioni di I/O (che tratteremo in sez.~\ref{sec:file_noblocking}):
questo significa il fallimento di \func{read} in assenza di dati da
leggere e quello di \func{write} in caso di impossibilità di scrivere
immediatamente. Questa modalità ha senso solo per le fifo e per alcuni
\const{O\_NDELAY} & in Linux\footnotemark\ è sinonimo di
\const{O\_NONBLOCK}.\\
\const{O\_ASYNC} & apre il file per l'I/O in modalità
- asincrona (vedi \secref{sec:file_asyncronous_io}). Quando è impostato viene
- generato il segnale \const{SIGIO} tutte le volte che sono disponibili
+ asincrona (vedi sez.~\ref{sec:file_asyncronous_io}). Quando è impostato
+ viene generato il segnale \const{SIGIO} tutte le volte che sono disponibili
dati in input sul file. \\
\const{O\_SYNC} & apre il file per l'input/output sincrono, ogni
\func{write} bloccherà fino al completamento della scrittura di tutti dati
sul sull'hardware sottostante.\\
\const{O\_FSYNC} & sinonimo di \const{O\_SYNC}. \\
\const{O\_NOATIME} & blocca l'aggiornamento dei tempi di accesso dei
- file (vedi \secref{sec:file_file_times}). In Linux questa opzione non è
+ file (vedi sez.~\ref{sec:file_file_times}). In Linux questa opzione non è
disponibile per il singolo file ma come opzione per il filesystem in fase
di montaggio.\\
\hline
\textsl{file di lock}\index{file!di lock} possono incorrere in una race
condition\index{race condition}. Si consiglia come alternativa di usare un
file con un nome univoco e la funzione \func{link} per verificarne
- l'esistenza (vedi \secref{sec:ipc_file_lock}).}
+ l'esistenza (vedi sez.~\ref{sec:ipc_file_lock}).}
\footnotetext[3]{\textit{Denial of Service}\index{DoS}, si chiamano così
attacchi miranti ad impedire un servizio causando una qualche forma di
\footnotetext[4]{il problema è che NFS non supporta la scrittura in append, ed
il kernel deve simularla, ma questo comporta la possibilità di una race
- condition, vedi \secref{sec:file_atomic}.}
+ condition, vedi sez.~\ref{sec:file_atomic}.}
\footnotetext[5]{l'opzione origina da SVr4, dove però causava il ritorno da
una \func{read} con un valore nullo e non con un errore, questo introduce
- un'ambiguità, dato che come vedremo in \secref{sec:file_read} il ritorno di
+ un'ambiguità, dato che come vedremo in sez.~\ref{sec:file_read} il ritorno di
zero da parte di \func{read} ha il significato di una end-of-file.}
Questa caratteristica permette di prevedere qual'è il valore del file
descriptor che si otterrà al ritorno di \func{open}, e viene talvolta usata da
alcune applicazioni per sostituire i file corrispondenti ai file standard
-visti in \secref{sec:file_std_descr}: se ad esempio si chiude lo standard
+visti in sez.~\ref{sec:file_std_descr}: se ad esempio si chiude lo standard
input e si apre subito dopo un nuovo file questo diventerà il nuovo standard
input (avrà cioè il file descriptor 0). Il nuovo file descriptor non è
condiviso con nessun altro processo (torneremo sulla condivisione dei file, in
-genere accessibile dopo una \func{fork}, in \secref{sec:file_sharing}) ed è
+genere accessibile dopo una \func{fork}, in sez.~\ref{sec:file_sharing}) ed è
impostato per restare aperto attraverso una \func{exec} (come accennato in
-\secref{sec:proc_exec}); l'offset è impostato all'inizio del file.
+sez.~\ref{sec:proc_exec}); l'offset è impostato all'inizio del file.
L'argomento \param{mode} indica i permessi con cui il file viene creato; i
-valori possibili sono gli stessi già visti in \secref{sec:file_perm_overview}
+valori possibili sono gli stessi già visti in sez.~\ref{sec:file_perm_overview}
e possono essere specificati come OR binario delle costanti descritte in
-\tabref{tab:file_bit_perm}. Questi permessi sono filtrati dal valore di
-\var{umask} (vedi \secref{sec:file_umask}) per il processo.
+tab.~\ref{tab:file_bit_perm}. Questi permessi sono filtrati dal valore di
+\var{umask} (vedi sez.~\ref{sec:file_umask}) per il processo.
La funzione prevede diverse opzioni, che vengono specificate usando vari bit
dell'argomento \param{flags}. Alcuni di questi bit vanno anche a costituire
il flag di stato del file (o \textit{file status flag}), che è mantenuto nel
campo \var{f\_flags} della struttura \struct{file} (al solito si veda lo schema
-di \figref{fig:file_proc_file}). Essi sono divisi in tre categorie
+di fig.~\ref{fig:file_proc_file}). Essi sono divisi in tre categorie
principali:
\begin{itemize*}
\item \textsl{i bit delle modalità di accesso}: specificano con quale modalità
che controllano) con una \func{fcntl}.
\end{itemize*}
-In \tabref{tab:file_open_flags} sono riportate, ordinate e divise fra loro
+In tab.~\ref{tab:file_open_flags} sono riportate, ordinate e divise fra loro
secondo le tre modalità appena elencate, le costanti mnemoniche associate a
ciascuno di questi bit. Dette costanti possono essere combinate fra loro con
un OR aritmetico per costruire il valore (in forma di maschera binaria)
\end{prototype}
La chiusura di un file rilascia ogni blocco (il \textit{file
- locking}\index{file!locking} è trattato in \secref{sec:file_locking}) che il
-processo poteva avere acquisito su di esso; se \param{fd} è l'ultimo
+ locking}\index{file!locking} è trattato in sez.~\ref{sec:file_locking}) che
+il processo poteva avere acquisito su di esso; se \param{fd} è l'ultimo
riferimento (di eventuali copie) ad un file aperto, tutte le risorse nella
file table vengono rilasciate. Infine se il file descriptor era l'ultimo
riferimento ad un file su disco quest'ultimo viene cancellato.
In ogni caso una \func{close} andata a buon fine non garantisce che i dati
siano stati effettivamente scritti su disco, perché il kernel può decidere di
ottimizzare l'accesso a disco ritardandone la scrittura. L'uso della funzione
-\func{sync} (vedi \secref{sec:file_sync}) effettua esplicitamente il
+\func{sync} (vedi sez.~\ref{sec:file_sync}) effettua esplicitamente il
\emph{flush} dei dati, ma anche in questo caso resta l'incertezza dovuta al
comportamento dell'hardware (che a sua volta può introdurre ottimizzazioni
dell'accesso al disco che ritardano la scrittura dei dati, da cui l'abitudine
\subsection{La funzione \func{lseek}}
\label{sec:file_lseek}
-Come già accennato in \secref{sec:file_fd} a ciascun file aperto è associata
+Come già accennato in sez.~\ref{sec:file_fd} a ciascun file aperto è associata
una \textsl{posizione corrente nel file} (il cosiddetto \textit{file offset},
mantenuto nel campo \var{f\_pos} di \struct{file}) espressa da un numero intero
positivo come numero di byte dall'inizio del file. Tutte le operazioni di
per ottenere la nuova posizione corrente.
\end{basedescript}
-Come accennato in \secref{sec:file_file_size} con \func{lseek} è possibile
+Come accennato in sez.~\ref{sec:file_file_size} con \func{lseek} è possibile
impostare la posizione corrente anche oltre la fine del file, e alla
successiva scrittura il file sarà esteso. La chiamata non causa nessun accesso
al file, si limita a modificare la posizione corrente (cioè il valore
-\var{f\_pos} in \param{file}, vedi \figref{fig:file_proc_file}). Dato che la
+\var{f\_pos} in \param{file}, vedi fig.~\ref{fig:file_proc_file}). Dato che la
funzione ritorna la nuova posizione, usando il valore zero per \param{offset}
si può riottenere la posizione corrente nel file chiamando la funzione con
\code{lseek(fd, 0, SEEK\_CUR)}.
la successiva scrittura avvenga alla fine del file, infatti se questo è stato
aperto anche da un altro processo che vi ha scritto, la fine del file può
essersi spostata, ma noi scriveremo alla posizione impostata in precedenza
-(questa è una potenziale sorgente di
-\textit{race condition}\index{race condition}, vedi \secref{sec:file_atomic}).
+(questa è una potenziale sorgente di \textit{race condition}
+\index{race condition}, vedi sez.~\ref{sec:file_atomic}).
Non tutti i file supportano la capacità di eseguire una \func{lseek}, in
questo caso la funzione ritorna l'errore \errcode{EPIPE}. Questo, oltre che per
quando si legge da un terminale, da una fifo o da una pipe. In tal caso
infatti, se non ci sono dati in ingresso, la \func{read} si blocca (a meno di
non aver selezionato la modalità non bloccante, vedi
-\secref{sec:file_noblocking}) e ritorna solo quando ne arrivano; se il numero
+sez.~\ref{sec:file_noblocking}) e ritorna solo quando ne arrivano; se il numero
di byte richiesti eccede quelli disponibili la funzione ritorna comunque, ma
con un numero di byte inferiore a quelli richiesti.
Lo stesso comportamento avviene caso di lettura dalla rete (cioè su un
-socket\index{socket}, come vedremo in \secref{sec:sock_io_behav}), o per la
+socket\index{socket}, come vedremo in sez.~\ref{sec:sock_io_behav}), o per la
lettura da certi file di dispositivo, come le unità a nastro, che
restituiscono sempre i dati ad un singolo blocco alla volta.
\errcode{EAGAIN} non sono errori. La prima si verifica quando la \func{read} è
bloccata in attesa di dati in ingresso e viene interrotta da un segnale; in
tal caso l'azione da intraprendere è quella di rieseguire la funzione.
-Torneremo in dettaglio sull'argomento in \secref{sec:sig_gen_beha}. La
+Torneremo in dettaglio sull'argomento in sez.~\ref{sec:sig_gen_beha}. La
seconda si verifica quando il file è in modalità non bloccante (vedi
-\secref{sec:file_noblocking}) e non ci sono dati in ingresso: la funzione
+sez.~\ref{sec:file_noblocking}) e non ci sono dati in ingresso: la funzione
allora ritorna immediatamente con un errore \errcode{EAGAIN}\footnote{BSD usa
per questo errore la costante \errcode{EWOULDBLOCK}, in Linux, con le
\acr{glibc}, questa è sinonima di \errcode{EAGAIN}.} che indica soltanto che
l'emulazione per i vecchi kernel che non hanno la system call, è stato
aggiunto con la versione 2.1, in versioni precedenti sia del kernel che
delle librerie la funzione non è disponibile.} (quello che viene chiamato
-normalmente Unix98, vedi \secref{sec:intro_opengroup}) è stata introdotta la
+normalmente Unix98, vedi sez.~\ref{sec:intro_opengroup}) è stata introdotta la
definizione di un'altra funzione di lettura, \funcd{pread}, il cui prototipo è:
\begin{prototype}{unistd.h}
{ssize\_t pread(int fd, void * buf, size\_t count, off\_t offset)}
\func{read} seguita da una \func{lseek} che riporti al valore precedente la
posizione corrente sul file, ma permette di eseguire l'operazione
atomicamente. Questo può essere importante quando la posizione sul file viene
-condivisa da processi diversi (vedi \secref{sec:file_sharing}). Il valore di
+condivisa da processi diversi (vedi sez.~\ref{sec:file_sharing}). Il valore di
\param{offset} fa sempre riferimento all'inizio del file.
della gestione file in un sistema unix-like, esaminando in dettaglio il
comportamento delle funzioni base, inoltre tratteremo le funzioni che
permettono di eseguire alcune operazioni avanzate con i file (il grosso
-dell'argomento sarà comunque affrontato in \capref{cha:file_advanced}).
+dell'argomento sarà comunque affrontato in cap.~\ref{cha:file_advanced}).
\subsection{La condivisione dei files}
\label{sec:file_sharing}
-In \secref{sec:file_fd} abbiamo descritto brevemente l'architettura
+In sez.~\ref{sec:file_fd} abbiamo descritto brevemente l'architettura
dell'interfaccia con i file da parte di un processo, mostrando in
-\figref{fig:file_proc_file} le principali strutture usate dal kernel;
+fig.~\ref{fig:file_proc_file} le principali strutture usate dal kernel;
esamineremo ora in dettaglio le conseguenze che questa architettura ha nei
confronti dell'accesso allo stesso file da parte di processi diversi.
\end{figure}
Il primo caso è quello in cui due processi diversi aprono lo stesso file
-su disco; sulla base di quanto visto in \secref{sec:file_fd} avremo una
-situazione come quella illustrata in \figref{fig:file_mult_acc}: ciascun
+su disco; sulla base di quanto visto in sez.~\ref{sec:file_fd} avremo una
+situazione come quella illustrata in fig.~\ref{fig:file_mult_acc}: ciascun
processo avrà una sua voce nella \textit{file table} referenziata da un
diverso file descriptor nella sua \struct{file\_struct}. Entrambe le voci
nella \textit{file table} faranno però riferimento allo stesso
Il secondo caso è quello in cui due file descriptor di due processi diversi
puntino alla stessa voce nella \textit{file table}; questo è ad esempio il
caso dei file aperti che vengono ereditati dal processo figlio all'esecuzione
-di una \func{fork} (si ricordi quanto detto in \secref{sec:proc_fork}). La
-situazione è illustrata in \figref{fig:file_acc_child}; dato che il processo
+di una \func{fork} (si ricordi quanto detto in sez.~\ref{sec:proc_fork}). La
+situazione è illustrata in fig.~\ref{fig:file_acc_child}; dato che il processo
figlio riceve una copia dello spazio di indirizzi del padre, riceverà anche
una copia di \struct{file\_struct} e relativa tabella dei file aperti.
In questo modo padre e figlio avranno gli stessi file descriptor che faranno
riferimento alla stessa voce nella \textit{file table}, condividendo così la
posizione corrente sul file. Questo ha le conseguenze descritte a suo tempo in
-\secref{sec:proc_fork}: in caso di scrittura contemporanea la posizione
+sez.~\ref{sec:proc_fork}: in caso di scrittura contemporanea la posizione
corrente nel file varierà per entrambi i processi (in quanto verrà modificato
\var{f\_pos} che è lo stesso per entrambi).
maniera imprevedibile. Il sistema però fornisce in alcuni casi la possibilità
di eseguire alcune operazioni di scrittura in maniera coordinata anche senza
utilizzare meccanismi di sincronizzazione più complessi (come il \textit{file
- locking}\index{file!locking}, che esamineremo in \secref{sec:file_locking}).
+ locking}\index{file!locking}, che esamineremo in
+sez.~\ref{sec:file_locking}).
Un caso tipico di necessità di accesso condiviso in scrittura è quello in cui
vari processi devono scrivere alla fine di un file (ad esempio un file di
-log). Come accennato in \secref{sec:file_lseek} impostare la posizione alla
+log). Come accennato in sez.~\ref{sec:file_lseek} impostare la posizione alla
fine del file e poi scrivere può condurre ad una \textit{race
condition}\index{race condition}: infatti può succedere che un secondo
processo scriva alla fine del file fra la \func{lseek} e la \func{write}; in
dell'esistenza del file (con relativa uscita dalla funzione con un errore) e
creazione in caso di assenza, diventa atomica essendo svolta tutta all'interno
di una singola system call (per i dettagli sull'uso di questa caratteristica
-si veda \secref{sec:ipc_file_lock}).
+si veda sez.~\ref{sec:ipc_file_lock}).
\subsection{La funzioni \func{sync} e \func{fsync}}
\label{sec:file_sync}
-Come accennato in \secref{sec:file_close} tutte le operazioni di scrittura
+Come accennato in sez.~\ref{sec:file_close} tutte le operazioni di scrittura
sono in genere bufferizzate dal kernel, che provvede ad effettuarle in maniera
asincrona (ad esempio accorpando gli accessi alla stessa zona del disco) in un
secondo tempo rispetto al momento della esecuzione della \func{write}.
\subsection{La funzioni \func{dup} e \func{dup2}}
\label{sec:file_dup}
-Abbiamo già visto in \secref{sec:file_sharing} come un processo figlio
+Abbiamo già visto in sez.~\ref{sec:file_sharing} come un processo figlio
condivida gli stessi file descriptor del padre; è possibile però ottenere un
comportamento analogo all'interno di uno stesso processo \textit{duplicando}
un file descriptor. Per far questo si usa la funzione \funcd{dup} il cui
La funzione ritorna, come \func{open}, il primo file descriptor libero. Il
file descriptor è una copia esatta del precedente ed entrambi possono essere
interscambiati nell'uso. Per capire meglio il funzionamento della funzione si
-può fare riferimento a \figref{fig:file_dup}: l'effetto della funzione è
+può fare riferimento a fig.~\ref{fig:file_dup}: l'effetto della funzione è
semplicemente quello di copiare il valore nella struttura
\struct{file\_struct}, cosicché anche il nuovo file descriptor fa riferimento
alla stessa voce nella \textit{file table}; per questo si dice che il nuovo
\label{fig:file_dup}
\end{figure}
-Si noti che per quanto illustrato in\figref{fig:file_dup} i file descriptor
+Si noti che per quanto illustrato in fig.~\ref{fig:file_dup} i file descriptor
duplicati condivideranno eventuali lock, \textit{file status flag}, e
posizione corrente. Se ad esempio si esegue una \func{lseek} per modificare la
posizione su uno dei due file descriptor, essa risulterà modificata anche
differenza fra due file descriptor duplicati è che ciascuno avrà il suo
\textit{file descriptor flag}; a questo proposito va specificato che nel caso
di \func{dup} il flag di \textit{close-on-exec}\index{close-on-exec} (vedi
-\secref{sec:proc_exec} e \secref{sec:file_fcntl}) viene sempre cancellato
+sez.~\ref{sec:proc_exec} e sez.~\ref{sec:file_fcntl}) viene sempre cancellato
nella copia.
L'uso principale di questa funzione è per la redirezione dell'input e
dell'output fra l'esecuzione di una \func{fork} e la successiva \func{exec};
diventa così possibile associare un file (o una pipe) allo standard input o
-allo standard output (torneremo sull'argomento in \secref{sec:ipc_pipe_use},
+allo standard output (torneremo sull'argomento in sez.~\ref{sec:ipc_pipe_use},
quando tratteremo le pipe). Per fare questo in genere occorre prima chiudere
il file che si vuole sostituire, cosicché il suo file descriptor possa esser
restituito alla chiamata di \func{dup}, come primo file descriptor
La duplicazione dei file descriptor può essere effettuata anche usando la
funzione di controllo dei file \func{fnctl} (che esamineremo in
-\secref{sec:file_fcntl}) con il parametro \const{F\_DUPFD}. L'operazione ha
+sez.~\ref{sec:file_fcntl}) con il parametro \const{F\_DUPFD}. L'operazione ha
la sintassi \code{fnctl(oldfd, F\_DUPFD, newfd)} e se si usa 0 come valore per
\param{newfd} diventa equivalente a \func{dup}.
\subsection{La funzione \func{fcntl}}
\label{sec:file_fcntl}
-Oltre alle operazioni base esaminate in \secref{sec:file_base_func} esistono
+Oltre alle operazioni base esaminate in sez.~\ref{sec:file_base_func} esistono
tutta una serie di operazioni ausiliarie che è possibile eseguire su un file
descriptor, che non riguardano la normale lettura e scrittura di dati, ma la
gestione sia delle loro proprietà, che di tutta una serie di ulteriori
funzionalità che il kernel può mettere a disposizione.\footnote{ad esempio si
gestiscono con questa funzione varie modalità di I/O asincrono (vedi
- \secref{sec:file_asyncronous_operation}) e il file
- locking\index{file!locking} (vedi \secref{sec:file_locking}).}
+ sez.~\ref{sec:file_asyncronous_operation}) e il file
+ locking\index{file!locking} (vedi sez.~\ref{sec:file_locking}).}
Per queste operazioni di manipolazione e di controllo delle varie proprietà e
caratteristiche di un file descriptor, viene usata la funzione \funcd{fcntl},
numero e il tipo degli argomenti, il valore di ritorno e gli eventuali errori
sono determinati dal valore dell'argomento \param{cmd} che in sostanza
corrisponde all'esecuzione di un determinato \textsl{comando}; in
-\secref{sec:file_dup} abbiamo incontrato un esempio dell'uso di \func{fcntl}
+sez.~\ref{sec:file_dup} abbiamo incontrato un esempio dell'uso di \func{fcntl}
per la duplicazione dei file descriptor, una lista di tutti i possibili valori
per \var{cmd} è riportata di seguito:
\begin{basedescript}{\desclabelwidth{2.0cm}}
valore specificato con \param{arg}. Al momento l'unico bit usato è quello di
\textit{close-on-exec}\index{close-on-exec}, identificato dalla costante
\const{FD\_CLOEXEC}, che serve a richiedere che il file venga chiuso nella
- esecuzione di una \func{exec} (vedi \secref{sec:proc_exec}). Ritorna un
+ esecuzione di una \func{exec} (vedi sez.~\ref{sec:proc_exec}). Ritorna un
valore nullo in caso di successo e -1 in caso di errore.
\item[\const{F\_GETFD}] ritorna il valore del \textit{file descriptor flag} di
\param{fd} o -1 in caso di errore; se \const{FD\_CLOEXEC} è impostato i file
caso di successo o -1 in caso di errore; permette cioè di rileggere quei bit
impostati da \func{open} all'apertura del file che vengono memorizzati
(quelli riportati nella prima e terza sezione di
- \tabref{tab:file_open_flags}).
+ tab.~\ref{tab:file_open_flags}).
\item[\const{F\_SETFL}] imposta il \textit{file status flag} al valore
specificato da \param{arg}, ritorna un valore nullo in caso di successo o -1
in caso di errore. Possono essere impostati solo i bit riportati nella terza
- sezione di \tabref{tab:file_open_flags}.\footnote{la pagina di manuale
+ sezione di tab.~\ref{tab:file_open_flags}.\footnote{la pagina di manuale
riporta come impostabili solo \const{O\_APPEND}, \const{O\_NONBLOCK} e
\const{O\_ASYNC}.}
\item[\const{F\_GETLK}] richiede un controllo sul file lock specificato da
\param{lock}, sovrascrivendo la struttura da esso puntata con il risultato,
ritorna un valore nullo in caso di successo o -1 in caso di errore. Questa
- funzionalità è trattata in dettaglio in \secref{sec:file_posix_lock}.
+ funzionalità è trattata in dettaglio in sez.~\ref{sec:file_posix_lock}.
\item[\const{F\_SETLK}] richiede o rilascia un file lock a seconda di quanto
specificato nella struttura puntata da \param{lock}. Se il lock è tenuto da
qualcun'altro ritorna immediatamente restituendo -1 e imposta \var{errno} a
\errcode{EACCES} o \errcode{EAGAIN}, in caso di successo ritorna un valore
nullo. Questa funzionalità è trattata in dettaglio in
- \secref{sec:file_posix_lock}.
+ sez.~\ref{sec:file_posix_lock}.
\item[\const{F\_SETLKW}] identica a \const{F\_SETLK} eccetto per il fatto che
la funzione non ritorna subito ma attende che il blocco sia rilasciato. Se
l'attesa viene interrotta da un segnale la funzione restituisce -1 e imposta
\var{errno} a \errcode{EINTR}, in caso di successo ritorna un valore nullo.
- Questa funzionalità è trattata in dettaglio in \secref{sec:file_posix_lock}.
+ Questa funzionalità è trattata in dettaglio in
+ sez.~\ref{sec:file_posix_lock}.
\item[\const{F\_GETOWN}] restituisce il \acr{pid} del processo o
l'identificatore del process group\footnote{i \texttt{process group} sono
- (vedi \secref{sec:sess_proc_group}) raggruppamenti di processi usati nel
+ (vedi sez.~\ref{sec:sess_proc_group}) raggruppamenti di processi usati nel
controllo di sessione; a ciascuno di essi è associato un identificatore
(un numero positivo analogo al \acr{pid}).} che è preposto alla ricezione
dei segnali \const{SIGIO} e \const{SIGURG} per gli eventi associati al file
group}.
\item[\const{F\_GETSIG}] restituisce il valore del segnale inviato quando ci
sono dati disponibili in ingresso su un file descriptor aperto ed impostato
- per l'I/O asincrono (si veda \secref{sec:file_asyncronous_io}). Il valore 0
+ per l'I/O asincrono (si veda sez.~\ref{sec:file_asyncronous_io}). Il valore 0
indica il valore predefinito (che è \const{SIGIO}), un valore diverso da
zero indica il segnale richiesto, (che può essere anche lo stesso
\const{SIGIO}). In caso di errore ritorna -1.
valore diverso da zero (compreso lo stesso \const{SIGIO}) specifica il
segnale voluto; l'uso di un valore diverso da zero permette inoltre, se si è
installato il gestore del segnale come \var{sa\_sigaction} usando
- \const{SA\_SIGINFO}, (vedi \secref{sec:sig_sigaction}), di rendere
+ \const{SA\_SIGINFO}, (vedi sez.~\ref{sec:sig_sigaction}), di rendere
disponibili al gestore informazioni ulteriori riguardo il file che ha
generato il segnale attraverso i valori restituiti in \struct{siginfo\_t}
- (come vedremo in \secref{sec:file_asyncronous_io}).\footnote{i due comandi
+ (come vedremo in sez.~\ref{sec:file_asyncronous_io}).\footnote{i due comandi
\const{F\_SETSIG} e \const{F\_GETSIG} sono una estensione specifica di
Linux.}
\item[\const{F\_SETLEASE}] imposta o rimuove un \textit{file
di esso.} sul file descriptor \var{fd} a seconda del valore del terzo
argomento, che in questo caso è un \ctyp{int}, ritorna un valore nullo in
caso di successo o -1 in caso di errore. Questa funzionalità avanzata è
- trattata in dettaglio in \secref{sec:file_asyncronous_operation}.
+ trattata in dettaglio in sez.~\ref{sec:file_asyncronous_operation}.
\item[\const{F\_GETLEASE}] restituisce il tipo di \textit{file lease} che il
processo detiene nei confronti del file descriptor \var{fd} o -1 in caso di
errore. Con questo comando il terzo argomento può essere omesso. Questa
funzionalità avanzata è trattata in dettaglio in
- \secref{sec:file_asyncronous_operation}.
+ sez.~\ref{sec:file_asyncronous_operation}.
\item[\const{F\_NOTIFY}] attiva un meccanismo di notifica per cui viene
riportata al processo chiamante, tramite il segnale \const{SIGIO} (o altro
segnale specificato con \const{F\_SETSIG}) ogni modifica eseguita o
direttamente sulla directory cui \var{fd} fa riferimento, o su uno dei file
in essa contenuti; ritorna un valore nullo in caso di successo o -1 in caso
di errore. Questa funzionalità avanzata, disponibile dai kernel della serie
- 2.4.x, è trattata in dettaglio in \secref{sec:file_asyncronous_operation}.
+ 2.4.x, è trattata in dettaglio in sez.~\ref{sec:file_asyncronous_operation}.
\end{basedescript}
La maggior parte delle funzionalità di \func{fcntl} sono troppo avanzate per
pertanto riprese più avanti quando affronteremo le problematiche ad esse
relative. In particolare le tematiche relative all'I/O asincrono e ai vari
meccanismi di notifica saranno trattate in maniera esaustiva in
-\secref{sec:file_asyncronous_operation} mentre quelle relative al \textit{file
- locking}\index{file!locking} saranno esaminate in
-\secref{sec:file_locking}).
+sez.~\ref{sec:file_asyncronous_operation} mentre quelle relative al
+\textit{file locking}\index{file!locking} saranno esaminate in
+sez.~\ref{sec:file_locking}).
Si tenga presente infine che quando si usa la funzione per determinare le
La memoria viene sempre gestita dal kernel attraverso il meccanismo della
\textsl{memoria virtuale}\index{memoria virtuale}, che consente di assegnare a
ciascun processo uno spazio di indirizzi ``\textsl{virtuale}'' (vedi
-\secref{sec:proc_memory}) che il kernel stesso, con l'ausilio della unità di
+sez.~\ref{sec:proc_memory}) che il kernel stesso, con l'ausilio della unità di
gestione della memoria, si incaricherà di rimappare automaticamente sulla
memoria disponibile, salvando su disco quando necessario (nella cosiddetta
area di \textit{swap}) le pagine di memoria in eccedenza.
Le periferiche infine vengono viste in genere attraverso un'interfaccia
astratta che permette di trattarle come fossero file, secondo il concetto per
cui \textit{everything is a file}, su cui torneremo in dettaglio in
-\capref{cha:file_intro}, (questo non è vero per le interfacce di rete, che
+cap.~\ref{cha:file_intro}, (questo non è vero per le interfacce di rete, che
hanno un'interfaccia diversa, ma resta valido il concetto generale che tutto
il lavoro di accesso e gestione a basso livello è effettuato dal kernel).
chiamate, che sono riportate nella seconda sezione del \textsl{Manuale di
programmazione di Unix} (quella cui si accede con il comando \cmd{man 2
<nome>}) e Linux non fa eccezione. Queste sono poi state codificate da vari
-standard, che esamineremo brevemente in \secref{sec:intro_standard}. Uno
+standard, che esamineremo brevemente in sez.~\ref{sec:intro_standard}. Uno
schema elementare della struttura del sistema è riportato in
-\figref{fig:intro_sys_struct}.
+fig.~\ref{fig:intro_sys_struct}.
\begin{figure}[htb]
\centering
Ogni utente è identificato da un nome (l'\textit{username}), che è quello che
viene richiesto all'ingresso nel sistema dalla procedura di \textit{login}
-(descritta in dettaglio in \secref{sec:sess_login}). Questa procedura si
+(descritta in dettaglio in sez.~\ref{sec:sess_login}). Questa procedura si
incarica di verificare l'identità dell'utente, in genere attraverso la
richiesta di una parola d'ordine (la \textit{password}), anche se sono
possibili meccanismi diversi.\footnote{Ad esempio usando la libreria PAM
appartiene ciascun processo ed impedire ad altri utenti di interferire con
quest'ultimo. Inoltre con questo sistema viene anche garantita una forma base
di sicurezza interna in quanto anche l'accesso ai file (vedi
-\secref{sec:file_access_control}) è regolato da questo meccanismo di
+sez.~\ref{sec:file_access_control}) è regolato da questo meccanismo di
identificazione.
Infine in ogni Unix è presente un utente speciale privilegiato, il cosiddetto
funzioni occorre includere con la direttiva \code{\#include} questi file nei
propri programmi; per ciascuna funzione che tratteremo in seguito
indicheremo anche gli \textit{header file} necessari ad usarla.} (anch'essi
-provvisti dalla \acr{glibc}), In \tabref{tab:intro_posix_header} si sono
+provvisti dalla \acr{glibc}), In tab.~\ref{tab:intro_posix_header} si sono
riportati i principali \textit{header file} definiti nello standard POSIX,
insieme a quelli definiti negli altri standard descritti nelle sezioni
successive.
Per questo motivo tutte le funzioni di libreria di solito non fanno
riferimento ai tipi elementari dello standard del linguaggio C, ma ad una
serie di \textsl{tipi primitivi}\index{tipo!primitivo} del sistema, riportati
-in \tabref{tab:intro_primitive_types}, e definiti nell'header file
+in tab.~\ref{tab:intro_primitive_types}, e definiti nell'header file
\file{sys/types.h}, in modo da mantenere completamente indipendenti i tipi
utilizzati dalle funzioni di sistema dai tipi elementari supportati dal
compilatore C.
Ma gli standard POSIX non si limitano alla standardizzazione delle funzioni di
libreria, e in seguito sono stati prodotti anche altri standard per la shell e
i comandi di sistema (1003.2), per le estensioni realtime e per i thread
-(1003.1d e 1003.1c) e vari altri. In \tabref{tab:intro_posix_std} è riportata
-una classificazione sommaria dei principali documenti prodotti, e di come sono
-identificati fra IEEE ed ISO; si tenga conto inoltre che molto spesso si usa
-l'estensione IEEE anche come aggiunta al nome POSIX (ad esempio si può parlare
-di POSIX.4 come di POSIX.1b).
+(1003.1d e 1003.1c) e vari altri. In tab.~\ref{tab:intro_posix_std} è
+riportata una classificazione sommaria dei principali documenti prodotti, e di
+come sono identificati fra IEEE ed ISO; si tenga conto inoltre che molto
+spesso si usa l'estensione IEEE anche come aggiunta al nome POSIX (ad esempio
+si può parlare di POSIX.4 come di POSIX.1b).
Si tenga presente inoltre che nuove specifiche e proposte di standardizzazione
si aggiungono continuamente, mentre le versioni precedenti vengono riviste;
Nelle versioni più recenti del kernel e delle librerie sono inoltre supportate
ulteriori funzionalità aggiunte dallo standard POSIX.1c per quanto riguarda i
-\textit{thread} (vedi \capref{cha:threads}), e dallo standard POSIX.1b per
+\textit{thread} (vedi cap.~\ref{cha:threads}), e dallo standard POSIX.1b per
quanto riguarda i segnali e lo scheduling real-time
-(\secref{sec:sig_real_time} e \secref{sec:proc_real_time}), la misura del
-tempo, i meccanismi di intercomunicazione (\secref{sec:ipc_posix}) e l'I/O
-asincrono (\secref{sec:file_asyncronous_io}).
+(sez.~\ref{sec:sig_real_time} e sez.~\ref{sec:proc_real_time}), la misura del
+tempo, i meccanismi di intercomunicazione (sez.~\ref{sec:ipc_posix}) e l'I/O
+asincrono (sez.~\ref{sec:file_asyncronous_io}).
Le funzionalità implementate sono principalmente il meccanismo di
intercomunicazione fra i processi e la memoria condivisa (il cosiddetto System
-V IPC, che vedremo in \secref{sec:ipc_sysv}) le funzioni della famiglia
+V IPC, che vedremo in sez.~\ref{sec:ipc_sysv}) le funzioni della famiglia
\func{hsearch} e \func{drand48}, \func{fmtmsg} e svariate funzioni
matematiche.
Le \textit{pipe} nascono sostanzialmente con Unix, e sono il primo, e tuttora
uno dei più usati, meccanismi di comunicazione fra processi. Si tratta in
-sostanza di una una coppia di file descriptor\footnote{si tenga presente che
+sostanza di una coppia di file descriptor\footnote{si tenga presente che
le pipe sono oggetti creati dal kernel e non risiedono su disco.} connessi
fra di loro in modo che se quanto scrive su di uno si può rileggere
dall'altro. Si viene così a costituire un canale di comunicazione tramite i
nel file descriptor aperto in lettura. I file descriptor infatti non sono
connessi a nessun file reale, ma ad un buffer nel kernel, la cui dimensione è
specificata dal parametro di sistema \const{PIPE\_BUF}, (vedi
-\secref{sec:sys_file_limits}). Lo schema di funzionamento di una pipe è
-illustrato in \figref{fig:ipc_pipe_singular}, in cui sono illustrati i due
+sez.~\ref{sec:sys_file_limits}). Lo schema di funzionamento di una pipe è
+illustrato in fig.~\ref{fig:ipc_pipe_singular}, in cui sono illustrati i due
capi della pipe, associati a ciascun file descriptor, con le frecce che
indicano la direzione del flusso dei dati.
\end{figure}
Chiaramente creare una pipe all'interno di un singolo processo non serve a
-niente; se però ricordiamo quanto esposto in \secref{sec:file_sharing}
+niente; se però ricordiamo quanto esposto in sez.~\ref{sec:file_sharing}
riguardo al comportamento dei file descriptor nei processi figli, è immediato
capire come una pipe possa diventare un meccanismo di intercomunicazione. Un
processo figlio infatti condivide gli stessi file descriptor del padre,
compresi quelli associati ad una pipe (secondo la situazione illustrata in
-\figref{fig:ipc_pipe_fork}). In questo modo se uno dei processi scrive su un
+fig.~\ref{fig:ipc_pipe_fork}). In questo modo se uno dei processi scrive su un
capo della pipe, l'altro può leggere.
\begin{figure}[htb]
codici a barre corrispondenti ad una qualunque stringa, mentre il secondo
serve per poter effettuare la conversione della stessa immagine in formato
JPEG. Usando una pipe potremo inviare l'output del primo sull'input del
-secondo, secondo lo schema mostrato in \figref{fig:ipc_pipe_use}, in cui la
+secondo, secondo lo schema mostrato in fig.~\ref{fig:ipc_pipe_use}, in cui la
direzione del flusso dei dati è data dalle frecce continue.
\begin{figure}[htb]
\centering
\includegraphics[height=5cm]{img/pipeuse}
\caption{Schema dell'uso di una pipe come mezzo di comunicazione fra
- due processi attraverso attraverso l'esecuzione una \func{fork} e la
- chiusura dei capi non utilizzati.}
+ due processi attraverso l'esecuzione una \func{fork} e la chiusura dei
+ capi non utilizzati.}
\label{fig:ipc_pipe_use}
\end{figure}
Il programma ci servirà anche come esempio dell'uso delle funzioni di
duplicazione dei file descriptor che abbiamo trattato in
-\secref{sec:file_dup}, in particolare di \func{dup2}. È attraverso queste
+sez.~\ref{sec:file_dup}, in particolare di \func{dup2}. È attraverso queste
funzioni infatti che è possibile dirottare gli stream standard dei processi
-(che abbiamo visto in \secref{sec:file_std_descr} e
-\secref{sec:file_std_stream}) sulla pipe. In \figref{fig:ipc_barcodepage_code}
-abbiamo riportato il corpo del programma, il cui codice completo è disponibile
-nel file \file{BarCodePage.c} che si trova nella directory dei sorgenti.
+(che abbiamo visto in sez.~\ref{sec:file_std_descr} e
+sez.~\ref{sec:file_std_stream}) sulla pipe. In
+fig.~\ref{fig:ipc_barcodepage_code} abbiamo riportato il corpo del programma,
+il cui codice completo è disponibile nel file \file{BarCodePage.c} che si
+trova nella directory dei sorgenti.
\begin{figure}[!htb]
per produrre il codice a barre; si ha cura di controllare la riuscita della
chiamata, inviando in caso di errore un messaggio invece dell'immagine
richiesta.\footnote{la funzione \func{WriteMess} non è riportata in
- \secref{fig:ipc_barcodepage_code}; essa si incarica semplicemente di
+ fig.~\ref{fig:ipc_barcodepage_code}; essa si incarica semplicemente di
formattare l'uscita alla maniera dei CGI, aggiungendo l'opportuno
\textit{mime type}, e formattando il messaggio in HTML, in modo che
quest'ultimo possa essere visualizzato correttamente da un browser.}
quindi associato allo standard input) in caso di \code{"w"}.
Lo stream restituito da \func{popen} è identico a tutti gli effetti ai file
-stream visti in \capref{cha:files_std_interface}, anche se è collegato ad una
-pipe e non ad un file, e viene sempre aperto in modalità
-\textit{fully-buffered} (vedi \secref{sec:file_buffering}); l'unica differenza
-con gli usuali stream è che dovrà essere chiuso dalla seconda delle due nuove
-funzioni, \funcd{pclose}, il cui prototipo è:
+stream visti in cap.~\ref{cha:files_std_interface}, anche se è collegato ad
+una pipe e non ad un file, e viene sempre aperto in modalità
+\textit{fully-buffered} (vedi sez.~\ref{sec:file_buffering}); l'unica
+differenza con gli usuali stream è che dovrà essere chiuso dalla seconda delle
+due nuove funzioni, \funcd{pclose}, il cui prototipo è:
\begin{prototype}{stdio.h}
{int pclose(FILE *stream)}
\func{popen}.
Per illustrare l'uso di queste due funzioni riprendiamo il problema
-precedente: il programma mostrato in \figref{fig:ipc_barcodepage_code} per
+precedente: il programma mostrato in fig.~\ref{fig:ipc_barcodepage_code} per
quanto funzionante, è (volutamente) codificato in maniera piuttosto complessa,
inoltre nella pratica sconta un problema di \cmd{gs} che non è in
grado\footnote{nella versione GNU Ghostscript 6.53 (2002-02-13).} di
Nel nostro caso, dato che ciascun processo deve scrivere il suo output sullo
standard input del successivo, occorrerà usare \func{popen} aprendo la pipe in
scrittura. Il codice del nuovo programma è riportato in
-\figref{fig:ipc_barcode_code}. Come si può notare l'ordine di invocazione dei
-programmi è l'inverso di quello in cui ci si aspetta che vengano
+fig.~\ref{fig:ipc_barcode_code}. Come si può notare l'ordine di invocazione
+dei programmi è l'inverso di quello in cui ci si aspetta che vengano
effettivamente eseguiti. Questo non comporta nessun problema dato che la
lettura su una pipe è bloccante, per cui ciascun processo, per quanto lanciato
per primo, si bloccherà in attesa di ricevere sullo standard input il
-risultato dell'elaborazione del precedente, benchè quest'ultimo venga
-invocato dopo.
+risultato dell'elaborazione del precedente, benchè quest'ultimo venga invocato
+dopo.
\begin{figure}[!htb]
\footnotesize \centering
\subsection{Le \textit{pipe} con nome, o \textit{fifo}}
\label{sec:ipc_named_pipe}
-Come accennato in \secref{sec:ipc_pipes} il problema delle \textit{pipe} è che
-esse possono essere utilizzate solo da processi con un progenitore comune o
-nella relazione padre/figlio; per superare questo problema lo standard POSIX.1
-ha definito dei nuovi oggetti, le \textit{fifo}, che hanno le stesse
+Come accennato in sez.~\ref{sec:ipc_pipes} il problema delle \textit{pipe} è
+che esse possono essere utilizzate solo da processi con un progenitore comune
+o nella relazione padre/figlio; per superare questo problema lo standard
+POSIX.1 ha definito dei nuovi oggetti, le \textit{fifo}, che hanno le stesse
caratteristiche delle pipe, ma che invece di essere strutture interne del
kernel, visibili solo attraverso un file descriptor, sono accessibili
attraverso un inode\index{inode} che risiede sul filesystem, così che i
l'inode\index{inode} allocato sul filesystem serve infatti solo a fornire un
punto di riferimento per i processi, che permetta loro di accedere alla stessa
fifo; il comportamento delle funzioni di lettura e scrittura è identico a
-quello illustrato per le pipe in \secref{sec:ipc_pipes}.
+quello illustrato per le pipe in sez.~\ref{sec:ipc_pipes}.
-Abbiamo già visto in \secref{sec:file_mknod} le funzioni \func{mknod} e
+Abbiamo già visto in sez.~\ref{sec:file_mknod} le funzioni \func{mknod} e
\func{mkfifo} che permettono di creare una fifo; per utilizzarne una un
processo non avrà che da aprire il relativo file speciale o in lettura o
scrittura; nel primo caso sarà collegato al capo di uscita della fifo, e dovrà
fondamentale che le operazioni di scrittura siano atomiche; per questo si deve
sempre tenere presente che questo è vero soltanto fintanto che non si supera
il limite delle dimensioni di \const{PIPE\_BUF} (si ricordi quanto detto in
-\secref{sec:ipc_pipes}).
+sez.~\ref{sec:ipc_pipes}).
A parte il caso precedente, che resta probabilmente il più comune, Stevens
riporta in \cite{APUE} altre due casistiche principali per l'uso delle fifo:
sull'input di parecchi altri (attraverso l'uso del comando \cmd{tee}).
\item Come canale di comunicazione fra client ed server (il modello
- \textit{client-server} è illustrato in \secref{sec:net_cliserv}).
+ \textit{client-server} è illustrato in sez.~\ref{sec:net_cliserv}).
\end{itemize}
Nel primo caso quello che si fa è creare tante fifo, da usare come standard
leggerli, quando i dati inviati sono destinati a loro.
Per risolvere questo problema, si può usare un'architettura come quella
-illustrata in \figref{fig:ipc_fifo_server_arch} in cui i client inviano le
+illustrata in fig.~\ref{fig:ipc_fifo_server_arch} in cui i client inviano le
richieste al server su una fifo nota mentre le risposte vengono reinviate dal
server a ciascuno di essi su una fifo temporanea creata per l'occasione.
un detto a caso estratto da un insieme di frasi; sia il numero delle frasi
dell'insieme, che i file da cui esse vengono lette all'avvio, sono importabili
da riga di comando. Il corpo principale del server è riportato in
-\figref{fig:ipc_fifo_server}, dove si è tralasciata la parte che tratta la
+fig.~\ref{fig:ipc_fifo_server}, dove si è tralasciata la parte che tratta la
gestione delle opzioni a riga di comando, che effettua il settaggio delle
variabili \var{fortunefilename}, che indica il file da cui leggere le frasi,
ed \var{n}, che indica il numero di frasi tenute in memoria, ad un valore
presenza di un valore nullo provoca l'uscita dal programma attraverso la
routine (non riportata) che ne stampa le modalità d'uso. Dopo di che installa
(\texttt{\small 13--15}) la funzione che gestisce i segnali di interruzione
-(anche questa non è riportata in \figref{fig:ipc_fifo_server}) che si limita a
-rimuovere dal filesystem la fifo usata dal server per comunicare.
+(anche questa non è riportata in fig.~\ref{fig:ipc_fifo_server}) che si limita
+a rimuovere dal filesystem la fifo usata dal server per comunicare.
Terminata l'inizializzazione (\texttt{\small 16}) si effettua la chiamata alla
funzione \code{FortuneParse} che legge dal file specificato in
sarà scritta. Infine (\texttt{\small 49}) si chiude la fifo di risposta che
non serve più.
-Il codice del client è invece riportato in \figref{fig:ipc_fifo_client}, anche
-in questo caso si è omessa la gestione delle opzioni e la funzione che stampa
-a video le informazioni di utilizzo ed esce, riportando solo la sezione
+Il codice del client è invece riportato in fig.~\ref{fig:ipc_fifo_client},
+anche in questo caso si è omessa la gestione delle opzioni e la funzione che
+stampa a video le informazioni di utilizzo ed esce, riportando solo la sezione
principale del programma e le definizioni delle variabili. Il codice completo
è nel file \file{FortuneClient.c} dei sorgenti allegati.
Avendo usato \func{daemon} per eseguire il server in background il comando
ritornerà immediatamente, ma potremo verificare con \cmd{ps} che in effetti il
programma resta un esecuzione in background, e senza avere associato un
-terminale di controllo (si ricordi quanto detto in \secref{sec:sess_daemon}):
+terminale di controllo (si ricordi quanto detto in sez.~\ref{sec:sess_daemon}):
\begin{verbatim}
[piccardi@gont sources]$ ps aux
...
fifo non è adatta a risolvere questo tipo di problemi, che possono essere
affrontati in maniera più semplice ed efficace o usando i
\textit{socket}\index{socket} (che tratteremo in dettaglio a partire da
-\capref{cha:socket_intro}) o ricorrendo a meccanismi di comunicazione diversi,
-come quelli che esamineremo in seguito.
+cap.~\ref{cha:socket_intro}) o ricorrendo a meccanismi di comunicazione
+diversi, come quelli che esamineremo in seguito.
Un meccanismo di comunicazione molto simile alle pipe, ma che non presenta il
problema della unidirezionalità del flusso dei dati, è quello dei cosiddetti
\textsl{socket locali} (o \textit{Unix domain socket}). Tratteremo l'argomento
-dei \textit{socket}\index{socket} in \capref{cha:socket_intro},\footnote{si
+dei \textit{socket}\index{socket} in cap.~\ref{cha:socket_intro},\footnote{si
tratta comunque di oggetti di comunicazione che, come le pipe, sono
utilizzati attraverso dei file descriptor.} nell'ambito dell'interfaccia
generale che essi forniscono per la programmazione di rete; e vedremo anche
-(in~\secref{sec:sock_sa_local}) come si possono definire dei file speciali (di
-tipo \textit{socket}, analoghi a quello associati alle fifo) cui si accede
+(in~sez.~\ref{sec:sock_sa_local}) come si possono definire dei file speciali
+(di tipo \textit{socket}, analoghi a quello associati alle fifo) cui si accede
però attraverso quella medesima interfaccia; vale però la pena esaminare qui
una modalità di uso dei socket locali\footnote{la funzione \func{socketpair} è
stata introdotta in BSD4.4, ma è supportata in genere da qualunque sistema
linea non solo dei dati, ma anche dei file descriptor: si può cioè passare da
un processo ad un altro un file descriptor, con una sorta di duplicazione
dello stesso non all'interno di uno stesso processo, ma fra processi distinti
-(torneremo su questa funzionalità in \secref{sec:xxx_fd_passing}).
+(torneremo su questa funzionalità in sez.~\ref{sec:xxx_fd_passing}).
\section{La comunicazione fra processi di System V}
specificando il relativo \textsl{identificatore}. Questo è un numero
progressivo (un po' come il \acr{pid} dei processi) che il kernel assegna a
ciascuno di essi quanto vengono creati (sul procedimento di assegnazione
-torneremo in \secref{sec:ipc_sysv_id_use}). L'identificatore viene restituito
+torneremo in sez.~\ref{sec:ipc_sysv_id_use}). L'identificatore viene restituito
dalle funzioni che creano l'oggetto, ed è quindi locale al processo che le ha
eseguite. Dato che l'identificatore viene assegnato dinamicamente dal kernel
non è possibile prevedere quale sarà, né utilizzare un qualche valore statico,
si sposta il problema dell'accesso dalla classificazione in base
all'identificatore alla classificazione in base alla chiave, una delle tante
complicazioni inutili presenti nel \textit{SysV IPC}.} Oltre la chiave, la
-struttura, la cui definizione è riportata in \figref{fig:ipc_ipc_perm},
+struttura, la cui definizione è riportata in fig.~\ref{fig:ipc_ipc_perm},
mantiene varie proprietà ed informazioni associate all'oggetto.
\begin{figure}[!htb]
identificare un oggetto, come sarebbe stato se lo si fosse associato ad in
file, e tutta l'interfaccia è inutilmente complessa. Per questo ne è stata
effettuata una revisione completa nello standard POSIX.1b, che tratteremo in
-\secref{sec:ipc_posix}.
+sez.~\ref{sec:ipc_posix}.
\subsection{Il controllo di accesso}
(nei campi \var{cuid} e \var{cgid}) e del proprietario (nei campi \var{uid} e
\var{gid}) dello stesso, e un insieme di permessi (nel campo \var{mode}). In
questo modo è possibile definire un controllo di accesso sugli oggetti di IPC,
-simile a quello che si ha per i file (vedi \secref{sec:file_perm_overview}).
+simile a quello che si ha per i file (vedi sez.~\ref{sec:file_perm_overview}).
Benché questo controllo di accesso sia molto simile a quello dei file, restano
delle importanti differenze. La prima è che il permesso di esecuzione non
permessi di lettura e scrittura (nel caso dei semafori poi quest'ultimo è più
propriamente un permesso di modifica). I valori di \var{mode} sono gli stessi
ed hanno lo stesso significato di quelli riportati in
-\secref{tab:file_mode_flags}\footnote{se però si vogliono usare le costanti
+tab.~\ref{tab:file_mode_flags}\footnote{se però si vogliono usare le costanti
simboliche ivi definite occorrerà includere il file \file{sys/stat.h},
alcuni sistemi definiscono le costanti \const{MSG\_R} (\texttt{0400}) e
\const{MSG\_W} (\texttt{0200}) per indicare i permessi base di lettura e
passi elencati non comporta il fallimento dell'accesso. Un'ulteriore
differenza rispetto a quanto avviene per i file è che per gli oggetti di IPC
il valore di \var{umask} (si ricordi quanto esposto in
-\secref{sec:file_umask}) non ha alcun significato.
+sez.~\ref{sec:file_umask}) non ha alcun significato.
\subsection{Gli identificatori ed il loro utilizzo}
\label{sec:ipc_sysv_id_use}
L'unico campo di \struct{ipc\_perm} del quale non abbiamo ancora parlato è
-\var{seq}, che in \figref{fig:ipc_ipc_perm} è qualificato con un criptico
+\var{seq}, che in fig.~\ref{fig:ipc_ipc_perm} è qualificato con un criptico
``\textsl{numero di sequenza}'', ne parliamo adesso dato che esso è
strettamente attinente alle modalità con cui il kernel assegna gli
identificatori degli oggetti del sistema di IPC.
\label{fig:ipc_sysv_idtest}
\end{figure}
-In \figref{fig:ipc_sysv_idtest} è riportato il codice di un semplice programma
-di test che si limita a creare un oggetto (specificato a riga di comando),
-stamparne il numero di identificatore e cancellarlo per un numero specificato
-di volte. Al solito non si è riportato il codice della gestione delle opzioni
-a riga di comando, che permette di specificare quante volte effettuare il
-ciclo \var{n}, e su quale tipo di oggetto eseguirlo.
+In fig.~\ref{fig:ipc_sysv_idtest} è riportato il codice di un semplice
+programma di test che si limita a creare un oggetto (specificato a riga di
+comando), stamparne il numero di identificatore e cancellarlo per un numero
+specificato di volte. Al solito non si è riportato il codice della gestione
+delle opzioni a riga di comando, che permette di specificare quante volte
+effettuare il ciclo \var{n}, e su quale tipo di oggetto eseguirlo.
La figura non riporta il codice di selezione delle opzioni, che permette di
inizializzare i valori delle variabili \var{type} al tipo di oggetto voluto, e
essere nullo e deve essere fornito come maschera binaria, impostando il bit
corrispondente al valore \const{IPC\_CREAT}. In questo caso i nove bit meno
significativi di \param{flag} saranno usati come permessi per il nuovo
-oggetto, secondo quanto illustrato in \secref{sec:ipc_sysv_access_control}.
+oggetto, secondo quanto illustrato in sez.~\ref{sec:ipc_sysv_access_control}.
Se si imposta anche il bit corrispondente a \const{IPC\_EXCL} la funzione avrà
successo solo se l'oggetto non esiste già, fallendo con un errore di
\errcode{EEXIST} altrimenti.
Le code di messaggi sono caratterizzate da tre limiti fondamentali, definiti
negli header e corrispondenti alle prime tre costanti riportate in
-\tabref{tab:ipc_msg_limits}, come accennato però in Linux è possibile
+tab.~\ref{tab:ipc_msg_limits}, come accennato però in Linux è possibile
modificare questi limiti attraverso l'uso di \func{sysctl} o scrivendo nei
file \file{msgmax}, \file{msgmnb} e \file{msgmni} di \file{/proc/sys/kernel/}.
aggiornare un puntatore), e relativamente veloce da attraversare in ordine
sequenziale (seguendo i puntatori), è invece relativamente lenta
nell'accesso casuale e nella ricerca.} i nuovi messaggi vengono inseriti in
-coda alla lista e vengono letti dalla cima, in \figref{fig:ipc_mq_schema} si è
-riportato lo schema con cui queste strutture vengono mantenute dal
-kernel.\footnote{lo schema illustrato in \figref{fig:ipc_mq_schema} è in
+coda alla lista e vengono letti dalla cima, in fig.~\ref{fig:ipc_mq_schema} si
+è riportato lo schema con cui queste strutture vengono mantenute dal
+kernel.\footnote{lo schema illustrato in fig.~\ref{fig:ipc_mq_schema} è in
realtà una semplificazione di quello usato effettivamente fino ai kernel
della serie 2.2.x, nei kernel della serie 2.4.x la gestione delle code di
messaggi è stata modificata ed è effettuata in maniera diversa; abbiamo
\end{figure}
A ciascuna coda è associata una struttura \struct{msgid\_ds}, la cui
-definizione, è riportata in \secref{fig:ipc_msqid_ds}. In questa struttura il
+definizione, è riportata in fig.~\ref{fig:ipc_msqid_ds}. In questa struttura il
kernel mantiene le principali informazioni riguardo lo stato corrente della
coda.\footnote{come accennato questo vale fino ai kernel della serie 2.2.x,
essa viene usata nei kernel della serie 2.4.x solo per compatibilità in
quanto è quella restituita dalle funzioni dell'interfaccia. Si noti come ci
sia una differenza con i campi mostrati nello schema di
- \figref{fig:ipc_mq_schema} che sono presi dalla definizione di
+ fig.~\ref{fig:ipc_mq_schema} che sono presi dalla definizione di
\file{linux/msg.h}, e fanno riferimento alla definizione della omonima
- struttura usata nel kernel.} In \figref{fig:ipc_msqid_ds} sono elencati i
+ struttura usata nel kernel.} In fig.~\ref{fig:ipc_msqid_ds} sono elencati i
campi significativi definiti in \file{sys/msg.h}, a cui si sono aggiunti gli
ultimi tre campi che sono previsti dalla implementazione originale di System
V, ma non dallo standard Unix98.
Quando si crea una nuova coda con \func{msgget} questa struttura viene
inizializzata, in particolare il campo \var{msg\_perm} viene inizializzato
-come illustrato in \secref{sec:ipc_sysv_access_control}, per quanto riguarda
+come illustrato in sez.~\ref{sec:ipc_sysv_access_control}, per quanto riguarda
gli altri campi invece:
\begin{itemize*}
\item il campo \var{msg\_qnum}, che esprime il numero di messaggi presenti
\item[\const{IPC\_RMID}] Rimuove la coda, cancellando tutti i dati, con
effetto immediato. Tutti i processi che cercheranno di accedere alla coda
riceveranno un errore di \errcode{EIDRM}, e tutti processi in attesa su
- funzioni di di lettura o di scrittura sulla coda saranno svegliati ricevendo
+ funzioni di lettura o di scrittura sulla coda saranno svegliati ricevendo
il medesimo errore. Questo comando può essere eseguito solo da un processo
con user-ID effettivo corrispondente al creatore o al proprietario della
coda, o all'amministratore.
messaggio ha lunghezza specificata da \param{msgsz} ed è passato attraverso il
l'argomento \param{msgp}. Quest'ultimo deve venire passato sempre come
puntatore ad una struttura \struct{msgbuf} analoga a quella riportata in
-\figref{fig:ipc_msbuf} che è quella che deve contenere effettivamente il
+fig.~\ref{fig:ipc_msbuf} che è quella che deve contenere effettivamente il
messaggio. La dimensione massima per il testo di un messaggio non può
comunque superare il limite \const{MSGMAX}.
-La struttura di \figref{fig:ipc_msbuf} è comunque solo un modello, tanto che
+La struttura di fig.~\ref{fig:ipc_msbuf} è comunque solo un modello, tanto che
la definizione contenuta in \file{sys/msg.h} usa esplicitamente per il secondo
campo il valore \code{mtext[1]}, che non è di nessuna utilità ai fini pratici.
La sola cosa che conta è che la struttura abbia come primo membro un campo
dimensione, e serve a contenere il testo del messaggio.
In generale pertanto per inviare un messaggio con \func{msgsnd} si usa
-ridefinire una struttura simile a quella di \figref{fig:ipc_msbuf}, adattando
+ridefinire una struttura simile a quella di fig.~\ref{fig:ipc_msbuf}, adattando
alle proprie esigenze il campo \var{mtype}, (o ridefinendo come si vuole il
corpo del messaggio, anche con più campi o con strutture più complesse) avendo
però la cura di mantenere nel primo campo un valore di tipo \ctyp{long} che ne
argomento è solo quella del messaggio, non quella di tutta la struttura, se
cioè \var{message} è una propria struttura che si passa alla funzione,
\param{msgsz} dovrà essere uguale a \code{sizeof(message)-sizeof(long)}, (se
-consideriamo il caso dell'esempio in \figref{fig:ipc_msbuf}, \param{msgsz}
+consideriamo il caso dell'esempio in fig.~\ref{fig:ipc_msbuf}, \param{msgsz}
dovrà essere pari a \const{LENGTH}).
\begin{figure}[!htb]
Per capire meglio il funzionamento della funzione riprendiamo in
considerazione la struttura della coda illustrata in
-\figref{fig:ipc_mq_schema}. Alla chiamata di \func{msgsnd} il nuovo messaggio
+fig.~\ref{fig:ipc_mq_schema}. Alla chiamata di \func{msgsnd} il nuovo messaggio
sarà aggiunto in fondo alla lista inserendo una nuova struttura \struct{msg},
il puntatore \var{msg\_last} di \struct{msqid\_ds} verrà aggiornato, come pure
il puntatore al messaggio successivo per quello che era il precedente ultimo
La funzione legge un messaggio dalla coda specificata, scrivendolo sulla
struttura puntata da \param{msgp}, che dovrà avere un formato analogo a quello
-di \figref{fig:ipc_msbuf}. Una volta estratto, il messaggio sarà rimosso dalla
-coda. L'argomento \param{msgsz} indica la lunghezza massima del testo del
-messaggio (equivalente al valore del parametro \const{LENGTH} nell'esempio di
-\figref{fig:ipc_msbuf}).
+di fig.~\ref{fig:ipc_msbuf}. Una volta estratto, il messaggio sarà rimosso
+dalla coda. L'argomento \param{msgsz} indica la lunghezza massima del testo
+del messaggio (equivalente al valore del parametro \const{LENGTH} nell'esempio
+di fig.~\ref{fig:ipc_msbuf}).
Se il testo del messaggio ha lunghezza inferiore a \param{msgsz} esso viene
rimosso dalla coda; in caso contrario, se \param{msgflg} è impostato a
L'argomento \param{msgtyp} permette di restringere la ricerca ad un
sottoinsieme dei messaggi presenti sulla coda; la ricerca infatti è fatta con
-una scansione della struttura mostrata in \figref{fig:ipc_mq_schema},
+una scansione della struttura mostrata in fig.~\ref{fig:ipc_mq_schema},
restituendo il primo messaggio incontrato che corrisponde ai criteri
specificati (che quindi, visto come i messaggi vengono sempre inseriti dalla
coda, è quello meno recente); in particolare:
\begin{itemize}
\item se \param{msgtyp} è 0 viene estratto il messaggio in cima alla coda, cioè
- quello fra i presenti che è stato inserito inserito per primo.
+ quello fra i presenti che è stato inserito per primo.
\item se \param{msgtyp} è positivo viene estratto il primo messaggio il cui
tipo (il valore del campo \var{mtype}) corrisponde al valore di
\param{msgtyp}.
utilizzava termina. Questo comporta che in caso di errori si può saturare il
sistema, e che devono comunque essere esplicitamente previste delle funzioni
di rimozione in caso di interruzioni o uscite dal programma (come vedremo in
-\figref{fig:ipc_mq_fortune_server}).
+fig.~\ref{fig:ipc_mq_fortune_server}).
L'altro problema è non facendo uso di file descriptor le tecniche di
-\textit{I/O multiplexing} descritte in \secref{sec:file_multiplexing} non
+\textit{I/O multiplexing} descritte in sez.~\ref{sec:file_multiplexing} non
possono essere utilizzate, e non si ha a disposizione niente di analogo alle
funzioni \func{select} e \func{poll}. Questo rende molto scomodo usare più di
una di queste strutture alla volta; ad esempio non si può scrivere un server
\label{fig:ipc_mq_fortune_server}
\end{figure}
-In \figref{fig:ipc_mq_fortune_server} si è riportato un estratto delle parti
+In fig.~\ref{fig:ipc_mq_fortune_server} si è riportato un estratto delle parti
principali del codice del nuovo server (il codice completo è nel file
\file{MQFortuneServer.c} nei sorgenti allegati). Il programma è basato su un
uso accorto della caratteristica di poter associate un ``tipo'' ai messaggi
\label{fig:ipc_mq_fortune_client}
\end{figure}
-In \figref{fig:ipc_mq_fortune_client} si è riportato un estratto il codice del
-programma client. Al solito il codice completo è con i sorgenti allegati, nel
-file \file{MQFortuneClient.c}. Come sempre si sono rimosse le parti relative
-alla gestione delle opzioni, ed in questo caso, anche la dichiarazione delle
-variabili, che, per la parte relative alle strutture usate per la
-comunicazione tramite le code, sono le stesse viste in
-\figref{fig:ipc_mq_fortune_server}.
+In fig.~\ref{fig:ipc_mq_fortune_client} si è riportato un estratto il codice
+del programma client. Al solito il codice completo è con i sorgenti allegati,
+nel file \file{MQFortuneClient.c}. Come sempre si sono rimosse le parti
+relative alla gestione delle opzioni, ed in questo caso, anche la
+dichiarazione delle variabili, che, per la parte relative alle strutture usate
+per la comunicazione tramite le code, sono le stesse viste in
+fig.~\ref{fig:ipc_mq_fortune_server}.
Il client in questo caso è molto semplice; la prima parte del programma
(\texttt{\small 4--9}) si occupa di accedere alla coda di messaggi, ed è
(pipe, fifo e code di messaggi) visti finora, e non consentono di scambiare
dati fra processi, ma servono piuttosto come meccanismi di sincronizzazione o
di protezione per le \textsl{sezioni critiche}\index{sezioni critiche} del
-codice (si ricordi quanto detto in \secref{sec:proc_race_cond}).
+codice (si ricordi quanto detto in sez.~\ref{sec:proc_race_cond}).
Un semaforo è uno speciale contatore, mantenuto nel kernel, che permette, a
seconda del suo valore, di consentire o meno la prosecuzione dell'esecuzione
La funzione è del tutto analoga a \func{msgget}, solo che in questo caso
restituisce l'identificatore di un insieme di semafori, in particolare è
identico l'uso degli argomenti \param{key} e \param{flag}, per cui non
-ripeteremo quanto detto al proposito in \secref{sec:ipc_sysv_mq}. L'argomento
+ripeteremo quanto detto al proposito in sez.~\ref{sec:ipc_sysv_mq}. L'argomento
\param{nsems} permette di specificare quanti semafori deve contenere l'insieme
quando se ne richieda la creazione, e deve essere nullo quando si effettua una
richiesta dell'identificatore di un insieme già esistente.
\end{figure}
A ciascun insieme di semafori è associata una struttura \struct{semid\_ds},
-riportata in \figref{fig:ipc_semid_ds}.\footnote{non si sono riportati i campi
- ad uso interno del kernel, che vedremo in \figref{fig:ipc_sem_schema}, che
- dipendono dall'implementazione.} Come nel caso delle code di messaggi quando
-si crea un nuovo insieme di semafori con \func{semget} questa struttura viene
-inizializzata, in particolare il campo \var{sem\_perm} viene inizializzato
-come illustrato in \secref{sec:ipc_sysv_access_control} (si ricordi che in
-questo caso il permesso di scrittura è in realtà permesso di alterare il
-semaforo), per quanto riguarda gli altri campi invece:
+riportata in fig.~\ref{fig:ipc_semid_ds}.\footnote{non si sono riportati i
+ campi ad uso interno del kernel, che vedremo in
+ fig.~\ref{fig:ipc_sem_schema}, che dipendono dall'implementazione.} Come nel
+caso delle code di messaggi quando si crea un nuovo insieme di semafori con
+\func{semget} questa struttura viene inizializzata, in particolare il campo
+\var{sem\_perm} viene inizializzato come illustrato in
+sez.~\ref{sec:ipc_sysv_access_control} (si ricordi che in questo caso il
+permesso di scrittura è in realtà permesso di alterare il semaforo), per
+quanto riguarda gli altri campi invece:
\begin{itemize*}
\item il campo \var{sem\_nsems}, che esprime il numero di semafori
nell'insieme, viene inizializzato al valore di \param{nsems}.
ormai è ridotta ai soli due primi membri, e gli altri vengono calcolati
dinamicamente. La si è utilizzata a scopo di esempio, perché indica tutti i
valori associati ad un semaforo, restituiti dalle funzioni di controllo, e
- citati dalle pagine di manuale.} è riportata in \figref{fig:ipc_sem}. Questa
-struttura, non è accessibile in user space, ma i valori in essa specificati
-possono essere letti in maniera indiretta, attraverso l'uso delle funzioni di
-controllo.
+ citati dalle pagine di manuale.} è riportata in fig.~\ref{fig:ipc_sem}.
+Questa struttura, non è accessibile in user space, ma i valori in essa
+specificati possono essere letti in maniera indiretta, attraverso l'uso delle
+funzioni di controllo.
\begin{figure}[!htb]
\footnotesize \centering
\label{fig:ipc_sem}
\end{figure}
-I dati mantenuti nella struttura, ed elencati in \figref{fig:ipc_sem},
+I dati mantenuti nella struttura, ed elencati in fig.~\ref{fig:ipc_sem},
indicano rispettivamente:
\begin{description*}
\item[\var{semval}] il valore numerico del semaforo.
Come per le code di messaggi anche per gli insiemi di semafori esistono una
serie di limiti, i cui valori sono associati ad altrettante costanti, che si
-sono riportate in \tabref{tab:ipc_sem_limits}. Alcuni di questi limiti sono al
-solito accessibili e modificabili attraverso \func{sysctl} o scrivendo
+sono riportate in tab.~\ref{tab:ipc_sem_limits}. Alcuni di questi limiti sono
+al solito accessibili e modificabili attraverso \func{sysctl} o scrivendo
direttamente nel file \file{/proc/sys/kernel/sem}.
La funzione che permette di effettuare le varie operazioni di controllo sui
generico, che conterrà un dato diverso a seconda dell'azione richiesta; per
unificare l'argomento esso deve essere passato come una \struct{semun}, la cui
definizione, con i possibili valori che può assumere, è riportata in
-\figref{fig:ipc_semun}.
+fig.~\ref{fig:ipc_semun}.
Come già accennato sia il comportamento della funzione che il numero di
parametri con cui deve essere invocata, dipendono dal valore dell'argomento
Il valore di ritorno della funzione in caso di successo dipende
dall'operazione richiesta; per tutte le operazioni che richiedono quattro
argomenti esso è sempre nullo, per le altre operazioni, elencate in
-\tabref{tab:ipc_semctl_returns} viene invece restituito il valore richiesto,
+tab.~\ref{tab:ipc_semctl_returns} viene invece restituito il valore richiesto,
corrispondente al campo della struttura \struct{sem} indicato nella seconda
colonna della tabella.
Il contenuto di ciascuna operazione deve essere specificato attraverso una
opportuna struttura \struct{sembuf} (la cui definizione è riportata in
-\figref{fig:ipc_sembuf}) che il programma chiamante deve avere cura di
+fig.~\ref{fig:ipc_sembuf}) che il programma chiamante deve avere cura di
allocare in un opportuno vettore. La struttura permette di indicare il
semaforo su cui operare, il tipo di operazione, ed un flag di controllo.
Il campo \var{sem\_num} serve per indicare a quale semaforo dell'insieme fa
Tutto questo però ha un problema di fondo. Per capire di cosa si tratta
occorre fare riferimento all'implementazione usata in Linux, che è riportata
-in maniera semplificata nello schema di \figref{fig:ipc_sem_schema}. Si è
+in maniera semplificata nello schema di fig.~\ref{fig:ipc_sem_schema}. Si è
presa come riferimento l'architettura usata fino al kernel 2.2.x che è più
semplice (ed illustrata in dettaglio in \cite{tlk}); nel kernel 2.4.x la
struttura del \textit{SysV IPC} è stata modificata, ma le definizioni relative
Come esempio di uso dell'interfaccia dei semafori vediamo come implementare
con essa dei semplici \textit{mutex} (cioè semafori binari), tutto il codice
in questione, contenuto nel file \file{Mutex.c} allegato ai sorgenti, è
-riportato in \figref{fig:ipc_mutex_create}. Utilizzeremo l'interfaccia per
+riportato in fig.~\ref{fig:ipc_mutex_create}. Utilizzeremo l'interfaccia per
creare un insieme contenente un singolo semaforo, per il quale poi useremo un
valore unitario per segnalare la disponibilità della risorsa, ed un valore
nullo per segnalarne l'indisponibilità.
considerata libera). Infine si tenga presente che usare \func{MutexRead} per
controllare il valore dei mutex prima di proseguire in una operazione di
sblocco non servirebbe comunque, dato che l'operazione non sarebbe atomica.
-Vedremo in \secref{sec:ipc_lock_file} come sia possibile ottenere
+Vedremo in sez.~\ref{sec:ipc_lock_file} come sia possibile ottenere
un'interfaccia analoga a quella appena illustrata, senza incorrere in questi
problemi, usando il file locking\index{file!locking}.
La funzione, come \func{semget}, è del tutto analoga a \func{msgget}, ed
identico è l'uso degli argomenti \param{key} e \param{flag} per cui non
-ripeteremo quanto detto al proposito in \secref{sec:ipc_sysv_mq}. L'argomento
+ripeteremo quanto detto al proposito in sez.~\ref{sec:ipc_sysv_mq}. L'argomento
\param{size} specifica invece la dimensione, in byte, del segmento, che viene
comunque arrotondata al multiplo superiore di \const{PAGE\_SIZE}.
\end{figure}
A ciascun segmento di memoria condivisa è associata una struttura
-\struct{shmid\_ds}, riportata in \figref{fig:ipc_shmid_ds}. Come nel caso
+\struct{shmid\_ds}, riportata in fig.~\ref{fig:ipc_shmid_ds}. Come nel caso
delle code di messaggi quando si crea un nuovo segmento di memoria condivisa
con \func{shmget} questa struttura viene inizializzata, in particolare il
campo \var{shm\_perm} viene inizializzato come illustrato in
-\secref{sec:ipc_sysv_access_control}, e valgono le considerazioni ivi fatte
+sez.~\ref{sec:ipc_sysv_access_control}, e valgono le considerazioni ivi fatte
relativamente ai permessi di accesso; per quanto riguarda gli altri campi
invece:
\begin{itemize}
\func{sysctl} o scrivendo direttamente nei rispettivi file di
\file{/proc/sys/kernel/}.
-In \tabref{tab:ipc_shm_limits} si sono riportate le
+In tab.~\ref{tab:ipc_shm_limits} si sono riportate le
costanti simboliche associate a ciascuno di essi, il loro significato, i
valori preimpostati, e, quando presente, il file in \file{/proc/sys/kernel/}
che permettono di cambiarne il valore.
\textit{memory locking}\index{memory locking}\footnote{impedisce cioè che la
memoria usata per il segmento venga salvata su disco dal meccanismo della
memoria virtuale\index{memoria virtuale}; si ricordi quanto trattato in
- \secref{sec:proc_mem_lock}.} sul segmento di memoria condivisa. Solo
+ sez.~\ref{sec:proc_mem_lock}.} sul segmento di memoria condivisa. Solo
l'amministratore può utilizzare questo comando.
\item[\const{SHM\_UNLOCK}] Disabilita il \textit{memory locking} sul segmento
di memoria condivisa. Solo l'amministratore può utilizzare questo comando.
La funzione inserisce un segmento di memoria condivisa all'interno dello
spazio di indirizzi del processo, in modo che questo possa accedervi
direttamente, la situazione dopo l'esecuzione di \func{shmat} è illustrata in
-\figref{fig:ipc_shmem_layout} (per la comprensione del resto dello schema si
-ricordi quanto illustrato al proposito in \secref{sec:proc_mem_layout}). In
+fig.~\ref{fig:ipc_shmem_layout} (per la comprensione del resto dello schema si
+ricordi quanto illustrato al proposito in sez.~\ref{sec:proc_mem_layout}). In
particolare l'indirizzo finale del segmento dati (quello impostato da
-\func{brk}, vedi \secref{sec:proc_mem_sbrk}) non viene influenzato. Si tenga
+\func{brk}, vedi sez.~\ref{sec:proc_mem_sbrk}) non viene influenzato. Si tenga
presente infine che la funzione ha successo anche se il segmento è stato
marcato per la cancellazione.
aumentato di uno.
\end{itemize*}
-Come accennato in \secref{sec:proc_fork} un segmento di memoria condivisa
+Come accennato in sez.~\ref{sec:proc_fork} un segmento di memoria condivisa
agganciato ad un processo viene ereditato da un figlio attraverso una
\func{fork}, dato che quest'ultimo riceve una copia dello spazio degli
indirizzi del padre. Invece, dato che attraverso una \func{exec} viene
Come esempio di uso di queste funzioni vediamo come implementare una serie di
funzioni di libreria che ne semplifichino l'uso, automatizzando le operazioni
più comuni; il codice, contenuto nel file \file{SharedMem.c}, è riportato in
-\figref{fig:ipc_sysv_shm_func}.
+fig.~\ref{fig:ipc_sysv_shm_func}.
La prima funzione (\texttt{\small 3--16}) è \func{ShmCreate} che, data una
chiave, crea il segmento di memoria condivisa restituendo il puntatore allo
sequenziale, altri meccanismi come le pipe, le fifo o i socket, che non
necessitano di sincronizzazione esplicita, sono da preferire. Essa diventa
l'unico meccanismo possibile quando la comunicazione non è
-sequenziale\footnote{come accennato in \secref{sec:ipc_sysv_mq} per la
+sequenziale\footnote{come accennato in sez.~\ref{sec:ipc_sysv_mq} per la
comunicazione non sequenziale si possono usare le code di messaggi,
attraverso l'uso del campo \var{mtype}, ma solo se quest'ultima può essere
effettuata in forma di messaggio.} o quando non può avvenire secondo una
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
+In fig.~\ref{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
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
+ nonostante le indicazioni illustrate in sez.~\ref{sec:sess_daemon}, per il
particolare scopo del programma, che necessita comunque di restare
all'interno di una directory.} Infine (\texttt{\small 27--29}) si installano
i gestori per i vari segnali di terminazione che, avendo a che fare con un
accedere alla memoria condivisa, che, per come abbiamo lo abbiamo definito,
sarà vista nella forma data da \struct{DirProp}. Infine (\texttt{\small
36--39}) 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.
+di interfaccia già descritte in sez.~\ref{sec:ipc_sysv_sem}, anche un mutex,
+che utilizzeremo per regolare l'accesso alla memoria condivisa.
\begin{figure}[!htb]
\footnotesize \centering
Si noti come per il calcolo dei valori da mantenere nella memoria condivisa si
sia usata ancora una volta la funzione \func{DirScan}, già utilizzata (e
-descritta in dettaglio) in \secref{sec:file_dir_read}, che ci permette di
+descritta in dettaglio) in sez.~\ref{sec:file_dir_read}, che ci permette di
effettuare la scansione delle voci della directory, chiamando per ciascuna di
esse la funzione \func{ComputeValues}, che esegue tutti i calcoli necessari.
-Il codice di quest'ultima è riportato in \figref{fig:ipc_dirmonitor_sub}. Come
-si vede la funzione (\texttt{\small 2--16}) è molto semplice e si limita a
-chiamare (\texttt{\small 5}) la funzione \func{stat} sul file indicato da
+Il codice di quest'ultima è riportato in fig.~\ref{fig:ipc_dirmonitor_sub}.
+Come si vede la funzione (\texttt{\small 2--16}) è molto semplice e si limita
+a chiamare (\texttt{\small 5}) la funzione \func{stat} sul file indicato da
ciascuna voce, per ottenerne i dati, che poi utilizza per incrementare i vari
contatori nella memoria condivisa, cui accede grazie alla variabile globale
\var{shmptr}.
condivisa usando \var{shmptr} per riempire i campi della struttura
\struct{DirProp}; così prima (\texttt{\small 6--7}) si sommano le dimensioni
dei file ed il loro numero, poi, utilizzando le macro di
-\tabref{tab:file_type_macro}, si contano (\texttt{\small 8--14}) quanti ce ne
-sono per ciascun tipo.
-
-In \figref{fig:ipc_dirmonitor_sub} è riportato anche il codice (\texttt{\small
- 17--23}) del gestore dei segnali di terminazione, usato per chiudere il
-programma. Esso, oltre a provocare l'uscita del programma, si incarica anche
-di cancellare tutti gli oggetti di intercomunicazione non più necessari. Per
-questo anzitutto (\texttt{\small 19}) acquisisce il mutex con
+tab.~\ref{tab:file_type_macro}, si contano (\texttt{\small 8--14}) quanti ce
+ne sono per ciascun tipo.
+
+In fig.~\ref{fig:ipc_dirmonitor_sub} è riportato anche il codice
+(\texttt{\small 17--23}) del gestore dei segnali di terminazione, usato per
+chiudere il programma. Esso, oltre a provocare l'uscita del programma, si
+incarica anche di cancellare tutti gli oggetti di intercomunicazione non più
+necessari. Per questo anzitutto (\texttt{\small 19}) acquisisce il mutex con
\func{MutexLock}, per evitare di operare mentre un client sta ancora leggendo
i dati, dopo di che (\texttt{\small 20}) distacca e rimuove il segmento di
memoria condivisa usando \func{ShmRemove}. Infine (\texttt{\small 21})
\end{figure}
Il codice del client usato per leggere le informazioni mantenute nella memoria
-condivisa è riportato in \figref{fig:ipc_dirmonitor_client}. Al solito si è
+condivisa è riportato in fig.~\ref{fig:ipc_dirmonitor_client}. Al solito si è
omessa la sezione di gestione delle opzioni e la funzione che stampa a video
le istruzioni; il codice completo è nei sorgenti allegati, nel file
\file{ReadMonitor.c}.
%% Per capire meglio il funzionamento delle funzioni facciamo ancora una volta
%% riferimento alle strutture con cui il kernel implementa i segmenti di memoria
%% condivisa; uno schema semplificato della struttura è illustrato in
-%% \figref{fig:ipc_shm_struct}.
+%% fig.~\ref{fig:ipc_shm_struct}.
%% \begin{figure}[htb]
%% \centering
\section{Tecniche alternative}
\label{sec:ipc_alternatives}
-Come abbiamo detto in \secref{sec:ipc_sysv_generic}, e ripreso nella
+Come abbiamo detto in sez.~\ref{sec:ipc_sysv_generic}, e ripreso nella
descrizione dei singoli oggetti che ne fan parte, il \textit{SysV IPC}
presenta numerosi problemi; in \cite{APUE}\footnote{in particolare nel
capitolo 14.} Stevens ne effettua una accurata analisi (alcuni dei concetti
Le code di messaggi sono probabilmente il meno usato degli oggetti del
\textit{SysV IPC}; esse infatti nacquero principalmente come meccanismo di
comunicazione bidirezionale quando ancora le pipe erano unidirezionali; con la
-disponibilità di \func{socketpair} (vedi \secref{sec:ipc_socketpair}) o
+disponibilità di \func{socketpair} (vedi sez.~\ref{sec:ipc_socketpair}) o
utilizzando una coppia di pipe, si può ottenere questo risultato senza
incorrere nelle complicazioni introdotte dal \textit{SysV IPC}.
\label{sec:ipc_file_lock}
\index{file!di lock|(}
-Come illustrato in \secref{sec:ipc_sysv_sem} i semafori del \textit{SysV IPC}
+Come illustrato in sez.~\ref{sec:ipc_sysv_sem} i semafori del \textit{SysV IPC}
presentano una interfaccia inutilmente complessa e con alcuni difetti
strutturali, per questo quando si ha una semplice esigenza di sincronizzazione
per la quale basterebbe un semaforo binario (quello che abbiamo definito come
dei \textsl{file di lock} (per i quali esiste anche una opportuna directory,
\file{/var/lock}, nel filesystem standard). Per questo si usa la
caratteristica della funzione \func{open} (illustrata in
-\secref{sec:file_open}) che prevede\footnote{questo è quanto dettato dallo
+sez.~\ref{sec:file_open}) che prevede\footnote{questo è quanto dettato dallo
standard POSIX.1, ciò non toglie che in alcune implementazioni questa
tecnica possa non funzionare; in particolare per Linux, nel caso di NFS, si
è comunque soggetti alla possibilità di una race
ad \func{unlink}.
Un esempio dell'uso di questa funzione è mostrato dalle funzioni
-\func{LockFile} ed \func{UnlockFile} riportate in \figref{fig:ipc_file_lock}
+\func{LockFile} ed \func{UnlockFile} riportate in fig.~\ref{fig:ipc_file_lock}
(sono contenute in \file{LockFile.c}, un'altro dei sorgenti allegati alla
guida) che permettono rispettivamente di creare e rimuovere un \textsl{file di
lock}. Come si può notare entrambe le funzioni sono elementari; la prima
\end{figure}
Uno dei limiti di questa tecnica è che, come abbiamo già accennato in
-\secref{sec:file_open}, questo comportamento di \func{open} può non funzionare
-(la funzione viene eseguita, ma non è garantita l'atomicità dell'operazione)
-se il filesystem su cui si va ad operare è su NFS; in tal caso si può adottare
-una tecnica alternativa che prevede l'uso della \func{link} per creare come
-\textsl{file di lock} un hard link ad un file esistente; se il link esiste già
-e la funzione fallisce, significa che la risorsa è bloccata e potrà essere
-sbloccata solo con un \func{unlink}, altrimenti il link è creato ed il lock
-acquisito; il controllo e l'eventuale acquisizione sono atomici; la soluzione
-funziona anche su NFS, ma ha un'altro difetto è che è quello di poterla usare
-solo se si opera all'interno di uno stesso filesystem.
+sez.~\ref{sec:file_open}, questo comportamento di \func{open} può non
+funzionare (la funzione viene eseguita, ma non è garantita l'atomicità
+dell'operazione) se il filesystem su cui si va ad operare è su NFS; in tal
+caso si può adottare una tecnica alternativa che prevede l'uso della
+\func{link} per creare come \textsl{file di lock} un hard link ad un file
+esistente; se il link esiste già e la funzione fallisce, significa che la
+risorsa è bloccata e potrà essere sbloccata solo con un \func{unlink},
+altrimenti il link è creato ed il lock acquisito; il controllo e l'eventuale
+acquisizione sono atomici; la soluzione funziona anche su NFS, ma ha un'altro
+difetto è che è quello di poterla usare solo se si opera all'interno di uno
+stesso filesystem.
Un generale comunque l'uso di un \textsl{file di lock} presenta parecchi
problemi, che non lo rendono una alternativa praticabile per la
Dato che i file di lock\index{file!di lock} presentano gli inconvenienti
illustrati in precedenza, la tecnica alternativa di sincronizzazione più
comune è quella di fare ricorso al \textit{file locking}\index{file!locking}
-(trattato in \secref{sec:file_locking}) usando \func{fcntl} su un file creato
+(trattato in sez.~\ref{sec:file_locking}) usando \func{fcntl} su un file creato
per l'occasione per ottenere un write lock. In questo modo potremo usare il
lock come un \textit{mutex}: per bloccare la risorsa basterà acquisire il
lock, per sbloccarla basterà rilasciare il lock. Una richiesta fatta con un
\end{figure}
Il codice delle varie funzioni usate per implementare un mutex utilizzando il
-file locking\index{file!locking} è riportato in \figref{fig:ipc_flock_mutex};
+file locking\index{file!locking} è riportato in fig.~\ref{fig:ipc_flock_mutex};
si è mantenuta volutamente una struttura analoga alle precedenti funzioni che
usano i semafori, anche se le due interfacce non possono essere completamente
equivalenti, specie per quanto riguarda la rimozione del mutex.
caso si inizializza (\texttt{\small 28--31}) la struttura \var{lock} per il
rilascio del lock, che viene effettuato (\texttt{\small 33}) con la opportuna
chiamata a \func{fcntl}. Avendo usato il file locking in semantica POSIX (si
-riveda quanto detto \secref{sec:file_posix_lock}) solo il processo che ha
+riveda quanto detto sez.~\ref{sec:file_posix_lock}) solo il processo che ha
precedentemente eseguito il lock può sbloccare il mutex.
La quinta funzione (\texttt{\small 36--39}) è \func{RemoveMutex} e serve a
Basandosi sulla semantica dei file lock POSIX valgono tutte le considerazioni
relative al comportamento di questi ultimi fatte in
-\secref{sec:file_posix_lock}; questo significa ad esempio che, al contrario di
-quanto avveniva con l'interfaccia basata sui semafori, chiamate multiple a
+sez.~\ref{sec:file_posix_lock}; questo significa ad esempio che, al contrario
+di quanto avveniva con l'interfaccia basata sui semafori, chiamate multiple a
\func{UnlockMutex} o \func{LockMutex} non si cumulano e non danno perciò
nessun inconveniente.
evitare l'uso di una memoria condivisa facendo ricorso al cosiddetto
\textit{memory mapping} anonimo.
-In \secref{sec:file_memory_map} abbiamo visto come sia possibile mappare il
+In sez.~\ref{sec:file_memory_map} abbiamo visto come sia possibile mappare il
contenuto di un file nella memoria di un processo, e che, quando viene usato
il flag \const{MAP\_SHARED}, le modifiche effettuate al contenuto del file
vengono viste da tutti i processi che lo hanno mappato. Utilizzare questa
restano in memoria e possono essere riletti secondo le stesse modalità usate
nel \textit{memory mapping} anonimo.} Vedremo come utilizzare questa tecnica
più avanti, quando realizzeremo una nuova versione del monitor visto in
-\secref{sec:ipc_sysv_shm} che possa restituisca i risultati via rete.
+sez.~\ref{sec:ipc_sysv_shm} che possa restituisca i risultati via rete.
\label{sec:ipc_posix}
Per superare i numerosi problemi del \textit{SysV IPC}, evidenziati per i suoi
-aspetti generali in coda a \secref{sec:ipc_sysv_generic} e per i singoli
+aspetti generali in coda a sez.~\ref{sec:ipc_sysv_generic} e per i singoli
oggetti nei paragrafi successivi, lo standard POSIX.1b ha introdotto dei nuovi
meccanismi di comunicazione, che vanno sotto il nome di POSIX IPC, definendo
una interfaccia completamente nuova, che tratteremo in questa sezione.
quanto riguarda la memoria condivisa, che per quanto riguarda le code di
messaggi, tutto viene creato usando come radici delle opportune directory
(rispettivamente \file{/dev/shm} e \file{/dev/mqueue}, per i dettagli si
-faccia riferimento a \secref{sec:ipc_posix_shm} e \secref{sec:ipc_posix_mq})
-ed i nomi specificati nelle relative funzioni sono considerati come un
-pathname assoluto (comprendente eventuali sottodirectory) rispetto a queste
-radici.
+faccia riferimento a sez.~\ref{sec:ipc_posix_shm} e
+sez.~\ref{sec:ipc_posix_mq}) ed i nomi specificati nelle relative funzioni
+sono considerati come un pathname assoluto (comprendente eventuali
+sottodirectory) rispetto a queste radici.
Il vantaggio degli oggetti di IPC POSIX è comunque che essi vengono inseriti
nell'albero dei file, e possono essere maneggiati con le usuali funzioni e
In particolare i permessi associati agli oggetti di IPC POSIX sono identici ai
permessi dei file, e il controllo di accesso segue esattamente la stessa
-semantica (quella illustrata in \secref{sec:file_access_control}), invece di
+semantica (quella illustrata in sez.~\ref{sec:file_access_control}), invece di
quella particolare (si ricordi quanto visto in
-\secref{sec:ipc_sysv_access_control}) usata per gli oggetti del SysV IPC. Per
+sez.~\ref{sec:ipc_sysv_access_control}) usata per gli oggetti del SysV IPC. Per
quanto riguarda l'attribuzione dell'utente e del gruppo proprietari
dell'oggetto alla creazione di quest'ultimo essa viene effettuata secondo la
semantica SysV (essi corrispondono cioè a userid e groupid effettivi del
La funzione è del tutto analoga ad \func{open} ed analoghi sono i valori che
possono essere specificati per \param{oflag}, che deve essere specificato come
maschera binaria; i valori possibili per i vari bit sono quelli visti in
-\tabref{tab:file_open_flags} dei quali però \func{mq\_open} riconosce solo i
+tab.~\ref{tab:file_open_flags} dei quali però \func{mq\_open} riconosce solo i
seguenti:
\begin{basedescript}{\desclabelwidth{2cm}\desclabelstyle{\nextlinelabel}}
\item[\const{O\_RDONLY}] Apre la coda solo per la ricezione di messaggi. Il
essere specificati anche gli attributi specifici della coda tramite
l'argomento \param{attr}; quest'ultimo è un puntatore ad una apposita
struttura \struct{mq\_attr}, la cui definizione è riportata in
-\figref{fig:ipc_mq_attr}.
+fig.~\ref{fig:ipc_mq_attr}.
\begin{figure}[!htb]
\footnotesize \centering
Il comportamento di \func{mq\_notify} dipende dal valore dell'argomento
\param{notification}, che è un puntatore ad una apposita struttura
-\struct{sigevent}, (definita in \figref{fig:file_sigevent}) introdotta dallo
+\struct{sigevent}, (definita in fig.~\ref{fig:file_sigevent}) introdotta dallo
standard POSIX.1b per gestire la notifica di eventi; per altri dettagli si può
-vedere quanto detto in \secref{sec:file_asyncronous_io} a proposito dell'uso
+vedere quanto detto in sez.~\ref{sec:file_asyncronous_io} a proposito dell'uso
della stessa struttura per l'invio dei segnali usati per l'I/O asincrono.
Attraverso questa struttura si possono impostare le modalità con cui viene
implementato.} ed il campo \var{sigev\_signo} deve indicare il valore del
segnale che sarà inviato al processo. Inoltre il campo \var{sigev\_value} è il
puntatore ad una struttura \struct{sigval\_t} (definita in
-\figref{fig:sig_sigval}) che permette di restituire al gestore del segnale un
+fig.~\ref{fig:sig_sigval}) che permette di restituire al gestore del segnale un
valore numerico o un indirizzo,\footnote{per il suo uso si riveda la
- trattazione fatta in \secref{sec:sig_real_time} a proposito dei segnali
+ trattazione fatta in sez.~\ref{sec:sig_real_time} a proposito dei segnali
real-time.} posto che questo sia installato nella forma estesa vista in
-\secref{sec:sig_sigaction}.
+sez.~\ref{sec:sig_sigaction}.
La funzione registra il processo chiamante per la notifica se
\param{notification} punta ad una struttura \struct{sigevent} opportunamente
L'invio del segnale di notifica avvalora alcuni campi di informazione
restituiti al gestore attraverso la struttura \struct{siginfo\_t} (definita in
-\figref{fig:sig_siginfo_t}). In particolare \var{si\_pid} viene impostato al
+fig.~\ref{fig:sig_siginfo_t}). In particolare \var{si\_pid} viene impostato al
valore del \acr{pid} del processo che ha emesso il segnale, \var{si\_uid}
all'userid effettivo, \var{si\_code} a \const{SI\_MESGQ}, e \var{si\_errno} a
0. Questo ci dice che, se si effettua la ricezione dei messaggi usando
esclusivamente il meccanismo di notifica, è possibile ottenere le informazioni
sul processo che ha inserito un messaggio usando un gestore per il segnale in
forma estesa\footnote{di nuovo si faccia riferimento a quanto detto al
- proposito in \secref{sec:sig_sigaction} e \secref{sec:sig_real_time}.}
+ proposito in sez.~\ref{sec:sig_sigaction} e sez.~\ref{sec:sig_real_time}.}
sincronizzazione fra processi diversi.} Esiste però anche una libreria
realizzata da Konstantin Knizhnik, che reimplementa l'interfaccia POSIX usando
i semafori di SysV IPC, e che non vale comunque la pena di usare visto che i
-problemi sottolineati in \secref{sec:ipc_sysv_sem} rimangono, anche se
+problemi sottolineati in sez.~\ref{sec:ipc_sysv_sem} rimangono, anche se
mascherati.
In realtà a partire dal kernel 2.5.7 è stato introdotto un meccanismo di
\end{prototype}
La funzione apre un segmento di memoria condivisa identificato dal nome
-\param{name}. Come già spiegato in \secref{sec:ipc_posix_generic} questo nome
+\param{name}. Come già spiegato in sez.~\ref{sec:ipc_posix_generic} questo nome
può essere specificato in forma standard solo facendolo iniziare per \file{/}
e senza ulteriori \file{/}, Linux supporta comunque nomi generici, che
verranno intepretati prendendo come radice \file{/dev/shm}.\footnote{occorre
possono essere specificati per \param{oflag}, che deve essere specificato come
maschera binaria comprendente almeno uno dei due valori \const{O\_RDONLY} e
\const{O\_RDWR}; i valori possibili per i vari bit sono quelli visti in
-\tabref{tab:file_open_flags} dei quali però \func{shm\_open} riconosce solo i
-seguenti:
+tab.~\ref{tab:file_open_flags} dei quali però \func{shm\_open} riconosce solo
+i seguenti:
\begin{basedescript}{\desclabelwidth{2.0cm}\desclabelstyle{\nextlinelabel}}
\item[\const{O\_RDONLY}] Apre il file descriptor associato al segmento di
memoria condivisa per l'accesso in sola lettura.
segmento di memoria condiviso con le stesse modalità di
\func{open}\footnote{in realtà, come accennato, \func{shm\_open} è un semplice
wrapper per \func{open}, usare direttamente quest'ultima avrebbe lo stesso
- effetto.} viste in \secref{sec:file_open}; in particolare viene impostato
+ effetto.} viste in sez.~\ref{sec:file_open}; in particolare viene impostato
il flag \const{FD\_CLOEXEC}. Chiamate effettuate da diversi processi usando
lo stesso nome, restituiranno file descriptor associati allo stesso segmento
(così come, nel caso di file di dati, essi sono associati allo stesso inode).
\const{O\_CREAT}; in tal caso il segmento avrà (così come i nuovi file)
lunghezza nulla. Dato che un segmento di lunghezza nulla è di scarsa utilità,
per impostarne la dimensione si deve usare \func{ftruncate} (vedi
-\secref{sec:file_file_size}), prima di mapparlo in memoria con \func{mmap}. Si
-tenga presente che una volta chiamata \func{mmap} si può chiudere il file
+sez.~\ref{sec:file_file_size}), prima di mapparlo in memoria con \func{mmap}.
+Si tenga presente che una volta chiamata \func{mmap} si può chiudere il file
descriptor (con \func{close}), senza che la mappatura ne risenta.
Come esempio per l'uso di queste funzioni vediamo come è possibile riscrivere
una interfaccia semplificata analoga a quella vista in
-\secref{fig:ipc_sysv_shm_func} per la memoria condivisa in stile SysV. Il
-codice, riportato in \figref{fig:ipc_posix_shmmem}, è sempre contenuto nel
+fig.~\ref{fig:ipc_sysv_shm_func} per la memoria condivisa in stile SysV. Il
+codice, riportato in fig.~\ref{fig:ipc_posix_shmmem}, è sempre contenuto nel
file \file{SharedMem.c} dei sorgenti allegati.
La prima funzione (\texttt{\small 1--24}) è \func{CreateShm} che, dato un nome
In questa appendice prenderemo in esame i vari protocolli disponibili a
livello di rete.\footnote{per la spiegazione della suddivisione in livelli dei
protocolli di rete, si faccia riferimento a quanto illustrato in
- \secref{sec:net_protocols}.} Per ciascuno di essi forniremo una descrizione
+ sez.~\ref{sec:net_protocols}.} Per ciascuno di essi forniremo una descrizione
generica delle principlai caratteristiche, del formato di dati usato e quanto
possa essere necessario per capirne meglio il funzionamento dal punto di vista
della programmazione.
Per venire incontro alle diverse esigenze gli indirizzi di rete sono stati
originariamente organizzati in \textit{classi}, (rappresentate in
-\tabref{tab:IP_ipv4class}), per consentire dispiegamenti di reti di dimensioni
-diverse.
+tab.~\ref{tab:IP_ipv4class}), per consentire dispiegamenti di reti di
+dimensioni diverse.
\begin{table}[htb]
è destinata al (non molto usato) \textit{multicast} mentre la classe E è
riservata per usi sperimentali e non viene impiegata.
-Come si può notare però la suddivisione riportata in \tabref{tab:IP_ipv4class}
-è largamente inefficiente in quanto se ad un utente necessita anche solo un
-indirizzo in più dei 256 disponibili con una classe A occorre passare a una
-classe B, con un conseguente spreco di numeri.
+Come si può notare però la suddivisione riportata in
+tab.~\ref{tab:IP_ipv4class} è largamente inefficiente in quanto se ad un
+utente necessita anche solo un indirizzo in più dei 256 disponibili con una
+classe A occorre passare a una classe B, con un conseguente spreco di numeri.
Inoltre, in particolare per le reti di classe C, la presenza di tanti
indirizzi di rete diversi comporta una crescita enorme delle tabelle di
Per questo nel 1992 è stato introdotto un indirizzamento senza classi (il
CIDR, \textit{Classless Inter-Domain Routing}) in cui il limite fra i bit
destinati a indicare il numero di rete e quello destinati a indicare l'host
-finale può essere piazzato in qualunque punto (vedi \tabref{tab:IP_ipv4cidr}),
-permettendo di accorpare più classi A su un'unica rete o suddividere una
-classe B e diminuendo al contempo il numero di indirizzi di rete da inserire
-nelle tabelle di instradamento dei router.
+finale può essere piazzato in qualunque punto (vedi
+tab.~\ref{tab:IP_ipv4cidr}), permettendo di accorpare più classi A su un'unica
+rete o suddividere una classe B e diminuendo al contempo il numero di
+indirizzi di rete da inserire nelle tabelle di instradamento dei router.
\subsection{Principali caratteristiche di IPv6}
\label{sec:IP_ipv6over}
-Per rispondere alle esigenze descritte in \secref{sec:IP_whyipv6} IPv6 nasce
+Per rispondere alle esigenze descritte in sez.~\ref{sec:IP_whyipv6} IPv6 nasce
come evoluzione di IPv4, mantendone inalterate le funzioni che si sono
dimostrate valide, eliminando quelle inutili e aggiungendone poche altre
ponendo al contempo una grande attenzione a mantenere il protocollo il più
Per capire le caratteristiche di IPv6 partiamo dall'intestazione usata dal
protocollo per gestire la trasmissione dei pacchetti; in
-\figref{fig:IP_ipv6head} è riportato il formato dell'intestazione di IPv6 da
-confrontare con quella di IPv4 in \figref{fig:IP_ipv4_head}. La spiegazione del
-significato dei vari campi delle due intestazioni è riportato rispettivamente
-in \tabref{tab:IP_ipv6field} e \tabref{tab:IP_ipv4field})
+fig.~\ref{fig:IP_ipv6head} è riportato il formato dell'intestazione di IPv6 da
+confrontare con quella di IPv4 in fig.~\ref{fig:IP_ipv4_head}. La spiegazione
+del significato dei vari campi delle due intestazioni è riportato
+rispettivamente in tab.~\ref{tab:IP_ipv6field} e tab.~\ref{tab:IP_ipv4field})
% \begin{table}[htb]
% \footnotesize
\textit{version} & 4 bit &
\textsl{versione}, nel caso specifico vale sempre 6\\
\textit{priority} & 4 bit &
- \textsl{priorità}, vedi Sez.~\ref{sec:prio} \\
+ \textsl{priorità}, vedi sez.~\ref{sec:prio} \\
\textit{flow label} & 24 bit &
- \textsl{etichetta di flusso}, vedi Sez.~\ref{sec:IP_ipv6_flow}\\
+ \textsl{etichetta di flusso}, vedi sez.~\ref{sec:IP_ipv6_flow}\\
\textit{payload length} & 16 bit &
\textsl{lunghezza del carico}, cioè del corpo dei dati che segue
l'intestazione, in byte. \\
\end{center}
\end{table}
-Abbiamo già anticipato in \secref{sec:IP_ipv6over} uno dei criteri principali
+Abbiamo già anticipato in sez.~\ref{sec:IP_ipv6over} uno dei criteri principali
nella progettazione di IPv6 è stato quello di ridurre al minimo il tempo di
processamento dei pacchetti da parte dei router, un confronto con
-l'intestazione di IPv4 (vedi \figref{fig:IP_ipv4_head}) mostra le seguenti
+l'intestazione di IPv4 (vedi fig.~\ref{fig:IP_ipv4_head}) mostra le seguenti
differenze:
\begin{itemize}
\item è stato eliminato il campo \textit{header length} in quanto le opzioni
sono state tolte dall'intestazione che ha così dimensione fissa; ci possono
essere più intestazioni opzionali (\textsl{intestazioni di estensione}, vedi
- \secref{sec:IP_ipv6_extens}), ciascuna delle quali avrà un suo campo di
+ sez.~\ref{sec:IP_ipv6_extens}), ciascuna delle quali avrà un suo campo di
lunghezza all'interno.
\item l'intestazione e gli indirizzi sono allineati a 64 bit, questo rende più
veloce il processo da parte di computer con processori a 64 bit.
\item è stato introdotto un nuovo campo \textit{flow label}, che viene usato,
insieme al campo \textit{priority} (che recupera i bit di precedenza del
campo \textit{type of service}) per implementare la gestione di una
- ``\textsl{qualità di servizio}'' (vedi \secref{sec:IP_ipv6_qos}) che
+ ``\textsl{qualità di servizio}'' (vedi sez.~\ref{sec:IP_ipv6_qos}) che
permette di identificare i pacchetti appartenenti a un ``\textsl{flusso}''
di dati per i quali si può provvedere un trattamento speciale.
\end{itemize}
indica la posizione del frammento rispetto al pacchetto originale\\
\textit{time to live} & 16 & \textsl{tempo di vita},
ha lo stesso significato di
- \textit{hop limit}, vedi Tab.~\ref{tab:IP_ipv6field}\\
+ \textit{hop limit}, vedi tab.~\ref{tab:IP_ipv6field}\\
\textit{protocol} & 8 & \textsl{protocollo}
identifica il tipo di pacchetto che segue
l'intestazione di IPv4\\
\begin{itemize}
\item il broadcasting non è previsto in IPv6, le applicazioni che lo usano
dovono essere reimplementate usando il multicasting (vedi
- \secref{sec:IP_ipv6_multicast}), che da opzionale diventa obbligatorio.
+ sez.~\ref{sec:IP_ipv6_multicast}), che da opzionale diventa obbligatorio.
\item è stato introdotto un nuovo tipo di indirizzi, gli \textit{anycast}.
\item i router non possono più frammentare i pacchetti lungo il cammino, la
frammentazione di pacchetti troppo grandi potrà essere gestita solo ai
capi della comunicazione (usando un'apposita estensione vedi
- \secref{sec:IP_ipv6_extens}).
+ sez.~\ref{sec:IP_ipv6_extens}).
\item IPv6 richiede il supporto per il \textit{path MTU discovery} (cioè il
protocollo per la selezione della massima lunghezza del pacchetto); seppure
questo sia in teoria opzionale, senza di esso non sarà possibile inviare
gruppo.
In IPv6 non ci sono più le classi ma i bit più significativi indicano il tipo
-di indirizzo; in \tabref{tab:IP_ipv6addr} sono riportati i valori di detti
+di indirizzo; in tab.~\ref{tab:IP_ipv6addr} sono riportati i valori di detti
bit e il tipo di indirizzo che loro corrispondente. I bit più significativi
costituiscono quello che viene chiamato il \textit{format prefix} ed è sulla
base di questo che i vari tipi di indirizzi vengono identificati. Come si
spazio (più del 70\%) è riservato per usi futuri.
Si noti infine che gli indirizzi \textit{anycast} non sono riportati in
-\tabref{tab:IP_ipv6addr} in quanto allocati al di fuori dello spazio di
+tab.~\ref{tab:IP_ipv6addr} in quanto allocati al di fuori dello spazio di
allocazione degli indirizzi unicast.
\subsection{Indirizzi unicast \textit{provider-based}}
efficiente di allocazione la struttura di questi indirizzi è organizzata fin
dall'inizio in maniera gerarchica; pertanto lo spazio di questi indirizzi è
stato suddiviso in una serie di campi secondo lo schema riportato in
-\tabref{tab:IP_ipv6_unicast}.
+tab.~\ref{tab:IP_ipv6_unicast}.
\begin{table}[htb]
\centering
gestione dei singoli fruitori finali, gli indirizzi \textit{provider-based}
lasciano normalmente gli ultimi 64~bit a disposizione per questo livello, la
modalità più immediata è quella di usare uno schema del tipo mostrato in
-\tabref{tab:IP_ipv6_uninterf} dove l'\textit{Interface Id} è dato dal
+tab.~\ref{tab:IP_ipv6_uninterf} dove l'\textit{Interface Id} è dato dal
MAC-address a 48~bit dello standard Ethernet, scritto in genere nell'hardware
delle scheda di rete, e si usano i restanti 16~bit per indicare la sottorete.
attribuzione degli indirizzi per i fornitori di servizi nell'ambito del/i
paese coperto dal registro nazionale con le modalità viste in precedenza.
Una tale ripartizione andrà effettuata all'interno dei soliti 56~bit come
-mostrato in \tabref{tab:IP_ipv6_uninaz}.
+mostrato in tab.~\ref{tab:IP_ipv6_uninaz}.
\begin{table}[htb]
\centering
Ci sono due tipi di indirizzi, \textit{link-local} e \textit{site-local}. Il
primo è usato per un singolo link; la struttura è mostrata in
-\tabref{tab:IP_ipv6_linklocal}, questi indirizzi iniziano sempre con un valore
-nell'intervallo \texttt{FE80}--\texttt{FEBF} e vengono in genere usati per la
-configurazione automatica dell'indirizzo al bootstrap e per la ricerca dei
-vicini (vedi \ref{sec:IP_ipv6_autoconf}); un pacchetto che abbia tale
+tab.~\ref{tab:IP_ipv6_linklocal}, questi indirizzi iniziano sempre con un
+valore nell'intervallo \texttt{FE80}--\texttt{FEBF} e vengono in genere usati
+per la configurazione automatica dell'indirizzo al bootstrap e per la ricerca
+dei vicini (vedi \ref{sec:IP_ipv6_autoconf}); un pacchetto che abbia tale
indirizzo come sorgente o destinazione non deve venire ritrasmesso dai router.
Un indirizzo \textit{site-local} invece è usato per l'indirizzamento
all'interno di un sito che non necessita di un prefisso globale; la struttura
-è mostrata in \tabref{tab:IP_ipv6_sitelocal}, questi indirizzi iniziano sempre
-con un valore nell'intervallo \texttt{FEC0}--\texttt{FEFF} e non devono venire
-ritrasmessi dai router all'esterno del sito stesso; sono in sostanza gli
-equivalenti degli indirizzi riservati per reti private definiti su IPv4. Per
-entrambi gli indirizzi il campo \textit{Interface Id} è un identificatore che
-deve essere unico nel dominio in cui viene usato, un modo immediato per
+è mostrata in tab.~\ref{tab:IP_ipv6_sitelocal}, questi indirizzi iniziano
+sempre con un valore nell'intervallo \texttt{FEC0}--\texttt{FEFF} e non devono
+venire ritrasmessi dai router all'esterno del sito stesso; sono in sostanza
+gli equivalenti degli indirizzi riservati per reti private definiti su IPv4.
+Per entrambi gli indirizzi il campo \textit{Interface Id} è un identificatore
+che deve essere unico nel dominio in cui viene usato, un modo immediato per
costruirlo è quello di usare il MAC-address delle schede di rete.
\begin{table}[!h]
di compatibilità.
Un primo tipo sono gli indirizzi \textit{IPv4 mappati su IPv6} (mostrati in
-\tabref{tab:IP_ipv6_map}), questo sono indirizzi unicast che vengono usati per
-consentire ad applicazioni IPv6 di comunicare con host capaci solo di IPv4;
-questi sono ad esempio gli indirizzi generati da un DNS quando l'host
+tab.~\ref{tab:IP_ipv6_map}), questo sono indirizzi unicast che vengono usati
+per consentire ad applicazioni IPv6 di comunicare con host capaci solo di
+IPv4; questi sono ad esempio gli indirizzi generati da un DNS quando l'host
richiesto supporta solo IPv4; l'uso di un tale indirizzo in un socket IPv6
comporta la generazione di un pacchetto IPv4 (ovviamente occorre che sia IPv4
che IPv6 siano supportati sull'host di origine).
\end{table}
Un secondo tipo di indirizzi di compatibilità sono gli \textsl{IPv4
- compatibili IPv6} (vedi \tabref{tab:IP_ipv6_comp}) usati nella transizione
+ compatibili IPv6} (vedi tab.~\ref{tab:IP_ipv6_comp}) usati nella transizione
da IPv4 a IPv6: quando un nodo che supporta sia IPv6 che IPv4 non ha un router
IPv6 deve usare nel DNS un indirizzo di questo tipo, ogni pacchetto IPv6
inviato a un tale indirizzo verrà automaticamente incapsulato in IPv4.
e il pacchetto viene inviato a tutte le interfacce di detto gruppo.
Un'interfaccia può appartenere ad un numero qualunque numero di gruppi di
multicast. Il formato degli indirizzi \textit{multicast} è riportato in
-\tabref{tab:IP_ipv6_multicast}:
+tab.~\ref{tab:IP_ipv6_multicast}:
\begin{table}[htb]
\centering
transitorio.
\item \textsl{scop} è un numero di quattro bit che indica il raggio di
validità dell'indirizzo, i valori assegnati per ora sono riportati in
- \tabref{tab:IP_ipv6_multiscope}.
+ tab.~\ref{tab:IP_ipv6_multiscope}.
\end{itemize}
Infine l'ultimo campo identifica il gruppo di multicast, sia permanente che
transitorio, all'interno del raggio di validità del medesimo. Alcuni
-indirizzi multicast, riportati in \tabref{tab:multiadd} sono già riservati
+indirizzi multicast, riportati in tab.~\ref{tab:multiadd} sono già riservati
per il funzionamento della rete.
\begin{table}[!htb]
opzioni questa sarà l'intestazione di un protocollo di trasporto del livello
superiore, per cui il campo assumerà lo stesso valore del campo
\textit{protocol} di IPv4, altrimenti assumerà il valore dell'opzione
-presente; i valori possibili sono riportati in \tabref{tab:IP_ipv6_nexthead}.
+presente; i valori possibili sono riportati in
+tab.~\ref{tab:IP_ipv6_nexthead}.
\begin{table}[htb]
\begin{center}
di integrità (ma senza riservatezza) dei pacchetti IP.
L'intestazione di autenticazione ha il formato descritto in
-\figref{fig:autent_estens}: il campo \textit{Next Header} indica
+fig.~\ref{fig:autent_estens}: il campo \textit{Next Header} indica
l'intestazione successiva, con gli stessi valori del campo omonimo
nell'intestazione principale di IPv6, il campo \textit{Length} indica la
lunghezza dell'intestazione di autenticazione in numero di parole a 32 bit, il
estensione; ad essa segue il carico del pacchetto che viene criptato.
Un pacchetto crittografato pertanto viene ad avere una struttura del tipo di
-quella mostrata in \figref{fig:ESP_criptopack}, tutti i campi sono in chiaro
+quella mostrata in fig.~\ref{fig:ESP_criptopack}, tutti i campi sono in chiaro
fino al vettore di inizializzazione, il resto è crittografato.
La procedura di configurazione è la seguente: all'avvio tutti i nodi IPv6
iniziano si devono aggregare al gruppo multicast \textit{all-nodes}
programmando la propria interfaccia per ricevere i messaggi dall'indirizzo
-multicast \texttt{FF02::1} (vedi \secref{sec:IP_ipv6_multicast}); a questo
+multicast \texttt{FF02::1} (vedi sez.~\ref{sec:IP_ipv6_multicast}); a questo
punto devono inviare un messaggio ICMP \textit{Router solicitation} a tutti i
router locali usando l'indirizzo multicast \texttt{FF02::2} usando come
sorgente il proprio indirizzo link-local.
pagine web, la posta elettronica, ftp, telnet, ssh e praticamente ogni
servizio che viene fornito tramite la rete, anche se, come abbiamo visto, il
modello è utilizzato in generale anche per programmi che, come gli esempi che
-abbiamo usato in \capref{cha:IPC} a proposito della comunicazione fra processi
-nello stesso sistema, non fanno necessariamente uso della rete.
+abbiamo usato in cap.~\ref{cha:IPC} a proposito della comunicazione fra
+processi nello stesso sistema, non fanno necessariamente uso della rete.
Normalmente si dividono i server in due categorie principali, e vengono detti
\textsl{concorrenti} o \textsl{iterativi}, sulla base del loro comportamento.
Una caratteristica comune dei protocolli di rete è il loro essere strutturati
in livelli sovrapposti; in questo modo ogni protocollo di un certo livello
realizza le sue funzionalità basandosi su un protocollo del livello
-sottostante. Questo modello di funzionamento è stato stato standardizzato
-dalla \textit{International Standards Organization} (ISO) che ha preparato fin
-dal 1984 il Modello di Riferimento \textit{Open Systems Interconnection}
-(OSI), strutturato in sette livelli, secondo quanto riportato in
-\tabref{tab:net_osilayers}.
+sottostante. Questo modello di funzionamento è stato standardizzato dalla
+\textit{International Standards Organization} (ISO) che ha preparato fin dal
+1984 il Modello di Riferimento \textit{Open Systems Interconnection} (OSI),
+strutturato in sette livelli, secondo quanto riportato in
+tab.~\ref{tab:net_osilayers}.
\begin{table}[htb]
\centering
è stata creata la frase \texttt{All people seem to need data processing}, in
cui ciascuna parola corrisponde all'iniziale di uno dei livelli.}, tanto che
usualmente si tende a suddividerlo in due parti, secondo lo schema mostrato in
-\figref{fig:net_osi_tcpip_comp}, con un \textit{upper layer} che riguarda solo
-le applicazioni, che viene realizzato in user space, ed un \textit{lower
+fig.~\ref{fig:net_osi_tcpip_comp}, con un \textit{upper layer} che riguarda
+solo le applicazioni, che viene realizzato in user space, ed un \textit{lower
layer} in cui si mescolano la gestione fatta dal kernel e le funzionalità
fornite dall'hardware.
\label{sec:net_tcpip_overview}
Così come ISO/OSI anche il modello del TCP/IP è stato strutturato in livelli
-(riassunti in \tabref{tab:net_layers}); un confronto fra i due è riportato in
-\figref{fig:net_osi_tcpip_comp} dove viene evidenziata anche la corrispondenza
-fra i rispettivi livelli (che comunque è approssimativa) e su come essi vanno
-ad inserirsi all'interno del sistema rispetto alla divisione fra user space e
-kernel space spiegata in \secref{sec:intro_unix_struct}.\footnote{in realtà è
- sempre possibile accedere dallo user space, attraverso una opportuna
- interfaccia (come vedremo in \secref{sec:sock_sa_packet}), ai livelli
- inferiori del protocollo.}
+(riassunti in tab.~\ref{tab:net_layers}); un confronto fra i due è riportato
+in fig.~\ref{fig:net_osi_tcpip_comp} dove viene evidenziata anche la
+corrispondenza fra i rispettivi livelli (che comunque è approssimativa) e su
+come essi vanno ad inserirsi all'interno del sistema rispetto alla divisione
+fra user space e kernel space spiegata in
+sez.~\ref{sec:intro_unix_struct}.\footnote{in realtà è sempre possibile
+ accedere dallo user space, attraverso una opportuna interfaccia (come
+ vedremo in sez.~\ref{sec:sock_sa_packet}), ai livelli inferiori del
+ protocollo.}
\begin{table}[htb]
\centering
\begin{basedescript}{\desclabelwidth{2.5cm}\desclabelstyle{\nextlinelabel}}
\item[\textbf{Applicazione}] É relativo ai programmi di interfaccia con la
rete, in genere questi vengono realizzati secondo il modello client-server
- (vedi \secref{sec:net_cliserv}), realizzando una comunicazione secondo un
+ (vedi sez.~\ref{sec:net_cliserv}), realizzando una comunicazione secondo un
protocollo che è specifico di ciascuna applicazione.
\item[\textbf{Trasporto}] Fornisce la comunicazione tra le due stazioni
terminali su cui girano gli applicativi, regola il flusso delle
\end{basedescript}
La comunicazione fra due stazioni remote avviene secondo le modalità
-illustrate in \figref{fig:net_tcpip_data_flux}, dove si è riportato il flusso
+illustrate in fig.~\ref{fig:net_tcpip_data_flux}, dove si è riportato il flusso
dei dati reali e i protocolli usati per lo scambio di informazione su ciascun
livello. Si è genericamente indicato \textit{ethernet} per il livello 1, anche
se in realtà i protocolli di trasmissione usati possono essere molti altri.
\end{figure}
Per chiarire meglio la struttura della comunicazione attraverso i vari
-protocolli mostrata in \figref{fig:net_tcpip_data_flux}, conviene prendere in
+protocolli mostrata in fig.~\ref{fig:net_tcpip_data_flux}, conviene prendere in
esame i singoli passaggi fatti per passare da un livello al sottostante,
la procedura si può riassumere nei seguenti passi:
\begin{itemize}
standard per Internet.}).
\item I dati delle applicazioni vengono inviati al livello di trasporto usando
un'interfaccia opportuna (i \textit{socket}\index{socket}, che esamineremo
- in dettaglio in \capref{cha:socket_intro}). Qui verranno spezzati in
+ in dettaglio in cap.~\ref{cha:socket_intro}). Qui verranno spezzati in
pacchetti di dimensione opportuna e inseriti nel protocollo di trasporto,
aggiungendo ad ogni pacchetto le informazioni necessarie per la sua
gestione. Questo processo viene svolto direttamente nel kernel, ad esempio
\section{Il protocollo TCP/IP}
\label{sec:net_tpcip}
-Come accennato in \secref{sec:net_protocols} il protocollo TCP/IP è un insieme
-di protocolli diversi, che operano su 4 livelli diversi. Per gli interessi
-della programmazione di rete però sono importanti principalmente i due livelli
-centrali, e soprattutto quello di trasporto.
+Come accennato in sez.~\ref{sec:net_protocols} il protocollo TCP/IP è un
+insieme di protocolli diversi, che operano su 4 livelli diversi. Per gli
+interessi della programmazione di rete però sono importanti principalmente i
+due livelli centrali, e soprattutto quello di trasporto.
La principale interfaccia usata nella programmazione di rete, quella dei
socket\index{socket}, è infatti un'interfaccia nei confronti di quest'ultimo.
che fare solo con dettagli specifici delle applicazioni, mentre al di sotto
vengono curati tutti i dettagli relativi alla comunicazione. È pertanto
naturale definire una interfaccia di programmazione su questo confine, tanto
-più che è proprio lì (come evidenziato in \figref{fig:net_osi_tcpip_comp}) che
-nei sistemi Unix (e non solo) viene inserita la divisione fra kernel space e
-user space.
+più che è proprio lì (come evidenziato in fig.~\ref{fig:net_osi_tcpip_comp})
+che nei sistemi Unix (e non solo) viene inserita la divisione fra kernel space
+e user space.
In realtà in un sistema Unix è possibile accedere anche agli altri livelli
inferiori (e non solo a quello di trasporto) con opportune interfacce di
-programmazione (vedi \secref{sec:sock_sa_packet}), ma queste vengono usate
+programmazione (vedi sez.~\ref{sec:sock_sa_packet}), ma queste vengono usate
solo quando si debbano fare applicazioni di sistema per il controllo della
rete a basso livello, di uso quindi molto specialistico.
\label{sec:net_tcpip_general}
Benché si parli di TCP/IP questa famiglia di protocolli è composta anche da
-molti membri. In \figref{fig:net_tcpip_overview} si è riportato uno schema che
-mostra un panorama sui principali protocolli della famiglia, e delle loro
+molti membri. In fig.~\ref{fig:net_tcpip_overview} si è riportato uno schema
+che mostra un panorama sui principali protocolli della famiglia, e delle loro
relazioni reciproche e con alcune dalle principali applicazioni che li usano.
\begin{figure}[!htbp]
\label{fig:net_tcpip_overview}
\end{figure}
-I vari protocolli riportati in \figref{fig:net_tcpip_overview} sono i
+I vari protocolli riportati in fig.~\ref{fig:net_tcpip_overview} sono i
seguenti:
\begin{basedescript}{\desclabelwidth{1.7cm}\desclabelstyle{\nextlinelabel}}
si riferisce ad esso come ICPMv4 per distinguerlo da ICMPv6.
\item[\textsl{IGMP}] \textit{Internet Group Management Protocol}. É un
protocollo di livello 2 usato per il \textit{multicasting} (vedi
- \secref{sec:xxx_multicast}). Permette alle stazioni remote di notificare ai
- router che supportano questa comunicazione a quale gruppo esse appartengono.
- Come ICMP viene implementato direttamente sopra IP.
+ sez.~\ref{sec:xxx_multicast}). Permette alle stazioni remote di notificare
+ ai router che supportano questa comunicazione a quale gruppo esse
+ appartengono. Come ICMP viene implementato direttamente sopra IP.
\item[\textsl{ARP}] \textit{Address Resolution Protocol}. È il protocollo che
mappa un indirizzo IP in un indirizzo hardware sulla rete locale. È usato in
reti di tipo broadcast come Ethernet, Token Ring o FDDI che hanno associato
\end{itemize}
Maggiori dettagli riguardo a caratteristiche, notazioni e funzionamento del
-protocollo IP sono forniti nell'appendice \secref{sec:ip_protocol}.
+protocollo IP sono forniti nell'appendice sez.~\ref{sec:ip_protocol}.
\subsection{User Datagram Protocol (UDP)}
un'applicazione usa UDP essa scrive un pacchetto di dati (il cosiddetto
\textit{datagram} che da il nome al protocollo) su un socket\index{socket}, al
pacchetto viene aggiunto un header molto semplice (per una descrizione più
-accurata vedi \secref{sec:udp_protocol}), e poi viene passato al livello
+accurata vedi sez.~\ref{sec:udp_protocol}), e poi viene passato al livello
superiore (IPv4 o IPv6 che sia) che lo spedisce verso la destinazione. Dato
che né IPv4 né IPv6 garantiscono l'affidabilità niente assicura che il
pacchetto arrivi a destinazione, né che più pacchetti arrivino nello stesso
effettuato per entrambe le direzioni di comunicazione.
%% Una descrizione più accurata del protocollo è fornita in appendice
-%% \secref{sec:tcp_protocol}.
+%% sez.~\ref{sec:tcp_protocol}.
\subsection{Limiti e dimensioni riguardanti la trasmissione dei dati}
\label{sec:net_lim_dim}
\item La dimensione massima di un pacchetto IP è di 65535 byte, compresa
l'intestazione. Questo è dovuto al fatto che la dimensione è indicata da un
campo apposito nell'header di IP che è lungo 16 bit (vedi
- \figref{fig:IP_ipv4_head}).
+ fig.~\ref{fig:IP_ipv4_head}).
\item La dimensione massima di un pacchetto normale di IPv6 è di 65575 byte,
il campo apposito nell'header infatti è sempre a 16 bit, ma la dimensione
dell'header è fissa e di 40 byte e non è compresa nel valore indicato dal
\item Molte reti fisiche hanno un MTU (\textit{maximum transfer unit}) che
dipende dal protocollo specifico usato al livello di connessione fisica. Il
più comune è quello di ethernet che è pari a 1500 byte, una serie di altri
- valori possibili sono riportati in \tabref{tab:net_mtu_values}.
+ valori possibili sono riportati in tab.~\ref{tab:net_mtu_values}.
\end{itemize}
Quando un pacchetto IP viene inviato su una interfaccia di rete e le sue
\textit{frammentazione}, i pacchetti cioè vengono suddivisi\footnote{questo
accade sia per IPv4 che per IPv6, anche se i pacchetti frammentati sono
gestiti con modalità diverse, IPv4 usa un flag nell'header, IPv6 una
- opportuna opzione, si veda \secref{sec:ipv6_protocol}.}) in blocchi più
+ opportuna opzione, si veda sez.~\ref{sec:ipv6_protocol}.}) in blocchi più
piccoli che possono essere trasmessi attraverso l'interfaccia.
\begin{table}[!htb]
Oltre alla conclusione ``\textsl{normale}'' esiste anche la possibilità di una
conclusione ``\textsl{anomala}'' del programma a causa della ricezione di un
-segnale (si veda \capref{cha:signals}) o della chiamata alla funzione
+segnale (si veda cap.~\ref{cha:signals}) o della chiamata alla funzione
\func{abort}; torneremo su questo in sez.~\ref{sec:proc_termination}.
Il valore di ritorno della funzione \func{main}, o quello usato nelle chiamate
La funzione chiude tutti i file descriptor appartenenti al processo (si tenga
presente che questo non comporta il salvataggio dei dati bufferizzati degli
stream), fa sì che ogni figlio del processo sia ereditato da \cmd{init} (vedi
-sez.~\ref{cha:process_handling}), manda un segnale \const{SIGCHLD} al processo
-padre (vedi sez.~\ref{sec:sig_job_control}) ed infine ritorna lo stato di uscita
-specificato in \param{status} che può essere raccolto usando la funzione
-\func{wait} (vedi sez.~\ref{sec:proc_wait}).
+cap.~\ref{cha:process_handling}), manda un segnale \const{SIGCHLD} al processo
+padre (vedi sez.~\ref{sec:sig_job_control}) ed infine ritorna lo stato di
+uscita specificato in \param{status} che può essere raccolto usando la
+funzione \func{wait} (vedi sez.~\ref{sec:proc_wait}).
\subsection{Le funzioni \func{atexit} e \func{on\_exit}}
Si ricordi infine che un programma può anche essere interrotto dall'esterno
attraverso l'uso di un segnale (modalità di conclusione non mostrata in
fig.~\ref{fig:proc_prog_start_stop}); torneremo su questo aspetto in
-\capref{cha:signals}.
+cap.~\ref{cha:signals}.
2Gb. Con il kernel 2.4 ed il supporto per la \textit{high-memory} il limite
è stato esteso.}
-Come accennato in \capref{cha:intro_unix} questo spazio di indirizzi è
+Come accennato in cap.~\ref{cha:intro_unix} questo spazio di indirizzi è
virtuale e non corrisponde all'effettiva posizione dei dati nella RAM del
computer; in genere detto spazio non è neppure continuo (cioè non tutti gli
indirizzi possibili sono utilizzabili, e quelli usabili non sono
in genere il sistema è molto efficiente in questo lavoro; quando però ci siano
esigenze specifiche di prestazioni è possibile usare delle funzioni che
permettono di bloccare il meccanismo della paginazione\index{paginazione} e
-mantenere fisse delle pagine in memoria (vedi \ref{sec:proc_mem_lock}).
+mantenere fisse delle pagine in memoria (vedi sez.~\ref{sec:proc_mem_lock}).
\subsection{La struttura della memoria di un processo}
qualunque processo può a sua volta generarne altri, detti processi figli
(\textit{child process}). Ogni processo è identificato presso il sistema da un
numero univoco, il cosiddetto \textit{process identifier} o, più brevemente,
-\acr{pid}, assegnato in forma progressiva (vedi \secref{sec:proc_pid}) quando
+\acr{pid}, assegnato in forma progressiva (vedi sez.~\ref{sec:proc_pid}) quando
il processo viene creato.
Una seconda caratteristica di un sistema Unix è che la generazione di un
partire tutti gli altri processi necessari al funzionamento del sistema,
inoltre \cmd{init} è essenziale per svolgere una serie di compiti
amministrativi nelle operazioni ordinarie del sistema (torneremo su alcuni di
-essi in \secref{sec:proc_termination}) e non può mai essere terminato. La
+essi in sez.~\ref{sec:proc_termination}) e non può mai essere terminato. La
struttura del sistema comunque consente di lanciare al posto di \cmd{init}
qualunque altro programma, e in casi di emergenza (ad esempio se il file di
\cmd{init} si fosse corrotto) è ad esempio possibile lanciare una shell al suo
possono classificare i processi con la relazione padre/figlio in
un'organizzazione gerarchica ad albero, in maniera analoga a come i file sono
organizzati in un albero di directory (si veda
-\secref{sec:file_organization}); in \figref{fig:proc_tree} si è mostrato il
+sez.~\ref{sec:file_organization}); in fig.~\ref{fig:proc_tree} si è mostrato il
risultato del comando \cmd{pstree} che permette di visualizzare questa
struttura, alla cui base c'è \cmd{init} che è progenitore di tutti gli altri
processi.
\file{linux/sched.h}, ed uno schema semplificato, che riporta la struttura
delle principali informazioni contenute nella \struct{task\_struct} (che in
seguito incontreremo a più riprese), è mostrato in
-\figref{fig:proc_task_struct}.
+fig.~\ref{fig:proc_task_struct}.
\begin{figure}[htb]
\centering
\label{fig:proc_task_struct}
\end{figure}
-Come accennato in \secref{sec:intro_unix_struct} è lo
+Come accennato in sez.~\ref{sec:intro_unix_struct} è lo
\textit{scheduler}\index{scheduler} che decide quale processo mettere in
esecuzione; esso viene eseguito ad ogni system call ed ad ogni
interrupt,\footnote{più in una serie di altre occasioni. NDT completare questa
Hertz.\footnote{Il valore usuale di questa costante è 100, per tutte le
architetture eccetto l'alpha, per la quale è 1000. Occorre fare attenzione a
non confondere questo valore con quello dei clock tick (vedi
- \secref{sec:sys_unix_time}).}
+ sez.~\ref{sec:sys_unix_time}).}
%Si ha cioè un interrupt dal timer ogni centesimo di secondo.
Ogni volta che viene eseguito, lo \textit{scheduler}\index{scheduler} effettua
il calcolo delle priorità dei vari processi attivi (torneremo su questo in
-\secref{sec:proc_priority}) e stabilisce quale di essi debba essere posto in
+sez.~\ref{sec:proc_priority}) e stabilisce quale di essi debba essere posto in
esecuzione fino alla successiva invocazione.
\textsl{figlio}) creato dalla \func{fork} è una copia identica del processo
processo originale (detto \textsl{padre}), ma ha un nuovo \acr{pid} e viene
eseguito in maniera indipendente (le differenze fra padre e figlio sono
-affrontate in dettaglio in \secref{sec:proc_fork}).
+affrontate in dettaglio in sez.~\ref{sec:proc_fork}).
Se si vuole che il processo padre si fermi fino alla conclusione del processo
figlio questo deve essere specificato subito dopo la \func{fork} chiamando la
funzione \func{wait} o la funzione \func{waitpid} (si veda
-\secref{sec:proc_wait}); queste funzioni restituiscono anche un'informazione
+sez.~\ref{sec:proc_wait}); queste funzioni restituiscono anche un'informazione
abbastanza limitata sulle cause della terminazione del processo figlio.
Quando un processo ha concluso il suo compito o ha incontrato un errore non
risolvibile esso può essere terminato con la funzione \func{exit} (si veda
-quanto discusso in \secref{sec:proc_conclusion}). La vita del processo però
+quanto discusso in sez.~\ref{sec:proc_conclusion}). La vita del processo però
termina solo quando la notifica della sua conclusione viene ricevuta dal
processo padre, a quel punto tutte le risorse allocate nel sistema ad esso
associate vengono rilasciate.
Il \acr{pid} viene assegnato in forma progressiva\footnote{in genere viene
assegnato il numero successivo a quello usato per l'ultimo processo creato,
a meno che questo numero non sia già utilizzato per un altro \acr{pid},
- \acr{pgid} o \acr{sid} (vedi \secref{sec:sess_proc_group}).} ogni volta che
-un nuovo processo viene creato, fino ad un limite che, essendo il \acr{pid} un
-numero positivo memorizzato in un intero a 16 bit, arriva ad un massimo di
-32768. Oltre questo valore l'assegnazione riparte dal numero più basso
-disponibile a partire da un minimo di 300,\footnote{questi valori, fino al
- kernel 2.4.x, sono definiti dalla macro \const{PID\_MAX} in \file{threads.h}
- e direttamente in \file{fork.c}, con il kernel 2.5.x e la nuova interfaccia
- per i thread creata da Ingo Molnar anche il meccanismo di allocazione dei
- \acr{pid} è stato modificato.} che serve a riservare i \acr{pid} più bassi
-ai processi eseguiti direttamente dal kernel. Per questo motivo, come visto
-in \secref{sec:proc_hierarchy}, il processo di avvio (\cmd{init}) ha sempre il
-\acr{pid} uguale a uno.
+ \acr{pgid} o \acr{sid} (vedi sez.~\ref{sec:sess_proc_group}).} ogni volta
+che un nuovo processo viene creato, fino ad un limite che, essendo il
+\acr{pid} un numero positivo memorizzato in un intero a 16 bit, arriva ad un
+massimo di 32768. Oltre questo valore l'assegnazione riparte dal numero più
+basso disponibile a partire da un minimo di 300,\footnote{questi valori, fino
+ al kernel 2.4.x, sono definiti dalla macro \const{PID\_MAX} in
+ \file{threads.h} e direttamente in \file{fork.c}, con il kernel 2.5.x e la
+ nuova interfaccia per i thread creata da Ingo Molnar anche il meccanismo di
+ allocazione dei \acr{pid} è stato modificato.} che serve a riservare i
+\acr{pid} più bassi ai processi eseguiti direttamente dal kernel. Per questo
+motivo, come visto in sez.~\ref{sec:proc_hierarchy}, il processo di avvio
+(\cmd{init}) ha sempre il \acr{pid} uguale a uno.
Tutti i processi inoltre memorizzano anche il \acr{pid} del genitore da cui
sono stati creati, questo viene chiamato in genere \acr{ppid} (da
\bodydesc{Entrambe le funzioni non riportano condizioni di errore.}
\end{functions}
\noindent esempi dell'uso di queste funzioni sono riportati in
-\figref{fig:proc_fork_code}, nel programma \file{ForkTest.c}.
+fig.~\ref{fig:proc_fork_code}, nel programma \file{ForkTest.c}.
Il fatto che il \acr{pid} sia un numero univoco per il sistema lo rende un
candidato per generare ulteriori indicatori associati al processo di cui
diventa possibile garantire l'unicità: ad esempio in alcune implementazioni la
-funzione \func{tmpname} (si veda \secref{sec:file_temp_file}) usa il \acr{pid}
-per generare un pathname univoco, che non potrà essere replicato da un altro
-processo che usi la stessa funzione.
+funzione \func{tmpname} (si veda sez.~\ref{sec:file_temp_file}) usa il
+\acr{pid} per generare un pathname univoco, che non potrà essere replicato da
+un altro processo che usi la stessa funzione.
Tutti i processi figli dello stesso processo padre sono detti
\textit{sibling}, questa è una delle relazioni usate nel \textsl{controllo di
sessione}, in cui si raggruppano i processi creati su uno stesso terminale,
o relativi allo stesso login. Torneremo su questo argomento in dettaglio in
-\secref{cha:session}, dove esamineremo gli altri identificativi associati ad
+cap.~\ref{cha:session}, dove esamineremo gli altri identificativi associati ad
un processo e le varie relazioni fra processi utilizzate per definire una
sessione.
Oltre al \acr{pid} e al \acr{ppid}, (e a quelli che vedremo in
-\secref{sec:sess_proc_group}, relativi al controllo di sessione), ad ogni
+sez.~\ref{sec:sess_proc_group}, relativi al controllo di sessione), ad ogni
processo vengono associati degli altri identificatori che vengono usati per il
controllo di accesso. Questi servono per determinare se un processo può
eseguire o meno le operazioni richieste, a seconda dei privilegi e
dell'identità di chi lo ha posto in esecuzione; l'argomento è complesso e sarà
-affrontato in dettaglio in \secref{sec:proc_perms}.
+affrontato in dettaglio in sez.~\ref{sec:proc_perms}.
\subsection{La funzione \func{fork}}
il processo figlio continuano ad essere eseguiti normalmente a partire
dall'istruzione successiva alla \func{fork}; il processo figlio è però una
copia del padre, e riceve una copia dei segmenti di testo, stack e dati (vedi
-\secref{sec:proc_mem_layout}), ed esegue esattamente lo stesso codice del
+sez.~\ref{sec:proc_mem_layout}), ed esegue esattamente lo stesso codice del
padre. Si tenga presente però che la memoria è copiata, non condivisa,
pertanto padre e figlio vedono variabili diverse.
avere più figli, ed il valore di ritorno di \func{fork} è l'unico modo che gli
permette di identificare quello appena creato; al contrario un figlio ha
sempre un solo padre (il cui \acr{pid} può sempre essere ottenuto con
-\func{getppid}, vedi \secref{sec:proc_pid}) per cui si usa il valore nullo,
+\func{getppid}, vedi sez.~\ref{sec:proc_pid}) per cui si usa il valore nullo,
che non è il \acr{pid} di nessun processo.
\begin{figure}[!htb]
sono già troppi processi nel sistema (il che di solito è sintomo che
qualcos'altro non sta andando per il verso giusto) o si è ecceduto il limite
sul numero totale di processi permessi all'utente (vedi
-\secref{sec:sys_resource_limit}, ed in particolare
-\tabref{tab:sys_rlimit_values}).
+sez.~\ref{sec:sys_resource_limit}, ed in particolare
+tab.~\ref{tab:sys_rlimit_values}).
L'uso di \func{fork} avviene secondo due modalità principali; la prima è
quella in cui all'interno di un programma si creano processi figli cui viene
affidata l'esecuzione di una certa sezione di codice, mentre il processo padre
ne esegue un'altra. È il caso tipico dei programmi server (il modello
-\textit{client-server} è illustrato in \secref{sec:net_cliserv}) in cui il
+\textit{client-server} è illustrato in sez.~\ref{sec:net_cliserv}) in cui il
padre riceve ed accetta le richieste da parte dei programmi client, per
ciascuna delle quali pone in esecuzione un figlio che è incaricato di fornire
il servizio.
La seconda modalità è quella in cui il processo vuole eseguire un altro
programma; questo è ad esempio il caso della shell. In questo caso il processo
crea un figlio la cui unica operazione è quella di fare una \func{exec} (di
-cui parleremo in \secref{sec:proc_exec}) subito dopo la \func{fork}.
+cui parleremo in sez.~\ref{sec:proc_exec}) subito dopo la \func{fork}.
Alcuni sistemi operativi (il VMS ad esempio) combinano le operazioni di questa
seconda modalità (una \func{fork} seguita da una \func{exec}) in un'unica
relativamente facile intervenire sulle le modalità di esecuzione del nuovo
programma.
-In \figref{fig:proc_fork_code} è riportato il corpo del codice del programma
+In fig.~\ref{fig:proc_fork_code} è riportato il corpo del codice del programma
di esempio \cmd{forktest}, che permette di illustrare molte caratteristiche
dell'uso della funzione \func{fork}. Il programma crea un numero di figli
specificato da linea di comando, e prende anche alcune opzioni per indicare
occorrerà provvedere ad espliciti meccanismi di sincronizzazione, pena il
rischio di incorrere nelle cosiddette
\textit{race condition}\index{race condition}
-(vedi \secref{sec:proc_race_cond}).
+(vedi sez.~\ref{sec:proc_race_cond}).
Si noti inoltre che essendo i segmenti di memoria utilizzati dai singoli
processi completamente separati, le modifiche delle variabili nei processi
che come si vede è completamente diverso da quanto ottenevamo sul terminale.
Il comportamento delle varie funzioni di interfaccia con i file è analizzato
-in gran dettaglio in \capref{cha:file_unix_interface} e in
-\secref{cha:files_std_interface}. Qui basta accennare che si sono usate le
+in gran dettaglio in cap.~\ref{cha:file_unix_interface} e in
+cap.~\ref{cha:files_std_interface}. Qui basta accennare che si sono usate le
funzioni standard della libreria del C che prevedono l'output bufferizzato; e
-questa bufferizzazione (trattata in dettaglio in \secref{sec:file_buffering})
+questa bufferizzazione (trattata in dettaglio in sez.~\ref{sec:file_buffering})
varia a seconda che si tratti di un file su disco (in cui il buffer viene
scaricato su disco solo quando necessario) o di un terminale (nel qual caso il
buffer viene scaricato ad ogni carattere di a capo).
valido anche per l'esempio precedente, ma meno evidente: il fatto cioè che non
solo processi diversi possono scrivere in contemporanea sullo stesso file
(l'argomento della condivisione dei file è trattato in dettaglio in
-\secref{sec:file_sharing}), ma anche che, a differenza di quanto avviene per
+sez.~\ref{sec:file_sharing}), ma anche che, a differenza di quanto avviene per
le variabili, la posizione corrente sul file è condivisa fra il padre e tutti
i processi figli.
lo stesso avviene anche per tutti i figli; la funzione \func{fork} infatti ha
la caratteristica di duplicare nei figli tutti i file descriptor aperti nel
padre (allo stesso modo in cui lo fa la funzione \func{dup}, trattata in
-\secref{sec:file_dup}), il che comporta che padre e figli condividono le
+sez.~\ref{sec:file_dup}), il che comporta che padre e figli condividono le
stesse voci della \textit{file table} (per la spiegazione di questi termini si
-veda \secref{sec:file_sharing}) fra cui c'è anche la posizione corrente nel
+veda sez.~\ref{sec:file_sharing}) fra cui c'è anche la posizione corrente nel
file.
In questo modo se un processo scrive sul file aggiornerà la posizione corrente
\begin{itemize*}
\item i file aperti e gli eventuali flag di
\textit{close-on-exec}\index{close-on-exec} impostati (vedi
- \secref{sec:proc_exec} e \secref{sec:file_fcntl}).
+ sez.~\ref{sec:proc_exec} e sez.~\ref{sec:file_fcntl}).
\item gli identificatori per il controllo di accesso: l'\textsl{user-ID
reale}, il \textsl{group-ID reale}, l'\textsl{user-ID effettivo}, il
\textsl{group-ID effettivo} ed i \textit{group-ID supplementari} (vedi
- \secref{sec:proc_access_id}).
+ sez.~\ref{sec:proc_access_id}).
\item gli identificatori per il controllo di sessione: il \textit{process
group-ID} e il \textit{session id} ed il terminale di controllo (vedi
- \secref{sec:sess_proc_group}).
+ sez.~\ref{sec:sess_proc_group}).
\item la directory di lavoro e la directory radice (vedi
- \secref{sec:file_work_dir} e \secref{sec:file_chroot}).
-\item la maschera dei permessi di creazione (vedi \secref{sec:file_umask}).
-\item la maschera dei segnali bloccati (vedi \secref{sec:sig_sigmask}) e le
- azioni installate (vedi \secref{sec:sig_gen_beha}).
+ sez.~\ref{sec:file_work_dir} e sez.~\ref{sec:file_chroot}).
+\item la maschera dei permessi di creazione (vedi sez.~\ref{sec:file_umask}).
+\item la maschera dei segnali bloccati (vedi sez.~\ref{sec:sig_sigmask}) e le
+ azioni installate (vedi sez.~\ref{sec:sig_gen_beha}).
\item i segmenti di memoria condivisa agganciati al processo (vedi
- \secref{sec:ipc_sysv_shm}).
-\item i limiti sulle risorse (vedi \secref{sec:sys_resource_limit}).
-\item le variabili di ambiente (vedi \secref{sec:proc_environ}).
+ sez.~\ref{sec:ipc_sysv_shm}).
+\item i limiti sulle risorse (vedi sez.~\ref{sec:sys_resource_limit}).
+\item le variabili di ambiente (vedi sez.~\ref{sec:proc_environ}).
\end{itemize*}
le differenze fra padre e figlio dopo la \func{fork} invece sono:
\begin{itemize*}
\item il \acr{ppid} (\textit{parent process id}), quello del figlio viene
impostato al \acr{pid} del padre.
\item i valori dei tempi di esecuzione della struttura \struct{tms} (vedi
- \secref{sec:sys_cpu_times}) che nel figlio sono posti a zero.
-\item i \textit{lock} sui file (vedi \secref{sec:file_locking}), che non
+ sez.~\ref{sec:sys_cpu_times}) che nel figlio sono posti a zero.
+\item i \textit{lock} sui file (vedi sez.~\ref{sec:file_locking}), che non
vengono ereditati dal figlio.
-\item gli allarmi ed i segnali pendenti (vedi \secref{sec:sig_gen_beha}), che
+\item gli allarmi ed i segnali pendenti (vedi sez.~\ref{sec:sig_gen_beha}), che
per il figlio vengono cancellati.
\end{itemize*}
\subsection{La conclusione di un processo.}
\label{sec:proc_termination}
-In \secref{sec:proc_conclusion} abbiamo già affrontato le modalità con cui
+In sez.~\ref{sec:proc_conclusion} abbiamo già affrontato le modalità con cui
chiudere un programma, ma dall'interno del programma stesso; avendo a che fare
con un sistema multitasking resta da affrontare l'argomento dal punto di vista
di come il sistema gestisce la conclusione dei processi.
-Abbiamo visto in \secref{sec:proc_conclusion} le tre modalità con cui un
+Abbiamo visto in sez.~\ref{sec:proc_conclusion} le tre modalità con cui un
programma viene terminato in maniera normale: la chiamata di \func{exit} (che
esegue le funzioni registrate per l'uscita e chiude gli stream), il ritorno
dalla funzione \func{main} (equivalente alla chiamata di \func{exit}), e la
\item ad ogni processo figlio viene assegnato un nuovo padre (in genere
\cmd{init}).
\item viene inviato il segnale \const{SIGCHLD} al processo padre (vedi
- \secref{sec:sig_sigchld}).
+ sez.~\ref{sec:sig_sigchld}).
\item se il processo è un leader di sessione ed il suo terminale di controllo
è quello della sessione viene mandato un segnale di \const{SIGHUP} a tutti i
processi del gruppo di foreground e il terminale di controllo viene
- disconnesso (vedi \secref{sec:sess_ctrl_term}).
+ disconnesso (vedi sez.~\ref{sec:sess_ctrl_term}).
\item se la conclusione di un processo rende orfano un \textit{process
group} ciascun membro del gruppo viene bloccato, e poi gli vengono
inviati in successione i segnali \const{SIGHUP} e \const{SIGCONT}
- (vedi ancora \secref{sec:sess_ctrl_term}).
+ (vedi ancora sez.~\ref{sec:sess_ctrl_term}).
\end{itemize*}
Oltre queste operazioni è però necessario poter disporre di un meccanismo
scelto consiste nel riportare lo stato di terminazione (il cosiddetto
\textit{termination status}) al processo padre.
-Nel caso di conclusione normale, abbiamo visto in \secref{sec:proc_conclusion}
-che lo stato di uscita del processo viene caratterizzato tramite il valore del
-cosiddetto \textit{exit status}, cioè il valore passato alle funzioni
-\func{exit} o \func{\_exit} (o dal valore di ritorno per \func{main}). Ma se
-il processo viene concluso in maniera anomala il programma non può specificare
-nessun \textit{exit status}, ed è il kernel che deve generare autonomamente il
-\textit{termination status} per indicare le ragioni della conclusione anomala.
+Nel caso di conclusione normale, abbiamo visto in
+sez.~\ref{sec:proc_conclusion} che lo stato di uscita del processo viene
+caratterizzato tramite il valore del cosiddetto \textit{exit status}, cioè il
+valore passato alle funzioni \func{exit} o \func{\_exit} (o dal valore di
+ritorno per \func{main}). Ma se il processo viene concluso in maniera anomala
+il programma non può specificare nessun \textit{exit status}, ed è il kernel
+che deve generare autonomamente il \textit{termination status} per indicare le
+ragioni della conclusione anomala.
Si noti la distinzione fra \textit{exit status} e \textit{termination status}:
quello che contraddistingue lo stato di chiusura del processo e viene
riportato attraverso le funzioni \func{wait} o \func{waitpid} (vedi
-\secref{sec:proc_wait}) è sempre quest'ultimo; in caso di conclusione normale
+sez.~\ref{sec:proc_wait}) è sempre quest'ultimo; in caso di conclusione normale
il kernel usa il primo (nel codice eseguito da \func{\_exit}) per produrre il
secondo.
Questo viene fatto mantenendo attiva la voce nella tabella dei processi, e
memorizzando alcuni dati essenziali, come il \acr{pid}, i tempi di CPU usati
-dal processo (vedi \secref{sec:sys_unix_time}) e lo stato di terminazione,
+dal processo (vedi sez.~\ref{sec:sys_unix_time}) e lo stato di terminazione,
mentre la memoria in uso ed i file aperti vengono rilasciati immediatamente. I
processi che sono terminati, ma il cui stato di terminazione non è stato
ancora ricevuto dal padre sono chiamati \textit{zombie}\index{zombie}, essi
restano presenti nella tabella dei processi ed in genere possono essere
identificati dall'output di \cmd{ps} per la presenza di una \texttt{Z} nella
-colonna che ne indica lo stato (vedi \tabref{tab:proc_proc_states}). Quando il
-padre effettuerà la lettura dello stato di uscita anche questa informazione,
-non più necessaria, verrà scartata e la terminazione potrà dirsi completamente
-conclusa.
+colonna che ne indica lo stato (vedi tab.~\ref{tab:proc_proc_states}). Quando
+il padre effettuerà la lettura dello stato di uscita anche questa
+informazione, non più necessaria, verrà scartata e la terminazione potrà dirsi
+completamente conclusa.
Possiamo utilizzare il nostro programma di prova per analizzare anche questa
condizione: lanciamo il comando \cmd{forktest} in background, indicando al
a lungo e creare molti figli. In questo caso si deve sempre avere cura di far
leggere l'eventuale stato di uscita di tutti i figli (in genere questo si fa
attraverso un apposito \textit{signal handler}, che chiama la funzione
-\func{wait}, vedi \secref{sec:sig_sigchld} e \secref{sec:proc_wait}). Questa
-operazione è necessaria perché anche se gli \textit{zombie}\index{zombie} non
-consumano risorse di memoria o processore, occupano comunque una voce nella
-tabella dei processi, che a lungo andare potrebbe esaurirsi.
+\func{wait}, vedi sez.~\ref{sec:sig_sigchld} e sez.~\ref{sec:proc_wait}).
+Questa operazione è necessaria perché anche se gli
+\textit{zombie}\index{zombie} non consumano risorse di memoria o processore,
+occupano comunque una voce nella tabella dei processi, che a lungo andare
+potrebbe esaurirsi.
Si noti che quando un processo adottato da \cmd{init} termina, esso non
diviene uno \textit{zombie}\index{zombie}; questo perché una delle funzioni di
Al ritorno della funzione lo stato di terminazione del figlio viene salvato
nella variabile puntata da \param{status} e tutte le risorse del kernel
-relative al processo (vedi \secref{sec:proc_termination}) vengono rilasciate.
+relative al processo (vedi sez.~\ref{sec:proc_termination}) vengono rilasciate.
Nel caso un processo abbia più figli il valore di ritorno (il \acr{pid} del
figlio) permette di identificare qual'è quello che è uscito.
Per questo motivo lo standard POSIX.1 ha introdotto la funzione
\funcd{waitpid} che effettua lo stesso servizio, ma dispone di una serie di
funzionalità più ampie, legate anche al controllo di sessione (si veda
-\secref{sec:sess_job_control}). Dato che è possibile ottenere lo stesso
+sez.~\ref{sec:sess_job_control}). Dato che è possibile ottenere lo stesso
comportamento di \func{wait} si consiglia di utilizzare sempre questa
funzione, il cui prototipo è:
\begin{functions}
possibilità si specificare un'opzione \const{WNOHANG} che ne previene il
blocco; inoltre \func{waitpid} può specificare in maniera flessibile quale
processo attendere, sulla base del valore fornito dall'argomento \param{pid},
-secondo lo specchietto riportato in \tabref{tab:proc_waidpid_pid}.
+secondo lo specchietto riportato in tab.~\ref{tab:proc_waidpid_pid}.
\begin{table}[!htb]
\centering
\hline
\hline
$<-1$& -- & attende per un figlio il cui \textit{process group} (vedi
- \secref{sec:sess_proc_group}) è uguale al
+ sez.~\ref{sec:sess_proc_group}) è uguale al
valore assoluto di \param{pid}. \\
$-1$ & \const{WAIT\_ANY} & attende per un figlio qualsiasi, usata in
questa maniera è equivalente a \func{wait}.\\
come maschera binaria ottenuta con l'OR delle suddette costanti con zero.
In genere si utilizza \const{WUNTRACED} all'interno del controllo di sessione,
-(l'argomento è trattato in \secref{sec:sess_job_control}). In tal caso infatti
-la funzione ritorna, restituendone il \acr{pid}, quando c'è un processo figlio
-che è entrato in stato di sleep (vedi \tabref{tab:proc_proc_states}) e del
-quale non si è ancora letto lo stato (con questa stessa opzione). In Linux
-sono previste altre opzioni non standard relative al comportamento con i
-thread, che riprenderemo in \secref{sec:thread_xxx}.
+(l'argomento è trattato in sez.~\ref{sec:sess_job_control}). In tal caso
+infatti la funzione ritorna, restituendone il \acr{pid}, quando c'è un
+processo figlio che è entrato in stato di sleep (vedi
+tab.~\ref{tab:proc_proc_states}) e del quale non si è ancora letto lo stato
+(con questa stessa opzione). In Linux sono previste altre opzioni non standard
+relative al comportamento con i thread, che riprenderemo in
+sez.~\ref{sec:thread_xxx}.
La terminazione di un processo figlio è chiaramente un evento asincrono
rispetto all'esecuzione di un programma e può avvenire in un qualunque
momento. Per questo motivo, come accennato nella sezione precedente, una delle
azioni prese dal kernel alla conclusione di un processo è quella di mandare un
segnale di \const{SIGCHLD} al padre. L'azione predefinita (si veda
-\secref{sec:sig_base}) per questo segnale è di essere ignorato, ma la sua
+sez.~\ref{sec:sig_base}) per questo segnale è di essere ignorato, ma la sua
generazione costituisce il meccanismo di comunicazione asincrona con cui il
kernel avverte il processo padre che uno dei suoi figli è terminato.
\textit{zombie}\index{zombie}), per questo la modalità più usata per chiamare
queste funzioni è quella di utilizzarle all'interno di un \textit{signal
handler} (vedremo un esempio di come gestire \const{SIGCHLD} con i segnali
-in \secref{sec:sig_example}). In questo caso infatti, dato che il segnale è
+in sez.~\ref{sec:sig_example}). In questo caso infatti, dato che il segnale è
generato dalla terminazione di un figlio, avremo la certezza che la chiamata a
\func{wait} non si bloccherà.
\val{WIFEXITED} ha restituito un valore non nullo.\\
\macro{WIFSIGNALED(s)} & Vera se il processo figlio è terminato
in maniera anomala a causa di un segnale che non è stato catturato (vedi
- \secref{sec:sig_notification}).\\
+ sez.~\ref{sec:sig_notification}).\\
\macro{WTERMSIG(s)} & restituisce il numero del segnale che ha causato
la terminazione anomala del processo. Può essere valutata solo se
\val{WIFSIGNALED} ha restituito un valore non nullo.\\
Lo standard POSIX.1 definisce una serie di macro di preprocessore da usare per
analizzare lo stato di uscita. Esse sono definite sempre in
-\file{<sys/wait.h>} ed elencate in \tabref{tab:proc_status_macro} (si tenga
+\file{<sys/wait.h>} ed elencate in tab.~\ref{tab:proc_status_macro} (si tenga
presente che queste macro prendono come parametro la variabile di tipo
\ctyp{int} puntata da \param{status}).
Si tenga conto che nel caso di conclusione anomala il valore restituito da
\val{WTERMSIG} può essere confrontato con le costanti definite in
-\file{signal.h} ed elencate in \tabref{tab:sig_signal_list}, e stampato usando
-le apposite funzioni trattate in \secref{sec:sig_strsignal}.
+\file{signal.h} ed elencate in tab.~\ref{tab:sig_signal_list}, e stampato
+usando le apposite funzioni trattate in sez.~\ref{sec:sig_strsignal}.
\subsection{Le funzioni \func{wait3} e \func{wait4}}
\noindent
la struttura \struct{rusage} è definita in \file{sys/resource.h}, e viene
utilizzata anche dalla funzione \func{getrusage} (vedi
-\secref{sec:sys_resource_use}) per ottenere le risorse di sistema usate da un
-processo; la sua definizione è riportata in \figref{fig:sys_rusage_struct}.
+sez.~\ref{sec:sys_resource_use}) per ottenere le risorse di sistema usate da un
+processo; la sua definizione è riportata in fig.~\ref{fig:sys_rusage_struct}.
\subsection{Le funzioni \func{exec}}
Ci sono sei diverse versioni di \func{exec} (per questo la si è chiamata
famiglia di funzioni) che possono essere usate per questo compito, in realtà
-(come mostrato in \figref{fig:proc_exec_relat}), sono tutte un front-end a
+(come mostrato in fig.~\ref{fig:proc_exec_relat}), sono tutte un front-end a
\funcd{execve}. Il prototipo di quest'ultima è:
\begin{prototype}{unistd.h}
{int execve(const char *filename, char *const argv[], char *const envp[])}
\end{functions}
Per capire meglio le differenze fra le funzioni della famiglia si può fare
-riferimento allo specchietto riportato in \tabref{tab:proc_exec_scheme}. La
+riferimento allo specchietto riportato in tab.~\ref{tab:proc_exec_scheme}. La
prima differenza riguarda le modalità di passaggio dei parametri che poi
andranno a costituire gli argomenti a linea di comando (cioè i valori di
\param{argv} e \param{argc} visti dalla funzione \func{main} del programma
Con lo mnemonico \code{e} vengono indicate quelle funzioni che necessitano di
un vettore di parametri \var{envp[]} analogo a quello usato per gli argomenti
a riga di comando (terminato quindi da un \val{NULL}), le altre usano il
-valore della variabile \var{environ} (vedi \secref{sec:proc_environ}) del
+valore della variabile \var{environ} (vedi sez.~\ref{sec:proc_environ}) del
processo di partenza per costruire l'ambiente.
Oltre a mantenere lo stesso \acr{pid}, il nuovo programma fatto partire da
\item il \textit{process id} (\acr{pid}) ed il \textit{parent process id}
(\acr{ppid}).
\item l'\textsl{user-ID reale}, il \textit{group-ID reale} ed i
- \textsl{group-ID supplementari} (vedi \secref{sec:proc_access_id}).
+ \textsl{group-ID supplementari} (vedi sez.~\ref{sec:proc_access_id}).
\item il \textit{session id} (\acr{sid}) ed il \textit{process group-ID}
- (\acr{pgid}), vedi \secref{sec:sess_proc_group}.
-\item il terminale di controllo (vedi \secref{sec:sess_ctrl_term}).
-\item il tempo restante ad un allarme (vedi \secref{sec:sig_alarm_abort}).
+ (\acr{pgid}), vedi sez.~\ref{sec:sess_proc_group}.
+\item il terminale di controllo (vedi sez.~\ref{sec:sess_ctrl_term}).
+\item il tempo restante ad un allarme (vedi sez.~\ref{sec:sig_alarm_abort}).
\item la directory radice e la directory di lavoro corrente (vedi
- \secref{sec:file_work_dir}).
+ sez.~\ref{sec:file_work_dir}).
\item la maschera di creazione dei file (\var{umask}, vedi
- \secref{sec:file_umask}) ed i \textit{lock} sui file (vedi
- \secref{sec:file_locking}).
+ sez.~\ref{sec:file_umask}) ed i \textit{lock} sui file (vedi
+ sez.~\ref{sec:file_locking}).
\item i segnali sospesi (\textit{pending}) e la maschera dei segnali (si veda
- \secref{sec:sig_sigmask}).
-\item i limiti sulle risorse (vedi \secref{sec:sys_resource_limit}).
+ sez.~\ref{sec:sig_sigmask}).
+\item i limiti sulle risorse (vedi sez.~\ref{sec:sys_resource_limit}).
\item i valori delle variabili \var{tms\_utime}, \var{tms\_stime},
- \var{tms\_cutime}, \var{tms\_ustime} (vedi \secref{sec:sys_cpu_times}).
+ \var{tms\_cutime}, \var{tms\_ustime} (vedi sez.~\ref{sec:sys_cpu_times}).
\end{itemize*}
Inoltre i segnali che sono stati impostati per essere ignorati nel processo
gli altri segnali vengono impostati alla loro azione predefinita. Un caso
speciale è il segnale \const{SIGCHLD} che, quando impostato a
\const{SIG\_IGN}, può anche non essere reimpostato a \const{SIG\_DFL} (si veda
-\secref{sec:sig_gen_beha}).
+sez.~\ref{sec:sig_gen_beha}).
La gestione dei file aperti dipende dal valore che ha il flag di
\textit{close-on-exec}\index{close-on-exec} (vedi anche
-\secref{sec:file_fcntl}) per ciascun file descriptor. I file per cui è
+sez.~\ref{sec:file_fcntl}) per ciascun file descriptor. I file per cui è
impostato vengono chiusi, tutti gli altri file restano aperti. Questo
significa che il comportamento predefinito è che i file restano aperti
attraverso una \func{exec}, a meno di una chiamata esplicita a \func{fcntl}
Per le directory, lo standard POSIX.1 richiede che esse vengano chiuse
attraverso una \func{exec}, in genere questo è fatto dalla funzione
-\func{opendir} (vedi \secref{sec:file_dir_read}) che effettua da sola
+\func{opendir} (vedi sez.~\ref{sec:file_dir_read}) che effettua da sola
l'impostazione del flag di \textit{close-on-exec}\index{close-on-exec} sulle
directory che apre, in maniera trasparente all'utente.
Abbiamo detto che l'\textsl{user-ID reale} ed il \textsl{group-ID reale}
restano gli stessi all'esecuzione di \func{exec}; lo stesso vale per
l'\textsl{user-ID effettivo} ed il \textsl{group-ID effettivo} (il significato
-di questi identificatori è trattato in \secref{sec:proc_access_id}), tranne
+di questi identificatori è trattato in sez.~\ref{sec:proc_access_id}), tranne
quando il file che si va ad eseguire abbia o il \acr{suid} bit o lo \acr{sgid}
bit impostato, in questo caso l'\textsl{user-ID effettivo} ed il
\textsl{group-ID effettivo} vengono impostati rispettivamente all'utente o al
-gruppo cui il file appartiene (per i dettagli vedi \secref{sec:proc_perms}).
+gruppo cui il file appartiene (per i dettagli vedi sez.~\ref{sec:proc_perms}).
Se il file da eseguire è in formato \emph{a.out} e necessita di librerie
condivise, viene lanciato il \textit{linker} dinamico \cmd{ld.so} prima del
\subsection{Gli identificatori del controllo di accesso}
\label{sec:proc_access_id}
-Come accennato in \secref{sec:intro_multiuser} il modello base\footnote{in
+Come accennato in sez.~\ref{sec:intro_multiuser} il modello base\footnote{in
realtà già esistono estensioni di questo modello base, che lo rendono più
flessibile e controllabile, come le \textit{capabilities}, le ACL per i file
o il \textit{Mandatory Access Control} di SELinux; inoltre basandosi sul
identificatori univoci, lo user-ID ed il group-ID; questi servono al kernel per
identificare uno specifico utente o un gruppo di utenti, per poi poter
controllare che essi siano autorizzati a compiere le operazioni richieste. Ad
-esempio in \secref{sec:file_access_control} vedremo come ad ogni file vengano
+esempio in sez.~\ref{sec:file_access_control} vedremo come ad ogni file vengano
associati un utente ed un gruppo (i suoi \textsl{proprietari}, indicati
appunto tramite un \acr{uid} ed un \acr{gid}) che vengono controllati dal
kernel nella gestione dei permessi di accesso.
rispettivamente \textit{real} ed \textit{effective} (cioè \textsl{reali} ed
\textsl{effettivi}). Nel caso di Linux si aggiungono poi altri due gruppi, il
\textit{saved} (\textsl{salvati}) ed il \textit{filesystem} (\textsl{di
- filesystem}), secondo la situazione illustrata in \tabref{tab:proc_uid_gid}.
+ filesystem}), secondo la situazione illustrata in
+tab.~\ref{tab:proc_uid_gid}.
\begin{table}[htb]
\footnotesize
reale}: questi vengono impostati al login ai valori corrispondenti
all'utente con cui si accede al sistema (e relativo gruppo principale).
Servono per l'identificazione dell'utente e normalmente non vengono mai
-cambiati. In realtà vedremo (in \secref{sec:proc_setuid}) che è possibile
+cambiati. In realtà vedremo (in sez.~\ref{sec:proc_setuid}) che è possibile
modificarli, ma solo ad un processo che abbia i privilegi di amministratore;
questa possibilità è usata proprio dal programma \cmd{login} che, una volta
completata la procedura di autenticazione, lancia una shell per la quale
supplementari} dei gruppi dei quali l'utente fa parte). Questi sono invece
gli identificatori usati nella verifiche dei permessi del processo e per il
controllo di accesso ai file (argomento affrontato in dettaglio in
-\secref{sec:file_perm_overview}).
+sez.~\ref{sec:file_perm_overview}).
Questi identificatori normalmente sono identici ai corrispondenti del gruppo
\textit{real} tranne nel caso in cui, come accennato in
-\secref{sec:proc_exec}, il programma che si è posto in esecuzione abbia i bit
+sez.~\ref{sec:proc_exec}, il programma che si è posto in esecuzione abbia i bit
\acr{suid} o \acr{sgid} impostati (il significato di questi bit è affrontato
-in dettaglio in \secref{sec:file_suid_sgid}). In questo caso essi saranno
+in dettaglio in sez.~\ref{sec:file_suid_sgid}). In questo caso essi saranno
impostati all'utente e al gruppo proprietari del file. Questo consente, per
programmi in cui ci sia necessità, di dare a qualunque utente normale
privilegi o permessi di un altro (o dell'amministratore).
L'\textsl{user-ID di filesystem} e il \textsl{group-ID di filesystem} sono
un'estensione introdotta in Linux per rendere più sicuro l'uso di NFS
-(torneremo sull'argomento in \secref{sec:proc_setfsuid}). Essi sono una
+(torneremo sull'argomento in sez.~\ref{sec:proc_setfsuid}). Essi sono una
replica dei corrispondenti identificatori del gruppo \textit{effective}, ai
quali si sostituiscono per tutte le operazioni di verifica dei permessi
-relativi ai file (trattate in \secref{sec:file_perm_overview}). Ogni
+relativi ai file (trattate in sez.~\ref{sec:file_perm_overview}). Ogni
cambiamento effettuato sugli identificatori effettivi viene automaticamente
riportato su di essi, per cui in condizioni normali si può tranquillamente
ignorarne l'esistenza, in quanto saranno del tutto equivalenti ai precedenti.
Le due funzioni che vengono usate per cambiare identità (cioè utente e gruppo
di appartenenza) ad un processo sono rispettivamente \funcd{setuid} e
-\funcd{setgid}; come accennato in \secref{sec:proc_access_id} in Linux esse
+\funcd{setgid}; come accennato in sez.~\ref{sec:proc_access_id} in Linux esse
seguono la semantica POSIX che prevede l'esistenza dell'\textit{user-ID
salvato} e del \textit{group-ID salvato}; i loro prototipi sono:
\begin{functions}
Come accennato l'uso principale di queste funzioni è quello di poter
consentire ad un programma con i bit \acr{suid} o \acr{sgid} impostati (vedi
-\secref{sec:file_suid_sgid}) di riportare l'\textsl{user-ID effettivo} a quello
-dell'utente che ha lanciato il programma, effettuare il lavoro che non
+sez.~\ref{sec:file_suid_sgid}) di riportare l'\textsl{user-ID effettivo} a
+quello dell'utente che ha lanciato il programma, effettuare il lavoro che non
necessita di privilegi aggiuntivi, ed eventualmente tornare indietro.
Come esempio per chiarire l'uso di queste funzioni prendiamo quello con cui
Questo comportamento è corretto per l'uso che ne fa \cmd{login} una volta che
crea una nuova shell per l'utente; ma quando si vuole cambiare soltanto
l'\textsl{user-ID effettivo} del processo per cedere i privilegi occorre
-ricorrere ad altre funzioni (si veda ad esempio \secref{sec:proc_seteuid}).
+ricorrere ad altre funzioni (si veda ad esempio sez.~\ref{sec:proc_seteuid}).
\subsection{Le funzioni \func{setreuid} e \func{setregid}}
\end{functions}
La due funzioni sono analoghe ed il loro comportamento è identico; quanto
-detto per la prima prima riguardo l'user-ID, si applica immediatamente alla
-seconda per il group-ID. I processi non privilegiati possono impostare solo i
-valori del loro user-ID effettivo o reale; valori diversi comportano il
-fallimento della chiamata; l'amministratore invece può specificare un valore
-qualunque. Specificando un argomento di valore -1 l'identificatore
-corrispondente verrà lasciato inalterato.
+detto per la prima riguardo l'user-ID, si applica immediatamente alla seconda
+per il group-ID. I processi non privilegiati possono impostare solo i valori
+del loro user-ID effettivo o reale; valori diversi comportano il fallimento
+della chiamata; l'amministratore invece può specificare un valore qualunque.
+Specificando un argomento di valore -1 l'identificatore corrispondente verrà
+lasciato inalterato.
Con queste funzioni si possono scambiare fra loro gli user-ID reale e
effettivo, e pertanto è possibile implementare un comportamento simile a
Queste funzioni servono per impostare gli identificatori del gruppo
\textit{filesystem} che sono usati da Linux per il controllo dell'accesso ai
-file. Come già accennato in \secref{sec:proc_access_id} Linux definisce
+file. Come già accennato in sez.~\ref{sec:proc_access_id} Linux definisce
questo ulteriore gruppo di identificatori, che in circostanze normali sono
assolutamente equivalenti a quelli del gruppo \textit{effective}, dato che
ogni cambiamento di questi ultimi viene immediatamente riportato su di essi.
gruppi supplementari cui un utente può appartenere. Ogni processo può avere
almeno \const{NGROUPS\_MAX} gruppi supplementari\footnote{il numero massimo di
gruppi secondari può essere ottenuto con \func{sysconf} (vedi
- \secref{sec:sys_sysconf}), leggendo il parametro
+ sez.~\ref{sec:sys_sysconf}), leggendo il parametro
\texttt{\_SC\_NGROUPS\_MAX}.} in aggiunta al gruppo primario; questi vengono
ereditati dal processo padre e possono essere cambiati con queste funzioni.
La funzione legge i gruppi supplementari dell'utente specificato da
\param{user}, eseguendo una scansione del database dei gruppi (si veda
-\secref{sec:sys_user_group}). Ritorna poi in \param{groups} la lista di quelli
-a cui l'utente appartiene. Si noti che \param{ngroups} è passato come
+sez.~\ref{sec:sys_user_group}). Ritorna poi in \param{groups} la lista di
+quelli a cui l'utente appartiene. Si noti che \param{ngroups} è passato come
puntatore perché, qualora il valore specificato sia troppo piccolo, la
funzione ritorna -1, passando indietro il numero dei gruppi trovati.
specificati nel vettore passato con l'argomento \param{list}, di dimensioni
date dall'argomento \param{size}. Il numero massimo di gruppi supplementari è
un parametro di sistema, che può essere ricavato con le modalità spiegate in
-\secref{sec:sys_characteristics}.
+sez.~\ref{sec:sys_characteristics}.
Se invece si vogliono impostare i gruppi supplementari del processo a quelli di
un utente specifico, si può usare \funcd{initgroups} il cui prototipo è:
contrario di altri sistemi (che usano invece il cosiddetto \textit{cooperative
multitasking}) non sono i singoli processi, ma il kernel stesso a decidere
quando la CPU deve essere passata ad un altro processo. Come accennato in
-\secref{sec:proc_hierarchy} questa scelta viene eseguita da una sezione
+sez.~\ref{sec:proc_hierarchy} questa scelta viene eseguita da una sezione
apposita del kernel, lo \textit{scheduler}\index{scheduler}, il cui scopo è
quello di distribuire al meglio il tempo di CPU fra i vari processi.
Tutte queste possibilità sono caratterizzate da un diverso \textsl{stato} del
processo, in Linux un processo può trovarsi in uno degli stati riportati in
-\tabref{tab:proc_proc_states}; ma soltanto i processi che sono nello stato
+tab.~\ref{tab:proc_proc_states}; ma soltanto i processi che sono nello stato
\textit{runnable} concorrono per l'esecuzione. Questo vuol dire che, qualunque
sia la sua priorità, un processo non potrà mai essere messo in esecuzione
fintanto che esso si trova in uno qualunque degli altri stati.
abbia risultati significativi in termini di prestazioni.
Il meccanismo tradizionale di scheduling di Unix (che tratteremo in
-\secref{sec:proc_sched_stand}) è sempre stato basato su delle \textsl{priorità
- dinamiche}, in modo da assicurare che tutti i processi, anche i meno
-importanti, possano ricevere un po' di tempo di CPU. In sostanza quando un
-processo ottiene la CPU la sua priorità viene diminuita. In questo modo alla
-fine, anche un processo con priorità iniziale molto bassa, finisce per avere
-una priorità sufficiente per essere eseguito.
+sez.~\ref{sec:proc_sched_stand}) è sempre stato basato su delle
+\textsl{priorità dinamiche}, in modo da assicurare che tutti i processi, anche
+i meno importanti, possano ricevere un po' di tempo di CPU. In sostanza quando
+un processo ottiene la CPU la sua priorità viene diminuita. In questo modo
+alla fine, anche un processo con priorità iniziale molto bassa, finisce per
+avere una priorità sufficiente per essere eseguito.
Lo standard POSIX.1b però ha introdotto il concetto di \textsl{priorità
assoluta}, (chiamata anche \textsl{priorità statica}, in contrapposizione
eseguiti (cioè nello stato \textit{runnable}). La priorità assoluta viene in
genere indicata con un numero intero, ed un valore più alto comporta una
priorità maggiore. Su questa politica di scheduling torneremo in
-\secref{sec:proc_real_time}.
+sez.~\ref{sec:proc_real_time}.
In generale quello che succede in tutti gli Unix moderni è che ai processi
normali viene sempre data una priorità assoluta pari a zero, e la decisione di
La funzione permette, a seconda del valore di \param{which}, di leggere la
priorità di un processo, di un gruppo di processi (vedi
-\secref{sec:sess_proc_group}) o di un utente, specificando un corrispondente
-valore per \param{who} secondo la legenda di \tabref{tab:proc_getpriority}; un
-valore nullo di quest'ultimo indica il processo, il gruppo di processi o
+sez.~\ref{sec:sess_proc_group}) o di un utente, specificando un corrispondente
+valore per \param{who} secondo la legenda di tab.~\ref{tab:proc_getpriority};
+un valore nullo di quest'ultimo indica il processo, il gruppo di processi o
l'utente correnti.
\begin{table}[htb]
\subsection{Il meccanismo di \textit{scheduling real-time}}
\label{sec:proc_real_time}
-Come spiegato in \secref{sec:proc_sched} lo standard POSIX.1b ha introdotto le
-priorità assolute per permettere la gestione di processi real-time. In realtà
-nel caso di Linux non si tratta di un vero hard real-time, in quanto in
+Come spiegato in sez.~\ref{sec:proc_sched} lo standard POSIX.1b ha introdotto
+le priorità assolute per permettere la gestione di processi real-time. In
+realtà nel caso di Linux non si tratta di un vero hard real-time, in quanto in
presenza di eventuali interrupt il kernel interrompe l'esecuzione di un
processo qualsiasi sia la sua priorità,\footnote{questo a meno che non si
siano installate le patch di RTLinux, RTAI o Adeos, con i quali è possibile
più elevata di un \textit{interrupt handler}.} mentre con l'incorrere in un
page fault\index{page fault} si possono avere ritardi non previsti. Se
l'ultimo problema può essere aggirato attraverso l'uso delle funzioni di
-controllo della memoria virtuale (vedi \secref{sec:proc_mem_lock}), il primo
+controllo della memoria virtuale (vedi sez.~\ref{sec:proc_mem_lock}), il primo
non è superabile e può comportare ritardi non prevedibili riguardo ai tempi di
esecuzione di qualunque processo.
La funzione esegue l'impostazione per il processo specificato dall'argomento
\param{pid}; un valore nullo esegue l'impostazione per il processo corrente.
La politica di scheduling è specificata dall'argomento \param{policy} i cui
-possibili valori sono riportati in \tabref{tab:proc_sched_policy}; un valore
+possibili valori sono riportati in tab.~\ref{tab:proc_sched_policy}; un valore
negativo per \param{policy} mantiene la politica di scheduling corrente.
Solo un processo con i privilegi di amministratore può impostare priorità
assolute diverse da zero o politiche \const{SCHED\_FIFO} e \const{SCHED\_RR}.
\end{table}
Il valore della priorità è passato attraverso la struttura
-\struct{sched\_param} (riportata in \figref{fig:sig_sched_param}), il cui solo
-campo attualmente definito è \var{sched\_priority}, che nel caso delle
+\struct{sched\_param} (riportata in fig.~\ref{fig:sig_sched_param}), il cui
+solo campo attualmente definito è \var{sched\_priority}, che nel caso delle
priorità assolute deve essere specificato nell'intervallo fra un valore
massimo ed uno minimo, che nel caso sono rispettivamente 1 e 99 (il valore
zero è legale, ma indica i processi normali).
\end{prototype}
La funzione restituisce il valore (secondo quanto elencato in
-\tabref{tab:proc_sched_policy}) della politica di scheduling per il processo
+tab.~\ref{tab:proc_sched_policy}) della politica di scheduling per il processo
specificato; se \param{pid} è nullo viene restituito quello del processo
chiamante.
La funzione restituisce il valore dell'intervallo di tempo usato per la
politica \textit{round robin} in una struttura \struct{timespec}, (la cui
-definizione si può trovare in \figref{fig:sys_timeval_struct}).
+definizione si può trovare in fig.~\ref{fig:sys_timeval_struct}).
Come accennato ogni processo che usa lo scheduling real-time può rilasciare
altro processo o dalla ricezione di un segnale; occorre pertanto essere
accorti nei confronti delle possibili
\textit{race condition}\index{race condition} (vedi
-\secref{sec:proc_race_cond}) derivanti da operazioni interrotte in una fase in
-cui non erano ancora state completate.
+sez.~\ref{sec:proc_race_cond}) derivanti da operazioni interrotte in una fase
+in cui non erano ancora state completate.
Nel caso dell'interazione fra processi la situazione è molto più semplice, ed
occorre preoccuparsi della atomicità delle operazioni solo quando si ha a che
fare con meccanismi di intercomunicazione (che esamineremo in dettaglio in
-\capref{cha:IPC}) o nelle operazioni con i file (vedremo alcuni esempi in
-\secref{sec:file_atomic}). In questi casi in genere l'uso delle appropriate
+cap.~\ref{cha:IPC}) o nelle operazioni con i file (vedremo alcuni esempi in
+sez.~\ref{sec:file_atomic}). In questi casi in genere l'uso delle appropriate
funzioni di libreria per compiere le operazioni necessarie è garanzia
sufficiente di atomicità in quanto le system call con cui esse sono realizzate
non possono essere interrotte (o subire interferenze pericolose) da altri
sono compiute nello stesso spazio di indirizzi del processo. Per questo, anche
il solo accesso o l'assegnazione di una variabile possono non essere più
operazioni atomiche (torneremo su questi aspetti in
-\secref{sec:sig_control}).
+sez.~\ref{sec:sig_control}).
In questo caso il sistema provvede un tipo di dato, il \type{sig\_atomic\_t},
il cui accesso è assicurato essere atomico. In pratica comunque si può
codice in cui si compiono le operazioni sulle risorse condivise (le cosiddette
\textsl{sezioni critiche}\index{sezioni critiche}) del programma, siano
opportunamente protette da meccanismi di sincronizzazione (torneremo su queste
-problematiche di questo tipo in \capref{cha:IPC}).
+problematiche di questo tipo in cap.~\ref{cha:IPC}).
Un caso particolare di \textit{race condition}\index{race condition} sono poi
i cosiddetti \textit{deadlock}\index{deadlock}, particolarmente gravi in
diventerà perpetua (da cui il nome di \textit{deadlock}\index{deadlock}).
In tutti questi casi è di fondamentale importanza il concetto di atomicità
-visto in \secref{sec:proc_atom_oper}; questi problemi infatti possono essere
+visto in sez.~\ref{sec:proc_atom_oper}; questi problemi infatti possono essere
risolti soltanto assicurandosi, quando essa sia richiesta, che sia possibile
eseguire in maniera atomica le operazioni necessarie.
\chapter{Terminali e sessioni di lavoro}
\label{cha:session}
-I terminali per lungo tempo tempo sono stati l'unico modo per accedere al
-sistema, per questo anche oggi che esistono molte altre interfacce, essi
-continuano a coprire un ruolo particolare, restando strettamente legati al
-funzionamento dell'interfaccia a linea di comando.
+I terminali per lungo tempo sono stati l'unico modo per accedere al sistema,
+per questo anche oggi che esistono molte altre interfacce, essi continuano a
+coprire un ruolo particolare, restando strettamente legati al funzionamento
+dell'interfaccia a linea di comando.
Nella prima parte del capitolo esamineremo i concetti base del sistema delle
sessioni di lavoro, vale a dire il metodo con cui il kernel permette ad un
supporto sia da parte della shell (quasi tutte ormai lo fanno), che da parte
del kernel; in particolare il kernel deve assicurare sia la presenza di un
driver per i terminali abilitato al \textit{job control} che quella dei
-relativi segnali illustrati in \secref{sec:sig_job_control}.
+relativi segnali illustrati in sez.~\ref{sec:sig_job_control}.
In un sistema che supporta il \textit{job control}, una volta completato il
login, l'utente avrà a disposizione una shell dalla quale eseguire i comandi e
potrà iniziare quella che viene chiamata una \textsl{sessione}, che riunisce
-(vedi \secref{sec:sess_proc_group}) tutti i processi eseguiti all'interno
+(vedi sez.~\ref{sec:sess_proc_group}) tutti i processi eseguiti all'interno
dello stesso login (esamineremo tutto il processo in dettaglio in
-\secref{sec:sess_login}).
+sez.~\ref{sec:sess_login}).
Siccome la shell è collegata ad un solo terminale, che viene usualmente
-chiamato \textsl{terminale di controllo}, (vedi \secref{sec:sess_ctrl_term})
+chiamato \textsl{terminale di controllo}, (vedi sez.~\ref{sec:sess_ctrl_term})
un solo comando alla volta (quello che viene detto in \textit{foreground}),
potrà scrivere e leggere dal terminale. La shell però può eseguire anche più
comandi in contemporanea, mandandoli in \textit{background} (aggiungendo una
nella gestione del job control non si può far riferimento ai singoli processi.
Per questo il kernel prevede la possibilità di raggruppare più processi in un
\textit{process group} (detto anche \textsl{raggruppamento di processi}, vedi
-\secref{sec:sess_proc_group}) e la shell farà sì che tutti i processi che
+sez.~\ref{sec:sess_proc_group}) e la shell farà sì che tutti i processi che
originano da una riga di comando appartengano allo stesso raggruppamento, in
modo che le varie funzioni di controllo, ed i segnali inviati dal terminale,
possano fare riferimento ad esso.
\textit{background}, che non possono accedervi. Il job control prevede che
quando un processo appartenente ad un raggruppamento in \textit{background}
cerca di accedere al terminale, venga inviato un segnale a tutti i processi
-del raggruppamento, in modo da bloccarli (vedi \secref{sec:sess_ctrl_term}).
+del raggruppamento, in modo da bloccarli (vedi sez.~\ref{sec:sess_ctrl_term}).
Un comportamento analogo si ha anche per i segnali generati dai comandi di
tastiera inviati dal terminale che vengono inviati a tutti i processi del
in grado, grazie all'uso di \func{waitpid}, di rilevare sia i processi che
sono terminati, sia i raggruppamenti che sono bloccati (in questo caso usando
l'opzione \const{WUNTRACED}, secondo quanto illustrato in
-\secref{sec:proc_wait}).
+sez.~\ref{sec:proc_wait}).
\subsection{I \textit{process group} e le \textsl{sessioni}}
\label{sec:sess_proc_group}
-Come accennato in \secref{sec:sess_job_control_overview} nel job control i
+Come accennato in sez.~\ref{sec:sess_job_control_overview} nel job control i
processi vengono raggruppati in \textit{process group} e \textit{sessioni};
per far questo vengono utilizzati due ulteriori identificatori (oltre quelli
-visti in \secref{sec:proc_pid}) che il kernel associa a ciascun
+visti in sez.~\ref{sec:proc_pid}) che il kernel associa a ciascun
processo:\footnote{in Linux questi identificatori sono mantenuti nei campi
\var{pgrp} e \var{session} della struttura \struct{task\_struct} definita in
\file{sched.h}.} l'identificatore del \textit{process group} e
è mantenuta in maniera indipendente con un apposito campo \var{leader} in
\struct{task\_struct}.} se il suo \acr{sid} è uguale al suo \acr{pid}) ed
unico componente. Inoltre la funzione distacca il processo da ogni terminale
-di controllo (torneremo sull'argomento in \secref{sec:sess_ctrl_term}) cui
+di controllo (torneremo sull'argomento in sez.~\ref{sec:sess_ctrl_term}) cui
fosse in precedenza associato.
La funzione ha successo soltanto se il processo non è già leader di un
avendo questo lo stesso \acr{pgid} del padre ma un \acr{pid} diverso, non ci
siano possibilità di errore.\footnote{potrebbe sorgere il dubbio che, per il
riutilizzo dei valori dei \acr{pid} fatto nella creazione dei nuovi processi
- (vedi \secref{sec:proc_pid}), il figlio venga ad assumere un valore
+ (vedi sez.~\ref{sec:proc_pid}), il figlio venga ad assumere un valore
corrispondente ad un process group esistente; questo viene evitato dal
kernel che considera come disponibili per un nuovo \acr{pid} solo valori che
non corrispondono ad altri \acr{pid}, \acr{pgid} o \acr{sid} in uso nel
sistema.} Questa funzione viene usata di solito nel processo di login (per i
-dettagli vedi \secref{sec:sess_login}) per raggruppare in una sessione tutti i
-comandi eseguiti da un utente dalla sua shell.
+dettagli vedi sez.~\ref{sec:sess_login}) per raggruppare in una sessione tutti
+i comandi eseguiti da un utente dalla sua shell.
\subsection{Il terminale di controllo e il controllo di sessione}
\label{sec:sess_ctrl_term}
-Come accennato in \secref{sec:sess_job_control_overview}, nel sistema del
+Come accennato in sez.~\ref{sec:sess_job_control_overview}, nel sistema del
\textit{job control} i processi all'interno di una sessione fanno riferimento
ad un terminale di controllo (ad esempio quello su cui si è effettuato il
login), sul quale effettuano le operazioni di lettura e
l'implementazione; in Linux anch'esso viene mantenuto nella solita struttura
\struct{task\_struct}, nel campo \var{tty}.} In generale ogni processo
eredita dal padre, insieme al \acr{pgid} e al \acr{sid} anche il terminale di
-controllo (vedi \secref{sec:proc_fork}). In questo modo tutti processi
+controllo (vedi sez.~\ref{sec:proc_fork}). In questo modo tutti processi
originati dallo stesso leader di sessione mantengono lo stesso terminale di
controllo.
Alla creazione di una nuova sessione con \func{setsid} ogni associazione con
il precedente terminale di controllo viene cancellata, ed il processo che è
divenuto un nuovo leader di sessione dovrà riottenere\footnote{solo quando ciò
- è necessario, cosa che, come vedremo in \secref{sec:sess_daemon}, non è
+ è necessario, cosa che, come vedremo in sez.~\ref{sec:sess_daemon}, non è
sempre vera.}, un terminale di controllo. In generale questo viene fatto
automaticamente dal sistema\footnote{a meno di non avere richiesto
esplicitamente che questo non diventi un terminale di controllo con il flag
- \const{O\_NOCTTY} (vedi \secref{sec:file_open}). In questo Linux segue la
+ \const{O\_NOCTTY} (vedi sez.~\ref{sec:file_open}). In questo Linux segue la
semantica di SVr4; BSD invece richiede che il terminale venga allocato
esplicitamente con una \func{ioctl} con il comando \const{TIOCSCTTY}.}
quando viene aperto il primo terminale (cioè uno dei vari file di dispositivo
\noindent la funzione può essere eseguita con successo solo da
un processo nella stessa sessione e con lo stesso terminale di controllo.
-Come accennato in \secref{sec:sess_job_control_overview}, tutti i processi (e
+Come accennato in sez.~\ref{sec:sess_job_control_overview}, tutti i processi (e
relativi raggruppamenti) che non fanno parte del gruppo di \textit{foreground}
sono detti in \textit{background}; se uno si essi cerca di accedere al
terminale di controllo provocherà l'invio da parte del kernel di uno dei due
segnali \const{SIGTTIN} o \const{SIGTTOU} (a seconda che l'accesso sia stato
in lettura o scrittura) a tutto il suo \textit{process group}; dato che il
comportamento di default di questi segnali (si riveda quanto esposto in
-\secref{sec:sig_job_control}) è di fermare il processo, di norma questo
+sez.~\ref{sec:sig_job_control}) è di fermare il processo, di norma questo
comporta che tutti i membri del gruppo verranno fermati, ma non si avranno
condizioni di errore.\footnote{la shell in genere notifica comunque un
avvertimento, avvertendo la presenza di processi bloccati grazie all'uso di
utilizzando su di esso le combinazioni di tasti speciali (\cmd{C-z},
\cmd{C-c}, \cmd{C-y} e \verb|C-\|) si farà sì che il kernel invii i
corrispondenti segnali (rispettivamente \const{SIGTSTP}, \const{SIGINT},
-\const{SIGQUIT} e \const{SIGTERM}, trattati in \secref{sec:sig_job_control}) a
-tutti i processi del raggruppamento di \textit{foreground}; in questo modo la
-shell può gestire il blocco e l'interruzione dei vari comandi.
+\const{SIGQUIT} e \const{SIGTERM}, trattati in sez.~\ref{sec:sig_job_control})
+a tutti i processi del raggruppamento di \textit{foreground}; in questo modo
+la shell può gestire il blocco e l'interruzione dei vari comandi.
Per completare la trattazione delle caratteristiche del job control legate al
terminale di controllo, occorre prendere in considerazione i vari casi legati
solo i raggruppamenti che diventano orfani in seguito alla terminazione di un
processo.\footnote{l'emissione dei segnali infatti avviene solo nella fase di
uscita del processo, come una delle operazioni legate all'esecuzione di
- \func{\_exit}, secondo quanto illustrato in \secref{sec:proc_termination}.}
+ \func{\_exit}, secondo quanto illustrato in sez.~\ref{sec:proc_termination}.}
Il leader di sessione provvederà a creare nuovi raggruppamenti che a questo
punto non sono orfani in quanto esso resta padre per almeno uno dei processi
del gruppo (gli altri possono derivare dal primo). Alla terminazione del
leader di sessione però avremo che, come visto in
-\secref{sec:proc_termination}, tutti i suoi figli vengono adottati da
+sez.~\ref{sec:proc_termination}, tutti i suoi figli vengono adottati da
\cmd{init}, che è fuori dalla sessione. Questo renderà orfani tutti i process
group creati direttamente dal leader di sessione (a meno di non aver spostato
con \func{setpgid} un processo da un gruppo ad un altro, cosa che di norma non
connessione di rete. Dato che i concetti base sono gli stessi, e dato che alla
fine le differenze sono\footnote{in generale nel caso di login via rete o di
terminali lanciati dall'interfaccia grafica cambia anche il processo da cui
- ha origine l'esecuzione della shell.} nel dispositivo cui il kernel associa i
-file standard (vedi \secref{sec:file_std_descr}) per l'I/O, tratteremo solo il
-caso classico del terminale.
+ ha origine l'esecuzione della shell.} nel dispositivo cui il kernel associa
+i file standard (vedi sez.~\ref{sec:file_std_descr}) per l'I/O, tratteremo
+solo il caso classico del terminale.
-Abbiamo già brevemente illustrato in \secref{sec:intro_kern_and_sys} le
+Abbiamo già brevemente illustrato in sez.~\ref{sec:intro_kern_and_sys} le
modalità con cui il sistema si avvia, e di come, a partire da \cmd{init},
vengano lanciati tutti gli altri processi. Adesso vedremo in maniera più
dettagliata le modalità con cui il sistema arriva a fornire ad un utente la
rimanda alla lettura delle pagine di manuale di \cmd{init} e di
\file{inittab}) quello che comunque viene sempre fatto è di eseguire almeno
una istanza di un programma che permetta l'accesso ad un terminale. Uno schema
-di massima della procedura è riportato in \figref{fig:sess_term_login}.
+di massima della procedura è riportato in fig.~\ref{fig:sess_term_login}.
\begin{figure}[htb]
\centering
Un terminale, che esso sia un terminale effettivo, attaccato ad una seriale o
ad un altro tipo di porta di comunicazione, o una delle console virtuali
-associate allo schermo, viene sempre visto attraverso attraverso un device
-driver che ne presenta un'interfaccia comune su un apposito file di
-dispositivo.
+associate allo schermo, viene sempre visto attraverso un device driver che ne
+presenta un'interfaccia comune su un apposito file di dispositivo.
Per controllare un terminale si usa di solito il programma \cmd{getty} (od una
delle sue varianti), che permette di mettersi in ascolto su uno di questi
A sua volta \cmd{login}, che mantiene i privilegi di amministratore, usa il
nome dell'utente per effettuare una ricerca nel database degli
utenti,\footnote{in genere viene chiamata \func{getpwnam}, che abbiamo visto
- in \secref{sec:sys_user_group}, per leggere la password e gli altri dati dal
- database degli utenti.} e richiede una password. Se l'utente non esiste o se
-la password non corrisponde\footnote{il confronto non viene effettuato con un
- valore in chiaro; quanto immesso da terminale viene invece a sua volta
- criptato, ed è il risultato che viene confrontato con il valore che viene
- mantenuto nel database degli utenti.} la richiesta viene ripetuta un certo
-numero di volte dopo di che \cmd{login} esce ed \cmd{init} provvede a
+ in sez.~\ref{sec:sys_user_group}, per leggere la password e gli altri dati
+ dal database degli utenti.} e richiede una password. Se l'utente non esiste
+o se la password non corrisponde\footnote{il confronto non viene effettuato
+ con un valore in chiaro; quanto immesso da terminale viene invece a sua
+ volta criptato, ed è il risultato che viene confrontato con il valore che
+ viene mantenuto nel database degli utenti.} la richiesta viene ripetuta un
+certo numero di volte dopo di che \cmd{login} esce ed \cmd{init} provvede a
rilanciare un'altra istanza di \func{getty}.
Se invece la password corrisponde \cmd{login} esegue \func{chdir} per settare
valori per le variabili di ambiente, come \texttt{HOME}, \texttt{SHELL}, ecc.
Infine attraverso l'uso di \func{setuid}, \func{setpid} e \func{initgroups}
verrà cambiata l'identità del proprietario del processo, infatti, come
-spiegato in \secref{sec:proc_setuid}, avendo invocato tali funzioni con i
+spiegato in sez.~\ref{sec:proc_setuid}, avendo invocato tali funzioni con i
privilegi di amministratore, tutti gli user-ID ed i group-ID (reali, effettivi
e salvati) saranno settati a quelli dell'utente.
A questo punto \cmd{login} provvederà (fatte salve eventuali altre azioni
iniziali, come la stampa di messaggi di benvenuto o il controllo della posta)
ad eseguire con un'altra \func{exec} la shell, che si troverà con un ambiente
-già pronto con i file standard di \secref{sec:file_std_descr} impostati sul
+già pronto con i file standard di sez.~\ref{sec:file_std_descr} impostati sul
terminale, e pronta, nel ruolo di leader di sessione e di processo di
controllo per il terminale, a gestire l'esecuzione dei comandi come illustrato
-in \secref{sec:sess_job_control_overview}.
+in sez.~\ref{sec:sess_job_control_overview}.
Dato che il processo padre resta sempre \cmd{init} quest'ultimo potrà
provvedere, ricevendo un \const{SIGCHLD} all'uscita della shell quando la
\subsection{Prescrizioni per un programma \textit{daemon}}
\label{sec:sess_daemon}
-Come sottolineato fin da \secref{sec:intro_base_concept}, in un sistema
+Come sottolineato fin da sez.~\ref{sec:intro_base_concept}, in un sistema
unix-like tutte le operazioni sono eseguite tramite processi, comprese quelle
operazioni di sistema (come l'esecuzione dei comandi periodici, o la consegna
della posta, ed in generale tutti i programmi di servizio) che non hanno
un terminale di controllo e mantenuto all'interno di una sessione, e anche se
può essere mandato in background e non eseguire più nessun I/O su terminale,
si avranno comunque tutte le conseguenze che abbiamo appena visto in
-\secref{sec:sess_ctrl_term} (in particolare l'invio dei segnali in
+sez.~\ref{sec:sess_ctrl_term} (in particolare l'invio dei segnali in
corrispondenza dell'uscita del leader di sessione).
Per questo motivo un programma che deve funzionare come demone deve sempre
problema di come fare per la notifica di eventuali errori, non potendosi più
utilizzare lo standard error; per il normale I/O infatti ciascun demone avrà
le sue modalità di interazione col sistema e gli utenti a seconda dei compiti
-e delle funzionalità che sono sono previste; ma gli errori devono normalmente
+e delle funzionalità che sono previste; ma gli errori devono normalmente
essere notificati all'amministratore del sistema.
Una soluzione può essere quella di scrivere gli eventuali messaggi su uno
in un sistema unix-like, viene gestito attraverso un apposito programma,
\cmd{syslogd}, che è anch'esso un \textsl{demone}. In generale i messaggi di
errore vengono raccolti dal file speciale \file{/dev/log}, un
-\textit{socket}\index{socket} locale (vedi \secref{sec:sock_sa_local})
+\textit{socket}\index{socket} locale (vedi sez.~\ref{sec:sock_sa_local})
dedicato a questo scopo, o via rete, con un \textit{socket} UDP, o da un
apposito demone, \cmd{klogd}, che estrae i messaggi del kernel.\footnote{i
messaggi del kernel sono tenuti in un buffer circolare e scritti tramite la
L'argomento è interpretato come una maschera binaria, e pertanto è possibile
inviare i messaggi su più categorie alla volta; i valori delle costanti che
identificano ciascuna categoria sono riportati in
-\tabref{tab:sess_syslog_facility}, il valore di \param{facility} deve essere
+tab.~\ref{tab:sess_syslog_facility}, il valore di \param{facility} deve essere
specificato con un OR aritmetico.
\begin{table}[htb]
funzione \func{openlog} e delle modalità con cui le successive chiamate
scriveranno i messaggi, esso viene specificato come maschera binaria composta
con un OR aritmetico di una qualunque delle costanti riportate in
-\tabref{tab:sess_openlog_option}.
+tab.~\ref{tab:sess_openlog_option}.
\begin{table}[htb]
\footnotesize
Il comportamento della funzione è analogo quello di \func{printf}, e il valore
dell'argomento \param{format} è identico a quello descritto nella pagina di
manuale di quest'ultima (per i valori principali si può vedere la trattazione
-sommaria che se ne è fatto in \secref{sec:file_formatted_io}); l'unica
+sommaria che se ne è fatto in sez.~\ref{sec:file_formatted_io}); l'unica
differenza è che la sequenza \val{\%m} viene rimpiazzata dalla stringa
restituita da \code{strerror(errno)}. Gli argomenti seguenti i primi due
devono essere forniti secondo quanto richiesto da \param{format}.
\param{priority} sono occupati da questo valore, mentre i restanti bit più
significativi vengono usati per specificare la \textit{facility}.}
specificabile attraverso le costanti riportate in
-\secref{tab:sess_syslog_priority}. Nel caso si voglia specificare anche la
+tab.~\ref{tab:sess_syslog_priority}. Nel caso si voglia specificare anche la
\textit{facility} basta eseguire un OR aritmetico del valore della priorità
-con la maschera binaria delle costanti di \tabref{tab:sess_syslog_facility}.
+con la maschera binaria delle costanti di tab.~\ref{tab:sess_syslog_facility}.
\begin{table}[htb]
\footnotesize
registrata. La registrazione viene disabilitata per tutte quelle priorità che
non rientrano nella maschera; questa viene settata usando la macro
\macro{LOG\_MASK(p)} dove \code{p} è una delle costanti di
-\secref{tab:sess_syslog_priority}. É inoltre disponibile anche la macro
+tab.~\ref{tab:sess_syslog_priority}. É inoltre disponibile anche la macro
\macro{LOG\_UPTO(p)} che permette di specificare automaticamente tutte le
priorità fino ad un certo valore.
\label{sec:term_design}
I terminali sono una classe speciale di dispositivi a caratteri (si ricordi la
-classificazione di \secref{sec:file_file_types}); un terminale ha infatti una
+classificazione di sez.~\ref{sec:file_file_types}); un terminale ha infatti una
caratteristica che lo contraddistingue da un qualunque altro dispositivo, e
cioè che è destinato a gestire l'interazione con un utente (deve essere cioè
in grado di fare da terminale di controllo per una sessione), che comporta la
fintanto che non si preme il tasto di ritorno a capo: a questo punto la
linea sarà completa e la funzione ritornerà.} ed in cui alcuni caratteri
vengono interpretati per compiere operazioni (come la generazione dei segnali
-illustrati in \secref{sec:sig_job_control}), questa di norma è la modalità in
+illustrati in sez.~\ref{sec:sig_job_control}), questa di norma è la modalità in
cui funziona la shell.
Un terminale in modo non canonico invece non effettua nessun accorpamento dei
Per capire le caratteristiche dell'I/O sui terminali, occorre esaminare le
modalità con cui esso viene effettuato; l'accesso, come per tutti i
dispositivi, viene gestito da un driver apposito, la cui struttura generica è
-mostrata in \secref{fig:term_struct}. Ad un terminale sono sempre associate
+mostrata in fig.~\ref{fig:term_struct}. Ad un terminale sono sempre associate
due code per gestire l'input e l'output, che ne implementano una
bufferizzazione\footnote{completamente indipendente dalla eventuale ulteriore
bufferizzazione fornita dall'interfaccia standard dei file.} all'interno del
La coda di ingresso mantiene i caratteri che sono stati letti dal terminale ma
non ancora letti da un processo, la sua dimensione è definita dal parametro di
-sistema \const{MAX\_INPUT} (si veda \secref{sec:sys_file_limits}), che ne
+sistema \const{MAX\_INPUT} (si veda sez.~\ref{sec:sys_file_limits}), che ne
specifica il limite minimo, in realtà la coda può essere più grande e cambiare
dimensione dinamicamente. Se è stato abilitato il controllo di flusso in
ingresso il driver emette i caratteri di STOP e START per bloccare e sbloccare
\param{s}. La memoria per contenere la stringa deve essere stata allocata in
precedenza ed essere lunga almeno
\const{L\_ctermid}\footnote{\const{L\_ctermid} è una delle varie costanti del
- sistema, non trattata esplicitamente in \secref{sec:sys_characteristics} che
- indica la dimensione che deve avere una stringa per poter contenere il nome
- di un terminale.} caratteri.
+ sistema, non trattata esplicitamente in sez.~\ref{sec:sys_characteristics}
+ che indica la dimensione che deve avere una stringa per poter contenere il
+ nome di un terminale.} caratteri.
Esiste infine una versione rientrante \funcd{ttyname\_r} della funzione
\func{ttyname}, che non presenta il problema dell'uso di una zona di memoria
I vari attributi vengono mantenuti per ciascun terminale in una struttura
\struct{termios}, (la cui definizione è riportata in
-\figref{fig:term_termios}), usata dalle varie funzioni dell'interfaccia. In
-\figref{fig:term_termios} si sono riportati tutti i campi della definizione
+fig.~\ref{fig:term_termios}), usata dalle varie funzioni dell'interfaccia. In
+fig.~\ref{fig:term_termios} si sono riportati tutti i campi della definizione
usata in Linux; di questi solo i primi cinque sono previsti dallo standard
POSIX.1, ma le varie implementazioni ne aggiungono degli altri per mantenere
ulteriori informazioni.\footnote{la definizione della struttura si trova in
terminale, come il controllo di parità, il controllo di flusso, la gestione
dei caratteri speciali; un elenco dei vari bit, del loro significato e delle
costanti utilizzate per identificarli è riportato in
-\tabref{tab:sess_termios_iflag}.
+tab.~\ref{tab:sess_termios_iflag}.
Si noti come alcuni di questi flag (come quelli per la gestione del flusso)
fanno riferimento a delle caratteristiche che ormai sono completamente
come l'impacchettamento dei caratteri sullo schermo, la traslazione degli a
capo, la conversione dei caratteri speciali; un elenco dei vari bit, del loro
significato e delle costanti utilizzate per identificarli è riportato in
-\tabref{tab:sess_termios_oflag}.
+tab.~\ref{tab:sess_termios_oflag}.
-Si noti come alcuni dei valori riportati in \tabref{tab:sess_termios_oflag}
+Si noti come alcuni dei valori riportati in tab.~\ref{tab:sess_termios_oflag}
fanno riferimento a delle maschere di bit; essi infatti vengono utilizzati per
impostare alcuni valori numerici relativi ai ritardi nell'output di alcuni
caratteri: una caratteristica originaria dei primi terminali su telescrivente,
\const{PARENB} & Se impostato abilita la generazione il controllo di
parità. La reazione in caso di errori dipende dai
relativi valori per \var{c\_iflag}, riportati in
- \tabref{tab:sess_termios_iflag}. Se non è impostato i bit
- di parità non vengono
+ tab.~\ref{tab:sess_termios_iflag}. Se non è impostato i
+ bit di parità non vengono
generati e i caratteri non vengono controllati.\\
\const{PARODD} & Ha senso solo se è attivo anche \const{PARENB}. Se
impostato viene usata una parità è dispari, altrimenti
della parità, il funzionamento del controllo di flusso; esso ha senso solo per
i terminali connessi a linee seriali. Un elenco dei vari bit, del loro
significato e delle costanti utilizzate per identificarli è riportato in
-\tabref{tab:sess_termios_cflag}.
+tab.~\ref{tab:sess_termios_cflag}.
I valori di questo flag sono molto specifici, e completamente indirizzati al
controllo di un terminale mantenuto su una linea seriale; essi pertanto non
seriali all'interno dei flag; come accennato in Linux questo viene fatto
(seguendo l'esempio di BSD) attraverso due campi aggiuntivi, \var{c\_ispeed} e
\var{c\_ospeed}, nella struttura \struct{termios} (mostrati in
-\figref{fig:term_termios}).
+fig.~\ref{fig:term_termios}).
\begin{table}[b!ht]
\footnotesize
driver e l'utente, come abilitare l'eco, gestire i caratteri di controllo e
l'emissione dei segnali, impostare modo canonico o non canonico; un elenco dei
vari bit, del loro significato e delle costanti utilizzate per identificarli è
-riportato in \tabref{tab:sess_termios_lflag}. Con i terminali odierni l'unico
+riportato in tab.~\ref{tab:sess_termios_lflag}. Con i terminali odierni l'unico
flag con cui probabilmente si può avere a che fare è questo, in quanto è con
questo che si impostano le caratteristiche generiche comuni a tutti i
terminali.
vettore, i vari elementi vengono indicizzati attraverso delle opportune
costanti, il cui nome corrisponde all'azione ad essi associata. Un elenco
completo dei caratteri di controllo, con le costanti e delle funzionalità
-associate è riportato in \tabref{tab:sess_termios_cc}, usando quelle
+associate è riportato in tab.~\ref{tab:sess_termios_cc}, usando quelle
definizioni diventa possibile assegnare un nuovo carattere di controllo con un
codice del tipo:
\includecodesnip{listati/value_c_cc.c}
La maggior parte di questi caratteri (tutti tranne \const{VTIME} e
\const{VMIN}) hanno effetto solo quando il terminale viene utilizzato in modo
-canonico; per alcuni devono essere essere soddisfatte ulteriori richieste, ad
-esempio \const{VINTR}, \const{VSUSP}, e \const{VQUIT} richiedono sia settato
+canonico; per alcuni devono essere soddisfatte ulteriori richieste, ad esempio
+\const{VINTR}, \const{VSUSP}, e \const{VQUIT} richiedono sia settato
\const{ISIG}; \const{VSTART} e \const{VSTOP} richiedono sia settato
\const{IXON}; \const{VLNEXT}, \const{VWERASE}, \const{VREPRINT} richiedono sia
settato \const{IEXTEN}. In ogni caso quando vengono attivati i caratteri
specificabili attraverso l'argomento \param{optional\_actions}, che permette
di stabilire come viene eseguito il cambiamento delle impostazioni del
terminale, i valori possibili sono riportati in
-\tabref{tab:sess_tcsetattr_option}; di norma (come fatto per le due funzioni
+tab.~\ref{tab:sess_tcsetattr_option}; di norma (come fatto per le due funzioni
di esempio) si usa sempre \const{TCSANOW}, le altre opzioni possono essere
utili qualora si cambino i parametri di output.
valore corrente delle impostazioni con \func{tcgetattr} per poi modificare i
valori impostati.
-In \figref{fig:term_set_attr} e \figref{fig:term_unset_attr} si è riportato
+In fig.~\ref{fig:term_set_attr} e fig.~\ref{fig:term_unset_attr} si è riportato
rispettivamente il codice delle due funzioni \func{SetTermAttr} e
\func{UnSetTermAttr}, che possono essere usate per impostare o rimuovere, con
le dovute precauzioni, un qualunque bit di \var{c\_lflag}. Il codice di
\subsection{La gestione della disciplina di linea.}
\label{sec:term_line_discipline}
-Come illustrato dalla struttura riportata in \figref{fig:term_struct} tutti i
-terminali hanno un insieme di funzionalità comuni, che prevedono la presenza
+Come illustrato dalla struttura riportata in fig.~\ref{fig:term_struct} tutti
+i terminali hanno un insieme di funzionalità comuni, che prevedono la presenza
di code di ingresso ed uscita; in generale si fa riferimento ad esse con il
-nome di \textsl{discipline di linea}.
+nome di \textsl{discipline di linea}.
Lo standard POSIX prevede alcune funzioni che permettono di intervenire
vengono considerate, dal punto di vista dell'accesso al terminale, come delle
funzioni di scrittura, pertanto se usate da processi in background sul loro
terminale di controllo provocano l'emissione di \const{SIGTTOU} come
-illustrato in \secref{sec:sess_ctrl_term}.\footnote{con la stessa eccezione,
+illustrato in sez.~\ref{sec:sess_ctrl_term}.\footnote{con la stessa eccezione,
già vista per \func{tcsetaddr}, che quest'ultimo sia bloccato o ignorato dal
processo chiamante.}
La funzione agisce sul terminale associato a \param{fd}, l'argomento
\param{queue} permette di specificare su quale coda (ingresso, uscita o
entrambe), operare. Esso può prendere i valori riportati in
-\tabref{tab:sess_tcflush_queue}, nel caso si specifichi la coda di ingresso
+tab.~\ref{tab:sess_tcflush_queue}, nel caso si specifichi la coda di ingresso
cancellerà i dati ricevuti ma non ancora letti, nel caso si specifichi la coda
di uscita cancellerà i dati scritti ma non ancora trasmessi.
flusso dei dati fra il terminale ed il sistema sia in ingresso che in uscita.
Il comportamento della funzione è regolato dall'argomento \param{action}, i
cui possibili valori, e relativa azione eseguita dalla funzione, sono
-riportati in \secref{tab:sess_tcflow_action}.
+riportati in tab.~\ref{tab:sess_tcflow_action}.
\begin{table}[htb]
\footnotesize
\func{read} quando è stata letta una determinata quantità di dati o è passato
un certo tempo.
-Come accennato nella relativa spiegazione in \tabref{tab:sess_termios_cc},
+Come accennato nella relativa spiegazione in tab.~\ref{tab:sess_termios_cc},
TIME e MIN non sono in realtà caratteri ma valori numerici. Il comportamento
del sistema per un terminale in modalità non canonica prevede quattro casi
distinti:
In questo caso è possibile una situazione in cui i segnali possono essere
perduti. Si consideri il segmento di codice riportato in
-\secref{fig:sig_old_handler}, nel programma principale viene installato un
+fig.~\ref{fig:sig_old_handler}, nel programma principale viene installato un
gestore (\texttt{\small 5}), ed in quest'ultimo la prima operazione
(\texttt{\small 11}) è quella di reinstallare se stesso. Se nell'esecuzione
del gestore un secondo segnale arriva prima che esso abbia potuto eseguire la
semantica viene chiamata \textsl{inaffidabile}; infatti la ricezione del
segnale e la reinstallazione del suo gestore non sono operazioni
atomiche, e sono sempre possibili delle race condition\index{race condition}
-(sull'argomento vedi quanto detto in \secref{sec:proc_multi_prog}).
+(sull'argomento vedi quanto detto in sez.~\ref{sec:proc_multi_prog}).
Un'altro problema è che in questa semantica non esiste un modo per bloccare i
segnali quando non si vuole che arrivino; i processi possono ignorare il
\textsl{generati} dal kernel per un processo all'occorrenza dell'evento che
causa il segnale. In genere questo viene fatto dal kernel impostando l'apposito
campo della \struct{task\_struct} del processo nella process table (si veda
-\figref{fig:proc_task_struct}).
+fig.~\ref{fig:proc_task_struct}).
Si dice che il segnale viene \textsl{consegnato} al processo (dall'inglese
\textit{delivered}) quando viene eseguita l'azione per esso prevista, mentre
Si tenga presente che il kernel stabilisce cosa fare con un segnale che è
stato bloccato al momento della consegna, non quando viene generato; questo
consente di cambiare l'azione per il segnale prima che esso venga consegnato,
-e si può usare la funzione \func{sigpending} (vedi \secref{sec:sig_sigmask})
+e si può usare la funzione \func{sigpending} (vedi sez.~\ref{sec:sig_sigmask})
per determinare quali segnali sono bloccati e quali sono pendenti.
\end{itemize*}
Un programma può specificare queste scelte usando le due funzioni
-\func{signal} e \func{sigaction} (vedi \secref{sec:sig_signal} e
-\secref{sec:sig_sigaction}). Se si è installato un gestore sarà
+\func{signal} e \func{sigaction} (vedi sez.~\ref{sec:sig_signal} e
+sez.~\ref{sec:sig_sigaction}). Se si è installato un gestore sarà
quest'ultimo ad essere eseguito alla notifica del segnale. Inoltre il sistema
farà si che mentre viene eseguito il gestore di un segnale, quest'ultimo
venga automaticamente bloccato (così si possono evitare race
condition\index{race condition}).
Nel caso non sia stata specificata un'azione, viene utilizzata l'azione
-standard che (come vedremo in \secref{sec:sig_standard}) è propria di ciascun
+standard che (come vedremo in sez.~\ref{sec:sig_standard}) è propria di ciascun
segnale; nella maggior parte dei casi essa porta alla terminazione del
processo, ma alcuni segnali che rappresentano eventi innocui vengono ignorati.
Quando un segnale termina un processo, il padre può determinare la causa della
terminazione esaminando il codice di stato riportato delle funzioni
-\func{wait} e \func{waitpid} (vedi \secref{sec:proc_wait}); questo è il modo
+\func{wait} e \func{waitpid} (vedi sez.~\ref{sec:proc_wait}); questo è il modo
in cui la shell determina i motivi della terminazione di un programma e scrive
un eventuale messaggio di errore.
Il numero totale di segnali presenti è dato dalla macro \const{NSIG}, e dato
che i numeri dei segnali sono allocati progressivamente, essa corrisponde
anche al successivo del valore numerico assegnato all'ultimo segnale definito.
-In \tabref{tab:sig_signal_list} si è riportato l'elenco completo dei segnali
+In tab.~\ref{tab:sig_signal_list} si è riportato l'elenco completo dei segnali
definiti in Linux (estratto dalle pagine di manuale), comparati con quelli
definiti in vari standard.
\hline
\end{tabular}
\caption{Legenda delle azioni predefinite dei segnali riportate in
- \tabref{tab:sig_signal_list}.}
+ tab.~\ref{tab:sig_signal_list}.}
\label{tab:sig_action_leg}
\end{table}
-In \tabref{tab:sig_signal_list} si sono anche riportate le azioni predefinite
+In tab.~\ref{tab:sig_signal_list} si sono anche riportate le azioni predefinite
di ciascun segnale (riassunte con delle lettere, la cui legenda completa è in
-\tabref{tab:sig_action_leg}), quando nessun gestore è installato un
+tab.~\ref{tab:sig_action_leg}), quando nessun gestore è installato un
segnale può essere ignorato o causare la terminazione del processo. Nella
colonna standard sono stati indicati anche gli standard in cui ciascun segnale
-è definito, secondo lo schema di \tabref{tab:sig_standard_leg}.
+è definito, secondo lo schema di tab.~\ref{tab:sig_standard_leg}.
\begin{table}[htb]
\hline
\end{tabular}
\caption{Legenda dei valori della colonna \textbf{Standard} di
- \tabref{tab:sig_signal_list}.}
+ tab.~\ref{tab:sig_signal_list}.}
\label{tab:sig_standard_leg}
\end{table}
avuto successo.
\item[\const{SIGURG}] Questo segnale è inviato quando arrivano dei dati
urgenti o \textit{out-of-band} su di un socket\index{socket}; per maggiori
- dettagli al proposito si veda \secref{sec:TCP_urgent_data}.
+ dettagli al proposito si veda sez.~\ref{sec:TCP_urgent_data}.
\item[\const{SIGPOLL}] Questo segnale è equivalente a \const{SIGIO}, è
definito solo per compatibilità con i sistemi System V.
\end{basedescript}
\begin{basedescript}{\desclabelwidth{2.0cm}}
\item[\const{SIGCHLD}] Questo è il segnale mandato al processo padre quando un
figlio termina o viene fermato. L'azione predefinita è di ignorare il
- segnale, la sua gestione è trattata in \secref{sec:proc_wait}.
+ segnale, la sua gestione è trattata in sez.~\ref{sec:proc_wait}.
\item[\const{SIGCLD}] Per Linux questo è solo un segnale identico al
precedente, il nome è obsoleto e andrebbe evitato.
\item[\const{SIGCONT}] Il nome sta per \textit{continue}. Il segnale viene
se viene fermato e riavviato, come per esempio riscrivere un prompt, o
inviare un avviso.
\item[\const{SIGSTOP}] Il segnale ferma un processo (lo porta cioè in uno
- stato di sleep, vedi \secref{sec:proc_sched}); il segnale non può essere né
+ stato di sleep, vedi sez.~\ref{sec:proc_sched}); il segnale non può essere né
intercettato, né ignorato, né bloccato.
\item[\const{SIGTSTP}] Il nome sta per \textit{interactive stop}. Il segnale
ferma il processo interattivamente, ed è generato dal carattere SUSP
sessione di lavoro in \textit{background}. Quando un processo in background
tenta di leggere da un terminale viene inviato questo segnale a tutti i
processi della sessione di lavoro. L'azione predefinita è di fermare il
- processo. L'argomento è trattato in \secref{sec:sess_job_control_overview}.
+ processo. L'argomento è trattato in
+ sez.~\ref{sec:sess_job_control_overview}.
\item[\const{SIGTTOU}] Segnale analogo al precedente \const{SIGTTIN}, ma
generato quando si tenta di scrivere o modificare uno dei modi del
terminale. L'azione predefinita è di fermare il processo, l'argomento è
- trattato in \secref{sec:sess_job_control_overview}.
+ trattato in sez.~\ref{sec:sess_job_control_overview}.
\end{basedescript}
\item[\const{SIGPIPE}] Sta per \textit{Broken pipe}. Se si usano delle pipe,
(o delle FIFO o dei socket) è necessario, prima che un processo inizi a
scrivere su una di esse, che un'altro l'abbia aperta in lettura (si veda
- \secref{sec:ipc_pipes}). Se il processo in lettura non è partito o è
+ sez.~\ref{sec:ipc_pipes}). Se il processo in lettura non è partito o è
terminato inavvertitamente alla scrittura sulla pipe il kernel genera questo
segnale. Se il segnale è bloccato, intercettato o ignorato la chiamata che
lo ha causato fallisce, restituendo l'errore \errcode{EPIPE}.
situazione precedente.
\item[\const{SIGXCPU}] Sta per \textit{CPU time limit exceeded}. Questo
segnale è generato quando un processo eccede il limite impostato per il
- tempo di CPU disponibile, vedi \secref{sec:sys_resource_limit}.
+ tempo di CPU disponibile, vedi sez.~\ref{sec:sys_resource_limit}.
\item[\const{SIGXFSZ}] Sta per \textit{File size limit exceeded}. Questo
segnale è generato quando un processo tenta di estendere un file oltre le
dimensioni specificate dal limite impostato per le dimensioni massime di un
- file, vedi \secref{sec:sys_resource_limit}.
+ file, vedi sez.~\ref{sec:sys_resource_limit}.
\end{basedescript}
terminazione di un processo figlio o di un gestore che gestisce più segnali);
la prima funzione, \funcd{strsignal}, è una estensione GNU, accessibile avendo
definito \macro{\_GNU\_SOURCE}, ed è analoga alla funzione \func{strerror} (si
-veda \secref{sec:sys_strerror}) per gli errori:
+veda sez.~\ref{sec:sys_strerror}) per gli errori:
\begin{prototype}{string.h}{char *strsignal(int signum)}
Ritorna il puntatore ad una stringa che contiene la descrizione del segnale
\param{signum}.
necessario copiarlo.
La seconda funzione, \funcd{psignal}, deriva da BSD ed è analoga alla funzione
-\func{perror} descritta sempre in \secref{sec:sys_strerror}; il suo prototipo
+\func{perror} descritta sempre in sez.~\ref{sec:sys_strerror}; il suo prototipo
è:
\begin{prototype}{signal.h}{void psignal(int sig, const char *s)}
Stampa sullo standard error un messaggio costituito dalla stringa \param{s},
\subsection{Il comportamento generale del sistema.}
\label{sec:sig_gen_beha}
-Abbiamo già trattato in \secref{sec:sig_intro} le modalità con cui il sistema
+Abbiamo già trattato in sez.~\ref{sec:sig_intro} le modalità con cui il sistema
gestisce l'interazione fra segnali e processi, ci resta da esaminare però il
comportamento delle system call; in particolare due di esse, \func{fork} ed
\func{exec}, dovranno essere prese esplicitamente in considerazione, data la
loro stretta relazione con la creazione di nuovi processi.
-Come accennato in \secref{sec:proc_fork} quando viene creato un nuovo processo
-esso eredita dal padre sia le azioni che sono state impostate per i singoli
-segnali, che la maschera dei segnali bloccati (vedi \secref{sec:sig_sigmask}).
-Invece tutti i segnali pendenti e gli allarmi vengono cancellati; essi infatti
-devono essere recapitati solo al padre, al figlio dovranno arrivare solo i
-segnali dovuti alle sue azioni.
+Come accennato in sez.~\ref{sec:proc_fork} quando viene creato un nuovo
+processo esso eredita dal padre sia le azioni che sono state impostate per i
+singoli segnali, che la maschera dei segnali bloccati (vedi
+sez.~\ref{sec:sig_sigmask}). Invece tutti i segnali pendenti e gli allarmi
+vengono cancellati; essi infatti devono essere recapitati solo al padre, al
+figlio dovranno arrivare solo i segnali dovuti alle sue azioni.
Quando si mette in esecuzione un nuovo programma con \func{exec} (si ricordi
-quanto detto in \secref{sec:proc_exec}) tutti i segnali per i quali è stato
+quanto detto in sez.~\ref{sec:proc_exec}) tutti i segnali per i quali è stato
installato un gestore vengono reimpostati a \const{SIG\_DFL}. Non ha più
senso infatti fare riferimento a funzioni definite nel programma originario,
che non sono presenti nello spazio di indirizzi del nuovo programma.
\item la scrittura sugli stessi file, nel caso in cui dati non possano essere
accettati immediatamente.
\item l'apertura di un file di dispositivo che richiede operazioni non
- immediate per una una risposta.
+ immediate per una risposta.
\item le operazioni eseguite con \func{ioctl} che non è detto possano essere
eseguite immediatamente.
\item le funzioni di intercomunicazione che si bloccano in attesa di risposte
Linux e le \acr{glibc} consentono di utilizzare entrambi gli approcci,
attraverso una opportuna opzione di \func{sigaction} (vedi
-\secref{sec:sig_sigaction}). È da chiarire comunque che nel caso di
+sez.~\ref{sec:sig_sigaction}). È da chiarire comunque che nel caso di
interruzione nel mezzo di un trasferimento parziale di dati, le system call
ritornano sempre indicando i byte trasferiti.
comportamento, pur mantenendone immutato il prototipo\footnote{in realtà in
alcune vecchie implementazioni (SVr4 e 4.3+BSD in particolare) vengono usati
alcuni parametri aggiuntivi per definire il comportamento della funzione,
- vedremo in \secref{sec:sig_sigaction} che questo è possibile usando la
+ vedremo in sez.~\ref{sec:sig_sigaction} che questo è possibile usando la
funzione \func{sigaction}.} che è:
\begin{prototype}{signal.h}
{sighandler\_t signal(int signum, sighandler\_t handler)}
segnale.
Il numero di segnale passato in \param{signum} può essere indicato
-direttamente con una delle costanti definite in \secref{sec:sig_standard}. Il
+direttamente con una delle costanti definite in sez.~\ref{sec:sig_standard}. Il
gestore \param{handler} invece, oltre all'indirizzo della funzione da chiamare
all'occorrenza del segnale, può assumere anche i due valori costanti
\const{SIG\_IGN} con cui si dice ignorare il segnale e \const{SIG\_DFL} per
e bloccando il segnale durante l'esecuzione dello stesso. Con l'utilizzo delle
\acr{glibc} dalla versione 2 anche Linux è passato a questo comportamento. Il
comportamento della versione originale della funzione, il cui uso è deprecato
-per i motivi visti in \secref{sec:sig_semantics}, può essere ottenuto
+per i motivi visti in sez.~\ref{sec:sig_semantics}, può essere ottenuto
chiamando \func{sysv\_signal}, una volta che si sia definita la macro
\macro{\_XOPEN\_SOURCE}. In generale, per evitare questi problemi, l'uso di
\func{signal} (ed ogni eventuale ridefinizine della stessa) è da evitare;
\subsection{Le funzioni \func{kill} e \func{raise}}
\label{sec:sig_kill_raise}
-Come accennato in \secref{sec:sig_types}, un segnale può essere generato
+Come accennato in sez.~\ref{sec:sig_types}, un segnale può essere generato
direttamente da un processo attraverso una opportuna system call. Le funzioni
che si usano di solito per inviare un segnale generico sono due, \func{raise} e
\func{kill}.
Il valore di \param{sig} specifica il segnale che si vuole inviare e può
essere specificato con una delle macro definite in
-\secref{sec:sig_classification}. In genere questa funzione viene usata per
+sez.~\ref{sec:sig_classification}. In genere questa funzione viene usata per
riprodurre il comportamento predefinito di un segnale che sia stato
intercettato. In questo caso, una volta eseguite le operazioni volute, il
gestore dovrà prima reinstallare l'azione predefinita, per poi attivarla
in tal caso si otterrà un errore \errcode{EPERM} se non si hanno i permessi
necessari ed un errore \errcode{ESRCH} se il processo specificato non esiste.
Si tenga conto però che il sistema ricicla i \acr{pid} (come accennato in
-\secref{sec:proc_pid}) per cui l'esistenza di un processo non significa che
+sez.~\ref{sec:proc_pid}) per cui l'esistenza di un processo non significa che
esso sia realmente quello a cui si intendeva mandare il segnale.
Il valore dell'argomento \param{pid} specifica il processo (o i processi) di
destinazione a cui il segnale deve essere inviato e può assumere i valori
-riportati in \tabref{tab:sig_kill_values}.
+riportati in tab.~\ref{tab:sig_kill_values}.
Si noti pertanto che la funzione \code{raise(sig)} può essere definita in
termini di \func{kill}, ed è sostanzialmente equivalente ad una
errore, gli errori sono gli stessi di \func{kill}.}
\end{prototype}
\noindent e che permette di inviare un segnale a tutto un \textit{process
- group} (vedi \secref{sec:sess_proc_group}).
+ group} (vedi sez.~\ref{sec:sess_proc_group}).
\begin{table}[htb]
\footnotesize
destinazione. Fa eccezione il caso in cui il segnale inviato sia
\const{SIGCONT}, nel quale occorre che entrambi i processi appartengano alla
stessa sessione. Inoltre, dato il ruolo fondamentale che riveste nel sistema
-(si ricordi quanto visto in \secref{sec:sig_termination}), non è possibile
+(si ricordi quanto visto in sez.~\ref{sec:sig_termination}), non è possibile
inviare al processo 1 (cioè a \cmd{init}) segnali per i quali esso non abbia
un gestore installato.
predisporre le opportune misure per gestire il caso di necessità di più
interruzioni.
-In \secref{sec:sys_unix_time} abbiamo visto che ad ogni processo sono
+In sez.~\ref{sec:sys_unix_time} abbiamo visto che ad ogni processo sono
associati tre tempi diversi: il \textit{clock time}, l'\textit{user time} ed
il \textit{system time}. Per poterli calcolare il kernel mantiene per ciascun
processo tre diversi timer:
\item un \textit{profiling timer} che calcola la somma dei tempi di processore
utilizzati direttamente dal processo in user space, e dal kernel nelle
system call ad esso relative (che corrisponde a quello che in
- \secref{sec:sys_unix_time} abbiamo chiamato \textit{CPU time}). La scadenza
+ sez.~\ref{sec:sys_unix_time} abbiamo chiamato \textit{CPU time}). La scadenza
di questo timer provoca l'emissione di \const{SIGPROF}.
\end{itemize}
Il valore di \param{which} permette di specificare quale dei tre timer
illustrati in precedenza usare; i possibili valori sono riportati in
-\tabref{tab:sig_setitimer_values}.
+tab.~\ref{tab:sig_setitimer_values}.
\begin{table}[htb]
\footnotesize
\centering
Il valore della struttura specificata \param{value} viene usato per impostare
il timer, se il puntatore \param{ovalue} non è nullo il precedente valore
viene salvato qui. I valori dei timer devono essere indicati attraverso una
-struttura \struct{itimerval}, definita in \figref{fig:file_stat_struct}.
+struttura \struct{itimerval}, definita in fig.~\ref{fig:file_stat_struct}.
La struttura è composta da due membri, il primo, \var{it\_interval} definisce
il periodo del timer; il secondo, \var{it\_value} il tempo mancante alla
definita direttamente nello standard POSIX.1, può a sua volta essere espressa
in termini di \func{setitimer}, come evidenziato dal manuale delle \acr{glibc}
\cite{glibc} che ne riporta la definizione mostrata in
-\figref{fig:sig_alarm_def}.
+fig.~\ref{fig:sig_alarm_def}.
\begin{figure}[!htb]
\footnotesize \centering
conto poi che in caso di sistema molto carico, si può avere il caso patologico
in cui un timer scade prima che il segnale di una precedente scadenza sia
stato consegnato; in questo caso, per il comportamento dei segnali descritto
-in \secref{sec:sig_sigchld}, un solo segnale sarà consegnato.
+in sez.~\ref{sec:sig_sigchld}, un solo segnale sarà consegnato.
Dato che sia \func{alarm} che \func{setitimer} non consentono di leggere il
L'ultima funzione che permette l'invio diretto di un segnale è \funcd{abort};
-che, come accennato in \secref{sec:proc_termination}, permette di abortire
+che, come accennato in sez.~\ref{sec:proc_termination}, permette di abortire
l'esecuzione di un programma tramite l'invio di \const{SIGABRT}. Il suo
prototipo è:
\begin{prototype}{stdlib.h}{void abort(void)}
sono apposite funzioni che permettono di mettere un processo in stato di
attesa.\footnote{si tratta in sostanza di funzioni che permettono di portare
esplicitamente il processo in stato di \textit{sleep}, vedi
- \secref{sec:proc_sched}.}
+ sez.~\ref{sec:proc_sched}.}
Il metodo tradizionale per fare attendere ad un processo fino all'arrivo di un
segnale è quello di usare la funzione \funcd{pause}, il cui prototipo è:
In alcune implementazioni inoltre l'uso di \func{sleep} può avere conflitti
con quello di \const{SIGALRM}, dato che la funzione può essere realizzata con
l'uso di \func{pause} e \func{alarm} (in maniera analoga all'esempio che
-vedremo in \secref{sec:sig_example}). In tal caso mescolare chiamata di
+vedremo in sez.~\ref{sec:sig_example}). In tal caso mescolare chiamata di
\func{alarm} e \func{sleep} o modificare l'azione di \const{SIGALRM}, può
causare risultati indefiniti. Nel caso delle \acr{glibc} è stata usata una
implementazione completamente indipendente e questi problemi non ci sono.
utilizzando direttamente il timer del kernel.} e sia utilizzabile senza
interferenze con l'uso di \const{SIGALRM}. La funzione prende come parametri
delle strutture di tipo \struct{timespec}, la cui definizione è riportata in
-\figref{fig:sys_timeval_struct}, che permettono di specificare un tempo con
+fig.~\ref{fig:sys_timeval_struct}, che permettono di specificare un tempo con
una precisione (teorica) fino al nanosecondo.
La funzione risolve anche il problema di proseguire l'attesa dopo
Un semplice esempio per illustrare il funzionamento di un gestore di segnale è
quello della gestione di \const{SIGCHLD}. Abbiamo visto in
-\secref{sec:proc_termination} che una delle azioni eseguite dal kernel alla
+sez.~\ref{sec:proc_termination} che una delle azioni eseguite dal kernel alla
conclusione di un processo è quella di inviare questo segnale al
padre.\footnote{in realtà in SVr4 eredita la semantica di System V, in cui il
segnale si chiama \const{SIGCLD} e viene trattato in maniera speciale; in
\func{waitpid} per completare la procedura di terminazione in modo da evitare
la formazione di zombie\index{zombie}.
-In \figref{fig:sig_sigchld_handl} è mostrato il codice contenente una
+In fig.~\ref{fig:sig_sigchld_handl} è mostrato il codice contenente una
implementazione generica di una routine di gestione per \const{SIGCHLD}, (che
si trova nei sorgenti allegati nel file \file{SigHand.c}); se ripetiamo i test
-di \secref{sec:proc_termination}, invocando \cmd{forktest} con l'opzione
+di sez.~\ref{sec:proc_termination}, invocando \cmd{forktest} con l'opzione
\cmd{-s} (che si limita ad effettuare l'installazione di questa funzione come
gestore di \const{SIGCHLD}) potremo verificare che non si ha più la creazione
di zombie\index{zombie}.
\end{figure}
Il codice del gestore è di lettura immediata; come buona norma di
-programmazione (si ricordi quanto accennato \secref{sec:sys_errno}) si
+programmazione (si ricordi quanto accennato sez.~\ref{sec:sys_errno}) si
comincia (\texttt{\small 12-13}) con il salvare lo stato corrente di
\var{errno}, in modo da poterlo ripristinare prima del ritorno del gestore
(\texttt{\small 22-23}). In questo modo si preserva il valore della variabile
generazione di un segnale e l'esecuzione del gestore possa passare un certo
lasso di tempo e niente ci assicura che il gestore venga eseguito prima della
generazione di ulteriori segnali dello stesso tipo. In questo caso normalmente
-i segnali segnali successivi vengono ``\textsl{fusi}'' col primo ed al
-processo ne viene recapitato soltanto uno.
+i segnali successivi vengono ``\textsl{fusi}'' col primo ed al processo ne
+viene recapitato soltanto uno.
Questo può essere un caso comune proprio con \const{SIGCHLD}, qualora capiti
che molti processi figli terminino in rapida successione. Esso inoltre si
Per questo occorre ripetere la chiamata di \func{waitpid} fino a che essa non
ritorni un valore nullo, segno che non resta nessun processo di cui si debba
-ancora ricevere lo stato di terminazione (si veda \secref{sec:proc_wait} per
+ancora ricevere lo stato di terminazione (si veda sez.~\ref{sec:proc_wait} per
la sintassi della funzione). Si noti anche come la funzione venga invocata con
il parametro \const{WNOHANG} che permette di evitare il suo blocco quando
tutti gli stati di terminazione sono stati ricevuti.
\subsection{Alcune problematiche aperte}
\label{sec:sig_example}
-Come accennato in \secref{sec:sig_pause_sleep} è possibile implementare
+Come accennato in sez.~\ref{sec:sig_pause_sleep} è possibile implementare
\func{sleep} a partire dall'uso di \func{pause} e \func{alarm}. A prima vista
questo può sembrare di implementazione immediata; ad esempio una semplice
versione di \func{sleep} potrebbe essere quella illustrata in
-\figref{fig:sig_sleep_wrong}.
+fig.~\ref{fig:sig_sleep_wrong}.
Dato che è nostra intenzione utilizzare \const{SIGALRM} il primo passo della
nostra implementazione di sarà quello di installare il relativo gestore
interrotta (se non in caso di un altro segnale).
Questo problema può essere risolto (ed è la modalità con cui veniva fatto in
-SVr2) usando la funzione \func{longjmp} (vedi \secref{sec:proc_longjmp}) per
+SVr2) usando la funzione \func{longjmp} (vedi sez.~\ref{sec:proc_longjmp}) per
uscire dal gestore; in questo modo, con una condizione sullo stato di
uscita di quest'ultima, si può evitare la chiamata a \func{pause}, usando un
-codice del tipo di quello riportato in \figref{fig:sig_sleep_incomplete}.
+codice del tipo di quello riportato in fig.~\ref{fig:sig_sleep_incomplete}.
\begin{figure}[!htb]
\footnotesize \centering
\end{figure}
In questo caso il gestore (\texttt{\small 18-26}) non ritorna come in
-\figref{fig:sig_sleep_wrong}, ma usa \func{longjmp} (\texttt{\small 24}) per
+fig.~\ref{fig:sig_sleep_wrong}, ma usa \func{longjmp} (\texttt{\small 24}) per
rientrare nel corpo principale del programma; dato che in questo caso il
valore di uscita di \func{setjmp} è 1, grazie alla condizione in
(\texttt{\small 9-12}) si evita comunque che \func{pause} sia chiamata a
qualche forma di evento; in genere quello che si fa in questo caso è impostare
nel gestore un opportuno flag da controllare nel corpo principale del
programma (con un codice del tipo di quello riportato in
-\figref{fig:sig_event_wrong}).
+fig.~\ref{fig:sig_event_wrong}).
\begin{figure}[!htb]
\footnotesize\centering
quale potrà determinare, osservandone il contenuto, l'occorrenza o meno del
segnale, e prendere le relative azioni conseguenti (\texttt{\small 6-11}).
-Questo è il tipico esempio di caso, già citato in \secref{sec:proc_race_cond},
-in cui si genera una race condition\index{race condition}; se infatti il
-segnale arriva immediatamente dopo l'esecuzione del controllo (\texttt{\small
- 6}) ma prima della cancellazione del flag (\texttt{\small 7}), la sua
-occorrenza sarà perduta.
+Questo è il tipico esempio di caso, già citato in
+sez.~\ref{sec:proc_race_cond}, in cui si genera una race condition\index{race
+ condition}; se infatti il segnale arriva immediatamente dopo l'esecuzione
+del controllo (\texttt{\small 6}) ma prima della cancellazione del flag
+(\texttt{\small 7}), la sua occorrenza sarà perduta.
Questi esempi ci mostrano che per una gestione effettiva dei segnali occorrono
funzioni più sofisticate di quelle illustrate finora, che hanno origine dalla
In genere si usa un insieme di segnali per specificare quali segnali si vuole
bloccare, o per riottenere dalle varie funzioni di gestione la maschera dei
-segnali attivi (vedi \secref{sec:sig_sigmask}). Essi possono essere definiti
+segnali attivi (vedi sez.~\ref{sec:sig_sigmask}). Essi possono essere definiti
in due diverse maniere, aggiungendo i segnali voluti ad un insieme vuoto
ottenuto con \func{sigemptyset} o togliendo quelli che non servono da un
insieme completo ottenuto con \func{sigfillset}. Infine \func{sigismember}
\subsection{La funzione \func{sigaction}}
\label{sec:sig_sigaction}
-Abbiamo già accennato in \secref{sec:sig_signal} i problemi di compatibilità
+Abbiamo già accennato in sez.~\ref{sec:sig_signal} i problemi di compatibilità
relativi all'uso di \func{signal}. Per ovviare a tutto questo lo standard
POSIX.1 ha ridefinito completamente l'interfaccia per la gestione dei segnali,
rendendola molto più flessibile e robusta, anche se leggermente più complessa.
Entrambi i puntatori fanno riferimento alla struttura \struct{sigaction},
tramite la quale si specificano tutte le caratteristiche dell'azione associata
ad un segnale. Anch'essa è descritta dallo standard POSIX.1 ed in Linux è
-definita secondo quanto riportato in \figref{fig:sig_sigaction}. Il campo
+definita secondo quanto riportato in fig.~\ref{fig:sig_sigaction}. Il campo
\var{sa\_restorer}, non previsto dallo standard, è obsoleto e non deve essere
più usato.
sempre aggiunto il segnale che ne ha causato la chiamata, a meno che non si
sia specificato con \var{sa\_flag} un comportamento diverso. Quando il
gestore ritorna comunque la maschera dei segnali bloccati (vedi
-\secref{sec:sig_sigmask}) viene ripristinata al valore precedente
+sez.~\ref{sec:sig_sigmask}) viene ripristinata al valore precedente
l'invocazione.
L'uso di questo campo permette ad esempio di risolvere il problema residuo
dell'implementazione di \code{sleep} mostrata in
-\secref{fig:sig_sleep_incomplete}. In quel caso infatti se il segnale di
+fig.~\ref{fig:sig_sleep_incomplete}. In quel caso infatti se il segnale di
allarme avesse interrotto un altro gestore questo non sarebbe stato
eseguito correttamente; la cosa poteva essere prevenuta installando gli altri
gestori usando \var{sa\_mask} per bloccare \const{SIGALRM} durante la
loro esecuzione. Il valore di \var{sa\_flag} permette di specificare vari
aspetti del comportamento di \func{sigaction}, e della reazione del processo
ai vari segnali; i valori possibili ed il relativo significato sono riportati
-in \tabref{tab:sig_sa_flag}.
+in tab.~\ref{tab:sig_sa_flag}.
\begin{table}[htb]
\footnotesize
\var{sa\_sigaction} al posto di \var{sa\_handler}.\\
\const{SA\_ONSTACK} & Stabilisce l'uso di uno stack alternativo per
l'esecuzione del gestore (vedi
- \secref{sec:sig_specific_features}).\\
+ sez.~\ref{sec:sig_specific_features}).\\
\hline
\end{tabular}
\caption{Valori del campo \var{sa\_flag} della struttura \struct{sigaction}.}
\label{tab:sig_sa_flag}
\end{table}
-Come si può notare in \figref{fig:sig_sigaction} \func{sigaction}
+Come si può notare in fig.~\ref{fig:sig_sigaction} \func{sigaction}
permette\footnote{La possibilità è prevista dallo standard POSIX.1b, ed è
stata aggiunta nei kernel della serie 2.1.x con l'introduzione dei segnali
- real-time (vedi \secref{sec:sig_real_time}). In precedenza era possibile
+ real-time (vedi sez.~\ref{sec:sig_real_time}). In precedenza era possibile
ottenere alcune informazioni addizionali usando \var{sa\_handler} con un
secondo parametro addizionale di tipo \var{sigcontext}, che adesso è
deprecato.} di utilizzare due forme diverse di gestore, da specificare, a
è quella classica usata anche con \func{signal}, mentre la prima permette di
usare un gestore più complesso, in grado di ricevere informazioni più
dettagliate dal sistema, attraverso la struttura \struct{siginfo\_t},
-riportata in \figref{fig:sig_siginfo_t}.
+riportata in fig.~\ref{fig:sig_siginfo_t}.
\begin{figure}[!htb]
\footnotesize \centering
altre informazioni specifiche. In tutti i casi il valore del campo è
riportato attraverso delle costanti (le cui definizioni si trovano
\file{bits/siginfo.h}) il cui elenco dettagliato è disponibile nella pagina di
-manuale di di \func{sigaction}.
+manuale di \func{sigaction}.
Il resto della struttura è definito come \ctyp{union} ed i valori
eventualmente presenti dipendono dal segnale, così \const{SIGCHLD} ed i
-segnali real-time (vedi \secref{sec:sig_real_time}) inviati tramite
+segnali real-time (vedi sez.~\ref{sec:sig_real_time}) inviati tramite
\func{kill} avvalorano \var{si\_pid} e \var{si\_uid} coi valori corrispondenti
al processo che ha emesso il segnale, \const{SIGILL}, \const{SIGFPE},
\const{SIGSEGV} e \const{SIGBUS} avvalorano \var{si\_addr} con l'indirizzo cui
-è avvenuto l'errore, \const{SIGIO} (vedi \secref{sec:file_asyncronous_io})
+è avvenuto l'errore, \const{SIGIO} (vedi sez.~\ref{sec:file_asyncronous_io})
avvalora \var{si\_fd} con il numero del file descriptor e \var{si\_band} per i
dati urgenti su un socket\index{socket}.
Per questo motivo si è provveduto, per mantenere un'interfaccia semplificata
che abbia le stesse caratteristiche di \func{signal}, a definire attraverso
\func{sigaction} una funzione equivalente, il cui codice è riportato in
-\figref{fig:sig_Signal_code} (il codice completo si trova nel file
+fig.~\ref{fig:sig_Signal_code} (il codice completo si trova nel file
\file{SigHand.c} nei sorgenti allegati). Si noti come, essendo la funzione
estremamente semplice, è definita come \direct{inline}.\footnote{la direttiva
\direct{inline} viene usata per dire al compilatore di trattare la funzione
\textit{signal mask}}
\label{sec:sig_sigmask}
-Come spiegato in \secref{sec:sig_semantics} tutti i moderni sistemi unix-like
+Come spiegato in sez.~\ref{sec:sig_semantics} tutti i moderni sistemi unix-like
permettono si bloccare temporaneamente (o di eliminare completamente,
impostando \const{SIG\_IGN} come azione) la consegna dei segnali ad un
processo. Questo è fatto specificando la cosiddetta \textsl{maschera dei
segnali} (o \textit{signal mask}) del processo\footnote{nel caso di Linux
essa è mantenuta dal campo \var{blocked} della \struct{task\_struct} del
processo.} cioè l'insieme dei segnali la cui consegna è bloccata. Abbiamo
-accennato in \secref{sec:proc_fork} che la \textit{signal mask} viene
+accennato in sez.~\ref{sec:proc_fork} che la \textit{signal mask} viene
ereditata dal padre alla creazione di un processo figlio, e abbiamo visto al
paragrafo precedente che essa può essere modificata, durante l'esecuzione di
un gestore, attraverso l'uso dal campo \var{sa\_mask} di \struct{sigaction}.
-Uno dei problemi evidenziatisi con l'esempio di \secref{fig:sig_event_wrong} è
-che in molti casi è necessario proteggere delle sezioni di codice (nel caso in
-questione la sezione fra il controllo e la eventuale cancellazione del flag
+Uno dei problemi evidenziatisi con l'esempio di fig.~\ref{fig:sig_event_wrong}
+è che in molti casi è necessario proteggere delle sezioni di codice (nel caso
+in questione la sezione fra il controllo e la eventuale cancellazione del flag
che testimoniava l'avvenuta occorrenza del segnale) in modo da essere sicuri
che essi siano eseguiti senza interruzioni.
La funzione usa l'insieme di segnali dato all'indirizzo \param{set} per
modificare la maschera dei segnali del processo corrente. La modifica viene
effettuata a seconda del valore dell'argomento \param{how}, secondo le modalità
-specificate in \tabref{tab:sig_procmask_how}. Qualora si specifichi un valore
+specificate in tab.~\ref{tab:sig_procmask_how}. Qualora si specifichi un valore
non nullo per \param{oldset} la maschera dei segnali corrente viene salvata a
quell'indirizzo.
In questo modo diventa possibile proteggere delle sezioni di codice bloccando
l'insieme di segnali voluto per poi riabilitarli alla fine della sezione
critica. La funzione permette di risolvere problemi come quelli mostrati in
-\secref{fig:sig_event_wrong}, proteggendo la sezione fra il controllo del flag
-e la sua cancellazione.
+fig.~\ref{fig:sig_event_wrong}, proteggendo la sezione fra il controllo del
+flag e la sua cancellazione.
La funzione può essere usata anche all'interno di un gestore, ad esempio
per riabilitare la consegna del segnale che l'ha invocato, in questo caso però
Benché con l'uso di \func{sigprocmask} si possano risolvere la maggior parte
dei casi di race condition\index{race condition} restano aperte alcune
possibilità legate all'uso di \func{pause}; il caso è simile a quello del
-problema illustrato nell'esempio di \secref{fig:sig_sleep_incomplete}, e cioè
+problema illustrato nell'esempio di fig.~\ref{fig:sig_sleep_incomplete}, e cioè
la possibilità che il processo riceva il segnale che si intende usare per
uscire dallo stato di attesa invocato con \func{pause} immediatamente prima
dell'esecuzione di quest'ultima. Per poter effettuare atomicamente la modifica
Come esempio dell'uso di queste funzioni proviamo a riscrivere un'altra volta
l'esempio di implementazione di \code{sleep}. Abbiamo accennato in
-\secref{sec:sig_sigaction} come con \func{sigaction} sia possibile bloccare
-\const{SIGALRM} nell'installazione dei gestori degli altri segnali, per
-poter usare l'implementazione vista in \secref{fig:sig_sleep_incomplete} senza
+sez.~\ref{sec:sig_sigaction} come con \func{sigaction} sia possibile bloccare
+\const{SIGALRM} nell'installazione dei gestori degli altri segnali, per poter
+usare l'implementazione vista in fig.~\ref{fig:sig_sleep_incomplete} senza
interferenze. Questo però comporta una precauzione ulteriore al semplice uso
della funzione, vediamo allora come usando la nuova interfaccia è possibile
-ottenere un'implementazione, riportata in \figref{fig:sig_sleep_ok} che non
+ottenere un'implementazione, riportata in fig.~\ref{fig:sig_sleep_ok} che non
presenta neanche questa necessità.
\begin{figure}[!htb]
\end{figure}
Per evitare i problemi di interferenza con gli altri segnali in questo caso
-non si è usato l'approccio di \figref{fig:sig_sleep_incomplete} evitando l'uso
-di \func{longjmp}. Come in precedenza il gestore (\texttt{\small 35-37})
+non si è usato l'approccio di fig.~\ref{fig:sig_sleep_incomplete} evitando
+l'uso di \func{longjmp}. Come in precedenza il gestore (\texttt{\small 35-37})
non esegue nessuna operazione, limitandosi a ritornare per interrompere il
programma messo in attesa.
Una delle caratteristiche di BSD, disponibile anche in Linux, è la possibilità
di usare uno stack alternativo per i segnali; è cioè possibile fare usare al
sistema un altro stack (invece di quello relativo al processo, vedi
-\secref{sec:proc_mem_layout}) solo durante l'esecuzione di un
+sez.~\ref{sec:proc_mem_layout}) solo durante l'esecuzione di un
gestore. L'uso di uno stack alternativo è del tutto trasparente ai
gestori, occorre però seguire una certa procedura:
\begin{enumerate}
\item Usare la funzione \func{sigaltstack} per rendere noto al sistema
l'esistenza e la locazione dello stack alternativo.
\item Quando si installa un gestore occorre usare \func{sigaction}
- specificando il flag \const{SA\_ONSTACK} (vedi \tabref{tab:sig_sa_flag}) per
- dire al sistema di usare lo stack alternativo durante l'esecuzione del
- gestore.
+ specificando il flag \const{SA\_ONSTACK} (vedi tab.~\ref{tab:sig_sa_flag})
+ per dire al sistema di usare lo stack alternativo durante l'esecuzione del
+ gestore.
\end{enumerate}
In genere il primo passo viene effettuato allocando un'opportuna area di
\end{prototype}
La funzione prende come argomenti puntatori ad una struttura di tipo
-\var{stack\_t}, definita in \figref{fig:sig_stack_t}. I due valori \param{ss}
+\var{stack\_t}, definita in fig.~\ref{fig:sig_stack_t}. I due valori \param{ss}
e \param{oss}, se non nulli, indicano rispettivamente il nuovo stack da
installare e quello corrente (che viene restituito dalla funzione per un
successivo ripristino).
Si ricordi infine che una chiamata ad una funzione della famiglia
\func{exec} cancella ogni stack alternativo.
-Abbiamo visto in \secref{fig:sig_sleep_incomplete} come si possa usare
+Abbiamo visto in fig.~\ref{fig:sig_sleep_incomplete} come si possa usare
\func{longjmp} per uscire da un gestore rientrando direttamente nel corpo
del programma; sappiamo però che nell'esecuzione di un gestore il segnale
che l'ha invocato viene bloccato, e abbiamo detto che possiamo ulteriormente
Lo standard POSIX.1 non specifica questo comportamento per \func{setjmp} e
\func{longjmp}, ed il comportamento delle \acr{glibc} dipende da quale delle
caratteristiche si sono abilitate con le macro viste in
-\secref{sec:intro_gcc_glibc_std}.
+sez.~\ref{sec:intro_gcc_glibc_std}.
Lo standard POSIX però prevede anche la presenza di altre due funzioni
\funcd{sigsetjmp} e \funcd{siglongjmp}, che permettono di decidere quale dei
non-locale su un precedente contesto.
\bodydesc{Le due funzioni sono identiche alle analoghe \func{setjmp} e
- \func{longjmp} di \secref{sec:proc_longjmp}, ma consentono di specificare
+ \func{longjmp} di sez.~\ref{sec:proc_longjmp}, ma consentono di specificare
il comportamento sul ripristino o meno della maschera dei segnali.}
\end{functions}
salvato il contesto dello stack per permettere il salto non-locale
\index{salto non-locale}; nel caso specifico essa è di tipo
\type{sigjmp\_buf}, e non \type{jmp\_buf} come per le analoghe di
-\secref{sec:proc_longjmp} in quanto in questo caso viene salvata anche la
+sez.~\ref{sec:proc_longjmp} in quanto in questo caso viene salvata anche la
maschera dei segnali.
Nel caso di \func{sigsetjmp} se si specifica un valore di \param{savesigs}
questo sarà eseguito una sola volta, ed il processo non sarà in grado di
accorgersi di quante volte l'evento che ha generato il segnale è accaduto.
\item[I segnali non trasportano informazione]
- i segnali classici non prevedono prevedono altra informazione sull'evento
+ i segnali classici non prevedono altra informazione sull'evento
che li ha generati se non il fatto che sono stati emessi (tutta
l'informazione che il kernel associa ad un segnale è il suo numero).
\item[I segnali non hanno un ordine di consegna]
Si tenga presente che questi nuovi segnali non sono associati a nessun evento
specifico, a meno di non utilizzarli in meccanismi di notifica come quelli per
-l'I/O asincrono (vedi \secref{sec:file_asyncronous_io}) o per le code di
-messaggi POSIX (vedi \secref{sec:ipc_posix_mq}); pertanto devono essere
+l'I/O asincrono (vedi sez.~\ref{sec:file_asyncronous_io}) o per le code di
+messaggi POSIX (vedi sez.~\ref{sec:ipc_posix_mq}); pertanto devono essere
inviati esplicitamente.
Inoltre, per poter usufruire della capacità di restituire dei dati, i relativi
gestori devono essere installati con \func{sigaction}, specificando per
\var{sa\_flags} la modalità \const{SA\_SIGINFO} che permette di utilizzare la
-forma estesa \var{sa\_sigaction} (vedi \secref{sec:sig_sigaction}). In questo
-modo tutti i segnali real-time possono restituire al gestore una serie di
-informazioni aggiuntive attraverso l'argomento \struct{siginfo\_t}, la cui
-definizione abbiamo già visto in \figref{fig:sig_siginfo_t}, nella trattazione
-dei gestori in forma estesa.
+forma estesa \var{sa\_sigaction} (vedi sez.~\ref{sec:sig_sigaction}). In
+questo modo tutti i segnali real-time possono restituire al gestore una serie
+di informazioni aggiuntive attraverso l'argomento \struct{siginfo\_t}, la cui
+definizione abbiamo già visto in fig.~\ref{fig:sig_siginfo_t}, nella
+trattazione dei gestori in forma estesa.
In particolare i campi utilizzati dai segnali real-time sono \var{si\_pid} e
\var{si\_uid} in cui vengono memorizzati rispettivamente il \acr{pid} e
restituzione dei dati viene usato il campo \var{si\_value}.
Questo è una \ctyp{union} di tipo \struct{sigval\_t} (la sua definizione è in
-\figref{fig:sig_sigval}) in cui può essere memorizzato o un valore numerico,
+fig.~\ref{fig:sig_sigval}) in cui può essere memorizzato o un valore numerico,
se usata nella forma \var{sival\_int}, o un indirizzo, se usata nella forma
\var{sival\_ptr}. L'unione viene usata dai segnali real-time e da vari
meccanismi di notifica\footnote{un campo di tipo \struct{sigval\_t} è presente
anche nella struttura \struct{sigevent} che viene usata dai meccanismi di
notifica come quelli per l'I/O asincrono (vedi
- \secref{sec:file_asyncronous_io}) o le code di messaggi POSIX (vedi
- \secref{sec:ipc_posix_mq}).} per restituire dati al gestore del segnale; in
+ sez.~\ref{sec:file_asyncronous_io}) o le code di messaggi POSIX (vedi
+ sez.~\ref{sec:ipc_posix_mq}).} per restituire dati al gestore del segnale; in
alcune definizioni essa viene identificata anche come \code{union sigval}.
\begin{figure}[!htb]
(vale a dire che c'è posto\footnote{la profondità della coda è indicata dalla
costante \const{SIGQUEUE\_MAX}, una della tante costanti di sistema definite
dallo standard POSIX che non abbiamo riportato esplicitamente in
- \secref{sec:sys_limits}. Il suo valore minimo secondo lo standard,
+ sez.~\ref{sec:sys_limits}. Il suo valore minimo secondo lo standard,
\const{\_POSIX\_SIGQUEUE\_MAX}, è pari a 32. Nel caso di Linux questo è uno
dei parametri del kernel impostabili sia con \func{sysctl}, che scrivendolo
direttamente in \file{/proc/sys/kernel/rtsig-max}, il valore predefinito è
Esamineremo in questo capitolo le funzionalità più evolute della gestione dei
socket TCP, come l'uso del I/O multiplexing (trattato in
-\secref{sec:file_multiplexing}) con i socket, l'uso delle opzioni dei socket e
-la gestione dei dati urgenti e \textit{out-of-band}.
+sez.~\ref{sec:file_multiplexing}) con i socket, l'uso delle opzioni dei socket
+e la gestione dei dati urgenti e \textit{out-of-band}.
\textsl{presa}, ma essendo universalmente noti come \textit{socket}
utilizzeremo sempre la parola inglese.} sono uno dei principali meccanismi
di comunicazione utilizzato in ambito Unix, e li abbiamo brevemente incontrati
-in \secref{sec:ipc_socketpair}, fra i vari meccanismi di intercominazione fra
-processi. Un socket costituisce in sostanza un canale di comunicazione fra due
-processi su cui si possono leggere e scrivere dati analogo a quello di una
-pipe (vedi \secref{sec:ipc_pipes}) ma, a differenza di questa e degli altri
-meccanismi esaminati nel capitolo \capref{cha:IPC}, i socket non sono limitati
-alla comunicazione fra processi che girano sulla stessa macchina, ma possono
-realizzare la comunicazione anche attraverso la rete.
+in sez.~\ref{sec:ipc_socketpair}, fra i vari meccanismi di intercominazione
+fra processi. Un socket costituisce in sostanza un canale di comunicazione fra
+due processi su cui si possono leggere e scrivere dati analogo a quello di una
+pipe (vedi sez.~\ref{sec:ipc_pipes}) ma, a differenza di questa e degli altri
+meccanismi esaminati nel capitolo cap.~\ref{cha:IPC}, i socket non sono
+limitati alla comunicazione fra processi che girano sulla stessa macchina, ma
+possono realizzare la comunicazione anche attraverso la rete.
Quella dei socket costituisce infatti la principale interfaccia usata nella
programmazione di rete. La loro origine risale al 1983, quando furono
\label{sec:sock_gen}
Per capire il funzionamento dei socket occorre avere presente il funzionamento
-dei protocolli di rete (vedi \capref{cha:network}), ma l'interfaccia è del
+dei protocolli di rete (vedi cap.~\ref{cha:network}), ma l'interfaccia è del
tutto generale e benché le problematiche (e quindi le modalità di risolvere i
problemi) siano diverse a seconda del tipo di protocollo di comunicazione
usato, le funzioni da usare restano le stesse.
La creazione di un socket avviene attraverso l'uso della funzione
\funcd{socket}; essa restituisce un \textit{file descriptor}\footnote{del
tutto analogo a quelli che si ottengono per i file di dati e le pipe,
- descritti in \secref{sec:file_fd}.} che serve come riferimento al socket; il
-suo prototipo è:
+ descritti in sez.~\ref{sec:file_fd}.} che serve come riferimento al socket;
+il suo prototipo è:
\begin{prototype}{sys/socket.h}{int socket(int domain, int type, int protocol)}
Apre un socket.
\end{prototype}
La funzione ha tre argomenti, \param{domain} specifica il dominio del socket
-(definisce cioè, come vedremo in \secref{sec:sock_domain}, la famiglia di
+(definisce cioè, come vedremo in sez.~\ref{sec:sock_domain}, la famiglia di
protocolli usata), \param{type} specifica il tipo di socket (definisce cioè,
-come vedremo in \secref{sec:sock_type}, lo stile di comunicazione) e
+come vedremo in sez.~\ref{sec:sock_type}, lo stile di comunicazione) e
\param{protocol} il protocollo; in genere quest'ultimo è indicato
implicitamente dal tipo di socket, per cui di norma questo valore viene messo
a zero (con l'eccezione dei \textit{raw socket}).
I domini (e i relativi nomi simbolici), così come i nomi delle famiglie di
indirizzi, sono definiti dall'header \textit{socket.h}. Un elenco delle
famiglie di protocolli disponibili in Linux è riportato in
-\tabref{tab:net_pf_names}.\footnote{l'elenco indica tutti i protocolli
+tab.~\ref{tab:net_pf_names}.\footnote{l'elenco indica tutti i protocolli
definiti; fra questi però saranno utilizzabili solo quelli per i quali si è
compilato il supporto nel kernel (o si sono caricati gli opportuni moduli),
viene definita anche una costante \const{PF\_MAX} che indica il valore
\label{tab:sock_sock_valid_combinations}
\end{table}
-In \secref{tab:sock_sock_valid_combinations} sono mostrate le combinazioni
+In tab.~\ref{tab:sock_sock_valid_combinations} sono mostrate le combinazioni
valide possibili per le principali famiglie di protocolli. Per ogni
combinazione valida si è indicato il tipo di protocollo, o la parola
\textsl{si} qualora non il protocollo non abbia un nome definito, mentre si
generici (i \ctyp{void *}), ma l'interfaccia dei socket è antecedente alla
definizione dello standard ANSI C, e per questo nel 1982 fu scelto di definire
una struttura generica per gli indirizzi dei socket, \struct{sockaddr}, che si
-è riportata in \figref{fig:sock_sa_gen_struct}.
+è riportata in fig.~\ref{fig:sock_sa_gen_struct}.
\begin{figure}[!htb]
\footnotesize \centering
occorrerà eseguire una conversione del relativo puntatore.
I tipi di dati che compongono la struttura sono stabiliti dallo standard
-POSIX.1g e li abbiamo riassunti in \tabref{tab:sock_data_types} con i
+POSIX.1g e li abbiamo riassunti in tab.~\ref{tab:sock_data_types} con i
rispettivi file di include in cui sono definiti; la struttura è invece
definita nell'include file \file{sys/socket.h}.
attraverso internet; la struttura per gli indirizzi per un socket internet (se
si usa IPv4) è definita come \struct{sockaddr\_in} nell'header file
\file{netinet/in.h} ed ha la forma mostrata in
-\figref{fig:sock_sa_ipv4_struct}, conforme allo standard POSIX.1g.
+fig.~\ref{fig:sock_sa_ipv4_struct}, conforme allo standard POSIX.1g.
\begin{figure}[!htb]
\footnotesize\centering
L'indirizzo di un socket internet (secondo IPv4) comprende l'indirizzo
internet di un'interfaccia più un \textsl{numero di porta} (affronteremo in
-dettaglio il significato di questi numeri in \secref{sec:TCP_port_num}). Il
+dettaglio il significato di questi numeri in sez.~\ref{sec:TCP_port_num}). Il
protocollo IP non prevede numeri di porta, che sono utilizzati solo dai
protocolli di livello superiore come TCP e UDP. Questa struttura però viene
usata anche per i socket RAW che accedono direttamente al livello di IP, nel
chiamati \textsl{riservati} in quanto utilizzati da servizi standard e
soltanto processi con i privilegi di amministratore (con user-ID effettivo
uguale a zero) o con la capability \texttt{CAP\_NET\_BIND\_SERVICE} possono
-usare la funzione \func{bind} (che vedremo in \secref{sec:TCP_func_bind}) su
+usare la funzione \func{bind} (che vedremo in sez.~\ref{sec:TCP_func_bind}) su
queste porte.
Il membro \var{sin\_addr} contiene un indirizzo internet, e viene acceduto sia
una \direct{union} usata per accedere alle diverse classi di indirizzi) che
direttamente come intero. In \file{netinet/in.h} vengono definite anche alcune
costanti che identificano alcuni indirizzi speciali, riportati in
-\tabref{tab:TCP_ipv4_addr}.
+tab.~\ref{tab:TCP_ipv4_addr}.
Infine occorre sottolineare che sia gli indirizzi che i numeri di porta devono
essere specificati in quello che viene chiamato \textit{network order}, cioè
con i bit ordinati in formato \textit{big endian}, questo comporta la
necessità di usare apposite funzioni di conversione per mantenere la
-portabilità del codice (vedi \secref{sec:sock_addr_func} per i dettagli del
+portabilità del codice (vedi sez.~\ref{sec:sock_addr_func} per i dettagli del
problema e le relative soluzioni).
sostanzialmente identici ai precedenti; la parte in cui si trovano
praticamente tutte le differenze fra i due socket è quella della struttura
degli indirizzi; la sua definizione, presa da \file{netinet/in.h}, è riportata
-in \figref{fig:sock_sa_ipv6_struct}.
+in fig.~\ref{fig:sock_sa_ipv6_struct}.
\begin{figure}[!htb]
\footnotesize \centering
il campo \var{sin6\_flowinfo} è a sua volta diviso in tre parti di cui i 24
bit inferiori indicano l'etichetta di flusso, i successivi 4 bit la priorità e
gli ultimi 4 sono riservati. Questi valori fanno riferimento ad alcuni campi
-specifici dell'header dei pacchetti IPv6 (vedi \secref{sec:IP_ipv6head}) ed il
+specifici dell'header dei pacchetti IPv6 (vedi sez.~\ref{sec:IP_ipv6head}) ed il
loro uso è sperimentale.
Il campo \var{sin6\_addr} contiene l'indirizzo a 128 bit usato da IPv6, infine
2.4, per gestire alcune operazioni riguardanti il multicasting.
Si noti che questa struttura ha una dimensione maggiore della struttura
-\struct{sockaddr} generica vista in \figref{fig:sock_sa_gen_struct}, quindi
+\struct{sockaddr} generica vista in fig.~\ref{fig:sock_sa_gen_struct}, quindi
occorre stare attenti a non avere fatto assunzioni riguardo alla possibilità
di contenere i dati nelle dimensioni di quest'ultima.
vengono chiamati \textit{local domain} o anche \textit{Unix domain}); essi
hanno la caratteristica ulteriore di poter essere creati anche in maniera
anonima attraverso la funzione \func{socketpair} (che abbiamo trattato in
-\secref{sec:ipc_socketpair}). Quando però si vuole fare riferimento esplicito
-ad uno di questi socket si deve usare una struttura degli indirizzi di tipo
-\struct{sockaddr\_un}, la cui definizione si è riportata in
-\secref{fig:sock_sa_local_struct}.
+sez.~\ref{sec:ipc_socketpair}). Quando però si vuole fare riferimento
+esplicito ad uno di questi socket si deve usare una struttura degli indirizzi
+di tipo \struct{sockaddr\_un}, la cui definizione si è riportata in
+fig.~\ref{fig:sock_sa_local_struct}.
\begin{figure}[!htb]
\footnotesize \centering
Gli indirizzi AppleTalk devono essere specificati tramite una struttura
\struct{sockaddr\_atalk}, la cui definizione è riportata in
-\figref{fig:sock_sa_atalk_struct}; la struttura viene dichiarata includendo il
-file \file{netatalk/at.h}.
+fig.~\ref{fig:sock_sa_atalk_struct}; la struttura viene dichiarata includendo
+il file \file{netatalk/at.h}.
\begin{figure}[!htb]
\footnotesize \centering
usati solo da processi con i privilegi di amministratore o con la capability
\const{CAP\_NET\_BIND\_SERVICE}. L'indirizzo remoto è specificato nella
struttura \var{sat\_addr}, e deve essere in \textit{network order} (vedi
-\secref{sec:sock_endianess}); esso è composto da un parte di rete data dal
+sez.~\ref{sec:sock_endianess}); esso è composto da un parte di rete data dal
campo \var{s\_net}, che può assumere il valore \const{AT\_ANYNET}, che indica
una rete generica e vale anche per indicare la rete su cui si è, il singolo
nodo è indicato da \var{s\_node}, e può prendere il valore generico
Nel caso dei \textit{packet socket} la struttura degli indirizzi è di tipo
\struct{sockaddr\_ll}, e la sua definizione è riportata in
-\figref{fig:sock_sa_packet_struct}; essa però viene ad assumere un ruolo
+fig.~\ref{fig:sock_sa_packet_struct}; essa però viene ad assumere un ruolo
leggermente diverso rispetto a quanto visto finora per gli altri tipi di
socket. Infatti se il socket è di tipo \const{SOCK\_RAW} si deve comunque
scrivere tutto direttamente nel pacchetto, quindi la struttura non serve più a
Per capire meglio il problema si consideri un intero a 32 bit scritto in una
locazione di memoria posta ad un certo indirizzo. Come illustrato in
-\figref{fig:sock_endianess} i singoli bit possono essere disposti un memoria
+fig.~\ref{fig:sock_endianess} i singoli bit possono essere disposti un memoria
in due modi: a partire dal più significativo o a partire dal meno
significativo. Così nel primo caso si troverà il byte che contiene i bit più
significativi all'indirizzo menzionato e il byte con i bit meno significativi
Per controllare quale tipo di ordinamento si ha sul proprio computer si è
scritta una piccola funzione di controllo, il cui codice è riportato
-\figref{fig:sock_endian_code}, che restituisce un valore nullo (falso) se
+fig.~\ref{fig:sock_endian_code}, che restituisce un valore nullo (falso) se
l'architettura è \textit{big endian} ed uno non nullo (vero) se l'architettura
è \textit{little endian}.
Per questo prima (\texttt{\small 10}) si definisce il puntatore \var{ptr} per
accedere al contenuto della prima variabile, ed infine calcola (\texttt{\small
11}) il valore della seconda assumendo che il primo byte sia quello meno
-significativo (cioè, per quanto visto in \secref{fig:sock_endianess}, che sia
+significativo (cioè, per quanto visto in fig.~\ref{fig:sock_endianess}, che sia
\textit{little endian}). Infine la funzione restituisce (\texttt{\small 12})
il valore del confonto delle due variabili.
La funzione \func{inet\_aton} converte la stringa puntata da \param{src}
nell'indirizzo binario che viene memorizzato nell'opportuna struttura
-\struct{in\_addr} (si veda \secref{fig:sock_sa_ipv4_struct}) situata
+\struct{in\_addr} (si veda fig.~\ref{fig:sock_sa_ipv4_struct}) situata
all'indirizzo dato dall'argomento \param{dest} (è espressa in questa forma in
modo da poterla usare direttamente con il puntatore usato per passare la
struttura degli indirizzi). La funzione restituisce 0 in caso di successo e 1
Il formato usato per gli indirizzi in formato di presentazione è la notazione
\textit{dotted decimal} per IPv4 e quello descritto in
-\secref{sec:IP_ipv6_notation} per IPv6.
+sez.~\ref{sec:IP_ipv6_notation} per IPv6.
\index{socket|)}
La funzione, che viene usata dal comando \cmd{uname}, restituisce le
informazioni richieste nella struttura \param{info}; anche questa struttura è
definita in \file{sys/utsname.h}, secondo quanto mostrato in
-sez.~\ref{fig:sys_utsname}, e le informazioni memorizzate nei suoi membri
+fig.~\ref{fig:sys_utsname}, e le informazioni memorizzate nei suoi membri
indicano rispettivamente:
\begin{itemize*}
\item il nome del sistema operativo;
Entrambe le funzioni permettono di specificare, attraverso l'argomento
\param{resource}, su quale risorsa si vuole operare: i possibili valori di
-questo argomento sono elencati in sez.~\ref{tab:sys_rlimit_values}. L'acceso
+questo argomento sono elencati in tab.~\ref{tab:sys_rlimit_values}. L'acceso
(rispettivamente in lettura e scrittura) ai valori effettivi dei limiti viene
poi effettuato attraverso la struttura \struct{rlimit} puntata da
\param{rlim}.
La funzione restituisce i valori di process time del processo corrente in una
struttura di tipo \struct{tms}, la cui definizione è riportata in
-sez.~\ref{fig:sys_tms_struct}. La struttura prevede quattro campi; i primi due,
+fig.~\ref{fig:sys_tms_struct}. La struttura prevede quattro campi; i primi due,
\var{tms\_utime} e \var{tms\_stime}, sono l'\textit{user time} ed il
\textit{system time} del processo, così come definiti in
sez.~\ref{sec:sys_unix_time}.
specificato in un opportuno campo di \struct{timex}, deve essere impostato. Un
valore nullo serve per leggere i parametri correnti; i valori diversi da zero
devono essere specificati come OR binario delle costanti riportate in
-sez.~\ref{tab:sys_timex_mode}.
+tab.~\ref{tab:sys_timex_mode}.
La funzione utilizza il meccanismo di David L. Mills, descritto
nell'\href{http://www.ietf.org/rfc/rfc1305.txt}{RFC~1305}, che è alla base del
serie di flag usati per gestire la connessione, come SYN, ACK, URG, FIN,
alcuni di essi, come SYN (che sta per \textit{syncronize}) corrispondono a
funzioni particolari del protocollo e danno il nome al segmento, (per
- maggiori dettagli vedere \secref{sec:tcp_protocol}).} di dati che vengono
+ maggiori dettagli vedere sez.~\ref{sec:tcp_protocol}).} di dati che vengono
scambiati) che porta alla creazione di una connessione è la seguente:
\begin{enumerate}
e ACK.
\item una volta che il client ha ricevuto l'acknowledge dal server la funzione
- \func{connect} ritorna, l'ultimo passo è dare dare il ricevuto del SYN del
+ \func{connect} ritorna, l'ultimo passo è dare il ricevuto del SYN del
server inviando un ACK. Alla ricezione di quest'ultimo la funzione
\func{accept} del server ritorna e la connessione è stabilita.
\end{enumerate}
Il procedimento viene chiamato \textit{three way handshake} dato che per
-realizzarlo devono essere scambiati tre segmenti. In \figref{fig:TCP_TWH}
+realizzarlo devono essere scambiati tre segmenti. In fig.~\ref{fig:TCP_TWH}
si è rappresentata graficamente la sequenza di scambio dei segmenti che
stabilisce la connessione.
\end{figure}
Si è accennato in precedenza ai \textsl{numeri di sequenza} (che sono anche
-riportati in \figref{fig:TCP_TWH}): per gestire una connessione affidabile
+riportati in fig.~\ref{fig:TCP_TWH}): per gestire una connessione affidabile
infatti il protocollo TCP prevede nell'header la presenza di un numero a 32
bit (chiamato appunto \textit{sequence number}) che identifica a quale byte
nella sequenza del flusso corrisponde il primo byte della sezione dati
aspetta di ricevere con il pacchetto successivo; dato che il primo pacchetto
SYN consuma un byte, nel \textit{three way handshake} il numero di acknowledge
è sempre pari al numero di sequenza iniziale incrementato di uno; lo stesso
-varrà anche (vedi \figref{fig:TCP_close}) per l'acknowledgement di un FIN.
+varrà anche (vedi fig.~\ref{fig:TCP_close}) per l'acknowledgement di un FIN.
\subsection{Le opzioni TCP.}
\label{sec:TCP_TCP_opt}
connessione corrente. È possibile leggere e scrivere questo valore
attraverso l'opzione del socket \const{TCP\_MAXSEG}.
-\item \textit{window scale option}, %come spiegato in \secref{sec:tcp_protocol}
+\item \textit{window scale option}, %come spiegato in sez.~\ref{sec:tcp_protocol}
il protocollo TCP implementa il controllo di flusso attraverso una
\textsl{finestra annunciata} (\textit{advertized window}) con la quale
ciascun capo della comunicazione dichiara quanto spazio disponibile ha in
giacché in alcune situazioni il FIN del passo 1) è inviato insieme a dei dati.
Inoltre è possibile che i segmenti inviati nei passi 2 e 3 dal capo che
effettua la chiusura passiva, siano accorpati in un singolo segmento. In
-\figref{fig:TCP_close} si è rappresentato graficamente lo sequenza di
+fig.~\ref{fig:TCP_close} si è rappresentato graficamente lo sequenza di
scambio dei segmenti che conclude la connessione.
\begin{figure}[htb]
è chiuso il socket dal lato che esegue la chiusura attiva; esistono tuttavia
situazioni in cui si vuole poter sfruttare questa possibilità, usando una
procedura che è chiamata \textit{half-close}; torneremo su questo aspetto e su
-come utilizzarlo in \secref{sec:TCP_shutdown}, quando parleremo della funzione
-\func{shutdown}.
+come utilizzarlo in sez.~\ref{sec:TCP_shutdown}, quando parleremo della
+funzione \func{shutdown}.
La emissione del FIN avviene quando il socket viene chiuso, questo però non
avviene solo per la chiamata esplicita della funzione \func{close}, ma anche
connessioni aperte verranno chiuse.
Infine occorre sottolineare che, benché nella figura (e nell'esempio che
-vedremo più avanti in \secref{sec:TCP_echo}) sia stato il client ad eseguire
+vedremo più avanti in sez.~\ref{sec:TCP_echo}) sia stato il client ad eseguire
la chiusura attiva, nella realtà questa può essere eseguita da uno qualunque
dei due capi della comunicazione (come nell'esempio di
-\figref{fig:TCP_daytime_iter_server_code}), e anche se il caso più comune
+fig.~\ref{fig:TCP_daytime_iter_server_code}), e anche se il caso più comune
resta quello del client, ci sono alcuni servizi, il principale dei quali è
l'HTTP, per i quali è il server ad effettuare la chiusura attiva.
Come abbiamo visto le operazioni del TCP nella creazione e conclusione di una
connessione sono piuttosto complesse, ed abbiamo esaminato soltanto quelle
-relative ad un andamento normale. In \secref{sec:TCP_states} vedremo con
+relative ad un andamento normale. In sez.~\ref{sec:TCP_states} vedremo con
maggiori dettagli che una connessione può assumere vari stati, che ne
caratterizzano il funzionamento, e che sono quelli che vengono riportati dal
comando \cmd{netstat}, per ciascun socket TCP aperto, nel campo
Non possiamo affrontare qui una descrizione completa del funzionamento del
protocollo; un approfondimento sugli aspetti principali si trova in
-\secref{sec:tcp_protocol}, ma per una trattazione completa il miglior
+sez.~\ref{sec:tcp_protocol}, ma per una trattazione completa il miglior
riferimento resta \cite{TCPIll1}. Qui ci limiteremo a descrivere brevemente un
semplice esempio di connessione e le transizioni che avvengono nei due casi
appena citati (creazione e terminazione della connessione).
\texttt{ESTABLISHED} (chiusura passiva) la transizione è verso lo stato
\texttt{CLOSE\_WAIT}.
-In \figref{fig:TCP_conn_example} è riportato lo schema dello scambio dei
+In fig.~\ref{fig:TCP_conn_example} è riportato lo schema dello scambio dei
pacchetti che avviene per una un esempio di connessione, insieme ai vari stati
che il protocollo viene ad assumere per i due lati, server e client.
restituisce una risposta (che di nuovo supponiamo stare in un singolo
segmento). Si noti che l'acknowledge della richiesta è mandato insieme alla
risposta: questo viene chiamato \textit{piggybacking} ed avviene tutte le
-volte che che il server è sufficientemente veloce a costruire la risposta; in
+volte che il server è sufficientemente veloce a costruire la risposta; in
caso contrario si avrebbe prima l'emissione di un ACK e poi l'invio della
risposta.
Infine si ha lo scambio dei quattro segmenti che terminano la connessione
-secondo quanto visto in \secref{sec:TCP_conn_term}; si noti che il capo della
+secondo quanto visto in sez.~\ref{sec:TCP_conn_term}; si noti che il capo della
connessione che esegue la chiusura attiva entra nello stato
\texttt{TIME\_WAIT}, sul cui significato torneremo fra poco.
in questo stato lasciando attiva una connessione ormai conclusa; la risposta è
che non deve essere fatto, ed il motivo cercheremo di spiegarlo adesso.
-Come si è visto nell'esempio precedente (vedi \figref{fig:TCP_conn_example})
+Come si è visto nell'esempio precedente (vedi fig.~\ref{fig:TCP_conn_example})
\texttt{TIME\_WAIT} è lo stato finale in cui il capo di una connessione che
esegue la chiusura attiva resta prima di passare alla chiusura definitiva
della connessione. Il tempo in cui l'applicazione resta in questo stato deve
sulla rete; questo tempo è limitato perché ogni pacchetto IP può essere
ritrasmesso dai router un numero massimo di volte (detto \textit{hop limit}).
Il numero di ritrasmissioni consentito è indicato dal campo TTL dell'header di
-IP (per maggiori dettagli vedi \secref{sec:ip_protocol}), e viene decrementato
-ad ogni passaggio da un router; quando si annulla il pacchetto viene scartato.
-Siccome il numero è ad 8 bit il numero massimo di ``\textsl{salti}'' è di 255,
-pertanto anche se il TTL (da \textit{time to live}) non è propriamente un
-limite sul tempo di vita, si stima che un pacchetto IP non possa restare nella
-rete per più di MSL secondi.
+IP (per maggiori dettagli vedi sez.~\ref{sec:ip_protocol}), e viene
+decrementato ad ogni passaggio da un router; quando si annulla il pacchetto
+viene scartato. Siccome il numero è ad 8 bit il numero massimo di
+``\textsl{salti}'' è di 255, pertanto anche se il TTL (da \textit{time to
+ live}) non è propriamente un limite sul tempo di vita, si stima che un
+pacchetto IP non possa restare nella rete per più di MSL secondi.
Ogni implementazione del TCP deve scegliere un valore per la MSL
(l'\href{http://www.ietf.org/rfc/rfc1122.txt}{RFC~1122} raccomanda 2 minuti,
durata di questo stato.
Il primo dei due motivi precedenti si può capire tornando a
-\figref{fig:TCP_conn_example}: assumendo che l'ultimo ACK della sequenza
+fig.~\ref{fig:TCP_conn_example}: assumendo che l'ultimo ACK della sequenza
(quello del capo che ha eseguito la chiusura attiva) venga perso, chi esegue
la chiusura passiva non ricevendo risposta rimanderà un ulteriore FIN, per
questo motivo chi esegue la chiusura attiva deve mantenere lo stato della
sia UDP che TCP, e ci devono poter essere più connessioni in contemporanea.
Per poter tenere distinte le diverse connessioni entrambi i protocolli usano i
\textsl{numeri di porta}, che fanno parte, come si può vedere in
-\secref{sec:sock_sa_ipv4} e \secref{sec:sock_sa_ipv6} pure delle strutture
+sez.~\ref{sec:sock_sa_ipv4} e sez.~\ref{sec:sock_sa_ipv6} pure delle strutture
degli indirizzi del socket.
Quando un client contatta un server deve poter identificare con quale dei vari
In realtà rispetto a quanto indicato
nell'\href{http://www.ietf.org/rfc/rfc1700.txt}{RFC~1700} i vari sistemi hanno
fatto scelte diverse per le porte effimere, in particolare in
-\figref{fig:TCP_port_alloc} sono riportate quelle di BSD e Linux. Nel caso di
-Linux poi la scelta fra i due intervalli possibili viene fatta dinamicamente a
-seconda della memoria a disposizione del kernel per gestire le relative
-tabelle.
+fig.~\ref{fig:TCP_port_alloc} sono riportate quelle di BSD e Linux. Nel caso
+di Linux poi la scelta fra i due intervalli possibili viene fatta
+dinamicamente a seconda della memoria a disposizione del kernel per gestire le
+relative tabelle.
\begin{figure}[!htb]
\centering
Per capire meglio l'uso delle porte e come vengono utilizzate quando si ha a
che fare con un'applicazione client/server (come quelle che descriveremo in
-\secref{sec:TCP_daytime_application} e \secref{sec:TCP_echo_application})
+sez.~\ref{sec:TCP_daytime_application} e sez.~\ref{sec:TCP_echo_application})
esamineremo cosa accade con le connessioni nel caso di un server TCP che deve
gestire connessioni multiple.
In questa sezione descriveremo in maggior dettaglio le varie funzioni che
vengono usate per la gestione di base dei socket TCP, non torneremo però sulla
funzione \func{socket}, che è già stata esaminata accuratamente nel capitolo
-precedente in \secref{sec:sock_socket}.
+precedente in sez.~\ref{sec:sock_socket}.
\subsection{La funzione \func{bind}}
Il primo argomento è un file descriptor ottenuto da una precedente chiamata a
\func{socket}, mentre il secondo e terzo argomento sono rispettivamente
l'indirizzo (locale) del socket e la dimensione della struttura che lo
-contiene, secondo quanto già trattato in \secref{sec:sock_sockaddr}.
+contiene, secondo quanto già trattato in sez.~\ref{sec:sock_sockaddr}.
Con i socket TCP la chiamata \func{bind} permette di specificare l'indirizzo,
la porta, entrambi o nessuno dei due. In genere i server utilizzano una porta
Per specificare un indirizzo generico, con IPv4 si usa il valore
\const{INADDR\_ANY}, il cui valore, come accennato in
-\secref{sec:sock_sa_ipv4}, è pari a zero; nell'esempio
-\figref{fig:TCP_daytime_iter_server_code} si è usata un'assegnazione immediata
-del tipo: \includecodesnip{listati/serv_addr_sin_addr.c}
+sez.~\ref{sec:sock_sa_ipv4}, è pari a zero; nell'esempio
+fig.~\ref{fig:TCP_daytime_iter_server_code} si è usata un'assegnazione
+immediata del tipo: \includecodesnip{listati/serv_addr_sin_addr.c}
Si noti che si è usato \func{htonl} per assegnare il valore
\const{INADDR\_ANY}, anche se, essendo questo nullo, il riordinamento è
inutile. Si tenga presente comunque che tutte le costanti \val{INADDR\_}
-(riportate in \tabref{tab:TCP_ipv4_addr}) sono definite secondo
+(riportate in tab.~\ref{tab:TCP_ipv4_addr}) sono definite secondo
l'\textit{endianess} della macchina, ed anche se esse possono essere
invarianti rispetto all'ordinamento dei bit, è comunque buona norma usare
sempre la funzione \func{htonl}.
connessione.
\item[\errcode{ENETUNREACH}] la rete non è raggiungibile.
\item[\errcode{EINPROGRESS}] il socket è non bloccante (vedi
- \secref{sec:file_noblocking}) e la connessione non può essere conclusa
+ sez.~\ref{sec:file_noblocking}) e la connessione non può essere conclusa
immediatamente.
\item[\errcode{EALREADY}] il socket è non bloccante (vedi
- \secref{sec:file_noblocking}) e un tentativo precedente di connessione non
- si è ancora concluso.
+ sez.~\ref{sec:file_noblocking}) e un tentativo precedente di connessione
+ non si è ancora concluso.
\item[\errcode{EAGAIN}] non ci sono più porte locali libere.
\item[\errcode{EAFNOSUPPORT}] l'indirizzo non ha una famiglia di indirizzi
corretta nel relativo campo.
Il primo argomento è un file descriptor ottenuto da una precedente chiamata a
\func{socket}, mentre il secondo e terzo argomento sono rispettivamente
l'indirizzo e la dimensione della struttura che contiene l'indirizzo del
-socket, già descritta in \secref{sec:sock_sockaddr}.
+socket, già descritta in sez.~\ref{sec:sock_sockaddr}.
La struttura dell'indirizzo deve essere inizializzata con l'indirizzo IP e il
numero di porta del server a cui ci si vuole connettere, come mostrato
-nell'esempio \secref{sec:TCP_daytime_client}, usando le funzioni illustrate in
-\secref{sec:sock_addr_func}.
+nell'esempio sez.~\ref{sec:TCP_daytime_client}, usando le funzioni illustrate
+in sez.~\ref{sec:sock_addr_func}.
Nel caso di socket TCP la funzione \func{connect} avvia il \textit{three way
handshake}, e ritorna solo quando la connessione è stabilita o si è
\end{enumerate}
Se si fa riferimento al diagramma degli stati del TCP riportato in
-\figref{fig:TCP_state_diag} la funzione \func{connect} porta un socket
+fig.~\ref{fig:TCP_state_diag} la funzione \func{connect} porta un socket
dallo stato \texttt{CLOSED} (lo stato iniziale in cui si trova un socket
appena creato) prima allo stato \texttt{SYN\_SENT} e poi, al ricevimento del
ACK, nello stato \texttt{ESTABLISHED}. Se invece la connessione fallisce il
Questi socket sono tutti nello stato \texttt{ESTABLISHED}.
\end{enumerate}
-Lo schema di funzionamento è descritto in \figref{fig:TCP_listen_backlog}:
+Lo schema di funzionamento è descritto in fig.~\ref{fig:TCP_listen_backlog}:
quando arriva un SYN da un client il server crea una nuova voce nella coda
delle connessioni incomplete, e poi risponde con il SYN$+$ACK. La voce resterà
nella coda delle connessioni incomplete fino al ricevimento dell'ACK dal
client o fino ad un timeout. Nel caso di completamento del three way handshake
la voce viene spostata nella coda delle connessioni complete. Quando il
-processo chiama la funzione \func{accept} (vedi \secref{sec:TCP_func_accept})
+processo chiama la funzione \func{accept} (vedi sez.~\ref{sec:TCP_func_accept})
la prima voce nella coda delle connessioni complete è passata al programma, o,
se la coda è vuota, il processo viene posto in attesa e risvegliato all'arrivo
della prima connessione completa.
comunque una risposta univoca per la scelta del valore, per questo non
conviene specificarlo con una costante (il cui cambiamento richiederebbe la
ricompilazione del server) ma usare piuttosto una variabile di ambiente (vedi
-\secref{sec:proc_environ}).
+sez.~\ref{sec:proc_environ}).
Stevens tratta accuratamente questo argomento in \cite{UNP1}, con esempi presi
da casi reali su web server, ed in particolare evidenzia come non sia più vero
\item[\errcode{EOPNOTSUPP}] il socket è di un tipo che non supporta questa
operazione.
\item[\errcode{EAGAIN} o \errcode{EWOULDBLOCK}] il socket è stato impostato
- come non bloccante (vedi \secref{sec:file_noblocking}), e non ci sono
+ come non bloccante (vedi sez.~\ref{sec:file_noblocking}), e non ci sono
connessioni in attesa di essere accettate.
\item[\errcode{EPERM}] Le regole del firewall non consentono la connessione.
\item[\errcode{ENOBUFS}, \errcode{ENOMEM}] questo spesso significa che
Se la funzione ha successo restituisce il descrittore di un nuovo socket
creato dal kernel (detto \textit{connected socket}) a cui viene associata la
prima connessione completa (estratta dalla relativa coda, vedi
-\secref{sec:TCP_func_listen}) che il client ha effettuato verso il socket
+sez.~\ref{sec:TCP_func_listen}) che il client ha effettuato verso il socket
\param{sockfd}. Quest'ultimo (detto \textit{listening socket}) è quello creato
all'inizio e messo in ascolto con \func{listen}, e non viene toccato dalla
funzione. Se non ci sono connessioni pendenti da accettare la funzione mette
in attesa il processo\footnote{a meno che non si sia impostato il socket per
- essere non bloccante (vedi \secref{sec:file_noblocking}), nel qual caso
+ essere non bloccante (vedi sez.~\ref{sec:file_noblocking}), nel qual caso
ritorna con l'errore \errcode{EAGAIN}. Torneremo su questa modalità di
- operazione in \secref{sec:TCP_sock_multiplexing}.} fintanto che non ne
+ operazione in sez.~\ref{sec:TCP_sock_multiplexing}.} fintanto che non ne
arriva una.
La funzione può essere usata solo con socket che supportino la connessione
\func{accept} passa gli errori di rete pendenti sul nuovo socket come codici
di errore per \func{accept}, per cui l'applicazione deve tenerne conto ed
eventualmente ripetere la chiamata alla funzione come per l'errore di
-\errcode{EAGAIN} (torneremo su questo in \secref{sec:TCP_echo_critical}).
+\errcode{EAGAIN} (torneremo su questo in sez.~\ref{sec:TCP_echo_critical}).
Un'altra differenza con BSD è che la funzione non fa ereditare al nuovo socket
i flag del socket originale, come \const{O\_NONBLOCK},\footnote{ed in generale
tutti quelli che si possono impostare con \func{fcntl}, vedi
- \secref{sec:file_fcntl}.} che devono essere rispecificati ogni volta. Tutto
+ sez.~\ref{sec:file_fcntl}.} che devono essere rispecificati ogni volta. Tutto
questo deve essere tenuto in conto se si devono scrivere programmi portabili.
Il meccanismo di funzionamento di \func{accept} è essenziale per capire il
si trovano automaticamente nello stato \texttt{ESTABLISHED}, e vengono
utilizzati per lo scambio dei dati, che avviene su di essi, fino alla chiusura
della connessione. Si può riconoscere questo schema anche nell'esempio
-elementare di \figref{fig:TCP_daytime_iter_server_code}, dove per ogni
+elementare di fig.~\ref{fig:TCP_daytime_iter_server_code}, dove per ogni
connessione il socket creato da \func{accept} viene chiuso dopo l'invio dei
dati.
capo della connessione. Ci si può chiedere a cosa serva questa funzione dato
che dal lato client l'indirizzo remoto è sempre noto quando si esegue la
\func{connect} mentre dal lato server si possono usare, come vedremo in
-\figref{fig:TCP_daytime_cunc_server_code}, i valori di ritorno di
+fig.~\ref{fig:TCP_daytime_cunc_server_code}, i valori di ritorno di
\func{accept}.
Il fatto è che in generale quest'ultimo caso non è sempre possibile. In
particolare questo avviene quando il server, invece di gestire la connessione
direttamente in un processo figlio, come vedremo nell'esempio di server
-concorrente di \secref{sec:TCP_daytime_cunc_server}, lancia per ciascuna
+concorrente di sez.~\ref{sec:TCP_daytime_cunc_server}, lancia per ciascuna
connessione un altro programma, usando \func{exec}.\footnote{questa ad esempio
è la modalità con cui opera il \textsl{super-server} \cmd{inetd}, che può
gestire tutta una serie di servizi diversi, eseguendo su ogni connessione
\subsection{La funzione \func{close}}
\label{sec:TCP_func_close}
-La funzione standard Unix \func{close} (vedi \secref{sec:file_close}) che si
+La funzione standard Unix \func{close} (vedi sez.~\ref{sec:file_close}) che si
usa sui file può essere usata con lo stesso effetto anche sui file descriptor
associati ad un socket.
connessione non avesse chiuso la sua parte). Il kernel invierà comunque tutti
i dati che ha in coda prima di iniziare la sequenza di chiusura.
-Vedremo più avanti in \secref{sec:TCP_so_linger} come è possibile cambiare
+Vedremo più avanti in sez.~\ref{sec:TCP_so_linger} come è possibile cambiare
questo comportamento, e cosa deve essere fatto perché il processo possa
assicurarsi che l'altro capo abbia ricevuto tutti i dati.
di riferimenti, per cui se più di un processo ha lo stesso socket aperto
l'emissione del FIN e la sequenza di chiusura di TCP non viene innescata
fintanto che il numero di riferimenti non si annulla, questo si applica, come
-visto in \secref{sec:file_sharing}, sia ai file descriptor duplicati che a
+visto in sez.~\ref{sec:file_sharing}, sia ai file descriptor duplicati che a
quelli ereditati dagli eventuali processi figli, ed è il comportamento che ci
si aspetta in una qualunque applicazione client/server.
Per attivare immediatamente l'emissione del FIN e la sequenza di chiusura
-descritta in \secref{sec:TCP_conn_term}, si può invece usare la funzione
+descritta in sez.~\ref{sec:TCP_conn_term}, si può invece usare la funzione
\func{shutdown} su cui torneremo in seguito (vedi
-\secref{sec:TCP_shutdown}).
+sez.~\ref{sec:TCP_shutdown}).
dall'\href{http://www.ietf.org/rfc/rfc867.txt}{RFC~867}. Prima di passare
agli esempi del client e del server, inizieremo riesaminando con maggiori
dettagli una peculiarità delle funzioni di I/O, già accennata in
-\secref{sec:file_read} e \secref{sec:file_write}, che nel caso dei socket è
+sez.~\ref{sec:file_read} e sez.~\ref{sec:file_write}, che nel caso dei socket è
particolarmente rilevante. Passeremo poi ad illustrare gli esempi
dell'implementazione, sia dal lato client, che dal lato server, che si è
realizzato sia in forma iterativa che concorrente.
Infatti con i socket è comune che funzioni come \func{read} o \func{write}
possano restituire in input o scrivere in output un numero di byte minore di
-quello richiesto. Come già accennato in \secref{sec:file_read} questo è un
+quello richiesto. Come già accennato in sez.~\ref{sec:file_read} questo è un
comportamento normale per le funzioni di I/O, ma con i normali file di dati il
problema si avverte solo in lettura, quando si incontra la fine del file. In
generale non è così, e con i socket questo è particolarmente evidente.
byte restanti, tenendo conto che le funzioni si possono bloccare se i dati non
sono disponibili: è lo stesso comportamento che si può avere scrivendo più di
\const{PIPE\_BUF} byte in una pipe (si riveda quanto detto in
-\secref{sec:ipc_pipes}).
+sez.~\ref{sec:ipc_pipes}).
Per questo motivo, seguendo l'esempio di R. W. Stevens in \cite{UNP1}, si sono
definite due funzioni, \func{FullRead} e \func{FullWrite}, che eseguono
lettura e scrittura tenendo conto di questa caratteristica, ed in grado di
ritornare solo dopo avere letto o scritto esattamente il numero di byte
specificato; il sorgente è riportato rispettivamente in
-\figref{fig:sock_FullRead_code} e \figref{fig:sock_FullWrite_code} ed è
+fig.~\ref{fig:sock_FullRead_code} e fig.~\ref{fig:sock_FullWrite_code} ed è
disponibile fra i sorgenti allegati alla guida nei file \file{FullRead.c} e
\file{FullWrite.c}.
\label{sec:TCP_daytime_client}
Il primo esempio di applicazione delle funzioni di base illustrate in
-\secref{sec:TCP_functions} è relativo alla creazione di un client elementare
+sez.~\ref{sec:TCP_functions} è relativo alla creazione di un client elementare
per il servizio \textit{daytime}, un servizio elementare, definito
nell'\href{http://www.ietf.org/rfc/rfc867.txt}{RFC~867}, che restituisce
l'ora locale della macchina a cui si effettua la richiesta, e che è assegnato
alla porta 13.
-In \figref{fig:TCP_daytime_client_code} è riportata la sezione principale del
+In fig.~\ref{fig:TCP_daytime_client_code} è riportata la sezione principale del
codice del nostro client. Il sorgente completo del programma
(\file{TCP\_daytime.c}, che comprende il trattamento delle opzioni ed una
funzione per stampare un messaggio di aiuto) è allegato alla guida nella
dopo la dichiarazione delle variabili (\texttt{\small 9--12}) si è omessa
tutta la parte relativa al trattamento degli argomenti passati dalla linea di
comando (effettuata con le apposite funzioni illustrate in
-\secref{sec:proc_opt_handling}).
+sez.~\ref{sec:proc_opt_handling}).
Il primo passo (\texttt{\small 14--18}) è creare un socket TCP (quindi di tipo
\const{SOCK\_STREAM} e di famiglia \const{AF\_INET}). La funzione
35}) con il solito carattere nullo per poter essere stampata (\texttt{\small
36}) sullo standard output con l'uso di \func{fputs}.
-Come si è già spiegato in \secref{sec:sock_io_behav} la risposta dal socket
+Come si è già spiegato in sez.~\ref{sec:sock_io_behav} la risposta dal socket
potrà arrivare in un unico pacchetto di 26 byte (come avverrà senz'altro nel
caso in questione) ma potrebbe anche arrivare in 26 pacchetti di un byte. Per
questo nel caso generale non si può mai assumere che tutti i dati arrivino con
elementare, che sia anche in grado di rispondere al precedente client. Come
primo esempio realizzeremo un server iterativo, in grado di fornire una sola
risposta alla volta. Il codice del programma è nuovamente mostrato in
-\figref{fig:TCP_daytime_iter_server_code}, il sorgente completo
+fig.~\ref{fig:TCP_daytime_iter_server_code}, il sorgente completo
(\file{TCP\_iter\_daytimed.c}) è allegato insieme agli altri file degli esempi.
\begin{figure}[!htbp]
comando, se lo si volesse utilizzare come demone occorrerebbero le opportune
modifiche\footnote{come una chiamata a \func{daemon} prima dell'inizio del
ciclo principale.} per tener conto di quanto illustrato in
-\secref{sec:sess_daemon}. Si noti anche che non si è inserita nessuna forma di
-gestione della terminazione del processo, dato che tutti i file descriptor
+sez.~\ref{sec:sess_daemon}. Si noti anche che non si è inserita nessuna forma
+di gestione della terminazione del processo, dato che tutti i file descriptor
vengono chiusi automaticamente alla sua uscita, e che, non generando figli,
non è necessario preoccuparsi di gestire la loro terminazione.
\label{sec:TCP_daytime_cunc_server}
Il server \texttt{daytime} dell'esempio in
-\secref{sec:TCP_daytime_iter_server} è un tipico esempio di server iterativo,
+sez.~\ref{sec:TCP_daytime_iter_server} è un tipico esempio di server iterativo,
in cui viene servita una richiesta alla volta; in generale però, specie se il
servizio è più complesso e comporta uno scambio di dati più sostanzioso di
quello in questione, non è opportuno bloccare un server nel servizio di un
client per volta; per questo si ricorre alle capacità di multitasking del
sistema.
-Come accennato anche in \secref{sec:proc_gen} una delle modalità più comuni di
-funzionamento da parte dei server è quella di usare la funzione \func{fork}
+Come accennato anche in sez.~\ref{sec:proc_gen} una delle modalità più comuni
+di funzionamento da parte dei server è quella di usare la funzione \func{fork}
per creare, ad ogni richiesta da parte di un client, un processo figlio che si
incarichi della gestione della comunicazione. Si è allora riscritto il server
\textit{daytime} dell'esempio precedente in forma concorrente, inserendo anche
una opzione per la stampa degli indirizzi delle connessioni ricevute.
-In \figref{fig:TCP_daytime_cunc_server_code} è mostrato un estratto del
+In fig.~\ref{fig:TCP_daytime_cunc_server_code} è mostrato un estratto del
codice, in cui si sono tralasciati il trattamento delle opzioni e le parti
rimaste invariate rispetto al precedente esempio (cioè tutta la parte
riguardante l'apertura passiva del socket). Al solito il sorgente completo del
immediatamente (\texttt{\small 33}) il socket \var{list\_fd}; mentre il padre
continua ad operare solo sul socket in ascolto chiudendo (\texttt{\small 48})
\var{conn\_fd} al ritorno dalla \func{fork}. Per quanto abbiamo detto in
-\secref{sec:TCP_func_close} nessuna delle due chiamate a \func{close} causa
+sez.~\ref{sec:TCP_func_close} nessuna delle due chiamate a \func{close} causa
l'innesco della sequenza di chiusura perché il numero di riferimenti al file
descriptor non si è annullato.
Il codice della prima versione del client per il servizio \textit{echo},
disponibile nel file \file{TCP\_echo\_first.c}, è riportato in
-\figref{fig:TCP_echo_client_1}. Esso ricalca la struttura del precedente
+fig.~\ref{fig:TCP_echo_client_1}. Esso ricalca la struttura del precedente
client per il servizio \textit{daytime} (vedi
-\secref{sec:TCP_daytime_client}), e la prima parte (\texttt{\small 10--27}) è
+sez.~\ref{sec:TCP_daytime_client}), e la prima parte (\texttt{\small 10--27}) è
sostanzialmente identica, a parte l'uso di una porta diversa.
\begin{figure}[!htb]
\textit{echo}, infine si converte (\texttt{\small 18--22}) l'indirizzo
specificato a riga di comando. A questo punto (\texttt{\small 23--27}) si può
eseguire la connessione al server secondo la stessa modalità usata in
-\secref{sec:TCP_daytime_client}.
+sez.~\ref{sec:TCP_daytime_client}.
Completata la connessione, per gestire il funzionamento del protocollo si usa
la funzione \code{ClientEcho}, il cui codice si è riportato a parte in
-\figref{fig:TCP_client_echo_sub}. Questa si preoccupa di gestire tutta la
+fig.~\ref{fig:TCP_client_echo_sub}. Questa si preoccupa di gestire tutta la
comunicazione, leggendo una riga alla volta dallo standard input \file{stdin},
scrivendola sul socket e ristampando su \file{stdout} quanto ricevuto in
risposta dal server. Al ritorno dalla funzione (\texttt{\small 30--31}) anche
\const{MAXLINE} caratteri) e la salva sul buffer di invio.
Si usa poi (\texttt{\small 6}) la funzione \func{FullWrite}, vista in
-\secref{sec:sock_io_behav}, per scrivere i dati sul socket, gestendo
+sez.~\ref{sec:sock_io_behav}, per scrivere i dati sul socket, gestendo
automaticamente l'invio multiplo qualora una singola \func{write} non sia
sufficiente. I dati vengono riletti indietro (\texttt{\small 7}) con una
\func{read}\footnote{si è fatta l'assunzione implicita che i dati siano
Quando si concluderà l'invio di dati mandando un end-of-file sullo standard
input si avrà il ritorno di \func{fgets} con un puntatore nullo (si riveda
-quanto spiegato in \secref{sec:file_line_io}) e la conseguente uscita dal
+quanto spiegato in sez.~\ref{sec:file_line_io}) e la conseguente uscita dal
ciclo; al che la subroutine ritorna ed il nostro programma client termina.
Si può effettuare una verifica del funzionamento del client abilitando il
servizio \textit{echo} nella configurazione di \cmd{initd} sulla propria
macchina ed usandolo direttamente verso di esso in locale, vedremo in
-dettaglio più avanti (in \secref{sec:TCP_echo_startup}) il funzionamento del
+dettaglio più avanti (in sez.~\ref{sec:TCP_echo_startup}) il funzionamento del
programma, usato però con la nostra versione del server \textit{echo}, che
illustriamo immediatamente.
\label{sec:TCPsimp_server_main}
La prima versione del server, contenuta nel file \file{TCP\_echod\_first.c}, è
-riportata in \figref{fig:TCP_echo_server_first_code}. Come abbiamo fatto per
+riportata in fig.~\ref{fig:TCP_echo_server_first_code}. Come abbiamo fatto per
il client anche il server è stato diviso in un corpo principale, costituito
dalla funzione \code{main}, che è molto simile a quello visto nel precedente
esempio per il server del servizio \textit{daytime} di
-\secref{sec:TCP_daytime_cunc_server}, e da una funzione ausiliaria
+sez.~\ref{sec:TCP_daytime_cunc_server}, e da una funzione ausiliaria
\code{ServEcho} che si cura della gestione del servizio.
\begin{figure}[!htbp]
\end{figure}
In questo caso però, rispetto a quanto visto nell'esempio di
-\figref{fig:TCP_daytime_cunc_server_code} si è preferito scrivere il server
+fig.~\ref{fig:TCP_daytime_cunc_server_code} si è preferito scrivere il server
curando maggiormente alcuni dettagli, per tenere conto anche di alcune
esigenze generali (che non riguardano direttamente la rete), come la
possibilità di lanciare il server anche in modalità interattiva e la cessione
dei privilegi di amministratore non appena questi non sono più necessari.
La sezione iniziale del programma (\texttt{\small 8--21}) è la stessa del
-server di \secref{sec:TCP_daytime_cunc_server}, ed ivi descritta in dettaglio:
-crea il socket, inizializza l'indirizzo e esegue \func{bind}; dato che
-quest'ultima funzione viene usata su una porta riservata, il server dovrà
+server di sez.~\ref{sec:TCP_daytime_cunc_server}, ed ivi descritta in
+dettaglio: crea il socket, inizializza l'indirizzo e esegue \func{bind}; dato
+che quest'ultima funzione viene usata su una porta riservata, il server dovrà
essere eseguito da un processo con i privilegi di amministratore, pena il
fallimento della chiamata.
amministratore si può cambiare il gruppo di un processo ad un'altro di cui
non si fa parte, per cui chiamare prima \func{setuid} farebbe fallire una
successiva chiamata a \func{setgid}. Inoltre si ricordi (si riveda quanto
- esposto in \secref{sec:proc_perms}) che usando queste due funzioni il
+ esposto in sez.~\ref{sec:proc_perms}) che usando queste due funzioni il
rilascio dei privilegi è irreversibile.} Infine (\texttt{\small 30--36}),
qualora sia impostata la variabile \var{demonize}, prima (\texttt{\small 31})
si apre il sistema di logging per la stampa degli errori, e poi
A questo punto il programma riprende di nuovo lo schema già visto usato dal
server per il servizio \textit{daytime}, con l'unica differenza della chiamata
-alla funzione \code{PrintErr}, riportata in \figref{fig:TCP_PrintErr}, al
+alla funzione \code{PrintErr}, riportata in fig.~\ref{fig:TCP_PrintErr}, al
posto di \func{perror} per la stampa degli errori.
Si inizia con il porre (\texttt{\small 37--41}) in ascolto il socket, e poi si
Avendo trattato direttamente la gestione del programma come demone, si è
dovuto anche provvedere alla necessità di poter stampare eventuali messaggi di
errore attraverso il sistema del \textit{syslog} trattato in
-\secref{sec:sess_daemon}. Come accennato questo è stato fatto utilizzando come
-\textit{wrapper} la funzione \code{PrintErr}, il cui codice è riportato in
-\figref{fig:TCP_PrintErr}.
+sez.~\ref{sec:sess_daemon}. Come accennato questo è stato fatto utilizzando
+come \textit{wrapper} la funzione \code{PrintErr}, il cui codice è riportato
+in fig.~\ref{fig:TCP_PrintErr}.
In essa ci si limita a controllare (\texttt{\small 2}) se è stato impostato
(valore attivo per default) l'uso come demone, nel qual caso (\texttt{\small
- 3}) si usa \func{syslog} (vedi \secref{sec:sess_daemon}) per stampare il
+ 3}) si usa \func{syslog} (vedi sez.~\ref{sec:sess_daemon}) per stampare il
messaggio di errore fornito come argomento sui log di sistema. Se invece si è
in modalità interattiva (attivabile con l'opzione \texttt{-i}) si usa
(\texttt{\small 5}) semplicemente la funzione \func{perror} per stampare sullo
La gestione del servizio \textit{echo} viene effettuata interamente nella
funzione \code{ServEcho}, il cui codice è mostrato in
-\figref{fig:TCP_ServEcho_first}, e la comunicazione viene gestita all'interno
+fig.~\ref{fig:TCP_ServEcho_first}, e la comunicazione viene gestita all'interno
di un ciclo (\texttt{\small 6--13}). I dati inviati dal client vengono letti
(\texttt{\small 6}) dal socket con una semplice \func{read}, di cui non si
controlla lo stato di uscita, assumendo che ritorni solo in presenza di dati
in arrivo. La riscrittura (\texttt{\small 7}) viene invece gestita dalla
-funzione \func{FullWrite} (descritta in \figref{fig:sock_FullWrite_code}) che
+funzione \func{FullWrite} (descritta in fig.~\ref{fig:sock_FullWrite_code}) che
si incarica di tenere conto automaticamente della possibilità che non tutti i
dati di cui è richiesta la scrittura vengano trasmessi con una singola
\func{write}.
\end{verbatim} %$
(dove si sono cancellate le righe inutili) da cui si evidenzia la presenza di
tre processi, tutti in stato di \textit{sleep} (vedi
-\tabref{tab:proc_proc_states}).
+tab.~\ref{tab:proc_proc_states}).
Se a questo punto si inizia a scrivere qualcosa sul client non sarà trasmesso
niente fin tanto che non si prema il tasto di a capo (si ricordi quanto detto
-in \secref{sec:file_line_io} a proposito dell'I/O su terminale), solo allora
+in sez.~\ref{sec:file_line_io} a proposito dell'I/O su terminale), solo allora
\func{fgets} ritornerà ed il client scriverà quanto immesso sul socket, per
poi passare a rileggere quanto gli viene inviato all'indietro dal server, che
a sua volta sarà inviato sullo standard output, che nel caso ne provoca
così la funzione \code{ClientEcho} ritorna.
\item al ritorno di \code{ClientEcho} ritorna anche la funzione \code{main}, e
come parte del processo terminazione tutti i file descriptor vengono chiusi
- (si ricordi quanto detto in \secref{sec:proc_term_conclusion}); questo causa
- la chiusura del socket di comunicazione; il client allora invierà un FIN al
- server a cui questo risponderà con un ACK. A questo punto il client verrà a
- trovarsi nello stato \texttt{FIN\_WAIT\_2} ed il server nello stato
+ (si ricordi quanto detto in sez.~\ref{sec:proc_term_conclusion}); questo
+ causa la chiusura del socket di comunicazione; il client allora invierà un
+ FIN al server a cui questo risponderà con un ACK. A questo punto il client
+ verrà a trovarsi nello stato \texttt{FIN\_WAIT\_2} ed il server nello stato
\texttt{CLOSE\_WAIT} (si riveda quanto spiegato in
- \secref{sec:TCP_conn_term}).
+ sez.~\ref{sec:TCP_conn_term}).
\item quando il server riceve il FIN la \func{read} del processo figlio che
gestisce la connessione ritorna restituendo 0 causando così l'uscita dal
ciclo e il ritorno di \code{ServEcho}, a questo punto il processo figlio
Tutto questo riguarda la connessione, c'è però da tenere conto dell'effetto
del procedimento di chiusura del processo figlio nel server (si veda quanto
-esaminato in \secref{sec:proc_termination}). In questo caso avremo l'invio del
-segnale \const{SIGCHLD} al padre, ma dato che non si è installato un
+esaminato in sez.~\ref{sec:proc_termination}). In questo caso avremo l'invio
+del segnale \const{SIGCHLD} al padre, ma dato che non si è installato un
gestore e che l'azione predefinita per questo segnale è quella di essere
ignorato, non avendo predisposto la ricezione dello stato di terminazione,
otterremo che il processo figlio entrerà nello stato di zombie\index{zombie}
-(si riveda quanto illustrato in \secref{sec:sig_sigchld}), come risulterà
+(si riveda quanto illustrato in sez.~\ref{sec:sig_sigchld}), come risulterà
ripetendo il comando \cmd{ps}:
\begin{verbatim}
2356 pts/0 S 0:00 ./echod
Dato che non è il caso di lasciare processi zombie\index{zombie}, occorrerà
ricevere opportunamente lo stato di terminazione del processo (si veda
-\secref{sec:proc_wait}), cosa che faremo utilizzando \const{SIGCHLD} secondo
-quanto illustrato in \secref{sec:sig_sigchld}. Una prima modifica al nostro
+sez.~\ref{sec:proc_wait}), cosa che faremo utilizzando \const{SIGCHLD} secondo
+quanto illustrato in sez.~\ref{sec:sig_sigchld}. Una prima modifica al nostro
server è pertanto quella di inserire la gestione della terminazione dei
processi figli attraverso l'uso di un gestore. Per questo useremo la funzione
-\code{Signal} (che abbiamo illustrato in \figref{fig:sig_Signal_code}), per
+\code{Signal} (che abbiamo illustrato in fig.~\ref{fig:sig_Signal_code}), per
installare il gestore che riceve i segnali dei processi figli terminati già
-visto in \figref{fig:sig_sigchld_handl}. Basterà allora aggiungere il
+visto in fig.~\ref{fig:sig_sigchld_handl}. Basterà allora aggiungere il
seguente codice: \includecodesnip{listati/sigchildhand.c}
\noindent
-all'esempio illustrato in \figref{fig:TCP_echo_server_first_code}.
+all'esempio illustrato in fig.~\ref{fig:TCP_echo_server_first_code}.
In questo modo però si introduce un altro problema. Si ricordi infatti che,
-come spiegato in \secref{sec:sig_gen_beha}, quando un programma si trova in
+come spiegato in sez.~\ref{sec:sig_gen_beha}, quando un programma si trova in
stato di \texttt{sleep} durante l'esecuzione di una system call, questa viene
interrotta alla ricezione di un segnale. Per questo motivo, alla fine
dell'esecuzione del gestore del segnale, se questo ritorna, il programma
accept error: Interrupted system call
\end{verbatim}%#
-Come accennato in \secref{sec:sig_gen_beha} le conseguenze di questo
+Come accennato in sez.~\ref{sec:sig_gen_beha} le conseguenze di questo
comportamento delle system call possono essere superate in due modi diversi,
il più semplice è quello di modificare il codice di \func{Signal} per
richiedere il riavvio automatico delle system call interrotte secondo la
semantica di BSD, usando l'opzione \const{SA\_RESTART} di \func{sigaction};
-rispetto a quanto visto in \figref{fig:sig_Signal_code}. Definiremo allora la
+rispetto a quanto visto in fig.~\ref{fig:sig_Signal_code}. Definiremo allora la
nuova funzione \func{SignalRestart}\footnote{anche questa è definita, insieme
alle altre funzioni riguardanti la gestione dei segnali, nel file
\file{SigHand.c}, il cui contento completo può essere trovato negli esempi
- allegati.} come mostrato in \figref{fig:sig_SignalRestart_code}, ed
+ allegati.} come mostrato in fig.~\ref{fig:sig_SignalRestart_code}, ed
installeremo il gestore usando quest'ultima.
\begin{figure}[!htb]
\end{figure}
Come si può notare questa funzione è identica alla precedente \func{Signal},
-illustrata in \figref{fig:sig_Signal_code}, solo che in questo caso invece di
+illustrata in fig.~\ref{fig:sig_Signal_code}, solo che in questo caso invece di
inizializzare a zero il campo \var{sa\_flags} di \struct{sigaction}, lo si
inizializza (\texttt{\small 5}) al valore \const{SA\_RESTART}. Usando questa
funzione al posto di \func{Signal} nel server non è necessaria nessuna altra
La portabilità nella gestione dei segnali però viene al costo di una
riscrittura parziale del server, la nuova versione di questo, in cui si sono
introdotte una serie di nuove opzioni che ci saranno utili per il debug, è
-mostrata in \figref{fig:TCP_echo_server_code_second}, dove si sono riportate
+mostrata in fig.~\ref{fig:TCP_echo_server_code_second}, dove si sono riportate
la sezioni di codice modificate nella seconda versione del programma, il
codice completo di quest'ultimo si trova nel file \file{TCP\_echod\_second.c}
dei sorgenti allegati alla guida.
permette di impostare la variabile \var{waiting}. Infine si è introdotta una
opzione \texttt{-d} per abilitare il debugging che imposta ad un valore non
nullo la variabile \var{debugging}. Al solito si è omessa da
-\figref{fig:TCP_echo_server_code_second} la sezione di codice relativa alla
+fig.~\ref{fig:TCP_echo_server_code_second} la sezione di codice relativa alla
gestione di tutte queste opzioni, che può essere trovata nel sorgente del
programma.
Tutta la sezione seguente, che crea il socket, cede i privilegi di
amministratore ed eventualmente lancia il programma come demone, è rimasta
invariata e pertanto è stata omessa in
-\figref{fig:TCP_echo_server_code_second}; l'unica modifica effettuata prima
+fig.~\ref{fig:TCP_echo_server_code_second}; l'unica modifica effettuata prima
dell'entrata nel ciclo principale è stata quella di aver introdotto, subito
dopo la chiamata (\texttt{\small 17--20}) alla funzione \func{listen}, una
eventuale pausa con una condizione (\texttt{\small 21}) sulla variabile
l'unica funzione che può mettere il processo padre in stato di sleep nel
periodo in cui un figlio può terminare; si noti infatti come le altre
\index{system call lente} \textit{slow system call}\footnote{si ricordi la
- distinzione fatta in \secref{sec:sig_gen_beha}.} o sono chiamate prima di
+ distinzione fatta in sez.~\ref{sec:sig_gen_beha}.} o sono chiamate prima di
entrare nel ciclo principale, quando ancora non esistono processi figli, o
sono chiamate dai figli stessi e non risentono di \const{SIGCHLD}.
Per questo l'unica modifica sostanziale nel ciclo principale (\texttt{\small
- 23--42}), rispetto precedente versione di \figref{fig:TCP_ServEcho_first}, è
-nella sezione (\texttt{\small 25--31}) in cui si effettua la chiamata di
+ 23--42}), rispetto precedente versione di fig.~\ref{fig:TCP_ServEcho_first},
+è nella sezione (\texttt{\small 25--31}) in cui si effettua la chiamata di
\func{accept}. Quest'ultima viene effettuata (\texttt{\small 26--27})
all'interno di un ciclo di \code{while}\footnote{la sintassi del C relativa a
questo ciclo può non essere del tutto chiara. In questo caso infatti si è
Infine come ulteriore miglioria si è perfezionata la funzione \code{ServEcho},
sia per tenere conto della nuova funzionalità di debugging, che per effettuare
un controllo in caso di errore; il codice della nuova versione è mostrato in
-\figref{fig:TCP_ServEcho_second}.
+fig.~\ref{fig:TCP_ServEcho_second}.
\begin{figure}[!htb]
\footnotesize \centering
\label{fig:TCP_ServEcho_second}
\end{figure}
-Rispetto alla precedente versione di \figref{fig:TCP_ServEcho_first} in questo
-caso si è provveduto a controllare (\texttt{\small 7--10}) il valore di
+Rispetto alla precedente versione di fig.~\ref{fig:TCP_ServEcho_first} in
+questo caso si è provveduto a controllare (\texttt{\small 7--10}) il valore di
ritorno di \func{read} per rilevare un eventuale errore, in modo da stampare
(\texttt{\small 8}) un messaggio di errore e ritornare (\texttt{\small 9})
concludendo la connessione.
\section{I vari scenari critici}
\label{sec:TCP_echo_critical}
-Con le modifiche viste in \secref{sec:TCP_child_hand} il nostro esempio
+Con le modifiche viste in sez.~\ref{sec:TCP_child_hand} il nostro esempio
diventa in grado di affrontare la gestione ordinaria delle connessioni, ma un
server di rete deve tenere conto che, al contrario di quanto avviene per i
server che operano nei confronti di processi presenti sulla stessa macchina,
La prima situazione critica è quella della terminazione precoce, causata da un
qualche errore sulla rete, della connessione effettuata da un client. Come
-accennato in \secref{sec:TCP_func_accept} la funzione \func{accept} riporta
+accennato in sez.~\ref{sec:TCP_func_accept} la funzione \func{accept} riporta
tutti gli eventuali errori di rete pendenti su una connessione sul
\textit{connected socket}. Di norma questo non è un problema, in quanto non
appena completata la connessione, \func{accept} ritorna e l'errore sarà
chiamata di una funzione che opera sul socket.
È però possibile, dal punto di vista teorico, incorrere anche in uno scenario
-del tipo di quello mostrato in \figref{fig:TCP_early_abort}, in cui la
+del tipo di quello mostrato in fig.~\ref{fig:TCP_early_abort}, in cui la
connessione viene abortita sul lato client per un qualche errore di rete con
l'invio di un segmento RST, prima che nel server sia stata chiamata la
funzione \func{accept}.
handshake venga completato e la relativa connessione abortita subito dopo,
prima che il padre, per via del carico della macchina, abbia fatto in tempo ad
eseguire la chiamata ad \func{accept}. Di nuovo si ha una situazione analoga
-a quella illustrata in \figref{fig:TCP_early_abort}, in cui la connessione
+a quella illustrata in fig.~\ref{fig:TCP_early_abort}, in cui la connessione
viene stabilita, ma subito dopo si ha una condizione di errore che la chiude
prima che essa sia stata accettata dal programma.
Questo significa che, oltre alla interruzione da parte di un segnale, che
-abbiamo trattato in \secref{sec:TCP_child_hand} nel caso particolare di
+abbiamo trattato in sez.~\ref{sec:TCP_child_hand} nel caso particolare di
\const{SIGCHLD}, si possono ricevere altri errori non fatali all'uscita di
\func{accept}, che come nel caso precedente, necessitano semplicemente la
ripetizione della chiamata senza che si debba uscire dal programma. In questo
demone, in modo da poter avere il tempo per lanciare e terminare una
connessione usando il programma client. In tal caso infatti, alla terminazione
del client, il socket associato alla connessione viene semplicemente chiuso,
-attraverso la sequenza vista in \secref{sec:TCP_conn_term}, per cui la
+attraverso la sequenza vista in sez.~\ref{sec:TCP_conn_term}, per cui la
\func{accept} ritornerà senza errori, e si avrà semplicemente un end-of-file
al primo accesso al socket. Nel caso di Linux inoltre, anche qualora si
modifichi il client per fargli gestire l'invio di un segmento di RST alla
seguito dal numero di sequenza per il quale si da il ricevuto; quest'ultimo, a
partire dal terzo pacchetto, viene espresso in forma relativa per maggiore
compattezza. Il campo \texttt{win} in ogni riga indica la \textit{advertising
- window} di cui parlavamo in \secref{sec:TCP_TCP_opt}. Allora si può
+ window} di cui parlavamo in sez.~\ref{sec:TCP_TCP_opt}. Allora si può
verificare dall'output del comando come venga appunto realizzata la sequenza
-di pacchetti descritta in \secref{sec:TCP_conn_cre}: prima viene inviato dal
+di pacchetti descritta in sez.~\ref{sec:TCP_conn_cre}: prima viene inviato dal
client un primo pacchetto con il SYN che inizia la connessione, a cui il
server risponde dando il ricevuto con un secondo pacchetto, che a sua volta
porta un SYN, cui il client risponde con un il terzo pacchetto di ricevuto.
facciamo questo vengono immediatamente generati altri due pacchetti. La
terminazione del processo infatti comporta la chiusura di tutti i suoi file
descriptor, il che comporta, per il socket che avevamo aperto, l'inizio della
-sequenza di chiusura illustrata in \secref{sec:TCP_conn_term}. Questo
+sequenza di chiusura illustrata in sez.~\ref{sec:TCP_conn_term}. Questo
significa che dal server partirà un FIN, che è appunto il primo dei due
pacchetti, contraddistinto dalla lettera \texttt{F}, cui seguirà al solito un
ACK da parte del client.
definitiva della connessione anche nel client, dove non comparirà più
nell'output di \cmd{netstat}.
-Come abbiamo accennato in \secref{sec:TCP_conn_term} e come vedremo più avanti
-in \secref{sec:TCP_shutdown} la chiusura di un solo capo di un socket è
+Come abbiamo accennato in sez.~\ref{sec:TCP_conn_term} e come vedremo più avanti
+in sez.~\ref{sec:TCP_shutdown} la chiusura di un solo capo di un socket è
una operazione lecita, per cui la nostra scrittura avrà comunque successo
(come si può constatare lanciando usando \cmd{strace}\footnote{il comando
\cmd{strace} è un comando di debug molto utile che prende come parametro un
del socket, ma è completamente terminato il programma.
Per questo motivo il nostro client proseguirà leggendo dal socket, e dato che
-questo è stato chiuso avremo che, come spiegato in \secref{sec:TCP_conn_term},
-la funzione \func{read} ritorna normalmente con un valore nullo. Questo
-comporta che la seguente chiamata a \func{fputs} non ha effetto (viene
-stampata una stringa nulla) ed il client si blocca di nuovo nella successiva
-chiamata a \func{fgets}. Per questo diventa possibile inserire una terza riga
-e solo dopo averlo fatto si avrà la terminazione del programma.
+questo è stato chiuso avremo che, come spiegato in
+sez.~\ref{sec:TCP_conn_term}, la funzione \func{read} ritorna normalmente con
+un valore nullo. Questo comporta che la seguente chiamata a \func{fputs} non
+ha effetto (viene stampata una stringa nulla) ed il client si blocca di nuovo
+nella successiva chiamata a \func{fgets}. Per questo diventa possibile
+inserire una terza riga e solo dopo averlo fatto si avrà la terminazione del
+programma.
Per capire come questa avvenga comunque, non avendo inserito nel codice nessun
controllo di errore, occorre ricordare che, a parte la bidirezionalità del
flusso dei dati, dal punto di vista del funzionamento nei confronti delle
funzioni di lettura e scrittura, i socket sono del tutto analoghi a delle
-pipe. Allora, da quanto illustrato in \secref{sec:ipc_pipes}, sappiamo che
+pipe. Allora, da quanto illustrato in sez.~\ref{sec:ipc_pipes}, sappiamo che
tutte le volte che si cerca di scrivere su una pipe il cui altro capo non è
aperto il lettura il processo riceve un segnale di \const{SIGPIPE}, e questo è
esattamente quello che avviene in questo caso, e siccome non abbiamo un
modificare il nostro client perché sia in grado di trattare le varie tipologie
di errore, per questo dovremo riscrivere la funzione \func{ClientEcho}, in
modo da controllare gli stati di uscita delle varie chiamate. Si è riportata
-la nuova versione della funzione in \figref{fig:TCP_ClientEcho_second}.
+la nuova versione della funzione in fig.~\ref{fig:TCP_ClientEcho_second}.
\begin{figure}[!htb]
\footnotesize \centering
fare con la necessità di lavorare con più descrittori, nel qual caso diventa
si pone la questione di come fare a non restare bloccati su un socket quando
altri potrebbero essere liberi. Vedremo come affrontare questa problematica in
-\secref{sec:TCP_sock_multiplexing}.
+sez.~\ref{sec:TCP_sock_multiplexing}.
\subsection{Altri scenari di terminazione della connessione}
pacchetto sono cessati, per essere sostituiti da una serie di richieste di
protocollo ARP in cui il client richiede l'indirizzo del server.
-Come abbiamo accennato in \secref{sec:net_tcpip_general} ARP è il protocollo
-che si incarica di trovare le corrispondenze corrispondenze fra indirizzo IP e
-indirizzo hardware sulla scheda di rete. È evidente allora che nel nostro
-caso, essendo client e server sulla stessa rete, è scaduta la voce nella
-\textit{ARP cache}\footnote{la \textit{ARP chache} è una tabella mantenuta
- internamente dal kernel che contiene tutte le corrispondenze fra indirizzi
- IP e indirizzi fisici, ottenute appunto attraverso il protocollo ARP; le
- voci della tabella hanno un tempo di vita limitato, passato il quale scadono
- e devono essere nuovamente richieste.} relativa ad \texttt{anarres}, ed il
-nostro client ha iniziato ad effettuare richieste ARP sulla rete per sapere
-l'IP di quest'ultimo, che essendo scollegato non poteva rispondere. Anche per
-questo tipo di richieste esiste un timeout, per cui dopo un certo numero di
-tentativi il meccanismo si è interrotto, e l'errore riportato al programma a
-questo punto è stato \errcode{EHOSTUNREACH}, in quanto non si era più in grado
-di contattare il server.
+Come abbiamo accennato in sez.~\ref{sec:net_tcpip_general} ARP è il protocollo
+che si incarica di trovare le corrispondenze fra indirizzo IP e indirizzo
+hardware sulla scheda di rete. È evidente allora che nel nostro caso, essendo
+client e server sulla stessa rete, è scaduta la voce nella \textit{ARP
+ cache}\footnote{la \textit{ARP chache} è una tabella mantenuta internamente
+ dal kernel che contiene tutte le corrispondenze fra indirizzi IP e indirizzi
+ fisici, ottenute appunto attraverso il protocollo ARP; le voci della tabella
+ hanno un tempo di vita limitato, passato il quale scadono e devono essere
+ nuovamente richieste.} relativa ad \texttt{anarres}, ed il nostro client ha
+iniziato ad effettuare richieste ARP sulla rete per sapere l'IP di
+quest'ultimo, che essendo scollegato non poteva rispondere. Anche per questo
+tipo di richieste esiste un timeout, per cui dopo un certo numero di tentativi
+il meccanismo si è interrotto, e l'errore riportato al programma a questo
+punto è stato \errcode{EHOSTUNREACH}, in quanto non si era più in grado di
+contattare il server.
Un altro errore possibile in questo tipo di situazione, che si può avere
quando la macchina è su una rete remota, è \errcode{ENETUNREACH}; esso viene
si vuole che il client sia in grado di accorgersi del crollo del server anche
quando non sta effettuando uno scambio di dati, è possibile usare una
impostazione speciale del socket (ci torneremo in
-\secref{sec:TCP_sock_options}) che provvede all'esecuzione di questo
+sez.~\ref{sec:TCP_sock_options}) che provvede all'esecuzione di questo
controllo.
\section{L'uso dell'I/O multiplexing}
\label{sec:TCP_sock_multiplexing}
Affronteremo in questa sezione l'utilizzo dell'I/O multiplexing, affrontato in
-\secref{sec:file_multiplexing}, nell'ambito delle applicazioni di rete. Già in
-\secref{sec:TCP_server_crash} era emerso il problema relativo al client del
-servizio echo che non era in grado di accorgersi della terminazione precoce
-del server, essendo bloccato nella lettura dei dati immessi da tastiera.
-
-Abbiamo visto in \secref{sec:file_multiplexing} quali sono le funzionalità del
-sistema che ci permettono di tenere sotto controllo più file descriptor in
+sez.~\ref{sec:file_multiplexing}, nell'ambito delle applicazioni di rete. Già
+in sez.~\ref{sec:TCP_server_crash} era emerso il problema relativo al client
+del servizio echo che non era in grado di accorgersi della terminazione
+precoce del server, essendo bloccato nella lettura dei dati immessi da
+tastiera.
+
+Abbiamo visto in sez.~\ref{sec:file_multiplexing} quali sono le funzionalità
+del sistema che ci permettono di tenere sotto controllo più file descriptor in
contemporanea; in quella occasione non abbiamo fatto esempi, in quanto quando
si tratta con file normali questa tipologia di I/O normalmente non viene
usata, è invece un caso tipico delle applicazioni di rete quello di dover
Iniziamo con la prima delle funzioni usate per l'I/O multiplexing,
\func{select}; il suo funzionamento è già stato descritto in dettaglio in
-\secref{sec:file_multiplexing} e non staremo a ripetere quanto detto lì;
+sez.~\ref{sec:file_multiplexing} e non staremo a ripetere quanto detto lì;
sappiamo che la funzione ritorna quando uno o più dei file descriptor messi
sotto controllo è pronto per la relativa operazione.
sufficiente a superare il valore di una \textsl{soglia di basso livello} (il
cosiddetto \textit{low watermark}). Questo valore è espresso in numero di
byte e può essere impostato con l'opzione del socket \const{SO\_RCVLOWAT}
- (tratteremo le opzioni dei socket in \secref{sec:TCP_sock_options}); il suo
- valore di default è 1 per i socket TCP e UDP. In questo caso una operazione
- di lettura avrà successo e leggerà un numero di byte maggiore di zero.
+ (tratteremo le opzioni dei socket in sez.~\ref{sec:TCP_sock_options}); il
+ suo valore di default è 1 per i socket TCP e UDP. In questo caso una
+ operazione di lettura avrà successo e leggerà un numero di byte maggiore di
+ zero.
\item il lato in lettura della connessione è stato chiuso; si è cioè ricevuto
- un segmento FIN (si ricordi quanto illustrato in \secref{sec:TCP_conn_term})
- sulla connessione. In questo caso una operazione di lettura avrà successo,
- ma non risulteranno presenti dati (in sostanza \func{read} ritornerà con un
- valore nullo) per indicare la condizione di end-of-file.
+ un segmento FIN (si ricordi quanto illustrato in
+ sez.~\ref{sec:TCP_conn_term}) sulla connessione. In questo caso una
+ operazione di lettura avrà successo, ma non risulteranno presenti dati (in
+ sostanza \func{read} ritornerà con un valore nullo) per indicare la
+ condizione di end-of-file.
\item c'è stato un errore sul socket. In questo caso una operazione di lettura
non si bloccherà ma restituirà una condizione di errore (ad esempio
\func{read} restituirà -1) e imposterà la variabile \var{errno} al relativo
- valore. Vedremo in \secref{sec:TCP_sock_options} come sia possibile estrarre
- e cancellare errori pendenti su un socket usando l'opzione
+ valore. Vedremo in sez.~\ref{sec:TCP_sock_options} come sia possibile
+ estrarre e cancellare errori pendenti su un socket usando l'opzione
\const{SO\_ERROR}.
\item quando si sta utilizzando un \textit{listening socket} ed ci sono delle
connessioni completate. In questo caso la funzione \func{accept} non si
bloccherà.\footnote{in realtà questo non è sempre vero, come accennato in
- \secref{sec:TCP_conn_early_abort} una connessione può essere abortita
+ sez.~\ref{sec:TCP_conn_early_abort} una connessione può essere abortita
dalla ricezione di un segmento RST una volta che è stata completata,
allora se questo avviene dopo che \func{select} è ritornata, ma prima
della chiamata ad \func{accept}, quest'ultima, in assenza di altre
\item c'è stato un errore sul socket. In questo caso una operazione di
scrittura non si bloccherà ma restituirà una condizione di errore ed
imposterà opportunamente la variabile \var{errno}. Vedremo in
- \secref{sec:TCP_sock_options} come sia possibile estrarre e cancellare
+ sez.~\ref{sec:TCP_sock_options} come sia possibile estrarre e cancellare
errori pendenti su un socket usando l'opzione \const{SO\_ERROR}.
\end{itemize*}
che un socket (che sarà riportato nel terzo insieme di file descriptor) ha una
condizione di eccezione pendente, e cioè la ricezione sul socket di dati
\textsl{fuori banda} (o \textit{out-of-band}), una caratteristica specifica
-dei socket TCP su cui torneremo in \secref{sec:TCP_urgent_data}.
+dei socket TCP su cui torneremo in sez.~\ref{sec:TCP_urgent_data}.
Si noti come nel caso della lettura \func{select} si applichi anche ad
operazioni che non hanno nulla a che fare con l'I/O di dati come il
Abbiamo incontrato la problematica tipica che conduce all'uso dell'I/O
multiplexing nella nostra analisi degli errori in
-\secref{sec:TCP_conn_early_abort}, quando il nostro client non era in grado di
-rendersi conto di errori sulla connessione essendo impegnato nella attesa di
-dati in ingresso dallo standard input.
+sez.~\ref{sec:TCP_conn_early_abort}, quando il nostro client non era in grado
+di rendersi conto di errori sulla connessione essendo impegnato nella attesa
+di dati in ingresso dallo standard input.
In questo caso il problema è quello di dover tenere sotto controllo due
diversi file descriptor, lo standard input, da cui viene letto il testo che
Nel nostro caso quello che ci interessa è non essere bloccati in lettura sullo
standard input in caso di errori sulla connessione o chiusura della stessa da
parte del server. Entrambi questi casi possono essere rilevati usando
-\func{select}, per quanto detto in \secref{sec:TCP_sock_select}, mettendo
+\func{select}, per quanto detto in sez.~\ref{sec:TCP_sock_select}, mettendo
sotto osservazione i file descriptor per la condizione di essere pronti in
lettura: sia infatti che si ricevano dati, che la connessione sia chiusa
regolarmente (con la ricezione di un segmento FIN) che si riceva una
Riprendiamo allora il codice del client, modificandolo per l'uso di
\func{select}. Quello che dobbiamo modificare è la funzione \func{ClientEcho}
-di \figref{fig:TCP_ClientEcho_second}, dato che tutto il resto, che riguarda
+di fig.~\ref{fig:TCP_ClientEcho_second}, dato che tutto il resto, che riguarda
le modalità in cui viene stabilita la connessione con il server, resta
assolutamente identico. La nostra nuova versione di \func{ClientEcho}, la
-terza della serie, è riportata in \figref{fig:TCP_ClientEcho_third}, il codice
-completo si trova nel file \file{TCP\_echo\_third.c} dei sorgenti allegati alla
-guida.
+terza della serie, è riportata in fig.~\ref{fig:TCP_ClientEcho_third}, il
+codice completo si trova nel file \file{TCP\_echo\_third.c} dei sorgenti
+allegati alla guida.
In questo caso la funzione comincia (\texttt{\small 8--9}) con l'azzeramento
del file descriptor set \var{fset} e l'impostazione del valore \var{maxfd}, da
scritto. Ma adesso il client diventa capace di accorgersi immediatamente della
terminazione del server; in tal caso infatti il server chiuderà il socket
connesso, ed alla ricezione del FIN la funzione \func{select} ritornerà (come
-illustrato in \secref{sec:TCP_sock_select}) segnalando una condizione di end
+illustrato in sez.~\ref{sec:TCP_sock_select}) segnalando una condizione di end
of file, per cui il nostro client potrà uscire immediatamente.
-Riprendiamo la situazione affrontata in \secref{sec:TCP_server_crash},
+Riprendiamo la situazione affrontata in sez.~\ref{sec:TCP_server_crash},
terminando il server durante una connessione, in questo caso quello che
otterremo, una volta scritta una prima riga ed interrotto il server con un
\texttt{C-c}, sarà:
connesso è stato chiuso ed uscire immediatamente.
Veniamo allora agli altri scenari di terminazione anomala visti in
-\secref{sec:TCP_conn_crash}. Il primo di questi è l'interruzione fisica della
+sez.~\ref{sec:TCP_conn_crash}. Il primo di questi è l'interruzione fisica della
connessione; in questo caso avremo un comportamento analogo al precedente, in
cui si scrive una riga e non si riceve risposta dal server e non succede
niente fino a quando non si riceve un errore di \errcode{EHOSTUNREACH} o
in cui, una volta riconnessa la rete, tutto quello che abbiamo scritto durante
il periodo di disconnessione restituito indietro e stampato immediatamente.
-Lo stesso comportamento visto in \secref{sec:TCP_server_crash} si riottiene
+Lo stesso comportamento visto in sez.~\ref{sec:TCP_server_crash} si riottiene
nel caso di un crollo completo della macchina su cui sta il server. In questo
caso di nuovo il client non è in grado di accorgersi di niente dato che si
suppone che il programma server non venga terminato correttamente, ma si
\subsection{La funzione \func{shutdown}}
\label{sec:TCP_shutdown}
-Come spiegato in \secref{sec:TCP_conn_term} il procedimento di chiusura di un
+Come spiegato in sez.~\ref{sec:TCP_conn_term} il procedimento di chiusura di un
socket TCP prevede che da entrambe le parti venga emesso un segmento FIN. È
pertanto del tutto normale dal punto di vista del protocollo che uno dei due
capi chiuda la connessione, quando l'altro capo la lascia
aperta.\footnote{abbiamo incontrato questa situazione nei vari scenari critici
- di \secref{sec:TCP_echo_critical}.}
+ di sez.~\ref{sec:TCP_echo_critical}.}
È pertanto possibile avere una situazione in cui un capo della connessione non
avendo più nulla da scrivere, possa chiudere il socket, segnalando così
closed}.
Il problema che si pone è che se la chiusura del socket è effettuata con la
-funzione \func{close}, come spiegato in \secref{sec:TCP_func_close}, si perde
+funzione \func{close}, come spiegato in sez.~\ref{sec:TCP_func_close}, si perde
ogni possibilità di poter rileggere quanto l'altro capo può continuare a
scrivere. Per poter permettere allora di segnalare che si è concluso con la
scrittura, continuando al contempo a leggere quanto può provenire dall'altro
l'emissione di un segmento FIN, secondo la procedura chiamata
\textit{half-close}. Tutti i dati presenti nel buffer di scrittura prima
della chiamata saranno inviati, seguiti dalla sequenza di chiusura
- illustrata in \secref{sec:TCP_conn_term}.
+ illustrata in sez.~\ref{sec:TCP_conn_term}.
\item[\macro{SHUT\_RDWR}] chiude sia il lato in lettura che quello in
scrittura del socket. È equivalente alla chiamata in sequenza con
\macro{SHUT\_RD} e \macro{SHUT\_WR}.
cui si avrebbe potuto avere l'impressione che sia una corrispondenza univoca
fra un socket ed il file descriptor con cui vi si accede. Questo non è
assolutamente vero, (e lo abbiamo già visto nel codice del server di
-\figref{fig:TCP_echo_server_first_code}), ed è invece assolutamente normale
+fig.~\ref{fig:TCP_echo_server_first_code}), ed è invece assolutamente normale
che, come per gli altri oggetti, ci possano essere più file descriptor che
fanno riferimento allo stesso socket.
di \func{close} si limiterà a deallocare nel processo corrente il file
descriptor utilizzato, ma il socket resterà pienamente accessibile attraverso
tutti gli altri riferimenti. Se torniamo all'esempio originale del server di
-\figref{fig:TCP_echo_server_first_code} abbiamo infatti che ci sono due
+fig.~\ref{fig:TCP_echo_server_first_code} abbiamo infatti che ci sono due
\func{close}, una sul socket connesso nel padre, ed una sul socket in ascolto
nel figlio, ma queste non effettuano nessuna chiusura reale di detti socket,
dato che restano altri riferimenti attivi, uno al socket connesso nel figlio
quello che viene stimato con l'uso del comando \cmd{ping}.
A questo punto, se torniamo al codice mostrato in
-\figref{fig:TCP_ClientEcho_third}, possiamo vedere che mentre i pacchetti sono
-in transito sulla rete il client continua a leggere e a scrivere fintanto che
-il file in ingresso finisce. Però non appena viene ricevuto un end-of-file in
-ingresso il nostro client termina. Nel caso interattivo, in cui si inviavano
-brevi stringhe una alla volta, c'era sempre il tempo di eseguire la lettura
-completa di quanto il server rimandava indietro. In questo caso invece, quando
-il client termina, essendo la comunicazione saturata e a piena velocità, ci
-saranno ancora pacchetti in transito sulla rete che devono arrivare al server
-e poi tornare indietro, ma siccome il client esce immediatamente dopo la fine
-del file in ingresso, questi non faranno a tempo a completare il percorso e
-verranno persi.
+fig.~\ref{fig:TCP_ClientEcho_third}, possiamo vedere che mentre i pacchetti
+sono in transito sulla rete il client continua a leggere e a scrivere fintanto
+che il file in ingresso finisce. Però non appena viene ricevuto un end-of-file
+in ingresso il nostro client termina. Nel caso interattivo, in cui si
+inviavano brevi stringhe una alla volta, c'era sempre il tempo di eseguire la
+lettura completa di quanto il server rimandava indietro. In questo caso
+invece, quando il client termina, essendo la comunicazione saturata e a piena
+velocità, ci saranno ancora pacchetti in transito sulla rete che devono
+arrivare al server e poi tornare indietro, ma siccome il client esce
+immediatamente dopo la fine del file in ingresso, questi non faranno a tempo a
+completare il percorso e verranno persi.
Per evitare questo tipo di problema, invece di uscire una volta completata la
lettura del file in ingresso, occorre usare \func{shutdown} per effettuare la
\label{fig:TCP_ClientEcho}
\end{figure}
-Si è allora riportato in \figref{fig:TCP_ClientEcho} la versione finale della
+Si è allora riportato in fig.~\ref{fig:TCP_ClientEcho} la versione finale della
nostra funzione \func{ClientEcho}, in grado di gestire correttamente l'intero
flusso di dati fra client e server. Il codice completo del client,
comprendente la gestione delle opzioni a riga di comando e le istruzioni per
distribuito coi sorgenti allegati alla guida.
La nuova versione è molto simile alla precedente di
-\figref{fig:TCP_ClientEcho_third}; la prima differenza è l'introduzione
+fig.~\ref{fig:TCP_ClientEcho_third}; la prima differenza è l'introduzione
(\texttt{\small 7}) della variabile \var{eof}, inizializzata ad un valore
nullo, che serve a mantenere traccia dell'avvenuta conclusione della lettura
del file in ingresso.
connessione.\footnote{ne faremo comunque una implementazione diversa rispetto
a quella presentata da Stevens in \cite{UNP1}.}
-La struttura del nuovo server è illustrata in \figref{fig:TCP_echo_multiplex},
-in questo caso avremo un solo processo che ad ogni nuova connessione da parte
-di un client sul socket in ascolto si limiterà a registrare l'entrata in uso
-di un nuovo file descriptor ed utilizzerà \func{select} per rilevare la
-presenza di dati in arrivo su tutti i file descriptor attivi, operando
-direttamente su ciascuno di essi.
+La struttura del nuovo server è illustrata in
+fig.~\ref{fig:TCP_echo_multiplex}, in questo caso avremo un solo processo che
+ad ogni nuova connessione da parte di un client sul socket in ascolto si
+limiterà a registrare l'entrata in uso di un nuovo file descriptor ed
+utilizzerà \func{select} per rilevare la presenza di dati in arrivo su tutti i
+file descriptor attivi, operando direttamente su ciascuno di essi.
\begin{figure}[htb]
\centering
\end{figure}
La sezione principale del codice del nuovo server è illustrata in
-\figref{fig:TCP_SelectEchod}. Si è tralasciata al solito la gestione delle
+fig.~\ref{fig:TCP_SelectEchod}. Si è tralasciata al solito la gestione delle
opzioni, che è identica alla versione precedente. Resta invariata anche tutta
la parte relativa alla gestione dei segnali, degli errori, e della cessione
dei privilegi, così come è identica la gestione della creazione del socket (si
può fare riferimento al codice già illustrato in
-\secref{sec:TCPsimp_server_main}); al solito il codice completo del server è
+sez.~\ref{sec:TCPsimp_server_main}); al solito il codice completo del server è
disponibile coi sorgenti allegati nel file \texttt{select\_echod.c}.
\begin{figure}[!htbp]
In questo caso, una volta aperto e messo in ascolto il socket, tutto quello
che ci servirà sarà chiamare \func{select} per rilevare la presenza di nuove
connessioni o di dati in arrivo, e processarli immediatamente. Per
-implementare lo schema mostrato in \figref{fig:TCP_echo_multiplex}, il
+implementare lo schema mostrato in fig.~\ref{fig:TCP_echo_multiplex}, il
programma usa una tabella dei socket connessi mantenuta nel vettore
\var{fd\_open} dimensionato al valore di \macro{FD\_SETSIZE}, ed una variabile
\var{max\_fd} per registrare il valore più alto dei file descriptor aperti.
trovati attivi.
Per far questo si usa la caratteristica dei file descriptor, descritta in
-\secref{sec:file_open}, per cui il kernel associa sempre ad ogni nuovo file il
-file descriptor con il valore più basso disponibile. Questo fa sì che si possa
-eseguire il ciclo (\texttt{\small 8}) a partire da un valore minimo, che sarà
-sempre quello del socket in ascolto, mantenuto in \var{list\_fd}, fino al
+sez.~\ref{sec:file_open}, per cui il kernel associa sempre ad ogni nuovo file
+il file descriptor con il valore più basso disponibile. Questo fa sì che si
+possa eseguire il ciclo (\texttt{\small 8}) a partire da un valore minimo, che
+sarà sempre quello del socket in ascolto, mantenuto in \var{list\_fd}, fino al
valore massimo di \var{max\_fd} che dovremo aver cura di tenere aggiornato.
Dopo di che basterà controllare (\texttt{\small 9}) nella nostra tabella se il
file descriptor è in uso o meno,\footnote{si tenga presente che benché il
Una volta inizializzato con i socket aperti il nostro \textit{file descriptor
set} potremo chiamare \func{select} per fargli osservare lo stato degli
stessi (in lettura, presumendo che la scrittura sia sempre consentita). Come
-per il precedente esempio di \secref{sec:TCP_child_hand}, essendo questa
+per il precedente esempio di sez.~\ref{sec:TCP_child_hand}, essendo questa
l'unica funzione che può bloccarsi, ed essere interrotta da un segnale, la
eseguiremo (\texttt{\small 11--12}) all'interno di un ciclo di \code{while}
che la ripete indefinitamente qualora esca con un errore di \errcode{EINTR}.
\func{FullWrite} per riscriverli indietro sul socket stesso, avendo cura di
uscire con un messaggio in caso di errore (\texttt{\small 50--53}). Si noti
che nel ciclo si esegue una sola lettura, contrariamente a quanto fatto con la
-precedente versione (si riveda il codice di \secref{fig:TCP_ServEcho_second})
+precedente versione (si riveda il codice di fig.~\ref{fig:TCP_ServEcho_second})
in cui si continuava a leggere fintanto che non si riceveva un
\textit{end-of-file}, questo perché usando l'\textit{I/O multiplexing} non si
vuole essere bloccati in lettura. L'uso di \func{select} ci permette di
impiegando la funzione \func{select}; questo è quello che avviene nella
maggior parte dei casi, in quanto essa è nata sotto BSD proprio per affrontare
queste problematiche con i socket. Abbiamo però visto in
-\secref{sec:file_multiplexing} come la funzione \func{poll} possa costituire
+sez.~\ref{sec:file_multiplexing} come la funzione \func{poll} possa costituire
una alternativa a \func{select}, con alcuni vantaggi.\footnote{non soffrendo
delle limitazioni dovute all'uso dei \textit{file descriptor set}.}
-Ancora una volta in \secref{sec:file_poll} abbiamo trattato la funzione in
+Ancora una volta in sez.~\ref{sec:file_poll} abbiamo trattato la funzione in
maniera generica, parlando di file descriptor, ma come per \func{select}
quando si ha a che fare con dei socket il concetto di essere \textsl{pronti}
per l'I/O deve essere specificato nei dettagli, per tener conto delle
\end{itemize}
Come esempio dell'uso di \func{poll} proviamo allora a reimplementare il
-server \textit{echo} secondo lo schema di \figref{fig:TCP_echo_multiplex}
+server \textit{echo} secondo lo schema di fig.~\ref{fig:TCP_echo_multiplex}
usando \func{poll} al posto di \func{select}. In questo caso dovremo fare
qualche modifica, per tenere conto della diversa sintassi delle due funzioni,
ma la struttura del programma resta sostanzialmente la stessa.
\label{fig:TCP_PollEchod}
\end{figure}
-In \figref{fig:TCP_PollEchod} è riportata la sezione principale della nuova
+In fig.~\ref{fig:TCP_PollEchod} è riportata la sezione principale della nuova
versione del server, la versione completa del codice è riportata nel file
\file{poll\_echod.c} dei sorgenti allegati alla guida. Al solito nella figura
si sono tralasciate la gestione delle opzioni, la creazione del socket in
uscita e notifica in caso si errore (\texttt{\small 49--52}).
Come si può notare la logica del programma è identica a quella vista in
-\figref{fig:TCP_SelectEchod} per l'analogo server basato su \func{select}; la
+fig.~\ref{fig:TCP_SelectEchod} per l'analogo server basato su \func{select}; la
sola differenza significativa è che in questo caso non c'è bisogno di
rigenerare i file descriptor set in quanto l'uscita è indipendente dai dati in
ingresso. Si applicano comunque anche a questo server le considerazioni finali
-di \secref{sec:TCP_serv_select}.
+di sez.~\ref{sec:TCP_serv_select}.
In questa appendice tratteremo i vari protocolli relativi al livello di
trasporto.\footnote{al solito per la definizione dei livelli si faccia
- riferimento alle spiegazioni fornite in \ref{sec:net_protocols}.} In
+ riferimento alle spiegazioni fornite in sez.~\ref{sec:net_protocols}.} In
particolare gran parte del capitolo sarà dedicato al più importante di questi,
il TCP, che è pure il più complesso ed utilizzato su internet.
\subsection{Gli stati del TCP}
\label{sec:TCP_states}
-In \secref{sec:TCP_connession} abbiamo descritto in dettaglio le modalità con
+In sez.~\ref{sec:TCP_connession} abbiamo descritto in dettaglio le modalità con
cui il protocollo TCP avvia e conclude una connessione, ed abbiamo accennato
alla presenza dei vari stati del protocollo. In generale infatti il
funzionamento del protocollo segue una serie di regole, che possono essere
riassunte nel comportamento di una macchina a stati, il cui diagramma di
-transizione è riportato in \figref{fig:TCP_state_diag}.
+transizione è riportato in fig.~\ref{fig:TCP_state_diag}.
\begin{figure}[htb]
Il protocollo prevede l'esistenza di 11 diversi stati per una connessione ed
un insieme di regole per le transizioni da uno stato all'altro basate sullo
stato corrente, sull'operazione effettuata dall'applicazione o sul tipo di
-segmento ricevuto; i nomi degli stati mostrati in \figref{fig:TCP_state_diag}
-sono gli stessi che vengono riportati del comando \cmd{netstat} nel campo
-\textit{State}.
+segmento ricevuto; i nomi degli stati mostrati in
+fig.~\ref{fig:TCP_state_diag} sono gli stessi che vengono riportati del
+comando \cmd{netstat} nel campo \textit{State}.