使用 execl 执行守护进程

发布于 2024-07-19 02:43:41 字数 1414 浏览 6 评论 0原文

我正在 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 命令一起使用,则该代码可以正常工作。 但如果 你尝试运行一个守护进程,它只是挂起而不是返回到 提示,因为它应该。

I'm writing a program in C on Linux which includes a module that
allows a shell command to be executed on a remote machine. The
easiest way to actually execute the command would of course be to
simply use the system() function, or use popen and then grab the
output. However, I chose to use a more low-level approach due to other design requirements which are not relevant to the current
problem.

So basically, I set up a pipe and fork, and then call execl. This all
works perfectly, except for one annoying exception. It doesn't work
properly if the shell command to be executed is a daemon. In that
case, it just hangs. I can't figure out why. My understanding is
that when a daemon starts, it typically forks and then the parent exits. Since my application has an open pipe to the parent, the call
to read() should fail when the parent exits. But instead
the application just hangs.

Here is some bare bones code that reproduces the problem:


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);
    }

}

The code works fine if you use it with a normal shell command. But if
you try to run a daemon, it just hangs instead of returning to the
prompt as it should.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

指尖上的星空 2024-07-26 02:43:41

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

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

The most probable solution is adding close(fd[1]); above the execl().

The reason why your program hangs is that the read() function waits for the daemon to write something to its stdout/stderr. If the daemon (including the child process of your program, and also the child process' forked children who keep their stdout/stderr) doesn't write anything and there is at least one process holding the writable end of the pipe open, read() will never return. But which is that process, which is holding the writable end of the pipe open? It is most probably the child of your program's child, the long-running daemon process. Although it may have called close(0); and close(1); when daemonizing itself, most probably it hasn't called close(fd[1]);, so the writable end of the pipe is still open.

在巴黎塔顶看东京樱花 2024-07-26 02:43:41

您的问题可能在这里:-

// 等待子进程终止
int 状态;
等待(&状态);

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

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

Your problem is proably here:-

// Wait for child to terminate
int status;
wait(&status);

As the child process is a deamon it wont terminate anytime soon.

Also your "read()" is likely to hang. You are going to have to decide how long you wait before abandoning any attempt to display output.

陪你搞怪i 2024-07-26 02:43:41

<块引用>

由于子进程是守护进程,因此不会很快终止。

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

不管怎样,在不调用 wait() 的情况下也会出现同样的问题。

另外,为什么 read() 没有得到 EOF? read() 正在从与父守护进程连接的开放管道中读取数据。 因此,当父守护进程退出时,read() 应立即返回并带有 EOF。

As the child process is a deamon it wont terminate anytime soon.

Are you sure? Of course I would agree that a daemon won't terminate anytime soon - but when a daemon starts up it forks so the child can disassociate itself with the terminal, and then the parent exits. Since the wait() system call is waiting on the parent daemon process, it should exit.

Regardless, the same problem occurs without the call to wait().

Also, why doesn't the read() get an EOF? The read() is reading from an open pipe that is connected with the parent daemon process. So when the parent daemon process exits, the read() should return immediately with an EOF.

风吹雨成花 2024-07-26 02:43:41

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

I think you should receive the SIGPIPE signal when waiting on the read to complete, since the other end of the pipe is closed. Did you make anything unusual with the signal ? I suggest you run your code with the strace command.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文