From 3d5b3b8016e1bc932c386c46a4949e178d5985b9 Mon Sep 17 00:00:00 2001 From: Wolfgang Draxinger Date: Thu, 20 Oct 2022 12:28:09 +0200 Subject: Initial commit --- Makefile | 10 ++++++++++ README | 18 ++++++++++++++++++ src/rsvr.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 88 insertions(+) create mode 100644 Makefile create mode 100644 README create mode 100644 src/rsvr.c 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 + +With the source data being read from `stdin`. + +# Example + + # download a PDF from the web and show it using MuPDF + curl | 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 +#include +#include +#include +#include +#include +#include + +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 \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; +} -- cgit v1.2.3