0

I have picked the following example from APUE :

void daemonize(const char* cmd)
{
        int i,fd0,fd1,fd2;
        pid_t pid;
        struct rlimit r1;
        struct sigaction sa;

        //clear all file masks
        umask(0);

        //get max number of file descriptors
        if(getrlimit(RLIMIT_NOFILE,&r1) < 0)
        {
                perror("error getting file descriptor size");
                return;
        }

        //become a session leader
        if((pid = fork()) < 0)
        {
                perror("error forking");
                return;
        }
        else if(pid == 0)
        {
                setsid();
        }
        else
        {
                exit(0); //parent exits
        }

        sa.sa_handler = SIG_IGN;
        sigemptyset(&sa.sa_mask);
        sa.sa_flags = 0;
        if(sigaction(SIGHUP,&sa,NULL) < 0)
        {
                return;
        }

        if((pid = fork()) < 0)
        {
                return;
        }
        else if(pid != 0)
        {
                exit(0); //parent
        }

        //child continues

        syslog(LOG_ERR,"chile continuing with pid : %d",getpid());
        //change the working directory
        if(chdir("/") < 0)
        {
                return;
        }

        if(r1.rlim_max == RLIM_INFINITY)
                r1.rlim_max = 1024;
        for(i=0;i<r1.rlim_max;i++)
                close(i);

        //attach the file descriptors to /dev/null
        fd0 = open("/dev/null",O_RDWR);
        fd1 = dup(0);
        fd2 = dup(0);

        //initialize the log file
        openlog(cmd, LOG_CONS,LOG_DAEMON);
        if(fd0!=0 || fd1!=1 || fd2!=2)
        {
                syslog(LOG_ERR,"unexpected file descriptors %d %d %d\n",fd0,fd1,fd2);
                exit(1);
        }
}


int main()
{
        daemonize("date");
        pause();    //how is this working???
}

What I don't understand is how the pause() from the main function is working? What I was expecting is that since we have done exit(0) for the parent process in daemonize(), it should have exited and resulted in the normal termination of the main() process. It should have never returned to the main() and the call to pause() should not even happen. Why it did not terminate and why the pause() got called?

Naveen
  • 7,944
  • 12
  • 78
  • 165

1 Answers1

3

The code forks twice, producing a parent, a child, and a grandchild. The first two each exit(0); the last returns from daemonize.

rici
  • 234,347
  • 28
  • 237
  • 341
  • @aah... I missed that. Thanks. In fact, for a second i forgot that fact that the grandchild will still be executing the code as the gradparent (except few if-checks based on pid). – Naveen May 19 '19 at 03:54
  • One more question please, why we have called second `fork()` here when we had already done `setsid()` and started a new session. Is there a problem in continuing as a session and group leader after `setsid()`? – Naveen May 19 '19 at 03:57
  • 1
    @insane: That's explained in the note right at the top of page 426: it prevents the daemon from acquiring a controlling terminal even if it happens to open a terminal device. – rici May 19 '19 at 04:06