simbolico. Pertanto un collegamento simbolico può anche riferirsi ad un file
che non esiste ed in questo caso si ha quello che viene chiamato un
\itindex{dangling~link} \textit{dangling link}, letteralmente un
-\index{collegamento!ciondolante} ``\textsl{collegamento ciondolante}''.
+\index{collegamento!ciondolante} ``\textsl{collegamento ciondolante}''. Ad
+esempio possiamo usare il comando \cmd{ln} per creare un collegamento
+simbolico nella nostra directory con:
+\begin{Console}
+piccardi@hain:~/gapil$ \textbf{ln -s /tmp/tmp_file symlink}
+\end{Console}
+%$
+e questo avrà successo anche se \file{/tmp/tmp\_file} non esiste:
+\begin{Console}
+piccardi@hain:~/gapil$ \textbf{ls symlink}
+symlink
+\end{Console}
+%$
+ma questo può generare confusione, perché accedendo in lettura a
+\file{symlink}, ad esempio con \cmd{cat}, otterremmo:
+\begin{Console}
+piccardi@hain:~/gapil$ \textbf{cat symlink}
+cat: symlink: No such file or directory
+\end{Console}
+%$
+con un errore che può sembrare sbagliato, dato che \cmd{ls} ci ha mostrato in
+prcedenza l'esistenza di \file{symlink}. Se invece andassimo a scrivere su
+\file{symlink}, l'effetto sarebbe quello di ottenere la creazione di
+\file{/tmp/tmp\_file} (che a quel punto verrebbe creato) senza errori.
Come accennato i collegamenti simbolici sono risolti automaticamente dal
kernel all'invocazione delle varie \textit{system call}. In
sez.~\ref{sec:file_open_close}) e tutte le operazioni seguenti fanno
riferimento solo a quest'ultimo.
+Si tenga anche presente che a partire dal kernel 3.16, se si abilita la
+funzionalità dei \textit{protected symlinks} (attiva di default in tutte le
+distribuzioni più recenti) la risoluzione dei nomi attraverso un collegamento
+simbolico può fallire per una serie di restrizione di sicurezza agguntive
+imposte dal meccanismo (si consulti sez.~\ref{sec:procadv_security_misc} per i
+dettagli del meccanismo).
+
Dato che, come indicato in tab.~\ref{tab:file_symb_effect}, funzioni come la
\func{open} seguono i collegamenti simbolici, occorrono funzioni apposite per
accedere alle informazioni del collegamento invece che a quelle del file a cui
\begin{funcproto}{
\fhead{unistd.h}
-\fdecl{int readlink(const char *path, char *buff, size\_t size)}
+\fdecl{int readlink(const char *pathname, char *buff, size\_t size)}
\fdesc{Legge il contenuto di un collegamento simbolico.}
}
{La funzione ritorna il numero di caratteri letti dentro \param{buff} in caso
di successo e $-1$ per un errore, nel qual caso \var{errno} assumerà uno
dei valori:
\begin{errlist}
- \item[\errcode{EINVAL}] \param{path} non è un collegamento simbolico
+ \item[\errcode{EACCES}] non si hanno i permessi di attraversamento di una
+ delle directory del pathname
+ \item[\errcode{EINVAL}] \param{pathname} non è un collegamento simbolico
o \param{size} non è positiva.
- \end{errlist} ed inoltre \errval{EACCES}, \errval{EFAULT}, \errval{EIO},
- \errval{ELOOP}, \errval{ENAMETOOLONG}, \errval{ENOENT}, \errval{ENOMEM} e
- \errval{ENOTDIR} nel loro significato generico.}
+ \end{errlist} ed inoltre \errval{EFAULT}, \errval{EIO}, \errval{ELOOP},
+ \errval{ENAMETOOLONG}, \errval{ENOENT}, \errval{ENOMEM} e \errval{ENOTDIR}
+ nel loro significato generico.}
\end{funcproto}
La funzione legge il \textit{pathname} a cui fa riferimento il collegamento
-simbolico indicato dall'argomento \param{path} scrivendolo sul
-buffer \param{buff} di dimensione \param{size}. Si tenga presente che la
-funzione non termina la stringa con un carattere nullo e che se questa è
-troppo lunga la tronca alla dimensione specificata da \param{size} per evitare
-di sovrascrivere oltre le dimensioni del buffer.
+simbolico indicato dall'argomento \param{pathname} scrivendolo sul buffer
+\param{buff} di dimensione \param{size}. Si tenga presente che la funzione non
+termina la stringa con un carattere nullo e che se questa è troppo lunga la
+tronca alla dimensione specificata da \param{size} per evitare di scrivere
+dati oltre le dimensioni del buffer.
\begin{figure}[htb]
\centering
- \includegraphics[width=7.0cm]{img/link_loop}
+ \includegraphics[width=8cm]{img/link_loop}
\caption{Esempio di loop nel filesystem creato con un collegamento
simbolico.}
\label{fig:file_link_loop}
dei nomi che non possono essere eliminati facilmente. Invece è sempre
possibile, ed in genere anche molto utile, creare un collegamento simbolico ad
una directory, anche se in questo caso si potranno ottenere anche dei
-\textit{loop}. La situazione è illustrata in fig.~\ref{fig:file_link_loop},
-che riporta la struttura della directory \file{/boot}. Come si vede si è
-creato al suo interno un collegamento simbolico che punta di nuovo a
+\textit{loop}.
+
+La situazione è illustrata in fig.~\ref{fig:file_link_loop}, che riporta la
+struttura della directory \file{/boot}. Come si vede si è creato al suo
+interno un collegamento simbolico che punta di nuovo a
\file{/boot}.\footnote{il \textit{loop} mostrato in
- fig.~\ref{fig:file_link_loop} è stato usato per poter permettere a
- \cmd{grub} (un bootloader in grado di leggere direttamente da vari
- filesystem il file da lanciare come sistema operativo) di vedere i file
- contenuti nella directory \file{/boot} con lo stesso \textit{pathname} con
- cui verrebbero visti dal sistema operativo, anche se essi si trovano, come
- accade spesso, su una partizione separata (che \cmd{grub} all'avvio vedrebbe
- come \file{/}).}
-
-Questo però può causare problemi per tutti quei programmi che effettuano la
-scansione di una directory senza tener conto dei collegamenti simbolici, ad
-esempio se lanciassimo un comando del tipo \code{grep -r linux *}, il loop
-nella directory porterebbe il comando ad esaminare \file{/boot},
-\file{/boot/boot}, \file{/boot/boot/boot} e così via.
+ fig.~\ref{fig:file_link_loop} è stato usato per poter permettere a al
+ \textit{bootloader} \cmd{grub} di vedere i file contenuti nella directory
+ \file{/boot} con lo stesso \textit{pathname} con cui verrebbero visti dal
+ sistema operativo, anche quando si trovano, come accade spesso, su una
+ partizione separata (che \cmd{grub} all'avvio vedrebbe come \file{/}).} Un
+\textit{loop} di di questo tipo però può causare problemi per tutti i
+programmi che effettuano la scansione di una directory, e ad esempio se
+lanciassimo un comando come \code{grep -r linux *}, il \textit{loop} nella
+directory porterebbe ad esaminare \file{/boot}, \file{/boot/boot},
+\file{/boot/boot/boot} e così via.
Per questo motivo il kernel e le librerie prevedono che nella risoluzione di
un \textit{pathname} possano essere seguiti fino ad un certo numero massimo di
collegamenti simbolici, il cui valore limite è specificato dalla costante
-\constd{MAXSYMLINKS}. Qualora questo limite venga superato viene generato un
-errore ed \var{errno} viene impostata al valore \errcode{ELOOP}, che nella
-quasi totalità dei casi indica appunto che si è creato un collegamento
-simbolico che fa riferimento ad una directory del suo stesso
-\textit{pathname}.
-
-Un altro punto da tenere sempre presente è che, come abbiamo accennato, un
-collegamento simbolico può fare riferimento anche ad un file che non esiste;
-ad esempio possiamo usare il comando \cmd{ln} per creare un collegamento
-simbolico nella nostra directory con:
-\begin{Console}
-piccardi@hain:~/gapil$ \textbf{ln -s /tmp/tmp_file symlink}
-\end{Console}
-%$
-e questo avrà successo anche se \file{/tmp/tmp\_file} non esiste:
-\begin{Console}
-piccardi@hain:~/gapil$ \textbf{ls symlink}
-symlink
-\end{Console}
-%$
-ma questo può generare confusione, perché accedendo in sola lettura a
-\file{symlink}, ad esempio con \cmd{cat}, otterremmo un errore:
-\begin{Console}
-piccardi@hain:~/gapil$ \textbf{cat symlink}
-cat: symlink: No such file or directory
-\end{Console}
-%$
-con un errore che può sembrare sbagliato, dato che \cmd{ls} ci ha mostrato
-l'esistenza di \file{symlink}. Se invece scrivessimo su \file{symlink}
-otterremmo la creazione di \file{/tmp/tmp\_file} senza errori.
+\constd{MAXSYMLINKS}. Se il limite viene superato si ha un errore ed
+\var{errno} viene impostata al valore \errcode{ELOOP}, che nella quasi
+totalità dei casi indica appunto che si è creato un collegamento simbolico che
+fa riferimento ad una directory del suo stesso \textit{pathname}.
\itindend{symbolic~link}
nel qual caso \var{errno} assumerà uno dei valori:\footnotemark
\begin{errlist}
\item[\errcode{EACCES}] non si ha il permesso di scrittura sulla directory
- che contiene \param{pathname} o di attraversamento di una delle directory
- superiori.
+ che contiene \param{pathname} o quello di attraversamento per una delle
+ directory superiori.
+ \item[\errcode{EBUSY}] \param{pathname} non può essere rimosso perché è in
+ uso da parte del sistema (in particolare per i cosidetti \textit{silly
+ renames} di NFS).
\item[\errcode{EISDIR}] \param{pathname} si riferisce ad una
directory.
\item[\errcode{EPERM}] il filesystem non consente l'operazione, o la
directory che contiene \param{pathname} ha lo \textit{sticky bit} e non si
- è il proprietario o non si hanno privilegi amministrativi.
+ è il proprietario del file o non si hanno privilegi amministrativi.
\end{errlist} ed inoltre \errval{EFAULT}, \errval{EIO}, \errval{ELOOP},
\errval{ENOENT}, \errval{ENOMEM}, \errval{ENOTDIR}, \errval{EROFS} nel loro
significato generico.}
La funzione elimina il nome specificato dall'argomento \param{pathname} nella
directory che lo contiene e decrementa il numero di riferimenti nel relativo
-\textit{inode}.\footnote{come per \func{link} queste due operazioni sono
- effettuate all'interno della \textit{system call} in maniera atomica.} Nel
-caso di socket, \textit{fifo} o file di dispositivo rimuove il nome, ma come
-per i file normali i processi che hanno aperto uno di questi oggetti possono
-continuare ad utilizzarli. Nel caso di cancellazione di un collegamento
-simbolico, che consiste solo nel rimando ad un altro file, questo viene
-immediatamente eliminato.
+\textit{inode}; come per \func{link} queste due operazioni sono effettuate
+all'interno della \textit{system call} in maniera atomica rispetto ai
+processi.
+
+Si ricordi che, anche se se ne è rimosso il nome, un file viene realmente
+cancellato soltanto quando il numero di collegamenti mantenuto
+nell'\textit{inode} diventa nullo; solo allora l'\textit{inode} viene
+disallocato e lo spazio che il file occupava sul disco viene liberato.
+
+Si tenga presente comunque che a questo si aggiunge sempre un'ulteriore
+condizione e cioè che non ci siano processi che stiano ancora lavorando sul il
+file. Come vedremo in sez.~\ref{sec:file_unix_interface} il kernel una tabella
+di tutti file aperti da ciascun processo, che a sua volta contiene i
+riferimenti agli \textit{inode} ad essi relativi. Prima di procedere alla
+cancellazione dello spazio occupato su disco dal contenuto di un file il
+kernel controlla anche questa tabella, per verificare che anche in essa non ci
+sia più nessun riferimento all'\textit{inode} in questione, assicurandosi con
+questo che nessun processo stia ancora usando il file.
+
+Nel caso di socket, \textit{fifo} o file di dispositivo la funzione rimuove il
+nome, e come per i file normali i processi che hanno aperto uno di questi
+oggetti possono continuare ad utilizzarli. Nel caso di cancellazione di un
+\textit{link} simbolico, che consiste solo nel rimando ad un altro file,
+questo viene immediatamente eliminato e non sarà più utilizzabile.
Per cancellare una voce in una directory è necessario avere il permesso di
scrittura su di essa, dato che si va a rimuovere una voce dal suo contenuto, e
il diritto di esecuzione/attraversamento sulla directory che la contiene
(affronteremo in dettaglio l'argomento dei permessi di file e directory in
-sez.~\ref{sec:file_access_control}). Se inoltre lo \textit{sticky bit} (vedi
-sez.~\ref{sec:file_special_perm}) è impostato occorrerà anche essere
-proprietari del file o proprietari della directory o avere i privilegi di
-amministratore.
-
-Si ricordi inoltre che anche se se ne è rimosso il nome da una directory, un
-file non viene eliminato dal disco fintanto che tutti i riferimenti ad esso
-sono stati cancellati: solo quando il numero di collegamenti mantenuto
-nell'\textit{inode} diventa nullo, questo viene disallocato e lo spazio
-occupato su disco viene liberato. Si tenga presente comunque che a questo si
-aggiunge sempre un'ulteriore condizione e cioè che non ci siano processi che
-abbiano il suddetto file aperto.\footnote{come vedremo in
- sez.~\ref{sec:file_unix_interface} il kernel mantiene anche una tabella dei
- file aperti nei vari processi, che a sua volta contiene i riferimenti agli
- \textit{inode} ad essi relativi; prima di procedere alla cancellazione dello
- spazio occupato su disco dal contenuto di un file il kernel controlla anche
- questa tabella, per verificare che anche in essa non ci sia più nessun
- riferimento all'\textit{inode} in questione.}
-
-Questa caratteristica del sistema può essere usata per essere sicuri di non
-lasciare file temporanei su disco in caso di crash di un programma. La tecnica
-è quella di aprire un nuovo file e chiamare \func{unlink} su di esso subito
+sez.~\ref{sec:file_access_control}). Se inoltre per la directory è impostato
+lo \textit{sticky bit} (vedi sez.~\ref{sec:file_special_perm}), occorrerà
+anche essere proprietari del file o proprietari della directory o avere i
+privilegi di amministratore.
+
+Questa caratteristica del sistema, che consente di usare un file anche se lo
+si è ``cancellato'', può essere usata per essere sicuri di non lasciare file
+temporanei su disco in caso di uscita imprevista di un programma. La tecnica è
+quella di aprire un nuovo file e chiamare \func{unlink} su di esso subito
dopo, in questo modo il contenuto del file sarà sempre disponibile all'interno
del processo attraverso il suo file descriptor (vedi sez.~\ref{sec:file_fd}),
-ma non ne resta traccia in nessuna directory, e lo spazio occupato su disco
-viene immediatamente rilasciato alla conclusione del processo, quando tutti i
-file vengono chiusi.
+ma non ne resterà traccia in nessuna directory, inoltre lo spazio occupato su
+disco verrà immediatamente rilasciato alla conclusione del processo, quando
+tutti i file vengono chiusi.
Al contrario di quanto avviene con altri Unix, in Linux non è possibile usare
-la funzione \func{unlink} sulle directory, nel qual caso si otterrebbe un
+la funzione \func{unlink} sulle directory, che in tal caso fallisce con un
errore di \errcode{EISDIR}. Per cancellare una directory si deve usare la
apposita funzione di sistema \func{rmdir} (che vedremo in
sez.~\ref{sec:file_dir_creat_rem}), oppure la funzione \func{remove}.
+
Quest'ultima è la funzione prevista dallo standard ANSI C per effettuare una
-cancellazione generica di un file o di una directory e funziona anche per i
-sistemi operativo che non supportano gli \textit{hard link}. Nei sistemi
-unix-like \funcd{remove} è equivalente ad usare in maniera trasparente
+cancellazione generica di un file o di una directory e viene usata in generale
+anche per i sistemi operativi che non supportano gli \textit{hard link}. Nei
+sistemi unix-like \funcd{remove} è equivalente ad usare in maniera trasparente
\func{unlink} per i file ed \func{rmdir} per le directory; il suo prototipo è:
\begin{funcproto}{
\func{unlink} e \func{rmdir}.}
\end{funcproto}
-La funzione utilizza la funzione \func{unlink} per cancellare i file e la
-funzione \func{rmdir} (vedi sez.~\ref{sec:file_dir_creat_rem}) per cancellare
-le directory.\footnote{questo vale usando la \acr{glibc}; nella \acr{libc4} e
- nella \acr{libc5} la funzione \func{remove} era un semplice alias alla
- funzione \func{unlink} e quindi non poteva essere usata per le directory.}
-Si tenga presente che per alcune implementazioni del protocollo NFS utilizzare
-questa funzione può comportare la scomparsa di file ancora in uso.
+La funzione utilizza la funzione \func{unlink} per cancellare i file (e si
+applica anche a link simbolici, socket, \textit{fifo} e file di dispostivo) e
+la funzione \func{rmdir} (vedi sez.~\ref{sec:file_dir_creat_rem}) per
+cancellare le directory.\footnote{questo vale usando la \acr{glibc}; nella
+ \acr{libc4} e nella \acr{libc5} la funzione \func{remove} era un semplice
+ alias alla funzione \func{unlink} e quindi non poteva essere usata per le
+ directory.} Si tenga presente che per alcune limitazioni del protocollo
+NFS, utilizzare questa funzione su file che usano questo filesystem di rete
+può comportare la scomparsa di file ancora in uso.
Infine per cambiare nome ad un file o a una directory si usa la funzione di
sistema \funcd{rename},\footnote{la funzione è definita dallo standard ANSI C,
{La funzione ritorna $0$ in caso di successo e $-1$ per un errore,
nel qual caso \var{errno} assumerà uno dei valori:
\begin{errlist}
- \item[\errcode{EACCESS}] non c'è permesso di scrivere nelle directory
+ \item[\errcode{EACCESS}] manca il permesso di scrittura sulle directory
contenenti \param{oldpath} e \param{newpath} o di attraversare
- quelle dei loro \textit{pathname} o di scrivere su \param{newpath}
+ il loro \textit{pathname} o di scrivere su \param{newpath}
se questa è una directory.
\item[\errcode{EBUSY}] o \param{oldpath} o \param{newpath} sono in uso da
parte di qualche processo (come directory di lavoro o come radice) o del