diff options
-rw-r--r-- | Makefile | 10 | ||||
-rw-r--r-- | README | 18 | ||||
-rw-r--r-- | src/rsvr.c | 60 |
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 $@ $< @@ -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; +} |