commit 07edc3434494e230cdad90e1910c8619551eddca
parent 9383bca29156ecbdb32e16e9d33e77e82693a8eb
Author: Santtu Lakkala <inz@inz.fi>
Date: Sat, 26 Feb 2022 11:51:57 +0200
Add pipe_command component
pipe_command runs a command and provides the latest line of output from
it.
Diffstat:
4 files changed, 131 insertions(+), 0 deletions(-)
diff --git a/Makefile b/Makefile
@@ -19,6 +19,7 @@ COM =\
components/load_avg\
components/netspeeds\
components/num_files\
+ components/pipe_command\
components/ram\
components/run_command\
components/separator\
diff --git a/components/pipe_command.c b/components/pipe_command.c
@@ -0,0 +1,126 @@
+/* See LICENSE file for copyright and license details. */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "../util.h"
+
+static struct {
+ int fd;
+ int len;
+ int bused;
+ int neednl;
+ char last[256];
+ char buffer[256];
+ const char *cmd;
+} *pipes = NULL;
+int npipes = 0;
+
+char *find_last_seg(char *buffer, size_t n, char sep, int *len)
+{
+ char *i;
+ char *pp = NULL;
+ char *p = buffer - 1;
+
+ for (i = buffer; n--; i++) {
+ if (*i == sep) {
+ pp = p;
+ p = i;
+ }
+ }
+
+ if (pp) {
+ *len = p - pp - 1;
+ return pp + 1;
+ }
+
+ *len = -1;
+ return NULL;
+}
+
+const char *
+pipe_command(const char *cmd)
+{
+ int i;
+
+ for (i = 0; i < npipes && pipes[i].cmd != cmd; i++);
+ if (i == npipes) {
+ int pfd[2];
+ pipes = realloc(pipes, sizeof(*pipes) * ++npipes);
+ if (pipe(pfd))
+ die("failed to open pipe");
+ watch(pfd[0]);
+
+ switch (fork()) {
+ case -1:
+ die("fork failed");
+ break;
+ case 0:
+ close(pfd[0]);
+ close(STDIN_FILENO);
+ close(STDOUT_FILENO);
+ dup2(pfd[1], STDOUT_FILENO);
+ close(pfd[1]);
+ open("/dev/null", O_WRONLY);
+ execlp("sh", "sh", "-c", cmd, NULL);
+ exit(1);
+ break;
+ default:
+ close(pfd[1]);
+ fcntl(pfd[0], F_SETFL, O_NONBLOCK);
+ pipes[i].fd = pfd[0];
+ pipes[i].bused = 0;
+ pipes[i].len = 0;
+ pipes[i].cmd = cmd;
+ pipes[i].neednl = 0;
+ break;
+ }
+ npipes++;
+ }
+
+ int fd = pipes[i].fd;
+ int r;
+ char *nnl;
+ int len;
+
+ r = read(fd, pipes[i].buffer + pipes[i].bused,
+ sizeof(pipes[i].buffer) - pipes[i].bused);
+
+ if (r == 0)
+ die("pipe source died");
+ if (r < 0) {
+ if (errno == EWOULDBLOCK || errno == EAGAIN)
+ r = 0;
+ else
+ die("pipe error:");
+ }
+
+ nnl = find_last_seg(pipes[i].buffer, r, '\n', &len);
+
+ if (nnl) {
+ if (!pipes[i].neednl || nnl != pipes[i].buffer) {
+ memcpy(pipes[i].last, nnl, len);
+ pipes[i].len = len;
+ }
+ pipes[i].neednl = 0;
+ pipes[i].bused = r - (nnl + len + 1 - pipes[i].buffer);
+ memmove(pipes[i].buffer, nnl + len + 1, pipes[i].bused);
+ } else if (!pipes[i].neednl) {
+ pipes[i].bused += r;
+
+ if (pipes[i].bused == sizeof(pipes[i].buffer)) {
+ pipes[i].len = pipes[i].bused;
+ memcpy(pipes[i].last, pipes[i].buffer,
+ pipes[i].bused);
+ pipes[i].bused = 0;
+ pipes[i].neednl = 1;
+ }
+ }
+
+ if (pipes[i].len == 0)
+ return NULL;
+ return bprintf("%.*s", pipes[i].len, pipes[i].last);
+}
diff --git a/slstatus.c b/slstatus.c
@@ -96,6 +96,7 @@ main(int argc, char *argv[])
die("XOpenDisplay: Failed to open display");
}
+
do {
if (clock_gettime(CLOCK_MONOTONIC, &start) < 0) {
die("clock_gettime:");
diff --git a/slstatus.h b/slstatus.h
@@ -57,6 +57,9 @@ const char *ram_used(void);
/* run_command */
const char *run_command(const char *cmd);
+/* pipe_command */
+const char *pipe_command(const char *cmd);
+
/* separator */
const char *separator(const char *separator);