使用execl执行守护进程

时间:2009-04-29 03:00:19

标签: c linux daemon

我在Linux上用C编写程序,其中包含一个模块 允许在远程计算机上执行shell命令。该 实际执行命令的最简单方法当然是 只需使用system()函数,或使用popen然后抓住 输出。但是,由于与当前无关的其他设计要求,我选择使用更低级别的方法 问题

基本上,我设置了一个管道和分支,然后调用execl。这一切 除了一个令人讨厌的例外情况外它不起作用 如果要执行的shell命令是守护进程,则正确。在那里面 它只是挂起。我无法弄清楚为什么。我的理解是 当一个守护进程启动时,它通常会分叉然后父进程退出。由于我的应用程序有一个打开管道到父,调用 当父退出时,read()应该失败。但反而 应用程序刚刚挂起。

以下是一些可以重现问题的简单代码:


int main(int argc, char** argv)
{
        // Create a pipe and fork
        //
        int fd[2];
        int p = pipe(fd);
        pid_t pid = fork();

    if (pid > 0)
    {
            // Read from the pipe and output the result
            //
            close(fd[1]);
            char buf[1024] = { 0 };
            read(fd[0], buf, sizeof(buf));
            printf("%s\n", buf);

            // Wait for child to terminate
            int status;
            wait(&status);
    }
    else if (pid == 0)
    {
            // Redirect stdout and stderr to the pipe and execute the shell
            // command
            //
            dup2(fd[1], STDOUT_FILENO);
            dup2(fd[1], STDERR_FILENO);
            close(fd[0]);
            execl("/bin/sh", "sh", "-c", argv[1], 0);
    }

}

如果您使用普通的shell命令,代码可以正常工作。但如果 你试图运行一个守护进程,它只是挂起而不是返回到 提示它应该。

4 个答案:

答案 0 :(得分:2)

最可能的解决方案是在execl()上面添加close(fd[1]);

程序挂起的原因是read()函数等待守护进程向其stdout / stderr写入内容。如果守护进程(包括你的程序的子进程,以及子进程'保留stdout / stderr的分叉子进程)没有写任何内容,并且至少有一个进程保持管道的可写端打开,请阅读( )永远不会回来。但是那个过程是什么,它将管道的可写端保持打开状态?它很可能是程序的孩子的孩子,长期运行的守护进程。虽然在守护自身时可能会调用close(0);close(1);,但很可能它没有调用close(fd[1]);,因此管道的可写端仍然是打开的。

答案 1 :(得分:0)

你的问题可以在这里: -

//等待孩子终止         int状态;         等待(安培;状态);

由于子进程是一种守护,它不会很快终止。

此外,您的“read()”可能会挂起。在放弃任何显示输出的尝试之前,您必须决定等待多长时间。

答案 2 :(得分:0)

  
    

由于子进程是一种守护,它不会很快终止。

  
你确定吗?当然我同意守护进程不会很快终止 - 但是当一个守护进程启动时它会分叉,这样孩子就可以与终端解除关联,然后父进程退出。由于wait()系统调用正在等待父守护进程,因此它应该退出。

无论如何,如果没有调用wait(),也会出现同样的问题。

另外,为什么read()得不到EOF? read()从与父守护进程连接的打开管道读取。因此,当父守护程序进程退出时,read()应立即返回EOF。

答案 3 :(得分:0)

我认为在等待读取完成时应该收到SIGPIPE信号,因为管道的另一端已关闭。你有什么不寻常的信号吗?我建议你使用strace命令运行你的代码。