pipeln

Pipeline creation tool
git clone https://git.sinitax.com/sinitax/pipeln
Log | Files | Refs | README | LICENSE | sfeed.txt

commit 425e76fccf29a9d0eee4f331ac987ca2316a5c46
Author: Louis Burda <quent.burda@gmail.com>
Date:   Wed,  7 Jun 2023 15:10:35 +0200

Add initial version

Diffstat:
A.gitignore | 3+++
AMakefile | 19+++++++++++++++++++
Abuild.jst.tmpl | 28++++++++++++++++++++++++++++
Aconfigure | 3+++
Amain.c | 137+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
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; + } + } +}