From: Simone Piccardi Date: Fri, 6 Apr 2001 15:42:53 +0000 (+0000) Subject: Roba di ieri, riscritte meglio (spero) alcune parti X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=commitdiff_plain;h=79145add042bda64865b6939673388f3173284e5;hp=60ea832813214f6bc4a9761a85d9d2b2038991aa Roba di ieri, riscritte meglio (spero) alcune parti --- diff --git a/files.tex b/files.tex index a9f253b..e3c994d 100644 --- a/files.tex +++ b/files.tex @@ -1,44 +1,55 @@ -\chapter{I files} +\chapter{I files: introduzione} \label{cha:files} - + Uno dei concetti fondamentali del design di unix è il cosiddetto -\textit{everything is a file}, cioè il fatto che l'accesso alle periferiche -viene gestito attraverso un'interfaccia astratta che tratta nello stesso modo -sia i normali file di dati che le periferiche. Si può accedere cioè a queste -ultime (con l'eccezione delle interfacce di rete) attraverso i cosiddetti file -di dispositivo (i \textit{device files}) che permettono ai programmi di -interfacciarsi alle varie periferiche come la seriale, la parallela, la -console, e gli stessi dischi. - -\section{Concetti generali sui files} +\textit{everything is a file}, cioè il fatto che l'accesso ai vari dispositivi +di I/O del computer viene effettuato attraverso un'interfaccia astratta che +tratta le periferiche allo stesso modo degli usuali file di dati. + +Si può accedere cioè a qualunque periferica del computer, dalla seriale, alla +parallela, alla console, e agli stessi dischi, (unica eccezione le interfacce +di rete, che che non rientrano bene nell'astrazione) attraverso i cosiddetti +file di dispositivo (i \textit{device files}). Questi sono dei file speciali +agendo sui quali i programmi possono leggere, scrivere e compiere operazioni +sulle perferiche, usando le stesse funzioni che si usano per i normali file di +dati. + +\section{Concetti generali riguardanti i files} \label{sec:file_gen} -Per poter accedere ai singoli file su disco è necessario l'uso di un -\textit{filesystem}, cioè di un'interfaccia del kernel che permetta di -strutturare l'informazione tenuta sullo spazio grezzo disponibile sui dischi -in files e directory. Sarà quest'ultimo a gestire l'accesso ai dati -memorizzati all'interno del disco stesso, e l'uso delle normali directory e -files. +Visto il ruolo fondamentale che i files vengono ad assumere in un sistema +unix, è anzitutto opportuno fornire un'introduzione dettagliata su come essi +vengono trattati dal sistema. In particolare occorre tenere presente dov'è che +si situa il limite fondamentale fra kernel space e user space che tracciavamo +al Cap.~\ref{cha:intro_unix}. + +Partiamo allora da come viene strutturata nel sistema la disposizione dei +file: per potervi accedere il kernel usa una apposita interfaccia che permetta +di strutturare l'informazione tenuta sullo spazio grezzo disponibile sui +dischi, cioè quello che si chiama un \textit{filesystem}. + +Sarà attraverso quest'ultimo che il kernel andrà a gestire l'accesso ai dati +memorizzati all'interno del disco stesso, strutturando l'informazione in files +e directory. Per poter accedere ai file contenuti in un disco occorrerà +perciò attivare il filesystem, questo viene fatto \textsl{montando} il disco +(o la partizione del disco). %In generale un filesystem piazzerà opportunamente sul disco dei blocchi di %informazioni riservate che tengono conto degli inodes allocati, di quelli %liberi, e delle posizioni fisiche su disco dei dati contenuti nei files, per -Per poter accedere ai file contenuti in un disco occorrerà poi attivare il -filesystem \textit{montando} il disco (o la partizione del disco). - -In unix, a differenza di quanto avviene in altri sistemi operativi, tutti i +In Unix, a differenza di quanto avviene in altri sistemi operativi, tutti i file vengono tenuti all'interno di un unico albero la cui radice (la directory di \textit{root}) viene montata all'avvio. Pertanto un file viene identificato -dall'utente usando il suo \textit{pathname}, cioè il percorso completo che si -deve fare a partire dalla radice, per accedere al file. +dall'utente usando quello che viene chiamato \textit{pathname}, cioè il +percorso completo che si deve fare a partire dalla radice, per accedere al +file. Dopo la fase di inizializzazione il kernel riceve dal boot loader l'indicazione di quale dispositivo contiene il filesystem da usare come punto di partenza e questo viene montato come radice dell'albero (cioè nella directory \texttt{/}); tutti gli ulteriori dischi devono poi essere inseriti -nell'albero utilizzando opportune subdirectory (in genere sotto -\texttt{/mnt}) . +nell'albero utilizzando opportune subdirectory. Alcuni filesystem speciali (come \texttt{/proc} che contiene un'interfaccia ad alcune strutture interne del kernel) sono generati automaticamente dal kernel @@ -71,19 +82,19 @@ coesistenza di diversi filesystem all'interno dello stesso kernel. La funzione più importante implementata dal VFS è la system call \texttt{open} che permette di aprire un file. Dato un pathname viene eseguita una ricerca -dentro la \textit{directory entry cache} (la \textit{dcache}) una tabella di -hash che contiene tutte le \textit{directory entry} (in breve \textit{dentry}) -che permette di associare in maniera rapida ed efficiente il pathname a una -specifica dentry. +dentro la \textit{directory entry cache} (in breve \textit{dcache}) che è +una tabella di hash che contiene tutte le \textit{directory entry} (in breve +\textit{dentry}) che permette di associare in maniera rapida ed efficiente il +pathname a una specifica dentry. Una singola dentry contiene in genere il puntatore ad un \textit{inode}; quest'ultimo è la struttura base che sta sul disco e che identifica un singolo -oggetto del VFS che può essere un file, una directory, una FIFO, un file di -dispositivo, o una qualsiasi altra cosa che possa essere rappresentata dal -VFS (sui tipi di files possibili torneremo in seguito). +oggetto del VFS sia esso un file ordinario, una directory, una FIFO, un file +di dispositivo, o una qualsiasi altra cosa che possa essere rappresentata dal +VFS (sui tipi di ``files'' possibili torneremo in seguito). Le dentries ``vivono'' in memoria e non vengono mai salvate su disco, vengono -usate per motivi di velocità, gli inodes invece vivono su disco e vengono +usate per motivi di velocità, gli inodes invece stanno su disco e vengono copiati in memoria quando serve, ed ogni cambiamento viene copiato all'indietro sul disco, gli inodes che stanno in memoria sono inodes del VFS ed è ad essi che puntano le singole dentry. @@ -111,11 +122,6 @@ user space possono accedere alle operazioni attraverso detti metodi, che saranno diversi a seconda del tipo di file (o dispositivo) aperto. Un elenco delle operazioni disponibili è riportato in \ntab. -% La struttura file viene poi inserita nella tavola dei file -% , non -% tutte le operazioni possibili sono definite per tutti i dispositivi; un elenco -% delle operazioni definite in linux è riportato in \ntab. - \begin{table}[htb] \centering \begin{tabular}[c]{c p{7cm}} @@ -149,32 +155,33 @@ utilizzare la opportuna routine dichiarata in \verb|f_ops| appropriata al tipo di file in questione. Così sarà possibile scrivere sulla porta seriale come su un file di dati -normale; ovviamente certe operazioni (nel caso la \textit{seek}) non saranno -disponibili, però con questo sistema l'utilizzo di diversi filesystem è -immediato e (relativamente) trasparente per l'utente ed il programmatore. +normale; ovviamente certe operazioni (nel caso della seriale ad esempio la +\textit{seek}) non saranno disponibili, però con questo sistema l'utilizzo di +diversi filesystem (come quelli usati da Windows o MacOs) è immediato e +(relativamente) trasparente per l'utente ed il programmatore. \subsection{Proprietari e permessi} \label{sec:file_perms} -In unix è implementata da qualunque filesystem standard una forma elementare +In Unix è implementata da qualunque filesystem standard una forma elementare (ma adatta alla maggior parte delle esigenze) di controllo di accesso ai files. Torneremo sull'argomento in dettaglio più avanti, qui ci limitiamo ad una introduzione dei concetti essenziali. -Si tenga conto poi che quanto diremo è vero solo per filesystem di tipo unix, +Si tenga conto poi che quanto diremo è vero solo per filesystem di tipo Unix, e non è detto che sia applicabile (ed infatti non è vero per il filesystem di -windows) a un filesystem qualunque. Esistono inoltre estensioni che permettono +Windows) a un filesystem qualunque. Esistono inoltre estensioni che permettono di implementare le ACL (\textit{Access Control List}) che sono un meccanismo di controllo di accesso molto più sofisticato. -Ad ogni file unix associa sempre l'utente che ne è proprietario (il cosiddetto +Ad ogni file Unix associa sempre l'utente che ne è proprietario (il cosiddetto \textit{owner}) e il gruppo di appartenenza, secondo il meccanismo degli uid e gid spiegato in \ref{sec:intro_usergroup}, e un insieme di permessi che sono divisi in tre classi, e cioè attribuiti rispettivamente al proprietario, a qualunque utente faccia parte del gruppo cui appartiene il file, e a tutti gli altri utenti. -I permessi sono espressi da un insieme di 12 bit, di questi i nove meno +I permessi sono espressi da un insieme di 12 bit: di questi i nove meno significativi sono usati a gruppi di tre per indicare i permessi base di lettura, scrittura ed esecuzione (indicati rispettivamente con le lettere \textit{w}, \textit{r} \textit{x}) applicabili rispettivamente al @@ -220,7 +227,7 @@ dei vari tipi di file \textit{fifo} & \textsl{tubo} & un file speciale che identifica una linea di comunicazione software (unidirezionale) \\ - \textit{socket} & \textsl{presa} & + \textit{socket} & \textsl{manicotto} & un file speciale che identifica una linea di comunicazione software (bidirezionale) \\ \hline @@ -233,26 +240,27 @@ dei vari tipi di file Tutto ciò non ha ovviamente nulla a che fare con la classificazione sui tipi di file (in questo caso file di dati) in base al loro contenuto, o tipo di accesso. Una delle differenze principali con altri sistemi operativi (come il -VMS o windows) è che per unix tutti i file di dati sono identici e contengono +VMS o Windows) è che per Unix tutti i file di dati sono identici e contengono un flusso continuo di bytes; non esiste cioè differenza per come vengono visti dal sistema file di diverso contenuto o formato (come nel caso di quella fra file di testo e binari che c'è in windows) né c'è una strutturazione a record per il cosiddetto ``accesso diretto'' come nel caso del VMS. -Una seconda differenza è nel formato dei file ascii; in unix la fine riga è -codificata in maniera diversa da windows o macintosh, in particolare il fine -riga è il carattere \texttt{LF} al posto del \texttt{CR} del mac e del -\texttt{CR LF} di windows. Questo può causare alcuni problemi qualora si -facciano assunzioni sul terminatore della riga. +Una seconda differenza è nel formato dei file ascii; in Unix la fine riga è +codificata in maniera diversa da Windows o MacIntosh, in particolare il fine +riga è il carattere \texttt{LF} (o \verb|\n|) al posto del \texttt{CR} +(\verb|\r|) del mac e del \texttt{CR LF} di windows. Questo può causare alcuni +problemi qualora si facciano assunzioni sul terminatore della riga. -\section{Una panoramica sull'I/O sui file} +\section{Una panoramica sull'uso dei file} \label{sec:file_io_base} Per poter accedere al contenuto dei file occorre anzitutto aprirlo. Questo crea un canale di comunicazione che permette di eseguire una serie di operazioni. Una volta terminate le operazioni, il file dovrà essere chiuso, e -questo chiuderà il canale di comunicazione impedendo ogni ulteriore operazione. +questo chiuderà il canale di comunicazione impedendo ogni ulteriore +operazione. \subsection{Le due interfacce ai file} @@ -262,14 +270,14 @@ In unix le modalit programmazione sono due, basate su due diversi meccanismi di connessione. La prima è quella dei cosiddetti \textit{file descriptor} (descrittore di -file), che è specifica di unix e che provvede un accesso diretto a basso +file), che è specifica di Unix e che provvede un accesso diretto a basso livello non bufferizzato, con un'interfaccia primitiva ed essenziale; i file descriptors sono rappresentati da numeri interi (cioè semplici variabili di tipo \texttt{int}). L'interfaccia è definita nell'header \texttt{unistd.h}. La seconda è quella degli \textit{stream}, che provvede un'interfaccia più evoluta e un accesso bufferizzato. Questa è anche l'interfaccia standard usata -dal linguaggio C e perciò si trova anche su tutti i sistemi non unix. Gli +dal linguaggio C e perciò si trova anche su tutti i sistemi non Unix. Gli stream sono oggetti complessi e sono rappresentati da puntatori ad un opportuna struttura definita dalle librerie del C, si accede ad essi sempre in maniera indiretta utilizzando il tipo \texttt{FILE *}. L'interfaccia è @@ -289,8 +297,8 @@ l'eccezione di poter scegliere tre diversi stili di bufferizzazione. Il maggior vantaggio degli stream è che l'interfaccia per le operazioni di input/output è enormemente più ricca di quella dei file descriptor, che provvedono solo funzioni elementari per la lettura/scrittura diretta di -blocchi di bytes. In particolare dispongono di tutte le funzioni di -formattazione per l'input e l'output adatte per manipolare anche i dati in +blocchi di bytes. In particolare gli stream dispongono di tutte le funzioni +di formattazione per l'input e l'output adatte per manipolare anche i dati in forma di linee o singoli caratteri. In ogni caso, dato che gli stream sono implementati sopra l'interfaccia a @@ -308,7 +316,7 @@ pertanto di portabilit \label{sec:files_spec_unix} Essendo un sistema multitasking e multiutente esistono alcune caratteristiche -specifiche di unix che devono essere tenute in conto nell'accesso ai file. È +specifiche di Unix che devono essere tenute in conto nell'accesso ai file. È infatti normale che più processi o programmi possano accedere contemporaneamente allo stesso file e devono poter eseguire le loro operazioni indipendentemente da quello che fanno gli altri processi. @@ -334,18 +342,18 @@ ogni processo avr influenzata da quello che altri processi possono fare. Anzi, aprire un file significa appunto creare ed inizializzare una tale struttura, per cui se si apre due volte lo stesso file all'interno dello stesso processo, si otterrano -due file descriptor o due stream che avranno ancora un posizione corrente nel +due file descriptor o due stream che avranno ancora una posizione corrente nel file assolutamente indipendente. Si tenga conto inoltre che un'altro dei dati contenuti nella struttura di accesso è un riferimento all'inode del file, pertanto anche se il file viene -cancellato da un altro processo, sarà sempre possibile mantenere l'accesso, -e lo spazio su disco non verrà rilasciato fintanto che il file non sarà chiuso -e l'ultimo riferimento cancellato. È pertanto possibile (e pratica comune) -aprire un file provvisorio per cancellarlo immediatamente dopo; in questo modo -all'uscita del programma il file scomparirà definitivamente dal disco, ma il -file ed il suo contenuto saranno disponibili per tutto il tempo in cui il -processo è attivo. +cancellato da un altro processo, sarà sempre possibile mantenere l'accesso ai +dati, e lo spazio su disco non verrà rilasciato fintanto che il file non sarà +chiuso e l'ultimo riferimento cancellato. È pertanto possibile (e pratica +comune) aprire un file provvisorio per cancellarlo immediatamente dopo; in +questo modo all'uscita del programma il file scomparirà definitivamente dal +disco, ma il file ed il suo contenuto saranno disponibili per tutto il tempo +in cui il processo è attivo. \subsection{L'accesso ai files: nomi e directory} @@ -365,12 +373,12 @@ semplicemente specificando il nome da essa contenuto. Una directory contiene semplicemente un elenco di questi componenti, che possono corrispondere a un qualunque oggetto del filesystem, compresa un'altra directory. -Un nome di file è composto da una serie di componenti separati da una +Un nome di file è composto da una serie di \textsl{componenti} separati da una \texttt{/} (in linux più \texttt{/} consecutive sono considerate equivalenti ad una sola). Il nome completo di un file viene usualmente chiamato -\textit{pathname}, anche se questo può generare confusione, dato che con -\textit{path} si indica anche un insieme di directory su cui effettuare una -ricerca (ad esempio quello in cui si cercano i comandi). +\textit{filename} o \textit{pathname}, anche se quest'ultimo può generare +confusione, dato che con \textit{path} si indica anche un insieme di directory +su cui effettuare una ricerca (ad esempio quello in cui si cercano i comandi). Il processo con cui si associa ad un pathname uno specifico file (cioè si identifica l'inode a cui fare riferimento) è chiamato risoluzione del nome @@ -395,11 +403,11 @@ il secondo alla directory \textsl{genitore} (\textit{parent directory}) cio la directory che contiene il riferimento alla directory corrente; nel caso questa sia la directory radice allora il riferimento è a se stessa. -Infine si ricordi che in unix non esistono i tipi di file e che non c'è nessun +Infine si ricordi che in Unix non esistono i tipi di file e che non c'è nessun supporto per le estensioni come parte del filesystem. Ciò non ostante molti programmi adottano delle convenzioni per i nomi dei file, ad esempio il codice -C normalmente si mette in file con l'estensione .c, ma questa è solo una -convenzione. +C normalmente si mette in file con l'estensione .c, ma questa è, appunto, solo +una convenzione. \section{L'interfaccia al filesystem} @@ -602,8 +610,8 @@ nell'header file \texttt{unistd.h}. \begin{itemize} \item \texttt{int link(const char * oldname, const char * newname)} - Crea un nuovo link al file indicato da \texttt{oldname} dandogli nome - \texttt{newname}. + Crea un nuovo link diretto al file indicato da \texttt{oldname} dandogli + nome \texttt{newname}. La funzione restituisce zero in caso di successo e -1 per un errore, in caso di errore. La variabile \texttt{errno} viene settata secondo i codici di @@ -611,6 +619,10 @@ nell'header file \texttt{unistd.h}. \ref{sec:file_err_acc}) ai quali si aggiungono i seguenti: \begin{itemize} + \item \texttt{EXDEV} \texttt{oldname} e \texttt{newname} non sono sullo + stesso filesystem. + \item \texttt{EPERM} il filesystem che contiene \texttt{oldname} e + \texttt{newname} non supporta i link diretti. \item \texttt{EACCESS} Non c'è il permesso di scrittura per la directory in cui si vuole creare il nuovo link. @@ -620,13 +632,39 @@ nell'header file \texttt{unistd.h}. numero massimo è specificato dalla variabile \texttt{LINK\_MAX}, vedi \ref{sec:sys_limits}. \item \texttt{ENOSPC} La directory in cui si vuole creare il link è piena e - non può essere . + non può essere ampliata. \item \texttt{EROFS} La directory su cui si vuole inserire il nuovo link è su un filesystem montato readonly. \end{itemize} \end{itemize} +\begin{itemize} +\item \texttt{int symlink(const char * oldname, const char * newname)} + + Crea un nuovo link simbolico al file indicato da \texttt{oldname} dandogli + nome \texttt{newname}. + + La funzione restituisce zero in caso di successo e -1 per un errore, in caso + di errore. La variabile \texttt{errno} viene settata secondo i codici di + errore standard di accesso ai files (trattati in dettaglio in + \ref{sec:file_err_acc}) ai quali si aggiungono i seguenti: + + \begin{itemize} + \item \texttt{EEXIST} Un file (o una directory) con quel nome esiste di + già. + \item \texttt{EROFS} La directory su cui si vuole inserire il nuovo link è + su un filesystem montato readonly. + \item \texttt{ENOSPC} La directory o il filesystem in cui si vuole creare il + link è piena e non c'è ulteriore spazio disponibile. + \item \texttt{ELOOP} Ci sono troppi link simbolici nella risoluzione di + \texttt{oldname} o di \texttt{newname}. + \end{itemize} +\end{itemize} + + + + \section{L'input/output di basso livello} \label{sec:file_lowlev_io} % diff --git a/intro.tex b/intro.tex index bc81fb7..bbee690 100644 --- a/intro.tex +++ b/intro.tex @@ -1,4 +1,5 @@ \chapter{Introduzione} +\label{cha:intro_unix} In questo primo capitolo sarà fatta un'introduzione ai contetti generali su cui è basato un sistema di tipo unix, per fornire una base di comprensione @@ -200,3 +201,5 @@ qualunque operazione; pertanto per l'utente root i meccanismi di controllo descritti in precedenza sono disattivati. + + diff --git a/main.tex b/main.tex index 569f708..9fe6813 100644 --- a/main.tex +++ b/main.tex @@ -28,8 +28,6 @@ %\includeonly{macro,pref,intro,fdl} - - \title{Guida alla Programmazione in Linux.} \author{Simone Piccardi}