From: Simone Piccardi Date: Tue, 9 Aug 2011 20:27:08 +0000 (+0000) Subject: Programma di test della syscall syslog, e revisione generale X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=commitdiff_plain;h=7a714b576c5f449ab288923e33c04069c0a90af0 Programma di test della syscall syslog, e revisione generale dell'argomento del capitolo sulle sessioni di lavoro con ristrutturazione dei titoli e della introduzione, + aggiornamenti per alcune parti obsolete. --- diff --git a/process.tex b/process.tex index dfb5d2b..2918deb 100644 --- a/process.tex +++ b/process.tex @@ -1832,15 +1832,14 @@ sono definite delle apposite macro; la procedura da seguire è la seguente: \item Dichiarare la conclusione dell'estrazione degli argomenti invocando la macro \macro{va\_end}. \end{enumerate*} + In generale è perfettamente legittimo richiedere meno argomenti di quelli che potrebbero essere stati effettivamente forniti, e nella esecuzione delle \macro{va\_arg} ci si può fermare in qualunque momento ed i restanti argomenti saranno ignorati; se invece si richiedono più argomenti di quelli forniti si -otterranno dei valori indefiniti. Nel caso del \cmd{gcc} l'uso della macro -\macro{va\_end} è inutile, ma si consiglia di usarlo ugualmente per -compatibilità. - -Le definizioni delle tre macro sono le seguenti: +otterranno dei valori indefiniti. Nel caso del \cmd{gcc} l'uso di +\macro{va\_end} è inutile, ma si consiglia di usarla ugualmente per +compatibilità. Le definizioni delle macro citate sono le seguenti: \begin{functions} \headdecl{stdarg.h} @@ -1859,12 +1858,11 @@ Le definizioni delle tre macro sono le seguenti: In generale si possono avere più puntatori alla lista degli argomenti, ciascuno andrà inizializzato con \macro{va\_start} e letto con \macro{va\_arg} -e ciascuno potrà scandire la lista degli argomenti per conto suo. - -Dopo l'uso di \macro{va\_end} la variabile \param{ap} diventa indefinita e -successive chiamate a \macro{va\_arg} non funzioneranno. Si avranno risultati -indefiniti anche chiamando \macro{va\_arg} specificando un tipo che non -corrisponde a quello dell'argomento. +e ciascuno potrà scandire la lista degli argomenti per conto suo. Dopo l'uso +di \macro{va\_end} la variabile \param{ap} diventa indefinita e successive +chiamate a \macro{va\_arg} non funzioneranno. Si avranno risultati indefiniti +anche chiamando \macro{va\_arg} specificando un tipo che non corrisponde a +quello dell'argomento. Un altro limite delle macro è che i passi 1) e 3) devono essere eseguiti nel corpo principale della funzione, il passo 2) invece può essere eseguito anche @@ -1874,13 +1872,12 @@ usato (lo standard richiederebbe la chiamata esplicita di \macro{va\_end}), dato che il valore di \param{ap} risulterebbe indefinito. Esistono dei casi in cui è necessario eseguire più volte la scansione degli -argomenti e poter memorizzare una posizione durante la stessa. La cosa più -naturale in questo caso sembrerebbe quella di copiarsi il puntatore alla lista -degli argomenti con una semplice assegnazione. Dato che una delle -realizzazioni più comuni di \macro{va\_list} è quella di un puntatore nello -\itindex{stack} \textit{stack} all'indirizzo dove sono stati salvati gli -argomenti, è assolutamente normale pensare di poter effettuare questa -operazione. +argomenti e poter memorizzare una posizione durante la stessa. In questo caso +sembrerebbe naturale copiarsi il puntatore alla lista degli argomenti con una +semplice assegnazione. Dato che una delle realizzazioni più comuni di +\macro{va\_list} è quella di un puntatore nello \itindex{stack} \textit{stack} +all'indirizzo dove sono stati salvati gli argomenti, è assolutamente normale +pensare di poter effettuare questa operazione. In generale però possono esistere anche realizzazioni diverse, per questo motivo \macro{va\_list} è definito come \index{tipo!opaco} \textsl{tipo opaco} @@ -2050,7 +2047,7 @@ interagiscono direttamente con la gestione dello \itindex{stack} \func{setjmp} è implementata con una macro, pertanto non si può cercare di ottenerne l'indirizzo, ed inoltre delle chiamate a questa funzione sono sicure solo in uno dei seguenti casi: -\begin{itemize} +\begin{itemize*} \item come espressione di controllo in un comando condizionale, di selezione o di iterazione (come \code{if}, \code{switch} o \code{while}); \item come operando per un operatore di uguaglianza o confronto in una @@ -2059,11 +2056,12 @@ solo in uno dei seguenti casi: \item come operando per l'operatore di negazione (\code{!}) in una espressione di controllo di un comando condizionale, di selezione o di iterazione; \item come espressione a sé stante. -\end{itemize} +\end{itemize*} In generale, dato che l'unica differenza fra la chiamata diretta e quella -ottenuta da un \func{longjmp} è costituita dal valore di ritorno di -\func{setjmp}, essa è usualmente chiamata all'interno di un comando \code{if}. +ottenuta nell'uscita con un \func{longjmp} è costituita dal valore di ritorno +di \func{setjmp}, quest'ultima usualmente viene chiamata all'interno di un +comando \code{if}. Uno dei punti critici dei salti non-locali è quello del valore delle variabili, ed in particolare quello delle variabili automatiche della funzione diff --git a/session.tex b/session.tex index a13f618..53a631d 100644 --- a/session.tex +++ b/session.tex @@ -9,39 +9,59 @@ %% License". %% -\chapter{Terminali e sessioni di lavoro} +\chapter{Interfaccia utente: terminali e sessioni di lavoro} \label{cha:session} -I terminali per lungo tempo sono stati l'unico modo per accedere al sistema, -per questo anche oggi che esistono molte altre interfacce, essi continuano a -coprire un ruolo particolare, restando strettamente legati al funzionamento -dell'interfaccia a linea di comando. -Nella prima parte del capitolo esamineremo i concetti base del sistema delle -sessioni di lavoro, vale a dire il metodo con cui il kernel permette ad un -utente di gestire le capacità multitasking del sistema, permettendo 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 il -suo uso come interfaccia di accesso al sistema da parte degli utenti. +A lungo l'unico modo per interagire con sistema di tipo Unix è stato tramite +l'interfaccia dei terminali, ma anche oggi, nonostante la presenza di diverse +interfacce grafiche, essi continuano ad essere estensivamente usati per il +loro stretto legame la linea di comando. + +Nella prima parte esamineremo i concetti base in cui si articola l'interfaccia +dei terminali, a partire dal sistema del \textit{job control} e delle sessioni +di lavoro, toccando infine anche le problematiche dell'interazione con +programmi non interattivi. Nella seconda parte tratteremo il funzionamento +dell'I/O su terminale, e delle varie peculiarità che esso viene ad assumere +nell'uso come interfaccia di accesso al sistema da parte degli utenti. La +terza parte coprirà le tematiche relative alla creazione e gestione dei +terminali virtuali, che consentono di replicare via software l'interfaccia dei +terminali. + -\section{Il \textit{job control}} +\section{L'interazione con i terminali} \label{sec:sess_job_control} +I terminali sono l'interfaccia con cui fin dalla loro nascita i sistemi +unix-like hanno gestito l'interazione con gli utenti, tramite quella riga di +comando che li caratterizza da sempre. Ma essi hanno anche una rilevanza +particolare perché quella dei terminali è l'unica interfaccia hardware usata +dal kernel per comunicare direttamente con gli utenti, con la cosiddetta +\textit{console} di sistema, senza dover passare per un programma. + +Originariamente si trattava di dispositivi specifici (i terminali seriali, se +non addirittura le telescriventi). Oggi questa interfaccia viene in genere +emulata o tramite programmi o con le cosiddette console virtuali associate a +monitor e tastiera, ma esiste sempre la possibilità di associarla direttamente +ad alcuni dispositivi, come eventuali linee seriali.\footnote{ed in certi + casi, come buona parte dei dispositivi embedded su cui gira Linux (come + router, access point, ecc.) questa resta anche l'unica opzione per una + \textit{console} di sistema.} + + +\subsection{Il \textit{job control}} +\label{sec:sess_job_control_overview} + 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 - \textit{X Window} 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} + le interfacce grafiche di \textit{X Window} e con i terminali virtuali via + rete 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. Il \textit{job control} è una caratteristica opzionale, introdotta in BSD negli anni '80, e successivamente standardizzata da POSIX.1; la sua @@ -63,44 +83,47 @@ Siccome la shell è collegata ad un solo terminale, che viene usualmente chiamato \textsl{terminale di controllo}, (vedi sez.~\ref{sec:sess_ctrl_term}) un solo comando alla volta (quello che viene detto in \textit{foreground} o in \textsl{primo piano}), potrà scrivere e leggere dal terminale. La shell però -può eseguire, aggiungendo una \cmd{\&} alla fine del comando, più programmi in -contemporanea, mandandoli in \textit{background} (o \textsl{sullo sfondo}), -nel qual caso essi saranno eseguiti senza essere collegati al terminale. +può eseguire, aggiungendo una ``\cmd{\&}'' alla fine del comando, più +programmi in contemporanea, mandandoli in \textit{background} (o \textsl{sullo + sfondo}), 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 sotto-processi per eseguire dei compiti specifici. +eseguiti più programmi. Inoltre, anche quando si invoca un singolo programma, +questo potrà sempre lanciare eventuali sotto-processi 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 -\itindex{process~group} \textit{process group} (detto anche -\textsl{raggruppamento di processi}, vedi sez.~\ref{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) \itindex{process~group} \textit{process group} in -\textit{foreground}, che riunisce i processi che possono accedere al -terminale, e più \itindex{process~group} \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 sez.~\ref{sec:sess_ctrl_term}). +nella gestione del \textit{job control} non si può far riferimento ai singoli +processi. Per questo il kernel prevede la possibilità di raggruppare più +processi in un cosiddetto \itindex{process~group} \textit{process group} +(detto anche \textsl{raggruppamento di processi}, vedi +sez.~\ref{sec:sess_proc_group}). Deve essere cura della shell far sì che tutti +i processi che originano da una stessa riga di comando appartengano allo +stesso raggruppamento di processi, in modo che le varie funzioni di controllo, +ed i segnali inviati dal terminale, possano fare riferimento ad esso. + +In generale all'interno di una sessione avremo un eventuale (può non esserci) +\itindex{process~group} \textit{process group} in \textit{foreground}, che +riunisce i processi che possono accedere al terminale, e più +\itindex{process~group} \textit{process group} in \textit{background}, che non +possono accedervi. Il \textit{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 sez.~\ref{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 +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}. + comportano l'esecuzione di un programma esterno ma operazioni di gestione + compiute direttamente dalla shell stessa.} 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à @@ -493,19 +516,23 @@ 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 \conffile{/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 fig.~\ref{fig:sess_term_login}. +Nella maggior parte delle distribuzioni di GNU/Linux\footnote{in realtà negli + ultimi tempi questa situazione sta cambiando, e sono state proposte diversi + possibili rimpiazzi per il tradizionale \texttt{init} di System V, come + \texttt{upstart} o \texttt{systemd}, ma per quanto trattato in questa + sezione il risultato finale non cambia, si avrà comunque il lancio di un + programma che consenta l'accesso al terminale.} viene usata la procedura di +avvio di System V; questa prevede che \cmd{init} legga dal file di +configurazione \conffile{/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 \textit{run level}, (per il quale +si rimanda alla lettura delle pagine di manuale di \cmd{init} e di +\file{inittab} o alla trattazione in sez.~5.3.5 di \cite{AGL}) 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 fig.~\ref{fig:sess_term_login}. \begin{figure}[htb] \centering @@ -546,8 +573,8 @@ 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 +quanto necessario; ad esempio di solito viene opportunamente inizializzata la +variabile di ambiente \texttt{TERM} per 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 @@ -562,17 +589,22 @@ o se la password non corrisponde\footnote{il confronto non viene effettuato certo numero di volte dopo di che \cmd{login} esce ed \cmd{init} provvede a rilanciare un'altra istanza di \cmd{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{setgid} e \func{initgroups} -verrà cambiata l'identità del proprietario del processo, infatti, come -spiegato in sez.~\ref{sec:proc_setuid}, avendo invocato tali funzioni con i -privilegi di amministratore, tutti gli user-ID ed i group-ID (reali, effettivi -e salvati) saranno impostati a quelli dell'utente. +Se invece la password corrisponde \cmd{login} esegue \func{chdir} per +impostare come directory di lavoro 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.\footnote{oggi queste operazioni, + insieme ad altre relative alla contabilità ed alla tracciatura degli + accessi, vengono gestite dalle distribuzioni più recenti in una maniera + generica appoggiandosi a servizi di sistema come \textit{ConsoleKit}, ma il + concetto generale resta sostanzialmente lo stesso.} 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{setgid} e \func{initgroups} verrà cambiata l'identità del proprietario +del processo, infatti, come spiegato in sez.~\ref{sec:proc_setuid}, avendo +invocato tali funzioni con i privilegi di amministratore, tutti gli user-ID ed +i group-ID (reali, effettivi e salvati) saranno impostati 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) @@ -589,7 +621,8 @@ ripetere da capo tutto il procedimento. -\subsection{Le prescrizioni per un \textsl{demone} ed il \textit{syslog}} +\subsection{Interazione senza terminale: i \textsl{demoni} ed il + \textit{syslog}} \label{sec:sess_daemon} Come sottolineato fin da sez.~\ref{sec:intro_base_concept}, in un sistema @@ -624,7 +657,7 @@ prescrizioni\footnote{ad esempio sia Stevens in \cite{APUE}, che la Pertanto, quando si lancia un programma che deve essere eseguito come demone occorrerà predisporlo in modo che esso compia le seguenti azioni: -\begin{enumerate} +\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 \itindex{process~group~leader} \textit{process group @@ -652,7 +685,7 @@ occorrerà predisporlo in modo che esso compia le seguenti azioni: 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} +\end{enumerate*} In Linux buona parte di queste azioni possono venire eseguite invocando la @@ -831,7 +864,7 @@ tab.~\ref{tab:sess_openlog_option}. La funzione che si usa per generare un messaggio è \funcd{syslog}, dato che l'uso di \func{openlog} è opzionale, 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 è: +\param{ident} è \val{NULL}). Il suo prototipo è: \begin{prototype}{syslog.h} {void syslog(int priority, const char *format, ...)} @@ -886,8 +919,34 @@ con la maschera binaria delle costanti di tab.~\ref{tab:sess_syslog_facility}. \label{tab:sess_syslog_priority} \end{table} -Una ulteriore funzione, \funcd{setlogmask}, permette di filtrare -preliminarmente i messaggi in base alla loro priorità; il suo prototipo è: +Una funzione sostanzialmente identica a \func{syslog}, la cui sola differenza +è prendere invece di una lista esplicita di argomenti un unico argomento +finale nella forma di una lista di argomenti passato come \macro{va\_list}, +utile qualora si ottengano questi nella invocazione di una funzione +\index{variadic} \textit{variadic} (si rammenti quanto visto in +sez.~\ref{sec:proc_variadic}), è \funcd{vsyslog},\footnote{la funzione è + originaria di BSD e per utilizzarla deve essere definito + \macro{\_BSD\_SOURCE}.} il suo prototipo è: +\begin{prototype}{syslog.h} +{void vsyslog(int priority, const char *format, va\_list src)} + +Genera un messaggio di priorità \param{priority}. + +\bodydesc{La funzione non restituisce nulla.} +\end{prototype} + + +Per semplificare la gestione della scelta del livello di priorità a partire +dal quale si vogliono registrare i messaggi, le funzioni di gestione +mantengono per ogni processo una maschera che determina quale delle chiamate +effettuate a \func{syslog} verrà effettivamente registrata. In questo modo +sarà possibile escludere, impostando opportunamente la maschera una volta per +tutte, i livelli di priorità che non interessa registrare.\footnote{questo + significa che in genere nei programmi vengono comunque previste le chiamate + a \func{syslog} per tutti i livelli di priorità, ma poi si imposta questa + maschera per registrare solo quello che effettivamente interessa.} La +funzione che consente di fare questo è \funcd{setlogmask}, ed il suo prototipo +è: \begin{prototype}{syslog.h}{int setlogmask(int mask)} Imposta la maschera dei log al valore specificato. @@ -895,27 +954,120 @@ Imposta la maschera dei log al valore specificato. \bodydesc{La funzione restituisce il precedente valore.} \end{prototype} -Le funzioni 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 impostata usando la macro -\macro{LOG\_MASK(p)} dove \code{p} è una delle costanti di -tab.~\ref{tab:sess_syslog_priority}. É inoltre disponibile anche la macro -\macro{LOG\_UPTO(p)} che permette di specificare automaticamente tutte le -priorità fino ad un certo valore. +La funzione restituisce il valore della maschera corrente, e se si passa un +valore nullo per \param{mask} la maschera corrente non viene modificata; in +questo modo si può leggere il valore della maschera corrente. Indicando un +valore non nullo per \param{mask} la registrazione dei messaggi viene +disabilitata per tutte quelle priorità che non rientrano nella maschera. In +genere il valore viene impostato usando la macro \macro{LOG\_MASK(p)} dove +\code{p} è una delle costanti di tab.~\ref{tab:sess_syslog_priority}. É +inoltre disponibile anche la macro \macro{LOG\_UPTO(p)} che permette di +specificare automaticamente tutte le priorità fino a quella indicata da +\code{p}. -\itindend{syslog} +Una volta che si sia certi che non si intende registrare più nessun messaggio +si può chiudere esplicitamente la connessione al \textit{syslog} con la +funzione \funcd{closelog}, il cui prototipo è: +\begin{prototype}{syslog.h}{void closelog(void)} +Chiude la connessione al \textit{syslog}. -Oltre ai vari demoni, il servizio viene utilizzato anche dal kernel per -comunicare messaggi in user space, in questo caso +\bodydesc{La funzione non restituisce nulla.} +\end{prototype} +\noindent l'uso di questa funzione è comunque completamente opzionale. + +Come si evince anche dalla presenza della facility \const{LOG\_KERN} in +tab.~\ref{tab:sess_syslog_facility}, uno dei possibili utenti del servizio del +\textit{syslog} è anche il kernel, che a sua volta può avere necessità di +inviare messaggi verso l'\textit{user space}. I messaggi del kernel sono +mantenuti in un apposito buffer circolare e generati all'interno del kernel +tramite la funzione \func{printk}, analoga alla \func{printf} usata in +\textit{user space}.\footnote{una trattazione eccellente dell'argomento si + trova nel quarto capitolo di \cite{LinDevDri}.} + +Come per i messaggi ordinari anche i messaggi del kernel hanno una priorità ma +in questo caso non si può contare sulla coincidenza con le costanti di +tab.~\ref{tab:sess_syslog_priority} dato che il codice del kernel viene +mantenuto in maniera indipendente dalle librerie. Per questo motivo le varie +priorità usate dal kernel sono associate ad un valore numerico che viene +tradotto in una stringa preposta ad ogni messaggio, secondo i valori che si +sono riportati in fig.~\ref{fig:printk_priority} +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{15cm} + \includestruct{listati/printk_prio.c} + \end{minipage} + \normalsize + \caption{Definizione delle stringe coi relativi valori numerici che indicano + le priorità dei messaggi del kernel, ripresa da \texttt{linux/kernel.h}.} + \label{fig:printk_priority} +\end{figure} + +Dato che i messaggi generati da \func{printk} hanno un loro specifico formato, +tradizionalmente si usava un demone ausiliario, \cmd{klogd}, per leggerli, +rimappare le priorità sui valori di tab.~\ref{tab:sess_syslog_priority} e +inviarli al sistema del \textit{syslog} nella facility \const{LOG\_KERN}, +anche se oggi i nuovi demoni che realizzano il servizio (come \texttt{rsyslog} +o \texttt{syslog-ng}) sono in grado di fare tutto questo da soli. + +Ma i messaggi del kernel non sono necessariamente connessi al sistema del +\textit{syslog}; ad esempio possono anche essere letti direttamente dal buffer +con il comando \texttt{dmesg}. Inoltre è previsto che essi vengano anche +stampati direttamente sul terminale indicato come console di +sistema,\footnote{quello che viene indicato con il parametro di avvio + \texttt{console} del kernel, si consulti al riguardo sez.~5.3.1 di + \cite{AGL}.} se superano una certa priorità, in modo che sia possibile +vederli anche in caso di blocco totale del sistema (nell'assunzione che la +console sia collegata). + +In particolare la stampa dei messaggi sulla console è controllata con +\procfile{/proc/sys/kernel/printk} (o dall'equivalente parametro di +\func{sysctl}) che prevede quattro valori numerici interi: il primo indica la +priorità di base oltre la quale vengono stampati i messaggi sulla console, il +secondo la priorità di default assegnata ai messaggi che non ne hanno +impostata una, il terzo il valore minimo che si può assegnare al primo +valore,\footnote{quello che può essere usato con una delle operazioni di + gestione che vedremo a breve per ``\textsl{silenziare}'' il kernel. } ed il +quarto come valore di default.\footnote{anch'esso viene usato nelle operazioni + di controllo per tornare ad un valore predefinito.} + +Per la lettura dei messaggi del kernel e la gestione del relativo buffer +circolare esiste una apposita \textit{system call} chiamata anch'essa +\texttt{syslog}, ma dato il conflitto di nomi questa viene rimappata su +un'altra funzione di libreria, in particolare nelle \acr{glibc} essa viene +invocata tramite la funzione \funcd{klogctl}, il cui prototipo è: +\begin{prototype}{sys/klog.h}{int klogctl(int op, char *buffer, int len)} + +Gestisce il buffer dei messaggi di log del kernel. + +\bodydesc{La funzione restituisce un intero positivo dipendente + dall'operazione scelta o $-1$ in caso di errore, nel qual caso \var{errno} + assumerà i valori: + \begin{errlist} + \item[\errcode{EINVAL}] l'argomento \param{op} non ha un valore valido. + \item[\errcode{ERESTARTSYS}] l'operazione è stata interrotta da un segnale. + \item[\errcode{EPERM}] non si hanno i privilegi richiesti per l'operazione. + \item[\errcode{ENOSYS}] il supporto per \func{printk} non è stato compilato + nel kernel. + \end{errlist} + ed inoltre \errval{EBADF} ed \errval{ENOSYS}. +} +\end{prototype} - 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.} + + +La lettura dei messaggi del kernel può avvenire direttamente da + + +Il funzionamento del kernel prevede anche che sia possibile indicare quali +messaggi di \func{printk} devono essere stampati direttamente sulla console, +con la possibilità di impostare + + + + +\itindend{syslog} @@ -2016,7 +2168,7 @@ Qui vanno spiegati i terminali virtuali, \file{/dev/pty} e compagnia. % vedi man pts -\subsection{Allocazione dei terminale virtuali} +\subsection{Allocazione dei terminali virtuali} \label{sec:sess_openpty} Qui vanno le cose su \func{openpty} e compagnia. @@ -2062,11 +2214,12 @@ Qui vanno le cose su \func{openpty} e compagnia. % LocalWords: interrupt VQUIT VERASE VKILL VEOF VTIME VMIN VSWTC switch VSTART % LocalWords: VSTOP VSUSP VEOL VREPRINT VDISCARD VWERASE VLNEXT escape actions % LocalWords: tcgetattr tcsetattr EINTR TCSANOW TCSADRAIN TCSAFLUSH speed MIN -% LocalWords: SetTermAttr UnSetTermAttr cfsetispeed cfsetospeed cfgetispeed -% LocalWords: cfgetospeed quest'ultime tcsendbreak duration break tcdrain +% LocalWords: SetTermAttr UnSetTermAttr cfsetispeed cfsetospeed cfgetispeed ng +% LocalWords: cfgetospeed quest'ultime tcsendbreak duration break tcdrain list % LocalWords: tcflush queue TCIFLUSH TCOFLUSH TCIOFLUSH tcflow action TCOOFF -% LocalWords: TCOON TCIOFF TCION timer openpty Window nochdir - +% LocalWords: TCOON TCIOFF TCION timer openpty Window nochdir embedded router +% LocalWords: access point upstart systemd rsyslog vsyslog variadic src linux +% LocalWords: closelog dmesg sysctl klogctl sys ERESTARTSYS %%% Local Variables: %%% mode: latex diff --git a/sources/mydmesg.c b/sources/mydmesg.c new file mode 100644 index 0000000..268d248 --- /dev/null +++ b/sources/mydmesg.c @@ -0,0 +1,159 @@ +/* mydmesg.c + * + * Copyright (C) 2011 Simone Piccardi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/***************************************************************************** + * + * File mydmesg.c: An example for klogctl function + * + * Author: S. Piccardi Aug. 2011 + * + *****************************************************************************/ +#include /* primitive system data types */ +#include /* file characteristics constants and functions */ +#include /* C standard library */ +#include /* standard I/O library */ +#include /* unix standard library */ +#include + + +/* + * Program mydmesg + */ +/* Help printing routine */ +void usage(void); + +int main(int argc, char *argv[]) +{ +/* + * Variables definition + */ + int i, len, cmd=0, level=7, third; + char * buffer; + char * err_msg[]= { + "This is a NOP so it should'nt happen", + "This is a NOP so it should'nt happen", + "Error on reading kernel log buffer last messages", + "Error on reading kernel log buffer", + "Error on reading kernel and clearing log buffer", + "Error on clearing log buffer", + "Error on setting console log level to minimum", + "Error on setting console log level to default", + "Error on setting console log level", + "Error on reading unread message size", + "Error on reading log buffer size" + }; + /* + * Input section: decode command line parameters + * Use getopt function + */ + opterr = 0; /* don't want writing to stderr */ + while ( (i = getopt(argc, argv, "c:l:h")) != -1) { + switch (i) { + /* + * Handling options + */ + case 'h': /* help option */ + printf("Wrong -h option use\n"); + usage(); + return -1; + break; + case 'c': /* klogctl command */ + cmd = strtol(optarg, NULL, 10); /* convert input */ + break; + case 'l': /* log level */ + level = strtol(optarg, NULL, 10); /* convert input */ + break; + case '?': /* unrecognized options */ + printf("Unrecognized options -%c\n",optopt); + usage(); + default: /* should not reached */ + usage(); + } + } + /* *********************************************************** + * + * Options processing completed + * + * Main code beginning + * + * ***********************************************************/ + if ((argc - optind) != 0) { /* There must be 0 remaing arguments */ + printf("Wrong number of arguments %d\n", argc - optind); + usage(); + } + if ((cmd < 1) || (cmd>10)) { + printf("You must give a value between 1 and 10 for the -c option\n"); + usage(); + } + i = klogctl(10, NULL, 0); + if ((buffer = malloc(i+1)) == NULL) { + printf("Cannot allocate buffer for %d bytes\n", i); + exit(1); + } else { + printf("Allocated %d bytes\n", i); + } + + /* setting third argument */ + if (cmd == 8) third=level; + else third=i; + + + if ((len = klogctl(cmd, buffer, third)) < 0) { + perror(err_msg[cmd]); + exit(0); + } + + switch (cmd) + { + case 2: + case 3: + case 4: + printf("Debug, cmd = %d\n", cmd); + printf("Debug, len = %d\n", len); + buffer[len]=0; + printf("%s", buffer); + exit(0); + case 5: + case 6: + case 7: + case 8: + printf("Operation %d executed", cmd); + exit(0); + case 9: + printf("Kernel log buffer ring has %d bytes\n", len); + exit(0); + case 10: + printf("Kernel log buffer ring is %d bytes\n", len); + exit(0); + } + + + exit(0); +} +/* + * routine to print usage info and exit + */ +void usage(void) { + printf("Program mydmesg: klogctl testing \n"); + printf("Usage:\n"); + printf(" mydmesg [-h] [-l N] -c command \n"); + printf(" -h print this help\n"); + printf(" -c klogctl command (mandatory)\n"); + printf(" -l level\n"); + exit(1); +}