简体   繁体   English

使用C在Linux后台启动进程

[英]Start a process in the background in Linux with C

I am trying to do something a little weird here. 我想在这里做一些有点奇怪的事情。 I need to start a process, logcat, from a deamon that will run in the background and print to the terminal without taking control of stdin. 我需要从一个将在后台运行的deamon启动一个进程logcat,并在不控制stdin的情况下打印到终端。 It is for logging so ideally logcat will print log messages while still allowing the user to input standard commands and initialize programs from the shell. 它用于日志记录,因此理想情况下logcat将打印日志消息,同时仍允许用户输入标准命令并从shell初始化程序。 Here is the code for the daemon I have so far. 这是我到目前为止守护进程的代码。 The program, logcat, starts and shows log messages but I cannot enter any commands into stdin as it appears that the program has taken control of stdin. 程序logcat启动并显示日志消息但我无法输入任何命令到stdin,因为程序似乎控制了stdin。

int main ( int argc, char** argv, char** env )
{
    int fd;
    if ((fd = open("/dev/console", O_RDWR)) < 0) {
        fd = open("/dev/null", O_RDWR);
    }
    printf("THIS IS A TEST\n");
    dup2(1, fd);
    dup2(2, fd);

    pid_t childpid = fork();

    if(childpid == -1) {
        perror("Failed to fork, logcat not starting");
        return 1;
    }

    if(childpid == 0) {
        //this is the child, exec logcat
        setsid();
        int execReturn = execl("/system/bin/logcat", "logcat", (char *) 0);
    } else {
        //this is the parent do nothing
        close(fd);
        return 0;
    }
    close(fd);
     return 0;
}

Thanks 谢谢

How to Daemonize in Linux [dead link] 如何在Linux中进行Daemonize [死链接]

How to Daemonize in Linux [wayback machine archive of the above] 如何在Linux中进行Daemonize [以上的回程机器存档]

gist on github -- code taken from link above 关于github的要点 - 从上面的链接中获取的代码

Executive summary: 执行摘要:

One of the things I keep running across is Linux daemons that don't properly daemonize themselves. 我一直在运行的一件事是Linux守护进程,它们没有正确地守护自己。 To properly daemonize, the following steps must be followed. 要正确守护,必须遵循以下步骤。

  • The fork() call is used to create a separate process. fork()调用用于创建单独的进程。
  • The setsid() call is used to detach the process from the parent (normally a shell). setsid()调用用于将进程与父进程(通常是shell)分离。
  • The file mask should be reset. 应重置文件掩码。
  • The current directory should be changed to something benign. 应将当前目录更改为良性。
  • The standard files (stdin,stdout and stderr) need to be reopened. 需要重新打开标准文件(stdin,stdout和stderr)。

Failure to do any of these steps will lead to a daemon process that can misbehave. 如果不执行任何这些步骤,将导致守护程序进程无法正常运行。 The typical symptoms are as follows. 典型症状如下。

  • Starting the daemon and then logging out will cause the terminal to hang. 启动守护程序然后注销将导致终端挂起。 This is particularly nasty with ssh. 这对ssh特别讨厌。
  • The directory from which the daemon was launched remains locked. 启动守护程序的目录保持锁定状态。
  • Spurious output appears in the shell from which the daemon was started. 虚假输出出现在启动守护程序的shell中。

The 'logcat' command seems to be for Android development - that might explain the odd location of the command. 'logcat'命令似乎适用于Android开发 - 这可能解释了命令的奇怪位置。

The key operation that you must fix is to ensure that you close your current standard input (the terminal) and open /dev/null/ for the input device: 您必须修复的关键操作是确保关闭当前标准输入(终端)并为输入设备打开/dev/null/

close(0);
if ((fd = open("/dev/null", O_RDONLY)) != 0)
    ...error - failed to open /dev/null!

This means that your daemonized child process will not read anything from the terminal. 这意味着您的守护进程子进程将不会从终端读取任何内容。


What I think you want to do is: 我认为你想做的是:

  1. Run your launcher program from a command line, which will have standard input, standard output and standard error connected to 'the terminal'. 从命令行运行启动程序,命令行将标准输入,标准输出和标准错误连接到“终端”。
  2. Inside your program, you want to replace the standard input so it comes from /dev/null . 在程序内部,您想要替换标准输入,因此它来自/dev/null
  3. You want to leave standard output alone - you want logcat to write to the current standard output. 您希望单独保留标准输出 - 您希望logcat写入当前标准输出。
  4. You probably want to leave standard error alone too. 您可能也想单独留下标准错误。

At some point in the proceedings, you do your daemonization properly (borrowing the link from @bstpierre's answer), making sure that the terminal you are connected to is not your controlling terminal, so that interrupts and hangups sent to the terminal don't affect your daemon. 在程序中的某个时刻,你正确地进行守护 (从@bstpierre的答案借用链接),确保你所连接的终端不是你的控制终端,这样发送到终端的中断和挂断不会影响你的守护进程。 The plumbing is simpler than what you have set up - you should deal with standard input and leave standard output and standard error unchanged (instead of changing the outputs and leaving the input unchanged). 管道比您设置的更简单 - 您应该处理标准输入并保持标准输出和标准错误不变(而不是更改输出并保持输入不变)。

Now, you might want the output to go to /dev/console ; 现在,您可能希望输出转到/dev/console ; if so, then it is reasonable to revise the code to open /dev/console . 如果是这样,那么修改代码以打开/dev/console是合理的。 However, it is not reasonable to fall back on /dev/null if you can't open /dev/console ; 但是,如果无法打开/dev/console ,则退回/dev/null是不合理的; your program should report an error and fail (because there is no point in having logcat writing to /dev/null !). 你的程序应该报告错误并失败(因为将logcat写入/dev/null没有意义!)。 Make sure you open the console with the O_NOCTTY flag so it does not become the controlling terminal for the daemon. 确保使用O_NOCTTY标志打开控制台,这样它就不会成为守护程序的控制终端。

The final comment I'd make is: 我最后的评论是:

  • Are you sure you want random text appearing over your terminal or console when it is in use for other things? 您确定要在其他用途​​中使用随机文本显示在终端或控制台上吗?

I don't much like it when that happens. 当发生这种情况时,我不太喜欢它。


See also: SO 958249 参见: SO 958249

There is special purposed function for this in glibc: 在glibc中有这个特殊功能:

#include <unistd.h>

...
/* We are in the parent, yet */
daemon(0,0);
/* Now we are in the child */
...

More details here http://linux.die.net/man/3/daemon 更多详情请访问http://linux.die.net/man/3/daemon

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM