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

如何识别/dev/sd*设备对应的物理USB端口(Busybox嵌入式环境)

识别USB U盘对应物理端口的C实现方案(Busybox嵌入式系统)

优先方案:基于sysfs的非systemd/udev实现

Busybox嵌入式系统通常默认挂载sysfs,可通过读取sysfs中的设备层级信息,关联块设备(/dev/sda、/dev/sdb)到物理USB端口。

核心思路

每个块设备(如sda)在sysfs中的路径为/sys/class/block/sda,通过device符号链接可追溯到对应的USB主机控制器和端口节点,最终从port或physical_port属性中提取物理端口标识。

C程序示例

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <unistd.h>

#define SYS_BLOCK_PATH "/sys/class/block"
#define MAX_PATH_LEN 256

// 获取设备对应的物理USB端口编号
int get_usb_physical_port(const char *block_dev, char *port_str, int len) {
    char dev_path[MAX_PATH_LEN];
    char real_path[MAX_PATH_LEN];
    char *port_ptr;

    // 拼接sysfs中的块设备路径
    snprintf(dev_path, MAX_PATH_LEN, "%s/%s/device", SYS_BLOCK_PATH, block_dev);
    if (readlink(dev_path, real_path, MAX_PATH_LEN) == -1) {
        perror("readlink failed");
        return -1;
    }

    // 查找路径中的"port"节点(USB 3.0设备路径通常包含类似"usbX/XX/portX"的结构)
    port_ptr = strstr(real_path, "/port");
    if (!port_ptr) {
        // 尝试查找"physical_port"(部分平台可能用这个字段)
        char phys_port_path[MAX_PATH_LEN];
        snprintf(phys_port_path, MAX_PATH_LEN, "%s/physical_port", dev_path);
        FILE *fp = fopen(phys_port_path, "r");
        if (!fp) {
            fprintf(stderr, "Cannot find port info for %s\n", block_dev);
            return -1;
        }
        if (fgets(port_str, len, fp) == NULL) {
            fclose(fp);
            return -1;
        }
        // 去掉换行符
        port_str[strcspn(port_str, "\n")] = '\0';
        fclose(fp);
        return 0;
    }

    // 提取port后面的数字
    strncpy(port_str, port_ptr + 1, len);
    port_str[strcspn(port_str, "/")] = '\0';
    return 0;
}

int main() {
    DIR *dir = opendir(SYS_BLOCK_PATH);
    struct dirent *entry;
    char port_str[32];

    if (!dir) {
        perror("opendir failed");
        return EXIT_FAILURE;
    }

    printf("Block Device -> Physical USB Port\n");
    printf("---------------------------------\n");

    while ((entry = readdir(dir)) != NULL) {
        // 只处理sd开头的块设备(排除分区如sda1)
        if (strncmp(entry->d_name, "sd", 2) == 0 && strlen(entry->d_name) == 3) {
            if (get_usb_physical_port(entry->d_name, port_str, sizeof(port_str)) == 0) {
                printf("/dev/%s      -> %s\n", entry->d_name, port_str);
            }
        }
    }

    closedir(dir);
    return EXIT_SUCCESS;
}

说明

  • 编译时直接用Busybox系统的交叉编译器,比如arm-linux-gcc usb_port_detect.c -o usb_port_detect
  • 不同平台的sysfs路径结构可能略有差异,若port字段不存在,可检查/sys/class/block/sdX/device/../路径下的busnum、devnum或physical_location等属性,适配调整代码
  • 需确保程序以root权限运行,否则可能无法读取sysfs中的部分文件

备用方案:基于systemd/udev的实现

若系统支持udev,可通过调用udevadm工具获取设备的物理端口信息,在C程序中通过popen执行命令并解析输出:

示例代码片段

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

void get_port_via_udev(const char *block_dev) {
    char cmd[MAX_PATH_LEN];
    char buf[MAX_PATH_LEN];
    FILE *fp;

    snprintf(cmd, MAX_PATH_LEN, "udevadm info --query=property --name=/dev/%s | grep ID_PATH", block_dev);
    fp = popen(cmd, "r");
    if (!fp) {
        perror("popen failed");
        return;
    }

    while (fgets(buf, MAX_PATH_LEN, fp) != NULL) {
        // ID_PATH通常包含物理端口信息,比如"pci-0000:01:00.0-usb-0:1:1.0-scsi-0:0:0:0"
        printf("/dev/%s -> %s", block_dev, buf);
    }

    pclose(fp);
}

说明

  • 需确保系统安装了udevadm工具,且ID_PATH属性包含可识别的物理端口标识
  • 该方案依赖systemd/udev环境,仅在非sysfs方案无法适配时使用

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 05:52:39