为什么fork后关闭文件描述符会影响子进程?

2024-04-05

我想通过单击按钮在linux中运行程序,因此我编写了一个函数execute:

void execute(const char* program_call, const char* param )
{
    pid_t child = vfork();

    if(child == 0) // child process
    {
        int child_pid = getpid();

        char *args[2]; // arguments for exec
        args[0] = (char*)program_call; // first argument is program_call
        args[1] = (char*)param;

        // close all opened file descriptors:
        const char* prefix = "/proc/";
        const char* suffix = "/fd/";
        char child_proc_dir[16]; 
        sprintf(child_proc_dir,"%s%d%s",prefix,child_pid, suffix);

        DIR *dir;
        struct dirent *ent;

        if ((dir = opendir (child_proc_dir)) != NULL) {
            // get files and directories within directory
            while ((ent = readdir (dir)) != NULL) {
                // convert file name to int
                char* end;
                int fd = strtol(ent->d_name, &end, 32);
                if (!*end) // valid file descriptor
                {
                    close(fd); // close file descriptor
                    // or set the flag FD_CLOEXEC
                    //fcntl( fd, F_SETFD, FD_CLOEXEC );
                }
            }
            closedir (dir);
        } 
        else 
        {
            cerr<< "can not open directory: " << child_proc_dir <<endl;
        }
        // replace the child process with exec*-function
            execv(program_call,args);
            _exit(2);
        }
    else if (child == -1) // fork error
    {
        if (errno == EAGAIN)
        {
            cerr<<“To much processes"<<endl;
        }
        else if (errno == ENOMEM)
        {
            cerr<<“Not enough space available."<<endl;
        }
    }
    else // parent process
    {
        usleep(50); // give some time 
        if ( errno == EACCES)
        {
            cerr<<“Permission denied or process file not executable."<<endl;
        }
        else if ( errno == ENOENT)
        {
            cerr<<"\n Invalid path or file."<<endl;
        }
        int child_status;
        if ( waitpid(child, &child_status, WNOHANG | WUNTRACED) < 0) // waitpid failed
        {
            cerr<<"Error - Execution failed"<<endl;
        }
        else if ( WIFEXITED( child_status ) &&  WEXITSTATUS( child_status ) != 0)   
        {
            cerr<<“Child process error - Execution failed"<<endl;
        }
    }
}

有两个问题:

  1. 关闭文件描述符会导致一些问题,例如 Thunderbird 崩溃或 VLC 运行时没有声音。更准确地说:关闭stdout(1) and stderr(2)导致这些问题。据我了解,在 exec 之前关闭文件描述符只会防止它们被复制(不需要从子进程向父进程发送信息)。为什么这会影响子进程?更换close()通过设置标志FD_CLOEXEC并没有改变任何东西。还设置FD_CLOEXECfork 之前的 flag 并不能解决问题。有没有更好的方法来防止文件描述符的继承?

  2. waitpid的返回值往往是0,即使程序调用失败,我想是因为有两个(异步)进程。usleep(50)解决了这个问题以满足我的需求,但我希望有更好的解决方案来解决这个问题。

我使用的是vfork,但是使用fork也会出现同样的问题。


首先,在2014年,从来没有使用过vfork但简单地说fork(2) http://man7.org/linux/man-pages/man2/fork.2.html。 (自从vfork(2) http://man7.org/linux/man-pages/man2/vfork.2.html自 POSIX 2001 起已过时,并在 POSIX 2008 中删除)。

然后,关闭大部分文件描述符的最简单方法就是

for (int fd=3; fd<256; fd++) (void) close(fd);

(hint: if a fd is invalid, close(fd) would fail and we ignore the failure; and you start from 3 to keep open 0==stdin, 1==stdout, 2==stderr; so in principle all the close above would fail).

然而,行为良好且编写良好的程序在关闭时不需要这样的循环(因此这是克服以前的错误的粗略方法)。

当然,如果您知道除 stdin、stdout、stderr 之外的某些文件描述符是有效的并且子级需要program_call(这不太可能)您需要明确跳过它。

然后使用FD_CLOEXEC越多越好。

您的程序不太可能在您不知情的情况下拥有大量文件描述符。

也许你想要守护进程(3) http://man7.org/linux/man-pages/man3/daemon.3.html或(正如评论者vality https://stackoverflow.com/users/3323096/vality) posix_spawn http://pubs.opengroup.org/onlinepubs/009695399/functions/posix_spawn.html.

如果您需要显式关闭STDIN_FILENO(即 0),或STDOUT_FILENO(即 1),或STDERR_FILENO(即2)你会更好open("/dev/null",... and dup2他们在打电话之后 - 打电话之前exec,因为大多数程序都期望它们存在。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么fork后关闭文件描述符会影响子进程? 的相关文章

随机推荐

  • CSS 旋转并定位到页面左下角

    我试图将 div 放置在窗口的左下角 以便它始终卡在那里 但它应该包含从下向上阅读的文本 如图所示 pic 1 https i stack imgur com k4PGN jpg 我尝试过这种样式 ms transform rotate 2
  • 解释awk命令

    今天我在网上搜索一个命令来打印模式后的下两行 我遇到了一个我无法理解的 awk 命令 usr xpg4 bin awk PATTERN 2 input 有人可以解释一下吗 See https stackoverflow com a 1791
  • 如何在 echo 调用中运行函数

    这是一个快速但简单的问题 我今天过得很糟糕 不知道该怎么做 我需要做的是这个 我正在检查 url 中的 PMD 如果是这样 请回显
  • 使用curl上传本地目录中的所有文件

    我想上传一个目录中的所有文件 并且我知道如何使用curl上传一个文件 如下所示 curl T local xxx suffix u xxx psw ftp 192 168 1 158 public demon test xxx suffix
  • 有没有一种方法可以编辑符号链接而不先删除它? [复制]

    这个问题在这里已经有答案了 所以我创建了一个符号链接 https en wikipedia org wiki Symbolic link ln s location to link linkname 现在我想更改符号链接链接到的位置 我怎么
  • 如何在打字稿中将 Observable 中存储的值转换为字符串?

    您好 我是 Angular 和 TypeScript 的新手 我需要一个值Observable在字符串的格式中 如何做到这一点 BmxComponent 文件 export class BmxComponent asyncString th
  • 组件加载时如何设置角度垫选择值?

    我使用了有角的材料 角度 材料 7 1 0 mat select box 然后我使用表单控件而不是 ng model 现在的问题是我无法在组件加载时设置值 我需要将第一个值设置为列表中的 mat select box 我尝试过 但我做不到
  • Gradle 不包括 FXML 和图像

    我一直在寻找将 FXML 和图像包含在build gradle以便将它们构建到罐子中 我有看here https stackoverflow com questions 21128652 location is required in ja
  • 比较数据网格中同一行的两个单元格

    使用 C NET 4 5 MS Visual Studio 2012 WPF 你好 刚刚让这段代码终于起作用了 它基本上是通过数据网格进行迭代来进行行的 请注意 他可能会冒犯所有 WPF 奇才 public IEnumerable
  • 如何下载 Telegram 群组的聊天记录?

    我想下载 Telegram 公共群组中发布的聊天记录 所有消息 我怎样才能用Python做到这一点 我在API中找到了这个方法https core telegram org method messages getHistory https
  • 使用 ssh-keygen 创建 JSch 接受的 SSH 私钥 [重复]

    这个问题在这里已经有答案了 不是直接的编程问题 但有某种相关性 JSch Java SSH 库 似乎不允许 macOS 10 14 使用以下命令创建私钥 ssh keygen t rsa b 4096 我应该使用什么命令来创建具有这种格式的
  • 需要一个支持自动布局的可视化java库

    我需要一个用于可视化的 java 图形库 我可以将其合并到我自己的应用程序中 我发现 jgraph 非常适合可视化 但需要明确定位节点 有没有支持自动布局的开源java图形库 任何建议都会对我非常有帮助 有许多软件包可以做到这一点 如果你习
  • 如何在 Haskell 中获取 Maybe 的值

    我对 Haskell 比较陌生 并开始阅读 Real World Haskell 我刚刚偶然发现了 Maybe 类型 并且有一个关于如何从 a 接收实际值的问题Just 1例如 我编写了以下代码 combine a b c eliminat
  • 使用 npm 安装 Angular-cli 时出错

    当我尝试使用 npm 安装 Angular cli 时 出现错误 代码为 ETIMEDOUT 我尝试删除代理 代理和 HTTP 代理 尝试在管理模式下运行 cmd 更改 Nodejs 目标的路径 npm ERR code ETIMEDOUT
  • document.documentElement.scrollTop 返回值在 Chrome 中有所不同

    我正在尝试根据 处理一些代码document documentElement scrollTop 价值 它返回 348 在 FF 和 IE 中 但在 Chrome 中它返回 0 我需要做些什么来克服这个问题吗 FF gt gt gt doc
  • 具有 Visual Studio 编辑器功能的独立文本编辑器

    有人知道任何具有 Visual Studio 编辑器功能的文本编辑器吗 具体来说 我正在寻找以下功能 CTRL C 行中任意位置 未选择任何文本 gt 复制整行 在线任意位置按 CTRL X 或 SHIFT DEL 未选择任何文本 gt 剪
  • Perl 逐行读取

    我有一个简单的 Perl 脚本来逐行读取文件 代码如下 我想显示两行并打破循环 但这不起作用 错误在哪里 file SnPmaster txt open INFO file or die Could not open file count
  • 将ArrayList数据传递到android中的SOAP Web服务

    您好 我需要将数组列表数据传递到soap web 服务中 到目前为止 我有以下代码 public class ResultActivity extends Activity public final String NAMESPACE pub
  • 在 iOS 上发送 HTTP POST 请求

    我正在尝试使用我正在开发的 iOS 应用程序发送 HTTP Post 但推送从未到达服务器 尽管我确实收到了代码 200 作为响应 来自 urlconnection 我从未收到服务器的响应 服务器也没有检测到我的帖子 服务器确实检测到来自
  • 为什么fork后关闭文件描述符会影响子进程?

    我想通过单击按钮在linux中运行程序 因此我编写了一个函数execute void execute const char program call const char param pid t child vfork if child 0