Obter nó do dispositivo pelo par de números principais / secundários

12

Cada nó do dispositivo /devpossui seu próprio par de números maior / menor. Eu sei que podemos recuperar esse par de números do nó do dispositivo por meio de stat, assim:

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

Ou, ls -ltambém mostra esses números.

Mas como podemos obter o (s) nó (s) do dispositivo com números maiores e menores? A única maneira pela qual estou ciente é de algum tipo de ls -l+ awktruque, mas espero realmente que haja uma solução melhor.

Dmitry Frank
fonte
@ MikeServ, sim, eu sei que alguns dispositivos podem compartilhar esses números, então na minha pergunta inicial eu mencionei: "obter nó (s) do dispositivo". Idealmente, quero obter uma lista com todos os nós de dispositivos cujos números maiores / menores correspondem, um nó por linha. Estranho, não temos uma ferramenta pronta para isso. Obrigado pela resposta btw!
Dmitry Frank

Respostas:

7

Eu encontrei uma abordagem mais simples usando o sistema pseudofiles sys , em / sys / dev você tem os dispositivos ordenados por tipo e depois por major / minor, o uevent do arquivo contém o nome do dispositivo e várias outras informações.

Então, por exemplo,

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

Ecos,

loop0
vcs

Nota: Isso foi testado no Debian Wheezy

xae
fonte
para encontrar de trás para frente a partir do nome do desenvolvedor:for file in $(ls /sys/dev/block/ ); do source /sys/dev/block/${file}/uevent; if [ "$DEVNAME" == "sda1" ] ; then echo ${file}; fi done;
BBK
5

Não tenho certeza do que você quer dizer.

mknod foo b 8 0

Criará o arquivo do dispositivo chamado foocomo um dispositivo de bloco com 8 maiores e menores 0. Se você deseja encontrar um ou qualquer um dos arquivos /devcom o mesmo tipo, maior e menor, você pode fazer (com zsh):

  • Para dispositivo de bloco 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
    
  • para dispositivo 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
    

Observe que qualquer coisa pode criar arquivos no /dev. Antigamente, era um script criando arquivos estáticos lá. Em algum momento, você ainda tinha um sistema de arquivos especial à la /proc.

Nas versões modernas do Linux, geralmente é udevbaseado na entrada do kernel.

O nome escolhido para o arquivo de dispositivo base é baseado no DEVNAMEfornecido pelo kernel. udevas regras podem mudar isso, mas geralmente não mudam, e algumas udevregras adicionam mais links simbólicos por conveniência (como /dev/disk/by...os).

Você pode passar de major: minor para kernel DEVNAME, olhando para:

$ 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

Você também pode obter essas informações do udevbanco de dados, como o mikeserv mostrou.

Stéphane Chazelas
fonte
5

Aparentemente, isso pode ser feito de maneira mais simples udevadm, e acabei de descobrir como.

Para obter o DEVNAMEde udevadmque você só precisa fazer:

udevadm info -rq name $PATH

Por exemplo, se você quisesse saber o /devnome, /sys/dev/char/5:1faria:

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

RESULTADO

/dev/console

A -ropção é especificar um --rootcaminho ed - sem ele, o resultado acima seria somente leitura console. A -qopção especifica um banco de dados --querye leva o operando nameaqui - porque queremos o DEVNAME.

Um meio muito simples de encontrar o caminho para um dispositivo de char e / ou bloco, considerando apenas os principais: números menores podem se parecer com:

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

Então, executando:

mmdev 8 0

impressões ...

b:8:0:/dev/sda

Aqui está o primeiro que escrevi.

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

Isso apenas verifica a udevadm info --export-dbsaída em busca dos números correspondentes. A saída se parece com:

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

O fluxo de trabalho é como:

  • tente tirar a [^=]*DEVNAME=corda da cabeça de cada linha

  • se uma linha não tiver um primeiro caractere ou seu primeiro caractere for /copiá-la no hespaço antigo

  • se uma linha corresponder, MAJOR=acrescente Na linha de entrada ext ao espaço do padrão

  • se houver duas linhas no espaço do padrão que correspondam =$1\n.*=$2$, copie o hespaço antigo sobre o espaço do padrão e imprima automaticamente; mais excluir espaço padrão

Então, se eu fizer:

majminpath 7 133 ; majminpath 8 0 ; majminpath 8 1

RESULTADO

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

Mas, como @xae aponta, os dispositivos do tipo bloco / caractere podem compartilhar combinações maj: min e, portanto, isso pode imprimir mais de um caminho por chamada.

mikeserv
fonte
1
Infelizmente, não é tão fácil, um bloco e um dispositivo de caracteres podem compartilhar o mesmo número principal. Dê uma olhada no arquivo / proc / devices.
X23
Tenho que verificar o subsistema - está certo. Obrigado, @xae.
mikeserv
1

Infelizmente , a /sys/devhierarquia só foi adicionado ao kernel tão tarde quanto 2.6.27 ( Cf. o relevante cometer contra a base de código do kernel), por isso precisamos de uma abordagem “bifurcado”.

Seja $Me $m, respectivamente, o número principal e o menor de nosso arquivo de dispositivo.

Post 2.6.27 kernels

Conforme sugerido por outros, a abordagem mais simples libera o poder do sysfssistema de arquivos “virtual”, perseguindo diretamente os arquivos nomeados $M:$msob a pasta /sys/dev(mais de um arquivo é esperado se não soubermos se nosso dispositivo é um caractere). ou um baseado em bloco) e, em seguida, forneça o ueventarquivo (em uma subshell para evitar a poluição do espaço para nome):

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

Kernels anteriores à 2.6.27

Vamos supor, por uma questão de simplicidade, que nosso arquivo é um dispositivo de bloco (uma abordagem semelhante se aplica a dispositivos de caracteres). Procuraremos a string em $M:$mtoda a /sys/blockhierarquia, examinando (embaixo dessa pasta) o conteúdo de cada arquivo cujo nome seja dev. Se /sys/block/<...>/<DEV>/devfor um desses arquivos, DEVserá o nome do nosso dispositivo:

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

No Linux, é possível tirar proveito de certos arquivos no /procsistema de arquivos virtual.

$ 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

A forma simples do padrão já fornece informações sobre o dispositivo desejado na saída, no entanto, filtragem adicional para extrair apenas uma sequência específica também é possível.

Sergiy Kolodyazhnyy
fonte
0

Existe uma função de biblioteca: makedev()

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

Dados os IDs principais e secundários do dispositivo, makedev () os combina para produzir um ID do dispositivo, retornado como resultado da função.

Para mais detalhes, visite: http://man7.org/linux/man-pages/man3/major.3.html

Krishna Kanth Yenumula
fonte