Obtenir le nœud de l'appareil par paire de nombres majeurs / mineurs

12

Chaque nœud de périphérique sous /devpossède sa propre paire de numéros majeurs / mineurs. Je sais que nous pouvons récupérer cette paire de nombres à partir du nœud de l'appareil au moyen de stat, comme ceci:

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

Ou, ls -lmontre également ces chiffres.

Mais comment obtenir des nœuds d'appareil en utilisant des nombres majeurs et mineurs donnés? La seule façon dont je suis au courant est une sorte de ls -l+ awktruc, mais je l' espère vraiment il y a une meilleure solution.

Dmitry Frank
la source
@mikeserv, oui je sais que certains appareils peuvent partager ces numéros, donc dans ma question initiale, j'ai mentionné: "obtenir les nœuds de l'appareil". Idéalement, je veux obtenir une liste de tous les nœuds de périphérique dont les numéros majeurs / mineurs correspondent, un nœud par ligne. C'est étrange, nous n'avons pas d'outil prêt pour cela. Merci pour la réponse btw!
Dmitry Frank

Réponses:

7

J'ai trouvé une approche plus simple en utilisant le pseudofichier système sys , dans / sys / dev vous avez les appareils classés par type puis par majeur / mineur, le fichier uevent contient le nom de l'appareil et un tas d'autres informations.

Ainsi, par exemple,

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

Echoes,

loop0
vcs

Remarque: cela a été testé dans Debian Wheezy

xae
la source
pour rechercher en arrière à partir du nom du développeur:for file in $(ls /sys/dev/block/ ); do source /sys/dev/block/${file}/uevent; if [ "$DEVNAME" == "sda1" ] ; then echo ${file}; fi done;
BBK
5

Pas sûr de ce que vous voulez dire.

mknod foo b 8 0

Créera le fichier de périphérique appelé en footant que périphérique de bloc avec 8 majeur et 0 mineur. Si vous voulez trouver un ou l'un des fichiers /devqui ont le même type, majeur et mineur, vous pouvez faire (avec zsh):

  • Pour périphérique bloc 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
    
  • pour le périphérique 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
    

Notez que tout peut créer des fichiers dans /dev. Autrefois, c'était un script créant des fichiers statiques dedans. À un moment donné, vous aviez même un système de fichiers spécial à la /proc.

Sur les versions modernes de Linux, il est généralement udevbasé sur les entrées du noyau.

Le nom qu'il choisit pour le fichier de périphérique de base est basé sur celui DEVNAMEfourni par le noyau. udevles règles peuvent changer cela mais ne le font généralement pas, et certaines udevrègles ajouteront d'autres liens symboliques pour plus de commodité (comme /dev/disk/by...ceux-ci).

Vous pouvez passer du majeur: mineur au noyau DEVNAMEen regardant:

$ 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

Vous pouvez également obtenir ces informations de la udevbase de données comme l'a montré mikeserv.

Stéphane Chazelas
la source
5

Apparemment, cela peut être fait plus simplement avec udevadm, et je viens de découvrir comment.

Pour obtenir le DEVNAMEde udevadmvous suffit de faire:

udevadm info -rq name $PATH

Par exemple, si vous vouliez connaître le /devnom de /sys/dev/char/5:1votre choix, vous le feriez:

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

PRODUCTION

/dev/console

L' -roption est de spécifier un --rootchemin ed - sans lui le résultat ci-dessus serait en lecture seule console. L' -qoption spécifie une base de données --queryet il prend l'opérande nameici - parce que nous voulons le DEVNAME.

Un moyen très simple de trouver le chemin vers un périphérique char et / ou block étant donné uniquement les principaux: les nombres mineurs peuvent ressembler à:

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

Donc en cours d'exécution:

mmdev 8 0

impressions ...

b:8:0:/dev/sda

Voici le premier que j'ai écrit.

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

Cela scanne simplement la udevadm info --export-dbsortie pour les numéros correspondants. La sortie ressemble à:

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

Le workflow est comme:

  • tenter de retirer la [^=]*DEVNAME=chaîne de la tête de chaque ligne

  • si une ligne n'a pas de premier caractère ou si son premier caractère est de /copier cette ligne sur l' hancien espace

  • si une ligne correspond à MAJOR=ajouter Nla ligne d'entrée ext à l'espace modèle

  • s'il y a 2 lignes dans l'espace du motif qui correspondent, =$1\n.*=$2$copiez l' hancien espace sur l'espace du motif et l'impression automatique; sinon supprimer l'espace de motif

Donc si je le fais:

majminpath 7 133 ; majminpath 8 0 ; majminpath 8 1

PRODUCTION

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

Mais, comme le souligne @xae, les périphériques de type bloc / caractère peuvent partager des combinaisons maj: min, et cela peut donc éventuellement imprimer plus d'un chemin par appel.

mikeserv
la source
1
Malheureusement, ce n'est pas si facile, un bloc et un appareil de caractères peuvent partager le même nombre majeur. Jetez un œil au fichier / proc / devices.
xae
Je dois vérifier le sous-système - c'est vrai. Merci, @xae.
mikeserv
1

Hélas , la /sys/devhiérarchie n'a été ajoutée au noyau qu'en 2.6.27 ( cf. la validation pertinente contre la base de code du noyau), nous avons donc besoin d'une approche «bifurquée».

Soit $Met $m, respectivement, le nombre majeur et mineur de notre fichier de périphérique.

Post 2.6.27 kernels

Comme suggéré par d'autres, l'approche la plus simple libère la puissance du sysfssystème de fichiers «virtuel», en poursuivant directement pour les fichiers nommés $M:$msous le dossier /sys/dev(plus d'un fichier est à prévoir si nous ne savons pas si notre appareil est un caractère- ou basé sur des blocs), puis à sourcer le ueventfichier (dans un sous-shell afin d'éviter la pollution de l'espace de noms):

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

Pré 2.6.27 noyaux

Supposons, par souci de simplicité, que notre fichier est un périphérique de bloc (une approche similaire s'applique aux périphériques de caractères). Nous rechercherons la chaîne $M:$mdans toute la /sys/blockhiérarchie, en examinant (sous ce dossier) le contenu de chaque fichier dont le nom se trouve être dev. Si /sys/block/<...>/<DEV>/devest un de ces fichiers, alors DEVest lié au nom de notre appareil:

dirname "$(find "/sys/block" -name dev | xargs -r grep -l ^$M:$m$)"
Roberto Reale
la source
0

Sous Linux, il est possible de profiter de certains fichiers dans /procun système de fichiers virtuel.

$ 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

La forme simple du modèle fournit déjà des informations sur le périphérique souhaité dans la sortie, mais un filtrage supplémentaire pour extraire une seule chaîne particulière est également possible.

Sergiy Kolodyazhnyy
la source
0

Il existe une fonction de bibliothèque: makedev()

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

Étant donné les ID de périphérique majeurs et mineurs, makedev () les combine pour produire un ID de périphérique, renvoyé comme résultat de la fonction.

Pour plus de détails, visitez: http://man7.org/linux/man-pages/man3/major.3.html

Krishna Kanth Yenumula
la source