From 304ea079d2157b6625c960e0daa817213ba1ffd6 Mon Sep 17 00:00:00 2001 From: schwarze Date: Tue, 16 Jul 2013 00:07:52 +0000 Subject: [PATCH 01/47] use .Mt for email addresses; from Jan Stary ; ok jmc@ --- tmux.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmux.1 b/tmux.1 index da010d17..7a01b394 100644 --- a/tmux.1 +++ b/tmux.1 @@ -3799,4 +3799,4 @@ bind-key S command-prompt "new-window -n %1 'ssh %1'" .Sh SEE ALSO .Xr pty 4 .Sh AUTHORS -.An Nicholas Marriott Aq nicm@users.sourceforge.net +.An Nicholas Marriott Aq Mt nicm@users.sourceforge.net From 3d8a8ea0c68d6ab343568559f7d5879170c2e78c Mon Sep 17 00:00:00 2001 From: nicm Date: Sat, 5 Oct 2013 08:12:39 +0000 Subject: [PATCH 02/47] Use open(".")/fchdir() to save and restore current directory rather than getcwd()/chdir(). --- tmux.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/tmux.c b/tmux.c index b229967d..8726a55f 100644 --- a/tmux.c +++ b/tmux.c @@ -127,16 +127,22 @@ areshell(const char *shell) const char* get_full_path(const char *wd, const char *path) { + int fd; static char newpath[MAXPATHLEN]; - char oldpath[MAXPATHLEN]; - if (getcwd(oldpath, sizeof oldpath) == NULL) + fd = open(".", O_RDONLY); + if (fd == -1) return (NULL); + if (chdir(wd) != 0) return (NULL); if (realpath(path, newpath) != 0) return (NULL); - chdir(oldpath); + + if (fchdir(fd) != 0) + chdir("/"); + close(fd); + return (newpath); } From 9f330897a8fc4f927d355eacf9cc58f3be2092f7 Mon Sep 17 00:00:00 2001 From: nicm Date: Sat, 5 Oct 2013 10:40:49 +0000 Subject: [PATCH 03/47] Fix previous not to leak fd on failure, whoops. --- tmux.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/tmux.c b/tmux.c index 8726a55f..73843a96 100644 --- a/tmux.c +++ b/tmux.c @@ -127,23 +127,25 @@ areshell(const char *shell) const char* get_full_path(const char *wd, const char *path) { - int fd; - static char newpath[MAXPATHLEN]; + int fd; + static char newpath[MAXPATHLEN]; + const char *retval; fd = open(".", O_RDONLY); if (fd == -1) return (NULL); - if (chdir(wd) != 0) - return (NULL); - if (realpath(path, newpath) != 0) - return (NULL); + retval = NULL; + if (chdir(wd) == 0) { + if (realpath(path, newpath) == 0) + retval = newpath; + } if (fchdir(fd) != 0) chdir("/"); close(fd); - return (newpath); + return (retval); } void From 7c71c3e27de71e8a91590a4e2ed1945873cfc538 Mon Sep 17 00:00:00 2001 From: nicm Date: Sat, 5 Oct 2013 13:56:48 +0000 Subject: [PATCH 04/47] Change the default for the default-path option to ~. This is a quick change to turn off the KERN_PROC_CWD code which is unpredictable. Later it will go away and there may be other changes to how this works. --- options-table.c | 2 +- tmux.1 | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/options-table.c b/options-table.c index cf0202b7..138a307e 100644 --- a/options-table.c +++ b/options-table.c @@ -128,7 +128,7 @@ const struct options_table_entry session_options_table[] = { { .name = "default-path", .type = OPTIONS_TABLE_STRING, - .default_str = "" + .default_str = "~" }, { .name = "default-shell", diff --git a/tmux.1 b/tmux.1 index 7a01b394..61158872 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2173,13 +2173,15 @@ to create a login shell using the value of the option. .It Ic default-path Ar path Set the default working directory for new panes. -If empty (the default), the working directory is determined from the process +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 From 4c9f41f1adbdf2e9c5fa2def959ac13ea4a9785c Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Oct 2013 11:45:28 +0000 Subject: [PATCH 05/47] Pass flags into cmdq_guard as an argument since sometimes cmdq->cmd can be NULL. Avoids crash when a command in a command client can't be parsed. --- cmd-queue.c | 16 ++++++++-------- control.c | 4 ++-- tmux.h | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/cmd-queue.c b/cmd-queue.c index 904b092c..f3506a34 100644 --- a/cmd-queue.c +++ b/cmd-queue.c @@ -154,18 +154,15 @@ cmdq_error(struct cmd_q *cmdq, const char *fmt, ...) /* Print a guard line. */ int -cmdq_guard(struct cmd_q *cmdq, const char *guard) +cmdq_guard(struct cmd_q *cmdq, const char *guard, int flags) { struct client *c = cmdq->client; - int flags; if (c == NULL) return 0; if (!(c->flags & CLIENT_CONTROL)) return 0; - flags = !!(cmdq->cmd->flags & CMD_CONTROL); - evbuffer_add_printf(c->stdout_data, "%%%s %ld %u %d\n", guard, (long) cmdq->time, cmdq->number, flags); server_push_stdout(c); @@ -202,7 +199,7 @@ cmdq_continue(struct cmd_q *cmdq) { struct cmd_q_item *next; enum cmd_retval retval; - int empty, guard; + int empty, guard, flags; char s[1024]; notify_disable(); @@ -228,13 +225,16 @@ cmdq_continue(struct cmd_q *cmdq) cmdq->time = time(NULL); cmdq->number++; - guard = cmdq_guard(cmdq, "begin"); + flags = !!(cmdq->cmd->flags & CMD_CONTROL); + guard = cmdq_guard(cmdq, "begin", flags); + retval = cmdq->cmd->entry->exec(cmdq->cmd, cmdq); + if (guard) { if (retval == CMD_RETURN_ERROR) - cmdq_guard(cmdq, "error"); + cmdq_guard(cmdq, "error", flags); else - cmdq_guard(cmdq, "end"); + cmdq_guard(cmdq, "end", flags); } if (retval == CMD_RETURN_ERROR) diff --git a/control.c b/control.c index 1f3739fc..8e24fd0e 100644 --- a/control.c +++ b/control.c @@ -73,9 +73,9 @@ control_callback(struct client *c, int closed, unused void *data) c->cmdq->time = time(NULL); c->cmdq->number++; - cmdq_guard(c->cmdq, "begin"); + cmdq_guard(c->cmdq, "begin", 1); control_write(c, "parse error: %s", cause); - cmdq_guard(c->cmdq, "error"); + cmdq_guard(c->cmdq, "error", 1); free(cause); } else { diff --git a/tmux.h b/tmux.h index b5608da3..21be2bd6 100644 --- a/tmux.h +++ b/tmux.h @@ -1871,7 +1871,7 @@ int cmdq_free(struct cmd_q *); void printflike2 cmdq_print(struct cmd_q *, const char *, ...); void printflike2 cmdq_info(struct cmd_q *, const char *, ...); void printflike2 cmdq_error(struct cmd_q *, const char *, ...); -int cmdq_guard(struct cmd_q *, const char *); +int cmdq_guard(struct cmd_q *, const char *, int); void cmdq_run(struct cmd_q *, struct cmd_list *); void cmdq_append(struct cmd_q *, struct cmd_list *); int cmdq_continue(struct cmd_q *); From 0538676aa38914097fcf1a8eb292eac8852434aa Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Oct 2013 11:46:00 +0000 Subject: [PATCH 06/47] Make recalculate_sizes() handle an empty window with no active pane. This can happen when a window is in two sessions - it isn't destroyed immediately when the pane goes away but is left until the last session is destroyed. Fixes problems with grouped sessions reported by Daniel Ralston. --- resize.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resize.c b/resize.c index b5196c1c..ff3ec6c5 100644 --- a/resize.c +++ b/resize.c @@ -92,7 +92,7 @@ recalculate_sizes(void) for (i = 0; i < ARRAY_LENGTH(&windows); i++) { w = ARRAY_ITEM(&windows, i); - if (w == NULL) + if (w == NULL || w->active == NULL) continue; flag = options_get_number(&w->options, "aggressive-resize"); From d3830e622f94f0826e2169eca1f920abc234a412 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Oct 2013 11:46:28 +0000 Subject: [PATCH 07/47] Grouped sessions were being leaked on destroy, correctly free them. --- server-fn.c | 7 ++++--- session.c | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/server-fn.c b/server-fn.c index efb95acd..fb0eadd6 100644 --- a/server-fn.c +++ b/server-fn.c @@ -398,14 +398,15 @@ void server_destroy_session_group(struct session *s) { struct session_group *sg; + struct session *s1; if ((sg = session_group_find(s)) == NULL) server_destroy_session(s); else { - TAILQ_FOREACH(s, &sg->sessions, gentry) + TAILQ_FOREACH_SAFE(s, &sg->sessions, gentry, s1) { server_destroy_session(s); - TAILQ_REMOVE(&session_groups, sg, entry); - free(sg); + session_destroy(s); + } } } diff --git a/session.c b/session.c index c7b54a2b..7e144886 100644 --- a/session.c +++ b/session.c @@ -151,6 +151,7 @@ void session_destroy(struct session *s) { struct winlink *wl; + log_debug("session %s destroyed", s->name); RB_REMOVE(sessions, &sessions, s); From 6e665708fc13836dff9a683ccddb2ed194951767 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Oct 2013 11:46:47 +0000 Subject: [PATCH 08/47] Missing space in refresh-client synopsis. --- cmd-refresh-client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd-refresh-client.c b/cmd-refresh-client.c index eff692dd..e95e1ea3 100644 --- a/cmd-refresh-client.c +++ b/cmd-refresh-client.c @@ -29,7 +29,7 @@ enum cmd_retval cmd_refresh_client_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_refresh_client_entry = { "refresh-client", "refresh", "C:St:", 0, 0, - "[-S] [-C size]" CMD_TARGET_CLIENT_USAGE, + "[-S] [-C size] " CMD_TARGET_CLIENT_USAGE, 0, NULL, NULL, From d75dd2ab1c792ea06c2777a31cb83cb3ba4c47a7 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Oct 2013 11:47:52 +0000 Subject: [PATCH 09/47] Add formats for window flags. --- format.c | 24 +++++++++++++++++++++--- tmux.1 | 4 ++++ 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/format.c b/format.c index 168ff5b9..e870cd0a 100644 --- a/format.c +++ b/format.c @@ -151,6 +151,7 @@ void format_add(struct format_tree *ft, const char *key, const char *fmt, ...) { struct format_entry *fe; + struct format_entry *fe_now; va_list ap; fe = xmalloc(sizeof *fe); @@ -160,7 +161,13 @@ format_add(struct format_tree *ft, const char *key, const char *fmt, ...) xvasprintf(&fe->value, fmt, ap); va_end(ap); - RB_INSERT(format_tree, ft, fe); + fe_now = RB_INSERT(format_tree, ft, fe); + if (fe_now != NULL) { + free(fe_now->value); + fe_now->value = fe->value; + free(fe->key); + free(fe); + } } /* Find a format entry. */ @@ -346,8 +353,10 @@ format_client(struct format_tree *ft, struct client *c) 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); - format_add(ft, "client_tty", "%s", c->tty.path); - format_add(ft, "client_termname", "%s", c->tty.termname); + if (c->tty.path != NULL) + format_add(ft, "client_tty", "%s", c->tty.path); + if (c->tty.termname != NULL) + format_add(ft, "client_termname", "%s", c->tty.termname); t = c->creation_time.tv_sec; format_add(ft, "client_created", "%lld", (long long) t); @@ -401,6 +410,15 @@ format_winlink(struct format_tree *ft, struct session *s, struct winlink *wl) format_add(ft, "window_active", "%d", wl == s->curw); format_add(ft, "window_panes", "%u", window_count_panes(w)); + format_add(ft, "window_bell_flag", "%u", + !!(wl->flags & WINLINK_BELL)); + format_add(ft, "window_content_flag", "%u", + !!(wl->flags & WINLINK_CONTENT)); + format_add(ft, "window_activity_flag", "%u", + !!(wl->flags & WINLINK_ACTIVITY)); + format_add(ft, "window_silence_flag", "%u", + !!(wl->flags & WINLINK_SILENCE)); + free(flags); free(layout); } diff --git a/tmux.1 b/tmux.1 index 61158872..fe2b1765 100644 --- a/tmux.1 +++ b/tmux.1 @@ -3094,6 +3094,9 @@ The following variables are available, where appropriate: .It Li "session_width" Ta "" Ta "Width of session" .It Li "session_windows" Ta "" Ta "Number of windows in session" .It Li "window_active" Ta "" Ta "1 if window active" +.It Li "window_activity_flag" Ta "" Ta "1 if window has activity alert" +.It Li "window_bell_flag" Ta "" Ta "1 if window has bell" +.It Li "window_content_flag" Ta "" Ta "1 if window has content alert" .It Li "window_find_matches" Ta "" Ta "Matched data from the find-window" .It Li "window_flags" Ta "#F" Ta "Window flags" .It Li "window_height" Ta "" Ta "Height of window" @@ -3102,6 +3105,7 @@ The following variables are available, where appropriate: .It Li "window_layout" Ta "" Ta "Window layout description" .It Li "window_name" Ta "#W" Ta "Name of window" .It Li "window_panes" Ta "" Ta "Number of panes in window" +.It Li "window_silence_flag" Ta "" Ta "1 if window has silence alert" .It Li "window_width" Ta "" Ta "Width of window" .It Li "wrap_flag" Ta "" Ta "Pane wrap flag" .El From 47a4a9992c59199bb55188c666eddce7895d884e Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Oct 2013 11:49:07 +0000 Subject: [PATCH 10/47] Allow the file descriptor received from the client to be -1. --- server-client.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server-client.c b/server-client.c index 5f61f5c0..44119237 100644 --- a/server-client.c +++ b/server-client.c @@ -825,8 +825,6 @@ server_client_msg_dispatch(struct client *c) case MSG_IDENTIFY: if (datalen != sizeof identifydata) fatalx("bad MSG_IDENTIFY size"); - if (imsg.fd == -1) - fatalx("MSG_IDENTIFY missing fd"); memcpy(&identifydata, imsg.data, sizeof identifydata); server_client_msg_identify(c, &identifydata, imsg.fd); @@ -972,6 +970,8 @@ server_client_msg_identify( return; } + if (fd == -1) + return; if (!isatty(fd)) { close(fd); return; From 7839993fe734aec38355401ce5a02d85f9dab5ba Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Oct 2013 11:49:29 +0000 Subject: [PATCH 11/47] Only include actual trailing spaces not unused cells with capturep -J, from George Nachman. --- grid.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/grid.c b/grid.c index 529ce154..b2ee0c69 100644 --- a/grid.c +++ b/grid.c @@ -592,6 +592,7 @@ grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx, char *buf, code[128]; size_t len, off, size, codelen; u_int xx; + const struct grid_line *gl; GRID_DEBUG(gd, "px=%u, py=%u, nx=%u", px, py, nx); @@ -604,8 +605,11 @@ grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx, buf = xmalloc(len); off = 0; + gl = grid_peek_line(gd, py); for (xx = px; xx < px + nx; xx++) { - gc = grid_peek_cell(gd, xx, py); + if (gl == NULL || xx >= gl->cellsize) + break; + gc = &gl->celldata[xx]; if (gc->flags & GRID_FLAG_PADDING) continue; grid_cell_get(gc, &ud); From 2756d127507cb939582adf2bbaf7be4cf5b711cd Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Oct 2013 11:49:42 +0000 Subject: [PATCH 12/47] Handle input mouse positions <33 (we already can generate them). --- tty-keys.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/tty-keys.c b/tty-keys.c index 26edbf32..3b652db8 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -676,11 +676,17 @@ tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size) log_debug("mouse input: %.*s", (int) *size, buf); /* Check and return the mouse input. */ - if (b < 32 || x < 33 || y < 33) + if (b < 32) return (-1); b -= 32; - x -= 33; - y -= 33; + if (x >= 33) + x -= 33; + else + x = 256 - x; + if (y >= 33) + y -= 33; + else + y = 256 - y; } else if (buf[2] == '<') { /* Read the three inputs. */ *size = 3; From 40811eb8d45c1b6d93da2ebae6c4bc821d2b9836 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Oct 2013 11:50:20 +0000 Subject: [PATCH 13/47] Add length limit operator for formats. --- format.c | 40 ++++++++++++++++++++++++++++++++++------ options-table.c | 2 +- tmux.1 | 6 ++++++ 3 files changed, 41 insertions(+), 7 deletions(-) diff --git a/format.c b/format.c index e870cd0a..72e42ba0 100644 --- a/format.c +++ b/format.c @@ -18,6 +18,8 @@ #include +#include +#include #include #include #include @@ -188,18 +190,40 @@ format_find(struct format_tree *ft, const char *key) * #{?blah,a,b} is replace with a if blah exists and is nonzero else b. */ int -format_replace(struct format_tree *ft, - const char *key, size_t keylen, char **buf, size_t *len, size_t *off) +format_replace(struct format_tree *ft, const char *key, size_t keylen, + char **buf, size_t *len, size_t *off) { - char *copy, *ptr; + char *copy, *copy0, *endptr, *ptr; const char *value; size_t valuelen; + u_long limit = ULONG_MAX; /* Make a copy of the key. */ - copy = xmalloc(keylen + 1); + copy0 = copy = xmalloc(keylen + 1); memcpy(copy, key, keylen); copy[keylen] = '\0'; + /* Is there a length limit or whatnot? */ + if (!islower((u_char) *copy) && *copy != '?') { + while (*copy != ':' && *copy != '\0') { + switch (*copy) { + case '=': + errno = 0; + limit = strtoul(copy + 1, &endptr, 10); + if (errno == ERANGE && limit == ULONG_MAX) + goto fail; + copy = endptr; + break; + default: + copy++; + break; + } + } + if (*copy != ':') + goto fail; + copy++; + } + /* * Is this a conditional? If so, check it exists and extract either the * first or second element. If not, look up the key directly. @@ -230,6 +254,10 @@ format_replace(struct format_tree *ft, } valuelen = strlen(value); + /* Truncate the value if needed. */ + if (valuelen > limit) + valuelen = limit; + /* Expand the buffer and copy in the value. */ while (*len - *off < valuelen + 1) { *buf = xrealloc(*buf, 2, *len); @@ -238,11 +266,11 @@ format_replace(struct format_tree *ft, memcpy(*buf + *off, value, valuelen); *off += valuelen; - free(copy); + free(copy0); return (0); fail: - free(copy); + free(copy0); return (-1); } diff --git a/options-table.c b/options-table.c index 138a307e..a62d38b2 100644 --- a/options-table.c +++ b/options-table.c @@ -387,7 +387,7 @@ const struct options_table_entry session_options_table[] = { { .name = "status-right", .type = OPTIONS_TABLE_STRING, - .default_str = "\"#22T\" %H:%M %d-%b-%y" + .default_str = "\"#{=22:pane_title}\" %H:%M %d-%b-%y" }, { .name = "status-right-attr", diff --git a/tmux.1 b/tmux.1 index fe2b1765..1f886cf7 100644 --- a/tmux.1 +++ b/tmux.1 @@ -3024,6 +3024,12 @@ will include the string if the session is attached and the string .Ql not attached if it is unattached. +A limit may be placed on the length of the resultant string by prefixing it +by an +.Ql = , +a number and a colon, so +.Ql #{=10:pane_title} +will include at most the first 10 characters of the pane title. .Pp The following variables are available, where appropriate: .Bl -column "XXXXXXXXXXXXXXXXXXX" "XXXXX" From 2bf2f5d58ee060068e915873a191a1d0d6e5c18f Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Oct 2013 11:50:36 +0000 Subject: [PATCH 14/47] Allow nested format expansion. --- format.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/format.c b/format.c index 72e42ba0..1b460855 100644 --- a/format.c +++ b/format.c @@ -193,7 +193,7 @@ int format_replace(struct format_tree *ft, const char *key, size_t keylen, char **buf, size_t *len, size_t *off) { - char *copy, *copy0, *endptr, *ptr; + char *copy, *copy0, *endptr, *ptr, *saved; const char *value; size_t valuelen; u_long limit = ULONG_MAX; @@ -247,10 +247,13 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen, goto fail; value = ptr + 1; } + saved = format_expand(ft, value); + value = saved; } else { value = format_find(ft, copy); if (value == NULL) value = ""; + saved = NULL; } valuelen = strlen(value); @@ -266,6 +269,7 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen, memcpy(*buf + *off, value, valuelen); *off += valuelen; + free(saved); free(copy0); return (0); @@ -278,10 +282,10 @@ fail: char * format_expand(struct format_tree *ft, const char *fmt) { - char *buf, *ptr; - const char *s; + char *buf; + const char *ptr, *s; size_t off, len, n; - int ch; + int ch, brackets; len = 64; buf = xmalloc(len); @@ -299,11 +303,16 @@ format_expand(struct format_tree *ft, const char *fmt) fmt++; ch = (u_char) *fmt++; - switch (ch) { case '{': - ptr = strchr(fmt, '}'); - if (ptr == NULL) + brackets = 1; + for (ptr = fmt; *ptr != '\0'; ptr++) { + if (*ptr == '{') + brackets++; + if (*ptr == '}' && --brackets == 0) + break; + } + if (*ptr != '}' || brackets != 0) break; n = ptr - fmt; From fd1750af490f837405eb688ed82b3f8b18d29e26 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Oct 2013 11:56:50 +0000 Subject: [PATCH 15/47] Add automatic-rename-format option allowing automatic rename to use something other than pane_current_command. --- names.c | 58 ++++++++++++++++++++----------------------------- options-table.c | 5 +++++ 2 files changed, 28 insertions(+), 35 deletions(-) diff --git a/names.c b/names.c index 76dec82c..cfdaff83 100644 --- a/names.c +++ b/names.c @@ -22,12 +22,10 @@ #include #include #include -#include #include "tmux.h" void window_name_callback(unused int, unused short, void *); -char *parse_window_name(const char *); void queue_window_name(struct window *w) @@ -47,7 +45,7 @@ void window_name_callback(unused int fd, unused short events, void *data) { struct window *w = data; - char *name, *wname; + char *name; if (w->active == NULL) return; @@ -59,49 +57,39 @@ window_name_callback(unused int fd, unused short events, void *data) } queue_window_name(w); - if (w->active->screen != &w->active->base) - name = NULL; - else - name = get_proc_name(w->active->fd, w->active->tty); - if (name == NULL) - wname = default_window_name(w); - else { - /* - * If tmux is using the default command, it will be a login - * shell and argv[0] may have a - prefix. Remove this if it is - * present. Ick. - */ - if (w->active->cmd != NULL && *w->active->cmd == '\0' && - name != NULL && name[0] == '-' && name[1] != '\0') - wname = parse_window_name(name + 1); - else - wname = parse_window_name(name); - free(name); - } - - if (w->active->fd == -1) { - xasprintf(&name, "%s[dead]", wname); - free(wname); - wname = name; - } - - if (strcmp(wname, w->name)) { - window_set_name(w, wname); + name = format_window_name(w); + if (strcmp(name, w->name) != 0) { + window_set_name(w, name); server_status_window(w); } - free(wname); + free(name); } char * default_window_name(struct window *w) { - if (w->active->screen != &w->active->base) - return (xstrdup("[tmux]")); if (w->active->cmd != NULL && *w->active->cmd != '\0') return (parse_window_name(w->active->cmd)); return (parse_window_name(w->active->shell)); } +char * +format_window_name(struct window *w) +{ + struct format_tree *ft; + char *fmt, *name; + + ft = format_create(); + format_window(ft, w); + format_window_pane(ft, w->active); + + fmt = options_get_string(&w->options, "automatic-rename-format"); + name = format_expand(ft, fmt); + + format_free(ft); + return (name); +} + char * parse_window_name(const char *in) { @@ -111,7 +99,7 @@ parse_window_name(const char *in) if (strncmp(name, "exec ", (sizeof "exec ") - 1) == 0) name = name + (sizeof "exec ") - 1; - while (*name == ' ') + while (*name == ' ' || *name == '-') name++; if ((ptr = strchr(name, ' ')) != NULL) *ptr = '\0'; diff --git a/options-table.c b/options-table.c index a62d38b2..22913854 100644 --- a/options-table.c +++ b/options-table.c @@ -482,6 +482,11 @@ const struct options_table_entry window_options_table[] = { .default_num = 1 }, + { .name = "automatic-rename-format", + .type = OPTIONS_TABLE_STRING, + .default_str = "#{?pane_in_mode,[tmux],#{pane_current_command}}#{?pane_dead,[dead],}" + }, + { .name = "c0-change-trigger", .type = OPTIONS_TABLE_NUMBER, .default_num = 250, From 81a548bcc4bf4e85935ce8ee65217b41d094d990 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Oct 2013 11:57:14 +0000 Subject: [PATCH 16/47] Accept multiple parameters to SM/RM/DECSET/DECRST, based on a diff from Hayaki Saito. --- input.c | 151 +++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 99 insertions(+), 52 deletions(-) diff --git a/input.c b/input.c index 5f70f872..e27250ed 100644 --- a/input.c +++ b/input.c @@ -70,6 +70,10 @@ int input_input(struct input_ctx *); int input_c0_dispatch(struct input_ctx *); int input_esc_dispatch(struct input_ctx *); int input_csi_dispatch(struct input_ctx *); +void input_csi_dispatch_rm(struct input_ctx *); +void input_csi_dispatch_rm_private(struct input_ctx *); +void input_csi_dispatch_sm(struct input_ctx *); +void input_csi_dispatch_sm_private(struct input_ctx *); void input_csi_dispatch_sgr(struct input_ctx *); int input_dcs_dispatch(struct input_ctx *); int input_utf8_open(struct input_ctx *); @@ -1071,7 +1075,6 @@ int input_csi_dispatch(struct input_ctx *ictx) { struct screen_write_ctx *sctx = &ictx->ctx; - struct window_pane *wp = ictx->wp; struct screen *s = sctx->s; struct input_table_entry *entry; int n, m; @@ -1230,7 +1233,60 @@ input_csi_dispatch(struct input_ctx *ictx) screen_write_cursormove(sctx, ictx->old_cx, ictx->old_cy); break; case INPUT_CSI_RM: - switch (input_get(ictx, 0, 0, -1)) { + input_csi_dispatch_rm(ictx); + break; + case INPUT_CSI_RM_PRIVATE: + input_csi_dispatch_rm_private(ictx); + break; + case INPUT_CSI_SCP: + memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell); + ictx->old_cx = s->cx; + ictx->old_cy = s->cy; + break; + case INPUT_CSI_SGR: + input_csi_dispatch_sgr(ictx); + break; + case INPUT_CSI_SM: + input_csi_dispatch_sm(ictx); + break; + case INPUT_CSI_SM_PRIVATE: + input_csi_dispatch_sm_private(ictx); + break; + case INPUT_CSI_TBC: + switch (input_get(ictx, 0, 0, 0)) { + case 0: + if (s->cx < screen_size_x(s)) + bit_clear(s->tabs, s->cx); + break; + case 3: + bit_nclear(s->tabs, 0, screen_size_x(s) - 1); + break; + default: + log_debug("%s: unknown '%c'", __func__, ictx->ch); + break; + } + break; + case INPUT_CSI_VPA: + n = input_get(ictx, 0, 1, 1); + screen_write_cursormove(sctx, s->cx, n - 1); + break; + case INPUT_CSI_DECSCUSR: + n = input_get(ictx, 0, 0, 0); + screen_set_cursor_style(s, n); + break; + } + + return (0); +} + +/* Handle CSI RM. */ +void +input_csi_dispatch_rm(struct input_ctx *ictx) +{ + u_int i; + + for (i = 0; i < ictx->param_list_len; i++) { + switch (input_get(ictx, i, 0, -1)) { case 4: /* IRM */ screen_write_mode_clear(&ictx->ctx, MODE_INSERT); break; @@ -1238,10 +1294,18 @@ input_csi_dispatch(struct input_ctx *ictx) log_debug("%s: unknown '%c'", __func__, ictx->ch); break; } - break; - case INPUT_CSI_RM_PRIVATE: - switch (input_get(ictx, 0, 0, -1)) { - case 1: /* GATM */ + } +} + +/* Handle CSI private RM. */ +void +input_csi_dispatch_rm_private(struct input_ctx *ictx) +{ + u_int i; + + for (i = 0; i < ictx->param_list_len; i++) { + switch (input_get(ictx, i, 0, -1)) { + case 1: /* DECCKM */ screen_write_mode_clear(&ictx->ctx, MODE_KCURSOR); break; case 3: /* DECCOLM */ @@ -1271,10 +1335,10 @@ input_csi_dispatch(struct input_ctx *ictx) break; case 47: case 1047: - window_pane_alternate_off(wp, &ictx->cell, 0); + window_pane_alternate_off(ictx->wp, &ictx->cell, 0); break; case 1049: - window_pane_alternate_off(wp, &ictx->cell, 1); + window_pane_alternate_off(ictx->wp, &ictx->cell, 1); break; case 2004: screen_write_mode_clear(&ictx->ctx, MODE_BRACKETPASTE); @@ -1283,17 +1347,17 @@ input_csi_dispatch(struct input_ctx *ictx) log_debug("%s: unknown '%c'", __func__, ictx->ch); break; } - break; - case INPUT_CSI_SCP: - memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell); - ictx->old_cx = s->cx; - ictx->old_cy = s->cy; - break; - case INPUT_CSI_SGR: - input_csi_dispatch_sgr(ictx); - break; - case INPUT_CSI_SM: - switch (input_get(ictx, 0, 0, -1)) { + } +} + +/* Handle CSI SM. */ +void +input_csi_dispatch_sm(struct input_ctx *ictx) +{ + u_int i; + + for (i = 0; i < ictx->param_list_len; i++) { + switch (input_get(ictx, i, 0, -1)) { case 4: /* IRM */ screen_write_mode_set(&ictx->ctx, MODE_INSERT); break; @@ -1301,10 +1365,18 @@ input_csi_dispatch(struct input_ctx *ictx) log_debug("%s: unknown '%c'", __func__, ictx->ch); break; } - break; - case INPUT_CSI_SM_PRIVATE: - switch (input_get(ictx, 0, 0, -1)) { - case 1: /* GATM */ + } +} + +/* Handle CSI private SM. */ +void +input_csi_dispatch_sm_private(struct input_ctx *ictx) +{ + u_int i; + + for (i = 0; i < ictx->param_list_len; i++) { + switch (input_get(ictx, i, 0, -1)) { + case 1: /* DECCKM */ screen_write_mode_set(&ictx->ctx, MODE_KCURSOR); break; case 3: /* DECCOLM */ @@ -1330,10 +1402,10 @@ input_csi_dispatch(struct input_ctx *ictx) screen_write_mode_set(&ictx->ctx, MODE_MOUSE_ANY); break; case 1004: - if (s->mode & MODE_FOCUSON) + if (ictx->ctx.s->mode & MODE_FOCUSON) break; screen_write_mode_set(&ictx->ctx, MODE_FOCUSON); - wp->flags |= PANE_FOCUSPUSH; /* force update */ + ictx->wp->flags |= PANE_FOCUSPUSH; /* force update */ break; case 1005: screen_write_mode_set(&ictx->ctx, MODE_MOUSE_UTF8); @@ -1343,10 +1415,10 @@ input_csi_dispatch(struct input_ctx *ictx) break; case 47: case 1047: - window_pane_alternate_on(wp, &ictx->cell, 0); + window_pane_alternate_on(ictx->wp, &ictx->cell, 0); break; case 1049: - window_pane_alternate_on(wp, &ictx->cell, 1); + window_pane_alternate_on(ictx->wp, &ictx->cell, 1); break; case 2004: screen_write_mode_set(&ictx->ctx, MODE_BRACKETPASTE); @@ -1355,32 +1427,7 @@ input_csi_dispatch(struct input_ctx *ictx) log_debug("%s: unknown '%c'", __func__, ictx->ch); break; } - break; - case INPUT_CSI_TBC: - switch (input_get(ictx, 0, 0, 0)) { - case 0: - if (s->cx < screen_size_x(s)) - bit_clear(s->tabs, s->cx); - break; - case 3: - bit_nclear(s->tabs, 0, screen_size_x(s) - 1); - break; - default: - log_debug("%s: unknown '%c'", __func__, ictx->ch); - break; - } - break; - case INPUT_CSI_VPA: - n = input_get(ictx, 0, 1, 1); - screen_write_cursormove(sctx, s->cx, n - 1); - break; - case INPUT_CSI_DECSCUSR: - n = input_get(ictx, 0, 0, 0); - screen_set_cursor_style(s, n); - break; } - - return (0); } /* Handle CSI SGR. */ From 784b711393f99523482515d7e6d0114f96f2ecec Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Oct 2013 11:57:52 +0000 Subject: [PATCH 17/47] Assign mouse x/y coords before checking them. When receiving mouse inputs, we should set the x/y coordinates earlier than we currently do, so that we aren't off-by-one in the case when the statusbar is at the top of the screen. By Thomas Adam. --- tty-keys.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tty-keys.c b/tty-keys.c index 3b652db8..7de5ce59 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -746,6 +746,8 @@ tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size) m->sgr = sgr; m->sgr_xb = sgr_b; m->sgr_rel = sgr_rel; + m->x = x; + m->y = y; if (b & 64) { /* wheel button */ b &= 3; if (b == 0) @@ -773,8 +775,6 @@ tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size) } m->button = (b & 3); } - m->x = x; - m->y = y; return (0); } From 34674bb180176662d51b774cfcd9f335f329f235 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Oct 2013 11:58:24 +0000 Subject: [PATCH 18/47] Renumber windows: Lookup lastw via window not index When calling 'movew -r' on a session to reorder the winlinks, ensure when adding back in the information for the lastw stack that we look up the winlink based on the window and not its index. Using the index doesn't make sense here because when comparing it to the old set, it will never match since the winlink has been renumbered. Bug reported by Ben Boeckel. Patch by Thomas Adam. --- session.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/session.c b/session.c index 7e144886..f967de19 100644 --- a/session.c +++ b/session.c @@ -616,7 +616,7 @@ session_renumber_windows(struct session *s) memcpy(&old_lastw, &s->lastw, sizeof old_lastw); TAILQ_INIT(&s->lastw); TAILQ_FOREACH(wl, &old_lastw, sentry) { - wl_new = winlink_find_by_index(&s->windows, wl->idx); + wl_new = winlink_find_by_window(&s->windows, wl->window); if (wl_new != NULL) TAILQ_INSERT_TAIL(&s->lastw, wl_new, sentry); } From e6af0ad23e1a43add71dd09a03c05057aab26748 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Oct 2013 11:58:52 +0000 Subject: [PATCH 19/47] choose-tree: Reset top when toggling items When choose-tree is told to expand/collapse items (especially when first rendering collapsed to just show sessions), ensure that in addition to setting the selected item, that the item itself appears on the bottom of the screen, rather than off screen. This was causing rendering glitches when a very small tmux window tried to render a list of items in choose-tree much larger than itself, and the selected item appeared off screen, and didn't show the selection until the selection had wrapped around to the top of the screen. --- window-choose.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/window-choose.c b/window-choose.c index 38773605..70c20085 100644 --- a/window-choose.c +++ b/window-choose.c @@ -81,6 +81,7 @@ int window_choose_key_index(struct window_choose_mode_data *, u_int); int window_choose_index_key(struct window_choose_mode_data *, int); void window_choose_prompt_input(enum window_choose_input_type, const char *, struct window_pane *, int); +void window_choose_reset_top(struct window_pane *, u_int); void window_choose_add(struct window_pane *wp, struct window_choose_data *wcd) @@ -107,8 +108,17 @@ window_choose_set_current(struct window_pane *wp, u_int cur) struct screen *s = &data->screen; data->selected = cur; - if (data->selected > screen_size_y(s) - 1) - data->top = ARRAY_LENGTH(&data->list) - screen_size_y(s); + window_choose_reset_top(wp, screen_size_y(s)); +} + +void +window_choose_reset_top(struct window_pane *wp, u_int sy) +{ + struct window_choose_mode_data *data = wp->modedata; + + data->top = 0; + if (data->selected > sy - 1) + data->top = data->selected - (sy - 1); window_choose_redraw_screen(wp); } @@ -277,10 +287,7 @@ window_choose_resize(struct window_pane *wp, u_int sx, u_int sy) struct window_choose_mode_data *data = wp->modedata; struct screen *s = &data->screen; - data->top = 0; - if (data->selected > sy - 1) - data->top = data->selected - (sy - 1); - + window_choose_reset_top(wp, sy); screen_resize(s, sx, sy, 0); window_choose_redraw_screen(wp); } @@ -373,6 +380,7 @@ window_choose_collapse_all(struct window_pane *wp) { struct window_choose_mode_data *data = wp->modedata; struct window_choose_mode_item *item; + struct screen *scr = &data->screen; struct session *s, *chosen; u_int i; @@ -391,7 +399,7 @@ window_choose_collapse_all(struct window_pane *wp) if (item->wcd->type & TREE_SESSION) data->selected = i; } - window_choose_redraw_screen(wp); + window_choose_reset_top(wp, screen_size_y(scr)); } void @@ -399,6 +407,7 @@ window_choose_expand_all(struct window_pane *wp) { struct window_choose_mode_data *data = wp->modedata; struct window_choose_mode_item *item; + struct screen *scr = &data->screen; struct session *s; u_int i; @@ -414,7 +423,7 @@ window_choose_expand_all(struct window_pane *wp) } } - window_choose_redraw_screen(wp); + window_choose_reset_top(wp, screen_size_y(scr)); } void From 90ae7682ed06557bd4d8deac9d9e48ecc7b38a07 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Oct 2013 11:59:23 +0000 Subject: [PATCH 20/47] Clear window->flags when clearing winlinks When clearing WINLINK_ALERTFLAGS for all sessions, we must also, for that window, clear the window->flags as well, otherwise sessions may well still see flags for winlinks long since cleared. This therefore introduces WINDOW_ALERTFLAGS to help with this. --- window.c | 1 + 1 file changed, 1 insertion(+) diff --git a/window.c b/window.c index 3b6b74bd..0ea70688 100644 --- a/window.c +++ b/window.c @@ -1242,6 +1242,7 @@ winlink_clear_flags(struct winlink *wl) continue; wm->flags &= ~WINLINK_ALERTFLAGS; + wm->window->flags &= ~WINDOW_ALERTFLAGS; server_status_session(s); } } From d45c12b6c9405da549197c2852ac124fc0d5b340 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Oct 2013 12:00:18 +0000 Subject: [PATCH 21/47] Remove the barely-used and unnecessary command check() function. --- cmd-bind-key.c | 27 ++++++++++++--------------- cmd-break-pane.c | 1 - cmd-capture-pane.c | 1 - cmd-choose-buffer.c | 1 - cmd-choose-client.c | 1 - cmd-choose-list.c | 1 - cmd-choose-tree.c | 4 ---- cmd-clear-history.c | 1 - cmd-clock-mode.c | 1 - cmd-command-prompt.c | 2 -- cmd-confirm-before.c | 1 - cmd-copy-mode.c | 1 - cmd-delete-buffer.c | 1 - cmd-detach-client.c | 1 - cmd-display-panes.c | 1 - cmd-find-window.c | 1 - cmd-has-session.c | 1 - cmd-join-pane.c | 2 -- cmd-kill-pane.c | 1 - cmd-kill-server.c | 1 - cmd-kill-session.c | 1 - cmd-kill-window.c | 1 - cmd-link-window.c | 1 - cmd-list-buffers.c | 1 - cmd-list-clients.c | 1 - cmd-list-commands.c | 1 - cmd-list-keys.c | 1 - cmd-list-panes.c | 1 - cmd-list-sessions.c | 1 - cmd-list-windows.c | 1 - cmd-load-buffer.c | 1 - cmd-lock-server.c | 3 --- cmd-move-window.c | 1 - cmd-paste-buffer.c | 1 - cmd-pipe-pane.c | 1 - cmd-refresh-client.c | 1 - cmd-rename-session.c | 1 - cmd-rename-window.c | 1 - cmd-resize-pane.c | 1 - cmd-respawn-pane.c | 1 - cmd-respawn-window.c | 1 - cmd-rotate-window.c | 1 - cmd-run-shell.c | 1 - cmd-save-buffer.c | 2 -- cmd-select-layout.c | 3 --- cmd-select-pane.c | 2 -- cmd-select-window.c | 4 ---- cmd-send-keys.c | 2 -- cmd-server-info.c | 1 - cmd-set-buffer.c | 1 - cmd-set-environment.c | 1 - cmd-set-option.c | 2 -- cmd-show-environment.c | 1 - cmd-show-messages.c | 1 - cmd-show-options.c | 2 -- cmd-start-server.c | 1 - cmd-suspend-client.c | 1 - cmd-swap-pane.c | 1 - cmd-swap-window.c | 1 - cmd-switch-client.c | 1 - cmd-unbind-key.c | 24 +++++++++++------------- cmd-unlink-window.c | 1 - 62 files changed, 23 insertions(+), 105 deletions(-) diff --git a/cmd-bind-key.c b/cmd-bind-key.c index d9b65bec..1ca31484 100644 --- a/cmd-bind-key.c +++ b/cmd-bind-key.c @@ -27,7 +27,6 @@ * Bind a key to a command, this recurses through cmd_*. */ -enum cmd_retval cmd_bind_key_check(struct args *); enum cmd_retval cmd_bind_key_exec(struct cmd *, struct cmd_q *); enum cmd_retval cmd_bind_key_table(struct cmd *, struct cmd_q *, int); @@ -38,23 +37,9 @@ const struct cmd_entry cmd_bind_key_entry = { "[-cnr] [-t key-table] key command [arguments]", 0, NULL, - cmd_bind_key_check, cmd_bind_key_exec }; -enum cmd_retval -cmd_bind_key_check(struct args *args) -{ - if (args_has(args, 't')) { - if (args->argc != 2 && args->argc != 3) - return (CMD_RETURN_ERROR); - } else { - if (args->argc < 2) - return (CMD_RETURN_ERROR); - } - return (CMD_RETURN_NORMAL); -} - enum cmd_retval cmd_bind_key_exec(struct cmd *self, struct cmd_q *cmdq) { @@ -63,6 +48,18 @@ cmd_bind_key_exec(struct cmd *self, struct cmd_q *cmdq) struct cmd_list *cmdlist; int key; + if (args_has(args, 't')) { + if (args->argc != 2 && args->argc != 3) { + cmdq_error(cmdq, "not enough arguments"); + return (CMD_RETURN_ERROR); + } + } else { + if (args->argc < 2) { + cmdq_error(cmdq, "not enough arguments"); + return (CMD_RETURN_ERROR); + } + } + key = key_string_lookup_string(args->argv[0]); if (key == KEYC_NONE) { cmdq_error(cmdq, "unknown key: %s", args->argv[0]); diff --git a/cmd-break-pane.c b/cmd-break-pane.c index bac332a2..defd22ec 100644 --- a/cmd-break-pane.c +++ b/cmd-break-pane.c @@ -34,7 +34,6 @@ const struct cmd_entry cmd_break_pane_entry = { "[-dP] [-F format] " CMD_TARGET_PANE_USAGE, 0, NULL, - NULL, cmd_break_pane_exec }; diff --git a/cmd-capture-pane.c b/cmd-capture-pane.c index 779cbe08..cf9a2f49 100644 --- a/cmd-capture-pane.c +++ b/cmd-capture-pane.c @@ -42,7 +42,6 @@ const struct cmd_entry cmd_capture_pane_entry = { CMD_TARGET_PANE_USAGE, 0, NULL, - NULL, cmd_capture_pane_exec }; diff --git a/cmd-choose-buffer.c b/cmd-choose-buffer.c index 8713815d..359de068 100644 --- a/cmd-choose-buffer.c +++ b/cmd-choose-buffer.c @@ -35,7 +35,6 @@ const struct cmd_entry cmd_choose_buffer_entry = { CMD_TARGET_WINDOW_USAGE " [-F format] [template]", 0, NULL, - NULL, cmd_choose_buffer_exec }; diff --git a/cmd-choose-client.c b/cmd-choose-client.c index df57f9cf..47ff1976 100644 --- a/cmd-choose-client.c +++ b/cmd-choose-client.c @@ -37,7 +37,6 @@ const struct cmd_entry cmd_choose_client_entry = { CMD_TARGET_WINDOW_USAGE " [-F format] [template]", 0, NULL, - NULL, cmd_choose_client_exec }; diff --git a/cmd-choose-list.c b/cmd-choose-list.c index 15f87294..c3caabba 100644 --- a/cmd-choose-list.c +++ b/cmd-choose-list.c @@ -39,7 +39,6 @@ const struct cmd_entry cmd_choose_list_entry = { "[-l items] " CMD_TARGET_WINDOW_USAGE "[template]", 0, NULL, - NULL, cmd_choose_list_exec }; diff --git a/cmd-choose-tree.c b/cmd-choose-tree.c index 601d24f1..257908e1 100644 --- a/cmd-choose-tree.c +++ b/cmd-choose-tree.c @@ -41,7 +41,6 @@ const struct cmd_entry cmd_choose_tree_entry = { "[-W format] " CMD_TARGET_WINDOW_USAGE, 0, NULL, - NULL, cmd_choose_tree_exec }; @@ -51,7 +50,6 @@ const struct cmd_entry cmd_choose_session_entry = { CMD_TARGET_WINDOW_USAGE " [-F format] [template]", 0, NULL, - NULL, cmd_choose_tree_exec }; @@ -61,7 +59,6 @@ const struct cmd_entry cmd_choose_window_entry = { CMD_TARGET_WINDOW_USAGE "[-F format] [template]", 0, NULL, - NULL, cmd_choose_tree_exec }; @@ -228,7 +225,6 @@ windows_only: free(final_win_template_last); window_choose_ready(wl->window->active, cur_win, NULL); - window_choose_collapse_all(wl->window->active); if (args_has(args, 'u')) { window_choose_expand_all(wl->window->active); diff --git a/cmd-clear-history.c b/cmd-clear-history.c index 768ba86d..69885f08 100644 --- a/cmd-clear-history.c +++ b/cmd-clear-history.c @@ -32,7 +32,6 @@ const struct cmd_entry cmd_clear_history_entry = { CMD_TARGET_PANE_USAGE, 0, NULL, - NULL, cmd_clear_history_exec }; diff --git a/cmd-clock-mode.c b/cmd-clock-mode.c index b1837004..09f16e17 100644 --- a/cmd-clock-mode.c +++ b/cmd-clock-mode.c @@ -32,7 +32,6 @@ const struct cmd_entry cmd_clock_mode_entry = { CMD_TARGET_PANE_USAGE, 0, NULL, - NULL, cmd_clock_mode_exec }; diff --git a/cmd-command-prompt.c b/cmd-command-prompt.c index 3b773316..fc625f53 100644 --- a/cmd-command-prompt.c +++ b/cmd-command-prompt.c @@ -30,7 +30,6 @@ */ void cmd_command_prompt_key_binding(struct cmd *, int); -int cmd_command_prompt_check(struct args *); enum cmd_retval cmd_command_prompt_exec(struct cmd *, struct cmd_q *); int cmd_command_prompt_callback(void *, const char *); @@ -42,7 +41,6 @@ const struct cmd_entry cmd_command_prompt_entry = { "[-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE " [template]", 0, cmd_command_prompt_key_binding, - NULL, cmd_command_prompt_exec }; diff --git a/cmd-confirm-before.c b/cmd-confirm-before.c index 6282be2e..5b8151c9 100644 --- a/cmd-confirm-before.c +++ b/cmd-confirm-before.c @@ -38,7 +38,6 @@ const struct cmd_entry cmd_confirm_before_entry = { "[-p prompt] " CMD_TARGET_CLIENT_USAGE " command", 0, cmd_confirm_before_key_binding, - NULL, cmd_confirm_before_exec }; diff --git a/cmd-copy-mode.c b/cmd-copy-mode.c index 883a9376..bc9cfd62 100644 --- a/cmd-copy-mode.c +++ b/cmd-copy-mode.c @@ -33,7 +33,6 @@ const struct cmd_entry cmd_copy_mode_entry = { "[-u] " CMD_TARGET_PANE_USAGE, 0, cmd_copy_mode_key_binding, - NULL, cmd_copy_mode_exec }; diff --git a/cmd-delete-buffer.c b/cmd-delete-buffer.c index 6e425b57..32fb243b 100644 --- a/cmd-delete-buffer.c +++ b/cmd-delete-buffer.c @@ -34,7 +34,6 @@ const struct cmd_entry cmd_delete_buffer_entry = { CMD_BUFFER_USAGE, 0, NULL, - NULL, cmd_delete_buffer_exec }; diff --git a/cmd-detach-client.c b/cmd-detach-client.c index 17b437ab..fc80499c 100644 --- a/cmd-detach-client.c +++ b/cmd-detach-client.c @@ -32,7 +32,6 @@ const struct cmd_entry cmd_detach_client_entry = { "[-P] [-a] [-s target-session] " CMD_TARGET_CLIENT_USAGE, CMD_READONLY, NULL, - NULL, cmd_detach_client_exec }; diff --git a/cmd-display-panes.c b/cmd-display-panes.c index a97a1809..9160f4e7 100644 --- a/cmd-display-panes.c +++ b/cmd-display-panes.c @@ -32,7 +32,6 @@ const struct cmd_entry cmd_display_panes_entry = { CMD_TARGET_CLIENT_USAGE, 0, NULL, - NULL, cmd_display_panes_exec }; diff --git a/cmd-find-window.c b/cmd-find-window.c index f757d10f..45dbd571 100644 --- a/cmd-find-window.c +++ b/cmd-find-window.c @@ -48,7 +48,6 @@ const struct cmd_entry cmd_find_window_entry = { "[-CNT] [-F format] " CMD_TARGET_WINDOW_USAGE " match-string", 0, NULL, - NULL, cmd_find_window_exec }; diff --git a/cmd-has-session.c b/cmd-has-session.c index 28e3aea3..d7ef9be6 100644 --- a/cmd-has-session.c +++ b/cmd-has-session.c @@ -32,7 +32,6 @@ const struct cmd_entry cmd_has_session_entry = { CMD_TARGET_SESSION_USAGE, 0, NULL, - NULL, cmd_has_session_exec }; diff --git a/cmd-join-pane.c b/cmd-join-pane.c index cf17e7d9..b70f93dc 100644 --- a/cmd-join-pane.c +++ b/cmd-join-pane.c @@ -40,7 +40,6 @@ const struct cmd_entry cmd_join_pane_entry = { "[-bdhv] [-p percentage|-l size] [-s src-pane] [-t dst-pane]", 0, cmd_join_pane_key_binding, - NULL, cmd_join_pane_exec }; @@ -50,7 +49,6 @@ const struct cmd_entry cmd_move_pane_entry = { "[-bdhv] [-p percentage|-l size] [-s src-pane] [-t dst-pane]", 0, NULL, - NULL, cmd_join_pane_exec }; diff --git a/cmd-kill-pane.c b/cmd-kill-pane.c index ba3bfd20..64fd11e4 100644 --- a/cmd-kill-pane.c +++ b/cmd-kill-pane.c @@ -34,7 +34,6 @@ const struct cmd_entry cmd_kill_pane_entry = { "[-a] " CMD_TARGET_PANE_USAGE, 0, NULL, - NULL, cmd_kill_pane_exec }; diff --git a/cmd-kill-server.c b/cmd-kill-server.c index 808dca59..ef4a3946 100644 --- a/cmd-kill-server.c +++ b/cmd-kill-server.c @@ -35,7 +35,6 @@ const struct cmd_entry cmd_kill_server_entry = { "", 0, NULL, - NULL, cmd_kill_server_exec }; diff --git a/cmd-kill-session.c b/cmd-kill-session.c index 095fb9bb..097189ec 100644 --- a/cmd-kill-session.c +++ b/cmd-kill-session.c @@ -35,7 +35,6 @@ const struct cmd_entry cmd_kill_session_entry = { "[-a] " CMD_TARGET_SESSION_USAGE, 0, NULL, - NULL, cmd_kill_session_exec }; diff --git a/cmd-kill-window.c b/cmd-kill-window.c index dcb1fd28..2f924260 100644 --- a/cmd-kill-window.c +++ b/cmd-kill-window.c @@ -32,7 +32,6 @@ const struct cmd_entry cmd_kill_window_entry = { "[-a] " CMD_TARGET_WINDOW_USAGE, 0, NULL, - NULL, cmd_kill_window_exec }; diff --git a/cmd-link-window.c b/cmd-link-window.c index c7dfa5aa..8bd63b7c 100644 --- a/cmd-link-window.c +++ b/cmd-link-window.c @@ -34,7 +34,6 @@ const struct cmd_entry cmd_link_window_entry = { "[-dk] " CMD_SRCDST_WINDOW_USAGE, 0, NULL, - NULL, cmd_link_window_exec }; diff --git a/cmd-list-buffers.c b/cmd-list-buffers.c index 54284d55..e36a7cd0 100644 --- a/cmd-list-buffers.c +++ b/cmd-list-buffers.c @@ -35,7 +35,6 @@ const struct cmd_entry cmd_list_buffers_entry = { "[-F format]", 0, NULL, - NULL, cmd_list_buffers_exec }; diff --git a/cmd-list-clients.c b/cmd-list-clients.c index e0f8558e..98c564ad 100644 --- a/cmd-list-clients.c +++ b/cmd-list-clients.c @@ -36,7 +36,6 @@ const struct cmd_entry cmd_list_clients_entry = { "[-F format] " CMD_TARGET_SESSION_USAGE, CMD_READONLY, NULL, - NULL, cmd_list_clients_exec }; diff --git a/cmd-list-commands.c b/cmd-list-commands.c index 7073d5f8..287df428 100644 --- a/cmd-list-commands.c +++ b/cmd-list-commands.c @@ -32,7 +32,6 @@ const struct cmd_entry cmd_list_commands_entry = { "", 0, NULL, - NULL, cmd_list_commands_exec }; diff --git a/cmd-list-keys.c b/cmd-list-keys.c index 1f568909..65e4469e 100644 --- a/cmd-list-keys.c +++ b/cmd-list-keys.c @@ -35,7 +35,6 @@ const struct cmd_entry cmd_list_keys_entry = { "[-t key-table]", 0, NULL, - NULL, cmd_list_keys_exec }; diff --git a/cmd-list-panes.c b/cmd-list-panes.c index 910c19bc..07884ff2 100644 --- a/cmd-list-panes.c +++ b/cmd-list-panes.c @@ -41,7 +41,6 @@ const struct cmd_entry cmd_list_panes_entry = { "[-as] [-F format] " CMD_TARGET_WINDOW_USAGE, 0, NULL, - NULL, cmd_list_panes_exec }; diff --git a/cmd-list-sessions.c b/cmd-list-sessions.c index 14ac4808..d401608f 100644 --- a/cmd-list-sessions.c +++ b/cmd-list-sessions.c @@ -36,7 +36,6 @@ const struct cmd_entry cmd_list_sessions_entry = { "[-F format]", 0, NULL, - NULL, cmd_list_sessions_exec }; diff --git a/cmd-list-windows.c b/cmd-list-windows.c index c709e471..bc56816f 100644 --- a/cmd-list-windows.c +++ b/cmd-list-windows.c @@ -39,7 +39,6 @@ const struct cmd_entry cmd_list_windows_entry = { "[-a] [-F format] " CMD_TARGET_SESSION_USAGE, 0, NULL, - NULL, cmd_list_windows_exec }; diff --git a/cmd-load-buffer.c b/cmd-load-buffer.c index 698210d8..8c92ca32 100644 --- a/cmd-load-buffer.c +++ b/cmd-load-buffer.c @@ -39,7 +39,6 @@ const struct cmd_entry cmd_load_buffer_entry = { CMD_BUFFER_USAGE " path", 0, NULL, - NULL, cmd_load_buffer_exec }; diff --git a/cmd-lock-server.c b/cmd-lock-server.c index 8491c8b1..97c86c1e 100644 --- a/cmd-lock-server.c +++ b/cmd-lock-server.c @@ -36,7 +36,6 @@ const struct cmd_entry cmd_lock_server_entry = { "", 0, NULL, - NULL, cmd_lock_server_exec }; @@ -46,7 +45,6 @@ const struct cmd_entry cmd_lock_session_entry = { CMD_TARGET_SESSION_USAGE, 0, NULL, - NULL, cmd_lock_server_exec }; @@ -56,7 +54,6 @@ const struct cmd_entry cmd_lock_client_entry = { CMD_TARGET_CLIENT_USAGE, 0, NULL, - NULL, cmd_lock_server_exec }; diff --git a/cmd-move-window.c b/cmd-move-window.c index 945e9daa..bb160e5c 100644 --- a/cmd-move-window.c +++ b/cmd-move-window.c @@ -34,7 +34,6 @@ const struct cmd_entry cmd_move_window_entry = { "[-dkr] " CMD_SRCDST_WINDOW_USAGE, 0, NULL, - NULL, cmd_move_window_exec }; diff --git a/cmd-paste-buffer.c b/cmd-paste-buffer.c index 1cfc17c8..8f7530a2 100644 --- a/cmd-paste-buffer.c +++ b/cmd-paste-buffer.c @@ -39,7 +39,6 @@ const struct cmd_entry cmd_paste_buffer_entry = { "[-dpr] [-s separator] [-b buffer-index] " CMD_TARGET_PANE_USAGE, 0, NULL, - NULL, cmd_paste_buffer_exec }; diff --git a/cmd-pipe-pane.c b/cmd-pipe-pane.c index 5de675df..9b29e568 100644 --- a/cmd-pipe-pane.c +++ b/cmd-pipe-pane.c @@ -42,7 +42,6 @@ const struct cmd_entry cmd_pipe_pane_entry = { "[-o] " CMD_TARGET_PANE_USAGE " [command]", 0, NULL, - NULL, cmd_pipe_pane_exec }; diff --git a/cmd-refresh-client.c b/cmd-refresh-client.c index e95e1ea3..d3dae49d 100644 --- a/cmd-refresh-client.c +++ b/cmd-refresh-client.c @@ -32,7 +32,6 @@ const struct cmd_entry cmd_refresh_client_entry = { "[-S] [-C size] " CMD_TARGET_CLIENT_USAGE, 0, NULL, - NULL, cmd_refresh_client_exec }; diff --git a/cmd-rename-session.c b/cmd-rename-session.c index c94b460b..ba8f9588 100644 --- a/cmd-rename-session.c +++ b/cmd-rename-session.c @@ -34,7 +34,6 @@ const struct cmd_entry cmd_rename_session_entry = { CMD_TARGET_SESSION_USAGE " new-name", 0, NULL, - NULL, cmd_rename_session_exec }; diff --git a/cmd-rename-window.c b/cmd-rename-window.c index 34b03f98..bdd3fbef 100644 --- a/cmd-rename-window.c +++ b/cmd-rename-window.c @@ -34,7 +34,6 @@ const struct cmd_entry cmd_rename_window_entry = { CMD_TARGET_WINDOW_USAGE " new-name", 0, NULL, - NULL, cmd_rename_window_exec }; diff --git a/cmd-resize-pane.c b/cmd-resize-pane.c index 41c15269..e54c0760 100644 --- a/cmd-resize-pane.c +++ b/cmd-resize-pane.c @@ -35,7 +35,6 @@ const struct cmd_entry cmd_resize_pane_entry = { "[-DLRUZ] [-x width] [-y height] " CMD_TARGET_PANE_USAGE " [adjustment]", 0, cmd_resize_pane_key_binding, - NULL, cmd_resize_pane_exec }; diff --git a/cmd-respawn-pane.c b/cmd-respawn-pane.c index 0aae0331..2315b241 100644 --- a/cmd-respawn-pane.c +++ b/cmd-respawn-pane.c @@ -36,7 +36,6 @@ const struct cmd_entry cmd_respawn_pane_entry = { "[-k] " CMD_TARGET_PANE_USAGE " [command]", 0, NULL, - NULL, cmd_respawn_pane_exec }; diff --git a/cmd-respawn-window.c b/cmd-respawn-window.c index a446794b..e4ef6dfb 100644 --- a/cmd-respawn-window.c +++ b/cmd-respawn-window.c @@ -35,7 +35,6 @@ const struct cmd_entry cmd_respawn_window_entry = { "[-k] " CMD_TARGET_WINDOW_USAGE " [command]", 0, NULL, - NULL, cmd_respawn_window_exec }; diff --git a/cmd-rotate-window.c b/cmd-rotate-window.c index 7af592b3..6005ae5d 100644 --- a/cmd-rotate-window.c +++ b/cmd-rotate-window.c @@ -33,7 +33,6 @@ const struct cmd_entry cmd_rotate_window_entry = { "[-DU] " CMD_TARGET_WINDOW_USAGE, 0, cmd_rotate_window_key_binding, - NULL, cmd_rotate_window_exec }; diff --git a/cmd-run-shell.c b/cmd-run-shell.c index ef1dbdd4..d835e461 100644 --- a/cmd-run-shell.c +++ b/cmd-run-shell.c @@ -41,7 +41,6 @@ const struct cmd_entry cmd_run_shell_entry = { "[-b] " CMD_TARGET_PANE_USAGE " shell-command", 0, NULL, - NULL, cmd_run_shell_exec }; diff --git a/cmd-save-buffer.c b/cmd-save-buffer.c index 29f71837..57c3d65d 100644 --- a/cmd-save-buffer.c +++ b/cmd-save-buffer.c @@ -38,7 +38,6 @@ const struct cmd_entry cmd_save_buffer_entry = { "[-a] " CMD_BUFFER_USAGE " path", 0, NULL, - NULL, cmd_save_buffer_exec }; @@ -48,7 +47,6 @@ const struct cmd_entry cmd_show_buffer_entry = { CMD_BUFFER_USAGE, 0, NULL, - NULL, cmd_save_buffer_exec }; diff --git a/cmd-select-layout.c b/cmd-select-layout.c index aa73e500..26d8538e 100644 --- a/cmd-select-layout.c +++ b/cmd-select-layout.c @@ -33,7 +33,6 @@ const struct cmd_entry cmd_select_layout_entry = { "[-np] " CMD_TARGET_WINDOW_USAGE " [layout-name]", 0, cmd_select_layout_key_binding, - NULL, cmd_select_layout_exec }; @@ -43,7 +42,6 @@ const struct cmd_entry cmd_next_layout_entry = { CMD_TARGET_WINDOW_USAGE, 0, NULL, - NULL, cmd_select_layout_exec }; @@ -53,7 +51,6 @@ const struct cmd_entry cmd_previous_layout_entry = { CMD_TARGET_WINDOW_USAGE, 0, NULL, - NULL, cmd_select_layout_exec }; diff --git a/cmd-select-pane.c b/cmd-select-pane.c index 77be368f..1a1072d8 100644 --- a/cmd-select-pane.c +++ b/cmd-select-pane.c @@ -33,7 +33,6 @@ const struct cmd_entry cmd_select_pane_entry = { "[-lDLRU] " CMD_TARGET_PANE_USAGE, 0, cmd_select_pane_key_binding, - NULL, cmd_select_pane_exec }; @@ -43,7 +42,6 @@ const struct cmd_entry cmd_last_pane_entry = { CMD_TARGET_WINDOW_USAGE, 0, NULL, - NULL, cmd_select_pane_exec }; diff --git a/cmd-select-window.c b/cmd-select-window.c index 6206ae4b..744bdf77 100644 --- a/cmd-select-window.c +++ b/cmd-select-window.c @@ -35,7 +35,6 @@ const struct cmd_entry cmd_select_window_entry = { "[-lnpT] " CMD_TARGET_WINDOW_USAGE, 0, cmd_select_window_key_binding, - NULL, cmd_select_window_exec }; @@ -45,7 +44,6 @@ const struct cmd_entry cmd_next_window_entry = { "[-a] " CMD_TARGET_SESSION_USAGE, 0, cmd_select_window_key_binding, - NULL, cmd_select_window_exec }; @@ -55,7 +53,6 @@ const struct cmd_entry cmd_previous_window_entry = { "[-a] " CMD_TARGET_SESSION_USAGE, 0, cmd_select_window_key_binding, - NULL, cmd_select_window_exec }; @@ -65,7 +62,6 @@ const struct cmd_entry cmd_last_window_entry = { CMD_TARGET_SESSION_USAGE, 0, NULL, - NULL, cmd_select_window_exec }; diff --git a/cmd-send-keys.c b/cmd-send-keys.c index dcd5f288..ef61d2bb 100644 --- a/cmd-send-keys.c +++ b/cmd-send-keys.c @@ -35,7 +35,6 @@ const struct cmd_entry cmd_send_keys_entry = { "[-lR] " CMD_TARGET_PANE_USAGE " key ...", 0, NULL, - NULL, cmd_send_keys_exec }; @@ -45,7 +44,6 @@ const struct cmd_entry cmd_send_prefix_entry = { "[-2] " CMD_TARGET_PANE_USAGE, 0, NULL, - NULL, cmd_send_keys_exec }; diff --git a/cmd-server-info.c b/cmd-server-info.c index 07b224a1..6cbabe2b 100644 --- a/cmd-server-info.c +++ b/cmd-server-info.c @@ -39,7 +39,6 @@ const struct cmd_entry cmd_server_info_entry = { "", 0, NULL, - NULL, cmd_server_info_exec }; diff --git a/cmd-set-buffer.c b/cmd-set-buffer.c index 46450e21..f67f7a0c 100644 --- a/cmd-set-buffer.c +++ b/cmd-set-buffer.c @@ -35,7 +35,6 @@ const struct cmd_entry cmd_set_buffer_entry = { CMD_BUFFER_USAGE " data", 0, NULL, - NULL, cmd_set_buffer_exec }; diff --git a/cmd-set-environment.c b/cmd-set-environment.c index 6e75a294..7a446fc6 100644 --- a/cmd-set-environment.c +++ b/cmd-set-environment.c @@ -35,7 +35,6 @@ const struct cmd_entry cmd_set_environment_entry = { "[-gru] " CMD_TARGET_SESSION_USAGE " name [value]", 0, NULL, - NULL, cmd_set_environment_exec }; diff --git a/cmd-set-option.c b/cmd-set-option.c index 3b822d8b..1b25fac0 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -67,7 +67,6 @@ const struct cmd_entry cmd_set_option_entry = { "[-agosquw] [-t target-session|target-window] option [value]", 0, NULL, - NULL, cmd_set_option_exec }; @@ -77,7 +76,6 @@ const struct cmd_entry cmd_set_window_option_entry = { "[-agoqu] " CMD_TARGET_WINDOW_USAGE " option [value]", 0, NULL, - NULL, cmd_set_option_exec }; diff --git a/cmd-show-environment.c b/cmd-show-environment.c index cb53e84c..4ba111b2 100644 --- a/cmd-show-environment.c +++ b/cmd-show-environment.c @@ -35,7 +35,6 @@ const struct cmd_entry cmd_show_environment_entry = { "[-g] " CMD_TARGET_SESSION_USAGE " [name]", 0, NULL, - NULL, cmd_show_environment_exec }; diff --git a/cmd-show-messages.c b/cmd-show-messages.c index cbf083a7..f43607aa 100644 --- a/cmd-show-messages.c +++ b/cmd-show-messages.c @@ -35,7 +35,6 @@ const struct cmd_entry cmd_show_messages_entry = { CMD_TARGET_CLIENT_USAGE, 0, NULL, - NULL, cmd_show_messages_exec }; diff --git a/cmd-show-options.c b/cmd-show-options.c index 57e49a33..529289ea 100644 --- a/cmd-show-options.c +++ b/cmd-show-options.c @@ -40,7 +40,6 @@ const struct cmd_entry cmd_show_options_entry = { "[-gqsvw] [-t target-session|target-window] [option]", 0, NULL, - NULL, cmd_show_options_exec }; @@ -50,7 +49,6 @@ const struct cmd_entry cmd_show_window_options_entry = { "[-gv] " CMD_TARGET_WINDOW_USAGE " [option]", 0, NULL, - NULL, cmd_show_options_exec }; diff --git a/cmd-start-server.c b/cmd-start-server.c index c926b5fe..d98f9506 100644 --- a/cmd-start-server.c +++ b/cmd-start-server.c @@ -32,7 +32,6 @@ const struct cmd_entry cmd_start_server_entry = { "", CMD_STARTSERVER, NULL, - NULL, cmd_start_server_exec }; diff --git a/cmd-suspend-client.c b/cmd-suspend-client.c index dda0f977..5d1e7fe2 100644 --- a/cmd-suspend-client.c +++ b/cmd-suspend-client.c @@ -35,7 +35,6 @@ const struct cmd_entry cmd_suspend_client_entry = { CMD_TARGET_CLIENT_USAGE, 0, NULL, - NULL, cmd_suspend_client_exec }; diff --git a/cmd-swap-pane.c b/cmd-swap-pane.c index e6b46d67..e8170bbb 100644 --- a/cmd-swap-pane.c +++ b/cmd-swap-pane.c @@ -35,7 +35,6 @@ const struct cmd_entry cmd_swap_pane_entry = { "[-dDU] " CMD_SRCDST_PANE_USAGE, 0, cmd_swap_pane_key_binding, - NULL, cmd_swap_pane_exec }; diff --git a/cmd-swap-window.c b/cmd-swap-window.c index ed175480..00bf6d4d 100644 --- a/cmd-swap-window.c +++ b/cmd-swap-window.c @@ -34,7 +34,6 @@ const struct cmd_entry cmd_swap_window_entry = { "[-d] " CMD_SRCDST_WINDOW_USAGE, 0, NULL, - NULL, cmd_swap_window_exec }; diff --git a/cmd-switch-client.c b/cmd-switch-client.c index ea5012ed..9db35365 100644 --- a/cmd-switch-client.c +++ b/cmd-switch-client.c @@ -36,7 +36,6 @@ const struct cmd_entry cmd_switch_client_entry = { "[-lnpr] [-c target-client] [-t target-session]", CMD_READONLY, cmd_switch_client_key_binding, - NULL, cmd_switch_client_exec }; diff --git a/cmd-unbind-key.c b/cmd-unbind-key.c index 88c81270..b89340da 100644 --- a/cmd-unbind-key.c +++ b/cmd-unbind-key.c @@ -26,7 +26,6 @@ * Unbind key from command. */ -enum cmd_retval cmd_unbind_key_check(struct args *); enum cmd_retval cmd_unbind_key_exec(struct cmd *, struct cmd_q *); enum cmd_retval cmd_unbind_key_table(struct cmd *, struct cmd_q *, int); @@ -36,20 +35,9 @@ const struct cmd_entry cmd_unbind_key_entry = { "[-acn] [-t key-table] key", 0, NULL, - cmd_unbind_key_check, cmd_unbind_key_exec }; -enum cmd_retval -cmd_unbind_key_check(struct args *args) -{ - if (args_has(args, 'a') && args->argc != 0) - return (CMD_RETURN_ERROR); - if (!args_has(args, 'a') && args->argc != 1) - return (CMD_RETURN_ERROR); - return (CMD_RETURN_NORMAL); -} - enum cmd_retval cmd_unbind_key_exec(struct cmd *self, struct cmd_q *cmdq) { @@ -58,13 +46,23 @@ cmd_unbind_key_exec(struct cmd *self, struct cmd_q *cmdq) int key; if (!args_has(args, 'a')) { + if (args->argc != 1) { + cmdq_error(cmdq, "missing key"); + return (CMD_RETURN_ERROR); + } + return (CMD_RETURN_ERROR); key = key_string_lookup_string(args->argv[0]); if (key == KEYC_NONE) { cmdq_error(cmdq, "unknown key: %s", args->argv[0]); return (CMD_RETURN_ERROR); } - } else + } else { + if (args->argc != 0) { + cmdq_error(cmdq, "key given with -a"); + return (CMD_RETURN_ERROR); + } key = KEYC_NONE; + } if (args_has(args, 't')) return (cmd_unbind_key_table(self, cmdq, key)); diff --git a/cmd-unlink-window.c b/cmd-unlink-window.c index 78c4b390..d4c77f2a 100644 --- a/cmd-unlink-window.c +++ b/cmd-unlink-window.c @@ -32,7 +32,6 @@ const struct cmd_entry cmd_unlink_window_entry = { "[-k] " CMD_TARGET_WINDOW_USAGE, 0, NULL, - NULL, cmd_unlink_window_exec }; From 1b7c2dd056f4e41f0cec38c1b8ed5531f7281e33 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Oct 2013 12:01:14 +0000 Subject: [PATCH 22/47] Trivial style and spacing nits. --- cmd-display-message.c | 7 +++---- grid.c | 7 +++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/cmd-display-message.c b/cmd-display-message.c index 52d47a4c..b60d732a 100644 --- a/cmd-display-message.c +++ b/cmd-display-message.c @@ -36,7 +36,6 @@ const struct cmd_entry cmd_display_message_entry = { " [message]", 0, NULL, - NULL, cmd_display_message_exec }; @@ -71,9 +70,9 @@ cmd_display_message_exec(struct cmd *self, struct cmd_q *cmdq) } if (args_has(args, 'c')) { - c = cmd_find_client(cmdq, args_get(args, 'c'), 0); - if (c == NULL) - return (CMD_RETURN_ERROR); + c = cmd_find_client(cmdq, args_get(args, 'c'), 0); + if (c == NULL) + return (CMD_RETURN_ERROR); } else { c = cmd_current_client(cmdq); if (c == NULL && !args_has(self->args, 'p')) { diff --git a/grid.c b/grid.c index b2ee0c69..d06e7154 100644 --- a/grid.c +++ b/grid.c @@ -268,8 +268,7 @@ grid_get_cell(struct grid *gd, u_int px, u_int py) /* Set cell at relative position. */ void -grid_set_cell( - struct grid *gd, u_int px, u_int py, const struct grid_cell *gc) +grid_set_cell(struct grid *gd, u_int px, u_int py, const struct grid_cell *gc) { if (grid_check_y(gd, py) != 0) return; @@ -657,8 +656,8 @@ grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx, * available. */ void -grid_duplicate_lines( - struct grid *dst, u_int dy, struct grid *src, u_int sy, u_int ny) +grid_duplicate_lines(struct grid *dst, u_int dy, struct grid *src, u_int sy, + u_int ny) { struct grid_line *dstl, *srcl; u_int yy; From 1bd0851ee852b305c48863b7701af74a171633e9 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Oct 2013 12:02:55 +0000 Subject: [PATCH 23/47] Mark flags as optional and mutually exclusive. From Tiago Cunha. --- cmd-wait-for.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cmd-wait-for.c b/cmd-wait-for.c index 3a8d8ea4..42c7f42d 100644 --- a/cmd-wait-for.c +++ b/cmd-wait-for.c @@ -33,10 +33,9 @@ enum cmd_retval cmd_wait_for_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_wait_for_entry = { "wait-for", "wait", "LSU", 1, 1, - "[-LSU] channel", + "[-L|-S|-U] channel", 0, NULL, - NULL, cmd_wait_for_exec }; From e4dc1568ce49120962d4932ff8417c60778a5a33 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Oct 2013 12:03:22 +0000 Subject: [PATCH 24/47] Don't treat TMUX_TMPDIR as a potential file The point of setting TMUX_TMPDIR is to then make any labels from -L go to that directory. In the case of makesocketpath() with no TMUX_TMPDIR set, would set both the path and the default socket to a file. The checking of the permissions on the file worked fine in that case, but when TMUX_TMPDIR is set, won't work on a directory. This fixes the problem by ensuring the check on the permissions is performed on directories only. By Thomas Adam. --- tmux.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tmux.c b/tmux.c index 73843a96..901ded80 100644 --- a/tmux.c +++ b/tmux.c @@ -189,7 +189,8 @@ makesocketpath(const char *label) errno = ENOTDIR; return (NULL); } - if (sb.st_uid != uid || (sb.st_mode & (S_IRWXG|S_IRWXO)) != 0) { + if (sb.st_uid != uid || (!S_ISDIR(sb.st_mode) && + sb.st_mode & (S_IRWXG|S_IRWXO)) != 0) { errno = EACCES; return (NULL); } @@ -389,7 +390,8 @@ main(int argc, char **argv) /* -L or default set. */ if (label != NULL) { if ((path = makesocketpath(label)) == NULL) { - fprintf(stderr, "can't create socket\n"); + fprintf(stderr, "can't create socket: %s\n", + strerror(errno)); exit(1); } } From 1a49ebaa9f5e5b90ebb27eb5acd0ff5653e34a46 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Oct 2013 12:04:01 +0000 Subject: [PATCH 25/47] First period not last for host_short, from Michael Scholz. --- format.c | 55 ++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 42 insertions(+), 13 deletions(-) diff --git a/format.c b/format.c index 1b460855..8f86eba3 100644 --- a/format.c +++ b/format.c @@ -34,9 +34,10 @@ * string. */ -int format_replace(struct format_tree *, const char *, size_t, char **, - size_t *, size_t *); -void format_window_pane_tabs(struct format_tree *, struct window_pane *); +int format_replace(struct format_tree *, const char *, size_t, char **, + size_t *, size_t *); +char *format_get_command(struct window_pane *); +void format_window_pane_tabs(struct format_tree *, struct window_pane *); /* Format key-value replacement entry. */ RB_GENERATE(format_tree, format_entry, entry, format_cmp); @@ -120,7 +121,7 @@ format_create(void) if (gethostname(host, sizeof host) == 0) { format_add(ft, "host", "%s", host); - if ((ptr = strrchr(host, '.')) != NULL) + if ((ptr = strchr(host, '.')) != NULL) *ptr = '\0'; format_add(ft, "host_short", "%s", host); } @@ -348,6 +349,21 @@ format_expand(struct format_tree *ft, const char *fmt) return (buf); } +/* Get command name for format. */ +char * +format_get_command(struct window_pane *wp) +{ + char *cmd; + + cmd = get_proc_name(wp->fd, wp->tty); + if (cmd == NULL || *cmd == '\0') { + cmd = wp->cmd; + if (cmd == NULL || *cmd == '\0') + cmd = wp->shell; + } + return (parse_window_name(cmd)); +} + /* Set default format keys for a session. */ void format_session(struct format_tree *ft, struct session *s) @@ -427,25 +443,38 @@ format_client(struct format_tree *ft, struct client *c) format_add(ft, "client_last_session", "%s", s->name); } +/* Set default format keys for a window. */ +void +format_window(struct format_tree *ft, struct window *w) +{ + char *layout; + + layout = layout_dump(w); + + format_add(ft, "window_id", "@%u", w->id); + format_add(ft, "window_name", "%s", w->name); + format_add(ft, "window_width", "%u", w->sx); + format_add(ft, "window_height", "%u", w->sy); + format_add(ft, "window_layout", "%s", layout); + format_add(ft, "window_panes", "%u", window_count_panes(w)); + + free(layout); +} + /* Set default format keys for a winlink. */ void format_winlink(struct format_tree *ft, struct session *s, struct winlink *wl) { struct window *w = wl->window; - char *layout, *flags; + char *flags; - layout = layout_dump(w); flags = window_printable_flags(s, wl); - format_add(ft, "window_id", "@%u", w->id); + format_window(ft, w); + format_add(ft, "window_index", "%d", wl->idx); - format_add(ft, "window_name", "%s", w->name); - format_add(ft, "window_width", "%u", w->sx); - format_add(ft, "window_height", "%u", w->sy); format_add(ft, "window_flags", "%s", flags); - format_add(ft, "window_layout", "%s", layout); format_add(ft, "window_active", "%d", wl == s->curw); - format_add(ft, "window_panes", "%u", window_count_panes(w)); format_add(ft, "window_bell_flag", "%u", !!(wl->flags & WINLINK_BELL)); @@ -456,8 +485,8 @@ format_winlink(struct format_tree *ft, struct session *s, struct winlink *wl) format_add(ft, "window_silence_flag", "%u", !!(wl->flags & WINLINK_SILENCE)); + free(flags); - free(layout); } /* Add window pane tabs. */ From fc54bfe6b0b5a9053fe967e87f55fbe684abc679 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Oct 2013 12:04:38 +0000 Subject: [PATCH 26/47] Make cmdq->client_exit a tristate (-1 means "not set") so that if explicitly set it can be copied from child to parent cmdq by if-shell and source-file. This fixes using attach or new. From Chris Johnsen. --- cmd-if-shell.c | 4 +++- cmd-source-file.c | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/cmd-if-shell.c b/cmd-if-shell.c index e810b0fc..4193944c 100644 --- a/cmd-if-shell.c +++ b/cmd-if-shell.c @@ -41,7 +41,6 @@ const struct cmd_entry cmd_if_shell_entry = { "[-b] " CMD_TARGET_PANE_USAGE " shell-command command [command]", 0, NULL, - NULL, cmd_if_shell_exec }; @@ -148,6 +147,9 @@ cmd_if_shell_done(struct cmd_q *cmdq1) struct cmd_if_shell_data *cdata = cmdq1->data; struct cmd_q *cmdq = cdata->cmdq; + if (cmdq1->client_exit >= 0) + cmdq->client_exit = cmdq1->client_exit; + if (!cmdq_free(cmdq) && !cdata->bflag) cmdq_continue(cmdq); diff --git a/cmd-source-file.c b/cmd-source-file.c index f50efbe3..8fcfe2f3 100644 --- a/cmd-source-file.c +++ b/cmd-source-file.c @@ -37,7 +37,6 @@ const struct cmd_entry cmd_source_file_entry = { "path", 0, NULL, - NULL, cmd_source_file_exec }; @@ -96,6 +95,9 @@ cmd_source_file_done(struct cmd_q *cmdq1) { struct cmd_q *cmdq = cmdq1->data; + if (cmdq1->client_exit >= 0) + cmdq->client_exit = cmdq1->client_exit; + cmdq_free(cmdq1); cfg_references--; From b822d24b15669a0b7d325e2a2f04959b05a3d4fb Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Oct 2013 12:07:36 +0000 Subject: [PATCH 27/47] Support -c for new-session, based on code from J Raynor. --- cmd-new-window.c | 3 +-- cmd-queue.c | 28 +++++++++++++++++++-- cmd-split-window.c | 3 +-- cmd.c | 61 +++++++++++++++++----------------------------- tmux.1 | 21 ++++++++++++---- 5 files changed, 67 insertions(+), 49 deletions(-) diff --git a/cmd-new-window.c b/cmd-new-window.c index eac0df44..e72a1196 100644 --- a/cmd-new-window.c +++ b/cmd-new-window.c @@ -35,7 +35,6 @@ const struct cmd_entry cmd_new_window_entry = { CMD_TARGET_WINDOW_USAGE " [command]", 0, NULL, - NULL, cmd_new_window_exec }; @@ -103,7 +102,7 @@ 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 = cmd_get_default_path(cmdq, args_get(args, 'c')); + cwd = cmdq_default_path(cmdq, args_get(args, 'c')); if (idx == -1) idx = -1 - options_get_number(&s->options, "base-index"); diff --git a/cmd-queue.c b/cmd-queue.c index f3506a34..1eacb4bc 100644 --- a/cmd-queue.c +++ b/cmd-queue.c @@ -35,7 +35,7 @@ cmdq_new(struct client *c) cmdq->dead = 0; cmdq->client = c; - cmdq->client_exit = 0; + cmdq->client_exit = -1; TAILQ_INIT(&cmdq->queue); cmdq->item = NULL; @@ -259,7 +259,7 @@ cmdq_continue(struct cmd_q *cmdq) } while (cmdq->item != NULL); empty: - if (cmdq->client_exit) + if (cmdq->client_exit > 0) cmdq->client->flags |= CLIENT_EXIT; if (cmdq->emptyfn != NULL) cmdq->emptyfn(cmdq); /* may free cmdq */ @@ -283,3 +283,27 @@ 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-split-window.c b/cmd-split-window.c index 98bbd423..2e984de5 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -38,7 +38,6 @@ const struct cmd_entry cmd_split_window_entry = { CMD_TARGET_PANE_USAGE " [command]", 0, cmd_split_window_key_binding, - NULL, cmd_split_window_exec }; @@ -84,7 +83,7 @@ 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 = cmd_get_default_path(cmdq, args_get(args, 'c')); + cwd = cmdq_default_path(cmdq, args_get(args, 'c')); type = LAYOUT_TOPBOTTOM; if (args_has(args, 'h')) diff --git a/cmd.c b/cmd.c index e7290f26..2aa5f514 100644 --- a/cmd.c +++ b/cmd.c @@ -255,8 +255,6 @@ cmd_parse(int argc, char **argv, const char *file, u_int line, char **cause) goto usage; if (entry->args_upper != -1 && args->argc > entry->args_upper) goto usage; - if (entry->check != NULL && entry->check(args) != 0) - goto usage; cmd = xcalloc(1, sizeof *cmd); cmd->entry = entry; @@ -1281,68 +1279,55 @@ cmd_template_replace(const char *template, const char *s, int idx) } /* - * Return the default path for a new pane, using the given path or the - * default-path option if it is NULL. Several special values are accepted: the - * empty string or relative path for the current pane's working directory, ~ - * for the user's home, - for the session working directory, . for the tmux - * server's working directory. The default on failure is the session's working - * directory. + * Return the default path for a new pane. Several special values are accepted: + * the empty string or relative path for the current working directory, + * ~ for the user's home, - for the base working directory, . for the server + * working directory. */ const char * -cmd_get_default_path(struct cmd_q *cmdq, const char *cwd) +cmd_default_path(const char *base, const char *current, const char *in) { - struct client *c = cmdq->client; - struct session *s; - struct environ_entry *envent; const char *root; + struct environ_entry *envent; char tmp[MAXPATHLEN]; struct passwd *pw; int n; size_t skip; static char path[MAXPATHLEN]; - if ((s = cmd_current_session(cmdq, 0)) == NULL) - return (NULL); - - if (cwd == NULL) - cwd = options_get_string(&s->options, "default-path"); - skip = 1; - if (strcmp(cwd, "$HOME") == 0 || strncmp(cwd, "$HOME/", 6) == 0) { + if (strcmp(in, "$HOME") == 0 || strncmp(in, "$HOME/", 6) == 0) { /* User's home directory - $HOME. */ skip = 5; goto find_home; - } else if (cwd[0] == '~' && (cwd[1] == '\0' || cwd[1] == '/')) { + } else if (in[0] == '~' && (in[1] == '\0' || in[1] == '/')) { /* User's home directory - ~. */ goto find_home; - } else if (cwd[0] == '-' && (cwd[1] == '\0' || cwd[1] == '/')) { - /* Session working directory. */ - root = s->cwd; + } else if (in[0] == '-' && (in[1] == '\0' || in[1] == '/')) { + /* Base working directory. */ + root = base; goto complete_path; - } else if (cwd[0] == '.' && (cwd[1] == '\0' || cwd[1] == '/')) { + } else if (in[0] == '.' && (in[1] == '\0' || in[1] == '/')) { /* Server working directory. */ if (getcwd(tmp, sizeof tmp) != NULL) { root = tmp; goto complete_path; } - return (s->cwd); - } else if (*cwd == '/') { + return ("/"); + } else if (*in == '/') { /* Absolute path. */ - return (cwd); + return (in); } else { /* Empty or relative path. */ - if (c != NULL && c->session == NULL && c->cwd != NULL) - root = c->cwd; - else if (s->curw != NULL) - root = get_proc_cwd(s->curw->window->active->fd); + if (current != NULL) + root = current; else - return (s->cwd); + return (base); skip = 0; - if (root != NULL) - goto complete_path; + goto complete_path; } - return (s->cwd); + return (base); find_home: envent = environ_find(&global_environ, "HOME"); @@ -1351,15 +1336,15 @@ find_home: else if ((pw = getpwuid(getuid())) != NULL) root = pw->pw_dir; else - return (s->cwd); + return (base); complete_path: if (root[skip] == '\0') { strlcpy(path, root, sizeof path); return (path); } - n = snprintf(path, sizeof path, "%s/%s", root, cwd + skip); + n = snprintf(path, sizeof path, "%s/%s", root, in + skip); if (n > 0 && (size_t)n < sizeof path) return (path); - return (s->cwd); + return (base); } diff --git a/tmux.1 b/tmux.1 index 1f886cf7..07d6b3fe 100644 --- a/tmux.1 +++ b/tmux.1 @@ -99,7 +99,9 @@ Force .Nm to assume the terminal supports 256 colours. .It Fl C -Start in control mode. +Start in control mode (see the +.Sx CONTROL MODE +section). Given twice .Xo ( Fl CC ) Xc disables echo. @@ -622,9 +624,10 @@ If it does exist, exit with 0. Kill the .Nm server and clients and destroy all sessions. -.It Ic kill-session +.It Xo Ic kill-session .Op Fl a .Op Fl t Ar target-session +.Xc Destroy the given session, closing any windows linked to it and no other sessions, and detaching all clients attached to it. If @@ -669,6 +672,7 @@ Lock all clients attached to .Ar target-session . .It Xo Ic new-session .Op Fl AdDP +.Op Fl c Ar start-directory .Op Fl F Ar format .Op Fl n Ar window-name .Op Fl s Ar session-name @@ -2708,8 +2712,8 @@ The default is on. Control automatic window renaming. When this setting is enabled, .Nm -will attempt - on supported platforms - to rename the window to reflect the -command currently running in it. +will rename the window automatically using the format specified by +.Ic automatic-rename-format . This flag is automatically disabled for an individual window when a name is specified at creation with .Ic new-window @@ -2723,6 +2727,13 @@ It may be switched off globally with: set-window-option -g automatic-rename off .Ed .Pp +.It Ic automatic-rename-format Ar format +The format (see +.Sx FORMATS ) +used when the +.Ic automatic-rename +option is enabled. +.Pp .It Ic c0-change-interval Ar interval .It Ic c0-change-trigger Ar trigger These two options configure a simple form of rate limiting for a pane. @@ -3570,7 +3581,7 @@ If the command doesn't return success, the exit status is also displayed. .D1 (alias: Ic info ) Show server information and terminal details. .It Xo Ic wait-for -.Fl LSU +.Op Fl L | S | U .Ar channel .Xc .D1 (alias: Ic wait ) From d2160e3f838bc2f5c08dffc0f05bc27502668ed7 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Oct 2013 12:08:14 +0000 Subject: [PATCH 28/47] mouse-resize-pane: Only resize on border select The current behaviour of mouse-resize-pane is such that if the mouse button is held down and a selection takes place within a pane, that if the mouse pointer then hits a border edge, that pane-resize would initiate. This seems counter-intuitive; instead, check for a resize condition if the border of a pane is selected, and in the case of mouse selection within a pane, no longer resize the pane if edge of the border is hit. By Thomas Adam. --- layout.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/layout.c b/layout.c index 4dd3756c..b91b86cd 100644 --- a/layout.c +++ b/layout.c @@ -533,6 +533,9 @@ layout_resize_pane_mouse(struct client *c) pane_border = 0; if (m->event & MOUSE_EVENT_DRAG && m->flags & MOUSE_RESIZE_PANE) { TAILQ_FOREACH(wp, &w->panes, entry) { + if (!window_pane_visible(wp)) + continue; + if (wp->xoff + wp->sx == m->lx && wp->yoff <= 1 + m->ly && wp->yoff + wp->sy >= m->ly) { @@ -550,7 +553,7 @@ layout_resize_pane_mouse(struct client *c) } if (pane_border) server_redraw_window(w); - } else if (~m->event & MOUSE_EVENT_UP) { + } else if (m->event & MOUSE_EVENT_DOWN) { TAILQ_FOREACH(wp, &w->panes, entry) { if ((wp->xoff + wp->sx == m->x && wp->yoff <= 1 + m->y && From 6c093010e0c181433d263be54b65def01a8a3513 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Oct 2013 12:09:34 +0000 Subject: [PATCH 29/47] Remove CMD_SENDENVIRON. --- client.c | 7 ++----- cmd-attach-session.c | 3 +-- cmd-new-session.c | 39 ++++++++++++++++++++------------------- tmux.h | 31 ++++++++++++++++++------------- 4 files changed, 41 insertions(+), 39 deletions(-) diff --git a/client.c b/client.c index 0c8657eb..0101fc0b 100644 --- a/client.c +++ b/client.c @@ -179,7 +179,7 @@ client_main(int argc, char **argv, int flags) cmdflags = CMD_STARTSERVER; } else if (argc == 0) { msg = MSG_COMMAND; - cmdflags = CMD_STARTSERVER|CMD_SENDENVIRON|CMD_CANTNEST; + cmdflags = CMD_STARTSERVER|CMD_CANTNEST; } else { msg = MSG_COMMAND; @@ -197,8 +197,6 @@ client_main(int argc, char **argv, int flags) TAILQ_FOREACH(cmd, &cmdlist->list, qentry) { if (cmd->entry->flags & CMD_STARTSERVER) cmdflags |= CMD_STARTSERVER; - if (cmd->entry->flags & CMD_SENDENVIRON) - cmdflags |= CMD_SENDENVIRON; if (cmd->entry->flags & CMD_CANTNEST) cmdflags |= CMD_CANTNEST; } @@ -258,8 +256,7 @@ client_main(int argc, char **argv, int flags) set_signals(client_signal); /* Send initial environment. */ - if (cmdflags & CMD_SENDENVIRON) - client_send_environ(); + client_send_environ(); client_send_identify(flags); /* Send first command. */ diff --git a/cmd-attach-session.c b/cmd-attach-session.c index f5f2778d..70fea988 100644 --- a/cmd-attach-session.c +++ b/cmd-attach-session.c @@ -32,8 +32,7 @@ const struct cmd_entry cmd_attach_session_entry = { "attach-session", "attach", "drt:", 0, 0, "[-dr] " CMD_TARGET_SESSION_USAGE, - CMD_CANTNEST|CMD_STARTSERVER|CMD_SENDENVIRON, - NULL, + CMD_CANTNEST|CMD_STARTSERVER, NULL, cmd_attach_session_exec }; diff --git a/cmd-new-session.c b/cmd-new-session.c index 653db876..7c6ede62 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -30,28 +30,19 @@ * Create a new session and attach to the current terminal unless -d is given. */ -enum cmd_retval cmd_new_session_check(struct args *); enum cmd_retval cmd_new_session_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_new_session_entry = { "new-session", "new", - "AdDF:n:Ps:t:x:y:", 0, 1, - "[-AdDP] [-F format] [-n window-name] [-s session-name] " - CMD_TARGET_SESSION_USAGE " [-x width] [-y height] [command]", - CMD_STARTSERVER|CMD_CANTNEST|CMD_SENDENVIRON, + "Ac:dDF:n:Ps:t:x:y:", 0, 1, + "[-AdDP] [-c start-directory] [-F format] [-n window-name] " + "[-s session-name] " CMD_TARGET_SESSION_USAGE " [-x width] [-y height] " + "[command]", + CMD_STARTSERVER|CMD_CANTNEST, NULL, - cmd_new_session_check, cmd_new_session_exec }; -enum cmd_retval -cmd_new_session_check(struct args *args) -{ - if (args_has(args, 't') && (args->argc != 0 || args_has(args, 'n'))) - return (CMD_RETURN_ERROR); - return (CMD_RETURN_NORMAL); -} - enum cmd_retval cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) { @@ -62,14 +53,19 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) struct environ env; struct termios tio, *tiop; struct passwd *pw; - const char *newname, *target, *update, *cwd, *errstr; - const char *template; + const char *newname, *target, *update, *base, *cwd; + const char *errstr, *template; char *cmd, *cause, *cp; int detached, idx; u_int sx, sy; int already_attached; struct format_tree *ft; + if (args_has(args, 't') && (args->argc != 0 || args_has(args, 'n'))) { + cmdq_error(cmdq, "command or window name given with target"); + return (CMD_RETURN_ERROR); + } + newname = args_get(args, 's'); if (newname != NULL) { if (!session_check_name(newname)) { @@ -131,14 +127,19 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) /* Get the new session working directory. */ if (c != NULL && c->cwd != NULL) - cwd = c->cwd; + base = c->cwd; else { pw = getpwuid(getuid()); if (pw->pw_dir != NULL && *pw->pw_dir != '\0') - cwd = pw->pw_dir; + base = pw->pw_dir; else - cwd = "/"; + 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) { diff --git a/tmux.h b/tmux.h index 21be2bd6..891f6233 100644 --- a/tmux.h +++ b/tmux.h @@ -151,7 +151,7 @@ extern char **environ; "[layout #{window_layout}] #{window_id}" \ "#{?window_active, (active),}"; #define LIST_WINDOWS_WITH_SESSION_TEMPLATE \ - "#{session_name}: " \ + "#{session_name}:" \ "#{window_index}: #{window_name}#{window_flags} " \ "(#{window_panes} panes) " \ "[#{window_width}x#{window_height}] " @@ -1008,6 +1008,7 @@ struct window { #define WINDOW_REDRAW 0x4 #define WINDOW_SILENCE 0x8 #define WINDOW_ZOOMED 0x10 +#define WINDOW_ALERTFLAGS (WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_SILENCE) struct options options; @@ -1449,12 +1450,10 @@ struct cmd_entry { #define CMD_STARTSERVER 0x1 #define CMD_CANTNEST 0x2 -#define CMD_SENDENVIRON 0x4 -#define CMD_READONLY 0x8 +#define CMD_READONLY 0x4 int flags; void (*key_binding)(struct cmd *, int); - int (*check)(struct args *); enum cmd_retval (*exec)(struct cmd *, struct cmd_q *); }; @@ -1552,16 +1551,19 @@ int format_cmp(struct format_entry *, struct format_entry *); RB_PROTOTYPE(format_tree, format_entry, entry, format_cmp); struct format_tree *format_create(void); void format_free(struct format_tree *); -void printflike3 format_add( - struct format_tree *, const char *, const char *, ...); +void printflike3 format_add(struct format_tree *, const char *, const char *, + ...); const char *format_find(struct format_tree *, const char *); char *format_expand(struct format_tree *, const char *); void format_session(struct format_tree *, struct session *); void format_client(struct format_tree *, struct client *); -void format_winlink( - struct format_tree *, struct session *, struct winlink *); -void format_window_pane(struct format_tree *, struct window_pane *); -void format_paste_buffer(struct format_tree *, struct paste_buffer *); +void format_window(struct format_tree *, struct window *); +void format_winlink(struct format_tree *, struct session *, + struct winlink *); +void format_window_pane(struct format_tree *, + struct window_pane *); +void format_paste_buffer(struct format_tree *, + struct paste_buffer *); /* mode-key.c */ extern const struct mode_key_table mode_key_tables[]; @@ -1767,7 +1769,7 @@ 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_get_default_path(struct cmd_q *, const char *); +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; @@ -1876,6 +1878,7 @@ 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 *, @@ -2275,8 +2278,10 @@ void window_choose_collapse_all(struct window_pane *); void window_choose_set_current(struct window_pane *, u_int); /* names.c */ -void queue_window_name(struct window *); -char *default_window_name(struct window *); +void queue_window_name(struct window *); +char *default_window_name(struct window *); +char *format_window_name(struct window *); +char *parse_window_name(const char *); /* signal.c */ void set_signals(void(*)(int, short, void *)); From eb26dbd0724075e3cc316f722ff934de46458eb4 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Oct 2013 12:12:08 +0000 Subject: [PATCH 30/47] Merge IDENTIFY_* flags with CLIENT_* flags. --- tmux.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tmux.c b/tmux.c index 901ded80..140946b9 100644 --- a/tmux.c +++ b/tmux.c @@ -261,17 +261,17 @@ main(int argc, char **argv) while ((opt = getopt(argc, argv, "2c:Cdf:lL:qS:uUv")) != -1) { switch (opt) { case '2': - flags |= IDENTIFY_256COLOURS; + flags |= CLIENT_256COLOURS; break; case 'c': free(shell_cmd); shell_cmd = xstrdup(optarg); break; case 'C': - if (flags & IDENTIFY_CONTROL) - flags |= IDENTIFY_TERMIOS; + if (flags & CLIENT_CONTROL) + flags |= CLIENT_CONTROLCONTROL; else - flags |= IDENTIFY_CONTROL; + flags |= CLIENT_CONTROL; break; case 'f': free(cfg_file); @@ -292,7 +292,7 @@ main(int argc, char **argv) path = xstrdup(optarg); break; case 'u': - flags |= IDENTIFY_UTF8; + flags |= CLIENT_UTF8; break; case 'v': debug_level++; @@ -307,7 +307,7 @@ main(int argc, char **argv) if (shell_cmd != NULL && argc != 0) usage(); - if (!(flags & IDENTIFY_UTF8)) { + if (!(flags & CLIENT_UTF8)) { /* * If the user has set whichever of LC_ALL, LC_CTYPE or LANG * exist (in that order) to contain UTF-8, it is a safe @@ -321,7 +321,7 @@ main(int argc, char **argv) } if (s != NULL && (strcasestr(s, "UTF-8") != NULL || strcasestr(s, "UTF8") != NULL)) - flags |= IDENTIFY_UTF8; + flags |= CLIENT_UTF8; } environ_init(&global_environ); @@ -340,7 +340,7 @@ main(int argc, char **argv) options_table_populate_tree(window_options_table, &global_w_options); /* Enable UTF-8 if the first client is on UTF-8 terminal. */ - if (flags & IDENTIFY_UTF8) { + if (flags & CLIENT_UTF8) { options_set_number(&global_s_options, "status-utf8", 1); options_set_number(&global_s_options, "mouse-utf8", 1); options_set_number(&global_w_options, "utf8", 1); From a0404b69026f420c8a1c35b6d017047f208cd322 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Oct 2013 12:12:54 +0000 Subject: [PATCH 31/47] retcode -> retval for exit message. --- cmd-queue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd-queue.c b/cmd-queue.c index 1eacb4bc..b2030e69 100644 --- a/cmd-queue.c +++ b/cmd-queue.c @@ -143,7 +143,7 @@ cmdq_error(struct cmd_q *cmdq, const char *fmt, ...) evbuffer_add(c->stderr_data, "\n", 1); server_push_stderr(c); - c->retcode = 1; + c->retval = 1; } else { *msg = toupper((u_char) *msg); status_message_set(c, "%s", msg); From 10c38436aae90c61e1b43ffdbd4d10d3eb95fd6a Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Oct 2013 12:13:56 +0000 Subject: [PATCH 32/47] Similarly for MSG_COMMAND - allow full imsg limit not arbitrary 2048. --- client.c | 148 ++++++++++++++++++++++++++++-------------------- server-client.c | 67 +++++++++++----------- server-fn.c | 9 +-- tmux.h | 82 +++++++++++++-------------- 4 files changed, 163 insertions(+), 143 deletions(-) diff --git a/client.c b/client.c index 0101fc0b..5be747dd 100644 --- a/client.c +++ b/client.c @@ -54,7 +54,8 @@ int client_get_lock(char *); int client_connect(char *, int); void client_send_identify(int); void client_send_environ(void); -void client_write_server(enum msgtype, void *, size_t); +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); void client_signal(int, short, void *); void client_stdin_callback(int, short, void *); @@ -165,12 +166,13 @@ client_main(int argc, char **argv, int flags) { struct cmd *cmd; struct cmd_list *cmdlist; - struct msg_command_data cmddata; - int cmdflags, fd; + struct msg_command_data *data; + int cmdflags, fd, i; pid_t ppid; enum msgtype msg; char *cause; struct termios tio, saved_tio; + size_t size; /* Set up the initial command. */ cmdflags = 0; @@ -234,7 +236,7 @@ client_main(int argc, char **argv, int flags) setblocking(STDIN_FILENO, 0); event_set(&client_stdin, STDIN_FILENO, EV_READ|EV_PERSIST, client_stdin_callback, NULL); - if (flags & IDENTIFY_TERMIOS) { + if (flags & CLIENT_CONTROLCONTROL) { if (tcgetattr(STDIN_FILENO, &saved_tio) != 0) { fprintf(stderr, "tcgetattr failed: %s\n", strerror(errno)); @@ -261,19 +263,32 @@ client_main(int argc, char **argv, int flags) /* Send first command. */ if (msg == MSG_COMMAND) { + /* How big is the command? */ + size = 0; + for (i = 0; i < argc; i++) + size += strlen(argv[i]) + 1; + data = xmalloc((sizeof *data) + size); + /* Fill in command line arguments. */ - cmddata.pid = environ_pid; - cmddata.session_id = environ_session_id; + data->pid = environ_pid; + data->session_id = environ_session_id; /* Prepare command for server. */ - cmddata.argc = argc; - if (cmd_pack_argv( - argc, argv, cmddata.argv, sizeof cmddata.argv) != 0) { + data->argc = argc; + if (cmd_pack_argv(argc, argv, (char*)(data + 1), size) != 0) { fprintf(stderr, "command too long\n"); + free(data); return (1); } + size += sizeof *data; - client_write_server(msg, &cmddata, sizeof cmddata); + /* Send the command. */ + if (client_write_server(msg, data, size) != 0) { + fprintf(stderr, "failed to send command\n"); + free(data); + return (1); + } + free(data); } else if (msg == MSG_SHELL) client_write_server(msg, NULL, 0); @@ -289,14 +304,12 @@ client_main(int argc, char **argv, int flags) ppid = getppid(); if (client_exittype == MSG_DETACHKILL && ppid > 1) kill(ppid, SIGHUP); - } else if (flags & IDENTIFY_TERMIOS) { - if (flags & IDENTIFY_CONTROL) { - if (client_exitreason != CLIENT_EXIT_NONE) - printf("%%exit %s\n", client_exit_message()); - else - printf("%%exit\n"); - printf("\033\\"); - } + } else if (flags & CLIENT_CONTROLCONTROL) { + if (client_exitreason != CLIENT_EXIT_NONE) + printf("%%exit %s\n", client_exit_message()); + else + printf("%%exit\n"); + printf("\033\\"); tcsetattr(STDOUT_FILENO, TCSAFLUSH, &saved_tio); } setblocking(STDIN_FILENO, 1); @@ -342,12 +355,29 @@ client_send_environ(void) } } -/* Write a message to the server without a file descriptor. */ -void -client_write_server(enum msgtype type, void *buf, size_t len) +/* Helper to send one message. */ +int +client_write_one(enum msgtype type, int fd, const void *buf, size_t len) { - imsg_compose(&client_ibuf, type, PROTOCOL_VERSION, -1, -1, buf, len); - client_update_event(); + int retval; + + retval = imsg_compose(&client_ibuf, type, PROTOCOL_VERSION, -1, fd, + (void*)buf, len); + if (retval != 1) + return (-1); + return (0); +} + +/* Write a message to the server without a file descriptor. */ +int +client_write_server(enum msgtype type, const void *buf, size_t len) +{ + int retval; + + retval = client_write_one(type, -1, buf, len); + if (retval == 0) + client_update_event(); + return (retval); } /* Update client event based on whether it needs to read or read and write. */ @@ -481,33 +511,33 @@ client_write(int fd, const char *data, size_t size) /* Dispatch imsgs when in wait state (before MSG_READY). */ int -client_dispatch_wait(void *data) +client_dispatch_wait(void *data0) { - struct imsg imsg; - ssize_t n, datalen; - struct msg_shell_data shelldata; - struct msg_exit_data exitdata; - struct msg_stdout_data stdoutdata; - struct msg_stderr_data stderrdata; - const char *shellcmd = data; + struct imsg imsg; + char *data; + ssize_t n, datalen; + struct msg_stdout_data stdoutdata; + struct msg_stderr_data stderrdata; + int retval; for (;;) { if ((n = imsg_get(&client_ibuf, &imsg)) == -1) fatalx("imsg_get failed"); if (n == 0) return (0); + + data = imsg.data; datalen = imsg.hdr.len - IMSG_HEADER_SIZE; log_debug("got %d from server", imsg.hdr.type); switch (imsg.hdr.type) { case MSG_EXIT: case MSG_SHUTDOWN: - if (datalen != sizeof exitdata) { - if (datalen != 0) - fatalx("bad MSG_EXIT size"); - } else { - memcpy(&exitdata, imsg.data, sizeof exitdata); - client_exitval = exitdata.retcode; + if (datalen != sizeof retval && datalen != 0) + fatalx("bad MSG_EXIT size"); + if (datalen == sizeof retval) { + memcpy(&retval, data, sizeof retval); + client_exitval = retval; } imsg_free(&imsg); return (-1); @@ -527,17 +557,19 @@ client_dispatch_wait(void *data) break; case MSG_STDOUT: if (datalen != sizeof stdoutdata) - fatalx("bad MSG_STDOUT"); - memcpy(&stdoutdata, imsg.data, sizeof stdoutdata); + fatalx("bad MSG_STDOUT size"); + memcpy(&stdoutdata, data, sizeof stdoutdata); - client_write(STDOUT_FILENO, stdoutdata.data, stdoutdata.size); + client_write(STDOUT_FILENO, stdoutdata.data, + stdoutdata.size); break; case MSG_STDERR: if (datalen != sizeof stderrdata) - fatalx("bad MSG_STDERR"); - memcpy(&stderrdata, imsg.data, sizeof stderrdata); + fatalx("bad MSG_STDERR size"); + memcpy(&stderrdata, data, sizeof stderrdata); - client_write(STDERR_FILENO, stderrdata.data, stderrdata.size); + client_write(STDERR_FILENO, stderrdata.data, + stderrdata.size); break; case MSG_VERSION: if (datalen != 0) @@ -551,14 +583,11 @@ client_dispatch_wait(void *data) imsg_free(&imsg); return (-1); case MSG_SHELL: - if (datalen != sizeof shelldata) - fatalx("bad MSG_SHELL size"); - memcpy(&shelldata, imsg.data, sizeof shelldata); - shelldata.shell[(sizeof shelldata.shell) - 1] = '\0'; + if (data[datalen - 1] != '\0') + fatalx("bad MSG_SHELL string"); clear_signals(0); - - shell_exec(shelldata.shell, shellcmd); + shell_exec(data, data0); /* NOTREACHED */ case MSG_DETACH: client_write_server(MSG_EXITING, NULL, 0); @@ -578,16 +607,18 @@ client_dispatch_wait(void *data) int client_dispatch_attached(void) { - struct imsg imsg; - struct msg_lock_data lockdata; - struct sigaction sigact; - ssize_t n, datalen; + struct imsg imsg; + struct sigaction sigact; + char *data; + ssize_t n, datalen; for (;;) { if ((n = imsg_get(&client_ibuf, &imsg)) == -1) fatalx("imsg_get failed"); if (n == 0) return (0); + + data = imsg.data; datalen = imsg.hdr.len - IMSG_HEADER_SIZE; log_debug("got %d from server", imsg.hdr.type); @@ -605,8 +636,7 @@ client_dispatch_attached(void) client_write_server(MSG_EXITING, NULL, 0); break; case MSG_EXIT: - if (datalen != 0 && - datalen != sizeof (struct msg_exit_data)) + if (datalen != 0 && datalen != sizeof (int)) fatalx("bad MSG_EXIT size"); client_write_server(MSG_EXITING, NULL, 0); @@ -639,12 +669,10 @@ client_dispatch_attached(void) kill(getpid(), SIGTSTP); break; case MSG_LOCK: - if (datalen != sizeof lockdata) - fatalx("bad MSG_LOCK size"); - memcpy(&lockdata, imsg.data, sizeof lockdata); + if (data[datalen - 1] != '\0') + fatalx("bad MSG_LOCK string"); - lockdata.cmd[(sizeof lockdata.cmd) - 1] = '\0'; - system(lockdata.cmd); + system(data); client_write_server(MSG_UNLOCK, NULL, 0); break; default: diff --git a/server-client.c b/server-client.c index 44119237..4bba5f7d 100644 --- a/server-client.c +++ b/server-client.c @@ -40,7 +40,7 @@ void server_client_reset_state(struct client *); int server_client_assume_paste(struct session *); int server_client_msg_dispatch(struct client *); -void server_client_msg_command(struct client *, struct msg_command_data *); +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_shell(struct client *); @@ -695,8 +695,6 @@ server_client_repeat_timer(unused int fd, unused short events, void *data) void server_client_check_exit(struct client *c) { - struct msg_exit_data exitdata; - if (!(c->flags & CLIENT_EXIT)) return; @@ -707,9 +705,7 @@ server_client_check_exit(struct client *c) if (EVBUFFER_LENGTH(c->stderr_data) != 0) return; - exitdata.retcode = c->retcode; - server_write_client(c, MSG_EXIT, &exitdata, sizeof exitdata); - + server_write_client(c, MSG_EXIT, &c->retval, sizeof c->retval); c->flags &= ~CLIENT_EXIT; } @@ -790,10 +786,10 @@ int server_client_msg_dispatch(struct client *c) { struct imsg imsg; - struct msg_command_data commanddata; struct msg_identify_data identifydata; struct msg_environ_data environdata; struct msg_stdin_data stdindata; + const char *data; ssize_t n, datalen; if ((n = imsg_read(&c->ibuf)) == -1 || n == 0) @@ -804,6 +800,8 @@ server_client_msg_dispatch(struct client *c) return (-1); if (n == 0) return (0); + + data = imsg.data; datalen = imsg.hdr.len - IMSG_HEADER_SIZE; if (imsg.hdr.peerid != PROTOCOL_VERSION) { @@ -815,13 +813,6 @@ 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_COMMAND: - if (datalen != sizeof commanddata) - fatalx("bad MSG_COMMAND size"); - memcpy(&commanddata, imsg.data, sizeof commanddata); - - server_client_msg_command(c, &commanddata); - break; case MSG_IDENTIFY: if (datalen != sizeof identifydata) fatalx("bad MSG_IDENTIFY size"); @@ -829,10 +820,13 @@ server_client_msg_dispatch(struct client *c) server_client_msg_identify(c, &identifydata, imsg.fd); break; + case MSG_COMMAND: + server_client_msg_command(c, &imsg); + break; case MSG_STDIN: if (datalen != sizeof stdindata) fatalx("bad MSG_STDIN size"); - memcpy(&stdindata, imsg.data, sizeof stdindata); + memcpy(&stdindata, data, sizeof stdindata); if (c->stdin_callback == NULL) break; @@ -907,15 +901,26 @@ server_client_msg_dispatch(struct client *c) /* Handle command message. */ void -server_client_msg_command(struct client *c, struct msg_command_data *data) +server_client_msg_command(struct client *c, struct imsg *imsg) { - struct cmd_list *cmdlist = NULL; - int argc; - char **argv, *cause; + struct msg_command_data data; + char *buf; + size_t len; + struct cmd_list *cmdlist = NULL; + int argc; + char **argv, *cause; - argc = data->argc; - data->argv[(sizeof data->argv) - 1] = '\0'; - if (cmd_unpack_argv(data->argv, sizeof data->argv, argc, &argv) != 0) { + if (imsg->hdr.len - IMSG_HEADER_SIZE < sizeof data) + fatalx("bad MSG_COMMAND size"); + memcpy(&data, imsg->data, sizeof data); + + buf = (char*)imsg->data + sizeof data; + len = imsg->hdr.len - IMSG_HEADER_SIZE - sizeof data; + if (len > 0 && buf[len - 1] != '\0') + fatalx("bad MSG_COMMAND string"); + + argc = data.argc; + if (cmd_unpack_argv(buf, len, argc, &argv) != 0) { cmdq_error(c->cmdq, "command too long"); goto error; } @@ -954,12 +959,12 @@ server_client_msg_identify( if (*data->cwd != '\0') c->cwd = xstrdup(data->cwd); - if (data->flags & IDENTIFY_CONTROL) { + if (data->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 & IDENTIFY_TERMIOS) + if (data->flags & CLIENT_CONTROLCONTROL) evbuffer_add_printf(c->stdout_data, "\033P1000p"); server_write_client(c, MSG_STDIN, NULL, 0); @@ -978,14 +983,14 @@ server_client_msg_identify( } data->term[(sizeof data->term) - 1] = '\0'; tty_init(&c->tty, c, fd, data->term); - if (data->flags & IDENTIFY_UTF8) + if (data->flags & CLIENT_UTF8) c->tty.flags |= TTY_UTF8; - if (data->flags & IDENTIFY_256COLOURS) + if (data->flags & CLIENT_256COLOURS) c->tty.term_flags |= TERM_256COLOURS; tty_resize(&c->tty); - if (!(data->flags & IDENTIFY_CONTROL)) + if (!(data->flags & CLIENT_CONTROL)) c->flags |= CLIENT_TERMINAL; } @@ -993,16 +998,12 @@ server_client_msg_identify( void server_client_msg_shell(struct client *c) { - struct msg_shell_data data; - const char *shell; + const char *shell; shell = options_get_string(&global_s_options, "default-shell"); - if (*shell == '\0' || areshell(shell)) shell = _PATH_BSHELL; - if (strlcpy(data.shell, shell, sizeof data.shell) >= sizeof data.shell) - strlcpy(data.shell, _PATH_BSHELL, sizeof data.shell); + server_write_client(c, MSG_SHELL, shell, strlen(shell) + 1); - server_write_client(c, MSG_SHELL, &data, sizeof data); c->flags |= CLIENT_BAD; /* it will die after exec */ } diff --git a/server-fn.c b/server-fn.c index fb0eadd6..f6485b49 100644 --- a/server-fn.c +++ b/server-fn.c @@ -235,9 +235,7 @@ server_lock_session(struct session *s) void server_lock_client(struct client *c) { - const char *cmd; - size_t cmdlen; - struct msg_lock_data lockdata; + const char *cmd; if (c->flags & CLIENT_CONTROL) return; @@ -246,8 +244,7 @@ server_lock_client(struct client *c) return; cmd = options_get_string(&c->session->options, "lock-command"); - cmdlen = strlcpy(lockdata.cmd, cmd, sizeof lockdata.cmd); - if (cmdlen >= sizeof lockdata.cmd) + if (strlen(cmd) + 1 > MAX_IMSGSIZE - IMSG_HEADER_SIZE) return; tty_stop_tty(&c->tty); @@ -256,7 +253,7 @@ server_lock_client(struct client *c) tty_raw(&c->tty, tty_term_string(c->tty.term, TTYC_E3)); c->flags |= CLIENT_SUSPENDED; - server_write_client(c, MSG_LOCK, &lockdata, sizeof lockdata); + server_write_client(c, MSG_LOCK, cmd, strlen(cmd) + 1); } void diff --git a/tmux.h b/tmux.h index 891f6233..2d631a17 100644 --- a/tmux.h +++ b/tmux.h @@ -19,7 +19,7 @@ #ifndef TMUX_H #define TMUX_H -#define PROTOCOL_VERSION 7 +#define PROTOCOL_VERSION 8 #include #include @@ -62,7 +62,6 @@ extern char **environ; * Maximum sizes of strings in message data. Don't forget to bump * PROTOCOL_VERSION if any of these change! */ -#define COMMAND_LENGTH 2048 /* packed argv size */ #define TERMINAL_LENGTH 128 /* length of TERM environment variable */ #define ENVIRON_LENGTH 1024 /* environment variable length */ @@ -437,27 +436,36 @@ ARRAY_DECL(causelist, char *); /* Message codes. */ enum msgtype { - MSG_COMMAND, + MSG_VERSION = 12, + + MSG_IDENTIFY_FLAGS = 100, + MSG_IDENTIFY_TERM, + MSG_IDENTIFY_TTYNAME, + MSG_IDENTIFY_CWD, + MSG_IDENTIFY_STDIN, + MSG_IDENTIFY_ENVIRON, + MSG_IDENTIFY_DONE, + + MSG_COMMAND = 200, MSG_DETACH, - MSG_ERROR, + MSG_DETACHKILL, MSG_EXIT, MSG_EXITED, MSG_EXITING, - MSG_IDENTIFY, - MSG_STDIN, + MSG_LOCK, MSG_READY, MSG_RESIZE, - MSG_SHUTDOWN, - MSG_SUSPEND, - MSG_VERSION, - MSG_WAKEUP, - MSG_ENVIRON, - MSG_UNLOCK, - MSG_LOCK, MSG_SHELL, + MSG_SHUTDOWN, MSG_STDERR, + MSG_STDIN, MSG_STDOUT, - MSG_DETACHKILL + MSG_SUSPEND, + MSG_UNLOCK, + MSG_WAKEUP, + + MSG_IDENTIFY = 300, + MSG_ENVIRON }; /* @@ -466,42 +474,23 @@ enum msgtype { * Don't forget to bump PROTOCOL_VERSION if any of these change! */ struct msg_command_data { - pid_t pid; /* from $TMUX or -1 */ - int session_id; /* from $TMUX or -1 */ + pid_t pid; /* from $TMUX or -1 */ + int session_id; /* from $TMUX or -1 */ - int argc; - char argv[COMMAND_LENGTH]; -}; + int argc; +}; /* followed by packed argv */ struct msg_identify_data { char cwd[MAXPATHLEN]; - char term[TERMINAL_LENGTH]; -#define IDENTIFY_UTF8 0x1 -#define IDENTIFY_256COLOURS 0x2 -/* 0x4 unused */ -#define IDENTIFY_CONTROL 0x8 -#define IDENTIFY_TERMIOS 0x10 int flags; }; -struct msg_lock_data { - char cmd[COMMAND_LENGTH]; -}; - struct msg_environ_data { char var[ENVIRON_LENGTH]; }; -struct msg_shell_data { - char shell[MAXPATHLEN]; -}; - -struct msg_exit_data { - int retcode; -}; - struct msg_stdin_data { ssize_t size; char data[BUFSIZ]; @@ -1294,8 +1283,9 @@ RB_HEAD(status_out_tree, status_out); /* Client connection. */ struct client { struct imsgbuf ibuf; + struct event event; - int retcode; + int retval; struct timeval creation_time; struct timeval activity_time; @@ -1326,7 +1316,7 @@ struct client { #define CLIENT_EXIT 0x4 #define CLIENT_REDRAW 0x8 #define CLIENT_STATUS 0x10 -#define CLIENT_REPEAT 0x20 /* allow command to repeat within repeat time */ +#define CLIENT_REPEAT 0x20 #define CLIENT_SUSPENDED 0x40 #define CLIENT_BAD 0x80 #define CLIENT_IDENTIFY 0x100 @@ -1335,7 +1325,11 @@ struct client { #define CLIENT_READONLY 0x800 #define CLIENT_REDRAWWINDOW 0x1000 #define CLIENT_CONTROL 0x2000 -#define CLIENT_FOCUSED 0x4000 +#define CLIENT_CONTROLCONTROL 0x4000 +#define CLIENT_FOCUSED 0x8000 +#define CLIENT_UTF8 0x10000 +#define CLIENT_256COLOURS 0x20000 +#define CLIENT_IDENTIFIED 0x40000 int flags; struct event identify_timer; @@ -1925,10 +1919,10 @@ void server_window_loop(void); /* server-fn.c */ void server_fill_environ(struct session *, struct environ *); void server_write_ready(struct client *); -int server_write_client( - struct client *, enum msgtype, const void *, size_t); -void server_write_session( - struct session *, enum msgtype, const void *, size_t); +int server_write_client(struct client *, enum msgtype, const void *, + size_t); +void server_write_session(struct session *, enum msgtype, const void *, + size_t); void server_redraw_client(struct client *); void server_status_client(struct client *); void server_redraw_session(struct session *); From 165aa597600ae5bb2b22f06a2633fbae5a77d917 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Oct 2013 12:14:09 +0000 Subject: [PATCH 33/47] Make tilde expansion in command strings work even if it isn't terminated by /. --- cmd-string.c | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/cmd-string.c b/cmd-string.c index f785b842..e19b8856 100644 --- a/cmd-string.c +++ b/cmd-string.c @@ -318,10 +318,13 @@ cmd_string_expand_tilde(const char *s, size_t *p) { struct passwd *pw; struct environ_entry *envent; - char *home, *path, *username; + char *home, *path, *user, *cp; + int last; home = NULL; - if (cmd_string_getc(s, p) == '/') { + + last = cmd_string_getc(s, p); + if (last == EOF || last == '/' || last == ' '|| last == '\t') { envent = environ_find(&global_environ, "HOME"); if (envent != NULL && *envent->value != '\0') home = envent->value; @@ -329,15 +332,27 @@ cmd_string_expand_tilde(const char *s, size_t *p) home = pw->pw_dir; } else { cmd_string_ungetc(p); - if ((username = cmd_string_string(s, p, '/', 0)) == NULL) - return (NULL); - if ((pw = getpwnam(username)) != NULL) + + cp = user = xmalloc(strlen(s)); + for (;;) { + last = cmd_string_getc(s, p); + if (last == EOF || last == '/' || last == ' '|| last == '\t') + break; + *cp++ = last; + } + *cp = '\0'; + + if ((pw = getpwnam(user)) != NULL) home = pw->pw_dir; - free(username); + free(user); } + if (home == NULL) return (NULL); - xasprintf(&path, "%s/", home); + if (last != EOF) + xasprintf(&path, "%s%c", home, last); + else + xasprintf(&path, "%s", home); return (path); } From 282c5f9644ed262ee15efbd3d072f7acc577da15 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Oct 2013 12:26:34 +0000 Subject: [PATCH 34/47] 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) From b8b85fbb0c6cf4e9a3fa650ec7dc5036a1b0b01a Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Oct 2013 12:27:38 +0000 Subject: [PATCH 35/47] Don't look at string[length - 1] if length == 0. --- client.c | 4 ++-- server-client.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/client.c b/client.c index 82e43992..e1bd47c2 100644 --- a/client.c +++ b/client.c @@ -575,7 +575,7 @@ client_dispatch_wait(void *data0) imsg_free(&imsg); return (-1); case MSG_SHELL: - if (data[datalen - 1] != '\0') + if (datalen == 0 || data[datalen - 1] != '\0') fatalx("bad MSG_SHELL string"); clear_signals(0); @@ -659,7 +659,7 @@ client_dispatch_attached(void) kill(getpid(), SIGTSTP); break; case MSG_LOCK: - if (data[datalen - 1] != '\0') + if (datalen == 0 || data[datalen - 1] != '\0') fatalx("bad MSG_LOCK string"); system(data); diff --git a/server-client.c b/server-client.c index a39f56d8..e202902e 100644 --- a/server-client.c +++ b/server-client.c @@ -961,12 +961,12 @@ server_client_msg_identify(struct client *c, struct imsg *imsg) c->flags |= flags; break; case MSG_IDENTIFY_TERM: - if (data[datalen - 1] != '\0') + if (datalen == 0 || data[datalen - 1] != '\0') fatalx("bad MSG_IDENTIFY_TERM string"); c->term = xstrdup(data); break; case MSG_IDENTIFY_TTYNAME: - if (data[datalen - 1] != '\0') + if (datalen == 0 || data[datalen - 1] != '\0') fatalx("bad MSG_IDENTIFY_TTYNAME string"); c->ttyname = xstrdup(data); break; @@ -981,7 +981,7 @@ server_client_msg_identify(struct client *c, struct imsg *imsg) c->fd = imsg->fd; break; case MSG_IDENTIFY_ENVIRON: - if (data[datalen - 1] != '\0') + if (datalen == 0 || data[datalen - 1] != '\0') fatalx("bad MSG_IDENTIFY_ENVIRON string"); if (strchr(data, '=') != NULL) environ_put(&c->environ, data); From 7936ce38749a4751120c856a112ee85122df612c Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Oct 2013 12:28:08 +0000 Subject: [PATCH 36/47] Show session name in detached message. Requested by somebody a few months ago who didn't bother testing it. But it works for me anyway. --- client.c | 21 ++++++++++++++++++--- cmd-attach-session.c | 10 +++++++--- cmd-detach-client.c | 22 +++++++++++++++------- 3 files changed, 40 insertions(+), 13 deletions(-) diff --git a/client.c b/client.c index e1bd47c2..0d57b793 100644 --- a/client.c +++ b/client.c @@ -48,6 +48,7 @@ enum { } client_exitreason = CLIENT_EXIT_NONE; int client_exitval; enum msgtype client_exittype; +const char *client_exitsession; int client_attached; int client_get_lock(char *); @@ -138,12 +139,24 @@ failed: const char * client_exit_message(void) { + static char msg[256]; + switch (client_exitreason) { case CLIENT_EXIT_NONE: break; case CLIENT_EXIT_DETACHED: + if (client_exitsession != NULL) { + xsnprintf(msg, sizeof msg, "detached " + "(from session %s)", client_exitsession); + return (msg); + } return ("detached"); case CLIENT_EXIT_DETACHED_HUP: + if (client_exitsession != NULL) { + xsnprintf(msg, sizeof msg, "detached and SIGHUP " + "(from session %s)", client_exitsession); + return (msg); + } return ("detached and SIGHUP"); case CLIENT_EXIT_LOST_TTY: return ("lost tty"); @@ -582,6 +595,7 @@ client_dispatch_wait(void *data0) shell_exec(data, data0); /* NOTREACHED */ case MSG_DETACH: + case MSG_DETACHKILL: client_write_server(MSG_EXITING, NULL, 0); break; case MSG_EXITED: @@ -613,11 +627,12 @@ client_dispatch_attached(void) log_debug("got %d from server", imsg.hdr.type); switch (imsg.hdr.type) { - case MSG_DETACHKILL: case MSG_DETACH: - if (datalen != 0) - fatalx("bad MSG_DETACH size"); + case MSG_DETACHKILL: + if (datalen == 0 || data[datalen - 1] != '\0') + fatalx("bad MSG_DETACH string"); + client_exitsession = xstrdup(data); client_exittype = imsg.hdr.type; if (imsg.hdr.type == MSG_DETACHKILL) client_exitreason = CLIENT_EXIT_DETACHED_HUP; diff --git a/cmd-attach-session.c b/cmd-attach-session.c index 8dcc5997..c71e6f1f 100644 --- a/cmd-attach-session.c +++ b/cmd-attach-session.c @@ -77,7 +77,9 @@ cmd_attach_session(struct cmd_q *cmdq, const char *tflag, int dflag, int rflag, continue; if (c == cmdq->client) continue; - server_write_client(c, MSG_DETACH, NULL, 0); + server_write_client(c, MSG_DETACH, + c->session->name, + strlen(c->session->name) + 1); } } @@ -138,8 +140,10 @@ cmd_attach_session(struct cmd_q *cmdq, const char *tflag, int dflag, int rflag, if (rflag) cmdq->client->flags |= CLIENT_READONLY; - if (dflag) - server_write_session(s, MSG_DETACH, NULL, 0); + if (dflag) { + server_write_session(s, MSG_DETACH, s->name, + strlen(s->name) + 1); + } update = options_get_string(&s->options, "update-environment"); environ_update(update, &cmdq->client->environ, &s->environ); diff --git a/cmd-detach-client.c b/cmd-detach-client.c index fc80499c..82001bee 100644 --- a/cmd-detach-client.c +++ b/cmd-detach-client.c @@ -18,6 +18,8 @@ #include +#include + #include "tmux.h" /* @@ -40,8 +42,8 @@ cmd_detach_client_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct client *c, *c2; - struct session *s; - enum msgtype msgtype; + struct session *s; + enum msgtype msgtype; u_int i; if (args_has(args, 'P')) @@ -56,8 +58,10 @@ cmd_detach_client_exec(struct cmd *self, struct cmd_q *cmdq) for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); - if (c != NULL && c->session == s) - server_write_client(c, msgtype, NULL, 0); + if (c == NULL || c->session != s) + continue; + server_write_client(c, msgtype, c->session->name, + strlen(c->session->name) + 1); } } else { c = cmd_find_client(cmdq, args_get(args, 't'), 0); @@ -69,10 +73,14 @@ cmd_detach_client_exec(struct cmd *self, struct cmd_q *cmdq) c2 = ARRAY_ITEM(&clients, i); if (c2 == NULL || c == c2) continue; - server_write_client(c2, msgtype, NULL, 0); + server_write_client(c2, msgtype, + c2->session->name, + strlen(c2->session->name) + 1); } - } else - server_write_client(c, msgtype, NULL, 0); + } else { + server_write_client(c, msgtype, c->session->name, + strlen(c->session->name) + 1); + } } return (CMD_RETURN_STOP); From 909e1c1a86667bf71eab83ac064f038995bf5d20 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Oct 2013 12:28:38 +0000 Subject: [PATCH 37/47] Don't boke when figuring out working directory from configuration file. --- cmd-new-session.c | 2 +- cmd-new-window.c | 2 +- cmd-split-window.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd-new-session.c b/cmd-new-session.c index 5e69a77c..49ece8b4 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -115,7 +115,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) return (CMD_RETURN_ERROR); } cwd = fd; - } else if (c->session == NULL) + } else if (c != NULL && c->session == NULL) cwd = c->cwd; else if ((c0 = cmd_current_client(cmdq)) != NULL) cwd = c0->session->cwd; diff --git a/cmd-new-window.c b/cmd-new-window.c index 445f0a33..e2a01190 100644 --- a/cmd-new-window.c +++ b/cmd-new-window.c @@ -125,7 +125,7 @@ cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq) return (CMD_RETURN_ERROR); } cwd = fd; - } else if (cmdq->client->session == NULL) + } else if (cmdq->client != NULL && cmdq->client->session == NULL) cwd = cmdq->client->cwd; else cwd = s->cwd; diff --git a/cmd-split-window.c b/cmd-split-window.c index 43d47c47..92e6121f 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -103,7 +103,7 @@ cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq) return (CMD_RETURN_ERROR); } cwd = fd; - } else if (cmdq->client->session == NULL) + } else if (cmdq->client != NULL && cmdq->client->session == NULL) cwd = cmdq->client->cwd; else cwd = s->cwd; From 6ac7abe8f038c21c1cf33d50a02e970f0de81c09 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Oct 2013 12:28:56 +0000 Subject: [PATCH 38/47] Remove now unused cmd_get_default_path. --- cmd.c | 71 ----------------------------------------------------------- 1 file changed, 71 deletions(-) diff --git a/cmd.c b/cmd.c index 2aa5f514..b349da77 100644 --- a/cmd.c +++ b/cmd.c @@ -1277,74 +1277,3 @@ cmd_template_replace(const char *template, const char *s, int idx) return (buf); } - -/* - * Return the default path for a new pane. Several special values are accepted: - * the empty string or relative path for the current working directory, - * ~ for the user's home, - for the base working directory, . for the server - * working directory. - */ -const char * -cmd_default_path(const char *base, const char *current, const char *in) -{ - const char *root; - struct environ_entry *envent; - char tmp[MAXPATHLEN]; - struct passwd *pw; - int n; - size_t skip; - static char path[MAXPATHLEN]; - - skip = 1; - if (strcmp(in, "$HOME") == 0 || strncmp(in, "$HOME/", 6) == 0) { - /* User's home directory - $HOME. */ - skip = 5; - goto find_home; - } else if (in[0] == '~' && (in[1] == '\0' || in[1] == '/')) { - /* User's home directory - ~. */ - goto find_home; - } else if (in[0] == '-' && (in[1] == '\0' || in[1] == '/')) { - /* Base working directory. */ - root = base; - goto complete_path; - } else if (in[0] == '.' && (in[1] == '\0' || in[1] == '/')) { - /* Server working directory. */ - if (getcwd(tmp, sizeof tmp) != NULL) { - root = tmp; - goto complete_path; - } - return ("/"); - } else if (*in == '/') { - /* Absolute path. */ - return (in); - } else { - /* Empty or relative path. */ - if (current != NULL) - root = current; - else - return (base); - skip = 0; - goto complete_path; - } - - return (base); - -find_home: - envent = environ_find(&global_environ, "HOME"); - if (envent != NULL && *envent->value != '\0') - root = envent->value; - else if ((pw = getpwuid(getuid())) != NULL) - root = pw->pw_dir; - else - return (base); - -complete_path: - if (root[skip] == '\0') { - strlcpy(path, root, sizeof path); - return (path); - } - n = snprintf(path, sizeof path, "%s/%s", root, in + skip); - if (n > 0 && (size_t)n < sizeof path) - return (path); - return (base); -} From c1ccefc62d2a70c91ac31cff141031d61cc0a12c Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Oct 2013 12:29:35 +0000 Subject: [PATCH 39/47] We accidentally haven't been using $TMUX to work out the session for a while and in fact it is less useful that using the client ttyname. So don't bother and don't pass it from the client. If we need it in future it is in c->environ. --- client.c | 4 ---- cmd.c | 8 -------- server-client.c | 2 ++ tmux.c | 30 ++++++++---------------------- tmux.h | 7 ------- 5 files changed, 10 insertions(+), 41 deletions(-) diff --git a/client.c b/client.c index 0d57b793..3b929b71 100644 --- a/client.c +++ b/client.c @@ -280,10 +280,6 @@ client_main(int argc, char **argv, int flags) size += strlen(argv[i]) + 1; data = xmalloc((sizeof *data) + size); - /* Fill in command line arguments. */ - data->pid = environ_pid; - data->session_id = environ_session_id; - /* Prepare command for server. */ data->argc = argc; if (cmd_pack_argv(argc, argv, (char*)(data + 1), size) != 0) { diff --git a/cmd.c b/cmd.c index b349da77..2edda633 100644 --- a/cmd.c +++ b/cmd.c @@ -314,7 +314,6 @@ cmd_print(struct cmd *cmd, char *buf, size_t len) struct session * cmd_current_session(struct cmd_q *cmdq, int prefer_unattached) { - struct msg_command_data *data = cmdq->msgdata; struct client *c = cmdq->client; struct session *s; struct sessionslist ss; @@ -356,13 +355,6 @@ cmd_current_session(struct cmd_q *cmdq, int prefer_unattached) return (s); } - /* Use the session from the TMUX environment variable. */ - if (data != NULL && data->pid == getpid() && data->session_id != -1) { - s = session_find_by_id(data->session_id); - if (s != NULL) - return (s); - } - return (cmd_choose_session(prefer_unattached)); } diff --git a/server-client.c b/server-client.c index e202902e..6aa2a0fa 100644 --- a/server-client.c +++ b/server-client.c @@ -62,6 +62,8 @@ server_client_create(int fd) fatal("gettimeofday failed"); memcpy(&c->activity_time, &c->creation_time, sizeof c->activity_time); + environ_init(&c->environ); + c->cmdq = cmdq_new(c); c->cmdq->client_exit = 1; diff --git a/tmux.c b/tmux.c index a78746ae..74d827a5 100644 --- a/tmux.c +++ b/tmux.c @@ -49,11 +49,8 @@ time_t start_time; char socket_path[MAXPATHLEN]; int login_shell; char *environ_path; -pid_t environ_pid = -1; -int environ_session_id = -1; __dead void usage(void); -void parseenvironment(void); char *makesocketpath(const char *); __dead void @@ -124,23 +121,6 @@ areshell(const char *shell) return (0); } -void -parseenvironment(void) -{ - char *env, path[256]; - long pid; - int id; - - if ((env = getenv("TMUX")) == NULL) - return; - - if (sscanf(env, "%255[^,],%ld,%d", path, &pid, &id) != 3) - return; - environ_path = xstrdup(path); - environ_pid = pid; - environ_session_id = id; -} - char * makesocketpath(const char *label) { @@ -223,7 +203,9 @@ main(int argc, char **argv) { struct passwd *pw; char *s, *path, *label, *home, **var, tmp[MAXPATHLEN]; - int opt, flags, quiet, keys; + char in[256]; + long long pid; + int opt, flags, quiet, keys, session; #ifdef DEBUG malloc_options = (char *) "AFGJPX"; @@ -351,11 +333,15 @@ main(int argc, char **argv) } } + /* Get path from environment. */ + s = getenv("TMUX"); + if (s != NULL && sscanf(s, "%255[^,],%lld,%d", in, &pid, &session) == 3) + environ_path = xstrdup(in); + /* * Figure out the socket path. If specified on the command-line with -S * or -L, use it, otherwise try $TMUX or assume -L default. */ - parseenvironment(); if (path == NULL) { /* If no -L, use the environment. */ if (label == NULL) { diff --git a/tmux.h b/tmux.h index e281790d..e18176e8 100644 --- a/tmux.h +++ b/tmux.h @@ -464,9 +464,6 @@ enum msgtype { * Don't forget to bump PROTOCOL_VERSION if any of these change! */ struct msg_command_data { - pid_t pid; /* from $TMUX or -1 */ - int session_id; /* from $TMUX or -1 */ - int argc; }; /* followed by packed argv */ @@ -1408,8 +1405,6 @@ struct cmd_q { void (*emptyfn)(struct cmd_q *); void *data; - struct msg_command_data *msgdata; - TAILQ_ENTRY(cmd_q) waitentry; }; @@ -1503,8 +1498,6 @@ extern time_t start_time; extern char socket_path[MAXPATHLEN]; extern int login_shell; extern char *environ_path; -extern pid_t environ_pid; -extern int environ_session_id; void logfile(const char *); const char *getshell(void); int checkshell(const char *); From b85de1ddb34a1b22567e9bf89c9a21a81bf12aa1 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Oct 2013 12:29:53 +0000 Subject: [PATCH 40/47] Pass -1 for cwd now not NULL. --- cmd-respawn-pane.c | 2 +- cmd-respawn-window.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd-respawn-pane.c b/cmd-respawn-pane.c index 2315b241..d7d88c27 100644 --- a/cmd-respawn-pane.c +++ b/cmd-respawn-pane.c @@ -77,7 +77,7 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmd_q *cmdq) cmd = args->argv[0]; else cmd = NULL; - if (window_pane_spawn(wp, cmd, NULL, NULL, &env, s->tio, &cause) != 0) { + if (window_pane_spawn(wp, cmd, NULL, -1, &env, s->tio, &cause) != 0) { cmdq_error(cmdq, "respawn pane failed: %s", cause); free(cause); environ_free(&env); diff --git a/cmd-respawn-window.c b/cmd-respawn-window.c index e4ef6dfb..b681f2f4 100644 --- a/cmd-respawn-window.c +++ b/cmd-respawn-window.c @@ -79,7 +79,7 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_q *cmdq) cmd = args->argv[0]; else cmd = NULL; - if (window_pane_spawn(wp, cmd, NULL, NULL, &env, s->tio, &cause) != 0) { + if (window_pane_spawn(wp, cmd, NULL, -1, &env, s->tio, &cause) != 0) { cmdq_error(cmdq, "respawn window failed: %s", cause); free(cause); environ_free(&env); From 99e3cbc526cff605f32d61c0b4be77a8b2dbaa9f Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Oct 2013 12:35:30 +0000 Subject: [PATCH 41/47] Use format_get_command() and some spacing tweaks. --- client.c | 1 + job.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/client.c b/client.c index 3b929b71..0f2d3684 100644 --- a/client.c +++ b/client.c @@ -351,6 +351,7 @@ client_send_identify(int flags) 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(); diff --git a/job.c b/job.c index 0ae03b31..e8006308 100644 --- a/job.c +++ b/job.c @@ -145,7 +145,7 @@ job_write_callback(unused struct bufferevent *bufev, void *data) size_t len = EVBUFFER_LENGTH(EVBUFFER_OUTPUT(job->event)); log_debug("job write %p: %s, pid %ld, output left %zu", job, job->cmd, - (long) job->pid, len); + (long) job->pid, len); if (len == 0) { shutdown(job->fd, SHUT_WR); From d0566a474aa43cb27c6a8fc62ff80ef32c7fe86e Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Oct 2013 12:39:24 +0000 Subject: [PATCH 42/47] Remove the KERN_PROC_CWD the proc_current_path format (which is the only thing that uses it now). --- format.c | 5 +---- procname.c | 15 --------------- tmux.1 | 1 - tmux.h | 1 - 4 files changed, 1 insertion(+), 21 deletions(-) diff --git a/format.c b/format.c index 19c4dc15..40957a59 100644 --- a/format.c +++ b/format.c @@ -518,7 +518,6 @@ format_window_pane(struct format_tree *ft, struct window_pane *wp) struct grid_line *gl; unsigned long long size; u_int i, idx; - const char *cwd; char *cmd; size = 0; @@ -551,9 +550,7 @@ 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 ((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) { + if ((cmd = format_get_command(wp)) != NULL) { format_add(ft, "pane_current_command", "%s", cmd); free(cmd); } diff --git a/procname.c b/procname.c index 1518c94b..ee9b99dc 100644 --- a/procname.c +++ b/procname.c @@ -37,7 +37,6 @@ struct kinfo_proc *cmp_procs(struct kinfo_proc *, struct kinfo_proc *); char *get_proc_name(int, char *); -char *get_proc_cwd(int); struct kinfo_proc * cmp_procs(struct kinfo_proc *p1, struct kinfo_proc *p2) @@ -132,17 +131,3 @@ error: free(buf); return (NULL); } - -char* -get_proc_cwd(int fd) -{ - int name[] = { CTL_KERN, KERN_PROC_CWD, 0 }; - static char path[MAXPATHLEN]; - size_t pathlen = sizeof path; - - if ((name[2] = tcgetpgrp(fd)) == -1) - return (NULL); - if (sysctl(name, 3, path, &pathlen, NULL, 0) != 0) - return (NULL); - return (path); -} diff --git a/tmux.1 b/tmux.1 index eb417da0..4fb588e3 100644 --- a/tmux.1 +++ b/tmux.1 @@ -3068,7 +3068,6 @@ The following variables are available, where appropriate: .It Li "mouse_utf8_flag" Ta "" Ta "Pane mouse UTF-8 flag" .It Li "pane_active" Ta "" Ta "1 if active pane" .It Li "pane_current_command" Ta "" Ta "Current command if available" -.It Li "pane_current_path" Ta "" Ta "Current path if available" .It Li "pane_dead" Ta "" Ta "1 if pane is dead" .It Li "pane_height" Ta "" Ta "Height of pane" .It Li "pane_id" Ta "#D" Ta "Unique pane ID" diff --git a/tmux.h b/tmux.h index e18176e8..67192740 100644 --- a/tmux.h +++ b/tmux.h @@ -2317,7 +2317,6 @@ u_int utf8_split2(u_int, u_char *); /* procname.c */ char *get_proc_name(int, char *); -char *get_proc_cwd(int); /* log.c */ void log_open(int, const char *); From 0b77d17b35fad797b26632f3305dcd2c9b994a3f Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Oct 2013 23:31:03 +0000 Subject: [PATCH 43/47] Fix leak in format_get_command. --- format.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/format.c b/format.c index 40957a59..14dcd000 100644 --- a/format.c +++ b/format.c @@ -353,7 +353,7 @@ format_expand(struct format_tree *ft, const char *fmt) char * format_get_command(struct window_pane *wp) { - char *cmd; + char *cmd, *out; cmd = get_proc_name(wp->fd, wp->tty); if (cmd == NULL || *cmd == '\0') { @@ -361,7 +361,9 @@ format_get_command(struct window_pane *wp) if (cmd == NULL || *cmd == '\0') cmd = wp->shell; } - return (parse_window_name(cmd)); + out = parse_window_name(cmd); + free(cmd); + return (out); } /* Set default format keys for a session. */ From 17ec688ced8c1d6104cab700f9713cfa0fa1f858 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Oct 2013 23:31:28 +0000 Subject: [PATCH 44/47] Bracket in the wrong place in description of c0-change-trigger. --- tmux.1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tmux.1 b/tmux.1 index 4fb588e3..65849212 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2734,8 +2734,8 @@ instead redraw it entirely every .Ar interval milliseconds. This helps to prevent fast output (such as -.Xr yes 1 -overwhelming the terminal). +.Xr yes 1 ) +overwhelming the terminal. The default is a trigger of 250 and an interval of 100. A trigger of zero disables the rate limiting. .Pp From 98b81e983428c7770022c698a0c4ef3c7fc4ea36 Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 11 Oct 2013 08:03:43 +0000 Subject: [PATCH 45/47] And get it right this time... don't leak if it is an empty string either. --- format.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/format.c b/format.c index 14dcd000..bfc40906 100644 --- a/format.c +++ b/format.c @@ -357,9 +357,12 @@ format_get_command(struct window_pane *wp) cmd = get_proc_name(wp->fd, wp->tty); if (cmd == NULL || *cmd == '\0') { - cmd = wp->cmd; - if (cmd == NULL || *cmd == '\0') - cmd = wp->shell; + free(cmd); + cmd = xstrdup(wp->cmd); + if (cmd == NULL || *cmd == '\0') { + free(cmd); + cmd = xstrdup(wp->shell); + } } out = parse_window_name(cmd); free(cmd); From ffba21a60c26eefe5e4cb67dd290514fa3b5af17 Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 11 Oct 2013 08:06:03 +0000 Subject: [PATCH 46/47] Remove stray return, from Chris Johnsen. --- cmd-unbind-key.c | 1 - 1 file changed, 1 deletion(-) diff --git a/cmd-unbind-key.c b/cmd-unbind-key.c index b89340da..5d86665b 100644 --- a/cmd-unbind-key.c +++ b/cmd-unbind-key.c @@ -50,7 +50,6 @@ cmd_unbind_key_exec(struct cmd *self, struct cmd_q *cmdq) cmdq_error(cmdq, "missing key"); return (CMD_RETURN_ERROR); } - return (CMD_RETURN_ERROR); key = key_string_lookup_string(args->argv[0]); if (key == KEYC_NONE) { cmdq_error(cmdq, "unknown key: %s", args->argv[0]); From 4901d9ddc8d8c33ecdca363dcb67e66482745fa5 Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 11 Oct 2013 08:07:12 +0000 Subject: [PATCH 47/47] Don't leak file descriptors in the rare MSG_VERSION case. From Chris Johnsen. --- server-client.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server-client.c b/server-client.c index 6aa2a0fa..b6d4870d 100644 --- a/server-client.c +++ b/server-client.c @@ -808,6 +808,8 @@ server_client_msg_dispatch(struct client *c) if (imsg.hdr.peerid != PROTOCOL_VERSION) { server_write_client(c, MSG_VERSION, NULL, 0); c->flags |= CLIENT_BAD; + if (imsg.fd != -1) + close(imsg.fd); imsg_free(&imsg); continue; }