使用Python的ctypes调用libc中的uname
简而言之
这个在GNU版本的libc下可以运行(我还没试过uclibc)
from ctypes import *
libc = CDLL('libc.so.6')
class uts_struct(Structure):
_fields_ = [ ('sysname', c_char * 65),
('nodename', c_char * 65),
('release', c_char * 65),
('version', c_char * 65),
('machine', c_char * 65),
('domain', c_char * 65) ]
gnar = uts_struct()
libc.uname(byref(gnar))
print gnar.nodename
原帖
下面的代码出现了段错误;我不知道我哪里出错了。
from ctypes import *
libc = CDLL('libc.so.6')
class uts_struct(Structure):
_fields_ = [ ('sysname', c_char_p),
('nodename', c_char_p),
('release', c_char_p),
('version', c_char_p),
('machine', c_char_p) ]
utsname = uts_struct()
libc.uname(byref(utsname))
print utsname.sysname
这个代码做的事情是一样的:
from ctypes import *
libc = CDLL('libc.so.6')
class uts_struct(Structure):
_fields_ = [ ('sysname', c_char_p),
('nodename', c_char_p),
('release', c_char_p),
('version', c_char_p),
('machine', c_char_p) ]
utsname = uts_struct()
utsname_pointer = pointer(utsname)
libc.uname(utsname_pointer)
print utsname.sysname
我肯定是搞错了什么基本的东西...
(我知道有os.uname()
,这只是一个理解的练习,但我失败了)
我参考了这里的uname手册:http://www.cl.cam.ac.uk/cgi-bin/manpage?2+uname
我到底哪里出错了?
编辑:
感谢Nemo,我终于能获取到数据了;
>>> from ctypes import *
>>> libc = CDLL('libc.so.6')
>>> gnar = create_string_buffer(512)
>>> libc.uname(byref(gnar))
0
>>> print gnar.value
Linux
>>>
不过,我猜我只得到了'Linux'是因为这些项是用NULL分隔的,就像一些规范字符串一样。有没有办法读取NULL之后的内容?
编辑2:
根据Nemo的评论,我尝试了这个——虽然不成功,但我觉得这可能是朝着正确方向迈出的一步... 出现了错误:
Traceback (most recent call last):
File "gnar.py", line 18, in <module>
utsname = uts_struct(gnar)
TypeError: incompatible types, c_char_Array_512 instance instead of c_char_p instance
这就完全无法实现了吗?
from ctypes import *
libc = CDLL('libc.so.6')
class uts_struct(Structure):
_fields_ = [ ('sysname', c_char_p),
('nodename', c_char_p),
('release', c_char_p),
('version', c_char_p),
('machine', c_char_p) ]
gnar = create_string_buffer(512)
libc.uname(byref(gnar))
utsname = uts_struct(gnar)
编辑3:(我在追求最长的帖子... =P)
from ctypes import *
libc = CDLL('libc.so.6')
class uts_struct(Structure):
_fields_ = [ ('sysname', c_char * 65),
('nodename', c_char * 65),
('release', c_char * 65),
('version', c_char * 65),
('machine', c_char * 65) ]
gnar = uts_struct()
libc.uname(byref(gnar))
print gnar.machine
这个可以运行,但在打印值后又出现了段错误...
最终编辑:
下面的代码可以运行——我当然是在使用GNU版本的libc。(我在一台Ubuntu机器上)所以添加域的字段就解决了段错误。从现在回想起来,这很有道理。 :)
from ctypes import *
libc = CDLL('libc.so.6')
class uts_struct(Structure):
_fields_ = [ ('sysname', c_char * 65),
('nodename', c_char * 65),
('release', c_char * 65),
('version', c_char * 65),
('machine', c_char * 65),
('domain', c_char * 65) ]
gnar = uts_struct()
libc.uname(byref(gnar))
print gnar.nodename
2 个回答
utsname结构里的字段不是指针,而是“大小不确定的数组”。
这意味着这些字符串是紧挨着放在结构里的,并且以空字符结束。
我不知道怎么在Python中表示这个。不过我建议你先别用uname()来做实验。:-)
[更新]
517366245708这个十进制数是0x78756E694C,它的ASCII表示是"xuniL"。在一个64位的小端机器上,这其实是有道理的……
但问题是你用c_char_p创建了一个指针,然后在调用byref()时又传递了一个指向那个的指针。所以uname()是在填充你的指针(而不是它指向的内容)。更糟糕的是,它放入的内容超过了8个字节,这样你的代码就会破坏内存。
你需要弄清楚怎么分配一块和struct utsname
大小相同的内存,然后把指向那块内存的指针传给uname()函数,接着找出那块内存中各个字段对应的偏移量。我不确定在Python中这有多少是可能的……
[第二次更新]
这样好一些……但现在你得查看数组中的偏移量。如果这是一个典型的Linux系统,每个字段是65个字节(没错,真的)。所以你需要开始从字符串中读取65个字节。我不知道你是否可以在这个东西上调用string.index
……
根据这个 uname 手册页面,这个结构体里包含的是一些大小由实现决定的数组,而不是字符指针(c_char_p)。你有没有查看过sys/utsname.h
里的结构体定义?你需要确保你的定义和它完全一致。数据类型可能应该是c_char * n
,其中n是sys/utsname.h
中那个字段的数组大小。
另外,只要缓冲区足够大,可以容纳整个结构体,你应该可以通过print gnar.raw
来访问你第一次编辑中的所有字符串。