linux守护程序

时间:2024-03-10 20:31:19

概述

周末还要加班写代码,偷个懒发个刚刚写的守护进程,有一个小bug懒得处理,急着要用,发出来记录一下成果。

守护程序

网上很多介绍的,大家有兴趣自己去查查

上酸菜

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>

#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <string.h>

#define MAX_FILE_LEL 1024
#define MAX_FILE_SIZE 30

#define MAXFILE 65535
volatile sig_atomic_t _running = 1;

#define WATCH_PROCESS_NAME "IPSound"
#define DEAMON_NAME "IPSDeamon"

char *Primary_Program = "./IPSound &";

int logMsgFD;
void writeLogger(const char* msg){
    if (logMsgFD <= 0){
        return ;
    }

    write(logMsgFD, msg, strlen(msg));
    write(logMsgFD, "\n",1);
}
// 拦截中断信息,确保程序退出时释放资源
void sigterm_handler(int arg)
{
    _running = 0;
}

void killProcess(char *processName)
{
    FILE *sp = NULL;
    char cmd[128];
    memset(cmd, 0, sizeof(cmd));
    sprintf(cmd, "killall %s ", processName); // task_name 替换为需要结束的进程名称
    sp = popen(cmd, "r");
    if (sp == NULL)
    {
        return;
    }
    pclose(sp);
}

void updateProgram(char *fileNamesrc)
{
    // write(fd, "updateProgram", sizeof("updateProgram"));
    FILE *sp = NULL;
    char cmd[128];
    memset(cmd, 0, sizeof(cmd));
    sprintf(cmd, "mv %s ./ ", fileNamesrc); // task_name 替换为需要结束的进程名称

    sp = popen(cmd, "r");
    if (sp == NULL)
    {
        // write(fd, "update failed", sizeof("update failed"));
        return;
    }
    pclose(sp);
    // write(fd, "update success", sizeof("update success"));
}

int find_files(const char *path, char *dirs)
{
    struct dirent *entry;
    DIR *dp;
    struct stat statbuf;

    dp = opendir(path);
    if (dp == NULL)
    {
        perror("opendir");
        exit(EXIT_FAILURE);
    }
    int index = 0;
    while ((entry = readdir(dp)))
    {
        if (entry->d_type == DT_REG)
        { // 普通文件
            char filename[256];
            snprintf(filename, sizeof(filename), "%s/%s", path, entry->d_name);
            if (stat(filename, &statbuf) == -1)
            {
                perror("stat");
                continue;
            }
            // printf("Found regular file: %s\n", filename);
            dirs += index * MAX_FILE_LEL;
            memcpy(dirs, filename, sizeof(filename));
            index++;
        }
    }
    closedir(dp);

    return index;
}

int get_pid_by_name(const char *process_name)
{
    char cmd[256];
    char buf[1024];
    int pid = -1;
    FILE *fp;

    // 构造命令
    snprintf(cmd, sizeof(cmd), "pidof %s", process_name);

    // 执行命令并打开管道
    fp = popen(cmd, "r");
    if (fp == NULL)
    {
        perror("popen failed:");
        return -1;
    }

    // 读取输出结果
    while (fgets(buf, sizeof(buf), fp) != NULL)
    {
        pid = atoi(buf);
        break; // 假设只有一个进程,所以获取第一个ID即可
    }

    // 关闭管道
    pclose(fp);

    return pid;
}

int is_daemon_running(const char *daemon_name) {
    FILE *fp;
    char buffer[256];
    int daemon_running = 0;
 
    // 使用ps命令列出所有进程
    fp = popen("ps aux", "r");
    if (fp == NULL) {
        printf("Failed to run ps command.\n");
        return 0;
    }
 
    // 读取ps命令的输出
    while (fgets(buffer, sizeof(buffer), fp) != NULL) {
        // 查找守护进程名称
        if (strstr(buffer, daemon_name) != NULL) {
            daemon_running = 1;
            break;
        }
    }
 
    pclose(fp);
    return daemon_running;
}
 
 
int main()
{
    const char *process_name = "IPSDeamon";
    pid_t currentPID = getpid();
    //判断守护进程是否已经运行
    int pidDeamonPID = get_pid_by_name(process_name);
    if (pidDeamonPID > 0 && pidDeamonPID != currentPID){
        printf("已经启动了守护程序: %d",currentPID);
        return;
    }

    // 初始化日志
    if ((logMsgFD = open("/tmp/ipsound.log", O_CREAT | O_WRONLY | O_APPEND, 0600)) < 0)
    {
        printf("日志文件打开失败 \n");
        exit(1);
    }

    writeLogger("启动守护程序");

    pid_t pc;
    int i, len;
    pc = fork();

    

    // 出错退出
    if (pc < 0)
    {
        writeLogger("守护创建失败");
        exit(1);
    }
    else if (pc > 0) // 主进程退出
        exit(0);

    // 脱离终端控制
    setsid();

    char cwd[256];
    if (getcwd(cwd, sizeof(cwd)) != NULL) {
        writeLogger("当前工作目录为");
        writeLogger(cwd);
        writeLogger("\n");
    }
    chdir(cwd);
    umask(0);
    // 关闭标准输出
    close(STDIN_FILENO);
    close(STDOUT_FILENO);
    close(STDERR_FILENO);

    // 注册中断信息
    signal(SIGTERM, sigterm_handler);

    writeLogger("守护进程创建成功");

    while (_running)
    {
        writeLogger("检查是否有升级文件");
        // 查找 Update目录是否有升级文件
        char files[MAX_FILE_SIZE][MAX_FILE_LEL] = {{0}};
        int count = find_files("./update", files);
        if (count > 0)
        {
            writeLogger("... ...发现升级文件---准备升级");
            //printf("-----------------> 重新启动进程 <--------------------------");

            writeLogger("... ...终止当前业务程序IPSound");
            // 终止当前程序
            killProcess(WATCH_PROCESS_NAME);

            writeLogger("... ...执行升级");
            for (int i = 0; i < count; i++)
            {
                printf(files[i]);
                printf("\n");
                // 将升级程序拷贝到当前目录
                updateProgram(files[i]);
            }

            // 重新启动进程
            writeLogger("重新启动业务程序");
            int val = system(Primary_Program); 

            writeLogger("升级完毕");
        }
        else
        {
            writeLogger("检查业务程序是否退出");

            // 检查进程是否正常工作
            int pid = get_pid_by_name(WATCH_PROCESS_NAME);
            printf("enter sub process 10 = %d\n", pid);
            if (pid == -1)
            {
                writeLogger("... ...业务程序已退出,启动业务程序");
                int val = system(Primary_Program); 
                writeLogger("... ...异常处理结束");
            }
            else
            {
                
            }
        }

        // 循环等待
        usleep(1000*1000*10);
    }
    printf("exit .....");
    close(logMsgFD);
}

我公司承接各类技术服务,主要聚焦于:stm32、单片机、嵌入式、QT应用开发、Web+Python+Django应用开发。欢迎合作。