aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile10
-rw-r--r--README18
-rw-r--r--src/rsvr.c60
3 files changed, 88 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..52b516d
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,10 @@
+.PHONY: all clean
+
+all: install/bin/rsvr
+
+clean:
+ -rm -r install
+
+install/bin/rsvr: src/rsvr.c
+ mkdir -p install/bin
+ $(CC) -Os -Wl,-s -o $@ $<
diff --git a/README b/README
new file mode 100644
index 0000000..356ab49
--- /dev/null
+++ b/README
@@ -0,0 +1,18 @@
+# rsvr -- a in-memory file reservoir
+
+rsvr is a small helper utility that receives data from non-seekable
+sources on `stdin` such as a pipe or a socket, placing it into a in-memory
+file resorvoir (it also can read from regular, seekable files). When the
+source is closed (or end-of-file is reached) the subsequent command is
+executed.
+
+There are no options to set. Usage is as simple as
+
+ rsvr <subsequent command with argument>
+
+With the source data being read from `stdin`.
+
+# Example
+
+ # download a PDF from the web and show it using MuPDF
+ curl <some URL> | rsvr mupdf /dev/stdin
diff --git a/src/rsvr.c b/src/rsvr.c
new file mode 100644
index 0000000..01fa845
--- /dev/null
+++ b/src/rsvr.c
@@ -0,0 +1,60 @@
+#define _GNU_SOURCE
+#include <sys/mman.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+char buf[128*1024];
+
+int main(int argc, char *argv[])
+{
+ if( 2 > argc ){
+ fprintf(stderr,
+ "Read stdin into a memfd reservoir file and use this as stdin for a subsequently executed command.\n"
+ "usage: %s <command and argument>\n",
+ (argc ? argv[0] : "rsvr") );
+ return EXIT_FAILURE;
+ }
+
+ int rsvr_fd = memfd_create("reservoiur", MFD_CLOEXEC);
+ if( 0 > rsvr_fd ){
+ perror("memfd_create('reservoiur', MFD_CLOEXEC)");
+ return EXIT_FAILURE;
+ }
+
+ ssize_t rb = 0, wb = 0;
+ do {
+ rb = read(0, buf, sizeof(buf));
+ if( 0 >= rb ){ continue; }
+
+ for( ssize_t cb = 0
+ ; 0 <= wb && (cb < rb)
+ ; cb += ((0 < wb) ? wb : 0)
+ ){
+ wb = write(rsvr_fd, (buf+cb), (rb-cb));
+ if( (0 > wb) && (EINTR == errno) ){ wb = 0; }
+ }
+ } while( (0 < rb)
+ || (0 > rb) && EINTR == errno );
+
+ if( 0 > rb ){ perror("read(stdin)"); }
+ if( 0 > wb ){ perror("write(reservoir)"); }
+ if( 0 > rb || 0 > wb ){ return EXIT_FAILURE; }
+
+ if( 0 > dup2(rsvr_fd, 0) ){
+ perror("dup2(reservoir, stdin)");
+ return EXIT_FAILURE;
+ }
+ close(rsvr_fd);
+
+ memmove(argv, argv+1, sizeof(*argv)*(argc-1));
+ argv[argc-1] = NULL;
+ if( 0 > execvp(argv[0], argv) ){
+ perror("exec(...)");
+ }
+
+ return EXIT_FAILURE;
+}