Get device node by major/minor numbers pair
I found a simpler approach using the sys pseudofilesystem, at /sys/dev you have the devices ordered by type an then by major/minor, the file uevent contains the device name and a bunch of other info.
So for example,
for file in $(find /sys/dev/ -name 7:0); do
source ${file}/uevent; echo $DEVNAME;
done;
Echoes,
loop0
vcs
Note: This was tested in Debian Wheezy
Apparently it can be done more simply with udevadm
, and I've just found out how.
To get the DEVNAME
from udevadm
you need only do:
udevadm info -rq name $PATH
For instance, if you wanted to know the /dev
name for /sys/dev/char/5:1
you'd do:
udevadm info -rq name /sys/dev/char/5:1
OUTPUT
/dev/console
The -r
option is to specify a --root
ed path - without it the result above would read only console
. The -q
option specifies a database --query
and it takes the operand name
here - because we want the DEVNAME
.
A very simple means of finding the path to a char and/or block device given only the major:minor numbers might look like:
mmdev() for d in /sys/dev/[cb]*/$1:$2
do [ -e "$d" ] || return
printf %c:%s: "${d#/*/*/}" "${d##*/}"
udevadm info -rq name "$d"
done
So running:
mmdev 8 0
prints...
b:8:0:/dev/sda
Here's the first one I wrote.
majminpath() {
set -- ${1##*[!0-9]*} ${2##*[!0-9]*}
udevadm info --export-db |
sed 's|^[^=]*DEVNAME=||
\|^[^/]|!h;/MAJOR=/N
\|='"$1\n.*=${2?}"'$|!d;g'
}
This just scans udevadm info --export-db
output for the matching numbers. The output looks like:
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
The workflow is like:
attempt to strip the
[^=]*DEVNAME=
string from the head of each lineif a line does not have a first character or its first character is
/
copy that line overh
old spaceif a line matches
MAJOR=
appendN
ext input line to pattern spaceif there are 2 lines in pattern space that match
=$1\n.*=$2$
then copyh
old space over pattern space and auto-print; else delete pattern space
So if I do:
majminpath 7 133 ; majminpath 8 0 ; majminpath 8 1
OUTPUT
/dev/vcsa5
/dev/sda
/dev/sda1
But, as @xae points out, block/char type devices can share maj:min combinations, and so this might possibly print more than one path per call.
Not sure what you mean.
mknod foo b 8 0
Will create the device file called foo
as a block device with major 8 and minor 0. If you mean to find one or any of the files in /dev
that have the same type, major and minor, you can do (with zsh
):
For block device
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
for char device
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
Note that anything can create files in /dev
. In the very old days, it was a script creating static files in there. At some point, you even had a special file system à la /proc
.
On modern versions of Linux, it's usually udev
based on input from the kernel.
The name it chooses for the base device file is based on the DEVNAME
supplied by the kernel. udev
rules may change that but generally don't, and some udev
rules will add some more symlinks for convenience (like the /dev/disk/by...
ones).
You can go from major:minor to kernel DEVNAME
by looking at:
$ 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
You can also get that information from the udev
database as mikeserv has shown.