/* Copyright (C) 2007-2009, 2012 Romain Quey */
/* see the COPYING file in the top-level directory.*/

#include<stdlib.h>
#include<limits.h>
#include<unistd.h>
#include<stdio.h>
#include<stdarg.h>
#include<sys/wait.h>
#include<sys/time.h>
#include<sys/stat.h>
#include<errno.h>
#include<signal.h>
#include<string.h>
#include<float.h>
#include"ut.h"

void
sighandler ()
{
}

int
ut_sys_runwtime (char *exec, char *command, double t)
{
  int status;
  pid_t pid;
  struct sigaction act;
  struct itimerval value = { {0, 0}, {0, 0} };
  char **list = NULL;
  int qty;

  memset (&act, 0, sizeof (struct sigaction));
  act.sa_handler = sighandler;
  // act.sa_flags = SA_RESTART;

  value.it_value.tv_sec = (long int) (t);
  value.it_value.tv_usec =
    (long int) ((double) (t - value.it_value.tv_sec) * 1000000);

  setitimer (ITIMER_REAL, &value, 0);

  sigaction (SIGCHLD, &act, 0);
  sigaction (SIGINT, &act, 0);
  sigaction (SIGALRM, &act, 0);

  ut_string_separate (command, " ", &list, &qty);
  list = ut_realloc_1d_pchar (list, qty + 1);
  list[qty] = NULL;
  pid = fork ();
  if (pid == 0)
    {
      execvp (exec, list);
      _exit (EXIT_FAILURE);
    }
  else if (pid < 0)
    /* The fork failed. Report failure. */
    status = -1;
  else
    {
      /* printf ("waiting for pid = %d\n", pid); */
      if (waitpid (pid, &status, 0) != pid)
	status = -1;
      /* printf ("waiting for pid = %d\n", pid); */

      /* it is likely that this should not be necessary */
      if (status == -1)
	{
	  /* printf ("killing %d\n", pid); */
	  kill (pid, 9);
	}
    }

  ut_free_2d_char (list, qty + 1);

  return status;
}

int
ut_sys_mkdirp (const char *dir, ...)
{
  int status;
  char tmp[1000];
  char *p = NULL;
  size_t len;

  va_list args;

  va_start (args, dir);
  vsnprintf (tmp, sizeof (tmp), dir, args);
  va_end (args);

  len = strlen (tmp);
  if (tmp[len - 1] == '/')
    tmp[len - 1] = 0;
  for (p = tmp + 1; *p; p++)
    if (*p == '/')
      {
	*p = 0;
	mkdir (tmp, S_IRWXU | S_IRGRP | S_IXGRP);
	*p = '/';
      }

  status = mkdir (tmp, S_IRWXU | S_IRGRP | S_IXGRP);

  if (status && errno != EEXIST)
    {
      ut_print_message (2, 2, "%s cannot be created.\n", dir);
      abort ();
    }

  return 0;
}

int
ut_sys_isdir (const char *pathname, ...)
{
  struct stat sb;

  char tmp[1000];
  va_list args;

  va_start (args, pathname);
  vsnprintf (tmp, sizeof (tmp), pathname, args);
  va_end (args);

  return (stat (tmp, &sb) == 0 && S_ISDIR (sb.st_mode));
}

char *
ut_sys_realpath (const char *pathname)
{
  char *actualpath = NULL; // ut_alloc_1d_char (PATH_MAX + 1);
  char *ptr = NULL;

  ptr = realpath (pathname, actualpath);

  if (ptr == NULL)
    ut_free_1d_char (actualpath);

  return ptr;
}

int
ut_sys_currentbin_path (char **ppath)
{
  ssize_t r;
  // see http://linux.die.net/man/2/readlink for how not to use a fixed bufsize
  int bufsize = 1024;

  (*ppath) = ut_alloc_1d_char (bufsize);

  r = readlink ("/proc/self/exe", *ppath, bufsize);

  return (r == -1) ? -1 : 0;
}
