La manipolazione delle caratteristiche di questi filee e la loro cancellazione
può essere effettuata con le stesse funzioni che operano sui file normali; ma
-quando li si devono creare sono necessarie delle funzioni apposite.
-
+quando li si devono creare sono necessarie delle funzioni apposite. La prima
+di queste funzioni è \func{mknod}, il suo prototipo è:
\begin{functions}
\headdecl{sys/types.h}
\headdecl{sys/stat.h}
\headdecl{fnctl.h}
\headdecl{unistd.h}
- \funcdecl{int mknod(const char *pathname, mode\_t mode, dev\_t dev)}
+ \funcdecl{int mknod(const char *pathname, mode\_t mode, dev\_t dev)} Crea un
+ inode, si usa per creare i file speciali.
\bodydesc{La funzione restituisce zero in caso di successo e -1 per un
errore, nel qual caso \var{errno} assumerà i valori:
\begin{errlist}
- \item[\macro{EPERM}] Il filesystem non supporta la cancellazione di
- directory, oppure la directory che contiene \var{dirname} ha lo sticky bit
- settato e l'\textit{effective user id} del processo non corrisponde al
- proprietario della directory.
- \item[\macro{EACCESS}] Non c'è il permesso di scrittura per la directory che
- contiene la directory che si vuole cancellare, o non c'è il permesso di
- attraversare (esecuzione) una delle directory specificate in
- \var{dirname}.
- \item[\macro{EBUSY}] La directory specificata è la directory di lavoro o la
- radice di qualche processo.
- \item[\macro{ENOTEMPTY}] La directory non è vuota.
+ \item[\macro{EPERM}] Non si hanno privilegi sufficienti a creare l'inode, o
+ il filesystem su cui si è cercato di creare \func{pathname} non supporta
+ l'operazione.
+ \item[\macro{EINVAL}] Il valore di \var{mode} non indica un file, una fifo o
+ un dipositivo.
+ \item[\macro{EEXIST}] \param{pathname} esiste già o è un link simbolico.
\end{errlist}
- ed inoltre anche \macro{EFAULT}, \macro{ENAMETOOLONG}, \macro{ENOENT},
- \macro{ENOTDIR}, \macro{ENOMEM}, \macro{ELOOP}, \macro{EROFS}.}
+ ed inoltre anche \macro{EFAULT}, \macro{EACCESS}, \macro{ENAMETOOLONG},
+ \macro{ENOENT}, \macro{ENOTDIR}, \macro{ENOMEM}, \macro{ELOOP},
+ \macro{ENOSPC}, \macro{EROFS}.}
\end{functions}
-
+La funzione permette di creare un file speciale, ma si può usare anche per
+creare file normali e fifo; l'argomento \param{mode} specifica il tipo di file
+che si vuole creare ed i relativi permessi, secondo i valori riportati in
+\tabref{tab:file_mode_flags}, che vanno combinato come OR binario. I permessi
+sono comunque modificati nella maniera usuale dal valore di \var{umask} (si
+veda \secref{sec:file_umask}.
+
+Per il tipo di file può essere specificato solo uno fra: \macro{S\_IFREG} per
+un file normale (che sarà creato vuoto), \macro{S\_IFBLK} per un device a
+blocchi, \macro{S\_IFCHR} per un device a caratteri e \macro{S\_IFIFO} per una
+fifo. Un valore diverso comporterà l'errore \macro{EINVAL}. Qualora si sia
+specificato in \param{mode} un file di dispositivo, il valore di \param{dev}
+viene usato per indicare a quale dispositivo si fa riferimento.
+
+Solo l'amministratore può creare un file di dispositivo o un file regolare
+usando questa funzione; ma in Linux\footnote{la funzione non è prevista dallo
+ standard POSIX, e deriva da SVr4, con appunto questa differenza e diversi
+ codici di errore.} l'uso per la creazione di una fifo è consentito anche
+agli utenti normali.
+
+I nuovi inode creati con \func{mknod} apparterranno al proprietario e al
+gruppo del processo che li creati, a meno che non si sia attivato il bit
+\acr{sgid} per la directory o sia stata attivata la semantica BSD per il
+filesystem (si veda \secref{sec:file_ownership}) in cui si va a creare
+l'inode.
+
+Per creare una fifo (un file speciale, su cui torneremo in dettaglio in
+\secref{sec:ipc_named_pipe}) lo standard POSIX specifica l'uso della funzione
+\func{mkfifo}, il cui prototipo è:
\begin{functions}
- \headdecl{sys/types.h}
- \headdecl{sys/stat.h}
- \funcdecl{int mkfifo(const char *pathname, mode\_t mode)}
+ \headdecl{sys/types.h} \headdecl{sys/stat.h}
+
+ \funcdecl{int mkfifo(const char *pathname, mode\_t mode)} Crea una fifo.
\bodydesc{La funzione restituisce zero in caso di successo e -1 per un
- errore, nel qual caso \var{errno} assumerà i valori:
- \begin{errlist}
- \item[\macro{EPERM}] Il filesystem non supporta la cancellazione di
- directory, oppure la directory che contiene \var{dirname} ha lo sticky bit
- settato e l'\textit{effective user id} del processo non corrisponde al
- proprietario della directory.
- \item[\macro{EACCESS}] Non c'è il permesso di scrittura per la directory che
- contiene la directory che si vuole cancellare, o non c'è il permesso di
- attraversare (esecuzione) una delle directory specificate in
- \var{dirname}.
- \item[\macro{EBUSY}] La directory specificata è la directory di lavoro o la
- radice di qualche processo.
- \item[\macro{ENOTEMPTY}] La directory non è vuota.
- \end{errlist}
- ed inoltre anche \macro{EFAULT}, \macro{ENAMETOOLONG}, \macro{ENOENT},
- \macro{ENOTDIR}, \macro{ENOMEM}, \macro{ELOOP}, \macro{EROFS}.}
+ errore, nel qual caso \var{errno} assumerà i valori \macro{EACCESS},
+ \macro{EEXIST}, \macro{ENAMETOOLONG}, \macro{ENOENT}, \macro{ENOSPC},
+ \macro{ENOTDIR} e\macro{EROFS}.}
\end{functions}
-
+\noindent come per \func{mknod} il file \param{pathname} non deve esistere
+(neanche come link simbolico); al solito i permessi specificati da
+\param{mode} vengono modificati dal valore di \var{umask}.
Per accedere al contenuto delle directory si usano i cosiddetti
\textit{directory streams} (chiamati così per l'analogia con i file stream di
-\capref{che:file_std_interface}); la funzione \func{opendir} apre uno di
+\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
Una seconda funzione simile è \code{char *get\_current\_dir\_name(void)} che è
sostanzialmente equivalente ad una \code{getcwd(NULL, 0)}, con la sola
differenza che essa ritorna il valore della variabile di ambiente \macro{PWD},
-che essendo costruita dalla shell può contenere anche dei riferimenti
-simbolici; nel caso di \func{getcwd} infatti, essendo il pathname ricavato
-risalendo all'indietro l'albero della directory, si perderebbe traccia di ogni
-passaggio attraverso eventuali pathname.
-
-Altre due funzioni, \func{chdir} e \func{fchdir}, vengono usate, come dice il
-nome (che deriva da \textit{change directory}), per cambiare la directory di
-lavoro corrente. Dato che anche le directory sono file, è possibile riferirsi
-ad esse anche tramite il file descriptor dell'interfaccia a basso livello, e
-non solo tramite il filename, i prototipi di queste funzioni sono:
-\begin{functions}
- \headdecl{unistd.h}
- \funcdecl{int chdir(const char *path)}
- Cambia la directory di lavoro corrente a quella specificata dal pathname
- contenuto nella stringa \var{path}.
-
- \funcdecl{int fchdir(int fd)} Analoga alla precedente, ma usa un file
- descriptor invece del pathname.
+che essendo costruita dalla shell può contenere un pathname comprendente anche
+con dei link simbolici. Usando \func{getcwd} infatti, essendo il
+pathname ricavato risalendo all'indietro l'albero della directory, si
+perderebbe traccia di ogni passaggio attraverso eventuali link simbolici.
+
+Per cambiare la directory di lavoro corrente si può usare la funzione
+\func{chdir} (omonima dell'analogo comando di shell) il cui nome sta appunto
+per \textit{change directory}), il suo prototipo è:
+\begin{prototype}{unistd.h}{int chdir(const char *pathname)}
+ Cambia la directory di lavoro corrente in \param{pathname}.
- \bodydesc{Entrambe le funzioni restituiscono zero in caso di successo
- e -1 per un errore, in caso di errore \var{errno} viene settata per
- \func{chdir} ai valori:
+ \bodydesc{La funzione restituisce 0 in caso di successo e -1 per un errore,
+ nel qual caso \var{errno} viene settata a:
\begin{errlist}
- \item[\macro{ENOTDIR}] Uno dei componenti di \param{path} non è una
- directory.
+ \item[\macro{ENOTDIR}] Non si è specificata una directory.
\item[\macro{EACCESS}] Manca il permesso di ricerca su uno dei componenti di
\param{path}.
\end{errlist}
ed inoltre \macro{EFAULT}, \macro{ENAMETOOLONG}, \macro{ENOENT},
- \macro{ENOMEM}, \macro{ELOOP} e \macro{EIO}. Per \func{fchdir} invece gli
- errori sono \macro{EBADF} e \macro{EACCES}.}
-\end{functions}
+ \macro{ENOMEM}, \macro{ELOOP} e \macro{EIO}.}
+\end{prototype}
+\noindent ed ovviamente \param{pathname} deve indicare una directory per la
+quale si hanno i permessi di accesso.
+
+Dato che anche le directory sono file, è possibile riferirsi ad esse anche
+tramite il file descriptor, e non solo tramite il filename, per fare questo si
+usa \func{fchdir}, il cui prototipo è:
+\begin{prototype}{unistd.h}{int fchdir(int fd)}
+ Identica a \func{chdir}, ma usa il file descriptor \param{fd} invece del
+ pathname.
+
+ \bodydesc{La funzione restituisce zero in caso di successo e -1 per un
+ errore, in caso di errore \var{errno} viene settata ai valori
+ \macro{EBADF} o \macro{EACCES}.}
+\end{prototype}
+\noindent anche in questo caso \param{fd} deve essere un file descriptor
+valido che fa riferimento ad una directory. Inoltre l'unico errore di accesso
+possibile (tutti gli altri sarebbero occorsi all'apertura di \func{fd}), è
+quello in cui il processo non ha il permesso di accesso alla directory
+specificata da \param{fd}.
\subsection{I file temporanei}
\label{sec:file_temp_file}
-Un'altra serie di funzioni definite dalle librerie standard del C sono quelle
-che riguardano la creazione di file temporanei.
+In molte occasioni è utile poter creare dei file temporanei; benchè la cosa
+sembri semplice in realtà il problema è più sottile di quanto non appaia a
+prima vista. Infatti anche se sembrerebbe banale generare un nome a caso e
+creare il file dopo aver controllato che questo non esista, nel momento fra il
+controllo e la creazione si ha giusto lo spazio per una \textit{race
+ condition} (si ricordi quanto visto in \secref{sec:proc_race_cond}).
+Per questo motivo il kernel le \acr{glibc} provvedono una serie di funzioni da
+utilizzare per la gestione dei file temporanei.
Usare la semantica BSD ha il vantaggio che il \acr{gid} viene sempre
automaticamente propagato, restando coerente a quello della directory di
-partenza, in tutte le sottodirectory. La semantica SVR4 offre una maggiore
+partenza, in tutte le sottodirectory. La semantica SVr4 offre una maggiore
possibilità di scelta, ma per ottenere lo stesso risultato necessita che per
le nuove directory venga anche propagato anche il bit \acr{sgid}. Questo è
comunque il comportamento di default di \func{mkdir}, ed é in questo modo ad
\label{sec:proc_handling_intro}
I processi vengono creati dalla funzione \func{fork}; in molti unix questa è
-una system call, Linux però usa un'altra nomenclatura, e la funzione fork è
-basata a sua volta sulla system call \func{\_\_clone}, che viene usata anche
-per generare i \textit{thread}. Il processo figlio creato dalla \func{fork} è
-una copia identica del processo processo padre, ma ha nuovo \acr{pid} e viene
-eseguito in maniera indipendente (le differenze fra padre e figlio sono
-affrontate in dettaglio in \secref{sec:proc_fork}).
+una system call, Linux però usa un'altra nomenclatura, e la funzione
+\func{fork} è basata a sua volta sulla system call \func{\_\_clone}, che viene
+usata anche per generare i \textit{thread}. Il processo figlio creato dalla
+\func{fork} è una copia identica del processo processo padre, ma ha nuovo
+\acr{pid} e viene eseguito in maniera indipendente (le differenze fra padre e
+figlio sono affrontate in dettaglio in \secref{sec:proc_fork}).
Se si vuole che il processo padre si fermi fino alla conclusione del processo
figlio questo deve essere specificato subito dopo la \func{fork} chiamando la
funzione \func{wait} o la funzione \func{waitpid} (si veda
\secref{sec:proc_wait}); queste funzioni restituiscono anche una informazione
abbastanza limitata (lo stato di terminazione) sulle cause della terminazione
-del processo.
+del processo figlio.
Quando un processo ha concluso il suo compito o ha incontrato un errore non
risolvibile esso può essere terminato con la funzione \func{exit} (si veda
\section{La gestione dei processi}
\label{sec:proc_handling}
-In questa sezione tratteremo le funzioni per la gestione dei processi, a
-partire dalle funzioni elementari che permettono di leggerne gli
-identificatori, alle varie funzioni di manipolazione dei processi, che
-riguardano la loro creazione, terminazione, e la messa in esecuzione di altri
-programmi.
+In questa sezione tratteremo le problematiche della gestione dei processi
+all'interno del sistema, illustrandone tutti i dettagli. Inizieremo con le
+funzioni elementari che permettono di leggerne gli identificatori, per poi
+passare alla spiegazione delle funzioni fondamentali che si usano per la
+creazione e la terminazione dei processi, e per la messa in esecuzione degli
+altri programmi.
\subsection{Gli identificatori dei processi}
Come accennato nell'introduzione ogni processo viene identificato dal sistema
da un numero identificativo unico, il \textit{process id} o \acr{pid};
quest'ultimo è un tipo di dato standard, il \type{pid\_t} che in genere è un
-intero con segno (nel caso di Linux e delle glibc il tipo usato è \type{int}).
+intero con segno (nel caso di Linux e delle \acr{glibc} il tipo usato è \type{int}).
Il \acr{pid} viene assegnato in forma progressiva ogni volta che un nuovo
processo viene creato, fino ad un limite massimo (in genere essendo detto
un processo e le varie relazioni fra processi utilizzate per definire una
sessione.
-Oltre al \acr{pid} e al \acr{ppid}, e a quelli usati per il controllo di
-sessione, ad ogni processo sono associati altri identificatori, usati per il
-controllo di accesso, che servono per determinare se il processo può o meno
-eseguire le operazioni richieste, a seconda dei privilegi e dell'identità di
-chi lo ha posto in esecuzione; su questi torneremo in dettagli più avanti in
-\secref{sec:proc_perms}.
+Oltre al \acr{pid} e al \acr{ppid}, (e a quelli che vedremo in
+\secref{sec:sess_xxx}, relativi al controllo di sessione), ad ogni processo
+vengono associati degli altri identificatori che vengono usati per il
+controllo di accesso. Questi servono per determinare se un processo può
+eseguire o meno le operazioni richieste, a seconda dei privilegi e
+dell'identità di chi lo ha posto in esecuzione; l'argomento è complesso e sarà
+affrontato in dettaglio in \secref{sec:proc_perms}.
\subsection{La funzione \func{fork}}
di testo, che è identico, è condiviso e tenuto in read-only, Linux poi
utilizza la tecnica del \textit{copy-on-write}, per cui la memoria degli
altri segmenti viene copiata dal kernel per il nuovo processo solo in caso
- di scrittura, rendendo molto più efficiente il meccanismo} pertanto padre e
-figlio vedono variabili diverse.
+ di scrittura, rendendo molto più efficiente il meccanismo della creazione di
+ un nuovo processo}, pertanto padre e figlio vedono variabili diverse.
La differenza che si ha nei due processi è che nel processo padre il valore di
-ritorno della funzione fork è il \acr{pid} del processo figlio, mentre nel
-figlio è zero; in questo modo il programma può identificare se viene eseguito
-dal padre o dal figlio. Si noti come la funzione \func{fork} ritorni
-\textbf{due} volte: una nel padre e una nel figlio. La sola differenza che si
-ha nei due processi è il valore di ritorno restituito dalla funzione, che nel
-padre è il \acr{pid} del figlio mentre nel figlio è zero; in questo modo il
-programma può identificare se viene eseguito dal padre o dal figlio.
-
-La scelta di questi valori non è casuale, un processo infatti può avere più
-figli, ed il valore di ritorno di \func{fork} è l'unico modo che permette di
-identificare quello appena creato; al contrario un figlio ha sempre un solo
-padre (il cui \acr{pid} può sempre essere ottenuto con \func{getppid}, vedi
-\secref{sec:proc_pid}) e si usa il valore nullo, che non può essere il
-\acr{pid} di nessun processo.
+ritorno della funzione \func{fork} è il \acr{pid} del processo figlio, mentre
+nel figlio è zero; in questo modo il programma può identificare se viene
+eseguito dal padre o dal figlio. Si noti come la funzione \func{fork} ritorni
+\textbf{due} volte: una nel padre e una nel figlio.
+
+La scelta di questi valori di ritorno non è casuale, un processo infatti può
+avere più figli, ed il valore di ritorno di \func{fork} è l'unico modo che gli
+permette di identificare quello appena creato; al contrario un figlio ha
+sempre un solo padre (il cui \acr{pid} può sempre essere ottenuto con
+\func{getppid}, vedi \secref{sec:proc_pid}) per cui si usa il valore nullo,
+che non è il \acr{pid} di nessun processo.
\begin{figure}[!htb]
\footnotesize
Normalmente la chiamata a \func{fork} può fallire solo per due ragioni, o ci
sono già troppi processi nel sistema (il che di solito è sintomo che
qualcos'altro non sta andando per il verso giusto) o si è ecceduto il limite
-sul numero totale di processi permessi all'utente (il valore della costante
-\macro{CHILD\_MAX} definito in \file{limits.h}, che fa riferimento ai processo
-con lo stesso \textit{real user id}).
+sul numero totale di processi permessi all'utente (vedi \secref{sec:sys_xxx}).
L'uso di \func{fork} avviene secondo due modalità principali; la prima è
quella in cui all'interno di un programma si creano processi figli per
Alcuni sistemi operativi (il VMS ad esempio) combinano le operazioni di questa
seconda modalità (una \func{fork} seguita da una \func{exec}) in un'unica
operazione che viene chiamata \textit{spawn}. Nei sistemi unix-like è stato
-scelto di mantenere questa separazione, dato che, come visto per la prima
-modalità d'uso, esistono numerosi scenari in cui si può usare una \func{fork}
-senza bisogno di una \func{exec}. Inoltre anche nel caso della seconda
-modalità di operazioni, avere le due funzioni separate permette al figlio di
+scelto di mantenere questa separazione, dato che, come per la prima modalità
+d'uso, esistono numerosi scenari in cui si può usare una \func{fork} senza
+aver bisogno di eseguire una \func{exec}. Inoltre, anche nel caso della
+seconda modalità di uso, avere le due funzioni separate permette al figlio di
cambiare gli attributi del processo (maschera dei segnali, redirezione
-dell'output, \textit{user id}) prima della \func{exec}, rendendo molto più
-flessibile la possibilità di modificare gli attributi del nuovo processo.
+dell'output, \textit{user id}) prima della \func{exec}, rendendo così
+relativamente facile intervenire sulle le modalità di esecuzione del nuovo
+programma.
In \curfig\ si è riportato il corpo del codice del programma di esempio
\cmd{forktest}, che ci permette di illustrare molte caratteristiche dell'uso
istruzioni del codice fra padre e figli, nè sull'ordine in cui questi potranno
essere messi in esecuzione, e se è necessaria una qualche forma di precedenza
occorrerà provvedere ad espliciti meccanismi di sincronizzazione, pena il
-rischio di incorrere nelle cosiddette \textit{race conditions}.
+rischio di incorrere nelle cosiddette \textit{race condition} \index{race
+ condition} (vedi \secref{sec:proc_race_cond}.
-Si noti inoltre che, come accennato, essendo i segmenti di memoria utilizzati
-dai singoli processi completamente separati, le modifiche delle variabili nei
-processi figli (come l'incremento di \var{i} in \texttt{\small 33}) sono
-visibili solo al loro interno, e non hanno alcun effetto sul valore che le
-stesse variabili hanno nel processo padre (ed in eventuali altri processi
-figli che eseguano lo stesso codice).
+Si noti inoltre che essendo i segmenti di memoria utilizzati dai singoli
+processi completamente separati, le modifiche delle variabili nei processi
+figli (come l'incremento di \var{i} in \texttt{\small 33}) sono visibili solo
+a loro, e non hanno alcun effetto sul valore che le stesse variabili hanno nel
+processo padre (ed in eventuali altri processi figli che eseguano lo stesso
+codice).
Un secondo aspetto molto importante nella creazione dei processi figli è
quello dell'interazione dei vari processi con i file; per illustrarlo meglio
in gran dettaglio in \capref{cha:file_unix_interface} e in
\secref{cha:files_std_interface}. Qui basta accennare che si sono usate le
funzioni standard della libreria del C che prevedono l'output bufferizzato; e
-questa bufferizzazione varia a seconda che si tratti di un file su disco (in
-cui il buffer viene scaricato su disco solo quando necessario) o di un
-terminale (nel qual caso il buffer viene scaricato ad ogni a capo).
+questa bufferizzazione (di veda \secref{sec:file_buffering}) varia a seconda
+che si tratti di un file su disco (in cui il buffer viene scaricato su disco
+solo quando necessario) o di un terminale (nel qual caso il buffer viene
+scaricato ad ogni carattere di a capo).
Nel primo esempio allora avevamo che ad ogni chiamata a \func{printf} il
buffer veniva scaricato, e le singole righe erano stampate a video subito dopo
l'esecuzione della \func{printf}. Ma con la redirezione su file la scrittura
-non avviene più alla fine di ogni riga e l'output resta nel buffer, per questo
+non avviene più alla fine di ogni riga e l'output resta nel buffer. Per questo
motivo, dato che ogni figlio riceve una copia della memoria del padre, esso
riceverà anche quanto c'è nel buffer delle funzioni di I/O, comprese le linee
scritte dal padre fino allora. Così quando all'uscita del figlio il buffer
viene scritto su disco, troveremo nel file anche tutto quello che il processo
-padre aveva scritto prima della sua creazione. E alla fine del file, dato che
-in questo caso il padre esce per ultimo, troviamo anche l'output del padre.
+padre aveva scritto prima della sua creazione. E solo alla fine del file,
+dato che in questo caso il padre esce per ultimo, troveremo anche l'output del
+padre.
Ma l'esempio ci mostra un'altro aspetto fondamentale dell'interazione con i
file, che era valido anche per l'esempio precedente, ma meno evidente; il
la caratteristica di duplicare (allo stesso modo in cui lo fa la funzione
\func{dup}, trattata in \secref{sec:file_dup}) nei figli tutti i file
descriptor aperti nel padre, il che comporta che padre e figli condividono le
-stesse voci della file table (per la spiegazione di questi termini si veda
-\secref{sec:file_sharing}) e quindi anche l'offset corrente nel file.
-
-In questo modo se un processo scrive sul file aggiornerà l'offset sulla file
-table, e tutti gli altri processi che condividono la file table vedranno il
-nuovo valore; in questo modo si evita, in casi come quello appena mostrato in
-cui diversi processi scrivono sullo stesso file, che l'output successivo di un
-processo vada a sovrapporsi a quello dei precedenti (l'output potrà risultare
-mescolato, ma non ci saranno parti perdute per via di una sovrascrittura).
+stesse voci della \textit{file table} (per la spiegazione di questi termini si
+veda \secref{sec:file_sharing}) e fra cui c'è anche la posizione corrente nel
+file.
+
+In questo modo se un processo scrive sul file aggiornerà la posizione corrente
+sulla \textit{file table}, e tutti gli altri processi, che vedono la stessa
+\textit{file table}, vedranno il nuovo valore. In questo modo si evita, in
+casi come quello appena mostrato in cui diversi processi scrivono sullo stesso
+file, che l'output successivo di un processo vada a sovrapporsi a quello dei
+precedenti: l'output potrà risultare mescolato, ma non ci saranno parti
+perdute per via di una sovrascrittura.
Questo tipo di comportamento è essenziale in tutti quei casi in cui il padre
-crea un figlio ed attende la sua conclusione per proseguire, ed entrambi
-scrivono sullo stesso file, ad esempio lo standard output (un caso tipico è la
-shell). Se l'output viene rediretto con questo comportamento avremo che il
-padre potrà continuare a scrivere automaticamente in coda a quanto scritto dal
-figlio; se così non fosse ottenere questo comportamento sarebbe estremamente
-complesso necessitando di una qualche forma di comunicazione fra i due
-processi.
+crea un figlio e attende la sua conclusione per proseguire, ed entrambi
+scrivono sullo stesso file (un caso tipico è la shell quando lancia un
+programma, il cui output va sullo standard output).
+
+In questo modo, anche se l'output viene rediretto, il padre potrà sempre
+continuare a scrivere in coda a quanto scritto dal figlio in maniera
+automatica; se così non fosse ottenere questo comportamento sarebbe
+estremamente complesso necessitando di una qualche forma di comunicazione fra
+i due processi per far riprendere al padre la scrittura al punto giusto.
In generale comunque non è buona norma far scrivere più processi sullo stesso
-file senza una qualche forma di sincronizzazione in quanto, come visto con il
-nostro esempio, le varie scritture risulteranno mescolate fra loro in una
-sequenza impredicibile. Le modalità con cui in genere si usano i file dopo una
-\func{fork} sono sostanzialmente due:
+file senza una qualche forma di sincronizzazione in quanto, come visto anche
+con il nostro esempio, le varie scritture risulteranno mescolate fra loro in
+una sequenza impredicibile. Per questo le modalità con cui in genere si usano
+i file dopo una \func{fork} sono sostanzialmente due:
\begin{enumerate}
\item Il processo padre aspetta la conclusione del figlio. In questo caso non
è necessaria nessuna azione riguardo ai file, in quanto la sincronizzazione
- degli offset dopo eventuali operazioni di lettura e scrittura effettuate dal
- figlio è automatica.
+ della posizione corrente dopo eventuali operazioni di lettura e scrittura
+ effettuate dal figlio è automatica.
\item L'esecuzione di padre e figlio procede indipendentemente. In questo caso
- ciascuno dei due deve chiudere i file che non gli servono una volta che la
- \func{fork} è stata eseguita, per evitare ogni forma di interferenza.
+ ciascuno dei due processi deve chiudere i file che non gli servono una volta
+ che la \func{fork} è stata eseguita, per evitare ogni forma di interferenza.
\end{enumerate}
Oltre ai file aperti i processi figli ereditano dal padre una serie di altre
proprietà; la lista dettagliata delle proprietà che padre e figlio hanno in
comune dopo l'esecuzione di una \func{fork} è la seguente:
\begin{itemize*}
-\item i file aperti e gli eventuali flag di \textit{close-on-exec} (vedi
-\secref{sec:proc_exec} e \secref{sec:file_fcntl}) se settati.
+\item i file aperti e gli eventuali flag di \textit{close-on-exec} settati
+ (vedi \secref{sec:proc_exec} e \secref{sec:file_fcntl}).
\item gli identificatori per il controllo di accesso: il \textit{real user
id}, il \textit{real group id}, l'\textit{effective user id},
- l'\textit{effective group id} e i \textit{supplementary group id} (vedi
+ l'\textit{effective group id} ed i \textit{supplementary group id} (vedi
\secref{sec:proc_user_group}).
\item gli identificatori per il controllo di sessione: il \textit{process
- group id} e il \textit{session id} e il terminale di controllo (vedi
+ group id} e il \textit{session id} ed il terminale di controllo (vedi
\secref{sec:sess_xxx} e \secref{sec:sess_xxx}).
\item i flag di \acr{suid} e \acr{sgid} (vedi \secref{sec:file_suid_sgid}).
\item la directory di lavoro e la directory radice (vedi
- \secref{sec:file_work_dir}).
+ \secref{sec:file_work_dir} e \secref{sec:file_chroot}).
\item la maschera dei permessi di creazione (vedi \secref{sec:file_umask}).
\item la maschera dei segnali bloccati e le azioni installate (vedi
\secref{sec:sig_xxx}).
\item i segmenti di memoria condivisa agganciati al processo (vedi
\secref{sec:ipc_xxx}).
-\item i limiti sulle risorse (vedi \secref{sec:sys_xxx}).
+\item i limiti sulle risorse (vedi \secref{sec:sys_xxx}).
\item le variabili di ambiente (vedi \secref{sec:proc_environ}).
\end{itemize*}
le differenze fra padre e figlio dopo la \func{fork} invece sono:
Dato che Linux supporta il \textit{copy on write} la perdita di prestazioni è
assolutamente trascurabile, e l'uso di questa funzione (che resta un caso
-speciale della funzione \func{clone}), è deprecato, per questo eviteremo di
+speciale della funzione \func{clone}), è deprecato; per questo eviteremo di
trattarla ulteriormente.
\label{sec:proc_termination}
In \secref{sec:proc_conclusion} abbiamo già affrontato le modalità con cui
-concludere un programma, ma dal punto di vista del programma stesso; avendo a
+chiudere un programma, ma dal punto di vista del programma stesso; avendo a
che fare con un sistema multitasking occorre adesso affrontare l'argomento dal
punto di vista generale di come il sistema gestisce la conclusione dei
processi.
memoria che stava usando, e così via; l'elenco completo delle operazioni
eseguite alla chiusura di un processo è il seguente:
\begin{itemize*}
-\item tutti i descrittori dei file sono chiusi.
+\item tutti i file descriptor sono chiusi.
\item viene memorizzato lo stato di terminazione del processo.
-\item ad ogni processo figlio viene assegnato un nuovo padre.
+\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_xxx}).
\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}).
ma al di la di queste operazioni è necessario poter disporre di un meccanismo
ulteriore che consenta di sapere come questa terminazione è avvenuta; dato che
in un sistema unix-like tutto viene gestito attraverso i processi il
-meccanismo scelto consiste nel riportare lo stato di terminazione
-(\textit{termination status}) di cui sopra al processo padre.
+meccanismo scelto consiste nel riportare lo stato di terminazione (il
+cosiddetto \textit{termination status}) al processo padre.
-Nel caso di conclusione normale, lo stato di uscita del processo viene
-caratterizzato tramite il valore del cosiddetto \textit{exit status}, cioè il
-valore passato alle funzioni \func{exit} o \func{\_exit} (o dal valore di
-ritorno per \func{main}). Ma se il processo viene concluso in maniera anomala
-il programma non può specificare nessun \textit{exit status}, ed è il kernel
-che deve generare autonomamente il \textit{termination status} per indicare le
-ragioni della conclusione anomala.
+Nel caso di conclusione normale, abbiamo visto in \secref{sec:proc_conclusion}
+che lo stato di uscita del processo viene caratterizzato tramite il valore del
+cosiddetto \textit{exit status}, cioè il valore passato alle funzioni
+\func{exit} o \func{\_exit} (o dal valore di ritorno per \func{main}). Ma se
+il processo viene concluso in maniera anomala il programma non può specificare
+nessun \textit{exit status}, ed è il kernel che deve generare autonomamente il
+\textit{termination status} per indicare le ragioni della conclusione anomala.
Si noti la distinzione fra \textit{exit status} e \textit{termination status}:
quello che contraddistingue lo stato di chiusura del processo e viene
Questo viene fatto mantenendo attiva la voce nella tabella dei processi, e
memorizzando alcuni dati essenziali, come il \acr{pid}, i tempi di CPU usati
-dal processo (vedi \secref{sec:sys_unix_time}) e lo stato di terminazione
-\footnote{NdA verificare esattamente cosa c'è!}, mentre la memoria in uso ed i
-file aperti vengono rilasciati immediatamente. I processi che sono terminati,
-ma il cui stato di terminazione non è stato ancora ricevuto dal padre sono
-chiamati \textit{zombie}, essi restano presenti nella tabella dei processi ed
-in genere possono essere identificati dall'output di \cmd{ps} per la presenza
-di una \cmd{Z} nella colonna che ne indica lo stato. Quando il padre
-effettuerà la lettura dello stato di uscita anche questa informazione, non più
-necessaria, verrà scartata e la terminazione potrà dirsi completamente
+dal processo (vedi \secref{sec:sys_unix_time}) e lo stato di
+terminazione\footnote{NdA verificare esattamente cosa c'è!}, mentre la memoria
+in uso ed i file aperti vengono rilasciati immediatamente. I processi che sono
+terminati, ma il cui stato di terminazione non è stato ancora ricevuto dal
+padre sono chiamati \textit{zombie}, essi restano presenti nella tabella dei
+processi ed in genere possono essere identificati dall'output di \cmd{ps} per
+la presenza di una \texttt{Z} nella colonna che ne indica lo stato. Quando il
+padre effettuerà la lettura dello stato di uscita anche questa informazione,
+non più necessaria, verrà scartata e la terminazione potrà dirsi completamente
conclusa.
Possiamo utilizzare il nostro programma di prova per analizzare anche questa
\begin{functions}
\headdecl{sys/types.h}
\headdecl{sys/wait.h}
-\funcdecl{pid\_t wait(int * status)}
+\funcdecl{pid\_t wait(int *status)}
Sospende il processo corrente finché un figlio non è uscito, o finché un
segnale termina il processo o chiama una funzione di gestione.
}
\end{functions}
\noindent
-è presente fin dalle prime versioni di unix; la funzione ritorna alla
-conclusione del primo figlio (o immediatamente se un figlio è già
-uscito). Se un figlio è già uscito la funzione ritorna immediatamente.
+è presente fin dalle prime versioni di unix; la funzione ritorna non appena un
+processo figlio termina. Se un figlio è già terminato la funzione ritorna
+immediatamente.
Al ritorno lo stato di termininazione del processo viene salvato nella
variabile puntata da \var{status} e tutte le informazioni relative al
che effettua lo stesso servizio, ma dispone di una serie di funzionalità più
ampie, legate anche al controllo di sessione. Dato che è possibile ottenere
lo stesso comportamento di \func{wait} si consiglia di utilizzare sempre
-questa funzione; il suo prototipo è:
+questa funzione, il cui prototipo è:
\begin{functions}
\headdecl{sys/types.h}
\headdecl{sys/wait.h}
-\funcdecl{pid\_t waitpid(pid\_t pid, int * status, int options)}
+\funcdecl{pid\_t waitpid(pid\_t pid, int *status, int options)}
Attende la conclusione di un processo figlio.
\bodydesc{La funzione restituisce il \acr{pid} del processo che è uscito, 0 se
\label{tab:proc_status_macro}
\end{table}
-Entrambe le funzioni restituiscono lo stato di terminazione del processo
-tramite il puntatore \var{status} (se non interessa memorizzare lo stato si
-può passare un puntatore nullo). Il valore restituito da entrambe le funzioni
-dipende dall'implementazione, e tradizionalmente alcuni bit sono riservati per
-memorizzare lo stato di uscita (in genere 8) altri per indicare il segnale che
-ha causato la terminazione (in caso di conclusione anomala), uno per indicare
-se è stato generato un core file, etc.\footnote{le definizioni esatte si
- possono trovare in \file{<bits/waitstatus.h} ma questo file non deve mai
- essere usato direttamente, esso viene incluso attraverso
+Entrambe le funzioni di attesa restituiscono lo stato di terminazione del
+processo tramite il puntatore \var{status} (se non interessa memorizzare lo
+stato si può passare un puntatore nullo). Il valore restituito da entrambe le
+funzioni dipende dall'implementazione, e tradizionalmente alcuni bit sono
+riservati per memorizzare lo stato di uscita (in genere 8) altri per indicare
+il segnale che ha causato la terminazione (in caso di conclusione anomala),
+uno per indicare se è stato generato un core file, ecc\footnote{le
+ definizioni esatte si possono trovare in \file{<bits/waitstatus.h} ma questo
+ file non deve mai essere usato direttamente, esso viene incluso attraverso
\file{<sys/wait.h>}}. Lo standard POSIX.1 definisce una serie di macro di
preprocessore da usare per analizzare lo stato di uscita; esse sono definite
sempre in \file{<sys/wait.h>} ed elencate in \curtab\ (si tenga presente che
Si tenga conto che nel caso di conclusione anomala il valore restituito da
\macro{WTERMSIG} può essere controllato contro le costanti definite in
-\file{signal.h}, e stampato usando le funzioni definite in
-\secref{sec:sig_strsignal}.
+\file{signal.h} ed elencate in \tabref{tab:sig_signal_list}, e stampato usando
+le apposite funzioni trattate in \secref{sec:sig_strsignal}.
\subsection{Le funzioni \func{wait3} e \func{wait4}}
Linux, seguendo una estensione di BSD, supporta altre due funzioni per la
lettura dello stato di terminazione di un processo, analoghe a \func{wait} e
\func{waitpid}, ma che prevedono un ulteriore parametro attraverso il quale il
-kernel può restituire al processo padre ulteriori informazioni sulle risorse
-usate dal processo terminato e dai vari figli. Queste funzioni, che diventano
-accessibili definendo la costante \macro{\_USE\_BSD}, sono:
+kernel può restituire al padre informazioni sulle risorse usate dal processo
+terminato e dai vari figli. Queste funzioni, che diventano accessibili
+definendo la costante \macro{\_USE\_BSD}, sono:
\begin{functions}
\headdecl{sys/times.h}
\headdecl{sys/types.h}
\label{sec:proc_exec}
Abbiamo già detto che una delle modalità principali con cui si utilizzano i
-processi in unix è quella di usarli per lanciare nuovi programmi: questo viene
+processi in Unix è quella di usarli per lanciare nuovi programmi: questo viene
fatto attraverso una delle funzioni della famiglia \func{exec}. Quando un
processo chiama una di queste funzioni esso viene completamente sostituito dal
nuovo programma; il \acr{pid} del processo non cambia, dato che non viene
-creato un nuovo processo, la funzione semplicemente rimpiazza lo stack, o
+creato un nuovo processo, la funzione semplicemente rimpiazza lo stack, lo
heap, i dati ed il testo del processo corrente con un nuovo programma letto da
disco.
Ci sono sei diverse versioni di \func{exec} (per questo la si è chiamata
-famiglia di funzioni) che possono essere usate per questo compito, che in
-realtà (come mostrato in \figref{fig:proc_exec_relat}), costituiscono un
-front-end a \func{execve}. Il prototipo di quest'ultima è:
+famiglia di funzioni) che possono essere usate per questo compito, in realtà
+(come mostrato in \figref{fig:proc_exec_relat}), sono tutte un front-end a
+\func{execve}. Il prototipo di quest'ultima è:
\begin{prototype}{unistd.h}
{int execve(const char *filename, char *const argv[], char *const envp[])}
Esegue il programma contenuto nel file \param{filename}.
argomenti a linea di comando (cioè i valori di \var{argv} e \var{argc} visti
dalla funzione \func{main} del programma chiamato).
-Queste modalità sono due e sono riassunte dagli mnenonici \code{v} e \code{l}
+Queste modalità sono due e sono riassunte dagli mnemonici \code{v} e \code{l}
che stanno rispettivamente per \textit{vector} e \textit{list}. Nel primo caso
gli argomenti sono passati tramite il vettore di puntatori \var{argv[]} a
stringhe terminate con zero che costituiranno gli argomenti a riga di comando,
Nel secondo caso le stringhe degli argomenti sono passate alla funzione come
lista di puntatori, nella forma:
\begin{lstlisting}[labelstep=0,frame=,indent=1cm]{}
- char * arg0, char * arg1, ..., char * argn, NULL
+ char *arg0, char *arg1, ..., char *argn, NULL
\end{lstlisting}
che deve essere terminata da un puntatore nullo. In entrambi i casi vale la
convenzione che il primo argomento (\var{arg0} o \var{argv[0]}) viene usato
\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.
+\item il tempo restante ad un allarme (vedi \secref{sec:sig_xxx}).
\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
\secref{sec:file_locking}).
\item i segnali sospesi (\textit{pending}) e la maschera dei segnali (si veda
\secref{sec:sig_xxx}).
-\item i limiti sulle risorse (vedi \secref{sec:sys_limits})..
+\item i limiti sulle risorse (vedi \secref{sec:sys_limits}).
\item i valori delle variabili \var{tms\_utime}, \var{tms\_stime},
\var{tms\_cutime}, \var{tms\_ustime} (vedi \secref{sec:xxx_xxx}).
\end{itemize*}
Per le directory lo standard POSIX.1 richiede che esse vengano chiuse
attraverso una \func{exec}, in genere questo è fatto dalla funzione
-\func{opendir} che effettua da sola il settaggio del flag di
-\textit{close-on-exec} sulle directory che apre, in maniera trasparente
-all'utente.
+\func{opendir} (vedi \secref{sec:file_dir_read}) che effettua da sola il
+settaggio del flag di \textit{close-on-exec} sulle directory che apre, in
+maniera trasparente all'utente.
Abbiamo detto che il \textit{real user ID} ed il \textit{real group ID}
restano gli stessi all'esecuzione di \func{exec}; lo stesso vale per
filename}.
Con la famiglia delle \func{exec} si chiude il novero delle funzioni su cui è
-basata la gestione dei processi in unix: con \func{fork} si crea un nuovo
+basata la gestione dei processi in Unix: con \func{fork} si crea un nuovo
processo, con \func{exec} si avvia un nuovo programma, con \func{exit} e
\func{wait} si effettua e verifica la conclusione dei programmi. Tutte le
altre funzioni sono ausiliarie e servono la lettura e il settaggio dei vari
accesso dal punto di vista del processi; vedremo quali sono gli identificatori
usati, come questi possono essere modificati nella creazione e nel lancio di
nuovi processi, e le varie funzioni per la loro manipolazione diretta e tutte
-le problematiche connesse alla gestione accorta dei privilegi.
+le problematiche connesse ad una gestione accorta dei privilegi.
\subsection{Utente e gruppo di un processo}
Dato che tutte le operazioni del sistema vengono compiute dai processi, è
evidente che per poter implementare un controllo sulle operazioni occorre
-anche poter identificare chi è che ha lanciato un certo processo, e pertanto
-anche a ciascuno di essi è associato un utente e a un gruppo.
+anche poter identificare chi è che ha lanciato un certo programma, e pertanto
+anche a ciascun processo è associato un utente e a un gruppo.
Un semplice controllo di una corrispondenza fra identificativi però non
garantisce però sufficiente flessibilità per tutti quei casi in cui è
necessario poter disporre di privilegi diversi, o dover impersonare un altro
utente per un limitato insieme di operazioni. Per questo motivo in generale
-tutti gli unix prevedono che i processi abbiano almeno due gruppi di
+tutti gli Unix prevedono che i processi abbiano almeno due gruppi di
identificatori, chiamati rispettivamente \textit{real} ed \textit{effective}.
\begin{table}[htb]
dettaglio in \secref{sec:file_perm_overview}).
Questi identificatori normalmente sono identici ai corrispondenti del gruppo
-\textsl{reale} tranne nel caso in cui, come visto in \secref{sec:proc_exec},
-il programma che si è posto in esecuzione abbia i bit \acr{suid} o \acr{sgid}
-settati (il significato di questi bit è affrontato in dettaglio in
-\secref{sec:file_suid_sgid}). In questo caso essi saranno settati all'utente e
-al gruppo proprietari del file; questo consente, per programmi in cui ci sia
-necessità, di dare a qualunque utente normale privilegi o permessi di
-un'altro (o dell'amministratore).
+\textsl{reale} tranne nel caso in cui, come accennato in
+\secref{sec:proc_exec}, il programma che si è posto in esecuzione abbia i bit
+\acr{suid} o \acr{sgid} settati (il significato di questi bit è affrontato in
+dettaglio in \secref{sec:file_suid_sgid}). In questo caso essi saranno settati
+all'utente e al gruppo proprietari del file; questo consente, per programmi in
+cui ci sia necessità, di dare a qualunque utente normale privilegi o permessi
+di un'altro (o dell'amministratore).
Come nel caso del \acr{pid} e del \acr{ppid} tutti questi identificatori
possono essere letti dal processo attraverso delle opportune funzioni, i cui
\textit{saved} ed il \textit{filesystem}, analoghi ai precedenti. Il primo
gruppo è lo stesso usato in SVr4, e previsto dallo standard POSIX quando è
definita la costante \macro{\_POSIX\_SAVED\_IDS}\footnote{in caso si abbia a
- cuore la portabilità del programma su altri unix è buona norma controllare
+ cuore la portabilità del programma su altri Unix è buona norma controllare
sempre la disponibilità di queste funzioni controllando se questa costante è
definita}, il secondo gruppo è specifico di Linux e viene usato per
migliorare la sicurezza con NFS.
Le due funzioni che vengono usate per cambiare identità (cioè utente e gruppo
di appartenenza) ad un processo sono rispettivamente \func{setuid} e
\func{setgid}; come accennato in \secref{sec:proc_user_group} in Linux esse
-seguono la semantica POSIX che prevede l'esistenza di \textit{saved user id} e
-\textit{saved group id}; i loro prototipi sono:
+seguono la semantica POSIX che prevede l'esistenza del \textit{saved user id}
+e del \textit{saved group id}; i loro prototipi sono:
\begin{functions}
\headdecl{unistd.h}
\headdecl{sys/types.h}
-\funcdecl{int setuid(uid\_t uid)} Setta l'\textit{user ID} del processo
+\funcdecl{int setuid(uid\_t uid)} Setta l'\textit{user id} del processo
corrente.
-\funcdecl{int setgid(gid\_t gid)} Setta il \textit{group ID} del processo
+\funcdecl{int setgid(gid\_t gid)} Setta il \textit{group id} del processo
corrente.
\bodydesc{Le funzioni restituiscono 0 in caso di successo e -1 in caso
\subsection{Le funzioni \func{setreuid} e \func{setresuid}}
\label{sec:proc_setreuid}
-Queste due funzioni derivano da BSD che non supportando\footnote{almeno fino
- alla versione 4.3+BSD TODO, verificare e aggiornare la nota} i \textit{saved
- id} le usava per poter scambiare fra di loro effective e real id. I
-prototipi sono:
+Queste due funzioni derivano da BSD che, non supportando\footnote{almeno fino
+ alla versione 4.3+BSD TODO, verificare e aggiornare la nota.} i
+\textit{saved id}, le usava per poter scambiare fra di loro \textit{effective}
+e \textit{real id}. I loro prototipi sono:
\begin{functions}
\headdecl{unistd.h}
\headdecl{sys/types.h}
effettuare uno scambio e riottenere privilegi non previsti.
Lo stesso problema di propagazione dei privilegi ad eventuali processi figli
-si porrebbe per i \textit{saved id}. Queste funzioni derivano da
+si porrebbe per i \textit{saved id}: queste funzioni derivano da
un'implementazione che non ne prevede la presenza, e quindi non è possibile
-usarle per correggere la situazione come nel caso precedente, per questo
-motivo tutte le volte che uno degli identificatori viene modificato ad un
-valore diverso dal precedente \textit{real id}, il \textit{saved id} viene
-sempre settato al valore dell'\textit{effective id}.
+usarle per correggere la situazione come nel caso precedente. Per questo
+motivo in Linux tutte le volte che vengono usata per modificare uno degli
+identificatori ad un valore diverso dal \textit{real id} precedente, il
+\textit{saved id} viene sempre settato al valore dell'\textit{effective id}.
\subsection{Le funzioni \func{setresuid} e \func{setresgid}}
\label{sec:proc_seteuid}
Queste funzioni sono un'estensione allo standard POSIX.1 (ma sono comunque
-supportate dalla maggior parte degli unix) e usate per cambiare gli
+supportate dalla maggior parte degli Unix) e usate per cambiare gli
\textit{effective id}; i loro prototipi sono:
\begin{functions}
\headdecl{unistd.h}
espone alla ricezione di eventuali segnali ostili da parte dell'utente di cui
ha temporaneamente assunto l'identità. Cambiando solo il \textit{filesystem
id} si ottengono i privilegi necessari per accedere ai file, mantenendo
-quelli originari per quanto riguarda tutti gli altri controlli di accesso.
+quelli originari per quanto riguarda tutti gli altri controlli di accesso,
+così che l'utente non possa inviare segnali al server NFS.
Le due funzioni usate per cambiare questi identificatori sono \func{setfsuid}
e \func{setfsgid}, ovviamente sono specifiche di Linux e non devono essere
\bodydesc{Le funzioni restituiscono 0 in caso di successo e -1 in caso
di fallimento: l'unico errore possibile è \macro{EPERM}.}
\end{functions}
-
-Queste funzioni hanno successo solo se il processo chiamante ha i privilegi di
-amministratore o, per gli altri utenti, se il valore specificato coincide con
-uno dei \textit{real}, \textit{effective} o \textit{saved id}.
+\noindent queste funzioni hanno successo solo se il processo chiamante ha i
+privilegi di amministratore o, per gli altri utenti, se il valore specificato
+coincide con uno dei \textit{real}, \textit{effective} o \textit{saved id}.
\section{Problematiche di programmazione multitasking}
stesso processo, e pure alcune system call, possono essere interrotti in
qualunque momento, e le operazioni di un eventuale \textit{signal handler}
sono compiute nello stesso spazio di indirizzi del processo. Per questo anche
-solo il solo accesso o l'assegnazione di una variabile possono non essere più
+il solo accesso o l'assegnazione di una variabile possono non essere più
operazioni atomiche (torneremo su questi aspetti in \secref{sec:sign_xxx}).
In questo caso il sistema provvede un tipo di dato, il \type{sig\_atomic\_t},