X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=system.tex;h=e2b9a4cc47c325f7c67287969290e33c9af173f7;hp=01930a0c182364ce5e07db72c671b1ace60f7668;hb=21f68aeaebed8afa19039115dd97dde5f03caae0;hpb=2c682ba44f85eb183ddf75760b38bf048f89de53 diff --git a/system.tex b/system.tex index 01930a0..e2b9a4c 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ù @@ -317,7 +317,8 @@ relative spiegazioni, si pu contemporanea. Questo limite previsto anche dallo standard ANSI C, che specifica la macro {FOPEN\_MAX}.\\ \texttt{\_SC\_TZNAME\_MAX}&\macro{TZNAME\_MAX}& - La dimensione massima di un nome di una \texttt{timezone} (vedi ).\\ + La dimensione massima di un nome di una \texttt{timezone} (vedi + \secref{sec:sys_date}).\\ \texttt{\_SC\_NGROUPS\_MAX}&\macro{NGROUP\_MAX}& Massimo numero di gruppi supplementari che può avere un processo (vedi \secref{sec:proc_access_id}).\\ @@ -531,7 +532,7 @@ In generale si tenga presente che le dimensioni delle stringe di una \macro{\_UTSNAME\_LENGTH} per i campi standard e \macro{\_UTSNAME\_DOMAIN\_LENGTH} per quello specifico per il nome di dominio; altri sistemi usano nomi diversi come \macro{SYS\_NMLN} o \macro{\_SYS\_NMLN} -or \macro{UTSLEN} che possono avere valori diversi. Nel caso di Linux +o \macro{UTSLEN} che possono avere valori diversi. Nel caso di Linux \func{uname} corrisponde in realtà a 3 system call diverse, le prime due usano rispettivamente delle lunghezze delle stringhe di 9 e 65 byte; la terza usa anch'essa 65 byte, ma restituisce anche l'ultimo campo, \var{domainname}, con @@ -903,14 +904,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 @@ -989,7 +990,7 @@ struct passwd { La struttura usata da entrambe le funzioni è allocata staticamente, per questo motivo viene sovrascritta ad ogni nuova invocazione, lo stesso dicasi per la memoria dove sono scritte le stringhe a cui i puntatori in essa contenuti -fanno riferimento. Ovviamente questo implica che dette funzioni non posono +fanno riferimento. Ovviamente questo implica che dette funzioni non possono essere rientranti, per cui ne esistono anche due versioni alternative (denotate dalla solita estensione \code{\_r}), i cui prototipi sono: \begin{functions} @@ -1252,8 +1253,8 @@ riportati in \tabref{tab:sys_ut_type}, quando assume i valori \macro{RUN\_LVL}, \macro{BOOT\_TIME}, \macro{OLD\_TIME}, \macro{NEW\_TIME}, verrà restituito la prima voce che corrisponde al tipo determinato; quando invece assume i valori \macro{INIT\_PROCESS}, \macro{LOGIN\_PROCESS}, -\macro{USER\_PROCESS} o \macro{DEAD\_PROCESS} verrà restiuita la prima voce -corripondente al valore del campo \var{ut\_id} specificato in \param{ut}. +\macro{USER\_PROCESS} o \macro{DEAD\_PROCESS} verrà restituita la prima voce +corrispondente al valore del campo \var{ut\_id} specificato in \param{ut}. \begin{table}[htb] \footnotesize @@ -1309,7 +1310,7 @@ staticamente rende le funzioni di lettura non rientranti; per questo motivo le \acr{glibc} forniscono anche delle versioni rientranti: \func{getutent\_r}, \func{getutid\_r}, \func{getutline\_r}, che invece di restituire un puntatore restituiscono un intero e prendono due argomenti aggiuntivi. Le funzioni si -comportano esattamente come le analoge non rientranti, solo che restituiscono +comportano esattamente come le analoghe non rientranti, solo che restituiscono il risultato all'indirizzo specificato dal primo argomento aggiuntivo (di tipo \code{struct utmp *buffer}) mentre il secondo (di tipo \code{struct utmp **result)} viene usato per restituire il puntatore allo stesso buffer. @@ -1488,7 +1489,7 @@ sono: \bodydesc{Le funzioni ritornano 0 in caso di successo e -1 in caso di errore, nel qual caso \var{errno} viene settata ai valori: \begin{errlist} - \item[\macro{INVAL}] I valori per \param{resource} non sono validi. + \item[\macro{EINVAL}] I valori per \param{resource} non sono validi. \item[\macro{EPERM}] Un processo senza i privilegi di amministratore ha cercato di innalzare i propri limiti. \end{errlist} @@ -1516,7 +1517,7 @@ specificarne i valori. oltre questa dimensione riceverà un segnale di \macro{SIGXFSZ}.\\ \macro{RLIMIT\_DATA} & La massima dimensione della memoria dati di un - processo. Il tentatico di allocare più memoria + processo. Il tentativo di allocare più memoria causa il fallimento della funzione di allocazione. \\ \macro{RLIMIT\_STACK} & La massima dimensione dello stack del @@ -1617,7 +1618,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} @@ -1626,7 +1627,7 @@ rispettivamente con i parametri \macro{\_SC\_PHYS\_PAGES} e corrispondenti alla RAM della macchina; la seconda invece la memoria effettivamente disponibile per i processi. -Le \acr{glibc} supportano inoltre, come estenzioni GNU, due funzioni che +Le \acr{glibc} supportano inoltre, come estensioni GNU, due funzioni che restituiscono il numero di processori della macchina (e quello dei processori attivi); anche queste sono informazioni comunque ottenibili attraverso \func{sysconf} utilizzando rispettivamente i parametri @@ -1754,7 +1755,7 @@ La funzione restituisce il tempo in tick, quindi se si vuole il tempo in secondi occorre moltiplicare il risultato per la costante \macro{CLOCKS\_PER\_SEC}.\footnote{le \acr{glibc} seguono lo standard ANSI C, POSIX richiede che \macro{CLOCKS\_PER\_SEC} sia definito pari a 1000000 - indipendetemente dalla risoluzione del timer di sistema.} In genere + indipendentemente dalla risoluzione del timer di sistema.} In genere \type{clock\_t} viene rappresentato come intero a 32 bit, il che comporta un valore massimo corrispondente a circa 72 minuti, dopo i quali il contatore riprenderà lo stesso valore iniziale. @@ -1804,8 +1805,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 terminazione di tutti i suoi figli, questi processi ``nipoti'' non +verranno considerati nel calcolo di questi tempi. @@ -1815,45 +1817,70 @@ questi ``nipoti'' non potranno essere considerati nel calcolo di questi tempi. 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} può essere ottenuto con la funzione -\func{time} che lo restituisce in nel suddetto formato; il suo prototipo è: +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 valore del \textit{calendar time} in caso di - successo e -1 in caso di errore, che può essere solo \macro{EFAULT}.} + \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 l'orologio di sistema; il suo -prototipo è: +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}.} + 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)} -Dato che modificare l'ora ha un impatto su tutto il sistema, la funzione può -essere usata solo dall'ammninistratore. - - -Dato che il tempo misurato in termini di\type{time\_t} ha comunque una -risoluzione massima di un secondo le \acr{glibc} provvedono delle -rappresentazioni alternative che consentono di indicare intervalli o tempi con -precisioni maggiori del secondo, queste sono realizzate attraverso le -strutture \var{timeval} e \var{timespec}, le cui definizioni sono riportate in -\figref{fig:sys_timeval_struct}, 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.}. + 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 @@ -1868,21 +1895,410 @@ struct timespec { \end{lstlisting} \end{minipage} \normalsize - \caption{Le strutture \var{timeval} e \var{timespec} 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} -Data la scarsa precisione nell'uso di \type{time\_t} per le operazioni sui -tempi di norma l'uso delle funzioni precedenti è di norma sconsigliato, ed -esse sono di solito sostituite da \func{gettimeofday} e \func{settimeofday} +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 +effettuato. + +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} -\subsection{Le \textit{timezone} e la gestione delle date.} -\label{sec:sys_time_base} +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 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 + restituisce 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'informazione 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 +variabili 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 variabili 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. + +Benché la funzione \func{asctime} fornisca la modalità più immediata per +stampare un tempo o una data, la flessibilità non fa parte delle sue +caratteristiche; quando si vuole poter stampare solo una parte (l'ora, o il +gionrno) di un tempo si può ricorrere alla più sofisticata \func{strftime}, il +cui prototipo è: +\begin{prototype}{time.h} +{size\_t strftime(char *s, size\_t max, const char *format, + const struct tm *tm)} + +Stampa il tempo \param{tm} nella stringa \param{s} secondo il formato +\param{format}. + + \bodydesc{La funzione ritorna il numero di caratteri stampati in \param{s}, + altrimenti restuisce 0.} +\end{prototype} + +La funzione converte opportunamente il tempo \param{tm} in una stringa di +testo da salvare in \param{s}, purché essa sia di dimensione, indicata da +\param{size}, sufficiente. I caratteri generati dalla funzione vengono +restituiti come valore di ritorno, ma non tengono conto del terminatore +finale, che invece viene considerato nel computo della dimensione; se +quest'ultima è eccessiva viene restituito 0 e lo stato di \param{s} è +indefinito. + +\begin{table}[htb] + \footnotesize + \centering + \begin{tabular}[c]{|c|l|p{6cm}|} + \hline + \textbf{Modificatore} & \textbf{Esempio} & \textbf{Significato}\\ + \hline + \hline + \macro{\%a}&\texttt{Wed} & Nome del giorno, abbreviato.\\ + \macro{\%A}&\texttt{Wednesday} & Nome del giorno, completo.\\ + \macro{\%b}&\texttt{Apr} & Nome del mese, abbreviato.\\ + \macro{\%B}&\texttt{April} & Nome del mese, completo.\\ + \macro{\%c}&\texttt{Wed Apr 24 18:40:50 2002}& Data e ora.\\ + \macro{\%d}&\texttt{24} & Giorno del mese.\\ + \macro{\%H}&\texttt{18} & Ora del giorno, da 0 a 24.\\ + \macro{\%I}&\texttt{06} & Ora del giorno, da 0 a 12.\\ + \macro{\%j}&\texttt{114} & Giorno dell'anno.\\ + \macro{\%m}&\texttt{04} & Mese dell'anno.\\ + \macro{\%M}&\texttt{40} & Minuto.\\ + \macro{\%p}&\texttt{PM} & AM/PM.\\ + \macro{\%S}&\texttt{50} & Secondo.\\ + \macro{\%U}&\texttt{16} & Settimana dell'anno (partendo dalla + domenica).\\ + \macro{\%w}&\texttt{3} & Giorno della settimana. \\ + \macro{\%W}&\texttt{16} & Settimana dell'anno (partendo dal + lunedì).\\ + \macro{\%x}&\texttt{04/24/02} & La data.\\ + \macro{\%X}&\texttt{18:40:50} & L'ora.\\ + \macro{\%y}&\texttt{02} & Anno nel secolo.\\ + \macro{\%Y}&\texttt{2002} & Anno.\\ + \macro{\%Z}&\texttt{CEST} & Nome della \textit{timezone}.\\ + \macro{\%\%}&\texttt{\%} & Il carattere \%.\\ + \hline + \end{tabular} + \caption{Valori previsti dallo standard ANSI C per modificatore della + stringa di formato di \func{strftime}.} + \label{tab:sys_strftime_format} +\end{table} + +Il risultato della funzione è controllato dalla stringa di formato +\param{format}, tutti i caratteri restano invariati eccetto \texttt{\%} che +viene utilizzato come modificatore; alcuni\footnote{per la precisione quelli + definiti dallo standard ANSI C, che sono anche quelli riportati da POSIX.1; + le \acr{glibc} provvedono tutte le estensioni introdotte da POSIX.2 per il + comando \cmd{date}, i valori introdotti da SVID3 e ulteriori estensioni GNU; + l'elenco completo dei possibili valori è riportato nella pagina di manuale + della funzione.} dei possibili valori che esso può assumere sono ripotati in +\tabref{tab:sys_strftime_format}. La funzione tiene conto anche della presenza +di una localizzazione per stampare in maniera adeguata i vari nomi. + \section{La gestione degli errori} \label{sec:sys_errors} @@ -1896,7 +2312,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. @@ -1948,39 +2364,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 restituisce 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 @@ -1997,18 +2433,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}{} @@ -2034,6 +2458,95 @@ 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 estensione 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. Inoltre essa usa un'altra variabile globale, +\var{error\_one\_per\_line}, che settata ad un valore diverso da zero fa si +che errori relativi alla stessa linea non vengano ripetuti. + + %%% Local Variables: