【问题标题】:error in executing system function with STDOUT_FILENO closed在 STDOUT_FILENO 关闭的情况下执行系统函数时出错
【发布时间】:2016-11-09 16:31:35
【问题描述】:

我有一个奇怪的问题。我的C语言不是很好。我正在尝试创建一个守护程序来在 Linux 中执行我的基于 bash 脚本的服务。为了方便起见,我使代码变得简单。下面是我的代码。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <syslog.h>

int main(int argc, char* argv[])
{
    pid_t process_id = 0;
    pid_t sid = 0;
    process_id = fork();
    if (process_id < 0)
    {
        printf("fork failed!\n");
        exit(1);
    }
    if (process_id > 0)
    {
        printf("daemon creatd with process id %d \n", process_id);
        exit(0);
    }

    umask(0);
    sid = setsid();
    if(sid < 0)
    {
        fprintf(stderr, "Return error\n");
        exit(1);
    }

    chdir("/");
    close(STDIN_FILENO);
    close(STDOUT_FILENO);
    close(STDERR_FILENO);



    int status = system("ls");

    openlog("slog", LOG_PID|LOG_CONS, LOG_USER);
    syslog(LOG_INFO, "Returned status is %d", status);
    closelog();

    return (0);
}

如您所见,上述程序会执行system函数来执行ls命令并将退出代码输出到系统日志。

程序编译运行后,在日志中可以看到状态码是512。但是如果我注释掉下面这行,

close(STDOUT_FILENO);

然后它完美运行,我可以在日志中看到状态码为 0,

我可能做错了什么?

更新

我的程序很大,我没有在实际环境中使用ls。我使程序变得简单,以重现我所面临的问题。另外,要查看程序的状态,我不是查看输出,而是查看系统日志中的状态代码。

【问题讨论】:

  • 你为什么要做ls,你希望它的输出去哪里?按照惯例,子进程继承父进程的标准输出。您在父进程中关闭了标准输出。 ls 使用标准输出。这是正确的预期行为。
  • 我的程序很大,我没有在实际环境中使用ls。我使程序变得简单,以重现我所面临的问题。另外,要查看程序的状态,我不是查看输出,而是查看系统日志中的统计代码。希望你能理解。

标签: c daemon


【解决方案1】:

如果其他 cmets 和答案不清楚,ls 会将其输出写入标准输出。如果它无法写入标准输出,它会终止并(显然)设置状态码 512(在任何情况下都非零)。

子进程会从父进程继承stdout,所以如果你不关闭父进程的stdout,子进程就会有一个stdout可以写入,命令就会成功。如果关闭stdout,那么孩子无处可写其输出,就会出现错误。

因此,尽管ls 只是此问题的一个示例,但您的实际子进程正在写入标准输出,这会导致相同的问题。

解决这个问题的最简单方法,假设您不想要孩子的输出,是在命令行上重定向孩子的标准输出:

int status = system("ls >/dev/null 2>&1");

这会将 stdout 和 stderr 重定向到 /dev/null,有效地丢弃孩子的输出,同时仍然给它写的地方。

【讨论】:

  • 看起来是一个完美的解释。我没有意识到这一点。让我试试这个并回复评论。谢谢。
  • 完美!。感谢您的指导。
【解决方案2】:

您的守护进程创建看起来不错。但是按照惯例,守护进程没有控制终端,您可以通过关闭所有标准文件描述符并调用setsid() 来创建新会话以使守护进程成为会话领导者。因此,您不能让守护进程在stdout 流上产生任何输出。如果您不关闭stdout 流,它显然可以工作。

所以,您正在做的是尝试从终端向 tty 写入内容。因此,您要么不需要守护进程,要么需要写入不同的文件(而不是标准输出)。

【讨论】:

  • 感谢您的回复。不幸的是,我不希望这个程序有任何输出。我完全知道关闭 tbe STDOUT 后不会有任何输出。那就是我正在使用log。而我真正的程序根本没有使用ls。这是为了尽量减少这种情况。我只是更新了这个问题。我需要知道的是,外部程序是否使用0 退出代码退出或不使用syslog
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-08
  • 2012-03-10
  • 1970-01-01
相关资源
最近更新 更多