符号链接上的意外 ioctl 行为

Posted

技术标签:

【中文标题】符号链接上的意外 ioctl 行为【英文标题】:Unexpected ioctl behavior on symlinks 【发布时间】:2016-12-13 10:57:43 【问题描述】:

我目前正在使用 HID 设备。它有两种设置模式:HID 和 RS232。所以我写了一个小脚本把他切换到 RS232,每当它作为 HID 设备插入时,使用这个 udev 规则:

ENVID_VENDOR=="Vendor", ENVID_VENDOR_ID=="001d", ENVID_USB_DRIVER=="usbhid",\
SYMLINK+="hid_device", RUN+="/path/to/HID_to_serial"

脚本如下:

// HID_to_serial.c
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>

//#define DEFAULT_DEVICE_PATH   "/dev/hidraw0"
#define DEFAULT_DEVICE_PATH     "/dev/hid_device"

int main(int argc, char **argv)

  int fd = open(DEFAULT_DEVICE_PATH, O_RDWR);

  if (fd < 0)
  
      perror("Unable to open device");
      return 1;
  

  // Very specific report descriptor
  const char buf[64] =   0x02, 0x0b, 0x02, 0x04, 0x42, 0x40, 0x10, 0x42,
                          0x62, 0x10, 0x42, 0x42, 0x03, 0x00, 0x00, 0x00,
                          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ;

  int res = ioctl(fd, _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x06, 64), buf);
  if (res < 0)
      perror("ioctl");
  else
      printf("Device was succesfully switched back to serial mode!\n");

  return 0;

现在,通常,当我插入设备时,Linux 会给它/dev/hidraw0 文件。当我在/dev/hidraw0 上使用我的脚本时,它运行良好。脚本中使用的报告描述符是正确的,一切正常:HID 设备切换回 RS232 模式。

但是,当我尝试在 udev 规则创建的 /dev/hid_device 符号链接上使用我的脚本时,它在 99% 的情况下都不起作用,告诉我 ioctl: Invalid argument。更奇怪的是,它有效,但只有 1% 的时间(可能更频繁)。

有谁知道这可能来自哪里,以及如何解决它或解决它?提前致谢。

【问题讨论】:

【参考方案1】:

我发现了问题。

这在我的 udev 规则中:不够精确。

当我插入设备时,linux 在/dev/ 中创建两个character special 设备文件:hidraw0input/event15(在我的情况下)。它们共享许多环境值,例如它们的ID_VENDOR_IDID_USB_DRIVER。但是,它们不共享相同的MAJOR

所以我所做的是在我的 udev 规则中添加 ENVMAJOR=="correct_major",现在我的符号链接链接到正确的设备文件。

这也解释了为什么它有时会起作用:我猜是由于 udev 规则中缺乏细节,有时符号链接链接到正确的设备文件,有时没有。

【讨论】:

以上是关于符号链接上的意外 ioctl 行为的主要内容,如果未能解决你的问题,请参考以下文章

通过 rpmbuild 打包符号链接?

如何列出 NTFS 文件系统上的所有符号链接

符号链接和硬链接有啥区别?

硬链接到带有 Win32 API 的符号链接?

共享主机上的Laravel存储符号链接

新安装的 XAMPP for Linux 上的“符号链接不允许或链接目标不可访问”