Les montages liés ne sont pas un type de système de fichiers, ni un paramètre d'un système de fichiers monté ; ce sont des paramètres d'une opération de montage . Autant que je sache, les séquences de commandes suivantes conduisent à des états système essentiellement identiques en ce qui concerne le noyau :
mount /dev/foo /mnt/one; mount --bind /mnt/one /mnt/two
mount /dev/foo /mnt/two; mount --bind /mnt/two /mnt/one
Ainsi, la seule façon de se rappeler quels montages étaient des montages liés est le journal de mount
commandes laissées dans /etc/mtab
. Une opération de montage lié est indiquée par le bind
option de montage (ce qui fait que le type de système de fichiers est ignoré). Mais mount
n'a pas la possibilité de lister uniquement les systèmes de fichiers montés avec un ensemble particulier d'ensembles d'options. Vous devez donc faire votre propre filtrage.
mount | grep -E '[,(]bind[,)]'
</etc/mtab awk '$4 ~ /(^|,)bind(,|$)/'
Notez que /etc/mtab
n'est utile ici que s'il s'agit d'un fichier texte maintenu par mount
. Certaines distributions configurent /etc/mtab
sous forme de lien symbolique vers /proc/mounts
Au lieu; /proc/mounts
est principalement équivalent à /etc/mtab
mais présente quelques différences, dont l'une n'est pas le suivi des montages liés.
Une information conservée par le noyau, mais non affichée dans /proc/mounts
, c'est lorsqu'un point de montage n'affiche qu'une partie de l'arborescence des répertoires sur le système de fichiers monté. En pratique, cela se produit principalement avec les montages liés :
mount --bind /mnt/one/sub /mnt/partial
En /proc/mounts
, les entrées pour /mnt/one
et /mnt/partial
ont le même périphérique, le même type de système de fichiers et les mêmes options. Les informations que /mnt/partial
affiche uniquement la partie du système de fichiers qui est enracinée à /sub
est visible dans les informations de point de montage par processus dans /proc/$pid/mountinfo
(colonne 4). Les entrées ressemblent à ceci :
12 34 56:78 / /mnt/one rw,relatime - ext3 /dev/foo rw,errors=remount-ro,data=ordered
12 34 56:78 /sub /mnt/partial rw,relatime - ext3 /dev/foo rw,errors=remount-ro,data=ordered
Peut-être que ceci pourrait faire l'affaire :
findmnt | grep "\["
Exemple :
$ mkdir /tmp/foo
$ sudo mount --bind /media/ /tmp/foo
$ findmnt | grep "\["
│ └─/tmp/foo /dev/sda2[/media] ext4 rw,relatime,data=ordered
Le noyau ne gère pas les montages liés différents de normal monte après coup. La seule différence dans ce qui se passe alors que mount
s'exécute.
Lorsque vous montez un système de fichiers (par exemple avec mount -t ext4 /dev/sda1 /mnt
) le noyau (un peu simplifié) effectue trois étapes :
- Le noyau recherche un pilote de système de fichiers pour le type de système de fichiers spécifié (si vous omettez
-t
ou utilisez-t auto
mount
devine le type pour vous et fournit le type deviné au noyau) - Le noyau demande au pilote du système de fichiers d'accéder au système de fichiers en utilisant le chemin source et toutes les options fournies. À ce stade, le système de fichiers n'est identifié que par une paire de nombres majeur :mineur.
- Le système de fichiers est lié à un chemin (le point de montage). Le noyau utilise également certaines des options de montage ici. (
nodev
par exemple est une option sur le point de montage, pas sur le système de fichiers. Vous pouvez avoir un montage lié avecnodev
et une sans)
Si vous effectuez un montage lié (par exemple avec mount --bind /a /b
) voici ce qui se passe :
- Le noyau détermine quel système de fichiers contient le chemin source et le chemin relatif du point de montage au répertoire.
- Le système de fichiers est lié au nouveau point de montage à l'aide des options et du chemin relatif.
(Je vais sauter mount --move
, car ce n'est pas pertinent pour la question.)
Cela ressemble assez à la façon dont les fichiers sont créés sous Linux :
- Le noyau détermine quel système de fichiers est responsable du répertoire dans lequel le fichier doit être créé.
- Un nouveau fichier dans le système de fichiers est créé. À ce stade, le fichier n'a qu'un numéro d'inode.
- Le nouveau fichier est lié à un nom de fichier dans le répertoire.
Si vous créez un lien physique, voici ce qui se passe :
- Le noyau résout le numéro d'inode du fichier source.
- Le fichier est lié au nom du fichier de destination.
Comme vous pouvez le voir, le fichier créé et le lien physique sont indiscernables :
$ touch first
$ ln first second
$ ls -li
1184243 -rw-rw-r-- 2 cg909 cg909 0 Feb 20 23:56 /tmp/first
1184243 -rw-rw-r-- 2 cg909 cg909 0 Feb 20 23:56 /tmp/second
Mais , comme vous pouvez identifier tous les liens physiques vers un fichier en comparant les numéros d'inode, vous pouvez identifier tous les montages sur un système de fichiers en comparant les nombres majeur/mineur de montages.
Vous pouvez le faire avec findmnt -o TARGET,MAJ:MIN
ou en regardant directement /proc/self/mountinfo
(voir la documentation du noyau Linux pour plus d'informations).
Le script Python suivant répertorie tous les montages liés. Il suppose que le point de montage le plus ancien avec le chemin relatif le plus court vers la racine du système de fichiers monté est le montage d'origine.
#!/usr/bin/python3
import os.path, re
from collections import namedtuple
MountInfo = namedtuple('MountInfo', ['mountid', 'parentid', 'devid', 'root', 'mountpoint', 'mountoptions', 'extra', 'fstype', 'source', 'fsoptions'])
mounts = {}
def unescape(string):
return re.sub(r'\\([0-7]{3})', (lambda m: chr(int(m.group(1), 8))), string)
with open('/proc/self/mountinfo', 'r') as f:
for line in f:
# Parse line
mid, pid, devid, root, mp, mopt, *tail = line.rstrip().split(' ')
extra = []
for item in tail:
if item != '-':
extra.append(item)
else:
break
fstype, src, fsopt = tail[len(extra)+1:]
# Save mount info
mount = MountInfo(int(mid), int(pid), devid, unescape(root), unescape(mp), mopt, extra, fstype, unescape(src), fsopt)
mounts.setdefault(devid, []).append(mount)
for devid, mnts in mounts.items():
# Skip single mounts
if len(mnts) <= 1:
continue
# Sort list to get the first mount of the device's root dir (if still mounted)
mnts.sort(key=lambda x: x.root)
src, *binds = mnts
# Print bind mounts
for bindmount in binds:
if src.root == bindmount.root:
srcstring = src.mountpoint
else:
srcstring = src.mountpoint+':/'+os.path.relpath(bindmount.root, src.root)
print('{0} -> {1.mountpoint} ({1.mountoptions})'.format(srcstring, bindmount))