X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=fileunix.tex;h=b9d72195ec213c26ea4f5ca78bc3e4151e1b4f0d;hp=3e1915af22d851a6259e146e7e57b37327fe0f81;hb=d58b732f24797c3c17ab1cc8d8aa85ec04df62ed;hpb=90d696f5005a8ce307042cb6aabfff8335747380 diff --git a/fileunix.tex b/fileunix.tex index 3e1915a..b9d7219 100644 --- a/fileunix.tex +++ b/fileunix.tex @@ -1,12 +1,12 @@ -\chapter{L'interfaccia unix di I/O con i file} +\chapter{I file: l'interfaccia standard unix} \label{cha:file_unix_interface} 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, che non prevede funzioni evolute come la -bufferizzazione o funzioni di lettura o scrittura formattata, ma è su questa -che è costruita anche l'interfaccia standard dei file definita dallo standard -ANSI C. +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 in \capref{cha:files_std_interface}. @@ -205,12 +205,7 @@ prototipo La funzione apre il file, usando il primo file descriptor libero, e crea l'opportuna voce (cioè la struttura \var{file}) nella file table. Viene usato -sempre il file descriptor con il valore più basso. Questa caratteristica -permette di prevedere qual'è il valore che si otterrà, e viene talvolta usata -da alcune applicazioni per sostituire i file corrispondenti ai file standard -di \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). +sempre il file descriptor con il valore più basso. \begin{table}[!htb] \centering @@ -308,6 +303,13 @@ cio una ambiguità, dato che come vedremo in \secref{sec:file_read} il ritorno di zero da parte di \func{read} ha il significato di una end-of-file.} +Questa caratteristica permette di prevedere qual'è il valore del file +descriptor che si otterrà al ritorno di \func{open}, e viene talvolta usata da +alcune applicazioni per sostituire i file corrispondenti ai file standard di +\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 sulla condivisione dei file, in genere accessibile dopo una \func{fork}, in @@ -481,8 +483,9 @@ causano un errore ma restituiscono un valore indefinito. \subsection{La funzione \func{read}} \label{sec:file_read} -Per leggere da un file precedentemente aperto, si può la funzione \func{read}, -il cui prototipo è: + +Una volta che un file è stato aperto 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)} La funzione cerca di leggere \var{count} byte dal file \var{fd} al buffer @@ -567,17 +570,18 @@ per \func{read} e \func{lseek}. \end{prototype} 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 dato che la posizione sul file può essere -condivisa fra vari processi (vedi \secref{sec:file_sharing}), essa permette di -eseguire l'operazione atomicamente. Il valore di \var{offset} fa riferimento -all'inizio del file. +modificarne la posizione corrente. È sostanzialmente equivalente alla +esecuzione di una \func{read} e una \func{lseek}, ma dato che la posizione sul +file può essere condivisa fra vari processi (vedi \secref{sec:file_sharing}), +essa permette di eseguire l'operazione atomicamente. Il valore di \var{offset} +fa sempre riferimento all'inizio del file. \subsection{La funzione \func{write}} \label{sec:file_write} -Per scrivere su un file si usa la funzione \func{write}, il cui prototipo è: +Una volta che un file è stato aperto 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)} La funzione scrive \var{count} byte dal buffer \var{buf} sul file \var{fd}. @@ -860,7 +864,7 @@ file descriptor viene usata la funzione \func{fcntl} il cui prototipo \headdecl{fcntl.h} \funcdecl{int fcntl(int fd, int cmd)} \funcdecl{int fcntl(int fd, int cmd, long arg)} - \funcdecl{int fcntl(int fd, int cmd, struct flock *lock)} + \funcdecl{int fcntl(int fd, int cmd, struct flock * lock)} La funzione esegue una delle possibili operazioni specificate da \param{cmd} sul file \param{fd}. @@ -874,7 +878,8 @@ file descriptor viene usata la funzione \func{fcntl} il cui prototipo Il comportamento di questa funzione è determinato dal valore del comando \param{cmd} che le viene fornito; in \secref{sec:file_dup} abbiamo incontrato -un esempio, una lista dei possibili valori è riportata di seguito: +un esempio per la duplicazione dei file descriptor, una lista dei possibili +valori è riportata di seguito: \begin{basedescript}{\desclabelwidth{2.0cm}} \item[\macro{F\_DUPFD}] trova il primo file descriptor disponibile di valore maggiore o uguale ad \param{arg} e ne fa una copia di \var{fd}. In caso di @@ -892,13 +897,88 @@ un esempio, una lista dei possibili valori \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 file che vengono memorizzati (quelli riportati nella prima e terza sezione - di \tabref{tab:file_open_flags}). + 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\_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}). +\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 + 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 sul file descriptor. 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}), nel qual caso al manipolatore del + segnale, se installato con \macro{SA\_SIGINFO}, vengono rese disponibili + informazioni ulteriori informazioni. +\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}. \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. + +Per determinare le modalità di accesso inoltre può essere necessario usare la \subsection{La funzione \func{ioctl}} \label{sec:file_ioctl} +Benché il concetto di \textit{everything is a file} si sia dimostratato molto +valido anche per l'interazione con i più vari dispositivi, con cui si può +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 +una porta seriale, o le dimensioni di un framebuffer). + +Per questo motivo l'architettura del sistema ha previsto l'esistenza di una +funzione speciale, \func{ioctl}, con cui poter compiere operazioni specifiche +per ogni singolo dispositivo. Il prototipo di questa funzione è: + +\begin{prototype}{sys/ioctl.h}{int ioctl(int fd, int request, ...)} + + La funzione manipola il sottostante dispositivo, usando il parametro + \param{request} per specificare l'operazione richiesta e il terzo parametro + (che usualmente è di tipo \param{char * argp}) per passare o ricevere + l'informazione necessaria al dispositivo. + + 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: + \begin{errlist} + \item \macro{ENOTTY} il file \param{fd} non è associato con un device. + \item \macro{EINVAL} gli argomenti \param{request} o \param{argp} non sono + validi. + \end{errlist} + ed inoltre \macro{EBADF} e \macro{EFAULT}. +\end{prototype} + +La funzione serve in sostanza per fare tutte quelle operazioni che non si +adattano all'architettura di I/O di unix e che non è possibile effettuare con +le funzioni esaminate finora. Per questo motivo non è possibile fare altro che +una descrizione generica; torneremo ad esaminarla in seguito, quando si +tratterà di applicarla ad alcune problematiche specifiche. +