X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=fileunix.tex;h=d5221ca500ea6330369c59035836f2e36d9b3b62;hp=a8a7d781255c6b31fac6583d12c538ad0be33bac;hb=a001cbbaab17ce4f15d210d74af8912dbaa07b68;hpb=aa5d63f2af4475ae1188f695a33e4d0bee55f787 diff --git a/fileunix.tex b/fileunix.tex index a8a7d78..d5221ca 100644 --- a/fileunix.tex +++ b/fileunix.tex @@ -3,11 +3,12 @@ Esamineremo in questo capitolo la prima delle due interfacce di programmazione -per i file, quella dei \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 è costruita anche l'interfaccia definita -dallo standard ANSI C che affronteremo al \capref{cha:files_std_interface}. +per i file, quella dei \textit{file descriptor}\index{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 è +costruita anche l'interfaccia definita dallo standard ANSI C che affronteremo +al \capref{cha:files_std_interface}. @@ -33,10 +34,10 @@ terminate le operazioni, il file dovr canale di comunicazione impedendo ogni ulteriore operazione. All'interno di ogni processo i file aperti sono identificati da un intero non -negativo, chiamato appunto \textit{file descriptor}. Quando un file viene -aperto la funzione \func{open} restituisce questo numero, tutte le ulteriori -operazioni saranno compiute specificando questo stesso valore come argomento -alle varie funzioni dell'interfaccia. +negativo, chiamato appunto \textit{file descriptor}\index{file descriptor}. +Quando un file viene aperto la funzione \func{open} restituisce questo numero, +tutte le ulteriori operazioni saranno compiute specificando questo stesso +valore come argomento alle varie funzioni dell'interfaccia. Per capire come funziona il meccanismo occorre spiegare a grandi linee come è che il kernel gestisce l'interazione fra processi e file. Il kernel mantiene @@ -56,8 +57,8 @@ particolare: \item una tabella che contiene un puntatore alla relativa voce nella \textit{file table} per ogni file aperto. \end{itemize*} -il \textit{file descriptor} in sostanza è l'intero positivo che indicizza -quest'ultima tabella. +il \textit{file descriptor}\index{file descriptor} in sostanza è l'intero +positivo che indicizza quest'ultima tabella. La \textit{file table} è una tabella che contiene una voce per ciascun file che è stato aperto nel sistema. In Linux è costituita da strutture di tipo @@ -87,23 +88,23 @@ varie strutture di dati sulla quale essa \end{figure} Ritorneremo su questo schema più volte, dato che esso è fondamentale per capire i dettagli del funzionamento dell'interfaccia dei \textit{file - descriptor}. + descriptor}\index{file descriptor}. \subsection{I file standard} \label{sec:file_std_descr} -Come accennato i \textit{file descriptor} non sono altro che un indice nella -tabella dei file aperti di ciascun processo; per questo motivo essi vengono -assegnati in successione tutte le volte che si apre un nuovo file (se non ne è -stato chiuso nessuno in precedenza). +Come accennato i \textit{file descriptor}\index{file descriptor} non sono +altro che un indice nella tabella dei file aperti di ciascun processo; per +questo motivo essi vengono assegnati in successione tutte le volte che si apre +un nuovo file (se non ne è 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} 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à. +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 @@ -137,10 +138,11 @@ posto di questi valori numerici: \label{tab:file_std_files} \end{table} -In \curfig\ 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). +In \figref{tab:file_std_files} si è utilizzata questa situazione come esempio, +facendo riferimento ad un programma in cui lo \textit{standard input} è +associato ad un file mentre lo \textit{standard output} e lo \textit{standard + error} sono entrambi associati ad un altro file (e quindi utilizzano lo +stesso inode). 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 @@ -182,8 +184,8 @@ prototipo specificati da \var{mode}. \bodydesc{La funzione ritorna il file descriptor in caso di successo e -1 in - caso di errore. In questo caso la variabile \var{errno} viene settata ad - uno dei valori: + caso di errore. In questo caso la variabile \var{errno} assumerà uno dei + valori: \begin{errlist} \item[\macro{EEXIST}] \var{pathname} esiste e si è specificato \macro{O\_CREAT} e \macro{O\_EXCL}. @@ -191,7 +193,7 @@ prototipo l'accesso in scrittura. \item[\macro{ENOTDIR}] si è specificato \macro{O\_DIRECTORY} e \var{pathname} non è una directory. - \item[\macro{ENXIO}] si sono settati \macro{O\_NOBLOCK} o \macro{O\_WRONLY} + \item[\macro{ENXIO}] si sono impostati \macro{O\_NOBLOCK} o \macro{O\_WRONLY} ed il file è una fifo che non viene letta da nessun processo o \var{pathname} è un file di dispositivo ma il dispositivo è assente. \item[\macro{ENODEV}] \var{pathname} si riferisce a un file di dispositivo @@ -221,7 +223,7 @@ sempre il file descriptor con il valore pi \hline % modalità di accesso al file \macro{O\_RDONLY} & apre il file in sola lettura. \\ \macro{O\_WRONLY} & apre il file in sola scrittura. \\ - \macro{O\_RDWR} & apre il file lettura/scrittura. \\ + \macro{O\_RDWR} & apre il file in lettura/scrittura. \\ \hline % modalità di apertura del file \hline \macro{O\_CREAT} & se il file non esiste verrà creato, con le regole di @@ -232,11 +234,11 @@ sempre il file descriptor con il valore pi \func{open} con \macro{EEXIST}. \\ \macro{O\_NONBLOCK} & apre il file in modalità non bloccante. Questo valore specifica anche una modalità di operazione (vedi sotto), e - comporta che \func{open} ritorni immediatamente (torneremo su - questo in \secref{sec:file_noblocking}). \\ + comporta che \func{open} ritorni immediatamente (l'opzione ha senso + solo per le fifo, torneremo questo in \secref{sec:ipc_named_pipe}). \\ \macro{O\_NOCTTY} & se \var{pathname} si riferisce ad un device di terminale, questo non diventerà il terminale di controllo, anche se il - processo non ne ha ancora uno (si veda \secref{sec:sess_xxx}). \\ + processo non ne ha ancora uno (si veda \secref{sec:sess_ctrl_term}). \\ \macro{O\_SHLOCK} & opzione di BSD, acquisisce uno shared lock (vedi \secref{sec:file_locking}) sul file. Non è disponibile in Linux. \\ \macro{O\_EXLOCK} & opzione di BSD, acquisisce uno lock esclusivo (vedi @@ -251,7 +253,8 @@ sempre il file descriptor con il valore pi opzione è ignorata. \\ \macro{O\_DIRECTORY} & se \var{pathname} non è una directory la chiamata fallisce. Questo flag è specifico di Linux ed è stato introdotto con il - kernel 2.1.126 per evitare dei DoS\protect\footnotemark\ quando + kernel 2.1.126 per evitare dei + \textit{DoS}\index{DoS}\protect\footnotemark\ quando \func{opendir} viene chiamata su una fifo o su un device di unità a nastri, non deve essere utilizzato al di fuori dell'implementazione di \func{opendir}. \\ @@ -261,18 +264,19 @@ sempre il file descriptor con il valore pi \hline \hline % modalità di operazione col file \macro{O\_APPEND} & il file viene aperto in append mode. Prima di ciascuna - scrittura la posizione corrente viene sempre settata alla fine del + 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\\ \macro{O\_NONBLOCK} & il file viene aperto in modalità non bloccante per - le operazioni di I/O: questo significa il fallimento di \func{read} in - assenza di dati da leggere e quello di \func{write} in caso di - impossibilità di scrivere immediatamente. L'opzione è effettiva solo per - le fifo e per alcuni file di dispositivo. \\ + le operazioni di I/O (che tratteremo in \secref{sec:file_noblocking}): + questo significa il fallimento di \func{read} in assenza di dati da + leggere e quello di \func{write} in caso di impossibilità di scrivere + immediatamente. Questa modalità ha senso solo per le fifo e per alcuni + file di dispositivo. \\ \macro{O\_NDELAY} & in Linux\footnotemark\ è sinonimo di \macro{O\_NONBLOCK}.\\ \macro{O\_ASYNC} & apre il file per l'I/O in modalità - asincrona (vedi \secref{sec:file_asyncronous_io}). Quando è settato viene + asincrona (vedi \secref{sec:file_asyncronous_io}). Quando è impostato viene generato il segnale \macro{SIGIO} tutte le volte che sono disponibili dati in input sul file. \\ \macro{O\_SYNC} & apre il file per l'input/output sincrono, ogni @@ -289,15 +293,16 @@ sempre il file descriptor con il valore pi \label{tab:file_open_flags} \end{table} -\footnotetext[2]{la man page di \func{open} segnala che questa opzione è - difettosa su NFS, e che i programmi che la usano per stabilire un file di - lock possono incorrere in una race condition. Si consiglia come alternativa - di usare un file con un nome univoco e la funzione \func{link} per - verificarne l'esistenza.} +\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 + file di lock (vedi \secref{sec:ipc_file_lock}) possono incorrere in una race + condition\index{race condition}. Si consiglia come alternativa di usare un + file con un nome univoco e la funzione \func{link} per verificarne + l'esistenza.} -\footnotetext[3]{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[3]{\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 append, ed il kernel deve simularla, ma questo comporta la possibilità di una race @@ -315,11 +320,11 @@ visti in \secref{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 +Il nuovo file descriptor non è condiviso con nessun altro processo (torneremo sulla condivisione dei file, in genere accessibile dopo una \func{fork}, in -\secref{sec:file_sharing}). Il nuovo file descriptor è settato di default per -restare aperto attraverso una \func{exec} (come accennato in -\secref{sec:proc_exec}) e l'offset è settato all'inizio del file. +\secref{sec:file_sharing}). Il nuovo file descriptor è impostato per restare +aperto attraverso una \func{exec} (come accennato in \secref{sec:proc_exec}) e +l'offset è impostato all'inizio del file. L'argomento \param{mode} specifica i permessi con cui il file viene eventualmente creato; i valori possibili sono gli stessi già visti in @@ -332,12 +337,13 @@ La funzione prevede diverse opzioni, che vengono specificate usando vari bit dell'argomento \param{flags}. Alcuni di questi bit vanno anche a costituire il flag di stato del file (o \textit{file status flag}), che è mantenuto nel campo \var{f\_flags} della struttura \var{file} (al solito si veda lo schema -di \curfig). Essi sono divisi in tre categorie principali: +di \figref{fig:file_proc_file}). Essi sono divisi in tre categorie +principali: \begin{itemize} \item \textsl{i bit delle modalità di accesso}: specificano con quale modalità si accederà al file: i valori possibili sono lettura, scrittura o lettura/scrittura. Uno di questi bit deve essere sempre specificato quando - si apre un file. Vengono settati alla chiamata da \func{open}, e possono + si apre un file. Vengono impostati alla chiamata da \func{open}, e possono essere riletti con una \func{fcntl} (fanno parte del \textit{file status flag}), ma non possono essere modificati. \item \textsl{i bit delle modalità di apertura}: permettono di specificare @@ -347,7 +353,7 @@ di \curfig). Essi sono divisi in tre categorie principali: \item \textsl{i bit delle modalità di operazione}: permettono di specificare alcune caratteristiche del comportamento delle future operazioni sul file (come la \func{read} o la \func{write}). Anch'essi fanno parte del - \textit{file status flag}. Il loro valore è settato alla chiamata di + \textit{file status flag}. Il loro valore è impostato alla chiamata di \func{open}, ma possono essere riletti e modificati (insieme alle caratteristiche operative che controllano) con una \func{fcntl}. \end{itemize} @@ -358,7 +364,7 @@ ciascuno di questi bit. Dette costanti possono essere combinate fra di loro con un OR aritmetico per costruire il valore (in forma di maschera binaria) dell'argomento \param{flags} da passare alla \func{open} per specificarne il comportamento. I due flag \macro{O\_NOFOLLOW} e \macro{O\_DIRECTORY} sono -estensioni specifiche di Linux, e deve essere usata definita la macro +estensioni specifiche di Linux, e deve essere definita la macro \macro{\_GNU\_SOURCE} per poterli usare. Nelle prime versioni di Unix i valori di \param{flag} specificabili per @@ -367,7 +373,7 @@ questo motivo per creare un nuovo file c'era una system call apposita, \func{creat}, il cui prototipo è: \begin{prototype}{fcntl.h} {int creat(const char *pathname, mode\_t mode)} - Crea un nuovo file vuoto, con i permessi specificati da \var{mode}. É del + Crea un nuovo file vuoto, con i permessi specificati da \var{mode}. È del tutto equivalente a \code{open(filedes, O\_CREAT|O\_WRONLY|O\_TRUNC, mode)}. \end{prototype} \noindent adesso questa funzione resta solo per compatibilità con i vecchi @@ -383,7 +389,7 @@ descriptor ritorna disponibile; il suo prototipo Chiude il descrittore \var{fd}. \bodydesc{La funzione ritorna 0 in caso di successo e -1 in caso di errore, - ed in questo caso \var{errno} è settata ai valori: + ed in questo caso \var{errno} assumerà uno dei valori: \begin{errlist} \item[\macro{EBADF}] \var{fd} non è un descrittore valido. \item[\macro{EINTR}] la funzione è stata interrotta da un segnale. @@ -430,17 +436,17 @@ lettura e scrittura avvengono a partire da questa posizione che viene automaticamente spostata in avanti del numero di byte letti o scritti. In genere (a meno di non avere richiesto la modalità \macro{O\_APPEND}) questa -posizione viene settata a zero all'apertura del file. È possibile settarla ad -un valore qualsiasi con la funzione \func{lseek}, il cui prototipo è: +posizione viene impostata a zero all'apertura del file. È possibile impostarla +ad un valore qualsiasi con la funzione \func{lseek}, il cui prototipo è: \begin{functions} \headdecl{sys/types.h} \headdecl{unistd.h} \funcdecl{off\_t lseek(int fd, off\_t offset, int whence)} - Setta la posizione attuale nel file. + Imposta la posizione attuale nel file. \bodydesc{La funzione ritorna valore della posizione corrente in caso di - successo e -1 in caso di errore nel qual caso \var{errno} viene settata ad - uno dei valori: + successo e -1 in caso di errore nel qual caso \var{errno} assumerà uno dei + valori: \begin{errlist} \item[\macro{ESPIPE}] \param{fd} è una pipe, un socket o una fifo. \item[\macro{EINVAL}] \param{whence} non è un valore valido. @@ -448,22 +454,25 @@ un valore qualsiasi con la funzione \func{lseek}, il cui prototipo ed inoltre \macro{EBADF}.} \end{functions} -La nuova posizione è settata usando il valore specificato da \param{offset}, +La nuova posizione è impostata usando il valore specificato da \param{offset}, sommato al riferimento dato da \param{whence}; quest'ultimo può assumere i seguenti valori\footnote{per compatibilità con alcune vecchie notazioni questi valori possono essere rimpiazzati rispettivamente con 0, 1 e 2 o con \macro{L\_SET}, \macro{L\_INCR} e \macro{L\_XTND}.}: \begin{basedescript}{\desclabelwidth{2.0cm}} -\item[\macro{SEEK\_SET}] si fa riferimento all'inizio del file: il valore di - \var{offset} è la nuova posizione. +\item[\macro{SEEK\_SET}] si fa riferimento all'inizio del file: il valore + (sempre positivo) di \param{offset} indica direttamente la nuova posizione + corrente. \item[\macro{SEEK\_CUR}] si fa riferimento alla posizione corrente del file: - \var{offset} può essere negativo e positivo. -\item[\macro{SEEK\_END}] si fa riferimento alla fine del file: il valore di - \var{offset} può essere negativo e positivo. + ad essa viene sommato \param{offset} (che può essere negativo e positivo) + per ottenere la nuova posizione corrente. +\item[\macro{SEEK\_END}] si fa riferimento alla fine del file: alle dimensioni + del file viene sommato \param{offset} (che può essere negativo e positivo) + per ottenere la nuova posizione corrente. \end{basedescript} Come accennato in \secref{sec:file_file_size} con \func{lseek} è possibile -settare la posizione corrente anche al di la della fine del file, e alla +impostare la posizione corrente anche oltre la fine del file, e alla successiva scrittura il file sarà esteso. La chiamata non causa nessuna attività di input/output, si limita a modificare la posizione corrente nel kernel (cioè \var{f\_pos} in \var{file}, vedi \figref{fig:file_proc_file}). @@ -473,35 +482,36 @@ Dato che la funzione ritorna la nuova posizione, usando il valore zero per funzione con \code{lseek(fd, 0, SEEK\_CUR)}. Si tenga presente inoltre che usare \macro{SEEK\_END} non assicura affatto che -successiva scrittura avvenga alla fine del file, infatti se questo è stato +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 settata in precedenza. -(questa è una potenziale sorgente di \textit{race condition}, vedi -\secref{sec:file_atomic}). +essersi spostata, ma noi scriveremo alla posizione impostata in precedenza +(questa è una potenziale sorgente di \textit{race condition}\index{race + condition}, vedi \secref{sec:file_atomic}). Non tutti i file supportano la capacità di eseguire una \func{lseek}, in questo caso la funzione ritorna l'errore \macro{EPIPE}. Questo, oltre che per i tre casi citati nel prototipo, vale anche per tutti quei dispositivi che non -supportano questa funzione, come ad esempio per le \acr{tty}.\footnote{altri - sistemi, usando \macro{SEEK\_SET}, in questo caso ritornano il numero di - caratteri che vi sono stati scritti.} Lo standard POSIX però non specifica -niente al proposito. Infine alcuni device, ad esempio \file{/dev/null}, non -causano un errore ma restituiscono un valore indefinito. +supportano questa funzione, come ad esempio per i file di +terminale.\footnote{altri sistemi, usando \macro{SEEK\_SET}, in questo caso + ritornano il numero di caratteri che vi sono stati scritti.} Lo standard +POSIX però non specifica niente in proposito. Infine alcuni file speciali, ad +esempio \file{/dev/null}, non causano un errore ma restituiscono un valore +indefinito. \subsection{La funzione \func{read}} \label{sec:file_read} -Una volta che un file è stato aperto su possono leggere i dati che contiene -utilizzando la funzione \func{read}, il cui prototipo è: +Una volta che un file è stato aperto (con il permesso in lettura) su possono +leggere i dati che contiene utilizzando la funzione \func{read}, il cui +prototipo è: \begin{prototype}{unistd.h}{ssize\_t read(int fd, void * buf, size\_t count)} Cerca di leggere \var{count} byte dal file \var{fd} al buffer \var{buf}. \bodydesc{La funzione ritorna il numero di byte letti in caso di successo e - -1 in caso di errore, nel qual caso \var{errno} viene settata ad uno dei - valori: + -1 in caso di errore, nel qual caso \var{errno} assumerà uno dei valori: \begin{errlist} \item[\macro{EINTR}] la funzione è stata interrotta da un segnale prima di aver potuto leggere qualsiasi dato. @@ -529,7 +539,7 @@ sua fine, e la funzione ritorna regolarmente il numero di byte letti effettivamente. Raggiunta la fine del file, alla ripetizione di un'operazione di lettura, -otterremmo il ritorno immediato di \func{read} con uno zero. La condizione +otterremmo il ritorno immediato di \func{read} con uno zero. La condizione di raggiungimento della fine del file non è un errore, e viene segnalata appunto da un valore di ritorno di \func{read} nullo. Ripetere ulteriormente la lettura non avrebbe nessun effetto se non quello di continuare a ricevere zero @@ -538,55 +548,58 @@ come valore di ritorno. Con i \textsl{file regolari} questa è l'unica situazione in cui si può avere un numero di byte letti inferiore a quello richiesto, ma questo non è vero quando si legge da un terminale, da una fifo o da una pipe. In tal caso -infatti, se non ci sono dati in ingresso, la \func{read} si blocca e ritorna -solo quando ne arrivano; se il numero di byte richiesti eccede quelli -disponibili la funzione ritorna comunque, ma con un numero di byte inferiore a -quelli richiesti. +infatti, se non ci sono dati in ingresso, la \func{read} si blocca (a meno di +non aver selezionato la modalità non bloccante, vedi +\secref{sec:file_noblocking}) e ritorna solo quando ne arrivano; se il numero +di byte richiesti eccede quelli disponibili la funzione ritorna comunque, ma +con un numero di byte inferiore a quelli richiesti. Lo stesso comportamento avviene caso di lettura dalla rete (cioè su un socket, -come vedremo in \secref{sec:sock_io_behav}), o per certi dispositivi, come le -unità a nastro, che restituiscono un singolo blocco di dati alla volta. +come vedremo in \secref{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 \macro{EINTR} e \macro{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 prendere è quella di rieseguire la funzione. Torneremo -sull'argomento in \secref{sec:sig_gen_beha}. - -La seconda si verifica quando il file è in modalità non bloccante e non ci -sono dati in ingresso: la funzione allora ritorna immediatamente con un errore -\macro{EAGAIN}\footnote{sotto BSD questo per questo errore viene usata la - costante \macro{EWOULDBLOCK}, in GNU/Linux questa è sinonima di - \macro{EAGAIN}.} che nel caso indica soltanto che occorrerà provare a -ripetere la lettura. - - -Nella seconda versione delle \textit{Single Unix +tal caso l'azione da intraprendere è quella di rieseguire la funzione. +Torneremo in dettaglio sull'argomento in \secref{sec:sig_gen_beha}. + +La seconda si verifica quando il file è in modalità non bloccante (vedi +\secref{sec:file_noblocking}) e non ci sono dati in ingresso: la funzione +allora ritorna immediatamente con un errore \macro{EAGAIN}\footnote{sotto BSD + per questo errore viene usata la costante \macro{EWOULDBLOCK}, in Linux, con + le glibc, questa è sinonima di \macro{EAGAIN}.} che indica soltanto che +occorrerà provare a ripetere la lettura. + +La funzione \func{read} è una delle system call fondamentali, esistenti fin +dagli albori di Unix, ma nella seconda versione delle \textit{Single Unix Specification}\footnote{questa funzione, e l'analoga \func{pwrite} sono state aggiunte nel kernel 2.1.60, il supporto nelle \acr{glibc}, compresa l'emulazione per i vecchi kernel che non hanno la system call, è stato - aggiunto con la versione 2.1.} (quello che viene chiamato normalmente Unix98, -vedi \secref{sec:intro_opengroup}) è stata introdotta la definizione di -un'altra funzione di lettura, \func{pread}, che diventa accessibile con la -definizione: -\begin{verbatim} - #define _XOPEN_SOURCE 500 -\end{verbatim} -il prototipo di questa funzione è: + aggiunto con la versione 2.1, in versioni precedenti sia del kernel che + delle librerie la funzione non è disponibile.} (quello che viene chiamato +normalmente Unix98, vedi \secref{sec:intro_opengroup}) è stata introdotta la +definizione di un'altra funzione di lettura, \func{pread}, il cui prototipo è: \begin{prototype}{unistd.h} {ssize\_t pread(int fd, void * buf, size\_t count, off\_t offset)} - + Cerca di leggere \var{count} byte dal file \var{fd}, a partire dalla posizione \var{offset}, nel buffer \var{buf}. \bodydesc{La funzione ritorna il numero di byte letti in caso di successo e -1 - in caso di errore, nel qual caso \var{errno} viene settata secondo i valori - già visti per \func{read} e \func{lseek}.} + 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: +\begin{verbatim} + #define _XOPEN_SOURCE 500 +\end{verbatim} Questa funzione serve quando si vogliono leggere dati dal file senza -modificarne la posizione corrente. È equivalente alla esecuzione di una -\func{read} e una \func{lseek}, ma permette di eseguire l'operazione +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 \secref{sec:file_sharing}). Il valore di \var{offset} fa sempre riferimento all'inizio del file. @@ -595,15 +608,14 @@ condivisa da processi diversi (vedi \secref{sec:file_sharing}). Il valore di \subsection{La funzione \func{write}} \label{sec:file_write} -Una volta che un file è stato aperto su può scrivere su di esso utilizzando la -funzione \func{write}, il cui prototipo è: +Una volta che un file è stato aperto (con il permesso in scrittura) su può +scrivere su di esso utilizzando la funzione \func{write}, il cui prototipo è: \begin{prototype}{unistd.h}{ssize\_t write(int fd, void * buf, size\_t count)} Scrive \var{count} byte dal buffer \var{buf} sul file \var{fd}. \bodydesc{La funzione ritorna il numero di byte scritti in caso di successo - e -1 in caso di errore, nel qual caso \var{errno} viene settata ad uno dei - valori: + e -1 in caso di errore, nel qual caso \var{errno} assumerà uno dei valori: \begin{errlist} \item[\macro{EINVAL}] \var{fd} è connesso ad un oggetto che non consente la scrittura. @@ -648,8 +660,8 @@ Cerca di scrivere sul file \var{fd}, a partire dalla posizione \var{offset}, \var{count} byte dal buffer \var{buf}. \bodydesc{La funzione ritorna il numero di byte letti in caso di successo e -1 - in caso di errore, nel qual caso \var{errno} viene settata secondo i valori - già visti per \func{write} e \func{lseek}.} + in caso di errore, nel qual caso \var{errno} assumerà i valori già visti per + \func{write} e \func{lseek}.} \end{prototype} \noindent e per essa valgono le stesse considerazioni fatte per \func{pread}. @@ -668,7 +680,7 @@ dell'argomento sar \label{sec:file_sharing} In \secref{sec:file_fd} abbiamo descritto brevemente l'architettura -dell'interfaccia coi file da parte di un processo, mostrando in +dell'interfaccia con i file da parte di un processo, mostrando in \figref{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. @@ -699,13 +711,13 @@ stesso file, in particolare occorre tenere presente che: scrittura eccede la dimensione corrente del file questo verrà esteso automaticamente con l'aggiornamento del campo \var{i\_size} nell'inode. \item se un file è in modalità \macro{O\_APPEND} tutte le volte che viene - effettuata una scrittura la posizione corrente viene prima settata alla + effettuata una scrittura la posizione corrente viene prima impostata alla dimensione corrente del file letta 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 \var{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 settata leggendo la dimensione corrente dall'inode. + la posizione viene impostata leggendo la dimensione corrente dall'inode. \end{itemize} \begin{figure}[htb] @@ -728,9 +740,9 @@ riferimento alla stessa voce nella \textit{file table}, condividendo cos posizione corrente sul file. Questo ha le conseguenze descritte a suo tempo in \secref{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 è la stesso per entrambi). +\var{f\_pos} che è lo stesso per entrambi). -Si noti inoltre che anche i flag di stato del file (quelli settati +Si noti inoltre che anche i flag di stato del file (quelli impostati dall'argomento \param{flag} di \func{open}) essendo tenuti nella voce della \textit{file table}\footnote{per la precisione nel campo \var{f\_flags} di \var{file}.}, vengono in questo caso condivisi. Ai file però sono associati @@ -742,10 +754,10 @@ voce della \textit{file table}. -\subsection{Operazioni atomiche coi file} +\subsection{Operazioni atomiche con i file} \label{sec:file_atomic} -Come si è visto in un sistema unix è sempre possibile per più processi +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. @@ -759,13 +771,14 @@ utilizzare meccanismi di sincronizzazione pi Un caso tipico di necessità di accesso condiviso in scrittura è quello in cui vari processi devono scrivere alla fine di un file (ad esempio un file di -log). Come accennato in \secref{sec:file_lseek} settare la posizione alla fine -del file e poi scrivere può condurre ad una \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 settata con la \func{lseek} che non corrisponde più alla fine del -file, e la successiva \func{write} sovrascriverà i dati del secondo processo. +log). Come accennato in \secref{sec:file_lseek} impostare la posizione alla +fine del file e poi scrivere può condurre ad una \textit{race + condition}\index{race condition}: infatti può succedere che un secondo +processo scriva alla fine del file fra la \func{lseek} e la \func{write}; in +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à @@ -779,10 +792,10 @@ Un altro caso tipico in cui creare un 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 da parte di un altro processo che crea lo -stesso file fra il controllo e la creazione. +possibilità di una race condition\index{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 pe \func{open} i due flag +Per questo motivo sono stati introdotti per \func{open} i due flag \macro{O\_CREAT} e \macro{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 @@ -800,10 +813,11 @@ 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 da la garanzia assoluta che i dati siano integri dopo la chiamata, - l'hardware dei dischi è in genere dotato di un suo meccanismo interno che - può ritardare ulteriormente la scrittura effettiva.} La prima di queste -funzioni è \func{sync} il cui prototipo è: + 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 è \func{sync} il cui +prototipo è: \begin{prototype}{unistd.h}{int sync(void)} Sincronizza il buffer della cache dei file col disco. @@ -818,9 +832,13 @@ 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 per l'update dei dati è ogni 30 secondi, ma in Linux era -di 5 secondi; con le nuove versioni poi, è il kernel che si occupa -direttamente di tutto quanto. +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 \file{/proc/sys/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 @@ -833,7 +851,7 @@ usare le due funzioni \func{fsync} e \func{fdatasync}, i cui prototipi sono: Sincronizza i dati del file \param{fd}. \bodydesc{La funzione ritorna 0 in caso di successo e -1 in caso di errore, - nel qual caso i codici restituiti in \var{errno} sono: + nel qual caso \var{errno} assume i valori: \begin{errlist} \item[\macro{EINVAL}] \param{fd} è un file speciale che non supporta la sincronizzazione. @@ -843,8 +861,10 @@ usare le due funzioni \func{fsync} e \func{fdatasync}, i cui prototipi sono: 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 metadata dell'inode (i dati -di \var{fstat} come i tempi del file). +\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 che si leggono con \var{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 @@ -866,7 +886,7 @@ prototipo Crea una copia del file descriptor \param{oldfd}. \bodydesc{La funzione ritorna il nuovo file descriptor in caso di successo e - -1 in caso di errore, nel qual caso \var{errno} viene settata ad uno dei + -1 in caso di errore, nel qual caso \var{errno} assumerà uno dei valori: \begin{errlist} \item[\macro{EBADF}] \param{oldfd} non è un file aperto. @@ -881,7 +901,8 @@ interscambiati nell'uso. Per capire meglio il funzionamento della funzione si può fare riferimento a \figref{fig:file_dup}: l'effetto della funzione è semplicemente quello di copiare il valore nella struttura \var{file\_struct}, cosicché anche il nuovo file descriptor fa riferimento alla stessa voce -nella \textit{file table}. +nella \textit{file table}; per questo si dice che il nuovo file descriptor è +\textsl{duplicato}, da cui il nome della funzione. \begin{figure}[htb] \centering \includegraphics[width=13cm]{img/filedup} @@ -889,25 +910,37 @@ nella \textit{file table}. \label{fig:file_dup} \end{figure} -In questo modo entrambi i file condivideranno eventuali lock, \textit{file - status flag}, e posizione corrente: se ad esempio \func{lseek} modifica la -posizione su uno dei due file descriptor essa sarà modificata anche sull'altro -(al solito viene modificato lo stesso campo nella voce della \textit{file - table} a cui entrambi fanno riferimento). - -L'unica differenza fra i due file descriptor è che ciascuno avrà il suo -\textit{file descriptor flag}: nel caso di \func{dup} il flag di \textit{close - on exec} viene sempre cancellato nella copia. - -Una diversa versione della funzione, \func{dup2} viene utilizzata per -specificare esplicitamente il nuovo file descriptor; il suo prototipo è: +Si noti che per quanto illustrato in\figref{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}\index{close-on-exec} (vedi +\secref{sec:proc_exec} e \secref{sec:file_fcntl}) viene sempre cancellato +nella copia. + +L'uso principale di questa funzione è per la redirezione dell'input e +dell'output fra l'esecuzione di una \func{fork} e la successiva \func{exec}; +diventa così possibile associare un file (o una pipe) allo standard input o +allo standard output (torneremo sull'argomento in \secref{sec:ipc_pipe_use}, +quando tratteremo le pipe). Per fare questo in genere occorre prima chiudere +il file che si vuole sostituire, cossicché 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, \func{dup2}, che permette di specificare esplicitamente 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)} Rende \param{newfd} una copia del file descriptor \param{oldfd}. \bodydesc{La funzione ritorna il nuovo file descriptor in caso di successo e - -1 in caso di errore, nel qual caso \var{errno} viene settata ad uno dei - valori: + -1 in caso di errore, nel qual caso \var{errno} assumerà uno dei valori: \begin{errlist} \item[\macro{EBADF}] \param{oldfd} non è un file aperto o \param{newfd} ha un valore fuori dall'intervallo consentito per i file descriptor. @@ -915,11 +948,13 @@ specificare esplicitamente il nuovo file descriptor; il suo prototipo descriptor aperti. \end{errlist}} \end{prototype} -\noindent la funzione chiude il file descriptor \param{newfd} se è aperto. +\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. La duplicazione dei file descriptor può essere effettuata anche usando la funzione di controllo dei file \func{fnctl} (che esamineremo in -\secref{sec:file_fcntl}) con il parametro \macro{F\_DUPFD}. +\secref{sec:file_fcntl}) con il parametro \macro{F\_DUPFD}. L'operazione ha la sintassi \code{fnctl(oldfd, F\_DUPFD, newfd)} e se si usa 0 come valore per \param{newfd} diventa equivalente a \func{dup}. La sola @@ -928,12 +963,6 @@ se superiore, per cui per poterla usare come \func{dup2} occorrerebbe prima effettuare una \func{close}, perdendo l'atomicità dell'operazione. -L'uso principale di queste funzioni è 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 su questo uso in \secref{sec:ipc_pipes} quando -tratteremo le pipe. - \subsection{La funzione \func{fcntl}} \label{sec:file_fcntl} @@ -952,11 +981,11 @@ file descriptor viene usata la funzione \func{fcntl} il cui prototipo sul file \param{fd}. \bodydesc{La funzione ha valori di ritorno diversi a seconda - dell'operazione. In caso di errore il valore di ritorno è -1 e la - variabile \var{errno} viene settata ad un opportuno codice, quelli validi - in generale sono: + dell'operazione. In caso di errore il valore di ritorno è sempre -1 ed il + codice dell'errore è restituito nella variabile \var{errno}; i codici + possibili dipendono dal tipo di operazione, l'unico valido in generale è: \begin{errlist} - \item[\macro{EBADF}] \param{oldfd} non è un file aperto. + \item[\macro{EBADF}] \param{fd} non è un file aperto. \end{errlist}} \end{functions} @@ -971,60 +1000,70 @@ valori \macro{EINVAL} se \param{arg} è negativo o maggiore del massimo consentito o \macro{EMFILE} se il processo ha già raggiunto il massimo numero di descrittori consentito. -\item[\macro{F\_SETFD}] setta 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}, identificato dalla costante - \macro{FD\_CLOEXEC}. +\item[\macro{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{close-on-exec}, identificato dalla costante + \macro{FD\_CLOEXEC}, che serve a richiedere che il file venga chiuso nella + esecuzione di una \func{exec} (vedi \secref{sec:proc_exec}). \item[\macro{F\_GETFD}] ritorna il valore del \textit{file descriptor flag} di - \var{fd}, se \macro{FD\_CLOEXEC} è settato i file descriptor aperti vengono - chiusi attraverso una \func{exec} altrimenti (il default) restano aperti. + \var{fd}, se \macro{FD\_CLOEXEC} è impostato i file descriptor aperti + vengono chiusi attraverso una \func{exec} altrimenti (il comportamento + predefinito) restano aperti. \item[\macro{F\_GETFL}] ritorna il valore del \textit{file status flag}, - permette cioè di rileggere quei bit settati da \func{open} all'apertura del + permette cioè di rileggere quei bit impostati da \func{open} all'apertura del file che vengono memorizzati (quelli riportati nella prima e terza sezione di \tabref{tab:file_open_flags}). -\item[\macro{F\_SETFL}] setta il \textit{file status flag} al valore - specificato da \param{arg}, possono essere settati solo i bit riportati - nella terza sezione di \tabref{tab:file_open_flags} (da verificare). -\item[\macro{F\_GETLK}] se un file lock è attivo restituisce nella struttura - \param{lock} la struttura \type{flock} che impedisce l'acquisizione del - blocco, altrimenti setta il campo \var{l\_type} a \macro{F\_UNLCK} (per i - dettagli sul \textit{file locking} vedi \secref{sec:file_locking}). -\item[\macro{F\_SETLK}] richiede il file lock specificato da \param{lock} se - \var{l\_type} è \macro{F\_RDLCK} o \macro{F\_WRLLCK} o lo rilascia se - \var{l\_type} è \macro{F\_UNLCK}. Se il lock è tenuto da qualcun'altro - ritorna immediatamente restituendo -1 e setta \var{errno} a \macro{EACCES} o - \macro{EAGAIN} (per i dettagli sul \textit{file locking} vedi - \secref{sec:file_locking}). +\item[\macro{F\_SETFL}] imposta il \textit{file status flag} al valore + specificato da \param{arg}, possono essere impostati solo i bit riportati + nella terza sezione di \tabref{tab:file_open_flags}.\footnote{la pagina di + manuale riporta come impostabili solo \macro{O\_APPEND}, + \macro{O\_NONBLOCK} e \macro{O\_ASYNC}.} +\item[\macro{F\_GETLK}] richiede un controllo sul file lock specificato da + \param{lock}, sovrascrivendo la struttura da esso puntata con il risultato + (questa funzionalità è trattata in dettaglio in + \secref{sec:file_posix_lock}). +\item[\macro{F\_SETLK}] richiede o rilascia un file lock a seconda di quanto + specificato nella struttura puntata da \param{lock}. Se il lock è tenuto da + qualcun'altro ritorna immediatamente restituendo -1 e imposta \var{errno} a + \macro{EACCES} o \macro{EAGAIN} (questa funzionalità è trattata in dettaglio + in \secref{sec:file_posix_lock}). \item[\macro{F\_SETLKW}] identica a \macro{F\_SETLK} eccetto per il fatto che la funzione non ritorna subito ma attende che il blocco sia rilasciato. Se - l'attesa viene interrotta da un segnale la funzione restituisce -1 e setta - \var{errno} a \macro{EINTR} (per i dettagli sul \textit{file locking} vedi - \secref{sec:file_locking}). + l'attesa viene interrotta da un segnale la funzione restituisce -1 e imposta + \var{errno} a \macro{EINTR} (questa funzionalità è trattata in dettaglio in + \secref{sec:file_posix_lock}). \item[\macro{F\_GETOWN}] restituisce il \acr{pid} del processo o il process group che è preposto alla ricezione dei segnali \macro{SIGIO} e \macro{SIGURG} per gli eventi associati al file descriptor \var{fd}. Il process group è restituito come valore negativo. -\item[\macro{F\_SETOWN}] setta il processo o process group che riceverà i +\item[\macro{F\_SETOWN}] imposta il processo o process group che riceverà i segnali \macro{SIGIO} e \macro{SIGURG} per gli eventi associati al file - descriptor \var{fd}. I process group sono settati usando valori negativi. -\item[\macro{F\_GETSIG}] restituisce il segnale mandato quando ci sono dati - disponibili in input su un file descriptor aperto o settato in I/O - asincrono. Il valore 0 indica il default (che è \macro{SIGIO}), un valore - diverso da zero indica il segnale richiesto, (che può essere lo stesso - \macro{SIGIO}).\footnote{in questo caso al manipolatore del segnale, se - installato come \var{sa\_sigaction} con \macro{SA\_SIGINFO}, vengono rese - disponibili informazioni ulteriori informazioni (vedi - \secref{sec:sig_sigaction} e \secref{sec:file_asyncronous_io})}. -\item[\macro{F\_SETSIG}] setta il segnale da inviare quando diventa possibile - effettuare I/O sul file descriptor. Il valore zero indica il default - (\macro{SIGIO}), ogni altro valore permette di rendere disponibile al - manipolatore del segnale ulteriori informazioni se si è usata - \macro{SA\_SIGINFO}. + descriptor \var{fd}. I process group sono impostati usando valori negativi. +\item[\macro{F\_GETSIG}] restituisce il valore del segnale mandato quando ci + sono dati disponibili in input su un file descriptor aperto o impostato in + I/O asincrono. Il valore 0 indica il valore predefinito (che è + \macro{SIGIO}), un valore diverso da zero indica il segnale richiesto, (che + può essere lo stesso \macro{SIGIO}). +\item[\macro{F\_SETSIG}] imposta il segnale da inviare quando diventa + possibile effettuare I/O sul file descriptor in caso di I/O asincrono. Il + valore zero indica di usare il segnale predefinito, \macro{SIGIO}. Un altro + valore (compreso lo stesso \macro{SIGIO}) specifica il segnale voluto; l'uso + di un valore diverso da zero permette inoltre, se si è installato il + manipolatore del segnale come \var{sa\_sigaction} usando + \macro{SA\_SIGINFO}, (vedi \secref{sec:sig_sigaction}), di rendere + disponibili al manipolatore informazioni ulteriori informazioni riguardo il + file che ha generato il segnale attraverso i valori restituiti in + \type{siginfo\_t} (come vedremo in + \secref{sec:file_asyncronous_io}).\footnote{i due comandi \macro{F\_SETSIG} + e \macro{F\_GETSIG} sono una estensione specifica di Linux.} \end{basedescript} La maggior parte delle funzionalità di \func{fcntl} sono troppo avanzate per poter essere affrontate in dettaglio a questo punto; saranno riprese più -avanti quando affronteremo le problematiche ad esse relative. +avanti quando affronteremo le problematiche ad esse relative (in particolare +riprenderemo le tematiche relative all'I/O asincrono in +\secref{sec:file_asyncronous_io} e quelle relative al \textit{file locking} in +\secref{sec:file_locking}). Per determinare le modalità di accesso inoltre è necessario estrarre i bit di accesso (ottenuti con il comando \macro{F\_GETFL}); infatti la definizione @@ -1044,7 +1083,7 @@ valido anche per l'interazione con i pi interagire con le stesse funzioni usate per i normali file di dati, esisteranno sempre caratteristiche peculiari, specifiche dell'hardware e della funzionalità che ciascuno di essi provvede, che non possono venire comprese in -questa interfaccia astratta (un caso tipico è il settaggio della velocità di +questa interfaccia astratta (un caso tipico è l'impostazione della velocità di una porta seriale, o le dimensioni di un framebuffer). Per questo motivo l'architettura del sistema ha previsto l'esistenza di una @@ -1053,14 +1092,16 @@ per ogni singolo dispositivo. 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 e il terzo parametro (usualmente di tipo - \param{char * argp}) per il trasferimento dell'informazione necessaria. + \param{char * argp} o \param{int argp}) per il trasferimento + dell'informazione necessaria. \bodydesc{La funzione nella maggior parte dei casi ritorna 0, alcune operazioni usano però il valore di ritorno per restituire informazioni. In - caso di errore viene sempre restituito -1 e \var{errno} viene settata ad - uno dei valori seguenti: + caso di errore viene sempre restituito -1 ed \var{errno} assumerà uno dei + valori: \begin{errlist} - \item[\macro{ENOTTY}] il file \param{fd} non è associato con un device. + \item[\macro{ENOTTY}] il file \param{fd} non è associato con un device, o la + richiesta non è applicabile all'oggetto a cui fa riferimento \param{fd}. \item[\macro{EINVAL}] gli argomenti \param{request} o \param{argp} non sono validi. \end{errlist} @@ -1069,9 +1110,45 @@ per ogni singolo dispositivo. Il prototipo di questa funzione La funzione serve in sostanza per fare tutte quelle operazioni che non si adattano al design dell'architettura dei file e che non è possibile effettuare -con le funzioni esaminate finora. Per questo motivo non è possibile fare altro -che darne una descrizione generica; torneremo ad esaminarla in seguito, quando -si tratterà di applicarla ad alcune problematiche specifiche. +con le funzioni esaminate finora. Esse vengono selezionate attraverso il +valore di \param{request} e gli eventuali risultati possono essere restituiti +sia attraverso il valore di ritorno che attraverso il terzo argomento +\param{argp}. Sono esempi delle operazioni gestite con una \func{ioctl}: +\begin{itemize*} +\item il cambiamento dei font di un terminale. +\item l'esecuzione di una traccia audio di un CDROM. +\item i comandi di avanti veloce e riavvolgimento di un nastro. +\item il comando di espulsione di un dispositivo rimovibile. +\item l'impostazione della velocità trasmissione di una linea seriale. +\item l'impostazione della frequenza e della durata dei suoni emessi dallo + speaker. +\end{itemize*} + +In generale ogni dispositivo ha un suo insieme di possibili diverse operazioni +effettuabili attraverso \func{ioctl}, che sono definite nell'header file +\file{sys/ioctl.h}, e devono essere usate solo sui dispositivi cui fanno +riferimento. Infatti anche se in genere i valori di \param{request} sono +opportunamente differenziati a seconda del dispositivo\footnote{il kernel usa + un apposito \textit{magic number} per distinguere ciascun dispositivo nella + definizione delle macro da usare per \param{request}, in modo da essere + sicuri che essi siano sempre diversi, ed il loro uso causi al più un errore. + Si veda il capitolo quinto di \cite{LinDevDri} per una trattazione + dettagliata dell'argomento.} in alcuni casi, relativi a valori assegnati +prima che questa differenziazione diventasse pratica corrente si potrebbe +avere + +Per questo motivo non è possibile fare altro che darne una descrizione +generica; torneremo ad esaminare in seguito 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 che sono definiti per ogni file: +\begin{basedescript}{\desclabelwidth{2.0cm}} +\item[\macro{FIOCLEX}] Imposta il bit di \textit{close on exec}. +\item[\macro{FIONCLEX}] Cancella il bit di \textit{close on exec}. +\item[\macro{FIOASYNC}] Abilita l'I/O asincrono. +\item[\macro{FIONBIO}] Abilita l'I/O in modalità non bloccante. +\end{basedescript} +relativi ad operazioni comunque eseguibili anche attraverso \func{fcntl}. %%% Local Variables: