diff --git a/client.c b/client.c index 83aa05ca..db29fdec 100644 --- a/client.c +++ b/client.c @@ -272,8 +272,10 @@ client_main(struct event_base *base, int argc, char **argv, int flags) client_peer = proc_add_peer(client_proc, fd, client_dispatch, NULL); /* Save these before pledge(). */ - if ((cwd = getcwd(path, sizeof path)) == NULL) - cwd = "/"; + if ((cwd = getcwd(path, sizeof path)) == NULL) { + if ((cwd = find_home()) == NULL) + cwd = "/"; + } if ((ttynam = ttyname(STDIN_FILENO)) == NULL) ttynam = ""; diff --git a/cmd-attach-session.c b/cmd-attach-session.c index c570358c..b339b890 100644 --- a/cmd-attach-session.c +++ b/cmd-attach-session.c @@ -51,9 +51,8 @@ cmd_attach_session(struct cmd_q *cmdq, const char *tflag, int dflag, int rflag, struct window_pane *wp = NULL; const char *update; char *cause; - int fd; struct format_tree *ft; - char *cp; + char *cwd; if (RB_EMPTY(&sessions)) { cmdq_error(cmdq, "no sessions"); @@ -97,18 +96,17 @@ cmd_attach_session(struct cmd_q *cmdq, const char *tflag, int dflag, int rflag, ft = format_create(); format_defaults(ft, cmd_find_client(cmdq, NULL, 1), s, NULL, NULL); - cp = format_expand(ft, cflag); + cwd = format_expand(ft, cflag); format_free(ft); - fd = open(cp, O_RDONLY|O_DIRECTORY); - free(cp); - if (fd == -1) { + if (access(cwd, X_OK) != 0) { + free((void *)cwd); cmdq_error(cmdq, "bad working directory: %s", strerror(errno)); return (CMD_RETURN_ERROR); } - close(s->cwd); - s->cwd = fd; + free((void *)s->cwd); + s->cwd = cwd; } if (c->session != NULL) { diff --git a/cmd-if-shell.c b/cmd-if-shell.c index 0271fdea..a9c84261 100644 --- a/cmd-if-shell.c +++ b/cmd-if-shell.c @@ -66,7 +66,7 @@ cmd_if_shell_exec(struct cmd *self, struct cmd_q *cmdq) struct winlink *wl = NULL; struct window_pane *wp = NULL; struct format_tree *ft; - int cwd; + const char *cwd; if (args_has(args, 't')) { wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp); @@ -83,7 +83,7 @@ cmd_if_shell_exec(struct cmd *self, struct cmd_q *cmdq) else if (s != NULL) cwd = s->cwd; else - cwd = -1; + cwd = NULL; } ft = format_create(); diff --git a/cmd-load-buffer.c b/cmd-load-buffer.c index 897807d0..c55e6c11 100644 --- a/cmd-load-buffer.c +++ b/cmd-load-buffer.c @@ -49,10 +49,10 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_q *cmdq) struct client *c = cmdq->client; struct session *s; FILE *f; - const char *path, *bufname; - char *pdata, *new_pdata, *cause; + const char *path, *bufname, *cwd; + char *pdata, *new_pdata, *cause, *file, resolved[PATH_MAX]; size_t psize; - int ch, error, cwd, fd; + int ch, error; bufname = NULL; if (args_has(args, 'b')) @@ -75,13 +75,16 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_q *cmdq) else if ((s = cmd_find_current(cmdq)) != NULL) cwd = s->cwd; else - cwd = AT_FDCWD; + cwd = "."; - if ((fd = openat(cwd, path, O_RDONLY)) == -1 || - (f = fdopen(fd, "rb")) == NULL) { - if (fd != -1) - close(fd); - cmdq_error(cmdq, "%s: %s", path, strerror(errno)); + xasprintf(&file, "%s/%s", cwd, path); + if (realpath(file, resolved) == NULL) + f = NULL; + else + f = fopen(resolved, "rb"); + free(file); + if (f == NULL) { + cmdq_error(cmdq, "%s: %s", resolved, strerror(errno)); return (CMD_RETURN_ERROR); } @@ -97,7 +100,7 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_q *cmdq) pdata[psize++] = ch; } if (ferror(f)) { - cmdq_error(cmdq, "%s: read error", path); + cmdq_error(cmdq, "%s: read error", resolved); goto error; } if (pdata != NULL) diff --git a/cmd-new-session.c b/cmd-new-session.c index 7b637bc6..90bb2e0e 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -63,10 +63,9 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) struct environ *env; struct termios tio, *tiop; const char *newname, *target, *update, *errstr, *template; - const char *path; + const char *path, *cwd, *to_free; char **argv, *cmd, *cause, *cp; - int detached, already_attached, idx, cwd, fd = -1; - int argc; + int detached, already_attached, idx, argc; u_int sx, sy; struct format_tree *ft; struct environ_entry *envent; @@ -118,32 +117,26 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) already_attached = 1; /* Get the new session working directory. */ + to_free = NULL; if (args_has(args, 'c')) { ft = format_create(); format_defaults(ft, cmd_find_client(cmdq, NULL, 1), NULL, NULL, NULL); - cp = format_expand(ft, args_get(args, 'c')); + to_free = cwd = format_expand(ft, args_get(args, 'c')); format_free(ft); - if (cp != NULL && *cp != '\0') { - fd = open(cp, O_RDONLY|O_DIRECTORY); - free(cp); - if (fd == -1) { - cmdq_error(cmdq, "bad working directory: %s", - strerror(errno)); - return (CMD_RETURN_ERROR); - } - } else - free(cp); - cwd = fd; + if (access(cwd, X_OK) != 0) { + free((void *)cwd); + cmdq_error(cmdq, "bad working directory: %s", + strerror(errno)); + return (CMD_RETURN_ERROR); + } } else if (c != NULL && c->session == NULL) cwd = c->cwd; else if ((c0 = cmd_find_client(cmdq, NULL, 1)) != NULL) cwd = c0->session->cwd; - else { - fd = open(".", O_RDONLY); - cwd = fd; - } + else + cwd = "."; /* * If this is a new client, check for nesting and save the termios @@ -311,12 +304,12 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) if (!detached) cmdq->client_exit = 0; - if (fd != -1) - close(fd); + if (to_free != NULL) + free((void *)to_free); return (CMD_RETURN_NORMAL); error: - if (fd != -1) - close(fd); + if (to_free != NULL) + free((void *)to_free); return (CMD_RETURN_ERROR); } diff --git a/cmd-new-window.c b/cmd-new-window.c index 70e70c68..a5085fff 100644 --- a/cmd-new-window.c +++ b/cmd-new-window.c @@ -49,9 +49,9 @@ cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq) struct args *args = self->args; struct session *s; struct winlink *wl; - const char *cmd, *path, *template; + const char *cmd, *path, *template, *cwd, *to_free; char **argv, *cause, *cp; - int argc, idx, detached, cwd, fd = -1; + int argc, idx, detached; struct format_tree *ft; struct environ_entry *envent; @@ -92,24 +92,20 @@ cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq) if (envent != NULL) path = envent->value; + to_free = NULL; if (args_has(args, 'c')) { ft = format_create(); format_defaults(ft, cmd_find_client(cmdq, NULL, 1), s, NULL, NULL); - cp = format_expand(ft, args_get(args, 'c')); + cwd = format_expand(ft, args_get(args, 'c')); format_free(ft); - if (cp != NULL && *cp != '\0') { - fd = open(cp, O_RDONLY|O_DIRECTORY); - free(cp); - if (fd == -1) { - cmdq_error(cmdq, "bad working directory: %s", - strerror(errno)); - return (CMD_RETURN_ERROR); - } - } else - free(cp); - cwd = fd; + if (access(cwd, X_OK) != 0) { + free((void *)cwd); + cmdq_error(cmdq, "bad working directory: %s", + strerror(errno)); + return (CMD_RETURN_ERROR); + } } else if (cmdq->client != NULL && cmdq->client->session == NULL) cwd = cmdq->client->cwd; else @@ -165,12 +161,12 @@ cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq) format_free(ft); } - if (fd != -1) - close(fd); + if (to_free != NULL) + free((void *)to_free); return (CMD_RETURN_NORMAL); error: - if (fd != -1) - close(fd); + if (to_free != NULL) + free((void *)to_free); return (CMD_RETURN_ERROR); } diff --git a/cmd-respawn-pane.c b/cmd-respawn-pane.c index 864b45b8..a50b9d06 100644 --- a/cmd-respawn-pane.c +++ b/cmd-respawn-pane.c @@ -81,7 +81,7 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmd_q *cmdq) if (envent != NULL) path = envent->value; - if (window_pane_spawn(wp, args->argc, args->argv, path, NULL, -1, env, + if (window_pane_spawn(wp, args->argc, args->argv, path, NULL, NULL, env, s->tio, &cause) != 0) { cmdq_error(cmdq, "respawn pane failed: %s", cause); free(cause); diff --git a/cmd-respawn-window.c b/cmd-respawn-window.c index 8d8332b1..93af1b68 100644 --- a/cmd-respawn-window.c +++ b/cmd-respawn-window.c @@ -84,7 +84,7 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_q *cmdq) if (envent != NULL) path = envent->value; - if (window_pane_spawn(wp, args->argc, args->argv, path, NULL, -1, env, + if (window_pane_spawn(wp, args->argc, args->argv, path, NULL, NULL, env, s->tio, &cause) != 0) { cmdq_error(cmdq, "respawn window failed: %s", cause); free(cause); diff --git a/cmd-run-shell.c b/cmd-run-shell.c index 17ac0f76..def3ef01 100644 --- a/cmd-run-shell.c +++ b/cmd-run-shell.c @@ -80,7 +80,7 @@ cmd_run_shell_exec(struct cmd *self, struct cmd_q *cmdq) struct winlink *wl = NULL; struct window_pane *wp = NULL; struct format_tree *ft; - int cwd; + const char *cwd; if (args_has(args, 't')) { wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp); @@ -97,7 +97,7 @@ cmd_run_shell_exec(struct cmd *self, struct cmd_q *cmdq) else if (s != NULL) cwd = s->cwd; else - cwd = -1; + cwd = NULL; } ft = format_create(); diff --git a/cmd-save-buffer.c b/cmd-save-buffer.c index 1e020934..6c55fabb 100644 --- a/cmd-save-buffer.c +++ b/cmd-save-buffer.c @@ -56,10 +56,10 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_q *cmdq) struct client *c = cmdq->client; struct session *s; struct paste_buffer *pb; - const char *path, *bufname, *bufdata, *start, *end; - char *msg; + const char *path, *bufname, *bufdata, *start, *end, *cwd; + const char *flags; + char *msg, *file, resolved[PATH_MAX]; size_t size, used, msglen, bufsize; - int cwd, fd; FILE *f; if (!args_has(args, 'b')) { @@ -96,26 +96,25 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_q *cmdq) else if ((s = cmd_find_current(cmdq)) != NULL) cwd = s->cwd; else - cwd = AT_FDCWD; + cwd = "."; - f = NULL; - if (args_has(self->args, 'a')) { - fd = openat(cwd, path, O_CREAT|O_RDWR|O_APPEND, 0600); - if (fd != -1) - f = fdopen(fd, "ab"); - } else { - fd = openat(cwd, path, O_CREAT|O_RDWR|O_TRUNC, 0600); - if (fd != -1) - f = fdopen(fd, "wb"); - } + flags = "wb"; + if (args_has(self->args, 'a')) + flags = "ab"; + + xasprintf(&file, "%s/%s", cwd, path); + if (realpath(file, resolved) == NULL) + f = NULL; + else + f = fopen(resolved, flags); + free(file); if (f == NULL) { - if (fd != -1) - close(fd); - cmdq_error(cmdq, "%s: %s", path, strerror(errno)); + cmdq_error(cmdq, "%s: %s", resolved, strerror(errno)); return (CMD_RETURN_ERROR); } + if (fwrite(bufdata, 1, bufsize, f) != bufsize) { - cmdq_error(cmdq, "%s: fwrite error", path); + cmdq_error(cmdq, "%s: write error", resolved); fclose(f); return (CMD_RETURN_ERROR); } diff --git a/cmd-split-window.c b/cmd-split-window.c index ec37e0d7..b8a03953 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -52,10 +52,10 @@ cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq) struct window *w; struct window_pane *wp, *new_wp = NULL; struct environ *env; - const char *cmd, *path, *shell, *template; + const char *cmd, *path, *shell, *template, *cwd, *to_free; char **argv, *cause, *new_cause, *cp; u_int hlimit; - int argc, size, percentage, cwd, fd = -1; + int argc, size, percentage; enum layout_type type; struct layout_cell *lc; struct format_tree *ft; @@ -85,24 +85,20 @@ cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq) argv = args->argv; } + to_free = NULL; if (args_has(args, 'c')) { ft = format_create(); format_defaults(ft, cmd_find_client(cmdq, NULL, 1), s, NULL, NULL); - cp = format_expand(ft, args_get(args, 'c')); + to_free = cwd = format_expand(ft, args_get(args, 'c')); format_free(ft); - if (cp != NULL && *cp != '\0') { - fd = open(cp, O_RDONLY|O_DIRECTORY); - free(cp); - if (fd == -1) { - cmdq_error(cmdq, "bad working directory: %s", - strerror(errno)); - return (CMD_RETURN_ERROR); - } - } else - free(cp); - cwd = fd; + if (access(cwd, X_OK) != 0) { + free((void *)cwd); + cmdq_error(cmdq, "bad working directory: %s", + strerror(errno)); + return (CMD_RETURN_ERROR); + } } else if (cmdq->client != NULL && cmdq->client->session == NULL) cwd = cmdq->client->cwd; else @@ -187,8 +183,8 @@ cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq) } notify_window_layout_changed(w); - if (fd != -1) - close(fd); + if (to_free != NULL) + free((void *)to_free); return (CMD_RETURN_NORMAL); error: @@ -199,7 +195,8 @@ error: } cmdq_error(cmdq, "create pane failed: %s", cause); free(cause); - if (fd != -1) - close(fd); + + if (to_free != NULL) + free((void *)to_free); return (CMD_RETURN_ERROR); } diff --git a/format.c b/format.c index 3c0f4a39..21b341bf 100644 --- a/format.c +++ b/format.c @@ -241,7 +241,7 @@ format_job_get(struct format_tree *ft, const char *cmd) t = time(NULL); if (fj->job == NULL && ((ft->flags & FORMAT_FORCE) || fj->last != t)) { - fj->job = job_run(fj->cmd, NULL, -1, format_job_callback, + fj->job = job_run(fj->cmd, NULL, NULL, format_job_callback, NULL, fj); if (fj->job == NULL) { free(fj->out); diff --git a/job.c b/job.c index 47274db1..191d0a0f 100644 --- a/job.c +++ b/job.c @@ -40,13 +40,14 @@ struct joblist all_jobs = LIST_HEAD_INITIALIZER(all_jobs); /* Start a job running, if it isn't already. */ struct job * -job_run(const char *cmd, struct session *s, int cwd, +job_run(const char *cmd, struct session *s, const char *cwd, void (*callbackfn)(struct job *), void (*freefn)(void *), void *data) { struct job *job; struct environ *env; pid_t pid; int nullfd, out[2]; + const char *home; if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, out) != 0) return (NULL); @@ -66,8 +67,10 @@ job_run(const char *cmd, struct session *s, int cwd, case 0: /* child */ clear_signals(1); - if (cwd != -1 && fchdir(cwd) != 0) - chdir("/"); + if (cwd == NULL || chdir(cwd) != 0) { + if ((home = find_home()) == NULL || chdir(home) != 0) + chdir("/"); + } environ_push(env); environ_free(env); diff --git a/server-client.c b/server-client.c index bf18cae7..a800a1aa 100644 --- a/server-client.c +++ b/server-client.c @@ -96,7 +96,7 @@ server_client_create(int fd) c->environ = environ_create(); c->fd = -1; - c->cwd = -1; + c->cwd = NULL; c->cmdq = cmdq_new(c); c->cmdq->client_exit = 1; @@ -192,7 +192,7 @@ server_client_lost(struct client *c) screen_free(&c->status); free(c->title); - close(c->cwd); + free((void *)c->cwd); evtimer_del(&c->repeat_timer); @@ -1107,7 +1107,7 @@ error: void server_client_dispatch_identify(struct client *c, struct imsg *imsg) { - const char *data; + const char *data, *home; size_t datalen; int flags; @@ -1140,8 +1140,12 @@ server_client_dispatch_identify(struct client *c, struct imsg *imsg) case MSG_IDENTIFY_CWD: if (datalen == 0 || data[datalen - 1] != '\0') fatalx("bad MSG_IDENTIFY_CWD string"); - if ((c->cwd = open(data, O_RDONLY)) == -1) - c->cwd = open("/", O_RDONLY); + if (access(data, X_OK) == 0) + c->cwd = xstrdup(data); + else if ((home = find_home()) != NULL) + c->cwd = xstrdup(home); + else + c->cwd = xstrdup("/"); log_debug("client %p IDENTIFY_CWD %s", c, data); break; case MSG_IDENTIFY_STDIN: diff --git a/session.c b/session.c index 9f086bbd..e4dadc97 100644 --- a/session.c +++ b/session.c @@ -103,8 +103,8 @@ session_find_by_id(u_int id) /* Create a new session. */ struct session * session_create(const char *name, int argc, char **argv, const char *path, - int cwd, struct environ *env, struct termios *tio, int idx, u_int sx, - u_int sy, char **cause) + const char *cwd, struct environ *env, struct termios *tio, int idx, + u_int sx, u_int sy, char **cause) { struct session *s; struct winlink *wl; @@ -113,7 +113,7 @@ session_create(const char *name, int argc, char **argv, const char *path, s->references = 1; s->flags = 0; - s->cwd = dup(cwd); + s->cwd = xstrdup(cwd); s->curw = NULL; TAILQ_INIT(&s->lastw); @@ -223,7 +223,7 @@ session_destroy(struct session *s) winlink_remove(&s->windows, wl); } - close(s->cwd); + free((void *)s->cwd); session_unref(s); } @@ -314,7 +314,7 @@ session_previous_session(struct session *s) /* Create a new window on a session. */ struct winlink * session_new(struct session *s, const char *name, int argc, char **argv, - const char *path, int cwd, int idx, char **cause) + const char *path, const char *cwd, int idx, char **cause) { struct window *w; struct winlink *wl; diff --git a/tmux.h b/tmux.h index 0fd8062e..6f54b1da 100644 --- a/tmux.h +++ b/tmux.h @@ -832,7 +832,7 @@ struct window_pane { int argc; char **argv; char *shell; - int cwd; + const char *cwd; pid_t pid; char tty[TTY_NAME_MAX]; @@ -979,7 +979,7 @@ struct session { u_int id; char *name; - int cwd; + const char *cwd; struct timeval creation_time; struct timeval last_attached_time; @@ -1184,7 +1184,7 @@ struct client { struct environ *environ; char *title; - int cwd; + const char *cwd; char *term; char *ttyname; @@ -1539,7 +1539,7 @@ int options_table_find(const char *, const struct options_table_entry **, /* job.c */ extern struct joblist all_jobs; -struct job *job_run(const char *, struct session *, int, +struct job *job_run(const char *, struct session *, const char *, void (*)(struct job *), void (*)(void *), void *); void job_free(struct job *); void job_died(struct job *, int); @@ -1985,8 +1985,8 @@ struct window *window_find_by_id(u_int); void window_update_activity(struct window *); struct window *window_create1(u_int, u_int); struct window *window_create(const char *, int, char **, const char *, - const char *, int, struct environ *, struct termios *, - u_int, u_int, u_int, char **); + const char *, const char *, struct environ *, + struct termios *, u_int, u_int, u_int, char **); void window_destroy(struct window *); struct window_pane *window_get_active_at(struct window *, u_int, u_int); struct window_pane *window_find_string(struct window *, const char *); @@ -2013,7 +2013,7 @@ struct window_pane *window_pane_find_by_id(u_int); struct window_pane *window_pane_create(struct window *, u_int, u_int, u_int); void window_pane_destroy(struct window_pane *); int window_pane_spawn(struct window_pane *, int, char **, - const char *, const char *, int, struct environ *, + const char *, const char *, const char *, struct environ *, struct termios *, char **); void window_pane_resize(struct window_pane *, u_int, u_int); void window_pane_alternate_on(struct window_pane *, @@ -2147,8 +2147,8 @@ struct session *session_find(const char *); struct session *session_find_by_id_str(const char *); struct session *session_find_by_id(u_int); struct session *session_create(const char *, int, char **, const char *, - int, struct environ *, struct termios *, int, u_int, - u_int, char **); + const char *, struct environ *, struct termios *, int, + u_int, u_int, char **); void session_destroy(struct session *); void session_unref(struct session *); int session_check_name(const char *); @@ -2156,7 +2156,7 @@ void session_update_activity(struct session *, struct timeval *); struct session *session_next_session(struct session *); struct session *session_previous_session(struct session *); struct winlink *session_new(struct session *, const char *, int, char **, - const char *, int, int, char **); + const char *, const char *, int, char **); struct winlink *session_attach(struct session *, struct window *, int, char **); int session_detach(struct session *, struct winlink *); diff --git a/window-copy.c b/window-copy.c index 3ba27c80..c5c053bf 100644 --- a/window-copy.c +++ b/window-copy.c @@ -1488,7 +1488,7 @@ window_copy_copy_pipe(struct window_pane *wp, struct session *sess, format_defaults(ft, NULL, sess, NULL, wp); expanded = format_expand(ft, arg); - job = job_run(expanded, sess, -1, NULL, NULL, NULL); + job = job_run(expanded, sess, NULL, NULL, NULL, NULL); bufferevent_write(job->event, buf, len); free(expanded); diff --git a/window.c b/window.c index eb0f8ac3..3b9958b1 100644 --- a/window.c +++ b/window.c @@ -315,8 +315,8 @@ window_create1(u_int sx, u_int sy) struct window * window_create(const char *name, int argc, char **argv, const char *path, - const char *shell, int cwd, struct environ *env, struct termios *tio, - u_int sx, u_int sy, u_int hlimit, char **cause) + const char *shell, const char *cwd, struct environ *env, + struct termios *tio, u_int sx, u_int sy, u_int hlimit, char **cause) { struct window *w; struct window_pane *wp; @@ -735,7 +735,7 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit) wp->argc = 0; wp->argv = NULL; wp->shell = NULL; - wp->cwd = -1; + wp->cwd = NULL; wp->fd = -1; wp->event = NULL; @@ -798,7 +798,7 @@ window_pane_destroy(struct window_pane *wp) RB_REMOVE(window_pane_tree, &all_window_panes, wp); - close(wp->cwd); + free((void *)wp->cwd); free(wp->shell); cmd_free_argv(wp->argc, wp->argv); free(wp); @@ -806,12 +806,12 @@ window_pane_destroy(struct window_pane *wp) int window_pane_spawn(struct window_pane *wp, int argc, char **argv, - const char *path, const char *shell, int cwd, struct environ *env, + const char *path, const char *shell, const char *cwd, struct environ *env, struct termios *tio, char **cause) { struct winsize ws; char *argv0, *cmd, **argvp, paneid[16]; - const char *ptr, *first; + const char *ptr, *first, *home; struct termios tio2; #ifdef HAVE_UTEMPTER char s[32]; @@ -831,9 +831,9 @@ window_pane_spawn(struct window_pane *wp, int argc, char **argv, free(wp->shell); wp->shell = xstrdup(shell); } - if (cwd != -1) { - close(wp->cwd); - wp->cwd = dup(cwd); + if (cwd != NULL) { + free((void *)wp->cwd); + wp->cwd = xstrdup(cwd); } cmd = cmd_stringify_argv(wp->argc, wp->argv); @@ -852,8 +852,10 @@ window_pane_spawn(struct window_pane *wp, int argc, char **argv, free(cmd); return (-1); case 0: - if (fchdir(wp->cwd) != 0) - chdir("/"); + if (chdir(wp->cwd) != 0) { + if ((home = find_home()) == NULL || chdir(home) != 0) + chdir("/"); + } if (tcgetattr(STDIN_FILENO, &tio2) != 0) fatal("tcgetattr failed");