mirror of
https://github.com/tmate-io/tmate-ssh-server.git
synced 2020-11-18 19:53:51 -08:00
merge complete
This commit is contained in:
parent
8284dd910c
commit
1a48abd0be
12
Makefile.am
12
Makefile.am
@ -1,7 +1,7 @@
|
|||||||
# Makefile.am
|
# Makefile.am
|
||||||
|
|
||||||
# Obvious program stuff.
|
# Obvious program stuff.
|
||||||
bin_PROGRAMS = tmate
|
bin_PROGRAMS = tmate-slave
|
||||||
CLEANFILES = tmate.1.mdoc tmate.1.man
|
CLEANFILES = tmate.1.mdoc tmate.1.man
|
||||||
|
|
||||||
# Distribution tarball options.
|
# Distribution tarball options.
|
||||||
@ -185,7 +185,7 @@ dist_tmate_slave_SOURCES = \
|
|||||||
tmate-ssh-daemon.c \
|
tmate-ssh-daemon.c \
|
||||||
tmate-ssh-exec.c \
|
tmate-ssh-exec.c \
|
||||||
tmate-ssh-server.c \
|
tmate-ssh-server.c \
|
||||||
tmux-bare.c \
|
tmux.c \
|
||||||
tty-acs.c \
|
tty-acs.c \
|
||||||
tty-keys.c \
|
tty-keys.c \
|
||||||
tty-term.c \
|
tty-term.c \
|
||||||
@ -228,7 +228,7 @@ if NO_FGETLN
|
|||||||
nodist_tmate_slave_SOURCES += compat/fgetln.c
|
nodist_tmate_slave_SOURCES += compat/fgetln.c
|
||||||
endif
|
endif
|
||||||
if NO_FPARSELN
|
if NO_FPARSELN
|
||||||
nodist_tmux_SOURCES += compat/fparseln.c
|
nodist_tmate_slave_SOURCES += compat/fparseln.c
|
||||||
endif
|
endif
|
||||||
if NO_GETOPT
|
if NO_GETOPT
|
||||||
nodist_tmate_slave_SOURCES += compat/getopt.c
|
nodist_tmate_slave_SOURCES += compat/getopt.c
|
||||||
@ -249,11 +249,11 @@ if NO_B64_NTOP
|
|||||||
nodist_tmate_slave_SOURCES += compat/b64_ntop.c
|
nodist_tmate_slave_SOURCES += compat/b64_ntop.c
|
||||||
endif
|
endif
|
||||||
if NO_CFMAKERAW
|
if NO_CFMAKERAW
|
||||||
nodist_tmate_SOURCES += compat/cfmakeraw.c
|
nodist_tmate_slave_SOURCES += compat/cfmakeraw.c
|
||||||
endif
|
endif
|
||||||
if NO_OPENAT
|
if NO_OPENAT
|
||||||
nodist_tmate_SOURCES += compat/openat.c
|
nodist_tmate_slave_SOURCES += compat/openat.c
|
||||||
endif
|
endif
|
||||||
if NO_REALLOCARRAY
|
if NO_REALLOCARRAY
|
||||||
nodist_tmate_SOURCES += compat/reallocarray.c
|
nodist_tmate_slave_SOURCES += compat/reallocarray.c
|
||||||
endif
|
endif
|
||||||
|
12
client.c
12
client.c
@ -227,8 +227,10 @@ client_main(struct event_base *base, int argc, char **argv, int flags,
|
|||||||
struct termios tio, saved_tio;
|
struct termios tio, saved_tio;
|
||||||
size_t size;
|
size_t size;
|
||||||
|
|
||||||
|
#ifndef TMATE_SLAVE
|
||||||
/* Ignore SIGCHLD now or daemon() in the server will leave a zombie. */
|
/* Ignore SIGCHLD now or daemon() in the server will leave a zombie. */
|
||||||
signal(SIGCHLD, SIG_IGN);
|
signal(SIGCHLD, SIG_IGN);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Save the flags. */
|
/* Save the flags. */
|
||||||
client_flags = flags;
|
client_flags = flags;
|
||||||
@ -264,10 +266,10 @@ client_main(struct event_base *base, int argc, char **argv, int flags,
|
|||||||
|
|
||||||
#ifdef TMATE_SLAVE
|
#ifdef TMATE_SLAVE
|
||||||
fd = tmate_session->tmux_socket_fd;
|
fd = tmate_session->tmux_socket_fd;
|
||||||
#else
|
|
||||||
/* Create client process structure (starts logging). */
|
/* Create client process structure (starts logging). */
|
||||||
client_proc = proc_start("client", base, 0, client_signal);
|
client_proc = proc_start("client", base, 0, client_signal);
|
||||||
|
#else
|
||||||
/* Initialize the client socket and start the server. */
|
/* Initialize the client socket and start the server. */
|
||||||
fd = client_connect(base, socket_path, cmdflags & CMD_STARTSERVER);
|
fd = client_connect(base, socket_path, cmdflags & CMD_STARTSERVER);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
@ -306,11 +308,13 @@ client_main(struct event_base *base, int argc, char **argv, int flags,
|
|||||||
fatal("pledge failed");
|
fatal("pledge failed");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef TMATE_SLAVE
|
||||||
/* Free stuff that is not used in the client. */
|
/* Free stuff that is not used in the client. */
|
||||||
options_free(global_options);
|
options_free(global_options);
|
||||||
options_free(global_s_options);
|
options_free(global_s_options);
|
||||||
options_free(global_w_options);
|
options_free(global_w_options);
|
||||||
environ_free(global_environ);
|
environ_free(global_environ);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Create stdin handler. */
|
/* Create stdin handler. */
|
||||||
setblocking(STDIN_FILENO, 0);
|
setblocking(STDIN_FILENO, 0);
|
||||||
@ -524,11 +528,9 @@ client_signal(int sig)
|
|||||||
client_exitval = 1;
|
client_exitval = 1;
|
||||||
proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
|
proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
|
||||||
break;
|
break;
|
||||||
#ifndef TMATE_SLAVE
|
|
||||||
case SIGWINCH:
|
case SIGWINCH:
|
||||||
proc_send(client_peer, MSG_RESIZE, -1, NULL, 0);
|
proc_send(client_peer, MSG_RESIZE, -1, NULL, 0);
|
||||||
break;
|
break;
|
||||||
#endif
|
|
||||||
case SIGCONT:
|
case SIGCONT:
|
||||||
memset(&sigact, 0, sizeof sigact);
|
memset(&sigact, 0, sizeof sigact);
|
||||||
sigemptyset(&sigact.sa_mask);
|
sigemptyset(&sigact.sa_mask);
|
||||||
@ -642,10 +644,10 @@ client_dispatch_wait(struct imsg *imsg, const char *shellcmd)
|
|||||||
if (datalen == 0 || data[datalen - 1] != '\0')
|
if (datalen == 0 || data[datalen - 1] != '\0')
|
||||||
fatalx("bad MSG_SHELL string");
|
fatalx("bad MSG_SHELL string");
|
||||||
|
|
||||||
clear_signals(0);
|
|
||||||
#ifdef TMATE_SLAVE
|
#ifdef TMATE_SLAVE
|
||||||
exit(1);
|
exit(1);
|
||||||
#else
|
#else
|
||||||
|
clear_signals(0);
|
||||||
client_exec(data, shellcmd);
|
client_exec(data, shellcmd);
|
||||||
#endif
|
#endif
|
||||||
/* NOTREACHED */
|
/* NOTREACHED */
|
||||||
|
@ -125,7 +125,6 @@ cmd_resize_pane_exec(struct cmd *self, struct cmd_q *cmdq)
|
|||||||
server_redraw_window(wl->window);
|
server_redraw_window(wl->window);
|
||||||
|
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -173,4 +172,5 @@ cmd_resize_pane_mouse_update(struct client *c, struct mouse_event *m)
|
|||||||
server_redraw_window(wl->window);
|
server_redraw_window(wl->window);
|
||||||
else
|
else
|
||||||
c->tty.mouse_drag_update = NULL;
|
c->tty.mouse_drag_update = NULL;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
6
format.c
6
format.c
@ -380,9 +380,14 @@ format_cb_window_visible_layout(struct format_tree *ft, struct format_entry *fe)
|
|||||||
if (w == NULL)
|
if (w == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
#ifdef TMATE_SLAVE
|
||||||
|
fe->value = xstrdup("no layout");
|
||||||
|
#else
|
||||||
fe->value = layout_dump(w->layout_root);
|
fe->value = layout_dump(w->layout_root);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef TMATE_SLAVE
|
||||||
/* Callback for pane_start_command. */
|
/* Callback for pane_start_command. */
|
||||||
void
|
void
|
||||||
format_cb_start_command(struct format_tree *ft, struct format_entry *fe)
|
format_cb_start_command(struct format_tree *ft, struct format_entry *fe)
|
||||||
@ -432,6 +437,7 @@ format_cb_current_path(struct format_tree *ft, struct format_entry *fe)
|
|||||||
if (cwd != NULL)
|
if (cwd != NULL)
|
||||||
fe->value = xstrdup(cwd);
|
fe->value = xstrdup(cwd);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Callback for history_bytes. */
|
/* Callback for history_bytes. */
|
||||||
void
|
void
|
||||||
|
2
job.c
2
job.c
@ -65,7 +65,9 @@ job_run(const char *cmd, struct session *s, const char *cwd,
|
|||||||
close(out[1]);
|
close(out[1]);
|
||||||
return (NULL);
|
return (NULL);
|
||||||
case 0: /* child */
|
case 0: /* child */
|
||||||
|
#ifndef TMATE_SLAVE
|
||||||
clear_signals(1);
|
clear_signals(1);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (cwd == NULL || chdir(cwd) != 0) {
|
if (cwd == NULL || chdir(cwd) != 0) {
|
||||||
if ((home = find_home()) == NULL || chdir(home) != 0)
|
if ((home = find_home()) == NULL || chdir(home) != 0)
|
||||||
|
10
log.c
10
log.c
@ -43,7 +43,7 @@ static void log_event_cb(int, const char *);
|
|||||||
static void log_vwrite(int, const char *, va_list);
|
static void log_vwrite(int, const char *, va_list);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
log_event_cb(unused int severity, const char *msg)
|
log_event_cb(__unused int severity, const char *msg)
|
||||||
{
|
{
|
||||||
log_debug("%s", msg);
|
log_debug("%s", msg);
|
||||||
}
|
}
|
||||||
@ -52,14 +52,14 @@ log_event_cb(unused int severity, const char *msg)
|
|||||||
void
|
void
|
||||||
log_add_level(void)
|
log_add_level(void)
|
||||||
{
|
{
|
||||||
logging_settings.log_level++;
|
log_settings.log_level++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get log level. */
|
/* Get log level. */
|
||||||
int
|
int
|
||||||
log_get_level(void)
|
log_get_level(void)
|
||||||
{
|
{
|
||||||
return (logging_settings.log_level);
|
return (log_settings.log_level);
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_logging(const char *program_name, bool use_syslog, int log_level)
|
void init_logging(const char *program_name, bool use_syslog, int log_level)
|
||||||
@ -130,7 +130,7 @@ fatal(const char *msg, ...)
|
|||||||
va_start(ap, msg);
|
va_start(ap, msg);
|
||||||
if (asprintf(&fmt, "fatal: %s: %s", msg, strerror(errno)) == -1)
|
if (asprintf(&fmt, "fatal: %s: %s", msg, strerror(errno)) == -1)
|
||||||
exit(1);
|
exit(1);
|
||||||
log_vwrite(fmt, ap);
|
log_vwrite(LOG_CRIT, fmt, ap);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,7 +144,7 @@ fatalx(const char *msg, ...)
|
|||||||
va_start(ap, msg);
|
va_start(ap, msg);
|
||||||
if (asprintf(&fmt, "fatal: %s", msg) == -1)
|
if (asprintf(&fmt, "fatal: %s", msg) == -1)
|
||||||
exit(1);
|
exit(1);
|
||||||
log_vwrite(fmt, ap);
|
log_vwrite(LOG_CRIT, fmt, ap);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
8
proc.c
8
proc.c
@ -172,6 +172,10 @@ proc_start(const char *name, struct event_base *base, int forkflag,
|
|||||||
struct tmuxproc *tp;
|
struct tmuxproc *tp;
|
||||||
struct utsname u;
|
struct utsname u;
|
||||||
|
|
||||||
|
#ifdef TMATE_SLAVE
|
||||||
|
if (forkflag)
|
||||||
|
fatal("can't fork");
|
||||||
|
#else
|
||||||
if (forkflag) {
|
if (forkflag) {
|
||||||
switch (fork()) {
|
switch (fork()) {
|
||||||
case -1:
|
case -1:
|
||||||
@ -188,8 +192,8 @@ proc_start(const char *name, struct event_base *base, int forkflag,
|
|||||||
if (event_reinit(base) != 0)
|
if (event_reinit(base) != 0)
|
||||||
fatalx("event_reinit failed");
|
fatalx("event_reinit failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
log_open(name);
|
log_open(name);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_SETPROCTITLE
|
#ifdef HAVE_SETPROCTITLE
|
||||||
setproctitle("%s (%s)", name, socket_path);
|
setproctitle("%s (%s)", name, socket_path);
|
||||||
@ -206,8 +210,10 @@ proc_start(const char *name, struct event_base *base, int forkflag,
|
|||||||
tp = xcalloc(1, sizeof *tp);
|
tp = xcalloc(1, sizeof *tp);
|
||||||
tp->name = xstrdup(name);
|
tp->name = xstrdup(name);
|
||||||
|
|
||||||
|
#ifndef TMATE_SLAVE
|
||||||
tp->signalcb = signalcb;
|
tp->signalcb = signalcb;
|
||||||
set_signals(proc_signal_cb, tp);
|
set_signals(proc_signal_cb, tp);
|
||||||
|
#endif
|
||||||
|
|
||||||
return (tp);
|
return (tp);
|
||||||
}
|
}
|
||||||
|
@ -313,10 +313,6 @@ server_client_detach(struct client *c, enum msgtype msgtype)
|
|||||||
key_code
|
key_code
|
||||||
server_client_check_mouse(struct client *c)
|
server_client_check_mouse(struct client *c)
|
||||||
{
|
{
|
||||||
#ifdef TMATE_SLAVE
|
|
||||||
/* TODO Support mouse */
|
|
||||||
return;
|
|
||||||
#else
|
|
||||||
struct session *s = c->session;
|
struct session *s = c->session;
|
||||||
struct mouse_event *m = &c->tty.mouse;
|
struct mouse_event *m = &c->tty.mouse;
|
||||||
struct window *w;
|
struct window *w;
|
||||||
@ -539,7 +535,6 @@ server_client_check_mouse(struct client *c)
|
|||||||
key |= KEYC_SHIFT;
|
key |= KEYC_SHIFT;
|
||||||
|
|
||||||
return (key);
|
return (key);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Is this fast enough to probably be a paste? */
|
/* Is this fast enough to probably be a paste? */
|
||||||
|
@ -332,11 +332,11 @@ server_destroy_pane(struct window_pane *wp, int hooks)
|
|||||||
server_unzoom_window(w);
|
server_unzoom_window(w);
|
||||||
#ifndef TMATE_SLAVE
|
#ifndef TMATE_SLAVE
|
||||||
layout_close_pane(wp);
|
layout_close_pane(wp);
|
||||||
#endif
|
|
||||||
window_remove_pane(w, wp);
|
window_remove_pane(w, wp);
|
||||||
|
|
||||||
if (hooks && cmd_find_from_window(&fs, w) == 0)
|
if (hooks && cmd_find_from_window(&fs, w) == 0)
|
||||||
hooks_run(hooks_get(fs.s), NULL, &fs, "pane-exited");
|
hooks_run(hooks_get(fs.s), NULL, &fs, "pane-exited");
|
||||||
|
#endif
|
||||||
|
|
||||||
if (TAILQ_EMPTY(&w->panes))
|
if (TAILQ_EMPTY(&w->panes))
|
||||||
server_kill_window(w);
|
server_kill_window(w);
|
||||||
|
27
server.c
27
server.c
@ -135,7 +135,9 @@ server_create_socket(void)
|
|||||||
int
|
int
|
||||||
server_start(struct event_base *base, int lockfd, char *lockfile)
|
server_start(struct event_base *base, int lockfd, char *lockfile)
|
||||||
{
|
{
|
||||||
#ifndef TMATE_SLAVE
|
#ifdef TMATE_SLAVE
|
||||||
|
server_proc = proc_start("server", base, 0, server_signal);
|
||||||
|
#else
|
||||||
int pair[2];
|
int pair[2];
|
||||||
|
|
||||||
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0)
|
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0)
|
||||||
@ -186,15 +188,23 @@ server_start(struct event_base *base, int lockfd, char *lockfile)
|
|||||||
|
|
||||||
start_cfg();
|
start_cfg();
|
||||||
|
|
||||||
|
#ifndef TMATE_SLAVE
|
||||||
status_prompt_load_history();
|
status_prompt_load_history();
|
||||||
|
#endif
|
||||||
|
|
||||||
server_add_accept(0);
|
server_add_accept(0);
|
||||||
|
|
||||||
proc_loop(server_proc, server_loop);
|
proc_loop(server_proc, server_loop);
|
||||||
|
#ifndef TMATE_SLAVE
|
||||||
status_prompt_save_history();
|
status_prompt_save_history();
|
||||||
|
#endif
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef TMATE_SLAVE
|
||||||
|
static int tmate_server_request_exit;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Server loop callback. */
|
/* Server loop callback. */
|
||||||
int
|
int
|
||||||
server_loop(void)
|
server_loop(void)
|
||||||
@ -203,10 +213,15 @@ server_loop(void)
|
|||||||
|
|
||||||
server_client_loop();
|
server_client_loop();
|
||||||
|
|
||||||
|
#ifdef TMATE_SLAVE
|
||||||
|
if (!tmate_server_request_exit)
|
||||||
|
return 0;
|
||||||
|
#else
|
||||||
if (!options_get_number(global_options, "exit-unattached")) {
|
if (!options_get_number(global_options, "exit-unattached")) {
|
||||||
if (!RB_EMPTY(&sessions))
|
if (!RB_EMPTY(&sessions))
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
TAILQ_FOREACH(c, &clients, entry) {
|
TAILQ_FOREACH(c, &clients, entry) {
|
||||||
if (c->session != NULL)
|
if (c->session != NULL)
|
||||||
@ -221,11 +236,7 @@ server_loop(void)
|
|||||||
if (!TAILQ_EMPTY(&clients))
|
if (!TAILQ_EMPTY(&clients))
|
||||||
return (0);
|
return (0);
|
||||||
|
|
||||||
#ifdef TMATE_SLAVE
|
|
||||||
return server_shutdown;
|
|
||||||
#else
|
|
||||||
return (1);
|
return (1);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Exit the server by killing all clients and windows. */
|
/* Exit the server by killing all clients and windows. */
|
||||||
@ -235,6 +246,10 @@ server_send_exit(void)
|
|||||||
struct client *c, *c1;
|
struct client *c, *c1;
|
||||||
struct session *s, *s1;
|
struct session *s, *s1;
|
||||||
|
|
||||||
|
#ifdef TMATE_SLAVE
|
||||||
|
tmate_server_request_exit = 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
cmd_wait_for_flush();
|
cmd_wait_for_flush();
|
||||||
|
|
||||||
TAILQ_FOREACH_SAFE(c, &clients, entry, c1) {
|
TAILQ_FOREACH_SAFE(c, &clients, entry, c1) {
|
||||||
@ -353,7 +368,6 @@ server_signal(int sig)
|
|||||||
server_child_signal();
|
server_child_signal();
|
||||||
break;
|
break;
|
||||||
case SIGUSR1:
|
case SIGUSR1:
|
||||||
#ifndef TMATE_SLAVE
|
|
||||||
event_del(&server_ev_accept);
|
event_del(&server_ev_accept);
|
||||||
fd = server_create_socket();
|
fd = server_create_socket();
|
||||||
if (fd != -1) {
|
if (fd != -1) {
|
||||||
@ -362,7 +376,6 @@ server_signal(int sig)
|
|||||||
server_update_socket();
|
server_update_socket();
|
||||||
}
|
}
|
||||||
server_add_accept(0);
|
server_add_accept(0);
|
||||||
#endif
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
#include "tmux.h"
|
#include "tmux.h"
|
||||||
|
#include "tmate.h"
|
||||||
|
|
||||||
struct sessions sessions;
|
struct sessions sessions;
|
||||||
u_int next_session_id;
|
u_int next_session_id;
|
||||||
@ -343,6 +344,9 @@ session_new(struct session *s, const char *name, int argc, char **argv,
|
|||||||
shell = _PATH_BSHELL;
|
shell = _PATH_BSHELL;
|
||||||
|
|
||||||
hlimit = options_get_number(s->options, "history-limit");
|
hlimit = options_get_number(s->options, "history-limit");
|
||||||
|
#ifdef TMATE_SLAVE
|
||||||
|
hlimit = hlimit > TMATE_HLIMIT ? TMATE_HLIMIT : hlimit;
|
||||||
|
#endif
|
||||||
w = window_create(name, argc, argv, path, shell, cwd, env, s->tio,
|
w = window_create(name, argc, argv, path, shell, cwd, env, s->tio,
|
||||||
s->sx, s->sy, hlimit, cause);
|
s->sx, s->sy, hlimit, cause);
|
||||||
if (w == NULL) {
|
if (w == NULL) {
|
||||||
|
4
signal.c
4
signal.c
@ -24,6 +24,8 @@
|
|||||||
|
|
||||||
#include "tmux.h"
|
#include "tmux.h"
|
||||||
|
|
||||||
|
#ifndef TMATE_SLAVE
|
||||||
|
|
||||||
struct event ev_sighup;
|
struct event ev_sighup;
|
||||||
struct event ev_sigchld;
|
struct event ev_sigchld;
|
||||||
struct event ev_sigcont;
|
struct event ev_sigcont;
|
||||||
@ -103,3 +105,5 @@ clear_signals(int after_fork)
|
|||||||
event_del(&ev_sigwinch);
|
event_del(&ev_sigwinch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
@ -2,11 +2,10 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include "tmate.h"
|
#include "tmate.h"
|
||||||
#include "tmate-protocol.h"
|
#include "tmate-protocol.h"
|
||||||
|
#include "window-copy.h"
|
||||||
|
|
||||||
char *tmate_left_status, *tmate_right_status;
|
char *tmate_left_status, *tmate_right_status;
|
||||||
|
|
||||||
static struct session *main_session;
|
|
||||||
|
|
||||||
static void tmate_header(struct tmate_session *session,
|
static void tmate_header(struct tmate_session *session,
|
||||||
struct tmate_unpacker *uk)
|
struct tmate_unpacker *uk)
|
||||||
{
|
{
|
||||||
@ -24,8 +23,8 @@ static void tmate_header(struct tmate_session *session,
|
|||||||
client_version = unpack_string(uk);
|
client_version = unpack_string(uk);
|
||||||
}
|
}
|
||||||
|
|
||||||
tmate_debug("new master, client version: %s, protocol version: %d",
|
tmate_notice("new master, client version: %s, protocol version: %d",
|
||||||
client_version, session->client_protocol_version);
|
client_version, session->client_protocol_version);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
if (strcmp(client_version, TMATE_LATEST_VERSION))
|
if (strcmp(client_version, TMATE_LATEST_VERSION))
|
||||||
@ -113,10 +112,7 @@ static void tmate_sync_windows(struct session *s,
|
|||||||
|
|
||||||
wl = winlink_find_by_index(&s->windows, idx);
|
wl = winlink_find_by_index(&s->windows, idx);
|
||||||
if (!wl) {
|
if (!wl) {
|
||||||
/* Avoid memory bloats with the scroll buffer */
|
wl = session_new(s, name, 0, NULL, NULL, NULL, idx, &cause);
|
||||||
options_set_number(&s->options,
|
|
||||||
"history-limit", TMATE_HLIMIT);
|
|
||||||
wl = session_new(s, name, "", NULL, idx, &cause);
|
|
||||||
if (!wl)
|
if (!wl)
|
||||||
tmate_fatal("can't create window idx=%d", idx);
|
tmate_fatal("can't create window idx=%d", idx);
|
||||||
}
|
}
|
||||||
@ -146,7 +142,7 @@ static void tmate_sync_windows(struct session *s,
|
|||||||
server_redraw_window(wl->window);
|
server_redraw_window(wl->window);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tmate_sync_layout(struct tmate_session *session,
|
static void tmate_sync_layout(__unused struct tmate_session *session,
|
||||||
struct tmate_unpacker *uk)
|
struct tmate_unpacker *uk)
|
||||||
{
|
{
|
||||||
struct session *s;
|
struct session *s;
|
||||||
@ -157,8 +153,8 @@ static void tmate_sync_layout(struct tmate_session *session,
|
|||||||
|
|
||||||
s = RB_MIN(sessions, &sessions);
|
s = RB_MIN(sessions, &sessions);
|
||||||
if (!s) {
|
if (!s) {
|
||||||
s = session_create("default", NULL, "default", NULL,
|
s = session_create("default", 0, NULL, "/", "/",
|
||||||
NULL, 0, sx, sy, &cause);
|
NULL, NULL, 0, sx, sy, &cause);
|
||||||
if (!s)
|
if (!s)
|
||||||
tmate_fatal("can't create main session");
|
tmate_fatal("can't create main session");
|
||||||
}
|
}
|
||||||
@ -169,7 +165,7 @@ static void tmate_sync_layout(struct tmate_session *session,
|
|||||||
tmate_sync_windows(s, uk);
|
tmate_sync_windows(s, uk);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tmate_pty_data(struct tmate_session *session,
|
static void tmate_pty_data(__unused struct tmate_session *session,
|
||||||
struct tmate_unpacker *uk)
|
struct tmate_unpacker *uk)
|
||||||
{
|
{
|
||||||
struct window_pane *wp;
|
struct window_pane *wp;
|
||||||
@ -190,7 +186,7 @@ static void tmate_pty_data(struct tmate_session *session,
|
|||||||
wp->window->flags |= WINDOW_SILENCE;
|
wp->window->flags |= WINDOW_SILENCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tmate_exec_cmd(struct tmate_session *session,
|
static void tmate_exec_cmd(__unused struct tmate_session *session,
|
||||||
struct tmate_unpacker *uk)
|
struct tmate_unpacker *uk)
|
||||||
{
|
{
|
||||||
struct cmd_q *cmd_q;
|
struct cmd_q *cmd_q;
|
||||||
@ -205,26 +201,24 @@ static void tmate_exec_cmd(struct tmate_session *session,
|
|||||||
}
|
}
|
||||||
|
|
||||||
cmd_q = cmdq_new(NULL);
|
cmd_q = cmdq_new(NULL);
|
||||||
cmdq_run(cmd_q, cmdlist);
|
cmdq_run(cmd_q, cmdlist, NULL);
|
||||||
cmd_list_free(cmdlist);
|
cmd_list_free(cmdlist);
|
||||||
cmdq_free(cmd_q);
|
cmdq_free(cmd_q);
|
||||||
out:
|
out:
|
||||||
free(cmd_str);
|
free(cmd_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tmate_failed_cmd(struct tmate_session *session,
|
static void tmate_failed_cmd(__unused struct tmate_session *session,
|
||||||
struct tmate_unpacker *uk)
|
struct tmate_unpacker *uk)
|
||||||
{
|
{
|
||||||
struct client *c;
|
struct client *c;
|
||||||
unsigned int i;
|
|
||||||
int client_id;
|
int client_id;
|
||||||
char *cause;
|
char *cause;
|
||||||
|
|
||||||
client_id = unpack_int(uk);
|
client_id = unpack_int(uk);
|
||||||
cause = unpack_string(uk);
|
cause = unpack_string(uk);
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
|
TAILQ_FOREACH(c, &clients, entry) {
|
||||||
c = ARRAY_ITEM(&clients, i);
|
|
||||||
if (c && c->id == client_id) {
|
if (c && c->id == client_id) {
|
||||||
*cause = toupper((u_char) *cause);
|
*cause = toupper((u_char) *cause);
|
||||||
status_message_set(c, "%s", cause);
|
status_message_set(c, "%s", cause);
|
||||||
@ -235,34 +229,25 @@ static void tmate_failed_cmd(struct tmate_session *session,
|
|||||||
free(cause);
|
free(cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tmate_status(struct tmate_session *session,
|
static void tmate_status(__unused struct tmate_session *session,
|
||||||
struct tmate_unpacker *uk)
|
struct tmate_unpacker *uk)
|
||||||
{
|
{
|
||||||
struct client *c;
|
struct client *c;
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
free(tmate_left_status);
|
free(tmate_left_status);
|
||||||
free(tmate_right_status);
|
free(tmate_right_status);
|
||||||
tmate_left_status = unpack_string(uk);
|
tmate_left_status = unpack_string(uk);
|
||||||
tmate_right_status = unpack_string(uk);
|
tmate_right_status = unpack_string(uk);
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
|
TAILQ_FOREACH(c, &clients, entry)
|
||||||
c = ARRAY_ITEM(&clients, i);
|
c->flags |= CLIENT_STATUS;
|
||||||
if (c)
|
|
||||||
c->flags |= CLIENT_STATUS;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void window_copy_redraw_screen(struct window_pane *);
|
|
||||||
extern int window_copy_update_selection(struct window_pane *);
|
|
||||||
extern void window_copy_init_for_output(struct window_pane *);
|
|
||||||
|
|
||||||
static void tmate_sync_copy_mode(struct tmate_session *session,
|
static void tmate_sync_copy_mode(struct tmate_session *session,
|
||||||
struct tmate_unpacker *uk)
|
struct tmate_unpacker *uk)
|
||||||
{
|
{
|
||||||
struct tmate_unpacker cm_uk, sel_uk, input_uk;
|
struct tmate_unpacker cm_uk, sel_uk, input_uk;
|
||||||
struct window_copy_mode_data *data;
|
struct window_copy_mode_data *data;
|
||||||
struct screen_write_ctx ctx;
|
|
||||||
struct window_pane *wp;
|
struct window_pane *wp;
|
||||||
int pane_id;
|
int pane_id;
|
||||||
int base_backing = 1;
|
int base_backing = 1;
|
||||||
@ -288,7 +273,7 @@ static void tmate_sync_copy_mode(struct tmate_session *session,
|
|||||||
|
|
||||||
if (window_pane_set_mode(wp, &window_copy_mode) == 0) {
|
if (window_pane_set_mode(wp, &window_copy_mode) == 0) {
|
||||||
if (base_backing)
|
if (base_backing)
|
||||||
window_copy_init_from_pane(wp);
|
window_copy_init_from_pane(wp, 0);
|
||||||
else
|
else
|
||||||
window_copy_init_for_output(wp);
|
window_copy_init_for_output(wp);
|
||||||
}
|
}
|
||||||
@ -335,11 +320,11 @@ static void tmate_sync_copy_mode(struct tmate_session *session,
|
|||||||
data->inputprompt = NULL;
|
data->inputprompt = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
window_copy_update_selection(wp);
|
window_copy_update_selection(wp, 1);
|
||||||
window_copy_redraw_screen(wp);
|
window_copy_redraw_screen(wp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tmate_write_copy_mode(struct tmate_session *session,
|
static void tmate_write_copy_mode(__unused struct tmate_session *session,
|
||||||
struct tmate_unpacker *uk)
|
struct tmate_unpacker *uk)
|
||||||
{
|
{
|
||||||
struct window_pane *wp;
|
struct window_pane *wp;
|
||||||
|
@ -10,7 +10,7 @@ static void __tmate_notify(const char *msg)
|
|||||||
pack(string, msg);
|
pack(string, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void printflike1 tmate_notify(const char *fmt, ...)
|
void tmate_notify(const char *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
char msg[1024];
|
char msg[1024];
|
||||||
@ -22,13 +22,14 @@ void printflike1 tmate_notify(const char *fmt, ...)
|
|||||||
__tmate_notify(msg);
|
__tmate_notify(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __tmate_notify_later(evutil_socket_t fd, short what, void *arg)
|
static void __tmate_notify_later(__unused evutil_socket_t fd,
|
||||||
|
__unused short what, void *arg)
|
||||||
{
|
{
|
||||||
char *msg = arg;
|
char *msg = arg;
|
||||||
__tmate_notify(msg);
|
__tmate_notify(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void printflike2 tmate_notify_later(int timeout, const char *fmt, ...)
|
void tmate_notify_later(int timeout, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
va_list ap;
|
va_list ap;
|
||||||
@ -42,12 +43,12 @@ void printflike2 tmate_notify_later(int timeout, const char *fmt, ...)
|
|||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* FIXME leaks like crazy when calling tmate_notify_later()
|
* FIXME leaks when calling tmate_notify_later()
|
||||||
* multiple times.
|
* multiple times.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
evtimer_assign(&tmate_session->ev_notify_timer, ev_base,
|
evtimer_set(&tmate_session->ev_notify_timer,
|
||||||
__tmate_notify_later, msg);
|
__tmate_notify_later, msg);
|
||||||
evtimer_add(&tmate_session->ev_notify_timer, &tv);
|
evtimer_add(&tmate_session->ev_notify_timer, &tv);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,6 +93,13 @@ void tmate_client_pane_key(int pane_id, int key)
|
|||||||
pack(int, key);
|
pack(int, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern const struct cmd_entry cmd_bind_key_entry;
|
||||||
|
extern const struct cmd_entry cmd_unbind_key_entry;
|
||||||
|
extern const struct cmd_entry cmd_set_option_entry;
|
||||||
|
extern const struct cmd_entry cmd_set_window_option_entry;
|
||||||
|
extern const struct cmd_entry cmd_detach_client_entry;
|
||||||
|
extern const struct cmd_entry cmd_attach_session_entry;
|
||||||
|
|
||||||
static const struct cmd_entry *local_cmds[] = {
|
static const struct cmd_entry *local_cmds[] = {
|
||||||
&cmd_bind_key_entry,
|
&cmd_bind_key_entry,
|
||||||
&cmd_unbind_key_entry,
|
&cmd_unbind_key_entry,
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
#include "tmate.h"
|
#include "tmate.h"
|
||||||
#include "tmate-protocol.h"
|
#include "tmate-protocol.h"
|
||||||
|
|
||||||
static void on_encoder_buffer_ready(evutil_socket_t fd, short what, void *arg)
|
static void on_encoder_buffer_ready(__unused evutil_socket_t fd,
|
||||||
|
__unused short what, void *arg)
|
||||||
{
|
{
|
||||||
struct tmate_encoder *encoder = arg;
|
struct tmate_encoder *encoder = arg;
|
||||||
|
|
||||||
@ -161,8 +162,8 @@ void tmate_encoder_init(struct tmate_encoder *encoder,
|
|||||||
if (!encoder->buffer)
|
if (!encoder->buffer)
|
||||||
tmate_fatal("Can't allocate buffer");
|
tmate_fatal("Can't allocate buffer");
|
||||||
|
|
||||||
event_assign(&encoder->ev_buffer, ev_base, -1,
|
event_set(&encoder->ev_buffer, -1,
|
||||||
EV_READ | EV_PERSIST, on_encoder_buffer_ready, encoder);
|
EV_READ | EV_PERSIST, on_encoder_buffer_ready, encoder);
|
||||||
|
|
||||||
event_add(&encoder->ev_buffer, NULL);
|
event_add(&encoder->ev_buffer, NULL);
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
#define pack(what, ...) _pack(&tmate_session->proxy_encoder, what, __VA_ARGS__)
|
#define pack(what, ...) _pack(&tmate_session->proxy_encoder, what, __VA_ARGS__)
|
||||||
|
|
||||||
static void ctl_daemon_fwd_msg(struct tmate_session *session,
|
static void ctl_daemon_fwd_msg(__unused struct tmate_session *session,
|
||||||
struct tmate_unpacker *uk)
|
struct tmate_unpacker *uk)
|
||||||
{
|
{
|
||||||
if (uk->argc != 1)
|
if (uk->argc != 1)
|
||||||
@ -18,15 +18,14 @@ static void ctl_daemon_fwd_msg(struct tmate_session *session,
|
|||||||
tmate_send_mc_obj(&uk->argv[0]);
|
tmate_send_mc_obj(&uk->argv[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_snapshot(struct tmate_unpacker *uk,
|
static void do_snapshot(__unused struct tmate_unpacker *uk,
|
||||||
unsigned int max_history_lines,
|
unsigned int max_history_lines,
|
||||||
struct window_pane *pane)
|
struct window_pane *pane)
|
||||||
{
|
{
|
||||||
struct screen *screen;
|
struct screen *screen;
|
||||||
struct grid *grid;
|
struct grid *grid;
|
||||||
struct grid_line *line;
|
struct grid_line *line;
|
||||||
struct grid_cell *cell;
|
struct grid_cell gc;
|
||||||
struct utf8_data utf8;
|
|
||||||
unsigned int line_i, i;
|
unsigned int line_i, i;
|
||||||
unsigned int max_lines;
|
unsigned int max_lines;
|
||||||
size_t str_len;
|
size_t str_len;
|
||||||
@ -59,30 +58,28 @@ static void do_snapshot(struct tmate_unpacker *uk,
|
|||||||
pack(array, 2);
|
pack(array, 2);
|
||||||
str_len = 0;
|
str_len = 0;
|
||||||
for (i = 0; i < line->cellsize; i++) {
|
for (i = 0; i < line->cellsize; i++) {
|
||||||
cell = &line->celldata[i];
|
grid_get_cell(grid, line_i, i, &gc);
|
||||||
grid_cell_get(cell, &utf8);
|
str_len += gc.data.size;
|
||||||
str_len += utf8.size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pack(str, str_len);
|
pack(str, str_len);
|
||||||
for (i = 0; i < line->cellsize; i++) {
|
for (i = 0; i < line->cellsize; i++) {
|
||||||
cell = &line->celldata[i];
|
grid_get_cell(grid, line_i, i, &gc);
|
||||||
grid_cell_get(cell, &utf8);
|
pack(str_body, gc.data.data, gc.data.size);
|
||||||
pack(str_body, utf8.data, utf8.size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pack(array, line->cellsize);
|
pack(array, line->cellsize);
|
||||||
for (i = 0; i < line->cellsize; i++) {
|
for (i = 0; i < line->cellsize; i++) {
|
||||||
cell = &line->celldata[i];
|
grid_get_cell(grid, line_i, i, &gc);
|
||||||
pack(unsigned_int, ((cell->flags << 24) |
|
pack(unsigned_int, ((gc.flags << 24) |
|
||||||
(cell->attr << 16) |
|
(gc.attr << 16) |
|
||||||
(cell->bg << 8) |
|
(gc.bg << 8) |
|
||||||
cell->fg ));
|
gc.fg ));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ctl_daemon_request_snapshot(struct tmate_session *session,
|
static void ctl_daemon_request_snapshot(__unused struct tmate_session *session,
|
||||||
struct tmate_unpacker *uk)
|
struct tmate_unpacker *uk)
|
||||||
{
|
{
|
||||||
struct session *s;
|
struct session *s;
|
||||||
@ -122,7 +119,7 @@ static void ctl_daemon_request_snapshot(struct tmate_session *session,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ctl_pane_keys(struct tmate_session *session,
|
static void ctl_pane_keys(__unused struct tmate_session *session,
|
||||||
struct tmate_unpacker *uk)
|
struct tmate_unpacker *uk)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@ -191,7 +188,7 @@ void tmate_proxy_exec(struct tmate_session *session, const char *command)
|
|||||||
pack(string, command);
|
pack(string, command);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tmate_notify_client_join(struct tmate_session *session,
|
void tmate_notify_client_join(__unused struct tmate_session *session,
|
||||||
struct client *c)
|
struct client *c)
|
||||||
{
|
{
|
||||||
if (!tmate_has_proxy())
|
if (!tmate_has_proxy())
|
||||||
@ -205,7 +202,7 @@ void tmate_notify_client_join(struct tmate_session *session,
|
|||||||
pack(boolean, c->readonly);
|
pack(boolean, c->readonly);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tmate_notify_client_left(struct tmate_session *session,
|
void tmate_notify_client_left(__unused struct tmate_session *session,
|
||||||
struct client *c)
|
struct client *c)
|
||||||
{
|
{
|
||||||
if (!tmate_has_proxy())
|
if (!tmate_has_proxy())
|
||||||
@ -216,10 +213,9 @@ void tmate_notify_client_left(struct tmate_session *session,
|
|||||||
pack(int, c->id);
|
pack(int, c->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tmate_send_proxy_daemon_msg(struct tmate_session *session,
|
void tmate_send_proxy_daemon_msg(__unused struct tmate_session *session,
|
||||||
struct tmate_unpacker *uk)
|
struct tmate_unpacker *uk)
|
||||||
{
|
{
|
||||||
struct timespec time_diff, current_time;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (!tmate_has_proxy())
|
if (!tmate_has_proxy())
|
||||||
@ -253,7 +249,7 @@ static void on_proxy_decoder_read(void *userdata, struct tmate_unpacker *uk)
|
|||||||
tmate_dispatch_proxy_message(session, uk);
|
tmate_dispatch_proxy_message(session, uk);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void on_proxy_read(struct bufferevent *bev, void *_session)
|
static void on_proxy_read(__unused struct bufferevent *bev, void *_session)
|
||||||
{
|
{
|
||||||
struct tmate_session *session = _session;
|
struct tmate_session *session = _session;
|
||||||
struct evbuffer *proxy_in;
|
struct evbuffer *proxy_in;
|
||||||
@ -281,7 +277,6 @@ static void on_proxy_encoder_write(void *userdata, struct evbuffer *buffer)
|
|||||||
{
|
{
|
||||||
struct tmate_session *session = userdata;
|
struct tmate_session *session = userdata;
|
||||||
struct evbuffer *proxy_out;
|
struct evbuffer *proxy_out;
|
||||||
size_t len;
|
|
||||||
|
|
||||||
proxy_out = bufferevent_get_output(session->bev_proxy);
|
proxy_out = bufferevent_get_output(session->bev_proxy);
|
||||||
|
|
||||||
@ -289,7 +284,7 @@ static void on_proxy_encoder_write(void *userdata, struct evbuffer *buffer)
|
|||||||
tmate_fatal("Cannot write to proxy buffer");
|
tmate_fatal("Cannot write to proxy buffer");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void on_proxy_event_default(struct tmate_session *session, short events)
|
static void on_proxy_event_default(__unused struct tmate_session *session, short events)
|
||||||
{
|
{
|
||||||
if (events & BEV_EVENT_EOF)
|
if (events & BEV_EVENT_EOF)
|
||||||
tmate_fatal("Connection to proxy closed");
|
tmate_fatal("Connection to proxy closed");
|
||||||
@ -299,7 +294,7 @@ static void on_proxy_event_default(struct tmate_session *session, short events)
|
|||||||
evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR()));
|
evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR()));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void on_proxy_event(struct bufferevent *bev, short events, void *_session)
|
static void on_proxy_event(__unused struct bufferevent *bev, short events, void *_session)
|
||||||
{
|
{
|
||||||
struct tmate_session *session = _session;
|
struct tmate_session *session = _session;
|
||||||
session->on_proxy_error(session, events);
|
session->on_proxy_error(session, events);
|
||||||
@ -315,8 +310,8 @@ void tmate_init_proxy(struct tmate_session *session,
|
|||||||
session->proxy_sy = -1;
|
session->proxy_sy = -1;
|
||||||
|
|
||||||
/* session->proxy_fd is already connected */
|
/* session->proxy_fd is already connected */
|
||||||
session->bev_proxy = bufferevent_socket_new(ev_base, session->proxy_fd,
|
session->bev_proxy = bufferevent_socket_new(session->ev_base, session->proxy_fd,
|
||||||
BEV_OPT_CLOSE_ON_FREE);
|
BEV_OPT_CLOSE_ON_FREE);
|
||||||
if (!session->bev_proxy)
|
if (!session->bev_proxy)
|
||||||
tmate_fatal("Cannot setup socket bufferevent");
|
tmate_fatal("Cannot setup socket bufferevent");
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <libssh/libssh.h>
|
#include <libssh/libssh.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <sys/param.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <grp.h>
|
#include <grp.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
@ -28,7 +29,7 @@ static char *cmdline_end;
|
|||||||
static int dev_urandom_fd;
|
static int dev_urandom_fd;
|
||||||
|
|
||||||
extern int server_create_socket(void);
|
extern int server_create_socket(void);
|
||||||
extern int client_connect(char *path, int start_server);
|
extern int client_connect(struct event_base *base, const char *path, int start_server);
|
||||||
|
|
||||||
struct tmate_settings _tmate_settings = {
|
struct tmate_settings _tmate_settings = {
|
||||||
.keys_dir = TMATE_SSH_DEFAULT_KEYS_DIR,
|
.keys_dir = TMATE_SSH_DEFAULT_KEYS_DIR,
|
||||||
@ -60,14 +61,12 @@ long tmate_get_random_long(void)
|
|||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int server_shutdown;
|
|
||||||
extern int server_fd;
|
extern int server_fd;
|
||||||
extern void server_send_shutdown(void);
|
extern void server_send_exit(void);
|
||||||
void request_server_termination(void)
|
void request_server_termination(void)
|
||||||
{
|
{
|
||||||
if (server_fd) {
|
if (server_fd) {
|
||||||
server_shutdown = 1;
|
server_send_exit();
|
||||||
server_send_shutdown();
|
|
||||||
} else
|
} else
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@ -154,9 +153,10 @@ static char *get_random_token(void)
|
|||||||
static void set_session_token(struct tmate_session *session,
|
static void set_session_token(struct tmate_session *session,
|
||||||
const char *token)
|
const char *token)
|
||||||
{
|
{
|
||||||
|
char *path;
|
||||||
session->session_token = xstrdup(token);
|
session->session_token = xstrdup(token);
|
||||||
strcpy(socket_path, TMATE_WORKDIR "/sessions/");
|
xasprintf(&path, TMATE_WORKDIR "/sessions/%s", token);
|
||||||
strcat(socket_path, token);
|
socket_path = path;
|
||||||
|
|
||||||
memset(cmdline, 0, cmdline_end - cmdline);
|
memset(cmdline, 0, cmdline_end - cmdline);
|
||||||
sprintf(cmdline, "tmate-slave [%s] %s %s",
|
sprintf(cmdline, "tmate-slave [%s] %s %s",
|
||||||
@ -164,6 +164,7 @@ static void set_session_token(struct tmate_session *session,
|
|||||||
session->ssh_client.role == TMATE_ROLE_DAEMON ? "(daemon)" : "(pty client)",
|
session->ssh_client.role == TMATE_ROLE_DAEMON ? "(daemon)" : "(pty client)",
|
||||||
session->ssh_client.ip_address);
|
session->ssh_client.ip_address);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void create_session_ro_symlink(struct tmate_session *session)
|
static void create_session_ro_symlink(struct tmate_session *session)
|
||||||
{
|
{
|
||||||
char session_ro_path[MAXPATHLEN];
|
char session_ro_path[MAXPATHLEN];
|
||||||
@ -271,7 +272,7 @@ static void jail(void)
|
|||||||
if (chdir("/") < 0)
|
if (chdir("/") < 0)
|
||||||
tmate_fatal("Cannot chdir()");
|
tmate_fatal("Cannot chdir()");
|
||||||
|
|
||||||
#if IS_LINUX
|
#ifdef IS_LINUX
|
||||||
if (unshare(CLONE_NEWPID | CLONE_NEWIPC | CLONE_NEWNS | CLONE_NEWNET) < 0)
|
if (unshare(CLONE_NEWPID | CLONE_NEWIPC | CLONE_NEWNS | CLONE_NEWNET) < 0)
|
||||||
tmate_fatal("Cannot create new namespace");
|
tmate_fatal("Cannot create new namespace");
|
||||||
#endif
|
#endif
|
||||||
@ -279,10 +280,10 @@ static void jail(void)
|
|||||||
if (setgroups(1, (gid_t[]){gid}) < 0)
|
if (setgroups(1, (gid_t[]){gid}) < 0)
|
||||||
tmate_fatal("Cannot setgroups()");
|
tmate_fatal("Cannot setgroups()");
|
||||||
|
|
||||||
#if HAVE_SETRESGID
|
#if defined(HAVE_SETRESGID)
|
||||||
if (setresgid(gid, gid, gid) < 0)
|
if (setresgid(gid, gid, gid) < 0)
|
||||||
tmate_fatal("Cannot setresgid() %d", gid);
|
tmate_fatal("Cannot setresgid() %d", gid);
|
||||||
#elif HAVE_SETREGID
|
#elif defined(HAVE_SETREGID)
|
||||||
if (setregid(gid, gid) < 0)
|
if (setregid(gid, gid) < 0)
|
||||||
tmate_fatal("Cannot setregid()");
|
tmate_fatal("Cannot setregid()");
|
||||||
#else
|
#else
|
||||||
@ -290,10 +291,10 @@ static void jail(void)
|
|||||||
tmate_fatal("Cannot setgid()");
|
tmate_fatal("Cannot setgid()");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if HAVE_SETRESUID
|
#if defined(HAVE_SETRESUID)
|
||||||
if (setresuid(uid, uid, uid) < 0)
|
if (setresuid(uid, uid, uid) < 0)
|
||||||
tmate_fatal("Cannot setresuid()");
|
tmate_fatal("Cannot setresuid()");
|
||||||
#elif HAVE_SETREUID
|
#elif defined(HAVE_SETREUID)
|
||||||
if (setreuid(uid, uid) < 0)
|
if (setreuid(uid, uid) < 0)
|
||||||
tmate_fatal("Cannot setreuid()");
|
tmate_fatal("Cannot setreuid()");
|
||||||
#else
|
#else
|
||||||
@ -304,8 +305,8 @@ static void jail(void)
|
|||||||
if (nice(1) < 0)
|
if (nice(1) < 0)
|
||||||
tmate_fatal("Cannot nice()");
|
tmate_fatal("Cannot nice()");
|
||||||
|
|
||||||
tmate_debug("Dropped priviledges to %s (%d,%d), jailed in %s",
|
tmate_info("Dropped priviledges to %s (%d,%d), jailed in %s",
|
||||||
TMATE_JAIL_USER, uid, gid, TMATE_WORKDIR "/jail");
|
TMATE_JAIL_USER, uid, gid, TMATE_WORKDIR "/jail");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setup_ncurse(int fd, const char *name)
|
static void setup_ncurse(int fd, const char *name)
|
||||||
@ -318,10 +319,7 @@ static void setup_ncurse(int fd, const char *name)
|
|||||||
static void tmate_spawn_slave_daemon(struct tmate_session *session)
|
static void tmate_spawn_slave_daemon(struct tmate_session *session)
|
||||||
{
|
{
|
||||||
struct tmate_ssh_client *client = &session->ssh_client;
|
struct tmate_ssh_client *client = &session->ssh_client;
|
||||||
|
|
||||||
char *token;
|
char *token;
|
||||||
struct tmate_encoder encoder;
|
|
||||||
struct tmate_decoder decoder;
|
|
||||||
|
|
||||||
token = get_random_token();
|
token = get_random_token();
|
||||||
#ifdef DEVENV
|
#ifdef DEVENV
|
||||||
@ -331,8 +329,8 @@ static void tmate_spawn_slave_daemon(struct tmate_session *session)
|
|||||||
set_session_token(session, token);
|
set_session_token(session, token);
|
||||||
free(token);
|
free(token);
|
||||||
|
|
||||||
tmate_debug("Spawning slave server for %s at %s (%s)",
|
tmate_notice("Spawning slave server for %s at %s (%s)",
|
||||||
client->username, client->ip_address, client->pubkey);
|
client->username, client->ip_address, client->pubkey);
|
||||||
|
|
||||||
session->tmux_socket_fd = server_create_socket();
|
session->tmux_socket_fd = server_create_socket();
|
||||||
if (session->tmux_socket_fd < 0)
|
if (session->tmux_socket_fd < 0)
|
||||||
@ -354,9 +352,10 @@ static void tmate_spawn_slave_daemon(struct tmate_session *session)
|
|||||||
session->proxy_fd}, 4);
|
session->proxy_fd}, 4);
|
||||||
|
|
||||||
jail();
|
jail();
|
||||||
event_reinit(ev_base);
|
event_reinit(session->ev_base);
|
||||||
|
|
||||||
tmux_server_init(IDENTIFY_UTF8 | IDENTIFY_256COLOURS);
|
tmux_server_init();
|
||||||
|
server_start(session->ev_base, -1, NULL);
|
||||||
/* never reached */
|
/* never reached */
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -383,10 +382,10 @@ static void tmate_spawn_slave_pty_client(struct tmate_session *session)
|
|||||||
|
|
||||||
set_session_token(session, token);
|
set_session_token(session, token);
|
||||||
|
|
||||||
tmate_debug("Spawning slave client for %s (%s)",
|
tmate_notice("Spawning slave client for %s (%s)",
|
||||||
client->ip_address, client->pubkey);
|
client->ip_address, client->pubkey);
|
||||||
|
|
||||||
session->tmux_socket_fd = client_connect(socket_path, 0);
|
session->tmux_socket_fd = client_connect(session->ev_base, socket_path, 0);
|
||||||
if (session->tmux_socket_fd < 0) {
|
if (session->tmux_socket_fd < 0) {
|
||||||
random_sleep(); /* for making timing attacks harder */
|
random_sleep(); /* for making timing attacks harder */
|
||||||
ssh_echo(client, EXPIRED_TOKEN_ERROR_STR);
|
ssh_echo(client, EXPIRED_TOKEN_ERROR_STR);
|
||||||
@ -427,9 +426,10 @@ static void tmate_spawn_slave_pty_client(struct tmate_session *session)
|
|||||||
ssh_get_fd(session->ssh_client.session),
|
ssh_get_fd(session->ssh_client.session),
|
||||||
session->pty, log_file ? fileno(log_file) : -1}, 7);
|
session->pty, log_file ? fileno(log_file) : -1}, 7);
|
||||||
jail();
|
jail();
|
||||||
event_reinit(ev_base);
|
event_reinit(session->ev_base);
|
||||||
|
|
||||||
ret = client_main(argc, argv, IDENTIFY_UTF8 | IDENTIFY_256COLOURS);
|
ret = client_main(session->ev_base, argc, argv,
|
||||||
|
CLIENT_UTF8 | CLIENT_256COLOURS, NULL);
|
||||||
tmate_flush_pty(session);
|
tmate_flush_pty(session);
|
||||||
exit(ret);
|
exit(ret);
|
||||||
}
|
}
|
||||||
@ -440,11 +440,11 @@ static void tmate_spawn_slave_exec(struct tmate_session *session)
|
|||||||
log_file ? fileno(log_file) : -1,
|
log_file ? fileno(log_file) : -1,
|
||||||
session->proxy_fd}, 3);
|
session->proxy_fd}, 3);
|
||||||
jail();
|
jail();
|
||||||
event_reinit(ev_base);
|
event_reinit(session->ev_base);
|
||||||
|
|
||||||
tmate_client_exec_init(session);
|
tmate_client_exec_init(session);
|
||||||
|
|
||||||
if (event_base_dispatch(ev_base) < 0)
|
if (event_base_dispatch(session->ev_base) < 0)
|
||||||
tmate_fatal("Cannot run event loop");
|
tmate_fatal("Cannot run event loop");
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
@ -3,11 +3,12 @@
|
|||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include "tmate.h"
|
#include "tmate.h"
|
||||||
|
|
||||||
extern void client_write_server(enum msgtype type, void *buf, size_t len);
|
extern void client_signal(int sig);
|
||||||
|
|
||||||
static int on_ssh_channel_read(ssh_session _session, ssh_channel channel,
|
static int on_ssh_channel_read(__unused ssh_session _session,
|
||||||
|
__unused ssh_channel channel,
|
||||||
void *_data, uint32_t total_len,
|
void *_data, uint32_t total_len,
|
||||||
int is_stderr, void *userdata)
|
__unused int is_stderr, void *userdata)
|
||||||
{
|
{
|
||||||
struct tmate_session *session = userdata;
|
struct tmate_session *session = userdata;
|
||||||
char *data = _data;
|
char *data = _data;
|
||||||
@ -32,7 +33,8 @@ static int on_ssh_channel_read(ssh_session _session, ssh_channel channel,
|
|||||||
return written;
|
return written;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int on_ssh_message_callback(ssh_session _session, ssh_message msg, void *arg)
|
static int on_ssh_message_callback(__unused ssh_session _session,
|
||||||
|
ssh_message msg, void *arg)
|
||||||
{
|
{
|
||||||
struct tmate_session *session = arg;
|
struct tmate_session *session = arg;
|
||||||
|
|
||||||
@ -44,7 +46,7 @@ static int on_ssh_message_callback(ssh_session _session, ssh_message msg, void *
|
|||||||
ws.ws_row = ssh_message_channel_request_pty_height(msg);
|
ws.ws_row = ssh_message_channel_request_pty_height(msg);
|
||||||
|
|
||||||
ioctl(session->pty, TIOCSWINSZ, &ws);
|
ioctl(session->pty, TIOCSWINSZ, &ws);
|
||||||
client_write_server(MSG_RESIZE, NULL, 0);
|
client_signal(SIGWINCH);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -77,7 +79,7 @@ static void on_pty_event(struct tmate_session *session)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __on_pty_event(evutil_socket_t fd, short what, void *arg)
|
static void __on_pty_event(__unused evutil_socket_t fd, __unused short what, void *arg)
|
||||||
{
|
{
|
||||||
on_pty_event(arg);
|
on_pty_event(arg);
|
||||||
}
|
}
|
||||||
@ -104,7 +106,7 @@ void tmate_client_pty_init(struct tmate_session *session)
|
|||||||
on_ssh_message_callback, session);
|
on_ssh_message_callback, session);
|
||||||
|
|
||||||
setblocking(session->pty, 0);
|
setblocking(session->pty, 0);
|
||||||
event_assign(&session->ev_pty, ev_base, session->pty,
|
event_set(&session->ev_pty, session->pty,
|
||||||
EV_READ | EV_PERSIST, __on_pty_event, session);
|
EV_READ | EV_PERSIST, __on_pty_event, session);
|
||||||
event_add(&session->ev_pty, NULL);
|
event_add(&session->ev_pty, NULL);
|
||||||
}
|
}
|
||||||
|
@ -13,11 +13,11 @@ void tmate_dump_exec_response(struct tmate_session *session,
|
|||||||
ssh_channel_send_eof(client->channel);
|
ssh_channel_send_eof(client->channel);
|
||||||
ssh_channel_close(client->channel);
|
ssh_channel_close(client->channel);
|
||||||
|
|
||||||
if (event_base_loopexit(ev_base, NULL) < 0)
|
if (event_base_loopexit(session->ev_base, NULL) < 0)
|
||||||
tmate_fatal("cannot stop event loop");
|
tmate_fatal("cannot stop event loop");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void on_proxy_error(struct tmate_session *session, short events)
|
static void on_proxy_error(struct tmate_session *session, __unused short events)
|
||||||
{
|
{
|
||||||
tmate_warn("Lost proxy connection");
|
tmate_warn("Lost proxy connection");
|
||||||
tmate_dump_exec_response(session, 1, "Internal Error\r\n");
|
tmate_dump_exec_response(session, 1, "Internal Error\r\n");
|
||||||
|
@ -11,7 +11,8 @@
|
|||||||
#include "tmate.h"
|
#include "tmate.h"
|
||||||
|
|
||||||
static void start_keepalive_timer(struct tmate_ssh_client *client);
|
static void start_keepalive_timer(struct tmate_ssh_client *client);
|
||||||
static void on_keepalive_timer(evutil_socket_t fd, short what, void *arg)
|
static void on_keepalive_timer(__unused evutil_socket_t fd,
|
||||||
|
__unused short what, void *arg)
|
||||||
{
|
{
|
||||||
struct tmate_ssh_client *client = arg;
|
struct tmate_ssh_client *client = arg;
|
||||||
|
|
||||||
@ -23,14 +24,17 @@ static void start_keepalive_timer(struct tmate_ssh_client *client)
|
|||||||
{
|
{
|
||||||
struct timeval tv = { TMATE_SSH_KEEPALIVE, 0 };
|
struct timeval tv = { TMATE_SSH_KEEPALIVE, 0 };
|
||||||
|
|
||||||
evtimer_assign(&client->ev_keepalive_timer, ev_base,
|
evtimer_set(&client->ev_keepalive_timer,
|
||||||
on_keepalive_timer, client);
|
on_keepalive_timer, client);
|
||||||
evtimer_add(&client->ev_keepalive_timer, &tv);
|
evtimer_add(&client->ev_keepalive_timer, &tv);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pty_request(ssh_session session, ssh_channel channel,
|
static int pty_request(__unused ssh_session session,
|
||||||
const char *term, int width, int height,
|
__unused ssh_channel channel,
|
||||||
int pxwidth, int pwheight, void *userdata)
|
__unused const char *term,
|
||||||
|
int width, int height,
|
||||||
|
__unused int pxwidth, __unused int pwheight,
|
||||||
|
void *userdata)
|
||||||
{
|
{
|
||||||
struct tmate_ssh_client *client = userdata;
|
struct tmate_ssh_client *client = userdata;
|
||||||
|
|
||||||
@ -40,7 +44,8 @@ static int pty_request(ssh_session session, ssh_channel channel,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int shell_request(ssh_session session, ssh_channel channel,
|
static int shell_request(__unused ssh_session session,
|
||||||
|
__unused ssh_channel channel,
|
||||||
void *userdata)
|
void *userdata)
|
||||||
{
|
{
|
||||||
struct tmate_ssh_client *client = userdata;
|
struct tmate_ssh_client *client = userdata;
|
||||||
@ -53,7 +58,8 @@ static int shell_request(ssh_session session, ssh_channel channel,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int subsystem_request(ssh_session session, ssh_channel channel,
|
static int subsystem_request(__unused ssh_session session,
|
||||||
|
__unused ssh_channel channel,
|
||||||
const char *subsystem, void *userdata)
|
const char *subsystem, void *userdata)
|
||||||
{
|
{
|
||||||
struct tmate_ssh_client *client = userdata;
|
struct tmate_ssh_client *client = userdata;
|
||||||
@ -67,7 +73,8 @@ static int subsystem_request(ssh_session session, ssh_channel channel,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int exec_request(ssh_session session, ssh_channel channel,
|
static int exec_request(__unused ssh_session session,
|
||||||
|
__unused ssh_channel channel,
|
||||||
const char *command, void *userdata)
|
const char *command, void *userdata)
|
||||||
{
|
{
|
||||||
struct tmate_ssh_client *client = userdata;
|
struct tmate_ssh_client *client = userdata;
|
||||||
@ -114,7 +121,8 @@ static ssh_channel channel_open_request_cb(ssh_session session, void *userdata)
|
|||||||
return client->channel;
|
return client->channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int auth_pubkey_cb(ssh_session session, const char *user,
|
static int auth_pubkey_cb(__unused ssh_session session,
|
||||||
|
const char *user,
|
||||||
struct ssh_key_struct *pubkey,
|
struct ssh_key_struct *pubkey,
|
||||||
char signature_state, void *userdata)
|
char signature_state, void *userdata)
|
||||||
{
|
{
|
||||||
@ -139,7 +147,7 @@ static struct ssh_server_callbacks_struct ssh_server_cb = {
|
|||||||
.channel_open_request_session_function = channel_open_request_cb,
|
.channel_open_request_session_function = channel_open_request_cb,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void on_ssh_read(evutil_socket_t fd, short what, void *arg)
|
static void on_ssh_read(__unused evutil_socket_t fd, __unused short what, void *arg)
|
||||||
{
|
{
|
||||||
struct tmate_ssh_client *client = arg;
|
struct tmate_ssh_client *client = arg;
|
||||||
ssh_execute_message_callbacks(client->session);
|
ssh_execute_message_callbacks(client->session);
|
||||||
@ -156,23 +164,21 @@ static void on_ssh_read(evutil_socket_t fd, short what, void *arg)
|
|||||||
|
|
||||||
static void register_on_ssh_read(struct tmate_ssh_client *client)
|
static void register_on_ssh_read(struct tmate_ssh_client *client)
|
||||||
{
|
{
|
||||||
event_assign(&client->ev_ssh, ev_base, ssh_get_fd(client->session),
|
event_set(&client->ev_ssh, ssh_get_fd(client->session),
|
||||||
EV_READ | EV_PERSIST, on_ssh_read, client);
|
EV_READ | EV_PERSIST, on_ssh_read, client);
|
||||||
event_add(&client->ev_ssh, NULL);
|
event_add(&client->ev_ssh, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void client_bootstrap(struct tmate_session *_session)
|
static void client_bootstrap(struct tmate_session *_session)
|
||||||
{
|
{
|
||||||
struct tmate_ssh_client *client = &_session->ssh_client;
|
struct tmate_ssh_client *client = &_session->ssh_client;
|
||||||
int auth = 0;
|
|
||||||
int grace_period = TMATE_SSH_GRACE_PERIOD;
|
int grace_period = TMATE_SSH_GRACE_PERIOD;
|
||||||
ssh_event mainloop;
|
ssh_event mainloop;
|
||||||
ssh_session session = client->session;
|
ssh_session session = client->session;
|
||||||
ssh_message msg;
|
|
||||||
|
|
||||||
tmate_notice("Bootstrapping ssh client ip=%s", client->ip_address);
|
tmate_notice("Bootstrapping ssh client ip=%s", client->ip_address);
|
||||||
|
|
||||||
ev_base = osdep_event_init();
|
_session->ev_base = osdep_event_init();
|
||||||
|
|
||||||
/* new process group, we don't want to die with our parent (upstart) */
|
/* new process group, we don't want to die with our parent (upstart) */
|
||||||
setpgid(0, 0);
|
setpgid(0, 0);
|
||||||
@ -200,7 +206,7 @@ static void client_bootstrap(struct tmate_session *_session)
|
|||||||
|
|
||||||
ssh_set_auth_methods(client->session, SSH_AUTH_METHOD_PUBLICKEY);
|
ssh_set_auth_methods(client->session, SSH_AUTH_METHOD_PUBLICKEY);
|
||||||
|
|
||||||
tmate_debug("Exchanging DH keys");
|
tmate_info("Exchanging DH keys");
|
||||||
if (ssh_handle_key_exchange(session) < 0)
|
if (ssh_handle_key_exchange(session) < 0)
|
||||||
tmate_fatal("Error doing the key exchange: %s",
|
tmate_fatal("Error doing the key exchange: %s",
|
||||||
ssh_get_error(session));
|
ssh_get_error(session));
|
||||||
@ -248,10 +254,15 @@ static void handle_sigsegv(void)
|
|||||||
tmate_print_stack_trace();
|
tmate_print_stack_trace();
|
||||||
tmate_fatal("CRASHED");
|
tmate_fatal("CRASHED");
|
||||||
}
|
}
|
||||||
|
static void handle_sigterm(void)
|
||||||
|
{
|
||||||
|
request_server_termination();
|
||||||
|
}
|
||||||
|
|
||||||
static void signal_handler(int sig)
|
static void signal_handler(int sig)
|
||||||
{
|
{
|
||||||
switch (sig) {
|
switch (sig) {
|
||||||
|
case SIGTERM: handle_sigterm(); break;
|
||||||
case SIGCHLD: handle_sigchld(); break;
|
case SIGCHLD: handle_sigchld(); break;
|
||||||
case SIGALRM: handle_sigalrm(); break;
|
case SIGALRM: handle_sigalrm(); break;
|
||||||
case SIGSEGV: handle_sigsegv(); break;
|
case SIGSEGV: handle_sigsegv(); break;
|
||||||
@ -260,6 +271,7 @@ static void signal_handler(int sig)
|
|||||||
|
|
||||||
static void setup_signals(void)
|
static void setup_signals(void)
|
||||||
{
|
{
|
||||||
|
signal(SIGTERM, signal_handler);
|
||||||
signal(SIGCHLD, signal_handler);
|
signal(SIGCHLD, signal_handler);
|
||||||
signal(SIGALRM, signal_handler);
|
signal(SIGALRM, signal_handler);
|
||||||
signal(SIGSEGV, signal_handler);
|
signal(SIGSEGV, signal_handler);
|
||||||
@ -293,9 +305,9 @@ static int get_ip(int fd, char *dst, size_t len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void ssh_log_function(int priority, const char *function,
|
static void ssh_log_function(int priority, const char *function,
|
||||||
const char *buffer, void *userdata)
|
const char *buffer, __unused void *userdata)
|
||||||
{
|
{
|
||||||
tmate_debug("[%d] [%s] %s", priority, function, buffer);
|
tmate_info("[%d] [%s] %s", priority, function, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssh_bind prepare_ssh(const char *keys_dir, int port)
|
static ssh_bind prepare_ssh(const char *keys_dir, int port)
|
||||||
|
11
tmate.h
11
tmate.h
@ -14,7 +14,7 @@ struct tmate_session;
|
|||||||
/* log.c */
|
/* log.c */
|
||||||
|
|
||||||
extern void init_logging(const char *program_name, bool use_syslog, int log_level);
|
extern void init_logging(const char *program_name, bool use_syslog, int log_level);
|
||||||
extern void printflike2 tmate_log(int level, const char *msg, ...);
|
extern void printflike(2, 3) tmate_log(int level, const char *msg, ...);
|
||||||
|
|
||||||
#define tmate_debug(str, ...) tmate_log(LOG_DEBUG, str, ##__VA_ARGS__)
|
#define tmate_debug(str, ...) tmate_log(LOG_DEBUG, str, ##__VA_ARGS__)
|
||||||
#define tmate_info(str, ...) tmate_log(LOG_INFO, str, ##__VA_ARGS__)
|
#define tmate_info(str, ...) tmate_log(LOG_INFO, str, ##__VA_ARGS__)
|
||||||
@ -88,8 +88,8 @@ extern void unpack_array(struct tmate_unpacker *uk, struct tmate_unpacker *neste
|
|||||||
|
|
||||||
#define TMATE_LATEST_VERSION "1.8.10"
|
#define TMATE_LATEST_VERSION "1.8.10"
|
||||||
|
|
||||||
extern void printflike1 tmate_notify(const char *fmt, ...);
|
extern void printflike(1, 2) tmate_notify(const char *fmt, ...);
|
||||||
extern void printflike2 tmate_notify_later(int timeout, const char *fmt, ...);
|
extern void printflike(2, 3) tmate_notify_later(int timeout, const char *fmt, ...);
|
||||||
|
|
||||||
extern void tmate_client_resize(u_int sx, u_int sy);
|
extern void tmate_client_resize(u_int sx, u_int sy);
|
||||||
extern void tmate_client_pane_key(int pane_id, int key);
|
extern void tmate_client_pane_key(int pane_id, int key);
|
||||||
@ -195,6 +195,7 @@ extern struct tmate_settings *tmate_settings;
|
|||||||
typedef void on_proxy_error_cb(struct tmate_session *session, short events);
|
typedef void on_proxy_error_cb(struct tmate_session *session, short events);
|
||||||
|
|
||||||
struct tmate_session {
|
struct tmate_session {
|
||||||
|
struct event_base *ev_base;
|
||||||
struct tmate_ssh_client ssh_client;
|
struct tmate_ssh_client ssh_client;
|
||||||
int tmux_socket_fd;
|
int tmux_socket_fd;
|
||||||
|
|
||||||
@ -259,8 +260,8 @@ extern unsigned long long timespec_to_millisec(struct timespec *ts);
|
|||||||
extern void tmate_preload_trace_lib(void);
|
extern void tmate_preload_trace_lib(void);
|
||||||
extern void tmate_print_stack_trace(void);
|
extern void tmate_print_stack_trace(void);
|
||||||
|
|
||||||
/* tmux-bare.c */
|
/* tmux.c */
|
||||||
|
|
||||||
extern void tmux_server_init(int flags);
|
extern void tmux_server_init(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
78
tmux-bare.c
78
tmux-bare.c
@ -1,78 +0,0 @@
|
|||||||
#include <stdlib.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include "tmux.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;
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
void tmux_server_init(int flags)
|
|
||||||
{
|
|
||||||
int quiet = 0;
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
31
tmux.c
31
tmux.c
@ -31,6 +31,7 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "tmux.h"
|
#include "tmux.h"
|
||||||
|
#include "tmate.h"
|
||||||
|
|
||||||
#if defined(DEBUG) && defined(__OpenBSD__)
|
#if defined(DEBUG) && defined(__OpenBSD__)
|
||||||
extern char *malloc_options;
|
extern char *malloc_options;
|
||||||
@ -45,6 +46,7 @@ struct hooks *global_hooks;
|
|||||||
struct timeval start_time;
|
struct timeval start_time;
|
||||||
const char *socket_path;
|
const char *socket_path;
|
||||||
|
|
||||||
|
#ifndef TMATE_SLAVE
|
||||||
__dead void usage(void);
|
__dead void usage(void);
|
||||||
static char *make_label(const char *);
|
static char *make_label(const char *);
|
||||||
|
|
||||||
@ -151,6 +153,7 @@ fail:
|
|||||||
errno = saved_errno;
|
errno = saved_errno;
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void
|
void
|
||||||
setblocking(int fd, int state)
|
setblocking(int fd, int state)
|
||||||
@ -166,6 +169,11 @@ setblocking(int fd, int state)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef TMATE_SLAVE
|
||||||
|
const char * find_home(void) { return NULL; }
|
||||||
|
int areshell(__unused const char *shell) { return 0; }
|
||||||
|
#else
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
find_home(void)
|
find_home(void)
|
||||||
{
|
{
|
||||||
@ -337,3 +345,26 @@ main(int argc, char **argv)
|
|||||||
/* Pass control to the client. */
|
/* Pass control to the client. */
|
||||||
exit(client_main(event_init(), argc, argv, flags, shellcmd));
|
exit(client_main(event_init(), argc, argv, flags, shellcmd));
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef TMATE_SLAVE
|
||||||
|
void tmux_server_init(void)
|
||||||
|
{
|
||||||
|
global_hooks = hooks_create(NULL);
|
||||||
|
|
||||||
|
global_environ = environ_create();
|
||||||
|
|
||||||
|
global_options = options_create(NULL);
|
||||||
|
options_table_populate_tree(OPTIONS_TABLE_SERVER, global_options);
|
||||||
|
|
||||||
|
global_s_options = options_create(NULL);
|
||||||
|
options_table_populate_tree(OPTIONS_TABLE_SESSION, global_s_options);
|
||||||
|
options_set_string(global_s_options, "default-shell", "%s", "/bin/false");
|
||||||
|
|
||||||
|
global_w_options = options_create(NULL);
|
||||||
|
options_table_populate_tree(OPTIONS_TABLE_WINDOW, global_w_options);
|
||||||
|
|
||||||
|
options_set_number(global_s_options, "status-keys", MODEKEY_VI);
|
||||||
|
options_set_number(global_w_options, "mode-keys", MODEKEY_VI);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
8
tmux.h
8
tmux.h
@ -409,6 +409,12 @@ enum msgtype {
|
|||||||
MSG_IDENTIFY_CLIENTPID,
|
MSG_IDENTIFY_CLIENTPID,
|
||||||
MSG_IDENTIFY_CWD,
|
MSG_IDENTIFY_CWD,
|
||||||
|
|
||||||
|
#ifdef TMATE_SLAVE
|
||||||
|
MSG_IDENTIFY_TMATE_IP_ADDRESS,
|
||||||
|
MSG_IDENTIFY_TMATE_PUBKEY,
|
||||||
|
MSG_IDENTIFY_TMATE_READONLY,
|
||||||
|
#endif
|
||||||
|
|
||||||
MSG_COMMAND = 200,
|
MSG_COMMAND = 200,
|
||||||
MSG_DETACH,
|
MSG_DETACH,
|
||||||
MSG_DETACHKILL,
|
MSG_DETACHKILL,
|
||||||
@ -879,8 +885,8 @@ struct window_pane {
|
|||||||
#else
|
#else
|
||||||
int fd;
|
int fd;
|
||||||
struct bufferevent *event;
|
struct bufferevent *event;
|
||||||
struct event timer;
|
|
||||||
#endif
|
#endif
|
||||||
|
struct event timer;
|
||||||
|
|
||||||
struct input_ctx *ictx;
|
struct input_ctx *ictx;
|
||||||
|
|
||||||
|
@ -24,67 +24,7 @@
|
|||||||
|
|
||||||
#include "tmux.h"
|
#include "tmux.h"
|
||||||
|
|
||||||
struct screen *window_copy_init(struct window_pane *);
|
#include "window-copy.h"
|
||||||
void window_copy_free(struct window_pane *);
|
|
||||||
void window_copy_resize(struct window_pane *, u_int, u_int);
|
|
||||||
void window_copy_key(struct window_pane *, struct client *, struct session *,
|
|
||||||
key_code, struct mouse_event *);
|
|
||||||
int window_copy_key_input(struct window_pane *, key_code);
|
|
||||||
int window_copy_key_numeric_prefix(struct window_pane *, key_code);
|
|
||||||
|
|
||||||
void window_copy_redraw_selection(struct window_pane *, u_int);
|
|
||||||
void window_copy_redraw_lines(struct window_pane *, u_int, u_int);
|
|
||||||
void window_copy_redraw_screen(struct window_pane *);
|
|
||||||
void window_copy_write_line(struct window_pane *, struct screen_write_ctx *,
|
|
||||||
u_int);
|
|
||||||
void window_copy_write_lines(struct window_pane *,
|
|
||||||
struct screen_write_ctx *, u_int, u_int);
|
|
||||||
|
|
||||||
void window_copy_scroll_to(struct window_pane *, u_int, u_int);
|
|
||||||
int window_copy_search_compare(struct grid *, u_int, u_int, struct grid *,
|
|
||||||
u_int, int);
|
|
||||||
int window_copy_search_lr(struct grid *, struct grid *, u_int *, u_int,
|
|
||||||
u_int, u_int, int);
|
|
||||||
int window_copy_search_rl(struct grid *, struct grid *, u_int *, u_int,
|
|
||||||
u_int, u_int, int);
|
|
||||||
void window_copy_search_up(struct window_pane *, const char *);
|
|
||||||
void window_copy_search_down(struct window_pane *, const char *);
|
|
||||||
void window_copy_goto_line(struct window_pane *, const char *);
|
|
||||||
void window_copy_update_cursor(struct window_pane *, u_int, u_int);
|
|
||||||
void window_copy_start_selection(struct window_pane *);
|
|
||||||
int window_copy_update_selection(struct window_pane *, int);
|
|
||||||
void *window_copy_get_selection(struct window_pane *, size_t *);
|
|
||||||
void window_copy_copy_buffer(struct window_pane *, const char *, void *,
|
|
||||||
size_t);
|
|
||||||
void window_copy_copy_pipe(struct window_pane *, struct session *,
|
|
||||||
const char *, const char *);
|
|
||||||
void window_copy_copy_selection(struct window_pane *, const char *);
|
|
||||||
void window_copy_append_selection(struct window_pane *, const char *);
|
|
||||||
void window_copy_clear_selection(struct window_pane *);
|
|
||||||
void window_copy_copy_line(struct window_pane *, char **, size_t *, u_int,
|
|
||||||
u_int, u_int);
|
|
||||||
int window_copy_in_set(struct window_pane *, u_int, u_int, const char *);
|
|
||||||
u_int window_copy_find_length(struct window_pane *, u_int);
|
|
||||||
void window_copy_cursor_start_of_line(struct window_pane *);
|
|
||||||
void window_copy_cursor_back_to_indentation(struct window_pane *);
|
|
||||||
void window_copy_cursor_end_of_line(struct window_pane *);
|
|
||||||
void window_copy_other_end(struct window_pane *);
|
|
||||||
void window_copy_cursor_left(struct window_pane *);
|
|
||||||
void window_copy_cursor_right(struct window_pane *);
|
|
||||||
void window_copy_cursor_up(struct window_pane *, int);
|
|
||||||
void window_copy_cursor_down(struct window_pane *, int);
|
|
||||||
void window_copy_cursor_jump(struct window_pane *);
|
|
||||||
void window_copy_cursor_jump_back(struct window_pane *);
|
|
||||||
void window_copy_cursor_jump_to(struct window_pane *, int);
|
|
||||||
void window_copy_cursor_jump_to_back(struct window_pane *, int);
|
|
||||||
void window_copy_cursor_next_word(struct window_pane *, const char *);
|
|
||||||
void window_copy_cursor_next_word_end(struct window_pane *, const char *);
|
|
||||||
void window_copy_cursor_previous_word(struct window_pane *, const char *);
|
|
||||||
void window_copy_scroll_up(struct window_pane *, u_int);
|
|
||||||
void window_copy_scroll_down(struct window_pane *, u_int);
|
|
||||||
void window_copy_rectangle_toggle(struct window_pane *);
|
|
||||||
void window_copy_drag_update(struct client *, struct mouse_event *);
|
|
||||||
void window_copy_drag_release(struct client *, struct mouse_event *);
|
|
||||||
|
|
||||||
const struct window_mode window_copy_mode = {
|
const struct window_mode window_copy_mode = {
|
||||||
window_copy_init,
|
window_copy_init,
|
||||||
@ -93,8 +33,6 @@ const struct window_mode window_copy_mode = {
|
|||||||
window_copy_key,
|
window_copy_key,
|
||||||
};
|
};
|
||||||
|
|
||||||
#include "window-copy.h"
|
|
||||||
|
|
||||||
struct screen *
|
struct screen *
|
||||||
window_copy_init(struct window_pane *wp)
|
window_copy_init(struct window_pane *wp)
|
||||||
{
|
{
|
||||||
|
@ -3,6 +3,70 @@
|
|||||||
|
|
||||||
#include "tmux.h"
|
#include "tmux.h"
|
||||||
|
|
||||||
|
struct screen *window_copy_init(struct window_pane *);
|
||||||
|
void window_copy_free(struct window_pane *);
|
||||||
|
void window_copy_resize(struct window_pane *, u_int, u_int);
|
||||||
|
void window_copy_key(struct window_pane *, struct client *, struct session *,
|
||||||
|
key_code, struct mouse_event *);
|
||||||
|
int window_copy_key_input(struct window_pane *, key_code);
|
||||||
|
int window_copy_key_numeric_prefix(struct window_pane *, key_code);
|
||||||
|
|
||||||
|
void window_copy_redraw_selection(struct window_pane *, u_int);
|
||||||
|
void window_copy_redraw_lines(struct window_pane *, u_int, u_int);
|
||||||
|
void window_copy_redraw_screen(struct window_pane *);
|
||||||
|
void window_copy_write_line(struct window_pane *, struct screen_write_ctx *,
|
||||||
|
u_int);
|
||||||
|
void window_copy_write_lines(struct window_pane *,
|
||||||
|
struct screen_write_ctx *, u_int, u_int);
|
||||||
|
|
||||||
|
void window_copy_scroll_to(struct window_pane *, u_int, u_int);
|
||||||
|
int window_copy_search_compare(struct grid *, u_int, u_int, struct grid *,
|
||||||
|
u_int, int);
|
||||||
|
int window_copy_search_lr(struct grid *, struct grid *, u_int *, u_int,
|
||||||
|
u_int, u_int, int);
|
||||||
|
int window_copy_search_rl(struct grid *, struct grid *, u_int *, u_int,
|
||||||
|
u_int, u_int, int);
|
||||||
|
void window_copy_search_up(struct window_pane *, const char *);
|
||||||
|
void window_copy_search_down(struct window_pane *, const char *);
|
||||||
|
void window_copy_goto_line(struct window_pane *, const char *);
|
||||||
|
void window_copy_update_cursor(struct window_pane *, u_int, u_int);
|
||||||
|
void window_copy_start_selection(struct window_pane *);
|
||||||
|
int window_copy_update_selection(struct window_pane *, int);
|
||||||
|
void *window_copy_get_selection(struct window_pane *, size_t *);
|
||||||
|
void window_copy_copy_buffer(struct window_pane *, const char *, void *,
|
||||||
|
size_t);
|
||||||
|
void window_copy_copy_pipe(struct window_pane *, struct session *,
|
||||||
|
const char *, const char *);
|
||||||
|
void window_copy_copy_selection(struct window_pane *, const char *);
|
||||||
|
void window_copy_append_selection(struct window_pane *, const char *);
|
||||||
|
void window_copy_clear_selection(struct window_pane *);
|
||||||
|
void window_copy_copy_line(struct window_pane *, char **, size_t *, u_int,
|
||||||
|
u_int, u_int);
|
||||||
|
int window_copy_in_set(struct window_pane *, u_int, u_int, const char *);
|
||||||
|
u_int window_copy_find_length(struct window_pane *, u_int);
|
||||||
|
void window_copy_cursor_start_of_line(struct window_pane *);
|
||||||
|
void window_copy_cursor_back_to_indentation(struct window_pane *);
|
||||||
|
void window_copy_cursor_end_of_line(struct window_pane *);
|
||||||
|
void window_copy_other_end(struct window_pane *);
|
||||||
|
void window_copy_cursor_left(struct window_pane *);
|
||||||
|
void window_copy_cursor_right(struct window_pane *);
|
||||||
|
void window_copy_cursor_up(struct window_pane *, int);
|
||||||
|
void window_copy_cursor_down(struct window_pane *, int);
|
||||||
|
void window_copy_cursor_jump(struct window_pane *);
|
||||||
|
void window_copy_cursor_jump_back(struct window_pane *);
|
||||||
|
void window_copy_cursor_jump_to(struct window_pane *, int);
|
||||||
|
void window_copy_cursor_jump_to_back(struct window_pane *, int);
|
||||||
|
void window_copy_cursor_next_word(struct window_pane *, const char *);
|
||||||
|
void window_copy_cursor_next_word_end(struct window_pane *, const char *);
|
||||||
|
void window_copy_cursor_previous_word(struct window_pane *, const char *);
|
||||||
|
void window_copy_scroll_up(struct window_pane *, u_int);
|
||||||
|
void window_copy_scroll_down(struct window_pane *, u_int);
|
||||||
|
void window_copy_rectangle_toggle(struct window_pane *);
|
||||||
|
void window_copy_drag_update(struct client *, struct mouse_event *);
|
||||||
|
void window_copy_drag_release(struct client *, struct mouse_event *);
|
||||||
|
|
||||||
|
extern const struct window_mode window_copy_mode;
|
||||||
|
|
||||||
enum window_copy_input_type {
|
enum window_copy_input_type {
|
||||||
WINDOW_COPY_OFF,
|
WINDOW_COPY_OFF,
|
||||||
WINDOW_COPY_NAMEDBUFFER,
|
WINDOW_COPY_NAMEDBUFFER,
|
||||||
@ -33,10 +97,6 @@ enum window_copy_input_type {
|
|||||||
* mode ends).
|
* mode ends).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef TMATE
|
|
||||||
typedef void (*copy_password_callback)(const char *password, void *private);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct window_copy_mode_data {
|
struct window_copy_mode_data {
|
||||||
struct screen screen;
|
struct screen screen;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user