Определите, на каком устройстве находится каталог

50

Если я сделаю

# cd /
# ln -s /home test
# cd test
# mount --bind $PWD /mnt

запись в /proc/mountsIS

/dev/sda2 /mnt ext4 rw,noatime,data=ordered 0 0

которое является устройством, которое монтируется /homeи не является легко выводимым из $PWDчего /test. Как я могу определить, какое устройство (например, / dev / sda2) будет отображаться /proc/mountsв общем, учитывая, что монтирование привязки может быть к каталогу / файлу, который потенциально «скрыт» символическими ссылками, другими монтируемыми ссылками и т. Д.?

StrongBad
источник

Ответы:

49

Если я понимаю ваш вопрос, вы хотите знать, какое устройство использовалось для данного крепления. Для этого вы можете использовать dfкоманду:

$ df -h 
Filesystem                         Size  Used Avail Use% Mounted on
/dev/mapper/fedora_greeneggs-root   50G   21G   27G  44% /
devtmpfs                           3.8G     0  3.8G   0% /dev
tmpfs                              3.8G   14M  3.8G   1% /dev/shm
tmpfs                              3.8G  984K  3.8G   1% /run
tmpfs                              3.8G     0  3.8G   0% /sys/fs/cgroup
tmpfs                              3.8G  3.4M  3.8G   1% /tmp
/dev/sda1                          477M   99M  349M  23% /boot
/dev/mapper/fedora_greeneggs-home  402G  184G  198G  49% /home

Чтобы определить, на каком устройстве находится конкретный файл / каталог, укажите в качестве аргумента файл df. Используя ваш пример:

$ df -h /mnt
Filesystem                         Size  Used Avail Use% Mounted on
/dev/sda1                          477M   99M  349M  23% /

Вы также можете использовать mountкоманду:

$ mount | grep '^/dev'
/dev/mapper/fedora_greeneggs-root on / type ext4 (rw,relatime,seclabel,data=ordered)
/dev/sda1 on /boot type ext4 (rw,relatime,seclabel,data=ordered)
/dev/mapper/fedora_greeneggs-home on /home type ext4 (rw,relatime,seclabel,data=ordered)

Каталог, смонтированный для каждого устройства, является третьим аргументом в выводе выше. Так что для устройства /dev/sda1было бы /boot. Другие устройства используют LVM (управление логическими томами), и их необходимо будет запросить, чтобы узнать, какое фактическое устройство используется LVM.

SLM
источник
Если $PWD(это то, что я монтирую) похоронено в серии символических ссылок, привязных монтирований и т. Д., То мне нужно будет рекурсивно исследовать путь для точек монтирования.
StrongBad
С bind mounts, несмотря на то, что обнаруживается в /proc/mounts«вещи», которая монтируется, по крайней мере, на мой взгляд, не устройство, это каталог / файл.
StrongBad
@ StrongBad - что readlink -f /mntпоказывает?
СЛМ
2
@ StrongBad, если вам приходится иметь дело с определением точки монтирования / устройства, когда они скрыты символическими ссылками, вы должны указать это в своем вопросе. Будет намного легче получить правильный ответ.
Патрик
readlink -f /mntдает/mnt
StrongBad
30

В Linux мы findmntс util-linuxточно сделали для этого

findmnt -n -o SOURCE --target /path/to/FILE

Преимущество других решений заключается в том, что оно по-прежнему работает, если пути скрыты символическими ссылками или монтированными привязками.

rudimeier
источник
Это не работает для меня. Он показывает источник каждого монтирования в системе. findmnt из util-linux 2.23.2
bwduncan
@bwduncan для меня это работает с 2.23.2. Может быть, ошибка? Не могли бы вы попробовать последнюю версию 2.29.2?
rudimeier
2.29 на Ubuntu делает свое дело. Не баг как таковой, скорее фича :)
bwduncan
1
Спасибо! Это именно то, что мне нужно для системного скрипта.
ВОГ
12

Самый точный из известных мне методов заключается в использовании вывода системного вызова lstat (). В частности, поле st_dev. Существует утилита командной строки stat (1), которую можно использовать для просмотра этой информации. Например, вывод «stat / etc / issue» на моем ноутбуке:

File: ‘/etc/issue’
  Size: 65          Blocks: 8          IO Block: 4096   regular file
Device: 801h/2049d  Inode: 1610916043  Links: 1
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)

Обратите внимание на третью строку, первое поле «Устройство». Здесь перечислены 801h. Это значение может быть разделено на два байта, 8 и 1. Первый байт известен как старший номер, второй байт - младший номер. Итак, следующий шаг - выяснить, какое устройство старшее 8, младшее 1.

Я считаю консалтинг / proc / partitions самым быстрым. В моем случае / proc / partitions содержит содержимое:

major minor  #blocks  name

   8       16  234431064 sdb
   8       17   33554432 sdb1
   8       18  200875608 sdb2
   8        0  500107608 sda
   8        1  500106584 sda1

Из этого вывода довольно ясно, что старший 8, младший 1 - это sda1. Мы можем подтвердить это с помощью ls -l / dev / sda1

brw-rw---- 1 root disk 8, 1 May  8 05:33 /dev/sda1

Обратите внимание на 8, 1 перед отметкой даты.

Важно понимать / помнить, что имя файла устройства, например / dev / sda1, является только меткой. Старшие и младшие числа являются значимыми, важными значениями файла устройства. Если вам интересно, посмотрите утилиту mknod (1), используемую для создания файлов устройств. Я мог бы создать новую запись / dev под названием aardvark с основным 8, второстепенным 18 со следующим синтаксисом:

mknod /dev/aardvark b 8 18

Тогда я мог бы легко смонтировать его:

mount /dev/aardvark /mnt

и если мы посмотрим на вывод команды mount или содержимое / proc / mounts и увидим:

/dev/aardvark on /mnt type xfs (rw,relatime,attr2,inode64,noquota)

df -h показывает:

/dev/aardvark   192G  154G   38G  81% /mnt

... В любом случае, смысл всего этого состоит в том, чтобы проиллюстрировать, что важными деталями для идентификации блочного устройства являются старшие и младшие номера, а не метка файла устройства, и что использование системного вызова lstat () - лучший способ запросить эти значения.

В качестве последнего комментария я просто перечитал ваш вопрос, чтобы убедиться, что отвечаю на него, и понял, что вы спрашиваете, какая метка исходного устройства будет отображаться в / proc / mounts для монтирования с привязкой. Это будет та же самая метка исходного устройства, которая использовалась в исходном вызове mount (2) для источника точки монтирования файловой системы для монтирования связывания. Возможно, пример поможет:

У меня есть / dev / sdb2 и / dev / aardvark (так же, как указано выше). Они оба - основные 8, второстепенные 18. Обратите внимание, я буду монтировать одну и ту же файловую систему дважды. Я делаю следующее:

mkdir /mnt1 /mnt2 /foo

mount /dev/aardvark /mnt1
mount /dev/sdb2 /mnt2

Обратите внимание, что я делаю каталог somedir в / mnt1. Но поскольку / mnt1 и / mnt2 имеют одинаковую монтированную файловую систему, somedir также будет доступен через / mnt2.

mkdir /mnt1/somedir

mkdir /foo/left /foo/right

mount -o bind /mnt1/somedir /foo/left
mount -o bind /mnt2/somedir /foo/right

Теперь, если мы проверим / proc / mounts, мы увидим:

/dev/aardvark /mnt1 xfs rw,relatime,attr2,inode64,noquota 0 0
/dev/sdb2 /mnt2 xfs rw,relatime,attr2,inode64,noquota 0 0
/dev/aardvark /foo/left xfs rw,relatime,attr2,inode64,noquota 0 0
/dev/sdb2 /foo/right xfs rw,relatime,attr2,inode64,noquota 0 0

Метка исходного устройства на / foo / ... bind mounts совпадает со значением, изначально указанным в вызове файловой системы mount (2). Помните, что / dev / aardvark и / dev / sdb2 в моем примере - это одно и то же устройство.

Я понимаю, что только что напечатал роман, и первая половина на самом деле не отвечает на ваш вопрос, но казалось, что это пустая трата, чтобы удалить его. Возможно, это поможет кому-то еще.

Удачи.

PS Имейте в виду, что некоторые файловые системы основаны на сети - например, NFS или CIFS - или являются виртуальными - как procfs или sysfs и не имеют блочного устройства-источника. Я не знаю, что будет возвращено как устройство в выводе статистики, просто за то, что оно того стоит.

etherfish
источник
1
Первая часть определенно помогает мне понять последнюю часть.
StrongBad
Этот ответ не работает для путей tmpfs. Вы не найдете второстепенный st_dev в / proc / partitions.
mbello
@mbello Как я уже упоминал в конце моего ответа, этот метод не будет работать и не будет работать для файловых систем, у которых нет устройства поддержки, таких как монтирование tmpfs.
etherfish
2

Учитывая следующие типичные точки монтирования:

$ df --output=target
Mounted on
/
/dev
/run
/sys/fs/cgroup
/run/lock
/run/shm
/run/user

stat --format %m <path> будет печатать только точку монтирования с возможностью обхода (хотя вам нужно проверить код выхода, чтобы однозначно обнаружить ошибку разрешения; подходы монтирования здесь выигрывают):

$ stat --format %m /
/
$ stat --format %m /tmp
/
$ stat --format %m /proc
/proc
$ stat --format %m /run
/run
$ stat --format %m /run/mount
/run
$ stat --format %m /run/user
/run/user
$ stat --format %m /run/user/1000/dconf
/run/user
$ stat --format %m /run/user/1000/gvfs
/run/user/1000/gvfs

Симлинки позаботятся как обычно:

$ ls -lh ~/.gvfs
/home/cwillu/.gvfs -> /run/user/1000/gvfs
$ stat --format %m ~/.gvfs
/run/user/1000/gvfs
$ stat --format %m ~/.gvfs
/

И, конечно же, не забывайте использовать кавычки при написании сценариев. Рассмотрим путь точки монтирования с пробелами и такие:

$ mkdir /tmp/Something\ Like\ This\!
$ sudo mount none /tmp/Something\ Like\ This\! -t tmpfs
$ stat --format %m /tmp/Something\ Like\ This\!
/tmp/Something Like This!
$ touch /tmp/Something\ Like\ This\!/pretend-I\'m-big
$ ls /tmp/Something\ Like\ This\!
pretend-I'm-big

Насколько велико это вы?

$ du $(stat --format %m /tmp/Something\ Like\ This\!/)
du: cannot access /tmp/Something: No such file or directory
du: cannot access Like: No such file or directory
du: cannot access This!: No such file or directory

$ du "$(stat --format %m /tmp/Something\ Like\ This\!/)"
0   /tmp/Something Like This!

Завершение вкладки моего дистрибутива даже не дает правильного решения, поэтому мы просто подстановочные знаки этого примера точки монтирования с возвратами каретки и переводами строк и пробелов:

$ stat --format %m /tmp/Something*
/tmp/Something   
Like   This!

$ a="$(stat --format %m /tmp/Something*)"
    # the above assignment is actually the one place you don't need quotes, 
    # but `export a=...` or similar _would_ need them, so we'll just put them in;
    # they don't change the behaviour in this form of assignment.

$ stat "$a"
  File: ‘/tmp/Something   \r\n\rLike   This!’
  Size: 40          Blocks: 0          IO Block: 4096   directory
Device: 7bh/123d    Inode: 1279171     Links: 2
Access: (1777/drwxrwxrwt)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2016-09-30 11:43:17.933467344 -0600
Modify: 2016-09-30 11:43:17.933467344 -0600
Change: 2016-09-30 11:43:17.933467344 -0600
 Birth: -
Кэри Андервуд
источник
1
Разметка <kbd> используется для одного ключа, а не для всей команды. Это не выглядит лучше, по моему скромному мнению.
Томаш