Python: check if two Linux paths are on same physical disk
Asked Answered
P

1

5

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.

Perfectly answered 20/6, 2013 at 9:52 Comment(1)
While you might get an answer that is useful for many cases, note that there's probably not a completely general answer to this, and you might want to re-think exactly why you think you need it. As an example, you might have a file system that exists in a loopback mounted file that exists on another file system that lives in an LVM2 logical volume that is striped across several "physical disks" that are actually RAID10 md devices on 8 separate hard drives that just happen to be hardware RAID devices as well...Riddle
C
9

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

Background:

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).

Careerist answered 20/6, 2013 at 10:41 Comment(5)
Hey,sorry for the late reply. As you said that Major ID corresponds to physical disk no., and the concept is pretty well explained. Now I have the following observation:- I have 2 physical disks on my machine:- --/dev/sdb/ with logicals /dev/sdb1/ and /dev/sdb2/ --/dev/sdc/ with logicals /dev/sdc1Perfectly
but ls -l /dev gives me the following:- brw-rw----. 1 root disk 8, 16 Jul 2 18:32 sdb brw-rw----. 1 root disk 8, 17 Jul 2 18:33 sdb1 brw-rw----. 1 root disk 8, 18 Jul 2 18:35 sdb2 brw-rw----. 1 root disk 8, 32 Jul 2 18:32 sdc brw-rw----. 1 root disk 8, 33 Jul 2 18:36 sdc1 So, I see that the major nos. are same for both of them. m confused? :(Perfectly
major and minor numbers...I think major no is for a device driver and all the devices managed by this device driver will have the same major nos.Perfectly
Good reference you found there. Important quotes: "All devices controlled by the same device driver have a common major device number. The minor device numbers are used to distinguish between different devices and their controllers.", "The major number for all SCSI drives is 8. The minor number is based on the drive number, which is multiplied by 16 instead of 64, like the IDE drives. The partition number is then added to this number to give the minor."Careerist
I have updated the answer. I think now everything is also clear to me :-). It's pretty simple actually, best reference is kernel.org/doc/Documentation/devices.txtCareerist

© 2022 - 2024 — McMap. All rights reserved.