X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=system.tex;h=c474854e8924c5c96d5244e898a14fdd93fd7bed;hp=4482834d30d9b3b59cbafef3dc19921abf6506f9;hb=65a5b6a82bdcfeefa6ebc270fe759f3a38560d33;hpb=996f31582fc276069a62f707bc5bdb4255342062 diff --git a/system.tex b/system.tex index 4482834..c474854 100644 --- a/system.tex +++ b/system.tex @@ -2,30 +2,31 @@ \label{cha:system} In questo capitolo tratteremo varie interfacce che attengono agli aspetti più -generali del sistema, come quelle per la gestione di parametri e -configurazione, quelle per la lettura dei limiti e delle caratteristiche dello -stesso, quelle per il controllo dell'uso delle risorse da parte dei processi, -quelle per la gestione dei tempi e degli errori. +generali del sistema, come quelle per la gestione dei parametri e della +configurazione dello stesso, quelle per la lettura dei limiti e delle +caratteristiche, quelle per il controllo dell'uso delle risorse dei processi, +quelle per la gestione ed il controllo dei filesystem, degli utenti, dei tempi +e degli errori. -\section{La lettura delle caratteristiche del sistema} +\section{Capacità e caratteristiche del sistema} \label{sec:sys_characteristics} In questa sezione tratteremo le varie modalità con cui un programma può -ottenere informazioni riguardo alle capacità del sistema. Ogni sistema infatti -è contraddistinto da un gran numero di limiti e costanti che lo -caratterizzano, e che possono dipendere da fattori molteplici, come +ottenere informazioni riguardo alle capacità del sistema. Ogni sistema +unix-like infatti è contraddistinto da un gran numero di limiti e costanti che +lo caratterizzano, e che possono dipendere da fattori molteplici, come l'architettura hardware, l'implementazione del kernel e delle librerie, le opzioni di configurazione. La definizione di queste caratteristiche ed il tentativo di provvedere dei -meccanismi generali che i programmi potessero usare per ricavarle è uno degli -aspetti più complessi e controversi coi cui i vari standard si sono dovuti -confrontare, spesso con risultati spesso tutt'altro che chiari. Proveremo -comunque a dare una descrizione dei principali metodi previsti dai vari +meccanismi generali che i programmi possono usare per ricavarle è uno degli +aspetti più complessi e controversi con cui le diverse standardizzazioni si +sono dovute confrontare, spesso con risultati spesso tutt'altro che chiari. +Daremo comunque una descrizione dei principali metodi previsti dai vari standard per ricavare sia le caratteristiche specifiche del sistema, che -quelle dei file. +quelle della gestione dei file. \subsection{Limiti e parametri di sistema} @@ -34,11 +35,11 @@ quelle dei file. Quando si devono determinare le le caratteristiche generali del sistema ci si trova di fronte a diverse possibilità; alcune di queste infatti possono dipendere dall'architettura dell'hardware (come le dimensioni dei tipi -interi), o dal sistema operativo (come la presenza o meno dei \textit{saved - id}), altre invece possono dipendere dalle opzioni con cui si è costruito -il sistema (ad esempio da come si è compilato il kernel), o dalla -configurazione del medesimo; per questo motivo in generale sono necessari due -tipi diversi di funzionalità: +interi), o dal sistema operativo (come la presenza o meno del gruppo degli +identificatori \textit{saved}), altre invece possono dipendere dalle opzioni +con cui si è costruito il sistema (ad esempio da come si è compilato il +kernel), o dalla configurazione del medesimo; per questo motivo in generale +sono necessari due tipi diversi di funzionalità: \begin{itemize*} \item la possibilità di determinare limiti ed opzioni al momento della compilazione. @@ -58,7 +59,7 @@ tramite la funzione \func{sysconf} (che esamineremo in \secref{sec:sys_sysconf}). Lo standard ANSI C definisce dei limiti che sono tutti fissi, pertanto questo -saranno sempre disponibili al momento della compilazione; un elenco, ripreso +saranno sempre disponibili al momento della compilazione. Un elenco, ripreso da \file{limits.h}, è riportato in \tabref{tab:sys_ansic_macro}. Come si può vedere per la maggior parte questi limiti attengono alle dimensioni dei dati interi, che sono in genere fissati dall'architettura hardware (le analoghe @@ -161,7 +162,8 @@ file, riportate in \tabref{tab:sys_file_macro}). \macro{STREAM\_MAX}& 8& massimo numero di stream aperti per processo in contemporanea.\\ \macro{TZNAME\_MAX}& 6& dimensione massima del nome di una - \texttt{timezone} (vedi ).\\ + \texttt{timezone} (vedi + \secref{sec:sys_time_base})).\\ \macro{NGROUPS\_MAX}& 32& numero di gruppi supplementari per processo (vedi \secref{sec:proc_access_id}).\\ \macro{SSIZE\_MAX}&32767& valore massimo del tipo \type{ssize\_t}.\\ @@ -206,7 +208,8 @@ riportati in \tabref{tab:sys_posix1_general}. \macro{\_POSIX\_STREAM\_MAX} & 8& massimo numero di stream aperti per processo in contemporanea.\\ \macro{\_POSIX\_TZNAME\_MAX} & & dimensione massima del nome di una - \texttt{timezone} (vedi ).\\ + \texttt{timezone} (vedi + \secref{sec:sys_date}). \\ \macro{\_POSIX\_NGROUPS\_MAX}& 0& numero di gruppi supplementari per processo (vedi \secref{sec:proc_access_id}).\\ @@ -238,9 +241,10 @@ valori ottenuti da \func{sysconf}. \hline \macro{\_POSIX\_JOB\_CONTROL}& il sistema supporta il \textit{job control} (vedi - \secref{sec:sess_xxx}).\\ - \macro{\_POSIX\_SAVED\_IDS} & il sistema supporta i \textit{saved id} - (vedi \secref{sec:proc_access_id}). + \secref{sec:sess_job_control}).\\ + \macro{\_POSIX\_SAVED\_IDS} & il sistema supporta gli identificatori del + gruppo \textit{saved} (vedi + \secref{sec:proc_access_id}) per il controllo di accesso dei processi\\ \macro{\_POSIX\_VERSION} & fornisce la versione dello standard POSIX.1 supportata nel formato YYYYMML (ad esempio @@ -260,32 +264,32 @@ incluso automaticamente all'interno di \file{limits.h}). Di questi vale la pena menzionare alcune macro di uso comune, (riportate in \tabref{tab:sys_posix1_other}), che non indicano un valore specifico, ma denotano la presenza di alcune funzionalità nel sistema (come il supporto del -\textit{job control} o dei \textit{saved id}). +\textit{job control} o degli identificatori del gruppo \textit{saved}). Oltre allo standard POSIX.1, anche lo standard POSIX.2 definisce una serie di altre costanti. Siccome queste sono principalmente attinenti a limiti relativi alle applicazioni di sistema presenti (come quelli su alcuni parametri delle espressioni regolari o del comando \cmd{bc}), non li tratteremo esplicitamente, se ne trova una menzione completa nell'header file -\file{bits/posix2\_lim.h}, e alcuni di loro sono descritti nella man page di -\func{sysconf} e nel manuale delle \acr{glibc}. +\file{bits/posix2\_lim.h}, e alcuni di loro sono descritti nella pagina di +manuale di \func{sysconf} e nel manuale delle \acr{glibc}. \subsection{La funzione \func{sysconf}} \label{sec:sys_sysconf} Come accennato in \secref{sec:sys_limits} quando uno dei limiti o delle -caratteristiche del sistema può variare, è necessario ottenerne il valore -attraverso la funzione \func{sysconf}, per non dover essere costretti a +caratteristiche del sistema può variare, per non dover essere costretti a ricompilare un programma tutte le volte che si cambiano le opzioni con cui è -compilato il kernel, o alcuni dei parametri modificabili a run time. Il +compilato il kernel, o alcuni dei parametri modificabili a run time, è +necessario ottenerne il valore attraverso la funzione \func{sysconf}. Il prototipo di questa funzione è: \begin{prototype}{unistd.h}{long sysconf(int name)} Restituisce il valore del parametro di sistema \param{name}. \bodydesc{La funzione restituisce indietro il valore del parametro richiesto, o 1 se si tratta di un'opzione disponibile, 0 se l'opzione non - è disponibile e -1 in caso di errore (ma \var{errno} non viene settata).} + è disponibile e -1 in caso di errore (ma \var{errno} non viene impostata).} \end{prototype} La funzione prende come argomento un intero che specifica quale dei limiti si @@ -316,18 +320,19 @@ 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}).\\ \texttt{\_SC\_SSIZE\_MAX}&\macro{SSIZE\_MAX}& valore massimo del tipo di dato \type{ssize\_t}.\\ \texttt{\_SC\_CLK\_TCK}& \macro{CLK\_TCK} & - Il numero di \textit{clock tick} al secondo, cioè la frequenza delle - interruzioni del timer di sistema (vedi \secref{sec:proc_priority}).\\ + Il numero di \textit{clock tick} al secondo, cioè l'unità di misura del + \textit{process time} (vedi \secref{sec:sys_unix_time}).\\ \texttt{\_SC\_JOB\_CONTROL}&\macro{\_POSIX\_JOB\_CONTROL}& Indica se è supportato il \textit{job control} (vedi - \secref{sec:sess_xxx}) in stile POSIX.\\ + \secref{sec:sess_job_control}) in stile POSIX.\\ \texttt{\_SC\_SAVED\_IDS}&\macro{\_POSIX\_SAVED\_IDS}& Indica se il sistema supporta i \textit{saved id} (vedi \secref{sec:proc_access_id}).\\ @@ -366,9 +371,9 @@ get_child_max(void) } \end{lstlisting} %\normalsize -ma in realtà in Linux queste macro sono comunque definite e indicando un -limite generico, per cui è sempre meglio usare i valori restituiti da -quest'ultima. +ma in realtà in Linux queste macro sono comunque definite, indicando però un +limite generico. Per questo motivo è sempre meglio usare i valori restituiti +da \func{sysconf}. \subsection{I limiti dei file} @@ -383,49 +388,49 @@ riportate in \tabref{tab:sys_file_macro}. \begin{table}[htb] \centering \footnotesize - \begin{tabular}[c]{|l|r|p{8cm}|} + \begin{tabular}[c]{|l|r|l|} \hline \textbf{Macro}&\textbf{Valore}&\textbf{Significato}\\ \hline \hline - \macro{NAME\_MAX}& 14 & lunghezza in byte di un nome di file. \\ - \macro{PATH\_MAX}& 256 & lunghezza in byte di pathname.\\ - \macro{PIPE\_BUF}& 512 & byte scrivibili atomicamente in una pipe\\ \macro{LINK\_MAX} &8 & numero massimo di link a un file\\ - \macro{MAX\_CANON}&255 & spazio disponibile nella coda di input - canonica del terminale\\ + \macro{NAME\_MAX}& 14 & lunghezza in byte di un nome di file. \\ + \macro{PATH\_MAX}& 256 & lunghezza in byte di un pathname.\\ + \macro{PIPE\_BUF}&4096 & byte scrivibili atomicamente in una pipe + (vedi \secref{sec:ipc_pipes}).\\ + \macro{MAX\_CANON}&255 & dimensione di una riga di terminale in modo + canonico (vedi \secref{sec:term_design}).\\ \macro{MAX\_INPUT}&255 & spazio disponibile nella coda di input - del terminale\\ + del terminale (vedi \secref{sec:term_design}).\\ \hline \end{tabular} \caption{Macro per i limiti sulle caratteristiche dei file.} \label{tab:sys_file_macro} \end{table} -Come per i limiti di sistema POSIX.1 detta una serie di valori minimi per -queste caratteristiche, che ogni sistema che vuole essere conforme deve -rispettare; le relative macro sono riportate in \tabref{tab:sys_posix1_file}, -e per esse vale lo stesso discorso fatto per le analoghe di -\tabref{tab:sys_posix1_general}. +Come per i limiti di sistema, lo standard POSIX.1 detta una serie di valori +minimi anche per queste caratteristiche, che ogni sistema che vuole essere +conforme deve rispettare; le relative macro sono riportate in +\tabref{tab:sys_posix1_file}, e per esse vale lo stesso discorso fatto per le +analoghe di \tabref{tab:sys_posix1_general}. \begin{table}[htb] \centering \footnotesize - \begin{tabular}[c]{|l|r|p{8cm}|} + \begin{tabular}[c]{|l|r|l|} \hline \textbf{Macro}&\textbf{Valore}&\textbf{Significato}\\ \hline \hline - \textbf{Macro}&\textbf{Valore}&\textbf{Significato}\\ - \macro{\_POSIX\_LINK\_MAX} &8 & numero massimo di link a un file\\ - \macro{\_POSIX\_MAX\_CANON}&255 & spazio disponibile nella coda di input - canonica del terminale\\ - \macro{\_POSIX\_MAX\_INPUT}&255 & spazio disponibile nella coda di input - del terminale\\ + \macro{\_POSIX\_LINK\_MAX} &8 & numero massimo di link a un file.\\ \macro{\_POSIX\_NAME\_MAX}& 14 & lunghezza in byte di un nome di file. \\ - \macro{\_POSIX\_PATH\_MAX}& 256 & lunghezza in byte di pathname.\\ + \macro{\_POSIX\_PATH\_MAX}& 256 & lunghezza in byte di un pathname.\\ \macro{\_POSIX\_PIPE\_BUF}& 512 & byte scrivibili atomicamente in una - pipe\\ + pipe.\\ + \macro{\_POSIX\_MAX\_CANON}&255 & dimensione di una riga di + terminale in modo canonico.\\ + \macro{\_POSIX\_MAX\_INPUT}&255 & spazio disponibile nella coda di input + del terminale.\\ % \macro{\_POSIX\_MQ\_OPEN\_MAX}& 8& \\ % \macro{\_POSIX\_MQ\_PRIO\_MAX}& 32& \\ % \macro{\_POSIX\_FD\_SETSIZE}& 16 & \\ @@ -446,22 +451,22 @@ implementazioni moderne. \label{sec:sys_pathconf} In generale i limiti per i file sono molto più soggetti ad essere variabili -rispetto ai precedenti limiti generali del sistema; ad esempio parametri come -la lunghezza del nome del file o il numero di link possono variare da -filesystem a filesystem; per questo motivo questi limiti devono essere sempre -controllati con la funzione \func{pathconf}, il cui prototipo è: +rispetto ai limiti generali del sistema; ad esempio parametri come la +lunghezza del nome del file o il numero di link possono variare da filesystem +a filesystem; per questo motivo questi limiti devono essere sempre controllati +con la funzione \func{pathconf}, il cui prototipo è: \begin{prototype}{unistd.h}{long pathconf(char *path, int name)} Restituisce il valore del parametro \param{name} per il file \param{path}. \bodydesc{La funzione restituisce indietro il valore del parametro - richiesto, o -1 in caso di errore (ed \var{errno} viene settata ad uno + richiesto, o -1 in caso di errore (ed \var{errno} viene impostata ad uno degli errori possibili relativi all'accesso a \param{path}).} \end{prototype} E si noti come la funzione in questo caso richieda un parametro che specifichi a quale file si fa riferimento, dato che il valore del limite cercato può variare a seconda del filesystem. Una seconda versione della funzione, -\func{fpathconf}, opera su un file descriptor invece che su un pathname, il +\func{fpathconf}, opera su un file descriptor invece che su un pathname. Il suo prototipo è: \begin{prototype}{unistd.h}{long fpathconf(int fd, int name)} Restituisce il valore del parametro \param{name} per il file \param{fd}. @@ -477,13 +482,13 @@ suo prototipo \label{sec:sys_uname} Un'altra funzione che si può utilizzare per raccogliere informazioni sia -riguardo al sistema che al computer su cui esso sta girando è \func{uname}, il +riguardo al sistema che al computer su cui esso sta girando è \func{uname}; il suo prototipo è: \begin{prototype}{sys/utsname.h}{int uname(struct utsname *info)} Restituisce informazioni sul sistema nella struttura \param{info}. \bodydesc{La funzione ritorna 0 in caso di successo e -1 in caso di - fallimento, nel qual caso \var{errno} viene settata a \macro{EFAULT}.} + fallimento, nel qual caso \var{errno} assumerà il valore \macro{EFAULT}.} \end{prototype} La funzione, che viene usata dal comando \cmd{uname}, restituisce le @@ -500,7 +505,7 @@ indicano rispettivamente: \item il nome del domino. \end{itemize*} l'ultima informazione è stata aggiunta di recente e non è prevista dallo -standard POSIX, essa è accessibile, come mostrato in \figref{fig:sig_stack_t}, +standard POSIX, essa è accessibile, come mostrato in \figref{fig:sys_utsname}, solo definendo \macro{\_GNU\_SOURCE}. \begin{figure}[!htb] @@ -529,11 +534,12 @@ In generale si tenga presente che le dimensioni delle stringe di una \macro{NULL}; il manuale delle \acr{glibc} indica due diverse dimensioni, \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} or \macro{\_SYS\_NMLN} -or \macro{UTSLEN} che possono avere valori diversi; nel caso di Linux +altri sistemi usano nomi diversi come \macro{SYS\_NMLN} o \macro{\_SYS\_NMLN} +o \macro{UTSLEN} che possono avere valori diversi.\footnote{Nel caso di Linux \func{uname} corrisponde in realtà a 3 system call diverse, le prime due usano -delle lunghezze delle stringhe di 9 e 65 byte; la terza 65, restituisce anche -l'ultimo campo con una lunghezza di 257 byte. +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 +una lunghezza di 257 byte.} \section{Opzioni e configurazione del sistema} @@ -549,67 +555,68 @@ Inoltre, al di la di quelli che possono essere limiti caratteristici previsti da uno standard, ogni sistema può avere una sua serie di altri parametri di configurazione, che, non essendo mai fissi e variando da sistema a sistema, non sono stati inclusi nella standardizzazione della sezione precedente. Per -questi occorre, oltre al meccanismo di settaggio, pure un meccanismo di -lettura. - -Affronteremo questi argomenti in questa sezione, insieme alle funzioni che si -usano per il controllo di altre caratteristiche generali del sistema, come -quelle per la gestione dei filesystem e di utenti e gruppi. +questi occorre, oltre al meccanismo di impostazione, pure un meccanismo di +lettura. Affronteremo questi argomenti in questa sezione, insieme alle +funzioni che si usano per il controllo di altre caratteristiche generali del +sistema, come quelle per la gestione dei filesystem e di utenti e gruppi. \subsection{La funzione \func{sysctl} ed il filesystem \file{/proc}} \label{sec:sys_sysctl} -La funzione che permette la lettura ed il settaggio dei parametri del sistema -è \func{sysctl}; è una funzione derivata da BSD4.4, ma l'implementazione è -specifica di Linux; il suo prototipo è: +La funzione che permette la lettura ed l'impostazione dei parametri del +sistema è \func{sysctl}; è una funzione derivata da BSD4.4, ma +l'implementazione è specifica di Linux; il suo prototipo è: \begin{functions} \headdecl{unistd.h} -\headdecl{linux/unistd.h} -\headdecl{linux/sysctl.h} \funcdecl{int sysctl(int *name, int nlen, void *oldval, size\_t *oldlenp, void *newval, size\_t newlen)} Legge o scrive uno dei parametri di sistema. \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di - errore, nel qual caso \var{errno} viene settato ai valori: + errore, nel qual caso \var{errno} assumerà uno dei valori: \begin{errlist} - \item[\macro{EPERM}] il processo non ha il permesso di accedere ad uno dei - componenti nel cammino specificato per il parametro, o non ha il permesso - di accesso al parametro nella modalità scelta. + \item[\macro{EPERM}] non si ha il permesso di accedere ad uno dei componenti + nel cammino specificato per il parametro, o di accedere al parametro nella + modalità scelta. \item[\macro{ENOTDIR}] non esiste un parametro corrispondente al nome \param{name}. - \item[\macro{EFAULT}] si è specificato \param{oldlenp} zero quando - \param{oldval} è non nullo. +% \item[\macro{EFAULT}] si è specificato \param{oldlenp} zero quando +% \param{oldval} è non nullo. \item[\macro{EINVAL}] o si è specificato un valore non valido per il - parametro che si vuole settare o lo spazio provvisto per il ritorno di un + parametro che si vuole impostare o lo spazio provvisto per il ritorno di un valore non è delle giuste dimensioni. \item[\macro{ENOMEM}] talvolta viene usato più correttamente questo errore quando non si è specificato sufficiente spazio per ricevere il valore di un parametro. \end{errlist} + ed inoltre \macro{EFAULT}. } \end{functions} I parametri a cui la funzione permettere di accedere sono organizzati in -maniera gerarchica all'interno un albero; per accedere ad uno di essi occorre -specificare un cammino attraverso i vari nodi dell'albero, in maniera analoga -a come avviene per la risoluzione di un pathname (da cui l'uso alternativo del -filesystem \file{/proc} che vedremo dopo). +maniera gerarchica all'interno un albero;\footnote{si tenga presente che + includendo solo \file{unistd.h}, saranno definiti solo i parametri generici; + dato che ce ne sono molti specifici dell'implementazione, nel caso di Linux + occorrerà includere anche i file \file{linux/unistd.h} e + \file{linux/sysctl.h}.} per accedere ad uno di essi occorre specificare un +cammino attraverso i vari nodi dell'albero, in maniera analoga a come avviene +per la risoluzione di un pathname (da cui l'uso alternativo del filesystem +\file{/proc}, che vedremo dopo). Ciascun nodo dell'albero è identificato da un valore intero, ed il cammino che arriva ad identificare un parametro specifico è passato alla funzione attraverso l'array \param{name}, di lunghezza \param{nlen}, che contiene la sequenza dei vari nodi da attraversare. Ogni parametro ha un valore in un -formato specifico chee può essere un intero, una stringa o anche una struttura +formato specifico che può essere un intero, una stringa o anche una struttura complessa, per questo motivo il valori vengono passati come puntatori \ctyp{void}. L'indirizzo a cui il valore corrente del parametro deve essere letto è specificato da \param{oldvalue}, e lo spazio ivi disponibile è specificato da \param{oldlenp} (passato come puntatore per avere indietro la dimensione -effettiva di quanto letto); il valore che si vuole settare nel sistema è +effettiva di quanto letto); il valore che si vuole impostare nel sistema è passato in \param{newval} e la sua dimensione in \param{newlen}. Si può effettuare anche una lettura e scrittura simultanea, nel qual caso il @@ -645,7 +652,7 @@ nomi dei file corrispondenti, e questo ha il grande vantaggio di rendere accessibili i vari parametri a qualunque comando di shell e di permettere la navigazione dell'albero dei valori. -Alcune delle corrispondenze dei file presentin \file{/proc/sys} con i valori +Alcune delle corrispondenze dei file presenti in \file{/proc/sys} con i valori di \func{sysctl} sono riportate nei commenti del codice che può essere trovato in \file{linux/sysctl.h},\footnote{indicando un file di definizioni si fa riferimento alla directory standard dei file di include, che in ogni @@ -721,7 +728,7 @@ loro dati sono generati al volo ad ogni lettura, e passati al kernel ad ogni scrittura. Il tipo di filesystem è specificato da \param{filesystemtype}, che deve essere -una delle stringhe riportate in \file{/proc/filesystems}, che contiene +una delle stringhe riportate nel file \file{/proc/filesystems}, che contiene l'elenco dei filesystem supportati dal kernel; nel caso si sia indicato uno dei filesystem virtuali, il contenuto di \param{source} viene ignorato. @@ -731,8 +738,8 @@ precedente contenuto di detta directory viene mascherato dal contenuto della directory radice del filesystem montato. Dal kernel 2.4.x inoltre è divenuto possibile sia spostare atomicamente un -\textit{mount point} da una directory ad un'altra, che montare in diversi -\textit{mount point} lo stesso filesystem, che montare più filesystem sullo +\textit{mount point} da una directory ad un'altra, sia montare in diversi +\textit{mount point} lo stesso filesystem, sia montare più filesystem sullo stesso \textit{mount point} (nel qual caso vale quanto appena detto, e solo il contenuto dell'ultimo filesystem montato sarà visibile). @@ -747,8 +754,8 @@ significativi sono un \textit{magic number}\footnote{cio costante \macro{MS\_MGC\_MSK} per ottenere la parte di \param{mountflags} riservata al \textit{magic number}.} mentre i 16 meno significativi sono usati per specificare le opzioni; essi sono usati come maschera binaria e -vanno settati con un OR aritmetico della costante \macro{MS\_MGC\_VAL} con i -valori riportati in \ntab. +vanno impostati con un OR aritmetico della costante \macro{MS\_MGC\_VAL} con i +valori riportati in \tabref{tab:sys_mount_flags}. \begin{table}[htb] \footnotesize @@ -782,7 +789,7 @@ valori riportati in \ntab. \label{tab:sys_mount_flags} \end{table} -Per il settaggio delle caratteristiche particolari di ciascun filesystem si +Per l'impostazione delle caratteristiche particolari di ciascun filesystem si usa invece l'argomento \param{data} che serve per passare le ulteriori informazioni necessarie, che ovviamente variano da filesystem a filesystem. @@ -790,12 +797,11 @@ La funzione \func{mount} pu \textsl{rimontaggio} di un filesystem, cosa che permette di cambiarne al volo alcune delle caratteristiche di funzionamento (ad esempio passare da sola lettura a lettura/scrittura). Questa operazione è attivata attraverso uno dei -bit di \param{mountflags}, \macro{MS\_REMOUNT}, che se settato specifica che +bit di \param{mountflags}, \macro{MS\_REMOUNT}, che se impostato specifica che deve essere effettuato il rimontaggio del filesystem (con le opzioni specificate dagli altri bit), anche in questo caso il valore di \param{source} viene ignorato. - Una volta che non si voglia più utilizzare un certo filesystem è possibile \textsl{smontarlo} usando la funzione \func{umount}, il cui prototipo è: \begin{prototype}{sys/mount.h}{umount(const char *target)} @@ -803,7 +809,7 @@ Una volta che non si voglia pi Smonta il filesystem montato sulla directory \param{target}. \bodydesc{La funzione ritorna 0 in caso di successo e -1 in caso di - fallimento, nel qual caso \var{errno} viene settata a: + fallimento, nel qual caso \var{errno} assumerà uno dei valori: \begin{errlist} \item[\macro{EPERM}] il processo non ha i privilegi di amministratore. \item[\macro{EBUSY}] \param{target} è la directory di lavoro di qualche @@ -858,7 +864,7 @@ informazioni riguardo al filesystem su cui si trova un certo file, sono posto il file specificato. \bodydesc{Le funzioni ritornano 0 in caso di successo e -1 in caso di - errore, nel qual caso \var{errno} viene settato ai valori: + errore, nel qual caso \var{errno} assumerà uno dei valori: \begin{errlist} \item[\macro{ENOSYS}] il filesystem su cui si trova il file specificato non supporta la funzione. @@ -872,7 +878,7 @@ Queste funzioni permettono di ottenere una serie di informazioni generali riguardo al filesystem su cui si trova il file specificato; queste vengono restituite una struttura \param{buf} di tipo \type{statfs} definita come in \ref{fig:sys_statfs}, ed i campi che sono indefiniti per il filesystem in -esame sono settati a zero. I valori del campo \var{f\_type} sono definiti per +esame sono impostati a zero. I valori del campo \var{f\_type} sono definiti per i vari filesystem nei relativi file di header dei sorgenti del kernel da costanti del tipo \macro{XXX\_SUPER\_MAGIC}, dove \macro{XXX} in genere è il nome del filesystem stesso. @@ -881,18 +887,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 @@ -902,14 +908,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 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 @@ -920,14 +926,18 @@ tralasceremo la trattazione, rimandando al manuale delle \acr{glibc} \subsection{La gestione di utenti e gruppi} \label{sec:sys_user_group} -L'ultimo argomento di questa sezione è quello che riguarda le funzioni -utilizzate per gestire utenti e gruppi all'interno del sistema. Tradizionalmente l'informazione per la gestione di utenti e gruppi veniva -tenuta tutta nei due file di testo \file{/etc/passwd} ed \file{/etc/group}; -oggi la maggior parte delle distribuzioni di Linux usa la libreria PAM (sigla -che sta \textit{Pluggable Authentication Method}) che permette di separare -completamente i meccanismi di gestione degli utenti (autenticazione, -riconoscimento, ecc.) dalle modalità in cui i relativi dati vengono mantenuti. +tenuta tutta nei due file di testo \file{/etc/passwd} ed \file{/etc/group}, e +tutte le funzioni facevano riferimento ad essi. Oggi la maggior parte delle +distribuzioni di Linux usa la libreria PAM (sigla che sta \textit{Pluggable + Authentication Method}) che permette di separare completamente i meccanismi +di gestione degli utenti (autenticazione, riconoscimento, ecc.) dalle modalità +in cui i relativi dati vengono mantenuti, per cui pur restando in gran parte +le stesse\footnote{in genere quello che viene cambiato è l'informazione usata + per l'autenticazione, che non è più necessariamente una password criptata da + verificare, ma può assumere le forme più diverse, come impronte digitali, + chiavi elettroniche, ecc.}, le informazioni non sono più necessariamente +mantenute in quei file. In questo paragrafo ci limiteremo comunque alle funzioni classiche per la lettura delle informazioni relative a utenti e gruppi previste dallo standard @@ -944,19 +954,20 @@ funzioni, \func{getpwuid} e \func{getpwnam}, i cui prototipi sono: \funcdecl{struct passwd *getpwnam(const char *name)} - Restituiscono le informazioni relative alll'utente specificato. + Restituiscono le informazioni relative all'utente specificato. \bodydesc{Le funzioni ritornano il puntatore alla struttura contenente le - informazioni in caso di successo e \macro{NULL} in caso di errore, nel - qual caso \var{errno} viene settata ad \macro{ENOMEM}.} + informazioni in caso di successo e \macro{NULL} nel caso non sia stato + trovato nessun utente corrispondente a quanto specificato.} \end{functions} Le due funzioni forniscono le informazioni memorizzate nel database degli utenti (che nelle versioni più recenti possono essere ottenute attraverso PAM) relative all'utente specificato attraverso il suo \acr{uid} o il nome di -login, restituendo un puntatore ad una struttura di tipo \type{passwd}, (la -cui definizione è riportata in \figref{fig:sys_passwd_struct}), allocata -staticamente. +login. Entrambe le funzioni restituiscono un puntatore ad una struttura di +tipo \type{passwd} la cui definizione (anch'essa eseguita in \file{pwd.h}) è +riportata in \figref{fig:sys_passwd_struct}, dove è pure brevemente illustrato +il significato dei vari campi. \begin{figure}[!htb] \footnotesize @@ -980,6 +991,69 @@ struct passwd { \label{fig:sys_passwd_struct} \end{figure} +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 possono +essere rientranti, per cui ne esistono anche due versioni alternative +(denotate dalla solita estensione \code{\_r}), i cui prototipi sono: +\begin{functions} + \headdecl{pwd.h} + + \headdecl{sys/types.h} + + \funcdecl{struct passwd *getpwuid\_r(uid\_t uid, struct passwd *password, + char *buffer, size\_t buflen, struct passwd **result)} + + \funcdecl{struct passwd *getpwnam\_r(const char *name, struct passwd + *password, char *buffer, size\_t buflen, struct passwd **result)} + + Restituiscono le informazioni relative all'utente specificato. + + \bodydesc{Le funzioni ritornano 0 in caso di successo e un codice d'errore + altrimenti, nel qual caso \var{errno} sarà impostata opportunamente.} +\end{functions} + +In questo caso l'uso è molto più complesso, in quanto bisogna prima allocare +la memoria necessaria a contenere le informazioni. In particolare i valori +della struttura \var{passwd} saranno restituiti all'indirizzo \param{password} +mentre la memoria allocata all'indirizzo \param{buffer}, per un massimo di +\param{buflen} byte, sarà utilizzata per contenere le stringhe puntate dai +campi di \param{password}. Infine all'indirizzo puntato da \param{result} +viene restituito il puntatore ai dati ottenuti, cioè \param{buffer} nel caso +l'utente esista, o \macro{NULL} altrimenti. Qualora i dati non possano essere +contenuti nei byte specificati da \param{buflen}, la funzione fallirà +restituendo \macro{ERANGE} (e \param{result} sarà comunque impostato a +\macro{NULL}). + +Del tutto analoghe alle precedenti sono le funzioni \func{getgrnam} e +\func{getgrgid} (e le relative analoghe rientranti con la stessa estensione +\code{\_r}) che permettono di leggere le informazioni relative ai gruppi, i +loro prototipi sono: +\begin{functions} + \headdecl{grp.h} + \headdecl{sys/types.h} + + \funcdecl{struct group *getgrgid(gid\_t gid)} + + \funcdecl{struct group *getgrnam(const char *name)} + + \funcdecl{struct group *getpwuid\_r(gid\_t gid, struct group *password, + char *buffer, size\_t buflen, struct group **result)} + + \funcdecl{struct group *getpwnam\_r(const char *name, struct group + *password, char *buffer, size\_t buflen, struct group **result)} + + Restituiscono le informazioni relative al gruppo specificato. + + \bodydesc{Le funzioni ritornano 0 in caso di successo e un codice d'errore + altrimenti, nel qual caso \var{errno} sarà impostata opportunamente.} +\end{functions} + +Il comportamento di tutte queste funzioni è assolutamente identico alle +precedenti che leggono le informazioni sugli utenti, l'unica differenza è che +in questo caso le informazioni vengono restituite in una struttura di tipo +\type{group}, la cui definizione è riportata in \figref{fig:sys_group_struct}. \begin{figure}[!htb] \footnotesize @@ -995,84 +1069,605 @@ struct group { \end{lstlisting} \end{minipage} \normalsize - \caption{La struttura \var{passwd} contenente le informazioni relative ad un - utente del sistema.} - \label{fig:sys_passwd_struct} + \caption{La struttura \var{group} contenente le informazioni relative ad un + gruppo del sistema.} + \label{fig:sys_group_struct} +\end{figure} + +Le funzioni viste finora sono in grado di leggere le informazioni sia dal file +delle password in \file{/etc/passwd} che con qualunque altro metodo sia stato +utilizzato per mantenere il database degli utenti. Non permettono però di +impostare direttamente le password; questo è possibile con un'altra interfaccia +al database degli utenti, derivata da SVID, che però funziona soltanto con un +database che sia tenuto su un file che abbia il formato classico di +\file{/etc/passwd}. + +\begin{table}[htb] + \footnotesize + \centering + \begin{tabular}[c]{|l|p{8cm}|} + \hline + \textbf{Funzione} & \textbf{Significato}\\ + \hline + \hline + \func{fgetpwent} & Legge una voce dal database utenti da un file + specificato aprendolo la prima volta.\\ + \func{fgetpwent\_r}& Come la precedente, ma rientrante.\\ + \func{getpwent} & Legge una voce dal database utenti (da + \file{/etc/passwd}) aprendolo la prima volta.\\ + \func{getpwent\_r} & Come la precedente, ma rientrante.\\ + \func{setpwent} & Ritorna all'inizio del database.\\ + \func{putpwent} & Immette una voce nel database utenti.\\ + \func{endpwent} & Chiude il database degli utenti.\\ + \func{fgetgrent} & Legge una voce dal database dei gruppi da un file + specificato aprendolo la prima volta.\\ + \func{fgetgrent\_r}& Come la precedente, ma rientrante.\\ + \func{getgrent} & Legge una voce dal database dei gruppi (da + \file{/etc/passwd}) aprendolo la prima volta.\\ + \func{getgrent\_r} & Come la precedente, ma rientrante.\\ + \func{setgrent} & Immette una voce nel database dei gruppi.\\ + \func{putgrent} & Immette una voce nel database dei gruppi.\\ + \func{endgrent} & Chiude il database dei gruppi.\\ + \hline + \end{tabular} + \caption{Funzioni per la manipolazione dei campi di un file usato come + database di utenti e gruppi nel formato di \file{/etc/passwd} e + \file{/etc/groups}.} + \label{tab:sys_passwd_func} +\end{table} + +Dato che ormai la gran parte delle distribuzioni di Linux utilizzano PAM, che +come minimo usa almeno le \textit{shadow password} (quindi con delle modifiche +rispetto al formato classico di \file{/etc/passwd}), le funzioni che danno la +capacità scrivere delle voci nel database (cioè \func{putpwent} e +\func{putgrent}) non permettono di effettuarne una specificazione in maniera +completa. Per questo motivo l'uso di queste funzioni è deprecato in favore +dell'uso di PAM, ci limiteremo pertanto ad elencarle in +\tabref{tab:sys_passwd_func}, rimandando chi fosse interessato alle rispettive +pagine di manuale e al manuale delle \acr{glibc} per i dettagli del loro +funzionamento. + + + +\subsection{Il database di accounting} +\label{sec:sys_accounting} + +L'ultimo insieme di funzioni relative alla gestione del sistema che +esamineremo è quello che permette di accedere ai dati del database di +\textit{accounting}. In esso vengono mantenute una serie di informazioni +storiche relative sia agli utenti che si sono collegati al sistema, (tanto per +quelli correntemente collegati, che per la registrazione degli accessi +precedenti), sia relative all'intero sistema, come il momento di lancio di +processi da parte di \cmd{init}, il cambiamento dell'orologio di sistema, il +cambiamento di runlevel o il riavvio della macchina. + +I dati vengono usualmente\footnote{questa è la locazione specificata dal + \textit{Linux Filesystem Hierarchy Standard}, adottato dalla gran parte + delle distribuzioni.} memorizzati nei due file \file{/var/run/utmp} e +\file{/var/log/wtmp}. Quando un utente si collega viene aggiunta una voce a +\file{/var/run/utmp} in cui viene memorizzato il nome di login, il terminale +da cui ci si collega, l'\acr{uid} della shell di login, l'orario della +connessione ed altre informazioni. La voce resta nel file fino al logout, +quando viene cancellata e spostata in \file{/var/log/wtmp}. + +In questo modo il primo file viene utilizzato per registrare sta utilizzando +il sistema al momento corrente, mentre il secondo mantiene la registrazione +delle attività degli utenti. A quest'ultimo vengono anche aggiunte delle voci +speciali per tenere conto dei cambiamenti del sistema, come la modifica del +runlevel, il riavvio della macchina, ecc. Tutte queste informazioni sono +descritte in dettaglio nel manuale delle \acr{glibc}. + +Questi file non devono mai essere letti direttamente, ma le informazioni che +contengono possono essere ricavate attraverso le opportune funzioni di +libreria. Queste sono analoghe alle precedenti (vedi +\tabref{tab:sys_passwd_func}) usate per accedere al database degli utenti, +solo che in questo caso la struttura del database di accounting è molto più +complessa, dato che contiene diversi tipi di informazione. + +Le prime tre funzioni, \func{setutent}, \func{endutent} e \func{utmpname} +servono rispettivamente a aprire e a chiudere il file che contiene il +database, e a specificare su quale file esso viene mantenuto. I loro prototipi +sono: +\begin{functions} + \headdecl{utmp.h} + + \funcdecl{void utmpname(const char *file)} Specifica il file da usare come + database di \textit{accounting}. + + \funcdecl{void setutent(void)} Apre il file del database di + \textit{accounting}, posizionandosi al suo inizio. + + \funcdecl{void endutent(void)} Chiude il file del database di + \textit{accounting}. + + \bodydesc{Le funzioni non ritornano codici di errore.} +\end{functions} + +In caso questo non venga specificato nessun file viene usato il valore +standard \macro{\_PATH\_UTMP} (che è definito in \file{paths.h}); in genere +\func{utmpname} prevede due possibili valori: +\begin{basedescript}{\desclabelwidth{2.0cm}} +\item[\macro{\_PATH\_UTMP}] Specifica il database di accounting per gli utenti + correntemente collegati. +\item[\macro{\_PATH\_WTMP}] Specifica il database di accounting per l'archivio + storico degli utenti collegati. +\end{basedescript} +corrispondenti ai file \file{/var/run/utmp} e \file{/var/log/wtmp} visti in +precedenza. + +Una volta aperto il file si può eseguire una scansione leggendo o scrivendo +una voce con le funzioni \func{getutent}, \func{getutid}, \func{getutline} e +\func{pututline}, i cui prototipi sono: +\begin{functions} + \headdecl{utmp.h} + + \funcdecl{struct utmp *getutent(void)} + Legge una voce dal dalla posizione corrente nel database. + + \funcdecl{struct utmp *getutid(struct utmp *ut)} + Ricerca una voce sul database in base al contenuto di \param{ut}. + + \funcdecl{struct utmp *getutline(struct utmp *ut)} + Ricerca nel database la prima voce corrispondente ad un processo sulla linea + di terminale specificata tramite \param{ut}. + + \funcdecl{struct utmp *pututline(struct utmp *ut)} + Scrive una voce nel database. + + \bodydesc{Le funzioni ritornano il puntatore ad una struttura \var{utmp} in + caso di successo e \macro{NULL} in caso di errore.} +\end{functions} + +Tutte queste funzioni fanno riferimento ad una struttura di tipo \var{utmp}, +la cui definizione in Linux è riportata in \secref{fig:sys_utmp_struct}. Le +prime tre funzioni servono per leggere una voce dal database; \func{getutent} +legge semplicemente la prima voce disponibile; le altre due permettono di +eseguire una ricerca. + +\begin{figure}[!htb] + \footnotesize + \centering + \begin{minipage}[c]{15cm} + \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{} +struct utmp +{ + short int ut_type; /* Type of login. */ + pid_t ut_pid; /* Process ID of login process. */ + char ut_line[UT_LINESIZE]; /* Devicename. */ + char ut_id[4]; /* Inittab ID. */ + char ut_user[UT_NAMESIZE]; /* Username. */ + char ut_host[UT_HOSTSIZE]; /* Hostname for remote login. */ + struct exit_status ut_exit; /* Exit status of a process marked + as DEAD_PROCESS. */ + long int ut_session; /* Session ID, used for windowing. */ + struct timeval ut_tv; /* Time entry was made. */ + int32_t ut_addr_v6[4]; /* Internet address of remote host. */ + char __unused[20]; /* Reserved for future use. */ +}; + \end{lstlisting} + \end{minipage} + \normalsize + \caption{La struttura \var{utmp} contenente le informazioni di una voce del + database di \textit{accounting}.} + \label{fig:sys_utmp_struct} \end{figure} +Con \func{getutid} si può cercare una voce specifica, a seconda del valore del +campo \var{ut\_type} dell'argomento \param{ut}. Questo può assumere i valori +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à restituita la prima voce +corrispondente al valore del campo \var{ut\_id} specificato in \param{ut}. + +\begin{table}[htb] + \footnotesize + \centering + \begin{tabular}[c]{|l|p{8cm}|} + \hline + \textbf{Funzione} & \textbf{Significato}\\ + \hline + \hline + \macro{EMPTY} & Non contiene informazioni valide. \\ + \macro{RUN\_LVL} & Identica il runlevel del sistema. \\ + \macro{BOOT\_TIME} & Identifica il tempo di avvio del sistema \\ + \macro{OLD\_TIME} & Identifica quando è stato modificato l'orologio di + sistema. \\ + \macro{NEW\_TIME} & Identifica da quanto è stato modificato il + sistema. \\ + \macro{INIT\_PROCESS} & Identifica un processo lanciato da \cmd{init}. \\ + \macro{LOGIN\_PROCESS}& Identifica un processo di login. \\ + \macro{USER\_PROCESS} & Identifica un processo utente. \\ + \macro{DEAD\_PROCESS} & Identifica un processo terminato. \\ + \macro{ACCOUNTING} & ??? \\ + \hline + \end{tabular} + \caption{Classificazione delle voci del database di accounting a seconda dei + possibili valori del campo \var{ut\_type}.} + \label{tab:sys_ut_type} +\end{table} + +La funzione \func{getutline} esegue la ricerca sulle voci che hanno +\var{ut\_type} uguale a \macro{LOGIN\_PROCESS} o \macro{USER\_PROCESS}, +restituendo la prima che corrisponde al valore di \var{ut\_line}, che +specifica il device\footnote{espresso senza il \file{/dev/} iniziale.} di +terminale che interessa. Lo stesso criterio di ricerca è usato da +\func{pututline} per trovare uno spazio dove inserire la voce specificata, +qualora non sia trovata la voce viene aggiunta in coda al database. + +In generale occorre però tenere conto che queste funzioni non sono +completamente standardizzate, e che in sistemi diversi possono esserci +differenze; ad esempio \func{pututline} restituisce \code{void} in vari +sistemi (compreso Linux, fino alle \acr{libc5}). Qui seguiremo la sintassi +fornita dalle \acr{glibc}, ma gli standard POSIX 1003.1-2001 e XPG4.2 hanno +introdotto delle nuove strutture (e relativi file) di tipo \code{utmpx}, che +sono un sovrainsieme di \code{utmp}. + +Le \acr{glibc} utilizzano già una versione estesa di \code{utmp}, che rende +inutili queste nuove strutture; pertanto esse e le relative funzioni di +gestione (\func{getutxent}, \func{getutxid}, \func{getutxline}, +\func{pututxline}, \func{setutxent} e \func{endutxent}) sono ridefinite come +sinonimi delle funzioni appena viste. + +Come visto in \secref{sec:sys_user_group}, l'uso di strutture allocate +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 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. + +Infine le \acr{glibc} forniscono come estensione per la scrittura delle voci +in \file{wmtp} altre due funzioni, \func{updwtmp} e \func{logwtmp}, i cui +prototipi sono: +\begin{functions} + \headdecl{utmp.h} + + \funcdecl{void updwtmp(const char *wtmp\_file, const struct utmp *ut)} + Aggiunge la voce \param{ut} nel database di accounting \file{wmtp}. + + \funcdecl{void logwtmp(const char *line, const char *name, const char + *host)} Aggiunge nel database di accounting una voce con i valori + specificati. + + \bodydesc{Le funzioni ritornano il puntatore ad una struttura \var{utmp} in + caso di successo e \macro{NULL} in caso di errore.} +\end{functions} + +La prima funzione permette l'aggiunta di una voce a \file{wmtp} specificando +direttamente una struttura \type{utmp}, mentre la seconda utilizza gli +argomenti \param{line}, \param{name} e \param{host} per costruire la voce che +poi aggiunge chiamando \func{updwtmp}. + \section{Limitazione ed uso delle risorse} \label{sec:sys_res_limits} -In questa sezione esamineremo le funzioni che permettono di esaminare e -controllare come le varie risorse del sistema (CPU, memoria, ecc.) vengono -utilizzate dai singoli processi, e le modalità con cui è possibile imporre dei -limiti sul loro utilizzo. +Dopo aver esaminato le funzioni che permettono di controllare le varie +caratteristiche, capacità e limiti del sistema a livello globale, in questa +sezione tratteremo le varie funzioni che vengono usate per quantificare le +risorse (CPU, memoria, ecc.) utilizzate da ogni singolo processo e quelle che +permettono di imporre a ciascuno di essi vincoli e limiti di utilizzo. \subsection{L'uso delle risorse} \label{sec:sys_resource_use} +Come abbiamo accennato in \secref{sec:proc_wait4} le informazioni riguardo +l'utilizzo delle risorse da parte di un processo è mantenuto in una struttura +di tipo \code{struct }\type{rusage}, la cui definizione (che si trova in +\file{sys/resource.h}) è riportata in \figref{fig:sys_rusage_struct}. +\begin{figure}[!htb] + \footnotesize + \centering + \begin{minipage}[c]{15cm} + \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{} +struct rusage { + struct timeval ru_utime; /* user time used */ + struct timeval ru_stime; /* system time used */ + long ru_maxrss; /* maximum resident set size */ + long ru_ixrss; /* integral shared memory size */ + long ru_idrss; /* integral unshared data size */ + long ru_isrss; /* integral unshared stack size */ + long ru_minflt; /* page reclaims */ + long ru_majflt; /* page faults */ + long ru_nswap; /* swaps */ + long ru_inblock; /* block input operations */ + long ru_oublock; /* block output operations */ + long ru_msgsnd; /* messages sent */ + long ru_msgrcv; /* messages received */ + long ru_nsignals; ; /* signals received */ + long ru_nvcsw; /* voluntary context switches */ + long ru_nivcsw; /* involuntary context switches */ +}; + \end{lstlisting} + \end{minipage} + \normalsize + \caption{La struttura \var{rusage} per la lettura delle informazioni dei + delle risorse usate da un processo.} + \label{fig:sys_rusage_struct} +\end{figure} -\subsection{Limiti sulle risorse} -\label{sec:sys_resource_limit} +La struttura è ripresa da BSD 4.3, ma attualmente (con i kernel della serie +2.4.x) i soli campi che sono mantenuti sono: \var{ru\_utime}, \var{ru\_stime}, +\var{ru\_minflt}, \var{ru\_majflt}, e \var{ru\_nswap}. I primi due indicano +rispettivamente il tempo impiegato dal processo nell'eseguire le istruzioni in +user space, e quello impiegato dal kernel nelle system call eseguite per conto +del processo. + +Gli altri tre campi servono a quantificare l'uso della memoria +virtuale\index{memoria virtuale} e corrispondono rispettivamente al numero di +\textit{page fault}\index{page fault} (vedi \secref{sec:proc_mem_gen}) +avvenuti senza richiedere I/O (i cosiddetti \textit{minor page fault}), a +quelli che invece han richiesto I/O (detti invece \textit{major page fault}) +ed al numero di volte che il processo è stato completamente tolto dalla +memoria per essere inserito nello swap. + +In genere includere esplicitamente \file{} non è più necessario, +ma aumenta la portabilità, e serve comunque quando, come nella maggior parte +dei casi, si debba accedere ai campi di \var{rusage} relativi ai tempi di +utilizzo del processore, che sono definiti come \code{struct }\type{timeval}. + + +Questa è la stessa struttura utilizzata da \func{wait4} per ricavare la +quantità di risorse impiegato dal processo di cui si è letto lo stato di +terminazione, ma essa può anche essere letta direttamente utilizzando la +funzione \func{getrusage}, il cui prototipo è: +\begin{functions} + \headdecl{sys/time.h} + \headdecl{sys/resource.h} + \headdecl{unistd.h} + + \funcdecl{int getrusage(int who, struct rusage *usage)} + Legge la quantità di risorse usate da un processo. -\subsection{Le risorse di memoria} -\label{sec:sys_memory_res} + \bodydesc{La funzione ritorna 0 in caso di successo e -1 in caso di errore, + nel qual caso \var{errno} può essere \macro{EINVAL} o \macro{EFAULT}.} +\end{functions} +L'argomento \param{who} permette di specificare il processo di cui si vuole +leggere l'uso delle risorse; esso può assumere solo i due valori +\macro{RUSAGE\_SELF} per indicare il processo corrente e +\macro{RUSAGE\_CHILDREN} per indicare l'insieme dei processi figli di cui si è +ricevuto lo stato di terminazione. -\subsection{Le risorse di processore} -\label{sec:sys_cpu_load} +\subsection{Limiti sulle risorse} +\label{sec:sys_resource_limit} +Come accennato nell'introduzione oltre a leggere l'uso delle risorse da parte +di un processo si possono anche imporre dei limiti sulle sue capacità. Ogni +processo ha in generale due limiti associati ad ogni risorsa; questi sono +detti il \textsl{limite corrente} (o \textit{current limit}) che esprime il +valore che attualmente il processo non può superare, ed il \textsl{limite + massimo} (o \textit{maximum limit}) che esprime il valore massimo che può +assumere il \textsl{limite corrente}. + +In generale il primo viene chiamato un limite \textsl{soffice} (o \textit{soft + limit}) dato che il suo valore può essere aumentato, mentre il secondo è +detto \textsl{duro} (o \textit{hard limit}), in quanto un processo normale non +può modificarne il valore. Il valore di questi limiti è mantenuto in una +struttura \var{rlimit}, la cui definizione è riportata in +\figref{fig:sys_rlimit_struct}, ed i cui campi corrispondono appunto a limite +corrente e massimo. \begin{figure}[!htb] \footnotesize \centering \begin{minipage}[c]{15cm} \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{} -struct rusage { - struct timeval ru_utime; /* user time used */ - struct timeval ru_stime; /* system time used */ - long ru_maxrss; /* maximum resident set size */ - long ru_ixrss; /* integral shared memory size */ - long ru_idrss; /* integral unshared data size */ - long ru_isrss; /* integral unshared stack size */ - long ru_minflt; /* page reclaims */ - long ru_majflt; /* page faults */ - long ru_nswap; /* swaps */ - long ru_inblock; /* block input operations */ - long ru_oublock; /* block output operations */ - long ru_msgsnd; /* messages sent */ - long ru_msgrcv; /* messages received */ - long ru_nsignals; ; /* signals received */ - long ru_nvcsw; /* voluntary context switches */ - long ru_nivcsw; /* involuntary context switches */ +struct rlimit { + rlim_t rlim_cur; + rlim_t rlim_max; }; \end{lstlisting} \end{minipage} \normalsize - \caption{La struttura \var{rusage} per la lettura delle informazioni dei + \caption{La struttura \var{rlimit} per impostare i limiti di utilizzo delle risorse usate da un processo.} - \label{fig:sys_rusage_struct} + \label{fig:sys_rlimit_struct} \end{figure} +In genere il superamento di un limite comporta o l'emissione di un segnale o +il fallimento della system call che lo ha provocato; per far leggere o impostare +i limiti di utilizzo delle risorse da parte di un processo le \acr{glibc} +prevedono due funzioni, \func{getrlimit} e \func{setrlimit}, i cui prototipi +sono: +\begin{functions} + \headdecl{sys/time.h} + \headdecl{sys/resource.h} + \headdecl{unistd.h} + + \funcdecl{int getrlimit(int resource, struct rlimit *rlim)} + + Legge il limite corrente per la risorsa \param{resource}. + + \funcdecl{int setrlimit(int resource, const struct rlimit *rlim)} + + Imposta il limite per la risorsa \param{resource}. + + \bodydesc{Le funzioni ritornano 0 in caso di successo e -1 in caso di + errore, nel qual caso \var{errno} assumerà uno dei valori: + \begin{errlist} + \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} + ed \macro{EFAULT}.} +\end{functions} +Entrambe le funzioni permettono di specificare su quale risorsa si vuole +operare attraverso \param{resource}, i cui possibili valori sono elencati in +\secref{tab:sys_rlimit_values}, e utilizzano una struttura \var{rlimit} per +specificarne i valori. +\begin{table}[htb] + \footnotesize + \centering + \begin{tabular}[c]{|l|p{12cm}|} + \hline + \textbf{Valore} & \textbf{Significato}\\ + \hline + \hline + \macro{RLIMIT\_CPU} & Il massimo tempo di CPU che il processo può + usare. Il superamento del limite comporta + l'emissione di un segnale di \macro{SIGXCPU}.\\ + \macro{RLIMIT\_FSIZE} & La massima dimensione di un file che un processo + può usare. Se il processo cerca di scrivere + oltre questa dimensione riceverà un segnale di + \macro{SIGXFSZ}.\\ + \macro{RLIMIT\_DATA} & La massima dimensione della memoria dati di un + processo. Il tentativo di allocare più memoria + causa il fallimento della funzione di + allocazione. \\ + \macro{RLIMIT\_STACK} & La massima dimensione dello stack del + processo. Se il processo esegue operazioni che + estendano lo stack oltre questa dimensione + riceverà un segnale di \macro{SIGSEGV}.\\ + \macro{RLIMIT\_CORE} & La massima dimensione di un file di \textit{core + dump} creato da un processo. Nel caso le + dimensioni dovessero essere maggiori il file non + verrebbe generato.\footnotemark\\ + \macro{RLIMIT\_RSS} & L'ammontare massimo di memoria fisica dato al + processo. Il limite è solo una indicazione per + il kernel, qualora ci fosse un surplus di + memoria questa verrebbe assegnata.\\ + \macro{RLIMIT\_NPROC} & Il numero massimo di processi che possono essere + creati sullo stesso user id. Se il limite viene + raggiunto \func{fork} fallirà con un + \macro{EAGAIN}.\\ + \macro{RLIMIT\_NOFILE} & Il numero massimo di file che il processo può + aprire. L'apertura di un ulteriore file fallirà + con un errore \macro{EMFILE}.\\ + \macro{RLIMIT\_MEMLOCK}& L'ammontare massimo di memoria che può essere + bloccata (vedi \secref{sec:proc_mem_lock}).\\ + \macro{RLIMIT\_AS} & La dimensione massima di tutta la memoria che il + processo può ottenere. Se il processo tenta di + allocarne di più funzioni come \func{brk}, + \func{malloc} o \func{mmap} falliranno. \\ + \hline + \end{tabular} + \caption{Valori possibili dell'argomento \param{resource} delle funzioni + \func{getrlimit} e \func{setrlimit}.} + \label{tab:sys_rlimit_values} +\end{table} -\var{tms\_utime}, \var{tms\_stime}, \var{tms\_cutime}, \var{tms\_uetime} +\footnotetext{Impostare questo limite a zero è la maniera più semplice per + evitare la creazione di \file{core} file.} + +È inoltre definita la costante \macro{RLIM\_INFINITY} che permette di +sbloccare l'uso di una risorsa, ma solo un processo con i privilegi di +amministratore può innalzare un limite al di sopra del valore corrente del +limite massimo. Si tenga conto infine che tutti i limiti vengono ereditati dal +processo padre attraverso una \func{fork} (vedi \secref{sec:proc_fork}) e +mantenuti attraverso una \func{exec} (vedi \secref{sec:proc_exec}). + + +\subsection{Le risorse di memoria e processore} +\label{sec:sys_memory_res} + +La gestione della memoria è già stata affrontata in dettaglio in +\secref{sec:proc_memory}; abbiamo visto allora che il kernel provvede il +meccanismo della memoria virtuale\index{memoria virtuale} attraverso la +divisione della memoria fisica in pagine. + +In genere questo è del tutto trasparente al singolo processo, ma in certi +casi, come per l'I/O mappato in memoria (vedi \secref{sec:file_memory_map}) +che usa lo stesso meccanismo per accedere ai file, è necessario conoscere le +dimensioni delle pagine usate dal kernel. Lo stesso vale quando si vuole +gestire in maniera ottimale l'interazione della memoria allocata con il +meccanismo della paginazione. + +Di solito la dimensione delle pagine di memoria è fissata dall'architettura +hardware, per cui in genere la dimensione delle pagine di memoria era una +costante definita in fase di compilazione, ma oggi alcune architetture (ad +esempio su Sun Sparc) permettono di variare questa dimensione, e non volendo +dover fornire binari diversi per ogni possibile modello, è necessario poter +utilizzare una funzione. + +In genere questa dimensione può essere ottenuta attraverso una chiamata a +\func{sysconf} come \code{sysconf(\_SC\_PAGESIZE)}, ma in BSD 4.2 è stata +introdotta una apposita funzione, \func{getpagesize}, che restituisce la +dimensione delle pagine di memoria; il suo prototipo è: +\begin{prototype}{unistd.h}{int getpagesize(void)} + Legge le dimensioni delle pagine di memoria. + + \bodydesc{La funzione ritorna la dimensione di una pagina in byte, e non + sono previsti errori.} +\end{prototype} + +La funzione è prevista in SVr4, 4.4BSD e SUSv2, anche se questo ultimo +standard la etichetta come obsoleta, mentre lo standard POSIX 1003.1-2001 la +ha eliminata. In Linux è implementata come una system call nelle architetture +in cui essa è necessaria, ed in genere restituisce il valore del simbolo +\macro{PAGE\_SIZE} del kernel, anche se le versioni delle librerie del C +precedenti le \acr{glibc} 2.1 implementavano questa funzione restituendo +sempre un valore statico. + +Le \acr{glibc} forniscono, come specifica estensione GNU, altre due funzioni, +\func{get\_phys\_pages} e \func{get\_avphys\_pages} che permettono di ottenere +informazioni riguardo la memoria; i loro prototipi sono: +\begin{functions} + \headdecl{sys/sysinfo.h} + + \funcdecl{long int get\_phys\_pages(void)} + + Legge il numero totale di pagine di memoria disponibili per il sistema. + + \funcdecl{long int get\_avphys\_pages(void)} + + Legge il numero di pagine di memoria disponibili nel sistema. + + \bodydesc{Le funzioni restituiscono un numero di pagine.} +\end{functions} + +Queste funzioni sono equivalenti all'uso della funzione \func{sysconf} +rispettivamente con i parametri \macro{\_SC\_PHYS\_PAGES} e +\macro{\_SC\_AVPHYS\_PAGES}. La prima restituisce il numero totale di pagine +corrispondenti alla RAM della macchina; la seconda invece la memoria +effettivamente disponibile per i processi. + +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 +\macro{\_SC\_NPROCESSORS\_CONF} e \macro{\_SC\_NPROCESSORS\_ONLN}. + +Infine le \acr{glibc} riprendono da BSD la funzione \func{getloadavg} che +permette di ottenere il carico di processore della macchina, in questo modo è +possibile prendere decisioni su quando far partire eventuali nuovi processi. +Il suo prototipo è: +\begin{prototype}{stdlib.h}{int getloadavg(double loadavg[], int nelem)} + Legge il carico medio della macchina. + + \bodydesc{La funzione ritorna il numero di elementi scritti o -1 in caso di + errore.} +\end{prototype} + +La funzione restituisce in ciascun elemento di \param{loadavg} il numero medio +di processi attivi sulla coda dello scheduler, calcolato su un diverso +intervalli di tempo. Il numero di intervalli che si vogliono leggere è +specificato da \param{nelem}, dato che nel caso di Linux il carico viene +valutato solo su tre intervalli (corrispondenti a 1, 5 e 15 minuti), questo è +anche il massimo valore che può essere assegnato a questo argomento. \section{La gestione dei tempi del sistema} \label{sec:sys_time} -In questa sezione tratteremo le varie funzioni per la gestione delle -date e del tempo in un sistema unix-like, e quelle per convertire i vari -tempi nelle differenti rappresentazioni che vengono utilizzate. +In questa sezione, una volta introdotti i concetti base della gestione dei +tempi da parte del sistema, tratteremo le varie funzioni attinenti alla +gestione del tempo in un sistema unix-like, a partire da quelle per misurare i +veri tempi di sistema associati ai processi, a quelle per convertire i vari +tempi nelle differenti rappresentazioni che vengono utilizzate, a quelle della +gestione di data e ora. \subsection{La misura del tempo in Unix} @@ -1082,26 +1677,30 @@ Storicamente i sistemi unix-like hanno sempre mantenuto due distinti tipi di dati per la misure dei tempi all'interno del sistema: essi sono rispettivamente chiamati \textit{calendar time} e \textit{process time}, secondo le definizioni: -\begin{itemize} -\item \textit{calendar time}: è il numero di secondi dalla mezzanotte del - primo gennaio 1970, in tempo universale coordinato (o UTC), data che viene - usualmente indicata con 00:00:00 Jan, 1 1970 (UTC) e chiamata \textit{the - Epoch}. Questo tempo viene anche chiamato anche GMT (Greenwich Mean Time) - dato che l'UTC corrisponde all'ora locale di Greenwich. È il tempo su cui - viene mantenuto l'orologio del calcolatore, e viene usato ad esempio per - indicare le date di modifica dei file o quelle di avvio dei processi. Per - memorizzare questo tempo è stato riservato il tipo primitivo \type{time\_t}. -\item \textit{process time}: detto anche tempo di processore. Viene misurato - in \textit{clock tick}, corrispondenti al numero di interruzioni effettuate - dal timer di sistema, e che per Linux avvengono ogni centesimo di - secondo.\footnote{eccetto per la piattaforma alpha dove avvengono ogni - millesimo di secondo.} Il dato primitivo usato per questo tempo è - \type{clock\_t}, inoltre la costante \macro{HZ} restituisce la frequenza di - operazione del timer, e corrisponde dunque al numero di tick al secondo. Lo - standard POSIX definisce allo stesso modo la costante \macro{CLK\_TCK}); - questo valore può comunque essere ottenuto con \func{sysconf} (vedi - \secref{sec:sys_limits}). -\end{itemize} +\begin{description} +\item[\textit{calendar time}]: detto anche \textsl{tempo di calendario}. È il + numero di secondi dalla mezzanotte del primo gennaio 1970, in tempo + universale coordinato (o UTC), data che viene usualmente indicata con + 00:00:00 Jan, 1 1970 (UTC) e chiamata \textit{the Epoch}. Questo tempo viene + anche chiamato anche GMT (Greenwich Mean Time) dato che l'UTC corrisponde + all'ora locale di Greenwich. È il tempo su cui viene mantenuto l'orologio + del kernel, e viene usato ad esempio per indicare le date di modifica dei + file o quelle di avvio dei processi. Per memorizzare questo tempo è stato + riservato il tipo primitivo \type{time\_t}. +\item[\textit{process time}]: detto talvolta \textsl{tempo di processore}. + Viene misurato in \textit{clock tick}. Un tempo questo corrispondeva al + numero di interruzioni effettuate dal timer di sistema, adesso lo standard + POSIX richiede che esso sia pari al valore della costante + \macro{CLOCKS\_PER\_SEC}, che deve essere definita come 1000000, qualunque + sia la risoluzione reale dell'orologio di sistema e la frequenza delle + interruzioni del timer.\footnote{quest'ultima, come accennato in + \secref{sec:proc_hierarchy}, è invece data dalla costante \macro{HZ}.} Il + dato primitivo usato per questo tempo è \type{clock\_t}, che ha quindi una + risoluzione del microsecondo. Il numero di tick al secondo può essere + ricavato anche attraverso \func{sysconf} (vedi \secref{sec:sys_sysconf}). Il + vecchio simbolo \macro{CLK\_TCK} definito in \file{time.h} è ormai + considerato obsoleto. +\end{description} In genere si usa il \textit{calendar time} per esprimere le date dei file e le informazioni analoghe che riguardano i cosiddetti \textsl{tempi di orologio}, @@ -1114,10 +1713,11 @@ tempo locale, utilizzando le opportune informazioni di localizzazione mantenuto dal sistema e non è detto che corrisponda al tempo tenuto dall'orologio hardware del calcolatore. -Anche il \textit{process time} di solito si esprime in secondi, ma provvede una -precisione ovviamente superiore al \textit{calendar time} (la cui granularità -minima è il secondo) e viene usato per tenere conto dei tempi di esecuzione -dei processi. Per ciascun processo il kernel calcola tre tempi diversi: +Anche il \textit{process time} di solito si esprime in secondi, ma provvede +una precisione ovviamente superiore al \textit{calendar time} (che è mantenuto +dal sistema con una granularità di un secondo) e viene usato per tenere conto +dei tempi di esecuzione dei processi. Per ciascun processo il kernel calcola +tre tempi diversi: \begin{description*} \item[\textit{clock time}]: il tempo \textsl{reale} (viene chiamato anche \textit{wall clock time}) passato dall'avvio del processo. Chiaramente tale @@ -1131,9 +1731,579 @@ dei processi. Per ciascun processo il kernel calcola tre tempi diversi: In genere la somma di \textit{user time} e \textit{system time} indica il tempo di processore totale in cui il sistema è stato effettivamente impegnato -nell'eseguire un certo processo e viene chiamato \textit{CPU time}. +nell'eseguire un certo processo e viene chiamato \textit{CPU time} o +\textsl{tempo di CPU}. + +\subsection{La gestione del \textit{process time}} +\label{sec:sys_cpu_times} + +Di norma tutte le operazioni del sistema fanno sempre riferimento al +\textit{calendar time}, l'uso del \textit{process time} è riservato a quei +casi in cui serve conoscere i tempi di esecuzione di un processo (ad esempio +per valutarne l'efficienza). In tal caso infatti fare ricorso al +\textit{calendar time} è inutile in quanto il tempo può essere trascorso mentre +un altro processo era in esecuzione o in attesa del risultato di una +operazione di I/O. + +La funzione più semplice per leggere il \textit{process time} di un processo è +\func{clock}, che da una valutazione approssimativa del tempo di CPU +utilizzato dallo stesso; il suo prototipo è: +\begin{prototype}{time.h}{clock\_t clock(void)} + Legge il valore corrente del tempo di CPU. + + \bodydesc{La funzione ritorna il tempo di CPU usato dal programma e -1 in + caso di errore.} +\end{prototype} + +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 + 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. + +Come accennato in \secref{sec:sys_unix_time} il tempo di CPU è la somma di +altri due tempi, l'\textit{user time} ed il \textit{system time} che sono +quelli effettivamente mantenuti dal kernel per ciascun processo. Questi +possono essere letti attraverso la funzione \func{times}, il cui prototipo è: +\begin{prototype}{sys/times.h}{clock\_t times(struct tms *buf)} + Legge in \param{buf} il valore corrente dei tempi di processore. + + \bodydesc{La funzione ritorna il numero di clock tick dall'avvio del sistema + in caso di successo e -1 in caso di errore.} +\end{prototype} + +La funzione restituisce i valori di process time del processo corrente in una +struttura di tipo \var{tms}, la cui definizione è riportata in +\secref{fig:sys_tms_struct}. La struttura prevede quattro campi; i primi due, +\var{tms\_utime} e \var{tms\_stime}, sono l'\textit{user time} ed il +\textit{system time} del processo, così come definiti in +\secref{sec:sys_unix_time}. + +\begin{figure}[!htb] + \footnotesize + \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 */ +}; + \end{lstlisting} + \end{minipage} + \normalsize + \caption{La struttura \var{tms} dei tempi di processore associati a un + processo.} + \label{fig:sys_tms_struct} +\end{figure} + +Gli altri due campi mantengono rispettivamente la somma dell'\textit{user + time} ed del \textit{system time} di tutti i processi figli che sono +terminati; il kernel cioè somma in \var{tms\_cutime} il valore di +\var{tms\_utime} e \var{tms\_cutime} per ciascun figlio del quale è stato +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 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. + + + +\subsection{Le funzioni per il \textit{calendar time}} +\label{sec:sys_time_base} + +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 impostare il tempo di sistema qualora questo +sia necessario; il suo prototipo è: +\begin{prototype}{time.h}{int stime(time\_t *t)} + Imposta 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)} + + Imposta 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 i 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 + \begin{minipage}[c]{15cm} + \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{} +struct timeval +{ + 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{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{time zone}, 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 impostato 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 impostare 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 impostato. 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 & Imposta 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 & Imposta 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 & Imposta il valore massimo dell'errore + sul tempo, espresso in microsecondi + nel campo \var{maxerror} di + \var{timex}.\\ + \macro{ADJ\_ESTERROR} & 0x0008 & Imposta la stima dell'errore + sul tempo, espresso in microsecondi + nel campo \var{esterror} di + \var{timex}.\\ + \macro{ADJ\_STATUS} & 0x0010 & Imposta alcuni + valori di stato interni usati dal + sistema nella gestione + dell'orologio specificati nel campo + \var{status} di \var{timex}.\\ + \macro{ADJ\_TIMECONST} & 0x0020 & Imposta la larghezza di banda del PLL + implementato dal kernel, + specificato nel campo + \var{constant} di \var{timex}.\\ + \macro{ADJ\_TICK} & 0x4000 & Imposta il valore dei tick del timer + in microsecondi, espresso nel campo + \var{tick} di \var{timex}.\\ + \macro{ADJ\_OFFSET\_SINGLESHOT}&0x8001&Imposta 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 impostano 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 impostate 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)} + + Imposta 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} @@ -1148,7 +2318,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. @@ -1178,8 +2348,8 @@ sempre riferimento a tali valori, quando descriveremo i possibili errori restituiti dalle funzioni. Il programma di esempio \cmd{errcode} stampa il codice relativo ad un valore numerico con l'opzione \cmd{-l}. -Il valore di \var{errno} viene sempre settato a zero all'avvio di un -programma, gran parte delle funzioni di libreria settano \var{errno} ad un +Il valore di \var{errno} viene sempre impostato a zero all'avvio di un +programma, gran parte delle funzioni di libreria impostano \var{errno} ad un valore diverso da zero in caso di errore. Il valore è invece indefinito in caso di successo, perché anche se una funzione ha successo, può chiamarne altre al suo interno che falliscono, modificando così \var{errno}. @@ -1200,39 +2370,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} assumerà il valore \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 pagina di manuale), 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 @@ -1249,18 +2439,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}{} @@ -1286,6 +2464,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 impostata ad un valore diverso da zero fa si +che errori relativi alla stessa linea non vengano ripetuti. + + %%% Local Variables: