From 282c5f9644ed262ee15efbd3d072f7acc577da15 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Oct 2013 12:26:34 +0000 Subject: [PATCH] Alter how tmux handles the working directory to internally use file descriptors rather than strings. - Each session still has a current working directory. - New sessions still get their working directory from the client that created them or its attached session if any. - New windows are created by default in the session working directory. - The -c flag to new, neww, splitw allows the working directory to be overridden. - The -c flag to attach let's the session working directory be changed. - The default-path option has been removed. To get the equivalent to default-path '.', do: bind c neww -c $PWD To get the equivalent of default-path '~', do: bind c neww -c ~ This also changes the client identify protocol to be a set of messages rather than one as well as some other changes that should make it easier to make backwards-compatible protocol changes in future. --- client.c | 56 ++++++++------------ cmd-attach-session.c | 68 ++++++++++++++++++++---- cmd-load-buffer.c | 30 +++++------ cmd-new-session.c | 74 ++++++++++++++++---------- cmd-new-window.c | 41 +++++++++++++-- cmd-queue.c | 24 --------- cmd-save-buffer.c | 54 +++++++++---------- cmd-split-window.c | 40 +++++++++++--- format.c | 3 -- options-table.c | 5 -- server-client.c | 123 +++++++++++++++++++++++++++++-------------- server-fn.c | 8 +-- session.c | 17 +++--- tmux.1 | 24 ++------- tmux.c | 28 ++-------- tmux.h | 52 ++++++------------ window.c | 16 +++--- 17 files changed, 363 insertions(+), 300 deletions(-) diff --git a/client.c b/client.c index 5be747dd..82e43992 100644 --- a/client.c +++ b/client.c @@ -53,7 +53,6 @@ int client_attached; int client_get_lock(char *); int client_connect(char *, int); void client_send_identify(int); -void client_send_environ(void); int client_write_one(enum msgtype, int, const void *, size_t); int client_write_server(enum msgtype, const void *, size_t); void client_update_event(void); @@ -257,8 +256,7 @@ client_main(int argc, char **argv, int flags) /* Establish signal handlers. */ set_signals(client_signal); - /* Send initial environment. */ - client_send_environ(); + /* Send identify messages. */ client_send_identify(flags); /* Send first command. */ @@ -316,45 +314,39 @@ client_main(int argc, char **argv, int flags) return (client_exitval); } -/* Send identify message to server with the file descriptors. */ +/* Send identify messages to server. */ void client_send_identify(int flags) { - struct msg_identify_data data; - char *term; - int fd; + const char *s; + char **ss; + int fd; - data.flags = flags; + client_write_one(MSG_IDENTIFY_FLAGS, -1, &flags, sizeof flags); - if (getcwd(data.cwd, sizeof data.cwd) == NULL) - *data.cwd = '\0'; + if ((s = getenv("TERM")) == NULL) + s = ""; + client_write_one(MSG_IDENTIFY_TERM, -1, s, strlen(s) + 1); - term = getenv("TERM"); - if (term == NULL || - strlcpy(data.term, term, sizeof data.term) >= sizeof data.term) - *data.term = '\0'; + if ((s = ttyname(STDIN_FILENO)) == NULL) + s = ""; + client_write_one(MSG_IDENTIFY_TTYNAME, -1, s, strlen(s) + 1); + + if ((fd = open(".", O_RDONLY)) == -1) + fd = open("/", O_RDONLY); + client_write_one(MSG_IDENTIFY_CWD, fd, NULL, 0); if ((fd = dup(STDIN_FILENO)) == -1) fatal("dup failed"); - imsg_compose(&client_ibuf, - MSG_IDENTIFY, PROTOCOL_VERSION, -1, fd, &data, sizeof data); + client_write_one(MSG_IDENTIFY_STDIN, fd, NULL, 0); + + for (ss = environ; *ss != NULL; ss++) + client_write_one(MSG_IDENTIFY_ENVIRON, -1, *ss, strlen(*ss) + 1); + client_write_one(MSG_IDENTIFY_DONE, -1, NULL, 0); + client_update_event(); } -/* Forward entire environment to server. */ -void -client_send_environ(void) -{ - struct msg_environ_data data; - char **var; - - for (var = environ; *var != NULL; var++) { - if (strlcpy(data.var, *var, sizeof data.var) >= sizeof data.var) - continue; - client_write_server(MSG_ENVIRON, &data, sizeof data); - } -} - /* Helper to send one message. */ int client_write_one(enum msgtype type, int fd, const void *buf, size_t len) @@ -595,8 +587,6 @@ client_dispatch_wait(void *data0) case MSG_EXITED: imsg_free(&imsg); return (-1); - default: - fatalx("unexpected message"); } imsg_free(&imsg); @@ -675,8 +665,6 @@ client_dispatch_attached(void) system(data); client_write_server(MSG_UNLOCK, NULL, 0); break; - default: - fatalx("unexpected message"); } imsg_free(&imsg); diff --git a/cmd-attach-session.c b/cmd-attach-session.c index 70fea988..8dcc5997 100644 --- a/cmd-attach-session.c +++ b/cmd-attach-session.c @@ -18,7 +18,11 @@ #include +#include +#include #include +#include +#include #include "tmux.h" @@ -30,21 +34,25 @@ enum cmd_retval cmd_attach_session_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_attach_session_entry = { "attach-session", "attach", - "drt:", 0, 0, - "[-dr] " CMD_TARGET_SESSION_USAGE, + "c:drt:", 0, 0, + "[-dr] [-c working-directory] " CMD_TARGET_SESSION_USAGE, CMD_CANTNEST|CMD_STARTSERVER, NULL, cmd_attach_session_exec }; enum cmd_retval -cmd_attach_session(struct cmd_q *cmdq, const char* tflag, int dflag, int rflag) +cmd_attach_session(struct cmd_q *cmdq, const char *tflag, int dflag, int rflag, + const char *cflag) { - struct session *s; - struct client *c; - const char *update; - char *cause; - u_int i; + struct session *s; + struct client *c; + const char *update; + char *cause; + u_int i; + int fd; + struct format_tree *ft; + char *cp; if (RB_EMPTY(&sessions)) { cmdq_error(cmdq, "no sessions"); @@ -73,6 +81,27 @@ cmd_attach_session(struct cmd_q *cmdq, const char* tflag, int dflag, int rflag) } } + if (cflag != NULL) { + ft = format_create(); + if ((c = cmd_find_client(cmdq, NULL, 1)) != NULL) + format_client(ft, c); + format_session(ft, s); + format_winlink(ft, s, s->curw); + format_window_pane(ft, s->curw->window->active); + cp = format_expand(ft, cflag); + format_free(ft); + + 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); + } + close(s->cwd); + s->cwd = fd; + } + cmdq->client->session = s; notify_attached_session_changed(cmdq->client); session_update_activity(s); @@ -85,6 +114,27 @@ cmd_attach_session(struct cmd_q *cmdq, const char* tflag, int dflag, int rflag) return (CMD_RETURN_ERROR); } + if (cflag != NULL) { + ft = format_create(); + if ((c = cmd_find_client(cmdq, NULL, 1)) != NULL) + format_client(ft, c); + format_session(ft, s); + format_winlink(ft, s, s->curw); + format_window_pane(ft, s->curw->window->active); + cp = format_expand(ft, cflag); + format_free(ft); + + 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); + } + close(s->cwd); + s->cwd = fd; + } + if (rflag) cmdq->client->flags |= CLIENT_READONLY; @@ -115,5 +165,5 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_q *cmdq) struct args *args = self->args; return (cmd_attach_session(cmdq, args_get(args, 't'), - args_has(args, 'd'), args_has(args, 'r'))); + args_has(args, 'd'), args_has(args, 'r'), args_get(args, 'c'))); } diff --git a/cmd-load-buffer.c b/cmd-load-buffer.c index 8c92ca32..85595285 100644 --- a/cmd-load-buffer.c +++ b/cmd-load-buffer.c @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -49,11 +50,11 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_q *cmdq) struct client *c = cmdq->client; struct session *s; FILE *f; - const char *path, *newpath, *wd; + const char *path; char *pdata, *new_pdata, *cause; size_t psize; u_int limit; - int ch, error, buffer, *buffer_ptr; + int ch, error, buffer, *buffer_ptr, cwd, fd; if (!args_has(args, 'b')) buffer = -1; @@ -81,20 +82,17 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_q *cmdq) return (CMD_RETURN_WAIT); } - if (c != NULL) - wd = c->cwd; - else if ((s = cmd_current_session(cmdq, 0)) != NULL) { - wd = options_get_string(&s->options, "default-path"); - if (*wd == '\0') - wd = s->cwd; - } else - wd = NULL; - if (wd != NULL && *wd != '\0') { - newpath = get_full_path(wd, path); - if (newpath != NULL) - path = newpath; - } - if ((f = fopen(path, "rb")) == NULL) { + if (c != NULL && c->session == NULL) + cwd = c->cwd; + else if ((s = cmd_current_session(cmdq, 0)) != NULL) + cwd = s->cwd; + else + cwd = AT_FDCWD; + + 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)); return (CMD_RETURN_ERROR); } diff --git a/cmd-new-session.c b/cmd-new-session.c index 7c6ede62..5e69a77c 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -18,6 +18,8 @@ #include +#include +#include #include #include #include @@ -47,18 +49,15 @@ enum cmd_retval cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; - struct client *c = cmdq->client; + struct client *c = cmdq->client, *c0; struct session *s, *groupwith; struct window *w; struct environ env; struct termios tio, *tiop; - struct passwd *pw; - const char *newname, *target, *update, *base, *cwd; - const char *errstr, *template; + const char *newname, *target, *update, *errstr, *template; char *cmd, *cause, *cp; - int detached, idx; + int detached, already_attached, idx, cwd, fd = -1; u_int sx, sy; - int already_attached; struct format_tree *ft; if (args_has(args, 't') && (args->argc != 0 || args_has(args, 'n'))) { @@ -75,7 +74,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) if (session_find(newname) != NULL) { if (args_has(args, 'A')) { return (cmd_attach_session(cmdq, newname, - args_has(args, 'D'), 0)); + args_has(args, 'D'), 0, NULL)); } cmdq_error(cmdq, "duplicate session: %s", newname); return (CMD_RETURN_ERROR); @@ -100,6 +99,31 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) if (c != NULL && c->session != NULL) already_attached = 1; + /* Get the new session working directory. */ + if (args_has(args, 'c')) { + ft = format_create(); + if ((c0 = cmd_find_client(cmdq, NULL, 1)) != NULL) + format_client(ft, c0); + cp = format_expand(ft, args_get(args, 'c')); + format_free(ft); + + 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); + } + cwd = fd; + } else if (c->session == NULL) + cwd = c->cwd; + else if ((c0 = cmd_current_client(cmdq)) != NULL) + cwd = c0->session->cwd; + else { + fd = open(".", O_RDONLY); + cwd = fd; + } + /* * Save the termios settings, part of which is used for new windows in * this session. @@ -121,26 +145,10 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) if (server_client_open(c, NULL, &cause) != 0) { cmdq_error(cmdq, "open terminal failed: %s", cause); free(cause); - return (CMD_RETURN_ERROR); + goto error; } } - /* Get the new session working directory. */ - if (c != NULL && c->cwd != NULL) - base = c->cwd; - else { - pw = getpwuid(getuid()); - if (pw->pw_dir != NULL && *pw->pw_dir != '\0') - base = pw->pw_dir; - else - base = "/"; - } - if (args_has(args, 'c')) - cwd = args_get(args, 'c'); - else - cwd = options_get_string(&global_s_options, "default-path"); - cwd = cmd_default_path(base, base, cwd); - /* Find new session size. */ if (c != NULL) { sx = c->tty.sx; @@ -153,14 +161,14 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) sx = strtonum(args_get(args, 'x'), 1, USHRT_MAX, &errstr); if (errstr != NULL) { cmdq_error(cmdq, "width %s", errstr); - return (CMD_RETURN_ERROR); + goto error; } } if (detached && args_has(args, 'y')) { sy = strtonum(args_get(args, 'y'), 1, USHRT_MAX, &errstr); if (errstr != NULL) { cmdq_error(cmdq, "height %s", errstr); - return (CMD_RETURN_ERROR); + goto error; } } if (sy > 0 && options_get_number(&global_s_options, "status")) @@ -190,7 +198,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) if (s == NULL) { cmdq_error(cmdq, "create session failed: %s", cause); free(cause); - return (CMD_RETURN_ERROR); + goto error; } environ_free(&env); @@ -241,8 +249,8 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) template = NEW_SESSION_TEMPLATE; ft = format_create(); - if ((c = cmd_find_client(cmdq, NULL, 1)) != NULL) - format_client(ft, c); + if ((c0 = cmd_find_client(cmdq, NULL, 1)) != NULL) + format_client(ft, c0); format_session(ft, s); cp = format_expand(ft, template); @@ -254,5 +262,13 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) if (!detached) cmdq->client_exit = 0; + + if (fd != -1) + close(fd); return (CMD_RETURN_NORMAL); + +error: + if (fd != -1) + close(fd); + return (CMD_RETURN_ERROR); } diff --git a/cmd-new-window.c b/cmd-new-window.c index e72a1196..445f0a33 100644 --- a/cmd-new-window.c +++ b/cmd-new-window.c @@ -18,7 +18,11 @@ #include +#include +#include #include +#include +#include #include "tmux.h" @@ -45,9 +49,9 @@ cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq) struct session *s; struct winlink *wl; struct client *c; - const char *cmd, *cwd, *template; + const char *cmd, *template; char *cause, *cp; - int idx, last, detached; + int idx, last, detached, cwd, fd = -1; struct format_tree *ft; if (args_has(args, 'a')) { @@ -102,7 +106,29 @@ cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq) cmd = options_get_string(&s->options, "default-command"); else cmd = args->argv[0]; - cwd = cmdq_default_path(cmdq, args_get(args, 'c')); + + if (args_has(args, 'c')) { + ft = format_create(); + if ((c = cmd_find_client(cmdq, NULL, 1)) != NULL) + format_client(ft, c); + format_session(ft, s); + format_winlink(ft, s, s->curw); + format_window_pane(ft, s->curw->window->active); + cp = format_expand(ft, args_get(args, 'c')); + format_free(ft); + + 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); + } + cwd = fd; + } else if (cmdq->client->session == NULL) + cwd = cmdq->client->cwd; + else + cwd = s->cwd; if (idx == -1) idx = -1 - options_get_number(&s->options, "base-index"); @@ -110,7 +136,7 @@ cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq) if (wl == NULL) { cmdq_error(cmdq, "create window failed: %s", cause); free(cause); - return (CMD_RETURN_ERROR); + goto error; } if (!detached) { session_select(s, wl->idx); @@ -136,5 +162,12 @@ cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq) format_free(ft); } + if (fd != -1) + close(fd); return (CMD_RETURN_NORMAL); + +error: + if (fd != -1) + close(fd); + return (CMD_RETURN_ERROR); } diff --git a/cmd-queue.c b/cmd-queue.c index b2030e69..bb3a09ec 100644 --- a/cmd-queue.c +++ b/cmd-queue.c @@ -283,27 +283,3 @@ cmdq_flush(struct cmd_q *cmdq) } cmdq->item = NULL; } - -/* Get default path using command queue. */ -const char * -cmdq_default_path(struct cmd_q *cmdq, const char *cwd) -{ - struct client *c = cmdq->client; - struct session *s; - const char *current; - - if ((s = cmd_current_session(cmdq, 0)) == NULL) - return (NULL); - - if (cwd == NULL) - cwd = options_get_string(&s->options, "default-path"); - - if (c != NULL && c->session == NULL && c->cwd != NULL) - current = c->cwd; - else if (s->curw != NULL) - current = get_proc_cwd(s->curw->window->active->fd); - else - current = NULL; - - return (cmd_default_path(s->cwd, current, cwd)); -} diff --git a/cmd-save-buffer.c b/cmd-save-buffer.c index 57c3d65d..1b0a4e7b 100644 --- a/cmd-save-buffer.c +++ b/cmd-save-buffer.c @@ -20,8 +20,10 @@ #include #include +#include #include #include +#include #include #include "tmux.h" @@ -54,17 +56,14 @@ enum cmd_retval cmd_save_buffer_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; - struct client *c; + struct client *c = cmdq->client; struct session *s; struct paste_buffer *pb; - const char *path, *newpath, *wd; - char *cause, *start, *end; - size_t size, used; - int buffer; - mode_t mask; + const char *path; + char *cause, *start, *end, *msg; + size_t size, used, msglen; + int cwd, fd, buffer; FILE *f; - char *msg; - size_t msglen; if (!args_has(args, 'b')) { if ((pb = paste_get_top(&global_buffers)) == NULL) { @@ -91,7 +90,6 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_q *cmdq) else path = args->argv[0]; if (strcmp(path, "-") == 0) { - c = cmdq->client; if (c == NULL) { cmdq_error(cmdq, "can't write to stdout"); return (CMD_RETURN_ERROR); @@ -101,28 +99,26 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_q *cmdq) goto do_print; } - c = cmdq->client; - if (c != NULL) - wd = c->cwd; - else if ((s = cmd_current_session(cmdq, 0)) != NULL) { - wd = options_get_string(&s->options, "default-path"); - if (*wd == '\0') - wd = s->cwd; - } else - wd = NULL; - if (wd != NULL && *wd != '\0') { - newpath = get_full_path(wd, path); - if (newpath != NULL) - path = newpath; - } - - mask = umask(S_IRWXG | S_IRWXO); - if (args_has(self->args, 'a')) - f = fopen(path, "ab"); + if (c != NULL && c->session == NULL) + cwd = c->cwd; + else if ((s = cmd_current_session(cmdq, 0)) != NULL) + cwd = s->cwd; else - f = fopen(path, "wb"); - umask(mask); + cwd = AT_FDCWD; + + 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, 0600); + if (fd != -1) + f = fdopen(fd, "wb"); + } if (f == NULL) { + if (fd != -1) + close(fd); cmdq_error(cmdq, "%s: %s", path, strerror(errno)); return (CMD_RETURN_ERROR); } diff --git a/cmd-split-window.c b/cmd-split-window.c index 2e984de5..43d47c47 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -18,8 +18,11 @@ #include +#include +#include #include #include +#include #include #include "tmux.h" @@ -58,16 +61,14 @@ 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, *cwd, *shell; - char *cause, *new_cause; + const char *cmd, *shell, *template; + char *cause, *new_cause, *cp; u_int hlimit; - int size, percentage; + int size, percentage, cwd, fd = -1; enum layout_type type; struct layout_cell *lc; - const char *template; struct client *c; struct format_tree *ft; - char *cp; if ((wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp)) == NULL) return (CMD_RETURN_ERROR); @@ -83,7 +84,29 @@ cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq) cmd = options_get_string(&s->options, "default-command"); else cmd = args->argv[0]; - cwd = cmdq_default_path(cmdq, args_get(args, 'c')); + + if (args_has(args, 'c')) { + ft = format_create(); + if ((c = cmd_find_client(cmdq, NULL, 1)) != NULL) + format_client(ft, c); + format_session(ft, s); + format_winlink(ft, s, s->curw); + format_window_pane(ft, s->curw->window->active); + cp = format_expand(ft, args_get(args, 'c')); + format_free(ft); + + 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); + } + cwd = fd; + } else if (cmdq->client->session == NULL) + cwd = cmdq->client->cwd; + else + cwd = s->cwd; type = LAYOUT_TOPBOTTOM; if (args_has(args, 'h')) @@ -156,6 +179,9 @@ cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq) format_free(ft); } notify_window_layout_changed(w); + + if (fd != -1) + close(fd); return (CMD_RETURN_NORMAL); error: @@ -164,5 +190,7 @@ error: window_remove_pane(w, new_wp); cmdq_error(cmdq, "create pane failed: %s", cause); free(cause); + if (fd != -1) + close(fd); return (CMD_RETURN_ERROR); } diff --git a/format.c b/format.c index 8f86eba3..19c4dc15 100644 --- a/format.c +++ b/format.c @@ -403,7 +403,6 @@ format_client(struct format_tree *ft, struct client *c) time_t t; struct session *s; - format_add(ft, "client_cwd", "%s", c->cwd); format_add(ft, "client_height", "%u", c->tty.sy); format_add(ft, "client_width", "%u", c->tty.sx); if (c->tty.path != NULL) @@ -552,8 +551,6 @@ format_window_pane(struct format_tree *ft, struct window_pane *wp) format_add(ft, "pane_pid", "%ld", (long) wp->pid); if (wp->cmd != NULL) format_add(ft, "pane_start_command", "%s", wp->cmd); - if (wp->cwd != NULL) - format_add(ft, "pane_start_path", "%s", wp->cwd); if ((cwd = get_proc_cwd(wp->fd)) != NULL) format_add(ft, "pane_current_path", "%s", cwd); if ((cmd = get_proc_name(wp->fd, wp->tty)) != NULL) { diff --git a/options-table.c b/options-table.c index 22913854..97ca90be 100644 --- a/options-table.c +++ b/options-table.c @@ -126,11 +126,6 @@ const struct options_table_entry session_options_table[] = { .default_str = "" }, - { .name = "default-path", - .type = OPTIONS_TABLE_STRING, - .default_str = "~" - }, - { .name = "default-shell", .type = OPTIONS_TABLE_STRING, .default_str = _PATH_BSHELL diff --git a/server-client.c b/server-client.c index 4bba5f7d..a39f56d8 100644 --- a/server-client.c +++ b/server-client.c @@ -41,8 +41,7 @@ int server_client_assume_paste(struct session *); int server_client_msg_dispatch(struct client *); void server_client_msg_command(struct client *, struct imsg *); -void server_client_msg_identify( - struct client *, struct msg_identify_data *, int); +void server_client_msg_identify(struct client *, struct imsg *); void server_client_msg_shell(struct client *); /* Create a new client. */ @@ -151,6 +150,8 @@ server_client_lost(struct client *c) */ if (c->flags & CLIENT_TERMINAL) tty_free(&c->tty); + free(c->ttyname); + free(c->term); evbuffer_free (c->stdin_data); evbuffer_free (c->stdout_data); @@ -162,6 +163,7 @@ server_client_lost(struct client *c) screen_free(&c->status); free(c->title); + close(c->cwd); evtimer_del(&c->repeat_timer); @@ -179,7 +181,6 @@ server_client_lost(struct client *c) free(c->prompt_string); free(c->prompt_buffer); - free(c->cwd); c->cmdq->dead = 1; cmdq_free(c->cmdq); @@ -786,8 +787,6 @@ int server_client_msg_dispatch(struct client *c) { struct imsg imsg; - struct msg_identify_data identifydata; - struct msg_environ_data environdata; struct msg_stdin_data stdindata; const char *data; ssize_t n, datalen; @@ -813,12 +812,14 @@ server_client_msg_dispatch(struct client *c) log_debug("got %d from client %d", imsg.hdr.type, c->ibuf.fd); switch (imsg.hdr.type) { - case MSG_IDENTIFY: - if (datalen != sizeof identifydata) - fatalx("bad MSG_IDENTIFY size"); - memcpy(&identifydata, imsg.data, sizeof identifydata); - - server_client_msg_identify(c, &identifydata, imsg.fd); + case MSG_IDENTIFY_FLAGS: + case MSG_IDENTIFY_TERM: + case MSG_IDENTIFY_TTYNAME: + case MSG_IDENTIFY_CWD: + case MSG_IDENTIFY_STDIN: + case MSG_IDENTIFY_ENVIRON: + case MSG_IDENTIFY_DONE: + server_client_msg_identify(c, &imsg); break; case MSG_COMMAND: server_client_msg_command(c, &imsg); @@ -876,23 +877,12 @@ server_client_msg_dispatch(struct client *c) server_redraw_client(c); recalculate_sizes(); break; - case MSG_ENVIRON: - if (datalen != sizeof environdata) - fatalx("bad MSG_ENVIRON size"); - memcpy(&environdata, imsg.data, sizeof environdata); - - environdata.var[(sizeof environdata.var) - 1] = '\0'; - if (strchr(environdata.var, '=') != NULL) - environ_put(&c->environ, environdata.var); - break; case MSG_SHELL: if (datalen != 0) fatalx("bad MSG_SHELL size"); server_client_msg_shell(c); break; - default: - fatalx("unexpected message"); } imsg_free(&imsg); @@ -951,46 +941,99 @@ error: /* Handle identify message. */ void -server_client_msg_identify( - struct client *c, struct msg_identify_data *data, int fd) +server_client_msg_identify(struct client *c, struct imsg *imsg) { - c->cwd = NULL; - data->cwd[(sizeof data->cwd) - 1] = '\0'; - if (*data->cwd != '\0') - c->cwd = xstrdup(data->cwd); + const char *data; + size_t datalen; + int flags; - if (data->flags & CLIENT_CONTROL) { + if (c->flags & CLIENT_IDENTIFIED) + fatalx("out-of-order identify message"); + + data = imsg->data; + datalen = imsg->hdr.len - IMSG_HEADER_SIZE; + + switch (imsg->hdr.type) { + case MSG_IDENTIFY_FLAGS: + if (datalen != sizeof flags) + fatalx("bad MSG_IDENTIFY_FLAGS size"); + memcpy(&flags, data, sizeof flags); + c->flags |= flags; + break; + case MSG_IDENTIFY_TERM: + if (data[datalen - 1] != '\0') + fatalx("bad MSG_IDENTIFY_TERM string"); + c->term = xstrdup(data); + break; + case MSG_IDENTIFY_TTYNAME: + if (data[datalen - 1] != '\0') + fatalx("bad MSG_IDENTIFY_TTYNAME string"); + c->ttyname = xstrdup(data); + break; + case MSG_IDENTIFY_CWD: + if (datalen != 0) + fatalx("bad MSG_IDENTIFY_CWD size"); + c->cwd = imsg->fd; + break; + case MSG_IDENTIFY_STDIN: + if (datalen != 0) + fatalx("bad MSG_IDENTIFY_STDIN size"); + c->fd = imsg->fd; + break; + case MSG_IDENTIFY_ENVIRON: + if (data[datalen - 1] != '\0') + fatalx("bad MSG_IDENTIFY_ENVIRON string"); + if (strchr(data, '=') != NULL) + environ_put(&c->environ, data); + break; + default: + break; + } + + if (imsg->hdr.type != MSG_IDENTIFY_DONE) + return; + c->flags |= CLIENT_IDENTIFIED; + +#ifdef __CYGWIN__ + c->fd = open(c->ttyname, O_RDWR|O_NOCTTY); + c->cwd = open(".", O_RDONLY); +#endif + + if (c->flags & CLIENT_CONTROL) { c->stdin_callback = control_callback; + evbuffer_free(c->stderr_data); c->stderr_data = c->stdout_data; - c->flags |= CLIENT_CONTROL; - if (data->flags & CLIENT_CONTROLCONTROL) + + if (c->flags & CLIENT_CONTROLCONTROL) evbuffer_add_printf(c->stdout_data, "\033P1000p"); server_write_client(c, MSG_STDIN, NULL, 0); c->tty.fd = -1; c->tty.log_fd = -1; - close(fd); + close(c->fd); + c->fd = -1; + return; } - if (fd == -1) + if (c->fd == -1) return; - if (!isatty(fd)) { - close(fd); + if (!isatty(c->fd)) { + close(c->fd); + c->fd = -1; return; } - data->term[(sizeof data->term) - 1] = '\0'; - tty_init(&c->tty, c, fd, data->term); - if (data->flags & CLIENT_UTF8) + tty_init(&c->tty, c, c->fd, c->term); + if (c->flags & CLIENT_UTF8) c->tty.flags |= TTY_UTF8; - if (data->flags & CLIENT_256COLOURS) + if (c->flags & CLIENT_256COLOURS) c->tty.term_flags |= TERM_256COLOURS; tty_resize(&c->tty); - if (!(data->flags & CLIENT_CONTROL)) + if (!(c->flags & CLIENT_CONTROL)) c->flags |= CLIENT_TERMINAL; } diff --git a/server-fn.c b/server-fn.c index f6485b49..d0747628 100644 --- a/server-fn.c +++ b/server-fn.c @@ -56,8 +56,8 @@ server_write_ready(struct client *c) } int -server_write_client( - struct client *c, enum msgtype type, const void *buf, size_t len) +server_write_client(struct client *c, enum msgtype type, const void *buf, + size_t len) { struct imsgbuf *ibuf = &c->ibuf; int error; @@ -73,8 +73,8 @@ server_write_client( } void -server_write_session( - struct session *s, enum msgtype type, const void *buf, size_t len) +server_write_session(struct session *s, enum msgtype type, const void *buf, + size_t len) { struct client *c; u_int i; diff --git a/session.c b/session.c index f967de19..4f6ebed6 100644 --- a/session.c +++ b/session.c @@ -85,9 +85,8 @@ session_find_by_id(u_int id) /* Create a new session. */ struct session * -session_create(const char *name, const char *cmd, const char *cwd, - struct environ *env, struct termios *tio, int idx, u_int sx, u_int sy, - char **cause) +session_create(const char *name, const char *cmd, int cwd, struct environ *env, + struct termios *tio, int idx, u_int sx, u_int sy, char **cause) { struct session *s; @@ -99,7 +98,7 @@ session_create(const char *name, const char *cmd, const char *cwd, fatal("gettimeofday failed"); session_update_activity(s); - s->cwd = xstrdup(cwd); + s->cwd = dup(cwd); s->curw = NULL; TAILQ_INIT(&s->lastw); @@ -171,7 +170,7 @@ session_destroy(struct session *s) winlink_remove(&s->windows, wl); } - free(s->cwd); + close(s->cwd); RB_INSERT(sessions, &dead_sessions, s); } @@ -227,8 +226,8 @@ session_previous_session(struct session *s) /* Create a new window on a session. */ struct winlink * -session_new(struct session *s, - const char *name, const char *cmd, const char *cwd, int idx, char **cause) +session_new(struct session *s, const char *name, const char *cmd, int cwd, + int idx, char **cause) { struct window *w; struct winlink *wl; @@ -251,8 +250,8 @@ session_new(struct session *s, shell = _PATH_BSHELL; hlimit = options_get_number(&s->options, "history-limit"); - w = window_create( - name, cmd, shell, cwd, &env, s->tio, s->sx, s->sy, hlimit, cause); + w = window_create(name, cmd, shell, cwd, &env, s->tio, s->sx, s->sy, + hlimit, cause); if (w == NULL) { winlink_remove(&s->windows, wl); environ_free(&env); diff --git a/tmux.1 b/tmux.1 index 07d6b3fe..eb417da0 100644 --- a/tmux.1 +++ b/tmux.1 @@ -564,6 +564,7 @@ The following commands are available to manage clients and sessions: .Bl -tag -width Ds .It Xo Ic attach-session .Op Fl dr +.Op Fl c Ar working-directory .Op Fl t Ar target-session .Xc .D1 (alias: Ic attach ) @@ -597,6 +598,10 @@ needs to select the most recently used session, it will prefer the most recently used .Em unattached session. +.Pp +.Fl c +will set the session working directory (used for new windows) to +.Ar working-directory . .It Xo Ic detach-client .Op Fl P .Op Fl a @@ -1509,13 +1514,6 @@ is not specified, the value of the option is used. .Fl c specifies the working directory in which the new window is created. -It may have an absolute path or one of the following values (or a subdirectory): -.Bl -column "XXXXXXXXXXXX" "XXXXXXXXXXXXXXXXXXXXXXXX" -offset indent -.It Li "Empty string" Ta "Current pane's directory" -.It Li "~" Ta "User's home directory" -.It Li "-" Ta "Where session was started" -.It Li "." Ta "Where server was started" -.El .Pp When the shell command completes, the window closes. See the @@ -2175,17 +2173,6 @@ The default is an empty string, which instructs to create a login shell using the value of the .Ic default-shell option. -.It Ic default-path Ar path -Set the default working directory for new panes. -If empty, the working directory is determined from the process -running in the active pane, from the command line environment or from the -working directory where the session was created. -Otherwise the same options are available as for the -.Fl c -flag to -.Ic new-window . -The default is -.Ql ~ . .It Ic default-shell Ar path Specify the default shell. This is used as the login shell for new windows when the @@ -3054,7 +3041,6 @@ The following variables are available, where appropriate: .It Li "client_activity_string" Ta "" Ta "String time client last had activity" .It Li "client_created" Ta "" Ta "Integer time client created" .It Li "client_created_string" Ta "" Ta "String time client created" -.It Li "client_cwd" Ta "" Ta "Working directory of client" .It Li "client_height" Ta "" Ta "Height of client" .It Li "client_last_session" Ta "" Ta "Name of the client's last session" .It Li "client_prefix" Ta "" Ta "1 if prefix key has been pressed" diff --git a/tmux.c b/tmux.c index 140946b9..a78746ae 100644 --- a/tmux.c +++ b/tmux.c @@ -124,30 +124,6 @@ areshell(const char *shell) return (0); } -const char* -get_full_path(const char *wd, const char *path) -{ - int fd; - static char newpath[MAXPATHLEN]; - const char *retval; - - fd = open(".", O_RDONLY); - if (fd == -1) - return (NULL); - - retval = NULL; - if (chdir(wd) == 0) { - if (realpath(path, newpath) == 0) - retval = newpath; - } - - if (fchdir(fd) != 0) - chdir("/"); - close(fd); - - return (retval); -} - void parseenvironment(void) { @@ -246,7 +222,7 @@ int main(int argc, char **argv) { struct passwd *pw; - char *s, *path, *label, *home, **var; + char *s, *path, *label, *home, **var, tmp[MAXPATHLEN]; int opt, flags, quiet, keys; #ifdef DEBUG @@ -327,6 +303,8 @@ main(int argc, char **argv) environ_init(&global_environ); for (var = environ; *var != NULL; var++) environ_put(&global_environ, *var); + if (getcwd(tmp, sizeof tmp) != NULL) + environ_set(&global_environ, "PWD", tmp); options_init(&global_options, NULL); options_table_populate_tree(server_options_table, &global_options); diff --git a/tmux.h b/tmux.h index 2d631a17..e281790d 100644 --- a/tmux.h +++ b/tmux.h @@ -58,13 +58,6 @@ extern char **environ; /* Automatic name refresh interval, in milliseconds. */ #define NAME_INTERVAL 500 -/* - * Maximum sizes of strings in message data. Don't forget to bump - * PROTOCOL_VERSION if any of these change! - */ -#define TERMINAL_LENGTH 128 /* length of TERM environment variable */ -#define ENVIRON_LENGTH 1024 /* environment variable length */ - /* * UTF-8 data size. This must be big enough to hold combined characters as well * as single. @@ -463,9 +456,6 @@ enum msgtype { MSG_SUSPEND, MSG_UNLOCK, MSG_WAKEUP, - - MSG_IDENTIFY = 300, - MSG_ENVIRON }; /* @@ -480,17 +470,6 @@ struct msg_command_data { int argc; }; /* followed by packed argv */ -struct msg_identify_data { - char cwd[MAXPATHLEN]; - char term[TERMINAL_LENGTH]; - - int flags; -}; - -struct msg_environ_data { - char var[ENVIRON_LENGTH]; -}; - struct msg_stdin_data { ssize_t size; char data[BUFSIZ]; @@ -937,7 +916,7 @@ struct window_pane { char *cmd; char *shell; - char *cwd; + int cwd; pid_t pid; char tty[TTY_NAME_MAX]; @@ -1084,7 +1063,7 @@ struct session { u_int id; char *name; - char *cwd; + int cwd; struct timeval creation_time; struct timeval activity_time; @@ -1284,6 +1263,7 @@ RB_HEAD(status_out_tree, status_out); struct client { struct imsgbuf ibuf; + int fd; struct event event; int retval; @@ -1293,8 +1273,10 @@ struct client { struct environ environ; char *title; - char *cwd; + int cwd; + char *term; + char *ttyname; struct tty tty; void (*stdin_callback)(struct client *, int, void *); @@ -1527,7 +1509,6 @@ void logfile(const char *); const char *getshell(void); int checkshell(const char *); int areshell(const char *); -const char* get_full_path(const char *, const char *); void setblocking(int, int); __dead void shell_exec(const char *, const char *); @@ -1763,7 +1744,6 @@ int cmd_find_index(struct cmd_q *, const char *, struct winlink *cmd_find_pane(struct cmd_q *, const char *, struct session **, struct window_pane **); char *cmd_template_replace(const char *, const char *, int); -const char *cmd_default_path(const char *, const char *, const char *); extern const struct cmd_entry *cmd_table[]; extern const struct cmd_entry cmd_attach_session_entry; extern const struct cmd_entry cmd_bind_key_entry; @@ -1854,7 +1834,8 @@ extern const struct cmd_entry cmd_up_pane_entry; extern const struct cmd_entry cmd_wait_for_entry; /* cmd-attach-session.c */ -enum cmd_retval cmd_attach_session(struct cmd_q *, const char*, int, int); +enum cmd_retval cmd_attach_session(struct cmd_q *, const char *, int, int, + const char *); /* cmd-list.c */ struct cmd_list *cmd_list_parse(int, char **, const char *, u_int, char **); @@ -1872,7 +1853,6 @@ void cmdq_run(struct cmd_q *, struct cmd_list *); void cmdq_append(struct cmd_q *, struct cmd_list *); int cmdq_continue(struct cmd_q *); void cmdq_flush(struct cmd_q *); -const char *cmdq_default_path(struct cmd_q *, const char *); /* cmd-string.c */ int cmd_string_parse(const char *, struct cmd_list **, const char *, @@ -2144,9 +2124,9 @@ void winlink_stack_remove(struct winlink_stack *, struct winlink *); int window_index(struct window *, u_int *); struct window *window_find_by_id(u_int); struct window *window_create1(u_int, u_int); -struct window *window_create(const char *, const char *, const char *, - const char *, struct environ *, struct termios *, - u_int, u_int, u_int, char **); +struct window *window_create(const char *, const char *, const char *, int, + 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); void window_set_active_at(struct window *, u_int, u_int); @@ -2170,8 +2150,8 @@ struct window_pane *window_pane_create(struct window *, u_int, u_int, u_int); void window_pane_destroy(struct window_pane *); void window_pane_timer_start(struct window_pane *); int window_pane_spawn(struct window_pane *, const char *, - const char *, const char *, struct environ *, - struct termios *, char **); + const char *, int, struct environ *, struct termios *, + char **); void window_pane_resize(struct window_pane *, u_int, u_int); void window_pane_alternate_on(struct window_pane *, struct grid_cell *, int); @@ -2307,7 +2287,7 @@ RB_PROTOTYPE(sessions, session, entry, session_cmp); int session_alive(struct session *); struct session *session_find(const char *); struct session *session_find_by_id(u_int); -struct session *session_create(const char *, const char *, const char *, +struct session *session_create(const char *, const char *, int, struct environ *, struct termios *, int, u_int, u_int, char **); void session_destroy(struct session *); @@ -2315,8 +2295,8 @@ int session_check_name(const char *); void session_update_activity(struct session *); struct session *session_next_session(struct session *); struct session *session_previous_session(struct session *); -struct winlink *session_new(struct session *, - const char *, const char *, const char *, int, char **); +struct winlink *session_new(struct session *, const char *, const char *, int, + int, char **); struct winlink *session_attach( struct session *, struct window *, int, char **); int session_detach(struct session *, struct winlink *); diff --git a/window.c b/window.c index 0ea70688..83e14db6 100644 --- a/window.c +++ b/window.c @@ -309,7 +309,7 @@ window_create1(u_int sx, u_int sy) struct window * window_create(const char *name, const char *cmd, const char *shell, - const char *cwd, struct environ *env, struct termios *tio, + int cwd, struct environ *env, struct termios *tio, u_int sx, u_int sy, u_int hlimit, char **cause) { struct window *w; @@ -675,7 +675,7 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit) wp->cmd = NULL; wp->shell = NULL; - wp->cwd = NULL; + wp->cwd = -1; wp->fd = -1; wp->event = NULL; @@ -730,7 +730,7 @@ window_pane_destroy(struct window_pane *wp) RB_REMOVE(window_pane_tree, &all_window_panes, wp); - free(wp->cwd); + close(wp->cwd); free(wp->shell); free(wp->cmd); free(wp); @@ -738,7 +738,7 @@ window_pane_destroy(struct window_pane *wp) int window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell, - const char *cwd, struct environ *env, struct termios *tio, char **cause) + int cwd, struct environ *env, struct termios *tio, char **cause) { struct winsize ws; char *argv0, paneid[16]; @@ -757,9 +757,9 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell, free(wp->shell); wp->shell = xstrdup(shell); } - if (cwd != NULL) { - free(wp->cwd); - wp->cwd = xstrdup(cwd); + if (cwd != -1) { + close(wp->cwd); + wp->cwd = dup(cwd); } log_debug("spawn: %s -- %s", wp->shell, wp->cmd); @@ -774,7 +774,7 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell, xasprintf(cause, "%s: %s", cmd, strerror(errno)); return (-1); case 0: - if (chdir(wp->cwd) != 0) + if (fchdir(wp->cwd) != 0) chdir("/"); if (tcgetattr(STDIN_FILENO, &tio2) != 0)