使用Pythons ctypes从libc调用uname

时间:2011-06-02 22:14:24

标签: python c ctypes libc uname

tl; dr

这适用于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?


EDIT2:

根据Nemos评论,我试过这个 - 这不起作用,但我认为这可能是朝着正确方向迈出的一步......错误:

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 个答案:

答案 0 :(得分:2)

utsname structure中的字段不是指针;它们是“未指定大小的阵列”。

因此字符串在结构中背靠背打包并以null结尾。

我不知道如何在Python中表示这一点。但我会建议你从uname()以外的其他东西开始实验。 : - )

[更新]

517366245708十进制为0x78756E694C,这是“xuniL”的ascii。这在64位小端机器上实际上是有意义的......

但问题是您正在使用c_char_p创建指针,然后在调用byref()时传递指向的指针。所以uname()填充你的指针(而不是它指向的)。更糟糕的是,它在那里超过8个字节,所以你当前的代码是破坏内存。

你需要弄清楚如何分配一个struct utsname大小的内存块,然后将指向的指针传递给uname()函数,然后弄清楚是什么该块内部的偏移对应于结构中的哪些字段。我不确定Python中有多少甚至是可能的......

[第二次更新]

那更好......但现在你必须查看数组中的偏移量。如果这是典型的Linux系统,则每个字段为65字节(是的,真的)。所以你需要开始在字符串中读取65个字节。我不知道你是否可以就此问题致电string.index ......

答案 1 :(得分:2)

根据this uname man page,结构包含实现定义大小的数组,而不是char *(c_char_p)。你看过sys/utsname.h中的结构定义了吗?您必须匹配确切的结构定义。数据类型可能应为c_char * n,其中 n sys/utsname.h中找到的该字段的数组大小。

或者,您应该能够使用print gnar.raw访问第一个编辑中的所有字符串,只要缓冲区足够大于整个结构。