X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=prochand.tex;h=1dddefcb93d822c011e3bfedeea47539934d4df9;hp=97e25c103b62dcd9e1f2f9ad7fcc10ca0d00f7a8;hb=c1b22636d04ef04d31842b40878c83fa63ebe739;hpb=0c9d95dfc21869e96f8a3e3ab8111c842e85a1f9 diff --git a/prochand.tex b/prochand.tex index 97e25c1..1dddefc 100644 --- a/prochand.tex +++ b/prochand.tex @@ -137,10 +137,12 @@ system call ed ad ogni interrupt,\footnote{pi occasioni. NDT completare questa parte.} (ma può essere anche attivato esplicitamente). Il timer di sistema provvede comunque a che esso sia invocato periodicamente, generando un interrupt periodico secondo la frequenza -specificata dalla costante \macro{HZ}, definita in \file{asm/param.h}. Il -valore usuale è 100\footnote{è così per tutte le architetture eccetto l'alpha, - per la quale è 1000} ed è espresso in Hertz. Si ha cioè un interrupt dal -timer ogni centesimo di secondo. +specificata dalla costante \macro{HZ}, definita in \file{asm/param.h}, ed il +cui valore è espresso in Hertz.\footnote{Il valore usuale di questa costante è + 100, per tutte le architetture eccetto l'alpha, per la quale è 1000. Occorre + fare attenzione a non confondere questo valore con quello dei clock tick + (vedi \secref{sec:sys_unix_time}).} +%Si ha cioè un interrupt dal timer ogni centesimo di secondo. Ogni volta che viene eseguito, lo \textit{scheduler} effettua il calcolo delle priorità dei vari processi attivi (torneremo su questo in @@ -229,11 +231,9 @@ sono stati creati, questo viene chiamato in genere \acr{ppid} (da \textit{parent process id}). Questi due identificativi possono essere ottenuti da programma usando le funzioni: \begin{functions} -\headdecl{sys/types.h} -\headdecl{unistd.h} -\funcdecl{pid\_t getpid(void)} Restituisce il pid del processo corrente. -\funcdecl{pid\_t getppid(void)} Restituisce il pid del padre del processo - corrente. + \headdecl{sys/types.h} \headdecl{unistd.h} \funcdecl{pid\_t getpid(void)} + Restituisce il \acr{pid} del processo corrente. \funcdecl{pid\_t + getppid(void)} Restituisce il \acr{pid} del padre del processo corrente. \bodydesc{Entrambe le funzioni non riportano condizioni di errore.} \end{functions} @@ -377,14 +377,18 @@ int main(int argc, char *argv[]) Normalmente la chiamata a \func{fork} può fallire solo per due ragioni, o ci sono già troppi processi nel sistema (il che di solito è sintomo che qualcos'altro non sta andando per il verso giusto) o si è ecceduto il limite -sul numero totale di processi permessi all'utente (vedi \secref{sec:sys_xxx}). +sul numero totale di processi permessi all'utente (vedi +\secref{sec:sys_resource_limit}, ed in particolare +\tabref{tab:sys_rlimit_values}). L'uso di \func{fork} avviene secondo due modalità principali; la prima è quella in cui all'interno di un programma si creano processi figli cui viene affidata l'esecuzione di una certa sezione di codice, mentre il processo padre -ne esegue un'altra. È il caso tipico dei server di rete in cui il padre riceve -ed accetta le richieste da parte dei client, per ciascuna delle quali pone in -esecuzione un figlio che è incaricato di fornire il servizio. +ne esegue un'altra. È il caso tipico dei server (il modello +\textit{client-server} è illustrato in \secref{sec:net_cliserv}) di rete in +cui il padre riceve ed accetta le richieste da parte dei client, per ciascuna +delle quali pone in esecuzione un figlio che è incaricato di fornire il +servizio. La seconda modalità è quella in cui il processo vuole eseguire un altro programma; questo è ad esempio il caso della shell. In questo caso il processo @@ -399,21 +403,21 @@ d'uso, esistono numerosi scenari in cui si pu aver bisogno di eseguire una \func{exec}. Inoltre, anche nel caso della seconda modalità d'uso, avere le due funzioni separate permette al figlio di cambiare gli attributi del processo (maschera dei segnali, redirezione -dell'output, \textit{user id}) prima della \func{exec}, rendendo così +dell'output, identificatori) prima della \func{exec}, rendendo così relativamente facile intervenire sulle le modalità di esecuzione del nuovo programma. -In \curfig\ si è riportato il corpo del codice del programma di esempio -\cmd{forktest}, che ci permette di illustrare molte caratteristiche dell'uso -della funzione \func{fork}. Il programma permette di creare un numero di figli -specificato da linea di comando, e prende anche alcune opzioni per indicare -degli eventuali tempi di attesa in secondi (eseguiti tramite la funzione -\func{sleep}) per il padre ed il figlio (con \cmd{forktest -h} si ottiene la -descrizione delle opzioni); il codice completo, compresa la parte che gestisce -le opzioni a riga di comando, è disponibile nel file \file{ForkTest.c}, -distribuito insieme agli altri sorgenti degli esempi su -\href{http://firenze.linux.it/~piccardi/gapil_source.tgz} -{\texttt{http://firenze.linux.it/\~~\hspace{-2.0mm}piccardi/gapil\_source.tgz}}. +In \figref{fig:proc_fork_code} si è riportato il corpo del codice del +programma di esempio \cmd{forktest}, che ci permette di illustrare molte +caratteristiche dell'uso della funzione \func{fork}. Il programma permette di +creare un numero di figli specificato da linea di comando, e prende anche +alcune opzioni per indicare degli eventuali tempi di attesa in secondi +(eseguiti tramite la funzione \func{sleep}) per il padre ed il figlio (con +\cmd{forktest -h} si ottiene la descrizione delle opzioni); il codice +completo, compresa la parte che gestisce le opzioni a riga di comando, è +disponibile nel file \file{ForkTest.c}, distribuito insieme agli altri +sorgenti degli esempi su \href{http://gapil.firenze.linux.it/gapil_source.tgz} +{\texttt{http://gapil.firenze.linux.it/gapil\_source.tgz}}. Decifrato il numero di figli da creare, il ciclo principale del programma (\texttt{\small 24--40}) esegue in successione la creazione dei processi figli @@ -427,7 +431,7 @@ alla conclusione del ciclo, prima di uscire, pu periodo di attesa. Se eseguiamo il comando senza specificare attese (come si può notare in -\texttt{\small 17--19} i valori di default specificano di non attendere), +\texttt{\small 17--19} i valori predefiniti specificano di non attendere), otterremo come output sul terminale: \footnotesize @@ -474,8 +478,9 @@ Pertanto non si pu istruzioni del codice fra padre e figli, né sull'ordine in cui questi potranno essere messi in esecuzione. Se è necessaria una qualche forma di precedenza occorrerà provvedere ad espliciti meccanismi di sincronizzazione, pena il -rischio di incorrere nelle cosiddette \textit{race condition} \index{race - condition} (vedi \secref{sec:proc_race_cond}. +rischio di incorrere nelle cosiddette +\textit{race condition}\index{race condition} +(vedi \secref{sec:proc_race_cond}). Si noti inoltre che essendo i segmenti di memoria utilizzati dai singoli processi completamente separati, le modifiche delle variabili nei processi @@ -594,33 +599,33 @@ 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 comune dopo l'esecuzione di una \func{fork} è la seguente: \begin{itemize*} -\item i file aperti e gli eventuali flag di \textit{close-on-exec} settati +\item i file aperti e gli eventuali flag di \textit{close-on-exec} impostati (vedi \secref{sec:proc_exec} e \secref{sec:file_fcntl}). -\item gli identificatori per il controllo di accesso: il \textit{real user - id}, il \textit{real group id}, l'\textit{effective user id}, - l'\textit{effective group id} ed i \textit{supplementary group id} (vedi +\item gli identificatori per il controllo di accesso: l'\textsl{userid reale}, + il \textsl{groupid reale}, l'\textsl{userid effettivo}, il \textsl{groupid + effettivo} ed i \textit{groupid supplementari} (vedi \secref{sec:proc_access_id}). \item gli identificatori per il controllo di sessione: il \textit{process - group id} e il \textit{session id} ed il terminale di controllo (vedi + groupid} e il \textit{session id} ed il terminale di controllo (vedi \secref{sec:sess_xxx} e \secref{sec:sess_xxx}). \item la directory di lavoro e la directory radice (vedi \secref{sec:file_work_dir} e \secref{sec:file_chroot}). \item la maschera dei permessi di creazione (vedi \secref{sec:file_umask}). -\item la maschera dei segnali bloccati (vedi \secref{sec:sig_sigpending}) e le +\item la maschera dei segnali bloccati (vedi \secref{sec:sig_sigmask}) e le azioni installate (vedi \secref{sec:sig_gen_beha}). \item i segmenti di memoria condivisa agganciati al processo (vedi -\secref{sec:ipc_xxx}). -\item i limiti sulle risorse (vedi \secref{sec:sys_xxx}). + \secref{sec:ipc_sysv_shm}). +\item i limiti sulle risorse (vedi \secref{sec:sys_resource_limit}). \item le variabili di ambiente (vedi \secref{sec:proc_environ}). \end{itemize*} le differenze fra padre e figlio dopo la \func{fork} invece sono: \begin{itemize*} \item il valore di ritorno di \func{fork}. -\item il \textit{process id}. -\item il \textit{parent process id} (quello del figlio viene settato al - \acr{pid} del padre). -\item i valori dei tempi di esecuzione (vedi \secref{sec:sys_xxx}) che - nel figlio sono posti a zero. +\item il \acr{pid} (\textit{process id}). +\item il \acr{ppid} (\textit{parent process id}), quello del figlio viene + impostato al \acr{pid} del padre. +\item i valori dei tempi di esecuzione della struttura \var{tms} (vedi + \secref{sec:sys_cpu_times}) che nel figlio sono posti a zero. \item i \textit{file lock} (vedi \secref{sec:file_locking}), che non vengono ereditati dal figlio. \item gli allarmi ed i segnali pendenti (vedi \secref{sec:sig_gen_beha}), che @@ -645,10 +650,10 @@ padre, che costituiva un inutile appesantimento in tutti quei casi in cui la \func{fork} veniva fatta solo per poi eseguire una \func{exec}. La funzione venne introdotta in BSD per migliorare le prestazioni. -Dato che Linux supporta il \textit{copy on write} la perdita di prestazioni è -assolutamente trascurabile, e l'uso di questa funzione (che resta un caso -speciale della funzione \func{clone}), è deprecato; per questo eviteremo di -trattarla ulteriormente. +Dato che Linux supporta il \textit{copy on write}\index{copy on write} la +perdita di prestazioni è assolutamente trascurabile, e l'uso di questa +funzione (che resta un caso speciale della funzione \func{clone}), è +deprecato; per questo eviteremo di trattarla ulteriormente. \subsection{La conclusione di un processo.} @@ -929,7 +934,7 @@ La terminazione di un processo figlio rispetto all'esecuzione di un programma e può avvenire in un qualunque momento. Per questo motivo, come accennato nella sezione precedente, una delle azioni prese dal kernel alla conclusione di un processo è quella di mandare un -segnale di \macro{SIGCHLD} al padre. L'azione di default (si veda +segnale di \macro{SIGCHLD} al padre. L'azione predefinita (si veda \secref{sec:sig_base}) per questo segnale è di essere ignorato, ma la sua generazione costituisce il meccanismo di comunicazione asincrona con cui il kernel avverte il processo padre che uno dei suoi figli è terminato. @@ -1015,15 +1020,14 @@ sulle risorse usate dal processo terminato e dai vari figli. I prototipi di queste funzioni, che diventano accessibili definendo la costante \macro{\_USE\_BSD}, sono: \begin{functions} - \headdecl{sys/times.h} - \headdecl{sys/types.h} - \headdecl{sys/wait.h} - \headdecl{sys/resource.h} + \headdecl{sys/times.h} \headdecl{sys/types.h} \headdecl{sys/wait.h} + \headdecl{sys/resource.h} + \funcdecl{pid\_t wait4(pid\_t pid, int * status, int options, struct rusage - * rusage)} - È identica a \func{waitpid} sia per comportamento che per i - valori dei parametri, ma restituisce in \param{rusage} un sommario delle - risorse usate dal processo (per i dettagli vedi \secref{sec:sys_xxx}) + * rusage)} + È identica a \func{waitpid} sia per comportamento che per i valori dei + parametri, ma restituisce in \param{rusage} un sommario delle risorse usate + dal processo. \funcdecl{pid\_t wait3(int *status, int options, struct rusage *rusage)} Prima versione, equivalente a \code{wait4(-1, \&status, opt, rusage)} è @@ -1031,16 +1035,9 @@ queste funzioni, che diventano accessibili definendo la costante \end{functions} \noindent la struttura \type{rusage} è definita in \file{sys/resource.h}, e viene -utilizzata anche dalla funzione \func{getrusage} (vedi \secref{sec:sys_xxx}) -per ottenere le risorse di sistema usate da un processo; la sua definizione è -riportata in \figref{fig:sys_rusage_struct}. - -In genere includere esplicitamente \file{} non è più -necessario, ma aumenta la portabilità, e serve in caso si debba accedere -ai campi di \var{rusage} definiti come \type{struct timeval}. La -struttura è ripresa da BSD 4.3, attualmente (con il kernel 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}. +utilizzata anche dalla funzione \func{getrusage} (vedi +\secref{sec:sys_resource_use}) per ottenere le risorse di sistema usate da un +processo; la sua definizione è riportata in \figref{fig:sys_rusage_struct}. \subsection{Le funzioni \func{exec}} @@ -1067,7 +1064,7 @@ famiglia di funzioni) che possono essere usate per questo compito, in realt qual caso \var{errno} può assumere i valori: \begin{errlist} \item[\macro{EACCES}] il file non è eseguibile, oppure il filesystem è - montato in \cmd{noexec}, oppure non è un file normale o un interprete. + montato in \cmd{noexec}, oppure non è un file regolare o un interprete. \item[\macro{EPERM}] il file ha i bit \acr{suid} o \acr{sgid}, l'utente non è root, e o il processo viene tracciato, o il filesystem è montato con l'opzione \cmd{nosuid}. @@ -1203,10 +1200,9 @@ la lista completa \begin{itemize*} \item il \textit{process id} (\acr{pid}) ed il \textit{parent process id} (\acr{ppid}). -\item il \textit{real user id} ed il \textit{real group id} (vedi - \secref{sec:proc_access_id}). -\item i \textit{supplementary group id} (vedi \secref{sec:proc_access_id}). -\item il \textit{session id} ed il \textit{process group id} (vedi +\item l'\textsl{userid reale}, il \textit{groupid reale} ed i \textsl{groupid + supplementari} (vedi \secref{sec:proc_access_id}). +\item il \textit{session id} ed il \textit{process groupid} (vedi \secref{sec:sess_xxx}). \item il terminale di controllo (vedi \secref{sec:sess_xxx}). \item il tempo restante ad un allarme (vedi \secref{sec:sig_alarm_abort}). @@ -1216,38 +1212,40 @@ la lista completa \secref{sec:file_umask}) ed i \textit{lock} sui file (vedi \secref{sec:file_locking}). \item i segnali sospesi (\textit{pending}) e la maschera dei segnali (si veda - \secref{sec:sig_sigpending}). -\item i limiti sulle risorse (vedi \secref{sec:sys_limits}). + \secref{sec:sig_sigmask}). +\item i limiti sulle risorse (vedi \secref{sec:sys_resource_limit}). \item i valori delle variabili \var{tms\_utime}, \var{tms\_stime}, - \var{tms\_cutime}, \var{tms\_ustime} (vedi \secref{sec:xxx_xxx}). + \var{tms\_cutime}, \var{tms\_ustime} (vedi \secref{sec:sys_cpu_times}). \end{itemize*} -Inoltre i segnali che sono stati settati per essere ignorati nel processo -chiamante mantengono lo stesso settaggio pure nel nuovo programma, tutti gli -altri segnali vengono settati alla loro azione di default. Un caso speciale è -il segnale \macro{SIGCHLD} che, quando settato a \macro{SIG\_IGN}, può anche -non essere resettato a \macro{SIG\_DFL} (si veda \secref{sec:sig_gen_beha}). +Inoltre i segnali che sono stati impostati per essere ignorati nel processo +chiamante mantengono la stessa impostazione pure nel nuovo programma, tutti +gli altri segnali vengono impostati alla loro azione predefinita. Un caso +speciale è il segnale \macro{SIGCHLD} che, quando impostato a +\macro{SIG\_IGN}, può anche non essere reimpostato a \macro{SIG\_DFL} (si veda +\secref{sec:sig_gen_beha}). La gestione dei file aperti dipende dal valore che ha il flag di \textit{close-on-exec} (trattato in \secref{sec:file_fcntl}) per ciascun file -descriptor. I file per cui è settato vengono chiusi, tutti gli altri file -restano aperti. Questo significa che il comportamento di default è che i 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 setti il suddetto flag. +\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 \secref{sec:file_dir_read}) che effettua da sola il -settaggio del flag di \textit{close-on-exec} sulle directory che apre, in +\func{opendir} (vedi \secref{sec:file_dir_read}) che effettua da sola +l'impostazione del flag di \textit{close-on-exec} sulle directory che apre, in maniera trasparente all'utente. -Abbiamo detto che il \textit{real user id} ed il \textit{real group id} -restano gli stessi all'esecuzione di \func{exec}; lo stesso vale per -l'\textit{effective user id} ed l'\textit{effective group id}, tranne quando -il file che si va ad eseguire abbia o il \acr{suid} bit o lo \acr{sgid} bit -settato, in questo caso l'\textit{effective user id} e l'\textit{effective - group id} vengono settati rispettivamente all'utente o al gruppo cui il file -appartiene (per i dettagli vedi \secref{sec:proc_perms}). +Abbiamo detto che l'\textsl{userid reale} ed il \textsl{groupid reale} restano +gli stessi all'esecuzione di \func{exec}; lo stesso vale per l'\textsl{userid + effettivo} ed il \textsl{groupid effettivo} (il significato di questi +identificatori è trattato in \secref{sec:proc_access_id}), tranne quando il +file che si va ad eseguire abbia o il \acr{suid} bit o lo \acr{sgid} bit +impostato, in questo caso l'\textsl{userid effettivo} ed il \textsl{groupid + effettivo} vengono impostati rispettivamente all'utente o al gruppo cui il +file appartiene (per i dettagli vedi \secref{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{ld.so} prima del @@ -1255,8 +1253,8 @@ 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 \macro{PT\_INTERP}, in genere questo è \file{/lib/ld-linux.so.1} per programmi linkati con le -\emph{libc5}, e \file{/lib/ld-linux.so.2} per programmi linkati con le -\emph{glibc}. Infine nel caso il file sia uno script esso deve iniziare con +\acr{libc5}, e \file{/lib/ld-linux.so.2} per programmi linkati con le +\acr{glibc}. Infine nel caso il file sia uno script esso deve iniziare con una linea nella forma \cmd{\#!/path/to/interpreter} dove l'interprete indicato deve esse un valido programma (binario, non un altro script) che verrà chiamato come se si fosse eseguito il comando \cmd{interpreter [arg] @@ -1266,7 +1264,7 @@ Con la famiglia delle \func{exec} si chiude il novero delle funzioni su cui basata la gestione dei processi in Unix: con \func{fork} si crea un nuovo processo, con \func{exec} si avvia un nuovo programma, con \func{exit} e \func{wait} si effettua e verifica la conclusione dei programmi. Tutte le -altre funzioni sono ausiliarie e servono la lettura e il settaggio dei vari +altre funzioni sono ausiliarie e servono la lettura e l'impostazione dei vari parametri connessi ai processi. @@ -1298,8 +1296,8 @@ utenti, per i quali invece vengono effettuati i vari controlli di accesso. %notevole flessibilità, Abbiamo già accennato come il sistema associ ad ogni utente e gruppo due -identificatori univoci, lo \acr{uid} e il \acr{gid}; questi servono al kernel -per identificare uno specifico utente o un gruppo di utenti, per poi poter +identificatori univoci, lo userid ed il groupid; questi servono al kernel per +identificare uno specifico utente o un gruppo di utenti, per poi poter controllare che essi siano autorizzati a compiere le operazioni richieste. Ad esempio in \secref{sec:file_access_control} vedremo come ad ogni file vengano associati un utente ed un gruppo (i suoi \textsl{proprietari}, indicati @@ -1309,42 +1307,49 @@ kernel nella gestione dei permessi di accesso. Dato che tutte le operazioni del sistema vengono compiute dai processi, è evidente che per poter implementare un controllo sulle operazioni occorre anche poter identificare chi è che ha lanciato un certo programma, e pertanto -anche a ciascun processo è associato un utente e a un gruppo. +anche a ciascun processo dovrà essere associato ad un utente e ad un gruppo. Un semplice controllo di una corrispondenza fra identificativi non garantisce però sufficiente flessibilità per tutti quei casi in cui è necessario poter disporre di privilegi diversi, o dover impersonare un altro utente per un limitato insieme di operazioni. Per questo motivo in generale tutti gli Unix prevedono che i processi abbiano almeno due gruppi di identificatori, chiamati -rispettivamente \textit{real} ed \textit{effective}. +rispettivamente \textit{real} ed \textit{effective} (cioè \textsl{reali} ed +\textsl{effettivi}). Nel caso di Linux si aggiungono poi altri due gruppi, il +\textit{saved} (\textsl{salvati}) ed il \textit{filesystem} (\textsl{di + filesystem}), secondo la situazione illustrata in \tabref{tab:proc_uid_gid}. \begin{table}[htb] \footnotesize \centering - \begin{tabular}[c]{|c|l|p{6.5cm}|} + \begin{tabular}[c]{|c|c|l|p{7.3cm}|} \hline - \textbf{Suffisso} & \textbf{Significato} & \textbf{Utilizzo} \\ + \textbf{Suffisso} & \textbf{Gruppo} & \textbf{Denominazione} + & \textbf{Significato} \\ \hline \hline - \acr{uid} & \textit{real user id} & indica l'utente che ha lanciato - il programma\\ - \acr{gid} & \textit{real group id} & indica il gruppo dell'utente - che ha lanciato il programma \\ + \acr{uid} & \textit{real} & \textsl{userid reale} + & indica l'utente che ha lanciato il programma\\ + \acr{gid} & '' &\textsl{groupid reale} + & indica il gruppo principale dell'utente che ha lanciato + il programma \\ \hline - \acr{euid} & \textit{effective user id} & indica l'utente usato - dal programma nel controllo di accesso \\ - \acr{egid} & \textit{effective group id} & indica il gruppo - usato dal programma nel controllo di accesso \\ - -- & \textit{supplementary group id} & indica i gruppi cui - l'utente appartiene \\ + \acr{euid} & \textit{effective} &\textsl{userid effettivo} + & indica l'utente usato nel controllo di accesso \\ + \acr{egid} & '' & \textsl{groupid effettivo} + & indica il gruppo usato nel controllo di accesso \\ + -- & -- & \textsl{groupid supplementari} + & indicano gli ulteriori gruppi cui l'utente appartiene \\ \hline - -- & \textit{saved user id} & copia dell'\acr{euid} iniziale\\ - -- & \textit{saved group id} & copia dell'\acr{egid} iniziale \\ + -- & \textit{saved} & \textsl{userid salvato} + & è una copia dell'\acr{euid} iniziale\\ + -- & '' & \textsl{groupid salvato} + & è una copia dell'\acr{egid} iniziale \\ \hline - \acr{fsuid} & \textit{filesystem user id} & indica l'utente effettivo per - il filesystem \\ - \acr{fsgid} & \textit{filesystem group id} & indica il gruppo effettivo - per il filesystem \\ + \acr{fsuid} & \textit{filesystem} &\textsl{userid di filesystem} + & indica l'utente effettivo per l'accesso al filesystem \\ + \acr{fsgid} & '' & \textsl{groupid di filesystem} + & indica il gruppo effettivo per l'accesso al filesystem \\ \hline \end{tabular} \caption{Identificatori di utente e gruppo associati a ciascun processo con @@ -1352,31 +1357,32 @@ rispettivamente \textit{real} ed \textit{effective}. \label{tab:proc_uid_gid} \end{table} -Al primo gruppo appartengono il \textit{real user id} e il \textit{real group - id}: questi vengono settati al login ai valori corrispondenti all'utente con -cui si accede al sistema (e relativo gruppo di default). Servono per -l'identificazione dell'utente e normalmente non vengono mai cambiati. In -realtà vedremo (in \secref{sec:proc_setuid}) che è possibile modificarli, ma -solo ad un processo che abbia i privilegi di amministratore; questa -possibilità è usata ad esempio da \cmd{login} che, una volta completata la -procedura di autenticazione, lancia una shell per la quale setta questi -identificatori ai valori corrispondenti all'utente che entra nel sistema. - -Al secondo gruppo appartengono l'\textit{effective user id} e -l'\textit{effective group id} (a cui si aggiungono gli eventuali -\textit{supplementary group id} dei gruppi dei quali l'utente fa parte). -Questi sono invece gli identificatori usati nella verifiche dei permessi del -processo e per il controllo di accesso ai file (argomento affrontato in -dettaglio in \secref{sec:file_perm_overview}). +Al primo gruppo appartengono l'\textsl{userid reale} ed il \textsl{groupid + reale}: questi vengono impostati al login ai valori corrispondenti +all'utente con cui si accede al sistema (e relativo gruppo principale). +Servono per l'identificazione dell'utente e normalmente non vengono mai +cambiati. In realtà vedremo (in \secref{sec:proc_setuid}) che è possibile +modificarli, ma solo ad un processo che abbia i privilegi di amministratore; +questa possibilità è usata proprio dal programma \cmd{login} che, una volta +completata la procedura di autenticazione, lancia una shell per la quale +imposta questi identificatori ai valori corrispondenti all'utente che entra +nel sistema. + +Al secondo gruppo appartengono l'\textsl{userid effettivo} e l'\textsl{groupid + effettivo} (a cui si aggiungono gli eventuali \textsl{groupid supplementari} +dei gruppi dei quali l'utente fa parte). Questi sono invece gli +identificatori usati nella verifiche dei permessi del processo e per il +controllo di accesso ai file (argomento affrontato in dettaglio in +\secref{sec:file_perm_overview}). Questi identificatori normalmente sono identici ai corrispondenti del gruppo \textit{real} tranne nel caso in cui, come accennato in \secref{sec:proc_exec}, il programma che si è posto in esecuzione abbia i bit -\acr{suid} o \acr{sgid} settati (il significato di questi bit è affrontato in -dettaglio in \secref{sec:file_suid_sgid}). In questo caso essi saranno settati -all'utente e al gruppo proprietari del file. Questo consente, per programmi in -cui ci sia necessità, di dare a qualunque utente normale privilegi o permessi -di un'altro (o dell'amministratore). +\acr{suid} o \acr{sgid} impostati (il significato di questi bit è affrontato +in dettaglio in \secref{sec:file_suid_sgid}). In questo caso essi saranno +impostati all'utente e al gruppo proprietari del file. Questo consente, per +programmi in cui ci sia necessità, di dare a qualunque utente normale +privilegi o permessi di un'altro (o dell'amministratore). Come nel caso del \acr{pid} e del \acr{ppid} tutti questi identificatori possono essere letti dal processo attraverso delle opportune funzioni, i cui @@ -1384,18 +1390,18 @@ prototipi sono i seguenti: \begin{functions} \headdecl{unistd.h} \headdecl{sys/types.h} - \funcdecl{uid\_t getuid(void)} Restituisce il \textit{real user id} del + \funcdecl{uid\_t getuid(void)} Restituisce l'\textsl{userid reale} del processo corrente. - \funcdecl{uid\_t geteuid(void)} Restituisce l'\textit{effective user id} del + \funcdecl{uid\_t geteuid(void)} Restituisce l'\textsl{userid effettivo} del processo corrente. - \funcdecl{gid\_t getgid(void)} Restituisce il \textit{real group id} del - processo corrente. - - \funcdecl{gid\_t getegid(void)} Restituisce l'\textit{effective group id} del + \funcdecl{gid\_t getgid(void)} Restituisce il \textsl{groupid reale} del processo corrente. + \funcdecl{gid\_t getegid(void)} Restituisce il \textsl{groupid effettivo} + del processo corrente. + \bodydesc{Queste funzioni non riportano condizioni di errore.} \end{functions} @@ -1406,37 +1412,32 @@ maggiori privilegi necessari, una volta che si siano effettuate le operazioni per i quali erano richiesti, e a poterli eventualmente recuperare in caso servano di nuovo. -Questo in Linux viene fatto usando altri due gruppi di identificatori, il -\textit{saved} ed il \textit{filesystem}, analoghi ai precedenti. Il primo -gruppo è lo stesso usato in SVr4, e previsto dallo standard POSIX quando è -definita la costante \macro{\_POSIX\_SAVED\_IDS},\footnote{in caso si abbia a - cuore la portabilità del programma su altri Unix è buona norma controllare - sempre la disponibilità di queste funzioni controllando se questa costante è +Questo in Linux viene fatto usando altri gli altri due gruppi di +identificatori, il \textit{saved} ed il \textit{filesystem}. Il primo gruppo è +lo stesso usato in SVr4, e previsto dallo standard POSIX quando è definita la +costante \macro{\_POSIX\_SAVED\_IDS},\footnote{in caso si abbia a cuore la + portabilità del programma su altri Unix è buona norma controllare sempre la + disponibilità di queste funzioni controllando se questa costante è definita.} il secondo gruppo è specifico di Linux e viene usato per migliorare la sicurezza con NFS. -Il \textit{saved user id} e il \textit{saved group id} sono copie -dell'\textit{effective user id} e dell'\textit{effective group id} del -processo padre, e vengono settati dalla funzione \func{exec} all'avvio del -processo, come copie dell'\textit{effective user id} e dell'\textit{effective - group id} dopo che questo sono stati settati tenendo conto di eventuali -\acr{suid} o \acr{sgid}. Essi quindi consentono di tenere traccia di quale -fossero utente e gruppo effettivi all'inizio dell'esecuzione di un nuovo -programma. +L'\textsl{userid salvato} ed il \textsl{groupid salvato} sono copie +dell'\textsl{userid effettivo} e del \textsl{groupid effettivo} del processo +padre, e vengono impostati dalla funzione \func{exec} all'avvio del processo, +come copie dell'\textsl{userid effettivo} e del \textsl{groupid effettivo} +dopo che questo sono stati impostati tenendo conto di eventuali \acr{suid} o +\acr{sgid}. Essi quindi consentono di tenere traccia di quale fossero utente +e gruppo effettivi all'inizio dell'esecuzione di un nuovo programma. -Il \textit{filesystem user id} e il \textit{filesystem group id} sono +L'\textsl{userid di filesystem} e il \textsl{groupid di filesystem} sono un'estensione introdotta in Linux per rendere più sicuro l'uso di NFS (torneremo sull'argomento in \secref{sec:proc_setfsuid}). Essi sono una -replica dei corrispondenti \textit{effective id}, ai quali si sostituiscono -per tutte le operazioni di verifica dei permessi relativi ai file (trattate in -\secref{sec:file_perm_overview}). Ogni cambiamento effettuato sugli -\textit{effective id} viene automaticamente riportato su di essi, per cui in -condizioni normali se ne può tranquillamente ignorare l'esistenza, in quanto -saranno del tutto equivalenti ai precedenti. - -Uno specchietto riassuntivo, contenente l'elenco completo degli identificatori -di utente e gruppo associati dal kernel ad ogni processo, è riportato in -\tabref{tab:proc_uid_gid}. +replica dei corrispondenti identificatori del gruppo \textit{effective}, ai +quali si sostituiscono per tutte le operazioni di verifica dei permessi +relativi ai file (trattate in \secref{sec:file_perm_overview}). Ogni +cambiamento effettuato sugli identificatori effettivi viene automaticamente +riportato su di essi, per cui in condizioni normali si può tranquillamente +ignorarne l'esistenza, in quanto saranno del tutto equivalenti ai precedenti. \subsection{Le funzioni \func{setuid} e \func{setgid}} @@ -1445,16 +1446,16 @@ di utente e gruppo associati dal kernel ad ogni processo, Le due funzioni che vengono usate per cambiare identità (cioè utente e gruppo di appartenenza) ad un processo sono rispettivamente \func{setuid} e \func{setgid}; come accennato in \secref{sec:proc_access_id} in Linux esse -seguono la semantica POSIX che prevede l'esistenza del \textit{saved user id} -e del \textit{saved group id}; i loro prototipi sono: +seguono la semantica POSIX che prevede l'esistenza dell'\textit{userid + salvato} e del \textit{groupid salvato}; i loro prototipi sono: \begin{functions} \headdecl{unistd.h} \headdecl{sys/types.h} -\funcdecl{int setuid(uid\_t uid)} Setta l'\textit{user id} del processo +\funcdecl{int setuid(uid\_t uid)} Imposta l'\textsl{userid} del processo corrente. -\funcdecl{int setgid(gid\_t gid)} Setta il \textit{group id} del processo +\funcdecl{int setgid(gid\_t gid)} Imposta il \textsl{groupid} del processo corrente. \bodydesc{Le funzioni restituiscono 0 in caso di successo e -1 in caso @@ -1463,21 +1464,21 @@ corrente. Il funzionamento di queste due funzioni è analogo, per cui considereremo solo la prima; la seconda si comporta esattamente allo stesso modo facendo -riferimento al \textit{group id} invece che all'\textit{user id}. Gli -eventuali \textit{supplementary group id} non vengono modificati. - +riferimento al \textsl{groupid} invece che all'\textsl{userid}. Gli +eventuali \textsl{groupid supplementari} non vengono modificati. L'effetto della chiamata è diverso a seconda dei privilegi del processo; se -l'\textit{effective user id} è zero (cioè è quello dell'amministratore di -sistema) allora tutti gli identificatori (\textit{real}, \textit{effective} -e \textit{saved}) vengono settati al valore specificato da \var{uid}, -altrimenti viene settato solo l'\textit{effective user id}, e soltanto se il -valore specificato corrisponde o al \textit{real user id} o al \textit{saved - user id}. Negli altri casi viene segnalato un errore (con \macro{EPERM}). +l'\textsl{userid effettivo} è zero (cioè è quello dell'amministratore di +sistema) allora tutti gli identificatori (\textit{real}, \textit{effective} e +\textit{saved}) vengono impostati al valore specificato da \var{uid}, +altrimenti viene impostato solo l'\textsl{userid effettivo}, e soltanto se il +valore specificato corrisponde o all'\textsl{userid reale} o +all'\textsl{userid salvato}. Negli altri casi viene segnalato un errore (con +\macro{EPERM}). Come accennato l'uso principale di queste funzioni è quello di poter -consentire ad un programma con i bit \acr{suid} o \acr{sgid} settati di -riportare l'\textit{effective user id} a quello dell'utente che ha lanciato il +consentire ad un programma con i bit \acr{suid} o \acr{sgid} impostati di +riportare l'\textsl{userid effettivo} a quello dell'utente che ha lanciato il programma, effettuare il lavoro che non necessita di privilegi aggiuntivi, ed eventualmente tornare indietro. @@ -1490,41 +1491,41 @@ falsificare la registrazione. Per questo motivo questo file (e l'analogo un gruppo dedicato (\acr{utmp}) ed i programmi che devono accedervi (ad esempio tutti i programmi di terminale in X, o il programma \cmd{screen} che crea terminali multipli su una console) appartengono a questo gruppo ed hanno -il bit \acr{sgid} settato. +il bit \acr{sgid} impostato. Quando uno di questi programmi (ad esempio \cmd{xterm}) viene lanciato, la situazione degli identificatori è la seguente: \begin{eqnarray*} \label{eq:1} - \textit{real group id} &=& \textrm{\acr{gid} (del chiamante)} \\ - \textit{effective group id} &=& \textrm{\acr{utmp}} \\ - \textit{saved group id} &=& \textrm{\acr{utmp}} + \textsl{groupid reale} &=& \textrm{\acr{gid} (del chiamante)} \\ + \textsl{groupid effettivo} &=& \textrm{\acr{utmp}} \\ + \textsl{groupid salvato} &=& \textrm{\acr{utmp}} \end{eqnarray*} -in questo modo, dato che l'\textit{effective group id} è quello giusto, il +in questo modo, dato che il \textsl{groupid effettivo} è quello giusto, il programma può accedere a \file{/var/log/utmp} in scrittura ed aggiornarlo. A -questo punto il programma può eseguire una \code{setgid(getgid())} per settare -l'\textit{effective group id} a quello dell'utente (e dato che il \textit{real - group id} corrisponde la funzione avrà successo), in questo modo non sarà -possibile lanciare dal terminale programmi che modificano detto file, in tal -caso infatti la situazione degli identificatori sarebbe: +questo punto il programma può eseguire una \code{setgid(getgid())} per +impostare il \textsl{groupid effettivo} a quello dell'utente (e dato che il +\textsl{groupid reale} corrisponde la funzione avrà successo), in questo modo +non sarà possibile lanciare dal terminale programmi che modificano detto file, +in tal caso infatti la situazione degli identificatori sarebbe: \begin{eqnarray*} \label{eq:2} - \textit{real group id} &=& \textrm{\acr{gid} (invariato)} \\ - \textit{effective group id} &=& \textrm{\acr{gid}} \\ - \textit{saved group id} &=& \textrm{\acr{utmp} (invariato)} + \textsl{groupid reale} &=& \textrm{\acr{gid} (invariato)} \\ + \textsl{groupid effettivo} &=& \textrm{\acr{gid}} \\ + \textsl{groupid salvato} &=& \textrm{\acr{utmp} (invariato)} \end{eqnarray*} e ogni processo lanciato dal terminale avrebbe comunque \acr{gid} come -\textit{effective group id}. All'uscita dal terminale, per poter di nuovo +\textsl{groupid effettivo}. All'uscita dal terminale, per poter di nuovo aggiornare lo stato di \file{/var/log/utmp} il programma eseguirà una \code{setgid(utmp)} (dove \var{utmp} è il valore numerico associato al gruppo \acr{utmp}, ottenuto ad esempio con una precedente \func{getegid}), dato che -in questo caso il valore richiesto corrisponde al \textit{saved group id} la +in questo caso il valore richiesto corrisponde al \textsl{groupid salvato} la funzione avrà successo e riporterà la situazione a: \begin{eqnarray*} \label{eq:3} - \textit{real group id} &=& \textrm{\acr{gid} (invariato)} \\ - \textit{effective group id} &=& \textrm{\acr{utmp}} \\ - \textit{saved group id} &=& \textrm{\acr{utmp} (invariato)} + \textsl{groupid reale} &=& \textrm{\acr{gid} (invariato)} \\ + \textsl{groupid effettivo} &=& \textrm{\acr{utmp}} \\ + \textsl{groupid salvato} &=& \textrm{\acr{utmp} (invariato)} \end{eqnarray*} consentendo l'accesso a \file{/var/log/utmp}. @@ -1534,7 +1535,7 @@ comporta il cambiamento di tutti gli identificatori associati al processo, rendendo impossibile riguadagnare i privilegi di amministratore. Questo comportamento è corretto per l'uso che ne fa \cmd{login} una volta che crea una nuova shell per l'utente; ma quando si vuole cambiare soltanto -l'\textit{effective user id} del processo per cedere i privilegi occorre +l'\textsl{userid effettivo} del processo per cedere i privilegi occorre ricorrere ad altre funzioni (si veda ad esempio \secref{sec:proc_seteuid}). @@ -1542,84 +1543,83 @@ ricorrere ad altre funzioni (si veda ad esempio \secref{sec:proc_seteuid}). \label{sec:proc_setreuid} Queste due funzioni derivano da BSD che, non supportando\footnote{almeno fino - alla versione 4.3+BSD TODO, FIXME verificare e aggiornare la nota.} i -\textit{saved id}, le usava per poter scambiare fra di loro \textit{effective} -e \textit{real id}. I loro prototipi sono: + alla versione 4.3+BSD TODO, FIXME verificare e aggiornare la nota.} gli +identificatori del gruppo \textit{saved}, le usa per poter scambiare fra di +loro \textit{effective} e \textit{real}. I loro prototipi sono: \begin{functions} \headdecl{unistd.h} \headdecl{sys/types.h} -\funcdecl{int setreuid(uid\_t ruid, uid\_t euid)} Setta il \textit{real user - id} e l'\textit{effective user id} del processo corrente ai valori +\funcdecl{int setreuid(uid\_t ruid, uid\_t euid)} Imposta l'\textsl{userid + reale} e l'\textsl{userid effettivo} del processo corrente ai valori specificati da \var{ruid} e \var{euid}. -\funcdecl{int setregid(gid\_t rgid, gid\_t egid)} Setta il \textit{real group - id} e l'\textit{effective group id} del processo corrente ai valori +\funcdecl{int setregid(gid\_t rgid, gid\_t egid)} Imposta il \textsl{groupid + reale} ed il \textsl{groupid effettivo} del processo corrente ai valori specificati da \var{rgid} e \var{egid}. \bodydesc{Le funzioni restituiscono 0 in caso di successo e -1 in caso di fallimento: l'unico errore possibile è \macro{EPERM}.} \end{functions} -I processi non privilegiati possono settare i \textit{real id} soltanto ai -valori dei loro \textit{effective id} o \textit{real id} e gli -\textit{effective id} ai valori dei loro \textit{real id}, \textit{effective - id} o \textit{saved id}; valori diversi comportano il fallimento della -chiamata; l'amministratore invece può specificare un valore qualunque. -Specificando un valore di -1 l'identificatore corrispondente viene lasciato -inalterato. +La due funzioni sono analoghe ed il loro comportamento è identico; quanto +detto per la prima prima riguardo l'userid, si applica immediatamente alla +seconda per il groupid. I processi non privilegiati possono impostare solo i +valori del loro userid effettivo o reale; valori diversi comportano il +fallimento della chiamata; l'amministratore invece può specificare un valore +qualunque. Specificando un argomento di valore -1 l'identificatore +corrispondente verrà lasciato inalterato. -Con queste funzione si possono scambiare fra loro \textit{real id} e -\textit{effective id}, e pertanto è possibile implementare un comportamento -simile a quello visto in precedenza per \func{setgid}, cedendo i privilegi con -un primo scambio, e recuperandoli, eseguito il lavoro non privilegiato, con un -secondo scambio. +Con queste funzione si possono scambiare fra loro gli userid reale e +effettivo, e pertanto è possibile implementare un comportamento simile a +quello visto in precedenza per \func{setgid}, cedendo i privilegi con un primo +scambio, e recuperandoli, eseguito il lavoro non privilegiato, con un secondo +scambio. In questo caso però occorre porre molta attenzione quando si creano nuovi processi nella fase intermedia in cui si sono scambiati gli identificatori, in -questo caso infatti essi avranno un \textit{real id} privilegiato, che dovrà +questo caso infatti essi avranno un userid reale privilegiato, che dovrà essere esplicitamente eliminato prima di porre in esecuzione un nuovo -programma (occorrerà cioè eseguire un'altra chiamata dopo la \func{fork}, e -prima della \func{exec} per uniformare i \textit{real id} agli -\textit{effective id}) in caso contrario quest'ultimo potrebbe a sua volta -effettuare uno scambio e riottenere privilegi non previsti. +programma (occorrerà cioè eseguire un'altra chiamata dopo la \func{fork} e +prima della \func{exec} per uniformare l'userid reale a quello effettivo) in +caso contrario il nuovo programma potrebbe a sua volta effettuare uno scambio +e riottenere privilegi non previsti. Lo stesso problema di propagazione dei privilegi ad eventuali processi figli -si porrebbe per i \textit{saved id}: queste funzioni derivano da -un'implementazione che non ne prevede la presenza, e quindi non è possibile -usarle per correggere la situazione come nel caso precedente. Per questo -motivo in Linux tutte le volte che tali funzioni vengono usate per modificare -uno degli identificatori ad un valore diverso dal \textit{real id} precedente, -il \textit{saved id} viene sempre settato al valore dell'\textit{effective - id}. - +si pone per l'userid salvato: questa funzione deriva da un'implementazione che +non ne prevede la presenza, e quindi non è possibile usarla per correggere la +situazione come nel caso precedente. Per questo motivo in Linux tutte le volte +che si imposta un qualunque valore diverso da quello dall'userid reale +corrente, l'userid salvato viene automaticamente uniformato al valore +dell'userid effettivo. \subsection{Le funzioni \func{seteuid} e \func{setegid}} \label{sec:proc_seteuid} Queste funzioni sono un'estensione allo standard POSIX.1 (ma sono comunque -supportate dalla maggior parte degli Unix) e usate per cambiare gli -\textit{effective id}; i loro prototipi sono: +supportate dalla maggior parte degli Unix) e vengono usate per cambiare gli +identificatori del gruppo \textit{effective}; i loro prototipi sono: \begin{functions} \headdecl{unistd.h} \headdecl{sys/types.h} -\funcdecl{int seteuid(uid\_t uid)} Setta l'\textit{effective user id} del -processo corrente a \var{uid}. +\funcdecl{int seteuid(uid\_t uid)} Imposta l'userid effettivo del processo +corrente a \var{uid}. -\funcdecl{int setegid(gid\_t gid)} Setta l'\textit{effective group id} del -processo corrente a \var{gid}. +\funcdecl{int setegid(gid\_t gid)} Imposta il groupid effettivo del processo +corrente a \var{gid}. \bodydesc{Le funzioni restituiscono 0 in caso di successo e -1 in caso di fallimento: l'unico errore possibile è \macro{EPERM}.} \end{functions} -Gli utenti normali possono settare l'\textit{effective id} solo al valore del -\textit{real id} o del \textit{saved id}, l'amministratore può specificare -qualunque valore. Queste funzioni sono usate per permettere a root di settare -solo l'\textit{effective id}, dato che l'uso normale di \func{setuid} comporta -il settaggio di tutti gli identificatori. +Come per le precedenti le due funzioni sono identiche, per cui tratteremo solo +la prima. Gli utenti normali possono impostare l'userid effettivo solo al +valore dell'userid reale o dell'userid salvato, l'amministratore può +specificare qualunque valore. Queste funzioni sono usate per permettere +all'amministratore di impostare solo l'userid effettivo, dato che l'uso +normale di \func{setuid} comporta l'impostazione di tutti gli identificatori. \subsection{Le funzioni \func{setresuid} e \func{setresgid}} @@ -1632,25 +1632,25 @@ e permettono un completo controllo su tutti gli identificatori (\textit{real}, \headdecl{unistd.h} \headdecl{sys/types.h} -\funcdecl{int setresuid(uid\_t ruid, uid\_t euid, uid\_t suid)} Setta il -\textit{real user id}, l'\textit{effective user id} e il \textit{saved user - id} del processo corrente ai valori specificati rispettivamente da -\var{ruid}, \var{euid} e \var{suid}. +\funcdecl{int setresuid(uid\_t ruid, uid\_t euid, uid\_t suid)} Imposta +l'userid reale, l'userid effettivo e l'userid salvato del processo corrente +ai valori specificati rispettivamente da \var{ruid}, \var{euid} e \var{suid}. -\funcdecl{int setresgid(gid\_t rgid, gid\_t egid, gid\_t sgid)} Setta il -\textit{real group id}, l'\textit{effective group id} e il \textit{saved group - id} del processo corrente ai valori specificati rispettivamente da -\var{rgid}, \var{egid} e \var{sgid}. +\funcdecl{int setresgid(gid\_t rgid, gid\_t egid, gid\_t sgid)} Imposta il +groupid reale, il groupid effettivo ed il groupid salvato del processo +corrente ai valori specificati rispettivamente da \var{rgid}, \var{egid} e +\var{sgid}. \bodydesc{Le funzioni restituiscono 0 in caso di successo e -1 in caso di fallimento: l'unico errore possibile è \macro{EPERM}.} \end{functions} -I processi non privilegiati possono cambiare uno qualunque degli -identificatori usando uno qualunque dei valori correnti di \textit{real id}, -\textit{effective id} o \textit{saved id}, l'amministratore può specificare i -valori che vuole; un valore di -1 per un qualunque parametro lascia inalterato -l'identificatore corrispondente. +Le due funzioni sono identiche, quanto detto per la prima riguardo gli userid +si applica alla seconda per i groupid. I processi non privilegiati possono +cambiare uno qualunque degli userid solo ad un valore corripondente o +all'userid reale, o a quello effettivo o a quello salvato, l'amministratore +può specificare i valori che vuole; un valore di -1 per un qualunque parametro +lascia inalterato l'identificatore corrispondente. Per queste funzioni esistono anche due controparti che permettono di leggere in blocco i vari identificatori: \func{getresuid} e \func{getresgid}; i loro @@ -1659,13 +1659,12 @@ prototipi sono: \headdecl{unistd.h} \headdecl{sys/types.h} -\funcdecl{int getresuid(uid\_t *ruid, uid\_t *euid, uid\_t *suid)} Legge il -\textit{real user id}, l'\textit{effective user id} e il \textit{saved user - id} del processo corrente. +\funcdecl{int getresuid(uid\_t *ruid, uid\_t *euid, uid\_t *suid)} Legge +l'userid reale, l'userid effettivo e l'userid salvato del processo corrente. \funcdecl{int getresgid(gid\_t *rgid, gid\_t *egid, gid\_t *sgid)} Legge il -\textit{real group id}, l'\textit{effective group id} e il \textit{saved group - id} del processo corrente. +groupid reale, il groupid effettivo e il groupid salvato del processo +corrente. \bodydesc{Le funzioni restituiscono 0 in caso di successo e -1 in caso di fallimento: l'unico errore possibile è \macro{EFAULT} se gli indirizzi delle @@ -1675,31 +1674,32 @@ prototipi sono: Anche queste funzioni sono un'estensione specifica di Linux, e non richiedono nessun privilegio. I valori sono restituiti negli argomenti, che vanno specificati come puntatori (è un'altro esempio di \textit{value result - argument}). Si noti che queste funzioni sono le uniche in grado di leggere i -\textit{saved id}. + argument}). Si noti che queste funzioni sono le uniche in grado di leggere +gli identificatori del gruppo \textit{saved}. \subsection{Le funzioni \func{setfsuid} e \func{setfsgid}} \label{sec:proc_setfsuid} -Queste funzioni sono usate per settare gli identificatori usati da Linux per -il controllo dell'accesso ai file. Come già accennato in -\secref{sec:proc_access_id} in Linux è definito questo ulteriore gruppo di -identificatori, che di norma sono assolutamente equivalenti agli -\textit{effective id}, dato che ogni cambiamento di questi ultimi viene -immediatamente riportato sui \textit{filesystem id}. - -C'è un solo caso in cui si ha necessità di introdurre una differenza fra -\textit{effective id} e \textit{filesystem id}, ed è per ovviare ad un -problema di sicurezza che si presenta quando si deve implementare un server -NFS. Il server NFS infatti deve poter cambiare l'identificatore con cui accede -ai file per assumere l'identità del singolo utente remoto, ma se questo viene -fatto cambiando l'\textit{effective id} o il \textit{real id} il server si -espone alla ricezione di eventuali segnali ostili da parte dell'utente di cui -ha temporaneamente assunto l'identità. Cambiando solo il \textit{filesystem - id} si ottengono i privilegi necessari per accedere ai file, mantenendo -quelli originari per quanto riguarda tutti gli altri controlli di accesso, -così che l'utente non possa inviare segnali al server NFS. +Queste funzioni sono usate per impostare gli identificatori del gruppo +\textit{filesystem} che usati da Linux per il controllo dell'accesso ai file. +Come già accennato in \secref{sec:proc_access_id} Linux definisce questo +ulteriore gruppo di identificatori, che di norma sono assolutamente +equivalenti a quelli del gruppo \textit{effective}, dato che ogni cambiamento +di questi ultimi viene immediatamente riportato su di essi. + +C'è un solo caso in cui si ha necessità di introdurre una differenza fra gli +identificatori dei gruppi \textit{effective} e \textit{filesystem}, ed è per +ovviare ad un problema di sicurezza che si presenta quando si deve +implementare un server NFS. Il server NFS infatti deve poter cambiare +l'identificatore con cui accede ai file per assumere l'identità del singolo +utente remoto, ma se questo viene fatto cambiando l'userid effettivo o +l'userid reale il server si espone alla ricezione di eventuali segnali ostili +da parte dell'utente di cui ha temporaneamente assunto l'identità. Cambiando +solo l'userid di filesystem si ottengono i privilegi necessari per accedere ai +file, mantenendo quelli originari per quanto riguarda tutti gli altri +controlli di accesso, così che l'utente non possa inviare segnali al server +NFS. Le due funzioni usate per cambiare questi identificatori sono \func{setfsuid} e \func{setfsgid}, ovviamente sono specifiche di Linux e non devono essere @@ -1707,10 +1707,10 @@ usate se si intendono scrivere programmi portabili; i loro prototipi sono: \begin{functions} \headdecl{sys/fsuid.h} -\funcdecl{int setfsuid(uid\_t fsuid)} Setta il \textit{filesystem user id} del +\funcdecl{int setfsuid(uid\_t fsuid)} Imposta l'userid di filesystem del processo corrente a \var{fsuid}. -\funcdecl{int setfsgid(gid\_t fsgid)} Setta l'\textit{filesystem group id} del +\funcdecl{int setfsgid(gid\_t fsgid)} Imposta il groupid di filesystem del processo corrente a \var{fsgid}. \bodydesc{Le funzioni restituiscono 0 in caso di successo e -1 in caso @@ -1718,7 +1718,8 @@ processo corrente a \var{fsgid}. \end{functions} \noindent queste funzioni hanno successo solo se il processo chiamante ha i privilegi di amministratore o, per gli altri utenti, se il valore specificato -coincide con uno dei \textit{real}, \textit{effective} o \textit{saved id}. +coincide con uno dei di quelli del gruppo \textit{real}, \textit{effective} o +\textit{saved}. \subsection{Le funzioni \func{setgroups} e \func{getgroups}} @@ -1741,7 +1742,7 @@ questa funzione \bodydesc{La funzione restituisce il numero di gruppi letti in caso di successo e -1 in caso di fallimento, nel qual caso \var{errno} viene - settata a: + impostata a: \begin{errlist} \item[\macro{EFAULT}] \param{list} non ha un indirizzo valido. \item[\macro{EINVAL}] il valore di \param{size} è diverso da zero ma @@ -1749,9 +1750,9 @@ questa funzione \end{errlist}} \end{functions} \noindent non è specificato se la funzione inserisca o meno nella lista -l'\textit{effective user id} del processo. Se si specifica un valore di -\param{size} uguale a 0 \param{list} non viene modificato, ma si ottiene il -numero di gruppi supplementari. +il groupid effettivo del processo. Se si specifica un valore di \param{size} +uguale a 0 \param{list} non viene modificato, ma si ottiene il numero di +gruppi supplementari. Una seconda funzione, \func{getgrouplist}, può invece essere usata per ottenere tutti i gruppi a cui appartiene un utente; il suo prototipo è: @@ -1771,18 +1772,18 @@ cui l'utente appartiene. Si noti che \param{ngroups} perché qualora il valore specificato sia troppo piccolo la funzione ritorna -1, passando indietro il numero dei gruppi trovati. -Per settare i gruppi supplementari di un processo ci sono due funzioni, che +Per impostare i gruppi supplementari di un processo ci sono due funzioni, che possono essere usate solo se si hanno i privilegi di amministratore. La prima delle due è \func{setgroups}, ed il suo prototipo è: \begin{functions} \headdecl{sys/types.h} \headdecl{grp.h} - \funcdecl{int setgroups(size\_t size, gid\_t *list)} Setta i gruppi + \funcdecl{int setgroups(size\_t size, gid\_t *list)} Imposta i gruppi supplementari del processo ai valori specificati in \param{list}. \bodydesc{La funzione restituisce 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} viene impostata a: \begin{errlist} \item[\macro{EFAULT}] \param{list} non ha un indirizzo valido. \item[\macro{EPERM}] il processo non ha i privilegi di amministratore. @@ -1791,18 +1792,18 @@ delle due \end{errlist}} \end{functions} -Se invece si vogliono settare i gruppi supplementari del processo a quelli di +Se invece si vogliono impostare i gruppi supplementari del processo a quelli di un utente specifico, si può usare \func{initgroups} il cui prototipo è: \begin{functions} \headdecl{sys/types.h} \headdecl{grp.h} - \funcdecl{int initgroups(const char *user, gid\_t group)} Setta i gruppi + \funcdecl{int initgroups(const char *user, gid\_t group)} Imposta i gruppi supplementari del processo a quelli di cui è membro l'utente \param{user}, aggiungendo il gruppo addizionale \param{group}. \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di - fallimento, nel qual caso \var{errno} viene settata agli stessi valori di + fallimento, nel qual caso \var{errno} viene impostata agli stessi valori di \func{setgroups} più \macro{ENOMEM} quando non c'è memoria sufficiente per allocare lo spazio per informazioni dei gruppi.} \end{functions} @@ -1810,8 +1811,7 @@ un utente specifico, si pu La funzione esegue la scansione del database dei gruppi (usualmente \file{/etc/groups}) cercando i gruppi di cui è membro \param{user} e costruendo una lista di gruppi supplementari a cui aggiunge \param{group}, che -poi setta usando \func{setgroups}. - +poi imposta usando \func{setgroups}. Si tenga presente che sia \func{setgroups} che \func{initgroups} non sono definite nello standard POSIX.1 e che pertanto non è possibile utilizzarle quando si definisce \macro{\_POSIX\_SOURCE} o si compila con il flag @@ -1858,11 +1858,11 @@ semplicemente l'allocazione della risorsa \textsl{tempo di esecuzione}, la cui assegnazione sarà governata dai meccanismi di scelta delle priorità che restano gli stessi indipendentemente dal numero di processori. -I processi non devono solo eseguire del codice, ad esempio molto spesso -saranno impegnati in operazioni di I/O, possono venire bloccati da un comando -dal terminale, sospesi per un certo periodo di tempo. In tutti questi casi la -CPU diventa disponibile ed è compito dello kernel provvedere a mettere in -esecuzione un altro processo. +Si tenga conto poi che i processi non devono solo eseguire del codice: ad +esempio molto spesso saranno impegnati in operazioni di I/O, o potranno +venire bloccati da un comando dal terminale, o sospesi per un certo periodo di +tempo. In tutti questi casi la CPU diventa disponibile ed è compito dello +kernel provvedere a mettere in esecuzione un altro processo. Tutte queste possibilità sono caratterizzate da un diverso \textsl{stato} del processo, in Linux un processo può trovarsi in uno degli stati riportati in @@ -1873,7 +1873,7 @@ fintanto che esso si trova in uno qualunque degli altri stati. \begin{table}[htb] \centering - \begin{tabular}[c]{|p{3cm}|c|p{8cm}|} + \begin{tabular}[c]{|p{2.8cm}|c|p{10cm}|} \hline \textbf{Stato} & \texttt{STAT} & \textbf{Descrizione} \\ \hline @@ -1892,7 +1892,7 @@ fintanto che esso si trova in uno qualunque degli altri stati. \hline \end{tabular} \caption{Elenco dei possibili stati di un processo in Linux, nella colonna - \texttt{STAT} si è riportata la corripondente lettera usata dal comando + \texttt{STAT} si è riportata la corrispondente lettera usata dal comando \cmd{ps} nell'omonimo campo.} \label{tab:proc_proc_states} \end{table} @@ -1982,15 +1982,14 @@ valore di \var{counter} del processo corrente viene diminuito, questo assicura che anche i processi con priorità più bassa verranno messi in esecuzione. La priorità di un processo è così controllata attraverso il valore di -\var{nice}, che stabilisce la durata della \textit{time-slice}; un valore più -lungo infatti assicura una maggiore attribuzione di CPU. L'origine di questo -parametro sta nel fatto che in genere esso viene generalmente usato come per -diminuire la priorità di un processo, come termine di cortesia (da cui il -nome) nei confronti degli altri. - +\var{nice}, che stabilisce la durata della \textit{time-slice}; per il +meccanismo appena descritto infatti un valore più lungo infatti assicura una +maggiore attribuzione di CPU. L'origine del nome di questo parametro sta nel +fatto che in genere esso viene generalmente usato per diminuire la priorità di +un processo, come misura di cortesia nei confronti degli altri. I processi infatti vengono creati dal sistema con lo stesso valore di -\var{nice} (nullo) e nessuno è privilegiato; il valore può essere modificato -solo attraverso la funzione \func{nice}, il cui prototipo è: +\var{nice} (nullo) e nessuno è privilegiato rispetto agli altri; il valore può +essere modificato solo attraverso la funzione \func{nice}, il cui prototipo è: \begin{prototype}{unistd.h} {int nice(int inc)} Aumenta il valore di \var{nice} per il processo corrente. @@ -1998,58 +1997,343 @@ solo attraverso la funzione \func{nice}, il cui prototipo \bodydesc{La funzione ritorna zero in caso di successo e -1 in caso di errore, nel qual caso \var{errno} può assumere i valori: \begin{errlist} - \item[\macro{EPERM}] un utente normale ha specificato un valore di - \param{inc} negativo. + \item[\macro{EPERM}] un processo senza i privilegi di amministratore ha + specificato un valore di \param{inc} negativo. \end{errlist}} \end{prototype} L'argomento \param{inc} indica l'incremento del valore di \var{nice}: quest'ultimo può assumere valori compresi fra \macro{PRIO\_MIN} e -\macro{PRIO\_MAX} (che nel caso di Linux sono $-19$ e $20$) , ma per +\macro{PRIO\_MAX} (che nel caso di Linux sono $-19$ e $20$), ma per \param{inc} si può specificare un valore qualunque, positivo o negativo, ed il sistema provvederà a troncare il risultato nell'intervallo consentito. Valori positivi comportano maggiore \textit{cortesia} e cioè una diminuzione della -priorità. Solo l'amministratore può specificare valori negativi che permettono -di aumentare la priorità di un processo. - +priorità, ogni utente può solo innalzare il valore di un suo processo. Solo +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, per leggere il nuovo valore di occorre invece usare la +questa convenzione, e per leggere il nuovo valore occorre invece usare la funzione \func{getpriority}, derivata da BSD, il cui prototipo è: \begin{prototype}{sys/resource.h} {int getpriority(int which, int who)} - Restituisce la priorità per l'insieme dei processi specificati. +Restituisce il valore di \var{nice} per l'insieme dei processi specificati. \bodydesc{La funzione ritorna la priorità in caso di successo e -1 in caso di errore, nel qual caso \var{errno} può assumere i valori: \begin{errlist} \item[\macro{ESRCH}] non c'è nessun processo che corrisponda ai valori di \param{which} e \param{who}. - \item[\macro{ESRCH}] il valore di \param{which} non è valido. + \item[\macro{EINVAL}] il valore di \param{which} non è valido. \end{errlist}} \end{prototype} +\noindent (in vecchie versioni può essere necessario includere anche +\file{}, questo non è più necessario con versioni recenti delle +librerie, ma è comunque utile per portabilità). +La funzione permette di leggere la priorità di un processo, di un gruppo di +processi (vedi \secref{sec:sess_proc_group}) o di un utente, a seconda del +valore di \param{which}, secondo la legenda di \tabref{tab:proc_getpriority}, +specificando un corrispondente valore per \param{who}; un valore nullo di +quest'ultimo indica il processo, il gruppo di processi o l'utente correnti. +\begin{table}[htb] + \centering + \footnotesize + \begin{tabular}[c]{|c|c|l|} + \hline + \param{which} & \param{who} & \textbf{Significato} \\ + \hline + \hline + \macro{PRIO\_PROCESS} & \type{pid\_t} & processo \\ + \macro{PRIO\_PRGR} & \type{pid\_t} & process group \\ + \macro{PRIO\_USER} & \type{uid\_t} & utente \\ + \hline + \end{tabular} + \caption{Legenda del valore dell'argomento \param{which} e del tipo + dell'argomento \param{who} delle funzioni \func{getpriority} e + \func{setpriority} per le tre possibili scelte.} + \label{tab:proc_getpriority} +\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. + +Analoga a \func{getpriority} la funzione \func{setpriority} 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)} + Imposta la priorità per l'insieme dei processi specificati. + + \bodydesc{La funzione ritorna la priorità in caso di successo e -1 in caso di + errore, nel qual caso \var{errno} può assumere i valori: + \begin{errlist} + \item[\macro{ESRCH}] non c'è nessun processo che corrisponda ai valori di + \param{which} e \param{who}. + \item[\macro{EINVAL}] il valore di \param{which} non è valido. + \item[\macro{EPERM}] un processo senza i privilegi di amministratore ha + specificato un valore di \param{inc} negativo. + \item[\macro{EACCESS}] un processo senza i privilegi di amministratore ha + cercato di modificare la priorità di un processo di un altro utente. + \end{errlist}} +\end{prototype} + +La funzione imposta la priorità al valore specificato da \param{prio} per +tutti i processi indicati dagli argomenti \param{which} e \param{who}. La +gestione dei permessi dipende dalle varie implementazioni; in Linux, secondo +le specifiche dello standard SUSv3, e come avviene per tutti i sistemi che +derivano da SYSV, è richiesto che l'userid reale o effettivo del processo +chiamante corrispondano al real user id (e solo quello) del processo di cui si +vuole cambiare la priorità; per i sistemi derivati da BSD invece (SunOS, +Ultrix, *BSD) la corrispondenza può essere anche con l'userid effettivo. \subsection{Il meccanismo di \textit{scheduling real-time}} \label{sec:proc_real_time} -Per settare le +Come spiegato in \secref{sec:proc_sched} lo standard POSIX.1b ha introdotto le +priorità assolute per permettere la gestione di processi real-time. In realtà +nel caso di Linux non si tratta di un vero hard real-time, in quanto in +presenza di eventuali interrupt il kernel interrompe l'esecuzione di un +processo qualsiasi sia la sua priorità,\footnote{questo a meno che non si + siano installate le patch di RTLinux o RTAI, con i quali è possibile + ottenere un sistema effettivamente hard real-time. In tal caso infatti gli + interrupt vengono intercettati dall'interfaccia real-time, e gestiti + direttamente qualora ci sia la necessità di avere un processo con priorità + più elevata di un \textit{interrupt handler}.} mentre con l'incorrere in un +page fault\index{page fault} si possono avere ritardi non previsti. Se +l'ultimo problema può essere aggirato attraverso l'uso delle funzioni di +controllo della memoria virtuale (vedi \secref{sec:proc_mem_lock}), il primo +non è superabile e può comportare ritardi non prevedibili riguardo ai tempi di +esecuzione di qualunque processo. + +In ogni caso occorre usare le priorità assolute con molta attenzione: se si dà +ad un processo una priorità assoluta e questo finisce in un loop infinito, +nessun altro processo potrà essere eseguito, ed esso sarà mantenuto in +esecuzione permanentemente assorbendo tutta la CPU e senza nessuna possibilità +di riottenere l'accesso al sistema. Per questo motivo è sempre opportuno, +quando si lavora con processi che usano priorità assolute, tenere attiva una +shell cui si sia assegnata la massima priorità assoluta, in modo da poter +essere comunque in grado di rientrare nel sistema. + +Quando c'è un processo con priorità assoluta lo scheduler lo metterà in +esecuzione prima di ogni processo normale. In caso di più processi sarà +eseguito per primo quello con priorità assoluta più alta. Quando ci sono più +processi con la stessa priorità assoluta questi vengono tenuti in una coda +tocca al kernel decidere quale deve essere eseguito. + + + +Il meccanismo con cui vengono gestiti questi processi dipende dalla politica +di scheduling che si è scelto; lo standard ne prevede due: +\begin{basedescript}{\desclabelwidth{3cm}\desclabelstyle{\nextlinelabel}} +\item[\textit{FIFO}] il processo viene eseguito fintanto che non cede + volontariamente la CPU, si blocca, finisce o viene interrotto da un processo + a priorità più alta. +\item[\textit{Round Robin}] ciascun processo viene eseguito a turno per un + certo periodo di tempo (una \textit{time slice}). Solo i processi con la + stessa priorità ed in stato \textit{runnable} entrano nel circolo. +\end{basedescript} + +La funzione per impostare le politiche di scheduling (sia real-time che +ordinarie) ed i relativi parametri è \func{sched\_setscheduler}; il suo +prototipo è: +\begin{prototype}{sched.h} +{int sched\_setscheduler(pid\_t pid, int policy, const struct sched\_param *p)} + Imposta priorità e politica di scheduling per il processo \param{pid}. + + \bodydesc{La funzione ritorna la priorità in caso di successo e -1 in caso di + errore, nel qual caso \var{errno} può assumere i valori: + \begin{errlist} + \item[\macro{ESRCH}] il processo \param{pid} non esiste. + \item[\macro{EINVAL}] il valore di \param{policy} non esiste o il relativo + valore di \param{p} non è valido. + \item[\macro{EPERM}] il processo non ha i privilegi per attivare la + politica richiesta (vale solo per \macro{SCHED\_FIFO} e + \macro{SCHED\_RR}). + \end{errlist}} +\end{prototype} + +La funzione esegue l'impostazione per il processo specificato; un valore nullo +di \param{pid} esegue l'impostazione per il processo corrente, solo un +processo con i privilegi di amministratore può impostare delle priorità +assolute diverse da zero. La politica di scheduling è specificata +dall'argomento \param{policy} i cui possibili valori sono riportati in +\tabref{tab:proc_sched_policy}; un valore negativo per \param{policy} mantiene +la politica di scheduling corrente. + +\begin{table}[htb] + \centering + \footnotesize + \begin{tabular}[c]{|c|l|} + \hline + \textbf{Policy} & \textbf{Significato} \\ + \hline + \hline + \macro{SCHED\_FIFO} & Scheduling real-time con politica \textit{FIFO} \\ + \macro{SCHED\_RR} & Scheduling real-time con politica \textit{Round + Robin} \\ + \macro{SCHED\_OTHER}& Scheduling ordinario\\ + \hline + \end{tabular} + \caption{Valori dell'argomento \param{policy} per la funzione + \func{sched\_setscheduler}. } + \label{tab:proc_sched_policy} +\end{table} + +Il valore della priorità è passato attraverso la struttura \var{sched\_param} +(riportata in \figref{fig:sig_sched_param}), il cui solo campo attualmente +definito è \var{sched\_priority}, che nel caso delle priorità assolute deve +essere specificato nell'intervallo fra un valore massimo ed uno minimo, che +nel caso sono rispettivamente 1 e 99 (il valore zero è legale, ma indica i +processi normali). + +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{15cm} + \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{} +struct sched_param { + int sched_priority; +}; + \end{lstlisting} + \end{minipage} + \normalsize + \caption{La struttura \var{sched\_param}.} + \label{fig:sig_sched_param} +\end{figure} + -\footnote{a meno che non si siano installate le patch di RTLinux o RTAI, con i - quali è possibile ottenere un sistema effettivamente hard real-time.} +Lo standard POSIX.1b prevede comunque che i due valori della massima e minima +priorità statica possano essere ottenuti, per ciascuna delle politiche di +scheduling realtime, tramite le due funzioni \func{sched\_get\_priority\_max} +e \func{sched\_get\_priority\_min}, i cui prototipi sono: +\begin{functions} + \headdecl{sched.h} + + \funcdecl{int sched\_get\_priority\_max(int policy)} Legge il valore + massimo della priorità statica per la politica di scheduling \param{policy}. -in realtà non si tratta di un vero hard real-time, in quanto - la presenza di eventuali interrupt o di page fault può sempre interrompere - l'esecuzione di un processo, a meno di non installare le estensioni di - RTLinux o RTAI, il normale kernel non è real-time. + + \funcdecl{int sched\_get\_priority\_min(int policy)} Legge il valore minimo + della priorità statica per la politica di scheduling \param{policy}. + + \bodydesc{La funzioni ritornano il valore della priorità in caso di successo + e -1 in caso di errore, nel qual caso \var{errno} può assumere i valori: + \begin{errlist} + \item[\macro{EINVAL}] il valore di \param{policy} è invalido. + \end{errlist}} +\end{functions} +I processi con politica di scheduling \macro{SCHED\_OTHER} devono specificare +un valore nullo (altrimenti si avrà un errore \macro{EINVAL}), questo valore +infatti non ha niente a che vedere con la priorità dinamica determinata dal +valore di \var{nice}, che deve essere impostato con le funzioni viste in +precedenza. + +Il kernel mantiene i processi con la stessa priorità assoluta in una lista, ed +esegue sempre il primo della lista, mentre un nuovo processo che torna in +stato \textit{runnable} viene sempre inserito in coda alla lista. Se la +politica scelta è \macro{SCHED\_FIFO} quando il processo viene eseguito viene +automaticamente rimesso in coda alla lista, e la sua esecuzione continua +fintanto che non viene bloccato da una richiesta di I/O, o non rilascia +volontariamente la CPU (in tal caso, tornando nello stato \textit{runnable} +sarà reinserito in coda alla lista); l'esecuzione viene ripresa subito solo +nel caso che esso sia stato interrotto da un processo a priorità più alta. + +La priorità assoluta può essere riletta indietro dalla funzione +\func{sched\_getscheduler}, il cui prototipo è: +\begin{prototype}{sched.h} +{int sched\_getscheduler(pid\_t pid)} + Legge la politica di scheduling per il processo \param{pid}. + + \bodydesc{La funzione ritorna la politica di scheduling in caso di successo + e -1 in caso di errore, nel qual caso \var{errno} può assumere i valori: + \begin{errlist} + \item[\macro{ESRCH}] il processo \param{pid} non esiste. + \item[\macro{EINVAL}] il valore di \param{pid} è negativo. + \end{errlist}} +\end{prototype} + +La funzione restituisce il valore (secondo la quanto elencato in +\tabref{tab:proc_sched_policy}) della politica di scheduling per il processo +specificato; se \param{pid} è nullo viene restituito quello del processo +chiamante. + +Se si intende operare solo sulla priorità assoluta di un processo si possono +usare le funzioni \func{sched\_setparam} e \func{sched\_getparam}, i cui +prototipi sono: + +\begin{functions} + \headdecl{sched.h} + + \funcdecl{int sched\_setparam(pid\_t pid, const struct sched\_param *p)} + Imposta la priorità assoluta del processo \param{pid}. + + + \funcdecl{int sched\_getparam(pid\_t pid, struct sched\_param *p)} + Legge la priorità assoluta del processo \param{pid}. + + \bodydesc{La funzione ritorna la priorità in caso di successo + e -1 in caso di errore, nel qual caso \var{errno} può assumere i valori: + \begin{errlist} + \item[\macro{ESRCH}] il processo \param{pid} non esiste. + \item[\macro{EINVAL}] il valore di \param{pid} è negativo. + \end{errlist}} +\end{functions} + +L'uso di \func{sched\_setparam} che è del tutto equivalente a +\func{sched\_setscheduler} con \param{priority} uguale a -1. Come per +\func{sched\_setscheduler} specificando 0 come valore di \param{pid} si opera +sul processo corrente. La disponibilità di entrambe le funzioni può essere +verificata controllando la macro \macro{\_POSIX\_PRIORITY\_SCHEDULING} che è +definita nell'header \macro{sched.h}. + +L'ultima funzione che permette di leggere le informazioni relative ai processi +real-time è \func{sched\_rr\_get\_interval}, che permette di ottenere la +lunghezza della \textit{time slice} usata dalla politica \textit{round robin}; +il suo prototipo è: +\begin{prototype}{sched.h} + {int sched\_rr\_get\_interval(pid\_t pid, struct timespec *tp)} Legge in + \param{tp} la durata della \textit{time slice} per il processo \param{pid}. + + \bodydesc{La funzione ritorna 0in caso di successo e -1 in caso di errore, + nel qual caso \var{errno} può assumere i valori: + \begin{errlist} + \item[\macro{ESRCH}] il processo \param{pid} non esiste. + \item[\macro{ENOSYS}] la system call non è stata implementata. + \end{errlist}} +\end{prototype} + +La funzione restituisce il valore dell'intervallo di tempo usato per la +politica \textit{round robin} in una struttura \var{timespec}, (la cui +definizione si può trovare in \figref{fig:sys_timeval_struct}). + + +Come accennato ogni processo che usa lo scheduling real-time può rilasciare +volontariamente la CPU; questo viene fatto attraverso la funzione +\func{sched\_yield}, il cui prototipo è: +\begin{prototype}{sched.h} + {int sched\_yield(void)} + + Rilascia volontariamente l'esecuzione. + + \bodydesc{La funzione ritorna 0 in caso di successo e -1 in caso di errore, + nel qual caso \var{errno} viene impostata opportunamente.} +\end{prototype} +La funzione fa si che il processo rilasci la CPU, in modo da essere rimesso in +coda alla lista dei processi da eseguire, e permettere l'esecuzione di un +altro processo; se però il processo è l'unico ad essere presente sulla coda +l'esecuzione non sarà interrotta. In genere usano questa funzione i processi +in modalità \textit{fifo}, per permettere l'esecuzione degli altri processi +con pari priorità quando la sezione più urgente è finita. \section{Problematiche di programmazione multitasking} @@ -2079,7 +2363,8 @@ di interruzione in una fase intermedia. In un ambiente multitasking il concetto è essenziale, dato che un processo può essere interrotto in qualunque momento dal kernel che mette in esecuzione un altro processo o dalla ricezione di un segnale; occorre pertanto essere -accorti nei confronti delle possibili \textit{race condition} (vedi +accorti nei confronti delle possibili +\textit{race condition}\index{race condition} (vedi \secref{sec:proc_race_cond}) derivanti da operazioni interrotte in una fase in cui non erano ancora state completate. @@ -2113,7 +2398,8 @@ condiviso, onde evitare problemi con le ottimizzazioni del codice. -\subsection{Le \textit{race condition} e i \textit{deadlock}} +\subsection{Le \textit{race condition}\index{race condition} e i + \textit{deadlock}} \label{sec:proc_race_cond} Si definiscono \textit{race condition} tutte quelle situazioni in cui processi @@ -2142,7 +2428,7 @@ atomicamente le operazioni necessarie, occorre che quelle parti di codice in cui si compiono le operazioni sulle risorse condivise (le cosiddette \textsl{sezioni critiche}) del programma, siano opportunamente protette da meccanismi di sincronizzazione (torneremo su queste problematiche di questo -tipo in \secref{sec:ipc_semaph}). +tipo in \capref{cha:IPC}). Un caso particolare di \textit{race condition} sono poi i cosiddetti \textit{deadlock}, particolarmente gravi in quanto comportano spesso il blocco