Standardizzazione dei Sistemi UNIX
Entro la fine degli anni '80, la grande varietà di implementazioni UNIX disponibili presentava anche degli svantaggi.
Alcune implementazioni UNIX erano basate su BSD, altre su System V, e alcune combinavano caratteristiche di entrambe le varianti. Inoltre, ogni fornitore commerciale aveva aggiunto funzionalità extra alla propria implementazione.
La conseguenza era che spostare software e personale da un'implementazione UNIX all'altra diventava sempre più difficile. Questa situazione creò una forte pressione per la standardizzazione del linguaggio di programmazione C e del sistema UNIX, affinché le applicazioni potessero essere più facilmente portate da un sistema all'altro. Ora esamineremo gli standard che ne sono derivati.
Storia e Standard del Linguaggio C
Nei i primi anni '80 il C esisteva da dieci anni ed era stato implementato su una vasta gamma di sistemi UNIX e su altri sistemi operativi.
Tra le varie implementazioni erano comparse piccole differenze, in parte perché alcuni aspetti del funzionamento del linguaggio non erano specificati nello standard de facto dell'epoca, il libro del 1978 di Kernighan e Ritchie, The C Programming Language (la sintassi più vecchia descritta in quel libro è talvolta chiamata C tradizionale o K&R C).
Inoltre, la comparsa del C++ nel 1985 mise in evidenza miglioramenti e aggiunte che potevano essere introdotti in C senza rompere i programmi esistenti, come i prototipi di funzione, l'assegnazione di strutture, i qualificatori di tipo (const e volatile), i tipi enumerati e la parola chiave void.
Questi fattori generarono una spinta verso la standardizzazione del C, culminata nel 1989 con l'approvazione dello standard ANSI C (X3.159‑1989), successivamente adottato nel 1990 come standard ISO (ISO/IEC 9899:1990).
Oltre a definire sintassi e semantica, lo standard descriveva il funzionamento della libreria standard C, che comprende le funzioni stdio, le funzioni di manipolazione delle stringhe, le funzioni matematiche, vari header e così via. Questa versione è solitamente nota come C89 o, meno comunemente, ISO C90, ed è descritta integralmente nella seconda edizione (1988) del libro di Kernighan e Ritchie.
Una revisione dello standard C fu adottata dall'ISO nel 1999 (ISO/IEC 9899:1999; vedi http://www.open-std.org/jtc1/sc22/wg14/www/standards).
Lo standard è comunemente indicato come C99 e introduce numerose modifiche al linguaggio e alla libreria standard, tra cui i tipi di dato long long e Boolean, i commenti in stile C++ (//), i puntatori restrict e gli array a lunghezza variabile.
Gli standard C sono indipendenti dai dettagli di qualsiasi sistema operativo; cioè non sono legati al sistema UNIX. Questo significa che i programmi C scritti usando solo la libreria standard C dovrebbero essere portabili su qualsiasi computer e sistema operativo che fornisca un'implementazione del C.
Storicamente, C89 era spesso chiamato ANSI C, e questo termine è talvolta ancora usato con quel significato. Per esempio,
gccutilizza questo significato; il suo qualificatore-ansisignifica "supporta tutti i programmi ISO C90". Tuttavia, evitiamo questo termine perché ora è un po' ambiguo. Da quando il comitato ANSI ha adottato la revisione C99, correttamente parlando, ANSI C è ora C99.
I Primi Standard POSIX
Il termine POSIX (abbreviazione di Portable Operating System Interface) si riferisce a un gruppo di standard sviluppati sotto l'egida dell'Institute of Electrical and Electronic Engineers (IEEE), in particolare del suo Portable Application Standards Committee (PASC, http://www.pasc.org/). Lo scopo degli standard PASC è promuovere la portabilità delle applicazioni a livello di codice sorgente.
Il nome POSIX fu suggerito da Richard Stallman. La X finale compare perché la maggior parte delle varianti UNIX termina con X. Lo standard specifica che il nome dovrebbe essere pronunciato “pahz-icks”, come “positive”, ossia positivo.
I più interessanti per noi sono il primo standard POSIX, indicato come POSIX.1 (o più formalmente POSIX 1003.1), e il successivo standard POSIX.2.
POSIX.1 divenne uno standard IEEE nel 1988 e, con lievi revisioni, fu adottato come standard ISO nel 1990 (ISO/IEC 9945-1:1990). (Gli standard POSIX originali non sono disponibili online, ma possono essere acquistati dall'IEEE all'indirizzo http://www.ieee.org/.)
POSIX.1 fu inizialmente basato su uno standard non ufficiale (1984) prodotto da un'associazione di fornitori UNIX chiamata /usr/group.
POSIX.1 descrive un'API per un insieme di servizi che devono essere messi a disposizione di un programma da un sistema operativo conforme. Un sistema operativo che lo fa può essere certificato come conforme a POSIX.1. POSIX.1 si basa sulle chiamate di sistema UNIX e sull'API delle funzioni della libreria C, ma non richiede alcuna implementazione specifica associata a questa interfaccia.
Ciò significa che l'interfaccia può essere implementata da qualsiasi sistema operativo, non necessariamente da un sistema UNIX. Infatti, alcuni fornitori hanno aggiunto API ai loro sistemi operativi proprietari rendendoli conformi a POSIX.1, lasciando però in gran parte invariato il sistema operativo sottostante.
Un certo numero di estensioni allo standard originale POSIX.1 sono state anch'esse importanti:
- IEEE POSIX 1003.1b (POSIX.1b, precedentemente chiamato POSIX.4 o POSIX 1003.4), ratificato nel 1993, contiene una serie di estensioni realtime allo standard POSIX di base.
- IEEE POSIX 1003.1c (POSIX.1c), ratificato nel 1995, è la definizione dei thread POSIX.
Nel 1996 è stata prodotta una versione rivista dello standard POSIX.1 (ISO/IEC 9945-1:1996), che ha lasciato invariato il testo principale, ma ha incorporato le estensioni realtime e thread. IEEE POSIX 1003.1g (POSIX.1g) ha definito le API di rete, inclusi i socket.
- IEEE POSIX 1003.1d (POSIX.1d), ratificato nel 1999, e POSIX.1j, ratificato nel 2000, hanno definito ulteriori estensioni realtime allo standard POSIX di base.
Le estensioni realtime POSIX.1b includono sincronizzazione dei file; I/O asincrono; scheduling dei processi; orologi e timer ad alta precisione; e comunicazione interprocesso mediante semafori, memoria condivisa e code di messaggi. Il prefisso POSIX è spesso applicato ai tre metodi di comunicazione interprocesso per distinguerli da quelli simili, ma più vecchi, dei semafori, della memoria condivisa e delle code di messaggi di System V.
Uno standard correlato, POSIX.2 (1992, ISO/IEC 9945-2:1993), ha standardizzato la shell e varie utility UNIX, inclusa l'interfaccia a riga di comando del compilatore C.
FIPS 151-1 e FIPS 151-2
FIPS è l'abbreviazione di Federal Information Processing Standard, il nome di un insieme di standard specificati dal governo degli Stati Uniti per l'acquisto dei suoi sistemi informatici.
Nel 1989 fu pubblicato il FIPS 151-1. Questo standard si basava sullo standard IEEE POSIX.1 del 1988 e sul draft dello standard ANSI C.
La principale differenza tra FIPS 151-1 e POSIX.1 (1988) era che lo standard FIPS richiedeva alcune funzionalità che POSIX.1 lasciava opzionali.
Poiché il governo degli USA è un grande acquirente di sistemi informatici, la maggior parte dei fornitori ha garantito che i loro sistemi UNIX fossero conformi alla versione FIPS 151-1 di POSIX.1. FIPS 151-2 era allineato con l'edizione ISO del 1990 di POSIX.1, ma altrimenti rimaneva invariato. Il ormai obsoleto FIPS 151-2 è stato ritirato come standard nel febbraio 2000.
X/Open Company e The Open Group
X/Open Company era un consorzio costituito da un gruppo internazionale di fornitori di computer con l'obiettivo di adottare e adattare gli standard esistenti per produrre un insieme completo e coerente di standard per sistemi aperti.
Il consorzio ha pubblicato la X/Open Portability Guide, una serie di guide di portabilità basate sugli standard POSIX.
La prima versione importante di questa guida è stata la Issue 3 (XPG3) del 1989, seguita dalla XPG4 nel 1992. La XPG4 è stata revisionata nel 1994, dando origine alla XPG4 versione 2, standard che ha incorporato anche parti rilevanti della System V Interface Definition Issue 3 di AT&T, descritta nella Sezione 1.3.7.
Questa revisione è anche nota come Spec 1170, dove 1170 indica il numero di interfacce‑funzioni, file header e comandi definiti dallo standard.
Quando Novell, che aveva acquisito il business dei sistemi UNIX da AT&T all'inizio del 1993, in seguito si è disimpegnata da tale attività, ha trasferito i diritti sul marchio UNIX a X/Open.
(Il piano di trasferimento fu annunciato nel 1993, ma requisiti legali ne hanno ritardato l'effettiva attuazione fino all'inizio del 1994.) La XPG4 versione 2 è stata poi riproposta come Single UNIX Specification (SUS, o talvolta SUSv1), nota anche come UNIX 95. Questo re‑packaging comprendeva la XPG4 versione 2, la specifica X/Open Curses Issue 4 versione 2 e la specifica X/Open Networking Services (XNS) Issue 4.
La versione 2 della Single UNIX Specification (SUSv2, http://www.unix.org/version2/online.html) è comparsa nel 1997; le implementazioni UNIX certificate secondo questo standard possono definirsi UNIX 98. (Talvolta questo standard è indicato anche come XPG5.)
Nel 1996 X/Open si è fuso con l'Open Software Foundation (OSF) per formare The Open Group.
Oggi quasi tutte le aziende o organizzazioni coinvolte nel mondo UNIX sono membri di The Open Group, che continua a sviluppare standard API.
OSF era uno dei due consorzi di fornitori formatisi durante le guerre UNIX della fine degli anni '80. Tra gli altri, OSF includeva Digital, IBM, HP, Apollo, Bull, Nixdorf e Siemens. OSF è stato creato principalmente in risposta alla minaccia generata da un'alleanza commerciale tra AT&T (gli ideatori di UNIX) e Sun (il più potente attore nel mercato delle workstation UNIX). Di conseguenza, AT&T, Sun e altre aziende hanno fondato il consorzio rivale UNIX International.
Susv3 e POSIX.1‑2001
A partire dal 1999, IEEE, The Open Group e il Comitato Tecnico Congiunto ISO/IEC 1 hanno collaborato nel Austin Common Standards Revision Group (CSRG, http://www.opengroup.org/austin/) con l'obiettivo di revisionare e consolidare gli standard POSIX e la Single UNIX Specification. (Il gruppo prende il nome da Austin, Texas, dove si è tenuta la prima riunione, nel settembre 1998.) Il lavoro ha portato alla ratifica di POSIX 1003.1‑2001, talvolta chiamato semplicemente POSIX.1‑2001, nel dicembre 2001 (successivamente approvato come standard ISO, ISO/IEC 9945:2002).
POSIX 1003.1‑2001 sostituisce SUSv2, POSIX.1, POSIX.2 e una serie di altri standard POSIX precedenti. Questo standard è anche conosciuto come Single UNIX Specification Version 3; per brevità, nel resto del libro lo indicheremo come SUSv3. Le specifiche di base di SUSv3 comprendono circa 3700 pagine, suddivise in quattro parti:
- Base Definitions (XBD): contiene definizioni, termini, concetti e specifiche dei contenuti dei file header. Sono fornite 84 specifiche di file header.
- System Interfaces (XSH): inizia con varie informazioni di contesto utili; la maggior parte è dedicata alla specifica delle funzioni (implementate come system call o funzioni di libreria nelle diverse implementazioni UNIX). Sono incluse 1123 interfacce di sistema.
- Shell and Utilities (XCU): specifica il funzionamento della shell e di vari comandi UNIX. Sono specificate 160 utility.
- Rationale (XRAT): contiene testo informativo e le motivazioni relative alle parti precedenti.
In aggiunta, SUSv3 include la specifica X/Open CURSES Issue 4 Version 2 (XCURSES), che definisce 372 funzioni e 3 file header per l'API di gestione dello schermo curses. In totale, SUSv3 specifica 1742 interfacce.
Per confronto, POSIX.1‑1990 (con FIPS 151‑2) ne specificava 199, mentre POSIX.2‑1992 ne specificava 130. SUSv3 è disponibile online all'indirizzo http://www.unix.org/version3/online.html.
Le implementazioni UNIX certificate secondo SUSv3 possono definirsi UNIX 03. Sono state apportate varie correzioni minori e miglioramenti per problemi scoperti dopo la ratifica del testo originale di SUSv3. Queste hanno portato al Technical Corrigendum Number 1, le cui migliorie sono state incorporate nella revisione del 2003 di SUSv3, e al Technical Corrigendum Number 2, le cui migliorie sono state incorporate nella revisione del 2004.
Conformità POSIX, conformità XSI e estensione XSI
Storicamente, gli standard SUS (e XPG) si riferivano agli standard POSIX corrispondenti e venivano strutturati come supersets funzionali di POSIX. Oltre a specificare interfacce aggiuntive, gli standard SUS rendevano obbligatorie molte interfacce e comportamenti che in POSIX erano opzionali. Questa distinzione persiste, in forma più sottile, in POSIX 1003.1‑2001, che è sia uno standard IEEE sia uno Standard Tecnico di The Open Group (cioè, come già detto, è una consolidazione dei precedenti standard POSIX e SUS).
Il documento definisce due livelli di conformità:
- Conformità POSIX: definisce un insieme di base di interfacce che un'implementazione conforme deve fornire. Consente all'implementazione di fornire altre interfacce opzionali.
- Conformità X/Open System Interface (XSI): per essere conforme XSI, un'implementazione deve soddisfare tutti i requisiti della conformità POSIX e inoltre fornire una serie di interfacce e comportamenti che sono opzionali in POSIX. Un'implementazione deve raggiungere questo livello per ottenere il marchio UNIX 03 da The Open Group.
Le interfacce e i comportamenti aggiuntivi richiesti per la conformità XSI sono collettivamente noti come estensione XSI. Esse includono il supporto a funzionalità quali thread, mmap() e munmap(), l'API dlopen, limiti di risorse, pseudoterminali, IPC System V, l'API syslog, poll(), e la contabilizzazione dei login.
Nelle prossime lezioni, quando parleremo di conformità SUSv3, intendiamo la conformità XSI.
Poiché POSIX e SUSv3 fanno ora parte dello stesso documento, le interfacce aggiuntive e la selezione delle opzioni obbligatorie richieste per SUSv3 sono indicate mediante ombreggiature e marcature a margine nel testo del documento.
Interfacce non specificate e debolmente specificate
Talvolta ci riferiamo a un'interfaccia come "non specificata" o "debolmente specificata" all'interno di SUSv3:
- Un'interfaccia non specificata è quella che non è definita affatto nello standard formale, anche se in alcuni casi vi sono note di contesto o testi di motivazione che la menzionano.
- Definire un'interfaccia debolmente specificata è un'abbreviazione per dire che, sebbene l'interfaccia sia inclusa nello standard, dettagli importanti rimangono non specificati (spesso perché il comitato non è riuscito a raggiungere un accordo a causa di differenze tra le implementazioni esistenti).
Quando si usano interfacce non specificate o debolmente specificate, le garanzie per il porting delle applicazioni su altre implementazioni UNIX sono limitate. Tuttavia, in alcuni casi tali interfacce risultano abbastanza coerenti tra le implementazioni; in tali situazioni lo segnaliamo esplicitamente.
Funzionalità LEGACY
A volte, SUSv3 contrassegna una funzionalità specificata come LEGACY. Questo termine indica una caratteristica mantenuta per compatibilità con applicazioni più vecchie, ma le cui limitazioni suggeriscono di evitarne l'uso in nuovi progetti. Nella maggior parte dei casi esiste un'altra API che fornisce la stessa funzionalità in modo più moderno.
SUSv4 e POSIX.1‑2008
Nel 2008 il gruppo Austin ha completato una revisione della combinazione POSIX.1 e Single UNIX Specification.
Come per la versione precedente dello standard, essa è composta da una specifica di base affiancata da un'estensione XSI. Ci riferiremo a questa revisione come SUSv4.
Le modifiche introdotte da SUSv4 sono meno estese rispetto a quelle di SUSv3. Le più significative sono le seguenti:
- SUSv4 aggiunge nuove specifiche per una serie di funzioni. Tra le funzioni appena specificate e citate nelle prossime lezioni troviamo
dirfd(),fdopendir(),fexecve(),futimens(),mkdtemp(),psignal(),strsignal()eutimensat(). - Un altro gruppo di nuove funzioni legate ai file (ad es.
openat()) sono analoghe a funzioni esistenti (ad es.open()), ma differiscono perché interpretano i percorsi relativi rispetto alla directory indicata da un descrittore di file aperto, anziché rispetto alla directory di lavoro corrente del processo. - Alcune funzioni che in SUSv3 erano opzionali diventano obbligatorie nella base di SUSv4. Per esempio, diverse funzioni che facevano parte dell'estensione XSI in SUSv3 sono ora incluse nella specifica di base. Tra le funzioni rese obbligatorie in SUSv4 ci sono quelle dell'API
dlopen, l'API dei segnali in tempo reale, l'API dei semafori POSIX e l'API dei timer POSIX. - Alcune funzioni presenti in SUSv3 sono contrassegnate come obsolete in SUSv4. Tra queste vi sono
asctime(),ctime(),ftw(),gettimeofday(),getitimer(),setitimer()esiginterrupt(). - Alcune specifiche di funzioni già marcate come obsolete in SUSv3 sono state rimosse in SUSv4. Le funzioni eliminate includono
gethostbyname(),gethostbyaddr()evfork(). - Vari dettagli delle specifiche esistenti in SUSv3 sono stati modificati in SUSv4. Per esempio, diverse funzioni sono state aggiunte all'elenco di quelle che devono essere async‑signal‑safe.
Nel resto delle lezioni indicheremo le modifiche introdotte da SUSv4 quando saranno rilevanti per l'argomento trattato.
Standard di Implementazione
Oltre agli standard prodotti da gruppi indipendenti o multipartitici, a volte si fa riferimento ai due standard di implementazione definiti dall'ultima release di BSD (4.4BSD) e da System V Release 4 di AT&T (SVR4).
Quest'ultimo standard di implementazione è stato formalizzato dalla pubblicazione da parte di AT&T della System V Interface Definition (SVID).
Nel 1989 AT&T pubblicò la terza edizione del SVID, che definiva l'interfaccia che un'implementazione UNIX deve fornire per potersi definire System V Release 4. (Il SVID è disponibile online all'indirizzo http://www.sco.com/ developers/devspecs/.)
Poiché il comportamento di alcune system call e funzioni di libreria varia tra SVR4 e BSD, molte implementazioni UNIX forniscono librerie di compatibilità e meccanismi di compilazione condizionale che emulano il comportamento del tipo di UNIX non usato come base per quella specifica implementazione. Questo facilita il porting di un'applicazione da un'altra implementazione UNIX.
Linux Standard e Linux Standard Base (LSB)
Come obiettivo generale, lo sviluppo di Linux (cioè kernel, glibc e tool vari) mira a conformarsi ai vari standard UNIX, in particolare POSIX e alla Single UNIX Specification.
Tuttavia, al momento della stesura, nessuna distribuzione Linux è etichettata come “UNIX” da The Open Group.
I motivi sono tempi e costi: ogni distribuzione dovrebbe sottoporsi a test di conformità per ottenere tale etichetta e dovrebbe ripetere tali test ad ogni nuova versione.
Tuttavia, è la quasi conformità de facto a diversi standard che ha permesso a Linux di avere tanto successo nel mercato UNIX. Nella maggior parte delle implementazioni commerciali di UNIX, la stessa azienda sviluppa e distribuisce il sistema operativo.
Con Linux la situazione è diversa: l'implementazione è separata dalla distribuzione e molte organizzazioni, sia commerciali che non commerciali, si occupano della distribuzione di Linux. Linus Torvalds non contribuisce né sostiene una distribuzione Linux specifica.
Tuttavia, per quanto riguarda gli altri individui che partecipano allo sviluppo di Linux, la situazione è più complessa. Molti sviluppatori che lavorano sul kernel Linux e su altri progetti di software libero sono impiegati da varie aziende di distribuzione Linux o lavorano per società (come IBM e HP) con un forte interesse verso Linux.
Sebbene queste aziende possano influenzare la direzione di Linux destinando ore di programmazione a determinati progetti, nessuna di esse controlla Linux in sé. E, naturalmente, molti altri contributori al kernel Linux e ai progetti GNU operano volontariamente.
Al momento della stesura, Torvalds è impiegato come fellow presso la Linux Foundation (http://www.linux-foundation.org/; precedentemente Open Source Development Laboratory, OSDL), un consorzio no‑profit di organizzazioni commerciali e non commerciali con lo scopo di promuovere la crescita di Linux.
Poiché esistono molteplici distributori Linux e gli implementatori del kernel non controllano il contenuto delle distribuzioni, non esiste un “Linux commerciale standard”. L'offerta di kernel di ciascun distributore Linux si basa tipicamente su una snapshot del kernel mainline (cioè quello di Torvalds) in un determinato momento, a cui vengono applicati vari patch. Questi patch forniscono tipicamente funzionalità ritenute commercialmente desiderabili, consentendo così una differenziazione competitiva sul mercato. In alcuni casi, le patch vengono successivamente accettate nel kernel mainline.
In realtà, alcune nuove funzionalità del kernel sono state inizialmente sviluppate da una società di distribuzione e sono apparse nelle loro distribuzioni prima di essere integrate nel mainline. Per esempio, la versione 3 del file system journaling Reiserfs era presente in alcune distribuzioni Linux molto prima di essere accettata nel kernel mainline 2.4.
Il risultato di quanto detto è che esistono (per lo più minime) differenze nei sistemi offerti dalle varie aziende di distribuzione Linux. Su scala più ridotta, ciò ricorda le divisioni nelle implementazioni che si verificarono nei primi anni di UNIX. La Linux Standard Base (LSB) è un'iniziativa volta a garantire la compatibilità tra le diverse distribuzioni Linux. Per farlo, la LSB (http://www.linux-foundation.org/en/LSB) sviluppa e promuove un insieme di standard per i sistemi Linux con l'obiettivo di assicurare che le applicazioni binarie (cioè i programmi compilati) possano essere eseguite su qualsiasi sistema conforme alla LSB.
La portabilità binaria promossa dalla LSB è in contrasto con la portabilità del codice sorgente promossa da POSIX. La portabilità del codice sorgente significa che possiamo scrivere un programma in C e poi compilarlo ed eseguirlo con successo su qualsiasi sistema conforme a POSIX. La compatibilità binaria è molto più esigente e generalmente non è realizzabile su piattaforme hardware diverse. Essa consente di compilare un programma una sola volta per una data piattaforma hardware e poi eseguire quel programma compilato su qualsiasi implementazione conforme che giri su quella piattaforma. La portabilità binaria è un requisito fondamentale per la fattibilità commerciale delle applicazioni di fornitori di software indipendenti (ISV) sviluppate per Linux.
In Sintesi
La diversità delle versioni UNIX rendeva difficile la migrazione di software e personale. Per questo emerse la necessità di standardizzare C e UNIX, facilitando il porting delle applicazioni. Gli standard successivi sono il risultato di questa spinta verso l'uniformità.