Вызов uname из libc с помощью Pythons ctypes - PullRequest
4 голосов
/ 03 июня 2011

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

Исходное сообщение

Следующий код segfaults;Я не уверен, что я делаю не так.

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)

Edit3: (я собираюсь дольше всехотправлять когда-либо ... = 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), поэтому добавление поля для домена - это все, что нужно, чтобы остановить segfault.Это имеет смысл в заднем плане.:)

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 ]

2 голосов
/ 03 июня 2011

Согласно этой man-странице uname , структура содержит массивы определенного размера, а не char * (c_char_p). Вы смотрели на определение структуры в sys/utsname.h? Вы должны соответствовать точному определению структуры. Тип данных, вероятно, должен быть c_char * n, где n - это размер массива из этого поля, найденного в sys/utsname.h.

Кроме того, вы должны иметь доступ ко всем строкам в вашем первом Редактировании с помощью print gnar.raw, если буфер достаточно большой для всей структуры.

2 голосов
/ 03 июня 2011

Поля в структуре utsname не являются указателями;они являются «массивами неопределенного размера».

Таким образом, строки упакованы в структуру и имеют нулевое окончание.

Я не знаю, как это представить в Python.Но я бы предложил начать с чего-то другого, кроме uname () для ваших экспериментов.: -)

[обновление]

517366245708 десятичное значение равно 0x78756E694C, что является ascii для "xuniL".Что на самом деле имеет смысл на 64-битной машине с прямым порядком байтов ...

Но проблема в том, что вы создаете указатель с помощью c_char_p, а затем передаете указатель на , который , когдаВы вызываете byref ().Таким образом, uname () заполняет ваш указатель (а не то, на что он указывает).И что еще хуже, он помещает туда более 8 байтов, поэтому ваш текущий код забивает память.

Вам необходимо выяснить, как выделить блок памяти размером struct utsname, а затем передатьуказатель на , который в функции uname (), затем выяснить, какие смещения внутри этого блока соответствуют каким полям в структуре.Я не уверен, насколько это возможно даже с помощью Python ...

[второе обновление]

Это лучше ... Но теперь вы должны посмотреть на смещение в массиве.Если это типичная система Linux, каждое поле имеет размер 65 байт (да, действительно).Итак, вам нужно начать читать 65 байтов в строку.Я не знаю, можно ли позвонить string.index на эту вещь ...

...