如何识别/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
相关产品推荐
相关产品推荐

