How to find the disk where root / is on in Bash on Linux?

Question: how to find the disk where the Linux’s root(/) is on in Bash? The root may be on a LVM volume or on a raw disk.

2 cases:

One example:

# df -hT | grep /$
/dev/sda4               ext4       48G   32G   14G  71% /

For another example:

# df -hT | grep /$
/dev/mapper/fedora-root        ext4       48G   45G  1.4G  98% /

The it is a LVM volume in LVM group ‘fedora’:

# lvs | grep fedora | grep root
  root        fedora   -wi-ao----  48.83g   

and ‘fedora’ is on the single disk partition ‘/dev/sda3’ of disk ‘/dev/sda’:

# pvs | grep fedora
  /dev/sda3  fedora   lvm2 a--    64.46g   4.00m

For both cases above, we want to find out ‘/dev/sda’ (the root filesystem is on only one physical disk).

To solve this problem, one straightforward way is to check every possible cases and handle each case following the format for each case (raw partition, or LVM partition). But in Linux, there is a more convenient tool to handle this problem – using lsblk.

lsblk and PKNAME

lsblk can show one important value here:

PKNAME  internal parent kernel device name

For a raw partition, the parent kernel device is the disk, and for an LVM partition, the parent kernel device is the physical volume (the partition). Here are examples of output of lsblk.

For a ‘/’ on a raw partition:

root@vm0:~# lsblk 
NAME   MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
...
sdc      8:32   0   1.8T  0 disk 
├─sdc1   8:33   0   512M  0 part /boot/efi
└─sdc2   8:34   0   1.8T  0 part /

For a ‘/’ on an LVM partition:

root@vm1:~# lsblk 
NAME                MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
sda                   8:0    0    20G  0 disk 
├─sda1                8:1    0   512M  0 part /boot/efi
├─sda2                8:2    0     1K  0 part 
└─sda5                8:5    0  19.5G  0 part 
  ├─vgubuntu-root   253:0    0  18.5G  0 lvm  /
  └─vgubuntu-swap_1 253:1    0   976M  0 lvm  [SWAP]

PKNAME for raw or LVM partition backed root ‘/’

From lsblk‘s manual, we can see it supports various output format. Here, we use the key/value pair format which is easy to parse in Bash.

For raw partition based ‘/’:

# lsblk -oMOUNTPOINT,PKNAME -P | grep 'MOUNTPOINT="/"'
MOUNTPOINT="/" PKNAME="sdc"

For LVM partition based ‘/’:

# lsblk -oMOUNTPOINT,PKNAME -P | grep 'MOUNTPOINT="/"'
MOUNTPOINT="/" PKNAME="sda5"

We can easily get rid of the trailing numbers (so we get the disk device name) by

sed 's/[0-9]*$//'

This can be applied to both cases. For the raw partition case, the sed command simply does not have any additional effect.

Wrap up to be a bash statement

Now, we can wrap all up into a bash statement using some Bash grammar and techniques

dev=$(eval $(lsblk -oMOUNTPOINT,PKNAME -P -M | grep 'MOUNTPOINT="/"'); echo $PKNAME | sed 's/[0-9]*$//')

For the raw partition case, we get

root@vm0:~# dev=$(eval $(lsblk -oMOUNTPOINT,PKNAME -P -M | grep 'MOUNTPOINT="/"'); echo $PKNAME | sed 's/[0-9]*$//')
root@vm0:~# echo $dev
sdc

For the LVM partition case, we get

root@vm1:~# dev=$(eval $(lsblk -oMOUNTPOINT,PKNAME -P | grep 'MOUNTPOINT="/"'); echo $PKNAME | sed 's/[0-9]*$//')
root@vm1:~# echo $dev
sda

Eric Ma

Eric is a systems guy. Eric is interested in building high-performance and scalable distributed systems and related technologies. The views or opinions expressed here are solely Eric's own and do not necessarily represent those of any third parties.