UNIX. Di tutto un file
Nel caso di una macchina VMS, questo e` un tipico
elenco di devices
Dischi locali
Dischi remoti
Nastri
Come si giunge ad un file?
disk$xx:[directory]file.txt
disco
directory
L’equivalente in UNIX:
• Un file su di un disco locale:
/home/user/file.txt
• Un file su di un disco remoto
/afs/infn.it/system/file.txt
• una unita` nastro
/dev/st0
file
Elementi
sintatticamente
distinti
individuano
oggetti
diversi
La sintassi
non e` di alcun
aiuto
Una visione d’insieme
user level
kernel level
file subsystem
process control
subsystem
filesystem
buff. cache
char.
block
device drivers
kernel level
hardware level
Da questo schema ricaviamo due elementi utili:
• Due soli blocchi funzionali: la gestione dei files e quella
dei processi
• I device sono mascherati dietro il filesystem: ne
discende che ad ogni device si accede come ad un file.
Il principio fondamentale di UNIX: semplificare.
Ad ogni cosa si accede tramite:
open, close, read, write, ioctl
Una lettura consigliabile:
Maurice Bach, THE DESIGN OF THE UNIX OPERATING SYSTEM,
Prentice Hall International Editions
Cos’e` un file?
A questo siamo abituati
con il VMS:
accesso:
diretto/sequenziale
formato del record:
fisso/variabile
lunghezza del record
Secondo il principio della semplificazione, in UNIX
un file e` una sequenza di bytes.
Cio` ha conseguenze molto importanti
• Il sistema operativo non conosce la differenza tra un
record di lunghezza fissa ed uno di lunghezza variabile, ne`
sa quanto sia lungo un record. La gestione del filesystem e`
piu` semplice.
• In questo contesto, la conoscenza di come il file e`
organizzato e` demandata all’applicazione.
E` lecito chiedersi, a questo punto, cosa siano gli oggetti piu`
comuni, come un disco o un terminale alfanumerico
Due directory interessanti
/dev
/proc
Notare il flag. In VMS conosciamo i flag r,w,x (file
permissions). Qui ne aggiungiamo un altro: la lettera d
indica che il file deve essere interpretato come
directory.
• A seconda del valore di quel flag, il sistema e` in grado di
sapere COME un certo file deve essere trattato.
• Nel caso di un file di tipo directory, il flag dice al sistema
che in quel file trovera` un elenco di altri file, ed i relativi
puntatori per potervi accedere.
Vediamo piu` in dettaglio /dev e /proc, perche` illustrano bene
il principio “di tutto un file”.
/dev ovvero: dove sono finiti i dischi???
dischi locali:
/dev/sda, ...
unita` nastro:
/dev/st0, ...
terminali:
/dev/tty0, ...
Notare ancora il flag:
• b significa block special file: file da leggere a
blocchi attraverso la buffer cache.
Questo e`, tipicamente, un disco: un oggetto i cui
blocchi sono raggiungibili direttamente, ed il cui
contenuto e` utile mantenere - per quanto
possibile - in una cache.
• c significa character special file: file da leggere
sequenzialmente un carattere alla volta, senza
bufferizzare i byte.
Tradizionalmente si tratta di un terminale (da cui
la definizione character): un file da cui si legge in
sequenza un carattere (byte) alla volta. Questa
definizione si applica anche ad una unita` nastro.
/proc ovvero: spiare il sistema
Ogni processo
e`identificato da
un numero (PID);
ognuna di queste
directory contiene
dati statistici sui
processi
Questi files
contengono
informazioni e
statistiche
generali sul
sistema
Statistica di uso
della memoria
Informazioni sulla
configurazione di interrupt
/proc e` visto come directory sulla quale e` montato un
filesystem; in realta` e` una finestra aperta sulla memoria di
sistema, dalla quale e` possibile ricavare lo stato attuale del
kernel ed informazioni statistiche sui device e sui processi.
--> Nota: non tutti i sistemi UNIX usano /proc: lo si puo`
trovare, ad esempio, su Linux e su Digital Unix, ma non su AIX.
Conseguenze del paradigma “di tutto un file”.
Ovvero: un digressione istruttiva ...
Supponiamo che il disco /dev/sda1 contenga un filesystem.
Vedremo meglio in seguito cosa sia; qui ci basta dire che
e` un albero di files e directories.
1) /dev/sda1 e` un file = sequenza di byte. Su di esso possiamo
usare open-close-read-write.
Ammetteremo che il piu` delle volte non sia molto utile.
Ricordiamo tuttavia che la creazione di un filesystem
avviene accedendo al disco proprio in questo modo.
2) Per accedere al filesystem eseguiamo:
mount /dev/sda1 /home
(spiegheremo meglio questo comando tra poco)
Cosa abbiamo fatto? Semplice: agganciare il filesystem di
/dev/sda1 su quello principale (cioe` sul root filesystem)
• Il file /home (=directory) non contiene piu` un elenco di
files, ma gli viene assegnato un flag di mount point.
Transitando su di un mount point, il sistema sapra` di
doverlo interpretare come punto di accesso ad un altro
filesystem, residente su di un altro disco.
• D’ora in poi il contenuto di /dev/sda1 e` agganciato al
tronco principale, e sintatticamente indistinguibile da esso.
non trascurabile corollario:
Siccome anche i dischi remoti sono agganciati con lo stesso
meccanismo, si forma un unico albero, come se si trattasse di
un unico immenso disco. !! Semplicita`, eleganza !!
Cio` che forse non e` evidente a tutta prima e` che, dopo
aver eseguito il mount (ed ammesso che si abbiano i privilegi
necessari per fare la seguente, piratesca, operazione), siamo
in grado di vedere il disco - contemporaneamente - in due
modi.
/dev/sda1:
stream di
bytes
/home: un
ramo del
filesystem
E` meglio discuterne solo in modo accademico: potemmo
infatti usare open-close-read-write per accedere a
/dev/sda1, al posto che passare attraverso il filesystem...
ma sconsiglio caldamente di farlo se volete ritrovare
intatti i vostri file !!!
pipes ovvero l’idraulica fatta con i file.
Una delle caratteristiche peculiari di UNIX sono le PIPES,
altrimenti detti pipe special files.
Ne esistono di due tipi
• Named pipes: residenti sul filesystem ed accessibili a
qualunque processo, ammesso che la protezione del file lo
permetta
• Unnamed pipes: sono volatili ed accessibili solo al processo
creatore ed ai suoi discendenti.
Le pipes sono un potente strumento di comunicazione tra
processi
Un processo
scrive da un lato
Un processo legge
dall’altro
Oltre a creare un canale di comunicazione di
tipo FIFO tra due processi, la pipe provvede
anche alla loro sincronizzazione.
• Il processo (o i processi) in lettura sono costretti in stato di
wait fino a quando quello (o quelli) in scrittura non cominciano
a riempire la pipe.
• Viceversa, il processo in scrittura viene bloccato quando
quello in lettura non estrae i dati dalla pipe ad una velocita`
sufficiente.
• Tutto cio` e` controllato dal sistema: l’applicazione esegue
solo open-close-read-write.
Vedremo piu` avanti molti esempi di uso delle pipe.
Cosa succede in pratica quando si usa una pipe?
Per la seguente discussione, prepariamo una
rappresentazione di un processo e delle sue unita`
logiche di I/O
unita` 2:
standard error
2
unita` 1:
standard output
1
0
unita` 0:
standard input
Ad esempio, il comando cat file fa si` che la shell crei un
sottoprocesso in cui viene eseguito cat, e collega il file file
all’unita` 0; le unita` 1 e 2 restano agganciate alla shell
principale.
filesystem
shell
2
file
0
1
Vediamo ora cosa succede con il comando:
cat file | grep -i string | more
La shell crea tre sottoprocessi ed aggancia le unita` di I/O
a delle pipe, in modo che i 3 processi possano leggere e
scrivere l’uno dall’altro con la corretta sincronia.
Durante l’esecuzione, dopo aver usato ctrl-Z, possiamo
usare ps per sorvegliare i sottoprocessi della nostra shell:
[1]+ Stopped
bach2:~$ ps
PID TTY STAT
1759 p1 S
1783 p1 T
1784 p1 T
1785 p1 T
1786 p1 R
cat file | grep -i string | more
TIME COMMAND
0:00 -bash
0:00 cat file
0:00 grep -i string
0:00 more
0:00 ps
A cio` corrisponde lo schema seguente:
Qui riceviamo il risultato
finale
shell
2
file
filesystem
0
1
cat
pipe
2
0
pipe
1
grep
2
0
more
1
Scarica

file - INFN