From f58b8d0d6abb2477b584547a4e72cc362ecbbcdb Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 8 Dec 2025 08:04:35 +0000 Subject: [PATCH] Setting working directory after fork means there is a race with pane_current_path (especially on platforms with systemd which have to take time to do some additional faffing around). To avoid this, change it before fork and back in the parent afterwards. GitHub issue 4719. --- spawn.c | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/spawn.c b/spawn.c index d06d3969..3b5fae26 100644 --- a/spawn.c +++ b/spawn.c @@ -213,7 +213,9 @@ spawn_pane(struct spawn_context *sc, char **cause) struct environ *child; struct environ_entry *ee; char **argv, *cp, **argvp, *argv0, *cwd, *new_cwd; - const char *cmd, *tmp; + char path[PATH_MAX]; + const char *cmd, *tmp, *home = find_home(); + const char *actual_cwd = NULL; int argc; u_int idx; struct termios now; @@ -368,6 +370,16 @@ spawn_pane(struct spawn_context *sc, char **cause) goto complete; } + /* Store current working directory and change to new one. */ + if (getcwd(path, sizeof path) != NULL) { + if (chdir(new_wp->cwd) == 0) + actual_cwd = new_wp->cwd; + else if (home != NULL && chdir(home) == 0) + actual_cwd = home; + else if (chdir("/") == 0) + actual_cwd = "/"; + } + /* Fork the new process. */ new_wp->pid = fdforkpty(ptm_fd, &new_wp->fd, new_wp->tty, NULL, &ws); if (new_wp->pid == -1) { @@ -383,22 +395,23 @@ spawn_pane(struct spawn_context *sc, char **cause) return (NULL); } - /* In the parent process, everything is done now. */ - if (new_wp->pid != 0) + /* + * In the parent process, everything is done now. Change the working + * directory back. + */ + if (new_wp->pid != 0) { + if (actual_cwd != NULL && + chdir(path) != 0 && + (home == NULL || chdir(home) != 0)) + chdir("/"); goto complete; + } /* - * Child process. Change to the working directory or home if that - * fails. + * Child process. Set PWD to the working directory. */ - if (chdir(new_wp->cwd) == 0) - environ_set(child, "PWD", 0, "%s", new_wp->cwd); - else if ((tmp = find_home()) != NULL && chdir(tmp) == 0) - environ_set(child, "PWD", 0, "%s", tmp); - else if (chdir("/") == 0) - environ_set(child, "PWD", 0, "/"); - else - fatal("chdir failed"); + if (actual_cwd != NULL) + environ_set(child, "PWD", 0, "%s", actual_cwd); /* * Update terminal escape characters from the session if available and