Подтвердить что ты не робот

Сделать syscall в Python

Я хочу сделать syscall в Python, и функция не находится в libc, есть ли способ сделать это в Python?

В частности, я хочу называть getdents, чья manpage говорит

Примечание. Для этих системных вызовов нет оболочек glibc;

Все существующие связанные решения, которые я нашел в Интернете, используют ctypes с libc.so: для пример.

Пожалуйста, не задавайте вопросов, почему я хочу использовать getdents напрямую, у меня есть очень специфическая причина для этого, и это будет отвлекать обсуждение в этом вопросе. Спасибо.

4b9b3361

Ответ 1

Libc предоставляет функцию для вызова "настраиваемых" системных вызовов: long syscall(long number, ...);

syscall() - небольшая библиотечная функция, которая вызывает системный вызов        интерфейс интерфейса ассемблера имеет указанный number с        указанных аргументов. Использование syscall() полезно, например,        при вызове системного вызова, который не имеет оберточной функции в C        библиотека.

Просто войдите в эту функцию, как любая другая функция:

import ctypes

libc = ctypes.CDLL(None)
syscall = libc.syscall

например.

syscall(39)  # 39 = getpid, but you get the gist

Или перевести пример на странице руководства:

import os, ctypes

off_t = ctypes.c_long  # YMMV
__NR_getdents = 78  # YMMV

class linux_dirent(ctypes.Structure):
    _fields_ = [
        ('d_ino', ctypes.c_long),
        ('d_off', off_t),
        ('d_reclen', ctypes.c_ushort),
        ('d_name', ctypes.c_char)
    ]

_getdents = ctypes.CDLL(None).syscall
_getdents.restype = ctypes.c_int
_getdents.argtypes = ctypes.c_long, ctypes.c_uint, ctypes.POINTER(ctypes.c_char), ctypes.c_uint

fd = os.open('/tmp/', os.O_RDONLY | os.O_DIRECTORY)

buf = ctypes.ARRAY(ctypes.c_char, 1024)()
while True:
    nread = _getdents(__NR_getdents, fd, buf, len(buf))
    if nread == -1:
        raise OSError('getdents')
    elif nread == 0:
        break

    pos = 0
    while pos < nread:
        d = linux_dirent.from_buffer(buf, pos)

        name = buf[pos + linux_dirent.d_name.offset : pos + d.d_reclen]
        name = name[:name.index('\0')]
        print 'name:', name

        pos += d.d_reclen