python中的克隆进程支持

时间:2012-11-14 05:44:51

标签: python

Python中是否支持系统调用clone(2) os.fork)?我想在Python下使用Linux命名空间,但似乎没有很多关于它的信息。

编辑:

我认为使用libc的ctypes是答案,但我仍然没有取得任何成功。 fork工作没有问题,因为它没有任何参数,然后这段代码工作:

from ctypes import *

libc = CDLL("libc.so.6")
libc.fork()

克隆我试试这个:

from ctypes import *

def f():
    print "In callback."
    return 0

libc = CDLL("libc.so.6")

f_c = CFUNCTYPE(c_int)(f)

print libc.getpid()
print libc.clone(f_c)
print get_errno()

克隆实际上有这个签名:

int clone(int(* fn)(void *),void * child_stack,                  int flags,void arg,...                  / pid_t * ptid,struct user_desc * tls,pid_t * ctid * /);

我仍然需要传递* child_stack和flags但不知道该怎么做。有什么帮助吗?

更多编辑:

我现在得到了这个:

from ctypes import *

def f():
    print "In callback."
    return 0

libc = CDLL("libc.so.6")

f_c = CFUNCTYPE(c_int)(f)
stack = c_char_p(" " * 1024 * 1024)
libc.clone(f_c, c_void_p(cast(stack, c_void_p).value + 1024 * 1024), 0)

这实际上有效,但我想我在堆叠的系统中打了一个大洞,有一个更干净的方法吗?

编辑:

差不多完成了,为newpid添加了正确的标志:

from ctypes import *

libc = CDLL("libc.so.6")

def f():
    print libc.getpid()
    return 0

f_c = CFUNCTYPE(c_int)(f)
stack = c_char_p(" " * 1024 * 1024)
libc.clone(f_c, c_void_p(cast(stack, c_void_p).value + 1024 * 1024), 0x20000000)

这不仅仅是针对root运行,而是打印一个不错的1。

在这篇文章之后,堆栈看起来很好:http://code.google.com/p/chromium/wiki/LinuxPidNamespaceSupport

2 个答案:

答案 0 :(得分:8)

好吧,最后我想我得到了答案,就是将ctypes与libc一起使用,

这是一个简单的概念证明:

from ctypes import *

libc = CDLL("libc.so.6")

# Create stack.                                                                                                                                                                            
stack = c_char_p(" " * 8096)

def f():
    print libc.getpid()
    return 0

# Conver function to c type returning an integer.                                                                                                                                          
f_c = CFUNCTYPE(c_int)(f)

# We need the top of the stack.                                                                                                                                                            
stack_top = c_void_p(cast(stack, c_void_p).value + 8096)

# Call clone with the NEWPID Flag                                                                                                                                                          
libc.clone(f_c, stack_top, 0x20000000)

这必须由root运行。

答案 1 :(得分:1)

如果你想拥有“fork()但是有新的命名空间”语义,你可以直接调用SYS_clone系统调用。请注意,如果这样做,os.getpid()方法将在子级中返回错误的进程ID,因为glibc会缓存进程ID,并且不知道SYS_clone调用以使其缓存无效。

假设x86_64(NR_clone == 56NR_getpid == 39),您可以将libc.syscall(56, signal.SIGCHLD|0x000200000, 0 0 0)调用为“fork”,然后调用libc.syscall(39)以获取“分叉”子项的当前PID过程