gcokeefe@postoffice.utas.edu.au
lferraro@NOSPAM.caspur.it
, Dicembre 2004).
Revisione di Antonio "bombadur" Bracaglia ( bombadur@slacky.it
, Febbraio 2005).
Trovo frustrante che all'interno della mia macchina Linux avvengano delle cose che non comprendo. Se, come me, volete veramente conoscere il vostro sistema invece di saperlo solamente usare, questo documento dovrebbe essere un buon punto di partenza. Questo tipo di conoscenze di basso livello è necessario se volete diventare dei veri esperti nel risolvere i problemi di Linux.
Darò per scontato che abbiate un sistema Linux funzionante e una conoscenza basilare di Unix e dell'hardware di un PC. Se così non fosse, un documento eccellente per iniziare ad imparare è quello di Eric S. Raymond, The Unix and Internet Fundamentals HOWTO È breve, facilmente comprensibile, e copre tutte le basi.
L'argomento principale di questo documento è come fa Linux ad avviarsi. Ma cerca anche di essere una risorsa più generale di apprendimento. Per ciascuna sezione ho inserito degli esercizi. Se ne farete qualcuno, imparerete molto più di quanto fareste solamente leggendo.
Spero che alcuni lettori si cimenteranno nell'esercizio migliore che io conosca per Linux, ossia quello di costruirsi un sistema a partire dal codice sorgente. Giambattista Vico, filosofo italiano (1668 - 1744), disse "verum ipsum factum", che significa "la comprensione viene attraverso le azioni". Ringrazio Alex (vedi Acknowledgements) per questa citazione.
Se volete farvelo da soli (NdT: l'espressione originale inglese era ``roll your own'', come le sigarette arrotolate a mano), dovreste leggervi l'HOWTO di Gerard Beekmans, Linux From Scratch HOWTO (LFS). LFS contiene istruzioni dettagliate sulla cotruzione di un sistema operativo Linux usabile e completo a partire dal codice sorgente. Sul sito di LFS troverete anche una mailing list per le persone che stanno creando il proprio sistema operativo in questo modo. Le istruzioni a riguardo che facevano parte di questo documento si trovano ora in un documento separato "Building a Minimal Linux System from Source Code", che potete trovare su From PowerUp to Bash Prompt home page. Spiegano come ``giocare'' con il sistema, puramente a scopo educativo.
I pacchetti vengono presentati nell'ordine in cui compaiono durante il processo di avvio del sistema. Questo significa che se installate i pacchetti in questo ordine, potrete riavviare dopo ciascuna installazione, e vedere come ogni volta il sistema si avvicina sempre più al prompt finale della shell. Trovo un rassicurante senso di avanzamento in questo.
Vi consiglio di leggere prima il testo principale di ogni sezione, saltando la parte degli esercizi e dei riferimenti. Successivamente scegliete a quale profondità di comprensione volete arrivare, e quanti sforzi siete disposti a fare. Quindi ricominciate a leggere dall'inizio, eseguendo gli esercizi e leggendo i documenti aggiuntivi man mano che procedete.
Quando accendete il computer, questo esegue una sorta di auto-verifica per controllare che tutto funzioni correttamente. Questa fase viene chiamata "auto-verifica di accensione" (dall'inglese "Power on self test"). A questo punto, un programma chiamato "bootstrap loader", che risiede nella memoria ROM del BIOS, cerca un settore di avvio (boot sector). Il settore di avvio è il primo settore di un disco, che contiene un piccolo programma capace di avviare un sistema operativo. I settori di avvio vengono marcati con il numero magico 0xAA55 = 43603 al byte 0x1FE = 510. Questo corrisponde agli ultimi due byte del settore. È in questo modo che l'hardware è in grado di riconoscere se un settore è di avvio oppure no.
Il bootstrap loader ha una lista di luoghi in cui cercare i possibili settori di avvio. Il mio vecchio computer cerca nel primo floppy drive e quindi nell'hard disk primario. I computer più moderni possono cercare un settore di avvio anche sul CD-ROM (NdT: recentemente anche tramite rete o dispositivi esterni come memory card o penne USB). Se trova un settore di avvio, lo carica in memoria e passa il controllo al programma in esso contenuto, che a sua volta carica il sistema operativo. In un tipico sistema Linux, questo programma corrisponde probabilmente alla prima parte del boot loader LILO (NdT: o di GRUB). Esistono diversi modi di configurare l'avvio del vostro sistema. Date uno sguardo al documento LILO User's Guide per maggiori dettagli, e alla sezione LILO per dei rimandi sull'argomento.
Ovviamente ci sarebbe molto altro da dire su quello che fa l'hardware di un PC. Ma questo non è il posto adatto per dirlo. Leggetevi magari uno dei numerosi libri sull'hardware dei PC.
Il computer immagazzina alcune informazioni su se stesso nella sua CMOS. Queste informazioni comprendono ad esempio il tipo di hard disk e di RAM presenti nel sistema. Il BIOS del computer contiene un programma che permette di modificare queste impostazioni. Per capire come accedervi, controllate i messaggi che compaiono sullo schermo quando accendete il computer. Sul mio computer, bisogna premere il tasto Canc prima che inizi ad avviarsi il sistema operativo.
Un ottimo modo per imparare a conoscere l'hardware di un PC è quello di costruirsi una macchina da soli con dei pezzi di seconda mano. Procuratevi un processore, almeno un 386, così da poter poi eseguire un sistema Linux agevolmente. Non vi costerà molto. Chiedete in giro, qualcuno potrebbe darvi alcuni dei pezzi di cui avrete bisogno.
Scaricate e compilate il programma Unios (avevano una homepage su http://www.unios.org, ma è scomparsa) e fatevi con questo un dischetto di avvio. Si tratta semplicemente del programma tipo "Ciao mondo!" avviabile, che consiste soltanto di un centinaio di righe di codice assembly. Sarebbe bene vederle convertite in un formato comprensibile dal compilatore assembler GNU.
Aprite l'immagine del dischetto di avvio di unios con un editor
esadecimale. Questa immagine è grande 512 byte, ossia esattamente un
settore. Individuate il numero magico 0xAA55. Fate lo stesso con il
settore di boot di un dischetto avviabile del vostro computer.
Potete utilizzare il comando dd
per copiarlo su un file:
dd if=/dev/fd0 of=myboot.sector
.
Fate molta attenzione a come usate if
(file di input)
e of
(file di output).
Date uno sguardo al codice sorgente del boot loader LILO.
Quando il computer carica il settore di boot su un normale sistema operativo Linux, quello che carica effettivamente è una parte di LILO, detta la "prima parte del boot loader" (NdT: "first stage boot loader"). Questo è un piccolo programma il cui unico scopo nella vita è quello di caricare ed avviare la "seconda parte del boot loader" (NdT: "second stage boot loader").
La seconda parte del boot loader vi fornisce un prompt (se installato in modo tale da farlo) e carica il sistema operativo che avrete scelto.
Quando il vostro sistema è attivo e in uso, se eseguite il comando
lilo
, quello che di fatto mandate in esecuzione è
l'installatore di mappa (NdT: map installer). Questo legge il file di
configurazione /etc/lilo.conf
e scrive sull'hard disk il boot
loader e le informazioni sui sistemi operativi che possono venire
avviati.
Esistono molti modi diversi di configurare l'avvio del vostro sistema. Quello che vi ho appena illustrato è il più ovvio e "normale", se non altro per un computer il cui sistema operativo principale è Linux. La Guida Utente di LILO (NdT: LILO Users' Guide) tratta vari esempi di avvio. Sarebbe bene leggerli e provarne alcuni.
Il file di configurazione di lilo è /etc/lilo.conf
. C'è una
pagina di manuale per questo file: digitate man lilo.conf
in
una shell per leggerlo. La parte principale del file lilo.conf
consiste in una voce per ogni sistema che lilo deve avviare. Una voce
per Linux deve includere la posizione del kernel, e quale partizione del
disco deve essere montata come filesystem radice. Per gli altri sistemi
operativi, l'informazione principale è la partizione da cui eseguire
l'avvio.
ATTENZIONE: fate molta attenzione con questi esercizi. È piuttosto facile che qualcosa vada storto e che venga compromesso il vostro master boot record, rendendo il vostro sistema inutilizzabile. Assicuratevi di avere un disco di recupero funzionante, e di sapere come utilizzarlo per rimettere le cose a posto. Vedete sotto per un link a tomsrtbt, il disco di recupero che uso e vi raccomando. La migliore precauzione è quella di utilizzare una macchina di cui non vi importa molto.
Installate lilo su un dischetto. Non importa se nel floppy ci sarà solo il kernel - incorrerete in un ``kernel panic'' quando il kernel tenterà di avviare init, ma almeno saprete che lilo sta funzionando.
Se vi piace, potete provare ad andare avanti a stiparvi del materiale, e vedere quanto del sistema operativo riuscite a mettere sul floppy. Questa è sicuramente la seconda miglior maniera per imparare qualcosa su Linux. Vedete il Bootdisk HOWTO (l'url è riportata più sotto), e tomsrtbt (url più sotto) per alcuni suggerimenti utili.
Provate a configurare lilo per avviare unios (vedete la sezione hardware exercises). Come ulteriore esercizio, provate a farlo da un dischetto.
Create un ciclo di boot (NdT: boot-loop): configurate lilo nel master boot record in modo tale che avvii lilo da uno dei settori di boot delle partizioni primarie, e configurate quest'ultimo in modo tale da avviare quello nel master boot record... Oppure usate il master boot record e tutte e quattro le partizioni primarie per creare un ciclo a cinque punti. Divertente!
lilo-u-21.ps.gz
(o superiore).
Potreste già avere questo documento installato.
Controllate in /usr/doc/lilo
, o comunque in quella zona
del filesystem. La versione postscript è migliore di quella in
testo semplice, perché contiene diagrammi e tabelle.Il kernel assume molti compiti. Credo che un modo semplice per riassumerli sia quello di dire che esso fa in modo che l'hardware soddisfi tutte le richieste dei programmi, in modo semplice ed efficiente.
Il processore può eseguire solo un'istruzione alla volta, ma i sistemi Linux sembrano far girare molte cose contemporaneamente. Il kernel riesce a fare questo passando molto velocemente da un task ad un altro. Riesce a fare il miglior uso del processore, tenendo traccia dei processi che sono pronti per essere eseguiti, e di quelli invece che sono in attesa di qualcosa, come un record da un file sull'hard disk o di un input dalla tastiera. Questa attività del kernel è chiamata scheduling.
Se un programma non sta facendo nulla, allora non è necessario che risieda nella RAM. Anche se un programma sta facendo qualcosa, potrebbe avere delle parti che non stanno facendo nulla. Lo spazio degli indirizzi di memoria di ciascun processo viene diviso in pagine. Il kernel tiene traccia delle pagine di cui i processi stanno facendo maggiore uso. Le pagine che non vengono utilizzate con frequenza possono venire spostate nella partizione di swap. Quando saranno nuovamente necessarie, un'altra pagina non utilizzata potrà essere spostata per fare lo spazio. Questa è la gestione della memoria virtuale.
Se avete compilato qualche volta il vostro kernel, avrete notato che esistono moltissime opzioni per specifici dispositivi. Il kernel contiene una grande quantità di codice specifico per comunicare con diverse tipologie di hardware, e presentarle ai programmi applicativi in modo semplice e uniforme.
Il kernel inoltre gestisce il filesystem, le comunicazioni tra i processi e diverso materiale riguardante il il networking.
Una volta che il kernel è stato caricato, la prima cosa che fa è quella
di cercare un programma init
da eseguire.
La maggior parte della configurazione del kernel viene fatta durante la
sua compilazione, utilizzando il comando make menuconfig
, o
make xconfig
da dentro la directory /usr/src/linux/
(o comunque dalla directory contenente i sorgenti del kernel Linux).
Potete riconfigurare i valori della modalità video predefinita, il
filesystem radice, il dispositivo di swap, e la dimensione del disco
RAM, tramite il comando rdev
. (NdT: dalla versione 0.95 del
kernel Linux il comandordev -s
per l'indicazione delle
partizioni di swap non è più valido, in quanto l'attivazione dello swap
viene effettuato tramite la chiamata di sistema swapon()
).
Questi parametri e altri ancora possono essere passati al kernel
attraverso lilo. Potete fornire a lilo i parametri da passare al kernel
o dal file di configurazione lilo.conf, o direttamente dal prompt di
lilo. Per esempio, se voleste utilizzare hda3 come filesystem radice al
posto di hda2, potreste digitare il comando
LILO: linux root=/dev/hda3
Se state costruendo un sistema dai sorgenti, potete rendervi la vita molto più semplice se create un kernel ``monolitico''. Ossia senza moduli. A questo punto non avrete bisogno di copiare i moduli del kernel sul sistema per cui è stato compilato.
NOTA: il file System.map
viene utilizzato dal logger del
kernel per determinare i nomi dei moduli che generano messaggi. Anche il
programma top
utilizza queste informazioni. Quando copiate il
kernel sul nuovo sistema, copiate anche il file System.map
.
Riflettete su questo: /dev/hda3
è un file speciale che
descrive una partizione dell'hard disk. Ma risiede su un filesystem,
proprio come tutti gli altri file. Il kernel vuole sapere quale
partizione deve montare come filesystem radice - ma questa non ha ancora
un filesystem. Allora, come può leggere /dev/hda3
per sapere
quale partizione montare?
Se non lo avete ancora fatto: compilatevi un kernel. Leggete tutta la documentazione di aiuto per ciascuna opzione.
Vedete quanto piccolo riuscite a compilare un kernel che ancora funzioni. Potrete imparare molto se lascerete fuori le cose sbagliate!
Leggete ``The Linux Kernel'' (vedi l'indirizzo URL più sotto) e, mentre lo leggete, individuate le parti di codice sorgente a cui fa riferimento. Il libro (come ho detto) si riferisce alla versione 2.0.33 del kernel, che è piuttosto vecchia. Potrebbe essere più semplice da seguire se scaricaste questa vecchia versione del kernel ed esaminaste quel codice sorgente. Trovo sia entusiasmante trovare pezzi di codice C chiamati ``processo'' e ``pagina''.
Hack! Vedete se riuscite a farvi sputare fuori qualche messaggio extra o cose simili.
/usr/src/linux/README
ed i contenuti di
/usr/src/linux/Documentation/
(Questi potrebbero trovarsi da qualche altra parte sul vostro
sistema).make menuconfig
o make xconfig
Il passo successivo all'accensione del computer consiste nel caricamento e nella esecuzione di init. Comunque, init, come la maggior parte dei programmi, utilizza delle funzioni di libreria.
Potreste aver già visto un esempio di programma C come questo:
main() { printf("Hello World!\n"); }
Il programma non contiene nessuna definizione della funzione
printf
, e quindi da dove salta fuori? Questa proviene dalle
librerie standard C che, su un sistema GNU/Linux, si chiamano glibc. Se
compilate il programma sotto Visual C++, allora quella funzione viene da
una implementazione Microsoft delle stesse funzioni standard. Esistono
milioni di queste funzioni standard, per matematica, stringhe,
allocazione di memoria per data e ora, e così via. Qualsiasi cosa in
Unix (incluso Linux) è stata scritta scritta in C, perciò ogni
applicazione utilizza queste funzioni.
Se guardate nella directory /lib
del vostro sistema Linux
troverete molti file chiamati libqualcosa.so
o
libqualcosa.a
, ecc. Sono le librerie di queste funzioni. Glibc
è esattamente l'implementazione GNU di queste funzioni.
Ci sono due modi in cui i programmi possono utilizzare queste le
funzioni di libreria. Se linkate il programma in modo statico,
queste funzioni di libreria verranno copiate dentro l'eseguibile che
viene creato. Le librerie libqualcosa.a
servono a questo. Se
invece linkate il programma in modo dinamico (e questa è la
modalità predefinita), quando il programma sarà in esecuzione e avrà
bisogno del codice della libreria, questo verrà chiamato dal file
libqualcosa.so
.
Il comando ldd
farà al caso vostro quando vorrete sapere quali
librerie sono necessarie ad un particolare programma. Per esempio, ecco
le librerie utilizzate da bash
:
[greg@Curry power2bash]$ ldd /bin/bash libtermcap.so.2 => /lib/libtermcap.so.2 (0x40019000) libc.so.6 => /lib/libc.so.6 (0x4001d000) /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
Alcune funzioni delle librerie dipendono dal posto in cui vivete. Per
esempio, in Australia scriviamo le date nel formato dd/mm/yy
(NdT: giorno/mese/anno, come in Italia), ma in America viene usato il
formato mm/dd/yy. Esiste un programma che viene fornito con le
glibc
, chiamato localedef
, che consente di configurare
le localizzazioni.
Usate ldd
per scoprire quali librerie utilizzano le vostre
applicazioni preferite.
Usate ldd
per scoprire quali librerie sono utilizzate da
init
.
Createvi una libreria giocattolo, con una o due funzioni. Per crearla
utilizzate il programma ar
. La pagina di manuale di ar
può essere un buon punto di inizio per capire come fare. Scrivete,
compilate e linkate un programma che faccia uso di questa vostra
libreria.
Parlerò solamente dello stile ``System V'' di init, utilizzato dalla
maggior parte dei sistemi Linux. Esistono anche altre alternative.
Infatti, potete mettere qualsiasi programma vogliate in
/sbin/init
, e il kernel lo eseguirà non appena avrà terminato la
sua fase di caricamento.
È compito di init
mandare in esecuzione qualsiasi cosa nel
modo corretto. init
verifica che i filesystem siano a posto e li
monta. Avvia i "demoni" per registrare i messaggi di sistema, gestisce
le funzionalità di rete, rende disponibili le pagine web, gestisce il
vostro mouse, e così via. Avvia anche i processi getty che fanno
comparire il prompt di login sui vostri terminali virtuali.
Dovrei anche parlare di una faccenda piuttosto complessa riguardo al passaggio tra i vari ``run-levels'', ma la salterò quasi del tutto e vi parlerò piuttosto di come si avvia il sistema.
Init legge il file /etc/inittab
che gli dice cosa fare.
La prima cosa che di solito viene richiesta è quella di eseguire uno
script di inizializzazione. Il programma che esegue (o interpreta)
questo script è bash
, lo stesso programma che vi fornisce un
prompt dei comandi.
Nei sistemi Debian, lo script di inizializzazione è
/etc/init.d/rcS
, mentre in Red Hat, è
/etc/rc.d/rc.sysinit
.
In questo script vengono verificati e montati i filesystem, viene
impostato l'orologio di sistema, abilitato lo spazio di swap, il nome
dell'host, ecc.
Successivamente, viene chiamato un altro script che ci porta al
run-level predefinito. Questo significa un gruppo di sottosistemi da
avviare.
Esistono una serie di directory /etc/rc.d/rc0.d
,
/etc/rc.d/rc1.d
, ..., /etc/rc.d/rc6.d
in Red Hat, o
/etc/rc0.d
, /etc/rc1.d
, ..., /etc/rc6.d
in
Debian, che corrispondono ai vari run-level. Se stiamo entrando nel
run-level 3 di un sistema Debian, allora lo script eseguirà tutti gli
script presenti nella directory /etc/rc3.d
i cui nomi inizino
per `S' (S sta per start). Questi script in realtà sono soltanto dei
link simbolici a degli script che si trovano in un'altra directory,
generalmente chiamata init.d
.
Quindi, il nostro script di run-level è stato chiamato da init
e ora sta cercando all'interno di una directory tutti gli script che
cominciano per `S'. Potrebbe trovare S10syslog
per primo. Il
numero dice allo script di run-level in quale ordine questi devono
venire eseguiti. Perciò in questo caso, dal momento che non ci sono
altri script che cominciano per S00 ... S09, S10syslog
viene
eseguito per primo. Ma S10syslog
è in realtà un link a
/etc/init.d/syslog
, uno script per avviare o fermare il logger
di sistema. Dato che il link comincia per `S', lo script di run-level
sa che dovrà eseguire lo script syslog
con il parametro
``start''. Esistono anche i corrispettivi link che cominciano per `K' (K
sta per kill), che specificano quali servizi fermare e in quale ordine,
quando viene lasciato un certo run-level.
Per scegliere quali sottosistemi (servizi) far partire in modo
predefinito, dovrete impostare questi collegamenti nella directory
rcN.d
, dove per N si intende il runlevel predefinito,
configurato nel vostro inittab
.
L'ultima cosa importante che fa init è far partire alcune sessioni del
programma getty
. Questi sono di tipo ``respawned'', che
significa che se si fermano, init
li fa partire nuovamente. La
maggior parte delle distribuzioni vengono configurate con sei terminali
virtuali. Potreste volerne di meno per risparmiare memoria, o di più in
modo da mandare in esecuzione più cose, e passare rapidamente da una
all'altra a seconda delle vostre necessità.
Potreste anche voler eseguire getty
per un terminale testuale o
per un modem. In tal caso dovrete modificare il file inittab
.
Il file /etc/inittab
rappresenta il vertice della configurazione
di init.
Le directory rcN.d
, dove N = 0, 1, ..., 6 determinano quali
sottosistemi vengono avviati.
Da qualche parte, in uno degli script richiamati da init, verrà dato il
comando mount -a
. Questo significa montare tutti i filesystem
che si suppone debbano venire montati. Il file /etc/fstab
definisce quali filesystem il sistema deve montare. Se volete modificare
quello che viene montato quando il il sistema viene avviato, questo è il
file che dovrete editare. Esiste anche una pagina di manuale per
fstab
.
Individuate la directory rcN.d
del run-level predefinito del
vostro sistema ed eseguite un ls -l
per vedere a cosa puntano
link in essa presenti.
Cambiate il numero di sessioni getty che vengono eseguite sul vostro sistema.
Eliminate ogni servizio di cui non avete bisogno dal vostro run-level predefinito.
Provate a verificare il numero minimo di servizi con cui riuscite a partire.
Create un dischetto con lilo, un kernel e un programma "ciao mondo!"
compilato staticamente, chiamato /sbin/init
e osservate se si
avvia ed emette il messaggio di saluto.
Osservate attentamente l'avvio del vostro sistema, e prendete nota di
tutto ciò che si sta verificando. Oppure stampate una porzione del file
di log di sistema /var/log/messages
dal momento dell'avvio. A
questo punto, partendo da inittab
, seguite tutti gli script e
cercate di capire ogni parte del codice, e che cosa fa. Potete anche
inserire dei messaggi extra, come ad esempio
echo "Ciao, io sono il file rc.sysinit"
Questo è un buon esercizio per imparare anche il linguaggio di scripting della shell Bash, visto che alcuni di questi script sono piuttosto complicati. Procuratevi una buona guida di Bash da tenere sottomano.
inittab
e fstab
.
Digitate ad esempio man inittab
in una shell per vederlo.In questa sezione, utilizzerò la parola ``filesystem'' in due differenti accezioni. Una riferendomi ai filesystem delle partizioni del disco o di altre periferiche, l'altra riferita al filesystem che vi viene presentato da un sistema Linux in esecuzione. In Linux, infatti, voi ``montate'' il filesystem di un disco all'interno del filesystem di sistema.
Nella sezione precedente ho detto che gli script di avvio verificano e
montano i filesystem. I comandi a cui vengono affidati questi compiti
sono rispettivamente fsck
e mount
.
L'hard disk può essere visto come un grande spazio su cui potete
scrivere tanti 1 e 0. Un filesystem impone su di esso una struttura, e
fa in modo che i file vengano visualizzati all'interno di directory
dentro altre directory... Ogni file viene rappresentato da un inode, che
definisce il file a cui fa riferimento, quando è stato creato e dove si
trova il suo contenuto. Anche le directory vengono rappresentate dagli
inode, ma questi dicono piuttosto dove trovare gli inode dei file in
esse contenuti. Se il sistema vuole leggere il file
/home/greg/bigboobs.jpeg
, prima trova l'inode della directory
radice /
nel ``superblocco'', poi troverà l'inode per la
directory home
tra quelli contenuti in /
, quindi
l'inode per la directory greg
tra quelli contenuti in
/home
, e infine l'inode per bigboobs.jpeg
, che indica
quali blocchi del disco devono essere letti.
Se aggiungiamo dei dati alla fine di un file, potrebbe accadere che
questi dati vengano scritti prima che l'inode sia aggiornato in modo da
sapere che i nuovi blocchi appartengono al file, o viceversa. Se venisse
a mancare la corrente in questo momento, il filesystem risulterebbe
corrotto. Ed è proprio questo genere di cose che fsck
tenta di
verificare e riparare.
Il comando mount
prende il filesystem di un dispositivo, e lo
innesta nella gerarchia che vedete quando usate il vostro sistema.
Generalmente, il kernel monta la radice del proprio filesystem in
modalità di sola lettura. Il comando mount
viene utilizzato per
rimontarlo in modalità di lettura e scrittura dopo che fsck
abbia verificato che tutto sia in ordine.
Linux supporta anche altri tipi di filesystem: msdos, vfat, minix, e così via. Le caratteristiche di ogni filesystem vengono descritte in modo astratto attraverso il file system virtuale (VFS). Ma su questo argomento non entrerò nei dettagli. Potete trovarne una trattazione su ``The Linux Kernel'' (vedete la sessione The Linux Kernel per la URL).
Un tipo di filesystem completamente differente viene montato su
/proc
. Questo contiene una rappresentazione di quello che
accade nel kernel. Qui esiste una directory per ogni processo che si
trova in esecuzione sul sistema, con il numero del processo come nome
per la directory. Sono presenti anche dei file come interrupts
o meminfo
, che vi informano sul modo in cui viene utilizzato
l'hardware. Potete imparare molto esplorando /proc
.
Sono presenti dei parametri per il comandomke2fs
, che crea un
filesystem ext2. Questi controllano la dimensione dei blocchi, il numero
di inode, e così via. Controllate la pagina di manuale di
mke2fs
per maggiori dettagli.
Ciò che viene montato, e dove, sul vostro filesystem, viene controllato
dal file /etc/fstab
. Anche per questo esiste una pagina di
manuale.
Create un piccolissimo filesystem, e guardatelo attraverso un editor esadecimale. Identificate gli inode, i superblocchi e i file in esso contenuti.
Sono sicuro che esistono degli strumenti che vi possano fornire una rappresentazione grafica del filesystem. Trovatene uno, provatelo e mandatemi una email con una bella recensione!
Leggete il codice del filesystem ext2 nel Kernel.
mount
fa parte del pacchetto util-linux, di
cui trovate un link su
Building a Minimal Linux System from Source Code mount
, fstab
, fsck
,
mke2fs
e proc
Documentation/proc.txt
nella directory dei
sorgenti del Kernel Linux illustra il filesystem /proc
./bin
, /sbin
e così via. Questo è un buon
riferimento se il vostro obiettivo è quello di creare un sistema
minimo ma completo.Se eseguite il comandops aux
, vedrete probabilmente qualcosa di
simile:
USER PID %CPU %MEM SIZE RSS TTY STAT START TIME COMMAND root 1 0.1 8.0 1284 536 ? S 07:37 0:04 init [2] root 2 0.0 0.0 0 0 ? SW 07:37 0:00 (kflushd) root 3 0.0 0.0 0 0 ? SW 07:37 0:00 (kupdate) root 4 0.0 0.0 0 0 ? SW 07:37 0:00 (kpiod) root 5 0.0 0.0 0 0 ? SW 07:37 0:00 (kswapd) root 52 0.0 10.7 1552 716 ? S 07:38 0:01 syslogd -m 0 root 54 0.0 7.1 1276 480 ? S 07:38 0:00 klogd root 56 0.3 17.3 2232 1156 1 S 07:38 0:13 -bash root 57 0.0 7.1 1272 480 2 S 07:38 0:01 /sbin/agetty 38400 tt root 64 0.1 7.2 1272 484 S1 S 08:16 0:01 /sbin/agetty -L ttyS1 root 70 0.0 10.6 1472 708 1 R Sep 11 0:01 ps aux
Questa è una lista dei processi in esecuzione sul sistema. Le
informazioni provengono dal filesystem /proc
che ho descritto
nella sezione precedente.
Notate che init
è il processo numero uno. I process 2, 3, 4 e 5
sono kflushd, kupdate, kpiod e kswapd. C'è tuttavia qualcosa di strano:
notate che in entrambe le colonne del Virtual Storage Size (SIZE) e del
Real Storage Size (RSS), questi processi hanno valori nulli. Come può un
processo non utilizzare memoria?
Questi processi sono i demoni del kernel. La maggior parte dei kernel non mostra affatto una lista dei processi attivi, e potete capire quanta memoria questi stanno utilizzando solamente sottraendo la memoria disponibile da quella totale del sistema. I demoni del kernel vengono avviati dopo init, e quindi prendono un numero di processo come fanno tutti gli altri processi. Ma il loro codice ed i loro dati risiedono nella parte di memoria riservata al kernel.
Intorno alle voci della colonna dei comandi ci sono le parentesi
perché il filesystem /proc
non contiene informazioni sulla
linea di comando per questi processi.
Ma allora a cosa servono questi demoni del kernel? Versioni precedenti di questo documento riportavano una richiesta di aiuto per questo paragrafo, dal momento che non sapevo molto sui demoni del kernel. La storia parziale che segue è stata realizzata combinando le diverse risposte a questa richiesta, per le quali sono veramente grato. Maggiori informazioni, riferimenti e correzioni sono benvenute!
L'input e l'output viene realizzato tramite i buffer in
memoria. Questo consente di far eseguire le cose più velocemente. Quello
che i programmi scrivono può essere tenuto in memoria, in un buffer, e
quindi scritto su blocchi di disco in modo molto più efficiente. I
demoni kflushd
e kupdate
hanno questo compito:
kupdate
viene eseguito periodicamente (5 secondi?) per
verificare se vi siano dei buffer utilizzati. Se ci sono, richiama
kflushd
per riversarli sul disco.
Spesso i processi non hanno nulla da fare, e spesso, quelli in
esecuzione non hanno bisogno di tenere in memoria tutto il loro codice
ed i loro dati. Questo significa che possiamo fare un utilizzo migliore
della memoria, spostando le porzioni inutilizzate dei programmi sulla(e)
partizione(i) di swap dell'hard disk.
Il trasferimento di questi dati da e verso la memoria a seconda della
necessità viene gestito di demoni kpiod
e kswapd
. Ogni
secondo circa, kswapd
si attiva e verifica lo stato della
memoria e, se qualcosa che era stato portato sul disco diventa
necessario alla memoria, o se non c'è memoria libera a sufficienza,
viene attivato kpiod
.
Sul vostro sistema potrebbe essere in esecuzione anche il demone
kapmd
, se avete configurato il kernel con la gestione
automatica dell'energia.
Il programma update
vi consente di configurare kflushd
e kswapd
. Provate il comando update -h
per avere
maggiori informazioni.
Lo spazio di swap viene attivato da swapon
, e disattivato da
swapoff
. Lo script di init (/etc/rc.sysinit
oppure
/etc/rc.d/rc.sysinit
) generalmente fa una chiamata a
swapon
quando il sistema si avvia.
Mi è stato detto che swapoff
è comodo per il risparmio
energetico sui portatili.
Eseguite un update -d
(NdT: al momento della traduzione,
l'opzione -d
non viene contemplata dal programma udate
,
e notate cosa viene blaterato nell'ultima riga riguardo al ``threshold
for buffer fratricide'' (NdT: ``punto limite per un fratricidio tra
buffer''). Ecco un argomento intrigante, provate ad investigare!
Entrate nella directory /proc/sys/vm
e visualizzate con
cat
i file ivi contenuti. Vedete cosa riuscite a scoprire.
Il documento ``The Linux Kernel'' su Linux Documentation Project (LDP) (vedete la sessione The Linux Kernel per la URL)
Il codice sorgente del kernel Linux, se siete abbastanza coraggiosi!
Il codice di kswapd
è in linux/mm/vmscan.c
,
quello di kflushd
e di kupdate
sono in
linux/fs/buffer.c
.
Init avvia i demoni syslogd
e klogd
. Questi scrivono
dei messaggi nei log. I messaggi del kernel vengono gestiti da
klogd
, mentre syslogd
gestisce i messaggi di log degli
altri processi. Il file di log principale è /var/log/messages
.
Questo è un buon posto in cui investigare se c'è qualcosa che non va nel
vostro sistema. Spesso potreste trovarvi degli indizi importanti.
Il file /etc/syslog.conf
istruisce il programma che gestisce i
log sui messaggi da gestire, e dove riportarli. I messaggi vengono
identificati tramite il servizio da cui provengono, e dal loro livello
di priorità. Questo file di configurazione consiste di una serie di
righe su cui viene indicato che i messaggi provenienti dal servizio x,
con priorità y, devono venire inviati su z, dove z può essere un file,
una tty, una stampante, un host remoto o altro.
NOTA: il demone Syslog richiede che il file /etc/services
sia
presente sul sistema. Il file services assegna le porte. Non sono sicuro
se syslog necessiti di una porta assegnata per poter gestire i log in
remoto, o se la stessa gestione locale dei log venga fatta tramite una
porta, o se utilizza /etc/services
soltanto per convertire i
nomi dei servizi che avete impostato in /etc/syslog.conf
in
numeri di porta.
Osservate i vostri log di sistema. Cercate un messaggio che non comprendete, e sforzatevi di capire cosa significhi.
Mandate tutti i vostri messaggi di log su una tty. (poi reimpostateli al modo predefinito)
Australian sysklogd Mirror
Getty è il programma che vi permette di autenticarvi attraverso un
dispositivo seriale, come ad esempio un terminale fisico o virtuale,
oppure tramite un modem. Getty visualizza il prompt di autenticazione.
Una volta inserito il vostro nome utente, getty lo passa a
login
, il quale vi chiederà una password, controllerà la sua
validità, e vi fornirà una shell.
Esistono diverse versioni disponibili di getty. Alcune distribuzioni,
compresa Red Hat, ne usano una molto piccola chiamata mingetty
,
che funziona solamente con i terminali virtuali.
Il programma login
fa parte del pacchetto util-linux, che
contiene a sua volta una versione di getty chiamata agetty
, e
che funziona molto bene. Questo pacchetto contiene anche
mkswap
, fdisk
, passwd
, kill
,
setterm
, mount
, swapon
, rdev
,
renice
, more
e molti altri ancora.
Il messaggio che viene visualizzato sulla parte alta del vostro schermo
assieme al prompt di login, proviene da /etc/issue
. In genere
le istanze di Getty vengono avviate da /etc/inittab
. Login
verifica i dati di un utente contenuti in /etc/passwd
, o in
/etc/shadow
se usate lo shadow delle password.
Create un file /etc/passwd
a mano. Potete anche impostare delle
password vuote, e modificarle con il comando passwd
una volta
eseguito il login. Leggete la pagina di manuale corrispondente tramite
il comando man 5 passwd
, per avere il manuale del file
piuttosto che quello del programma passwd.
Se fornite a login
una combinazione di username e password
valida, questo verificherà nel file /etc/passwd
quale shell
deve mettervi a disposizione. Nella maggior parte dei casi per un
sistema Linux, questa sarà la shell bash
. Spetta a
bash
leggere ed interpretare i vostri comandi. Può essere vista
contemporaneamente come un'interfaccia utente, e come un interprete di
linguaggio di programmazione.
Come interfaccia utente legge i vostri comandi e, se sono dei comandi
``interni'' come cd
li esegue essa stessa, altrimenti cerca ed
esegue un programma se sono dei comandi ``esterni'', come cp
o
startx
. Bash svolge anche altri compiti diversi, come il
mantenimento dello storico dei comandi ed il completamento automatico
dei nomi.
Abbiamo già visto bash
in azione come interprete di linguaggio
di programmazione. Gli script che vengono eseguiti da init
per
avviare il sistema solitamente sono degli script di shell, e vengono
eseguiti da bash
. Avere a disposizione un vero e proprio
linguaggio di programmazione affianco ai programmi di utilità messi a
disposizione dalla linea di comando, costituisce un potente strumento,
se sapete usarlo.
Ad esempio (permettetemi l'immodestia), l'altro giorno ho dovuto
applicare una serie di patch ai file di una directory contenente del
codice sorgente. Sono riuscito a farlo con questo semplice, singolo
comando:
for f in /home/greg/sh-utils-1.16*.patch; do patch -p0 < $f; done;
Questo comando cerca nella mia directory personale tutti quei file i cui
nomi iniziano per sh-utils-1.16
e finiscono per
.patch
. Quindi ne prende uno alla volta, lo imposta alla
variabile f
, ed esegue i comandi contenuti tra le istruzioni
do
e done
. Nel mio caso c'erano 11 file di patch, ma
avrebbero potuto facilmente essere anche 3000.
Il file /etc/profile
controlla il comportamento globale di bash
sul sistema. Quello che scriverete su questo file avrà effetto per tutti
gli utenti che utilizzeranno bash sul vostro sistema. Aggiungerà inoltre
alcune directory alla variabile di ambiente PATH
, imposterà
la variabile MAIL
, ecc.
Il comportamento predefinito della tastiera lascia spesso molto a
desiderare. Attualmente è la libreria readline che lo gestisce.
Readline è un pacchetto separato che gestisce la linea di comando,
fornendo lo storico dei comandi ed il completamento automatico dei nomi,
così come alcune caratteristiche di editing avanzato da linea di
comando. Viene compilata all'interno di bash. In modo predefinito,
readline viene configurata attraverso il file .inputrc
,
presente nella vostra directory home. La variabile bash INPUTRC può
venire utilizzata per modificare questa impostazione. Per esempio in Red
Hat 6, INPUTRC
viene impostata a /etc/inputrc
in
/etc/profile
. Questo permette ai tasti backspace, delete, home
e end, di funzionare adeguatamente per tutti gli utenti.
Dopo che bash ha letto il file di configurazione globale di sistema, va
a leggere il vostro file di configurazione personale. Ne verifica la
presenza nella vostra directory home attraverso i nomi di file
.bash_profile
, .bash_login
e .profile
. Esegue
il primo dei tre che individua. Se volete modificare il comportamento di
bash solo per voi, senza cambiare il suo funzionamento per gli altri
utenti, fatelo in questi file. Ad esempio, molte applicazioni usano
delle variabili di ambiente per impostare il proprio funzionamento. Io
ho la variabile EDITOR
impostata a vi
, in modo da
poter utilizzare vi all'interno di Midnight Commander (un eccellente
file manager testuale), invece del suo editor predefinito.
I principi base di bash sono facili da imparare. Ma non fermatevi lì: c'è ancora molto materiale per approfondire. Prendete l'abitudine di cercare metodi sempre migliori per svolgere determinati compiti.
Leggete gli script di shell, cercate di capire le cose che non vi sono chiare.
Gran parte del lavoro che svolgete in bash viene eseguito attraverso dei
comandi come cp
. La maggior parte di questi comandi sono dei
piccoli programmi, sebbene alcuni, come cd
, siano contenuti
all'interno della shell.
I comandi vengono distribuiti sotto forma di pacchetti, la maggior parte dei quali dalla Free Software Foundation (o GNU). Piuttosto che mettermi ad elencare qui i pacchetti, vi rimando direttamente a Linux From Scratch HOWTO. Contiene una lista completa ed aggiornata dei pacchetti che vengono installati in un sistema Linux, insieme alle istruzioni su come compilarli.
Una delle cose migliori di Linux, secondo la mia modesta opinione, è che potete entrarci dentro e capire davvero come funzioni l'intero sistema. Spero che apprezziate questo come l'ho apprezzato io. E spero che questa piccola guida vi sia stata di aiuto.
This document is copyright (c) 1999, 2000 Greg O'Keefe. You are welcome to use, copy, distribute or modify it, without charge, under the terms of the GNU General Public Licence. Please acknowledge me if you use all or part of this in another document.
Potete trovare la versione aggiornata di questo documento su From Powerup To Bash Prompt insieme al suo complementare ``Building a Minimal Linux System from Source Code''.
Esiste una traduzione in Francese su From Powerup To Bash Prompt grazie a Dominique van den Broeck. La versione giapponese arriverà presto, se non si trova già su Japanese Documentation and FAQ Project.
Mi piacerebbe ricevere i vostri commenti, critiche o suggerimenti per migliorare questo documento. Per favore scrivetemi all'indirizzo Greg O'Keefe
I nomi dei prodotti sono marchi registrati dei rispettivi proprietari, e sono perciò da considerarsi come noti.
Ci sono alcune persone che vorrei ringraziare per avermi aiutato a realizzare questa guida.
Per avermi ricordato di Unios.
Per alcuni buoni suggerimenti su /etc/passwd
Che mi ha fatto notare come syslogd necessiti di /etc/services
,
e che mi ha fatto conoscere l'espressione ``rolling your own'' in
riferimento alla costruzione di un sistema a partire dal codice
sorgente.
Per avermi fatto conoscere Vico e il suo ``verum ipsum factum'' (la comprensione viene attraverso le azioni).
Per aver corretto la mia aritmetica esadecimale.
Per avermi segnalato alcuni errori di battitura.
Per aver contribuito a chiarire alcuni dubbi sui demoni del kernel.
Per aver tradotto questo documento in Francese.
Per alcune preziose informazioni sui demoni del kernel.
Per alcune preziose informazioni sui demoni del kernel.
Per la traduzione in Giapponese del documento.
Per aver contribuito alla realizzazione di una versione assembler GNU di UNIOS (vedete la sezione ``risorse'' nella mia home page)
/proc
.