 \chapter{Sessioni di lavoro e terminali}
\label{cha:session}

Esamineremo in questo capitolo i concetti base del sistema delle sessioni di
lavoro, vale a dire il metodo con cui il kernel gestisce l'accesso concorrente
al sistema da parte di più utenti, permettendo loro di eseguire più programmi
in contemporanea.  Nella seconda parte del capitolo tratteremo poi il
funzionamento dell'I/O su terminale, e delle varie peculiarità che esso viene
ad assumere a causa del suo stretto legame con le modalità di accesso al
sistema da parte degli utenti.


\section{Il \textit{job control}}
\label{sec:sess_job_control}

Viene comunemente chiamato \textit{job control} quell'insieme di funzionalità
il cui scopo è quello di permettere ad un utente di poter sfruttare le
capacità multitasking di un sistema Unix per eseguire in contemporanea più
processi, pur potendo accedere, di solito, ad un solo terminale,\footnote{con
  X e con i terminali virtuali tutto questo non è più vero, dato che si può
  accedere a molti terminali in contemporanea da una singola postazione di
  lavoro, ma il sistema è nato prima dell'esistenza di tutto ciò.} avendo cioè
un solo punto in cui si può avere accesso all'input ed all'output degli
stessi.


\subsection{Una panoramica introduttiva}
\label{sec:sess_job_control_overview}

Il \textit{job control} è una caratteristica opzionale, introdotta in BSD
negli anni '80, e successivamente standardizzata da POSIX.1; la sua
disponibilità nel sistema è verificabile attraverso il controllo della macro
\macro{\_POSIX\_JOB\_CONTROL}. In generale il \textit{job control} richiede il
supporto sia da parte della shell (quasi tutte ormai lo fanno), che da parte
del kernel; in particolare il kernel deve assicurare sia la presenza di un
driver per i terminali abilitato al \textit{job control} che quella dei
relativi segnali illustrati in \secref{sec:sig_job_control}. 

In un sistema che supporta il \textit{job control}, una volta completato il
login, l'utente avrà a disposizione una shell dalla quale eseguire i comandi e
potrà iniziare quella che viene chiamata una \textsl{sessione}, che riunisce
(vedi \secref{sec:sess_proc_group}) tutti i processi eseguiti all'interno
dello stesso login (esamineremo tutto il processo in dettaglio in
\secref{sec:sess_login}).

Siccome la shell è collegata ad un solo terminale, che viene usualmente
chiamato \textsl{terminale di controllo}, (vedi \secref{sec:sess_ctrl_term})
un solo comando alla volta (quello che viene detto in \textit{foreground}),
potrà scrivere e leggere dal terminale. La shell però può eseguire anche più
comandi in contemporanea, mandandoli in \textit{background} (aggiungendo una
\cmd{\&} alla fine del comando), nel qual caso essi saranno eseguiti senza
essere collegati al terminale.

Si noti come si sia parlato di comandi e non di programmi o processi; fra le
funzionalità della shell infatti c'è anche quella di consentire di concatenare
più programmi in una sola riga di comando con le pipe, ed in tal caso verranno
eseguiti più programmi, inoltre, anche quando si invoca un singolo programma,
questo potrà sempre lanciare sottoprocessi per eseguire dei compiti specifici.

Per questo l'esecuzione di un comando può originare più di un processo; quindi
nella gestione del job control non si può far riferimento ai singoli processi.
Per questo il kernel prevede la possibilità di raggruppare più processi in un
\textit{process group} (detto anche \textsl{raggruppamento di processi}, vedi
\secref{sec:sess_proc_group}) e la shell farà sì che tutti i processi che
originano da una riga di comando appartengano allo stesso raggruppamento, in
modo che le varie funzioni di controllo, ed i segnali inviati dal terminale,
possano fare riferimento ad esso.

In generale allora all'interno di una sessione avremo un eventuale (può non
esserci) \textit{process group} in \textit{foreground}, che riunisce i
processi che possono accedere al terminale, e più \textit{process group} in
\textit{background}, che non possono accedervi. Il job control prevede che
quando un processo appartenente ad un raggruppamento in \textit{background}
cerca di accedere al terminale, venga inviato un segnale a tutti i processi
del raggruppamento, in modo da bloccarli (vedi \secref{sec:sess_ctrl_term}).

Un comportamento analogo si ha anche per i segnali generati dai comandi di
tastiera inviati dal terminale che vengono inviati a tutti i processi del
raggruppamento in \textit{foreground}. In particolare \cmd{C-z} interrompe
l'esecuzione del comando, che può poi essere mandato in \textit{background}
con il comando \cmd{bg}.\footnote{si tenga presente che \cmd{bg} e \cmd{fg}
  sono parole chiave che indicano comandi interni alla shell, e nel caso non
  comportano l'esecuzione di un programma esterno.} Il comando \cmd{fg}
consente invece di mettere in \textit{foreground} un comando precedentemente
lanciato in \textit{background}.

Di norma la shell si cura anche di notificare all'utente (di solito prima
della stampa a video del prompt) lo stato dei vari processi; essa infatti sarà
in grado, grazie all'uso di \func{waitpid}, di rilevare sia i processi che
sono terminati, sia i raggruppamenti che sono bloccati (in questo caso usando
l'opzione \macro{WUNTRACED}, secondo quanto illustrato in
\secref{sec:proc_wait}).


\subsection{I \textit{process group} e le \textsl{sessioni}}
\label{sec:sess_proc_group}

Come accennato in \secref{sec:sess_job_control_overview} nel job control i
processi vengono raggruppati in \textit{process group} e \textit{sessioni};
per far questo vengono utilizzati due ulteriori identificatori (oltre quelli
visti in \secref{sec:proc_pid}) che il kernel associa a ciascun
processo:\footnote{in Linux questi identificatori sono mantenuti nei campi
  \var{pgrp} e \var{session} della struttura \var{task\_struct} definita in
  \file{sched.h}.}  l'identificatore del \textit{process group} e
l'identificatore della \textsl{sessione}, che vengono indicati rispettivamente
con le sigle \acr{pgid} e \acr{sid}, e sono mantenuti in variabili di tipo
\type{pid\_t}. I valori di questi identificatori possono essere visualizzati
dal comando \cmd{ps} usando l'opzione \cmd{-j}.

Un \textit{process group} è pertanto definito da tutti i processi che hanno lo
stesso \acr{pgid}; è possibile leggere il valore di questo identificatore con
le funzioni \func{getpgid} e \func{getpgrp},\footnote{\func{getpgrp} è
  definita nello standard POSIX.1, mentre \func{getpgid} è richiesta da SVr4.}
i cui prototipi sono:
\begin{functions}
  \headdecl{unistd.h}

  \funcdecl{pid\_t getpgid(pid\_t pid)} 
  Legge il \acr{pgid} del processo \param{pid}.

  \funcdecl{pid\_t getpgrp(void)}
  Legge il \acr{pgid} del processo corrente.
  
  \bodydesc{Le funzioni restituiscono il \acr{pgid} del processo,
    \func{getpgrp} ha sempre successo, mentre \func{getpgid} restituisce -1
    ponendo \var{errno} a \macro{ESRCH} se il processo selezionato non esiste.}
\end{functions}

La funzione \func{getpgid} permette di specificare il \acr{pid} del processo
di cui si vuole sapere il \acr{pgid}; un valore nullo per \param{pid}
restituisce il \acr{pgid} del processo corrente; \func{getpgrp} è di norma
equivalente a \code{getpgid(0)}.

In maniera analoga l'identificatore della sessione può essere letto dalla
funzione \func{getsid}, che però nelle \acr{glibc}\footnote{la system call è
  stata introdotta in Linux a partire dalla versione 1.3.44, il supporto nelle
  librerie del C è iniziato dalla versione 5.2.19. La funzione non è prevista
  da POSIX.1, che parla solo di processi leader di sessione, e non di
  identificatori di sessione.} è accessibile solo definendo
\macro{\_XOPEN\_SOURCE} e \macro{\_XOPEN\_SOURCE\_EXTENDED}; il suo prototipo
è:
\begin{prototype}{unistd.h}{pid\_t getsid(pid\_t pid)}
  Legge l'identificatore di sessione del processo \param{pid}.
  
  \bodydesc{La funzione restituisce l'identificatore (un numero positivo) in
  caso di successo, e -1 in caso di errore, nel qual caso \var{errno} assumerà
  i valori:
    \begin{errlist}
    \item[\macro{ESRCH}] Il processo selezionato non esiste.
    \item[\macro{EPERM}] In alcune implementazioni viene restituito quando il
      processo selezionato non fa parte della stessa sessione del processo
      corrente.
    \end{errlist}
  }
\end{prototype}

Entrambi gli identificatori vengono inizializzati alla creazione di ciascun
processo con lo stesso valore che hanno nel processo padre, per cui un
processo appena creato appartiene sempre allo stesso raggruppamento e alla
stessa sessione del padre. Vedremo poi come sia possibile creare più
\textit{process group} all'interno della stessa sessione, e spostare i
processi dall'uno all'altro, ma sempre all'interno di una stessa sessione.

Ciascun raggruppamento di processi ha sempre un processo principale, il
cosiddetto \textit{process group leader}, che è identificato dall'avere un
\acr{pgid} uguale al suo \acr{pid}, in genere questo è il primo processo del
raggruppamento, che si incarica di lanciare tutti gli altri. Un nuovo
raggruppamento si crea con la funzione \func{setpgrp},\footnote{questa è la
  definizione di POSIX.1, BSD definisce una funzione con lo stesso nome, che
  però è identica a \func{setpgid}; nelle \acr{glibc} viene sempre usata
  sempre questa definizione, a meno di non richiedere esplicitamente la
  compatibilità all'indietro con BSD, definendo la macro
  \macro{\_BSD\_SOURCE}.} il cui prototipo è:
\begin{prototype}{unistd.h}{int setpgrp(void)}
  Modifica il \acr{pgid} al valore del \acr{pid} del processo corrente.
  
  \bodydesc{La funzione restituisce il valore del nuovo \textit{process
      group}.}
\end{prototype}

La funzione, assegnando al \acr{pgid} il valore del \acr{pid} processo
corrente, rende questo \textit{group leader} di un nuovo raggruppamento, tutti
i successivi processi da esso creati apparterranno (a meno di non cambiare di
nuovo il \acr{pgid}) al nuovo raggruppamento. È possibile invece spostare un
processo da un raggruppamento ad un altro con la funzione \func{setpgid}, il
cui prototipo è:
\begin{prototype}{unistd.h}{int setpgid(pid\_t pid, pid\_t pgid)}
  Assegna al \acr{pgid} del processo \param{pid} il valore \param{pgid}.
  
  \bodydesc{La funzione ritorna il valore del nuovo \textit{process group}, e
  -1 in caso di errore, nel qual caso \var{errno} assumerà i valori:
    \begin{errlist}
    \item[\macro{ESRCH}] Il processo selezionato non esiste.
    \item[\macro{EPERM}] Il cambiamento non è consentito.
    \item[\macro{EACCESS}] Il processo ha già eseguito una \func{exec}.
    \item[\macro{EINVAL}] Il valore di \param{pgid} è negativo.
    \end{errlist}
 }
\end{prototype}

La funzione permette di cambiare il \acr{pgid} del processo \param{pid}, ma il
cambiamento può essere effettuato solo se \param{pgid} indica un
\textit{process group} che è nella stessa sessione del processo chiamante.
Inoltre la funzione può essere usata soltanto sul processo corrente o su uno
dei suoi figli, ed in quest'ultimo caso ha successo soltanto se questo non ha
ancora eseguito una \func{exec}.\footnote{questa caratteristica è implementata
  dal kernel che mantiene allo scopo un altro campo, \var{did\_exec}, in
  \var{task\_struct}.}  Specificando un valore nullo per \param{pid} si indica
il processo corrente, mentre specificando un valore nullo per \param{pgid} si
imposta il \textit{process group} al valore del \acr{pid} del processo
selezionato; pertanto \func{setpgrp} è equivalente a \code{setpgid(0, 0)}.

Di norma questa funzione viene usata dalla shell quando si usano delle
pipeline, per mettere nello stesso process group tutti i programmi lanciati su
ogni linea di comando; essa viene chiamata dopo una \func{fork} sia dal
processo padre, per impostare il valore nel figlio, che da quest'ultimo, per
sé stesso, in modo che il cambiamento di \textit{process group} sia immediato
per entrambi; una delle due chiamate sarà ridondante, ma non potendo
determinare quale dei due processi viene eseguito per primo, occorre eseguirle
comunque entrambe per evitare di esporsi ad una race condition. 

Si noti come nessuna delle funzioni esaminate finora permetta di spostare un
processo da una sessione ad un altra; infatti l'unico modo di far cambiare
sessione ad un processo è quello di crearne una nuova con l'uso di
\func{setsid}; il suo prototipo è:
\begin{prototype}{unistd.h}{pid\_t setsid(void)}
  Crea una nuova sessione sul processo corrente impostandone \acr{sid} e
  \acr{pgid}.
  
  \bodydesc{La funzione ritorna il valore del nuovo \acr{sid}, e -1 in caso di
    errore, il solo errore possibile è \macro{EPERM}, che si ha quando il
    \acr{pgid} e \acr{pid} del processo coincidono.}
\end{prototype}

La funzione imposta il \acr{pgid} ed il \acr{sid} del processo corrente al
valore del suo \acr{pid}, creando così una nuova sessione ed un nuovo
\textit{process group} di cui esso diventa leader (come per i \textit{process
  group} un processo si dice leader di sessione\footnote{in Linux la proprietà
  è mantenuta in maniera indipendente con un apposito campo \var{leader} in
  \var{task\_struct}.} se il suo \acr{sid} è uguale al suo \acr{pid}) ed unico
componente.  Inoltre la funzione distacca il processo da ogni terminale di
controllo (torneremo sull'argomento in \secref{sec:sess_ctrl_term}) cui fosse
in precedenza associato.

  funzione ha successo soltanto se il processo non è già leader di un
\textit{process group}, per cui per usarla di norma si esegue una \func{fork}
e si esce, per poi chiamare \func{setsid} nel processo figlio, in modo che,
avendo questo lo stesso \acr{pgid} del padre ma un \acr{pid} diverso, non ci
siano possibilità di errore.\footnote{potrebbe sorgere il dubbio che, per il
  riutilizzo dei valori dei \acr{pid} fatto nella creazione dei nuovi processi
  (vedi \secref{sec:proc_pid}), il figlio venga ad assumere un valore
  corrispondente ad un process group esistente; questo viene evitato dal
  kernel che considera come disponibili per un nuovo \acr{pid} solo valori che
  non corrispondono ad altri \acr{pid}, \acr{pgid} o \acr{sid} in uso nel
  sistema.} Questa funzione viene usata di solito nel processo di login (per i
dettagli vedi \secref{sec:sess_login}) per raggruppare in una sessione tutti i
comandi eseguiti da un utente dalla sua shell.



\subsection{Il terminale di controllo e il controllo di sessione}
\label{sec:sess_ctrl_term}

Come accennato in \secref{sec:sess_job_control_overview}, nel sistema del
\textit{job control} i processi all'interno di una sessione fanno riferimento
ad un terminale di controllo (ad esempio quello su cui si è effettuato il
login), sul quale effettuano le operazioni di lettura e
scrittura,\footnote{nel caso di login grafico la cosa può essere più
  complessa, e di norma l'I/O è effettuato tramite il server X, ma ad esempio
  per i programmi, anche grafici, lanciati da un qualunque emulatore di
  terminale, sarà quest'ultimo a fare da terminale (virtuale) di controllo.} e
dal quale ricevono gli eventuali segnali da tastiera.

A tale scopo lo standard POSIX.1 prevede che ad ogni sessione possa essere
associato un terminale di controllo; in Linux questo viene realizzato
mantenendo fra gli attributi di ciascun processo anche qual'è il suo terminale
di controllo. \footnote{Lo standard POSIX.1 non specifica nulla riguardo
  l'implementazione; in Linux anch'esso viene mantenuto nella solita struttura
  \var{task\_struct}, nel campo \var{tty}.}  In generale ogni processo eredita
dal padre, insieme al \acr{pgid} e al \acr{sid} anche il terminale di
controllo (vedi \secref{sec:proc_fork}). In questo modo tutti processi
originati dallo stesso leader di sessione mantengono lo stesso terminale di
controllo.

Alla creazione di una nuova sessione con \func{setsid} ogni associazione con
il precedente terminale di controllo viene cancellata, ed il processo che è
divenuto un nuovo leader di sessione dovrà riottenere\footnote{solo quando ciò
  è necessario, cosa che, come vedremo in \secref{sec:sess_daemon}, non è
  sempre vera.}, un terminale di controllo. In generale questo viene fatto
automaticamente dal sistema\footnote{a meno di non avere richiesto
  esplicitamente che questo non diventi un terminale di controllo con il flag
  \macro{O\_NOCTTY} (vedi \secref{sec:file_open}). In questo Linux segue la
  semantica di SVr4; BSD invece richiede che il terminale venga allocato
  esplicitamente con una \func{ioctl} con il comando \macro{TIOCSCTTY}.}
quando viene aperto il primo terminale (cioè uno dei vari file di dispositivo
\file{/dev/tty*}) che diventa automaticamente il terminale di controllo,
mentre il processo diventa il \textsl{processo di controllo} di quella
sessione.

In genere (a meno di redirezioni) nelle sessioni di lavoro questo terminale è
associato ai file standard (di input, output ed error) dei processi nella
sessione, ma solo quelli che fanno parte del cosiddetto raggruppamento di
\textit{foreground}, possono leggere e scrivere in certo istante. Per
impostare il raggruppamento di \textit{foreground} di un terminale si usa la
funzione \func{tcsetpgrp}, il cui prototipo è:
\begin{functions}
  \headdecl{unistd.h}
  \headdecl{termios.h}
  
  \funcdecl{int tcsetpgrp(int fd, pid\_t pgrpid)} Imposta a \param{pgrpid} il
  \textit{process group} di \textit{foreground} del terminale associato al
  file descriptor \param{fd}.
   
  \bodydesc{La funzione restituisce 0 in caso di successo, e -1 in caso di
    errore, nel qual caso \var{errno} assumerà i valori:
    \begin{errlist}
    \item[\macro{ENOTTY}] Il file \param{fd} non corrisponde al terminale di
      controllo del processo chiamante.
    \item[\macro{ENOSYS}] Il sistema non supporta il job control.
    \item[\macro{EPERM}] Il \textit{process group} specificato non è nella
    stessa sessione del processo chiamante.
    \end{errlist}
    ed inoltre \macro{EBADF} ed \macro{EINVAL}. 
  }
\end{functions}
\noindent la funzione può essere eseguita con successo solo da
un processo nella stessa sessione e con lo stesso terminale di controllo. 

Come accennato in \secref{sec:sess_job_control_overview}, tutti i processi (e
relativi raggruppamenti) che non fanno parte del gruppo di \textit{foreground}
sono detti in \textit{background}; se uno si essi cerca di accedere al
terminale di controllo provocherà l'invio da parte del kernel di uno dei due
segnali \macro{SIGTTIN} o \macro{SIGTTOU} (a seconda che l'accesso sia stato
in lettura o scrittura) a tutto il suo \textit{process group}; dato che il
comportamento di default di questi segnali (si riveda quanto esposto in
\secref{sec:sig_job_control}) è di fermare il processo, di norma questo
comporta che tutti i membri del gruppo verranno fermati, ma non si avranno
condizioni di errore.\footnote{la shell in genere notifica comunque un
  avvertimento, avvertendo la presenza di processi bloccati grazie all'uso di
  \func{waitpid}.} Se però si bloccano o ignorano i due segnali citati, le
funzioni di lettura e scrittura falliranno con un errore di \macro{EIO}.

Un processo può controllare qual'è il gruppo di \textit{foreground} associato
ad un terminale con la funzione \func{tcgetpgrp}, il cui prototipo è:
\begin{functions}
  \headdecl{unistd.h} \headdecl{termios.h}
  
  \funcdecl{pid\_t tcgetpgrp(int fd)} Legge il \textit{process group} di
  \textit{foreground} del terminale associato al file descriptor \param{fd}.
  \bodydesc{La funzione restituisce in caso di successo il \acr{pgid} del
    gruppo di \textit{foreground}, e -1 in caso di errore, nel qual caso
    \var{errno} assumerà i valori:
    \begin{errlist}
    \item[\macro{ENOTTY}] Non c'è un terminale di controllo o \param{fd} non
      corrisponde al terminale di controllo del processo chiamante.
    \end{errlist}
    ed inoltre \macro{EBADF} ed \macro{ENOSYS}. 
  }
\end{functions}

Si noti come entrambe le funzioni usino come argomento il valore di un file
descriptor, il risultato comunque non dipende dal file descriptor che si usa
ma solo dal terminale cui fa riferimento; il kernel inoltre permette a ciascun
processo di accedere direttamente al suo terminale di controllo attraverso il
file speciale \file{/dev/tty}, che per ogni processo è un sinonimo per il
proprio terminale di controllo.  Questo consente anche a processi che possono
aver rediretto l'output di accedere al terminale di controllo, pur non
disponendo più del file descriptor originario; un caso tipico è il programma
\cmd{crypt} che accetta la redirezione sullo standard input di un file da
decifrare, ma deve poi leggere la password dal terminale.

Un'altra caratteristica del terminale di controllo usata nel job control è che
utilizzando su di esso le combinazioni di tasti speciali (\cmd{C-z},
\cmd{C-c}, \cmd{C-y} e \verb|C-\|) si farà sì che il kernel invii i
corrispondenti segnali (rispettivamente \macro{SIGTSTP}, \macro{SIGINT},
\macro{SIGQUIT} e \macro{SIGTERM}, trattati in \secref{sec:sig_job_control}) a
tutti i processi del raggruppamento di \textit{foreground}; in questo modo la
shell può gestire il blocco e l'interruzione dei vari comandi.
 
Per completare la trattazione delle caratteristiche del job control legate al
terminale di controllo, occorre prendere in considerazione i vari casi legati
alla terminazione anomala dei processi, che sono di norma gestite attraverso
il segnale \macro{SIGHUP}. Il nome del segnale deriva da \textit{hungup},
termine che viene usato per indicare la condizione in cui il terminale diventa
inutilizzabile, (letteralmente sarebbe \textsl{impiccagione}). 

Quando si verifica questa condizione, ad esempio se si interrompe la linea, o
va giù la rete o più semplicemente si chiude forzatamente la finestra di
terminale su cui si stava lavorando, il kernel provvederà ad inviare il
segnale di \macro{SIGHUP} al processo di controllo. L'azione preimpostata in
questo caso è la terminazione del processo, il problema che si pone è cosa
accade agli altri processi nella sessione, che non han più un processo di
controllo che possa gestire l'accesso al terminale, che potrebbe essere
riutilizzato per qualche altra sessione.

Lo standard POSIX.1 prevede che quando il processo di controllo termina, che
ciò avvenga o meno per un \textit{hungup} del terminale (ad esempio si
potrebbe terminare direttamente la shell con \cmd{kill}) venga inviato un
segnale di \macro{SIGHUP} ai processi del raggruppamento di foreground. In
questo modo essi potranno essere avvisati che non esiste più un processo in
grado di gestire il terminale (di norma tutto ciò comporta la terminazione
anche di questi ultimi).

Restano però gli eventuali processi in background, che non ricevono il
segnale; in effetti se il terminale non dovesse più servire essi potrebbero
proseguire fino al completamento della loro esecuzione; ma si pone il problema
di come gestire quelli che sono bloccati, o che si bloccano nell'accesso al
terminale, in assenza di un processo che sia in grado di effettuare il
controllo dello stesso.

Questa è la situazione in cui si ha quello che viene chiamato un
\textit{orphaned process group}. Lo standard POSIX.1 lo definisce come un
\textit{process group} i cui processi hanno come padri esclusivamente o altri
processi nel raggruppamento, o processi fuori della sessione.  Lo standard
prevede inoltre che se la terminazione di un processo fa sì che un
raggruppamento di processi diventi orfano e se i suoi membri sono bloccati, ad
essi vengano inviati in sequenza i segnali di \macro{SIGHUP} e
\macro{SIGCONT}.

La definizione può sembrare complicata, e a prima vista non è chiaro cosa
tutto ciò abbia a che fare con il problema della terminazione del processo di
controllo.  Consideriamo allora cosa avviene di norma nel \textit{job
  control}: una sessione viene creata con \func{setsid} che crea anche un
nuovo process group: per definizione quest'ultimo è sempre \textsl{orfano},
dato che il padre del leader di sessione è fuori dalla stessa e il nuovo
process group contiene solo il leader di sessione. Questo è un caso limite, e
non viene emesso nessun segnale perché quanto previsto dallo standard riguarda
solo i raggruppamenti che diventano orfani in seguito alla terminazione di un
processo.\footnote{l'emissione dei segnali infatti avviene solo nella fase di
  uscita del processo, come una delle operazioni legate all'esecuzione di
  \func{\_exit}, secondo quanto illustrato in \secref{sec:proc_termination}.}

Il leader di sessione provvederà a creare nuovi raggruppamenti che a questo
punto non sono orfani in quanto esso resta padre per almeno uno dei processi
del gruppo (gli altri possono derivare dal primo). Alla terminazione del
leader di sessione però avremo che, come visto in
\secref{sec:proc_termination}, tutti i suoi figli vengono adottati da
\cmd{init}, che è fuori dalla sessione. Questo renderà orfani tutti i process
group creati direttamente dal leader di sessione (a meno di non aver spostato
con \func{setpgid} un processo da un gruppo ad un altro, cosa che di norma non
viene fatta) i quali riceveranno, nel caso siano bloccati, i due segnali;
\macro{SIGCONT} ne farà proseguire l'esecuzione, ed essendo stato nel
frattempo inviato anche \macro{SIGHUP}, se non c'è un gestore per
quest'ultimo, i processi bloccati verranno automaticamente terminati.



\subsection{Dal login alla shell}
\label{sec:sess_login}

L'organizzazione del sistema del job control è strettamente connessa alle
modalità con cui un utente accede al sistema per dare comandi, collegandosi ad
esso con un terminale, che sia questo realmente tale, come un VT100 collegato
ad una seriale o virtuale, come quelli associati a schermo e tastiera o ad una
connessione di rete. Dato che i concetti base sono gli stessi, e dato che alla
fine le differenze sono\footnote{in generale nel caso di login via rete o di
  terminali lanciati dall'interfaccia grafica cambia anche il processo da cui
  ha origine l'esecuzione della shell.} nel dispositivo cui il kernel associa i
file standard (vedi \secref{sec:file_std_descr}) per l'I/O, tratteremo solo il
caso classico del terminale.

Abbiamo già brevemente illustrato in \secref{sec:intro_kern_and_sys} le
modalità con cui il sistema si avvia, e di come, a partire da \cmd{init},
vengano lanciati tutti gli altri processi. Adesso vedremo in maniera più
dettagliata le modalità con cui il sistema arriva a fornire ad un utente la
shell che gli permette di lanciare i suoi comandi su un terminale.

Nella maggior parte delle distribuzioni di GNU/Linux\footnote{fa eccezione la
  distribuzione \textit{Slackware}, come alcune distribuzioni su dischetto, ed
  altre distribuzioni dedicate a compiti limitati e specifici.}  viene usata
la procedura di avvio di System V; questa prevede che \cmd{init} legga dal
file di configurazione \file{/etc/inittab} quali programmi devono essere
lanciati, ed in quali modalità, a seconda del cosiddetto \textit{run level},
anch'esso definito nello stesso file.

Tralasciando la descrizione del sistema dei run level, (per il quale si
rimanda alla lettura delle pagine di manuale di \cmd{init} e di
\file{inittab}) quello che comunque viene sempre fatto è di eseguire almeno
una istanza di un programma che permetta l'accesso ad un terminale. Uno schema
di massima della procedura è riportato in \figref{fig:sess_term_login}.

\begin{figure}[htb]
  \centering
  \includegraphics[width=15cm]{img/tty_login}
  \caption{Schema della procedura di login su un terminale.}
  \label{fig:sess_term_login}
\end{figure}

Un terminale, che esso sia un terminale effettivo, attaccato ad una seriale o
ad un altro tipo di porta di comunicazione, o una delle console virtuali
associate allo schermo, viene sempre visto attraverso attraverso un device
driver che ne presenta un'interfaccia comune su un apposito file di
dispositivo. Storicamente i primi terminali erano appunto terminali di
telescriventi (\textit{teletype}), da cui deriva sia il nome dell'interfaccia,
\textit{tty}, che quello dei relativi file di dispositivo, che sono sempre
della forma \texttt{/dev/tty*}.\footnote{questo vale anche per i terminali
  virtuali associati alle connessioni di rete con \cmd{telnet} o \cmd{ssh}.}

Per controllare un terminale si usa di solito il programma \cmd{getty} (od una
delle sue varianti), che permette di mettersi in ascolto su uno di questi
dispositivi. Alla radice della catena che porta ad una shell per i comandi
perciò c'è sempre \cmd{init} che esegue prima una \func{fork} e poi una
\func{exec} per lanciare una istanza di questo programma su un terminale, il
tutto ripetuto per ciascuno dei terminali che si hanno a disposizione (o per
un certo numero di essi, nel caso delle console virtuali), secondo quanto
indicato dall'amministratore nel file di configurazione del programma,
\file{/etc/inittab}.

Quando viene lanciato da \cmd{init} il programma parte con i privilegi di
amministratore e con un ambiente vuoto; \cmd{getty} si cura di chiamare
\func{setsid} per creare una nuova sessione ed un nuovo process group, e di
aprire il terminale (che così diventa il terminale di controllo della
sessione) in lettura sullo standard input ed in scrittura sullo standard
output e sullo standard error; inoltre effettuerà, qualora servano, ulteriori
settaggi.\footnote{ad esempio, come qualcuno si sarà accorto scrivendo un nome
  di login in maiuscolo, può effettuare la conversione automatica dell'input
  in minuscolo, ponendosi in una modalità speciale che non distingue fra i due
  tipi di caratteri (a beneficio di alcuni vecchi terminali che non
  supportavano le minuscole).} Alla fine il programma stamperà un messaggio di
benvenuto per poi porsi in attesa dell'immissione del nome di un utente.

Una volta che si sia immesso il nome di login \cmd{getty} esegue direttamente
il programma \cmd{login} con una \func{exevle}, passando come argomento la
stringa con il nome, ed un ambiente opportunamente costruito che contenga
quanto necessario (ad esempio di solito viene opportunamente inizializzata la
variabile di ambiente \texttt{TERM}) ad identificare il terminale su cui si
sta operando, a beneficio dei programmi che verranno lanciati in seguito.

A sua volta \cmd{login}, che mantiene i privilegi di amministratore, usa il
nome dell'utente per effettuare una ricerca nel database degli
utenti,\footnote{in genere viene chiamata \func{getpwnam}, che abbiamo visto
  in \secref{sec:sys_user_group}, per leggere la password e gli altri dati dal
  database degli utenti.} e richiede una password. Se l'utente non esiste o se
la password non corrisponde\footnote{il confronto non viene effettuato con un
  valore in chiaro; quanto immesso da terminale viene invece a sua volta
  criptato, ed è il risultato che viene confrontato con il valore che viene
  mantenuto nel database degli utenti.} la richiesta viene ripetuta un certo
numero di volte dopo di che \cmd{login} esce ed \cmd{init} provvede a
rilanciare un'altra istanza di \func{getty}.

Se invece la password corrisponde \cmd{login} esegue \func{chdir} per settare
la \textit{home directory} dell'utente, cambia i diritti di accesso al
terminale (con \func{chown} e \func{chmod}) per assegnarne la titolarità
all'utente ed al suo gruppo principale, assegnandogli al contempo i diritti di
lettura e scrittura. Inoltre il programma provvede a costruire gli opportuni
valori per le variabili di ambiente, come \texttt{HOME}, \texttt{SHELL}, ecc.
Infine attraverso l'uso di \func{setuid}, \func{setpid} e \func{initgroups}
verrà cambiata l'identità del proprietario del processo, infatti, come
spiegato in \secref{sec:proc_setuid}, avendo invocato tali funzioni con i
privilegi di amministratore, tutti gli userid ed i groupid (reali, effettivi e
salvati) saranno settati a quelli dell'utente.

A questo punto \cmd{login} provvederà (fatte salve eventuali altre azioni
iniziali, come la stampa di messaggi di benvenuto o il controllo della posta)
ad eseguire con un'altra \func{exec} la shell, che si troverà con un ambiente
già pronto con i file standard di \secref{sec:file_std_descr} impostati sul
terminale, e pronta, nel ruolo di leader di sessione e di processo di
controllo per il terminale, a gestire l'esecuzione dei comandi come illustrato
in \secref{sec:sess_job_control_overview}. 

Dato che il processo padre resta sempre \cmd{init} quest'ultimo potrà
provvedere, ricevendo un \macro{SIGCHLD} all'uscita della shell quando la
sessione di lavoro è terminata, a rilanciare \cmd{getty} sul terminale per
ripetere da capo tutto il procedimento. 



\subsection{Prescrizioni per un programma \textit{daemon}}
\label{sec:sess_daemon}

Come sottolineato fin da \secref{sec:intro_base_concept}, in un sistema
unix-like tutte le operazioni sono eseguite tramite processi, comprese quelle
operazioni di sistema (come l'esecuzione dei comandi periodici, o la consegna
della posta, ed in generale tutti i programmi di servizio) che non hanno a che
fare con la gestione diretta dei comandi dell'utente.

Questi programmi, che devono essere eseguiti in modalità non interattiva e
senza nessun intervento dell'utente, sono normalmente chiamati
\textsl{demoni}, (o \textit{daemons}), nome ispirato dagli omonimi spiritelli
che svolgevano vari compiti, di cui parlava Socrate (che sosteneva di averne
uno al suo servizio).\footnote{NdT. ricontrollare, i miei ricordi di filosofia
  sono piuttosto datati.} 

Dato che un demone deve essere eseguito non interattivamente, esso non può far
parte di una sessione e non deve avere un terminale di controllo, per questo
motivo occorre prendere gli opportuni provvedimenti perché il sistema del
\textit{job contol} non interferisca. 



\section{L'I/O su terminale}
\label{sec:sess_terminal_io}

Esamineremo in questa sezione le peculiarità dell'I/O eseguito sui terminali,
tenendo conto delle differenze che quest'ultimi presentano rispetto ai normali
file su disco.




%%% Local Variables: 
%%% mode: latex
%%% TeX-master: "gapil"
%%% End: 
