about summary refs log tree commit diff
path: root/xe.c
diff options
context:
space:
mode:
authorLeah Neukirchen <leah@vuxu.org>2023-08-01 18:49:26 +0200
committerLeah Neukirchen <leah@vuxu.org>2023-08-02 13:50:38 +0200
commitf350b6f16c668cd49dc24be3b6dd44c059fe2e0c (patch)
treebeb62542f4a90d688cd77a1512e605da7925d7cb /xe.c
parent8a2a4899769335bc14c62aef12cdf26f2f487f2a (diff)
downloadxe-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.
Diffstat (limited to 'xe.c')
-rw-r--r--xe.c35
1 files changed, 27 insertions, 8 deletions
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();