pipeln

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

pipeln.c (2618B)


      1#include <sys/wait.h>
      2#include <unistd.h>
      3#include <dirent.h>
      4#include <wait.h>
      5#include <errno.h>
      6#include <stdio.h>
      7#include <stdarg.h>
      8#include <string.h>
      9#include <stdlib.h>
     10#include <stdbool.h>
     11
     12static bool resolve_bin = true;
     13
     14static void
     15__attribute__((noreturn))
     16die(const char *fmt, ...)
     17{
     18	va_list ap;
     19
     20	setvbuf(stderr, NULL, _IOLBF, 0);
     21	fputs("pipeln: ", stderr);
     22	va_start(ap, fmt);
     23	vfprintf(stderr, fmt, ap);
     24	va_end(ap);
     25	if (*fmt && fmt[strlen(fmt)-1] == ':') {
     26		fputc(' ', stderr);
     27		perror(NULL);
     28	} else {
     29		fputc('\n', stderr);
     30	}
     31
     32	exit(1);
     33}
     34
     35static void
     36usage(int rc, FILE *file)
     37{
     38	fprintf(file, "Usage: pipeln [-h] [-R] [--] [CMD |].. CMD\n");
     39	exit(rc);
     40}
     41
     42static pid_t
     43run(int *in, int *out, const char **argv)
     44{
     45	pid_t child;
     46
     47	if (!argv[0]) die("run: empty command");
     48
     49	child = fork();
     50	if (child < 0) die("fork:");
     51
     52	if (!child) {
     53		if (in) {
     54			if (dup2(in[0], 0) < 0)
     55				die("dup2 %i:", errno);
     56			if (close(in[0]) < 0)
     57				die("close:"); 
     58		}
     59		if (out) {
     60			if (dup2(out[1], 1) < 0)
     61				die("dup2:");
     62			if (close(out[0]) < 0 || close(out[1]) < 0)
     63				die("close:"); 
     64		}
     65		if (resolve_bin) {
     66			execvp(argv[0], (char *const *) argv);
     67		} else {
     68			execv(argv[0], (char *const *) argv);
     69		}
     70		die("execv %s:", argv[0]);
     71	}
     72
     73	if (in) close(in[0]);
     74	if (out) close(out[1]);
     75
     76	return child;
     77}
     78
     79static void
     80__attribute__((noreturn))
     81waitall(pid_t tpid)
     82{
     83	int status, exitcode;
     84	pid_t pid;
     85
     86	exitcode = 0;
     87	do {
     88		pid = waitpid(-1, &status, 0);
     89		if (pid < 0 && errno != EINTR && errno != ECHILD)
     90			die("waitpid:");
     91		if (pid == tpid) {
     92			if (!exitcode && WIFEXITED(status))
     93				exitcode = WEXITSTATUS(status);
     94			else if (!exitcode && WIFSIGNALED(status))
     95				exitcode = 128 + WTERMSIG(status);
     96		}
     97	} while (pid >= 0 || errno != ECHILD);
     98
     99	exit(exitcode);
    100}
    101
    102int
    103main(int argc, const char **argv)
    104{
    105	const char **arg, **cmdargs;
    106	int pipe1[2], pipe2[2];
    107	int *in, *out;
    108	pid_t pid;
    109
    110	if (argc < 1) return 1;
    111
    112	for (arg = argv + 1; *arg; arg++) {
    113		if (!strcmp(*arg, "--")) {
    114			arg++;
    115			break;
    116		} else if (!strcmp(*arg, "-h")) {
    117			usage(1, stderr);
    118		} else if (!strcmp(*arg, "-R")) {
    119			resolve_bin = false;
    120		} else {
    121			break;
    122		}
    123	}
    124
    125	// First command from stdin.
    126	in = NULL;
    127	out = pipe1;
    128
    129	cmdargs = arg;
    130	for (; ; arg++) {
    131		if (!*arg || !strcmp(*arg, "|")) {
    132			// Last command to stdout.
    133			if (!*arg) out = NULL;
    134			else if (pipe(out) < 0) die("pipe:");
    135
    136			*arg = NULL;
    137			pid = run(in, out, cmdargs);
    138			if (!out) waitall(pid);
    139			cmdargs = arg + 1;
    140
    141			in = out;
    142			out = (out == pipe1) ? pipe2 : pipe1;
    143		} else if (!strcmp(*arg, "\\|")) {
    144			*arg = "|";
    145		}
    146	}
    147}