summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@sbcglobal.net>2015-09-05 00:54:42 -0600
committerLuke Shumaker <lukeshu@sbcglobal.net>2015-09-05 00:54:42 -0600
commitadc8af1a3a0d9077621d2b9b5e36b33452f31947 (patch)
tree3b9a16de006c2ab7077a3889fc038a9a18c6d103 /test
parentd9e982b0f922d79535ae210d5262dbb15fd332d9 (diff)
Add a minimal systemd-like runner for testing
Diffstat (limited to 'test')
-rw-r--r--test/.gitignore1
-rw-r--r--test/runner.c146
2 files changed, 147 insertions, 0 deletions
diff --git a/test/.gitignore b/test/.gitignore
new file mode 100644
index 0000000..09230a9
--- /dev/null
+++ b/test/.gitignore
@@ -0,0 +1 @@
+/runner
diff --git a/test/runner.c b/test/runner.c
new file mode 100644
index 0000000..82b8d6e
--- /dev/null
+++ b/test/runner.c
@@ -0,0 +1,146 @@
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <error.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#define _(s) s
+
+const char *xgetenv(const char *name, const char *unset) {
+ const char *val = getenv(name);
+ if (!val)
+ val = unset;
+ return val;
+}
+
+char *xasprintf(const char *format, ...) {
+ va_list arg;
+ int len;
+ char *str = NULL;
+
+ va_start(arg, format);
+ len = vasprintf(&str, format, arg);
+ va_end(arg);
+
+ if (len < 0)
+ error(EXIT_FAILURE, errno, _("Could not allocate memory in vasprintf"));
+
+ return str;
+}
+
+#define xasprintfa(...) (__extension__ ({ char *heap = xasprintf(__VA_ARGS__); char *stack = strdupa(heap); free(heap); stack; }))
+
+int pid = -1;
+void
+sigchld_handler(int sig __attribute__((__unused__))) {
+ int status;
+ pid = waitpid(pid, &status, WNOHANG);
+ int exited = WEXITSTATUS(status);
+ error(exited, 0, "%ld exited with status %d", (long)pid, exited);
+ exit(0);
+}
+
+union addr {
+ struct sockaddr gen;
+ struct sockaddr_un un;
+};
+
+int new_unix_sock(const char *filename, int type) {
+ union addr addr;
+ addr.un.sun_family = AF_UNIX;
+ strcpy(addr.un.sun_path, filename);
+
+ int sock = socket(AF_UNIX, type, 0);
+ if (sock < 0)
+ error(EXIT_FAILURE, errno, "socket(%d, %d)", AF_UNIX, type);
+ unlink(filename);
+ if (bind(sock, &addr.gen, sizeof(addr)))
+ error(EXIT_FAILURE, errno, "bind(%d, sockaddr(\"%s\"))", sock, filename);
+ switch (type) {
+ case SOCK_STREAM:
+ case SOCK_SEQPACKET:
+ if (listen(sock, 5))
+ error(EXIT_FAILURE, errno, "listen(%d /* \"%s\" */, %d)", sock, filename, 5);
+ break;
+ case SOCK_DGRAM:
+ break;
+ default:
+ error(EXIT_FAILURE, errno, "new_unix_sock: Unrecognized type: %d", type);
+ }
+ return sock;
+}
+
+char *cmdname = "nshd_runner";
+const char *notify_sockname = "notify.sock";
+const char *nslcd_sockname = "nslcd.sock";
+void cleanup(void) {
+ if (nslcd_sockname)
+ unlink(nslcd_sockname);
+ if (notify_sockname)
+ unlink(notify_sockname);
+ fprintf(stderr, "%s: Exiting\n", cmdname);
+}
+
+int main(int argc, char *argv[]) {
+ cmdname = argv[0];
+ if (argc != 2) {
+ error(2, 0, _("Usage: %s NSHD_PROGRAM"), argv[0]);
+ }
+
+ atexit(&cleanup);
+ int nslcd_sock = new_unix_sock(nslcd_sockname , SOCK_STREAM);
+ int notify_sock = new_unix_sock(notify_sockname, SOCK_DGRAM );
+
+ struct sigaction act;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = SA_RESTART;
+ act.sa_handler = sigchld_handler;
+ if (sigaction(SIGCHLD, &act, 0))
+ error(EXIT_FAILURE, errno, "sigaction");
+
+
+ pid = fork();
+ switch (pid) {
+ case -1:
+ error(EXIT_FAILURE, errno, "fork");
+ case 0:
+ close(notify_sock);
+ dup2(nslcd_sock, 3);
+ if (nslcd_sock != 3)
+ close(nslcd_sock);
+ pid = getpid();
+ setenv("LISTEN_PID", xasprintfa("%ld", (long)pid), 1);
+ setenv("LISTEN_FDS", "1", 1);
+ execl(argv[1], argv[1], NULL);
+ error(EXIT_FAILURE, errno, "execl");
+ }
+
+ while (1) {
+ union addr client_addr;
+ socklen_t client_size;
+ char buf[4096];
+ ssize_t bytes_read = recvfrom(notify_sock, buf, sizeof(buf), 0, &client_addr.gen, &client_size);
+ if (bytes_read < 1)
+ error(EXIT_FAILURE, errno, "recvfrom");
+ ssize_t bytes_written = 0;
+ while (bytes_written < bytes_read) {
+ ssize_t n = write(2, &(buf[bytes_written]), bytes_read-bytes_written);
+ if (n < 0) {
+ bytes_written = -1;
+ break;
+ }
+ bytes_written += n;
+ }
+ if (bytes_written < 0)
+ error(EXIT_FAILURE, errno, "write");
+ }
+
+ return 0;
+}