X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=session.tex;h=17bfaa961275bd542f0189a63c2aeb8235036334;hp=c5c1d2430c08d142ebccdb2969c1d76afd4ae477;hb=de41308ec9349b36a117358295dacf7cb0bd0877;hpb=221191d7d22570a7adaf6f1089f87ab0a547d88a diff --git a/session.tex b/session.tex index c5c1d24..17bfaa9 100644 --- a/session.tex +++ b/session.tex @@ -18,9 +18,10 @@ il cui scopo 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. + 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} @@ -35,20 +36,20 @@ 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 (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. +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 @@ -59,38 +60,36 @@ questo potr 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 +\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 \textit{process - group}, in modo che le varie funzioni di controllo, ed i segnali inviati dal -terminale, possano fare riferimento ad esso. +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 (possono -non esserci) \textit{process group} in \textit{foreground}, che riunisce i +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 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. +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 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}. +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 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. +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}} @@ -99,12 +98,14 @@ e quali sono terminati. 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}. +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 @@ -160,16 +161,16 @@ 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 è: +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. @@ -178,10 +179,11 @@ prototipo \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 è: +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}. @@ -190,6 +192,7 @@ da un gruppo ad un altro con la funzione \func{setpgid}, il cui prototipo \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} } @@ -200,11 +203,12 @@ cambiamento pu \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)}. +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 @@ -220,42 +224,225 @@ 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 + 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 concidono.} + \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 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 + 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. 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. +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} +\subsection{Il terminale di controllo e il controllo di sessione} \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. +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. -Le modalità con cui \subsection{Dal login alla shell} @@ -268,7 +455,7 @@ 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 + 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. @@ -307,7 +494,7 @@ 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}.} + 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 @@ -324,7 +511,7 @@ 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 +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 @@ -365,12 +552,16 @@ 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. +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. @@ -379,25 +570,308 @@ per ripetere da capo tutto il procedimento. 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. +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 +niente 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 compiti vari, di cui parlava Socrate (che sosteneva di averne +uno al suo servizio).\footnote{NdT. ricontrollare, i miei ricordi di filosofia + sono piuttosto datati.} + +Se però si lancia un programma demone dalla riga di comando in un sistema che +supporta, come Linux, il \textit{job control} esso verrà comunque associato ad +un terminale di controllo e mantenuto all'interno di una sessione, e anche se +può essere mandato in background e non eseguire più nessun I/O su terminale, +si avranno comunque tutte le conseguenze che abbiamo appena visto in +\secref{sec:sess_ctrl_term} (in particolare l'invio dei segnali in +corrispondenza dell'uscita del leader di sessione). + +Per questo motivo un programma che deve funzionare come demone deve sempre +prendere autonomamente i provvedimenti opportuni (come distaccarsi dal +terminale e dalla sessione) ad impedire eventuali interferenze da parte del +sistema del \textit{job contol}; questi sono riassunti in una lista di +prescrizioni\footnote{ad esempio sia Stevens in \cite{APUE}, che la + \textit{Unix Programming FAQ} \cite{UnixFAQ} ne riportano di sostanzialmente + identiche.} da seguire quando si scrive un demone. + +Pertanto, quando si lancia un programma che deve essere eseguito come demone +occorrerà predisporlo in modo che esso compia le seguenti azioni: +\begin{enumerate} +\item Eseguire una \func{fork} e terminare immediatamente il processo padre + proseguendo l'esecuzione nel figlio. In questo modo si ha la certezza che + il figlio non è un \textit{process group leader}, (avrà il \acr{pgid} del + padre, ma un \acr{pid} diverso) e si può chiamare \func{setsid} con + successo. Inoltre la shell considererà terminato il comando all'uscita del + padre. +\item Eseguire \func{setsid} per creare una nuova sessione ed un nuovo + raggruppamento di cui il processo diventa automaticamente il leader, che + però non ha associato nessun terminale di controllo. +\item Assicurarsi che al processo non venga associato in seguito nessun nuovo + terminale di controllo; questo può essere fatto sia avendo cura di usare + sempre l'opzione \macro{O\_NOCTTY} nell'aprire i file di terminale, che + eseguendo una ulteriore \func{fork} uscendo nel padre e proseguendo nel + figlio. In questo caso, non essendo più quest'ultimo un leader di sessione + non potrà ottenere automaticamente un terminale di controllo. +\item Eseguire una \func{chdir} per impostare la directory di lavoro del + processo (su \file{/} o su una directory che contenga dei file necessari per + il programma), per evitare che la directory da cui si è lanciato il processo + resti in uso e non sia possibile rimuoverla o smontare il filesystem che la + contiene. +\item Impostare la maschera dei permessi (di solito con \code{umask(0)}) in + modo da non essere dipendenti dal valore ereditato da chi ha lanciato + originariamente il processo. +\item Chiudere tutti i file aperti che non servono più (in generale tutti); in + particolare vanno chiusi i file standard che di norma sono ancora associati + al terminale (un'altra opzione è quella di redirigerli verso + \file{/dev/null}). +\end{enumerate} + + +In Linux buona parte di queste azioni possono venire eseguite invocando la +funzione \func{daemon}, introdotta per la prima volta in BSD4.4; il suo +prototipo è: +\begin{prototype}{unistd.h}{int daemon(int nochdir, int noclose)} + Esegue le operazioni che distaccano il processo dal terminale di controllo e + lo fanno girare come demone. + + \bodydesc{La funzione restituisce (nel nuovo processo) 0 in caso di + successo, e -1 in caso di errore, nel qual caso \var{errno} assumerà i + valori impostati dalle sottostanti \func{fork} e \func{setsid}.} +\end{prototype} -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.} +La funzione esegue una \func{fork}, per uscire subito, con \func{\_exit}, nel +padre, mentre l'esecuzione prosegue nel figlio che esegue subito una +\func{setsid}. In questo modo si compiono automaticamente i passi 1 e 2 della +precedente lista. Se \param{nochdir} è nullo la funzione imposta anche la +directory di lavoro su \file{/}, se \param{noclose} è nullo i file standard +vengono rediretti su \file{/dev/null} (corrispondenti ai passi 4 e 6); in caso +di valori non nulli non viene eseguita nessuna altra azione. + +Dato che un programma demone non può più accedere al terminale, si pone il +problema di come fare per la notifica di eventuali errori, non potendosi più +utilizzare lo standard error; per il normale I/O infatti ciascun demone avrà +le sue modalità di interazione col sistema e gli utenti a seconda dei compiti +e delle funzionalità che sono sono previste; ma gli errori devono normalmente +essere notificati all'amministratore del sistema. + +Una soluzione può essere quella di scrivere gli eventuali messaggi su uno +specifico file (cosa che a volte viene fatta comunque) ma questo comporta il +grande svantaggio che l'amministratore dovrà tenere sotto controllo un file +diverso per ciascun demone, e che possono anche generarsi conflitti di nomi. +Per questo in BSD4.2 venne introdotto un servizio di sistema, il +\textit{syslog}, che oggi si trova su tutti i sistemi Unix, e che permettesse +ai demoni di inviare messaggi all'amministratore in una maniera +standardizzata. + +Il servizio prevede vari meccanismi di notifica, e, come ogni altro servizio +in un sistema unix-like, viene gestito attraverso un apposito programma, +\cmd{syslogd}, che è anch'esso un \textsl{demone}. In generale i messaggi di +errore vengono raccolti dal file speciale \file{/dev/log}, un \textit{socket} +locale (vedi \secref{sec:sock_sa_local}) dedicato a questo scopo, o via rete, +con un \textit{socket} UDP, o da un apposito demone, \cmd{klogd}, che estrae i +messaggi del kernel.\footnote{i messaggi del kernel sono tenuti in un buffer + circolare e scritti tramite la funzione \func{printk}, analoga alla + \func{printf} usata in user space; una trattazione eccellente dell'argomento + si trova in \cite{LinDevDri}, nel quarto capitolo.} + +Il servizio permette poi di trattare i vari messaggi classificandoli +attraverso due indici; il primo, chiamato \textit{facility}, indica quale +categoria di demone ha emesso il messaggio, ed è organizzato in sottosistemi +(kernel, posta elettronica, demoni di stampa, ecc.), il secondo, chiamato +\textit{priority}, identifica l'importanza del messaggio. Il sistema di +\textit{syslog} provvede poi a riportare i messaggi all'amministratore +attraverso differenti meccanismi come: +\begin{itemize*} +\item scrivere sulla console. +\item inviare via mail ad uno specifico utente. +\item scrivere su un file (comunemente detto \textit{log file}). +\item inviare ad un altro demone (anche via rete). +\item scartare. +\end{itemize*} +secondo le modalità che questo preferisce e che possono essere impostate +attraverso il file di configurazione \file{/etc/syslog.conf} (maggiori +dettagli si possono trovare sulle pagine di manuale per questo file e per +\cmd{syslogd}). + +Le \acr{glibc} definiscono una serie di funzioni standard con cui un processo +può accedere in maniera generica al servizio di syslog, che però funzionano +solo localmente; se si vogliono inviare i messaggi ad un'altro sistema occorre +farlo esplicitamente con un socket UDP, o utilizzare le capacità di reinvio +del servizio. + +La prima funzione definita dall'interfaccia è \func{openlog}, che apre una +connessione al servizio di \textit{syslog}; essa in generale non è necessaria +per l'uso del servizio, ma permette di impostare alcuni valori che controllano +gli effetti delle chiamate successive; il suo prototipo è: +\begin{prototype}{syslog.h}{void openlog(const char *ident, int option, +int facility)} + +Apre una connessione al sistema di \textit{syslog}. + +\bodydesc{La funzione non restituisce nulla.} +\end{prototype} + +La funzione permette di specificare, tramite \param{ident}, l'identità di chi +ha inviato il messaggio (di norma si passa il nome del programma, come +specificato da \code{argv[0]}); la stringa verrà preposta all'inizio di ogni +messaggio. Si tenga presente che il valore di \param{ident} che si passa alla +funzione è un puntatore, se la stringa cui punta viene cambiata lo sarà pure +nei successivi messaggi, e se viene cancellata i risultati potranno essere +impredicibili, per questo è sempre opportuno usare una stringa costante. + +L'argomento \param{facility} permette invece di preimpostare per le successive +chiamate l'omonimo indice che classifica la categoria del messaggio. +L'argomento è interpretato come una maschera binaria, e pertanto è possibile +inviare i messaggi su più categorie alla volta; i valori delle costanti che +identificano ciascuna categoria sono riportati in +\tabref{tab:sess_syslog_facility}, il valore di \param{facility} deve essere +specificato con un OR aritmetico. + +\begin{table}[htb] +\centering +\begin{tabular}[c]{|l|p{8cm}|} +\hline +\textbf{Valore}& \textbf{Significato}\\ +\hline +\hline +\macro{LOG\_AUTH} & Messaggi relativi ad autenticazione e sicurezza, + obsoleto, è sostituito da \macro{LOG\_AUTHPRIV}. \\ +\macro{LOG\_AUTHPRIV} & Sostituisce \macro{LOG\_AUTH}.\\ +\macro{LOG\_CRON} & Messaggi dei demoni di gestione dei comandi + programmati (\cmd{cron} e \cmd{at}).\\ +\macro{LOG\_DAEMON} & Demoni di sistema.\\ +\macro{LOG\_FTP} & Server FTP.\\ +\macro{LOG\_KERN} & Messaggi del kernel\\ +\macro{LOG\_LOCAL0} & Riservato all'amministratore per uso locale\\ +--- & \\ +\macro{LOG\_LOCAL7} & Riservato all'amministratore per uso locale\\ +\macro{LOG\_LPR} & Messaggi del sistema di gestione delle stampanti \\ +\macro{LOG\_MAIL} & Messaggi del sistema di posta elettronica\\ +\macro{LOG\_NEWS} & Messaggi del sistema di gestione delle news (USENET) \\ +\macro{LOG\_SYSLOG} & Messaggi generati dallo stesso \cmd{syslogd}\\ +\macro{LOG\_USER} & Messaggi generici a livello utente\\ +\macro{LOG\_UUCP} & Messaggi del sistema UUCP\\ +\hline +\end{tabular} +\caption{Valori possibili per l'argomento \param{facility} di \func{openlog}.} +\label{tab:sess_syslog_facility} +\end{table} + +L'argomento \param{option} serve invece per controllare il comportamento della +funzione \func{openlog} e delle modalità con cui le successive chiamate +scriveranno i messaggi, anch'esso viene specificato come maschera binaria +composta con un OR aritmetico di una qualunque delle costanti riportate in +\tabref{tab:sess_openlog_option}. + +\begin{table}[htb] +\centering +\begin{tabular}[c]{|l|p{8cm}|} +\hline +\textbf{Valore}& \textbf{Significato}\\ +\hline +\hline +\macro{LOG\_CONS} & Scrive sulla console quando. \\ +\macro{LOG\_NDELAY} & Sostituisce \macro{LOG\_AUTH}.\\ +\macro{LOG\_NOWAIT} & Messaggi dei demoni di gestione dei comandi + programmati (\cmd{cron} e \cmd{at}).\\ +\macro{LOG\_ODELAY} & .\\ +\macro{LOG\_PERROR} & Stampa anche su \file{stderr}.\\ +\macro{LOG\_PID} & Inserisce nei messaggi il \acr{pid} del processo + chiamante. \\ +\hline +\end{tabular} +\caption{Valori possibili per l'argomento \param{option} di \func{openlog}.} +\label{tab:sess_openlog_option} +\end{table} + +La funzione che si usa per generare un messaggio è \func{syslog}, dato che +l'uso di \func{openlog} è ozionale, sarà quest'ultima a provvede a chiamare la +prima qualora ciò non sia stato fatto (nel qual caso il valore di +\param{ident} è nullo). Il suo prototipo è: +\begin{prototype}{syslog.h} +{void syslog(int priority, const char *format, ...)} + +Genera un messaggio di priorità \param{priority}. + +\bodydesc{La funzione non restituisce nulla.} +\end{prototype} +Il comportamento della funzione è analogo quello di \func{printf}, e il valore +dell'argomento \param{format} è identico a quello descritto nella pagina di +manuale di quest'ultima (per i valori principali si può vedere la trattazione +sommaria che se ne è fatto in \secref{sec:file_formatted_io}); l'unica +differenza è che la sequenza \cmd{\%m} viene rimpiazzata dalla stringa +restituita da \code{strerror(errno)}. Gli argomenti seguenti i primi due +devono essere forniti secondo quanto richiesto da \func{format}. + + L'argomento \param{priority} permette di impostare sia la \textit{facility} + che la \textit{priority} del messaggio. In realtà viene prevalentemente usato + per specificare solo quest'ultima in quanto la prima viene di norma + preimpostata con \func{openlog}. La priorità è indicata con un valore + numerico\footnote{le \acr{glibc}, seguendo POSIX.1-2001, prevedono otto + diverse priorità ordinate da 0 a 7, in ordine di importanza decrescente; + questo comporta che i tre bit meno significativi dell'argomento + \param{priority} sono occupati da questo valore, mentre i restanti bit più + significativi vengono usati per specificare la \textit{facility}.} + specificabile attraverso le costanti riportate in + \secref{tab:sess_syslog_priority}. Nel caso si voglia specificare anche la + \textit{facility} basta eseguire un OR aritmetico del valore della priorità + con la maschera binaria delle costanti di \tabref{tab:sess_syslog_facility}. + +\begin{table}[htb] +\centering +\begin{tabular}[c]{|l|p{8cm}|} +\hline +\textbf{Valore}& \textbf{Significato}\\ +\hline +\hline +\macro{LOG\_EMERG} & Il sistema è inutilizzabile. \\ +\macro{LOG\_ALERT} & C'è una emergenza che richiede intervento immediato.\\ +\macro{LOG\_CRIT} & Si è in una condizione critica.\\ +\macro{LOG\_ERR} & Si è in una condizione di errore.\\ +\macro{LOG\_WARNING} & Messaggio di avvertimento.\\ +\macro{LOG\_NOTICE} & Notizia significativa relativa al comportamento.\\ +\macro{LOG\_INFO} & Messaggio informativo. \\ +\macro{LOG\_DEBUG} & Messaggio di debug.\\ +\hline +\end{tabular} + \caption{Valori possibili per l'indice di importanza del messaggio da + specificare nell'argomento \param{priority} di \func{syslog}.} +\label{tab:sess_syslog_priority} +\end{table} + + Una ulteriore funzione, \func{setlogmask}, permette di filtrare + preliminarmente i messaggi in base alla loro priorità; il suo prototipo è: +\begin{prototype}{syslog.h} + {int setlogmask(int mask)} + +Imposta la maschera dei log al valore specificato. + +\bodydesc{La funzione restituisce il precedente valore.} +\end{prototype} + +Le routine di gestione mantengono per ogni processo una maschera che +determina quale delle chiamate effettuate a \func{syslog} verrà +effettivamente registrata. La registrazione viene disabilitata per tutte +quelle priorità che non rientrano nella maschera; questa viene settata +usando la macro \code{LOG\_MASK(p)} dove \code{p} è una delle costanti di +\secref{tab:sess_syslog_priority}. É inoltre disponibile anche la macro +\code{LOG\_UPTO(p)} che permette di specificare automaticamente tutte le +priorità fino ad un certo valore. \section{L'I/O su terminale} \label{sec:sess_terminal_io} -Esamineremo in questa sezione le peculiarità dell'I/O su terminale, tenendo -conto delle +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: