X-Git-Url: https://gapil.gnulinux.it/gitweb/?a=blobdiff_plain;f=filedir.tex;h=87913fe9e3b99e027f946537bafa771411498a98;hb=f486510bed043527644e38f161d1bf69e09039e9;hp=34e64d9ddc6929cf1bc41a6f9cf8ee6886493daf;hpb=ae0f5a752ec86bf15b78031f4b33664a8c0b515b;p=gapil.git diff --git a/filedir.tex b/filedir.tex index 34e64d9..b077277 100644 --- a/filedir.tex +++ b/filedir.tex @@ -1,539 +1,6743 @@ -\chapter{Files e directories} +%% filedir.tex +%% +%% Copyright (C) 2000-2018 Simone Piccardi. Permission is granted to +%% copy, distribute and/or modify this document under the terms of the GNU Free +%% Documentation License, Version 1.1 or any later version published by the +%% Free Software Foundation; with the Invariant Sections being "Un preambolo", +%% with no Front-Cover Texts, and with no Back-Cover Texts. A copy of the +%% license is included in the section entitled "GNU Free Documentation +%% License". +%% + +\chapter{La gestione di file e directory} \label{cha:files_and_dirs} -In questo capitolo tratteremo in dettaglio le varie caratteristiche di files e -directories, ed in particolare approfondiremo i dettagli su come è organizzata -la struttura dei files in un sistema unix; esamineremo poi come è strutturato -il sistema base di protezioni e controllo di accesso ai files, e tutta -l'interfaccia che permette la manipolazione dei vari attributi di files e -directories. Tutto quello che riguarda invece la manipolazione dei contenuti e -lasciato ai capitoli successivi. - -Le funzioni che esamineremo in questo capitolo pertanto sono quelle che -permettono di creare e cancellare o leggere le directories, rinominare o -cancellare i files ed esaminare o cambiare i loro attributi. - - -\section{L'organizzazione di files e directories} -\label{sec:filedir_org} - -L'organizzazione dei nomi dei file deriva direttamente dall'organizzazione dei -medesimi nell'albero descritto brevemente in \secref{sec:fileintr_overview}; -una directory comunque, come già specificato in \secref{sec:fileintr_vfs}, è -solo un particolare tipo di file che contiene le informazioni che associano un -nome al contenuto. Per questo, anche se è usuale parlare di ``file in una -directory'' in realtà una directory contiene solo delle etichette per fare -riferimento ai file stessi. - -I manuale delle librerie del C chiama i nomi contenuti nelle directory -\textsl{componenti} (in inglese \textit{file name components}), noi li -chiameremo più semplicemente nomi. Un file può essere indicato rispetto alla -directory corrente semplicemente specificando il nome da essa contenuto. Una -directory contiene semplicemente un elenco di questi nomi, che possono -corrispondere a un qualunque oggetto del filesystem, compresa un'altra -directory; l'albero viene appunto creato inserendo directory in altre -directory. +In questo capitolo tratteremo in dettaglio le modalità con cui si gestiscono +file e directory, iniziando da un approfondimento dell'architettura del +sistema illustrata a grandi linee in sez.~\ref{sec:file_arch_overview} ed +illustrando le principali caratteristiche di un filesystem e le interfacce +che consentono di controllarne il montaggio e lo smontaggio. + +Esamineremo poi le funzioni di libreria che si usano per copiare, spostare e +cambiare i nomi di file e directory e l'interfaccia che permette la +manipolazione dei loro attributi. Tratteremo inoltre la struttura di base del +sistema delle protezioni e del controllo dell'accesso ai file e le successive +estensioni (\textit{Extended Attributes}, ACL, quote disco). Tutto quello che +riguarda invece la gestione dell'I/O sui file è lasciato al capitolo +successivo. + + + +\section{L'architettura della gestione dei file} +\label{sec:file_arch_func} + +In questa sezione tratteremo con maggiori dettagli rispetto a quanto visto in +sez.~\ref{sec:file_arch_overview} il \textit{Virtual File System} di Linux e +come il kernel può gestire diversi tipi di filesystem, descrivendo prima le +caratteristiche generali di un filesystem di un sistema unix-like, per poi +fare una panoramica sul filesystem tradizionalmente più usato con Linux, +l'\acr{ext2} ed i suoi successori. + + +\subsection{Il funzionamento del \textit{Virtual File System} di Linux} +\label{sec:file_vfs_work} + +% NOTE articolo interessante: +% http://www.ibm.com/developerworks/linux/library/l-virtual-filesystem-switch/index.html?ca=dgr-lnxw97Linux-VFSdth-LXdW&S_TACT=105AGX59&S_CMP=GRlnxw97 + +\itindbeg{Virtual~File~System~(VFS)} + +Come illustrato brevemente in sez.~\ref{sec:file_arch_overview} in Linux il +concetto di \textit{everything is a file} è stato implementato attraverso il +\textit{Virtual File System}, la cui struttura generale è illustrata in +fig.~\ref{fig:file_VFS_scheme}. Il VFS definisce un insieme di funzioni che +tutti i filesystem devono implementare per l'accesso ai file che contengono e +l'interfaccia che consente di eseguire l'I/O sui file, che questi siano di +dati o dispositivi. + +\itindbeg{inode} + +L'interfaccia fornita dal VFS comprende in sostanza tutte le funzioni che +riguardano i file, le operazioni implementate dal VFS sono realizzate con una +astrazione che prevede quattro tipi di oggetti strettamente correlati: i +filesystem, le \textit{dentry}, gli \textit{inode} ed i file. A questi oggetti +corrispondono una serie di apposite strutture definite dal kernel che +contengono come campi le funzioni di gestione e realizzano l'infrastruttura +del VFS. L'interfaccia è molto complessa, ne faremo pertanto una trattazione +estremamente semplificata che consenta di comprenderne i principi +di funzionamento. + +Il VFS usa una tabella mantenuta dal kernel che contiene il nome di ciascun +filesystem supportato, quando si vuole inserire il supporto di un nuovo +filesystem tutto quello che occorre è chiamare la funzione +\code{register\_filesystem} passando come argomento la struttura +\kstruct{file\_system\_type} (la cui definizione è riportata in +fig.~\ref{fig:kstruct_file_system_type}) relativa a quel filesystem. Questa +verrà inserita nella tabella, ed il nuovo filesystem comparirà in +\procfile{/proc/filesystems}. + +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{0.80\textwidth} + \includestruct{listati/file_system_type.h} + \end{minipage} + \normalsize + \caption{Estratto della struttura \kstructd{file\_system\_type} usata dal + VFS (da \texttt{include/linux/fs.h}).} + \label{fig:kstruct_file_system_type} +\end{figure} + +La struttura \kstruct{file\_system\_type}, oltre ad una serie di dati interni, +come il nome del tipo di filesystem nel campo \var{name},\footnote{quello che + viene riportato in \procfile{/proc/filesystems} e che viene usato come + valore del parametro dell'opzione \texttt{-t} del comando \texttt{mount} che + indica il tipo di filesystem.} contiene i riferimenti alle funzioni di base +che consentono l'utilizzo di quel filesystem. In particolare la funzione +\code{mount} del quarto campo è quella che verrà invocata tutte le volte che +si dovrà effettuare il montaggio di un filesystem di quel tipo. Per ogni nuovo +filesystem si dovrà allocare una di queste strutture ed inizializzare i +relativi campi con i dati specifici di quel filesystem, ed in particolare si +dovrà creare anche la relativa versione della funzione \code{mount}. + +\itindbeg{pathname} +\itindbeg{pathname~resolution} + +Come illustrato in fig.~\ref{fig:kstruct_file_system_type} questa funzione +restituisce una \textit{dentry}, abbreviazione che sta per \textit{directory + entry}. Le \textit{dentry} sono gli oggetti che il kernel usa per eseguire +la \textit{pathname resolution}, ciascuna di esse corrisponde ad un +\textit{pathname} e contiene il riferimento ad un \textit{inode}, che come +vedremo a breve è l'oggetto usato dal kernel per identificare un +file.\footnote{in questo caso si parla di file come di un qualunque oggetto + generico che sta sul filesystem e non dell'oggetto file del VFS cui + accennavamo prima.} La \textit{dentry} ottenuta dalla chiamata alla funzione +\code{mount} sarà inserita in corrispondenza al \textit{pathname} della +directory in cui il filesystem è stato montato. + +% NOTA: struct dentry è dichiarata in include/linux/dcache.h + +Le \textit{dentry} sono oggetti del VFS che vivono esclusivamente in memoria, +nella cosiddetta \textit{directory entry cache} (spesso chiamata in breve +\textit{dcache}). Ogni volta che una \textit{system call} specifica un +\textit{pathname} viene effettuata una ricerca nella \textit{dcache} per +ottenere immediatamente la \textit{dentry} corrispondente,\footnote{il buon + funzionamento della \textit{dcache} è in effetti di una delle parti più + critiche per le prestazioni del sistema.} che a sua volta ci darà, tramite +l'\textit{inode}, il riferimento al file. + +Dato che normalmente non è possibile mantenere nella \textit{dcache} le +informazioni relative a tutto l'albero dei file la procedura della +\textit{pathname resolution} richiede un meccanismo con cui riempire gli +eventuali vuoti. Il meccanismo prevede che tutte le volte che si arriva ad una +\textit{dentry} mancante venga invocata la funzione \texttt{lookup} +dell'\textit{inode} associato alla \textit{dentry} precedente nella +risoluzione del \textit{pathname},\footnote{che a questo punto è una + directory, per cui si può cercare al suo interno il nome di un file.} il cui +scopo è risolvere il nome mancante e fornire la sua \textit{dentry} che a +questo punto verrà inserita nella cache. + +Dato che tutte le volte che si monta un filesystem la funzione \texttt{mount} +(vedi sez.~\ref{sec:filesystem_mounting}) della corrispondente +\kstruct{file\_system\_type} inserisce la \textit{dentry} iniziale nel +\textit{mount point} dello stesso, si avrà comunque un punto di +partenza. Inoltre essendo questa \textit{dentry} relativa a quel tipo di +filesystem essa farà riferimento ad un \textit{inode} di quel filesystem, e +come vedremo questo farà sì che venga eseguita una \texttt{lookup} adatta per +effettuare la risoluzione dei nomi per quel filesystem. + +\itindend{pathname} +\itindend{pathname~resolution} + +% Un secondo effetto della chiamata funzione \texttt{mount} di +% \kstruct{file\_system\_type} è quello di allocare una struttura +% \kstruct{super\_block} per ciascuna istanza montata, che contiene le +% informazioni generali di un qualunque filesystem montato, come le opzioni di +% montaggio, le dimensioni dei blocchi, quando il filesystem è stato montato +% ecc. Fra queste però viene pure inserta, nel campo \var{s\_op}, una ulteriore +% struttura \kstruct{super\_operations}, il cui contenuto sono i puntatori +% alle funzioni di gestione di un filesystem, anche inizializzata in modo da +% utilizzare le versioni specifiche di quel filesystem. + +L'oggetto più importante per il funzionamento del VFS è probabilmente +l'\textit{inode}, ma con questo nome si può fare riferimento a due cose +diverse. La prima è la struttura su disco (su cui torneremo anche in +sez.~\ref{sec:file_filesystem}) che fa parte della organizzazione dei dati +realizzata dal filesystem e che contiene le informazioni relative alle +proprietà (i cosiddetti \textsl{metadati}) di ogni oggetto presente su di esso +(si intende al solito uno qualunque dei tipi di file di +tab.~\ref{tab:file_file_types}). + +La seconda è la corrispondente struttura \kstruct{inode}, della cui +definizione si è riportato un estratto in +fig.~\ref{fig:kstruct_inode}.\footnote{l'estratto fa riferimento alla versione + del kernel 2.6.37.} Questa struttura viene mantenuta in memoria ed è a +questa che facevamo riferimento quando parlavamo dell'\textit{inode} associato +a ciascuna \textit{dentry}. Nella struttura in memoria sono presenti gli +stessi \textsl{metadati} memorizzati su disco, che vengono letti quando questa +struttura viene allocata e trascritti all'indietro se modificati. + +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{0.8\textwidth} + \includestruct{listati/inode.h} + \end{minipage} + \normalsize + \caption{Estratto della struttura \kstructd{inode} del kernel (da + \texttt{include/linux/fs.h}).} + \label{fig:kstruct_inode} +\end{figure} + +Il fatto che la struttura \kstruct{inode} sia mantenuta in memoria, +direttamente associata ad una \textit{dentry}, rende sostanzialmente immediate +le operazioni che devono semplicemente effettuare un accesso ai dati in essa +contenuti: è così ad esempio che viene realizzata la \textit{system call} +\func{stat} che vedremo in sez.~\ref{sec:file_stat}. Rispetto ai dati salvati +sul disco questa struttura contiene però anche quanto necessario alla +implementazione del VFS, ed in particolare è importante il campo \var{i\_op} +che, come illustrato in fig.~\ref{fig:kstruct_inode}, contiene il puntatore ad +una struttura di tipo \kstruct{inode\_operation}, la cui definizione si può +trovare nel file \texttt{include/kernel/fs.h} dei sorgenti del kernel. + +Questa struttura non è altro che una tabella di funzioni, ogni suo membro cioè +è un puntatore ad una funzione e, come suggerisce il nome della struttura +stessa, queste funzioni sono quelle che definiscono le operazioni che il VFS +può compiere su un \textit{inode}. Si sono riportate in +tab.~\ref{tab:file_inode_operations} le più rilevanti. -Il nome completo di file generico è composto da una serie di questi -\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}, e anche se il manuale della -glibc depreca questo nome (poichè genererebbe confusione, dato che con -\textit{path} si indica anche un insieme di directory su cui effettuare una -ricerca, come quello in cui si cercano i comandi) l'uso è ormai così comune -che è senz'altro più chiaro dell'alternativa proposta. - -Il processo con cui si associa ad un pathname uno specifico file è chiamato -risoluzione del nome (\textit{file name resolution} o \textit{pathname - resolution}). La risoluzione viene fatta esaminando il pathname da destra a -sinistra e localizzando ogni nome nella directory indicata dal nome -precedente: ovviamente perché il procedimento funzioni occorre che i nomi -indicati come directory esistano e siano effettivamente directory, inoltre i -permessi devono consentire l'accesso. - -Se il pathname comincia per \texttt{/} la ricerca parte dalla directory radice -del processo; questa, a meno di un \textit{chroot} (su cui torneremo in -seguito, vedi \secref{sec:proc_chroot}) è la stessa per tutti i processi ed -equivale alla directory radice dell'albero (come descritto in -\secref{sec:fileintr_overview}): in questo caso si parla di un pathname -\textsl{assoluto}. Altrimenti la ricerca parte dalla directory corrente (su -cui torneremo più avanti in \secref{sec:filedir_work_dir}) ed il pathname è -detto \textsl{relativo}. - -I nomi \texttt{.} e \texttt{..} hanno un significato speciale e vengono -inseriti in ogni directory, il primo fa riferimento alla directory corrente e -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. - - -\section{La manipolazione di files e directories} -\label{sec:filedir_handling} - -Per capire fino in fondo le proprietà di files e directories in un sistema -unix ed il funzionamento delle relative funzioni di manipolazione occorre una -breve introduzione agli oggetti su cui è basato un filesystem unix; in -particolare si riprenderà, approfondendolo sul piano dell'uso nelle funzioni -di libreria, il concetto di \textit{inode} di cui abbiamo brevemente accennato -le caratteristiche (dal lato dell'implementazione nel kernel) in -\secref{sec:fileintr_vfs}. - - -\subsection{Il funzionamento di un filesystem} -\label{sec:filedir_filesystem} - -Come già accennato in \secref{sec:fileintr_overview} linux (ed ogni unix in -generale) organizza i dati che tiene su disco attraverso l'uso di un -filesystem. Una delle caratteristiche di linux rispetto agli altri unix è -quella di poter supportare grazie al VFS una enorme quantità di filesystem -diversi, ognuno dei quali ha una sua particolare struttura e funzionalità -proprie; per questo non entreremo nei dettagli di un filesystem specifico, ma +\begin{table}[htb] + \centering + \footnotesize + \begin{tabular}[c]{|l|l|} + \hline + \textbf{Funzione} & \textbf{Operazione} \\ + \hline + \hline + \textsl{\code{create}} & Chiamata per creare un nuovo file (vedi + sez.~\ref{sec:file_open_close}).\\ + \textsl{\code{link}} & Crea un \textit{hard link} (vedi + sez.~\ref{sec:link_symlink_rename}).\\ + \textsl{\code{unlink}} & Cancella un \textit{hard link} (vedi + sez.~\ref{sec:link_symlink_rename}).\\ + \textsl{\code{symlink}}& Crea un collegamento simbolico (vedi + sez.~\ref{sec:link_symlink_rename}).\\ + \textsl{\code{mkdir}} & Crea una directory (vedi + sez.~\ref{sec:file_dir_creat_rem}).\\ + \textsl{\code{rmdir}} & Rimuove una directory (vedi + sez.~\ref{sec:file_dir_creat_rem}).\\ + \textsl{\code{mknod}} & Crea un file speciale (vedi + sez.~\ref{sec:file_mknod}).\\ + \textsl{\code{rename}} & Cambia il nome di un file (vedi + sez.~\ref{sec:link_symlink_rename}).\\ + \textsl{\code{lookup}}& Risolve il nome di un file.\\ + \hline + \end{tabular} + \caption{Le principali operazioni sugli \textit{inode} definite tramite + \kstructd{inode\_operation}.} + \label{tab:file_inode_operations} +\end{table} + +Possiamo notare come molte di queste funzioni abbiano nomi sostanzialmente +identici alle varie \textit{system call} con le quali si gestiscono file e +directory, che tratteremo nel resto del capitolo. Quello che succede è che +tutte le volte che deve essere eseguita una \textit{system call}, o una +qualunque altra operazione su un \textit{inode} (come \texttt{lookup}) il VFS +andrà ad utilizzare la funzione corrispondente attraverso il puntatore +\var{i\_op}. + +Sarà allora sufficiente che nella realizzazione di un filesystem si crei una +implementazione di queste funzioni per quel filesystem e si allochi una +opportuna istanza di \kstruct{inode\_operation} contenente i puntatori a dette +funzioni. A quel punto le strutture \kstruct{inode} usate per gli oggetti di +quel filesystem otterranno il puntatore alla relativa istanza di +\kstruct{inode\_operation} e verranno automaticamente usate le funzioni +corrette. + +Si noti però come in tab.~\ref{tab:file_inode_operations} non sia presente la +funzione \texttt{open} che invece è citata in +tab.~\ref{tab:file_file_operations}.\footnote{essa può essere comunque + invocata dato che nella struttura \kstruct{inode} è presente anche il + puntatore \var{i\_fop} alla struttura \kstruct{file\_operation} che fornisce + detta funzione.} Questo avviene perché su Linux l'apertura di un file +richiede comunque un'altra operazione che mette in gioco l'omonimo oggetto del +VFS: l'allocazione di una struttura di tipo \kstruct{file} che viene associata +ad ogni file aperto nel sistema. I motivi per cui viene usata una struttura a +parte sono diversi, anzitutto, come illustrato in sez.~\ref{sec:file_fd}, +questa è necessaria per le operazioni eseguite dai processi con l'interfaccia +dei file descriptor. Ogni processo infatti mantiene il riferimento ad una +struttura \kstruct{file} per ogni file che ha aperto, ed è tramite essa che +esegue le operazioni di I/O. Inoltre il kernel mantiene un elenco di tutti i +file aperti nella \textit{file table} (torneremo su questo in +sez.~\ref{sec:file_fd}). + +Inoltre se le operazioni relative agli \textit{inode} fanno riferimento ad +oggetti posti all'interno di un filesystem e vi si applicano quindi le +funzioni fornite nell'implementazione di quest'ultimo, quando si apre un file +questo può essere anche un file di dispositivo, ed in questo caso il VFS +invece di usare le operazioni fornite dal filesystem (come farebbe per un file +di dati) dovrà invece ricorrere a quelle fornite dal driver del dispositivo. + +\itindend{inode} + +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{0.8\textwidth} + \includestruct{listati/file.h} + \end{minipage} + \normalsize + \caption{Estratto della struttura \kstructd{file} del kernel (da + \texttt{include/linux/fs.h}).} + \label{fig:kstruct_file} +\end{figure} + +Come si può notare dall'estratto di fig.~\ref{fig:kstruct_file}, la struttura +\kstruct{file} contiene, oltre ad alcune informazioni usate dall'interfaccia +dei file descriptor il cui significato emergerà più avanti, il puntatore +\var{f\_op} ad una struttura \kstruct{file\_operation}. Questa è l'analoga per +i file di \kstruct{inode\_operation}, e definisce le operazioni generiche +fornite dal VFS per i file. Si sono riportate in +tab.~\ref{tab:file_file_operations} le più significative. + +\begin{table}[htb] + \centering + \footnotesize + \begin{tabular}[c]{|l|p{8cm}|} + \hline + \textbf{Funzione} & \textbf{Operazione} \\ + \hline + \hline + \textsl{\code{open}} & Apre il file (vedi + sez.~\ref{sec:file_open_close}).\\ + \textsl{\code{read}} & Legge dal file (vedi sez.~\ref{sec:file_read}).\\ + \textsl{\code{write}} & Scrive sul file (vedi + sez.~\ref{sec:file_write}).\\ + \textsl{\code{llseek}} & Sposta la posizione corrente sul file (vedi + sez.~\ref{sec:file_lseek}).\\ + \textsl{\code{ioctl}} & Accede alle operazioni di controllo + (vedi sez.~\ref{sec:file_fcntl_ioctl}).\\ + \textsl{\code{readdir}}& Legge il contenuto di una directory (vedi + sez.~\ref{sec:file_dir_read}).\\ + \textsl{\code{poll}} & Usata nell'I/O multiplexing (vedi + sez.~\ref{sec:file_multiplexing}).\\ + \textsl{\code{mmap}} & Mappa il file in memoria (vedi + sez.~\ref{sec:file_memory_map}).\\ + \textsl{\code{release}}& Chiamata quando l'ultimo riferimento a un file + aperto è chiuso.\\ + \textsl{\code{fsync}} & Sincronizza il contenuto del file (vedi + sez.~\ref{sec:file_sync}).\\ + \textsl{\code{fasync}} & Abilita l'I/O asincrono (vedi + sez.~\ref{sec:file_asyncronous_io}) sul file.\\ + \hline + \end{tabular} + \caption{Operazioni sui file definite tramite \kstructd{file\_operation}.} + \label{tab:file_file_operations} +\end{table} + +Anche in questo caso tutte le volte che deve essere eseguita una +\textit{system call} o una qualunque altra operazione sul file il VFS andrà ad +utilizzare la funzione corrispondente attraverso il puntatore +\var{f\_op}. Dato che è cura del VFS quando crea la struttura all'apertura del +file assegnare a \var{f\_op} il puntatore alla versione di +\kstruct{file\_operation} corretta per quel file, sarà possibile scrivere allo +stesso modo sulla porta seriale come su un normale file di dati, e lavorare +sui file allo stesso modo indipendentemente dal filesystem. + +Il VFS realizza la quasi totalità delle operazioni relative ai file grazie +alle funzioni presenti nelle due strutture \kstruct{inode\_operation} e +\kstruct{file\_operation}. Ovviamente non è detto che tutte le operazioni +possibili siano poi disponibili in tutti i casi, ad esempio \code{llseek} non +sarà presente per un dispositivo come la porta seriale o per una +\textit{fifo}, mentre sui file del filesystem \texttt{vfat} non saranno +disponibili i permessi, ma resta il fatto che grazie al VFS le \textit{system + call} per le operazioni sui file possono restare sempre le stesse nonostante +le enormi differenze che possono esserci negli oggetti a cui si applicano. + + +\itindend{Virtual~File~System~(VFS)} + +% NOTE: documentazione interessante: +% * sorgenti del kernel: Documentation/filesystems/vfs.txt +% * http://thecoffeedesk.com/geocities/rkfs.html +% * http://www.linux.it/~rubini/docs/vfs/vfs.html + + + +\subsection{Il funzionamento di un filesystem Unix} +\label{sec:file_filesystem} + +Come già accennato in sez.~\ref{sec:file_arch_overview} Linux (ed ogni sistema +unix-like) organizza i dati che tiene su disco attraverso l'uso di un +filesystem. Una delle caratteristiche di Linux rispetto agli altri Unix è +quella di poter supportare, grazie al VFS, una enorme quantità di filesystem +diversi, ognuno dei quali avrà una sua particolare struttura e funzionalità +proprie. Per questo non entreremo nei dettagli di un filesystem specifico, ma daremo una descrizione a grandi linee che si adatta alle caratteristiche -comuni di un qualunque filesystem standard unix. +comuni di qualunque filesystem di un sistema unix-like. -Dato un disco lo spazio fisico viene usualmente diviso in partizioni; ogni -partizione può contenere un filesystem; quest'ultimo è in genere strutturato -secondo \nfig, con una lista di inodes all'inizio e il resto dello spazio a -disposizione per i dati e le directory. +\itindbeg{superblock} -\begin{figure}[htb] +Una possibile strutturazione dell'informazione su un disco è riportata in +fig.~\ref{fig:file_disk_filesys}, dove si hanno tre filesystem su tre +partizioni. In essa per semplicità si è fatto riferimento alla struttura del +filesystem \acr{ext2}, che prevede una suddivisione dei dati in \textit{block + group}. All'interno di ciascun \textit{block group} viene anzitutto +replicato il cosiddetto \textit{superblock}, (la struttura che contiene +l'indice iniziale del filesystem e che consente di accedere a tutti i dati +sottostanti) e creata una opportuna suddivisione dei dati e delle informazioni +per accedere agli stessi. Sulle caratteristiche di \acr{ext2} e derivati +torneremo in sez.~\ref{sec:file_ext2}. + +\itindend{superblock} +\itindbeg{inode} + +È comunque caratteristica comune di tutti i filesystem per Unix, +indipendentemente da come poi viene strutturata nei dettagli questa +informazione, prevedere la presenza di due tipi di risorse: gli +\textit{inode}, cui abbiamo già accennato in sez.~\ref{sec:file_vfs_work}, che +sono le strutture che identificano i singoli oggetti sul filesystem, e i +blocchi, che invece attengono allo spazio disco che viene messo a disposizione +per i dati in essi contenuti. + +\begin{figure}[!htb] \centering - - \caption{Organizzazione dello spazio su un disco in partizioni e filesystem} - \label{fig:filedir_disk_filesys} + \includegraphics[width=11cm]{img/disk_struct} + \caption{Organizzazione dello spazio su un disco in partizioni e + filesystem.} + \label{fig:file_disk_filesys} \end{figure} -Se si va ad esaminare come è strutturata l'informazione all'interno di un -singolo filesystem (tralasciando le parti connesse alla strutturazione e al -funzionamento del filesystem stesso come il super-block) avremo una situazione -del tipo di quella esposta in \nfig. -\begin{figure}[htb] +Se si va ad esaminare con maggiore dettaglio la strutturazione +dell'informazione all'interno del filesystem \textsl{ext2}, tralasciando i +dettagli relativi al funzionamento del filesystem stesso come la +strutturazione in gruppi dei blocchi, il \textit{superblock} e tutti i dati di +gestione possiamo esemplificare la situazione con uno schema come quello +esposto in fig.~\ref{fig:file_filesys_detail}. + +\begin{figure}[!htb] \centering - - \caption{Organizzazione di un filesystem} - \label{fig:filedir_filesys_detail} + \includegraphics[width=11cm]{img/filesys_struct} + \caption{Strutturazione dei dati all'interno di un filesystem.} + \label{fig:file_filesys_detail} \end{figure} -da questa figura si evidenzano alcune caratteristiche su cui è bene porre -attenzione in quanto sono fondamentali per capire il funzionamento delle -funzioni che manipolano i file e le directory su cui torneremo fra poco; in -particolare è opportuno ricordare sempre che: -\begin{enumerate} +Da fig.~\ref{fig:file_filesys_detail} si evidenziano alcune delle +caratteristiche di base di un filesystem, che restano le stesse anche su +filesystem la cui organizzazione dei dati è totalmente diversa da quella +illustrata, e sulle quali è bene porre attenzione visto che sono fondamentali +per capire il funzionamento delle funzioni che manipolano i file e le +directory che tratteremo nel prosieguo del capitolo. In particolare è +opportuno tenere sempre presente che: + + +\begin{enumerate*} -\item L'\textit{inode} contiene tutte le informazioni riguardanti il file: il - tipo di file, i permessi di accesso, le dimensioni, i puntatori ai blocchi - fisici che contengono i dati e così via; le informazioni che la funzione - \texttt{stat} fornisce provengono dall'\textit{inode}; dentro una directory - si troverà solo il nome del file e il numero dell'\textit{inode} ad esso - associato, cioè quella che da qui in poi chiameremo una \textsl{voce} - (traduzione approssimata dell'inglese \textit{directory entry}, che non - useremo anche per evitare confusione con le \textit{dentries} del kernel di - cui si parlava in \secref{sec:fileintr_vfs}). +\item L'\textit{inode} contiene i cosiddetti \textsl{metadati}, vale dire le + informazioni riguardanti le proprietà del file come oggetto del filesystem: + il tipo di file, i permessi di accesso, le dimensioni, i puntatori ai + blocchi fisici che contengono i dati e così via. Le informazioni che la + funzione \func{stat} (vedi sez.~\ref{sec:file_stat}) fornisce provengono + dall'\textit{inode}. Dentro una directory si troverà solo il nome del file + e il numero dell'\textit{inode} ad esso associato; il nome non è una + proprietà del file e non viene mantenuto nell'\textit{inode}. Da da qui in + poi chiameremo il nome del file contenuto in una directory + ``\textsl{voce}'', come traduzione della nomenclatura inglese + \textit{directory entry} che non useremo per evitare confusione con le + \textit{dentry} del kernel viste in sez.~\ref{sec:file_vfs_work}. -\item Come mostrato in \curfig si possono avere più voci che puntano allo - stesso \textit{inode}. Ogni \textit{inode} ha un contatore che contiene il - numero di riferimenti (\textit{link count}) che sono stati fatti ad esso, - solo quando questo contatore si annulla i dati del file vengono - effettivamente rimossi dal disco. Per questo la funzione per cancellare un - file si chiama \texttt{unlink}, ed in realtà non cancella affatto i dati del - file, ma si limita a eliminare la relativa voce da una directory e - decrementare il numero di riferimenti nell'\textit{inode}. +\item Come mostrato in fig.~\ref{fig:file_filesys_detail} per i file + \texttt{macro.tex} e \texttt{gapil\_macro.tex}, ci possono avere più voci + che fanno riferimento allo stesso \textit{inode}. Fra le proprietà di un + file mantenute nell'\textit{inode} c'è anche il contatore con il numero di + riferimenti che sono stati fatti ad esso, il cosiddetto \textit{link + count}.\footnote{mantenuto anche nel campo \var{i\_nlink} della struttura + \kstruct{inode} di fig.~\ref{fig:kstruct_inode}.} Solo quando questo + contatore si annulla i dati del file possono essere effettivamente rimossi + dal disco. Per questo la funzione per cancellare un file si chiama + \func{unlink} (vedi sez.~\ref{sec:link_symlink_rename}), ed in realtà non + cancella affatto i dati del file, ma si limita ad eliminare la relativa voce + da una directory e decrementare il numero di riferimenti + nell'\textit{inode}. -\item Il numero di \textit{inode} nella voce si riferisce ad un \textit{inode} - nello stesso filesystem e non ci può essere una directory che contiene - riferimenti ad \textit{inodes} relativi ad altri filesystem. Questo limita - l'uso del comando \texttt{ln} (che crea una nuova voce per un file - esistente, con la funzione \texttt{link}) al filesystem corrente. +\item All'interno di ogni filesystem ogni \textit{inode} è identificato da un + numero univoco. Il numero di \textit{inode} associato ad una voce in una + directory si riferisce ad questo numero e non ci può essere una directory + che contiene riferimenti ad \textit{inode} relativi ad altri filesystem. + Questa è la ragione che limita l'uso del comando \cmd{ln}, che crea una + nuova voce per un file esistente con la funzione \func{link} (vedi + sez.~\ref{sec:link_symlink_rename}), a operare su file nel filesystem + corrente. \item Quando si cambia nome ad un file senza cambiare filesystem il contenuto - del file non deve essere spostato, viene semplicemente creata una nuova voce - per l'\textit{inode} in questione e rimossa la vecchia (questa è la modalità - in cui opera normalmente il comando \texttt{mv} attraverso la funzione - \texttt{rename}). + del file non viene spostato fisicamente, viene semplicemente creata una + nuova voce per l'\textit{inode} in questione e rimossa la precedente, questa + è la modalità in cui opera normalmente il comando \cmd{mv} attraverso la + funzione \func{rename} (vedi sez.~\ref{sec:link_symlink_rename}). Questa + operazione non modifica minimamente neanche l'\textit{inode} del file, dato + che non si opera sul file ma sulla directory che lo contiene. -\end{enumerate} +\item Gli \textit{inode} dei file, che contengono i \textsl{metadati}, ed i + blocchi di spazio disco, che contengono i dati, sono risorse indipendenti ed + in genere vengono gestite come tali anche dai diversi filesystem; è pertanto + possibile esaurire sia lo spazio disco (il caso più comune) che lo spazio + per gli \textit{inode}. Nel primo caso non sarà possibile allocare ulteriore + spazio, ma si potranno creare file (vuoti), nel secondo non si potranno + creare nuovi file, ma si potranno estendere quelli che ci + sono.\footnote{questo comportamento non è generale, alcuni filesystem più + sofisticati possono evitare il problema dell'esaurimento degli + \textit{inode} riallocando lo spazio disco libero per i blocchi.} -Infine è bene avere presente che essendo file pure loro, esiste un numero di -riferimenti anche per le directories; per cui se ad esempio a partire dalla -situazione mostrata in \curfig\ creiamo una nuova directory \texttt{textdir} -nella directory corrente avremo una situazione come quella in \nfig, dove per -chiarezza abbiamo aggiunto dei numeri di inode. - -La nuova directory avrà allora un numero di riferimenti pari a due, in quanto -è referenziata dalla directory da cui si era partiti (in cui è inserita la -nuova voce che fa riferimento a \texttt{textdir}) e dalla voce \texttt{.} -che è sempre inserita in ogni directory; questo vale sempre per ogni directory -che non contenga a sua volta altre directories. Al contempo la directory da -cui si era partiti avrà un numero di riferiementi di almeno tre, in quanto -adesso sarà referenziata anche dalla voce \texttt{..} di \texttt{textdir}. - - -\subsection{Le funzioni \texttt{link} e \texttt{unlink}} -\label{sec:filedir_link} - -Una delle caratteristiche usate quando si opera con i file è quella di poter -creare dei nomi fittizi (alias o collegamenti) per potersi riferire allo -stesso file accedendovi da directory diverse. Questo è possibile anche in -ambiente unix, dove tali collegamenti sono usualmente chiamati \textit{link}, -ma data la struttura del sistema ci sono due metodi sostanzialmente diversi -per fare questa operazione. - -Come si è appena detto l'accesso al contenuto di un file su disco avviene -attraverso il suo inode, e il nome che si trova in una directory è solo una -etichetta associata ad un puntatore a detto inode. Questo significa che la -realizzazione di un link è immediata in quanto uno stesso file può avere tanti -nomi diversi allo stesso tempo, dati da altrettante diverse associazioni allo -stesso inode; si noti poi che nessuno di questi nomi viene ad assumere una -particolare preferenza rispetto agli altri. - -Per aggiungere un nome ad un inode si utilizza la funzione \texttt{link}; si -suole chiamare questo tipo di associazione un collegamento diretto (o -\textit{hard link}). Il prototipo della funzione e le sue caratteritiche -principali, come risultano dalla man page, sono le seguenti: -\begin{prototype}{unistd.h} -{int link(const char * oldname, const char * newname)} - Crea un nuovo collegamento 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 seguenti - codici di errore: - \begin{errlist} - \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. - \item \texttt{EEXIST} Un file (o una directory) con quel nome esiste di - già. - \item \texttt{EMLINK} Ci sono troppi link al file \texttt{oldname} (il - numero massimo è specificato dalla variabile \texttt{LINK\_MAX}, vedi - \secref{sec:xxx_limits}. - \item \texttt{ENOSPC} La directory in cui si vuole creare il link è piena e - non può essere ampliata. - \item \texttt{EROFS} La directory su cui si vuole inserire il nuovo link è - su un filesystem montato readonly. - \end{errlist} -\end{prototype} - -La creazione di un nuovo collegamento diretto non copia il contenuto del file, -ma si limita ad aumentare di uno il numero di referenze al file aggiungendo il -nuovo nome ai precedenti. Si noti che uno stesso file può essere così -richiamato in diverse directory. - -Per quanto dicevamo in \secref{sec:filedir_filesystem} la creazione del -collegamento diretto è possibile solo se entrambi i pathname sono nello stesso -filesytem; inoltre il filesystem deve supportare i collegamenti diretti (non è -il caso ad esempio del filesystem \texttt{vfat} di windows). - -La funzione opera sui file ordinari, come sugli altri oggetti del filesystem, -ma solo l'amministratore è in grado di creare un collegamento diretto ad -un'altra directory, questo lo si fa perché in questo caso è possibile creare -dei cerchi nel filesystem (vedi \secref{sec:filedir_symlink}) che molti programmi -non sono in grado di gestire e la cui rimozione diventa estremamente -complicata (in genere occorre far girare il programma \texttt{fsck} per -riparare il filesystem). - - -La rimozione di un file (o più precisamente della voce che lo referenzia) si -effettua con la funzione \texttt{unlink}; il suo prototipo è il seguente: - -\begin{prototype}{unistd.h}{int unlink(const char * filename)} - Cancella il nome specificato dal pathname nella relativa directory e - decrementa il numero di riferimenti nel relativo inode. - - La funzione restituisce zero in caso di successo e -1 per un errore, nel - qual caso il file non viene toccato. La variabile \texttt{errno} viene - settata secondo i seguenti codici di errore: - \begin{errlist} - \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. - \item \texttt{EEXIST} Un file (o una directory) con quel nome esiste di - già. - \item \texttt{EMLINK} Ci sono troppi link al file \texttt{oldname} (il - numero massimo è specificato dalla variabile \texttt{LINK\_MAX}, vedi - \secref{sec:xxx_limits}. - \item \texttt{ENOSPC} La directory in cui si vuole creare il link è piena e - non può essere ampliata. - \item \texttt{EROFS} La directory su cui si vuole inserire il nuovo link è - su un filesystem montato readonly. - \end{errlist} -\end{prototype} - -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 sulla directory che la contiene (torneremo in -dettaglio sui permessi e gli attributi fra poco), se inoltre lo -\textit{sticky} bit è settato occorerà anche essere proprietari del file o -proprietari della directory (o root, per cui nessuna delle restrizioni è -applicata). - -Una delle caratteristiche di queste funzioni è che la creazione/rimozione -della nome dalla directory e l'incremento/decremento del numero di -riferimenti nell'inode deve essere una operazione atomica (cioè non -interrompibile da altri) processi, per questo entrambe queste funzioni sono -realizzate tramite una singola system call. - -Si ricordi infine che il file non viene eliminato dal disco fintanto che tutti -i riferimenti ad esso sono stati cancellati, solo quando il \textit{link - count} mantenuto nell'inode diventa zero lo spazio occupato viene rimosso. A -questo però si aggiunge una altra condizione, e cioè che non ci siano processi -che abbiano detto file aperto. Come accennato questa proprietà viene spesso -usata per essere sicuri di non lasciare file temporanei su disco in caso di -crash dei programmi; la tecnica è quella di aprire il file e chiamare -\texttt{unlink} subito dopo. - - -\subsection{Le funzioni \texttt{remove} e \texttt{rename}} -\label{sec:filedir_cre_canc} - - -\subsection{I link simbolici} -\label{sec:filedir_sym_link} - -Siccome la funzione \texttt{link} crea riferimenti agli inodes, essa può -funzionare soltanto per file che risiedono sullo stesso filesystem, dato che -in questo caso è garantita l'unicità dell'inode, e solo per un filesystem di -tipo unix. Inoltre in linux non è consentito eseguire un link diretto ad una -directory se non si è root. - -Per ovviare a queste limitazioni i sistemi unix supportano un'altra forma di -link (i cosiddetti \textit{soft link} o \textit{symbolic link}), che sono, -come avviene in altri sistemi operativi, dei file che contengono il -semplicemente il riferimento ad un altro file (o directory). In questo modo è -possibile effettuare link anche attraverso filesystem diversi e a directory, e -pure a file che non esistono ancora. - -Il sistema funziona in quanto i link simbolici sono contrassegnati come tali -al kernel (analogamente a quanto avviene per le directory) per cui la chiamata -ad una \texttt{open} o una \texttt{stat} su un link simbolico comporta la -lettura del contenuto del medesimo e l'applicazione della funzione al file -specificato da quest'ultimo. Invece altre funzioni come quelle per cancellare -o rinominare i file operano direttamente sul link simbolico. Inoltre esistono -funzioni apposite, come la \texttt{readlink} e la \texttt{lstat} per accedere -alle informazioni del link invece che a quelle del file a cui esso fa -riferimento. - -Le funzioni per operare sui link simbolici sono le seguenti, esse sono tutte -dichiarate nell'header file \texttt{unistd.h}. - -\begin{prototype}{unistd.h} -{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 - \secref{sec:filedir_access_control}) ai quali si aggiungono i seguenti: - \begin{errlist} - \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{errlist} -\end{prototype} - - -\subsection{Le funzioni \texttt{mkdir} e \texttt{rmdir}} -\label{sec:filedir_dir_creat_rem} - -Per creare una nuova directory si può usare la seguente funzione, omonima -dell'analogo comando di shell \texttt{mkdir}; per accedere ai tipi usati -programma deve includere il file \texttt{sys/types.h}. - -\begin{prototype}{sys/stat.h} -{int mkdir (const char * dirname, mode\_t mode)} - Questa funzione crea una nuova directory vuota con il nome indicato da - \texttt{dirname}, assegnandole i permessi indicati da \texttt{mode}. Il nome - può essere indicato con il pathname assoluto o relativo. - - La funzione restituisce zero in caso di successo e -1 per un errore, in caso - di errore \texttt{errno} viene settata secondo i codici di errore standard - di accesso ai files (trattati in dettaglio in - \secref{sec:filedir_access_control}) ai quali si aggiungono i seguenti: - \begin{errlist} - \item \texttt{EACCESS} - Non c'è il permesso di scrittura per la directory in cui si vuole inserire - la nuova directory. - \item \texttt{EEXIST} Un file (o una directory) con quel nome essite di già. - \item \texttt{EMLINK} La directory in cui si vuole creare la nuova directory - contiene troppi file. Sotto linux questo normalmente non avviene perchè il - filesystem standard consente la creazione di un numero di file maggiore di - quelli che possono essere contenuti nell'hard-disk, ma potendo avere a che - fare anche con filesystem di altri sistemi questo errore può presentarsi. - \item \texttt{ENOSPC} Non c'è abbastanza spazio sul file system per creare - la nuova directory. - \item \texttt{EROFS} La directory su cui si vuole inserire la nuova - directory è su un filesystem montato readonly. - \end{errlist} -\end{prototype} - +\end{enumerate*} -\subsection{Accesso alle directory} -\label{sec:filedir_dir_read} +\begin{figure}[!htb] + \centering + \includegraphics[width=12cm]{img/dir_links} + \caption{Organizzazione dei \textit{link} per le directory.} + \label{fig:file_dirs_link} +\end{figure} -Benchè le directory siano oggetti del filesystem come tutti gli altri non ha -ovviamente senso aprirle come fossero dei file di dati. Può però essere utile -poterne leggere il contenuto ad esempio per fare la lista dei file che esse -contengono o ricerche sui medesimi. +Infine tenga presente che, essendo file pure loro, il numero di riferimenti +esiste anche per le directory. Per questo se a partire dalla situazione +mostrata in fig.~\ref{fig:file_filesys_detail} creiamo una nuova directory +\file{img} nella directory \file{gapil}, avremo una situazione come quella +illustrata in fig.~\ref{fig:file_dirs_link}. -Per accedere al contenuto delle directory si usano i cosiddetti -\textit{directory streams} (chiamati così per l'analogia con i file stream); -la funzione \texttt{opendir} apre uno di questi stream e la funzione -\texttt{readdir} legge il contenuto della directory, i cui elementi sono le -\textit{directory entries} (da distinguersi da quelle della cache di cui -parlavamo in \secref{sec:fileintr_vfs}) in una opportuna struttura -\texttt{struct dirent}. +La nuova directory avrà un numero di riferimenti pari a due, in quanto è +referenziata dalla directory da cui si era partiti (in cui è inserita la nuova +voce che fa riferimento a \texttt{img}) e dalla voce interna ``\texttt{.}'' +che è presente in ogni directory. Questo è il valore che si troverà sempre +per ogni directory che non contenga a sua volta altre directory. Al contempo, +la directory da cui si era partiti avrà un numero di riferimenti di almeno +tre, in quanto adesso sarà referenziata anche dalla voce ``\texttt{..}'' di +\texttt{img}. L'aggiunta di una sottodirectory fa cioè crescere di uno il +\textit{link count} della directory genitrice. +\itindend{inode} -\subsection{La directory di lavoro} -\label{sec:filedir_work_dir} - -A ciascun processo è associato ad una directory nel filesystem che è chiamata -directory corrente o directory di lavoro (\textit{current working directory}) -che è quella a cui si fa riferimento quando un filename è espresso in forma -relativa (relativa appunto a questa directory). - -Quando un utente effettua il login questa directory viene settata alla -cosiddetta \textit{home directory} del suo account, il comando \texttt{cd} -della shell consente di cambiarla a piacere, spostandosi da una directory ad -un'altra. Siccome la directory corrente resta la stessa quando viene creato -un processo figlio, la directory corrente della shell diventa anche la -directory corrente di qualunque comando da essa lanciato. - -Le funzioni qui descritte servono esaminare e cambiare la directory di lavoro -corrente. - -\begin{prototype}{unistd.h}{char * getcwd (char * buffer, size\_t size)} - Restituisce il filename completo della directory di lavoro corrente nella - stringa puntata da \texttt{buffer}, che deve essere precedentemente - allocata, per una dimensione massima di \texttt{size}. Si può anche - specificare un puntatore nullo come \textit{buffer}, nel qual caso la - stringa sarà allocata automaticamente per una dimensione pari a - \texttt{size} qualora questa sia diversa da zero, o della lunghezza esatta - del pathname altrimenti. In questo caso si deve ricordare di disallocara la - stringa una volta cessato il suo utilizzo. - - La funzione restituisce il puntatore \texttt{buffer} se riesce, - \texttt{NULL} se fallisce, in quest'ultimo caso la variabile - \texttt{errno} è settata con i seguenti codici di errore: - \begin{errlist} - \item \texttt{EINVAL} L'argomento \texttt{size} è zero e \texttt{buffer} non - è nullo. - \item \texttt{ERANGE} L'argomento \texttt{size} è più piccolo della - lunghezza del pathname. - \item \texttt{EACCES} Manca il permesso di lettura o di ricerca su uno dei - componenti del pathname (cioè su una delle directory superiori alla - corrente). - \end{errlist} -\end{prototype} - -Di questa funzione esiste una versione \texttt{char * getwd(char * buffer)} -fatta per compatibilità all'indietro con BSD, che non consente di specificare -la dimensione del buffer; esso deve essere allocato in precedenza ed avere una -dimensione superiore a \texttt{PATH\_MAX} (di solito 256 byters, vedi -\secref{sec:xxx_limits}; il problema è che in linux non esiste una dimensione -superiore per un pathname, per cui non è detto che il buffer sia sufficiente a -contenere il nome del file, e questa è la ragione principale per cui questa -funzione è deprecata. - -Una seconda funzione simile è \texttt{char * get\_current\_dir\_name(void)} -che è sostanzialmente equivalente ad una \texttt{getcwd(NULL, 0)}, con la sola -differenza che essa ritorna il valore della variabile di ambiente -\texttt{PWD}, che essendo costruita dalla shell può contenere anche dei -riferimenti simbolici. - -Come già detto in unix anche le directory sono file, è possibile pertanto -riferirsi ad esse tramite il file descriptor dell'interfaccia a basso livello, -e non solo tramite il filename; per questo motivo ci sono due diverse funzioni -per cambiare directory di lavoro. - -\begin{prototype}{unistd.h}{int chdir (const char * pathname)} - Come dice il nome (che significa \textit{change directory}) questa funzione - serve a cambiare la directory di lavoro a quella speficata dal pathname - contenuto nella stringa \texttt{pathname}. -\end{prototype} + +\subsection{Alcuni dettagli sul filesystem \textsl{ext2} e successori} +\label{sec:file_ext2} + +Benché non esista ``il'' filesystem di Linux, dato che esiste un supporto +nativo di diversi filesystem che sono in uso da anni, quello che gli avvicina +di più è la famiglia di filesystem evolutasi a partire dal \textit{second + extended filesystem}, o \acr{ext2}. Il filesystem \acr{ext2} ha subito un +grande sviluppo e diverse evoluzioni, fra cui l'aggiunta del +\textit{journaling} con il passaggio ad \acr{ext3}, che probabilmente è ancora +il filesystem più diffuso, ed una serie di ulteriori miglioramenti con il +successivo \acr{ext4}. In futuro è previsto che questo debba essere sostituito +da un filesystem completamente diverso, \acr{btrfs}, che dovrebbe diventare il +filesystem standard di Linux, ma questo al momento è ancora in fase di +sviluppo.\footnote{si fa riferimento al momento dell'ultima revisione di + questo paragrafo, l'inizio del 2012.} + +Il filesystem \acr{ext2} nasce come filesystem nativo per Linux a partire +dalle prime versioni del kernel e supporta tutte le caratteristiche di un +filesystem standard Unix: è in grado di gestire nomi di file lunghi (256 +caratteri, estensibili a 1012) e supporta una dimensione massima dei file fino +a 4~Tb. I successivi filesystem \acr{ext3} ed \acr{ext4} sono evoluzioni di +questo filesystem, e sia pure con molti miglioramenti ed estensioni +significative ne mantengono le caratteristiche fondamentali. + +Oltre alle caratteristiche standard, \acr{ext2} fornisce alcune estensioni che +non sono presenti su un classico filesystem di tipo Unix; le principali sono +le seguenti: +\begin{itemize*} +\item gli attributi estesi (vedi sez.~\ref{sec:file_xattr}) che consentono di + estendere le informazioni salvabili come metadati e le ACL (vedi + sez.~\ref{sec:file_ACL}) che consentono di estendere il modello tradizionale + dei permessi sui file. +\item sono supportate entrambe le semantiche di BSD e SVr4 come opzioni di + montaggio. La semantica BSD comporta che i file in una directory sono creati + con lo stesso identificatore di gruppo della directory che li contiene. La + semantica SVr4 comporta che i file vengono creati con l'identificatore del + gruppo primario del processo, eccetto il caso in cui la directory ha il bit + di \acr{sgid} impostato (per una descrizione dettagliata del significato di + questi termini si veda sez.~\ref{sec:file_access_control}), nel qual caso + file e subdirectory ereditano sia il \ids{GID} che lo \acr{sgid}. +\item l'amministratore può scegliere la dimensione dei blocchi del filesystem + in fase di creazione, a seconda delle sue esigenze: blocchi più grandi + permettono un accesso più veloce, ma sprecano più spazio disco. +\item il filesystem implementa collegamenti simbolici veloci, in cui il nome + del file non è salvato su un blocco, ma tenuto all'interno + dell'\textit{inode} (evitando letture multiple e spreco di spazio), non + tutti i nomi però possono essere gestiti così per limiti di spazio (il + limite è 60 caratteri). +\item vengono supportati i cosiddetti \textit{file attributes} (vedi + sez.~\ref{sec:file_perm_overview}) che attivano comportamenti specifici per + i file su cui vengono attivati come marcarli come immutabili (che possono + cioè essere soltanto letti) per la protezione di file di configurazione + sensibili, o come \textit{append-only} (che possono essere aperti in + scrittura solo per aggiungere dati) per la protezione dei file di log. +\end{itemize*} + +La struttura di \acr{ext2} è stata ispirata a quella del filesystem di BSD: un +filesystem è composto da un insieme di blocchi, la struttura generale è quella +riportata in fig.~\ref{fig:file_filesys_detail}, in cui la partizione è divisa +in gruppi di blocchi. + +Ciascun gruppo di blocchi contiene una copia delle informazioni essenziali del +filesystem (i \textit{superblock} sono quindi ridondati) per una maggiore +affidabilità e possibilità di recupero in caso di corruzione del +\textit{superblock} principale. L'utilizzo di raggruppamenti di blocchi ha +inoltre degli effetti positivi nelle prestazioni dato che viene ridotta la +distanza fra i dati e la tabella degli \textit{inode}. + +\begin{figure}[!htb] + \centering + \includegraphics[width=9cm]{img/dir_struct} + \caption{Struttura delle directory nel \textit{second extended filesystem}.} + \label{fig:file_ext2_dirs} +\end{figure} + + +Le directory sono implementate come una \textit{linked list} con voci di +dimensione variabile. Ciascuna voce della lista contiene il numero di +\textit{inode}, la sua lunghezza, il nome del file e la sua lunghezza, secondo +lo schema in fig.~\ref{fig:file_ext2_dirs}; in questo modo è possibile +implementare nomi per i file anche molto lunghi (fino a 1024 caratteri) senza +sprecare spazio disco. + +Con l'introduzione del filesystem \textit{ext3} sono state introdotte diverse +modifiche strutturali, la principale di queste è quella che \textit{ext3} è un +filesystem \textit{journaled}, è cioè in grado di eseguire una registrazione +delle operazioni di scrittura su un giornale (uno speciale file interno) in +modo da poter garantire il ripristino della coerenza dei dati del +filesystem\footnote{si noti bene che si è parlato di dati \textsl{del} + filesystem, non di dati \textsl{nel} filesystem, quello di cui viene + garantito un veloce ripristino è relativo ai dati della struttura interna + del filesystem, non di eventuali dati contenuti nei file che potrebbero + essere stati persi.} in brevissimo tempo in caso di interruzione improvvisa +della corrente o di crollo del sistema che abbia causato una interruzione +della scrittura dei dati sul disco. + +Oltre a questo \textit{ext3} introduce ulteriori modifiche volte a migliorare +sia le prestazioni che la semplicità di gestione del filesystem, in +particolare per le directory si è passato all'uso di alberi binari con +indicizzazione tramite \textit{hash} al posto delle \textit{linked list} che +abbiamo illustrato, ottenendo un forte guadagno di prestazioni in caso di +directory contenenti un gran numero di file. + +% TODO (bassa priorità) portare a ext3, ext4 e btrfs ed illustrare le +% problematiche che si possono incontrare (in particolare quelle relative alla +% perdita di contenuti in caso di crash del sistema) +% TODO (media priorità) trattare btrfs quando sarà usato come stabile + + +\subsection{La gestione dell'uso dei filesystem} +\label{sec:filesystem_mounting} + +Come accennato in sez.~\ref{sec:file_arch_overview} per poter accedere ai file +occorre rendere disponibile al sistema il filesystem su cui essi sono +memorizzati. L'operazione di attivazione del filesystem è chiamata +\textsl{montaggio} e per far questo in Linux si usa la funzione di sistema +\funcd{mount}, il cui prototipo è:\footnote{la funzione è una versione + specifica di Linux che usa la omonima \textit{system call} e non è + portabile.} + +\begin{funcproto}{ +\fhead{sys/mount.h} +\fdecl{mount(const char *source, const char *target, const char + *filesystemtype, \\ +\phantom{mount(}unsigned long mountflags, const void *data)} +\fdesc{Monta un filesystem.} +} +{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{EACCES}] non si ha il permesso di accesso su uno dei + componenti del \textit{pathname}, o si è cercato di montare un filesystem + disponibile in sola lettura senza aver specificato \const{MS\_RDONLY} o il + device \param{source} è su un filesystem montato con l'opzione + \const{MS\_NODEV}. + \item[\errcode{EBUSY}] \param{source} è già montato, o non può essere + rimontato in sola lettura perché ci sono ancora file aperti in scrittura, + o non può essere montato su \param{target} perché la directory è ancora in + uso. + \item[\errcode{EINVAL}] il dispositivo \param{source} presenta un + \textit{superblock} non valido, o si è cercato di rimontare un filesystem + non ancora montato, o di montarlo senza che \param{target} sia un + \textit{mount point} o di spostarlo quando \param{target} non è un + \textit{mount point} o è la radice o si è usato un valore di + \param{mountflags} non valido. + \item[\errcode{ELOOP}] si è cercato di spostare un \textit{mount point} su + una sottodirectory di \param{source} o si sono incontrati troppi + collegamenti simbolici nella risoluzione di un nome. + \item[\errcode{EMFILE}] in caso di filesystem virtuale, la tabella dei + dispositivi fittizi (chiamati \textit{dummy} nella documentazione inglese) + è piena. + \item[\errcode{ENODEV}] il tipo \param{filesystemtype} non esiste o non è + configurato nel kernel. + \item[\errcode{ENOTBLK}] non si è usato un \textit{block device} per + \param{source} quando era richiesto. + \item[\errcode{ENXIO}] il \textit{major number} del + dispositivo \param{source} è sbagliato. + \item[\errcode{EPERM}] il processo non ha i privilegi di amministratore. + \end{errlist} + ed inoltre \errval{EFAULT}, \errval{ENOMEM}, \errval{ENAMETOOLONG}, + \errval{ENOENT}, \errval{ENOTDIR} nel loro significato generico.} +\end{funcproto} + +\itindbeg{mount~point} + +L'uso più comune della funzione è quello di montare sulla directory indicata +da \param{target}, detta \textit{mount point}, il filesystem contenuto nel +file di dispositivo indicato da \param{source}. In entrambi i casi, come +daremo per assunto da qui in avanti tutte le volte che si parla di directory o +file nel passaggio di un argomento di una funzione, si intende che questi +devono essere indicati con la stringa contenente il loro \textit{pathname}. + +Normalmente un filesystem è contenuto su un disco o una partizione, ma come +illustrato in sez.~\ref{sec:file_vfs_work} la struttura del \textit{Virtual + File System} è estremamente flessibile e può essere usata anche per oggetti +diversi da un disco. Ad esempio usando il \textit{loop device} si può montare +un file qualunque (come l'immagine di un CD-ROM o di un floppy) che contiene +l'immagine di un filesystem, inoltre alcuni tipi di filesystem, come +\texttt{proc} o \texttt{sysfs} sono virtuali e non hanno un supporto che ne +contenga i dati che sono generati al volo dal kernel ad ogni lettura, e +inviati al kernel ad ogni scrittura (costituiscono quindi un meccanismo di +comunicazione, attraverso l'ordinaria interfaccia dei file, con il kernel). + +Il tipo di filesystem che si vuole montare è specificato +dall'argomento \param{filesystemtype}, che deve essere una delle stringhe +riportate nel file \procfilem{/proc/filesystems} che, come accennato in +sez.~\ref{sec:file_vfs_work}, contiene l'elenco dei filesystem supportati dal +kernel. Nel caso si sia indicato un filesystem virtuale, che non è associato a +nessun file di dispositivo, il contenuto di \param{source} viene ignorato. + +L'argomento \param{data} viene usato per passare le impostazioni relative alle +caratteristiche specifiche di ciascun filesystem. Si tratta di una stringa di +parole chiave (separate da virgole e senza spazi) che indicano le cosiddette +``\textsl{opzioni}'' del filesystem che devono essere impostate; in genere +viene usato direttamente il contenuto del parametro dell'opzione \texttt{-o} +del comando \texttt{mount}. I valori utilizzabili dipendono dal tipo di +filesystem e ciascuno ha i suoi, pertanto si rimanda alla documentazione della +pagina di manuale di questo comando e dei singoli filesystem. + +Dopo l'esecuzione della funzione il contenuto del filesystem viene reso +disponibile nella directory specificata come \textit{mount point} ed il +precedente contenuto di detta directory viene mascherato dal contenuto della +directory radice del filesystem montato. Fino ai kernel della serie 2.2.x non +era possibile montare un filesystem se un \textit{mount point} era già in uso, +coi kernel successivi è possibile montare più filesystem sullo stesso +\textit{mount point} impilandoli l'uno sull'altro, anche in questo caso vale +quanto appena detto, e solo il contenuto dell'ultimo filesystem montato sarà +visibile, mascherando quelli sottostanti. + +In realtà quella di montare un filesystem è solo una delle operazioni che si +possono effettuare con \func{mount}, la funzione infatti è dedicata a tutte le +operazioni relative alla gestione del montaggio dei filesystem e dei +\textit{mount point}. Ad esempio fin dalle sue origini poteva essere +utilizzata per effettuare il rimontaggio di un filesystem con opzioni diverse, +ed a partire dal kernel 2.4.x è divenuto possibile usarla per spostare +atomicamente un \textit{mount point} da una directory ad un'altra, per montare +lo stesso filesystem in diversi \textit{mount point}, per montare una +directory su un'altra (il cosiddetto \textit{bind mount}). + +\itindend{mount~point} + +Il tipo di operazione compiuto da \func{mount} viene stabilito in base al +valore dell'argomento \param{mountflags}, che oltre alla selezione del tipo di +operazione da compiere, consente anche di indicare alcune opzioni generiche +valide per qualunque filesystem.\footnote{benché queste siano espresse nel + comando \cmd{mount} con l'opzione \texttt{-o} esse non vengono impostate nei + valori di \param{data}, che serve solo per le opzioni specifiche di ogni + filesystem.} Il valore dell'argomento deve essere espresso come maschera +binaria e i vari bit che lo compongono, detti anche \textit{mount flags}, +devono essere impostati con un OR aritmetico dei valori dalle opportune +costanti che illustreremo a breve. + +In Linux \param{mountflags} deve essere un intero a 32 bit; +fino ai kernel della serie 2.2.x i 16 più significativi avevano un valore +riservato che doveva essere specificato obbligatoriamente,\footnote{il valore + era il \textit{magic number} \code{0xC0ED}, si può usare la costante + \constd{MS\_MGC\_MSK} per ottenere la parte di \param{mountflags} riservata + al \textit{magic number}, mentre per specificarlo si può dare un OR + aritmetico con la costante \constd{MS\_MGC\_VAL}.} e si potevano usare solo +i 16 meno significativi. Oggi invece, con un numero di opzioni superiore, sono +utilizzati tutti e 32 i bit, ma qualora nei 16 più significativi sia presente +detto valore, che non esprime una combinazione valida, esso viene ignorato. + +Come accennato il tipo di operazione eseguito da \func{mount} viene stabilito +in base al contenuto di \param{mountflags}, la scelta viene effettuata +controllando nell'ordine: +\begin{enumerate*} +\item se è presente il flag \const{MS\_REMOUNT}, nel qual caso verrà eseguito + il rimontaggio del filesystem, con le nuove opzioni indicate da \param{data} + e dagli altri flag di \param{mountflags}; +\item se è presente il flag \const{MS\_BIND}, nel qual caso verrà eseguito un + \textit{bind mount} (argomento che tratteremo più avanti); +\item se è presente uno fra \const{MS\_SHARED}, \const{MS\_PRIVATE}, + \const{MS\_SLAVE}, \const{MS\_UNBINDABLE}, nel qual caso verrà cambiata la + modalità di propagazione del montaggio (detti valori sono mutualmente + esclusivi). +\item se è presente \const{MS\_MOVE}, nel qual caso verrà effettuato uno + spostamento del \textit{mount point}; +\item se nessuno dei precedenti è presente si tratta di una ordinaria + operazione di montaggio di un filesystem. +\end{enumerate*} + +Il fatto che questi valori vengano controllati in quest'ordine significa che +l'effetto di alcuni di questi flag possono cambiare se usati in combinazione +con gli altri che vengono prima nella sequenza (è quanto avviene ad esempio +per \const{MS\_BIND} usato con \const{MS\_REMOUNT}). Tratteremo questi +\textit{mount flags} speciali per primi, nell'ordine appena illustrato, +tornando sugli altri più avanti. + +Usando il flag \constd{MS\_REMOUNT} si richiede a \func{mount} di rimontare un +filesystem già montato cambiandone le opzioni di montaggio in maniera atomica +(non è cioè necessario smontare e rimontare il filesystem per effettuare il +cambiamento). Questa operazione consente di modificare le opzioni del +filesystem anche se questo è in uso. Gli argomenti \param{source} e +\param{target} devono essere gli stessi usati per il montaggio originale, +mentre sia \param{data} che \param{mountflags} conterranno le nuove opzioni, +\param{filesystemtype} viene ignorato. Perché l'operazione abbia successo +occorre comunque che il cambiamento sia possibile (ad esempio non sarà +possibile rimontare in sola lettura un filesystem su cui sono aperti file per +la lettura/scrittura). + +Qualunque opzione specifica del filesystem indicata con \param{data} può +essere modificata (ma si dovranno rielencare tutte quelle volute), mentre con +\param{mountflags} possono essere modificate solo alcune opzioni generiche: +\const{MS\_LAZYTIME}, \const{MS\_MANDLOCK}, \const{MS\_NOATIME}, +\const{MS\_NODEV}, \const{MS\_NODIRATIME}, \const{MS\_NOEXEC}, +\const{MS\_NOSUID}, \const{MS\_RELATIME}, \const{MS\_RDONLY}, +\const{MS\_STRICTATIME} e \const{MS\_SYNCHRONOUS}. Inoltre dal kernel 3.17 il +comportamento relativo alle opzioni che operano sui tempi di ultimo accesso +dei file (vedi sez.~\ref{sec:file_file_times}) è cambiato e se non si è +indicato nessuno dei vari \texttt{MS\_*ATIME} vengono mantenute le +impostazioni esistenti anziché forzare l'uso di \const{MS\_RELATIME}. + +\itindbeg{bind~mount} + +Usando il flag \constd{MS\_BIND} si richiede a \func{mount} di effettuare un +cosiddetto \textit{bind mount}, l'operazione che consente di montare una +directory di un filesystem in un'altra directory. L'opzione è disponibile a +partire dai kernel della serie 2.4. In questo caso verranno presi in +considerazione solo gli argomenti \param{source}, che stavolta indicherà la +directory che si vuole montare e non un file di dispositivo, e \param{target} +che indicherà la directory su cui verrà effettuato il \textit{bind mount}. Gli +argomenti \param{filesystemtype} e \param{data} vengono ignorati. + +Quello che avviene con questa operazione è che in corrispondenza del +\textit{pathname} indicato da \param{target} viene montato l'\textit{inode} di +\param{source}, così che la porzione di albero dei file presente sotto +\param{source} diventi visibile allo stesso modo sotto +\param{target}. Trattandosi esattamente dei dati dello stesso filesystem, ogni +modifica fatta in uno qualunque dei due rami di albero sarà visibile +nell'altro, visto che entrambi faranno riferimento agli stessi \textit{inode}. + +Dal punto di vista del VFS l'operazione è analoga al montaggio di un +filesystem proprio nel fatto che anche in questo caso si inserisce in +corrispondenza della \textit{dentry} di \texttt{target} un diverso +\textit{inode}, che stavolta, invece di essere quello della radice del +filesystem indicato da un file di dispositivo, è quello di una directory già +montata. + +Si tenga presente che proprio per questo sotto \param{target} comparirà il +contenuto che è presente sotto \param{source} all'interno del filesystem in +cui quest'ultima è contenuta. Questo potrebbe non corrispondere alla porzione +di albero che sta sotto \param{source} qualora in una sottodirectory di +quest'ultima si fosse effettuato un altro montaggio. In tal caso infatti nella +porzione di albero sotto \param{source} si troverebbe il contenuto del nuovo +filesystem (o di un altro \textit{bind mount}) mentre sotto \param{target} ci +sarebbe il contenuto presente nel filesystem originale. + +L'unico altro \textit{mount flag} usabile direttamente con \const{MS\_BIND} è +\const{MS\_REC} che consente di eseguire una operazione di \textit{bind mount} +ricorsiva, in cui sotto \param{target} vengono montati ricorsivamente anche +tutti gli eventuali ulteriori \textit{bind mount} già presenti sotto +\param{source}. + +E' però possibile, a partire dal kernel 2.6.26, usare questo flag insieme a +\const{MS\_REMOUNT}, nel qual caso consente di effettuare una modifica delle +opzioni di montaggio del \textit{bind mount} ed in particolare effettuare il +cosiddetto \textit{read-only bind mount} in cui viene onorata anche la +presenza aggiuntiva del flag \const{MS\_RDONLY}. In questo modo si ottiene che +l'accesso ai file sotto \param{target} sia effettuabile esclusivamente in sola +lettura, mantenendo il normale accesso in lettura/scrittura sotto +\param{source}. + +Il supporto per il \textit{bind mount} consente di superare i limiti presenti +per gli \textit{hard link} (di cui parleremo in +sez.~\ref{sec:link_symlink_rename}) con la possibilità di fare riferimento +alla porzione dell'albero dei file di un filesystem presente a partire da una +certa directory utilizzando una qualunque altra directory, anche se questa sta +su un filesystem diverso.\footnote{e non c'è neanche il problema di non esser + più in grado di cancellare un \textit{hard link} ad una directory sullo + stesso filesystem (vedi sez.~\ref{sec:link_symlink_rename}), per cui su + Linux questi non sono possibili, dato che in questo caso per la rimozione + del collegamento basta smontare \param{target}.} Si può così fornire una +alternativa all'uso dei collegamenti simbolici (di cui parleremo in +sez.~\ref{sec:link_symlink_rename}) che funziona correttamente anche +all'intero di un \textit{chroot} (argomento su cui torneremo in +sez.~\ref{sec:file_chroot}). + +\itindend{bind~mount} +\itindbeg{shared~subtree} + +I quattro flag \const{MS\_PRIVATE}, \const{MS\_SHARED}, \const{MS\_SLAVE} e +\const{MS\_UNBINDABLE} sono stati introdotti a partire dal kernel 2.6.15 per +realizzare l'infrastruttura dei cosiddetti \textit{shared subtree}, che +estendono le funzionalità dei \textit{bind mount}. La funzionalità nasce +dalle esigenze di poter utilizzare a pieno le funzionalità di isolamento +fornite dal kernel per i processi (i \textit{namespace}, che tratteremo in +sez.~\ref{sec:process_namespaces}) in particolare per quanto riguarda la +possibilità di far avere ad un processo una visione ristretta dei filesystem +montati (il \textit{mount namespace}), ma l'applicazione è comunque rilevante +anche con un classico \textit{chroot} (vedi sez.~\ref{sec:file_chroot}). + +\itindbeg{submount} + +Abbiamo visto come nella modalità ordinaria in cui si esegue un +\textit{bind mount} sotto \param{target} compaia lo stesso ramo di albero dei +file presente sotto \param{source}, ma limitato a quanto presente nel +filesystem di \param{source}; i risultati di un eventuale +``\textit{submount}'' effettuato all'interno di \param{source} non saranno +visibili. Ed anche se quelli presenti al momento dell'uso di \const{MS\_BIND} +possono essere riottenuti usando \const{MS\_REC}, ogni eventuale +``\textit{submount}'' successivo (che avvenga sotto \param{source} o sotto +\param{target}) resterà ``\textsl{privato}'' al ramo di albero su cui è +avvenuto. + +\itindend{submount} +\itindbeg{mount peer group} + +Ci sono casi però in cui può risultare utile che eventuali +``\textit{submount}'' siano visibili sui rami di albero presenti al di sotto +di tutte le directory coinvolte in un \textit{bind mount}, anche se effettuati +in un secondo tempo. Per poter ottenere questa funzionalità i +\textit{bind mount} sono stati estesi introducendo i \textit{mount peer + group}, che consentono di raggrupparli in modo da poter inviare a ciascuno +di essi tutti gli eventi relativi a montaggi o smontaggi effettuati al loro +interno ed avere sempre una propagazione degli stessi che li renda coerenti. + +Quando si effettua un montaggio ordinario, o si esegue un \textit{bind mount}, +di default non viene utilizzato nessun \textit{mount peer group} ed il +\textit{mount point} viene classificato come ``\textsl{privato}'', nel senso +che abbiamo appena visto. Si può però marcare un \textit{mount point} come +``\textsl{condiviso}'', ed in questo modo esso verrà associato ad un +\textit{mount peer group} insieme a tutti gli altri ulteriori \textit{mount + point} per i quali sia stato eseguito un \textit{bind mount}. Questo fa sì +che tutte le volte che si effettua un montaggio o uno smontaggio all'interno +di uno qualunque dei \textit{mount point} del gruppo, questo venga propagato +anche su tutti gli altri e sotto tutti sia visibile sempre lo stesso ramo di +albero dei file. + +A completare l'infrastruttura degli \textit{shared subtree} sono state +previste due ulteriori funzionalità: la prima è quella di marcare un +\textit{mount point} come ``\textit{slave}'', in tal caso le operazioni di +montaggio e smontaggio effettuate al suo interno non verranno più propagate +agli altri membri del \textit{mount peer group} di cui fa parte, ma continuerà +a ricevere quelle eseguite negli altri membri. + +La seconda funzionalità è quella di marcare un \textit{mount point} come +``\textit{unbindable}''; questo anzitutto impedirà che possa essere usato come +sorgente di un \textit{bind mount} ed inoltre lo renderà privato, con la +conseguenza che quando è presente all'interno di altri \textit{bind mount}, +all'interno di questi si vedrà solo il contenuto originale e non quello +risultante da eventuali ulteriori montaggi effettuati al suo interno. + +\itindend{mount peer group} + +I \textit{mount flag} che controllano le operazioni relative agli +\textit{shared subtree} sono descritti nella lista seguente. Si ricordi che +sono mutuamente esclusivi, e compatibili solo con l'uso degli ulteriori flag +\const{MS\_REC} (che applica ricorsivamente l'operazione a tutti gli eventuali +\textit{mount point} sottostanti) e \const{MS\_SILENT}; in tutti gli altri +casi \func{mount} fallirà con un errore di \errval{EINVAL}. L'unico altro +argomento che deve essere specificato quando li si usano è \param{target}; +\param{source}, \param{data} e \param{filesystem} sono ignorati. + +\begin{basedescript}{\desclabelwidth{1.9cm}\desclabelstyle{\nextlinelabel}} + +\item[\constd{MS\_PRIVATE}] Marca un \textit{mount point} come \textit{private + mount}. Di default, finché non lo si marca altrimenti con una delle altre + opzioni dell'interfaccia, ogni \textit{mount point} è privato. Ogni + \textit{bind mount} ottenuto da un \textit{mount point} privato si comporta + come descritto nella trattazione di \const{MS\_BIND}. Si usa questo flag + principalmente per revocare gli effetti delle altre opzioni e riportare il + comportamento a quello ordinario. + +\item[\constd{MS\_SHARED}] Marca un \textit{mount point} come \textit{shared + mount}. Lo scopo dell'opzione è ottenere che tutti i successivi + \textit{bind mount} ottenuti da un \textit{mount point} così marcato siano + di tipo \textit{shared} e vengano inseriti nello stesso \textit{mount peer + group} in modo da ``\textsl{condividere}'' ogni ulteriore operazione di + montaggio o smontaggio. Con questa opzione le operazioni di montaggio e + smontaggio effettuate al di sotto di uno \textit{shared mount} vengono + automaticamente ``\textsl{propagate}'' a tutti gli altri membri del + \textit{mount peer group} di cui fa parte, in modo che la sezione di albero + dei file visibile al di sotto di ciascuno di essi sia sempre la stessa. + +\item[\constd{MS\_SLAVE}] Marca un \textit{mount point} come \textit{slave + mount}. Se il \textit{mount point} è parte di un \textit{mount peer group} + esso diventerà di tipo \textit{slave}: le operazioni di montaggio e + smontaggio al suo interno non verranno più propagate agli altri membri del + gruppo, ma continuerà a ricevere quelle eseguite negli altri membri. Se non + esistono altri membri nel gruppo il \textit{mount point} diventerà privato, + negli altri casi non subirà nessun cambiamento. + +\item[\constd{MS\_UNBINDABLE}] Marca un \textit{mount point} come + \textit{unbindable mount}. Un \textit{mount point} marcato in questo modo + non può essere usato per un \textit{bind mount} del suo contenuto. Si + comporta cioè come allo stesso modo di un \textit{mount point} ordinario di + tipo \textit{private} con in più la restrizione che nessuna sua + sottodirectory (anche se relativa ad un ulteriore montaggio) possa essere + utilizzata come sorgente di un \textit{bind mount}. -\begin{prototype}{unistd.h}{int fchdir (int filedes)} - Analoga alla precedente, ma usa un file descriptor invece del pathname. +\end{basedescript} +\itindend{shared~subtree} + +L'ultimo \textit{mount flag} che controlla una modalità operativa di +\func{mount} è \constd{MS\_MOVE}, che consente di effettuare lo spostamento +del \textit{mount point} di un filesystem. La directory del \textit{mount + point} originale deve essere indicata nell'argomento \param{source}, e la +sua nuova posizione nell'argomento \param{target}. Tutti gli altri argomenti +della funzione vengono ignorati. + +Lo spostamento avviene atomicamente, ed il ramo di albero presente sotto +\param{source} sarà immediatamente visibile sotto \param{target}. Non esiste +cioè nessun momento in cui il filesystem non risulti montato in una o +nell'altra directory e pertanto è garantito che la risoluzione di +\textit{pathname} relativi all'interno del filesystem non possa fallire. + +Elenchiamo infine i restanti \textit{mount flag}, il cui utilizzo non attiene +alle operazioni di \func{mount}, ma soltanto l'impostazione di opzioni +generiche relative al funzionamento di un filesystem e che vengono per lo più +utilizzati solo in fase di montaggio: + +\begin{basedescript}{\desclabelwidth{2.0cm}\desclabelstyle{\nextlinelabel}} +\item[\constd{MS\_DIRSYNC}] Richiede che ogni modifica al contenuto di una + directory venga immediatamente registrata su disco in maniera sincrona + (introdotta a partire dai kernel della serie 2.6). L'opzione si applica a + tutte le directory del filesystem, ma su alcuni filesystem è possibile + impostarla a livello di singole directory o per i sotto-rami di una directory + con il comando \cmd{chattr}.\footnote{questo avviene tramite delle opportune + \texttt{ioctl} (vedi sez.~\ref{sec:file_fcntl_ioctl}).} + + Questo consente di ridurre al minimo il rischio di perdita dei dati delle + directory in caso di crollo improvviso del sistema, al costo di una certa + perdita di prestazioni dato che le funzioni di scrittura relative ad + operazioni sulle directory non saranno più bufferizzate e si bloccheranno + fino all'arrivo dei dati sul disco prima che un programma possa proseguire. + +\item[\constd{MS\_LAZYTIME}] Modifica la modalità di registrazione di tempi + dei file (vedi sez.~\ref{sec:file_file_times}) per ridurre al massimo gli + accessi a disco (particolarmente utile per i portatili). Attivandolo i tempi + dei file vengono mantenuti in memoria e vengono salvati su disco solo in + quattro casi: quando c'è da eseguire un aggiornamento dei dati + dell'\textit{inode} per altri motivi, se viene usata una delle funzioni di + sincronizzazione dei dati su disco (vedi sez.~\ref{sec:file_sync}), se + l'\textit{inode} viene rimosso dalla memoria, o se è passato un giorno + dall'ultima registrazione. Introdotto a partire dal kernel 4.0. + + In questo modo si possono ridurre significativamente le scritture su disco + mantenendo tutte le informazioni riguardo ai tempi dei file, riducendo anche + l'impatto dell'uso di \const{MS\_STRICTATIME}. Il costo da pagare è il + rischio, in caso di crash del sistema, di avere dati vecchi fino a 24 ore + per quel che riguarda i tempi dei file. - Entrambe le funzioni restituiscono zero in caso di successo e -1 per un - errore, in caso di errore \texttt{errno} viene settata secondo i codici di - errore standard di accesso ai files (trattati in dettaglio in - \secref{sec:filedir_access_control}) ai quali si aggiunge il codice - \texttt{ENOTDIR} nel caso il \texttt{filename} indichi un file che non sia - una directory. -\end{prototype} +\item[\constd{MS\_MANDLOCK}] Consente l'uso del \textit{mandatory locking} + (vedi sez.~\ref{sec:file_mand_locking}) sui file del filesystem. Per poterlo + utilizzare effettivamente però esso dovrà essere comunque attivato + esplicitamente per i singoli file impostando i permessi come illustrato in + sez.~\ref{sec:file_mand_locking}. +\item[\constd{MS\_NOATIME}] Viene disabilitato sul filesystem l'aggiornamento + dell'\textit{access time} (vedi sez.~\ref{sec:file_file_times}) per + qualunque tipo di file. Dato che l'aggiornamento dell'\textit{access time} è + una funzionalità la cui utilità è spesso irrilevante ma comporta un costo + elevato visto che una qualunque lettura comporta comunque una scrittura su + disco, questa opzione consente di disabilitarla completamente. La soluzione + può risultare troppo drastica dato che l'informazione viene comunque + utilizzata da alcuni programmi, per cui nello sviluppo del kernel sono state + introdotte altre opzioni che forniscono soluzioni più appropriate e meno + radicali. +\item[\constd{MS\_NODEV}] Viene disabilitato sul filesystem l'accesso ai file + di dispositivo eventualmente presenti su di esso. L'opzione viene usata come + misura di precauzione per rendere inutile la presenza di eventuali file di + dispositivo su filesystem che non dovrebbero contenerne.\footnote{si ricordi + che le convenzioni del \textit{Linux Filesystem Hierarchy Standard} + richiedono che questi siano mantenuti esclusivamente sotto \texttt{/dev}.} + Viene utilizzata, assieme a \const{MS\_NOEXEC} e \const{MS\_NOSUID}, per + fornire un accesso più controllato a quei filesystem di cui gli utenti hanno + il controllo dei contenuti, in particolar modo quelli posti su dispositivi + rimuovibili. In questo modo si evitano alla radice possibili situazioni in + cui un utente malizioso inserisce su uno di questi filesystem dei file di + dispositivo con permessi ``opportunamente'' ampliati che gli consentirebbero + di accedere anche a risorse cui non dovrebbe. +\item[\constd{MS\_NODIRATIME}] Viene disabilitato sul filesystem + l'aggiornamento dell'\textit{access time} (vedi + sez.~\ref{sec:file_file_times}) ma soltanto per le directory. Costituisce + una alternativa per \const{MS\_NOATIME}, che elimina l'informazione per le + directory, che in pratica che non viene mai utilizzata, mantenendola per i + file in cui invece ha un impiego, sia pur limitato. -\section{La manipolazione delle caratteristiche dei files} -\label{sec:filedir_infos} +\item[\constd{MS\_NOEXEC}] Viene disabilitata sul filesystem l'esecuzione di un + qualunque file eseguibile eventualmente presente su di esso. L'opzione viene + usata come misura di precauzione per rendere impossibile l'uso di programmi + posti su filesystem che non dovrebbero contenerne. + Anche in questo caso viene utilizzata per fornire un accesso più controllato + a quei filesystem di cui gli utenti hanno il controllo dei contenuti. Da + questo punto di vista l'opzione è meno importante delle analoghe + \const{MS\_NODEV} e \const{MS\_NOSUID} in quanto l'esecuzione di un + programma creato dall'utente pone un livello di rischio nettamente + inferiore, ed è in genere consentita per i file contenuti nella sua home + directory.\footnote{cosa che renderebbe superfluo l'attivazione di questa + opzione, il cui uso ha senso solo per ambienti molto controllati in cui si + vuole che gli utenti eseguano solo i programmi forniti + dall'amministratore.} +\item[\constd{MS\_NOSUID}] Viene disabilitato sul filesystem l'effetto dei bit + dei permessi \acr{suid} e \acr{sgid} (vedi sez.~\ref{sec:file_special_perm}) + eventualmente presenti sui file in esso contenuti. L'opzione viene usata + come misura di precauzione per rendere inefficace l'effetto di questi bit + per filesystem in cui non ci dovrebbero essere file dotati di questi + permessi. + Di nuovo viene utilizzata, analogamente a \const{MS\_NOEXEC} e + \const{MS\_NODEV}, per fornire un accesso più controllato a quei filesystem + di cui gli utenti hanno il controllo dei contenuti. In questo caso si evita + che un utente malizioso possa inserire su uno di questi filesystem un + eseguibile con il bit \acr{suid} attivo e di proprietà dell'amministratore o + di un altro utente, che gli consentirebbe di eseguirlo per conto di + quest'ultimo. -\subsection{Le funzioni \texttt{stat}, \texttt{fstat} e \texttt{lstat}} -\label{sec:filedir_stat} +\item[\constd{MS\_RDONLY}] Esegue il montaggio del filesystem in sola lettura, + non sarà possibile nessuna modifica ai suoi contenuti. Viene usato tutte le + volte che si deve accedere ai contenuti di un filesystem con la certezza che + questo non venga modificato (ad esempio per ispezionare un filesystem + corrotto). All'avvio di default il kernel monta la radice in questa + modalità. Si tenga presente che se non viene indicato il filesystem verrà + montato, o rimontato nel caso lo si usi con \const{MS\_REMOUNT}, in + lettura/scrittura; questo significa in sostanza che non esiste una opzione + separata per indicare il montaggio in lettura/scrittura. -\subsection{I tipi di file} -\label{sec:filedir_file_types} +\item[\constd{MS\_REC}] Applica ricorsivamente a tutti i \textit{mount point} + presenti al di sotto del \textit{mount point} indicato gli effetti della + opzione degli \textit{shared subtree} associata. In questo caso l'argomento + \param{target} deve fare riferimento ad un \textit{mount point} e tutti gli + altri argomenti sono ignorati, ed il flag deve essere indicato con uno fra + \const{MS\_PRIVATE}, \const{MS\_SHARED}, \const{MS\_SLAVE} e + \const{MS\_UNBINDABLE}. Può anche essere usato con \const{MS\_BIND} per + richiedere il montaggio ricorsivo anche degli eventuali ulteriori + \textit{bind mount} presenti sotto \param{target}. -\subsection{La dimensione dei file} -\label{sec:filedir_file_size} +\item[\constd{MS\_RELATIME}] Indica di effettuare l'aggiornamento + dell'\textit{access time} sul filesystem soltanto quando questo risulti + antecedente il valore corrente del \textit{modification time} o del + \textit{change time} (per i tempi dei file si veda + sez.~\ref{sec:file_file_times}). L'opzione è disponibile a partire dal + kernel 2.6.20, mentre dal 2.6.30 questo è diventato il comportamento di + default del sistema, che può essere riportato a quello tradizionale con + l'uso di \const{MS\_STRICTATIME}. Sempre dal 2.6.30 il comportamento è stato + anche modificato e l'\textit{access time} viene comunque aggiornato se è più + vecchio di un giorno. -\subsection{I tempi dei file} -\label{sec:filedir_file_times} + L'opzione consente di evitare i problemi di prestazioni relativi + all'aggiornamento dell'\textit{access time} senza avere impatti negativi + riguardo le funzionalità, il comportamento adottato infatti consente di + rendere evidente che vi è stato un accesso dopo la scrittura, ed evitando al + contempo ulteriori operazioni su disco negli accessi successivi. In questo + modo l'informazione relativa al fatto che un file sia stato letto resta + disponibile, ed i programmi che ne fanno uso continuano a funzionare. Con + l'introduzione di questo comportamento l'uso delle alternative + \const{MS\_NOATIME} e \const{MS\_NODIRATIME} è sostanzialmente inutile. -\subsection{La funzione \texttt{utime}} -\label{sec:filedir_utime} +\item[\constd{MS\_SILENT}] Richiede la soppressione di alcuni messaggi di + avvertimento nei log del kernel (vedi sez.~\ref{sec:sess_daemon}). L'opzione + è presente a partire dal kernel 2.6.17 e sostituisce, utilizzando un nome + non fuorviante, la precedente \const{MS\_VERBOSE}, introdotta nel kernel + 2.6.12, che aveva lo stesso effetto. +\item[\constd{MS\_STRICTATIME}] Ripristina il comportamento tradizionale per + cui l'\textit{access time} viene aggiornato ad ogni accesso al + file. L'opzione è disponibile solo a partire dal kernel 2.6.30 quando il + comportamento di default del kernel è diventato quello fornito da + \const{MS\_RELATIME}. +\item[\constd{MS\_SYNCHRONOUS}] Abilita la scrittura sincrona richiedendo che + ogni modifica al contenuto del filesystem venga immediatamente registrata su + disco. Lo stesso comportamento può essere ottenuto con il flag + \const{O\_SYNC} di \func{open} (vedi sez.~\ref{sec:file_open_close}). -\section{Il controllo di accesso ai file} -\label{sec:filedir_access_control} + Questa opzione consente di ridurre al minimo il rischio di perdita dei dati + in caso di crollo improvviso del sistema, al costo di una pesante perdita di + prestazioni dato che tutte le funzioni di scrittura non saranno più + bufferizzate e si bloccheranno fino all'arrivo dei dati sul disco. Per un + compromesso in cui questo comportamento avviene solo per le directory, ed ha + quindi una incidenza nettamente minore, si può usare \const{MS\_DIRSYNC}. + +\end{basedescript} + +% NOTE: per l'opzione \texttt{lazytime} introdotta con il kernel 4.0, +% vedi http://lwn.net/Articles/621046/ + +% NOTE per \const{MS\_SLAVE},\const{MS\_SHARE}, \const{MS\_PRIVATE} e +% \const{MS\_UNBINDABLE} dal 2.6.15 vedi shared subtrees, in particolare +% * http://lwn.net/Articles/159077/ e +% * Documentation/filesystems/sharedsubtree.txt + +% TODO: (bassa priorità) non documentati ma presenti in sys/mount.h: +% * MS_POSIXACL +% * MS_KERNMOUNT +% * MS_I_VERSION +% * MS_ACTIVE +% * MS_NOUSER + + +Una volta che non si voglia più utilizzare un certo filesystem è possibile +``\textsl{smontarlo}'' usando la funzione di sistema \funcd{umount}, il cui +prototipo è: + +\begin{funcproto}{ +\fhead{sys/mount.h} +\fdecl{umount(const char *target)} +\fdesc{Smonta un filesystem.} +} +{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{EBUSY}] il filesystem è occupato. + \item[\errcode{EINVAL}] \param{target} non è un \textit{mount point}. + \item[\errcode{EPERM}] il processo non ha i privilegi di + amministratore.\footnotemark + \end{errlist} + ed inoltre \errval{EFAULT}, \errval{ELOOP}, \errval{ENAMETOOLONG}, + \errval{ENOENT}, \errval{ENOMEM} nel loro significato generico. } +\end{funcproto} + +\footnotetext{più precisamente la capacità \const{CAP\_SYS\_ADMIN}, vedi + sez.~\ref{sec:proc_capabilities}.} + +La funzione prende il nome della directory su cui il filesystem è montato e +non il file o il dispositivo che è stato montato,\footnote{questo è vero a + partire dal kernel 2.3.99-pre7, prima esistevano due chiamate separate e la + funzione poteva essere usata anche specificando il file di dispositivo.} in +quanto a partire dai kernel della serie 2.4.x è possibile montare lo stesso +dispositivo in più punti. Nel caso più di un filesystem sia stato montato +sullo stesso \textit{mount point} viene smontato quello che è stato montato +per ultimo. Si tenga presente che la funzione fallisce se il filesystem è +``\textsl{occupato}'', cioè quando ci sono ancora dei file aperti sul +filesystem, se questo contiene la directory di lavoro (vedi +sez.~\ref{sec:file_work_dir}) di un qualunque processo o il \textit{mount + point} di un altro filesystem. + +Linux provvede inoltre una seconda funzione di sistema, \funcd{umount2}, che +consente un maggior controllo delle operazioni, come forzare lo smontaggio di +un filesystem anche quando questo risulti occupato; il suo prototipo è: + +\begin{funcproto}{ +\fhead{sys/mount.h} +\fdecl{umount2(const char *target, int flags)} +\fdesc{Smonta un filesystem.} +} +{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{EAGAIN}] si è chiamata la funzione con \const{MNT\_EXPIRE} + ed il filesystem non era occupato. + \item[\errcode{EBUSY}] \param{target} è la directory di lavoro di qualche + processo, o contiene dei file aperti, o un altro \textit{mount point}. + \item[\errcode{EINVAL}] \param{target} non è un \textit{mount point} o si + è usato \const{MNT\_EXPIRE} con \const{MNT\_FORCE} o + \const{MNT\_DETACH} o si è specificato un flag non esistente. + \end{errlist} + e tutti gli altri valori visti per \func{umount} con lo stesso significato.} +\end{funcproto} + +Il valore di \param{flags} è una maschera binaria dei flag che controllano le +modalità di smontaggio, che deve essere specificato con un OR aritmetico delle +costanti illustrate in tab.~\ref{tab:umount2_flags}. Specificando +\constd{MNT\_FORCE} la funzione cercherà di liberare il filesystem anche se è +occupato per via di una delle condizioni descritte in precedenza. A seconda +del tipo di filesystem alcune (o tutte) possono essere superate, evitando +l'errore di \errcode{EBUSY}. In tutti i casi prima dello smontaggio viene +eseguita una sincronizzazione dei dati. + +\begin{table}[!htb] + \centering + \footnotesize + \begin{tabular}[c]{|l|p{8cm}|} + \hline + \textbf{Costante} & \textbf{Descrizione}\\ + \hline + \hline + \const{MNT\_FORCE} & Forza lo smontaggio del filesystem anche se questo è + occupato (presente dai kernel della serie 2.2).\\ + \const{MNT\_DETACH} & Esegue uno smontaggio ``\textsl{pigro}'', in cui si + blocca l'accesso ma si aspetta che il filesystem si + liberi (presente dal kernel 2.4.11 e dalla + \acr{glibc} 2.11).\\ + \const{MNT\_EXPIRE} & Se non occupato marca un \textit{mount point} come + ``\textsl{in scadenza}'' in modo che ad una + successiva chiamata senza utilizzo del filesystem + questo venga smontato (presente dal + kernel 2.6.8 e dalla \acr{glibc} 2.11).\\ + \const{UMOUNT\_NOFOLLOW}& Non dereferenzia \param{target} se questo è un + collegamento simbolico (vedi + sez.~\ref{sec:link_symlink_rename}) evitando + problemi di sicurezza (presente dal kernel + 2.6.34).\\ + \hline + \end{tabular} + \caption{Costanti che identificano i bit dell'argomento \param{flags} + della funzione \func{umount2}.} + \label{tab:umount2_flags} +\end{table} + +Con l'opzione \constd{MNT\_DETACH} si richiede invece uno smontaggio +``\textsl{pigro}'' (o \textit{lazy umount}) in cui il filesystem diventa +inaccessibile per i nuovi processi subito dopo la chiamata della funzione, ma +resta accessibile per quelli che lo hanno ancora in uso e non viene smontato +fintanto che resta occupato. + +Con \constd{MNT\_EXPIRE}, che non può essere specificato insieme agli altri +due, si marca il \textit{mount point} di un filesystem non occupato come +``\textsl{in scadenza}'', in tal caso \func{umount2} ritorna con un errore di +\errcode{EAGAIN}, mentre in caso di filesystem occupato si sarebbe ricevuto +\errcode{EBUSY}. Una volta marcato, se nel frattempo non viene fatto nessun +uso del filesystem, ad una successiva chiamata con \const{MNT\_EXPIRE} questo +verrà smontato. Questo flag consente di realizzare un meccanismo che smonti +automaticamente i filesystem che restano inutilizzati per un certo periodo di +tempo. + +Infine il flag \constd{UMOUNT\_NOFOLLOW} non dereferenzia \param{target} se +questo è un collegamento simbolico (vedi +sez.~\ref{sec:link_symlink_rename}). Questa è una misura di sicurezza +introdotta per evitare, per quei filesystem per il quale è prevista una +gestione diretta da parte degli utenti, come quelli basati su \itindex{FUSE} +FUSE,\footnote{il \textit{Filesystem in USEr space} (FUSE) è una delle più + interessanti applicazioni del VFS che consente, tramite un opportuno modulo, + di implementarne le funzioni in \textit{user space}, così da rendere + possibile l'implementazione di un qualunque filesystem (con applicazioni di + grande interesse come il filesystem cifrato \textit{encfs} o il filesystem + di rete \textit{sshfs}) che possa essere usato direttamente per conto degli + utenti.} che si possano passare ai programmi che effettuano lo smontaggio +dei filesystem, che in genere sono privilegiati ma consentono di agire solo +sui propri \textit{mount point}, dei collegamenti simbolici che puntano ad +altri \textit{mount point}, ottenendo così la possibilità di smontare +qualunque filesystem. + + +Altre due funzioni di sistema specifiche di Linux,\footnote{esse si trovano + anche su BSD, ma con una struttura diversa.} utili per ottenere in maniera +diretta informazioni riguardo al filesystem su cui si trova un certo file, +sono \funcd{statfs} e \funcd{fstatfs}, i cui prototipi sono: + +\begin{funcproto}{ +\fhead{sys/vfs.h} +\fdecl{int statfs(const char *path, struct statfs *buf)} +\fdecl{int fstatfs(int fd, struct statfs *buf)} +\fdesc{Restituiscono informazioni relative ad un filesystem.} +} +{Le funzioni ritornano $0$ in caso di successo e $-1$ per un errore, + nel qual caso \var{errno} assumerà uno dei valori: + \begin{errlist} + \item[\errcode{ENOSYS}] il filesystem su cui si trova il file specificato + non supporta la funzione. + \end{errlist} ed inoltre \errval{EFAULT} ed \errval{EIO} per entrambe, + \errval{EBADF} per \func{fstatfs}, \errval{ENOTDIR}, \errval{ENAMETOOLONG}, + \errval{ENOENT}, \errval{EACCES}, \errval{ELOOP} per \func{statfs} nel loro + significato generico.} +\end{funcproto} + +Queste funzioni permettono di ottenere una serie di informazioni generali +riguardo al filesystem su cui si trova il file specificato con un +\textit{pathname} per \func{statfs} e con un file descriptor (vedi +sez.~\ref{sec:file_fd}) per \func{statfs}. Le informazioni vengono restituite +all'indirizzo \param{buf} di una struttura \struct{statfs} definita come in +fig.~\ref{fig:sys_statfs}, ed i campi che sono indefiniti per il filesystem in +esame sono impostati a zero. I valori del campo \var{f\_type} sono definiti +per i vari filesystem nei relativi file di header dei sorgenti del kernel da +costanti del tipo \var{XXX\_SUPER\_MAGIC}, dove \var{XXX} in genere è il nome +del filesystem stesso. + +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{0.8\textwidth} + \includestruct{listati/statfs.h} + \end{minipage} + \normalsize + \caption{La struttura \structd{statfs}.} + \label{fig:sys_statfs} +\end{figure} + +\conffilebeg{/etc/mtab} + +La \acr{glibc} provvede infine una serie di funzioni per la gestione dei due +file \conffiled{/etc/fstab}\footnote{più precisamente \funcm{setfsent}, + \funcm{getfsent}, \funcm{getfsfile}, \funcm{getfsspec}, \funcm{endfsent}.} +ed \conffile{/etc/mtab}\footnote{più precisamente \funcm{setmntent}, + \funcm{getmntent},\funcm{getmntent\_r}, \funcm{addmntent},\funcm{endmntent}, + \funcm{hasmntopt}.} che convenzionalmente sono usati in quasi tutti i +sistemi unix-like per mantenere rispettivamente le informazioni riguardo ai +filesystem da montare e a quelli correntemente montati. Le funzioni servono a +leggere il contenuto di questi file in opportune strutture \structd{fstab} e +\structd{mntent}, e, nel caso di \conffile{/etc/mtab}, per inserire e +rimuovere le voci presenti nel file. + +In generale si dovrebbero usare queste funzioni, in particolare quelle +relative a \conffile{/etc/mtab}, quando si debba scrivere un programma che +effettua il montaggio di un filesystem. In realtà in questi casi è molto più +semplice invocare direttamente il programma \cmd{mount}. Inoltre l'uso stesso +di \conffile{/etc/mtab} è considerato una pratica obsoleta, in quanto se non +aggiornato correttamente (cosa che è impossibile se la radice è montata in +sola lettura) il suo contenuto diventa fuorviante. + +Per questo motivo il suo utilizzo viene deprecato ed in molti casi viene già +oggi sostituito da un collegamento simbolico a \procfile{/proc/mounts}, che +contiene una versione degli stessi contenuti (vale a dire l'elenco dei +filesystem montati) generata direttamente dal kernel, e quindi sempre +disponibile e sempre aggiornata. Per questo motivo tralasceremo la +trattazione, di queste funzioni, rimandando al manuale della \acr{glibc} +\cite{GlibcMan} per la documentazione completa. + +\conffileend{/etc/mtab} + +% TODO (bassa priorità) scrivere delle funzioni (getfsent e getmntent &C) +% TODO (bassa priorità) documentare ? swapon e swapoff (man 2 ...) + + + +\section{La gestione di file e directory} +\label{sec:file_dir} + +In questa sezione esamineremo le funzioni usate per la manipolazione dei nomi +file e directory, per la creazione di collegamenti simbolici e diretti, per la +gestione e la lettura delle directory. In particolare ci soffermeremo sulle +conseguenze che derivano dalla architettura di un filesystem unix-like +illustrata in sez.~\ref{sec:file_filesystem} per quanto attiene il +comportamento e gli effetti delle varie funzioni. Tratteremo infine la +directory di lavoro e le funzioni per la gestione di file speciali e +temporanei. + + +\subsection{La gestione dei nomi dei file} +\label{sec:link_symlink_rename} + +% \subsection{Le funzioni \func{link} e \func{unlink}} +% \label{sec:file_link} + +Una caratteristica comune a diversi sistemi operativi è quella di poter creare +dei nomi alternativi, come gli alias del vecchio MacOS o i collegamenti di +Windows o i nomi logici del VMS, che permettono di fare riferimento allo +stesso file chiamandolo con nomi diversi o accedendovi da directory diverse. +Questo è possibile anche in ambiente Unix, dove un nome alternativo viene +usualmente chiamato ``\textsl{collegamento}'' (o \textit{link}). Data +l'architettura del sistema riguardo la gestione dei file vedremo però che ci +sono due metodi sostanzialmente diversi per fare questa operazione. + +\itindbeg{hard~link} +\index{collegamento!diretto|(} + +In sez.~\ref{sec:file_filesystem} abbiamo spiegato come la capacità di +chiamare un file con nomi diversi sia connaturata con l'architettura di un +filesystem per un sistema Unix, in quanto il nome del file che si trova in una +directory è solo un'etichetta associata ad un puntatore che permette di +ottenere il riferimento ad un \textit{inode}, e che è quest'ultimo che viene +usato dal kernel per identificare univocamente gli oggetti sul filesystem. + +Questo significa che fintanto che si resta sullo stesso filesystem la +realizzazione di un \textit{link} è immediata: uno stesso file può avere tanti +nomi diversi, dati da altrettante associazioni diverse allo stesso +\textit{inode} effettuate tramite ``etichette'' diverse in directory +diverse. Si noti anche come nessuno di questi nomi possa assumere una +particolare preferenza o originalità rispetto agli altri, in quanto tutti +fanno comunque riferimento allo stesso \textit{inode} e quindi tutti +otterranno lo stesso file. + +Quando si vuole aggiungere ad una directory una voce che faccia riferimento ad +un file già esistente come appena descritto, per ottenere quello che viene +denominato ``\textsl{collegamento diretto}'' (o \textit{hard link}), si deve +usare la funzione di sistema \funcd{link}, il cui prototipo è: + +\begin{funcproto}{ +\fhead{unistd.h} +\fdecl{int link(const char *oldpath, const char *newpath)} +\fdesc{Crea un nuovo collegamento diretto (\textit{hard link}).} +} +{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{EEXIST}] un file (o una directory) di nome \param{newpath} + esiste già. + \item[\errcode{EMLINK}] ci sono troppi collegamenti al file \param{oldpath} + (il numero massimo è specificato dalla variabile \const{LINK\_MAX}, vedi + sez.~\ref{sec:sys_limits}). + \item[\errcode{EPERM}] il filesystem che contiene \param{oldpath} e + \param{newpath} non supporta i collegamenti diretti, è una directory o per + \param{oldpath} non si rispettano i criteri per i \textit{protected + hardlink}.\footnotemark + \item[\errcode{EXDEV}] i file \param{oldpath} e \param{newpath} non fanno + riferimento ad un filesystem montato sullo stesso + \textit{mount point}. + \end{errlist} ed inoltre \errval{EACCES}, \errval{EDQUOT}, \errval{EFAULT}, + \errval{EIO}, \errval{ELOOP}, \errval{ENAMETOOLONG}, \errval{ENOENT}, + \errval{ENOMEM}, \errval{ENOSPC}, \errval{ENOTDIR}, \errval{EROFS} nel loro + significato generico.} +\end{funcproto} + +\footnotetext{i \textit{protected hardlink} sono una funzionalità di + protezione introdotta con il kernel 3.16 (si veda + sez.~\ref{sec:procadv_security_misc} per i dettagli) che limita la capacità + di creare un \textit{hard link} ad un file qualunque.} + +La funzione crea in \param{newpath} un collegamento diretto al file indicato +da \param{oldpath}. Per quanto detto la creazione di un nuovo collegamento +diretto non copia il contenuto del file, ma si limita a creare la voce +specificata da \param{newpath} nella directory corrispondente e l'unica +proprietà del file che verrà modificata sarà il numero di riferimenti al file +(il campo \var{i\_nlink} della struttura \kstruct{inode}, vedi +fig.~\ref{fig:kstruct_inode}) che verrà aumentato di uno. In questo modo lo +stesso file potrà essere acceduto sia con \param{newpath} che +con \param{oldpath}. + +Per quanto dicevamo in sez.~\ref{sec:file_filesystem} la creazione di un +collegamento diretto è possibile solo se entrambi i \textit{pathname} sono +nello stesso filesystem ed inoltre esso deve supportare gli \textit{hard link} +(il meccanismo non è disponibile ad esempio con il filesystem \acr{vfat} di +Windows). In realtà la funzione ha un ulteriore requisito, e cioè che non solo +che i due file siano sullo stesso filesystem, ma anche che si faccia +riferimento ad essi all'interno dello stesso \textit{mount point}.\footnote{si + tenga presente infatti, come detto in sez.~\ref{sec:filesystem_mounting}, + che a partire dal kernel 2.4 uno stesso filesystem può essere montato più + volte su directory diverse.} +La funzione inoltre opera sia sui file ordinari che sugli altri oggetti del +filesystem, con l'eccezione delle directory. In alcune versioni di Unix solo +l'amministratore è in grado di creare un collegamento diretto ad un'altra +directory: questo viene fatto perché con una tale operazione è possibile +creare dei \textit{loop} nel filesystem (vedi fig.~\ref{fig:file_link_loop}) +la cui rimozione diventerebbe piuttosto complicata.\footnote{occorrerebbe + infatti eseguire il programma \cmd{fsck} per riparare il filesystem, perché + in caso di \textit{loop} la directory non potrebbe essere più svuotata, + contenendo comunque se stessa, e quindi non potrebbe essere rimossa.} + +Data la pericolosità di questa operazione, e visto che i collegamenti +simbolici (che tratteremo a breve) ed i \textit{bind mount} (già visti in +sez.~\ref{sec:filesystem_mounting}) possono fornire la stessa funzionalità +senza questi problemi, nel caso di Linux questa capacità è stata completamente +disabilitata, e al tentativo di creare un collegamento diretto ad una +directory la funzione \func{link} restituisce sempre l'errore \errcode{EPERM}. +Un ulteriore comportamento peculiare di Linux è quello in cui si crea un +\textit{hard link} ad un collegamento simbolico. In questo caso lo standard +POSIX.1-2001 prevederebbe che quest'ultimo venga risolto e che il collegamento +sia effettuato rispetto al file cui esso punta, e che venga riportato un +errore qualora questo non esista o non sia un file. Questo era anche il +comportamento iniziale di Linux ma a partire dai kernel della serie +2.0.x\footnote{per la precisione il comportamento era quello previsto dallo + standard POSIX fino al kernel di sviluppo 1.3.56, ed è stato temporaneamente + ripristinato anche durante lo sviluppo della serie 2.1.x, per poi tornare al + comportamento attuale fino ad oggi (per riferimento si veda + \url{http://lwn.net/Articles/293902}).} è stato adottato un comportamento +che non segue più lo standard per cui l'\textit{hard link} viene creato nei +confronti del collegamento simbolico, e non del file cui questo punta. La +revisione POSIX.1-2008 lascia invece il comportamento dipendente +dall'implementazione, cosa che rende Linux conforme a questa versione +successiva dello standard. -\subsection{I flag \texttt{suid} e \texttt{sgid}} -\label{sec:filedir_suid_sgid} +\itindbeg{symbolic~link} +\index{collegamento!simbolico|(} -\subsection{La titolarità di nuovi files e directory} -\label{sec:filedir_ownership} +La ragione di questa differenza rispetto al vecchio standard, presente anche +in altri sistemi unix-like, è dovuta al fatto che un collegamento simbolico +può fare riferimento anche ad un file non esistente o a una directory, per i +quali l'\textit{hard link} non può essere creato, per cui la scelta di seguire +il collegamento simbolico è stata ritenuta una scelta scorretta nella +progettazione dell'interfaccia. Infatti se non ci fosse il comportamento +adottato da Linux sarebbe impossibile creare un \textit{hard link} ad un +collegamento simbolico, perché la funzione lo risolverebbe e l'\textit{hard + link} verrebbe creato verso la destinazione. Invece evitando di seguire lo +standard l'operazione diventa possibile, ed anche il comportamento della +funzione risulta molto più comprensibile. Tanto più che se proprio se si vuole +creare un \textit{hard link} rispetto alla destinazione di un collegamento +simbolico è sempre possibile farlo direttamente.\footnote{ciò non toglie che + questo comportamento possa causare problemi, come nell'esempio descritto + nell'articolo citato nella nota precedente, a programmi che non si aspettano + questa differenza rispetto allo standard POSIX.} + +Dato che \func{link} crea semplicemente dei nomi che fanno riferimenti agli +\textit{inode}, essa può funzionare soltanto per file che risiedono sullo +stesso filesystem e solo per un filesystem di tipo Unix. Inoltre abbiamo +visto che in Linux non è consentito eseguire un collegamento diretto ad una +directory. + +Per ovviare a queste limitazioni, come accennato all'inizio, i sistemi +unix-like supportano un'altra forma di collegamento, detta +``\textsl{collegamento simbolico}'' (o anche \textit{soft link} o +\textit{symbolic link}). In questo caso si tratta, come avviene in altri +sistemi operativi, di file speciali che contengono semplicemente il +riferimento ad un altro file (o directory). In questo modo è possibile +effettuare \textit{link} anche attraverso filesystem diversi, a file posti in +filesystem che non supportano i collegamenti diretti, a delle directory, ed +anche a file che non esistono ancora. + +\itindend{hard~link} +\index{collegamento!diretto|)} + +Il meccanismo funziona in quanto i \textit{symbolic link} sono riconosciuti +come tali dal kernel\footnote{è uno dei diversi tipi di file visti in + tab.~\ref{tab:file_file_types}, contrassegnato come tale nell'\textit{inode} + e riconoscibile dal valore del campo \var{st\_mode} della struttura + \struct{stat} (vedi sez.~\ref{sec:file_stat}).} e tutta una serie di +funzioni di sistema (come \func{open} o \func{stat}) quando ricevono come +argomento il \textit{pathname} di un collegamento simbolico vanno +automaticamente ad operare sul file da esso specificato. La funzione di +sistema che permette di creare un nuovo collegamento simbolico è +\funcd{symlink}, ed il suo prototipo è: + +\begin{funcproto}{ +\fhead{unistd.h} +\fdecl{int symlink(const char *oldpath, const char *newpath)} +\fdesc{Crea un nuovo collegamento simbolico (\textit{symbolic link}).} +} +{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{EACCES}] o non si hanno i permessi sulla directory in cui + creare il \textit{link}. + \item[\errcode{EEXIST}] esiste già un file \param{newpath}. + \item[\errcode{ENOENT}] una componente di \param{newpath} non esiste o + \param{oldpath} è una stringa vuota. + \item[\errcode{EPERM}] il filesystem che contiene \param{newpath} non + supporta i collegamenti simbolici. + \item[\errcode{EROFS}] \param{newpath} è su un filesystem montato in sola + lettura. + \end{errlist} ed inoltre \errval{EDQUOT}, \errval{EFAULT}, \errval{EIO}, + \errval{ELOOP}, \errval{ENAMETOOLONG}, \errval{ENOMEM}, \errval{ENOSPC} e + \errval{ENOTDIR} nel loro significato generico.} +\end{funcproto} + + +La funzione crea un nuovo collegamento simbolico \param{newpath} che fa +riferimento ad \param{oldpath}. Si tenga presente che la funzione non +effettua nessun controllo sull'esistenza di un file di nome \param{oldpath}, +ma si limita ad inserire il \textit{pathname} nel collegamento +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}''. 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 +precedenza 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 +tab.~\ref{tab:file_symb_effect} si è riportato un elenco dei comportamenti +delle varie funzioni di sistema che operano sui file nei confronti della +risoluzione dei collegamenti simbolici, specificando quali li seguono e quali +invece possono operare direttamente sui loro contenuti. +\begin{table}[htb] + \centering + \footnotesize + \begin{tabular}[c]{|l|c|c|} + \hline + \textbf{Funzione} & \textbf{Segue il link} & \textbf{Non segue il link} \\ + \hline + \hline + \func{access} & $\bullet$ & -- \\ + \func{chdir} & $\bullet$ & -- \\ + \func{chmod} & $\bullet$ & -- \\ + \func{chown} & -- & $\bullet$ \\ + \func{creat} & $\bullet$ & -- \\ + \func{exec} & $\bullet$ & -- \\ + \func{lchown} & $\bullet$ & -- \\ + \func{link}\footnotemark & -- & $\bullet$ \\ + \func{lstat} & -- & $\bullet$ \\ + \func{mkdir} & $\bullet$ & -- \\ + \func{mkfifo} & $\bullet$ & -- \\ + \func{mknod} & $\bullet$ & -- \\ + \func{open} & $\bullet$ & -- \\ + \func{opendir} & $\bullet$ & -- \\ + \func{pathconf} & $\bullet$ & -- \\ + \func{readlink} & -- & $\bullet$ \\ + \func{remove} & -- & $\bullet$ \\ + \func{rename} & -- & $\bullet$ \\ + \func{stat} & $\bullet$ & -- \\ + \func{truncate} & $\bullet$ & -- \\ + \func{unlink} & -- & $\bullet$ \\ + \hline + \end{tabular} + \caption{Uso dei collegamenti simbolici da parte di alcune funzioni.} + \label{tab:file_symb_effect} +\end{table} + +\footnotetext{a partire dalla serie 2.0, e contrariamente a quanto indicato + dallo standard POSIX.1-2001.} + +Si noti che non si è specificato il comportamento delle funzioni che operano +con i file descriptor (che tratteremo nel prossimo capitolo), in quanto la +risoluzione del collegamento simbolico viene in genere effettuata dalla +funzione che restituisce il file descriptor (normalmente la \func{open}, vedi +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 aggiuntive +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 +esso fa riferimento. Quando si vuole leggere il contenuto di un collegamento +simbolico si usa la funzione di sistema \funcd{readlink}, il cui prototipo è: + +\begin{funcproto}{ +\fhead{unistd.h} +\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{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{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{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=8cm]{img/link_loop} + \caption{Esempio di loop nel filesystem creato con un collegamento + simbolico.} + \label{fig:file_link_loop} +\end{figure} + +Come accennato uno dei motivi per cui non sono consentiti \textit{hard link} +alle directory è che questi possono creare dei \textit{loop} nella risoluzione +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 +\file{/boot}.\footnote{il \textit{loop} mostrato in + 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}. 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} +\index{collegamento!simbolico|)} + +Un'altra funzione relativa alla gestione dei nomi dei file, anche se a prima +vista parrebbe riguardare un argomento completamente diverso, è quella per la +cancellazione di un file. In realtà una \textit{system call} che serva proprio +a cancellare un file non esiste neanche perché, come accennato in +sez.~\ref{sec:file_filesystem}, quando in un sistema unix-like si richiede la +rimozione di un file, quello che si va a cancellare è soltanto la voce che +referenzia il suo \textit{inode} all'interno di una directory. + +La funzione di sistema che consente di effettuare questa operazione, il cui +nome come si può notare ha poco a che fare con il concetto di rimozione, è +\funcd{unlink}, ed il suo prototipo è: + +\begin{funcproto}{ +\fhead{unistd.h} +\fdecl{int unlink(const char *pathname)} +\fdesc{Cancella un file.} +} +{La funzione ritorna $0$ in caso di successo e $-1$ per un errore, + 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 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 cosiddetti \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 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.} +\end{funcproto} + +\footnotetext{questa funzione su Linux ha alcune peculiarità nei codici di + errore, in particolare riguardo la rimozione delle directory che non è mai + permessa e che causa l'errore \errcode{EISDIR}; questo è un valore specifico + di Linux non conforme allo standard POSIX che prescrive invece l'uso di + \errcode{EPERM} in caso l'operazione non sia consentita o il processo non + abbia privilegi sufficienti, valore che invece Linux usa anche se il + filesystem non supporta la funzione, inoltre il codice \errcode{EBUSY} nel + caso la directory sia occupata su Linux non esiste.} + +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}; 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 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 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, 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 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}{ +\fhead{stdio.h} +\fdecl{int remove(const char *pathname)} +\fdesc{Cancella un file o una directory.} +} +{La funzione ritorna $0$ in caso di successo e $-1$ per un errore, nel qual + caso \var{errno} assumerà uno dei valori relativi alla chiamata utilizzata, + pertanto si può fare riferimento a quanto illustrato nelle descrizioni di + \func{unlink} e \func{rmdir}.} +\end{funcproto} + +La funzione utilizza la funzione \func{unlink} per cancellare i file (e si +applica anche a link simbolici, socket, \textit{fifo} e file di dispositivo) 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, + ma si applica solo per i file, lo standard POSIX estende la funzione anche + alle directory.} il cui prototipo è: + +\begin{funcproto}{ +\fhead{stdio.h} +\fdecl{int rename(const char *oldpath, const char *newpath)} +\fdesc{Rinomina un file o una directory.} +} +{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}] manca il permesso di scrittura sulle directory + contenenti \param{oldpath} e \param{newpath} o di attraversare + 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 + sistema (come \textit{mount point}) ed il sistema non riesce a risolvere + la situazione. + \item[\errcode{EEXIST}] \param{newpath} è una directory già esistente e + non è vuota (anche \errcode{ENOTEMPTY}). + \item[\errcode{EINVAL}] \param{newpath} contiene un prefisso di + \param{oldpath} o più in generale si è cercato di creare una directory come + sotto-directory di sé stessa. + \item[\errcode{EISDIR}] \param{newpath} è una directory mentre + \param{oldpath} non è una directory. + \item[\errcode{ENOTDIR}] uno dei componenti dei \textit{pathname} non è una + directory o \param{oldpath} è una directory e + \param{newpath} esiste e non è una directory. + \item[\errval{EPERM}] la directory contenente \param{oldpath} o quella + contenente un \param{newpath} esistente hanno lo \textit{sticky bit} e non + si è i proprietari dei rispettivi file (o non si hanno privilegi + amministrativi) oppure il filesystem non supporta l'operazione. + \item[\errcode{EXDEV}] \param{oldpath} e \param{newpath} non sono sullo + stesso filesystem e sotto lo stesso \textit{mount point}. + \end{errlist} ed inoltre \errval{EFAULT}, \errval{ELOOP}, \errval{EMLINK}, + \errval{ENAMETOOLONG}, \errval{ENOENT}, \errval{ENOMEM}, \errval{ENOSPC} e + \errval{EROFS} nel loro significato generico.} +\end{funcproto} + +La funzione rinomina in \param{newpath} il file o la directory indicati +dall'argomento \param{oldpath}. Il nome viene eliminato nella directory +originale e ricreato nella directory di destinazione mantenendo il riferimento +allo stesso \textit{inode}. Non viene spostato nessun dato e l'\textit{inode} +del file non subisce nessuna modifica in quanto le modifiche sono eseguite +sulle directory che contengono \param{newpath} ed \param{oldpath}. + +Il vantaggio nell'uso di questa funzione al posto della chiamata successiva di +\func{link} e \func{unlink} è che l'operazione è eseguita atomicamente, non +c'è modifica, per quanto temporanea, al \textit{link count} del file e non può +esistere un istante in cui un altro processo possa trovare attivi entrambi i +nomi per lo stesso file se la destinazione non esiste o in cui questa sparisca +temporaneamente se già esiste. + +Dato che opera in maniera analoga la funzione è soggetta alle stesse +restrizioni di \func{link}, quindi è necessario che \param{oldpath} +e \param{newpath} siano nello stesso filesystem e facciano riferimento allo +stesso \textit{mount point}, e che il filesystem supporti questo tipo di +operazione. Qualora questo non avvenga si dovrà effettuare l'operazione in +maniera non atomica copiando il file a destinazione e poi cancellando +l'originale. + +Il comportamento della funzione è diverso a seconda che si voglia rinominare +un file o una directory. Se ci riferisce ad un file allora \param{newpath}, se +esiste, non deve essere una directory, altrimenti si avrà un errore di +\errcode{EISDIR}. Se \param{newpath} indica un file già esistente questo verrà +rimpiazzato atomicamente, ma nel caso in cui \func{rename} fallisca il kernel +assicura che esso non sarà toccato. I caso di sovrascrittura però potrà +esistere una breve finestra di tempo in cui sia \param{oldpath} +che \param{newpath} potranno fare entrambi riferimento al file che viene +rinominato. + +Se \param{oldpath} è una directory allora \param{newpath}, se esistente, deve +essere una directory vuota, altrimenti si avranno gli errori \errcode{ENOTDIR} +(se non è una directory) o \errcode{ENOTEMPTY} o \errcode{EEXIST} (se non è +vuota). Chiaramente \param{newpath} non potrà contenere \param{oldpath} nel +suo \textit{pathname}, non essendo possibile rendere una directory una +sottodirectory di sé stessa, se questo fosse il caso si otterrebbe un errore +di \errcode{EINVAL}. + +Se \param{oldpath} si riferisce ad un collegamento simbolico questo sarà +rinominato restando tale senza nessun effetto sul file a cui fa riferimento. +Se invece \param{newpath} esiste ed è un collegamento simbolico verrà +cancellato come qualunque altro file. Infine qualora \param{oldpath} +e \param{newpath} siano due nomi che già fanno riferimento allo stesso file lo +standard POSIX prevede che la funzione non ritorni un errore, e semplicemente +non faccia nulla, lasciando entrambi i nomi. Linux segue questo standard, +anche se, come fatto notare dal manuale della \acr{glibc}, il comportamento +più ragionevole sarebbe quello di cancellare \param{oldpath}. + +In tutti i casi si dovranno avere i permessi di scrittura nelle directory +contenenti \param{oldpath} e \param{newpath}, e nel caso \param{newpath} sia +una directory vuota già esistente anche su di essa (perché dovrà essere +aggiornata la voce ``\texttt{..}''). Se poi le directory +contenenti \param{oldpath} o \param{newpath} hanno lo \textit{sticky bit} +attivo (vedi sez.~\ref{sec:file_special_perm}) si dovrà essere i proprietari +dei file (o delle directory) che si vogliono rinominare, o avere i permessi di +amministratore. + + +\subsection{La creazione e la cancellazione delle directory} +\label{sec:file_dir_creat_rem} + +Benché in sostanza le directory non siano altro che dei file contenenti +elenchi di nomi con riferimenti ai rispettivi \textit{inode}, non è possibile +trattarle come file ordinari e devono essere create direttamente dal kernel +attraverso una opportuna \textit{system call}.\footnote{questo è quello che + permette anche, attraverso l'uso del VFS, l'utilizzo di diversi formati per + la gestione dei suddetti elenchi, dalle semplici liste a strutture complesse + come alberi binari, hash, ecc. che consentono una ricerca veloce quando il + numero di file è molto grande.} La funzione di sistema usata per creare una +directory è \funcd{mkdir}, ed il suo prototipo è: + +\begin{funcproto}{ +\fhead{sys/stat.h} +\fhead{sys/types.h} +\fdecl{int mkdir(const char *dirname, mode\_t mode)} +\fdesc{Crea una nuova directory.} +} +{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{EACCES}] non c'è il permesso di scrittura per la directory in + cui si vuole inserire la nuova directory o di attraversamento per le + directory al di sopra di essa. + \item[\errcode{EEXIST}] un file o una directory o un collegamento simbolico + con quel nome esiste già. + \item[\errcode{EMLINK}] la directory in cui si vuole creare la nuova + directory contiene troppi file; sotto Linux questo normalmente non avviene + perché il filesystem standard consente la creazione di un numero di file + maggiore di quelli che possono essere contenuti nel disco, ma potendo + avere a che fare anche con filesystem di altri sistemi questo errore può + presentarsi. + \item[\errcode{ENOSPC}] non c'è abbastanza spazio sul file system per creare + la nuova directory o si è esaurita la quota disco dell'utente. + \end{errlist} + ed inoltre \errval{EFAULT}, \errval{ELOOP}, \errval{ENAMETOOLONG}, + \errval{ENOENT}, \errval{ENOMEM}, \errval{ENOTDIR}, \errval{EPERM}, + \errval{EROFS} nel loro significato generico.} +\end{funcproto} + +La funzione crea una nuova directory vuota, che contiene cioè solo le due voci +standard presenti in ogni directory (``\file{.}'' e ``\file{..}''), con il +nome indicato dall'argomento \param{dirname}. + +I permessi di accesso (vedi sez.~\ref{sec:file_access_control}) con cui la +directory viene creata sono specificati dall'argomento \param{mode}, i cui +possibili valori sono riportati in tab.~\ref{tab:file_permission_const}; si +tenga presente che questi sono modificati dalla maschera di creazione dei file +(si veda sez.~\ref{sec:file_perm_management}). La titolarità della nuova +directory è impostata secondo quanto illustrato in +sez.~\ref{sec:file_ownership_management}. + +Come accennato in precedenza per eseguire la cancellazione di una directory è +necessaria una specifica funzione di sistema, \funcd{rmdir}, il suo prototipo +è: + +\begin{funcproto}{ +\fhead{sys/stat.h} +\fdecl{int rmdir(const char *dirname)} +\fdesc{Cancella una directory.} +} +{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{EACCES}] non c'è il permesso di scrittura per la directory + che contiene la directory che si vuole cancellare, o non c'è il permesso + di attraversare (esecuzione) una delle directory specificate in + \param{dirname}. + \item[\errcode{EBUSY}] la directory specificata è la directory di lavoro o + la radice di qualche processo o un \textit{mount point}. + \item[\errcode{EINVAL}] si è usato ``\texttt{.}'' come ultimo componente + di \param{dirname}. + \item[\errcode{EPERM}] il filesystem non supporta la cancellazione di + directory, oppure la directory che contiene \param{dirname} ha lo + \textit{sticky bit} impostato e non si è i proprietari della directory o + non si hanno privilegi amministrativi. + \end{errlist} + ed inoltre \errval{EFAULT}, \errval{ELOOP}, \errval{ENAMETOOLONG}, + \errval{ENOENT}, \errval{ENOMEM}, \errval{ENOTDIR}, \errcode{ENOTEMPTY} e + \errval{EROFS} nel loro significato generico.} +\end{funcproto} -\subsection{La funzione \texttt{access}} -\label{sec:filedir_access} -\subsection{La funzione \texttt{umask}} -\label{sec:filedir_umask} +La funzione cancella la directory \param{dirname}, che deve essere vuota, la +directory deve cioè contenere le due voci standard ``\file{.}'' e +``\file{..}'' e niente altro. Il nome può essere indicato con un +\textit{pathname} assoluto o relativo, ma si deve fare riferimento al nome +nella directory genitrice, questo significa che \textit{pathname} terminanti +in ``\file{.}'' e ``\file{..}'' anche se validi in altri contesti, causeranno +il fallimento della funzione. + +Inoltre per eseguire la cancellazione, oltre ad essere vuota, occorre anche +che la directory non sia utilizzata, questo vuol dire anche che non deve +essere la directory di lavoro (vedi sez.~\ref{sec:file_work_dir}) o la +directory radice (vedi sez.~\ref{sec:file_chroot}) di nessun processo, od +essere utilizzata come \textit{mount point}. + +Se la directory cancellata risultasse aperta in qualche processo per una +lettura dei suoi contenuti (vedi sez.~\ref{sec:file_dir_read}), pur +scomparendo dal filesystem e non essendo più possibile accedervi o crearvi +altri file, le risorse ad essa associate verrebbero disallocate solo alla +chiusura di tutti questi ulteriori riferimenti. + + +\subsection{Lettura e scansione delle directory} +\label{sec:file_dir_read} + +Benché le directory alla fine non siano altro che dei file che contengono +delle liste di nomi associati ai relativi \textit{inode}, per il ruolo che +rivestono nella struttura del sistema non possono essere trattate come dei +normali file di dati. Ad esempio, onde evitare inconsistenze all'interno del +filesystem, solo il kernel può scrivere il contenuto di una directory, e non +può essere un processo a inserirvi direttamente delle voci con le usuali +funzioni di scrittura. + +Ma se la scrittura e l'aggiornamento dei dati delle directory è compito del +kernel, sono molte le situazioni in cui i processi necessitano di poterne +leggere il contenuto. Benché questo possa essere fatto direttamente (vedremo +in sez.~\ref{sec:file_open_close} che è possibile aprire una directory come se +fosse un file, anche se solo in sola lettura) in generale il formato con cui +esse sono scritte può dipendere dal tipo di filesystem, tanto che, come +riportato in tab.~\ref{tab:file_file_operations}, il VFS prevede una apposita +funzione per la lettura delle directory. + +\itindbeg{directory~stream} + +Tutto questo si riflette nello standard POSIX\footnote{le funzioni erano + presenti in SVr4 e 4.3BSD, la loro specifica è riportata in POSIX.1-2001.} +che ha introdotto una apposita interfaccia per la lettura delle directory, +basata sui cosiddetti \textit{directory stream}, chiamati così per l'analogia +con i \textit{file stream} dell'interfaccia standard ANSI C che vedremo in +sez.~\ref{sec:files_std_interface}. La prima funzione di questa interfaccia è +\funcd{opendir}, il cui prototipo è: + +\begin{funcproto}{ +\fhead{sys/types.h} +\fhead{dirent.h} +\fdecl{DIR *opendir(const char *dirname)} +\fdesc{Apre un \textit{directory stream}.} +} +{La funzione ritorna un puntatore al \textit{directory stream} in caso di + successo e \val{NULL} per un errore, nel qual caso \var{errno} assumerà uno + dei valori \errval{EACCES}, \errval{EMFILE}, \errval{ENFILE}, + \errval{ENOENT}, \errval{ENOMEM} e \errval{ENOTDIR} nel loro significato + generico.} +\end{funcproto} + +La funzione apre un \textit{directory stream} per la directory +\param{dirname}, ritornando il puntatore ad un oggetto di tipo \typed{DIR} (che +è il tipo opaco usato dalle librerie per gestire i \textit{directory stream}) +da usare per tutte le operazioni successive, la funzione inoltre posiziona lo +\textit{stream} sulla prima voce contenuta nella directory. + +Si tenga presente che comunque la funzione opera associando il +\textit{directory stream} ad un opportuno file descriptor sottostante, sul +quale vengono compiute le operazioni. Questo viene sempre aperto impostando il +flag di \textit{close-on-exec} (si ricordi quanto detto in +sez.~\ref{sec:proc_exec}), così da evitare che resti aperto in caso di +esecuzione di un altro programma. + +Nel caso in cui sia necessario conoscere il \textit{file descriptor} associato +ad un \textit{directory stream} si può usare la funzione +\funcd{dirfd},\footnote{questa funzione è una estensione introdotta con BSD + 4.3-Reno ed è presente in Linux con le libc5 (a partire dalla versione + 5.1.2) e con la \acr{glibc} ma non presente in POSIX fino alla revisione + POSIX.1-2008, per questo per poterla utilizzare fino alla versione 2.10 + della \acr{glibc} era necessario definire le macro \macro{\_BSD\_SOURCE} o + \macro{\_SVID\_SOURCE}, dalla versione 2.10 si possono usare anche + \texttt{\macro{\_POSIX\_C\_SOURCE} >= 200809L} o + \texttt{\macro{\_XOPEN\_SOURCE} >= 700}.} il cui prototipo è: + +\begin{funcproto}{ +\fhead{sys/types.h} +\fhead{dirent.h} +\fdecl{int dirfd(DIR *dir)} +\fdesc{Legge il file descriptor associato ad un \textit{directory stream}.} +} +{La funzione ritorna un valore positivo corrispondente al file descriptor in + caso di successo e $-1$ per un errore, nel qual caso \var{errno} assumerà + uno dei valori: + \begin{errlist} + \item[\errcode{EINVAL}] \param{dir} non è un puntatore ad un + \textit{directory stream}. + \item[\errcode{ENOTSUP}] l'implementazione non supporta l'uso di un file + descriptor per la directory. + \end{errlist} +} +\end{funcproto} + +La funzione restituisce il file descriptor associato al \textit{directory + stream} \param{dir}. Di solito si utilizza questa funzione in abbinamento a +funzioni che operano sui file descriptor, ad esempio si potrà usare +\func{fstat} per ottenere le proprietà della directory, o \func{fchdir} per +spostare su di essa la directory di lavoro (vedi sez.~\ref{sec:file_work_dir}). + +Viceversa se si è aperto un file descriptor corrispondente ad una directory è +possibile associarvi un \textit{directory stream} con la funzione +\funcd{fdopendir},\footnote{questa funzione è però disponibile solo a partire + dalla versione 2.4 della \acr{glibc}, ed è stata introdotta nello standard + POSIX solo a partire dalla revisione POSIX.1-2008, prima della versione 2.10 + della \acr{glibc} per poterla utilizzare era necessario definire la macro + \macro{\_GNU\_SOURCE}, dalla versione 2.10 si possono usare anche + \texttt{\macro{\_POSIX\_C\_SOURCE} >= 200809L} o \texttt{\_XOPEN\_SOURCE >= + 700} .} il cui prototipo è: + +\begin{funcproto}{ +\fhead{sys/types.h} +\fhead{dirent.h} +\fdecl{DIR *fdopendir(int fd)} +\fdesc{Associa un \textit{directory stream} ad un file descriptor.} +} +{La funzione ritorna un puntatore al \textit{directory stream} in caso di + successo e \val{NULL} per un errore, nel qual caso \var{errno} assumerà uno + dei valori \errval{EBADF} o \errval{ENOMEM} nel loro significato generico.} +\end{funcproto} + +La funzione è identica a \func{opendir}, ma ritorna un \textit{directory + stream} facendo riferimento ad un file descriptor \param{fd} che deve essere +stato aperto in precedenza; la funzione darà un errore qualora questo non +corrisponda ad una directory. L'uso di questa funzione permette di rispondere +agli stessi requisiti delle funzioni ``\textit{at}'' che vedremo in +sez.~\ref{sec:file_openat}. + +Una volta utilizzata il file descriptor verrà usato internamente dalle +funzioni che operano sul \textit{directory stream} e non dovrà essere più +utilizzato all'interno del proprio programma. In particolare dovrà essere +chiuso attraverso il \textit{directory stream} con \func{closedir} e non +direttamente. Si tenga presente inoltre che \func{fdopendir} non modifica lo +stato di un eventuale flag di \textit{close-on-exec}, che pertanto dovrà +essere impostato esplicitamente in fase di apertura del file descriptor. + +Una volta che si sia aperto un \textit{directory stream} la lettura del +contenuto della directory viene effettuata attraverso la funzione +\funcd{readdir}, il cui prototipo è: + +\begin{funcproto}{ +\fhead{sys/types.h} +\fhead{dirent.h} +\fdecl{struct dirent *readdir(DIR *dir)} +\fdesc{Legge una voce dal \textit{directory stream}.} +} +{La funzione ritorna il puntatore alla struttura contenente i dati in caso di + successo e \val{NULL} per un errore o se si è raggiunta la fine dello + \textit{stream}. Il solo codice di errore restituito in \var{errno} è + \errval{EBADF} qualora \param{dir} non indichi un \textit{directory stream} + valido.} +\end{funcproto} + +La funzione legge la voce corrente nella directory, posizionandosi sulla voce +successiva. Pertanto se si vuole leggere l'intero contenuto di una directory +occorrerà ripetere l'esecuzione della funzione fintanto che non si siano +esaurite tutte le voci in essa presenti, che viene segnalata dalla +restituzione di \val{NULL} come valore di ritorno. Si può distinguere questa +condizione da un errore in quanto in questo caso \var{errno} non verrebbe +modificata. + +I dati letti da \func{readdir} vengono memorizzati in una struttura +\struct{dirent}, la cui definizione è riportata in +fig.~\ref{fig:file_dirent_struct}.\footnote{la definizione è quella usata da + Linux, che si trova nel file \file{/usr/include/bits/dirent.h}, essa non + contempla la presenza del campo \var{d\_namlen} che indica la lunghezza del + nome del file.} La funzione non è rientrante e restituisce il puntatore ad +una struttura allocata staticamente, che viene sovrascritta tutte le volte che +si ripete la lettura di una voce sullo stesso \textit{directory stream}. + +Di questa funzione esiste anche una versione rientrante, +\funcd{readdir\_r},\footnote{per usarla è necessario definire una qualunque + delle macro \texttt{\macro{\_POSIX\_C\_SOURCE} >= 1}, + \macro{\_XOPEN\_SOURCE}, \macro{\_BSD\_SOURCE}, \macro{\_SVID\_SOURCE}, + \macro{\_POSIX\_SOURCE}.} che non usa una struttura allocata staticamente, e +può essere utilizzata anche con i \textit{thread}, il suo prototipo è: + +\begin{funcproto}{ +\fhead{sys/types.h} +\fhead{dirent.h} +\fdecl{int readdir\_r(DIR *dir, struct dirent *entry, struct dirent **result)} +\fdesc{Legge una voce dal \textit{directory stream}.} +} +{La funzione ritorna $0$ in caso di successo ed un numero positivo per un + errore, nel qual caso \var{errno} assumerà gli stessi valori di + \func{readdir}.} +\end{funcproto} + +La funzione restituisce in \param{result} come \textit{value result argument} +l'indirizzo della struttura \struct{dirent} dove sono stati salvati i dati, +che deve essere allocata dal chiamante, ed il cui indirizzo deve essere +indicato con l'argomento \param{entry}. Se si è raggiunta la fine del +\textit{directory stream} invece in \param{result} viene restituito il valore +\val{NULL}. + +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{0.8\textwidth} + \includestruct{listati/dirent.c} + \end{minipage} + \normalsize + \caption{La struttura \structd{dirent} per la lettura delle informazioni dei + file.} + \label{fig:file_dirent_struct} +\end{figure} + +% Lo spazio per la \struct{dirent} dove vengono restituiti i dati della +% directory deve essere allocato a cura del chiamante, dato che la dimensione + + +I vari campi di \struct{dirent} contengono le informazioni relative alle voci +presenti nella directory. Sia BSD che SVr4 che POSIX.1-2001\footnote{il + vecchio standard POSIX prevedeva invece solo la presenza del campo + \var{d\_fileno}, identico \var{d\_ino}, che in Linux era definito come alias + di quest'ultimo, mentre il campo \var{d\_name} era considerato dipendente + dall'implementazione.} prevedono che siano sempre presenti il campo +\var{d\_name}, che contiene il nome del file nella forma di una stringa +terminata da uno zero, ed il campo \var{d\_ino}, che contiene il numero di +\textit{inode} cui il file è associato e corrisponde al campo \var{st\_ino} di +\struct{stat}. La presenza di ulteriori campi opzionali oltre i due citati è +segnalata dalla definizione di altrettante macro nella forma +\code{\_DIRENT\_HAVE\_D\_XXX} dove \code{XXX} è il nome del relativo +campo. Come si può evincere da fig.~\ref{fig:file_dirent_struct} nel caso di +Linux sono pertanto definite le macro \macrod{\_DIRENT\_HAVE\_D\_TYPE}, +\macrod{\_DIRENT\_HAVE\_D\_OFF} e \macrod{\_DIRENT\_HAVE\_D\_RECLEN}, mentre non +è definita la macro \macrod{\_DIRENT\_HAVE\_D\_NAMLEN}. + +Dato che possono essere presenti campi opzionali e che lo standard +POSIX.1-2001 non specifica una dimensione definita per il nome dei file (che +può variare a seconda del filesystem), ma solo un limite superiore pari a +\const{NAME\_MAX} (vedi tab.~\ref{tab:sys_file_macro}), in generale per +allocare una struttura \struct{dirent} in maniera portabile occorre eseguire +un calcolo per ottenere le dimensioni appropriate per il proprio +sistema.\footnote{in SVr4 la lunghezza del campo è definita come + \code{NAME\_MAX+1} che di norma porta al valore di 256 byte usato anche in + fig.~\ref{fig:file_dirent_struct}.} Lo standard però richiede che il campo +\var{d\_name} sia sempre l'ultimo della struttura, questo ci consente di +ottenere la dimensione della prima parte con la macro di utilità generica +\macro{offsetof}, che si può usare con il seguente prototipo: + +{\centering +\vspace{3pt} +\begin{funcbox}{ +\fhead{stddef.h} +\fdecl{size\_t \macrod{offsetof}(type, member)} +\fdesc{Restituisce la posizione del campo \param{member} nella + struttura \param{type}.} +} +\end{funcbox} +} + +Ottenuta allora con \code{offsetof(struct dirent, d\_name)} la dimensione +della parte iniziale della struttura, basterà sommarci la dimensione massima +dei nomi dei file nel filesystem che si sta usando, che si può ottenere +attraverso la funzione \func{pathconf} (per la quale si rimanda a +sez.~\ref{sec:sys_file_limits}) più un ulteriore carattere per la terminazione +della stringa. + +Per quanto riguarda il significato dei campi opzionali, il campo \var{d\_type} +indica il tipo di file (se \textit{fifo}, directory, collegamento simbolico, +ecc.), e consente di evitare una successiva chiamata a \func{lstat} (vedi +sez.~\ref{sec:file_stat}) per determinarlo. I suoi possibili valori sono +riportati in tab.~\ref{tab:file_dtype_macro}. Si tenga presente che questo +valore è disponibile solo per i filesystem che ne supportano la restituzione +(fra questi i più noti sono \textsl{btrfs}, \textsl{ext2}, \textsl{ext3}, e +\textsl{ext4}), per gli altri si otterrà sempre il valore +\const{DT\_UNKNOWN}.\footnote{inoltre fino alla versione 2.1 della + \acr{glibc}, pur essendo il campo \var{d\_type} presente, il suo uso non era + implementato, e veniva restituito comunque il valore \const{DT\_UNKNOWN}.} + +\begin{table}[htb] + \centering + \footnotesize + \begin{tabular}[c]{|l|l|} + \hline + \textbf{Valore} & \textbf{Tipo di file} \\ + \hline + \hline + \constd{DT\_UNKNOWN} & Tipo sconosciuto.\\ + \constd{DT\_REG} & File normale.\\ + \constd{DT\_DIR} & Directory.\\ + \constd{DT\_LNK} & Collegamento simbolico.\\ + \constd{DT\_FIFO} & \textit{Fifo}.\\ + \constd{DT\_SOCK} & Socket.\\ + \constd{DT\_CHR} & Dispositivo a caratteri.\\ + \constd{DT\_BLK} & Dispositivo a blocchi.\\ + \hline + \end{tabular} + \caption{Costanti che indicano i vari tipi di file nel campo \var{d\_type} + della struttura \struct{dirent}.} + \label{tab:file_dtype_macro} +\end{table} + +Per la conversione da e verso l'analogo valore mantenuto dentro il campo +\var{st\_mode} di \struct{stat} (vedi fig.~\ref{fig:file_stat_struct}) sono +definite anche due macro di conversione, \macro{IFTODT} e \macro{DTTOIF}: + +{\centering +\vspace{3pt} +\begin{funcbox}{ +\fhead{dirent.h} +\fdecl{int \macrod{IFTODT}(mode\_t MODE)} +\fdesc{Converte il tipo di file dal formato di \var{st\_mode} a quello di + \var{d\_type}.} +\fdecl{mode\_t \macrod{DTTOIF}(int DTYPE)} +\fdesc{Converte il tipo di file dal formato di \var{d\_type} a quello di + \var{st\_mode}.} +} +\end{funcbox} +} + +Il campo \var{d\_off} contiene invece la posizione della voce successiva della +directory, mentre il campo \var{d\_reclen} la lunghezza totale della voce +letta. Con questi due campi diventa possibile, determinando la posizione delle +varie voci, spostarsi all'interno dello \textit{stream} usando la funzione +\funcd{seekdir},\footnote{sia questa funzione che \func{telldir}, sono + estensioni prese da BSD, ed introdotte nello standard POSIX solo a partire + dalla revisione POSIX.1-2001, per poterle utilizzare deve essere definita + una delle macro \macro{\_XOPEN\_SOURCE}, \macro{\_BSD\_SOURCE} o + \macro{\_SVID\_SOURCE}.} il cui prototipo è: + +\begin{funcproto}{ +\fhead{dirent.h} +\fdecl{void seekdir(DIR *dir, off\_t offset)} +\fdesc{Cambia la posizione all'interno di un \textit{directory stream}.} +} +{La funzione non ritorna niente e non imposta errori.} +\end{funcproto} + +La funzione non ritorna nulla e non segnala errori, è però necessario che il +valore dell'argomento \param{offset} sia valido per lo +\textit{stream} \param{dir}; esso pertanto deve essere stato ottenuto o dal +valore di \var{d\_off} di \struct{dirent} o dal valore restituito dalla +funzione \funcd{telldir}, che legge la posizione corrente; il cui prototipo +è:\footnote{prima della \acr{glibc} 2.1.1 la funzione restituiva un valore di + tipo \type{off\_t}, sostituito a partire dalla versione 2.1.2 da \ctyp{long} + per conformità a POSIX.1-2001.} + +\begin{funcproto}{ +\fhead{dirent.h} +\fdecl{long telldir(DIR *dir)} +\fdesc{Ritorna la posizione corrente in un \textit{directory stream}.} +} +{La funzione ritorna la posizione corrente nello \textit{stream} (un numero + positivo) in caso di successo e $-1$ per un errore, nel qual caso + \var{errno} assume solo il valore di \errval{EBADF}, corrispondente ad un + valore errato per \param{dir}. } +\end{funcproto} + +La sola funzione di posizionamento per un \textit{directory stream} prevista +originariamente dallo standard POSIX è \funcd{rewinddir}, che riporta la +posizione a quella iniziale; il suo prototipo è: + +\begin{funcproto}{ +\fhead{sys/types.h} +\fhead{dirent.h} +\fdecl{void rewinddir(DIR *dir)} +\fdesc{Si posiziona all'inizio di un \textit{directory stream}.} +} +{La funzione non ritorna niente e non imposta errori.} +\end{funcproto} + +Una volta completate le operazioni si può chiudere il \textit{directory + stream}, ed il file descriptor ad esso associato, con la funzione +\funcd{closedir}, il cui prototipo è: + +\begin{funcproto}{ +\fhead{sys/types.h} +\fhead{dirent.h} +\fdecl{int closedir(DIR *dir)} +\fdesc{Chiude un \textit{directory stream}.} +} +{La funzione ritorna $0$ in caso di successo e $-1$ per un errore, nel qual + caso \var{errno} assume solo il valore \errval{EBADF}.} +\end{funcproto} + +A parte queste funzioni di base in BSD 4.3 venne introdotta un'altra funzione +che permette di eseguire una scansione completa, con tanto di ricerca ed +ordinamento, del contenuto di una directory; la funzione è +\funcd{scandir}\footnote{in Linux questa funzione è stata introdotta fin dalle + \acr{libc4} e richiede siano definite le macro \macro{\_BSD\_SOURCE} o + \macro{\_SVID\_SOURCE}.} ed il suo prototipo è: + +\begin{funcproto}{ +\fhead{dirent.h} +\fdecl{int scandir(const char *dir, struct dirent ***namelist, \\ +\phantom{int scandir(}int(*filter)(const struct dirent *), \\ +\phantom{int scandir(}int(*compar)(const struct dirent **, const struct dirent **))} +\fdesc{Esegue una scansione di un \textit{directory stream}.} +} +{La funzione ritorna il numero di voci trovate in caso di successo e $-1$ per + un errore, nel qual caso \var{errno} può assumere solo il valore + \errval{ENOMEM}.} +\end{funcproto} + +Al solito, per la presenza fra gli argomenti di due puntatori a funzione, il +prototipo non è molto comprensibile; queste funzioni però sono quelle che +controllano rispettivamente la selezione di una voce, passata con +l'argomento \param{filter}, e l'ordinamento di tutte le voci selezionate, +specificata dell'argomento \param{compar}. + +La funzione legge tutte le voci della directory indicata dall'argomento +\param{dir}, passando un puntatore a ciascuna di esse (una struttura +\struct{dirent}) come argomento della funzione di selezione specificata da +\param{filter}; se questa ritorna un valore diverso da zero il puntatore viene +inserito in un vettore che viene allocato dinamicamente con \func{malloc}. +Qualora si specifichi un valore \val{NULL} per l'argomento \param{filter} non +viene fatta nessuna selezione e si ottengono tutte le voci presenti. + +Le voci selezionate possono essere riordinate tramite \funcm{qsort}, le +modalità del riordinamento possono essere personalizzate usando la funzione +\param{compar} come criterio di ordinamento di \funcm{qsort}, la funzione +prende come argomenti le due strutture \struct{dirent} da confrontare +restituendo un valore positivo, nullo o negativo per indicarne l'ordinamento; +alla fine l'indirizzo della lista ordinata dei puntatori alle strutture +\struct{dirent} viene restituito nell'argomento +\param{namelist}.\footnote{la funzione alloca automaticamente la lista, e + restituisce, come \textit{value result argument}, l'indirizzo della stessa; + questo significa che \param{namelist} deve essere dichiarato come + \code{struct dirent **namelist} ed alla funzione si deve passare il suo + indirizzo.} + +\itindend{directory~stream} + +Per l'ordinamento, vale a dire come valori possibili per l'argomento +\param{compar}, sono disponibili due funzioni predefinite, \funcd{alphasort} e +\funcd{versionsort}, i cui prototipi sono: + +\begin{funcproto}{ +\fhead{dirent.h} +\fdecl{int alphasort(const void *a, const void *b)} +\fdecl{int versionsort(const void *a, const void *b)} +\fdesc{Riordinano le voci di \textit{directory stream}.} +} +{Le funzioni restituiscono un valore minore, uguale o maggiore di zero qualora + il primo argomento sia rispettivamente minore, uguale o maggiore del secondo + e non forniscono errori.} +\end{funcproto} + +La funzione \func{alphasort} deriva da BSD ed è presente in Linux fin dalle +\acr{libc4}\footnote{la versione delle \acr{libc4} e \acr{libc5} usa però come + argomenti dei puntatori a delle strutture \struct{dirent}; la glibc usa il + prototipo originario di BSD, mostrato anche nella definizione, che prevede + puntatori a \ctyp{void}.} e deve essere specificata come argomento +\param{compar} per ottenere un ordinamento alfabetico secondo il valore del +campo \var{d\_name} delle varie voci. La \acr{glibc} prevede come +estensione\footnote{la \acr{glibc}, a partire dalla versione 2.1, effettua + anche l'ordinamento alfabetico tenendo conto delle varie localizzazioni, + usando \funcm{strcoll} al posto di \funcm{strcmp}.} anche +\func{versionsort}, che ordina i nomi tenendo conto del numero di versione, +cioè qualcosa per cui \texttt{file10} viene comunque dopo \texttt{file4}. + +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{\codesamplewidth} + \includecodesample{listati/my_ls.c} + \end{minipage} + \caption{Esempio di codice per eseguire la lista dei file contenuti in una + directory.} + \label{fig:file_my_ls} +\end{figure} + +Un semplice esempio dell'uso di queste funzioni è riportato in +fig.~\ref{fig:file_my_ls}, dove si è riportata la sezione principale di un +programma che, usando la funzione di scansione illustrata in +fig.~\ref{fig:file_dirscan}, stampa i nomi dei file contenuti in una directory +e la relativa dimensione, in sostanza una versione semplificata del comando +\cmd{ls}. + +Il programma è estremamente semplice; in fig.~\ref{fig:file_my_ls} si è omessa +la parte di gestione delle opzioni, che prevede solo l'uso di una funzione per +la stampa della sintassi, anch'essa omessa, ma il codice completo può essere +trovato coi sorgenti allegati alla guida nel file \file{myls.c}. + +In sostanza tutto quello che fa il programma, dopo aver controllato +(\texttt{\small 12-15}) di avere almeno un argomento, che indicherà la +directory da esaminare, è chiamare (\texttt{\small 16}) la funzione +\myfunc{dir\_scan} per eseguire la scansione, usando la funzione \code{do\_ls} +(\texttt{\small 22-29}) per fare tutto il lavoro. + +Quest'ultima si limita (\texttt{\small 26}) a chiamare \func{stat} sul file +indicato dalla directory entry passata come argomento (il cui nome è appunto +\var{direntry->d\_name}), memorizzando in una opportuna struttura \var{data} i +dati ad esso relativi, per poi provvedere (\texttt{\small 27}) a stampare il +nome del file e la dimensione riportata in \var{data}. + +Dato che la funzione verrà chiamata all'interno di \myfunc{dir\_scan} per ogni +voce presente, questo è sufficiente a stampare la lista completa dei file e +delle relative dimensioni. Si noti infine come si restituisca sempre 0 come +valore di ritorno per indicare una esecuzione senza errori. + +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{\codesamplewidth} + \includecodesample{listati/dir_scan.c} + \end{minipage} + \caption{Codice della funzione di scansione di una directory contenuta nel + file \file{dir\_scan.c}.} + \label{fig:file_dirscan} +\end{figure} + +Tutto il grosso del lavoro è svolto dalla funzione \myfunc{dir\_scan}, +riportata in fig.~\ref{fig:file_dirscan}. La funzione è volutamente generica e +permette di eseguire una funzione, passata come secondo argomento, su tutte le +voci di una directory. La funzione inizia con l'aprire (\texttt{\small + 18-22}) uno \textit{stream} sulla directory passata come primo argomento, +stampando un messaggio in caso di errore. + +Il passo successivo (\texttt{\small 23-24}) è cambiare directory di lavoro +(vedi sez.~\ref{sec:file_work_dir}), usando in sequenza le funzioni +\func{dirfd} e \func{fchdir} (in realtà si sarebbe potuto usare direttamente +\func{chdir} su \var{dirname}), in modo che durante il successivo ciclo +(\texttt{\small 26-30}) sulle singole voci dello \textit{stream} ci si trovi +all'interno della directory.\footnote{questo è essenziale al funzionamento + della funzione \code{do\_ls}, e ad ogni funzione che debba usare il campo + \var{d\_name}, in quanto i nomi dei file memorizzati all'interno di una + struttura \struct{dirent} sono sempre relativi alla directory in questione, + e senza questo posizionamento non si sarebbe potuto usare \func{stat} per + ottenere le dimensioni.} + +Avendo usato lo stratagemma di fare eseguire tutte le manipolazioni necessarie +alla funzione passata come secondo argomento, il ciclo di scansione della +directory è molto semplice; si legge una voce alla volta (\texttt{\small 26}) +all'interno di una istruzione di \code{while} e fintanto che si riceve una +voce valida, cioè un puntatore diverso da \val{NULL}, si esegue +(\texttt{\small 27}) la funzione di elaborazione \var{compare} (che nel nostro +caso sarà \code{do\_ls}), ritornando con un codice di errore (\texttt{\small + 28}) qualora questa presenti una anomalia, identificata da un codice di +ritorno negativo. Una volta terminato il ciclo la funzione si conclude con la +chiusura (\texttt{\small 31}) dello \textit{stream}\footnote{nel nostro caso, + uscendo subito dopo la chiamata, questo non servirebbe, in generale però + l'operazione è necessaria, dato che la funzione può essere invocata molte + volte all'interno dello stesso processo, per cui non chiudere i + \textit{directory stream} comporterebbe un consumo progressivo di risorse, + con conseguente rischio di esaurimento delle stesse.} e la restituzione +(\texttt{\small 32}) del codice di operazioni concluse con successo. + + + +\subsection{La directory di lavoro} +\label{sec:file_work_dir} + +\index{directory~di~lavoro|(} + +Come accennato in sez.~\ref{sec:proc_fork} a ciascun processo è associata una +directory nell'albero dei file,\footnote{questa viene mantenuta all'interno + dei dati della sua \kstruct{task\_struct} (vedi + fig.~\ref{fig:proc_task_struct}), più precisamente nel campo \texttt{pwd} + della sotto-struttura \kstruct{fs\_struct}.} che è chiamata +\textsl{directory corrente} o \textsl{directory di lavoro} (in inglese +\textit{current working directory}). La directory di lavoro è quella da cui +si parte quando un \textit{pathname} è espresso in forma relativa, dove il +``\textsl{relativa}'' fa riferimento appunto a questa directory. + +Quando un utente effettua il login, questa directory viene impostata alla +\textit{home directory} del suo account. Il comando \cmd{cd} della shell +consente di cambiarla a piacere, spostandosi da una directory ad un'altra, il +comando \cmd{pwd} la stampa sul terminale. Siccome la directory di lavoro +resta la stessa quando viene creato un processo figlio (vedi +sez.~\ref{sec:proc_fork}), la directory di lavoro della shell diventa anche la +directory di lavoro di qualunque comando da essa lanciato. + +Dato che è il kernel che tiene traccia dell'\textit{inode} della directory di +lavoro di ciascun processo, per ottenerne il \textit{pathname} occorre usare +una apposita funzione, \funcd{getcwd},\footnote{con Linux \func{getcwd} è una + \textit{system call} dalla versione 2.1.9, in precedenza il valore doveva + essere ottenuto tramite il filesystem \texttt{/proc} da + \procfile{/proc/self/cwd}.} il cui prototipo è: + +\begin{funcproto}{ +\fhead{unistd.h} +\fdecl{char *getcwd(char *buffer, size\_t size)} +\fdesc{Legge il \textit{pathname} della directory di lavoro corrente.} +} +{La funzione ritorna il puntatore a \param{buffer} in caso di successo e + \val{NULL} per un errore, nel qual caso \var{errno} assumerà uno dei valori: + \begin{errlist} + \item[\errcode{EACCES}] manca il permesso di lettura o di attraversamento su + uno dei componenti del \textit{pathname} (cioè su una delle directory + superiori alla corrente). + \item[\errcode{EINVAL}] l'argomento \param{size} è zero e \param{buffer} non + è nullo. + \item[\errcode{ENOENT}] la directory di lavoro è stata eliminata. + \item[\errcode{ERANGE}] l'argomento \param{size} è più piccolo della + lunghezza del \textit{pathname}. + \end{errlist} + ed inoltre \errcode{EFAULT} ed \errcode{ENOMEM} nel loro significato + generico.} +\end{funcproto} + +La funzione restituisce il \textit{pathname} completo della directory di +lavoro corrente nella stringa puntata da \param{buffer}, che deve essere +precedentemente allocata, per una dimensione massima di \param{size}. Il +buffer deve essere sufficientemente largo da poter contenere il +\textit{pathname} completo più lo zero di terminazione della stringa. Qualora +esso ecceda le dimensioni specificate con \param{size} la funzione restituisce +un errore. + +A partire dal kernel Linux 2.6.36 il nome può avere come prefisso la stringa +\texttt{(unreachable)} se la directory di lavoro resta fuori dalla directory +radice del processo dopo un \func{chroot} (torneremo su questi argomenti in +sez.~\ref{sec:file_chroot}); pertanto è sempre opportuno controllare il primo +carattere della stringa restituita dalla funzione per evitare di interpreare +mare un \textit{pathname} irraggiungibile. + +Come estensione allo standard POSIX.1, supportata da Linux e dalla +\acr{glibc}, si può anche specificare un puntatore nullo come \param{buffer} +nel qual caso la stringa sarà allocata automaticamente per una dimensione pari +a \param{size} qualora questa sia diversa da zero, o della lunghezza esatta +del \textit{pathname} altrimenti. In questo caso ci si deve ricordare di +disallocare la stringa con \func{free} una volta cessato il suo utilizzo. + +Un uso comune di \func{getcwd} è quello di salvarsi la directory di lavoro +all'avvio del programma per poi potervi tornare in un tempo successivo, un +metodo alternativo più veloce, se non si è a corto di file descriptor, è +invece quello di aprire all'inizio la directory corrente (vale a dire +``\texttt{.}'') e tornarvi in seguito con \func{fchdir}. + +Di questa funzione esiste una versione alternativa per compatibilità +all'indietro con BSD, \funcm{getwd}, che non prevede l'argomento \param{size} +e quindi non consente di specificare la dimensione di \param{buffer} che +dovrebbe essere allocato in precedenza ed avere una dimensione sufficiente +(per BSD maggiore \const{PATH\_MAX}, che di solito 256 byte, vedi +sez.~\ref{sec:sys_limits}). Il problema è che su Linux non esiste una +dimensione superiore per la lunghezza di un \textit{pathname}, per cui non è +detto che il buffer sia sufficiente a contenere il nome del file, e questa è +la ragione principale per cui questa funzione è deprecata, e non la tratteremo. + +Una seconda funzione usata per ottenere la directory di lavoro è +\funcm{get\_current\_dir\_name} (la funzione è una estensione GNU e presente +solo nella \acr{glibc}) che non prende nessun argomento ed è sostanzialmente +equivalente ad una \code{getcwd(NULL, 0)}, con la differenza che se +disponibile essa ritorna il valore della variabile di ambiente \envvar{PWD}, +che essendo costruita dalla shell può contenere un \textit{pathname} +comprendente anche dei collegamenti simbolici. Usando \func{getcwd} infatti, +essendo il \textit{pathname} ricavato risalendo all'indietro l'albero della +directory, si perderebbe traccia di ogni passaggio attraverso eventuali +collegamenti simbolici. + +Per cambiare la directory di lavoro si può usare la funzione di sistema +\funcd{chdir}, equivalente del comando di shell \cmd{cd}, il cui nome sta +appunto per \textit{change directory}, il suo prototipo è: + +\begin{funcproto}{ +\fhead{unistd.h} +\fdecl{int chdir(const char *pathname)} +\fdesc{Cambia la directory di lavoro per \textit{pathname}.} +} +{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{EACCES}] manca il permesso di ricerca su uno dei componenti + di \param{pathname}. + \item[\errcode{ENAMETOOLONG}] il nome indicato in \param{path} è troppo lungo. + \item[\errcode{ENOTDIR}] non si è specificata una directory. + \end{errlist} + ed inoltre \errval{EFAULT}, \errval{EIO}, \errval{ELOOP}, \errval{ENOENT} e + \errval{ENOMEM} nel loro significato generico.} +\end{funcproto} + +La funzione cambia la directory di lavoro in \param{pathname} ed +ovviamente \param{pathname} deve indicare una directory per la quale si hanno +i permessi di accesso. + +Dato che ci si può riferire ad una directory anche tramite un file descriptor, +per cambiare directory di lavoro è disponibile anche la funzione di sistema +\funcd{fchdir}, il cui prototipo è: + +\begin{funcproto}{ +\fhead{unistd.h} +\fdecl{int fchdir(int fd)} +\fdesc{Cambia la directory di lavoro per file descriptor.} +} +{La funzione ritorna $0$ in caso di successo e $-1$ per un errore, nel qual + caso \var{errno} assumerà i valori \errval{EBADF} o \errval{EACCES} nel loro + significato generico.} +\end{funcproto} + +La funzione è identica a \func{chdir}, ma prende come argomento un file +descriptor \param{fd} invece di un \textit{pathname}. Anche in questo +caso \param{fd} deve essere un file descriptor valido che fa riferimento ad +una directory. Inoltre l'unico errore di accesso possibile (tutti gli altri +sarebbero occorsi all'apertura di \param{fd}), è quello in cui il processo non +ha il permesso di attraversamento alla directory specificata da \param{fd}. + +\index{directory~di~lavoro|)} + + +\subsection{La creazione dei \textsl{file speciali}} +\label{sec:file_mknod} + +\index{file!di~dispositivo|(} +\index{file!speciali|(} + +Finora abbiamo parlato esclusivamente di file, directory e collegamenti +simbolici, ma in sez.~\ref{sec:file_file_types} abbiamo visto che il sistema +prevede anche degli altri tipi di file, che in genere vanno sotto il nome +generico di \textsl{file speciali}, come i file di dispositivo, le +\textit{fifo} ed i socket. + +La manipolazione delle caratteristiche di questi file speciali, il cambiamento +di nome o la loro cancellazione può essere effettuata con le stesse funzioni +che operano sugli altri file, ma quando li si devono creare sono necessarie, +come per le directory, delle funzioni apposite. La prima di queste è la +funzione di sistema \funcd{mknod}, il cui prototipo è: + +\begin{funcproto}{ +\fhead{sys/types.h} +\fhead{sys/stat.h} +\fhead{fcntl.h} +\fhead{unistd.h} +\fdecl{int mknod(const char *pathname, mode\_t mode, dev\_t dev)} +\fdesc{Crea un file speciale sul filesystem.} +} +{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{EEXIST}] \param{pathname} esiste già o è un collegamento + simbolico. + \item[\errcode{EINVAL}] il valore di \param{mode} non indica un file, una + \textit{fifo}, un socket o un dispositivo. + \item[\errcode{EPERM}] non si hanno privilegi sufficienti a creare + l'\texttt{inode}, o il filesystem su cui si è cercato di + creare \param{pathname} non supporta l'operazione. + \end{errlist} + ed inoltre \errval{EACCES}, \errval{EFAULT}, \errval{ELOOP}, + \errval{ENAMETOOLONG}, \errval{ENOENT}, \errval{ENOMEM}, \errval{ENOSPC}, + \errval{ENOTDIR} e \errval{EROFS} nel loro significato generico.} +\end{funcproto} + +La funzione permette di creare un \textit{inode} di tipo generico sul +filesystem, e viene in genere utilizzata per creare i file di dispositivo, ma +si può usare anche per creare qualunque tipo di file speciale ed anche file +regolari. L'argomento \param{mode} specifica sia il tipo di file che si vuole +creare che i relativi permessi, secondo i valori riportati in +tab.~\ref{tab:file_mode_flags}, che vanno combinati con un OR aritmetico. I +permessi sono comunque modificati nella maniera usuale dal valore di +\textit{umask} (si veda sez.~\ref{sec:file_perm_management}). + +Per il tipo di file può essere specificato solo uno fra i seguenti valori: +\const{S\_IFREG} per un file regolare (che sarà creato vuoto), +\const{S\_IFBLK} per un dispositivo a blocchi, \const{S\_IFCHR} per un +dispositivo a caratteri, \const{S\_IFSOCK} per un socket e \const{S\_IFIFO} +per una \textit{fifo};\footnote{con Linux la funzione non può essere usata per + creare directory o collegamenti simbolici, si dovranno usare le funzioni + \func{mkdir} e \func{symlink} a questo dedicate.} un valore diverso +comporterà l'errore \errcode{EINVAL}. Inoltre \param{pathname} non deve +esistere, neanche come collegamento simbolico. + +Qualora si sia specificato in \param{mode} un file di dispositivo (vale a dire +o \const{S\_IFBLK} o \const{S\_IFCHR}), il valore di \param{dev} dovrà essere +usato per indicare a quale dispositivo si fa riferimento, altrimenti il suo +valore verrà ignorato. Solo l'amministratore può creare un file di +dispositivo usando questa funzione (il processo deve avere la capacità +\const{CAP\_MKNOD}), ma in Linux\footnote{questo è un comportamento specifico + di Linux, la funzione non è prevista dallo standard POSIX.1 originale, + mentre è presente in SVr4 e 4.4BSD, ma esistono differenze nei comportamenti + e nei codici di errore, tanto che questa è stata introdotta in POSIX.1-2001 + con una nota che la definisce portabile solo quando viene usata per creare + delle \textit{fifo}, ma comunque deprecata essendo utilizzabile a tale scopo + la specifica \func{mkfifo}.} l'uso per la creazione di un file ordinario, di +una \textit{fifo} o di un socket è consentito anche agli utenti normali. + +Gli \textit{inode} creati con \func{mknod} apparterranno al proprietario e al +gruppo del processo (usando \ids{UID} e \ids{GID} del gruppo effettivo) che li +ha creati a meno non sia presente il bit \acr{sgid} per la directory o sia +stata attivata la semantica BSD per il filesystem (si veda +sez.~\ref{sec:file_ownership_management}) in cui si va a creare +l'\textit{inode}, nel qual caso per il gruppo verrà usato il \ids{GID} del +proprietario della directory. + +\itindbeg{major~number} +\itindbeg{minor~number} + +Nella creazione di un file di dispositivo occorre poi specificare +correttamente il valore di \param{dev}; questo infatti è di tipo +\type{dev\_t}, che è un tipo primitivo (vedi +tab.~\ref{tab:intro_primitive_types}) riservato per indicare un +\textsl{numero} di dispositivo. Il kernel infatti identifica ciascun +dispositivo con un valore numerico, originariamente questo era un intero a 16 +bit diviso in due parti di 8 bit chiamate rispettivamente \textit{major + number} e \textit{minor number}, che sono poi i due numeri mostrati dal +comando \texttt{ls -l} al posto della dimensione quando lo si esegue su un +file di dispositivo. + +Il \textit{major number} identifica una classe di dispositivi (ad esempio la +seriale, o i dischi IDE) e serve in sostanza per indicare al kernel quale è il +modulo che gestisce quella classe di dispositivi. Per identificare uno +specifico dispositivo di quella classe (ad esempio una singola porta seriale, +o uno dei dischi presenti) si usa invece il \textit{minor number}. L'elenco +aggiornato di questi numeri con le relative corrispondenze ai vari dispositivi +può essere trovato nel file \texttt{Documentation/devices.txt} allegato alla +documentazione dei sorgenti del kernel. + +Data la crescita nel numero di dispositivi supportati, ben presto il limite +massimo di 256 si è rivelato troppo basso, e nel passaggio dai kernel della +serie 2.4 alla serie 2.6 è stata aumentata a 32 bit la dimensione del tipo +\type{dev\_t}, con delle dimensioni passate a 12 bit per il \textit{major + number} e 20 bit per il \textit{minor number}. La transizione però ha +comportato il fatto che \type{dev\_t} è diventato un tipo opaco, e la +necessità di specificare il numero tramite delle opportune macro, così da non +avere problemi di compatibilità con eventuali ulteriori estensioni. + +Le macro sono definite nel file \headfiled{sys/sysmacros.h},\footnote{se si + usa la \acr{glibc} dalla versione 2.3.3 queste macro sono degli alias alle + versioni specifiche di questa libreria, \macrod{gnu\_dev\_major}, + \macrod{gnu\_dev\_minor} e \macrod{gnu\_dev\_makedev} che si possono usare + direttamente, al costo di una minore portabilità.} che viene automaticamente +incluso quando si include \headfile{sys/types.h}. Si possono pertanto ottenere +i valori del \textit{major number} e \textit{minor number} di un dispositivo +rispettivamente con le macro \macro{major} e \macro{minor}: + +{\centering +\vspace{3pt} +\begin{funcbox}{ +\fhead{sys/types.h} +\fdecl{int \macrod{major}(dev\_t dev)} +\fdesc{Restituisce il \textit{major number} del dispositivo \param{dev}.} +\fdecl{int \macrod{minor}(dev\_t dev)} +\fdesc{Restituisce il \textit{minor number} del dispositivo \param{dev}.} +} +\end{funcbox} +} + +\noindent mentre una volta che siano noti \textit{major number} e +\textit{minor number} si potrà costruire il relativo identificativo con la +macro \macro{makedev}: + +{\centering +\vspace{3pt} +\begin{funcbox}{ +\fhead{sys/types.h} +\fdecl{dev\_t \macrod{makedev}(int major, int minor)} +\fdesc{Dati \textit{major number} e \textit{minor number} restituisce + l'identificativo di un dispositivo.} +} +\end{funcbox} +} + + +\itindend{major~number} +\itindend{minor~number} +\index{file!di~dispositivo|)} + +Dato che la funzione di sistema \func{mknod} presenta diverse varianti nei +vari sistemi unix-like, lo standard POSIX.1-2001 la dichiara portabile solo in +caso di creazione delle \textit{fifo}, ma anche in questo caso alcune +combinazioni degli argomenti restano non specificate, per cui nello stesso +standard è stata introdotta una funzione specifica per creare una +\textit{fifo} deprecando l'uso di \func{mknod} a tale riguardo. La funzione è +\funcd{mkfifo} ed il suo prototipo è: + +\begin{funcproto}{ +\fhead{sys/types.h} +\fhead{sys/stat.h} +\fdecl{int mkfifo(const char *pathname, mode\_t mode)} +\fdesc{Crea una \textit{fifo}.} +} +{La funzione ritorna $0$ in caso di successo e $-1$ per un errore, nel qual + caso \var{errno} assumerà \errval{EACCES}, \errval{EEXIST}, + \errval{ENAMETOOLONG}, \errval{ENOENT}, \errval{ENOSPC}, \errval{ENOTDIR} e + \errval{EROFS} nel loro significato generico.} +\end{funcproto} + +La funzione crea la \textit{fifo} \param{pathname} con i +permessi \param{mode}. Come per \func{mknod} il file \param{pathname} non deve +esistere (neanche come collegamento simbolico); al solito i permessi +specificati da \param{mode} vengono modificati dal valore di \textit{umask} +(vedi sez.~\ref{sec:file_perm_management}). + +\index{file!speciali|)} + + +\subsection{I file temporanei} +\label{sec:file_temp_file} + +In molte occasioni è utile poter creare dei file temporanei; benché la cosa +sembri semplice, in realtà il problema è più sottile di quanto non appaia a +prima vista. Infatti anche se sembrerebbe banale generare un nome a caso e +creare il file dopo aver controllato che questo non esista, nel momento fra il +controllo e la creazione si ha giusto lo spazio per una possibile \textit{race + condition} (si ricordi quanto visto in sez.~\ref{sec:proc_race_cond}). + +\itindbeg{symlink~attack} + +Molti problemi di sicurezza derivano proprio da una creazione non accorta di +file temporanei che lascia aperta questa \textit{race condition}. Un +attaccante allora potrà sfruttarla con quello che viene chiamato +``\textit{symlink attack}'' dove nell'intervallo fra la generazione di un nome +e l'accesso allo stesso, viene creato un collegamento simbolico con quel nome +verso un file diverso, ottenendo, se il programma sotto attacco ne ha la +capacità, un accesso privilegiato.\footnote{dal kernel 3.6 sono state + introdotte delle contromisure, illustrate in + sez.~\ref{sec:procadv_security_misc}, che rendono impraticabili questo tipo + di attacchi, ma questa non è una buona scusa per ignorare il problema.} + +\itindend{symlink~attack} + +La \acr{glibc} provvede varie funzioni per generare nomi di file temporanei, +di cui si abbia certezza di unicità al momento della generazione; storicamente +la prima di queste funzioni create a questo scopo era +\funcd{tmpnam},\footnote{la funzione è stata deprecata nella revisione + POSIX.1-2008 dello standard POSIX.} il cui prototipo è: + +\begin{funcproto}{ +\fhead{stdio.h} +\fdecl{char *tmpnam(char *string)} +\fdesc{Genera un nome univoco per un file temporaneo.} +} +{La funzione ritorna il puntatore alla stringa con il nome in caso di successo + e \val{NULL} in caso di fallimento, non sono definiti errori.} +\end{funcproto} + +La funzione restituisce il puntatore ad una stringa contente un nome di file +valido e non esistente al momento dell'invocazione. Se si è passato come +argomento \param{string} un puntatore non nullo ad un buffer di caratteri +questo deve essere di dimensione \constd{L\_tmpnam} ed il nome generato vi +verrà copiato automaticamente, altrimenti il nome sarà generato in un buffer +statico interno che verrà sovrascritto ad una chiamata successiva. Successive +invocazioni della funzione continueranno a restituire nomi unici fino ad un +massimo di \constd{TMP\_MAX} volte, limite oltre il quale il comportamento è +indefinito. Al nome viene automaticamente aggiunto come prefisso la directory +specificata dalla costante \constd{P\_tmpdir}.\footnote{le costanti + \const{L\_tmpnam}, \const{P\_tmpdir} e \const{TMP\_MAX} sono definite in + \headfile{stdio.h}.} + +Di questa funzione esiste una versione rientrante, \funcm{tmpnam\_r}, che non +fa nulla quando si passa \val{NULL} come argomento. Una funzione simile, +\funcd{tempnam}, permette di specificare un prefisso per il file +esplicitamente, il suo prototipo è: + +\begin{funcproto}{ +\fhead{stdio.h} +\fdecl{char *tempnam(const char *dir, const char *pfx)} +\fdesc{Genera un nome univoco per un file temporaneo.} +} +{La funzione ritorna il puntatore alla stringa con il nome in caso di successo + e \val{NULL} per un errore, nel qual caso \var{errno} potrà assumere solo il + valore \errval{ENOMEM} qualora fallisca l'allocazione della stringa.} +\end{funcproto} + +La funzione alloca con \code{malloc} la stringa in cui restituisce il nome, +per cui è sempre rientrante, occorre però ricordarsi di disallocare con +\code{free} il puntatore che restituisce. L'argomento \param{pfx} specifica +un prefisso di massimo 5 caratteri per il nome provvisorio. La funzione +assegna come directory per il file temporaneo, verificando che esista e sia +accessibile, la prima valida fra le seguenti: +\begin{itemize*} +\item la variabile di ambiente \envvar{TMPDIR} (non ha effetto se non è + definita o se il programma chiamante è \acr{suid} o \acr{sgid}, vedi + sez.~\ref{sec:file_special_perm}), +\item il valore dell'argomento \param{dir} (se diverso da \val{NULL}), +\item il valore della costante \const{P\_tmpdir}, +\item la directory \file{/tmp}. +\end{itemize*} + +In ogni caso, anche se con queste funzioni la generazione del nome è casuale, +ed è molto difficile ottenere un nome duplicato, nulla assicura che un altro +processo non possa avere creato, fra l'ottenimento del nome e l'apertura del +file, un altro file o un collegamento simbolico con lo stesso nome. Per questo +motivo quando si usa il nome ottenuto da una di queste funzioni occorre sempre +assicurarsi che non si stia usando un collegamento simbolico e aprire il nuovo +file in modalità di esclusione (cioè con l'opzione \const{O\_EXCL} per i file +descriptor o con il flag ``\texttt{x}'' per gli \textit{stream}) che fa +fallire l'apertura in caso il file sia già esistente. Essendo disponibili +alternative migliori l'uso di queste funzioni è deprecato. + +Per evitare di dovere effettuare a mano tutti questi controlli, lo standard +POSIX definisce la funzione \funcd{tmpfile}, che permette di ottenere in +maniera sicura l'accesso ad un file temporaneo, il suo prototipo è: + +\begin{funcproto}{ +\fhead{stdio.h} +\fdecl{FILE *tmpfile(void)} +\fdesc{Apre un file temporaneo in lettura/scrittura.} +} +{La funzione ritorna il puntatore allo \textit{stream} associato al file + temporaneo in caso di successo e \val{NULL} per un errore, nel qual caso + \var{errno} assumerà uno dei valori: + \begin{errlist} + \item[\errcode{EEXIST}] non è stato possibile generare un nome univoco. + \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale. + \end{errlist} + ed inoltre \errval{EFAULT}, \errval{EMFILE}, \errval{ENFILE}, + \errval{ENOSPC}, \errval{EROFS} e \errval{EACCES} nel loro significato + generico.} +\end{funcproto} + + +La funzione restituisce direttamente uno \textit{stream} già aperto (in +modalità \code{w+b}, si veda sez.~\ref{sec:file_fopen}) e pronto per l'uso, +che viene automaticamente cancellato alla sua chiusura o all'uscita dal +programma. Lo standard non specifica in quale directory verrà aperto il file, +ma la \acr{glibc} prima tenta con \const{P\_tmpdir} e poi con +\file{/tmp}. Questa funzione è rientrante e non soffre di problemi di +\textit{race condition}. + +Alcune versioni meno recenti di Unix non supportano queste funzioni; in questo +caso si possono usare le vecchie funzioni \funcd{mktemp} e \func{mkstemp} che +modificano una stringa di input che serve da modello e che deve essere +conclusa da 6 caratteri ``\texttt{X}'' che verranno sostituiti da un codice +unico. La prima delle due è analoga a \func{tmpnam} e genera soltanto un nome +casuale, il suo prototipo è: + +\begin{funcproto}{ +\fhead{stlib.h} +\fdecl{char *mktemp(char *template)} +\fdesc{Genera un nome univoco per un file temporaneo.} +} +{La funzione ritorna il puntatore a \param{template} in caso di successo e + \val{NULL} per un errore, nel qual caso \var{errno} assumerà uno dei valori: + \begin{errlist} + \item[\errcode{EINVAL}] \param{template} non termina con \code{XXXXXX}. + \end{errlist}} +\end{funcproto} + +La funzione genera un nome univoco sostituendo le \code{XXXXXX} finali di +\param{template}; dato che \param{template} deve poter essere modificata dalla +funzione non si può usare una stringa costante. Tutte le avvertenze riguardo +alle possibili \textit{race condition} date per \func{tmpnam} continuano a +valere; inoltre in alcune vecchie implementazioni il valore usato per +sostituire le \code{XXXXXX} viene formato con il \ids{PID} del processo più +una lettera, il che mette a disposizione solo 26 possibilità diverse per il +nome del file, e rende il nome temporaneo facile da indovinare. Per tutti +questi motivi la funzione è deprecata e non dovrebbe mai essere usata. + +La seconda funzione, \funcd{mkstemp} è sostanzialmente equivalente a +\func{tmpfile}, ma restituisce un file descriptor invece di un nome; il suo +prototipo è: + +\begin{funcproto}{ +\fhead{stlib.h} +\fdecl{int mkstemp(char *template)} +\fdesc{Apre un file temporaneo.} +} + +{La funzione ritorna il file descriptor in caso di successo e $-1$ per un + errore, nel qual + caso \var{errno} assumerà uno dei valori: + \begin{errlist} + \item[\errcode{EEXIST}] non è riuscita a creare un file temporaneo, il + contenuto di \param{template} è indefinito. + \item[\errcode{EINVAL}] \param{template} non termina con \code{XXXXXX}. + \end{errlist}} +\end{funcproto} + +Come per \func{mktemp} anche in questo caso \param{template} non può essere +una stringa costante. La funzione apre un file in lettura/scrittura con la +funzione \func{open}, usando l'opzione \const{O\_EXCL} (si veda +sez.~\ref{sec:file_open_close}), in questo modo al ritorno della funzione si +ha la certezza di essere stati i creatori del file, i cui permessi (si veda +sez.~\ref{sec:file_perm_overview}) sono impostati al valore \code{0600} +(lettura e scrittura solo per il proprietario).\footnote{questo è vero a + partire dalla \acr{glibc} 2.0.7, le versioni precedenti della \acr{glibc} e + le vecchie \acr{libc5} e \acr{libc4} usavano il valore \code{0666} che + permetteva a chiunque di leggere e scrivere i contenuti del file.} Di +questa funzione esiste una variante \funcd{mkostemp}, introdotta +specificamente dalla \acr{glibc},\footnote{la funzione è stata introdotta + nella versione 2.7 delle librerie e richiede che sia definita la macro + \macro{\_GNU\_SOURCE}.} il cui prototipo è: + +\begin{funcproto}{ +\fhead{stlib.h} +\fdecl{int mkostemp(char *template, int flags)} +\fdesc{Apre un file temporaneo.} +} +{La funzione ritorna un file descriptor in caso di successo e $-1$ per un + errore, nel qual caso \var{errno} assumerà gli stessi valori di + \func{mkstemp}.} +\end{funcproto} +\noindent la cui sola differenza è la presenza dell'ulteriore argomento +\var{flags} che consente di specificare alcuni ulteriori flag (come +\const{O\_APPEND}, \const{O\_CLOEXEC}, \const{O\_SYNC}, il cui significato +vedremo in sez.~\ref{sec:file_open_close}) da passare ad \func{open} +nell'apertura del file.\footnote{si tenga presente che \func{mkostemp} + utilizza già \const{O\_CREAT}, \const{O\_EXCL} e \const{O\_RDWR}, che non è + il caso di reindicare, dato che ciò potrebbe portare ad errori in altri + sistemi operativi.} + +Di queste due funzioni sono state poi introdotte, a partire dalla \acr{glibc} +2.11 due varianti, \funcd{mkstemps} e \funcd{mkostemps}, che consentono di +indicare anche un suffisso, i loro prototipi sono: + +\begin{funcproto}{ +\fhead{stlib.h} +\fdecl{int mkstemps(char *template, int suffixlen)} +\fdesc{Apre un file temporaneo.} +\fdecl{int mkostemps(char *template, int suffixlen, int flags)} +\fdesc{Apre un file temporaneo.} +} + +{Le funzioni hanno gli stessi valori di ritorno e gli stessi errori di + \func{mkstemp} con lo stesso significato, tranne \errval{EINVAL} che viene + restituito se \param{template} non è di lunghezza pari ad almeno + $6+$\param{suffixlen} ed i 6 caratteri prima del suffisso non sono + \code{XXXXXX}.} +\end{funcproto} + +Le due funzioni, un'estensione non standard fornita dalla \acr{glibc}, sono +identiche a \funcd{mkstemp} e \funcd{mkostemp}, ma consentono di avere un nome +del file nella forma \texttt{prefissoXXXXXXsuffisso} dove la lunghezza del +suffisso deve essere indicata con \param{suffixlen}. + +Infine con OpenBSD è stata introdotta un'altra funzione simile alle +precedenti, \funcd{mkdtemp}, che crea invece una directory +temporanea;\footnote{la funzione è stata introdotta nella \acr{glibc} a + partire dalla versione 2.1.91 ed inserita nello standard POSIX.1-2008.} il +suo prototipo è: + +\begin{funcproto}{ +\fhead{stlib.h} +\fdecl{char *mkdtemp(char *template)} +\fdesc{Crea una directory temporanea.} +} +{La funzione ritorna il puntatore al nome della directory in caso di successo + e \val{NULL} per un errore, nel qual caso \var{errno} assumerà uno dei + valori: + \begin{errlist} + \item[\errcode{EINVAL}] \param{template} non termina con \code{XXXXXX}. + \end{errlist} + più gli altri eventuali codici di errore di \func{mkdir}.} +\end{funcproto} + +La funzione crea una directory temporanea il cui nome è ottenuto sostituendo +le \code{XXXXXX} finali di \param{template} con permessi \code{0700} (si veda +sez.~\ref{sec:file_perm_overview} per i dettagli). Dato che la creazione della +directory è sempre atomica i precedenti problemi di \textit{race condition} +non si pongono. + + +\section{La manipolazione delle caratteristiche dei file} +\label{sec:file_infos} + +Come spiegato in sez.~\ref{sec:file_filesystem} tutte le informazioni generali +relative alle caratteristiche di ciascun file, a partire dalle informazioni +relative al controllo di accesso, sono mantenute nell'\textit{inode}. Vedremo +in questa sezione come sia possibile leggere tutte queste informazioni usando +la funzione \func{stat}, che permette l'accesso a tutti i dati memorizzati +nell'\textit{inode}; esamineremo poi le varie funzioni usate per manipolare +tutte queste informazioni, eccetto quelle che riguardano la gestione del +controllo di accesso, trattate in sez.~\ref{sec:file_access_control}. + + +\subsection{La lettura delle caratteristiche dei file} +\label{sec:file_stat} + +La lettura delle informazioni relative ai file è fatta attraverso la famiglia +delle funzioni \func{stat} che sono quelle che usa il comando \cmd{ls} per +poter ottenere e mostrare tutti i dati relativi ad un file; ne fanno parte le +funzioni di sistema \funcd{stat}, \funcd{fstat} e \funcd{lstat}, i cui +prototipi sono: + +\begin{funcproto}{ +\fhead{sys/types.h} +\fhead{sys/stat.h} +\fhead{unistd.h} +\fdecl{int stat(const char *file\_name, struct stat *buf)} +\fdecl{int lstat(const char *file\_name, struct stat *buf)} +\fdecl{int fstat(int filedes, struct stat *buf)} +\fdesc{Leggono le informazioni di un file.} +} +{Le funzioni ritornano $0$ in caso di successo e $-1$ per un errore, nel qual + caso \var{errno} assumerà uno dei valori: + \begin{errlist} + \item[\errcode{EOVERFLOW}] il file ha una dimensione che non può essere + rappresentata nel tipo \type{off\_t} (può avvenire solo in caso di + programmi compilati su piattaforme a 32 bit senza le estensioni + (\texttt{-D \_FILE\_OFFSET\_BITS=64}) per file a 64 bit). + \end{errlist} + ed inoltre \errval{EFAULT} ed \errval{ENOMEM}, per \func{stat} e + \func{lstat} anche \errval{EACCES}, \errval{ELOOP}, \errval{ENAMETOOLONG}, + \errval{ENOENT}, \errval{ENOTDIR}, per \func{fstat} anche \errval{EBADF}, + nel loro significato generico.} +\end{funcproto} + +La funzione \func{stat} legge le informazioni del file indicato +da \param{file\_name} e le inserisce nel buffer puntato +dall'argomento \param{buf}; la funzione \func{lstat} è identica a \func{stat} +eccetto che se \param{file\_name} è un collegamento simbolico vengono lette le +informazioni relative ad esso e non al file a cui fa riferimento. Infine +\func{fstat} esegue la stessa operazione su un file già aperto, specificato +tramite il suo file descriptor \param{filedes}. + +La struttura \struct{stat} usata da queste funzioni è definita nell'header +\headfiled{sys/stat.h} e in generale dipende dall'implementazione; la versione +usata da Linux è mostrata in fig.~\ref{fig:file_stat_struct}, così come +riportata dalla pagina di manuale di \func{stat}. In realtà la definizione +effettivamente usata nel kernel dipende dall'architettura e ha altri campi +riservati per estensioni come tempi dei file più precisi (vedi +sez.~\ref{sec:file_file_times}). + +\begin{figure}[!htb] + \footnotesize + \centering + \begin{minipage}[c]{0.8\textwidth} + \includestruct{listati/stat.h} + \end{minipage} + \normalsize + \caption{La struttura \structd{stat} per la lettura delle informazioni dei + file.} + \label{fig:file_stat_struct} +\end{figure} + +Si noti come i vari membri della struttura siano specificati come tipi +primitivi del sistema, di quelli definiti in +tab.~\ref{tab:intro_primitive_types}, e dichiarati in \headfile{sys/types.h}, +con l'eccezione di \typed{blksize\_t} e \typed{blkcnt\_t} che sono nuovi tipi +introdotti per rendersi indipendenti dalla piattaforma. + +Benché la descrizione dei commenti di fig.~\ref{fig:file_stat_struct} sia +abbastanza chiara, vale la pena illustrare maggiormente il significato dei +campi di \struct{stat} su cui non torneremo in maggior dettaglio nel resto di +questa sezione: +\begin{itemize*} +\item Il campo \var{st\_nlink} contiene il numero di \textit{hard link} che + fanno riferimento al file (il cosiddetto \textit{link count}) di cui abbiamo + già parlato in numerose occasioni. +\item Il campo \var{st\_ino} contiene il numero di \textit{inode} del file, + quello viene usato all'interno del filesystem per identificarlo e che può + essere usato da un programma per determinare se due \textit{pathname} fanno + riferimento allo stesso file. +\item Il campo \var{st\_dev} contiene il numero del dispositivo su cui risiede + il file (o meglio il suo filesystem). Si tratta dello stesso numero che si + usa con \func{mknod} e che può essere decomposto in \textit{major number} e + \textit{minor number} con le macro \macro{major} e \macro{minor} viste in + sez.~\ref{sec:file_mknod}. +\item Il campo \var{st\_rdev} contiene il numero di dispositivo associato al + file stesso ed ovviamente ha un valore significativo soltanto quando il file + è un dispositivo a caratteri o a blocchi. +\item Il campo \var{st\_blksize} contiene la dimensione dei blocchi di dati + usati nell'I/O su disco, che è anche la dimensione usata per la + bufferizzazione dei dati dalle librerie del C per l'interfaccia degli + \textit{stream}. Leggere o scrivere blocchi di dati in dimensioni inferiori + a questo valore è inefficiente in quanto le operazioni su disco usano + comunque trasferimenti di questa dimensione. +\end{itemize*} + +Nell'evoluzione del kernel la \textit{system call} che fornisce \func{stat} è +stata modificata più volte per tener conto dei cambiamenti fatti alla +struttura \struct{stat},\footnote{questo ha significato l'utilizzo a basso + livello di diverse \textit{system call} e diverse versioni della struttura.} +in particolare a riguardo ai tempi dei file, di cui è stata aumentata la +precisione (torneremo su questo in sez.~\ref{sec:file_file_times}) ma anche +per gli aggiornamenti fatti ai campi \var{st\_ino}, \var{st\_uid} e +\var{st\_gid}. Sulle piattaforme a 32 bit questi cambiamenti, che han visto un +aumento delle dimensioni dei campi della struttura per adattarli alle nuove +esigenze, sono mascherati dalla \acr{glibc} che attraverso \func{stat} invoca +la versione più recente della \textit{system call} e reimpacchetta i dati se +questo è necessario per eseguire dei vecchi programmi. Nelle piattaforme a 64 +bit invece è presente un'unica versione della \textit{system call} e la +struttura \struct{stat} ha campi di dimensione sufficiente. + +Infine a partire dal kernel 2.6.16 è stata introdutta una ulteriore funzione +della famiglia, \func{fstatat} che consente di trattare con sicurezza i +\textit{pathname} relativi, la tratteremo in sez.~\ref{sec:file_openat}, +insieme alla nuova \textit{system call} \func{statx}, introdotta dal kernel +4.11 per estendere l'interfaccia di \func{stat} e le informazioni che essa può +restituire. + + +\subsection{I tipi di file} +\label{sec:file_types} + +Abbiamo sottolineato fin dall'introduzione che Linux, come ogni sistema +unix-like, supporta oltre ai file ordinari e alle directory una serie di altri +``\textsl{tipi}'' di file che possono stare su un filesystem (elencati in +tab.~\ref{tab:file_file_types}). Il tipo di file viene ritornato dalle +funzioni della famiglia \func{stat} all'interno del campo \var{st\_mode} di +una struttura \struct{stat}. + +\begin{table}[htb] + \centering + \footnotesize + \begin{tabular}[c]{|l|l|} + \hline + \textbf{Macro} & \textbf{Tipo del file} \\ + \hline + \hline + \macrod{S\_ISREG}\texttt{(m)} & File normale.\\ + \macrod{S\_ISDIR}\texttt{(m)} & Directory.\\ + \macrod{S\_ISCHR}\texttt{(m)} & Dispositivo a caratteri.\\ + \macrod{S\_ISBLK}\texttt{(m)} & Dispositivo a blocchi.\\ + \macrod{S\_ISFIFO}\texttt{(m)} & \textit{Fifo}.\\ + \macrod{S\_ISLNK}\texttt{(m)} & Collegamento simbolico.\\ + \macrod{S\_ISSOCK}\texttt{(m)} & Socket.\\ + \hline + \end{tabular} + \caption{Macro per i tipi di file (definite in \headfile{sys/stat.h}).} + \label{tab:file_type_macro} +\end{table} + +Il campo \var{st\_mode} è una maschera binaria in cui l'informazione viene +suddivisa nei vari bit che compongono, ed oltre a quelle sul tipo di file, +contiene anche le informazioni relative ai permessi su cui torneremo in +sez.~\ref{sec:file_perm_overview}. Dato che i valori numerici usati per +definire il tipo di file possono variare a seconda delle implementazioni, lo +standard POSIX definisce un insieme di macro che consentono di verificare il +tipo di file in maniera standardizzata. + +Queste macro vengono usate anche da Linux che supporta pure le estensioni allo +standard per i collegamenti simbolici e i socket definite da BSD.\footnote{le + ultime due macro di tab.~\ref{tab:file_type_macro}, che non sono presenti + nello standard POSIX fino alla revisione POSIX.1-1996.} L'elenco completo +delle macro con cui è possibile estrarre da \var{st\_mode} l'informazione +relativa al tipo di file è riportato in tab.~\ref{tab:file_type_macro}, tutte +le macro restituiscono un valore intero da usare come valore logico e prendono +come argomento il valore di \var{st\_mode}. + +\begin{table}[htb] + \centering + \footnotesize + \begin{tabular}[c]{|l|c|l|} + \hline + \textbf{Flag} & \textbf{Valore} & \textbf{Significato} \\ + \hline + \hline + \constd{S\_IFMT} & 0170000 & Maschera per i bit del tipo di file.\\ + \constd{S\_IFSOCK} & 0140000 & Socket.\\ + \constd{S\_IFLNK} & 0120000 & Collegamento simbolico.\\ + \constd{S\_IFREG} & 0100000 & File regolare.\\ + \constd{S\_IFBLK} & 0060000 & Dispositivo a blocchi.\\ + \constd{S\_IFDIR} & 0040000 & Directory.\\ + \constd{S\_IFCHR} & 0020000 & Dispositivo a caratteri.\\ + \constd{S\_IFIFO} & 0010000 & \textit{Fifo}.\\ + \hline + \constd{S\_ISUID} & 0004000 & Set user ID (\acr{suid}) bit, vedi + sez.~\ref{sec:file_special_perm}).\\ + \constd{S\_ISGID} & 0002000 & Set group ID (\acr{sgid}) bit, vedi + sez.~\ref{sec:file_special_perm}).\\ + \constd{S\_ISVTX} & 0001000 & \acr{Sticky} bit, vedi + sez.~\ref{sec:file_special_perm}).\\ + \hline + \constd{S\_IRWXU} & 00700 & Maschera per i permessi del proprietario.\\ + \constd{S\_IRUSR} & 00400 & Il proprietario ha permesso di lettura.\\ + \constd{S\_IWUSR} & 00200 & Il proprietario ha permesso di scrittura.\\ + \constd{S\_IXUSR} & 00100 & Il proprietario ha permesso di esecuzione.\\ + \hline + \constd{S\_IRWXG} & 00070 & Maschera per i permessi del gruppo.\\ + \constd{S\_IRGRP} & 00040 & Il gruppo ha permesso di lettura.\\ + \constd{S\_IWGRP} & 00020 & Il gruppo ha permesso di scrittura.\\ + \constd{S\_IXGRP} & 00010 & Il gruppo ha permesso di esecuzione.\\ + \hline + \constd{S\_IRWXO} & 00007 & Maschera per i permessi di tutti gli altri\\ + \constd{S\_IROTH} & 00004 & Gli altri hanno permesso di lettura.\\ + \constd{S\_IWOTH} & 00002 & Gli altri hanno permesso di esecuzione.\\ + \constd{S\_IXOTH} & 00001 & Gli altri hanno permesso di esecuzione.\\ + \hline + \end{tabular} + \caption{Costanti per l'identificazione dei vari bit che compongono il campo + \var{st\_mode} (definite in \headfile{sys/stat.h}).} + \label{tab:file_mode_flags} +\end{table} + +Oltre alle macro di tab.~\ref{tab:file_type_macro}, che semplificano +l'operazione, è possibile usare direttamente il valore di \var{st\_mode} per +ricavare il tipo di file controllando direttamente i vari bit in esso +memorizzati. Per questo sempre in \headfile{sys/stat.h} sono definite le varie +costanti numeriche riportate in tab.~\ref{tab:file_mode_flags}, che +definiscono le maschere che consentono di selezionare non solo i dati relativi +al tipo di file, ma anche le informazioni relative ai permessi su cui +torneremo in sez.~\ref{sec:file_access_control}, ed identificare i rispettivi +valori. + +Le costanti che servono per la identificazione del tipo di file sono riportate +nella prima sezione di tab.~\ref{tab:file_mode_flags}, mentre le sezioni +successive attengono alle costanti usate per i permessi. Il primo valore +dell'elenco è la maschera binaria \const{S\_IFMT} che permette di estrarre da +\var{st\_mode} (con un AND aritmetico) il blocco di bit nei quali viene +memorizzato il tipo di file. I valori successivi sono le costanti +corrispondenti ai vari tipi di file, e possono essere usate per verificare la +presenza del tipo di file voluto ed anche, con opportune combinazioni, +alternative fra più tipi di file. + +Si tenga presente però che a differenza dei permessi, l'informazione relativa +al tipo di file non è una maschera binaria, per questo motivo se si volesse +impostare una condizione che permetta di controllare se un file è una +directory o un file ordinario non si possono controllare dei singoli bit, ma +si dovrebbe usare una macro di preprocessore come: +\includecodesnip{listati/is_regdir.h} +in cui si estraggono ogni volta da \var{st\_mode} i bit relativi al tipo di +file e poi si effettua il confronto con i due possibili tipi di file. + + +\subsection{Le dimensioni dei file} +\label{sec:file_file_size} + +Abbiamo visto in fig.~\ref{fig:file_stat_struct} che campo \var{st\_size} di +una struttura \struct{stat} contiene la dimensione del file in byte. Questo +però è vero solo se si tratta di un file regolare, mentre nel caso di un +collegamento simbolico la dimensione è quella del \textit{pathname} che il +collegamento stesso contiene, infine per le \textit{fifo} ed i file di dispositivo +questo campo è sempre nullo. + +Il campo \var{st\_blocks} invece definisce la lunghezza del file in blocchi di +512 byte. La differenza con \var{st\_size} è che in questo caso si fa +riferimento alla quantità di spazio disco allocata per il file, e non alla +dimensione dello stesso che si otterrebbe leggendolo sequenzialmente. + +Si deve tener presente infatti che la lunghezza del file riportata in +\var{st\_size} non è detto che corrisponda all'occupazione dello spazio su +disco, e non solo perché la parte finale del file potrebbe riempire +parzialmente un blocco. In un sistema unix-like infatti è possibile +l'esistenza dei cosiddetti \textit{sparse file}, cioè file in cui sono +presenti dei ``\textsl{buchi}'' (\textit{holes} nella nomenclatura inglese) +che si formano tutte le volte che si va a scrivere su un file dopo aver +eseguito uno spostamento oltre la sua fine (tratteremo in dettaglio +l'argomento in sez.~\ref{sec:file_lseek}). + +In questo caso si avranno risultati differenti a seconda del modo in cui si +calcola la lunghezza del file, ad esempio il comando \cmd{du}, (che riporta il +numero di blocchi occupati) potrà dare una dimensione inferiore, mentre se si +legge dal file (ad esempio usando il comando \cmd{wc -c}), dato che in tal +caso per i ``\textsl{buchi}'' vengono restituiti degli zeri, si avrà lo stesso +risultato di \cmd{ls}. + +Se è sempre possibile allargare un file, scrivendoci sopra o usando la +funzione \func{lseek} (vedi sez.~\ref{sec:file_lseek}) per spostarsi oltre la +sua fine, esistono anche casi in cui si può avere bisogno di effettuare un +troncamento, scartando i dati presenti al di là della dimensione scelta come +nuova fine del file. + +Un file può sempre essere troncato a zero aprendolo con il flag +\const{O\_TRUNC}, ma questo è un caso particolare; per qualunque altra +dimensione si possono usare le due funzioni di sistema \funcd{truncate} e +\funcd{ftruncate}, i cui prototipi sono: + +\begin{funcproto}{ +\fhead{unistd.h} +\fdecl{int ftruncate(int fd, off\_t length))} +\fdecl{int truncate(const char *file\_name, off\_t length)} +\fdesc{Troncano un file.} +} +{Le funzioni ritornano $0$ in caso di successo e $-1$ per un errore, nel qual + caso \var{errno} assumerà uno dei valori: + \begin{errlist} + \item[\errcode{EINTR}] si è stati interrotti da un segnale. + \item[\errcode{EINVAL}] \param{length} è negativa o maggiore delle + dimensioni massime di un file. + \item[\errcode{EPERM}] il filesystem non supporta il troncamento di un file. + \item[\errcode{ETXTBSY}] il file è un programma in esecuzione. + \end{errlist} + per entrambe, mentre per \func{ftruncate} si avranno anche: + \begin{errlist} + \item[\errcode{EBADF}] \param{fd} non è un file descriptor. + \item[\errcode{EINVAL}] \param{fd} non è un riferimento a un file o non è + aperto in scrittura. + \end{errlist} + e per \func{truncate} si avranno anche: + \begin{errlist} + \item[\errcode{EACCES}] non si ha il permesso di scrittura sul file o il + permesso di attraversamento di una delle componenti del \textit{pathname}. + \item[\errcode{EISDIR}] \param{file\_name} fa riferimento ad una directory. + \end{errlist} + ed inoltre \errval{EFAULT}, \errval{EIO}, \errval{ELOOP}, + \errval{ENAMETOOLONG}, \errval{ENOENT}, \errval{ENOTDIR} e \errval{EROFS} + nel loro significato generico.} +\end{funcproto} + +Entrambe le funzioni fan sì che la dimensione del file sia troncata ad un +valore massimo specificato da \param{length}, e si distinguono solo per il +fatto che il file viene indicato con un \textit{pathname} per \func{truncate} +e con un file descriptor per \funcd{ftruncate}. Si tenga presente che se il +file è più lungo della lunghezza specificata i dati in eccesso saranno +perduti. + +Il comportamento in caso di lunghezza del file inferiore a \param{length} non +è specificato e dipende dall'implementazione: il file può essere lasciato +invariato o esteso fino alla lunghezza scelta. Nel caso di Linux viene esteso +con la creazione di un \textsl{buco} nel file e ad una lettura si otterranno +degli zeri, si tenga presente però che questo comportamento è supportato solo +per filesystem nativi, ad esempio su un filesystem non nativo come il VFAT di +Windows questo non è possibile. + + +\subsection{I tempi dei file} +\label{sec:file_file_times} + +Il sistema mantiene per ciascun file tre tempi, che sono registrati +nell'\textit{inode} insieme agli altri attributi del file. Questi possono +essere letti tramite la funzione \func{stat}, che li restituisce attraverso +tre campi della struttura \struct{stat} di fig.~\ref{fig:file_stat_struct}. Il +significato di questi tempi e dei relativi campi della struttura \struct{stat} +è illustrato nello schema di tab.~\ref{tab:file_file_times}, dove è anche +riportato un esempio delle funzioni che effettuano cambiamenti su di essi. Il +valore del tempo è espresso nel cosiddetto \textit{calendar time}, su cui +torneremo in dettaglio in sez.~\ref{sec:sys_time}. + +\begin{table}[htb] + \centering + \footnotesize + \begin{tabular}[c]{|c|l|l|c|} + \hline + \textbf{Membro} & \textbf{Significato} & \textbf{Funzione} + & \textbf{Opzione di \cmd{ls}} \\ + \hline + \hline + \var{st\_atime}& ultimo accesso ai dati del file & + \func{read}, \func{utime} & \cmd{-u}\\ + \var{st\_mtime}& ultima modifica ai dati del file & + \func{write}, \func{utime} & default\\ + \var{st\_ctime}& ultima modifica ai dati dell'\textit{inode} & + \func{chmod}, \func{utime} & \cmd{-c}\\ + \hline + \end{tabular} + \caption{I tre tempi associati a ciascun file.} + \label{tab:file_file_times} +\end{table} + +Il primo punto da tenere presente è la differenza fra il cosiddetto tempo di +ultima modifica (il \textit{modification time}) riportato in \var{st\_mtime}, +ed il tempo di ultimo cambiamento di stato (il \textit{change status time}) +riportato in \var{st\_ctime}. Il primo infatti fa riferimento ad una modifica +del contenuto di un file, mentre il secondo ad una modifica dei metadati +dell'\textit{inode}. Dato che esistono molte operazioni, come la funzione +\func{link} e altre che vedremo in seguito, che modificano solo le +informazioni contenute nell'\textit{inode} senza toccare il contenuto del +file, diventa necessario l'utilizzo di questo secondo tempo. + +Il tempo di ultima modifica viene usato ad esempio da programmi come +\cmd{make} per decidere quali file necessitano di essere ricompilati perché +più recenti dei loro sorgenti oppure dai programmi di backup, talvolta insieme +anche al tempo di cambiamento di stato, per decidere quali file devono essere +aggiornati nell'archiviazione. Il tempo di ultimo accesso viene di solito +usato per identificare i file che non vengono più utilizzati per un certo +lasso di tempo. Ad esempio un programma come \texttt{leafnode} lo usa per +cancellare gli articoli letti più vecchi, mentre \texttt{mutt} lo usa per +marcare i messaggi di posta che risultano letti. + +Il sistema non tiene mai conto dell'ultimo accesso all'\textit{inode}, +pertanto funzioni come \func{access} o \func{stat} non hanno alcuna influenza +sui tre tempi. Il comando \cmd{ls} (quando usato con le opzioni \cmd{-l} o +\cmd{-t}) mostra i tempi dei file secondo lo schema riportato nell'ultima +colonna di tab.~\ref{tab:file_file_times}. Si noti anche come non esista, a +differenza di altri sistemi operativi, un \textsl{tempo di creazione} di un +file. + +L'aggiornamento del tempo di ultimo accesso è stato a lungo considerato un +difetto progettuale di Unix, questo infatti comporta la necessità di +effettuare un accesso in scrittura sul disco anche in tutti i casi in cui +questa informazione non interessa e sarebbe possibile avere un semplice +accesso in lettura sui dati bufferizzati. Questo comporta un ovvio costo sia +in termini di prestazioni, che di consumo di risorse come la batteria per i +portatili, o i cicli di riscrittura per i dischi su memorie riscrivibili. + + +Per questo motivo abbiamo visto in sez.~\ref{sec:filesystem_mounting} come +nello sviluppo del kernel siano stati introdotti degli opportuni \textit{mount + flag} che consentissero di evitare di aggiornare continuamente una +informazione che nella maggior parte dei casi non interessa. Per questo i +valori che si possono trovare per l'\textit{access time} dipendono dalle +opzioni di montaggio, ed anche, essendo stato cambiato il comportamento di +default a partire dalla versione 2.6.30, dal kernel che si sta usando. + +In generale quello che si ha con i kernel più recenti è che il tempo di ultimo +accesso viene aggiornato solo se è precedente al tempo di ultima modifica o +cambiamento, o se è passato più di un giorno dall'ultimo accesso. Così si può +rendere evidente che vi è stato un accesso dopo una modifica e che il file +viene comunque osservato regolarmente, conservando tutte le informazioni +veramente utili senza dover consumare risorse in scritture continue per +mantenere costantemente aggiornata una informazione che a questo punto non ha +più nessuna rilevanza pratica.\footnote{qualora ce ne fosse la necessità è + comunque possibile, tramite l'opzione di montaggio \texttt{strictatime}, + richiedere in ogni caso il comportamento tradizionale.} + +\begin{table}[htb] + \centering + \footnotesize + \begin{tabular}[c]{|l|c|c|c|c|c|c|l|} + \hline + \multicolumn{1}{|p{2.3cm}|}{\centering{\vspace{6pt}\textbf{Funzione}}} & + \multicolumn{3}{|p{3.2cm}|}{\centering{ + \textbf{File o directory del riferimento}}}& + \multicolumn{3}{|p{3.2cm}|}{\centering{ + \textbf{Directory contenente il riferimento}}} + &\multicolumn{1}{|p{3.cm}|}{\centering{\vspace{6pt}\textbf{Note}}} \\ + \cline{2-7} + \cline{2-7} + \multicolumn{1}{|p{2.3cm}|}{} + &\multicolumn{1}{|p{.8cm}|}{\centering{\textsl{(a)}}} + &\multicolumn{1}{|p{.8cm}|}{\centering{\textsl{(m)}}} + &\multicolumn{1}{|p{.8cm}|}{\centering{\textsl{(c)}}} + &\multicolumn{1}{|p{.8cm}|}{\centering{\textsl{(a)}}} + &\multicolumn{1}{|p{.8cm}|}{\centering{\textsl{(m)}}} + &\multicolumn{1}{|p{.8cm}|}{\centering{\textsl{(c)}}} + &\multicolumn{1}{|p{3cm}|}{} \\ + \hline + \hline + \func{chmod}, \func{fchmod} + & -- & -- &$\bullet$& -- & -- & -- &\\ + \func{chown}, \func{fchown} + & -- & -- &$\bullet$& -- & -- & -- &\\ + \func{creat} + &$\bullet$&$\bullet$&$\bullet$& -- &$\bullet$&$\bullet$& + con \const{O\_CREATE} \\ + \func{creat} + & -- &$\bullet$&$\bullet$& -- &$\bullet$&$\bullet$& + con \const{O\_TRUNC} \\ + \func{exec} + &$\bullet$& -- & -- & -- & -- & -- &\\ + \func{lchown} + & -- & -- &$\bullet$& -- & -- & -- &\\ + \func{link} + & -- & -- &$\bullet$& -- &$\bullet$&$\bullet$&\\ + \func{mkdir} + &$\bullet$&$\bullet$&$\bullet$& -- &$\bullet$&$\bullet$&\\ + \func{mknod} + &$\bullet$&$\bullet$&$\bullet$& -- &$\bullet$&$\bullet$&\\ + \func{mkfifo} + &$\bullet$&$\bullet$&$\bullet$& -- &$\bullet$&$\bullet$&\\ + \func{open} + &$\bullet$&$\bullet$&$\bullet$& -- &$\bullet$&$\bullet$& + con \const{O\_CREATE} \\ + \func{open} + & -- &$\bullet$&$\bullet$& -- & -- & -- & + con \const{O\_TRUNC} \\ + \func{pipe} + &$\bullet$&$\bullet$&$\bullet$& -- & -- & -- &\\ + \func{read} + &$\bullet$& -- & -- & -- & -- & -- &\\ + \func{remove} + & -- & -- &$\bullet$& -- &$\bullet$&$\bullet$& + se esegue \func{unlink}\\ + \func{remove} + & -- & -- & -- & -- &$\bullet$&$\bullet$& + se esegue \func{rmdir}\\ + \func{rename} + & -- & -- &$\bullet$& -- &$\bullet$&$\bullet$& + per ambo gli argomenti\\ + \func{rmdir} + & -- & -- & -- & -- &$\bullet$&$\bullet$&\\ + \func{truncate} + & -- &$\bullet$&$\bullet$& -- & -- & -- &\\ + \func{ftruncate} + & -- &$\bullet$&$\bullet$& -- & -- & -- &\\ + \func{unlink} + & -- & -- &$\bullet$& -- &$\bullet$&$\bullet$&\\ + \func{utime} + &$\bullet$&$\bullet$&$\bullet$& -- & -- & -- &\\ + \func{utimes} + &$\bullet$&$\bullet$&$\bullet$& -- & -- & -- &\\ + \func{write} + & -- &$\bullet$&$\bullet$& -- & -- & -- &\\ + \hline + \end{tabular} + \caption{Prospetto dei cambiamenti effettuati sui tempi di ultimo + accesso \textsl{(a)}, ultima modifica \textsl{(m)} e ultimo cambiamento di + stato \textsl{(c)} dalle varie funzioni operanti su file e directory.} + \label{tab:file_times_effects} +\end{table} + + +L'effetto delle varie funzioni di manipolazione dei file sui relativi tempi è +illustrato in tab.~\ref{tab:file_times_effects}, facendo riferimento al +comportamento classico per quanto riguarda \var{st\_atime}. Si sono riportati +gli effetti sia per il file a cui si fa riferimento, sia per la directory che +lo contiene. Questi ultimi possono essere capiti immediatamente se si tiene +conto di quanto già detto e ripetuto a partire da +sez.~\ref{sec:file_filesystem}, e cioè che anche le directory sono anch'esse +file che contengono una lista di nomi, che il sistema tratta in maniera del +tutto analoga a tutti gli altri. + +Per questo motivo tutte le volte che compiremo un'operazione su un file che +comporta una modifica del nome contenuto nella directory, andremo anche a +scrivere sulla directory che lo contiene cambiandone il tempo di ultima +modifica. Un esempio di questo tipo di operazione può essere la cancellazione +di un file, invece leggere o scrivere o cambiare i permessi di un file ha +effetti solo sui tempi di quest'ultimo. + +Si ricordi infine come \var{st\_ctime} non è il tempo di creazione del file, +che in Unix non esiste, anche se può corrispondervi per file che non sono mai +stati modificati. Per questo motivo, a differenza di quanto avviene con altri +sistemi operativi, quando si copia un file, a meno di preservare +esplicitamente i tempi (ad esempio con l'opzione \cmd{-p} di \cmd{cp}) esso +avrà sempre il tempo corrente in cui si è effettuata la copia come data di +ultima modifica. + +I tempi di ultimo accesso ed ultima modifica possono essere modificati +esplicitamente usando la funzione di sistema \funcd{utime}, il cui prototipo +è: + +\begin{funcproto}{ +\fhead{utime.h} +\fdecl{int utime(const char *filename, struct utimbuf *times)} +\fdesc{Modifica i tempi di ultimo accesso ed ultima modifica di un file.} +} + +{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{EACCES}] non c'è il permesso di attraversamento per uno dei + componenti di \param{filename} o \param{times} è \val{NULL} e non si ha il + permesso di scrittura sul file, o non si è proprietari del file o non si + hanno i privilegi di amministratore. + \item[\errcode{EPERM}] \param{times} non è \val{NULL}, e non si è + proprietari del file o non si hanno i privilegi di amministratore. + \end{errlist} + ed inoltre \errval{ENOENT} e \errval{EROFS} nel loro significato generico.} +\end{funcproto} + +La funzione cambia i tempi di ultimo accesso e di ultima modifica del file +specificato dall'argomento \param{filename}, e richiede come secondo argomento +il puntatore ad una struttura \struct{utimbuf}, la cui definizione è riportata +in fig.~\ref{fig:struct_utimebuf}, con i nuovi valori di detti tempi +(rispettivamente nei campi \var{actime} e \var{modtime}). Se si passa un +puntatore nullo verrà impostato il tempo corrente. + +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{0.8\textwidth} + \includestruct{listati/utimbuf.h} + \end{minipage} + \normalsize + \caption{La struttura \structd{utimbuf}, usata da \func{utime} per modificare + i tempi dei file.} + \label{fig:struct_utimebuf} +\end{figure} + +L'effetto della funzione ed i privilegi necessari per eseguirla dipendono dal +valore dell'argomento \param{times}. Se è \val{NULL} la funzione imposta il +tempo corrente ed è sufficiente avere accesso in scrittura al file o essere +proprietari del file o avere i privilegi di amministratore. Se invece si è +specificato un valore diverso la funzione avrà successo solo se si è +proprietari del file o se si hanno i privilegi di amministratore.\footnote{per + essere precisi la capacità \const{CAP\_FOWNER}, vedi + sez.~\ref{sec:proc_capabilities}.} In entrambi i casi per verificare la +proprietà del file viene utilizzato l'\ids{UID} effettivo del processo. + +Si tenga presente che non è possibile modificare manualmente il tempo di +cambiamento di stato del file, che viene aggiornato direttamente dal kernel +tutte le volte che si modifica l'\textit{inode}, e quindi anche alla chiamata +di \func{utime}. Questo serve anche come misura di sicurezza per evitare che +si possa modificare un file nascondendo completamente le proprie tracce. In +realtà la cosa resta possibile se si è in grado di accedere al file di +dispositivo, scrivendo direttamente sul disco senza passare attraverso il +filesystem, ma ovviamente in questo modo la cosa è più complicata da +realizzare.\footnote{esistono comunque molti programmi che consentono di farlo + con relativa semplicità per cui non si dia per scontato che il valore sia + credibile in caso di macchina compromessa.} + +A partire dal kernel 2.6 la risoluzione dei tempi dei file, che nei campi di +tab.~\ref{tab:file_file_times} è espressa in secondi, è stata portata ai +nanosecondi per la gran parte dei filesystem. La ulteriore informazione può +essere acceduta attraverso altri campi appositamente aggiunti alla struttura +\struct{stat}. Se si sono definite le macro \macro{\_BSD\_SOURCE} o +\macro{\_SVID\_SOURCE} questi sono \var{st\_atim.tv\_nsec}, +\var{st\_mtim.tv\_nsec} e \var{st\_ctim.tv\_nsec} se queste non sono definite, +\var{st\_atimensec}, \var{st\_mtimensec} e \var{st\_mtimensec}. Qualora il +supporto per questa maggior precisione sia assente questi campi aggiuntivi +saranno nulli. + +Per la gestione di questi nuovi valori è stata definita una seconda funzione +di sistema, \funcd{utimes}, che consente di specificare tempi con maggior +precisione; il suo prototipo è: + +\begin{funcproto}{ +\fhead{sys/time.h} +\fdecl{int utimes(const char *filename, struct timeval times[2])} +\fdesc{Modifica i tempi di ultimo accesso e ultima modifica di un file.} +} +{La funzione ritorna $0$ in caso di successo e $-1$ per un errore, nel qual + caso \var{errno} assumerà gli stessi valori di \func{utime}.} +\end{funcproto} + +La funzione è del tutto analoga alla precedente \func{utime} ma usa come +secondo argomento un vettore di due strutture \struct{timeval}, la cui +definizione è riportata in fig.~\ref{fig:sys_timeval_struct}, che consentono +di indicare i tempi con una precisione del microsecondo. Il primo elemento +di \param{times} indica il valore per il tempo di ultimo accesso, il secondo +quello per il tempo di ultima modifica. Se si indica come secondo argomento un +puntatore nullo di nuovo verrà utilizzato il tempo corrente. + +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{0.8\textwidth} + \includestruct{listati/timeval.h} + \end{minipage} + \normalsize + \caption{La struttura \structd{timeval} usata per indicare valori di tempo + con la precisione del microsecondo.} + \label{fig:sys_timeval_struct} +\end{figure} + +Oltre ad \func{utimes} su Linux sono presenti altre due funzioni,\footnote{le + due funzioni non sono definite in nessuno standard, ma sono presenti, oltre + che su Linux, anche su BSD.} \funcd{futimes} e \funcd{lutimes}, che +consentono rispettivamente di effettuare la modifica utilizzando un file già +aperto o di eseguirla direttamente su un collegamento simbolico. I relativi +prototipi sono: + +\begin{funcproto}{ +\fhead{sys/time.h} +\fdecl{int futimes(int fd, const struct timeval tv[2])} +\fdesc{Cambia i tempi di un file già aperto.} +\fdecl{int lutimes(const char *filename, const struct timeval tv[2])} +\fdesc{Cambia i tempi di un collegamento simbolico.} +} + +{Le funzioni ritornano $0$ in caso di successo e $-1$ per un errore, nel qual + caso \var{errno} assumerà uno gli stessi valori di \func{utimes}, con in più + per \func{futimes}: + \begin{errlist} + \item[\errcode{EBADF}] \param{fd} non è un file descriptor. + \item[\errcode{ENOSYS}] il filesystem \texttt{/proc} non è accessibile. + \end{errlist}} +\end{funcproto} + +Le due funzioni hanno lo stesso comportamento di \texttt{utimes} e richiedono +gli stessi privilegi per poter operare, la differenza è che con \func{futimes} +si può indicare il file su cui operare se questo è già aperto facendo +riferimento al suo file descriptor, mentre con \func{lutimes} nel caso in +cui \param{filename} sia un collegamento simbolico saranno modificati i suoi +tempi invece di quelli del file a cui esso punta. + +Nonostante il kernel nelle versioni più recenti supporti, come accennato, +risoluzioni dei tempi dei file fino al nanosecondo, le funzioni fin qui +esaminate non consentono di impostare valori con questa precisione. Per questo +sono state introdotte due nuove funzioni di sistema, \funcd{futimens} e +\funcd{utimensat}, in grado di eseguire questo compito; i rispettivi prototipi +sono: + +\begin{funcproto}{ +\fhead{sys/time.h} +\fdecl{futimens(int fd, const struct timespec times[2])} +\fdesc{Cambia i tempi di un file già aperto.} +\fdecl{int utimensat(int dirfd, const char *pathname, const struct + timespec times[2], int flags)} +\fdesc{Cambia i tempi di un file.} +} + +{Le funzioni ritornano $0$ in caso di successo e $-1$ per un errore, nel qual + caso \var{errno} assumerà uno dei valori: + \begin{errlist} + \item[\errcode{EACCES}] si è richiesta l'impostazione del tempo corrente ma + non si ha il permesso di scrittura sul file, o non si è proprietari del + file o non si hanno i privilegi di amministratore; oppure il file è + immutabile (vedi sez.~\ref{sec:file_perm_overview}). + \item[\errcode{EBADF}] \param{fd} non è un file descriptor valido (solo + \func{futimens}), oppure \param{dirfd} non è \const{AT\_FDCWD} o un file + descriptor valido (solo \func{utimensat}). + \item[\errcode{EFAULT}] \param{times} non è un puntatore valido (per + entrambe), oppure \param{dirfd} è \const{AT\_FDCWD} ma \param{pathname} è + \var{NULL} o non è un puntatore valido (solo \func{utimensat}). + \item[\errcode{EINVAL}] si sono usati dei valori non corretti per i tempi + di \param{times} (per entrambe), oppure è si usato un valore non valido + per \param{flags}, oppure \param{pathname} è \var{NULL}, \param{dirfd} non + è \const{AT\_FDCWD} e \param{flags} contiene \const{AT\_SYMLINK\_NOFOLLOW} + (solo \func{utimensat}). + \item[\errcode{EPERM}] si è richiesto un cambiamento nei tempi non al tempo + corrente, ma non si è proprietari del file o non si hanno i privilegi di + amministratore; oppure il file è immutabile o \textit{append-only} (vedi + sez.~\ref{sec:file_perm_overview}). + \item[\errcode{ESRCH}] non c'è il permesso di attraversamento per una delle + componenti di \param{pathname} (solo \func{utimensat}) + \end{errlist} + ed inoltre per entrambe \errval{EROFS} e per \func{utimensat} + \errval{ELOOP}, \errval{ENAMETOOLONG}, \errval{ENOENT}, \errval{ENOTDIR} nel + loro significato generico.} +\end{funcproto} + +Entrambe le funzioni utilizzano per indicare i valori dei tempi un +vettore \param{times} di due strutture \struct{timespec}, la cui definizione è +riportata in fig.~\ref{fig:sys_timespec_struct}, che permette di specificare +un valore dei tempi con una precisione fino al nanosecondo. + +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{0.8\textwidth} + \includestruct{listati/timespec.h} + \end{minipage} + \normalsize + \caption{La struttura \structd{timespec} usata per indicare valori di tempo + con la precisione del nanosecondo.} + \label{fig:sys_timespec_struct} +\end{figure} + +Come per le precedenti funzioni il primo elemento di \param{times} indica il +tempo di ultimo accesso ed il secondo quello di ultima modifica, e se si usa +il valore \val{NULL} verrà impostato il tempo corrente sia per l'ultimo +accesso che per l'ultima modifica. Nei singoli elementi di \param{times} si +possono inoltre utilizzare due valori speciali per il campo \var{tv\_nsec}: +con \constd{UTIME\_NOW} si richiede l'uso del tempo corrente, mentre con +\constd{UTIME\_OMIT} si richiede di non impostare il tempo. Si può così +aggiornare in maniera specifica soltanto uno fra il tempo di ultimo accesso e +quello di ultima modifica. Quando si usa uno di questi valori speciali per +\var{tv\_nsec} il corrispondente valore di \var{tv\_sec} viene ignorato. + +Queste due funzioni sono una estensione definita nella revisione POSIX.1-2008 +dello standard POSIX, in Linux sono state introdotte a partire dal kernel +2.6.22,\footnote{si tenga presente però che per kernel precedenti il 2.6.26 le + due funzioni sono difettose nel rispetto di alcuni requisiti minori dello + standard e nel controllo della correttezza dei tempi, per i dettagli dei + quali si rimanda alla pagina di manuale.} e supportate dalla \acr{glibc} a +partire dalla versione 2.6.\footnote{in precedenza, a partire dal kernel + 2.6.16, era stata introdotta una \textit{system call} \funcm{futimesat} + seguendo una bozza della revisione dello standard poi modificata; questa + funzione, sostituita da \func{utimensat}, è stata dichiarata obsoleta, non è + supportata da nessuno standard e non deve essere più utilizzata: pertanto + non ne parleremo.} La prima è sostanzialmente una estensione di +\func{futimes} che consente di specificare i tempi con precisione maggiore, la +seconda supporta invece, rispetto ad \func{utimes}, una sintassi più complessa +che consente una indicazione sicura del file su cui operare specificando la +directory su cui si trova tramite il file descriptor \param{dirfd} ed il suo +nome come \textit{pathname relativo} in \param{pathname}.\footnote{su Linux + solo \func{utimensat} è una \textit{system call} e \func{futimens} è una + funzione di libreria, infatti se \param{pathname} è \var{NULL} \param{dirfd} + viene considerato un file descriptor ordinario e il cambiamento del tempo + applicato al file sottostante, qualunque esso sia, per cui + \code{futimens(fd, times}) è del tutto equivalente a \code{utimensat(fd, + NULL, times, 0)}.} + +Torneremo su questa sintassi e sulla sua motivazione in +sez.~\ref{sec:file_openat}, quando tratteremo tutte le altre funzioni (le +cosiddette \textit{at-functions}) che la utilizzano; essa prevede comunque +anche la presenza dell'argomento \param{flags} con cui attivare flag di +controllo che modificano il comportamento della funzione, nel caso specifico +l'unico valore consentito è \const{AT\_SYMLINK\_NOFOLLOW} che indica alla +funzione di non dereferenziare i collegamenti simbolici, cosa che le permette +di riprodurre le funzionalità di \func{lutimes}. + + + + +\section{Il controllo di accesso ai file} +\label{sec:file_access_control} + +Una delle caratteristiche fondamentali di tutti i sistemi unix-like è quella +del controllo di accesso ai file, che viene implementato per qualunque +filesystem standard.\footnote{per standard si intende che implementa le + caratteristiche previste dallo standard POSIX; in Linux sono utilizzabili + anche filesystem di altri sistemi operativi, che non supportano queste + caratteristiche.} In questa sezione ne esamineremo i concetti essenziali e +le funzioni usate per gestirne i vari aspetti. + + +\subsection{I permessi per l'accesso ai file} +\label{sec:file_perm_overview} + +Ad ogni file Linux associa sempre, oltre ad un insieme di permessi, l'utente +che ne è proprietario (il cosiddetto \textit{owner}) ed un gruppo di +appartenenza, indicati dagli identificatori di utente e gruppo (\ids{UID} e +\ids{GID}) di cui abbiamo già parlato in +sez.~\ref{sec:proc_access_id}.\footnote{questo è vero solo per filesystem di + tipo Unix, ad esempio non è vero per il filesystem VFAT di Windows, che non + fornisce nessun supporto per l'accesso multiutente, e per il quale queste + proprietà vengono assegnate in maniera fissa con opportune opzioni di + montaggio.} Anche questi sono mantenuti sull'\textit{inode} insieme alle +altre proprietà e sono accessibili da programma tramite la funzione +\func{stat} (trattata in sez.~\ref{sec:file_stat}), che restituisce l'utente +proprietario nel campo \var{st\_uid} ed il gruppo proprietario nel campo +\var{st\_gid} della omonima struttura \struct{stat}. + +Il controllo di accesso ai file segue un modello abbastanza semplice che +prevede tre permessi fondamentali strutturati su tre livelli di accesso. +Esistono varie estensioni a questo modello,\footnote{come le \textit{Access + Control List} che sono state aggiunte ai filesystem standard con opportune + estensioni (vedi sez.~\ref{sec:file_ACL}) per arrivare a meccanismi di + controllo ancora più sofisticati come il \textit{Mandatory Access Control} + di \textit{SELinux} e delle altre estensioni come \textit{Smack} o + \textit{AppArmor}.} ma nella maggior parte dei casi il meccanismo standard è +più che sufficiente a soddisfare tutte le necessità più comuni. I tre +permessi di base associati ad ogni file sono: +\begin{itemize*} +\item il permesso di lettura (indicato con la lettera \texttt{r}, dall'inglese + \textit{read}). +\item il permesso di scrittura (indicato con la lettera \texttt{w}, + dall'inglese \textit{write}). +\item il permesso di esecuzione (indicato con la lettera \texttt{x}, + dall'inglese \textit{execute}). +\end{itemize*} +mentre i tre livelli su cui sono divisi i privilegi sono: +\begin{itemize*} +\item i privilegi per l'utente proprietario del file. +\item i privilegi per un qualunque utente faccia parte del gruppo cui + appartiene il file. +\item i privilegi per tutti gli altri utenti. +\end{itemize*} + +L'insieme dei permessi viene espresso con un numero a 12 bit; di questi i nove +meno significativi sono usati a gruppi di tre per indicare i permessi base di +lettura, scrittura ed esecuzione e sono applicati rispettivamente +rispettivamente al proprietario, al gruppo, a tutti gli altri. + +\begin{figure}[htb] + \centering + \includegraphics[width=6cm]{img/fileperm} + \caption{Lo schema dei bit utilizzati per specificare i permessi di un file + contenuti nel campo \var{st\_mode} di \struct{stat}.} + \label{fig:file_perm_bit} +\end{figure} + +I restanti tre bit (noti come \textit{suid bit}, \textit{sgid bit}, e +\textit{sticky bit}) sono usati per indicare alcune caratteristiche più +complesse del meccanismo del controllo di accesso su cui torneremo in seguito +(in sez.~\ref{sec:file_special_perm}), lo schema di allocazione dei bit è +riportato in fig.~\ref{fig:file_perm_bit}. Come tutte le altre proprietà di +un file anche i permessi sono memorizzati nell'\textit{inode}, e come +accennato in sez.~\ref{sec:file_types} essi sono vengono restituiti in una +parte del campo \var{st\_mode} della struttura \struct{stat} (si veda di nuovo +fig.~\ref{fig:file_stat_struct}). + +In genere ci si riferisce ai tre livelli dei privilegi usando le lettere +\texttt{u} (per \textit{user}), \texttt{g} (per \textit{group}) e \texttt{o} +(per \textit{other}), inoltre se si vuole indicare tutti i raggruppamenti +insieme si usa la lettera \texttt{a} (per \textit{all}). Si tenga ben presente +questa distinzione dato che in certi casi, mutuando la terminologia in uso a +suo tempo nel VMS, si parla dei permessi base come di permessi per +\textit{owner}, \textit{group} ed \textit{all}, le cui iniziali possono dar +luogo a confusione. Le costanti che permettono di accedere al valore numerico +di questi bit nel campo \var{st\_mode}, già viste in +tab.~\ref{tab:file_mode_flags}, sono riportate per chiarezza una seconda volta +in tab.~\ref{tab:file_bit_perm}. + +\begin{table}[htb] + \centering + \footnotesize + \begin{tabular}[c]{|c|l|} + \hline + \textbf{\var{st\_mode}} bit & \textbf{Significato} \\ + \hline + \hline + \const{S\_IRUSR} & \textit{user-read}, l'utente può leggere.\\ + \const{S\_IWUSR} & \textit{user-write}, l'utente può scrivere.\\ + \const{S\_IXUSR} & \textit{user-execute}, l'utente può eseguire.\\ + \hline + \const{S\_IRGRP} & \textit{group-read}, il gruppo può leggere.\\ + \const{S\_IWGRP} & \textit{group-write}, il gruppo può scrivere.\\ + \const{S\_IXGRP} & \textit{group-execute}, il gruppo può eseguire.\\ + \hline + \const{S\_IROTH} & \textit{other-read}, tutti possono leggere.\\ + \const{S\_IWOTH} & \textit{other-write}, tutti possono scrivere.\\ + \const{S\_IXOTH} & \textit{other-execute}, tutti possono eseguire.\\ + \hline + \end{tabular} + \caption{I bit dei permessi di accesso ai file, come definiti in + \texttt{}} + \label{tab:file_bit_perm} +\end{table} + +I permessi vengono usati in maniera diversa dalle varie funzioni, e a seconda +che si riferiscano a dei file, dei collegamenti simbolici o delle directory; +qui ci limiteremo ad un riassunto delle regole generali, entrando nei dettagli +più avanti. + +La prima regola è che per poter accedere ad un file attraverso il suo +\textit{pathname} occorre il permesso di esecuzione in ciascuna delle +directory che compongono il \textit{pathname}; lo stesso vale per aprire un +file nella directory corrente (per la quale appunto serve il diritto di +esecuzione). Per una directory infatti il permesso di esecuzione significa che +essa può essere attraversata nella risoluzione del \textit{pathname}, e per +questo viene anche chiamato permesso di attraversamento. Esso è sempre +distinto dal permesso di lettura che invece implica che si può leggere il +contenuto della directory. + +Questo significa che se si ha il permesso di esecuzione senza permesso di +lettura si potrà lo stesso aprire un file all'interno di una directory (se si +hanno i permessi adeguati per il medesimo) ma non si potrà vederlo con +\cmd{ls} mancando il permesso di leggere il contenuto della directory. Per +crearlo o rinominarlo o cancellarlo invece occorrerà avere anche il permesso +di scrittura per la directory. + +Avere il permesso di lettura per un file consente di aprirlo con le opzioni +(si veda quanto riportato in sez.~\ref{sec:file_open_close}) di sola lettura o +di lettura/scrittura e leggerne il contenuto. Avere il permesso di scrittura +consente di aprire un file in sola scrittura o lettura/scrittura e modificarne +il contenuto, lo stesso permesso è necessario per poter troncare il file o per +aggiornare il suo tempo di ultima modifica al tempo corrente, ma non per +modificare arbitrariamente quest'ultimo, operazione per la quale, come per +buona parte delle modifiche effettuate sui metadati del file, occorre esserne +i proprietari. + +Non si può creare un file fintanto che non si disponga del permesso di +esecuzione e di quello di scrittura per la directory di destinazione. Gli +stessi permessi occorrono per cancellare un file da una directory (si ricordi +che questo non implica necessariamente la rimozione del contenuto del file dal +disco). Per la cancellazione non è necessario nessun tipo di permesso per il +file stesso dato che, come illustrato in sez.~\ref{sec:link_symlink_rename} +esso non viene toccato, nella cancellazione infatti viene solo modificato il +contenuto della directory, rimuovendo la voce che ad esso fa riferimento. Lo +stesso vale per poter rinominare o spostare il file in altra directory, in +entrambi i casi occorrerà il permesso di scrittura sulle directory che si +vanno a modificare. + +Per poter eseguire un file, che sia un programma compilato od uno script di +shell, od un altro tipo di file eseguibile riconosciuto dal kernel, occorre +oltre al permesso di lettura per accedere al contenuto avere anche il permesso +di esecuzione. Inoltre solo i file regolari possono essere eseguiti. Per i +file di dispositivo i permessi validi sono solo quelli di lettura e scrittura, +che corrispondono al poter eseguire dette operazioni sulla periferica +sottostante. + +I permessi per un collegamento simbolico sono ignorati, contano quelli del +file a cui fa riferimento; per questo in genere il comando \cmd{ls} riporta +per un collegamento simbolico tutti i permessi come concessi. Utente e gruppo +a cui esso appartiene vengono pure ignorati quando il collegamento viene +risolto, vengono controllati solo quando viene richiesta la rimozione del +collegamento e quest'ultimo è in una directory con lo \textit{sticky bit} +impostato (si veda sez.~\ref{sec:file_special_perm}). + +La procedura con cui il kernel stabilisce se un processo possiede un certo +permesso (di lettura, scrittura o esecuzione) si basa sul confronto fra +l'utente e il gruppo a cui il file appartiene (i valori di \var{st\_uid} e +\var{st\_gid} accennati in precedenza) e l'\ids{UID} effettivo, il \ids{GID} +effettivo e gli eventuali \ids{GID} supplementari del processo.\footnote{in + realtà Linux, per quanto riguarda l'accesso ai file, utilizza gli + identificatori del gruppo \textit{filesystem} (si ricordi quanto esposto in + sez.~\ref{sec:proc_perms}), ma essendo questi del tutto equivalenti ai primi, + eccetto il caso in cui si voglia scrivere un server NFS, ignoreremo questa + differenza.} + +Per una spiegazione dettagliata degli identificatori associati ai processi si +veda sez.~\ref{sec:proc_perms}; normalmente, a parte quanto vedremo in +sez.~\ref{sec:file_special_perm}, l'\ids{UID} effettivo e il \ids{GID} effettivo +corrispondono ai valori dell'\ids{UID} e del \ids{GID} dell'utente che ha +lanciato il processo, mentre i \ids{GID} supplementari sono quelli dei gruppi +cui l'utente appartiene. + +I passi attraverso i quali viene stabilito se il processo possiede il diritto +di accesso sono i seguenti: +\begin{enumerate*} +\item Se l'\ids{UID} effettivo del processo è zero (corrispondente + all'amministratore) l'accesso è sempre garantito senza nessun controllo. Per + questo motivo l'amministratore ha piena libertà di accesso a tutti i file. +\item Se l'\ids{UID} effettivo del processo è uguale all'\ids{UID} del + proprietario del file (nel qual caso si dice che il processo è proprietario + del file) allora: + \begin{itemize*} + \item se il relativo\footnote{per relativo si intende il bit di + \textit{user-read} se il processo vuole accedere in lettura, quello di + \textit{user-write} per l'accesso in scrittura, ecc.} bit dei permessi + d'accesso dell'utente è impostato, l'accesso è consentito; + \item altrimenti l'accesso è negato. + \end{itemize*} +\item Se il \ids{GID} effettivo del processo o uno dei \ids{GID} supplementari + del processo corrispondono al \ids{GID} del file allora: + \begin{itemize*} + \item se il bit dei permessi d'accesso del gruppo è impostato, l'accesso è + consentito; + \item altrimenti l'accesso è negato. + \end{itemize*} +\item Se il bit dei permessi d'accesso per tutti gli altri è impostato, + l'accesso è consentito, altrimenti l'accesso è negato. +\end{enumerate*} + +Si tenga presente che questi passi vengono eseguiti esattamente in +quest'ordine. Questo vuol dire che se un processo è il proprietario di un +file, l'accesso è consentito o negato solo sulla base dei permessi per +l'utente; i permessi per il gruppo non vengono neanche controllati. Lo stesso +vale se il processo appartiene ad un gruppo appropriato, in questo caso i +permessi per tutti gli altri non vengono controllati. + +Questo significa che se si è proprietari di un file ma non si ha il permesso +di scrittura, non vi si potrà scrivere anche se questo fosse scrivibile per +tutti gli altri. Permessi di questo tipo sono ovviamente poco ortodossi, e +comunque, come vedremo in sez.~\ref{sec:file_perm_management}, il proprietario +di un file può sempre modificarne i permessi, e riassegnarsi un eventuale +permesso di scrittura mancante. + +\itindbeg{file~attributes} + +A questi che sono i permessi ordinari si aggiungono, per i filesystem che +supportano questa estensione, due permessi speciali mantenuti nei cosiddetti +\textit{file attributes}, che si possono leggere ed impostare con i comandi +\cmd{lsattr} e \cmd{chattr}.\footnote{per l'utilizzo di questi comandi e per + le spiegazioni riguardo tutti gli altri \textit{file attributes} si rimanda + alla sezione 1.4.4 di \cite{AGL}.} + +Il primo è il cosiddetto attributo di immutabilità (\textit{immutable}, +identificato dalla lettera \texttt{i}) che impedisce ogni modifica al file, +\textit{inode} compreso. Questo significa non solo che non se ne può cambiare +il contenuto, ma neanche nessuna delle sue proprietà, ed in particolare non si +può modificare nei permessi o nei tempi o nel proprietario ed inoltre, visto +che non se può modificare il \textit{link count}, non si può neanche +cancellare, rinominare, o creare \textit{hard link} verso di esso. + +Il secondo è il cosiddetto attributo di \textit{append-only}, (identificato +dalla lettera \texttt{a}) che consente soltanto la scrittura in coda al +file. Il file cioè può essere soltanto esteso nel contenuto, ma i suoi +metadati, a parte i tempi che però possono essere impostati al valore +corrente, non possono essere modificati in alcun modo, quindi di nuovo non si +potrà cancellare, rinominare, o modificare nei permessi o nelle altre +proprietà. + +Entrambi questi attributi attivano queste restrizioni a livello di filesystem, +per cui a differenza dei permessi ordinari esse varranno per qualunque utente +compreso l'amministratore. L'amministratore è l'unico che può attivare o +disattivare questi attributi,\footnote{più precisamente un processo con la + capacità \const{CAP\_LINUX\_IMMUTABLE}, vedi + sez.~\ref{sec:proc_capabilities}.} e potendo rimuoverli è comunque capace di +tornare in grado di eseguire qualunque operazione su un file immutabile o +\textit{append-only}. + +\itindend{file~attributes} + + + +\subsection{I bit dei permessi speciali} +\label{sec:file_special_perm} + +\itindbeg{suid~bit} +\itindbeg{sgid~bit} + +Come si è accennato (in sez.~\ref{sec:file_perm_overview}) nei dodici bit del +campo \var{st\_mode} di \struct{stat} che vengono usati per il controllo di +accesso oltre ai bit dei permessi veri e propri, ci sono altri tre bit che +vengono usati per indicare alcune proprietà speciali dei file. Due di questi +sono i bit detti \acr{suid} (da \textit{set-user-ID bit}) e \acr{sgid} (da +\textit{set-group-ID bit}) che sono identificati dalle costanti +\const{S\_ISUID} e \const{S\_ISGID}. + +Come spiegato in dettaglio in sez.~\ref{sec:proc_exec}, quando si lancia un +programma il comportamento normale del kernel è quello di impostare gli +identificatori del gruppo \textit{effective} del nuovo processo al valore dei +corrispondenti del gruppo \textit{real} del processo corrente, che normalmente +corrispondono a quelli dell'utente con cui si è entrati nel sistema. + +Se però il file del programma, che ovviamente deve essere +eseguibile,\footnote{anzi più precisamente un binario eseguibile: per motivi + di sicurezza il kernel ignora i bit \acr{suid} e \acr{sgid} per gli script + eseguibili.} ha il bit \acr{suid} impostato, il kernel assegnerà come +\ids{UID} effettivo al nuovo processo l'\ids{UID} del proprietario del file al +posto dell'\ids{UID} del processo originario. Avere il bit \acr{sgid} +impostato ha lo stesso effetto sul \ids{GID} effettivo del processo. É +comunque possibile riconoscere questa situazione perché il cambiamento viene +effettuato solo sugli identificativi del gruppo \textit{effective}, mentre +quelli dei gruppi \textit{real} e \textit{saved} restano quelli dell'utente +che ha eseguito il programma. + +I bit \acr{suid} e \acr{sgid} vengono usati per permettere agli utenti normali +di usare programmi che richiedono privilegi speciali. L'esempio classico è il +comando \cmd{passwd} che ha la necessità di modificare il file delle password, +quest'ultimo ovviamente può essere scritto solo dall'amministratore, ma non è +necessario chiamare l'amministratore per cambiare la propria password. Infatti +il comando \cmd{passwd} appartiene in genere all'utente \textit{root} ma ha il +bit \acr{suid} impostato, per cui quando viene lanciato da un utente normale +ottiene comunque i privilegi di amministratore. + +Chiaramente avere un processo che ha privilegi superiori a quelli che avrebbe +normalmente l'utente che lo ha lanciato comporta vari rischi, e questo tipo di +programmi devono essere scritti accuratamente per evitare che possano essere +usati per guadagnare privilegi non consentiti (l'argomento è affrontato in +dettaglio in sez.~\ref{sec:proc_perms}). + +La presenza dei bit \acr{suid} e \acr{sgid} su un file può essere rilevata con +il comando \cmd{ls -l}, che visualizza una lettera ``\cmd{s}'' al posto della +``\cmd{x}'' in corrispondenza dei permessi di utente o gruppo. La stessa +lettera ``\cmd{s}'' può essere usata nel comando \cmd{chmod} per impostare +questi bit. Infine questi bit possono essere controllati all'interno di +\var{st\_mode} con l'uso delle due costanti \const{S\_ISUID} e +\const{S\_IGID}, i cui valori sono riportati in +tab.~\ref{tab:file_mode_flags}. + +Gli stessi bit vengono ad assumere un significato completamente diverso per le +directory, normalmente infatti Linux usa la convenzione di SVr4 per indicare +con questi bit l'uso della semantica BSD nella creazione di nuovi file (si +veda sez.~\ref{sec:file_ownership_management} per una spiegazione dettagliata +al proposito). + +Infine Linux utilizza il bit \acr{sgid} per un'ulteriore estensione mutuata da +SVr4. Il caso in cui un file ha il bit \acr{sgid} impostato senza che lo sia +anche il corrispondente bit di esecuzione viene utilizzato per attivare per +quel file il \textit{mandatory locking} (affronteremo questo argomento in +dettaglio più avanti, in sez.~\ref{sec:file_mand_locking}). + +\itindend{suid~bit} +\itindend{sgid~bit} + +\itindbeg{sticky~bit} + +L'ultimo dei bit rimanenti, identificato dalla costante \const{S\_ISVTX}, è in +parte un rimasuglio delle origini dei sistemi Unix. A quell'epoca infatti la +memoria virtuale e l'accesso ai file erano molto meno sofisticati e per +ottenere la massima velocità possibile per i programmi usati più comunemente +si poteva impostare questo bit. + +L'effetto di questo bit era che il segmento di testo del programma (si veda +sez.~\ref{sec:proc_mem_layout} per i dettagli) veniva scritto nella swap la +prima volta che questo veniva lanciato, e vi permaneva fino al riavvio della +macchina (da questo il nome di \textsl{sticky bit}); essendo la swap un file +continuo o una partizione indicizzata direttamente si poteva risparmiare in +tempo di caricamento rispetto alla ricerca attraverso la struttura del +filesystem. Lo \textsl{sticky bit} è indicato usando la lettera ``\texttt{t}'' +al posto della ``\texttt{x}'' nei permessi per gli altri. + +Ovviamente per evitare che gli utenti potessero intasare la swap solo +l'amministratore era in grado di impostare questo bit, che venne chiamato +anche con il nome di \textit{saved text bit}, da cui deriva quello della +costante. Le attuali implementazioni di memoria virtuale e filesystem rendono +sostanzialmente inutile questo procedimento. + +Benché ormai non venga più utilizzato per i file, lo \textit{sticky bit} ha +invece assunto un uso importante per le directory;\footnote{lo \textit{sticky + bit} per le directory è un'estensione non definita nello standard POSIX, + Linux però la supporta, così come BSD e SVr4.} in questo caso se tale bit è +impostato un file potrà essere rimosso dalla directory soltanto se l'utente ha +il permesso di scrittura su di essa ed inoltre è vera una delle seguenti +condizioni: +\begin{itemize*} +\item l'utente è proprietario del file, +\item l'utente è proprietario della directory, +\item l'utente è l'amministratore. +\end{itemize*} + +Un classico esempio di directory che ha questo bit impostato è \file{/tmp}, i +cui permessi infatti di solito sono i seguenti: +\begin{Console} +piccardi@hain:~/gapil$ \textbf{ls -ld /tmp} +drwxrwxrwt 6 root root 1024 Aug 10 01:03 /tmp +\end{Console} +%$ +quindi con lo \textit{sticky bit} bit impostato. In questo modo qualunque +utente nel sistema può creare dei file in questa directory, che come +suggerisce il nome è normalmente utilizzata per la creazione di file +temporanei, ma solo l'utente che ha creato un certo file potrà cancellarlo o +rinominarlo. In questo modo si evita che un utente possa, più o meno +consapevolmente, cancellare i file temporanei creati degli altri utenti. + +\itindend{sticky~bit} + + + +\subsection{Le funzioni per la gestione dei permessi dei file} +\label{sec:file_perm_management} + +Come visto in sez.~\ref{sec:file_access_control} il controllo di accesso ad un +file viene fatto utilizzando l'\ids{UID} ed il \ids{GID} effettivo del processo; +ci sono casi però in cui si può voler effettuare il controllo con l'\ids{UID} +reale ed il \ids{GID} reale, vale a dire usando i valori di \ids{UID} e +\ids{GID} relativi all'utente che ha lanciato il programma, e che, come +accennato in sez.~\ref{sec:file_special_perm} e spiegato in dettaglio in +sez.~\ref{sec:proc_perms}, non è detto siano uguali a quelli effettivi. + +Per far questo si può usare la funzione di sistema \funcd{access}, il cui +prototipo è: + +\begin{funcproto}{ +\fhead{unistd.h} +\fdecl{int access(const char *pathname, int mode)} +\fdesc{Verifica i permessi di accesso.} +} + +{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{EACCES}] l'accesso al file non è consentito, o non si ha il + permesso di attraversare una delle directory di \param{pathname}. + \item[\errcode{EINVAL}] il valore di \param{mode} non è valido. + \item[\errcode{EROFS}] si è richiesto l'accesso in scrittura per un file su + un filesystem montato in sola lettura. + \item[\errcode{ETXTBSY}] si è richiesto l'accesso in scrittura per un + eseguibile binario correntemente in esecuzione. + \end{errlist} + ed inoltre \errval{EFAULT}, \errval{EIO}, \errval{ELOOP}, + \errval{ENAMETOOLONG}, \errval{ENOENT}, \errval{ENOTDIR} nel loro + significato generico.} +\end{funcproto} + +La funzione verifica i permessi di accesso, indicati da \param{mode}, per il +file indicato da \param{pathname}. I valori possibili per l'argomento +\param{mode} sono esprimibili come combinazione delle costanti numeriche +riportate in tab.~\ref{tab:file_access_mode_val} (attraverso un OR binario +delle stesse). I primi tre valori implicano anche la verifica dell'esistenza +del file, se si vuole verificare solo quest'ultima si può usare \const{F\_OK}, +o anche direttamente \func{stat}. Nel caso in cui \param{pathname} si +riferisca ad un collegamento simbolico, questo viene seguito ed il controllo è +fatto sul file a cui esso fa riferimento. + +La funzione controlla solo i bit dei permessi di accesso per \param{pathname}, +ma occorre poter risolvere quest'ultimo, e se non c'è il permesso di +esecuzione per una qualunque delle sue componenti la funzione fallirà +indipendentemente dai permessi del file. Si tenga presente poi che il fatto +che una directory abbia permesso di scrittura non significa che vi si possa +scrivere come fosse un file, e che se un file ha il permesso di esecuzione non +è detto che sia eseguibile. La funzione ha successo solo se tutti i permessi +controllati sono disponibili. + +\begin{table}[htb] + \centering + \footnotesize + \begin{tabular}{|c|l|} + \hline + \textbf{\param{mode}} & \textbf{Significato} \\ + \hline + \hline + \constd{R\_OK} & Verifica il permesso di lettura. \\ + \constd{W\_OK} & Verifica il permesso di scrittura. \\ + \constd{X\_OK} & Verifica il permesso di esecuzione. \\ + \constd{F\_OK} & Verifica l'esistenza del file. \\ + \hline + \end{tabular} + \caption{Valori possibili per l'argomento \param{mode} della funzione + \func{access}.} + \label{tab:file_access_mode_val} +\end{table} + +Un esempio tipico per l'uso di questa funzione è quello di un processo che sta +eseguendo un programma coi privilegi di un altro utente (ad esempio attraverso +l'uso del \textit{suid bit}) che vuole controllare se l'utente originale ha i +permessi per accedere ad un certo file, ma eseguire questo controllo prima di +aprire il file espone al rischio di una \textit{race condition} che apre ad un +possibile \textit{symlink attack} fra il controllo e l'apertura del file. In +questo caso è sempre opportuno usare invece la funzione \func{faccessat} che +tratteremo insieme alle altre \textit{at-functions} in +sez.~\ref{sec:file_openat}. + +Del tutto analoghe a \func{access} sono le due funzioni \funcm{euidaccess} e +\funcm{eaccess} che ripetono lo stesso controllo usando però gli +identificatori del gruppo effettivo, verificando quindi le effettive capacità +di accesso ad un file. Le funzioni hanno entrambe lo stesso +prototipo\footnote{in realtà \funcm{eaccess} è solo un sinonimo di + \funcm{euidaccess} fornita per compatibilità con l'uso di questo nome in + altri sistemi.} che è del tutto identico a quello di \func{access}. Prendono +anche gli stessi valori e restituiscono gli stessi risultati e gli stessi +codici di errore. + +Per cambiare i permessi di un file il sistema mette ad disposizione due +funzioni \funcd{chmod} e \funcd{fchmod}, che operano rispettivamente su un +filename e su un file descriptor, i loro prototipi sono: + +\begin{funcproto}{ +\fhead{sys/types.h} +\fhead{sys/stat.h} +\fdecl{int chmod(const char *path, mode\_t mode)} +\fdesc{Cambia i permessi del file indicato da \param{path} al valore indicato + da \param{mode}.} +\fdecl{int fchmod(int fd, mode\_t mode)} +\fdesc{Analoga alla precedente, ma usa il file descriptor \param{fd} per + indicare il file.} + +} + +{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{EPERM}] l'\ids{UID} effettivo non corrisponde a quello del + proprietario del file o non si hanno i privilegi di amministratore. + \item[\errcode{EROFS}] il file è su un filesystem in sola lettura. + \end{errlist} + ed inoltre per entrambe \errval{EIO}, per \func{chmod} \errval{EACCES}, + \errval{EFAULT}, \errval{ELOOP}, \errval{ENAMETOOLONG}, \errval{ENOENT}, + \errval{ENOMEM}, \errval{ENOTDIR}, per \func{fchmod} \errval{EBADF} nel loro + significato generico.} +\end{funcproto} + + +Entrambe le funzioni utilizzano come secondo argomento \param{mode}, una +variabile dell'apposito tipo primitivo \type{mode\_t} (vedi +tab.~\ref{tab:intro_primitive_types}) utilizzato per specificare i permessi +sui file. + +\begin{table}[!htb] + \centering + \footnotesize + \begin{tabular}[c]{|c|c|l|} + \hline + \textbf{\param{mode}} & \textbf{Valore} & \textbf{Significato} \\ + \hline + \hline + \const{S\_ISUID} & 04000 & Set user ID bit.\\ + \const{S\_ISGID} & 02000 & Set group ID bit.\\ + \const{S\_ISVTX} & 01000 & Sticky bit.\\ + \hline + \const{S\_IRWXU} & 00700 & L'utente ha tutti i permessi.\\ + \const{S\_IRUSR} & 00400 & L'utente ha il permesso di lettura.\\ + \const{S\_IWUSR} & 00200 & L'utente ha il permesso di scrittura.\\ + \const{S\_IXUSR} & 00100 & L'utente ha il permesso di esecuzione.\\ + \hline + \const{S\_IRWXG} & 00070 & Il gruppo ha tutti i permessi.\\ + \const{S\_IRGRP} & 00040 & Il gruppo ha il permesso di lettura.\\ + \const{S\_IWGRP} & 00020 & Il gruppo ha il permesso di scrittura.\\ + \const{S\_IXGRP} & 00010 & Il gruppo ha il permesso di esecuzione.\\ + \hline + \const{S\_IRWXO} & 00007 & Gli altri hanno tutti i permessi.\\ + \const{S\_IROTH} & 00004 & Gli altri hanno il permesso di lettura.\\ + \const{S\_IWOTH} & 00002 & Gli altri hanno il permesso di scrittura.\\ + \const{S\_IXOTH} & 00001 & Gli altri hanno il permesso di esecuzione.\\ + \hline + \end{tabular} + \caption{Valori delle costanti usate per indicare i vari bit di + \param{mode} utilizzato per impostare i permessi dei file.} + \label{tab:file_permission_const} +\end{table} + +Le costanti con cui specificare i singoli bit di \param{mode} sono riportate +in tab.~\ref{tab:file_permission_const}, e corrispondono agli stessi valori +usati per \var{st\_mode} in tab.~\ref{tab:file_mode_flags}. Il valore +di \param{mode} può essere ottenuto combinando fra loro con un OR binario le +costanti simboliche relative ai vari bit, o specificato direttamente, come per +l'omonimo comando di shell, con un valore numerico (la shell lo vuole in +ottale, dato che i bit dei permessi sono divisibili in gruppi di tre), che si +può calcolare direttamente usando lo schema di utilizzo dei bit illustrato in +fig.~\ref{fig:file_perm_bit}. + +Ad esempio i permessi standard assegnati ai nuovi file (lettura e scrittura +per il proprietario, sola lettura per il gruppo e gli altri) sono +corrispondenti al valore ottale $0644$, un programma invece avrebbe anche il +bit di esecuzione attivo, con un valore di $0755$, se si volesse attivare il +bit \acr{suid} il valore da fornire sarebbe $4755$. + +Il cambiamento dei permessi di un file eseguito attraverso queste funzioni ha +comunque alcune limitazioni, previste per motivi di sicurezza. L'uso delle +funzioni infatti è possibile solo se l'\ids{UID} effettivo del processo +corrisponde a quello del proprietario del file o dell'amministratore, +altrimenti esse falliranno con un errore di \errcode{EPERM}. + +Ma oltre a questa regola generale, di immediata comprensione, esistono delle +limitazioni ulteriori. Per questo motivo, anche se si è proprietari del file, +non tutti i valori possibili di \param{mode} sono permessi o hanno effetto; +in particolare accade che: +\begin{enumerate*} +\item siccome solo l'amministratore può impostare lo \textit{sticky bit}, se + l'\ids{UID} effettivo del processo non è zero esso viene automaticamente + cancellato, senza notifica di errore, qualora sia stato indicato + in \param{mode}. +\item per quanto detto in sez.~\ref{sec:file_ownership_management} riguardo la + creazione dei nuovi file, si può avere il caso in cui il file creato da un + processo è assegnato ad un gruppo per il quale il processo non ha privilegi. + Per evitare che si possa assegnare il bit \acr{sgid} ad un file appartenente + ad un gruppo per cui non si hanno diritti, questo viene automaticamente + cancellato da \param{mode}, senza notifica di errore, qualora il gruppo del + file non corrisponda a quelli associati al processo; la cosa non avviene + quando l'\ids{UID} effettivo del processo è zero. +\end{enumerate*} + +Per alcuni filesystem\footnote{i filesystem più comuni (\textsl{ext2}, + \textsl{ext3}, \textsl{ext4}, \textsl{ReiserFS}) supportano questa + caratteristica, che è mutuata da BSD.} è inoltre prevista un'ulteriore +misura di sicurezza, volta a scongiurare l'abuso dei bit \acr{suid} e +\acr{sgid}; essa consiste nel cancellare automaticamente questi bit dai +permessi di un file qualora un processo che non appartenga +all'amministratore\footnote{per la precisione un processo che non dispone + della capacità \const{CAP\_FSETID}, vedi sez.~\ref{sec:proc_capabilities}.} +effettui una scrittura. In questo modo anche se un utente malizioso scopre un +file \acr{suid} su cui può scrivere, un'eventuale modifica comporterà la +perdita di questo privilegio. + +Le funzioni \func{chmod} e \func{fchmod} ci permettono di modificare i +permessi di un file, resta però il problema di quali sono i permessi assegnati +quando il file viene creato. Le funzioni dell'interfaccia nativa di Unix, come +vedremo in sez.~\ref{sec:file_open_close}, permettono di indicare +esplicitamente i permessi di creazione di un file, ma questo non è possibile +per le funzioni dell'interfaccia standard ANSI C che non prevede l'esistenza +di utenti e gruppi, ed inoltre il problema si pone anche per l'interfaccia +nativa quando i permessi non vengono indicati esplicitamente. + +\itindbeg{umask} + +Per le funzioni dell'interfaccia standard ANSI C l'unico riferimento possibile +è quello della modalità di apertura del nuovo file (lettura/scrittura o sola +lettura), che però può fornire un valore che è lo stesso per tutti e tre i +permessi di sez.~\ref{sec:file_perm_overview} (cioè $666$ nel primo caso e +$222$ nel secondo). Per questo motivo il sistema associa ad ogni +processo\footnote{è infatti contenuta nel campo \var{umask} della struttura + \kstruct{fs\_struct}, vedi fig.~\ref{fig:proc_task_struct}.} una maschera +di bit, la cosiddetta \textit{umask}, che viene utilizzata per impedire che +alcuni permessi possano essere assegnati ai nuovi file in sede di creazione. I +bit indicati nella maschera vengono infatti cancellati dai permessi quando un +nuovo file viene creato.\footnote{l'operazione viene fatta sempre: anche + qualora si indichi esplicitamente un valore dei permessi nelle funzioni di + creazione che lo consentono, i permessi contenuti nella \textit{umask} + verranno tolti.} + +La funzione di sistema che permette di impostare il valore di questa maschera +di controllo è \funcd{umask}, ed il suo prototipo è: + +\begin{funcproto}{ +\fhead{stat.h} +\fdecl{mode\_t umask(mode\_t mask)} +\fdesc{Imposta la maschera dei permessi.} +} + +{La funzione ritorna il precedente valore della maschera, non sono previste + condizioni di errore.} +\end{funcproto} + +La funzione imposta la maschera dei permessi dei bit al valore specificato +da \param{mask}, di cui vengono presi solo i 9 bit meno significativi. In +genere si usa questa maschera per impostare un valore predefinito che escluda +preventivamente alcuni permessi, il caso più comune è eliminare il permesso di +scrittura per il gruppo e gli altri, corrispondente ad un valore +per \param{mask} pari a $022$. In questo modo è possibile cancellare +automaticamente i permessi non voluti. Di norma questo valore viene impostato +una volta per tutte al login (a $022$ se non indicato altrimenti), e gli +utenti non hanno motivi per modificarlo. + +\itindend{umask} + + +\subsection{La gestione della titolarità dei file} +\label{sec:file_ownership_management} + +Vedremo in sez.~\ref{sec:file_open_close} con quali funzioni si possono creare +nuovi file, in tale occasione vedremo che è possibile specificare in sede di +creazione quali permessi applicare ad un file, però non si può indicare a +quale utente e gruppo esso deve appartenere. Lo stesso problema si presenta +per la creazione di nuove directory (procedimento descritto in +sez.~\ref{sec:file_dir_creat_rem}). + +Lo standard POSIX prescrive che l'\ids{UID} del nuovo file corrisponda +all'\ids{UID} effettivo del processo che lo crea; per il \ids{GID} invece +prevede due diverse possibilità: +\begin{itemize*} +\item che il \ids{GID} del file corrisponda al \ids{GID} effettivo del + processo. +\item che il \ids{GID} del file corrisponda al \ids{GID} della directory in + cui esso è creato. +\end{itemize*} + +In genere BSD usa sempre la seconda possibilità, che viene per questo chiamata +semantica BSD. Linux invece segue normalmente quella che viene chiamata +semantica SVr4: di norma un nuovo file viene creato, seguendo la prima +opzione, con il \ids{GID} del processo, se però la directory in cui viene +creato ha il bit \acr{sgid} impostato allora viene usata la seconda +opzione. L'adozione di questa semantica però può essere controllata, +all'interno di alcuni filesystem,\footnote{con il kernel 2.6.25 questi erano + \acr{ext2}, \acr{ext3}, \acr{ext4}, e XFS.} con l'uso dell'opzione di +montaggio \texttt{grpid}, che se attivata fa passare all'uso della semantica +BSD. + +Usare la semantica BSD ha il vantaggio che il \ids{GID} viene sempre +automaticamente propagato, restando coerente a quello della directory di +partenza, in tutte le sotto-directory. La semantica SVr4 offre la possibilità +di scegliere, ma per ottenere lo stesso risultato di coerenza che si ha con +quella di BSD necessita che quando si creano nuove directory venga propagato +il bit \acr{sgid}. Questo è il comportamento predefinito del comando +\cmd{mkdir}, ed è in questo modo ad esempio che le varie distribuzioni +assicurano che le sotto-directory create nella home di un utente restino +sempre con il \ids{GID} del gruppo primario dello stesso. + +La presenza del bit \acr{sgid} è inoltre molto comoda quando si hanno +directory contenenti file condivisi da un gruppo di utenti in cui possono +scrivere tutti i membri dello stesso, dato che assicura che i file che gli +utenti vi creano appartengano allo gruppo stesso. Questo non risolve però +completamente i problemi di accesso da parte di altri utenti dello stesso +gruppo, in quanto di default i permessi assegnati al gruppo non sono +sufficienti per un accesso in scrittura; in questo caso si deve aver cura di +usare prima della creazione dei file un valore per \textit{umask} lasci il +permesso di scrittura.\footnote{in tal caso si può assegnare agli utenti del + gruppo una \textit{umask} di $002$, anche se la soluzione migliore in questo + caso è usare una ACL di default (vedi sez.~\ref{sec:file_ACL}).} + +Come avviene nel caso dei permessi esistono anche delle appropriate funzioni +di sistema, \funcd{chown} \funcd{fchown} e \funcd{lchown}, che permettono di +cambiare sia l'utente che il gruppo a cui un file appartiene; i rispettivi +prototipi sono: + +\begin{funcproto}{ +\fhead{sys/types.h} +\fhead{sys/stat.h} +\fdecl{int chown(const char *path, uid\_t owner, gid\_t group)} +\fdecl{int fchown(int fd, uid\_t owner, gid\_t group)} +\fdecl{int lchown(const char *path, uid\_t owner, gid\_t group)} +\fdesc{Cambiano proprietario e gruppo proprietario di un file.} +} + +{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{EPERM}] l'\ids{UID} effettivo non corrisponde a quello del + proprietario del file o non è zero, o utente e gruppo non sono validi. + \end{errlist} + ed inoltre per tutte \errval{EROFS} e \errval{EIO}, per \func{chown} + \errval{EACCES}, \errval{EFAULT}, \errval{ELOOP}, \errval{ENAMETOOLONG}, + \errval{ENOENT}, \errval{ENOMEM}, \errval{ENOTDIR}, per \func{fchown} + \errval{EBADF} nel loro significato generico.} +\end{funcproto} + +Le funzioni cambiano utente e gruppo di appartenenza di un file ai valori +specificati dalle variabili \param{owner} e \param{group}. Con Linux solo +l'amministratore\footnote{o in generale un processo con la capacità + \const{CAP\_CHOWN}, vedi sez.~\ref{sec:proc_capabilities}.} può cambiare il +proprietario di un file; in questo viene seguita la semantica usata da BSD che +non consente agli utenti di assegnare i loro file ad altri utenti evitando +eventuali aggiramenti delle quote. L'amministratore può cambiare sempre il +gruppo di un file, il proprietario può cambiare il gruppo solo dei file che +gli appartengono e solo se il nuovo gruppo è il suo gruppo primario o uno dei +gruppi di cui fa parte. + +La funzione \func{chown} segue i collegamenti simbolici, per operare +direttamente su un collegamento simbolico si deve usare la funzione +\func{lchown}.\footnote{fino alla versione 2.1.81 in Linux \func{chown} non + seguiva i collegamenti simbolici, da allora questo comportamento è stato + assegnato alla funzione \func{lchown}, introdotta per l'occasione, ed è + stata creata una nuova \textit{system call} per \func{chown} che seguisse i + collegamenti simbolici.} La funzione \func{fchown} opera su un file aperto, +essa è mutuata da BSD, ma non è nello standard POSIX. Un'altra estensione +rispetto allo standard POSIX è che specificando -1 come valore +per \param{owner} e \param{group} i valori restano immutati. + +Quando queste funzioni sono chiamate con successo da un processo senza i +privilegi di amministratore entrambi i bit \acr{suid} e \acr{sgid} vengono +cancellati. Questo non avviene per il bit \acr{sgid} nel caso in cui esso sia +usato (in assenza del corrispondente permesso di esecuzione) per indicare che +per il file è attivo il \textit{mandatory locking} (vedi +sez.~\ref{sec:file_mand_locking}). + + +\subsection{Un quadro d'insieme sui permessi} +\label{sec:file_riepilogo} + +Avendo affrontato in maniera separata il comportamento delle varie funzioni +che operano sui permessi dei file ed avendo trattato in sezioni diverse il +significato dei singoli bit dei permessi, vale la pena di fare un riepilogo in +cui si riassumano le caratteristiche di ciascuno di essi, in modo da poter +fornire un quadro d'insieme. + +\begin{table}[!htb] + \centering + \footnotesize + \begin{tabular}[c]{|c|c|c|c|c|c|c|c|c|c|c|c|l|} + \hline + \multicolumn{3}{|c|}{special}& + \multicolumn{3}{|c|}{user}& + \multicolumn{3}{|c|}{group}& + \multicolumn{3}{|c|}{other}& + \multirow{2}{*}{\textbf{Significato per i file}} \\ + \cline{1-12} + \texttt{s}&\texttt{s}&\texttt{t}& + \texttt{r}&\texttt{w}&\texttt{x}& + \texttt{r}&\texttt{w}&\texttt{x}& + \texttt{r}&\texttt{w}&\texttt{x}& \\ + \hline + \hline + 1&-&-&-&-&1&-&-&-&-&-&-&Eseguito conferisce l'\ids{UID} effettivo dell'utente.\\ + -&1&-&-&-&1&-&-&-&-&-&-&Eseguito conferisce il \ids{GID} effettivo del gruppo.\\ + -&1&-&-&-&0&-&-&-&-&-&-&Il \textit{mandatory locking} è abilitato.\\ + -&-&1&-&-&-&-&-&-&-&-&-&Non utilizzato.\\ + -&-&-&1&-&-&-&-&-&-&-&-&Permesso di lettura per l'utente.\\ + -&-&-&-&1&-&-&-&-&-&-&-&Permesso di scrittura per l'utente.\\ + -&-&-&-&-&1&-&-&-&-&-&-&Permesso di esecuzione per l'utente.\\ + -&-&-&-&-&-&1&-&-&-&-&-&Permesso di lettura per il gruppo.\\ + -&-&-&-&-&-&-&1&-&-&-&-&Permesso di scrittura per il gruppo.\\ + -&-&-&-&-&-&-&-&1&-&-&-&Permesso di esecuzione per il gruppo.\\ + -&-&-&-&-&-&-&-&-&1&-&-&Permesso di lettura per tutti gli altri.\\ + -&-&-&-&-&-&-&-&-&-&1&-&Permesso di scrittura per tutti gli altri.\\ + -&-&-&-&-&-&-&-&-&-&-&1&Permesso di esecuzione per tutti gli altri.\\ + \hline + \hline + \multicolumn{3}{|c|}{special}& + \multicolumn{3}{|c|}{user}& + \multicolumn{3}{|c|}{group}& + \multicolumn{3}{|c|}{other}& + \multirow{2}{*}{\textbf{Significato per le directory}} \\ + \cline{1-12} + \texttt{s}&\texttt{s}&\texttt{t}& + \texttt{r}&\texttt{w}&\texttt{x}& + \texttt{r}&\texttt{w}&\texttt{x}& + \texttt{r}&\texttt{w}&\texttt{x}& \\ + \hline + \hline + 1&-&-&-&-&-&-&-&-&-&-&-&Non utilizzato.\\ + -&1&-&-&-&-&-&-&-&-&-&-&Propaga il gruppo ai nuovi file creati.\\ + -&-&1&-&-&-&-&-&-&-&-&-&Solo il proprietario di un file può rimuoverlo.\\ + -&-&-&1&-&-&-&-&-&-&-&-&Permesso di visualizzazione per l'utente.\\ + -&-&-&-&1&-&-&-&-&-&-&-&Permesso di aggiornamento per l'utente.\\ + -&-&-&-&-&1&-&-&-&-&-&-&Permesso di attraversamento per l'utente.\\ + -&-&-&-&-&-&1&-&-&-&-&-&Permesso di visualizzazione per il gruppo.\\ + -&-&-&-&-&-&-&1&-&-&-&-&Permesso di aggiornamento per il gruppo.\\ + -&-&-&-&-&-&-&-&1&-&-&-&Permesso di attraversamento per il gruppo.\\ + -&-&-&-&-&-&-&-&-&1&-&-&Permesso di visualizzazione per tutti gli altri.\\ + -&-&-&-&-&-&-&-&-&-&1&-&Permesso di aggiornamento per tutti gli altri.\\ + -&-&-&-&-&-&-&-&-&-&-&1&Permesso di attraversamento per tutti gli altri.\\ + \hline + \end{tabular} + \caption{Tabella riassuntiva del significato dei bit dei permessi per un + file e directory.} + \label{tab:file_fileperm_bits} +\end{table} + +Nella parte superiore di tab.~\ref{tab:file_fileperm_bits} si è riassunto il +significato dei vari bit dei permessi per un file ordinario; per quanto +riguarda l'applicazione dei permessi per proprietario, gruppo ed altri si +ricordi quanto illustrato in sez.~\ref{sec:file_perm_overview}. Per +compattezza, nella tabella si sono specificati i bit di \textit{suid}, +\textit{sgid} e \textit{sticky} con la notazione illustrata anche in +fig.~\ref{fig:file_perm_bit}. Nella parte inferiore si sono invece riassunti +i significati dei vari bit dei permessi per una directory; anche in questo +caso si è riapplicato ai bit di \textit{suid}, \textit{sgid} e \textit{sticky} +la notazione illustrata in fig.~\ref{fig:file_perm_bit}. + +Si ricordi infine che i permessi non hanno alcun significato per i +collegamenti simbolici, mentre per i file di dispositivo hanno senso soltanto +i permessi di lettura e scrittura, che si riflettono sulla possibilità di +compiere dette operazioni sul dispositivo stesso. + +Nella tabella si è indicato con il carattere ``-'' il fatto che il valore del +bit in questione non è influente rispetto a quanto indicato nella riga della +tabella; la descrizione del significato fa riferimento soltanto alla +combinazione di bit per i quali è stato riportato esplicitamente un valore. +Si rammenti infine che il valore dei bit dei permessi non ha alcun effetto +qualora il processo possieda i privilegi di amministratore. + + +\section{Caratteristiche e funzionalità avanzate} +\label{sec:file_dir_advances} + +Tratteremo qui alcune caratteristiche e funzionalità avanzate della gestione +di file e directory, affrontando anche una serie di estensioni +dell'interfaccia classica dei sistemi unix-like, principalmente utilizzate a +scopi di sicurezza, che sono state introdotte nelle versioni più recenti di +Linux. + +\subsection{Gli attributi estesi} +\label{sec:file_xattr} + +\itindbeg{Extended~Attributes} + +Nelle sezioni precedenti abbiamo trattato in dettaglio le varie informazioni +che il sistema mantiene negli \textit{inode}, e le varie funzioni che +permettono di modificarle. Si sarà notato come in realtà queste informazioni +siano estremamente ridotte. Questo è dovuto al fatto che Unix origina negli +anni '70, quando le risorse di calcolo e di spazio disco erano minime. Con il +venir meno di queste restrizioni è incominciata ad emergere l'esigenza di +poter associare ai file delle ulteriori informazioni astratte (quelli che +abbiamo chiamato genericamente \textsl{metadati}) che però non potevano +trovare spazio nei dati classici mantenuti negli \textit{inode}. + +Per risolvere questo problema alcuni sistemi unix-like (e fra questi anche +Linux) hanno introdotto un meccanismo generico, detto \textit{Extended + Attributes} che consente di associare delle informazioni ulteriori ai +singoli file.\footnote{essi ad esempio vengono usati per le ACL, che + tratteremo in sez.~\ref{sec:file_ACL} e le \textit{file capabilities}, che + vedremo in sez.~\ref{sec:proc_capabilities}.} Gli \textsl{attributi estesi} +non sono altro che delle coppie nome/valore che sono associate permanentemente +ad un oggetto sul filesystem, analoghi di quello che sono le variabili di +ambiente (vedi sez.~\ref{sec:proc_environ}) per un processo. + +Altri sistemi (come Solaris, MacOS e Windows) hanno adottato un meccanismo +diverso in cui ad un file sono associati diversi flussi di dati, su cui +possono essere mantenute ulteriori informazioni, che possono essere accedute +con le normali operazioni di lettura e scrittura. Questi non vanno confusi con +gli \textit{Extended Attributes} (anche se su Solaris hanno lo stesso nome), +che sono un meccanismo molto più semplice, che pur essendo limitato (potendo +contenere solo una quantità limitata di informazione) hanno il grande +vantaggio di essere molto più semplici da realizzare, più +efficienti,\footnote{cosa molto importante, specie per le applicazioni che + richiedono una gran numero di accessi, come le ACL.} e di garantire +l'atomicità di tutte le operazioni. + +In Linux gli attributi estesi sono sempre associati al singolo \textit{inode} +e l'accesso viene sempre eseguito in forma atomica, in lettura il valore +corrente viene scritto su un buffer in memoria, mentre la scrittura prevede +che ogni valore precedente sia sovrascritto. + +Si tenga presente che non tutti i filesystem supportano gli \textit{Extended + Attributes}; al momento della scrittura di queste dispense essi sono +presenti solo sui vari \textsl{extN}, \textsl{ReiserFS}, \textsl{JFS}, +\textsl{XFS} e \textsl{Btrfs}.\footnote{l'elenco è aggiornato a Luglio 2011.} +Inoltre a seconda della implementazione ci possono essere dei limiti sulla +quantità di attributi che si possono utilizzare.\footnote{ad esempio nel caso + di \textsl{ext2} ed \textsl{ext3} è richiesto che essi siano contenuti + all'interno di un singolo blocco, pertanto con dimensioni massime pari a + 1024, 2048 o 4096 byte a seconda delle dimensioni di quest'ultimo impostate + in fase di creazione del filesystem, mentre con \textsl{XFS} non ci sono + limiti ed i dati vengono memorizzati in maniera diversa (nell'\textit{inode} + stesso, in un blocco a parte, o in una struttura ad albero dedicata) per + mantenerne la scalabilità.} Infine lo spazio utilizzato per mantenere gli +attributi estesi viene tenuto in conto per il calcolo delle quote di utente e +gruppo proprietari del file. + +Come meccanismo per mantenere informazioni aggiuntive associate al singolo +file, gli \textit{Extended Attributes} possono avere usi anche molto diversi +fra loro. Per poterli distinguere allora sono stati suddivisi in +\textsl{classi}, a cui poter applicare requisiti diversi per l'accesso e la +gestione. Per questo motivo il nome di un attributo deve essere sempre +specificato nella forma \texttt{namespace.attribute}, dove \texttt{namespace} +fa riferimento alla classe a cui l'attributo appartiene, mentre +\texttt{attribute} è il nome ad esso assegnato. In tale forma il nome di un +attributo esteso deve essere univoco. Al momento\footnote{della scrittura di + questa sezione, kernel 2.6.23, ottobre 2007.} sono state definite le quattro +classi di attributi riportate in tab.~\ref{tab:extended_attribute_class}. + +\begin{table}[htb] + \centering + \footnotesize + \begin{tabular}{|l|p{8cm}|} + \hline + \textbf{Nome} & \textbf{Descrizione} \\ + \hline + \hline + \texttt{security}&Gli \textit{extended security attributes}: vengono + utilizzati dalle estensioni di sicurezza del kernel (i + \textit{Linux Security Modules}), per le realizzazione + di meccanismi evoluti di controllo di accesso come + \textit{SELinux} o le \textit{capabilities} dei + file di sez.~\ref{sec:proc_capabilities}.\\ + \texttt{system} & Gli \textit{extended security attributes}: sono usati + dal kernel per memorizzare dati di sistema associati ai + file come le ACL (vedi sez.~\ref{sec:file_ACL}) o le + \textit{capabilities} (vedi + sez.~\ref{sec:proc_capabilities}).\\ + \texttt{trusted}& I \textit{trusted extended attributes}: vengono + utilizzati per poter realizzare in user space + meccanismi che consentano di mantenere delle + informazioni sui file che non devono essere accessibili + ai processi ordinari.\\ + \texttt{user} & Gli \textit{extended user attributes}: utilizzati per + mantenere informazioni aggiuntive sui file (come il + \textit{mime-type}, la codifica dei caratteri o del + file) accessibili dagli utenti.\\ + \hline + \end{tabular} + \caption{I nomi utilizzati valore di \texttt{namespace} per distinguere le + varie classi di \textit{Extended Attributes}.} + \label{tab:extended_attribute_class} +\end{table} + + +Dato che uno degli usi degli \textit{Extended Attributes} è di impiegarli per +realizzare delle estensioni (come le ACL, \textit{SELinux}, ecc.) al +tradizionale meccanismo dei controlli di accesso di Unix, l'accesso ai loro +valori viene regolato in maniera diversa a seconda sia della loro classe che +di quali, fra le estensioni che li utilizzano, sono poste in uso. In +particolare, per ciascuna delle classi riportate in +tab.~\ref{tab:extended_attribute_class}, si hanno i seguenti casi: +\begin{basedescript}{\desclabelwidth{1.7cm}\desclabelstyle{\nextlinelabel}} +\item[\texttt{security}] L'accesso agli \textit{extended security attributes} + dipende dalle politiche di sicurezza stabilite da loro stessi tramite + l'utilizzo di un sistema di controllo basato sui \textit{Linux Security + Modules} (ad esempio \textit{SELinux}). Pertanto l'accesso in lettura o + scrittura dipende dalle politiche di sicurezza implementate all'interno dal + modulo di sicurezza che si sta utilizzando al momento (ciascuno avrà le + sue). Se non è stato caricato nessun modulo di sicurezza l'accesso in + lettura sarà consentito a tutti i processi, mentre quello in scrittura solo + ai processi con privilegi amministrativi dotati della capacità + \const{CAP\_SYS\_ADMIN}. + +\item[\texttt{system}] Anche l'accesso agli \textit{extended system + attributes} dipende dalle politiche di accesso che il kernel realizza + anche utilizzando gli stessi valori in essi contenuti. Ad esempio nel caso + delle ACL (vedi sez.~\ref{sec:file_ACL}) l'accesso è consentito in lettura + ai processi che hanno la capacità di eseguire una ricerca sul file (cioè + hanno il permesso di lettura sulla directory che contiene il file) ed in + scrittura al proprietario del file o ai processi dotati della capacità + \const{CAP\_FOWNER}.\footnote{vale a dire una politica di accesso analoga a + quella impiegata per gli ordinari permessi dei file.} + +\item[\texttt{trusted}] L'accesso ai \textit{trusted extended attributes}, sia + per la lettura che per la scrittura, è consentito soltanto ai processi con + privilegi amministrativi dotati della capacità \const{CAP\_SYS\_ADMIN}. In + questo modo si possono utilizzare questi attributi per realizzare in user + space dei meccanismi di controllo che accedono ad informazioni non + disponibili ai processi ordinari. + +\item[\texttt{user}] L'accesso agli \textit{extended user attributes} è + regolato dai normali permessi dei file: occorre avere il permesso di lettura + per leggerli e quello di scrittura per scriverli o modificarli. Dato l'uso + di questi attributi si è scelto di applicare al loro accesso gli stessi + criteri che si usano per l'accesso al contenuto dei file (o delle directory) + cui essi fanno riferimento. Questa scelta vale però soltanto per i file e le + directory ordinarie, se valesse in generale infatti si avrebbe un serio + problema di sicurezza dato che esistono diversi oggetti sul filesystem per i + quali è normale avere il permesso di scrittura consentito a tutti gli + utenti, come i collegamenti simbolici, o alcuni file di dispositivo come + \texttt{/dev/null}. Se fosse possibile usare su di essi gli \textit{extended + user attributes} un utente qualunque potrebbe inserirvi dati a + piacere.\footnote{la cosa è stata notata su XFS, dove questo comportamento + permetteva, non essendovi limiti sullo spazio occupabile dagli + \textit{Extended Attributes}, di bloccare il sistema riempiendo il disco.} + + La semantica del controllo di accesso indicata inoltre non avrebbe alcun + senso al di fuori di file e directory: i permessi di lettura e scrittura per + un file di dispositivo attengono alle capacità di accesso al dispositivo + sottostante,\footnote{motivo per cui si può formattare un disco anche se + \texttt{/dev} è su un filesystem in sola lettura.} mentre per i + collegamenti simbolici questi vengono semplicemente ignorati: in nessuno dei + due casi hanno a che fare con il contenuto del file, e nella discussione + relativa all'uso degli \textit{extended user attributes} nessuno è mai stato + capace di indicare una qualche forma sensata di utilizzo degli stessi per + collegamenti simbolici o file di dispositivo, e neanche per le \textit{fifo} o i + socket. Per questo motivo essi sono stati completamente disabilitati per + tutto ciò che non sia un file regolare o una directory.\footnote{si può + verificare la semantica adottata consultando il file \texttt{fs/xattr.c} + dei sorgenti del kernel.} Inoltre per le directory è stata introdotta una + ulteriore restrizione, dovuta di nuovo alla presenza ordinaria di permessi + di scrittura completi su directory come \texttt{/tmp}. Per questo motivo, + per evitare eventuali abusi, se una directory ha lo \textit{sticky bit} + attivo sarà consentito scrivere i suoi \textit{extended user attributes} + soltanto se si è proprietari della stessa, o si hanno i privilegi + amministrativi della capacità \const{CAP\_FOWNER}. +\end{basedescript} + +Le funzioni per la gestione degli attributi estesi, come altre funzioni di +gestione avanzate specifiche di Linux, non fanno parte della \acr{glibc}, e +sono fornite da una apposita libreria, \texttt{libattr}, che deve essere +installata a parte;\footnote{la versione corrente della libreria è + \texttt{libattr1}.} pertanto se un programma le utilizza si dovrà indicare +esplicitamente l'uso della suddetta libreria invocando il compilatore con +l'opzione \texttt{-lattr}. + +Per leggere gli attributi estesi sono disponibili tre diverse funzioni di +sistema, \funcd{getxattr}, \funcd{lgetxattr} e \funcd{fgetxattr}, che +consentono rispettivamente di richiedere gli attributi relativi a un file, a +un collegamento simbolico e ad un file descriptor; i rispettivi prototipi +sono: + +\begin{funcproto}{ +\fhead{sys/types.h} +\fhead{attr/xattr.h} +\fdecl{ssize\_t getxattr(const char *path, const char *name, void *value, + size\_t size)} +\fdecl{ssize\_t lgetxattr(const char *path, const char *name, void *value, + size\_t size)} +\fdecl{ssize\_t fgetxattr(int filedes, const char *name, void *value, + size\_t size)} +\fdesc{Leggono il valore di un attributo esteso.} +} + +{Le funzioni ritornano un intero positivo che indica la dimensione + dell'attributo richiesto in caso di successo e $-1$ per un errore, nel qual + caso \var{errno} assumerà uno dei valori: + \begin{errlist} + \item[\errcode{ENOATTR}] l'attributo richiesto non esiste. + \item[\errcode{ENOTSUP}] gli attributi estesi non sono supportati dal + filesystem o sono disabilitati. + \item[\errcode{ERANGE}] la dimensione \param{size} del buffer \param{value} + non è sufficiente per contenere il risultato. + \end{errlist} + ed inoltre tutti gli errori delle analoghe della famiglia \func{stat} con lo + stesso significato, ed in particolare \errcode{EPERM} se non si hanno i + permessi di accesso all'attributo.} +\end{funcproto} + +Le funzioni \func{getxattr} e \func{lgetxattr} prendono come primo argomento +un \textit{pathname} che indica il file di cui si vuole richiedere un +attributo, la sola differenza è che la seconda, se il \textit{pathname} indica +un collegamento simbolico, restituisce gli attributi di quest'ultimo e non +quelli del file a cui esso fa riferimento. La funzione \func{fgetxattr} prende +invece come primo argomento un numero di file descriptor, e richiede gli +attributi del file ad esso associato. + +Tutte e tre le funzioni richiedono di specificare nell'argomento \param{name} +il nome dell'attributo di cui si vuole ottenere il valore. Il nome deve essere +indicato comprensivo di prefisso del \textit{namespace} cui appartiene (uno +dei valori di tab.~\ref{tab:extended_attribute_class}) nella forma +\texttt{namespace.attributename}, come stringa terminata da un carattere NUL. +Il suo valore verrà restituito nel buffer puntato dall'argomento \param{value} +per una dimensione massima di \param{size} byte;\footnote{gli attributi estesi + possono essere costituiti arbitrariamente da dati testuali o binari.} se +quest'ultima non è sufficiente si avrà un errore di \errcode{ERANGE}. + +Per evitare di dover indovinare la dimensione di un attributo per tentativi si +può eseguire una interrogazione utilizzando un valore nullo per \param{size}; +in questo caso non verrà letto nessun dato, ma verrà restituito come valore di +ritorno della funzione chiamata la dimensione totale dell'attributo esteso +richiesto, che si potrà usare come stima per allocare un buffer di dimensioni +sufficienti.\footnote{si parla di stima perché anche se le funzioni + restituiscono la dimensione esatta dell'attributo al momento in cui sono + eseguite, questa potrebbe essere modificata in qualunque momento da un + successivo accesso eseguito da un altro processo.} + +Un secondo gruppo di funzioni è quello che consente di impostare il valore di +un attributo esteso, queste sono \funcd{setxattr}, \funcd{lsetxattr} e +\funcd{fsetxattr}, e consentono di operare rispettivamente su un file, su un +collegamento simbolico o specificando un file descriptor; i loro prototipi sono: + +\begin{funcproto}{ +\fhead{sys/types.h} +\fhead{attr/xattr.h} +\fdecl{int setxattr(const char *path, const char *name, const void *value, + size\_t size, int flags)} +\fdecl{int lsetxattr(const char *path, const char *name, const void *value, + size\_t size, int flags)} +\fdecl{int fsetxattr(int filedes, const char *name, const void *value, size\_t + size, int flags)} +\fdesc{Impostano il valore di un attributo esteso.} +} + +{Le funzioni ritornano un $0$ in caso di successo e $-1$ per un errore, nel qual + caso \var{errno} assumerà uno dei valori: + \begin{errlist} + \item[\errcode{EEXIST}] si è usato il flag \const{XATTR\_CREATE} ma + l'attributo esiste già. + \item[\errcode{ENOATTR}] si è usato il flag \const{XATTR\_REPLACE} e + l'attributo richiesto non esiste. + \item[\errcode{ENOTSUP}] gli attributi estesi non sono supportati dal + filesystem o sono disabilitati. + \end{errlist} + ed inoltre tutti gli errori delle analoghe della famiglia \func{stat} con lo + stesso significato ed in particolare \errcode{EPERM} se non si hanno i + permessi di accesso all'attributo.} +\end{funcproto} + +Le tre funzioni prendono come primo argomento un valore adeguato al loro +scopo, usato in maniera del tutto identica a quanto visto in precedenza per le +analoghe che leggono gli attributi estesi. Il secondo argomento \param{name} +deve indicare, anche in questo caso con gli stessi criteri appena visti per le +analoghe \func{getxattr}, \func{lgetxattr} e \func{fgetxattr}, il nome +(completo di suffisso) dell'attributo su cui si vuole operare. + +Il valore che verrà assegnato all'attributo dovrà essere preparato nel buffer +puntato da \param{value}, e la sua dimensione totale (in byte) sarà indicata +dall'argomento \param{size}. Infine l'argomento \param{flag} consente di +controllare le modalità di sovrascrittura dell'attributo esteso, esso può +prendere due valori: con \constd{XATTR\_REPLACE} si richiede che l'attributo +esista, nel qual caso verrà sovrascritto, altrimenti si avrà errore, mentre +con \constd{XATTR\_CREATE} si richiede che l'attributo non esista, nel qual +caso verrà creato, altrimenti si avrà errore ed il valore attuale non sarà +modificato. Utilizzando per \param{flag} un valore nullo l'attributo verrà +modificato se è già presente, o creato se non c'è. + +Le funzioni finora illustrate permettono di leggere o scrivere gli attributi +estesi, ma sarebbe altrettanto utile poter vedere quali sono gli attributi +presenti; a questo provvedono le funzioni di sistema \funcd{listxattr}, +\funcd{llistxattr} e \funcd{flistxattr} i cui prototipi sono: + +\begin{funcproto}{ +\fhead{sys/types.h} +\fhead{attr/xattr.h} +\fdecl{ssize\_t listxattr(const char *path, char *list, size\_t size)} +\fdecl{ssize\_t llistxattr(const char *path, char *list, size\_t size)} +\fdecl{ssize\_t flistxattr(int filedes, char *list, size\_t size)} +\fdesc{Leggono la lista degli attributi estesi di un file.} +} + +{Le funzioni ritornano un intero positivo che indica la dimensione della lista + in caso di successo e $-1$ per un errore, nel qual caso \var{errno} assumerà + uno dei valori: + \begin{errlist} + \item[\errcode{ENOTSUP}] gli attributi estesi non sono supportati dal + filesystem o sono disabilitati. + \item[\errcode{ERANGE}] la dimensione \param{size} del buffer \param{value} + non è sufficiente per contenere il risultato. + \end{errlist} + ed inoltre tutti gli errori delle analoghe della famiglia \func{stat} con lo + stesso significato ed in particolare \errcode{EPERM} se non si hanno i + permessi di accesso all'attributo.} +\end{funcproto} + +Come per le precedenti le tre funzioni leggono gli attributi rispettivamente +di un file, un collegamento simbolico o specificando un file descriptor, da +specificare con il loro primo argomento. Gli altri due argomenti, identici per +tutte e tre, indicano rispettivamente il puntatore \param{list} al buffer dove +deve essere letta la lista e la dimensione \param{size} di quest'ultimo. + +La lista viene fornita come sequenza non ordinata dei nomi dei singoli +attributi estesi (sempre comprensivi del prefisso della loro classe) ciascuno +dei quali è terminato da un carattere nullo. I nomi sono inseriti nel buffer +uno di seguito all'altro. Il valore di ritorno della funzione indica la +dimensione totale della lista in byte. + +Come per le funzioni di lettura dei singoli attributi se le dimensioni del +buffer non sono sufficienti si avrà un errore, ma è possibile ottenere dal +valore di ritorno della funzione una stima della dimensione totale della lista +usando per \param{size} un valore nullo. + +Infine per rimuovere semplicemente un attributo esteso, si ha a disposizione +un ultimo gruppo di funzioni di sistema: \funcd{removexattr}, +\funcd{lremovexattr} e \funcd{fremovexattr}; i rispettivi prototipi sono: + +\begin{funcproto}{ +\fhead{sys/types.h} +\fhead{attr/xattr.h} +\fdecl{int removexattr(const char *path, const char *name)} +\fdecl{int lremovexattr(const char *path, const char *name)} +\fdecl{int fremovexattr(int filedes, const char *name)} +\fdesc{Rimuovono un attributo esteso di un file.} +} + +{Le funzioni ritornano $0$ in caso di successo e $-1$ per un errore, nel qual + caso \var{errno} assumerà uno dei valori: + \begin{errlist} + \item[\errcode{ENOATTR}] l'attributo richiesto non esiste. + \item[\errcode{ENOTSUP}] gli attributi estesi non sono supportati dal + filesystem o sono disabilitati. + \end{errlist} + ed inoltre tutti gli errori delle analoghe della famiglia \func{stat} con lo + stesso significato ed in particolare \errcode{EPERM} se non si hanno i + permessi di accesso all'attributo.} +\end{funcproto} + +Le tre funzioni rimuovono un attributo esteso operando rispettivamente su di +un file, su un collegamento simbolico o un file descriptor, che vengono +specificati dal valore passato con il loro primo argomento. L'attributo da +rimuovere deve essere anche in questo caso indicato con +l'argomento \param{name} secondo le stesse modalità già illustrate in +precedenza per le altre funzioni relative alla gestione degli attributi +estesi. + +\itindend{Extended~Attributes} + + +\subsection{Le \textit{Access Control List}} +\label{sec:file_ACL} + +% la documentazione di sistema è nei pacchetti libacl1-dev e acl +% vedi anche http://www.suse.de/~agruen/acl/linux-acls/online/ + +\itindbeg{Access~Control~List~(ACL)} + +Il modello classico dei permessi di Unix, per quanto funzionale ed efficiente, +è comunque piuttosto limitato e per quanto possa aver coperto per lunghi anni +le esigenze più comuni con un meccanismo semplice e potente, non è in grado di +rispondere in maniera adeguata a situazioni che richiedono una gestione +complessa dei permessi di accesso.\footnote{già un requisito come quello di + dare accesso in scrittura ad alcune persone ed in sola lettura ad altre non + si può soddisfare in maniera semplice.} + +Per questo motivo erano state progressivamente introdotte nelle varie versioni +di Unix dei meccanismi di gestione dei permessi dei file più flessibili, nella +forma delle cosiddette \textit{Access Control List} (indicate usualmente con +la sigla ACL). Nello sforzo di standardizzare queste funzionalità era stato +creato un gruppo di lavoro il cui scopo era estendere lo standard POSIX 1003 +attraverso due nuovi insiemi di specifiche, la POSIX 1003.1e per l'interfaccia +di programmazione e la POSIX 1003.2c per i comandi di shell. + +Gli obiettivi del gruppo di lavoro erano però forse troppo ambizioni, e nel +gennaio del 1998 i finanziamenti vennero ritirati senza che si fosse arrivati +alla definizione dello standard richiesto. Dato però che una parte della +documentazione prodotta era di alta qualità venne deciso di rilasciare al +pubblico la diciassettesima bozza del documento, quella che va sotto il nome +di \textit{POSIX 1003.1e Draft 17}, che è divenuta la base sulla quale si +definiscono le cosiddette \textit{Posix ACL}. + +A differenza di altri sistemi, come ad esempio FreeBSD, nel caso di Linux si è +scelto di realizzare le ACL attraverso l'uso degli \textit{Extended + Attributes} (appena trattati in sez.~\ref{sec:file_xattr}), e fornire tutte +le relative funzioni di gestione tramite una libreria, \texttt{libacl} che +nasconde i dettagli implementativi delle ACL e presenta ai programmi una +interfaccia che fa riferimento allo standard POSIX 1003.1e. + +Anche in questo caso le funzioni di questa libreria non fanno parte della +\acr{glibc} e devono essere installate a parte;\footnote{la versione corrente + della libreria è \texttt{libacl1}, e nel caso si usi Debian la si può + installare con il pacchetto omonimo e con il collegato \texttt{libacl1-dev} + per i file di sviluppo.} pertanto se un programma le utilizza si dovrà +indicare esplicitamente l'uso della libreria \texttt{libacl} invocando il +compilatore con l'opzione \texttt{-lacl}. Si tenga presente inoltre che le ACL +devono essere attivate esplicitamente montando il filesystem\footnote{che deve + supportarle, ma questo è ormai vero per praticamente tutti i filesystem più + comuni, con l'eccezione di NFS per il quale esiste però un supporto + sperimentale.} su cui le si vogliono utilizzare con l'opzione \texttt{acl} +attiva. Dato che si tratta di una estensione è infatti opportuno utilizzarle +soltanto laddove siano necessarie. + +Una ACL è composta da un insieme di voci, e ciascuna voce è a sua volta +costituita da un \textsl{tipo}, da un eventuale +\textsl{qualificatore},\footnote{deve essere presente soltanto per le voci di + tipo \const{ACL\_USER} e \const{ACL\_GROUP}.} e da un insieme di permessi. +Ad ogni oggetto sul filesystem si può associare una ACL che ne governa i +permessi di accesso, detta \textit{access ACL}. Inoltre per le directory si +può impostare una ACL aggiuntiva, detta ``\textit{Default ACL}'', che serve ad +indicare quale dovrà essere la ACL assegnata di default nella creazione di un +file all'interno della directory stessa. Come avviene per i permessi le ACL +possono essere impostate solo del proprietario del file, o da un processo con +la capacità \const{CAP\_FOWNER}. + +\begin{table}[htb] + \centering + \footnotesize + \begin{tabular}{|l|p{8cm}|} + \hline + \textbf{Tipo} & \textbf{Descrizione} \\ + \hline + \hline + \constd{ACL\_USER\_OBJ}& Voce che contiene i diritti di accesso del + proprietario del file.\\ + \constd{ACL\_USER} & Voce che contiene i diritti di accesso per + l'utente indicato dal rispettivo + qualificatore.\\ + \constd{ACL\_GROUP\_OBJ}&Voce che contiene i diritti di accesso del + gruppo proprietario del file.\\ + \constd{ACL\_GROUP} & Voce che contiene i diritti di accesso per + il gruppo indicato dal rispettivo + qualificatore.\\ + \constd{ACL\_MASK} & Voce che contiene la maschera dei massimi + permessi di accesso che possono essere garantiti + da voci del tipo \const{ACL\_USER}, + \const{ACL\_GROUP} e \const{ACL\_GROUP\_OBJ}.\\ + \constd{ACL\_OTHER} & Voce che contiene i diritti di accesso di chi + non corrisponde a nessuna altra voce dell'ACL.\\ + \hline + \end{tabular} + \caption{Le costanti che identificano i tipi delle voci di una ACL.} + \label{tab:acl_tag_types} +\end{table} + +L'elenco dei vari tipi di voci presenti in una ACL, con una breve descrizione +del relativo significato, è riportato in tab.~\ref{tab:acl_tag_types}. Tre di +questi tipi, \const{ACL\_USER\_OBJ}, \const{ACL\_GROUP\_OBJ} e +\const{ACL\_OTHER}, corrispondono direttamente ai tre permessi ordinari dei +file (proprietario, gruppo proprietario e tutti gli altri) e per questo una +ACL valida deve sempre contenere una ed una sola voce per ciascuno di questi +tipi. + +Una ACL può poi contenere un numero arbitrario di voci di tipo +\const{ACL\_USER} e \const{ACL\_GROUP}, ciascuna delle quali indicherà i +permessi assegnati all'utente e al gruppo indicato dal relativo qualificatore. +Ovviamente ciascuna di queste voci dovrà fare riferimento ad un utente o ad un +gruppo diverso, e non corrispondenti a quelli proprietari del file. Inoltre se +in una ACL esiste una voce di uno di questi due tipi, è obbligatoria anche la +presenza di una ed una sola voce di tipo \const{ACL\_MASK}, che negli altri +casi è opzionale. + +Una voce di tipo \const{ACL\_MASK} serve a mantenere la maschera dei permessi +che possono essere assegnati tramite voci di tipo \const{ACL\_USER}, +\const{ACL\_GROUP} e \const{ACL\_GROUP\_OBJ}. Se in una di queste voci si +fosse specificato un permesso non presente in \const{ACL\_MASK} questo +verrebbe ignorato. L'uso di una ACL di tipo \const{ACL\_MASK} è di particolare +utilità quando essa associata ad una \textit{Default ACL} su una directory, in +quanto i permessi così specificati verranno ereditati da tutti i file creati +nella stessa directory. Si ottiene così una sorta di \textit{umask} associata +ad un oggetto sul filesystem piuttosto che a un processo. + +Dato che le ACL vengono a costituire una estensione dei permessi ordinari, uno +dei problemi che si erano posti nella loro standardizzazione era appunto +quello della corrispondenza fra questi e le ACL. Come accennato i permessi +ordinari vengono mappati nelle tre voci di tipo \const{ACL\_USER\_OBJ}, +\const{ACL\_GROUP\_OBJ} e \const{ACL\_OTHER} che devono essere presenti in +qualunque ACL; un cambiamento ad una di queste voci viene automaticamente +riflesso sui permessi ordinari dei file e viceversa.\footnote{per permessi + ordinari si intende quelli mantenuti nell'\textit{inode}, che devono restare + dato che un filesystem può essere montato senza abilitare le ACL.} + +In realtà la mappatura è diretta solo per le voci \const{ACL\_USER\_OBJ} e +\const{ACL\_OTHER}, nel caso di \const{ACL\_GROUP\_OBJ} questo vale soltanto +se non è presente una voce di tipo \const{ACL\_MASK}, che è quanto avviene +normalmente se non sono presenti ACL aggiuntive rispetto ai permessi +ordinari. Se invece questa è presente verranno tolti dai permessi di +\const{ACL\_GROUP\_OBJ} (cioè dai permessi per il gruppo proprietario del +file) tutti quelli non presenti in \const{ACL\_MASK}.\footnote{questo diverso + comportamento a seconda delle condizioni è stato introdotto dalla + standardizzazione \textit{POSIX 1003.1e Draft 17} per mantenere il + comportamento invariato sui sistemi dotati di ACL per tutte quelle + applicazioni che sono conformi soltanto all'ordinario standard \textit{POSIX + 1003.1}.} + +Un secondo aspetto dell'incidenza delle ACL sul comportamento del sistema è +quello relativo alla creazione di nuovi file,\footnote{o oggetti sul + filesystem, il comportamento discusso vale per le funzioni \func{open} e + \func{creat} (vedi sez.~\ref{sec:file_open_close}), \func{mkdir} (vedi + sez.~\ref{sec:file_dir_creat_rem}), \func{mknod} e \func{mkfifo} (vedi + sez.~\ref{sec:file_mknod}).} che come accennato può essere modificato dalla +presenza di una \textit{Default ACL} sulla directory che andrà a contenerli. +Se questa non c'è valgono le regole usuali illustrate in +sez.~\ref{sec:file_perm_management}, per cui essi sono determinati dalla +\textit{umask} del processo, e la sola differenza è che i permessi ordinari da +esse risultanti vengono automaticamente rimappati anche su una ACL di accesso +assegnata automaticamente al nuovo file, che contiene soltanto le tre +corrispondenti voci di tipo \const{ACL\_USER\_OBJ}, \const{ACL\_GROUP\_OBJ} e +\const{ACL\_OTHER}. + +Se invece è presente una ACL di default sulla directory che contiene il nuovo +file, essa diventerà automaticamente anche la ACL di accesso di quest'ultimo, +a meno di non aver indicato, nelle funzioni di creazione che lo consentono, +uno specifico valore per i permessi ordinari.\footnote{tutte le funzioni + citate in precedenza supportano un argomento \var{mode} che indichi un + insieme di permessi iniziale.} In tal caso saranno eliminati dalle voci +corrispondenti che deriverebbero dalla ACL di default, tutti i permessi non +presenti in tale indicazione. + +Dato che questa è la ragione che ha portato alla loro creazione, la principale +modifica introdotta nel sistema con la presenza della ACL è quella alle regole +del controllo di accesso ai file che si sono illustrate in +sez.~\ref{sec:file_perm_overview}. Come nel caso ordinario per il controllo +vengono sempre utilizzati gli identificatori del gruppo \textit{effective} del +processo, ma in caso di presenza di una ACL sul file, i passi attraverso i +quali viene stabilito se il processo ha il diritto di accesso sono i seguenti: +\begin{enumerate} +\item Se l'\ids{UID} del processo è nullo (se cioè si è l'amministratore) + l'accesso è sempre garantito senza nessun controllo.\footnote{più + precisamente se si devono avere le capacità \const{CAP\_DAC\_OVERRIDE} per + i file e \const{CAP\_DAC\_READ\_SEARCH} per le directory, vedi + sez.~\ref{sec:proc_capabilities}.} +\item Se l'\ids{UID} del processo corrisponde al proprietario del file allora: + \begin{itemize*} + \item se la voce \const{ACL\_USER\_OBJ} contiene il permesso richiesto, + l'accesso è consentito; + \item altrimenti l'accesso è negato. + \end{itemize*} +\item Se l'\ids{UID} del processo corrisponde ad un qualunque qualificatore + presente in una voce \const{ACL\_USER} allora: + \begin{itemize*} + \item se la voce \const{ACL\_USER} corrispondente e la voce + \const{ACL\_MASK} contengono entrambe il permesso richiesto, l'accesso è + consentito; + \item altrimenti l'accesso è negato. + \end{itemize*} +\item Se è il \ids{GID} del processo o uno dei \ids{GID} supplementari + corrisponde al gruppo proprietario del file allora: + \begin{itemize*} + \item se la voce \const{ACL\_GROUP\_OBJ} e una eventuale voce + \const{ACL\_MASK} (se non vi sono voci di tipo \const{ACL\_GROUP} questa + può non essere presente) contengono entrambe il permesso richiesto, + l'accesso è consentito; + \item altrimenti l'accesso è negato. + \end{itemize*} +\item Se è il \ids{GID} del processo o uno dei \ids{GID} supplementari + corrisponde ad un qualunque qualificatore presente in una voce + \const{ACL\_GROUP} allora: + \begin{itemize*} + \item se la voce \const{ACL\_GROUP} corrispondente e la voce + \const{ACL\_MASK} contengono entrambe il permesso richiesto, l'accesso è + consentito; + \item altrimenti l'accesso è negato. + \end{itemize*} +\item Se la voce \const{ACL\_USER\_OBJ} contiene il permesso richiesto, + l'accesso è consentito, altrimenti l'accesso è negato. +\end{enumerate} + +I passi di controllo vengono eseguiti esattamente in questa sequenza, e la +decisione viene presa non appena viene trovata una corrispondenza con gli +identificatori del processo. Questo significa che i permessi presenti in una +voce di tipo \const{ACL\_USER} hanno la precedenza sui permessi ordinari +associati al gruppo proprietario del file (vale a dire su +\const{ACL\_GROUP\_OBJ}). + +Per la gestione delle ACL lo standard \textit{POSIX 1003.1e Draft 17} ha +previsto delle apposite funzioni ed tutta una serie di tipi di dati +dedicati;\footnote{fino a definire un tipo di dato e delle costanti apposite + per identificare i permessi standard di lettura, scrittura ed esecuzione.} +tutte le operazioni devono essere effettuate attraverso tramite questi tipi di +dati, che incapsulano tutte le informazioni contenute nelle ACL. La prima di +queste funzioni che prendiamo in esame è \funcd{acl\_init}, il cui prototipo +è: + +\begin{funcproto}{ +\fhead{sys/types.h} +\fhead{sys/acl.h} +\fdecl{acl\_t acl\_init(int count)} +\fdesc{Inizializza un'area di lavoro per una ACL.} +} + +{La funzione ritorna un oggetto di tipo \type{acl\_t} in caso di successo e + \val{NULL} per un errore, nel qual caso \var{errno} assumerà uno dei valori: + \begin{errlist} + \item[\errcode{EINVAL}] il valore di \param{count} è negativo. + \item[\errcode{ENOMEM}] non c'è sufficiente memoria disponibile. + \end{errlist} +} +\end{funcproto} + +La funzione alloca ed inizializza un'area di memoria che verrà usata per +mantenere i dati di una ACL contenente fino ad un massimo di \param{count} +voci. La funzione ritorna un valore di tipo \typed{acl\_t} da usare in tutte le +altre funzioni che operano sulla ACL. La funzione si limita alla allocazione +iniziale e non inserisce nessun valore nella ACL che resta vuota. + +Si tenga presente che pur essendo \typed{acl\_t} un tipo opaco che identifica +``\textsl{l'oggetto}'' ACL, il valore restituito dalla funzione non è altro +che un puntatore all'area di memoria allocata per i dati richiesti. Pertanto +in caso di fallimento verrà restituito un puntatore nullo di tipo +``\code{(acl\_t) NULL}'' e si dovrà, in questa come in tutte le funzioni +seguenti che restituiscono un oggetto di tipo \type{acl\_t}, confrontare il +valore di ritorno della funzione con \val{NULL}.\footnote{a voler essere + estremamente pignoli si dovrebbe usare ``\code{(acl\_t) NULL}'', ma è + sufficiente fare un confronto direttamente con \val{NULL} essendo cura del + compilatore fare le conversioni necessarie.} + +Una volta che si siano completate le operazioni sui dati di una ACL la memoria +allocata per un oggetto \type{acl\_t} dovrà essere liberata esplicitamente +attraverso una chiamata alla funzione \funcd{acl\_free}, il cui prototipo è: + +\begin{funcproto}{ +\fhead{sys/types.h} +\fhead{sys/acl.h} +\fdecl{int acl\_free(void *obj\_p)} +\fdesc{Disalloca la memoria riservata per una ACL.} +} + +{La funzione ritorna $0$ in caso di successo e $-1$ per un errore, nel qual + caso \var{errno} può assumere solo il valore: + \begin{errlist} + \item[\errcode{EINVAL}] \param{obj\_p} non è valido. + \end{errlist} +} +\end{funcproto} + +Si noti come la funzione usi come argomento un puntatore di tipo ``\ctyp{void + *}'', essa infatti può essere usata non solo per liberare la memoria +allocata per i dati di una ACL, ma anche per quella usata per creare le +stringhe di descrizione testuale delle ACL o per ottenere i valori dei +qualificatori della una voce di una ACL. L'uso del tipo generico ``\ctyp{void + *}'' consente di evitare di eseguire un \textit{cast} al tipo di dato di cui +si vuole effettuare la disallocazione. + +Si tenga presente poi che oltre a \func{acl\_init} ci sono molte altre +funzioni che possono allocare memoria per i dati delle ACL, è pertanto +opportuno tenere traccia di tutte le chiamate a queste funzioni perché alla +fine delle operazioni tutta la memoria allocata dovrà essere liberata con +\func{acl\_free}. + +Una volta che si abbiano a disposizione i dati di una ACL tramite il +riferimento ad oggetto di tipo \type{acl\_t} questi potranno essere copiati +con la funzione \funcd{acl\_dup}, il cui prototipo è: + +\begin{funcproto}{ +\fhead{sys/types.h} +\fhead{sys/acl.h} +\fdecl{acl\_t acl\_dup(acl\_t acl)} +\fdesc{Crea una copia di una ACL.} +} + +{La funzione ritorna un oggetto di tipo \type{acl\_t} in caso di successo in + caso di successo e \val{NULL} per un errore, nel qual caso \var{errno} + assumerà uno dei valori: + \begin{errlist} + \item[\errcode{EINVAL}] l'argomento \param{acl} non è un puntatore valido + per una ACL. + \item[\errcode{ENOMEM}] non c'è sufficiente memoria disponibile per eseguire + la copia. + \end{errlist} +} +\end{funcproto} + +La funzione crea una copia dei dati della ACL indicata tramite l'argomento +\param{acl}, allocando autonomamente tutto spazio necessario alla copia e +restituendo un secondo oggetto di tipo \type{acl\_t} come riferimento a +quest'ultima. Valgono per questo le stesse considerazioni fatte per il valore +di ritorno di \func{acl\_init}, ed in particolare il fatto che occorrerà +prevedere una ulteriore chiamata esplicita a \func{acl\_free} per liberare la +memoria occupata dalla copia. + +Se si deve creare una ACL manualmente l'uso di \func{acl\_init} è scomodo, +dato che la funzione restituisce una ACL vuota, una alternativa allora è usare +\funcd{acl\_from\_mode} che consente di creare una ACL a partire da un valore +di permessi ordinari, il prototipo della funzione è: + +\begin{funcproto}{ +\fhead{sys/types.h} +\fhead{sys/acl.h} +\fdecl{acl\_t acl\_from\_mode(mode\_t mode)} +\fdesc{Crea una ACL inizializzata con i permessi ordinari.} +} + +{La funzione ritorna un oggetto di tipo \type{acl\_t} in caso di successo e + \val{NULL} per un errore, nel qual caso \var{errno} può assumere solo + il valore \errval{ENOMEM}.} +\end{funcproto} + + +La funzione restituisce una ACL inizializzata con le tre voci obbligatorie +\const{ACL\_USER\_OBJ}, \const{ACL\_GROUP\_OBJ} e \const{ACL\_OTHER} già +impostate secondo la corrispondenza ai valori dei permessi ordinari indicati +dalla maschera passata nell'argomento \param{mode}. Questa funzione è una +estensione usata dalle ACL di Linux e non è portabile, ma consente di +semplificare l'inizializzazione in maniera molto comoda. + +Altre due funzioni che consentono di creare una ACL già inizializzata sono +\funcd{acl\_get\_fd} e \funcd{acl\_get\_file}, che consentono di leggere la +ACL di un file; i rispettivi prototipi sono: + +\begin{funcproto}{ +\fhead{sys/types.h} +\fhead{sys/acl.h} +\fdecl{acl\_t acl\_get\_file(const char *path\_p, acl\_type\_t type)} +\fdecl{acl\_t acl\_get\_fd(int fd)} +\fdesc{Leggono i dati delle ACL di un file.} +} + +{Le funzioni ritornano un oggetto di tipo \type{acl\_t} in caso di successo e + \val{NULL} per un errore, nel qual caso \var{errno} assumerà uno dei valori: + \begin{errlist} + \item[\errcode{EACCESS}] non c'è accesso per una componente di + \param{path\_p} o si è richiesta una ACL di default per un file (solo per + \func{acl\_get\_file}). + \item[\errcode{EINVAL}] \param{type} non ha un valore valido (solo per + \func{acl\_get\_file}). + \item[\errcode{ENOTSUP}] il filesystem cui fa riferimento il file non + supporta le ACL. + \end{errlist} + ed inoltre \errval{ENOMEM} per entrambe, \errval{EBADF} per + \func{acl\_get\_fd}, e \errval{ENAMETOOLONG}, \errval{ENOENT}, + \errval{ENOTDIR}, per \func{acl\_get\_file} nel loro significato generico. } +\end{funcproto} + +Le due funzioni ritornano, con un oggetto di tipo \type{acl\_t}, il valore +della ACL correntemente associata ad un file, che può essere identificato +tramite un file descriptor usando \func{acl\_get\_fd} o con un +\textit{pathname} usando \func{acl\_get\_file}. Nel caso di quest'ultima +funzione, che può richiedere anche la ACL relativa ad una directory, il +secondo argomento \param{type} consente di specificare se si vuole ottenere la +ACL di default o quella di accesso. Questo argomento deve essere di tipo +\typed{acl\_type\_t} e può assumere solo i due valori riportati in +tab.~\ref{tab:acl_type}. + +\begin{table}[htb] + \centering + \footnotesize + \begin{tabular}{|l|l|} + \hline + \textbf{Tipo} & \textbf{Descrizione} \\ + \hline + \hline + \constd{ACL\_TYPE\_ACCESS} & Indica una ACL di accesso.\\ + \constd{ACL\_TYPE\_DEFAULT}& Indica una ACL di default.\\ + \hline + \end{tabular} + \caption{Le costanti che identificano il tipo di ACL.} + \label{tab:acl_type} +\end{table} + +Si tenga presente che nel caso di \func{acl\_get\_file} occorrerà che il +processo chiamante abbia privilegi di accesso sufficienti a poter leggere gli +attributi estesi dei file (come illustrati in sez.~\ref{sec:file_xattr}); +inoltre una ACL di tipo \const{ACL\_TYPE\_DEFAULT} potrà essere richiesta +soltanto per una directory, e verrà restituita solo se presente, altrimenti +verrà restituita una ACL vuota. + +Infine si potrà creare una ACL direttamente dalla sua rappresentazione +testuale con la funzione \funcd{acl\_from\_text}, il cui prototipo è: + +\begin{funcproto}{ +\fhead{sys/types.h} +\fhead{sys/acl.h} +\fdecl{acl\_t acl\_from\_text(const char *buf\_p)} +\fdesc{Crea una ACL a partire dalla sua rappresentazione testuale.} +} + +{La funzione ritorna un oggetto di tipo \type{acl\_t} in caso di successo e + \val{NULL} per un errore, nel qual caso \var{errno} assumerà uno + dei valori: + \begin{errlist} + \item[\errcode{EINVAL}] la rappresentazione testuale all'indirizzo + \param{buf\_p} non è valida. + \item[\errcode{ENOMEM}] non c'è memoria sufficiente per allocare i dati. + \end{errlist} +} +\end{funcproto} + +La funzione prende come argomento il puntatore ad un buffer dove si è inserita +la rappresentazione testuale della ACL che si vuole creare, la memoria +necessaria viene automaticamente allocata ed in caso di successo viene +restituito come valore di ritorno un oggetto di tipo \type{acl\_t} con il +contenuto della stessa, che come per le precedenti funzioni, dovrà essere +disallocato esplicitamente al termine del suo utilizzo. + +La rappresentazione testuale di una ACL è quella usata anche dai comandi +ordinari per la gestione delle ACL (\texttt{getfacl} e \texttt{setfacl}), che +prevede due diverse forme, estesa e breve, entrambe supportate da +\func{acl\_from\_text}. La forma estesa prevede che sia specificata una voce +per riga, nella forma: +\begin{Example} +tipo:qualificatore:permessi +\end{Example} +dove il tipo può essere uno fra \texttt{user}, \texttt{group}, \texttt{other} +e \texttt{mask}. Il qualificatore è presente solo per \texttt{user} e +\texttt{group} e indica l'utente o il gruppo a cui la voce si riferisce; i +permessi sono espressi con una tripletta di lettere analoga a quella usata per +i permessi dei file.\footnote{vale a dire ``\texttt{r}'' per il permesso di + lettura, ``\texttt{w}'' per il permesso di scrittura, ``\texttt{x}'' per il + permesso di esecuzione (scritti in quest'ordine) e ``\texttt{-}'' per + l'assenza del permesso.} + +Un possibile esempio di rappresentazione della ACL di un file ordinario a cui, +oltre ai permessi ordinari, si è aggiunto un altro utente con un accesso in +lettura, è il seguente: +\begin{Example} +user::rw- +group::r-- +other::r-- +user:piccardi:r-- +\end{Example} + +Va precisato che i due tipi \texttt{user} e \texttt{group} sono usati +rispettivamente per indicare delle voci relative ad utenti e +gruppi,\footnote{cioè per voci di tipo \const{ACL\_USER\_OBJ} e + \const{ACL\_USER} per \texttt{user} e \const{ACL\_GROUP\_OBJ} e + \const{ACL\_GROUP} per \texttt{group}.} applicate sia a quelli proprietari +del file che a quelli generici; quelle dei proprietari si riconoscono per +l'assenza di un qualificatore, ed in genere si scrivono per prima delle altre. +Il significato delle voci di tipo \texttt{mask} e \texttt{mark} è evidente. In +questa forma si possono anche inserire dei commenti precedendoli con il +carattere ``\texttt{\#}''. + +La forma breve prevede invece la scrittura delle singole voci su una riga, +separate da virgole; come specificatori del tipo di voce si possono usare le +iniziali dei valori usati nella forma estesa (cioè ``\texttt{u}'', +``\texttt{g}'', ``\texttt{o}'' e ``\texttt{m}''), mentre le altri parte della +voce sono le stesse. In questo caso non sono consentiti permessi. + +Per la conversione inversa, che consente di ottenere la rappresentazione +testuale di una ACL, sono invece disponibili due funzioni. La prima delle due, +di uso più immediato, è \funcd{acl\_to\_text}, ed il suo prototipo è: + +\begin{funcproto}{ +\fhead{sys/types.h} +\fhead{sys/acl.h} +\fdecl{char *acl\_to\_text(acl\_t acl, ssize\_t *len\_p)} +\fdesc{Produce la rappresentazione testuale di una ACL.} +} + +{La funzione ritorna il puntatore ad una stringa con la rappresentazione + testuale della ACL in caso di successo e \var{NULL} per un errore, nel qual + caso \var{errno} assumerà uno dei valori: + \begin{errlist} + \item[\errcode{EINVAL}] la ACL indicata da \param{acl} non è valida. + \item[\errcode{ENOMEM}] non c'è memoria sufficiente per allocare i dati. + \end{errlist} +} +\end{funcproto} + +La funzione restituisce il puntatore ad una stringa terminata da NUL +contenente la rappresentazione in forma estesa della ACL passata come +argomento, ed alloca automaticamente la memoria necessaria. Questa dovrà poi +essere liberata, quando non più necessaria, con \func{acl\_free}. Se +nell'argomento \param{len\_p} si passa un valore puntatore ad una variabile +intera in questa verrà restituita (come \textit{value result argument}) la +dimensione della stringa con la rappresentazione testuale, non comprendente il +carattere nullo finale. + +La seconda funzione, che permette di controllare con una gran dovizia di +particolari la generazione della stringa contenente la rappresentazione +testuale della ACL, è \funcd{acl\_to\_any\_text}, ed il suo prototipo è: + +\begin{funcproto}{ +\fhead{sys/types.h} +\fhead{sys/acl.h} +\fdecl{char *acl\_to\_any\_text(acl\_t acl, const char *prefix, char + separator, int options)} +\fdesc{Produce la rappresentazione testuale di una ACL.} +} + +{La funzione ritorna il puntatore ad una stringa con la rappresentazione + testuale della ACL in caso di successo e \val{NULL} per un errore, nel qual + caso \var{errno} assumerà uno dei valori: + \begin{errlist} + \item[\errcode{EINVAL}] la ACL indicata da \param{acl} non è valida. + \item[\errcode{ENOMEM}] non c'è memoria sufficiente per allocare i dati. + \end{errlist} +} +\end{funcproto} + +La funzione converte in formato testo la ACL indicata dall'argomento +\param{acl}, usando il carattere \param{separator} come separatore delle +singole voci; se l'argomento \param{prefix} non è nullo la stringa da esso +indicata viene utilizzata come prefisso per le singole voci. + +L'ultimo argomento, \param{options}, consente di controllare la modalità con +cui viene generata la rappresentazione testuale. Un valore nullo fa sì che +vengano usati gli identificatori standard \texttt{user}, \texttt{group}, +\texttt{other} e \texttt{mask} con i nomi di utenti e gruppi risolti rispetto +ai loro valori numerici. Altrimenti si può specificare un valore in forma di +maschera binaria, da ottenere con un OR aritmetico dei valori riportati in +tab.~\ref{tab:acl_to_text_options}. + +\begin{table}[htb] + \centering + \footnotesize + \begin{tabular}{|l|p{8cm}|} + \hline + \textbf{Tipo} & \textbf{Descrizione} \\ + \hline + \hline + \constd{TEXT\_ABBREVIATE} & Stampa le voci in forma abbreviata.\\ + \constd{TEXT\_NUMERIC\_IDS} & non effettua la risoluzione numerica di + \ids{UID} e \ids{GID}.\\ + \constd{TEXT\_SOME\_EFFECTIVE}&Per ciascuna voce che contiene permessi che + vengono eliminati dalla \const{ACL\_MASK} + viene generato un commento con i permessi + effettivamente risultanti; il commento è + separato con un tabulatore.\\ + \constd{TEXT\_ALL\_EFFECTIVE}& Viene generato un commento con i permessi + effettivi per ciascuna voce che contiene + permessi citati nella \const{ACL\_MASK}, + anche quando questi non vengono modificati + da essa; il commento è separato con un + tabulatore.\\ + \constd{TEXT\_SMART\_INDENT} & Da usare in combinazione con le precedenti + opzioni \const{TEXT\_SOME\_EFFECTIVE} e + \const{TEXT\_ALL\_EFFECTIVE}, aumenta + automaticamente il numero di spaziatori + prima degli eventuali commenti in modo da + mantenerli allineati.\\ + \hline + \end{tabular} + \caption{Possibili valori per l'argomento \param{options} di + \func{acl\_to\_any\_text}.} + \label{tab:acl_to_text_options} +\end{table} + +Come per \func{acl\_to\_text} anche in questo caso il buffer contenente la +rappresentazione testuale dell'ACL, di cui la funzione restituisce +l'indirizzo, viene allocato automaticamente, e dovrà essere esplicitamente +disallocato con una chiamata ad \func{acl\_free}. Si tenga presente infine che +questa funzione è una estensione specifica di Linux, e non è presente nella +bozza dello standard POSIX.1e. + +Per quanto utile per la visualizzazione o l'impostazione da riga di comando +delle ACL, la forma testuale non è la più efficiente per poter memorizzare i +dati relativi ad una ACL, ad esempio quando si vuole eseguirne una copia a +scopo di archiviazione. Per questo è stata prevista la possibilità di +utilizzare una rappresentazione delle ACL in una apposita forma binaria +contigua e persistente. È così possibile copiare il valore di una ACL in un +buffer e da questa rappresentazione tornare indietro e generare una ACL. + +Lo standard POSIX.1e prevede a tale scopo tre funzioni, la prima e più +semplice è \funcd{acl\_size}, che consente di ottenere la dimensione che avrà +la citata rappresentazione binaria, in modo da poter allocare per essa un +buffer di dimensione sufficiente, il suo prototipo è: + +\begin{funcproto}{ +\fhead{sys/types.h} +\fhead{sys/acl.h} +\fdecl{ssize\_t acl\_size(acl\_t acl)} +\fdesc{Determina la dimensione della rappresentazione binaria di una ACL.} +} + +{La funzione ritorna la dimensione in byte della rappresentazione binaria + della ACL in caso di successo e $-1$ per un errore, nel qual caso + \var{errno} può assumere solo il valore: + \begin{errlist} + \item[\errcode{EINVAL}] la ACL indicata da \param{acl} non è valida. + \end{errlist} +} +\end{funcproto} + +Ottenuta con \func{acl\_size} la dimensione per il buffer di una ACL lo si +potrà allocare direttamente con \func{malloc}. La rappresentazione binaria di +una ACL si potrà invece ottenere con la funzione \funcd{acl\_copy\_ext}, il +cui prototipo è: + +\begin{funcproto}{ +\fhead{sys/types.h} +\fhead{sys/acl.h} +\fdecl{ssize\_t acl\_copy\_ext(void *buf\_p, acl\_t acl, ssize\_t size)} +\fdesc{Ottiene la rappresentazione binaria di una ACL.} +} + +{La funzione ritorna la dimensione in byte della rappresentazione binaria + della ACL in caso di successo e $-1$ per un errore, nel qual caso + \var{errno} assumerà uno dei valori: + \begin{errlist} + \item[\errcode{EINVAL}] la ACL indicata da \param{acl} non è valida o + \param{size} è negativo o nullo. + \item[\errcode{ERANGE}] il valore di \param{size} è più piccolo della + dimensione della rappresentazione della ACL. + \end{errlist} +} +\end{funcproto} + +La funzione scriverà la rappresentazione binaria della ACL indicata da +\param{acl} sul buffer di dimensione \param{size} +all'indirizzo \param{buf\_p}, restituendo la dimensione della stessa come +valore di ritorno. Qualora la dimensione della rappresentazione ecceda il +valore di \param{size} la funzione fallirà con un errore di +\errcode{ERANGE}. La funzione non ha nessun effetto sulla ACL indicata +da \param{acl}. + +Viceversa se si vuole ripristinare una ACL a partire da una rappresentazione +binaria si potrà usare la funzione \funcd{acl\_copy\_int}, il cui prototipo è: + +\begin{funcproto}{ +\fhead{sys/types.h} +\fhead{sys/acl.h} +\fdecl{acl\_t acl\_copy\_int(const void *buf\_p)} +\fdesc{Ripristina la rappresentazione binaria di una ACL.} +} + +{La funzione ritorna un oggetto di tipo \type{acl\_t} in caso di successo e + \val{NULL} per un errore, nel qual caso \var{errno} assumerà uno dei valori: + \begin{errlist} + \item[\errcode{EINVAL}] il buffer all'indirizzo \param{buf\_p} non contiene + una rappresentazione corretta di una ACL. + \item[\errcode{ENOMEM}] non c'è memoria sufficiente per allocare un oggetto + \type{acl\_t} per la ACL richiesta. + \end{errlist} +} +\end{funcproto} + +La funzione alloca autonomamente un oggetto di tipo \type{acl\_t}, restituito +come valore di ritorno, con il contenuto della ACL rappresentata dai dati del +buffer puntato da \param{buf\_p}. Al solito l'oggetto \type{acl\_t} dovrà +essere disallocato esplicitamente al termine del suo utilizzo. + +Una volta che si disponga della ACL desiderata, questa potrà essere impostata +su un file o una directory. Per impostare una ACL sono disponibili due +funzioni; la prima è \funcd{acl\_set\_file}, che opera sia su file che su +directory, ed il cui prototipo è: + +\begin{funcproto}{ +\fhead{sys/types.h} +\fhead{sys/acl.h} +\fdecl{int acl\_set\_file(const char *path, acl\_type\_t type, acl\_t acl)} +\fdesc{Imposta una ACL su un file o una directory.} +} + +{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{EACCES}] o un generico errore di accesso a \param{path} o il + valore di \param{type} specifica una ACL il cui tipo non può essere + assegnato a \param{path}. + \item[\errcode{EINVAL}] o \param{acl} non è una ACL valida, o \param{type} + ha un valore non corretto. + \item[\errcode{ENOSPC}] non c'è spazio disco sufficiente per contenere i + dati aggiuntivi della ACL. + \item[\errcode{ENOTSUP}] si è cercato di impostare una ACL su un file + contenuto in un filesystem che non supporta le ACL. + \end{errlist} + ed inoltre \errval{ENAMETOOLONG}, \errval{ENOENT}, \errval{ENOTDIR}, + \errval{EPERM}, \errval{EROFS} nel loro significato generico.} +\end{funcproto} + +La funzione consente di assegnare la ACL contenuta in \param{acl} al file o +alla directory indicate dal \textit{pathname} \param{path}, mentre +con \param{type} si indica il tipo di ACL utilizzando le costanti di +tab.~\ref{tab:acl_type}, ma si tenga presente che le ACL di default possono +essere solo impostate qualora \param{path} indichi una directory. Inoltre +perché la funzione abbia successo la ACL dovrà essere valida, e contenere +tutti le voci necessarie, unica eccezione è quella in cui si specifica una ACL +vuota per cancellare la ACL di default associata a +\param{path}.\footnote{questo però è una estensione della implementazione delle + ACL di Linux, la bozza di standard POSIX.1e prevedeva l'uso della apposita + funzione \funcd{acl\_delete\_def\_file}, che prende come unico argomento il + \textit{pathname} della directory di cui si vuole cancellare l'ACL di + default, per i dettagli si ricorra alla pagina di manuale.} La seconda +funzione che consente di impostare una ACL è \funcd{acl\_set\_fd}, ed il suo +prototipo è: + +\begin{funcproto}{ +\fhead{sys/types.h} +\fhead{sys/acl.h} +\fdecl{int acl\_set\_fd(int fd, acl\_t acl)} +\fdesc{Imposta una ACL su un file descriptor.} +} + +{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{EINVAL}] o \param{acl} non è una ACL valida, o ha più voci di + quante se ne possono assegnare al file indicato da \param{fd}. + \item[\errcode{ENOSPC}] non c'è spazio disco sufficiente per contenere i + dati aggiuntivi della ACL. + \item[\errcode{ENOTSUP}] si è cercato di impostare una ACL su un file + contenuto in un filesystem che non supporta le ACL. + \end{errlist} + ed inoltre \errval{EBADF}, \errval{EPERM}, \errval{EROFS} nel loro + significato generico. +} +\end{funcproto} + +La funzione è del tutto è analoga a \func{acl\_set\_file} ma opera +esclusivamente sui file identificati tramite un file descriptor. Non dovendo +avere a che fare con directory (e con la conseguente possibilità di avere una +ACL di default) la funzione non necessita che si specifichi il tipo di ACL, +che sarà sempre di accesso, e prende come unico argomento, a parte il file +descriptor, la ACL da impostare. + +Le funzioni viste finora operano a livello di una intera ACL, eseguendo in una +sola volta tutte le operazioni relative a tutte le voci in essa contenuta. In +generale è possibile modificare un singolo valore all'interno di una singola +voce direttamente con le funzioni previste dallo standard POSIX.1e. Queste +funzioni però sono alquanto macchinose da utilizzare per cui è molto più +semplice operare direttamente sulla rappresentazione testuale. Questo è il +motivo per non tratteremo nei dettagli dette funzioni, fornendone solo una +descrizione sommaria; chi fosse interessato potrà ricorrere alle pagine di +manuale. + +Se si vuole operare direttamente sui contenuti di un oggetto di tipo +\type{acl\_t} infatti occorre fare riferimento alle singole voci tramite gli +opportuni puntatori di tipo \typed{acl\_entry\_t}, che possono essere ottenuti +dalla funzione \funcm{acl\_get\_entry} (per una voce esistente) o dalla +funzione \funcm{acl\_create\_entry} per una voce da aggiungere. Nel caso della +prima funzione si potrà poi ripetere la lettura per ottenere i puntatori alle +singole voci successive alla prima. + +Una volta ottenuti detti puntatori si potrà operare sui contenuti delle +singole voci: con le funzioni \funcm{acl\_get\_tag\_type}, +\funcm{acl\_get\_qualifier}, \funcm{acl\_get\_permset} si potranno leggere +rispettivamente tipo, qualificatore e permessi, mentre con le corrispondenti +\funcm{acl\_set\_tag\_type}, \funcm{acl\_set\_qualifier}, +\funcm{acl\_set\_permset} si potranno impostare i valori; in entrambi i casi +vengono utilizzati tipi di dato ad hoc, descritti nelle pagine di manuale. Si +possono poi copiare i valori di una voce da una ACL ad un altra con +\funcm{acl\_copy\_entry} o eliminare una voce da una ACL con +\funcm{acl\_delete\_entry} e verificarne la validità prima di usarla con +\funcm{acl\_valid} o \funcm{acl\_check}. + +\itindend{Access~Control~List~(ACL)} + +Come esempio di utilizzo di queste funzioni nei sorgenti allegati alla guida +si è distribuito il programma \texttt{mygetfacl.c}, che consente di leggere le +ACL di un file, passato come argomento. + +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{\codesamplewidth} + \includecodesample{listati/mygetfacl.c} + \end{minipage} + \normalsize + \caption{Corpo principale del programma \texttt{mygetfacl.c}.} + \label{fig:proc_mygetfacl} +\end{figure} + +La sezione principale del programma, da cui si è rimossa la sezione sulla +gestione delle opzioni, è riportata in fig.~\ref{fig:proc_mygetfacl}. Il +programma richiede un unico argomento (\texttt{\small 16-20}) che indica il +file di cui si vuole leggere la ACL. Se questo è presente si usa +(\texttt{\small 22}) la funzione \func{get\_acl\_file} per leggerne la ACL, e +si controlla (\texttt{\small 23-26}) se l'operazione ha successo, uscendo con +un messaggio di errore in caso contrario. + +Ottenuta la ACL la si converte in formato testuale (\texttt{\small 27}) con la +funzione \func{acl\_to\_text}, controllando di nuovo se l'operazione ha +successo (\texttt{\small 28-31}) ed uscendo in caso contrario. Si provvede +infine a stampare la rappresentazione testuale (\texttt{\small 32}) e dopo +aver liberato (\texttt{\small 33-34}) le risorse allocate automaticamente, si +conclude l'esecuzione. + + +\subsection{La gestione delle quote disco} +\label{sec:disk_quota} + +Quella delle quote disco è una funzionalità introdotta inizialmente da BSD e +presente in Linux fino dai kernel dalla serie 2.0, che consente di porre dei +tetti massimi al consumo delle risorse di un filesystem (spazio disco e +\textit{inode}) da parte di utenti e gruppi. + +Dato che la funzionalità ha senso solo per i filesystem su cui si mantengono i +dati degli utenti\footnote{in genere la si attiva sul filesystem che contiene + le \textit{home} degli utenti, dato che non avrebbe senso per i file di + sistema che in genere appartengono all'amministratore.} essa deve essere +attivata esplicitamente. Questo si fa, per tutti i filesystem che le +supportano, tramite due distinte opzioni di montaggio, \texttt{usrquota} e +\texttt{grpquota} che abilitano le quote rispettivamente per gli utenti e per +i gruppi. Così è possibile usare le limitazioni sulle quote o sugli utenti o +sui gruppi o su entrambi. + +Il meccanismo prevede che per ciascun filesystem che supporta le quote disco +(i vari \textit{extN}, \textit{btrfs}, \textit{XFS}, \textit{JFS}, +\textit{ReiserFS}) il kernel provveda sia a mantenere aggiornati i dati +relativi al consumo delle risorse da parte degli utenti e dei gruppi, che a +far rispettare i limiti imposti dal sistema, con la generazione di un errore +di \errcode{EDQUOT} per tutte le operazioni sui file che porterebbero ad un +superamento degli stessi. Si tenga presente che questi due compiti sono +separati, il primo si attiva al montaggio del filesystem con il supporto per +le quote, il secondo deve essere abilitato esplicitamente. + +Per il mantenimento dei dati di consumo delle risorse vengono usati due file +riservati nella directory radice del filesystem su cui si sono attivate le +quote, uno per le quote utente e l'altro per le quote gruppo.\footnote{la cosa + vale per tutti i filesystem tranne \textit{XFS} che mantiene i dati + internamente.} Con la versione 2 del supporto delle quote, che da anni è +l'unica rimasta in uso, questi file sono \texttt{aquota.user} e +\texttt{aquota.group}, in precedenza erano \texttt{quota.user} e +\texttt{quota.group}. + +Dato che questi file vengono aggiornati soltanto se il filesystem è stato +montato attivando il supporto delle quote, se si abilita il supporto in un +secondo tempo e nel frattempo sono state eseguite delle operazioni sul +filesystem quando il supporto era disabilitato, i dati contenuti possono non +corrispondere esattamente allo stato corrente del consumo delle risorse. Per +questo motivo prima di montare in scrittura un filesystem su cui sono +abilitate le quote viene richiesto di utilizzare il comando \cmd{quotacheck} +per verificare e aggiornare i dati. + +Le restrizioni sul consumo delle risorse previste dal sistema delle quote +prevedono sempre la presenza di due diversi limiti, il primo viene detto +\textit{soft limit} e può essere superato per brevi periodi di tempo senza che +causare errori per lo sforamento delle quote, il secondo viene detto +\textit{hard limit} e non può mai essere superato. + +Il periodo di tempo per cui è possibile eccedere rispetto alle restrizioni +indicate dal \textit{soft limit} è detto ``\textsl{periodo di grazia}'' +(\textit{grace period}), che si attiva non appena si supera la quota da esso +indicata. Se si continua a restare al di sopra del \textit{soft limit} una +volta scaduto il \textit{grace period} questo verrà trattato allo stesso modo +dell'\textit{hard limit} e si avrà l'emissione immediata di un errore. + +Si tenga presente infine che entrambi i tipi di limiti (\textit{soft limit} e +\textit{hard limit}) possono essere disposti separatamente su entrambe le +risorse di un filesystem, essi cioè possono essere presenti in maniera +indipendente sia sullo spazio disco, con un massimo per il numero di blocchi, +che sui file, con un massimo per il numero di \textit{inode}. + +La funzione di sistema che consente di controllare tutti i vari aspetti della +gestione delle quote è \funcd{quotactl}, ed il suo prototipo è: + +\begin{funcproto}{ +\fhead{sys/types.h} +\fhead{sys/quota.h} +\fdecl{int quotactl(int cmd, const char *dev, int id, caddr\_t addr)} +\fdesc{Esegue una operazione di controllo sulle quote disco.} +} + +{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{EACCES}] si è richiesto \const{Q\_QUOTAON}, ma il file delle + quote indicato da \param{addr} non esiste o non è un file ordinario. + \item[\errcode{EBUSY}] si è richiesto \const{Q\_QUOTAON}, ma le quote sono + già attive. + \item[\errcode{EFAULT}] \param{addr} non è un puntatore valido. + \item[\errcode{EINVAL}] o \param{cmd} non è un comando valido, + o il dispositivo \param{dev} non esiste. + \item[\errcode{EIO}] errore di lettura/scrittura sul file delle quote. + \item[\errcode{EMFILE}] non si può aprire il file delle quote avendo + superato il limite sul numero di file aperti nel sistema. + \item[\errcode{ENODEV}] \param{dev} non corrisponde ad un \textit{mount + point} attivo. + \item[\errcode{ENOPKG}] il kernel è stato compilato senza supporto per le + quote. + \item[\errcode{ENOTBLK}] \param{dev} non è un dispositivo a blocchi. + \item[\errcode{EPERM}] non si hanno i permessi per l'operazione richiesta. + \item[\errcode{ESRCH}] è stato richiesto uno fra \const{Q\_GETQUOTA}, + \const{Q\_SETQUOTA}, \const{Q\_SETUSE}, \const{Q\_SETQLIM} per un + filesystem senza quote attivate. + \end{errlist} +} +\end{funcproto} + +% TODO rivedere gli errori + +La funzione richiede che il filesystem sul quale si vuole operare, che deve +essere specificato con il nome del relativo file di dispositivo +nell'argomento \param{dev}, sia montato con il supporto delle quote +abilitato. Per le operazioni che lo richiedono inoltre si dovrà indicare con +l'argomento \param{id} l'utente o il gruppo (specificati rispettivamente per +\ids{UID} e \ids{GID}) su cui si vuole operare, o altri dati relativi +all'operazione. Alcune operazioni più complesse usano infine +l'argomento \param{addr} per indicare un indirizzo ad un area di memoria il +cui utilizzo dipende dall'operazione stessa. + +La funzione prevede la possibilità di eseguire una serie operazioni sulle +quote molto diverse fra loro, la scelta viene effettuata tramite il primo +argomento, \param{cmd}, che però oltre all'operazione indica anche a quale +tipo di quota (utente o gruppo) l'operazione deve applicarsi. Per questo il +valore di questo argomento viene costruito con l'ausilio della di una apposita +macro \macro{QCMD}: + +{\centering +\vspace{3pt} +\begin{funcbox}{ +\fhead{sys/quota.h} +\fdecl{int \macrod{QCMD}(subcmd,type)} +\fdesc{Imposta il comando \param{subcmd} per il tipo di quote (utente o + gruppo) \param{type}.} +} +\end{funcbox} +} + +La macro consente di specificare, oltre al tipo di operazione, da indicare con +l'argomento \param{subcmd} se questa deve applicarsi alle quote utente o alle +quote gruppo. Questo viene indicato dall'argomento \param{type} che deve +essere sempre definito ed assegnato ad uno fra i due valori \const{USRQUOTA} o +\const{GRPQUOTA}. + +\begin{table}[htb] + \centering + \footnotesize + \begin{tabular}{|l|p{10cm}|} + \hline + \textbf{Comando} & \textbf{Descrizione} \\ + \hline + \hline + \constd{Q\_QUOTAON} & Attiva l'applicazione delle quote disco per il + filesystem indicato da \param{dev}, si deve passare + in \param{addr} il \textit{pathname} al file che + mantiene le quote, che deve esistere, e \param{id} + deve indicare la versione del formato con uno dei + valori di tab.~\ref{tab:quotactl_id_format}; + l'operazione richiede i privilegi di + amministratore.\\ + \constd{Q\_QUOTAOFF}& Disattiva l'applicazione delle quote disco per il + filesystem indicato da \param{dev}, \param{id} + e \param{addr} vengono ignorati; l'operazione + richiede i privilegi di amministratore.\\ + \constd{Q\_GETQUOTA}& Legge i limiti ed i valori correnti delle quote nel + filesystem indicato da \param{dev} per l'utente o + il gruppo specificato da \param{id}; si devono avere + i privilegi di amministratore per leggere i dati + relativi ad altri utenti o a gruppi di cui non si fa + parte, il risultato viene restituito in una struttura + \struct{dqblk} all'indirizzo indicato + da \param{addr}.\\ + \constd{Q\_SETQUOTA}& Imposta i limiti per le quote nel filesystem + indicato da \param{dev} per l'utente o il gruppo + specificato da \param{id} secondo i valori ottenuti + dalla struttura \struct{dqblk} puntata + da \param{addr}; l'operazione richiede i privilegi + di amministratore.\\ + \constd{Q\_GETINFO} & Legge le informazioni (in sostanza i \textit{grace + time}) delle quote del filesystem indicato + da \param{dev} sulla struttura \struct{dqinfo} + puntata da \param{addr}, \param{id} viene ignorato.\\ + \constd{Q\_SETINFO} & Imposta le informazioni delle quote del filesystem + indicato da \param{dev} come ottenuti dalla + struttura \struct{dqinfo} puntata + da \param{addr}, \param{id} viene ignorato; + l'operazione richiede i privilegi di amministratore.\\ + \constd{Q\_GETFMT} & Richiede il valore identificativo (quello di + tab.~\ref{tab:quotactl_id_format}) per il formato + delle quote attualmente in uso sul filesystem + indicato da \param{dev}, che sarà memorizzato + sul buffer di 4 byte puntato da \param{addr}.\\ + \constd{Q\_SYNC} & Aggiorna la copia su disco dei dati delle quote del + filesystem indicato da \param{dev}; in questo + caso \param{dev} può anche essere \val{NULL} nel + qual caso verranno aggiornati i dati per tutti i + filesystem con quote attive, \param{id} + e \param{addr} vengono comunque ignorati.\\ + \constd{Q\_GETSTATS}& Ottiene statistiche ed altre informazioni generali + relative al sistema delle quote per il filesystem + indicato da \param{dev}, richiede che si + passi come argomento \param{addr} l'indirizzo di una + struttura \struct{dqstats}, mentre i valori + di \param{id} e \param{dev} vengono ignorati; + l'operazione è obsoleta e non supportata nei kernel + più recenti, che espongono la stessa informazione + nei file sotto \procfile{/proc/self/fs/quota/}.\\ +% \const{} & .\\ + \hline + \end{tabular} + \caption{Possibili valori per l'argomento \param{subcmd} di + \macro{QCMD}.} + \label{tab:quotactl_commands} +\end{table} + +I possibili valori per l'argomento \param{subcmd} di \macro{QCMD} sono +riportati in tab.~\ref{tab:quotactl_commands}, che illustra brevemente il +significato delle operazioni associate a ciascuno di essi. In generale le +operazioni di attivazione, disattivazione e di modifica dei limiti delle quote +sono riservate e richiedono i privilegi di amministratore.\footnote{per essere + precisi tutte le operazioni indicate come privilegiate in + tab.~\ref{tab:quotactl_commands} richiedono la capacità + \const{CAP\_SYS\_ADMIN}.} Inoltre gli utenti possono soltanto richiedere i +dati relativi alle proprie quote, solo l'amministratore può ottenere i dati di +tutti. + + +Alcune delle operazioni di tab.~\ref{tab:quotactl_commands} sono alquanto +complesse e richiedono un approfondimento maggiore. Le due più rilevanti sono +probabilmente \const{Q\_GETQUOTA} e \const{Q\_SETQUOTA}, che consentono la +gestione dei limiti delle quote. Entrambe fanno riferimento ad una specifica +struttura \struct{dqblk}, la cui definizione è riportata in +fig.~\ref{fig:dqblk_struct},\footnote{la definizione mostrata è quella usata + fino dal kernel 2.4.22, non prenderemo in considerazione le versioni + obsolete.} nella quale vengono inseriti i dati relativi alle quote di un +singolo utente o gruppo. + +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{0.95\textwidth} + \includestruct{listati/dqblk.h} + \end{minipage} + \normalsize + \caption{La struttura \structd{dqblk} per i dati delle quote disco.} + \label{fig:dqblk_struct} +\end{figure} + +La struttura \struct{dqblk} viene usata sia con \const{Q\_GETQUOTA} per +ottenere i valori correnti dei limiti e dell'occupazione delle risorse, che +con \const{Q\_SETQUOTA} per effettuare modifiche ai limiti. Come si può notare +ci sono alcuni campi (in sostanza \val{dqb\_curspace}, \val{dqb\_curinodes}, +\val{dqb\_btime}, \val{dqb\_itime}) che hanno senso solo in lettura, in quanto +riportano uno stato non modificabile da \func{quotactl} come l'uso corrente di +spazio disco ed \textit{inode}, o il tempo che resta nel caso si sia superato +un \textit{soft limit}. + +Inoltre in caso di modifica di un limite si può voler operare solo su una +delle risorse (blocchi o \textit{inode}),\footnote{non è possibile modificare + soltanto uno dei limiti (\textit{hard} o \textit{soft}) occorre sempre + rispecificarli entrambi.} per questo la struttura prevede un campo apposito, +\val{dqb\_valid}, il cui scopo è quello di indicare quali sono gli altri campi +che devono essere considerati validi. Questo campo è una maschera binaria che +deve essere espressa nei termini di OR aritmetico delle apposite costanti di +tab.~\ref{tab:quotactl_qif_const}, dove si è riportato il significato di +ciascuna di esse ed i campi a cui fanno riferimento. + +\begin{table}[!htb] + \centering + \footnotesize + \begin{tabular}{|l|p{10cm}|} + \hline + \textbf{Costante} & \textbf{Descrizione} \\ + \hline + \hline + \constd{QIF\_BLIMITS}& Limiti sui blocchi di spazio disco + (\val{dqb\_bhardlimit} e \val{dqb\_bsoftlimit}).\\ + \constd{QIF\_SPACE} & Uso corrente dello spazio disco + (\val{dqb\_curspace}).\\ + \constd{QIF\_ILIMITS}& Limiti sugli \textit{inode} + (\val{dqb\_ihardlimit} e \val{dqb\_isoftlimit}).\\ + \constd{QIF\_INODES} & Uso corrente degli \textit{inode} + (\val{dqb\_curinodes}).\\ + \constd{QIF\_BTIME} & Tempo di sforamento del \textit{soft limit} sul + numero di blocchi (\val{dqb\_btime}).\\ + \constd{QIF\_ITIME} & Tempo di sforamento del \textit{soft limit} sul + numero di \textit{inode} (\val{dqb\_itime}).\\ + \constd{QIF\_LIMITS} & L'insieme di \const{QIF\_BLIMITS} e + \const{QIF\_ILIMITS}.\\ + \constd{QIF\_USAGE} & L'insieme di \const{QIF\_SPACE} e + \const{QIF\_INODES}.\\ + \constd{QIF\_TIMES} & L'insieme di \const{QIF\_BTIME} e + \const{QIF\_ITIME}.\\ + \constd{QIF\_ALL} & Tutti i precedenti.\\ + \hline + \end{tabular} + \caption{Costanti per il campo \val{dqb\_valid} di \struct{dqblk}.} + \label{tab:quotactl_qif_const} +\end{table} + +In lettura con \const{Q\_SETQUOTA} eventuali valori presenti in \struct{dqblk} +vengono comunque ignorati, al momento la funzione sovrascrive tutti i campi +che restituisce e li marca come validi in \val{dqb\_valid}. Si possono invece +usare \const{QIF\_BLIMITS} o \const{QIF\_ILIMITS} per richiedere di impostare +solo la rispettiva tipologia di limiti con \const{Q\_SETQUOTA}. Si tenga +presente che il sistema delle quote richiede che l'occupazione di spazio disco +sia indicata in termini di blocchi e non di byte, dato che la dimensione dei +blocchi dipende da come si è creato il filesystem potrà essere necessario +effettuare qualche conversione per avere un valore in byte.\footnote{in genere + viene usato un default di 1024 byte per blocco, ma quando si hanno file di + dimensioni medie maggiori può convenire usare valori più alti per ottenere + prestazioni migliori in conseguenza di un minore frazionamento dei dati e di + indici più corti.} + +Come accennato realizzazione delle quote disco ha visto diverse revisioni, con +modifiche sia del formato delle stesse che dei nomi dei file utilizzate. Per +questo alcune operazioni di gestione (in particolare \const{Q\_QUOTAON} e +\const{Q\_GETFMT}) e possono fare riferimento a queste versioni, che vengono +identificate tramite le costanti di tab.~\ref{tab:quotactl_id_format}. + +\begin{table}[htb] + \centering + \footnotesize + \begin{tabular}{|l|p{10cm}|} + \hline + \textbf{Identificatore} & \textbf{Descrizione} \\ + \hline + \hline + \constd{QFMT\_VFS\_OLD}& Il vecchio (ed obsoleto) formato delle quote.\\ + \constd{QFMT\_VFS\_V0} & La versione 0 usata dal VFS di Linux, supporta + \ids{UID} e \ids{GID} a 32 bit e limiti fino a + $2^{42}$ byte e $2^{32}$ file.\\ + \constd{QFMT\_VFS\_V1} & La versione 1 usata dal VFS di Linux, supporta + \ids{UID} e \ids{GID} a 32 bit e limiti fino a + $2^{64}$ byte e $2^{64}$ file.\\ + \hline + \end{tabular} + \caption{Valori di identificazione del formato delle quote.} + \label{tab:quotactl_id_format} +\end{table} + +Altre due operazioni che necessitano di ulteriori spiegazioni sono +\const{Q\_GETINFO} e \const{Q\_SETINFO}, che consentono di ottenere i dati +relativi alle impostazioni delle altre proprietà delle quote, che al momento +sono solo la durata del \textit{grace time} per i due tipi di limiti. Queste +sono due proprietà generali identiche per tutti gli utenti (e i gruppi), per +cui viene usata una operazione distinta dalle precedenti. Anche in questo caso +le due operazioni richiedono l'uso di una apposita struttura \struct{dqinfo}, +la cui definizione è riportata in fig.~\ref{fig:dqinfo_struct}. + +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{0.8\textwidth} + \includestruct{listati/dqinfo.h} + \end{minipage} + \normalsize + \caption{La struttura \structd{dqinfo} per i dati delle quote disco.} + \label{fig:dqinfo_struct} +\end{figure} + +Come per \struct{dqblk} anche in questo caso viene usato un campo della +struttura, \val{dqi\_valid} come maschera binaria per dichiarare quale degli +altri campi sono validi; le costanti usate per comporre questo valore sono +riportate in tab.~\ref{tab:quotactl_iif_const} dove si è riportato il +significato di ciascuna di esse ed i campi a cui fanno riferimento. + +\begin{table}[htb] + \centering + \footnotesize + \begin{tabular}{|l|l|} + \hline + \textbf{Costante} & \textbf{Descrizione} \\ + \hline + \hline + \constd{IIF\_BGRACE}& Il \textit{grace period} per i blocchi + (\val{dqi\_bgrace}).\\ + \constd{IIF\_IGRACE}& Il \textit{grace period} per gli \textit{inode} + (\val{dqi\_igrace}).\\ + \constd{IIF\_FLAGS} & I flag delle quote (\val{dqi\_flags}) (inusato ?).\\ + \constd{IIF\_ALL} & Tutti i precedenti.\\ + \hline + \end{tabular} + \caption{Costanti per il campo \val{dqi\_valid} di \struct{dqinfo}.} + \label{tab:quotactl_iif_const} +\end{table} + +Come in precedenza con \const{Q\_GETINFO} tutti i valori vengono letti +sovrascrivendo il contenuto di \struct{dqinfo} e marcati come validi in +\val{dqi\_valid}. In scrittura con \const{Q\_SETINFO} si può scegliere quali +impostare, si tenga presente che i tempi dei campi \val{dqi\_bgrace} e +\val{dqi\_igrace} devono essere specificati in secondi. + +Come esempi dell'uso di \func{quotactl} utilizzeremo estratti del codice di un +modulo Python usato per fornire una interfaccia diretta a \func{quotactl} +senza dover passare dalla scansione dei risultati di un comando. Il modulo si +trova fra i pacchetti Debian messi a disposizione da Truelite Srl, +all'indirizzo \url{http://labs.truelite.it/projects/packages}.\footnote{in + particolare il codice C del modulo è nel file \texttt{quotamodule.c} + visionabile a partire dall'indirizzo indicato nella sezione + \textit{Repository}.} + +\begin{figure}[!htbp] + \footnotesize \centering + \begin{minipage}[c]{\codesamplewidth} + \includecodesample{listati/get_quota.c} + \end{minipage} + \caption{Esempio di codice per ottenere i dati delle quote.} + \label{fig:get_quota} +\end{figure} + +Il primo esempio, riportato in fig.~\ref{fig:get_quota}, riporta il codice +della funzione che consente di leggere le quote. La funzione fa uso +dell'interfaccia dal C verso Python, che definisce i vari simboli \texttt{Py*} +(tipi di dato e funzioni). Non staremo ad approfondire i dettagli di questa +interfaccia, per la quale esistono numerose trattazioni dettagliate, ci +interessa solo esaminare l'uso di \func{quotactl}. + +In questo caso la funzione prende come argomenti (\texttt{\small 1}) l'intero +\texttt{who} che indica se si vuole operare sulle quote utente o gruppo, +l'identificatore \texttt{id} dell'utente o del gruppo scelto, ed il nome del +file di dispositivo del filesystem su cui si sono attivate le +quote.\footnote{questi vengono passati come argomenti dalle funzioni mappate + come interfaccia pubblica del modulo (una per gruppi ed una per gli utenti) + che si incaricano di decodificare i dati passati da una chiamata nel codice + Python.} Questi argomenti vengono passati direttamente alla chiamata a +\func{quotactl} (\texttt{\small 5}), a parte \texttt{who} che viene abbinato +con \macro{QCMD} al comando \const{Q\_GETQUOTA} per ottenere i dati. + +La funzione viene eseguita all'interno di un condizionale (\texttt{\small + 5-16}) che in caso di successo provvede a costruire (\texttt{\small 6-12}) +opportunamente una risposta restituendo tramite la opportuna funzione di +interfaccia un oggetto Python contenente i dati della struttura \struct{dqblk} +relativi a uso corrente e limiti sia per i blocchi che per gli +\textit{inode}. In caso di errore (\texttt{\small 13-15}) si usa un'altra +funzione dell'interfaccia per passare il valore di \var{errno} come eccezione. + +\begin{figure}[!htbp] + \footnotesize \centering + \begin{minipage}[c]{\codesamplewidth} + \includecodesample{listati/set_block_quota.c} + \end{minipage} + \caption{Esempio di codice per impostare i limiti sullo spazio disco.} + \label{fig:set_block_quota} +\end{figure} + +Per impostare i limiti sullo spazio disco si potrà usare una seconda funzione, +riportata in fig.~\ref{fig:set_block_quota}, che prende gli stessi argomenti +della precedente, con lo stesso significato, a cui si aggiungono i valori per +il \textit{soft limit} e l'\textit{hard limit}. In questo caso occorrerà, +prima di chiamare \func{quotactl}, inizializzare opportunamente +(\texttt{\small 5-7}) i campi della struttura \struct{dqblk} che si vogliono +utilizzare (quelli relativi ai limiti sui blocchi) e specificare gli stessi +con \const{QIF\_BLIMITS} in \var{dq.dqb\_valid}. + +Fatto questo la chiamata a \func{quotactl}, stavolta con il comando +\const{Q\_SETQUOTA}, viene eseguita come in precedenza all'interno di un +condizionale (\texttt{\small 9-14}). In questo caso non essendovi da +restituire nessun dato in caso di successo si usa (\texttt{\small 10}) una +apposita funzione di uscita, mentre si restituisce come prima una eccezione +con il valore di \var{errno} in caso di errore (\texttt{\small 12-13}). + +\subsection{La gestione dei {chroot}} +\label{sec:file_chroot} + +% TODO: valutare se introdurre una nuova sezione sulle funzionalità di +% sicurezza avanzate, con dentro chroot SELinux e AppArmor, Tomoyo, Smack, +% cgroup o altro + +% TODO: spostare chroot e le funzioni affini relative ai container da qualche +% parte diversa se è il caso. + +% TODO Inheriting capabilities vedi http://lwn.net/Articles/632520/ eambient +% capabilities introdotte con il kernel 4.3, vedi +% http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=58319057b7847667f0c9585b9de0e8932b0fdb08 + +Benché non abbia niente a che fare con permessi, utenti e gruppi, la funzione +\func{chroot} viene usata spesso per restringere le capacità di accesso di un +programma ad una sezione limitata del filesystem, per cui ne parleremo in +questa sezione. + +Come accennato in sez.~\ref{sec:proc_fork} ogni processo oltre ad una +directory di lavoro, ha anche una directory \textsl{radice}\footnote{entrambe + sono contenute in due campi (rispettivamente \var{pwd} e \var{root}) di + \kstruct{fs\_struct}; vedi fig.~\ref{fig:proc_task_struct}.} che, pur +essendo di norma corrispondente alla radice dell'albero dei file dell'intero +sistema, ha per il processo il significato specifico di directory rispetto +alla quale vengono risolti i \textit{pathname} assoluti.\footnote{cioè quando + un processo chiede la risoluzione di un \textit{pathname}, il kernel usa + sempre questa directory come punto di partenza.} Il fatto che questo valore +sia specificato per ogni processo apre allora la possibilità di modificare le +modalità di risoluzione dei \textit{pathname} assoluti da parte di un processo +cambiando questa directory, così come si fa coi \textit{pathname} relativi +cambiando la directory di lavoro. + +Normalmente la directory radice di un processo coincide con la radice generica +dell'albero dei file, che è la directory che viene montata direttamente dal +kernel all'avvio secondo quanto illustrato in sez.~\ref{sec:file_pathname}. +Questo avviene perché, come visto in sez.~\ref{cha:process_handling} la +directory radice di un processo viene ereditata dal padre attraverso una +\func{fork} e mantenuta attraverso una \func{exec}, e siccome tutti i processi +derivano da \cmd{init}, che ha come radice quella montata dal kernel, questa +verrà mantenuta. + +In certe situazioni però è utile poter impedire che un processo possa accedere +a tutto l'albero dei file iniziale; per far questo si può cambiare la sua +directory radice con la funzione di sistema \funcd{chroot}, il cui prototipo +è: + +\begin{funcproto}{ +\fhead{unistd.h} +\fdecl{int chroot(const char *path)} +\fdesc{Cambia la directory radice del processo.} +} + +{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{EPERM}] non si hanno i privilegi di amministratore. + \end{errlist} + ed inoltre \errval{EFAULT}, \errval{ENAMETOOLONG}, \errval{ENOENT}, + \errval{ENOMEM}, \errval{ENOTDIR}, \errval{EACCES}, \errval{ELOOP}; + \errval{EROFS} e \errval{EIO} nel loro significato generico.} +\end{funcproto} + +La funzione imposta la directory radice del processo a quella specificata da +\param{path} (che ovviamente deve esistere) ed ogni \textit{pathname} assoluto +usato dalle funzioni chiamate nel processo sarà risolto a partire da essa, +rendendo impossibile accedere alla parte di albero sovrastante. Si ha così +quella che viene chiamata una \textit{chroot jail}, in quanto il processo non +può più accedere a file al di fuori della sezione di albero in cui è stato +\textsl{imprigionato}. -\subsection{Le funzioni \texttt{chmod} e \texttt{fchmod}} -\label{sec:filedir_chmod} +Solo un processo con i privilegi di amministratore può usare questa +funzione,\footnote{più precisamente se possiede la capacità + \const{CAP\_SYS\_CHROOT}.} e la nuova radice, per quanto detto in +sez.~\ref{sec:proc_fork}, sarà ereditata da tutti i suoi processi figli. Si +tenga presente però che la funzione non cambia la directory di lavoro del +processo, che potrebbe restare fuori dalla \textit{chroot jail}. -\subsection{Il flag \texttt{stiky}} -\label{sec:filedir_stiky} +Questo è il motivo per cui la funzione è efficace nel restringere un processo +ad un ramo di albero solo se dopo averla eseguita si cedono i privilegi di +amministratore. Infatti se per un qualunque motivo il processo resta con la +sua directory di lavoro al di fuori dalla \textit{chroot jail}, potrà accedere +a tutto il resto del filesystem usando dei \textit{pathname} relativi, dato +che in tal caso è possibile, grazie all'uso di ``\texttt{..}'', risalire +all'indietro fino alla radice effettiva dell'albero dei file. -\subsection{Le funzioni \texttt{chown}, \texttt{fchown} e \texttt{lchown}} -\label{sec:filedir_chown} +Potrebbe sembrare che per risolvere il problema sia sufficiente ricordarsi di +eseguire preventivamente anche una \func{chdir} sulla directory su cui si +andrà ad eseguire \func{chroot}, così da assicurarsi che le directory di +lavoro sia all'interno della \textit{chroot jail}. Ma se ad un processo +restano i privilegi di amministratore esso potrà comunque portare la sua +directory di lavoro fuori dalla \textit{chroot jail} in cui si trova. Basterà +infatti eseguire di nuovo \func{chroot} su una qualunque directory contenuta +nell'attuale directory di lavoro perché quest'ultima risulti al di fuori della +nuova \textit{chroot jail}. Per questo motivo l'uso di questa funzione non ha +molto senso quando un processo di cui si vuole limitare l'accesso necessita +comunque dei privilegi di amministratore per le sue normali operazioni. +Nonostante queste limitazioni la funzione risulta utile qualora la si possa +applicare correttamente cedendo completamente i privilegi di amministratore +una volta eseguita. Ed esempio caso tipico di uso di \func{chroot} è quello +di un server FTP anonimo in si vuole che il server veda solo i file che deve +trasferire. In tal caso si esegue una \func{chroot} sulla directory che +contiene i file, che il server dovrà in grado di leggere come utente +ordinario, e poi si cedono tutti i privilegi di amministratore. Si tenga +presente però che in casi come questo occorrerà fornire all'interno della +\textit{chroot jail} un accesso anche a tutti i file (in genere programmi e +librerie) di cui il server potrebbe avere bisogno. -%La struttura fondamentale che contiene i dati essenziali relativi ai file è il -%cosiddetto \textit{inode}; questo conterrà informazioni come il -%tipo di file (file di dispositivo, directory, file di dati, per un elenco -%completo vedi \ntab), i permessi (vedi \secref{sec:file_perms}), le date (vedi -%\secref{sec:file_times}). +% LocalWords: sez like filesystem unlink MacOS Windows VMS inode kernel unistd +% LocalWords: int const char oldpath newpath errno EXDEV EPERM st Smack SysV +% LocalWords: EEXIST EMLINK EACCES ENAMETOOLONG ENOTDIR EFAULT ENOMEM EROFS ls +% LocalWords: ELOOP ENOSPC EIO pathname nlink stat vfat fsck EISDIR ENOENT cap +% LocalWords: POSIX socket fifo sticky root system call count crash init linux +% LocalWords: descriptor remove rename rmdir stdio glibc libc NFS DT obj dup +% LocalWords: ENOTEMPTY EBUSY mount point EINVAL soft symbolic tab symlink fig +% LocalWords: dangling access chdir chmod chown creat exec lchown lstat mkdir +% LocalWords: mkfifo mknod opendir pathconf readlink truncate path buff size +% LocalWords: grub bootloader grep MAXSYMLINKS cat VFS sys dirname fcntl tv Py +% LocalWords: dev umask IFREG IFBLK IFCHR IFIFO SVr sgid BSD SVID NULL from to +% LocalWords: stream dirent EMFILE ENFILE dirfd SOURCE fchdir readdir struct +% LocalWords: EBADF namlen HAVE thread entry result value argument fileno ext +% LocalWords: name TYPE OFF RECLEN UNKNOWN REG SOCK CHR BLK type IFTODT DTTOIF +% LocalWords: DTYPE off reclen seekdir telldir void rewinddir closedir select +% LocalWords: namelist compar malloc qsort alphasort versionsort strcoll myls +% LocalWords: strcmp direntry while current working home shell pwd get stddef +% LocalWords: getcwd ERANGE getwd change fd race condition tmpnam getfacl mark +% LocalWords: string tmpdir TMP tempnam pfx TMPNAME suid tmp EXCL tmpfile pid +% LocalWords: EINTR mktemp mkstemp stlib template filename XXXXXX OpenBSD buf +% LocalWords: mkdtemp fstat filedes nell'header padding ISREG ISDIR ISCHR IFMT +% LocalWords: ISBLK ISFIFO ISLNK ISSOCK IFSOCK IFLNK IFDIR ISUID UID ISGID GID +% LocalWords: ISVTX IRUSR IWUSR IXUSR IRGRP IWGRP IXGRP IROTH IWOTH IXOTH OLD +% LocalWords: blocks blksize holes lseek TRUNC ftruncate ETXTBSY length QCMD +% LocalWords: hole atime read utime mtime write ctime modification leafnode cp +% LocalWords: make fchmod fchown utimbuf times actime modtime Mac owner uid fs +% LocalWords: gid Control List patch mandatory control execute group other all +% LocalWords: effective passwd IGID locking swap saved text IRWXU IRWXG subcmd +% LocalWords: IRWXO capability FSETID mask capabilities chroot jail QUOTAOFF +% LocalWords: FTP filter Attributes Solaris FreeBSD libacl hash at dqblk SYNC +% LocalWords: XFS SELinux namespace attribute security trusted Draft Modules +% LocalWords: attributes mime ADMIN FOWNER libattr lattr getxattr lgetxattr of +% LocalWords: fgetxattr attr ssize ENOATTR ENOTSUP NUL setxattr lsetxattr list +% LocalWords: fsetxattr flags XATTR REPLACE listxattr llistxattr flistxattr by +% LocalWords: removexattr lremovexattr fremovexattr attributename acl GETINFO +% LocalWords: OBJ setfacl len any prefix separator options NUMERIC IDS SMART +% LocalWords: INDENT major number IDE Documentation makedev proc copy LNK long +% LocalWords: euidaccess eaccess delete def tag qualifier permset calendar NOW +% LocalWords: mutt noatime relatime strictatime atim nsec mtim ctim atimensec +% LocalWords: mtimensec utimes timeval futimes lutimes ENOSYS futimens OMIT PR +% LocalWords: utimensat timespec sec futimesat LIDS DAC OVERRIDE SEARCH chattr +% LocalWords: Discrectionary KILL SETGID domain SETUID setuid setreuid SETPCAP +% LocalWords: setresuid setfsuid IMMUTABLE immutable append only BIND SERVICE +% LocalWords: BROADCAST broadcast multicast multicasting RAW PACKET IPC LOCK +% LocalWords: memory mlock mlockall shmctl mmap MODULE RAWIO ioperm iopl PACCT +% LocalWords: ptrace accounting NICE RESOURCE TTY CONFIG hangup vhangup dell' +% LocalWords: LEASE lease SETFCAP AUDIT permitted inherited inheritable AND nn +% LocalWords: bounding execve fork capget capset header hdrp datap ESRCH undef +% LocalWords: version libcap lcap clear ncap caps pag capgetp CapInh CapPrm RT +% LocalWords: fffffeff CapEff getcap scheduling lookup dqinfo SETINFO GETFMT +% LocalWords: NEWNS unshare nice NUMA ioctl journaling close XOPEN fdopendir +% LocalWords: btrfs mkostemp extN ReiserFS JFS Posix usrquota grpquota EDQUOT +% LocalWords: aquota quotacheck limit grace period quotactl cmd caddr addr dqb +% LocalWords: QUOTAON ENODEV ENOPKG ENOTBLK GETQUOTA SETQUOTA SETUSE SETQLIM +% LocalWords: forced allowed sendmail SYSLOG WAKE ALARM CLOCK BOOTTIME dqstats +% LocalWords: REALTIME securebits GETSTATS QFMT curspace curinodes btime itime +% LocalWords: QIF BLIMITS bhardlimit bsoftlimit ILIMITS ihardlimit isoftlimit +% LocalWords: INODES LIMITS USAGE valid dqi IIF BGRACE bgrace IGRACE igrace is +% LocalWords: Python Truelite Srl quotamodule Repository who nell' dall' KEEP +% LocalWords: SECURE KEEPCAPS prctl FIXUP NOROOT LOCKED dell'IPC dell'I IOPRIO +% LocalWords: CAPBSET CLASS IDLE dcookie overflow DIFFERS Virtual everything +% LocalWords: dentry register resolution cache dcache operation llseek poll ln +% LocalWords: multiplexing fsync fasync seek block superblock gapil tex img du +% LocalWords: second linked journaled source filesystemtype unsigned device +% LocalWords: mountflags NODEV ENXIO dummy devfs magic MGC RDONLY NOSUID MOVE +% LocalWords: NOEXEC SYNCHRONOUS REMOUNT MANDLOCK NODIRATIME umount MNT statfs +% LocalWords: fstatfs fstab mntent ino bound orig new setpcap metadati sysfs +% LocalWords: bind DIRSYNC lsattr Hierarchy FHS SHARED UNBINDABLE shared REC +% LocalWords: subtree SILENT log unbindable BUSY EAGAIN EXPIRE DETACH NOFOLLOW +% LocalWords: lazy encfs sshfs setfsent getfsent getfsfile getfsspec endfsent +% LocalWords: setmntent getmntent addmntent endmntent hasmntopt such offsetof +% LocalWords: member scan attack EOVERFLOW BITS blkcnt rdev FDCWD functions +% LocalWords: faccessat grpid lacl AppArmor capsetp mygetfacl table Tb MSK +% LocalWords: LAZYTIME submount peer protected hardlink symlinks silly +%%% Local Variables: +%%% mode: latex +%%% TeX-master: "gapil" +%%% End: +% LocalWords: renames