【问题标题】:execve does not inherit any filedescriptorexecve 不继承任何文件描述符
【发布时间】:2019-06-20 16:21:17
【问题描述】:

我正在编写一个 shell 并尝试实现 process substitution。 fork 继承所有文件描述符、分配的内存等。我知道 execve 也应该保留这种信息,因此只要没有设置 O_CLOEXEC 标志,就保留每个打开的文件描述符。

我尝试了一个简单的 python 脚本:
fd.py:

#!/usr/bin/env python3
import sys, os

if __name__ == "__main__":
    if len(sys.argv) == 1:
        new_fd = open("the_content_file", "w+")
        print("father table : ", os.listdir("/dev/fd"))
        if os.fork() == 0:
            os.execve("/PATH/OF/SCRIPT/fd.py", ["fd", "content"], os.environ)
    else:
        print("child table : ", os.listdir("/dev/fd"))
    pass

作为输出,我得到:

father table :  ['0', '1', '2', '3', '4']
child table :  ['0', '1', '2', '3']

在 fork 之后,我保留了相同的 fd 表,但是每当我在可执行文件上使用 execve 时,我都会丢失所有内容并默认打开 fd。 为什么打开的 fd 消失了? 谢谢

【问题讨论】:

    标签: python python-3.x unix file-descriptor execve


    【解决方案1】:

    python3(从 3.4 版开始,与 python2 不同)默认打开带有 O_CLOEXEC 标志的文件。

    我不是 python 程序员,但是在文件上关闭 O_CLOEXEC 的一种简单方法是在 new_fd = .. 行之后添加:

            os.set_inheritable(new_fd.fileno(), True)
    

    (在 python 3.6.6 上测试,参见文档here

    或者,在 3.5.3 等旧版本上:

            tmp_fd = os.dup(new_fd.fileno())
            os.dup2(tmp_fd, new_fd.fileno())
            os.close(tmp_fd)
    

    (os.dup2默认用来制作目标fdinheritable

    请注意,尽管您给它起了名字,但您的 new_fd 不是文件描述符,而是 python 流。您在父级和子级中看到的额外文件是/dev/fd 目录的打开句柄。

    【讨论】:

    • 对,将O_CLOEXEC默认设置为文件描述符是python的特殊性。如果我在 C 中运行类似的东西,它将正常工作。作为扩展,您给了我一些使 fd 可继承的提示,但它不起作用(至少在 python 3.7 上),即使使用os.open。你有os.get_inheritable 来检查一个fd 是否是可继承的,os.set_inheritable 来改变他的状态。 docs.python.org/3/library/os.html#fd-inheritance 谢谢
    • 谢谢,我已经在答案中添加了os.set_inheritable,这可能是推荐的方法(尽管在 debian stable (3.5.3) 的 python3 中还没有 os.set_inheritable
    猜你喜欢
    • 2011-03-11
    • 1970-01-01
    • 2017-11-30
    • 1970-01-01
    • 2010-09-19
    • 2011-08-08
    • 1970-01-01
    • 2020-06-06
    • 1970-01-01
    相关资源
    最近更新 更多