Risistemazione di sessioni e pgid
[gapil.git] / session.tex
index d852e8463210304efb26bb2947249e675e8942cb..c5c1d2430c08d142ebccdb2969c1d76afd4ae477 100644 (file)
-\chapter{Il controllo di sessione}
+ \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 login}
-\label{sec:sess_login}
+\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, 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}. 
 
-\subsection{Il login da terminale}
-\label{sec:sess_term_log}
+In un sistema che supporta il \textit{job control} una volta completato il
+login (che esamineremo in dettaglio in \secref{sec:sess_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.
 
+Siccome la shell è collegata ad un solo terminale (che viene usualmente
+chiamato \textsl{terminale di controllo}) 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.
 
-\subsection{Il login via rete}
-\label{sec:sess_net_log}
+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}, 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 \textit{process
+  group}, in modo che le varie funzioni di controllo, ed i segnali inviati dal
+terminale, possano fare riferimento ad esso.
 
-\section{Le relazioni fra i processi}
-\label{sec:sess_relation}
+In generale allora all'interno di una sessione avremo un eventuale (possono
+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 questo invii a tutti i processi del
+raggruppamento un segnale di \macro{SIGTTIN} o di \macro{SIGTTOU}, a seconda
+che l'accesso sia rispettivamente in lettura o scrittura, bloccando (secondo
+il comportamento di default esposto in \secref{sec:sig_job_control}) i
+processi.
 
+Un comportamento analogo si ha anche per i segnali generati dai comandi di
+tastiera inviati dal terminale con \cmd{C-z}, \cmd{C-c}, \cmd{C-y} e
+\verb|C-\|; questi generano rispettivamente i segnali \macro{SIGTSTP},
+\macro{SIGINT}, \macro{SIGQUIT} e \macro{SIGTERM}, che vengono inviati a tutti
+i processi del raggruppamento in \textit{foreground}. In particolare il primo
+di essi, \macro{SIGTSTP}, interrompe l'esecuzione del comando, che può poi
+essere mandato in \textit{background} con il comando \cmd{bg}. Il comando
+\cmd{fg} consente invece di mettere in \textit{foreground} un comando
+precedentemente lanciato in \textit{background}.
 
-\subsection{I \textit{process group}}
+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 usa
+le caratteristiche della funzione \func{waitpid} (si riveda quanto detto in
+\secref{sec:proc_wait}) per verificare quali gruppi di processi sono bloccati
+e quali sono terminati. 
+
+
+\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:
+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 gruppo 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 gruppo, che
+si incarica di lanciare tutti gli altri. Un nuovo gruppo 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{process leader} di un nuovo gruppo, tutti i
+successivi processi da esso creati apparterranno (a meno di non cambiare di
+nuovo il \acr{pgid}) al nuovo gruppo. È possibile invece spostare un processo
+da un gruppo 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{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}. 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 settandone \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 concidono.}
+\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 se il suo \acr{sid} è uguale
+al suo \acr{pid}).  Inoltre il processo non avrà più un terminale di
+controllo.
+
+La funzione ha successo soltanto se il processo non è già leader per 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.  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{Le sessioni}
-\label{sec:sess_sessions}
 
 
 \subsection{Il terminale di controllo}
 \label{sec:sess_ctrl_term}
 
+Come accennato in \secref{sec:sess_job_control_overview} ad ogni sessione di
+lavoro di norma viene associato un terminale di controllo. Alla creazione
+della sessione con \func{setsid} infatti ogni associazione con un precedente
+terminale di controllo viene spezzata, ed il processo dovrà riottenere (se
+necessario, vedi \secref{sec:sess_daemon}), un terminale di controllo.
+
+Le modalità con cui 
+
+
+\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 device 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
+  vitruali 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 effettuarà, 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 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{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 di 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 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.}
+
 
 
-\section{Il \textit{job control}}
-\label{sec:sess_job_control}
 
+\section{L'I/O su terminale}
+\label{sec:sess_terminal_io}
 
-\subsection{La shell e i programmi}
-\label{sec:sess_shell}
+Esamineremo in questa sezione le peculiarità dell'I/O su terminale, tenendo
+conto delle 
 
 
 %%% Local Variables: