From 9cb8f6e3b7549b1f279f6de34a97c0e568f4d148 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 24 Feb 2021 21:29:34 +0100 Subject: [PATCH 1/3] spawn: handle custom stdin/stdout/stderr fds being the same MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow the caller to pass the same FD (for example, a single /dev/null FD) to spawn(). All we need to do to handle this correctly is ensure we don’t try to close the same FD multiple times. --- spawn.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/spawn.c b/spawn.c index 3f8a8fd3..d200ed12 100644 --- a/spawn.c +++ b/spawn.c @@ -45,9 +45,16 @@ spawn(struct reaper *reaper, const char *cwd, char *const argv[], _exit(errno_copy); } - if ((stdin_fd >= 0 && (dup2(stdin_fd, STDIN_FILENO) < 0 || close(stdin_fd) < 0)) || - (stdout_fd >= 0 && (dup2(stdout_fd, STDOUT_FILENO) < 0 || close(stdout_fd) < 0)) || - (stderr_fd >= 0 && (dup2(stderr_fd, STDERR_FILENO) < 0 || close(stderr_fd) < 0)) || + bool close_stderr = stderr_fd >= 0; + bool close_stdout = stdout_fd >= 0 && stdout_fd != stderr_fd; + bool close_stdin = stdin_fd >= 0 && stdin_fd != stdout_fd && stdin_fd != stderr_fd; + + if ((stdin_fd >= 0 && (dup2(stdin_fd, STDIN_FILENO) < 0 + || (close_stdin && close(stdin_fd) < 0))) || + (stdout_fd >= 0 && (dup2(stdout_fd, STDOUT_FILENO) < 0 + || (close_stdout && close(stdout_fd) < 0))) || + (stderr_fd >= 0 && (dup2(stderr_fd, STDERR_FILENO) < 0 + || (close_stderr && close(stderr_fd) < 0))) || (cwd != NULL && chdir(cwd) < 0) || execvp(argv[0], argv) < 0) { From 8365fde980ccb7f28627805a75f4884df14d7004 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 24 Feb 2021 21:30:58 +0100 Subject: [PATCH 2/3] url-mode: redirect stdin/stdout/stderr to /dev/null when opening an URL This fixex an issue where TUI programs started in the parent terminal (when running nested terminals). --- url-mode.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/url-mode.c b/url-mode.c index bc6e7722..cea099e9 100644 --- a/url-mode.c +++ b/url-mode.c @@ -3,6 +3,10 @@ #include #include #include +#include + +#include +#include #define LOG_MODULE "url-mode" #define LOG_ENABLE_DBG 0 @@ -81,18 +85,27 @@ activate_url(struct seat *seat, struct terminal *term, const struct url *url) size_t argc; char **argv; + int dev_null = open("/dev/null", O_RDWR); + + if (dev_null < 0) { + LOG_ERRNO("failed to open /dev/null"); + break; + } + if (spawn_expand_template( &term->conf->url_launch, 1, (const char *[]){"url"}, (const char *[]){url_string}, &argc, &argv)) { - spawn(term->reaper, term->cwd, argv, -1, -1, -1); + spawn(term->reaper, term->cwd, argv, dev_null, dev_null, dev_null); for (size_t i = 0; i < argc; i++) free(argv[i]); free(argv); } + + close(dev_null); break; } } From 4e577110127702c450a2ae3eddab3e97e55127cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 25 Feb 2021 21:09:59 +0100 Subject: [PATCH 3/3] spawn: call setsid() in child process --- spawn.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/spawn.c b/spawn.c index d200ed12..99f1dc7e 100644 --- a/spawn.c +++ b/spawn.c @@ -35,15 +35,14 @@ spawn(struct reaper *reaper, const char *cwd, char *const argv[], /* Child */ close(pipe_fds[0]); + if (setsid() < 0) + goto child_err; + /* Clear signal mask */ sigset_t mask; sigemptyset(&mask); - if (sigprocmask(SIG_SETMASK, &mask, NULL) < 0) { - const int errno_copy = errno; - LOG_ERRNO("failed to restore signals"); - (void)!write(pipe_fds[1], &errno_copy, sizeof(errno_copy)); - _exit(errno_copy); - } + if (sigprocmask(SIG_SETMASK, &mask, NULL) < 0) + goto child_err; bool close_stderr = stderr_fd >= 0; bool close_stdout = stdout_fd >= 0 && stdout_fd != stderr_fd; @@ -58,12 +57,17 @@ spawn(struct reaper *reaper, const char *cwd, char *const argv[], (cwd != NULL && chdir(cwd) < 0) || execvp(argv[0], argv) < 0) { - const int errno_copy = errno; - (void)!write(pipe_fds[1], &errno_copy, sizeof(errno_copy)); - _exit(errno_copy); + goto child_err; } + xassert(false); _exit(errno); + + child_err: + ; + const int errno_copy = errno; + (void)!write(pipe_fds[1], &errno_copy, sizeof(errno_copy)); + _exit(errno_copy); } /* Parent */