%% fileunix.tex
%%
-%% Copyright (C) 2000-2006 Simone Piccardi. Permission is granted to
+%% Copyright (C) 2000-2007 Simone Piccardi. Permission is granted to
%% copy, distribute and/or modify this document under the terms of the GNU Free
%% Documentation License, Version 1.1 or any later version published by the
%% Free Software Foundation; with the Invariant Sections being "Un preambolo",
Esamineremo in questo capitolo la prima delle due interfacce di programmazione
-per i file, quella dei \textit{file descriptor}\index{file!descriptor},
+per i file, quella dei \index{file!descriptor} \textit{file descriptor},
nativa di Unix. Questa è l'interfaccia di basso livello provvista direttamente
dalle system call, che non prevede funzionalità evolute come la
bufferizzazione o funzioni di lettura o scrittura formattata, e sulla quale è
\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 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
+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 sez.~\ref{sec:file_vfs_work}). Questo si fa aprendo il file
+con la funzione \func{open} che provvederà a localizzare \index{inode} l'inode
+del file e inizializzare i puntatori che rendono disponibili le funzioni che
+il VFS mette a disposizione (riportate in
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.
\item il valore della posizione corrente (l'\textit{offset}) nel file (nel
campo \var{f\_pos}).
\item un puntatore \index{inode} all'inode\footnote{nel kernel 2.4.x si è in
- realtà passati ad un puntatore ad una struttura \struct{dentry} che punta a
- sua volta all'inode\index{inode} passando per la nuova struttura del VFS.}
- del file.
+ realtà passati ad un puntatore ad una struttura \struct{dentry} che punta
+ a sua volta \index{inode} all'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 sez.~\ref{sec:file_vfs_work}} che si possono usare
% sul file.
Ritorneremo su questo schema più volte, dato che esso è fondamentale per
capire i dettagli del funzionamento dell'interfaccia dei \textit{file
descriptor}.
+
\index{file!descriptor|)}
\begin{figure}[htb]
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}).
+stesso \index{inode} 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
\label{sec:file_open}
La funzione \funcd{open} è la funzione fondamentale per accedere ai file, ed è
-quella che crea l'associazione fra un \itindex{pathname}\textit{pathname} ed
-un file descriptor, il suo prototipo è:
+quella che crea l'associazione fra un \itindex{pathname} \textit{pathname} ed
+un \index{file!descriptor} file descriptor, il suo prototipo è:
\begin{functions}
\headdecl{sys/types.h}
\headdecl{sys/stat.h}
\footnotetext[2]{la pagina di manuale di \func{open} segnala che questa
opzione è difettosa su NFS, e che i programmi che la usano per stabilire un
- \textsl{file di lock}\index{file!di lock} possono incorrere in una
- \textit{race condition}\itindex{race~condition}. Si consiglia come
+ \index{file!di lock} \textsl{file di lock} possono incorrere in una
+ \itindex{race~condition} \textit{race condition}. Si consiglia come
alternativa di usare un file con un nome univoco e la funzione \func{link}
per verificarne l'esistenza (vedi sez.~\ref{sec:ipc_file_lock}).}
-\footnotetext[3]{acronimo di \textit{Denial of
- Service}\itindex{Denial~of~Service~(DoS)}, si chiamano così attacchi
- miranti ad impedire un servizio causando una qualche forma di carico
- eccessivo per il sistema, che resta bloccato nelle risposte all'attacco.}
-
\begin{table}[!htb]
\centering
\footnotesize
- \begin{tabular}[c]{|l|p{12cm}|}
+ \begin{tabular}[c]{|l|p{13cm}|}
\hline
\textbf{Flag} & \textbf{Descrizione} \\
\hline
\label{tab:file_open_flags}
\end{table}
+\footnotetext[3]{acronimo di \itindex{Denial~of~Service~(DoS)} \textit{Denial
+ of Service}, si chiamano così attacchi miranti ad impedire un servizio
+ causando una qualche forma di carico eccessivo per il sistema, che resta
+ bloccato nelle risposte all'attacco.}
+
\footnotetext[4]{il problema è che NFS non supporta la scrittura in
\itindex{append~mode} \textit{append}, ed il kernel deve simularla, ma
questo comporta la possibilità di una \itindex{race~condition} \textit{race
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 \itindex{race~condition}\textit{race
+(questa è una potenziale sorgente di \itindex{race~condition} \textit{race
condition}, vedi sez.~\ref{sec:file_atomic}).
Non tutti i file supportano la capacità di eseguire una \func{lseek}, in
\label{fig:file_mult_acc}
\end{figure}
-Il primo caso è quello in cui due processi diversi aprono lo stesso file
-su disco; sulla base di quanto visto in sez.~\ref{sec:file_fd} avremo una
+Il primo caso è quello in cui due processi diversi aprono lo stesso file 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
-inode\index{inode} su disco.
+nella \itindex{file~table} \textit{file table} faranno però riferimento allo
+stesso \index{inode} inode su disco.
Questo significa che ciascun processo avrà la sua posizione corrente sul file,
la sua modalità di accesso e versioni proprie di tutte le proprietà che
-vengono mantenute nella sua voce della \textit{file table}. Questo ha
-conseguenze specifiche sugli effetti della possibile azione simultanea sullo
-stesso file, in particolare occorre tenere presente che:
+vengono mantenute nella sua voce della \itindex{file~table} \textit{file
+ table}. Questo ha conseguenze specifiche sugli effetti della possibile
+azione simultanea sullo stesso file, in particolare occorre tenere presente
+che:
\begin{itemize}
\item ciascun processo può scrivere indipendentemente; dopo ciascuna
\func{write} la posizione corrente sarà cambiata solo nel processo. Se la
scrittura eccede la dimensione corrente del file questo verrà esteso
- automaticamente con l'aggiornamento del campo \var{i\_size}
- nell'inode\index{inode}.
+ automaticamente con l'aggiornamento del campo \var{i\_size} \index{inode}
+ nell'inode.
\item se un file è in modalità \itindex{append~mode} \const{O\_APPEND} tutte
le volte che viene effettuata una scrittura la posizione corrente viene
- prima impostata alla dimensione corrente del file letta
- dall'inode\index{inode}. Dopo la scrittura il file viene automaticamente
- esteso.
+ prima impostata alla dimensione corrente del file letta \index{inode}
+ dall'inode. Dopo la scrittura il file viene automaticamente esteso.
\item l'effetto di \func{lseek} è solo quello di cambiare il campo
- \var{f\_pos} nella struttura \struct{file} della \textit{file table}, non
- c'è nessuna operazione sul file su disco. Quando la si usa per porsi alla
- fine del file la posizione viene impostata leggendo la dimensione corrente
- dall'inode\index{inode}.
+ \var{f\_pos} nella struttura \struct{file} della \itindex{file~table}
+ \textit{file table}, non c'è nessuna operazione sul file su disco. Quando la
+ si usa per porsi alla fine del file la posizione viene impostata leggendo la
+ dimensione corrente \index{inode} dall'inode.
\end{itemize}
\begin{figure}[htb]
\end{figure}
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 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.
+puntino alla stessa voce nella \itindex{file~table} \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
+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
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 sez.~\ref{sec:file_lseek} impostare la posizione alla
-fine del file e poi scrivere può condurre ad una
-\itindex{race~condition}\textit{race condition}: infatti può succedere che un
-secondo processo scriva alla fine del file fra la \func{lseek} e la
-\func{write}; in questo caso, come abbiamo appena visto, il file sarà esteso,
-ma il nostro primo processo avrà ancora la posizione corrente impostata con la
-\func{lseek} che non corrisponde più alla fine del file, e la successiva
-\func{write} sovrascriverà i dati del secondo processo.
+fine del file e poi scrivere può condurre ad una \itindex{race~condition}
+\textit{race condition}: infatti può succedere che un secondo processo scriva
+alla fine del file fra la \func{lseek} e la \func{write}; in questo caso, come
+abbiamo appena visto, il file sarà esteso, ma il nostro primo processo avrà
+ancora la posizione corrente impostata con la \func{lseek} che non corrisponde
+più alla fine del file, e la successiva \func{write} sovrascriverà i dati del
+secondo processo.
Il problema è che usare due system call in successione non è un'operazione
atomica; il problema è stato risolto introducendo la modalità
atomica.
Un altro caso tipico in cui è necessaria l'atomicità è quello in cui si vuole
-creare un \textsl{file di lock}\index{file!di lock}, bloccandosi se il file
+creare un \textsl{file di lock} \index{file!di lock}, bloccandosi se il file
esiste. In questo caso la sequenza logica porterebbe a verificare prima
l'esistenza del file con una \func{stat} per poi crearlo con una \func{creat};
-di nuovo avremmo la possibilità di una \textit{race
- condition}\itindex{race~condition} da parte di un altro processo che crea lo
-stesso file fra il controllo e la creazione.
+di nuovo avremmo la possibilità di una \itindex{race~condition} \textit{race
+ condition} da parte di un altro processo che crea lo stesso file fra il
+controllo e la creazione.
Per questo motivo sono stati introdotti per \func{open} i due flag
\const{O\_CREAT} e \const{O\_EXCL}. In questo modo l'operazione di controllo
file specificato, ed attendono fino alla conclusione delle operazioni;
\func{fsync} forza anche la sincronizzazione dei metadati del file (che
riguardano sia le modifiche alle tabelle di allocazione dei settori, che gli
-altri dati contenuti nell'inode\index{inode} che si leggono con \func{fstat},
+altri dati contenuti \index{inode} nell'inode che si leggono con \func{fstat},
come i tempi del file).
Si tenga presente che questo non comporta la sincronizzazione della
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
- sez.~\ref{sec:file_asyncronous_operation}) e il \textit{file locking}
- \index{file!locking} (vedi sez.~\ref{sec:file_locking}).}
+ sez.~\ref{sec:file_asyncronous_operation}) e il \index{file!locking}
+ \textit{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},
massimo numero di descrittori consentito.
\item[\const{F\_SETFD}] imposta il valore del \textit{file descriptor flag} al
valore specificato con \param{arg}. Al momento l'unico bit usato è quello di
- \textit{close-on-exec}\itindex{close-on-exec}, identificato dalla costante
+ \itindex{close-on-exec} \textit{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 sez.~\ref{sec:proc_exec}). Ritorna un
valore nullo in caso di successo e $-1$ in caso di errore.
dei segnali \const{SIGIO} e \const{SIGURG} per gli eventi associati al file
descriptor \param{fd}. Nel caso di un \textit{process group} viene
restituito un valore negativo il cui valore assoluto corrisponde
- all'identificatore del \itindex{process~group}\textit{process group}. In
+ all'identificatore del \itindex{process~group} \textit{process group}. In
caso di errore viene restituito $-1$.
\item[\const{F\_SETOWN}] imposta, con il valore dell'argomento \param{arg},
l'identificatore del processo o del \itindex{process~group} \textit{process
valore nullo in caso di successo o $-1$ in caso di errore. Questa
funzionalità avanzata è trattata in dettaglio in
sez.~\ref{sec:file_asyncronous_lease}.
-\item[\const{F\_GETLEASE}] restituisce il tipo di \textit{file lease}
- \index{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
- sez.~\ref{sec:file_asyncronous_lease}.
+\item[\const{F\_GETLEASE}] restituisce il tipo di \index{file!lease}
+ \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 sez.~\ref{sec:file_asyncronous_lease}.
\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
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
-sez.~\ref{sec:file_asyncronous_access} mentre quelle relative al \textit{file
- locking}\index{file!locking} saranno esaminate in
+sez.~\ref{sec:file_asyncronous_access} mentre quelle relative al
+\index{file!locking} \textit{file locking} saranno esaminate in
sez.~\ref{sec:file_locking}). L'uso di questa funzione con i socket verrà
trattato in sez.~\ref{sec:sock_ctrl_func}.
Data la assoluta specificità della funzione, il cui comportamento varia da
dispositivo a dispositivo, non è possibile fare altro che dare una descrizione
sommaria delle sue caratteristiche; torneremo ad esaminare in
-seguito\footnote{per l'uso con i socket si veda
- sez.~\ref{sec:sock_ctrl_func}.} quelle relative ad alcuni casi specifici
-(ad esempio la gestione dei terminali è effettuata attraverso \func{ioctl} in
+seguito\footnote{per l'uso di \func{ioctl} con i socket si veda
+ sez.~\ref{sec:sock_ctrl_func}.} quelle relative ad alcuni casi specifici (ad
+esempio la gestione dei terminali è effettuata attraverso \func{ioctl} in
quasi tutte le implementazioni di Unix), qui riportiamo solo i valori di
alcuni comandi che sono definiti per ogni file:
\begin{basedescript}{\desclabelwidth{2.0cm}}
-\item[\const{FIOCLEX}] Imposta il flag di
- \textit{close-on-exec}\itindex{close-on-exec}.
-\item[\const{FIONCLEX}] Cancella il flag di
- \textit{close-on-exec}\itindex{close-on-exec}.
+\item[\const{FIOCLEX}] Imposta il flag di \itindex{close-on-exec}
+ \textit{close-on-exec}.
+\item[\const{FIONCLEX}] Cancella il flag di \itindex{close-on-exec}
+ \textit{close-on-exec}.
\item[\const{FIOASYNC}] Abilita l'I/O asincrono.
\item[\const{FIONBIO}] Abilita l'I/O in modalità non bloccante.
\end{basedescript}
-% TODO estendere la lista delle ioctl
+% TODO estendere la lista delle ioctl sui file
%%% Local Variables: