/* hooks.c:
 *
 ****************************************************************
 * Copyright (C) 2003 Tom Lord
 *
 * See the file "COPYING" for further information about
 * the copyright and warranty status of this work.
 */


#include "hackerlab/bugs/panic.h"
#include "hackerlab/os/stdarg.h"
#include "hackerlab/os/sys/types.h"
#include "hackerlab/os/unistd.h"
#include "hackerlab/os/sys/wait.h"
#include "hackerlab/os/signal.h"
#include "hackerlab/char/str.h"
#include "hackerlab/fs/file-names.h"
#include "hackerlab/arrays/ar.h"
#include "hackerlab/vu/safe.h"
#include "tla/libarch/my.h"
#include "tla/libarch/hooks.h"



extern char ** environ;


int
arch_run_hook (t_uchar * name, ...)
{
  t_uchar * hook_script = 0;
  int exit_status = 0;

  hook_script = arch_my_hook_script ();

  if (hook_script)
    {
      va_list ap;
      t_uchar * hook_tail = 0;
      t_uchar ** argv = 0;
      t_uchar ** env = 0;
      int x;
      int pid;

      hook_tail = file_name_tail (0, hook_script);

      *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (t_uchar *)) = str_save (0, hook_tail);
      *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (t_uchar *)) = str_save (0, name);
      *(t_uchar **)ar_push ((void **)&argv, 0, sizeof (t_uchar *)) = 0;

      va_start (ap, name);
      while (1)
        {
          t_uchar * var;
          t_uchar * val;

          var = va_arg (ap, t_uchar *);
          if (!var)
            break;

          val = va_arg (ap, t_uchar *);
          invariant (!!val);

          *(t_uchar **)ar_push ((void **)&env, 0, sizeof (t_uchar *)) = str_alloc_cat_many (0, var, "=", val, str_end);
        }
      va_end (ap);

      for (x = 0; environ[x]; ++x)
        *(t_uchar **)ar_push ((void **)&env, 0, sizeof (t_uchar *)) = str_save (0, environ[x]);

      *(t_uchar **)ar_push ((void **)&env, 0, sizeof (t_uchar *)) = 0;

      pid = fork ();
      if (pid == -1)
        panic ("unable to fork for hook");

      if (pid)
        {
          int status;
          int wait_pid;

          wait_pid = waitpid (pid, &status, 0);
          if (wait_pid < 0)
            {
              panic_msg ("error waiting for hook subprocess");
              kill (0, SIGKILL);
              panic ("error waiting for hook subprocess");
            }
          if (WIFSIGNALED (status))
            {
              safe_printfmt (2, "\n");
              safe_printfmt (2, "arch_run_hook: hook subprocess killed by signal %d\n", WTERMSIG (status));
              safe_printfmt (2, "\n");
              exit (2);
              return -1;
            }
          else if (!WIFEXITED (status))
            {
              panic_msg ("waitpid returned for a non-exited hook process");
              kill (0, SIGKILL);
              panic ("waitpid returned for a non-exited hook process and kill failed");
              return -1;
            }
          else
            {
              exit_status = WEXITSTATUS (status);
            }
        }
      else
        {
          execve (hook_script, (char **)argv, (char **)env);
          panic ("invoke_tar_extract: execve for hook script returned to caller");
          exit (2);
        }

      lim_free (0, hook_tail);
      for (x = 0; x < ar_size ((void *)argv, 0, sizeof (t_uchar *)); ++x)
        {
          lim_free (0, argv[x]);
        }
      ar_free ((void **)&argv, 0);
      for (x = 0; x < ar_size ((void *)env, 0, sizeof (t_uchar *)); ++x)
        {
          lim_free (0, env[x]);
        }
      ar_free ((void **)&env, 0);
    }

  lim_free (0, hook_script);
  return exit_status;
}




/* tag: Tom Lord Mon Jun 16 17:47:47 2003 (hooks.c)
 */
