X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=system.tex;h=1e5a20f878d802c0e87002f56354df4d592b8d25;hp=fd0284d05b0bb478454b75868ad852c70142c0d9;hb=85acea6db3dceef49bbaf7b02f73895425ea1168;hpb=c3e498249706436db56faaa3be03458b7ac1113d diff --git a/system.tex b/system.tex index fd0284d..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ù @@ -882,18 +882,18 @@ nome del filesystem stesso. \footnotesize \centering \begin{minipage}[c]{15cm} \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{} - struct statfs { - long f_type; /* tipo di filesystem */ - long f_bsize; /* dimensione ottimale dei blocchi di I/O */ - long f_blocks; /* blocchi totali nel filesystem */ - long f_bfree; /* blocchi liberi nel filesystem */ - long f_bavail; /* blocchi liberi agli utenti normali */ - long f_files; /* inodes totali nel filesystem */ - long f_ffree; /* inodes liberi nel filesystem */ - fsid_t f_fsid; /* filesystem id */ - long f_namelen; /* lunghezza massima dei nomi dei file */ - long f_spare[6]; /* riservati per uso futuro */ - }; +struct statfs { + long f_type; /* tipo di filesystem */ + long f_bsize; /* dimensione ottimale dei blocchi di I/O */ + long f_blocks; /* blocchi totali nel filesystem */ + long f_bfree; /* blocchi liberi nel filesystem */ + long f_bavail; /* blocchi liberi agli utenti normali */ + long f_files; /* inodes totali nel filesystem */ + long f_ffree; /* inodes liberi nel filesystem */ + fsid_t f_fsid; /* filesystem id */ + long f_namelen; /* lunghezza massima dei nomi dei file */ + long f_spare[6]; /* riservati per uso futuro */ +}; \end{lstlisting} \end{minipage} \normalsize @@ -903,14 +903,14 @@ nome del filesystem stesso. 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 @@ -1455,10 +1455,10 @@ corrente e massimo. \centering \begin{minipage}[c]{15cm} \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{} - struct rlimit { - rlim_t rlim_cur; - rlim_t rlim_max; - }; +struct rlimit { + rlim_t rlim_cur; + rlim_t rlim_max; +}; \end{lstlisting} \end{minipage} \normalsize @@ -1617,7 +1617,7 @@ informazioni riguardo la memoria; i loro prototipi sono: Legge il numero di pagine di memoria disponibili nel sistema. - \bodydesc{Le funzioni restituiscono il numero di pagine, } + \bodydesc{Le funzioni restituiscono un numero di pagine.} \end{functions} Queste funzioni sono equivalenti all'uso della funzione \func{sysconf} @@ -1782,12 +1782,12 @@ struttura di tipo \var{tms}, la cui definizione \centering \begin{minipage}[c]{15cm} \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{} - struct tms { - clock_t tms_utime; /* user time */ - clock_t tms_stime; /* system time */ - clock_t tms_cutime; /* user time of children */ - clock_t tms_cstime; /* system time of children */ - }; +struct tms { + clock_t tms_utime; /* user time */ + clock_t tms_stime; /* system time */ + clock_t tms_cutime; /* user time of children */ + clock_t tms_cstime; /* system time of children */ +}; \end{lstlisting} \end{minipage} \normalsize @@ -1804,38 +1804,425 @@ 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. \subsection{Le funzioni per il \textit{calendar time}} \label{sec:sys_time_base} -Normalmente il \textit{calendar time} è mantenuto in una variabile di tipo -\type{time\_t}, che usualmente corrisponde ad un tipo nativo (in Linux è un -intero a 32 bit). Le \acr{glibc} provvedono delle rappresentazioni -alternative che consentono un suo utilizzo per diversi scopi; in particolare -quando necessita manipolare +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 +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}. + + \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, 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 +sia necessario; il suo prototipo è: +\begin{prototype}{time.h}{int stime(time\_t *t)} + Setta a \param{t} il valore corrente del \textit{calendar time}. + + \bodydesc{La funzione ritorna 0 in caso di successo e -1 in caso di errore, + che può essere \macro{EFAULT} o \macro{EPERM}.} +\end{prototype} +\noindent dato che modificare l'ora ha un impatto su tutto il sistema +il cambiamento dell'orologio è una operazione privilegiata e questa funzione +può essere usata solo da un processo con i privilegi di amministratore, +altrimenti la chiamata fallirà con un errore di \macro{EPERM}. + +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},\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} + + \funcdecl{int gettimeofday(struct timeval *tv, struct timezone *tz)} + + Legge il tempo corrente del sistema. + + \funcdecl{int settimeofday(const struct timeval *tv, const struct timezone + *tz)} + + Setta il tempo di sistema. + + \bodydesc{Entrambe le funzioni restituiscono 0 in caso di successo e -1 in + caso di errore, nel qual caso \var{errno} può assumere il valori + \macro{EINVAL} \macro{EFAULT} e per \func{settimeofday} anche + \macro{EPERM}.} +\end{functions} +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 { - long tv_sec; /* seconds */ - long tv_usec; /* microseconds */ + long tv_sec; /* seconds */ + long tv_usec; /* microseconds */ +}; +struct timespec { + time_t tv_sec; /* seconds */ + long tv_nsec; /* nanoseconds */ }; \end{lstlisting} \end{minipage} \normalsize - \caption{La struttura \var{timeval} per il calendar time.} + \caption{Le strutture \var{timeval} e \var{timespec} usate per una + rappresentazione ad alta risoluzione del \textit{calendar time}.} \label{fig:sys_timeval_struct} \end{figure} +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. 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)} + + 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}.} +\end{prototype} + +Questa funzione permette di avere un aggiustamento graduale del tempo di +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 ricevere il valore dell'ultimo aggiustamento +effettuto. + +Linux poi prevede un'altra funzione, \func{adjtimex}, che consente un +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 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. @@ -1851,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. @@ -1903,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 @@ -1952,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}{} @@ -1989,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: