/*
 *******************************************************************
 * $Author: lindner $
 * $Revision: 1.1 $
 * $Date: 91/03/25 21:10:22 $
 * $Source: /export/mermaid/staff/lindner/gopherd/RCS/daemon.c,v $
 *******************************************************************
 */

#include "gopherd.h"

#define BSD 1       /* System V signal handling doesn't seem to work
		       Correctly */

/*
 * A BSD style SIGCLD signal handler that can be used by a server
 * that's not interested in its child's exit status, but needs to
 * wait for them, to avoid clogging up the system with zombies.
 *
 * Beware that the calling process may get an interrupted system
 * call when we return, so they had better handle that.
 *
 * (From Stevens pg 82)
 */

#include <sys/ioctl.h>
#include <sys/wait.h>
#include <signal.h>

#ifdef HP9000
  #define TIOCNOTTY       _IO('t', 113)           /* void tty association */
#endif

sig_child()
{
#ifdef BSD
     /*
      * Use the wait3() system call with the WNOHANG option
      */

     int pid;
     union wait  status;

     while ( (pid = wait3(&status, WNOHANG, (struct rusage *) 0)) > 0)
	  ;
#endif
}


#include <stdio.h>
#include <sys/param.h>
#include <errno.h>
extern int errno;

#ifdef SIGTSTP    /* True on a BSD system */
#include <sys/file.h>
#include <sys/ioctl.h>
#endif

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

daemon_start(ignsigcld)
int ignsigcld;          /* Nonzero -> nuke zombie children */
{
     register int childpid, fd;

     /*
      * If we were started by init (process 1) from the /etc/inittab
      * file there's no need to detach.
      */
      
     if (getppid() != 1) {

	  

#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
	   */
	  
#ifdef SIGTSTP  /* BSD */

	  if (setpgrp(0, getpid()) == -1)
	       err_sys("can't change process group");
	  
	  if ( (fd = open("/dev/tty", O_RDWR)) >= 0) {
	       ioctl(fd, TIOCNOTTY, (char *)NULL); /* lose controlling TTY*/
	       close(fd);
	  }
	  
#else /* System V */
	  
	  if (setpgrp() == -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 */
#endif

     }  /* End of if test for ppid == 1 */

     /** Close any file descriptors **/

     for (fd = 0; fd < NOFILE; fd++)
	  close(fd);

     errno = 0;  /* probably set to EBADF from a close */


     /** Change the current directory to / **/

      chdir("/");

     /** Clear inherited file mode creation mask. **/

     umask(0);

     /*
      * See if the caller isn't ineterested in the exit status of its
      * children, and doesn't want to have them become zombies
      */

     if (ignsigcld) {
#ifdef SIGTSTP
	  int sig_child();

	  signal(SIGCLD, sig_child);  /* BSD */
#else
	  signal(SIGCLD, SIG_IGN);    /* System V */
#endif
     }
}
