Je veux faire syscall
en Python et la fonction n'est pas en libc
, est-il possible de le faire en Python?
Plus précisément, je veux appeler getdents
, dont la page de manuel indique
Remarque: Il n'y a pas d'encapsuleurs glibc pour ces appels système;
Toutes les solutions connexes existantes que j'ai trouvées sur le Web utilisent ctypes
avec libc.so
: pour exemple .
Veuillez ne pas vous demander pourquoi je veux utiliser getdents
directement, j'ai une raison très spécifique de le faire, et ce serait gênant d'en discuter dans cette question. Je vous remercie.
Libc expose une fonction pour invoquer des appels système "personnalisés": long syscall(long number, ...);
syscall()
est une petite fonction de bibliothèque qui appelle l'appel système dont l'interface du langage d'assembly a lenumber
spécifié avec les arguments spécifiés. L'utilisation desyscall()
est utile, par exemple, lors de l'appel d'un appel système qui n'a pas de fonction wrapper dans la bibliothèque C.
Accédez simplement à cette fonction comme n'importe quelle fonction étrangère:
import ctypes
libc = ctypes.CDLL(None)
syscall = libc.syscall
par exemple.
syscall(39) # 39 = getpid, but you get the Gist
Ou pour traduire l'exemple dans la page de manuel:
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