commit 425e76fccf29a9d0eee4f331ac987ca2316a5c46
Author: Louis Burda <quent.burda@gmail.com>
Date: Wed, 7 Jun 2023 15:10:35 +0200
Add initial version
Diffstat:
5 files changed, 190 insertions(+), 0 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -0,0 +1,3 @@
+.gdb_history
+build.jst
+pipeln
diff --git a/Makefile b/Makefile
@@ -0,0 +1,19 @@
+PREFIX ?= /usr/local
+BINDIR ?= /bin
+
+CFLAGS = -std=c99 -Wunused-variable -Wunused-function -Wconversion -O2
+
+
+all: pipeln
+
+pipeln: main.c
+ $(CC) -o $@ $^ $(CFLAGS)
+
+clean:
+ rm -f pipeln
+
+install:
+ install -m755 pipeln -t "$(DESTDIR)$(PREFIX)$(BINDIR)"
+
+uninstall:
+ rm -f "$(DESTDIR)$(PREFIX)$(BINDIR)/pipeln"
diff --git a/build.jst.tmpl b/build.jst.tmpl
@@ -0,0 +1,28 @@
+#default PREFIX /usr/local
+#default BINDIR /bin
+#default CC gcc
+
+#ifdef PIPELN_DEBUG
+#define DEBUG
+#endif
+
+#ifdef DEBUG
+#define OPT_CFLAGS -Og -g
+#else
+#define OPT_CFLAGS -O2
+#endif
+
+cflags = -std=c99 -Wunused-variable -Wunused-function -Wconversion
+ #{OPT_CFLAGS} #{EXTRA_CFLAGS} #{PIPELN_EXTRA_CFLAGS}
+
+rule cc
+ #{CC} -o $out $in $cflags
+
+target pipeln
+ cc main.c
+
+command clean
+ rm -f pipeln
+
+command all
+ just pipeln
diff --git a/configure b/configure
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+tmpl "$@" build.jst.tmpl > build.jst
diff --git a/main.c b/main.c
@@ -0,0 +1,137 @@
+#include <sys/wait.h>
+#include <linux/limits.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <wait.h>
+#include <stdio.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+
+void __attribute__((noreturn))
+die(const char *fmt, ...)
+{
+ va_list ap;
+
+ fputs("pipeln: ", stderr);
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ if (*fmt && fmt[strlen(fmt)-1] == ':') {
+ fputc(' ', stderr);
+ perror(NULL);
+ } else {
+ fputc('\n', stderr);
+ }
+
+ exit(1);
+}
+
+char *
+findbin(const char *name)
+{
+ static char pathbuf[PATH_MAX];
+ const char *tok, *sep, *end;
+ struct dirent *ent;
+ size_t entlen;
+ DIR *dir;
+
+ tok = getenv("PATH");
+ while (tok) {
+ sep = strchr(tok, ':');
+ end = sep ? sep : tok + strlen(tok);
+ entlen = (size_t) (end - tok);
+ if (entlen > 0 && entlen < PATH_MAX) {
+ strncpy(pathbuf, tok, entlen);
+ pathbuf[entlen] = '\0';
+ dir = opendir(pathbuf);
+ if (dir) {
+ while ((ent = readdir(dir))) {
+ if (entlen + 1 + strlen(name) >= PATH_MAX)
+ continue;
+ if (!strcmp(ent->d_name, name)) {
+ strcat(pathbuf, "/");
+ strcat(pathbuf, name);
+ closedir(dir);
+ return pathbuf;
+ }
+ }
+ closedir(dir);
+ }
+ }
+ tok = sep ? sep + 1 : NULL;
+ }
+
+ die("findbin %s", name);
+}
+
+int
+run(int *in, int *out, const char **argv)
+{
+ int status;
+ pid_t child;
+
+ if (!argv[0]) die("run: empty command");
+
+ if (strncmp(argv[0], "/", 1) && strncmp(argv[0], "./", 2))
+ argv[0] = findbin(argv[0]);
+
+ child = fork();
+ if (child < 0) die("fork:");
+
+ if (!child) {
+ if (in) {
+ close(0);
+ dup2(in[0], 0);
+ }
+ if (out) {
+ close(1);
+ dup2(out[1], 1);
+ }
+ execv(argv[0], (char *const *) argv);
+ die("execv %s:", argv[0]);
+ }
+ if (in) close(in[0]);
+ if (out) close(out[1]);
+
+ do {
+ waitpid(child, &status, 0);
+ } while (!WIFEXITED(status) && !WIFSIGNALED(status));
+
+ if (WIFEXITED(status))
+ return WEXITSTATUS(status);
+ else
+ return 128 + WTERMSIG(status);
+}
+
+int
+main(int argc, const char **argv)
+{
+ const char **arg, **cmdargs;
+ int pipe1[2], pipe2[2];
+ int *in, *out;
+
+ /* first cmd from stdin */
+ in = NULL;
+ out = pipe2;
+
+ cmdargs = argv + 1;
+ for (arg = argv + 1; ; arg++) {
+ if (!*arg || !strcmp(*arg, "|")) {
+ /* last cmd goes to stdout */
+ if (!*arg) out = NULL;
+ else if (pipe(out)) die("pipe:");
+
+ /* run piped cmd */
+ *arg = NULL;
+ run(in, out, cmdargs);
+ cmdargs = arg + 1;
+ if (!out) break;
+
+ /* out => in */
+ in = out;
+ out = out == pipe1 ? pipe2 : pipe1;
+ }
+ }
+}