使用 Python ctypes 从 libc 调用 uname

发布于 2024-11-11 16:00:46 字数 3758 浏览 9 评论 0原文

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吗?


编辑2:

根据 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

tl;dr

this works with the GNU version of libc (haven't tried it with uclibc yet)

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

Original post

The following code segfaults; I'm not sure what I'm doing wrong.

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

This does the same thing:

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

I must be messing up something basic...

(I am aware of os.uname(), this is just an exercise in understanding, which I am failing)

I referenced the uname manual here: http://www.cl.cam.ac.uk/cgi-bin/manpage?2+uname

What am I doing wrong?


Edit:

Thanks to Nemo I'm able to get the data;

>>> from ctypes import *
>>> libc = CDLL('libc.so.6')
>>> gnar = create_string_buffer(512)
>>> libc.uname(byref(gnar))
0
>>> print gnar.value
Linux
>>> 

However, I'm assuming I'm only getting 'Linux' because the items are NULL delimited, as are regulator strings. Any way to read past the NULL?


Edit2:

Based on Nemos comment, I've tried this- which doesn't work, but I thought it might be a step in the right direction... errors with:

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

Is this just un-doable?

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)

Edit3: ( im going for the longest post ever... =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

This works, however, it segfaults after it prints the value...


Final edit:

The following works- I am of course using the GNU version of libc. (im on an Ubuntu machine) so adding the field for the domain is all it took to stop the segfault. It makes sense in hind sight. :)

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

梦中楼上月下 2024-11-18 16:00:46

根据 此 uname 手册页,该结构包含实现定义大小的数组,而不是 char *(c_char_p)。您看过 s​​ys/utsname.h 中的结构定义吗?您必须匹配准确的结构定义。数据类型可能应为 c_char * n,其中 n 是在 sys/utsname.h 中找到的该字段的数组大小。

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

According to this uname man page, The structure contains arrays of implementation-defined size, not char* (c_char_p). Have you looked at the structure definition in sys/utsname.h? You have to match the exact structure definition. The data type should probably be c_char * n where n is the size of the array from that field found in sys/utsname.h.

Alternatively, you should be able to access all the strings in your first Edit by using print gnar.raw, as long as the buffer is big enough for the whole structure.

缘字诀 2024-11-18 16:00:46

utsname 结构中的字段不是指针;它们是“未指定大小的数组”。

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

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

[更新]

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

但问题是您正在使用 c_char_p 创建一个指针,然后当您调用 byref() 时,您将传递一个指向 that 的指针。所以 uname() 正在填充您的指针(而不是它指向的内容)。更糟糕的是,它在其中放置了超过 8 个字节,因此您当前的代码正在破坏内存。

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

[第二次更新]

更好......但是现在你必须查看数组内的偏移量。如果这是一个典型的 Linux 系统,每个字段都是 65 个字节(是的,确实如此)。因此您需要开始将 65 个字节读入字符串中。我不知道你是否可以在这个东西上调用 string.index ...

The fields in a utsname structure are not pointers; they are "arrays of unspecified size".

So the strings are packed back-to-back in the structure and null-terminated.

I do not know how to represent this in Python. But I would suggest starting with something other than uname() for your experiments. :-)

[update]

517366245708 decimal is 0x78756E694C, which is ascii for "xuniL". Which actually makes sense on a 64-bit little-endian machine...

But the problem is that you are creating a pointer with c_char_p, then you are passing a pointer to that when you invoke byref(). So uname() is filling in your pointer (not what it points to). And worse, it is putting way more than 8 bytes in there, so your current code is clobbering memory.

You need to figure out how to allocate a block of memory the size of a struct utsname, then pass a pointer to that in to the uname() function, then figure out what offsets inside of that block correspond to which fields in the struct. I am not sure how much of this is even possible with Python...

[second update]

That's better... But now you have to look at an offset within the array. If this is a typical Linux system, each field is 65 bytes (yes, really). So you need to start reading 65 bytes into the string. I do not know whether you can call string.index on this thing...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文