Introduzione a Unix: un po’ di storia
C. Baroglio∗
a.a. 2002–2003
Il sistema operativo utilizzato nella parte di laboratorio del corso intitolato
“Sistemi Operativi e Sperimentazioni” è Unix. Unix è nato nel 1969, questo
significa che noi lo studieremo nel corso del suo trentaquattresimo anno di esistenza e di evoluzione. Studiare uno strumento che esiste da tanto tempo,
sopravvivendo a molti antagonisti, e ritrovando negli ultimi anni un nuovo impulso di affermazione (grazie alle varie distribuzioni Linux e al lavoro di molti
affezionati sparsi un po’ ovunque nel mondo), è un compito interessante sia per
motivi tecnico-scientifici (quali caratteristiche rendono Unix cosı̀ popolare come
sistema operativo?) sia perché qualcuno potrebbe un giorno di questi farvi la
domanda “ma tu usi già Linux?” (come è successo a me pochi mesi fa) ed allora
voi potrete divertirvi a raccontare alla persona in questione l’interessante storia
di questo strumento.
Spesso nella storia una cosa importante nasce a seguito di un evento che di
per sè non sarebbe mai assurto agli onori della cronaca. Nel caso del nostro
sistema operativo, nella seconda metà degli anni sessanta del secolo scorso, il
signor Ken Thompson –ricercatore presso i Bell Labs della AT&T– scrisse il
programma di un gioco: Space Travel. A quell’epoca i Bell Labs erano coinvolti
in un progetto finalizzato alla realizzazione di un sistema operativo chiamato
Multics, per un mainframe GE645 (della General Electrics). L’esecuzione del
gioco sul GE645 avveniva però a scatti ed era molto costosa. Di qui l’esigenza di
sviluppare un supporto diverso. Thompson e alcuni suoi colleghi (fra cui Dennis
Ritchie) svilupparono un nuovo sistema operativo multi-tasking, che sfruttava
una gestione del file system innovativa e comprendeva un interprete di comandi
ed alcune utility, per un altro tipo di computer: il DEC PDP-7. Brian Kernighan
lo battezzò UNICS (Uniplexed Information and Computing System), poco dopo
sintetizzato in Unix. Molte idee implementate in quella versione si sono rivelate
vincenti, tanto da essersi mantenute inalterate fino ai giorni nostri.
Un po’ in sordina e con scarsi finanziamenti, l’avventura continuò. L’anno
successivo venne sviluppato un programma di formattazione del testo (antesignano da un lato dei moderni pacchetti Office, dall’altro di linguaggi di formattazione come LaTeX –usato per esempio per scrivere queste note– e HTML)
∗ Fonte: UNIX la guida completa, di K. Rosen, D. Host, J. Farber e R. Rosinski, McGrawHill, 1999.
1
chiamato runoff. Il successore di runoff, troff, fu il primo programma mai sviluppato per la pubblicazione elettronica.
Altra data importante nella storia di Unix è il 1973: in quell’anno Thompson e Ritchie riscrissero il kernel in un linguaggio di programmazione di alto
livello, il C (un linguaggio ideato dallo stesso Ritchie e da Kernighan). Un’idea
innovativa, in quanto fino ad allora tutti i sistemi operativi erano scritti in linguaggio assembly, e al contempo geniale in quanto rese questo sistema operativo
facilmente mantenibile e, soprattutto, ampiamente portabile. Un parallelo più
recente può essere fatto con il linguaggio Java, che avete studiato, il cui successo
sta in parte proprio nella sua portabilità.
L’infanzia di Unix comprende un’ultima innovazione portante: l’introduzione
di uno strumento che consente di collegare più utility, inviando l’output dell’una
in input all’altra. Tale strumento (che studieremo) si chiama pipe.
Nel 1982, all’età di tredici anni Unix, fino ad allora utilizzato solo in ambiente
universitario, divenne un prodotto commerciale, regolarmente distribuito da
At&T. L’unico problema era che a quel punto esistevano diverse versioni di
Unix, sviluppate a partire dal codice originario da centri di ricerca indipendenti.
At&T sviluppò nel 1983 Unix System V, Release 1 impegnandosi da quel momento
in avanti a mantenere la compatibilità. In altri termini tutto ciò che girava
in System V, Release 1 avrebbe dovuto rimanere eseguibile per sempre nelle
versioni successive di Unix.
Fra gli spin-off prodotti da questa avventura occorre ricordare BSD (Berckley
Software Distribution) e XENIX. BSD è un figlio di Unix nato all’Università di
Berckley, su richiesta del DARPA (Dipartimento della Difesa) che lo adottò
quale proprio sistema operativo. William Joy, uno degli autori di BSD, fondò
di lı̀ a poco Sun Microsystems, dove venne realizzata la versione di Unix nota
come Sun OS e poi sviluppatasi in Solaris. XENIX nacque nel 1980 ad opera
di Microsoft. Il maggior contributo di questa distribuzione fu l’introduzione di
Unix nel mondo dei desktop. Fino ad allora, infatti, questo sistema operativo era
rimasto prerogativa di computer più grandi. In tempi più recenti si è sviluppato
Linux, la cui storia merita però un capitolo a sè.
Come conclusione a questa breve introduzione ricordiamo che se possiamo
utilizzare certi strumenti è perché ci sono persone che hanno avuto sia le idee sia
la costanza di portarle a frutto. Fra i molti che hanno contribuito a Unix alcuni
dei nomi più illustri sono: K. Thompson (iniziatore dell’avventura), D. Ritchie
(autore del linguaggio C), B. Kernighan (coatore di C e di awk), R. Canady
(coautore del file system), J. Ossanna (autore di troff), W. Joy (autore di vi,
della C shell –csh– e fondatore di Sun), D. Korn e S. Bourne (autore della korn
shell –ksh– e della bourne shell –bsh– rispettivamente), R. Stallman (autore di
emacs e fondatore della Free Software Foundation).
2
1
Caratteristiche principali
Il principio cardine che ha da sempre guidato lo sviluppo di Unix è che un sistema deve essere semplice, generale ed estendibile. La semplicità è fondamentale
perché semplifica la vita agli utilizzatori (e ottimizza il tempo necessario a svolgere i compiti che si prefiggono). La generalità è fondamentale perché conduce
a non legarsi mani e piedi ad una nicchia e consente di realizzare strumenti che
divengono una ricchezza condivisa da una popolazione ampia. L’estendibilità
è fondamentale perché base dell’evoluzione, e senza evoluzione ai sistemi non
rimane che l’oblio o al più una nota nei libri di storia dell’informatica. Questo
principio rifrasa una lezione molto importante di quella disciplina nota come
software engeneering, nella quale si insegna che nella realizzazione di programmi
occorre evitare di sviluppare sistemi monolitici, per tanti motivi: occupano
molto spazio, generalmente li si sfrutta per un minimo delle loro potenzialità e,
cosa peggiore, non possiamo riutilizzarne delle parti per risolvere problemi di
tipo diverso (noto problema del riuso del software).
Ecco alcuni esempi di come queste lezioni sono state applicate alla realizzazione di Unix. Un esempio di attenzione alla semplicità della soluzione adottata è dato dal file system: l’utente non ha bisogno di sapere su quale unità
disco è contenuto un file in quanto gli viene proposto un modello (una visione)
più astratto, che prescinde dalle complicazioni dovute all’hardware (uno dei
compiti per i quali i sistemi operativi vengono sviluppati). Inoltre le periferiche
(tastiera, monitor, ...) sono gestite alla stregua di file attraverso il meccanismo
dei flussi di dati, fra i quali standard input e standard output.
Per quel che riguarda la modularità l’utente ha a disposizione una vasta
libreria di piccoli programmi in grado di assolvere compiti molto specifici; tali
programmi possono essere composti per realizzare strumenti ad hoc tramite il
meccanismo dello standard input, standard output connessi dalle già citate pipe
(tutti argomenti che affronteremo in una lezione successiva). Oltre ad applicativi
specifici sono a disposizione anche linguaggi e interpreti specifici (per lavorare
su file di dati –awk, nawk–, per lanciare compilazioni complesse –make–, ...).
Per quel che riguarda l’interazione fra utente e sistema, possiamo immaginare un computer sul quale è installato Unix come organizzato a cipolla. L’utente
lavora in un ambiente chiamato shell (conchiglia o guscio). La shell funge da
interfaccia fra l’utente e il nucleo (kernel) del sistema operativo, il quale a sua
volta nasconde l’hardware. In Unix sono presenti diversi tipi di shell, fra questi:
sh, bsh, ksh, zsh, csh, tcsh, bash. Una shell è un ambiente di lavoro e un interprete di comandi ed è anche un linguaggio di programmazione, come vedremo.
La gestione degli utenti e del meccanismo delle shell è tale che è possible per
più utenti lavorare contemporaneamente su di una stessa macchina, addirittura
utilizzando finestre diverse aperte sullo stesso monitor. Questa è una caratteristica che differenzia Unix da altri sistemi operativi che sono multiutente però non
consentono a più utenti di utilizzare contemporaneamente (da remoto) un computer oppure ad un singolo utente di utilizzare contemporaneamente account
3
diversi su di uno stesso computer. Il tipo interazione privilegiato fra utente e
sistema è quello attraverso linea di comando. Questa caratteristica porta in sè
alcuni vantaggi e alcuni svantaggi. Il vantaggio è l’alto grado di flessibilità d’uso
del sistema. Lo svantaggio è che per utilizzare questo sistema operativo occorre
imparare a scrivere quel che vogliamo che faccia per noi nel linguaggio che sa
interpretare, non sempre intuitivo. Questo è uno dei motivi che ha frenato la
diffusione di Unix in ambienti non tecnologici (uffici, amministrazioni, imprese
commerciali, ...). Negli ultimi anni è stato compiuto un grosso sforzo per realizzare interfacce grafiche più intuitive e gradevoli (gnome e kde in primis), che
consentano un’interazione più agevole, tuttavia questo sviluppo non è avvenuto
nell’ottica di sostituire la linea di comando (e quindi perdere quella flessibilità
di cui si parlava).
Il kernel di Unix svolge le funzionalità tipiche di un sistema operativo, come
la gestione del file system, della memoria, l’interfacciamento con le periferiche
attraverso driver, la gestione degli utenti e cosı̀ via. L’utente può invocare
l’esecuzione di funzionalità di sistema operativo utilizzando un insieme di system
call quali fossero funzioni di libreria. Noi studieremo alcune di esse soffermandoci
in particolar modo sulle call per la gestione dei processi e sul pacchetto IPC
(inter-process communication).
Infine uno dei motivi del successo, dell’efficienza e dello sviluppo di questo
sistema operativo è che, per lo meno nella prima fase della sua vita, i codici
sorgenti sono stati resi disponibili a chiunque volesse realizzare una nuova versione del medesimo o semplicemente volesse realizzare una nuova funzionalità.
Il fatto di distribuire il codici sorgente dei programmi era prassi negli anni in cui
Unix si è sviluppato; è solo in tempi più recenti, con la diffusione capillare dei
computer negli uffici e nelle case e con il conseguente incremento di concorrenza
fra i produttori di software, che è nata l’idea di distribuire i soli eseguibili.
4