Get unique serial number of USB device mounted to /dev folder
Just ran into this same problem and it took a bit to find the solution. Any solution which starts with «just use lsusb» is incorrect. You can figure out the devices serial, but none of the extra information it provides help you determine which /dev/video it links to.
/bin/udevadm info --name=/dev/video1 | grep SERIAL_SHORT
E: ID_SERIAL_SHORT=256DEC57
@debuti This problem came from your USB devices. They were produced with same serial number or they haven’t serial number capability which cause the same serial number. You can reconfigure their serial number for some hardware. For example you can use CP210xSetIDs.exe if you are using CP2102 USB to UART.
Based on the hint of using udevadm and the tutorial from http://www.signal11.us/oss/udev/ I got below code to get the serial info of my webcam.
#include "stdio.h" #include int main(int argc, char **argv) < struct udev *udev; struct udev_device *dev; struct udev_enumerate *enumerate; struct udev_list_entry *list, *node; const char *path; udev = udev_new(); if (!udev) < printf("can not create udev"); return 0; >enumerate = udev_enumerate_new(udev); udev_enumerate_add_match_subsystem(enumerate, "video4linux"); udev_enumerate_scan_devices(enumerate); list = udev_enumerate_get_list_entry(enumerate); udev_list_entry_foreach(node, list) < path = udev_list_entry_get_name(node); dev = udev_device_new_from_syspath(udev, path); printf("Printing serial for %s\n", path); printf("ID_SERIAL=%s\n", udev_device_get_property_value(dev, "ID_SERIAL")); printf("ID_SERIAL_SHORT=%s\n", udev_device_get_property_value(dev, "ID_SERIAL_SHORT")); udev_device_unref(dev); >return 0; >
You can use lsusb , but you need to add verbose flag and make sure you use sudo with it, otherwise the serial will be incorrect.
If that is too verbose, then run lsusb to get the device id:
$ lsusb Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub Bus 001 Device 012: ID 1ab1:0e11 Rigol Technologies Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Then run lsusb with device flag and grep the serial number.
So for the serial number of Rigol device:
$ sudo lsusb -s 012 -v|grep -i iserial iSerial 3 DP8C221100000
Thanks! This reply deserves to receive a lot more attention IMO, because it (ie lsusb with the verbose flag) is likely to be what a lot of people coming here are looking for 🙂
Playing around with libusb, it looks like there’s a standard getSerialNumber() method. Unfortunately, not all USB devices implement this. I have a couple cheap $4 webcams that return None for it. These interfaces expose other metadata, like VendorID and ProductID, which I’ve seen some code try and use as a unique identifier, but it’s not guaranteed to be unique, especially if you have multiple devices of the same make and model.
But assuming you get a serial number for your device, the next problem is figuring out which /dev/videoN file it corresponds to. I have an old version of libusb installed, so I couldn’t get the method working that returned the full sysfs path of the USB device, so instead I scrapped the output from hwinfo . I extracted all the chunks corresponding to cameras, and then from those I extracted the piece that looked like:
USB devices actually form a complicated tree, and that BusID encodes where the device is located in that tree.
You can then take that BusID to find where the device lives in the filesystem as well as the video path, which should be at:
/sys/bus/usb/devices//video4linux/
That’s a directory, and inside it you’ll find a videoN file matching one in /dev.
USB serial number not shown with lsusb -v command
I have a USB-Stick from which I would like to read the serial number. If I invoke the command lsusb -v the output in the line iSerial is as follows:
Host scsi10: usb-storage Vendor: USB Product: Disk 2.0 Serial Number: 92071573E1272519149 Protocol: Transparent SCSI Transport: Bulk Quirks:
Why is there no serial output with the lsusb command on the one hand, but on the other hand I get a serial number from /proc/scsi/usb-storage . Where is the difference between the two methods to gather the serial?
3 Answers 3
lsusb may try to open the USB device as O_RDWR (read/write mode) and your user might not have the rights to do this (some error message «Couldn’t open device, some information will be missing» should be inbetween the output, if so). Started as root lsusb should also be able to output the whole iSerial value.
There are lots of different USB devices in general (keyboard, mice, webcams, . ). lsusb deals with the connected devices on the USB protocol level.
Some USB device are storage devices (USB sticks, USB harddisks, . ). They understand a different protocol (more or less SCSI) on top of the USB protocol. Within this protocol, an USB storage device has a serial number (as does an ATA device). This is what you see in /proc/scsi/usb-storage .
The iSerial number you see in lsusb has nothing to do with it.
So that’s why you see the serial number you are interested in with one method, but not with the other method. And that’s why you can’t use lsusb to get the kind of serial number you are interested in
You can use lsusb with verbose flag, but you need to make sure you use sudo with it, otherwise the serial will be incorrect.
If that is too verbose, then run lsusb to get the device id:
$ lsusb Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub Bus 001 Device 012: ID 1ab1:0e11 Rigol Technologies Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Then run lsusb with -s flag to show only specified device and grep for the serial number.
So for the serial number of Rigol device:
$ sudo lsusb -s 012 -v|grep -i iserial iSerial 3 DP8C221100000
For more information on lsusb use the —help flag:
$ lsusb --help Usage: lsusb [options]. List USB devices -v, --verbose Increase verbosity (show descriptors) -s [[bus]:][devnum] Show only devices with specified device and/or bus numbers (in decimal) -d vendor:[product] Show only devices with the specified vendor and product ID numbers (in hexadecimal) -D device Selects which device lsusb will examine -t, --tree Dump the physical USB device hierarchy as a tree -V, --version Show version of program -h, --help Show usage and help
How to check serial number of NVMe disk?
However it does not work for NVMe disks (nvme0n0, nvme0n1 etc). No information about serial number is provided.
Note that newer versions of lsblk (e.g. mine is from util-linux 2.33.1) do return the serial number for NVMe disks too.
4 Answers 4
The nvme tool provides options to obtain NVME device information, for example, to install the tool, list the NVME devices and look at the id control fields on /dev/nvme0n1, one would use:
sudo apt-get install nvme-cli sudo nvme list sudo nvme id-ctrl /dev/nvme0n1
You can use good old sysfs and cat for that:
$ cat /sys/block/nvme0n1/device/serial PHNH912345441P0B
Also as @VZ pointed out modern versions of lsblk will output serial numbers for NVMe drives correctly. Example:
$ lsblk -d -o TRAN,NAME,TYPE,MODEL,SERIAL,SIZE TRAN NAME TYPE MODEL SERIAL SIZE mmcblk0 disk 0xda61bcdf 14.6G mmcblk0boot0 disk 0xda61bcdf 4M mmcblk0boot1 disk 0xda61bcdf 4M nvme nvme0n1 disk INTEL SSDPEKNW010T8 PHNH912345441P0B 953.9G
Note that there are two kinds of M.2 drives — the NVMe and the SATA — and they present completely different interfaces.
This is as evidenced by the completely different dev device name: /dev/sd? for SATA, and /dev/nvme0n1 for NVMe.
If you download smartmontools 6.6, it has experimental NVMe support built in and can show serial number as I remember. ( smartctl -a , again IIRC).
Otherwise, for NVMe drives you indeed need the nvme-cli tools to be able to do anything more than smartctl can do.
USB-drive serial number under linux C++
Is there any way to determine s/n of usb-drive in linux using C++ ? If not C++ is there any other way different from hwinfo -disk and hdparm -i ?
4 Answers 4
I’ll try to summarize my experience regarding storage drive serial number retrieval on linux.
I assume you want the serial number of the storage device identity (as per SCSI specification) not the serial number of the USB device (as per USB specification under Device Descriptor ), these two are different entities.
NOTICE!
Most devices tend to implement a serial number in the USB-Controller and leave the serial number of the inner SCSI-disk unimplemented.
So if you want to uniquely identify an USB-device the best way is to create a string from the Device Descriptor (USB specification) like VendorId-ProductId-HardwareRevision-SerialNumber
In the following I shall describe how to retrieve the SN of the storage drive, as asked.
Drives fall in 2 categories (actually more, but let’s simplify): ATA-like (hda, hdb . ) and SCSI-like (sda sdb . ). USB drives fall in the second category, they are called SCSI attached disks. In both situation ioctl calls can be used to retrieve the required information (in our case the serial number).
For SCSI devices (and these include USB drives) the Linux generic driver and it’s API is documented at tldp.
The serial number on SCSI devices is available inside the Vital Product Data (short: VPD) and is retrievable by using the SCSI Inquiry Command. A commad line utility in linux that can fetch this VPD is sdparm:
> yum install sdparm > sdparm --quiet --page=sn /dev/sda Unit serial number VPD page: 3BT1ZQGR000081240XP7
Note that not all devices have this serial number, the market is flooded with cheep knockoffs, and some usb flash disks return strange serials (for example my sandisk cruzer returns just the letter «u»). To overcome this some people choose to create a unique identifier by mixing different strings from VPD like Product ID, Vendor ID and Serial Number.
#include #include #include #include #include #include #include #include #include int scsi_get_serial(int fd, void *buf, size_t buf_len) < // we shall retrieve page 0x80 as per http://en.wikipedia.org/wiki/SCSI_Inquiry_Command unsigned char inq_cmd[] = ; unsigned char sense[32]; struct sg_io_hdr io_hdr; int result; memset(&io_hdr, 0, sizeof (io_hdr)); io_hdr.interface_id = 'S'; io_hdr.cmdp = inq_cmd; io_hdr.cmd_len = sizeof (inq_cmd); io_hdr.dxferp = buf; io_hdr.dxfer_len = buf_len; io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; io_hdr.sbp = sense; io_hdr.mx_sb_len = sizeof (sense); io_hdr.timeout = 5000; result = ioctl(fd, SG_IO, &io_hdr); if (result < 0) return result; if ((io_hdr.info & SG_INFO_OK_MASK) != SG_INFO_OK) return 1; return 0; >int main(int argc, char** argv) < char *dev = "/dev/sda"; char scsi_serial[255]; int rc; int fd; fd = open(dev, O_RDONLY | O_NONBLOCK); if (fd < 0) < perror(dev); >memset(scsi_serial, 0, sizeof (scsi_serial)); rc = scsi_get_serial(fd, scsi_serial, 255); // scsi_serial[3] is the length of the serial number // scsi_serial[4] is serial number (raw, NOT null terminated) if (rc < 0) < printf("FAIL, rc=%d, errno=%d\n", rc, errno); >else if (rc == 1) < printf("FAIL, rc=%d, drive doesn't report serial number\n", rc); >else < if (!scsi_serial[3]) < printf("Failed to retrieve serial for %s\n", dev); return -1; >printf("Serial Number: %.*s\n", (size_t) scsi_serial[3], (char *) & scsi_serial[4]); > close(fd); return (EXIT_SUCCESS); >
For the sake of completness i’ll also provide the code to retrieve the serial number for ATA devices (hda, hdb . ). This will NOT work for USB devices.
#include #include #include #include #include #include #include #include #include int main() < struct hd_driveid *id; char *dev = "/dev/hda"; int fd; fd = open(dev, O_RDONLY|O_NONBLOCK); if(fd < 0) < perror("cannot open"); >if (ioctl(fd, HDIO_GET_IDENTITY, id) < 0) < close(fd); perror("ioctl error"); >else < // if we want to retrieve only for removable drives use this branching if ((id->config & (1 command_set_1 & 4)) < close(fd); printf("Serial Number: %s\n", id->serial_no); > else < perror("support not removable"); >close(fd); > >
Extract the Linux serial number without sudo
It is possible to extract the Linux serial number without using sudo? I know it is possible to do in Windows: wmic bios get serialnumber and in macOS: system_profiler | grep «r (system)» . Both of them do not require root privileges. In Linux this can be used: sudo dmidecode -s system-serial-number , but it needs sudo. Is there another way?
3 Answers 3
dmidecode reads this information from physical memory, using /dev/mem , which requires root.
The same information is also provided by the Linux kernel via sysfs in a virtual directory, /sys/devices/virtual/dmi/id .
Unfortunately, someone decided that all information in that virtual directory is open to anyone for reading, just not the serial numbers:
$ ls -l /sys/devices/virtual/dmi/id -r--r--r-- 1 root root 4096 Nov 25 17:12 bios_date -r--r--r-- 1 root root 4096 Nov 14 14:59 bios_vendor -r--r--r-- 1 root root 4096 Nov 25 17:12 bios_version -r--r--r-- 1 root root 4096 Nov 25 17:12 board_asset_tag -r--r--r-- 1 root root 4096 Nov 25 17:12 board_name -r-------- 1 root root 4096 Nov 25 17:12 board_serial -r--r--r-- 1 root root 4096 Nov 14 14:59 board_vendor -r--r--r-- 1 root root 4096 Nov 25 17:12 board_version -r--r--r-- 1 root root 4096 Nov 25 17:12 chassis_asset_tag -r-------- 1 root root 4096 Nov 25 17:12 chassis_serial -r--r--r-- 1 root root 4096 Nov 25 17:12 chassis_type -r--r--r-- 1 root root 4096 Nov 25 17:12 chassis_vendor -r--r--r-- 1 root root 4096 Nov 25 17:12 chassis_version -r--r--r-- 1 root root 4096 Nov 25 17:12 modalias drwxr-xr-x 2 root root 0 Nov 25 17:12 power -r--r--r-- 1 root root 4096 Nov 14 14:59 product_name -r-------- 1 root root 4096 Nov 25 17:12 product_serial -r-------- 1 root root 4096 Nov 14 14:59 product_uuid -r--r--r-- 1 root root 4096 Nov 14 14:59 product_version lrwxrwxrwx 1 root root 0 Nov 14 14:59 subsystem -> ../../../../class/dmi -r--r--r-- 1 root root 4096 Nov 14 14:59 sys_vendor -rw-r--r-- 1 root root 4096 Nov 14 14:59 uevent
If you can install package hal (not installed by default on recent Ubuntu versions), this command will work for you as non-root:
lshal | grep system.hardware.serial system.hardware.serial = '' (string)
This works because package hal installs the hald daemon, which runs as root and collects this data, making it possible for lshal to read it as non-root.