Les liens dans les systèmes *nix
Le 3 décembre 2007, à 10:26 par Ulhume...

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
  • ...

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 :

  1. #! /bin/sh
  2. file=$1
  3. while [ -L $file ] ; do
  4.   file=$(readlink $file)
  5. done
  6. 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

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:

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

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

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

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/

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

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

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 Wink

Commentaires

Larry Cow , le 3 December, 2007 - 10: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 December, 2007 - 11: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 July, 2008 - 19: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

Jérôme , le 11 July, 2008 - 08: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 July, 2008 - 08: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.

Ulhume, le 11 July, 2008 - 08:29

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

Poster un nouveau commentaire

Le contenu de ce champ est gardé secret et ne sera pas montré publiquement.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • 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.
  • 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.

Plus d'informations sur les options de formatage

Connexion utilisateur
Sommaire
Commentaires récents