From 9b1fc11a597c4f05dae0e225f292a0c31f17718b Mon Sep 17 00:00:00 2001 From: Daniel Barlow Date: Sun, 15 Sep 2024 19:33:21 +0100 Subject: [PATCH] logshipper/logtee :copy stdin to stdout & to a unix socket if present first draft --- pkgs/default.nix | 1 + pkgs/logshipper/Makefile | 5 ++ pkgs/logshipper/default.nix | 8 ++++ pkgs/logshipper/logtee.c | 93 +++++++++++++++++++++++++++++++++++++ 4 files changed, 107 insertions(+) create mode 100644 pkgs/logshipper/Makefile create mode 100644 pkgs/logshipper/default.nix create mode 100644 pkgs/logshipper/logtee.c diff --git a/pkgs/default.nix b/pkgs/default.nix index 8e72b59..81e17d0 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -78,6 +78,7 @@ in { levitate = callPackage ./levitate { }; libubootenv = callPackage ./libubootenv { }; linotify = callPackage ./linotify { }; + logshipper = callPackage ./logshipper { }; lualinux = callPackage ./lualinux { }; # we need to build real lzma instead of using xz, because the lzma diff --git a/pkgs/logshipper/Makefile b/pkgs/logshipper/Makefile new file mode 100644 index 0000000..07b26df --- /dev/null +++ b/pkgs/logshipper/Makefile @@ -0,0 +1,5 @@ +TARGETS=logtee # ship-zinc backfill +default: $(TARGETS) + +install: $(TARGETS) + install -Dt $(PREFIX)/bin/ logtee diff --git a/pkgs/logshipper/default.nix b/pkgs/logshipper/default.nix new file mode 100644 index 0000000..3177693 --- /dev/null +++ b/pkgs/logshipper/default.nix @@ -0,0 +1,8 @@ +{ + stdenv +}: +stdenv.mkDerivation { + name = "logshipper"; + makeFlags = [ "PREFIX=${placeholder "out"}" ]; + src = ./.; +} diff --git a/pkgs/logshipper/logtee.c b/pkgs/logshipper/logtee.c new file mode 100644 index 0000000..ba7cfee --- /dev/null +++ b/pkgs/logshipper/logtee.c @@ -0,0 +1,93 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int open_shipper_socket(char *pathname) { + int fd; + + struct sockaddr_un sa = { + .sun_family = AF_LOCAL + }; + strncpy(sa.sun_path, pathname, sizeof(sa.sun_path) - 1); + + fd = socket(AF_LOCAL, SOCK_STREAM, 0); + if(fd >= 0) { + if(connect(fd, (struct sockaddr *) &sa, sizeof sa)) { + perror("connect socket"); + return -1; + } + int flags = fcntl(fd, F_GETFL); + fcntl(fd, F_SETFL, flags | O_NONBLOCK); + } + return fd; +} + + +int main(int argc, char * argv[]) { + struct pollfd fds[] = { + { .fd = 0, .events = POLLIN }, + { .fd = 1, .events = POLLERR }, + { .fd = -1, .events = POLLERR }, + }; + + char * buf = malloc(8192); + int out_bytes = 0; + int tee_bytes = 0; + + if(argc > 1 && (strlen(argv[1]) > 108)) { + error(1, 0, "socket pathname \"%s\" is too long, max 108 bytes", + argv[1]); + }; + signal(SIGPIPE, SIG_IGN); + + char * start_cookie = "COOKIE-START\n"; + char * stop_cookie = "COOKIE-STOP\n"; + + int flags = fcntl(STDOUT_FILENO, F_GETFL); + fcntl(STDOUT_FILENO, F_SETFL, flags | O_NONBLOCK); + + while(1) { + int nfds = poll(fds, 3, 2000); + if(nfds > 0) { + if((fds[0].revents & (POLLIN|POLLHUP)) && + (out_bytes == 0) && + (tee_bytes == 0)) { + out_bytes = read(fds[0].fd, buf, 8192); + if(out_bytes == 0) { + exit(0); + }; + if(fds[2].fd >= 0) tee_bytes = out_bytes; + }; + + if(out_bytes) { + out_bytes -= write(fds[1].fd, buf, out_bytes); + }; + if(fds[1].revents & (POLLERR|POLLHUP)) { + exit(1); // can't even log an error if the logging stream fails + }; + if(fds[2].fd >= 0) { + if(tee_bytes) { + tee_bytes -= write(fds[2].fd, buf, tee_bytes); + }; + if(fds[2].revents & (POLLERR|POLLHUP)) { + close(fds[2].fd); + fds[2].fd = -1; + (void) write(1, stop_cookie , strlen(stop_cookie)); + }; + }; + } else { + if(fds[2].fd < 0) { + if(argc>1) fds[2].fd = open_shipper_socket(argv[1]); + } + }; + }; +}