/*
**
** Copyright (C) 1994 Swedish University Network (SUNET)
**
**
** This program is developed by UDAC, Uppsala University by commission
** of the Swedish University Network (SUNET). 
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITTNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
** 
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
**
**
**                                        Martin.Wendel@udac.uu.se
**                                        Torbjorn.Wictorin@udac.uu.se
**
**                                        UDAC	
**                                        P.O. Box 174
**                                        S-751 04 Uppsala
**                                        Sweden
**
*/


#include "emil.h"
#include <fcntl.h>
extern int pseudo_route;
static	int	fd[2];

void
do_fork()
{
  /* int pgrp; */
  char *precipient;

  if (pipe(fd) != 0)
    {
      logger(LOG_ERR, "Unable to create pipe\n");
      closelog();
      fprintf(stderr, "Emil: Unable to create pipe\n");
      exit(EX_OSERR);
    }
  if (fork() == 0) 
    {
      /* Child */
      int dev;
      {
	/* setpgrp(0, pgrp); */
	if (close(0) == -1) {
	  logger(LOG_ERR, "close child failed \n");
	  fprintf(stderr, "Emil: Close child failed\n");
	  exit(EX_IOERR);
	}
	if (dup(fd[0]) == -1) {
	  logger(LOG_ERR, "dup 1 failed\n");
	  fprintf(stderr, "Emil: dup 1 failed\n");
	  exit(EX_OSERR);
	}
	if (close(fd[0]) == -1 || close(fd[1]) == -1) {
	  logger(LOG_ERR, "close 1 failed\n");
	  fprintf(stderr, "Emil: Close 1 failed\n");
	  exit(EX_IOERR);
	}
	if (close(1) == -1) 
	  {
	    logger(LOG_ERR, "close 2 failed\n");
	    fprintf(stderr, "Emil: Close 2 failed\n");
	    exit(EX_IOERR);
	  }
	if ((dev = open("/dev/null", O_WRONLY)) == -1)
	  {
	    logger(LOG_ERR, "open /dev/null failed\n");
	    fprintf(stderr, "Emil: Open /dev/null failed\n");
	    exit(EX_NOPERM);
	  }
	if (dup(dev) == -1) {
	  logger(LOG_ERR, "dup 2 failed\n");
	  fprintf(stderr, "Emil: Dup 2 failed\n");
	  exit(EX_OSERR);
	}
	if (close(2) == -1)
	  {
	    logger(LOG_ERR, "close 3 failed\n");
	    fprintf(stderr, "Emil: Close 3 failed\n");
	    exit(EX_IOERR);
	  }
	if (dup(dev) == -1) {
	  logger(LOG_ERR, "dup 3 failed\n");
	  fprintf(stderr, "Emil: Dup 3 failed\n");
	  exit(EX_OSERR);
	}
	if (close(dev) == -1)
	  {
	    logger(LOG_ERR, "close 3 failed\n");
	    fprintf(stderr, "Emil: Close 3 failed\n");
	    exit(EX_IOERR);
	  }
	precipient = (char *)Yalloc(strlen(recipient) + 8);
	if (pseudo_route == 1)
	  sprintf(precipient, "@EMIL:%s", recipient);
	else
	  sprintf(precipient, "%s", recipient);
	execv(mailer[0], &mailer[1]);
	closelog();
	fprintf(stderr, "Emil: Reached unreachable in forks.c\n");
	exit(EX_UNAVAILABLE); 
      }
    }
  else
    /* Parent */
    {
      if (close(fd[0]) == -1) {
	logger(LOG_ERR, "close 4 failed\n");
	closelog();
	fprintf(stderr, "Emil: Close 4 failed\n");
	exit(EX_IOERR);
      }
      if (close(1) == -1) {
	logger(LOG_ERR, "close 5 failed\n");
	closelog();
	fprintf(stderr, "Emil: Close 5 failed\n");
	exit(EX_IOERR);
      }
      if (dup(fd[1]) == -1)
	{
	  logger(LOG_ERR, "dup 4 failed");
	  closelog();
	  fprintf(stderr, "Emil: Dup 4 failed\n");
	  exit(EX_OSERR);
	}
    }
}

int
end_fork()
{
      /* Cleanup after fork */

      int status;

      if (close(1) == -1) {
	logger(LOG_ERR, "close 6 failed\n");
	closelog();
	fprintf(stderr, "Emil: Close 6 failed\n");
	exit(EX_IOERR);
      }

      if (close(fd[1]) == -1) {
	logger(LOG_ERR, "close 7 failed\n");
	closelog();
	fprintf(stderr, "Emil: Close 7 failed\n");
	exit(EX_IOERR);
      }
      closelog();
      wait(&status);
      if (status == -1)
	exit(EX_SOFTWARE);

      if ((status & 0377) != 0)
	exit(EX_TEMPFAIL);

      /* normal death -- return status */
      status = (status >> 8) & 0377;
      exit(status);
}




