pipeln

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

commit 8afeed1a607f70606a81ab39cac8d684964fdab1
parent 29f6aee4d9c8df7375b369ddba9121f1cb4498bf
Author: Louis Burda <quent.burda@gmail.com>
Date:   Sat, 29 Jul 2023 00:35:43 +0200

Rename main.c to pipeln.c and properly close fds

Diffstat:
MMakefile | 6+++---
Mbuild.jst.tmpl | 3++-
Dmain.c | 151------------------------------------------------------------------------------
Apipeln.c | 154+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 159 insertions(+), 155 deletions(-)

diff --git a/Makefile b/Makefile @@ -3,11 +3,9 @@ BINDIR ?= /bin CFLAGS = -std=c99 -Wunused-variable -Wunused-function -Wconversion -O2 - all: pipeln -pipeln: main.c - $(CC) -o $@ $^ $(CFLAGS) +pipeln: pipeln.c clean: rm -f pipeln @@ -17,3 +15,5 @@ install: uninstall: rm -f "$(DESTDIR)$(PREFIX)$(BINDIR)/pipeln" + +.PHONY: all clean install uninstall diff --git a/build.jst.tmpl b/build.jst.tmpl @@ -19,7 +19,7 @@ rule cc #{CC} -o $out $in $cflags target pipeln - cc main.c + cc pipeln.c command install install -m755 pipeln -t "#{DESTDIR}#{PREFIX}#{BINDIR}" @@ -32,3 +32,4 @@ command clean command all just pipeln + diff --git a/main.c b/main.c @@ -1,151 +0,0 @@ -#include <asm-generic/errno-base.h> -#include <linux/limits.h> -#include <sys/wait.h> -#include <errno.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); -} - -void -run(int *in, int *out, const char **argv) -{ - 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); - if (dup2(in[0], 0) < 0) - die("dup2:"); - } - if (out) { - close(1); - if (dup2(out[1], 1) < 0) - die("dup2:"); - } - execv(argv[0], (char *const *) argv); - die("execv %s:", argv[0]); - } - if (in) close(in[0]); - if (out) close(out[1]); -} - -void -waitall(void) -{ - int rc, status, exitcode; - - errno = 0; - exitcode = 0; - do { - rc = waitpid(-1, &status, 0); - if (rc < 0 && errno != EINTR && errno != ECHILD) - die("waitpid:"); - if (!exitcode && WIFEXITED(status)) - exitcode = WEXITSTATUS(status); - else if (!exitcode && WIFSIGNALED(status)) - exitcode = 128 + WTERMSIG(status); - } while (rc >= 0 && errno != ECHILD); - - exit(exitcode); -} - -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); - if (!out) waitall(); - cmdargs = arg + 1; - - /* out => in */ - in = out; - out = out == pipe1 ? pipe2 : pipe1; - } - } -} diff --git a/pipeln.c b/pipeln.c @@ -0,0 +1,154 @@ +#include <asm-generic/errno-base.h> +#include <linux/limits.h> +#include <sys/wait.h> +#include <errno.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); +} + +void +run(int *in, int *out, const char **argv) +{ + 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) { + if (dup2(in[0], 0) < 0) + die("dup2:"); + close(in[0]); + close(in[1]); + } + if (out) { + if (dup2(out[1], 1) < 0) + die("dup2:"); + close(out[0]); + close(out[1]); + } + execv(argv[0], (char *const *) argv); + die("execv %s:", argv[0]); + } + + if (in) close(in[0]); + if (out) close(out[1]); +} + +void +waitall(void) +{ + int rc, status, exitcode; + + errno = 0; + exitcode = 0; + do { + rc = waitpid(-1, &status, 0); + if (rc < 0 && errno != EINTR && errno != ECHILD) + die("waitpid:"); + if (!exitcode && WIFEXITED(status)) + exitcode = WEXITSTATUS(status); + else if (!exitcode && WIFSIGNALED(status)) + exitcode = 128 + WTERMSIG(status); + } while (rc >= 0 && errno != ECHILD); + + exit(exitcode); +} + +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); + if (!out) waitall(); + cmdargs = arg + 1; + + /* out => in */ + in = out; + out = out == pipe1 ? pipe2 : pipe1; + } + } +}