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


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.