jcs's openbsd hax
openbsd

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.

nicm ea4a7080 904a900a

+27 -14
+27 -14
usr.bin/tmux/spawn.c
··· 1 - /* $OpenBSD: spawn.c,v 1.34 2025/04/24 08:55:40 nicm Exp $ */ 1 + /* $OpenBSD: spawn.c,v 1.35 2025/12/08 08:04:35 nicm Exp $ */ 2 2 3 3 /* 4 4 * Copyright (c) 2019 Nicholas Marriott <nicholas.marriott@gmail.com> ··· 213 213 struct environ *child; 214 214 struct environ_entry *ee; 215 215 char **argv, *cp, **argvp, *argv0, *cwd, *new_cwd; 216 - const char *cmd, *tmp; 216 + char path[PATH_MAX]; 217 + const char *cmd, *tmp, *home = find_home(); 218 + const char *actual_cwd = NULL; 217 219 int argc; 218 220 u_int idx; 219 221 struct termios now; ··· 368 370 goto complete; 369 371 } 370 372 373 + /* Store current working directory and change to new one. */ 374 + if (getcwd(path, sizeof path) != NULL) { 375 + if (chdir(new_wp->cwd) == 0) 376 + actual_cwd = new_wp->cwd; 377 + else if (home != NULL && chdir(home) == 0) 378 + actual_cwd = home; 379 + else if (chdir("/") == 0) 380 + actual_cwd = "/"; 381 + } 382 + 371 383 /* Fork the new process. */ 372 384 new_wp->pid = fdforkpty(ptm_fd, &new_wp->fd, new_wp->tty, NULL, &ws); 373 385 if (new_wp->pid == -1) { ··· 383 395 return (NULL); 384 396 } 385 397 386 - /* In the parent process, everything is done now. */ 387 - if (new_wp->pid != 0) 398 + /* 399 + * In the parent process, everything is done now. Change the working 400 + * directory back. 401 + */ 402 + if (new_wp->pid != 0) { 403 + if (actual_cwd != NULL && 404 + chdir(path) != 0 && 405 + (home == NULL || chdir(home) != 0)) 406 + chdir("/"); 388 407 goto complete; 408 + } 389 409 390 410 /* 391 - * Child process. Change to the working directory or home if that 392 - * fails. 411 + * Child process. Set PWD to the working directory. 393 412 */ 394 - if (chdir(new_wp->cwd) == 0) 395 - environ_set(child, "PWD", 0, "%s", new_wp->cwd); 396 - else if ((tmp = find_home()) != NULL && chdir(tmp) == 0) 397 - environ_set(child, "PWD", 0, "%s", tmp); 398 - else if (chdir("/") == 0) 399 - environ_set(child, "PWD", 0, "/"); 400 - else 401 - fatal("chdir failed"); 413 + if (actual_cwd != NULL) 414 + environ_set(child, "PWD", 0, "%s", actual_cwd); 402 415 403 416 /* 404 417 * Update terminal escape characters from the session if available and