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

Unix nasce prima dell'esistenza dei moderni PC, quando i computer occupavano
stanze intere e ci si poteva collegare solo attraverso dei terminali, ma fin
dalle sue origini è sempre stato un sistema multitasking e multiutente,
in grado di consentire l'utilizzo di un solo computer da parte di più persone.

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.


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

Viene comunemente chiamato \textit{Job control} quell'insieme di funzionalità
del sistema 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 vituali tutto questo non è più
  vero, dato che si può accedere a molti terminali in contemporanea, 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{La struttura di base}
\label{sec:sess_relation}

Per poter gestire il \textit{Job Control} il kernel associa a ciascun processo
due ulteriori identificatori (oltre quelli visti in \secref{sec:proc_pid}):
l'identificatore del cosiddetto \textit{process group} (o
\textsl{ragguppamento di processi}), cui si fa di norma riferimento con la
sigla \acr{pgid}, l'identificatore di sessione (il \textit{session id}) cui si
fa riferimento con la sigla \acr{sid}).  In questo modo, sulla base dei valori
dei rispettivi indicatori, i processi vengono organizzati in \textsl{sessioni}
e \textsl{raggruppamenti}.

Entrambi gli identificatori vengono impostati alla creazione di ciascun
processo allo stesso valore che hanno nel processo padre, un processo appena
creato cioè appartiene sempre allo stesso raggruppamento e alla stessa
sessione del padre. La differenza fra i due identificatori è che un processo
può cambiare \acr{pgid} soltanto ad un valore che corrisponda al
\textit{process group} di un altro processo della stessa sessione, oppure al
suo stesso \acr{pid} (creando così un nuovo \textit{process group}). Se invece
si modifica il \acr{sid} il processo viene automaticamente messo anche in un
nuovo \textit{process group}, corrispondente al suo \acr{pid}.

Per capire meglio il significato di questi identificatori vediamone subito
l'uso concreto nella gestione del \textit{job control} della linea di comando.
Una volta che si è completata la procedura di login (che esamineremo in
dettaglio in \secref{sec:sess_login}), si avrà a disposizione una shell,
associata ad un terminale (detto \textsl{terminale di controllo}), dalla quale
eseguire i comandi, una delle caratteristiche della shell è quella di
consentire di inviare un comando in \textit{background}, cioè di farlo
eseguire distaccandolo dal terminale, che potrà essere utilizzato da altri
comandi. Così un solo un comando alla volta potrà leggere e scrivere sul
terminale (quello che viene detto in \textit{foreground}).

Fra le funzionalità della shell c'è anche quella di consentire di concatenare
più programmi in una sola riga di comando con le pipe, in tal caso, ed
inoltre, anche quando si invoca un singolo programma, questo può sempre
lanciare ulteriori sottoprocessi per eseguire dei compiti specifici.

La shell farà si che tutti i processi che originano da un sola riga di
comando vengano raggruppati in un unico \textit{process group}; questo perché
i segnali inviati sul terminale con i comandi da tastiera (quelli illustrati
in \secref{sec:sig_job_control}) vengono inviati a tutti i processi che fan
parte del raggruppamento di \textit{foreground}, cioè quelli che stanno corre


Per consentire l'utilizzo contemporaneo dello stesso terminale la shell deve
essere in grado di garantire che solo un comando alla volta possa accedervi; 





Lo stato del sistema può essere verificato con il comando \cmd{ps -je f}



\subsection{Il login ed il terminale di controllo}
\label{sec:sess_login}

L'organizzazione del sistema del \textit{Job Control} è strettamente connessa
alle modalità con cui un utente accede al sistema, 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 device cui il kernel associa i
file standard di \secref{sec:file_std_descr}, tratteremo solo il caso in
questo è il classico 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 \secref{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
  associati alle connessioni di rete con \cmd{telnet} o \cmd{ssh}.}

Per controllare i terminali si usa di solito il programma \cmd{getty} (od una
delle sue varianti), che permette di mettersi in ascolto sugli stessi. 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 aprire il
terminale in lettura sullo standard input ed in scrittura sullo standard
output e sullo standard error, e di effettuare, 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).} ed infine 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
suddetta stringa 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 a questo punto \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 di login, che si troverà con un
ambiente già pronto e con file standard di \secref{sec:file_std_descr}
impostati sul terminale, pronta ad eseguire i comandi fino all'uscita. Dato
che il processo genitore resta sempre \cmd{init} quest'ultimo provvederà,
ricevendo un \macro{SIGCHLD} all'uscita della shell, a rilanciare \cmd{getty}
per ripetere da capo tutto il procedimento.




\subsection{I \textit{process group}}
\label{sec:sess_proc_group}



\subsection{Le sessioni}
\label{sec:sess_sessions}



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



\subsection{La shell e i programmi}
\label{sec:sess_shell}



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