Posted by Jannon Blog on March 13, 2025

方法一:使用udev库接口

#include <libudev.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>

int main() {
    struct udev *udev;
    struct udev_device *dev, *parent_dev;
    struct stat root_stat;

    // 获取根目录的设备信息
    if (stat("/", &root_stat) != 0) {
        perror("无法获取根目录信息");
        return 1;
    }

    // 创建 udev 对象
    udev = udev_new();
    if (!udev) {
        fprintf(stderr, "无法创建 udev 对象\n");
        return 1;
    }

    // 获取根目录对应的设备
    dev = udev_device_new_from_devnum(udev, 'b', root_stat.st_dev);
    if (!dev) {
        fprintf(stderr, "无法获取设备信息\n");
        udev_unref(udev);
        return 1;
    }

    // 获取父设备(硬盘)
    parent_dev = udev_device_get_parent_with_subsystem_devtype(dev, "block", NULL);
    if (!parent_dev) {
        fprintf(stderr, "无法获取父设备信息\n");
        udev_device_unref(dev);
        udev_unref(udev);
        return 1;
    }

    // 获取硬盘的序列号
    const char *serial = udev_device_get_property_value(parent_dev, "ID_SERIAL_SHORT");
    if (serial) {
        printf("根目录所在硬盘的序列号: %s\n", serial);
    } else {
        printf("未找到硬盘序列号\n");
    }

    // 释放资源
    udev_device_unref(dev);
    udev_unref(udev);

    return 0;
}

打印系统中所有硬盘序列号:

#include <libudev.h>
#include <stdio.h>

int main() {
    struct udev *udev;
    struct udev_enumerate *enumerate;
    struct udev_list_entry *devices, *dev_list_entry;
    struct udev_device *dev;

    // 创建 udev 对象
    udev = udev_new();
    if (!udev) {
        fprintf(stderr, "无法创建 udev 对象\n");
        return 1;
    }

    // 枚举块设备
    enumerate = udev_enumerate_new(udev);
    udev_enumerate_add_match_subsystem(enumerate, "block");
    udev_enumerate_scan_devices(enumerate);
    devices = udev_enumerate_get_list_entry(enumerate);

    // 遍历设备
    udev_list_entry_foreach(dev_list_entry, devices) {
        const char *path = udev_list_entry_get_name(dev_list_entry);
        dev = udev_device_new_from_syspath(udev, path);

        // 获取设备名称(如 sda)
        const char *devname = udev_device_get_devnode(dev);
        if (devname) {
            // 获取序列号
            const char *serial = udev_device_get_property_value(dev, "ID_SERIAL");
            if (serial) {
                printf("设备: %s, 序列号: %s\n", devname, serial);
            }
        }

        udev_device_unref(dev);
    }

    // 释放资源
    udev_enumerate_unref(enumerate);
    udev_unref(udev);

    return 0;
}

方法二:使用ioctl接口

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/hdreg.h>

int main() {
    const char *device = "/dev/nvme1n1p2"; // 设备路径
    int fd;
    struct hd_driveid id;

    // 打开设备
    fd = open(device, O_RDONLY);
    if (fd < 0) {
        perror("Failed to open device");
        return 1;
    }

    // 使用 ioctl 获取硬盘信息
    if (ioctl(fd, HDIO_GET_IDENTITY, &id) < 0) {
        perror("Failed to get drive identity");
        close(fd);
        return 1;
    }

    // 打印序列号
    printf("Serial number: %.20s\n", id.serial_no);

    // 关闭设备
    close(fd);
    return 0;
}

方法三:通过文件

#include <stdio.h>
#include <mntent.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <limits.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/hdreg.h>
#include <string>
#include <cstring>
using namespace std;
int main() {
    struct mntent *ent;
    FILE *fp = setmntent("/proc/mounts", "r");
    if (!fp) {
        perror("Failed to open /proc/mounts");
        return 1;
    }
    string dev_path;
    while ((ent = getmntent(fp)) != NULL) {
        if (strcmp(ent->mnt_dir, "/") == 0) {
            printf("根目录挂载设备:%s\n", ent->mnt_fsname);
            dev_path = ent->mnt_fsname;
            break;
        }
    }
    printf("----%s\n",dev_path.c_str());
    endmntent(fp);

     static char parent[256];
    char sysfs_path[PATH_MAX];
    char real_path[PATH_MAX];

    // 提取分区名(如 "/dev/sda1" → "sda1")
    const char *slash = strrchr(dev_path.c_str(), '/');
    if (!slash) return NULL;
    const char *devname = slash + 1;

    // 构造 sysfs 路径(如 /sys/class/block/sda1/..)
    snprintf(sysfs_path, sizeof(sysfs_path), "/sys/class/block/%s/..", devname);

    // 解析父设备的 sysfs 路径
    if (realpath(sysfs_path, real_path) == NULL) return NULL;

    // 提取父设备名(如 /sys/devices/pci0000:00/.../sda → sda)
    const char *parent_name = strrchr(real_path, '/');
    if (!parent_name) return NULL;
    parent_name++;

    snprintf(parent, sizeof(parent), "/dev/%s", parent_name);
    printf("-----%s\n",parent);


    //先找一下文件/sys/block/slash/devices/serial
    string serialFile  = "/sys/block/";
           serialFile += parent_name;
           serialFile += "/device/serial";
    printf("序列号文件:%s\n",serialFile.c_str());
    int Fd;
    char buffer[256];
    ssize_t bytes_read;

    // 打开文件
    Fd = open(serialFile.c_str(), O_RDONLY);
    if (Fd == -1) {
        perror("打开文件失败");
    }

    // 读取内容
    bytes_read = read(Fd, buffer, sizeof(buffer) - 1);
    if (bytes_read == -1) {
        perror("读取文件失败");
        close(Fd);
    }
    else
    {
        // 处理数据
        buffer[bytes_read] = '\0'; // 添加字符串终止符
        printf("设备序列号: %s", buffer);
        close(Fd);
    }
	return 0;
}