Aggiunte mknod e mkfifo, e fatta una passata di ispell
authorSimone Piccardi <piccardi@gnulinux.it>
Wed, 26 Dec 2001 22:36:13 +0000 (22:36 +0000)
committerSimone Piccardi <piccardi@gnulinux.it>
Wed, 26 Dec 2001 22:36:13 +0000 (22:36 +0000)
Makefile
filedir.tex
fileintro.tex
filestd.tex
fileunix.tex
ipc.tex
process.tex
prochand.tex
socket.tex
system.tex

index 6c01a04..af51df5 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -16,5 +16,5 @@ install:
        scp -r gapil*  piccardi@firenze.linux.it:public_html
 
 clean: 
-       rm -f *.dvi *.log *.ps *.html *.aux *.toc *.rel 
+       rm -f *.dvi *.log *.ps *.html *.aux *.toc *.rel *~
 
index b09d760..df14491 100644 (file)
@@ -514,59 +514,73 @@ un caso a parte, che vedremo in \secref{cha:socket_intro}).
 
 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}.
 
 
 
@@ -582,7 +596,7 @@ processi devono creare i file usando le apposite funzioni.
 
 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
@@ -651,47 +665,61 @@ funzione 
 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.
 
 
 
@@ -1449,7 +1477,7 @@ bit \acr{sgid} settato allora viene usata la seconda opzione.
 
 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
index 47e002c..cf0e674 100644 (file)
@@ -66,7 +66,7 @@ alcune strutture interne del kernel) sono generati automaticamente dal kernel
 stesso, ma anche essi devono essere montati all'interno dell'albero.
 
 All'interno dello stesso albero si potranno poi inserire anche gli altri
-oggetti visti attraverso l'interfaccia che manipola i file come le FIFO, i
+oggetti visti attraverso l'interfaccia che manipola i file come le fifo, i
 link, i socket e gli stessi i file di dispositivo (questi ultimi, per
 convenzione, sono inseriti nella directory \file{/dev}).
 
@@ -215,12 +215,12 @@ del C, si accede ad essi sempre in maniera indiretta utilizzando il tipo
 \type{FILE *}.  L'interfaccia è definita nell'header \type{stdio.h}.
 
 Entrambe le interfacce possono essere usate per l'accesso ai file come agli
-altri oggetti del VFS (pipe, socket, device), ma per poter accedere alle
-operazioni di controllo sul particolare tipo di oggetto del VFS scelto occorre
-usare l'interfaccia standard di unix coi file descriptor. Allo stesso modo
-devono essere usati i file descriptor se si vuole ricorrere a modalità
-speciali di I/O come il polling o il non-bloccante (vedi
-\secref{sec:file_noblocking}).
+altri oggetti del VFS (pipe, socket, device, sui quali torneremo in dettaglio
+a tempo opportuno), ma per poter accedere alle operazioni di controllo sul
+particolare tipo di oggetto del VFS scelto occorre usare l'interfaccia
+standard di unix coi file descriptor. Allo stesso modo devono essere usati i
+file descriptor se si vuole ricorrere a modalità speciali di I/O come il
+polling o il non-bloccante (vedi \secref{sec:file_noblocking}).
 
 Gli stream forniscono un'interfaccia di alto livello costruita sopra quella
 dei file descriptor, che tratta tutti i file nello stesso modo, con
index 1c5c288..0070226 100644 (file)
@@ -304,13 +304,12 @@ valore \verb|STRING| 
 e \func{fopen} marca il file per l'uso dei caratteri estesi e abilita le
 opportune funzioni di conversione in lettura e scrittura.
 
-Inoltre nel caso si usi \func{fdopen} i valori specificati da
-\param{mode} devono essere compatibili con quelli con cui il file
-descriptor è stato aperto. Inoltre i modi \cmd{w} e \cmd{w+} non
-troncano il file. La posizione nello stream viene settata a quella
-corrente nel file descriptor, e le variabili di errore e di fine del
-file (vedi \secref{sec:file_io}) sono cancellate. Il file non viene
-duplicato e verrà chiuso alla chiusura dello stream.
+Nel caso si usi \func{fdopen} i valori specificati da \param{mode} devono
+essere compatibili con quelli con cui il file descriptor è stato aperto.
+Inoltre i modi \cmd{w} e \cmd{w+} non troncano il file. La posizione nello
+stream viene settata a quella corrente nel file descriptor, e le variabili di
+errore e di fine del file (vedi \secref{sec:file_io}) sono cancellate. Il file
+non viene duplicato e verrà chiuso alla chiusura dello stream.
 
 I nuovi file saranno creati secondo quanto visto in
 \secref{sec:file_ownership} ed avranno i permessi di accesso settati al
@@ -355,9 +354,9 @@ dati presenti nei buffer in user space usati dalle \acr{glibc}; se si vuole
 essere sicuri che il kernel forzi la scrittura su disco occorrerà effettuare
 una \func{sync} (vedi \secref{sec:file_sync}).
 
-Linux supporta, come estensione implementata dalle \acr{glibc}, anche una
-altra funzione, \func{fcloseall}, che serve a chiudere tutti i file, il suo
-prototipo è:
+Linux supporta anche una altra funzione, \func{fcloseall}, come estensione GNU
+implementata dalle \acr{glibc}, accessibile avendo definito
+\macro{\_GNU\_SOURCE}, il suo prototipo è:
 \begin{prototype}{stdio.h}{int fcloseall(void)}
   Chiude tutti gli stream. 
   
@@ -489,10 +488,10 @@ si avr
 struct histogram {
     int nbins; 
     double max, min;
-    double * bin;
+    double *bin;
 } histo; 
 
-int WriteStruct(FILE * stream, struct histogram * histo, size_t nelem) 
+int WriteStruct(FILE *stream, struct histogram *histo, size_t nelem) 
 {
     if ( fwrite(vec, sizeof(*histo), 1, stream) !=1) {
         perror("Write error");
@@ -546,10 +545,9 @@ rileggere i dati tenendo conto delle eventuali differenze.
 Le \acr{glibc} definiscono altre due funzioni per l'I/O binario, che
 evitano il lock implicito dello stream, usato per dalla librerie per la
 gestione delle applicazioni multi-thread (si veda
-\secref{sec:file_stream_thread} per i dettagli).
-
+\secref{sec:file_stream_thread} per i dettagli):
 \begin{functions}
-  \headdecl{stdio.h} 
+  \headdecl{stdio.h}
   
   \funcdecl{size\_t fread\_unlocked(void *ptr, size\_t size, size\_t
     nmemb, FILE *stream)}
@@ -589,14 +587,14 @@ rispettivi prototipi sono:
 
 A parte \func{getchar}, che si usa in genere per leggere un carattere da
 tastiera, le altre due funzioni sono sostanzialmente equivalenti. La
-differenza è che \func{gets} è ottimizzata al massimo e normalmente
+differenza è che \func{getc} è ottimizzata al massimo e normalmente
 viene implementata con una macro, per cui occorre stare attenti a cosa
 le si passa come argomento, infatti \param{stream} può essere valutato
 più volte nell'esecuzione, e non viene passato in copia con il
 meccanismo visto in \secref{sec:proc_var_passing}; per questo motivo se
 si passa una espressione si possono avere effetti indesiderati.
 
-Invece \func{fgets} è assicurata essere sempre una funzione, per questo
+Invece \func{fgetc} è assicurata essere sempre una funzione, per questo
 motivo la sua esecuzione normalmente è più lenta per via dell'overhead
 della chiamata, ma è altresì possibile ricavarne l'indirizzo, che può
 essere passato come parametro ad un altra funzione (e non si hanno i
@@ -745,13 +743,13 @@ prototipi sono:
     di successo o \macro{NULL} in caso di errore.}
 \end{functions}
 
-Entrambe le funzioni effettuano la lettura (dal file specificato
-\func{fgets}, dallo standard input \func{gets}) di una linea di
-caratteri (terminata dal carattere \textit{newline}, \verb|\n|), ma
-\func{gets} sostituisce \verb|\n| con uno zero, mentre \func{fgets}
-aggiunge uno zero dopo il \textit{newline}, che resta dentro la
-stringa. Se la lettura incontra la fine del file (o c'è un errore) viene
-restituito un \macro{NULL}, ed il buffer \param{buf} non viene toccato.
+Entrambe le funzioni effettuano la lettura (dal file specificato \func{fgets},
+dallo standard input \func{gets}) di una linea di caratteri (terminata dal
+carattere \textit{newline}, \verb|\n|, quello mappato sul tasto di ritorno a
+capo della tastiera), ma \func{gets} sostituisce \verb|\n| con uno zero,
+mentre \func{fgets} aggiunge uno zero dopo il \textit{newline}, che resta
+dentro la stringa. Se la lettura incontra la fine del file (o c'è un errore)
+viene restituito un \macro{NULL}, ed il buffer \param{buf} non viene toccato.
 
 L'uso di \func{gets} è deprecato e deve essere assolutamente evitato; la
 funzione infatti non controlla il numero di byte letti, per cui nel caso
@@ -794,13 +792,13 @@ rispettivi prototipi sono:
     successo o \macro{EOF} in caso di errore.}
 \end{functions}
 
-Dato che in questo caso si scrivono i dati in uscita \func{puts} non ha
-i problemi di \func{gets} ed è in genere la forma più immediata per
-scrivere messaggi sullo standard output; la funzione prende una stringa
-terminata da uno zero ed aggiunge automaticamente un newline. La
-differenza con \func{fputs} (a parte la possibilità di specificare un
-file diverso da \var{stdout}) è che quest'ultima non aggiunge il
-newline, che deve essere previsto esplicitamente. 
+Dato che in questo caso si scrivono i dati in uscita \func{puts} non ha i
+problemi di \func{gets} ed è in genere la forma più immediata per scrivere
+messaggi sullo standard output; la funzione prende una stringa terminata da
+uno zero ed aggiunge automaticamente il ritorno a capo. La differenza con
+\func{fputs} (a parte la possibilità di specificare un file diverso da
+\var{stdout}) è che quest'ultima non aggiunge il newline, che deve essere
+previsto esplicitamente.
 
 Come per le funzioni di input/output a caratteri esistono le estensioni
 per leggere e scrivere caratteri estesi, i loro prototipi sono:
@@ -1298,7 +1296,8 @@ argomenti di tipo \type{off\_t} anzich
 
 In questa sezione esamineremo alcune funzioni avanzate che permettono di
 eseguire operazioni particolari sugli stream, come leggerne gli attributi,
-controllarne le modalità di bufferizzazione, ecc.
+controllarne le modalità di bufferizzazione, gestire direttamente i lock
+impliciti per la programmazione multi thread.
 
 
 \subsection{Le funzioni di controllo}
@@ -1410,8 +1409,8 @@ bufferizzata i valori di \param{buf} e \param{size} vengono ignorati.
       \hline
     \end{tabular}
   \label{tab:file_stream_buf_mode}
-  \caption{Valori possibili per il parametro \param{mode} di \func{setvbuf} 
-    nel settaggio delle modalità di bufferizzazione.}
+  \caption{Valori del parametro \param{mode} di \func{setvbuf} 
+    per il settaggio delle modalità di bufferizzazione.}
 \end{table}
 
 Oltre a \func{setvbuf} le \acr{glibc} definiscono altre tre funzioni per la
index d321ee9..c3938d9 100644 (file)
@@ -925,8 +925,8 @@ effettuare una \func{close}, perdendo l'atomicit
 L'uso principale di queste funzioni è per la redirezione dell'input e
 dell'output fra l'esecuzione di una \func{fork} e la successiva \func{exec};
 diventa così possibile associare un file (o una pipe) allo standard input o
-allo standard output, torneremo su questo uso più avanti quando tratteremo le
-pipe.
+allo standard output, torneremo su questo uso in \secref{sec:ipc_pipes} quando
+tratteremo le pipe.
 
 
 \subsection{La funzione \func{fcntl}}
diff --git a/ipc.tex b/ipc.tex
index eecdb32..f3de1c8 100644 (file)
--- a/ipc.tex
+++ b/ipc.tex
@@ -6,27 +6,50 @@
 \label{sec:ipc_intro}
 
 Uno degli aspetti fondamentali della programmazione in unix è la comunicazione
-fra processi. In questo testo affronteremo solo alcuni dei meccanismi
-fondamentali che permettono di scrivere applicazioni, esistono pure sistemi
-più complessi ed evoluti come le RPC (\textit{Remote Procedure Calls})  e
-CORBA (\textit{Common Object Request Brocker Architecture}) non saranno
-affrontati qui. 
+fra processi. In questo capitolo affronteremo solo alcuni dei meccanismi più
+elementari che permettono di mettere in comunicazione processi diversi, come
+quelli tradizionali che coinvolgono \textit{pipe} e \textit{fifo} e i
+meccanismi di intercomunicazione di System V.
 
-\section{Le pipes standard}
+Esistono pure sistemi più complessi ed evoluti come le RPC (\textit{Remote
+  Procedure Calls}) e CORBA (\textit{Common Object Request Brocker
+  Architecture}) che non saranno affrontati qui.
+
+
+\section{La comunicazione fra processi tradizionale}
+\label{sec:ipc_unix}
+
+Il primo meccanismo di comunicazione fra processi usato dai sistemi unix-like
+è quello delle \textit{pipe}, in questa sezione descriveremo le sue basi, le
+funzioni che ne gestiscono l'uso e le varie forme in cui si è evoluto.
+
+
+\subsection{Le \textit{pipe} standard}
 \label{sec:ipc_pipes}
 
-\section{Le pipes con nome}
-\label{sec:ipc_nampipe}
 
-\section{System V IPC}
+
+\subsection{Le \textit{pipe} con nome, o \textit{fifo}}
+\label{sec:ipc_named_pipe}
+
+
+
+
+\section{La comunicazione fra processi di System V}
 \label{sec:ipc_sysv}
 
-\section{Code di messaggi}
+Per ovviare ad i vari limiti dei meccanismo tradizionale di comunicazione fra
+processi basato sulle \textit{pipe}, nello sviluppo di System V vennero
+introdotti una serie di nuovi oggetti che garantissero una maggiore
+flessibilità; in questa sezione esamineremo quello che viene ormai chiamato il
+sistema \textit{SystemV IPC}.
+
+\subsection{Code di messaggi}
 \label{sec:ipc_messque}
 
-\section{Semafori}
+\subsection{Semafori}
 \label{sec:ipc_semaph}
 
-\section{Memoria condivisa}
+\subsection{Memoria condivisa}
 \label{sec:ipc_shar_mem}
 
index 0d7a5dc..24935da 100644 (file)
@@ -64,7 +64,7 @@ se si vogliono scrivere programmi portabili 
 \label{sec:proc_conclusion}
 
 Normalmente un programma finisce è quando la funzione \func{main} ritorna, una
-modalità equivalente di concludere il programma è quella di chiamare
+modalità equivalente di chiudere il programma è quella di chiamare
 direttamente la funzione \func{exit} (che viene comunque chiamata
 automaticamente quando \func{main} ritorna).  Una forma alternativa è quella
 di chiamare direttamente la system call \func{\_exit}, che restituisce il
@@ -77,8 +77,8 @@ torneremo su questo in \secref{sec:proc_termination}.
 
 Il valore di ritorno della funzione \func{main}, o quello usato nelle chiamate
 ad \func{exit} e \func{\_exit}, viene chiamato \textsl{stato di uscita} (o
-\textit{exit status}) e passato al processo padre che aveva lanciato il
-programma (in genere la shell). In generale si usa questo valore per fornire
+\textit{exit status}) e passato al processo che aveva lanciato il programma
+(in genere la shell). In generale si usa questo valore per fornire
 informazioni sulla riuscita o il fallimento del programma; l'informazione è
 necessariamente generica, ed il valore deve essere compreso fra 0 e 255.
 
index e632e24..adf67a3 100644 (file)
@@ -118,19 +118,19 @@ alla cui base c'
 \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
@@ -163,11 +163,12 @@ non ritorna mai (in quanto con essa viene eseguito un altro programma).
 \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}
@@ -176,7 +177,7 @@ programmi.
 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
@@ -216,12 +217,13 @@ o relativi allo stesso login. Torneremo su questo argomento in dettaglio in
 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}}
@@ -259,24 +261,21 @@ padre, ma la memoria 
   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
@@ -333,9 +332,7 @@ int main(int argc, char *argv[])
 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
@@ -352,13 +349,14 @@ parleremo in \secref{sec:proc_exec}) subito dopo la \func{fork}.
 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
@@ -427,14 +425,15 @@ Pertanto non si pu
 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
@@ -475,20 +474,22 @@ Il comportamento delle varie funzioni di interfaccia con i file 
 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
@@ -503,62 +504,66 @@ lo stesso avviene anche per tutti i figli; la funzione \func{fork} infatti ha
 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:
@@ -594,7 +599,7 @@ venne introdotta in BSD per migliorare le prestazioni.
 
 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.
 
 
@@ -602,7 +607,7 @@ 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.
@@ -626,11 +631,12 @@ comunque una serie di operazioni: chiude tutti i file aperti, rilascia la
 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}).
@@ -642,16 +648,16 @@ eseguite alla chiusura di un processo 
 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
@@ -708,15 +714,15 @@ informazioni riguardo ai processi che sta terminando.
 
 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
@@ -781,7 +787,7 @@ prototipo 
 \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. 
@@ -795,9 +801,9 @@ caso di errore; \var{errno} pu
 }
 \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
@@ -816,11 +822,11 @@ Per questo motivo lo standard POSIX.1 ha introdotto la funzione \func{waitpid}
 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
@@ -927,15 +933,15 @@ certezza che la chiamata a \func{wait} non si bloccher
   \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
@@ -944,8 +950,8 @@ da \var{status}).
 
 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}}
@@ -954,9 +960,9 @@ Si tenga conto che nel caso di conclusione anomala il valore restituito da
 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} 
@@ -1019,18 +1025,18 @@ campi che sono mantenuti sono: \var{ru\_utime}, \var{ru\_stime},
 \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}.
@@ -1094,7 +1100,7 @@ le modalit
 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,
@@ -1103,7 +1109,7 @@ questo vettore \emph{deve} essere terminato da un puntatore nullo.
 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
@@ -1179,7 +1185,7 @@ la lista completa 
 \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
@@ -1187,7 +1193,7 @@ la lista completa 
   \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*}
@@ -1208,9 +1214,9 @@ esplicita a \func{fcntl} che setti il suddetto flag.
 
 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
@@ -1234,7 +1240,7 @@ chiamato come se si fosse eseguito il comando \cmd{interpreter [arg]
   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
@@ -1249,7 +1255,7 @@ In questa sezione esamineremo le problematiche relative al controllo di
 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}
@@ -1279,14 +1285,14 @@ kernel nella gestione dei permessi di accesso.
 
 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]
@@ -1341,13 +1347,13 @@ processo e per il controllo di accesso ai file (argomento affrontato in
 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
@@ -1381,7 +1387,7 @@ Questo in Linux viene fatto usando altri due gruppi di identificatori, il
 \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.
@@ -1416,16 +1422,16 @@ di utente e gruppo associati dal kernel ad ogni processo, 
 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
@@ -1513,10 +1519,10 @@ ricorrere ad altre funzioni (si veda ad esempio \secref{sec:proc_seteuid}).
 \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}
@@ -1557,12 +1563,12 @@ prima della \func{exec} per uniformare i \textit{real id} agli
 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}}
@@ -1601,7 +1607,7 @@ l'identificatore corrispondente.
 \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}
@@ -1643,7 +1649,8 @@ fatto cambiando l'\textit{effective id} o il \textit{real id} il server si
 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
@@ -1660,10 +1667,9 @@ processo corrente a \var{fsgid}.
 \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}
@@ -1715,7 +1721,7 @@ Nel caso dei segnali invece la situazione 
 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},
index f38305a..a563c35 100644 (file)
@@ -331,8 +331,9 @@ definiti; la struttura 
   \centering
   \begin{tabular}{|l|l|l|}
     \hline
-    \multicolumn{1}{|c|}{Tipo}& \multicolumn{1}{|c|}{Descrizione}& 
-    \multicolumn{1}{|c|}{Header} \\
+    \multicolumn{1}{|c|}{\textbf{Tipo}}& 
+    \multicolumn{1}{|c|}{\textbf{Descrizione}}& 
+    \multicolumn{1}{|c|}{\textbf{Header}} \\
     \hline
     \hline
     \type{int8\_t}   & intero a 8 bit con segno   & \file{sys/types.h}\\
index a1aa32f..d82687e 100644 (file)
@@ -2,24 +2,40 @@
 \label{cha:system}
 
 In questo capitolo si è raccolta le trattazione delle varie funzioni
-concernenti la gestione generale del sistema che permettono di trattare
-le varie informazioni ad esso connesse, come i limiti sulle risorse, la
-gestione dei tempi, degli errori, degli utenti ed in generale dei vari
-parametri di configurazione del sistema.
+concernenti la gestione generale del sistema che permettono di trattare le
+varie informazioni ad esso connesse, i limiti sulle risorse, la gestione dei
+tempi, degli errori e degli utenti ed in generale la gestione dei vari
+parametri di configurazione dei vari componenti del sistema.
 
 
+\section{La gestione della configurazione del sistema}
+\label{sec:sys_config}
+
+
+\subsection{Opzioni e configurazione del systema}
+\label{sec:sys_sys_config}
+
+La funzione \func{sysconf} ...
+
+\subsection{La configurazione dei file}
+\label{sec:sys_file_config}
+
+La funzione \func{statfs} ...
+
+La funzione \func{pathconf} ...
 
 
 \section{La gestione delle risorse e dei limiti di sistema}
 \label{sec:sys_limits}
 
-In questa sezione esamimeremo le funzioni che permettono di gestire le
-varie risorse associate ad un processo ed i relativi limiti, e quelle
-relatica al sistema in quanto tale. 
-
+In questa sezione esamimeremo le funzioni che permettono di gestire le varie
+risorse associate ad un processo ed i relativi limiti, e quelle relatica al
+sistema in quanto tale.
 
 \var{tms\_utime}, \var{tms\_stime}, \var{tms\_cutime}, \var{tms\_uetime}
 
+
+
 \section{La gestione dei tempi del sistema}
 \label{sec:sys_time}
 
@@ -234,3 +250,8 @@ o la macro (\texttt{\small 15--17}) associate a quel codice.
   \caption{Codice per la stampa del messaggio di errore standard.}
   \label{fig:sys_err_mess}
 \end{figure}
+
+
+\section{La gestione di utenti e gruppi}
+\label{sec:sys_user_group}
+