For now I use os.stat(path).st_dev
to get the device id. But the id seems to be different for logical disks on same same physical drive. So it doesn't actually works for me. Is there a better or direct solution to it.
Look at the hex output. The first number after the 0x
prefix indicates the device driver:
>>> hex(os.stat("/usr").st_dev)
'0x801L'
This is a 'SCSI' disk, because all of them have ID 8. Reference: https://www.kernel.org/doc/Documentation/devices.txt. Drive ID and partition number are encoded in the remaining part of the st_dev
.
The exact transformation for major ID and minor ID as implemented by glibc
is as follows:
>>> minor = int(os.stat("/lib").st_dev & 0xff)
>>> major = int(os.stat("/lib").st_dev >> 8 & 0xff)
>>> major, minor
(8, 1)
Meaning major number 8 (SCSI host adapter), minor number 1. The minor number encodes drive number as well as partition. As can also be inferred from here, all partitions on the first disk have a minor ID between 1 and 15. All partitions on the second disk have a minor ID between 17 and 31, and so on.
Showcase, same device controller (SCSI):
>>> int(os.stat("/lib").st_dev >> 8 & 0xff)
8
>>> int(os.stat("/usr").st_dev >> 8 & 0xff)
8
Showcase, different device controller (NFS mount in this case):
>>> int(os.stat("/home/*****").st_dev >> 8 & 0xff)
0
What you get from e.g.
>>> os.stat("/usr").st_dev
2049L
corresponds to the decimal Device
output of the stat
program:
$ stat /usr
File: `/usr'
Size: 4096 Blocks: 8 IO Block: 4096 directory
Device: 801h/2049d Inode: 1308164 Links: 11
From man 2 stat
(or e.g. http://linux.die.net/man/2/stat) you can then read
The st_dev field describes the device on which this file resides. (The major(3) and minor(3) macros may be useful to decompose the device ID in this field.)
These macros are not defined by POSIX, but implemented in glibc, as can be seen here:
https://github.com/jeremie-koenig/glibc/blob/master-beware-rebase/sysdeps/generic/sys/sysmacros.h
The actual C implementation is:
#define major(dev) ((int)(((unsigned int) (dev) >> 8) & 0xff))
#define minor(dev) ((int)((dev) & 0xff))
This can easily be translated into Python as I have done above. As of these macros it is also obvious that the hex notation is more intuitive than the decimal one:
>>> hex(os.stat("/usr").st_dev)
'0x801L'
From here you can already see the 8 and the 1 being major device ID and minor device ID, respectively. We can also check this like so:
$ pwd
/usr
$ df -h .
Filesystem Size Used Avail Use% Mounted on
/dev/disk/by-uuid/cba70a49-04a7-40a6-8a53-465f817e51cd 29G 8.6G 19G 32% /
This is the disk, which actually corresponds to /dev/sda1:
$ ls -al /dev/disk/by-uuid/cba70a49-04a7-40a6-8a53-465f817e51cd
0 lrwxrwxrwx 1 root root 10 May 6 16:33 /dev/disk/by-uuid/cba70a49-04a7-40a6-8a53-465f817e51cd -> ../../sda1
Major ID 8 (-> sd
, SCSI device), minor 1 (-> a1
, first disk, first partition).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With