su questo sito

Transcript

su questo sito
Principali Revisioni
•
v. 1.0, novembre 2000
•
v. 1.1, febbraio 2002
•
v. 1.2, aprile-giugno 2002
•
v. 1.3, dicembre 2002
•
v. 1.4, aprile 2003
Il presente testo contiene materiale dell’autore di proprietà della Axis&Agix Sarl (Boulogne, Francia) e della AX
Digital Systems Srl (Pomezia, Italia), il cui uso è stato consentito esclusivamente per le attività didattiche dell’autore
stesso.
Pertanto l’uso e la riproduzione dell’opera, in qualsiasi modalità, sono consentiti a titolo gratuito per i soli fini personali
degli studenti dei corsi tenuti dall’autore.
Ogni altra forma di utilizzazione potrà avvenire soltanto previa richiesta esplicita e successiva autorizzazione per
iscritto dall’autore, sentito il parere dei coproprietari dell’opera.
!#"%$'& )(*%+ ! ",-! ! $',%.! 0/ ,'&1-2$!43'! * "%!456,7)" *98: !#" * 5
3 ;=<> ?
@A BDCEGF BDH
1. Introduzione
Il presente testo è destinato agli studenti dei corsi di laurea in Ingegneria Informatica e in Ingegneria delle
Telecomunicazioni dell’Università Roma 1 "La Sapienza", sede distaccata di Latina, e agli studenti dei
corsi di laurea e di laurea specialistica in Ingegneria Gestionale, Ingegneria delle Telecomunicazioni e
Ingegneria Elettronica dell’Università Roma 2 "Tor Vergata", come parte dei sussidi didattici per i corsi di
"Sistemi Operativi" tenuti dall’autore; il testo è completato, per ciò che attiene alla parte pratica di
programmazione di script shell, da una dispensa gemella, "Esercitazioni di programmazione in linguaggio
shell".
Allo stato attuale, la dispensa è in una forma leggermente incompleta; alcune parti necessitano di una
revisione e/o riorganizzazione del materiale. Lo studente è invitato, per queste parti, a far riferimento a
quanto detto nelle lezioni.
1.1 Storia
Il Sistema Operativo UNIX1 è stato originalmente concepito e realizzato nei primi anni anni ’70, da due
ricercatori dei Bell Laboratories2 (Ken Thompson e Dennis Ritchie), e si è diffuso commercialmente a
partire dagli anni ’80.
Le prime versioni giravano su sistemi della Digital Equipment Corporation3 (DEC): dapprima su un PDP-7,
poi (dal 1971) su quelli della famiglia PDP-11, quindi (1979) sui VAX-11. Nel 1981, con la versione
PC/IX, UNIX fa la sua prima apparizione nella gamma dei Personal Computer IBM e compatibili.
La storia della nascita e dell’evoluzione di questo sistema è reperibile in molti testi, tra cui [Bach 1986],
[Silberschatz, Galvin e Gagne 2003], [Asta 1984] e altri; esistono poi due numeri speciali del The Bell
System Technical Journal, dedicati esclusivamente a UNIX, che illustrano molti aspetti interessanti del
sistema, della sua storia, delle sue motivazioni originali e delle sue caratteristiche ([BSTJ 1978], [BSTJ
1984]). Qui ci si limiterà ad esporre succintamente la cronologia essenziale degli sviluppi e delle versioni
più importanti. Una cronologia più dettagliata è riportata in Appendice 1.
- 1969: Thompson e Ritchie, reduci dal progetto MULTICS4, iniziano a lavorare su un sistema di
filesystem e di gestione dei processi, scritto parte in assembler e parte in Fortran; sperimentazioni su un
PDP-7
1.
La proprietà del nome UNIX ha una lunga storia alle spalle; in origine, UNIX era un marchio registrato dei Bell Laboratories, poi
della AT&T, e successivamente di varie altre organizzazioni; oggi UNIX è un marchio registrato di The Open Group
(http://www.opengroup.org), un consorzio industriale senza fini di lucro.
2.
I Bell Laboratories erano allora una filiale della Western Electric Company, casa madre della AT&T (American Telephone and
Telegraph Company); le prime versioni di UNIX si acquistavano dalla Western Electric, e solo successivamente dalla AT&T.
3.
La Digital Equipment Corporation è stata successivamente acquisita dalla Compaq.
4.
Progetto per lo sviluppo di un Sistema Operativo di tipo interattivo e multiutente a cui parteciparono l’MIT (Massachusetts
Institute of Technology), General Electric, e Bell Laboratories; il risultato fu un sistema concettualmente interessante ma
elefantiaco nella sua implementazione. Ciò deluse i ricercatori dei Bell Laboratories, che finirono per ritirarsi dal progetto.
V. Asta - Introduzione a Unix e GNU/Linux
3
- 1971: viene pubblicata, internamente ai Bell Laboratories, la prima edizione del manuale di UNIX; le
prime versioni, fino al 1979, saranno identificate col numero di edizione del manuale. Viene effettuato il
porting su PDP-11
- 1973: riscrittura del sistema in linguaggio C, sviluppato da Ritchie
- 1973: UNIX Versione 3 (terza edizione del manuale), distribuita alle Università di Berkeley e di Columbia
- 1975: V.6, prima versione commercializzata; primi esperimenti di porting su calcolatori non DEC
- 1979: V.7, prima versione riscritta senza alcuna dipendenza concettuale dall’architettura dei PDP-11;
prime licenze con diritto di ridistribuzione binaria (fino ad allora, l’unico tipo di distribuzione era tramite
i sorgenti); prima versione UNIX per minicalcolatori VAX (UNIX 32/V)
- 1980: Microsoft introduce sul mercato Xenix, una delle più famose versioni commerciali (ridistribuzione
binaria) di UNIX
- 1981: AT&T subentra a Western Electric (che finora era stato l’organismo di vendita delle licenze del
sistema) per la commercializzazione di UNIX; nuova versione, denominata System III
- 1983: versione System V release 15; Berkeley pubblica la versione 4.2 per VAX, una delle più
importanti, che vede tra l’altro la prima implementazione dei protocolli di rete TCP/IP
- 1984: System V rel. 2
- 1986: System V rel. 3; molti sistemi UNIX commerciali, tra cui SCO UNIX per architettura IBM-PC, si
basano su questa versione
- 1988: System V rel. 3.2
- 1989: System V rel. 4, versione che riunifica tutte le caratteristiche di System V e quelle di Berkeley
Unix.
- 1991: Linus Torvalds, all’epoca studente di informatica all’università di Helsinki, inizia a sviluppare
LINUX, una riscrittura indipendente di UNIX, con l’intento di renderne liberi i sorgenti; è rapidamente
seguito da moltre altre persone che collaborano al progetto.
- 1994: Versione 1.0 di LINUX
- 2001: Versione 2.4 di LINUX
Nell’arco della sua storia, il sistema ha visto la nascita e l’introduzione sul mercato di molte
implementazioni, più o meno fedeli allo standard AT&T, tutte legate all’evoluzione sia dei microprocessori
Intel (8088/86, 80286, 80386 e seguenti) e di altri costruttori (inizialmente soprattutto Motorola
68000/88000, Zilog Z-8000, National Semiconductors 32000, poi SUN Sparc e altri), sia delle varie release
di System V. Oggi, il sistema GNU/LINUX è sicuramente l’implementazione su IBM-PC più nota e diffusa,
e una tra le più valide in generale.
Lo scopo di questo testo è di fornire delle nozioni di base su UNIX (di norma con riferimento al contesto
IBM-PC e GNU/LINUX, anche se non necessariamente limitate ad esso), con particolare attenzione agli
aspetti dell’utilizzazione a livello utente e con alcuni accenni alle problematiche di amministrazione di un
sistema.
1.2 Caratteristiche generali del kernel
Nell’uso corrente, il termine UNIX si riferisce genericamente ad una famiglia di Sistemi Operativi, tutti
derivati in vario modo dal lavoro originale dei Bell Laboratories; si tratta di un moderno sistema timesharing, multi-utente e multi-task. Una distribuzione UNIX comprende il kernel del sistema più numerosi
applicativi e programmi di utilità.
Il kernel si occupa di diversi compiti indispensabili al funzionamento del sistema, tra cui:
5.
La versione System IV non ha mai visto la luce al difuori dei Bell Laboratories.
V. Asta - Introduzione a Unix e GNU/Linux
4
— inizializzazione
— gestione dei processi (priorità, cambiamenti di stato etc.)
— gestione delle risorse (CPU, memoria primaria e secondaria, periferiche etc.)
— gestione dei filesystems
— gestione della comunicazione tra processi e tra sistemi (protocolli di rete)
È importante sottolineare che il kernel gestisce solo le funzioni essenziali dei processi: dati, interruzioni,
ingressi ed uscite. Tendenzialmente, ogni altro compito è separato e realizzato da programmi indipendenti,
a livello utente, come ad esempio la shell che è l’interprete dei comandi UNIX.
Questo tipo di approccio è solo uno tra i numerosi elementi di novità introdotti dal sistema UNIX, che
storicamente è stato un sistema "rivoluzionario" da molti punti di vista; tra le molte verità universalmente
accettate fino allora, e che sono state ribaltate da UNIX, suscitando inizialmente non poche perplessità tra gli
addetti ai lavori, si possono ricordare le seguenti:
— Non è vero che l’interprete di linguaggio di comandi deve essere implementato nel kernel del Sistema
Operativo
In UNIX, la shell è un programma qualsiasi come gli altri, che per di più gira senza nessun particolare
privilegio; ne esistono anzi numerose varianti, e ciascun utente può scegliere il programma che più
gli è congeniale
— Non è vero, analogamente, che i principali sottosistemi devono essere almeno parzialmente
implementati nel kernel
In UNIX, lo spooler di stampa, il sottosistema di accoglienza e autenticazione degli utenti, tutti i
server Internet, quelli di basi di dati e così via, sono implementati esclusivamente a livello utente; il
kernel ne ignora praticamente l’esistenza
— Non è vero che il kernel di un Sistema Operativo deve essere scritto tutto in linguaggio assembler,
pena un grave abbassamento delle prestazioni ottenibili
In UNIX, tutto il kernel è scritto in linguaggio C6, compresi i device drivers, salvo una minima parte
in assembler; nella Versione 7 di UNIX, la prima ad essere diffusa in modo significativo al difuori dei
Bell Laboratories, il kernel si componeva in tutto di circa 10.000 righe di codice C e 1.000 righe di
assembler (cioè il 9,1% del totale); di queste, 200 lo erano per ragioni di efficienza ed 800
effettuavano funzioni hardware impossibili in linguaggio C, come gestione del Memory Management
o altro
— Corollario: Non è vero che sono necessarie squadre di decine e decine di programmatori per
realizzare il kernel di un Sistema Operativo
Se si pensa di realizzarlo in assembler, la mole di lavoro è tale da richiedere molte persone; ma grazie
all’uso di un linguaggio evoluto come C, UNIX è stato interamente progettato e (nelle sue prime
versioni) realizzato da due persone (come già detto, in tutto sono bastate 11.000 righe di codice7); ciò
ha avuto forti conseguenze positive per ciò che riguarda la compattezza e la coerenza della logica di
tutto il sistema, che è stato concepito e realizzato soltanto da due menti8
6.
Il linguaggio C fu progettato e realizzato da Dennis Ritchie esattamente per il proposito di scrivere UNIX in linguaggio evoluto;
ciò indica chiaramente l’orientamento originale di questo linguaggio, concepito come uno strumento di implementazione di
sistemi, potente ma al tempo stesso capace di permettere operazioni di basso livello che un tempo venivano spesso effettuate
solo in assembler.
7.
Le cose sono evolute non poco negli anni; oggi il kernel di LINUX (versione 2.4.18) consta di oltre 3.800.000 righe di codice
(comprendendo il codice per tutte le piattaforme supportate); ma la proporzione tra codice in assembler e codice in C è ancora
nettamente diminuita, e oscilla oggi tra l’uno e il cinque percento (per la piattaforma Intel IBM-PC, senza considerare i device
drivers, il conto è approssimativamente di 9.000 righe in assembler contro 670.000 righe in C, cioè un rapporto dell’1.3%).
8.
Questa strategia di sviluppo è stata poi rivoluzionata ulteriormente dal modello di sviluppo di LINUX e di tutto il software libero
− vedi oltre, nel paragrafo "Il fenomeno del Software Libero" (paragrafo 1.5 pag. 10).
V. Asta - Introduzione a Unix e GNU/Linux
5
— Non è vero che un Sistema Operativo debba essere concepito e realizzato per uno specifico tipo di
hardware, quindi per una sola macchina o al massimo per una famiglia di macchine simili di uno
stesso costruttore
UNIX è stato scritto in linguaggio C proprio perchè, fin dall’inizio, lo si voleva portabile ad altre
architetture hardware; il primo porting ad un’architettura hardware diversa dai PDP-119 è stato
realizzato già prima del rilascio della Versione 7, ed oggi il sistema è disponibile praticamente su tutti
i tipi di macchine esistenti sul mercato, dagli IBM-PC agli Apple McIntosh o ai PowerPC, passando
attraverso i mini-computer di tutti i fabbricanti (HP, IBM, Bull, DEC/Compaq, Data General e così
via) fino ai mainframe della IBM e ai supercomputers della Cray Inc.
— Non è vero che il Sistema Operativo debba prevedere un certo numero di tipi di files, gestiti a livello
del kernel
UNIX rifiuta di occuparsi di questo aspetto, e rimane perfettamente neutrale; un file, per il kernel, è
proprio quello che è, cioè semplicemente un array ordinato di bytes, numerati da 0 in su. Qualunque
altra struttura di dati (file di testo o binari, records, lunghezza fissa o variabile e così via) è
interamente lasciata ai livelli applicativi utente
— Non è vero nemmeno che un Sistema Operativo debba imporre una struttura per i nomi dei files,
come ad esempio del tipo <nome>.<estensione>
Il kernel di UNIX ignora cosa sia un’estensione del nome di un file; per UNIX, un tale nome è
semplicemente una stringa di caratteri assolutamente arbitrari: il carattere ‘.’ è un carattere come un
altro, ed un nome come ".a?...!" è perfettamente legale. Un compilatore, quanto a lui, distingue tra
nomi di file che finiscono per .c o per .s o .o, e li interpreta come indicatori di formato dei file; ma
questo avviene appunto a livello di programmi utente.
In sintesi, i principali elementi di interesse di un sistema UNIX possono essere così riassunti ([Bach 1986]):
— Kernel multi-utente e multi-task; ciascun utente può eseguire più processi simultaneamente.
— Capacità di gestione asincrona dei processi.
— Organizzazione gerarchica (ad arborescenza) dei filesystems, caratterizzata da un’implementazione
efficiente e semplicità di manutenzione.
— Supporto per files non strutturati, basato su una rappresentazione semplice e coerente del formato dei
files, come array di bytes, ciò che rende i programmi più semplici da scrivere.
— Banalizzazione dei volumi di memoria secondaria (dischi), visti come un’unica arborescenza di files
dall’utente e dal programmatore grazie a un meccanismo di montaggio logico di filesystems.
— Banalizzazione dei meccanismi di I/O, gestiti in modo univoco (dal punto di vista dell’utente e del
programmatore) per
- files
- periferiche (dispositivi)
- comunicazione tra processi.
— Interfaccia tra kernel e processi utente chiaramente definita (chiamate di sistema, il cui codice nel
kernel è isolato in appositi file sorgente).
— Interfaccia tra kernel e periferiche esterne chiaramente definita (device drivers, il cui codice nel
kernel è isolato in appositi file sorgente).
9.
Si trattava di una macchina Interdata 8/32, che era stata scelta proprio perchè aveva caratteristiche hardware notevolmente
diverse da quelle dei PDP-11, così da testare adeguatamente l’effettiva portabilità del sistema (vedi [Johnson e Ritchie 1978]).
V. Asta - Introduzione a Unix e GNU/Linux
6
— Kernel rigenerabile e configurabile.
— Sistema (kernel e utilities) scritto in linguaggio evoluto (linguaggio C), e quindi facile da leggere,
capire, cambiare, e portare a nuove macchine.
— Sorgenti disponibili, o commercializzati10.
— Interfaccia utente semplice e potente.
— Interfaccia di programmazione semplice e potente, con un numero relativamente ristretto di chiamate
di sistema.
— Insieme di primitive che permettono e incoraggiano la costruzione di applicazioni complesse a partire
da programmi più semplici.
— Programmazione indipendente dall’hardware: il sistema nasconde totalmente all’utente i dettagli
dell’architettura della macchina, permettendo così di scrivere programmi che girano inalterati su
differenti implementazioni hardware.
— Sistema non legato commercialmente a nessun hardware vendor, e pertanto intrinsecamente portato a
favorire meccanismi e politiche di interoperabilità tra macchine diverse.
Come già evidenziato, il kernel di un sistema UNIX o derivato si può considerare diviso in almeno in tre
parti, mostrate nella Figura 1:
— kernel interno
— strato delle chiamate di sistema
— strato dei device drivers.
Le ultime due costituiscono l’interfaccia software tra il kernel interno e, rispettivamente, i processi utente e
le periferiche fisiche.
Il kernel è la sola parte del codice che in genere l’utente non può modificare, ed è per questo che nella
filosofia di UNIX deve operare il minimo di decisioni possibili, in modo da rimanere più neutro possibile
rispetto a futuri miglioramenti ed estensioni; viceversa, tutto ciò che è implementato a livello di processo
utente è relativamente semplice da sostituire, e pertanto, ovunque la scelta si sia stata possibile, si è sempre
teso ad usare il modo utente per l’implementazione di funzionalità, salvo quando ciò implicherebbe pesanti
conseguenze sulle prestazioni.
Pertanto il kernel interno (o core kernel) si occupa concettualmente di pochissime cose; essenzialmente
— inizializzazione del sistema
— gestione dei processi
— gestione delle risorse (multiplexaggio della CPU, allocazione e protezione della memoria, etc.)
— gestione dei filesystems
— gestione dei meccanismi di protezione
— gestione "astratta" (secondo una visione canonica, indipendente dall’hardware reale) delle
periferiche.
10.
Come già detto, fin dalle prime versioni dei Bell Laboratories i sorgenti di UNIX sono sempre stati disponibili, benchè
rigorosamente protetti da meccanismi di licensing molto stringenti; l’acquisto di una licenza sorgente del Sistema Operativo era
anzi inizialmente l’unico modo di ottenere UNIX. Tale licenza, comprensiva di tutto il kernel e di tutte le utilities applicative, era
molto costosa per società con fini di lucro, ma era venduta ad un prezzo simbolico (500 dollari US) per le università ed altre
istituzioni di tipo educativo o di ricerca. In ogni caso, la distribuzione consisteva in un nastro magnetico bootstrappabile, e due
fogli di carta stampati con stringatissime istruzioni di installazione, che terminavano con la frase ormai celeberrima "Good
luck." ("Buona fortuna."). Tutta la manualistica era on-line, e andava stampata a cura dell’acquirente. Il contratto di licenza
specificava chiaramente che nessuna forma di assistenza era prevista. Erano tempi eroici.
V. Asta - Introduzione a Unix e GNU/Linux
7
Kernel
User
Proc.s
System
Calls
Kernel interno
Device
Drivers
Devices
Figura 1. - Struttura del kernel di UNIX.
Esistono d’altra parte numerose utilities per lo sviluppo di software e praticamente per qualunque altra
attività di interesse:
— interpreti di linguaggio di comandi, in varie forme e varianti,
— editor, compilatori, interpreti, debuggers, sistemi integrati di sviluppo software (IDE),
— analizzatori lessicali e sintattici,
— suites di programmi integrati per l’automazione d’ufficio,
— utilities per la gestione e il trattamento di documenti grafici, sonori, video, e in genere per
applicazioni multimediali
— utilities per la gestione di progetti software, inclusa la loro documentazione,
— ambienti desktop grafici, sia a livello utente che di sviluppo di applicazioni
— sistemi di gestione di basi di dati,
— programmi e utilities per applicazioni scientifiche,
— servers e clients per applicazioni distribuite e per servizi interattivi su rete Internet (TCP/IP) ed altre
reti: posta elettronica, news, groupware, World-wide Web, DNS (servizio di nomi a dominio), FTP
(trasferimento di files), sistemi di filesystems distribuiti, login remoto, e così via.
Com’è noto, il kernel costituisce una parte tra le più importanti della distribuzione del Sistema Operativo,
ma relativamente piccola, in termini di righe di codice, rispetto al totale (meno del 5%; spesso solo il 2 o
3%).
È opportuno precisare fin d’ora che, nel caso di LINUX, questo termine si riferisce normalmente al solo
kernel, opera del suo ideatore e iniziatore, Linus Torvalds, e dei vari collaboratori che si sono via via
aggiunti; mentre l’insieme del kernel e dei vari programmi applicativi e sottosistemi, cioè la distribuzione
V. Asta - Introduzione a Unix e GNU/Linux
8
completa del Sistema Operativo, viene appropriatamente denominato GNU/LINUX, poichè si basa in
larghissima parte su tutto il lavoro (il cosiddetto GNU Toolkit) derivato dal progetto GNU della Free
Software Foundation (http://www.fsf.org, http://www.gnu.org)11, di cui si dirà meglio in seguito.
1.3 Tipi di UNIX
È importante distinguere almeno tra le seguenti tipologie di kernel e relative distribuzioni, che si
differenziano per numero e tipo di chiamate di sistema, programmi e applicazioni disponibili, e altri aspetti:
•
•
Tipi fondamentali:
UNIX AT&T
La linea originale, partita dagli sviluppi iniziali presso i Bell Laboratories,
attraverso le release principali: Version 6, Version 7, System III, System V,
System V release 3, System V release 4.
Unix BSD
"Berkeley Software Distribution", derivata inizialmente dalla Version 7;
distribuita dalla UCB (University of California at Berkeley), solo per licenziatari
di UNIX AT&T.
Tipi derivati (distribuzioni commerciali):
Unix-based
Derivati in genere da una licenza sorgente AT&T con diritto di ridistribuzione
esclusivamente binaria; spesso queste distribuzioni riuniscono le caratteristiche di
UNIX AT&T e quelle di UNIX BSD; molte tra di esse sono state realizzate dai
costruttori di macchine hardware (Hewlett-Packard, Digital/Compaq, IBM etc.).
tra queste si citano: Xenix, SCO Unix, Unixware (tutte e tre per generiche
macchine IBM/PC), Ultrix (per macchine Digital Equipment Corporation),
HP/UX (per macchine Hewlett-Packard), DG/UX (Data General), AIX
(macchine RS-6000 IBM e Bull), SunOS e SOLARIS (Sparc di SUN), IRIX
(Silicon Graphics Inc.), ... (la lista è lungi dall’essere esaustiva).
Unix-like
Si tratta di riscritture indipendenti, non vincolate al meccanismo di licensing
della AT&T; si citano: Idris, Coherent, Regulus, Unos, Tunis, Xinu, Minix,
FreeBSD, OpenBSD, BSDI, LINUX, etc.
1.4 Utilità dello studio di LINUX
Lo studio e la pratica del kernel LINUX riveste un ruolo centrale nei corsi di Sistemi Operativi di molte
Università nel mondo intero12, per diversi motivi:
— È un Sistema Operativo compatibile con UNIX, da cui eredita tutta la potenza, l’efficienza, la
modularità e la robustezza dell’ambiente di lavoro [Kernighan e Pike 1984] e il pieno supporto multitask e multi-utente.
— È ampiamente diffuso sia in ambienti accademici che industriali.
— Il codice del kernel è aperto e liberamente utilizzabile da chiunque, in particolare per scopi di studio;
LINUX rappresenta quindi un’occasione ideale per toccare con mano il codice di un vero Sistema
Operativo, apprezzando tutte le scelte fatte, osservando come le teorie e gli algoritmi studiati nella
parte di base del corso si siano concretizzati nella realizzazione pratica di un sistema reale, e
considerando quali compromessi siano stati adottati, nel classico processo di intermediazione tra
teoria, pratica ed esperienza pregressa che è tipico di tutte le attività ingegneristiche. Un tale
approccio è ovviamente impossibile con sistemi proprietari come quelli della Microsoft, con i quali
11.
Le due URL http://www.fsf.org e http://www.gnu.org riportano al medesimo sito WEB.
12.
Un’inchiesta della Addison-Wesley, citata in [Nutt 2001], indica che già nel 1998, su un campione di 78 Università, 43
insegnavano aspetti di implementazione interna (OSinternals) nel corso introduttivo di Sistemi Operativi; di queste, 26 usavano
una variante di UNIX come sistema di studio, 13 usavano LINUX, 10 una versione non specificata di UNIX, e 3 usavano Minix; 8
Università hanno dichiarato di utilizzare un altro tipo di Sistema Operativo, e le rimanenti 9 non hanno specificato il sistema
utilizzato.
V. Asta - Introduzione a Unix e GNU/Linux
9
lo studio si ferma inevitabilmente alle descrizioni generiche degli algoritmi, per ciò che è dato sapere
all’esterno dalle pubblicazioni esistenti.
— È un sistema moderno ed altamente competitivo in termini di prestazioni, con caratteristiche
importanti quali
- vera multiutenza e vero multitasking su un’unica macchina
- supporto per processi e threads a livello kernel
- multitasking avanzato, con scheduling della CPU con prelazione (preemptive scheduling) e
supporto per task "soft real-time"
- meccanismi di protezione della memoria
- memoria virtuale
- supporto per multiprocessing simmetrico (macchine multi-CPU)
- compatibilità con lo standard POSIX13
- supporto per TCP/IP e numerosi altri protocolli di rete
- interfaccia utente grafica (con possibilità di scelta tra più ambienti desktop)
- alta scalabilità in termini di carico di lavoro e di modelli e capacità delle macchine hardware (il
sistema è utilizzato con successo su macchine che vanno dalla semplice workstation IBM-PC al
mainframe IBM 390)
- alta affidabilità e prestazioni, in termini di stabilità e di velocità.
Ma il sistema GNU/LINUX riveste un’importanza tutta particolare soprattutto perchè è un sistema basato sul
modello Software Libero, oltre ad essere stato il primo progetto di notevole successo in quest’ambito. Ciò,
come sarà chiaro nel seguito, conferisce interesse all’argomento non solo per motivi tecnici o legati
all’ampia diffusione, ma anche per motivi di tipo sociologico e di sviluppo dei futuri modelli di lavoro e di
business nel software.
1.5 Il fenomeno del Software Libero
1.5.1 Introduzione
A partire dall’inizio degli anni ’90 il mondo dell’informatica ha assistito al lento ma progressivo affermarsi
di un fenomeno nuovo, che a giusto titolo può essere considerato ormai come una vera e propria rivoluzione
in atto su scala mondiale: la nascita e la diffusione del Software Libero. Si tratta di un modo radicalmente
nuovo di considerare l’organizzazione del lavoro di sviluppo software, basato su un modello di tipo aperto,
cooperativo e volontario di partecipazione allo sviluppo e al miglioramento dei prodotti software; il
fenomeno sta prendendo piede in modo inarrestabile, e un numero sempre crescente di osservatori sia
tecnici che economici ritiene che possa rivoluzionare completamente il mercato.
Il Software Libero è al tempo stesso un modello di metodologia di lavoro per la produzione del software, e
un modello di strategia di business [Behlendorf 1999]14.
Grazie a tale fenomeno, programmatori e sviluppatori che lavorano in varie parti del mondo riescono a
condividere il loro lavoro e il codice risultante in modo più efficiente e produttivo di quanto non sia mai
stato fatto in precedenza. GNU/LINUX, Apache e Netscape rappresentano tre casi notevoli di successo
13.
POSIX è uno standard di interfaccia di Sistema Operativo, promosso dalla ISO/IEC, IEEE, e The Open Group, che mira a
definire le caratteristiche di un Sistema Operativo aperto, in pratica di tipo UNIX. Per maggiori dettagli, vedi
http://std.dkuug.dk/jtc1/sc22/wg15/ . Molti sistemi (di tipo UNIX e non) tendono ad essere compatibili con questo standard.
14.
L’interesse per questo fenomeno dal punto di vista economico e di modello di business è in forte crescita negli ultimi anni, e il
Software Libero è ormai oggetto di analisi sempre più approfondite da parte di ricercatori e studiosi di economia aziendale;
oltre al lavoro di Behlendorf, si citano [Dalle e Jullien 2000], [Kuan 2001], [Garzarelli 2002].
V. Asta - Introduzione a Unix e GNU/Linux
10
nell’adozione del modello Software Libero.
Per apprezzare appieno l’impatto di tale metodologia e le implicazioni da e verso il mondo di LINUX, è
opportuno dettagliare alquanto la genesi, il tipo di approccio e le caratteristiche del Software Libero.
Una buona esposizione informale dell’idea alla base del Software Libero è la seguente, derivata da
http://www.opensource.org/advocacy/index.html:
"Se i programmatori possono leggere, ridistribuire, e modificare il codice sorgente di un dato
software, il software evolve. La gente lo migliora, lo adatta, ne corregge gli errori. E ciò può
accadere ad una velocità che, per chi è abituato al lento ritmo di sviluppo convenzionale del
software, risulta impressionante.
Questo rapido processo evolutivo produce software migliore rispetto al tradizionale modello
chiuso, nel quale solo pochi programmatori possono vedere il codice sorgente e tutti gli altri
devono usare ciecamente un blocco opaco di bits. La Open Source Initiative esiste proprio
per portare questo modello verso il mondo commerciale."
È opportuno precisare subito che, per ciò che attiene alla terminologia, e al tipo di approccio al problema,
esistono diverse scuole di pensiero, di cui le principali sono le seguenti:
— Free Software - è il termine originale, coniato dal Richard M. Stallman, fondatore della Free Software
Foundation (FSF - http://www.fsf.org); riflette un approccio di tipo più purista e integralista
— Open Source - termine che fa capo a Bruce Perens ed Eric S. Raymond, della Open Source Initiative
(OSI - http://www.opensource.org); riflette un approccio più orientato alle esigenze di mercato e di
profitto delle aziende.
Tali differenti denominazioni riflettono in ultima analisi diverse posizioni, di carattere tecnico, sociologico,
politico e di visione del business, presenti tra gli operatori del settore. Un’analisi dettagliata delle
differenze esistenti esula dallo scopo del testo; alcuni buoni punti iniziali per approfondire l’argomento
sono
le
URL
http://www.fsfeurope.org/documents/whyfs.en.html,
http://www.opensource.org/docs/history.html
e
http://www.linux.it/GNU/softwarelibero.shtml,
e
l’introduzione a [DiBona et al. 1999]. Alcuni tendono oggi ad utilizzare il termine Libre Software, che
riflette forse un approccio più neutro ed equidistante tra le parti; altri ancora si servono del termine FLOSS,
che è l’acronimo di "Free/Libre and Open Source Software". In questo testo verrà consistentemente
utilizzata la dizione "Software Libero" (con le iniziali in maiuscolo), come termine generico.
Ad ogni modo, come fa giustamente notare F. Potortì [2002], "La voluta neutralità del movimento Open
Source verso gli aspetti etici e politici del software libero è la caratteristica sostanziale che lo distingue
dalla filosofia del Software Libero (Free Software), che al contrario pone l’accento sulle motivazioni ideali.
Parlare di Software Libero piuttosto che di Open Source è una questione politica piuttosto che pratica; i due
movimenti concordano infatti sulle licenze considerate accettabili, ed hanno obiettivi e mezzi comuni."
1.5.2 Licenze Software Libero
Esistono diverse licenze di tipo Software Libero, ciascuna con le sue caratteristiche e le sue più o meno
aperte concessioni d’uso del software; una lista delle principali è dettagliata in
http://www.gnu.org/licenses/license-list.it.html. Senza entrare in un’analisi dettagliata dell’argomento,
quella che è di gran lunga più utilizzata e conosciuta è comunque la licenza GNU GPL (General Public
License - http://www.gnu.org/copyleft/gpl.html), messa a punto dalla FSF, e quelle da essa derivate: la GNU
LGPL (Lesser General Public License - http://www.gnu.org/copyleft/lesser.html), adatta in particolare per le
librerie di software, e la GNU GFDL (GNU Free Documentatione License http://www.gnu.org/copyleft/fdl.html), adatta per la pubblicazione di documentazione. Secondo i termini
della GNU GPL, tutto il software generato da codice GPL è a sua volta necessariamente GPL.
Preme comunque sottolineare che, contrariamente a quanto si possa ritenere a prima vista, il modello
Software Libero, e tutte le licenze che ad esso si rifanno, pone la massima attenzione nel preservare
V. Asta - Introduzione a Unix e GNU/Linux
11
integralmente i diritti di proprietà del software, e non è assolutamente incompatibile con una logica di
profitto nel campo della commercializzazione del software, ma anzi facilita tale logica, aumentando
l’affidabilità e la robustezza dei prodotti software, e quindi il grado di fiducia delle aziende clienti in ciò su
cui investono. Si veda in proposito http://www.gnu.org/philosophy/selling.html, che dice tra l’altro:
"Molta gente crede che lo spirito del progetto GNU sia che non si debba far pagare per
distribuire copie del software, o che si debba far pagare il meno possibile − solo il minimo
per coprire le spese.
In realtà noi incoraggiamo chi ridistribuisce il software libero a far pagare quanto vuole o
può."
In sostanza, si può e anzi si deve fare business e generare profitto, senza di che non è ovviamente possibile
nessuna strategia aziendale e quindi nessun futuro.
Constatare che il modello Software Libero può portare benissimo al successo non solo tecnico ma anche
commerciale è semplice, basta controllare le quotazioni in borsa di alcune società che hanno adottato tale
modello di business; i dati sono eloquenti15:
Società
Red Hat Inc.
VA Software
Caldera International
Fatturato
103
135
40.4
Valore di Mercato
781
62.5
15.2
Fatturato e Valore di Mercato sono espressi in milioni di dollari USA.
1.5.3 Definizioni
Definizioni complete e formali del Software Libero, nelle sue varie accezioni, possono essere trovate in
rete, in particolare sul sito della FSF (http://www.fsf.org) per l’approccio "Free Software", e su quello della
OSI (http://www.opensource.org) per quello "Open Source"; la teoria sottostante alle licenze Software
Libero (Copyleft) è spiegata alla URL http://www.gnu.org/licenses/licenses.html#WhatIsCopyleft.
La definizione formale del Free Software, dovuta a Richard Stallman della FSF
(http://www.gnu.org/philosophy/free-sw.html), parte da un’idea semplice e rivoluzionaria: usare le leggi sul
copyright, così come definite dalla convenzione di Berna, per garantire e proteggere le libertà anzichè per
limitarle; il documento, riportato integralmente in Appendice 2, dichiara tra l’altro:
Il Free Software (software libero) è una questione di libertà, non di prezzo.
L’espressione "Free Software" si riferisce alla libertà dell’utente di eseguire, copiare,
distribuire, studiare, cambiare e migliorare il software. Più precisamente, esso si riferisce a
quattro tipi di libertà per gli utenti del software:
— La libertà di far girare il programma, per qualunque scopo (libertà 0)
— La libertà di studiare come funziona il programma, e di adattarlo per le proprie
necessità (libertà 1). L’accessibilità del codice sorgente è una necessaria precondizione
per questo punto
— La libertà di ridistribuire copie del programma, così da poter aiutare gli altri (libertà 2)
— La libertà di migliorare il programma, e rilasciare al pubblico le proprie migliorìe, così
che tutta la comunità ne possa beneficiare (libertà 3). Anche qui, l’accessibilità del
codice sorgente è una precondizione necessaria.
Un programma è software libero se l’utente ha tutte queste libertà.
Queste libertà ne implicano poi molte altre, tra cui in particolare: libertà di imparare, libertà di insegnare,
15.
Riferimento: sito WEB del NASDAQ (http://www.nasdaq.com, borsa statunitense dei titoli tecnologici) maggio 2002.
V. Asta - Introduzione a Unix e GNU/Linux
12
libertà di concorrenza (libertà di competere liberamente sul mercato), libertà di parola, libertà di scelta.
La definizione dell’Open Source, dovuta alla OSI (http://www.opensource.org/docs/osd-italian.html,
riportata integralmente in Appendice 3), è più circostanziata, e sostanzialmente recita:
Open source (sorgente aperta) non significa semplicemente accesso al codice sorgente. La
distribuzione in termini di programmi open-source deve soddisfare i seguenti criteri:
1.
Ridistribuzione Libera e Gratuita
Le licenze non potranno limitare alcuno dal vendere o donare i programmi come
componenti di una distribuzione aggregata di software contenenti programmi di varia
origine. La licenza non potrà richiedere royalties o altri pagamenti per tali vendite.
2.
Codice Sorgente
Il programma deve includere il codice sorgente, e deve permetterne la distribuzione
così come per la forma compilata. Dove alcune forme di un prodotto non sono
distribuite con codice sorgente, ci deve essere un modo ben pubblicizzato di ottenerne
il codice sorgente per niente più di una ragionevole riproduzione; preferibilmente, per
via dei costi, scaricandolo da Internet gratis. Il codice sorgente deve essere la forma
preferita in cui un programmatore modificherebbe il programma. Codice sorgente
deliberatamente obnubilato non è permesso. Forme intermedie come l’output di un
preprocessore o traduttore non sono permesse.
3.
Prodotti Derivati
La licenza deve permettere modifiche e prodotti derivati, e deve permettere loro di
essere distribuiti sotto le stesse condizioni della licenza del software originale.
4.
Integrità del Codice Sorgente dell’Autore
La licenza potrà impedire il codice sorgente dall’essere redistribuito in forma
modificata solo se la licenza consentirà la distribuzione di pezze ("patch files") con il
codice sorgente al fine di modificare il programma all’installazione. La licenza deve
esplicitamente permettere la distribuzione del software costruito da un diverso codice
sorgente. La licenza può richiedere che i lavori derivati abbiano un nome diverso o
versione diversa dal software originale.
5.
Nessuna Discriminazione contro Persone o Gruppi
La licenza non deve discriminare alcuna persona o gruppo di persone.
6.
Nessuna Discriminazione contro Campi d’Applicazione
La licenza non deve impedire ad alcuno da far uso del programma in un ambito
specifico. Per esempio, non potrà impedire l’uso del programma nell’ambito di
un’impresa, o nell’ambito della ricerca genetica.
7.
Distribuzione della Licenza
I diritti allegati a un programma devono valere a tutti coloro cui il programma è
redistribuito senza necessità dell’emissione di una addizionale licenza da parte dei
licenziatari.
8.
La Licenza non deve essere Specifica a un Prodotto
I diritti allegati al programma non devono dipendere dall’essere il programmma parte
di una particolare distribuzione di software. Se il programma è estratto da quella
V. Asta - Introduzione a Unix e GNU/Linux
13
distribuzione e usato o distribuito all’interno dei termini delle licenze del programma,
tutte le parti cui il programma è ridistribuito dovranno avere gli stessi diritti che sono
garantiti nel caso della distribuzione di software originale.
9.
La Licenza non deve Porre Vincoli su Altro Software
La licenza non deve porre restrizioni su altro software che è distribuito insieme al
software licenziato. Per esempio, la licenza non dovrà insistere che tutti gli altri
programmi distribuiti sugli stessi supporti siano software open-source.
I testi integrali di entrambe le definizioni (nelle loro traduzioni ufficiali in italiano) sono riportati in due
Appendici.
1.5.4 Benefici
Oltre a rappresentare chiaramente un sistema nel quale è più facile l’apprendimento e la diffusione delle
conoscenze e del progresso scientifico, e quindi un sistema di indubbia validità sociale, il modello del
Software Libero presenta molti benefici anche dal punto di vista industriale [Bernardini 2001]:
— Benefici per tutte le Piccole e Medie Imprese (PMI), che possono trarre profitto da tecnologie spesso
altamente sofisticate ad una frazione del pricing usuale di mercato: il software diventa libero, e i
prodotti finali, tipicamente comprensivi di software e servizi (customizzazione, installazione,
aggiornamenti, assistenza tecnica) sono spesso proposti sul mercato a prezzi nettamente più
abbordabili (non è infrequente un rapporto di 10:1 o più nelle riduzioni di costo). Va da sè che ciò
aumenta notevolmente la "piramide di mercato", permettendo l’accesso a queste tecnologie ad un
numero assai maggiore di aziende, realizzando così un effetto di raggiungimento di massa critica
importante ad un tempo per gli utilizzatori e per chi propone la soluzione. Un numero via via
maggiore di PMI può così trarre vantaggio da queste opportunità tecnologiche, di mercato e di
business, a prezzi estremamente competitivi.
— Benefici per molte società a vocazione tecnologica, e per i loro clienti: aziende con skills tecnici
adeguati possono contribuire allo sviluppo dei prodotti, e fare business proponendo servizi di
consulenza e di integrazione di sistemi. Queste aziende traggono vantaggio da tutti i classici punti di
forza che derivano dal modello di business del Software Libero e dalla libertà d’azione che ne deriva,
tra cui:
- Maggior velocità di sviluppo: nuove ed efficienti pratiche di lavoro nel software, come la riusabilità
e l’adattabilità, combinate con la conoscenza dei sorgenti, permettono di ottenere velocità di
sviluppo di applicativi che non hanno precedenti nella storia del software
- Efficienza estrema in termini di risorse umane: adottando le strategie del Software Libero, una
piccola équipe di sviluppatori può produrre una notevole quantità di lavoro; oltre ad essere meno
costosa, un’équipe limitata è notoriamente molto più efficiente di un grosso gruppo di lavoro
- Disponibilità permanente di un gran numero di risorse: la comunità del Software Libero fornisce,
attraverso Internet, libero accesso ad un immenso serbatoio di risorse e strumenti software; i
progetti Software Libero hanno accesso istantaneo a tali risorse, pressochè illimitate e in continua
crescita
- Maggiori capacità di supporto ai clienti e di adattabilità alle loro necessità: oltre ad avere capacità
di auto-assistenza, il Software Libero è fornito da una comunità che tipicamente consiste in un gran
numero di persone sparse sul pianeta, in costante monitoraggio del proprio lavoro e di quello degli
altri; quando si presenta un problema di sviluppo, ci sono ottime probabilità che, inviando un
messaggio nella mailing list appropriata, la soluzione possa essere trovata nello spazio di poche
ore. Da ciò consegue una capacità decisamente superiore di bug-tracking ed una maggior
robustezza dei prodotti risultanti
V. Asta - Introduzione a Unix e GNU/Linux
14
- Minori costi di produzione e budget di sviluppo: tutti i prodotti Software Libero sono normalmente
disponibili e scaricabili via Internet, e hanno di norma, come già accennato, prezzi di licenza molto
bassi; ciò porta a riduzioni di costi e agli ampliamenti di target di mercato già menzionati
- Mercato più ampio e globalizzato: per sua stessa natura, il Software Libero fa sì che i prodotti
pubblicati in questo contesto abbiano visibilità e clienti potenziali su scala mondiale.
1.5.5 Il caso di LINUX
GNU/LINUX, con la sua progressiva e continua penetrazione sul mercato, è l’antesignano e principale
esponente della nuova tendenza rappresentata dal Software Libero. Le distribuzioni di GNU/LINUX
presentano grandi vantaggi su tutti i sistemi proprietari analoghi: esse sono totalmente configurabili e
personalizzabili, forniscono una vastissima panoplia di programmi di utilità ed applicazioni in ogni
possibile settore, e non da ultimo vantano caratteristiche di affidabilità e di sicurezza insorpassate.
GNU/LINUX è accessibile agli utenti in diverse distribuzioni e configurazioni, a seconda delle preferenze e
dei campi applicativi.
L’impatto del modello di sviluppo del kernel LINUX, messo a punto dal suo iniziatore Linus Torvalds, è
stato enorme in tutto il mondo del Software Libero, perchè ha dimostrato per primo che il modello poteva
funzionare su larga scala e per grandi progetti, ed inoltre perchè ha sfatato molti miti sul "come" si sviluppa
software; in questo senso, è paragonabile all’impatto dell’iniziativa di Ken Thompson e Dennis Ritchie alla
fine degli anni ’60, quando decisero di farsi da soli un Sistema Operativo.
Eric Raymond è probabilmente la persona che meglio di ogni altro ha saputo mettere in evidenza gli aspetti
importanti di questa esperienza, e l’originalità e genialità di Linus Torvalds. Nel suo libro "The Cathedral
and the Bazaar" [Raymond 2001], si evidenzia che il modello di lavoro dello sviluppo di LINUX è simile ad
un bazar, dove si trova un po’ di tutto nel disordine; l’esatto contrario di quanto si faceva (e si fa ancora) dai
più, che invece seguono un modello di sviluppo del software simile alla costruzione di una cattedrale, in
modo monolitico, con pochi addetti ai lavori appartati nei laboratori.
Ecco alcuni estratti interessanti:
LINUX è sovversivo. Chi avrebbe potuto pensare appena cinque anni fa16 che un Sistema
Operativo di livello mondiale sarebbe emerso come per magia dal lavoro part-time di diverse
migliaia di hacker e sviluppatori sparsi sull’intero pianeta, collegati tra loro solo grazie ai
tenui cavi di Internet?
[...]
LINUX stravolse gran parte di quel che credevo di sapere. Credevo che il software più
importante andasse realizzato come le cattedrali, attentamente lavorato a mano da singoli
geni o piccole bande di maghi che lavoravano in splendido isolamento, senza che alcuna
versione beta vedesse la luce prima del momento giusto.
Rimasi non poco sorpreso dallo stile di sviluppo proprio di Linus Torvalds − diffondere le
release presto e spesso ("release early, release often"), delegare ad altri tutto il possibile,
essere aperti fino alla promiscuità. Nessuna cattedrale da costruire in silenzio e reverenza.
Piuttosto, la comunità LINUX assomigliava a un grande e confusionario bazar, pullulante di
progetti e approcci tra loro diversi (efficacemente simbolizzati dai siti contenenti l’archivio di
LINUX dove apparivano materiali prodotti da chiunque). Un bazar dal quale soltanto una
serie di miracoli avrebbe potuto far emergere un sistema stabile e coerente.
Il fatto che questo stile bazar sembrasse funzionare, e anche piuttosto bene, mi colpì come
uno shock. Mentre imparavo a prenderne le misure, lavoravo sodo non soltanto sui singoli
progetti, ma anche cercando di comprendere come mai il mondo LINUX non soltanto non
cadesse preda della confusione più totale, ma al contrario andasse rafforzandosi sempre più a
una velocità a malapena immaginabile per quanti costruivano cattedrali.
[...]
16.
La prima versione ufficiale di questo brano è del maggio 1997. La stesura originale è ancora anteriore.
V. Asta - Introduzione a Unix e GNU/Linux
15
Nella parte restante di questo saggio, racconto la storia di quel progetto, usandola per
proporre alcuni aforismi sull’efficacia dello sviluppo Open Source. Questi aforismi ci
aiuteranno a comprendere con esattezza cos’è che rende la comunità LINUX una sorgente
così copiosa di buon software − e aiuteranno tutti noi a divenire più produttivi.
Vale la pena di citare alcuni tra questi aforismi, ed altre considerazioni dell’autore, perchè sono pregni di
significato e possono indurre ad utili riflessioni; ognuno di essi illustra bene alcuni degli aspetti
caratterizzanti il modello Software Libero, ognuno tende a sfatare dei miti, ognuno meriterebbe un
commento specifico (ma per questo si rimanda il lettore interessato all’opera citata di Raymond).
1.
Ogni buon lavoro software inizia dalla frenesia personale di uno sviluppatore (il che spiega l’alta
qualità media del software originato dalla comunità LINUX)
2.
I bravi programmatori sanno cosa scrivere. I migliori sanno cosa riscrivere (e riusare)
3.
Quando hai perso interesse in un programma, l’ultimo tuo dovere è passarlo a un successore
competente
4.
Trattare gli utenti come co-sviluppatori è la strada migliore per ottenere rapidi miglioramenti del
codice e debugging efficace
5.
Ritengo che la mossa più scaltra e consequenziale di Linus non sia stata la costruzione del kernel di
LINUX in sè, bens ì la sua invenzione del modello di sviluppo di LINUX.
6.
Distribuisci presto. Distribuisci spesso. E presta ascolto agli utenti. Linus trattava gli utenti al pari
di co-sviluppatori nella maniera più efficace possibile.
7.
Stabilita una base di beta-tester e co-sviluppatori sufficientemente ampia, ogni problema verrà
rapidamente definito e qualcuno troverà la soluzione adeguata. O, in modo meno formale, "Dato
un numero sufficiente di occhi, tutti i bug vengono a galla". Io la chiamo la "Legge di Linus".
Questa può essere definita anche così: "Il debugging è parallelizzabile".
8.
Nella concezione a bazar si dà per scontato che generalmente i bug siano fenomeni marginali − o
che almeno divengano rapidamente tali se esposti all’attenzione di migliaia di volenterosi cosviluppatori che soppesano ogni nuova release. Ne consegue la rapidità di diffusione per ottenere
maggiori correzioni, e come positivo effetto collaterale, c’è meno da perdere se occasionalmente
viene diffuso qualche pasticcio.
9.
Se tratti i beta-tester come se fossero la risorsa più preziosa, replicheranno trasformandosi davvero
nella risorsa più preziosa a disposizione.
10.
La cosa migliore, dopo l’avere buone idee, è riconoscere quelle che arrivano dagli utenti. Qualche
volta sono le migliori.
11.
Stabilito che il coordinatore dello sviluppo abbia a disposizione un medium almeno altrettanto
affidabile di Internet, e che sappia come svolgere il ruolo di leader senza costrizione, molte teste
funzionano inevitabilmente meglio di una sola.
12.
Forse alla fine la cultura dell’Open Source trionferà non perchè la cooperazione sia moralmente
giusta o perché il software "chiuso" sia moralmente sbagliato, [...] ma semplicemente perché il
mondo "closed-source" non è in grado di vincere la corsa agli armamenti dell’evoluzione contro
quelle comunità Open Source capaci di affrontare un problema con tempi e capacità superiori di
diversi ordini di grandezza.
1.5.6 Situazione e prospettive
Oggi, molti prodotti Software Libero stanno iniziando ad essere sviluppati e supportati in un contesto
orientato ormai direttamente al mercato industriale vero e proprio. Si possono citare molti "business case"
di successo, tra cui importanti aziende come le citate Red Hat, VA Software e Caldera (che ha acquisito
SCO - Santa Cruz Operation), e poi Cygnus, Mandrake, Vixie Enterprise ed altre; e l’enorme successo,
legato ad un impatto sia tecnologico che commerciale, di progetti quali GNU/LINUX, Apache e Zope, solo
V. Asta - Introduzione a Unix e GNU/Linux
16
per ricordare i più significativi.
Non è facile quantificare ad oggi l’uso complessivo del Software Libero e il suo impatto, ma è fin troppo
chiaro ormai che entrambi sono in grande e rapida espansione: il nuovo modello di lavoro e di business si è
ormai stabilito, e sta prendendo sempre più piede, scalzando attivamente le posizioni di grosse società che
finora avevano sempre basato tutte le loro strategie sul software proprietario. Molte di queste hanno
modificato tali strategie, a dimostrazione della bontà ed efficacia del nuovo modello; prime fra tutte la IBM
(http://www.investor.ibm.com/investor/events/linux080800/ ), che ha investito un miliardo di dollari sul
Sistema Operativo GNU/LINUX, implementandolo addirittura su tutta la gamma delle loro macchine, dalle
workstations su PC ai Mainframe; IBM è poi stata seguita da SGI, SUN, e altri.
Già oggi il Software Libero ha raggiunto molti risultati significativi, tra cui in particolare un’ormai ben
diffusa consapevolezza dell’importanza della libertà di scelta e di selezione del software, e non solo per
fattori puramente economici (il Software Libero come detto non è necessariamente gratuito, ma è
generalmente meno costoso del software proprietario).
Alcuni fatti significativi possono dare un ulteriore contributo alla corretta valutazione della portata del
fenomeno:
— La Gartner Inc., azienda di consulting strategico di fama mondiale, ha dichiarato in un rapporto
tecnico del settembre 2001 (http://www.gartner.com/DisplayDocument?doc_cd=101034), che il
server WEB IIS (Internet Information Server) di Microsoft è troppo facilmente attaccabile da virus e
altro, e ha esplicitamente raccomandato di migrare da IIS ad un server Apache; ciò è un chiaro segno
di inversione di tendenza anche presso aziende che lavorano nel campo finanziario, notoriamente
molto prudenti nell’accettare novità tecnologiche.
— La Borsa di New York (NYSE - New York Stock Echange) ha cambiato il proprio sistema
informativo centrale nel 2001: tutto è ora gestito da un mainframe IBM con Sistema Operativo
GNU/LINUX. Ciò dimostra che il Software Libero ha raggiunto livelli di sicurezza e di affidabilità
sufficienti anche per applicazioni estremamente mission-critical.
— Il DoD (Department of Defense) degli Stati Uniti ha dichiarato da tempo l’intenzione di effettuare
una migrazione di tutti i suoi server da Sistema Operativo Windows NT / 2000 a GNU/LINUX, per
ragioni di convenienza economica, non reputando più giustificata la spesa continua di licenze e di
upgrades imposta dalla Microsoft per ciascun server; il Ministero della Difesa francese ha
successivamente dichiarato che farà altrettanto, ma non per ragioni economiche, bensì per ragioni di
sicurezza: lo Stato Francese non ritiene sicuro, per applicazioni militari, l’utilizzo di un Sistema
Operativo di cui non si possa controllare il codice sorgente, e quindi esattamente tutto ciò che fa e
che non fa (quali garanzie si hanno, per un prodotto a modello chiuso, che non vi siano internamente
parti di codice che vanno a trasferire informazioni altrove, oggi che tutte le macchine sono connesse
in una rete mondiale?); GNU/LINUX risponde invece pienamente a tali esigenze. Ciò è un chiaro
segno di come si stia evolvendo verso un mondo e un contesto di lavoro e sociologico che ammette
sempre meno il modello "closed source", e men che meno il modello Microsoft, che rischia di finire
un giorno fuori mercato. Esempi come quelli citati di adozione su scala nazionale di GNU/LINUX o
altri prodotti Software Libero, si sono verificati anche in Cina (con la distribuzione "Red Flag
LINUX" − http://www.linuxjournal.com/article.php?sid=5784), in Germania, dove il Ministero
dell’Economia e Tecnologia finanzia lo sviluppo del progetto GnuPG (GNU Privacy Guard)17,
ritenendolo importante per la sicurezza nazionale (http://www.gnupg.de/presse.en.html), e in altri
paesi.
— In Italia, nell’ottobre 2000 è stata redatta una lettera aperta, indirizzata al Dipartimento della
Funzione Pubblica, all’Autorità per l’Informatica nella Pubblica Amministrazione, e al Ministero del
Tesoro, intitolata "Soggezione informatica dello Stato italiano alla Microsoft"
(http://www.interlex.it/pa/letterap.htm); la lettera ha registrato oltre duemila firme di adesione in
17.
GnuPG (http://www.gnupg.org/ ) è un’implementazione Software Libero del noto sistema PGP (Pretty Good Privacy − vedi
http://www.philzimmermann.com/ ), che riguarda applicazioni di sicurezza e privatezza dell’informzazione basata su algoritmi
crittografici.
V. Asta - Introduzione a Unix e GNU/Linux
17
pochi giorni. In essa si chiedono allo Stato le ragioni per cui si continua a spendere il denaro dei
contribuenti per acquistare continue licenze Microsoft Office per più o meno tutti gli uffici pubblici,
quando esistono prodotti funzionalmente equivalenti e con caratteristiche ergonomiche perfettamente
simili, distribuiti gratuitamente (StarOffice, oggi OpenOffice, prodotto Software Libero).
— Paesi quali l’Argentina, l’Inghilterra, la Finlandia e la Germania (ed altri) hanno ormai leggi che
richiedono di adottare esclusivamente prodotti Software Libero per tutta la Pubblica
Amministrazione. La Francia sta facendo altrettanto; anche in Italia è stato recententemente proposto
(febbraio 2002) un disegno di legge analogo, per iniziativa del senatore Cortiana [2002], intitolato
"Norme in materia di pluralismo informatico sull’adozione e la diffusione del software libero e sulla
portabilità dei documenti informatici nella pubblica amministrazione". Nel settembre 2002, secondo
il New York Times, si contavano 66 progetti di legge di questo tipo, in 26 diversi paesi [Lohr 2002].
Sono esempi come questi che portano un numero sempre crescente di osservatori e operatori del settore a
ritenere che il Software Libero sia un processo irreversibile.
Strategie legate al Software Libero sono state adottate ormai anche da diverse aziende leader di mercato
nell’industria dei computer, come appunto la IBM, la Netscape Corp. (http://www.mozilla.org) e la SGI
(http://www.sgi.com/linux), nonchè, pur dopo varie esitazioni, dalla SUN Microsystems
(http://www.sun.com/software/linux/ ). Val la pena di rammentare che il successo del modello di business
del Software Libero e l’alta produttività e qualità del software sviluppato secondo questo modello indussero
i managers di Netscape Corp. a porre lo sviluppo dei propri browsers sotto una licenza Software Libero già
nel gennaio 1998 (http://www.netscape.com/newsref/pr/newsrelease558.html), profondamente influenzati
dagli scritti di Eric Raymond [1997], per loro esplicita ammissione.
Anche se ci sono ancora moltissimi progressi da compiere in questo campo, e se la partita non è ancora
vinta, il futuro del Software Libero sembra oggi decisamente promettente, e già oggi è una realtà
significativa; solo pochissimi anni fa, anche i più accesi difensori del Software Libero non avrebbero osato
sperare che:
— un Sistema Operativo Software Libero (GNU/LINUX) avrebbe potuto preoccupare seriamente il
dominio incontrastato della società che detiene il monopolio planetario del settore (Microsoft)
— società importanti come IBM, Intel, Netscape, Creative, SGI, SUN ed altre avrebbero cominciato a
guardare al Software Libero come una prospettiva di sviluppo percorribile
— interi sistemi governativi, come i casi citati (Argentina, Inghilterra, Finlandia, Germania, Cina,
Francia) avrebbero considerato l’ipotesi di adottare esclusivamente sistemi Software Libero.
A proposito del primo punto ora esposto, val la pena citare il caso emblematico del famoso Halloween
document [Valloppillil 1998]: un rapporto interno Microsoft, intitolato "Open Source Software: a (new?)
development methodology", destinato a rimanere strettamente riservato, finì invece nelle mani di Eric
Raymond, che lo rese pubblico in una versione da lui commentata passo per passo (il rapporto, i commenti,
le reazioni della stampa e della Microsoft sono tutti disponibili a partire dalla URL
http://www.opensource.org/halloween); questo documento, la cui inattesa pubblicazione ebbe una grande
eco nella stampa di tutto il mondo, è da una parte la prova di quanto Microsoft sia seriamente preoccupata
dall’ascesa del Software Libero, e dall’altra costituisce una vera e propria dichiarazione di guerra della
Microsoft verso LINUX, e ha evidenziato agli occhi di molti che Microsoft era intenzionata a mettere in atto
iniziative senza scrupoli e di dubbia correttezza pur di gettare discredito su LINUX e sul Software Libero in
generale. Alla pubblicazione del documento, la stessa Microsoft ha dovuto ammettere la sua autenticità,
difendendosi con la tesi che si trattava di "un semplice studio ingegneristico" che rifletteva le opinioni
personali del suo autore, ma non le idee nè la politica dell’azienda.
La reazione dell’opinione pubblica e degli addetti ai lavori non si fece attendere, e l’effetto risultante fu
un’enorme crescita di interesse e popolarità per il Sistema Operativo GNU/LINUX: in sostanza, molti
costruttori di hardware e produttori di software si dissero: "se LINUX preoccupa la Microsoft, allora è
davvero una cosa seria"; risale a questo periodo la decisione di grandi multinazionali, come Eicon
Technology, Dialogic e altri, di sviluppare per LINUX i device drivers e le librerie software di tutte le schede
V. Asta - Introduzione a Unix e GNU/Linux
18
hardware da loro prodotte; similmente, software houses come Oracle, Informix, Computer Associates e altri
hanno deciso di portare i loro prodotti software proprietari su una piattaforma libera, LINUX.
L’industria dei computer ha già visto più volte, nella sua storia passata, sorprendenti ondate di crescita e di
innovazione, come i primissimi microcomputer negli anni ’70, la coalizione spontanea di tutti i costruttori
contro lo strapotere di IBM, grazie al potere aggregante di UNIX, i PC prodotti su larga scala dalla metà
degli anni ’80 fino ad oggi, e l’irresistibile ascesa di Internet nello stesso periodo. Il software commerciale
rilasciato sotto una licenza di sviluppo Software Libero può costituire il prossimo, importante passo.
1.5.7 Conclusione
In conclusione, i punti salienti che caratterizzano il Software Libero possono essere così riassunti:
— È un modello aperto e cooperativo di sviluppo software
— È un modello di lavoro e modello di business a un tempo
— È in forte espansione a livello mondiale
— Offre i seguenti vantaggi:
- maggior velocità di sviluppo
- numero teoricamente illimitato di sviluppatori, a costo nullo o tendente a zero
- costi di produzione più bassi
- miglior posizionamento del fornitore, che si trova naturalmente più vicino ai bisogni del cliente
- scala di mercato più ampia e globale
— È basato sulla filosofia di sviluppo "Release fast, release often"
— La proprietà del software è preservata
— Sono possibili, in certe condizioni, strategie miste (che combinano software libero e software a
licenza chiusa)
1.6 Tipi di distribuzioni di GNU/LINUX
Esistono diverse distribuzioni del Sistema Operativo GNU/LINUX, che si differenziano, tra l’altro, per le
procedure di installazione (più o meno facili e/o flessibili da usare), per i package di applicazioni inclusi,
per gli ambienti grafici proposti; inoltre, alcune sono specializzate a certi tipi di ambienti di lavoro. Tra di
esse: Slackware, Debian, Caldera, Red Hat, Mandrake, SuSe.
V. Asta - Introduzione a Unix e GNU/Linux
19
2. Come iniziare
2.1 Login
In questo paragrafo si introduce il sistema strettamente da un punto di vista di utente; si presuppone in
particolare la disponibilità di un sistema UNIX regolarmente avviato, pronto all’interazione con gli utenti;
ciò che accade prima, e che l’utente normale tipicamente non vede, viene spiegato in paragrafi successivi18.
Dal punto di vista dell’utente, una sessione di lavoro con un sistema UNIX inizia invariabilmente col
collegamento ad un terminale di lavoro; ciò in genere può corrispondere, in pratica, ad un terminale fisico
reale (ad esempio una VT-100 connessa ad una linea seriale, o la console di un Personal Computer) ovvero
ad un terminale virtuale (ad esempio una finestra xterm in una postazione grafica, o un utente connesso in
rete ad un server TELNET). In ogni caso, la prima operazione da fare è l’identificazione dell’utente, o
procedura di login, il che consiste nel fornire al sistema un nominativo utente (che dovrà essere già noto al
sistema stesso) ed una password (o parola d’ordine) ad esso associata19. È da notare che in qualsiasi
sistema UNIX si fa sempre distinzione tra caratteri minuscoli e caratteri maiuscoli, che sono considerate
entità diverse.
...il sistema attende il nome dell’utente.
...nome dell’utente, in minuscolo.
...parola d’ordine dell’utente (che non
comparirà sullo schermo),
terminata da <CR> (Invio, o Carriage-Return)
Login:
Login: luca<CR>
Password:
Last login: Sat May
4 11:34:42
...varie informazioni di servizio
Il Sistema sarà...
...eventuale stampa dei messaggi del giorno
You have mail.
...eventuale notifica di messaggi di E-mail
$
...prompt dell’interprete di comandi
È bene, in generale, cambiare subito la password inizialmente assegnata dall’amministratore con un’altra
nota solo all’utente. Il comando utilizzato per creare o modificare la password è passwd.
Esempio:
$ passwd
Changing password for luca
Old password:
New password:
Re-enter new password:
password updated successfully
$
Chiaramente nè la vecchia nè la nuova parola d’ordine appariranno sullo schermo.
Per uscire, si digita ˆD, da inserire all’inizio della riga20; questo carattere segna la fine della sessione di
login. Quando la shell incontra la fine della sessione di login, termina.
2.2 La manualistica on-line
Una delle prime cose in assoluto da sapere su un sistema UNIX è che normalmente dispone di un’estesa
manualistica on-line, in varie forme; la forma più immediata è quella che fa riferimento al comando man, il
18.
La descrizione delle fasi di avvio del sistema è descritta nel paragrafo 11. pag. 78, "avvio del sistema", e nel paragrafo 12.
pag. 81, "il programma init".
19.
L’amministratore del sistema avrà assegnato un nome di login all’utente, ed una password iniziale, che permetta al sistema di
identificare l’utente.
V. Asta - Introduzione a Unix e GNU/Linux
20
quale permette di consultare da terminale il manuale di riferimento di tutto il sistema.
Il manuale è diviso in un certo numero di sezioni, che riguardano i comandi, le chiamate di sistema, e altro;
nella letteratura, ogni riferimento del tipo entry(n) indica un rimando alla pagina di manuale entry nella
sezione numero n; ad esempio, per saperne di più sul manuale on-line, basta consultare man(1), cioè la
voce man del manuale, in sezione 1. Anche in questo testo ci si atterrà a questa convenzione, dovunque si
voglia evidenziare un rimando ad una pagina di manuale.
Ciò detto, la lista delle sezioni è la seguente21:
Sezione
1
2
3
4
5
6
7
8
Titolo
Esempio
comandi
chiamate di sistema
funzioni di libreria
periferiche
formato dei files
giochi
miscellanea
comandi di amministrazione
passwd(1)
open(2)
printf(3)
console(4)
inittab(5)
chess(6)
ascii(7)
shutdown(8)
2.3 Utilizzazione del terminale
L’interfaccia tra il sistema UNIX e tutte le periferiche (chiamate anche ’device’) è effettuata da parti di
codice del kernel chiamati driver. Un driver gestisce uno o più device.
I terminali o (tty) sono anch’essi gestiti da un driver, chiamato ’driver di tty’ o driver di linea seriale. Una
tty è in pratica ciò che precedentemente è stato denominato, in termini generici, una "linea utente", e come
detto può corrispondere ad un terminale reale o ad uno virtuale.
Essendo il terminale software totalmente parametrabile, è utile conoscere alcune delle sue possibilità;
queste sono tutte consultabili o posizionabili tramite il comando stty(1), la cui sintassi in generale è:
stty [-a]
stty param [value] [ param [value] ... ]
Nella prima forma, vengono mostrati i parametri nella loro configurazione attuale22; nel secondo caso, uno
o più parametri vengono posizionati a nuovi valori. I parametri possono avere un valore specifico ad essi
relativo, come ad esempio
stty intr ˆc
oppure essere parametri di tipo booleano; in tal caso, specificando il nome del parametro questo viene
asserito, mentre viene negato facendolo precedere da un segno ‘-’.
speed
Indica la velocità del terminale, in bps (bits per second); ad esempio,
$ stty 19200
20.
ˆD rappresenta il carattere ‘control-D’. In seguito i caratteri di controllo e gli altri caratteri speciali saranno indicati in questo
modo:
ˆcarattere
o talvolta
<carattere-speciale>
Ad esempio: ˆD, <newline>, <CR>, <Invio>.
21.
La numerazione delle sezioni è stata cambiata in System V, dove ad esempio le periferiche sono in sezione 7. Alcuni altri
sistemi, come ad esempio SCO UNIX, utilizzano una propria divisione in sezioni, diversa da quella abituale.
22.
Senza argomenti, vengono visualizzati solo i parametri principali; con l’opzione -a, vengono mostrati tutti.
V. Asta - Introduzione a Unix e GNU/Linux
21
Naturalmente, specificare la velocità ha senso soltanto se si tratta di una vera linea seriale
fisica, ad esempio connessa con un modem.
erase
Carattere che permette di sopprimere l’ultimo carattere digitato (di solito ˆH o <DEL>). Ad
esempio,
$ tty erase ’ˆH’
$
Dopo questo comando sarà il carattere ˆH che permetterà di annullare l’ultimo carattere
digitato.
kill
Carattere che permette di sopprimere tutti i caratteri della riga (di solito ˆU).
intr
Carattere che permette di inviare il segnale di interrupt, SIGINT (vedere il paragrafo 5.13
pag. 53 sui segnali), che può essere considerato come un break (di solito ˆC).
quit
Carattere che permette di inviare il segnale di quit, SIGQUIT (vedere il paragrafo sui
segnali) (per default ˆ\).
stop, start
Caratteri che permettono di sospendere e di riprendere una visualizzazione a terminale (in
genere ˆS e ˆQ).
eof
Carattere che permette di simulare la fine di file a partire da un terminale (in genere ˆD) vedi oltre.
susp
Carattere che permette di sospendere il comando attualmente in esecuzione in foreground (di
solito ˆZ).
tabs
Flag indicante che il terminale è in grado di visualizzare il carattere di tabulazione (<tab> o
ˆI, codice ASCII 009), nel qual caso il driver invia direttamente tali caratteri inalterati,
altrimenti invia, in loro luogo, il numero di spazi necessari.
echo
Abilita l’eco a terminale dell’input da tastiera; ad esempio,
stty
echo
read
stty
-echo
-n "parola segreta: "
SECRET
echo
# disabilita l’eco
# leggi la parola, senza eco
# riabilita l’eco
echoe
Fissa l’eco del carattere erase alla stringa "<BS> <BS>"23.
icanon
Abilita il trattamento "canonico" dell’input; in questa modalità, normalmente attiva di
default, tutto l’input da tastiera è "line-buffered", cioè bufferizzato fin quando la riga non è
terminata da un <Invio>; solo allora il contenuto della riga è passato al programma che la
deve leggere. La bufferizzazione di riga permette in particolare l’editing, cioè la possibilità
di correggere la riga (con i caratteri erase e kill, che altrimenti non hanno senso), prima che
questa sia mandata al programma.
icrnl
Valido solo se icanon è asserito. Abilita la traslazione \r => \n in input (cioè un carattere
<CR> ovvero <Invio> è traslato, nel buffer di input, in un newline, o line-feed: <NL> - vedi
oltre).
23.
<BS> è il carattere "back-space"; la sequenza è dunque di tre caratteri: un back-space, uno spazio, un altro back-space. Ciò
produce come effetto l’effettiva cancellazione dallo schermo del carattere che si vuole eliminare: il primo <BS> riporta il
cursore indietro di una posizione (dunque sul carattere da eliminare), lo spazio cancella il carattere, l’ultimo <BS> riporta
nuovamente il cursore sulla posizione giusta per il prossimo carattere.
V. Asta - Introduzione a Unix e GNU/Linux
22
opost
Abilita il post-trattamento dell’output; ciò è analogo al trattamento canonico dell’input.
onlcr
Valido solo se opost è asserito. Abilita la traslazione \n => \r\n in output, cioè un carattere
<LF> (newline, o line-feed) è traslato, nel buffer di output, nella sequenza <CR><LF> vedi oltre.
sane
Questo non è un vero parametro, ma corrisponde ad un "menù" precostituito nel programma
stty(1): imposta tutti i parametri a valori iniziali ragionevoli
Per quanto riguarda i parametri icanon, icrnl, opost e onlcr, si precisa che in UNIX tutti i files di testo
hanno le righe terminate da un solo carattere, il <newline> (`\n’); ciò è in contrasto con quanto avviene in
molti altri sistemi, dove ciascuna riga di testo è terminata con due caratteri: il ritorno carrello, <CR>, e il
line-feed o newline, <LF> (il che costituisce evidentemente uno spreco di dati da memorizzare). Per
gestire con coerenza questo aspetto, in input da tastiera il tasto <Invio> (che genera un <CR>) è
normalmente convertito in new-line, mentre in output il carattere new-line è normalmente convertito nella
sequenza "ritorno carrello" + "new-line", che provoca l’effettivo ritorno a capo del cursore e l’avanzamento
alla prossima riga.
È opportuno precisare meglio il ruolo del carattere di eof ; com’è noto dallo studio delle chiamate di
sistema per la gestione dei canali di I/O, la condizione di end of file (fine di file) si verifica se e solo se la
chiamata sistema read(2) ritorna 0 byte letti; in un normale contesto tty (con icanon asserito), il driver di
terminale ritorna alla read() i caratteri letti in una riga (digitati dall’utente), fino al <newline> incluso,
ovvero fino al carattere di eof escluso; ad esempio, se l’utente digita
abc<newline>
la read() ritorna 4 caratteri letti (le tre lettere più il <newline>), mentre se digita
abcˆD
la read() ritorna 3 caratteri letti (le tre lettere e basta); ne segue che se un utente digita il carattere di eof ad
inizio riga, la read() ritornerà 0 byte letti, quindi la condizione di end of file.
Per vedere tutti i parametri attuali di un terminale, come detto basta digitare il comando
$ stty -a
$
Consultare la pagina di manuale stty(1) per maggiori dettagli.
2.4 Primi comandi
Sono stati introdotti già due comandi:
• passwd
per modificare una password
• stty
per modificare o consultare i parametri del driver di linea seriale (set/show tty).
Si può fin da ora citare qualche altro comando utile per i primi contatti con il sistema.
• date
stampa la data e l’ora conosciute dal sistema.
• who
stampa l’elenco degli utenti attualmente connessi ("loggati") al sistema.
• tty
stampa il nome della linea seriale (o pseudo-linea seriale) sulla quale si sta lavorando
(teletype).
• grep
ricerca un pattern, cioè un modello di selezione di una stringa di caratteri, in un file; il
pattern è specificato come un’espressione regolare (regular expression − vedere l’Appendice
4 sulle espressioni regolari).
• cal
stampa il calendario corrispondente al mese o all’anno considerato (calendar).
V. Asta - Introduzione a Unix e GNU/Linux
23
• man
stampa le pagine del manuale corrispondenti al comando precisato (manual).
• cat
visualizza un file ascii sullo schermo.
• less24
visualizza un file ascii paginato sullo schermo.
• pr
formatta un testo per la stampa (inserendo la data, la numerazione di pagine e altro) (print).
• lpr25
spooler di stampa (line printer).
• echo
stampa i suoi argomenti.
• wc
conta i numeri di riga, le parole ed i caratteri contenuti nei file passati in argomento (word
count).
• mail
permette di inviare un messaggio ad un utente o di leggere il proprio messaggio26.
Esempio:
L’utente luca digita:
$ mail gianni
questo è un messaggio per gianni
bla bla bla
ciao
ˆD
$
Questo testo sarà inviato all’utente gianni, che potrà leggerlo digitando semplicemente
$ mail
• write
permette di comunicare con un altro utente loggato sul sistema27.
Esempio:
L’utente luca digita:
$ write gianni
L’utente gianni riceve28:
<Bell> message from luca on ttya3
gianni digita allora:
$ write luca
A partire da questo momento tutto ciò che luca digita fino al ritorno carrello (Carriage
24.
less(1) è generalmente usato nei sistemi GNU, tra cui GNU/LINUX; sostituito dal programma pg in System V; un altro
programma equivalente è more, tipico dei sistemi BSD.
25.
sostituito dal programma lp in System V
26.
Esistono molti altri programmi analoghi, e più user-friendly: si citano elm, pine, oltre ai moduli di mailing dei browser WEB
(Netscape e altri). Come si vedrà nel seguito e negli esempi, il comando mail(1) viene solitamente utilizzato in contesti non
interattivi, in particolare da procedure di comandi che devono inviare messaggi di e-mail in modo automatico.
27.
Il programma talk fornisce funzionalità analoghe, ma in modalità full-screen e con possibilità di dialogare tra utenti di
macchine diverse, connesse in rete.
28.
<Bell> indica il carattere di avvisatore acustico, o "alert" (bell - ASCII 007, o ˆG)
V. Asta - Introduzione a Unix e GNU/Linux
24
Return − <CR>) è inviato a gianni, e viceversa. Per evitare di confondere caratteri e ruoli
dei due utenti, si utilizza spesso la seguente convenzione: (o) alla fine di ciascuna replica
(per "over", cioè "passo") e (oo) a fine conversazione (per "over and out", cioè "passo e
chiudo"). Per terminare la connessione, ciascuno digita ˆD e l’altro riceve allora la stringa
"<EOT>" (end of text).
• mesg
se si desidera lavorare senza essere disturbati da nessun messaggio sul terminale si può
digitare:
$ mesg n
$
poi
$ mesg y
$
allorchè si è nuovamente disposti a ricevere dei messaggi (message).
2.5 Primi file di sistema
2.5.1 /etc/passwd
Questo file (vedi la Figura 1) contiene delle informazioni su tutti gli utenti autorizzati. È un file di testo che
si può editare normalmente e che è strutturato nel modo seguente:
— una linea per utente
— sette campi per riga, separati dal carattere ’:’ - ogni linea ha la forma seguente:
nome:password:UID:GID:commento:HOME directory:comando
nome
nome dell’utente, da dare al login; deve essere al massimo di 8 caratteri e in
minuscolo.
password
parola d’ordine da dare al login, memorizzata in forma criptata. Dopo la
creazione di un account, questo campo viene lasciato vuoto, sarà riempito dal
programma passwd che cripterà esso stesso la parola d’ordine data.
UID
numero di identificazione dell’utente: deve essere unico (User IDentity).
GID
numero di identificazione del gruppo (Group IDentity).
commento
questo campo è facoltativo ed in genere non è utilizzato da alcun programma
di sistema. È spesso utilizzato per indicare il nome completo dell’utente.
HOME directory
è la directory in cui sarà posto l’utente al momento del login; di solito questa
directory appartiene all’utente stesso, che quindi è in grado di creare nuovi
file e directory a partire da questa, che è dunque la directory di partenza di
tutta la sua zona di lavoro su disco.
comando
questo comando sarà lanciato al momento del login; si tratta generalmente di
un interprete di comandi. Se questo campo è vuoto, il programma /bin/sh
sarà eseguito per default.
V. Asta - Introduzione a Unix e GNU/Linux
25
mario:FBSyjXpjW1JUo:44:22:Mario Rossi:/home/mario:/bin/bash
ˆ
ˆ
ˆ ˆ
ˆ
ˆ
ˆ
|
|
| |
|
|
|
|
|
| |
|
|
|
USERNAME |
| |
|
|
|
|
UID |
COMMENTO |
SHELL
|
|
|
PASSWORD
GID
HOME DIRECTORY
Fig. 1
2.5.2 /etc/profile
È un file di comandi che viene eseguito ad ogni login. Permette di aggiornare parametri, di controllare se
c’è posta in arrivo per l’utente, ed altre operazioni comuni per tutti gli utenti del sistema.
2.5.3 .profile
È un file di comandi analogo al precedente che, se esiste nella home directory dell’utente, è eseguito
anch’esso ad ogni login29. Permette di aggiornare altri parametri, di stampare la data e altre
personalizzazioni dell’ambiente di lavoro, differenziate per ciascun utente.
2.5.4 /etc/motd
Motd sta per "message of the day", cioè messaggio del giorno. È un file testuale che viene gestito
liberamente dall’amministratore del sistema; il suo contenuto è visualizzato sul terminale durante la
procedura di login, infatti in /etc/profile c’è normalmente una riga contenente
cat /etc/motd
29.
A seconda della shell, vengono talvolta utilizzati altri files, con nomi leggermente diversi, per questo stesso scopo; in
particolare, la shell bash (v. oltre) utilizza normalmente, al posto di .profile, il file .bash_profile
V. Asta - Introduzione a Unix e GNU/Linux
26
3. L’interprete di comandi - 1
L’interprete di comandi (denominato anche CLI, o "command line interpreter") in UNIX è un programma,
normalmente chiamato sh, dunque un semplice file eseguibile. È in generale chiamato automaticamente al
momento del login (secondo l’ultimo campo del file /etc/passwd).
Può anche essere chiamato interattivamente, come gli altri comandi digitando:
$ sh
Esistono diverse varianti della shell, tra cui:
Bourne shell - /bin/sh
scritta da Steve Bourne ai Bell Laboratories, è la shell classica, ma
anche la meno potente ed elastica.
C-shell - /bin/csh
scritta da Bill Joy, dell’Università di California a Berkeley30, è molto
popolare negli UNIX di derivazione BSD; superiore al Bourne shell
come interprete interattivo, ma meno adatta all’uso non interattivo
(per procedure di comandi).
Korn shell - /bin/ksh
scritta da David Korn, dei Bell Laboratories, raduna le qualità della
Bourne shell, con cui mantiene la compatibilità, e della C-shell.
Bourne-Again shell - /bin/bash
scritta da Richard Stallman e dalla comunità del progetto GNU, è
molto simile alla Korn shell, a cui aggiunge peraltro varie
funzionalità, ed è la shell di elezione nei sistemi GNU/LINUX.
In questo testo la descrizione della shell è essenzialmente basata, salvo avviso contrario, sulle
caratteristiche comuni della Bourne-Again shell e della Korn shell.
È possibile pensare la shell come un sottosistema dove si entra sovrapponendo il proprio ambiente corrente,
e da dove si può uscire operando in senso inverso.
La shell è un programma che permette la comunicazione tra l’utente ed il Sistema Operativo UNIX. Legge
sulla tastiera le righe di comando digitate e le interpreta come richieste per eseguire dei programmi.
Un comando è un programma contenuto in un file. I comandi standard si trovano raggruppati in alcune
directory (inizialmente /bin e /usr/bin). I comandi aggiunti dagli utenti si trovano normalmente in
/usr/local/bin o in una directory denominata bin, a partire dalla loro home directory (questa non è che una
convenzione che permette di restare in coerenza con la gerarchia standard di un sistema UNIX). La shell
deve dunque ricercare il comando in tutte le directory possibili, e per questo usa un elenco, il cui formato è:
dir1:dir2:dir3:...
Questo elenco deve essere facilmente modificabile e deve poter essere differente per ciascun utente; è
dunque posto in una variabile shell, chiamata PATH. È possibile verificare il suo valore digitando:
$ echo $PATH
/bin:/usr/bin:/usr/local/bin
$
o modificare il suo valore; per esempio:31
$ PATH=$PATH:/home/gianni/bin
$
30.
Bill Joy, che è anche l’autore dell’editor vi e di molte altre utilities classiche di BSD UNIX, ha successivamente lasciato
l’Università per fondare la SUN Microsystems Inc.
31.
È possibile anche scrivere export PATH=$PATH:/home/gianni/bin ; il comando export, introdotto più avanti nel
testo (paragrafo 5.12 pag. 53 e paragrafo 6. pag. 54), permette di esportare il valore della variabile anche ai processi generati
dalla shell, cioè ai comandi da questo lanciati.
V. Asta - Introduzione a Unix e GNU/Linux
27
Dopo l’esecuzione, il prompt ritorna indicando che la shell è pronta ed attende un’altra riga di comando.
3.1 Separatore di comandi
Per potere digitare più di un comando sulla stessa riga, si può utilizzare il carattere ; − detto operatore di
esecuzione sequenziale; questo indica alla shell di eseguire il primo comando, di attendere la sua fine, e poi
di eseguire il prossimo comando.
$ date ; who
$
I comandi date e who sono eseguiti in sequenza. Dopo la data e l’ora correnti, l’elenco delle persone
connesse sul sistema è visualizzato sul terminale.
3.2 Ridirezione delle uscite verso un file
Le uscite dei programmi sono tradizionalmente inviate dal sistema UNIX su un canale di I/O chiamato
uscita standard, o standard output (abbreviato in stdout). Normalmente questo canale è assegnato allo
schermo del terminale di lavoro. È possibile cambiare temporaneamente questa uscita domandando alla
shell di "ridirigere" l’uscita standard verso un altro canale, specificato sulla riga di comando.
comando >file
La sintassi di questo comando ha per effetto di non inviare le informazioni prodotte da comando sul
terminale ma di accantonarle nel file file. Se il file non esiste, sarà creato dalla shell. Se esiste già, la shell
cancellerà il suo contenuto per sostituirvi l’uscita di comando.
Esempio32:
$ who >who.temp
$
Questo comando non produce alcuna uscita sul terminale; tutte le informazioni del comando who sono
accantonate nel file "who.temp" Si noti che il programma who si ritrova invocato senza argomenti: la parte
">who.temp" della riga di comando è gestita direttamente dalla shell, prima di lanciare il programma, e non
è mai passata in argomento al programma stesso.
$ cat who.temp
gianni
pts/0
luca
pts/2
marion
pts/6
marion
ttyS0
$
jul
jul
jul
jul
31
31
31
31
09:46
09:17
09:34
09:02
Visualizza il contenuto del file who.temp, vale a dire le persone loggate ad un istante t.
È possibile ridirigere più di un comando in un file, per fare questo è sufficiente delimitare questi comandi
con delle parentesi.
Esempio:
33.
Come già introdotto nel paragrafo 1.2 pag. 4, "Caratteristiche generali del kernel", e come si ridirà meglio nel paragrafo 10.1
pag. 67, "Il sistema di file", i nomi di file in UNIX possono essere composti con qualunque carattere, escluso `/’ (che indica il
passaggio ad una componente successiva in un pathname) e ’\0’ (che termina le stringhe di caratteri); il carattere `.’ non ha
nessun significato particolare, non esistendo nel kernel il concetto di "estensione di un nome di file"; tale concetto può invece
esistere a livello applicativo, e infatti ad esempio il compilatore cc(1) fa questa distinzione per i nomi dei files passati in
argomento: quelli che hanno estensione .c sono files contenenti programmi sorgente in linguaggio C, quelli con estensione .a
sono files di sorgente in assembler, e così via.
V. Asta - Introduzione a Unix e GNU/Linux
28
$ (date ; who) >who.temp
$
In questo esempio le uscite dei comandi date e who saranno ridirette nello stesso file who.temp.
$ cat who.temp
Wed jul 31 10:33:20 MET 2000
gianni
pts/0
jul 31 09:46
luca
pts/2
jul 31 09:17
marion
pts/6
jul 31 09:34
marion
ttyS0
jul 31 09:02
$
Visualizza la data completa e le persone loggate.
Si noti che se il comando non fosse stato delimitato da parentesi, la shell avrebbe eseguito date, stampato il
risultato sul terminale, ed in seguito avrebbe lanciato who salvando il risultato sul file "who.temp".
comando >>file
Aggiunge l’uscita di questo comando alla fine del file file senza peraltro cancellare il suo contenuto. Se il
file file non esiste, la shell lo crea.
Esempio:
$ date >date.temp
$ cat date.temp
Wed jul 31 10:45:21 MET 2000
$ date >>date.temp
$ cat date.temp
Wed jul 31 10:45:21 MET 2000
Wed jul 31 10:45:36 MET 2000
$
3.3 Ridirezione dell’ingresso standard a partire da un file
La shell permette anche di ridirigere l’ingresso standard verso un comando. Un comando prende i suoi dati
d’ingresso a partire da un canale di I/O, denominato ingresso standard (standard input, o stdin),
normalmente connesso alla tastiera del terminale, ma si può ugualmente utilizzare un file, o delle
informazioni che sono state inserite in precedenza, come ingresso standard per questo comando.
Esempi:
$ mail marion <letter
$
Per default, mail prende il testo di questo messaggio a partire dall’ingresso standard, vale a dire la tastiera;
il fatto di avere specificato "<letter", ha per effetto di ridirigere l’ingresso del comando mail a partire dal
file "letter".
$ cat <who.temp
Wed jul 31 10:33:20 MET 2000
gianni
pts/0
jul 31 09:46
luca
pts/2
jul 31 09:17
marion
pts/6
jul 31 09:34
marion
ttyS0
jul 31 09:02
$
Questo comando ha per effetto di visualizzare il contenuto del file "who.temp". Si noti che il comando cat
si può utilizzare ugualmente senza il segno <, ma questa non è che una facilitazione poichè cat è un
comando che legge, in assenza di argomenti, dal suo ingresso standard e scrive sulla sua uscita standard.
V. Asta - Introduzione a Unix e GNU/Linux
29
Vista l’utilizzazione di questo comando il segno < è implicito.
Più precisamente, si può dire che esistono sotto UNIX numerosi comandi, di cui cat è un esempio, che
accettano uno o più file di input come argomento; se tali argomenti mancano del tutto, l’input è letto dallo
stdin. Esempi, tra i comandi già visti, sono: cat, grep, more, pr, lpr, wc, mail.
Un comando che è in grado di lavorare leggendo dallo stdin e scrivendo allo stdout è detto un filtro.
Esempio:
$ who >tmp
gianni
gianni
gianni
$
; grep gianni <tmp
ttya4
jul 31 10:50
ttyc6
jul 31 09:34
ttya2
jul 31 09:02
Questo comando crea un file di nome "tmp" contenente i riferimenti delle persone loggate; in seguito grep
verifica se il pattern "gianni" è presente, leggendo dal proprio ingresso standard, che è costituito dal file
"tmp".
Si noti che l’operazione di ridirezione dell’ingresso/uscita standard, è effettuata dalla shell in modo
totalmente indipendente dal contesto. Così è possibile digitare lo stesso comando nella forma seguente:
$ >tmp who ; <tmp grep gianni
gianni
ttya4
jul 31 10:50
gianni
ttyc6
jul 31 09:34
gianni
ttya2
jul 31 09:02
$
Anche se questa forma non è particolarmente leggibile, essa è perfettamente valida per la shell.
3.4 Pipe: comunicazione tra processi
La shell permette di mettere in comunicazione due processi, in modo che l’uscita standard di un comando
costituisca l’ingresso standard di un secondo. Per illustrare questa possibilità della shell, riprendiamo
l’esempio trattato precedentemente:
$ who >tmp
gianni
gianni
gianni
$ rm tmp
$
; grep gianni <tmp
ttya4
jul 31 10:50
ttyc6
jul 31 09:34
ttya2
jul 31 09:02
L’ultimo comando, rm, rimuove il file di appoggio "tmp", per evitare di conservare dei file temporanei ed
inutili.
L’utilizzazione del pipe permette di riassumere questi tre comandi in uno solo:
$ who | grep gianni
gianni
ttya4
jul 31 10:50
gianni
ttyc6
jul 31 09:34
gianni
ttya2
jul 31 09:02
$
L’uscita prodotta dal comando who costituisce l’ingresso del comando grep. Quindi who dà l’elenco delle
persone loggate ad un momento dato; grep, cerca invece se il pattern "gianni" è presente nel flusso di dati
che riceve. Possiamo dunque considerare che il comando grep gioca il ruolo di filtro, come già detto.
$ ls -l /tmp | grep marion | tee file
-rw--------- 1 marion users
37888 jul 31 11:17 Ex01687
V. Asta - Introduzione a Unix e GNU/Linux
30
-rw--------- 1 marion
$ cat file
-rw--------- 1 marion
-rw--------- 1 marion
$
users
5120 jul 31 11:18 Ex01693
users
users
37888 jul 31 11:17 Ex01687
5120 jul 31 11:18 Ex01693
Questo comando permette di mandare in uscita tutti i file presenti nella directory /tmp, questa uscita è
utilizzata da grep che filtra tutti i file appartenenti a marion. Una volta operata questa selezione, la si dirige
sul comando tee, che si limita a duplicare le sue uscite; vale a dire che invia le informazioni che riceve, non
soltanto alla sua uscita standard ma anche al file "file", che viene creato se non esiste.
Si noti che non si vedrà alcun risultato intermedio di questa serie di pipe.
3.5 Classificazione dei comandi
Un approccio possibile per classificare i comandi, è di considerarli dal punto di vista dell’ingresso/uscita.
3.5.1 Comandi con ingresso e uscita
I comandi di questa categoria hanno il proprio ingresso standard associato alla tastiera o ad un file, mentre
l’uscita standard può essere sia lo schermo, sia un file. In base a queste caratteristiche essi sono suscettibili
di essere combinati con un pipe.
Esempi:
wc
$ cat /etc/passwd | wc
27
44
1186
$ wc </etc/passwd >tmp
$ cat tmp
27
44
1186
$ rm tmp
$
grep
$ grep marion </etc/passwd
marion:OaGKskj1Q1By2:243:100:Marion Rossi:/home/marion:/bin/ksh
$
3.5.2 Comandi aventi solo un’uscita
Essi hanno soltanto uscite, e possono accettare degli argomenti, ma non hanno ingresso.
who
I parametri di esecuzione di questo comando sono degli argomenti che determinano il tipo di
uscita, questa sarà effettuata per default sullo schermo, tuttavia essa potrà essere ridiretta.
echo
stampa i suoi argomenti sull’uscita standard.
3.5.3 Comandi aventi una sola entrata
mail
mail prende in argomento il nome della persona a cui è destinato il messaggio; prende in ingresso
il messaggio stesso, che può dunque essere dato a partire da un file; non produce alcuna uscita.
3.5.4 Comandi senza nè ingresso nè uscita standard
cd
accetta un solo argomento indicante la nuova directory corrente; non è prodotta alcuna uscita.
rm
accetta solo nomi di file; non produce alcuna uscita.
3.6 I processi in background
UNIX è un Sistema Operativo multi-task. Questo significa che si possono eseguire più processi
V. Asta - Introduzione a Unix e GNU/Linux
31
simultaneamente. In effetti, com’è ben noto, il calcolatore tratta un solo processo alla volta34, ma lo
scheduler di CPU del kernel permette al sistema di passare da un processo all’altro molto rapidamente.
3.6.1 Esecuzione asincrona di un processo
UNIX non attribuisce un unico processo per utente ma permette ad uno stesso utente di eseguire più processi
alla volta. Per fare questo è sufficiente utilizzare il metacarattere35 & alla fine di una riga di comando;
questo comando sarà allora lanciato in modo asincrono, o in background: la shell lancia il comando e non
ne aspetta la fine, ma è pronta ad accettare immediatamente altri comandi.
Ecco un esempio di comando che può richiedere più di un minuto per essere eseguito:
$ find / -name program.c -print &
3672
$
Questo comando cerca a partire dalla root directory (la radice del file sistem) tutti i file di nome
"program.c"; per questo, il programma find esplorerà tutta la struttura ad albero, ed ogni volta che
incontrerà un file di nome "program.c", visualizzerà il suo pathname completo sullo schermo36.
Dopo aver convalidato questa riga con un <CR> (ritorno carrello), la shell visualizza un numero; questo
rappresenta il numero che il sistema ha attribuito al vostro processo. Questo numero è denominato PID
(Process IDentifier).
Più comandi possono essere lanciati in background con l’aiuto di parentesi37.
Esempio:
$ (date; find / -type d -print) >/tmp/lista.directories &
$
Questo comando memorizza, nel file specificato, dapprima la data e a seguire la lista di tutte le directory del
sistema; l’insieme dei due programmi (date e find) è lanciato in background, con l’output ridiretto sul file.
3.6.2 Stato dei processi
È possibile ottenere delle informazioni sui processi in esecuzione tramite il comando ps
Esempio:
$ ps -f
UID
PID PPID
gianni
827
782
gianni
874
1
gianni 13148
827
gianni 13175
874
gianni 13187 13176
$
C STIME TTY
0 Dec30 pts/0
0 Dec30 pts/0
0 12:59 pts/0
0 13:01 pts/0
0 13:01 pts/0
TIME CMD
00:00:02 -bash
00:00:01 sh /home/gianni/bin/pconn
00:00:00 vi Disp_P2_01.mm
00:00:00 sleep 60
00:00:00 ps -f
34.
Supponendo una macchina con una sola CPU; su una macchina multiprocessore, con N CPU, i processi in esecuzione
simultanea saranno al massimo N .
35.
Per metacarattere si intende qualsiasi carattere che abbia un significato speciale per la shell; vedi oltre, al paragrafo "caratteri
speciali" (paragrafo 3.7 pag. 33).
36.
Il comando find è presentato in dettaglio in un’Appendice del testo.
37.
Come sarà precisato successivamente (vedi paragrafo 3.7 pag. 33), i comandi tra parentesi tonde vengono eseguiti in una subshell.
V. Asta - Introduzione a Unix e GNU/Linux
32
Questo comando indica tra l’altro gli identificativi numerici dei processi (PID) collegati al terminale di
lavoro, il nome del terminale stesso (qui pts/0), il PID del padre di ciascun processo (PPID), l’ora (o il
giorno) di avvio del programma (STIME), il tempo CPU utilizzato fin qui (TIME), i nomi dei comandi in
esecuzione e i loro argomenti.38
L’arresto di un processo in background, ove necessario, si effettua con l’aiuto del comando kill:
kill numero-processo
Il numero di processo fa riferimento al processo lanciato in background. Si noti che il fatto di lanciare un
comando in background provoca la disattivazione dell’ingresso standard40, a meno che questo non sia
esplicitamente ridiretto, mentre invece non modifica la sua uscita standard. Se il comando deve produrre
un’uscita, può essere utile ridirigere l’uscita su di un file per non essere disturbati da questa, mentre si
continua a lavorare.
3.7 Caratteri speciali
Esistono dei caratteri, detti metacaratteri della shell, aventi per questa un significato speciale:
* ? [ ] < > ; | ’ ` & " = $ /
Pertanto è consigliabile non utilizzarli per attribuire il nome ad un file.
*?[]
Quando la shell incontra questi caratteri, li sostituisce con i nomi dei file che ha potuto trovare.
Esempi:
$ ls -l *.c
-rw-r--r--rw-r--r--rw-r--r-$
1 gianni
1 gianni
1 gianni
dev
dev
dev
1024 jul 31 11:57 foo.c
2048 jul 31 11:57 prog.c
2048 jul 31 11:57 ap.c
Il carattere ‘*’ seleziona tutte le stringhe (compresa quella nulla) salvo il carattere ‘/’. Per questo la riga di
comando qui sopra, visualizza tutti i file nella directory corrente terminanti per ’.c’.
$ ls -l ??.c
-rw-r--r-$
1 gianni
dev
2048 jul 31 11:57 ap.c
Il carattere ‘?’ seleziona un carattere qualunque. Questo esempio visualizza tutti i file il cui nome comporta
due caratteri qualsiasi seguiti dal suffisso ’.c’.
$ ls -l [a-c]?.[ac]
-rw-r--r-1 gianni
-rw-r--r-1 gianni
$
dev
dev
2048 jul 31 11:57 ap.c
3246 jul 31 11:59 bk.a
Le parentesi quadre selezionano tutti i caratteri:
— sia compresi in un dato intervallo, se il carattere - è presente: [a-c]
— sia facenti parte di un elenco: [ac]. Così la riga di comando considerata visualizza tutti i file che
iniziano per a, b o c, seguiti da un carattere qualunque, seguito a sua volta da un . e terminante per a
39.
Il formato esatto dei dati visualizzati da ps varia a seconda dello specifico Sistema Operativo UNIX, e delle eventuali opzioni
passate in argomento al programma; consultare ps(1) per i dettagli.
40.
Più precisamente, lo standard input dei processi lanciati in background è ridiretto, per default, su /dev/null; quest’ultimo è uno
pseudo-device (vedi paragrafo paragrafo 9. pag. 63 sui file speciali): la lettura da /dev/null provoca sistematicamente una
condizione di end of file (0 byte letti).
V. Asta - Introduzione a Unix e GNU/Linux
33
o c.
V. Asta - Introduzione a Unix e GNU/Linux
34
4. Sintassi dei comandi
4.1 Comandi semplici
Un comando semplice è una serie di parole separate da spazi o da tab; o, più in generale, da qualsiasi
carattere precisato nella variabile IFS (vedi "Assegnazione e sostituzione di variabili", paragrafo 5.4 pag.
43). La prima parola è considerata come il nome del comando; le altre come gli argomenti di questo
comando.
Esempi:
ls
cd test
cat fileA fileB
chmod +x fileA
who
mv fileA fileZ
wc -l fileZ
grep jo fileZ
man sort
Un comando possiede uno status o valore significativo di ritorno. Questo valore è memorizzato in una
variabile shell, ma non è stampato. Le terminologie utilizzate per designare lo ‘status’ sono variabili; è
possibile trovare indifferentemente i termini ‘exit code’, ‘codice di uscita’, ‘exit status’, ‘return code’ o
altro; qui, oltre a ‘status’, sarà usato talvolta il termine ‘codice di uscita’, o il suo equivalente ‘exit code’.
Per convenzione, i comandi hanno uno status uguale a 0 in caso di successo (il programma si è eseguito
normalmente fino in fondo), e diverso da 0 in caso d’errore (in tal caso, ove ciò sia utile, si possono
utilizzare diversi valori per significare distintamente diverse possibili condizioni di errore).
4.2 Pipeline
Un pipeline è un comando semplice o una serie di comandi semplici separati dal carattere | (denominato
pipe).
cmd1 | cmd2
L’uscita standard di cmd1 serve come ingresso standard per cmd2. Ogni comando è eseguito da un
processo distinto. I due processi lavorano nello stesso tempo, e sono sincronizzati. La shell attende che
l’ultimo sia terminato, prima di continuare.
Esempi:
$ ls | wc -l
20
$ ls -l | grep test
-rw-r--r-1 gianni
$
axis
2238 jul 29 15:03 test
4.3 Liste
Una lista è un pipeline o una serie di più pipeline separati da ;, &, &&, ||, eventualmente terminanti con ; o
&.
V. Asta - Introduzione a Unix e GNU/Linux
35
— ; e & hanno la stessa priorità.
— && e || hanno la stessa priorità.
— ; e & hanno maggiore priorità rispetto a && e ||.
; : esecuzione in sequenza
cmd1 ; cmd2
Dapprima viene eseguito cmd1, e successivamente cmd2.
Esempio:
$ cd ; ls
Si pone nella HOME directory e lista il suo contenuto.
& : esecuzione in parallelo, o asincrona
cmd1 & cmd2
cmd1 e cmd2 sono lanciati contemporaneamente; entrambi si eseguono in modo asincrono
rispetto all’altro.
Caso particolare:
& : esecuzione ’in background’
cmd &
L’esecuzione di cmd sarà lanciata, poi la shell continuerà senza attendere la fine
dell’esecuzione (è la shell stessa che è in parallelo con il comando).
Esempio:
$ find / -name ’*.o’ -print| sort >/tmp/obj-lista &
1401
$
Mette l’elenco di tutti i files che terminano per ".o" (files oggetto rilocabili), selezionati in
ordine alfabetico, nel file "/tmp/obj-lista"; poichè il comando portà impiegare un certo tempo
ad eseguirsi, è comodo mandare il programma in background, così la shell restituisce
immediatamente il prompt ed è pronta ad accettare altri comandi mentre il primo si esegue.
&& : ’and’ logico
cmd1 && cmd2
Se cmd1 ritorna 0 ( vero in shell), cmd2 sarà lanciato. Se cmd1 ritorna con un valore diverso da
0 ( falso in shell), cmd2 non sarà eseguito. In ogni caso, il codice di uscita del costrutto è
quello ell’ultimo comando eseguito.
Nota: non è usuale trovare 0 per rappresentare il valore ’vero’; ma questa scelta, come già
detto, permette di restituire dei codici d’errore significativi, permettendo di determinare con
precisione dove si è verificato l’errore.
Esempio:
$ [ -d tmp ] && cd tmp
$
V. Asta - Introduzione a Unix e GNU/Linux
36
Se tmp esiste ed è una directory, posizionarsi qui come directory di lavoro; altrimenti restare
nella directory attuale. (per la notazione [ -d tmp ], vedi l’Appendice 5 sul comando test o la
pagina di manuale di test(1)).
|| : ’or’ logico
cmd1 || cmd2
Se cmd1 risulta falso, cmd2 sarà lanciato. Se cmd1 risulta vero, cmd2 non sarà eseguito. In
ogni caso, il codice di uscita del costrutto è quello ell’ultimo comando eseguito.
Esempio:
$ cd $HOME/tmp || cd /tmp
Se non esiste la directory tmp nella HOME directory, portarsi nella directory comune /tmp.
4.4 Comandi
Un comando è un comando semplice o uno dei costrutti seguenti, che permettono la programmazione
strutturata in shell:
4.4.1 Il costrutto for
for name [ in word... ]
do
list
done
for, in, do e done sono parole chiavi del linguaggio shell. La lista di comandi list viene eseguita tante volte
quante sono le parole word che seguono in, con il parametro name che assume successivamente il valore
delle singole parole. Ad esempio, nel costrutto seguente: "for I in a b c", il parametro I prenderà dapprima
come valore ’a’, poi ’b’, ed infine ’c’. La sezione "in word..." è facoltativa; se viene omessa, essa è, per
default, costituita dall’elenco degli argomenti che sono stati passati al comando (equivale cioè a "for I
in $*" - vedi oltre, "Assegnazione e sostituzioni di variabili", paragrafo 5.4 pag. 43). L’esecuzione
termina quando non ci sono più elementi nell’elenco.
Esempi:
for I in 1 2 3
do
cp file$I /tmp
done
Copia i file file1, file2 e file3 nella directory /tmp.
for I
do
echo $I
done
"for I" è, come detto, l’equivalente di "for I in $*"; viene stampata la lista degli argomenti, uno
per riga.
for I
do
grep $I *.c
done
cerca ciascun pattern passato in argomento in tutti i files che terminano per ’.c’.
V. Asta - Introduzione a Unix e GNU/Linux
37
for i
do
echo $i:
sed "s/$1/$2/g" $i
done
Sostituisce, in ogni riga di tutti i file passati in argomento, tutte le occorrenze della stringa "$1" con la
stringa "$2"41.
4.4.2 Il costrutto case
case word in
pattern [| pattern ]...) [list];;
...
esac
case, in ed esac sono parole chiavi del linguaggio shell. Il comando case esegue l’elenco di comandi list
associato al primo pattern che seleziona word. La forma di un pattern è la stessa di quella utilizzata per la
generazione dei nomi di files (avvalendosi degli operatori *, ?, []), con l’aggiunta dell’operatore |, che
indica alternativa. Come si vede, ciascun pattern è delimitato da una parentesi tonda chiusa, e ciascuna lista
di comandi associata ad un pattern termina con un doppio punto e virgola (;;).
Esempi:
case $1 in
a) X=alpha
b) X=beta
g) X=gamma
*) X=$1 ;;
esac
echo $X
;;
;;
;;
Se $1 è ’a’, stampa alpha, altrimenti se $1 è ’b’, stampa beta, altrimenti se $1 è ’g’, stampa gamma,
altrimenti stampa $1 inalterato.
case $# in
3) ed - $3 <<%%
g/$1/s//$2/
w
q
%%
;;
*) echo "usage: $0 s1 s2 file" ; exit 1;;
esac
Cambia, tutte le volte che si presenta, $1 con $2 nel file dato da $3.
41.
$1, $2, $3 etc. indicano rispettivamente il primo, secondo, terzo etc. argomento di una procedura di comandi shell; vedi oltre,
"Assegnazione e sostituzioni di variabili", paragrafo 5.4 pag. 43.
V. Asta - Introduzione a Unix e GNU/Linux
38
FLAG=
for A
do
case $A in
-[ocO]) FLAG="$FLAG $A" ;;
-*) echo unknown flag $A; exit 1 ;;
*.c) cc $FLAG $A; FLAG= ;;
*.s) as $FLAG $A; FLAG= ;;
*) echo unexpected argument $A; exit 1 ;;
esac
done
Compila o assembla i file passati in argomento con le opzioni valide.
4.4.3 Il costrutto if
if list1
then
list2
[elif list3
then
list4]
[else
list5]
fi
if, then, elif, else e fi sono parole chiavi del linguaggio shell. list1 è eseguito, se il suo valore di ritorno è
vero (0) list2 sarà eseguito; altrimenti list3 è eseguito, se il suo valore di ritorno è vero, list4 sarà eseguito,
altrimenti sarà eseguito list5. Possono esserci più elementi "elif - then" di seguito.
Esempio:
V. Asta - Introduzione a Unix e GNU/Linux
39
for I
do
if test -f "$I"
then
echo -n "$I" is an ordinary file
if test -r "$I"
then
echo -n readable
fi
if test -w "$I"
then
echo -n writable
fi
if test -x "$I"
then
echo -n executable
fi
echo
elif test -d "$I"
then
echo "$I" is a directory
else
echo "$I" is unknown
fi
done
Per ogni argomento, stampa il suo tipo (file o directory) ed i diritti di accesso che gli sono associati. (per
test, vedi l’Appendice 5 su questo comando).
4.4.4 Il costrutto while
while list1
do
list2
done
while, do e done sono parole chiavi del linguaggio shell. Finchè il valore di ritorno di list1 è vero, list2 è
eseguito.
Esempio:
while :
do
if who | grep $1 > /dev/null
then
echo $1 è loggato
exit
else
sleep 180
fi
done
Cerca se l’utente il cui nome è dato nel primo argomento è loggato, e questo fino a che lo sia
effettivamente, riprovando ogni 3 minuti (180 secondi).
L’argomento ‘:’ di questo loop while è uno pseudo-comando, built-in del linguaggio shell, che resta sempre
vero, e non effettua alcuna azione.
V. Asta - Introduzione a Unix e GNU/Linux
40
4.4.5 Il costrutto until
until list1
do
list2
done
until, do e done sono parole chiavi del linguaggio shell. Finchè il valore di ritorno di list1 è falso, list2
sarà eseguito.
Esempio:
until who | grep $1 >/dev/null
do
sleep 300
done
echo "$1 e’ arrivato"
Ogni 5 minuti (300 secondi), controlla se l’utente il cui nome è stato dato in argomento ($1) risulta loggato
nel sistema; continua fintantochè l’esito è negativo, poi quando finalmente l’utente risulta connesso, stampa
a schermo il messaggio che è arrivato.
4.4.6 I sotto-processi
( lista )
Esempio:
$ (date ; who) >file
Esegue la lista di comandi in una sub-shell.
La ridirezione dell’uscita standard ">file" si applica per tutti i comandi di questa sub-shell: in effetti, è lo
stdout della sub-shell che che viene ridiretto sul file; tutti i programmi eseguiti al suo interno ereditano
ovviamente l’ambiente, tra cui la ridirezione dell’uscita standard.
4.4.7 L’esecuzione semplice
{ lista
}
Esegue semplicemente la lista senza creare sub-shell.
Nota: le parentesi graffe ({ }) sono riconosciute come delimitatori di lista solo se in una posizione
sintatticamente equivalente ad un comando; pertanto devono obbligatoriamente trovarsi dopo un line feed, o
dopo un ; o altri separatori di comando.
V. Asta - Introduzione a Unix e GNU/Linux
41
5. L’interprete di comandi - 2
5.1 Funzionamento generale
L’interprete shell viene impiegato per:
— stampare il prompt
— attendere una riga
— trattare questa riga.
In modo più dettagliato, trattare una riga significa:
— Trattamento dei caratteri quotati.
— Sostituzione delle variabili.
— Sostituzione dei comandi.
— Sostituzione dei nomi di file.
— Se si tratta di un comando speciale: eseguirlo.
Altrimenti
- eseguire un fork
a.
per il processo padre:
. se non si tratta di un processo lanciato in background attendere la fine del comando.
. altrimenti fine.
b.
per il processo figlio:
. redirezione dell’ingresso/uscita.
. costruzione di una tavola di argomenti.
. esecuzione del comando.
Nei seguenti sottoparagrafi vengono dettagliate le operazioni introdotte.
5.2 Il Prompt
Prima di attendere un comando, la shell stampa come prompt il valore della variabile shell PS1 (valore di
default: PS1=’$ ’, salvo per l’utente root: PS1=’# ’).
Dopo un ritorno carrello, se il comando è incompleto, la shell stampa come prompt secondario il valore
della variabile PS2 (valore di default: PS2=’> ’).
5.3 Quoting
Gli operatori seguenti hanno un significato speciale per la shell, e agiscono da separatori se i relativi
caratteri non sono quotati.
; & | && || ( ) { } < > << >> * ? $ ’ " ` \ <newline> <space> <tab>
— Un carattere preceduto da \ è quotato.
— Tutti i caratteri inclusi tra una coppia di ’ sono quotati, eccetto ’ stesso.
— Tutti i caratteri inclusi tra una coppia di " sono quotati, ma le sostituzioni dei parametri ($PARAM) e
dei comandi ( `cmd arg...`, $(cmd arg ...) ) sono effettuate; i caratteri $ ` " \ sono quotati da \.
Esempio:
V. Asta - Introduzione a Unix e GNU/Linux
42
$ echo *
Stamperà tutti i nomi di file della directory.
$ echo ’*’
Stamperà il carattere *.
5.4 Assegnazione e sostituzioni di variabili
Una variabile shell (o variabile di ambiente) VAR è rappresentata da un nome costituito da una serie di
lettere, di cifre, underscore (_), oppure da uno dei caratteri: * @ # ? - $ !
VAR=value
Assegna la stringa di caratteri value alla variabile VAR.
Esempio:
$ TDIR=/home/gianni/tmp
$
$VAR
sostituzione col valore della variabile VAR (detto anche interpolazione della variabile)
Esempio:
$ cd $TDIR
$ pwd
/home/gianni/tmp
$
${VAR}
Identico a $VAR, ma utile a delimitare il nome del parametro se questo deve essere
seguito da uno o più caratteri.
Esempio:
$ X=1
$ Y=2
$ echo $X$Y
12
$ echo $XO
$ echo ${X}O
10
$
${VAR:-word} Se VAR ha un valore, sostituire questo valore, altrimenti sostituirgli word.
Esempio:
$ mv file ${TDIR:-/tmp}
Se TDIR non ha un valore, file sarà posto nella directory /tmp.
${VAR:=word} Se VAR non ha valore, assegnargli word come valore; sostituire VAR con il suo valore.
Questo permette di stabilire dei valori di default.
Esempio:
$ cc ${FLAG:=-O} *.c
Se FLAG non ha valore gli sarà assegnato -O e tutti i file della directory corrente che
terminano per ’.c’ saranno compilati con $FLAG come opzione per cc.
V. Asta - Introduzione a Unix e GNU/Linux
43
${VAR:?word} Se VAR ha un valore, sostituirlo. Altrimenti stampare word ed uscire dalla shell. Se word
è omesso, la shell stampa un messaggio per default.
Esempio:
$ mv file ${TDIR:?no dir}
Se TDIR ha un valore, il file file è posto nella directory $TDIR; altrimenti il messaggio
"no dir" è stampato.
${VAR:+word} Se VAR ha un valore, sostituirlo con word e rimandarlo, altrimenti non rinviare nulla.
Nota: word è valutato solo se deve essere utilizzato.
Alcune variabili sono posizionate automaticamente dalla shell:
0 1 2 3 ...
parametri posizionali contenenti gli argomenti del comando lanciato. $0 è il nome del
comando stesso, $1 è il suo primo argomento, $2 il secondo, e così via.
#
numero di parametri posizionali in decimale (ad esclusione di $0).
Esempio:
Per un comando che necessita di almeno un argomento:
case $# in
0) echo usage: ....
exit 1 ;;
*) comando ... ;;
esac
Permette di sapere se è stato dato il numero esatto di argomenti al comando, e di
visualizzare il modo di utilizzarlo.
*,@
— $* equivale a "$1 $2 $3 ..."
— $@ equivale a "$1" "$2" "$3" ...
-
opzioni passate alla shell alla sua chiamata o tramite il comando set (vedi oltre, "Comandi
speciali", paragrafo 5.7 pag. 46).
?
status di ritorno dell’ultimo comando eseguito, in decimale.
$
numero di processo (PID) della shell.
Nota: questa variabile può servire ad esempio per creare dei file temporanei di nome
differente ed unico:
$ >file$$
$ ls file*
file1254
$
In generale viene usato negli shell script.
!
numero di processo (PID) dell’ultimo comando lanciato in background. Ciò è molto utile
per arrestare l’ultimo processo lanciato in background, senza dover eseguire il comando
ps.
Esempio:
$ kill -15 $!
V. Asta - Introduzione a Unix e GNU/Linux
44
Le variabili seguenti sono utilizzate dalla shell, ma sono posizionate solo da comandi espliciti.
HOME
HOME directory.
PATH
percorso per accedere ai comandi.
CDPATH
un PATH per il comando cd.
Esempio:
$ CDPATH=:/usr
$ cd games
/usr/games
$
MAIL
se questa variabile contiene il nome di un mailbox, la shell segnala l’arrivo di un messaggio
in questo mailbox.
PS1
prompt principale ( per default ’$ ’).
PS2
prompt secondario ( per default ’> ’).
IFS
separatori di parole per la shell (per default spazio, <tab>, <newline>)
Infine, le seguenti variabili, tra le altre, sono anch’esse utilizzate dalla shell, che le posiziona
automaticamente (come per i parametri posizionali e gli altri parametri speciali visti in apertura di
paragrafo):
PWD
posizionato al pathname della directory di lavoro corrente
OLDPWD
posizionato al pathname della directory di lavoro precedente
5.5 Sostituzione di comandi
L’uscita standard di un comando posto tra ` ` o tra $( ) viene succcessivamente utilizzata come una parola o
una serie di parole nel comando (i <newline> sono ignorati).
Esempi:
$ DIR=`pwd`
$ echo $DIR
/home/gianni
$
$ A=1
$ A=$(expr $a + 1)
$ echo $A
2
$
In uno shell script:
for I in `ls -t`
do
...
...
done
Per trattare tutti i file della directory corrente selezionati in ordine di data.
set $(date)
Assegna i parametri posizionali ai campi della data (vedi set nel paragrafo paragrafo 5.7
"Comandi speciali").
V. Asta - Introduzione a Unix e GNU/Linux
pag. 46,
45
5.6 Sostituzione dei nomi di file
I metacaratteri della shell per la sostituzione dei nomi di file (file globbing) sono:
*, ?, []
Se uno di questi caratteri compare in una parola, questa è considerata come un pattern. Esso sarà sostituito
dall’elenco di nomi dei file che selezionano questo pattern, messi in ordine alfabetico. Se la shell non trova
alcun nome di file che seleziona il pattern, questo sarà conservato tale e quale. Il carattere ’.’ all’inizio del
nome di file, così come il carattere ’/’, deve essere selezionato esplicitamente.
— * seleziona qualsiasi stringa, compresa quella nulla.
— ? seleziona qualsiasi carattere.
— [...] seleziona uno qualsiasi dei caratteri tra le parentesi quadre. Una coppia di caratteri separati da ed entro parentesi quadre seleziona qualunque carattere incluso nell’intervallo lessicografico definito.
Esempi:
ls f*
elenca tutti i file il cui nome comincia per ’f’
ls file?
lista tutti i file il cui nome è composto da file, seguito da un carattere qualsiasi.
ls file[A-Z]
lista tutti i file il cui nome è composto da file, seguito da una lettera maiuscola.
ls*.c
lista tutti i file il cui nome termina con i due caratteri ".c".
ls ?.c
lista tutti i file il cui nome è formato da un carattere qualunque, seguito dai due caratteri
’.c’
ls ? ?? ???
lista tutti i file il cui nome è composto da 1, 2, o 3 caratteri.
5.7 Comandi speciali
Questi comandi sono eseguiti nella stessa shell (e non in un sottoprocesso), e non permettono, in generale,
di ridirigere gli ingressi/uscite.
:
questo comando non fa nulla; ritorna 0
. file
legge file, ed esegue i comandi letti senza generare delle sotto-shell; è utile per eseguire ad
esempio .profile
$ cat >.profile
PS1=’yes,dear? ’
ˆD
$ chmod +x .profile
$ .profile
$ . .profile
yes,dear?
break [n]
permette di uscire da n blocchi nidificati; se n non è precisato, 1 è preso per default, quindi
permette di uscire dal blocco corrente. (Un blocco è un loop for, while o until)
continue [n] permette di riprendere all’inizio dell’iterazione seguente nello n-mo blocco nidificato; se n
non è precisato, 1 è preso per default.
cd [dir]
prende dir come directory corrente; se dir non è precisato, il valore di $HOME è preso per
default; se dir vale -, è preso il valore di $OLDPWD; vedi anche la variabile CDPATH
eval [arg]
gli argomenti sono letti come input per la shell, valutati ed eseguiti. Serve per forzare una
nuova valutazione di una stringa di comando, di solito costruita con variabili shell a cui sono
stati assegnati valori con metacaratteri della shell, che debbono essere valutati in un secondo
momento.
V. Asta - Introduzione a Unix e GNU/Linux
46
Esempio:
# con l’opzione -p, l’output viene paginato allo schermo;
# altrimenti viene inviato allo stdin come un unico flusso
OUT=
case $1 in
-p) OUT="|more" ;;
...
esac
eval commd args $OUT
# si richiede qui di interpretare
# il | come operatore di pipe
exec [arg]
il comando specificato da arg è eseguito al posto della shell. Non c’e quindi creazione di un
nuovo processo. Gli ingressi/uscite possono essere ridiretti. Questo sarà l’ultimo comando
eseguito dalla procedura (la shell fa una chiamata sistema exec(2), quindi sparisce).
exit [n]
termina una shell rimandando n come codice d’uscita. Se n è omesso, il codice è quello
rinviato dall’ultimo comando eseguito.
export [var...] le variabili specificate vengono poste nell’ambiente di lavoro attuale (working environment),
dunque i processi figli le erediteranno. Se non ci sono argomenti, l’elenco delle variabili
esportate viene stampato.
newgrp arg
equivale ad ’exec newgrp arg’42
read var [var ...] legge una riga sull’ingresso standard; le parole lette sono assegnate, in ordine, alle
variabili specificate. Se ci sono più parole che variabili, tutte le parole restanti sono
assegnate all’ultima variabile. Il valore di ritorno è 0 salvo in caso di fine file.
Esempi:
42.
Vedere newgrp(1) per dettagli.
V. Asta - Introduzione a Unix e GNU/Linux
47
$ echo ciao bello | read AAA
$ echo $AAA
ciao bello
$ echo ciao bello | read AAA BBB
$ echo $AAA
ciao
$ echo $BBB
bello
$ echo ciao bello come stai | read AAA BBB
$ echo $AAA
ciao
$ echo $BBB
bello come stai
# cat rubrica
Gianni Bianchi via Giulio Cesare n. 43, Roma
Luca Verdi via Marco Aurelio n. 54, Milano
$ cat rubrica | while read NOME COGNOME INDIRIZZO
> do
>
echo Nome: $NOME / Cognome: $COGNOME -- Ind.: $INDIRIZZO
> done
Nome: Gianni / Cognome: Bianchi -- Ind.: via Giulio Cesare n. 43, Roma
Nome: Luca / Cognome: Verdi -- Ind.: via Marco Aurelio n. 54, Milano
readonly [var...] le variabili specificate sono in sola lettura, e non si potrà dunque assegnar loro dei nuovi
valori. Se non ci sono argomenti, l’elenco delle variabili in sola lettura viene stampato.
set [-enptuvx [arg...]] ciascuna opzione viene posizionata servendosi di ’set -o’, e puo‘ essere annullata da
’set +o’ (dove o è un’opzione).
-a
ogni variabile creata o modificata nella shell corrente sarà automaticamente
esportata.
-e
se la shell non è interattiva, uscire non appena un comando ritorna ’falso’.
-f
vieta l’uso dei metacaratteri per la generazione di nomi di file.
Esempio:
$ set -f
$ cat *
cat: can’t open *
$ set +f
$
-n
legge i comandi ma non li esegue.
-u
considera le variabili non definite come un errore.
-v
stampa le righe shell così come sono lette.
-x
stampa i comandi ed i loro argomenti così come sono eseguiti.
-
annulla le opzioni -x e -v.
Tutte queste opzioni possono essere date al momento della chiamata della shell. Esse sono
V. Asta - Introduzione a Unix e GNU/Linux
48
custodite nella variabile $-.
set può altrimenti essere utilizzato per posizionare esplicitamente i parametri posizionali,
assegnando quindi nuovi valori a $1 $2 $3 etc, e agli altri parametri a questi correlati: $* $@
$#.
Esempio:
$ set abc def ghi
$ echo $* / $#
abc def ghi / 3
shift [n]
i parametri posizionali sono scalati di n posizioni verso sinistra; $# è diminuito di n. Se n è
omesso, i parametri sono scalati di 1 per default.
Esempio:
$ set a.out aaa.c bbb.c file1.txt file2.txt
$ echo $* / $#
a.out aaa.c bbb.c file1.txt file2.txt / 5
$ shift
$ echo $* / $#
aaa.c bbb.c file1.txt file2.txt / 4
$ shift 2
$ echo $* / $#
file1.txt file2.txt / 2
$
time
stampa l’accumulo di tempo reale, del tempo utente e del tempo sistema utilizzato per i
processi lanciati a partire dalla shell.
trap [arg] [n] arg è un comando (o un insieme di comandi) che sarà letto ed eseguito dalla shell quando
questa riceverà il segnale n. Se arg è omesso, il segnale riprende il suo valore iniziale. Se
arg è una stringa vuota, il segnale è ignorato. trap senza argomento stampa l’elenco dei
valori associati al segnale.
Esempio:
TFILE=/tmp/tf.$$
trap ’rm -f $TFILE; exit’ 2 3
#
#
#
#
#
file temporaneo
intercetta i segnali
n. 2 e 3 (intr e quit);
se interrotto, rimuovi
il file prima di uscire
# sezione critica, in cui viene fatto uso
# del file temporaneo
...
# fine sezione critica
rm $TFILE
trap 2 3
# non intercettare più
# i segnali
...
umask [nnn] la maschera per i permessi d’accesso dopo la creazione di un file prende il valore ottale nnn
(vedi la chiamata sistema umask(2) per dettagli). Se nnn è omesso, umask stampa il valore
corrente del comando stesso.
V. Asta - Introduzione a Unix e GNU/Linux
49
Esempio:
$ umask
0000
$ cc foo.c
$ ls -l a.out
-rwxrwxrwx
$ umask 002
$ cc foo.c
$ ls -l a.out
-rwxrwxr-x
$ umask 007
$ cc foo.c
$ ls -l a.out
-rwxrwx--$
wait [n]
1 gianni
axis
1008 jul
3 16:39 a.out
1 gianni
axis
1008 jul
3 16:39 a.out
1 gianni
axis
1008 jul
3 16:39 a.out
attende la fine del processo con PID pari a n e ritorna il suo codice d’uscita. Se n è omesso,
attende la fine di tutti i processi figli.
5.8 Controllo degli ingressi/uscite
È possibile richiedere alla shell, prima di eseguire un comando, di aprire un canale di I/O su un dato file
(normale o speciale), e di associarlo a un dato file-descriptor (f.d.). Se il f.d. corrisponde già a un canale
aperto, quest’ultimo viene chiuso prima della nuova associazione; in tal caso si parla di ridirezione degli
ingressi/uscite. I caratteri speciali utilizzati possono essere situati ovunque in un comando semplice, prima
o dopo il comando. Sono trattati dalla shell e non sono passati al comando.
n<file
apre il file file in sola lettura, e lo associa al file descriptor n; se n manca, il default è 0,
cioè lo standard input.
Esempio:
$ mail gianni < letter
$
n>file
apre il file file in sola scrittura, e lo associa al file descriptor n; se n manca, il default è
1, cioè lo standard output. Se il file non esiste, la shell lo crea; se esiste, il contenuto
precedente del file è soppresso.
Esempio:
$ date > info
$ cat info
wed jul 3 18:24:08 MET 2000
$
n>>file
identico al caso precedente, ma se il file esiste i dati in uscita sono appesi dopo la fine
del contenuto attuale.
Esempio:
$ who >> info
$ cat info
wed jul 3 18:24:08 MET 2000
root
console
jul
gianni
ttyc6
jul
$
V. Asta - Introduzione a Unix e GNU/Linux
3 18:15
3 18:21
50
n<>file
apre il file file in lettura/scrittura, e lo associa al file descriptor n; se n manca, il default
è 0, cioè lo standard input. Se il file non esiste, la shell lo crea; se esiste, il contenuto
precedente del file è soppresso.
<<word
le righe seguenti sono considerate come l’ingresso standard del comando, fino ad una
riga contenente word, o fino alla fine del file. Se si vuole utilizzare word in queste
righe, bisogna quotarlo. La sequenza di caratteri \<newline> è ignorata (ciò implica
che una riga lunga può essere scritta come due righe separate, terminando la prima con
\). I caratteri speciali $ e ` provocano la sostituzione dei comandi e dei parametri. Per
utilizzare questi caratteri occorre quotarli.
Esempio:
$ cat foo
titi
toto
$ ed foo <<%
> s/to/ti/g
> w
> q
> %
10
10
$ cat foo
titi
titi
$
Nota: a partire da System V, la notazione alternativa <<-word può essere utilizzata.
Essa permette di arrestare le operazioni tutte le volte che si presenta word, ovunque
nella riga. Se questa notazione non è accettata, la stringa d’arresto scelta dovrà, per
essere effettiva, trovarsi all’inizio della riga (a partire da colonna 1).
n<&m
Il file descriptor n diventa un duplicato del f.d. m; se n manca, il default è 0, cioè lo
standard input.
n>&m
Il file descriptor n diventa un duplicato del f.d. m; se n manca, il default è 1, cioè lo
standard output.
n<&-
il f.d. n è chiuso; se n manca, il default è 0.
n>&-
il f.d. n è chiuso; se n manca, il default è 1.
Note:
— Se il comando è lanciato in background, e non è stata precisata alcuna
ridirezione, l’ingresso standard è ridiretto su /dev/null.
— In tutti i casi, la shell chiama il comando dopo queste modifiche, e il comando
non vede mai gli operatori di ridirezione (che sono appunto trattate dalla shell e
fatte sparire dalla riga di comando).
5.9 Costruzione di una tavola di argomenti
Nell’effettuare il parsing di ciascuna riga di comando, la shell divide quest’ultima in parole, secondo i
separatori dati dalla variabile IFS. La prima parola è considerata come il nome di un comando, quelle
seguenti come gli argomenti di questo comando. Gli argomenti costituiti da una stringa nulla sono
conservati, se quotati tra " o ’, altrimenti sono ignorati.
Esempio43:
V. Asta - Introduzione a Unix e GNU/Linux
51
$ cat proc
#! /bin/sh
echo $1 / $#
$ ls -l proc
-rwxr-xr-x
1 gianni
$
$ PAR=
$ proc "$PAR"
/ 1
$ proc $PAR
/ 0
$ proc ’’
/ 1
axis
24 Nov 21 19:06 proc
La shell costruisce una tavola di argomenti, dove il nome del comando occupa lo slot 0, ed i suoi argomenti
gli slot da 1 a n (ove n è il numero d’argomenti passati al comando, ovvero $#). La shell chiama
successivamente il comando e gli fornisce questa tavola ed il numero di slot occupati.
5.10 Esecuzione di un comando
La variabile shell PATH contiene più pathname di directory, separati da :, ed è utilizzata per ricercare il
comando da eseguire. Se il nome del comando da eseguire contiene uno /, PATH non sarà utilizzato.
Altrimenti il file è ricercato in ogni directory specificata. Se è eseguibile, ma non in formato di file binario,
si considera che si tratti di uno shell script. Una sotto-shell sarà lanciata per leggerlo. Se però il file
contiene una prima riga con questo formato:
#!
prog
si considera che si tratti di uno script da passare all’interprete prog, che verrà lanciato per leggerlo ed
eseguirne le istruzioni. prog viene normalmente specificato col suo pathname assoluto, ed è così che si
possono specificare shell script destinati ad un particolare tipo di shell, ad esempio
#!
/bin/sh
#!
/bin/ksh
#!
/bin/csh
Questa convenzione è anche nota come ’sh-bang notation’, ed è utilizzata anche per altri interpreti, come ad
esempio PERL:
#!
/usr/bin/perl
5.11 Chiamata
Se il primo carattere del nome di invocazione del comando ($0) è ‘-’, la shell è una shell di login44; in tal
caso, i comandi posti nei file /etc/profile e $HOME/.profile (se esiste) sono letti ed eseguiti.
I flag seguenti sono riconosciuti alla chiamata della shell:
43.
Per il significato della prima riga della procedura riportata,
#!
/bin/sh
vedi paragrafo 5.10 pag. 52.
44.
La shell si trova in questa condizione quando il programma login(1) effettua una chiamata di sistema execve(2) per eseguire il
programma specificato nell’ultimo campo della riga di utente del file /etc/passwd; login prepende sempre il carattere ‘-’
all’argv[0] dell’array degli argomenti, cioè al nome di invocazione del programma da eseguire.
V. Asta - Introduzione a Unix e GNU/Linux
52
-c string
I comandi si trovano in string.
-s
I comandi sono letti dall’ingresso standard, la shell scrive sul file descriptor 2.
-i
La shell è una shell interattiva. Il segnale SIGTERM è ignorato, così come SIGINT e
SIGQUIT. Stesso comportamento se l’ingresso e l’uscita standard sono assegnati ad un
terminale.
-r
La shell è una shell interattiva ristretta, che impone diverse limitazioni, tra cui: non si può
utilizzare cd nè PATH, non è permessa la ridirezione degli ingressi/uscite, etc.
5.12 Ambiente (environment)
L’ambiente di un qualsiasi processo UNIX è un elenco di stringhe nome=valore, passato ad ogni processo
dal processo padre. Al suo avvio, la shell percorre quest’elenco e crea delle variabili shell (o parametri
d’ambiente) dando loro questi nomi e questi valori. I comandi eseguiti nella shell erediteranno questo
ambiente. Se, nel corso dell’esecuzione di questa shell, l’utente modifica il valore di questi parametri o ne
crea di nuovi, l’ambiente non sarà modificato. Dunque i programmi lanciati non erediteranno i valori
modificati. Per riportare queste modifiche nell’ambiente, si utilizza il comando export.
La chiamata di un comando semplice può essere prefissata tramite l’assegnazione di parametri, che in tal
caso vengono posizionati ed esportati soltanto per il processo in cui si esegue il comando.
Esempio:
$ TERM=vt120 vi file
Chiama l’editor vi per il file file, precisandogli che il terminale utilizzato è un DEC VT-120. Il parametro
TERM ha questo valore solo per il processo che esegue vi.
5.13 Segnali
Se un comando è lanciato in background, i segnali QUIT e INTERRUPT sono ignorati; altrimenti i valori
delle azioni per questi segnali sono ereditati dal processo padre. Un segnale può essere esplicitamente
inviato ad un dato processo, utilizzando il comando kill, che prende come argomento un numero di segnale
(preceduto dal segno ‘-’) e uno o più numeri di processi (PID) a cui inviare il segnale (vedi il comando shell
trap in "Comandi speciali", paragrafo 5.7 pag. 46).
Ecco i principali segnali ed il loro significato:
nome
simbolo
numero
hangup
SIGHUP
1
interrupt
SIGINT
2
quit
SIQUIT
3
kill
term
SIGKILL
SIGTERM
9
15
note
inviato dal kernel alla chiusura di una tty,
a tutti i processi del process-group
inviato da tastiera col carattere intr
(di solito ˆC)
inviato da tastiera col carattere intr
(di solito ˆ\)
non può essere ignorato o soppresso
segnale di terminazione software (default per
kill(1))
Vedere le chiamate di sistema kill(2) e signal(2) per maggiori dettagli.
V. Asta - Introduzione a Unix e GNU/Linux
53
6. Ricapitolativo della shell: comportamento e sintassi
Viene qui dato un riassunto globale delle caratteristiche della shell, sia come interprete di comandi che
come linguaggio di programmazione; nel Tomo 2, dedicato ad esempi, complementi ed esercitazioni sulla
programmazione in shell, vengono poi listate diverse procedure.
•
Doppio aspetto della shell: interprete di linguaggio di comandi + linguaggio di programmazione
•
Sintassi generale per ogni riga letta dalla shell:
comando argomento argomento ...
•
Separatori di base tra token: spazio, <tab>, <newline>
•
Codice di uscita: 0 significa successo, != 0 insuccesso
•
Nozione di stdin, stdout, stderr, corrispondenti ai canali di I/O con file descriptor (fd) rispettivamente
0, 1, 2
•
Operatore ; di esecuzione in serie (sequenziale); operatore & di esecuzione parallela; processi in
background
•
Operatori di sostituzione di filename: *, ?, [abc], [A-Z], [!xyz]
•
Operatori per parametri di ambiente: operatore = di assegnazione; operatore $ di interpolazione
(sostituzione del valore di un parametro).
PAR=stringa, LOGNAME=gianni, HOME=/home/gianni, PS1=’$ ’; $PAR, echo $HOME; parametro
PATH, PATH=$PATH:$HOME/bin
Il comando export consente di esportare un parametro d’ambiente anche agli eventuali sottoprocessi
che saranno generati.
Il comando set permette di visualizzare tuti i parametri d’ambiente e i loro valori.
•
Operatori di ridirezione dei canali di I/O: <, >, >>
In forma generalizzata: n<file, n>file, n>>file, n>&m
"Here scripts": operatore <<string
•
Operatore | di creazione di un pipe; operatore (...) di esecuzione in una sub-shell; operatore {...} di
raggruppamento di comandi
•
Operatori di quoting: \, ’...’, "..." (" interpreta $, ‘ e \; \ quota $, ‘, \ e " )
•
Operatori di sostituzione di comandi: ‘...‘, $(...)
Caso particolare: $(<file) equivale a $(cat file)
•
Parametri d’ambiente posizionati dalla shell: $0, $1, $2, ... $#, $*, $@; $?, $$, $!, $PWD,
$OLDPWD
•
Operatori di AND e OR logico tra comandi: &&, ||
•
Strutture di controllo:
— if cmd-list
then
cmd
cmd
...
[else
cmd
cmd
...]
fi
V. Asta - Introduzione a Unix e GNU/Linux
54
— while cmd-list
do
cmd
cmd
...
done
— until cmd-list
do
cmd
cmd
...
done
— for var in word-list
do
cmd
cmd
...
done
— case param in
pattern1)
cmd
cmd
...
;;
pattern2)
cmd
cmd
...
;;
...
esac
— break [n]
— continue [n]
— exit [code]
•
Comandi e operatori speciali: . : # export wait shift read set trap exec eval umask ulimit let cd
•
Funzioni shell:
func_name()
{
cmd
cmd
...
return
}
V. Asta - Introduzione a Unix e GNU/Linux
55
7. Comandi di uso corrente
I comandi qui succintamente presentati sono utilizzati comunemente sia in modo interattivo, da terminale,
sia nella programmazione in shell.
Il carattere [ precede gli argomenti opzionali.
Si consiglia di consultare le pagine di manuale per approfondire almeno il ruolo e l’uso dei flag segnalati
per ciascun programma.
7.1 Manipolazione di file e directory
•
cd [dir
cambia directory di lavoro in dir; se non c’è argomento, va in $HOME; se dir vale -, va in
$OLDPWD (cioè nella directory precedente, prima dell’ultimo cd).
•
cp file1 file2
cp file1 file2 ... dir
copia file1 in file2, oppure tutti i file specificati, con lo stesso nome, nella directory dir.
Flag importanti: -p -a -R
•
mv file1 file2
mv file1 file2 ... dir
muove (rinomina o sposta) file1 in file2, oppure tutti i file specificati, con lo stesso nome, nella
directory dir.
•
rm file [file ...
rimuove (elimina) i file specificati.
Flag importanti: -r -f -i
•
ln file1 file2
ln file1 file2 ... dir
aggiunge un link (un nuovo nome) da file1 (che di norma deve già esistere) a file2, oppure da tutti i
file specificati, con lo stesso nome, alla directory dir. Un link può essere di tipo hard (hardlink,
default) oppure soft (o symlink, se si usa il flag -s).
Flag importanti: -s -f
•
mkdir dir [dir ...
crea le directory specificate.
Flag importanti: -p
•
rmdir dir [dir ...
rimuove le directory specificate, che devono essere vuote (altrimenti, usare rm -r).
7.2 Informazioni su file e directory
•
pwd
scrive a stdout la directory di lavoro corrente.
•
ls [file_dir file_dir ...
scrive a stdout la lista dei file dati in argomento; se si tratta di una directory, scrive la lista di tutti i file
in essa contenuti; di default, scrive la lista dei file della directory corrente.
Flag importanti: -l -a -A -d -i -s -t -r -1 -x -R
•
file file [file ...
descrive il tipo di ciascuno dei file passati in argomento (la codifica dei tipi di file, detta "magic
number", è in /etc/magic).
7.3 Manipolazione delle informazioni su file e directory
V. Asta - Introduzione a Unix e GNU/Linux
56
•
chmod mode file [file ...
modifica i diritti di accesso ai file (o bit di protezione) secondo il modo mode, che può essere
specificato in ottale oppure in modo simbolico.
•
chown user[:group] file [file ...
cambia il proprietario (ed eventualmente il gruppo di appartenenza) dei file.
•
chgrp group file [file ...
cambia il gruppo a cui appartengono i file.
•
touch file [file ...
cambia la data di ultima modifica (o di ultimo accesso) al file
Flag importanti: -a; -r reffile; -t date
7.4 Visualizzazione del contenuto di file
45.
•
cat [file file ...
− copia i file allo stdout, concatenandoli; se non ci sono argomenti, legge da stdin.
Flag importanti: -v -n
•
pg [file file ...
− visualizza i file a schermo, pagina per pagina. presente solo in UNIX System V. Se non ci sono
argomenti, legge da stdin.
•
more [file file ...
− visualizza i file a schermo, pagina per pagina; come pg(1), ma più potente e versatile. Se non ci
sono argomenti, legge da stdin.
•
less [file file ...
− visualizza i file a schermo, pagina per pagina; come more(1), ma più potente e versatile. Se non ci
sono argomenti, legge da stdin.
•
tail [file
copia a stdout le ultime righe (10 di default) del file; se non ci sono argomenti, legge da stdin.
Flag importanti45: -N -f
•
head [file
copia a stdout le prime righe (10 di default) del file; se non ci sono argomenti, legge da stdin.
Flag importanti: -N
•
od [file
effettua un dump a stdout del contenuto del file; se non ci sono argomenti, legge da stdin; di default, i
dati sono interpretati come parole da 16 bit e visualizzati in ottale, ma è possibile ad esempio
interpretarli anche come singoli byte e/o stamparli in esadecimale o come caratteri ASCII.
Flag importanti: -b -c -d -h
•
tee [file
legge da stdin e scrive i dati letti a stdout e nel file file, se specificato. Utile soprattutto per debugging
di pipe.
•
lpr [file file ...
invia il o i file allo spooler di stampa; se non ci sono argomenti, legge da stdin.
•
lp [file file ...
invia il o i file allo spooler di stampa; se non ci sono argomenti, legge da stdin. Come lpr(1), ma
versione System V; i flag sono completamente diversi.
Nei flag dei programmi introdotti, N indica ovunque un numero.
V. Asta - Introduzione a Unix e GNU/Linux
57
7.5 Informazioni sul contenuto di file
•
wc [file file ...
conta i caratteri, le parole e le righe dei file; se non ci sono argomenti, conta leggendo da stdin.
Flag importanti: -c -w -l
•
cmp file1 file2
confronta i due file, byte a byte.
Flag importanti: -s -l
•
diff file1 file2
confronta i due file di testo, riga a riga.
Flag importanti: -b -c -e -h
7.6 Manipolazione del contenuto di file
•
cut [file file ...
seleziona porzioni di ciascuna riga dei file, e le scrive a stdout; se non ci sono argomenti, legge da
stdin.
Flag importanti: -c list; -f list; -d char
•
grep pattern [file file ...
scrive a stdout le righe dei file che sono selezionate dall’espressione regolare (vedi l’Appendice 4)
specificata in pattern; se non ci sono argomenti, legge da stdin.
Flag importanti: -i -n -l -v
Varianti: fgrep (il pattern è una stringa fissa), egrep (il pattern è un’espressione regolare estesa).
•
sed -e cmd [-e cmd ...] [file]
stream editor; legge il file e applica a ciascuna riga i comandi cmd dati come argomento a ciascuna
opzione -e; i comandi hanno la stessa sintassi dell’editor di riga ed. Le righe così trattate sono scritte
a stdout. Se non ci sono argomenti, legge da stdin.
Flag importanti: -n; -f file
•
awk program [file ...
linguaggio di gestione e trattamento di pattern; è un vero linguaggio autocontenuto, con una sintassi
specifica; il programma può essere specificato nell’argomento program, perchè spesso si tratta di
programmi brevi (una riga o poco più). Applica il programma ai file e stampa il risultato a stdout; se
non ci sono argomenti, legge da stdin.
Flag importanti: -F char; -f program-file
•
sort [file ...
ordina le righe dei file, in ordine alfanumerico o numerico (sono possibili anche altri modi); se non ci
sono argomenti, legge da stdin.
Flag importanti: -f; -n; -o file; -r
•
uniq [file [outfile
copia file a stdout (o scrive in outfile se specificato), escludendo le righe adiacenti identiche; se non ci
sono argomenti, legge da stdin.
Flag importanti: -i; -u; -d; -fN
•
pr [file file ...
formatta file di testo per la stampa; scrive il risultato a stdout, che di solito è inviato in pipe a lpr(1).
Se non ci sono argomenti, legge da stdin.
Flag importanti: -l; -w; -f; -h header
7.7 Modifica del contenuto di file
•
ed file
editor di testo line-oriented.
V. Asta - Introduzione a Unix e GNU/Linux
58
•
vi file [file ...
editor di testo screen-oriented.
7.8 Comandi di utilità per shell script
•
true
non fa nulla, con successo: termina con exit code pari a 0.
•
false
non fa nulla, con insuccesso: termina con exit code diverso da 0.
•
echo [ word word ...
scrive a stdout i suoi argomenti.
Flag importanti: -n-e
•
test expression
valuta l’espressione booleana data in argomento, e termina con exit code pari a 0 se l’espressione è
vera, pari a 1 se è falsa, pari a 2 se è mal formata. L’espressione è composta con operatori unari e
binari, che permettono di effettuare test su numeri, file, stringhe. Vedi l’Appendice 5.
•
expr expression
valuta l’espressione numerica data in argomento, e ne scrive il valore a stdout.
•
bc
calcolatore a precisione infinita; legge da stdin espressioni matematiche, e ne stampa il valore a
stdout. Esce con la parola chiave ‘quit’; permette di gestire fino a 26 variabili (tutte le lettere
minuscole).
•
find path [path ...] expr action
cerca file a partire dalle directory specificate in path; i file sono selezionati mediante l’espressione di
selezione expr; su ciascun file trovato viene applicata un’azione action (l’azione di default è la
scrittura a stdout del nome del file). Vedi l’Appendice 5.
•
line
legge una riga da stdin e la scrive a stdout.
•
printf format [argument ...
scrive a stdout una stringa formattata; lavora esattamente come printf (3).
•
getopt optstring parameters
effettua il parsing delle opzioni di una procedura shell; lavora esattamente come getopt(3).
•
sleep seconds
attende seconds secondi, poi esce.
•
basename pathname [suffix
seleziona e scrive a stdout la sola ultima componente di pathname; se un suffisso suffix è specificato,
anche questo viene tolto.
•
dirname pathname
seleziona e scrive a stdout le componenti di un pathname, salvo l’ultima.
7.9 Comandi generici
•
ps
scrive a stdout lo stato dei processi attivi nel sistema; i processi e il formato di presentazione possono
essere variamente selezionati con i flag del programma.
Flag importanti: -u user; -t tty; -e; -f; -l; -w
N.B. − esistono almeno due stili diversi di sintassi: quello di derivazione BSD, e quello di
derivazione System V. I flag e il loro significato cambiano a seconda dello stile, per cui è opportuno
consultare la pagina di manuale ps(1). Si veda la nota n. 39 pag.33.
V. Asta - Introduzione a Unix e GNU/Linux
59
•
kill [-sig] pid [pid ...
invia il segnale n. sig ai processi specificati tramite i pid; il segnale di default è il n. 15 (SIGTERM).
I segnali possono essere specificati tramite il loro numero o tramite il loro simbolo (senza la stringa
iniziale SIG); ad esempio, i due comandi qui riportati sono equivalenti:
$ kill -1 798
$ kill -HUP 798
$
•
who
scrive a stdout la lista degli utenti attivi nel sistema.
Flag importanti: -u
•
date
scrive a stdout la data e l’ora corrente; può essere anche utilizzato per posizionare la data e l’ora del
sistema ad un nuovo valore.
•
cal [month] [year]
scrive a stdout il calendario del mese o dell’intero anno specificato.
•
tty
scrive a stdout il nome della tty di lavoro.
•
stty permette di consultare o di posizionare i parametri di funzionamento della tty di lavoro.
Flag importanti: -a
•
id
scrive a stdout l’identità di utente e di gruppo della sessione di lavoro.
Flag importanti: -u -g -G -n
•
mail [user [user ...
Mail User Agent di base; permette di inviare posta elettronica agli utenti specificati, leggendo il
messaggio da stdin; senza argomenti, permette di leggere la posta in arrivo e di disporne.
Flag importanti: -s subject
•
write user [tty
permette di scrivere messaggi a un altro utente connesso al sistema.
•
mesg y | n
abilita (y) o disabilita (n) la ricezione di messaggi sul terminale da parte di altri utenti.
V. Asta - Introduzione a Unix e GNU/Linux
60
8. Gli utenti speciali
Il file /etc/passwd contiene un elenco di tutte le persone che hanno un account nel sistema. Viene utilizzato
al momento del login, dal comando login(1), oltre al comando crypt(1) e a tutti i comandi che realizzano il
mapping UID-nome dell’utente, come ad esempio ls(1) con l’opzione -l. Non ci soffermeremo qui sulla
struttura di questo file, ma ci occuperemo di alcuni degli utenti incontrati in /etc/passwd. A titolo di
esempio e prima di passare a considerare questi utenti detti speciali ecco un esempio di file /etc/passwd:
root:YcxCJXNuc.F5g:0:0:root:/root:/bin/bash
bin:ScI25kc9qOiO2:1:1:bin:/bin:
daemon:*:2:2:daemon:/sbin:
adm:*:3:4:adm:/var/adm:
lp:*:4:7:lp:/var/spool/lpd:
sync:*:5:0:sync:/sbin:/bin/sync
shutdown:*:6:0:shutdown:/sbin:/sbin/shutdown
halt:*:7:0:halt:/sbin:/sbin/halt
mail:*:8:12:mail:/var/spool/mail:
news:*:9:13:news:/usr/lib/news:
uucp:*:10:14:uucp:/var/spool/uucppublic:
operator:*:11:0:operator:/root:/bin/bash
games:*:12:100:games:/usr/games:
man:*:13:15:man:/usr/man:
postmaster:*:14:12:postmaster:/var/spool/mail:/bin/bash
nobody:*:65534:100:nobody:/dev/null:
ftp:*:404:1::/home/ftp:/bin/bash
guest:*:405:100:guest:/dev/null:/dev/null
marion:OaGKskj1Q1By2:243:100:Marion Rossi:/home/marion:/bin/ksh
gianni:X0Al4t9f4aWCA:209:101:Gianni Bianchi:/home/gianni:/bin/bash
luca:0Gu/rjtYBjkwk:209:101:Luca Verdi:/home/luca:/bin/bash
8.1 root
Chiamato anche superuser, root è un identificativo di utente utilizzato in genere dall’amministratore del
sistema per svolgere delle mansioni di maintenance. Il suo user-ID (UID) è sempre pari a 0. Infatti la
regola è la seguente:
Nessuno dei meccanismi di protezione attivati dal kernel, viene applicato se lo user-ID effettivo del
processo attivo è uguale a zero.
Questi meccanismi riguardano la protezione dei file, la trasmissione dei segnali, delle restrizioni su alcune
chiamate di sistema (mknod(2), chown(2) etc.) e, con System V, le protezioni per l’accesso e la
manipolazione dei meccanismi d’IPC46 (UNIX è probabilmente uno dei pochi sistemi in cui è possibile
distruggere tutto il sistema di file, ovviamente senza ricorrere alla formattazione del disco, con un solo
comando e senza nemmeno un warning). Questo approccio ha il merito di essere particolarmente semplice
e coerente, tuttavia conviene usare la massima prudenza, quando si deve lavorare come superuser. In pratica
questo stato deve essere utilizzato il meno possibile, e solo per motivi precisi. In genere, ogni riga di
/etc/passwd definisce un utente e l’UID di ogni utente è unico; tuttavia, in alcuni casi, è possibile creare più
utenti aventi lo stesso UID, ad esempio se l’ultimo campo è diverso per questi utenti. La home directory di
root è normalmente / o /root.
8.2 bin
L’utente bin è un altro identificativo usato spesso dall’amministratore del sistema; dal punto di vista del
kernel, si tratta di un utente qualunque, ma bin è il proprietario di un gran numero di files dell’arborescenza
di base. È così spesso possibile, oltre che consigliabile, effettuare delle manipolazioni su alcuni file di
46.
Inter Process Communication: code di messaggi, semafori, memoria condivisa.
V. Asta - Introduzione a Unix e GNU/Linux
61
sistema senza essere root, diventando bin (grazie al comando su(1)).
8.3 daemon
Lo pseudo utente daemon è di norma il possessore delle directory di spool e dei file che gli sono associati,
anche se ciò varia a seconda dei sistemi. In generale uno pseudo utente come daemon è utile ogni volta che
deve essere garantito l’accesso indiretto a dei file. È sufficiente quindi dare questi file al daemon, di
garantirgli l’accesso esclusivo, ed in fine posizionare il bit "set effective user-ID", per gli eseguibili che
manipolano i file. Ma non bisogna dimenticare in questo caso che nessuno deve potersi loggare come il
"daemon" in questione. Esistono vari metodi per garantire che un ingresso di /etc/passwd non sarà utilizzato
da login(1), come ad esempio utilizzare il programma /bin/false come ultimo campo della riga in questione.
8.4 Gli altri utenti speciali
Esistono numerosi altri utenti speciali, quali adm, sys, lp, uucp etc.; in genere questi utenti esistono per dare
la proprietà di alcuni file a specifici applicativi. Ad esempio, lo special file /dev/lp è di proprietà dello
pseudo-user lp, ed ha bit di protezione pari a 0600, cioè sono il proprietario può leggervi e scrivervi; lo
spooler di stampante è un programma che gira con i diritti dell’utente lp. Ciò fa sì che nessun utente
normale possa scrivere direttamente verso la periferica /dev/lp, cortocircuitando lo spooler, ma debba
invece passare per i programmi preposti.
Su più sistemi è poi possibile incontrare degli pseudo-utenti associati ad un programma di login specifico e
non necessariamente interattivo, ciò che permette di lanciare dei comandi come sync(1), who(1),
shutdown(8), halt(8) senza essere loggati.
V. Asta - Introduzione a Unix e GNU/Linux
62
9. I file speciali
9.1 Cosa è un file speciale
I file UNIX sono essenzialmente di tre tipi:
— i file normali
— le directory
— i file speciali (special files)
Così come i file normali associano un inode ed un nome ad una serie di byte in memoria secondaria (vale a
dire su disco), i file speciali associano un inode ed un nome ad una periferica47. I file speciali sono gestiti
dalle stesse primitive dei files normali (open(2), read(2), write(2), close(2)...). Viene utilizzato lo stesso
meccanismo di protezione. Infatti, sono presenti tutte le caratteristiche di un file associate ad un inode ad
eccezione degli indirizzi dei blocchi di dati contenuti nell’inode di un file normale. Al posto degli indirizzi
dei blocchi di dati si trovano due numeri che individuano il device associato ad un file, cioè al suo
contenuto virtuale. Questi due numeri sono chiamati rispettivamente major device number e minor device
number48, ed occupano l’inizio dell’area destinata agli indirizzi dei blocchi di dati. Così come il nome di
un file normale non fornisce delle specifiche sul suo contenuto, il nome di un file speciale non garantisce
nulla sulla specifica periferica fisica a cui è associato. Solo l’esame del MDN e del mdn permette di
assicurarsene.
Ogni periferica può essere associata ad uno o più file speciali; ciò sia per il meccanismo dei link, sia perchè
più file speciali con nomi diversi possono possedere degli MDN e mdn identici. Se il MDN di più file è
indentico, ma il mdn è diverso, si tratta, come si vedrà, di più unità di uno stesso device, o di diversi modi
di utilizzare uno stesso device.
Il MDN determina il device driver che sarà utilizzato per accedere al device. Il mdn è un argomento
passato tale e quale al driver selezionato dal MDN, e dunque il suo significato sarà totalmente determinato
da questo. Normalmente, il mdn permette di selezionare una delle unità gestite da uno stesso controllore. Se
necessario, il mdn sarà diviso in campi49 che permettono di codificare altre suddivisioni o degli attributi
propri di un device particolare. Tuttavia dato che il senso del mdn e del MDN dipendono interamente da
ciascun sistema UNIX generato, è possibile trovare dei sistemi che presentano casi particolari. (Ad esempio,
nulla impedisce allo stesso MDN di riferire due tipi di periferiche fondamentalmente diverse, essendo
queste distinte solo dal loro mdn).
I file speciali sono raggruppati nella directory /dev ed i loro nomi sono in genere abbastanza stabili da un
sistema ad un altro. Questa localizzazione dei file speciali non è obbligatoria, si tratta di una convenzione
che permette una gestione coerente ed efficace dei device. Ci sono egualmente delle convenzioni che
riguardano l’organizzazione di /dev, e la scelta dei nomi da associare ai diversi tipi di device.
I file speciali si ividono in due classi distinte:
— i file speciali in modo carattere50
— i file speciali in modo blocco51
Dunque si tratta essenzialmente:
47.
I termini "device" e "periferica" saranno utilizzati indifferentemente, per evitare se necessario, l’impiego di locuzioni come:
"handler di periferiche", peraltro insolite in un contesto UNIX.
48.
Numero di periferica maggiore e minore. Si indicheranno con MDN e mdn.
49.
Nel senso di campi di bit
50.
Le altre denominazioni possibili comprendono: raw, non-strutturata.
51.
O ancora, strutturati.
V. Asta - Introduzione a Unix e GNU/Linux
63
— per i file speciali in modo carattere, di una interfaccia non strutturata (ciò che purtroppo non è
indicato dal loro nome), vale a dire che i dati passano direttamente dalla periferica al processo
utente52, o viceversa, senza transitare attraverso la memoria di cache del kernel.
— Per i file speciali in modo blocco, invece, di una interfaccia strutturata, vale a dire che la richiesta
dell’utente è filtrata dal kernel, che assicura un servizio di cache per tutti i dati scambiati con i device.
La classe di appartenenza di uno special file è specificata nell’inode del file53.
Sarebbe così più giusto dire che i file UNIX sono di quattro tipi base:
— i file normali
— le directories
— i file speciali in modo carattere
— i file speciali in modo blocco
I file speciali sono creati dal comando mknod(1)54 che prende in argomento il nome del file, la sua classe
(blocco o carattere), il suo mdn ed il suo MDN.
Il comando ls permette di conoscere il tipo di un file, e per i file speciali i loro mdn e MDN. Il tipo di un file
è indicato dal primo carattere del campo mode dell’output del comando ls -l. I MDN e mdn di un file
speciale sostituiscono il campo size.
$ cd
$ cd tmp
$ ls -l
total 4
-rw-r----- 1 marion axis
ˆ file normale
-rw-r----- 1 marion axis
drwxr-x--- 2 marion axis
ˆ directory
144 Jul 23
6456 Jul 23
32 Jul 23
14:01 bar
14:01 foo
14:01 the_dir
52.
Alla zona di memoria dello spazio dati di un programma in modo utente puntato dal secondo argomento di un read(2) o di un
write(2)
53.
Vedi il paragrafo paragrafo 3.6.2 pag. 33 sull’organizzazione del filesystem
54.
Il comando mknod è la versione "shell" della chiamata di sistema mknod(2)
V. Asta - Introduzione a Unix e GNU/Linux
64
$ ls -lsi
total 16
4001 1 -rw-r--- 1
ˆ il campo
4064 14 -rw-r-- 1
4065 1 drwxr-x- 2
marion axis
144
mode inizia qui
marion axis
6456
marion axis
32
Jul 23 14:01 bar
Jul 23 14:01 foo
Jul 23 14:01 the_dir
$ cd /dev
$ ls -l root
brw------- 2 deamon
sys
ˆ file speciale in modo blocco
0, 0
Jul
23
09:32 root
$ ls -l tty
crw-rw-rw-
1 deamon
sys
2,
MDNˆ
0 Jul 23
ˆmdn
14:10 tty
$ ls -lsi *rmt0
203
0 crw-rw---- 2 deamon axis
5, 4 Aug 14 2000 nrmt0
ˆfile speciale in modo carattere
202
0 crw-rw---- 2 deamon axis
5, 0 Jul 22 14:20 rmt0
ˆsize in blocchi, zero per un file speciale
ˆ i-number
E per la creazione:
# cd /dev
# mknod mem c 3 0
ˆ la chiamata di sistema mknod(2) è riservata al
superuser,
ed
il
comando
/etc/mknod
non è
set-user-id root!
Ciò in realtà non è totalmente esatto; qualunque processo infatti può invocare mknod(2), per creare un
named pipe (ma non per creare uno special file).
# mknod mt0 b 1 0
ˆil nome del file
# mknod nmt0 b 1 4
ˆil modo (blocco o carattere), qui blocco
# mknod nrmt0 c 5 4
ˆ ˆ MDN e mdn espressi in decimale
# ls -l [nm]*
crw-r----- 1
brw-r----- 1
brw-r----- 1
crw-r----- 1
root
root
root
root
sys
sys
sys
sys
V. Asta - Introduzione a Unix e GNU/Linux
3,
1,
1,
5,
ˆ
0
0
4
4
ˆ
Jul 23 14:47
mem
Jul 23 14:48
mt0
Jul 23 14:48
nmt0
Jul 23 14:48
nrmt0
anche ls dà il MDN
ed il mdn in decimale.
65
9.2 Device e pseudo-device
Uno special file può anche riferirsi ad una periferica fittizia, alla quale non corrisponde un’entità fisica; in
tal caso lo special file viene comunemente detto uno pseudo-device. Un esempio evidente è /dev/null, che
rappresenta una periferica con le seguenti proprietà:
— ogni scrittura verso /dev/null provoca l’eliminazione dei dati
— ogni lettura da /dev/null ritorna con 0 byte letti (condizione di end-of-file).
La distinzione fatta tra device e pseudo-device non è netta come quella definita tra device in modo carattere
ed in modo blocco. Non si tratta di una differenza strutturale chiaramente identificabile (un campo di bit in
un campo mode di inode), ma di una differenza concettuale, tra device associati a una unità fisica reale e
devices associate ad una periferica virtuale. Ad esempio, a condizione di non considerare la memoria come
una periferica reale, un driver che implementa un disco virtuale, è uno pseudo-device. La nozione di
periferica virtuale non è sempre chiara; se la memoria può essere considerata come una periferica (si tratta
comunque di un dispositivo materiale), un device che implementa un meccanismo di semafori non può
essere visto come una periferica. È possibile anche considerare uno pseudo-device semplicemente come un
servizio di kernel, a cui si accede da un file piuttosto che da una chiamata di sistema.
Esiste un certo numero di pseudo-device standard, presenti in tutte le versioni di UNIX e sempre con lo
stesso nome; tra di essi ricordiamo:
— /dev/null
— /dev/full (ogni scrittura fallisce; ogni lettura ritorna byte nulli)
— /dev/zero (ogni scrittura elimina i dati; ogni lettura ritorna byte nulli)
— /dev/mem, /dev/kmem (accesso alla memoria fisica e alla memoria vista nello spazio di
indirizzamento virtuale del kernel)
— /dev/tty (si riferisce al terminale di controllo del processo attivo)
V. Asta - Introduzione a Unix e GNU/Linux
66
10. Organizzazione dei filesystems di UNIX
10.1 Il sistema di file
Questo paragrafo illustra l’implementazione "standard" di un filesystem UNIX di tipo AT&T (Version 7,
System V; si veda il classico articolo di Ken Thompson [1978]).
Le versioni odierne di UNIX, incluso LINUX ovviamente, generalmente utilizzano implementazioni che
sono tutte derivate da questa, con l’introduzione di varie migliorìe.
Peraltro, gli esempi di codice qui presentati sono tutti presi da un sistema LINUX.
Nel sistema UNIX un file è un array (unidimensionale) di bytes. Nessun’altra organizzazione, o tipo, di file
è implicata dal Sistema Operativo. Ma questo semplice modello permette l’aggiunta di una qualunque
struttura di dati a livello utente. Vedere, per esempio, /usr/include/ar.h, che descrive l’organizzazione di
un file di libreria (archivio) di UNIX,
$ cat /usr/include/ar.h
...
/* Archive files start with the ARMAG identifying string. Then follows a
‘struct ar_hdr’, and as many bytes of member file data as its ‘ar_size’
member indicates, for each member file. */
#define ARMAG
"!<arch>\n"
#define SARMAG 8
#define ARFMAG
"‘\n"
/* String that begins an archive file.
/* Size of that string. */
*/
/* String in ar_fmag at end of each header.
*/
__BEGIN_DECLS
struct ar_hdr
{
char ar_name[16];
/* Member file name, sometimes / terminated. */
char ar_date[12];
/* File date, decimal seconds since Epoch. */
char ar_uid[6], ar_gid[6]; /* User and group IDs, in ASCII decimal. */
char ar_mode[8];
/* File mode, in ASCII octal. */
char ar_size[10];
/* File size, in ASCII decimal. */
char ar_fmag[2];
/* Always contains ARFMAG. */
};
...
o ancora /usr/include/elf.h, per una struttura manipolata anche dal kernel stesso (si tratta
dell’organizzazione dei dati in un file binario eseguibile).
I files sono connessi in un qualunque punto (ed eventualmente più volte) su una gerarchia di directories. Le
directories, dal punto di vista del filesystem e del sistema, sono semplicemente dei files che gli utenti non
possono scrivere.
Nessun utente (nemmeno root) può scrivere direttamente in una directory; peraltro i meccanismi di
protezione sono trattati in modo normale quando una scrittura è fatta tramite chiamate sistema.
Il file sistem UNIX è costituito da una struttura di dati su disco55 a cui si accede esclusivamente attraverso il
sistema d’I/O in modo blocco, cioè attraverso il passaggio sistematico per la cache di sistema.
Un volume è quindi sempre montato utilizzando l’interfaccia strutturata (cioè appunto quella in modo
blocco). Il modo canonico di vedere un disco è come un array di blocchi da N bytes indirizzabili
aleatoriamente, ove N vale di solito 512 o 102456.
55.
Ovunque nel testo, con il termine "disco" si intende un’unità logica (disco logico), così come è vista dal Sistema Operativo;
questa di solito non coincide con l’intero disco fisico, che è di norma diviso in più partizioni, ciascuna delle quali costituisce un
disco logico.
56.
LINUX, come altre versioni recenti di UNIX, utilizza anche i valori 2048 e 4096.
V. Asta - Introduzione a Unix e GNU/Linux
67
Un file system viene creato tramite il comando mkfs(8); questa operazione organizza il disco in 4 regioni
autoidentificate. La prima regione (blocco numero 0) non è utilizzata dal file system. Questo blocco è
messo da parte per le procedure di bootstrap. La seconda regione (blocco numero 1) contiene il
"superblock". Questo blocco contiene una struttura di dati con tutto ciò che serve per gestire un filesystem;
tra le altre cose, contiene la lunghezza del filesystem stesso e le frontiere delle altre regioni57.
La struttura del superblock è descritta nel file /usr/include/sys/filsys.h (in LINUX, per un filesystem di tipo
System V: /usr/include/linux/sysv_fs.h).
$ cat /usr/include/linux/sysv_fs.h
...
#define SYSV_NICINOD
#define SYSV_NICFREE
100
50
/* number of inode cache entries */
/* number of free block list chunk entries */
/* SystemV4 super-block data on disk */
struct sysv4_super_block
{
u16
s_isize;
/* index of first data zone */
u16
s_pad0;
u32
s_fsize;
/* total number of zones of this fs */
/* the start of the free block list: */
u16
s_nfree;
/* number of free blocks in s_free,
<= SYSV_NICFREE */
u16
s_pad1;
u32
s_free[SYSV_NICFREE]; /* first free block list chunk */
/* the cache of free inodes: */
u16
s_ninode;
/* number of free inodes in s_inode,
<= SYSV_NICINOD */
u16
s_pad2;
sysv_ino_t
s_inode[SYSV_NICINOD]; /* some free inodes */
/* locks: */
char
s_flock;
/* lock during free block list manipulation */
char
s_ilock;
/* lock during inode cache manipulation */
char
s_fmod;
/* super-block modified flag */
char
s_ronly;
/* flag whether fs is mounted read-only */
u32
s_time;
/* time of last super block update */
s16
s_dinfo[4];
/* device information ?? */
u32
s_tfree;
/* total number of free zones */
u16
s_tinode;
/* total number of free inodes */
u16
s_pad3;
char
s_fname[6];
/* file system volume name */
char
s_fpack[6];
/* file system pack name */
s32
s_fill[12];
s32
s_state;
/* file system state: 0x7c269d38-s_time
means clean */
s32
s_magic;
/* version of file system */
s32
s_type;
/* type of file system:
1 for 512 byte blocks
2 for 1024 byte blocks */
};
...
#define FSTYPE_XENIX
1
#define FSTYPE_SYSV4
2
#define FSTYPE_SYSV2
3
#define FSTYPE_COH
4
#define SYSV_MAGIC_BASE
0x012FF7B3
#define SYSV4_SUPER_MAGIC
(SYSV_MAGIC_BASE+FSTYPE_SYSV4)
...
57.
Poichè l’integrità del superblock è critica per l’intero filesystem (nel senso che se viene corrotto il superblock, c’è rischio di
perdere il contenuto di tutti i files), molte implementazioni più recenti, incluso il classico filesystem ext2 di LINUX, mantengono
copie del superblock in vari altri blocchi sparsi nel disco.
V. Asta - Introduzione a Unix e GNU/Linux
68
I vari pseudo-tipi utilizzati in questa struttura, così come in altre strutture che avremo occasione di
esaminare più avanti, sono definiti nel file /usr/include/sys/types.h (e in altri files da questo inclusi).
$ cat /usr/include/sys/types.h
...
/*
* These aren’t exported outside the kernel to avoid name space clashes
*/
#ifdef __KERNEL__
typedef signed char s8;
typedef unsigned char u8;
typedef signed short s16;
typedef unsigned short u16;
typedef signed int s32;
typedef unsigned int u32;
typedef signed long long s64;
typedef unsigned long long u64;
#define BITS_PER_LONG 32
#endif /* __KERNEL__ */
...
/* inode numbers are 16 bit */
typedef u16 sysv_ino_t;
...
La terza regione è denominata i-list, e contiene una lista di strutture di controllo di files. Ognuna di queste è
una struttura di 64 bytes, chiamata i-node.
$ cat /usr/include/linux/sysv_fs.h
...
/* System V inode data on disk */
struct sysv_inode
{
u16 i_mode;
/* file type, set-UID etc., and protection bits */
u16 i_nlink;
/* link count */
u16 i_uid;
/* numeric UID */
u16 i_gid;
/* numeric GID */
u32 i_size;
/* file size, in bytes */
union
{
/* directories, regular files, ... */
unsigned char i_addb[3*(10+1+1+1)+1];
/* zone numbers: max. 10 data blocks,
* then 1 indirection block,
* then 1 double indirection block,
* then 1 triple indirection block.
* Then maybe a "file generation number" ??
*/
/* devices: major + minor device number */
dev_t i_rdev;
} i_a;
u32 i_atime;
/* time of last access */
u32 i_mtime;
/* time of last modification */
u32 i_ctime;
/* time of creation */
};
...
L’offset di un i-node particolare all’interno della i-list è chiamato il suo i-number. La combinazione del
V. Asta - Introduzione a Unix e GNU/Linux
69
nome del device (numero maggiore e numero minore) e dello i-number serve a identificare univocamente
un file.
Dopo la i-list e fino alla fine del disco, viene la quarta regione, che comprende i blocchi di allocazione
libera che sono disponibili per il contenuto dei files.
Qualora la dimensione totale del filesystem (specificata in argomento a mkfs(8)) sia inferiore alla
dimensione totale del disco, può infine esistere una quinta regione, che si estende dalla fine del filesystem
alla fine del disco; tale regione può essere utilizzata come spazio di swap del sistema58.
In altre parole, un primo sguardo su un filesystem mostra una struttura molto semplice e piatta: una sola
grande directory di lunghezza fissa contenente descrittori di files. Per chiamare un file in questo contesto si
potrebbe dire: disco (modo blocco) IDE, unità 1, volume 2, file 354... Lo spazio libero su disco è
mantenuto con una lista collegata dei blocchi disco disponibili. Ogni blocco di questa catena contiene
l’indirizzo disco del blocco seguente nella catena. Il rimanente spazio contiene l’indirizzo di un massimo di
50 (parametro SYSV_NICFREE) blocchi disco che sono anch’essi liberi. La testa di questa lista si trova nel
superblock, come pure un contatore che indica il numero di blocchi liberi restanti, tra i SYSV_NICFREE
possibili. Vedere la struct sysv4_super_block. La tabella s_free contiene fino a 49 numeri di blocchi liberi,
da s_free[1] a s_free[s_nfree-1]. s_free[0] è il numero del blocco che è in testa alla catena dei blocchi
costituenti la free list. Così con una operazione di I/O, il sistema ottiene 50 blocchi liberi ed un puntatore
per trovarne ancora.
L’algoritmo di allocazione del disco è molto semplice.
Per allocare un blocco:
Decrementare s_nfree, ed il nuovo blocco è s_free[s_nfree]. Se il numero del nuovo blocco è
0 non vi sono più blocchi disponibili. Se s_nfree diventa uguale a 0, leggere il blocco
designato col numero del nuovo blocco, rimpiazzare s_nfree con la prima parola di questo
blocco e copiare i numeri di blocco nei 50 elementi della tabella s_free.
Per liberare un blocco:
Se s_nfree è uguale a 50 (SYSV_NICFREE), copiare s_nfree e la tabella s_free in questo
blocco, scriverla, e mettere s_nfree a 0. In tutti i casi mettere in s_free[s_nfree] il numero del
blocco liberato ed incrementare s_nfree.
Dato che tutte le allocazioni sono in blocchi di lunghezza fissa e che viene effettuato un calcolo rigoroso
dello spazio, non è necessario compattare o fare garbage-collecting. Tuttavia mano mano che lo spazio su
disco si disperde (creando, modificando e rimuovendo files), i tempi di accesso aumentano gradualmente, e
si assiste ad un fenomeno di degradazione a lungo termine delle prestazioni del filesystem. Per ovviare a
questo problema, può essere opportuno ricompattare di tanto in tanto lo spazio su disco, per ridurre i tempi
di risposta.
Su System V esiste un comando che permette di ricopiare un filesystem riorganizzandolo. In questo caso i
blocchi di dati dei files non sono semplicemente allocati consecutivamente, ma distribuiti in modo ottimale
sul disco, e sono inoltre possibili varie altre ottimizzazioni. Si tratta del comando dcopy(8). Se questo
comando non esiste, un backup del filesystem per mezzo di tar(1) (seguito da un restore su di un filesystem
riinizializzato) rigenera i files con blocchi allocati consecutivamente, e ciò avrà lo stesso effetto di dcopy(8)
se il filesystem è stato rigenerato precisando la dimensione del gap di rotazione, dato che la free list è creata
tenendo conto di questo gap.
Un i-node contiene 13 indirizzi di blocchi disco. La dichiarazione di i_addb come un array di 40 caratteri,
piuttosto che di 13 daddr_t (equivalenti ad unsigned long) è necessaria per ottenere una lunghezza pari a
64 (8 o 16 i-nodes per ogni blocco) per la struttura sysv_inode. Infatti gli indirizzi disco sono limitati ad
una lunghezza reale di 24 bits e i_addb contiene 13*3 bytes, che saranno convertiti in interi a 32 bit prima
di usarli. Esistono funzioni di libreria per realizzare questa conversione (l3tol, ltol3, vedi l3tol(3C)).
I 10 primi indirizzi puntano direttamente verso i primi 10 blocchi di un file. Se un file è più grande di 10
58.
Più comunemente, alla zona di swap si dedica un’intera partizione del disco.
V. Asta - Introduzione a Unix e GNU/Linux
70
blocchi (5.120 bytes, con blocchi da 512 byte), l’undicesimo indirizzo punta su un blocco che contiene gli
indirizzi dei 128 blocchi successivi del file. Se il file è ancora più grande di (10+128)*512 = 70.656 bytes,
il dodicesimo indirizzo punta ancora su 128 blocchi, ognuno dei quali punta su 128 blocchi di questo file.
Per files ancora più grandi, oltre (10+128+1282)*512 = 16522*512 = 8.459.264 bytes, il tredicesimo
indirizzo è utilizzato per realizzare analogamente una tripla indirezione. L’algoritmo si ferma qui, con una
lunghezza massima di file pari a (10+128+1282+1283)*512 = 2.113.674*512 = 1.082.201.088 bytes (il
doppio, cioè circa 2 Gbytes, con blocchi da 1024 byte; circa 8 Gbytes per file con blocchi da 4 kbytes).
Una gerarchia logica ad albero è aggiunta a questa struttura fisica piatta, aggiungendo semplicemente un
nuovo tipo di file: la directory. L’accesso ad una directory è esattamente come quello di un file ordinario.
Essa contiene degli slots di 16 bytes, costituiti da un nome di 14 caratteri qualsiasi59 e da un i-number. Si
rammenta ancora una volta (vedi anche nota 33 nel paragrafo 3.2 pag. 28) che dal punto di vista del kernel
non vi è distinzione alcuna tra caratteri per il nome di un file, che possono essere di qualunque tipo,
compresi caratteri di controllo e/o non stampabili, salvo il carattere `/’ (che indica il passaggio ad una
componente successiva in un pathname) e ’\0’ (che termina le stringhe di caratteri). Il carattere `.’ non ha
nessun significato particolare, non esistendo nel kernel il concetto di "estensione di un nome di file", salvo a
livello applicativo.
$ cat /usr/include/linux/sysv_fs.h
...
/* Among the inodes ... */
/* 0 is non-existent */
#define SYSV_ROOT_INO
2
/* inode of root directory */
/* SystemV directory entry on disk */
#define SYSV_NAMELEN
14
/* max size of name in struct sysv_dir_entry */
struct sysv_dir_entry
{
sysv_ino_t inode;
char name[SYSV_NAMELEN]; /* up to 14 characters, the rest are zeroes */
};
...
La radice di una gerarchia si trova in un i-node noto (lo i-node numero 2).
Com’è facile capire, l’i-number identifica univocamente un i-node (almeno all’interno di un dato
filesystem), e quindi un file. È perfettamente legale avere più slots di una directory, ovvero slots di diverse
directories, che contengono lo stesso i-number, e che rappresentano quindi più punti di accesso (detti link)
a uno stesso file; ciascun file può pertanto presentarsi con diversi nomi, e/o sotto diverse directories. Il
numero di link di un file (link count) è memorizzato nell’i-node (campo i_nlink); l’aggiunta di un nuovo
link viene effettuata mediante la chiamata sistema link(2), ovvero con il comando ln(1); la rimozione,
mediante la chiamata unlink(2) o con il comando rm(1). La chiamata unlink(2), nel caso generale, non fa
che decrementare il link count e rimuovere lo slot della directory; solo nel caso particolare in cui il link
count, decrementato, scenda a 0 (ultimo link per quel file), il sistema provvede anche a rimuovere
effettivamente il file, deallocando l’i-node e i blocchi di dati.
Si accenna, infine, che il programma ls(1) permette di visionare il valore del link count, con l’opzione -l (è
il secondo campo visualizzato, dopi i bit di protezione), e l’i-number, con l’opzione -i.
59.
Il limite di 14 caratteri è stato tipicamente portato a 256 nelle versioni attuali di UNIX, incluso LINUX.
V. Asta - Introduzione a Unix e GNU/Linux
71
$ ls -l *.ps
1 gianni
-rw-r--r--
axis
51718 Nov
7 19:21 FileSystem.ps
$ ls -i *.ps
75763 FileSystem.ps
$ ls -li *.ps
75763 -rw-r--r-1 gianni
axis
51718 Nov
7 19:21 FileSystem.ps
La struttura del filesystem permette, in linea di massima, la formazione di un grafo arbitrario di directories
con i files regolari collegati a punti qualsiasi di questo grafo. In effetti i primi sistemi UNIX utilizzavano
una struttura di questo tipo, ma l’amministrarla divenne così caotico che i sistemi seguenti furono limitati
ad una arborescenza di directories.
È sempre possibile per root, tramite le chiamate sistema link(2) e unlink(2), manipolare un filesystem come
un grafo qualsiasi, creando link anche per files di tipo directory (questa è appunto un’operazione consentita
solo al superuser). System V possiede persino i comandi link(8) e unlink(8), riservati al superuser, che
offrono una interfaccia diretta con le chiamate sistema direttamente dalla shell. Tuttavia si tratta di
manipolazioni molto pericolose le cui implicazioni non sono spesso ovvie, dato che i comandi di
amministrazione del filesystem manipolano un albero piuttosto che un grafo.
Il filesystem consente una creazione facile, una soppressione facile, un accesso aleatorio facilitato ed una
allocazione dello spazio molto facile. Con la maggior parte degli indirizzi fisici confinati in una piccola
parte contigua del disco, è altrettanto facile fare il dump, il restore, e verificare la coerenza del filesystem. I
grossi files sono penalizzati dall’indirizzamento indiretto, ma la memoria di cache evita la maggior parte
degli I/O fisici che ne derivano senza aggiungere troppa esecuzione di codice. Le caratteristiche di questo
modello, in termini di proporzione di occupazione dello spazio, sono piuttosto buone. Ken Thompson,
nell’articolo citato in apertura, fa questo esempio:
"In un dato filesystem, ci sono 25000 files che contengono 130M bytes di dati. Lo spazio
extra occupato (i-node, blocchi di indirezione, e complemento sull’ultimo blocco) è circa
11.5M bytes. La struttura di directories che supportano questi files comprende circa 1500
directories contenenti 0.6M bytes di dati e 0.5M bytes per l’accesso alle directories. In totale
si arriva a meno del 10% di rapporto con i dati realmente memorizzati. Molti sistemi
tradizionali hanno tutto questo overhead semplicemente per gli spazi di padding delle righe."
10.2 Implementazione del filesystem
Dato che l’i-node definisce un file, l’implementazione del filesystem è centrato intorno all’accesso all’inode. Il sistema gestisce una tavola di tutti gli i-nodes attivi.
Gli i-nodes contenuti in questa tavola (quindi in memoria) hanno una struttura diversa da quella degli inodes descritti fino ad ora, che erano quelli che si possono trovare su un filesystem, considerato da un punto
di vista statico. La dichiarazione di un i-node in memoria si trova nel file /usr/include/sys/inode.h (in
LINUX, in /usr/include/linux/fs.h):
$ cat /usr/include/linux/fs.h
...
/*
* This
*/
#define
#define
#define
#define
#define
is the inode attributes flag definitions
ATTR_FLAG_SYNCRONOUS
ATTR_FLAG_NOATIME
ATTR_FLAG_APPEND
ATTR_FLAG_IMMUTABLE
ATTR_FLAG_NODIRATIME
1
2
4
8
16
/* Syncronous write */
/* Don’t update atime */
/* Append-only file */
/* Immutable file */
/* Don’t update atime for directory */
struct inode
{
V. Asta - Introduzione a Unix e GNU/Linux
72
struct list_head
struct list_head
struct list_head
unsigned long
unsigned int
kdev_t
umode_t
i_hash;
i_list;
i_dentry;
i_ino;
i_count;
i_dev;
i_mode;
/* linked lists */
/* i-number */
/* reference count */
/* device where inode lives */
/* file type + setUID etc.
+ protection bits */
/* nr. of hard links */
/* numeric UID */
/* numeric GID */
/* device, if special file */
/* file size */
/* time stamps */
nlink_t
i_nlink;
uid_t
i_uid;
gid_t
i_gid;
kdev_t
i_rdev;
off_t
i_size;
time_t
i_atime;
time_t
i_mtime;
time_t
i_ctime;
unsigned long
i_blksize; /* block size for file system I/O */
unsigned long
i_blocks; /* number of blocks allocated */
unsigned long
i_version; /* Dcache version management */
unsigned long
i_nrpages;
struct semaphore
i_sem;
/* access control */
struct semaphore
i_atomic_write;
struct inode_operations *i_op;
/* pointers to functions */
struct super_block
*i_sb;
struct wait_queue
*i_wait;
/* wait queue */
struct file_lock
*i_flock;
struct vm_area_struct
*i_mmap; /* memory areas */
struct page
*i_pages;
struct dquot
*i_dquot[MAXQUOTAS];
unsigned
unsigned
unsigned
unsigned
long
int
char
char
int
unsigned int
__u32
union {
struct
struct
struct
struct
struct
struct
struct
struct
struct
struct
struct
struct
struct
struct
struct
struct
struct
struct
struct
struct
void
} u;
i_state;
i_flags;
i_pipe;
i_sock;
/* state - see below */
i_writecount;
/* number authorized to write */
i_attr_flags;
/* attr. flags - see before */
i_generation;
/* file-system specific information */
pipe_inode_info
pipe_i;
minix_inode_info
minix_i;
ext2_inode_info
ext2_i;
hpfs_inode_info
hpfs_i;
ntfs_inode_info
ntfs_i;
msdos_inode_info
msdos_i;
umsdos_inode_info
umsdos_i;
iso_inode_info
isofs_i;
nfs_inode_info
nfs_i;
sysv_inode_info
sysv_i;
affs_inode_info
affs_i;
ufs_inode_info
ufs_i;
efs_inode_info
efs_i;
romfs_inode_info
romfs_i;
coda_inode_info
coda_i;
smb_inode_info
smbfs_i;
hfs_inode_info
hfs_i;
adfs_inode_info
adfs_i;
qnx4_inode_info
qnx4_i;
socket
socket_i;
*generic_ip;
};
/* Inode state bits.. */
V. Asta - Introduzione a Unix e GNU/Linux
73
#define I_DIRTY
#define I_LOCK
#define I_FREEING
...
1
2
4
$ cat /usr/include/linux/stat.h
...
/* Inode mode bits... */
#define S_IFMT 00170000
#define S_IFSOCK 0140000
#define S_IFLNK 0120000
#define S_IFREG 0100000
#define S_IFBLK 0060000
#define S_IFDIR 0040000
#define S_IFCHR 0020000
#define S_IFIFO 0010000
#define S_ISUID 0004000
#define S_ISGID 0002000
#define S_ISVTX 0001000
/* type of file */
/* socket */
/* symbolic link */
/* regular file */
/* block special */
/* directory */
/* character special */
/* named pipe - FIFO */
/* set-UID bit */
/* set-GID bit */
/* save swapped text even after use
- sticky bit */
#define
#define
#define
#define
#define
#define
#define
S_ISLNK(m)
S_ISREG(m)
S_ISDIR(m)
S_ISCHR(m)
S_ISBLK(m)
S_ISFIFO(m)
S_ISSOCK(m)
(((m)
(((m)
(((m)
(((m)
(((m)
(((m)
(((m)
&
&
&
&
&
&
&
S_IFMT)
S_IFMT)
S_IFMT)
S_IFMT)
S_IFMT)
S_IFMT)
S_IFMT)
==
==
==
==
==
==
==
S_IFLNK)
S_IFREG)
S_IFDIR)
S_IFCHR)
S_IFBLK)
S_IFIFO)
S_IFSOCK)
#define
#define
#define
#define
S_IRWXU
S_IRUSR
S_IWUSR
S_IXUSR
00700
00400
00200
00100
/* user permission bits */
#define
#define
#define
#define
S_IRWXG
S_IRGRP
S_IWGRP
S_IXGRP
00070
00040
00020
00010
/* group permission bits */
#define
#define
#define
#define
...
S_IRWXO
S_IROTH
S_IWOTH
S_IXOTH
00007
00004
00002
00001
/* others’ permission bits */
Quando si accede ad un nuovo file il sistema localizza l’i-node corrispondente, alloca uno slot nella tavola
di sistema degli i-nodes, e legge l’i-node in memoria primaria. Come per i buffers della cache di sistema, lo
slot nella tavola è considerato la versione corrente dell’i-node. Le modifiche dell’i-node sono fatte nella
tavola. Quando viene effetuato l’ultimo accesso al file, l’i-node è ricopiato nella i-list in memoria
secondaria, e lo slot è deallocato nella tavola.
Tutte le operazioni di I/O sui files sono effettuate con l’aiuto dello slot corrispondente nella tavola degli inodes. L’accesso ad un file è una semplice implementazione dell’algoritmo ora menzionato. L’utente non
deve occuparsi dello i-node nè dell’i-number. I riferimenti al filesystem sono fatti in termini di path-name
nell’albero delle directories. Convertire un path-name in uno slot nella tavola degli i-nodes è anch’esso
molto semplice: partendo da qualche i-node conosciuto (la radice dell’arborescenza, per path-name
assoluti, o la directory di lavoro attuale di un processo, per path-name relativi) il prossimo componente del
path-name viene ricercato leggendo la directory. Ciò fornisce un i-number ed un device implicito (il disco
della directory). Così si può accedere allo slot successivo nella tavola degli i-nodes. Se si tratta dell’ultima
componente del path-name, allora questo i-node è il risultato cercato. Altrimenti questo i-node è la
directory necessaria per cercare il successivo componente del path-name, e si ripete l’algoritmo.
V. Asta - Introduzione a Unix e GNU/Linux
74
L’utente accede al filesystem con alcune primitive di sistema. Le più comuni sono open(2), create(2),
read(2), write(2), lseek(2) e close(2).
Nella zona dei dati di sistema associati ad un processo (nella tavola dei processi attivi) c’è spazio per un
certo numero di files aperti (in genere dai 50 in su). Questa tavola dei files aperti per processo consiste di
puntatori che possono essere utilizzati per accedere all’entrata corrispondente nella tavola degli i-nodes.
Associato ad ognuno di questi files aperti c’è un puntatore di I/O. Si tratta di un offset in bytes nel file, per
la successiva operazione di I/O. Il sistema tratta le richiesta di lettura/scrittura come aleatorie con un seek
implicito al puntatore di I/O. L’utente vede in generale i suoi files come sequenziali, col puntatore di I/O
che conta automaticamente il numero di bytes che sono già stati letti/scritti sul file. L’utente può
ovviamente fare dei veri I/O aleatori posizionando il puntatore di I/O prima di una lettura/scrittura (con la
primitiva lseek(2)).
A causa del meccanismo di condivisione di files aperti, è necessario autorizzare i processi in relazione
padre-figlio a condividere un puntatore di I/O comune, e avere ugualmente puntatori di I/O differenti per i
processi indipendenti che accedono ad uno stesso file. Con queste due condizioni, il puntatore di I/O non
può trovarsi nella tavola degli i-nodes, nè nella tavola dei files aperti per processo. Una nuova tavola (la
tavola dei files aperti di sistema) è stata quindi introdotta, con lo scopo di contenere il puntatore di I/O, il
modo di apertura del file (O_RDONLY, O_RDWR etc.) e alcune altre informazioni. La definizione della
struttura degli slot di questa tavola si trova nel file /usr/include/sys/file.h (in LINUX, in
/usr/include/linux/fs.h):
$ cat /usr/include/linux/fs.h
...
struct file
{
struct file
*f_next, **f_pprev;
struct dentry
*f_dentry;
struct file_operations *f_op;
/* pointers to functions */
mode_t
f_mode;
/* O_RDONLY, etc. */
loff_t
f_pos;
/* I/O pointer */
unsigned int
f_count,
/* reference count */
f_flags;
unsigned long
f_reada, f_ramax, f_raend, f_ralen, f_rawin;
struct fown_struct
f_owner;
unsigned int
f_uid, f_gid;
int
f_error;
unsigned long
f_version;
/* needed for tty driver, and maybe others */
void
*private_data;
};
...
I processi che condividono uno stesso file aperto (i risultati della primitiva fork(2)) condividono una entrata
comune nella tavola dei files aperti di sistema. Un’apertura separata dello stesso file condividerà soltanto lo
slot nella tavola degli i-nodes, ma avrà uno slot separato nella tavola dei files aperti.
Le principali primitive di gestione del filesystem sono implementate nel modo seguente: open(2) converte
un path-name del filesystem in uno slot nella tavola degli i-nodes. Un puntatore verso lo slot nella tavola
degli i-nodes viene inizializzato in uno slot della tavola dei files aperti, allocato per l’occasione (in LINUX,
ciò avviene attraverso un’ulteriore struttura di dati: il membro f_dentry della struct file punta ad una struct
dentry, di cui il membro d_inode punta all’i-node).
$ cat /usr/include/linux/dcache.h
...
struct dentry {
V. Asta - Introduzione a Unix e GNU/Linux
75
int d_count;
unsigned int d_flags;
struct inode * d_inode;
/* pointer to inode structure */
struct dentry * d_parent;
/* parent directory */
struct dentry * d_mounts;
/* mount information */
struct dentry * d_covers;
struct list_head d_hash;
/* lookup hash list */
struct list_head d_lru;
/* d_count = 0 LRU list */
struct list_head d_child;
/* child of parent list */
struct list_head d_subdirs;
/* our children */
struct list_head d_alias;
/* inode alias list */
struct qstr d_name;
unsigned long d_time;
/* used by d_revalidate */
struct dentry_operations *d_op;
struct super_block * d_sb;
/* The root of the dentry tree */
unsigned long d_reftime;
/* last time referenced */
void * d_fsdata;
/* fs-specific data */
unsigned char d_iname[DNAME_INLINE_LEN]; /* small names */
};
...
Un puntatore verso lo slot nella tavola dei files aperti è inizializzato nella zona di dati sistema del processo;
tale tavola è dichiarata in /usr/include/sys/user.h (in LINUX, in /usr/include/linux/sched.h).
$ cat /usr/include/linux/sched.h
...
/*
* Open file table structure
*/
struct files_struct {
atomic_t count;
int max_fds;
int max_fdset;
int next_fd;
struct file ** fd;
/* current fd array */
fd_set *close_on_exec;
fd_set *open_fds;
fd_set close_on_exec_init;
fd_set open_fds_init;
struct file * fd_array[NR_OPEN_DEFAULT];
};
...
creat(2) inizia col creare un nuovo i-node, scrive lo i-number in una directory, e costruisce poi la stessa
struttura che per una open(2). read(2) e write(2) utilizzano l’i-node in memoria come descritto
precedentemente. lseek(2) manipola semplicemente il puntatore di I/O nella tavola (membro f_pos della
struct file): nessuno spostamento fisico viene effettuato.
close(2) libera le strutture costruite da open(2) e create(2), e provoca tra l’altro la riscrittura in memoria
secondaria dell’i-node. Gli slot della tavola dei files aperti e della tavola degli i-nodes gestiscono anche dei
reference counts (membri i_count di struct inode e f_count di struct file), per liberare queste strutture
quando l’ultimo riferimento viene meno (quando cioè il reference count, decrementato, scende a zero).
unlink(2) decrementa semplicemente il conto del numero di directories che puntano sull’i-node dato (link
count; membro i_count di struct inode).
Quando l’ultimo riferimento ad uno slot nella tavola degli i-nodes sparisce, se l’i-node non ha più
directories che puntano su di lui, il file viene soppresso e l’i-node è liberato. Questa proroga nella
soppressione dei files evita i problemi posti dalla soppressione di files attivi. Un file può essere soppresso
anche se ancora aperto. Il file senza nome che ne risulta sparirà quando il file sarà chiuso. Questo è un
metodo tipico per creare e gestire dei files temporanei.
V. Asta - Introduzione a Unix e GNU/Linux
76
Esiste un tipo di file FIFO senza nome (cioè senza directory entry) chiamato pipe. La implementazione dei
pipes consiste in spostamenti (seeks) impliciti prima di ogni read/write per implementare il meccanismo
first-in-first-out. Ci sono anche alcune verifiche, ed una sincronizzazione per impedire al produttore di dati
di produrre troppo per il consumatore e per impedire al consumatore di prendere troppi dati.
A partire da System III esistono anche dei named pipes (pipes nominati), chiamati anche FIFO files. Si
tratta di pipes che hanno un i-node e una directory entry su disco.
Un altro tipo di file, introdotto in BSD UNIX, è costituito dai symbolic link files (link simbolici, anche detti
symlink); si tratta di files che contengono, come dati, il path-name del file reale a cui si riferiscono. Quando
viene fatta una open(2) di un file di questo tipo, il sistema riconosce dall’i-node che si tratta di un symlink,
e legge allora nel file il path del vero file da aprire.
Alcune versioni di UNIX hanno introdotto ulteriori tipi particolari di file.
10.3 File systems montati
Il filesystem di un sistema UNIX parte con un block device qualsiasi formattato come sopra descritto per
contenere una arborescenza. La radice di questa struttura è la radice del sistema UNIX. Un secondo block
device formattato può essere montato su qualunque foglia dell’arborescenza attuale. Ciò rappresenta quindi
un’estensione logica dell’arborescenza preesistente. L’implementazione del montaggio è banale: il sistema
gestisce una tavola di volumi montati che contiene coppie di i-node/foglie e di block devices; tale tavola è
dichiarata in /usr/include/sys/mount.h (in LINUX, in /usr/include/linux/mount.h).
$ cat /usr/include/linux/mount.h
...
struct vfsmount
{
kdev_t mnt_dev;
/* Device this applies to */
char *mnt_devname;
/* Name of device e.g. /dev/dsk/hda1 */
char *mnt_dirname;
/* Name of directory mounted on */
unsigned int mnt_flags;
/* Flags of this device */
struct super_block *mnt_sb;
/* pointer to superblock */
struct quota_mount_options mnt_dquot; /* Diskquota specific mount options */
struct vfsmount *mnt_next;
/* pointer to next in linkedlist */
};
...
Quando un path-name e è convertito in i-node, si fa una verifica per vedere se il nuovo i-node è una di
queste foglie. In caso affermativo, esso viene sostituito con l’i-node della radice del block device.
L’allocazione dello spazio per un file è fatta nel pool dei blocchi liberi sul device nel quale il file si trova.
Così un filesystem costituito da più devices montati non ha un pool comune di spazio libero in memoria
secondaria. Questa separazione dello spazio su più devices è necessaria per permettere smontaggi facili di
un device.
V. Asta - Introduzione a Unix e GNU/Linux
77
11. Avvio del sistema
All’avvio fisico di un sistema UNIX vengono percorsi i seguenti passi:
— il kernel viene caricato in memoria dal programma di bootstrap
— il kernel si inizializza e lancia un certo numero (che varia a seconda del tipo e versione del Sistema
Operativo) di threads o processi di sistema; tipicamente, si tratta del processo init e poi di altri
processi che hanno a che fare con lo scheduling, la paginazione e/o lo swapping, la gestione della
cache di I/O. In un tipico UNIX System V, troviamo:
- scheduler/swapper (in-swapper) (PID = 0)
- init (PID = 1); vedi oltre
- page daemon (out-swapper) (PID = 2)
- update; si occupa di eseguire un codice che effettua periodicamente (di solito ogni 30 secondi) una
chiamata di sistema sync(2); ciò serve a garantire la sincronizzazione periodica tra memoria di
cache di I/O e contenuto della memoria secondaria.
In LINUX, i processi sono invece i seguenti:
- idletask (PID = 0); è il thread a cui viene data la CPU quando il sistema non ha nulla da fare
- init (PID = 1)
- kflushd (PID = 2), kupdate (PID = 3) − hanno entrambi a che fare con la scrittura su disco dei
buffer di cache modificati ("dirty buffers"); sono quindi l’equivalente del task update, ma lavorano
con un algoritmo più sofisticato, che tiene conto dell’età di residenza in memoria dei buffer (oltre
una certa età, viene forzata la scrittura su disco) e comunque di una sincronizzazione periodica (30
secondi per il blocchi di dati, 5 secondi per i superblock)
- kpiod (out-pager) (PID = 5)
- kswapd (PID = 6), che si ocupa di liberare e rendere disponibili per un nuovo uso pagine libere di
memoria.
— come detto, uno di questi processi (presente in qualunque versione di UNIX) è /etc/init (o /sbin/init),
che ha il compito di lanciare tutti gli altri processi di sistema e quelli a livello utente per permettere
l’avvio dei server e dei programmi per il login degli utenti.
— init consulta il file /etc/inittab, che contiene le istruzioni sul da farsi.
— tra le cose da fare al bootstrap, init lancia uno o più shell script che si trovano nella directory
/etc/rc.d; l’organizzazione dei file in questa directory può variare da un sistema all’altro, ma il
meccanismo di base è identico
— gli shell script in /etc/rc.d
- effettuano varie inizializzazioni (ad esempio configurando le interfacce di rete con gli appropriati
indirizzi IP), cleanup di file e directory temporanee o di spool, etc.
- lanciano i server di sistema; dapprima quelli locali, poi eventualmente quelli di rete
- lanciano, per ogni linea utente (tty), un’istanza del programma getty (che si trova normalmente in
/etc o in /sbin, e di cui possono esistere più varianti) in sottoprocessi figli diretti di init;
— il programma getty viene invocato col nome della tty come argomento, ed effettua i seguenti passi:
- apre (per la prima volta, stabilendo così un process group) lo special file della linea
- lo ridirige sul suo stdin, stdout e stderr (aprendo i canali n. 0, 1 e 2)
V. Asta - Introduzione a Unix e GNU/Linux
78
- consulta il file /etc/gettydefs60 e configura i parametri di funzionamento della linea (velocità di
trasmissione, traslazione <CR> -> <NL> in input, etc.61)
- scrive a stdout la stringa di invito al login (ad es. "Login: ")
- legge una riga dallo stdin (il nome dell’utente) ed effettua una chiamata di sistema execve(2) e
lancia il programma /bin/login con argomento il nome d’utente letto
— il programma login, invocato come detto, effettua a sua volta i seguenti passi:
- scrive a stdout la stringa di richiesta di password (ad es. "Password: ")
- legge una riga dallo stdin (la password)
- apre il file /etc/passwd; per convenienza, si denominino come segue i campi di ciascuna riga di
questo file:
User:Passwd:Uid:Gid:Comment:Home:Program
e legge in memoria la riga il cui campo User corrisponde al nome dell’utente;
- cripta la password letta, e la confronta col campo Passwd (si noti che il confronto è tra le forme
criptate delle password); se la password letta non corrisponde con quella del file /etc/passwd, il
login viene abortito
- effettua le chiamate sistema setgid(2) e poi setuid(2) per assumere l’identità di gruppo e di utente
specificata dai campi Gid e Uid (si noti che il programma finora stava girando con i diritti del
superuser, essendo figlio diretto di init)
- effettua una chiamata sistema chdir(2) per posizionarsi nella directory del campo Home
- posiziona alcune variabili di environment, quali il parametro LOGNAME, il parametro HOME etc.
- esegue infine una chiamata execve(2) per lanciare il programma specificato nel campo Program (di
solito una shell); come già detto, login prepende il carattere ‘-’ all’argv[0] dell’array degli
argomenti, cioè al nome di invocazione del programma da eseguire, e ciò permette a quest’ultimo
di rendersi conto che sta girando come programma di login; nel caso di una shell, l’effetto
risultante è che i comandi posti nei file /etc/profile e $HOME/.profile (se esiste) sono letti ed
eseguiti all’avvio della shell.
Pertanto, alla fine di questa sequenza, la situazione risultante è, normalmente, che una shell di login
si trova avviata su ciascuna linea utente, all’interno di un processo che è figlio diretto di init
(all’interno di questo processo, si sono succeduti dapprima il programma init, poi getty, poi login e
infine la shell), con i diritti dell’utente che si è connesso e del relativo gruppo di login.
— all’uscita della shell, il processo init rilancia, in loop, la stessa sequenza sulla linea utente
— i programmi init, getty e login aggiornano due file di sistema che contengono le informazioni sugli
utenti collegati:
- utmp (path abituale: /etc/utmp, o /var/run/utmp)
- wtmp (path abituale: /etc/wtmp, o /var/log/wtmp)
il primo contiene essenzialmente un record (si veda utmp(5) per i dettagli di formato interno) per
ogni linea utente, con le informazioni sull’utente collegato, la tty, l’ora di inizio della sessione di
lavoro, il PID del processo iniziale e altro; il record è inizializzato con i dati rilevanti ad ogni login,
ed è poi invalidato ad ogni logout; utmp contiene quindi la fotografia istantanea degli utenti collegati
60.
Alcune versioni di getty utilizzano altri file di configurazione, con differente formato
61.
Questi parametri sono precisati in una struttura dati di sistema, struct termio, e vengono posizionati o consultati mediante la
chiamata di sistema ioctl(2)
V. Asta - Introduzione a Unix e GNU/Linux
79
al sistema. Il secondo file (wtmp) ha formato identico al primo, ma ad ogni login e logout un nuovo
record viene accodato al file (nel caso dei logout, il campo col nome dell’utente è una stringa nulla);
tale file quindi registra tutti i login e logout del sistema, ed è un file che cresce indefinitamente
(pertanto, insieme ai file di log del sistema e ad altri file, deve essere riazzerato e preventivamente
salvato, con cadenza periodica). Il comando who non fa altro che leggere il file utmp e visualizzarne
il contenuto in formato leggibile da terminale.
V. Asta - Introduzione a Unix e GNU/Linux
80
12. Il programma init
Il programma init funziona secondo una logica a livelli, che regolano il modo di funzionamento del
sistema. Ad ogni livello (detto anche run-level) corrispondono varie applicazioni, o sottosistemi, da
lanciare o da fermare; tutto ciò è precisato nel file di configurazione /etc/inittab. All’avvio, init si configura
per un livello di default, e lancia tutte le applicazioni relative a questo livello; per cambiare di livello,
l’amministratore di sistema lancia il programma /sbin/telinit (che altro non è che un link allo stesso
eseguibile di init), con un argomento pari al nuovo livello voluto; telinit comunica tale informazione al
processo init attivo, il quale provvede a lanciare le applicazioni relative al nuovo livello. Ad esempio, il
comando
telinit 3
fa sì che il processo init originale (PID = 1) si sposti al livello 3, avviando tutti e soli i sottosistemi
predisposti per questo livello; infine, il comando
telinit q
viene lanciato normalmente dopo una modifica al file inittab, per notificare a init che deve rileggere questo
file e comportarsi di conseguenza (ad esempio, dopo aver abilitato una nuova linea di login); ciò non
implica nessun cambiamento di livello.
Il livelli sono normalmente sette, numerati da 0 a 6 (il livello 1 è anche denominato livello s, o single-user);
l’utilizzo di questi livelli può variare a seconda del tipi di sistema UNIX; un esempio tipico (per un sistema
GNU/LINUX) è il seguente:
0
power off - shutdown del sistema
1s
mono-utente (modo di maintenance, login disabilitati salvo sulla console di sistema)
2
modo normale multi-utente (login abilitati)
3
modo normale multi-utente con supporto di rete (NFS abilitato62)
4
test locale di nuove applicazioni (spesso inutilizzato)
5
modo multi-utente con ambiente grafico X1163 abilitato
6
reboot del sistema
Il formato del file /etc/inittab è il seguente (si tratta anche qui, come per /etc/passwd e /etc/group, di righe di
testo con campi separati dal carattere ‘:’):
Id:Runlevels:Action:Command
id
è una sequenza unica da 1 a 4 caratteri, che identifica il record
Runlevels
lista dei livelli per i quali l’azione deve essere avviata; se il campo è nullo, l’azione va
avviata per qualunque livello
Action
descrive il tipo di azione da avviare
Command
specifica il processo da eseguire per la data azione (comando e argomenti).
Ad esempio, la riga seguente
g1:235:respawn:/sbin/getty tty1a L19200
62.
NFS = Network File System; si tratta di un sottosistema che permette il montaggio di filesystem remoti, attraverso una rete
TCP/IP
63.
X11 è l’ambiente grafico dei sistemi UNIX; si tratta di un grosso package di librerie grafiche, ambienti desktop e programmi;
X11 è stato sviluppato inizialmente all’M.I.T. (Massachusetts Institute of Technology); i sorgenti sono di dominio pubblico
V. Asta - Introduzione a Unix e GNU/Linux
81
indica che la riga denominata "g1" specifica un’azione da attivare per i livelli di run n. 2, 3 e 5; l’azione
consiste nel lancio in loop continuo ("respawn") del programma getty, con argomenti tty1a (nome dello
special file da aprire, in /dev/) e L19200 (che è una label che rinvia ad una riga del file /etc/gettydefs, con i
dettagli sulla configurazione di linea da adottare).
Le azioni principali previste da init sono le seguenti (si veda inittab(5) per ulteriori dettagli):
respawn
Lancia Command, non aspettare che finisca; quando termina, rilancialo. Quest’azione è
quella tipica delle sequenze di login, dove il comando prevede appunto l’avvio in ciclo
continuo del programma getty.
off
Se Command è attivo, terminalo; altrimenti, ignora questa riga. Utilizzato spesso per
disabilitare una entry.
wait
Lancia Command, e aspetta che termini prima di continuare.
once
Lancia Command una sola volta all’ingresso nel dato run-level, non aspettare che esca, e
non rilanciarlo.
initdefault
Specifica il run-level di default; in questo caso, il campo Command è ignorato.
sysinit
Lancia Command al bootstrap del sistema, prima di ogni altra cosa (prima ancora di
accedere alla console di sistema); il campo Runlevels è ignorato.
boot
Lancia Command al bootstrap del sistema, dopo le eventuali entry sysinit.
bootwait
Analogo al caso precedente, ma aspetta che Command termini prima di continuare.
powerfail
Lancia Command alla ricezione del segnale n. 30 (SIGPWR - segnale di assenza di
alimentazione elettrica), che viene normalmente inviato da un apposito daemon connesso
ad un dispositivo di gruppo di continuità (UPS - Uninterruptible Power System). Il
comando tipicamente prevede un messaggio di avvertimento a tutti gli utenti connessi, e
l’avvio della procedura di shutdown entro pochi minuti (comunque entro il tempo di
autonomia dello UPS, cioè prima che l’energia elettrica manchi del tutto e si verifichi
quindi uno spegnimento forzato della macchina).
powerwait
Analogo al caso precedente, ma aspetta che Command termini prima di continuare
powerokwait
Lancia Command non appena informato che l’alimentazione elettrica è stata ripristinata
(ovviamente durante il tempo di autonomia dello UPS); aspetta che il comando termini
prima di continuare. Il comando di norma prevede l’annullamento della procedura di
shutdown precedentemente avviata.
ctrlaltdel64
Lancia Command alla ricezione del segnale n. 2 (SIGINT); ciò avviene normalmente
quando l’utente digita la combinazione <CTRL-ALT-DEL> sulla console di sistema. Il
comando tipico è l’avvio della procedura di shutdown.
A titolo di esempio, si riporta qui un file inittab completo:
# inittab
#
This file describes how the INIT process should set up
the system in a certain run-level.
id:5:initdefault:
# System initialization.
si::sysinit:/etc/rc.d/rc.sysinit
l0:0:wait:/etc/rc.d/rc.0
l1:1:wait:/etc/rc.d/rc.1
l2:2:wait:/etc/rc.d/rc.2
64.
Questo tipo di azione, com’è facile intuire, è un’estensione propria delle architetture IBM-PC, e non è supportato da tutte le
versioni di init
V. Asta - Introduzione a Unix e GNU/Linux
82
l3:3:wait:/etc/rc.d/rc.3
l4:4:wait:/etc/rc.d/rc.4
l5:5:wait:/etc/rc.d/rc.5
l6:6:wait:/etc/rc.d/rc.6
# Things to run in every runlevel.
ud::once:/sbin/update
# Trap CTRL-ALT-DELETE
ca::ctrlaltdel:/sbin/shutdown -t3 -r now
# When our UPS tells us power has failed, assume we have a few minutes
# of power left. Schedule a shutdown for 2 minutes from now.
# This does, of course, assume you have powerd installed and your
# UPS connected and working correctly.
pf::powerfail:/sbin/shutdown -f +2 "Power Failure; System Shutting Down"
# If power was restored before the shutdown kicked in, cancel it.
pr:12345:powerokwait:/sbin/shutdown -c "Power Restored; Shutdown Cancelled"
# If power comes back in single user mode, return to multi user mode.
ps:S:powerokwait:/sbin/init 3
# Run gettys for logins in standard runlevels
g1:235:respawn:/sbin/getty tty1 M19200
g2:235:respawn:/sbin/getty tty2 M19200
g3:235:respawn:/sbin/getty tty3 M19200
g4:235:respawn:/sbin/getty tty4 M19200
g5:235:respawn:/sbin/getty tty5 M19200
g6:235:respawn:/sbin/getty tty6 Ldefault
# Dialin lines -- modems for external access, esp. for Internet
s0:235:respawn:/usr/local/sbin/mgetty -x 9 -D /dev/ttyS16 UU38400
s1:235:respawn:/usr/local/sbin/mgetty -x 9 -D /dev/ttyS17 UU38400
s2:235:respawn:/usr/local/sbin/mgetty -x 9 -D /dev/ttyS18 UU38400
s3:235:respawn:/usr/local/sbin/mgetty -x 9 -D /dev/ttyS19 UU38400
# Run xdm in runlevel 5
# xdm is now a separate service
x:5:respawn:/etc/X11/prefdm -nodaemon
Com’è facile vedere, tipicamente ad ogni avvio di livello corrisponde l’avvio di una specifica procedura
shell; queste procedure, come già anticipato, si trovano tutte nella directory /etc/rc.d ed hanno nomi del
tipo rc.# dove # è una cifra, corrispondente al livello da raggiungere. In linea generale, questi script
lanciano a loro volta una serie di altri script, spesso uno per ciascun sottosistema (ad esempio, uno per
montare tutti i filesystem, uno per avviare lo spooler della stampante, uno per il collegamento in rete, etc.), i
quali effettuano due tipi di azioni:
— terminazione dei programmi di tutti i sottosistemi relativi a livelli precedenti, e che non devono
essere presenti nel nuovo livello
— avvio dei programmi dei sottosistemi pertinenti al nuovo livello.
Qui di seguito si riporta un semplice esempio di script per l’avvio di un livello multi-utente completo (ad
esempio livello 3, nell’esempio tipico ipotizzato):
#!
#
# rc.3
#
#
#
#
/bin/sh
This file is executed by init(8) when the system is being
initialized for one of the "multi user" run levels (i.e.
levels 2 through 5). It usually does mounting of file
systems et al.
V. Asta - Introduzione a Unix e GNU/Linux
83
# Tell the viewers what’s going to happen...
echo "Going multiuser..."
# stop any unwanted sub-systems
if [ -x /etc/rc.d/rc.stop ]
then
. /etc/rc.d/rc.stop
fi
# Look for a CD-ROM in a CD-ROM drive, and if one is found,
# mount it under /cdrom. This must happen before any of the
# binaries on the CD are needed.
if [ -x /etc/rc.d/rc.cdrom ]
then
. /etc/rc.d/rc.cdrom
fi
# mount all required file-systems
if [ -x /etc/rc.d/rc.mount ]
then
. /etc/rc.d/rc.mount
else
# no specific script -- hope this will do...
/bin/mount -a
fi
# If there’s no /etc/HOSTNAME, fall back on this default:
if [ ! -r /etc/HOSTNAME ]
then
echo "localhost.localdomain" >/etc/HOSTNAME
fi
# Set the hostname. This might not work correctly if TCP/IP is not
# compiled in the kernel.
/bin/hostname ‘cat /etc/HOSTNAME | cut -f1 -d .‘
# Initialize the NET subsystem.
if [ -x /etc/rc.d/rc.inet1 ]
then
. /etc/rc.d/rc.inet1
. /etc/rc.d/rc.inet2
else
# no NET subsystem - local config. only; start just local daemons
if [ -x /usr/sbin/syslogd ]
then
# system logging daemons
/usr/sbin/syslogd
/usr/sbin/klogd -c 3
fi
if [ -x /usr/sbin/lpd ]
then
# line printer spooler daemon
/usr/sbin/lpd
fi
fi
# Start Cron daemon
/usr/sbin/crond -l10 >>/var/adm/cron 2>&1
# Start At daemon (manages jobs scheduled with ’at’):
/usr/sbin/atd -b 15 -l 1
# Remove stale locks and junk files (must be done after mount -a!)
/bin/rm -f /var/lock/* /var/spool/uucp/LCK..* /tmp/.X*lock \
/tmp/core /core >/dev/null 2>&1
V. Asta - Introduzione a Unix e GNU/Linux
84
# Ensure basic filesystem permissions sanity.
chmod 755 /
chmod 1777 /tmp /var/tmp
# Update all the shared library links automatically
/sbin/ldconfig
# Check quotas and then turn quota system on:
if fgrep quota /etc/fstab >/dev/null 2>&1
then
if [ -x /sbin/quotacheck ]
then
echo "Checking filesystem quotas..."
/sbin/quotacheck -avug
fi
if [ -x /sbin/quotaon ]
then
echo "Activating filesystem quotas..."
/sbin/quotaon -avug
fi
fi
# Start the sendmail daemon (SMTP - E-mail handling):
if [ -x /usr/sbin/sendmail ]
then
echo "Starting sendmail daemon (/usr/sbin/sendmail -bd -q15m)..."
/usr/sbin/sendmail -bd -q15m
fi
# Load a custom keymap if the user has an rc.keymap script.
if [ -x /etc/rc.d/rc.keymap ]
then
. /etc/rc.d/rc.keymap
fi
# iBCS Emulation for Linux
if [ -x /etc/rc.d/rc.ibcs2 ]
then
. /etc/rc.d/rc.ibcs2
fi
# Start Web server:
if [ -x /etc/rc.d/rc.httpd ]
then
. /etc/rc.d/rc.httpd
fi
# Start Samba (a file/print server for Win95/NT machines):
if [ -x /etc/rc.d/rc.samba ]
then
. /etc/rc.d/rc.samba
fi
# If there are SystemV-style init scripts for this runlevel, run them.
if [ -x /etc/rc.d/rc.sysvinit ]
then
. /etc/rc.d/rc.sysvinit
fi
# Start the local setup procedure (any local subsystems, specific to
# this machine).
if [ -x /etc/rc.d/rc.local ]
then
. /etc/rc.d/rc.local
fi
V. Asta - Introduzione a Unix e GNU/Linux
85
# All done.
V. Asta - Introduzione a Unix e GNU/Linux
86
APPENDICE A
Cronologia dettagliata di UNIX
Nota − per comodità di consultazione e per completezza, in questa Appendice vengono ripetute
sostanzialmente anche le informazioni già esposte nel paragrafo 1.1 pag. 3 e in parte nei
paragrafi 1.2 pag. 4 e 1.3 pag. 9.
Il Sistema Operativo UNIX è stato realizzato a partire dai primi anni ’70 nei Bell Laboratories, ad
opera soprattutto di Ken Thompson e Dennis Ritchie, dapprima per soli usi interni; è stato poi
commercializzato dalla Western Electric, casa madre dei Bell Labs e della AT&T, e
successivamente dalla AT&T stessa; si è affermato commercialmente a partire dagli anni ’80.
Le prime versioni giravano su sistemi della Digital Equipment Corporation (DEC): dapprima su
un PDP-7, poi (dal 1971) su quelli della famiglia PDP-11, quindi (1979) sui VAX-11. Nel 1981,
con la versione PC/IX della Interactive Systems per macchine IBM PC/AT, UNIX fa la sua prima
apparizione nella gamma dei Personal Computer IBM e compatibili.
La storia della nascita e dell’evoluzione di questo sistema è reperibile in molti testi, alcuni dei
quali citati in bibliografia; esistono inoltre due numeri speciali del The Bell System Technical
Journal, dedicati esclusivamente a UNIX, che illustrano molti aspetti interessanti del sistema,
della sua storia, delle sue motivazioni originali e delle sue caratteristiche ([BSTJ 1978], [BSTJ
1984]).
1968:
Bell Labs abbandona il progetto MULTICS, nato da uno sforzo congiunto insieme
all’MIT e a General Electric per la realizzazione di un Sistema Operativo di tipo
interattivo e multiutente65.
Ken Thompson (seguito poi da Dennis Ritchie) inizia a lavorare su un sistema di
filesystem e di gestione dei processi, scritto parte in assembler e parte in Fortran,
per il Sistema Operativo GECOS, che sarà all’origine della progettazione di UNIX.
1969-1970:
Thompson e Ritchie producono una prima versione sperimentale di un Sistema
Operativo, scritta in Assembler per un PDP-766 della Digital Equipment
Corporation (DEC). I concetti di base derivano in parte dai sistemi CTSS,
TENEX, MULTICS. L’obiettivo è di realizzare un Sistema Operativo interattivo
che offra su dei minicomputers un ambiente di programmazione equivalente a
quello di cui disponevano i grandi calcolatori.
1971:
Viene effettuato il porting su PDP-11; la prima edizione ufficiale67 di UNIX,
diffusa solo all’interno dei Bell Labs, viene realizzata su un DEC PDP-11/20. Si
tratta di una versione che permette solo la monoprogrammazione68, ma è capace di
girare con un quantità minima di risorse hardware: 16 kbytes per il kernel, 8
kbytes per i programmi utente, un disco da 512 kbytes, 64 kbytes come limite
massimo di lunghezza di un file. Tutte le distribuzioni includevano la totalità del
codice sorgente del kernel e dei programmi: il sistema era concepito da
programmatori per l’uso dei programmatori, dunque la migliore (e in certi casi
65.
Una versione iniziale di MULTICS funzionò nel 1969 su macchine GE 645 della General Electric, ma il prodotto risultante,
benchè interessante dal punto di vista concettuale, risultò troppo complesso ed elefantiaco, e sostanzialmente non raggiunse gli
scopi che il progetto si era prefisso.
66.
La macchina era equipaggiata con 4 kbytes di memoria RAM in tutto.
67.
Le prime versioni, fino al 1979, saranno identificate col numero di edizione del manuale, per cui è più corretto dire ad esempio
"UNIX 6. edizione" anzichè "UNIX Versione 6".
68.
Il nome UNIX è stato originalmente coniato come contraposizione umoristica a MULTICS, che poteva fare molte cose per molti
utenti, mentre UNIX all’origine era un sistema piccolino, che faceva una sola cosa alla volta per un solo utente.
V. Asta - Introduzione a Unix e GNU/Linux
87
unica) forma di documentazione era la consultazione diretta dei sorgenti.
1971-1972:
Thompson lavora su un linguaggio interpretato, chiamato "linguaggio B", derivato
dal linguaggio BCPL, sviluppato da M. Richards (sempre internamente ai Bell
Labs).
Ritchie scrive un compilatore per un nuovo linguaggio, derivato a sua volta dal
linguaggio B, che permetta ad un tempo di realizzare software di base (sistemi,
utilities, etc.) e di realizzare delle applicazioni ad alto livello. Nasce così il
linguaggio C.
1972:
Seconda edizione di UNIX, che permette la multiprogrammazione. È disponibile su
diverse macchine della serie PDP-11 (ma non tutte): PDP-11/34, 40, 45, 60, 70.
1973:
Riscrittura di UNIX (kernel e applicativi) in linguaggio C, ad opera essenzialente di
Thompson, Ritchie e alcuni altri ricercatori dei Bell Labs, tra cui Brian Kernighan.
La dimensione del kernel aumenta del 30%69, ma il sistema diventa realmente
multitasking e multiutente.
Due progetti indipendenti si innestano sull’evoluzione di UNIX:
— MERT, derivazione orientata al tempo reale
— PWB (Programmer’s WorkBench), versione specializzata destinata a fornire
un ambiente di programmazione per i teams di sviluppo software.
1973-1974:
UNIX Versione 3 (terza edizione del manuale), poi 4 e 5; si tratta ancora di versioni
ad uso interno, modificate dagli utenti secondo i loro propri bisogni (MERT,
PWB/UNIX). Pur non essendo comercializzate, vengono distribuite (in forma di
codice sorgente) ad organizzazioni senza scopo di lucro che riescono ad ottenerne
la licenza, in particolare l’Università di California a Berkeley (UCB) e la
Columbia University. La reputazione e la robustezza di UNIX si è inizialmente
costruita su questa base universitaria, che ha fornito un prezioso feedback ai Bell
Labs. Val la pena di evidenziare che si è qui in presenza di un’anticipazione
storica del modello cooperativo del Software Libero, sia pure su scala molto più
ridotta e controllata.
1975:
Messa a punto di UNIX Versione 6 (V.6); prima versione commercializzata, senza
installazione, senza manutenzione, senza aggiornamenti70. Primissime imitazioni
di UNIX (sistemi UNIX-like), in particolare IDRIS, della Whitesmiths Ltd, che è il
capostipite di questo tipo di sistemi.
1977:
Primi adattamenti di UNIX su calcolatori non DEC; la prima nuova macchina è un
Interdata 8/3271.
L’approccio ai problemi di portabilità porta delle modifiche, a livello di linguaggio
C, per rendere il sistema e i programmi indipendenti dalle caratteristiche
dell’hardware; il kernel viene ristrutturato per isolare le parti dipendenti dalle
macchine.
69.
La dimensione massima della memoria è sempre stato un problema non indifferente, anche negli anni seguenti, per tutte le
macchine DEC della serie PDP (di cui i PDP-11 sono stati la serie più evoluta): l’architettura hardware dei PDP-11 dell’epoca
prevedeva un bus di dati a 16 bit e, soprattutto, un bus di indirizzi a 18 bit; pertanto la memoria fisica massima installabile era di
256 kbytes, divisa in 4 pagine da 64 kbytes (ma molte macchine disponevano di 128 kbytes in tutto). Il codice del kernel doveva
rimanere compreso comunque in un’unica pagina da 64 kbytes.
70.
L’unico tipo di licenza disponibile era la licenza sorgente, che comprendeva il codice di tutto il kernel e di tutte le utilities
applicative; la distribuzione consisteva in un nastro magnetico bootstrappabile, e due fogli di carta stampati con stringatissime
istruzioni di installazione, che terminavano con la frase ormai celeberrima "Good luck." ("Buona fortuna."). Tutta la
manualistica era on-line, e andava stampata a cura dell’acquirente. Il contratto di licenza specificava chiaramente che nessuna
forma di assistenza era prevista. Le cose sono cambiate a partire da System III, che AT&T dichiarò considerare il primo vero
prodotto commerciale UNIX.
V. Asta - Introduzione a Unix e GNU/Linux
88
Nei Bell Labs, il BISP (Business Information System Program) utilizza
PWB/UNIX, che permette lo sviluppo dei programmi su minicomputer PDP-11 e la
loro esecuzione su mainframe IBM 370 e UNIVAC 1100. PWB/UNIX apporta
molte modifiche e novità rispetto a ’*(uX V6, in particolare:
— funzionalità per il supporto di progetti software di grandi dimensioni
(numero massimo di utenti, dimensione massima dei files, etc.)
— Utilities di gestione delle versioni dei sorgenti (si tratta del package SCCS Source Code Control System, l’antenato di RCS e di CVS), e di lancio
dell’esecuzione di jobs a distanza (RJE - Remote Job Entry).
1979:
Rilascio di UNIX V.7; si tratta di una versione più stabile e con migliori prestazioni
rispetto alla versione precedente, sviluppato per PDP-11/45 e PDP-11/7072. La
V.7 è la prima versione riscritta senza alcuna dipendenza concettuale
dall’architettura dei PDP-11; vengono introdotte numerose modifiche tecniche, tra
cui l’ulteriore soppressione di limiti massimi di sistema (ripresa ed estesa da
PWB/UNIX), e modifiche per la portabilità.
UNIX V.7, con una versione denominata "32/V", viene adattato da John Reiser e
Tom London ai nuovi minicalcolatori a 32 bit di DEC, i VAX-11 (dapprima il
VAX 780, poi i modelli inferiori).
Prime licenze con diritto di ridistribuzione binaria (fino ad allora, l’unico tipo di
distribuzione era tramite i sorgenti): aziende di software e hardware vendors
possono acquistare la licenza sorgente del sistema (per un prezzo che, all’epoca
della V.7, era di diverse decine di migliaia di dollari73, licenza per una sola CPU),
e successivamente ottenere il diritto di realizzare versioni modificate e di venderle
in forma di prodotto binario (mediante l’ulteriore esborso di alcune centinaia di
migliaia di dollari, in termini di anticipo sulle royalties dovute per ogni licenza
venduta).
Risale a questo periodo l’inizio di quel vasto fenomeno che ha portato lentamente
ma inesorabilmente tutti i costruttori di calcolatori a realizzare una propria
versione del Sistema Operativo UNIX, realizzando così quell’importantissimo
fenomeno che ha condotto verso l’interoperabilità e compatibilità dei sistemi,
anche di marche differenti, e che ha determinato la caduta della supremazia quasi
monopolistica di IBM, incotrastato dominatore del mercato dell’hardware e del
software di base fin dagli albori della storia dell’informatica: per la prima volta,
tutti i concorrenti si sono trovati uniti in una causa comune, quella di UNIX contro i
sistemi proprietari di IBM, che ha dovuto alla fine capitolare e adottare anch’essa
sistemi UNIX per le proprie macchine.
Entrano così in scena i sistemi "UNIX-based", cioè prodotti venduti con licenza
binaria, ma dipendenti dal meccanismo di licensing della Western Electric che
percepisce una royalty per ogni sistema venduto. Tali sistemi, implementati e
proposti sul mercato su vari tipi di macchine, per motivi contrattuali non possono
71.
La macchina della Interdata (si veda [Johnson e Ritchie 1978], pag. 2038), che era stata scelta proprio perchè aveva
caratteristiche hardware notevolmente diverse da quelle dei PDP-11, così da testare adeguatamente l’effettiva portabilità del
sistema. Tra l’altro, oltre alla differente lunghezza di parola (32 bit, contro i 16 bit del PDP-11), l’Interdata aveva lo stack che
cresceva verso l’alto, al contrario del PDP-11 e della maggior parte dei calcolatori oggi sul mercato; la gestione dell’hardware
di memory management era differente; i tipi di trap disponibili, e il metodo di passaggio degli argomenti nelle chiamate
sistema, erano differenti. Ciò nonostante, delle 7000 righe del kernel interno, solo 350 (circa il 5%) erano differenti tra le due
implementazioni.
72.
I PDP-11/45 e 70 erano di tipo "split I&D" (Split Instructions and Data), cioè con un set di registri di Memory Management
(MMU) capace di gestire separatamente le sezioni di testo (codice dei programmi) e quelle di dati. La Versione 7 di UNIX, nella
sua implementazione iniziale, aveva bisogno di questa capacità per funzionare correttamente.
73.
Le Università pagavano invece un prezzo simbolico: la licenza, per numero illimitato di CPU, veniva proposta loro per qualche
centinaio di dollari.
V. Asta - Introduzione a Unix e GNU/Linux
89
chiamarsi UNIX (tale nome restava riservato alla sola licenza originale, sempre in
forma sorgente); nascono così prodotti i cui nomi spesso riecheggiano in qualche
modo la parola UNIX, pur con delle modifiche: tra di essi, IS/174 (Interactive
Systems), Xenix e SCO Unix (Microsoft e SCO - Santa Cruz Operation75),
Unixware (Novell, poi SCO), Zeus (Zilog), Uniplus+ (Unisoft Systems), Ultrix
(Digital Equipment Corporation), HP/UX (Hewlett-Packard), DG/UX (Data
General), AIX (IBM e Bull), SunOS e SOLARIS (SUN Microsystems), IRIX
(Silicon Graphics), e molti altri.
Nel frattempo, l’Università di California a Berkeley (UCB) lavora
all’implementazione di una nuova versione di UNIX 32/V per VAX, che supporta
la paginazione76 (implementata da Ozalp Babaoglu e Bill Joy); nel mese di
dicembre inizia la distribuzione di UNIX 3BSD (3. Berkeley Software
Distribution), la prima distribuzione BSD per VAX-1177.
1980:
Microsoft introduce sul mercato Xenix, una delle più famose versioni commerciali
di tipo UNIX-based78; tale attività viene dapprima svolta autonomamente, poi
tramite società partner, tra cui in particolare la SCO79.
Rilascio di UNIX 4BSD, con varie migliorìe nelle prestazioni.
1981:
AT&T subentra a Western Electric (che finora era stato l’organismo di vendita
delle licenze del sistema) per la commercializzazione di UNIX.
1982:
Nuova versione, denominata System III; nuova politica di commercializzazione e
di distribuzione di UNIX, che è ora proposto per macchine PDP-11, VAX-11 (e più
tardi per la serie 3B della AT&T) con condizioni di prezzo delle licenze binarie
derivate (in termini di royalties) più favorevoli in funzione delle quantità vendute.
System III ha le seguenti caratteristiche:
- riunisce tutte le caratteristiche di UNIX V.7 con quelle delle altre varianti interne
ai Bell Labs (in particolare PWB/UNIX);
- supporta tutta la gamma delle macchine PDP-11 e VAX-11, dal PDP-11/23 al
VAX/11 780
- contiene numerose estensioni di sistema, tra cui il supporto dei named pipes e
del meccanismo a più modi del sistema, tramite la tavola inittab per il processo
init.
74.
Il sistema IS/1 era commercializzato dalla Interactive Systems Corp., che è stata in assoluto la prima società rivenditrice di
UNIX come VAR (Value-Added Reseller).
75.
SCO è stata acquisita nel 2001 da Caldera International.
76.
L’implementazione del kernel di UNIX 32/V era funzionalmente identica a quello della V.7 per PDP-11, e quindi il sistema era
di tipo "segment sharing" (con un meccanismo di swapping totale dei processi: ciascun processo era o totalmente in RAM, o
totalmente nell’area di swap), sebbene l’hardware dei VAX permettesse di gestire la paginazione.
77.
Le distribuzioni BSD sono sempre state pressochè gratuite (il prezzo di realizzazione e spedizione di un nastro magnetico), ma
essendo dipendenti dal codice di UNIX 32/V, cioè in ultima analisi di UNIX V.7, l’Università di Berkeley poteva distribuire le sue
versioni (che erano anch’esse solo in forma sorgente) esclusivamente a chi aveva precedentemente acquisito una licenza Bell
Labs per UNIX V.7 o 32/V. Molte aziende pagavano il prezzo forte per la licenza Bell Labs solo per poter avere poi la versione di
Berkeley UNIX (la distribuzione Bell non veniva nemmeno installata). Questa situazione si è protratta di fatto fino al 1994, anno
in cui UCB ottenne ufficialmente, al termine di un processo, il diritto di distribuire liberamente la propria versione di UNIX
[McKusick 1999].
78.
È abbastanza ironico osservare che Microsoft sia stata tra le società private principali responsabili dell’affermarsi e del successo
di UNIX allora, e quindi indirettamente di quello di LINUX oggi.
79.
Contrariamente a quanto molti ritengono, Xenix non è nato sulla piattaforma IBM-PC; è stato invece la prima versione
commerciale binaria di UNIX su macchine PDP-11, proposto sul mercato da alcune società partner, tra cui la più autorevole era
la HCR (Human Computing Resources Corp.) di Toronto, Canada.
V. Asta - Introduzione a Unix e GNU/Linux
90
Interactive Systems Corp. commercializza PC/IX, una versione di System III che è
la prima implementazione di UNIX su IBM PC o compatibili.
1983:
Versione System V release 180, A partire dal mese di gennaio, AT&T amplifica
ulteriormente la sua politica commerciale, proponendo per la prima volta, insieme
alla licenza d’uso del sistema, contratti per prestazioni di installazione, assistenza e
aggiornamenti del software.
Berkeley pubblica la versione 4.2BSD per VAX, una delle più importanti, che vede
tra l’altro la prima implementazione dei protocolli di rete TCP/IP, finanziata dal
DARPA (Defense Advanced Research Projects Agency − un organismo
governativo americano per il sovvenzionamento dei progetti di ricerca, dipendente
dal Dipartimento della Difesa).
1984:
System V rel. 2
1985:
Nascono i primi standard di riferimento per UNIX; tra di essi, SVID (System V
Interface Definition) e X-OPEN
1986:
System V rel. 3.0; molti sistemi UNIX commerciali, tra cui SCO UNIX per
architettura IBM-PC, si basano su questa versione
4.3BSD
RFS (Remote File System - AT&T)
NFS (sviluppato dalla SUN, per BSD UNIX); STREAMS; IPC; COFF
POSIX 1.st draft (IEEE) - P1003
ANSI X3J11 C
1988:
System V rel. 3.2
1989:
System V rel. 4, versione che riunifica tutte le caratteristiche di System V e quelle
di Berkeley Unix.
1991:
Linus Torvalds, all’epoca studente di informatica all’università di Helsinki, inizia a
sviluppare LINUX, una riscrittura indipendente di UNIX, con l’intento di renderne
liberi i sorgenti; è rapidamente seguito da molte altre persone che collaborano al
progetto.
1994:
Versione 1.0 di LINUX
2001:
Versione 2.4 di LINUX
80.
La versione System IV non ha mai visto la luce al difuori dei Bell Laboratories.
V. Asta - Introduzione a Unix e GNU/Linux
91
APPENDICE B
La definizione di Free Software
Questa definizione è disponibile on-line come http://www.gnu.org/philosophy/free-sw.it.html
Cos’è il Software Libero?
Sosteniamo questa definizione di software libero per indicare chiaramente ciò che deve essere
vero di un particolare programma software perchè sia considerato software libero.
Il "Software libero" è una questione di libertà, non di prezzo. Per capire il concetto, bisognerebbe
pensare alla "libertà di parola" e non alla "birra gratis" [NdT: il termine "free" in inglese significa
sia "gratuito" che "libero", in italiano il problema non esiste].
L’espressione "software libero" si riferisce alla libertà dell’utente di eseguire, copiare, distribuire,
studiare, cambiare e migliorare il software. Più precisamente, esso si riferisce a quattro tipi di
libertà per gli utenti del software:
— Libertà di eseguire il programma, per qualsiasi scopo (libertà 0).
— Libertà di studiare come funziona il programma e adattarlo alle proprie necessità (libertà 1).
L’accesso al codice sorgente ne è un prerequisito.
— Libertà di ridistribuire copie in modo da aiutare il prossimo (libertà 2).
— Libertà di migliorare il programma e distribuirne pubblicamente i miglioramenti, in modo
tale che tutta la comunità ne tragga beneficio (libertà 3). L’accesso al codice sorgente ne è
un prerequisito.
Un programma è software libero se l’utente ha tutte queste libertà. In particolare, se è libero di
ridistribuire copie, con o senza modifiche, gratis o addebitando delle spese di distribuzione a
chiunque ed ovunque. Essere liberi di fare queste cose significa (tra l’altro) che non bisogna
chiedere o pagare nessun permesso.
Bisogna anche avere la libertà di fare modifiche e usarle privatamente nel proprio lavoro o
divertimento senza doverlo dire a nessuno. Se si pubblicano le proprie modifiche, non si deve
essere tenuti a comunicarlo a qualcuno in particolare o in qualche modo particolare.
La libertà di usare un programma significa libertà per qualsiasi tipo di persona od organizzazione
di utilizzarlo su qualsiasi tipo di sistema informatico, per qualsiasi tipo di attività e senza dover
successivamente comunicare con lo sviluppatore o con qualche altra entità specifica.
La libertà di ridistribuire copie deve includere le forme binarie o eseguibili del programma e
anche il codice sorgente, sia per le versioni modificate che non modificate. È legittimo anche se
non c’è alcun modo di produrre una forma binaria o eseguibile (dal momento che alcuni linguaggi
non supportano questa caratteristica), ma si deve avere la libertà di ridistribuire tali forme nel caso
si trovi o si sviluppi un modo per farlo.
Affinchè le libertà di fare modifiche e di pubblicare versioni migliorate abbiano senso, si deve
avere accesso al codice sorgente del programma. Perciò, l’accessibilità al codice sorgente è una
condizione necessaria per il software libero.
Queste libertà per essere reali devono essere irrevocabili fin tanto che non si fa qualcosa di
sbagliato: se lo sviluppatore del software ha il potere di revocare la licenza anche senza che
l’utente sia causa di tale revoca, il software non è libero.
Tuttavia, certi tipi di regole sul come distribuire il software libero sono accettabili quando non
entrano in conflitto con le libertà principali. Per esempio, il permesso d’autore(1) è (detto in due
parole) la regola per cui, quando il programma è ridistribuito, non è possibile aggiungere
restrizioni per negare ad altre persone le libertà principali. Questa regola non entra in conflitto con
V. Asta - Introduzione a Unix e GNU/Linux
92
le libertà principali, anzi le protegge.
Indipendentemente dal fatto che si siano ottenute copie di software GNU a pagamento o
gratuitamente, si ha sempre la libertà di copiare e cambiare il software, e anche di venderne copie.
"Software libero" non vuol dire "non-commerciale". Un programma libero deve essere
disponibile per uso commerciale, sviluppo commerciale e distribuzione commerciale. Lo
sviluppo commerciale di software libero non è più inusuale: questo software commerciale libero è
molto importante.
Regole su come fare un pacchetto di una versione modificata sono accettabili, a meno che esse in
pratica non blocchino la libertà di distribuire versioni modificate. Regole del tipo "se rendi
disponibile il programma in questo modo, lo devi rendere disponibile anche in quell’altro modo"
possono essere pur esse accettabili, con le stesse condizioni. (Si noti che tale regola lascia ancora
aperta la possibilità di distribuire o meno il programma.) È anche accettabile che la licenza
richieda che, se avete distribuito una versione modificata e un precedente sviluppatore ne richiede
una copia, dobbiate inviargliene una.
Nel progetto GNU, noi usiamo il permesso d’autore per proteggere queste libertà legalmente per
tutti. Ma esiste anche software libero senza permesso d’autore. Crediamo che ci siano importanti
ragioni per cui sia meglio usare il permesso d’autore, ma se un programma è software libero
senza permesso d’autore, possiamo comunque utilizzarlo.
Si veda http://www.gnu.org/philosophy/categories.it.html (classificazione del software libero) per
una descrizione dei rapporti fra "software libero", "software con permesso d’autore" e altre
categorie di software.
Qualche volta le leggi sul controllo delle esportazioni e le sanzioni sul commercio possono
limitare la libertà di distribuire copie di programmi verso paesi esteri. I programmatori non
hanno il potere di eliminare o di aggirare queste restrizioni, ma quello che possono e devono fare
è rifiutare di imporle come condizioni d’uso del programma. In tal modo, le restrizioni non
influiranno sulle attività e sulle persone al di fuori della giurisdizione degli stati che applicano tali
restrizioni.
Quando si parla di software libero, è meglio evitare di usare espressioni come "gratuito", perchè
esse pongono l’attenzione sul prezzo, e non sulla libertà. Parole comuni quali "pirateria"
implicano
opinioni
che
speriamo
non
vogliate
sostenere.
Si
veda
http://www.gnu.org/philosophy/words-to-avoid.html (Confusing Words and Phrases that are
Worth Avoiding) per una discussione su queste parole. Abbiamo anche una lista di traduzioni in
varie lingue dell’espressione "software libero".
Infine, si noti che criteri come quelli indicati in questa definizione di software libero richiedono
un’attenta interpretazione. Per decidere se una determinata licenza software si qualifichi come
licenza per il software libero, noi la consideriamo basata su questi criteri al fine di determinare se
corrisponde al loro spirito così come alle precise parole. Se una licenza include restrizioni
irragionevoli, la rifiutiamo, anche se in questi criteri non anticipiamo il problema. Qualche volta
le richieste di una licenza sollevano un problema che richiede un’analisi dettaglia, oltre a
discussioni con un avvocato prima di poter decidere se la richiesta sia accettabile. Quando
raggiungiamo una conclusione riguardo ad un nuovo problema, spesso aggiorniamo questi criteri
per fare in modo che sia più facile capire perchè determinate licenze siano adeguate o meno.
Se siete interessati a sapere se una determinata licenza abbia le caratteristiche per essere una
licenza
di
software
libero,
consultate
il
nostro
elenco
delle
licenze
(http://www.gnu.org/licenses/license-list.it.html). Se la licenza che vi interessa non vi è elencata,
potete interpellarci inviandoci un’e-mail a [email protected].
(1) [NdT: si tratta di un gioco di parole, che qui viene reso con "permesso di autore": copyright
(diritto di autore) è formato dalle parola "copy" (copia) e "right" (diritto, ma anche destra),
opposto di "left" (sinistra, ma anche lasciato).]
V. Asta - Introduzione a Unix e GNU/Linux
93
Un altro gruppo ha cominciato ad utilizzare l’espressione "open source" per indicare un concetto
vicino (ma non identico) a quello di "software libero". Preferiamo l’espressione "software libero"
perchè, una volta sentito che si riferisce alla libertà piuttosto che al prezzo, richiama alla mente
l’idea di libertà.
Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111, USA
La copia letterale e la distribuzione di questo articolo nella sua integrità sono permesse con
qualsiasi mezzo, a condizione che questa nota sia riprodotta.
V. Asta - Introduzione a Unix e GNU/Linux
94
APPENDICE C
La definizione di Open Source
Questa definizione è disponibile on-line come http://www.opensource.org/docs/osd-italian.html
Definizione di Open Source - Versione 1.9
Le sezioni indentate e in corsivo qui sotto appaiono come note della definizione di Open Source
(OSD) e non sono una parte della OSD.
Introduzione
Open source (sorgente aperta) non significa semplicemente accesso al codice sorgente. La
distribuzione in termini di programmi open-source deve soddisfare i seguenti criteri:
1.
Ridistribuzione Libera e Gratuita
Le licenze non potranno limitare alcuno dal vendere o donare i programmi come
componenti di una distribuzione aggregata di software contenenti programmi di varia
origine. La licenza non potrà richiedere royalties o altri pagamenti per tali vendite.
Motivo: Imponendo la licenza a richiedere una ridistribuzione libera e gratuita,
eliminiamo la tentazione di gettare alle ortiche molti guadagni di lungo periodo per
fare qualche lira di breve periodo con le vendite. Se non lo facessimo ci sarebbe
una forte pressione all’abbandono sui collaboratori.
2.
Codice Sorgente
Il programma deve includere il codice sorgente, e deve permetterne la distribuzione così
come per la forma compilata. Dove alcune forme di un prodotto non sono distribuite con
codice sorgente, ci deve essere un modo ben pubblicizzato di ottenerne il codice sorgente
per niente più di una ragionevole riproduzione; preferibilmente, per via dei costi,
scaricandolo da Internet gratis. Il codice sorgente deve essere la forma preferita in cui un
programmatore modificherebbe il programma. Codice sorgente deliberatamente
obnubilato non è permesso. Forme intermedie come l’output di un preprocessore o
traduttore non sono permesse.
Motivo: Richiediamo accesso al codice sorgente in chiaro perchè non puoi
migliorare i programmi senza modificarli. Siccome il nostro obiettivo è rendere
l’evoluzione facile, richiediamo che le modifiche siano facilitate.
3.
Prodotti Derivati
La licenza deve permettere modifiche e prodotti derivati, e deve permettere loro di essere
distribuiti sotto le stesse condizioni della licenza del software originale.
Motivo: La sola possibilità di leggere il codice non è abbastanza per sostenere un
confronto paritario e una selezione evolutiva rapida. Per far avvenire questa
rapida evoluzione, la gente deve poter sperimentare con le modifiche e
redistribuirle.
4.
Integrità del Codice Sorgente dell’Autore
La licenza potrà impedire il codice sorgente dall’essere redistribuito in forma modificata
solo se la licenza consentirà la distribuzione di pezze ("patch files") con il codice sorgente
V. Asta - Introduzione a Unix e GNU/Linux
95
al fine di modificare il programma all’installazione. La licenza deve esplicitamente
permettere la distribuzione del software costruito da un diverso codice sorgente. La
licenza può richiedere che i lavori derivati abbiano un nome diverso o versione diversa dal
software originale.
Motivo: Incoraggiare il miglioramento è bene, ma gli utenti hanno diritto di sapere
chi è responsabile del software che stanno usando. Gli autori e i tecnici hanno
diritto reciproco di sapere cosa è loro chiesto di supportare e di proteggere la loro
reputazione.
Perciò, una licenza open-source deve garantire che il codice sorgente sia
prontamente disponibile, ma può richiedere che esso sia distribuito come sorgente
originale di base più le pezze. In questo modo, i cambiamenti "non ufficiali"
possono essere disponibili ma prontamente distinti dal codice di base.
5.
Nessuna Discriminazione contro Persone o Gruppi
La licenza non deve discriminare alcuna persona o gruppo di persone.
Motivo: Per ottenere il massimo beneficio dal processo, la massima diversità di
persone e gruppi deve avere eguale possibilità a contribuire ai codici sorgente.
Quindi proibiamo qualsiasi licenza open-source dall’escludere chiunque dal
processo.
Alcuni paesi, inclusi gli Stati Uniti, hanno restrizioni alle esportazioni per certi tipi
di software. Una licenza conforme all’OSD può avvertire i licenziati di restrizioni
applicabili e ricordare loro che sono obbligati a rispettare la legge; comunque, non
potrà incorporare tali restrizioni essa stessa.
6.
Nessuna Discriminazione contro Campi d’Applicazione
La licenza non deve impedire ad alcuno da far uso del programma in un ambito specifico.
Per esempio, non potrà impedire l’uso del programma nell’ambito di un’impresa, o
nell’ambito della ricerca genetica.
Motivo: La prima intenzione di questa clausola è di proibire trappole nella licenza
che impediscano all’open-source di essere usato commercialmente. Vogliamo che
gli utenti commerciali si uniscano alla nostra comunità, non che se ne sentano
esclusi.
7.
Distribuzione della Licenza
I diritti allegati a un programma devono valere a tutti coloro cui il programma è
redistribuito senza necessità dell’emissione di una addizionale licenza da parte dei
licenziatari.
Motivo: Questa clausola intende proibire la chiusura del software per mezzi
indiretti come una richiesta di un accordo di non diffusione.
8.
La Licenza non deve essere Specifica a un Prodotto
I diritti allegati al programma non devono dipendere dall’essere il programmma parte di
una particolare distribuzione di software. Se il programma è estratto da quella
distribuzione e usato o distribuito all’interno dei termini delle licenze del programma, tutte
le parti cui il programma è ridistribuito dovranno avere gli stessi diritti che sono garantiti
nel caso della distribuzione di software originale.
Motivo: Questa clausola impedisce ancora un’altra classe di licenze-trappola.
V. Asta - Introduzione a Unix e GNU/Linux
96
9.
La Licenza non deve Porre Vincoli su Altro Software
La licenza non deve porre restrizioni su altro software che è distribuito insieme al software
licenziato. Per esempio, la licenza non dovrà insistere che tutti gli altri programmi
distribuiti sugli stessi supporti siano software open-source.
Motivo: I distributori di software open-source hanno il diritto di fare le loro scelte
riguardo al loro software.
Sì, la GPL è conforme con questo requisito. Il software collegato con librerie a
licenza GPL eredita la GPL solo se forma un solo prodotto, non ogni software con
cui è semplicemente distribuito.
V. Asta - Introduzione a Unix e GNU/Linux
97
APPENDICE D
Alcuni comandi notevoli
1. Il comando test
1.1 Sintassi generale
test <expr>
test valuta <expr>, che è un’espressione booleana costruita con gli operatori unari e binari descritti nel
seguito, e rinvia come codice d’uscita il risultato di questa valutazione:
- ritorna 0 se <expr> è vera
- ritorna 1 se <expr> è falsa
- ritorna 2 se <expr> è mal formata (errore di sintassi).
test chiamato senza argomento ritorna 1.
Il programma ha un alias, consistente in una parentesi quadra aperta: [ . Per correttezza sintattica dal punto
di vista della shell, un eventuale ultimo argomento consistente in una parentesi quadra chiusa viene
ignorato dal programma, sicchè le due forme seguenti sono equivalenti:
if test $PAR = string
if [ $PAR = string ]
Segue una lista dei principali operatori.
1.2 Test su dei file
test -e <file>
vero se il file <file> esiste
test -r <file>
vero se il file <file> esiste ed è accessibile in lettura.
test -w <file>
vero se il file <file> esiste ed è accessibile in scrittura.
test -x <file>
vero se il file <file> esiste ed è accessibile in esecuzione.
test -f <file>
vero se il file <file> esiste ed è un file regolare.
test -d <file>
vero se il file <file> esiste ed è una directory.
test -c <file>
vero se il file <file> esiste ed è uno special file in modo carattere.
test -b <file>
vero se il file <file> esiste ed è uno special file in modo blocco.
test -p <file>
vero se il file <file> esiste ed è un named pipe.
test -L <file>
vero se il file <file> esiste ed è un link simbolico.
test -s <file>
vero se il file <file> esiste ed è di lunghezza superiore a 0 byte.
test <file1> -ef <file2> vero se i file <file1> e <file2> sono lo stesso file (stesso file-system e stesso inumber) ("equal file")
test -t <fildes>
vero se <fildes> è il file descriptor di un terminale.
1.3 Test sulle stringhe
V. Asta - Introduzione a Unix e GNU/Linux
98
test -z <s1>
vero se la stringa <s1> è vuota (ha una lunghezza di 0 byte).
test -n <s1>
vero se la stringa <s1> non è vuota .
test <s1> = <s2>
vero se le due stringhe <s1> ed <s2> sono identiche.
test <s1> != <s2>
vero se le stringhe <s1> ed <s2> sono differenti.
test <s1>
vero se la stringa <s1> non è quella nulla.
1.4 Test sui numeri
test <n1> -eq <n2>
verifica se <n1> è uguale ad <n2>, essendo queste due stringhe di carattere
interpretate come due numeri decimali.
test <n1> -ne <n2>
verifica se la stringa <n1> è diversa da <n2>
test <n1> -gt <n2>
verifica se la stringa <n1> è superiore a <n2>.
test <n1> -lt <n2>
verifica se la stringa <n1> è inferiore a <n2>
test <n1> -ge <n2>
verifica se la stringa <n1> è superiore o uguale ad <n2>
test <n1> -le <n2>
verifica se la stringa <n1> è inferiore o uguale ad <n2>.
1.5 Combinazioni di primitive
É possibile combinare tutte queste primitive tramite gli operatori:
— !
negazione
— -a
and logico
— -o
or logico
— ( expr )
Note:
per raggruppare logicamente più test.
— L’operatore -a ha maggiore priorità di -o .
— Ogni primitiva, operatore o operando deve costituire un singolo token per la shell, dunque deve
essere separato da spazi.
— Le parentesi devono essere quotate per evitare che la shell le interpreti.
2. Il comando find
2.1 Sintassi generale
find <path-name> <expr>
find cerca ricorsivamente path-name nella struttura ad albero, secondo quanto specificato in expr. In expr è
possibile precisare sia delle direttive di selezione, sia delle azioni da eseguire su ogni file selezionato.
2.2 I criteri di ricerca
-name <pattern>
seleziona unicamente i file il cui nome seleziona il pattern.
N.B. - il pattern deve essere interpretato dal comando find e non dalla shell.
-name ’*.c’
la shell non effettua alcuna operazione e find cercherà nella struttura ad albero i
file che selezionano *.c
Esempio :
find /home/pippo -name ’*.c’ -print
V. Asta - Introduzione a Unix e GNU/Linux
99
-perm <numero ottale> seleziona i file di cui i diritti di accesso sono esattamente quelli indicati dal
numero ottale.
Esempio :
find /home/pippo -perm 0777 -print
... stampa tutti i file che sono autorizzati in read, write ed execute per l’utente, le
persone del suo gruppo e tutti gli altri.
-type <carattere>
seleziona i file il cui tipo è quello indicato dal carattere, vale a dire :
- c per un file speciale di tipo carattere
- b per un file speciale di tipo blocco
- p per un file named pipe
- l per un file link simbolico
- d per una directory
- f per un file normale
Esempio :
find /home/pippo -type d -print
...stamperà tutte le directory e le sotto-directory dell’utente pippo.
-links <numero decimale> seleziona tutti i file di cui il numero di link è dato dal numero decimale. Se il
numero è preceduto da un + o da un -, questo significa qualunque valore superiore
(o inferiore) al numero dato.
Esempio :
find /home/pippo -link +2 -print
...stamperà tutti i file che hanno più di due link.
-group < gruppo>
seleziona i file che appartengono al gruppo <gruppo>.
Esempio:
find /dev -group other -print
...stamperà tutti i file speciali appartenenti al gruppo other.
-user <utente>
seleziona i file di cui l’utente proprietario è <utente>.
Esempio :
find /dev -user pippo -print
...stamperà tutti i file speciali appartenenti a pippo.
-size <numero decimale> seleziona i file la cui grandezza è di <numero decimale> blocchi.
-inum <numero decimale> seleziona i file aventi <numero decimale> per i-number
-atime <numero decimale> seleziona i file che sono stati utilizzati negli <numero decimale> ultimi giorni.
Esempio :
find /home/pippo -atime -2 -print
-mtime <numero decimale> seleziona i file che sono stati modificati negli <numero decimale> ultimi
giorni.
-newer <file>
seleziona i file che sono più recenti di quello passato in argomento.
V. Asta - Introduzione a Unix e GNU/Linux
100
2.3 Combinazione di criteri
Alcuni di questi caratteri possono essere raggruppati dagli operatori ( e ) .
Attenzione: ( e), essendo dei caratteri speciali per la shell, devono essere quotati.
Se più criteri sono messi in serie, find seleziona i file che rispondono a tutti i criteri. Lo "and logico" è
dunque implicito.
Esempio :
find /home/pippo \( -name ’*.c’ -mtime -3 \) -print
... stamperà i file che terminano per .c e modificati negli ultimi tre giorni.
Lo ’or logico’ è rappresentato dall’operatore -o.
Esempio :
find /home/pippo \( -name ’*.txt’ -o -name -’*.doc’ \) -print
... stamperà tutti i file che terminano per .txt o .doc
Il ’not logico’ è l’operatore !
Esempio :
find /home/gianni ! -user gianni -print
... stamperà tutti i file che non appartengono a gianni, ma che si trovano nella struttura ad albero sotto la sua
home directory.
2.4 Le azioni possibili sui file selezionati
-print
stampa il nome dei file selezionati sull’uscita standard; questa è l’azione di default.
Esempio:
find /home/pippo -print
... stamperà tutta la struttura ad albero.
-exec <comando>
esegue il comando <comando> su tutti i file selezionati. <comando> deve essere
della forma: <comando shell> ;
Nel comando shell, {} sarà sostituito dal nome del file selezionato.
Esempio :
find /home/pippo -name ’*.txt’ -exec cat {} \;
... stamperà il contenuto di tutti i file che terminano per .txt in tutta la struttura ad
albero /home/pippo.
-ok <comando>
stessa cosa di -exec, ma richiede conferma prima di ogni esecuzione.
Esempio :
find /home/pippo -name ’*.save’ -ok rm {} \;
... distruggerà (o no) ogni file che termina per .save, nella struttura ad albero
/home/pippo, dopo aver richiesto conferma.
2.5 Un ultimo esempio
find / \( -name a.out -o -name ’*.o’ \) -atime +7 -exec rm -f {} \;
find cerca a partire dalla radice "/" tutti i file il cui nome è a.out, o che terminano per ".o". Se in più questi
file non sono stati aperti da sette giorni, find lancerà il comando rm su questi file.
V. Asta - Introduzione a Unix e GNU/Linux
101
APPENDICE E
Espressioni Regolari
1. Espressioni regolari di tipo ed
Le espressioni regolari sono definite da 11 regole.
Un carattere designa, nelle regole seguenti, qualsiasi carattere, salvo <newline>.
1.
Tutti i caratteri, salvo quelli speciali, selezionano se stessi.
I seguenti caratteri sono speciali:
/\[.ˆ$*]
- ˆ è un carattere speciale solo se è posto all’inizio del pattern o se segue immediatamente [
- $ è un carattere speciale solo se è posto a fine pattern
- * è un carattere speciale solo se segue un pattern
- ] è un carattere speciale solo se c’è stata un’apertura [
2.
Un punto seleziona qualsiasi carattere.
3.
Un \ seguito da un qualsiasi carattere eccetto ( e ) seleziona questo carattere (anche se è speciale).
4.
Una stringa s non vuota entro [s] o [ˆs] seleziona qualsiasi carattere di questa stringa (o salvo quelli
della stringa). Nella stringa s, \ non ha alcun valore speciale, non si possono dunque quotare dei
caratteri. Per integrare ] alla stringa bisognerà porla in prima posizione. Una stringa a-b, dove <a> e
<b> sono classificate in ordine ASCII crescente, designa l’intervallo che include quei caratteri
ASCII.
5.
Una espressione regolare della forma da 1 a 4 seguita da* selezionerà una sequenza da 0 a n
caratteri, selezionati dall’espressione regolare. Dato che espressioni regolari definite dalle regole da
1 a 4 selezionano un solo carattere, * opera una ripetizione solo sul carattere precedentemente
selezionato.
6.
Per una espressione regolare x definita dalle regole da 1 a 8, \(x\) selezionerà ciò che x seleziona.
7.
Un \ seguito da una cifra <n> seleziona ciò che l’espressione regolare che inizia all’n-ma \( ha
selezionato.
Per esempio, \([a-z]\1 selezionerà "rr" se \([a-z]\) ha selezionato "r"
8.
Una espressione regolare x, definita dalle regole da 1 a 8 seguita da un’espressione regolare y,
definita dalle regole da 1 a 7 selezionerà ciò che seleziona x, seguito da ciò che seleziona y, essendo
inteso che ciò che seleziona x dovrà essere più lungo possibile, senza impedire ad y di selezionare.
9.
Una espressione regolare definita dalle regole da 1 a 8 e preceduta da ˆ o seguita da $ deve
selezionare all’inizio o alla fine della riga.
10.
Una espressione regolare definita dalle regole da 1 a 9 seleziona più caratteri possibili cominciando
da sinistra.
11.
Una espressione regolare vuota designerà l’ultima espressione regolare utilizzata.
un’espressione regolare vuota).
(// è
2. grep fgrep egrep
grep e la sua famiglia sono dei programmi che ricercano una stringa di caratteri nelle righe di uno o più
files.
V. Asta - Introduzione a Unix e GNU/Linux
102
— fgrep seleziona unicamente delle stringhe costanti.
— grep seleziona delle espressioni regolari di tipo ed.
— egrep seleziona delle espressioni regolari più complesse di ed.
3. Espressioni regolari di tipo egrep
Un carattere seleziona qualunque carattere ad eccezione di <newline>.
1.
Un \ seguito da un carattere seleziona questo carattere.
2.
Un ˆ o $ seleziona l’inizio o la fine di una riga.
3.
Un . seleziona qualsiasi carattere.
4.
Tutti i caratteri ad eccezione di quelli speciali selezionano se stessi.
5.
Una stringa tra parentesi quadre [] seleziona qualsiasi carattere di questa stringa.
Un intervallo di caratteri di valore ASCII crescente può essere abbreviato da - (per esempio [a-z]).
Un ] deve essere messo immediatamente dopo [ per poter essere incluso nell’intervallo.
6.
Un’espressione regolare, seguita da * (+ ?) seleziona una sequenza da 0 a n (1 a n, 0 o 1) caratteri
selezionati da questa espressione.
7.
Due espressioni regolari concatenate selezionano ciò che è selezionato dalla prima, seguito da ciò
che seleziona la seconda.
8.
Due espressioni regolari separate da | o da un <newline> selezionano ciò che seleziona la prima, o
ciò che seleziona la seconda.
9.
Un’espressione regolare tra () seleziona ciò che seleziona questa espressione regolare.
10.
L’ordine di precedenza degli operatori, per uno stesso livello di parentesi è:
[]
*+?
concatenazione
| e <newline>
V. Asta - Introduzione a Unix e GNU/Linux
103
BIBLIOGRAFIA
— [Asta 1982] V. Asta, "UNIX Utilisation", Axis Digital, Editions LASER 1982 / 1995
— [Asta 1984] V. Asta, "Administration UNIX", Axis Digital, Boulogne 1984 / 1992
— [Bach 1986] M. Bach, "The Design of the Unix Operating System", Prentice-Hall 1986
— [Behlendorf 1999] B. Behlendorf, "Open Source as a Business Strategy", in [DiBona et al. 1999]
— [Bernardini2001] N. Bernardini, comunicazione privata, Roma 2001
— [Bovet e Cesati 2001] D.P. Bovet - M. Cesati, "Understanding the Linux Kernel", O’Reilly 2001
— [BSTJ 1978] AA.VV., "Unix Time-Sharing System", The Bell System Technical Journal, vol. 57 n. 6
part 2, Luglio-Agosto 1978
— [BSTJ 1984] AA.VV., "The Unix System", The Bell System Technical Journal, vol. 63 n. 8 part 2,
Ottobre 1984
— [Cooper 2002] M. Cooper, "Advanced Bash-Scripting Guide", vers. 1.2, marzo 2002 (disponibile online come http://personal.riverusers.com/ thegrendel/abs-guide-1.2.tar.gz)
— [Cortiana 2002] F. Cortiana, proposta di legge "Norme in materia di pluralismo informatico
sull’adozione e la diffusione del software libero e sulla portabilità dei documenti informatici nella
pubblica amministrazione" (XIV Legislatura Atto Senato n. 1188) (disponibile on-line come
http://www.nwork.it/documento.asp?id=233 ; http://www.softwarelibero.it/altri/cortiana.shtml), 2002
— [Dalle e Jullien 2000] J.M. Dalle - N. Jullien, "NT vs. Linux, or Some Explorations into the
Economics of Free Software", in Ballot G., Weisbuch G. (editors), Application of simulation to social
sciences, Hermès, Paris, pp. 399-416
— [DiBona et al. 1999] C. DiBona - S. Ockman - M. Stone (editors), "Open Sources - Voices from the
Open
Source
Revolution",
O’Reilly
1999
(disponibile
on-line
come
http://www.oreilly.com/catalog/opensources/book/toc.html)
— [Garzarelli 2002] G. Garzarelli, "The Pure Convergence of Knowledge and Rights in Economic
Organization: the Case of Open Source Software Development", DRUID Summer Conference on
"Industrial Dynamics of the New and Old Economy - Who is Embracing Whom?" Copenhagen/Elsinore 6-8 June 2002
— [Giacomini 2002] D. Giacomini, "Appunti di Informatica Libera", versione 2002.03.10 (disponibile
on-line come http://a2.swlibero.org)
— [Grasso 2002] F. Grasso, "Il Software Open Source (OSS) - Scenario e Prospettive", rapporto AIPA
(Autorità per l’Informatica nella Pubblica Amministrazione) (disponibile on-line come
http://www.aipa.it/servizi[3/notizie[2/scenariooss.pdf )
— [Johnson e Ritchie 1978] S.C. Johnson - D.M. Ritchie, "Portability of C Programs and the Unix
System," in [BSTJ 1978]
— [Kernighan e Pike 1984] B.W. Kernighan - R. Pike, "The UNIX Programming Environment",
Prentice-Hall 1984
— [Kuan 2001] J. Kuan, "Open Source Software as Consumer Integration Into Production", rapporto
dello
Institute
for
Economic
Policy
Research
Stanford
University,
http://papers.ssrn.com/sol3/papers.cfm?abstract_id=259648
— [Lohr 2002] S. Lohr, "An alternative to Microsoft gains support in high places", New York Times, 5
settembre
2002
(abstract
disponibile
on-line
come
http://query.nytimes.com/search/abstract?res=F30B1FF83F5A0C768CDDA00894DA404482;
articolo intero disponibile come http://www.axdigital.com/ vito/nytimes_linux.html)
V. Asta - Introduzione a Unix e GNU/Linux
104
— [Maxwell 1999] S.E. Maxwell, "Linux Core Kernel Commentary", Coriolis Group 1999
— [McKusick 1999] M.K. McKusick, "Twenty years of Berkeley UNIX", in [DiBona et al. 1999]
— [Nutt 2001] G. Nutt, "Kernel Projects for Linux", Addison Wesley 2001
— [Potortì
2002]
F.
Potortì,
"Cos’è
il
http://softwarelibero.it/documentazione/softwarelibero.html , 2002
software
libero",
— [Raymond
1997]
E.S.
Raymond,
"The
Cathedral
&
the
Bazaar",
http://tuxedo.org/ esr/writings/cathedral-bazaar/cathedral-bazaar/ , 1997-2000, ristampato in
[Raymond 2001]; trad. it. in http://www.apogeonline.com/openpress/doc/cathedral.html
— [Raymond 2001] E.S. Raymond, "The Cathedral & the Bazaar - Musings on Linux and Open Source
by an Accidental Revolutionary", Revised Edition, O’Reilly 2001
— [Ritchie 1979] D. Ritchie, "The Unix I/O System", in Unix Programmer’s Manual, 7. Edition, 1979
— [Rubini e Corbet 2001] A. Rubini - J. Corbet, "Linux Device Drivers", 2. Edition, O’Reilly 2001
— [Silberschatz, Galvin e Gagne 2003] A. Silberschatz - P.B. Galvin - G. Gagne, "Operating System
Concepts", 6. Edition, Addison Wesley 2003, cap. 20 e Appendice A
— [Thompson 1978] K. Thompson, "Unix implementation", The Bell Systems Technical Journal, vol.
57 n. 6 part 2, July-August 1978, pag. 1931-1946
— [Torvalds 1999] L. Torvalds, "The Linux Edge", in [DiBona et al. 1999]
— [Valloppillil 1998] V. Valloppillil, "Open Source Software, a (new?) Development Methodology",
Microsoft report, http://www.opensource.org/halloween/halloween1.html
— M. Welsh, M.K. Dalheimer, T. Dawson, L. Kaufman, "Running Linux", 4. Edition, O’Reilly 2002
— [Wirzenius et al. 2001] L. Wirzenius - J. Oja - S. Stafford, "The Linux System Administrators’
Guide", vers. 0.7, novembre 2001 (disponibile on-line come http://people.debian.org/ bagpuss/ )
V. Asta - Introduzione a Unix e GNU/Linux
105
INDICE
Principali Revisioni
............................................................................................................................
2
1.
Introduzione .......................................................................................................................................
1.1 Storia .........................................................................................................................................
1.2 Caratteristiche generali del kernel ............................................................................................
1.3 Tipi di UNIX ..............................................................................................................................
1.4 Utilità dello studio di LINUX ....................................................................................................
1.5 Il fenomeno del Software Libero ............................................................................................
1.6 Tipi di distribuzioni di GNU/LINUX ........................................................................................
3
3
4
9
9
10
19
2.
Come iniziare ...................................................................................................................................
2.1 Login .......................................................................................................................................
2.2 La manualistica on-line ...........................................................................................................
2.3 Utilizzazione del terminale .....................................................................................................
2.4 Primi comandi .........................................................................................................................
2.5 Primi file di sistema ................................................................................................................
20
20
20
21
23
25
3.
L’interprete di comandi - 1 .............................................................................................................. 27
3.1 Separatore di comandi ............................................................................................................ 28
3.2 Ridirezione delle uscite verso un file ...................................................................................... 28
3.3 Ridirezione dell’ingresso standard a partire da un file ........................................................... 29
3.4 Pipe: comunicazione tra processi ............................................................................................ 30
3.5 Classificazione dei comandi ................................................................................................... 31
3.6 I processi in background ......................................................................................................... 31
3.7 Caratteri speciali ..................................................................................................................... 33
4.
Sintassi dei comandi ........................................................................................................................
4.1 Comandi semplici ...................................................................................................................
4.2 Pipeline ...................................................................................................................................
4.3 Liste ........................................................................................................................................
4.4 Comandi ..................................................................................................................................
35
35
35
35
37
5.
L’interprete di comandi - 2 ..............................................................................................................
5.1 Funzionamento generale .........................................................................................................
5.2 Il Prompt .................................................................................................................................
5.3 Quoting ...................................................................................................................................
5.4 Assegnazione e sostituzioni di variabili ..................................................................................
5.5 Sostituzione di comandi ..........................................................................................................
5.6 Sostituzione dei nomi di file ...................................................................................................
5.7 Comandi speciali ....................................................................................................................
5.8 Controllo degli ingressi/uscite ................................................................................................
5.9 Costruzione di una tavola di argomenti ..................................................................................
5.10 Esecuzione di un comando .....................................................................................................
5.11 Chiamata .................................................................................................................................
5.12 Ambiente (environment) .........................................................................................................
5.13 Segnali ....................................................................................................................................
42
42
42
42
43
45
46
46
50
51
52
52
53
53
6.
Ricapitolativo della shell: comportamento e sintassi
.......................................................................
54
7.
Comandi di uso corrente ..................................................................................................................
7.1 Manipolazione di file e directory ............................................................................................
7.2 Informazioni su file e directory ...............................................................................................
56
56
56
i
7.3
7.4
7.5
7.6
7.7
7.8
7.9
Manipolazione delle informazioni su file e directory .............................................................
Visualizzazione del contenuto di file ......................................................................................
Informazioni sul contenuto di file ...........................................................................................
Manipolazione del contenuto di file .......................................................................................
Modifica del contenuto di file .................................................................................................
Comandi di utilità per shell script ...........................................................................................
Comandi generici ....................................................................................................................
56
57
58
58
58
59
59
8.
Gli utenti speciali .............................................................................................................................
8.1 root ..........................................................................................................................................
8.2 bin ...........................................................................................................................................
8.3 daemon ....................................................................................................................................
8.4 Gli altri utenti speciali ............................................................................................................
61
61
61
62
62
9.
I file speciali ..................................................................................................................................... 63
9.1 Cosa è un file speciale ............................................................................................................. 63
9.2 Device e pseudo-device .......................................................................................................... 66
10. Organizzazione dei filesystems di UNIX ..........................................................................................
10.1 Il sistema di file .......................................................................................................................
10.2 Implementazione del filesystem .............................................................................................
10.3 File systems montati ...............................................................................................................
67
67
72
77
11. Avvio del sistema
.............................................................................................................................
78
12. Il programma init
.............................................................................................................................
81
APPENDICE A: Cronologia dettagliata di UNIX
...................................................................................
87
APPENDICE B: La definizione di Free Software
..................................................................................
92
APPENDICE C: La definizione di Open Source
....................................................................................
95
.............................................................................................
98
1.
Il comando test .................................................................................................................................
1.1 Sintassi generale .....................................................................................................................
1.2 Test su dei file .........................................................................................................................
1.3 Test sulle stringhe ...................................................................................................................
1.4 Test sui numeri ........................................................................................................................
1.5 Combinazioni di primitive ......................................................................................................
98
98
98
98
99
99
2.
Il comando find ................................................................................................................................ 99
2.1 Sintassi generale ..................................................................................................................... 99
2.2 I criteri di ricerca .................................................................................................................... 99
2.3 Combinazione di criteri ........................................................................................................ 101
2.4 Le azioni possibili sui file selezionati ................................................................................... 101
2.5 Un ultimo esempio ................................................................................................................ 101
APPENDICE D: Alcuni comandi notevoli
APPENDICE E: Espressioni Regolari
..................................................................................................
102
.......................................................................................................
102
1.
Espressioni regolari di tipo ed
2.
grep fgrep egrep
.............................................................................................................................
102
3.
Espressioni regolari di tipo egrep ..................................................................................................
BIBLIOGRAFIA ...........................................................................................................................
103
104
ii