Uzyskaj węzeł urządzenia przez parę liczb głównych / podrzędnych

12

Każdy węzeł urządzenia /devma swoją własną parę liczb głównych / podrzędnych. Wiem, że możemy pobrać tę parę liczb z węzła urządzenia za pomocą stat:

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

Lub ls -lteż pokazuje te liczby.

Ale w jaki sposób możemy uzyskać węzły urządzeń według danych liczb głównych i pomocniczych? Jedyny sposób, w jaki jestem świadomy, to jakaś sztuczka ls -l+ awk, ale naprawdę mam nadzieję, że istnieje lepsze rozwiązanie.

Dmitry Frank
źródło
@ Mikeserv, tak, wiem, że niektóre urządzenia mogą współdzielić te numery, więc w początkowym pytaniu wspomniałem: „pobierz węzeł (urządzenia)”. Idealnie chcę uzyskać listę ze wszystkimi węzłami urządzeń, których numery główne / dodatkowe są zgodne, po jednym węźle na linię. To dziwne, że nie mamy na to gotowego narzędzia. Dzięki za odpowiedź btw!
Dmitry Frank

Odpowiedzi:

7

Znalazłem prostsze podejście przy użyciu pseudofilesystemu sys , w / sys / dev masz urządzenia uporządkowane według typu, a następnie według major / minor, plik uevent zawiera nazwę urządzenia i kilka innych informacji.

Na przykład

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

Echa,

loop0
vcs

Uwaga: Zostało to przetestowane w Debian Wheezy

xae
źródło
znaleźć wstecz od nazwy programisty:for file in $(ls /sys/dev/block/ ); do source /sys/dev/block/${file}/uevent; if [ "$DEVNAME" == "sda1" ] ; then echo ${file}; fi done;
BBK
5

Nie wiem co masz na myśli.

mknod foo b 8 0

Utworzy plik urządzenia nazywany foojako urządzenie blokowe z wersją główną 8 i podrzędną 0. Jeśli chcesz znaleźć jeden lub jeden z plików /devtego samego typu, główny i podrzędny, możesz (za pomocą zsh):

  • W przypadku urządzenia blokowego 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
    
  • dla urządzenia 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
    

Zauważ, że wszystko może tworzyć pliki /dev. W dawnych czasach był to skrypt tworzący tam pliki statyczne. W pewnym momencie miałeś nawet specjalny system plików à la /proc.

W nowoczesnych wersjach Linuksa zwykle udevopiera się na danych wejściowych z jądra.

Nazwa, którą wybiera dla podstawowego pliku urządzenia, jest oparta na DEVNAMEdostarczonej przez jądro. udevreguły mogą to zmienić, ale generalnie nie, a niektóre udevreguły dodają więcej dowiązań symbolicznych dla wygody (jak /dev/disk/by...te).

Możesz przejść z wersji major: minor na jądro DEVNAME, patrząc na:

$ 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

Możesz również uzyskać te informacje z udevbazy danych, jak pokazał mikeserv.

Stéphane Chazelas
źródło
5

Najwyraźniej można to zrobić prościej udevadm, a ja właśnie dowiedziałem się, jak to zrobić.

Aby uzyskać DEVNAMEod udevadm, musisz tylko:

udevadm info -rq name $PATH

Na przykład, jeśli chcesz poznać /devnazwę /sys/dev/char/5:1, którą możesz zrobić:

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

WYNIK

/dev/console

-rOpcją jest, aby określić --rootścieżkę Ed - bez niego wynik powyżej będzie tylko do odczytu console. -qOpcja określa bazę danych --queryi przyjmuje argument nametutaj - bo chcemy DEVNAME.

Bardzo prosty sposób znalezienia ścieżki do urządzenia char i / lub block, biorąc pod uwagę tylko główne: liczby mniejsze:

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

Tak działa:

mmdev 8 0

drukuje ...

b:8:0:/dev/sda

Oto pierwszy, który napisałem.

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

To po prostu skanuje udevadm info --export-dbdane wyjściowe w celu znalezienia pasujących liczb. Dane wyjściowe wyglądają następująco:

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

Przepływ pracy wygląda następująco:

  • spróbuj usunąć [^=]*DEVNAME=sznurek z nagłówka każdej linii

  • jeśli linia nie ma pierwszego znaku lub jego pierwszym znakiem jest /skopiowanie tej linii nad hstarą spacją

  • Jeśli linia pasuje MAJOR=Dołącz Nlinię wejściową ext do przestrzeni wzorca

  • jeśli w obszarze wzorca znajdują się 2 wiersze, =$1\n.*=$2$skopiuj hstarą przestrzeń nad obszarem wzorca i wydrukuj automatycznie; w przeciwnym razie usuń przestrzeń wzorca

Więc jeśli to zrobię:

majminpath 7 133 ; majminpath 8 0 ; majminpath 8 1

WYNIK

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

Ale, jak wskazuje @xae, urządzenia typu blok / char mogą współdzielić kombinacje maj: min, więc może to wydrukować więcej niż jedną ścieżkę na połączenie.

mikeserv
źródło
1
Niestety nie jest to takie proste, blok i urządzenie postaci mogą mieć ten sam numer główny. Spójrz na plik / proc / devices.
xae
Muszę sprawdzić podsystem - zgadza się. Dzięki, @xae.
mikeserv
1

Niestety , /sys/devhierarchia została dodana do jądra dopiero w wersji 2.6.27 ( por . Odpowiednie zatwierdzenie przeciw bazie kodowej jądra), więc potrzebujemy podejścia „rozwidlonego”.

Niech $Mi $modpowiednio będą główną i podrzędną liczbą naszego pliku urządzenia.

Zakładać 2.6.27 jądra

Jak sugerują inni, najprostsze podejście uwalnia moc sysfs„wirtualnego” systemu plików, goniąc prosto za plikami nazwanymi $M:$mw folderze /sys/dev(więcej niż jeden plik należy się spodziewać, jeśli nie wiemy, czy nasze urządzenie jest znakiem lub oparty na blokach), a następnie sourcing ueventpliku (w podpowłoce, aby zapobiec zanieczyszczeniu przestrzeni nazw):

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

Jądra wersji wcześniejszej niż 2.6.27

Załóżmy, dla uproszczenia, że ​​nasz plik jest urządzeniem blokowym (podobne podejście dotyczy urządzeń znakowych). Będziemy wyszukiwać ciąg w $M:$mcałej /sys/blockhierarchii, badając (pod tym folderem) zawartość każdego pliku, którego nazwa jest przypadkowa dev. Jeśli /sys/block/<...>/<DEV>/devjest to jeden z takich plików, DEVto na pewno będzie to nazwa naszego urządzenia:

dirname "$(find "/sys/block" -name dev | xargs -r grep -l ^$M:$m$)"
Roberto Reale
źródło
0

W systemie Linux można korzystać z niektórych plików w /procwirtualnym systemie plików.

$ 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

Prosta forma wzorca już dostarcza informacji o pożądanym urządzeniu na wyjściu, jednak możliwe jest również dodatkowe filtrowanie w celu wyodrębnienia tylko jednego określonego ciągu.

Sergiy Kolodyazhnyy
źródło
0

Istnieje funkcja biblioteki: makedev()

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

Biorąc pod uwagę główne i mniejsze identyfikatory urządzeń, makedev () łączy je w celu utworzenia identyfikatora urządzenia, zwracanego jako wynik funkcji.

Więcej informacji na stronie: http://man7.org/linux/man-pages/man3/major.3.html

Krishna Kanth Yenumula
źródło