在Python中进行系统调用

Kan*_* Li 17 python system-calls python-2.7

我想syscall在Python中制作并且函数不在libc,有没有办法在Python中做到这一点?

更具体地说,我想打电话getdents,其联机帮助页说

注意:这些系统调用没有glibc包装器;

所有现有的相关解决方案我发现在网络上使用ctypes与libc.so:为例子.

请不要质疑我为什么要getdents直接使用,我有一个非常具体的理由这样做,在这个问题上讨论会分散注意力.谢谢.

kay*_*kay 22

Libc公开了一个函数来调用"自定义"系统调用: long syscall(long number, ...);

syscall()是一个小型库函数,它调用系统调用,其汇编语言接口具有number指定参数的指定.syscall()例如,在调用C库中没有包装函数的系统调用时,使用是很有用的.

只需像任何外来函数一样访问此函数:

import ctypes

libc = ctypes.CDLL(None)
syscall = libc.syscall
Run Code Online (Sandbox Code Playgroud)

例如

syscall(39)  # 39 = getpid, but you get the gist
Run Code Online (Sandbox Code Playgroud)

或者翻译手册页中的示例:

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
Run Code Online (Sandbox Code Playgroud)

  • @cheshirekow真是个奇怪的巧合...当你问一个3岁的问题后,我现在正好抬头10个小时... AFAICT的答案是,对CDLL的单次调用只能设置一次argtypes。但是,如果两次调用CDLL(None),则可以在每个副本上分别设置dll.syscall.argtypes。 (3认同)