Отримайте вузол пристрою за допомогою пари основних / другорядних чисел


12

Кожен вузол пристрою в підрозділі /devмає власну основну / другорядну пару номерів. Я знаю, що ми можемо отримати цю пару чисел з вузла пристрою за допомогою stat:

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

Або, ls -lтакож показує ці цифри.

Але як ми можемо отримати вузли (пристрої) пристроїв за вказаними основними та незначними числами? Єдиний спосіб, про який я знаю, - це якийсь ls -l+ awkтрюк, але я дуже сподіваюся, що є кращий варіант.


@mikeserv, так, я знаю, що деякі пристрої можуть ділитися цими номерами, тому в своєму початковому запитанні я згадав: "отримати вузли (пристрої) пристроїв". В ідеалі я хочу отримати список усіх вузлів пристроїв, основні чи незначні числа яких відповідають одному вузлу на рядок. Дивно, що ми не маємо для цього готового інструменту. Дякуємо за відповідь btw!
Дмитро Франк

Відповіді:


7

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

Так, наприклад,

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

Відлуння,

loop0
vcs

Примітка. Це було протестовано в Debian Wheezy


щоб знайти назад від dev name: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. У старі часи це був сценарій створення статичних файлів. У якийсь момент у вас навіть була спеціальна файлова система à la /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ред шлях - без нього результат вище , буде тільки для читання console. -qПараметр визначає базу даних , --queryі вона приймає операнд nameтут - бо ми хочемо DEVNAME.

Дуже простий засіб пошуку шляху до char та / або блокування пристрою, що задається лише основним: незначні числа можуть виглядати так:

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, пристрої типу блок / шар можуть спільно використовувати май: min комбінації, і, можливо, це може надрукувати більше одного шляху за виклик.


1
На жаль, це не так просто, блок і символьний пристрій можуть мати однакове основне число. Погляньте на файл / proc / пристрої.
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

Попередньо 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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.