Quando leggete un disco fisso su Unix vedete un albero di nomi di file e directory. Normalmente non avrete bisogno di andare oltre, ma può essere utile avere maggiori dettagli se vi capita un crash del disco e dovete cercare di salvare dei file. Sfortunatamente non c'è un buon modo per descrivere l'organizzazione del disco dal livello dei file in giù, quindi dovrò partire dall'hardware e risalire.
La superficie del vostro disco, dove vengono immagazzinati i dati, si divide in una sorta di bersaglio per il tiro a freccette: in tracce circolari che sono poi `affettate' in settori. Dal momento che le tracce vicino al bordo esterno hanno area maggiore di quelle vicino al centro, le tracce esterne hanno più settori rispetto a quelle interne. Ogni settore (o blocco del disco) ha la stessa dimensione, che sui moderni Unix è generalmente pari a 1K binario (1024 parole da 8 bit). Ogni blocco è individuato da un indirizzo univoco, il numero di blocco del disco.
Unix divide il disco in partizioni del disco. Ogni partizione è formata da una serie continua di blocchi che vengono usati separatamente da quelli delle altre partizioni, come file system oppure come spazio swap. La partizione con numero più basso viene spesso trattata in modo speciale, come partizione di avvio dove si può mettere un kernel da far partire.
Ogni partizione è alternativamente uno spazio swap, usato per implementare memoria virtuale, oppure un file system, usato per contenere i file. Le partizioni swap sono trattate proprio come una sequenza lineare di blocchi. I file system, invece, hanno bisogno di un modo per associare i nomi dei file alle sequenze di blocchi disco. Dal momento che la dimensione dei file aumenta, diminuisce, si modifica nel tempo, i blocchi dati di un file non saranno una sequenza lineare ma potranno essere disseminati su tutta la sua partizione (dipende da dove il sistema operativo riesce a trovare un blocco libero quando gliene serve uno).
All'interno di ciascun file system la corrispondenza tra i nomi e i blocchi viene assicurata da una struttura chiamata i-node. C'è un gruppo di questi elementi vicino al ``fondo'' (i blocchi a numerazione più bassa) di ciascun file system (quelli più bassi in assoluto sono usati a fini di manutenzione e di etichettatura, non ne parleremo qui). Ogni i-node individua un file. I blocchi dati dei file si trovano sotto gli i-node.
Ciascun i-node contiene una lista dei numeri di blocco disco relativi al file che individua. (Questa è una mezza verità, corretta solo per i file piccoli, ma il resto dei dettagli non è importante qui.) Notate che l'i-node non contiene il nome del file.
I nomi dei file si trovano nelle strutture delle directory. Una struttura della directory associa i nomi ai numeri i-node. Ecco perché, su Unix, un file può avere più nomi reali (o hard link); sono soltanto diverse voci di directory che puntano allo stesso i-node.
Nel caso più semplice, tutto il vostro file system Unix si trova su di una sola partizione disco. Anche se questa situazione si ritrova in qualche piccolo sistema Unix personale, è inusuale. Più generalmente esso è suddiviso tra più partizioni disco, magari su diversi dischi fisici. Così, per esempio, il vostro sistema può avere una piccola partizione dove alloggia il kernel, una un po' più grande dove si trovano i programmi di utilità del SO e una molto più grande dove ci sono le directory personali degli utenti.
La sola partizione alla quale avrete accesso subito dopo l'avvio del sistema è la partizione root, che è (quasi sempre) quella dalla quale avete fatto il boot. Essa contiene la root directory del file system, il nodo superiore dal quale dipende tutto il resto.
Le altre partizioni del sistema devono collegarsi a questa root affinché tutto il vostro file system multipartizione sia accessibile. Circa a metà del processo di avvio, il vostro Unix renderà accessibili queste partizioni non root. Dovrà montare ciascuna di esse su una directory della partizione root.
Per esempio, se avete una directory chiamata `/usr', si tratta probabilmente di un mount point per una partizione che contiene molti programmi che fanno parte della distribuzione standard del vostro Unix ma che non sono necessari durante l'avvio iniziale.
Ora possiamo guardare al file system dall'alto al basso. Ecco cosa succede quando aprite un file (quale, ad esempio, /home/esr/WWW/ldp/fundamentals.sgml):
Il kernel parte dalla radice del vostro file system Unix (dalla partizione root). Cerca una directory chiamata `home'. Di solito `home' è un mount point per una grande partizione utente da qualche altra parte, così va di là. Nella struttura della directory di livello più alto di quella partizione utente cerca poi una voce chiamata `esr' e ne estrae un numero di i-node. Va a quell'i-node, vede che si tratta di una struttura di directory e cerca `WWW'. Estraendo quell'i-node, va alla corrispondente sottodirectory e cerca `ldp'. Questo lo porta a un altro i-node di directory ancora. Aprendolo, trova il numero i-node di `fundamentals.sgml'. Questo i-node non è una directory, ma contiene invece l'elenco dei blocchi disco associati al file.
Per impedire ai programmi di intervenire accidentalmente o maliziosamente su dati su cui non dovrebbero, Unix usa le autorizzazioni. Queste vennero originariamente pensate per supportare il timesharing, proteggendo gli uni dagli altri utenti diversi sulla stessa macchina, quando ancora Unix veniva usato su costosi minicomputer condivisi.
Per comprendere le autorizzazioni sui file, occorre richiamare la descrizione di utenti e gruppi nella sezione Che cosa accade con il log in?. Ciascun file ha un utente proprietario e un gruppo proprietario. Inizialmente sono quelli del creatore del file; possono poi essere modificati con i programmi chown(1) e chgrp(1).
Le autorizzazioni fondamentali che possono essere associate a un file sono `read' (autorizzazione a leggere i dati contenuti), `write' (autorizzazione a modificarli) e `execute' (autorizzazione a eseguirli come programma). Ciascun file ha tre set di autorizzazioni; uno per l'utente proprietario, uno per tutti gli utenti nel gruppo proprietario e uno per tutti gli altri. I `privilegi' che si ottengono al momento del log in sono la possibilità di leggere, modificare ed eseguire quei file i cui bit di autorizzazione coincidono la propria ID utente o quella di un gruppo a cui si appartiene.
Per vedere come queste possono interagire e come le visualizza Unix, osserviamo alcuni elenchi di file su un sistema Unix ipotetico. Ecco un esempio:
snark:~$ ls -l notes
-rw-r--r-- 1 esr users 2993 Jun 17 11:00 notes
Si tratta di un file di dati ordinario. Il listato ci dice che il proprietario è l'utente `esr', creato con il gruppo proprietario `users'. Probabilmente la macchina su cui si trova mette per definizione tutti gli utenti ordinari in questo gruppo; altri gruppi che si vedranno comunemente su macchine con timesharing sono `staff', `admin', o `wheel' (per ovvie ragioni, i gruppi non sono molto importanti su workstation a singolo utente o PC). Il vostro Unix potrebbe usare un gruppo di default differente, magari derivato dal vostro nome utente.
La stringa `-rw-r--r--' rappresenta i bit di autorizzazione per il file. Il primo trattino è la posizione del bit directory; se il file fosse stato una directory il bit sarebbe stato `d'. Dopo di questo, le prime tre posizioni successive sono le autorizzazioni utente, le seconde tre le autorizzazioni del gruppo e le terze tre le autorizzazioni per gli altri (spesso chiamate autorizzazioni `world'). Su questo file l'utente proprietario `esr' può leggere e modificare il file, gli altri appartenenti al gruppo `users' possono leggerlo e così tutti gli altri utenti. Si tratta di un set di autorizzazioni piuttosto tipiche per un file di dati ordinario.
Ora osserviamo un file con autorizzazioni molto diverse. Tale file è GCC, il compilatore C GNU.
snark:~$ ls -l /usr/bin/gcc
-rwxr-xr-x 3 root bin 64796 Mar 21 16:41 /usr/bin/gcc
Questo file appartiene a un utente chiamato `root' e ad un gruppo chiamato `bin'; può essere modificato solo da root, ma letto ed eseguito da tutti. Si tratta di un proprietario e un set di autorizzazioni tipiche per un comando di sistema pre-installato. Il gruppo `bin' esiste su alcuni Unix per raggruppare i comandi di sistema (il nome è una reliquia storica, abbreviazione di `binary'). Il vostro Unix potrebbe usare invece un gruppo `root' (non esattamente la stessa cosa dell'utente `root'!).
L'utente `root' è il nome convenzionale per l'ID utente con numero 0, un account speciale privilegiato che può scavalcare tutti i privilegi. L'accesso root è utile ma pericoloso; un errore di battitura quando si è collegati come root potrebbe rovinare file critici del sistema, cosa che non può avvenire con un account utente ordinario.
Poiché l'account root è così potente, il suo accesso dovrebbe essere sorvegliato attentamente. La password di root è il componente più critico nelle informazioni di sicurezza del sistema, e sarà quello che cercheranno di ottenere tutti i cracker e gli intrusi che verranno dopo di voi.
(Per quanto riguarda le password: non scrivetele su carta -- e non scegliete password che possano essere indovinate facilmente, come il nome della/o vostra/o ragazza/o. È una pratica sorprendentemente comune che aiuta continuamente i cracker...)
Osserviamo ora un terzo caso:
snark:~$ ls -ld ~
drwxr-xr-x 89 esr users 9216 Jun 27 11:29 /home2/esr
snark:~$
Questo file è una directory (osserviamo la `d' in prima posizione). Vediamo che può essere modificata solo da esr, ma letta ed eseguita da tutti gli altri. Le autorizzazioni vengono interpretate in modo speciale sulle directory; esse controllano l'accesso ai file contenuti all'interno della directory.
Autorizzazione in lettura su una directory è semplice; significa semplicemente che potete esplorare la directory e aprire i file e le directory che contiene. L'autorizzazione in scrittura (modifica) da la possibilità di creare e cancellare file nella directory. Autorizzazione di esecuzione consente di effettuare ricerche nella directory -- ovvero elencare il suo contenuto e vedere i nomi dei file e delle directory che contiene. A volte troverete directory che sono leggibili da tutti ma non eseguibili; questo significa che un utente qualunque può accedere a file e directory al suo interno, ma solamente se ne conosce il nome esatto.
Infine, osserviamo le autorizzazioni del programma login stesso.
snark:~$ ls -l /bin/login
-rwsr-xr-x 1 root bin 20164 Apr 17 12:57 /bin/login
Possiede le autorizzazioni che ci aspetteremmo per un comando di sistema -- tranne la `s' dove dovrebbe esserci il bit per l'autorizzazione in esecuzione del proprietario. Si tratta della manifestazione visibile di un tipo speciale di autorizzazione chiamata `set-user-id' o bit setuid.
Il bit setuid è normalmente legato a programmi che hanno la necessità di dare agli utenti ordinari i privilegi di root, ma in modo controllato. Quando è impostato su un programma eseguibile, si acquistano i privilegi del proprietario di quel file finché si esegue quel programma, sia che essi coincidano con i nostri oppure no.
Come l'account root stesso, i programmi setuid sono utili ma pericolosi. Chiunque sia in grado di sovvertire o modificare un programma setuid che ha root come proprietario, può utilizzarlo per accedere alla shell con privilegi di root. Per questa ragione sulla maggior parte dei sistemi Unix, aprendo un file in scrittura automaticamente il suo bit setuid viene disattivato. Molti attacchi alla sicurezza su Unix tentano di scoprire bug nei programmi setuid, con lo scopo di sovvertirli. Amministratori di sistema attenti alla sicurezza sono quindi molto prudenti con questi programmi e riluttanti alla installazione di nuovi.
Ci sono un paio di importati dettagli che abbiamo sorvolato durante la
discussione precedente sulle autorizzazioni; in particolare, come
vengono assegnati l'utente e il gruppo proprietario quando viene
creato un file per la prima volta. Il gruppo è importante poiché gli
utenti possono essere membri di più gruppi, ma uno di essi
(specificato nella voce dell'utente in /etc/passwd
) è il gruppo di default dell'utente e normalmente possiederà
i file creati dall'utente.
Per quanto riguarda i bit iniziali di autorizzazione, la faccenda è leggermente più complicata. Un programma che crea un file normalmente specificherà le autorizzazioni con cui dovrà partire. Queste, però, verranno modificate da una variabile nell'ambiente dell'utente chiamata umask. Umask speciica quali bit di autorizzazione disattivare quando crea un file; il valore più comune, e il default sulla maggior parte dei sistemi, è -------w- o 002, che disattiva il bit di modifica per tutti gli utenti. Vedere la documentazione per il comando umask nella pagina di manuale della shell per maggiori dettagli.
Prima accennavamo al fatto che i file system possono essere delicati. Ora sappiamo che per raggiungere un file dobbiamo fare il gioco della campana attraverso quella che può essere una catena arbitrariamente lunga di riferimenti i-node e directory. Supponiamo ora che sul vostro disco fisso si formi un punto danneggiato.
Se siete fortunati ciò vi farà perdere solo qualche file di dati. Se invece siete sfortunati, si potrebbe danneggiare una struttura di directory o un numero i-node e un intero sottoalbero del vostro sistema potrebbe rimanere pendente nel limbo. Oppure, peggio ancora, si potrebbe originare una struttura rovinata che punta in più modi allo stesso blocco disco o i-node. Un danneggiamento di questo tipo si può propagare a partire da una normale operazione sui file, facendo perdere tutti i dati collegati al punto danneggiato di origine.
Fortunatamente questo tipo di eventualità è divenuto abbastanza infrequente perché l'hardware dei dischi è più affidabile. Tuttavia, questo comporta che il vostro Unix voglia controllare periodicamente l'integrità del file system per assicurarsi che non ci sia nulla fuori posto. Gli Unix moderni compiono un rapido controllo dell'integrità di ciascuna partizione nella fase di avvio, giusto prima di montarle. Ogni tot riavvii fanno un controllo molto più approfondito che impiega qualche minuto in più.
Se tutto questo può far sembrare che Unix sia terribilmente complesso e incline a malfunzionamenti, può essere rassicurante sapere che questi controlli nella fase d'avvio tipicamente intercettano e correggono i problemi normali prima che diventino veramente disastrosi. Altri sistemi operativi non hanno questi strumenti, cosa che velocizza un po' l'avvio ma può mettervi molto di più nei pasticci quando cercate di fare un salvataggio a mano (e sempre assumendo che abbiate una copia delle Norton Utilities o simili, tanto per cominciare...).