在infi.storagemodel的infi.instruct包中定义了一套和C语言结构体相互映射的机制。可以实现使用python调用linux系统调用,并且将调用结果封装成结构体。
以下是一个例子:
一、fcntl.ioctl
fcntl来自于fcntlmodule.so,是python中可以直接import的一个模块,ioctl函数是一个系统调用函数,原型是:
fcntl.ioctl(fd, op[, arg[, mutate_flag]])
- fd:文件句柄
- op:operation code,定义ioctl的执行行为
- args:一个结构体的指针,执行结果将回写到这个结构体中去
执行ioctl需要一个op_code,以及这个操作结果是一个什么样的结构体,op和结构体的对应关系需要发起系统调用的人提前知道。
二、infi中定义一个结构体
现在,我们使用op_code=2,去调用ioctl,将会返回以下的结构体:
#C语言中的定义
struct info{
char a;
int b;
};
在infi中使用python创建一个同样的结构体类,结构体中两个成员,一个char,一个int:
#ioctl_structure.py
from infi.instruct import Struct
from infi.instruct import SNInt32,UBInt8
class Info(Struct):
_fields_=[
#unsigned char=UBInt8
UBInt8('ch'),
SNInt32('In'),
]
三、执行ioctl
参见以下代码:
#导入我们定义的结构体
from ioctl_structure import Info
from array import array
from fcntl import ioctl as _ioctl
import os
#定义op
op_number=2
#size,需要准备几个byte给ioctl,由结构体决定
size = Info.min_max_sizeof().max
print "size: ",size
buffer = array("B", [0]*size)
#获取设备的文件句柄
fd = os.open('/dev/sdb', os.O_RDONLY | os.O_NONBLOCK)
args = [fd, op_number,]
args.extend([buffer, True])
print buffer
#执行ioctl,结构回写在buffer中
result=_ioctl(*args)
print buffer
#通过buffer,生成我们的结构体对象
result_struct=Info.create_from_string(buffer)
print result_struct.ch
print result_struct.In
>>>>>>>>>>>>>>>>>>>>>>>output>>>>>>>>>>>>>>>>>>>
size: 5
#原始buffer
array('B', [0, 0, 0, 0, 0])
#被回写之后的buffer
array('B', [0, 16, 0, 0, 0])
#一个字节的的char,和4个字节的int解析之后的结果(注意,是little-endian的字节序)
0
16