A Simple Introduction to Linux Daemon (with exa...

Daemon

In Unix and other multitasking computer operating systems, a daemon is a computer program that runs as a background process, rather than being under the direct control of an interactive user. Alternate terms for daemon are service (Microsoft Windows NT), subsystem (IBM z/OS), server virtual machine (IBM VM), ghost job (XDS UTS).

Systems often start daemons at boot time: they often serve the function of responding to network requests, hardware activity, or other programs by performing some task. Daemons can also configure hardware (like udevd on some GNU/Linux systems), run scheduled tasks (like cron), and perform a variety of other tasks.

In a strictly technical sense, a Unix-like system process is a daemon when its parent process terminates and the daemon is assigned the init process (process number 1) as its parent process and has no controlling terminal. However, more commonly, a daemon may be any background process, whether a child of init or not.

In a word, a daemon has two major characteristics which distinguish a daemon from other normal processes. It runs in background, and it has no direct interactive control interface.

 

 

Linux Daemon

The common method for a process to become a daemon involves:

  • Dissociating from the controlling tty
  • Becoming a session leader
  • Becoming a process group leader
  • Executing as a background task by forking and exiting (once or twice). This is required sometimes for the process to become a session leader. It also allows the parent process to continue its normal execution.
  • Setting the root directory ("/") as the current working directory so that the process does not keep any directory in use that may be on a mounted file system (allowing it to be unmounted).
  • Changing the umask to 0 to allow open(), creat(), et al. operating system calls to provide their own permission masks and not to depend on the umask of the caller
  • Closing all inherited files at the time of execution that are left open by the parent process, including file descriptors 0, 1 and 2 (stdin, stdout, stderr). Required files will be opened later.
  • Using a logfile, the console, or /dev/null as stdin, stdout, and stderr

 

SYNOPSIS

       #include <unistd.h>

 

       int daemon(int nochdir, int noclose);

 

nochdir == 0 => chdir to ‘/’

noclose == 0 => close all inherited files

HowTo

A daemon should do one thing, and do it well. That one thing may be as complex as managing hundreds of mailboxes on multiple domains, or as simple as writing a report and calling sendmail to mail it out to an admin.

Daemons should never have direct communication with a user through a terminal. In fact, a daemon shouldn't communicate directly with a user at all. All communication should pass through some sort of interface (which you may or may not have to write), which can be as complex as a GTK+ GUI, or as simple as a signal set.

To conclude, we have to plan job and interface for a daemon.

When a daemon starts up, it has to do some low-level housework to get itself ready for its real job. This involves a few steps:

  • Fork off the parent process
  • Change file mode mask (umask)
  • Open any logs for writing
  • Create a unique Session ID (SID)
  • Change the current working directory to a safe place
  • Close standard file descriptors
  • Enter actual daemon code

One Golden Principle: Program Defensively!

 

 

//Example 1 (use daemon(3) library function to create a daemon)
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

int main(int argc, char *argv[])
{
        assert(argc == 3);
        int nochdir = atoi(argv[1]);
        int noclose = atoi(argv[2]);
        printf("Start Test Daemon\n");
        int ret = daemon(nochdir, noclose);
        if (ret < 0)
                exit(EXIT_FAILURE);
        while(1)
        {
                sleep(1);
                printf("Test Daemon Running ...\n");
        }
        printf("End Test Daemon\n");
        exit(EXIT_SUCCESS);
}

 

It seems that a daemon(3) is a simple encapsulation of forking off the parent process, change the file mode mask, creating a unique session ID, changing the current working directory and closing the standard file descriptors.

 

 

//Example 2 (use fork, umask, setsid, chdir, close, syslog …)
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <assert.h>
#include <time.h>
#include <string.h>

#define LOG_FILE "/var/log/test_daemon.log"
#define LOCK_FILE "/var/lock/test_daemon"
static void CQ_log(FILE *fp, const char *msg)
{
        assert(fp != NULL);
        assert(msg != NULL);
        struct tm *current_time = NULL;
        char *time_string = NULL;
        time_t t = time(NULL);
        current_time = gmtime(&t); /* the return value of gmtime is statically allocated, no need for free */
        assert(current_time != NULL);
        time_string = asctime(current_time);
        assert(time_string != NULL);
        fwrite(time_string, sizeof(char), strlen(time_string)+1, fp);
        fwrite(msg, sizeof(char), strlen(msg), fp);
        fwrite("\n", sizeof(char), strlen("\n"), fp);
        fflush(fp);
}

int main(void)
{
        /* process ID and session ID */
        pid_t pid, sid;

        /* create a lock file to prevent the daemon from running twice */
        int lock_fd = open(LOCK_FILE, O_RDWR | O_CREAT | O_EXCL, 0640); 
        if (lock_fd < 0)
        {
                exit(EXIT_FAILURE);
        }

        /* fork off the parent process */
        pid = fork();
        if (pid < 0)
        {
                exit(EXIT_FAILURE);
        }
        if (pid > 0)
        {
                exit(EXIT_SUCCESS);
        }
        /* change the file mode mask */
        umask(0);

        /* open log here */
        FILE* fp_log = fopen(LOG_FILE, "a");
        if (fp_log == NULL)
        {
                exit(EXIT_FAILURE);
        }

        /* create a new sid for child process */
        sid = setsid();
        if (sid < 0)
        {
                CQ_log(fp_log, "FAILURE: create a new session id");
                exit(EXIT_FAILURE);
        }

        /* change the current working directory */
        if ((chdir("/"))<0)
        {
                CQ_log(fp_log, "FAILURE: chdir to / failed");
                exit(EXIT_FAILURE);
        }

        /* close out the standard file descriptors */
        close(STDIN_FILENO);
        close(STDOUT_FILENO);
        close(STDERR_FILENO);

        /* daemon specific initialization goes here */
        CQ_log(fp_log, "Start Initializing Test Daemon");
        CQ_log(fp_log, "End Initializing Test Daemon");

        /* the big loop */
        while(1)
        {
                /* do something here */
                CQ_log(fp_log, "Test Daemon Running ...");
                sleep(10);
        }
        exit(EXIT_SUCCESS);
}

 

root@localhost :/home/James/mypro/Linux-Pro/daemon# cat /var/log/test_daemon.log
Wed Jun 13 07:52:47 2012
Start Initializing Test Daemon
Wed Jun 13 07:52:47 2012
End Initializing Test Daemon
Wed Jun 13 07:52:47 2012
Test Daemon Running ...
root@localhost :/home/James/mypro/Linux-Pro/daemon# ./test_daemon
root@localhost :/home/James/mypro/Linux-Pro/daemon# echo $?
1

 

References

http://en.wikipedia.org/wiki/Daemon_(computer_software)

man daemon

man 3 setsid

man start-stop-daemon

http://www-theorie.physik.unizh.ch/~dpotter/howto/daemonize

http://www.netzmafia.de/skripten/unix/linux-daemon-howto.html

http://wenku.baidu.com/view/73a4771b227916888486d77a.html

 

 

 

 

 

 

你可能感兴趣的:(linux,Daemon,file_lock)