X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=process.tex;h=776a025b828df11dafd3c84e230b14092cea7fcf;hp=dafdef803099fa791a30d9c35055588980bbc376;hb=429f6e0da8fc282eb6611b6fe83fdf58ae8da611;hpb=ffde006b4b38517dd190c394b769c619d13174a5 diff --git a/process.tex b/process.tex index dafdef8..776a025 100644 --- a/process.tex +++ b/process.tex @@ -9,7 +9,7 @@ richiedere servizi al sistema, su cosa deve fare quando ha finito la sua esecuzione. In genere un programma viene eseguito quando un processo lo fa partire -eseguendo una funzione della famiglia \texttt{exec}; torneremo su questo e +eseguendo una funzione della famiglia \func{exec}; torneremo su questo e sulla la creazione e gestione dei processi nel prossimo capitolo, in questo affronteremo l'avvio e il funzionamento di un singolo processo partendo dal punto di vista del programma posto in esecuzione. @@ -32,25 +32,25 @@ posto in esecuzione esso apparir discorso dei \textit{thread} comunque in Linux necessita di una trattazione a parte per la peculiarità dell'implementazione). -\section{La funzione \texttt{main}} +\subsection{La funzione \func{main}} \label{sec:proc_main} Quando un programma viene lanciato il kernel esegue una opportuna routine di -avvio, usando il programma \texttt{ld-linux.so}, è questo programma che prima +avvio, usando il programma \cmd{ld-linux.so}, è questo programma che prima carica le librerie condivise che servono al programma, effettua il link dinamico del codice e poi alla fine lo esegue. Infatti, a meno di non aver specificato il flag \texttt{-static} durante la compilazione, tutti i programmi in Linux sono incompleti e necessitano di essere linkati alle librerie condivise quando vengono avviati. La procedura è controllata da -alcune variabili di ambiente e dal contenuto di \texttt{/etc/ld.so.conf}, i -dettagli sono riportati nella man page di \texttt{ld.so}. +alcune variabili di ambiente e dal contenuto di \file{/etc/ld.so.conf}, i +dettagli sono riportati nella man page di \cmd{ld.so}. -Il sistema fa partire qualunque programma chiamando la funzione \texttt{main}; +Il sistema fa partire qualunque programma chiamando la funzione \func{main}; sta al programmatore chiamare così la funzione principale del programma da cui si suppone iniziale l'esecuzione; in ogni caso senza questa funzione lo stesso linker darebbe luogo ad errori. -Lo standard ISO C specifica che la funzione \texttt{main} può non avere +Lo standard ISO C specifica che la funzione \func{main} può non avere argomenti o prendere due argomenti che rappresentano gli argomenti passati da linea di comando, in sostanza un prototipo che va sempre bene è il seguente: \begin{lstlisting}[labelstep=0,frame=,indent=1cm]{} @@ -58,7 +58,7 @@ linea di comando, in sostanza un prototipo che va sempre bene \end{lstlisting} In realtà nei sistemi unix esiste un'altro modo per definire la funzione -\texttt{main}, che prevede la presenza di un terzo parametro, \texttt{char +\func{main}, che prevede la presenza di un terzo parametro, \var{char *envp[]}, che fornisce l'\textsl{ambiente} (vedi \secref{sec:proc_environ}) del programma; questa forma però non è prevista dallo standard POSIX.1 per cui se si vogliono scrivere programmi portabili è meglio evitarla. @@ -67,20 +67,20 @@ se si vogliono scrivere programmi portabili \subsection{Come chiudere un programma} \label{sec:proc_termination} -La via normale per la quale un programma finisce è quando la funzione main -ritorna, una modalità equivalente di conclusione è quella di chiamare -direttamente la funzione \texttt{exit} (che viene comunque chiamata dalla -routine di avvio del programma quando la funzione main ritorna). Una forma -alternativa è quella di chiamare direttamente la system call \texttt{\_exit} -che passa il controllo direttamente al kernel. +La via normale per la quale un programma finisce è quando la funzione +\func{main} ritorna, una modalità equivalente di conclusione è quella di +chiamare direttamente la funzione \func{exit} (che viene comunque chiamata +dalla routine di avvio del programma quando la funzione \func{main} ritorna). +Una forma alternativa è quella di chiamare direttamente la system call +\func{\_exit} che passa il controllo direttamente al kernel. Oltre alla conclusione ``normale'' esiste anche la possibilità di una conclusione ``anomala'' del programma a causa di segnali o della chiamata alla -funzione \texttt{abort} (che comunque genera un segnale che termina il +funzione \func{abort} (che comunque genera un segnale che termina il programma); torneremo su questo in \secref{sec:sig_prog_error}. Il valore di ritorno della funzione main, o quello usato nelle chiamate ad -\texttt{exit} e \texttt{\_exit}, viene chiamato \textit{exit status} e passato +\func{exit} e \func{\_exit}, viene chiamato \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 un'informazione generica sulla riuscita o il fallimento del programma; l'informazione è necessariamente @@ -88,11 +88,11 @@ generica, ed il valore deve essere compreso fra 0 e 255. In generale si usa la convenzione di restituire 0 in caso di successo e 1 in caso di fallimento, i programmi che effettuano dei confronti (come -\texttt{diff}) usano invece una notazione leggermente diversa, usando 0 per +\cmd{diff}) usano invece una notazione leggermente diversa, usando 0 per indicare la corrispondenza, 1 per indicare la non corrispondenza e 2 per indicare l'incapacità di effettuare il confronto. È opportuno adottare una di queste convenzioni a seconda dei casi. Si tenga presente che se si raggiunge -la fine della funzione \texttt{main} senza ritornare esplicitamente si ha un +la fine della funzione \func{main} senza ritornare esplicitamente si ha un valore di uscita indefinito, è pertanto consigliabile di concludere sempre in maniera esplicita detta funzione. @@ -102,13 +102,13 @@ programma in un sottoprocesso. Bench universalmente seguita è una buona idea tenerne conto. Si tenga presente inoltre che non è una buona idea usare il valore dell'errore -restituito dalla variabile \texttt{errno} come stato di uscita, in generale +restituito dalla variabile \var{errno} come stato di uscita, in generale una shell non si cura di tutto questo e comunque il valore dello stato di uscita è sempre troncato ad 8 bit, per cui si potrebbe incorrere nel caso in cui l'errore 256, diventando zero, verrebbe interpretato come un successo. In -\texttt{stdlib.h} sono definite due macro \texttt{EXIT\_SUCCESS} e -\texttt{EXIT\_FAILURE}, che in Linux sono poste rispettivamente ai valori 0 e -1 (di tipo \texttt{int}), seguendo lo standard POSIX. +\file{stdlib.h} sono definite due macro \macro{EXIT\_SUCCESS} e +\macro{EXIT\_FAILURE}, che in Linux sono poste rispettivamente ai valori 0 e +1 (di tipo \type{int}), seguendo lo standard POSIX. Infine occorre distinguere fra lo stato di uscita di un programma (l'\textit{exit status}) e lo stato di conclusione di un processo (il @@ -119,51 +119,51 @@ programma per processo (vedi \secref{sec:proc_xxx}). -\subsection{Le funzioni \texttt{exit} e \texttt{\_exit}} +\subsection{Le funzioni \func{exit} e \func{\_exit}} \label{sec:proc_exit} Come accennato funzioni per l'uscita ``normale'' da un programma sono due, la -prima è la funzione \texttt{exit} che è definita dallo standard ANSI C; il +prima è la funzione \func{exit} che è definita dallo standard ANSI C; il prototipo della funzione è il seguente: \begin{prototype}{stdlib.h}{void exit(int status)} Causa la conclusione ordinaria del programma restituendo il valore - \texttt{status} al processo padre. + \var{status} al processo padre. La funzione non ritorna. Il processo viene terminato \end{prototype} -La funzione \texttt{exit} è pensata per una conclusione pulita di un programma +La funzione \func{exit} è pensata per una conclusione pulita di un programma che usa le librerie standard del C; essa esegue tutte le funzioni che sono -state registrate con \texttt{atexit} e \texttt{on\_exit} (vedi +state registrate con \func{atexit} e \func{on\_exit} (vedi \secref{sec:proc_atexit}), e chiude tutti gli stream di I/O effettuando il -salvataggio dei dati sospesi (chiamando \texttt{fclose}, vedi +salvataggio dei dati sospesi (chiamando \func{fclose}, vedi \secref{sec:file_fclose}), infine ripassa il controllo al kernel chiamando -\texttt{\_exit} e passando il valore \texttt{status} come stato di uscita. +\func{\_exit} e passando il valore \var{status} come stato di uscita. -La system call \texttt{\_exit} restituisce direttamente il controllo al +La system call \func{\_exit} restituisce direttamente il controllo al kernel, concludendo immediatamente il processo, le eventuali funzioni -registrate con \texttt{atexit} e \texttt{on\_exit} non vengono eseguite. Il +registrate con \func{atexit} e \func{on\_exit} non vengono eseguite. Il prototipo della funzione è il seguente: \begin{prototype}{unistd.h}{void \_exit(int status)} Causa la conclusione immediata del programma restituendo il valore - \texttt{status} al processo padre. + \var{status} al processo padre. La funzione non ritorna. Il processo viene terminato. \end{prototype} La funzione chiude tutti i file descriptor appartenenti al processo (sui tenga presente che questo non comporta il salvataggio dei dati bufferizzati degli -stream), fa si che ogni figlio del processo sia ereditato da \texttt{init} -(vedi \secref{cha:process_handling}), manda un segnale \texttt{SIGCHLD} al +stream), fa si che ogni figlio del processo sia ereditato da \cmd{init} +(vedi \secref{cha:process_handling}), manda un segnale \macro{SIGCHLD} al processo padre (vedi \ref{sec:sig_job_control}) ed infine ritorna lo stato di -uscita specificato in \texttt{status} che può essere raccolto usando la -funzione \texttt{wait} (vedi \secref{sec:proc_wait}). +uscita specificato in \var{status} che può essere raccolto usando la +funzione \func{wait} (vedi \secref{sec:proc_wait}). -\subsection{Le funzioni \texttt{atexit} e \texttt{on\_exit}} +\subsection{Le funzioni \func{atexit} e \func{on\_exit}} \label{sec:proc_atexit} -Come accennato l'uso di \texttt{exit} al posto della \texttt{\_exit} è fatto +Come accennato l'uso di \func{exit} al posto della \func{\_exit} è fatto principalmente per permettere una uscita pulita dalle funzioni delle librerie standard del C (in particolare per quel che riguarda la chiusura degli stream). @@ -177,10 +177,10 @@ di una funzione che effettui tali operazioni all'uscita dal programma. A questo scopo lo standard ANSI C prevede la possibilità di registrare un certo numero funzioni che verranno eseguite all'uscita dal programma (sia per -la chiamata ad \textit{exit} che per il ritorno di \texttt{main}). La prima +la chiamata ad \func{exit} che per il ritorno di \func{main}). La prima funzione che si può utilizzare a tal fine è: \begin{prototype}{stdlib.h}{void atexit(void (*function)(void))} - Registra la funzione \texttt{function} per essere chiamata all'uscita dal + Registra la funzione \var{function} per essere chiamata all'uscita dal programma. La funzione restituisce 0 in caso di successo e -1 in caso di fallimento, @@ -189,28 +189,28 @@ funzione che si pu La funzione richiede come argomento l'indirizzo della opportuna da chiamare all'uscita che non deve prendere argomenti e non deve ritornare niente. Una -estensione di \texttt{atexit} è la funzione \texttt{on\_exit} (che la glibc +estensione di \func{atexit} è la funzione \func{on\_exit} (che la glibc include per compatibilità con SunOS e che non è detto sia definita su altri sistemi), il cui prototipo è: \begin{prototype}{stdlib.h} {void on\_exit(void (*function)(int status, void *arg), void *arg)} - Registra la funzione \texttt{function} per essere chiamata all'uscita dal + Registra la funzione \var{function} per essere chiamata all'uscita dal programma. Tutte le funzioni registrate vengono chiamate in ordine inverso rispetto a quello di registrazione. La funzione restituisce 0 in caso di successo e -1 in caso di fallimento, - \texttt{errno} non viene settata. + \var{errno} non viene settata. \end{prototype} In questo caso la funzione da chiamare prende due parametri, il primo dei quali sarà inizializzato allo stato di uscita con cui è stata chiamata -\texttt{exit} ed il secondo al puntatore generico specificato come secondo -argomento nella chiamata di \texttt{on\_exit}. +\func{exit} ed il secondo al puntatore generico specificato come secondo +argomento nella chiamata di \func{on\_exit}. Nella sequenza di chiusura tutte le funzioni registrate verranno chiamate in ordine inverso rispetto a quello di registrazione (ed una stessa funzione registrata più volte sarà chiamata più volte); poi verranno chiusi tutti gli -stream aperti, infine verrà chiamata \texttt{\_exit}. +stream aperti, infine verrà chiamata \func{\_exit}. \subsection{Conclusioni} @@ -218,14 +218,14 @@ stream aperti, infine verr Data l'importanza dell'argomento è opportuno sottolineare ancora una volta che in un sistema unix l'unico modo in cui un programma può essere eseguito dal -kernel è attraverso la chiamata alla system call \texttt{execve} (in genere -attraverso una delle funzioni \texttt{exec} che vedremo in +kernel è attraverso la chiamata alla system call \func{execve} (in genere +attraverso una delle funzioni \func{exec} che vedremo in \secref{sec:proc_exec}). Allo stesso modo l'unico modo in cui un programma può concludere volontariamente la sua esecuzione è attraverso una chiamata alla system call -\texttt{\_exit} sia esplicitamente o che in maniera indiretta attraverso l'uso -di \texttt{exit} o il ritorno della funzione \texttt{main}. +\func{\_exit} sia esplicitamente o che in maniera indiretta attraverso l'uso +di \func{exit} o il ritorno della funzione \func{main}. Lo schema delle modalità con cui si avvia e conclude normalmente un programma è riportato in \nfig. @@ -279,7 +279,7 @@ spazio disco riservato alla swap, o i file che contengono il codice). Lo stesso pezzo di memoria reale (o di spazio disco) può fare da supporto a diverse pagine di memoria virtuale appartenenti a processi diversi (come accade in genere per le pagine che contengono il codice delle librerie -condivise). Ad esempio il codice della funzione \texttt{printf} starà su una +condivise). Ad esempio il codice della funzione \func{printf} starà su una sola pagina di memoria reale che farà da supporto a tutte le pagine di memoria virtuale di tutti i processi hanno detta funzione nel loro codice. @@ -322,7 +322,7 @@ commette quando si chiamato un \textit{segmentation fault}. Se si tenta cioè di leggere o scrivere da un indirizzo per il quale non esiste una associazione della pagina virtuale il kernel risponde al relativo \textit{page fault}, mandando un -segnale \texttt{SIGSEGV} al processo, che normalmente ne causa la terminazione +segnale \macro{SIGSEGV} al processo, che normalmente ne causa la terminazione immediata. È pertanto importante capire come viene strutturata la memoria virtuale di un @@ -337,7 +337,7 @@ programma C viene suddiviso nei seguenti segmenti: utilizzarlo, e viene marcato in sola lettura per evitare sovrascritture accidentali (o maliziose) che ne modifichino le istruzioni. - Viene allocato da \texttt{exec} all'avvio del programma e resta invariato + Viene allocato da \func{exec} all'avvio del programma e resta invariato per tutto il tempo dell'esecuzione. \item Il segmento dei dati (\textit{data segment}). Contiene le variabili @@ -351,7 +351,7 @@ programma C viene suddiviso nei seguenti segmenti: double pi = 3.14; \end{lstlisting} questo valore sarà immagazzinato in questo segmento. La memoria di questo - segmento viene preallocato dalla \texttt{exec} e inizializzata ai valori + segmento viene preallocato dalla \func{exec} e inizializzata ai valori specificati. La seconda parte è il segmento dei dati non inizializzati, che contiene le @@ -362,7 +362,7 @@ programma C viene suddiviso nei seguenti segmenti: \end{lstlisting} questo valore sarà immagazzinato in questo segmento. Anch'esso viene allocato all'avvio, e tutte le variabili vengono inizializzate a - zero (ed i puntatori a \texttt{NULL}). + zero (ed i puntatori a \macro{NULL}). Storicamente questo segmento viene chiamato BBS (da \textit{block started by symbol}. La sua dimensione è fissa. @@ -394,7 +394,7 @@ programma C viene suddiviso nei seguenti segmenti: \end{figure} Una disposizione tipica di questi segmenti è riportata in \nfig. Usando il -comando \texttt{size} su un programma se ne può stampare le dimensioni dei +comando \cmd{size} su un programma se ne può stampare le dimensioni dei segmenti di testo e di dati (inizializzati e BSS); il BSS però non è mai salvato sul file, in quanto viene inizializzato a zero al caricamento del programma. @@ -407,7 +407,7 @@ Il C supporta due tipi di allocazione della memoria, l'allocazione statica quella in cui vanno le variabili globali e le variabili statiche (e viene effettuata nel segmento dei dati), lo spazio per queste variabili viene allocati all'avvio del programma (come parte delle operazioni svolte da -\texttt{exec}) e non viene liberato fino alla sua conclusione. +\func{exec}) e non viene liberato fino alla sua conclusione. L'allocazione automatica è quella che avviene per le cosiddette variabili automatiche, cioè gli argomenti delle funzioni o le variabili locali. Lo @@ -425,12 +425,12 @@ cio possano essere modificate durante l'esecuzione del programma; però le librerie del C forniscono una serie opportuna di funzioni per permettere l'allocazione dinamica di spazio in memoria (in genere nello heap, usando la system call -\texttt{sbrk}), solo che a questo punto detto spazio sarà accessibile solo in +\func{sbrk}), solo che a questo punto detto spazio sarà accessibile solo in maniera indiretta attraverso dei puntatori. -\subsection{Le funzioni \texttt{malloc}, \texttt{calloc}, \texttt{realloc} e - \texttt{free}} +\subsection{Le funzioni \func{malloc}, \func{calloc}, \func{realloc} e + \func{free}} \label{sec:proc_mem_malloc} Le funzioni previste dallo standard ANSI C per la gestione della memoria sono @@ -438,26 +438,26 @@ quattro, i prototipi sono i seguenti: \begin{functions} \headdecl{stdlib.h} \funcdecl{void *calloc(size\_t size)} - Alloca \texttt{size} bytes nello heap. La memoria viene inizializzata a 0. + Alloca \var{size} bytes nello heap. La memoria viene inizializzata a 0. La funzione restituisce il puntatore alla zona di memoria allocata in caso - di successo e \texttt{NULL} in caso di fallimento, nel qual caso - \texttt{errno} viene settata a \texttt{ENOMEM}. + di successo e \macro{NULL} in caso di fallimento, nel qual caso + \var{errno} viene settata a \macro{ENOMEM}. \funcdecl{void *malloc(size\_t size)} - Alloca \texttt{size} bytes nello heap. La memoria non viene inizializzata. + Alloca \var{size} bytes nello heap. La memoria non viene inizializzata. La funzione restituisce il puntatore alla zona di memoria allocata in caso - di successo e \texttt{NULL} in caso di fallimento, nel qual caso - \texttt{errno} viene settata a \texttt{ENOMEM}. + di successo e \macro{NULL} in caso di fallimento, nel qual caso + \var{errno} viene settata a \macro{ENOMEM}. \funcdecl{void *realloc(void *ptr, size\_t size)} - Cambia la dimensione del blocco allocato all'indirizzo \texttt{ptr} - portandola a \texttt{size}. + Cambia la dimensione del blocco allocato all'indirizzo \var{ptr} + portandola a \var{size}. La funzione restituisce il puntatore alla zona di memoria allocata in caso - di successo e \texttt{NULL} in caso di fallimento, nel qual caso - \texttt{errno} viene settata a \texttt{ENOMEM}. + di successo e \macro{NULL} in caso di fallimento, nel qual caso + \var{errno} viene settata a \macro{ENOMEM}. \funcdecl{void free(void *ptr)} - Disalloca lo spazio di memoria puntato da \texttt{ptr}. + Disalloca lo spazio di memoria puntato da \var{ptr}. La funzione non ritorna nulla. \end{functions} @@ -466,29 +466,29 @@ sempre correttamente allineato per tutti i tipi di dati; ad esempio sulle macchine a 32 bit in genere è allineato a multipli di 4 byte e sulle macchine a 64 bit a multipli di 8 byte. -In genere su usano le funzioni \texttt{malloc} e \texttt{calloc} per allocare +In genere su usano le funzioni \func{malloc} e \func{calloc} per allocare dinamicamente la memoria necessaria al programma, siccome i puntatori ritornati sono di tipo generico non è necessario effettuare un cast per assegnarli a puntatori al tipo di variabile per la quale si effettua la allocazione. La memoria allocata dinamicamente deve essere esplicitamente rilasciata usando -\texttt{free}\footnote{le glibc provvedono anche una funzione \texttt{cfree} +\func{free}\footnote{le glibc provvedono anche una funzione \func{cfree} defininita per compatibilità con SunOS, che è deprecata} una volta che non sia più necessaria. Questa funzione vuole come parametro un puntatore restituito da una precedente chiamata a una qualunque delle funzioni di allocazione e che non sia già stato liberato da un'altra chiamata a -\texttt{free}, in caso contrario il comportamento della funzione è indefinito. +\func{free}, in caso contrario il comportamento della funzione è indefinito. -La funzione \texttt{realloc} si usa invece per cambiare (in genere aumentare) +La funzione \func{realloc} si usa invece per cambiare (in genere aumentare) la dimensione di un'area di memoria precedentemente allocata, la funzione vuole in ingresso il puntatore restituito dalla precedente chiamata ad una -\texttt{malloc} (se è passato un valore \texttt{NULL} allora la funzione si -comporta come \texttt{malloc}\footnote{questo è vero per linux e +\func{malloc} (se è passato un valore \macro{NULL} allora la funzione si +comporta come \func{malloc}\footnote{questo è vero per linux e l'implementazione secondo lo standard ANSI C, ma non è vero per alcune vecchie implementazioni, inoltre alcune versioni delle librerie del C - consentivano di usare \texttt{realloc} anche per un puntatore liberato con - \texttt{free} purché non ci fossero state altre chiamate a funzioni di + consentivano di usare \func{realloc} anche per un puntatore liberato con + \func{free} purché non ci fossero state altre chiamate a funzioni di allocazione, questa funzionalità è totalmente deprecata e non è consentita sotto linux}), ad esempio quando si deve far crescere la dimensione di un vettore; in questo caso se è disponibile dello spazio adiacente al precedente @@ -503,20 +503,26 @@ essere altri puntatori che puntino all'interno di un'area che si vuole ridimensionare. Uno degli errori più comuni (specie se si ha a che fare con array di -puntatori) è infatti quello di chiamare \texttt{free} più di una volta sullo +puntatori) è infatti quello di chiamare \func{free} più di una volta sullo stesso puntatore; per evitare questo problema una soluzione di ripiego è -quella di assegnare sempre a \texttt{NULL} ogni puntatore liberato con -\texttt{free}, dato che, quando il parametro è un puntatore nullo, -\texttt{free} non esegue nessuna operazione. +quella di assegnare sempre a \macro{NULL} ogni puntatore liberato con +\func{free}, dato che, quando il parametro è un puntatore nullo, +\func{free} non esegue nessuna operazione. Linux e le glibc hanno una implementazione delle routine di allocazione che è controllabile dall'utente attraverso alcune variabili di ambiente, in particolare diventa possibile tracciare questo tipo di errori usando la -variabile \texttt{MALLOC\_CHECK\_} che quando viene settata mette in uso una +variabile \macro{MALLOC\_CHECK\_} che quando viene settata mette in uso una versione meno efficiente delle funzioni, che però è più tollerante nei -confronti di piccoli errori come quello di chiamate doppie a \texttt{free}; in -particolare se la variabile è posta a zero gli errori vengono ignorati, se è -posta ad 1 viene stampato un avviso sullo standard error e se +confronti di piccoli errori come quello di chiamate doppie a \func{free}; in +particolare: +\begin{itemize} +\item se la variabile è posta a zero gli errori vengono ignorati. +\item se è posta ad 1 viene stampato un avviso sullo \textit{standard error} + (vedi \secref{sec:file_stdfiles}). +\item se è posta a 2 viene chiamata \func{abort}, che in genere causa + l'immediata conclusione del programma. +\end{itemize} Il problema più comune e più difficile da tracciare che si incontra con l'allocazione della memoria è però quando la memoria non più utilizzata non @@ -698,7 +704,7 @@ annidate occorre usare la funzione \func{longjump}. Il passaggio dei parametri e delle variabili di ambiente dalla riga di comando al singolo programma quando viene lanciato è effettuato attraverso le -variabili \texttt{argc}, \texttt{argv} che vengono passate al programma +variabili \var{argc}, \var{argv} che vengono passate al programma come argomenti della funzione principale. \subsection{Il formato dei parametri} @@ -710,9 +716,9 @@ ciascuna delle quali viene considerata un parametro; di default per individuare le parole viene usato come separatore lo spazio (comportamento modificabile attraverso il settaggio della variabile di ambiente IFS). -Nella scansione viene costruito il vettore di puntatori \texttt{argv} inserendo +Nella scansione viene costruito il vettore di puntatori \var{argv} inserendo in successione il puntatore alla stringa costituente l'$n$-simo parametro; la -variabile \texttt{argc} viene inizializzata al numero di parametri trovati, in +variabile \var{argc} viene inizializzata al numero di parametri trovati, in questo modo il primo parametro è sempre il nome del programma (vedi \nfig). \subsection{La gestione delle opzioni} @@ -720,7 +726,7 @@ questo modo il primo parametro In generale un programma unix riceve da linea di comando sia i parametri che le opzioni, queste ultime sono standardizzate per essere riconosciute come -tali: un elemento di \texttt{argv} che inizia con \texttt{-} e che non sia un +tali: un elemento di \var{argv} che inizia con \texttt{-} e che non sia un singolo \texttt{-} o \texttt{--} viene considerato un'opzione. In in genere le opzioni sono costituite da una lettera preceduta dal meno e possono avere o no un parametro associato; un comando tipico può essere cioè qualcosa del @@ -730,20 +736,26 @@ touch -r riferimento.txt -m questofile.txt \end{verbatim} ed in questo caso le opzioni sono \texttt{m} ed \texttt{r}. -Per gestire le opzioni all'interno dei parametri passati in \texttt{argv} le -librerie standard del C forniscono la funzione \texttt{getopt} (accessibile -includendo \texttt{unistd.h}), che ha il prototipo: -\begin{verbatim} -int getopt(int argc, char * const argv[], const char * optstring); -\end{verbatim} +Per gestire le opzioni all'interno dei parametri passati in \func{argv} le +librerie standard del C forniscono la funzione \func{getopt} che ha il +prototipo: +\begin{prototype}{unistd.h} +{int getopt(int argc, char * const argv[], const char * optstring)} +La funzione esegue il parsing degli argomenti passati da linea di comando +riconoscendo le possibili opzioni segnalate con \var{optstring}. + +Ritorna il carattere che segue l'opzione, \cmd{:} se manca un paramatro +all'opzione, \cmd{?} se l'opzione è sconosciuta, e -1 se non esistono altre +opzioni. +\end{prototype} -Questa funzione prende come argomenti le due variabili \texttt{argc} e -\texttt{argv} ed una stringa che indica quali sono le opzioni valide; la +Questa funzione prende come argomenti le due variabili \var{argc} e +\var{argv} ed una stringa che indica quali sono le opzioni valide; la funzione effettua la scansione della lista dei parametri ricercando ogni -stringa che comincia con \texttt{-} e ritorna ogni volta che trova una opzione +stringa che comincia con \cmd{-} e ritorna ogni volta che trova una opzione valida. -La stringa \texttt{optstring} indica quali sono le opzioni riconosciute ed è +La stringa \var{optstring} indica quali sono le opzioni riconosciute ed è costituita da tutti i caratteri usati per identificare le singole opzioni, se l'opzione ha un parametro al carattere deve essere fatto seguire un segno di due punti \texttt{:} nel caso appena accennato ad esempio la stringa di @@ -755,7 +767,8 @@ all'interno di un ciclo di while fintanto che essa non ritorna il valore un'opzione non dichiarata in \texttt{optstring} viene ritornato un \texttt{?} mentre se l'opzione non è seguita da un parametro viene ritornato un \texttt{:} infine se viene incontrato il valore \texttt{--} la scansione viene -considerata conclusa. +considerata conclusa, anche se vi sono altri parametri che cominciano con +\texttt{-}. Quando la funzione trova un'opzione essa ritorna il valore numerico del carattere, in questo modo si possono prendere le azioni relative usando un @@ -770,8 +783,7 @@ case; la funzione inizializza inoltre alcune variabili globali: \item \texttt{int optopt} contiene il carattere dell'opzione non riconosciuta. \end{itemize} -In \nfig\ è mostrato un programma di esempio, - +In \nfig\ è mostrato un programma di esempio: \begin{figure}[htbp] \footnotesize \begin{lstlisting}{} @@ -823,8 +835,9 @@ In \nfig\ Un'estensione di questo schema è costituito dalle cosiddette \textit{long-options} espresse nella forma \texttt{--option=parameter}, anche la gestione di queste ultime è stata standardizzata attraverso l'uso di una -versione estesa di \texttt{getopt}. +versione estesa di \func{getopt}. +(NdA: da finire). \subsection{Le variabili di ambiente} \label{sec:proc_environ} @@ -878,4 +891,3 @@ comuni), come riportato in \ntab. GNU/Linux le supporta tutte e ne definisce anche altre per una lista parziale si può controllare \cmd{man environ} -