创建一个 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;
}
相关推荐
坚果派·白晓明3 分钟前
鸿蒙 PC 应用集成 libhv 鸿蒙化三方库 —— AtomCode + Skills 驱动的高效集成实践
c语言·c++·ai编程·harmonyos·atomcode
aaaameliaaa27 分钟前
C语言随机数函数使用全解析
c语言·笔记
玖玥拾2 小时前
C/C++ 数据结构(二)双向链表
c语言·数据结构·c++
dnbug Blog2 小时前
C 程序基本结构
c语言·程序结构
QiLinkOS2 小时前
极客精神与商业思维的融合实践(2)
c语言·c++·人工智能·算法·开源协议
不会C语言的男孩2 小时前
Linux 系统编程 · 第 2 章:系统调用与库函数
linux·c语言
Luminous.3 小时前
C语言--day29
c语言·开发语言
十月的皮皮4 小时前
C语言学习笔记20260612-菱形图案打印(两种写法)
c语言·笔记·学习
AI科技星4 小时前
第三卷:质数王朝志(全卷定稿)
c语言·开发语言·汇编·electron·概率论
2601_951645745 小时前
C语言基础语法,分支语句
c语言·运算符·if语句·switch语句·分支语句