linux下如何通过对应的文件获取磁盘的序列号?

linux下如何通过对应的文件获取磁盘的序列号?

我知道对于linux中的一个磁盘,我们可以使用诸如hdparm或之类的命令smartctl来获取它的基本信息。但对于这些命令的实现,我认为它们都是通过读取linux中磁盘的相应文件来实现的。例如,要获取设备的大小/dev/sda,我们可以使用或cat /sys/block/sda/size之类的命令来代替。那么问题是如何通过直接读取磁盘对应的文件来获取磁盘的序列号。hdparmsmartctl

答案1

我只是尝试一下。它确实通过 ioctl 获取序列号。这是 strace 的一些输出:

open("/dev/sda", O_RDONLY|O_NONBLOCK)   = 3
fcntl(3, F_SETFD, FD_CLOEXEC)           = 0
ioctl(3, SG_IO, {'S', SG_DXFER_FROM_DEV, cmd[6]=[12, 00, 00, 00, 24, 00], mx_sb_len=32, iovec_count=0, dxfer_len=36, timeout=20000, flags=0, data[36]=["\0\0\5\2[\0\0\0ATA     WDC WD5000LPVX-0"...], status=00, masked_status=00, sb[0]=[], host_status=0, driver_status=0, resid=0, duration=0, info=0}) = 0
ioctl(3, SG_IO, {'S', SG_DXFER_FROM_DEV, cmd[16]=[85, 08, 0e, 00, 00, 00, 01, 00, 00, 00, 00, 00, 00, 00, ec, 00], mx_sb_len=32, iovec_count=0, dxfer_len=512, timeout=20000, flags=0, data[512]=["zB\377?7\310\20\0\0\0\0\0?\0\0\0\0\0\0\0    W -DXW11"...], status=00, masked_status=00, sb[0]=[], host_status=0, driver_status=0, resid=0, duration=0, info=0}) = 0
ioctl(3, SG_IO, {'S', SG_DXFER_FROM_DEV, cmd[16]=[85, 08, 0e, 00, 00, 00, 01, 00, 00, 00, 00, 00, 00, 00, ec, 00], mx_sb_len=32, iovec_count=0, dxfer_len=512, timeout=20000, flags=0, data[512]=["zB\377?7\310\20\0\0\0\0\0?\0\0\0\0\0\0\0    W -DXW11"...], status=00, masked_status=00, sb[0]=[], host_status=0, driver_status=0, resid=0, duration=0, info=0}) = 0

答案2

这是可能的,至少在我的系统上是这样。该解决方案依赖于/run/udev/data转储数据。

下面是一个 bash 脚本示例:

#!/bin/bash

IFS=$'\n' read -d '' -r -a DRIVES <<< "$(ls /dev/sd*[0-9] 2>/dev/null)"
IFS=$'\n' read -d '' -r -a NVME_DRIVES <<< "$(ls /dev/nvme*[0-9]n[0-9] 2>/dev/null)"

DRIVES+=("${NVME_DRIVES[@]}")

for drive in "${DRIVES[@]}"; do
  drive=${drive##*/}
  IFS=$'\n' read -d '' -r -a _uevent <<< "$(grep -e "MAJOR" -e "MINOR" "/sys/class/block/${drive}/uevent"| sort | awk -F "=" '{print $2}')"
  _serial=$(grep "ID_SERIAL=" "/run/udev/data/b${_uevent[0]}:${_uevent[1]}" | awk -F "=" '{print $2}')

  echo "[${drive}] serial: ${_serial}  short: ${_serial##*_}"
done

该脚本的逻辑如下:

  • 获取系统中的驱动器列表
  • 读取每个驱动设备的块地址
  • 从 udev 元数据中获取数据

步骤是从 strace 中扣除的lsblk --nodeps -no serial /dev/sda

答案3

您可以使用 strace 来了解 smartctl 如何获取磁盘的序列号。 CMD 行如下:strace smartctl -a /dev/sda。也许它只是通过 ioctl 获取序列号。

答案4

在 Linux 上磁盘 sda:

egrep '^E:ID_SERIAL' /run/udev/data/b$(basename $(readlink --canonicalize /sys/block/sda/bdi))
E:ID_SERIAL=Samsung_SSD_850_EVO_500GB_S3R3NF0JA99600T
E:ID_SERIAL_SHORT=S3R3NF0JA99600T
日期 && uname --kernel-release
2021 年太平洋夏令时间 11 月 2 日星期二上午 11:50:37
5.13.0-20-通用

相关内容