LINUX下守护进程的C语言实现#2


=Start=

缘由:

以后估计会经常和daemon进程打交道,所以在这里整理一下Linux的C语言中daemon进程编写的函数,方便以后直接使用。

正文:

参考解答:
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <syslog.h>
#include <string.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/resource.h>
#include <errno.h>        /* for definition of errno */
#include <stdarg.h>       /* ISO C variable aruments */
#define LOCKFILE "/var/run/daemon.pid"
#define LOCKMODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
#define MAXLINE 4096            /* max line length */
/*
 * Print a message and return to caller.
 * Caller specifies "errnoflag".
 */
static void
err_doit(int errnoflag, int error, const char *fmt, va_list ap)
{
    char    buf[MAXLINE];
    vsnprintf(buf, MAXLINE, fmt, ap);
    if (errnoflag)
        snprintf(buf+strlen(buf), MAXLINE-strlen(buf), ": %s",
          strerror(error));
    strcat(buf, "\n");
    fflush(stdout);     /* in case stdout and stderr are the same */
    fputs(buf, stderr);
    fflush(NULL);       /* flushes all stdio output streams */
}
/*
 * Fatal error unrelated to a system call.
 * Print a message and terminate.
 */
void
err_quit(const char *fmt, ...)
{
    va_list     ap;
    va_start(ap, fmt);
    err_doit(00, fmt, ap);
    va_end(ap);
    exit(1);
}
int
lockfile(int fd)
{
    struct flock fl;
    fl.l_type = F_WRLCK;
    fl.l_start = 0;
    fl.l_whence = SEEK_SET;
    fl.l_len = 0;
    return(fcntl(fd, F_SETLK, &fl));
}
int
already_running(void)
{
    int     fd;
    char    buf[16];
    fd = open(LOCKFILE, O_RDWR|O_CREAT, LOCKMODE);
    if (fd < 0) {
        syslog(LOG_ERR, "can't open %s: %s", LOCKFILE, strerror(errno));
        exit(1);
    }
    if (lockfile(fd) < 0) {
        if (errno == EACCES || errno == EAGAIN) {
            close(fd);
            return(1);
        }
        syslog(LOG_ERR, "can't lock %s: %s", LOCKFILE, strerror(errno));
        exit(1);
    }
    ftruncate(fd, 0);
    sprintf(buf, "%ld", (long)getpid());
    write(fd, buf, strlen(buf)+1);
    return(0);
}
void
daemonize(const char *cmd)
{
    int                 i, fd0, fd1, fd2;
    pid_t               pid;
    struct rlimit       rl;
    /*
     * Initialize the log file.
     */
    openlog(cmd, LOG_CONS, LOG_DAEMON);
    /*
     * Clear file creation mask.
     */
    umask(0);
    /*
     * Get maximum number of file descriptors.
     */
    if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
        syslog(LOG_ERR, "%s: can't get file limit", cmd);
        exit(1);
    }
    /*
     * Become a session leader to lose controlling TTY.
     */
    if ((pid = fork()) < 0) {
        syslog(LOG_ERR, "%s: can't fork", cmd);
        exit(1);
    else if (pid != 0/* parent */
        exit(0);
    setsid();
    /*
     * Ensure future opens won't allocate controlling TTYs.
     */
    if ((pid = fork()) < 0){
        syslog(LOG_ERR, "%s: can't fork", cmd);
        exit(1);
    else if (pid != 0/* parent */
        exit(0);
    /*
     * Change the current working directory to the root so
     * we won't prevent file systems from being unmounted.
     */
    if (chdir("/") < 0) {
        syslog(LOG_ERR, "%s: can't change directory to /", cmd);
        exit(1);
    }
    /*
     * Close all open file descriptors.
     */
    if (rl.rlim_max == RLIM_INFINITY)
        rl.rlim_max = 1024;
    for (i = 0; i < rl.rlim_max; i++)
        close(i);
    /*
     * Attach file descriptors 0, 1, and 2 to /dev/null.
     */
    fd0 = open("/dev/null", O_RDWR);
    fd1 = dup(0);
    fd2 = dup(0);
    if (fd0 != 0 || fd1 != 1 || fd2 != 2) {
        syslog(LOG_ERR, "%s: unexpected file descriptors %d %d %d", cmd, fd0, fd1, fd2);
        exit(1);
    }
}
int main(int argc, char *argv[])
{
    char                *cmd;
    if ((cmd = strrchr(argv[0], '/')) == NULL)
        cmd = argv[0];
    else
        cmd++;
    /*
     * Become a daemon.
     */
    daemonize(cmd);
    /*
     * Make sure only one copy of the daemon is running.
     */
    if (already_running()) {
        syslog(LOG_ERR, "daemon already running");
        exit(1);
    }
    /*
     * code here
     */
    return 0;
}

 

参考链接:

http://man7.org/linux/man-pages/man3/daemon.3.html

https://stackoverflow.com/questions/17954432/creating-a-daemon-in-linux
http://alfred-sun.github.io/blog/2015/06/18/daemon-implementation/
https://typecodes.com/cseries/apuesingledaemonprocess.html
http://debugo.com/apue-deamon/
https://notes.shichao.io/apue/ch13/ #里面有几张很棒的图

=END=

, ,

《 “LINUX下守护进程的C语言实现#2” 》 有 2 条评论

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注