Linux – How to detect whether a hard drive is external USB or internal

hard drivelinuxusb

I want to detect whether a drive is external or internal. I have an SATA drive connected to a USB port through an SATA-USB adapter.

hdparm -I reports it as:

ATA device, with non-removable media
...
Transport: Serial, ATA8-AST, SATA 1.0a, SATA II Extensions, SATA Rev 2.5, SATA Rev 2.6, SATA Rev 3.0.

It apparently gets this data directly from the drive. Is it possible for hdparm to detect the actual transport layer, instead of the one the drive reports?

I also tried lsusb. It doesn't seem to be useful. It is human readable, but there is no way to cross-reference its output with other device commands. Iterating through buses with lsusb -D /dev/bus/usb/... doesn't seem appropriate, either, although maybe I could do something like find /dev/bus | while read -r line; do if((lsusb -D $line | grep) CONTAINS SOME SUBSTRING MENTIONING THE DEVICE) then blah done

parted --list also fails to report the fact that the external drive is running over USB:

Model: ADATA SU 800 (scsi)

Best Answer

I can tell like this:

$ realpath /sys/block/sd*
/sys/devices/pci0000:00/0000:00:1f.2/ata1/host0/target0:0:0/0:0:0:0/block/sda
/sys/devices/pci0000:00/0000:00:1f.2/ata2/host1/target1:0:0/1:0:0:0/block/sdb
/sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0/host6/target6:0:0/6:0:0:0/block/sdc

Notes:

  • If not realpath then readlink may give you a clue.
  • Query about a specific device, some of them (like above) or all of them (/sys/block/*).
  • In my Kubuntu /sys/class/block/ contains entries for partitions as well (e.g. sda1).

POSIX solution:

$ for p in /sys/block/sd*; do (cd "$p" && pwd -P); done
/sys/devices/pci0000:00/0000:00:1f.2/ata1/host0/target0:0:0/0:0:0:0/block/sda
/sys/devices/pci0000:00/0000:00:1f.2/ata2/host1/target1:0:0/1:0:0:0/block/sdb
/sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0/host6/target6:0:0/6:0:0:0/block/sdc
Related Question