首页 > 编程语言 >c++ create daemonizeMe

c++ create daemonizeMe

时间:2023-06-12 16:15:48浏览次数:48  
标签:bufsize daemonizeMe process create c++ FAILURE exit EXIT include

daemonizeMe

// Copyright (c) 2017 Deep Aggarwal
#include <getopt.h>
#include <grp.h>
#include <pwd.h>
#include <stdlib.h>
#include <syslog.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#include <fstream>
#include <iostream>
#include <stdexcept>
#include <string>
#include <thread>

static char *applicationName = NULL;
static char *pidFileName = NULL;
static int pidFd = -1;

/**
 * @brief Callback function for handling signals.
 *
 * @param sig Identifier of a signal
 */
void handleSignal(int sig) {
    if (sig == SIGINT) {
        syslog(LOG_INFO, "Stopping %s", applicationName);

        // Unlock and close lockfile
        if (pidFd != -1) {
            lockf(pidFd, F_ULOCK, 0);
            close(pidFd);
        }

        // Delete lockfile
        if (pidFileName != NULL) {
            unlink(pidFileName);
        }

        // Reset signal handling to default behavior
        signal(SIGINT, SIG_DFL);
    }
}

static uid_t getUserID(const char *name) {
    struct passwd pwentry;
    struct passwd *result;
    char *buf;
    size_t bufsize;
    int s;

    // Call to sysconf(_SC_GETPW_R_SIZE_MAX) returns either -1
    // without changing errno or an initial value suggested for
    // the size for buf
    bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
    if (bufsize == -1) {
        // Should be more than enough
        bufsize = 16384;
    }

    buf = new char[bufsize];
    if (buf == NULL) {
        exit(EXIT_FAILURE);
    }

    s = getpwnam_r(name, &pwentry, buf, bufsize, &result);
    if (result == NULL) {
        if (s == 0) {
            std::string sname = name;
            throw std::runtime_error("User \""+ sname +"\" is not found");
        } else {
            std::cerr << "Error in getpwnam_r(...)" << std::endl;
        }
        exit(EXIT_FAILURE);
    }

    return pwentry.pw_uid;
}

static gid_t getGroupID(const char *name) {
    struct group grentry;
    struct group *result;
    char *buf;
    size_t bufsize;
    int s;

    // Call to sysconf(_SC_GETGR_R_SIZE_MAX) returns either -1
    // without changing errno or an initial value suggested for
    // the size for buf
    bufsize = sysconf(_SC_GETGR_R_SIZE_MAX);
    if (bufsize == -1) {
        // Should be more than enough
        bufsize = 16384;
    }

    buf = new char[bufsize];
    if (buf == NULL) {
        exit(EXIT_FAILURE);
    }

    s = getgrnam_r(name, &grentry, buf, bufsize, &result);
    if (result == NULL) {
        if (s == 0) {
            std::string sname = name;
            throw std::runtime_error("User \""+ sname +"\" is not found");
        } else {
            std::cerr << "Error in getgrnam_r(...)" << std::endl;
        }
        exit(EXIT_FAILURE);
    }

    return grentry.gr_gid;
}

/**
 * @brief This function will daemonize this application
 */
static void daemonizeMe() {
    pid_t pid = 0;
    int fd;

    // Fork off the parent process to ensures that
    //   the child process is not a process group leader, so
    //   that it is possible for that process tocreate
    //   a new session and become a session leader
    pid = fork();

    // If error occurred
    if (pid < 0) {
        exit(EXIT_FAILURE);
    }

    // On success, terminate the parent
    if (pid > 0) {
        exit(EXIT_SUCCESS);
    }

    // On success, the child process becomes processgroup
    // and session group leader. Since a controlling terminal
    // is associated with a session, and this new session
    // has not yet acquired a controlling terminal our
    // process now has no controlling terminal,
    // which is a good thing for daemons
    if (setsid() < 0) {
        exit(EXIT_FAILURE);
    }

    // Ignore signal sent from child to parent process
    signal(SIGCHLD, SIG_IGN);

    // Fork off for the second time to ensure that
    // the new child process is not a session leader,
    // so it won't be able to (accidentally) allocate
    // a controlling terminal, since daemons are not
    // supposed to ever have a controlling terminal
    pid = fork();

    // If error occurred
    if (pid < 0) {
        exit(EXIT_FAILURE);
    }

    // On success, terminate the parent
    if (pid > 0) {
        exit(EXIT_SUCCESS);
    }

    // Set new file permissions
    //
    //  "0" means that new files this daemon will
    //  create will have read and write permission for everyone
    //  (0666 or -rw-rw-rw-), and new directories that
    //  this daemon will create will have read, write and
    //  search permissions for everyone (0777 or drwxrwxrwx)
    //  This measn that we have complete control over the
    //  permissions of anything we write
    umask(0);

    // Change the working directory to the root directory
    //  This is to ensure that our process doesn't keep any directory in use.
    //  Failure to do this could make it so that an administrator couldn't unmount
    //  a filesystem, because it was our current directory
    if (chdir("/") != 0) {
        exit(EXIT_FAILURE);
    }

    // Drop priviledges since running network based daemons
    // with root permissions is considered to be a serious risk
    if (getuid() == 0) {
        // If here that means process is running as root,
        // so drop the root privileges
        uid_t userid = NULL;
        gid_t groupid = NULL;
        try {
            // FIXME: Hard-coded since this is the user that we will deal with
            userid = getUserID("mydaemon");
            groupid = getGroupID("mydaemon");
        } catch(const std::runtime_error& error) {
            syslog(LOG_ERR, "\"mydaemon\" couldn't be found");
            exit(EXIT_FAILURE);
        }

        if (setgid(groupid) != 0) {
            exit(EXIT_FAILURE);
        }
        if (setuid(userid) != 0) {
            exit(EXIT_FAILURE);
        }
    }

    // If we try to get root privileges back, it
    // should fail. If it doesn't fail, we exit with failure
    if (setuid(0) != -1) {
        exit(EXIT_FAILURE);
    }

    // Close all open file descriptors
    for (fd = sysconf(_SC_OPEN_MAX); fd > 0; fd--) {
        close(fd);
    }

    // Reopen stdin (fd = 0), stdout (fd = 1), stderr (fd = 2) as /dev/null
    stdin = fopen("/dev/null", "r");
    stdout = fopen("/dev/null", "w+");
    stderr = fopen("/dev/null", "w+");

    // Write PID of daemon to lockfile
    if (pidFileName != NULL) {
        char str[256];
        pidFd = open(pidFileName, O_RDWR|O_CREAT, 0640);
        if (pidFd < 0) {
            // Can't open lockfile
            exit(EXIT_FAILURE);
        }
        if (lockf(pidFd, F_TLOCK, 0) < 0) {
            // Can't lock file
            exit(EXIT_FAILURE);
        }

        // Get current PID
        sprintf(str, "%d\n", getpid());

        // Write PID to lockfile
        write(pidFd, str, strlen(str));
    }
}

/**
 * @brief This function starts the application
 */
static void startApplication() {
    syslog(LOG_NOTICE, "I am daemonizeMe and I am writing to my syslog");
    while (true) {
        // Run your server here
        // For example, a server running in background as a daemon process
        // listening for incoming requests from clients
    }
}

/**
 * @brief Free allocated memory
 */
static void cleanGlobalMemory() {
    if (pidFileName) {
        free(pidFileName);
    }

    return;
}

/**
 * @brief Print usage on the stdout
 */
void printHelp(void) {
    printf("\nUsage: %s [OPTIONS]\n\n", applicationName);
    printf("Options:\n");
    printf("    -h --help                 Print this help message\n");
    printf("    -p --pid_file  filename   PID file used by this application\n");
    printf("    -d --daemon               Daemonize this application\n");
    printf("\n");
}

int main(int argc, char **argv) {
    // Get the application name
    applicationName = argv[0];

    static struct option commandLineOptions[] = {
        {"pid_file",    required_argument,  0, 'p'},
        {"daemon",      no_argument,        0, 'd'},
        {"help",        no_argument,        0, 'h'},
        {NULL,          0,                  0,  0 }
    };

    // Process all the command line arguments
    int getopt_longRV;
    int optionIndex = 0;
    int daemonize = 0;  // 0 means do not daemonize
    while ((getopt_longRV = getopt_long(argc,
                    argv,
                    "p:dh",
                    commandLineOptions,
                    &optionIndex)) != -1) {
        switch (getopt_longRV) {
            case 'p':
                pidFileName = strdup(optarg);
                break;
            case 'd':
                daemonize = 1;
                break;
            case 'h':
                printHelp();
                return EXIT_SUCCESS;
            case '?':
                printHelp();
                return EXIT_FAILURE;
            default:
                break;
        }
    }

    // If daemonize flag is passed
    if (daemonize == 1) {
        daemonizeMe();
    }

    // Open system log to write message to it
    openlog(argv[0], LOG_PID|LOG_CONS, LOG_DAEMON);
    syslog(LOG_INFO, "Started %s", applicationName);

    // Handle SIGINT by this daemon
    signal(SIGINT, handleSignal);

    // Main function to start the application
    startApplication();

    // Write final system log and close the log
    syslog(LOG_INFO, "Stopped %s", applicationName);
    closelog();

    // Free memory
    cleanGlobalMemory();

    return 0;
}

标签:bufsize,daemonizeMe,process,create,c++,FAILURE,exit,EXIT,include
From: https://www.cnblogs.com/lidabo/p/17475278.html

相关文章

  • C++采用Daemon进行后台程序的部署
    文章目录一、如何采用Daemon进行后台程序的部署1.创建子进程2.终止父进程3.创建新的会话4.改变当前工作目录5.重设文件权限掩码6.关闭不需要的文件描述二.代码示例 一、如何采用Daemon进行后台程序的部署在C++中,如果要让一个程序一直在后台运行并且和......
  • mysql启动报can't create/write to file 'var/run/mysqld/mysqld.pid 错误解决办法
    msql启动报错,启动不了。进入mysql日志默认的路径为/var/log/mysqld.log查看日志,发现报错信息如下:can'tcreate/writetofile'var/run/mysqld/mysqld.pid解决办法:将/var/run/mysqld/权限赋给mysql执行以下命令即可:chown-Rmysql/var/run/mysqldchgrp-Rmysql/var/ru......
  • 【C++】STL常用容器总结之十二:string类
    13、string类声明string类本不是STL的容器,但是它与STL容器有着很多相似的操作,因此,把string放在这里一起进行介绍。之所以抛弃char*的字符串而选用C++标准程序库中的string类,是因为他和前者比较起来,不必担心内存是否足够、字符串长度等等,而且作为一个类出现,他集成的操作函数足以完......
  • c++中string类的源代码
    一:回顾(1)c++中的string类是在面试中和笔试中经常考的题目;工程代码免费下载 string类的自行实现(2)c++中的string类和fstream类合起来是处理外部数据的利器;(3)string类经常用到findfind_first_offind_first_not_offind_last_offind_last_not_ofsubstrreplace等,以及联合使用来达......
  • C++ operator关键字(重载操作符)
    operator是C++的关键字,它和运算符一起使用,表示一个运算符函数,理解时应将operator=整体上视为一个函数名。  这是C++扩展运算符功能的方法,虽然样子古怪,但也可以理解:一方面要使运算符的使用方法与其原来一致,另一方面扩展其功能只能通过函数的方式(c++中,“功能”都是由函数实现的)......
  • C++ 运算符重载讲解与经典实例
    C++中预定义的运算符的操作对象只能是基本数据类型,实际上,对于很多用户自定义类型,也需要有类似的运算操作。例如: classcomplex{public:complex(doubler=0.0,doubleI=0.0){real=r;imag=I;}voiddisplay();private:doublereal;doubleimag;};comple......
  • C++面试八股文:如何在堆上和栈上分配一块内存?
    C++面试八股文:如何在堆上和栈上分配一块内存?某日二师兄参加XXX科技公司的C++工程师开发岗位6面:面试官:如何在堆上申请一块内存?二师兄:常用的方法有malloc,new等。面试官:两者有什么区别?二师兄:malloc是向操作系统申请一块内存,这块内存没有经过初始化,通常需要使用memset手......
  • (一)、C++学习随笔:指针
    北京时间2023年6月11日22点53分,天气总体晴,温度适宜。没写随笔差不多一年了,也从佛山的广发银行、美的外包跳槽到了深圳坂田这边的华为OD,JAVA或许是干的不太愿意深入了,想学习下C++。今天学习到C++的重点之一:指针,鄙人不才,记忆力不太好,所谓的好记性不如烂笔头,把学到的指针知识都记录下......
  • 《C++》C转C++基础2
    跳转语句break、continue、goto。数组一维数组、二维数组创建、赋值、访问同C。函数定义、声明、调用同C,代过。指针变量指针、数组指针、结构体指针同C,代过。结构体结构体、结构体数组、结构体指针同C,代过......
  • C++面试八股文:在C++中,你知道哪些运算符?
    某日二师兄参加XXX科技公司的C++工程师开发岗位第11面:面试官:在C++中,你都知道都哪些运算符?二师兄:啥?运算符?+-*/=这些算吗?面试官:嗯,还有其他的吗?二师兄:当然还有,+=,-=,*=,/=,==,还有逻辑运算,位运算等。面试官:好的。那你知道这些运算的优先级吗?二师兄:(面试官傻逼吧,这谁记得住)记不住......