Obter o nó do dispositivo pelo par de números maior / menor

11

Cada nó de dispositivo em /dev tem seu próprio par de números maiores / menores. Eu sei que podemos recuperar este par de números do nó do dispositivo por meio de stat , assim:

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

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

Mas como podemos obter o (s) nó (s) do dispositivo por números maiores e menores? A única maneira que conheço é algum tipo de truque ls -l + awk , mas eu realmente espero que haja uma solução melhor.

    
por Dmitry Frank 23.08.2014 / 20:51

4 respostas

7

Eu encontrei uma abordagem mais simples usando o sys pseudofilesystem, em / sys / dev você tem os dispositivos ordenados por tipo an e por major / menor, o arquivo uevent contém o nome do dispositivo e um monte de 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

    
por 23.08.2014 / 23:01
5

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

mknod foo b 8 0

Criará o arquivo de dispositivo chamado foo como um dispositivo de bloco com 8 principais e menor 0. Se você quiser encontrar um ou qualquer arquivo em /dev que tenha o mesmo tipo, maior e menor, você pode do (com zsh ):

  • Para o 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 o 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 em /dev . Nos velhos tempos, era um script que criava arquivos estáticos lá. Em algum momento, você até tinha um sistema de arquivos especial à la /proc .

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

O nome escolhido para o arquivo de dispositivo base é baseado no DEVNAME fornecido pelo kernel. As regras udev podem mudar isso, mas geralmente não, e algumas regras udev adicionarão mais alguns links simbólicos para conveniência (como os /dev/disk/by... ).

Você pode ir de maior: menor para o 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 banco de dados udev , conforme mostrado pelo mikeserv.

    
por 23.08.2014 / 23:18
5

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

Para obter o DEVNAME de udevadm , basta fazer:

udevadm info -rq name $PATH

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

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

OUTPUT

/dev/console

A opção -r é especificar um caminho --root ed - sem o resultado acima, seria lido apenas console . A opção -q especifica um banco de dados --query e leva o operando name aqui - porque queremos o DEVNAME .

Um meio muito simples de encontrar o caminho para um dispositivo de char e / ou de bloco, dado apenas o principal: números menores podem parecer:

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

imprime ...

b:8:0:/dev/sda

Aqui está o primeiro que eu 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 saída udevadm info --export-db 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 remover a string [^=]*DEVNAME= da cabeça de cada linha

  • se uma linha não tiver um primeiro caractere ou seu primeiro caractere for / , copie essa linha sobre h espaço antigo

  • se uma linha corresponder à linha de entrada MAJOR= append N ext para o espaço padrão

  • se houver duas linhas no espaço padrão que correspondam a =$1\n.*=$2$ , em seguida, copie h espaço antigo sobre espaço padrão e impressão automática; mais excluir espaço padrão

Então, se eu fizer isso:

majminpath 7 133 ; majminpath 8 0 ; majminpath 8 1

OUTPUT

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

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

    
por 23.08.2014 / 21:35
1

Alas , o /sys/dev hierachy foi adicionado apenas ao kernel em 2.6.27 ( cf. o relevante commitar contra a base de código do kernel, então precisamos de uma abordagem “bifurcada”.

Seja $M e $m , respectivamente, o maior e menor número do arquivo do nosso dispositivo.

Postar 2.6.27 kernels

Como sugerido por outros, a abordagem mais simples libera o poder do sistema de arquivos sysfs “virtual”, procurando por arquivos chamados $M:$m na pasta /sys/dev (mais de um arquivo é esperado se não sabemos se nosso dispositivo é baseado em caracteres ou em blocos) e, em seguida, obtemos o arquivo uevent (em uma subcaixa para evitar a poluição do namespace):

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

Pré 2.6.27 kernels

Vamos supor, para simplificar, que nosso arquivo é um dispositivo bloco (uma abordagem semelhante se aplica a dispositivos de caractere). Vamos procurar a string $M:$m em toda a hierarquia /sys/block , examinando (abaixo dessa pasta) o conteúdo de cada arquivo cujo nome seja dev . Se /sys/block/<...>/<DEV>/dev for um desses arquivos, DEV será o nome do nosso dispositivo:

dirname "$(find "/sys/block" -name dev | xargs -r grep -l ^$M:$m$)"
    
por 16.10.2015 / 05:53

Tags