mirror of
https://github.com/tmate-io/tmate-ssh-server.git
synced 2020-11-18 19:53:51 -08:00
Slave implementation draft
This commit is contained in:
parent
1b083aa0fd
commit
dbc4ecc92d
4
.gitignore
vendored
4
.gitignore
vendored
@ -15,3 +15,7 @@ tmux
|
|||||||
Makefile
|
Makefile
|
||||||
Makefile.in
|
Makefile.in
|
||||||
configure
|
configure
|
||||||
|
keys/
|
||||||
|
tmate-server
|
||||||
|
cscope.*
|
||||||
|
tags
|
||||||
|
64
Makefile.am
64
Makefile.am
@ -1,8 +1,8 @@
|
|||||||
# $Id$
|
# $Id$
|
||||||
|
|
||||||
# Obvious program stuff.
|
# Obvious program stuff.
|
||||||
bin_PROGRAMS = tmux
|
bin_PROGRAMS = tmate-server
|
||||||
dist_man1_MANS = tmux.1
|
dist_man1_MANS = tmate.1
|
||||||
|
|
||||||
# Distribution tarball options.
|
# Distribution tarball options.
|
||||||
EXTRA_DIST = \
|
EXTRA_DIST = \
|
||||||
@ -21,6 +21,9 @@ if IS_GLIBC
|
|||||||
CFLAGS += -D_GNU_SOURCE
|
CFLAGS += -D_GNU_SOURCE
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
CFLAGS += -Wno-unused-parameter -Wno-unused-variable
|
||||||
|
|
||||||
|
|
||||||
# Set flags for gcc. gcc4 whines abouts silly stuff so it needs slightly
|
# Set flags for gcc. gcc4 whines abouts silly stuff so it needs slightly
|
||||||
# different flags.
|
# different flags.
|
||||||
if IS_GCC
|
if IS_GCC
|
||||||
@ -57,7 +60,7 @@ CFLAGS += -erroff=E_EMPTY_DECLARATION
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
# List of sources.
|
# List of sources.
|
||||||
dist_tmux_SOURCES = \
|
dist_tmate_server_SOURCES = \
|
||||||
arguments.c \
|
arguments.c \
|
||||||
attributes.c \
|
attributes.c \
|
||||||
cfg.c \
|
cfg.c \
|
||||||
@ -171,7 +174,13 @@ dist_tmux_SOURCES = \
|
|||||||
session.c \
|
session.c \
|
||||||
signal.c \
|
signal.c \
|
||||||
status.c \
|
status.c \
|
||||||
tmux.c \
|
tmate-debug.c \
|
||||||
|
tmate-decoder.c \
|
||||||
|
tmate-encoder.c \
|
||||||
|
tmate-server.c \
|
||||||
|
tmate-ssh-client-pty.c \
|
||||||
|
tmate-ssh-client.c \
|
||||||
|
tmate-ssh-server.c \
|
||||||
tty-acs.c \
|
tty-acs.c \
|
||||||
tty-keys.c \
|
tty-keys.c \
|
||||||
tty-term.c \
|
tty-term.c \
|
||||||
@ -183,66 +192,51 @@ dist_tmux_SOURCES = \
|
|||||||
window.c \
|
window.c \
|
||||||
xmalloc.c \
|
xmalloc.c \
|
||||||
xterm-keys.c
|
xterm-keys.c
|
||||||
nodist_tmux_SOURCES = osdep-@PLATFORM@.c
|
nodist_tmate_server_SOURCES = osdep-@PLATFORM@.c
|
||||||
|
|
||||||
# Pile in all the compat/ stuff that is needed.
|
# Pile in all the compat/ stuff that is needed.
|
||||||
if NO_FORKPTY
|
if NO_FORKPTY
|
||||||
nodist_tmux_SOURCES += compat/forkpty-@PLATFORM@.c
|
nodist_tmate_server_SOURCES += compat/forkpty-@PLATFORM@.c
|
||||||
endif
|
endif
|
||||||
if NO_IMSG
|
if NO_IMSG
|
||||||
nodist_tmux_SOURCES += compat/imsg.c compat/imsg-buffer.c
|
nodist_tmate_server_SOURCES += compat/imsg.c compat/imsg-buffer.c
|
||||||
endif
|
endif
|
||||||
if NO_CLOSEFROM
|
if NO_CLOSEFROM
|
||||||
nodist_tmux_SOURCES += compat/closefrom.c
|
nodist_tmate_server_SOURCES += compat/closefrom.c
|
||||||
endif
|
endif
|
||||||
if NO_DAEMON
|
if NO_DAEMON
|
||||||
nodist_tmux_SOURCES += compat/daemon.c
|
nodist_tmate_server_SOURCES += compat/daemon.c
|
||||||
endif
|
endif
|
||||||
if NO_SETENV
|
if NO_SETENV
|
||||||
nodist_tmux_SOURCES += compat/setenv.c
|
nodist_tmate_server_SOURCES += compat/setenv.c
|
||||||
endif
|
endif
|
||||||
if NO_STRLCAT
|
if NO_STRLCAT
|
||||||
nodist_tmux_SOURCES += compat/strlcat.c
|
nodist_tmate_server_SOURCES += compat/strlcat.c
|
||||||
endif
|
endif
|
||||||
if NO_STRLCPY
|
if NO_STRLCPY
|
||||||
nodist_tmux_SOURCES += compat/strlcpy.c
|
nodist_tmate_server_SOURCES += compat/strlcpy.c
|
||||||
endif
|
endif
|
||||||
if NO_ASPRINTF
|
if NO_ASPRINTF
|
||||||
nodist_tmux_SOURCES += compat/asprintf.c
|
nodist_tmate_server_SOURCES += compat/asprintf.c
|
||||||
endif
|
endif
|
||||||
if NO_FGETLN
|
if NO_FGETLN
|
||||||
nodist_tmux_SOURCES += compat/fgetln.c
|
nodist_tmate_server_SOURCES += compat/fgetln.c
|
||||||
endif
|
endif
|
||||||
if NO_GETOPT
|
if NO_GETOPT
|
||||||
nodist_tmux_SOURCES += compat/getopt.c
|
nodist_tmate_server_SOURCES += compat/getopt.c
|
||||||
endif
|
endif
|
||||||
if NO_STRCASESTR
|
if NO_STRCASESTR
|
||||||
nodist_tmux_SOURCES += compat/strcasestr.c
|
nodist_tmate_server_SOURCES += compat/strcasestr.c
|
||||||
endif
|
endif
|
||||||
if NO_STRSEP
|
if NO_STRSEP
|
||||||
nodist_tmux_SOURCES += compat/strsep.c
|
nodist_tmate_server_SOURCES += compat/strsep.c
|
||||||
endif
|
endif
|
||||||
if NO_VIS
|
if NO_VIS
|
||||||
nodist_tmux_SOURCES += compat/vis.c compat/unvis.c
|
nodist_tmate_server_SOURCES += compat/vis.c compat/unvis.c
|
||||||
endif
|
endif
|
||||||
if NO_STRTONUM
|
if NO_STRTONUM
|
||||||
nodist_tmux_SOURCES += compat/strtonum.c
|
nodist_tmate_server_SOURCES += compat/strtonum.c
|
||||||
endif
|
endif
|
||||||
if NO_B64_NTOP
|
if NO_B64_NTOP
|
||||||
nodist_tmux_SOURCES += compat/b64_ntop.c
|
nodist_tmate_server_SOURCES += compat/b64_ntop.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Update SF web site.
|
|
||||||
upload-index.html: update-index.html
|
|
||||||
scp www/index.html www/main.css www/images/*.png \
|
|
||||||
${USER},tmux@web.sf.net:/home/groups/t/tm/tmux/htdocs
|
|
||||||
rm -f www/index.html www/images/small-*
|
|
||||||
|
|
||||||
update-index.html:
|
|
||||||
(cd www/images && \
|
|
||||||
rm -f small-* && \
|
|
||||||
for i in *.png; do \
|
|
||||||
convert "$$i" -resize 200x150 "small-$$i"; \
|
|
||||||
done \
|
|
||||||
)
|
|
||||||
sed "s/%%VERSION%%/${VERSION}/g" www/index.html.in >www/index.html
|
|
||||||
|
13
client.c
13
client.c
@ -205,6 +205,10 @@ client_main(int argc, char **argv, int flags)
|
|||||||
cmd_list_free(cmdlist);
|
cmd_list_free(cmdlist);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef TMATE_SLAVE
|
||||||
|
cmdflags &= ~CMD_STARTSERVER;
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check if this could be a nested session, if the command can't nest:
|
* Check if this could be a nested session, if the command can't nest:
|
||||||
* if the socket path matches $TMUX, this is probably the same server.
|
* if the socket path matches $TMUX, this is probably the same server.
|
||||||
@ -228,7 +232,6 @@ client_main(int argc, char **argv, int flags)
|
|||||||
#ifdef HAVE_SETPROCTITLE
|
#ifdef HAVE_SETPROCTITLE
|
||||||
setproctitle("client (%s)", socket_path);
|
setproctitle("client (%s)", socket_path);
|
||||||
#endif
|
#endif
|
||||||
logfile("client");
|
|
||||||
|
|
||||||
/* Create imsg. */
|
/* Create imsg. */
|
||||||
imsg_init(&client_ibuf, fd);
|
imsg_init(&client_ibuf, fd);
|
||||||
@ -505,7 +508,7 @@ client_dispatch_wait(void *data)
|
|||||||
return (0);
|
return (0);
|
||||||
datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
|
datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
|
||||||
|
|
||||||
log_debug("got %d from server", imsg.hdr.type);
|
log_debug2("got %d from server", imsg.hdr.type);
|
||||||
switch (imsg.hdr.type) {
|
switch (imsg.hdr.type) {
|
||||||
case MSG_EXIT:
|
case MSG_EXIT:
|
||||||
case MSG_SHUTDOWN:
|
case MSG_SHUTDOWN:
|
||||||
@ -544,7 +547,7 @@ client_dispatch_wait(void *data)
|
|||||||
fatalx("bad MSG_STDERR");
|
fatalx("bad MSG_STDERR");
|
||||||
memcpy(&stderrdata, imsg.data, sizeof stderrdata);
|
memcpy(&stderrdata, imsg.data, sizeof stderrdata);
|
||||||
|
|
||||||
client_write(STDERR_FILENO, stderrdata.data, stderrdata.size);
|
client_write(fileno(stderr), stderrdata.data, stderrdata.size);
|
||||||
break;
|
break;
|
||||||
case MSG_VERSION:
|
case MSG_VERSION:
|
||||||
if (datalen != 0)
|
if (datalen != 0)
|
||||||
@ -565,7 +568,7 @@ client_dispatch_wait(void *data)
|
|||||||
|
|
||||||
clear_signals(0);
|
clear_signals(0);
|
||||||
|
|
||||||
shell_exec(shelldata.shell, shellcmd);
|
exit(1);
|
||||||
/* NOTREACHED */
|
/* NOTREACHED */
|
||||||
case MSG_DETACH:
|
case MSG_DETACH:
|
||||||
client_write_server(MSG_EXITING, NULL, 0);
|
client_write_server(MSG_EXITING, NULL, 0);
|
||||||
@ -597,7 +600,7 @@ client_dispatch_attached(void)
|
|||||||
return (0);
|
return (0);
|
||||||
datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
|
datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
|
||||||
|
|
||||||
log_debug("got %d from server", imsg.hdr.type);
|
log_debug2("got %d from server", imsg.hdr.type);
|
||||||
switch (imsg.hdr.type) {
|
switch (imsg.hdr.type) {
|
||||||
case MSG_DETACHKILL:
|
case MSG_DETACHKILL:
|
||||||
case MSG_DETACH:
|
case MSG_DETACH:
|
||||||
|
@ -45,6 +45,9 @@ const struct cmd_entry cmd_paste_buffer_entry = {
|
|||||||
enum cmd_retval
|
enum cmd_retval
|
||||||
cmd_paste_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
|
cmd_paste_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
|
||||||
{
|
{
|
||||||
|
#ifdef TMATE_SLAVE
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
#else
|
||||||
struct args *args = self->args;
|
struct args *args = self->args;
|
||||||
struct window_pane *wp;
|
struct window_pane *wp;
|
||||||
struct session *s;
|
struct session *s;
|
||||||
@ -99,4 +102,5 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -48,6 +48,9 @@ const struct cmd_entry cmd_pipe_pane_entry = {
|
|||||||
enum cmd_retval
|
enum cmd_retval
|
||||||
cmd_pipe_pane_exec(struct cmd *self, struct cmd_q *cmdq)
|
cmd_pipe_pane_exec(struct cmd *self, struct cmd_q *cmdq)
|
||||||
{
|
{
|
||||||
|
#ifdef TMATE_SLAVE
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
#else
|
||||||
struct args *args = self->args;
|
struct args *args = self->args;
|
||||||
struct client *c;
|
struct client *c;
|
||||||
struct window_pane *wp;
|
struct window_pane *wp;
|
||||||
@ -128,6 +131,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_q *cmdq)
|
|||||||
setblocking(wp->pipe_fd, 0);
|
setblocking(wp->pipe_fd, 0);
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -43,6 +43,9 @@ const struct cmd_entry cmd_respawn_pane_entry = {
|
|||||||
enum cmd_retval
|
enum cmd_retval
|
||||||
cmd_respawn_pane_exec(struct cmd *self, struct cmd_q *cmdq)
|
cmd_respawn_pane_exec(struct cmd *self, struct cmd_q *cmdq)
|
||||||
{
|
{
|
||||||
|
#ifdef TMATE_SLAVE
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
#else
|
||||||
struct args *args = self->args;
|
struct args *args = self->args;
|
||||||
struct winlink *wl;
|
struct winlink *wl;
|
||||||
struct window *w;
|
struct window *w;
|
||||||
@ -89,4 +92,5 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmd_q *cmdq)
|
|||||||
|
|
||||||
environ_free(&env);
|
environ_free(&env);
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,9 @@ const struct cmd_entry cmd_respawn_window_entry = {
|
|||||||
enum cmd_retval
|
enum cmd_retval
|
||||||
cmd_respawn_window_exec(struct cmd *self, struct cmd_q *cmdq)
|
cmd_respawn_window_exec(struct cmd *self, struct cmd_q *cmdq)
|
||||||
{
|
{
|
||||||
|
#ifdef TMATE_SLAVE
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
#else
|
||||||
struct args *args = self->args;
|
struct args *args = self->args;
|
||||||
struct winlink *wl;
|
struct winlink *wl;
|
||||||
struct window *w;
|
struct window *w;
|
||||||
@ -98,4 +101,5 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_q *cmdq)
|
|||||||
|
|
||||||
environ_free(&env);
|
environ_free(&env);
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -52,6 +52,9 @@ const struct cmd_entry cmd_send_prefix_entry = {
|
|||||||
enum cmd_retval
|
enum cmd_retval
|
||||||
cmd_send_keys_exec(struct cmd *self, struct cmd_q *cmdq)
|
cmd_send_keys_exec(struct cmd *self, struct cmd_q *cmdq)
|
||||||
{
|
{
|
||||||
|
#ifdef TMATE_SLAVE
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
#else
|
||||||
struct args *args = self->args;
|
struct args *args = self->args;
|
||||||
struct window_pane *wp;
|
struct window_pane *wp;
|
||||||
struct session *s;
|
struct session *s;
|
||||||
@ -100,4 +103,5 @@ cmd_send_keys_exec(struct cmd *self, struct cmd_q *cmdq)
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -123,8 +123,8 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_q *cmdq)
|
|||||||
sizeof *gl->celldata;
|
sizeof *gl->celldata;
|
||||||
}
|
}
|
||||||
cmdq_print(cmdq,
|
cmdq_print(cmdq,
|
||||||
"%6u: %s %lu %d %u/%u, %zu bytes", j,
|
"%6u: %s %lu %u/%u, %zu bytes", j,
|
||||||
wp->tty, (u_long) wp->pid, wp->fd, lines,
|
wp->tty, (u_long) wp->pid, lines,
|
||||||
gd->hsize + gd->sy, size);
|
gd->hsize + gd->sy, size);
|
||||||
j++;
|
j++;
|
||||||
}
|
}
|
||||||
|
@ -161,6 +161,7 @@ cmd_set_option_exec(struct cmd *self, struct cmd_q *cmdq)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Start or stop timers when automatic-rename changed. */
|
/* Start or stop timers when automatic-rename changed. */
|
||||||
|
#ifndef TMATE_SLAVE
|
||||||
if (strcmp (oe->name, "automatic-rename") == 0) {
|
if (strcmp (oe->name, "automatic-rename") == 0) {
|
||||||
for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
|
for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
|
||||||
if ((w = ARRAY_ITEM(&windows, i)) == NULL)
|
if ((w = ARRAY_ITEM(&windows, i)) == NULL)
|
||||||
@ -171,6 +172,7 @@ cmd_set_option_exec(struct cmd *self, struct cmd_q *cmdq)
|
|||||||
evtimer_del(&w->name_timer);
|
evtimer_del(&w->name_timer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Update sizes and redraw. May not need it but meh. */
|
/* Update sizes and redraw. May not need it but meh. */
|
||||||
recalculate_sizes();
|
recalculate_sizes();
|
||||||
|
@ -52,6 +52,9 @@ cmd_split_window_key_binding(struct cmd *self, int key)
|
|||||||
enum cmd_retval
|
enum cmd_retval
|
||||||
cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq)
|
cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq)
|
||||||
{
|
{
|
||||||
|
#ifdef TMATE_SLAVE
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
#else
|
||||||
struct args *args = self->args;
|
struct args *args = self->args;
|
||||||
struct session *s;
|
struct session *s;
|
||||||
struct winlink *wl;
|
struct winlink *wl;
|
||||||
@ -113,9 +116,7 @@ cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq)
|
|||||||
}
|
}
|
||||||
hlimit = options_get_number(&s->options, "history-limit");
|
hlimit = options_get_number(&s->options, "history-limit");
|
||||||
|
|
||||||
shell = options_get_string(&s->options, "default-shell");
|
shell = _PATH_BSHELL;
|
||||||
if (*shell == '\0' || areshell(shell))
|
|
||||||
shell = _PATH_BSHELL;
|
|
||||||
|
|
||||||
if ((lc = layout_split_pane(wp, type, size, 0)) == NULL) {
|
if ((lc = layout_split_pane(wp, type, size, 0)) == NULL) {
|
||||||
cause = xstrdup("pane too small");
|
cause = xstrdup("pane too small");
|
||||||
@ -165,4 +166,5 @@ error:
|
|||||||
cmdq_error(cmdq, "create pane failed: %s", cause);
|
cmdq_error(cmdq, "create pane failed: %s", cause);
|
||||||
free(cause);
|
free(cause);
|
||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
4
cmd.c
4
cmd.c
@ -1290,6 +1290,9 @@ cmd_template_replace(const char *template, const char *s, int idx)
|
|||||||
const char *
|
const char *
|
||||||
cmd_get_default_path(struct cmd_q *cmdq, const char *cwd)
|
cmd_get_default_path(struct cmd_q *cmdq, const char *cwd)
|
||||||
{
|
{
|
||||||
|
#ifdef TMATE_SLAVE
|
||||||
|
return NULL;
|
||||||
|
#else
|
||||||
struct client *c = cmdq->client;
|
struct client *c = cmdq->client;
|
||||||
struct session *s;
|
struct session *s;
|
||||||
struct environ_entry *envent;
|
struct environ_entry *envent;
|
||||||
@ -1361,4 +1364,5 @@ complete_path:
|
|||||||
if (n > 0 && (size_t)n < sizeof path)
|
if (n > 0 && (size_t)n < sizeof path)
|
||||||
return (path);
|
return (path);
|
||||||
return (s->cwd);
|
return (s->cwd);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -107,6 +107,9 @@ AC_MSG_RESULT($found_glibc)
|
|||||||
# Look for clock_gettime. Must come before event_init.
|
# Look for clock_gettime. Must come before event_init.
|
||||||
AC_SEARCH_LIBS(clock_gettime, rt)
|
AC_SEARCH_LIBS(clock_gettime, rt)
|
||||||
|
|
||||||
|
AC_SEARCH_LIBS(ssh_new, ssh)
|
||||||
|
AC_SEARCH_LIBS(msgpack_object_print, msgpack)
|
||||||
|
|
||||||
# Look for libevent.
|
# Look for libevent.
|
||||||
PKG_CHECK_MODULES(
|
PKG_CHECK_MODULES(
|
||||||
LIBEVENT,
|
LIBEVENT,
|
||||||
|
13
create_keys.sh
Executable file
13
create_keys.sh
Executable file
@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
gen_key() {
|
||||||
|
keytype=$1
|
||||||
|
ks="${keytype}_"
|
||||||
|
key="keys/ssh_host_${ks}key"
|
||||||
|
if [ ! -e "${key}" ] ; then
|
||||||
|
ssh-keygen -t ${keytype} -f "${key}" -N ''
|
||||||
|
return $?
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
mkdir -p keys
|
||||||
|
gen_key dsa && gen_key rsa && gen_key ecdsa || exit 1
|
4
format.c
4
format.c
@ -421,7 +421,9 @@ format_window_pane(struct format_tree *ft, struct window_pane *wp)
|
|||||||
format_add(ft, "pane_title", "%s", wp->base.title);
|
format_add(ft, "pane_title", "%s", wp->base.title);
|
||||||
format_add(ft, "pane_id", "%%%u", wp->id);
|
format_add(ft, "pane_id", "%%%u", wp->id);
|
||||||
format_add(ft, "pane_active", "%d", wp == wp->window->active);
|
format_add(ft, "pane_active", "%d", wp == wp->window->active);
|
||||||
|
#ifndef TMATE_SLAVE
|
||||||
format_add(ft, "pane_dead", "%d", wp->fd == -1);
|
format_add(ft, "pane_dead", "%d", wp->fd == -1);
|
||||||
|
#endif
|
||||||
|
|
||||||
format_add(ft, "pane_in_mode", "%d", wp->screen != &wp->base);
|
format_add(ft, "pane_in_mode", "%d", wp->screen != &wp->base);
|
||||||
|
|
||||||
@ -432,12 +434,14 @@ format_window_pane(struct format_tree *ft, struct window_pane *wp)
|
|||||||
format_add(ft, "pane_start_command", "%s", wp->cmd);
|
format_add(ft, "pane_start_command", "%s", wp->cmd);
|
||||||
if (wp->cwd != NULL)
|
if (wp->cwd != NULL)
|
||||||
format_add(ft, "pane_start_path", "%s", wp->cwd);
|
format_add(ft, "pane_start_path", "%s", wp->cwd);
|
||||||
|
#ifndef TMATE_SLAVE
|
||||||
if ((cwd = osdep_get_cwd(wp->fd)) != NULL)
|
if ((cwd = osdep_get_cwd(wp->fd)) != NULL)
|
||||||
format_add(ft, "pane_current_path", "%s", cwd);
|
format_add(ft, "pane_current_path", "%s", cwd);
|
||||||
if ((cmd = osdep_get_name(wp->fd, wp->tty)) != NULL) {
|
if ((cmd = osdep_get_name(wp->fd, wp->tty)) != NULL) {
|
||||||
format_add(ft, "pane_current_command", "%s", cmd);
|
format_add(ft, "pane_current_command", "%s", cmd);
|
||||||
free(cmd);
|
free(cmd);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
format_add(ft, "cursor_x", "%d", wp->base.cx);
|
format_add(ft, "cursor_x", "%d", wp->base.cx);
|
||||||
format_add(ft, "cursor_y", "%d", wp->base.cy);
|
format_add(ft, "cursor_y", "%d", wp->base.cy);
|
||||||
|
@ -23,6 +23,8 @@
|
|||||||
|
|
||||||
#include "tmux.h"
|
#include "tmux.h"
|
||||||
|
|
||||||
|
#ifndef TMATE_SLAVE
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This file is rather misleadingly named, it contains the code which takes a
|
* This file is rather misleadingly named, it contains the code which takes a
|
||||||
* key code and translates it into something suitable to be sent to the
|
* key code and translates it into something suitable to be sent to the
|
||||||
@ -253,3 +255,5 @@ input_mouse(struct window_pane *wp, struct session *s, struct mouse_event *m)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
62
input.c
62
input.c
@ -732,7 +732,11 @@ input_parse(struct window_pane *wp)
|
|||||||
{
|
{
|
||||||
struct input_ctx *ictx = &wp->ictx;
|
struct input_ctx *ictx = &wp->ictx;
|
||||||
const struct input_transition *itr;
|
const struct input_transition *itr;
|
||||||
|
#ifdef TMATE_SLAVE
|
||||||
|
struct evbuffer *evb = wp->event_input;
|
||||||
|
#else
|
||||||
struct evbuffer *evb = wp->event->input;
|
struct evbuffer *evb = wp->event->input;
|
||||||
|
#endif
|
||||||
u_char *buf;
|
u_char *buf;
|
||||||
size_t len, off;
|
size_t len, off;
|
||||||
|
|
||||||
@ -760,7 +764,7 @@ input_parse(struct window_pane *wp)
|
|||||||
/* Parse the input. */
|
/* Parse the input. */
|
||||||
while (off < len) {
|
while (off < len) {
|
||||||
ictx->ch = buf[off++];
|
ictx->ch = buf[off++];
|
||||||
log_debug("%s: '%c' %s", __func__, ictx->ch, ictx->state->name);
|
log_debug2("%s: '%c' %s", __func__, ictx->ch, ictx->state->name);
|
||||||
|
|
||||||
/* Find the transition. */
|
/* Find the transition. */
|
||||||
itr = ictx->state->transitions;
|
itr = ictx->state->transitions;
|
||||||
@ -848,6 +852,7 @@ input_get(struct input_ctx *ictx, u_int validx, int minval, int defval)
|
|||||||
void
|
void
|
||||||
input_reply(struct input_ctx *ictx, const char *fmt, ...)
|
input_reply(struct input_ctx *ictx, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
|
#ifndef TMATE_SLAVE
|
||||||
va_list ap;
|
va_list ap;
|
||||||
char *reply;
|
char *reply;
|
||||||
|
|
||||||
@ -857,6 +862,7 @@ input_reply(struct input_ctx *ictx, const char *fmt, ...)
|
|||||||
|
|
||||||
bufferevent_write(ictx->wp->event, reply, strlen(reply));
|
bufferevent_write(ictx->wp->event, reply, strlen(reply));
|
||||||
free(reply);
|
free(reply);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clear saved state. */
|
/* Clear saved state. */
|
||||||
@ -936,7 +942,7 @@ input_c0_dispatch(struct input_ctx *ictx)
|
|||||||
struct screen *s = sctx->s;
|
struct screen *s = sctx->s;
|
||||||
u_int trigger;
|
u_int trigger;
|
||||||
|
|
||||||
log_debug("%s: '%c", __func__, ictx->ch);
|
log_debug2("%s: '%c", __func__, ictx->ch);
|
||||||
|
|
||||||
switch (ictx->ch) {
|
switch (ictx->ch) {
|
||||||
case '\000': /* NUL */
|
case '\000': /* NUL */
|
||||||
@ -974,7 +980,7 @@ input_c0_dispatch(struct input_ctx *ictx)
|
|||||||
ictx->cell.attr &= ~GRID_ATTR_CHARSET;
|
ictx->cell.attr &= ~GRID_ATTR_CHARSET;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
log_debug("%s: unknown '%c'", __func__, ictx->ch);
|
log_debug2("%s: unknown '%c'", __func__, ictx->ch);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1000,12 +1006,12 @@ input_esc_dispatch(struct input_ctx *ictx)
|
|||||||
|
|
||||||
if (ictx->flags & INPUT_DISCARD)
|
if (ictx->flags & INPUT_DISCARD)
|
||||||
return (0);
|
return (0);
|
||||||
log_debug("%s: '%c', %s", __func__, ictx->ch, ictx->interm_buf);
|
log_debug2("%s: '%c', %s", __func__, ictx->ch, ictx->interm_buf);
|
||||||
|
|
||||||
entry = bsearch(ictx, input_esc_table, nitems(input_esc_table),
|
entry = bsearch(ictx, input_esc_table, nitems(input_esc_table),
|
||||||
sizeof input_esc_table[0], input_table_compare);
|
sizeof input_esc_table[0], input_table_compare);
|
||||||
if (entry == NULL) {
|
if (entry == NULL) {
|
||||||
log_debug("%s: unknown '%c'", __func__, ictx->ch);
|
log_debug2("%s: unknown '%c'", __func__, ictx->ch);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1080,13 +1086,13 @@ input_csi_dispatch(struct input_ctx *ictx)
|
|||||||
return (0);
|
return (0);
|
||||||
if (input_split(ictx) != 0)
|
if (input_split(ictx) != 0)
|
||||||
return (0);
|
return (0);
|
||||||
log_debug("%s: '%c' \"%s\" \"%s\"",
|
log_debug2("%s: '%c' \"%s\" \"%s\"",
|
||||||
__func__, ictx->ch, ictx->interm_buf, ictx->param_buf);
|
__func__, ictx->ch, ictx->interm_buf, ictx->param_buf);
|
||||||
|
|
||||||
entry = bsearch(ictx, input_csi_table, nitems(input_csi_table),
|
entry = bsearch(ictx, input_csi_table, nitems(input_csi_table),
|
||||||
sizeof input_csi_table[0], input_table_compare);
|
sizeof input_csi_table[0], input_table_compare);
|
||||||
if (entry == NULL) {
|
if (entry == NULL) {
|
||||||
log_debug("%s: unknown '%c'", __func__, ictx->ch);
|
log_debug2("%s: unknown '%c'", __func__, ictx->ch);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1131,7 +1137,7 @@ input_csi_dispatch(struct input_ctx *ictx)
|
|||||||
input_reply(ictx, "\033[?1;2c");
|
input_reply(ictx, "\033[?1;2c");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
log_debug("%s: unknown '%c'", __func__, ictx->ch);
|
log_debug2("%s: unknown '%c'", __func__, ictx->ch);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1141,7 +1147,7 @@ input_csi_dispatch(struct input_ctx *ictx)
|
|||||||
input_reply(ictx, "\033[>0;95;0c");
|
input_reply(ictx, "\033[>0;95;0c");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
log_debug("%s: unknown '%c'", __func__, ictx->ch);
|
log_debug2("%s: unknown '%c'", __func__, ictx->ch);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1168,7 +1174,7 @@ input_csi_dispatch(struct input_ctx *ictx)
|
|||||||
input_reply(ictx, "\033[%u;%uR", s->cy + 1, s->cx + 1);
|
input_reply(ictx, "\033[%u;%uR", s->cy + 1, s->cx + 1);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
log_debug("%s: unknown '%c'", __func__, ictx->ch);
|
log_debug2("%s: unknown '%c'", __func__, ictx->ch);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1195,7 +1201,7 @@ input_csi_dispatch(struct input_ctx *ictx)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
log_debug("%s: unknown '%c'", __func__, ictx->ch);
|
log_debug2("%s: unknown '%c'", __func__, ictx->ch);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1211,7 +1217,7 @@ input_csi_dispatch(struct input_ctx *ictx)
|
|||||||
screen_write_clearline(sctx);
|
screen_write_clearline(sctx);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
log_debug("%s: unknown '%c'", __func__, ictx->ch);
|
log_debug2("%s: unknown '%c'", __func__, ictx->ch);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1235,7 +1241,7 @@ input_csi_dispatch(struct input_ctx *ictx)
|
|||||||
screen_write_mode_clear(&ictx->ctx, MODE_INSERT);
|
screen_write_mode_clear(&ictx->ctx, MODE_INSERT);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
log_debug("%s: unknown '%c'", __func__, ictx->ch);
|
log_debug2("%s: unknown '%c'", __func__, ictx->ch);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1280,7 +1286,7 @@ input_csi_dispatch(struct input_ctx *ictx)
|
|||||||
screen_write_mode_clear(&ictx->ctx, MODE_BRACKETPASTE);
|
screen_write_mode_clear(&ictx->ctx, MODE_BRACKETPASTE);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
log_debug("%s: unknown '%c'", __func__, ictx->ch);
|
log_debug2("%s: unknown '%c'", __func__, ictx->ch);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1298,7 +1304,7 @@ input_csi_dispatch(struct input_ctx *ictx)
|
|||||||
screen_write_mode_set(&ictx->ctx, MODE_INSERT);
|
screen_write_mode_set(&ictx->ctx, MODE_INSERT);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
log_debug("%s: unknown '%c'", __func__, ictx->ch);
|
log_debug2("%s: unknown '%c'", __func__, ictx->ch);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1352,7 +1358,7 @@ input_csi_dispatch(struct input_ctx *ictx)
|
|||||||
screen_write_mode_set(&ictx->ctx, MODE_BRACKETPASTE);
|
screen_write_mode_set(&ictx->ctx, MODE_BRACKETPASTE);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
log_debug("%s: unknown '%c'", __func__, ictx->ch);
|
log_debug2("%s: unknown '%c'", __func__, ictx->ch);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1366,7 +1372,7 @@ input_csi_dispatch(struct input_ctx *ictx)
|
|||||||
bit_nclear(s->tabs, 0, screen_size_x(s) - 1);
|
bit_nclear(s->tabs, 0, screen_size_x(s) - 1);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
log_debug("%s: unknown '%c'", __func__, ictx->ch);
|
log_debug2("%s: unknown '%c'", __func__, ictx->ch);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1539,7 +1545,7 @@ input_dcs_dispatch(struct input_ctx *ictx)
|
|||||||
if (ictx->flags & INPUT_DISCARD)
|
if (ictx->flags & INPUT_DISCARD)
|
||||||
return (0);
|
return (0);
|
||||||
|
|
||||||
log_debug("%s: \"%s\"", __func__, ictx->input_buf);
|
log_debug2("%s: \"%s\"", __func__, ictx->input_buf);
|
||||||
|
|
||||||
/* Check for tmux prefix. */
|
/* Check for tmux prefix. */
|
||||||
if (ictx->input_len >= prefix_len &&
|
if (ictx->input_len >= prefix_len &&
|
||||||
@ -1555,7 +1561,7 @@ input_dcs_dispatch(struct input_ctx *ictx)
|
|||||||
void
|
void
|
||||||
input_enter_osc(struct input_ctx *ictx)
|
input_enter_osc(struct input_ctx *ictx)
|
||||||
{
|
{
|
||||||
log_debug("%s", __func__);
|
log_debug2("%s", __func__);
|
||||||
|
|
||||||
input_clear(ictx);
|
input_clear(ictx);
|
||||||
}
|
}
|
||||||
@ -1572,7 +1578,7 @@ input_exit_osc(struct input_ctx *ictx)
|
|||||||
if (ictx->input_len < 1 || *p < '0' || *p > '9')
|
if (ictx->input_len < 1 || *p < '0' || *p > '9')
|
||||||
return;
|
return;
|
||||||
|
|
||||||
log_debug("%s: \"%s\"", __func__, p);
|
log_debug2("%s: \"%s\"", __func__, p);
|
||||||
|
|
||||||
option = 0;
|
option = 0;
|
||||||
while (*p >= '0' && *p <= '9')
|
while (*p >= '0' && *p <= '9')
|
||||||
@ -1595,7 +1601,7 @@ input_exit_osc(struct input_ctx *ictx)
|
|||||||
screen_set_cursor_colour(ictx->ctx.s, "");
|
screen_set_cursor_colour(ictx->ctx.s, "");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
log_debug("%s: unknown '%u'", __func__, option);
|
log_debug2("%s: unknown '%u'", __func__, option);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1604,7 +1610,7 @@ input_exit_osc(struct input_ctx *ictx)
|
|||||||
void
|
void
|
||||||
input_enter_apc(struct input_ctx *ictx)
|
input_enter_apc(struct input_ctx *ictx)
|
||||||
{
|
{
|
||||||
log_debug("%s", __func__);
|
log_debug2("%s", __func__);
|
||||||
|
|
||||||
input_clear(ictx);
|
input_clear(ictx);
|
||||||
}
|
}
|
||||||
@ -1615,7 +1621,7 @@ input_exit_apc(struct input_ctx *ictx)
|
|||||||
{
|
{
|
||||||
if (ictx->flags & INPUT_DISCARD)
|
if (ictx->flags & INPUT_DISCARD)
|
||||||
return;
|
return;
|
||||||
log_debug("%s: \"%s\"", __func__, ictx->input_buf);
|
log_debug2("%s: \"%s\"", __func__, ictx->input_buf);
|
||||||
|
|
||||||
screen_set_title(ictx->ctx.s, ictx->input_buf);
|
screen_set_title(ictx->ctx.s, ictx->input_buf);
|
||||||
server_status_window(ictx->wp->window);
|
server_status_window(ictx->wp->window);
|
||||||
@ -1625,7 +1631,7 @@ input_exit_apc(struct input_ctx *ictx)
|
|||||||
void
|
void
|
||||||
input_enter_rename(struct input_ctx *ictx)
|
input_enter_rename(struct input_ctx *ictx)
|
||||||
{
|
{
|
||||||
log_debug("%s", __func__);
|
log_debug2("%s", __func__);
|
||||||
|
|
||||||
input_clear(ictx);
|
input_clear(ictx);
|
||||||
}
|
}
|
||||||
@ -1638,7 +1644,7 @@ input_exit_rename(struct input_ctx *ictx)
|
|||||||
return;
|
return;
|
||||||
if (!options_get_number(&ictx->wp->window->options, "allow-rename"))
|
if (!options_get_number(&ictx->wp->window->options, "allow-rename"))
|
||||||
return;
|
return;
|
||||||
log_debug("%s: \"%s\"", __func__, ictx->input_buf);
|
log_debug2("%s: \"%s\"", __func__, ictx->input_buf);
|
||||||
|
|
||||||
window_set_name(ictx->wp->window, ictx->input_buf);
|
window_set_name(ictx->wp->window, ictx->input_buf);
|
||||||
options_set_number(&ictx->wp->window->options, "automatic-rename", 0);
|
options_set_number(&ictx->wp->window->options, "automatic-rename", 0);
|
||||||
@ -1655,7 +1661,7 @@ input_utf8_open(struct input_ctx *ictx)
|
|||||||
input_print(ictx);
|
input_print(ictx);
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
log_debug("%s", __func__);
|
log_debug2("%s", __func__);
|
||||||
|
|
||||||
utf8_open(&ictx->utf8data, ictx->ch);
|
utf8_open(&ictx->utf8data, ictx->ch);
|
||||||
return (0);
|
return (0);
|
||||||
@ -1665,7 +1671,7 @@ input_utf8_open(struct input_ctx *ictx)
|
|||||||
int
|
int
|
||||||
input_utf8_add(struct input_ctx *ictx)
|
input_utf8_add(struct input_ctx *ictx)
|
||||||
{
|
{
|
||||||
log_debug("%s", __func__);
|
log_debug2("%s", __func__);
|
||||||
|
|
||||||
utf8_append(&ictx->utf8data, ictx->ch);
|
utf8_append(&ictx->utf8data, ictx->ch);
|
||||||
return (0);
|
return (0);
|
||||||
@ -1675,7 +1681,7 @@ input_utf8_add(struct input_ctx *ictx)
|
|||||||
int
|
int
|
||||||
input_utf8_close(struct input_ctx *ictx)
|
input_utf8_close(struct input_ctx *ictx)
|
||||||
{
|
{
|
||||||
log_debug("%s", __func__);
|
log_debug2("%s", __func__);
|
||||||
|
|
||||||
utf8_append(&ictx->utf8data, ictx->ch);
|
utf8_append(&ictx->utf8data, ictx->ch);
|
||||||
|
|
||||||
|
14
log.c
14
log.c
@ -24,6 +24,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "tmux.h"
|
#include "tmux.h"
|
||||||
|
|
||||||
@ -48,9 +49,14 @@ log_event_cb(unused int severity, const char *msg)
|
|||||||
void
|
void
|
||||||
log_open(int level, const char *path)
|
log_open(int level, const char *path)
|
||||||
{
|
{
|
||||||
log_file = fopen(path, "w");
|
if (path) {
|
||||||
if (log_file == NULL)
|
log_file = fopen(path, "a");
|
||||||
return;
|
if (log_file == NULL)
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
log_file = stderr;
|
||||||
|
}
|
||||||
|
|
||||||
log_level = level;
|
log_level = level;
|
||||||
|
|
||||||
setlinebuf(log_file);
|
setlinebuf(log_file);
|
||||||
@ -78,7 +84,7 @@ log_vwrite(const char *msg, va_list ap)
|
|||||||
if (log_file == NULL)
|
if (log_file == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (asprintf(&fmt, "%s\n", msg) == -1)
|
if (asprintf(&fmt, "[%d] %s\n", getpid(), msg) == -1)
|
||||||
exit(1);
|
exit(1);
|
||||||
if (vfprintf(log_file, fmt, ap) == -1)
|
if (vfprintf(log_file, fmt, ap) == -1)
|
||||||
exit(1);
|
exit(1);
|
||||||
|
18
names.c
18
names.c
@ -26,6 +26,22 @@
|
|||||||
|
|
||||||
#include "tmux.h"
|
#include "tmux.h"
|
||||||
|
|
||||||
|
#ifdef TMATE_SLAVE
|
||||||
|
|
||||||
|
char *
|
||||||
|
default_window_name(struct window *w)
|
||||||
|
{
|
||||||
|
return xstrdup("[tmux]");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
queue_window_name(struct window *w)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
|
||||||
void window_name_callback(unused int, unused short, void *);
|
void window_name_callback(unused int, unused short, void *);
|
||||||
char *parse_window_name(const char *);
|
char *parse_window_name(const char *);
|
||||||
|
|
||||||
@ -128,3 +144,5 @@ parse_window_name(const char *in)
|
|||||||
free(copy);
|
free(copy);
|
||||||
return (name);
|
return (name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
2
paste.c
2
paste.c
@ -167,6 +167,7 @@ paste_print(struct paste_buffer *pb, size_t width)
|
|||||||
return (buf);
|
return (buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef TMATE_SLAVE
|
||||||
/* Paste into a window pane, filtering '\n' according to separator. */
|
/* Paste into a window pane, filtering '\n' according to separator. */
|
||||||
void
|
void
|
||||||
paste_send_pane (struct paste_buffer *pb, struct window_pane *wp,
|
paste_send_pane (struct paste_buffer *pb, struct window_pane *wp,
|
||||||
@ -192,3 +193,4 @@ paste_send_pane (struct paste_buffer *pb, struct window_pane *wp,
|
|||||||
if (bracket)
|
if (bracket)
|
||||||
bufferevent_write(wp->event, "\033[201~", 6);
|
bufferevent_write(wp->event, "\033[201~", 6);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
7
resize.c
7
resize.c
@ -21,6 +21,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "tmux.h"
|
#include "tmux.h"
|
||||||
|
#include "tmate.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Recalculate window and session sizes.
|
* Recalculate window and session sizes.
|
||||||
@ -71,6 +72,12 @@ recalculate_sizes(void)
|
|||||||
ssy = c->tty.sy;
|
ssy = c->tty.sy;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef TMATE_SLAVE
|
||||||
|
tmate_client_resize(ssx, ssy);
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (ssx == UINT_MAX || ssy == UINT_MAX) {
|
if (ssx == UINT_MAX || ssy == UINT_MAX) {
|
||||||
s->flags |= SESSION_UNATTACHED;
|
s->flags |= SESSION_UNATTACHED;
|
||||||
continue;
|
continue;
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "tmux.h"
|
#include "tmux.h"
|
||||||
|
#include "tmate.h"
|
||||||
|
|
||||||
int screen_redraw_cell_border1(struct window_pane *, u_int, u_int);
|
int screen_redraw_cell_border1(struct window_pane *, u_int, u_int);
|
||||||
int screen_redraw_cell_border(struct client *, u_int, u_int);
|
int screen_redraw_cell_border(struct client *, u_int, u_int);
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "tmux.h"
|
#include "tmux.h"
|
||||||
|
#include "tmate.h"
|
||||||
|
|
||||||
void server_client_check_focus(struct window_pane *);
|
void server_client_check_focus(struct window_pane *);
|
||||||
void server_client_check_resize(struct window_pane *);
|
void server_client_check_resize(struct window_pane *);
|
||||||
@ -281,6 +282,7 @@ server_client_status_timer(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef TMATE_SLAVE
|
||||||
/* Check for mouse keys. */
|
/* Check for mouse keys. */
|
||||||
void
|
void
|
||||||
server_client_check_mouse(struct client *c, struct window_pane *wp)
|
server_client_check_mouse(struct client *c, struct window_pane *wp)
|
||||||
@ -333,6 +335,7 @@ server_client_check_mouse(struct client *c, struct window_pane *wp)
|
|||||||
/* Update last and pass through to client. */
|
/* Update last and pass through to client. */
|
||||||
window_pane_mouse(wp, c->session, m);
|
window_pane_mouse(wp, c->session, m);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Is this fast enough to probably be a paste? */
|
/* Is this fast enough to probably be a paste? */
|
||||||
int
|
int
|
||||||
@ -354,6 +357,9 @@ server_client_assume_paste(struct session *s)
|
|||||||
void
|
void
|
||||||
server_client_handle_key(struct client *c, int key)
|
server_client_handle_key(struct client *c, int key)
|
||||||
{
|
{
|
||||||
|
#ifdef TMATE_SLAVE
|
||||||
|
tmate_client_key(key);
|
||||||
|
#else
|
||||||
struct session *s;
|
struct session *s;
|
||||||
struct window *w;
|
struct window *w;
|
||||||
struct window_pane *wp;
|
struct window_pane *wp;
|
||||||
@ -479,6 +485,7 @@ server_client_handle_key(struct client *c, int key)
|
|||||||
|
|
||||||
/* Dispatch the command. */
|
/* Dispatch the command. */
|
||||||
key_bindings_dispatch(bd, c);
|
key_bindings_dispatch(bd, c);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Client functions that need to happen every loop. */
|
/* Client functions that need to happen every loop. */
|
||||||
@ -513,13 +520,16 @@ server_client_loop(void)
|
|||||||
|
|
||||||
w->flags &= ~WINDOW_REDRAW;
|
w->flags &= ~WINDOW_REDRAW;
|
||||||
TAILQ_FOREACH(wp, &w->panes, entry) {
|
TAILQ_FOREACH(wp, &w->panes, entry) {
|
||||||
|
#ifndef TMATE_SLAVE
|
||||||
server_client_check_focus(wp);
|
server_client_check_focus(wp);
|
||||||
server_client_check_resize(wp);
|
server_client_check_resize(wp);
|
||||||
|
#endif
|
||||||
wp->flags &= ~PANE_REDRAW;
|
wp->flags &= ~PANE_REDRAW;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef TMATE_SLAVE
|
||||||
/* Check if pane should be resized. */
|
/* Check if pane should be resized. */
|
||||||
void
|
void
|
||||||
server_client_check_resize(struct window_pane *wp)
|
server_client_check_resize(struct window_pane *wp)
|
||||||
@ -597,6 +607,7 @@ focused:
|
|||||||
bufferevent_write(wp->event, "\033[I", 3);
|
bufferevent_write(wp->event, "\033[I", 3);
|
||||||
wp->flags |= PANE_FOCUSED;
|
wp->flags |= PANE_FOCUSED;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Update cursor position and mode settings. The scroll region and attributes
|
* Update cursor position and mode settings. The scroll region and attributes
|
||||||
@ -811,7 +822,7 @@ server_client_msg_dispatch(struct client *c)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_debug("got %d from client %d", imsg.hdr.type, c->ibuf.fd);
|
log_debug2("got %d from client %d", imsg.hdr.type, c->ibuf.fd);
|
||||||
switch (imsg.hdr.type) {
|
switch (imsg.hdr.type) {
|
||||||
case MSG_COMMAND:
|
case MSG_COMMAND:
|
||||||
if (datalen != sizeof commanddata)
|
if (datalen != sizeof commanddata)
|
||||||
@ -996,10 +1007,7 @@ server_client_msg_shell(struct client *c)
|
|||||||
struct msg_shell_data data;
|
struct msg_shell_data data;
|
||||||
const char *shell;
|
const char *shell;
|
||||||
|
|
||||||
shell = options_get_string(&global_s_options, "default-shell");
|
shell = _PATH_BSHELL;
|
||||||
|
|
||||||
if (*shell == '\0' || areshell(shell))
|
|
||||||
shell = _PATH_BSHELL;
|
|
||||||
if (strlcpy(data.shell, shell, sizeof data.shell) >= sizeof data.shell)
|
if (strlcpy(data.shell, shell, sizeof data.shell) >= sizeof data.shell)
|
||||||
strlcpy(data.shell, _PATH_BSHELL, sizeof data.shell);
|
strlcpy(data.shell, _PATH_BSHELL, sizeof data.shell);
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ server_write_client(
|
|||||||
|
|
||||||
if (c->flags & CLIENT_BAD)
|
if (c->flags & CLIENT_BAD)
|
||||||
return (-1);
|
return (-1);
|
||||||
log_debug("writing %d to client %d", type, c->ibuf.fd);
|
log_debug2("writing %d to client %d", type, c->ibuf.fd);
|
||||||
error = imsg_compose(ibuf, type, PROTOCOL_VERSION, -1, -1,
|
error = imsg_compose(ibuf, type, PROTOCOL_VERSION, -1, -1,
|
||||||
(void *) buf, len);
|
(void *) buf, len);
|
||||||
if (error == 1)
|
if (error == 1)
|
||||||
@ -351,6 +351,7 @@ void
|
|||||||
server_destroy_pane(struct window_pane *wp)
|
server_destroy_pane(struct window_pane *wp)
|
||||||
{
|
{
|
||||||
struct window *w = wp->window;
|
struct window *w = wp->window;
|
||||||
|
#ifndef TMATE_SLAVE
|
||||||
int old_fd;
|
int old_fd;
|
||||||
struct screen_write_ctx ctx;
|
struct screen_write_ctx ctx;
|
||||||
struct grid_cell gc;
|
struct grid_cell gc;
|
||||||
@ -376,6 +377,7 @@ server_destroy_pane(struct window_pane *wp)
|
|||||||
wp->flags |= PANE_REDRAW;
|
wp->flags |= PANE_REDRAW;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
server_unzoom_window(w);
|
server_unzoom_window(w);
|
||||||
layout_close_pane(wp);
|
layout_close_pane(wp);
|
||||||
|
13
server.c
13
server.c
@ -36,6 +36,7 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "tmux.h"
|
#include "tmux.h"
|
||||||
|
#include "tmate.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Main server functions.
|
* Main server functions.
|
||||||
@ -105,10 +106,13 @@ server_create_socket(void)
|
|||||||
int
|
int
|
||||||
server_start(int lockfd, char *lockfile)
|
server_start(int lockfd, char *lockfile)
|
||||||
{
|
{
|
||||||
|
#ifndef TMATE_SLAVE
|
||||||
int pair[2];
|
int pair[2];
|
||||||
|
#endif
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
char *cause;
|
char *cause;
|
||||||
|
|
||||||
|
#ifndef TMATE_SLAVE
|
||||||
/* The first client is special and gets a socketpair; create it. */
|
/* The first client is special and gets a socketpair; create it. */
|
||||||
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0)
|
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0)
|
||||||
fatal("socketpair failed");
|
fatal("socketpair failed");
|
||||||
@ -135,8 +139,9 @@ server_start(int lockfd, char *lockfile)
|
|||||||
if (event_reinit(ev_base) != 0)
|
if (event_reinit(ev_base) != 0)
|
||||||
fatal("event_reinit failed");
|
fatal("event_reinit failed");
|
||||||
clear_signals(0);
|
clear_signals(0);
|
||||||
|
|
||||||
logfile("server");
|
logfile("server");
|
||||||
|
#endif
|
||||||
|
|
||||||
log_debug("server started, pid %ld", (long) getpid());
|
log_debug("server started, pid %ld", (long) getpid());
|
||||||
|
|
||||||
ARRAY_INIT(&windows);
|
ARRAY_INIT(&windows);
|
||||||
@ -158,11 +163,14 @@ server_start(int lockfd, char *lockfile)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
server_fd = server_create_socket();
|
server_fd = server_create_socket();
|
||||||
|
|
||||||
|
#ifndef TMATE_SLAVE
|
||||||
server_client_create(pair[1]);
|
server_client_create(pair[1]);
|
||||||
|
|
||||||
unlink(lockfile);
|
unlink(lockfile);
|
||||||
free(lockfile);
|
free(lockfile);
|
||||||
close(lockfd);
|
close(lockfd);
|
||||||
|
#endif
|
||||||
|
|
||||||
cfg_cmd_q = cmdq_new(NULL);
|
cfg_cmd_q = cmdq_new(NULL);
|
||||||
cfg_cmd_q->emptyfn = cfg_default_done;
|
cfg_cmd_q->emptyfn = cfg_default_done;
|
||||||
@ -203,7 +211,8 @@ server_start(int lockfd, char *lockfile)
|
|||||||
void
|
void
|
||||||
server_loop(void)
|
server_loop(void)
|
||||||
{
|
{
|
||||||
while (!server_should_shutdown()) {
|
while (!server_shutdown) {
|
||||||
|
//while (!server_should_shutdown()) {
|
||||||
event_loop(EVLOOP_ONCE);
|
event_loop(EVLOOP_ONCE);
|
||||||
|
|
||||||
server_window_loop();
|
server_window_loop();
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
#include "tmux.h"
|
#include "tmux.h"
|
||||||
|
#include "tmate.h"
|
||||||
|
|
||||||
/* Global session list. */
|
/* Global session list. */
|
||||||
struct sessions sessions;
|
struct sessions sessions;
|
||||||
@ -244,9 +245,7 @@ session_new(struct session *s,
|
|||||||
environ_copy(&s->environ, &env);
|
environ_copy(&s->environ, &env);
|
||||||
server_fill_environ(s, &env);
|
server_fill_environ(s, &env);
|
||||||
|
|
||||||
shell = options_get_string(&s->options, "default-shell");
|
shell = _PATH_BSHELL;
|
||||||
if (*shell == '\0' || areshell(shell))
|
|
||||||
shell = _PATH_BSHELL;
|
|
||||||
|
|
||||||
hlimit = options_get_number(&s->options, "history-limit");
|
hlimit = options_get_number(&s->options, "history-limit");
|
||||||
w = window_create(
|
w = window_create(
|
||||||
|
76
tmate-debug.c
Normal file
76
tmate-debug.c
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
#include <execinfo.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <regex.h>
|
||||||
|
#include "tmate.h"
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
|
||||||
|
static int print_resolved_stack_frame(const char *frame)
|
||||||
|
{
|
||||||
|
char file[100];
|
||||||
|
char cmd[200];
|
||||||
|
char output[300];
|
||||||
|
char address[20];
|
||||||
|
char *line;
|
||||||
|
FILE *ps;
|
||||||
|
|
||||||
|
static regex_t _regex;
|
||||||
|
static regex_t *regex;
|
||||||
|
regmatch_t matches[3];
|
||||||
|
|
||||||
|
if (!regex) {
|
||||||
|
if (regcomp(&_regex, "(.+)\\(\\) \\[([^]]+)\\]", REG_EXTENDED))
|
||||||
|
return -1;
|
||||||
|
regex = &_regex;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (regexec(regex, frame, 3, matches, 0))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
memcpy(file, &frame[matches[1].rm_so], matches[1].rm_eo - matches[1].rm_so);
|
||||||
|
file[matches[1].rm_eo - matches[1].rm_so] = 0;
|
||||||
|
|
||||||
|
memcpy(address, &frame[matches[2].rm_so], matches[2].rm_eo - matches[2].rm_so);
|
||||||
|
address[matches[2].rm_eo - matches[2].rm_so] = 0;
|
||||||
|
|
||||||
|
sprintf(cmd, "addr2line -e %s %s -f -p -s", file, address);
|
||||||
|
|
||||||
|
ps = popen(cmd, "r");
|
||||||
|
if (!ps)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
line = fgets(output, sizeof(output), ps);
|
||||||
|
pclose(ps);
|
||||||
|
|
||||||
|
if (!line)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
line[strlen(line)-1] = 0; /* remove \n */
|
||||||
|
tmate_debug("%s(%s) [%s]", file, line, address);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void
|
||||||
|
tmate_print_trace (void)
|
||||||
|
{
|
||||||
|
void *array[20];
|
||||||
|
size_t size;
|
||||||
|
char **strings;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
size = backtrace (array, 20);
|
||||||
|
strings = backtrace_symbols (array, size);
|
||||||
|
|
||||||
|
tmate_debug ("============ %zd stack frames ============", size);
|
||||||
|
|
||||||
|
for (i = 1; i < size; i++) {
|
||||||
|
#if DEBUG
|
||||||
|
if (print_resolved_stack_frame(strings[i]) < 0)
|
||||||
|
#endif
|
||||||
|
tmate_debug("%s", strings[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
free (strings);
|
||||||
|
}
|
260
tmate-decoder.c
Normal file
260
tmate-decoder.c
Normal file
@ -0,0 +1,260 @@
|
|||||||
|
#include "tmate.h"
|
||||||
|
|
||||||
|
static struct session *main_session;
|
||||||
|
|
||||||
|
struct tmate_unpacker {
|
||||||
|
msgpack_object *argv;
|
||||||
|
int argc;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void decoder_error(void)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
tmate_print_trace();
|
||||||
|
#endif
|
||||||
|
tmate_fatal("Received a bad message");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init_unpacker(struct tmate_unpacker *uk,
|
||||||
|
msgpack_object obj)
|
||||||
|
{
|
||||||
|
if (obj.type != MSGPACK_OBJECT_ARRAY)
|
||||||
|
decoder_error();
|
||||||
|
|
||||||
|
uk->argv = obj.via.array.ptr;
|
||||||
|
uk->argc = obj.via.array.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int64_t unpack_int(struct tmate_unpacker *uk)
|
||||||
|
{
|
||||||
|
int64_t val;
|
||||||
|
|
||||||
|
if (uk->argc == 0)
|
||||||
|
decoder_error();
|
||||||
|
|
||||||
|
if (uk->argv[0].type != MSGPACK_OBJECT_POSITIVE_INTEGER &&
|
||||||
|
uk->argv[0].type != MSGPACK_OBJECT_NEGATIVE_INTEGER)
|
||||||
|
decoder_error();
|
||||||
|
|
||||||
|
val = uk->argv[0].via.i64;
|
||||||
|
|
||||||
|
uk->argv++;
|
||||||
|
uk->argc--;
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void unpack_raw(struct tmate_unpacker *uk,
|
||||||
|
const char **buf, size_t *len)
|
||||||
|
{
|
||||||
|
if (uk->argc == 0)
|
||||||
|
decoder_error();
|
||||||
|
|
||||||
|
if (uk->argv[0].type != MSGPACK_OBJECT_RAW)
|
||||||
|
decoder_error();
|
||||||
|
|
||||||
|
*len = uk->argv[0].via.raw.size;
|
||||||
|
*buf = uk->argv[0].via.raw.ptr;
|
||||||
|
|
||||||
|
uk->argv++;
|
||||||
|
uk->argc--;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *unpack_string(struct tmate_unpacker *uk)
|
||||||
|
{
|
||||||
|
const char *buf;
|
||||||
|
char *alloc_buf;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
unpack_raw(uk, &buf, &len);
|
||||||
|
|
||||||
|
alloc_buf = xmalloc(len + 1);
|
||||||
|
memcpy(alloc_buf, buf, len);
|
||||||
|
alloc_buf[len] = '\0';
|
||||||
|
|
||||||
|
return alloc_buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void unpack_array(struct tmate_unpacker *uk,
|
||||||
|
struct tmate_unpacker *nested)
|
||||||
|
{
|
||||||
|
if (uk->argc == 0)
|
||||||
|
decoder_error();
|
||||||
|
|
||||||
|
init_unpacker(nested, uk->argv[0]);
|
||||||
|
|
||||||
|
uk->argv++;
|
||||||
|
uk->argc--;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define unpack_each(nested_uk, tmp_uk, uk) \
|
||||||
|
for (unpack_array(uk, tmp_uk); \
|
||||||
|
(tmp_uk)->argc > 0 && (init_unpacker(nested_uk, (tmp_uk)->argv[0]), 1); \
|
||||||
|
(tmp_uk)->argv++, (tmp_uk)->argc--)
|
||||||
|
|
||||||
|
static void tmate_header(struct tmate_unpacker *uk)
|
||||||
|
{
|
||||||
|
int protocol = unpack_int(uk);
|
||||||
|
|
||||||
|
if (protocol != 1)
|
||||||
|
decoder_error();
|
||||||
|
|
||||||
|
tmate_debug("new master, protocol: %d", protocol);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern u_int next_window_pane_id;
|
||||||
|
|
||||||
|
static void tmate_sync_window_panes(struct window *w,
|
||||||
|
struct tmate_unpacker *w_uk)
|
||||||
|
{
|
||||||
|
struct tmate_unpacker uk, tmp_uk;
|
||||||
|
struct window_pane *wp, *wp_tmp;
|
||||||
|
int active_pane_id;
|
||||||
|
|
||||||
|
TAILQ_FOREACH(wp, &w->panes, entry)
|
||||||
|
wp->flags |= PANE_KILL;
|
||||||
|
|
||||||
|
unpack_each(&uk, &tmp_uk, w_uk) {
|
||||||
|
int id = unpack_int(&uk);
|
||||||
|
int sx = unpack_int(&uk);
|
||||||
|
int sy = unpack_int(&uk);
|
||||||
|
int xoff = unpack_int(&uk);
|
||||||
|
int yoff = unpack_int(&uk);
|
||||||
|
|
||||||
|
wp = window_pane_find_by_id(id);
|
||||||
|
if (!wp) {
|
||||||
|
next_window_pane_id = id;
|
||||||
|
wp = window_add_pane(w, TMATE_HLIMIT);
|
||||||
|
window_set_active_pane(w, wp);
|
||||||
|
}
|
||||||
|
wp->flags &= ~PANE_KILL;
|
||||||
|
|
||||||
|
wp->xoff = xoff;
|
||||||
|
wp->yoff = yoff;
|
||||||
|
window_pane_resize(wp, sx, sy);
|
||||||
|
|
||||||
|
wp->flags |= PANE_REDRAW;
|
||||||
|
}
|
||||||
|
|
||||||
|
TAILQ_FOREACH_SAFE(wp, &w->panes, entry, wp_tmp) {
|
||||||
|
if (wp->flags & PANE_KILL)
|
||||||
|
window_remove_pane(w, wp);
|
||||||
|
}
|
||||||
|
|
||||||
|
active_pane_id = unpack_int(w_uk);
|
||||||
|
wp = window_pane_find_by_id(active_pane_id);
|
||||||
|
if (wp && wp->window == w)
|
||||||
|
window_set_active_pane(w, wp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tmate_sync_window(struct tmate_unpacker *uk)
|
||||||
|
{
|
||||||
|
struct session *s;
|
||||||
|
struct winlink *wl;
|
||||||
|
struct window *w;
|
||||||
|
char *cause;
|
||||||
|
|
||||||
|
int id = unpack_int(uk);
|
||||||
|
char *name = unpack_string(uk);
|
||||||
|
int sx = unpack_int(uk);
|
||||||
|
int sy = unpack_int(uk);
|
||||||
|
|
||||||
|
if (!main_session) {
|
||||||
|
main_session = session_create("default", NULL, "default", NULL,
|
||||||
|
NULL, 0, sx, sy, &cause);
|
||||||
|
if (!main_session)
|
||||||
|
tmate_fatal("can't create main session");
|
||||||
|
}
|
||||||
|
s = main_session;
|
||||||
|
|
||||||
|
wl = winlink_find_by_index(&s->windows, id);
|
||||||
|
if (!wl) {
|
||||||
|
wl = session_new(s, name, "sh", NULL, id, &cause);
|
||||||
|
if (!wl)
|
||||||
|
tmate_fatal("can't create window id=%d", id);
|
||||||
|
session_select(s, RB_ROOT(&s->windows)->idx);
|
||||||
|
}
|
||||||
|
w = wl->window;
|
||||||
|
|
||||||
|
free(w->name);
|
||||||
|
w->name = name;
|
||||||
|
s->sx = w->sx = sx;
|
||||||
|
s->sy = w->sy = sy;
|
||||||
|
|
||||||
|
tmate_sync_window_panes(w, uk);
|
||||||
|
|
||||||
|
server_redraw_window(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tmate_pty_data(struct tmate_unpacker *uk)
|
||||||
|
{
|
||||||
|
struct window_pane *wp;
|
||||||
|
const char *buf;
|
||||||
|
size_t len;
|
||||||
|
int id;
|
||||||
|
|
||||||
|
id = unpack_int(uk);
|
||||||
|
unpack_raw(uk, &buf, &len);
|
||||||
|
|
||||||
|
wp = window_pane_find_by_id(id);
|
||||||
|
if (!wp)
|
||||||
|
tmate_fatal("can't find pane id=%d", id);
|
||||||
|
|
||||||
|
evbuffer_add(wp->event_input, buf, len);
|
||||||
|
input_parse(wp);
|
||||||
|
|
||||||
|
wp->window->flags |= WINDOW_SILENCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_message(msgpack_object obj)
|
||||||
|
{
|
||||||
|
struct tmate_unpacker _uk;
|
||||||
|
struct tmate_unpacker *uk = &_uk;
|
||||||
|
int cmd;
|
||||||
|
|
||||||
|
init_unpacker(uk, obj);
|
||||||
|
|
||||||
|
switch (unpack_int(uk)) {
|
||||||
|
case TMATE_HEADER: tmate_header(uk); break;
|
||||||
|
case TMATE_SYNC_WINDOW: tmate_sync_window(uk); break;
|
||||||
|
case TMATE_PTY_DATA: tmate_pty_data(uk); break;
|
||||||
|
default: decoder_error();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tmate_decoder_commit(struct tmate_decoder *decoder, size_t len)
|
||||||
|
{
|
||||||
|
msgpack_unpacked result;
|
||||||
|
|
||||||
|
msgpack_unpacker_buffer_consumed(&decoder->unpacker, len);
|
||||||
|
|
||||||
|
msgpack_unpacked_init(&result);
|
||||||
|
while (msgpack_unpacker_next(&decoder->unpacker, &result)) {
|
||||||
|
handle_message(result.data);
|
||||||
|
}
|
||||||
|
msgpack_unpacked_destroy(&result);
|
||||||
|
|
||||||
|
if (msgpack_unpacker_message_size(&decoder->unpacker) >
|
||||||
|
TMATE_MAX_MESSAGE_SIZE) {
|
||||||
|
tmate_fatal("Message too big");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tmate_decoder_get_buffer(struct tmate_decoder *decoder,
|
||||||
|
char **buf, size_t *len)
|
||||||
|
{
|
||||||
|
/* rewind the buffer if possible */
|
||||||
|
if (msgpack_unpacker_buffer_capacity(&decoder->unpacker) <
|
||||||
|
TMATE_MAX_MESSAGE_SIZE) {
|
||||||
|
msgpack_unpacker_expand_buffer(&decoder->unpacker, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
*buf = msgpack_unpacker_buffer(&decoder->unpacker);
|
||||||
|
*len = msgpack_unpacker_buffer_capacity(&decoder->unpacker);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tmate_decoder_init(struct tmate_decoder *decoder)
|
||||||
|
{
|
||||||
|
if (!msgpack_unpacker_init(&decoder->unpacker, 2*TMATE_MAX_MESSAGE_SIZE))
|
||||||
|
tmate_fatal("cannot initialize the unpacker");
|
||||||
|
}
|
39
tmate-encoder.c
Normal file
39
tmate-encoder.c
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
#include "tmate.h"
|
||||||
|
|
||||||
|
static int msgpack_write(void *data, const char *buf, unsigned int len)
|
||||||
|
{
|
||||||
|
struct tmate_encoder *encoder = data;
|
||||||
|
|
||||||
|
evbuffer_add(encoder->buffer, buf, len);
|
||||||
|
|
||||||
|
if ((encoder->ev_readable.ev_flags & EVLIST_INSERTED) &&
|
||||||
|
!(encoder->ev_readable.ev_flags & EVLIST_ACTIVE)) {
|
||||||
|
event_active(&encoder->ev_readable, EV_READ, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tmate_encoder_init(struct tmate_encoder *encoder)
|
||||||
|
{
|
||||||
|
encoder->buffer = evbuffer_new();
|
||||||
|
msgpack_packer_init(&encoder->pk, encoder, &msgpack_write);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define pack(what, ...) msgpack_pack_##what(&tmate_encoder->pk, __VA_ARGS__)
|
||||||
|
|
||||||
|
void tmate_client_key(int key)
|
||||||
|
{
|
||||||
|
pack(array, 2);
|
||||||
|
pack(int, TMATE_CLIENT_KEY);
|
||||||
|
pack(int, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tmate_client_resize(u_int sx, u_int sy)
|
||||||
|
{
|
||||||
|
pack(array, 3);
|
||||||
|
pack(int, TMATE_CLIENT_RESIZE);
|
||||||
|
/* cast to signed, -1 == no clients */
|
||||||
|
pack(int, sx);
|
||||||
|
pack(int, sy);
|
||||||
|
}
|
164
tmate-server.c
Normal file
164
tmate-server.c
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include "tmate.h"
|
||||||
|
|
||||||
|
struct event_base *ev_base;
|
||||||
|
|
||||||
|
struct options global_options; /* server options */
|
||||||
|
struct options global_s_options; /* session options */
|
||||||
|
struct options global_w_options; /* window options */
|
||||||
|
struct environ global_environ;
|
||||||
|
|
||||||
|
struct event_base *ev_base;
|
||||||
|
|
||||||
|
char *cfg_file;
|
||||||
|
char *shell_cmd;
|
||||||
|
int debug_level;
|
||||||
|
time_t start_time;
|
||||||
|
char socket_path[MAXPATHLEN];
|
||||||
|
int login_shell;
|
||||||
|
char *environ_path;
|
||||||
|
pid_t environ_pid = -1;
|
||||||
|
int environ_session_id = -1;
|
||||||
|
|
||||||
|
void
|
||||||
|
setblocking(int fd, int state)
|
||||||
|
{
|
||||||
|
int mode;
|
||||||
|
|
||||||
|
if ((mode = fcntl(fd, F_GETFL)) != -1) {
|
||||||
|
if (!state)
|
||||||
|
mode |= O_NONBLOCK;
|
||||||
|
else
|
||||||
|
mode &= ~O_NONBLOCK;
|
||||||
|
fcntl(fd, F_SETFL, mode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char*
|
||||||
|
get_full_path(const char *wd, const char *path)
|
||||||
|
{
|
||||||
|
static char newpath[MAXPATHLEN];
|
||||||
|
char oldpath[MAXPATHLEN];
|
||||||
|
|
||||||
|
if (getcwd(oldpath, sizeof oldpath) == NULL)
|
||||||
|
return (NULL);
|
||||||
|
if (chdir(wd) != 0)
|
||||||
|
return (NULL);
|
||||||
|
if (realpath(path, newpath) != 0)
|
||||||
|
return (NULL);
|
||||||
|
chdir(oldpath);
|
||||||
|
return (newpath);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usage(void)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "usage: tmate-server [-p PORT]\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int opt;
|
||||||
|
int port = 22;
|
||||||
|
char *log_path = NULL; /* stderr */
|
||||||
|
|
||||||
|
strcpy(socket_path, "/tmp/tmate-slave");
|
||||||
|
|
||||||
|
while ((opt = getopt(argc, argv, "p:l:v")) != -1) {
|
||||||
|
switch (opt) {
|
||||||
|
case 'p':
|
||||||
|
port = atoi(optarg);
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
log_path = optarg;
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
debug_level++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log_open(debug_level, log_path);
|
||||||
|
tmate_ssh_server_main(port);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct tmate_encoder *tmate_encoder;
|
||||||
|
|
||||||
|
void tmate_spawn_slave_server(struct tmate_ssh_client *client)
|
||||||
|
{
|
||||||
|
int quiet = 0;
|
||||||
|
int flags = IDENTIFY_UTF8 | IDENTIFY_256COLOURS;
|
||||||
|
struct tmate_encoder encoder;
|
||||||
|
struct tmate_decoder decoder;
|
||||||
|
|
||||||
|
tmate_debug("Spawn tmux slave server");
|
||||||
|
|
||||||
|
ev_base = osdep_event_init();
|
||||||
|
|
||||||
|
tmate_encoder_init(&encoder);
|
||||||
|
tmate_decoder_init(&decoder);
|
||||||
|
tmate_encoder = &encoder;
|
||||||
|
|
||||||
|
tmate_ssh_client_init(client, &encoder, &decoder);
|
||||||
|
|
||||||
|
environ_init(&global_environ);
|
||||||
|
|
||||||
|
options_init(&global_options, NULL);
|
||||||
|
options_table_populate_tree(server_options_table, &global_options);
|
||||||
|
options_set_number(&global_options, "quiet", quiet);
|
||||||
|
|
||||||
|
options_init(&global_s_options, NULL);
|
||||||
|
options_table_populate_tree(session_options_table, &global_s_options);
|
||||||
|
|
||||||
|
options_init(&global_w_options, NULL);
|
||||||
|
options_table_populate_tree(window_options_table, &global_w_options);
|
||||||
|
|
||||||
|
if (flags & IDENTIFY_UTF8) {
|
||||||
|
options_set_number(&global_s_options, "status-utf8", 1);
|
||||||
|
options_set_number(&global_s_options, "mouse-utf8", 1);
|
||||||
|
options_set_number(&global_w_options, "utf8", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
server_start(0, NULL);
|
||||||
|
/* never reached */
|
||||||
|
}
|
||||||
|
|
||||||
|
void tmate_spawn_slave_client(struct tmate_ssh_client *ssh_client)
|
||||||
|
{
|
||||||
|
struct tmate_ssh_client_pty _client;
|
||||||
|
struct tmate_ssh_client_pty *client = &_client;
|
||||||
|
int slave_pty;
|
||||||
|
int ret;
|
||||||
|
char *argv[] = {(char *)"attach", NULL};
|
||||||
|
|
||||||
|
client->session = ssh_client->session;
|
||||||
|
client->channel = ssh_client->channel;
|
||||||
|
client->winsize_pty = ssh_client->winsize_pty;
|
||||||
|
|
||||||
|
tmate_debug("Spawn tmux slave client");
|
||||||
|
|
||||||
|
ev_base = osdep_event_init();
|
||||||
|
|
||||||
|
if (openpty(&client->pty, &slave_pty, NULL, NULL, NULL) < 0)
|
||||||
|
tmate_fatal("Cannot allocate pty");
|
||||||
|
|
||||||
|
/* setsid(); */
|
||||||
|
/* ioctl(slave_pty, TIOCSCTTY, NULL); */
|
||||||
|
|
||||||
|
dup2(slave_pty, STDIN_FILENO);
|
||||||
|
dup2(slave_pty, STDOUT_FILENO);
|
||||||
|
stderr = stdout;
|
||||||
|
close(slave_pty);
|
||||||
|
|
||||||
|
tmate_ssh_client_pty_init(client);
|
||||||
|
|
||||||
|
ret = client_main(1, argv, IDENTIFY_UTF8 | IDENTIFY_256COLOURS);
|
||||||
|
tmate_flush_pty(client);
|
||||||
|
exit(ret);
|
||||||
|
}
|
143
tmate-ssh-client-pty.c
Normal file
143
tmate-ssh-client-pty.c
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
#include "tmate.h"
|
||||||
|
#include <libssh/libssh.h>
|
||||||
|
#include <libssh/server.h>
|
||||||
|
#include <libssh/callbacks.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
static void consume_channel(struct tmate_ssh_client_pty *client)
|
||||||
|
{
|
||||||
|
ssize_t len, written;
|
||||||
|
char buf[4096];
|
||||||
|
char *ptr;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
len = ssh_channel_read_nonblocking(client->channel,
|
||||||
|
buf, sizeof(buf), 0);
|
||||||
|
if (len < 0) {
|
||||||
|
tmate_debug("Error reading from channel: %s",
|
||||||
|
ssh_get_error(client->session));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ptr = buf;
|
||||||
|
setblocking(client->pty, 1);
|
||||||
|
while (len > 0) {
|
||||||
|
written = write(client->pty, ptr, len);
|
||||||
|
if (written < 0)
|
||||||
|
tmate_fatal("Error writing to pty");
|
||||||
|
|
||||||
|
ptr += written;
|
||||||
|
len -= written;
|
||||||
|
}
|
||||||
|
setblocking(client->pty, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void on_session_event(struct tmate_ssh_client_pty *client)
|
||||||
|
{
|
||||||
|
ssh_execute_message_callbacks(client->session);
|
||||||
|
|
||||||
|
consume_channel(client);
|
||||||
|
|
||||||
|
if (!ssh_is_connected(client->session)) {
|
||||||
|
tmate_debug("Disconnected");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __on_session_event(evutil_socket_t fd, short what, void *arg)
|
||||||
|
{
|
||||||
|
on_session_event(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int message_callback(struct tmate_ssh_client_pty *client,
|
||||||
|
ssh_message msg)
|
||||||
|
{
|
||||||
|
if (ssh_message_type(msg) == SSH_REQUEST_CHANNEL &&
|
||||||
|
ssh_message_subtype(msg) == SSH_CHANNEL_REQUEST_WINDOW_CHANGE) {
|
||||||
|
struct winsize ws;
|
||||||
|
|
||||||
|
ws.ws_col = ssh_message_channel_request_pty_width(msg);
|
||||||
|
ws.ws_row = ssh_message_channel_request_pty_height(msg);
|
||||||
|
|
||||||
|
tmate_debug("change window size to %d, %d",
|
||||||
|
ws.ws_col, ws.ws_row);
|
||||||
|
ioctl(client->pty, TIOCSWINSZ, &ws);
|
||||||
|
kill(getpid(), SIGWINCH);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __message_callback(ssh_session session, ssh_message msg, void *arg)
|
||||||
|
{
|
||||||
|
return message_callback(arg, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void register_session_fd_event(struct tmate_ssh_client_pty *client)
|
||||||
|
{
|
||||||
|
ssh_set_message_callback(client->session, __message_callback, client);
|
||||||
|
|
||||||
|
event_assign(&client->ev_ssh, ev_base, ssh_get_fd(client->session),
|
||||||
|
EV_READ | EV_PERSIST, __on_session_event, client);
|
||||||
|
event_add(&client->ev_ssh, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void on_pty_event(struct tmate_ssh_client_pty *client)
|
||||||
|
{
|
||||||
|
ssize_t len, written;
|
||||||
|
char buf[4096];
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
len = read(client->pty, buf, sizeof(buf));
|
||||||
|
if (len < 0) {
|
||||||
|
if (errno == EAGAIN)
|
||||||
|
return;
|
||||||
|
tmate_fatal("pty read error");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len == 0)
|
||||||
|
tmate_fatal("pty reached EOF");
|
||||||
|
|
||||||
|
written = ssh_channel_write(client->channel, buf, len);
|
||||||
|
if (written < 0) {
|
||||||
|
tmate_debug("Error writing to channel: %s",
|
||||||
|
ssh_get_error(client->session));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (len != written) {
|
||||||
|
tmate_fatal("Cannot write %d bytes, wrote %d",
|
||||||
|
(int)len, (int)written);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __on_pty_event(evutil_socket_t fd, short what, void *arg)
|
||||||
|
{
|
||||||
|
on_pty_event(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tmate_flush_pty(struct tmate_ssh_client_pty *client)
|
||||||
|
{
|
||||||
|
on_pty_event(client);
|
||||||
|
close(client->pty);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void register_pty_event(struct tmate_ssh_client_pty *client)
|
||||||
|
{
|
||||||
|
setblocking(client->pty, 0);
|
||||||
|
event_assign(&client->ev_pty, ev_base, client->pty,
|
||||||
|
EV_READ | EV_PERSIST, __on_pty_event, client);
|
||||||
|
event_add(&client->ev_pty, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tmate_ssh_client_pty_init(struct tmate_ssh_client_pty *client)
|
||||||
|
{
|
||||||
|
ioctl(client->pty, TIOCSWINSZ, &client->winsize_pty);
|
||||||
|
register_session_fd_event(client);
|
||||||
|
register_pty_event(client);
|
||||||
|
}
|
103
tmate-ssh-client.c
Normal file
103
tmate-ssh-client.c
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
#include "tmate.h"
|
||||||
|
#include <libssh/libssh.h>
|
||||||
|
#include <libssh/server.h>
|
||||||
|
#include <libssh/callbacks.h>
|
||||||
|
|
||||||
|
static void consume_channel(struct tmate_ssh_client *client)
|
||||||
|
{
|
||||||
|
char *buf;
|
||||||
|
ssize_t len;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
tmate_decoder_get_buffer(client->decoder, &buf, &len);
|
||||||
|
if (len == 0)
|
||||||
|
tmate_fatal("Input buffer full");
|
||||||
|
|
||||||
|
len = ssh_channel_read_nonblocking(client->channel,
|
||||||
|
buf, len, 0);
|
||||||
|
if (len < 0) {
|
||||||
|
tmate_debug("Error reading from channel: %s",
|
||||||
|
ssh_get_error(client->session));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (len == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
tmate_decoder_commit(client->decoder, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void on_session_event(struct tmate_ssh_client *client)
|
||||||
|
{
|
||||||
|
ssh_session session = client->session;
|
||||||
|
ssh_channel channel = client->channel;
|
||||||
|
|
||||||
|
consume_channel(client);
|
||||||
|
if (!ssh_is_connected(session)) {
|
||||||
|
tmate_debug("Disconnected");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __on_session_event(evutil_socket_t fd, short what, void *arg)
|
||||||
|
{
|
||||||
|
on_session_event(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void register_session_fd_event(struct tmate_ssh_client *client)
|
||||||
|
{
|
||||||
|
event_assign(&client->ev_ssh, ev_base, ssh_get_fd(client->session),
|
||||||
|
EV_READ | EV_PERSIST, __on_session_event, client);
|
||||||
|
event_add(&client->ev_ssh, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void flush_input_stream(struct tmate_ssh_client *client)
|
||||||
|
{
|
||||||
|
struct evbuffer *evb = client->encoder->buffer;
|
||||||
|
ssize_t len, written;
|
||||||
|
char *buf;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
len = evbuffer_get_length(evb);
|
||||||
|
if (!len)
|
||||||
|
break;
|
||||||
|
|
||||||
|
buf = evbuffer_pullup(evb, -1);
|
||||||
|
|
||||||
|
written = ssh_channel_write(client->channel, buf, len);
|
||||||
|
if (written < 0) {
|
||||||
|
tmate_debug("Error writing to channel: %s",
|
||||||
|
ssh_get_error(client->session));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
evbuffer_drain(evb, written);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __flush_input_stream(evutil_socket_t fd, short what, void *arg)
|
||||||
|
{
|
||||||
|
flush_input_stream(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void register_input_stream_event(struct tmate_ssh_client *client)
|
||||||
|
{
|
||||||
|
event_assign(&client->encoder->ev_readable, ev_base, -1,
|
||||||
|
EV_READ | EV_PERSIST, __flush_input_stream, client);
|
||||||
|
event_add(&client->encoder->ev_readable, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void tmate_ssh_client_init(struct tmate_ssh_client *client,
|
||||||
|
struct tmate_encoder *encoder,
|
||||||
|
struct tmate_decoder *decoder)
|
||||||
|
{
|
||||||
|
client->winsize_pty.ws_col = 80;
|
||||||
|
client->winsize_pty.ws_row = 24;
|
||||||
|
|
||||||
|
client->encoder = encoder;
|
||||||
|
client->decoder = decoder;
|
||||||
|
|
||||||
|
register_session_fd_event(client);
|
||||||
|
register_input_stream_event(client);
|
||||||
|
}
|
225
tmate-ssh-server.c
Normal file
225
tmate-ssh-server.c
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
#include <libssh/libssh.h>
|
||||||
|
#include <libssh/server.h>
|
||||||
|
#include <libssh/callbacks.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/tcp.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <event.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
|
||||||
|
#include "tmate.h"
|
||||||
|
|
||||||
|
#define SSH_GRACE_PERIOD 60
|
||||||
|
|
||||||
|
static void client_bootstrap(struct tmate_ssh_client *client)
|
||||||
|
{
|
||||||
|
int auth = 0;
|
||||||
|
ssh_session session = client->session;
|
||||||
|
ssh_channel channel = NULL;
|
||||||
|
ssh_message msg;
|
||||||
|
|
||||||
|
int flag = 1;
|
||||||
|
setsockopt(ssh_get_fd(session), IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag));
|
||||||
|
alarm(SSH_GRACE_PERIOD);
|
||||||
|
|
||||||
|
tmate_debug("Exchanging DH keys");
|
||||||
|
|
||||||
|
if (ssh_handle_key_exchange(session) < 0)
|
||||||
|
tmate_fatal("Error doing the key exchange");
|
||||||
|
|
||||||
|
tmate_debug("Authenticating with public key");
|
||||||
|
|
||||||
|
while (!auth) {
|
||||||
|
msg = ssh_message_get(session);
|
||||||
|
if (!msg)
|
||||||
|
tmate_fatal("Authentification error");
|
||||||
|
|
||||||
|
switch (ssh_message_type(msg)) {
|
||||||
|
case SSH_REQUEST_AUTH:
|
||||||
|
switch (ssh_message_subtype(msg)) {
|
||||||
|
case SSH_AUTH_METHOD_PUBLICKEY:
|
||||||
|
if (ssh_message_auth_publickey_state(msg) == SSH_PUBLICKEY_STATE_NONE)
|
||||||
|
ssh_message_auth_reply_pk_ok_simple(msg);
|
||||||
|
|
||||||
|
else if (ssh_message_auth_publickey_state(msg) == SSH_PUBLICKEY_STATE_VALID) {
|
||||||
|
ssh_message_auth_reply_success(msg, 0);
|
||||||
|
auth = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SSH_AUTH_METHOD_NONE:
|
||||||
|
default:
|
||||||
|
ssh_message_auth_set_methods(msg, SSH_AUTH_METHOD_PUBLICKEY);
|
||||||
|
ssh_message_reply_default(msg);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ssh_message_reply_default(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssh_message_free(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
tmate_debug("Opening channel");
|
||||||
|
|
||||||
|
while (!channel) {
|
||||||
|
msg = ssh_message_get(session);
|
||||||
|
if (!msg)
|
||||||
|
tmate_fatal("Error getting channel");
|
||||||
|
|
||||||
|
if (ssh_message_type(msg) == SSH_REQUEST_CHANNEL_OPEN &&
|
||||||
|
ssh_message_subtype(msg) == SSH_CHANNEL_SESSION) {
|
||||||
|
client->channel = channel = ssh_message_channel_request_open_reply_accept(msg);
|
||||||
|
if (!channel)
|
||||||
|
tmate_fatal("Error getting channel");
|
||||||
|
} else {
|
||||||
|
ssh_message_reply_default(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssh_message_free(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
tmate_debug("Getting client type");
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
msg = ssh_message_get(session);
|
||||||
|
if (!msg)
|
||||||
|
tmate_fatal("Error getting subsystem");
|
||||||
|
|
||||||
|
/* subsystem request */
|
||||||
|
if (ssh_message_type(msg) == SSH_REQUEST_CHANNEL &&
|
||||||
|
ssh_message_subtype(msg) == SSH_CHANNEL_REQUEST_SUBSYSTEM &&
|
||||||
|
!strcmp(ssh_message_channel_request_subsystem(msg), "tmate")) {
|
||||||
|
alarm(0);
|
||||||
|
ssh_message_channel_request_reply_success(msg);
|
||||||
|
tmate_spawn_slave_server(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* PTY request */
|
||||||
|
else if (ssh_message_type(msg) == SSH_REQUEST_CHANNEL &&
|
||||||
|
ssh_message_subtype(msg) == SSH_CHANNEL_REQUEST_PTY) {
|
||||||
|
|
||||||
|
client->winsize_pty.ws_col = ssh_message_channel_request_pty_width(msg);
|
||||||
|
client->winsize_pty.ws_row = ssh_message_channel_request_pty_height(msg);
|
||||||
|
ssh_message_channel_request_reply_success(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SHELL request */
|
||||||
|
else if (ssh_message_type(msg) == SSH_REQUEST_CHANNEL &&
|
||||||
|
ssh_message_subtype(msg) == SSH_CHANNEL_REQUEST_SHELL) {
|
||||||
|
alarm(0);
|
||||||
|
ssh_message_channel_request_reply_success(msg);
|
||||||
|
tmate_spawn_slave_client(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Default */
|
||||||
|
else {
|
||||||
|
ssh_message_reply_default(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssh_message_free(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_sigchld(void)
|
||||||
|
{
|
||||||
|
int status, child_dead, child_exit_status;
|
||||||
|
pid_t pid;
|
||||||
|
|
||||||
|
while ((pid = waitpid(0, &status, WNOHANG)) > 0) {
|
||||||
|
child_dead = 0;
|
||||||
|
|
||||||
|
if (WIFEXITED(status)) {
|
||||||
|
child_dead = 1;
|
||||||
|
child_exit_status = WEXITSTATUS(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WIFSIGNALED(status)) {
|
||||||
|
child_dead = 1; child_exit_status = EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!child_dead)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
tmate_debug("Child reaped pid=%d exit=%d", pid, child_exit_status);
|
||||||
|
} while (pid > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_sigalrm(void)
|
||||||
|
{
|
||||||
|
log_fatal("Connection grace period (%d) passed", SSH_GRACE_PERIOD);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void signal_handler(int sig)
|
||||||
|
{
|
||||||
|
switch (sig) {
|
||||||
|
case SIGCHLD: handle_sigchld(); break;
|
||||||
|
case SIGALRM: handle_sigalrm(); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setup_signals(void)
|
||||||
|
{
|
||||||
|
signal(SIGCHLD, signal_handler);
|
||||||
|
signal(SIGALRM, signal_handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ssh_log_cb(ssh_session session, int priority,
|
||||||
|
const char *message, void *userdata)
|
||||||
|
{
|
||||||
|
tmate_debug("[%d] %s", priority, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ssh_callbacks_struct ssh_session_callbacks = {
|
||||||
|
.log_function = ssh_log_cb
|
||||||
|
};
|
||||||
|
|
||||||
|
void tmate_ssh_server_main(int port)
|
||||||
|
{
|
||||||
|
struct tmate_ssh_client _client;
|
||||||
|
struct tmate_ssh_client *client = &_client;
|
||||||
|
ssh_bind bind;
|
||||||
|
pid_t pid;
|
||||||
|
|
||||||
|
int verbosity = SSH_LOG_NOLOG;
|
||||||
|
//int verbosity = SSH_LOG_PACKET;
|
||||||
|
|
||||||
|
setup_signals();
|
||||||
|
ssh_callbacks_init(&ssh_session_callbacks);
|
||||||
|
|
||||||
|
bind = ssh_bind_new();
|
||||||
|
if (!bind)
|
||||||
|
log_fatal("Cannot initialize ssh");
|
||||||
|
|
||||||
|
ssh_bind_options_set(bind, SSH_BIND_OPTIONS_BINDPORT, &port);
|
||||||
|
ssh_bind_options_set(bind, SSH_BIND_OPTIONS_BANNER, SSH_BANNER);
|
||||||
|
ssh_bind_options_set(bind, SSH_BIND_OPTIONS_LOG_VERBOSITY, &verbosity);
|
||||||
|
ssh_bind_options_set(bind, SSH_BIND_OPTIONS_DSAKEY, "keys/ssh_host_dsa_key");
|
||||||
|
ssh_bind_options_set(bind, SSH_BIND_OPTIONS_RSAKEY, "keys/ssh_host_rsa_key");
|
||||||
|
|
||||||
|
if (ssh_bind_listen(bind) < 0)
|
||||||
|
log_fatal("Error listening to socket: %s\n", ssh_get_error(bind));
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
client->session = ssh_new();
|
||||||
|
client->channel = NULL;
|
||||||
|
if (!client->session)
|
||||||
|
tmate_fatal("Cannot initialize session");
|
||||||
|
|
||||||
|
ssh_set_callbacks(client->session, &ssh_session_callbacks);
|
||||||
|
|
||||||
|
if (ssh_bind_accept(bind, client->session) < 0)
|
||||||
|
tmate_fatal("Error accepting connection: %s", ssh_get_error(bind));
|
||||||
|
|
||||||
|
if ((pid = fork()) < 0)
|
||||||
|
tmate_fatal("Can't fork");
|
||||||
|
|
||||||
|
if (pid) {
|
||||||
|
ssh_free(client->session);
|
||||||
|
} else {
|
||||||
|
ssh_bind_free(bind);
|
||||||
|
tmate_debug("Child spawned pid=%d", getpid());
|
||||||
|
client_bootstrap(client);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
110
tmate.h
Normal file
110
tmate.h
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
#ifndef TMATE_H
|
||||||
|
#define TMATE_H
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <msgpack.h>
|
||||||
|
#include <event.h>
|
||||||
|
|
||||||
|
#include "tmux.h"
|
||||||
|
|
||||||
|
#define tmate_debug(str, ...) log_debug("[tmate] " str, ##__VA_ARGS__)
|
||||||
|
#define tmate_warn(str, ...) log_warn("[tmate] " str, ##__VA_ARGS__)
|
||||||
|
#define tmate_info(str, ...) log_info("[tmate] " str, ##__VA_ARGS__)
|
||||||
|
#define tmate_fatal(str, ...) log_fatal("[tmate] " str, ##__VA_ARGS__)
|
||||||
|
|
||||||
|
/* tmate-encoder.c */
|
||||||
|
|
||||||
|
enum tmate_notifications {
|
||||||
|
TMATE_CLIENT_KEY,
|
||||||
|
TMATE_CLIENT_RESIZE,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tmate_encoder {
|
||||||
|
struct evbuffer *buffer;
|
||||||
|
struct event ev_readable;
|
||||||
|
msgpack_packer pk;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern void tmate_encoder_init(struct tmate_encoder *encoder);
|
||||||
|
|
||||||
|
extern void tmate_write_header(void);
|
||||||
|
extern void tmate_write_pane(int pane, const char *data, size_t size);
|
||||||
|
|
||||||
|
extern void tmate_client_key(int key);
|
||||||
|
extern void tmate_client_resize(u_int sx, u_int sy);
|
||||||
|
|
||||||
|
/* tmate-decoder.c */
|
||||||
|
|
||||||
|
#define TMATE_HLIMIT 1000
|
||||||
|
#define TMATE_MAX_MESSAGE_SIZE (16*1024)
|
||||||
|
|
||||||
|
enum tmate_commands {
|
||||||
|
TMATE_HEADER,
|
||||||
|
TMATE_SYNC_WINDOW,
|
||||||
|
TMATE_PTY_DATA,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define TMATE_PANE_ACTIVE 1
|
||||||
|
|
||||||
|
struct tmate_decoder {
|
||||||
|
struct msgpack_unpacker unpacker;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern void tmate_decoder_init(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);
|
||||||
|
|
||||||
|
/* tmate-ssh-client.c */
|
||||||
|
|
||||||
|
typedef struct ssh_session_struct* ssh_session;
|
||||||
|
typedef struct ssh_channel_struct* ssh_channel;
|
||||||
|
|
||||||
|
struct tmate_ssh_client {
|
||||||
|
ssh_session session;
|
||||||
|
ssh_channel channel;
|
||||||
|
|
||||||
|
struct tmate_encoder *encoder;
|
||||||
|
struct tmate_decoder *decoder;
|
||||||
|
|
||||||
|
struct winsize winsize_pty;
|
||||||
|
|
||||||
|
struct event ev_ssh;
|
||||||
|
};
|
||||||
|
extern void tmate_ssh_client_init(struct tmate_ssh_client *ssh_client,
|
||||||
|
struct tmate_encoder *encoder,
|
||||||
|
struct tmate_decoder *decoder);
|
||||||
|
|
||||||
|
/* tmate-ssh-client-pty.c */
|
||||||
|
|
||||||
|
struct tmate_ssh_client_pty {
|
||||||
|
ssh_session session;
|
||||||
|
ssh_channel channel;
|
||||||
|
|
||||||
|
int pty;
|
||||||
|
struct winsize winsize_pty;
|
||||||
|
|
||||||
|
struct event ev_ssh;
|
||||||
|
struct event ev_pty;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern void tmate_ssh_client_pty_init(struct tmate_ssh_client_pty *client);
|
||||||
|
extern void tmate_flush_pty(struct tmate_ssh_client_pty *client);
|
||||||
|
|
||||||
|
/* tmate-ssh-server.c */
|
||||||
|
|
||||||
|
#define SSH_BANNER "tmate"
|
||||||
|
|
||||||
|
extern void tmate_ssh_server_main(int port);
|
||||||
|
|
||||||
|
/* tmate-server.c */
|
||||||
|
|
||||||
|
extern struct tmate_encoder *tmate_encoder;
|
||||||
|
|
||||||
|
extern void tmate_spawn_slave_server(struct tmate_ssh_client *client);
|
||||||
|
extern void tmate_spawn_slave_client(struct tmate_ssh_client *client);
|
||||||
|
|
||||||
|
/* tmate-debug.c */
|
||||||
|
extern void tmate_print_trace(void);
|
||||||
|
|
||||||
|
#endif
|
11
tmux.h
11
tmux.h
@ -19,6 +19,8 @@
|
|||||||
#ifndef TMUX_H
|
#ifndef TMUX_H
|
||||||
#define TMUX_H
|
#define TMUX_H
|
||||||
|
|
||||||
|
#define TMATE_SLAVE
|
||||||
|
|
||||||
#define PROTOCOL_VERSION 7
|
#define PROTOCOL_VERSION 7
|
||||||
|
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
@ -950,8 +952,13 @@ struct window_pane {
|
|||||||
struct event changes_timer;
|
struct event changes_timer;
|
||||||
u_int changes_redraw;
|
u_int changes_redraw;
|
||||||
|
|
||||||
|
#ifdef TMATE_SLAVE
|
||||||
|
#define PANE_KILL 0x10
|
||||||
|
struct evbuffer *event_input;
|
||||||
|
#else
|
||||||
int fd;
|
int fd;
|
||||||
struct bufferevent *event;
|
struct bufferevent *event;
|
||||||
|
#endif
|
||||||
|
|
||||||
struct input_ctx ictx;
|
struct input_ctx ictx;
|
||||||
|
|
||||||
@ -1714,8 +1721,10 @@ int paste_free_index(struct paste_stack *, u_int);
|
|||||||
void paste_add(struct paste_stack *, char *, size_t, u_int);
|
void paste_add(struct paste_stack *, char *, size_t, u_int);
|
||||||
int paste_replace(struct paste_stack *, u_int, char *, size_t);
|
int paste_replace(struct paste_stack *, u_int, char *, size_t);
|
||||||
char *paste_print(struct paste_buffer *, size_t);
|
char *paste_print(struct paste_buffer *, size_t);
|
||||||
|
#ifndef TMATE_SLAVE
|
||||||
void paste_send_pane(struct paste_buffer *, struct window_pane *,
|
void paste_send_pane(struct paste_buffer *, struct window_pane *,
|
||||||
const char *, int);
|
const char *, int);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* clock.c */
|
/* clock.c */
|
||||||
extern const char clock_table[14][5][5];
|
extern const char clock_table[14][5][5];
|
||||||
@ -1967,10 +1976,12 @@ void input_init(struct window_pane *);
|
|||||||
void input_free(struct window_pane *);
|
void input_free(struct window_pane *);
|
||||||
void input_parse(struct window_pane *);
|
void input_parse(struct window_pane *);
|
||||||
|
|
||||||
|
#ifndef TMATE_SLAVE
|
||||||
/* input-key.c */
|
/* input-key.c */
|
||||||
void input_key(struct window_pane *, int);
|
void input_key(struct window_pane *, int);
|
||||||
void input_mouse(struct window_pane *, struct session *,
|
void input_mouse(struct window_pane *, struct session *,
|
||||||
struct mouse_event *);
|
struct mouse_event *);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* xterm-keys.c */
|
/* xterm-keys.c */
|
||||||
char *xterm_keys_lookup(int);
|
char *xterm_keys_lookup(int);
|
||||||
|
17
tty-keys.c
17
tty-keys.c
@ -26,6 +26,7 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "tmux.h"
|
#include "tmux.h"
|
||||||
|
#include "tmate.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handle keys input from the outside terminal. tty_default_*_keys[] are a base
|
* Handle keys input from the outside terminal. tty_default_*_keys[] are a base
|
||||||
@ -301,10 +302,10 @@ tty_keys_add(struct tty *tty, const char *s, int key)
|
|||||||
|
|
||||||
keystr = key_string_lookup_key(key);
|
keystr = key_string_lookup_key(key);
|
||||||
if ((tk = tty_keys_find(tty, s, strlen(s), &size)) == NULL) {
|
if ((tk = tty_keys_find(tty, s, strlen(s), &size)) == NULL) {
|
||||||
log_debug("new key %s: 0x%x (%s)", s, key, keystr);
|
log_debug2("new key %s: 0x%x (%s)", s, key, keystr);
|
||||||
tty_keys_add1(&tty->key_tree, s, key);
|
tty_keys_add1(&tty->key_tree, s, key);
|
||||||
} else {
|
} else {
|
||||||
log_debug("replacing key %s: 0x%x (%s)", s, key, keystr);
|
log_debug2("replacing key %s: 0x%x (%s)", s, key, keystr);
|
||||||
tk->key = key;
|
tk->key = key;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -455,7 +456,7 @@ tty_keys_next(struct tty *tty)
|
|||||||
len = EVBUFFER_LENGTH(tty->event->input);
|
len = EVBUFFER_LENGTH(tty->event->input);
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
return (0);
|
return (0);
|
||||||
log_debug("keys are %zu (%.*s)", len, (int) len, buf);
|
log_debug2("keys are %zu (%.*s)", len, (int) len, buf);
|
||||||
|
|
||||||
/* Is this device attributes response? */
|
/* Is this device attributes response? */
|
||||||
switch (tty_keys_device(tty, buf, len, &size)) {
|
switch (tty_keys_device(tty, buf, len, &size)) {
|
||||||
@ -535,7 +536,7 @@ first_key:
|
|||||||
goto complete_key;
|
goto complete_key;
|
||||||
|
|
||||||
partial_key:
|
partial_key:
|
||||||
log_debug("partial key %.*s", (int) len, buf);
|
log_debug2("partial key %.*s", (int) len, buf);
|
||||||
|
|
||||||
/* If timer is going, check for expiration. */
|
/* If timer is going, check for expiration. */
|
||||||
if (tty->flags & TTY_TIMER) {
|
if (tty->flags & TTY_TIMER) {
|
||||||
@ -562,7 +563,7 @@ partial_key:
|
|||||||
return (0);
|
return (0);
|
||||||
|
|
||||||
complete_key:
|
complete_key:
|
||||||
log_debug("complete key %.*s %#x", (int) size, buf, key);
|
log_debug2("complete key %.*s %#x", (int) size, buf, key);
|
||||||
|
|
||||||
/* Remove data from buffer. */
|
/* Remove data from buffer. */
|
||||||
evbuffer_drain(tty->event->input, size);
|
evbuffer_drain(tty->event->input, size);
|
||||||
@ -673,7 +674,7 @@ tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size)
|
|||||||
else
|
else
|
||||||
y = value;
|
y = value;
|
||||||
}
|
}
|
||||||
log_debug("mouse input: %.*s", (int) *size, buf);
|
log_debug2("mouse input: %.*s", (int) *size, buf);
|
||||||
|
|
||||||
/* Check and return the mouse input. */
|
/* Check and return the mouse input. */
|
||||||
if (b < 32 || x < 33 || y < 33)
|
if (b < 32 || x < 33 || y < 33)
|
||||||
@ -714,7 +715,7 @@ tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size)
|
|||||||
return (-1);
|
return (-1);
|
||||||
y = 10 * y + (c - '0');
|
y = 10 * y + (c - '0');
|
||||||
}
|
}
|
||||||
log_debug("mouse input (sgr): %.*s", (int) *size, buf);
|
log_debug2("mouse input (sgr): %.*s", (int) *size, buf);
|
||||||
|
|
||||||
/* Check and return the mouse input. */
|
/* Check and return the mouse input. */
|
||||||
if (x < 1 || y < 1)
|
if (x < 1 || y < 1)
|
||||||
@ -824,7 +825,7 @@ tty_keys_device(struct tty *tty, const char *buf, size_t len, size_t *size)
|
|||||||
if (*endptr != ';')
|
if (*endptr != ';')
|
||||||
class = 0;
|
class = 0;
|
||||||
|
|
||||||
log_debug("received service class %u", class);
|
log_debug2("received service class %u", class);
|
||||||
tty_set_class(tty, class);
|
tty_set_class(tty, class);
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
|
1
tty.c
1
tty.c
@ -30,6 +30,7 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "tmux.h"
|
#include "tmux.h"
|
||||||
|
#include "tmate.h"
|
||||||
|
|
||||||
void tty_read_callback(struct bufferevent *, void *);
|
void tty_read_callback(struct bufferevent *, void *);
|
||||||
void tty_error_callback(struct bufferevent *, short, void *);
|
void tty_error_callback(struct bufferevent *, short, void *);
|
||||||
|
@ -178,8 +178,10 @@ window_copy_init(struct window_pane *wp)
|
|||||||
data->searchtype = WINDOW_COPY_OFF;
|
data->searchtype = WINDOW_COPY_OFF;
|
||||||
data->searchstr = NULL;
|
data->searchstr = NULL;
|
||||||
|
|
||||||
|
#ifndef TMATE_SLAVE
|
||||||
if (wp->fd != -1)
|
if (wp->fd != -1)
|
||||||
bufferevent_disable(wp->event, EV_READ|EV_WRITE);
|
bufferevent_disable(wp->event, EV_READ|EV_WRITE);
|
||||||
|
#endif
|
||||||
|
|
||||||
data->jumptype = WINDOW_COPY_OFF;
|
data->jumptype = WINDOW_COPY_OFF;
|
||||||
data->jumpchar = '\0';
|
data->jumpchar = '\0';
|
||||||
@ -241,8 +243,10 @@ window_copy_free(struct window_pane *wp)
|
|||||||
{
|
{
|
||||||
struct window_copy_mode_data *data = wp->modedata;
|
struct window_copy_mode_data *data = wp->modedata;
|
||||||
|
|
||||||
|
#ifndef TMATE_SLAVE
|
||||||
if (wp->fd != -1)
|
if (wp->fd != -1)
|
||||||
bufferevent_enable(wp->event, EV_READ|EV_WRITE);
|
bufferevent_enable(wp->event, EV_READ|EV_WRITE);
|
||||||
|
#endif
|
||||||
|
|
||||||
free(data->searchstr);
|
free(data->searchstr);
|
||||||
free(data->inputstr);
|
free(data->inputstr);
|
||||||
|
27
window.c
27
window.c
@ -674,8 +674,12 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit)
|
|||||||
wp->shell = NULL;
|
wp->shell = NULL;
|
||||||
wp->cwd = NULL;
|
wp->cwd = NULL;
|
||||||
|
|
||||||
|
#ifdef TMATE_SLAVE
|
||||||
|
wp->event_input = evbuffer_new();
|
||||||
|
#else
|
||||||
wp->fd = -1;
|
wp->fd = -1;
|
||||||
wp->event = NULL;
|
wp->event = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
wp->mode = NULL;
|
wp->mode = NULL;
|
||||||
|
|
||||||
@ -709,10 +713,14 @@ window_pane_destroy(struct window_pane *wp)
|
|||||||
if (event_initialized(&wp->changes_timer))
|
if (event_initialized(&wp->changes_timer))
|
||||||
evtimer_del(&wp->changes_timer);
|
evtimer_del(&wp->changes_timer);
|
||||||
|
|
||||||
|
#ifdef TMATE_SLAVE
|
||||||
|
evbuffer_free(wp->event_input);
|
||||||
|
#else
|
||||||
if (wp->fd != -1) {
|
if (wp->fd != -1) {
|
||||||
bufferevent_free(wp->event);
|
bufferevent_free(wp->event);
|
||||||
close(wp->fd);
|
close(wp->fd);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
input_free(wp);
|
input_free(wp);
|
||||||
|
|
||||||
@ -737,6 +745,9 @@ int
|
|||||||
window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell,
|
window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell,
|
||||||
const char *cwd, struct environ *env, struct termios *tio, char **cause)
|
const char *cwd, struct environ *env, struct termios *tio, char **cause)
|
||||||
{
|
{
|
||||||
|
#ifdef TMATE_SLAVE
|
||||||
|
return 0;
|
||||||
|
#else
|
||||||
struct winsize ws;
|
struct winsize ws;
|
||||||
char *argv0, paneid[16];
|
char *argv0, paneid[16];
|
||||||
const char *ptr;
|
const char *ptr;
|
||||||
@ -824,6 +835,7 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell,
|
|||||||
bufferevent_enable(wp->event, EV_READ|EV_WRITE);
|
bufferevent_enable(wp->event, EV_READ|EV_WRITE);
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -869,16 +881,21 @@ window_pane_read_callback(unused struct bufferevent *bufev, void *data)
|
|||||||
struct window_pane *wp = data;
|
struct window_pane *wp = data;
|
||||||
char *new_data;
|
char *new_data;
|
||||||
size_t new_size;
|
size_t new_size;
|
||||||
|
#ifdef TMATE_SLAVE
|
||||||
|
struct evbuffer *evb = wp->event_input;
|
||||||
|
#else
|
||||||
|
struct evbuffer *evb = wp->event->input;
|
||||||
|
#endif
|
||||||
|
|
||||||
new_size = EVBUFFER_LENGTH(wp->event->input) - wp->pipe_off;
|
new_size = EVBUFFER_LENGTH(evb) - wp->pipe_off;
|
||||||
if (wp->pipe_fd != -1 && new_size > 0) {
|
if (wp->pipe_fd != -1 && new_size > 0) {
|
||||||
new_data = EVBUFFER_DATA(wp->event->input);
|
new_data = EVBUFFER_DATA(evb);
|
||||||
bufferevent_write(wp->pipe_event, new_data, new_size);
|
bufferevent_write(wp->pipe_event, new_data, new_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
input_parse(wp);
|
input_parse(wp);
|
||||||
|
|
||||||
wp->pipe_off = EVBUFFER_LENGTH(wp->event->input);
|
wp->pipe_off = EVBUFFER_LENGTH(evb);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we get here, we're not outputting anymore, so set the silence
|
* If we get here, we're not outputting anymore, so set the silence
|
||||||
@ -1022,6 +1039,7 @@ window_pane_reset_mode(struct window_pane *wp)
|
|||||||
wp->flags |= PANE_REDRAW;
|
wp->flags |= PANE_REDRAW;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef TMATE_SLAVE
|
||||||
void
|
void
|
||||||
window_pane_key(struct window_pane *wp, struct session *sess, int key)
|
window_pane_key(struct window_pane *wp, struct session *sess, int key)
|
||||||
{
|
{
|
||||||
@ -1070,14 +1088,17 @@ window_pane_mouse(
|
|||||||
} else if (wp->fd != -1)
|
} else if (wp->fd != -1)
|
||||||
input_mouse(wp, sess, m);
|
input_mouse(wp, sess, m);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int
|
int
|
||||||
window_pane_visible(struct window_pane *wp)
|
window_pane_visible(struct window_pane *wp)
|
||||||
{
|
{
|
||||||
struct window *w = wp->window;
|
struct window *w = wp->window;
|
||||||
|
|
||||||
|
#ifndef TMATE_SLAVE
|
||||||
if (wp->layout_cell == NULL)
|
if (wp->layout_cell == NULL)
|
||||||
return (0);
|
return (0);
|
||||||
|
#endif
|
||||||
if (wp->xoff >= w->sx || wp->yoff >= w->sy)
|
if (wp->xoff >= w->sx || wp->yoff >= w->sy)
|
||||||
return (0);
|
return (0);
|
||||||
if (wp->xoff + wp->sx > w->sx || wp->yoff + wp->sy > w->sy)
|
if (wp->xoff + wp->sx > w->sx || wp->yoff + wp->sy > w->sy)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user