开发者

How to make a daemon process

I am trying to understand how can I make my program a daemon. So some things which I came across are in general, a program performs the following steps to become a daemon:

  1. Call fork().

  2. In the parent, call exit(). This ensures that the original parent (the daemon's grandparent) is satisfied that its child terminated, that the daemon's parent is no longer running, and that the daemon is not a process group leader. This last point is a requirement for the successful completion of the next step.

  3. Call setsid(), giving the daemon a new process group and session, both of which have it as leader. This also ensures that the process has no associated controlling terminal (as the process just created a new session, and will not assign one).

  4. Change the working directory to the root directory via chdir(). This is done because the inherited working directory can be anywhere on the filesystem. Daemons tend to run for the duration of the system's uptime, and you don't want to keep some random directory open, and thus prevent an administrator from unmounting the filesystem containing that directory.

  5. Close all file descriptors.

  6. Open file descriptors 0, 1, and 2 (standard in, standard out, and standard error) and redirect them to /dev/null.

#include <开发者_运维知识库;sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/fs.h>

int main (void)
{
    pid_t pid;
    int i;
    
    /* create new process */
    pid = fork ( );  
    if (pid == -1)  
        return -1;  
    else if (pid != 0)  
        exit (EXIT_SUCCESS);  

    /* create new session and process group */  
    if (setsid ( ) == -1)  
        return -1;  

    /* set the working directory to the root directory */  
    if (chdir ("/") == -1)  
        return -1;  

    /* close all open files--NR_OPEN is overkill, but works */  
    for (i = 0; i < NR_OPEN; i++)  
        close (i);  

    /* redirect fd's 0,1,2 to /dev/null */  
    open ("/dev/null", O_RDWR);  
    /* stdin */  
    dup (0);  
    /* stdout */  
    dup (0);  
    /* stderror */  
    
    /* do its daemon thing... */  
    
    return 0;  
}

Can some one give me a link to existing source code of some program like Apache so that I can understand this process in more depth?


If you are looking for a clean approach please consider using standard api- int daemon(int nochdir, int noclose);. Man page pretty simple and self explanatory. man page. A well tested api far outweigh our own implementation interms of portability and stability.


In Linux, it can be easily done using:

int main(int argc, char* argv[])
{
    daemon(0,0);
    while(1)
    {
        sleep(10)
        /*do something*/
    }

    return 0;
}


Concerning the part which closes the file descriptors, under Linux, the GLIBC's deamon() service merely redirects file descriptors 0, 1 and 2 to /dev/null using dup2(). Here is the code snippet of daemon() in GLIBC 2.34 (file misc/daemon.c):

    if (!noclose) {
        struct stat64 st;

        if ((fd = __open_nocancel(_PATH_DEVNULL, O_RDWR, 0)) != -1
            && (__builtin_expect (__fstat64 (fd, &st), 0)
            == 0)) {
            if (__builtin_expect (S_ISCHR (st.st_mode), 1) != 0
#if defined DEV_NULL_MAJOR && defined DEV_NULL_MINOR
                && (st.st_rdev
                == makedev (DEV_NULL_MAJOR, DEV_NULL_MINOR))
#endif
                ) {
                (void)__dup2(fd, STDIN_FILENO);
                (void)__dup2(fd, STDOUT_FILENO);
                (void)__dup2(fd, STDERR_FILENO);
                if (fd > 2)
                    (void)__close (fd);

Closing all the possible opened file descriptors using the NR_OPEN constant (typically equal to 1024) is not reliable as the limit on the number of opened file descriptors can be changed with setrlimit(RLIMIT_NOFILE, ...).
The currently opened file descriptors are present as symbolic links names in /proc/pid/fd directory. Here is the content of this directory from my current shell:

$ ls -la /proc/$$/fd
total 0
dr-x------ 2 xxx xxx  0 sept.   4 09:32 .
dr-xr-xr-x 9 xxx xxx  0 sept.   4 09:32 ..
lrwx------ 1 xxx xxx 64 sept.   4 09:32 0 -> /dev/pts/2
lrwx------ 1 xxx xxx 64 sept.   4 09:32 1 -> /dev/pts/2
lrwx------ 1 xxx xxx 64 sept.   4 09:32 2 -> /dev/pts/2
lrwx------ 1 xxx xxx 64 sept.   4 09:41 255 -> /dev/pts/2

Hence, a service function opening this directory for the current process could be used to close only the actually opened file descriptors:

#include <sys/types.h>
#include <dirent.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

void close_opened_fds(void)
{
  DIR *dp;
  char proc_fd_dirname[256];
  int my_fd;
  struct dirent *d;
  int fd;

  // Open /proc/<mypid>/fd directory
  snprintf(proc_fd_dirname, sizeof(proc_fd_dirname), "/proc/%d/fd", getpid());
  dp = opendir(proc_fd_dirname);
  if (!dp) {
    return;
  }

  // Get the file descriptor associated to the preceding open
  my_fd = dirfd(dp);

  while((d = readdir(dp))) {

    // Skip '.' and '..' directories
    if (d->d_name[0] == '.') {
      continue;
    }

    fd = atoi(d->d_name);

    // Close the file except if it is the fd of the opened directory
    if (fd != my_fd) {
      close(fd);
    }

  }

  closedir(dp);

}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜