/*
 * Initialize a daemon process.
 */

#include	<stdio.h>
#include	<signal.h>
#include	<sys/param.h>
#include	<errno.h>
#include    <unistd.h>
#include	<sys/file.h>
#include	<sys/ioctl.h>
#include    <sys/stat.h>

extern int	errno;
extern void err_sys(char *fmt, ...);

/*
 * Detach a daemon process from login session context.
 */

void
daemon_start(int ignsigcld)
   	          	/* nonzero -> handle SIGCLDs so zombies don't clog */
{
  register int	childpid, fd;
  
      /*
       * If we were started by init (process 1) from the /etc/inittab file
       * there's no need to detach.
       * This test is unreliable due to an unavoidable ambiguity
       * if the process is started by some other process and orphaned
       * (i.e., if the parent process terminates before we are started).
       */
  
  if (getppid() == 1)
    goto out;
  
      /*
       * Ignore the terminal stop signals (BSD).
       */
  
#ifdef SIGTTOU
  signal(SIGTTOU, SIG_IGN);
#endif
#ifdef SIGTTIN
  signal(SIGTTIN, SIG_IGN);
#endif
#ifdef SIGTSTP
  signal(SIGTSTP, SIG_IGN);
#endif
  
      /*
       * If we were not started in the background, fork and
       * let the parent exit.  This also guarantees the first child
       * is not a process group leader.
       */
  
  if ( (childpid = fork()) < 0)
    err_sys("can't fork first child");
  else if (childpid > 0)
    exit(0);	/* parent */
  
      /*
       * First child process.
       *
       * Disassociate from controlling terminal and process group.
       * Ensure the process can't reacquire a new controlling terminal.
       */
  
  if (setpgid(0, getpid()) == -1)
    err_sys("can't change process group");
  
  signal(SIGHUP, SIG_IGN);	/* immune from pgrp leader death */
  
  if ( (childpid = fork()) < 0)
    err_sys("can't fork second child");
  else if (childpid > 0)
    exit(0);	/* first child */
  
      /* second child */
  
  out:
      /*
       * Close any open files descriptors.
       */
  
  for (fd = 0; fd < NOFILE; fd++)
    close(fd);
  
  errno = 0;		/* probably got set to EBADF from a close */
  
      /*
       * Move the current directory to root, to make sure we
       * aren't on a mounted filesystem.
       */
  
  chdir("/");
  
      /*
       * Clear any inherited file mode creation mask.
       */
  
  umask(0);
  
      /*
       * See if the caller isn't interested in the exit status of its
       * children, and doesn't want to have them become zombies and
       * clog up the system.
       * With System V all we need do is ignore the signal.
       * With BSD, however, we have to catch each signal
       * and execute the wait3() system call.
       */
  
  if (ignsigcld)
    {
      signal(SIGCLD, SIG_IGN);	/* System V */
    }
}
