\chapter{La gestione dei processi}
\label{cha:process_handling}

Come accennato nell'introduzione in un sistema unix ogni attività del sistema
viene svolta tramite i processi.  In sostanza i processi costituiscono l'unità
base per l'allocazione e l'uso delle risorse del sistema.

Nel precedente capitolo abbiamo visto come funziona un singolo processo, in
questo capitolo affronteremo i dettagli della creazione e della distruzione
dei processi, della gestione dei loro attributi e privilegi, e di tutte le
funzioni a questo connesse.


\section{Introduzione}
\label{sec:proc_gen}

Partiremo con una introduzione generale ai concetti che stanno alla base della
gestione dei processi in unix. Introdurremo in questa sezione l'architettura
della gestione dei processi e le sue principali caratteristiche, e daremo una
panoramica sull'uso delle principali funzioni per la gestione dei processi.

\subsection{La gerarchia dei processi}
\label{sec:proc_hierarchy}

A differenza di quanto avviene in altri sistemi (ad esempio nel VMS la
generazione di nuovi processi è un'operazione privilegiata) una delle
caratteristiche di unix (che esamineremo in dettaglio più avanti) è che
qualunque processo può a sua volta generarne altri, detti processi figli
(\textit{child process}). Ogni processo è identificato presso il sistema da un
numero unico, il \acr{pid} (da \textit{process identifier}).

Una seconda caratteristica è che la generazione di un processo è una
operazione separata rispetto al lancio di un programma. In genere la sequenza
è sempre quella di creare un nuovo processo, il quale si eseguirà, in un passo
successivo, il programma voluto: questo è ad esempio quello che fa la shell
quando mette in esecuzione il programma che gli indichiamo nella linea di
comando.

Una terza caratteristica è che ogni processo viene sempre generato da un altro
che viene chiamato processo genitore (\textit{parent process}). Questo vale
per tutti i processi, con una eccezione (dato che ci deve essere un punto di
partenza), esiste sempre infatti un processo speciale, che normalmente è
\cmd{/sbin/init}, che viene lanciato dal kernel quando questo ha finito la
fase di avvio, esso essendo il primo processo lanciato ha sempre il \acr{pid}
uguale a 1 e non è figlio di nessuno.

Questo è ovviamente un processo speciale, che in genere si occupa di far
partire tutti gli processi altri necessari al funzionamento del sistema,
inoltre \cmd{init} è essenziale per svolgere una serie di compiti
amministrativi nelle operazioni ordinarie del sistema (torneremo si alcuni di
essi in \secref{}) e non può mai essere terminato. La struttura del sistema
comunque consente di lanciare al posto di \cmd{init} qualunque altro programma
(e in casi di emergenza, ad esempio se il file di \cmd{init} si fosse
corrotto, è possibile farlo ad esempio passando la riga \cmd{init=/bin/sh}
all'avvio).

Dato che tutti i processi successivi sono comunque generati da \cmd{init} o da
suoi figli tutto ciò comporta che, i processi sono organizzati gerarchicamente
dalla relazione fra genitori e figli, in maniera analoga a come i file sono
organizzati in un albero di directory con alla base \file{/} (si veda
\secref{sec:file_file_struct}); in questo caso alla base dell'albero c'è il
processo \cmd{init} che è progenitore di ogni altro processo\footnote{in
  realtà questo non è del tutto vero, in Linux ci sono alcuni processi che pur
  comparendo come figli di init (ad esempio in \cmd{pstree}) sono generati
  direttamente dal kernel, come \cmd{keventd}, \cmd{kswapd}, etc.}.


\subsection{Una panoramica sulle funzioni di gestione}
\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}).

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}; queste funzioni
restituiscono anche una informazione abbastanza limitata (il codice di uscita)
sulle cause della terminazione del processo.

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
quanto discusso in \secref{sec:proc_termination}). La vita del processo però
termina solo quando la notifica della sua conclusione viene ricevuta dal
processo padre, a quel punto tutte le risorse allocate nel sistema ad esso
associate vengono rilasciate.

Avere due processi che eseguono esattamente lo stesso codice non è molto
utile, normalmente si genera un secondo processo per affidargli l'esecuzione
di un compito specifico (ad esempio gestire una connessione dopo che questa è
stata stabilita), o fargli eseguire (come fa la shell) un altro programma. Per
quest'ultimo caso si usa la seconda funzione fondamentale per programmazione
coi processi che è la \func{exec}.

Il programma che un processo sta eseguendo si chiama immagine del processo (o
\textit{process image}), le funzioni della famiglia \func{exec} permettono di
caricare un'altro programma da disco sostituendo quest'ultimo all'immagine
corrente; questo fa si che l'immagine precedente venga completamente
cancellata. Questo significa che quando il nuovo programma esce anche il
processo termina, e non si può tornare alla precedente immagine.

Per questo motivo la \func{fork} e la \func{exec} sono funzioni molto
particolari con caratteristiche uniche rispetto a tutte le altre, infatti la
prima ritorna due volte (nel processo padre e nel figlio) mentre la seconda
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 lore creazione, terminazione, e la messa in esecuzione di altri
programmi.


\subsection{Gli identificatori dei processi}
\label{sec:proc_pid}

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}).

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
numero memorizzato in un intero a 16 bit si arriva a 32767) oltre il quale si
riparte dal numero più basso disponibile (FIXME: verificare, non sono sicuro).
Per questo motivo processo il processo di avvio (\cmd{init}) ha sempre il
\acr{pid} uguale a uno. 

Tutti i processi inoltre memorizzano anche il \acr{pid} del genitore da cui
sono stati creati, questo viene chiamato in genere \acr{ppid} (da
\textit{parent process id}) ed è normalmente utilizzato per il controllo di
sessione.  Questi due identificativi possono essere ottenuti da programma
usando le funzioni:
\begin{functions}
\headdecl{sys/types.h}
\headdecl{unistd.h}
\funcdecl{pid\_t getpid(void)} restituisce il pid del processo corrente.
\funcdecl{pid\_t getppid(void)} restituisce il pid del padre del processo
    corrente.

Entrambe le funzioni non riportano condizioni di errore. 
\end{functions}

Il fatto che il \acr{pid} sia un numero univoco per il sistema lo rende il
candidato ideale per generare ultieriori indicatori associati al processo di
cui diventa possibile garantire l'unicità: ad esempio la funzione
\func{tmpname} (si veda \secref{sec:file_temp_file}) usa il \acr{pid} per
generare un pathname univoco, che non potrà essere replicato da un'altro
processo che usi la stessa funzione. 

Tutti i processi figli dello stesso processo padre sono detti
\textit{sibling}, questa è un'altra delle relazioni usate nel controllo di
sessione, in cui si raggruppano tutti i processi creati su uno stesso
terminale una volta che si è effettuato il login. Torneremo su questo
argomento in \secref{cap:terminal}, dove esamineremo tutti gli altri
identificativi associati ad un processo relativi al controllo di sessione.


\subsection{La funzione \func{fork}}
\label{sec:proc_fork}

La funzione \func{fork} è la funzione fondamentale della gestione dei processi
in unix; come si è detto l'unico modo di creare un nuovo processo è attraverso
l'uso di questa funzione, che è quindi la base per il multitasking; il protipo
della funzione è:

\begin{functions}
  \headdecl{sys/types.h} 
  \headdecl{unistd.h} 
  
  \funcdecl{pid\_t fork(void)} 
  
  Restituisce zero al padre e il \acr{pid} al figlio in caso di successo,
  ritorna -1 al padre (senza creare il figlio) in caso di errore;
  \texttt{errno} può assumere i valori:
  \begin{errlist}
  \item \macro{EAGAIN} non ci sono risorse sufficienti per creare un'altro
    processo (per allocare la tabella delle pagine e le strutture del task) o
    si è esaurito il numero di processi disponibili.
  \item \macro{ENOMEM} non è stato possibile allocare la memoria per le
    strutture necessarie al kernel per creare il nuovo processo.
  \end{errlist}
\end{functions}

Dopo l'esecuzione di una \func{fork} sia il processo padre che il processo
figlio continuano ad essere eseguiti normalmente alla istruzione seguente la
\func{fork}; il processo figlio è però una copia del padre, e riceve una copia
dei segmenti di testo, stack e dati (vedi \secref{sec:proc_mem_layout}), ed
esegue esattamente lo stesso codice del padre, ma la memoria è copiata, non
condivisa\footnote{In generale il segmento 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.

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.

\begin{figure}[!htb]
  \footnotesize
  \begin{lstlisting}{}
#include <errno.h>       /* error definitions and routines */ 
#include <stdlib.h>      /* C standard library */
#include <unistd.h>      /* unix standard library */
#include <stdio.h>       /* standard I/O library */
#include <string.h>      /* string functions */

/* Help printing routine */
void usage(void);

int main(int argc, char *argv[])
{
/* 
 * Variables definition  
 */
    int nchild, i;
    pid_t pid;
    int wait_child=0;
    int wait_parent=0;

    ...        /* handling options */

    /* There must be remaing parameters */
    if (optind == argc) {
        usage();
    }
    nchild = atoi(argv[optind]);
    printf("Test for forking %d child\n", nchild);
    /* loop to fork children */
    for (i=0; i<nchild; i++) {
        if ( (pid = fork()) < 0) {
            printf("Error on %d child creation, %s\n", i, strerror(errno));
        }
        if (pid == 0) {   /* child */
            printf("Child %d successfully executing\n", ++i);
            if (wait_child) sleep(wait_child);
            printf("Child %d exiting\n", i);
            exit(0);
        } else {          /* parent */
            printf("Spawned %d child, pid %d \n", i+1, pid);
            if (wait_parent) sleep(wait_parent);
            printf("Go to next child \n");
        }
    }
    /* normal exit */
    return 0;
}
  \end{lstlisting}
  \caption{Esempio di codice per la creazione di nuovi processi.}
  \label{fig:proc_fork_code}
\end{figure}

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}, vista
in \secref{sec:proc_pid}) e si usa il valore nullo, che non può essere il
\acr{pid} di nessun processo.

In \curfig\ si è riportato il corpo del codice del programma di esempio
\cmd{forktest}, che ci permette di illustrare l'uso della funzione
\func{fork}. Il programma permette di creare un numero di figli specificato a
linea di comando, e prende anche due opzioni \cmd{-p} e \cmd{-c} per indicare
degli eventuali tempi di attesa (in secondi, ottenuti tramite la funzione
\func{sleep}) per il padre ed il figlio; il codice completo, compresa la parte
che gestisce le opzioni a riga di comando, è disponibile nel file
\file{ForkTest.c}.

Decifrato il numero di figli da creare, il ciclo principale del programma
(\texttt{\small 28--40}) esegue in successione la creazione dei processi figli
controllando il successo della chiamata a \func{fork} (\texttt{\small
  29--31}); ciascun figlio (\texttt{\small 29--31}) si limita a stampare il
suo numero di successione, evantualmente attendere il numero di secondi
specificato e scrivere un messaggio prima di uscire. Il processo padre invece
(\texttt{\small 29--31}) stampa un messaggio di creazione, eventualmente
attende il numero di secondi specificato e procede nell'esecuzione del ciclo.
Se eseguiamo il comando senza specificare attese (il default è non attendere),
otterremo come output sul terminale:
\begin{verbatim}
[piccardi@selidor sources]$ ./forktest 3
Test for forking 3 child
Spawned 1 child, pid 2038 
Child 1 successfully executing
Child 1 exiting
Go to next child 
Spawned 2 child, pid 2039 
Child 2 successfully executing
Child 2 exiting
Go to next child 
Child 3 successfully executing
Child 3 exiting
Spawned 3 child, pid 2040 
Go to next child 
\end{verbatim} %$

Esaminiamo questo risultato; una prima conclusione che si può trarre è non si
può dire quale processo fra il padre ed il figlio venga eseguito per
primo\footnote{anche se nel kernel 2.4.x era stato introdotto un meccanismo
  che metteva in esecuzione sempre il xxx per primo (TODO recuperare le
  informazioni esatte)} dopo la chiamata a \func{fork}; dall'esempio si può
notare infatti come nei primi due cicli sia stato eseguito per primo il padre
(con la stampa del \acr{pid} del nuovo processo) per poi passare
all'esecuzione del figlio (completata con i due avvisi di esecuzione ed
uscita), e tornare all'esecuzione del padre (con la stampa del passaggio al
ciclo successivo), mentre la terza volta è stato prima eseguito il figlio (in
maniera completa) e poi il padre.

In generale l'ordine di esecuzione dipenderà, oltre che dall'algoritmo di
scheduling usato dal kernel, dalla particolare situazione in si trova la
macchina al momento della chiamata, risultando del tutto impredicibile.
Eseguendo più volte il programma di prova e producendo un numero diverso di
figli, si sono ottenute situazioni completamente diverse, compreso il caso in
cui il processo padre ha eseguito più di una \func{fork} prima che uno dei
figli venisse messo in esecuzione.

Pertanto non si può fare nessuna assunzione sulla sequenza di esecuzione delle
istruzioni del codice fra padre e figli, 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}.

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).

Un secondo aspetto molto importante nella creazione dei processi figli è
quello dell'interazione dei vari processi con i file; per illustrarlo meglio
proviamo a redirigere su un file l'output del nostro programma di test, quello
che otterremo è:
\begin{verbatim}
[piccardi@selidor sources]$ ./forktest 3 > output
[piccardi@selidor sources]$ cat output
Test for forking 3 child
Child 1 successfully executing
Child 1 exiting
Test for forking 3 child
Spawned 1 child, pid 836 
Go to next child 
Child 2 successfully executing
Child 2 exiting
Test for forking 3 child
Spawned 1 child, pid 836 
Go to next child 
Spawned 2 child, pid 837 
Go to next child 
Child 3 successfully executing
Child 3 exiting
Test for forking 3 child
Spawned 1 child, pid 836 
Go to next child 
Spawned 2 child, pid 837 
Go to next child 
Spawned 3 child, pid 838 
Go to next child 
\end{verbatim}
che come si vede è completamente diverso da quanto ottenevamo sul terminale.

Analizzeremo in gran dettaglio in \capref{cha:file_unix_interface} e in
\secref{cha:files_std_interface} il comportamento delle varie funzioni di
interfaccia con i file. Qui basta ricordare 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). 

Nel primo esempio allora avevamo che ad ogni chiamata a \func{printf} il
buffer veniva scaricato, e le singole righe erano stampate a video volta a
volta. Quando con la redirezione andiamo a scrivere su un file, questo non
avviene più, e 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 di un figlio il
buffer viene scritto su disco, troveremo nel file anche tutto quello che il
processo padre aveva scritto prima della sua creazione.  Alla fine, dato che
in questo caso il padre esce per ultimo, troviamo 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
fatto cioè che non solo processi diversi possono scrivere in contemporanea
sullo stesso file (l'argomento della condivisione dei file in unix è trattato
in dettaglio in \secref{sec:file_sharing}), ma anche che, a differenza di
quanto avviene per le variabili, la posizione corrente sul file è condivisa 
fra il padre e tutti i processi figli. 

Quello che succede è che quando lo standard output del padre viene rediretto,
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 referenza a figura da fare) 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 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 sovrascrivere
quello dei precedenti (l'output potrà risultare mescolato, ma non ci saranno
parti perdute per via di una sovrapposizione).

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). 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.

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à generali con cui si usano i file dopo una
\func{fork} sono sostanzialmente due:
\begin{itemize}
\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.
\item L'esecuzione di padre e figlio procede indipendentemente. In questo caso
  entrambi devono chiudere i file che non servono, per evitare ogni forma 
\end{itemize}

\subsection{Le funzioni \texttt{wait} e  \texttt{waitpid}}
\label{sec:proc_wait}


\subsection{Le funzioni \texttt{exec}}
\label{sec:proc_exec}




\section{Il controllo di accesso}
\label{sec:proc_perms}

In questa sezione esamineremo le problematiche relative al controllo di
accesso dal punto di vista del processi; gli identificativi usati, come questi
vengono modificati nella creazione e nel lancio di nuovi processi, e le varie
funzioni per la loro manipolazione diretta.


\subsection{Utente e gruppo di un processo}
\label{sec:proc_user_group}

Abbiamo già accennato in \secref{sec:intro_multiuser} ad ogni utente ed gruppo
sono associati due identificatori univoci, lo \acr{uid} e il \acr{gid} che li
contraddistinguono nei confonti del kernel. Questi identificatori stanno alla
base del sistema di permessi e protezioni di un sistema unix, e vengono usati
anche nella gestione dei privilegi di accesso dei processi.

In realtà ad ogni processo è associato un certo numero di identificatori, il
cui elenco è riportato \ntab, in genere questi derivano direttamente
dall'utente che ha lanciato il processo (attraverso i valori di \acr{uid} e
\acr{gid}), e vengono usati sia per il controllo di accesso ai file che per la
gestione dei privilegi associati ai processi stessi.
\begin{table}[htb]
  \centering
  \begin{tabular}[c]{|c|l|l|}
    \hline
    Sigla & Significato & Utilizzo \\ 
    \hline
    \hline
    \acr{ruid} & \textit{real user id} & indica l'utente reale che ha lanciato
    il programma\\ 
    \acr{rgid} & \textit{real group id} & indica il gruppo reale dell'utente 
    che ha lanciato il programma \\ 
    \acr{euid} & \textit{effective user id} & indica l'utente effettivo usato
    dal programma \\ 
    \acr{egid} & \textit{effective group id} & indica il gruppo effettivo usato
    dal programma \\ 
               & \textit{supplementary group id} & indica i gruppi cui
    l'utente appartiene  \\ 
    \acr{suid} & \textit{saved user id} & indica l'utente  \\ 
    \acr{sgid} & \textit{daved group id} & indica il gruppo  \\ 
    \acr{fsuid} & \textit{filesystem user id} & indica l'utente effettivo per
    il filesystem \\ 
    \acr{fsgid} & \textit{filesystem group id} & indica il gruppo effettivo
    per il filesystem  \\ 
    \hline
  \end{tabular}
  \caption{Identificatori di utente e gruppo associati a ciascun processo.}
  \label{tab:proc_uid_gid}
\end{table}

Il \textit{real user id} e il \textit{real group id} indicano l'utente che ha
lanciato il processo, e vengono settati al login al valore standard di
\acr{uid} e \acr{gid} dell'utente letti direttamente da \file{/etc/passwd}.
Questi non vengono mai cambiati nella creazione di nuovi processi e restano
sempre gli stessi per tutti i processi avviati in una sessione. In realtà è
possibile modificarli (vedi \secref{sec:proc_setuid}), ma solo per un processo
che abbia i privilegi di amministratore (ed è così infatti che \cmd{login},
che gira con i privilegi di amministratore, li setta ai valori corrispondenti
all'utente che entra nel sistema).

L'\textit{effective user id}, l'\textit{effective group id} e gli eventuali
\textit{supplementary group id} sono gli identificativi usati per il controllo
di accesso ai file secondo quanto descritto in dettaglio in
\secref{sec:file_perm_overview}. Normalmente sono uguali al \textit{real user
  id} e al \textit{real group id}, a meno che il file posto in esecuzione non
abbia i bit \acr{suid} o \acr{sgid} settati, nel qual caso vengono settati
rispettivamente all'\acr{uid} e \acr{gid} del file.

Il \textit{saved user id} e il \textit{saved group id} sono copie
dell'\textit{effective user id} e dell'\textit{effective group id} del
processo padre, e vengono settati all'avvio del processo, prima che
\textit{effective user id} e \textit{effective group id} vengano modificati
per tener conto di eventuali \acr{suid} o \acr{sgid}.


\subsection{Le funzioni \texttt{setuid} e \texttt{setgid}}
\label{sec:proc_setuid}


\subsection{Le funzioni \texttt{seteuid} e \texttt{setegid}}
\label{sec:proc_seteuid}

