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:
M | Makefile | | | 6 | +++--- |
M | build.jst.tmpl | | | 3 | ++- |
D | main.c | | | 151 | ------------------------------------------------------------------------------ |
A | pipeln.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;
+ }
+ }
+}