summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Makefile10
-rw-r--r--test/.gitignore1
-rw-r--r--test/runner.c146
4 files changed, 156 insertions, 2 deletions
diff --git a/.gitignore b/.gitignore
index b4d898a..061fe12 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,3 +5,4 @@
/nshd.socket
/.Makefile.var.*
/.tmp.Makefile.var.*
+*.o
diff --git a/Makefile b/Makefile
index 1af0fcb..f1e8783 100644
--- a/Makefile
+++ b/Makefile
@@ -1,3 +1,4 @@
+MAKEFLAGS += --no-builtin-rules
prefix = /usr/local
bindir = $(prefix)/bin
libdir = $(prefix)/lib
@@ -26,10 +27,10 @@ all: build
include $(addsuffix /Makefile,$(subdirs))
-secondary +=
+secondary += test/*.o
download += $(addprefix src/,$(deps))
generate +=
-build += bin/nshd nshd.service nshd.socket
+build += bin/nshd nshd.service nshd.socket test/runner
install += $(addprefix $(DESTDIR),$(bindir)/nshd $(systemddir)/system/nshd.socket $(systemddir)/system/nshd.service)
download: $(download)
@@ -67,6 +68,11 @@ $(DESTDIR)$(systemddir)/system/%.socket: %.socket
$(DESTDIR)$(systemddir)/system/%.service: %.service
install -TDm644 $< $@
+%.o: %.c .Makefile.var.CC .Makefile.var.CPPFLAGS .Makefile.var.CFLAGS
+ $(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(filter-out $(vp),$^)
+%: %.o .Makefile.var.CC .Makefile.var.LDFLAGS .Makefile.var.LOADLIBES .Makefile.var.LDLIBS
+ $(CC) $(LDFLAGS) -o $@ $(filter-out $(vp),$^) $(LOADLIBES) $(LDLIBS)
+
.Makefile.var.%: FORCE
@printf '%s' '$($*)' > .tmp$@ && { cmp -s .tmp$@ $@ && rm -f -- .tmp$@ || mv -Tf .tmp$@ $@; } || { rm -f -- .tmp$@; false; }
.PHONY: FORCE
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;
+}