From: Simone Piccardi Date: Mon, 12 May 2008 10:15:16 +0000 (+0000) Subject: Aggiornamento sezione sulla gestione dei processi con i cambiamenti X-Git-Url: https://gapil.gnulinux.it/gitweb/?a=commitdiff_plain;h=260bf7cea27648dc1d5a81b55b996fc4f710e507;p=gapil.git Aggiornamento sezione sulla gestione dei processi con i cambiamenti avuti nelle ultime versioni di kernel e altro materiale sulle ACL --- diff --git a/filedir.tex b/filedir.tex index f3b61c5..2ca508f 100644 --- a/filedir.tex +++ b/filedir.tex @@ -3073,24 +3073,73 @@ quello della corrispondenza fra questi e le ACL. Come accennato i permessi ordinari vengono mappati le tre voci di tipo \const{ACL\_USER\_OBJ}, \const{ACL\_GROUP\_OBJ} e \const{ACL\_OTHER} che devono essere presenti in qualunque ACL; un cambiamento ad una di queste voci viene automaticamente -riflesso sui permessi ordinari dei file\footnote{quelli mantenuti - nell'\textit{inode}.} e viceversa. In realtà la mappatura è diretta solo per -le voci \const{ACL\_USER\_OBJ} e \const{ACL\_OTHER}, nel caso di -\const{ACL\_GROUP\_OBJ} questo vale fintanto che non è presente una voce di -tipo \const{ACL\_MASK}, nel qual caso valgono invece i permessi in essa -specificati.\footnote{questo diverso comportamento a seconda delle condizioni - è stato introdotto dalla standardizzazione \textit{POSIX 1003.1e Draft 17} - per mantenere il comportamento invariato sui sistemi dotati di ACL per tutte - quelle applicazioni che sono conformi soltanto all'ordinario standard - \textit{POSIX 1003.1}.} +riflesso sui permessi ordinari dei file\footnote{per permessi ordinari si + intende quelli mantenuti nell'\textit{inode}, che devono restare dato che un + filesystem può esseere montato senza abilitare le ACL.} e viceversa. In +realtà la mappatura è diretta solo per le voci \const{ACL\_USER\_OBJ} e +\const{ACL\_OTHER}, nel caso di \const{ACL\_GROUP\_OBJ} questo vale fintanto +che non è presente una voce di tipo \const{ACL\_MASK}, nel qual caso valgono +invece i permessi in essa specificati.\footnote{questo diverso comportamento a + seconda delle condizioni è stato introdotto dalla standardizzazione + \textit{POSIX 1003.1e Draft 17} per mantenere il comportamento invariato sui + sistemi dotati di ACL per tutte quelle applicazioni che sono conformi + soltanto all'ordinario standard \textit{POSIX 1003.1}.} Un secondo aspetto dell'incidenza delle ACL sul comportamento del sistema è -quello relativo alla creazione di nuovi file, che come accennato può essere -modificato dalla presenza di una default ACL sulla directory che contiene quel -file. Se questa non c'è valgono le regole illustrate in -sez.~\ref{sec:file_perm_management}, altrimen - - +quello relativo alla creazione di nuovi file,\footnote{o oggetti sul + filesystem, il comportamento discusso vale per le funzioni \func{open} e + \func{creat} (vedi sez.~\ref{sec:file_open}), \func{mkdir} (vedi + sez.~\ref{sec:file_dir_creat_rem}), \func{mknod} e \func{mkfifo} (vedi + sez.~\ref{sec:file_mknod}).} che come accennato può essere modificato dalla +presenza di una default ACL sulla directory che contiene quel file. Se questa +non c'è valgono le regole illustrate in sez.~\ref{sec:file_perm_management} +per cui essi sono determinati dalla \itindex{umask} \textit{umask} del +processo, e la sola differenza è che i permessi ordinari da esse risultanti +vengono automaticamente rimappati su una ACL di accesso assegnata al nuovo +file che contiene solo le tre voci di tipo \const{ACL\_USER\_OBJ}, +\const{ACL\_GROUP\_OBJ} e \const{ACL\_OTHER}. + +Se invece è presente una ACL di default sulla directory che contiene il nuovo +file questa diventerà la sua ACL di accesso, a meno di non aver indicato nelle +funzioni di creazione che lo consentono uno specifico insieme di +permessi.\footnote{tutte le funzioni citate in precedenza supportano un + argomento \var{mode} che indichi un insieme di permssi iniziale.} In tal +caso quelli non presenti in tale insieme saranno eliminati dalle voci +corrispondenti nella ACL. + +Ovviamente la presenza della ACL modifica anche le regole del controllo di +accesso ai file illustrate in sez.~\ref{sec:file_perm_overview}; per il +controllo vengono sempre utilizzati gli identificatori del gruppo +\textit{effective} del processo, ed i passi attraverso i quali viene stabilito +se esso ha diritto di accesso sono i seguenti: +\begin{enumerate} +\item Se l'user-ID del processo è nullo l'accesso è sempre garantito senza + nessun ulteriore controllo. +\item Se l'user-ID del processo corrisponde al proprietario del file allora: + \begin{itemize*} + \item se la voce \const{ACL\_USER\_OBJ} contiene il permesso richiesto, + l'accesso è consentito + \item altrimenti l'accesso è negato + \end{itemize*} +\item Se l'user-ID del processo corrisponde ad un qualunque qualificatore + presente in una voce \const{ACL\_USER} allora: + \begin{itemize*} + \item se la voce \const{ACL\_USER} corrispondente e la voce + \const{ACL\_MASK} contengono entrambe il permesso richiesto, l'accesso è + consentito + \item altrimenti l'accesso è negato + \end{itemize*} +\item Se il group-ID del processo o uno dei group-ID supplementari corrisponde + al gruppo proprietario del file o a un qualunque qualificatore di una voce + di tipo allora: + \begin{itemize*} + \item se il bit dei permessi d'accesso del gruppo è impostato, l'accesso è + consentito, + \item altrimenti l'accesso è negato + \end{itemize*} +\item Se il bit dei permessi d'accesso per tutti gli altri è impostato, + l'accesso è consentito, altrimenti l'accesso è negato. +\end{enumerate} diff --git a/prochand.tex b/prochand.tex index 390c431..a500f25 100644 --- a/prochand.tex +++ b/prochand.tex @@ -138,7 +138,7 @@ fig.~\ref{fig:proc_task_struct}. \begin{figure}[htb] \centering - \includegraphics[width=11cm]{img/task_struct} + \includegraphics[width=12cm]{img/task_struct} \caption{Schema semplificato dell'architettura delle strutture usate dal kernel nella gestione dei processi.} \label{fig:proc_task_struct} @@ -432,8 +432,7 @@ Se eseguiamo il comando\footnote{che senza specificare attese (come si può notare in (\texttt{\small 17--19}) i valori predefiniti specificano di non attendere), otterremo come output sul terminale: -\footnotesize -\begin{verbatim} +\begin{Verbatim}[fontsize=\footnotesize,xleftmargin=1cm,xrightmargin=1.5cm] [piccardi@selidor sources]$ export LD_LIBRARY_PATH=./; ./forktest 3 Process 1963: forking 3 child Spawned 1 child, pid 1964 @@ -448,8 +447,8 @@ Child 3 successfully executing Child 3, parent 1963, exiting Spawned 3 child, pid 1966 Go to next child -\end{verbatim} %$ -\normalsize +\end{Verbatim} +%$ Esaminiamo questo risultato: una prima conclusione che si può trarre è che non si può dire quale processo fra il padre ed il figlio venga eseguito per primo @@ -505,8 +504,7 @@ Un secondo aspetto molto importante nella creazione dei processi figli quello dell'interazione dei vari processi con i file; per illustrarlo meglio proviamo a redirigere su un file l'output del nostro programma di test, quello che otterremo è: -\footnotesize -\begin{verbatim} +\begin{Verbatim}[fontsize=\footnotesize,xleftmargin=1cm,xrightmargin=1.5cm] [piccardi@selidor sources]$ ./forktest 3 > output [piccardi@selidor sources]$ cat output Process 1967: forking 3 child @@ -531,8 +529,7 @@ Spawned 2 child, pid 1969 Go to next child Spawned 3 child, pid 1970 Go to next child -\end{verbatim} -\normalsize +\end{Verbatim} che come si vede è completamente diverso da quanto ottenevamo sul terminale. Il comportamento delle varie funzioni di interfaccia con i file è analizzato @@ -563,14 +560,15 @@ sez.~\ref{sec:file_sharing}), ma anche che, a differenza di quanto avviene per le variabili, la posizione corrente sul file è condivisa fra il padre e tutti i processi figli. -Quello che succede è che quando lo standard output del padre viene rediretto, -lo stesso avviene anche per tutti i figli; la funzione \func{fork} infatti ha -la caratteristica di duplicare nei figli tutti i file descriptor aperti nel -padre (allo stesso modo in cui lo fa la funzione \func{dup}, trattata in -sez.~\ref{sec:file_dup}), il che comporta che padre e figli condividono le -stesse voci della \itindex{file~table} \textit{file table} (per la spiegazione -di questi termini si veda sez.~\ref{sec:file_sharing}) fra cui c'è anche la -posizione corrente nel file. +Quello che succede è che quando lo standard output del padre viene rediretto +come si è fatto nell'esempio, lo stesso avviene anche per tutti i figli; la +funzione \func{fork} infatti ha la caratteristica di duplicare nei processi +figli tutti i file descriptor aperti nel processo padre (allo stesso modo in +cui lo fa la funzione \func{dup}, trattata in sez.~\ref{sec:file_dup}), il che +comporta che padre e figli condividono le stesse voci della +\itindex{file~table} \textit{file table} (per la spiegazione di questi termini +si veda sez.~\ref{sec:file_sharing}) fra cui c'è anche la posizione corrente +nel file. In questo modo se un processo scrive sul file aggiornerà la posizione corrente sulla \itindex{file~table} \textit{file table}, e tutti gli altri processi, @@ -582,21 +580,20 @@ mescolato, ma non ci saranno parti perdute per via di una sovrascrittura. Questo tipo di comportamento è essenziale in tutti quei casi in cui il padre crea un figlio e attende la sua conclusione per proseguire, ed entrambi -scrivono sullo stesso file (un caso tipico è la shell quando lancia un -programma, il cui output va sullo standard output). - -In questo modo, anche se l'output viene rediretto, il padre potrà sempre -continuare a scrivere in coda a quanto scritto dal figlio in maniera -automatica; se così non fosse ottenere questo comportamento sarebbe -estremamente complesso necessitando di una qualche forma di comunicazione fra -i due processi per far riprendere al padre la scrittura al punto giusto. +scrivono sullo stesso file; un caso tipico è la shell quando lancia un +programma, il cui output va sullo standard output. In questo modo, anche se +l'output viene rediretto, il padre potrà sempre continuare a scrivere in coda +a quanto scritto dal figlio in maniera automatica; se così non fosse ottenere +questo comportamento sarebbe estremamente complesso necessitando di una +qualche forma di comunicazione fra i due processi per far riprendere al padre +la scrittura al punto giusto. In generale comunque non è buona norma far scrivere più processi sullo stesso file senza una qualche forma di sincronizzazione in quanto, come visto anche con il nostro esempio, le varie scritture risulteranno mescolate fra loro in una sequenza impredicibile. Per questo le modalità con cui in genere si usano i file dopo una \func{fork} sono sostanzialmente due: -\begin{enumerate*} +\begin{enumerate} \item Il processo padre aspetta la conclusione del figlio. In questo caso non è necessaria nessuna azione riguardo ai file, in quanto la sincronizzazione della posizione corrente dopo eventuali operazioni di lettura e scrittura @@ -604,7 +601,7 @@ i file dopo una \func{fork} sono sostanzialmente due: \item L'esecuzione di padre e figlio procede indipendentemente. In questo caso ciascuno dei due processi deve chiudere i file che non gli servono una volta che la \func{fork} è stata eseguita, per evitare ogni forma di interferenza. -\end{enumerate*} +\end{enumerate} Oltre ai file aperti i processi figli ereditano dal padre una serie di altre proprietà; la lista dettagliata delle proprietà che padre e figlio hanno in @@ -695,7 +692,7 @@ Qualunque sia la modalit comunque una serie di operazioni: chiude tutti i file aperti, rilascia la memoria che stava usando, e così via; l'elenco completo delle operazioni eseguite alla chiusura di un processo è il seguente: -\begin{itemize*} +\begin{itemize} \item tutti i file descriptor sono chiusi; \item viene memorizzato lo stato di terminazione del processo; \item ad ogni processo figlio viene assegnato un nuovo padre (in genere @@ -710,7 +707,7 @@ eseguite alla chiusura di un processo group} ciascun membro del gruppo viene bloccato, e poi gli vengono inviati in successione i segnali \const{SIGHUP} e \const{SIGCONT} (vedi ancora sez.~\ref{sec:sess_ctrl_term}). -\end{itemize*} +\end{itemize} Oltre queste operazioni è però necessario poter disporre di un meccanismo ulteriore che consenta di sapere come la terminazione è avvenuta: dato che in @@ -752,8 +749,7 @@ avr cui riportare il suo stato di terminazione. Come verifica di questo comportamento possiamo eseguire il nostro programma \cmd{forktest} imponendo a ciascun processo figlio due secondi di attesa prima di uscire, il risultato è: -\footnotesize -\begin{verbatim} +\begin{Verbatim}[fontsize=\footnotesize,xleftmargin=1cm,xrightmargin=1.5cm] [piccardi@selidor sources]$ ./forktest -c2 3 Process 1972: forking 3 child Spawned 1 child, pid 1973 @@ -768,8 +764,7 @@ Go to next child [piccardi@selidor sources]$ Child 3, parent 1, exiting Child 2, parent 1, exiting Child 1, parent 1, exiting -\end{verbatim} -\normalsize +\end{Verbatim} come si può notare in questo caso il processo padre si conclude prima dei figli, tornando alla shell, che stampa il prompt sul terminale: circa due secondi dopo viene stampato a video anche l'output dei tre figli che @@ -799,9 +794,7 @@ condizione: lanciamo il comando \cmd{forktest} in \textit{background} (vedi sez.~\ref{sec:sess_job_control}), indicando al processo padre di aspettare 10 secondi prima di uscire; in questo caso, usando \cmd{ps} sullo stesso terminale (prima dello scadere dei 10 secondi) otterremo: - -\footnotesize -\begin{verbatim} +\begin{Verbatim}[fontsize=\footnotesize,xleftmargin=1cm,xrightmargin=1.5cm] [piccardi@selidor sources]$ ps T PID TTY STAT TIME COMMAND 419 pts/0 S 0:00 bash @@ -810,8 +803,9 @@ terminale (prima dello scadere dei 10 secondi) otterremo: 570 pts/0 Z 0:00 [forktest ] 571 pts/0 Z 0:00 [forktest ] 572 pts/0 R 0:00 ps T -\end{verbatim} %$ -\normalsize e come si vede, dato che non si è fatto nulla per riceverne lo +\end{Verbatim} +%$ +e come si vede, dato che non si è fatto nulla per riceverne lo stato di terminazione, i tre processi figli sono ancora presenti pur essendosi conclusi, con lo stato di \index{zombie} \textit{zombie} e l'indicazione che sono stati terminati. @@ -1224,13 +1218,14 @@ specificata l'opzione \const{WNOHANG} e la funzione senza che nessun figlio sia terminato. Pertanto per verificare il motivo del ritorno della funzione occorre analizzare le informazioni che essa restituisce; queste, al contrario delle precedenti \func{wait} e -\func{waitpid}, sono ritornate nella struttura di tipo \struct{siginfo\_t} -(vedi fig.~\ref{fig:sig_siginfo_t}) all'indirizzo puntato dall'argomento -\param{infop}. - -Tratteremo nei dettagli questa struttura ed il significato dei suoi vari campi -in sez.~\ref{sec:sig_sigaction}, per quanto ci interessa qui basta dire che al -ritorno di \func{waitid} verranno avvalorati i seguenti campi: +\func{waitpid} che usavano un semplice valore numerico, sono ritornate in una +struttura di tipo \struct{siginfo\_t} (vedi fig.~\ref{fig:sig_siginfo_t}) +all'indirizzo puntato dall'argomento \param{infop}. + +Tratteremo nei dettagli la struttura \struct{siginfo\_t} ed il significato dei +suoi vari campi in sez.~\ref{sec:sig_sigaction}, per quanto ci interessa qui +basta dire che al ritorno di \func{waitid} verranno avvalorati i seguenti +campi: \begin{basedescript}{\desclabelwidth{2.0cm}} \item[\var{si\_pid}] con il \acr{pid} del figlio. \item[\var{si\_uid}] con l'user-ID reale (vedi sez.~\ref{sec:proc_perms}) del @@ -1248,10 +1243,10 @@ ritorno di \func{waitid} verranno avvalorati i seguenti campi: Infine Linux, seguendo un'estensione di BSD, supporta altre due funzioni per la lettura dello stato di terminazione di un processo, analoghe alle precedenti ma che prevedono un ulteriore argomento attraverso il quale il -kernel può restituire al padre informazioni sulle risorse usate dal processo -terminato e dai vari figli. Le due funzioni sono \funcd{wait3} e -\funcd{wait4}, che diventano accessibili definendo la macro -\macro{\_USE\_BSD}; i loro prototipi sono: +kernel può restituire al padre informazioni sulle risorse (vedi +sez.~\ref{sec:sys_res_limits}) usate dal processo terminato e dai vari figli. +Le due funzioni sono \funcd{wait3} e \funcd{wait4}, che diventano accessibili +definendo la macro \macro{\_USE\_BSD}; i loro prototipi sono: \begin{functions} \headdecl{sys/times.h} \headdecl{sys/types.h} \headdecl{sys/wait.h} \headdecl{sys/resource.h} @@ -1431,7 +1426,7 @@ l'ambiente. Oltre a mantenere lo stesso \acr{pid}, il nuovo programma fatto partire da \func{exec} assume anche una serie di altre proprietà del processo chiamante; la lista completa è la seguente: -\begin{itemize*} +\begin{itemize} \item il \textit{process id} (\acr{pid}) ed il \textit{parent process id} (\acr{ppid}); \item l'\textsl{user-ID reale}, il \textit{group-ID reale} ed i @@ -1450,7 +1445,7 @@ la lista completa \item i limiti sulle risorse (vedi sez.~\ref{sec:sys_resource_limit}); \item i valori delle variabili \var{tms\_utime}, \var{tms\_stime}, \var{tms\_cutime}, \var{tms\_ustime} (vedi sez.~\ref{sec:sys_cpu_times}). -\end{itemize*} +\end{itemize} Inoltre i segnali che sono stati impostati per essere ignorati nel processo chiamante mantengono la stessa impostazione pure nel nuovo programma, tutti @@ -1465,32 +1460,34 @@ sez.~\ref{sec:file_fcntl}) per ciascun file descriptor. I file per cui impostato vengono chiusi, tutti gli altri file restano aperti. Questo significa che il comportamento predefinito è che i file restano aperti attraverso una \func{exec}, a meno di una chiamata esplicita a \func{fcntl} -che imposti il suddetto flag. - -Per le directory, lo standard POSIX.1 richiede che esse vengano chiuse -attraverso una \func{exec}, in genere questo è fatto dalla funzione -\func{opendir} (vedi sez.~\ref{sec:file_dir_read}) che effettua da sola -l'impostazione del flag di \itindex{close-on-exec} \textit{close-on-exec} -sulle directory che apre, in maniera trasparente all'utente. +che imposti il suddetto flag. Per le directory, lo standard POSIX.1 richiede +che esse vengano chiuse attraverso una \func{exec}, in genere questo è fatto +dalla funzione \func{opendir} (vedi sez.~\ref{sec:file_dir_read}) che effettua +da sola l'impostazione del flag di \itindex{close-on-exec} +\textit{close-on-exec} sulle directory che apre, in maniera trasparente +all'utente. Abbiamo detto che l'\textsl{user-ID reale} ed il \textsl{group-ID reale} -restano gli stessi all'esecuzione di \func{exec}; lo stesso vale per -l'\textsl{user-ID effettivo} ed il \textsl{group-ID effettivo} (il significato -di questi identificatori è trattato in sez.~\ref{sec:proc_access_id}), tranne -quando il file che si va ad eseguire abbia o il \itindex{suid~bit} \acr{suid} -bit o lo \itindex{sgid~bit} \acr{sgid} bit impostato, in questo caso -l'\textsl{user-ID effettivo} ed il \textsl{group-ID effettivo} vengono -impostati rispettivamente all'utente o al gruppo cui il file appartiene (per i -dettagli vedi sez.~\ref{sec:proc_perms}). +restano gli stessi all'esecuzione di \func{exec}; normalmente vale lo stesso +anche per l'\textsl{user-ID effettivo} ed il \textsl{group-ID effettivo} (il +significato di questi identificatori è trattato in +sez.~\ref{sec:proc_access_id}), tranne quando il file di cui viene chiesta +l'esecuzione ha o il \itindex{suid~bit} \acr{suid} bit o lo \itindex{sgid~bit} +\acr{sgid} bit impostato, in questo caso l'\textsl{user-ID effettivo} ed il +\textsl{group-ID effettivo} vengono impostati rispettivamente all'utente o al +gruppo cui il file appartiene (per i dettagli di questo comportamento si veda +sez.~\ref{sec:proc_perms}). Se il file da eseguire è in formato \emph{a.out} e necessita di librerie condivise, viene lanciato il \textit{linker} dinamico \cmd{/lib/ld.so} prima del programma per caricare le librerie necessarie ed effettuare il link -dell'eseguibile. Se il programma è in formato ELF per caricare le librerie -dinamiche viene usato l'interprete indicato nel segmento \const{PT\_INTERP}, -in genere questo è \sysfile{/lib/ld-linux.so.1} per programmi collegati con le -\acr{libc5}, e \sysfile{/lib/ld-linux.so.2} per programmi collegati con le -\acr{glibc}. +dell'eseguibile.\footnote{il formato è ormai in completo disuso, per cui è + molto probabile che non il relativo supporto non sia disponibile.} Se il +programma è in formato ELF per caricare le librerie dinamiche viene usato +l'interprete indicato nel segmento \const{PT\_INTERP} pervisto dal formato +stesso, in genere questo è \sysfile{/lib/ld-linux.so.1} per programmi +collegati con le \acr{libc5}, e \sysfile{/lib/ld-linux.so.2} per programmi +collegati con le \acr{glibc}. Infine nel caso il file sia uno script esso deve iniziare con una linea nella forma \cmd{\#!/path/to/interpreter [argomenti]} dove l'interprete indicato @@ -2423,9 +2420,12 @@ fig.~\ref{fig:cap_kernel_struct}, come i prototipi delle due funzioni \func{capget} e \func{capset}, sono soggette ad essere modificate con il cambiamento del kernel (in particolare i tipi di dati delle strutture) ed anche se finora l'interfaccia è risultata stabile, non c'è nessuna -assicurazione che questa venga mantenuta. Pertanto se si vogliono scrivere -programmi portabili che possano essere eseguiti su qualunque versione del -kernel è opportuno utilizzare le interfacce di alto livello. +assicurazione che questa venga mantenuta.\footnote{anzi, visto lo scarso + utilizzo di questa funzionalità ci sono state varie discussioni fra gli + sviluppatori del kernel relative all'eliminarla o al modificarla + radicalmente.} Pertanto se si vogliono scrivere programmi portabili che +possano essere eseguiti su qualunque versione del kernel è opportuno +utilizzare le interfacce di alto livello. \begin{figure}[!htb] \footnotesize @@ -2493,8 +2493,9 @@ con tutte le \textit{capabilities} azzerate. In caso di errore (cio non c'è memoria sufficiente ad allocare i dati) viene restituito \macro{NULL} ed \var{errno} viene impostata a \errval{ENOMEM}. La memoria necessaria a mantenere i dati viene automaticamente allocata da \func{cap\_init}, ma dovrà -essere disallocata esplicitamente quando non più necessaria utilizzando la -funzione \funcd{cap\_free}, il cui prototipo è: +essere disallocata esplicitamente quando non è più necessaria utilizzando, per +questo l'interfaccia fornisce una apposita funzione, \funcd{cap\_free}, il cui +prototipo è: \begin{functions} \headdecl{sys/capability.h} @@ -2510,10 +2511,11 @@ La funzione permette di liberare la memoria allocata dalle altre funzioni della libreria sia per un \textit{capability state}, nel qual caso l'argomento dovrà essere un dato di tipo \type{cap\_t}, che per una descrizione testuale dello stesso,\footnote{cioè quanto ottenuto tramite la funzione - \func{cap\_to\_text}.} nel qual caso l'argomento dovrà essere di tipo -\texttt{char *}. L'argomento \param{obj\_d} deve corrispondere ad un oggetto -ottenuto tramite altre funzioni della libreria, altrimenti la funzione fallirà -con un errore di \errval{EINVAL}. + \func{cap\_to\_text}.} nel qual caso l'argomento dovrà essere un dato di +tipo \texttt{char *}. Per questo l'argomento \param{obj\_d} è dichiarato come +\texttt{void *} e deve sempre corrispondere ad un puntatore ottenuto tramite +le altre funzioni della libreria, altrimenti la funzione fallirà con un errore +di \errval{EINVAL}. Infine si può creare una copia di un \textit{capability state} ottenuto in precedenza tramite la funzione \funcd{cap\_dup}, il cui prototipo è: @@ -2534,11 +2536,13 @@ La funzione crea una copia del \textit{capability state} posto all'indirizzo copia, che conterrà gli stessi valori delle \textit{capabilities} presenti nell'originale. La memoria necessaria viene allocata automaticamente dalla funzione. Una volta effettuata la copia i due \textit{capability state} -potranno essere modificati in maniera completamente indipendente. +potranno essere modificati in maniera completamente +indipendente.\footnote{alla fine delle operazioni si ricordi però di + disallocare anche la copia, oltre all'originale. } -Una seconda classe di funzioni di servizio sono quelle per la gestione dei -dati contenuti all'interno di un \textit{capability state}; la prima di esse è -\funcd{cap\_clear}, il cui prototipo è: +Una seconda classe di funzioni di servizio previste dall'interfaccia sono +quelle per la gestione dei dati contenuti all'interno di un \textit{capability + state}; la prima di queste è \funcd{cap\_clear}, il cui prototipo è: \begin{functions} \headdecl{sys/capability.h} @@ -2613,10 +2617,12 @@ combinare diversi valori in una maschera binaria, una variabile di tipo \type{cap\_value\_t} deve indicare una sola capacità.\footnote{nel file di header citato nella nota precedente il tipo \type{cap\_value\_t} è definito come \ctyp{int}, ma i valori validi sono soltanto quelli di - tab.~\ref{tab:proc_capabilities}.} Infine lo stato di una capacità è -descritto ad una variabile di tipo \type{cap\_flag\_value\_t}, che a sua volta -può assumere soltanto uno\footnote{anche questo è un tipo enumerato.} dei -valori di tab.~\ref{tab:cap_value_type}. + tab.~\ref{tab:proc_capabilities}.} + +Infine lo stato di una capacità è descritto ad una variabile di tipo +\type{cap\_flag\_value\_t}, che a sua volta può assumere soltanto +uno\footnote{anche questo è un tipo enumerato.} dei valori di +tab.~\ref{tab:cap_value_type}. \begin{table}[htb] \centering @@ -2642,11 +2648,11 @@ puntato dall'argomento \param{value\_p}; stato di una capacità alla volta. La funzione \func{cap\_set\_flag} può invece impostare in una sola chiamata -più capacità, anche se solo all'interno dello stesso insieme; per questo essa -prende un vettore di valori di tipo \type{cap\_value\_t} nell'argomento -\param{caps}, la cui dimensione è specificata dall'argomento \param{ncap}. Il -tipo di impostazione da eseguire (cancellazione o impostazione) viene indicato -dall'argomento \param{value}. +più \textit{capabilities}, anche se solo all'interno dello stesso insieme. Per +questo motivo essa prende un vettore di valori di tipo \type{cap\_value\_t} +nell'argomento \param{caps}, la cui dimensione viene specificata dall'argomento +\param{ncap}. Il tipo di impostazione da eseguire (cancellazione o +impostazione) viene indicato dall'argomento \param{value}. Per la visualizzazione dello stato delle \textit{capabilities} l'interfaccia prevede una funzione apposita, \funcd{cap\_to\_text}, il cui prototipo è: @@ -2669,12 +2675,13 @@ testuale del contenuto del \textit{capabilities state} \param{caps} passato come argomento, e, qualora l'argomento \param{length\_p} sia diverso da \val{NULL}, restituisce nella variabile intera da questo puntata la lunghezza della stringa. La stringa restituita viene allocata automaticamente dalla -funzione e deve essere liberata con \func{cap\_free}. +funzione e pertanto dovrà essere liberata con \func{cap\_free}. -Fin quei abbiamo trattato delle funzioni di manipolazione dei -\textit{capabilities state}; quando si vuole eseguire la lettura delle -\textit{capabilities} del processo corrente si deve usare la funzione -\funcd{cap\_get\_proc}, il cui prototipo è: +Fin quei abbiamo trattato solo le funzioni di servizio relative alla +manipolazione dei \textit{capabilities state}; l'interfaccia di gestione +prevede però anche le funzioni per la gestione delle \textit{capabilities} +stesse. La prima di queste è \funcd{cap\_get\_proc} che consente la lettura +delle \textit{capabilities} del processo corrente, il suo prototipo è: \begin{functions} \headdecl{sys/capability.h} @@ -2686,10 +2693,11 @@ Fin quei abbiamo trattato delle funzioni di manipolazione dei assumere i valori \errval{EINVAL}, \errval{EPERM} o \errval{ENOMEM}. } \end{functions} -La funzione legge il valore delle \textit{capabilities} del processo corrente -e restituisce il puntatore ad un \textit{capabilities state} contenente il -risultato, che provvede ad allocare autonomamente, e che occorrerà liberare -con \func{cap\_free} quando non sarà più utilizzato. +La funzione legge il valore delle \textit{capabilities} associate al processo +da cui viene invocata, restituendo il risultato tramite il puntatore ad un +\textit{capabilities state} contenente tutti i dati che provvede ad allocare +autonomamente e che di nuovo occorrerà liberare con \func{cap\_free} quando +non sarà più utilizzato. Se invece si vogliono leggere le \textit{capabilities} di un processo specifico occorre usare la funzione \funcd{capgetp}, il cui @@ -2708,19 +2716,23 @@ prototipo\footnote{su alcune pagine di manuale la funzione \errval{EPERM} o \errval{ENOMEM}. } \end{functions} +%TODO controllare e correggere i codici di errore!!! La funzione legge il valore delle \textit{capabilities} del processo indicato -con l'argomento \param{pid}, salvando il risultato nel \textit{capabilities - state} all'indirizzo \param{cap\_d} che deve essere stato creato in -precedenza. Qualora il processo non esista si avrà un errore di -\errval{ESRCH}. Gli stessi valori possono essere letti direttamente nel -filesystem \textit{proc}, nei file \texttt{/proc//status}; ad esempio per -\texttt{init} si otterrà qualcosa del tipo: +con l'argomento \param{pid}, e restituisce il risultato nel +\textit{capabilities state} posto all'indirizzo indicato con l'argomento +\param{cap\_d}; a differenza della precedente in questo caso il +\textit{capability state} deve essere stato creato in precedenza. Qualora il +processo indicato non esista si avrà un errore di \errval{ESRCH}. Gli stessi +valori possono essere letti direttamente nel filesystem \textit{proc}, nei +file \texttt{/proc//status}; ad esempio per \texttt{init} si otterrà +qualcosa del tipo: \begin{Verbatim} ... CapInh: 0000000000000000 CapPrm: 00000000fffffeff CapEff: 00000000fffffeff +... \end{Verbatim} Infine per impostare le \textit{capabilities} del processo corrente (non @@ -2984,8 +2996,9 @@ attraverso la funzione \funcd{nice}, il cui prototipo {int nice(int inc)} Aumenta il valore di \var{nice} per il processo corrente. - \bodydesc{La funzione ritorna zero in caso di successo e -1 in caso di - errore, nel qual caso \var{errno} può assumere i valori: + \bodydesc{La funzione ritorna zero o il nuovo valore di \var{nice} in caso + di successo e -1 in caso di errore, nel qual caso \var{errno} può assumere + i valori: \begin{errlist} \item[\errcode{EPERM}] un processo senza i privilegi di amministratore ha specificato un valore di \param{inc} negativo. @@ -3002,9 +3015,27 @@ priorit l'amministratore può specificare valori negativi che permettono di aumentare la priorità di un processo. -In SUSv2 la funzione ritorna il nuovo valore di \var{nice}; Linux non segue -questa convenzione, e per leggere il nuovo valore occorre invece usare la -funzione \funcd{getpriority}, derivata da BSD, il cui prototipo è: +Gli standard SUSv2 e POSIX.1 prevedono che la funzione ritorni il nuovo valore +di \var{nice} del processo; tuttavia la system call di Linux non segue questa +convenzione e restituisce sempre 0 in caso di successo, questo perchè $-1$ è +un valore di \var{nice} legittimo e questo comporta una confusione con una +eventuale condizione di errore. + +Fino alle \acr{glibc} 2.2.4 la funzione di libreria riportava direttamente il +valore ottenuto dalla system call, violando lo standard, per cui per ottenere +il nuovo valore occorreva una successiva chiamata alla funzione +\func{getpriority}. A partire dalla \acr{glibc} 2.2.4 \func{nice} è stata +reimplementata come funzione di libreria, e restituisce il valore di +\var{nice} come richiesto dallo standard.\footnote{questo viene fatto + chiamando al suo interno \func{getpriority}, ed è questo il motivo delle due + possibilità per i valori di ritorno citati nella descrizione del prototipo.} +In questo caso l'unico modo per rilevare in maniera affidabile una condizione +di errore è quello di azzerare \var{errno} prima della chiamata della funzione +e verificarne il valore quando \func{nice} restituisce $-1$. + + +Per leggere il valore di nice di un processo occorre usare la funzione +\funcd{getpriority}, derivata da BSD; il suo prototipo è: \begin{prototype}{sys/resource.h} {int getpriority(int which, int who)} @@ -3050,12 +3081,12 @@ l'utente correnti. \end{table} La funzione restituisce la priorità più alta (cioè il valore più basso) fra -quelle dei processi specificati; dato che -1 è un valore possibile, per poter -rilevare una condizione di errore è necessario cancellare sempre \var{errno} -prima della chiamata alla funzione, per verificare che essa resti uguale a -zero. +quelle dei processi specificati; di nuovo, dato che $-1$ è un valore +possibile, per poter rilevare una condizione di errore è necessario cancellare +sempre \var{errno} prima della chiamata alla funzione per verificare che essa +resti uguale a zero. -Analoga a \func{getpriority} la funzione \funcd{setpriority} permette di +Analoga a \func{getpriority} è la funzione \funcd{setpriority} che permette di impostare la priorità di uno o più processi; il suo prototipo è: \begin{prototype}{sys/resource.h} {int setpriority(int which, int who, int prio)} @@ -3407,18 +3438,10 @@ problematiche nei nuovi kernel\footnote{le due system call per la gestione l'opportuna infrastruttura ed una nuova system call che permette di impostare su quali processori far eseguire un determinato processo attraverso una \textsl{maschera di affinità}. La corrispondente funzione di libreria è -\funcd{sched\_setaffinity} ed il suo prototipo\footnote{di questa funzione (e - della corrispondente \func{sched\_setaffinity}) esistono versioni diverse - per gli argomenti successivi a \param{pid}: la prima (quella riportata nella - pagina di manuale) prevedeva due ulteriori argomenti di tipo - \texttt{unsigned int len} e \texttt{unsigned long *mask}, poi l'argomento - \texttt{len} è stato eliminato, successivamente si è introdotta la versione - riportata con però un secondo argomento di tipo \texttt{size\_t cpusetsize} - (anche questa citata nella pagina di manuale); la versione citata è quella - riportata nel manuale delle \textsl{glibc} e corrispondente alla definizione - presente in \file{sched.h}.} è: +\funcd{sched\_setaffinity} ed il suo prototipo è: \begin{prototype}{sched.h} - {int sched\_setaffinity (pid\_t pid, const cpu\_set\_t *cpuset)} + {int sched\_setaffinity (pid\_t pid, unsigned int cpusetsize, const + cpu\_set\_t *cpuset)} Imposta la maschera di affinità del processo \param{pid}. \bodydesc{La funzione ritorna 0 in caso di successo e -1 in caso di errore, @@ -3433,6 +3456,21 @@ su quali processori far eseguire un determinato processo attraverso una ed inoltre anche \errval{EFAULT}.} \end{prototype} + +Questa funzione e la corrispondente \func{sched\_setaffinity} hanno una storia +abbastanza complessa, la system call prevede l'uso di due ulteriori argomenti +di tipo \texttt{unsigned int len} e \texttt{unsigned long *mask}, che +corrispondono al fatto che la implementazione effettiva usa una semplice +maschera binaria. Quando le funzioni vennero incluse nelle \acr{glibc} +assunsero invece il prototipo appena mostrato. A complicare la cosa si +aggiunge il fatto che nella versione 2.3.3 delle \acr{glibc} l'argomento +\param{cpusetsize} è stato eliminato, per poi essere ripristinato nella +versione 2.3.4.\footnote{pertanto se la vostra pagina di manuale non è + aggiornata, o usate quella particolare versione delle \acr{glibc}, potrete + trovare indicazioni diverse, il prototipo illustrato è quello riportato + nella versione corrente (maggio 2008) delle pagine di manuale e + corrispondente alla definizione presente in \file{sched.h}.} + La funzione imposta, con l'uso del valore contenuto all'indirizzo \param{cpuset}, l'insieme dei processori sui quali deve essere eseguito il processo identificato tramite il valore passato in \param{pid}. Come in @@ -3507,7 +3545,8 @@ possa essere eseguito su qualunque processore, se pu valore per un processo specifico usando la funzione \funcd{sched\_getaffinity}, il suo prototipo è: \begin{prototype}{sched.h} - {int sched\_getaffinity (pid\_t pid, const cpu\_set\_t *cpuset)} + {int sched\_getaffinity (pid\_t pid, unsigned int cpusetsize, + const cpu\_set\_t *cpuset)} Legge la maschera di affinità del processo \param{pid}. \bodydesc{La funzione ritorna 0 in caso di successo e -1 in caso di errore,