%% fileunix.tex
%%
-%% Copyright (C) 2000-2004 Simone Piccardi. Permission is granted to
+%% Copyright (C) 2000-2005 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",
\subsection{L'architettura dei \textit{file descriptor}}
\label{sec:file_fd}
-\index{file!descriptor|(} Per poter accedere al contenuto di un file occorre
+\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
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.
+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]
\centering
\includegraphics[width=13cm]{img/procfile}
l'interfaccia dei \textit{file descriptor}.}
\label{fig:file_proc_file}
\end{figure}
-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|)}
-
stato chiuso nessuno in precedenza).
In tutti i sistemi unix-like esiste una convenzione generale per cui ogni
-processo viene lanciato con almeno tre file aperti. Questi, per quanto appena
-detto, avranno come \textit{file descriptor}\index{file!descriptor} i valori
-0, 1 e 2. Benché questa sia soltanto una convenzione, essa è seguita dalla
-gran parte delle applicazioni, e non aderirvi potrebbe portare a gravi
-problemi di interoperabilità.
-
-Il primo file è sempre associato a quello che viene chiamato \textit{standard
- input}. È cioè il file da cui il processo si aspetta di ricevere i dati in
-ingresso (nel caso della shell, è associato all'ingresso dal terminale, e
-quindi alla lettura della tastiera). Il secondo file è il cosiddetto
-\textit{standard output}, cioè il file su cui ci si aspetta debbano essere
-inviati i dati in uscita (sempre nel caso della shell, è associato all'uscita
-del terminale, e quindi alla scrittura sullo schermo). Il terzo è lo
-\textit{standard error}, su cui viene inviato l'output relativo agli errori,
-ed è anch'esso associato all'uscita del terminale. Lo standard POSIX.1
-provvede tre costanti simboliche, definite nell'header \file{unistd.h}, al
-posto di questi valori numerici:
+processo viene lanciato dalla shell con almeno tre file aperti. Questi, per
+quanto appena detto, avranno come \textit{file
+ descriptor}\index{file!descriptor} i valori 0, 1 e 2. Benché questa sia
+soltanto una convenzione, essa è seguita dalla gran parte delle applicazioni,
+e non aderirvi potrebbe portare a gravi problemi di interoperabilità.
+
+Il primo file è sempre associato al cosiddetto \textit{standard input}; è cioè
+il file da cui il processo si aspetta di ricevere i dati in ingresso. Il
+secondo file è il cosiddetto \textit{standard output}, cioè quello su cui ci
+si aspetta debbano essere inviati i dati in uscita. Il terzo è lo
+\textit{standard error}, su cui viene inviata l'uscita relativa agli errori.
+Nel caso della shell tutti questi file sono associati al terminale di
+controllo, e corrispondono quindi alla lettura della tastiera per l'ingresso e
+alla scrittura sul terminale per l'uscita. Lo standard POSIX.1 provvede, al
+posto dei valori numerici, tre costanti simboliche, definite in
+tab.~\ref{tab:file_std_files}.
+
\begin{table}[htb]
\centering
\footnotesize
\label{tab:file_std_files}
\end{table}
-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}).
+In fig.~\ref{fig:file_proc_file} si è rappresentata una situazione diversa,
+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
L'interfaccia standard Unix per l'input/output sui file è basata su cinque
funzioni fondamentali: \func{open}, \func{read}, \func{write}, \func{lseek} e
\func{close}, usate rispettivamente per aprire, leggere, scrivere, spostarsi e
-chiudere un file.
-
-La gran parte delle operazioni sui file si effettua attraverso queste cinque
-funzioni, esse vengono chiamate anche funzioni di I/O non bufferizzato dato
-che effettuano le operazioni di lettura e scrittura usando direttamente le
-system call del kernel.
+chiudere un file. La gran parte delle operazioni sui file si effettua
+attraverso queste cinque funzioni, esse vengono chiamate anche funzioni di I/O
+non bufferizzato dato che effettuano le operazioni di lettura e scrittura
+usando direttamente le system call del kernel.
\subsection{La funzione \func{open}}
\label{sec:file_open}
La funzione \funcd{open} è la funzione fondamentale per accedere ai file, ed è
-quella che crea l'associazione fra un
-\index{\textit{pathname}}\textit{pathname} ed un file descriptor, il suo
-prototipo è:
+quella che crea l'associazione fra un \itindex{pathname}\textit{pathname} ed
+un file descriptor, il suo prototipo è:
\begin{functions}
\headdecl{sys/types.h}
\headdecl{sys/stat.h}
\end{functions}
La funzione apre il file, usando il primo file descriptor libero, e crea
-l'opportuna voce (cioè la struttura \struct{file}) nella file table. Viene
-usato sempre il file descriptor con il valore più basso.
+l'opportuna voce (cioè la struttura \struct{file}) nella \textit{file table}.
+Viene sempre restituito come valore di ritorno il file descriptor con il
+valore più basso disponibile.
\begin{table}[!htb]
\centering
\textbf{Flag} & \textbf{Descrizione} \\
\hline
\hline % modalità di accesso al file
- \const{O\_RDONLY} & apre il file in sola lettura. \\
- \const{O\_WRONLY} & apre il file in sola scrittura. \\
- \const{O\_RDWR} & apre il file in lettura/scrittura. \\
+ \const{O\_RDONLY} & apre il file in sola lettura, le \acr{glibc}
+ definiscono anche \const{O\_READ} come sinonimo. \\
+ \const{O\_WRONLY} & apre il file in sola scrittura, le \acr{glibc}
+ definiscono anche \const{O\_WRITE} come sinonimo. \\
+ \const{O\_RDWR} & apre il file sia in lettura che in scrittura. \\
\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
- sez.~\ref{sec:file_ownership}. L'argomento
- \param{mode} deve essere specificato. \\
+ sez.~\ref{sec:file_ownership}. Con questa opzione
+ 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
+ la precedente esistenza del file diventi un
errore\protect\footnotemark\ che fa fallire
\func{open} con \errcode{EEXIST}. \\
\const{O\_NONBLOCK}& apre il file in modalità non bloccante. Questo
\hline % modalità di operazione col file
\const{O\_APPEND} & il file viene aperto in append mode. Prima di ciascuna
scrittura la posizione corrente viene sempre impostata
- alla fine del file. Può causare corruzione del file
- con NFS se più di un processo scrive allo stesso
- tempo.\footnotemark\\
+ alla fine del file. Con NFS si può avere una
+ corruzione del file 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
sez.~\ref{sec:file_noblocking}): questo significa il
\const{O\_SYNC} & apre il file per l'input/output sincrono: ogni
\func{write} bloccherà fino al completamento della
scrittura di tutti i dati sull'hardware sottostante.\\
- \const{O\_FSYNC} & sinonimo di \const{O\_SYNC}. \\
+ \const{O\_FSYNC} & sinonimo di \const{O\_SYNC}, usato da BSD. \\
+ \const{O\_DSYNC} & richiede una variante di I/O sincorno definita nello
+ standard POSIX; definita a partire dal kernel 2.1.130
+ come sinonimo di \const{O\_SYNC}. \\
+ \const{O\_RSYNC} & richiede una variante di I/O sincorno definita nello
+ standard POSIX; definita a partire dal kernel 2.1.130
+ come sinonimo di \const{O\_SYNC}. \\
\const{O\_NOATIME}& blocca l'aggiornamento dei tempi di accesso dei
file (vedi sez.~\ref{sec:file_file_times}). Per molti
filesystem questa funzionalità non è disponibile per
- il singolo file ma come opzione in fase di montaggio.\\
+ il singolo file ma come opzione generale da
+ specificare in fase di montaggio.\\
+ \const{O\_DIRECT} & esegue l'I/O direttamente dai buffer in user space, ed
+ in maniera sincrona, in modo da scavalcare i
+ meccanismi di caching del kernel. In gebere questo
+ peggiora le prestazioni tranne per casi speciali in
+ cui sono le applicazioni\footnotemark a gestire il
+ caching. Per i kernel della serie 2.4 si deve
+ garantire che i buffer in user space siano allineati
+ alle dimensioni dei blocchi del filesystem; per il
+ kernel 2.6 basta che siano allineati a multipli di 512
+ byte.\\
\hline
\end{tabular}
\caption{Valori e significato dei vari bit del \textit{file status flag}.}
\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 race
- condition\index{\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}).}
+ \textsl{file di lock}\index{file!di lock} possono incorrere in una
+ \textit{race condition}\itindex{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]{\textit{Denial of Service}\index{DoS}, si chiamano così
attacchi miranti ad impedire un servizio causando una qualche forma 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
+\footnotetext[6]{l'opzione è stata introdotta dalla SGI in IRIX, e serve
+ sostanzialmente a permettere ad alcuni programmi (in genere database) la
+ gestione diretta della bufferizzazione dell'I/O in quanto essi sono in grado
+ di ottimizzarla al meglio per le loro prestazioni; l'opzione è presente
+ anche in FreeBSD, senza limiti di allineamento dei buffer. In Linux è stata
+ introdotta con il kernel 2.4.10, le versioni precedenti la ignorano.}
+
+
+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 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 sez.~\ref{sec:file_sharing}) ed è
-impostato per restare aperto attraverso una \func{exec} (come accennato in
-sez.~\ref{sec:proc_exec}); l'offset è impostato all'inizio del file.
+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
+sez.~\ref{sec:file_sharing}) ed è impostato per restare aperto attraverso una
+\func{exec} (come accennato in 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 sez.~\ref{sec:file_perm_overview}
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{\textit{race~condition}}, vedi sez.~\ref{sec:file_atomic}).
+(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
questo caso la funzione ritorna l'errore \errcode{EPIPE}. Questo, oltre che per
Lo stesso comportamento avviene caso di lettura dalla rete (cioè su un
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.
-
-In realtà anche le due condizioni segnalate dagli errori \errcode{EINTR} e
-\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 sez.~\ref{sec:sig_gen_beha}. La
-seconda si verifica quando il file è in modalità non bloccante (vedi
-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
-occorrerà provare a ripetere la lettura.
+restituiscono sempre i dati ad un singolo blocco alla volta, o come le linee
+seriali, che restituiscono solo i dati ricevuti fino al momento della lettura.
+
+Infine anche le due condizioni segnalate dagli errori \errcode{EINTR} ed
+\errcode{EAGAIN} non sono propriamente degli 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
+sez.~\ref{sec:sig_gen_beha}. La seconda si verifica quando il file è aperto
+in modalità non bloccante (vedi 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 non essendoci al momento dati
+disponibili occorre provare a ripetere la lettura in un secondo tempo.
La funzione \func{read} è una delle system call fondamentali, esistenti fin
dagli albori di Unix, ma nella seconda versione delle \textit{Single Unix
in caso di errore, nel qual caso \var{errno} assumerà i valori già visti per
\func{read} e \func{lseek}.}
\end{prototype}
-\noindent che però diventa accessibile solo con la definizione della macro:
+
+La funzione prende esattamente gli stessi argomenti di \func{read} con lo
+stesso significato, a cui si aggiunge l'argomento \func{offset} che indica una
+posizione sul file. Indetico è il comportamento ed il valore di ritorno. La
+funzione serve quando si vogliono leggere dati dal file senza modificare la
+posizione corrente.
+
+L'uso di \func{pread} è equivalente all'esecuzione di una \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 sez.~\ref{sec:file_sharing}). Il valore di
+\param{offset} fa sempre riferimento all'inizio del file.
+
+La funzione \func{pread} è disponibile anche in Linux, però diventa
+accessibile solo attivando il supporto delle estensioni previste dalle
+\textit{Single Unix Specification} con la definizione della macro:
\begin{verbatim}
#define _XOPEN_SOURCE 500
\end{verbatim}
+e si ricordi di definire questa macro prima dell'inclusione del file di
+dichiarazioni \file{unistd.h}.
-Questa funzione serve quando si vogliono leggere dati dal file senza
-modificare la posizione corrente. È equivalente all'esecuzione di una
-\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 sez.~\ref{sec:file_sharing}). Il valore di
-\param{offset} fa sempre riferimento all'inizio del file.
\subsection{La funzione \func{write}}
\label{sec:file_write}
-Una volta che un file è stato aperto (con il permesso in scrittura) su può
+Una volta che un file è stato aperto (con il permesso in scrittura) si può
scrivere su di esso utilizzando la funzione \funcd{write}, il cui prototipo è:
\begin{prototype}{unistd.h}{ssize\_t write(int fd, void * buf, size\_t count)}
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 \textit{race
- condition}\index{\textit{race~condition}}: infatti può succedere che un
+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
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 race
-condition\index{\textit{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 \textit{race
+ condition}\itindex{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
della \textit{file table} a cui entrambi fanno riferimento). L'unica
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{\textit{close-on-exec}}
-(vedi sez.~\ref{sec:proc_exec} e sez.~\ref{sec:file_fcntl}) viene sempre
-cancellato nella copia.
+di \func{dup} il flag di \textit{close-on-exec}\itindex{close-on-exec} (vedi
+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};
Dato che questa è l'operazione più comune, è prevista una diversa versione
della funzione, \funcd{dup2}, che permette di specificare esplicitamente
-qual'è il valore di file descriptor che si vuole avere come duplicato; il suo
+qual è il valore di file descriptor che si vuole avere come duplicato; il suo
prototipo è:
\begin{prototype}{unistd.h}{int dup2(int oldfd, int newfd)}
allo stesso valore per il file descriptor).
La duplicazione dei file descriptor può essere effettuata anche usando la
-funzione di controllo dei file \func{fnctl} (che esamineremo in
+funzione di controllo dei file \func{fcntl} (che esamineremo in
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
+la sintassi \code{fcntl(oldfd, F\_DUPFD, newfd)} e se si usa 0 come valore per
\param{newfd} diventa equivalente a \func{dup}.
La sola differenza fra le due funzioni\footnote{a parte la sintassi ed i
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}\index{\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.
+ \textit{close-on-exec}\itindex{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.
\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
descriptor aperti vengono chiusi attraverso una \func{exec} altrimenti (il
specifiche di ogni dispositivo particolare, usando come riferimento il solito
file descriptor. Il prototipo di questa funzione è:
\begin{prototype}{sys/ioctl.h}{int ioctl(int fd, int request, ...)}
- Manipola il dispositivo sottostante, usando il parametro \param{request} per
- specificare l'operazione richiesta ed il terzo parametro (usualmente di tipo
+ Manipola il dispositivo sottostante, usando l'argomento \param{request} per
+ specificare l'operazione richiesta ed il terzo argomento (usualmente di tipo
\param{char * argp} o \param{int argp}) per il trasferimento
dell'informazione necessaria.
qui riportiamo solo i valori di alcuni comandi che sono definiti per ogni
file:
\begin{basedescript}{\desclabelwidth{2.0cm}}
-\item[\const{FIOCLEX}] Imposta il bit di \textit{close on exec}.
-\item[\const{FIONCLEX}] Cancella il bit di \textit{close on exec}.
+\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{FIOASYNC}] Abilita l'I/O asincrono.
\item[\const{FIONBIO}] Abilita l'I/O in modalità non bloccante.
\end{basedescript}