From cfb78654c2b9a9f0c2f90c22228563d5385c510c Mon Sep 17 00:00:00 2001 From: nicm Date: Sat, 2 Jan 2016 17:16:25 +0000 Subject: [PATCH 001/150] clock-mode needs CMD_PANE. --- cmd-copy-mode.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmd-copy-mode.c b/cmd-copy-mode.c index 1a006ebb..49f5b30c 100644 --- a/cmd-copy-mode.c +++ b/cmd-copy-mode.c @@ -46,6 +46,8 @@ const struct cmd_entry cmd_clock_mode_entry = { .args = { "t:", 0, 0 }, .usage = CMD_TARGET_PANE_USAGE, + .tflag = CMD_PANE, + .flags = 0, .exec = cmd_copy_mode_exec }; From 3a73f1735437ef08d32e3d14966f813a5ed7dfb9 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sat, 9 Jan 2016 21:35:13 -0500 Subject: [PATCH 002/150] Allow static linking --- .gitignore | 4 ++++ Makefile.static-build | 49 +++++++++++++++++++++++++++++++++++++++++++ configure.ac | 14 +++++++++++++ 3 files changed, 67 insertions(+) create mode 100644 Makefile.static-build diff --git a/.gitignore b/.gitignore index 0cd63730..93153ede 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,7 @@ cscope.* ctags *.log tmate.1.* +downloads/ +ext/ +libssh-*/ +msgpack-*/ diff --git a/Makefile.static-build b/Makefile.static-build new file mode 100644 index 00000000..cb16c961 --- /dev/null +++ b/Makefile.static-build @@ -0,0 +1,49 @@ +LIBSSH=libssh-0.7.2 +LIBSSH_URL=https://red.libssh.org/attachments/download/177/$(LIBSSH).tar.xz +LIBSSH_LIB=ext/lib/libssh.a + +MSGPACK=msgpack-1.3.0 +MSGPACK_URL=https://github.com/msgpack/msgpack-c/releases/download/cpp-1.3.0/$(MSGPACK).tar.gz +MSGPACK_LIB=ext/lib/libmsgpack.a + +TMATE_CONFIGURE=PKG_CONFIG_PATH=./ext/lib/pkgconfig + +all: tmate + +dependencies: + apt-get install build-essentials cmake libssl-dev autoconf automake pkg-config libtool libevent-dev libncurses-dev zlib1g-dev + +downloads/$(notdir $(LIBSSH_URL)): + mkdir -p downloads + wget -O $@ $(LIBSSH_URL) + +$(LIBSSH)/.ready: downloads/$(notdir $(LIBSSH_URL)) + tar xf $< + touch $@ + +downloads/$(notdir $(MSGPACK_URL)): + mkdir -p downloads + wget -O $@ $(MSGPACK_URL) + +$(MSGPACK)/.ready: downloads/$(notdir $(MSGPACK_URL)) + tar xf $< + touch $@ + +$(LIBSSH_LIB): $(LIBSSH)/.ready + mkdir -p $(LIBSSH)/build + cd $(LIBSSH)/build; ([ -f Makefile ] || cmake -DCMAKE_INSTALL_PREFIX:PATH=$(shell pwd)/ext .. -DWITH_SFTP=OFF -DWITH_SERVER=OFF -DWITH_PCAP=OFF -DWITH_STATIC_LIB=ON -DWITH_GSSAPI=OFF) + +make -C $(LIBSSH)/build install + +$(MSGPACK_LIB): $(MSGPACK)/.ready + mkdir -p $(MSGPACK)/build + cd $(MSGPACK)/build; ([ -f Makefile ] || cmake -DCMAKE_INSTALL_PREFIX:PATH=$(shell pwd)/ext ..) + +make -C $(MSGPACK)/build install + +tmate: $(MSGPACK_LIB) $(LIBSSH_LIB) + ./autogen.sh + $(TMATE_CONFIGURE) ./configure --enable-static + +make + +clean: + rm -rf ext $(LIBSSH) $(MSGPACK) + +make clean diff --git a/configure.ac b/configure.ac index e8074373..6c1c5b77 100644 --- a/configure.ac +++ b/configure.ac @@ -49,6 +49,20 @@ AC_ARG_ENABLE( if test "x$found_static" = xyes; then LDFLAGS="$LDFLAGS -static" PKG_CONFIG="pkg-config --static" + + CFLAGS="$CFLAGS -flto" + LDFLAGS="$LDFLAGS -flto" + + PKG_CHECK_MODULES([ZLIB], [zlib], [ + CPPFLAGS="$ZLIB_CFLAGS $CPPFLAGS" + LIBS="$ZLIB_LIBS $LIBS" + ]) + + PKG_CHECK_MODULES([LIBCRYPTO], [libcrypto], [ + CPPFLAGS="$LIBCRYPTO_CFLAGS $CPPFLAGS" + LIBS="$LIBCRYPTO_LIBS $LIBS" + ]) + AC_CHECK_LIB(dl, dlopen) fi # Is this gcc? From a2520da19591599538f8dc26b3bd6bf7a2619300 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sun, 10 Jan 2016 12:39:09 -0800 Subject: [PATCH 003/150] Fix static compilation (libc should be dynamically linked) --- Makefile.static-build | 2 +- configure.ac | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Makefile.static-build b/Makefile.static-build index cb16c961..809ac9db 100644 --- a/Makefile.static-build +++ b/Makefile.static-build @@ -11,7 +11,7 @@ TMATE_CONFIGURE=PKG_CONFIG_PATH=./ext/lib/pkgconfig all: tmate dependencies: - apt-get install build-essentials cmake libssl-dev autoconf automake pkg-config libtool libevent-dev libncurses-dev zlib1g-dev + apt-get install build-essential cmake libssl-dev autoconf automake pkg-config libtool libevent-dev libncurses-dev zlib1g-dev downloads/$(notdir $(LIBSSH_URL)): mkdir -p downloads diff --git a/configure.ac b/configure.ac index 6c1c5b77..663a51c5 100644 --- a/configure.ac +++ b/configure.ac @@ -47,13 +47,12 @@ AC_ARG_ENABLE( found_static=$enable_static ) if test "x$found_static" = xyes; then - LDFLAGS="$LDFLAGS -static" PKG_CONFIG="pkg-config --static" CFLAGS="$CFLAGS -flto" LDFLAGS="$LDFLAGS -flto" - PKG_CHECK_MODULES([ZLIB], [zlib], [ + PKG_CHECK_MODULES([ZLIB], [zlib], [ CPPFLAGS="$ZLIB_CFLAGS $CPPFLAGS" LIBS="$ZLIB_LIBS $LIBS" ]) @@ -62,7 +61,6 @@ if test "x$found_static" = xyes; then CPPFLAGS="$LIBCRYPTO_CFLAGS $CPPFLAGS" LIBS="$LIBCRYPTO_LIBS $LIBS" ]) - AC_CHECK_LIB(dl, dlopen) fi # Is this gcc? @@ -451,6 +449,11 @@ if test "x$found_getopt" != xno; then fi AM_CONDITIONAL(NO_GETOPT, [test "x$found_getopt" = xno]) +if test "x$found_static" = xyes; then + # libc and libdl should be dynamically linked. + LIBS="-Wl,-Bstatic ${LIBS/-ldl/} -Wl,-Bdynamic -ldl" +fi + # Check for BSD-style integer types. AC_MSG_CHECKING(for BSD-style unsigned types) AC_COMPILE_IFELSE([AC_LANG_SOURCE( From 6dc58ab6deef30020953882331c88ca6c80b4f2d Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Mon, 11 Jan 2016 02:20:10 -0800 Subject: [PATCH 004/150] Lower the required glib version to 2.8 for static builds --- Makefile.static-build | 15 +++++++++++++-- compat/clock_gettime.c | 9 +++++++++ compat/memcpy.c | 11 +++++++++++ configure.ac | 7 +++++++ 4 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 compat/clock_gettime.c create mode 100644 compat/memcpy.c diff --git a/Makefile.static-build b/Makefile.static-build index 809ac9db..6db26d76 100644 --- a/Makefile.static-build +++ b/Makefile.static-build @@ -8,6 +8,10 @@ MSGPACK_LIB=ext/lib/libmsgpack.a TMATE_CONFIGURE=PKG_CONFIG_PATH=./ext/lib/pkgconfig +LIBC=$(shell gcc -print-file-name=libc.a) +STATIC_LIBC_OBJECTS=fdelt_chk +STATIC_COMPAT_OBJECTS=memcpy clock_gettime + all: tmate dependencies: @@ -39,11 +43,18 @@ $(MSGPACK_LIB): $(MSGPACK)/.ready cd $(MSGPACK)/build; ([ -f Makefile ] || cmake -DCMAKE_INSTALL_PREFIX:PATH=$(shell pwd)/ext ..) +make -C $(MSGPACK)/build install -tmate: $(MSGPACK_LIB) $(LIBSSH_LIB) +libc/%.o: + mkdir -p libc + cd libc; ar x $(LIBC) $(notdir $@) + +compat/%.o: compat/%.c + gcc -c -o $@ $< + +tmate: $(MSGPACK_LIB) $(LIBSSH_LIB) $(patsubst %,libc/%.o,$(STATIC_LIBC_OBJECTS)) $(patsubst %,compat/%.o,$(STATIC_COMPAT_OBJECTS)) ./autogen.sh $(TMATE_CONFIGURE) ./configure --enable-static +make clean: - rm -rf ext $(LIBSSH) $(MSGPACK) + rm -rf ext libc $(LIBSSH) $(MSGPACK) +make clean diff --git a/compat/clock_gettime.c b/compat/clock_gettime.c new file mode 100644 index 00000000..0b631b79 --- /dev/null +++ b/compat/clock_gettime.c @@ -0,0 +1,9 @@ +#define _GNU_SOURCE +#include +#include +#include + +int clock_gettime(clockid_t clk_id, struct timespec *tp) +{ + return syscall(SYS_clock_gettime, clk_id, tp); +} diff --git a/compat/memcpy.c b/compat/memcpy.c new file mode 100644 index 00000000..37092a33 --- /dev/null +++ b/compat/memcpy.c @@ -0,0 +1,11 @@ +// http://stackoverflow.com/questions/8823267/linking-against-older-symbol-version-in-a-so-file + +#include + +/* some systems do not have newest memcpy@@GLIBC_2.14 - stay with old good one */ +asm (".symver memcpy, memcpy@GLIBC_2.2.5"); + +void *__wrap_memcpy(void *dest, const void *src, size_t n) +{ + return memcpy(dest, src, n); +} diff --git a/configure.ac b/configure.ac index 663a51c5..10d761bc 100644 --- a/configure.ac +++ b/configure.ac @@ -61,6 +61,7 @@ if test "x$found_static" = xyes; then CPPFLAGS="$LIBCRYPTO_CFLAGS $CPPFLAGS" LIBS="$LIBCRYPTO_LIBS $LIBS" ]) + # See more static settings below... (search for found_static) fi # Is this gcc? @@ -451,6 +452,12 @@ AM_CONDITIONAL(NO_GETOPT, [test "x$found_getopt" = xno]) if test "x$found_static" = xyes; then # libc and libdl should be dynamically linked. + # but we want to lower our requirements for libc's version. + # so we extract some symobls and add them here + if test `uname -m` = x86_64; then + LIBS="compat/memcpy.o -Wl,--wrap=memcpy $LIBS" + fi + LIBS="compat/clock_gettime.o libc/fdelt_chk.o $LIBS" LIBS="-Wl,-Bstatic ${LIBS/-ldl/} -Wl,-Bdynamic -ldl" fi From 68d797587ef2acf1464a9390912e4a22e4db6482 Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 15 Jan 2016 11:31:47 +0000 Subject: [PATCH 005/150] A couple of missing printflike attributes, from Andrey Starodubtsev. --- input.c | 2 +- tmux.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/input.c b/input.c index ed1ebffc..19fd48b7 100644 --- a/input.c +++ b/input.c @@ -100,7 +100,7 @@ struct input_ctx { struct input_transition; int input_split(struct input_ctx *); int input_get(struct input_ctx *, u_int, int, int); -void input_reply(struct input_ctx *, const char *, ...); +void printflike(2, 3) input_reply(struct input_ctx *, const char *, ...); void input_set_state(struct window_pane *, const struct input_transition *); void input_reset_cell(struct input_ctx *); diff --git a/tmux.h b/tmux.h index 194d01d8..dbea85bf 100644 --- a/tmux.h +++ b/tmux.h @@ -1540,7 +1540,7 @@ extern struct client *cfg_client; void start_cfg(void); int load_cfg(const char *, struct cmd_q *, char **); void set_cfg_file(const char *); -void cfg_add_cause(const char *, ...); +void printflike(1, 2) cfg_add_cause(const char *, ...); void cfg_print_causes(struct cmd_q *); void cfg_show_causes(struct session *); From d551ab8e5cfb00fbb7a79e7f0c3f4f2780fc6824 Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 15 Jan 2016 11:33:41 +0000 Subject: [PATCH 006/150] Clear the environment properly by looping until it is empty rather than looping over it (which may skip entries), from Brad King. --- environ.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/environ.c b/environ.c index de560896..101dfafd 100644 --- a/environ.c +++ b/environ.c @@ -196,10 +196,10 @@ void environ_push(struct environ *env) { struct environ_entry *envent; - char **vp, *v; + char *v; - for (vp = environ; *vp != NULL; vp++) { - v = xstrdup(*vp); + while (*environ != NULL) { + v = xstrdup(*environ); v[strcspn(v, "=")] = '\0'; unsetenv(v); From c1846177fc64bf52adecfb0e3350b43421564529 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Fri, 15 Jan 2016 16:02:42 -0500 Subject: [PATCH 007/150] Cleanup hacks around ev_ssh.ev_flags Fixes #69 Fix suggested by Leon M. George --- tmate-ssh-client.c | 36 +++++++++++++++++++++--------------- tmate.h | 1 + 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/tmate-ssh-client.c b/tmate-ssh-client.c index eb8a728b..691a49ce 100644 --- a/tmate-ssh-client.c +++ b/tmate-ssh-client.c @@ -162,18 +162,23 @@ static void request_passphrase(struct tmate_ssh_client *client) data->password_cb_private = client; } -static void register_session_fd_event(struct tmate_ssh_client *client) +static void init_conn_fd(struct tmate_ssh_client *client) { - if (!event_initialized(&client->ev_ssh)) { - int flag = 1; - setsockopt(ssh_get_fd(client->session), IPPROTO_TCP, - TCP_NODELAY, &flag, sizeof(flag)); + if (client->has_init_conn_fd) + return; - event_assign(&client->ev_ssh, client->tmate_session->ev_base, - ssh_get_fd(client->session), - EV_READ | EV_PERSIST, __on_ssh_client_event, client); - event_add(&client->ev_ssh, NULL); - } + if (ssh_get_fd(client->session) < 0) + return; + + int flag = 1; + setsockopt(ssh_get_fd(client->session), IPPROTO_TCP, + TCP_NODELAY, &flag, sizeof(flag)); + + event_set(&client->ev_ssh, ssh_get_fd(client->session), + EV_READ | EV_PERSIST, __on_ssh_client_event, client); + event_add(&client->ev_ssh, NULL); + + client->has_init_conn_fd = true; } static void on_ssh_client_event(struct tmate_ssh_client *client) @@ -232,14 +237,15 @@ static void on_ssh_client_event(struct tmate_ssh_client *client) case SSH_CONNECT: switch (ssh_connect(session)) { case SSH_AGAIN: - register_session_fd_event(client); + init_conn_fd(client); return; case SSH_ERROR: reconnect_ssh_client(client, "Error connecting: %s", ssh_get_error(session)); return; case SSH_OK: - register_session_fd_event(client); + init_conn_fd(client); + tmate_debug("Establishing connection to %s", client->server_ip); client->state = SSH_AUTH_SERVER; /* fall through */ @@ -383,9 +389,9 @@ static void __kill_ssh_client(struct tmate_ssh_client *client, else tmate_debug("Disconnecting %s", client->server_ip); - if (event_initialized(&client->ev_ssh)) { + if (client->has_init_conn_fd) { event_del(&client->ev_ssh); - client->ev_ssh.ev_flags = 0; + client->has_init_conn_fd = false; } if (client->session) { @@ -476,7 +482,7 @@ struct tmate_ssh_client *tmate_ssh_client_alloc(struct tmate_session *session, client->channel = NULL; client->has_encoder = 0; - client->ev_ssh.ev_flags = 0; + client->has_init_conn_fd = false; evtimer_assign(&client->ev_ssh_reconnect, session->ev_base, on_reconnect_timer, client); diff --git a/tmate.h b/tmate.h index 2018bbc3..98b109c4 100644 --- a/tmate.h +++ b/tmate.h @@ -132,6 +132,7 @@ struct tmate_ssh_client { ssh_session session; ssh_channel channel; + bool has_init_conn_fd; struct event ev_ssh; struct event ev_ssh_reconnect; }; From c9815307ebe8b729504d383904ae3ef3b862cf11 Mon Sep 17 00:00:00 2001 From: nicm Date: Sat, 16 Jan 2016 00:36:53 +0000 Subject: [PATCH 008/150] Add hooks for alerts (bell, silence, activity), from Thomas Adam. --- alerts.c | 23 ++++++++++++++++++++--- cmd-find.c | 16 ++++++++++++++++ tmux.1 | 10 ++++++++++ tmux.h | 2 ++ 4 files changed, 48 insertions(+), 3 deletions(-) diff --git a/alerts.c b/alerts.c index 536ea750..d1fb0fce 100644 --- a/alerts.c +++ b/alerts.c @@ -29,6 +29,7 @@ int alerts_enabled(struct window *, int); void alerts_callback(int, short, void *); void alerts_reset(struct window *); +void alerts_run_hook(struct session *, struct winlink *, int); int alerts_check_all(struct session *, struct winlink *); int alerts_check_bell(struct session *, struct winlink *); int alerts_check_activity(struct session *, struct winlink *); @@ -55,8 +56,6 @@ alerts_callback(__unused int fd, __unused short events, __unused void *arg) RB_FOREACH(w, windows, &windows) { RB_FOREACH(s, sessions, &sessions) { - if (s->flags & SESSION_UNATTACHED) - continue; RB_FOREACH(wl, winlinks, &s->windows) { if (wl->window != w) continue; @@ -73,6 +72,22 @@ alerts_callback(__unused int fd, __unused short events, __unused void *arg) alerts_fired = 0; } +void +alerts_run_hook(struct session *s, struct winlink *wl, int flags) +{ + struct cmd_find_state fs; + + if (cmd_find_from_winlink(&fs, s, wl) != 0) + return; + + if (flags & WINDOW_BELL) + hooks_run(s->hooks, NULL, &fs, "alert-bell"); + if (flags & WINDOW_SILENCE) + hooks_run(s->hooks, NULL, &fs, "alert-silence"); + if (flags & WINDOW_ACTIVITY) + hooks_run(s->hooks, NULL, &fs, "alert-activity"); +} + int alerts_check_all(struct session *s, struct winlink *wl) { @@ -81,8 +96,10 @@ alerts_check_all(struct session *s, struct winlink *wl) alerts = alerts_check_bell(s, wl); alerts |= alerts_check_activity(s, wl); alerts |= alerts_check_silence(s, wl); - if (alerts != 0) + if (alerts != 0) { + alerts_run_hook(s, wl, alerts); server_status_session(s); + } return (alerts); } diff --git a/cmd-find.c b/cmd-find.c index 9b1ca517..68aaf121 100644 --- a/cmd-find.c +++ b/cmd-find.c @@ -879,6 +879,22 @@ cmd_find_from_session(struct cmd_find_state *fs, struct session *s) return (0); } +/* Find state from a winlink. */ +int +cmd_find_from_winlink(struct cmd_find_state *fs, struct session *s, + struct winlink *wl) +{ + cmd_find_clear_state(fs, NULL, 0); + + fs->s = s; + fs->wl = wl; + fs->w = wl->window; + fs->wp = wl->window->active; + + cmd_find_log_state(__func__, fs); + return (0); +} + /* Find state from a window. */ int cmd_find_from_window(struct cmd_find_state *fs, struct window *w) diff --git a/tmux.1 b/tmux.1 index 9017b4e7..159a4bd9 100644 --- a/tmux.1 +++ b/tmux.1 @@ -3224,6 +3224,16 @@ Each hook has a .Em name . The following hooks are available: .Bl -tag -width "XXXXXXXXXXXXXXXX" +.It alert-activity +Run when a window has activity. +See +.Ic monitor-activity . +.It alert-bell +Run when a window has received a bell. +.It alert-silence +Run when a window has been silent. +See +.Ic monitor-silence . .It client-attached Run when a client is attached. .It client-detached diff --git a/tmux.h b/tmux.h index dbea85bf..55fe407f 100644 --- a/tmux.h +++ b/tmux.h @@ -1780,6 +1780,8 @@ void cmd_find_copy_state(struct cmd_find_state *, void cmd_find_log_state(const char *, struct cmd_find_state *); int cmd_find_from_session(struct cmd_find_state *, struct session *); +int cmd_find_from_winlink(struct cmd_find_state *, + struct session *, struct winlink *); int cmd_find_from_window(struct cmd_find_state *, struct window *); int cmd_find_from_pane(struct cmd_find_state *, struct window_pane *); From 995af0e2b72aec54ba3685b1a8ce5e78d279d8ff Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 19 Jan 2016 15:59:12 +0000 Subject: [PATCH 009/150] I no longer use my SourceForge address so replace it. --- alerts.c | 2 +- arguments.c | 2 +- array.h | 2 +- cfg.c | 2 +- client.c | 2 +- cmd-attach-session.c | 2 +- cmd-bind-key.c | 2 +- cmd-break-pane.c | 2 +- cmd-choose-buffer.c | 2 +- cmd-choose-client.c | 2 +- cmd-clear-history.c | 2 +- cmd-command-prompt.c | 2 +- cmd-copy-mode.c | 2 +- cmd-detach-client.c | 2 +- cmd-display-panes.c | 2 +- cmd-find-window.c | 2 +- cmd-find.c | 2 +- cmd-join-pane.c | 2 +- cmd-kill-pane.c | 2 +- cmd-kill-server.c | 2 +- cmd-kill-session.c | 2 +- cmd-kill-window.c | 2 +- cmd-list-buffers.c | 2 +- cmd-list-clients.c | 2 +- cmd-list-keys.c | 2 +- cmd-list-panes.c | 2 +- cmd-list-sessions.c | 2 +- cmd-list-windows.c | 2 +- cmd-list.c | 2 +- cmd-lock-server.c | 2 +- cmd-move-window.c | 2 +- cmd-new-session.c | 2 +- cmd-new-window.c | 2 +- cmd-paste-buffer.c | 2 +- cmd-pipe-pane.c | 2 +- cmd-queue.c | 2 +- cmd-refresh-client.c | 2 +- cmd-rename-session.c | 2 +- cmd-rename-window.c | 2 +- cmd-resize-pane.c | 2 +- cmd-respawn-pane.c | 2 +- cmd-respawn-window.c | 2 +- cmd-rotate-window.c | 2 +- cmd-select-layout.c | 2 +- cmd-select-pane.c | 2 +- cmd-select-window.c | 2 +- cmd-send-keys.c | 2 +- cmd-set-buffer.c | 2 +- cmd-set-environment.c | 2 +- cmd-set-option.c | 2 +- cmd-show-environment.c | 2 +- cmd-show-messages.c | 2 +- cmd-show-options.c | 2 +- cmd-split-window.c | 2 +- cmd-string.c | 2 +- cmd-swap-pane.c | 2 +- cmd-swap-window.c | 2 +- cmd-switch-client.c | 2 +- cmd-unbind-key.c | 2 +- cmd-wait-for.c | 2 +- cmd.c | 2 +- colour.c | 2 +- control-notify.c | 2 +- control.c | 2 +- environ.c | 2 +- format.c | 2 +- grid-view.c | 2 +- grid.c | 2 +- input-keys.c | 2 +- input.c | 2 +- job.c | 2 +- key-bindings.c | 2 +- key-string.c | 2 +- layout-custom.c | 2 +- layout-set.c | 2 +- layout.c | 2 +- log.c | 2 +- mode-key.c | 2 +- names.c | 2 +- options-table.c | 2 +- options.c | 2 +- paste.c | 2 +- proc.c | 2 +- procname.c | 2 +- resize.c | 2 +- screen-redraw.c | 2 +- screen-write.c | 2 +- screen.c | 2 +- server-client.c | 2 +- server-fn.c | 2 +- server.c | 2 +- session.c | 2 +- signal.c | 2 +- status.c | 2 +- style.c | 2 +- tmux.1 | 4 ++-- tmux.c | 2 +- tmux.h | 2 +- tty-acs.c | 2 +- tty-keys.c | 2 +- tty-term.c | 2 +- tty.c | 2 +- utf8.c | 2 +- window-choose.c | 2 +- window-clock.c | 2 +- window-copy.c | 2 +- window.c | 2 +- xterm-keys.c | 2 +- 108 files changed, 109 insertions(+), 109 deletions(-) diff --git a/alerts.c b/alerts.c index d1fb0fce..cca0d815 100644 --- a/alerts.c +++ b/alerts.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2015 Nicholas Marriott + * Copyright (c) 2015 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/arguments.c b/arguments.c index 0a42cc38..501f38df 100644 --- a/arguments.c +++ b/arguments.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2010 Nicholas Marriott + * Copyright (c) 2010 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/array.h b/array.h index 671bea42..209de0c5 100644 --- a/array.h +++ b/array.h @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2006 Nicholas Marriott + * Copyright (c) 2006 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cfg.c b/cfg.c index 136c94d1..c5c21b94 100644 --- a/cfg.c +++ b/cfg.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2008 Nicholas Marriott + * Copyright (c) 2008 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/client.c b/client.c index 516ed3bf..ed15bc80 100644 --- a/client.c +++ b/client.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2007 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-attach-session.c b/cmd-attach-session.c index 993f4c75..53c1df31 100644 --- a/cmd-attach-session.c +++ b/cmd-attach-session.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2007 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-bind-key.c b/cmd-bind-key.c index df3285f7..a829a2c5 100644 --- a/cmd-bind-key.c +++ b/cmd-bind-key.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2007 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-break-pane.c b/cmd-break-pane.c index c2b021fc..b5a2743f 100644 --- a/cmd-break-pane.c +++ b/cmd-break-pane.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2009 Nicholas Marriott + * Copyright (c) 2009 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-choose-buffer.c b/cmd-choose-buffer.c index 1f8fbfb2..90872e90 100644 --- a/cmd-choose-buffer.c +++ b/cmd-choose-buffer.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2010 Nicholas Marriott + * Copyright (c) 2010 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-choose-client.c b/cmd-choose-client.c index 7d5fc606..b9a24be6 100644 --- a/cmd-choose-client.c +++ b/cmd-choose-client.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2009 Nicholas Marriott + * Copyright (c) 2009 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-clear-history.c b/cmd-clear-history.c index 1236e7f1..62683ff6 100644 --- a/cmd-clear-history.c +++ b/cmd-clear-history.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2009 Nicholas Marriott + * Copyright (c) 2009 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-command-prompt.c b/cmd-command-prompt.c index 9200ada1..3ec22865 100644 --- a/cmd-command-prompt.c +++ b/cmd-command-prompt.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2008 Nicholas Marriott + * Copyright (c) 2008 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-copy-mode.c b/cmd-copy-mode.c index 49f5b30c..beb4d7c8 100644 --- a/cmd-copy-mode.c +++ b/cmd-copy-mode.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2007 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-detach-client.c b/cmd-detach-client.c index daf9a5c6..80c6555f 100644 --- a/cmd-detach-client.c +++ b/cmd-detach-client.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2007 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-display-panes.c b/cmd-display-panes.c index d8db4066..eed3611e 100644 --- a/cmd-display-panes.c +++ b/cmd-display-panes.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2009 Nicholas Marriott + * Copyright (c) 2009 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-find-window.c b/cmd-find-window.c index eb940d8c..6324f26a 100644 --- a/cmd-find-window.c +++ b/cmd-find-window.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2009 Nicholas Marriott + * Copyright (c) 2009 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-find.c b/cmd-find.c index 68aaf121..c76dc4a2 100644 --- a/cmd-find.c +++ b/cmd-find.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2015 Nicholas Marriott + * Copyright (c) 2015 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-join-pane.c b/cmd-join-pane.c index 8b4117fa..d630dd45 100644 --- a/cmd-join-pane.c +++ b/cmd-join-pane.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2011 George Nachman - * Copyright (c) 2009 Nicholas Marriott + * Copyright (c) 2009 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-kill-pane.c b/cmd-kill-pane.c index f843bc58..ebb2b8d6 100644 --- a/cmd-kill-pane.c +++ b/cmd-kill-pane.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2009 Nicholas Marriott + * Copyright (c) 2009 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-kill-server.c b/cmd-kill-server.c index 6f84e959..d1940c33 100644 --- a/cmd-kill-server.c +++ b/cmd-kill-server.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2007 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-kill-session.c b/cmd-kill-session.c index 4ca4e2c8..c77e45bb 100644 --- a/cmd-kill-session.c +++ b/cmd-kill-session.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2007 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-kill-window.c b/cmd-kill-window.c index 7a8e9fa6..9d388ce5 100644 --- a/cmd-kill-window.c +++ b/cmd-kill-window.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2007 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-list-buffers.c b/cmd-list-buffers.c index a6007c33..238b2776 100644 --- a/cmd-list-buffers.c +++ b/cmd-list-buffers.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2007 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-list-clients.c b/cmd-list-clients.c index 75c6f570..f318ac18 100644 --- a/cmd-list-clients.c +++ b/cmd-list-clients.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2007 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-list-keys.c b/cmd-list-keys.c index 4abe2473..c3ace8de 100644 --- a/cmd-list-keys.c +++ b/cmd-list-keys.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2007 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-list-panes.c b/cmd-list-panes.c index da0e0962..76e06a71 100644 --- a/cmd-list-panes.c +++ b/cmd-list-panes.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2009 Nicholas Marriott + * Copyright (c) 2009 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-list-sessions.c b/cmd-list-sessions.c index 1fde7f86..27e80dbc 100644 --- a/cmd-list-sessions.c +++ b/cmd-list-sessions.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2007 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-list-windows.c b/cmd-list-windows.c index dd05ea85..11a5fddf 100644 --- a/cmd-list-windows.c +++ b/cmd-list-windows.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2007 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-list.c b/cmd-list.c index 59fc7796..e999c370 100644 --- a/cmd-list.c +++ b/cmd-list.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2009 Nicholas Marriott + * Copyright (c) 2009 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-lock-server.c b/cmd-lock-server.c index 9cdd816f..01597169 100644 --- a/cmd-lock-server.c +++ b/cmd-lock-server.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2008 Nicholas Marriott + * Copyright (c) 2008 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-move-window.c b/cmd-move-window.c index bb33ab38..e756a638 100644 --- a/cmd-move-window.c +++ b/cmd-move-window.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2008 Nicholas Marriott + * Copyright (c) 2008 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-new-session.c b/cmd-new-session.c index f96003c7..b4bb37d5 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2007 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-new-window.c b/cmd-new-window.c index 33f68935..2a647b9f 100644 --- a/cmd-new-window.c +++ b/cmd-new-window.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2007 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-paste-buffer.c b/cmd-paste-buffer.c index 0728743a..8025975f 100644 --- a/cmd-paste-buffer.c +++ b/cmd-paste-buffer.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2007 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-pipe-pane.c b/cmd-pipe-pane.c index a2653dc5..e59fc586 100644 --- a/cmd-pipe-pane.c +++ b/cmd-pipe-pane.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2009 Nicholas Marriott + * Copyright (c) 2009 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-queue.c b/cmd-queue.c index 5bc3226a..fcca7eb6 100644 --- a/cmd-queue.c +++ b/cmd-queue.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2013 Nicholas Marriott + * Copyright (c) 2013 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-refresh-client.c b/cmd-refresh-client.c index 444e83fc..79e5aad0 100644 --- a/cmd-refresh-client.c +++ b/cmd-refresh-client.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2007 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-rename-session.c b/cmd-rename-session.c index 7fc6193d..b40f44f7 100644 --- a/cmd-rename-session.c +++ b/cmd-rename-session.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2007 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-rename-window.c b/cmd-rename-window.c index 36c1bf31..a1f15eef 100644 --- a/cmd-rename-window.c +++ b/cmd-rename-window.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2007 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-resize-pane.c b/cmd-resize-pane.c index bb29cef9..2b4f1c17 100644 --- a/cmd-resize-pane.c +++ b/cmd-resize-pane.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2009 Nicholas Marriott + * Copyright (c) 2009 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-respawn-pane.c b/cmd-respawn-pane.c index bff6c11b..ba2c1cd2 100644 --- a/cmd-respawn-pane.c +++ b/cmd-respawn-pane.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2008 Nicholas Marriott + * Copyright (c) 2008 Nicholas Marriott * Copyright (c) 2011 Marcel P. Partap * * Permission to use, copy, modify, and distribute this software for any diff --git a/cmd-respawn-window.c b/cmd-respawn-window.c index da9a365a..95fc0cb4 100644 --- a/cmd-respawn-window.c +++ b/cmd-respawn-window.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2008 Nicholas Marriott + * Copyright (c) 2008 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-rotate-window.c b/cmd-rotate-window.c index 014c1f2f..94eca37d 100644 --- a/cmd-rotate-window.c +++ b/cmd-rotate-window.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2009 Nicholas Marriott + * Copyright (c) 2009 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-select-layout.c b/cmd-select-layout.c index e6ede1af..44f01bb7 100644 --- a/cmd-select-layout.c +++ b/cmd-select-layout.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2009 Nicholas Marriott + * Copyright (c) 2009 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-select-pane.c b/cmd-select-pane.c index 02385a41..14d53d48 100644 --- a/cmd-select-pane.c +++ b/cmd-select-pane.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2009 Nicholas Marriott + * Copyright (c) 2009 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-select-window.c b/cmd-select-window.c index 82acc859..78228067 100644 --- a/cmd-select-window.c +++ b/cmd-select-window.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2007 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-send-keys.c b/cmd-send-keys.c index 7b0b952c..92c75ec3 100644 --- a/cmd-send-keys.c +++ b/cmd-send-keys.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2008 Nicholas Marriott + * Copyright (c) 2008 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-set-buffer.c b/cmd-set-buffer.c index 1494cf26..1f0cf3d8 100644 --- a/cmd-set-buffer.c +++ b/cmd-set-buffer.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2007 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-set-environment.c b/cmd-set-environment.c index f701d7d9..55bdaa9a 100644 --- a/cmd-set-environment.c +++ b/cmd-set-environment.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2009 Nicholas Marriott + * Copyright (c) 2009 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-set-option.c b/cmd-set-option.c index 13de02a3..7fc81286 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2007 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-show-environment.c b/cmd-show-environment.c index 54baafe4..83661c44 100644 --- a/cmd-show-environment.c +++ b/cmd-show-environment.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2009 Nicholas Marriott + * Copyright (c) 2009 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-show-messages.c b/cmd-show-messages.c index 68ef6674..3131184d 100644 --- a/cmd-show-messages.c +++ b/cmd-show-messages.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2009 Nicholas Marriott + * Copyright (c) 2009 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-show-options.c b/cmd-show-options.c index e99574f8..fec2f1de 100644 --- a/cmd-show-options.c +++ b/cmd-show-options.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2007 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-split-window.c b/cmd-split-window.c index aee323eb..8382d78e 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2009 Nicholas Marriott + * Copyright (c) 2009 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-string.c b/cmd-string.c index 51554800..757d4cdb 100644 --- a/cmd-string.c +++ b/cmd-string.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2008 Nicholas Marriott + * Copyright (c) 2008 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-swap-pane.c b/cmd-swap-pane.c index 84332c2f..aec7753d 100644 --- a/cmd-swap-pane.c +++ b/cmd-swap-pane.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2009 Nicholas Marriott + * Copyright (c) 2009 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-swap-window.c b/cmd-swap-window.c index e1835820..14907d2d 100644 --- a/cmd-swap-window.c +++ b/cmd-swap-window.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2007 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-switch-client.c b/cmd-switch-client.c index bc9f5585..6e2ee2a0 100644 --- a/cmd-switch-client.c +++ b/cmd-switch-client.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2007 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-unbind-key.c b/cmd-unbind-key.c index 8e89f21a..7452fd9f 100644 --- a/cmd-unbind-key.c +++ b/cmd-unbind-key.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2007 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/cmd-wait-for.c b/cmd-wait-for.c index 59f7dbfb..81b01627 100644 --- a/cmd-wait-for.c +++ b/cmd-wait-for.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2013 Nicholas Marriott + * Copyright (c) 2013 Nicholas Marriott * Copyright (c) 2013 Thiago de Arruda * * Permission to use, copy, modify, and distribute this software for any diff --git a/cmd.c b/cmd.c index 4f1e1b90..052c095b 100644 --- a/cmd.c +++ b/cmd.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2007 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/colour.c b/colour.c index a56ddce9..b349e2a5 100644 --- a/colour.c +++ b/colour.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2008 Nicholas Marriott + * Copyright (c) 2008 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/control-notify.c b/control-notify.c index a40f8d7c..c28d0fc8 100644 --- a/control-notify.c +++ b/control-notify.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2012 Nicholas Marriott + * Copyright (c) 2012 Nicholas Marriott * Copyright (c) 2012 George Nachman * * Permission to use, copy, modify, and distribute this software for any diff --git a/control.c b/control.c index e799a4cb..f6dedca8 100644 --- a/control.c +++ b/control.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2012 Nicholas Marriott + * Copyright (c) 2012 Nicholas Marriott * Copyright (c) 2012 George Nachman * * Permission to use, copy, modify, and distribute this software for any diff --git a/environ.c b/environ.c index 101dfafd..d855f8b5 100644 --- a/environ.c +++ b/environ.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2009 Nicholas Marriott + * Copyright (c) 2009 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/format.c b/format.c index 79445936..efa9d1e1 100644 --- a/format.c +++ b/format.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2011 Nicholas Marriott + * Copyright (c) 2011 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/grid-view.c b/grid-view.c index f6708c89..0989f800 100644 --- a/grid-view.c +++ b/grid-view.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2008 Nicholas Marriott + * Copyright (c) 2008 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/grid.c b/grid.c index 579eb966..c24e6c6a 100644 --- a/grid.c +++ b/grid.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2008 Nicholas Marriott + * Copyright (c) 2008 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/input-keys.c b/input-keys.c index 3bc1f812..254845cb 100644 --- a/input-keys.c +++ b/input-keys.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2007 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/input.c b/input.c index 19fd48b7..1772a4cd 100644 --- a/input.c +++ b/input.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2007 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/job.c b/job.c index e9799956..d6541709 100644 --- a/job.c +++ b/job.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2009 Nicholas Marriott + * Copyright (c) 2009 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/key-bindings.c b/key-bindings.c index 47a7d867..a922eb18 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2007 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/key-string.c b/key-string.c index 1ff3ca30..dc211696 100644 --- a/key-string.c +++ b/key-string.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2007 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/layout-custom.c b/layout-custom.c index 57503518..99c6c3ce 100644 --- a/layout-custom.c +++ b/layout-custom.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2010 Nicholas Marriott + * Copyright (c) 2010 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/layout-set.c b/layout-set.c index 852ec0f6..bd1304ce 100644 --- a/layout-set.c +++ b/layout-set.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2009 Nicholas Marriott + * Copyright (c) 2009 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/layout.c b/layout.c index c448814a..31dce95c 100644 --- a/layout.c +++ b/layout.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2009 Nicholas Marriott + * Copyright (c) 2009 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/log.c b/log.c index 46f1673c..9729a4dd 100644 --- a/log.c +++ b/log.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2007 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/mode-key.c b/mode-key.c index a47cda0b..f38ebf66 100644 --- a/mode-key.c +++ b/mode-key.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2008 Nicholas Marriott + * Copyright (c) 2008 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/names.c b/names.c index 3c25e215..a03f6f5b 100644 --- a/names.c +++ b/names.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2009 Nicholas Marriott + * Copyright (c) 2009 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/options-table.c b/options-table.c index 63e7ab61..af0f41ed 100644 --- a/options-table.c +++ b/options-table.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2011 Nicholas Marriott + * Copyright (c) 2011 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/options.c b/options.c index 02f0f957..df79ac4b 100644 --- a/options.c +++ b/options.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2008 Nicholas Marriott + * Copyright (c) 2008 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/paste.c b/paste.c index 5f60914f..f5702438 100644 --- a/paste.c +++ b/paste.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2007 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/proc.c b/proc.c index 5f51b0ac..bc27b4ff 100644 --- a/proc.c +++ b/proc.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2015 Nicholas Marriott + * Copyright (c) 2015 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/procname.c b/procname.c index 97a78d71..42f5f473 100644 --- a/procname.c +++ b/procname.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2009 Nicholas Marriott + * Copyright (c) 2009 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/resize.c b/resize.c index c7805e05..831302b1 100644 --- a/resize.c +++ b/resize.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2007 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/screen-redraw.c b/screen-redraw.c index 9958d04a..952a8515 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2007 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/screen-write.c b/screen-write.c index e53d3799..05315b3f 100644 --- a/screen-write.c +++ b/screen-write.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2007 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/screen.c b/screen.c index db9f52a6..e002b96e 100644 --- a/screen.c +++ b/screen.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2007 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/server-client.c b/server-client.c index 9b88a165..bb54643a 100644 --- a/server-client.c +++ b/server-client.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2009 Nicholas Marriott + * Copyright (c) 2009 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/server-fn.c b/server-fn.c index 0f35aaaf..39d31f3c 100644 --- a/server-fn.c +++ b/server-fn.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2007 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/server.c b/server.c index 170244c7..890743f6 100644 --- a/server.c +++ b/server.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2007 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/session.c b/session.c index b3ae2b42..7f2c3d97 100644 --- a/session.c +++ b/session.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2007 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/signal.c b/signal.c index 9a4d58c2..19938638 100644 --- a/signal.c +++ b/signal.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2007 Nicholas Marriott * Copyright (c) 2010 Romain Francoise * * Permission to use, copy, modify, and distribute this software for any diff --git a/status.c b/status.c index cbacfe4c..1bd02c43 100644 --- a/status.c +++ b/status.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2007 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/style.c b/style.c index c00b0fee..151c2912 100644 --- a/style.c +++ b/style.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2007 Nicholas Marriott * Copyright (c) 2014 Tiago Cunha * * Permission to use, copy, modify, and distribute this software for any diff --git a/tmux.1 b/tmux.1 index 159a4bd9..e41ba798 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1,6 +1,6 @@ .\" $OpenBSD$ .\" -.\" Copyright (c) 2007 Nicholas Marriott +.\" Copyright (c) 2007 Nicholas Marriott .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above @@ -4248,4 +4248,4 @@ bind-key S command-prompt "new-window -n %1 'ssh %1'" .Sh SEE ALSO .Xr pty 4 .Sh AUTHORS -.An Nicholas Marriott Aq Mt nicm@users.sourceforge.net +.An Nicholas Marriott Aq Mt nicholas.marriott@gmail.com diff --git a/tmux.c b/tmux.c index fe5e54a5..1ee2a269 100644 --- a/tmux.c +++ b/tmux.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2007 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/tmux.h b/tmux.h index 55fe407f..941548d0 100644 --- a/tmux.h +++ b/tmux.h @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2007 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/tty-acs.c b/tty-acs.c index 5d03c3eb..7fd265d4 100644 --- a/tty-acs.c +++ b/tty-acs.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2010 Nicholas Marriott + * Copyright (c) 2010 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/tty-keys.c b/tty-keys.c index 86839a17..2b998778 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2007 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/tty-term.c b/tty-term.c index 27c904a4..8716a1a9 100644 --- a/tty-term.c +++ b/tty-term.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2008 Nicholas Marriott + * Copyright (c) 2008 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/tty.c b/tty.c index 304e1378..52521be9 100644 --- a/tty.c +++ b/tty.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2007 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/utf8.c b/utf8.c index 2210675a..b03c425d 100644 --- a/utf8.c +++ b/utf8.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2008 Nicholas Marriott + * Copyright (c) 2008 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/window-choose.c b/window-choose.c index fdfc47a0..7a727aac 100644 --- a/window-choose.c +++ b/window-choose.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2009 Nicholas Marriott + * Copyright (c) 2009 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/window-clock.c b/window-clock.c index e8451f22..4cc58684 100644 --- a/window-clock.c +++ b/window-clock.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2009 Nicholas Marriott + * Copyright (c) 2009 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/window-copy.c b/window-copy.c index e09a504c..c8e38fd1 100644 --- a/window-copy.c +++ b/window-copy.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2007 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/window.c b/window.c index cfb44ae3..201942a3 100644 --- a/window.c +++ b/window.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2007 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/xterm-keys.c b/xterm-keys.c index f1490fcc..7bfefd15 100644 --- a/xterm-keys.c +++ b/xterm-keys.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2009 Nicholas Marriott + * Copyright (c) 2009 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above From b5b5221c13ded5b141fa35f60c707c9c403b83a6 Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 19 Jan 2016 16:01:30 +0000 Subject: [PATCH 010/150] Split out getting the current state from the target search so it can be replaced if we already know the current. --- cmd-find.c | 29 +++++++------ cmd-queue.c | 2 +- cmd.c | 118 ++++++++++++++++++++++++++++++++++++---------------- tmux.h | 10 +++-- 4 files changed, 106 insertions(+), 53 deletions(-) diff --git a/cmd-find.c b/cmd-find.c index c76dc4a2..7ffc5f15 100644 --- a/cmd-find.c +++ b/cmd-find.c @@ -923,15 +923,27 @@ cmd_find_from_pane(struct cmd_find_state *fs, struct window_pane *wp) return (0); } +/* Find current state. */ +int +cmd_find_current(struct cmd_find_state *fs, struct cmd_q *cmdq, int flags) +{ + cmd_find_clear_state(fs, cmdq, flags); + if (cmd_find_current_session(fs) != 0) { + if (~flags & CMD_FIND_QUIET) + cmdq_error(cmdq, "no current session"); + return (-1); + } + return (0); +} + /* * Split target into pieces and resolve for the given type. Fills in the given * state. Returns 0 on success or -1 on error. */ int -cmd_find_target(struct cmd_find_state *fs, struct cmd_q *cmdq, - const char *target, enum cmd_find_type type, int flags) +cmd_find_target(struct cmd_find_state *fs, struct cmd_find_state *current, + struct cmd_q *cmdq, const char *target, enum cmd_find_type type, int flags) { - struct cmd_find_state current; struct mouse_event *m; char *colon, *period, *copy = NULL; const char *session, *window, *pane; @@ -951,15 +963,8 @@ cmd_find_target(struct cmd_find_state *fs, struct cmd_q *cmdq, fs->current = &marked_pane; else if (cmd_find_valid_state(&cmdq->current)) fs->current = &cmdq->current; - else { - cmd_find_clear_state(¤t, cmdq, flags); - if (cmd_find_current_session(¤t) != 0) { - if (~flags & CMD_FIND_QUIET) - cmdq_error(cmdq, "no current session"); - goto error; - } - fs->current = ¤t; - } + else + fs->current = current; /* An empty or NULL target is the current. */ if (target == NULL || *target == '\0') diff --git a/cmd-queue.c b/cmd-queue.c index fcca7eb6..1c80c59d 100644 --- a/cmd-queue.c +++ b/cmd-queue.c @@ -199,7 +199,7 @@ cmdq_continue_one(struct cmd_q *cmdq) cmdq_guard(cmdq, "begin", flags); - if (cmd_prepare_state(cmd, cmdq) != 0) + if (cmd_prepare_state(cmd, cmdq, NULL) != 0) goto error; retval = cmd->entry->exec(cmd, cmdq); if (retval == CMD_RETURN_ERROR) diff --git a/cmd.c b/cmd.c index 052c095b..005f2a0f 100644 --- a/cmd.c +++ b/cmd.c @@ -389,10 +389,23 @@ usage: } static int -cmd_prepare_state_flag(struct cmd_find_state *fs, enum cmd_entry_flag flag, - const char *target, struct cmd_q *cmdq) +cmd_prepare_state_flag(char c, const char *target, enum cmd_entry_flag flag, + struct cmd_q *cmdq, struct cmd_q *parent) { - int targetflags, error; + int targetflags, error; + struct cmd_find_state *fs = NULL; + struct cmd_find_state *current = NULL; + struct cmd_find_state tmp; + + if (flag == CMD_NONE || + flag == CMD_CLIENT || + flag == CMD_CLIENT_CANFAIL) + return (0); + + if (c == 't') + fs = &cmdq->state.tflag; + else if (c == 's') + fs = &cmdq->state.sflag; if (flag == CMD_SESSION_WITHPANE) { if (target != NULL && target[strcspn(target, ":.")] != '\0') @@ -401,6 +414,55 @@ cmd_prepare_state_flag(struct cmd_find_state *fs, enum cmd_entry_flag flag, flag = CMD_SESSION; } + targetflags = 0; + switch (flag) { + case CMD_SESSION: + case CMD_SESSION_CANFAIL: + case CMD_SESSION_PREFERUNATTACHED: + if (flag == CMD_SESSION_CANFAIL) + targetflags |= CMD_FIND_QUIET; + if (flag == CMD_SESSION_PREFERUNATTACHED) + targetflags |= CMD_FIND_PREFER_UNATTACHED; + break; + case CMD_MOVEW_R: + flag = CMD_WINDOW_INDEX; + /* FALLTHROUGH */ + case CMD_WINDOW: + case CMD_WINDOW_CANFAIL: + case CMD_WINDOW_MARKED: + case CMD_WINDOW_INDEX: + if (flag == CMD_WINDOW_CANFAIL) + targetflags |= CMD_FIND_QUIET; + if (flag == CMD_WINDOW_MARKED) + targetflags |= CMD_FIND_DEFAULT_MARKED; + if (flag == CMD_WINDOW_INDEX) + targetflags |= CMD_FIND_WINDOW_INDEX; + break; + case CMD_PANE: + case CMD_PANE_CANFAIL: + case CMD_PANE_MARKED: + if (flag == CMD_PANE_CANFAIL) + targetflags |= CMD_FIND_QUIET; + if (flag == CMD_PANE_MARKED) + targetflags |= CMD_FIND_DEFAULT_MARKED; + break; + default: + fatalx("unknown %cflag %d", c, flag); + } + + log_debug("%s: flag %c %d %#x", __func__, c, flag, targetflags); + if (parent != NULL) { + if (c == 't') + current = &parent->state.tflag; + else if (c == 's') + current = &parent->state.sflag; + } else { + error = cmd_find_current(&tmp, cmdq, targetflags); + if (error != 0 && ~targetflags & CMD_FIND_QUIET) + return (-1); + current = &tmp; + } + switch (flag) { case CMD_NONE: case CMD_CLIENT: @@ -410,20 +472,14 @@ cmd_prepare_state_flag(struct cmd_find_state *fs, enum cmd_entry_flag flag, case CMD_SESSION_CANFAIL: case CMD_SESSION_PREFERUNATTACHED: case CMD_SESSION_WITHPANE: - targetflags = 0; - if (flag == CMD_SESSION_CANFAIL) - targetflags |= CMD_FIND_QUIET; - if (flag == CMD_SESSION_PREFERUNATTACHED) - targetflags |= CMD_FIND_PREFER_UNATTACHED; - - error = cmd_find_target(fs, cmdq, target, CMD_FIND_SESSION, - targetflags); - if (error != 0 && flag != CMD_SESSION_CANFAIL) + error = cmd_find_target(fs, current, cmdq, target, + CMD_FIND_SESSION, targetflags); + if (error != 0 && ~targetflags & CMD_FIND_QUIET) return (-1); break; case CMD_MOVEW_R: - error = cmd_find_target(fs, cmdq, target, CMD_FIND_SESSION, - CMD_FIND_QUIET); + error = cmd_find_target(fs, current, cmdq, target, + CMD_FIND_SESSION, CMD_FIND_QUIET); if (error == 0) break; flag = CMD_WINDOW_INDEX; @@ -432,39 +488,27 @@ cmd_prepare_state_flag(struct cmd_find_state *fs, enum cmd_entry_flag flag, case CMD_WINDOW_CANFAIL: case CMD_WINDOW_MARKED: case CMD_WINDOW_INDEX: - targetflags = 0; - if (flag == CMD_WINDOW_CANFAIL) - targetflags |= CMD_FIND_QUIET; - if (flag == CMD_WINDOW_MARKED) - targetflags |= CMD_FIND_DEFAULT_MARKED; - if (flag == CMD_WINDOW_INDEX) - targetflags |= CMD_FIND_WINDOW_INDEX; - - error = cmd_find_target(fs, cmdq, target, CMD_FIND_WINDOW, - targetflags); - if (error != 0 && flag != CMD_WINDOW_CANFAIL) + error = cmd_find_target(fs, current, cmdq, target, + CMD_FIND_WINDOW, targetflags); + if (error != 0 && ~targetflags & CMD_FIND_QUIET) return (-1); break; case CMD_PANE: case CMD_PANE_CANFAIL: case CMD_PANE_MARKED: - targetflags = 0; - if (flag == CMD_PANE_CANFAIL) - targetflags |= CMD_FIND_QUIET; - if (flag == CMD_PANE_MARKED) - targetflags |= CMD_FIND_DEFAULT_MARKED; - - error = cmd_find_target(fs, cmdq, target, CMD_FIND_PANE, - targetflags); - if (error != 0 && flag != CMD_PANE_CANFAIL) + error = cmd_find_target(fs, current, cmdq, target, + CMD_FIND_PANE, targetflags); + if (error != 0 && ~targetflags & CMD_FIND_QUIET) return (-1); break; + default: + fatalx("unknown %cflag %d", c, flag); } return (0); } int -cmd_prepare_state(struct cmd *cmd, struct cmd_q *cmdq) +cmd_prepare_state(struct cmd *cmd, struct cmd_q *cmdq, struct cmd_q *parent) { const struct cmd_entry *entry = cmd->entry; struct cmd_state *state = &cmdq->state; @@ -504,14 +548,14 @@ cmd_prepare_state(struct cmd *cmd, struct cmd_q *cmdq) s = args_get(cmd->args, 't'); log_debug("preparing -t state: target %s", s == NULL ? "none" : s); - error = cmd_prepare_state_flag(&state->tflag, entry->tflag, s, cmdq); + error = cmd_prepare_state_flag('t', s, entry->tflag, cmdq, parent); if (error != 0) return (error); s = args_get(cmd->args, 's'); log_debug("preparing -s state: target %s", s == NULL ? "none" : s); - error = cmd_prepare_state_flag(&state->sflag, entry->sflag, s, cmdq); + error = cmd_prepare_state_flag('s', s, entry->sflag, cmdq, parent); if (error != 0) return (error); diff --git a/tmux.h b/tmux.h index 941548d0..eb3373da 100644 --- a/tmux.h +++ b/tmux.h @@ -1769,8 +1769,11 @@ long long args_strtonum(struct args *, u_char, long long, long long, char **); /* cmd-find.c */ -int cmd_find_target(struct cmd_find_state *, struct cmd_q *, - const char *, enum cmd_find_type, int); +int cmd_find_current(struct cmd_find_state *, struct cmd_q *, + int); +int cmd_find_target(struct cmd_find_state *, + struct cmd_find_state *, struct cmd_q *, const char *, + enum cmd_find_type, int); struct client *cmd_find_client(struct cmd_q *, const char *, int); void cmd_find_clear_state(struct cmd_find_state *, struct cmd_q *, int); @@ -1793,7 +1796,8 @@ char **cmd_copy_argv(int, char **); void cmd_free_argv(int, char **); char *cmd_stringify_argv(int, char **); struct cmd *cmd_parse(int, char **, const char *, u_int, char **); -int cmd_prepare_state(struct cmd *, struct cmd_q *); +int cmd_prepare_state(struct cmd *, struct cmd_q *, + struct cmd_q *); char *cmd_print(struct cmd *); int cmd_mouse_at(struct window_pane *, struct mouse_event *, u_int *, u_int *, int); From ca29dc9abc5c90da1a56d06ecb692b35a3766bc0 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 19 Jan 2016 18:07:25 +0000 Subject: [PATCH 011/150] Update my email address. --- compat.h | 2 +- compat/asprintf.c | 2 +- compat/cfmakeraw.c | 2 +- compat/forkpty-aix.c | 2 +- compat/forkpty-hpux.c | 2 +- compat/forkpty-sunos.c | 2 +- compat/openat.c | 2 +- compat/setenv.c | 2 +- osdep-aix.c | 2 +- osdep-cygwin.c | 2 +- osdep-dragonfly.c | 2 +- osdep-freebsd.c | 2 +- osdep-hpux.c | 2 +- osdep-linux.c | 2 +- osdep-netbsd.c | 2 +- osdep-unknown.c | 2 +- 16 files changed, 16 insertions(+), 16 deletions(-) diff --git a/compat.h b/compat.h index 6812e9a5..b2267d37 100644 --- a/compat.h +++ b/compat.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2007 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/compat/asprintf.c b/compat/asprintf.c index 09020b35..5ed1c48c 100644 --- a/compat/asprintf.c +++ b/compat/asprintf.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006 Nicholas Marriott + * Copyright (c) 2006 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/compat/cfmakeraw.c b/compat/cfmakeraw.c index 85b2c9bc..d8794081 100644 --- a/compat/cfmakeraw.c +++ b/compat/cfmakeraw.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2013 Dagobert Michelsen - * Copyright (c) 2013 Nicholas Marriott + * Copyright (c) 2013 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/compat/forkpty-aix.c b/compat/forkpty-aix.c index 6894aa44..2557ebf7 100644 --- a/compat/forkpty-aix.c +++ b/compat/forkpty-aix.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009 Nicholas Marriott + * Copyright (c) 2009 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/compat/forkpty-hpux.c b/compat/forkpty-hpux.c index 59130e1b..09b27d08 100644 --- a/compat/forkpty-hpux.c +++ b/compat/forkpty-hpux.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008 Nicholas Marriott + * Copyright (c) 2008 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/compat/forkpty-sunos.c b/compat/forkpty-sunos.c index 554e51ac..9abda46c 100644 --- a/compat/forkpty-sunos.c +++ b/compat/forkpty-sunos.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008 Nicholas Marriott + * Copyright (c) 2008 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/compat/openat.c b/compat/openat.c index 6b04eedc..d003e53d 100644 --- a/compat/openat.c +++ b/compat/openat.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Nicholas Marriott + * Copyright (c) 2013 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/compat/setenv.c b/compat/setenv.c index 6c7d29ec..b16b08cf 100644 --- a/compat/setenv.c +++ b/compat/setenv.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2010 Dagobert Michelsen - * Copyright (c) 2010 Nicholas Marriott + * Copyright (c) 2010 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/osdep-aix.c b/osdep-aix.c index ef7d6c7e..e1ce4918 100644 --- a/osdep-aix.c +++ b/osdep-aix.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2011 Nicholas Marriott + * Copyright (c) 2011 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/osdep-cygwin.c b/osdep-cygwin.c index 9a3ea408..60630b33 100644 --- a/osdep-cygwin.c +++ b/osdep-cygwin.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2009 Nicholas Marriott + * Copyright (c) 2009 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/osdep-dragonfly.c b/osdep-dragonfly.c index f9b0efcf..879034e8 100644 --- a/osdep-dragonfly.c +++ b/osdep-dragonfly.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2009 Nicholas Marriott + * Copyright (c) 2009 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/osdep-freebsd.c b/osdep-freebsd.c index d7f419b8..067ba565 100644 --- a/osdep-freebsd.c +++ b/osdep-freebsd.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2009 Nicholas Marriott + * Copyright (c) 2009 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/osdep-hpux.c b/osdep-hpux.c index a6d75f94..16993b93 100644 --- a/osdep-hpux.c +++ b/osdep-hpux.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2009 Nicholas Marriott + * Copyright (c) 2009 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/osdep-linux.c b/osdep-linux.c index 00501efb..42712dea 100644 --- a/osdep-linux.c +++ b/osdep-linux.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2009 Nicholas Marriott + * Copyright (c) 2009 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/osdep-netbsd.c b/osdep-netbsd.c index 15686860..d8aa41b5 100644 --- a/osdep-netbsd.c +++ b/osdep-netbsd.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2009 Nicholas Marriott + * Copyright (c) 2009 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/osdep-unknown.c b/osdep-unknown.c index 9465db97..bc59f569 100644 --- a/osdep-unknown.c +++ b/osdep-unknown.c @@ -1,7 +1,7 @@ /* $OpenBSD$ */ /* - * Copyright (c) 2009 Nicholas Marriott + * Copyright (c) 2009 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above From 64e14eaff5912b592565130ca116251a1028bfe6 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sat, 23 Jan 2016 00:52:35 -0500 Subject: [PATCH 012/150] Avoid crashes when the ssh connction dies We might want to deal with reconnections soon --- tmate-ssh-client.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tmate-ssh-client.c b/tmate-ssh-client.c index 691a49ce..cd3a71b0 100644 --- a/tmate-ssh-client.c +++ b/tmate-ssh-client.c @@ -49,6 +49,9 @@ static void on_encoder_write(void *userdata, struct evbuffer *buffer) ssize_t len, written; unsigned char *buf; + if (!client->channel) + return; + for(;;) { len = evbuffer_get_length(buffer); if (!len) From 405cd82a8205c77657a586ee10e6ad015d686d25 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sat, 23 Jan 2016 01:07:25 -0500 Subject: [PATCH 013/150] Don't abort on unknown messages --- tmate-decoder.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmate-decoder.c b/tmate-decoder.c index d4646ac7..bc5141f5 100644 --- a/tmate-decoder.c +++ b/tmate-decoder.c @@ -146,6 +146,6 @@ void tmate_dispatch_slave_message(struct tmate_session *session, dispatch(TMATE_IN_SET_ENV, handle_set_env); dispatch(TMATE_IN_READY, handle_ready); dispatch(TMATE_IN_PANE_KEY, handle_pane_key); - default: tmate_fatal("Bad message type: %d", cmd); + default: tmate_info("Bad message type: %d", cmd); } } From 1d6bd50343f4395879169868e47bb59f5b2f3811 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 29 Jan 2016 10:58:08 +0000 Subject: [PATCH 014/150] libevent.org URL. --- README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README b/README index 6a78fa2b..88d77b5f 100644 --- a/README +++ b/README @@ -8,7 +8,7 @@ This release runs on OpenBSD, FreeBSD, NetBSD, Linux, OS X and Solaris. tmux depends on libevent 2.x. Download it from: - http://www.monkey.org/~provos/libevent/ + http://libevent.org To build tmux from a release tarball, do: From 427b8204268af5548d09b830e101c59daa095df9 Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 29 Jan 2016 11:13:56 +0000 Subject: [PATCH 015/150] Support for RGB colour, using the extended cell mechanism to avoid wasting unnecessary space. The 'Tc' flag must be set in the external TERM entry (using terminal-overrides or a custom terminfo entry), if not tmux will map to the closest of the 256 or 16 colour palettes. Mostly from Suraj N Kurapati, based on a diff originally by someone else. --- grid.c | 11 +++- input.c | 35 ++++++---- tmux.1 | 12 ++-- tmux.h | 20 +++++- tty-term.c | 1 + tty.c | 185 ++++++++++++++++++++++++++++++++++++++++++++--------- 6 files changed, 209 insertions(+), 55 deletions(-) diff --git a/grid.c b/grid.c index c24e6c6a..782032f4 100644 --- a/grid.c +++ b/grid.c @@ -37,7 +37,7 @@ /* Default grid cell data. */ const struct grid_cell grid_default_cell = { - 0, 0, 8, 8, { { ' ' }, 0, 1, 1 } + 0, 0, { .fg = 8 }, { .bg = 8 }, { { ' ' }, 0, 1, 1 } }; const struct grid_cell_entry grid_default_entry = { 0, { .data = { 0, 8, 8, ' ' } } @@ -284,6 +284,7 @@ grid_set_cell(struct grid *gd, u_int px, u_int py, const struct grid_cell *gc) struct grid_line *gl; struct grid_cell_entry *gce; struct grid_cell *gcp; + int extended; if (grid_check_y(gd, py) != 0) return; @@ -293,8 +294,12 @@ grid_set_cell(struct grid *gd, u_int px, u_int py, const struct grid_cell *gc) gl = &gd->linedata[py]; gce = &gl->celldata[px]; - if ((gce->flags & GRID_FLAG_EXTENDED) || gc->data.size != 1 || - gc->data.width != 1) { + extended = (gce->flags & GRID_FLAG_EXTENDED); + if (!extended && (gc->data.size != 1 || gc->data.width != 1)) + extended = 1; + if (!extended && (gc->flags & (GRID_FLAG_FGRGB|GRID_FLAG_BGRGB))) + extended = 1; + if (extended) { if (~gce->flags & GRID_FLAG_EXTENDED) { gl->extddata = xreallocarray(gl->extddata, gl->extdsize + 1, sizeof *gl->extddata); diff --git a/input.c b/input.c index 1772a4cd..ae205024 100644 --- a/input.c +++ b/input.c @@ -1629,18 +1629,20 @@ input_csi_dispatch_sgr_256(struct input_ctx *ictx, int fgbg, u_int *i) c = input_get(ictx, *i, 0, -1); if (c == -1) { if (fgbg == 38) { - gc->flags &= ~GRID_FLAG_FG256; + gc->flags &= ~(GRID_FLAG_FG256|GRID_FLAG_FGRGB); gc->fg = 8; } else if (fgbg == 48) { - gc->flags &= ~GRID_FLAG_BG256; + gc->flags &= ~(GRID_FLAG_BG256|GRID_FLAG_BGRGB); gc->bg = 8; } } else { if (fgbg == 38) { gc->flags |= GRID_FLAG_FG256; + gc->flags &= ~GRID_FLAG_FGRGB; gc->fg = c; } else if (fgbg == 48) { gc->flags |= GRID_FLAG_BG256; + gc->flags &= ~GRID_FLAG_BGRGB; gc->bg = c; } } @@ -1651,7 +1653,7 @@ void input_csi_dispatch_sgr_rgb(struct input_ctx *ictx, int fgbg, u_int *i) { struct grid_cell *gc = &ictx->cell.cell; - int c, r, g, b; + int r, g, b; (*i)++; r = input_get(ictx, *i, 0, -1); @@ -1666,13 +1668,18 @@ input_csi_dispatch_sgr_rgb(struct input_ctx *ictx, int fgbg, u_int *i) if (b == -1 || b > 255) return; - c = colour_find_rgb(r, g, b); if (fgbg == 38) { - gc->flags |= GRID_FLAG_FG256; - gc->fg = c; + gc->flags &= ~GRID_FLAG_FG256; + gc->flags |= GRID_FLAG_FGRGB; + gc->fg_rgb.r = r; + gc->fg_rgb.g = g; + gc->fg_rgb.b = b; } else if (fgbg == 48) { - gc->flags |= GRID_FLAG_BG256; - gc->bg = c; + gc->flags &= ~GRID_FLAG_BG256; + gc->flags |= GRID_FLAG_BGRGB; + gc->bg_rgb.r = r; + gc->bg_rgb.g = g; + gc->bg_rgb.b = b; } } @@ -1754,11 +1761,11 @@ input_csi_dispatch_sgr(struct input_ctx *ictx) case 35: case 36: case 37: - gc->flags &= ~GRID_FLAG_FG256; + gc->flags &= ~(GRID_FLAG_FG256|GRID_FLAG_FGRGB); gc->fg = n - 30; break; case 39: - gc->flags &= ~GRID_FLAG_FG256; + gc->flags &= ~(GRID_FLAG_FG256|GRID_FLAG_FGRGB); gc->fg = 8; break; case 40: @@ -1769,11 +1776,11 @@ input_csi_dispatch_sgr(struct input_ctx *ictx) case 45: case 46: case 47: - gc->flags &= ~GRID_FLAG_BG256; + gc->flags &= ~(GRID_FLAG_BG256|GRID_FLAG_BGRGB); gc->bg = n - 40; break; case 49: - gc->flags &= ~GRID_FLAG_BG256; + gc->flags &= ~(GRID_FLAG_BG256|GRID_FLAG_BGRGB); gc->bg = 8; break; case 90: @@ -1784,7 +1791,7 @@ input_csi_dispatch_sgr(struct input_ctx *ictx) case 95: case 96: case 97: - gc->flags &= ~GRID_FLAG_FG256; + gc->flags &= ~(GRID_FLAG_FG256|GRID_FLAG_FGRGB); gc->fg = n; break; case 100: @@ -1795,7 +1802,7 @@ input_csi_dispatch_sgr(struct input_ctx *ictx) case 105: case 106: case 107: - gc->flags &= ~GRID_FLAG_BG256; + gc->flags &= ~(GRID_FLAG_BG256|GRID_FLAG_BGRGB); gc->bg = n - 10; break; } diff --git a/tmux.1 b/tmux.1 index e41ba798..e70b07c3 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2921,7 +2921,7 @@ and poor for interactive programs such as shells. .Op Ic on | off .Xc Allow programs to change the window name using a terminal escape -sequence (\\033k...\\033\\\\). +sequence (\eek...\ee\e\e). The default is on. .Pp .It Xo Ic alternate-screen @@ -4024,7 +4024,7 @@ This command only works from outside .El .Sh TERMINFO EXTENSIONS .Nm -understands some extensions to +understands some unofficial extensions to .Xr terminfo 5 : .Bl -tag -width Ds .It Em Cs , Cr @@ -4048,10 +4048,12 @@ $ printf '\e033[4 q' If .Em Se is not set, \&Ss with argument 0 will be used to reset the cursor style instead. +.It Em \&Tc +Indicate that the terminal supports the +.Ql direct colour +RGB escape sequence (for example, \ee[38;2;255;255;255m). .It Em \&Ms -This sequence can be used by -.Nm -to store the current buffer in the host terminal's selection (clipboard). +Store the current buffer in the host terminal's selection (clipboard). See the .Em set-clipboard option above and the diff --git a/tmux.h b/tmux.h index eb3373da..8edb9209 100644 --- a/tmux.h +++ b/tmux.h @@ -385,6 +385,7 @@ enum tty_code_code { TTYC_SMSO, /* enter_standout_mode, so */ TTYC_SMUL, /* enter_underline_mode, us */ TTYC_SS, /* set cursor style, Ss */ + TTYC_TC, /* 24-bit "true" colour, Tc */ TTYC_TSL, /* to_status_line, tsl */ TTYC_VPA, /* row_address, cv */ TTYC_XENL, /* eat_newline_glitch, xn */ @@ -641,16 +642,31 @@ enum utf8_state { #define GRID_FLAG_BG256 0x2 #define GRID_FLAG_PADDING 0x4 #define GRID_FLAG_EXTENDED 0x8 +#define GRID_FLAG_FGRGB 0x10 +#define GRID_FLAG_BGRGB 0x20 /* Grid line flags. */ #define GRID_LINE_WRAPPED 0x1 +/* Grid cell RGB colours. */ +struct grid_cell_rgb { + u_char r; + u_char g; + u_char b; +}; + /* Grid cell data. */ struct grid_cell { u_char flags; u_char attr; - u_char fg; - u_char bg; + union { + u_char fg; + struct grid_cell_rgb fg_rgb; + }; + union { + u_char bg; + struct grid_cell_rgb bg_rgb; + }; struct utf8_data data; }; diff --git a/tty-term.c b/tty-term.c index 8716a1a9..05ef01e7 100644 --- a/tty-term.c +++ b/tty-term.c @@ -251,6 +251,7 @@ const struct tty_term_code_entry tty_term_codes[] = { [TTYC_SMSO] = { TTYCODE_STRING, "smso" }, [TTYC_SMUL] = { TTYCODE_STRING, "smul" }, [TTYC_SS] = { TTYCODE_STRING, "Ss" }, + [TTYC_TC] = { TTYCODE_FLAG, "Tc" }, [TTYC_TSL] = { TTYCODE_STRING, "tsl" }, [TTYC_VPA] = { TTYCODE_STRING, "vpa" }, [TTYC_XENL] = { TTYCODE_FLAG, "xenl" }, diff --git a/tty.c b/tty.c index 52521be9..c6fc2213 100644 --- a/tty.c +++ b/tty.c @@ -36,8 +36,15 @@ static int tty_log_fd = -1; void tty_read_callback(struct bufferevent *, void *); void tty_error_callback(struct bufferevent *, short, void *); +static int tty_same_fg(const struct grid_cell *, const struct grid_cell *); +static int tty_same_bg(const struct grid_cell *, const struct grid_cell *); +static int tty_same_colours(const struct grid_cell *, const struct grid_cell *); +static int tty_is_fg(const struct grid_cell *, int); +static int tty_is_bg(const struct grid_cell *, int); + void tty_set_italics(struct tty *); int tty_try_256(struct tty *, u_char, const char *); +int tty_try_rgb(struct tty *, const struct grid_cell_rgb *, const char *); void tty_colours(struct tty *, const struct grid_cell *); void tty_check_fg(struct tty *, struct grid_cell *); @@ -61,6 +68,74 @@ void tty_default_colours(struct grid_cell *, const struct window_pane *); #define tty_pane_full_width(tty, ctx) \ ((ctx)->xoff == 0 && screen_size_x((ctx)->wp->screen) >= (tty)->sx) +static int +tty_same_fg(const struct grid_cell *gc1, const struct grid_cell *gc2) +{ + int flags1, flags2; + + flags1 = (gc1->flags & (GRID_FLAG_FG256|GRID_FLAG_FGRGB)); + flags2 = (gc2->flags & (GRID_FLAG_FG256|GRID_FLAG_FGRGB)); + + if (flags1 != flags2) + return (0); + + if (flags1 & GRID_FLAG_FGRGB) { + if (gc1->fg_rgb.r != gc2->fg_rgb.r) + return (0); + if (gc1->fg_rgb.g != gc2->fg_rgb.g) + return (0); + if (gc1->fg_rgb.b != gc2->fg_rgb.b) + return (0); + return (1); + } + return (gc1->fg == gc2->fg); +} + +static int +tty_same_bg(const struct grid_cell *gc1, const struct grid_cell *gc2) +{ + int flags1, flags2; + + flags1 = (gc1->flags & (GRID_FLAG_BG256|GRID_FLAG_BGRGB)); + flags2 = (gc2->flags & (GRID_FLAG_BG256|GRID_FLAG_BGRGB)); + + if (flags1 != flags2) + return (0); + + if (flags1 & GRID_FLAG_BGRGB) { + if (gc1->bg_rgb.r != gc2->bg_rgb.r) + return (0); + if (gc1->bg_rgb.g != gc2->bg_rgb.g) + return (0); + if (gc1->bg_rgb.b != gc2->bg_rgb.b) + return (0); + return (1); + } + return (gc1->bg == gc2->bg); +} + +static int +tty_same_colours(const struct grid_cell *gc1, const struct grid_cell *gc2) +{ + return (tty_same_fg(gc1, gc2) && tty_same_bg(gc1, gc2)); +} + +static int +tty_is_fg(const struct grid_cell *gc, int c) +{ + if (gc->flags & (GRID_FLAG_FG256|GRID_FLAG_FGRGB)) + return (0); + return (gc->fg == c); +} + +static int +tty_is_bg(const struct grid_cell *gc, int c) +{ + if (gc->flags & (GRID_FLAG_BG256|GRID_FLAG_BGRGB)) + return (0); + return (gc->bg == c); +} + void tty_create_log(void) { @@ -1423,12 +1498,10 @@ void tty_colours(struct tty *tty, const struct grid_cell *gc) { struct grid_cell *tc = &tty->cell; - u_char fg = gc->fg, bg = gc->bg, flags = gc->flags; int have_ax, fg_default, bg_default; /* No changes? Nothing is necessary. */ - if (fg == tc->fg && bg == tc->bg && - ((flags ^ tc->flags) & (GRID_FLAG_FG256|GRID_FLAG_BG256)) == 0) + if (tty_same_colours(gc, tc)) return; /* @@ -1437,8 +1510,8 @@ tty_colours(struct tty *tty, const struct grid_cell *gc) * case if only one is default need to fall onward to set the other * colour. */ - fg_default = (fg == 8 && !(flags & GRID_FLAG_FG256)); - bg_default = (bg == 8 && !(flags & GRID_FLAG_BG256)); + fg_default = tty_is_fg(gc, 8); + bg_default = tty_is_bg(gc, 8); if (fg_default || bg_default) { /* * If don't have AX but do have op, send sgr0 (op can't @@ -1451,48 +1524,52 @@ tty_colours(struct tty *tty, const struct grid_cell *gc) if (!have_ax && tty_term_has(tty->term, TTYC_OP)) tty_reset(tty); else { - if (fg_default && - (tc->fg != 8 || tc->flags & GRID_FLAG_FG256)) { + if (fg_default && !tty_is_fg(tc, 8)) { if (have_ax) tty_puts(tty, "\033[39m"); - else if (tc->fg != 7 || - tc->flags & GRID_FLAG_FG256) + else if (!tty_is_fg(tc, 7)) tty_putcode1(tty, TTYC_SETAF, 7); tc->fg = 8; - tc->flags &= ~GRID_FLAG_FG256; + tc->flags &= ~(GRID_FLAG_FG256|GRID_FLAG_FGRGB); } - if (bg_default && - (tc->bg != 8 || tc->flags & GRID_FLAG_BG256)) { + if (bg_default && !tty_is_bg(tc, 8)) { if (have_ax) tty_puts(tty, "\033[49m"); - else if (tc->bg != 0 || - tc->flags & GRID_FLAG_BG256) + else if (!tty_is_bg(tc, 0)) tty_putcode1(tty, TTYC_SETAB, 0); tc->bg = 8; - tc->flags &= ~GRID_FLAG_BG256; + tc->flags &= ~(GRID_FLAG_BG256|GRID_FLAG_BGRGB); } } } /* Set the foreground colour. */ - if (!fg_default && (fg != tc->fg || - ((flags & GRID_FLAG_FG256) != (tc->flags & GRID_FLAG_FG256)))) + if (!fg_default && !tty_same_fg(gc, tc)) tty_colours_fg(tty, gc); /* * Set the background colour. This must come after the foreground as * tty_colour_fg() can call tty_reset(). */ - if (!bg_default && (bg != tc->bg || - ((flags & GRID_FLAG_BG256) != (tc->flags & GRID_FLAG_BG256)))) + if (!bg_default && !tty_same_bg(gc, tc)) tty_colours_bg(tty, gc); } void tty_check_fg(struct tty *tty, struct grid_cell *gc) { - u_int colours; + struct grid_cell_rgb *rgb = &gc->fg_rgb; + u_int colours; + /* Is this a 24-bit colour? */ + if (gc->flags & GRID_FLAG_FGRGB) { + /* Not a 24-bit terminal? Translate to 256-colour palette. */ + if (!tty_term_flag(tty->term, TTYC_TC)) { + gc->flags &= ~GRID_FLAG_FGRGB; + gc->flags |= GRID_FLAG_FG256; + gc->fg = colour_find_rgb(rgb->r, rgb->g, rgb->b); + } + } colours = tty_term_number(tty->term, TTYC_COLORS); /* Is this a 256-colour colour? */ @@ -1524,8 +1601,18 @@ tty_check_fg(struct tty *tty, struct grid_cell *gc) void tty_check_bg(struct tty *tty, struct grid_cell *gc) { - u_int colours; + struct grid_cell_rgb *rgb = &gc->bg_rgb; + u_int colours; + /* Is this a 24-bit colour? */ + if (gc->flags & GRID_FLAG_BGRGB) { + /* Not a 24-bit terminal? Translate to 256-colour palette. */ + if (!tty_term_flag(tty->term, TTYC_TC)) { + gc->flags &= ~GRID_FLAG_BGRGB; + gc->flags |= GRID_FLAG_BG256; + gc->bg = colour_find_rgb(rgb->r, rgb->g, rgb->b); + } + } colours = tty_term_number(tty->term, TTYC_COLORS); /* Is this a 256-colour colour? */ @@ -1560,12 +1647,21 @@ tty_colours_fg(struct tty *tty, const struct grid_cell *gc) u_char fg = gc->fg; char s[32]; + tc->flags &= ~(GRID_FLAG_FG256|GRID_FLAG_FGRGB); + + /* Is this a 24-bit colour? */ + if (gc->flags & GRID_FLAG_FGRGB) { + if (tty_try_rgb(tty, &gc->fg_rgb, "38") == 0) + goto save_fg; + /* Should not get here, already converted in tty_check_fg. */ + return; + } + /* Is this a 256-colour colour? */ if (gc->flags & GRID_FLAG_FG256) { - /* Try as 256 colours. */ if (tty_try_256(tty, fg, "38") == 0) goto save_fg; - /* Else already handled by tty_check_fg. */ + /* Should not get here, already converted in tty_check_fg. */ return; } @@ -1581,9 +1677,12 @@ tty_colours_fg(struct tty *tty, const struct grid_cell *gc) save_fg: /* Save the new values in the terminal current cell. */ - tc->fg = fg; - tc->flags &= ~GRID_FLAG_FG256; - tc->flags |= gc->flags & GRID_FLAG_FG256; + if (gc->flags & GRID_FLAG_FGRGB) + memcpy(&tc->fg_rgb, &gc->fg_rgb, sizeof tc->fg_rgb); + else + tc->fg = fg; + tc->flags &= ~(GRID_FLAG_FGRGB|GRID_FLAG_FG256); + tc->flags |= (gc->flags & (GRID_FLAG_FG256|GRID_FLAG_FGRGB)); } void @@ -1593,12 +1692,19 @@ tty_colours_bg(struct tty *tty, const struct grid_cell *gc) u_char bg = gc->bg; char s[32]; + /* Is this a 24-bit colour? */ + if (gc->flags & GRID_FLAG_BGRGB) { + if (tty_try_rgb(tty, &gc->bg_rgb, "48") == 0) + goto save_bg; + /* Should not get here, already converted in tty_check_bg. */ + return; + } + /* Is this a 256-colour colour? */ if (gc->flags & GRID_FLAG_BG256) { - /* Try as 256 colours. */ if (tty_try_256(tty, bg, "48") == 0) goto save_bg; - /* Else already handled by tty_check_bg. */ + /* Should not get here, already converted in tty_check_bg. */ return; } @@ -1614,9 +1720,12 @@ tty_colours_bg(struct tty *tty, const struct grid_cell *gc) save_bg: /* Save the new values in the terminal current cell. */ - tc->bg = bg; - tc->flags &= ~GRID_FLAG_BG256; - tc->flags |= gc->flags & GRID_FLAG_BG256; + if (gc->flags & GRID_FLAG_BGRGB) + memcpy(&tc->bg_rgb, &gc->bg_rgb, sizeof tc->bg_rgb); + else + tc->bg = bg; + tc->flags &= ~(GRID_FLAG_BGRGB|GRID_FLAG_BG256); + tc->flags |= (gc->flags & (GRID_FLAG_BG256|GRID_FLAG_BGRGB)); } int @@ -1656,6 +1765,20 @@ fallback: return (0); } +int +tty_try_rgb(struct tty *tty, const struct grid_cell_rgb *rgb, const char *type) +{ + char s[32]; + + if (!tty_term_flag(tty->term, TTYC_TC)) + return (-1); + + xsnprintf(s, sizeof s, "\033[%s;2;%hhu;%hhu;%hhum", type, rgb->r, + rgb->g, rgb->b); + tty_puts(tty, s); + return (0); +} + void tty_default_colours(struct grid_cell *gc, const struct window_pane *wp) { From a33bb3e876895ef40ee90e5f89c76184e65c7f10 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 29 Jan 2016 14:40:30 +0000 Subject: [PATCH 016/150] Link to the bash(1) completion file from README rather than including it in examples. --- README | 4 ++ examples/bash_completion_tmux.sh | 105 ------------------------------- 2 files changed, 4 insertions(+), 105 deletions(-) delete mode 100644 examples/bash_completion_tmux.sh diff --git a/README b/README index 88d77b5f..c0102e68 100644 --- a/README +++ b/README @@ -40,6 +40,10 @@ A vim(1) syntax file is available at: https://github.com/keith/tmux.vim https://raw.githubusercontent.com/keith/tmux.vim/master/syntax/tmux.vim +And a bash(1) completion file at: + + https://github.com/przepompownia/tmux-bash-completion + For debugging, running tmux with -v or -vv will generate server and client log files in the current directory. diff --git a/examples/bash_completion_tmux.sh b/examples/bash_completion_tmux.sh deleted file mode 100644 index 74728b91..00000000 --- a/examples/bash_completion_tmux.sh +++ /dev/null @@ -1,105 +0,0 @@ -# START tmux completion -# This file is in the public domain -# See: http://www.debian-administration.org/articles/317 for how to write more. -# Usage: Put "source bash_completion_tmux.sh" into your .bashrc -_tmux() -{ - local cur prev opts - COMPREPLY=() - cur="${COMP_WORDS[COMP_CWORD]}" - prev="${COMP_WORDS[COMP_CWORD-1]}" - - opts=" \ - attach-session \ - bind-key \ - break-pane \ - capture-pane \ - choose-client \ - choose-session \ - choose-window \ - clear-history \ - clock-mode \ - command-prompt \ - confirm-before \ - copy-buffer \ - copy-mode \ - delete-buffer \ - detach-client \ - display-message \ - display-panes \ - down-pane \ - find-window \ - has-session \ - if-shell \ - join-pane \ - kill-pane \ - kill-server \ - kill-session \ - kill-window \ - last-window \ - link-window \ - list-buffers \ - list-clients \ - list-commands \ - list-keys \ - list-panes \ - list-sessions \ - list-windows \ - load-buffer \ - lock-client \ - lock-server \ - lock-session \ - move-window \ - new-session \ - new-window \ - next-layout \ - next-window \ - paste-buffer \ - pipe-pane \ - previous-layout \ - previous-window \ - refresh-client \ - rename-session \ - rename-window \ - resize-pane \ - respawn-window \ - rotate-window \ - run-shell \ - save-buffer \ - select-layout \ - select-pane \ - select-prompt \ - select-window \ - send-keys \ - send-prefix \ - server-info \ - set-buffer \ - set-environment \ - set-option \ - set-window-option \ - show-buffer \ - show-environment \ - show-messages \ - show-options \ - show-window-options \ - source-file \ - split-window \ - start-server \ - suspend-client \ - swap-pane \ - swap-window \ - switch-client \ - unbind-key \ - unlink-window \ - up-pane" - - COMPREPLY=($(compgen -W "${opts}" -- ${cur})) - return 0 - -} -complete -F _tmux tmux - -# END tmux completion - - - From 2a1bb91bf73366b89d27f2ecfacdc770ceecb72e Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 29 Jan 2016 14:53:28 +0000 Subject: [PATCH 017/150] Remove old examples in favour of one example configuration file. --- README | 2 +- example_tmux.conf | 66 +++++++++++++++++++++++ examples/h-boetes.conf | 42 --------------- examples/n-marriott.conf | 110 -------------------------------------- examples/screen-keys.conf | 102 ----------------------------------- examples/t-williams.conf | 104 ----------------------------------- examples/vim-keys.conf | 36 ------------- examples/xterm-keys.vim | 49 ----------------- 8 files changed, 67 insertions(+), 444 deletions(-) create mode 100644 example_tmux.conf delete mode 100644 examples/h-boetes.conf delete mode 100644 examples/n-marriott.conf delete mode 100644 examples/screen-keys.conf delete mode 100644 examples/t-williams.conf delete mode 100644 examples/vim-keys.conf delete mode 100644 examples/xterm-keys.vim diff --git a/README b/README index c0102e68..dbc9b173 100644 --- a/README +++ b/README @@ -33,7 +33,7 @@ the source tree with: Some common questions are answered in the FAQ file and a more extensive (but slightly out of date) guide is available in the OpenBSD FAQ at http://www.openbsd.org/faq/faq7.html#tmux. A rough todo list is in the TODO -file and some example configurations are in the examples directory. +file and an example configuration in example_tmux.conf. A vim(1) syntax file is available at: diff --git a/example_tmux.conf b/example_tmux.conf new file mode 100644 index 00000000..f659a3c2 --- /dev/null +++ b/example_tmux.conf @@ -0,0 +1,66 @@ +# +# Example .tmux.conf +# +# By Nicholas Marriott. Public domain. +# + +# Some tweaks to the status line +set -g status-bg green +set -g status-right "%H:%M" +set -g window-status-current-attr "underscore" + +# No bells at all +set -g bell-action none + +# Lock after 15 minutes +set -g lock-after-time 1800 + +# Keep windows around after they exit +set -g remain-on-exit on + +# Turn on xterm-keys so that additional function keys get escape sequences +set -g xterm-keys on + +# Change the prefix key to C-a +set -g prefix C-a +unbind C-b +bind C-a send-prefix + +# Turn the mouse on, but without copy mode dragging +set -g mouse on +unbind -n MouseDrag1Pane +unbind -temacs-copy MouseDrag1Pane + +# Some extra key bindings to select higher numbered windows +bind F1 selectw -t:10 +bind F2 selectw -t:11 +bind F3 selectw -t:12 +bind F4 selectw -t:13 +bind F5 selectw -t:14 +bind F6 selectw -t:15 +bind F7 selectw -t:16 +bind F8 selectw -t:17 +bind F9 selectw -t:18 +bind F10 selectw -t:19 +bind F11 selectw -t:20 +bind F12 selectw -t:21 + +# Keys to toggle monitoring activity in a window, and synchronize-panes +bind m set monitor-activity +bind y set synchronize-panes\; display 'synchronize-panes #{?synchronize-panes,on,off}' + +# Keys to hide and show a window name from the status line +bind '-' set window-status-format '#I'\; set window-status-current-format '#I' +bind '+' set window-status-format '#I:#W#F'\; set window-status-current-format '#I:#W#F' + +# Create a single default session +new -d -s0 -nirssi 'exec irssi' +set -t0:0 monitor-activity on +set -t0:0 aggressive-resize on +neww -d -ntodo 'exec emacs ~/TODO' +setw -t0:1 aggressive-resize on +neww -d -nmutt 'exec mutt' +setw -t0:2 aggressive-resize on +neww -d +neww -d +neww -d diff --git a/examples/h-boetes.conf b/examples/h-boetes.conf deleted file mode 100644 index 2aa86dc5..00000000 --- a/examples/h-boetes.conf +++ /dev/null @@ -1,42 +0,0 @@ -# $Id: h-boetes.conf,v 1.2 2009-10-25 21:45:26 nicm Exp $ -# -# From Han Boetes. - -set -g default-command zsh -set -g status-right "#(uptime|awk '{print $11}') #(date)" - -# Statusbar properties. -set -g display-time 3000 -set -g status-bg black -set -g status-fg cyan -set-window-option -g window-status-current-attr bright,reverse -set-window-option -g window-status-current-bg cyan -set-window-option -g window-status-current-fg black - -# Use c-t instead of c-b as the prefix -unbind C-b -set -g prefix C-t -bind C-t send-prefix -bind t send-prefix - -# Bind function keys. -bind -n F1 select-window -t 1 -bind -n F2 select-window -t 2 -bind -n F3 select-window -t 3 -bind -n F4 select-window -t 4 -bind -n F5 select-window -t 5 -bind -n F6 select-window -t 6 -bind -n F7 select-window -t 7 -bind -n F8 select-window -t 8 - -# All new windows started at startup. -new emacs -neww irssi -neww mutt -neww -neww -neww -neww -neww - -select-window -t 1 diff --git a/examples/n-marriott.conf b/examples/n-marriott.conf deleted file mode 100644 index 6a047ec9..00000000 --- a/examples/n-marriott.conf +++ /dev/null @@ -1,110 +0,0 @@ -# $Id: n-marriott.conf,v 1.11 2009-11-24 19:03:59 nicm Exp $ -# -# By Nicholas Marriott. Public domain. - -# Default global options. -set -g status-bg green -set -g status-right "%H:%M" # %d-%b-%y -set -g bell-action none -set -g lock-after-time 1800 - -# Default global window options. -setw -g remain-on-exit on -setw -g window-status-current-attr "underscore" -#setw -g xterm-keys on - -# Prefix key. -set -g prefix C-a -unbind C-b -bind C-a send-prefix - -# Keys to switch session. -bind Q switchc -t0 -bind W switchc -t1 -bind E switchc -t2 - -# Other key bindings. -bind F1 selectw -t:10 -bind F2 selectw -t:11 -bind F3 selectw -t:12 -bind F4 selectw -t:13 -bind F5 selectw -t:14 -bind F6 selectw -t:15 -bind F7 selectw -t:16 -bind F8 selectw -t:17 -bind F9 selectw -t:18 -bind F10 selectw -t:19 -bind F11 selectw -t:20 -bind F12 selectw -t:21 - -bind m setw monitor-activity - -bind y setw force-width 81 -bind u setw force-width 0 - -bind -n F1 run-shell 'mpc toggle >/dev/null 2>&1' -bind -n F2 run-shell 'mpc' -bind -n F3 run-shell 'mpc prev >/dev/null 2>&1' -bind -n F4 run-shell 'mpc next >/dev/null 2>&1' -bind -n F5 run-shell 'mpc volume -5 >/dev/null 2>&1' -bind -n F6 run-shell 'mpc volume +5 >/dev/null 2>&1' - -# Hide and show window name from status line -bind '-' setw window-status-format '#I'\; setw window-status-current-format '#I' -bind '+' setw window-status-format '#I:#W#F'\; setw window-status-current-format '#I:#W#F' - -# First session. -new -d -s0 -nirssi 'exec ssh -t natalya exec sh ~/bin/tmux-start' -setw -t0:0 monitor-activity on -setw -t0:0 aggressive-resize on -set -t0 status-bg green -neww -d -ntodo 'exec emacs ~/TODO' -setw -t0:1 aggressive-resize on -neww -d -ntodo2 'exec emacs ~/TODO2' -setw -t0:2 aggressive-resize on -neww -d -nncmpc 'exec ncmpc -f ~/.ncmpc.conf' -setw -t0:3 aggressive-resize on -neww -d -nmutt 'exec mutt' -setw -t0:4 aggressive-resize on -neww -d -neww -d -neww -d -neww -d -neww -d -neww -d -neww -d -neww -d -neww -d -neww -d -neww -d -neww -d - -# Second session. -new -d -s1 -set -t1 status-bg cyan -linkw -dk -t0 -s0:0 -linkw -dk -t1 -s0:1 -linkw -dk -t2 -s0:2 -linkw -dk -t3 -s0:3 -linkw -dk -t4 -s0:4 -neww -d -neww -d -neww -d -neww -d -neww -d -neww -d - -# Third session. -new -d -s2 -set -t2 status-bg yellow -linkw -dk -t0 -s0:0 -linkw -dk -t1 -s0:1 -linkw -dk -t2 -s0:2 -linkw -dk -t3 -s0:3 -linkw -dk -t4 -s0:4 -neww -d -neww -d -neww -d -neww -d -neww -d -neww -d diff --git a/examples/screen-keys.conf b/examples/screen-keys.conf deleted file mode 100644 index ce149290..00000000 --- a/examples/screen-keys.conf +++ /dev/null @@ -1,102 +0,0 @@ -# $Id: screen-keys.conf,v 1.7 2010-07-31 11:39:13 nicm Exp $ -# -# By Nicholas Marriott. Public domain. -# -# This configuration file binds many of the common GNU screen key bindings to -# appropriate tmux key bindings. Note that for some key bindings there is no -# tmux analogue and also that this set omits binding some commands available in -# tmux but not in screen. -# -# Note this is only a selection of key bindings and they are in addition to the -# normal tmux key bindings. This is intended as an example not as to be used -# as-is. - -# Set the prefix to ^A. -unbind C-b -set -g prefix ^A -bind a send-prefix - -# Bind appropriate commands similar to screen. -# lockscreen ^X x -unbind ^X -bind ^X lock-server -unbind x -bind x lock-server - -# screen ^C c -unbind ^C -bind ^C new-window -unbind c -bind c new-window - -# detach ^D d -unbind ^D -bind ^D detach - -# displays * -unbind * -bind * list-clients - -# next ^@ ^N sp n -unbind ^@ -bind ^@ next-window -unbind ^N -bind ^N next-window -unbind " " -bind " " next-window -unbind n -bind n next-window - -# title A -unbind A -bind A command-prompt "rename-window %%" - -# other ^A -unbind ^A -bind ^A last-window - -# prev ^H ^P p ^? -unbind ^H -bind ^H previous-window -unbind ^P -bind ^P previous-window -unbind p -bind p previous-window -unbind BSpace -bind BSpace previous-window - -# windows ^W w -unbind ^W -bind ^W list-windows -unbind w -bind w list-windows - -# quit \ -unbind '\' -bind '\' confirm-before "kill-server" - -# kill K k -unbind K -bind K confirm-before "kill-window" -unbind k -bind k confirm-before "kill-window" - -# redisplay ^L l -unbind ^L -bind ^L refresh-client -unbind l -bind l refresh-client - -# split -v | -unbind | -bind | split-window - -# :kB: focus up -unbind Tab -bind Tab select-pane -t:.+ -unbind BTab -bind BTab select-pane -t:.- - -# " windowlist -b -unbind '"' -bind '"' choose-window diff --git a/examples/t-williams.conf b/examples/t-williams.conf deleted file mode 100644 index 0a2cc3f5..00000000 --- a/examples/t-williams.conf +++ /dev/null @@ -1,104 +0,0 @@ -# $Id: t-williams.conf,v 1.1 2009-11-02 18:59:28 nicm Exp $ -# -# ~/.tmux.conf - tmux terminal multiplexer config -# Thayer Williams (http://cinderwick.ca) -# "Feel free to do whatever you like with it." - -# I typically start tmux from ~/.xinitrc with the following: -# -# urxvt -e bash -c "tmux attach -d -t mysession" & -# -# and recall it any time thereafter with xbindkeys (Mod4+s): -# -# "urxvt -e bash -c 'tmux attach -d -t mysession'" -# m:0x50 + c:39 - - -# set prefix key to ctrl+a until I have time to adapt -unbind C-b -set -g prefix C-a - -# send the prefix to client inside window (ala nested sessions) -bind-key a send-prefix - -# toggle last window like screen -bind-key C-a last-window - -# confirm before killing a window or the server -bind-key k confirm kill-window -bind-key K confirm kill-server - -# toggle statusbar -bind-key b set-option status - -# ctrl+left/right cycles thru windows -bind-key -n C-right next -bind-key -n C-left prev - -# open a man page in new window -bind / command-prompt "split-window 'exec man %%'" - -# quick view of processes -bind '~' split-window "exec htop" - -# scrollback buffer n lines -set -g history-limit 5000 - -# listen for activity on all windows -set -g bell-action any - -# on-screen time for display-panes in ms -set -g display-panes-time 2000 - -# start window indexing at one instead of zero -set -g base-index 1 - -# enable wm window titles -set -g set-titles on - -# wm window title string (uses statusbar variables) -set -g set-titles-string "tmux.#I.#W" - -# session initialization -new -s mysession mutt -neww -t 2 -neww -d -t 3 -neww -d -t 5 mocp -neww -d -t 6 rtorrent -selectw -t 1 - -# statusbar -------------------------------------------------------------- - -set -g display-time 2000 - -# default statusbar colors -set -g status-fg white -set -g status-bg default -set -g status-attr default - -# default window title colors -set-window-option -g window-status-fg cyan -set-window-option -g window-status-bg default -set-window-option -g window-status-attr dim - -# active window title colors -set-window-option -g window-status-current-fg white -set-window-option -g window-status-current-bg default -set-window-option -g window-status-current-attr bright - -# command/message line colors -set -g message-fg white -set -g message-bg black -set -g message-attr bright - -# center align the window list -set -g status-justify centre - -# show some useful stats but only when tmux is started -# outside of Xorg, otherwise dwm statusbar shows these already -set -g status-right "" -set -g status-left "" -if '[ -z "$DISPLAY" ]' 'set -g status-left "[#[fg=green] #H #[default]]"' -if '[ -z "$DISPLAY" ]' 'set -g status-right "[ #[fg=magenta]#(cat /proc/loadavg | cut -d \" \" -f 1,2,3)#[default] ][ #[fg=cyan,bright]%a %Y-%m-%d %H:%M #[default]]"' -if '[ -z "$DISPLAY" ]' 'set -g status-right-length 50' - diff --git a/examples/vim-keys.conf b/examples/vim-keys.conf deleted file mode 100644 index d587d0bf..00000000 --- a/examples/vim-keys.conf +++ /dev/null @@ -1,36 +0,0 @@ -# $Id: vim-keys.conf,v 1.2 2010-09-18 09:36:15 nicm Exp $ -# -# vim-keys.conf, v1.2 2010/09/12 -# -# By Daniel Thau. Public domain. -# -# This configuration file binds many vi- and vim-like bindings to the -# appropriate tmux key bindings. Note that for many key bindings there is no -# tmux analogue. This is intended for tmux 1.3, which handles pane selection -# differently from the previous versions - -# split windows like vim -# vim's definition of a horizontal/vertical split is reversed from tmux's -bind s split-window -v -bind v split-window -h - -# move around panes with hjkl, as one would in vim after pressing ctrl-w -bind h select-pane -L -bind j select-pane -D -bind k select-pane -U -bind l select-pane -R - -# resize panes like vim -# feel free to change the "1" to however many lines you want to resize by, only -# one at a time can be slow -bind < resize-pane -L 1 -bind > resize-pane -R 1 -bind - resize-pane -D 1 -bind + resize-pane -U 1 - -# bind : to command-prompt like vim -# this is the default in tmux already -bind : command-prompt - -# vi-style controls for copy mode -setw -g mode-keys vi diff --git a/examples/xterm-keys.vim b/examples/xterm-keys.vim deleted file mode 100644 index 5672c26a..00000000 --- a/examples/xterm-keys.vim +++ /dev/null @@ -1,49 +0,0 @@ -" tmux.vim - Set xterm input codes passed by tmux -" Author: Mark Oteiza -" License: Public domain -" Description: Simple plugin that assigns some xterm(1)-style keys to escape -" sequences passed by tmux when "xterm-keys" is set to "on". Inspired by an -" example given by Chris Johnsen at: -" https://stackoverflow.com/a/15471820 -" -" Documentation: help:xterm-modifier-keys man:tmux(1) - -if exists("g:loaded_tmux") || &cp - finish -endif -let g:loaded_tmux = 1 - -function! s:SetXtermCapabilities() - set ttymouse=sgr - - execute "set =\e[1;*A" - execute "set =\e[1;*B" - execute "set =\e[1;*C" - execute "set =\e[1;*D" - - execute "set =\e[1;*H" - execute "set =\e[1;*F" - - execute "set =\e[2;*~" - execute "set =\e[3;*~" - execute "set =\e[5;*~" - execute "set =\e[6;*~" - - execute "set =\e[1;*P" - execute "set =\e[1;*Q" - execute "set =\e[1;*R" - execute "set =\e[1;*S" - - execute "set =\e[15;*~" - execute "set =\e[17;*~" - execute "set =\e[18;*~" - execute "set =\e[19;*~" - execute "set =\e[20;*~" - execute "set =\e[21;*~" - execute "set =\e[23;*~" - execute "set =\e[24;*~" -endfunction - -if exists('$TMUX') - call s:SetXtermCapabilities() -endif From 404379049a4cb5480c2b1c19634c869e46feb220 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 29 Jan 2016 15:45:32 +0000 Subject: [PATCH 018/150] examples/ has gone, so delete some text about it. --- README | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/README b/README index dbc9b173..9141f240 100644 --- a/README +++ b/README @@ -60,10 +60,7 @@ welcome. Please send by email to: tmux-users@googlegroups.com -This file and the CHANGES, FAQ, SYNCING and TODO files are licensed under -the ISC license. Files under examples/ remain copyright their authors unless -otherwise stated in the file but permission has been received to distribute -them with tmux. All other files have a license and copyright notice at their -start. +This file and the CHANGES, FAQ, SYNCING and TODO files are licensed under the +ISC license. All other files have a license and copyright notice at their start. -- Nicholas Marriott From 225a384dbb5ffe5fc91c59ebcaeda1946b80ca69 Mon Sep 17 00:00:00 2001 From: nicm Date: Sun, 31 Jan 2016 09:52:01 +0000 Subject: [PATCH 019/150] Fix new-session with -t after command flags changes, reported by Michael Graczyk. --- cmd-new-session.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/cmd-new-session.c b/cmd-new-session.c index b4bb37d5..ecbc5983 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -74,7 +74,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) struct environ *env; struct termios tio, *tiop; const char *newname, *target, *update, *errstr, *template; - const char *path, *cwd, *to_free; + const char *path, *cwd, *to_free = NULL; char **argv, *cmd, *cause, *cp; int detached, already_attached, idx, argc; u_int sx, sy; @@ -118,7 +118,12 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) } } - if ((target = args_get(args, 't')) == NULL) + if ((target = args_get(args, 't')) != NULL) { + if (groupwith == NULL) { + cmdq_error(cmdq, "no such session: %s", target); + goto error; + } + } else groupwith = NULL; /* Set -d if no client. */ @@ -132,7 +137,6 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) already_attached = 1; /* Get the new session working directory. */ - to_free = NULL; if (args_has(args, 'c')) { ft = format_create(cmdq, 0); format_defaults(ft, c, NULL, NULL, NULL); @@ -208,7 +212,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) if (!args_has(args, 't') && args->argc != 0) { argc = args->argc; argv = args->argv; - } else if (target == NULL) { + } else if (groupwith == NULL) { cmd = options_get_string(global_s_options, "default-command"); if (cmd != NULL && *cmd != '\0') { argc = 1; @@ -257,7 +261,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) * If a target session is given, this is to be part of a session group, * so add it to the group and synchronize. */ - if (args_has(args, 't')) { + if (groupwith != NULL) { session_group_add(groupwith, s); session_group_synchronize_to(s); session_select(s, RB_MIN(winlinks, &s->windows)->idx); From 8028560f8260aeea6fee1206cf8704a0a5fc25f9 Mon Sep 17 00:00:00 2001 From: nicm Date: Sun, 31 Jan 2016 09:54:46 +0000 Subject: [PATCH 020/150] Support negative trim values (#{=-10:pane_title}) to trim from the end, suggested by Kevin Brubeck Unhammer. --- format.c | 12 ++++++++---- tmux.1 | 10 +++++++--- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/format.c b/format.c index efa9d1e1..78c177cd 100644 --- a/format.c +++ b/format.c @@ -684,7 +684,7 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen, char *copy, *copy0, *endptr, *ptr, *found, *new, *value; char *from = NULL, *to = NULL; size_t valuelen, newlen, fromlen, tolen, used; - u_long limit = 0; + long limit = 0; int modifiers = 0, brackets; /* Make a copy of the key. */ @@ -696,8 +696,8 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen, switch (copy[0]) { case '=': errno = 0; - limit = strtoul(copy + 1, &endptr, 10); - if (errno == ERANGE && limit == ULONG_MAX) + limit = strtol(copy + 1, &endptr, 10); + if (errno == ERANGE && (limit == LONG_MIN || limit == LONG_MAX)) break; if (*endptr != ':') break; @@ -813,10 +813,14 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen, } /* Truncate the value if needed. */ - if (limit != 0) { + if (limit > 0) { new = utf8_trimcstr(value, limit); free(value); value = new; + } else if (limit < 0) { + new = utf8_rtrimcstr(value, -limit); + free(value); + value = new; } /* Expand the buffer and copy in the value. */ diff --git a/tmux.1 b/tmux.1 index e70b07c3..5dbf6b84 100644 --- a/tmux.1 +++ b/tmux.1 @@ -3377,9 +3377,13 @@ if not. 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. +a number and a colon. +Positive numbers count from the start of the string and negative from the end, +so +.Ql #{=5:pane_title} +will include at most the first 5 characters of the pane title, or +.Ql #{=-5:pane_title} +the last 5 characters. Prefixing a time variable with .Ql t: will convert it to a string, so if From 49e9f937387356a3970fdb2af6bb56818127b433 Mon Sep 17 00:00:00 2001 From: nicm Date: Sun, 31 Jan 2016 09:57:09 +0000 Subject: [PATCH 021/150] Add RGB escape sequences for capture-pane -e. --- grid.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/grid.c b/grid.c index 782032f4..0be0254f 100644 --- a/grid.c +++ b/grid.c @@ -452,6 +452,12 @@ grid_string_cells_fg(const struct grid_cell *gc, int *values) values[n++] = 38; values[n++] = 5; values[n++] = gc->fg; + } else if (gc->flags & GRID_FLAG_FGRGB) { + values[n++] = 38; + values[n++] = 2; + values[n++] = gc->fg_rgb.r; + values[n++] = gc->fg_rgb.g; + values[n++] = gc->fg_rgb.b; } else { switch (gc->fg) { case 0: @@ -493,6 +499,12 @@ grid_string_cells_bg(const struct grid_cell *gc, int *values) values[n++] = 48; values[n++] = 5; values[n++] = gc->bg; + } else if (gc->flags & GRID_FLAG_BGRGB) { + values[n++] = 48; + values[n++] = 2; + values[n++] = gc->bg_rgb.r; + values[n++] = gc->bg_rgb.g; + values[n++] = gc->bg_rgb.b; } else { switch (gc->bg) { case 0: @@ -532,7 +544,7 @@ void grid_string_cells_code(const struct grid_cell *lastgc, const struct grid_cell *gc, char *buf, size_t len, int escape_c0) { - int oldc[16], newc[16], s[32]; + int oldc[64], newc[64], s[128]; size_t noldc, nnewc, n, i; u_int attr = gc->attr; u_int lastattr = lastgc->attr; From fa64b89ad7af8daf04c50b54fe8b45411750149e Mon Sep 17 00:00:00 2001 From: nicm Date: Sun, 31 Jan 2016 09:57:41 +0000 Subject: [PATCH 022/150] Whoops, need this for the previous reverse trim commit too. --- tmux.h | 1 + utf8.c | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/tmux.h b/tmux.h index 8edb9209..997690fc 100644 --- a/tmux.h +++ b/tmux.h @@ -2324,6 +2324,7 @@ char *utf8_sanitize(const char *); struct utf8_data *utf8_fromcstr(const char *); char *utf8_tocstr(struct utf8_data *); u_int utf8_cstrwidth(const char *); +char *utf8_rtrimcstr(const char *, u_int); char *utf8_trimcstr(const char *, u_int); char *utf8_padcstr(const char *, u_int); diff --git a/utf8.c b/utf8.c index b03c425d..3f6107a7 100644 --- a/utf8.c +++ b/utf8.c @@ -724,6 +724,43 @@ utf8_trimcstr(const char *s, u_int width) return (out); } +/* Trim UTF-8 string to width. Caller frees. */ +char * +utf8_rtrimcstr(const char *s, u_int width) +{ + struct utf8_data *tmp, *next, *end; + char *out; + u_int at; + + tmp = utf8_fromcstr(s); + + for (end = tmp; end->size != 0; end++) + /* nothing */; + if (end == tmp) { + free(tmp); + return (xstrdup("")); + } + next = end - 1; + + at = 0; + for (;;) + { + if (at + next->width > width) { + next++; + break; + } + at += next->width; + + if (next == tmp) + break; + next--; + } + + out = utf8_tocstr(next); + free(tmp); + return (out); +} + /* Pad UTF-8 string to width. Caller frees. */ char * utf8_padcstr(const char *s, u_int width) From 97882f9ce27d615769d3140ef77ddfb47b17a89b Mon Sep 17 00:00:00 2001 From: nicm Date: Sun, 31 Jan 2016 14:11:49 +0000 Subject: [PATCH 023/150] Clear RGB flags during selection. --- screen-write.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/screen-write.c b/screen-write.c index 05315b3f..e58d744c 100644 --- a/screen-write.c +++ b/screen-write.c @@ -994,7 +994,9 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc) utf8_copy(&tmp_gc.data, &gc->data); tmp_gc.attr = tmp_gc.attr & ~GRID_ATTR_CHARSET; tmp_gc.attr |= gc->attr & GRID_ATTR_CHARSET; - tmp_gc.flags = gc->flags & ~(GRID_FLAG_FG256|GRID_FLAG_BG256); + tmp_gc.flags = gc->flags; + tmp_gc.flags &= ~(GRID_FLAG_FGRGB|GRID_FLAG_BGRGB); + tmp_gc.flags &= ~(GRID_FLAG_FG256|GRID_FLAG_BG256); tmp_gc.flags |= s->sel.cell.flags & (GRID_FLAG_FG256|GRID_FLAG_BG256); ttyctx.cell = &tmp_gc; From bdb8bb790ed53c0ea134c690c8f55b449eefbd3f Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 4 Feb 2016 14:11:20 +0000 Subject: [PATCH 024/150] Set up -t flag properly when passing new-session -A off to attach-session, GitHub issue 295. --- cmd-new-session.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd-new-session.c b/cmd-new-session.c index ecbc5983..291107bc 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -68,7 +68,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct client *c = cmdq->client; - struct session *s, *attach_sess; + struct session *s, *as; struct session *groupwith = cmdq->state.tflag.s; struct window *w; struct environ *env; @@ -100,7 +100,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) cmdq_error(cmdq, "bad session name: %s", newname); return (CMD_RETURN_ERROR); } - if ((attach_sess = session_find(newname)) != NULL) { + if ((as = session_find(newname)) != NULL) { if (args_has(args, 'A')) { /* * This cmdq is now destined for @@ -108,7 +108,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) * will have already been prepared, copy this * session into its tflag so it can be used. */ - cmdq->state.tflag.s = attach_sess; + cmd_find_from_session(&cmdq->state.tflag, as); return (cmd_attach_session(cmdq, args_has(args, 'D'), 0, NULL, args_has(args, 'E'))); From 2130a07b70db7df8d57b9cad96a6866203daacad Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 5 Feb 2016 10:08:39 +0000 Subject: [PATCH 025/150] Add to TODO. --- TODO | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/TODO b/TODO index b4b8231b..18d3ae61 100644 --- a/TODO +++ b/TODO @@ -62,6 +62,19 @@ * command to toggle selection not to move it in copy-mode * regex searching * copy-pipe should have -x as well + * copy mode key bindings should just be a standard key table, using + something like "copy-mode start-selection"; it could use + command-prompt for search, goto, etc: + + bind -Temacs command-prompt -p'Search Up: ' 'copy-mode search-up %%' + + it'd need a separate lookup, because modes are per-pane, perhaps a + table() cb to give the table name ("vi" or "emacs"). anything in the + table fires the command, anything not in the table is injected as a + key + * searching in copy mode should unwrap lines, so if you seach for "foobar" + then it should be found even if it is now "foo\nbar" (if the WRAP flag + is set on the line) - layout stuff * way to tag a layout as a number/name @@ -123,13 +136,3 @@ * automatic pane logging * BCE? We are halfway there (output side is done for pane backgrounds), just need to change how screen/grid handles erase - * copy mode key bindings should just be a standard key table, using - something like "copy-mode start-selection"; it could use - command-prompt for search, goto, etc: - - bind -Temacs command-prompt -p'Search Up: ' 'copy-mode search-up %%' - - it'd need a separate lookup, because modes are per-pane, perhaps a - table() cb to give the table name ("vi" or "emacs"). anything in the - table fires the command, anything not in the table is injected as a - key From bc0c9c7920349328ed426a735b999d9dc85fe1f1 Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 5 Feb 2016 10:20:06 +0000 Subject: [PATCH 026/150] Do not wrap cursor at start or end of history, from Michal Mazurek. --- window-copy.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/window-copy.c b/window-copy.c index c8e38fd1..009ed246 100644 --- a/window-copy.c +++ b/window-copy.c @@ -1775,11 +1775,13 @@ void window_copy_cursor_left(struct window_pane *wp) { struct window_copy_mode_data *data = wp->modedata; + u_int py; - if (data->cx == 0) { + py = screen_hsize(data->backing) + data->cy - data->oy; + if (data->cx == 0 && py > 0) { window_copy_cursor_up(wp, 0); window_copy_cursor_end_of_line(wp); - } else { + } else if (data->cx > 0) { window_copy_update_cursor(wp, data->cx - 1, data->cy); if (window_copy_update_selection(wp, 1)) window_copy_redraw_lines(wp, data->cy, 1); @@ -1790,19 +1792,20 @@ void window_copy_cursor_right(struct window_pane *wp) { struct window_copy_mode_data *data = wp->modedata; - u_int px, py; + u_int px, py, yy; + py = screen_hsize(data->backing) + data->cy - data->oy; + yy = screen_hsize(data->backing) + screen_size_y(data->backing) - 1; if (data->screen.sel.flag && data->rectflag) px = screen_size_x(&data->screen); else { - py = screen_hsize(data->backing) + data->cy - data->oy; px = window_copy_find_length(wp, py); } - if (data->cx >= px) { + if (data->cx >= px && py < yy) { window_copy_cursor_start_of_line(wp); window_copy_cursor_down(wp, 0); - } else { + } else if (data->cx < px) { window_copy_update_cursor(wp, data->cx + 1, data->cy); if (window_copy_update_selection(wp, 1)) window_copy_redraw_lines(wp, data->cy, 1); From ba97ae1737fbbdc7d6cd4ce4f8f0b4a3d77f027e Mon Sep 17 00:00:00 2001 From: Thomas Adam Date: Sat, 6 Feb 2016 19:04:21 +0000 Subject: [PATCH 027/150] EXTRA_DIST: add example_tmux.conf / xmalloc.h --- Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.am b/Makefile.am index d8c92aa9..8678a38e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -6,8 +6,8 @@ CLEANFILES = tmux.1.mdoc tmux.1.man # Distribution tarball options. EXTRA_DIST = \ - CHANGES FAQ README TODO COPYING examples compat/*.[ch] \ - array.h compat.h tmux.h osdep-*.c mdoc2man.awk tmux.1 + CHANGES FAQ README TODO COPYING example_tmux.conf compat/*.[ch] \ + array.h compat.h tmux.h osdep-*.c xmalloc.h mdoc2man.awk tmux.1 dist-hook: make clean grep "^#found_debug=" configure From f7c8f1ae291b0211734fe2c902a786033a9e0f3f Mon Sep 17 00:00:00 2001 From: Thomas Adam Date: Sun, 7 Feb 2016 00:04:46 +0000 Subject: [PATCH 028/150] xmalloc: define __bounded__ where necessary --- xmalloc.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/xmalloc.h b/xmalloc.h index d331ce99..0360b0d9 100644 --- a/xmalloc.h +++ b/xmalloc.h @@ -19,6 +19,10 @@ #ifndef XMALLOC_H #define XMALLOC_H +#if !defined(__bounded__) +# define __bounded__(x, y, z) +#endif + void *xmalloc(size_t); void *xcalloc(size_t, size_t); void *xrealloc(void *, size_t); From 4f6bc0a0a90a652172bdf251d5177476f7e6bdb1 Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 12 Feb 2016 12:24:52 +0000 Subject: [PATCH 029/150] Expand client formats in run-shell. --- cmd-run-shell.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd-run-shell.c b/cmd-run-shell.c index e857e9c9..0bd8fc59 100644 --- a/cmd-run-shell.c +++ b/cmd-run-shell.c @@ -93,7 +93,7 @@ cmd_run_shell_exec(struct cmd *self, struct cmd_q *cmdq) else cwd = NULL; ft = format_create(cmdq, 0); - format_defaults(ft, NULL, s, wl, wp); + format_defaults(ft, cmdq->state.c, s, wl, wp); shellcmd = format_expand(ft, args->argv[0]); format_free(ft); From 782dd941da97802108628fb068f5462f4c78f431 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 17 Feb 2016 23:21:58 +0000 Subject: [PATCH 030/150] Fire SIGCHLD after utempter_add_record since it probably eats it. --- window.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/window.c b/window.c index a89b1081..a364948f 100644 --- a/window.c +++ b/window.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -915,6 +916,7 @@ window_pane_spawn(struct window_pane *wp, int argc, char **argv, #ifdef HAVE_UTEMPTER xsnprintf(s, sizeof s, "tmux(%lu).%%%u", (long) getpid(), wp->id); utempter_add_record(wp->fd, s); + kill(getpid(), SIGCHLD); #endif setblocking(wp->fd, 0); From fc864529f587fc4c913d1ad40da41eab2e512521 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 19 Feb 2016 13:11:10 +0000 Subject: [PATCH 031/150] Remove malloc_options debug bit (already gone from OpenBSD). --- tmux.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/tmux.c b/tmux.c index 700687a5..ff087124 100644 --- a/tmux.c +++ b/tmux.c @@ -32,10 +32,6 @@ #include "tmux.h" -#if defined(DEBUG) && defined(__OpenBSD__) -extern char *malloc_options; -#endif - struct options *global_options; /* server options */ struct options *global_s_options; /* session options */ struct options *global_w_options; /* window options */ @@ -194,10 +190,6 @@ main(int argc, char **argv) const char *s; int opt, flags, keys; -#if defined(DEBUG) && defined(__OpenBSD__) - malloc_options = (char *) "AFGJPX"; -#endif - setlocale(LC_TIME, ""); tzset(); From acc1090e778090b8c5d2488220897873266dc368 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 19 Feb 2016 13:14:17 +0000 Subject: [PATCH 032/150] Use system wcwidth() instead of carrying around UTF-8 width tables. --- input-keys.c | 19 ++- tmux.c | 3 + tmux.h | 8 +- utf8.c | 452 ++++----------------------------------------------- 4 files changed, 51 insertions(+), 431 deletions(-) diff --git a/input-keys.c b/input-keys.c index 9a39ba7c..2a22b089 100644 --- a/input-keys.c +++ b/input-keys.c @@ -134,6 +134,19 @@ const struct input_key_ent input_keys[] = { { KEYC_KP_PERIOD, ".", 0 }, }; +/* Split a character into two UTF-8 bytes. */ +static size_t +input_split2(u_int c, u_char *dst) +{ + if (c > 0x7f) { + dst[0] = (c >> 6) | 0xc0; + dst[1] = (c & 0x3f) | 0x80; + return (2); + } + dst[0] = c; + return (1); +} + /* Translate a key code into an output key sequence. */ void input_key(struct window_pane *wp, key_code key, struct mouse_event *m) @@ -250,9 +263,9 @@ input_key_mouse(struct window_pane *wp, struct mouse_event *m) m->sgr_b, x + 1, y + 1, m->sgr_type); } else if (wp->screen->mode & MODE_MOUSE_UTF8) { len = xsnprintf(buf, sizeof buf, "\033[M"); - len += utf8_split2(m->b + 32, &buf[len]); - len += utf8_split2(x + 33, &buf[len]); - len += utf8_split2(y + 33, &buf[len]); + len += input_split2(m->b + 32, &buf[len]); + len += input_split2(x + 33, &buf[len]); + len += input_split2(y + 33, &buf[len]); } else { if (m->b > 223) return; diff --git a/tmux.c b/tmux.c index ff087124..b1285c3e 100644 --- a/tmux.c +++ b/tmux.c @@ -190,7 +190,10 @@ main(int argc, char **argv) const char *s; int opt, flags, keys; + + setlocale(LC_CTYPE, "en_US.UTF-8"); setlocale(LC_TIME, ""); + tzset(); if (**argv == '-') diff --git a/tmux.h b/tmux.h index be00098d..7c0acc75 100644 --- a/tmux.h +++ b/tmux.h @@ -29,6 +29,7 @@ #include #include #include +#include #ifdef HAVE_UTEMPTER #include @@ -2313,14 +2314,13 @@ void session_group_synchronize1(struct session *, struct session *); void session_renumber_windows(struct session *); /* utf8.c */ -u_int utf8_width(u_int); void utf8_set(struct utf8_data *, u_char); void utf8_copy(struct utf8_data *, const struct utf8_data *); enum utf8_state utf8_open(struct utf8_data *, u_char); enum utf8_state utf8_append(struct utf8_data *, u_char); -u_int utf8_combine(const struct utf8_data *); -enum utf8_state utf8_split(u_int, struct utf8_data *); -u_int utf8_split2(u_int, u_char *); +u_int utf8_width(wchar_t); +wchar_t utf8_combine(const struct utf8_data *); +enum utf8_state utf8_split(wchar_t, struct utf8_data *); int utf8_strvis(char *, const char *, size_t, int); char *utf8_sanitize(const char *); struct utf8_data *utf8_fromcstr(const char *); diff --git a/utf8.c b/utf8.c index 524ba872..503546af 100644 --- a/utf8.c +++ b/utf8.c @@ -20,333 +20,10 @@ #include #include +#include #include "tmux.h" -struct utf8_width_entry { - u_int first; - u_int last; - - int width; - - struct utf8_width_entry *left; - struct utf8_width_entry *right; -}; - -/* Sorted, then repeatedly split in the middle to balance the tree. */ -static struct utf8_width_entry utf8_width_table[] = { - { 0x00b41, 0x00b44, 0, NULL, NULL }, - { 0x008e4, 0x00902, 0, NULL, NULL }, - { 0x006d6, 0x006dd, 0, NULL, NULL }, - { 0x005c4, 0x005c5, 0, NULL, NULL }, - { 0x00591, 0x005bd, 0, NULL, NULL }, - { 0x00300, 0x0036f, 0, NULL, NULL }, - { 0x00483, 0x00489, 0, NULL, NULL }, - { 0x005bf, 0x005bf, 0, NULL, NULL }, - { 0x005c1, 0x005c2, 0, NULL, NULL }, - { 0x00610, 0x0061a, 0, NULL, NULL }, - { 0x00600, 0x00605, 0, NULL, NULL }, - { 0x005c7, 0x005c7, 0, NULL, NULL }, - { 0x0064b, 0x0065f, 0, NULL, NULL }, - { 0x0061c, 0x0061c, 0, NULL, NULL }, - { 0x00670, 0x00670, 0, NULL, NULL }, - { 0x007a6, 0x007b0, 0, NULL, NULL }, - { 0x006ea, 0x006ed, 0, NULL, NULL }, - { 0x006df, 0x006e4, 0, NULL, NULL }, - { 0x006e7, 0x006e8, 0, NULL, NULL }, - { 0x00711, 0x00711, 0, NULL, NULL }, - { 0x0070f, 0x0070f, 0, NULL, NULL }, - { 0x00730, 0x0074a, 0, NULL, NULL }, - { 0x0081b, 0x00823, 0, NULL, NULL }, - { 0x007eb, 0x007f3, 0, NULL, NULL }, - { 0x00816, 0x00819, 0, NULL, NULL }, - { 0x00829, 0x0082d, 0, NULL, NULL }, - { 0x00825, 0x00827, 0, NULL, NULL }, - { 0x00859, 0x0085b, 0, NULL, NULL }, - { 0x00a41, 0x00a42, 0, NULL, NULL }, - { 0x00981, 0x00981, 0, NULL, NULL }, - { 0x00941, 0x00948, 0, NULL, NULL }, - { 0x0093a, 0x0093a, 0, NULL, NULL }, - { 0x0093c, 0x0093c, 0, NULL, NULL }, - { 0x00951, 0x00957, 0, NULL, NULL }, - { 0x0094d, 0x0094d, 0, NULL, NULL }, - { 0x00962, 0x00963, 0, NULL, NULL }, - { 0x009e2, 0x009e3, 0, NULL, NULL }, - { 0x009c1, 0x009c4, 0, NULL, NULL }, - { 0x009bc, 0x009bc, 0, NULL, NULL }, - { 0x009cd, 0x009cd, 0, NULL, NULL }, - { 0x00a01, 0x00a02, 0, NULL, NULL }, - { 0x00a3c, 0x00a3c, 0, NULL, NULL }, - { 0x00ac1, 0x00ac5, 0, NULL, NULL }, - { 0x00a70, 0x00a71, 0, NULL, NULL }, - { 0x00a4b, 0x00a4d, 0, NULL, NULL }, - { 0x00a47, 0x00a48, 0, NULL, NULL }, - { 0x00a51, 0x00a51, 0, NULL, NULL }, - { 0x00a81, 0x00a82, 0, NULL, NULL }, - { 0x00a75, 0x00a75, 0, NULL, NULL }, - { 0x00abc, 0x00abc, 0, NULL, NULL }, - { 0x00ae2, 0x00ae3, 0, NULL, NULL }, - { 0x00ac7, 0x00ac8, 0, NULL, NULL }, - { 0x00acd, 0x00acd, 0, NULL, NULL }, - { 0x00b3c, 0x00b3c, 0, NULL, NULL }, - { 0x00b01, 0x00b01, 0, NULL, NULL }, - { 0x00b3f, 0x00b3f, 0, NULL, NULL }, - { 0x03190, 0x031ba, 2, NULL, NULL }, - { 0x017c9, 0x017d3, 0, NULL, NULL }, - { 0x00ec8, 0x00ecd, 0, NULL, NULL }, - { 0x00cc6, 0x00cc6, 0, NULL, NULL }, - { 0x00c3e, 0x00c40, 0, NULL, NULL }, - { 0x00b82, 0x00b82, 0, NULL, NULL }, - { 0x00b56, 0x00b56, 0, NULL, NULL }, - { 0x00b4d, 0x00b4d, 0, NULL, NULL }, - { 0x00b62, 0x00b63, 0, NULL, NULL }, - { 0x00bcd, 0x00bcd, 0, NULL, NULL }, - { 0x00bc0, 0x00bc0, 0, NULL, NULL }, - { 0x00c00, 0x00c00, 0, NULL, NULL }, - { 0x00c62, 0x00c63, 0, NULL, NULL }, - { 0x00c4a, 0x00c4d, 0, NULL, NULL }, - { 0x00c46, 0x00c48, 0, NULL, NULL }, - { 0x00c55, 0x00c56, 0, NULL, NULL }, - { 0x00cbc, 0x00cbc, 0, NULL, NULL }, - { 0x00c81, 0x00c81, 0, NULL, NULL }, - { 0x00cbf, 0x00cbf, 0, NULL, NULL }, - { 0x00dd2, 0x00dd4, 0, NULL, NULL }, - { 0x00d41, 0x00d44, 0, NULL, NULL }, - { 0x00ce2, 0x00ce3, 0, NULL, NULL }, - { 0x00ccc, 0x00ccd, 0, NULL, NULL }, - { 0x00d01, 0x00d01, 0, NULL, NULL }, - { 0x00d62, 0x00d63, 0, NULL, NULL }, - { 0x00d4d, 0x00d4d, 0, NULL, NULL }, - { 0x00dca, 0x00dca, 0, NULL, NULL }, - { 0x00e47, 0x00e4e, 0, NULL, NULL }, - { 0x00e31, 0x00e31, 0, NULL, NULL }, - { 0x00dd6, 0x00dd6, 0, NULL, NULL }, - { 0x00e34, 0x00e3a, 0, NULL, NULL }, - { 0x00eb4, 0x00eb9, 0, NULL, NULL }, - { 0x00eb1, 0x00eb1, 0, NULL, NULL }, - { 0x00ebb, 0x00ebc, 0, NULL, NULL }, - { 0x0105e, 0x01060, 0, NULL, NULL }, - { 0x00f8d, 0x00f97, 0, NULL, NULL }, - { 0x00f39, 0x00f39, 0, NULL, NULL }, - { 0x00f35, 0x00f35, 0, NULL, NULL }, - { 0x00f18, 0x00f19, 0, NULL, NULL }, - { 0x00f37, 0x00f37, 0, NULL, NULL }, - { 0x00f80, 0x00f84, 0, NULL, NULL }, - { 0x00f71, 0x00f7e, 0, NULL, NULL }, - { 0x00f86, 0x00f87, 0, NULL, NULL }, - { 0x01032, 0x01037, 0, NULL, NULL }, - { 0x00fc6, 0x00fc6, 0, NULL, NULL }, - { 0x00f99, 0x00fbc, 0, NULL, NULL }, - { 0x0102d, 0x01030, 0, NULL, NULL }, - { 0x0103d, 0x0103e, 0, NULL, NULL }, - { 0x01039, 0x0103a, 0, NULL, NULL }, - { 0x01058, 0x01059, 0, NULL, NULL }, - { 0x0135d, 0x0135f, 0, NULL, NULL }, - { 0x01085, 0x01086, 0, NULL, NULL }, - { 0x01071, 0x01074, 0, NULL, NULL }, - { 0x01082, 0x01082, 0, NULL, NULL }, - { 0x0109d, 0x0109d, 0, NULL, NULL }, - { 0x0108d, 0x0108d, 0, NULL, NULL }, - { 0x01100, 0x011ff, 2, NULL, NULL }, - { 0x01772, 0x01773, 0, NULL, NULL }, - { 0x01732, 0x01734, 0, NULL, NULL }, - { 0x01712, 0x01714, 0, NULL, NULL }, - { 0x01752, 0x01753, 0, NULL, NULL }, - { 0x017b7, 0x017bd, 0, NULL, NULL }, - { 0x017b4, 0x017b5, 0, NULL, NULL }, - { 0x017c6, 0x017c6, 0, NULL, NULL }, - { 0x01c2c, 0x01c33, 0, NULL, NULL }, - { 0x01a7f, 0x01a7f, 0, NULL, NULL }, - { 0x01a17, 0x01a18, 0, NULL, NULL }, - { 0x01920, 0x01922, 0, NULL, NULL }, - { 0x0180b, 0x0180e, 0, NULL, NULL }, - { 0x017dd, 0x017dd, 0, NULL, NULL }, - { 0x018a9, 0x018a9, 0, NULL, NULL }, - { 0x01932, 0x01932, 0, NULL, NULL }, - { 0x01927, 0x01928, 0, NULL, NULL }, - { 0x01939, 0x0193b, 0, NULL, NULL }, - { 0x01a60, 0x01a60, 0, NULL, NULL }, - { 0x01a56, 0x01a56, 0, NULL, NULL }, - { 0x01a1b, 0x01a1b, 0, NULL, NULL }, - { 0x01a58, 0x01a5e, 0, NULL, NULL }, - { 0x01a65, 0x01a6c, 0, NULL, NULL }, - { 0x01a62, 0x01a62, 0, NULL, NULL }, - { 0x01a73, 0x01a7c, 0, NULL, NULL }, - { 0x01b80, 0x01b81, 0, NULL, NULL }, - { 0x01b36, 0x01b3a, 0, NULL, NULL }, - { 0x01b00, 0x01b03, 0, NULL, NULL }, - { 0x01ab0, 0x01abe, 0, NULL, NULL }, - { 0x01b34, 0x01b34, 0, NULL, NULL }, - { 0x01b42, 0x01b42, 0, NULL, NULL }, - { 0x01b3c, 0x01b3c, 0, NULL, NULL }, - { 0x01b6b, 0x01b73, 0, NULL, NULL }, - { 0x01be6, 0x01be6, 0, NULL, NULL }, - { 0x01ba8, 0x01ba9, 0, NULL, NULL }, - { 0x01ba2, 0x01ba5, 0, NULL, NULL }, - { 0x01bab, 0x01bad, 0, NULL, NULL }, - { 0x01bed, 0x01bed, 0, NULL, NULL }, - { 0x01be8, 0x01be9, 0, NULL, NULL }, - { 0x01bef, 0x01bf1, 0, NULL, NULL }, - { 0x02329, 0x0232a, 2, NULL, NULL }, - { 0x01dc0, 0x01df5, 0, NULL, NULL }, - { 0x01ce2, 0x01ce8, 0, NULL, NULL }, - { 0x01cd0, 0x01cd2, 0, NULL, NULL }, - { 0x01c36, 0x01c37, 0, NULL, NULL }, - { 0x01cd4, 0x01ce0, 0, NULL, NULL }, - { 0x01cf4, 0x01cf4, 0, NULL, NULL }, - { 0x01ced, 0x01ced, 0, NULL, NULL }, - { 0x01cf8, 0x01cf9, 0, NULL, NULL }, - { 0x02060, 0x02064, 0, NULL, NULL }, - { 0x0200b, 0x0200f, 0, NULL, NULL }, - { 0x01dfc, 0x01dff, 0, NULL, NULL }, - { 0x0202a, 0x0202e, 0, NULL, NULL }, - { 0x02066, 0x0206f, 0, NULL, NULL }, - { 0x020d0, 0x020f0, 0, NULL, NULL }, - { 0x03001, 0x03029, 2, NULL, NULL }, - { 0x02e80, 0x02e99, 2, NULL, NULL }, - { 0x02d7f, 0x02d7f, 0, NULL, NULL }, - { 0x02cef, 0x02cf1, 0, NULL, NULL }, - { 0x02de0, 0x02dff, 0, NULL, NULL }, - { 0x02f00, 0x02fd5, 2, NULL, NULL }, - { 0x02e9b, 0x02ef3, 2, NULL, NULL }, - { 0x02ff0, 0x02ffb, 2, NULL, NULL }, - { 0x03099, 0x0309a, 0, NULL, NULL }, - { 0x0302e, 0x0303e, 2, NULL, NULL }, - { 0x0302a, 0x0302d, 0, NULL, NULL }, - { 0x03041, 0x03096, 2, NULL, NULL }, - { 0x03105, 0x0312d, 2, NULL, NULL }, - { 0x0309b, 0x030ff, 2, NULL, NULL }, - { 0x03131, 0x0318e, 2, NULL, NULL }, - { 0x10a3f, 0x10a3f, 0, NULL, NULL }, - { 0x0aa4c, 0x0aa4c, 0, NULL, NULL }, - { 0x0a825, 0x0a826, 0, NULL, NULL }, - { 0x0a490, 0x0a4c6, 2, NULL, NULL }, - { 0x03250, 0x032fe, 2, NULL, NULL }, - { 0x031f0, 0x0321e, 2, NULL, NULL }, - { 0x031c0, 0x031e3, 2, NULL, NULL }, - { 0x03220, 0x03247, 2, NULL, NULL }, - { 0x04e00, 0x09fcc, 2, NULL, NULL }, - { 0x03300, 0x04db5, 2, NULL, NULL }, - { 0x0a000, 0x0a48c, 2, NULL, NULL }, - { 0x0a6f0, 0x0a6f1, 0, NULL, NULL }, - { 0x0a674, 0x0a67d, 0, NULL, NULL }, - { 0x0a66f, 0x0a672, 0, NULL, NULL }, - { 0x0a69f, 0x0a69f, 0, NULL, NULL }, - { 0x0a806, 0x0a806, 0, NULL, NULL }, - { 0x0a802, 0x0a802, 0, NULL, NULL }, - { 0x0a80b, 0x0a80b, 0, NULL, NULL }, - { 0x0a9b6, 0x0a9b9, 0, NULL, NULL }, - { 0x0a947, 0x0a951, 0, NULL, NULL }, - { 0x0a8e0, 0x0a8f1, 0, NULL, NULL }, - { 0x0a8c4, 0x0a8c4, 0, NULL, NULL }, - { 0x0a926, 0x0a92d, 0, NULL, NULL }, - { 0x0a980, 0x0a982, 0, NULL, NULL }, - { 0x0a960, 0x0a97c, 2, NULL, NULL }, - { 0x0a9b3, 0x0a9b3, 0, NULL, NULL }, - { 0x0aa29, 0x0aa2e, 0, NULL, NULL }, - { 0x0a9bc, 0x0a9bc, 0, NULL, NULL }, - { 0x0a9e5, 0x0a9e5, 0, NULL, NULL }, - { 0x0aa35, 0x0aa36, 0, NULL, NULL }, - { 0x0aa31, 0x0aa32, 0, NULL, NULL }, - { 0x0aa43, 0x0aa43, 0, NULL, NULL }, - { 0x0fb1e, 0x0fb1e, 0, NULL, NULL }, - { 0x0aaf6, 0x0aaf6, 0, NULL, NULL }, - { 0x0aab7, 0x0aab8, 0, NULL, NULL }, - { 0x0aab0, 0x0aab0, 0, NULL, NULL }, - { 0x0aa7c, 0x0aa7c, 0, NULL, NULL }, - { 0x0aab2, 0x0aab4, 0, NULL, NULL }, - { 0x0aac1, 0x0aac1, 0, NULL, NULL }, - { 0x0aabe, 0x0aabf, 0, NULL, NULL }, - { 0x0aaec, 0x0aaed, 0, NULL, NULL }, - { 0x0ac00, 0x0d7a3, 2, NULL, NULL }, - { 0x0abe8, 0x0abe8, 0, NULL, NULL }, - { 0x0abe5, 0x0abe5, 0, NULL, NULL }, - { 0x0abed, 0x0abed, 0, NULL, NULL }, - { 0x0f900, 0x0fa6d, 2, NULL, NULL }, - { 0x0d800, 0x0dfff, 0, NULL, NULL }, - { 0x0fa70, 0x0fad9, 2, NULL, NULL }, - { 0x0fff9, 0x0fffb, 0, NULL, NULL }, - { 0x0fe30, 0x0fe52, 2, NULL, NULL }, - { 0x0fe10, 0x0fe19, 2, NULL, NULL }, - { 0x0fe00, 0x0fe0f, 0, NULL, NULL }, - { 0x0fe20, 0x0fe2d, 0, NULL, NULL }, - { 0x0fe68, 0x0fe6b, 2, NULL, NULL }, - { 0x0fe54, 0x0fe66, 2, NULL, NULL }, - { 0x0feff, 0x0feff, 0, NULL, NULL }, - { 0x10a01, 0x10a03, 0, NULL, NULL }, - { 0x102e0, 0x102e0, 0, NULL, NULL }, - { 0x101fd, 0x101fd, 0, NULL, NULL }, - { 0x10376, 0x1037a, 0, NULL, NULL }, - { 0x10a0c, 0x10a0f, 0, NULL, NULL }, - { 0x10a05, 0x10a06, 0, NULL, NULL }, - { 0x10a38, 0x10a3a, 0, NULL, NULL }, - { 0x11633, 0x1163a, 0, NULL, NULL }, - { 0x11236, 0x11237, 0, NULL, NULL }, - { 0x11100, 0x11102, 0, NULL, NULL }, - { 0x1107f, 0x11081, 0, NULL, NULL }, - { 0x11001, 0x11001, 0, NULL, NULL }, - { 0x10ae5, 0x10ae6, 0, NULL, NULL }, - { 0x11038, 0x11046, 0, NULL, NULL }, - { 0x110b9, 0x110ba, 0, NULL, NULL }, - { 0x110b3, 0x110b6, 0, NULL, NULL }, - { 0x110bd, 0x110bd, 0, NULL, NULL }, - { 0x11180, 0x11181, 0, NULL, NULL }, - { 0x1112d, 0x11134, 0, NULL, NULL }, - { 0x11127, 0x1112b, 0, NULL, NULL }, - { 0x11173, 0x11173, 0, NULL, NULL }, - { 0x1122f, 0x11231, 0, NULL, NULL }, - { 0x111b6, 0x111be, 0, NULL, NULL }, - { 0x11234, 0x11234, 0, NULL, NULL }, - { 0x11370, 0x11374, 0, NULL, NULL }, - { 0x11301, 0x11301, 0, NULL, NULL }, - { 0x112df, 0x112df, 0, NULL, NULL }, - { 0x112e3, 0x112ea, 0, NULL, NULL }, - { 0x11340, 0x11340, 0, NULL, NULL }, - { 0x1133c, 0x1133c, 0, NULL, NULL }, - { 0x11366, 0x1136c, 0, NULL, NULL }, - { 0x114c2, 0x114c3, 0, NULL, NULL }, - { 0x114ba, 0x114ba, 0, NULL, NULL }, - { 0x114b3, 0x114b8, 0, NULL, NULL }, - { 0x114bf, 0x114c0, 0, NULL, NULL }, - { 0x115bc, 0x115bd, 0, NULL, NULL }, - { 0x115b2, 0x115b5, 0, NULL, NULL }, - { 0x115bf, 0x115c0, 0, NULL, NULL }, - { 0x1d1aa, 0x1d1ad, 0, NULL, NULL }, - { 0x16b30, 0x16b36, 0, NULL, NULL }, - { 0x116ad, 0x116ad, 0, NULL, NULL }, - { 0x1163f, 0x11640, 0, NULL, NULL }, - { 0x1163d, 0x1163d, 0, NULL, NULL }, - { 0x116ab, 0x116ab, 0, NULL, NULL }, - { 0x116b7, 0x116b7, 0, NULL, NULL }, - { 0x116b0, 0x116b5, 0, NULL, NULL }, - { 0x16af0, 0x16af4, 0, NULL, NULL }, - { 0x1bca0, 0x1bca3, 0, NULL, NULL }, - { 0x1b000, 0x1b001, 2, NULL, NULL }, - { 0x16f8f, 0x16f92, 0, NULL, NULL }, - { 0x1bc9d, 0x1bc9e, 0, NULL, NULL }, - { 0x1d173, 0x1d182, 0, NULL, NULL }, - { 0x1d167, 0x1d169, 0, NULL, NULL }, - { 0x1d185, 0x1d18b, 0, NULL, NULL }, - { 0x2a700, 0x2b734, 2, NULL, NULL }, - { 0x1f210, 0x1f23a, 2, NULL, NULL }, - { 0x1e8d0, 0x1e8d6, 0, NULL, NULL }, - { 0x1d242, 0x1d244, 0, NULL, NULL }, - { 0x1f200, 0x1f202, 2, NULL, NULL }, - { 0x1f250, 0x1f251, 2, NULL, NULL }, - { 0x1f240, 0x1f248, 2, NULL, NULL }, - { 0x20000, 0x2a6d6, 2, NULL, NULL }, - { 0xe0020, 0xe007f, 0, NULL, NULL }, - { 0x2f800, 0x2fa1d, 2, NULL, NULL }, - { 0x2b740, 0x2b81d, 2, NULL, NULL }, - { 0xe0001, 0xe0001, 0, NULL, NULL }, - { 0xf0000, 0xffffd, 0, NULL, NULL }, - { 0xe0100, 0xe01ef, 0, NULL, NULL }, - { 0x100000, 0x10fffd, 0, NULL, NULL }, -}; -static struct utf8_width_entry *utf8_width_root = NULL; - -static void utf8_build(void); - /* Set a single character. */ void utf8_set(struct utf8_data *ud, u_char ch) @@ -420,118 +97,45 @@ utf8_append(struct utf8_data *ud, u_char ch) return (UTF8_DONE); } -/* Build UTF-8 width tree. */ -static void -utf8_build(void) +/* Get width of Unicode character. */ +u_int +utf8_width(wchar_t wc) { - struct utf8_width_entry **ptr, *item, *node; - u_int i; + int width; - for (i = 0; i < nitems(utf8_width_table); i++) { - item = &utf8_width_table[i]; - - ptr = &utf8_width_root; - while (*ptr != NULL) { - node = *ptr; - if (item->last < node->first) - ptr = &node->left; - else if (item->first > node->last) - ptr = &node->right; - } - *ptr = item; - } + width = wcwidth(wc); + if (width < 0) + return (0); + return (width); } -/* Lookup width of UTF-8 data in tree. */ -u_int -utf8_width(u_int uc) -{ - struct utf8_width_entry *item; - - if (utf8_width_root == NULL) - utf8_build(); - - item = utf8_width_root; - while (item != NULL) { - if (uc < item->first) - item = item->left; - else if (uc > item->last) - item = item->right; - else - return (item->width); - } - return (1); -} - -/* Combine UTF-8 into 32-bit Unicode. */ -u_int +/* Combine UTF-8 into Unicode. */ +wchar_t utf8_combine(const struct utf8_data *ud) { - u_int uc; + wchar_t wc; - uc = 0xfffd; - switch (ud->size) { - case 1: - uc = ud->data[0]; - break; - case 2: - uc = ud->data[1] & 0x3f; - uc |= (ud->data[0] & 0x1f) << 6; - break; - case 3: - uc = ud->data[2] & 0x3f; - uc |= (ud->data[1] & 0x3f) << 6; - uc |= (ud->data[0] & 0xf) << 12; - break; - case 4: - uc = ud->data[3] & 0x3f; - uc |= (ud->data[2] & 0x3f) << 6; - uc |= (ud->data[1] & 0x3f) << 12; - uc |= (ud->data[0] & 0x7) << 18; - break; - } - return (uc); + if (mbtowc(&wc, ud->data, ud->size) <= 0) + return (0xfffd); + return (wc); } -/* Split 32-bit Unicode into UTF-8. */ +/* Split Unicode into UTF-8. */ enum utf8_state -utf8_split(u_int uc, struct utf8_data *ud) +utf8_split(wchar_t wc, struct utf8_data *ud) { - if (uc < 0x7f) { - ud->size = 1; - ud->data[0] = uc; - } else if (uc < 0x7ff) { - ud->size = 2; - ud->data[0] = 0xc0 | ((uc >> 6) & 0x1f); - ud->data[1] = 0x80 | (uc & 0x3f); - } else if (uc < 0xffff) { - ud->size = 3; - ud->data[0] = 0xe0 | ((uc >> 12) & 0xf); - ud->data[1] = 0x80 | ((uc >> 6) & 0x3f); - ud->data[2] = 0x80 | (uc & 0x3f); - } else if (uc < 0x1fffff) { - ud->size = 4; - ud->data[0] = 0xf0 | ((uc >> 18) & 0x7); - ud->data[1] = 0x80 | ((uc >> 12) & 0x3f); - ud->data[2] = 0x80 | ((uc >> 6) & 0x3f); - ud->data[3] = 0x80 | (uc & 0x3f); - } else - return (UTF8_ERROR); - ud->width = utf8_width(uc); - return (UTF8_DONE); -} + char s[MB_CUR_MAX]; + int slen; -/* Split a two-byte UTF-8 character. */ -u_int -utf8_split2(u_int uc, u_char *ptr) -{ - if (uc > 0x7f) { - ptr[0] = (uc >> 6) | 0xc0; - ptr[1] = (uc & 0x3f) | 0x80; - return (2); - } - ptr[0] = uc; - return (1); + slen = wctomb(s, wc); + if (slen <= 0 || slen > (int)sizeof ud->data) + return (UTF8_ERROR); + + memcpy(ud->data, s, slen); + ud->size = slen; + + ud->width = utf8_width(wc); + return (UTF8_DONE); } /* From 02753ba9ea89bbeed1a5bba4d5b3a3c6a41e775e Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 19 Feb 2016 13:15:22 +0000 Subject: [PATCH 033/150] Remove unused variables, from Michal Mazurek. --- cmd-swap-pane.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/cmd-swap-pane.c b/cmd-swap-pane.c index aec7753d..13575e0a 100644 --- a/cmd-swap-pane.c +++ b/cmd-swap-pane.c @@ -45,28 +45,23 @@ const struct cmd_entry cmd_swap_pane_entry = { enum cmd_retval cmd_swap_pane_exec(struct cmd *self, struct cmd_q *cmdq) { - struct winlink *src_wl, *dst_wl; struct window *src_w, *dst_w; struct window_pane *tmp_wp, *src_wp, *dst_wp; struct layout_cell *src_lc, *dst_lc; u_int sx, sy, xoff, yoff; - dst_wl = cmdq->state.tflag.wl; - dst_w = dst_wl->window; + dst_w = cmdq->state.tflag.wl->window; dst_wp = cmdq->state.tflag.wp; - src_wl = cmdq->state.sflag.wl; - src_w = src_wl->window; + src_w = cmdq->state.sflag.wl->window; src_wp = cmdq->state.sflag.wp; server_unzoom_window(dst_w); if (args_has(self->args, 'D')) { - src_wl = dst_wl; src_w = dst_w; src_wp = TAILQ_NEXT(dst_wp, entry); if (src_wp == NULL) src_wp = TAILQ_FIRST(&dst_w->panes); } else if (args_has(self->args, 'U')) { - src_wl = dst_wl; src_w = dst_w; src_wp = TAILQ_PREV(dst_wp, window_panes, entry); if (src_wp == NULL) From 95adc0e6bacb32108fd6557e2e5ddeaaaa4fd58e Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 19 Feb 2016 13:28:03 +0000 Subject: [PATCH 034/150] When a mouse drag is finished, fire a MouseUp key press, instead of doing the drag end in code. From Stephen Coakley. --- mode-key.c | 2 ++ server-client.c | 40 ++++++++++++++++++++++++++++++++++++++-- window-copy.c | 15 +-------------- 3 files changed, 41 insertions(+), 16 deletions(-) diff --git a/mode-key.c b/mode-key.c index f38ebf66..a9b15bb9 100644 --- a/mode-key.c +++ b/mode-key.c @@ -347,6 +347,7 @@ const struct mode_key_entry mode_key_vi_copy[] = { { KEYC_WHEELUP_PANE, 0, MODEKEYCOPY_SCROLLUP }, { KEYC_WHEELDOWN_PANE, 0, MODEKEYCOPY_SCROLLDOWN }, { KEYC_MOUSEDRAG1_PANE, 0, MODEKEYCOPY_STARTSELECTION }, + { KEYC_MOUSEUP1_PANE, 0, MODEKEYCOPY_COPYSELECTION }, { 0, -1, 0 } }; @@ -495,6 +496,7 @@ const struct mode_key_entry mode_key_emacs_copy[] = { { KEYC_WHEELUP_PANE, 0, MODEKEYCOPY_SCROLLUP }, { KEYC_WHEELDOWN_PANE, 0, MODEKEYCOPY_SCROLLDOWN }, { KEYC_MOUSEDRAG1_PANE, 0, MODEKEYCOPY_STARTSELECTION }, + { KEYC_MOUSEUP1_PANE, 0, MODEKEYCOPY_COPYSELECTION }, { 0, -1, 0 } }; diff --git a/server-client.c b/server-client.c index 6e98f062..680350df 100644 --- a/server-client.c +++ b/server-client.c @@ -382,8 +382,42 @@ server_client_check_mouse(struct client *c) c->tty.mouse_drag_update = NULL; c->tty.mouse_drag_release = NULL; + /* + * End a mouse drag by passing a MouseUp key corresponding to + * the button that started the drag. + */ + switch (c->tty.mouse_drag_flag) { + case 1: + if (where == PANE) + key = KEYC_MOUSEUP1_PANE; + if (where == STATUS) + key = KEYC_MOUSEUP1_STATUS; + if (where == BORDER) + key = KEYC_MOUSEUP1_BORDER; + break; + case 2: + if (where == PANE) + key = KEYC_MOUSEUP2_PANE; + if (where == STATUS) + key = KEYC_MOUSEUP2_STATUS; + if (where == BORDER) + key = KEYC_MOUSEUP2_BORDER; + break; + case 3: + if (where == PANE) + key = KEYC_MOUSEUP3_PANE; + if (where == STATUS) + key = KEYC_MOUSEUP3_STATUS; + if (where == BORDER) + key = KEYC_MOUSEUP3_BORDER; + break; + default: + key = KEYC_MOUSE; + break; + } c->tty.mouse_drag_flag = 0; - return (KEYC_MOUSE); /* not a key, but still may want to pass */ + + return (key); } /* Convert to a key binding. */ @@ -423,7 +457,9 @@ server_client_check_mouse(struct client *c) } } - c->tty.mouse_drag_flag = 1; + /* Begin a drag by setting the flag to nonzero, where the value + corresponds to the mouse button doing the dragging. */ + c->tty.mouse_drag_flag = MOUSE_BUTTONS(b) + 1; break; case WHEEL: if (MOUSE_BUTTONS(b) == MOUSE_WHEEL_UP) { diff --git a/window-copy.c b/window-copy.c index 009ed246..d345f246 100644 --- a/window-copy.c +++ b/window-copy.c @@ -2248,7 +2248,7 @@ window_copy_start_drag(struct client *c, struct mouse_event *m) return; c->tty.mouse_drag_update = window_copy_drag_update; - c->tty.mouse_drag_release = window_copy_drag_release; + c->tty.mouse_drag_release = NULL; /* will fire MouseUp key */ window_copy_update_cursor(wp, x, y); window_copy_start_selection(wp); @@ -2275,16 +2275,3 @@ window_copy_drag_update(__unused struct client *c, struct mouse_event *m) if (window_copy_update_selection(wp, 1)) window_copy_redraw_selection(wp, old_cy); } - -void -window_copy_drag_release(__unused struct client *c, struct mouse_event *m) -{ - struct window_pane *wp; - - wp = cmd_mouse_pane(m, NULL, NULL); - if (wp == NULL || wp->mode != &window_copy_mode) - return; - - window_copy_copy_selection(wp, NULL); - window_pane_reset_mode(wp); -} From 6adf5615075944e87b2a988d5507cca5d9151826 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 19 Feb 2016 13:29:59 +0000 Subject: [PATCH 035/150] Redraw status on mode entry and exit. --- window.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/window.c b/window.c index a364948f..236d2436 100644 --- a/window.c +++ b/window.c @@ -1100,6 +1100,8 @@ window_pane_set_mode(struct window_pane *wp, const struct window_mode *mode) if ((s = wp->mode->init(wp)) != NULL) wp->screen = s; wp->flags |= (PANE_REDRAW|PANE_CHANGED); + + server_status_window(wp->window); return (0); } @@ -1114,6 +1116,8 @@ window_pane_reset_mode(struct window_pane *wp) wp->screen = &wp->base; wp->flags |= (PANE_REDRAW|PANE_CHANGED); + + server_status_window(wp->window); } void From e9d369a09e48ea8f940958025c8444988d31e840 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 19 Feb 2016 13:35:46 +0000 Subject: [PATCH 036/150] Fixed fgetln(3) implementation (from Joerg Jung) which does not depend on *BSD fgets(3) semantics. --- compat/fgetln.c | 110 +++++++++++++++++++----------------------------- 1 file changed, 43 insertions(+), 67 deletions(-) diff --git a/compat/fgetln.c b/compat/fgetln.c index a5c2489d..0ad6378a 100644 --- a/compat/fgetln.c +++ b/compat/fgetln.c @@ -1,43 +1,26 @@ -/* $NetBSD: fgetln.c,v 1.3 2007/08/07 02:06:58 lukem Exp $ */ - -/*- - * Copyright (c) 1998 The NetBSD Foundation, Inc. - * All rights reserved. +/* + * Copyright (c) 2015 Joerg Jung * - * This code is derived from software contributed to The NetBSD Foundation - * by Christos Zoulas. + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include +/* + * portable fgetln() version, NOT reentrant + */ -#include #include #include -#include +#include #include "tmux.h" @@ -45,41 +28,34 @@ char * fgetln(FILE *fp, size_t *len) { static char *buf = NULL; - static size_t bufsiz = 0; - char *ptr; + static size_t bufsz = 0; + size_t r = 0; + char *p; + int c, e; - - if (buf == NULL) { - bufsiz = BUFSIZ; - if ((buf = malloc(bufsiz)) == NULL) - return NULL; - } - - if (fgets(buf, bufsiz, fp) == NULL) + if (!fp || !len) { + errno = EINVAL; return NULL; - - *len = 0; - while ((ptr = strchr(&buf[*len], '\n')) == NULL) { - size_t nbufsiz = bufsiz + BUFSIZ; - char *nbuf = realloc(buf, nbufsiz); - - if (nbuf == NULL) { - int oerrno = errno; - free(buf); - errno = oerrno; - buf = NULL; - return NULL; - } else - buf = nbuf; - - *len = bufsiz; - if (fgets(&buf[bufsiz], BUFSIZ, fp) == NULL) - return buf; - - bufsiz = nbufsiz; } - - *len = (ptr - buf) + 1; - return buf; + if (!buf) { + if (!(buf = calloc(1, BUFSIZ))) + return NULL; + bufsz = BUFSIZ; + } + while ((c = getc(fp)) != EOF) { + buf[r++] = c; + if (r == bufsz) { + if (!(p = reallocarray(buf, 2, bufsz))) { + e = errno; + free(buf); + errno = e; + buf = NULL, bufsz = 0; + return NULL; + } + buf = p, bufsz = 2 * bufsz; + } + if (c == '\n') + break; + } + return (*len = r) ? buf : NULL; } - From c3f93e71785290d717ecf60623b99b30d4941850 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 19 Feb 2016 16:45:15 +0000 Subject: [PATCH 037/150] Add to TODO. --- TODO | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TODO b/TODO index 18d3ae61..4a284220 100644 --- a/TODO +++ b/TODO @@ -131,7 +131,7 @@ comes from config for new sessions and windows. likewise, panes and jobs and run-shell and lock command all start with slightly different environments - * multiline status line? + * multiline status line? separate command prompt and status line? * customizable command aliases * automatic pane logging * BCE? We are halfway there (output side is done for pane backgrounds), From a011b67f56448b38e251418f0af67ff12411a0a0 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 19 Feb 2016 16:45:35 +0000 Subject: [PATCH 038/150] Remove unused variables. --- cmd-if-shell.c | 3 +-- cmd-resize-pane.c | 1 - cmd.c | 1 - key-bindings.c | 4 ++-- 4 files changed, 3 insertions(+), 6 deletions(-) diff --git a/cmd-if-shell.c b/cmd-if-shell.c index 229289cd..3e2a5251 100644 --- a/cmd-if-shell.c +++ b/cmd-if-shell.c @@ -73,14 +73,13 @@ cmd_if_shell_exec(struct cmd *self, struct cmd_q *cmdq) struct format_tree *ft; const char *cwd; - cwd = wp->cwd; - if (cmdq->client != NULL && cmdq->client->session == NULL) cwd = cmdq->client->cwd; else if (s != NULL) cwd = s->cwd; else cwd = NULL; + ft = format_create(cmdq, 0); format_defaults(ft, NULL, s, wl, wp); shellcmd = format_expand(ft, args->argv[0]); diff --git a/cmd-resize-pane.c b/cmd-resize-pane.c index 2b4f1c17..7ec65f10 100644 --- a/cmd-resize-pane.c +++ b/cmd-resize-pane.c @@ -68,7 +68,6 @@ cmd_resize_pane_exec(struct cmd *self, struct cmd_q *cmdq) return (CMD_RETURN_NORMAL); } - w = wl->window; if (args_has(args, 'Z')) { if (w->flags & WINDOW_ZOOMED) window_unzoom(w); diff --git a/cmd.c b/cmd.c index b0517e62..28efa0c5 100644 --- a/cmd.c +++ b/cmd.c @@ -481,7 +481,6 @@ cmd_prepare_state_flag(char c, const char *target, enum cmd_entry_flag flag, CMD_FIND_SESSION, CMD_FIND_QUIET); if (error == 0) break; - flag = CMD_WINDOW_INDEX; /* FALLTHROUGH */ case CMD_WINDOW: case CMD_WINDOW_CANFAIL: diff --git a/key-bindings.c b/key-bindings.c index a922eb18..0d13385d 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -68,12 +68,12 @@ void key_bindings_unref_table(struct key_table *table) { struct key_binding *bd; + struct key_binding *bd1; if (--table->references != 0) return; - while (!RB_EMPTY(&table->key_bindings)) { - bd = RB_ROOT(&table->key_bindings); + RB_FOREACH_SAFE(bd, key_bindings, &table->key_bindings, bd1) { RB_REMOVE(key_bindings, &table->key_bindings, bd); cmd_list_free(bd->cmdlist); free(bd); From c7851e0ee71e26ee9af67f2523679132369b152f Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 1 Mar 2016 11:58:45 +0000 Subject: [PATCH 039/150] Fix break-pane synopsis and some other tmux.1 bits. --- cmd-break-pane.c | 2 +- tmux.1 | 13 ++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/cmd-break-pane.c b/cmd-break-pane.c index b5a2743f..85873227 100644 --- a/cmd-break-pane.c +++ b/cmd-break-pane.c @@ -35,7 +35,7 @@ const struct cmd_entry cmd_break_pane_entry = { .alias = "breakp", .args = { "dPF:s:t:", 0, 0 }, - .usage = "[-dP] [-F format] " CMD_SRCDST_PANE_USAGE, + .usage = "[-dP] [-F format] [-s src-pane] [-t dst-window]", .sflag = CMD_PANE, .tflag = CMD_WINDOW_INDEX, diff --git a/tmux.1 b/tmux.1 index 5dbf6b84..448673f1 100644 --- a/tmux.1 +++ b/tmux.1 @@ -717,7 +717,7 @@ will set the session working directory (used for new windows) to .Pp If .Fl E -is used, +is used, the .Ic update-environment option will not be applied. .It Xo Ic detach-client @@ -853,13 +853,12 @@ with .Ar target-session . This means they share the same set of windows - all windows from .Ar target-session -are linked to the new session and any subsequent new windows or windows being -closed are applied to both sessions. +are linked to the new session, any new windows are linked to both sessions and +any windows closed removed from both sessions. The current and previous window and any session options remain independent and either session may be killed without affecting the other. -Giving .Fl n -or +and .Ar shell-command are invalid if .Fl t @@ -875,7 +874,7 @@ but a different format may be specified with .Pp If .Fl E -is used, +is used, the .Ic update-environment option will not be applied. .It Xo Ic refresh-client @@ -1250,7 +1249,7 @@ Commands related to windows and panes are as follows: .Op Fl dP .Op Fl F Ar format .Op Fl s Ar src-pane -.Op Fl t Ar dst-pane +.Op Fl t Ar dst-window .Xc .D1 (alias: Ic breakp ) Break From 26945d7956bf1f160fba72677082e1a9c6968e0c Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 1 Mar 2016 12:02:08 +0000 Subject: [PATCH 040/150] Use system wcwidth() instead of carrying around UTF-8 width tables. --- input-keys.c | 19 ++- tmux.c | 3 + tmux.h | 8 +- utf8.c | 452 ++++----------------------------------------------- 4 files changed, 51 insertions(+), 431 deletions(-) diff --git a/input-keys.c b/input-keys.c index 254845cb..47786d27 100644 --- a/input-keys.c +++ b/input-keys.c @@ -135,6 +135,19 @@ const struct input_key_ent input_keys[] = { { KEYC_KP_PERIOD, ".", 0 }, }; +/* Split a character into two UTF-8 bytes. */ +static size_t +input_split2(u_int c, u_char *dst) +{ + if (c > 0x7f) { + dst[0] = (c >> 6) | 0xc0; + dst[1] = (c & 0x3f) | 0x80; + return (2); + } + dst[0] = c; + return (1); +} + /* Translate a key code into an output key sequence. */ void input_key(struct window_pane *wp, key_code key, struct mouse_event *m) @@ -251,9 +264,9 @@ input_key_mouse(struct window_pane *wp, struct mouse_event *m) m->sgr_b, x + 1, y + 1, m->sgr_type); } else if (wp->screen->mode & MODE_MOUSE_UTF8) { len = xsnprintf(buf, sizeof buf, "\033[M"); - len += utf8_split2(m->b + 32, &buf[len]); - len += utf8_split2(x + 33, &buf[len]); - len += utf8_split2(y + 33, &buf[len]); + len += input_split2(m->b + 32, &buf[len]); + len += input_split2(x + 33, &buf[len]); + len += input_split2(y + 33, &buf[len]); } else { if (m->b > 223) return; diff --git a/tmux.c b/tmux.c index 1ee2a269..68cd4bb7 100644 --- a/tmux.c +++ b/tmux.c @@ -188,7 +188,10 @@ main(int argc, char **argv) const char *s; int opt, flags, keys; + + setlocale(LC_CTYPE, "en_US.UTF-8"); setlocale(LC_TIME, ""); + tzset(); if (**argv == '-') diff --git a/tmux.h b/tmux.h index 997690fc..b00c7469 100644 --- a/tmux.h +++ b/tmux.h @@ -32,6 +32,7 @@ #include #include #include +#include #include "xmalloc.h" @@ -2311,14 +2312,13 @@ void session_group_synchronize1(struct session *, struct session *); void session_renumber_windows(struct session *); /* utf8.c */ -u_int utf8_width(u_int); void utf8_set(struct utf8_data *, u_char); void utf8_copy(struct utf8_data *, const struct utf8_data *); enum utf8_state utf8_open(struct utf8_data *, u_char); enum utf8_state utf8_append(struct utf8_data *, u_char); -u_int utf8_combine(const struct utf8_data *); -enum utf8_state utf8_split(u_int, struct utf8_data *); -u_int utf8_split2(u_int, u_char *); +u_int utf8_width(wchar_t); +wchar_t utf8_combine(const struct utf8_data *); +enum utf8_state utf8_split(wchar_t, struct utf8_data *); int utf8_strvis(char *, const char *, size_t, int); char *utf8_sanitize(const char *); struct utf8_data *utf8_fromcstr(const char *); diff --git a/utf8.c b/utf8.c index 3f6107a7..be0915ba 100644 --- a/utf8.c +++ b/utf8.c @@ -21,333 +21,10 @@ #include #include #include +#include #include "tmux.h" -struct utf8_width_entry { - u_int first; - u_int last; - - int width; - - struct utf8_width_entry *left; - struct utf8_width_entry *right; -}; - -/* Sorted, then repeatedly split in the middle to balance the tree. */ -static struct utf8_width_entry utf8_width_table[] = { - { 0x00b41, 0x00b44, 0, NULL, NULL }, - { 0x008e4, 0x00902, 0, NULL, NULL }, - { 0x006d6, 0x006dd, 0, NULL, NULL }, - { 0x005c4, 0x005c5, 0, NULL, NULL }, - { 0x00591, 0x005bd, 0, NULL, NULL }, - { 0x00300, 0x0036f, 0, NULL, NULL }, - { 0x00483, 0x00489, 0, NULL, NULL }, - { 0x005bf, 0x005bf, 0, NULL, NULL }, - { 0x005c1, 0x005c2, 0, NULL, NULL }, - { 0x00610, 0x0061a, 0, NULL, NULL }, - { 0x00600, 0x00605, 0, NULL, NULL }, - { 0x005c7, 0x005c7, 0, NULL, NULL }, - { 0x0064b, 0x0065f, 0, NULL, NULL }, - { 0x0061c, 0x0061c, 0, NULL, NULL }, - { 0x00670, 0x00670, 0, NULL, NULL }, - { 0x007a6, 0x007b0, 0, NULL, NULL }, - { 0x006ea, 0x006ed, 0, NULL, NULL }, - { 0x006df, 0x006e4, 0, NULL, NULL }, - { 0x006e7, 0x006e8, 0, NULL, NULL }, - { 0x00711, 0x00711, 0, NULL, NULL }, - { 0x0070f, 0x0070f, 0, NULL, NULL }, - { 0x00730, 0x0074a, 0, NULL, NULL }, - { 0x0081b, 0x00823, 0, NULL, NULL }, - { 0x007eb, 0x007f3, 0, NULL, NULL }, - { 0x00816, 0x00819, 0, NULL, NULL }, - { 0x00829, 0x0082d, 0, NULL, NULL }, - { 0x00825, 0x00827, 0, NULL, NULL }, - { 0x00859, 0x0085b, 0, NULL, NULL }, - { 0x00a41, 0x00a42, 0, NULL, NULL }, - { 0x00981, 0x00981, 0, NULL, NULL }, - { 0x00941, 0x00948, 0, NULL, NULL }, - { 0x0093a, 0x0093a, 0, NULL, NULL }, - { 0x0093c, 0x0093c, 0, NULL, NULL }, - { 0x00951, 0x00957, 0, NULL, NULL }, - { 0x0094d, 0x0094d, 0, NULL, NULL }, - { 0x00962, 0x00963, 0, NULL, NULL }, - { 0x009e2, 0x009e3, 0, NULL, NULL }, - { 0x009c1, 0x009c4, 0, NULL, NULL }, - { 0x009bc, 0x009bc, 0, NULL, NULL }, - { 0x009cd, 0x009cd, 0, NULL, NULL }, - { 0x00a01, 0x00a02, 0, NULL, NULL }, - { 0x00a3c, 0x00a3c, 0, NULL, NULL }, - { 0x00ac1, 0x00ac5, 0, NULL, NULL }, - { 0x00a70, 0x00a71, 0, NULL, NULL }, - { 0x00a4b, 0x00a4d, 0, NULL, NULL }, - { 0x00a47, 0x00a48, 0, NULL, NULL }, - { 0x00a51, 0x00a51, 0, NULL, NULL }, - { 0x00a81, 0x00a82, 0, NULL, NULL }, - { 0x00a75, 0x00a75, 0, NULL, NULL }, - { 0x00abc, 0x00abc, 0, NULL, NULL }, - { 0x00ae2, 0x00ae3, 0, NULL, NULL }, - { 0x00ac7, 0x00ac8, 0, NULL, NULL }, - { 0x00acd, 0x00acd, 0, NULL, NULL }, - { 0x00b3c, 0x00b3c, 0, NULL, NULL }, - { 0x00b01, 0x00b01, 0, NULL, NULL }, - { 0x00b3f, 0x00b3f, 0, NULL, NULL }, - { 0x03190, 0x031ba, 2, NULL, NULL }, - { 0x017c9, 0x017d3, 0, NULL, NULL }, - { 0x00ec8, 0x00ecd, 0, NULL, NULL }, - { 0x00cc6, 0x00cc6, 0, NULL, NULL }, - { 0x00c3e, 0x00c40, 0, NULL, NULL }, - { 0x00b82, 0x00b82, 0, NULL, NULL }, - { 0x00b56, 0x00b56, 0, NULL, NULL }, - { 0x00b4d, 0x00b4d, 0, NULL, NULL }, - { 0x00b62, 0x00b63, 0, NULL, NULL }, - { 0x00bcd, 0x00bcd, 0, NULL, NULL }, - { 0x00bc0, 0x00bc0, 0, NULL, NULL }, - { 0x00c00, 0x00c00, 0, NULL, NULL }, - { 0x00c62, 0x00c63, 0, NULL, NULL }, - { 0x00c4a, 0x00c4d, 0, NULL, NULL }, - { 0x00c46, 0x00c48, 0, NULL, NULL }, - { 0x00c55, 0x00c56, 0, NULL, NULL }, - { 0x00cbc, 0x00cbc, 0, NULL, NULL }, - { 0x00c81, 0x00c81, 0, NULL, NULL }, - { 0x00cbf, 0x00cbf, 0, NULL, NULL }, - { 0x00dd2, 0x00dd4, 0, NULL, NULL }, - { 0x00d41, 0x00d44, 0, NULL, NULL }, - { 0x00ce2, 0x00ce3, 0, NULL, NULL }, - { 0x00ccc, 0x00ccd, 0, NULL, NULL }, - { 0x00d01, 0x00d01, 0, NULL, NULL }, - { 0x00d62, 0x00d63, 0, NULL, NULL }, - { 0x00d4d, 0x00d4d, 0, NULL, NULL }, - { 0x00dca, 0x00dca, 0, NULL, NULL }, - { 0x00e47, 0x00e4e, 0, NULL, NULL }, - { 0x00e31, 0x00e31, 0, NULL, NULL }, - { 0x00dd6, 0x00dd6, 0, NULL, NULL }, - { 0x00e34, 0x00e3a, 0, NULL, NULL }, - { 0x00eb4, 0x00eb9, 0, NULL, NULL }, - { 0x00eb1, 0x00eb1, 0, NULL, NULL }, - { 0x00ebb, 0x00ebc, 0, NULL, NULL }, - { 0x0105e, 0x01060, 0, NULL, NULL }, - { 0x00f8d, 0x00f97, 0, NULL, NULL }, - { 0x00f39, 0x00f39, 0, NULL, NULL }, - { 0x00f35, 0x00f35, 0, NULL, NULL }, - { 0x00f18, 0x00f19, 0, NULL, NULL }, - { 0x00f37, 0x00f37, 0, NULL, NULL }, - { 0x00f80, 0x00f84, 0, NULL, NULL }, - { 0x00f71, 0x00f7e, 0, NULL, NULL }, - { 0x00f86, 0x00f87, 0, NULL, NULL }, - { 0x01032, 0x01037, 0, NULL, NULL }, - { 0x00fc6, 0x00fc6, 0, NULL, NULL }, - { 0x00f99, 0x00fbc, 0, NULL, NULL }, - { 0x0102d, 0x01030, 0, NULL, NULL }, - { 0x0103d, 0x0103e, 0, NULL, NULL }, - { 0x01039, 0x0103a, 0, NULL, NULL }, - { 0x01058, 0x01059, 0, NULL, NULL }, - { 0x0135d, 0x0135f, 0, NULL, NULL }, - { 0x01085, 0x01086, 0, NULL, NULL }, - { 0x01071, 0x01074, 0, NULL, NULL }, - { 0x01082, 0x01082, 0, NULL, NULL }, - { 0x0109d, 0x0109d, 0, NULL, NULL }, - { 0x0108d, 0x0108d, 0, NULL, NULL }, - { 0x01100, 0x011ff, 2, NULL, NULL }, - { 0x01772, 0x01773, 0, NULL, NULL }, - { 0x01732, 0x01734, 0, NULL, NULL }, - { 0x01712, 0x01714, 0, NULL, NULL }, - { 0x01752, 0x01753, 0, NULL, NULL }, - { 0x017b7, 0x017bd, 0, NULL, NULL }, - { 0x017b4, 0x017b5, 0, NULL, NULL }, - { 0x017c6, 0x017c6, 0, NULL, NULL }, - { 0x01c2c, 0x01c33, 0, NULL, NULL }, - { 0x01a7f, 0x01a7f, 0, NULL, NULL }, - { 0x01a17, 0x01a18, 0, NULL, NULL }, - { 0x01920, 0x01922, 0, NULL, NULL }, - { 0x0180b, 0x0180e, 0, NULL, NULL }, - { 0x017dd, 0x017dd, 0, NULL, NULL }, - { 0x018a9, 0x018a9, 0, NULL, NULL }, - { 0x01932, 0x01932, 0, NULL, NULL }, - { 0x01927, 0x01928, 0, NULL, NULL }, - { 0x01939, 0x0193b, 0, NULL, NULL }, - { 0x01a60, 0x01a60, 0, NULL, NULL }, - { 0x01a56, 0x01a56, 0, NULL, NULL }, - { 0x01a1b, 0x01a1b, 0, NULL, NULL }, - { 0x01a58, 0x01a5e, 0, NULL, NULL }, - { 0x01a65, 0x01a6c, 0, NULL, NULL }, - { 0x01a62, 0x01a62, 0, NULL, NULL }, - { 0x01a73, 0x01a7c, 0, NULL, NULL }, - { 0x01b80, 0x01b81, 0, NULL, NULL }, - { 0x01b36, 0x01b3a, 0, NULL, NULL }, - { 0x01b00, 0x01b03, 0, NULL, NULL }, - { 0x01ab0, 0x01abe, 0, NULL, NULL }, - { 0x01b34, 0x01b34, 0, NULL, NULL }, - { 0x01b42, 0x01b42, 0, NULL, NULL }, - { 0x01b3c, 0x01b3c, 0, NULL, NULL }, - { 0x01b6b, 0x01b73, 0, NULL, NULL }, - { 0x01be6, 0x01be6, 0, NULL, NULL }, - { 0x01ba8, 0x01ba9, 0, NULL, NULL }, - { 0x01ba2, 0x01ba5, 0, NULL, NULL }, - { 0x01bab, 0x01bad, 0, NULL, NULL }, - { 0x01bed, 0x01bed, 0, NULL, NULL }, - { 0x01be8, 0x01be9, 0, NULL, NULL }, - { 0x01bef, 0x01bf1, 0, NULL, NULL }, - { 0x02329, 0x0232a, 2, NULL, NULL }, - { 0x01dc0, 0x01df5, 0, NULL, NULL }, - { 0x01ce2, 0x01ce8, 0, NULL, NULL }, - { 0x01cd0, 0x01cd2, 0, NULL, NULL }, - { 0x01c36, 0x01c37, 0, NULL, NULL }, - { 0x01cd4, 0x01ce0, 0, NULL, NULL }, - { 0x01cf4, 0x01cf4, 0, NULL, NULL }, - { 0x01ced, 0x01ced, 0, NULL, NULL }, - { 0x01cf8, 0x01cf9, 0, NULL, NULL }, - { 0x02060, 0x02064, 0, NULL, NULL }, - { 0x0200b, 0x0200f, 0, NULL, NULL }, - { 0x01dfc, 0x01dff, 0, NULL, NULL }, - { 0x0202a, 0x0202e, 0, NULL, NULL }, - { 0x02066, 0x0206f, 0, NULL, NULL }, - { 0x020d0, 0x020f0, 0, NULL, NULL }, - { 0x03001, 0x03029, 2, NULL, NULL }, - { 0x02e80, 0x02e99, 2, NULL, NULL }, - { 0x02d7f, 0x02d7f, 0, NULL, NULL }, - { 0x02cef, 0x02cf1, 0, NULL, NULL }, - { 0x02de0, 0x02dff, 0, NULL, NULL }, - { 0x02f00, 0x02fd5, 2, NULL, NULL }, - { 0x02e9b, 0x02ef3, 2, NULL, NULL }, - { 0x02ff0, 0x02ffb, 2, NULL, NULL }, - { 0x03099, 0x0309a, 0, NULL, NULL }, - { 0x0302e, 0x0303e, 2, NULL, NULL }, - { 0x0302a, 0x0302d, 0, NULL, NULL }, - { 0x03041, 0x03096, 2, NULL, NULL }, - { 0x03105, 0x0312d, 2, NULL, NULL }, - { 0x0309b, 0x030ff, 2, NULL, NULL }, - { 0x03131, 0x0318e, 2, NULL, NULL }, - { 0x10a3f, 0x10a3f, 0, NULL, NULL }, - { 0x0aa4c, 0x0aa4c, 0, NULL, NULL }, - { 0x0a825, 0x0a826, 0, NULL, NULL }, - { 0x0a490, 0x0a4c6, 2, NULL, NULL }, - { 0x03250, 0x032fe, 2, NULL, NULL }, - { 0x031f0, 0x0321e, 2, NULL, NULL }, - { 0x031c0, 0x031e3, 2, NULL, NULL }, - { 0x03220, 0x03247, 2, NULL, NULL }, - { 0x04e00, 0x09fcc, 2, NULL, NULL }, - { 0x03300, 0x04db5, 2, NULL, NULL }, - { 0x0a000, 0x0a48c, 2, NULL, NULL }, - { 0x0a6f0, 0x0a6f1, 0, NULL, NULL }, - { 0x0a674, 0x0a67d, 0, NULL, NULL }, - { 0x0a66f, 0x0a672, 0, NULL, NULL }, - { 0x0a69f, 0x0a69f, 0, NULL, NULL }, - { 0x0a806, 0x0a806, 0, NULL, NULL }, - { 0x0a802, 0x0a802, 0, NULL, NULL }, - { 0x0a80b, 0x0a80b, 0, NULL, NULL }, - { 0x0a9b6, 0x0a9b9, 0, NULL, NULL }, - { 0x0a947, 0x0a951, 0, NULL, NULL }, - { 0x0a8e0, 0x0a8f1, 0, NULL, NULL }, - { 0x0a8c4, 0x0a8c4, 0, NULL, NULL }, - { 0x0a926, 0x0a92d, 0, NULL, NULL }, - { 0x0a980, 0x0a982, 0, NULL, NULL }, - { 0x0a960, 0x0a97c, 2, NULL, NULL }, - { 0x0a9b3, 0x0a9b3, 0, NULL, NULL }, - { 0x0aa29, 0x0aa2e, 0, NULL, NULL }, - { 0x0a9bc, 0x0a9bc, 0, NULL, NULL }, - { 0x0a9e5, 0x0a9e5, 0, NULL, NULL }, - { 0x0aa35, 0x0aa36, 0, NULL, NULL }, - { 0x0aa31, 0x0aa32, 0, NULL, NULL }, - { 0x0aa43, 0x0aa43, 0, NULL, NULL }, - { 0x0fb1e, 0x0fb1e, 0, NULL, NULL }, - { 0x0aaf6, 0x0aaf6, 0, NULL, NULL }, - { 0x0aab7, 0x0aab8, 0, NULL, NULL }, - { 0x0aab0, 0x0aab0, 0, NULL, NULL }, - { 0x0aa7c, 0x0aa7c, 0, NULL, NULL }, - { 0x0aab2, 0x0aab4, 0, NULL, NULL }, - { 0x0aac1, 0x0aac1, 0, NULL, NULL }, - { 0x0aabe, 0x0aabf, 0, NULL, NULL }, - { 0x0aaec, 0x0aaed, 0, NULL, NULL }, - { 0x0ac00, 0x0d7a3, 2, NULL, NULL }, - { 0x0abe8, 0x0abe8, 0, NULL, NULL }, - { 0x0abe5, 0x0abe5, 0, NULL, NULL }, - { 0x0abed, 0x0abed, 0, NULL, NULL }, - { 0x0f900, 0x0fa6d, 2, NULL, NULL }, - { 0x0d800, 0x0dfff, 0, NULL, NULL }, - { 0x0fa70, 0x0fad9, 2, NULL, NULL }, - { 0x0fff9, 0x0fffb, 0, NULL, NULL }, - { 0x0fe30, 0x0fe52, 2, NULL, NULL }, - { 0x0fe10, 0x0fe19, 2, NULL, NULL }, - { 0x0fe00, 0x0fe0f, 0, NULL, NULL }, - { 0x0fe20, 0x0fe2d, 0, NULL, NULL }, - { 0x0fe68, 0x0fe6b, 2, NULL, NULL }, - { 0x0fe54, 0x0fe66, 2, NULL, NULL }, - { 0x0feff, 0x0feff, 0, NULL, NULL }, - { 0x10a01, 0x10a03, 0, NULL, NULL }, - { 0x102e0, 0x102e0, 0, NULL, NULL }, - { 0x101fd, 0x101fd, 0, NULL, NULL }, - { 0x10376, 0x1037a, 0, NULL, NULL }, - { 0x10a0c, 0x10a0f, 0, NULL, NULL }, - { 0x10a05, 0x10a06, 0, NULL, NULL }, - { 0x10a38, 0x10a3a, 0, NULL, NULL }, - { 0x11633, 0x1163a, 0, NULL, NULL }, - { 0x11236, 0x11237, 0, NULL, NULL }, - { 0x11100, 0x11102, 0, NULL, NULL }, - { 0x1107f, 0x11081, 0, NULL, NULL }, - { 0x11001, 0x11001, 0, NULL, NULL }, - { 0x10ae5, 0x10ae6, 0, NULL, NULL }, - { 0x11038, 0x11046, 0, NULL, NULL }, - { 0x110b9, 0x110ba, 0, NULL, NULL }, - { 0x110b3, 0x110b6, 0, NULL, NULL }, - { 0x110bd, 0x110bd, 0, NULL, NULL }, - { 0x11180, 0x11181, 0, NULL, NULL }, - { 0x1112d, 0x11134, 0, NULL, NULL }, - { 0x11127, 0x1112b, 0, NULL, NULL }, - { 0x11173, 0x11173, 0, NULL, NULL }, - { 0x1122f, 0x11231, 0, NULL, NULL }, - { 0x111b6, 0x111be, 0, NULL, NULL }, - { 0x11234, 0x11234, 0, NULL, NULL }, - { 0x11370, 0x11374, 0, NULL, NULL }, - { 0x11301, 0x11301, 0, NULL, NULL }, - { 0x112df, 0x112df, 0, NULL, NULL }, - { 0x112e3, 0x112ea, 0, NULL, NULL }, - { 0x11340, 0x11340, 0, NULL, NULL }, - { 0x1133c, 0x1133c, 0, NULL, NULL }, - { 0x11366, 0x1136c, 0, NULL, NULL }, - { 0x114c2, 0x114c3, 0, NULL, NULL }, - { 0x114ba, 0x114ba, 0, NULL, NULL }, - { 0x114b3, 0x114b8, 0, NULL, NULL }, - { 0x114bf, 0x114c0, 0, NULL, NULL }, - { 0x115bc, 0x115bd, 0, NULL, NULL }, - { 0x115b2, 0x115b5, 0, NULL, NULL }, - { 0x115bf, 0x115c0, 0, NULL, NULL }, - { 0x1d1aa, 0x1d1ad, 0, NULL, NULL }, - { 0x16b30, 0x16b36, 0, NULL, NULL }, - { 0x116ad, 0x116ad, 0, NULL, NULL }, - { 0x1163f, 0x11640, 0, NULL, NULL }, - { 0x1163d, 0x1163d, 0, NULL, NULL }, - { 0x116ab, 0x116ab, 0, NULL, NULL }, - { 0x116b7, 0x116b7, 0, NULL, NULL }, - { 0x116b0, 0x116b5, 0, NULL, NULL }, - { 0x16af0, 0x16af4, 0, NULL, NULL }, - { 0x1bca0, 0x1bca3, 0, NULL, NULL }, - { 0x1b000, 0x1b001, 2, NULL, NULL }, - { 0x16f8f, 0x16f92, 0, NULL, NULL }, - { 0x1bc9d, 0x1bc9e, 0, NULL, NULL }, - { 0x1d173, 0x1d182, 0, NULL, NULL }, - { 0x1d167, 0x1d169, 0, NULL, NULL }, - { 0x1d185, 0x1d18b, 0, NULL, NULL }, - { 0x2a700, 0x2b734, 2, NULL, NULL }, - { 0x1f210, 0x1f23a, 2, NULL, NULL }, - { 0x1e8d0, 0x1e8d6, 0, NULL, NULL }, - { 0x1d242, 0x1d244, 0, NULL, NULL }, - { 0x1f200, 0x1f202, 2, NULL, NULL }, - { 0x1f250, 0x1f251, 2, NULL, NULL }, - { 0x1f240, 0x1f248, 2, NULL, NULL }, - { 0x20000, 0x2a6d6, 2, NULL, NULL }, - { 0xe0020, 0xe007f, 0, NULL, NULL }, - { 0x2f800, 0x2fa1d, 2, NULL, NULL }, - { 0x2b740, 0x2b81d, 2, NULL, NULL }, - { 0xe0001, 0xe0001, 0, NULL, NULL }, - { 0xf0000, 0xffffd, 0, NULL, NULL }, - { 0xe0100, 0xe01ef, 0, NULL, NULL }, - { 0x100000, 0x10fffd, 0, NULL, NULL }, -}; -static struct utf8_width_entry *utf8_width_root = NULL; - -static void utf8_build(void); - /* Set a single character. */ void utf8_set(struct utf8_data *ud, u_char ch) @@ -421,118 +98,45 @@ utf8_append(struct utf8_data *ud, u_char ch) return (UTF8_DONE); } -/* Build UTF-8 width tree. */ -static void -utf8_build(void) +/* Get width of Unicode character. */ +u_int +utf8_width(wchar_t wc) { - struct utf8_width_entry **ptr, *item, *node; - u_int i; + int width; - for (i = 0; i < nitems(utf8_width_table); i++) { - item = &utf8_width_table[i]; - - ptr = &utf8_width_root; - while (*ptr != NULL) { - node = *ptr; - if (item->last < node->first) - ptr = &node->left; - else if (item->first > node->last) - ptr = &node->right; - } - *ptr = item; - } + width = wcwidth(wc); + if (width < 0) + return (0); + return (width); } -/* Lookup width of UTF-8 data in tree. */ -u_int -utf8_width(u_int uc) -{ - struct utf8_width_entry *item; - - if (utf8_width_root == NULL) - utf8_build(); - - item = utf8_width_root; - while (item != NULL) { - if (uc < item->first) - item = item->left; - else if (uc > item->last) - item = item->right; - else - return (item->width); - } - return (1); -} - -/* Combine UTF-8 into 32-bit Unicode. */ -u_int +/* Combine UTF-8 into Unicode. */ +wchar_t utf8_combine(const struct utf8_data *ud) { - u_int uc; + wchar_t wc; - uc = 0xfffd; - switch (ud->size) { - case 1: - uc = ud->data[0]; - break; - case 2: - uc = ud->data[1] & 0x3f; - uc |= (ud->data[0] & 0x1f) << 6; - break; - case 3: - uc = ud->data[2] & 0x3f; - uc |= (ud->data[1] & 0x3f) << 6; - uc |= (ud->data[0] & 0xf) << 12; - break; - case 4: - uc = ud->data[3] & 0x3f; - uc |= (ud->data[2] & 0x3f) << 6; - uc |= (ud->data[1] & 0x3f) << 12; - uc |= (ud->data[0] & 0x7) << 18; - break; - } - return (uc); + if (mbtowc(&wc, ud->data, ud->size) <= 0) + return (0xfffd); + return (wc); } -/* Split 32-bit Unicode into UTF-8. */ +/* Split Unicode into UTF-8. */ enum utf8_state -utf8_split(u_int uc, struct utf8_data *ud) +utf8_split(wchar_t wc, struct utf8_data *ud) { - if (uc < 0x7f) { - ud->size = 1; - ud->data[0] = uc; - } else if (uc < 0x7ff) { - ud->size = 2; - ud->data[0] = 0xc0 | ((uc >> 6) & 0x1f); - ud->data[1] = 0x80 | (uc & 0x3f); - } else if (uc < 0xffff) { - ud->size = 3; - ud->data[0] = 0xe0 | ((uc >> 12) & 0xf); - ud->data[1] = 0x80 | ((uc >> 6) & 0x3f); - ud->data[2] = 0x80 | (uc & 0x3f); - } else if (uc < 0x1fffff) { - ud->size = 4; - ud->data[0] = 0xf0 | ((uc >> 18) & 0x7); - ud->data[1] = 0x80 | ((uc >> 12) & 0x3f); - ud->data[2] = 0x80 | ((uc >> 6) & 0x3f); - ud->data[3] = 0x80 | (uc & 0x3f); - } else - return (UTF8_ERROR); - ud->width = utf8_width(uc); - return (UTF8_DONE); -} + char s[MB_CUR_MAX]; + int slen; -/* Split a two-byte UTF-8 character. */ -u_int -utf8_split2(u_int uc, u_char *ptr) -{ - if (uc > 0x7f) { - ptr[0] = (uc >> 6) | 0xc0; - ptr[1] = (uc & 0x3f) | 0x80; - return (2); - } - ptr[0] = uc; - return (1); + slen = wctomb(s, wc); + if (slen <= 0 || slen > (int)sizeof ud->data) + return (UTF8_ERROR); + + memcpy(ud->data, s, slen); + ud->size = slen; + + ud->width = utf8_width(wc); + return (UTF8_DONE); } /* From e647eeb0c92cb5cf9134f77c30dce49f27224304 Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 1 Mar 2016 12:02:54 +0000 Subject: [PATCH 041/150] Remove unused variables, from Michal Mazurek. --- cmd-swap-pane.c | 9 ++------- tmux.c | 1 - 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/cmd-swap-pane.c b/cmd-swap-pane.c index aec7753d..13575e0a 100644 --- a/cmd-swap-pane.c +++ b/cmd-swap-pane.c @@ -45,28 +45,23 @@ const struct cmd_entry cmd_swap_pane_entry = { enum cmd_retval cmd_swap_pane_exec(struct cmd *self, struct cmd_q *cmdq) { - struct winlink *src_wl, *dst_wl; struct window *src_w, *dst_w; struct window_pane *tmp_wp, *src_wp, *dst_wp; struct layout_cell *src_lc, *dst_lc; u_int sx, sy, xoff, yoff; - dst_wl = cmdq->state.tflag.wl; - dst_w = dst_wl->window; + dst_w = cmdq->state.tflag.wl->window; dst_wp = cmdq->state.tflag.wp; - src_wl = cmdq->state.sflag.wl; - src_w = src_wl->window; + src_w = cmdq->state.sflag.wl->window; src_wp = cmdq->state.sflag.wp; server_unzoom_window(dst_w); if (args_has(self->args, 'D')) { - src_wl = dst_wl; src_w = dst_w; src_wp = TAILQ_NEXT(dst_wp, entry); if (src_wp == NULL) src_wp = TAILQ_FIRST(&dst_w->panes); } else if (args_has(self->args, 'U')) { - src_wl = dst_wl; src_w = dst_w; src_wp = TAILQ_PREV(dst_wp, window_panes, entry); if (src_wp == NULL) diff --git a/tmux.c b/tmux.c index 68cd4bb7..93503d2d 100644 --- a/tmux.c +++ b/tmux.c @@ -188,7 +188,6 @@ main(int argc, char **argv) const char *s; int opt, flags, keys; - setlocale(LC_CTYPE, "en_US.UTF-8"); setlocale(LC_TIME, ""); From 54ea8f74ae4ae3bff6df3f09ce8a8cdd148e51e5 Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 1 Mar 2016 12:04:43 +0000 Subject: [PATCH 042/150] When a mouse drag is finished, fire a MouseUp key press, instead of doing the drag end in code. From Stephen Coakley. --- mode-key.c | 2 ++ server-client.c | 42 ++++++++++++++++++++++++++++++++++++++++-- window-copy.c | 15 +-------------- 3 files changed, 43 insertions(+), 16 deletions(-) diff --git a/mode-key.c b/mode-key.c index f38ebf66..a9b15bb9 100644 --- a/mode-key.c +++ b/mode-key.c @@ -347,6 +347,7 @@ const struct mode_key_entry mode_key_vi_copy[] = { { KEYC_WHEELUP_PANE, 0, MODEKEYCOPY_SCROLLUP }, { KEYC_WHEELDOWN_PANE, 0, MODEKEYCOPY_SCROLLDOWN }, { KEYC_MOUSEDRAG1_PANE, 0, MODEKEYCOPY_STARTSELECTION }, + { KEYC_MOUSEUP1_PANE, 0, MODEKEYCOPY_COPYSELECTION }, { 0, -1, 0 } }; @@ -495,6 +496,7 @@ const struct mode_key_entry mode_key_emacs_copy[] = { { KEYC_WHEELUP_PANE, 0, MODEKEYCOPY_SCROLLUP }, { KEYC_WHEELDOWN_PANE, 0, MODEKEYCOPY_SCROLLDOWN }, { KEYC_MOUSEDRAG1_PANE, 0, MODEKEYCOPY_STARTSELECTION }, + { KEYC_MOUSEUP1_PANE, 0, MODEKEYCOPY_COPYSELECTION }, { 0, -1, 0 } }; diff --git a/server-client.c b/server-client.c index bb54643a..9111eb82 100644 --- a/server-client.c +++ b/server-client.c @@ -384,8 +384,42 @@ server_client_check_mouse(struct client *c) c->tty.mouse_drag_update = NULL; c->tty.mouse_drag_release = NULL; + /* + * End a mouse drag by passing a MouseUp key corresponding to + * the button that started the drag. + */ + switch (c->tty.mouse_drag_flag) { + case 1: + if (where == PANE) + key = KEYC_MOUSEUP1_PANE; + if (where == STATUS) + key = KEYC_MOUSEUP1_STATUS; + if (where == BORDER) + key = KEYC_MOUSEUP1_BORDER; + break; + case 2: + if (where == PANE) + key = KEYC_MOUSEUP2_PANE; + if (where == STATUS) + key = KEYC_MOUSEUP2_STATUS; + if (where == BORDER) + key = KEYC_MOUSEUP2_BORDER; + break; + case 3: + if (where == PANE) + key = KEYC_MOUSEUP3_PANE; + if (where == STATUS) + key = KEYC_MOUSEUP3_STATUS; + if (where == BORDER) + key = KEYC_MOUSEUP3_BORDER; + break; + default: + key = KEYC_MOUSE; + break; + } c->tty.mouse_drag_flag = 0; - return (KEYC_MOUSE); /* not a key, but still may want to pass */ + + return (key); } /* Convert to a key binding. */ @@ -425,7 +459,11 @@ server_client_check_mouse(struct client *c) } } - c->tty.mouse_drag_flag = 1; + /* + * Begin a drag by setting the flag to a non-zero value that + * corresponds to the mouse button in use. + */ + c->tty.mouse_drag_flag = MOUSE_BUTTONS(b) + 1; break; case WHEEL: if (MOUSE_BUTTONS(b) == MOUSE_WHEEL_UP) { diff --git a/window-copy.c b/window-copy.c index 009ed246..d345f246 100644 --- a/window-copy.c +++ b/window-copy.c @@ -2248,7 +2248,7 @@ window_copy_start_drag(struct client *c, struct mouse_event *m) return; c->tty.mouse_drag_update = window_copy_drag_update; - c->tty.mouse_drag_release = window_copy_drag_release; + c->tty.mouse_drag_release = NULL; /* will fire MouseUp key */ window_copy_update_cursor(wp, x, y); window_copy_start_selection(wp); @@ -2275,16 +2275,3 @@ window_copy_drag_update(__unused struct client *c, struct mouse_event *m) if (window_copy_update_selection(wp, 1)) window_copy_redraw_selection(wp, old_cy); } - -void -window_copy_drag_release(__unused struct client *c, struct mouse_event *m) -{ - struct window_pane *wp; - - wp = cmd_mouse_pane(m, NULL, NULL); - if (wp == NULL || wp->mode != &window_copy_mode) - return; - - window_copy_copy_selection(wp, NULL); - window_pane_reset_mode(wp); -} From 2e4503ad4eec5422e6425480681a261258f7e940 Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 1 Mar 2016 12:05:15 +0000 Subject: [PATCH 043/150] Redraw status on mode entry and exit. --- window.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/window.c b/window.c index 201942a3..1769552f 100644 --- a/window.c +++ b/window.c @@ -1085,6 +1085,8 @@ window_pane_set_mode(struct window_pane *wp, const struct window_mode *mode) if ((s = wp->mode->init(wp)) != NULL) wp->screen = s; wp->flags |= (PANE_REDRAW|PANE_CHANGED); + + server_status_window(wp->window); return (0); } @@ -1099,6 +1101,8 @@ window_pane_reset_mode(struct window_pane *wp) wp->screen = &wp->base; wp->flags |= (PANE_REDRAW|PANE_CHANGED); + + server_status_window(wp->window); } void From f0239a8fe97367ce7ab66d18716c411b424a0e63 Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 1 Mar 2016 12:06:07 +0000 Subject: [PATCH 044/150] Remove some more unused variables, and use RB_FOREACH_SAFE in key_bindings_unref_table. --- cmd-if-shell.c | 3 +-- cmd-resize-pane.c | 1 - cmd.c | 1 - key-bindings.c | 4 ++-- 4 files changed, 3 insertions(+), 6 deletions(-) diff --git a/cmd-if-shell.c b/cmd-if-shell.c index 229289cd..3e2a5251 100644 --- a/cmd-if-shell.c +++ b/cmd-if-shell.c @@ -73,14 +73,13 @@ cmd_if_shell_exec(struct cmd *self, struct cmd_q *cmdq) struct format_tree *ft; const char *cwd; - cwd = wp->cwd; - if (cmdq->client != NULL && cmdq->client->session == NULL) cwd = cmdq->client->cwd; else if (s != NULL) cwd = s->cwd; else cwd = NULL; + ft = format_create(cmdq, 0); format_defaults(ft, NULL, s, wl, wp); shellcmd = format_expand(ft, args->argv[0]); diff --git a/cmd-resize-pane.c b/cmd-resize-pane.c index 2b4f1c17..7ec65f10 100644 --- a/cmd-resize-pane.c +++ b/cmd-resize-pane.c @@ -68,7 +68,6 @@ cmd_resize_pane_exec(struct cmd *self, struct cmd_q *cmdq) return (CMD_RETURN_NORMAL); } - w = wl->window; if (args_has(args, 'Z')) { if (w->flags & WINDOW_ZOOMED) window_unzoom(w); diff --git a/cmd.c b/cmd.c index 005f2a0f..c643a346 100644 --- a/cmd.c +++ b/cmd.c @@ -482,7 +482,6 @@ cmd_prepare_state_flag(char c, const char *target, enum cmd_entry_flag flag, CMD_FIND_SESSION, CMD_FIND_QUIET); if (error == 0) break; - flag = CMD_WINDOW_INDEX; /* FALLTHROUGH */ case CMD_WINDOW: case CMD_WINDOW_CANFAIL: diff --git a/key-bindings.c b/key-bindings.c index a922eb18..0d13385d 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -68,12 +68,12 @@ void key_bindings_unref_table(struct key_table *table) { struct key_binding *bd; + struct key_binding *bd1; if (--table->references != 0) return; - while (!RB_EMPTY(&table->key_bindings)) { - bd = RB_ROOT(&table->key_bindings); + RB_FOREACH_SAFE(bd, key_bindings, &table->key_bindings, bd1) { RB_REMOVE(key_bindings, &table->key_bindings, bd); cmd_list_free(bd->cmdlist); free(bd); From d980d965ddb6165bd801351892fed2497204a279 Mon Sep 17 00:00:00 2001 From: nicm Date: Wed, 2 Mar 2016 15:33:36 +0000 Subject: [PATCH 045/150] Limit x, y and b to 0x7ff for UTF-8 mouse input, suggested by schwarze@. --- input-keys.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/input-keys.c b/input-keys.c index 47786d27..41bd5ab5 100644 --- a/input-keys.c +++ b/input-keys.c @@ -263,6 +263,8 @@ input_key_mouse(struct window_pane *wp, struct mouse_event *m) len = xsnprintf(buf, sizeof buf, "\033[<%u;%u;%u%c", m->sgr_b, x + 1, y + 1, m->sgr_type); } else if (wp->screen->mode & MODE_MOUSE_UTF8) { + if (m->b > 0x7ff - 32 || x > 0x7ff - 33 || y > 0x7ff - 33) + return; len = xsnprintf(buf, sizeof buf, "\033[M"); len += input_split2(m->b + 32, &buf[len]); len += input_split2(x + 33, &buf[len]); From b8a102d26f41e57b94359627a4df8f22af10c6fa Mon Sep 17 00:00:00 2001 From: nicm Date: Wed, 2 Mar 2016 15:36:02 +0000 Subject: [PATCH 046/150] Handle wcwidth() and mbtowc() failures in better style and drop characters where we can't find the width (wcwidth() fails) on input, the same as we drop invalid UTF-8. Suggested by schwarze@. --- input.c | 10 ++++++++-- key-string.c | 6 ++++-- tmux.h | 3 +-- tty-keys.c | 7 ++++++- utf8.c | 43 +++++++++++++++++++++++++++++-------------- 5 files changed, 48 insertions(+), 21 deletions(-) diff --git a/input.c b/input.c index ae205024..18c8eb9a 100644 --- a/input.c +++ b/input.c @@ -1960,8 +1960,14 @@ input_utf8_close(struct input_ctx *ictx) { struct utf8_data *ud = &ictx->utf8data; - if (utf8_append(ud, ictx->ch) != UTF8_DONE) - fatalx("UTF-8 close invalid %#x", ictx->ch); + if (utf8_append(ud, ictx->ch) != UTF8_DONE) { + /* + * An error here could be invalid UTF-8 or it could be a + * nonprintable character for which we can't get the + * width. Drop it. + */ + return (0); + } log_debug("%s %hhu '%*s' (width %hhu)", __func__, ud->size, (int)ud->size, ud->data, ud->width); diff --git a/key-string.c b/key-string.c index dc211696..c56681f1 100644 --- a/key-string.c +++ b/key-string.c @@ -149,6 +149,7 @@ key_string_lookup_string(const char *string) struct utf8_data ud; u_int i; enum utf8_state more; + wchar_t wc; /* Is this no key? */ if (strcasecmp(string, "None") == 0) @@ -185,8 +186,9 @@ key_string_lookup_string(const char *string) more = utf8_append(&ud, (u_char)string[i]); if (more != UTF8_DONE) return (KEYC_UNKNOWN); - key = utf8_combine(&ud); - return (key | modifiers); + if (utf8_combine(&ud, &wc) != UTF8_DONE) + return (KEYC_UNKNOWN); + return (wc | modifiers); } /* Otherwise look the key up in the table. */ diff --git a/tmux.h b/tmux.h index b00c7469..ac94d780 100644 --- a/tmux.h +++ b/tmux.h @@ -2316,8 +2316,7 @@ void utf8_set(struct utf8_data *, u_char); void utf8_copy(struct utf8_data *, const struct utf8_data *); enum utf8_state utf8_open(struct utf8_data *, u_char); enum utf8_state utf8_append(struct utf8_data *, u_char); -u_int utf8_width(wchar_t); -wchar_t utf8_combine(const struct utf8_data *); +enum utf8_state utf8_combine(const struct utf8_data *, wchar_t *); enum utf8_state utf8_split(wchar_t, struct utf8_data *); int utf8_strvis(char *, const char *, size_t, int); char *utf8_sanitize(const char *); diff --git a/tty-keys.c b/tty-keys.c index 2b998778..105f99f7 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -477,6 +477,7 @@ tty_keys_next(struct tty *tty) struct utf8_data ud; enum utf8_state more; u_int i; + wchar_t wc; /* Get key buffer. */ buf = EVBUFFER_DATA(tty->event->input); @@ -552,7 +553,11 @@ first_key: more = utf8_append(&ud, (u_char)buf[i]); if (more != UTF8_DONE) goto discard_key; - key = utf8_combine(&ud); + + if (utf8_combine(&ud, &wc) != UTF8_DONE) + goto discard_key; + key = wc; + log_debug("UTF-8 key %.*s %#llx", (int)size, buf, key); goto complete_key; } diff --git a/utf8.c b/utf8.c index be0915ba..114f2b90 100644 --- a/utf8.c +++ b/utf8.c @@ -25,6 +25,8 @@ #include "tmux.h" +static int utf8_width(wchar_t); + /* Set a single character. */ void utf8_set(struct utf8_data *ud, u_char ch) @@ -80,6 +82,9 @@ utf8_open(struct utf8_data *ud, u_char ch) enum utf8_state utf8_append(struct utf8_data *ud, u_char ch) { + wchar_t wc; + int width; + if (ud->have >= ud->size) fatalx("UTF-8 character overflow"); if (ud->size > sizeof ud->data) @@ -94,39 +99,49 @@ utf8_append(struct utf8_data *ud, u_char ch) if (ud->width == 0xff) return (UTF8_ERROR); - ud->width = utf8_width(utf8_combine(ud)); + + if (utf8_combine(ud, &wc) != UTF8_DONE) + return (UTF8_ERROR); + if ((width = utf8_width(wc)) < 0) + return (UTF8_ERROR); + ud->width = width; + return (UTF8_DONE); } /* Get width of Unicode character. */ -u_int +static int utf8_width(wchar_t wc) { - int width; + int width; width = wcwidth(wc); - if (width < 0) - return (0); + if (width < 0 || width > 0xff) + return (-1); return (width); } /* Combine UTF-8 into Unicode. */ -wchar_t -utf8_combine(const struct utf8_data *ud) +enum utf8_state +utf8_combine(const struct utf8_data *ud, wchar_t *wc) { - wchar_t wc; - - if (mbtowc(&wc, ud->data, ud->size) <= 0) - return (0xfffd); - return (wc); + switch (mbtowc(wc, ud->data, ud->size)) { + case -1: + mbtowc(NULL, NULL, MB_CUR_MAX); + return (UTF8_ERROR); + case 0: + return (UTF8_ERROR); + default: + return (UTF8_DONE); + } } /* Split Unicode into UTF-8. */ enum utf8_state utf8_split(wchar_t wc, struct utf8_data *ud) { - char s[MB_CUR_MAX]; - int slen; + char s[MB_LEN_MAX]; + int slen; slen = wctomb(s, wc); if (slen <= 0 || slen > (int)sizeof ud->data) From 9e2fbb31ec34c38d7e3acd42895f11b1a83bcd19 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 2 Mar 2016 18:19:13 +0000 Subject: [PATCH 047/150] +wchar.h --- utf8.c | 1 + 1 file changed, 1 insertion(+) diff --git a/utf8.c b/utf8.c index 6d80266b..c0407576 100644 --- a/utf8.c +++ b/utf8.c @@ -20,6 +20,7 @@ #include #include +#include #include "tmux.h" From bcb41a09b3d3f0c61d2e98c0b91fcea52f745efb Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 3 Mar 2016 12:58:15 +0000 Subject: [PATCH 048/150] RGB colours shouldn't be mixed up with aixterm colours, return before that happens when working out if they are supported. --- tty.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tty.c b/tty.c index c6fc2213..2dff5700 100644 --- a/tty.c +++ b/tty.c @@ -1569,6 +1569,8 @@ tty_check_fg(struct tty *tty, struct grid_cell *gc) gc->flags |= GRID_FLAG_FG256; gc->fg = colour_find_rgb(rgb->r, rgb->g, rgb->b); } + else + return; } colours = tty_term_number(tty->term, TTYC_COLORS); @@ -1612,6 +1614,8 @@ tty_check_bg(struct tty *tty, struct grid_cell *gc) gc->flags |= GRID_FLAG_BG256; gc->bg = colour_find_rgb(rgb->r, rgb->g, rgb->b); } + else + return; } colours = tty_term_number(tty->term, TTYC_COLORS); From fa81d838dacb2dd05d4556db3cbcb3760b7d2c47 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 3 Mar 2016 14:14:46 +0000 Subject: [PATCH 049/150] Accept clients as sessions in cmd_find_get_session. --- cmd-find.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/cmd-find.c b/cmd-find.c index 7ffc5f15..22511201 100644 --- a/cmd-find.c +++ b/cmd-find.c @@ -401,6 +401,7 @@ int cmd_find_get_session(struct cmd_find_state *fs, const char *session) { struct session *s, *s_loop; + struct client *c; log_debug("%s: %s", __func__, session); @@ -417,6 +418,13 @@ cmd_find_get_session(struct cmd_find_state *fs, const char *session) if (fs->s != NULL) return (0); + /* Look for as a client. */ + c = cmd_find_client(NULL, session, 1); + if (c != NULL && c->session != NULL) { + fs->s = c->session; + return (0); + } + /* Stop now if exact only. */ if (fs->flags & CMD_FIND_EXACT_SESSION) return (-1); @@ -1209,7 +1217,7 @@ cmd_find_client(struct cmd_q *cmdq, const char *target, int quiet) const char *path; /* A NULL argument means the current client. */ - if (target == NULL) { + if (cmdq != NULL && target == NULL) { c = cmd_find_current_client(cmdq); if (c == NULL && !quiet) cmdq_error(cmdq, "no current client"); From df0983af39922f2ee747a244c1c718ba7ca28910 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 3 Mar 2016 14:15:22 +0000 Subject: [PATCH 050/150] show-* and set-* need to handle a missing target. --- cmd-set-environment.c | 15 ++++++++++++--- cmd-set-option.c | 38 +++++++++++++++++++------------------- cmd-show-environment.c | 21 +++++++++++++++++++-- cmd-show-options.c | 31 +++++++++++++++++++++++-------- 4 files changed, 73 insertions(+), 32 deletions(-) diff --git a/cmd-set-environment.c b/cmd-set-environment.c index 55bdaa9a..ba295ea6 100644 --- a/cmd-set-environment.c +++ b/cmd-set-environment.c @@ -47,7 +47,7 @@ cmd_set_environment_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct environ *env; - const char *name, *value; + const char *name, *value, *target; name = args->argv[0]; if (*name == '\0') { @@ -64,10 +64,19 @@ cmd_set_environment_exec(struct cmd *self, struct cmd_q *cmdq) else value = args->argv[1]; - if (args_has(self->args, 'g') || cmdq->state.tflag.s == NULL) + if (args_has(self->args, 'g')) env = global_environ; - else + else { + if (cmdq->state.tflag.s == NULL) { + target = args_get(args, 't'); + if (target != NULL) + cmdq_error(cmdq, "no such session: %s", target); + else + cmdq_error(cmdq, "no current session"); + return (CMD_RETURN_ERROR); + } env = cmdq->state.tflag.s->environ; + } if (args_has(self->args, 'u')) { if (value != NULL) { diff --git a/cmd-set-option.c b/cmd-set-option.c index 7fc81286..b1771436 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -100,7 +100,7 @@ cmd_set_option_exec(struct cmd *self, struct cmd_q *cmdq) struct client *c; const struct options_table_entry *oe; struct options *oo; - const char *optstr, *valstr; + const char *optstr, *valstr, *target; /* Get the option name and value. */ optstr = args->argv[0]; @@ -140,29 +140,29 @@ cmd_set_option_exec(struct cmd *self, struct cmd_q *cmdq) else if (oe->scope == OPTIONS_TABLE_WINDOW) { if (args_has(self->args, 'g')) oo = global_w_options; - else { - if (wl == NULL) { - cmdq_error(cmdq, - "couldn't set '%s'%s", optstr, - (!args_has(args, 't') && !args_has(args, - 'g')) ? " need target window or -g" : ""); - return (CMD_RETURN_ERROR); - } + else if (wl == NULL) { + target = args_get(args, 't'); + if (target != NULL) { + cmdq_error(cmdq, "no such window: %s", + target); + } else + cmdq_error(cmdq, "no current window"); + return (CMD_RETURN_ERROR); + } else oo = wl->window->options; - } } else if (oe->scope == OPTIONS_TABLE_SESSION) { if (args_has(self->args, 'g')) oo = global_s_options; - else { - if (s == NULL) { - cmdq_error(cmdq, - "couldn't set '%s'%s", optstr, - (!args_has(args, 't') && !args_has(args, - 'g')) ? " need target session or -g" : ""); - return (CMD_RETURN_ERROR); - } + else if (s == NULL) { + target = args_get(args, 't'); + if (target != NULL) { + cmdq_error(cmdq, "no such session: %s", + target); + } else + cmdq_error(cmdq, "no current session"); + return (CMD_RETURN_ERROR); + } else oo = s->options; - } } else { cmdq_error(cmdq, "unknown table"); return (CMD_RETURN_ERROR); diff --git a/cmd-show-environment.c b/cmd-show-environment.c index 83661c44..29e89274 100644 --- a/cmd-show-environment.c +++ b/cmd-show-environment.c @@ -93,11 +93,28 @@ cmd_show_environment_exec(struct cmd *self, struct cmd_q *cmdq) struct args *args = self->args; struct environ *env; struct environ_entry *envent; + const char *target; - if (args_has(self->args, 'g') || cmdq->state.tflag.s == NULL) + if ((target = args_get(args, 't')) != NULL) { + if (cmdq->state.tflag.s == NULL) { + cmdq_error(cmdq, "no such session: %s", target); + return (CMD_RETURN_ERROR); + } + } + + if (args_has(self->args, 'g')) env = global_environ; - else + else { + if (cmdq->state.tflag.s == NULL) { + target = args_get(args, 't'); + if (target != NULL) + cmdq_error(cmdq, "no such session: %s", target); + else + cmdq_error(cmdq, "no current session"); + return (CMD_RETURN_ERROR); + } env = cmdq->state.tflag.s->environ; + } if (args->argc != 0) { envent = environ_find(env, args->argv[0]); diff --git a/cmd-show-options.c b/cmd-show-options.c index fec2f1de..322f532c 100644 --- a/cmd-show-options.c +++ b/cmd-show-options.c @@ -63,12 +63,13 @@ const struct cmd_entry cmd_show_window_options_entry = { enum cmd_retval cmd_show_options_exec(struct cmd *self, struct cmd_q *cmdq) { - struct args *args = self->args; - struct session *s = cmdq->state.tflag.s; - struct winlink *wl = cmdq->state.tflag.wl; - struct options *oo; - enum options_table_scope scope; - int quiet; + struct args *args = self->args; + struct session *s = cmdq->state.tflag.s; + struct winlink *wl = cmdq->state.tflag.wl; + struct options *oo; + enum options_table_scope scope; + int quiet; + const char *target; if (args_has(self->args, 's')) { oo = global_options; @@ -78,13 +79,27 @@ cmd_show_options_exec(struct cmd *self, struct cmd_q *cmdq) scope = OPTIONS_TABLE_WINDOW; if (args_has(self->args, 'g')) oo = global_w_options; - else + else if (wl == NULL) { + target = args_get(args, 't'); + if (target != NULL) { + cmdq_error(cmdq, "no such window: %s", target); + } else + cmdq_error(cmdq, "no current window"); + return (CMD_RETURN_ERROR); + } else oo = wl->window->options; } else { scope = OPTIONS_TABLE_SESSION; if (args_has(self->args, 'g')) oo = global_s_options; - else + else if (s == NULL) { + target = args_get(args, 't'); + if (target != NULL) { + cmdq_error(cmdq, "no such session: %s", target); + } else + cmdq_error(cmdq, "no current session"); + return (CMD_RETURN_ERROR); + } else oo = s->options; } From 1f0b317088aaeb230d69f13f43ed63b7406c6fd1 Mon Sep 17 00:00:00 2001 From: nicm Date: Sat, 5 Mar 2016 07:44:31 +0000 Subject: [PATCH 051/150] Although we always have en_US.UTF-8 on OpenBSD, some platforms do not, so fall back to setlocale(LC_CTYPE, ""). tmux requires a UTF-8 locale, so check with wcwidth() on a UTF-8 character after setlocale(). --- tmux.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tmux.c b/tmux.c index 93503d2d..d221c78e 100644 --- a/tmux.c +++ b/tmux.c @@ -188,9 +188,12 @@ main(int argc, char **argv) const char *s; int opt, flags, keys; - setlocale(LC_CTYPE, "en_US.UTF-8"); - setlocale(LC_TIME, ""); + if (setlocale(LC_CTYPE, "en_US.UTF-8") == NULL) + setlocale(LC_CTYPE, ""); + if (wcwidth(0xfffd) != 1) + errx(1, "no UTF-8 locale; please set LC_CTYPE"); + setlocale(LC_TIME, ""); tzset(); if (**argv == '-') From c38e0a4bbc722865f934db1282ca6f086874f530 Mon Sep 17 00:00:00 2001 From: nicm Date: Sat, 5 Mar 2016 07:47:52 +0000 Subject: [PATCH 052/150] Do not use c->cwd or s->cwd if it is NULL, found by Ben Boeckel. --- cmd-load-buffer.c | 4 ++-- cmd-new-session.c | 2 +- cmd-save-buffer.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cmd-load-buffer.c b/cmd-load-buffer.c index 6fd2a767..de76b855 100644 --- a/cmd-load-buffer.c +++ b/cmd-load-buffer.c @@ -73,9 +73,9 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_q *cmdq) return (CMD_RETURN_WAIT); } - if (c != NULL && c->session == NULL) + if (c != NULL && c->session == NULL && c->cwd != NULL) cwd = c->cwd; - else if ((s = c->session) != NULL) + else if ((s = c->session) != NULL && s->cwd != NULL) cwd = s->cwd; else cwd = "."; diff --git a/cmd-new-session.c b/cmd-new-session.c index 291107bc..357ffed1 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -142,7 +142,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) format_defaults(ft, c, NULL, NULL, NULL); to_free = cwd = format_expand(ft, args_get(args, 'c')); format_free(ft); - } else if (c != NULL && c->session == NULL) + } else if (c != NULL && c->session == NULL && c->cwd != NULL) cwd = c->cwd; else cwd = "."; diff --git a/cmd-save-buffer.c b/cmd-save-buffer.c index 591390b5..3aaf8159 100644 --- a/cmd-save-buffer.c +++ b/cmd-save-buffer.c @@ -98,9 +98,9 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_q *cmdq) goto do_print; } - if (c != NULL && c->session == NULL) + if (c != NULL && c->session == NULL && c->cwd != NULL) cwd = c->cwd; - else if ((s = c->session) != NULL) + else if ((s = c->session) != NULL && s->cwd != NULL) cwd = s->cwd; else cwd = "."; From 0d6de44a37755f0e5046c04e19e4506a6d59e750 Mon Sep 17 00:00:00 2001 From: nicm Date: Sat, 5 Mar 2016 16:08:38 +0000 Subject: [PATCH 053/150] If setlocale("en_US.UTF-8") succeeds, then don't do the check for UTF-8 locale since if it isn't UTF-8 the system is broken anyway. If it fails, try "" and check for UTF-8 with nl_langinfo(CODESET) rather than wcwidth(). Based on a diff from schwarze@, nl_langinfo also suggested by stsp@. --- tmux.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tmux.c b/tmux.c index d221c78e..f8654e2b 100644 --- a/tmux.c +++ b/tmux.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -188,10 +189,14 @@ main(int argc, char **argv) const char *s; int opt, flags, keys; - if (setlocale(LC_CTYPE, "en_US.UTF-8") == NULL) - setlocale(LC_CTYPE, ""); - if (wcwidth(0xfffd) != 1) - errx(1, "no UTF-8 locale; please set LC_CTYPE"); + if (setlocale(LC_CTYPE, "en_US.UTF-8") == NULL) { + if (setlocale(LC_CTYPE, "") == NULL) + errx(1, "invalid LC_ALL, LC_CTYPE or LANG"); + s = nl_langinfo(CODESET); + if (strcasecmp(s, "UTF-8") != 0 && + strcasecmp(s, "UTF8") != 0) + errx(1, "need UTF-8 locale (LC_CTYPE) but have %s", s); + } setlocale(LC_TIME, ""); tzset(); From 0d4aaa6defafee65659b4991050d2633d89c2163 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Fri, 11 Mar 2016 13:28:49 -0500 Subject: [PATCH 054/150] Fix compile warning --- tmate-ssh-client.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tmate-ssh-client.c b/tmate-ssh-client.c index cd3a71b0..898344f1 100644 --- a/tmate-ssh-client.c +++ b/tmate-ssh-client.c @@ -173,9 +173,11 @@ static void init_conn_fd(struct tmate_ssh_client *client) if (ssh_get_fd(client->session) < 0) return; + { int flag = 1; setsockopt(ssh_get_fd(client->session), IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag)); + } event_set(&client->ev_ssh, ssh_get_fd(client->session), EV_READ | EV_PERSIST, __on_ssh_client_event, client); From 9742aeaf9b44028a54c8e09aa63622c4ec5b7cfa Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Fri, 11 Mar 2016 14:11:28 -0500 Subject: [PATCH 055/150] Send a ready packet when initialization is done --- server.c | 4 ++++ tmate-encoder.c | 6 ++++++ tmate-protocol.h | 2 ++ tmate.h | 3 ++- 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/server.c b/server.c index 603dbb46..7461d533 100644 --- a/server.c +++ b/server.c @@ -205,6 +205,10 @@ server_start(struct event_base *base, int lockfd, char *lockfile) status_prompt_load_history(); +#ifdef TMATE + tmate_write_ready(); +#endif + server_add_accept(0); proc_loop(server_proc, server_loop); diff --git a/tmate-encoder.c b/tmate-encoder.c index ff6924da..b6a5384c 100644 --- a/tmate-encoder.c +++ b/tmate-encoder.c @@ -12,6 +12,12 @@ void tmate_write_header(void) pack(string, VERSION); } +void tmate_write_ready(void) +{ + pack(array, 1); + pack(int, TMATE_OUT_READY); +} + void tmate_sync_layout(void) { struct session *s; diff --git a/tmate-protocol.h b/tmate-protocol.h index 45beaec6..3f3a3614 100644 --- a/tmate-protocol.h +++ b/tmate-protocol.h @@ -49,6 +49,7 @@ enum tmate_daemon_out_msg_types { TMATE_OUT_SYNC_COPY_MODE, TMATE_OUT_WRITE_COPY_MODE, TMATE_OUT_FIN, + TMATE_OUT_READY, }; /* @@ -66,6 +67,7 @@ enum tmate_daemon_out_msg_types { // Any of the array can be [] [TMATE_OUT_WRITE_COPY_MODE, int: pane_id, string: str] [TMATE_OUT_FIN] +[TMATE_OUT_READY] */ enum tmate_daemon_in_msg_types { diff --git a/tmate.h b/tmate.h index 98b109c4..11236360 100644 --- a/tmate.h +++ b/tmate.h @@ -73,9 +73,10 @@ extern void unpack_array(struct tmate_unpacker *uk, struct tmate_unpacker *neste /* tmate-encoder.c */ -#define TMATE_PROTOCOL_VERSION 5 +#define TMATE_PROTOCOL_VERSION 6 extern void tmate_write_header(void); +extern void tmate_write_ready(void); extern void tmate_sync_layout(void); extern void tmate_pty_data(struct window_pane *wp, const char *buf, size_t len); extern int tmate_should_replicate_cmd(const struct cmd_entry *cmd); From cc20e826e0b5552d16cb8d463b60a2691783cd3b Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Fri, 11 Mar 2016 14:11:48 -0500 Subject: [PATCH 056/150] Add webhook options --- options-table.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/options-table.c b/options-table.c index ad061a20..eb87d8a9 100644 --- a/options-table.c +++ b/options-table.c @@ -942,6 +942,17 @@ const struct options_table_entry options_table[] = { .default_num = 30000 }, + { .name = "tmate-webhook-userdata", + .type = OPTIONS_TABLE_STRING, + .scope = OPTIONS_TABLE_SERVER, + .default_str = "" + }, + + { .name = "tmate-webhook-url", + .type = OPTIONS_TABLE_STRING, + .scope = OPTIONS_TABLE_SERVER, + .default_str = "" + }, #endif { .name = NULL } From 3dfc79fb092273b65fd8a24174007d13804d3641 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 17 Mar 2016 15:11:40 +0000 Subject: [PATCH 057/150] Tweak a comment. --- Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 8678a38e..718cfc77 100644 --- a/Makefile.am +++ b/Makefile.am @@ -54,7 +54,7 @@ if IS_SUNCC CFLAGS += -erroff=E_EMPTY_DECLARATION endif -# Set _LINUX_SOURCE_COMPAT for AIX for mallocing 0 bytes +# Set _LINUX_SOURCE_COMPAT for AIX for malloc(0). if IS_AIX DEFS += -D_LINUX_SOURCE_COMPAT=1 endif From fa97b0a95b804fec86b03d35d16c270d2866ebd6 Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 18 Mar 2016 07:28:27 +0000 Subject: [PATCH 058/150] Instead of reusing MouseUp at the finish of a drag, add a new key MouseDragEnd. It can be useful to bind them separately in copy mode. --- key-string.c | 3 +++ mode-key.c | 4 ++-- server-client.c | 22 +++++++++++----------- tmux.1 | 8 ++++---- tmux.h | 3 +++ 5 files changed, 23 insertions(+), 17 deletions(-) diff --git a/key-string.c b/key-string.c index c56681f1..119035a0 100644 --- a/key-string.c +++ b/key-string.c @@ -93,6 +93,9 @@ const struct { KEYC_MOUSE_STRING(MOUSEDRAG1, MouseDrag1), KEYC_MOUSE_STRING(MOUSEDRAG2, MouseDrag2), KEYC_MOUSE_STRING(MOUSEDRAG3, MouseDrag3), + KEYC_MOUSE_STRING(MOUSEDRAGEND1, MouseDragEnd1), + KEYC_MOUSE_STRING(MOUSEDRAGEND2, MouseDragEnd2), + KEYC_MOUSE_STRING(MOUSEDRAGEND3, MouseDragEnd3), KEYC_MOUSE_STRING(WHEELUP, WheelUp), KEYC_MOUSE_STRING(WHEELDOWN, WheelDown), }; diff --git a/mode-key.c b/mode-key.c index a9b15bb9..aed161bb 100644 --- a/mode-key.c +++ b/mode-key.c @@ -347,7 +347,7 @@ const struct mode_key_entry mode_key_vi_copy[] = { { KEYC_WHEELUP_PANE, 0, MODEKEYCOPY_SCROLLUP }, { KEYC_WHEELDOWN_PANE, 0, MODEKEYCOPY_SCROLLDOWN }, { KEYC_MOUSEDRAG1_PANE, 0, MODEKEYCOPY_STARTSELECTION }, - { KEYC_MOUSEUP1_PANE, 0, MODEKEYCOPY_COPYSELECTION }, + { KEYC_MOUSEDRAGEND1_PANE, 0, MODEKEYCOPY_COPYSELECTION }, { 0, -1, 0 } }; @@ -496,7 +496,7 @@ const struct mode_key_entry mode_key_emacs_copy[] = { { KEYC_WHEELUP_PANE, 0, MODEKEYCOPY_SCROLLUP }, { KEYC_WHEELDOWN_PANE, 0, MODEKEYCOPY_SCROLLDOWN }, { KEYC_MOUSEDRAG1_PANE, 0, MODEKEYCOPY_STARTSELECTION }, - { KEYC_MOUSEUP1_PANE, 0, MODEKEYCOPY_COPYSELECTION }, + { KEYC_MOUSEDRAGEND1_PANE, 0, MODEKEYCOPY_COPYSELECTION }, { 0, -1, 0 } }; diff --git a/server-client.c b/server-client.c index 9111eb82..6166eac4 100644 --- a/server-client.c +++ b/server-client.c @@ -385,33 +385,33 @@ server_client_check_mouse(struct client *c) c->tty.mouse_drag_release = NULL; /* - * End a mouse drag by passing a MouseUp key corresponding to - * the button that started the drag. + * End a mouse drag by passing a MouseDragEnd key corresponding + * to the button that started the drag. */ switch (c->tty.mouse_drag_flag) { case 1: if (where == PANE) - key = KEYC_MOUSEUP1_PANE; + key = KEYC_MOUSEDRAGEND1_PANE; if (where == STATUS) - key = KEYC_MOUSEUP1_STATUS; + key = KEYC_MOUSEDRAGEND1_STATUS; if (where == BORDER) - key = KEYC_MOUSEUP1_BORDER; + key = KEYC_MOUSEDRAGEND1_BORDER; break; case 2: if (where == PANE) - key = KEYC_MOUSEUP2_PANE; + key = KEYC_MOUSEDRAGEND2_PANE; if (where == STATUS) - key = KEYC_MOUSEUP2_STATUS; + key = KEYC_MOUSEDRAGEND2_STATUS; if (where == BORDER) - key = KEYC_MOUSEUP2_BORDER; + key = KEYC_MOUSEDRAGEND2_BORDER; break; case 3: if (where == PANE) - key = KEYC_MOUSEUP3_PANE; + key = KEYC_MOUSEDRAGEND3_PANE; if (where == STATUS) - key = KEYC_MOUSEUP3_STATUS; + key = KEYC_MOUSEDRAGEND3_STATUS; if (where == BORDER) - key = KEYC_MOUSEUP3_BORDER; + key = KEYC_MOUSEDRAGEND3_BORDER; break; default: key = KEYC_MOUSE; diff --git a/tmux.1 b/tmux.1 index 448673f1..a304e76b 100644 --- a/tmux.1 +++ b/tmux.1 @@ -3294,10 +3294,10 @@ for a pane border or for the status line). The following mouse events are available: .Bl -column "MouseDown1" "MouseDrag1" "WheelDown" -offset indent -.It Li "MouseDown1" Ta "MouseUp1" Ta "MouseDrag1" -.It Li "MouseDown2" Ta "MouseUp2" Ta "MouseDrag2" -.It Li "MouseDown3" Ta "MouseUp3" Ta "MouseDrag3" -.It Li "WheelUp" Ta "WheelDown" Ta "" +.It Li "MouseDown1" Ta "MouseUp1" Ta "MouseDrag1" Ta "MouseDragEnd1" +.It Li "MouseDown2" Ta "MouseUp2" Ta "MouseDrag2" Ta "MouseDragEnd2" +.It Li "MouseDown3" Ta "MouseUp3" Ta "MouseDrag3" Ta "MouseDragEnd3" +.It Li "WheelUp" Ta "WheelDown" Ta "" Ta "" .El .Pp Each should be suffixed with a location, for example diff --git a/tmux.h b/tmux.h index ac94d780..b2445fce 100644 --- a/tmux.h +++ b/tmux.h @@ -135,6 +135,9 @@ enum { KEYC_MOUSE_KEY(MOUSEDRAG1), KEYC_MOUSE_KEY(MOUSEDRAG2), KEYC_MOUSE_KEY(MOUSEDRAG3), + KEYC_MOUSE_KEY(MOUSEDRAGEND1), + KEYC_MOUSE_KEY(MOUSEDRAGEND2), + KEYC_MOUSE_KEY(MOUSEDRAGEND3), KEYC_MOUSE_KEY(WHEELUP), KEYC_MOUSE_KEY(WHEELDOWN), From 312a7a1e629431a71930fc6523f0feb6c595afda Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 18 Mar 2016 14:27:24 +0000 Subject: [PATCH 059/150] Make scrolling behaviour more sensible and maintain cursor position, as if the same had been done line-by-line. From Michal Mazurek. --- window-copy.c | 85 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 69 insertions(+), 16 deletions(-) diff --git a/window-copy.c b/window-copy.c index d345f246..5c907c3d 100644 --- a/window-copy.c +++ b/window-copy.c @@ -26,6 +26,7 @@ struct screen *window_copy_init(struct window_pane *); void window_copy_free(struct window_pane *); +void window_copy_pagedown(struct window_pane *); void window_copy_resize(struct window_pane *, u_int, u_int); void window_copy_key(struct window_pane *, struct client *, struct session *, key_code, struct mouse_event *); @@ -324,15 +325,80 @@ window_copy_pageup(struct window_pane *wp) { struct window_copy_mode_data *data = wp->modedata; struct screen *s = &data->screen; - u_int n; + u_int n, ox, oy; + + oy = screen_hsize(data->backing) + data->cy - data->oy; + ox = window_copy_find_length(wp, oy); + + if (s->sel.lineflag == LINE_SEL_LEFT_RIGHT && oy == data->sely) + window_copy_other_end(wp); + + if (data->cx != ox) { + data->lastcx = data->cx; + data->lastsx = ox; + } + data->cx = data->lastcx; n = 1; if (screen_size_y(s) > 2) n = screen_size_y(s) - 2; + if (data->oy + n > screen_hsize(data->backing)) data->oy = screen_hsize(data->backing); else data->oy += n; + + if (!data->screen.sel.flag || !data->rectflag) { + u_int py = screen_hsize(data->backing) + data->cy - data->oy; + u_int px = window_copy_find_length(wp, py); + if ((data->cx >= data->lastsx && data->cx != px) || data->cx > px) + window_copy_cursor_end_of_line(wp); + } + + window_copy_update_selection(wp, 1); + window_copy_redraw_screen(wp); +} + +void +window_copy_pagedown(struct window_pane *wp) +{ + struct window_copy_mode_data *data = wp->modedata; + struct screen *s = &data->screen; + u_int n, ox, oy; + + oy = screen_hsize(data->backing) + data->cy - data->oy; + ox = window_copy_find_length(wp, oy); + + if (s->sel.lineflag == LINE_SEL_RIGHT_LEFT && oy == data->sely) + window_copy_other_end(wp); + + if (data->cx != ox) { + data->lastcx = data->cx; + data->lastsx = ox; + } + data->cx = data->lastcx; + + n = 1; + if (screen_size_y(s) > 2) + n = screen_size_y(s) - 2; + + if (data->oy < n) + data->oy = 0; + else + data->oy -= n; + + if (!data->screen.sel.flag || !data->rectflag) { + u_int py = screen_hsize(data->backing) + data->cy - data->oy; + u_int px = window_copy_find_length(wp, py); + if ((data->cx >= data->lastsx && data->cx != px) || data->cx > px) + window_copy_cursor_end_of_line(wp); + } + + if (data->scroll_exit && data->oy == 0) { + window_pane_reset_mode(wp); + return; + } + window_copy_update_selection(wp, 1); window_copy_redraw_screen(wp); } @@ -479,21 +545,8 @@ window_copy_key(struct window_pane *wp, struct client *c, struct session *sess, window_copy_pageup(wp); break; case MODEKEYCOPY_NEXTPAGE: - n = 1; - if (screen_size_y(s) > 2) - n = screen_size_y(s) - 2; - for (; np != 0; np--) { - if (data->oy < n) - data->oy = 0; - else - data->oy -= n; - } - if (data->scroll_exit && data->oy == 0) { - window_pane_reset_mode(wp); - return; - } - window_copy_update_selection(wp, 1); - window_copy_redraw_screen(wp); + for (; np != 0; np--) + window_copy_pagedown(wp); break; case MODEKEYCOPY_HALFPAGEUP: n = screen_size_y(s) / 2; From b429a00cce4c150cf8050545f903ecb304691ab9 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sun, 20 Mar 2016 08:14:14 +0000 Subject: [PATCH 060/150] Add to TODO. --- TODO | 1 + 1 file changed, 1 insertion(+) diff --git a/TODO b/TODO index 4a284220..e0e3de6d 100644 --- a/TODO +++ b/TODO @@ -75,6 +75,7 @@ * searching in copy mode should unwrap lines, so if you seach for "foobar" then it should be found even if it is now "foo\nbar" (if the WRAP flag is set on the line) + * {} to go to next/previous blank line in copy mode - layout stuff * way to tag a layout as a number/name From 5658b628b9bf1c1e0bd5856736332ce8b9c51517 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Sat, 26 Mar 2016 20:17:17 +0000 Subject: [PATCH 061/150] Look for utempter_add_record to be sure we have the new utempter API, the old utempter API was also using utempter.h. --- configure.ac | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index 82e8a452..8ce20632 100644 --- a/configure.ac +++ b/configure.ac @@ -167,10 +167,17 @@ if test "x$found_curses" = xno; then fi # Look for utempter. -AC_CHECK_HEADER(utempter.h, have_utempter=yes, have_utempter=no) -if test "x$have_utempter" = xyes; then - AC_DEFINE(HAVE_UTEMPTER) - LIBS="$LIBS -lutempter" +AC_CHECK_HEADER(utempter.h, found_utempter=yes, found_utempter=no) +if test "x$found_utempter" = xyes; then + AC_SEARCH_LIBS( + utempter_add_record, + utempter, + found_utempter=yes, + found_utempter=no + ) + if test "x$found_utempter" = xyes; then + AC_DEFINE(HAVE_UTEMPTER) + fi fi # Check for b64_ntop. From cdfb6d7ef1122dbb64621c90a4cba88ab5517e53 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sat, 26 Mar 2016 19:00:16 -0400 Subject: [PATCH 062/150] Reconnect wip --- tmate-decoder.c | 14 +++++- tmate-encoder.c | 123 +++++++++++++++++++++++++++++++++++++++++++++ tmate-msgpack.c | 17 ++++++- tmate-protocol.h | 4 ++ tmate-session.c | 46 ++++++++++++++++- tmate-ssh-client.c | 117 ++++++++++++++++++------------------------ tmate.h | 12 ++++- 7 files changed, 259 insertions(+), 74 deletions(-) diff --git a/tmate-decoder.c b/tmate-decoder.c index bc5141f5..9669c4c0 100644 --- a/tmate-decoder.c +++ b/tmate-decoder.c @@ -114,19 +114,29 @@ out: free(cmd_str); } -static void handle_set_env(__unused struct tmate_session *session, +static void maybe_save_reconnection_data(struct tmate_session *session, + const char *name, const char *value) +{ + if (!strcmp(name, "tmate_reconnection_data")) { + free(session->reconnection_data); + session->reconnection_data = xstrdup(value); + } +} + +static void handle_set_env(struct tmate_session *session, struct tmate_unpacker *uk) { char *name = unpack_string(uk); char *value = unpack_string(uk); tmate_set_env(name, value); + maybe_save_reconnection_data(session, name, value); free(name); free(value); } -static void handle_ready(__unused struct tmate_session *session, +static void handle_ready(struct tmate_session *session, __unused struct tmate_unpacker *uk) { session->tmate_env_ready = 1; diff --git a/tmate-encoder.c b/tmate-encoder.c index b6a5384c..4155237b 100644 --- a/tmate-encoder.c +++ b/tmate-encoder.c @@ -236,3 +236,126 @@ void tmate_write_fin(void) pack(array, 1); pack(int, TMATE_OUT_FIN); } + +static void do_snapshot(unsigned int max_history_lines, + struct window_pane *pane) +{ + struct screen *screen; + struct grid *grid; + struct grid_line *line; + struct grid_cell gc; + unsigned int line_i, i; + unsigned int max_lines; + size_t str_len; + + screen = &pane->base; + grid = screen->grid; + + pack(array, 4); + pack(int, pane->id); + + pack(array, 2); + pack(int, screen->cx); + pack(int, screen->cy); + + pack(unsigned_int, screen->mode); + + max_lines = max_history_lines + grid->sy; + +#define grid_num_lines(grid) (grid->hsize + grid->sy) + + if (grid_num_lines(grid) > max_lines) + line_i = grid_num_lines(grid) - max_lines; + else + line_i = 0; + + pack(array, grid_num_lines(grid) - line_i); + for (; line_i < grid_num_lines(grid); line_i++) { + line = &grid->linedata[line_i]; + + pack(array, 2); + str_len = 0; + for (i = 0; i < line->cellsize; i++) { + grid_get_cell(grid, i, line_i, &gc); + str_len += gc.data.size; + } + + pack(str, str_len); + for (i = 0; i < line->cellsize; i++) { + grid_get_cell(grid, i, line_i, &gc); + pack(str_body, gc.data.data, gc.data.size); + } + + pack(array, line->cellsize); + for (i = 0; i < line->cellsize; i++) { + grid_get_cell(grid, i, line_i, &gc); + pack(unsigned_int, ((gc.flags << 24) | + (gc.attr << 16) | + (gc.bg << 8) | + gc.fg )); + } + } +} + +static void tmate_send_session_snapshot(unsigned int max_history_lines) +{ + struct session *s; + struct winlink *wl; + struct window *w; + struct window_pane *pane; + int num_panes; + + pack(array, 2); + pack(int, TMATE_OUT_SNAPSHOT); + + s = RB_MIN(sessions, &sessions); + if (!s) + tmate_fatal("no session?"); + + num_panes = 0; + RB_FOREACH(wl, winlinks, &s->windows) { + w = wl->window; + if (!w) + continue; + + TAILQ_FOREACH(pane, &w->panes, entry) + num_panes++; + } + + pack(array, num_panes); + RB_FOREACH(wl, winlinks, &s->windows) { + w = wl->window; + if (!w) + continue; + + TAILQ_FOREACH(pane, &w->panes, entry) + do_snapshot(max_history_lines, pane); + } +} + +static void tmate_send_reconnection_data(struct tmate_session *session) +{ + if (!session->reconnection_data) + return; + + pack(array, 2); + pack(int, TMATE_OUT_RECONNECT); + pack(string, session->reconnection_data); +} + +#define RECONNECTION_MAX_HISTORY_LINE 300 + +void tmate_send_reconnection_state(struct tmate_session *session) +{ + /* Start with a fresh encoder */ + tmate_encoder_destroy(&session->encoder); + tmate_encoder_init(&session->encoder, NULL, session); + + tmate_write_header(); + tmate_send_reconnection_data(session); + /* TODO send all option variables */ + tmate_write_ready(); + + tmate_sync_layout(); + tmate_send_session_snapshot(RECONNECTION_MAX_HISTORY_LINE); +} diff --git a/tmate-msgpack.c b/tmate-msgpack.c index dbf14148..b7948ef9 100644 --- a/tmate-msgpack.c +++ b/tmate-msgpack.c @@ -65,13 +65,22 @@ void tmate_encoder_init(struct tmate_encoder *encoder, encoder->ev_active = false; } +void tmate_encoder_destroy(struct tmate_encoder *encoder) +{ + /* encoder->pk doesn't need any cleanup */ + evbuffer_free(encoder->buffer); + event_del(&encoder->ev_buffer); + memset(encoder, 0, sizeof(*encoder)); +} + void tmate_encoder_set_ready_callback(struct tmate_encoder *encoder, tmate_encoder_write_cb *callback, void *userdata) { encoder->ready_callback = callback; encoder->userdata = userdata; - encoder->ready_callback(encoder->userdata, encoder->buffer); + if (encoder->ready_callback) + encoder->ready_callback(encoder->userdata, encoder->buffer); } void tmate_decoder_error(void) @@ -178,6 +187,12 @@ void tmate_decoder_init(struct tmate_decoder *decoder, tmate_decoder_reader *rea decoder->userdata = userdata; } +void tmate_decoder_destroy(struct tmate_decoder *decoder) +{ + msgpack_unpacker_destroy(&decoder->unpacker); + memset(decoder, 0, sizeof(*decoder)); +} + void tmate_decoder_get_buffer(struct tmate_decoder *decoder, char **buf, size_t *len) { diff --git a/tmate-protocol.h b/tmate-protocol.h index 3f3a3614..93c65ba3 100644 --- a/tmate-protocol.h +++ b/tmate-protocol.h @@ -29,6 +29,7 @@ enum tmate_control_in_msg_types { TMATE_CTL_PANE_KEYS, TMATE_CTL_RESIZE, TMATE_CTL_EXEC_RESPONSE, + TMATE_CTL_RENAME_SESSION, }; /* @@ -37,6 +38,7 @@ enum tmate_control_in_msg_types { [TMATE_CTL_PANE_KEYS, int: pane_id, string: keys] [TMATE_CTL_RESIZE, int: sx, int: sy] // sx == -1: no clients [TMATE_CTL_EXEC_RESPONSE, int: exit_code, string: message] +[TMATE_CTL_RENAME_SESSION, string: stoken, string: stoken_ro] */ enum tmate_daemon_out_msg_types { @@ -50,6 +52,8 @@ enum tmate_daemon_out_msg_types { TMATE_OUT_WRITE_COPY_MODE, TMATE_OUT_FIN, TMATE_OUT_READY, + TMATE_OUT_RECONNECT, + TMATE_OUT_SNAPSHOT, }; /* diff --git a/tmate-session.c b/tmate-session.c index b7001509..6c9fea69 100644 --- a/tmate-session.c +++ b/tmate-session.c @@ -11,7 +11,8 @@ #include "tmate.h" -#define TMATE_DNS_RETRY_TIMEOUT 10 +#define TMATE_DNS_RETRY_TIMEOUT 2 +#define TMATE_RECONNECT_RETRY_TIMEOUT 2 struct tmate_session tmate_session; @@ -129,7 +130,8 @@ void tmate_session_init(struct event_base *base) void tmate_session_start(void) { - /* We split init and start because: + /* + * We split init and start because: * - We need to process the tmux config file during the connection as * we are setting up the tmate identity. * - While we are parsing the config file, we need to be able to @@ -137,3 +139,43 @@ void tmate_session_start(void) */ lookup_and_connect(); } + +static void on_reconnect_retry(__unused evutil_socket_t fd, __unused short what, void *arg) +{ + struct tmate_session *session = arg; + + if (session->last_server_ip) { + /* + * We have a previous server ip. Let's try that again first, + * but then connect to any server if it fails again. + */ + (void)tmate_ssh_client_alloc(&tmate_session, session->last_server_ip); + free(session->last_server_ip); + session->last_server_ip = NULL; + } else { + lookup_and_connect(); + } +} + +void tmate_reconnect_session(struct tmate_session *session) +{ + /* + * We no longer have an SSH connection. Time to reconnect. + * We'll reuse some of the session information if we can, + * and we'll try to reconnect to the same server if possible, + * to avoid an SSH connection string change. + */ + struct timeval tv = { .tv_sec = TMATE_RECONNECT_RETRY_TIMEOUT, .tv_usec = 0 }; + + evtimer_assign(&session->ev_connection_retry, session->ev_base, + on_reconnect_retry, session); + evtimer_add(&session->ev_connection_retry, &tv); + + tmate_status_message("Reconnecting..."); + + /* + * This says that we'll need to send a snapshot of the current state. + * Until we have persisted logs... + */ + session->reconnected = true; +} diff --git a/tmate-ssh-client.c b/tmate-ssh-client.c index 898344f1..6a351483 100644 --- a/tmate-ssh-client.c +++ b/tmate-ssh-client.c @@ -12,7 +12,7 @@ static void __on_ssh_client_event(evutil_socket_t fd, short what, void *arg); static void printflike(2, 3) kill_ssh_client(struct tmate_ssh_client *client, const char *fmt, ...); -static void printflike(2, 3) reconnect_ssh_client(struct tmate_ssh_client *client, +static void printflike(2, 3) kill_ssh_client(struct tmate_ssh_client *client, const char *fmt, ...); static void read_channel(struct tmate_ssh_client *client) @@ -25,8 +25,8 @@ static void read_channel(struct tmate_ssh_client *client) tmate_decoder_get_buffer(decoder, &buf, &len); len = ssh_channel_read_nonblocking(client->channel, buf, len, 0); if (len < 0) { - reconnect_ssh_client(client, "Error reading from channel: %s", - ssh_get_error(client->session)); + kill_ssh_client(client, "Error reading from channel: %s", + ssh_get_error(client->session)); break; } @@ -61,8 +61,8 @@ static void on_encoder_write(void *userdata, struct evbuffer *buffer) written = ssh_channel_write(client->channel, buf, len); if (written < 0) { - reconnect_ssh_client(client, "Error writing to channel: %s", - ssh_get_error(client->session)); + kill_ssh_client(client, "Error writing to channel: %s", + ssh_get_error(client->session)); break; } @@ -245,8 +245,8 @@ static void on_ssh_client_event(struct tmate_ssh_client *client) init_conn_fd(client); return; case SSH_ERROR: - reconnect_ssh_client(client, "Error connecting: %s", - ssh_get_error(session)); + kill_ssh_client(client, "Error connecting: %s", + ssh_get_error(session)); return; case SSH_OK: init_conn_fd(client); @@ -315,19 +315,20 @@ static void on_ssh_client_event(struct tmate_ssh_client *client) case SSH_AUTH_PARTIAL: case SSH_AUTH_INFO: case SSH_AUTH_DENIED: - if (client->tmate_session->need_passphrase) + if (client->tmate_session->need_passphrase) { request_passphrase(client); - else + } else { kill_ssh_client(client, "SSH keys not found." " Run 'ssh-keygen' to create keys and try again."); + return; + } if (client->tried_passphrase) tmate_status_message("Can't load SSH key." " Try typing passphrase again in case of typo. ctrl-c to abort."); return; case SSH_AUTH_ERROR: - reconnect_ssh_client(client, "Auth error: %s", - ssh_get_error(session)); + kill_ssh_client(client, "Auth error: %s", ssh_get_error(session)); return; case SSH_AUTH_SUCCESS: tmate_debug("Auth successful"); @@ -340,8 +341,8 @@ static void on_ssh_client_event(struct tmate_ssh_client *client) case SSH_AGAIN: return; case SSH_ERROR: - reconnect_ssh_client(client, "Error opening channel: %s", - ssh_get_error(session)); + kill_ssh_client(client, "Error opening channel: %s", + ssh_get_error(session)); return; case SSH_OK: tmate_debug("Session opened, initalizing tmate"); @@ -354,8 +355,8 @@ static void on_ssh_client_event(struct tmate_ssh_client *client) case SSH_AGAIN: return; case SSH_ERROR: - reconnect_ssh_client(client, "Error initializing tmate: %s", - ssh_get_error(session)); + kill_ssh_client(client, "Error initializing tmate: %s", + ssh_get_error(session)); return; case SSH_OK: tmate_debug("Ready"); @@ -365,19 +366,22 @@ static void on_ssh_client_event(struct tmate_ssh_client *client) client->state = SSH_READY; + if (client->tmate_session->reconnected) + tmate_send_reconnection_state(client->tmate_session); + tmate_encoder_set_ready_callback(&client->tmate_session->encoder, on_encoder_write, client); tmate_decoder_init(&client->tmate_session->decoder, on_decoder_read, client); + + free(client->tmate_session->last_server_ip); + client->tmate_session->last_server_ip = xstrdup(client->server_ip); + /* fall through */ } case SSH_READY: read_channel(client); - if (!ssh_is_connected(session)) { - reconnect_ssh_client(client, "Disconnected"); - return; - } } } @@ -386,19 +390,37 @@ static void __on_ssh_client_event(__unused evutil_socket_t fd, __unused short wh on_ssh_client_event(arg); } -static void __kill_ssh_client(struct tmate_ssh_client *client, - const char *fmt, va_list va) +static void kill_ssh_client(struct tmate_ssh_client *client, + const char *fmt, ...) { - if (fmt && TAILQ_EMPTY(&client->tmate_session->clients)) - __tmate_status_message(fmt, va); - else - tmate_debug("Disconnecting %s", client->server_ip); + bool last_client; + va_list ap; + + TAILQ_REMOVE(&client->tmate_session->clients, client, node); + last_client = TAILQ_EMPTY(&client->tmate_session->clients); + + if (fmt && last_client) { + va_start(ap, fmt); + __tmate_status_message(fmt, ap); + va_end(ap); + } + + tmate_debug("SSH client killed (%s)", client->server_ip); if (client->has_init_conn_fd) { event_del(&client->ev_ssh); client->has_init_conn_fd = false; } + if (client->state == SSH_READY) { + tmate_encoder_set_ready_callback(&client->tmate_session->encoder, NULL, NULL); + tmate_decoder_destroy(&client->tmate_session->decoder); + + client->tmate_session->min_sx = -1; + client->tmate_session->min_sy = -1; + recalculate_sizes(); + } + if (client->session) { /* ssh_free() also frees the associated channels. */ ssh_free(client->session); @@ -406,19 +428,8 @@ static void __kill_ssh_client(struct tmate_ssh_client *client, client->channel = NULL; } - client->state = SSH_NONE; -} - -static void kill_ssh_client(struct tmate_ssh_client *client, - const char *fmt, ...) -{ - va_list ap; - - TAILQ_REMOVE(&client->tmate_session->clients, client, node); - - va_start(ap, fmt); - __kill_ssh_client(client, fmt, ap); - va_end(ap); + if (last_client) + tmate_reconnect_session(client->tmate_session); free(client->server_ip); free(client); @@ -432,33 +443,6 @@ static void connect_ssh_client(struct tmate_ssh_client *client) } } -static void on_reconnect_timer(__unused evutil_socket_t fd, __unused short what, void *arg) -{ - connect_ssh_client(arg); -} - -static void reconnect_ssh_client(struct tmate_ssh_client *client, - const char *fmt, ...) -{ - /* struct timeval tv; */ - va_list ap; - -#if 1 - TAILQ_REMOVE(&client->tmate_session->clients, client, node); -#endif - - va_start(ap, fmt); - __kill_ssh_client(client, fmt, ap); - va_end(ap); - - /* Not yet implemented... */ -#if 0 - tv.tv_sec = 1; - tv.tv_usec = 0; - evtimer_add(&client->ev_ssh_reconnect, &tv); -#endif -} - static void ssh_log_function(int priority, const char *function, const char *buffer, __unused void *userdata) { @@ -489,9 +473,6 @@ struct tmate_ssh_client *tmate_ssh_client_alloc(struct tmate_session *session, client->has_init_conn_fd = false; - evtimer_assign(&client->ev_ssh_reconnect, session->ev_base, - on_reconnect_timer, client); - connect_ssh_client(client); return client; diff --git a/tmate.h b/tmate.h index 11236360..5e799e7e 100644 --- a/tmate.h +++ b/tmate.h @@ -30,6 +30,7 @@ struct tmate_encoder { extern void tmate_encoder_init(struct tmate_encoder *encoder, tmate_encoder_write_cb *callback, void *userdata); +extern void tmate_encoder_destroy(struct tmate_encoder *encoder); extern void tmate_encoder_set_ready_callback(struct tmate_encoder *encoder, tmate_encoder_write_cb *callback, void *userdata); @@ -50,6 +51,7 @@ struct tmate_decoder { }; extern void tmate_decoder_init(struct tmate_decoder *decoder, tmate_decoder_reader *reader, void *userdata); +extern void tmate_decoder_destroy(struct tmate_decoder *decoder); extern void tmate_decoder_get_buffer(struct tmate_decoder *decoder, char **buf, size_t *len); extern void tmate_decoder_commit(struct tmate_decoder *decoder, size_t len); @@ -75,6 +77,8 @@ extern void unpack_array(struct tmate_unpacker *uk, struct tmate_unpacker *neste #define TMATE_PROTOCOL_VERSION 6 +struct tmate_session; + extern void tmate_write_header(void); extern void tmate_write_ready(void); extern void tmate_sync_layout(void); @@ -86,6 +90,7 @@ extern void tmate_status(const char *left, const char *right); extern void tmate_sync_copy_mode(struct window_pane *wp); extern void tmate_write_copy_mode(struct window_pane *wp, const char *str); extern void tmate_write_fin(void); +extern void tmate_send_reconnection_state(struct tmate_session *session); /* tmate-decoder.c */ @@ -135,7 +140,6 @@ struct tmate_ssh_client { bool has_init_conn_fd; struct event ev_ssh; - struct event ev_ssh_reconnect; }; TAILQ_HEAD(tmate_ssh_clients, tmate_ssh_client); @@ -166,11 +170,17 @@ struct tmate_session { struct tmate_ssh_clients clients; int need_passphrase; char *passphrase; + + bool reconnected; + struct event ev_connection_retry; + char *last_server_ip; + char *reconnection_data; }; extern struct tmate_session tmate_session; extern void tmate_session_init(struct event_base *base); extern void tmate_session_start(void); +extern void tmate_reconnect_session(struct tmate_session *session); /* tmate-debug.c */ extern void tmate_print_stack_trace(void); From a7c55074643b06041f24aabf9fcec827ae4906b7 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sun, 27 Mar 2016 00:30:20 -0400 Subject: [PATCH 063/150] snapshot --- tmate-encoder.c | 46 ++++++++++++++++++++++++++++------------------ tmate.h | 2 +- 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/tmate-encoder.c b/tmate-encoder.c index 4155237b..10c9e8c8 100644 --- a/tmate-encoder.c +++ b/tmate-encoder.c @@ -2,7 +2,7 @@ #include "tmate-protocol.h" #include "window-copy.h" -#define pack(what, ...) _pack(&tmate_session.encoder, what, __VA_ARGS__) +#define pack(what, ...) _pack(&tmate_session.encoder, what, ##__VA_ARGS__) void tmate_write_header(void) { @@ -237,29 +237,14 @@ void tmate_write_fin(void) pack(int, TMATE_OUT_FIN); } -static void do_snapshot(unsigned int max_history_lines, - struct window_pane *pane) +static void do_snapshot_grid(struct grid *grid, unsigned int max_history_lines) { - struct screen *screen; - struct grid *grid; struct grid_line *line; struct grid_cell gc; unsigned int line_i, i; unsigned int max_lines; size_t str_len; - screen = &pane->base; - grid = screen->grid; - - pack(array, 4); - pack(int, pane->id); - - pack(array, 2); - pack(int, screen->cx); - pack(int, screen->cy); - - pack(unsigned_int, screen->mode); - max_lines = max_history_lines + grid->sy; #define grid_num_lines(grid) (grid->hsize + grid->sy) @@ -295,6 +280,31 @@ static void do_snapshot(unsigned int max_history_lines, gc.fg )); } } + +} + +static void do_snapshot_pane(struct window_pane *wp, unsigned int max_history_lines) +{ + struct screen *screen = &wp->base; + + pack(array, 4); + pack(int, wp->id); + + pack(unsigned_int, screen->mode); + + pack(array, 3); + pack(int, screen->cx); + pack(int, screen->cy); + do_snapshot_grid(screen->grid, max_history_lines); + + if (wp->saved_grid) { + pack(array, 3); + pack(int, wp->saved_cx); + pack(int, wp->saved_cy); + do_snapshot_grid(wp->saved_grid, max_history_lines); + } else { + pack(nil); + } } static void tmate_send_session_snapshot(unsigned int max_history_lines) @@ -329,7 +339,7 @@ static void tmate_send_session_snapshot(unsigned int max_history_lines) continue; TAILQ_FOREACH(pane, &w->panes, entry) - do_snapshot(max_history_lines, pane); + do_snapshot_pane(pane, max_history_lines); } } diff --git a/tmate.h b/tmate.h index 5e799e7e..0dca56f9 100644 --- a/tmate.h +++ b/tmate.h @@ -38,7 +38,7 @@ extern void tmate_encoder_set_ready_callback(struct tmate_encoder *encoder, extern void msgpack_pack_string(msgpack_packer *pk, const char *str); extern void msgpack_pack_boolean(msgpack_packer *pk, bool value); -#define _pack(enc, what, ...) msgpack_pack_##what(&(enc)->pk, __VA_ARGS__) +#define _pack(enc, what, ...) msgpack_pack_##what(&(enc)->pk, ##__VA_ARGS__) struct tmate_unpacker; struct tmate_decoder; From 474487c33e864f9cabc91fc627f9d64160c03a8f Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sun, 27 Mar 2016 01:10:23 -0400 Subject: [PATCH 064/150] Replay commands --- tmate-encoder.c | 38 +++++++++++++++++++++++++++++++++++++- tmate.h | 11 +++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/tmate-encoder.c b/tmate-encoder.c index 10c9e8c8..1a6c7b19 100644 --- a/tmate-encoder.c +++ b/tmate-encoder.c @@ -150,13 +150,48 @@ int tmate_should_replicate_cmd(const struct cmd_entry *cmd) return 0; } -void tmate_exec_cmd(const char *cmd) +#define sc (&session->saved_tmux_cmds) +#define SAVED_TMUX_CMD_INITIAL_SIZE 256 +static void __tmate_exec_cmd(const char *cmd); + +static void append_saved_cmd(struct tmate_session *session, + const char *cmd) +{ + if (!sc->cmds) { + sc->capacity = SAVED_TMUX_CMD_INITIAL_SIZE; + sc->cmds = xmalloc(sizeof(char *) * sc->capacity); + sc->tail = 0; + } + + if (sc->tail == sc->capacity) { + sc->capacity *= 2; + sc->cmds = xrealloc(sc->cmds, sizeof(char *) * sc->capacity); + } + + sc->cmds[sc->tail++] = xstrdup(cmd); +} + +static void replay_saved_cmd(struct tmate_session *session) +{ + unsigned int i; + for (i = 0; i < sc->tail; i++) + __tmate_exec_cmd(sc->cmds[i]); +} +#undef sc + +static void __tmate_exec_cmd(const char *cmd) { pack(array, 2); pack(int, TMATE_OUT_EXEC_CMD); pack(string, cmd); } +void tmate_exec_cmd(const char *cmd) +{ + __tmate_exec_cmd(cmd); + append_saved_cmd(&tmate_session, cmd); +} + void tmate_failed_cmd(int client_id, const char *cause) { pack(array, 3); @@ -363,6 +398,7 @@ void tmate_send_reconnection_state(struct tmate_session *session) tmate_write_header(); tmate_send_reconnection_data(session); + replay_saved_cmd(session); /* TODO send all option variables */ tmate_write_ready(); diff --git a/tmate.h b/tmate.h index 0dca56f9..e6d3ef09 100644 --- a/tmate.h +++ b/tmate.h @@ -175,6 +175,17 @@ struct tmate_session { struct event ev_connection_retry; char *last_server_ip; char *reconnection_data; + /* + * When we reconnect, instead of serializing the key bindings and + * options, we replay all the tmux commands we replicated. + * It may be a little innacurate to replicate the state, but + * it's much easier. + */ + struct { + unsigned int capacity; + unsigned int tail; + char **cmds; + } saved_tmux_cmds; }; extern struct tmate_session tmate_session; From 37c71cfe1587ffaea76776714bd38abe28697e83 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sun, 27 Mar 2016 02:06:56 -0400 Subject: [PATCH 065/150] Escape sent commands --- arguments.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/arguments.c b/arguments.c index f7f8f737..bcd2cd42 100644 --- a/arguments.c +++ b/arguments.c @@ -177,20 +177,34 @@ args_print(struct args *args) args_print_add(&buf, &len, " -%c ", entry->flag); else args_print_add(&buf, &len, "-%c ", entry->flag); +#ifdef TMATE + if (strchr(entry->value, '\'') != NULL) + args_print_add(&buf, &len, "\"%s\"", entry->value); + else + args_print_add(&buf, &len, "'%s'", entry->value); +#else if (strchr(entry->value, ' ') != NULL) args_print_add(&buf, &len, "\"%s\"", entry->value); else args_print_add(&buf, &len, "%s", entry->value); +#endif } /* And finally the argument vector. */ for (i = 0; i < args->argc; i++) { if (*buf != '\0') args_print_add(&buf, &len, " "); +#ifdef TMATE + if (strchr(args->argv[i], '\'') != NULL) + args_print_add(&buf, &len, "\"%s\"", args->argv[i]); + else + args_print_add(&buf, &len, "'%s'", args->argv[i]); +#else if (strchr(args->argv[i], ' ') != NULL) args_print_add(&buf, &len, "\"%s\"", args->argv[i]); else args_print_add(&buf, &len, "%s", args->argv[i]); +#endif } return (buf); From 9b5bb8390cd5318a29ce6249b9f16a06d11b78f3 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sun, 27 Mar 2016 02:29:43 -0400 Subject: [PATCH 066/150] better error message --- client.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/client.c b/client.c index 3db8783f..164abdd3 100644 --- a/client.c +++ b/client.c @@ -296,6 +296,13 @@ client_main(struct event_base *base, int argc, char **argv, int flags, fprintf(stderr, "no server running on %s\n", socket_path); } else { +#ifdef TMATE + if (errno == ENOENT) + fprintf(stderr, "You must specify a socket name with -S. For example: \n" + " tmate -S /tmp/tmate.sock new-session -d\n" + " tmate -S /tmp/tmate.sock wait tmate-ready\n"); + else +#endif fprintf(stderr, "error connecting to %s (%s)\n", socket_path, strerror(errno)); } From 1ade196fb2005cef09409827ad743abbe97a90ed Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sun, 27 Mar 2016 02:35:11 -0400 Subject: [PATCH 067/150] Default tmate messages to 15s --- options-table.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/options-table.c b/options-table.c index eb87d8a9..6b0c248b 100644 --- a/options-table.c +++ b/options-table.c @@ -939,7 +939,7 @@ const struct options_table_entry options_table[] = { .scope = OPTIONS_TABLE_SESSION, .minimum = 1, .maximum = INT_MAX, - .default_num = 30000 + .default_num = 15000 }, { .name = "tmate-webhook-userdata", From 78305a7077adf6b3b9143308e68afcab4d9cd94f Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sun, 27 Mar 2016 10:39:19 -0400 Subject: [PATCH 068/150] Cleanup socket --- server.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/server.c b/server.c index 7461d533..7313b711 100644 --- a/server.c +++ b/server.c @@ -213,6 +213,9 @@ server_start(struct event_base *base, int lockfd, char *lockfile) proc_loop(server_proc, server_loop); status_prompt_save_history(); +#ifdef TMATE + unlink(socket_path); +#endif exit(0); } From c88870b0a38acdfb598057ec344cc3d5e3991933 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sun, 27 Mar 2016 23:33:39 -0400 Subject: [PATCH 069/150] Revert "Escape sent commands" This reverts commit 37c71cfe1587ffaea76776714bd38abe28697e83. --- arguments.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/arguments.c b/arguments.c index bcd2cd42..f7f8f737 100644 --- a/arguments.c +++ b/arguments.c @@ -177,34 +177,20 @@ args_print(struct args *args) args_print_add(&buf, &len, " -%c ", entry->flag); else args_print_add(&buf, &len, "-%c ", entry->flag); -#ifdef TMATE - if (strchr(entry->value, '\'') != NULL) - args_print_add(&buf, &len, "\"%s\"", entry->value); - else - args_print_add(&buf, &len, "'%s'", entry->value); -#else if (strchr(entry->value, ' ') != NULL) args_print_add(&buf, &len, "\"%s\"", entry->value); else args_print_add(&buf, &len, "%s", entry->value); -#endif } /* And finally the argument vector. */ for (i = 0; i < args->argc; i++) { if (*buf != '\0') args_print_add(&buf, &len, " "); -#ifdef TMATE - if (strchr(args->argv[i], '\'') != NULL) - args_print_add(&buf, &len, "\"%s\"", args->argv[i]); - else - args_print_add(&buf, &len, "'%s'", args->argv[i]); -#else if (strchr(args->argv[i], ' ') != NULL) args_print_add(&buf, &len, "\"%s\"", args->argv[i]); else args_print_add(&buf, &len, "%s", args->argv[i]); -#endif } return (buf); From 02694d2a966b5d1e3a5d2cbd1b76c627eb4b6ec2 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sun, 27 Mar 2016 23:32:32 -0400 Subject: [PATCH 070/150] Send commands with their arguments in an array --- cmd-queue.c | 7 +++-- server.c | 8 ++--- tmate-decoder.c | 56 +++++++++++++++++++++++++++++++-- tmate-encoder.c | 81 ++++++++++++++++++++++++++++++++++++++++-------- tmate-protocol.h | 14 ++++++--- tmate.h | 8 +++-- 6 files changed, 145 insertions(+), 29 deletions(-) diff --git a/cmd-queue.c b/cmd-queue.c index fad9760b..f08a724e 100644 --- a/cmd-queue.c +++ b/cmd-queue.c @@ -201,12 +201,13 @@ cmdq_continue_one(struct cmd_q *cmdq) char *tmp; int flags = !!(cmd->flags & CMD_CONTROL); - tmp = cmd_print(cmd); - log_debug("cmdq %p: %s", cmdq, tmp); #ifdef TMATE if (tmate_should_replicate_cmd(cmd->entry)) - tmate_exec_cmd(tmp); + tmate_exec_cmd(cmd); #endif + + tmp = cmd_print(cmd); + log_debug("cmdq %p: %s", cmdq, tmp); free(tmp); cmdq->time = time(NULL); diff --git a/server.c b/server.c index 7313b711..81334f1e 100644 --- a/server.c +++ b/server.c @@ -135,13 +135,13 @@ server_create_socket(void) static void tmate_set_editor_mode(void) { switch (options_get_number(global_s_options, "status-keys")) { - case MODEKEY_EMACS: tmate_exec_cmd("set-option -g status-keys emacs"); break; - case MODEKEY_VI: tmate_exec_cmd("set-option -g status-keys vi"); break; + case MODEKEY_EMACS: tmate_exec_cmd_args(4, (const char *[]){"set-option", "-g", "status-keys", "emacs"}); break; + case MODEKEY_VI: tmate_exec_cmd_args(4, (const char *[]){"set-option", "-g", "status-keys", "vi"}); break; } switch (options_get_number(global_w_options, "mode-keys")) { - case MODEKEY_EMACS: tmate_exec_cmd("set-window-option -g mode-keys emacs"); break; - case MODEKEY_VI: tmate_exec_cmd("set-window-option -g mode-keys vi"); break; + case MODEKEY_EMACS: tmate_exec_cmd_args(4, (const char *[]){"set-window-option", "-g", "status-keys", "emacs"}); break; + case MODEKEY_VI: tmate_exec_cmd_args(4, (const char *[]){"set-window-option", "-g", "status-keys", "vi"}); break; } } #endif diff --git a/tmate-decoder.c b/tmate-decoder.c index 9669c4c0..3b1e31af 100644 --- a/tmate-decoder.c +++ b/tmate-decoder.c @@ -78,8 +78,8 @@ static void handle_resize(struct tmate_session *session, extern char **cfg_causes; extern u_int cfg_ncauses; -static void handle_exec_cmd(__unused struct tmate_session *session, - struct tmate_unpacker *uk) +static void handle_exec_cmd_str(__unused struct tmate_session *session, + struct tmate_unpacker *uk) { struct cmd_q *cmd_q; struct cmd_list *cmdlist; @@ -114,6 +114,55 @@ out: free(cmd_str); } +static void handle_exec_cmd(__unused struct tmate_session *session, + struct tmate_unpacker *uk) +{ + struct cmd_q *cmd_q; + struct cmd_list *cmdlist; + struct cmd *cmd; + char *cause; + u_int i; + unsigned int argc; + char **argv; + + int client_id = unpack_int(uk); + + argc = uk->argc; + argv = xmalloc(sizeof(char *) * argc); + for (i = 0; i < argc; i++) + argv[i] = unpack_string(uk); + + cmd = cmd_parse(argc, argv, NULL, 0, &cause); + if (!cmd) { + tmate_failed_cmd(client_id, cause); + free(cause); + goto out; + } + + cmdlist = xcalloc(1, sizeof *cmdlist); + cmdlist->references = 1; + TAILQ_INIT(&cmdlist->list); + TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry); + + cmd_q = cmdq_new(NULL); + cmdq_run(cmd_q, cmdlist, NULL); + cmd_list_free(cmdlist); + cmdq_free(cmd_q); + + /* error messages land in cfg_causes */ + for (i = 0; i < cfg_ncauses; i++) { + tmate_failed_cmd(client_id, cfg_causes[i]); + free(cfg_causes[i]); + } + + free(cfg_causes); + cfg_causes = NULL; + cfg_ncauses = 0; + +out: + cmd_free_argv(argc, argv); +} + static void maybe_save_reconnection_data(struct tmate_session *session, const char *name, const char *value) { @@ -152,10 +201,11 @@ void tmate_dispatch_slave_message(struct tmate_session *session, dispatch(TMATE_IN_NOTIFY, handle_notify); dispatch(TMATE_IN_LEGACY_PANE_KEY, handle_legacy_pane_key); dispatch(TMATE_IN_RESIZE, handle_resize); - dispatch(TMATE_IN_EXEC_CMD, handle_exec_cmd); + dispatch(TMATE_IN_EXEC_CMD_STR, handle_exec_cmd_str); dispatch(TMATE_IN_SET_ENV, handle_set_env); dispatch(TMATE_IN_READY, handle_ready); dispatch(TMATE_IN_PANE_KEY, handle_pane_key); + dispatch(TMATE_IN_EXEC_CMD, handle_exec_cmd); default: tmate_info("Bad message type: %d", cmd); } } diff --git a/tmate-encoder.c b/tmate-encoder.c index 1a6c7b19..d4be7c6e 100644 --- a/tmate-encoder.c +++ b/tmate-encoder.c @@ -152,44 +152,99 @@ int tmate_should_replicate_cmd(const struct cmd_entry *cmd) #define sc (&session->saved_tmux_cmds) #define SAVED_TMUX_CMD_INITIAL_SIZE 256 -static void __tmate_exec_cmd(const char *cmd); +static void __tmate_exec_cmd_args(int argc, const char **argv); static void append_saved_cmd(struct tmate_session *session, - const char *cmd) + int argc, const char **argv) { if (!sc->cmds) { sc->capacity = SAVED_TMUX_CMD_INITIAL_SIZE; - sc->cmds = xmalloc(sizeof(char *) * sc->capacity); + sc->cmds = xmalloc(sizeof(*sc->cmds) * sc->capacity); sc->tail = 0; } if (sc->tail == sc->capacity) { sc->capacity *= 2; - sc->cmds = xrealloc(sc->cmds, sizeof(char *) * sc->capacity); + sc->cmds = xrealloc(sc->cmds, sizeof(*sc->cmds) * sc->capacity); } - sc->cmds[sc->tail++] = xstrdup(cmd); + sc->cmds[sc->tail].argc = argc; + sc->cmds[sc->tail].argv = cmd_copy_argv(argc, (char **)argv); + + sc->tail++; } static void replay_saved_cmd(struct tmate_session *session) { unsigned int i; for (i = 0; i < sc->tail; i++) - __tmate_exec_cmd(sc->cmds[i]); + __tmate_exec_cmd_args(sc->cmds[i].argc, (const char **)sc->cmds[i].argv); } #undef sc -static void __tmate_exec_cmd(const char *cmd) +struct args_entry { + u_char flag; + char *value; + RB_ENTRY(args_entry) entry; +}; + +static void extract_cmd(struct cmd *cmd, int *_argc, char ***_argv) { - pack(array, 2); - pack(int, TMATE_OUT_EXEC_CMD); - pack(string, cmd); + struct args_entry *entry; + struct args* args = cmd->args; + int argc = 0; + char **argv; + int next = 0, i; + + argc++; /* cmd name */ + RB_FOREACH(entry, args_tree, &args->tree) { + argc++; + if (entry->value != NULL) + argc++; + } + argc += args->argc; + argv = xmalloc(sizeof(char *) * argc); + + argv[next++] = xstrdup(cmd->entry->name); + + RB_FOREACH(entry, args_tree, &args->tree) { + xasprintf(&argv[next++], "-%c", entry->flag); + if (entry->value != NULL) + argv[next++] = xstrdup(entry->value); + } + + for (i = 0; i < args->argc; i++) + argv[next++] = xstrdup(args->argv[i]); + + *_argc = argc; + *_argv = argv; } -void tmate_exec_cmd(const char *cmd) +static void __tmate_exec_cmd_args(int argc, const char **argv) { - __tmate_exec_cmd(cmd); - append_saved_cmd(&tmate_session, cmd); + int i; + + pack(array, argc + 1); + pack(int, TMATE_OUT_EXEC_CMD); + + for (i = 0; i < argc; i++) + pack(string, argv[i]); +} + +void tmate_exec_cmd_args(int argc, const char **argv) +{ + __tmate_exec_cmd_args(argc, argv); + append_saved_cmd(&tmate_session, argc, argv); +} + +void tmate_exec_cmd(struct cmd *cmd) +{ + int argc; + char **argv; + + extract_cmd(cmd, &argc, &argv); + tmate_exec_cmd_args(argc, (const char **)argv); + cmd_free_argv(argc, argv); } void tmate_failed_cmd(int client_id, const char *cause) diff --git a/tmate-protocol.h b/tmate-protocol.h index 93c65ba3..ebae07a9 100644 --- a/tmate-protocol.h +++ b/tmate-protocol.h @@ -45,7 +45,7 @@ enum tmate_daemon_out_msg_types { TMATE_OUT_HEADER, TMATE_OUT_SYNC_LAYOUT, TMATE_OUT_PTY_DATA, - TMATE_OUT_EXEC_CMD, + TMATE_OUT_EXEC_CMD_STR, TMATE_OUT_FAILED_CMD, TMATE_OUT_STATUS, TMATE_OUT_SYNC_COPY_MODE, @@ -54,6 +54,7 @@ enum tmate_daemon_out_msg_types { TMATE_OUT_READY, TMATE_OUT_RECONNECT, TMATE_OUT_SNAPSHOT, + TMATE_OUT_EXEC_CMD, }; /* @@ -62,7 +63,7 @@ enum tmate_daemon_out_msg_types { [[int: pane_id, int: sx, int: sy, int: xoff, int: yoff], ...], int: active_pane_id], ...], int: active_win_id] [TMATE_OUT_PTY_DATA, int: pane_id, binary: buffer] -[TMATE_OUT_EXEC_CMD, string: cmd] +[TMATE_OUT_EXEC_CMD_STR, string: cmd] [TMATE_OUT_FAILED_CMD, int: client_id, string: cause] [TMATE_OUT_STATUS, string: left, string: right] [TMATE_OUT_SYNC_COPY_MODE, int: pane_id, [int: backing, int: oy, int: cx, int: cy, @@ -72,26 +73,31 @@ enum tmate_daemon_out_msg_types { [TMATE_OUT_WRITE_COPY_MODE, int: pane_id, string: str] [TMATE_OUT_FIN] [TMATE_OUT_READY] +[TMATE_OUT_RECONNECT, string: reconnection_data] +[TMATE_OUT_SNAPSHOT, ...] +[TMATE_OUT_EXEC_CMD, string: cmd_name, ...string: args] */ enum tmate_daemon_in_msg_types { TMATE_IN_NOTIFY, TMATE_IN_LEGACY_PANE_KEY, TMATE_IN_RESIZE, - TMATE_IN_EXEC_CMD, + TMATE_IN_EXEC_CMD_STR, TMATE_IN_SET_ENV, TMATE_IN_READY, TMATE_IN_PANE_KEY, + TMATE_IN_EXEC_CMD, }; /* [TMATE_IN_NOTIFY, string: msg] [TMATE_IN_PANE_KEY, int: key] [TMATE_IN_RESIZE, int: sx, int: sy] // sx == -1: no clients -[TMATE_IN_EXEC_CMD, int: client_id, string: cmd] +[TMATE_IN_EXEC_CMD_STR, int: client_id, string: cmd] [TMATE_IN_SET_ENV, string: name, string: value] [TMATE_IN_READY] [TMATE_IN_PANE_KEY, int: pane_id, uint64 keycode] // pane_id == -1: active pane +[TMATE_IN_EXEC_CMD, int: client_id, ...string: args] */ #endif diff --git a/tmate.h b/tmate.h index e6d3ef09..fb764c54 100644 --- a/tmate.h +++ b/tmate.h @@ -84,7 +84,8 @@ extern void tmate_write_ready(void); extern void tmate_sync_layout(void); extern void tmate_pty_data(struct window_pane *wp, const char *buf, size_t len); extern int tmate_should_replicate_cmd(const struct cmd_entry *cmd); -extern void tmate_exec_cmd(const char *cmd); +extern void tmate_exec_cmd_args(int argc, const char **argv); +extern void tmate_exec_cmd(struct cmd *cmd); extern void tmate_failed_cmd(int client_id, const char *cause); extern void tmate_status(const char *left, const char *right); extern void tmate_sync_copy_mode(struct window_pane *wp); @@ -184,7 +185,10 @@ struct tmate_session { struct { unsigned int capacity; unsigned int tail; - char **cmds; + struct { + int argc; + char **argv; + } *cmds; } saved_tmux_cmds; }; From 71d31e60e6eef1f79191977eb8c7210174d33187 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Mon, 28 Mar 2016 16:27:09 -0400 Subject: [PATCH 071/150] Be less strict over msgpack message size --- tmate-encoder.c | 7 ++++--- tmate-msgpack.c | 8 ++++---- tmate-protocol.h | 2 -- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/tmate-encoder.c b/tmate-encoder.c index d4be7c6e..c15d8921 100644 --- a/tmate-encoder.c +++ b/tmate-encoder.c @@ -108,13 +108,14 @@ void tmate_sync_layout(void) /* TODO add a buffer for pty_data ? */ +#define TMATE_MAX_PTY_SIZE (16*1024) + void tmate_pty_data(struct window_pane *wp, const char *buf, size_t len) { - size_t max_write, to_write; + size_t to_write; - max_write = TMATE_MAX_MESSAGE_SIZE - 16; while (len > 0) { - to_write = len < max_write ? len : max_write; + to_write = len < TMATE_MAX_PTY_SIZE ? len : TMATE_MAX_PTY_SIZE; pack(array, 3); pack(int, TMATE_OUT_PTY_DATA); diff --git a/tmate-msgpack.c b/tmate-msgpack.c index b7948ef9..144cda70 100644 --- a/tmate-msgpack.c +++ b/tmate-msgpack.c @@ -178,10 +178,12 @@ void unpack_array(struct tmate_unpacker *uk, struct tmate_unpacker *nested) uk->argc--; } +#define UNPACKER_RESERVE_SIZE 1024 + void tmate_decoder_init(struct tmate_decoder *decoder, tmate_decoder_reader *reader, void *userdata) { - if (!msgpack_unpacker_init(&decoder->unpacker, TMATE_MAX_MESSAGE_SIZE)) + if (!msgpack_unpacker_init(&decoder->unpacker, UNPACKER_RESERVE_SIZE)) tmate_fatal("Cannot initialize the unpacker"); decoder->reader = reader; decoder->userdata = userdata; @@ -196,9 +198,7 @@ void tmate_decoder_destroy(struct tmate_decoder *decoder) void tmate_decoder_get_buffer(struct tmate_decoder *decoder, char **buf, size_t *len) { - ssize_t current_size = msgpack_unpacker_message_size(&decoder->unpacker); - if (!msgpack_unpacker_reserve_buffer(&decoder->unpacker, - TMATE_MAX_MESSAGE_SIZE - current_size)) + if (!msgpack_unpacker_reserve_buffer(&decoder->unpacker, UNPACKER_RESERVE_SIZE)) tmate_fatal("cannot expand decoder buffer"); *buf = msgpack_unpacker_buffer(&decoder->unpacker); diff --git a/tmate-protocol.h b/tmate-protocol.h index ebae07a9..1858b691 100644 --- a/tmate-protocol.h +++ b/tmate-protocol.h @@ -1,8 +1,6 @@ #ifndef TMATE_PROTOCOL_H #define TMATE_PROTOCOL_H -#define TMATE_MAX_MESSAGE_SIZE (16*1024) - enum tmate_control_out_msg_types { TMATE_CTL_AUTH, TMATE_CTL_DEAMON_OUT_MSG, From d41b06dea2c87e02de7bb2a7f85f0ddaf2db7064 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Mon, 28 Mar 2016 16:28:11 -0400 Subject: [PATCH 072/150] sync tmate-protocol.h --- tmate-protocol.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tmate-protocol.h b/tmate-protocol.h index 1858b691..595b6271 100644 --- a/tmate-protocol.h +++ b/tmate-protocol.h @@ -2,23 +2,26 @@ #define TMATE_PROTOCOL_H enum tmate_control_out_msg_types { - TMATE_CTL_AUTH, + TMATE_CTL_HEADER, TMATE_CTL_DEAMON_OUT_MSG, TMATE_CTL_SNAPSHOT, TMATE_CTL_CLIENT_JOIN, TMATE_CTL_CLIENT_LEFT, TMATE_CTL_EXEC, + TMATE_CTL_LATENCY, }; /* -[TMATE_CTL_AUTH, int: ctl_proto_version, string: ip_address, string: pubkey, - string: session_token, string: session_token_ro] +[TMATE_CTL_HEADER, int: ctl_proto_version, string: ip_address, string: pubkey, + string: session_token, string: session_token_ro, string: ssh_cmd_fmt] + string: client_version, int: client_protocol_version] [TMATE_CTL_DEAMON_OUT_MSG, object: msg] [TMATE_CTL_SNAPSHOT, [[int: pane_id, [int: cur_x, int: cur_y], int: mode, [[string: line_utf8, [int: char_attr, ...]], ...], ...], ...]] [TMATE_CTL_CLIENT_JOIN, int: client_id, string: ip_address, string: pubkey, boolean: readonly] [TMATE_CTL_CLIENT_LEFT, int: client_id] [TMATE_CTL_EXEC, string: username, string: ip_address, string: pubkey, string: command] +[TMATE_CTL_LATENCY, int: client_id, int: latency_ms] // client_id == -1: tmate host */ enum tmate_control_in_msg_types { From 46a29037d43c774c07c1160994b15bb1a64c20a7 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Mon, 28 Mar 2016 23:19:42 -0400 Subject: [PATCH 073/150] strip static builds Fixes #79 --- Makefile.static-build | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile.static-build b/Makefile.static-build index 6db26d76..9bc83d92 100644 --- a/Makefile.static-build +++ b/Makefile.static-build @@ -54,6 +54,7 @@ tmate: $(MSGPACK_LIB) $(LIBSSH_LIB) $(patsubst %,libc/%.o,$(STATIC_LIBC_OBJECTS) ./autogen.sh $(TMATE_CONFIGURE) ./configure --enable-static +make + strip tmate clean: rm -rf ext libc $(LIBSSH) $(MSGPACK) From c9813a8c4249f930750ee4793e0972db43048d2c Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Mon, 28 Mar 2016 23:29:49 -0400 Subject: [PATCH 074/150] Provide better reconnection error message --- tmate-session.c | 7 +++++-- tmate-ssh-client.c | 6 ++++-- tmate.h | 2 +- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/tmate-session.c b/tmate-session.c index 6c9fea69..b43a261b 100644 --- a/tmate-session.c +++ b/tmate-session.c @@ -157,7 +157,7 @@ static void on_reconnect_retry(__unused evutil_socket_t fd, __unused short what, } } -void tmate_reconnect_session(struct tmate_session *session) +void tmate_reconnect_session(struct tmate_session *session, const char *message) { /* * We no longer have an SSH connection. Time to reconnect. @@ -171,7 +171,10 @@ void tmate_reconnect_session(struct tmate_session *session) on_reconnect_retry, session); evtimer_add(&session->ev_connection_retry, &tv); - tmate_status_message("Reconnecting..."); + if (message) + tmate_status_message("Reconnecting... (%s)", message); + else + tmate_status_message("Reconnecting..."); /* * This says that we'll need to send a snapshot of the current state. diff --git a/tmate-ssh-client.c b/tmate-ssh-client.c index 6a351483..7495d584 100644 --- a/tmate-ssh-client.c +++ b/tmate-ssh-client.c @@ -395,14 +395,16 @@ static void kill_ssh_client(struct tmate_ssh_client *client, { bool last_client; va_list ap; + char *message = NULL; TAILQ_REMOVE(&client->tmate_session->clients, client, node); last_client = TAILQ_EMPTY(&client->tmate_session->clients); if (fmt && last_client) { va_start(ap, fmt); - __tmate_status_message(fmt, ap); + xvasprintf(&message, fmt, ap); va_end(ap); + tmate_status_message("%s", message); } tmate_debug("SSH client killed (%s)", client->server_ip); @@ -429,7 +431,7 @@ static void kill_ssh_client(struct tmate_ssh_client *client, } if (last_client) - tmate_reconnect_session(client->tmate_session); + tmate_reconnect_session(client->tmate_session, message); free(client->server_ip); free(client); diff --git a/tmate.h b/tmate.h index fb764c54..f096a35c 100644 --- a/tmate.h +++ b/tmate.h @@ -195,7 +195,7 @@ struct tmate_session { extern struct tmate_session tmate_session; extern void tmate_session_init(struct event_base *base); extern void tmate_session_start(void); -extern void tmate_reconnect_session(struct tmate_session *session); +extern void tmate_reconnect_session(struct tmate_session *session, const char *message); /* tmate-debug.c */ extern void tmate_print_stack_trace(void); From e840ff7582496386e63d289f2c21dc914088374f Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Mon, 28 Mar 2016 23:06:24 -0400 Subject: [PATCH 075/150] Version Bump --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 55eaf24a..02d2872b 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ # configure.ac -AC_INIT(tmate, 2.2.0) +AC_INIT(tmate, 2.2.1) AC_CONFIG_AUX_DIR(etc) AM_INIT_AUTOMAKE([foreign subdir-objects]) From d433fe69565db25b4248b8e9f0316d2cd04fe7e3 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Tue, 29 Mar 2016 01:42:07 -0400 Subject: [PATCH 076/150] nits --- tmate-ssh-client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmate-ssh-client.c b/tmate-ssh-client.c index 7495d584..b280400d 100644 --- a/tmate-ssh-client.c +++ b/tmate-ssh-client.c @@ -319,7 +319,7 @@ static void on_ssh_client_event(struct tmate_ssh_client *client) request_passphrase(client); } else { kill_ssh_client(client, "SSH keys not found." - " Run 'ssh-keygen' to create keys and try again."); + " Run 'ssh-keygen' to create keys."); return; } From fe81322cc4801860c33b1e31970b8f0f6bf603c7 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Thu, 21 Apr 2016 16:05:52 -0400 Subject: [PATCH 077/150] Keep alive the socket to make reconnections work properly --- tmate-ssh-client.c | 44 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/tmate-ssh-client.c b/tmate-ssh-client.c index b280400d..8b78f5cc 100644 --- a/tmate-ssh-client.c +++ b/tmate-ssh-client.c @@ -165,22 +165,48 @@ static void request_passphrase(struct tmate_ssh_client *client) data->password_cb_private = client; } +#define KEEPALIVE_CNT 3 +#define KEEPALIVE_IDLE 20 +#define KEEPALIVE_INTVL 10 + +static void setup_socket(int fd) +{ +#define SSO(level, optname, val) ({ \ + int _flag = val; \ + if (setsockopt(fd, level, optname, &(_flag), sizeof(int)) < 0) { \ + tmate_warn("setsockopt(" #level ", " #optname ", %d) failed", val); \ + } \ +}) + + SSO(IPPROTO_TCP, TCP_NODELAY, 1); + SSO(SOL_SOCKET, SO_KEEPALIVE, 1); +#ifdef TCP_KEEPALIVE + SSO(IPPROTO_TCP, TCP_KEEPALIVE, KEEPALIVE_IDLE); +#endif +#ifdef TCP_KEEPCNT + SSO(IPPROTO_TCP, TCP_KEEPCNT, KEEPALIVE_CNT); +#endif +#ifdef TCP_KEEPIDLE + SSO(IPPROTO_TCP, TCP_KEEPIDLE, KEEPALIVE_IDLE); +#endif +#ifdef TCP_KEEPINTVL + SSO(IPPROTO_TCP, TCP_KEEPINTVL, KEEPALIVE_INTVL); +#endif +#undef SSO +} + static void init_conn_fd(struct tmate_ssh_client *client) { + int fd; + if (client->has_init_conn_fd) return; - if (ssh_get_fd(client->session) < 0) + if ((fd = ssh_get_fd(client->session)) < 0) return; - { - int flag = 1; - setsockopt(ssh_get_fd(client->session), IPPROTO_TCP, - TCP_NODELAY, &flag, sizeof(flag)); - } - - event_set(&client->ev_ssh, ssh_get_fd(client->session), - EV_READ | EV_PERSIST, __on_ssh_client_event, client); + setup_socket(fd); + event_set(&client->ev_ssh, fd, EV_READ | EV_PERSIST, __on_ssh_client_event, client); event_add(&client->ev_ssh, NULL); client->has_init_conn_fd = true; From 27169b7c076376718abf98f7a1a6b484bd579314 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sun, 5 Jun 2016 12:54:25 -0400 Subject: [PATCH 078/150] Add missing incldues for FreeBSD --- tmate-session.c | 1 + tmate-ssh-client.c | 1 + 2 files changed, 2 insertions(+) diff --git a/tmate-session.c b/tmate-session.c index b43a261b..8d647203 100644 --- a/tmate-session.c +++ b/tmate-session.c @@ -2,6 +2,7 @@ #include #include +#include #include #include diff --git a/tmate-ssh-client.c b/tmate-ssh-client.c index 8b78f5cc..f13db90a 100644 --- a/tmate-ssh-client.c +++ b/tmate-ssh-client.c @@ -1,4 +1,5 @@ #include +#include #include #include #include From b27f3bacc0308a86a5f3e3494bd0383cd7583971 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Fri, 10 Jun 2016 18:00:50 -0400 Subject: [PATCH 079/150] Crash fix in search prev/next match Fixes #87 --- window-copy.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/window-copy.c b/window-copy.c index 3862a688..939d3e19 100644 --- a/window-copy.c +++ b/window-copy.c @@ -1054,6 +1054,11 @@ window_copy_search_up(struct window_pane *wp, const char *searchstr) int n, wrapped, wrapflag, cis; const char *ptr; +#ifdef TMATE + if (!searchstr) + return; +#endif + if (*searchstr == '\0') return; wrapflag = options_get_number(wp->window->options, "wrap-search"); @@ -1120,6 +1125,11 @@ window_copy_search_down(struct window_pane *wp, const char *searchstr) int n, wrapped, wrapflag, cis; const char *ptr; +#ifdef TMATE + if (!searchstr) + return; +#endif + if (*searchstr == '\0') return; wrapflag = options_get_number(wp->window->options, "wrap-search"); From 608763a41a2437a8d3e0e54482d0b5f3d1c1e686 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Tue, 14 Jun 2016 13:46:15 -0400 Subject: [PATCH 080/150] Attempt to fix environment related crash Fixes #89 --- cmd-string.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cmd-string.c b/cmd-string.c index 757d4cdb..fdef4a82 100644 --- a/cmd-string.c +++ b/cmd-string.c @@ -307,6 +307,10 @@ cmd_string_variable(const char *s, size_t *p) free(buf); if (envent == NULL) return (xstrdup("")); +#ifdef TMATE + if (envent->value == NULL) + return (xstrdup("")); +#endif return (xstrdup(envent->value)); error: From 3f6c6d44472a5ccab0403ebf89fc59e7df58b6b2 Mon Sep 17 00:00:00 2001 From: Natanael Copa Date: Thu, 28 Sep 2017 10:28:42 +0000 Subject: [PATCH 081/150] Fix building with or without backtrace(3) backtrace(3) and execinfo.h are GNU extensions and may or may not be available, and they may be provided via libexecinfo. Fix detection of libexecinfo and allow building without any support of backtrace, in which case we let kernel create core dump. Fixes #116 #117 --- configure.ac | 5 +++++ tmate-debug.c | 10 ++++++++++ 2 files changed, 15 insertions(+) diff --git a/configure.ac b/configure.ac index 02d2872b..05c1c482 100644 --- a/configure.ac +++ b/configure.ac @@ -102,6 +102,7 @@ AC_CHECK_HEADERS( bitstring.h \ curses.h \ dirent.h \ + execinfo.h \ fcntl.h \ inttypes.h \ libutil.h \ @@ -121,9 +122,13 @@ AC_CHECK_HEADERS( # Look for library needed for flock. AC_SEARCH_LIBS(flock, bsd) +# Look for library needed for backtrace +AC_SEARCH_LIBS(backtrace, execinfo) + # Check for some functions that are replaced or omitted. AC_CHECK_FUNCS( [ \ + backtrace \ dirfd \ flock \ setproctitle \ diff --git a/tmate-debug.c b/tmate-debug.c index f1fd971f..f58efe0e 100644 --- a/tmate-debug.c +++ b/tmate-debug.c @@ -1,10 +1,19 @@ +#ifdef HAVE_EXECINFO_H #include +#endif #include #include #include #include #include "tmate.h" +#ifndef HAVE_BACKTRACE + +void tmate_print_stack_trace(void) {} +void tmate_catch_sigsegv(void) {} + +#else + #if DEBUG static int print_resolved_stack_frame(const char *frame) @@ -88,3 +97,4 @@ void tmate_catch_sigsegv(void) { signal(SIGSEGV, handle_sigsegv); } +#endif From 25f6a934cf498e32bd5e13ea9e03b6840ab7064d Mon Sep 17 00:00:00 2001 From: David Bishop Date: Tue, 23 Oct 2018 17:39:10 -0600 Subject: [PATCH 082/150] Update MAN page to properly reference tmate where applicable While there are still plenty of places where tmate uses tmux, including config files and environment variables, I have updated the various examples to use tmate where applicable. --- tmux.1 | 45 +++++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/tmux.1 b/tmux.1 index 776b6faf..b55b3682 100644 --- a/tmux.1 +++ b/tmux.1 @@ -15,13 +15,13 @@ .\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" .Dd $Mdocdate: March 25 2013 $ -.Dt TMUX 1 +.Dt TMATE 1 .Os .Sh NAME -.Nm tmux +.Nm tmate .Nd terminal multiplexer .Sh SYNOPSIS -.Nm tmux +.Nm tmate .Bk -words .Op Fl 2CluvV .Op Fl c Ar shell-command @@ -80,7 +80,7 @@ key strokes). .Nm may be reattached using: .Pp -.Dl $ tmux attach +.Dl $ tmate attach .Pp In .Nm , @@ -126,7 +126,9 @@ By default, loads the system configuration file from .Pa @SYSCONFDIR@/tmux.conf , if present, then looks for a user configuration file at -.Pa ~/.tmux.conf . +.Pa ~/.tmux.conf +and +.Pa ~/.tmate.conf . .Pp The configuration file is a set of .Nm @@ -167,7 +169,9 @@ directories are missing). .It Fl l Behave as a login shell. This flag currently has no effect and is for compatibility with other shells -when using tmux as a login shell. +when using +.Nm +as a login shell. .It Fl S Ar socket-path Specify a full alternative path to the server socket. If @@ -597,7 +601,7 @@ to be given as multiple arguments and executed directly (without This can avoid issues with shell quoting. For example: .Bd -literal -offset indent -$ tmux new-window vi /etc/passwd +$ tmate new-window vi /etc/passwd .Ed .Pp Will run @@ -616,7 +620,7 @@ bind-key F1 set-window-option force-width 81 Or if using .Xr sh 1 : .Bd -literal -offset indent -$ tmux bind-key F1 set-window-option force-width 81 +$ tmate bind-key F1 set-window-option force-width 81 .Ed .Pp Multiple commands may be specified together as part of a @@ -648,11 +652,11 @@ bind-key R source-file ~/.tmux.conf \e; \e Or from .Xr sh 1 : .Bd -literal -offset indent -$ tmux kill-window -t :1 +$ tmate kill-window -t :1 -$ tmux new-window \e; split-window -d +$ tmate new-window \e; split-window -d -$ tmux new-session -d 'vi /etc/passwd' \e; split-window -d \e; attach +$ tmate new-session -d 'vi /etc/passwd' \e; split-window -d \e; attach .Ed .Sh CLIENTS AND SESSIONS The @@ -1236,10 +1240,10 @@ command displays the layout of each window in a form suitable for use with .Ic select-layout . For example: .Bd -literal -offset indent -$ tmux list-windows +$ tmate list-windows 0: ksh [159x48] layout: bb62,159x48,0,0{79x48,0,0,79x48,80,0} -$ tmux select-layout bb62,159x48,0,0{79x48,0,0,79x48,80,0} +$ tmate select-layout bb62,159x48,0,0{79x48,0,0,79x48,80,0} .Ed .Pp .Nm @@ -2307,8 +2311,8 @@ User options may have any name, so long as they are prefixed with and be set to any string. For example: .Bd -literal -offset indent -$ tmux setw -q @foo "abc123" -$ tmux showw -v @foo +$ tmate setw -q @foo "abc123" +$ tmate showw -v @foo abc123 .Ed .Pp @@ -2394,7 +2398,8 @@ to work correctly, this .Em must be set to .Ql screen , -.Ql tmux +.Ql tmux , +.Ql tmate or a derivative of them. .It Ic escape-time Ar time Set the time in milliseconds for which @@ -4172,18 +4177,18 @@ To create a new session running .Xr vi 1 : .Pp -.Dl $ tmux new-session vi +.Dl $ tmate new-session vi .Pp Most commands have a shorter form, known as an alias. For new-session, this is .Ic new : .Pp -.Dl $ tmux new vi +.Dl $ tmate new vi .Pp Alternatively, the shortest unambiguous form of a command is accepted. If there are several options, they are listed: .Bd -literal -offset indent -$ tmux n +$ tmate n ambiguous command: n, could be: new-session, new-window, next-window .Ed .Pp @@ -4213,7 +4218,7 @@ A session may be detached using .Xr ssh 1 disconnection) and reattached with: .Pp -.Dl $ tmux attach-session +.Dl $ tmate attach-session .Pp Typing .Ql C-b \&? From 2ffcbbd18508d6fdb28660ee2e8826acc5899a12 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Wed, 20 Mar 2019 19:05:49 +0100 Subject: [PATCH 083/150] ssh-client: Use SHA256 finger prints Signed-off-by: Andreas Schneider --- options-table.c | 4 ++-- tmate-ssh-client.c | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/options-table.c b/options-table.c index 6b0c248b..90d3297b 100644 --- a/options-table.c +++ b/options-table.c @@ -925,13 +925,13 @@ const struct options_table_entry options_table[] = { { .name = "tmate-server-rsa-fingerprint", .type = OPTIONS_TABLE_STRING, .scope = OPTIONS_TABLE_SERVER, - .default_str = "af:2d:81:c1:fe:49:70:2d:7f:09:a9:d7:4b:32:e3:be" + .default_str = "SHA256:Hthk2T/M/Ivqfk1YYUn5ijC2Att3+UPzD7Rn72P5VWs" }, { .name = "tmate-server-ecdsa-fingerprint", .type = OPTIONS_TABLE_STRING, .scope = OPTIONS_TABLE_SERVER, - .default_str = "c7:a1:51:36:d2:bb:35:4b:0a:1a:c0:43:97:74:ea:42" + .default_str = "SHA256:8GmKHYHEJ6n0TEdciHeEGkKOigQfCFuBULdt6vZIhDc" }, { .name = "tmate-display-time", diff --git a/tmate-ssh-client.c b/tmate-ssh-client.c index f13db90a..fbe9a470 100644 --- a/tmate-ssh-client.c +++ b/tmate-ssh-client.c @@ -287,12 +287,14 @@ static void on_ssh_client_event(struct tmate_ssh_client *client) if (ssh_get_publickey(session, &pubkey) < 0) tmate_fatal("ssh_get_publickey"); - if (ssh_get_publickey_hash(pubkey, SSH_PUBLICKEY_HASH_MD5, &hash, &hash_len) < 0) { + if (ssh_get_publickey_hash(pubkey, SSH_PUBLICKEY_HASH_SHA256, + &hash, &hash_len) < 0) { kill_ssh_client(client, "Cannot authenticate server"); return; } - hash_str = ssh_get_hexa(hash, hash_len); + hash_str = ssh_get_fingerprint_hash(SSH_PUBLICKEY_HASH_SHA256, + hash, hash_len); if (!hash_str) tmate_fatal("malloc failed"); From b645ce15cb1b64183a002e82112f2ac4830cd693 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Wed, 20 Mar 2019 19:06:18 +0100 Subject: [PATCH 084/150] ssh-client: Add support for ed25519 keys Signed-off-by: Andreas Schneider --- options-table.c | 6 ++++++ tmate-ssh-client.c | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/options-table.c b/options-table.c index 90d3297b..a44f9445 100644 --- a/options-table.c +++ b/options-table.c @@ -934,6 +934,12 @@ const struct options_table_entry options_table[] = { .default_str = "SHA256:8GmKHYHEJ6n0TEdciHeEGkKOigQfCFuBULdt6vZIhDc" }, + { .name = "tmate-server-ed25519-fingerprint", + .type = OPTIONS_TABLE_STRING, + .scope = OPTIONS_TABLE_SERVER, + .default_str = "" + }, + { .name = "tmate-display-time", .type = OPTIONS_TABLE_NUMBER, .scope = OPTIONS_TABLE_SESSION, diff --git a/tmate-ssh-client.c b/tmate-ssh-client.c index fbe9a470..bdad138d 100644 --- a/tmate-ssh-client.c +++ b/tmate-ssh-client.c @@ -309,6 +309,10 @@ static void on_ssh_client_event(struct tmate_ssh_client *client) server_hash_str = options_get_string(global_options, "tmate-server-ecdsa-fingerprint"); break; + case SSH_KEYTYPE_ED25519: + server_hash_str = options_get_string(global_options, + "tmate-server-ed25519-fingerprint"); + break; default: server_hash_str = ""; } From b01c6ecebde69726b330c3d2c5ba0fa757dc6447 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Wed, 20 Mar 2019 19:12:33 +0100 Subject: [PATCH 085/150] configure: Require libssh >= 0.8.4 Signed-off-by: Andreas Schneider --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 05c1c482..8c6c5b98 100644 --- a/configure.ac +++ b/configure.ac @@ -214,7 +214,7 @@ fi PKG_CHECK_MODULES( LIBSSH, - libssh >= 0.6.0, + libssh >= 0.8.4, [ CPPFLAGS="$LIBSSH_CFLAGS $CPPFLAGS" LIBS="$LIBSSH_LIBS $LIBS" @@ -223,7 +223,7 @@ PKG_CHECK_MODULES( found_libssh=no ) if test "x$found_libssh" = xno; then - AC_MSG_ERROR("libssh >= 0.6.0 not found") + AC_MSG_ERROR("libssh >= 0.8.4 not found") fi # Check for b64_ntop. From 32d48cbc9df07045af43e0e8d76bd7a58647cce1 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sun, 7 Apr 2019 10:20:22 -0400 Subject: [PATCH 086/150] Update ed25519 server key (not yet in production) --- options-table.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/options-table.c b/options-table.c index a44f9445..4966431c 100644 --- a/options-table.c +++ b/options-table.c @@ -937,7 +937,7 @@ const struct options_table_entry options_table[] = { { .name = "tmate-server-ed25519-fingerprint", .type = OPTIONS_TABLE_STRING, .scope = OPTIONS_TABLE_SERVER, - .default_str = "" + .default_str = "SHA256:jfttvoypkHiQYUqUCwKeqd9d1fJj/ZiQlFOHVl6E9sI" }, { .name = "tmate-display-time", From fd4ac27d59604aae0117ad578b1a7e6dccf97bf7 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Wed, 20 Mar 2019 19:17:46 +0100 Subject: [PATCH 087/150] ssh-client: Don't use keys from the ssh-agent Fixes #138 Signed-off-by: Andreas Schneider --- tmate-ssh-client.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tmate-ssh-client.c b/tmate-ssh-client.c index bdad138d..96da14c8 100644 --- a/tmate-ssh-client.c +++ b/tmate-ssh-client.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -260,6 +261,9 @@ static void on_ssh_client_event(struct tmate_ssh_client *client) * regular one doesn't. */ ssh_options_set(session, SSH_OPTIONS_IDENTITY, identity); + + /* Do not use keys from ssh-agent. */ + unsetenv("SSH_AUTH_SOCK"); free(identity); } From 299c7c670c3d56ad6eaf73618dcf0c3c5d6fa2ec Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 30 Jul 2019 08:15:59 +0200 Subject: [PATCH 088/150] add new channel after authentication With libssh commit 8a885f0b ("channels: Add check if we are authenticated before we create a channel") connection fails if channel is added before successful authentication. So add the channel after authentication. Fixes #154 --- tmate-ssh-client.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tmate-ssh-client.c b/tmate-ssh-client.c index 96da14c8..2a9afee0 100644 --- a/tmate-ssh-client.c +++ b/tmate-ssh-client.c @@ -241,12 +241,6 @@ static void on_ssh_client_event(struct tmate_ssh_client *client) ssh_set_callbacks(session, &client->ssh_callbacks); - client->channel = channel = ssh_channel_new(session); - if (!channel) { - tmate_fatal("cannot initialize"); - return; - } - ssh_set_blocking(session, 0); ssh_options_set(session, SSH_OPTIONS_HOST, client->server_ip); ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity); @@ -370,6 +364,12 @@ static void on_ssh_client_event(struct tmate_ssh_client *client) case SSH_AUTH_SUCCESS: tmate_debug("Auth successful"); client->state = SSH_OPEN_CHANNEL; + + client->channel = channel = ssh_channel_new(session); + if (!channel) { + tmate_fatal("cannot initialize"); + return; + } /* fall through */ } From e25ab3cc8bb4d42b137625b376d677707bc4fbe2 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Tue, 30 Jul 2019 14:48:37 +0200 Subject: [PATCH 089/150] ssh-client: Add missing ecdsa keytypes of libssh 0.9 --- tmate-ssh-client.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tmate-ssh-client.c b/tmate-ssh-client.c index 2a9afee0..943ebf49 100644 --- a/tmate-ssh-client.c +++ b/tmate-ssh-client.c @@ -218,7 +218,7 @@ static void on_ssh_client_event(struct tmate_ssh_client *client) { char *identity; ssh_key pubkey; - int key_type; + enum ssh_keytypes_e key_type; unsigned char *hash; ssize_t hash_len; char *hash_str; @@ -304,6 +304,11 @@ static void on_ssh_client_event(struct tmate_ssh_client *client) "tmate-server-rsa-fingerprint"); break; case SSH_KEYTYPE_ECDSA: +#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 9, 0) + case SSH_KEYTYPE_ECDSA_P256: + case SSH_KEYTYPE_ECDSA_P384: + case SSH_KEYTYPE_ECDSA_P521: +#endif server_hash_str = options_get_string(global_options, "tmate-server-ecdsa-fingerprint"); break; From 4e7caeb536629fc4ddc4d413ca867f754b1257c3 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Tue, 30 Jul 2019 15:37:35 +0200 Subject: [PATCH 090/150] ssh-client: Use ssh_get_server_publickey() if possible --- tmate-ssh-client.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tmate-ssh-client.c b/tmate-ssh-client.c index 943ebf49..c5fb4243 100644 --- a/tmate-ssh-client.c +++ b/tmate-ssh-client.c @@ -282,8 +282,13 @@ static void on_ssh_client_event(struct tmate_ssh_client *client) } case SSH_AUTH_SERVER: +#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 9, 0) + if (ssh_get_server_publickey(session, &pubkey) < 0) + tmate_fatal("ssh_get_server_publickey"); +#else if (ssh_get_publickey(session, &pubkey) < 0) tmate_fatal("ssh_get_publickey"); +#endif if (ssh_get_publickey_hash(pubkey, SSH_PUBLICKEY_HASH_SHA256, &hash, &hash_len) < 0) { From 3e5d919b14e8f5c6aa703e45092247c4a737194e Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Wed, 31 Jul 2019 21:02:18 -0400 Subject: [PATCH 091/150] Bump to version 2.3.0 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 8c6c5b98..647ae333 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ # configure.ac -AC_INIT(tmate, 2.2.1) +AC_INIT(tmate, 2.3.0) AC_CONFIG_AUX_DIR(etc) AM_INIT_AUTOMAKE([foreign subdir-objects]) From d654ff22194bde5fc6e02b2f93ae55cb69c4ddcc Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Wed, 18 Sep 2019 23:35:07 -0400 Subject: [PATCH 092/150] Send TMATE_READY message when the config files are done loading This fixes bug where webhooks are not registering correctly, leading to a disconnect and reconnect. --- server.c | 4 ---- tmate-session.c | 1 + 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/server.c b/server.c index 81334f1e..a2378959 100644 --- a/server.c +++ b/server.c @@ -205,10 +205,6 @@ server_start(struct event_base *base, int lockfd, char *lockfile) status_prompt_load_history(); -#ifdef TMATE - tmate_write_ready(); -#endif - server_add_accept(0); proc_loop(server_proc, server_loop); diff --git a/tmate-session.c b/tmate-session.c index 8d647203..106687e1 100644 --- a/tmate-session.c +++ b/tmate-session.c @@ -138,6 +138,7 @@ void tmate_session_start(void) * - While we are parsing the config file, we need to be able to * serialize it, and so we need a worker encoder. */ + tmate_write_ready(); lookup_and_connect(); } From 44635e752d17993943885c1e77864f5395d740f6 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sat, 12 Oct 2019 13:50:27 -0400 Subject: [PATCH 093/150] Use docker to build static releases Static builds are possible with the musl C library. glibc is capricious when it comes to static linking and DNS support (and other things). --- Dockerfile | 27 +++++++++++++++++++ Makefile.static-build | 61 ------------------------------------------ compat/clock_gettime.c | 9 ------- compat/memcpy.c | 11 -------- configure.ac | 15 ++--------- 5 files changed, 29 insertions(+), 94 deletions(-) create mode 100644 Dockerfile delete mode 100644 Makefile.static-build delete mode 100644 compat/clock_gettime.c delete mode 100644 compat/memcpy.c diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..82d75ef4 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,27 @@ +FROM alpine:3.10 + +WORKDIR /build + +RUN apk add --no-cache wget cmake make gcc g++ linux-headers zlib-dev openssl-dev \ + automake autoconf libevent-dev ncurses-dev msgpack-c-dev libexecinfo-dev \ + ncurses-static libexecinfo-static libevent-static msgpack-c ncurses-libs \ + libevent libexecinfo openssl zlib + +RUN set -ex; \ + mkdir -p /src/libssh/build; \ + cd /src; \ + wget -O libssh.tar.xz https://www.libssh.org/files/0.9/libssh-0.9.0.tar.xz; \ + tar -xf libssh.tar.xz -C /src/libssh --strip-components=1; \ + cd /src/libssh/build; \ + cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr \ + -DWITH_SFTP=OFF -DWITH_SERVER=OFF -DWITH_PCAP=OFF \ + -DWITH_STATIC_LIB=ON -DWITH_GSSAPI=OFF ..; \ + make -j $(nproc); \ + make install + +COPY . . + +RUN ./autogen.sh +RUN ./configure --enable-static +RUN make -j $(nproc) +RUN strip tmate diff --git a/Makefile.static-build b/Makefile.static-build deleted file mode 100644 index 9bc83d92..00000000 --- a/Makefile.static-build +++ /dev/null @@ -1,61 +0,0 @@ -LIBSSH=libssh-0.7.2 -LIBSSH_URL=https://red.libssh.org/attachments/download/177/$(LIBSSH).tar.xz -LIBSSH_LIB=ext/lib/libssh.a - -MSGPACK=msgpack-1.3.0 -MSGPACK_URL=https://github.com/msgpack/msgpack-c/releases/download/cpp-1.3.0/$(MSGPACK).tar.gz -MSGPACK_LIB=ext/lib/libmsgpack.a - -TMATE_CONFIGURE=PKG_CONFIG_PATH=./ext/lib/pkgconfig - -LIBC=$(shell gcc -print-file-name=libc.a) -STATIC_LIBC_OBJECTS=fdelt_chk -STATIC_COMPAT_OBJECTS=memcpy clock_gettime - -all: tmate - -dependencies: - apt-get install build-essential cmake libssl-dev autoconf automake pkg-config libtool libevent-dev libncurses-dev zlib1g-dev - -downloads/$(notdir $(LIBSSH_URL)): - mkdir -p downloads - wget -O $@ $(LIBSSH_URL) - -$(LIBSSH)/.ready: downloads/$(notdir $(LIBSSH_URL)) - tar xf $< - touch $@ - -downloads/$(notdir $(MSGPACK_URL)): - mkdir -p downloads - wget -O $@ $(MSGPACK_URL) - -$(MSGPACK)/.ready: downloads/$(notdir $(MSGPACK_URL)) - tar xf $< - touch $@ - -$(LIBSSH_LIB): $(LIBSSH)/.ready - mkdir -p $(LIBSSH)/build - cd $(LIBSSH)/build; ([ -f Makefile ] || cmake -DCMAKE_INSTALL_PREFIX:PATH=$(shell pwd)/ext .. -DWITH_SFTP=OFF -DWITH_SERVER=OFF -DWITH_PCAP=OFF -DWITH_STATIC_LIB=ON -DWITH_GSSAPI=OFF) - +make -C $(LIBSSH)/build install - -$(MSGPACK_LIB): $(MSGPACK)/.ready - mkdir -p $(MSGPACK)/build - cd $(MSGPACK)/build; ([ -f Makefile ] || cmake -DCMAKE_INSTALL_PREFIX:PATH=$(shell pwd)/ext ..) - +make -C $(MSGPACK)/build install - -libc/%.o: - mkdir -p libc - cd libc; ar x $(LIBC) $(notdir $@) - -compat/%.o: compat/%.c - gcc -c -o $@ $< - -tmate: $(MSGPACK_LIB) $(LIBSSH_LIB) $(patsubst %,libc/%.o,$(STATIC_LIBC_OBJECTS)) $(patsubst %,compat/%.o,$(STATIC_COMPAT_OBJECTS)) - ./autogen.sh - $(TMATE_CONFIGURE) ./configure --enable-static - +make - strip tmate - -clean: - rm -rf ext libc $(LIBSSH) $(MSGPACK) - +make clean diff --git a/compat/clock_gettime.c b/compat/clock_gettime.c deleted file mode 100644 index 0b631b79..00000000 --- a/compat/clock_gettime.c +++ /dev/null @@ -1,9 +0,0 @@ -#define _GNU_SOURCE -#include -#include -#include - -int clock_gettime(clockid_t clk_id, struct timespec *tp) -{ - return syscall(SYS_clock_gettime, clk_id, tp); -} diff --git a/compat/memcpy.c b/compat/memcpy.c deleted file mode 100644 index 37092a33..00000000 --- a/compat/memcpy.c +++ /dev/null @@ -1,11 +0,0 @@ -// http://stackoverflow.com/questions/8823267/linking-against-older-symbol-version-in-a-so-file - -#include - -/* some systems do not have newest memcpy@@GLIBC_2.14 - stay with old good one */ -asm (".symver memcpy, memcpy@GLIBC_2.2.5"); - -void *__wrap_memcpy(void *dest, const void *src, size_t n) -{ - return memcpy(dest, src, n); -} diff --git a/configure.ac b/configure.ac index 647ae333..2681300a 100644 --- a/configure.ac +++ b/configure.ac @@ -47,10 +47,11 @@ AC_ARG_ENABLE( found_static=$enable_static ) if test "x$found_static" = xyes; then + # XXX Static build are only doable with the musl library PKG_CONFIG="pkg-config --static" CFLAGS="$CFLAGS -flto" - LDFLAGS="$LDFLAGS -flto" + LDFLAGS="$LDFLAGS -flto -static -no-pie" PKG_CHECK_MODULES([ZLIB], [zlib], [ CPPFLAGS="$ZLIB_CFLAGS $CPPFLAGS" @@ -61,7 +62,6 @@ if test "x$found_static" = xyes; then CPPFLAGS="$LIBCRYPTO_CFLAGS $CPPFLAGS" LIBS="$LIBCRYPTO_LIBS $LIBS" ]) - # See more static settings below... (search for found_static) fi # Is this gcc? @@ -462,17 +462,6 @@ if test "x$found_getopt" != xno; then fi AM_CONDITIONAL(NO_GETOPT, [test "x$found_getopt" = xno]) -if test "x$found_static" = xyes; then - # libc and libdl should be dynamically linked. - # but we want to lower our requirements for libc's version. - # so we extract some symobls and add them here - if test `uname -m` = x86_64; then - LIBS="compat/memcpy.o -Wl,--wrap=memcpy $LIBS" - fi - LIBS="compat/clock_gettime.o libc/fdelt_chk.o $LIBS" - LIBS="-Wl,-Bstatic ${LIBS/-ldl/} -Wl,-Bdynamic -ldl" -fi - # Check for BSD-style integer types. AC_MSG_CHECKING(for BSD-style unsigned types) AC_COMPILE_IFELSE([AC_LANG_SOURCE( From 74ff5229830afcca8cd57976a48632fef6f85c17 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sat, 12 Oct 2019 14:13:12 -0400 Subject: [PATCH 094/150] Build static build releases on travis-ci --- .travis.yml | 42 ++++++++++++++++++++++++++++++++++-------- Dockerfile | 27 ++++++++++++++------------- package_release.sh | 14 ++++++++++++++ 3 files changed, 62 insertions(+), 21 deletions(-) create mode 100755 package_release.sh diff --git a/.travis.yml b/.travis.yml index a1d7e427..a02e89a8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,36 @@ language: c +services: +- docker + matrix: - include: - - compiler: gcc - - compiler: clang - env: CFLAGS="-g -O2" -before_install: - - sudo apt-get update -qq - - sudo apt-get -y install debhelper autotools-dev dh-autoreconf file libncurses5-dev libevent-dev pkg-config libutempter-dev build-essential -script: (CFLAGS= ./autogen.sh) && ./configure --enable-debug && make + include: + - arch: amd64 + env: PLATFORM=amd64 + - arch: amd64 + env: PLATFORM=i386 + - arch: arm64 + env: PLATFORM=arm32v6 + - arch: arm64 + env: PLATFORM=arm32v7 + - arch: arm64 + env: PLATFORM=arm64v8 + +script: +- 'docker build . --tag local-$PLATFORM/tmate-build --build-arg PLATFORM=$PLATFORM' +# On arch=arm64, some directories are not setup correctly, and 'ruby -S gem +# install dpl' required by the release push scripts fails. +- 'if [ "$TRAVIS_TAG" ]; then sudo chown -R $USER: /var/lib/gems /usr/local/bin; fi' +- 'if [ "$TRAVIS_TAG" ]; then ./package_release.sh $TRAVIS_TAG $PLATFORM; fi' + +deploy: + provider: releases + api_key: + secure: T2109tjjOsrVLEpJZK/uxmO0AuDGXYFdN4AAsNTmVwu/W5dcX57Kk2TCgqDuLfD21iGGXP0U/OYHM06IfBDODBWCA9P8ASHYsenS7wIiFnvCEMbfzoAFyBMrXN2kNdM2+ho3aqc0xE2lQKOKDLxpGm5FZrzujscXXzxQjWBU5Hk= + skip_cleanup: true + overwrite: true + file_glob: true + file: /tmp/tmate-release/*.tar.* + on: + repo: tmate-io/tmate + branch: master + tags: true diff --git a/Dockerfile b/Dockerfile index 82d75ef4..c7aa2b9f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,5 @@ -FROM alpine:3.10 +ARG PLATFORM=amd64 +FROM ${PLATFORM}/alpine:3.10 WORKDIR /build @@ -8,20 +9,20 @@ RUN apk add --no-cache wget cmake make gcc g++ linux-headers zlib-dev openssl-de libevent libexecinfo openssl zlib RUN set -ex; \ - mkdir -p /src/libssh/build; \ - cd /src; \ - wget -O libssh.tar.xz https://www.libssh.org/files/0.9/libssh-0.9.0.tar.xz; \ - tar -xf libssh.tar.xz -C /src/libssh --strip-components=1; \ - cd /src/libssh/build; \ - cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr \ - -DWITH_SFTP=OFF -DWITH_SERVER=OFF -DWITH_PCAP=OFF \ - -DWITH_STATIC_LIB=ON -DWITH_GSSAPI=OFF ..; \ - make -j $(nproc); \ - make install + mkdir -p /src/libssh/build; \ + cd /src; \ + wget -O libssh.tar.xz https://www.libssh.org/files/0.9/libssh-0.9.0.tar.xz; \ + tar -xf libssh.tar.xz -C /src/libssh --strip-components=1; \ + cd /src/libssh/build; \ + cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr \ + -DWITH_SFTP=OFF -DWITH_SERVER=OFF -DWITH_PCAP=OFF \ + -DWITH_STATIC_LIB=ON -DWITH_GSSAPI=OFF ..; \ + make -j $(nproc); \ + make install COPY . . -RUN ./autogen.sh -RUN ./configure --enable-static +RUN ./autogen.sh && ./configure --enable-static RUN make -j $(nproc) RUN strip tmate +RUN ./tmate -V diff --git a/package_release.sh b/package_release.sh new file mode 100755 index 00000000..f4186e3c --- /dev/null +++ b/package_release.sh @@ -0,0 +1,14 @@ +#!/bin/bash +set -eux +VERSION=$1 +PLATFORM=$2 +RELEASE_NAME=tmate-$VERSION-static-linux-$PLATFORM + +# This assumes the follow command has already been run: +# docker build . --tag local-$PLATFORM/tmate-build --build-arg PLATFORM=$PLATFORM + +mkdir -p /tmp/tmate-release/$RELEASE_NAME +cd /tmp/tmate-release +docker run --rm local-$PLATFORM/tmate-build cat tmate > $RELEASE_NAME/tmate +chmod +x $RELEASE_NAME/tmate +tar -cf - $RELEASE_NAME | xz > tmate-$VERSION-static-linux-$PLATFORM.tar.xz From 7153958e9908658383438745592d9a8da64b2a3f Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sat, 12 Oct 2019 21:09:39 -0400 Subject: [PATCH 095/150] Allow the use of C.UTF-8 locale --- tmux.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tmux.c b/tmux.c index d55c2e1d..d7cf8d97 100644 --- a/tmux.c +++ b/tmux.c @@ -205,12 +205,12 @@ main(int argc, char **argv) const char *s; int opt, flags, keys; - if (setlocale(LC_CTYPE, "en_US.UTF-8") == NULL) { + if (setlocale(LC_CTYPE, "en_US.UTF-8") == NULL && + setlocale(LC_CTYPE, "C.UTF-8") == NULL) { if (setlocale(LC_CTYPE, "") == NULL) errx(1, "invalid LC_ALL, LC_CTYPE or LANG"); s = nl_langinfo(CODESET); - if (strcasecmp(s, "UTF-8") != 0 && - strcasecmp(s, "UTF8") != 0) + if (strcasecmp(s, "UTF-8") != 0 && strcasecmp(s, "UTF8") != 0) errx(1, "need UTF-8 locale (LC_CTYPE) but have %s", s); } From 7262aead737af678923ae7b9209ae220b0f915b9 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sat, 12 Oct 2019 19:29:48 -0400 Subject: [PATCH 096/150] Bump to version 2.3.1 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 2681300a..f623cadc 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ # configure.ac -AC_INIT(tmate, 2.3.0) +AC_INIT(tmate, 2.3.1) AC_CONFIG_AUX_DIR(etc) AM_INIT_AUTOMAKE([foreign subdir-objects]) From 4efe25d91d5c5de0fcb4df2cf9199a96b13afd66 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Tue, 15 Oct 2019 03:04:24 -0400 Subject: [PATCH 097/150] During SSH authentication, try the none auth method first --- tmate-ssh-client.c | 44 ++++++++++++++++++++++++++++++++------------ tmate.h | 4 +++- 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/tmate-ssh-client.c b/tmate-ssh-client.c index c5fb4243..e33f4b17 100644 --- a/tmate-ssh-client.c +++ b/tmate-ssh-client.c @@ -235,7 +235,7 @@ static void on_ssh_client_event(struct tmate_ssh_client *client) case SSH_INIT: client->session = session = ssh_new(); if (!session) { - tmate_fatal("cannot initialize"); + tmate_fatal("cannot ssh_new()"); return; } @@ -344,13 +344,30 @@ static void on_ssh_client_event(struct tmate_ssh_client *client) */ tmate_debug("Connected to %s", client->server_ip); on_ssh_auth_server_complete(client); - client->state = SSH_AUTH_CLIENT; + client->state = SSH_AUTH_CLIENT_NONE; /* fall through */ - case SSH_AUTH_CLIENT: + case SSH_AUTH_CLIENT_NONE: + switch (ssh_userauth_none(session, NULL)) { + case SSH_AUTH_AGAIN: + return; + case SSH_AUTH_ERROR: + kill_ssh_client(client, "Auth error: %s", ssh_get_error(session)); + return; + case SSH_AUTH_SUCCESS: + tmate_debug("Auth successful via none method"); + client->state = SSH_NEW_CHANNEL; + goto SSH_NEW_CHANNEL; + case SSH_AUTH_PARTIAL: + case SSH_AUTH_DENIED: + client->state = SSH_AUTH_CLIENT_PUBKEY; + /* fall through */ + } + + case SSH_AUTH_CLIENT_PUBKEY: client->tried_passphrase = client->tmate_session->passphrase; - switch (ssh_userauth_autopubkey(session, client->tried_passphrase)) { + switch (ssh_userauth_publickey_auto(session, NULL, client->tried_passphrase)) { case SSH_AUTH_AGAIN: return; case SSH_AUTH_PARTIAL: @@ -372,17 +389,20 @@ static void on_ssh_client_event(struct tmate_ssh_client *client) kill_ssh_client(client, "Auth error: %s", ssh_get_error(session)); return; case SSH_AUTH_SUCCESS: - tmate_debug("Auth successful"); - client->state = SSH_OPEN_CHANNEL; - - client->channel = channel = ssh_channel_new(session); - if (!channel) { - tmate_fatal("cannot initialize"); - return; - } + tmate_debug("Auth successful with pubkey"); + client->state = SSH_NEW_CHANNEL; /* fall through */ } +SSH_NEW_CHANNEL: + case SSH_NEW_CHANNEL: + client->channel = channel = ssh_channel_new(session); + if (!channel) { + tmate_fatal("cannot ssh_channel_new()"); + return; + } + client->state = SSH_OPEN_CHANNEL; + case SSH_OPEN_CHANNEL: switch (ssh_channel_open_session(channel)) { case SSH_AGAIN: diff --git a/tmate.h b/tmate.h index f096a35c..7deb0ba6 100644 --- a/tmate.h +++ b/tmate.h @@ -106,7 +106,9 @@ enum tmate_ssh_client_state_types { SSH_INIT, SSH_CONNECT, SSH_AUTH_SERVER, - SSH_AUTH_CLIENT, + SSH_AUTH_CLIENT_NONE, + SSH_AUTH_CLIENT_PUBKEY, + SSH_NEW_CHANNEL, SSH_OPEN_CHANNEL, SSH_BOOTSTRAP, SSH_READY, From 7f693a97aede385aad30db1412c48f0093b72509 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sun, 20 Oct 2019 21:23:48 -0400 Subject: [PATCH 098/150] Add options for customizing session names (WIP) --- options-table.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/options-table.c b/options-table.c index 4966431c..617ba05e 100644 --- a/options-table.c +++ b/options-table.c @@ -959,6 +959,24 @@ const struct options_table_entry options_table[] = { .scope = OPTIONS_TABLE_SERVER, .default_str = "" }, + + { .name = "tmate-account-key", + .type = OPTIONS_TABLE_STRING, + .scope = OPTIONS_TABLE_SERVER, + .default_str = "" + }, + + { .name = "tmate-session-name", + .type = OPTIONS_TABLE_STRING, + .scope = OPTIONS_TABLE_SERVER, + .default_str = "" + }, + + { .name = "tmate-session-name-ro", + .type = OPTIONS_TABLE_STRING, + .scope = OPTIONS_TABLE_SERVER, + .default_str = "" + }, #endif { .name = NULL } From 6e84bab68ca80f90023d4336467a44098d17a06f Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sun, 3 Nov 2019 05:11:37 -0500 Subject: [PATCH 099/150] Add foreground mode with -F --- cfg.c | 18 ++++++++++++++++ client.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++ cmd-new-session.c | 3 +++ log.c | 49 +++++++++++++++++++++++++++++++------------- proc.c | 10 +++++++-- server.c | 14 ++++++++++--- session.c | 21 +++++++++++++++---- signal.c | 18 ++++++++++++++++ tmate-msg.c | 2 +- tmate-session.c | 2 +- tmate-ssh-client.c | 14 +++++++------ tmate.h | 7 +++---- tmux.c | 13 ++++++++++-- tmux.h | 12 ++++++++++- 14 files changed, 196 insertions(+), 38 deletions(-) diff --git a/cfg.c b/cfg.c index 572f8369..68894cb2 100644 --- a/cfg.c +++ b/cfg.c @@ -149,6 +149,20 @@ load_cfg(const char *path, struct cmd_q *cmdq, char **cause) return (found); } +static void print_cfg_errors(void) +{ + u_int i; + + for (i = 0; i < cfg_ncauses; i++) { + tmate_info("%s", cfg_causes[i]); + free(cfg_causes[i]); + } + + free(cfg_causes); + cfg_causes = NULL; + cfg_ncauses = 0; +} + void cfg_default_done(__unused struct cmd_q *cmdq) { @@ -158,6 +172,10 @@ cfg_default_done(__unused struct cmd_q *cmdq) #ifdef TMATE tmate_session_start(); + if (tmate_foreground && cfg_ncauses) { + print_cfg_errors(); + exit(1); + } #endif if (!RB_EMPTY(&sessions)) diff --git a/client.c b/client.c index 164abdd3..ad349972 100644 --- a/client.c +++ b/client.c @@ -32,6 +32,7 @@ #include #include "tmux.h" +#include "tmate.h" struct tmuxproc *client_proc; struct tmuxpeer *client_peer; @@ -213,8 +214,56 @@ client_exit_message(void) #ifdef TMATE extern const struct cmd_entry cmd_attach_session_entry; extern const struct cmd_entry cmd_new_session_entry; + +/* For foreground mode */ +static int __argc; +static char **__argv; #endif +static void _run_initial_client_cmd(int argc, char **argv) +{ + struct cmd_q *cmd_q; + struct cmd_list *cmdlist; + char *cause; + const char *default_argv[] = {"new-session"}; + + if (argc == 0) { + argc = 1; + argv = (char **)default_argv; + } + + cmd_q = cmdq_new(NULL); /* No client */ + + if ((cmdlist = cmd_list_parse(argc, (char **)argv, NULL, 0, &cause)) == NULL) { + tmate_fatal("%s", cause); + } + + cmdq_run(cmd_q, cmdlist, NULL); + cmd_list_free(cmdlist); + cmdq_free(cmd_q); + + /* error messages land in cfg_causes */ + extern char **cfg_causes; + extern u_int cfg_ncauses; + int has_error = !!cfg_ncauses; + for (u_int i = 0; i < cfg_ncauses; i++) { + tmate_info("%s", cfg_causes[i]); + free(cfg_causes[i]); + } + + free(cfg_causes); + cfg_causes = NULL; + cfg_ncauses = 0; + + if (has_error) + exit(1); +} + +void run_initial_client_cmd(void) +{ + _run_initial_client_cmd(__argc, __argv); +} + /* Client main loop. */ int client_main(struct event_base *base, int argc, char **argv, int flags, @@ -232,6 +281,8 @@ client_main(struct event_base *base, int argc, char **argv, int flags, size_t size; #ifdef TMATE int cant_nest = 0; + __argc = argc; + __argv = argv; #endif /* Ignore SIGCHLD now or daemon() in the server will leave a zombie. */ diff --git a/cmd-new-session.c b/cmd-new-session.c index 357ffed1..fb2f7eab 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -131,6 +131,9 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) if (c == NULL) detached = 1; + if (tmate_foreground) + detached = 1; + /* Is this client already attached? */ already_attached = 0; if (c != NULL && c->session != NULL) diff --git a/log.c b/log.c index 018348cf..bc798778 100644 --- a/log.c +++ b/log.c @@ -32,6 +32,11 @@ static int log_level; static void log_event_cb(int, const char *); static void log_vwrite(const char *, va_list); +static int is_log_stdout(void) +{ + return fileno(log_file) <= 2; +} + /* Log callback for libevent. */ static void log_event_cb(__unused int severity, const char *msg) @@ -53,6 +58,18 @@ log_get_level(void) return (log_level); } +void +log_open_fp(FILE *f) +{ + if (log_file != NULL && !is_log_stdout()) + fclose(log_file); + + log_file = f; + + setvbuf(log_file, NULL, _IOLBF, 0); + event_set_log_callback(log_event_cb); +} + /* Open logging to file. */ void log_open(const char *name) @@ -62,24 +79,18 @@ log_open(const char *name) if (log_level == 0) return; - if (log_file != NULL) - fclose(log_file); - xasprintf(&path, "tmate-%s-%ld.log", name, (long)getpid()); - log_file = fopen(path, "w"); + FILE *f = fopen(path, "w"); free(path); - if (log_file == NULL) - return; - - setvbuf(log_file, NULL, _IOLBF, 0); - event_set_log_callback(log_event_cb); + if (f) + log_open_fp(f); } /* Close logging. */ void log_close(void) { - if (log_file != NULL) + if (log_file != NULL && !is_log_stdout()) fclose(log_file); log_file = NULL; @@ -102,9 +113,16 @@ log_vwrite(const char *msg, va_list ap) exit(1); gettimeofday(&tv, NULL); - if (fprintf(log_file, "%lld.%06d %s\n", (long long)tv.tv_sec, - (int)tv.tv_usec, out) == -1) - exit(1); + + if (is_log_stdout()) { + if (fprintf(log_file, "%s\n", out) == -1) + exit(1); + } else { + if (fprintf(log_file, "%lld.%06d %s\n", (long long)tv.tv_sec, + (int)tv.tv_usec, out) == -1) + exit(1); + } + fflush(log_file); free(out); @@ -113,10 +131,13 @@ log_vwrite(const char *msg, va_list ap) /* Log a debug message. */ void -log_debug(const char *msg, ...) +log_emit(int level, const char *msg, ...) { va_list ap; + if (log_level < level) + return; + va_start(ap, msg); log_vwrite(msg, ap); va_end(ap); diff --git a/proc.c b/proc.c index 27880f57..edd4a6f8 100644 --- a/proc.c +++ b/proc.c @@ -172,7 +172,7 @@ proc_start(const char *name, struct event_base *base, int forkflag, struct tmuxproc *tp; struct utsname u; - if (forkflag) { + if (forkflag && !tmate_foreground) { switch (fork()) { case -1: fatal("fork failed"); @@ -189,7 +189,13 @@ proc_start(const char *name, struct event_base *base, int forkflag, fatalx("event_reinit failed"); } - log_open(name); + if (tmate_foreground) { + if (forkflag) + clear_signals(0); + log_open_fp(stdout); + } else { + log_open(name); + } #ifdef HAVE_SETPROCTITLE setproctitle("%s (%s)", name, socket_path); diff --git a/server.c b/server.c index a2378959..05706769 100644 --- a/server.c +++ b/server.c @@ -152,14 +152,16 @@ server_start(struct event_base *base, int lockfd, char *lockfile) { int pair[2]; - if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0) - fatal("socketpair failed"); + if (!tmate_foreground) + if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0) + fatal("socketpair failed"); server_proc = proc_start("server", base, 1, server_signal); if (server_proc == NULL) { close(pair[1]); return (pair[0]); } + close(pair[0]); if (log_get_level() > 3) @@ -190,7 +192,8 @@ server_start(struct event_base *base, int lockfd, char *lockfile) if (server_fd == -1) fatal("couldn't create socket"); server_update_socket(); - server_client_create(pair[1]); + if (!tmate_foreground) + server_client_create(pair[1]); if (lockfd >= 0) { unlink(lockfile); @@ -207,11 +210,15 @@ server_start(struct event_base *base, int lockfd, char *lockfile) server_add_accept(0); + if (tmate_foreground) + run_initial_client_cmd(); + proc_loop(server_proc, server_loop); status_prompt_save_history(); #ifdef TMATE unlink(socket_path); #endif + exit(0); } @@ -361,6 +368,7 @@ server_signal(int sig) int fd; switch (sig) { + case SIGINT: case SIGTERM: server_exit = 1; server_send_exit(); diff --git a/session.c b/session.c index 5a3b867a..91fb9c1d 100644 --- a/session.c +++ b/session.c @@ -215,10 +215,6 @@ session_destroy(struct session *s) log_debug("session %s destroyed", s->name); -#ifdef TMATE - tmate_write_fin(); -#endif - RB_REMOVE(sessions, &sessions, s); notify_session_closed(s); @@ -240,6 +236,23 @@ session_destroy(struct session *s) free((void *)s->cwd); session_unref(s); + +#ifdef TMATE + if (tmate_foreground && !server_exit) { + tmate_info("Shell exited, restarting"); + /* + * throttle restarts. This is a blocking sleep. + * It's simpler than using a timer, but fairly harmless + * from a blocking perspective. + */ + usleep(500*1000); + next_session_id = 0; + run_initial_client_cmd(); + } else { + tmate_info("Session terminated"); + tmate_write_fin(); + } +#endif } /* Check a session name is valid: not empty and no colons or periods. */ diff --git a/signal.c b/signal.c index 19938638..f20a0257 100644 --- a/signal.c +++ b/signal.c @@ -24,6 +24,7 @@ #include "tmux.h" +struct event ev_sigint; struct event ev_sighup; struct event ev_sigchld; struct event ev_sigcont; @@ -40,15 +41,23 @@ set_signals(void (*handler)(int, short, void *), void *arg) sigemptyset(&sigact.sa_mask); sigact.sa_flags = SA_RESTART; sigact.sa_handler = SIG_IGN; +#ifndef TMATE if (sigaction(SIGINT, &sigact, NULL) != 0) fatal("sigaction failed"); +#endif if (sigaction(SIGPIPE, &sigact, NULL) != 0) fatal("sigaction failed"); if (sigaction(SIGUSR2, &sigact, NULL) != 0) fatal("sigaction failed"); +#ifndef TMATE if (sigaction(SIGTSTP, &sigact, NULL) != 0) fatal("sigaction failed"); +#endif +#ifdef TMATE + signal_set(&ev_sigint, SIGINT, handler, arg); + signal_add(&ev_sigint, NULL); +#endif signal_set(&ev_sighup, SIGHUP, handler, arg); signal_add(&ev_sighup, NULL); signal_set(&ev_sigchld, SIGCHLD, handler, arg); @@ -72,16 +81,24 @@ clear_signals(int after_fork) sigemptyset(&sigact.sa_mask); sigact.sa_flags = SA_RESTART; sigact.sa_handler = SIG_DFL; +#ifndef TMATE if (sigaction(SIGINT, &sigact, NULL) != 0) fatal("sigaction failed"); +#endif if (sigaction(SIGPIPE, &sigact, NULL) != 0) fatal("sigaction failed"); if (sigaction(SIGUSR2, &sigact, NULL) != 0) fatal("sigaction failed"); +#ifndef TMATE if (sigaction(SIGTSTP, &sigact, NULL) != 0) fatal("sigaction failed"); +#endif if (after_fork) { +#ifdef TMATE + if (sigaction(SIGINT, &sigact, NULL) != 0) + fatal("sigaction failed"); +#endif if (sigaction(SIGHUP, &sigact, NULL) != 0) fatal("sigaction failed"); if (sigaction(SIGCHLD, &sigact, NULL) != 0) @@ -95,6 +112,7 @@ clear_signals(int after_fork) if (sigaction(SIGWINCH, &sigact, NULL) != 0) fatal("sigaction failed"); } else { + event_del(&ev_sigint); event_del(&ev_sighup); event_del(&ev_sigchld); event_del(&ev_sigcont); diff --git a/tmate-msg.c b/tmate-msg.c index 880e3905..a47f9e4d 100644 --- a/tmate-msg.c +++ b/tmate-msg.c @@ -56,7 +56,7 @@ void __tmate_status_message(const char *fmt, va_list ap) char *message; xvasprintf(&message, fmt, ap); - tmate_debug("%s", message); + tmate_info("%s", message); TAILQ_FOREACH(c, &clients, entry) { if (c && !(c->flags & CLIENT_READONLY)) diff --git a/tmate-session.c b/tmate-session.c index 106687e1..5ab13511 100644 --- a/tmate-session.c +++ b/tmate-session.c @@ -96,7 +96,7 @@ static void lookup_and_connect(void) tmate_server_host = options_get_string(global_options, "tmate-server-host"); - tmate_info("Looking up %s...", tmate_server_host); + tmate_debug("Looking up %s...", tmate_server_host); (void)evdns_getaddrinfo(tmate_session.ev_dnsbase, tmate_server_host, NULL, &hints, dns_cb, (void *)tmate_server_host); } diff --git a/tmate-ssh-client.c b/tmate-ssh-client.c index e33f4b17..66eb1716 100644 --- a/tmate-ssh-client.c +++ b/tmate-ssh-client.c @@ -171,12 +171,12 @@ static void request_passphrase(struct tmate_ssh_client *client) #define KEEPALIVE_IDLE 20 #define KEEPALIVE_INTVL 10 -static void setup_socket(int fd) +static void tune_socket_opts(int fd) { #define SSO(level, optname, val) ({ \ int _flag = val; \ if (setsockopt(fd, level, optname, &(_flag), sizeof(int)) < 0) { \ - tmate_warn("setsockopt(" #level ", " #optname ", %d) failed", val); \ + tmate_debug("setsockopt(" #level ", " #optname ", %d) failed", val); \ } \ }) @@ -197,7 +197,7 @@ static void setup_socket(int fd) #undef SSO } -static void init_conn_fd(struct tmate_ssh_client *client) +static void init_conn_fd(struct tmate_ssh_client *client, bool tune_socket) { int fd; @@ -207,7 +207,9 @@ static void init_conn_fd(struct tmate_ssh_client *client) if ((fd = ssh_get_fd(client->session)) < 0) return; - setup_socket(fd); + if (tune_socket) + tune_socket_opts(fd); + event_set(&client->ev_ssh, fd, EV_READ | EV_PERSIST, __on_ssh_client_event, client); event_add(&client->ev_ssh, NULL); @@ -267,14 +269,14 @@ static void on_ssh_client_event(struct tmate_ssh_client *client) case SSH_CONNECT: switch (ssh_connect(session)) { case SSH_AGAIN: - init_conn_fd(client); + init_conn_fd(client, false); return; case SSH_ERROR: kill_ssh_client(client, "Error connecting: %s", ssh_get_error(session)); return; case SSH_OK: - init_conn_fd(client); + init_conn_fd(client, true); tmate_debug("Establishing connection to %s", client->server_ip); client->state = SSH_AUTH_SERVER; diff --git a/tmate.h b/tmate.h index 7deb0ba6..9bf8e975 100644 --- a/tmate.h +++ b/tmate.h @@ -9,10 +9,9 @@ #include "tmux.h" -#define tmate_debug(...) log_debug("[tmate] D " __VA_ARGS__) -#define tmate_warn(...) log_debug("[tmate] W " __VA_ARGS__) -#define tmate_info(...) log_debug("[tmate] I " __VA_ARGS__) -#define tmate_fatal(...) fatalx("[tmate] " __VA_ARGS__) +#define tmate_debug(...) log_emit(LOG_DEBUG, __VA_ARGS__) +#define tmate_info(...) log_emit(LOG_INFO, __VA_ARGS__) +#define tmate_fatal(...) fatalx( __VA_ARGS__) /* tmate-msgpack.c */ diff --git a/tmux.c b/tmux.c index d7cf8d97..60341f84 100644 --- a/tmux.c +++ b/tmux.c @@ -48,7 +48,11 @@ __dead void usage(void); static char *make_label(const char *); #ifndef HAVE___PROGNAME -char *__progname = (char *) "tmux"; +char *__progname = (char *) "tmate"; +#endif + +#ifdef TMATE +int tmate_foreground; #endif __dead void @@ -228,7 +232,7 @@ main(int argc, char **argv) #endif label = path = NULL; - while ((opt = getopt(argc, argv, "2c:Cdf:lL:qS:uUVv")) != -1) { + while ((opt = getopt(argc, argv, "2c:CdFf:lL:qS:uUVv")) != -1) { switch (opt) { case '2': flags |= CLIENT_256COLOURS; @@ -268,6 +272,11 @@ main(int argc, char **argv) case 'v': log_add_level(); break; + case 'F': + tmate_foreground = 1; + log_add_level(); + unsetenv("TMUX"); + break; default: usage(); } diff --git a/tmux.h b/tmux.h index 1ab784b7..3956e240 100644 --- a/tmux.h +++ b/tmux.h @@ -1549,6 +1549,9 @@ extern struct options *global_w_options; extern struct environ *global_environ; extern struct timeval start_time; extern const char *socket_path; +#ifdef TMATE +extern int tmate_foreground; +#endif const char *getshell(void); int checkshell(const char *); int areshell(const char *); @@ -1875,6 +1878,7 @@ void signal_waiting_clients(const char *name); void cmd_wait_for_flush(void); /* client.c */ +void run_initial_client_cmd(void); int client_main(struct event_base *, int, char **, int, const char *); /* key-bindings.c */ @@ -1902,6 +1906,7 @@ void alerts_queue(struct window *, int); void alerts_check_session(struct session *); /* server.c */ +extern int server_exit; extern struct tmuxproc *server_proc; extern struct clients clients; extern struct cmd_find_state marked_pane; @@ -2356,9 +2361,14 @@ struct event_base *osdep_event_init(void); /* log.c */ void log_add_level(void); int log_get_level(void); +void log_open_fp(FILE *f); void log_open(const char *); void log_close(void); -void printflike(1, 2) log_debug(const char *, ...); +#define LOG_ERROR 0 +#define LOG_INFO 1 +#define LOG_DEBUG 2 +#define log_debug(...) log_emit(LOG_DEBUG+1, __VA_ARGS__) +void printflike(2, 3) log_emit(int level, const char *, ...); __dead void printflike(1, 2) fatal(const char *, ...); __dead void printflike(1, 2) fatalx(const char *, ...); From c63c8fbf90ffdf7bc58a8f73428600ee29a6dcf5 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sun, 3 Nov 2019 18:15:27 -0500 Subject: [PATCH 100/150] Only use tmate.conf, not .tmux.conf Fixes #108 --- cfg.c | 16 +--------------- session.c | 2 +- tmux.c | 3 +-- 3 files changed, 3 insertions(+), 18 deletions(-) diff --git a/cfg.c b/cfg.c index 68894cb2..1fcbd0d6 100644 --- a/cfg.c +++ b/cfg.c @@ -71,7 +71,7 @@ start_cfg(void) cfg_add_cause("%s: %s", TMUX_CONF, strerror(errno)); if (cfg_file == NULL && (home = find_home()) != NULL) { - xasprintf(&cfg_file, "%s/.tmux.conf", home); + xasprintf(&cfg_file, "%s/.tmate.conf", home); if (access(cfg_file, R_OK) != 0 && errno == ENOENT) { free(cfg_file); cfg_file = NULL; @@ -81,20 +81,6 @@ start_cfg(void) cfg_add_cause("%s: %s", cfg_file, cause); free(cause); -#ifdef TMATE - cause = NULL; - if ((home = find_home()) != NULL) { - xasprintf(&tmate_cfg_file, "%s/.tmate.conf", home); - if (access(tmate_cfg_file, R_OK) != 0 && errno == ENOENT) { - free(tmate_cfg_file); - tmate_cfg_file = NULL; - } - } - if (tmate_cfg_file != NULL && load_cfg(tmate_cfg_file, cfg_cmd_q, &cause) == -1) - cfg_add_cause("%s: %s", cfg_file, cause); - free(cause); -#endif - cmdq_continue(cfg_cmd_q); } diff --git a/session.c b/session.c index 91fb9c1d..ab58ed9f 100644 --- a/session.c +++ b/session.c @@ -249,7 +249,7 @@ session_destroy(struct session *s) next_session_id = 0; run_initial_client_cmd(); } else { - tmate_info("Session terminated"); + tmate_info("Session closed"); tmate_write_fin(); } #endif diff --git a/tmux.c b/tmux.c index 60341f84..91ee316a 100644 --- a/tmux.c +++ b/tmux.c @@ -59,8 +59,7 @@ __dead void usage(void) { fprintf(stderr, - "usage: %s [-2CluvV] [-c shell-command] [-f file] [-L socket-name]\n" - " [-S socket-path] [command [flags]]\n", + "usage: %s [-vVF] [-f config-file] [-S socket-path] [command [flags]]\n", __progname); exit(1); } From c78198dc59f49e4998f36e31d289b7dd5450178f Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sun, 3 Nov 2019 22:40:41 -0500 Subject: [PATCH 101/150] Add command line arguments to set the account_key/session_names -k account_key -n session_name -r session_name_ro --- server.c | 1 + tmux.c | 35 ++++++++++++++++++++++++++++++++++- tmux.h | 1 + 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/server.c b/server.c index 05706769..f8f08d12 100644 --- a/server.c +++ b/server.c @@ -203,6 +203,7 @@ server_start(struct event_base *base, int lockfd, char *lockfile) #ifdef TMATE tmate_set_editor_mode(); + tmate_init_boot_options(); #endif start_cfg(); diff --git a/tmux.c b/tmux.c index 91ee316a..72c91d39 100644 --- a/tmux.c +++ b/tmux.c @@ -201,6 +201,30 @@ find_home(void) return (home); } +#ifdef TMATE +static char *account_key; +static char *session_name; +static char *session_name_ro; + +void tmate_init_boot_options(void) +{ + if (account_key) + tmate_exec_cmd_args(4, (const char *[]){"set-option", "-g", "tmate-account-key", account_key}); + if (session_name) + tmate_exec_cmd_args(4, (const char *[]){"set-option", "-g", "tmate-session-name", session_name}); + if (session_name_ro) + tmate_exec_cmd_args(4, (const char *[]){"set-option", "-g", "tmate-session-name-ro", session_name_ro}); + + free(account_key); + free(session_name); + free(session_name_ro); + + account_key = NULL; + session_name = NULL; + session_name_ro = NULL; +} +#endif + int main(int argc, char **argv) { @@ -231,7 +255,7 @@ main(int argc, char **argv) #endif label = path = NULL; - while ((opt = getopt(argc, argv, "2c:CdFf:lL:qS:uUVv")) != -1) { + while ((opt = getopt(argc, argv, "2c:CdFf:lL:qS:uUVvk:n:r:")) != -1) { switch (opt) { case '2': flags |= CLIENT_256COLOURS; @@ -276,6 +300,15 @@ main(int argc, char **argv) log_add_level(); unsetenv("TMUX"); break; + case 'k': + account_key = xstrdup(optarg); + break; + case 'n': + session_name = xstrdup(optarg); + break; + case 'r': + session_name_ro = xstrdup(optarg); + break; default: usage(); } diff --git a/tmux.h b/tmux.h index 3956e240..83a573c1 100644 --- a/tmux.h +++ b/tmux.h @@ -1551,6 +1551,7 @@ extern struct timeval start_time; extern const char *socket_path; #ifdef TMATE extern int tmate_foreground; +void tmate_init_boot_options(void); #endif const char *getshell(void); int checkshell(const char *); From 19341bc5444e7954da23ac06ac799c0fd80a160e Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Mon, 4 Nov 2019 16:43:59 -0500 Subject: [PATCH 102/150] Add authorized_keys option -a --- options-table.c | 12 ++++++++++++ tmate-encoder.c | 8 ++++++++ tmate-session.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ tmate.h | 1 + tmux.c | 10 +++++++++- 5 files changed, 75 insertions(+), 1 deletion(-) diff --git a/options-table.c b/options-table.c index 617ba05e..dd9f696e 100644 --- a/options-table.c +++ b/options-table.c @@ -977,6 +977,18 @@ const struct options_table_entry options_table[] = { .scope = OPTIONS_TABLE_SERVER, .default_str = "" }, + + { .name = "tmate-authorized-keys", + .type = OPTIONS_TABLE_STRING, + .scope = OPTIONS_TABLE_SERVER, + .default_str = "" + }, + + { .name = "tmate-set", + .type = OPTIONS_TABLE_STRING, + .scope = OPTIONS_TABLE_SERVER, + .default_str = "" + }, #endif { .name = NULL } diff --git a/tmate-encoder.c b/tmate-encoder.c index c15d8921..0040a3bf 100644 --- a/tmate-encoder.c +++ b/tmate-encoder.c @@ -238,6 +238,14 @@ void tmate_exec_cmd_args(int argc, const char **argv) append_saved_cmd(&tmate_session, argc, argv); } +void tmate_set_val(const char *name, const char *value) +{ + char *buf; + xasprintf(&buf, "%s=%s", name, value); + tmate_exec_cmd_args(3, (const char *[]){"set-option", "tmate-set", buf}); + free(buf); +} + void tmate_exec_cmd(struct cmd *cmd) { int argc; diff --git a/tmate-session.c b/tmate-session.c index 5ab13511..e3eb0c19 100644 --- a/tmate-session.c +++ b/tmate-session.c @@ -129,6 +129,50 @@ void tmate_session_init(struct event_base *base) tmate_write_header(); } +static void send_authorized_keys() +{ + char *path; + path = options_get_string(global_options, "tmate-authorized-keys"); + if (strlen(path) == 0) + return; + + path = xstrdup(path); + tmate_info("Using %s for access control", path); + + FILE *f; + char *line; + size_t len; + + if (path[0] == '~' && path[1] == '/') { + const char *home = find_home(); + if (home) { + char *new_path; + xasprintf(&new_path, "%s%s", home, &path[1]); + free(path); + path = new_path; + } + } + + if ((f = fopen(path, "r")) == NULL) { + cfg_add_cause("%s: %s", path, strerror(errno)); + free(path); + return; + } + + while ((line = fparseln(f, &len, NULL, NULL, 0)) != NULL) { + if (len == 0) + continue; + tmate_set_val("authorized_keys", line); + free(line); + } + + if (ferror(f)) + cfg_add_cause("%s: %s", path, strerror(errno)); + + fclose(f); + free(path); +} + void tmate_session_start(void) { /* @@ -138,6 +182,7 @@ void tmate_session_start(void) * - While we are parsing the config file, we need to be able to * serialize it, and so we need a worker encoder. */ + send_authorized_keys(); tmate_write_ready(); lookup_and_connect(); } diff --git a/tmate.h b/tmate.h index 9bf8e975..e1b9af47 100644 --- a/tmate.h +++ b/tmate.h @@ -83,6 +83,7 @@ extern void tmate_write_ready(void); extern void tmate_sync_layout(void); extern void tmate_pty_data(struct window_pane *wp, const char *buf, size_t len); extern int tmate_should_replicate_cmd(const struct cmd_entry *cmd); +extern void tmate_set_val(const char *name, const char *value); extern void tmate_exec_cmd_args(int argc, const char **argv); extern void tmate_exec_cmd(struct cmd *cmd); extern void tmate_failed_cmd(int client_id, const char *cause); diff --git a/tmux.c b/tmux.c index 72c91d39..90b46403 100644 --- a/tmux.c +++ b/tmux.c @@ -205,6 +205,7 @@ find_home(void) static char *account_key; static char *session_name; static char *session_name_ro; +static char *authorized_keys; void tmate_init_boot_options(void) { @@ -214,14 +215,18 @@ void tmate_init_boot_options(void) tmate_exec_cmd_args(4, (const char *[]){"set-option", "-g", "tmate-session-name", session_name}); if (session_name_ro) tmate_exec_cmd_args(4, (const char *[]){"set-option", "-g", "tmate-session-name-ro", session_name_ro}); + if (authorized_keys) + tmate_exec_cmd_args(4, (const char *[]){"set-option", "-g", "tmate-authorized-keys", authorized_keys}); free(account_key); free(session_name); free(session_name_ro); + free(authorized_keys_file); account_key = NULL; session_name = NULL; session_name_ro = NULL; + authorized_keys = NULL; } #endif @@ -255,7 +260,7 @@ main(int argc, char **argv) #endif label = path = NULL; - while ((opt = getopt(argc, argv, "2c:CdFf:lL:qS:uUVvk:n:r:")) != -1) { + while ((opt = getopt(argc, argv, "2c:CdFf:lL:qS:uUVvk:n:r:a:")) != -1) { switch (opt) { case '2': flags |= CLIENT_256COLOURS; @@ -309,6 +314,9 @@ main(int argc, char **argv) case 'r': session_name_ro = xstrdup(optarg); break; + case 'a': + authorized_keys = xstrdup(optarg); + break; default: usage(); } From 206c0f38b4c6d865b5294cc9ba66eb6b4a611100 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Mon, 4 Nov 2019 17:27:00 -0500 Subject: [PATCH 103/150] Set boot options via tmux commands --- cfg.c | 3 +++ client.c | 46 ++++++++++++++++++++++++++++++---------------- server.c | 1 - tmux.c | 32 +++++++++++++------------------- tmux.h | 4 +++- 5 files changed, 49 insertions(+), 37 deletions(-) diff --git a/cfg.c b/cfg.c index 1fcbd0d6..2410fbf9 100644 --- a/cfg.c +++ b/cfg.c @@ -157,6 +157,9 @@ cfg_default_done(__unused struct cmd_q *cmdq) cfg_finished = 1; #ifdef TMATE + /* We do it this late, this way, CLI options take precedence over cfg file */ + tmate_load_cli_options(); + tmate_session_start(); if (tmate_foreground && cfg_ncauses) { print_cfg_errors(); diff --git a/client.c b/client.c index ad349972..456fe793 100644 --- a/client.c +++ b/client.c @@ -217,37 +217,37 @@ extern const struct cmd_entry cmd_new_session_entry; /* For foreground mode */ static int __argc; -static char **__argv; +static const char **__argv; #endif -static void _run_initial_client_cmd(int argc, char **argv) +int run_headless_command(int argc, const char **argv, int flags, void (*err_callback)(const char *)) { struct cmd_q *cmd_q; struct cmd_list *cmdlist; char *cause; - const char *default_argv[] = {"new-session"}; - - if (argc == 0) { - argc = 1; - argv = (char **)default_argv; - } - cmd_q = cmdq_new(NULL); /* No client */ if ((cmdlist = cmd_list_parse(argc, (char **)argv, NULL, 0, &cause)) == NULL) { - tmate_fatal("%s", cause); + if (err_callback) + err_callback(cause); + return -1; } cmdq_run(cmd_q, cmdlist, NULL); cmd_list_free(cmdlist); cmdq_free(cmd_q); + if (flags & DEFER_ERRORS_CFG) + return 0; + /* error messages land in cfg_causes */ extern char **cfg_causes; extern u_int cfg_ncauses; - int has_error = !!cfg_ncauses; + + int ret = cfg_ncauses ? -1 : 0; for (u_int i = 0; i < cfg_ncauses; i++) { - tmate_info("%s", cfg_causes[i]); + if (err_callback) + err_callback(cfg_causes[i]); free(cfg_causes[i]); } @@ -255,13 +255,27 @@ static void _run_initial_client_cmd(int argc, char **argv) cfg_causes = NULL; cfg_ncauses = 0; - if (has_error) - exit(1); + return ret; +} + +static void initial_client_cmd_err_callback(const char *cause) +{ + tmate_info("%s", cause); } void run_initial_client_cmd(void) { - _run_initial_client_cmd(__argc, __argv); + int argc = __argc; + const char **argv = __argv; + + const char *default_argv[] = {"new-session"}; + if (argc == 0) { + argc = 1; + argv = default_argv; + } + + if (run_headless_command(argc, argv, 0, initial_client_cmd_err_callback) < 0) + exit(1); } /* Client main loop. */ @@ -282,7 +296,7 @@ client_main(struct event_base *base, int argc, char **argv, int flags, #ifdef TMATE int cant_nest = 0; __argc = argc; - __argv = argv; + __argv = (const char **)argv; #endif /* Ignore SIGCHLD now or daemon() in the server will leave a zombie. */ diff --git a/server.c b/server.c index f8f08d12..05706769 100644 --- a/server.c +++ b/server.c @@ -203,7 +203,6 @@ server_start(struct event_base *base, int lockfd, char *lockfile) #ifdef TMATE tmate_set_editor_mode(); - tmate_init_boot_options(); #endif start_cfg(); diff --git a/tmux.c b/tmux.c index 90b46403..2c790eca 100644 --- a/tmux.c +++ b/tmux.c @@ -207,26 +207,20 @@ static char *session_name; static char *session_name_ro; static char *authorized_keys; -void tmate_init_boot_options(void) +void tmate_load_cli_options(void) { - if (account_key) - tmate_exec_cmd_args(4, (const char *[]){"set-option", "-g", "tmate-account-key", account_key}); - if (session_name) - tmate_exec_cmd_args(4, (const char *[]){"set-option", "-g", "tmate-session-name", session_name}); - if (session_name_ro) - tmate_exec_cmd_args(4, (const char *[]){"set-option", "-g", "tmate-session-name-ro", session_name_ro}); - if (authorized_keys) - tmate_exec_cmd_args(4, (const char *[]){"set-option", "-g", "tmate-authorized-keys", authorized_keys}); - - free(account_key); - free(session_name); - free(session_name_ro); - free(authorized_keys_file); - - account_key = NULL; - session_name = NULL; - session_name_ro = NULL; - authorized_keys = NULL; +#define SET_OPT(name, val) ({\ + if (val) { \ + run_headless_command(3, (const char *[]){"set-option", name, val}, DEFER_ERRORS_CFG, NULL); \ + free(val); \ + val = NULL; \ + } \ +}) + SET_OPT("tmate-account-key", account_key); + SET_OPT("tmate-account-name", session_name); + SET_OPT("tmate-account-name-ro", session_name_ro); + SET_OPT("tmate-authorized-keys", authorized_keys); +#undef SET_OPT } #endif diff --git a/tmux.h b/tmux.h index 83a573c1..9f3ca7bd 100644 --- a/tmux.h +++ b/tmux.h @@ -1551,7 +1551,7 @@ extern struct timeval start_time; extern const char *socket_path; #ifdef TMATE extern int tmate_foreground; -void tmate_init_boot_options(void); +void tmate_load_cli_options(void); #endif const char *getshell(void); int checkshell(const char *); @@ -1879,6 +1879,8 @@ void signal_waiting_clients(const char *name); void cmd_wait_for_flush(void); /* client.c */ +#define DEFER_ERRORS_CFG 1 +int run_headless_command(int argc, const char **argv, int flags, void (*err_callback)(const char *)); void run_initial_client_cmd(void); int client_main(struct event_base *, int, char **, int, const char *); From fa49dc980d3aad68ffccb01579a1a29a023137f9 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Mon, 4 Nov 2019 19:00:06 -0500 Subject: [PATCH 104/150] Provide a better CLI help (-h) --- tmux.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/tmux.c b/tmux.c index 2c790eca..be50adfd 100644 --- a/tmux.c +++ b/tmux.c @@ -59,8 +59,18 @@ __dead void usage(void) { fprintf(stderr, - "usage: %s [-vVF] [-f config-file] [-S socket-path] [command [flags]]\n", - __progname); + "Usage: %s [options] [tmux-command [flags]]\n" + "\n" + "Basic options:\n" + " -n specify the session name instead of getting a random one\n" + " -r same, but for the read-only session name\n" + " -k specify the account-key, necessary for named sessions on tmate.io\n" + " -F set the foreground mode, useful for setting remote access\n" + " -f set the config file path\n" + " -S set the socket path, useful to issue commands to a running tmate instance\n" + " -v set verbosity (can be repeated)\n" + " -V print version\n" + ,__progname); exit(1); } @@ -254,7 +264,7 @@ main(int argc, char **argv) #endif label = path = NULL; - while ((opt = getopt(argc, argv, "2c:CdFf:lL:qS:uUVvk:n:r:a:")) != -1) { + while ((opt = getopt(argc, argv, "h2c:CdFf:lL:qS:uUVvk:n:r:a:")) != -1) { switch (opt) { case '2': flags |= CLIENT_256COLOURS; @@ -311,6 +321,7 @@ main(int argc, char **argv) case 'a': authorized_keys = xstrdup(optarg); break; + case 'h': default: usage(); } From c71307ed5c9c00c1fdd28add86b5d06a7fceb98e Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Tue, 5 Nov 2019 19:29:18 -0500 Subject: [PATCH 105/150] Fix reconnection hanging bugs --- tmate-msgpack.c | 13 +++++--- tmate-session.c | 81 ++++++++++++++++++++++++++++------------------ tmate-ssh-client.c | 24 ++++++++------ tmate.h | 9 +++--- 4 files changed, 76 insertions(+), 51 deletions(-) diff --git a/tmate-msgpack.c b/tmate-msgpack.c index 144cda70..c41b07ee 100644 --- a/tmate-msgpack.c +++ b/tmate-msgpack.c @@ -19,7 +19,7 @@ static int on_encoder_write(void *userdata, const char *buf, size_t len) tmate_fatal("Cannot buffer encoded data"); if (!encoder->ev_active) { - event_active(&encoder->ev_buffer, EV_READ, 0); + event_active(encoder->ev_buffer, EV_READ, 0); encoder->ev_active = true; } @@ -57,10 +57,12 @@ void tmate_encoder_init(struct tmate_encoder *encoder, if (!encoder->buffer) tmate_fatal("Can't allocate buffer"); - event_set(&encoder->ev_buffer, -1, - EV_READ | EV_PERSIST, on_encoder_buffer_ready, encoder); + encoder->ev_buffer = event_new(tmate_session.ev_base, -1, + EV_READ | EV_PERSIST, on_encoder_buffer_ready, encoder); + if (!encoder->ev_buffer) + tmate_fatal("Can't allocate event"); - event_add(&encoder->ev_buffer, NULL); + event_add(encoder->ev_buffer, NULL); encoder->ev_active = false; } @@ -69,7 +71,8 @@ void tmate_encoder_destroy(struct tmate_encoder *encoder) { /* encoder->pk doesn't need any cleanup */ evbuffer_free(encoder->buffer); - event_del(&encoder->ev_buffer); + event_del(encoder->ev_buffer); + event_free(encoder->ev_buffer); memset(encoder, 0, sizeof(*encoder)); } diff --git a/tmate-session.c b/tmate-session.c index e3eb0c19..b9f03a8e 100644 --- a/tmate-session.c +++ b/tmate-session.c @@ -20,35 +20,50 @@ struct tmate_session tmate_session; static void lookup_and_connect(void); static void on_dns_retry(__unused evutil_socket_t fd, __unused short what, - __unused void *arg) + void *arg) { + struct tmate_session *session = arg; + + assert(session->ev_dns_retry); + event_free(session->ev_dns_retry); + session->ev_dns_retry = NULL; + lookup_and_connect(); } static void dns_cb(int errcode, struct evutil_addrinfo *addr, void *ptr) { struct evutil_addrinfo *ai; - struct timeval tv; const char *host = ptr; if (errcode) { + struct tmate_session *session = &tmate_session; + + if (session->ev_dns_retry) + return; + + struct timeval tv = { .tv_sec = TMATE_DNS_RETRY_TIMEOUT, .tv_usec = 0 }; + + session->ev_dns_retry = evtimer_new(session->ev_base, on_dns_retry, session); + if (!session->ev_dns_retry) + tmate_fatal("out of memory"); + evtimer_add(session->ev_dns_retry, &tv); + tmate_status_message("%s lookup failure. Retrying in %d seconds (%s)", host, TMATE_DNS_RETRY_TIMEOUT, evutil_gai_strerror(errcode)); - - tv.tv_sec = TMATE_DNS_RETRY_TIMEOUT; - tv.tv_usec = 0; - - evtimer_assign(&tmate_session.ev_dns_retry, tmate_session.ev_base, - on_dns_retry, NULL); - evtimer_add(&tmate_session.ev_dns_retry, &tv); - return; } tmate_status_message("Connecting to %s...", host); - for (ai = addr; ai; ai = ai->ai_next) { + int i, num_clients = 0; + for (ai = addr; ai; ai = ai->ai_next) + num_clients++; + + struct tmate_ssh_client *ssh_clients[num_clients]; + + for (ai = addr, i = 0; ai; ai = ai->ai_next, i++) { char buf[128]; const char *ip = NULL; if (ai->ai_family == AF_INET) { @@ -59,23 +74,16 @@ static void dns_cb(int errcode, struct evutil_addrinfo *addr, void *ptr) ip = evutil_inet_ntop(AF_INET6, &sin6->sin6_addr, buf, 128); } - tmate_debug("Trying server %s", ip); - - /* - * Note: We don't deal with the client list. Clients manage it - * and free client structs when necessary. - */ - (void)tmate_ssh_client_alloc(&tmate_session, ip); + ssh_clients[i] = tmate_ssh_client_alloc(&tmate_session, ip); } + for (i = 0; i < num_clients; i++) + connect_ssh_client(ssh_clients[i]); + evutil_freeaddrinfo(addr); - /* - * XXX For some reason, freeing the DNS resolver makes MacOSX flip out... - * not sure what's going on... - * evdns_base_free(tmate_session.ev_dnsbase, 0); - * tmate_session.ev_dnsbase = NULL; - */ + evdns_base_free(tmate_session.ev_dnsbase, 0); + tmate_session.ev_dnsbase = NULL; } static void lookup_and_connect(void) @@ -83,8 +91,8 @@ static void lookup_and_connect(void) struct evutil_addrinfo hints; const char *tmate_server_host; - if (!tmate_session.ev_dnsbase) - tmate_session.ev_dnsbase = evdns_base_new(tmate_session.ev_base, 1); + assert(!tmate_session.ev_dnsbase); + tmate_session.ev_dnsbase = evdns_base_new(tmate_session.ev_base, 1); if (!tmate_session.ev_dnsbase) tmate_fatal("Cannot initialize the DNS lookup service"); @@ -191,12 +199,18 @@ static void on_reconnect_retry(__unused evutil_socket_t fd, __unused short what, { struct tmate_session *session = arg; + assert(session->ev_connection_retry); + event_free(session->ev_connection_retry); + session->ev_connection_retry = NULL; + if (session->last_server_ip) { /* * We have a previous server ip. Let's try that again first, * but then connect to any server if it fails again. */ - (void)tmate_ssh_client_alloc(&tmate_session, session->last_server_ip); + struct tmate_ssh_client *c = tmate_ssh_client_alloc(session, + session->last_server_ip); + connect_ssh_client(c); free(session->last_server_ip); session->last_server_ip = NULL; } else { @@ -214,18 +228,21 @@ void tmate_reconnect_session(struct tmate_session *session, const char *message) */ struct timeval tv = { .tv_sec = TMATE_RECONNECT_RETRY_TIMEOUT, .tv_usec = 0 }; - evtimer_assign(&session->ev_connection_retry, session->ev_base, - on_reconnect_retry, session); - evtimer_add(&session->ev_connection_retry, &tv); + if (session->ev_connection_retry) + return; - if (message) + session->ev_connection_retry = evtimer_new(session->ev_base, on_reconnect_retry, session); + if (!session->ev_connection_retry) + tmate_fatal("out of memory"); + evtimer_add(session->ev_connection_retry, &tv); + + if (message && !tmate_foreground) tmate_status_message("Reconnecting... (%s)", message); else tmate_status_message("Reconnecting..."); /* * This says that we'll need to send a snapshot of the current state. - * Until we have persisted logs... */ session->reconnected = true; } diff --git a/tmate-ssh-client.c b/tmate-ssh-client.c index 66eb1716..3f4690df 100644 --- a/tmate-ssh-client.c +++ b/tmate-ssh-client.c @@ -210,8 +210,12 @@ static void init_conn_fd(struct tmate_ssh_client *client, bool tune_socket) if (tune_socket) tune_socket_opts(fd); - event_set(&client->ev_ssh, fd, EV_READ | EV_PERSIST, __on_ssh_client_event, client); - event_add(&client->ev_ssh, NULL); + assert(!client->ev_ssh); + client->ev_ssh = event_new(client->tmate_session->ev_base, + fd, EV_READ | EV_PERSIST, __on_ssh_client_event, client); + if (!client->ev_ssh) + tmate_fatal("out of memory"); + event_add(client->ev_ssh, NULL); client->has_init_conn_fd = true; } @@ -479,7 +483,8 @@ static void kill_ssh_client(struct tmate_ssh_client *client, tmate_debug("SSH client killed (%s)", client->server_ip); if (client->has_init_conn_fd) { - event_del(&client->ev_ssh); + event_del(client->ev_ssh); + event_free(client->ev_ssh); client->has_init_conn_fd = false; } @@ -506,12 +511,11 @@ static void kill_ssh_client(struct tmate_ssh_client *client, free(client); } -static void connect_ssh_client(struct tmate_ssh_client *client) +void connect_ssh_client(struct tmate_ssh_client *client) { - if (!client->session) { - client->state = SSH_INIT; - on_ssh_client_event(client); - } + assert(!client->session); + client->state = SSH_INIT; + on_ssh_client_event(client); } static void ssh_log_function(int priority, const char *function, @@ -522,9 +526,11 @@ static void ssh_log_function(int priority, const char *function, struct tmate_ssh_client *tmate_ssh_client_alloc(struct tmate_session *session, const char *server_ip) + { struct tmate_ssh_client *client; client = xmalloc(sizeof(*client)); + memset(client, 0, sizeof(*client)); ssh_set_log_callback(ssh_log_function); @@ -544,7 +550,5 @@ struct tmate_ssh_client *tmate_ssh_client_alloc(struct tmate_session *session, client->has_init_conn_fd = false; - connect_ssh_client(client); - return client; } diff --git a/tmate.h b/tmate.h index e1b9af47..9b177120 100644 --- a/tmate.h +++ b/tmate.h @@ -22,7 +22,7 @@ struct tmate_encoder { tmate_encoder_write_cb *ready_callback; void *userdata; struct evbuffer *buffer; - struct event ev_buffer; + struct event *ev_buffer; bool ev_active; }; @@ -142,10 +142,11 @@ struct tmate_ssh_client { ssh_channel channel; bool has_init_conn_fd; - struct event ev_ssh; + struct event *ev_ssh; }; TAILQ_HEAD(tmate_ssh_clients, tmate_ssh_client); +extern void connect_ssh_client(struct tmate_ssh_client *client); extern struct tmate_ssh_client *tmate_ssh_client_alloc(struct tmate_session *session, const char *server_ip); @@ -154,7 +155,7 @@ extern struct tmate_ssh_client *tmate_ssh_client_alloc(struct tmate_session *ses struct tmate_session { struct event_base *ev_base; struct evdns_base *ev_dnsbase; - struct event ev_dns_retry; + struct event *ev_dns_retry; struct tmate_encoder encoder; struct tmate_decoder decoder; @@ -175,7 +176,7 @@ struct tmate_session { char *passphrase; bool reconnected; - struct event ev_connection_retry; + struct event *ev_connection_retry; char *last_server_ip; char *reconnection_data; /* From 442143cd90bc284b487aa2c723b81c8d33e5e38e Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Tue, 5 Nov 2019 21:18:13 -0500 Subject: [PATCH 106/150] Show message when restarting shell --- options-table.c | 8 ++++++++ session.c | 40 +++++++++++++++++++++++++++++++--------- 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/options-table.c b/options-table.c index dd9f696e..4a20c548 100644 --- a/options-table.c +++ b/options-table.c @@ -989,6 +989,14 @@ const struct options_table_entry options_table[] = { .scope = OPTIONS_TABLE_SERVER, .default_str = "" }, + + { .name = "tmate-foreground-restart", + .type = OPTIONS_TABLE_NUMBER, + .scope = OPTIONS_TABLE_SERVER, + .minimum = 0, + .maximum = 1, + .default_num = 1 + }, #endif { .name = NULL } diff --git a/session.c b/session.c index ab58ed9f..d1a644d5 100644 --- a/session.c +++ b/session.c @@ -207,6 +207,36 @@ session_free(__unused int fd, __unused short events, void *arg) } } +static void maybe_restart_session(void) +{ + int fg_restart = options_get_number(global_options, "tmate-foreground-restart"); + if (!fg_restart) + return; + + /* + * throttle restarts. This is a blocking sleep. It's + * simpler than using a timer, but fairly harmless + * from a blocking perspective. + */ + usleep(500*1000); + next_session_id = 0; + run_initial_client_cmd(); + + tmate_info("Shell exited. Shell restarted"); + + struct session *s; + s = RB_MIN(sessions, &sessions); + if (!s) + return; + + struct window_pane *wp; + wp = s->curw->window->active; + window_pane_set_mode(wp, &window_copy_mode); + window_copy_init_for_output(wp); + window_copy_add(wp, "%s", "Shell exited. Shell restarted."); + window_copy_add(wp, "%s", "Note: press the following sequence to disconnect from SSH: ~."); +} + /* Destroy a session. */ void session_destroy(struct session *s) @@ -239,15 +269,7 @@ session_destroy(struct session *s) #ifdef TMATE if (tmate_foreground && !server_exit) { - tmate_info("Shell exited, restarting"); - /* - * throttle restarts. This is a blocking sleep. - * It's simpler than using a timer, but fairly harmless - * from a blocking perspective. - */ - usleep(500*1000); - next_session_id = 0; - run_initial_client_cmd(); + maybe_restart_session(); } else { tmate_info("Session closed"); tmate_write_fin(); From 9781946a70d0bde07abdeca3221b5cb4a31b6f3c Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Tue, 5 Nov 2019 21:32:21 -0500 Subject: [PATCH 107/150] Show initial message in copy mode --- tmate-msg.c | 20 ++++++++++++++++++++ tmate-session.c | 5 +++++ 2 files changed, 25 insertions(+) diff --git a/tmate-msg.c b/tmate-msg.c index a47f9e4d..4ee0a5de 100644 --- a/tmate-msg.c +++ b/tmate-msg.c @@ -50,6 +50,24 @@ static void tmate_status_message_client(struct client *c, const char *message) recalculate_sizes(); } +static void tmate_status_message_session(const char *message) +{ + if (tmate_foreground) + return; + + struct session *s; + s = RB_MIN(sessions, &sessions); + if (!s) { + cfg_add_cause("%s", message); + return; + } + + struct window_pane *wp; + wp = s->curw->window->active; + if (wp->mode == &window_copy_mode) + window_copy_add(wp, "%s", message); +} + void __tmate_status_message(const char *fmt, va_list ap) { struct client *c; @@ -63,6 +81,8 @@ void __tmate_status_message(const char *fmt, va_list ap) tmate_status_message_client(c, message); } + tmate_status_message_session(message); + free(message); } diff --git a/tmate-session.c b/tmate-session.c index b9f03a8e..0c07a758 100644 --- a/tmate-session.c +++ b/tmate-session.c @@ -190,6 +190,11 @@ void tmate_session_start(void) * - While we are parsing the config file, we need to be able to * serialize it, and so we need a worker encoder. */ + if (!tmate_foreground) { + cfg_add_cause("%s", "To see these messages again, run: tmate show-messages"); + cfg_add_cause("%s", "-----------------------------------------------------"); + } + send_authorized_keys(); tmate_write_ready(); lookup_and_connect(); From 0272757aa531166acca449f081ea008c263b4485 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Wed, 6 Nov 2019 12:34:18 -0500 Subject: [PATCH 108/150] Clarify user message --- tmate-session.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tmate-session.c b/tmate-session.c index 0c07a758..0e6080e8 100644 --- a/tmate-session.c +++ b/tmate-session.c @@ -192,6 +192,7 @@ void tmate_session_start(void) */ if (!tmate_foreground) { cfg_add_cause("%s", "To see these messages again, run: tmate show-messages"); + cfg_add_cause("%s", "Press to dismiss"); cfg_add_cause("%s", "-----------------------------------------------------"); } From 1600a81e589e92f3e7bd68a34645797909a32b9a Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Wed, 6 Nov 2019 20:34:44 -0500 Subject: [PATCH 109/150] Also add crash info on SIGABRT --- tmate-debug.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tmate-debug.c b/tmate-debug.c index f58efe0e..59e8fe7d 100644 --- a/tmate-debug.c +++ b/tmate-debug.c @@ -85,7 +85,7 @@ void tmate_print_stack_trace(void) } -static void handle_sigsegv(__unused int sig) +static void handle_crash(__unused int sig) { /* TODO send stack trace to server */ tmate_info("CRASH, printing stack trace"); @@ -95,6 +95,7 @@ static void handle_sigsegv(__unused int sig) void tmate_catch_sigsegv(void) { - signal(SIGSEGV, handle_sigsegv); + signal(SIGSEGV, handle_crash); + signal(SIGABRT, handle_crash); } #endif From ba860b8f4580cee8878341a5cd1fb4fe4d440651 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Thu, 7 Nov 2019 09:08:17 -0500 Subject: [PATCH 110/150] Cleanup warnings --- Makefile.am | 7 +++++-- client.c | 3 --- compat/b64_ntop.c | 4 +++- configure.ac | 1 + log.c | 9 +++++++-- osdep-darwin.c | 2 ++ screen-redraw.c | 2 +- session.c | 1 + tmate-session.c | 2 +- tmate-ssh-client.c | 18 +++++++++--------- tmux.h | 2 ++ xmalloc.c | 2 ++ 12 files changed, 34 insertions(+), 19 deletions(-) diff --git a/Makefile.am b/Makefile.am index 2551bce3..3da954ae 100644 --- a/Makefile.am +++ b/Makefile.am @@ -33,8 +33,8 @@ CFLAGS += -g CFLAGS += -Wno-long-long -Wall -W -Wnested-externs -Wformat=2 CFLAGS += -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations CFLAGS += -Wwrite-strings -Wshadow -Wpointer-arith -Wsign-compare -CFLAGS += -Wundef -Wbad-function-cast -Winline -Wcast-align -CFLAGS += -Wdeclaration-after-statement -Wno-pointer-sign -Wno-attributes +CFLAGS += -Wundef -Wbad-function-cast -Winline +CFLAGS += -Wno-pointer-sign -Wno-attributes CPPFLAGS += -DDEBUG endif if IS_COVERAGE @@ -44,6 +44,9 @@ endif CPPFLAGS += -iquote. endif +CFLAGS += -Wno-unused-parameter -Wno-unused-variable -Wno-null-pointer-arithmetic +CFLAGS += -Wno-deprecated-declarations -Wno-format-nonliteral + # Set flags for Solaris. if IS_SUNOS if IS_GCC diff --git a/client.c b/client.c index 456fe793..c587ec0d 100644 --- a/client.c +++ b/client.c @@ -241,9 +241,6 @@ int run_headless_command(int argc, const char **argv, int flags, void (*err_call return 0; /* error messages land in cfg_causes */ - extern char **cfg_causes; - extern u_int cfg_ncauses; - int ret = cfg_ncauses ? -1 : 0; for (u_int i = 0; i < cfg_ncauses; i++) { if (err_callback) diff --git a/compat/b64_ntop.c b/compat/b64_ntop.c index 2b4dc2d4..fd8930f5 100644 --- a/compat/b64_ntop.c +++ b/compat/b64_ntop.c @@ -52,6 +52,8 @@ #include #include +#include "compat.h" + #define Assert(Cond) if (!(Cond)) abort() static const char Base64[] = @@ -122,7 +124,7 @@ static const char Pad64 = '='; */ int -b64_ntop(uint8_t const *src, size_t srclength, char *target, size_t targsize) { +b64_ntop(const char *src, size_t srclength, char *target, size_t targsize) { size_t datalength = 0; uint8_t input[3]; uint8_t output[4]; diff --git a/configure.ac b/configure.ac index f623cadc..8bdb0686 100644 --- a/configure.ac +++ b/configure.ac @@ -2,6 +2,7 @@ AC_INIT(tmate, 2.3.1) +AM_SILENT_RULES([yes]) AC_CONFIG_AUX_DIR(etc) AM_INIT_AUTOMAKE([foreign subdir-objects]) diff --git a/log.c b/log.c index bc798778..12266aa4 100644 --- a/log.c +++ b/log.c @@ -98,6 +98,7 @@ log_close(void) } /* Write a log message. */ +__attribute__((__format__(__printf__, 1, 0))) static void log_vwrite(const char *msg, va_list ap) { @@ -144,6 +145,7 @@ log_emit(int level, const char *msg, ...) } /* Log a critical error with error string and die. */ +__attribute__((__format__(__printf__, 1, 0))) __dead void fatal(const char *msg, ...) { @@ -153,11 +155,13 @@ fatal(const char *msg, ...) va_start(ap, msg); if (asprintf(&fmt, "fatal: %s: %s", msg, strerror(errno)) == -1) exit(1); - log_vwrite(fmt, ap); + msg = fmt; + log_vwrite(msg, ap); exit(1); } /* Log a critical error and die. */ +__attribute__((__format__(__printf__, 1, 0))) __dead void fatalx(const char *msg, ...) { @@ -167,6 +171,7 @@ fatalx(const char *msg, ...) va_start(ap, msg); if (asprintf(&fmt, "fatal: %s", msg) == -1) exit(1); - log_vwrite(fmt, ap); + msg = fmt; + log_vwrite(msg, ap); exit(1); } diff --git a/osdep-darwin.c b/osdep-darwin.c index 40b18951..53b48138 100644 --- a/osdep-darwin.c +++ b/osdep-darwin.c @@ -28,7 +28,9 @@ char *osdep_get_name(int, char *); char *osdep_get_cwd(int); struct event_base *osdep_event_init(void); +#ifndef __unused #define __unused __attribute__ ((__unused__)) +#endif char * osdep_get_name(int fd, __unused char *tty) diff --git a/screen-redraw.c b/screen-redraw.c index 952a8515..4201b022 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -278,7 +278,7 @@ screen_redraw_draw_borders(struct client *c, int status, u_int top) struct window *w = s->curw->window; struct options *oo = w->options; struct tty *tty = &c->tty; - struct window_pane *wp; + struct window_pane *wp = NULL; struct grid_cell m_active_gc, active_gc, m_other_gc, other_gc; struct grid_cell msg_gc; u_int i, j, type, msgx = 0, msgy = 0; diff --git a/session.c b/session.c index d1a644d5..07ca9acc 100644 --- a/session.c +++ b/session.c @@ -621,6 +621,7 @@ session_group_index(struct session_group *sg) } fatalx("session group not found"); + for(;;); } /* diff --git a/tmate-session.c b/tmate-session.c index 0e6080e8..f3a904bd 100644 --- a/tmate-session.c +++ b/tmate-session.c @@ -137,7 +137,7 @@ void tmate_session_init(struct event_base *base) tmate_write_header(); } -static void send_authorized_keys() +static void send_authorized_keys(void) { char *path; path = options_get_string(global_options, "tmate-authorized-keys"); diff --git a/tmate-ssh-client.c b/tmate-ssh-client.c index 3f4690df..030b330a 100644 --- a/tmate-ssh-client.c +++ b/tmate-ssh-client.c @@ -115,7 +115,7 @@ static int passphrase_callback(__unused const char *prompt, char *buf, size_t le client->tmate_session->need_passphrase = 1; if (client->tmate_session->passphrase) - strncpy(buf, client->tmate_session->passphrase, len); + strlcpy(buf, client->tmate_session->passphrase, len); else strcpy(buf, ""); @@ -268,7 +268,7 @@ static void on_ssh_client_event(struct tmate_ssh_client *client) } client->state = SSH_CONNECT; - /* fall through */ + // fall through case SSH_CONNECT: switch (ssh_connect(session)) { @@ -284,8 +284,8 @@ static void on_ssh_client_event(struct tmate_ssh_client *client) tmate_debug("Establishing connection to %s", client->server_ip); client->state = SSH_AUTH_SERVER; - /* fall through */ } + // fall through case SSH_AUTH_SERVER: #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 9, 0) @@ -352,7 +352,7 @@ static void on_ssh_client_event(struct tmate_ssh_client *client) on_ssh_auth_server_complete(client); client->state = SSH_AUTH_CLIENT_NONE; - /* fall through */ + // fall through case SSH_AUTH_CLIENT_NONE: switch (ssh_userauth_none(session, NULL)) { @@ -368,8 +368,8 @@ static void on_ssh_client_event(struct tmate_ssh_client *client) case SSH_AUTH_PARTIAL: case SSH_AUTH_DENIED: client->state = SSH_AUTH_CLIENT_PUBKEY; - /* fall through */ } + // fall through case SSH_AUTH_CLIENT_PUBKEY: client->tried_passphrase = client->tmate_session->passphrase; @@ -397,8 +397,8 @@ static void on_ssh_client_event(struct tmate_ssh_client *client) case SSH_AUTH_SUCCESS: tmate_debug("Auth successful with pubkey"); client->state = SSH_NEW_CHANNEL; - /* fall through */ } + // fall through SSH_NEW_CHANNEL: case SSH_NEW_CHANNEL: @@ -408,6 +408,7 @@ SSH_NEW_CHANNEL: return; } client->state = SSH_OPEN_CHANNEL; + // fall through case SSH_OPEN_CHANNEL: switch (ssh_channel_open_session(channel)) { @@ -420,8 +421,8 @@ SSH_NEW_CHANNEL: case SSH_OK: tmate_debug("Session opened, initalizing tmate"); client->state = SSH_BOOTSTRAP; - /* fall through */ } + // fall through case SSH_BOOTSTRAP: switch (ssh_channel_request_subsystem(channel, "tmate")) { @@ -449,9 +450,8 @@ SSH_NEW_CHANNEL: free(client->tmate_session->last_server_ip); client->tmate_session->last_server_ip = xstrdup(client->server_ip); - - /* fall through */ } + // fall through case SSH_READY: read_channel(client); diff --git a/tmux.h b/tmux.h index 9f3ca7bd..c60a044e 100644 --- a/tmux.h +++ b/tmux.h @@ -1576,6 +1576,8 @@ void proc_kill_peer(struct tmuxpeer *); extern int cfg_finished; extern int cfg_references; extern struct client *cfg_client; +extern char **cfg_causes; +extern u_int cfg_ncauses; void start_cfg(void); int load_cfg(const char *, struct cmd_q *, char **); void set_cfg_file(const char *); diff --git a/xmalloc.c b/xmalloc.c index afa8e585..90af1e2f 100644 --- a/xmalloc.c +++ b/xmalloc.c @@ -94,6 +94,7 @@ xasprintf(char **ret, const char *fmt, ...) return i; } +__attribute__((__format__(__printf__, 2, 0))) int xvasprintf(char **ret, const char *fmt, va_list ap) { @@ -120,6 +121,7 @@ xsnprintf(char *str, size_t len, const char *fmt, ...) return i; } +__attribute__((__format__(__printf__, 3, 0))) int xvsnprintf(char *str, size_t len, const char *fmt, va_list ap) { From 8b62c547486ce031bdefc91a7930e590e6dd5c2b Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Thu, 7 Nov 2019 11:29:28 -0500 Subject: [PATCH 111/150] Fix typo --- tmux.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tmux.c b/tmux.c index be50adfd..b6b03346 100644 --- a/tmux.c +++ b/tmux.c @@ -62,8 +62,8 @@ usage(void) "Usage: %s [options] [tmux-command [flags]]\n" "\n" "Basic options:\n" - " -n specify the session name instead of getting a random one\n" - " -r same, but for the read-only session name\n" + " -n specify the session token instead of getting a random one\n" + " -r same, but for the read-only token\n" " -k specify the account-key, necessary for named sessions on tmate.io\n" " -F set the foreground mode, useful for setting remote access\n" " -f set the config file path\n" @@ -227,8 +227,8 @@ void tmate_load_cli_options(void) } \ }) SET_OPT("tmate-account-key", account_key); - SET_OPT("tmate-account-name", session_name); - SET_OPT("tmate-account-name-ro", session_name_ro); + SET_OPT("tmate-session-name", session_name); + SET_OPT("tmate-session-name-ro", session_name_ro); SET_OPT("tmate-authorized-keys", authorized_keys); #undef SET_OPT } From d3c8808b0fddee80cf599257e0e68ab44a96d584 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Thu, 7 Nov 2019 11:38:54 -0500 Subject: [PATCH 112/150] Version bump --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 8bdb0686..028d5559 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ # configure.ac -AC_INIT(tmate, 2.3.1) +AC_INIT(tmate, 2.4.0) AM_SILENT_RULES([yes]) AC_CONFIG_AUX_DIR(etc) From 2b146115446ca0477d2c3d7155f07f22fdb9c265 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Thu, 7 Nov 2019 13:31:28 -0500 Subject: [PATCH 113/150] Polish session messages --- session.c | 4 ++-- tmate-session.c | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/session.c b/session.c index 07ca9acc..879eb657 100644 --- a/session.c +++ b/session.c @@ -222,7 +222,7 @@ static void maybe_restart_session(void) next_session_id = 0; run_initial_client_cmd(); - tmate_info("Shell exited. Shell restarted"); + tmate_info("Session shell restarted"); struct session *s; s = RB_MIN(sessions, &sessions); @@ -233,7 +233,7 @@ static void maybe_restart_session(void) wp = s->curw->window->active; window_pane_set_mode(wp, &window_copy_mode); window_copy_init_for_output(wp); - window_copy_add(wp, "%s", "Shell exited. Shell restarted."); + window_copy_add(wp, "%s", "Session shell restarted"); window_copy_add(wp, "%s", "Note: press the following sequence to disconnect from SSH: ~."); } diff --git a/tmate-session.c b/tmate-session.c index f3a904bd..1863f78c 100644 --- a/tmate-session.c +++ b/tmate-session.c @@ -190,7 +190,10 @@ void tmate_session_start(void) * - While we are parsing the config file, we need to be able to * serialize it, and so we need a worker encoder. */ - if (!tmate_foreground) { + if (tmate_foreground) { + tmate_set_val("foreground", "true"); + tmate_info("To connect to the session locally, run: tmate -S %s attach", socket_path); + } else { cfg_add_cause("%s", "To see these messages again, run: tmate show-messages"); cfg_add_cause("%s", "Press to dismiss"); cfg_add_cause("%s", "-----------------------------------------------------"); From 2b860313088465044a596b7604dc184336c93e54 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sun, 10 Nov 2019 03:44:37 -0500 Subject: [PATCH 114/150] Fix keepalive bug --- tmate-session.c | 6 ++-- tmate-ssh-client.c | 69 +++++++++++++++++++++++++++++++--------------- tmate.h | 1 - 3 files changed, 50 insertions(+), 26 deletions(-) diff --git a/tmate-session.c b/tmate-session.c index 1863f78c..10c6123b 100644 --- a/tmate-session.c +++ b/tmate-session.c @@ -36,6 +36,9 @@ static void dns_cb(int errcode, struct evutil_addrinfo *addr, void *ptr) struct evutil_addrinfo *ai; const char *host = ptr; + evdns_base_free(tmate_session.ev_dnsbase, 0); + tmate_session.ev_dnsbase = NULL; + if (errcode) { struct tmate_session *session = &tmate_session; @@ -81,9 +84,6 @@ static void dns_cb(int errcode, struct evutil_addrinfo *addr, void *ptr) connect_ssh_client(ssh_clients[i]); evutil_freeaddrinfo(addr); - - evdns_base_free(tmate_session.ev_dnsbase, 0); - tmate_session.ev_dnsbase = NULL; } static void lookup_and_connect(void) diff --git a/tmate-ssh-client.c b/tmate-ssh-client.c index 030b330a..221d7c9f 100644 --- a/tmate-ssh-client.c +++ b/tmate-ssh-client.c @@ -167,57 +167,84 @@ static void request_passphrase(struct tmate_ssh_client *client) data->password_cb_private = client; } -#define KEEPALIVE_CNT 3 -#define KEEPALIVE_IDLE 20 -#define KEEPALIVE_INTVL 10 +#define KEEPALIVE_IDLE 30 +#define KEEPALIVE_CNT 4 +#define KEEPALIVE_INTVL 11 +#define WRITE_TIMEOUT 80 static void tune_socket_opts(int fd) { #define SSO(level, optname, val) ({ \ int _flag = val; \ if (setsockopt(fd, level, optname, &(_flag), sizeof(int)) < 0) { \ - tmate_debug("setsockopt(" #level ", " #optname ", %d) failed", val); \ + tmate_info("setsockopt(" #level ", " #optname ", %d) failed", val); \ } \ }) SSO(IPPROTO_TCP, TCP_NODELAY, 1); SSO(SOL_SOCKET, SO_KEEPALIVE, 1); #ifdef TCP_KEEPALIVE + /* + * The TCP_KEEPALIVE options enable to specify the amount of time, in + * seconds, that the connection must be idle before keepalive probes + * (if enabled) are sent. + */ SSO(IPPROTO_TCP, TCP_KEEPALIVE, KEEPALIVE_IDLE); #endif -#ifdef TCP_KEEPCNT - SSO(IPPROTO_TCP, TCP_KEEPCNT, KEEPALIVE_CNT); -#endif #ifdef TCP_KEEPIDLE + /* + * Same as TCP_KEEPALIVE, but on different systems + */ SSO(IPPROTO_TCP, TCP_KEEPIDLE, KEEPALIVE_IDLE); #endif +#ifdef TCP_KEEPCNT + /* + * When keepalive probes are enabled, this option will set the number + * of times a keepalive probe should be repeated if the peer is not + * responding. After this many probes, the connection will be closed. + */ + SSO(IPPROTO_TCP, TCP_KEEPCNT, KEEPALIVE_CNT); +#endif #ifdef TCP_KEEPINTVL + /* + * When keepalive probes are enabled, this option will set the amount + * of time in seconds between successive keepalives sent to probe an + * unresponsive peer. + */ SSO(IPPROTO_TCP, TCP_KEEPINTVL, KEEPALIVE_INTVL); #endif +#ifdef TCP_USER_TIMEOUT + /* + * This option takes an unsigned int as an argument. When the + * value is greater than 0, it specifies the maximum amount of + * time in milliseconds that transmitted data may remain + * unacknowledged before TCP will forcibly close the + * corresponding connection and return ETIMEDOUT to the + * application. + */ + SSO(IPPROTO_TCP, TCP_USER_TIMEOUT, 1000*WRITE_TIMEOUT); +#endif #undef SSO } -static void init_conn_fd(struct tmate_ssh_client *client, bool tune_socket) +static void init_conn_fd(struct tmate_ssh_client *client) { int fd; - if (client->has_init_conn_fd) + if (client->ev_ssh) return; if ((fd = ssh_get_fd(client->session)) < 0) return; - if (tune_socket) - tune_socket_opts(fd); + tune_socket_opts(fd); - assert(!client->ev_ssh); - client->ev_ssh = event_new(client->tmate_session->ev_base, - fd, EV_READ | EV_PERSIST, __on_ssh_client_event, client); + client->ev_ssh = event_new(client->tmate_session->ev_base, fd, + EV_READ | EV_PERSIST, + __on_ssh_client_event, client); if (!client->ev_ssh) tmate_fatal("out of memory"); event_add(client->ev_ssh, NULL); - - client->has_init_conn_fd = true; } static void on_ssh_client_event(struct tmate_ssh_client *client) @@ -273,14 +300,14 @@ static void on_ssh_client_event(struct tmate_ssh_client *client) case SSH_CONNECT: switch (ssh_connect(session)) { case SSH_AGAIN: - init_conn_fd(client, false); + init_conn_fd(client); return; case SSH_ERROR: kill_ssh_client(client, "Error connecting: %s", ssh_get_error(session)); return; case SSH_OK: - init_conn_fd(client, true); + init_conn_fd(client); tmate_debug("Establishing connection to %s", client->server_ip); client->state = SSH_AUTH_SERVER; @@ -482,10 +509,10 @@ static void kill_ssh_client(struct tmate_ssh_client *client, tmate_debug("SSH client killed (%s)", client->server_ip); - if (client->has_init_conn_fd) { + if (client->ev_ssh) { event_del(client->ev_ssh); event_free(client->ev_ssh); - client->has_init_conn_fd = false; + client->ev_ssh = NULL; } if (client->state == SSH_READY) { @@ -548,7 +575,5 @@ struct tmate_ssh_client *tmate_ssh_client_alloc(struct tmate_session *session, client->channel = NULL; client->has_encoder = 0; - client->has_init_conn_fd = false; - return client; } diff --git a/tmate.h b/tmate.h index 9b177120..5c3af6a0 100644 --- a/tmate.h +++ b/tmate.h @@ -141,7 +141,6 @@ struct tmate_ssh_client { ssh_session session; ssh_channel channel; - bool has_init_conn_fd; struct event *ev_ssh; }; TAILQ_HEAD(tmate_ssh_clients, tmate_ssh_client); From 86ec8d1ad6f00b28ae9c20c6e3d0d2256d5336d2 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sun, 10 Nov 2019 03:59:12 -0500 Subject: [PATCH 115/150] Better crash messages --- tmate-debug.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tmate-debug.c b/tmate-debug.c index 59e8fe7d..8b4ddd5b 100644 --- a/tmate-debug.c +++ b/tmate-debug.c @@ -88,9 +88,13 @@ void tmate_print_stack_trace(void) static void handle_crash(__unused int sig) { /* TODO send stack trace to server */ - tmate_info("CRASH, printing stack trace"); + const char *what = sig == SIGSEGV ? "SIGSEGV" : "SIGABRT"; + tmate_info("%s printing stack trace", what); tmate_print_stack_trace(); - tmate_fatal("CRASHED"); + + /* Reraise */ + signal(sig, NULL); + kill(getpid(), sig); } void tmate_catch_sigsegv(void) From 9fc6e96444bf913c5dc8d1db1c6ff0eed55b9781 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sun, 10 Nov 2019 15:31:54 -0500 Subject: [PATCH 116/150] Send uname --- tmate-encoder.c | 19 +++++++++++++++++++ tmate-protocol.h | 3 +++ tmate-session.c | 1 + tmate.h | 1 + 4 files changed, 24 insertions(+) diff --git a/tmate-encoder.c b/tmate-encoder.c index 0040a3bf..e1373451 100644 --- a/tmate-encoder.c +++ b/tmate-encoder.c @@ -1,3 +1,4 @@ +#include #include "tmate.h" #include "tmate-protocol.h" #include "window-copy.h" @@ -12,6 +13,23 @@ void tmate_write_header(void) pack(string, VERSION); } +void tmate_write_uname(void) +{ + struct utsname name; + if (uname(&name) < 0) { + tmate_debug("uname() failed"); + return; + } + + pack(array, 6); + pack(int, TMATE_OUT_UNAME); + pack(string, name.sysname); + pack(string, name.nodename); + pack(string, name.release); + pack(string, name.version); + pack(string, name.machine); +} + void tmate_write_ready(void) { pack(array, 1); @@ -464,6 +482,7 @@ void tmate_send_reconnection_state(struct tmate_session *session) tmate_send_reconnection_data(session); replay_saved_cmd(session); /* TODO send all option variables */ + tmate_write_uname(); tmate_write_ready(); tmate_sync_layout(); diff --git a/tmate-protocol.h b/tmate-protocol.h index 595b6271..81716bb2 100644 --- a/tmate-protocol.h +++ b/tmate-protocol.h @@ -56,6 +56,7 @@ enum tmate_daemon_out_msg_types { TMATE_OUT_RECONNECT, TMATE_OUT_SNAPSHOT, TMATE_OUT_EXEC_CMD, + TMATE_OUT_UNAME, }; /* @@ -77,6 +78,8 @@ enum tmate_daemon_out_msg_types { [TMATE_OUT_RECONNECT, string: reconnection_data] [TMATE_OUT_SNAPSHOT, ...] [TMATE_OUT_EXEC_CMD, string: cmd_name, ...string: args] +[TMATE_OUT_UNAME, string: name.sysname, string: name.nodename, + string: name.release, string: name.version, string: name.machine] */ enum tmate_daemon_in_msg_types { diff --git a/tmate-session.c b/tmate-session.c index 10c6123b..d88ec5a5 100644 --- a/tmate-session.c +++ b/tmate-session.c @@ -200,6 +200,7 @@ void tmate_session_start(void) } send_authorized_keys(); + tmate_write_uname(); tmate_write_ready(); lookup_and_connect(); } diff --git a/tmate.h b/tmate.h index 5c3af6a0..1fdda4e0 100644 --- a/tmate.h +++ b/tmate.h @@ -79,6 +79,7 @@ extern void unpack_array(struct tmate_unpacker *uk, struct tmate_unpacker *neste struct tmate_session; extern void tmate_write_header(void); +extern void tmate_write_uname(void); extern void tmate_write_ready(void); extern void tmate_sync_layout(void); extern void tmate_pty_data(struct window_pane *wp, const char *buf, size_t len); From e5f6e68fadc2ca7a27c84a1a3b2ac9e4dce5079c Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sun, 10 Nov 2019 14:05:14 -0500 Subject: [PATCH 117/150] Unify tmate-debug.c with tmate-ssh-server --- tmate-debug.c | 11 +++++++++-- tmate.h | 1 + 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/tmate-debug.c b/tmate-debug.c index 8b4ddd5b..81850284 100644 --- a/tmate-debug.c +++ b/tmate-debug.c @@ -11,6 +11,7 @@ void tmate_print_stack_trace(void) {} void tmate_catch_sigsegv(void) {} +void tmate_preload_trace_lib(void) {} #else @@ -84,8 +85,7 @@ void tmate_print_stack_trace(void) free (strings); } - -static void handle_crash(__unused int sig) +static void handle_crash(int sig) { /* TODO send stack trace to server */ const char *what = sig == SIGSEGV ? "SIGSEGV" : "SIGABRT"; @@ -102,4 +102,11 @@ void tmate_catch_sigsegv(void) signal(SIGSEGV, handle_crash); signal(SIGABRT, handle_crash); } + +void tmate_preload_trace_lib(void) +{ + void *array[1]; + backtrace(array, 1); +} + #endif diff --git a/tmate.h b/tmate.h index 1fdda4e0..ec6d0f29 100644 --- a/tmate.h +++ b/tmate.h @@ -203,6 +203,7 @@ extern void tmate_reconnect_session(struct tmate_session *session, const char *m /* tmate-debug.c */ extern void tmate_print_stack_trace(void); extern void tmate_catch_sigsegv(void); +extern void tmate_preload_trace_lib(void); /* tmate-msg.c */ From bfa3c104d7aed6300313694585fa676f33ba5e4a Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sun, 10 Nov 2019 15:19:32 -0500 Subject: [PATCH 118/150] Refactor static builds --- .gitignore | 1 + .travis.yml | 4 ++-- Dockerfile | 5 +++-- build_static_release.sh | 33 +++++++++++++++++++++++++++++++++ package_release.sh | 14 -------------- 5 files changed, 39 insertions(+), 18 deletions(-) create mode 100755 build_static_release.sh delete mode 100755 package_release.sh diff --git a/.gitignore b/.gitignore index 93153ede..bcbdfe13 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,4 @@ downloads/ ext/ libssh-*/ msgpack-*/ +releases/ diff --git a/.travis.yml b/.travis.yml index a02e89a8..fc43a83f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,7 +20,7 @@ script: # On arch=arm64, some directories are not setup correctly, and 'ruby -S gem # install dpl' required by the release push scripts fails. - 'if [ "$TRAVIS_TAG" ]; then sudo chown -R $USER: /var/lib/gems /usr/local/bin; fi' -- 'if [ "$TRAVIS_TAG" ]; then ./package_release.sh $TRAVIS_TAG $PLATFORM; fi' +- 'if [ "$TRAVIS_TAG" ]; then ./build_static_release.sh $TRAVIS_TAG $PLATFORM; fi' deploy: provider: releases @@ -29,7 +29,7 @@ deploy: skip_cleanup: true overwrite: true file_glob: true - file: /tmp/tmate-release/*.tar.* + file: releases/*.tar.* on: repo: tmate-io/tmate branch: master diff --git a/Dockerfile b/Dockerfile index c7aa2b9f..8b736f63 100644 --- a/Dockerfile +++ b/Dockerfile @@ -20,9 +20,10 @@ RUN set -ex; \ make -j $(nproc); \ make install -COPY . . +COPY compat ./compat +COPY *.c *.h autogen.sh Makefile.am configure.ac ./ RUN ./autogen.sh && ./configure --enable-static RUN make -j $(nproc) -RUN strip tmate +RUN objcopy --only-keep-debug tmate tmate.symbols && strip tmate RUN ./tmate -V diff --git a/build_static_release.sh b/build_static_release.sh new file mode 100755 index 00000000..77b5d003 --- /dev/null +++ b/build_static_release.sh @@ -0,0 +1,33 @@ +#!/bin/bash +set -eux + +# This is invoked by .travis.yml + +VERSION=$1 +PLATFORM=$2 + +SRC_VERSION=`cat configure.ac | grep AC_INIT | sed -E 's/^AC_INIT\(tmate, (.+)\)$/\1/'` + +if [ $SRC_VERSION != $VERSION ]; then + echo "Version mismatch: $SRC_VERSION != $VERSION" + exit 1 +fi + +RELEASE_NAME=tmate-$VERSION-static-linux-$PLATFORM +echo "Building $RELEASE_NAME" + +docker build . --tag local-$PLATFORM/tmate-build --build-arg PLATFORM=$PLATFORM + +mkdir -p releases +cd releases + +rm -rf $RELEASE_NAME +mkdir -p $RELEASE_NAME +docker run --rm local-$PLATFORM/tmate-build cat tmate > $RELEASE_NAME/tmate +chmod +x $RELEASE_NAME/tmate +tar -cf - $RELEASE_NAME | xz > tmate-$VERSION-static-linux-$PLATFORM.tar.xz + +rm -rf $RELEASE_NAME-symbols +mkdir -p $RELEASE_NAME-symbols +docker run --rm local-$PLATFORM/tmate-build cat tmate.symbols > $RELEASE_NAME-symbols/tmate.symbols +tar -cf - $RELEASE_NAME-symbols | xz > dbg-symbols-tmate-$VERSION-static-linux-$PLATFORM.tar.xz diff --git a/package_release.sh b/package_release.sh deleted file mode 100755 index f4186e3c..00000000 --- a/package_release.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash -set -eux -VERSION=$1 -PLATFORM=$2 -RELEASE_NAME=tmate-$VERSION-static-linux-$PLATFORM - -# This assumes the follow command has already been run: -# docker build . --tag local-$PLATFORM/tmate-build --build-arg PLATFORM=$PLATFORM - -mkdir -p /tmp/tmate-release/$RELEASE_NAME -cd /tmp/tmate-release -docker run --rm local-$PLATFORM/tmate-build cat tmate > $RELEASE_NAME/tmate -chmod +x $RELEASE_NAME/tmate -tar -cf - $RELEASE_NAME | xz > tmate-$VERSION-static-linux-$PLATFORM.tar.xz From 7e02dba7efb73aabbf1a4f0cd3c43739d62b82bf Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sun, 10 Nov 2019 16:23:00 -0500 Subject: [PATCH 119/150] Minor refactor --- tmate-ssh-client.c | 38 ++++++++++++++++++++------------------ tmate.h | 1 - 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/tmate-ssh-client.c b/tmate-ssh-client.c index 221d7c9f..c52c166c 100644 --- a/tmate-ssh-client.c +++ b/tmate-ssh-client.c @@ -86,7 +86,6 @@ static void on_ssh_auth_server_complete(struct tmate_ssh_client *connected_clien if (client == connected_client) continue; - assert(!client->has_encoder); kill_ssh_client(client, NULL); } } @@ -177,7 +176,9 @@ static void tune_socket_opts(int fd) #define SSO(level, optname, val) ({ \ int _flag = val; \ if (setsockopt(fd, level, optname, &(_flag), sizeof(int)) < 0) { \ - tmate_info("setsockopt(" #level ", " #optname ", %d) failed", val); \ + /* If the connection has been closed, we'll get EINVAL */ \ + if (errno != EINVAL) \ + tmate_info("setsockopt(" #level ", " #optname ", %d) failed %s", val, strerror(errno)); \ } \ }) @@ -249,23 +250,11 @@ static void init_conn_fd(struct tmate_ssh_client *client) static void on_ssh_client_event(struct tmate_ssh_client *client) { - char *identity; - ssh_key pubkey; - enum ssh_keytypes_e key_type; - unsigned char *hash; - ssize_t hash_len; - char *hash_str; - const char *server_hash_str; - int match; - - int verbosity = SSH_LOG_NOLOG + log_get_level(); - int port = options_get_number(global_options, "tmate-server-port"); - ssh_session session = client->session; ssh_channel channel = client->channel; switch (client->state) { - case SSH_INIT: + case SSH_INIT: { client->session = session = ssh_new(); if (!session) { tmate_fatal("cannot ssh_new()"); @@ -274,6 +263,9 @@ static void on_ssh_client_event(struct tmate_ssh_client *client) ssh_set_callbacks(session, &client->ssh_callbacks); + int verbosity = SSH_LOG_NOLOG + log_get_level(); + int port = options_get_number(global_options, "tmate-server-port"); + ssh_set_blocking(session, 0); ssh_options_set(session, SSH_OPTIONS_HOST, client->server_ip); ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity); @@ -281,6 +273,7 @@ static void on_ssh_client_event(struct tmate_ssh_client *client) ssh_options_set(session, SSH_OPTIONS_USER, "tmate"); ssh_options_set(session, SSH_OPTIONS_COMPRESSION, "yes"); + char *identity; if ((identity = get_identity())) { /* * FIXME libssh will continue with the next set of @@ -295,7 +288,8 @@ static void on_ssh_client_event(struct tmate_ssh_client *client) } client->state = SSH_CONNECT; - // fall through + } + // fall through case SSH_CONNECT: switch (ssh_connect(session)) { @@ -314,7 +308,15 @@ static void on_ssh_client_event(struct tmate_ssh_client *client) } // fall through - case SSH_AUTH_SERVER: + case SSH_AUTH_SERVER: { + ssh_key pubkey; + enum ssh_keytypes_e key_type; + unsigned char *hash; + ssize_t hash_len; + char *hash_str; + const char *server_hash_str; + int match; + #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 9, 0) if (ssh_get_server_publickey(session, &pubkey) < 0) tmate_fatal("ssh_get_server_publickey"); @@ -379,6 +381,7 @@ static void on_ssh_client_event(struct tmate_ssh_client *client) on_ssh_auth_server_complete(client); client->state = SSH_AUTH_CLIENT_NONE; + } // fall through case SSH_AUTH_CLIENT_NONE: @@ -573,7 +576,6 @@ struct tmate_ssh_client *tmate_ssh_client_alloc(struct tmate_session *session, client->state = SSH_NONE; client->session = NULL; client->channel = NULL; - client->has_encoder = 0; return client; } diff --git a/tmate.h b/tmate.h index ec6d0f29..f4783dc8 100644 --- a/tmate.h +++ b/tmate.h @@ -130,7 +130,6 @@ struct tmate_ssh_client { char *server_ip; - int has_encoder; int state; /* From 9fe8b32293982bb85eb12b9c55991b6fa0dac400 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sun, 10 Nov 2019 16:29:05 -0500 Subject: [PATCH 120/150] Add foreground tip --- tmate-session.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tmate-session.c b/tmate-session.c index d88ec5a5..02f25c14 100644 --- a/tmate-session.c +++ b/tmate-session.c @@ -194,7 +194,8 @@ void tmate_session_start(void) tmate_set_val("foreground", "true"); tmate_info("To connect to the session locally, run: tmate -S %s attach", socket_path); } else { - cfg_add_cause("%s", "To see these messages again, run: tmate show-messages"); + cfg_add_cause("%s", "Tip: if you wish to use tmate for remote access, run tmate -F"); + cfg_add_cause("%s", "To see the following messages again, run: tmate show-messages"); cfg_add_cause("%s", "Press to dismiss"); cfg_add_cause("%s", "-----------------------------------------------------"); } From f895fe01b1ddd0f0dbd0d019c5f290c7650b7d3b Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sun, 10 Nov 2019 22:27:23 -0500 Subject: [PATCH 121/150] Rename account-key -> api-key --- options-table.c | 2 +- tmux.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/options-table.c b/options-table.c index 4a20c548..e3362ba8 100644 --- a/options-table.c +++ b/options-table.c @@ -960,7 +960,7 @@ const struct options_table_entry options_table[] = { .default_str = "" }, - { .name = "tmate-account-key", + { .name = "tmate-api-key", .type = OPTIONS_TABLE_STRING, .scope = OPTIONS_TABLE_SERVER, .default_str = "" diff --git a/tmux.c b/tmux.c index b6b03346..53b984d7 100644 --- a/tmux.c +++ b/tmux.c @@ -64,7 +64,7 @@ usage(void) "Basic options:\n" " -n specify the session token instead of getting a random one\n" " -r same, but for the read-only token\n" - " -k specify the account-key, necessary for named sessions on tmate.io\n" + " -k specify an api-key, necessary for using named sessions on tmate.io\n" " -F set the foreground mode, useful for setting remote access\n" " -f set the config file path\n" " -S set the socket path, useful to issue commands to a running tmate instance\n" @@ -212,7 +212,7 @@ find_home(void) } #ifdef TMATE -static char *account_key; +static char *api_key; static char *session_name; static char *session_name_ro; static char *authorized_keys; @@ -226,7 +226,7 @@ void tmate_load_cli_options(void) val = NULL; \ } \ }) - SET_OPT("tmate-account-key", account_key); + SET_OPT("tmate-api-key", api_key); SET_OPT("tmate-session-name", session_name); SET_OPT("tmate-session-name-ro", session_name_ro); SET_OPT("tmate-authorized-keys", authorized_keys); @@ -310,7 +310,7 @@ main(int argc, char **argv) unsetenv("TMUX"); break; case 'k': - account_key = xstrdup(optarg); + api_key = xstrdup(optarg); break; case 'n': session_name = xstrdup(optarg); From 5e00bfa5e137e76c81888727712ced2b3fd99f5b Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sat, 16 Nov 2019 17:08:46 -0500 Subject: [PATCH 122/150] Rephrase --- tmate-session.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tmate-session.c b/tmate-session.c index 02f25c14..62493278 100644 --- a/tmate-session.c +++ b/tmate-session.c @@ -194,10 +194,10 @@ void tmate_session_start(void) tmate_set_val("foreground", "true"); tmate_info("To connect to the session locally, run: tmate -S %s attach", socket_path); } else { - cfg_add_cause("%s", "Tip: if you wish to use tmate for remote access, run tmate -F"); - cfg_add_cause("%s", "To see the following messages again, run: tmate show-messages"); - cfg_add_cause("%s", "Press to dismiss"); - cfg_add_cause("%s", "-----------------------------------------------------"); + cfg_add_cause("%s", "Tip: if you wish to use tmate only for remote access, run: tmate -F"); + cfg_add_cause("%s", "To see the following messages again, run in a tmate session: tmate show-messages"); + cfg_add_cause("%s", "Press or to continue"); + cfg_add_cause("%s", "---------------------------------------------------------------------"); } send_authorized_keys(); From f0a4707ef35b04afb87092f11782f63776b3cdec Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Thu, 28 Nov 2019 16:30:32 -0500 Subject: [PATCH 123/150] Update dockerfile for size --- Dockerfile | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 8b736f63..2f6387c5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ ARG PLATFORM=amd64 -FROM ${PLATFORM}/alpine:3.10 +FROM ${PLATFORM}/alpine:3.10 AS build WORKDIR /build @@ -25,5 +25,13 @@ COPY *.c *.h autogen.sh Makefile.am configure.ac ./ RUN ./autogen.sh && ./configure --enable-static RUN make -j $(nproc) -RUN objcopy --only-keep-debug tmate tmate.symbols && strip tmate +RUN objcopy --only-keep-debug tmate tmate.symbols && chmod -x tmate.symbols && strip tmate RUN ./tmate -V + +FROM alpine:3.9 + +RUN apk --no-cache add bash +RUN mkdir /build +ENV PATH=/build:$PATH +COPY --from=build /build/tmate.symbols /build +COPY --from=build /build/tmate /build From cc01f3f13a73cba3021c072780a22d1fcbd0dceb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damian=20Szyma=C5=84ski?= Date: Fri, 29 Nov 2019 14:08:06 +0100 Subject: [PATCH 124/150] Add build on s390x and ppc64le --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index fc43a83f..5a83e0ed 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,6 +14,10 @@ matrix: env: PLATFORM=arm32v7 - arch: arm64 env: PLATFORM=arm64v8 + - arch: s390x + env: PLATFORM=s390x + - arch: ppc64le + env: PLATFORM=ppc64le script: - 'docker build . --tag local-$PLATFORM/tmate-build --build-arg PLATFORM=$PLATFORM' From ba6ac3a363ae7bdd4af946cc81a19f703d06907f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damian=20Szyma=C5=84ski?= Date: Fri, 6 Dec 2019 12:43:04 +0100 Subject: [PATCH 125/150] Update paths in build_static_release script (#178) --- build_static_release.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build_static_release.sh b/build_static_release.sh index 77b5d003..9cb35435 100755 --- a/build_static_release.sh +++ b/build_static_release.sh @@ -23,11 +23,11 @@ cd releases rm -rf $RELEASE_NAME mkdir -p $RELEASE_NAME -docker run --rm local-$PLATFORM/tmate-build cat tmate > $RELEASE_NAME/tmate +docker run --rm local-$PLATFORM/tmate-build cat /build/tmate > $RELEASE_NAME/tmate chmod +x $RELEASE_NAME/tmate tar -cf - $RELEASE_NAME | xz > tmate-$VERSION-static-linux-$PLATFORM.tar.xz rm -rf $RELEASE_NAME-symbols mkdir -p $RELEASE_NAME-symbols -docker run --rm local-$PLATFORM/tmate-build cat tmate.symbols > $RELEASE_NAME-symbols/tmate.symbols +docker run --rm local-$PLATFORM/tmate-build cat /build/tmate.symbols > $RELEASE_NAME-symbols/tmate.symbols tar -cf - $RELEASE_NAME-symbols | xz > dbg-symbols-tmate-$VERSION-static-linux-$PLATFORM.tar.xz From 9e3e39d66ddb4a610720fa37a5683c846d2a1ba6 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Wed, 11 Mar 2020 11:30:33 -0400 Subject: [PATCH 126/150] Avoid initializing stdout twice Closes #190 --- log.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/log.c b/log.c index 12266aa4..45aaea46 100644 --- a/log.c +++ b/log.c @@ -61,6 +61,9 @@ log_get_level(void) void log_open_fp(FILE *f) { + if (log_file == f) + return; + if (log_file != NULL && !is_log_stdout()) fclose(log_file); From 339e6c43575244f72831654e5dda41c037febde7 Mon Sep 17 00:00:00 2001 From: Klemens Nanni Date: Thu, 2 Apr 2020 18:19:57 +0200 Subject: [PATCH 127/150] Include for global errno At least on OpenBSD the symbol `errno` is otherwise not defined; it is used in the `SSO()` macro and `send_authorized_keys()` function. --- tmate-session.c | 1 + tmate-ssh-client.c | 1 + 2 files changed, 2 insertions(+) diff --git a/tmate-session.c b/tmate-session.c index 62493278..5ba0896c 100644 --- a/tmate-session.c +++ b/tmate-session.c @@ -5,6 +5,7 @@ #include #include +#include #include #include #include diff --git a/tmate-ssh-client.c b/tmate-ssh-client.c index c52c166c..42c4e6a6 100644 --- a/tmate-ssh-client.c +++ b/tmate-ssh-client.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include From cbec43f56dfb48c2fb6e00faa2cb85443d4b7d8f Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Tue, 14 Apr 2020 18:22:04 -0400 Subject: [PATCH 128/150] Better debugging when keys are not matching --- tmate-ssh-client.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tmate-ssh-client.c b/tmate-ssh-client.c index 42c4e6a6..995c92a7 100644 --- a/tmate-ssh-client.c +++ b/tmate-ssh-client.c @@ -328,7 +328,7 @@ static void on_ssh_client_event(struct tmate_ssh_client *client) if (ssh_get_publickey_hash(pubkey, SSH_PUBLICKEY_HASH_SHA256, &hash, &hash_len) < 0) { - kill_ssh_client(client, "Cannot authenticate server"); + kill_ssh_client(client, "Failed to get server fingerprint"); return; } @@ -362,15 +362,17 @@ static void on_ssh_client_event(struct tmate_ssh_client *client) } match = !strcmp(hash_str, server_hash_str); + if (!match) { + kill_ssh_client(client, "Server fingerprint not recognized: " + "`%s', expected `%s'", server_hash_str, hash_str); + } ssh_key_free(pubkey); ssh_clean_pubkey_hash(&hash); free(hash_str); - if (!match) { - kill_ssh_client(client, "Cannot authenticate server"); + if (!match) return; - } /* * At this point, we abort other connection attempts to the From f6a4ae6042f4bb2b6db8eda23df31d8b788a7978 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Jacke?= Date: Thu, 18 Feb 2021 11:58:52 +0100 Subject: [PATCH 129/150] client: set IPTOS_LOWDELAY on TCP connection this helps edge routers to prioritize our interactive network traffic. --- tmate-ssh-client.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tmate-ssh-client.c b/tmate-ssh-client.c index 995c92a7..ce8d5a5a 100644 --- a/tmate-ssh-client.c +++ b/tmate-ssh-client.c @@ -183,6 +183,7 @@ static void tune_socket_opts(int fd) } \ }) + SSO(IPPROTO_IP, IP_TOS, 0x10); /* IPTOS_LOWDELAY */ SSO(IPPROTO_TCP, TCP_NODELAY, 1); SSO(SOL_SOCKET, SO_KEEPALIVE, 1); #ifdef TCP_KEEPALIVE From 8123fa34f847c658f7cedf154dd4cf966047e6bf Mon Sep 17 00:00:00 2001 From: hpcbjdic Date: Tue, 24 Mar 2020 14:56:06 +0100 Subject: [PATCH 130/150] enable redefinition of TMUX_CONF Without the added #ifndef / #endif it's not possible to _actually_ redefine TMUX_CONF by means of the compiler flag -DTMUX_CONF=... as done by the build system. The same patch has also been applied to tmux, cf. master at https://github.com/tmux/tmux/blob/master/tmux.h. --- tmux.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tmux.h b/tmux.h index c60a044e..b38615b6 100644 --- a/tmux.h +++ b/tmux.h @@ -53,7 +53,9 @@ struct tmuxpeer; struct tmuxproc; /* Default global configuration file. */ +#ifndef TMUX_CONF #define TMUX_CONF "/etc/tmux.conf" +#endif /* * Minimum layout cell size, NOT including separator line. The scroll region From e5ce3f04d2851b4c825430f87620cc42d1d946d6 Mon Sep 17 00:00:00 2001 From: Sergio de Almeida Cipriano Junior Date: Wed, 18 Nov 2020 10:59:07 -0300 Subject: [PATCH 131/150] Fix typo in ssh client --- tmate-ssh-client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmate-ssh-client.c b/tmate-ssh-client.c index ce8d5a5a..bed79e95 100644 --- a/tmate-ssh-client.c +++ b/tmate-ssh-client.c @@ -453,7 +453,7 @@ SSH_NEW_CHANNEL: ssh_get_error(session)); return; case SSH_OK: - tmate_debug("Session opened, initalizing tmate"); + tmate_debug("Session opened, initializing tmate"); client->state = SSH_BOOTSTRAP; } // fall through From 808b5645641c82cc09e5488ea0466908a514bba5 Mon Sep 17 00:00:00 2001 From: Sergio de Almeida Cipriano Junior Date: Wed, 18 Nov 2020 11:30:37 -0300 Subject: [PATCH 132/150] Update manpage --- tmux.1 | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/tmux.1 b/tmux.1 index b55b3682..c90b5560 100644 --- a/tmux.1 +++ b/tmux.1 @@ -19,10 +19,11 @@ .Os .Sh NAME .Nm tmate -.Nd terminal multiplexer +.Nd terminal multiplexer with instant terminal sharing .Sh SYNOPSIS .Nm tmate .Bk -words +.Op show-messages .Op Fl 2CluvV .Op Fl c Ar shell-command .Op Fl f Ar file @@ -32,13 +33,24 @@ .Ek .Sh DESCRIPTION .Nm -is a terminal multiplexer: +is a terminal multiplexer with instant terminal sharing: it enables a number of terminals to be created, accessed, and -controlled from a single screen. +controlled from a single screen and be shared with another mates. .Nm may be detached from a screen and continue running in the background, -then later reattached. +then later reattached, like as a daemon. +.Pp +.Nm +provides an instant pairing solution, allowing you to share a terminal +with one or several teammates. Together with a voice call, it's almost like +pairing in person. The terminal sharing works by using SSH connections to +backend servers maintained by tmate upstream developers; teammates need to be +given a randomly-generated token to be able to join a session. +.Pp +.Nm +is a modified version of tmux, and uses the same configurations such as +keybindings, color schemes, etc. .Pp When .Nm @@ -47,9 +59,9 @@ is started it creates a new with a single .Em window and displays it on screen. -A status line at the bottom of the screen -shows information on the current session -and is used to enter interactive commands. +A status line at the bottom of the screen shows information +on the current session, such as ssh command to share with +your mate, and is used to enter interactive commands. .Pp A session is a single collection of .Em pseudo terminals From c9ec7af63238b0a47bf659729d32dde2066ce60f Mon Sep 17 00:00:00 2001 From: n0vember Date: Wed, 27 Jan 2021 15:53:45 +0100 Subject: [PATCH 133/150] add basic information for -a option in man page and help text --- tmux.1 | 4 ++++ tmux.c | 1 + 2 files changed, 5 insertions(+) diff --git a/tmux.1 b/tmux.1 index c90b5560..55f88c98 100644 --- a/tmux.1 +++ b/tmux.1 @@ -110,6 +110,10 @@ The options are as follows: Force .Nm to assume the terminal supports 256 colours. +.It Fl a Ar file +Limit access to the public keys listed in the +.Ar file +given as argument. .It Fl C Start in control mode (see the .Sx CONTROL MODE diff --git a/tmux.c b/tmux.c index 53b984d7..730c2dfc 100644 --- a/tmux.c +++ b/tmux.c @@ -68,6 +68,7 @@ usage(void) " -F set the foreground mode, useful for setting remote access\n" " -f set the config file path\n" " -S set the socket path, useful to issue commands to a running tmate instance\n" + " -a limit access to ssh public keys listed in provided file\n" " -v set verbosity (can be repeated)\n" " -V print version\n" ,__progname); From be4a88507e082e0e8e591e18b08374ff591b3980 Mon Sep 17 00:00:00 2001 From: Max Schmitt Date: Sat, 5 Mar 2022 01:33:21 +0100 Subject: [PATCH 134/150] chore: add FUNDING.yml --- .github/FUNDING.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..ea4e6439 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +github: nviennot From 169eb64b99719eadccba1f9a00856b68b589ef35 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 3 Aug 2022 18:19:32 +0800 Subject: [PATCH 135/150] Add FreeBSD build by https://github.com/vmactions/freebsd-vm --- .github/workflows/FreeBSD.yml | 40 +++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 .github/workflows/FreeBSD.yml diff --git a/.github/workflows/FreeBSD.yml b/.github/workflows/FreeBSD.yml new file mode 100644 index 00000000..3a16af9f --- /dev/null +++ b/.github/workflows/FreeBSD.yml @@ -0,0 +1,40 @@ +name: FreeBSD +on: + push: + branches: + - '*' + paths: + - '**.c' + - '**.h' + - 'compat/*' + - '.github/workflows/FreeBSD.yml' + pull_request: + branches: + - '*' + paths: + - '**.c' + - '**.h' + - 'compat/*' + - '.github/workflows/FreeBSD.yml' + + + +jobs: + FreeBSD: + runs-on: macos-12 + steps: + - uses: actions/checkout@v2 + - uses: vmactions/freebsd-vm@v0 + with: + prepare: | + pkg install -y gmake automake autoconf libtool pkgconf libevent msgpack libssh + usesh: true + run: | + autoupdate + ./autogen.sh + ./configure + make + make install + + + From a258907cf8a8888cbb895aa478b697200081c006 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 3 Aug 2022 18:20:33 +0800 Subject: [PATCH 136/150] add NetBSD test by https://github.com/vmactions/netbsd-vm --- .github/workflows/NetBSD.yml | 40 ++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 .github/workflows/NetBSD.yml diff --git a/.github/workflows/NetBSD.yml b/.github/workflows/NetBSD.yml new file mode 100644 index 00000000..0566d3b9 --- /dev/null +++ b/.github/workflows/NetBSD.yml @@ -0,0 +1,40 @@ +name: NetBSD +on: + push: + branches: + - '*' + paths: + - '**.c' + - '**.h' + - 'compat/*' + - '.github/workflows/NetBSD.yml' + pull_request: + branches: + - '*' + paths: + - '**.c' + - '**.h' + - 'compat/*' + - '.github/workflows/NetBSD.yml' + + + +jobs: + NetBSD: + runs-on: macos-12 + steps: + - uses: actions/checkout@v2 + - uses: vmactions/netbsd-vm@v0 + with: + prepare: | + pkg_add gmake automake autoconf libtool pkgconf libevent msgpack libssh + usesh: true + run: | + autoupdate + ./autogen.sh + ./configure + make + make install + + + From b1079b43930b42f53f6f1579fd1d6afcf9134aeb Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 3 Aug 2022 18:21:37 +0800 Subject: [PATCH 137/150] add OpenBSD build by https://github.com/vmactions/openbsd-vm --- .github/workflows/OpenBSD.yml | 44 +++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 .github/workflows/OpenBSD.yml diff --git a/.github/workflows/OpenBSD.yml b/.github/workflows/OpenBSD.yml new file mode 100644 index 00000000..fbeda51d --- /dev/null +++ b/.github/workflows/OpenBSD.yml @@ -0,0 +1,44 @@ +name: OpenBSD +on: + push: + branches: + - '*' + paths: + - '**.c' + - '**.h' + - 'compat/*' + - '.github/workflows/OpenBSD.yml' + pull_request: + branches: + - '*' + paths: + - '**.c' + - '**.h' + - 'compat/*' + - '.github/workflows/OpenBSD.yml' + + + +jobs: + OpenBSD: + runs-on: macos-12 + steps: + - uses: actions/checkout@v2 + - uses: vmactions/openbsd-vm@v0 + with: + prepare: | + pkg_add gmake automake-1.16.3 autoconf-2.71 libtool pkgconf libevent msgpack libssh gcc-11.2.0p2 + usesh: true + run: | + ln -s /usr/local/bin/egcc /usr/local/bin/gcc + autoupdate + aclocal --print-ac-dir + export AUTOMAKE_VERSION=1.16 + export AUTOCONF_VERSION=2.71 + ./autogen.sh + ./configure + make + make install + + + From 577e04df6c746acbca0b98e12f6ca143bf031be1 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 3 Aug 2022 23:33:18 +0800 Subject: [PATCH 138/150] fix --- .github/workflows/OpenBSD.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/OpenBSD.yml b/.github/workflows/OpenBSD.yml index fbeda51d..3c884006 100644 --- a/.github/workflows/OpenBSD.yml +++ b/.github/workflows/OpenBSD.yml @@ -31,10 +31,9 @@ jobs: usesh: true run: | ln -s /usr/local/bin/egcc /usr/local/bin/gcc - autoupdate - aclocal --print-ac-dir export AUTOMAKE_VERSION=1.16 export AUTOCONF_VERSION=2.71 + autoupdate ./autogen.sh ./configure make From ef11a7b30ed743051e703b5745fa41916ae0be9f Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 6 Aug 2022 13:39:23 +0800 Subject: [PATCH 139/150] fix OpenBSD.yml --- .github/workflows/OpenBSD.yml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/OpenBSD.yml b/.github/workflows/OpenBSD.yml index 3c884006..53f06485 100644 --- a/.github/workflows/OpenBSD.yml +++ b/.github/workflows/OpenBSD.yml @@ -27,10 +27,17 @@ jobs: - uses: vmactions/openbsd-vm@v0 with: prepare: | - pkg_add gmake automake-1.16.3 autoconf-2.71 libtool pkgconf libevent msgpack libssh gcc-11.2.0p2 + pkg_add automake-1.16.3 autoconf-2.71 libtool pkgconf libevent msgpack libssh usesh: true run: | - ln -s /usr/local/bin/egcc /usr/local/bin/gcc + sed -i 's,,,' *.[ch] + curl https://raw.githubusercontent.com/openbsd/ports/master/sysutils/tmate/patches/patch-Makefile_am | patch + curl https://raw.githubusercontent.com/openbsd/ports/master/sysutils/tmate/patches/patch-server_c | patch + curl https://raw.githubusercontent.com/openbsd/ports/master/sysutils/tmate/patches/patch-tmate-debug_c | patch + curl https://raw.githubusercontent.com/openbsd/ports/master/sysutils/tmate/patches/patch-tmate_h | patch + curl https://raw.githubusercontent.com/openbsd/ports/master/sysutils/tmate/patches/patch-tmux_c | patch + curl https://raw.githubusercontent.com/openbsd/ports/master/sysutils/tmate/patches/patch-tmux_h | patch + curl https://raw.githubusercontent.com/openbsd/ports/master/sysutils/tmate/patches/patch-osdep-openbsd_c | patch export AUTOMAKE_VERSION=1.16 export AUTOCONF_VERSION=2.71 autoupdate From 17d4a8a7dfa25bcf3ddb336916010f905f2f4183 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 6 Aug 2022 13:45:53 +0800 Subject: [PATCH 140/150] fix OpenBSD.yml --- .github/workflows/OpenBSD.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/OpenBSD.yml b/.github/workflows/OpenBSD.yml index 53f06485..8fb7901b 100644 --- a/.github/workflows/OpenBSD.yml +++ b/.github/workflows/OpenBSD.yml @@ -27,7 +27,7 @@ jobs: - uses: vmactions/openbsd-vm@v0 with: prepare: | - pkg_add automake-1.16.3 autoconf-2.71 libtool pkgconf libevent msgpack libssh + pkg_add automake-1.16.3 autoconf-2.71 libtool pkgconf libevent msgpack libssh curl usesh: true run: | sed -i 's,,,' *.[ch] From fde4b58228cd8226e7128bf101e2fe569eed5882 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 6 Aug 2022 13:46:36 +0800 Subject: [PATCH 141/150] add MacOS.yml --- .github/workflows/MacOS.yml | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 .github/workflows/MacOS.yml diff --git a/.github/workflows/MacOS.yml b/.github/workflows/MacOS.yml new file mode 100644 index 00000000..5e118ee7 --- /dev/null +++ b/.github/workflows/MacOS.yml @@ -0,0 +1,37 @@ +name: MacOS +on: + push: + branches: + - '*' + paths: + - '**.c' + - '**.h' + - 'compat/*' + - '.github/workflows/MacOS.yml' + pull_request: + branches: + - '*' + paths: + - '**.c' + - '**.h' + - 'compat/*' + - '.github/workflows/MacOS.yml' + + + +jobs: + NetBSD: + runs-on: macos-latest + steps: + - uses: actions/checkout@v2 + - run: | + brew install automake + autoupdate + ./autogen.sh + ./configure + make + make install + + + + From 05a849ba2b29351419ad2034994111388c0817b7 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 6 Aug 2022 13:47:18 +0800 Subject: [PATCH 142/150] fix MacOS.yml --- .github/workflows/MacOS.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/MacOS.yml b/.github/workflows/MacOS.yml index 5e118ee7..db1c9ca0 100644 --- a/.github/workflows/MacOS.yml +++ b/.github/workflows/MacOS.yml @@ -20,7 +20,7 @@ on: jobs: - NetBSD: + MacOS: runs-on: macos-latest steps: - uses: actions/checkout@v2 From 7c0bbf3e164d869073012b7fffd896869337b143 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 6 Aug 2022 13:56:06 +0800 Subject: [PATCH 143/150] fix MacOS.yml --- .github/workflows/MacOS.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/MacOS.yml b/.github/workflows/MacOS.yml index db1c9ca0..37293260 100644 --- a/.github/workflows/MacOS.yml +++ b/.github/workflows/MacOS.yml @@ -25,7 +25,7 @@ jobs: steps: - uses: actions/checkout@v2 - run: | - brew install automake + brew install automake msgpack autoupdate ./autogen.sh ./configure From 17fcc8b76d28ae5e59b59a08a642e462eea34221 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 6 Aug 2022 13:57:59 +0800 Subject: [PATCH 144/150] fix MacOS.yml --- .github/workflows/MacOS.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/MacOS.yml b/.github/workflows/MacOS.yml index 37293260..3dc5247e 100644 --- a/.github/workflows/MacOS.yml +++ b/.github/workflows/MacOS.yml @@ -25,7 +25,7 @@ jobs: steps: - uses: actions/checkout@v2 - run: | - brew install automake msgpack + brew install automake msgpack libssh autoupdate ./autogen.sh ./configure From 9a1aa9ae9d9c40b6d583355246089a9468dd03bc Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 6 Aug 2022 14:29:15 +0800 Subject: [PATCH 145/150] add Ubuntu.yml --- .github/workflows/Ubuntu.yml | 37 ++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 .github/workflows/Ubuntu.yml diff --git a/.github/workflows/Ubuntu.yml b/.github/workflows/Ubuntu.yml new file mode 100644 index 00000000..581e616d --- /dev/null +++ b/.github/workflows/Ubuntu.yml @@ -0,0 +1,37 @@ +name: Ubuntu +on: + push: + branches: + - '*' + paths: + - '**.c' + - '**.h' + - 'compat/*' + - '.github/workflows/Ubuntu.yml' + pull_request: + branches: + - '*' + paths: + - '**.c' + - '**.h' + - 'compat/*' + - '.github/workflows/Ubuntu.yml' + + + +jobs: + Ubuntu: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - run: | + apt-get install -y build-essential automake libtool libevent-dev libncurses5-dev libmsgpack-dev libssh-dev pkg-config + autoupdate + ACLOCAL_PATH=/usr/share/aclocal ./autogen.sh + ./configure + make + make install + + + + From 2ff8bc134d381c88eba8f382625642e5aec8d5da Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 6 Aug 2022 14:33:12 +0800 Subject: [PATCH 146/150] fix Ubuntu.yml --- .github/workflows/Ubuntu.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/Ubuntu.yml b/.github/workflows/Ubuntu.yml index 581e616d..7c8dea57 100644 --- a/.github/workflows/Ubuntu.yml +++ b/.github/workflows/Ubuntu.yml @@ -25,7 +25,7 @@ jobs: steps: - uses: actions/checkout@v2 - run: | - apt-get install -y build-essential automake libtool libevent-dev libncurses5-dev libmsgpack-dev libssh-dev pkg-config + sudo apt-get install -y build-essential automake libtool libevent-dev libncurses5-dev libmsgpack-dev libssh-dev pkg-config autoupdate ACLOCAL_PATH=/usr/share/aclocal ./autogen.sh ./configure From 3efc8496cc90d55dd9bc44d4b5f529ac9760bf66 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 6 Aug 2022 14:34:47 +0800 Subject: [PATCH 147/150] fix Ubuntu.yml --- .github/workflows/Ubuntu.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/Ubuntu.yml b/.github/workflows/Ubuntu.yml index 7c8dea57..cecf39b9 100644 --- a/.github/workflows/Ubuntu.yml +++ b/.github/workflows/Ubuntu.yml @@ -30,7 +30,7 @@ jobs: ACLOCAL_PATH=/usr/share/aclocal ./autogen.sh ./configure make - make install + sudo make install From 15001bfa7739b144969c1181e66c65f0cb14e614 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 6 Aug 2022 14:57:15 +0800 Subject: [PATCH 148/150] fix --- .github/workflows/FreeBSD.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/FreeBSD.yml b/.github/workflows/FreeBSD.yml index 3a16af9f..e879618e 100644 --- a/.github/workflows/FreeBSD.yml +++ b/.github/workflows/FreeBSD.yml @@ -27,7 +27,7 @@ jobs: - uses: vmactions/freebsd-vm@v0 with: prepare: | - pkg install -y gmake automake autoconf libtool pkgconf libevent msgpack libssh + pkg install -y automake autoconf libtool pkgconf libevent msgpack libssh usesh: true run: | autoupdate From 6cb27ead4e77ba8cc15982d909fe57c074239434 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 6 Aug 2022 15:04:07 +0800 Subject: [PATCH 149/150] fix NetBSD.yml --- .github/workflows/NetBSD.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/NetBSD.yml b/.github/workflows/NetBSD.yml index 0566d3b9..0bb0924a 100644 --- a/.github/workflows/NetBSD.yml +++ b/.github/workflows/NetBSD.yml @@ -27,7 +27,7 @@ jobs: - uses: vmactions/netbsd-vm@v0 with: prepare: | - pkg_add gmake automake autoconf libtool pkgconf libevent msgpack libssh + pkg_add automake autoconf libtool pkgconf libevent msgpack libssh usesh: true run: | autoupdate From ac919516f4f1b10ec928e20b3a5034d18f609d68 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 6 Aug 2022 15:05:07 +0800 Subject: [PATCH 150/150] add DragonflyBSD by https://github.com/vmactions/dragonflybsd-vm --- .github/workflows/DragonflyBSD.yml | 41 ++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 .github/workflows/DragonflyBSD.yml diff --git a/.github/workflows/DragonflyBSD.yml b/.github/workflows/DragonflyBSD.yml new file mode 100644 index 00000000..f014da9b --- /dev/null +++ b/.github/workflows/DragonflyBSD.yml @@ -0,0 +1,41 @@ +name: DragonflyBSD +on: + push: + branches: + - '*' + paths: + - '**.c' + - '**.h' + - 'compat/*' + - '.github/workflows/DragonflyBSD.yml' + pull_request: + branches: + - '*' + paths: + - '**.c' + - '**.h' + - 'compat/*' + - '.github/workflows/DragonflyBSD.yml' + + + +jobs: + DragonflyBSD: + runs-on: macos-12 + steps: + - uses: actions/checkout@v2 + - uses: vmactions/dragonflybsd-vm@v0 + with: + prepare: | + pkg install -y automake autoconf libtool pkgconf libevent msgpack libssh gsed + usesh: true + run: | + gsed -i "s/OK/0/g" tty-term.c + autoupdate + ./autogen.sh + ./configure + make + make install + + +