Python调用ioctl报FileNotFoundError但C代码同参数可正常运行
Python调用ioctl返回FileNotFoundError但设备文件实际存在的问题
我正在为一款通过ioctl通信的设备开发Python驱动,参考厂商提供的C示例代码,但卡在客户端连接调用上。Python中调用ioctl时返回FileNotFoundError: [Errno 2] No such file or directory,但该文件实际存在且我有访问权限(同款逻辑的C代码可正常运行)。
已做的尝试:
- 使用无效文件描述符(比如1/2)会出现其他错误,说明程序能识别文件描述符,但仍提示文件不存在
- 试过用
os.fdopen将io.File对象传入fcntl.ioctl,结果一致 - 从C代码中打印出request整数和返回结构体的大小,确保Python与C的ioctl调用参数完全一致
- 确认文件描述符已正常打开且活跃(通过
lsof验证)
C代码及输出
//c code int pse_client_connect(void) { int fd, ret; struct ishtp_cc_data cc_data; // Prep input connection data memcpy(&(cc_data.in_client_uuid), &pse_smhi_guid, sizeof(pse_smhi_guid)); // Open the pse character device for operations fd = open(PSE_CHRDEV, O_RDWR); printf("File Descriptor: %i\n", fd); printf("Size of Struct: %li\n",sizeof(cc_data)); printf("Request Int: %li\n", IOCTL_ISHTP_CONNECT_CLIENT); if (fd <= 0) { printf("Failed to open the pse device file\nAre you running as root?\n"); return fd; } // Send the connection IOCTL ret = ioctl(fd, IOCTL_ISHTP_CONNECT_CLIENT, &cc_data); if (ret) { printf("Failed to connect to the PSE over ISHTP/HECI\n"); return ret; } return fd; }
输出:
File Descriptor: 3 Size of Struct: 16 Request Int: 3222292481
Python代码及输出
#Python Code import fcntl, array, os def pse_client_connect(): device_file=os.open("/dev/pse", os.O_RDWR) print(device_file) if (device_file <= 0): print("Failed to open the pse device file\nAre you running as root?\n") buf = array.array('B', [0]*16) ret = fcntl.ioctl(device_file,3222292481,buf,True ) print(buf) os.close(device_file) if __name__ == "__main__": pse_client_connect()
输出:
(base) root@host:/# python main.py 3 Traceback (most recent call last): File "/home/tech/Downloads/pse_heci/py_example/main.py", line 14, in <module> pse_client_connect() File "/home/tech/Downloads/pse_heci/py_example/main.py", line 9, in pse_client_connect ret = fcntl.ioctl(device_file,3222292481,buf,True ) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ FileNotFoundError: [Errno 2] No such file or directory
文件描述符验证
(base) root@host:/# sudo lsof | grep "/dev/pse" python 311743 root 3u CHR 239,0 0t0 413 /dev/pse (base) root@host:/# sudo lsof | grep "/dev/pse" dio 320841 root 3u CHR 239,0 0t0 413 /dev/pse
期望:ioctl能填充buf对象,之后可解析为预期的结构体,现在陷入僵局。
解决方法
这个错误的核心原因是Python的fcntl.ioctl处理32位/64位ioctl请求码时的符号扩展问题:你从C代码中拿到的3222292481是无符号整数,但Python会将其当作有符号整数处理,导致请求码被内核错误解析,最终返回误导性的"文件不存在"错误。
具体修复步骤:
修正ioctl请求码的传递方式:
直接使用十六进制表示请求码0xC0084801(与十进制3222292481等价),或者用3222292481 & 0xFFFFFFFF确保它被当作无符号32位值传递给内核。初始化结构体输入数据:
C代码中通过memcpy将pse_smhi_guid写入了结构体的in_client_uuid字段,但你的Python代码中buf是全0数组,缺少必要的输入数据,这会导致内核处理失败。需要先将UUID写入buf的对应位置。
修改后的Python代码示例:
import fcntl, array, os # 替换为实际的pse_smhi_guid字节数据(16字节) pse_smhi_guid = b'\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF' def pse_client_connect(): device_file = os.open("/dev/pse", os.O_RDWR) print(device_file) if device_file <= 0: print("Failed to open the pse device file\nAre you running as root?\n") return # 用UUID初始化buf,保证输入数据与C代码一致 buf = array.array('B', pse_smhi_guid) # 使用十六进制请求码避免符号扩展问题 ioctl_request = 0xC0084801 try: ret = fcntl.ioctl(device_file, ioctl_request, buf, True) print("ioctl返回值:", ret) print("填充后的buf:", buf) finally: os.close(device_file) if __name__ == "__main__": pse_client_connect()
额外说明:
- Linux内核的ioctl请求码有固定格式,包含数据方向、大小、类型、编号,用十六进制直接传递能避免数值解析错误。
- 必须保证buf的大小与C语言中
struct ishtp_cc_data的大小完全一致,且输入数据初始化正确,否则内核可能返回其他错误。
内容的提问来源于stack exchange,提问作者Braedon
相关产品推荐
相关产品推荐

