You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

请求协助:将已连接U盘的序列号或PID|VID映射至其挂载点

映射U盘PID/VID/序列号到树莓派挂载点的解决方案

我之前在树莓派上折腾过类似的需求——用libusb拿到U盘的PID/VID、序列号后,关联到它的实际挂载点(比如/media/pi/<flash_drive_name>)。这里分享几个我实际测试可行的方案,主要是通过系统设备信息+挂载文件来关联:

核心思路

U盘的挂载点记录在系统挂载文件中,但我们需要先把libusb拿到的PID/VID、序列号对应到U盘的块设备节点(比如/dev/sda1),再通过设备节点找到挂载点。

方案一:用libudev + 系统挂载文件(推荐,纯C实现)

libudev是Linux下管理设备的官方库,可以直接和libusb配合使用,不需要调用外部命令,稳定性更好。

步骤1:通过PID/VID/序列号找到块设备节点

先写一个函数遍历系统中的块设备,匹配我们从libusb拿到的参数:

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

struct udev_device* find_target_usb_partition(struct udev *udev_ctx, const char *target_vid, const char *target_pid, const char *target_serial) {
    // 创建枚举器,筛选块设备中的分区
    struct udev_enumerate *enumerator = udev_enumerate_new(udev_ctx);
    udev_enumerate_add_match_subsystem(enumerator, "block");
    udev_enumerate_add_match_property(enumerator, "DEVTYPE", "partition");
    udev_enumerate_scan_devices(enumerator);

    struct udev_list_entry *device_entries = udev_enumerate_get_list_entry(enumerator);
    struct udev_list_entry *entry;

    udev_list_entry_foreach(entry, device_entries) {
        const char *sys_path = udev_list_entry_get_name(entry);
        struct udev_device *dev = udev_device_new_from_syspath(udev_ctx, sys_path);
        
        // 提取设备的VID、PID、序列号属性
        const char *dev_vid = udev_device_get_property_value(dev, "ID_VENDOR_ID");
        const char *dev_pid = udev_device_get_property_value(dev, "ID_MODEL_ID");
        const char *dev_serial = udev_device_get_property_value(dev, "ID_SERIAL_SHORT");

        // 匹配目标参数
        if (dev_vid && dev_pid && dev_serial &&
            strcmp(dev_vid, target_vid) == 0 &&
            strcmp(dev_pid, target_pid) == 0 &&
            strcmp(dev_serial, target_serial) == 0) {
            udev_enumerate_unref(enumerator);
            return dev; // 返回匹配到的设备
        }

        udev_device_unref(dev);
    }

    udev_enumerate_unref(enumerator);
    return NULL; // 未找到匹配设备
}

步骤2:通过设备节点获取挂载点

用getmntent函数读取/proc/mounts(系统实时挂载信息),匹配设备节点对应的挂载点:

#include <mntent.h>

char* get_device_mount_point(const char *device_path) {
    FILE *mount_file = setmntent("/proc/mounts", "r");
    if (!mount_file) return NULL;

    struct mntent *mount_entry;
    while ((mount_entry = getmntent(mount_file)) != NULL) {
        // 匹配设备路径
        if (strcmp(mount_entry->mnt_fsname, device_path) == 0) {
            char *mount_point = strdup(mount_entry->mnt_dir);
            endmntent(mount_file);
            return mount_point; // 返回挂载点(需要后续free释放)
        }
    }

    endmntent(mount_file);
    return NULL; // 设备未挂载
}

步骤3:主程序调用示例

int main() {
    // 初始化udev上下文
    struct udev *udev_ctx = udev_new();
    if (!udev_ctx) {
        fprintf(stderr, "Failed to initialize udev context\n");
        return 1;
    }

    // 替换成你从libusb拿到的实际参数
    const char *target_vid = "XXXX";    // 注意是小写十六进制
    const char *target_pid = "XXXX";
    const char *target_serial = "XXXXXXXXXXXXX";

    // 查找目标设备
    struct udev_device *target_dev = find_target_usb_partition(udev_ctx, target_vid, target_pid, target_serial);
    if (target_dev) {
        const char *device_path = udev_device_get_devnode(target_dev);
        printf("Matched device node: %s\n", device_path);

        // 获取挂载点
        char *mount_point = get_device_mount_point(device_path);
        if (mount_point) {
            printf("Mount point: %s\n", mount_point);
            free(mount_point);
        } else {
            printf("This device is not mounted yet\n");
        }

        udev_device_unref(target_dev);
    } else {
        printf("No matching USB device found\n");
    }

    udev_unref(udev_ctx);
    return 0;
}

编译与运行

编译时需要链接libudev库:

gcc -o usb_mount_mapper usb_mapper.c -ludev

运行时可能需要root权限(访问udev信息):

sudo ./usb_mount_mapper

方案二:调用外部工具(快速验证)

如果只是快速验证或者不需要纯C实现,可以用命令行工具组合:

  1. 用udevadm找到设备节点:
udevadm info --query=name --property --match-property=ID_VENDOR_ID=XXXX --match-property=ID_MODEL_ID=XXXX --match-property=ID_SERIAL_SHORT=XXXXXXXXXXXXX
  1. 用findmnt找到挂载点:
findmnt -n -o TARGET /dev/sda1

在C程序中可以通过system()或者popen()调用这些命令,解析输出结果,但稳定性不如纯libudev实现。

注意事项

  • 权限问题:普通用户可能无法访问udev的全部信息,建议程序运行时加sudo,或者添加udev规则赋予普通用户权限。
  • 多分区U盘:如果U盘有多个分区,上面的代码会匹配第一个符合条件的分区,需要根据需求调整筛选逻辑。
  • 参数格式:libudev返回的VID/PID是小写十六进制字符串,要和libusb拿到的格式保持一致(注意大小写)。

内容的提问来源于stack exchange,提问作者MaxWolf

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 23:27:26