#!/usr/bin/env python # Run a program for a period of time, sending it SIGTERM once done. # Usage: timer 08:00 10:00 arecord prog.wav import sys, os, time, signal import mx.DateTime as mxtime def warn(*s): print >>sys.stderr, " ".join(map(str, s)) def die(*s): warn(*s) sys.exit(1) def parse_date(s): if s is None or s == "unknown": return -1 return int(mxtime.DateTimeFrom(s).ticks()) def make_date(t): if t == -1: return "unknown" return mxtime.ISO.str(mxtime.localtime(t)) def main(args): if len(args) < 3: die("Usage: timer START END COMMAND ...") start = parse_date(args[0]) end = parse_date(args[1]) cmd = args[2:] now = time.time() if end < start: die("End before start") if start < now or end < now: die("Times must be in the future") warn("Time now is", make_date(now), "- sleeping until", make_date(start)) while time.time() < start: time.sleep(1) warn("Starting", *cmd) pid = os.fork() if pid == 0: os.execvp(cmd[0], cmd) os._exit(20) warn("Started as", pid, " - running until", make_date(end)) while time.time() < end: time.sleep(1) warn("Stopping", pid) os.kill(pid, signal.SIGTERM) (dpid, dstat) = os.waitpid(pid, 0) if os.WIFSIGNALED(dstat): sig = os.WTERMSIG(dstat) if sig == signal.SIGTERM: warn("Process signalled as expected") return 0 else: warn("Process killed with signal", sig) return 1 elif os.WIFEXITED(dstat): status = os.WEXITSTATUS(dstat) warn("Process exited with status", status) return status else: warn("Process died mysteriously with dstat", dstat) return 1 if __name__ == "__main__": sys.exit(main(sys.argv[1:]))