在 Linux 中创建守护进程

标签 c linux daemon

在 Linux 中,我想添加一个无法停止并监视文件系统更改的守护程序。 如果检测到任何更改,它应该写入启动它的控制台的路径以及一个换行符。

我已经准备好更改文件系统的代码,但我不知道如何创建守护进程。

我的代码来自这里:http://www.yolinux.com/TUTORIALS/ForkExecProcesses.html

fork 后怎么办?

int main (int argc, char **argv) {

  pid_t pID = fork();
  if (pID == 0)  {              // child
          // Code only executed by child process    
      sIdentifier = "Child Process: ";
    }
    else if (pID < 0) {
        cerr << "Failed to fork" << endl;
        exit(1);
       // Throw exception
    }
    else                                   // parent
    {
      // Code only executed by parent process

      sIdentifier = "Parent Process:";
    }       

    return 0;
}

最佳答案

In Linux i want to add a daemon that cannot be stopped and which monitors filesystem changes. If any changes would be detected it should write the path to the console where it was started + a newline.

守护进程在后台工作并且(通常...)不属于 TTY,这就是为什么您不能以您可能想要的方式使用 stdout/stderr。 通常使用 syslog 守护进程 (syslogd) 将消息记录到文件(调试、错误...)。

除此之外,还有一些必需的步骤来守护进程。


如果我没记错的话,这些步骤是:

  • fork 关闭父进程,如果 fork 成功则让它终止。 -> 因为父进程已经终止,子进程现在在后台运行。
  • setsid - 创建一个新 session 。调用进程成为新 session 的领导者和新进程组的进程组领导者。该进程现在已与其控制终端 (CTTY) 分离。
  • 捕捉信号 - 忽略和/或处理信号。
  • 再次 fork 并让父进程终止以确保您摆脱 session 领导进程。 (只有 session 负责人可以再次获得 TTY。)
  • chdir - 更改守护程序的工作目录。
  • umask - 根据守护进程的需要更改文件模式掩码。
  • close - 关闭所有可能从父进程继承的打开文件描述符。

为您提供一个起点:查看显示基本步骤的框架代码。此代码现在也可以在 GitHub 上 fork :Basic skeleton of a linux daemon

/*
 * daemonize.c
 * This example daemonizes a process, writes a few log messages,
 * sleeps 20 seconds and terminates afterwards.
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <syslog.h>

static void skeleton_daemon()
{
    pid_t pid;

    /* Fork off the parent process */
    pid = fork();

    /* An error occurred */
    if (pid < 0)
        exit(EXIT_FAILURE);

    /* Success: Let the parent terminate */
    if (pid > 0)
        exit(EXIT_SUCCESS);

    /* On success: The child process becomes session leader */
    if (setsid() < 0)
        exit(EXIT_FAILURE);

    /* Catch, ignore and handle signals */
    //TODO: Implement a working signal handler */
    signal(SIGCHLD, SIG_IGN);
    signal(SIGHUP, SIG_IGN);

    /* Fork off for the second time*/
    pid = fork();

    /* An error occurred */
    if (pid < 0)
        exit(EXIT_FAILURE);

    /* Success: Let the parent terminate */
    if (pid > 0)
        exit(EXIT_SUCCESS);

    /* Set new file permissions */
    umask(0);

    /* Change the working directory to the root directory */
    /* or another appropriated directory */
    chdir("/");

    /* Close all open file descriptors */
    int x;
    for (x = sysconf(_SC_OPEN_MAX); x>=0; x--)
    {
        close (x);
    }

    /* Open the log file */
    openlog ("firstdaemon", LOG_PID, LOG_DAEMON);
}
int main()
{
    skeleton_daemon();

    while (1)
    {
        //TODO: Insert daemon code here.
        syslog (LOG_NOTICE, "First daemon started.");
        sleep (20);
        break;
    }

    syslog (LOG_NOTICE, "First daemon terminated.");
    closelog();

    return EXIT_SUCCESS;
}


  • 编译代码:gcc -o firstdaemon daemonize.c
  • 启动守护进程:./firstdaemon
  • 检查是否一切正常:ps -xj | grep firstdaemon

  • 输出应该和这个类似:

+------+------+------+------+-----+-------+------+------+------+-----+
| PPID | PID  | PGID | SID  | TTY | TPGID | STAT | UID  | TIME | CMD |
+------+------+------+------+-----+-------+------+------+------+-----+
|    1 | 3387 | 3386 | 3386 | ?   |    -1 | S    | 1000 | 0:00 | ./  |
+------+------+------+------+-----+-------+------+------+------+-----+

您应该在这里看到的是:

  • 守护进程没有控制终端 (TTY = ?)
  • 父进程 ID (PPID) 为 1(初始化进程)
  • PID != SID 表示我们的进程不是 session 负责人
    (因为第二个 fork())
  • 因为 PID != SID 我们的进程无法再次控制 TTY

阅读系统日志:

  • 找到您的系统日志文件。我的在这里:/var/log/syslog
  • 执行:grep firstdaemon/var/log/syslog

  • 输出应该和这个类似:

  firstdaemon[3387]: First daemon started.
  firstdaemon[3387]: First daemon terminated.


备注: 实际上,您还希望实现一个信号处理程序并正确设置日志记录(文件、日志级别...)。

进一步阅读:

关于在 Linux 中创建守护进程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17954432/

相关文章:

java - JOptionPane 显示在父 JFrame 后面

java - 为什么连接到 main() 线程的守护线程在 main() 线程执行结束时没有死掉?

linux - 如何创建一个在后台运行且在 L​​inux 中交互式的应用程序?

c - "++"运算符在 "char *"上做了什么?

c - 在 linux 中同时输出已停止和正在运行的进程?

linux - 如何从 dhcpd.conf 中删除租约?

C 中的 Chmod 分配错误的权限

dockerd 不在 nixos 上运行

c - 显示C中正在运行的进程列表

c - 将字符串传递给函数从中获取整数数组