Les liens dans les systèmes *nix
Le 3 December 2007 à 10:26.

Le concept de lien est présent sur beaucoup d'OS mais sous *nix (et donc linux) c'est une religion. Les liens sont partout et il suffit de taper un ls -la /etc pour s'en convaincre. Ce petit tutorial a donc pour objectif d'expliquer un peu les différents liens et leur utilisation possible.

Le lien symbolique

Clairement le plus utilisé, il est possible, de loin, de comparer le lien symbolique au .lnk sous Windows, mais de très loin alors...

Le lien symbolique est un "faux fichier" ou un "faux dossier" qui contient le chemin d'un "vrai fichier" ou d'un "vrai dossier". Une fois un lien symbolique établi, pour la majorité des applications, le fichier ou dossier cible est bien réel. Et lorsqu'on supprime un lien symbolique, le fichier ou dossier d'origine n'en est en rien modifié. Dans l'autre sens, si l'on détruit le fichier/dossier source d'un lien symbolique, celui-ci ne disparaît pas pour autant, et lors d'un ls, il va apparaître clignotant et en erreur, ce sera un lien "cassé".

Une utilisation naturelle du lien symbolique est de "bouturer" un dossier/fichier venant d'un bout de l'arborescence du système de fichier vers un autre dossier, mais en le laissant "physiquement" là où il est.

La syntaxe du lien symbolique est ln -s source [cible]. Si la "cible" est omise, c'est le dernier élément du chemin de "source" qui est utilisé, dans le dossier courant. Par exemple :

gaston$# Lien d'un dossier vers un autre
gaston$ln -s /home/mon_dossier /home/worspace/mon_dossier
 
gaston$# Sans différence, lien d'un fichier vers un autre fichier
gaston$ln -s /home/fichier.txt /home/worspace/fichier.txt
 
gaston$# Les mêmes syntaxe en omettant le chemin cible
gaston$cd /home/workspace
gaston$ln -s /home/mon_dossier
gaston$ln -s /home/fichier.txt
 
gaston$# Voir le résultat des liens effectués
gaston$ls -la
fichier.txt -> /home/fichier.txt
mon_dossier -> /home/mon_dossier
 
gaston$# la même chose avec la commande stat
gaston$stat /etc/alternatives/gcc
File: `/etc/alternatives/gcc' -> `/usr/bin/gcc-4.2.2'
Size: 18 Blocks: 0 IO Block: 4096 lien symbolique
...
gaston$ 

Dans un script, il peut être important d'avoir le chemin réel d'un lien symbolique, c'est le rôle de la commande readlink. Le script suivant permet donc de tester si le paramétre est un lien symbolique et de le résoudre si c'est le cas pour renvoyer le véritable chemin :

#! /bin/sh
file=$1
while [ -L $file ] ; do
  file=$(readlink $file)
done
echo $file

L'autre utilisation classique des liens consiste à s'en servir pour choisir une version de logiciel. Par exemple si l'on a plusieurs version de mon_utilitaire (1.0, 2.0, etc...), si chacune, dans le dossier /usr/bin est nommée avec sa version comme suffixe (mon_utilitaire-1.0, mon_utilitaire-2.0, etc.), il suffit de faire un lien sur la bonne version au grès des besoins :

gaston$# lien sur la version 1.0
gaston$ln -s /usr/bin/mon_utilitaire_1.0 /usr/bin/mon_utilitaire
 
gaston$# Utilisation de mon utilitaire, en version 1.0
gaston$mon_utilitaire
 
gaston$# changement de version
gaston$rm -f /usr/bin/mon_utilitaire
gaston$ln -s /usr/bin/mon_utilitaire_2.0 /usr/bin/mon_utilitaire
 
gaston$# Utilisation de mon utilitaire, en version 2.0
gaston$mon_utilitaire
gaston$ 

Cette aspect est déjà implémenté dans beaucoup de distribution pour choisir ce que l'on appelle les "alternatives", c'est à dire la bonne version de gcc, de vi, de smb, etc... Sur la Mandriva, la liste des alternatives est disponible dans le dossier /etc/alternatives et la commande update-alternatives permet de gérer les liens symboliques pour vous :

gaston$ls -la /etc/alternatives
...
gcc -> gcc -> /usr/bin/gcc-4.2.2
...
 
gaston$update-alternatives --list gcc
/usr/bin/gcc-4.2.2
/usr/bin/gcc-3.3.6
 
gaston$update-alternatives --config gcc
There are 2 programs which provide `gcc'.
Selection Command
-----------------------------------------------
*+ 1 /usr/bin/gcc-4.2.2
2 /usr/bin/gcc-3.3.6
Enter to keep the default[*], or type selection number:
gaston$ 

Dernier aspect du lien symbolique, il peut relier des systèmes de fichiers différents. C'est à dire que l'on peut faire un lien symbolique entre n'importe lesquelles des dossiers/fichiers sans se préoccuper du type de montage du dossier parent (clef usb, cd-rom, nfs, etc..).

Maintenant, l'inconvénient des liens symboliques reste leur relative lenteur. En effet, à chaque entrée dans un dossier lié, le fichier du lien symbolique va devoir être lu par le système, interprété, puis celui ci va devoir le fermer pour aller ouvrir le "vrai" fichier ou dossier. Il n'est donc pas très conseillé sur un serveur web par exemple où un dossier va être accédé des centaines de fois par minutes. Un aspect réglé par un autre type de lien, le hard-link.

Le lien "hard"

Si le lien symbolique est géré par le système d'exploitation et ne dépend donc pas du système de fichier utilisé, Le lien "hard" quant à lui est directement géré par un système de fichier. Cela veut déjà dire qu'il ne fonctionnera donc pas pour tous les systèmes de fichier. Un volume monté en FAT par exemple ne passera pas, mais tous les FS sérieux disposent du hard-link (ext3, reiser, xfs, etc..).

Pour bien saisir ce que sont les hard-links, il faut comprendre que, pour les systèmes de fichiers qui le supportent, tous les fichiers/dossiers sont des liens hard. En effet, il faut ici distinguer deux notions : le nom du fichier (avec son nom, son chemin, etc.) et le bloc de données (un paquet de 0 et de 1 localisé à une position N du disque dur). Lorsque l'on crée un fichier, le système va d'abord allouer un bloc de donnée sur le disque dur, puis faire un hard-link entre ce bloc de donnée et le nom de fichier.

Ainsi, si vous avez un fichier qui s'appelle toto.txt dans le dossier /mes_dossiers, le nom de fichier /mes_donnees/toto.txt est en réalité un hard-link entre d'un côté le bloc de données du fichier toto.txt (les 0 et les 1) et le nom de fichier que vous lui avez donné (comprenant son chemin). Il y a donc toujours au moins 1 hard-link entre toto.txt et les données qu'il représente. Ainsi, faire un hard-link sur toto.txt, consiste en réalité à en créer un deuxième...

Cette caractéristique octroie une propriété très utile au hard-link : le bloc de données d'un fichier continue à exister (n'est pas détruit) tant qu'au moins un hard-link pointe dessus. Ainsi si j'ai, pour reprendre l'exemple précédent, mon bloc de donnée pointé par /mes_donnees/toto.txt et /autre_chemin/tutu.txt. Si je détruit toto.txt, le bloc de donnée n'est pas détruit et pour le système, c'est comme s'il s'était toujours appelé tutu.txt et qu'il a toujours été dans le dossier /autre_chemin. En revanche, si je détruit tutu.txt, le bloc de donnée est perdu, le fichier est physiquement détruit...

En conséquence, contrairement aux liens symboliques, les hard-links ne peuvent pas être réalisés entre deux fichiers systèmes de fichiers différents, et à fortiori, entre deux volumes d'origine différente (usb, cd-rom, etc.). Autre conséquence, nous ne pouvons créer un hard-link qu'en deux systèmes de fichiers.

La commande pour créer un hard-link est ln, la même donc que pour un lien symbolique mais sans l'argument -s. Le code suivant reprends le brillant exemple de toto et tutu sur mon disque :

gaston$# création du fichier toto
gaston$mkdir ~/mes_données
gaston$echo "Ces données sont celle de toto.. à l'origine ;-)" > ~/mes_données/toto.txt
 
gaston$# Regardez la deuxième colonne du résultat, le 1 signifie que l'on a 1 hard-link sur
gaston$# le bloc de données toto.txt
gaston$ls -l ~/mes_données
 
gaston$# Création du hard-link
gaston$mkdir ~/autre_chemin
gaston$ln ~/mes_données/toto.txt ~/autre_chemin/tutu.txt
 
gaston$# En exécutant cette commande, la deuxième colonne du résultat du ls donne 2, on a donc
gaston$# bien maintenant 2 hard-links sur le bloc de données (toto.txt et tutu.txt) !!
gaston$ls -l ~/mes_données
 
gaston$# En exécutant cette commande, la deuxième colonne du résultat du ls donne 2, on a donc
gaston$# bien maintenant 2 hard-links sur le bloc de données (toto.txt et tutu.txt) !!
gaston$ls -l ~/mes_données
 
gaston$# Destruction du premier fichier, et donc du premier hard-link
gaston$rm -f ~/mes_donnes/toto.txt
 
gaston$# On vérifie que l'on a bien le contenu de toto.txt "transféré" sur tutu.txt
gaston$cat ~/autre_chemin/tutu.txt
gaston$ 

Une application du hard-link, l'historisation du pauvre

Une application du hard-link est donc l'historisation. Imaginons que l'on veuille faire la copie de sauvegarde d'un grand de fichiers. Et imaginons aussi que l'on veuille historiser cette sauvegarde sur 10 jours, c'est à dire disposer en permanence 10 dossiers contenant la même copie de ces fichiers, mais représentant chacune l'état du dossier à sauvegarder pour chacun des 10 derniers jours passés. Alors Comment faire ?

Tout d'abord, nous allons créer 10 dossiers nommés jour.J,jour.J-1,jour.J-2, ..., jour.J-9, représentant le backup du jour pour jour.J à celui d'il y a 9 jours avec jour.J-9

gaston$mkdir ~/historisation
gaston$cd ~/historisation
gaston$mkdir jour.J
gaston$mkdir jour.J-1
...
gaston$mkdir jour.J-9
gaston$ 

Ensuite, il va falloir copier les fichiers à sauvegarder dans le dossier jour.J :

rsync -a --delete /chemin/vers/mes_donnees_importantes jour.J

Le -a voulant dire tout-récursivement et le --delete pour supprimer les fichiers cibles qui ne sont plus dans source). C'est tout pour aujourd'hui, la suite s'effectue le lendemain matin.

Le lendemain donc, nous allons faire descendre tous nos dossiers d'un cran. Tout d'abord nous allons commencer par détruire le dossier jour-J-9 (notre historisation ne portant que sur 10 jours). Puis, nous allons renommer le dossier jour.J en jour.J-1, jour.J-1 en jour.J-2, etc jusqu'à jour-J-8 en jour-J-9. Ensuite nous allons recréer un nouveau dossier jour.J.

gaston$# On détruit le 9° jour
gaston$rm -rf jour-J-9
 
gaston$# renommage des dossiers précédent
gaston$for jour in $(seq 8 -1 1) ; do
gaston$let jour_avant=${jour}+1;
gaston$echo mv jour-J-$jour jour-J-$jour_avant
gaston$done
 
gaston$# création de l'espace pour la nouvelle sauvegarde
gaston$mkdir jour-J
gaston$ 

Ensuite, et c'est là que la magie commence, nous allons, pour chaque fichier du dossier jour.J-1, faire un hard-link dans le dossier jour.J. Pour cela nous utilisons la simple commande cp

gaston$cp -lr jour.J-1/* jour.J/
gaston$ 

Le paramètre -r indique à cp que la copie recursive. -l indique quant à lui que cp ne doit pas copier mais fait des hard-link à la place.

Ceci fait, il suffit de refaire l'opération du jour précédente, à savoir notre rsync

gaston$rsync -a --delete /chemin/vers/mes_donnees_importantes jour.J
gaston$ 

Alors que se passe t-il exactement lors du rsync ? Au moment de faire cette 2nd sauvegarde, nous avons en fait 4 cas de figure :

  1. Les fichiers qui n'ont pas changé entre J et J-1 : Je vais donc avoir au moins 2 hard-link sur le même bloc de donnée physique.
  2. Des fichiers modifiés par rapport à hier : Je vais donc avoir un hard-link sur le nouveau fichier dans le dossier Jour.J et un autre sur l'ancien dans Jour.J-1
  3. Des fichiers détruits (option --delete de rsync) : Le bloc de donnée existe encore grâce à leur hard-link conservé dans jour.J-1 mais n'existe plus dans Jour.J.
  4. Des nouveaux fichiers : ils ne sont en hard-link QUE dans Jour.J.

Ainsi nous avons déjà l'historique sur 2 jours sans prendre plus d'espace disque que la différence de volume entre ces deux jours.

Le 3ième jour nous recommençons à l'étape du renommage des jour.J-1 à jour.J-9, à nouveau le rsync, et ainsi de suite... jusqu'au 9ieme jour.

Arrivé au 9ieme jour, tous nos dossiers sont plein, nous avons une historisation sur 10 jours et lors de la quotidienne séance de renommage, le dossier jour-9 est supprimé. Du coup tous les fichiers qu'il contient vont voir leur compteur de hard-link décrémenté de 1. Pour ceux qui atteignent 0, c'est la fin, ils disparaissent, mais pour tous les autres, ils continuent de vivre, soit dans le dossier d'origine, soit dans une des 9 sauvegarde précédente.

Le binding

Comme nous l'avons vu, le hard-link souffre de deux contraintes. On ne peut hard-linker QUE des fichiers et toujours de la même partition. C'est à cela que sert le binding. Cette technique sort un peu du cadre du lien (elle n'est pas gérée par la commande ln mais permet de lier n'importe quel objet sur n'importe quel système de fichier. Cette fonction est assurée par la commande mount :

root#mount --bind dossier_source dossier_cible
root# 

L'avantage par rapport aux liens symboliques (qui fonctionellement répondent au même besoin), c'est qu'il trompe totalement les applications. Autant une application peut vérifier que le dossier est un lien symbolique et préférer aller sur le vrai dossier (ce que l'on ne veut pas), autant avec un binding elle n'y voit que du feu. Une application pratique de cette technique est de créer rapidement un sous-linux en vue d'un chrootage par exemple. En effet, si l'on cré un dossier mon_linux dans lequel on bind chaque dossier du linux hôte (/bin, /dev, /lib, /usr, etc...) et que l'on tapes chroot mon_linux, on est dans un sous linux complétement autonome. Le binding, lien de bas niveau par excellence, est en général à utiliser lorsque le lien symbolique est "trop léger" pour être utilisé et le hard-link par trop "définitif".

Enfin, comme tous les montages, le bind peut être effectué de manière automatique en l'inscrivant dans le fichier /etc/fstab /mon/dossier/source /mon/dossier/cible none bind

Conclusion

Les liens sont sans aucun doute très important sous tous les systèmes *nix, ils permettent rapidement d'adapter, assouplir et étendre en fonctionnalité le concept de base de ces systèmes d'exploitation, à savoir

Tout n'est que fichier sous *nix, sauf lorsque ce n'est pas le cas ;-)

Commentaires

Larry Cow, le 3 décembre, 2007 - 11:58

En effet, à chaque entrée dans un dossier lié, le fichier du lien symbolique va devoir être lu par le système, interprété, puis celui ci va devoir le fermer pour aller ouvrir le "vrai" fichier ou dossier.

Si j'ai bonne mémoire, le fichier "lien" n'est pas à proprement parler ouvert : les informations indiquant la cible sont comprises dans les données retournées par stat(). Donc ça rajoute un traitement supplémentaire, certes, mais ça n'a rien à voir avec une ouverture de fichier de plus. Ca s'apparente davantage au listage d'un fichier de plus par ls -ls.

Enfin, ce me semble.

Ulhume, le 3 décembre, 2007 - 12:14

Optimisation des performances apache
The symlink checking requires an extra filesystem lookup (via the lstat() systemcall) for each path element in the location being opened, resulting in several such lookups per request.(...)

"Ouvrir", est manière simple de dire qu'il y a un accès de plus pour le lien symbolique que pour le hardlink. Mais je ne suis pas un manitou du kernel, loin de la Wink

Mica, le 10 juillet, 2008 - 20:52

Bonjour et merci pour cette explication claire et instructive.

Je suis justement en train de développer un script de backup avec l'historisation cité en exemple.

Mais une question me taraude : pourquoi "l'historisation du pauvre" ?

Vous connaissez une meilleur pratique (en dehors des svn-like très envahissant avec leur .svn dans tous les dossiers) ?

Le but étant d'avoir à la fois un miroir de l'état actuel ainsi que l'historique des fichiers (entiers).

Merci d'avance

Ulhume, le 11 juillet, 2008 - 09:27

@Mica c'est juste de l'humour au sens où cela demande peu de moyen Smiling Techniquement cette solution est loin d'être pauvre. Ceci dit, même si les .svn sont intrusifs, cela reste peut-être une des solutions les plus riches pour historiser. Mais je ne l'utilise que pour les projets. Donc pour ton besoin, je pense que cette méthode "du pauvre" est totalement adaptée à ton besoin.

Jérôme, le 11 juillet, 2008 - 09:21

Hello,

Juste une petite coquille :

"Le paramètre -r indique à cp que la copie recursive. -r indique quant à lui que cp ne doit pas copier mais fait des hard-link à la place."

Mais rien de grave Wink! (mauvaise option)

Bonne journée,

Ulhume, le 11 juillet, 2008 - 09:29

@Jérome merci Smiling c'est corrigé.

Emmanel, le 3 novembre, 2008 - 15:29

Petite précision quant au binding : cette option nécessite une version du noyau Linux au moins égale à 2.5.1.

Poster un nouveau commentaire

Si vous avez détecté une erreur, coquille ou bêtises du même ordre, merci de plutôt passer par le formulaire de contact
Pour vous abonner au flux des commentaires sur cet article, clickez ici.
Pour répondre à quelqu'un, utilisez plutôt le lien répondre qui se trouve en haut (ou en bas) à gauche de son commentaire.
Le contenu de ce champ sera maintenu privé et ne sera pas affiché publiquement. Si vous avez un compte gravatar, l'utilisez pour afficher votre avatar.
  • To highlight piece of code, just surround them with <code type="language"> Your code &tl;/code>>. Language can be java,c++,bash,etc... Everything Geshi support.
  • Tags HTML autorisés : <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <blockquote> <div> <p> <br>
  • Les lignes et les paragraphes vont à la ligne automatiquement.
  • Textual smileys will be replaced with graphical ones.
  • Les adresses de pages web et de messagerie électronique sont transformées en liens automatiquement.
  • Every instance of custom tags in the input text will be replaced with a specific tool shortcut.

Plus d'informations sur les options de formatage


Commentaires récents
Porte secrète