#include "checker.h"
#include <signal.h>

#ifdef CHKR_USE_BITMAP

#ifndef _NSIG
#define NSIGNALS 32
#else
#define NSIGNALS _NSIG
#endif

void _sig_jump_to(void *, void *);
static struct sigaction sig_tab[NSIGNALS+1];

/* The really used handler.
 * It calls your handler after changing the rights of the stack.
 */
static void 
chkr_sig_handler(int nsignal)
{
 known_stack_limit = &nsignal;
 chkr_set_right(&nsignal, SIG_FRAME_SIZE, CHKR_RW);
 _sig_jump_to(sig_tab[nsignal].sa_handler, &nsignal);	/* A jump */
}

/*
 * Save signal before main.
 */
void
save_signals(void)
{
 int i;
 struct sigaction t;
 
 for (i=1; i < NSIGNALS; i++)
   {
     chkr_sigaction(i, (struct sigaction*)0, &sig_tab[i]);
     if (i != SIGSTOP && i != SIGKILL 
         && sig_tab[i].sa_handler != SIG_DFL 
         && sig_tab[i].sa_handler != SIG_IGN)
       {
         t = sig_tab[i];
         t.sa_handler = chkr_sig_handler;
         chkr_sigaction(i, &t, (struct sigaction*)0);
       }
   }
}

/*
 * The new sigaction syscall.
 */
int
__sigaction(int sig, struct sigaction *act, struct sigaction *oldact)
{
  int ret;
  struct sigaction action;

  chkr_check_addr(&sig, sizeof(int), CHKR_RO);
  chkr_check_addr(&act, sizeof(struct sigaction*), CHKR_RO);
  chkr_check_addr(&oldact, sizeof(struct sigaction*), CHKR_RO);
    
  if (act)
#ifdef linux
    chkr_check_addr(act, sizeof(struct sigaction) - sizeof(int), CHKR_RO);
#else
    chkr_check_addr(act, sizeof(struct sigaction), CHKR_RO);
#endif
  if (oldact)
    chkr_check_addr(oldact, sizeof(struct sigaction), CHKR_WO);  
  if (sig == SIGSTOP || sig == SIGKILL || act == (struct sigaction*)0)
    return chkr_sigaction(sig, act, oldact);
  if (act->sa_handler == SIG_DFL || act->sa_handler == SIG_IGN)
    {
      ret = chkr_sigaction(sig, act, oldact);
      if (oldact)
        oldact->sa_handler = sig_tab[sig].sa_handler;
      return ret;
    }
   
  action = *act;
  action.sa_handler = chkr_sig_handler;		/* use the checker handler */
  ret = chkr_sigaction(sig, &action, oldact);
  if (oldact)
    oldact->sa_handler = sig_tab[sig].sa_handler;
  sig_tab[sig] = *act;
  return ret;
}

#endif /* CHKR_USE_BITMAP */