#ifdef _AIX
#define _ALL_SOURCE
#endif

#include "lclient.h"

#include <stdio.h>
#include <errno.h>

#include <fcntl.h>

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

static void alarm_handler(int sig)
{
}


int main(int argc, char *argv[])
{
  int fd, pid1, pid2;
  unsigned char key[KEY_SIZE];
  char **pargv;
#ifdef __ultrix
  union wait status;
#else
  int status;
#endif
  struct sigaction action;

  if (argc < 4)
    {
    usage:
      fputs("usage: run [-keyfile key-file] [-key key0 key1 key2 key3] program [arg ...]\n", stderr);
      return 1;
    }
  if (!strcmp(argv[1], "-keyfile"))
    {
      if (read_key_file("run", argv[2], key, sizeof key))
	return 2;
      pargv = &argv[3];
    }
  else if (!strcmp(argv[1], "-key"))
    {
#if CRYPT_TYPE == DES_CRYPT
      if (argc < 5 || lclient_parse_key_64(key, argv[2], argv[3]))
	goto usage;
      pargv = &argv[4];
#endif
#if CRYPT_TYPE == MD5_CRYPT
      if (argc < 7 || lclient_parse_key_128(key, argv[2], argv[3], argv[4], argv[5]))
	goto usage;
      pargv = &argv[6];
#endif
    }
  else
    {
      goto usage;
    }

  fd = open(pargv[0], O_RDONLY);
  if (fd == -1)
    {
      perror("run: unable to open input file");
      return 2;
    }

  pid1 = fork();
  if (pid1 > 0)
    {
      /* parent process should exit when child does, not when ^C pressed */
      signal(SIGINT, SIG_IGN);
      if (waitpid(pid1, &status, 0) == -1)
	perror("waitpid");
      return 0;
    }
  if (pid1 == -1)
    {
      perror("run: fork");
      return 3;
    }

  pid2 = decrypt_exec("run", pargv, fd, key);

  if (pid2 == 0)
    return 4;

  /* No need for terminal any more.  */
  close(0);
#ifndef DEBUG
  close(1);
#endif
#ifdef DEBUG
  printf("pid %d\n", pid2);
#endif
  signal(SIGTSTP, SIG_IGN);
  signal(SIGINT, SIG_IGN);

  /* Make SIGALRM interrupt the waitpid call.  The alternative method (making
     calls from the SIGALRM handler) could cause problems with single-threaded
     libraries.  */
  action.sa_handler = alarm_handler;
  sigemptyset(&action.sa_mask);

#ifndef SOLARIS /* XXX POSIX might be right */
  action.sa_flags = SV_INTERRUPT;
  sigaction(SIGALRM, &action, (struct sigaction *)0);
#endif

  while (1)
    {
      alarm(8);
      if (waitpid(pid2, &status, WUNTRACED) == -1)
	if (errno == EINTR)
	  {
	    /* send status report */
#ifdef DEBUG
	    puts("child running");
#endif
	    continue;
	  }
	else
	  {
	    perror("wait");
	    return 1;
	  }
      if (WIFSTOPPED(status))
	{
#ifdef DEBUG
	  puts("child stopped");
#endif
	  continue;
	}
      if (WIFEXITED(status))
	{
	  return WEXITSTATUS(status);
	}
      if (WIFSIGNALED(status))
	{
#ifdef DEBUG
	  printf("child died of signal %d\n", WTERMSIG(status));
#endif
	  return -WTERMSIG(status);
	}
    }
}

