diff options
author | Leah Neukirchen <leah@vuxu.org> | 2023-08-01 18:49:26 +0200 |
---|---|---|
committer | Leah Neukirchen <leah@vuxu.org> | 2023-08-02 13:50:38 +0200 |
commit | f350b6f16c668cd49dc24be3b6dd44c059fe2e0c (patch) | |
tree | beb62542f4a90d688cd77a1512e605da7925d7cb | |
parent | 8a2a4899769335bc14c62aef12cdf26f2f487f2a (diff) | |
download | xe-f350b6f16c668cd49dc24be3b6dd44c059fe2e0c.tar.gz xe-f350b6f16c668cd49dc24be3b6dd44c059fe2e0c.tar.xz xe-f350b6f16c668cd49dc24be3b6dd44c059fe2e0c.zip |
properly forward errors on exec, return 123 on any exit status 1-254
Use the CLOEXEC pipe trick to detect if exec happened; read the errno from the pipe if it wasn't closed due to exec.
-rwxr-xr-x | t/errors.t | 23 | ||||
-rw-r--r-- | xe.1 | 4 | ||||
-rw-r--r-- | xe.c | 35 |
3 files changed, 51 insertions, 11 deletions
diff --git a/t/errors.t b/t/errors.t index c2ecd5e..eb05dc0 100755 --- a/t/errors.t +++ b/t/errors.t @@ -1,7 +1,7 @@ #!/bin/sh export "PATH=.:$PATH" -printf '1..13\n' +printf '1..16\n' printf '# error handling\n' tap3 'exit code on success' <<'EOF' @@ -21,6 +21,27 @@ a >>>= 123 EOF +tap3 'exit code on when command fails with 126' <<'EOF' +xe -s 'exit 126' +<<< +a +>>>= 123 +EOF + +tap3 'exit code on when command fails with 127' <<'EOF' +xe -s 'exit 127' +<<< +a +>>>= 123 +EOF + +tap3 'exit code on when command fails with 250' <<'EOF' +xe -s 'exit 250' +<<< +a +>>>= 123 +EOF + tap3 'exit code on when command fails with 255' <<'EOF' xe -s 'exit 255' <<< diff --git a/xe.1 b/xe.1 index b0c1a78..e37db66 100644 --- a/xe.1 +++ b/xe.1 @@ -1,4 +1,4 @@ -.Dd November 3, 2017 +.Dd August 1, 2023 .Dt XE 1 .Os .Sh NAME @@ -247,7 +247,7 @@ follows the convention of GNU and OpenBSD xargs: .It 0 on success .It 123 -if any invocation of the command exited with status 1 to 125. +if any invocation of the command exited with status 1 to 254. .It 124 if the command exited with status 255 .It 125 diff --git a/xe.c b/xe.c index f220a82..804833c 100644 --- a/xe.c +++ b/xe.c @@ -99,17 +99,15 @@ mywait() my_child: if (WIFEXITED(status)) { - if (WEXITSTATUS(status) >= 1 && WEXITSTATUS(status) <= 125) { + if (WEXITSTATUS(status) == 255) { + fprintf(stderr, "xe: job %ld [pid %ld] exited with status 255\n", children[i].iter, (long)pid); + exit(124); + } else if (WEXITSTATUS(status) > 0) { if (Fflag) { fprintf(stderr, "xe: job %ld [pid %ld] exited with status %d\n", children[i].iter, (long)pid, WEXITSTATUS(status)); exit(123); } failed = 1; - } else if (WEXITSTATUS(status) == 255) { - fprintf(stderr, "xe: job %ld [pid %ld] exited with status 255\n", children[i].iter, (long)pid); - exit(124); - } else if (WEXITSTATUS(status) > 125) { - exit(WEXITSTATUS(status)); } } else if (WIFSIGNALED(status)) { fprintf(stderr, "xe: job %ld [pid %ld] terminated by signal %d\n", @@ -232,8 +230,17 @@ run() exit(126); } + unsigned char status; + int alivepipefd[2]; + if (pipe(alivepipefd) < 0) + exit(126); + fcntl(alivepipefd[0], F_SETFD, FD_CLOEXEC); + fcntl(alivepipefd[1], F_SETFD, FD_CLOEXEC); + pid = fork(); if (pid == 0) { // in child + close(alivepipefd[0]); + char iter[32]; snprintf(iter, sizeof iter, "%ld", iterations); setenv("ITER", iter, 1); @@ -268,14 +275,26 @@ run() execvp(args[0], args); - int status = (errno == ENOENT ? 127 : 126); + status = (errno == ENOENT ? 127 : 126); + if (write(alivepipefd[1], &status, 1) != 1) { + /* ignored */ + } fprintf(stderr, "xe: %s: %s\n", args[0], strerror(errno)); - exit(status); + _exit(status); } else if (pid < 0) { // fork failed fprintf(stderr, "xe: %s: %s\n", args[0], strerror(errno)); exit(126); } + close(alivepipefd[1]); + if (read(alivepipefd[0], &status, 1) == 1) { + if (status == 126) + exit(126); + if (status == 127) + exit(127); + } + close(alivepipefd[0]); + if (Lflag) { long iter = iterations; lpid = fork(); |