创建一个 Linux5.10 普通 kill 无效的守护进程 Daemon-demo

创建一个 Linux5.10 普通 kill 无效的守护进程 Daemon-demo

  1. 忽略 SIGTERM(15)、SIGHUP(1)等信号,让普通 kill 无效。
  2. 对 SIGKILL(9)无效 ------ 任何用户态进程都无法阻止 SIGKILL。
  3. 若想阻止普通用户杀死,可以以 root 运行并改变进程权限,但 root 自己依然可以 kill -9。

下面是一个尽可能防止被普通信号杀死的守护进程例子(Linux 5.10,C语言),它会:忽略 SIGTERM、SIGINT、SIGHUP,每秒输出 hello world 到 syslog。只能通过 kill -9 <pid> 杀死。

复制代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <syslog.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>

volatile sig_atomic_t keep_running = 1;

void signal_handler(int sig)
{
    // 除了 SIGKILL 和 SIGSTOP,这里可以捕获的信号都只是记录日志,并不退出
    syslog(LOG_INFO, "Received signal %d, but ignoring it", sig);
}

void setup_signals()
{
    struct sigaction sa;
    sa.sa_flags = 0;
    sigemptyset(&sa.sa_mask);
    sa.sa_handler = signal_handler;

    // 忽略终止信号,使普通 kill 无效
    sigaction(SIGTERM, &sa, NULL);
    sigaction(SIGINT, &sa, NULL);
    sigaction(SIGHUP, &sa, NULL);
    sigaction(SIGQUIT, &sa, NULL);
    sigaction(SIGUSR1, &sa, NULL);
    sigaction(SIGUSR2, &sa, NULL);
    // 不能忽略 SIGKILL 和 SIGSTOP
}

void daemonize()
{
    pid_t pid = fork();
    if (pid < 0)
        exit(EXIT_FAILURE);
    if (pid > 0)
        exit(EXIT_SUCCESS); // 父进程退出

    // 子进程成为会话首领
    if (setsid() < 0)
        exit(EXIT_FAILURE);

    // 忽略 SIGHUP 并再次 fork 确保不是会话首领
    signal(SIGHUP, SIG_IGN);
    pid = fork();
    if (pid < 0)
        exit(EXIT_FAILURE);
    if (pid > 0)
        exit(EXIT_SUCCESS);

    // 更改工作目录(忽略返回值,因为这不是关键操作)
    if (chdir("/") != 0)
    {
        // 即使失败也继续,只是记录一下
        syslog(LOG_WARNING, "chdir(/) failed");
    }

    // 重置文件掩码
    umask(0);

    // 关闭标准文件描述符
    close(STDIN_FILENO);
    close(STDOUT_FILENO);
    close(STDERR_FILENO);

    // 重定向到 /dev/null
    int fd = open("/dev/null", O_RDWR);
    if (fd != -1)
    {
        dup2(fd, STDIN_FILENO);  // stdin
        dup2(fd, STDOUT_FILENO); // stdout
        dup2(fd, STDERR_FILENO); // stderr
        if (fd > 2)
            close(fd);
    }
}

int main()
{
    // 先变成守护进程
    daemonize();

    // 打开系统日志
    openlog("undead_daemon", LOG_PID | LOG_CONS, LOG_DAEMON);
    syslog(LOG_INFO, "Daemon started. PID=%d. It cannot be killed by SIGTERM, only kill -9.", getpid());

    // 设置信号处理(忽略杀进程信号)
    setup_signals();

    // 主循环:每秒输出 hello world
    while (1)
    {
        syslog(LOG_INFO, "hello world");
        sleep(1);
    }

    closelog();
    return 0;
}
相关推荐
aaaameliaaa1 小时前
指针之总结
c语言·笔记·算法
agathakuan2 小时前
Wireshark 解密並導出TLS 1.2 / TLS 1.3 明文的方法(可控制 Client 端)
c语言·wireshark·ssl·openwrt
caimouse2 小时前
protoc-gen-c 支持 proto3 `optional` 关键字修改记录
c语言·学习
noipp2 小时前
推荐题目:洛谷 P6231 [JSOI2013] 公交系统
c语言·数据结构·c++·算法·游戏·洛谷·luogu
c238562 小时前
C/C++每日一练6
c语言·c++·算法
wdfk_prog2 小时前
嵌入式面试真题第 13 题:单硬件 Timer 下的高精度多路软件定时器架构设计
c语言·开发语言·面试·职场和发展·嵌入式
时间的拾荒人3 小时前
MySQL C语言连接 - 从入门到实战
android·c语言·mysql
code_pgf5 小时前
C/C++ 中 `typedef` 关键字详解
c语言·c++
小龙报8 小时前
【优选算法】1. 水果成蓝 2.找到字符串中所有字母的异位词
java·c语言·数据结构·数据库·c++·redis·算法
小肝一下9 小时前
7. 库制作与原理
linux·c语言·操作系统·bash·shell·动静态库