Aggiunte sezioni su problemi generici di programmazione, finita setfsuid
[gapil.git] / process.tex
index d04887348cd5cfd1770351f8511da3071a9b6d39..d3fa51d41ca3f9f6e280dd3d4056a61af62507eb 100644 (file)
@@ -6,7 +6,8 @@ sistema unix alloca ed utilizza le risorse.  Questo capitolo tratter
 l'interfaccia base fra il sistema e i processi, su come vengono passati i
 parametri, come viene gestita e allocata la memoria, su come un processo può
 richiedere servizi al sistema, su cosa deve fare quando ha finito la sua
-esecuzione.
+esecuzione. Nella sezione finale acceneremo ad alcune problematiche generiche
+di programmazione.
 
 In genere un programma viene eseguito quando un processo lo fa partire
 eseguendo una funzione della famiglia \func{exec}; torneremo su questo e
@@ -591,32 +592,32 @@ puntatore ad una di queste variabili, che sar
 all'uscita della funzione, con gli stessi problemi appena citati per
 \func{alloca}.
 
-\subsection{Le funzioni \texttt{brk} e \texttt{sbrk}}  
+\subsection{Le funzioni \func{brk} e \func{sbrk}}  
 \label{sec:proc_mem_sbrk}
 
 L'uso di queste funzioni è necessario solo quando si voglia accedere alle
 analoghe system call a cui fanno da interfaccia (ad esempio per implementare
-una propria versione di \texttt{malloc}. Le  funzione sono:
+una propria versione di \func{malloc}. Le  funzione sono:
 \begin{prototype}{unistd.h}{int *brk(void end\_data\_segment)}
   Sposta la fine del segmento dei dati all'indirizzo specificato da
-  \texttt{end\_data\_segment}.
+  \var{end\_data\_segment}.
   
   La funzione restituisce 0 in caso di successo e -1 in caso di fallimento,
-  nel qual caso \texttt{errno} viene settata a \texttt{ENOMEM}.
+  nel qual caso \var{errno} viene settata a \macro{ENOMEM}.
 \end{prototype}
 \begin{prototype}{unistd.h}{int *sbrk(ptrdiff\_t increment)}
-  Incrementa lo spazio dati di un programma di \texttt{increment}. Un valore
+  Incrementa lo spazio dati di un programma di \var{increment}. Un valore
   zero restituisce l'attuale posizione della fine del segmento dati.
   
   La funzione restituisce il puntatore all'inizio della nuova 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}.
+  allocata in caso di successo e \macro{NULL} in caso di fallimento, nel qual
+  caso \macro{errno} viene settata a \macro{ENOMEM}.
 \end{prototype}
 
 Queste funzioni sono state deliberatamente escluse dallo standard POSIX.1 e
 per i programmi normali è opportuno usare le funzioni di allocazione standard
 descritte in precedenza, che sono costruite su di esse.  In genere si usa
-\texttt{sbrk} con un valore zero per ottenere l'attuale posizione della fine
+\func{sbrk} con un valore zero per ottenere l'attuale posizione della fine
 del segmento dati. 
 
 
@@ -670,33 +671,50 @@ bloccata allora esso viene escluso dal meccanismo della paginazione. I blocchi
 non si accumulano, se si blocca due volte la stessa pagina non è necessario
 sbloccarla due volte, una pagina o è bloccata o no.
 
-Il blocco di memoria persiste fintanto che il processo che lo detiene la
+Il \textit{memory lock} persiste fintanto che il processo che detiene la
 memoria bloccata non la sblocca. Chiaramente la terminazione del processo
 comporta anche la fine dell'uso della sua memoria virtuale, e quindi anche di
-tutti i blocchi di memoria.
-
-I memory lock non sono ereditati dai processi figli\footnote{ma siccome Linux
-  usa il copy on write gli indirizzi virtuali del figlio sono mantenuti sullo
-  stesso segmento di RAM del padre, quindi usufruiscono dei memory lock di
-  questo}. Siccome la presenza di memory lock ha un impatto sugli altri
-processi solo root ha la capacità di bloccare una pagina, ogni processo può
-però sbloccare le sue pagine. Il sistema pone dei limiti all'ammontare di
+tutti i \textit{memory lock}.
+
+I \textit{memory lock} non sono ereditati dai processi figli\footnote{ma
+  siccome Linux usa il copy on write gli indirizzi virtuali del figlio sono
+  mantenuti sullo stesso segmento di RAM del padre, quindi fintanto che un
+  figlio non scrive su un segmento, può usufruire dei memory lock del padre}.
+Siccome la presenza di \textit{memory lock} ha un impatto sugli altri processi
+solo l'amministratore ha la capacità di bloccare una pagina; ogni processo
+però può sbloccare le sue pagine. Il sistema pone dei limiti all'ammontare di
 memoria di un processo che può essere bloccata e al totale di memoria fisica
 che può dedicare a questo.
 
+Le funzioni per bloccare e sbloccare singole sezioni di memoria sono
+\func{mlock} e \func{munlock}; i loro prototipi sono:
 
-\section{Il controllo di flusso non locale}
-\label{sec:proc_longjmp}
+\begin{functions}
+\headdecl{stdlib.h}
+\funcdecl{void *calloc(size\_t size)}
+  Alloca \var{size} byte nello heap. La memoria viene inizializzata a 0.
+  
+  La funzione restituisce il puntatore alla zona di memoria allocata in caso
+  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 \var{size} byte nello heap. La memoria non viene inizializzata.
 
-Il controllo del flusso di un programma in genere viene effettuato con le
-varie istruzioni del linguaggio C, la più bistrattata delle quali è il
-\func{goto}, ampiamente deprecato in favore di costrutti più puliti; esiste
-però un caso in l'uso di questa istruzione porta all'implementazione più
-efficiente, quello dell'uscita in caso di errore.
+  La funzione restituisce il puntatore alla zona di memoria allocata in caso
+  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 \var{ptr}
+  portandola a \var{size}.
 
-Il C però non consente di effettuare un salto ad una label definita in
-un'altra funzione, per cui se l'errore avviene in funzioni profondamente
-annidate occorre usare la funzione \func{longjump}. 
+  La funzione restituisce il puntatore alla zona di memoria allocata in caso
+  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 \var{ptr}.
+
+  La funzione non ritorna nulla.
+\end{functions}
 
 
 
@@ -727,7 +745,7 @@ questo modo il primo parametro 
 \subsection{La gestione delle opzioni}
 \label{sec:proc_opt_handling}
 
-In generale un programma unix riceve da linea di comando sia i parametri che
+In generale un programma unix riceve da linea di comando sia gli argomenti che
 le opzioni, queste ultime sono standardizzate per essere riconosciute come
 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
@@ -739,89 +757,67 @@ 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 \func{argv} le
-librerie standard del C forniscono la funzione \func{getopt} che ha il
-prototipo:
+Per gestire le opzioni all'interno dei argomenti a linea di comando passati in
+\func{argv} le librerie standard del C forniscono la funzione \func{getopt}
+che ha il seguente 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 parametro
-all'opzione, \cmd{?} se l'opzione è sconosciuta, e -1 se non esistono altre
+Ritorna il carattere che segue l'opzione, \cmd{':'} se manca un parametro
+all'opzione, \cmd{'?'} se l'opzione è sconosciuta, e -1 se non esistono altre
 opzioni.
 \end{prototype}
 
-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 \cmd{-} e ritorna ogni volta che trova una opzione
-valida.
+Questa funzione prende come argomenti le due variabili \var{argc} e \var{argv}
+passate a \func{main} (vedi \secref{sec:proc_main}) ed una stringa che indica
+quali sono le opzioni valide; la funzione effettua la scansione della lista
+degli argomenti ricercando ogni stringa che comincia con \cmd{-} e ritorna ogni
+volta che trova una opzione valida.
 
 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
-opzioni sarebbe \texttt{"r:m"}.
-
-La modalità di uso è pertanto quella di chiamare più volte la funzione
-all'interno di un ciclo di while fintanto che essa non ritorna il valore
-\texttt{-1} che indica che non ci sono più opzioni. Nel caso si incontri
-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, anche se vi sono altri parametri che cominciano con
-\texttt{-}.
+due punti \var{':'}, nel caso appena accennato ad esempio la stringa di
+opzioni sarebbe \var{"r:m"}.
+
+La modalità di uso di \func{getopt} è pertanto quella di chiamare più volte la
+funzione all'interno di un ciclo fintanto che essa non ritorna il valore -1
+che indica che non ci sono più opzioni. Nel caso si incontri un'opzione non
+dichiarata in \var{optstring} viene ritornato il carattere \texttt{'?'}
+mentre se un opzione che lo richiede non è seguita da un parametro viene
+ritornato il carattere \texttt{':'}, infine se viene incontrato il valore
+\cmd{--} la scansione viene considerata conclusa, anche se vi sono altri
+elementi di \var{argv} che cominciano con il carattere \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
-case; la funzione inizializza inoltre alcune variabili globali:
-\begin{itemize*}
-\item \var{char * optarg} contiene il puntatore alla stringa argomento
-  dell'opzione.
-\item \var{int optind} alla fine della scansione restituisce l'indice del
-  primo argomento che non è un'opzione.
-\item \var{int opterr} previene, se posto a zero, la stampa di un messaggio
-  di errore in caso di riconoscimento di opzioni non definite.
-\item \var{int optopt} contiene il carattere dell'opzione non riconosciuta.
-\end{itemize*}
-
-In \nfig\ è mostrato un programma di esempio:
 \begin{figure}[htbp]
   \footnotesize
     \begin{lstlisting}{}
     opterr = 0;  /* don't want writing to stderr */
-    while ( (i = getopt(argc, argv, "o:a:i:hve")) != -1) {
+    while ( (i = getopt(argc, argv, "hp:c:e:")) != -1) {
         switch (i) {
-        case 'i':   /* input file */
-            in_file=open(optarg,O_RDONLY);
-            if (in_file<0) {
-                perror("Cannot open input file");
-                exit(1);
-            }
-            break;
-        case 'o':   /* output file (overwrite) */
-            out_file=open(optarg,O_WRONLY|O_CREAT);
-            if (out_file<0) {
-                perror("Cannot open output file");
-                exit(1);
-            }
+        /* 
+         * Handling options 
+         */ 
+        case 'h':   /* help option */
+            printf("Wrong -h option use\n");
+            usage();
+            return -1;
             break;
-        case 'a':   /* output file (append) */
-            out_file=open(optarg,O_WRONLY|O_CREAT|O_APPEND);
+        case 'c':   /* take wait time for childen */
+            wait_child = strtol(optarg, NULL, 10);    /* convert input */
             break;
-        case 'h':   /* print help usage */
-            usage();
+        case 'p':   /* take wait time for childen */
+            wait_parent = strtol(optarg, NULL, 10);   /* convert input */
             break;
-        case 'v':   /* set verbose mode */
-            debug("Option -v active\n");
-            verbose=1;
+        case 'e':   /* take wait before parent exit */
+            wait_end = strtol(optarg, NULL, 10);      /* convert input */
             break;
         case '?':   /* unrecognized options */
             printf("Unrecognized options -%c\n",optopt);
             usage();
         default:    /* should not reached */
-            debug("default option\n");
             usage();
         }
     }
@@ -831,13 +827,56 @@ In \nfig\ 
   \label{fig:proc_options_code}
 \end{figure}
 
+Quando la funzione trova un'opzione essa ritorna il valore numerico del
+carattere, in questo modo si possono prendere le azioni relative usando uno
+\func{switch}; la funzione inizializza inoltre alcune variabili globali:
+\begin{itemize*}
+\item \var{char * optarg} contiene il puntatore alla stringa parametro
+  dell'opzione.
+\item \var{int optind} alla fine della scansione restituisce l'indice del
+  primo elemento di \var{argv} che non è un'opzione.
+\item \var{int opterr} previene, se posto a zero, la stampa di un messaggio
+  di errore in caso di riconoscimento di opzioni non definite.
+\item \var{int optopt} contiene il carattere dell'opzione non riconosciuta.
+\end{itemize*}
+
+In \figref{fig:proc_options_code} è mostrata la sezione del programma
+\file{ForkTest.c} (che useremo nel prossimo capitolo per effettuare dei test
+sulla creazione dei processi) deputata alla decodifica delle opzioni a riga di
+comando. 
+
+Anzitutto si può notare che si è anzitutto (\texttt{\small 1}) disabilitata la
+stampa di messaggi di errore per opzioni non riconosciute, per poi passare al
+ciclo per la verifica delle opzioni (\texttt{\small 2-27}); per ciascuna delle
+opioni possibili si è poi provveduto ad una opportuna azione, ad esempio per
+le tre opzioni che prevedono un parametro si è effettuata la decodifica del
+medesimo, il cui indirizzo è contenuto nella variabile \var{optarg},
+avvalorando la relativa variabile (\texttt{\small 12-14}, \texttt{\small
+  15-17} e \texttt{\small 18-20}). Completato il ciclo troveremo in
+\var{optind} l'indice in \var{argv[]} del primo degli argomenti a linea di
+comando restanti.
+
+Normalmente \func{getopt} compie una permutazione degli elementi di \var{argv}
+così che alla fine della scansione gli elementi che non sono opzioni sono
+spostati in coda al vettore. Oltre a questa esistono altre due modalità di
+gestire gli elementi di \var{argv}; se \var{optstring} inizia con il carattere
+\texttt{'+'} (o è settata la variabile di ambiente \macro{POSIXLY\_CORRECT})
+la scansione viene fermata non appena si incontra un elemento che non è
+un'opzione. L'ultima modalità, usata quando un programma può gestire la
+mescolanza fra opzioni e argomenti, ma se li aspetta in un ordine definito, si
+attiva quando \var{optstring} inizia con il carattere \texttt{'-'}. In questo
+caso ogni elemento che non è un'opzione viene considerato comunque un'opzione
+e associato ad un valore di ritorno pari ad 1, questo permette di identificare
+gli elementi che non sono opzioni, ma non effettua il riordinamento del
+vettore \var{argv}.
+
 
 \subsection{Opzioni in formato esteso}
 \label{sec:proc_opt_extended}
 
 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
+\textit{long-options} espresse nella forma \cmd{--option=parameter}, anche la
+gestione di queste ultime è stata standardizzata attraverso l'uso di una
 versione estesa di \func{getopt}.
 
 (NdA: da finire).
@@ -846,16 +885,16 @@ versione estesa di \func{getopt}.
 \subsection{Le variabili di ambiente}
 \label{sec:proc_environ}
 
-Oltre ai parametri passati da linea di comando ogni processo riceve dal
+Oltre agli argomenti passati a linea di comando ogni processo riceve dal
 sistema un \textsl{ambiente}, nella forma di una lista di variabili
-(\textit{environment list}) messa a disposizione dal processo costruita nella
-chiamata ad \func{exec} che lo ha lanciato.
+(\textit{environment list}) messa a disposizione dal processo, e costruita
+nella chiamata alla funzione \func{exec} quando questo viene lanciato.
 
 Come per la lista dei parametri anche questa lista è un array di puntatori a
-caratteri, ciascuno dei quali punta ad una stringa (terminata da un NULL). A
-differenza di \var{argv[]} però in questo caso non si ha la lunghezza
-dell'array dato da un equivalente di \var{argc}, ma la lista è terminata da un
-puntatore nullo.
+caratteri, ciascuno dei quali punta ad una stringa (terminata da un
+\macro{NULL}). A differenza di \var{argv[]} però in questo caso non si ha una
+lunghezza dell'array data da un equivalente di \var{argc}, ma la lista è
+terminata da un puntatore nullo.
 
 L'indirizzo della lista delle variabili di ambiente è passato attraverso la
 variabile globale \var{environ}, a cui si può accedere attraverso una semplice
@@ -874,8 +913,9 @@ variabili che normalmente sono definite dal sistema, 
 
 Per convenzione le stringhe che definiscono l'ambiente sono tutte del tipo
 \textsl{\texttt{nome=valore}}. Inoltre alcune variabili, come quelle elencate
-in \curfig, sono definite dal sistema per queste c'è la convezione di usare
-nomi espressi in caratteri maiuscoli.
+in \curfig, sono definite dal sistema per essere usate da diversi programmi e
+funzioni: per queste c'è l'ulteriore convezione di usare nomi espressi in
+caratteri maiuscoli.
 
 Il kernel non usa mai queste variabili, il loro uso e la loro interpretazione è
 riservata alle applicazioni e ad alcune funzioni di libreria; in genere esse
@@ -892,11 +932,61 @@ l'editor preferito da invocare in caso di necessit
 
 Gli standard POSIX e XPG3 definiscono alcune di queste variabili (le più
 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}.
+anche altre: per una lista parziale si può controllare \cmd{man environ}.
+
+
+
 
+\section{Problematiche di programmazione generica}
+\label{sec:proc_gen_prog}
 
+Benché questo non sia un libro di C, è opportuno affrontare alcune delle
+problematiche generali che possono emergere nella programmazione e di quali
+precauzioni o accorgimenti occorre prendere per risolverle. Queste
+problematiche non sono specifiche di sistemi unix-like o multitasking, ma
+avendo trattato in questo capitolo il comportamento dei processi visti come
+entità a se stanti, le riportiamo qui.
 
 
+\subsection{Il passaggio delle variabili e dei valori di ritorno}
+\label{sec:proc_var_passing}
 
+Una delle caratteristiche standard del C è che le variabili vengono passate
+alle subroutine attraverso un meccanismo che viene chiamato \textit{by value}
+(diverso ad esempio da quanto avviene con il Fortran, dove le variabli sono
+passate, come suol dirsi, \textit{by reference}, o dal C++ dove la modalità del
+passaggio può essere controllata con l'operatore \cmd{\&}). 
+
+Il passaggio di una variabile \textit{by value} significa che in realtà quello
+che viene passato alla subroutine è una copia del valore attuale di quella
+variabile, copia che la subroutine potrà modificare a piacere, senza che il
+valore originale nella routine chiamante venga toccato. In questo modo non
+occorre preoccuparsi di eventuali effetti delle operazioni della subroutine.
+
+La maggior parte delle funzioni di libreria e delle system call funziona
+esattamente in questo modo restituendo eventuali risultati alla routine
+chiamante attraverso il valore di ritorno. Talvolta però è necessario che la
+funzione possa restituire indietro alla funzione chiamate un valore relativo
+ad uno dei sui parametri.
+
+
+
+
+\subsection{Potenziali problemi con le variabili automatiche}
+\label{sec:proc_auto_var}
+
+
+\subsection{Il controllo di flusso non locale}
+\label{sec:proc_longjmp}
+
+Il controllo del flusso di un programma in genere viene effettuato con le
+varie istruzioni del linguaggio C, la più bistrattata delle quali è il
+\func{goto}, ampiamente deprecato in favore di costrutti più puliti; esiste
+però un caso in l'uso di questa istruzione porta all'implementazione più
+efficiente, quello dell'uscita in caso di errore.
+
+Il C però non consente di effettuare un salto ad una label definita in
+un'altra funzione, per cui se l'errore avviene in funzioni profondamente
+annidate occorre usare la funzione \func{longjump}.