zoukankan      html  css  js  c++  java
  • How to Daemonize in Linux

    How to Daemonize in Linux - silent_wind的专栏 - 博客频道 - CSDN.NET

    How to Daemonize in Linux

    分类: UNIX 170人阅读 评论(0) 收藏 举报

    One of the things I keep running across is Linux daemons that don’t properly daemonize themselves. To properly daemonize, the following steps must be followed.

    • The fork() call is used to create a separate process.
    • The setsid() call is used to detach the process from the parent (normally a shell).
    • The file mask should be reset.
    • The current directory should be changed to something benign.
    • The standard files (stdin,stdout and stderr) need to be reopened.

    Failure to do any of these steps will lead to a daemon process that can misbehave. The typical symptoms are as follows.

    • Starting the daemon and then logging out will cause the terminal to hang. This is particularly nasty with ssh.
    • The directory from which the daemon was launched remains locked.
    • Spurious output appears in the shell from which the daemon was started.

    Simple Example

    The following example program performs the bare minimum steps required to launch a daemon process.

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    
    #define EXIT_SUCCESS 0
    #define EXIT_FAILURE 1
    
    static void daemonize(void)
    {
        pid_t pid, sid;
    
        /* already a daemon */
        if ( getppid() == 1 ) return;
    
        /* Fork off the parent process */
        pid = fork();
        if (pid < 0) {
            exit(EXIT_FAILURE);
        }
        /* If we got a good PID, then we can exit the parent process. */
        if (pid > 0) {
            exit(EXIT_SUCCESS);
        }
    
        /* At this point we are executing as the child process */
    
        /* Change the file mode mask */
        umask(0);
    
        /* Create a new SID for the child process */
        sid = setsid();
        if (sid < 0) {
            exit(EXIT_FAILURE);
        }
    
        /* Change the current working directory.  This prevents the current
           directory from being locked; hence not being able to remove it. */
        if ((chdir("/")) < 0) {
            exit(EXIT_FAILURE);
        }
    
        /* Redirect standard files to /dev/null */
        freopen( "/dev/null", "r", stdin);
        freopen( "/dev/null", "w", stdout);
        freopen( "/dev/null", "w", stderr);
    }
    
    int main( int argc, char *argv[] ) {
        daemonize();
    
        /* Now we are a daemon -- do the work for which we were paid */
    
    
        return 0;
    }
    
    It has been brought to my attention that a second call to fork() may be required to fully detach the process from the controller terminal (in other words: fork, setsid, fork). This does not seem to be required in Linux. A second fork would not cause any problems, although it would complicate the child/parent signalling below.

    A More Useful Example

    The following program extends the basic daemon by adding the following features.

    • Logs messages to the system log (via syslog).
    • Creates a lock file to prevent the daemon from being run twice.
    • Changes the effective user (drops privileges).
    • Startup errors are reported to the main process.
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <syslog.h>
    #include <errno.h>
    #include <pwd.h>
    #include <signal.h>
    
    /* Change this to whatever your daemon is called */
    #define DAEMON_NAME "mydaemon"
    
    /* Change this to the user under which to run */
    #define RUN_AS_USER "daemon"
    
    #define EXIT_SUCCESS 0
    #define EXIT_FAILURE 1
    
    
    static void child_handler(int signum)
    {
        switch(signum) {
        case SIGALRM: exit(EXIT_FAILURE); break;
        case SIGUSR1: exit(EXIT_SUCCESS); break;
        case SIGCHLD: exit(EXIT_FAILURE); break;
        }
    }
    
    static void daemonize( const char *lockfile )
    {
        pid_t pid, sid, parent;
        int lfp = -1;
    
        /* already a daemon */
        if ( getppid() == 1 ) return;
    
        /* Create the lock file as the current user */
        if ( lockfile && lockfile[0] ) {
            lfp = open(lockfile,O_RDWR|O_CREAT,0640);
            if ( lfp < 0 ) {
                syslog( LOG_ERR, "unable to create lock file %s, code=%d (%s)",
                        lockfile, errno, strerror(errno) );
                exit(EXIT_FAILURE);
            }
        }
    
        /* Drop user if there is one, and we were run as root */
        if ( getuid() == 0 || geteuid() == 0 ) {
            struct passwd *pw = getpwnam(RUN_AS_USER);
            if ( pw ) {
                syslog( LOG_NOTICE, "setting user to " RUN_AS_USER );
                setuid( pw->pw_uid );
            }
        }
    
        /* Trap signals that we expect to recieve */
        signal(SIGCHLD,child_handler);
        signal(SIGUSR1,child_handler);
        signal(SIGALRM,child_handler);
    
        /* Fork off the parent process */
        pid = fork();
        if (pid < 0) {
            syslog( LOG_ERR, "unable to fork daemon, code=%d (%s)",
                    errno, strerror(errno) );
            exit(EXIT_FAILURE);
        }
        /* If we got a good PID, then we can exit the parent process. */
        if (pid > 0) {
    
            /* Wait for confirmation from the child via SIGTERM or SIGCHLD, or
               for two seconds to elapse (SIGALRM).  pause() should not return. */
            alarm(2);
            pause();
    
            exit(EXIT_FAILURE);
        }
    
        /* At this point we are executing as the child process */
        parent = getppid();
    
        /* Cancel certain signals */
        signal(SIGCHLD,SIG_DFL); /* A child process dies */
        signal(SIGTSTP,SIG_IGN); /* Various TTY signals */
        signal(SIGTTOU,SIG_IGN);
        signal(SIGTTIN,SIG_IGN);
        signal(SIGHUP, SIG_IGN); /* Ignore hangup signal */
        signal(SIGTERM,SIG_DFL); /* Die on SIGTERM */
    
        /* Change the file mode mask */
        umask(0);
    
        /* Create a new SID for the child process */
        sid = setsid();
        if (sid < 0) {
            syslog( LOG_ERR, "unable to create a new session, code %d (%s)",
                    errno, strerror(errno) );
            exit(EXIT_FAILURE);
        }
    
        /* Change the current working directory.  This prevents the current
           directory from being locked; hence not being able to remove it. */
        if ((chdir("/")) < 0) {
            syslog( LOG_ERR, "unable to change directory to %s, code %d (%s)",
                    "/", errno, strerror(errno) );
            exit(EXIT_FAILURE);
        }
    
        /* Redirect standard files to /dev/null */
        freopen( "/dev/null", "r", stdin);
        freopen( "/dev/null", "w", stdout);
        freopen( "/dev/null", "w", stderr);
    
        /* Tell the parent process that we are A-okay */
        kill( parent, SIGUSR1 );
    }
    
    int main( int argc, char *argv[] ) {
        /* Initialize the logging interface */
        openlog( DAEMON_NAME, LOG_PID, LOG_LOCAL5 );
        syslog( LOG_INFO, "starting" );
    
        /* One may wish to process command line arguments here */
    
        /* Daemonize */
        daemonize( "/var/lock/subsys/" DAEMON_NAME );
    
        /* Now we are a daemon -- do the work for which we were paid */
    
    
        /* Finish up */
        syslog( LOG_NOTICE, "terminated" );
        closelog();
        return 0;
    }
  • 相关阅读:
    sudo
    Ansible模块
    Ansible自动化运维
    Sersync
    eclipse报错MA
    myeclipse报错MA
    通过StringBuilder的reverse()实现倒序
    位运算实现高效互换
    scanf("%s",s)与gets(s)
    异或运算符实现简单加密
  • 原文地址:https://www.cnblogs.com/lexus/p/2937547.html
Copyright © 2011-2022 走看看