将当前进程转换为守护进程(c++)

#include <sys/types.h>    // 提供 pid_t 类型定义
#include <sys/stat.h>     // 提供 umask 函数
#include <sys/wait.h>     // 提供 waitpid 函数
#include <fcntl.h>        // 提供 open 和 lockf 函数
#include <signal.h>       // 提供信号处理函数和类型定义
#include <unistd.h>       // 提供 fork、setsid、chdir、dup2、close、write 等函数
#include <time.h>         // 提供 time、timespec、difftime 等函数
#include <errno.h>        // 提供 errno 定义
#include <cstring>        // 提供 strerror 函数
#include <iostream>       // 提供标准输入输出流(用于日志记录)
#include <string>         // 提供 std::string 类
#include <array>          // 提供 std::array 容器

void Daemonize(const std::string& pid_file)
{
    std::cout << "Starting daemonization" << std::endl;
    pid_t pid = 0;
    pid_t original_pid = getpid();
    sigset_t mask;
    sigemptyset(&mask);
    sigaddset(&mask, SIGUSR1);
    sigprocmask(SIG_BLOCK, &mask, nullptr);
    
    if ((pid = fork()) < 0) {
        perror("fork");
        exit(EXIT_FAILURE);
    }

    if (pid > 0) {
        constexpr int timeout_val = 5;
        struct timespec timeout { timeout_val, 0 };
        const time_t start = time(nullptr);
        siginfo_t info;

        do {
            const int signum = sigtimedwait(&mask, &info, &timeout);

            if (signum == SIGUSR1 && info.si_signo == SIGUSR1 && info.si_pid == pid) {
                waitpid(pid, nullptr, 0);
                std::cout << "Finished daemonization" << std::endl;
                exit(EXIT_SUCCESS);
            }

            if (signum == -1 && errno == EAGAIN) {
                break; // timed out
            }

            timeout.tv_sec = timeout_val - difftime(time(nullptr), start); // avoid potentially endless loop
        }
        while (true);

        std::cerr << "Waiting on pid file write timeout!" << std::endl;
        exit(EXIT_FAILURE);
    }

    // Now we are forked
    if (setsid() < 0) {
        perror("setsid");
        exit(EXIT_FAILURE);
    }
    signal(SIGCHLD, SIG_IGN);
    int pid_fd = open(pid_file.c_str(), O_RDWR | O_CREAT, 0640);
    if (pid_fd < 0) {
        perror("open");
        exit(EXIT_FAILURE);
    }
    if (lockf(pid_fd, F_TLOCK, 0) < 0) {
        perror("lockf");
        exit(EXIT_FAILURE);
    }
    if ((pid = fork()) < 0) {
        perror("fork");
        exit(EXIT_FAILURE);
    }

    if (pid > 0) {
        try {
            std::string pid_str = std::to_string(pid);
            if (write(pid_fd, pid_str.c_str(), pid_str.size()) != static_cast<ssize_t>(pid_str.size())) {
                perror("write");
                kill(pid, SIGKILL);
                exit(EXIT_FAILURE);
            }
            kill(original_pid, SIGUSR1);
            exit(EXIT_SUCCESS);
        }
        catch (...) {
            kill(pid, SIGKILL);
            throw;
        }
    }

    // Now we are forked 2nd time
    umask(0047);  // no need for world-accessible or executable files
    chdir("/");
    const std::array<int, 3> std_fds {{STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO}};
    int fd_null = open("/dev/null", O_RDWR);
    if (fd_null < 0) {
        perror("open /dev/null");
        exit(EXIT_FAILURE);
    }

    // We do not need to close all fds because there is only logging open at this point
    for (auto fd : std_fds) {
        close(fd);
        if (dup2(fd_null, fd) < 0) {
            perror("dup2");
            exit(EXIT_FAILURE);
        }
    }

    close(fd_null);
    if (lockf(pid_fd, F_LOCK, 0) < 0) {
        perror("lockf");
        exit(EXIT_FAILURE);
    }
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值