Un approccio pratico a Unix
Transcript
Un approccio pratico a Unix
sersh Un approccio pratico a Unix Sereno Ternullo 30 Maggio 2005 1 Copyright (c) 2005 Sereno Ternullo. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with the Invariant Sections being Prefazione, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled GNU Free Documentation License. If you would like to get the latex sources of this document, you can write to my email address asking for them: [email protected]. 2 Indice 1 Prefazione 4 2 Cosa è una Shell 2.1 2.2 Interazione col SO . . . . . . . . . Amministrazione di sistema . . . . 2.2.1 /bin/init . . . . . . . . . . . 2.2.2 Script di avvio in System V 2.2.3 Script di avvio in BSD . . . 2.2.4 Eseguibili Unix . . . . . . . 3 Funzionalità di una Shell Posix 3.1 3.2 3.3 3.4 Variabili di ambiente . . . . . . alias . . . . . . . . . . . . . . . Redirezione . . . . . . . . . . . 3.3.1 pipelining . . . . . . . . Strutture di controllo . . . . . . 3.4.1 if ... then ... else ... . 3.4.2 case $var in ... esac . . . 3.4.3 for var in ... do ... done 3.4.4 while ... do ... done . . 5.2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Genesi dei processi . . . . . . . . . . . . . . 5.1.1 fork . . . . . . . . . . . . . . . . . . 5.1.2 waitpid . . . . . . . . . . . . . . . . 5.1.3 exec . . . . . . . . . . . . . . . . . . Segnali . . . . . . . . . . . . . . . . . . . . . 5.2.1 sigaction . . . . . . . . . . . . . . . . 5.2.2 Dierenze fra SIGTERM e SIGKILL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Astrazione delle risorse . . . . . stdin, stdout, stderr . . . . . . Architettura del File System . . 4.3.1 Directory standard . . . 4.3.2 Multiutenza e permessi 5 Implementazione 5.1 . . . . . . . . . . . . . . . 4 Cenni sul File System Unix 4.1 4.2 4.3 . . . . . . 6 GNU Free Documentation License 3 5 5 6 6 6 7 7 8 8 8 9 9 10 10 11 11 12 13 13 14 14 14 15 16 16 16 17 18 21 21 23 26 1 Prefazione I sistemi operativi e la programmazione C rappresentano indubbiamente due tra le mie maggiori passioni; decisi quindi tempo fa di intraprendere uno studio privato di tale disciplina, motivato esclusivamente dalla mia passione. Oltre alla conoscenza che ho potuto attingere dalla sterminata documentazione fornita dalla comunità GNU/Linux, mi sono stati di grandissimo aiuto due opere in particolare, ovvero Sistemi Operativi, disegno e implementazione di Andy Tenenbaum e GaPiL di Simone Piccardi; consiglio a chiunque voglia cimentarsi nella programmazione di sistema di leggere questi mostri sacri della letteratura informatica. sersh è una semplicissima shell che nasce dalla mia volontà di voler vedere applicati nella pratica ed in un lavoro da me svolto alcuni di quei concetti che sono basilari nella programmazione di sistema Unix: gestione dei le, genesi dei processi, interazione col sistema operativo. Per comprendere un sistema Unix bisogna inanzitutto capire cosa è un le, perché sotto Unix tutto è un le, e per tale motivo risulta di vitale importanza la comprensione delle chiamate che il SO ore sui le, e come il lesystem organizzi le risorse del sistema. Inizialmente questa guida nasceva con lo scopo di documentare le principali chiamate di sistema utilizzate all'interno di sersh; in corso d'opera ho trovato utile arricchire tale lavoro con alcuni concetti chiave basilari nella comprensione e nell'uso di un sistema Unix. Per questa ragione ritengo che quanto io abbia scritto possa essere un buon punto di inizio anche per coloro che si avvicinano a Unix per la prima volta. sersh è una sorta di mia personale esercitazione che io rilascio con licenza GNU GPL con lo scopo di poter essere utile a quanti si trovano adesso nel- lo studio dei Sistemi Operativi. Non ho quindi l'intenzione di implementare un'autentica Shell Posix, - sarebbe fuori dal mio scopo -, ma soltanto quello di fornire un punto di partenza per quanti abbiano voglia di capire come certe cose funzionano. Sarò felice di ricevere commenti, suggerimenti o miglioramenti di quanto io ho già svolto. Sereno Ternullo, Catania 14 Maggio 2005 [email protected] 4 2 Cosa è una Shell 2.1 Interazione col SO Shell signica conchiglia, e la conchiglia è ciò che avvolge la perla. Così come per il mollusco, idealmente la Shell è in un sistema Unix quel programma utente che avvolge il kernel, facendo in modo che le richieste dell'utente possano essere soddisfatte dal sistema sottostante. Non bisogna infatti sottovalutare il fatto che un ipotetico SO che fosse composto esclusivamente dal proprio kernel non servirebbe proprio a niente, perché l'utente non avrebbe alcun modo di interfacciarsi con esso. La shell è un normalissimo processo utente con lo scopo di fornire un invito 1 , aspettare che l'utente digiti qualcosa, ed eseguire quanto questi desidera. Potrebbe sembrare alquanto banale, ma cosa si potrebbe fare di un sistema in cui non si potesse visualizzare il contenuto del proprio disco mediante un banalissimo ls 2 ? Possiamo quindi immagginare una shell davvero elementare come un ciclo innito in cui ad una richiesta di input avviene l'esecuzione di una fork, quindi l'esecuzione del comando richiesto mediante exec, e il successivo ritorno al processo padre una volta che il glio è terminato mediante waitpid. while(true) { prendo_una_riga(); pid = fork(); /* Creo un processo identico */ switch(pid) { /* Chi sono ? */ case 0: exec(); break; /* Sono il processo figlio, */ /* eseguo il codice del programma passato */ default: waitpid(); break; /* Sono il processo padre, */ /* quindi mi blocco finché il figlio non termina */ } } • sersh si comporta essenzialmente in questo modo. 1 user@home:$ 2 ls è un programma che si occupa di mostrare il contenuto di una directory 5 2.2 Amministrazione di sistema Una Shell Posix implementa tutta una seria di funzionalità e strutture di controllo che la rendono un utilissimo strumento indispensabile nell'amministrazione di sistema. E' possibile infatti denire degli script di cui la Shell sia l'interprete. Ciascuno degli Unix Shell Script inizia sempre con la seguente intestazione: #! /bin/sh Il primo rigo di ciascuno script serve al kernel del SO per avere indicazione su quale interprete avviare per eseguire lo script. Solitamente su un sistema GNU/Linux , /bin/sh è un link simbolico a /bin/bash, la Bourne Again Shell. Tuttavia, secondo il nome eettivamente specicato per l'interprete si avranno dei comportamenti leggermenti diversi. Se bash verrà avviato per mezzo del nome sh essa seguirà un comportamento rigidamente dettato dalle speciche Posix 3 , altrimenti abiliterà l'uso delle estensioni GNU. Il primo processo utente mandato in esecuzione sul sistema a cui spetta il compito di congurare la macchina non appena questa viene avviata è 2.2.1 /bin/init Una volta avviato init esamina il contenuto di /etc/inittab, le di congurazione in cui sono indicati i comandi da eseguire anché la macchina si porti ad un determinato runlevel. Un runlevel è semplicemente uno stato di esecuzione della macchina che identica le modalità di funzionamento del sistema e i servizi disponibili; in genere esiste sempre uno specicato runlevel che congura la macchina come postazione monoutente 4 , e vi è sempre un certo runlevel che congura la macchina come postazione multiutente inizializzando le interfacce di rete. • Gli eseguibili che si occupano di portare la macchina da un runlevel ad un'altro sono Script Shell. Nel mondo Unix esistono due scuole di pensiero sul modo in cui organizzare gli script di avvio; tradizionalmente si fa riferimento al modo in cui questo è stato fatto nei due grandi Unix storici: Unix System V della AT&T, e il Berkley Software Distribution Unix, detto più brevemente BSD Unix. 2.2.2 Script di avvio in System V Nei sistemi operativi aderenti allo stile System V per ciascun runlevel, init cerca nella directory /etc una sotto directory rcX.d, dove X è il numero che indica il runlevel desiderato. Se la directory cercata esiste, allora init eseguirà automaticamente tutti gli script shell in essa contenuti. 3 Questo viene fatto dal main di bash controllando argv[0], ovvero il nome stesso con cui il programma è stato mandato in esecuzione 4 questo può rendersi utile all'amministratore di sistema in caso di ripristini dovuti a situazioni critiche 6 runlevel=3 # Indica il runlevel su cui vogliamo portarci if [ -d rc${runlevel}.d ]; then for file in rc${runlevel}.d/* do . $file done fi # Esiste una directory chiamata rc3.d ? # ok, allora esegui tutti # gli script in essa contenuti 2.2.3 Script di avvio in BSD Nei sistemi operativi attinenti allo stile BSD l'esecuzione degli script avviene in maniera leggermente meno intuitiva. Tutti gli script di avvio sono contenuti all'interno della directory /etc/rc.d . Per ciascun runlevel init manda in esecuzione un le specico, ad esempio rc.M: esso congura il sistema come postazione multiutente. A sua volta questo script si occuperà di mandare in esecuzione degli ulteriori script, vericandone prima il ag di eseguibilità. if [ -x rc.pcmcia ] ; then . rc.pcmcia start fi # rc.pcmcia è eseguibile ? # Ok, lo mando in esecuzione 2.2.4 Eseguibili Unix Bisogna avere chiaro che sotto Unix un le è considerato eseguibile se la sua maschera dei permessi presenta attivo il ag di eseguibilità; al contrario di quanto avviene in windows, dove ciascun eseguibile deve essere necessariamente un le binario con estensione .exe, sotto Unix i le eseguibili non hanno alcuna estensione che li qualichi come tali. Come per gli Shell Script, sotto Unix anche un le ASCII può essere considerato eseguibile. Per vedere la maschera dei permessi è possibile eseguire il comando ls -l : 5 di un le user@home $ ls -l /etc/rc.d/rc.M -rwxr-xr-x 1 root root 7906 2004-06-20 03:42 /etc/rc.d/rc.M • il primo simbolo - ci indica che è un le normale. • Il le appartiene all'utente root ed al gruppo root. root può leggere, scrivere, ed eseguire il le. rwx corrisponde al valore ottale 7. • gli appartenenti al gruppo root possono leggere ed eseguire il le. r-x corrisponde al valore ottale 5. • il resto del mondo può leggere ed eseguire il le. r-x corrisponde al valore ottale 5. 5 della maschera dei permessi si parlerà in modo più approfondito nel capitolo successivo 7 3 Funzionalità di una Shell Posix 3.1 Variabili di ambiente All'interno di una Shell Posix è possibile denire variabili non tipizzate dette variabili di ambiente. La dichiarazione di una variabile avviene mediante il costrutto: user@home $ variabile=valore E' possibile accedere al contenuto di una variabile anteponendo ad essa il simbolo $. Per fare in modo che una variabile di ambiente dichiarata all'interno di una sessione Shell possa essere visibile anche ai successivi programmi lanciati da rigo di comando, è neccessario esportarla per mezzo del comando export. user@home $ export variabile E' possibile dichiarare ed esportare simultaneamente una variabile per mezzo della sintassi: user@home $ export variabile=valore • in sersh è possibile usare soltanto questo ultimo costrutto. E' possibile visualizzare la lista di tutte le variabile di ambiente per mezzo del comando env Alcune tra le variabili sempre presenti in una sessione Shell sono: ! - PID dell'ultimo processo mandato in esecuzione in background ; ? - Raccoglie il codice di uscita dell'ultimo comando mandato in esecuzione; PWD - Directory di lavoro; OLDPWD - Directory di lavoro precedente; PID - PID della Shell corrente; PPID - PID del processo che ha generato la shell corrente ( il padre ); USER - Nome dell'utente corrente; HOME - Home directory per l'utente corrente; SHELL - Shell di default per l'utente corrente; PATH - Insieme delle directory in cui cercare gli eseguibili; PS1 - Specica per la formattazione dell'invito primario; PS2 - Specica per la formattazione dell'invito secondario. E' possibile denire delle scorciatoie ai comandi più utilizzati per mezzo degli 3.2 alias La dichiarazione di un alias avviene per mezzo del costrutto: user@home $ alias comando_nuovo="comando [arg1] [arg2] ... [argN]" • Gli alias non sono attualmente supportati da sersh Per esempio potrò denire: user@home $ alias ls="ls -l -k" in modo da non dover scrivere ogni volta i ag frequentemente usati per il comando ls. 8 3.3 Redirezione Una Shell Posix permette la redirezione dei le standard di input, output ed error associati ai processi. Tramite un'opportuna sintassi è possibile sostituire i le standard di default specicandone di nuovi. comando < file comando <0 file Indica a comando di usare le come nuovo le di input. comando > file comando 1> file Indica a comando di usare le come nuovo le di output. comando 2> file Indica a comando di usare le come nuovo le di error. • La redirezione dei singoli comandi è supportata da sersh. In una Shell Posix più comandi possono essere assemblati fra loro per mezzo del 3.3.1 pipelining • Il pipelining non è al momento supportato da sersh. L'uso del pipelining permette che lo stdout di un comando sia rediretto verso lo stdin del comando successivo; è possibile fare questo mediante il simbolo |, pipe. Esempio Stampo a video il contenuto della directory corrente. E' possibile scorrere la pagina. user@home $ ls | less less si occupa di formattare a video quanto letto dal proprio stdin. ls stampa sul proprio stdout il contenuto della directory corrente. | fa in modo che lo stdout di ls sia concatenato allo stdin di less. Esempio Visualizzo il rigo esatto in cui inizia il main di sersh.c user@home $ cat sersh.c -n | grep main 70 int main(int argc, char *argv[]) { cat sersh.c -n stampa sul proprio stdout l'intero le sersh.c aggiungendo i numeri di riga. grep main legge stdin cercando le righe che abbiano corrispondenza con la parola main. Se queste righe vengono trovate, vengono allora stampate su stdout. 9 3.4 Strutture di controllo Una Shell Posix mette a disposizione le principali strutture di controllo presenti nella maggior parte dei linguaggi strutturati in modo da permettere la creazione di Shell Script . • Le strutture di controlo non sono attualmente supportate da sersh • Al contrario di quanto accade in C, al valore 0 viene dato valore di verità, mentre a qualsiasi valore diverso da 0 viene dato valore di falsità. 3.4.1 if ... then ... else ... Equivale al costrutto C if. Esempio i=10 if [ $i = 10 ] ; then echo "i vale 10" else echo "i non vale 10" fi E' possibile denire if annidati per mezzo della parola chiave elif, contrazione di else if. i=14 if [ $i = 1 ] then echo "i vale 1"; elif [ $i = 2 ] then echo "i vale 2" else echo "i non vale ne' 1 ne' 2" fi E' possibile denire un costrutto if sull'esito di un comando. Esempio Controlla se nel sistema esiste l'utente letto da tastiera #! /bin/sh echo "Inserisci il nome dell'utente da cercare" read utente if grep $utente /etc/passwd 1> /dev/null 2> /dev/null echo "L'utente $utente esiste nel sistema" exit 0 10 ; then else fi echo "L'utente $utente non esiste nel sistema" exit 1 3.4.2 case $var in ... esac Equivale al costrutto C switch. Esempio Confronta un numero inserito da tastiera con 1 e 10 #! /bin/sh echo "Inserisci un numero" read num case $num in 1) echo "hai inserito 1" ;; 10) echo "hai inserito 10" ;; esac *) echo "Non hai inserito ne' 1 ne' 10" ;; 3.4.3 for var in ... do ... done Eettua dei cicli all'interno del codice delimitato da do .. done facendo in modo che var assuma di volta in volta tutti i valori successivi a in. Non ha un esatto corrispondete C. Esempio #! /bin/sh for citta in Catania Firenze Napoli Milano Genova Messina do echo "$citta e' una citta' italiana" done 11 3.4.4 while ... do ... done Cicla all'interno del codice delimitato da do ... done no a quando l'espressione denita nel while è vera. Equivale al costrutto C while. Esempio #! /bin/sh ciclo=0 while [ $ciclo ] do echo "Vuoi continuare a ciclare ?" read risposta done if [ $risposta = "si" ] ; then ciclo=0 else ciclo=1 fi 12 4 Cenni sul File System Unix 4.1 Astrazione delle risorse File System signica sistema di archiviazione, ed è compito di ciascun sistema operativo astrarre le risorse di un computer in modo da renderle idealmente indipendenti dai propri supporti sici; Unix assolve a questa funzione mediante l'utilizzo di un'univoca gerarchia di directory, seguendo il paradigma secondo cui ogni cosa è un le : su Linux il primo disco rigido IDE è indicato dal le di dispositivo /dev/hda, la prima linea seriale è indicata dal le /dev/ttyS0, il terminale corrente è sempre indicato da /dev/tty etc. Questa astrazione nasce da una semplice constatazione: il funzionamento della stragrande maggioranza dei dispositivi di cui si compone un computer (stampanti, schede audio, schede video, linee seriali ) si basa su due delle più elementari funzioni di I/O : lettura e scrittura. Dal momento che le chiamate di read e write per scrivere e leggere da un le esistono n dalla notte dei tempi, è parso naturale ai padri di Unix associare a ciascun driver di dispositivo dei le speciali, collocati tradizionalmente nella directory /dev ; in modo si ore agli sviluppatori una semplice interfaccia per leggere e scrivere su un dispositivo, prescindendo da qualunque cosa via sotto. Se per esempio vorrò fare un programma che stampi sulla mia stampante parallela 6 ( /dev/lp0 ) ciascuna riga che andrò inserendo da terminale, basterà compilare il seguente programma: #include <stdio.h> int main(int argc, char *argv[]) { FILE * printer; /* Lo userò per la stampante */ char buffer[200]; /* buffer per la lettura */ printer = fopen("/dev/lp0", "r"); /* Apro in lettura la stampante */ while(1) { } fprintf(stdout, "\nInserisci una riga"); fgets(buffer, 200, stdin ); /* fprintf( printer, "%s", buffer ); /* fflush(printer); /* /* Prendo una riga da terminale */ Stampo sulla stampante */ scarico il buffer relativo */ allo stream printer */ } Come è possibile vedere dal codice, è stato possibile accedere alla stampante attraverso un paio di semplicissime istruzioni: le stesse che si usano per i le ordinari. 6 L'esempio può essere applicato anche ad una stampante USB, /dev/usblp0 13 Fra tutti i le presenti su un sistema Unix un ruolo di particolare importanza spetta ai le standard associati a ciascun processo, ovvero 4.2 stdin, stdout, stderr standard input, output, error Ciascun processo eseguito su una macchina Unix usa i le stdin, stdout e stderr rispettivamente per le operazioni di input (normalmente la tastiera), output (normalmente il monitor di terminale) e noticazioni di errore (anche in questo caso il monitor di terminale). Il più grande pregio oerto dai le standard è la possibilità di essere rediretti su altri le : molto spesso problemi apparentemente complessi possono essere risolti eettuando una semplice redirezione dei ussi standard. • Come si può vedere dalle prime righe di sersh.c , la redirezione è parecchio sfruttata da sersh Per questa ragione scrivere scanf(%s, string ) è del tutto equivalente allo scrivere fscanf(stdin , %s, string ), perché per default stdin è lo stream associato al le di input. Lo stesso vale per stdout e stderr. Tutto è un le. Una Shell Posix sfrutta pesantemente questa possibilità facendo in modo che più programmi possano essere assemblati per creare un comando che di per sè non esisterebbe. 4.3 Architettura del File System 4.3.1 Directory standard Tutto quanto ha origine dalla radice, indicata dal simbolo / e chiamata root. Nella maggior parte dei casi la root risiede sul File System della partizione su cui si è installato il sistema operativo. 7 All'interno della radice trovano posto diverse directory di primaria importanza, tra cui: /mnt /lib /boot /tmp /dev /etc /bin /sbin /home /root /proc 7a # # # # # # # # # # # Directory per il mounting dei dispositivi removibili Librerie condivise kernel e file di boot sotto Linux File temporanei File di dispositivo File di configurazione del sistema Programmi di uso generale per tutti gli utenti Programmi riservati all'utente root Directory per la home degli utenti sotto Linux Directory home per l'utente root sotto Linux File System virtuale, interfaccia col kernel sotto Linux meno che non sia stato eseguito un chroot 14 4.3.2 Multiutenza e permessi Il requisito che da sempre appartiene a Unix è quello della multiutenza 8 : a più persone deve essere concesso di lavorare su un singolo computer senza interferire con il lavoro degli altri. L'adozione di questo requisito necessita l'implementazione all'interno del SO di una politica che permetta di determinare chi possa accedere o meno a ciascun le, in modo da garantire che nessun utente, maliziosamente o meno, possa interferire sul lavoro degli altri. In Unix ciascun le viene dotato di una maschera ottale in cui si specicano i diritti in lettura, scrittura ed esecuzione per il possessore del le (owner), il gruppo di lavoro a cui appartiene il le ed il resto del mondo. La maschera ottale dei permessi di un le può essere ricavata facilmente per mezzo del seguente schema: Possessore _____________ 4 2 1 | | | r w x | Cifra Gruppo _____________ 4 2 1 | | | r w x | Cifra Resto del mondo _____________ 4 2 1 | | | r w x | Cifra Ciascuna delle 3 cifre è uguale alla somma dei valori corrispondenti a r, w , x. Avremo quindi: r--w--x = = = 4 + 0 + 0 = 0 + 2 + 0 = 0 + 0 + 1 = 4 2 1 rwr-x = = 4 + 2 + 0 = 4 + 0 + 1 = 6 5 rwx = 4 + 2 + 1 = 7 E quindi: -rwxr-xr-x -r-xr-xr-x -rw-r--r--rw-------rw-r----- corrisponde corrisponde corrisponde corrisponde corrisponde a a a a a 755 555 644 600 640 e così via. 8 in PDP eetti questo non era vero per i primi Unix implementati sui mitici computer della serie 15 5 Implementazione 5.1 Genesi dei processi Le principale chiamate di sistema Unix che competono alla genesi e gestione dei processi sono: fork exec 5.1.1 fork #include <sys/types.h> #include <unistd.h> pid_t fork(void); si occupa di creare un processo glio che dierisce dal padre solo nel suo Proe PPID. Il processo glio continua l'esecuzione del codice dall'istruzione successiva alla fork, ed evolve quindi in modo del tutto indipendente dal padre che lo ha generato. fork ritorna due valori dierenti: nel glio ritorna sempre il valore 0; nel padre ritorna sempre il pid del processo glio 9 . Esaminare i valori di ritorno risulta utile subito dopo l'esecuzione di una fork per determinare l'identità del processo corrente. cess IDentier e Parent Process IDentier, rispettivamente PID pid = fork(); /* Mi sono sdoppiato, ma adesso chi sono ? */ if (pid == 0) { /* Sono il processo figlio */ esegui_codice_processo_figlio(); exit(0); } else { /* Sono il processo padre */ esegui_codice_processo_padre(); exit(0); } fork è l'unica chiamata di sistema Unix che permette la creazione di un nuovo processo ! 9e quindi un valore sempre diverso da zero 16 Un caso in cui risulta indispensabile l'uso della chiamata fork è per esempio quello di un generico Web Server. Un Web Server è un processo daemon in perenne ascolto sulla porta TCP 80 il cui compito è quello di rispondere alle interrogazioni HTTP ricevute fornendo ai client remoti10 le dovute risposte11 . Un Web Server quindi inizia la propria esecuzione ponendosi in ascolto e bloccandosi sulla porta 80 in attesa di connessioni. Non appena viene eseguita una nuova connessione, il processo si clona mediante una chiamata a fork: in questo modo il processo glio si occuperà di servire il client remoto inviandogli quanto richiesto, mentre il processo padre si rimetterà subito in ascolto sulla porta 80 in attesa di servire nuove connessioni. while(true) { ascolto_sulla_porta_e_mi_blocco(); pid = fork(); } /* Ho ricevuto una connessione, quindi mi clono */ if (!pid) { /* Se sono il figlio servo il client e termino */ servi_il_client_remoto(); exit(0); } else continue; /* Se sono il padre */ /* mi rimetto subito in attesa di altre connessioni */ Ciascun processo al termine della propria esecuzione torna al padre un numero intero detto codice di uscita, a cui si attribuisce l'esito dell'esecuzione e i motivi per cui è potuto terminare. 0 indica successo nell'esecuzione, un qualsiasi valore diverso da zero indica un fallimento. Nel momento in cui un processo termina, il kernel manda al relativo processo padre un segnale di SIGCHLD per noticare l'avvenuta morta del glio. Se un processo termina la propria esecuzione senza che il genitore abbia raccolto il suo codice di uscita, si dice che esso rimane un processo zombie. Un processo zombie è un processo terminato di cui però il kernel non rilascia le risorse ( address space, le descriptors ... ) in attesa che il padre ne raccolga il codice di uscita. La chiamata di sistema che il processo padre deve invocare alla morte del glio per fare in modo che le risorse del glio terminato siano disallocate è 5.1.2 waitpid #include <sys/types.h> #include <sys/wait.h> pid_t waitpid(pid_t pid, int *status, int options); Raccoglie in *status il codice di uscita del processo glio specicato da pid. Se pid viene posto uguale a WAIT_ANY, la funzione avrà eetto su qualsiasi dei processi gli. 10 Browser Internet 11 Pagine HTML, immagini JPEG, audio MP3 ... 17 options può assumere uno dei seguenti valori: • 0 waitpid si blocca in attesa della terminazione di un processo glio • WNHOHANG waitpid non si blocca se nessun glio è terminato La chiamata a waitpid con options posto uguale a 0 può essere usata in una rudimentale forma di sincronizzazione fra processi diversi: padre > glio > padre. • Questo è il modo in cui si comporta sersh per i processi mandati in esecuzioni in foreground Se altrimenti si vorrà che padre e glio evolvano parallelamente, 12 sarà necessario che il padre si prenda carico di richiamare eplicitamente waitpid installando un gestore per il segnale SIGCHLD, evitando così la creazione di processi zombie. E se il padre termina prima del glio ? In tal caso il processo rimasto orfano verrà adottato da init, e sarà successivamente lo stesso init a prendersi carico di richiamare waitpid alla ricezione di SIGCHLD. Un nuovo processo generato per mezzo della funzione fork può eseguire il codice di un'altro programma rimpiazzando il proprio codice residente in memoria per mezzo della chiamata 13 5.1.3 exec Posix mette a disposizione delle funzioni di libreria che rendono più semplice e essibile l'uso della chiamata exec ed i cui prototipi sono: #include <unistd.h> extern char **environ; int int int int int execl(const char *path, const char *arg, ...); execlp(const char *file, const char *arg, ...); execle(const char *path, const char *arg , ..., char * const envp[]); execv(const char *path, char *const argv[]); execvp(const char *file, char *const argv[]); Il nuovo programma da mandare in esecuzione di norma deve essere fornito con il suo percorso assoluto ( /bin/ls per esempio ) nelle stringhe puntate da path o le. Fanno eccezione execlp e execvp : se il programma non viene indicato nel suo percorso assoluto, allora sarà automaticamente cercato mediante l'ausilio della variabile di ambiente PATH specicata, se esiste, all'interno di environ. 12 si ricorda che si tratta di un parallelismo simulato, e non reale 13 In verità sotto Linux la chiamata di sistema si chiama execve, ma per inveterata tradizione Unix continuerò anche qui a chiamarla exec 18 Gli argomenti da passare al nuovo programma possono essere specicati generalmente in due modi: ponendo in successione i puntatori a ciascuna stringa interessata ( execl, execlp ) , oppure confezionando ciascun argomento in un array di stringhe argv terminato dal puntatore NULL. execle si comporta sostianzialemente come execl, ma richiede che l'ultimo argomento sia un vettore di stringhe da passare al programma come nuovo ambiente. Bisogna prestare attenzione al primo argomento passato a qualsiasi delle funzioni exec: argv[0] rappresenta sempre il nome stesso del programma da eseguire, quindi qualsiasi programma si mandi in esecuzione ci si deve curare che almeno il primo argomento esista e che abbia lo stesso nome del programma specicato in path o le ! • La funzione utilizzata da sersh è execvp. Esempio sull'uso di execvp. Manda in esecuzione il comando /bin/ls ed esce. #include <stdio.h> #include <unistd.h> main(int argc, char *argv[]) { char char *ls = "/bin/ls"; *arg[] = { ls , (char *) NULL execvp(ls, arg ); } 19 }; Esempio sull'uso di fork, exec, waitpid. Aspetta che l'utente inserisca un comando14 e lo manda in esecuzione. Questa è già una rudimentalissima Shell ! #include <stdio.h> #include <sys/types.h> #include <unistd.h> #define BUFFER_SIZE 50 extern char ** environ; main(int argc, char *argv[]) { char buffer[BUFFER_SIZE]; char *arg[] = { buffer, (char *) NULL }; pid_t pid; while(1) { printf("\n$ "); fscanf(stdin, "%s", buffer ); pid = fork(); if (!pid) { int status; execvp(buffer, arg); } } } 14 senza } fprintf(stderr, "\nComando non valido !"); exit(1); else { int exitStatus; waitpid(pid,&exitStatus,0); fprintf(stdout, "\nIl processo precedente ") ; fprintf(stdout, "è terminato con codice %d", exitStatus ); alcun argomento ! 20 5.2 Segnali Come precedentemente accennato, se non si vuole che il padre si sincronizzi sulla morte del glio, sarà necessario che questi richiami esplicitamente waitpid per mezzo di un'apposità routine alla ricezione del segnale SIGCHLD . Questo è possibile per mezzo della chiamata 5.2.1 sigaction #include <signal.h> int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact); sigaction nstalla l'azione specicata dalla struct sigaction act alla ricezione del segnale specicato da signum. Se oldact non è NULL vi restituisce il comportamento adottato n'ora. struct sigaction { void (*sa_handler)(int); void (*sa_sigaction)(int, siginfo_t *, void *); sigset_t sa_mask; int sa_flags; void (*sa_restorer) (void); } Tralasciando gli aspetti più complessi sull'uso di sigaction e della relativa struttura dati, è necessario sapere che: • sa_handler è il puntatore ad una funzione void la cui esecuzione avviene sincronicamente alla ricezione del segnale specicato. • sa_mask è la maschera dei segnali che devono essere bloccati durante la ricezione del segnale specicato. • sa_ags specica particolari comportamenti da adottare alla ricezione del segnale specicato. 21 Esempio sull'uso di sigaction. Il programma installa l'azione per la ricezione di SIGTERM e si blocca per sempre in attesa di ricevere segnali. Ogni volta che riceve un segnale di SIGTERM stampa un messaggio a video. #include #include #include #include <stdio.h> <sys/types.h> <unistd.h> <signal.h> void handler(int a) { printf("\nHo ricevuto un SIGTERM!\n"); } int main(int argc, char *argv[]) { struct sigaction action; action.sa_handler = handler; sigemptyset(&action.sa_mask); /* Non blocco alcun segnale oltre signum */ action.sa_flags = 0; /* Non specifico alcuna azione particolare */ sigaction(SIGTERM, &action, NULL ); /* Installo l'azione */ while(1) pause(); /* Mi blocco e aspetto per sempre l'arrivo di SIGTERM */ } Dopo aver compilato il programma per mezzo di un semplicissimo gcc esempio_signal.c -o sig mandate in esecuzione il programma in background : user@home $ ./sig & [1] 3862 3862 è il PID del processo appena mandato in esecuzione. La shell mantiene il PID dell'ultimo processo mandato in esecuzione in background all'interno della variabile di ambiente ! Adesso possiamo inviare SIGTERM al processo per mezzo del comando user@home $ kill $! che equivale esattamente allo scrivere user@home $ kill -SIGTERM 3862 ottenendo Ho ricevuto un SIGTERM! Se non specicato diversamente, il comando kill manda il segnale SIGTERM ! Per terminare il processo sarà necessario inviargli un SIGKILL per mezzo di user@home $ kill -SIGKILL $! che equivale esattamente allo scrivere, 22 user@home $ kill -SIGKILL 3862 che equivale ancora allo scrivere user@home $ kill -9 3862 In questo ultimo caso ho specicato SIGKILL per mezzo del suo valore numerico Per avere la lista delle associazioni segnale-valore date il comando: user@home $ kill -l 5.2.2 Dierenze fra SIGTERM e SIGKILL Come si è potuto vedere dall'esempio precedente, ci è stato possibile intercettare SIGTERM per mezzo di sigaction e farne ciò che ne volevamo, ovvero mostrare una semplicissima frase sullo schermo ogni qual volta fosse arrivato. Questo ci è servito come piccolo esempio, ma in verità sotto Unix la ricezione di ciascun segnale è associata ad un suo preciso signicato. Normalmente SIGTERM viene inviato ad un processo quando si vuole che questo termini immediatamente ma in modo pulito. Mettiamo il caso di avere un programma che tenga aperti contemporaneamente una decina di le; supponiamo quindi di aver appena avviato la procedura di spegnimento per mezzo di root@home $ shutdown -h now Sarà compito di init noticare a tutti i processi in esecuzione sulla macchina il prossimo spegnimento; questo verrà fatto invitando tutti i processi a terminare il proprio lavoro nel modo più opportuno mediante l'invio di SIGTERM. Quindi è lecito pensare che il processo con i dieci le aperti avrà una routine per la ricezione di SIGTERM tale da chiudere tutti i le precedentemente aperti e richiamare automaticamente exit per terminare. Sottolineo che SIGTERM può essere intercettato, bloccato o completamente ignorato, quindi non è detto che ciascun processo che lo abbia ricevuto sia automaticamente terminato. init è consapevole di questa possibilità, e quindi, passato un certo tempo dall'invio di SIGTERM, provvederà a mandare a tutti i processi rimasti ancora attivi il segnale SIGKILL. SIGKILL a dierenza del precedente non può essere intercettato, né bloccato, né ignorato, causando per default la terminazione brutale di chi lo riceve. Dopo l'invio di SIGKILL init potrà avere la certezza che nessun altro processo utente sia rimasto attivo sulla macchina, quindi potrà ricorrere all'invocazione di sync per scaricare i buer sui dischi e arrestare denitivamente la macchina. SIGTERM è un invito a nire ciò che si stava facendo. SIGKILL è la terminazione senza appello di chi lo riceve. 23 #include #include #include #include #include <stdio.h> <sys/types.h> <unistd.h> <signal.h> <sys/wait.h> #define BUFFER_SIZE 50 extern char ** environ; void catchChild(int a) { /* Funzione da eseguire alla ricezione SIGCHLD */ pid_t pid; do { int status; pid = waitpid(WAIT_ANY, &status, WNOHANG ); if (pid > 0) { fprintf(stderr, "\nE' terminato figlio %d ", (int) pid fprintf(stderr, "con exit code %d", status ); } } while (pid > 0); ); } main(int argc, char *argv[]) { char buffer[BUFFER_SIZE]; char *arg[] = { buffer, (char *) NULL }; pid_t pid; struct sigaction action; action.sa_handler = catchChild; /* Inizzializzo struttura action */ sigemptyset(&action.sa_mask); action.sa_flags = 0; sigaction(SIGCHLD, &action, NULL); /* Installo azione ricezione SIGCHLD */ while(1) { printf("\n$ "); fscanf(stdin, "%s", buffer ); pid = fork(); if (!pid) { int status; fprintf(stderr, "\nIl mio pid e' %d\n", getpid() ); execvp(buffer, arg); 24 } } } fprintf(stderr, "\nComando non valido !"); exit(1); Come si può vedere dal codice, all'interno della funzione catchChild la chiamata a waitpid è eseguita in un ciclo while; è necessario adottare questo costrutto per via del modo stesso in cui sono implementati i segnali. Sotto Unix infatti i segnali non sono cumulabili ; se già un segnale risulta pendente 15 , l'invio di un'ulteriore segnale della stessa natura passerà come inosservato ; esiste quindi il rischio che l'invio repentino di numerosi segnali dello stesso tipo possa essere visto come l'invio di un unico segnale. Nel caso dell'esempio precedente potrebbe quindi accadere che un ulteriore glio termini proprio mentre è in esecuzione catchChild ; l'ulteriore segnale SIGCHLD verrebbe bloccato e quindi, nel caso in cui si vericasse la morte di un glio proprio mentre in esecuzione catchChild, questo verrebbe completamente ignorato dal padre, condannando arbitrariamente un glio a rimanere zombie. La soluzione più semplice a tale problema è quella di richiamare waitpid all'interno di un ciclo while specicando l'opzione WNOHANG. In questo modo waitpid verrà mandata in esecuzione senza bloccarsi nché vi sarà un qualsiasi processo zombie da terminare. Non appena il pid restituito sarà minore di zero, vorrà dire che non vi saranno ulteriori zombie e sarà quindi possibile uscire dal ciclo. 15 il segnale è stato inviato ma non ancora noticato al processo interessato 25 6 GNU Free Documentation License Version 1.2, November 2002 c 2000,2001,2002 Free Software Foundation, Inc. Copyright 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The purpose of this License is to make a manual, textbook, or other functional and useful document free in the sense of freedom: to assure everyone the eective freedom to copy and redistribute it, with or without modifying it, either commercially or noncommercially. Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being considered responsible for modications made by others. This License is a kind of copyleft, which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software. We have designed this License in order to use it for manuals for free software, because free software needs free documentation: a free program should come with manuals providing the same freedoms that the software does. But this License is not limited to software manuals; it can be used for any textual work, regardless of subject matter or whether it is published as a printed book. We recommend this License principally for works whose purpose is instruction or reference. 1. APPLICABILITY AND DEFINITIONS This License applies to any manual or other work, in any medium, that contains a notice placed by the copyright holder saying it can be distributed under the terms of this License. Such a notice grants a world-wide, royalty-free license, unlimited in duration, to use that work under the conditions stated herein. The Document, below, refers to any such manual or work. Any member of the public is a licensee, and is addressed as you. You accept the license if you copy, modify or distribute the work in a way requiring permission under copyright law. A Modied Version of the Document means any work containing the Document or a portion of it, either copied verbatim, or with modications and/or translated into another language. A Secondary Section is a named appendix or a front-matter section of the Document that deals exclusively with the relationship of the publishers or authors of the Document to the Document's overall subject (or to related matters) and contains nothing that could fall directly within that overall subject. (Thus, if the Document is in part a textbook of mathematics, a Secondary Section may not explain any mathematics.) The relationship could be a matter of historical connection with the subject or with related matters, or of legal, commercial, philosophical, ethical or political position regarding them. 26 The Invariant Sections are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License. If a section does not t the above denition of Secondary then it is not allowed to be designated as Invariant. The Document may contain zero Invariant Sections. If the Document does not identify any Invariant Sections then there are none. The Cover Texts are certain short passages of text that are listed, as FrontCover Texts or Back-Cover Texts, in the notice that says that the Document is released under this License. A Front-Cover Text may be at most 5 words, and a Back-Cover Text may be at most 25 words. A Transparent copy of the Document means a machine-readable copy, represented in a format whose specication is available to the general public, that is suitable for revising the document straightforwardly with generic text editors or (for images composed of pixels) generic paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent le format whose markup, or absence of markup, has been arranged to thwart or discourage subsequent modication by readers is not Transparent. An image format is not Transparent if used for any substantial amount of text. A copy that is not Transparent is called Opaque. Examples of suitable formats for Transparent copies include plain ASCII without markup, Texinfo input format, LaTeX input format, SGML or XML using a publicly available DTD, and standard-conforming simple HTML, PostScript or PDF designed for human modication. Examples of transparent image formats include PNG, XCF and JPG. Opaque formats include proprietary formats that can be read and edited only by proprietary word processors, SGML or XML for which the DTD and/or processing tools are not generally available, and the machine-generated HTML, PostScript or PDF produced by some word processors for output purposes only. The Title Page means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For works in formats which do not have any title page as such, Title Page means the text near the most prominent appearance of the work's title, preceding the beginning of the body of the text. A section Entitled XYZ means a named subunit of the Document whose title either is precisely XYZ or contains XYZ in parentheses following text that translates XYZ in another language. (Here XYZ stands for a specic section name mentioned below, such as Acknowledgements, Dedications, Endorsements, or History.) To Preserve the Title of such a section when you modify the Document means that it remains a section Entitled XYZ according to this denition. The Document may include Warranty Disclaimers next to the notice which states that this License applies to the Document. These Warranty Disclaimers are considered to be included by reference in this License, but only as regards disclaiming warranties: any other implication that these Warranty Disclaimers may have is void and has no eect on the meaning of this License. 2. VERBATIM COPYING 27 You may copy and distribute the Document in any medium, either commercially or noncommercially, provided that this License, the copyright notices, and the license notice saying this License applies to the Document are reproduced in all copies, and that you add no other conditions whatsoever to those of this License. You may not use technical measures to obstruct or control the reading or further copying of the copies you make or distribute. However, you may accept compensation in exchange for copies. If you distribute a large enough number of copies you must also follow the conditions in section 3. You may also lend copies, under the same conditions stated above, and you may publicly display copies. 3. COPYING IN QUANTITY If you publish printed copies (or copies in media that commonly have printed covers) of the Document, numbering more than 100, and the Document's license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover. Both covers must also clearly and legibly identify you as the publisher of these copies. The front cover must present the full title with all words of the title equally prominent and visible. You may add other material on the covers in addition. Copying with changes limited to the covers, as long as they preserve the title of the Document and satisfy these conditions, can be treated as verbatim copying in other respects. If the required texts for either cover are too voluminous to t legibly, you should put the rst ones listed (as many as t reasonably) on the actual cover, and continue the rest onto adjacent pages. If you publish or distribute Opaque copies of the Document numbering more than 100, you must either include a machine-readable Transparent copy along with each Opaque copy, or state in or with each Opaque copy a computernetwork location from which the general network-using public has access to download using public-standard network protocols a complete Transparent copy of the Document, free of added material. If you use the latter option, you must take reasonably prudent steps, when you begin distribution of Opaque copies in quantity, to ensure that this Transparent copy will remain thus accessible at the stated location until at least one year after the last time you distribute an Opaque copy (directly or through your agents or retailers) of that edition to the public. It is requested, but not required, that you contact the authors of the Document well before redistributing any large number of copies, to give them a chance to provide you with an updated version of the Document. 4. MODIFICATIONS You may copy and distribute a Modied Version of the Document under the conditions of sections 2 and 3 above, provided that you release the Modied Version under precisely this License, with the Modied Version lling the role of the Document, thus licensing distribution and modication of the Modied Version to whoever possesses a copy of it. In addition, you must do these things in the Modied Version: A. Use in the Title Page (and on the covers, if any) a title distinct from that of the Document, and from those of previous versions (which should, if 28 there were any, be listed in the History section of the Document). You may use the same title as a previous version if the original publisher of that version gives permission. B. List on the Title Page, as authors, one or more persons or entities responsible for authorship of the modications in the Modied Version, together with at least ve of the principal authors of the Document (all of its principal authors, if it has fewer than ve), unless they release you from this requirement. C. State on the Title page the name of the publisher of the Modied Version, as the publisher. D. Preserve all the copyright notices of the Document. E. Add an appropriate copyright notice for your modications adjacent to the other copyright notices. F. Include, immediately after the copyright notices, a license notice giving the public permission to use the Modied Version under the terms of this License, in the form shown in the Addendum below. G. Preserve in that license notice the full lists of Invariant Sections and required Cover Texts given in the Document's license notice. H. Include an unaltered copy of this License. I. Preserve the section Entitled History, Preserve its Title, and add to it an item stating at least the title, year, new authors, and publisher of the Modied Version as given on the Title Page. If there is no section Entitled History in the Document, create one stating the title, year, authors, and publisher of the Document as given on its Title Page, then add an item describing the Modied Version as stated in the previous sentence. J. Preserve the network location, if any, given in the Document for public access to a Transparent copy of the Document, and likewise the network locations given in the Document for previous versions it was based on. These may be placed in the History section. You may omit a network location for a work that was published at least four years before the Document itself, or if the original publisher of the version it refers to gives permission. K. For any section Entitled Acknowledgements or Dedications, Preserve the Title of the section, and preserve in the section all the substance and tone of each of the contributor acknowledgements and/or dedications given therein. L. Preserve all the Invariant Sections of the Document, unaltered in their text and in their titles. Section numbers or the equivalent are not considered part of the section titles. M. Delete any section Entitled Endorsements. Such a section may not be included in the Modied Version. 29 N. Do not retitle any existing section to be Entitled Endorsements or to conict in title with any Invariant Section. O. Preserve any Warranty Disclaimers. If the Modied Version includes new front-matter sections or appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their titles to the list of Invariant Sections in the Modied Version's license notice. These titles must be distinct from any other section titles. You may add a section Entitled Endorsements, provided it contains nothing but endorsements of your Modied Version by various partiesfor example, statements of peer review or that the text has been approved by an organization as the authoritative denition of a standard. You may add a passage of up to ve words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end of the list of Cover Texts in the Modied Version. Only one passage of Front-Cover Text and one of Back-Cover Text may be added by (or through arrangements made by) any one entity. If the Document already includes a cover text for the same cover, previously added by you or by arrangement made by the same entity you are acting on behalf of, you may not add another; but you may replace the old one, on explicit permission from the previous publisher that added the old one. The author(s) and publisher(s) of the Document do not by this License give permission to use their names for publicity for or to assert or imply endorsement of any Modied Version. 5. COMBINING DOCUMENTS You may combine the Document with other documents released under this License, under the terms dened in section 4 above for modied versions, provided that you include in the combination all of the Invariant Sections of all of the original documents, unmodied, and list them all as Invariant Sections of your combined work in its license notice, and that you preserve all their Warranty Disclaimers. The combined work need only contain one copy of this License, and multiple identical Invariant Sections may be replaced with a single copy. If there are multiple Invariant Sections with the same name but dierent contents, make the title of each such section unique by adding at the end of it, in parentheses, the name of the original author or publisher of that section if known, or else a unique number. Make the same adjustment to the section titles in the list of Invariant Sections in the license notice of the combined work. In the combination, you must combine any sections Entitled History in the various original documents, forming one section Entitled History; likewise combine any sections Entitled Acknowledgements, and any sections Entitled Dedications. You must delete all sections Entitled Endorsements. 6. COLLECTIONS OF DOCUMENTS You may make a collection consisting of the Document and other documents released under this License, and replace the individual copies of this License in 30 the various documents with a single copy that is included in the collection, provided that you follow the rules of this License for verbatim copying of each of the documents in all other respects. You may extract a single document from such a collection, and distribute it individually under this License, provided you insert a copy of this License into the extracted document, and follow this License in all other respects regarding verbatim copying of that document. 7. AGGREGATION WITH INDEPENDENT WORKS A compilation of the Document or its derivatives with other separate and independent documents or works, in or on a volume of a storage or distribution medium, is called an aggregate if the copyright resulting from the compilation is not used to limit the legal rights of the compilation's users beyond what the individual works permit. When the Document is included in an aggregate, this License does not apply to the other works in the aggregate which are not themselves derivative works of the Document. If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one half of the entire aggregate, the Document's Cover Texts may be placed on covers that bracket the Document within the aggregate, or the electronic equivalent of covers if the Document is in electronic form. Otherwise they must appear on printed covers that bracket the whole aggregate. 8. TRANSLATION Translation is considered a kind of modication, so you may distribute translations of the Document under the terms of section 4. Replacing Invariant Sections with translations requires special permission from their copyright holders, but you may include translations of some or all Invariant Sections in addition to the original versions of these Invariant Sections. You may include a translation of this License, and all the license notices in the Document, and any Warranty Disclaimers, provided that you also include the original English version of this License and the original versions of those notices and disclaimers. In case of a disagreement between the translation and the original version of this License or a notice or disclaimer, the original version will prevail. If a section in the Document is Entitled Acknowledgements, Dedications, or History, the requirement (section 4) to Preserve its Title (section 1) will typically require changing the actual title. 9. TERMINATION You may not copy, modify, sublicense, or distribute the Document except as expressly provided for under this License. Any other attempt to copy, modify, sublicense or distribute the Document is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 10. FUTURE REVISIONS OF THIS LICENSE 31 The Free Software Foundation may publish new, revised versions of the GNU Free Documentation License from time to time. Such new versions will be similar in spirit to the present version, but may dier in detail to address new problems or concerns. See http://www.gnu.org/copyleft/. Each version of the License is given a distinguishing version number. If the Document species that a particular numbered version of this License or any later version applies to it, you have the option of following the terms and conditions either of that specied version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the Document does not specify a version number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation. ADDENDUM: How to use this License for your documents To use this License in a document you have written, include a copy of the License in the document and put the following copyright and license notices just after the title page: c YEAR YOUR NAME. Permission is granted to copy, Copyright distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled GNU Free Documentation License. If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, replace the with...Texts. line with this: with the Invariant Sections being LIST THEIR TITLES, with the Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST. If you have Invariant Sections without Cover Texts, or some other combination of the three, merge those two alternatives to suit the situation. If your document contains nontrivial examples of program code, we recommend releasing these examples in parallel under your choice of free software license, such as the GNU General Public License, to permit their use in free software. 32