X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=system.tex;h=1e5a20f878d802c0e87002f56354df4d592b8d25;hp=b617a0c7a15a76af716c1cdbfb0338ac89611afe;hb=85acea6db3dceef49bbaf7b02f73895425ea1168;hpb=5fed12c59e5b3c15ee37d76a55202f0cce9b994a diff --git a/system.tex b/system.tex index b617a0c..1e5a20f 100644 --- a/system.tex +++ b/system.tex @@ -1,4 +1,4 @@ -fo \chapter{La gestione del sistema, delle risorse, e degli errori} +\chapter{La gestione del sistema, delle risorse, e degli errori} \label{cha:system} In questo capitolo tratteremo varie interfacce che attengono agli aspetti più @@ -903,14 +903,14 @@ struct statfs { Le \acr{glibc} provvedono infine una serie di funzioni per la gestione dei due -file standard \file{/etc/fstab} e \file{/etc/mtab}, che convenzionalmente sono -usati in quasi tutti i sistemi unix-like per mantenere rispettivamente le -informazioni riguardo ai filesystem da montare e a quelli correntemente -montati. Le funzioni servono a leggere il contenuto di questi file in -opportune strutture \var{struct fstab} e \var{struct mntent}, e, per -\file{/etc/mtab} per inserire e rimuovere le voci presenti nel file. - -In generale si dovrebbero usare queste funzioni (in particolar modo quelle +file \file{/etc/fstab} ed \file{/etc/mtab}, che convenzionalmente sono usati in +quasi tutti i sistemi unix-like per mantenere rispettivamente le informazioni +riguardo ai filesystem da montare e a quelli correntemente montati. Le +funzioni servono a leggere il contenuto di questi file in opportune strutture +\var{struct fstab} e \var{struct mntent}, e, per \file{/etc/mtab} per inserire +e rimuovere le voci presenti nel file. + +In generale si dovrebbero usare queste funzioni (in particolare quelle relative a \file{/etc/mtab}), quando si debba scrivere un programma che effettua il montaggio di un filesystem; in realtà in questi casi è molto più semplice invocare direttamente il programma \cmd{mount}, per cui ne @@ -1804,8 +1804,9 @@ ricevuto lo stato di terminazione, e lo stesso vale per \var{tms\_cstime}. Si tenga conto che l'aggiornamento di \var{tms\_cutime} e \var{tms\_cstime} viene eseguito solo quando una chiamata a \func{wait} o \func{waitpid} è -ritornata. Per questo motivo se un figlio termina prima di altri suoi figli, -questi ``nipoti'' non potranno essere considerati nel calcolo di questi tempi. +ritornata. Per questo motivo se un processo figlio termina prima di ricevere +lo stato di teminazione di tutti i suoi figli, questi processi ``nipoti'' non +verranno considerati nel calcolo di questi tempi. @@ -1816,7 +1817,7 @@ Come anticipato in \secref{sec:sys_unix_time} il \textit{calendar time} mantenuto dal kernel in una variabile di tipo \type{time\_t}, che usualmente corrisponde ad un tipo nativo (in Linux è un intero a 32 bit). Il valore corrente del \textit{calendar time}, che indicheremo come \textsl{tempo di - sistema} può essere ottenuto con la funzione \func{time} che lo restituisce + sistema}, può essere ottenuto con la funzione \func{time} che lo restituisce in nel suddetto formato; il suo prototipo è: \begin{prototype}{time.h}{time\_t time(time\_t *t)} Legge il valore corrente del \textit{calendar time}. @@ -1824,8 +1825,8 @@ in nel suddetto formato; il suo prototipo \bodydesc{La funzione ritorna il valore del \textit{calendar time} in caso di successo e -1 in caso di errore, che può essere solo \macro{EFAULT}.} \end{prototype} -\noindent dove \param{t}, se non nullo, è l'indirizzo su cui salvare il valore -di ritorno. +\noindent dove \param{t}, se non nullo, deve essere l'indirizzo di una +variabile su cui duplicare il valore di ritorno. Analoga a \func{time} è la funzione \func{stime} che serve per effettuare l'operazione inversa, e cioè per settare il tempo di sistema qualora questo @@ -1844,7 +1845,11 @@ altrimenti la chiamata fallir Data la scarsa precisione nell'uso di \type{time\_t} (che ha una risoluzione massima di un secondo) quando si devono effettuare operazioni sui tempi di norma l'uso delle funzioni precedenti è sconsigliato, ed esse sono di solito -sostituite da \func{gettimeofday} e \func{settimeofday}, i cui prototipi sono: +sostituite da \func{gettimeofday} e \func{settimeofday},\footnote{le due + funzioni \func{time} e \func{stime} sono più antiche e derivano da SVr4, + \func{gettimeofday} e \func{settimeofday} sono state introdotte da BSD, ed + in BSD4.3 sono indicate come sostitute delle precedenti.} i cui prototipi +sono: \begin{functions} \headdecl{sys/time.h} \headdecl{time.h} @@ -1864,18 +1869,17 @@ sostituite da \func{gettimeofday} e \func{settimeofday}, i cui prototipi sono: \macro{EPERM}.} \end{functions} -Queste funzioni utilizzano una struttura di tipo \var{timeval} che consente di -indicare intervalli o tempi con precisioni maggiori del secondo, in realtà le -\acr{glibc} provvedono due rappresentazioni alternative del \textit{calendar - time}, le strutture \var{timeval} e \var{timespec}, le cui definizioni sono -riportate in \figref{fig:sys_timeval_struct} e che consentono rispettivamente -precisioni del microsecondo e del nanosecondo.\footnote{la precisione è solo - astratta, l'orologio di sistema normalmente non è in grado di misuare dei - tempi con precisioni simili.} +Queste funzioni utilizzano una struttura di tipo \var{timeval}, la cui +definizione, insieme a quella della analoga \var{timespec}, è riportata in +\figref{fig:sys_timeval_struct}. Le \acr{glibc} infatti forniscono queste due +rappresentazioni alternative del \textit{calendar time} che rispetto a +\type{time\_t} consentono rispettivamente precisioni del microsecondo e del +nanosecondo.\footnote{la precisione è solo teorica, la precisione reale della + misura del tempo dell'orologio di sistema non dipende dall'uso di queste + strutture.} \begin{figure}[!htb] - \footnotesize - \centering + \footnotesize \centering \begin{minipage}[c]{15cm} \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{} struct timeval @@ -1891,24 +1895,28 @@ struct timespec { \end{minipage} \normalsize \caption{Le strutture \var{timeval} e \var{timespec} usate per una - rappresetnazione ad alta risoluzione del \textit{calendar time}.} + rappresentazione ad alta risoluzione del \textit{calendar time}.} \label{fig:sys_timeval_struct} \end{figure} -Come nel caso di \func{stime} anche \func{settimeofday} può essere utilizzata -solo da un processo coi privilegi di amministratore. Il secondo parametro di -entrambe le funzioni è una struttura \var{timezone}, che storicamente veniva -utilizzata per specificare appunto la \textit{timezone}, cioè l'insieme del -fuso orario e delle convenzioni per l'ora legale. Questo parametro è obsoleto -e in Linux non è mai stato utilizzato e non è supportato né dalle vecchie -\textsl{libc5}, né dalle \textsl{glibc}, e deve essere settato a \macro{NULL}. +Come nel caso di \func{stime} anche \func{settimeofday} (e qualunque funzione +vada a modificare l'orologio di sistema, come quelle che tratteremo in +seguito) può essere utilizzata solo da un processo coi privilegi di +amministratore. Il secondo parametro di entrambe le funzioni è una struttura +\var{timezone}, che storicamente veniva utilizzata per specificare appunto la +\textit{timezone}, cioè l'insieme del fuso orario e delle convenzioni per +l'ora legale che permettevano il passaggio dal tempo universale all'ora +locale. Questo parametro è obsoleto e in Linux non è mai stato utilizzato e +non è supportato né dalle vecchie \textsl{libc5}, né dalle \textsl{glibc}: +pertanto deve essere sempre settato a \macro{NULL}. Modificare l'orologio di sistema con queste funzioni è comunque problematico, -in quanto esse effettuano un cambiamento immediato, così ad esempio se si -porta avanti l'orologio si possono perdere delle esecuzioni di \cmd{cron} -programmate nell'intervallo che si è saltato. Per questo motivo la modalità -più corretta per settare l'ora è quella di usare la funzione \func{adjtime}, -il cui prototipo è: +in quanto esse effettuano un cambiamento immediato. Questo può creare dei +buchi o delle ripetizioni nello scorrere dell'orologio di sistema, con +conseguenze indesiderate; ad esempio se si porta avanti l'orologio si possono +perdere delle esecuzioni di \cmd{cron} programmate nell'intervallo che si è +saltato. Per questo motivo la modalità più corretta per settare l'ora è quella +di usare la funzione \func{adjtime}, il cui prototipo è: \begin{prototype}{sys/time.h} {int adjtime(const struct timeval *delta, struct timeval *olddelta)} @@ -1919,28 +1927,303 @@ il cui prototipo \end{prototype} Questa funzione permette di avere un aggiustamento graduale del tempo di -sistema in modo che esso sia sempre monotonicamente crescente. Il valore di -\param{delta} esprime il valore di cui si vuole spostare l'orologio; se è +sistema in modo che esso sia sempre crescente in maniera monotona. Il valore +di \param{delta} esprime il valore di cui si vuole spostare l'orologio; se è positivo l'orologio sarà accelerato per un certo tempo in modo da guadagnare il tempo richiesto, altrimenti sarà rallentato. Il secondo parametro viene -usato, se non nullo, per ricavare il valore del precedente aggiustamento. +usato, se non nullo, per ricevere il valore dell'ultimo aggiustamento +effettuto. Linux poi prevede un'altra funzione, \func{adjtimex}, che consente un -aggiustamento più dettagliato permettendo anche di modificare anche la -velocità dell'orologio di sistema. Il suo prototipo è: -\begin{prototype}{sys/time.h} +aggiustamento molto più dettagliato, permettendo ad esempio anche di +modificare anche la velocità dell'orologio di sistema. Il suo prototipo è: +\begin{prototype}{sys/timex.h} {int adjtimex(struct timex *buf)} Aggiusta del valore \param{delta} l'orologio di sistema. - \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di - errore, nel qual caso \var{errno} assumerà il valore \macro{EPERM}.} + \bodydesc{La funzione restituisce lo stato dell'orologio (un valore $>0$) in + caso di successo e -1 in caso di errore, nel qual caso \var{errno} + assumerà i valori \macro{EFAULT}, \macro{EINVAL} ed \macro{EPERM}.} \end{prototype} +La funzione richiede una struttura di tipo \var{timex}, la cui definizione, +così come effettuata in \file{sys/timex.h}, è riportata in +\figref{fig:sys_timex_struct}. L'azione della funzione dipende dal valore del +campo \var{mode}, che specifica quale parametro dell'orologio di sistema, +specificato in un opportuno campo di \var{timex}, deve essere settato. Un +valore nullo serve per leggere i parametri correnti; i valori diversi da zero +devono essere specificati come OR binario delle costanti riportate in +\secref{tab:sys_timex_mode}. + +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{15cm} + \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{} +struct timex { + unsigned int modes; /* mode selector */ + long int offset; /* time offset (usec) */ + long int freq; /* frequency offset (scaled ppm) */ + long int maxerror; /* maximum error (usec) */ + long int esterror; /* estimated error (usec) */ + int status; /* clock command/status */ + long int constant; /* pll time constant */ + long int precision; /* clock precision (usec) (read only) */ + long int tolerance; /* clock frequency tolerance (ppm) (read only) */ + struct timeval time; /* (read only) */ + long int tick; /* (modified) usecs between clock ticks */ + long int ppsfreq; /* pps frequency (scaled ppm) (ro) */ + long int jitter; /* pps jitter (us) (ro) */ + int shift; /* interval duration (s) (shift) (ro) */ + long int stabil; /* pps stability (scaled ppm) (ro) */ + long int jitcnt; /* jitter limit exceeded (ro) */ + long int calcnt; /* calibration intervals (ro) */ + long int errcnt; /* calibration errors (ro) */ + long int stbcnt; /* stability limit exceeded (ro) */ +}; + \end{lstlisting} + \end{minipage} + \normalsize + \caption{La struttura \var{timex} per il controllo dell'orologio di sistema.} + \label{fig:sys_timex_struct} +\end{figure} + +La funzione utilizza il meccanismo di David L. Mills, descritto nell'RFC~1305, +che è alla base del protocollo NTP; la funzione è specifica di Linux e non +deve essere usata se la portabilità è un requisito, le \acr{glibc} provvedono +anche un suo omonimo \func{ntp\_adjtime}. La trattazione completa di questa +funzione necessita di una lettura approfondita del meccanismo descritto +nell'RFC~1305, ci limitiamo a descrivere in \tabref{tab:sys_timex_mode} i +principali valori utilizzabili per il campo \var{mode}, un elenco più +dettagliato del significato dei vari campi della struttura \var{timex} può +essere ritrovato in \cite{glibc}. + +\begin{table}[htb] + \footnotesize + \centering + \begin{tabular}[c]{|l|c| p{10cm}|} + \hline + \textbf{Nome} & \textbf{Valore} & \textbf{Significato}\\ + \hline + \hline + \macro{ADJ\_OFFSET} & 0x0001 & Setta la differenza fra il tempo + reale e l'orologio di sistema, che + deve essere indicata in microsecondi + nel campo \var{offset} di + \var{timex}.\\ + \macro{ADJ\_FREQUENCY} & 0x0002 & Setta la differenze in frequenza + fra il tempo reale e l'orologio di + sistema, che deve essere indicata + in parti per milione nel campo + \var{frequency} di \var{timex}.\\ + \macro{ADJ\_MAXERROR} & 0x0004 & Setta il valore massimo dell'errore + sul tempo, espresso in microsecondi + nel campo \var{maxerror} di + \var{timex}.\\ + \macro{ADJ\_ESTERROR} & 0x0008 & Setta la stima dell'errore + sul tempo, espresso in microsecondi + nel campo \var{esterror} di + \var{timex}.\\ + \macro{ADJ\_STATUS} & 0x0010 & Setta alcuni + valori di stato interni usati dal + sistema nella gestione + dell'orologio specificati nel campo + \var{status} di \var{timex}.\\ + \macro{ADJ\_TIMECONST} & 0x0020 & Setta la larghezza di banda del PLL + implementato dal kernel, + specificato nel campo + \var{constant} di \var{timex}.\\ + \macro{ADJ\_TICK} & 0x4000 & Setta il valore dei tick del timer + in microsecondi, espresso nel campo + \var{tick} di \var{timex}.\\ + \macro{ADJ\_OFFSET\_SINGLESHOT}&0x8001&Setta uno spostamento una tantum + dell'orologio secondo il valore del + campo \var{offset} simulando il + comportamento di \func{adjtime}.\\ + \hline + \end{tabular} + \caption{Costanti per l'assegnazione del valore del campo \var{mode} della + struttura \var{timex}.} + \label{tab:sys_timex_mode} +\end{table} + +Il valore delle costanti per \var{mode} può essere anche espresso, secondo la +sintassi specificata per la forma equivalente di questa funzione definita come +\func{ntp\_adjtime}, utilizzando il prefisso \macro{MOD} al posto di +\macro{ADJ}. + +\begin{table}[htb] + \footnotesize + \centering + \begin{tabular}[c]{|l|c| p{10cm}|} + \hline + \textbf{Nome} & \textbf{Valore} & \textbf{Significato}\\ + \hline + \hline + \macro{TIME\_OK} & 0 & L'orologio è sincronizzato.\\ + \macro{TIME\_INS} & 1 & insert leap second.\\ + \macro{TIME\_DEL} & 2 & delete leap second.\\ + \macro{TIME\_OOP} & 3 & leap second in progress.\\ + \macro{TIME\_WAIT} & 4 & leap second has occurred.\\ + \macro{TIME\_BAD} & 5 & L'orologio non è sincronizzato.\\ + \hline + \end{tabular} + \caption{Possibili valori di ritorno di \func{adjtimex}.} + \label{tab:sys_adjtimex_return} +\end{table} + +La funzione ritorna un valore positivo che esprime lo stato dell'orologio di +sistema; questo può assumere i valori riportati in +\tabref{tab:sys_adjtimex_return}. Un valore di -1 viene usato per riportare +un errore; al solito se si cercherà di modificare l'orologio di sistema +(specificando un \var{mode} diverso da zero) senza avere i privilegi di +amministratore si otterrà un errore di \macro{EPERM}. + \subsection{La gestione delle date.} \label{sec:sys_date} +Le funzioni viste al paragrafo precedente sono molto utili per trattare le +operazioni elementari sui tempi, però le rappresentazioni del tempo ivi +illustrate, se han senso per specificare un intervallo, non sono molto +intuitive quando si deve esprimere un'ora o una data. Per questo motivo è +stata introdotta una ulteriore rappresentazione, detta \textit{broken-down + time}, che permette appunto di \textsl{suddividere} il \textit{calendar + time} usuale in ore, minuti, secondi, ecc. + +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{15cm} + \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{} +struct tm { + int tm_sec; /* seconds */ + int tm_min; /* minutes */ + int tm_hour; /* hours */ + int tm_mday; /* day of the month */ + int tm_mon; /* month */ + int tm_year; /* year */ + int tm_wday; /* day of the week */ + int tm_yday; /* day in the year */ + int tm_isdst; /* daylight saving time */ + long int tm_gmtoff; /* Seconds east of UTC. */ + cost char *tm_zone; /* Timezone abbreviation. */ +}; + \end{lstlisting} + \end{minipage} + \normalsize + \caption{La struttura \var{tm} per una rappresentazione del tempo in termini + di ora, minuti, secondi, ecc.} + \label{fig:sys_tm_struct} +\end{figure} + +Questo viene effettuato attraverso una opportuna struttura \var{tm}, la cui +definizione è riportata in \figref{fig:sys_tm_struct}, ed è in genere questa +struttura che si utilizza quando si deve specificare un tempo a partire dai +dati naturali (ora e data), dato che essa consente anche di trattare la +gestione del fuso orario e dell'ora legale.\footnote{in realtà i due campi + \var{tm\_gmtoff} e \var{tm\_zone} sono estensioni previste per da BSD e + dalle \acr{glibc}, che, quando è definita \macro{\_BSD\_SOURCE}, hanno la + forma in \figref{fig:sys_tm_struct}.} + +Le funzioni per la gestione del \textit{broken-down time} sono varie e vanno +da quelle usate per convertire gli altri formati in questo, usando o meno +l'ora locale o il tempo universale, a quelle per trasformare il valore di un +tempo in una stringa contenente data ed ora, i loro prototipi sono: +\begin{functions} + \headdecl{time.h} + \funcdecl{char *asctime(const struct tm *tm)} + Produce una stringa con data e ora partendo da un valore espresso in + \textit{broken-down time}. + + \funcdecl{char *ctime(const time\_t *timep)} + Produce una stringa con data e ora partendo da un valore espresso in + in formato \type{time\_t}. + + \funcdecl{struct tm *gmtime(const time\_t *timep)} + Converte il \textit{calendar time} dato in formato \type{time\_t} in un + \textit{broken-down time} espresso in UTC. + + \funcdecl{struct tm *localtime(const time\_t *timep)} + Converte il \textit{calendar time} dato in formato \type{time\_t} in un + \textit{broken-down time} espresso nell'ora locale. + + \funcdecl{time\_t mktime(struct tm *tm)} + Converte il \textit{broken-down time} in formato \type{time\_t}. + + \bodydesc{Tutte le funzioni restituiscono un puntatore al risultato in caso + di successo e \macro{NULL} in caso di errore, tranne che \func{mktime} che + restitusce direttamente il valore o -1 in caso di errore.} +\end{functions} + +Le prime due funzioni, \func{asctime} e \func{ctime} servono per poter +stampare in forma leggibile un tempo; esse restituiscono il puntatore ad una +stringa, allocata staticamente, nella forma: +\begin{verbatim} +"Wed Jun 30 21:49:08 1993\n" +\end{verbatim} +e settano anche la variabile \var{tzname} con l'infomazione della \textit{time + zone} corrente; \func{ctime} è banalmente definita in termini di +\func{asctime} come \code{asctime(localtime(t)}. Dato che l'uso di una stringa +statica rende le funzioni non rientranti POSIX.1c e SUSv2 prevedono due +sostitute rientranti, il cui nome è al solito ottenuto appendendo un +\code{\_r}, che prendono un secondo parametro \code{char *buf}, in cui +l'utente deve specificare il buffer su cui la stringa deve essere copiata +(deve essere di almeno 26 caratteri). + +Le altre tre funzioni, \func{gmtime}, \func{localtime} e \func{mktime} servono +per convertire il tempo dal formato \type{time\_t} a quello di \var{tm} e +viceversa; \func{gmtime} effettua la conversione usando il tempo coordinato +universale (UTC), cioè l'ora di Greenwich; mentre \func{localtime} usa l'ora +locale; \func{mktime} esegue la conversione inversa. + +Anche in questo caso le prime due funzioni restituiscono l'indirizzo di una +struttura allocata staticamente, per questo sono state definite anche altre +due versioni rientranti (con la solita estensione \code{\_r}), che prevedono +un secondo parametro \code{struct tm *result}, fornito dal chiamante, che deve +preallocare la struttura su cui sarà restituita la conversione. + +Come mostrato in \figref{fig:sys_tm_struct} il \textit{broken-down time} +permette di tenere conto anche della differenza fra tempo universale e ora +locale, compresa l'eventuale ora legale. Questo viene fatto attraverso le tre +variabli globali mostrate in \figref{fig:sys_tzname}, cui si accede quando si +include \file{time.h}. Queste variabili vengono settate quando si chiama una +delle precedenti funzioni di conversione, oppure invocando direttamente la +funzione \func{tzset}, il cui prototipo è: +\begin{prototype}{sys/timex.h} +{void tzset(void)} + + Setta le variabili globali della \textit{time zone}. + + \bodydesc{La funzione non ritorna niente e non dà errori.} +\end{prototype} + +La funzione inizializza le varaibili di \figref{fig:sys_tzname} a partire dal +valore della variabile di ambiente \macro{TZ}, se quest'ultima non è definita +verrà usato il file \file{/etc/localtime}. + +\begin{figure}[!htb] + \footnotesize + \centering + \begin{minipage}[c]{15cm} + \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{} +extern char *tzname[2]; +extern long timezone; +extern int daylight; + \end{lstlisting} + \end{minipage} + \normalsize + \caption{Le variabili globali usate per la gestione delle \textit{time + zone}.} + \label{fig:sys_tzname} +\end{figure} + +La variabile \var{tzname} contiene due stringhe, che indicano i due nomi +standard della \textit{time zone} corrente. La prima è il nome per l'ora +solare, la seconda per l'ora legale.\footnote{anche se sono indicati come + \code{char *} non è il caso di modificare queste stringhe.} La variabile +\var{timezone} indica la differenza di fuso orario in secondi, mentre +\var{daylight} indica se è attiva o meno l'ora legale. + \section{La gestione degli errori} @@ -1955,7 +2238,7 @@ Esamineremo in questa sezione le sue caratteristiche principali. \subsection{La variabile \var{errno}} \label{sec:sys_errno} -Quasi tutte le funzioni delle librerie del C sono in grado di individuare e +Quasi tutte le funzioni delle librerie del C sono in grado di individuare e riportare condizioni di errore, ed è una buona norma di programmazione controllare sempre che le funzioni chiamate si siano concluse correttamente. @@ -2007,39 +2290,59 @@ riportare in opportuni messaggi le condizioni di errore verificatesi. La prima funzione che si può usare per ricavare i messaggi di errore è \func{strerror}, il cui prototipo è: \begin{prototype}{string.h}{char *strerror(int errnum)} - Ritorna una stringa (statica) che descrive l'errore il cui codice è passato - come parametro. + Restituisce una stringa con il messaggio di errore relativo ad + \param{errnum}. + + \bodydesc{La funzione ritorna il puntatore alla stringa col messaggio di + errore in caso di successo e \macro{NULL} in caso di errore, nel qual caso + \var{errno} sarà settata a \macro{EINVAL} se si è specificato un numero di + errore non valido.} \end{prototype} In generale \func{strerror} viene usata passando \var{errno} come parametro; nel caso si specifichi un codice sbagliato verrà restituito un messaggio di -errore sconosciuto. La funzione utilizza una stringa statica che non deve -essere modificata dal programma e che è utilizzabile solo fino ad una chiamata -successiva a \func{strerror}; nel caso si usino i thread è -provvista\footnote{questa funzione è una estensione GNU, non fa parte dello - standard POSIX.} una versione apposita: +errore sconosciuto, e la funzione restituirà come errore \macro{EINVAL}. La +funzione tiene conto del valore della variabile di ambiente +\macro{LC\_MESSAGES} per usare eventuali traduzioni dei messaggi d'errore +nella localizzazione presente. + +La funzione utilizza una stringa statica che non deve essere modificata dal +programma e che è utilizzabile solo fino ad una chiamata successiva a +\func{strerror}; per questo motivo non è rientrante e nel caso si usino i +thread è provvista\footnote{questa funzione è la versione prevista dalle + \acr{glibc}, ed effettivamente definita in \file{string.h}, ne esiste una + analoga nello standard SUSv3 (quella riportata dalla man page), che + restituisce \code{int} al posto di \code{char *}, e che tronca la stringa + restituita a \param{size}.} una versione apposita: \begin{prototype}{string.h} -{char *strerror\_r(int errnum, char *buff, size\_t size)} - Analoga a \func{strerror} ma ritorna il messaggio in un buffer - specificato da \param{buff} di lunghezza massima (compreso il terminatore) - \param{size}. + {char * strerror\_r(int errnum, char *buf, size\_t size)} + + Analoga a \func{strerror} ma usa il buffer \param{buf} di lunghezza massima + (compreso il terminatore) \param{size}. + + \bodydesc{La funzione restitusce il puntatore alla stringa; in caso di + errore \var{errno} oltre a \macro{EINVAL} può assumere anche il valore + \macro{ERANGE} per indicare che non c'è sufficiente memoria per contenere + la stringa di descrizione.} \end{prototype} \noindent che utilizza un buffer che il singolo thread deve allocare, per evitare i -problemi connessi alla condivisione del buffer statico. Infine, per completare -la caratterizzazione dell'errore, si può usare anche la variabile -globale\footnote{anche questa è un'estensione GNU.} -\var{program\_invocation\_short\_name} che riporta il nome del programma -attualmente in esecuzione. +problemi connessi alla condivisione del buffer statico. La funzione +restituisce l'indirizzo della stringa usata, che può essere contenuta nel +buffer specificato da \param{buf}, per una lunghezza non superiore a +\param{size}, nel qual caso la stringa sarebbe troncata e terminata con +\macro{NUL}. + Una seconda funzione usata per riportare i codici di errore in maniera automatizzata sullo standard error (vedi \secref{sec:file_std_descr}) è \func{perror}, il cui prototipo è: -\begin{prototype}{stdio.h}{void perror (const char *message)} +\begin{prototype}{stdio.h}{void perror(const char *message)} Stampa il messaggio di errore relativo al valore corrente di \var{errno} sullo standard error; preceduto dalla stringa \var{message}. \end{prototype} -i messaggi di errore stampati sono gli stessi di \func{strerror}, (riportati + +I messaggi di errore stampati sono gli stessi di \func{strerror}, (riportati in \capref{cha:errors}), e, usando il valore corrente di \var{errno}, si riferiscono all'ultimo errore avvenuto. La stringa specificata con \var{message} viene stampato prime del messaggio d'errore, seguita dai due @@ -2056,18 +2359,6 @@ la prima contiene i puntatori alle stringhe di errore indicizzati da l'utilizzo di questa stringa è sostanzialmente equivalente a quello di \func{strerror}. -In \nfig\ è riportata la sezione attinente del codice del programma -\cmd{errcode}, che può essere usato per stampare i messaggi di errore e le -costanti usate per identificare i singoli errori; il sorgente completo del -programma è allegato nel file \file{ErrCode.c} e contiene pure la gestione -delle opzioni e tutte le definizioni necessarie ad associare il valore -numerico alla costante simbolica. In particolare si è riportata la sezione che -converte la stringa passata come parametro in un intero (\texttt{\small - 1--2}), controllando con i valori di ritorno di \func{strtol} che la -conversione sia avvenuta correttamente (\texttt{\small 4--10}), e poi stampa, -a seconda dell'opzione scelta il messaggio di errore (\texttt{\small 11--14}) -o la macro (\texttt{\small 15--17}) associate a quel codice. - \begin{figure}[!htb] \footnotesize \begin{lstlisting}{} @@ -2093,6 +2384,93 @@ o la macro (\texttt{\small 15--17}) associate a quel codice. \label{fig:sys_err_mess} \end{figure} +In \figref{fig:sys_err_mess} è riportata la sezione attinente del codice del +programma \cmd{errcode}, che può essere usato per stampare i messaggi di +errore e le costanti usate per identificare i singoli errori; il sorgente +completo del programma è allegato nel file \file{ErrCode.c} e contiene pure la +gestione delle opzioni e tutte le definizioni necessarie ad associare il +valore numerico alla costante simbolica. In particolare si è riportata la +sezione che converte la stringa passata come parametro in un intero +(\texttt{\small 1--2}), controllando con i valori di ritorno di \func{strtol} +che la conversione sia avvenuta correttamente (\texttt{\small 4--10}), e poi +stampa, a seconda dell'opzione scelta il messaggio di errore (\texttt{\small + 11--14}) o la macro (\texttt{\small 15--17}) associate a quel codice. + + + +\subsection{Alcune estensioni GNU} +\label{sec:sys_err_GNU} + +Le precedenti funzioni sono quelle definite ed usate nei vari standard; le +\acr{glibc} hanno però introdotto una serie di estensioni ``GNU'' che +forniscono alcune funzionalità aggiuntive per una gestione degli errori +semplificata e più efficiente. + +La prima estenzione consiste in due variabili, \code{char * + program\_invocation\_name} e \code{char * program\_invocation\_short\_name} +servono per ricavare il nome del programma; queste sono utili quando si deve +aggiungere il nome del programma (cosa comune quando si ha un programma che +non viene lanciato da linea di comando e salva gli errori in un file di log) +al messaggio d'errore. La prima contiene il nome usato per lanciare il +programma (ed è equivalente ad \code{argv[0]}); la seconda mantiene solo il +nome del programma (senza eventuali directory in testa). + +Uno dei problemi che si hanno con l'uso di \func{perror} è che non c'è +flessibilità su quello che si può aggiungere al messaggio di errore, che può +essere solo una stringa. In molte occasioni invece serve poter scrivere dei +messaggi con maggiore informazione; ad esempio negli standard di +programmazione GNU si richiede che ogni messaggio di errore sia preceduto dal +nome del programma, ed in generale si può voler stampare il contenuto di +qualche variabile; per questo le \acr{glibc} definiscono la funzione +\func{error}, il cui prototipo è: +\begin{prototype}{stdio.h} +{void error(int status, int errnum, const char *format, ...)} + +Stampa un messaggio di errore formattato. + +\bodydesc{La funzione non restituisce nulla e non riporta errori.} +\end{prototype} + +La funzione fa parte delle estensioni GNU per la gestione degli errori, +l'argomento \param{format} prende la stessa sintassi di \func{printf}, ed i +relativi parametri devono essere forniti allo stesso modo, mentre +\param{errnum} indica l'errore che si vuole segnalare (non viene quindi usato +il valore corrente di \var{errno}); la funzione stampa sullo standard error il +nome del programma, come indicato dalla variabile globale \var{program\_name}, +seguito da due punti ed uno spazio, poi dalla stringa generata da +\param{format} e dagli argomenti seguenti, seguita da due punti ed uno spazio +infine il messaggio di errore relativo ad \param{errnum}, il tutto è terminato +da un a capo. + +Il comportamento della funzione può essere ulteriormente controllato se si +definisce una variabile \var{error\_print\_progname} come puntatore ad una +funzione \ctyp{void} che restituisce \ctyp{void} che si incarichi di stampare +il nome del programma. + +L'argomento \param{status} può essere usato per terminare direttamente il +programma in caso di errore, nel qual caso \func{error} dopo la stampa del +messaggio di errore chiama \func{exit} con questo stato di uscita. Se invece +il valore è nullo \func{error} ritorna normalmente ma viene incrementata +un'altra variabile globale, \var{error\_message\_count}, che tiene conto di +quanti errori ci sono stati. + +Un'altra funzione per la stampa degli errori, ancora più sofisticata, è +\func{error\_at\_line}, che prende due argomenti aggiuntivi per indicare linea +e file su cui è avvenuto l'errore; il suo prototipo è: +\begin{prototype}{stdio.h} +{void error\_at\_line(int status, int errnum, const char *fname, + unsigned int lineno, const char *format, ...)} + +Stampa un messaggio di errore formattato. + +\bodydesc{La funzione non restituisce nulla e non riporta errori.} +\end{prototype} +\noindent ed il suo comportamento è identico a quello di \func{error} se non +per il fatto che, separati con il solito due punti-spazio, vengono inseriti un +nome di file indicato da \param{fname} ed un numero di linea subito dopo la +stampa del nome del programma. + + %%% Local Variables: