My disk is sda and I have these size files:
/sys/dev/block/8:0/size
/sys/class/block/sda/size
/sys/block/sda/size
Which one should I use? The first one is used by lsblk. Are there any differences?
Check out
ls -l /sys/dev/block/8:0 /sys/class/block/sda /sys/block/sda
You’ll see that all three point to the same directory.
There’s no difference between the files, other than their path.
ls -l on the size files because I expected that. But it didn't work. Have to use realpath next time.
– zomega
Dec 21 '22 at 19:51
If you have a path to a block device file such as /dev/sda, /dev/disk/by-id/whatever, some/path/to/my/loop/device, there are several options to get its size on Linux including:
open() the device and issue the BLKGETSIZE64 ioctl(). That's what blockdev --getsize64 path/to/block/device does.
open() the device and issue the BLKGETSIZE ioctl() like blockdev --getsz path/to/block/device does, and multiply that by 512 (not what the BLKSSZGET ioctl() (as blocksize --getss path/to/block/device) returns).
open() the device, lseek() to the end which will return the current cursor position. For instance, in zsh:
zmodload zsh/system
{ sysseek -w end 0 && print $(( systell(0) )); } < path/to/block/device
Assuming sysfs is mounted in /sys, find the corresponding path to the device file in there, read the size file in there and multiply by 512 (not the values in any of the queue/*size files in there).
For 1 to 3 above, you need at least read or write permission to the block device.
For 4, since the name of the block device file could be anything, the reliable way to identify the /sys path, and what lsblk does as you found out is to rely on the major and minor device numbers which you obtain by doing a stat() call on the path to the block device (for which you only need search access to the parent directory) and then use /sys/dev/block/<major>:<minor> which will be a symlink to the directory in the /sys/devices tree for the block device with <major> and <minor> as major/minor number.
For instance, with zsh:
zmodload zsh/stat
stat -sH s path/to/block/device &&
[[ $s[mode] = b* ]] &&
print $(( $(</sys/dev/block/$(( s[rdev] >> 8 )):$(( s[rdev] & 0xff ))/size) * 512 ))
Or you could just get lsblk to do it for you:
lsblk -nbdo size path/to/block/device
/sys/dev/block/8:0, /sys/class/block/sda and /sys/block/sda are all just symlinks pointing to the same location so it doesn't matter which you use.
$ realpath /sys/dev/block/8:0
/sys/devices/pci0000:00/0000:00:01.2/0000:02:00.1/ata4/host3/target3:0:0/3:0:0:0/block/sda
$ realpath /sys/class/block/sda
/sys/devices/pci0000:00/0000:00:01.2/0000:02:00.1/ata4/host3/target3:0:0/3:0:0:0/block/sda
$ realpath /sys/block/sda
/sys/devices/pci0000:00/0000:00:01.2/0000:02:00.1/ata4/host3/target3:0:0/3:0:0:0/block/sda
lsblk -nbdo size /dev/sdathen you don't need to worry about what path under /sys to use or what unit the value may be in. – Stéphane Chazelas Dec 21 '22 at 10:56