2016-05-04 4 views
12

Ich möchte syscall in Python machen und die Funktion ist nicht in libc, gibt es eine Möglichkeit, es in Python zu tun?Machen Sie Syscall in Python

Insbesondere möchte ich getdents nennen, deren manpage sagt

Hinweis: Es gibt keine glibc-Wrapper für diese Systemaufrufe sind;

Alle vorhandenen im Zusammenhang stehenden Lösungen, die ich im Internet gefunden verwendet ctypes mit libc.so: für example.

Bitte nicht in Frage, warum ich getdents direkt verwenden möchte, habe ich einen ganz bestimmten Grund, dies zu tun, und es wäre ablenkend, in dieser Frage zu diskutieren. Vielen Dank.

Antwort

12

Libc aussetzt, eine Funktion „custom“ syscalls aufzurufen: long syscall(long number, ...);

syscall() eine kleine Bibliotheksfunktion ist, die den Systemaufruf dessen Assemblersprache ruft die spezifizierte Schnittstelle number mit den angegebenen Argumente hat. Die Verwendung von syscall() ist nützlich, z. B. beim Aufrufen eines Systemaufrufs, der keine Wrapperfunktion in der C -Bibliothek hat.

nur Zugriff auf diese Funktion wie jede Fremd Funktion:

import ctypes 

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

z.B.

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

Oder das Beispiel in der man-Seite zu übersetzen:

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