Al momento dell'apertura il nuovo file descriptor non è condiviso con nessun
altro processo (torneremo sul significato della condivisione dei file
descriptor, che in genere si ottiene dopo una \func{fork}, in
-sez.~\ref{sec:file_sharing}) ed è impostato, come accennato in
+sez.~\ref{sec:file_shared_access}) ed è impostato, come accennato in
sez.~\ref{sec:proc_exec}, per restare aperto attraverso una
\func{exec}. Inoltre la posizione sul file, il cosiddetto \textit{offset}, è
impostata all'inizio del file. Una volta aperto un file si potrà operare su di
eventuale blocco (il \textit{file locking} \itindex{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, vedi
-sez.~\ref{sec:file_sharing} e \ref{sec:file_dup}) ad un file aperto, tutte le
-risorse nella \itindex{file~table} \textit{file table} vengono
+sez.~\ref{sec:file_shared_access} e \ref{sec:file_dup}) ad un file aperto,
+tutte le risorse nella \itindex{file~table} \textit{file table} vengono
rilasciate. Infine se il file descriptor era l'ultimo riferimento ad un file
su disco quest'ultimo viene cancellato.
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
- condition}, vedi sez.~\ref{sec:file_atomic}).
+ condition}, vedi sez.~\ref{sec:file_shared_access}).
Non tutti i file supportano la capacità di eseguire una \func{lseek}, in
questo caso la funzione ritorna l'errore \errcode{ESPIPE}. Questo, oltre che
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
+(vedi sez.~\ref{sec:file_shared_access}). Il valore di
\param{offset} fa sempre riferimento all'inizio del file.
La funzione \func{pread} è disponibile anche in Linux, però diventa
dell'argomento sarà comunque affrontato in cap.~\ref{cha:file_advanced}).
-\subsection{La condivisione dei files}
-\label{sec:file_sharing}
+\subsection{La gestione dell'accesso concorrente ai files}
+\label{sec:file_shared_access}
In sez.~\ref{sec:file_fd} abbiamo descritto brevemente l'architettura
dell'interfaccia con i file da parte di un processo, mostrando in
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.
+confronti dell'accesso concorrente allo stesso file da parte di processi
+diversi.
\begin{figure}[!htb]
\centering
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} \itindex{inode}
- nell'\textit{inode}.
+\item ciascun processo può scrivere indipendentemente, dopo ciascuna
+ \func{write} la posizione corrente sarà cambiata solo nel processo
+ scrivente. Se la scrittura eccede la dimensione corrente del file questo
+ verrà esteso automaticamente con l'aggiornamento del campo \var{i\_size}
+ della struttura \kstruct{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 \itindex{inode}
- dall'\textit{inode}. Dopo la scrittura il file viene automaticamente esteso.
+ prima impostata alla dimensione corrente del file letta dalla struttura
+ \kstruct{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 \kstruct{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 \itindex{inode} dall'\textit{inode}.
+ dimensione corrente dalla struttura \kstruct{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 \itindex{file~table} \textit{file table};
-questo è ad esempio il caso dei file aperti che vengono ereditati dal processo
+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
-\kstruct{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
-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).
-
-Si noti inoltre che anche i \itindex{file~status~flag} flag di stato del file
-(quelli impostati dall'argomento \param{flag} di \func{open}) essendo tenuti
-nella voce della \textit{file table}, vengono in questo caso condivisi. Ai
-file però sono associati anche altri flag, dei quali l'unico usato al momento
-è \const{FD\_CLOEXEC}, detti \itindex{file~descriptor~flags} \textit{file
- descriptor flags}. Questi ultimi sono tenuti invece in
-\kstruct{file\_struct}, e perciò sono specifici di ciascun processo e non
+\kstruct{file\_struct} e della relativa tabella dei file aperti.
+
+Questo significa che il figlio avrà gli stessi file aperti del padre, in
+quanto la sua \kstruct{file\_struct}, pur essendo allocata in maniera
+indipendente, contiene gli stessi valori di quella del padre e quindi i suoi
+file descriptor faranno riferimento alla stessa voce nella
+\itindex{file~table} \textit{file table}, condividendo così la posizione
+corrente sul file. Questo ha le conseguenze descritte a suo tempo in
+sez.~\ref{sec:proc_fork}: in caso di scrittura o lettura da parte di uno dei
+due processi, la posizione corrente nel file varierà per entrambi, in quanto
+verrà modificato il campo \var{f\_pos} della struttura \kstruct{file}, che è
+la stessa per entrambi. Questo consente una sorta di
+``\textsl{sincronizzazione}'' automatica della posizione sul file fra padre e
+figlio che occorre tenere presente.
+
+Si noti inoltre che in questo caso anche i \itindex{file~status~flag} flag di
+stato del file, essendo mantenuti nella struttura \kstruct{file} della
+\textit{file table}, vengono condivisi, per cui una modifica degli stessi con
+\func{fcntl} (vedi sez.~\ref{sec:file_fcntl}) si applicherebbe a tutti
+processi che condividono la voce nella \itindex{file~table} \textit{file
+ table}. Ai file però sono associati anche altri flag, dei quali l'unico
+usato al momento è \const{FD\_CLOEXEC}, detti \itindex{file~descriptor~flags}
+\textit{file descriptor flags}; questi invece sono mantenuti in
+\kstruct{file\_struct}, e perciò sono locali per ciascun processo e non
vengono modificati dalle azioni degli altri anche in caso di condivisione
-della stessa voce della \textit{file table}.
-
-
-
-\subsection{Operazioni atomiche con i file}
-\label{sec:file_atomic}
-
-Come si è visto in un sistema unix-like è sempre possibile per più processi
-accedere in contemporanea allo stesso file, e che le operazioni di lettura e
-scrittura possono essere fatte da ogni processo in maniera autonoma in base
-ad una posizione corrente nel file che è locale a ciascuno di essi.
-
-Se dal punto di vista della lettura dei dati questo non comporta nessun
-problema, quando si andrà a scrivere le operazioni potranno mescolarsi in
-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
-\itindex{file~locking} \textit{file locking}, che esamineremo in
-sez.~\ref{sec:file_locking}).
+della stessa voce della \itindex{file~table} \textit{file table}.
+
+Si tenga presente dunque che in un sistema unix-like è sempre possibile per
+più processi accedere in contemporanea allo stesso file e che non esistono, a
+differenza di altri sistemi operativi, dei meccanismi di blocco o di
+restrizione dell'accesso impliciti se più processi vogliono accedere allo
+stesso file. Questo significa che le operazioni di lettura e scrittura vengono
+sempre fatte da ogni processo in maniera autonoma, utilizzando una posizione
+corrente nel file che normalmente (a meno di non trovarsi nella situazione di
+fig.~\ref{fig:file_acc_child}) è locale a ciascuno di essi.
+
+Dal punto di vista della lettura dei dati questo comporta la possibilità di
+poter leggere dati non coerenti in caso di scrittura contemporanea da parte di
+un altro processo. Dal punto di vista della scrittura invece si potranno avere
+sovrapposizioni imprevedibili quando due processi scrivono nella stessa
+sezione di file, dato che ciascuno lo farà in maniera indipendente. Il
+sistema però fornisce in alcuni casi la possibilità di eseguire alcune
+operazioni di scrittura in maniera coordinata anche senza utilizzare dei
+meccanismi di sincronizzazione espliciti come il \itindex{file~locking}
+\textit{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 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.
-
-Il problema è che usare due \textit{system call} in successione non è
-un'operazione atomica; il problema è stato risolto introducendo la modalità
-\itindex{append~mode} \const{O\_APPEND}. In questo caso infatti, come abbiamo
-descritto in precedenza, è il kernel che aggiorna automaticamente la posizione
-alla fine del file prima di effettuare la scrittura, e poi estende il file.
-Tutto questo avviene all'interno di una singola \textit{system call} (la
-\func{write}) che non essendo interrompibile da un altro processo costituisce
-un'operazione 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
-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 \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
-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 \textit{system call} (per i dettagli sull'uso di questa
-caratteristica si veda sez.~\ref{sec:ipc_file_lock}).
-
-
-\subsection{Le funzioni \func{sync} e \func{fsync}}
-\label{sec:file_sync}
-
-% TODO, aggiungere syncfs, introdotta con il 2.6.39
-
-Come accennato in sez.~\ref{sec:file_open_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}.
-
-Per questo motivo, quando è necessaria una sincronizzazione dei dati, il
-sistema mette a disposizione delle funzioni che provvedono a forzare lo
-scarico dei dati dai buffer del kernel.\footnote{come già accennato neanche
- questo dà la garanzia assoluta che i dati siano integri dopo la chiamata,
- l'hardware dei dischi è in genere dotato di un suo meccanismo interno di
- ottimizzazione per l'accesso al disco che può ritardare ulteriormente la
- scrittura effettiva.} La prima di queste funzioni è \funcd{sync} il cui
-prototipo è:
-
-\begin{funcproto}{
-\fhead{unistd.h}
-\fdecl{int sync(void)}
-\fdesc{Sincronizza il buffer della cache dei file col disco.}
-}
-
-{La funzione ritorna sempre $0$ ed ha sempre successo.}
-\end{funcproto}
-
-\noindent i vari standard prevedono che la funzione si limiti a far partire
-le operazioni, ritornando immediatamente; in Linux (dal kernel 1.3.20) invece
-la funzione aspetta la conclusione delle operazioni di sincronizzazione del
-kernel.
-
-La funzione viene usata dal comando \cmd{sync} quando si vuole forzare
-esplicitamente lo scarico dei dati su disco, o dal demone di sistema
-\cmd{update} che esegue lo scarico dei dati ad intervalli di tempo fissi: il
-valore tradizionale, usato da BSD, per l'update dei dati è ogni 30 secondi, ma
-in Linux il valore utilizzato è di 5 secondi; con le nuove versioni\footnote{a
- partire dal kernel 2.2.8} poi, è il kernel che si occupa direttamente di
-tutto quanto attraverso il demone interno \cmd{bdflush}, il cui comportamento
-può essere controllato attraverso il file \sysctlfile{vm/bdflush} (per
-il significato dei valori si può leggere la documentazione allegata al kernel
-in \file{Documentation/sysctl/vm.txt}).
-
-Quando si vogliono scaricare soltanto i dati di un file (ad esempio essere
-sicuri che i dati di un database sono stati registrati su disco) si possono
-usare le due funzioni \funcd{fsync} e \funcd{fdatasync}, i cui prototipi sono:
-
-\begin{funcproto}{
-\fhead{unistd.h}
-\fdecl{int fsync(int fd)}
-\fdesc{Sincronizza dati e metadati di un file.}
-\fdecl{int fdatasync(int fd)}
-\fdesc{Sincronizza i dati di un file.}
-}
-
-{Le funzioni ritornano $0$ in caso di successo e $-1$ per un errore, nel qual
- caso \var{errno} assumerà uno dei valori:
- \begin{errlist}
- \item[\errcode{EINVAL}] \param{fd} è un \index{file!speciali} file speciale
- che non supporta la sincronizzazione.
- \end{errlist}
- ed inoltre \errval{EBADF}, \errval{EROFS} e \errval{EIO} nel loro
- significato generico.}
-\end{funcproto}
-
-Entrambe le funzioni forzano la sincronizzazione col disco di tutti i dati del
-file specificato, ed attendono fino alla conclusione delle operazioni;
-\func{fsync} forza anche la sincronizzazione dei meta-dati del file (che
-riguardano sia le modifiche alle tabelle di allocazione dei settori, che gli
-altri dati contenuti \itindex{inode} nell'\textit{inode} che si leggono con
-\func{fstat}, come i tempi del file).
-
-Si tenga presente che questo non comporta la sincronizzazione della
-directory che contiene il file (e scrittura della relativa voce su
-disco) che deve essere effettuata esplicitamente.\footnote{in realtà per
- il filesystem \acr{ext2}, quando lo si monta con l'opzione \cmd{sync},
- il kernel provvede anche alla sincronizzazione automatica delle voci
- delle directory.}
-
-
-\subsection{Le funzioni \func{dup} e \func{dup2}}
+\textit{race condition}l 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 primo processo, che avrà la
+posizione corrente che aveva impostato con la \func{lseek} che non corrisponde
+più alla fine del file, e la sua successiva \func{write} sovrascriverà i dati
+del secondo processo.
+
+Il problema deriva dal fatto che usare due \textit{system call} in successione
+non è mai un'operazione atomica dato che il kernel può interrompere
+l'esecuzione del processo fra le due. Nel caso specifico il problema è stato
+risolto introducendo la modalità di scrittura \itindex{append~mode} in
+\textit{append}, attivabile con il flag \const{O\_APPEND}. In questo caso
+infatti, come abbiamo illustrato in sez.~\ref{sec:file_open_close}, è il
+kernel che aggiorna automaticamente la posizione alla fine del file prima di
+effettuare la scrittura, e poi estende il file. Tutto questo avviene
+all'interno di una singola \textit{system call}, la \func{write}, che non
+essendo interrompibile da un altro processo realizza un'operazione atomica.
+
+
+\subsection{La duplicazione dei file descriptor}
\label{sec:file_dup}
-Abbiamo già visto in sez.~\ref{sec:file_sharing} come un processo figlio
+Abbiamo già visto in sez.~\ref{sec:file_shared_access} 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
-prototipo è:
+un file descriptor. Per far questo si usa la funzione di sistema \funcd{dup},
+il cui prototipo è:
\begin{funcproto}{
\fhead{unistd.h}
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 fig.~\ref{fig:file_dup}: l'effetto della funzione è
-semplicemente quello di copiare il valore nella struttura
-\kstruct{file\_struct}, cosicché anche il nuovo file descriptor fa riferimento
-alla stessa voce nella \textit{file table}; per questo si dice che il nuovo
-file descriptor è \textsl{duplicato}, da cui il nome della funzione.
+può fare riferimento a fig.~\ref{fig:file_dup}. L'effetto della funzione è
+semplicemente quello di copiare il valore di un certo file descriptor in
+un altro all'interno della struttura \kstruct{file\_struct}, cosicché anche
+questo faccia riferimento alla stessa voce nella \textit{file table}. Per
+questo motivo si dice che il nuovo file descriptor è ``\textsl{duplicato}'',
+da cui il nome della funzione.
\begin{figure}[!htb]
\centering \includegraphics[width=12cm]{img/filedup}
\end{figure}
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
-sull'altro (dato che quello che viene modificato è lo stesso campo nella voce
-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} \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};
-diventa così possibile associare un file (o una pipe) allo standard input o
-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
-disponibile.
-
-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
-prototipo è:
+duplicati condivideranno eventuali lock (vedi sez.~\ref{sec:file_locking}),
+\itindex{file~status~flag} i flag di stato, e la posizione corrente sul
+file. Se ad esempio si esegue una \func{lseek} per modificare la posizione su
+uno dei due file descriptor, essa risulterà modificata anche sull'altro, dato
+che quello che viene modificato è lo stesso campo nella voce della
+\textit{file table} a cui entrambi fanno riferimento.
+
+L'unica differenza fra due file descriptor duplicati è che ciascuno avrà un
+suo \textit{file descriptor flag} indipendente. A questo proposito deve essere
+tenuto presente che nel caso in cui si usi \func{dup} per duplicare un file
+descriptor, se questo ha il flag di \textit{close-on-exec}
+\itindex{close-on-exec} attivo (vedi sez.~\ref{sec:proc_exec} e
+sez.~\ref{sec:file_fcntl}), questo verrà cancellato nel file descriptor
+restituito come copia.
+
+L'uso principale di questa funzione è nella shell per la redirezione dei file
+standard di tab.~\ref{tab:file_std_files} fra l'esecuzione di una \func{fork}
+e la successiva \func{exec}. Diventa così possibile associare un file (o una
+pipe) allo \itindex{standard~input} \textit{standard input} o allo
+\itindex{standard~output} \textit{standard output} (vedremo un esempio in
+sez.~\ref{sec:ipc_pipe_use}, quando tratteremo le pipe).
+
+Ci si può chiedere perché non sia in questo caso sufficiente chiudere il file
+standard che si vuole redirigere e poi aprire direttamente con \func{open} il
+file vi si vuole far corrispondere, invece di duplicare un file descriptor che
+si è già aperto. La risposta sta nel fatto che il file che si vuole redirigere
+non è detto sia un file regolare, ma potrebbe essere, come accennato, anche
+una fifo o un socket, oppure potrebbe essere un file associato ad un file
+descriptor che si è ereditato già aperto (ad esempio attraverso un'altra
+\func{exec}) da un processo antenato del padre, del quale non si conosce il
+nome. Operando direttamente con i file descriptor \func{dup} consente di
+ignorare le origini del file descriptor che si duplica e funziona in maniera
+generica indipendentemente dall'oggetto a cui questo fa riferimento.
+
+Per ottenere la redirezione occorre pertanto disporre del file descriptor
+associato al file che si vuole usare e chiudere il file descriptor che si
+vuole sostituire, cosicché esso possa esser restituito alla successiva
+chiamata di \func{dup} come primo file descriptor disponibile. Dato che
+questa è l'operazione più comune, è prevista un'altra funzione di sistema,
+\funcd{dup2}, che permette di specificare esplicitamente qual è il numero di
+file descriptor che si vuole ottenere come duplicato; il suo prototipo è:
\begin{funcproto}{
\fhead{unistd.h}
\begin{errlist}
\item[\errcode{EBADF}] \param{oldfd} non è un file aperto o \param{newfd} ha
un valore fuori dall'intervallo consentito per i file descriptor.
+ \item[\errcode{EBUSY}] si è rilevata la possibilità di una
+ \itindex{race~condition} \textit{race condition}.
+ \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale.
\item[\errcode{EMFILE}] si è raggiunto il numero massimo consentito di file
descriptor aperti.
\end{errlist}
}
\end{funcproto}
-
-\noindent e qualora il file descriptor \param{newfd} sia già aperto (come
-avviene ad esempio nel caso della duplicazione di uno dei file standard) esso
-sarà prima chiuso e poi duplicato (così che il file duplicato sarà connesso
-allo stesso valore per il file descriptor).
+La funzione duplica il file descriptor \param{oldfd} su un altro file
+descriptor di valore \param{newfd}. Qualora il file descriptor \param{newfd}
+sia già aperto, come avviene ad esempio nel caso della duplicazione di uno dei
+file standard di tab.~\ref{tab:file_std_files}, esso sarà prima chiuso e poi
+duplicato. Se \param{newfd} è uguale a \param{oldfd} la funzione non fa nulla
+e si limita a restituire \param{newfd}.
+
+L'uso di \func{dup2} ha vari vantaggi rispetto alla combinazione di
+\func{close} e \func{dup}; anzitutto se \param{oldfd} è uguale \param{newfd}
+questo verrebbe chiuso e \func{dup} fallirebbe, ma soprattutto l'operazione è
+atomica e consente di evitare una \itindex{race~condition} \textit{race
+ condition} in cui dopo la chiusura del file si potrebbe avere la ricezione
+di un segnale il cui gestore (vedi sez.~\ref{sec:sig_signal_handler}) potrebbe
+a sua volta aprire un file, per cui alla fine \func{dup} restituirebbe un file
+descriptor diverso da quello voluto.
+
+Con Linux inoltre la funzione prevede la possibilità di restituire l'errore
+\errcode{EBUSY}, che non è previsto dallo standard, quando viene rilevata la
+possibilità di una \itindex{race~condition} \textit{race condition} interna in
+cui si cerca di duplicare un file descriptor che è stato allocato ma per il
+quale non sono state completate le operazioni di apertura.\footnote{la
+ condizione è abbastanza peculiare e non attinente al tipo di utilizzo
+ indicato, quanto piuttosto ad un eventuale tentativo di duplicare file
+ descriptor non ancora aperti, la condizione di errore non è prevista dallo
+ standard, ma in condizioni simili FreeBSD risponde con un errore di
+ \errval{EBADF}, mentre OpenBSD elimina la possibilità di una \textit{race
+ condition} al costo di una perdita di prestazioni.} In tal caso occorre
+ritentare l'operazione.
La duplicazione dei file descriptor può essere effettuata anche usando la
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{fcntl(oldfd, F\_DUPFD, newfd)} e se si usa 0 come valore per
-\param{newfd} diventa equivalente a \func{dup}.
+\param{newfd} diventa equivalente a \func{dup}. La sola differenza fra le due
+funzioni (a parte la sintassi ed i diversi codici di errore) è che \func{dup2}
+chiude il file descriptor \param{newfd} se questo è già aperto, garantendo che
+la duplicazione sia effettuata esattamente su di esso, invece \func{fcntl}
+restituisce il primo file descriptor libero di valore uguale o maggiore
+di \param{newfd}, per cui se \param{newfd} è aperto la duplicazione avverrà su
+un altro file descriptor.
+
+Su Linux inoltre è presente una terza funzione di sistema non
+standard,\footnote{la funzione è stata introdotta con il kernel 2.6.27 e resa
+ disponibile con la \acr{glibc} 2.9.} \funcd{dup3}, che consente di duplicare
+un file descriptor reimpostandone i flag, per usarla occorre definire la macro
+\macro{\_GNU\_SOURCE} ed il suo prototipo è:
+
+\begin{funcproto}{
+\fhead{unistd.h}
+\fdecl{int dup3(int oldfd, int newfd, int flags)}
+\fdesc{Duplica un file descriptor su un altro.}
+}
+
+{La funzione ritorna il nuovo file descriptor in caso di successo e $-1$ per
+ un errore, nel qual caso \var{errno} assumerà gli stessi valori di
+ \func{dup2} più \errcode{EINVAL} qualora \param{flags} contenga un valore
+ non valido o \param{newfd} sia uguale a \param{oldfd}.
+}
+\end{funcproto}
+
+La funzione è identica a \func{dup2} ma prevede la possibilità di mantenere il
+flag di \textit{close-on-exec} \itindex{close-on-exec} sul nuovo
+file descriptor specificando \const{O\_CLOEXEC} in \param{flags} (che è l'unico
+flag usabile in questo caso). Inoltre rileva esplicitamente la possibile
+coincidenza fra \param{newfd} e \param{oldfd}, fallendo con un errore di
+\errval{EINVAL}.
+
+
+\subsection{Le funzioni di sincronizzazione dei dati}
+\label{sec:file_sync}
+
+Come accennato in sez.~\ref{sec:file_open_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}.
+
+Per questo motivo quando è necessaria una sincronizzazione dei dati il sistema
+mette a disposizione delle funzioni che provvedono a forzare lo scarico dei
+dati dai buffer del kernel. La prima di queste funzioni di sistema è
+\funcd{sync}, il cui prototipo è:\footnote{questo è il prototipo usato a
+ partire dalla \acr{glibc} 2.2.2 seguendo gli standard, in precedenza la
+ funzione era definita come \code{int sync(void)} e ritornava sempre $0$.}
+
+\begin{funcproto}{
+\fhead{unistd.h}
+\fdecl{void sync(void)}
+\fdesc{Sincronizza il buffer della cache dei file col disco.}
+}
+
+{La funzione non ritorna nulla e non prevede condizioni di errore.}
+\end{funcproto}
-La sola differenza fra le due funzioni\footnote{a parte la sintassi ed i
- diversi codici di errore.} è che \func{dup2} chiude il file descriptor
-\param{newfd} se questo è già aperto, garantendo che la duplicazione sia
-effettuata esattamente su di esso, invece \func{fcntl} restituisce il primo
-file descriptor libero di valore uguale o maggiore di \param{newfd} (e se
-\param{newfd} è aperto la duplicazione avverrà su un altro file descriptor).
+I vari standard prevedono che la funzione si limiti a far partire le
+operazioni, ritornando immediatamente, con Linux fin dal kernel 1.3.20 invece
+la funzione aspetta la conclusione delle operazioni di sincronizzazione. Si
+tenga presente comunque che questo non dà la garanzia assoluta che i dati
+siano integri dopo la chiamata, l'hardware dei dischi è in genere dotato di un
+suo meccanismo interno di bufferizzazione che può ritardare ulteriormente la
+scrittura effettiva.
+La funzione viene usata dal comando \cmd{sync} quando si vuole forzare
+esplicitamente lo scarico dei dati su disco, un tempo era invocata da un
+apposito demone di sistema (in genere chiamato \cmd{update}) che eseguiva lo
+scarico dei dati ad intervalli di tempo fissi. Con le nuove versioni del
+kernel queste operazioni vengono gestite direttamente dal sistema della
+memoria virtuale, attraverso opportuni \textit{task} interni al kernel il cui
+comportamento può essere controllato attraverso il file
+\sysctlfile{vm/bdflush}.\footnote{per il significato dei valori che si possono
+ scrivere in questo file si consulti la documentazione allegata ai sorgenti
+ del kernel nel file \file{Documentation/sysctl/vm.txt}, trattandosi di
+ argomenti di natura sistemistica non li prenderemo in esame.} Si tenga
+presente che la funzione di sistema \funcm{bdflush}, che un tempo veniva usata
+per queste impostazioni, è deprecata e causa semplicemente la stampa di un
+messaggio nei log del kernel, pertanto non la prenderemo in esame.
+
+Quando si vogliano scaricare i dati di un singolo file, ad esempio essere
+sicuri che i dati di un database siano stati registrati su disco, si possono
+usare le due funzioni di sistema \funcd{fsync} e \funcd{fdatasync}, i cui
+prototipi sono:
+
+\begin{funcproto}{
+\fhead{unistd.h}
+\fdecl{int fsync(int fd)}
+\fdesc{Sincronizza dati e metadati di un file.}
+\fdecl{int fdatasync(int fd)}
+\fdesc{Sincronizza i dati di un file.}
+}
+{Le funzioni ritornano $0$ in caso di successo e $-1$ per un errore, nel qual
+ caso \var{errno} assumerà uno dei valori:
+ \begin{errlist}
+ \item[\errcode{EINVAL}] \param{fd} è un \index{file!speciali} file speciale
+ che non supporta la sincronizzazione.
+ \end{errlist}
+ ed inoltre \errval{EBADF}, \errval{EROFS} e \errval{EIO} nel loro
+ significato generico.}
+\end{funcproto}
-\subsection{Le funzioni \func{openat}, \func{mkdirat} e affini}
+Entrambe le funzioni forzano la sincronizzazione col disco di tutti i dati del
+file specificato, ed attendono fino alla conclusione delle operazioni. La
+prima, \func{fsync} forza anche la sincronizzazione dei meta-dati del file,
+che riguardano sia le modifiche alle tabelle di allocazione dei settori, che
+gli altri dati contenuti \itindex{inode} nell'\textit{inode} che si leggono
+con \func{fstat}, come i tempi del file. Se lo scopo dell'operazione, come
+avviene spesso per i database, è assicurarsi che i dati raggiungano il disco e
+siano rileggibili immediatamente in maniera corretta, è sufficiente l'uso di
+\func{fdatasync} che non comporta anche l'esecuzione di operazioni non
+necessarie all'integrità dei dati, come l'aggiornamento dei temi di ultima
+modifica ed ultimo accesso.
+
+Si tenga presente che l'uso di queste funzioni non comporta la
+sincronizzazione della directory che contiene il file e la scrittura della
+relativa voce su disco, che se necessaria deve essere effettuata
+esplicitamente con \func{fsync} sul file descriptor della
+directory.\footnote{in realtà per il filesystem \acr{ext2}, quando lo si monta
+ con l'opzione \cmd{sync}, il kernel provvede anche alla sincronizzazione
+ automatica delle voci delle directory.}
+
+L'uso di \func{sync} presenta in certi casi, quando ci sono più filesystem
+montati, problemi di prestazioni dovute al fatto che la funzione provoca la
+sincronizzazione dei dati su tutti quanti i filesystem, anche quando
+interesserebbe che questo avvenga soltanto su quello dei file su cui si sta
+lavorando, se i dati in attesa sono molti questo può causare seri problemi di
+prestazioni.
+
+Per questo motivo è stata introdotta una nuova funzione di sistema,
+\funcd{syncfs},\footnote{la funzione è stata introdotta a partire dal kernel
+ 2.6.39 ed è accessibile solo se è definita la macro \macro{\_GNU\_SOURCE}, è
+ specifica di Linux e non prevista da nessuno standard.} che effettua lo
+scarico dei dati soltanto per il filesystem su cui si sta operando, il suo
+prototipo è:
+
+\begin{funcproto}{
+\fhead{unistd.h}
+\fdecl{int syncfs(int fd)}
+\fdesc{Sincronizza il buffer della cache dei file del singolo filesystem col
+ disco.}
+}
+
+{La funzione ritorna $0$ in caso di successo e $-1$ per un errore, nel qual
+ caso \var{errno} assumerà uno dei valori:
+ \begin{errlist}
+ \item[\errcode{EBADF}] \param{fd} non è un descrittore valido.
+ \end{errlist}
+}
+\end{funcproto}
+
+La funzione richiede che si specifichi nell'argomento \param{fd} un file
+descriptor su cui si sta operando, e lo scarico dei dati sarà limitato al
+filesystem su cui il file ad esso corrispondente si trova.
+
+
+\subsection{Le \textit{at-functions}: \func{openat} e affini}
\label{sec:file_openat}
\itindbeg{at-functions}
-Un problema che si pone con l'uso della funzione \func{open}, così come per
-molte altre funzioni che accettano come argomenti dei
-\itindsub{pathname}{relativo} \textit{pathname} relativi, è che, quando un
-\textit{pathname} relativo non fa riferimento alla \index{directory~di~lavoro}
-directory di lavoro corrente, è possibile che alcuni dei suoi componenti
-vengano modificati in parallelo alla chiamata a \func{open}, e questo lascia
-aperta la possibilità di una \itindex{race~condition} \textit{race condition}.
+Un problema generale che si pone con l'uso della funzione \func{open}, così
+come per le altre funzioni che prendono come argomenti dei
+\itindsub{pathname}{relativo} \textit{pathname} relativi, è la possibilità,
+quando un \textit{pathname} relativo non fa riferimento ad un file posto
+direttamente nella \index{directory~di~lavoro} directory di lavoro corrente,
+che alcuni dei componenti del \textit{pathname} vengano modificati in
+parallelo alla chiamata a \func{open}, cosa che lascia aperta la possibilità
+di una \itindex{race~condition} \textit{race condition} in cui c'è spazio per
+un \itindex{symlink~attack} \textit{symlink attack} (si ricordi quanto visto
+per \func{access} in sez.~\ref{sec:file_perm_management}).
Inoltre come già accennato, la \index{directory~di~lavoro} directory di lavoro
corrente è una proprietà del singolo processo; questo significa che quando si
Per risolvere questi problemi, riprendendo una interfaccia già presente in
Solaris, a fianco delle normali funzioni che operano sui file (come
\func{open}, \func{mkdir}, ecc.) sono state introdotte delle ulteriori
-funzioni, dette anche funzioni ``\textit{at}'' in quanto contraddistinte dal
+funzioni, dette anche ``\textit{at-functions}'' in quanto contraddistinte dal
suffisso \texttt{at}, che permettono l'apertura di un file (o le rispettive
altre operazioni) usando un \itindsub{pathname}{relativo} \textit{pathname}
relativo ad una directory specificata.\footnote{l'introduzione è avvenuta su
- proposta dello sviluppatore principale delle \acr{glibc} Urlich Drepper; le
- corrispondenti \textit{system call} sono state inserite nel kernel ufficiale
- a partire dalla versione 2.6.16, in precedenza era disponibile una
- emulazione che, sia pure con prestazioni inferiori, funzionava facendo
- ricorso all'uso del filesystem \textit{proc} con l'apertura del file
- attraverso il riferimento a \textit{pathname} del tipo di
- \texttt{/proc/self/fd/dirfd/relative\_path}.} Benché queste funzioni non
-siano presenti negli standard tradizionali esse sono state adottate da vari
-Unix\footnote{oltre a Linux e Solaris sono presenti in vari BSD.} fino ad
-essere incluse nella recente revisione (la POSIX.1-2008) dello standard
-POSIX.1; con le \acr{glibc} per l'accesso a queste funzioni è necessario
+ proposta dello sviluppatore principale della \acr{glibc} Urlich Drepper e le
+ corrispondenti \textit{system call} sono state inserite nel kernel a partire
+ dalla versione 2.6.16, in precedenza era disponibile una emulazione che, sia
+ pure con prestazioni inferiori, funzionava facendo ricorso all'uso del
+ filesystem \textit{proc} con l'apertura del file attraverso il riferimento a
+ \textit{pathname} del tipo di \texttt{/proc/self/fd/dirfd/relative\_path}.}
+Benché queste funzioni non siano presenti negli standard tradizionali esse
+sono state adottate da altri sistemi unix-like com Solaris i vari BSD, fino ad
+essere incluse in una recente revisione (la POSIX.1-2008) dello standard
+POSIX.1. Con la \acr{glibc} per l'accesso a queste funzioni è necessario
definire la macro \macro{\_ATFILE\_SOURCE}.
L'uso di queste funzioni prevede una apertura iniziale della directory che
sarà la base della risoluzione dei \itindsub{pathname}{relativo}
\textit{pathname} relativi che verranno usati in seguito, dopo di che si dovrà
passare il relativo file descriptor alle varie funzioni che useranno quella
-directory come punto di partenza per la risoluzione.\footnote{in questo modo,
- anche quando si lavora con i \itindex{thread} \textit{thread}, si può
- mantenere una \index{directory~di~lavoro} directory di lavoro diversa per
- ciascuno di essi.}
+directory come punto di partenza per la risoluzione. In questo modo, anche
+quando si lavora con i \itindex{thread} \textit{thread}, si può mantenere una
+\index{directory~di~lavoro} directory di lavoro diversa per ciascuno di essi.
Questo metodo, oltre a risolvere i problemi di \itindex{race~condition}
\textit{race condition}, consente anche di ottenere aumenti di prestazioni
significativi quando si devono eseguire molte operazioni su sezioni
dell'albero dei file che prevedono delle gerarchie di sottodirectory molto
-profonde; infatti in questo caso basta eseguire la risoluzione del
+profonde. Infatti in questo caso basta eseguire la risoluzione del
\textit{pathname} della directory di partenza una sola volta (nell'apertura
iniziale) e non tutte le volte che si deve accedere a ciascun file che essa
contiene.
La sintassi generale di queste nuove funzioni è che esse prevedono come primo
-argomento il file descriptor della directory da usare come base, mentre gli
-argomenti successivi restano identici a quelli della corrispondente funzione
-ordinaria; ad esempio nel caso di \funcd{openat} avremo che essa è definita
-come:
+argomento il file descriptor della directory da usare come base per la
+risoluzione dei nomi, mentre gli argomenti successivi restano identici a
+quelli della corrispondente funzione ordinaria. Se ad esempio prendiamo in
+esame la nuova funzione di sistema \funcd{openat}, avremo il prototipo:
\begin{funcproto}{
\fhead{fcntl.h}
\fdecl{int openat(int dirfd, const char *pathname, int flags)}
-\fdecl{int openat(int dirfd, const char *pathname, int flags, mode\_t
- mode))}
+\fdecl{int openat(int dirfd, const char *pathname, int flags, mode\_t mode)}
\fdesc{Apre un file a partire da una directory di \index{directory~di~lavoro}
lavoro.}
}
corrispettive classiche, con la sola eccezione del fatto che se fra i loro
argomenti si utilizza un \itindsub{pathname}{relativo} \textit{pathname}
relativo questo sarà risolto rispetto alla directory indicata
-da \param{dirfd}; qualora invece si usi un \itindsub{pathname}{assoluto}
+da \param{dirfd}. Qualora invece si usi un \itindsub{pathname}{assoluto}
\textit{pathname} assoluto \param{dirfd} verrà semplicemente ignorato. Infine
-se per
-\param{dirfd} si usa il valore speciale \const{AT\_FDCWD},\footnote{questa,
- come le altre costanti \texttt{AT\_*}, è definita in \headfile{fcntl.h},
- pertanto se la si vuole usare occorrerà includere comunque questo file,
- anche per le funzioni che non sono definite in esso.} la risoluzione sarà
-effettuata rispetto alla directory di \index{directory~di~lavoro} lavoro
-corrente del processo.
+se per \param{dirfd} si usa il valore speciale \const{AT\_FDCWD}, la
+risoluzione sarà effettuata rispetto alla directory di
+\index{directory~di~lavoro} lavoro corrente del processo. Si tenga presente
+però che questa, come le altre costanti \texttt{AT\_*}, è definita in
+\headfile{fcntl.h}, pertanto se la si vuole usare occorrerà includere comunque
+questo file, anche per le funzioni che non sono definite in esso.
Così come il comportamento, anche i valori di ritorno e le condizioni di
errore delle nuove funzioni sono gli stessi delle funzioni classiche, agli
errori si aggiungono però quelli dovuti a valori errati per \param{dirfd}; in
particolare si avrà un errore di \errcode{EBADF} se esso non è un file
descriptor valido, ed un errore di \errcode{ENOTDIR} se esso non fa
-riferimento ad una directory.\footnote{tranne il caso in cui si sia
- specificato un \itindsub{pathname}{assoluto} \textit{pathname} assoluto, nel
- qual caso, come detto, il valore di \param{dirfd} sarà completamente
- ignorato.}
-
-In tab.~\ref{tab:file_atfunc_corr} si sono riportate le funzioni introdotte
-con questa nuova interfaccia, con a fianco la corrispondente funzione
-classica.\footnote{in realtà, come visto in sez.~\ref{sec:file_temp_file}, le
- funzioni \func{utimes} e \func{lutimes} non sono propriamente le
- corrispondenti di \func{utimensat}, dato che questa ha una maggiore
- precisione nella indicazione dei tempi dei file.} La gran parte di queste
-seguono la convenzione appena vista per \func{openat}, in cui agli argomenti
-della corrispondente funzione classica viene anteposto
-l'argomento \param{dirfd}.\footnote{non staremo pertanto a riportarle una per
- una.} Per una parte di queste, indicate dal contenuto della omonima colonna
-di tab.~\ref{tab:file_atfunc_corr}, oltre al nuovo argomento iniziale, è
-prevista anche l'aggiunta di un ulteriore argomento finale, \param{flags}.
+riferimento ad una directory, tranne il caso in cui si sia specificato un
+\itindsub{pathname}{assoluto} \textit{pathname} assoluto, nel qual caso, come
+detto, il valore di \param{dirfd} sarà completamente ignorato.
\begin{table}[htb]
\centering
\hline
\hline
\func{faccessat} &$\bullet$&\func{access} \\
- \func{fchmodat} &$\bullet$&\func{chmod} \\
+ \funcm{fchmodat} &$\bullet$&\func{chmod} \\
\func{fchownat} &$\bullet$&\func{chown},\func{lchown}\\
- \func{fstatat} &$\bullet$&\func{stat},\func{lstat} \\
+ \funcm{fstatat} &$\bullet$&\func{stat},\func{lstat} \\
\func{utimensat} &$\bullet$&\func{utimes},\func{lutimes}\\
\func{linkat} &$\bullet$\footnotemark&\func{link} \\
\funcm{mkdirat} & -- &\func{mkdir} \\
\footnotetext{in questo caso l'argomento \param{flags} è disponibile ed
utilizzabile solo a partire dal kernel 2.6.18.}
-% TODO manca prototipo di fchmodat, verificare se metterlo o metter menzione
-% TODO manca prototipo di fstatat, verificare se metterlo o metter menzione
+In tab.~\ref{tab:file_atfunc_corr} si sono riportate le funzioni introdotte
+con questa nuova interfaccia, con a fianco la corrispondente funzione
+classica. La gran parte di queste seguono la convenzione appena vista per
+\func{openat}, in cui agli argomenti della corrispondente funzione classica
+viene anteposto l'argomento \param{dirfd}, ed hanno per il resto un
+comportamento identico e non staremo pertanto a trattarle una per una. Per una
+parte di queste, indicate dal contenuto della omonima colonna di
+tab.~\ref{tab:file_atfunc_corr}, oltre al nuovo argomento iniziale, è prevista
+anche l'aggiunta di un ulteriore argomento finale, \param{flags}.
+
+
% TODO manca prototipo di linkat, verificare se metterlo o metter menzione
% TODO manca prototipo di utimensat, verificare se metterlo o metter menzione
In questo caso il valore di \param{flags} stabilisce il comportamento della
funzione quando la si applica ad un collegamento simbolico, e l'unico valore
-utilizzabile è \const{AT\_SYMLINK\_NOFOLLOW}\footnote{in \headfile{fcntl.h} è
- definito anche \const{AT\_SYMLINK\_FOLLOW}, che richiede di dereferenziare i
- collegamenti simbolici, essendo questo però il comportamento adottato per un
- valore nullo di \param{flags} questo valore non viene mai usato.} che se
-impostato indica alla funzione di non eseguire la dereferenziazione di un
-eventuale collegamento simbolico, facendo comportare \func{fchownat} come
-\func{lchown} invece che come \func{chown}.
+utilizzabile è \const{AT\_SYMLINK\_NOFOLLOW}, che se impostato indica alla
+funzione di non eseguire la dereferenziazione di un eventuale collegamento
+simbolico, facendo comportare \func{fchownat} come \func{lchown} invece che
+come \func{chown}.
Come accennato fra tutte quelle marcate in tab.~\ref{tab:file_atfunc_corr}
-solo due funzioni possono usare l'argomento \param{flags} con valori diversi
-da \const{AT\_SYMLINK\_NOFOLLOW}, la prima di queste è \funcd{faccessat}, ed
-il suo prototipo è:
+solo due funzioni possono usare l'argomento \param{flags} per indicare altro
+rispetto alla possibilità di seguire o meno un collegamento simbolico, la
+prima di queste è \funcd{faccessat}, ed il suo prototipo è:
\begin{funcproto}{
\fhead{unistd.h}
}
\end{funcproto}
-La funzione esegue lo stesso controllo di accesso effettuabile con
-\func{access}, ma si può utilizzare l'argomento \param{flags} per modificarne
-il comportamento rispetto a quello ordinario di \func{access}. In questo caso
-esso può essere specificato come maschera binaria di due valori:
-\begin{basedescript}{\desclabelwidth{3.0cm}}
-\item[\const{AT\_EACCES}] se impostato \funcd{faccessat} esegue il controllo
- dei permessi usando l'\ids{UID} effettivo invece di quello reale (il
- comportamento di default, che riprende quello di \func{access}).
-\item[\const{AT\_SYMLINK\_NOFOLLOW}] se impostato \funcd{faccessat} non esegue
- la dereferenziazione dei collegamenti simbolici, effettuando il controllo
- dei permessi direttamente sugli stessi.
-\end{basedescript}
+La funzione esegue il controllo di accesso ad un file, ma
+l'argomento \param{flags} consente di modificarne il comportamento rispetto a
+quello ordinario di \func{access}. In questo caso esso può essere specificato
+come maschera binaria di due valori: il solito \const{AT\_SYMLINK\_NOFOLLOW},
+con il significato già spiegato, e \const{AT\_EACCES} per indicare alla
+funzione di eseguire il controllo dei permessi usando l'\ids{UID} effettivo
+invece di quello reale (il comportamento di default, che riprende quello di
+\func{access}).
-La seconda eccezione è \func{unlinkat}, in questo caso l'ulteriore
-argomento \param{flags} viene utilizzato perché tramite esso la funzione possa
-comportarsi sia come analogo di \func{unlink} che di \func{rmdir}; il suo
-prototipo è:
+
+La seconda eccezione è \funcd{unlinkat}, in questo caso
+l'argomento \param{flags} viene utilizzato perché tramite esso si può indicare
+alla fuzione di comportarsi sia come analogo di \func{unlink} che di
+\func{rmdir}; il suo prototipo è:
\begin{funcproto}{
\fhead{fcntl.h}
Di default il comportamento di \func{unlinkat} è equivalente a quello che
avrebbe \func{unlink} applicata a \param{pathname}, fallendo in tutti i casi
in cui questo è una directory, se però si imposta \param{flags} al valore di
-\const{AT\_REMOVEDIR},\footnote{anche se \param{flags} è una maschera binaria,
- essendo questo l'unico flag disponibile per questa funzione, lo si può
- assegnare direttamente.} essa si comporterà come \func{rmdir}, in tal
+\const{AT\_REMOVEDIR}, essa si comporterà come \func{rmdir}, in tal
caso \param{pathname} deve essere una directory, che sarà rimossa qualora
-risulti vuota.
+risulti vuota. Non essendo in questo caso prevista la possibilità di usare
+altri valori (la funzione non segue comunque i collegamenti simbolici) anche
+se \param{flags} è una maschera binaria, essendo \const{AT\_REMOVEDIR} l'unico
+flag disponibile per questa funzione, lo si può assegnare direttamente.
+
+Infine una terza funzione, \funcm{linkat}, utilizza in maniera diversa dalle
+altre l'argomento \param{flags}, anche se in questo caso l'utilizzo continua
+ad essere attinente al comportamento con i collegamenti simbolici. Si ricordi
+che su Linux il comportamento di \func{link} è quello di non seguire mai i
+collegamenti simbolici, pertanto l'uso ordinario dell'argomento parrebbe in
+questo caso essere inutile. A partire dal kernel 2.6.18 invece però è stato
+aggiunta per questa funzione la possibilità di usare il valore
+\const{AT\_SYMLINK\_FOLLOW}, che richiede di dereferenziare i collegamenti
+simbolici.
+
+Dato che questo è il comportamento adottato per un valore nullo
+di \param{flags} da tutte le altre funzioni, \func{linkat} è l'unica per cui
+può essere usato esplicitamente questo valore e per la quale non ha senso
+usare \const{AT\_SYMLINK\_NOFOLLOW}. Per avere un quadro d'insieme si è
+riassunto in tab.~\ref{tab:at-functions_constant_values} l'elenco delle
+costanti utilizzabili per i valori di \param{flags}.
-\itindend{at-functions}
+\begin{table}[htb]
+ \centering
+ \footnotesize
+ \begin{tabular}[c]{|l|p{8cm}|}
+ \hline
+ \textbf{Costante} & \textbf{Significato} \\
+ \hline
+ \hline
+ \const{AT\_SYMLINK\_NOFOLLOW}& se impostato la funzione non esegue la
+ dereferenziazione dei collegamenti simbolici.\\
+ \const{AT\_SYMLINK\_FOLLOW}& se impostato la funzione esegue la
+ dereferenziazione dei collegamenti simbolici
+ (usato esplicitamente solo da \func{linkat}).\\
+ \const{AT\_EACCES} & usato solo da \func{faccessat}, richiede che
+ il controllo dei permessi sia fatto usando
+ l'\ids{UID} effettivo invece di quello
+ reale.\\
+ \const{AT\_REMOVEDIR} & usato solo da \func{unlinkat}, richiede che
+ la funzione si comporti come \func{rmdir}
+ invece che come \func{unlink}.\\
+ \hline
+ \end{tabular}
+ \caption{Le costanti utilizzate per i bit dell'argomento
+ aggiuntivo \param{flags} delle \textit{at-functions}.}
+ \label{tab:at-functions_constant_values}
+\end{table}
-% TODO manca prototipo e motivazione di fexecve, da trattare qui in quanto
-% inserita nello stesso standard e da usare con openat, vedi
-% http://pubs.opengroup.org/onlinepubs/9699939699/toc.pdf
+Un'ultima differenza fra le \textit{at-functions} e le funzioni tradizionali
+di cui sono estensione è, come accennato in sez.~\ref{sec:file_temp_file},
+quella relativa a \funcm{utimensat} che non è propriamente una corrispondente
+esatta di \func{utimes} e \func{lutimes}, dato che questa funzione ha una
+maggiore precisione nella indicazione dei tempi dei file, per i quali come per
+\func{futimes}, si devono usare strutture \struct{timespec} che consentono una
+precisione fino al nanosecondo.
+% NOTA: manca prototipo di utimensat, per ora si lascia una menzione
+\itindend{at-functions}
+
+% TODO: manca prototipo e motivazione di fexecve, da trattare qui in quanto
+% inserita nello stesso standard e da usare con openat, vedi
+% http://pubs.opengroup.org/onlinepubs/9699939699/toc.pdf
\subsection{La funzione \func{fcntl}}
\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},
-il cui prototipo è:
+caratteristiche di un file descriptor, viene usata la funzione di sistema
+\funcd{fcntl}, il cui prototipo è:
\begin{funcproto}{
\fhead{unistd.h}
errori possibili sono \errcode{EINVAL} se \param{arg} è negativo o maggiore
del massimo consentito o \errcode{EMFILE} se il processo ha già raggiunto il
massimo numero di descrittori consentito.
-\item[\const{F\_SETFD}] imposta il valore del \textit{file descriptor flag} al
+\item[\const{F\_DUPFD\_CLOEXEC}] ha lo stesso effetto di \const{F\_DUPFD}, ma
+ in più attiva il flag di \itindex{close-on-exec} \textit{close-on-exec} sul
+ nuovo file descriptor duplicato, in modo da evitare una successiva chiamata
+ con \const{F\_SETFD}. Introdotta con il kernel 2.6.24.
+\item[\const{F\_GETFD}] ritorna il valore dei \textit{file descriptor flags} di
+ \param{fd} o $-1$ in caso di errore, \param{arg} viene ignorato. Se
+ \const{FD\_CLOEXEC} è impostato i file descriptor aperti vengono chiusi
+ attraverso una \func{exec} altrimenti (il comportamento predefinito) restano
+ aperti.
+\item[\const{F\_SETFD}] imposta il valore dei \textit{file descriptor flags} al
valore specificato con \param{arg}. Al momento l'unico bit usato è quello di
\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.
-\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 comportamento predefinito) restano aperti.
-\item[\const{F\_GETFL}] ritorna il valore del \textit{file status flag} in
+\item[\const{F\_GETFL}] ritorna il valore dei \textit{file status flags} in
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
- tab.~\ref{tab:file_open_flags}).
-% TODO toglire riferimeto a tabella flag e mettere altro
-
+ valori dell'argomento \param{flags} di \func{open} che vengono memorizzati,
+ più precisamente quelli riportati in tab.~\ref{tab:open_access_mode_flag} e
+ tab.~\ref{tab:open_operation_flag}).
\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 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}.}
-% TODO toglire riferimeto a tabella flag e mettere altro
-
+ $-1$ in caso di errore. Possono essere impostati solo flag fra quelli
+ riportati in tab.~\ref{tab:open_operation_flag}. su Linux si possono
+ modificare soltanto \const{O\_APPEND}, \const{O\_ASYNC}, \const{O\_DIRECT},
+ \const{O\_NOATIME} e \const{O\_NONBLOCK}.
\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
(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 \ids{PID}).} che è preposto alla ricezione
- dei segnali \signal{SIGIO}\footnote{o qualunque altro segnale alternativo
- impostato con \const{F\_FSETSIG}.} per gli eventi associati al file
+ dei segnali \signal{SIGIO} (o qualunque altro segnale alternativo impostato
+ con \const{F\_FSETSIG}) per gli eventi associati al file
descriptor \param{fd}\footnote{il segnale viene usato sia per il
\textit{Signal Drive I/O}, che tratteremo in
- sez.~\ref{sec:file_asyncronous_operation}, e dai vari meccanismi di
+ sez.~\ref{sec:file_asyncronous_operation}, che dai vari meccanismi di
notifica asincrona, che tratteremo in
sez.~\ref{sec:file_asyncronous_lease}.} e \signal{SIGURG} per la notifica
- dei dati urgenti di un socket.\footnote{vedi
- sez.~\ref{sec:TCP_urgent_data}.} 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
- caso di errore viene restituito $-1$.
+ dei dati urgenti di un socket (vedi sez.~\ref{sec:TCP_urgent_data}). 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}.\footnote{si tenga presente però che se questo valore
+ è compreso nell'intervallo fra $-1$ e $-4095$ questo viene interpretato
+ dalla \acr{glibc} come un errore per cui in tal caso \func{fcntl}
+ ritornerà comunque $-1$ mentre il valore restituito dalla \textit{system
+ call} verrà assegnato ad \var{errno}, cambiato di segno.} 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
- group} che riceverà i segnali \signal{SIGIO} e \signal{SIGURG} per gli
+ group} che riceverà i segnali \signal{SIGIO} e \signal{SIGURG} per gli
eventi associati al file descriptor \param{fd}, ritorna un valore nullo in
caso di successo o $-1$ in caso di errore. Come per \const{F\_GETOWN}, per
impostare un \itindex{process~group} \textit{process group} si deve usare
scrittura (sia per quel che riguarda la bufferizzazione, che le
formattazioni), i \textit{file stream} restano del tutto equivalenti ai file
descriptor (sui quali sono basati), ed in particolare continua a valere quanto
-visto in sez.~\ref{sec:file_sharing} a proposito dell'accesso condiviso ed in
-sez.~\ref{sec:file_access_control} per il controllo di accesso.
+visto in sez.~\ref{sec:file_shared_access} a proposito dell'accesso
+concorrente ed in sez.~\ref{sec:file_access_control} per il controllo di
+accesso.
\itindend{file~stream}
% LocalWords: locking fsetlocking type Virtual operation dentry unistd sys AT
% LocalWords: modification hole functions FSETSIG pathname EEXIST CREAT EINTR
% LocalWords: EISDIR EFBIG EOVERFLOW ELOOP NOFOLLOW ENODEV ENOENT ENOTDIR fork
-
-%%% Local Variables:
-%%% mode: latex
-%%% TeX-master: "gapil"
-%%% End:
-% LocalWords: ENXIO NONBLOCK WRONLY EPERM NOATIME ETXTBSY EWOULDBLOCK EACCES% LocalWords: EFAULT
% LocalWords: EMFILE ENAMETOOLONG ENFILE ENOMEM ENOSPC EROFS exec access RDWR
% LocalWords: RDONLY ioctl AND ACCMODE creation Denial Service DoS opendir NFS
% LocalWords: SOURCE LARGEFILE BITS NOCTTY TRUNC SHLOCK shared EXLOCK race SGI
% LocalWords: sigaction SIGINFO siginfo SETLEASE lease GETLEASE NOTIFY request
% LocalWords: everything framebuffer ENOTTY argp CDROM lsattr chattr magic
% LocalWords: number FIOCLEX FIONCLEX FIOASYNC FIONBIO FIOSETOWN FIOGETOWN
-% LocalWords: FIONREAD epoll FIOQSIZE side effects SAFE BYCALLER QUERY
+% LocalWords: FIONREAD epoll FIOQSIZE side effects SAFE BYCALLER QUERY EACCES
+% LocalWords: EBUSY OpenBSD syncfs
+% LocalWords: ENXIO NONBLOCK WRONLY EPERM NOATIME ETXTBSY EWOULDBLOCK
+% LocalWords: EFAULT
+
+%%% Local Variables:
+%%% mode: latex
+%%% TeX-master: "gapil"
+%%% End: