Получить узел устройства по паре старших / младших номеров

12

Каждый узел устройства /devимеет свою собственную пару старших / младших номеров. Я знаю, что мы можем извлечь эту пару чисел из узла устройства stat, например, так:

stat -c 'major: %t minor: %T' <file>

Или ls -lтакже показывает эти цифры.

Но как мы можем получить узел (и) устройства по заданным старшим и младшим номерам? Единственный способ я знаю это своего рода ls -l+ awkтрюк, но я действительно надеюсь , что есть лучшее решение.

Дмитрий Франк
источник
@mikeserv, да, я знаю, что некоторые устройства могут разделять эти числа, поэтому в своем первоначальном вопросе я упомянул: «получить узел (и) устройства». В идеале я хочу получить список со всеми узлами устройства, у которых совпадают старшие / младшие номера, по одному узлу на строку. Странно, у нас нет готового инструмента для этого. Спасибо за ответ, кстати!
Дмитрий Франк

Ответы:

7

Я нашел более простой подход с использованием системы псевдофайлов sys : в / sys / dev у вас есть устройства, упорядоченные по типу тогда по мажорному / младшему, файл uevent содержит имя устройства и кучу другой информации.

Так, например,

  for file in $(find /sys/dev/ -name 7:0); do  
      source ${file}/uevent; echo $DEVNAME;
  done;

Echoes,

loop0
vcs

Примечание: это было проверено в Debian Wheezy

XAE
источник
найти назад от имени разработчика:for file in $(ls /sys/dev/block/ ); do source /sys/dev/block/${file}/uevent; if [ "$DEVNAME" == "sda1" ] ; then echo ${file}; fi done;
BBK
5

Не уверен, что вы имеете в виду.

mknod foo b 8 0

Создаст файл устройства, называемый fooблочным устройством с основными 8 и младшими 0. Если вы хотите найти один или любой из файлов /devс одинаковым типом, основным и второстепенным, вы можете сделать (с zsh):

  • Для блочного устройства 8:0:

    $ zmodload zsh/stat
    $ ls -ld /dev/**/*(-D%be:'zstat -H s $REPLY && (($s[rdev] == 8<<8+0))':)
    lrwxrwxrwx 1 root root    6 Aug 23 05:28 /dev/block/8:0 -> ../sda
    lrwxrwxrwx 1 root root    9 Aug 23 05:28 /dev/disk/by-id/ata-KINGSTON_SNV455S234GB_07MA10014418 -> ../../sda
    brw-rw---- 1 root disk 8, 0 Aug 23 05:28 /dev/sda
    
  • для устройства char 226:0:

    $ ls -ld /dev/**/*(-D%ce:'zstat -H s $REPLY && (($s[rdev] == 226<<8+0))':)
    lrwxrwxrwx  1 root root      12 Aug 23 05:28 /dev/char/226:0 -> ../dri/card0
    crw-rw----+ 1 root video 226, 0 Aug 23 05:28 /dev/dri/card0
    

Обратите внимание, что все может создавать файлы в /dev. В очень старые времена это был сценарий создания статических файлов. В какой-то момент у вас даже была специальная файловая система а-ля /proc.

В современных версиях Linux он обычно udevоснован на вводе из ядра.

Имя, которое он выбирает для файла базового устройства, основано на DEVNAMEпредоставленном ядром. udevправила могут изменить это, но, как правило, этого не происходит, и некоторые udevправила добавят еще несколько символических ссылок для удобства (например, /dev/disk/by...те).

Вы можете перейти от основного: младшего к ядру DEVNAME, посмотрев на:

$ sed -n 's/^DEVNAME=//p' /sys/dev/block/8:0/uevent
sda
$ sed -n 's/^DEVNAME=//p' /sys/dev/char/226:0/uevent
dri/card0

Вы также можете получить эту информацию из udevбазы данных, как показал mikeserv.

Стефан Шазелас
источник
5

Видимо, это можно сделать проще udevadm, и я только что узнал, как.

Чтобы получить DEVNAMEот udevadmвас нужно только сделать:

udevadm info -rq name $PATH

Например, если вы хотите знать /devимя /sys/dev/char/5:1вы могли бы сделать:

udevadm info -rq name /sys/dev/char/5:1

ВЫХОД

/dev/console

Можно -rуказать --rootпуть ed - без него приведенный выше результат будет доступен только для чтения console. -qПараметр определяет базу данных , --queryи она принимает операнд nameздесь - потому что мы хотим DEVNAME.

Очень простое средство нахождения пути к символу и / или блочному устройству с учетом только старшего: младшие числа могут выглядеть так:

mmdev() for d in /sys/dev/[cb]*/$1:$2
        do  [ -e "$d" ] || return
            printf %c:%s: "${d#/*/*/}" "${d##*/}"
            udevadm info -rq name "$d"
        done

Так работает:

mmdev 8 0

печатает ...

b:8:0:/dev/sda

Вот первый, который я написал.

majminpath() {
    set -- ${1##*[!0-9]*} ${2##*[!0-9]*}
    udevadm info --export-db |
    sed 's|^[^=]*DEVNAME=||
         \|^[^/]|!h;/MAJOR=/N
         \|='"$1\n.*=${2?}"'$|!d;g'
}

Это просто сканирует udevadm info --export-dbвыходные данные для соответствующих номеров. Вывод выглядит так:

P: /devices/virtual/vc/vcsa4
N: vcsa4
E: DEVNAME=/dev/vcsa4
E: DEVPATH=/devices/virtual/vc/vcsa4
E: MAJOR=7
E: MINOR=132
E: SUBSYSTEM=vc

P: /devices/virtual/vc/vcsa5
N: vcsa5
E: DEVNAME=/dev/vcsa5
E: DEVPATH=/devices/virtual/vc/vcsa5
E: MAJOR=7
E: MINOR=133
E: SUBSYSTEM=vc

#...and so on

Рабочий процесс похож на:

  • попытаться снять [^=]*DEVNAME=строку с головы каждой строки

  • если строка не имеет первого символа или ее первый символ /копирует эту строку в hстарое пространство

  • если строка совпадает, MAJOR=добавьте Nстроку ввода ext в пространство шаблона

  • если в шаблонном пространстве есть 2 строки, которые совпадают, =$1\n.*=$2$скопируйте hстарое пространство в шаблонное пространство и выполните автоматическую печать; иначе удалите пробел

Так что если я сделаю:

majminpath 7 133 ; majminpath 8 0 ; majminpath 8 1

ВЫХОД

/dev/vcsa5
/dev/sda
/dev/sda1

Но, как указывает @xae, устройства блочного / символьного типа могут совместно использовать комбинации maj: min, и это может привести к выводу нескольких путей за вызов.

mikeserv
источник
1
К сожалению, это не так просто, блок и символьное устройство могут использовать один и тот же старший номер. Взгляните на файл / proc / devices.
xae
Я должен проверить подсистему - это правильно. Спасибо, @xae.
mikeserv
1

Увы , /sys/devиерархия была добавлена ​​в ядро ​​только в 2.6.27 ( см. Соответствующий коммит против кодовой базы ядра), поэтому нам нужен «раздвоенный» подход.

Пусть $Mи $m, соответственно, будут старшим и младшим номером нашего файла устройства.

Пост 2.6.27 ядра

Как полагают другие, самый простой подход раскрывает всю мощь sysfs«виртуальной» файловой системы, гоняясь прямо за файлами, названными $M:$mв папке /sys/dev(более чем один файл следует ожидать, если мы не знаем, является ли наше устройство символьным). или блочный), а затем поиск ueventфайла (в подоболочке, чтобы предотвратить загрязнение пространства имен):

for file in $(find /sys/dev/ -name $M:$m)
do
    (
        source ${file}/uevent
        echo $DEVNAME
    )
done

Pre 2.6.27 ядра

Давайте для простоты предположим, что наш файл является блочным устройством (аналогичный подход применяется для символьных устройств). Мы будем искать строку по $M:$mвсей /sys/blockиерархии, изучая (под этой папкой) содержимое каждого файла, имя которого совпадает с именем dev. Если /sys/block/<...>/<DEV>/devодин из таких файлов, то DEVобязательно будет имя нашего устройства:

dirname "$(find "/sys/block" -name dev | xargs -r grep -l ^$M:$m$)"
Роберто Реале
источник
0

В Linux можно использовать определенные файлы в /procвиртуальной файловой системе.

$ grep '8[[:blank:]]\+1[[:blank:]]\+' /proc/partitions 
   8        1   29309568 sda1

$ grep '8:1[[:blank:]]' /proc/self/mountinfo 
28 0 8:1 / / rw,relatime shared:1 - ext4 /dev/sda1 rw,data=ordered

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

Сергей Колодяжный
источник
0

Есть функция библиотеки: makedev()

#include <sys/sysmacros.h>
dev_t makedev(unsigned int maj, unsigned int min);

Учитывая основные и второстепенные идентификаторы устройств, makedev () объединяет их для получения идентификатора устройства, возвращаемого как результат функции.

Для получения более подробной информации посетите: http://man7.org/linux/man-pages/man3/major.3.html

Кришна Кант Йенумула
источник