创建一个 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 天前
c语言指的是什么意思
c语言·编译器·编程开发·集成开发环境·程序实例
傲世仙尊3 天前
目录即文件-Ext文件系统收尾篇
linux·c语言
牵猫散步的鱼儿3 天前
重载、重写(覆盖)、重定义区别
c语言
phltxy3 天前
C 语言指针:从内存地址到灵活的数据访问
c语言
phltxy3 天前
C 语言中的数据存储:从类型到二进制位
c语言
wuminyu3 天前
HotSpot的轻量锁与膨胀后的ObjectMonitor状态重建原理
java·linux·c语言·jvm·c++
码不停蹄Zzz3 天前
指针用法篇——malloc和free指针详解
c语言
彧azz3 天前
操作系统时间管理与系统核心板块学习总结
c语言·笔记·学习·系统架构
白色的北极熊3 天前
c语言 牛客网 BC15
c语言
老当益壮梁奶奶3 天前
ARM汇编学习笔记(六):【i.MX6ULL】时钟系统与定时器(EPIT & GPT)
c语言·arm开发·嵌入式硬件·学习·51单片机