创建一个 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;
}
相关推荐
apocelipes1 天前
常用编程语言和库的正则表达式性能对比
c语言·c++·python·性能优化·golang·开发工具和环境
LDR00617 天前
Type-C 快充全面升级!LDR6601 赋能个人护理便携电机,重塑剃须刀 / 理发器新体验
c语言·开发语言
Luminous.17 天前
C语言--day30
c语言·开发语言
玖玥拾17 天前
C/C++ 数据结构(七)栈、容器适配器
c语言·数据结构·c++··容器适配器
謓泽17 天前
C语言不是语法,是通往机器的地图。
c语言·开发语言
不会C语言的男孩17 天前
Linux 系统编程 · 第 8 章:进程基础
linux·c语言
2601_9516438817 天前
C语言长文整理,关键字和数据类型
c语言·数据类型·关键字·嵌入式开发·格式化输出
m0_5474866617 天前
《C#语言程序设计与实践》 全套PPT课件
c语言·c#·c语言程序设计
✎ ﹏梦醒͜ღ҉繁华落℘17 天前
编程基础 --高内聚,低耦合
c语言·单片机
QK_0017 天前
C语言 static 关键字三大作用
c语言·开发语言