rspan

Executes a given command after a randomized time span.
git clone https://noxz.tech/git/rspan.git
Log | Files | LICENSE

commit: 10929d8c1438e91d3166aaccf5ae7153167cf7a6
parent: 
author: Chris Noxz <chris@noxz.tech>
date:   Thu, 3 Jan 2019 19:12:32 +0100
Initial commit
A.gitignore2+
AMakefile41++++++++
Aconfig.mk8++
Arspan.129++++++
Arspan.c103++++++++++++++++++++
5 files changed, 183 insertions(+)
diff --git a/.gitignore b/.gitignore
@@ -0,0 +1,2 @@
+rspan
+rspan.o
diff --git a/Makefile b/Makefile
@@ -0,0 +1,41 @@
+.POSIX:
+
+include config.mk
+
+SRC = rspan.c
+OBJ = $(SRC:.c=.o)
+
+all: options rspan
+
+options:
+	@echo rspan build options:
+	@echo "VERSION = $(VERSION)"
+	@echo "PREFIX  = $(PREFIX)"
+	@echo "CFLAGS  = $(STCFLAGS)"
+	@echo "CC      = $(CC)"
+
+.c.o:
+	$(CC) $(STCFLAGS) -c $<
+
+$(OBJ): config.mk
+
+rspan: $(OBJ)
+	$(CC) -o $@ $(OBJ) $(STCFLAGS)
+
+clean:
+	rm -f rspan $(OBJ)
+
+install: rspan
+	@echo installing executable to ${PREFIX}/bin
+	mkdir -p $(PREFIX)/bin
+	cp -f rspan $(PREFIX)/bin
+	chmod 755 $(PREFIX)/bin/rspan
+	@echo installing manual page to ${MANPREFIX}/man1
+	mkdir -p ${MANPREFIX}/man1
+	sed "s/VERSION/${VERSION}/g" < rspan.1 > ${MANPREFIX}/man1/rspan.1
+	chmod 644 ${MANPREFIX}/man1/rspan.1
+
+uninstall:
+	rm -f $(PREFIX)/bin/rspan
+
+.PHONY: all options clean install uninstall
diff --git a/config.mk b/config.mk
@@ -0,0 +1,8 @@
+VERSION = 0.0.1
+
+PREFIX = /usr/local
+MANPREFIX = $(PREFIX)/share/man
+
+CFLAGS = -Wall -pedantic -std=c99
+CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600
+STCFLAGS = $(CPPFLAGS) $(CFLAGS)
diff --git a/rspan.1 b/rspan.1
@@ -0,0 +1,29 @@
+.Dd $Mdocdate$
+.Dt RSPAN 1
+.Os
+.Sh NAME
+.Nm rspan
+.Nd a random time span creator
+.Sh SYNOPSIS
+.Nm
+.Ar interval
+.Ar file
+.Op Ar arguments ...
+.Sh DESCRIPTION
+.Nm
+is a random time span creator,
+a program that upon execution creates a random timeout based on given
+.Ar interval "."
+When the timeout ends the given
+.Ar file
+will get executed with potentially given
+.Ar arguments "."
+.Pp
+.Sh OPTIONS
+.Bl -tag -width Ds
+.It Ar interval
+Specifies the maximum timeout of the span. The interval must be a positive
+integer.
+.It Ar file
+Specifies what file to execute upon timeout.
+.El
diff --git a/rspan.c b/rspan.c
@@ -0,0 +1,103 @@
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <time.h>
+#include <unistd.h>
+
+static const char* usage = "usage: rspan INT FILE [ARG ...]\n"
+"\n"
+"  INT  : interval in seconds\n"
+"  FILE : file path to executable\n"
+"  ARG  : list of arguments for executable\n";
+
+static int command_argc;
+static char **command;
+
+static void die(int, const char*);
+static void handler(int);
+static void init_timer(int, void (*)(int));
+static unsigned long mix(unsigned long, unsigned long, unsigned long);
+
+unsigned long mix(unsigned long a, unsigned long b, unsigned long c)
+{
+    a=a-b; a=a-c; a=a^(c >> 13);
+    b=b-c; b=b-a; b=b^(a << 8);
+    a=a-b; a=a-c; a=a^(c >> 12);
+    b=b-c; b=b-a; b=b^(a << 16);
+    a=a-b; a=a-c; a=a^(c >> 3);
+    b=b-c; b=b-a; b=b^(a << 10);
+    c=c-a; c=c-b; c=c^(b >> 15);
+    return c;
+}
+
+void die(int code, const char *msg)
+{
+    int i;
+
+    if (msg != NULL)
+        fprintf(stderr, "%s\n", msg);
+
+    if (command != NULL) {
+        for (i = 0; i < command_argc; i++)
+            free(command[i]);
+        free(command);
+    }
+
+    exit(code);
+}
+
+void init_timer(int timeout, void (*func)(int))
+{
+    struct itimerval it_val;
+
+    it_val.it_value.tv_sec = timeout;
+    it_val.it_value.tv_usec = 0;
+    it_val.it_interval.tv_sec = 0;
+    it_val.it_interval.tv_usec = 0;
+
+    if (signal(SIGALRM, func) == SIG_ERR)
+        die(1, "signal handler couldn't be created");
+    if (setitimer(ITIMER_REAL, &it_val, NULL) == -1)
+        die(1, "timer couldn't initialize");
+}
+
+void handler(int signum)
+{
+    execvp(command[0], command);
+    die(0, NULL);
+}
+
+int main (int argc, char *argv[])
+{
+    unsigned long seed = mix(clock(), time(NULL), getpid());
+    int c, i, s;
+
+    if (argc == 1)
+        die(0, usage);
+
+    if (sscanf(argv[1], "%i", &s) != 1 || s <= 0)
+        die(1, "interval must be a positive integer");
+
+    if ((command_argc = argc - 1) < 2)
+        die(1, "please add something to execute");
+
+    command = (char **)malloc((command_argc) * sizeof(char *));
+    for (i = 2; i < argc; i++) {
+        *command = (char *)malloc(strlen(argv[i]) + 1);
+        strncpy(*command, argv[i], strlen(argv[i]) + 1);
+        command++;
+    }
+    *command = NULL;
+    command -= (command_argc - 1);
+
+    srand(seed);
+    s = rand() % s + 1;
+    init_timer(s, &handler);
+
+    while ((c = getchar()));
+
+    /* unreachable */
+    return 0;
+}