From f43b330570ece41d80aaca3c775eb4b7835aab28 Mon Sep 17 00:00:00 2001 From: Simone Piccardi Date: Wed, 26 Dec 2001 22:36:13 +0000 Subject: [PATCH] Aggiunte mknod e mkfifo, e fatta una passata di ispell --- Makefile | 2 +- filedir.tex | 162 +++++++++++++---------- fileintro.tex | 14 +- filestd.tex | 67 +++++----- fileunix.tex | 4 +- ipc.tex | 47 +++++-- process.tex | 6 +- prochand.tex | 356 +++++++++++++++++++++++++------------------------- socket.tex | 5 +- system.tex | 37 ++++-- 10 files changed, 389 insertions(+), 311 deletions(-) diff --git a/Makefile b/Makefile index 6c01a04..af51df5 100644 --- 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 *~ diff --git a/filedir.tex b/filedir.tex index b09d760..df14491 100644 --- a/filedir.tex +++ b/filedir.tex @@ -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 diff --git a/fileintro.tex b/fileintro.tex index 47e002c..cf0e674 100644 --- a/fileintro.tex +++ b/fileintro.tex @@ -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 diff --git a/filestd.tex b/filestd.tex index 1c5c288..0070226 100644 --- a/filestd.tex +++ b/filestd.tex @@ -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 diff --git a/fileunix.tex b/fileunix.tex index d321ee9..c3938d9 100644 --- a/fileunix.tex +++ b/fileunix.tex @@ -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 --- 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} diff --git a/process.tex b/process.tex index 0d7a5dc..24935da 100644 --- a/process.tex +++ b/process.tex @@ -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. diff --git a/prochand.tex b/prochand.tex index e632e24..adf67a3 100644 --- a/prochand.tex +++ b/prochand.tex @@ -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{}}. 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{} 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}, diff --git a/socket.tex b/socket.tex index f38305a..a563c35 100644 --- a/socket.tex +++ b/socket.tex @@ -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}\\ diff --git a/system.tex b/system.tex index a1aa32f..d82687e 100644 --- a/system.tex +++ b/system.tex @@ -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} + -- 2.30.2