\documentclass[a4paper]{article}


\usepackage{isolatin1}
\usepackage{italian}
\usepackage{alltt}
\usepackage{lscape}


\begin{document}

\title{La gestione dei processi in Linux}


\author{Antonio Messina}

\date{20 Marzo 2000}

\maketitle


\section{Introduzione}

Linus Torvalds, quando decise di progettare un nuovo sistema operativo,
disse che voleva far fare al suo 386 quello che facevano le SUN
dell'Universit\`a... appare quindi chiaro come Linux sia orientato verso
l'uso tipico di un server di rete. Per un server la stabilit\`a \`e
fondamentale, e per ottenerla \`e necessaria una struttura che permette
al sistema stesso di difendersi da chi, pi\`u o meno coscientemente,
mette a rischio le risorse della macchina. Vediamo qua alcune di queste
tecniche, in particolare quelle relative alla gestione dei processi, tra
cui il \textit{multitasking}, la gestione dei permessi, le limitazioni
imposte agli utenti.

Una precisazione: processo (traduzione delle parole inglesi
\textit{task} e \textit{processes}) \`e in genere un programma mentre
viene eseguito, o, come si dice spesso, \textit{gira}.

\section{Multitasking preemptive}

Un server di rete normalmente offre un certo numero di servizi (web,
ftp, posta...)  che devono poter essere utilizzabili
contemporaneamente e da pi\`u persone nello stesso tempo. \`E quindi
necessario che il sistema operativo permetta a pi\`u processi di
utilizzare periodicamente il processore (CPU); questa caratteristica
va sotto il nome di ``multitasking''. 

Esistono due tipi diversi di multitasking: quello \textit{cooperativo}
e il \textit{preemptive}; nel primo il sistema operativo lascia il
pieno controllo della CPU al processo che deve essere eseguito in quel
momento, e si affida ad esso affinch\'e rilasci il processore dopo un
po' di tempo, mentre nel secondo il pieno controllo resta sempre al
sistema operativo, che riesce a bloccare il processo e a riprendersi
la cpu, se necessario. Ovviamente il multitasking preemptive \`e molto
pi\`u sicuro.
In pratica si permette ad ogni processo di utilizzare la cpu solo per un
tempo limitato (200ms) alla volta, e se un processo deve essere eseguito
pi\`u rapidamente semplicemente gli si premette pi\`u spesso di utilizzarla.

Per sapere quale processo ha pi\`u urgenza di essere eseguito si
utilizza un sistema di priorit\`a, in modo che quelli con priorit\`a
maggiore utilizzino la CPU pi\`u spesso. Stranamente la priorit\`a
 viene rappresentata da un numero (NICE) compreso tra -20 e 20, e i
processi a maggiore priorit\`a sono quelli con un valore di NICE
minore. La priorit\`a di un processo pu\`o essere specificata al momento
dell'esecuzione con il
comando \texttt{nice} o modificata mentre il processo \`e in esecuzione 
con il comando \texttt{renice}. 

L'uso del comando \texttt{nice} \`e semplice: se seguito da
\texttt{-n}, da un numero (positivo o negativo) e dal comando, tenta
di eseguire quel comando assegnandogli il valore di NICE specificato
dal numero. Se invece si scrive semplicemente \texttt{nice <numero>
<comando>} verr\`a incrementato del valore specificato la NICE del
comando, che in genere \`e sempre `0'.

Il comando \texttt{renice} \`e ancora pi\`u semplice: seguito da un
numero (positivo o negativo) e dal PID di un processo setta il valore
di NICE del processo con il numero specificato. 

Sia con \texttt{nice} che con  \texttt{renice} valori negativi possono
essere assegnati solo da root.

Il multitasking rientra in un disegno generale pi\`u ampio volto a far
s\`\i che esista una differenziazione tra processi che comunicano
direttamente con l'hardware (si dice che girano in \textit{kernel
mode}) e processi che non possono farlo (girano in \textit{user
mode}), e che per poter utilizzare le risorse della macchina devono
necessariamente passare per i primi. Normalmente in kernel mode gira
solo il kernel stesso, ma in diverse forme. Esistono infatti dei
processi, come \texttt{kflushd, kswapd} ed altri che sono dei veri e
propri pezzi di kernel che per\`o girano come processi indipendenti. A
parte questi ogni altro programma che voglia utilizzare una qualche
risorsa hardware lo fa utilizzando delle \textit{chiamate di sistema}
che il kernel interpreta nel modo dovuto. La stabilit\`a di una
macchina \`e quindi fortemente legata a quella del kernel che monta, e
il kernel Linux \`e considerato piuttosto stabile.


\section{I processi: avvio, genealogia}

Quando si accende un computer esso carica ed esegue il kernel, e quando
questo \`e stato caricato, tra le altre cose che fa, come montare la
partizione di root, esegue il primo processo, di solito
\texttt{/sbin/init}.  Si pu\`o specificare anche in fase di boot (dal
prompt del LILO) quale programma utilizzare all'avvio, con l'opzione
\texttt{init=/path/programma}, cosa molto utile se la linux box ha
qualche problema di troppo...

Tutti gli altri processi sono fatti nascere, indirettamente o
direttamente, da init.

Ogni processo viene identificato dal kernel tramite un PID, assegnato
al momento dell'esecuzione del programma, e una serie di altre
informazioni. I PID vengono assegnati in ordine crescente, quindi init
ha sempre PID=1. 

In un sistema Linux tutti i processi nascono tramite una
\texttt{fork()}, che non fa altro che duplicare il processo e far
eseguire quello duplicato da dopo la chiamata. 
Se si vuole che un processo esegua un programma si utilizza una
fork(), e si fa in modo che il processo duplicato chiami una
\texttt{exec}, che di fatto sostituisce il programma corrente con
quello da eseguire.

Con questo sistema ogni processo ha un padre, il processo che lo ha
generato, e dei figli, i processi che ha generato, di conseguenza
tutti i processi sono discendenti di init (potevano chiamarlo adamo...)

Sapere le parentele \`e abbastanza utile (lo vedremo meglio nelle
prossime sezioni), perch\'e spesso se termina un processo terminano
tutti i suoi figli (se i figli sopravvivono diventano
orfani)(sto parlando seriamente).
Per vedere le parentele tra processi esistono i comandi
\texttt{pstree} e \texttt{ps}. Vediamo alcuni esempi:

\begin{verbatim}
[messina@poisson seminario $] pstree -p
init(1)-+-apache(325)-+-apache(28691)
        |             |-apache(28692)
        |             |-apache(28693)
        |             |-apache(28694)
        |             |-apache(28856)
        |             |-apache(16085)
        |             |-apache(11497)
        |             `-apache(28943)
        |-automount(260)
        |-automount(273)
        |-automount(284)
        |-cron(320)
        |-getty(2370)
        |-gpm(184)
        |-icmplogd(191)
        |-inetd(163)
        |-kdm(341)-+-XF86_S3(1478)
        |          `-kdm(2479)
        |-kerneld(40)
        |-kflushd(2)
        |-klogd(151)
        |-kswapd(3)
        |-nfsiod(292)
        |-nfsiod(293)
        |-nfsiod(294)
        |-nfsiod(295)
        |-portmap(161)
        |-rpc.mountd(303)
        |-rpc.nfsd(300)
        |-rpc.rstatd(310)
        |-rpc.rusersd(312)
        |-rpc.rwalld(308)
        |-rwhod(315)
        |-sshd(204)---sshd(3287)---bash(3291)-+-emacs(3315)
        |                                     |-pstree(3341)
        |                                     `-xdvi.bin.real(3316)
        |-syslogd(149)
        |-timeseal(327)
        |-update(20)
        |-ypbind(175)---ypbind(176)-+-ypbind(177)
        |                           `-ypbind(178)
        `-ypserv(171)
[messina@poisson seminario $]
\end{verbatim}


L'opzione `-p' stampa accanto ad un processo il suo PID. Se
aggiungiamo anche il nome di un utente verr\`a stampato solo l'albero
dei processi di quell'utente. L'altro comando \`e pi\`u prolisso...

\newpage
\begin{landscape}
\begin{verbatim}
[messina@poisson seminario $] ps axufwwww
USER       PID %CPU %MEM  SIZE   RSS TTY STAT START   TIME COMMAND
daemon     161  0.0  0.4   816   316  ?  S   Feb 17   0:00 /sbin/portmap 
nobody     308  0.0  0.5   860   344  ?  S   Feb 17   0:00 /usr/sbin/rpc.rwalld 
root         1  0.0  0.5   776   320  ?  S   Feb 17   0:04 init 
root        20  0.0  0.1   728   120  ?  S   Feb 17   0:03 update 
root        40  0.0  0.3   748   244  ?  S   Feb 17   0:00 /sbin/kerneld 
root       149  0.0  0.8   980   548  ?  S   Feb 17   0:42 /sbin/syslogd 
root       151  0.0  0.6   864   392  ?  S   Feb 17   0:13 /sbin/klogd 
root       163  0.0  0.6   852   392  ?  S   Feb 17   0:00 /usr/sbin/inetd 
root       175  0.0  0.5  1032   332  ?  S   Feb 17   0:01 /usr/sbin/ypbind 
root       184  0.0  0.3   772   232  ?  S   Feb 17   0:00 /usr/sbin/gpm -m /dev/ttyS0 -t msc 
root       204  0.0  0.7  1312   492  ?  S   Feb 17   1:23 /usr/sbin/sshd -q 
root      3287  1.7  2.3  1900  1468  ?  S    08:21   0:22  \_ /usr/sbin/sshd -q 
messina   3291  0.0  2.1  1984  1380  p0 S    08:21   0:00      \_ -bash 
messina   3315  1.8  8.1  6616  5156  p0 S    08:25   0:19          \_ emacs processi.tex 
messina   3347  0.0  0.9   964   628  p0 R    08:42   0:00          \_ ps axufwwww 
root       300  0.0  1.0  1296   672  ?  S   Feb 17   0:41 /usr/sbin/rpc.nfsd 
root       303  0.0  0.8  1224   564  ?  S   Feb 17   0:00 /usr/sbin/rpc.mountd 
root       310  0.0  0.3   768   204  ?  S   Feb 17   0:00 /usr/sbin/rpc.rstatd 
root       312  0.0  0.4   792   256  ?  S   Feb 17   0:00 /usr/sbin/rpc.rusersd 
root       325  0.0  1.5  2108   960  ?  S   Feb 17   0:00 /usr/sbin/apache 
www-data 11497  0.0  1.5  2204  1016  ?  S   Feb 27   0:09  \_ /usr/sbin/apache 
root       341  0.0  2.6  5300  1652  ?  S   Feb 17   0:24 /usr/bin/X11/kdm 
root      1478  0.4  8.1  9184  5200  ?  S   Feb 18  80:28  \_ /usr/bin/X11/X vt11 
root      2479  0.0  4.3  5472  2768  ?  S    17:53   0:00  \_ -:0              
root      2370  0.0  0.7   892   508   1 S    17:25   0:00 /sbin/getty 38400 tty1 
[messina@poisson seminario $]
\end{verbatim}
\end{landscape}
\newpage

\section{Permessi e multiutenza}

Come sappiamo bene Linux \`e un sistema multiutente, il che vuol dire
non solo che \`e possibile utilizzarlo solo avendo una coppia
nome\_login/password, ma anche che esiste un sistema di permessi che ci
impedisce di scrivere dove non dovremmo, in modo che io possa impedire
ad un altro utente di cancellarmi i file, ma che soprattutto il
sistema possa impedire ad un utente qualsiasi di modificare la
configurazione e magari anche l'integrit\`a del sistema stesso.

Questo sistema di permessi \`e integrato nel kernel, ma per quello che
riguarda la memorizzazione dei files deve essere utilizzato un
\textit{filesystem} (ovvero un modo di scrivere le informazioni sul
disco) che supporti questo sistema, visto che tutte le informazioni
che il kernel scrive riguardo ai permessi e i proprietari dei file
devono sopravvivere allo spegnimento della macchina. Il filesystem
utilizzato normalmente con Linux si chiama \textbf{ext2}, ed \`e in
genere molto efficiente\footnote{tra poco dovrebbe uscire una
evoluzione di questo filesystem, che oltre a migliorare la velocit\`a
di lettura/scrittura, avr\`a un sistema per evitare la perdita di dati
dovuta alla mancanza improvvisa di corrente}.

Il kernel identifica ogni utente con una coppia di numeri: l'UID e il
GID, che sono gli identificativi dell'Utente e del Gruppo a cui
appartiene un utente (in genere sono uguali, e ognuno fa gruppo a
s\'e). Il nome corrispondente \`e solo una nostra comodit\`a, e si
pu\`o cambiare semplicemente editando il file
\texttt{/etc/passwd}. Per vedere gli uid/gid di un utente si usa il
comando \texttt{id}:

\begin{verbatim}
[messina@sophie seminario $] id messina
uid=10295(messina) gid=10295(messina) groups=10295(messina)}
[messina@sophie seminario $]
\end{verbatim}

Per vedere quali permessi sono associati ad un file \`e sufficiente aggiungere al comando \texttt{ls} l'opzione `-l' (vi consiglio di usare anche l'opzione `--color', che colora diversamente file, directory, eseguibili ecc...):

\begin{verbatim}
[messina@sophie seminario $] ls -l 
total 25  
-rw-rw-r--   1 messina  messina       717 Feb 29 18:42 processi.aux
-rw-rw-r--   1 messina  messina      8220 Feb 29 18:42 processi.dvi
-rw-rw-r--   1 messina  messina      2362 Feb 29 18:42 processi.log
-rw-rw-r--   1 messina  messina      6116 Feb 29 18:42 processi.tex
[messina@sophie seminario $]
\end{verbatim}

Leggendo da destra l'output di questo comando vediamo il nome del
file, la data e l'ora di ultima modifica, la dimensione (di
solito... per le device vengono visualizzati \textit{major} e
\textit{minor number}) il gruppo e l'utente proprietari del file, e il numero di link riferiti al file. La parte a destra \`e leggermente pi\`u criptica...
Da sinistra a destra \`e idealmente divisa in quattro parti:

\vspace{1em}

\noindent
\begin{tabular}{|l|l|l|l|l|l|}
\hline
tipo     & permessi utente & perm. gruppo & perm. di tutti gli altri &extra \cr
\hline

-,d,c,b,l,p &  tre tra r,w,x,s,-     & tre tra   r,w,x,s,- & tre tra r,w,x,s,- & t,- \cr
\hline
\end{tabular}
\vspace{1em}

Il tipo ci dice se si tratta di un file (-), una device a blocchi (b)
come un disco o un cdrom, una device a caratteri (c), come le porte
seriali o un terminale, una \textit{named pipe} (p), una directory (d), o un link simbolico (l). I
permessi per i link simbolici sono sempre `lrwxrwxrwx' e non si
possono cambiare, mentre negli altri casi il loro significato cambia a
seconda che si tratti di una directory o di qualcos'altro. Vediamoli
in dettaglio:

\vspace{1em}

\noindent
\begin{tabular}{|c|*{2}{p{4.5cm}|}}
\hline
\textbf{Simbolo} & \textbf{File/device} & \textbf{Directory} \cr
\hline

r & Leggere il file & Listare il contenuto, per esempio con il comando `ls'\cr
\hline

w & Scrivere sul file o cambiarne gli attributi & Creare o rimuovere
file all'interno della directory \cr
\hline

x & Eseguire il file come programma & Accedere alla directory \cr
\hline

s (u+s)& bit SUID. Il programma al momento dell'esecizione acquisir\`a
l'uid o il gid dell'utente/gruppo proprietario del file &
\textit{Nessun effetto} \cr 
\hline

s (g+s) & bit SGID. Come prima. & I file creati in questa directory
non erediano il GID del processo che li crea ma quello della
directory. \cr
\hline

t (\textit{sticky}) &Mantiene il testo del programma sulla device di
swap & Solo il proprietario della directory o del file pu\`o rimuovere
un file contenuto nella directory (/tmp \`e un tipico esempio) \cr
\hline

\end{tabular}
\vspace{1em}

I permessi si possono cambiare tramite il comando \texttt{chmod},
mentre l'utente e il gruppo proprietari possono essere cambiati, da
root, con il comando \texttt{chown} e \texttt{chgrp}.

L'uso del comando chmod \`e semplice: si fa seguire il nome da una o
pi\`u tra
le lettere u,g,o,a, (User, Group, Other, All), che rappresentano i
gruppi di persone per le quali si vuole impostare il o i permessi; non
separato da spazio si inserisce un `+', se \`e un permesso che
vogliamo aggiungere, o un `-', se \`e un permesso esistente che
vogliamo rimuovere; infine si scelgono i permessi da settare/rimuovere
inserendo una o pi\`u delle lettere che rappresentano i permessi
(escluso `-', ovviamente, che rappresenta la non assegnazione di un
permesso).  Ultimi vanno messi i file su cui si deve impostare il
permesso.

Quando un utente lancia un processo questo mantiene memoria di uid/gid
dell'utente che lo ha lanciato, ma possiede anche un'altra coppia di
uid/gid che sono quelli effettivi del processo. Di solito sono gli
stessi dell'utente, ma non \`e detto. Per esempio all'avvio ci sono
alcuni processi che vengono lanciati da root, ma che non necessitano
effettivamente di cos\`\i \   alti privilegi, di conseguenza vengono fatti
partire come \texttt{nobody}, ovvero un utente fittizio che non ha
nessun diritto particolare. D'altro canto esistono programmi come X che
necessitano di permessi meno restrittivi ma che devono poter essere
lanciati da qualsiasi utente. Notiamo a questo punto che:

\begin{verbatim}
[messina@poisson seminario$] ls -l $(which X)
-rwsr-xr-x   1 root     root         4792 Feb 23  1999 /usr/X11R6/bin/X
\end{verbatim}

Quindi il file \`e di propriet\`a di root, ha il bit SUID impostato ed \`e eseguibile da tutti. Questo significa che chiunque esegua il processo esso acquisit\`a i diritti di root, infatti:

\begin{verbatim}
[messina@poisson seminario$] ps aux|grep 'X '
messina   1183  0.0  0.6   928   412  p0 S    12:26   0:00 grep X  
root       332  4.7  6.8  8464  4320  ?  R    11:14   3:25 /usr/bin/X11/X vt11 -
[messina@poisson seminario$] 
\end{verbatim}



Per capire quanto utili siano i permessi per rendere sicuro il sistema
facciamo un piccolo esempio: supponiamo che, siccome sono un pessimo
programmatore, ho fatto un programma, \texttt{sontuttunbuco}, che
periodicamente va a scrivere uno `0' nel file contenente il kernel. Se
lo lancio come utente normale ottengo qualcosa del tipo:

\begin{verbatim}
[messina@poisson seminario$] ./sontuttunbuco
Segmentation fault
[messina@poisson seminario$] 
\end{verbatim}

o anche, se faccio:

\begin{verbatim}
[messina@poisson seminario$] rm /boot/vmlinuz-2.2.14 -f
rm: cannot unlink `/boot/vmlinuz-2.2.14': Permission denied
[messina@poisson seminario$] 
\end{verbatim}

Se per\`o a questo punto do i comandi (da root) \texttt{chmod +s
sontuttunbuco} e \texttt{chown root sontuttunbuco}, rendo il processo
suid root, quindi una volta eseguito, da qualsiasi utente, questo
potr\`a scrivere sui file di sistema. (Ed io mi merito un pugno in faccia...)


\section{Ancora sui processi}

I processi sono visti dal kernel come elementi di un vettore di
puntatori a delle strutture di tipo \texttt{task\_struct}, che
contengono le informazioni relative al processo stesso, come il PID,
il processo padre, i figli, uid e gid di chi lo ha lanciato e quelli
effettivi, l'area di memoria a lui assegnata ed altro ancora. La
lunghezza massima di questo vettore rappresenta il numero massimo di
processi che possono girare sulla macchina, che in genere \`e 512.

Un processo pu\`o trovarsi in diverse condizioni. Per avere utili
informazioni riguardo a quelli che stanno girando mentre siete
collegati potete dare il comando \texttt{ps aux}, il cui output \`e
diviso in colonne che significano:

\begin{itemize}

\item USER

uid effettivo del processo

\item PID

PID del processo

\item \%CPU

rapporto tra il tempo usato e il tempo di esecuzione del
processo. (guai se arriva a 100\%...)
 
\item \%MEM

memoria occupata

\item SIZE

dimensione totale occupata dal processo, ovvero di text+data+stack

\item RSS

dimensione del set residente

\item TTY

terminale controllante

\item STAT

stato del processo (vedi dopo)

\item START

avvio del processo

\item TIME

tempo di esecuzione

\item COMMAND 

il comando eseguito.

\end{itemize}

Lo stato di un processo pu\`o essere:

\begin{itemize}

\item Running (R)

Il processo sta girando o aspetta che il kernel gli ceda la CPU per
poter girare.

\item Sleeping (D) o Sleeping non interrompibile (D)

Il processo sta aspettando che si verifichi un certo evento o che una
risorsa sia nuovamente disponibile. Il programma ps ci fornisce anche
ulteriori informazioni:
\begin{itemize}
\item \textbf{W}, se il processo non ha pagine residenti in memoria.
\item \textbf{N}, se ha una bassa priorit\`a (nice positivo)
\end{itemize}

\item Stopping (T)

Il processo \`e stato bloccato, in genere tramite l'invio di un
segnale.

\item Zombie (Z)

I programmatori di Linux hanno abbastanza sense of humor per chiamare
cos\`\i \  i processi che sono stati ufficialmente uccisi ma che per
qualche ragione non possono essere cancellati del tutto.  Di fatto un
processo in stato di zombie non occupa memoria, il suo codice non
esiste pi\`u, non pu\`o fare nulla (\`e morto!), ma permane, per
qualche motivo, la sua \texttt{tasc\_struct}, e quindi ne rimane
traccia nel sistema.
\end{itemize}


\section{Gruppi di processi e sessioni}

Il programma pi\`u importante in un sistema linux \`e la shell, che
legge da tastiera dei comandi e li interpreta in modo da eseguire certi
processi. Come abbiamo detto per fare questo usa le funzioni fork() ed
exec().

Un singolo comando pu\`o far partire pi\`u processi, ad esempio usando
la pipe (`$|$') possiamo concatenare due processi in modo da ridirigere lo
standard output del primo sullo standard input del secondo. L'insieme
dei processi che sono fatti partire da un unico comando viene chiamato
\textit{process group} o \textit{job}. 

Una sessione invece \`e un insieme pi\`u grande di processi, che
comprende di solito tutti i processi fatti partire da un unico login. Il
primo di questi viene chiamato \textit{session leader}. Quando un
processo viene creato appartiene alla stessa sessione cui appartiene al
 padre; tramite per\`o la funzione \texttt{setsid} il processo pu\`o
 divenire session leader di una nuova sessione. Questo muove il processo
 in un altro gruppo.

Normalmente si ha un solo session leader per login, e questo \`e la
shell. Essa controlla il terminale attuale, e deve anche gestire i
vari job che possono voler utilizzare contemporaneamente il terminale,
assegnando a uno solo per volta il controllo dello stesso. Il processo
che ha l'uso del terminale in un dato momento si dice essere in
\textit{foreground}, mentre gli altri sono in \textit{background}. Se
un processo in background ha necessit\`a di scrivere sul terminale
viene bloccato dal terminal driver.

Un utente pu\`o mettere in background un processo con il carattere SUSP
(di solito `C-z'), che blocca il processo. A questo punto tramite il
comando \texttt{bg} possiamo farlo continuare in
background\footnote{Quello che segue, per quello che riguarda la
ridirezione dell'output ed i comandi fg e bg funziona certamente se si
utilizza la shell \texttt{bash}, ma non \`e detto che con altri tipi
di shell funzioni.}.  Per
mettere un processo in foreground si usa il comando \texttt{fg}. Infine,
per far partire un processo (o un gruppo di processi) direttamente in
background si aggiunge alla fine del comando il carattere `\&'.

Quando il processo che controlla il terminale (nel caso precedente \`e
la shell) viene terminato manda a tutti gli appartenenti alla sessione
un segnale (SIGHUP) che, se non \`e ignorato, causa la morte dei
processi. Nel caso che il segnale sia ignorato (vedi successive sezioni)
il processo non muore, ma diventa ``orfano'', cio\`e non appartiene
pi\`u alla sessione, che non esiste, e diventa session leader. Se diamo
il comando \texttt{pstree} il processo risulter\`a essere figlio di init.

Normalmente lo standard output (cio\`e il luogo in cui il processo
scrive, se deve) e lo standard error (dove vengono scritti normalmente
messaggi di errore) di un processo \`e il terminale controllato dal
session leader, mentre lo standard input (cio\`e da dove prende
eventuali informazioni durante l'esecuzione) \`e la tastiera. Questi
possono essere modificati (ridiretti) all'avvio del processo, in modo,
per esempio, da far scrivere su un file anzich\'e sul terminale,
oppure in modo da prendere da un file le informazioni che invece il
processo avrebbe richiesto da tastiera.

Per ridirigere lo standard output esistono tre simboli chiave:
\texttt{$|$, >, >>}. 

Se si vuole far s\`\i che lo standard output del processo sia lo
standard input di un altro, come detto si usa la pipe (`$|$').
Esempio: \\ \texttt{man bash -t $|$ lpr}\\ formatta la manpage di bash e la
converte in formato postscript, che poi passa al comando lpr che la stampa.



Questo simbolo si usa anche per ridirigere lo standard error, e la
      sintassi \`e identica alla precedente, a meno di mettere un `2'
      davanti a `\texttt{>}'. Per esempio il comando \\ \texttt{kdvi
      processi.dvi 2>/dev/null}\\ non mi far\`a vedere nessuno dei
      messaggi normalmente stampati dal kdvi mentre elabora il file
      .dvi.


Se si vuole ridirigere lo standard output su un file scrivendo
dall'inizio (e quindi cancellando il contenuto del file, se esiste)
basta aggiungere '\texttt{> file}' in fondo.  Esempio: \\ \texttt{man
bash -t > man\_bash.ps} \\ genera un file postscript
\texttt{man\_bash.ps} che contiene la manpage di bash.

Se lo si vuole ridirigere su un file cominciando a scrivere dalla fine
del file, senza cancellare l'eventuale contenuto del file basta
aggiungere '\texttt{>> file}' in fondo.
Esempio: 
\\ \texttt{for i in *; do echo ``questo e' il file \$i''>>
cippa; done}\\
 aggiunge al file cippa una riga per ogni file contenuto
nella directory corrente scrivendo \texttt{questo e' il file} seguito dal
nome del file.


Per ridirigere lo standard input, oltre al gi\`a citato `$|$',
      esiste anche il simbolo `\texttt{<}', che permette di sostituire la
      tastiera con un file. Per esempio \\ \texttt{sort < file}\\
      stamper\`a le righe contenute nel file \texttt{file} in
      ordine alfabetico.




\section{Limitazioni sulle risorse utilizzate}

Una caratteristica molto utile di un sistema linux \`e la sua
capacit\`a di gestire delle limitazioni per quanto riguarda le risorse
utilizzate dai vari utenti. Queste limitazioni riguardano molti tipi
di risorse, per esempio lo spazio disco utilizzato da ogni utente
(vedi le quote), o utilizzato in totale dagli utenti non privilegiati
(la percentuale di blocchi riservati in un filesystem), ma anche e
soprattutto il numero di processi di propriet\`a di un utente che
girano contemporaneamente, la quantit\`a di memoria occupata et
coetera.

Per capire quanto siano efficaci facciamo un piccolo esempio:
supponiamo che faccia andare, senza aver impostato nessun limite per
gli utenti, un programma tipo questo
\footnote{Se qualcuno lo vuole ho un programma moooolto pi\`u cattivo
di questo...}:

\begin{verbatim}
main(){

while(1)
fork();
}
\end{verbatim}

Il processo comincer\`a a generare un mucchio di figli, e dopo un po`
il sistema diventer\`a inutilizzabile, visto che ogni volta che si
prover\`a ad eseguire un comando si verificher\`a qualcosa simile a questa:

\begin{verbatim}
[messina@sophie seminario$] ps ux
bash: fork: Resource temporarily unavailable
[messina@sophie seminario$] 
\end{verbatim}

Se invece viene impostato un limite massimo al numero di processi che
un utente pu\`o eseguire, il mio programma, dopo un po', non potr\`a
pi\`u ``forkare'', e \textbf{solo io} non potr\`o pi\`u fare
nulla. Per tutti gli altri utenti la macchina sar\`a, al massimo, un
po' lenta.

Un'altra cosa interessante \`e che le limitazioni valgono \textit{per
login}, ovvero se entro via rete o da un'altra console si applicano
nuove restrizioni. \`E quindi necessario limitare anche il numero
massimo di login che un utente pu\`o fare...

Oltre a questo tipo di limitazione, ricordiamo che comunque un processo
pu\`o scrivere solo nell'area di memoria che il kernel assegna lui, in
modo che nessun processo possa interferire con gli altri processi. Si
pu\`o inoltre limitare la quantit\`a di memoria occupata da un processo,
visto che il completo riempimento della memoria pu\`o provocare diversi
effetti sgradevoli...

A questo proposito, in uno dei miei esperimenti, ho fatto partire un
programma che forkava in continuazione e allocava sempre pi\`u memoria,
e non avevo impostato limiti n\'e di processi n\'e di memoria. Il risultato
\`e stato che la macchina dopo poco \`e diventata inutilizzabile, e
senza nemmeno che provassi a fare qualcosa comparivano una serie di:

\texttt{Out of memory for bash}

Non c'\`e stata possibilit\`a di recuperare, anche se in questa
situazione si \`e comunque dimostrata la stabilit\`a del sistema...
I processi infatti giravano regolarmente, molto lentamente, nessun
processo poteva pi\`u forkare, e quindi non potevo lanciare altri
processi, la memoria era completamente occupata, ma il kernel continuava
a funzionare, e quindi, per esempio tramite i \textbf{MAGIC SYSRQ KEY}
\footnote{Se si abilita questa opzione nel kernel gli si possono passare
dei comandi, tra i quali, appunto, quello per sincronizzare i
filesystem, onde non perdere dati, qello per rimontarli tutti RO,
sempre per lo stesso motivo, ed uno anche per uccidere tutti i processi
associati ad una certa console.}
ho potuto sincronizzare i filesystem e resettare con una certa tranquillit\`a...



\section{Comunicazioni tra processi}

I processi possono comunicare tra di loro in diversi modi, e cio\`e:
\begin{itemize}
\item FIFO/PIPE
\item Memoria condivisa
\item Segnali.
\end{itemize}

Una pipe \`e un semplice metodo per far s\`\i \ che due processi
possano passarsi uno stream di dati. Semplicemente un processo scrive
da una parte ed un altro legge ci\`o che il primo scrive. I dati sono
ordinati in modo che ci\`o che \`e scritto per prima viene anche letto
per prima (si tratta, appunto, di una FIFO: first-in-first-out).
Si ha una pipe quando si concatenano da linea di comando pi\`u comandi separati da '$|$'. Ad esempio:

\begin{verbatim}
[messina@poisson public_html $] cat *.html|tr '>' '\012'|grep \
SRC|cut -d '"' -f2
pam-censur.jpg
marchio.gif
lavoriincorso.gif
winslow.gif
email.gif
openlogo-50.jpg
penguin2.gif
Logo.jpg
[messina@poisson public_html $]
\end{verbatim}

Esistono poi dei file speciali, delle fifo, appunto, che si creano con
il comando \texttt{mknod}, e che funzionano come le pipe, ma restano su
disco, in modo che i processi possano collegarsi ad essi semplicemente
tramite il nome.

I segnali sono delle brevi informazioni che i processi si scambiano
durante l'esecuzione, e che possono tornare molto utili in diverse
occasioni, visto che esiste un programma, \texttt{kill}, che permette 
di mandare ad un particolare processo un segnale a scelta. Per sapere
quanti segnali sono disponibili potete dare il comando \texttt{kill
-l}.
\begin{verbatim}
[messina@poisson seminario$] kill -l
 1) SIGHUP	 2) SIGINT	 3) SIGQUIT	 4) SIGILL
 5) SIGTRAP	 6) SIGABRT	 7) SIGBUS	 8) SIGFPE
 9) SIGKILL	10) SIGUSR1	11) SIGSEGV	12) SIGUSR2
13) SIGPIPE	14) SIGALRM	15) SIGTERM	17) SIGCHLD
18) SIGCONT	19) SIGSTOP	20) SIGTSTP	21) SIGTTIN
22) SIGTTOU	23) SIGURG	24) SIGXCPU	25) SIGXFSZ
26) SIGVTALRM	27) SIGPROF	28) SIGWINCH	29) SIGIO
30) SIGPWR	31) SIGSYS	
[messina@poisson seminario$]
\end{verbatim}

Tramite l'opzione '-s' seguita dal nome del segnale e dal PID del
processo si pu\`o mandare quel segnale a quel processo. Se non si ha
lo stesso uid di quello effettivo del processo, o al limite uid=0 (che 
\`e quello dell'utente root) il segnale non ha effetto.

Di seguito un breve elenco del significato dei segnali (cfr \texttt{man 7
signal})

\begin{itemize}

\item SIGHUP

La connessione \`e stata chiusa, o il processo controllante del
terminale \`e morto. Quando un il processo che controlla un terminale
muore, il terminale da lui controllato resta libero. Per prevenire
problemi, visto che i processi suoi figli potrebbero voler accedervi,
viene loro mandato un segnale di SIGHUP, che in genere provoca la morte
del processo, che i processi possono ignorare. Se lo fanno non potranno
pi\'u accedere ad un terminale.

\item SIGINT

Sarebbe il segnale mandato quando l'utente digita la combinazione
corrispondente a INTR, di solito `C-c'

\item SIGQUIT 

Simile al precedente, ma produce anche un core dump e viene da
un'altra combinazione di tasti. (`C-$\backslash$', di solito)

\item SIGILL

In genere significa che il programma \`e corrotto in qualche modo, che
ha tentato di eseguire dei dati, o in caso di stack overflow, visto
che il compilatore dovrebbe accorgersi se il programma far\`a qualcosa
di illegale...

\item SIGABRT

\`E un segnale che il processo manda quando si accorge di qualche
errore, tramite la funzione abort.

\item SIGFPE

Errore aritmetico in generale: overflow, divisione per zero...

\item SIGKILL

Uccide il processo SICURAMENTE.  Non puo' essere ignorato. Di solito
viene usato solo su esplicita richiesta. Se il processo non muore vuol
dire che si \`e di fronte ad un baco del sistema operativo
(segnalarlo). In seguito a questo segnale il processo \`e terminato
immediatamente, a differenza del segnale SIGTERM.

\item SIGSEGV

Riferimento di memoria non valido.

\item SIGPIPE

Se un processo scrive su una PIPE o una FIFO, e il processo che deve
leggervi non parte o smette di leggere inaspettatamente, il processo
scrivente riceve questo segnale.

\item SIGALRM

Allarme di alarm(2)


\item SIGTERM

\`E un segnale che richiede al processo di terminare. A differenza di
SIGKILL pu\`o essere ignorato. \`E il segnale di default del comando
`kill'.


\item SIGUSR1

Primo segnale definito dall'utente

\item SIGUSR2

Secondo segnale definito dall'utente

\item SIGCHLD

Quando un processo viene terminato o bloccato, manda un segnale al
processo padre. In genere viene ignorato.

\item SIGCONT 

Continua se fermato. \`E il risultato del comando \texttt{bg}, quando
      rivolto ad un processo bloccato in background.

\item SIGSTOP

Blocca il processo. Puo' essere ignorato. \`E il segnale che riceve un
      processo in background quando necessita di scrivere sul terminale,
      o quello che mandiamo con la combinazione di tasti `C-z'.

\item SIGTSTP

Stop digitato sul tty

\item SIGTTIN

Input da tty per un processo in background. Quando un processo in
background tenta di leggere dal terminale riceve un segnale
SIGTTIN. Di default il risultato \`e di bloccare il processo.

\item SIGTTOU

Output da tty per un processo in background. Simile al precedente, si
verifica se il processo vuole scrivere sul terminale.
\end{itemize}

Se volete uccidere un processo che non potete chiudere normalmente
(tipico: il Netscape che si pianta o che continua a girare senza che
esistano pi\`u finestre...) potete provare con il comando
\texttt{kill}, ma se questo non ha effetto (SIGTERM pu\`o essere
ignorato!), digitando \texttt{kill -s sigkill} seguito dal PID del
processo sicuramente morir\`a. Ovviamente i processi in stato di
zombie, come gi\`a detto, essendo gi\`a morti sono immuni a questo
comando.  

\section{Ignorare i segnali}

Alcuni segnali, lo abbiamo accennato, possono essere ignorati. La
relativa chiamata \`e: 
\texttt{signal(<segnale>, SIG\_IGN);}

Per esempio il programma:
\begin{verbatim}
#include <signal.h>

main(){

  signal(SIGHUP, SIG_IGN);
  signal(SIGTERM, SIG_IGN);
  signal(SIGSTOP, SIG_IGN);
  signal(SIGKILL, SIG_IGN); /* questo non puo' essere ignorato !*/
  signal(SIGPIPE, SIG_IGN);

  while(1)
    ;
}
\end{verbatim}

ignora molti segnali. Siccome ignora il segnale SIGHUP se chiudo la
shell che lo ha generato invece di morire diventer\`a un nuovo session 
leader e apparir\`a come figlio di init. Se inoltre lancio il comando
\texttt{kill} il processo non morir\`a, ma sar\`a necessario
\texttt{kill -9} \footnote{si pu\`o sostituire il \texttt{-s <segnale>}
con il numero corrispondente come dall'output di \texttt{kill -l}, per
cui `-9' \`e equivalente a `-s sighup'.}

Un altro esempio di programma:

\begin{verbatim}
#include <signal.h>

main(){
  char c;
  signal(SIGHUP, SIG_IGN);

  while(1)
    c=getchar();
}
\end{verbatim}

Questo processo non potr\`a continuare a girare in background perch\'e 
tenta continuamente di leggere da standard input (la tastiera), e quindi
rester\`a in stato di ``stopping''.
Se per\`o chiudiamo la shell che lo ha generato, siccome ignora il
segnale SIGHUP non muore, anche se in futuro non potr\`a mai leggere
da tastiera.

\end{document}

