raise, iniziate alarm e setitimer).
\func{connect}, attraverso un procedimento che viene chiamato
\textsl{apertura attiva}, dall'inglese \textit{active open}. La chiamata di
\func{connect} blocca il processo e causa l'invio da parte del client di un
- segmento SYN\footnote{Si ricordi che il segmento è l'unità elementare di
+ segmento SYN,\footnote{Si ricordi che il segmento è l'unità elementare di
dati trasmessa dal protocollo TCP al livello superiore; tutti i segmenti
hanno un header che contiene le informazioni che servono allo
\textit{stack TCP} (così viene di solito chiamata la parte del kernel che
ci sono una serie di flag usati per gestire la connessione, come SYN, ACK,
URG, FIN, alcuni di essi, come SYN (che sta per \textit{syncronize})
corrispondono a funzioni particolari del protocollo e danno il nome al
- segmento, (per maggiori dettagli vedere \capref{cha:tcp_protocol})}, in
+ segmento, (per maggiori dettagli vedere \capref{cha:tcp_protocol}).} in
sostanza viene inviato al server un pacchetto IP che contiene solo gli
header IP e TCP (con il numero di sequenza iniziale e il flag SYN) e le
opzioni di TCP.
\textsl{finestra annunciata} (\textit{advertized window}) con la quale
ciascun capo della comunicazione dichiara quanto spazio disponibile ha in
memoria per i dati. Questo è un numero a 16 bit dell'header, che così può
- indicare un massimo di 65535 byte (anche se Linux usa come massimo 32767
- per evitare problemi con alcuni stack bacati che usano l'aritmetica con
- segno per implementare lo stack TCP); ma alcuni tipi di connessione come
- quelle ad alta velocità (sopra i 45Mbits/sec) e quelle che hanno grandi
- ritardi nel cammino dei pacchetti (come i satelliti) richiedono una finestra
- più grande per poter ottenere il massimo dalla trasmissione, per questo
- esiste questa opzione che indica un fattore di scala da applicare al valore
- della finestra annunciata\footnote{essendo una nuova opzione per garantire
- la compatibilità con delle vecchie implementazioni del protocollo la
- procedura che la attiva prevede come negoziazione che l'altro capo della
- connessione riconosca esplicitamente l'opzione inserendola anche lui nel
- suo SYN di risposta dell'apertura della connessione} per la connessione
- corrente (espresso come numero di bit cui shiftare a sinistra il valore
- della finestra annunciata inserito nel pacchetto).
+ indicare un massimo di 65535 byte (anche se Linux usa come massimo 32767 per
+ evitare problemi con alcuni stack bacati che usano l'aritmetica con segno
+ per implementare lo stack TCP); ma alcuni tipi di connessione come quelle ad
+ alta velocità (sopra i 45Mbits/sec) e quelle che hanno grandi ritardi nel
+ cammino dei pacchetti (come i satelliti) richiedono una finestra più grande
+ per poter ottenere il massimo dalla trasmissione, per questo esiste questa
+ opzione che indica un fattore di scala da applicare al valore della finestra
+ annunciata\footnote{essendo una nuova opzione per garantire la compatibilità
+ con delle vecchie implementazioni del protocollo la procedura che la
+ attiva prevede come negoziazione che l'altro capo della connessione
+ riconosca esplicitamente l'opzione inserendola anche lui nel suo SYN di
+ risposta dell'apertura della connessione.} per la connessione corrente
+ (espresso come numero di bit cui shiftare a sinistra il valore della
+ finestra annunciata inserito nel pacchetto).
\item \textit{timestamp option}, è anche questa una nuova opzione necessaria
per le connessioni ad alta velocità per evitare possibili corruzioni di dati
In questo caso viene fatta assegnare dal kernel una porta effimera che poi
viene registrata presso il \textit{portmapper}; quest'ultimo è un altro
demone che deve essere contattato dai client per ottenere la porta effimera
- su cui si trova il server} che in genere viene identificato dalla porta su
+ su cui si trova il server.} che in genere viene identificato dalla porta su
cui risponde.
Con \func{bind} si può assegnare un IP specifico ad un socket, purché questo
valore, e provvede una tabella con i risultati ottenuti con vari kernel,
compreso Linux 2.0, che mostrano le differenze fra diverse implementazioni.
-In Linux il significato di questo valore è cambiato a partire dal kernel
-2.2 per prevenire l'attacco chiamato \textit{syn flood}. Questo si basa
+In Linux il significato di questo valore è cambiato a partire dal kernel 2.2
+per prevenire l'attacco chiamato \textit{syn flood}. Questo si basa
sull'emissione da parte dell'attaccante di un grande numero di pacchetti SYN
indirizzati verso una porta forgiati con indirizzo IP fasullo\footnote{con la
- tecnica che viene detta \textit{ip spoofing}} così che i SYN$+$ACK vanno
+ tecnica che viene detta \textit{ip spoofing}.} così che i SYN$+$ACK vanno
perduti e la coda delle connessioni incomplete viene saturata, impedendo di
fatto ulteriori connessioni.
creato dal kernel (detto \textit{connected socket}) a cui viene associata la
prima connessione completa (estratta dalla relativa coda, vedi
\secref{sec:TCPel_func_listen}) che il client TCP ha effettuato verso il
-socket \var{sockfd}. Quest'ultimo (detto \textit{listening socket}) è
-quello creato all'inizio e messo in ascolto con \func{listen}, e non viene
-toccato dalla funzione.
-Se non ci sono connessioni pendenti da accettare la funzione mette in attesa
-il processo\footnote{a meno che non si sia settato il socket per essere
- non-bloccante, nel qual caso ritorna con l'errore \macro{EAGAIN},
- torneremo su questa modalità di operazione in \secref{sec:xxx_sock_noblock}}
-fintanto che non ne arriva una.
+socket \var{sockfd}. Quest'ultimo (detto \textit{listening socket}) è quello
+creato all'inizio e messo in ascolto con \func{listen}, e non viene toccato
+dalla funzione. Se non ci sono connessioni pendenti da accettare la funzione
+mette in attesa il processo\footnote{a meno che non si sia settato il socket
+ per essere non-bloccante, nel qual caso ritorna con l'errore \macro{EAGAIN}.
+ Torneremo su questa modalità di operazione in
+ \secref{sec:xxx_sock_noblock}.} fintanto che non ne arriva una.
Il meccanismo di funzionamento di \func{accept} è essenziale per capire il
funzionamento di un server: in generale infatti c'è sempre un solo socket in
Si ricordi infine che il file non viene eliminato dal disco fintanto che tutti
i riferimenti ad esso sono stati cancellati, solo quando il \textit{link
count} mantenuto nell'inode diventa zero lo spazio occupato viene rimosso. A
-questo però si aggiunge una altra condizione, e cioè che non ci siano processi
+questo però si aggiunge un'altra condizione, e cioè che non ci siano processi
che abbiano detto file aperto.
Questa proprietà viene spesso usata per essere sicuri di non lasciare file
\end{prototype}
Per cambiare nome ad un file o a una directory (che devono comunque essere
-nello stesso filesystem) si usa invece la funzione \func{rename}\footnote{la
+nello stesso filesystem) si usa invece la funzione \func{rename},\footnote{la
funzione è definita dallo standard ANSI C solo per i file, POSIX estende la
- funzione anche alle directory}, il cui prototipo è:
+ funzione anche alle directory.} il cui prototipo è:
\begin{prototype}{stdio.h}
{int rename(const char *oldpath, const char *newpath)}
In ogni caso se \var{newpath} esiste e l'operazione fallisce per un qualche
motivo (come un crash del kernel), \func{rename} garantisce di lasciare
-presente una istanza di \var{newpath}. Tuttavia nella sovrascrittura potrà
+presente un'istanza di \var{newpath}. Tuttavia nella sovrascrittura potrà
esistere una finestra in cui sia \var{oldpath} che \var{newpath} fanno
riferimento allo stesso file.
Un caso comune che si può avere con i link simbolici è la creazione dei
cosiddetti \textit{loop}. La situazione è illustrata in \curfig, che riporta
la struttura della directory \file{/boot}. Come si vede si è creato al suo
-interno un link simbolico che punta di nuovo a \file{/boot}\footnote{Questo
+interno un link simbolico che punta di nuovo a \file{/boot}.\footnote{Questo
tipo di loop è stato effettuato per poter permettere a \cmd{grub} (un
bootloader in grado di leggere direttamente da vari filesystem il file da
lanciare come sistema operativo) di vedere i file in questa directory con lo
stesso path con cui verrebbero visti dal sistema operativo, anche se essi si
trovano, come è solito, su una partizione separata (e che \cmd{grub}
- vedrebbe come radice).}.
+ vedrebbe come radice).}
Questo può causare problemi per tutti quei programmi che effettuano la
scansione di una directory senza tener conto dei link simbolici, ad esempio se
$ cat temporaneo
cat: temporaneo: No such file or directory
\end{verbatim}%$
-con un errore che può sembrare sbagliato, dato che una ispezione con \cmd{ls}
+con un errore che può sembrare sbagliato, dato che un'ispezione con \cmd{ls}
ci mostrerebbe invece l'esistenza di \file{temporaneo}.
\capref{cha:files_std_interface}); la funzione \func{opendir} apre uno di
questi stream e la funzione \func{readdir} legge il contenuto della directory,
i cui elementi sono le \textit{directory entry} (da distinguersi da quelle
-della cache di cui parlavamo in \secref{sec:file_vfs}) in una opportuna
+della cache di cui parlavamo in \secref{sec:file_vfs}) in un'opportuna
struttura \var{struct dirent}.
(NdA Il resto va scritto!!! É noioso e lo farò più avanti).
Il buffer deve essere sufficientemente lungo da poter contenere il pathname
completo più lo zero di terminazione della stringa. Qualora esso ecceda le
dimensioni specificate con \var{size} la funzione restituisce un errore. Si
-può anche specificare un puntatore nullo come \var{buffer}\footnote{questa è
- una estensione allo standard POSIX.1, supportata da Linux}, nel qual caso la
+può anche specificare un puntatore nullo come \var{buffer},\footnote{questa è
+ un'estensione allo standard POSIX.1, supportata da Linux.} nel qual caso la
stringa sarà allocata automaticamente per una dimensione pari a \var{size}
qualora questa sia diversa da zero, o della lunghezza esatta del pathname
altrimenti. In questo caso ci si deve ricordare di disallocare la stringa una
binaria che permette di estrarre i bit nei quali viene memorizzato il tipo di
file, i valori successivi sono le costanti corrispondenti ai singoli bit, e
possono essere usati per effettuare la selezione sul tipo di file voluto, con
-una opportuna combinazione.
+un'opportuna combinazione.
\begin{table}[htb]
\centering
directory sono file (che contengono una lista di nomi) che il sistema tratta
in maniera del tutto analoga a tutti gli altri.
-Per questo motivo tutte le volte che compiremo una operazione su un file che
+Per questo motivo tutte le volte che compiremo un'operazione su un file che
comporta una modifica del nome contenuto nella directory, andremo anche a
scrivere sulla directory che lo contiene cambiandone il tempo di modifica. Un
esempio di questo può essere la cancellazione di un file, invece leggere o
Control List} che possono essere aggiunte al filesystem standard con
opportune patch, e sono presenti in filesystem non ancora inclusi nel kernel
ufficiale come \textsl{xfs}, o meccanismi di controllo ancora più
- sofisticati come il \textit{mandatory access control} di SE-Linux} ma nella
+ sofisticati come il \textit{mandatory access control} di SE-Linux.} ma nella
maggior parte dei casi il meccanismo standard è più che sufficiente a
soffisfare tutte le necessità più comuni. I tre permessi di base associati ad
ogni file sono:
sostanzialmente inutile questo procedimento.
Benché ormai non venga più utilizzato per i file, lo \textsl{sticky bit} ha
-invece assunto un uso importante per le directory\footnote{lo \textsl{sticky
- bit} per le directory è una estensione non definita nello standard POSIX,
- Linux però la supporta, così come BSD e SVR4.}; in questo caso se il bit è
+invece assunto un uso importante per le directory;\footnote{lo \textsl{sticky
+ bit} per le directory è un'estensione non definita nello standard POSIX,
+ Linux però la supporta, così come BSD e SVR4.} in questo caso se il bit è
settato un file potrà essere rimosso dalla directory soltanto se l'utente ha
il permesso di scrittura su di essa ed inoltre è vera una delle seguenti
condizioni:
\acr{sgid}; essa consiste nel cancellare automaticamente questi bit qualora un
processo che non appartenga all'amministratore scriva su un file. In questo
modo anche se un utente malizioso scopre un file \acr{suid} su cui può
-scrivere, una eventuale modifica comporterà la perdita di ogni ulteriore
+scrivere, un'eventuale modifica comporterà la perdita di ogni ulteriore
privilegio.
\subsection{La funzione \func{umask}}
Questa maschera è una caratteristica di ogni processo\footnote{è infatti
contenuta nel campo \var{umask} di \var{fs\_struct}, vedi
- \figref{fig:proc_task_struct}} e viene utilizzata per impedire che alcuni
+ \figref{fig:proc_task_struct}.} e viene utilizzata per impedire che alcuni
permessi possano essere assegnati ai nuovi file in sede di creazione. I bit
indicati nella maschera vengono infatti esclusi quando un nuovo file viene
creato.
versione 2.1.81 in Linux \func{chown} non seguiva i link simbolici, da
allora questo comportamento è stato assegnato alla funzione \func{lchown},
introdotta per l'occasione, ed è stata creata una nuova system call per
- \func{chown} che seguisse i link simbolici} La funzione \func{fchown} opera
+ \func{chown} che seguisse i link simbolici.} La funzione \func{fchown} opera
su un file aperto, essa è mutuata da BSD, ma non è nello standard POSIX.
Un'altra estensione rispetto allo standard POSIX è che specificando -1 come
-valore per \var{owner} e \var{group} i valori restano immutati.
+valore per \var{owner} e \var{group} i valori restano immutati.
Quando queste funzioni sono chiamate con successo da un processo senza i
privilegi di root entrambi i bit \acr{suid} e \acr{sgid} vengono
\label{sec:file_fopen}
Le funzioni che si possono usare per aprire uno stream sono solo tre:
-\func{fopen}, \func{fdopen} e \func{freopen}\footnote{\func{fopen} e
+\func{fopen}, \func{fdopen} e \func{freopen},\footnote{\func{fopen} e
\func{freopen} fanno parte dello standard ANSI C, \func{fdopen} è parte
- dello standard POSIX.1.}, i loro prototipi sono:
+ dello standard POSIX.1.} i loro prototipi sono:
\begin{functions}
\headdecl{stdio.h}
\funcdecl{FILE *fopen(const char *path, const char *mode)}
In caso di file aperti in lettura e scrittura occorre ricordarsi che c'è
di messo una bufferizzazione; per questo motivo lo standard ANSI C
-richiede che ci sia una operazione di posizionamento fra una operazione
+richiede che ci sia un'operazione di posizionamento fra un'operazione
di output ed una di input o viceversa (eccetto il caso in cui l'input ha
incontrato la fine del file), altrimenti una lettura può ritornare anche
il risultato di scritture precedenti l'ultima effettuata.
\func{rewind} prima di eseguire una rilettura; viceversa nel caso in cui si
voglia fare una scrittura subito dopo aver eseguito una lettura occorre prima
usare una delle funzioni \func{fseek}, \func{fsetpos} o \func{rewind}. Anche
-una operazione nominalmente nulla come \code{fseek(file, 0, SEEK\_CUR)} è
+un'operazione nominalmente nulla come \code{fseek(file, 0, SEEK\_CUR)} è
sufficiente a garantire la sincronizzazione.
Una volta aperto lo stream, si può cambiare la modalità di bufferizzazione
\noindent tutte queste funzioni sono realizzate con opportune chiamate a
\func{setvbuf} e sono definite solo per compatibilità con le vecchie librerie
BSD. Infine le \acr{glibc} provvedono le funzioni non standard\footnote{anche
- queste sono originarie di Solaris} \func{\_\_flbf} e \func{\_\_fbufsize} che
-permettono di leggere le proprietà di bufferizzazione di uno stream; i cui
-prototipi sono:
+ queste funzioni sono originarie di Solaris.} \func{\_\_flbf} e
+\func{\_\_fbufsize} che permettono di leggere le proprietà di bufferizzazione
+di uno stream; i cui prototipi sono:
\begin{functions}
\headdecl{stdio\_ext.h}
\end{prototype}
\noindent anche di questa funzione esiste una analoga
\func{fflush\_unlocked}\footnote{accessibile definendo \macro{\_BSD\_SOURCE} o
- \macro{\_SVID\_SOURCE} o \macro{\_GNU\_SOURCE}} che non effettua il blocco
+ \macro{\_SVID\_SOURCE} o \macro{\_GNU\_SOURCE}.} che non effettua il blocco
dello stream.
Se \param{stream} è \macro{NULL} lo scarico dei dati è forzato per tutti gli
-\chapter{I file: l'interfaccia standard unix}
+\chapter{I file: l'interfaccia standard Unix}
\label{cha:file_unix_interface}
Esamineremo in questo capitolo la prima delle due interfacce di programmazione
campo \var{f\_pos}).
\item un puntatore all'inode\footnote{nel kernel 2.4.x si è in realtà passati
ad un puntatore ad una struttura \var{dentry} che punta a sua volta
- all'inode passando per la nuova struttura del VFS} del file.
+ all'inode passando per la nuova struttura del VFS.} del file.
%\item un puntatore alla tabella delle funzioni \footnote{la struttura
% \var{f\_op} descritta in \secref{sec:file_vfs_work}} che si possono usare
% sul file.
\section{Le funzioni base}
\label{sec:file_base_func}
-L'interfaccia standard unix per l'input/output sui file è basata su cinque
+L'interfaccia standard Unix per l'input/output sui file è basata su cinque
funzioni fondamentali: \func{open}, \func{read}, \func{write}, \func{lseek} e
\func{close}, usate rispettivamente per aprire, leggere, scrivere, spostarsi e
chiudere un file.
zero. Se il file è un terminale o una fifo il flag verrà ignorato, negli
altri casi il comportamento non è specificato. \\
\macro{O\_NOFOLLOW} & se \var{pathname} è un link simbolico la chiamata
- fallisce. Questa è una estensione BSD aggiunta in Linux dal kernel 2.1.126.
+ fallisce. Questa è un'estensione BSD aggiunta in Linux dal kernel 2.1.126.
Nelle versioni precedenti i link simbolici sono sempre seguiti, e questa
opzione è ignorata. \\
\macro{O\_DIRECTORY} & se \var{pathname} non è una directory la chiamata
\footnotetext[5]{l'opzione origina da SVr4, dove però causava il ritorno da
una \func{read} con un valore nullo e non con un errore, questo introduce
- una ambiguità, dato che come vedremo in \secref{sec:file_read} il ritorno di
+ un'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
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}}:
+ \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.
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
+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
+ 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.
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,
+ 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:
da \var{count}, a meno di un errore. Negli altri casi si ha lo stesso
comportamento di \func{read}.
-Anche per \func{write} lo standard Unix98 definisce una analoga \func{pwrite}
+Anche per \func{write} lo standard Unix98 definisce un'analoga \func{pwrite}
per scrivere alla posizione indicata senza modificare la posizione corrente
nel file, il suo prototipo è:
\begin{prototype}{unistd.h}
Si noti inoltre che anche i flag di stato del file (quelli settati
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
+ \var{file}.}, vengono in questo caso condivisi. Ai file però sono associati
anche altri flag, dei quali l'unico usato al momento è \macro{FD\_CLOEXEC},
detti \textit{file descriptor flags}. Questi ultimi sono tenuti invece in
\var{file\_struct}, e perciò sono specifici di ciascun processo e non vengono
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.
-Il problema è che usare due system call in successione non è una operazione
+Il problema è che usare due system call in successione non è un'operazione
atomica; il problema è stato risolto introducendo la modalità
\macro{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 system call (la \func{write}) che non
-essendo interrompibile da un altro processo costituisce una operazione
-atomica.
+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 file di lock, bloccandosi se il file esiste. In questo caso la
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
+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
+ può ritardare ulteriormente la scrittura effettiva.} La prima di queste
funzioni è \func{sync} il cui prototipo è:
\begin{prototype}{unistd.h}{int sync(void)}
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
+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.}.
+ delle directory.}
\subsection{La funzioni \func{dup} e \func{dup2}}
Per determinare le modalità di accesso inoltre è necessario estrarre i bit di
accesso (ottenuti con il comando \macro{F\_GETFL}); infatti la definizione
corrente non assegna bit separati a \macro{O\_RDONLY}, \macro{O\_WRONLY} e
-\macro{O\_RDWR}\footnote{posti rispettivamente ai valori 0, 1 e 2}, per cui il
+\macro{O\_RDWR},\footnote{posti rispettivamente ai valori 0, 1 e 2.} per cui il
valore si ottiene eseguendo un AND binario del valore di ritorno di
\func{fcntl} con la maschera \macro{O\_ACCMODE} anch'essa definita in
\file{fcntl.h}.
richiesto all'ingresso nel sistema dalla procedura di \textit{login}. Questa
procedura si incarica di verificare l'identità dell'utente, in genere
attraverso la richiesta di una parola d'ordine, anche se sono possibili
-meccanismi diversi\footnote{Ad esempio usando la libreria PAM
+meccanismi diversi.\footnote{Ad esempio usando la libreria PAM
(\textit{Pluggable Autentication Methods}) è possibile astrarre
completamente i meccanismi di autenticazione e sostituire ad esempio l'uso
- delle password con meccanismi di identificazione biometrica}.
+ delle password con meccanismi di identificazione biometrica.}
Eseguita la procedura di riconoscimento in genere il sistema manda in
esecuzione un programma di interfaccia (che può essere la \textit{shell} su
\acr{uid} è zero. Esso identifica l'amministratore del sistema, che deve
essere in grado di fare qualunque operazione; per l'utente \textit{root}
infatti i meccanismi di controllo descritti in precedenza sono
-disattivati\footnote{i controlli infatti vengono sempre eseguiti da un codice
- del tipo \texttt{if (uid) \{ ... \}}}.
+disattivati.\footnote{i controlli infatti vengono sempre eseguiti da un codice
+ del tipo \texttt{if (uid) \{ ... \}}}
\section{Gli standard di unix e GNU/Linux}
dimensioni eccedono la MTU viene eseguita la cosiddetta
\textit{frammentazione}, i pacchetti cioè vengono spezzati (sia da IPv4 che da
IPv6, anche se i pacchetti frammentati sono gestiti con modalità
-diverse\footnote{il primo usa un flag nell'header, il secondo una opportuna
- opzione, si veda \secref{cha:ip_protocol}}), in blocchi più piccoli che
+diverse,\footnote{il primo usa un flag nell'header, il secondo una opportuna
+ opzione, si veda \secref{cha:ip_protocol}.}) in blocchi più piccoli che
possono essere trasmessi attraverso l'interfaccia.
\begin{table}[!htb]
ciascun processo vedrà la sua copia del codice (in realtà il kernel fa sì che
tutte le parti uguali siano condivise), avrà un suo spazio di indirizzi,
variabili proprie e sarà eseguito in maniera completamente indipendente da
-tutti gli altri\footnote{questo non è del tutto vero nel caso di un programma
+tutti gli altri.\footnote{questo non è del tutto vero nel caso di un programma
\textit{multi-thread}, ma sulla gestione dei \textit{thread} in Linux
- torneremo più avanti}.
+ torneremo più avanti.}
\subsection{La funzione \func{main}}
dell'hardware), ma quello più tipico, usato dai sistemi unix-like come Linux è
la cosiddetta \textsl{memoria virtuale} che consiste nell'assegnare ad ogni
processo uno spazio virtuale di indirizzamento lineare, in cui gli indirizzi
-vanno da zero ad un qualche valore massimo\footnote{nel caso di Linux fino al
+vanno da zero ad un qualche valore massimo.\footnote{nel caso di Linux fino al
kernel 2.2 detto massimo era, per macchine a 32bit, di 2Gb, con il kernel
- 2.4 ed il supporto per la \textit{high-memory} il limite è stato esteso}.
+ 2.4 ed il supporto per la \textit{high-memory} il limite è stato esteso.}
Come accennato in \capref{cha:intro_unix} questo spazio di indirizzi è
virtuale e non corrisponde all'effettiva posizione dei dati nella RAM del
dimensione di un'area di memoria precedentemente allocata, la funzione vuole
in ingresso il puntatore restituito dalla precedente chiamata ad una
\func{malloc} (se è passato un valore \macro{NULL} allora la funzione si
-comporta come \func{malloc}\footnote{questo è vero per Linux e
+comporta come \func{malloc},\footnote{questo è vero per Linux e
l'implementazione secondo lo standard ANSI C, ma non è vero per alcune
vecchie implementazioni, inoltre alcune versioni delle librerie del C
consentivano di usare \func{realloc} anche per un puntatore liberato con
\func{free} purché non ci fossero state nel frattempo altre chiamate a
funzioni di allocazione, questa funzionalità è totalmente deprecata e non è
- consentita sotto Linux.}), ad esempio quando si deve far crescere la
+ consentita sotto Linux.}) ad esempio quando si deve far crescere la
dimensione di un vettore. In questo caso se è disponibile dello spazio
adiacente al precedente la funzione lo utilizza, altrimenti rialloca altrove
un blocco della dimensione voluta, copiandoci automaticamente il contenuto; lo
direttamente ad un altra variabile dello stesso tipo. Per risolvere questo
problema lo standard ISO C99\footnote{alcuni sistemi che non hanno questa
macro provvedono al suo posto \macro{\_\_va\_copy} che era il nome proposto
- in una bozza dello standard} ha previsto una macro ulteriore che permette di
-eseguire la copia di un puntatore alla lista degli argomenti:
+ in una bozza dello standard.} ha previsto una macro ulteriore che permette
+di eseguire la copia di un puntatore alla lista degli argomenti:
\begin{prototype}{stdarg.h}{void va\_copy(va\_list dest, va\_list src)}
Copia l'attuale valore \param{src} del puntatore alla lista degli argomenti
su \param{dest}.
primo\footnote{a partire dal kernel 2.5.2-pre10 è stato introdotto il nuovo
scheduler di Ingo Molnar che esegue sempre per primo il figlio; per
mantenere la portabilità è opportuno non fare comunque affidamento su questo
- comportamento} dopo la chiamata a \func{fork}; dall'esempio si può notare
+ comportamento.} dopo la chiamata a \func{fork}; dall'esempio si può notare
infatti come nei primi due cicli sia stato eseguito per primo il padre (con la
stampa del \acr{pid} del nuovo processo) per poi passare all'esecuzione del
figlio (completata con i due avvisi di esecuzione ed uscita), e tornare
\item ad ogni processo figlio viene assegnato un nuovo padre (in genere
\cmd{init}).
\item viene inviato il segnale \macro{SIGCHLD} al processo padre (vedi
- \secref{sec:sig_xxx}).
+ \secref{sec:sig_sigchld}).
\item se il processo è un leader di sessione viene mandato un segnale di
\macro{SIGHUP} a tutti i processi in background e il terminale di
controllo viene disconnesso (vedi \secref{sec:sess_xxx}).
creare molti figli. In questo caso si deve sempre avere cura di far leggere
l'eventuale stato di uscita di tutti i figli (in genere questo si fa
attraverso un apposito \textit{signal handler}, che chiama la funzione
-\func{wait}, vedi \secref{sec:sig_xxx} e \secref{sec:proc_wait}). Questa
+\func{wait}, vedi \secref{sec:sig_sigchld} e \secref{sec:proc_wait}). Questa
operazione è necessaria perché anche se gli \textit{zombie} non consumano
risorse di memoria o processore, occupano comunque una voce nella tabella dei
processi, che a lungo andare potrebbe esaurirsi.
\macro{WIFSIGNALED} ha restituito un valore non nullo.\\
\macro{WCOREDUMP(s)} & Vera se il processo terminato ha generato un
file si \textit{core dump}. Può essere valutata solo se
- \macro{WIFSIGNALED} ha restituito un valore non nullo\footnote{questa
+ \macro{WIFSIGNALED} ha restituito un valore non nullo.\footnote{questa
macro non è definita dallo standard POSIX.1, ma è presente come estensione
- sia in Linux che in altri unix}.\\
+ sia in Linux che in altri Unix.}\\
\macro{WIFSTOPPED(s)} & Vera se il processo che ha causato il ritorno di
\func{waitpid} è bloccato. L'uso è possibile solo avendo specificato
l'opzione \macro{WUNTRACED}. \\
\item il \textit{session id} ed il \textit{process group id} (vedi
\secref{sec:sess_xxx}).
\item il terminale di controllo (vedi \secref{sec:sess_xxx}).
-\item il tempo restante ad un allarme (vedi \secref{sec:sig_xxx}).
+\item il tempo restante ad un allarme (vedi \secref{sec:sig_alarm_abort}).
\item la directory radice e la directory di lavoro corrente (vedi
\secref{sec:file_work_dir}).
\item la maschera di creazione dei file (\var{umask}, vedi
Come accennato in \secref{sec:intro_multiuser} il modello base\footnote{in
realtà già esistono estensioni di questo modello base, che lo rendono più
flessibile e controllabile, come le \textit{capabilities}, le ACL per i file
- o il \textit{Mandatory Access Control} di SELinux} di sicurezza di un
+ o il \textit{Mandatory Access Control} di SELinux.} di sicurezza di un
sistema unix-like è fondato sui concetti di utente e gruppo, e sulla
separazione fra l'amministratore (\textsl{root}, detto spesso anche
\textit{superuser}) che non è sottoposto a restrizioni, ed il resto degli
l'esecuzione, vince sempre quello con la priorità assoluta più alta, anche
quando l'altro è in esecuzione (grazie al \textit{prehemptive scheduling}).
Ovviamente questo avviene solo per i processi che sono pronti per essere
-eseguiti (cioè nello stato \textit{runnable}\footnote{lo stato di un processo
+eseguiti (cioè nello stato \textit{runnable},\footnote{lo stato di un processo
è riportato nel campo \texttt{STAT} dell'output del comando \cmd{ps},
abbiamo già visto che lo stato di \textit{zombie} è indicato con \texttt{Z},
gli stati \textit{runnable}, \textit{sleep} e di I/O (\textit{uninteruttible
- sleep}) sono invece indicati con \texttt{R}, \texttt{S} e \texttt{D}.}),
+ sleep}) sono invece indicati con \texttt{R}, \texttt{S} e \texttt{D}.})
la priorità assoluta viene invece ignorata per quelli che sono bloccati su una
richiesta di I/O o in stato di \textit{sleep}. La priorità assoluta viene in
genere indicata con un numero intero, ed un valore più alto comporta una
\item una richiesta dell'utente di terminare o fermare il programma. In genere
si realizza attraverso un segnale mandato dalla shell in corrispondenza
della pressione di tasti del terminale come \code{C-c} o
- \code{C-z}\footnote{indichiamo con \code{C-x} la pressione simultanea al
- tasto \code{x} del tasto control (ctrl in molte tastiere)}.
+ \code{C-z}.\footnote{indichiamo con \code{C-x} la pressione simultanea al
+ tasto \code{x} del tasto control (ctrl in molte tastiere).}
\item l'esecuzione di una \func{kill} o di una \func{raise} da parte del
processo stesso o di un'altro (solo nel caso della \func{kill}).
\end{itemize*}
ogni implementazione successiva ne ha modificato e ridefinito il
comportamento, pur mantenendone immutato il prototipo\footnote{in realtà
alcune vecchie implementazioni (SVR4 e 4.3+BSD) usano parametri aggiuntivi
- per definire il comportamento della funzione} che è:
+ per definire il comportamento della funzione.} che è:
\begin{prototype}{signal.h}
{sighandler\_t signal(int signum, sighandler\_t handler)}
typedef void (* sighandler_t)(int)
\end{verbatim}
e cioè un puntatore ad una funzione \type{void} (cioè senza valore di ritorno)
-e che prende un argomento di tipo \type{int}\footnote{si devono usare le
+e che prende un argomento di tipo \type{int}.\footnote{si devono usare le
parentesi intorno al nome della funzione per via delle precedenze degli
operatori del C, senza di esse si sarebbe definita una funzione che ritorna
- un puntatore a \type{void} e non un puntatore ad una funzione \type{void}}.
+ un puntatore a \type{void} e non un puntatore ad una funzione \type{void}.}
La funzione \func{signal} quindi restituisce e prende come secondo argomento
un puntatore a una funzione di questo tipo, che è appunto il manipolatore del
segnale.
manipolatore \param{handler} invece, oltre all'indirizzo della funzione da
chiamare all'occorrenza del segnale, può assumere anche i due valori costanti
\macro{SIG\_IGN} con cui si dice ignorare il segnale e \macro{SIG\_DFL} per
-installare l'azione di di default\footnote{si ricordi però che i due segnali
+installare l'azione di di default.\footnote{si ricordi però che i due segnali
\macro{SIGKILL} e \macro{SIGSTOP} non possono essere ignorati né
- intercettati}.
-
-La funzione \func{signal} originale (e quella attuale in System V) era
-conforme alla semantica inaffidabile e resettava l'azione di default a
-\macro{SIG\_DEF}; Linux fino alle \acr{libc4} e le \acr{libc5} seguiva la
-stessa semantica; al contrario con l'utilizzo delle \acr{glibc2}, Linux, come
-BSD, non resetta il manipolatore e blocca il segnale durante la chiamata. La
-versione originale della funzione, il cui uso è deprecato, può essere
-utilizzata chiamando \func{sysv\_signal}.
-
-È da tenere presente che seguendo lo standard POSIX, il comportamento di un
+ intercettati.}
+
+La funzione restituisce l'indirizzo dell'azione precedente, che può essere
+salvato per poterlo ripristinare (con un'altra chiamata a \func{signal}) in un
+secondo tempo. Si ricordi che se si setta come azione \macro{SIG\_IGN} (o si
+setta un \macro{SIG\_DFL} per un segnale il cui default è di essere ignorato),
+tutti i segnali pendenti saranno scartati, e non verranno mai notificati.
+
+L'uso di \func{signal} è soggetto a problemi di compatibilità, dato che essa
+si comporta in maniera diversa per sistemi derivati da BSD o da System V. In
+questi ultimi infatti la funzione è conforme al comportamento originale dei
+primi Unix in cui il manipolatore viene disinstallato alla sua chiamata
+secondo la semantica inaffidabile; Linux seguiva questa convenzione fino alle
+\acr{libc5}. Al contrario BSD segue la semantica affidabile, non resettando il
+manipolatore e bloccando il segnale durante l'esecuzione dello stesso. Con
+l'utilizzo delle \acr{glibc2} anche Linux è passato a questo comportamento;
+quello della versione originale della funzione, il cui uso è deprecato per i
+motivi visti in \secref{sec:sig_semantics}, può essere ottenuto chiamando
+\func{sysv\_signal}. In generale, per evitare questi problemi, tutti i nuovi
+programmi dovrebbero usare \func{sigaction}.
+
+È da tenere presente che, seguendo lo standard POSIX, il comportamento di un
processo che ignora i segnali \macro{SIGFPE}, \macro{SIGILL}, o
\macro{SIGSEGV} (qualora non originino da una \func{kill} o una \func{raise})
è indefinito. Un manipolatore che ritorna da questi segnali può dare luogo ad
\label{sec:sig_kill_raise}
Come accennato in \secref{sec:sig_types}, un segnale può essere generato
-``artificialmente'' attraverso l'uso delle funzioni \func{kill} e
-\func{raise}, i cui prototipi sono:
+direttamente da un processo. L'invio di un sengale generico può essere
+effettuato attraverso delle funzioni \func{kill} e \func{raise}. La prima
+serve per inviare un segnale al processo corrente, ed il suo prototipo è:
+\begin{prototype}{signal.h}{int raise(int sig)}
+ Invia il segnale \param{sig} al processo corrente.
+
+ \bodydesc{La funzione restituisce zero in caso di successo e -1 per un
+ errore, il solo errore restituito è \macro{EINVAL} qualora si sia
+ specificato un numero di segnale invalido.}
+\end{prototype}
+
+Il valore di \param{sig} specifica il segnale che si vuole inviare e può
+essere specificato con una delle macro definite in
+\secref{sec:sig_classification}. In genere questa funzione viene usata per
+riprodurre il comportamento di default di un segnale che sia stato
+intercettato. In questo caso, una volta eseguite le operazioni volute, il
+manipolatore potrà reinstallare l'azione di default, e attivarla con
+\func{raise}.
+
+Se invece si vuole inviare un segnale ad un altro processo occorre utilizzare
+la funzione \func{kill}; il suo prototipo è:
\begin{functions}
\headdecl{sys/types.h}
\headdecl{signal.h}
- \funcdecl{int kill(pid\_t pid, int sig)} invia il segnale \param{sig} al
+ \funcdecl{int kill(pid\_t pid, int sig)} Invia il segnale \param{sig} al
processo specificato con \param{pid}.
- \funcdecl{int raise(int sig)} invia il segnale \param{sig} al processo
- corrente.
-
+
\bodydesc{La funzione restituisce zero in caso di successo e -1 per un
errore, nel qual caso \var{errno} assumerà i valori:
\begin{errlist}
\end{functions}
La funzione \code{raise(sig)} è sostanzialmente equivalente ad una
-\code{kill(getpid(), sig)}. Il valore di \param{sig} specifica il segnale che
-si vuole inviare e può essere specificato con una delle macro definite in
-\ref{sec:sig_classification}.
+\code{kill(getpid(), sig)}. Siccome \func{raise} è definita nello standard ISO
+C non esiste in alcune vecchie versioni di Unix, per cui in generale l'uso di
+\func{kill} è più portabile.
Lo standard POSIX poi prevede che il valore 0 sia usato per specificare il
segnale nullo. Se le funzioni vengono chiamate con questo valore non viene
inviato nessun segnale, ma viene eseguito il controllo degli errori, in tal
caso si otterrà un errore \macro{EPERM} se non si hanno i permessi necessari
ed un errore \macro{ESRCH} se il processo specificato non esiste. Si tenga
-conto però che il sistema ricicla i \acr{pid}, così come visto in
-\secref{sec:proc_pid}, per cui l'esistenza di un processo non significa che
+conto però che il sistema ricicla i \acr{pid} (come accennato in
+\secref{sec:proc_pid}) per cui l'esistenza di un processo non significa che
esso sia realmente quello a cui si intendeva mandare il segnale.
-Per poter effettuare l'invio del segnale ad un altro processo, si devono
-possedere i privilegi di amministratore, oppure il \textit{real user id} o
-l'\textit{effective user id} del chiamante devono corrispondere al
-\textit{real user id} o al \textit{aved user id} della destinazione. Nel caso
-del segnale \macro{SIGCONT} entrambi i processi devono appartenere alla stessa
-sessione.
-
Il valore dell'argomento \param{pid} specifica la destinazione a cui inviare
il segnale e può assumere i seguenti significati:
\begin{basedescript}{\desclabelwidth{2cm}\desclabelstyle{\nextlinelabel}}
group $|\code{pid}|$.
\end{basedescript}
+Solo l'amministratore può inviare un segnale ad un processo qualunque, in
+tutti gli altri casi il \textit{real user id} o l'\textit{effective user id}
+del processo chiamante devono corrispondere al \textit{real user id} o al
+\textit{saved user id} della destinazione. Fa eccezione il caso in cui il
+segnale inviato sia \macro{SIGCONT}, nel quale occorre che entrambi i processi
+appartengano alla stessa sessione. Inoltre, dato il ruolo fondamentale che
+riveste nel sistema (si ricordi quanto visto in \secref{sec:sig_termination}),
+non è possibile inviare al processo 1 (cioè a \cmd{init}) segnali per i quali
+esso non abbia un manipolatore installato.
+
+Infine, seguendo le specifiche POSIX 1003.1-2001, l'uso della chiamata
+\code{kill(-1, sig)} comporta che il segnale sia inviato (con la solita
+eccezione di \cmd{init}) a tutti i processi per i quali i permessi lo
+consentano. Lo standard permette comunque alle varie implementazione di
+escludere alcuni processi specifici: nel caso in questione Linux non invia il
+segnale al processo che ha effettuato la chiamata.
+
+
+\subsection{Le funzioni \func{alarm} e \func{abort}}
+\label{sec:sig_alarm_abort}
+
+Un caso particolare di segnali generati a richiesta è quello che riguarda i
+segnali di temporizzazione e e \macro{SIGABORT}, per i quali sono previste
+funzioni specifiche che ne effettuino l'invio. La prima di queste è
+\func{alarm} il cui prototipo è:
+\begin{prototype}{unistd.h}{unsigned int alarm(unsigned int seconds)}
+ Predispone l'invio di \macro{SIGALARM} dopo \param{seconds} secondi.
+
+ \bodydesc{La funzione restituisce il numero di secondi rimanenti ad un
+ precedente allarme, o zero se non c'erano allarmi pendenti.}
+\end{prototype}
-\subsection{Le funzioni \func{alarm} e \func{pause}}
-\label{sec:sig_alarm_pause}
+La funzione provvede un meccanismo che consente ad un processo di predisporre
+un'interruzione nel futuro, (ad esempio per effettuare una qualche operazione
+dopo un certo periodo di tempo), programmando l'emissione si un segnale di
+\macro{SIGALARM} dopo il numero di secondi specificato da \param{seconds}.
+Chiaramente la precisione è determinata da quella dell'orologio di sistema, e
+sono sempre possibili ritardi in caso di un sistema eccessivamente carico.
+
+Se si specifica per \param{seconds} un valore nullo non verrà inviato nessun
+segnale; siccome alla chiamata viene cancellato ogni precedente allarme,
+questo può essere usato per cancellare una programmazione precedente. La
+funzione inoltre ritorna il numero di secondi rimanenti all'invio dell'allarme
+precedentemente programmato, in modo che sia eventualmente possibile
+effettuare delle scelte in caso di necessità di più interruzioni.
+
+In \secref{sec:sys_unix_time} abbiamo visto che ad ogni processo sono
+associati tre tempi diversi: \textit{clock time}, \textit{user time} e
+\textit{system time}. Per poterli calcolare il kernel mantiene tre diversi
+timer per ciascun processo:
+\begin{itemize}
+\item un \textit{real-time timer} che calcola il tempo reale trascorso (che
+ corrisponde al \textit{clock time}). La scadenza di questo timer provoca
+ l'emissione di \macro{SIGALARM}.
+\item un \textit{virtual timer} che calcola il tempo di processore usato dal
+ processo in user space (che corrisponde all'\textit{user time}). La scadenza
+ di questo timer provoca l'emissione di \macro{SIGVTALRM}.
+\item un \textit{profiling timer} che calcola la somma dei tempi di processore
+ utilizzati direttamente dal processo in user space, e dal kernel nelle
+ system call ad esso relative (che corrisponde a quello che in
+ \secref{sec:sys_unix_time} abbiamo chiamato \textit{CPU time}). La scadenza
+ di questo timer provoca l'emissione di \macro{SIGPROF}.
+\end{itemize}
+
+Il timer usato da \func{alarm} è il \textit{clock time}, e corrisponde cioè al
+tempo reale. Dato che \func{alarm} non consente di usare gli altri timer, e
+non può specificare intervalli con precisione maggiore al secondo le
+\acr{glibc} provvedono la funzione \func{setitimer} che permette un controllo
+completo, a scapito di un uso molto più complesso. Il suo prototipo è:
+\begin{prototype}{sys/time.h}{int setitimer(int which, const struct
+ itimerval *value, struct itimerval *ovalue)}
+
+ Predispone l'invio di un segnale di allarme alla scadenza dell'intervallo
+ \param{value} sul timer specificato da \func{which}.
+
+ \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
+ errore, nel qual caso \var{errno} può assumere i valori \macro{EINVAL} e
+ \macro{EFAULT}.}
+\end{prototype}
+Il valore di \param{which} permette di specificare quale dei tre timer usare;
+i possibili valori sono riportati in \tabref{tab:sig_setitimer_values}.
+
+\begin{table}[htb]
+ \centering
+ \begin{tabular}[c]{|l|l|}
+ \hline
+ \textbf{Valore} & \textbf{Timer} \\
+ \hline
+ \hline
+ \macro{ITIMER\_REAL} & \textit{real-time timer}\\
+ \macro{ITIMER\_VIRTUAL} & \textit{virtual timer}\\
+ \macro{ITIMER\_PROF} & \textit{profiling timer}\\
+ \hline
+ \end{tabular}
+ \caption{Valori dell'argomento \param{which} per la funzione
+ \func{setitimer}.}
+ \label{tab:sig_setitimer_values}
+\end{table}
+
+
+\subsection{Le funzioni \func{pause} e \func{sleep}}
+\label{sec:sig_pause_sleep}
+
+
+
+
+
+\subsection{Le semantiche di \macro{SIGCHLD}}
+\label{sec:sig_sigchld}
-\subsection{Funzioni rientranti e default dei segnali}
-\label{sec:sig_reentrant}
+\subsection{Funzioni rientranti e default dei segnali}
+\label{sec:sig_reentrant}
+
, affrontando inoltre le varie problematiche di programmazione che si devono
tenere presenti quando si ha a che fare con essi.
Inoltre prenderemo in esame, oltre al comportamento in condizioni normali,
anche tutti i possibili scenari particolari (errori, sconnessione della rete,
crash del client o del server durante la connessione) che possono avere luogo
-durante l'impiego di una applicazione di rete.
+durante l'impiego di un'applicazione di rete.
\section{Il servizio \texttt{echo}}
\label{sec:TCPsimp_echo}
-L'applicazione scelta come esempio sarà una implementazione elementare, ma
+L'applicazione scelta come esempio sarà un'implementazione elementare, ma
completa, del servizio \texttt{echo}. Il servizio \texttt{echo} è uno dei
servizi standard solitamente provvisti direttamente dal superserver
\cmd{inetd}, ed è definito dall'RFC~862. Come dice il nome il servizio deve
applicazione più complessa è la elaborazione dell'input del client da parte
del server nel fornire le risposte in uscita.
-Partiremo da una implementazione elementare che dovrà essere rimaneggiata di
+Partiremo da un'implementazione elementare che dovrà essere rimaneggiata di
volta in volta per poter tenere conto di tutte le evenienze che si possono
-manifestare nella vita reale di una applicazione di rete, fino ad arrivare ad
-una implementazione completa.
+manifestare nella vita reale di un'applicazione di rete, fino ad arrivare ad
+un'implementazione completa.
\subsection{La struttura del server}
\label{sec:TCPsimp_server_main}
Benché il codice dell'esempio precedente sia molto ridotto, esso ci permetterà
di considerare in dettaglio tutte le problematiche che si possono incontrare
-nello scrivere una applicazione di rete. Infatti attraverso l'esame delle sue
+nello scrivere un'applicazione di rete. Infatti attraverso l'esame delle sue
modalità di funzionamento normali, all'avvio e alla terminazione, e di quello
che avviene nelle varie situazioni limite, da una parte potremo approfondire
la comprensione del protocollo TCP/IP e dall'altra ricavare le indicazioni
Dopo una breve panoramica sulle caratteristiche di questa interfaccia vedremo
come creare un socket e come collegarlo allo specifico protocollo di rete che
-utilizzerà per la comunicazione. Per evitare una introduzione puramente teorica
+utilizzerà per la comunicazione. Per evitare un'introduzione puramente teorica
concluderemo il capitolo con un primo esempio di applicazione.
\section{Una panoramica}
\label{sec:sock_socket_def}
Il \textit{socket}\footnote{una traduzione letterale potrebbe essere
- \textsl{manicotto}, ma essendo universalmente noti come socket utilizzeremo
- sempre la parola inglese} è uno dei principali meccanismi di comunicazione
-fra programmi utilizzato in ambito unix. Il socket costituisce in sostanza un
+ \textsl{presa}, ma essendo universalmente noti come socket utilizzeremo
+ sempre la parola inglese.} è uno dei principali meccanismi di comunicazione
+fra programmi utilizzato in ambito Unix. Il socket costituisce in sostanza un
canale di comunicazione fra due processi su cui si possono leggere e scrivere
dati analogo a quello di una pipe ma a differenza di questa e degli altri
meccanismi esaminati nel capitolo \capref{cha:IPC} i socket non sono limitati
\subsection{La struttura degli indirizzi IPv6}
\label{sec:sock_sa_ipv6}
-Essendo IPv6 una estensione di IPv4 i socket di tipo \macro{PF\_INET6} sono
+Essendo IPv6 un'estensione di IPv4 i socket di tipo \macro{PF\_INET6} sono
sostanzialmente identici ai precedenti; la parte in cui si trovano
praticamente tutte le differenze è quella della struttura degli indirizzi. La
struttura degli indirizzi è definita ancora in \file{netinet/in.h}.
socket in tutte le chiamate successive. Nel caso la chiamata fallisca si
stampa un errore con la relativa routine e si esce.
-Il passo seguente (\texttt{\small 19--27}) è quello di costruire una apposita
+Il passo seguente (\texttt{\small 19--27}) è quello di costruire un'apposita
struttura \type{sockaddr\_in} in cui sarà inserito l'indirizzo del server ed
il numero della porta del servizio. Il primo passo è inizializzare tutto a
zero, per poi inserire il tipo di protocollo e la porta (usando per
contengono le costanti necessarie definite come macro di preprocessore, per la
seconda invece sono ovviamente necessarie delle funzioni. La situazione è
complicata dal fatto che ci sono molti casi in cui alcuni di questi limiti
-sono fissi in una implementazione mentre possono variare in un altra. Tutto
+sono fissi in un'implementazione mentre possono variare in un altra. Tutto
questo crea una ambiguità che non è sempre possibile risolvere in maniera
chiara; in generale quello che succede è che quando i limiti del sistema sono
fissi essi vengono definiti come macro di preprocessore nel file
\subsection{La funzione \func{uname}}
\label{sec:sys_uname}
-Una altra funzione che si può utilizzare per raccogliere informazioni sia
+Un'altra funzione che si può utilizzare per raccogliere informazioni sia
riguardo al sistema che al computer su cui esso sta girando è \func{uname}, il
suo prototipo è:
\begin{prototype}{sys/utsname.h}{int uname(struct utsname *info)}
occorre prima rendere disponibile al sistema il filesystem su cui essi sono
memorizzati; l'operazione di attivazione del filesystem è chiamata
\textsl{montaggio}, per far questo in Linux\footnote{la funzione è specifica
- di Linux e non è portabile} si usa la funzione \func{mount} il cui prototipo
+ di Linux e non è portabile.} si usa la funzione \func{mount} il cui prototipo
è:
\begin{prototype}{sys/mount.h}
{mount(const char *source, const char *target, const char *filesystemtype,
\macro{ENAMETOOLONG}, \macro{ENOENT} o \macro{ELOOP}.}
\end{prototype}
\noindent la funzione prende il nome della directory su cui il filesystem è
-montato e non il file o il dispositivo che è stato montato\footnote{questo è
+montato e non il file o il dispositivo che è stato montato,\footnote{questo è
vero a partire dal kernel 2.3.99-pre7, prima esistevano due chiamate
separate e la funzione poteva essere usata anche specificando il file di
- dispositivo.}, in quanto con il kernel 2.4.x è possibile montare lo stesso
+ dispositivo.} in quanto con il kernel 2.4.x è possibile montare lo stesso
dispositivo in più punti. Nel caso più di un filesystem sia stato montato
sullo stesso \textit{mount point} viene smontato quello che è stato montato
-per ultimo.
+per ultimo.
Si tenga presente che la funzione fallisce quando il filesystem è
\textsl{occupato}, questo avviene quando ci sono ancora file aperti sul
evitando l'errore di \macro{EBUSY}. In tutti i casi prima dello smontaggio
viene eseguita una sincronizzazione dei dati.
-Altre due funzioni specifiche di Linux\footnote{esse si trovano anche su BSD,
- ma con una struttura diversa}, utili per ottenere in maniera diretta
+Altre due funzioni specifiche di Linux,\footnote{esse si trovano anche su BSD,
+ ma con una struttura diversa.} utili per ottenere in maniera diretta
informazioni riguardo al filesystem su cui si trova un certo file, sono
\func{statfs} e \func{fstatfs}, i cui prototipi sono:
\begin{functions}
tempi nelle differenti rappresentazioni che vengono utilizzate.
-\subsection{La misura del tempo in unix}
+\subsection{La misura del tempo in Unix}
\label{sec:sys_unix_time}
-Storicamente i sistemi unix-like hanno sempre mantenuto due distinti
-valori per i tempi all'interno del sistema, essi sono rispettivamente
-chiamati \textit{calendar time} e \textit{process time}, secondo le
-definizioni:
+Storicamente i sistemi unix-like hanno sempre mantenuto due distinti tipi di
+dati per la misure dei tempi all'interno del sistema: essi sono
+rispettivamente chiamati \textit{calendar time} e \textit{process time},
+secondo le definizioni:
\begin{itemize}
\item \textit{calendar time}: è il numero di secondi dalla mezzanotte del
primo gennaio 1970, in tempo universale coordinato (o UTC), data che viene
viene mantenuto l'orologio del calcolatore, e viene usato ad esempio per
indicare le date di modifica dei file o quelle di avvio dei processi. Per
memorizzare questo tempo è stato riservato il tipo primitivo \type{time\_t}.
-\item \textit{process time}: talvolta anche detto tempo di CPU. Viene misurato
+\item \textit{process time}: detto anche tempo di processore. Viene misurato
in \textit{clock tick}, corrispondenti al numero di interruzioni effettuate
dal timer di sistema, e che per Linux avvengono ogni centesimo di
- secondo\footnote{eccetto per la piattaforma alpha dove avvengono ogni
- millesimo di secondo}. Il dato primitivo usato per questo tempo è
+ secondo.\footnote{eccetto per la piattaforma alpha dove avvengono ogni
+ millesimo di secondo.} Il dato primitivo usato per questo tempo è
\type{clock\_t}, inoltre la costante \macro{HZ} restituisce la frequenza di
operazione del timer, e corrisponde dunque al numero di tick al secondo. Lo
standard POSIX definisce allo stesso modo la costante \macro{CLK\_TCK});
\secref{sec:sys_limits}).
\end{itemize}
-In genere si usa il \textit{calendar time} per tenere le date dei file e le
-informazioni analoghe che riguardano i tempi di ``orologio'', usati ad esempio
-per i demoni che compiono lavori amministrativi ad ore definite, come
-\cmd{cron}. Di solito questo vene convertito automaticamente dal valore in UTC
-al tempo locale, utilizzando le opportune informazioni di localizzazione
+In genere si usa il \textit{calendar time} per esprimere le date dei file e le
+informazioni analoghe che riguardano i cosiddetti \textsl{tempi di orologio},
+che vengono usati ad esempio per i demoni che compiono lavori amministrativi
+ad ore definite, come \cmd{cron}.
+
+Di solito questo tempo viene convertito automaticamente dal valore in UTC al
+tempo locale, utilizzando le opportune informazioni di localizzazione
(specificate in \file{/etc/timezone}). E da tenere presente che questo tempo è
-mantenuto dal sistema e non corrisponde all'orologio hardware del calcolatore.
+mantenuto dal sistema e non è detto che corrisponda al tempo tenuto
+dall'orologio hardware del calcolatore.
-Il \textit{process time} di solito si esprime in secondi e viene usato appunto
-per tenere conto dei tempi di esecuzione dei processi. Per ciascun processo il
-kernel tiene tre di questi tempi:
-\begin{itemize*}
-\item \textit{clock time}
-\item \textit{user time}
-\item \textit{system time}
-\end{itemize*}
-il primo è il tempo ``reale'' (viene anche chiamato \textit{wall clock time})
-dall'avvio del processo, e misura il tempo trascorso fino alla sua
-conclusione; chiaramente un tale tempo dipende anche dal carico del sistema e
-da quanti altri processi stavano girando nello stesso periodo. Il secondo
-tempo è quello che la CPU ha speso nell'esecuzione delle istruzioni del
-processo in user space. Il terzo è il tempo impiegato dal kernel per eseguire
-delle system call per conto del processo medesimo (tipo quello usato per
-eseguire una \func{write} su un file). In genere la somma di user e system
-time viene chiamato \textit{CPU time}.
+Anche il \textit{process time} di solito si esprime in secondi, ma provvede una
+precisione ovviamente superiore al \textit{calendar time} (la cui granularità
+minima è il secondo) e viene usato per tenere conto dei tempi di esecuzione
+dei processi. Per ciascun processo il kernel calcola tre tempi diversi:
+\begin{description*}
+\item[\textit{clock time}]: il tempo \textsl{reale} (viene chiamato anche
+ \textit{wall clock time}) passato dall'avvio del processo. Chiaramente tale
+ tempo dipende anche dal carico del sistema e da quanti altri processi
+ stavano girando nello stesso periodo.
+\item[\textit{user time}]: il tempo che la CPU ha impiegato nell'esecuzione
+ delle istruzioni del processo in user space.
+\item[\textit{system time}]: il tempo che la CPU ha impiegato nel kernel per
+ eseguire delle system call per conto del processo.
+\end{description*}
+In genere la somma di \textit{user time} e \textit{system time} indica il
+tempo di processore totale in cui il sistema è stato effettivamente impegnato
+nell'eseguire un certo processo e viene chiamato \textit{CPU time}.
che c'è stato un errore, non il tipo di errore.
Per riportare il tipo di errore il sistema usa la variabile globale
-\var{errno}\footnote{L'uso di una variabile globale può comportare alcuni
+\var{errno},\footnote{L'uso di una variabile globale può comportare alcuni
problemi (ad esempio nel caso dei thread) ma lo standard ISO C consente
anche di definire \var{errno} come un \textit{modifiable lvalue}, quindi si
può anche usare una macro, e questo è infatti il modo usato da Linux per
- renderla locale ai singoli thread.}, definita nell'header \file{errno.h}; la
+ renderla locale ai singoli thread.} definita nell'header \file{errno.h}; la
variabile è in genere definita come \type{volatile} dato che può essere
cambiata in modo asincrono da un segnale (per una descrizione dei segnali si
veda \secref{cha:signals}), ma dato che un manipolatore di segnale scritto
essere modificata dal programma e che è utilizzabile solo fino ad una chiamata
successiva a \func{strerror}; nel caso si usino i thread è
provvista\footnote{questa funzione è una estensione GNU, non fa parte dello
- standard POSIX} una versione apposita:
+ standard POSIX.} una versione apposita:
\begin{prototype}{string.h}
{char *strerror\_r(int errnum, char *buff, size\_t size)}
Analoga a \func{strerror} ma ritorna il messaggio in un buffer
che utilizza un buffer che il singolo thread deve allocare, per evitare i
problemi connessi alla condivisione del buffer statico. Infine, per completare
la caratterizzazione dell'errore, si può usare anche la variabile
-globale\footnote{anche questa è una estensione GNU}
+globale\footnote{anche questa è un'estensione GNU.}
\var{program\_invocation\_short\_name} che riporta il nome del programma
attualmente in esecuzione.