#include "prjlibs-include/standards.h"
#include <sys/time.h>
#include <unistd.h>
#include <errno.h>
#include <limits.h>
#include <signal.h>

#include "skalibs/include/stddjb.h"
#include "prjlibs-include/constants.h"
#include "runwhen.h"

char const* PROG="delayrun";

static void alarm_handler(int sig) {
  (void)sig;
}

static struct sigaction action;

static char const var_delay[]="$DELAY";

int main(int argc, char** argv) {
  sigset_t alarmset;
  sigset_t blockset;
  unsigned long delay=0;
  char const* x;

  /* set up sigset containing SIGALRM */
  if (sigemptyset(&alarmset)!=0)
    strerr_die5sys(100, PROG, err_unable, err_empty, err_sigset, ": ");
  if (sigaddset(&alarmset, SIGALRM)!=0)
    strerr_die5sys(100, PROG, err_unable, err_addto, err_sigset, ": ");

  /* block SIGALRM ASAP */
  if (sigprocmask(SIG_BLOCK, &alarmset, &blockset)!=0)
    strerr_die4sys(100, PROG, err_unable, err_sigmask, ": ");

  /* initialize SIGALRM action, for catching or ignoring later */
  if (sigemptyset(&action.sa_mask)!=0)
    strerr_die5sys(100, PROG, err_unable, err_empty, err_sigset, ": ");
  action.sa_flags=0;

  /* scan delay time */
  x=env_get(var_delay+1);
  if (x!=null) {
    unsigned int const len=scan_ulong(x, &delay);
    if (len==0 || x[len]!='\0')
      strerr_die4x(111, PROG, ": ", var_delay, err_malformed);
    if (delay>LONG_MAX)
      strerr_die5x(100, PROG, ": ", var_delay, err_oflow, "long");
  }

  if (x==null || delay!=0) { /* do we need to sleep? */
    { /* schedule SIGALRM */
      struct itimerval timer;
      timer.it_interval.tv_sec=0;
      timer.it_interval.tv_usec=0;
      timer.it_value.tv_sec=delay;
      timer.it_value.tv_usec=0;
      if (setitimer(ITIMER_REAL, &timer, null)!=0)
        strerr_die4sys(100, PROG, err_unable, err_timer, ": ");
    }

    /* catch SIGALRM */
    action.sa_handler=alarm_handler;
    if (sigaction(SIGALRM, &action, null)!=0)
      strerr_die4sys(100, PROG, err_unable, err_sigact, ": ");

    /* sleep */
    if (sigdelset(&blockset, SIGALRM)!=0)
      strerr_die5sys(100, PROG, err_unable, err_delfrom, err_sigset, ": ");
    if (sigsuspend(&blockset)!=0 && errno!=EINTR)
      strerr_die4sys(100, PROG, err_unable, err_suspend, ": ");
  }

  /* ignore and unblock SIGALRM */
  action.sa_handler=SIG_IGN;
  if (sigaction(SIGALRM, &action, null)!=0)
    strerr_die4sys(100, PROG, err_unable, err_sigact, ": ");
  if (sigprocmask(SIG_UNBLOCK, &alarmset, null)!=0)
    strerr_die4sys(100, PROG, err_unable, err_sigmask, ": ");

  if (argc<2) _exit(0);
  ++argv;
  pathexec_run(argv[0], (char const**)argv, (char const**)environ);
  strerr_die5sys(errstat, PROG, err_unable, err_exec, argv[0], ": ");
}


syntax highlighted by Code2HTML, v. 0.9.1