使用C在Linux后台启动一个进程

时间:2021-01-31 19:16:43

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. 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. 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.

我想在这里做一些有点奇怪的事情。我需要从后台运行的deamon启动一个进程logcat,然后打印到终端而不控制stdin。它用于日志记录,因此理想情况下logcat将打印日志消息,同时仍允许用户输入标准命令并从shell初始化程序。这是我到目前为止守护进程的代码。程序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

谢谢

3 个解决方案

#1


4  

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. 从命令行运行启动程序,该命令行将标准输入,标准输出和标准错误连接到“终端”。
  3. Inside your program, you want to replace the standard input so it comes from /dev/null.
  4. 在程序内部,您希望替换标准输入,使其来自/ dev / null。
  5. You want to leave standard output alone - you want logcat to write to the current standard output.
  6. 您希望单独保留标准输出 - 您希望logcat写入当前标准输出。
  7. You probably want to leave standard error alone too.
  8. 您可能也想单独留下标准错误。

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. 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).

在程序的某个时刻,你正确地进行守护(从@ bstpierre的答案借用链接),确保你所连接的终端不是你的控制终端,这样发送到终端的中断和挂断不会影响你的守护进程。管道比您设置的更简单 - 您应该处理标准输入并保持标准输出和标准错误不变(而不是更改输出并保持输入不变)。

Now, you might want the output to go to /dev/console; if so, then it is reasonable to revise the code to open /dev/console. However, it is not reasonable to fall back on /dev/null if you can't open /dev/console; your program should report an error and fail (because there is no point in having logcat writing to /dev/null!). Make sure you open the console with the O_NOCTTY flag so it does not become the controlling terminal for the daemon.

现在,您可能希望输出转到/ dev / console;如果是这样,那么修改代码以打开/ dev / console是合理的。但是,如果无法打开/ dev / console,则退回/ dev / null是不合理的;你的程序应该报告错误并失败(因为将logcat写入/ dev / null没有意义!)。确保使用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

#2


4  

How to Daemonize in Linux [dead link]

如何在Linux中进行Daemonize [死链接]

How to Daemonize in Linux [wayback machine archive of the above]

如何在Linux中进行Daemonize [以上的Wayback机器档案]

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. To properly daemonize, the following steps must be followed.

我一直在运行的事情之一是Linux守护进程,它们没有正确地守护自己。要正确守护,必须遵循以下步骤。

  • 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中。

#3


1  

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

#1


4  

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. 从命令行运行启动程序,该命令行将标准输入,标准输出和标准错误连接到“终端”。
  3. Inside your program, you want to replace the standard input so it comes from /dev/null.
  4. 在程序内部,您希望替换标准输入,使其来自/ dev / null。
  5. You want to leave standard output alone - you want logcat to write to the current standard output.
  6. 您希望单独保留标准输出 - 您希望logcat写入当前标准输出。
  7. You probably want to leave standard error alone too.
  8. 您可能也想单独留下标准错误。

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. 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).

在程序的某个时刻,你正确地进行守护(从@ bstpierre的答案借用链接),确保你所连接的终端不是你的控制终端,这样发送到终端的中断和挂断不会影响你的守护进程。管道比您设置的更简单 - 您应该处理标准输入并保持标准输出和标准错误不变(而不是更改输出并保持输入不变)。

Now, you might want the output to go to /dev/console; if so, then it is reasonable to revise the code to open /dev/console. However, it is not reasonable to fall back on /dev/null if you can't open /dev/console; your program should report an error and fail (because there is no point in having logcat writing to /dev/null!). Make sure you open the console with the O_NOCTTY flag so it does not become the controlling terminal for the daemon.

现在,您可能希望输出转到/ dev / console;如果是这样,那么修改代码以打开/ dev / console是合理的。但是,如果无法打开/ dev / console,则退回/ dev / null是不合理的;你的程序应该报告错误并失败(因为将logcat写入/ dev / null没有意义!)。确保使用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

#2


4  

How to Daemonize in Linux [dead link]

如何在Linux中进行Daemonize [死链接]

How to Daemonize in Linux [wayback machine archive of the above]

如何在Linux中进行Daemonize [以上的Wayback机器档案]

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. To properly daemonize, the following steps must be followed.

我一直在运行的事情之一是Linux守护进程,它们没有正确地守护自己。要正确守护,必须遵循以下步骤。

  • 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中。

#3


1  

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