2016-05-04 19 views
12

Voglio rendere syscall in Python e la funzione non è in libc, c'è un modo per farlo in Python?Crea syscall in Python

Più in particolare, voglio chiamare getdents, la cui man dice

Nota: Non ci sono wrapper glibc per queste chiamate di sistema;

Tutte le relative soluzioni esistenti che ho trovato sul web utilizza ctypes con libc.so: per example.

Si prega di non chiedere perché voglio usare getdents direttamente, ho un motivo ben preciso per farlo, e sarebbe fonte di distrazione per discutere in questa domanda. Grazie.

risposta

12

Libc espone una funzione per richiamare chiamate di sistema "su misura": long syscall(long number, ...);

syscall() è una piccola funzione di libreria che richiama la chiamata di sistema cui assemblaggio lingua di interfaccia ha specificato number con i argomenti specificati. L'utilizzo di syscall() è utile, ad esempio, quando si richiama una chiamata di sistema che non ha alcuna funzione wrapper nella libreria C .

Basta accedere a questa funzione come una funzione estera:

import ctypes 

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

esempio

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

o di tradurre l'esempio nella pagina man:

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