mirror of
https://github.com/tmux/tmux.git
synced 2025-01-27 16:48:49 +00:00
Merge branch 'obsd-master'
This commit is contained in:
commit
ea4425b9bd
45
client.c
45
client.c
@ -45,11 +45,13 @@ static enum {
|
|||||||
CLIENT_EXIT_LOST_SERVER,
|
CLIENT_EXIT_LOST_SERVER,
|
||||||
CLIENT_EXIT_EXITED,
|
CLIENT_EXIT_EXITED,
|
||||||
CLIENT_EXIT_SERVER_EXITED,
|
CLIENT_EXIT_SERVER_EXITED,
|
||||||
|
CLIENT_EXIT_MESSAGE_PROVIDED
|
||||||
} client_exitreason = CLIENT_EXIT_NONE;
|
} client_exitreason = CLIENT_EXIT_NONE;
|
||||||
static int client_exitflag;
|
static int client_exitflag;
|
||||||
static int client_exitval;
|
static int client_exitval;
|
||||||
static enum msgtype client_exittype;
|
static enum msgtype client_exittype;
|
||||||
static const char *client_exitsession;
|
static const char *client_exitsession;
|
||||||
|
static char *client_exitmessage;
|
||||||
static const char *client_execshell;
|
static const char *client_execshell;
|
||||||
static const char *client_execcmd;
|
static const char *client_execcmd;
|
||||||
static int client_attached;
|
static int client_attached;
|
||||||
@ -207,6 +209,8 @@ client_exit_message(void)
|
|||||||
return ("exited");
|
return ("exited");
|
||||||
case CLIENT_EXIT_SERVER_EXITED:
|
case CLIENT_EXIT_SERVER_EXITED:
|
||||||
return ("server exited");
|
return ("server exited");
|
||||||
|
case CLIENT_EXIT_MESSAGE_PROVIDED:
|
||||||
|
return (client_exitmessage);
|
||||||
}
|
}
|
||||||
return ("unknown reason");
|
return ("unknown reason");
|
||||||
}
|
}
|
||||||
@ -793,13 +797,38 @@ client_dispatch(struct imsg *imsg, __unused void *arg)
|
|||||||
client_dispatch_wait(imsg);
|
client_dispatch_wait(imsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Process an exit message. */
|
||||||
|
static void
|
||||||
|
client_dispatch_exit_message(char *data, size_t datalen)
|
||||||
|
{
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
if (datalen < sizeof retval && datalen != 0)
|
||||||
|
fatalx("bad MSG_EXIT size");
|
||||||
|
|
||||||
|
if (datalen >= sizeof retval) {
|
||||||
|
memcpy(&retval, data, sizeof retval);
|
||||||
|
client_exitval = retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (datalen > sizeof retval) {
|
||||||
|
datalen -= sizeof retval;
|
||||||
|
data += sizeof retval;
|
||||||
|
|
||||||
|
client_exitmessage = xmalloc(datalen);
|
||||||
|
memcpy(client_exitmessage, data, datalen);
|
||||||
|
client_exitmessage[datalen - 1] = '\0';
|
||||||
|
|
||||||
|
client_exitreason = CLIENT_EXIT_MESSAGE_PROVIDED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Dispatch imsgs when in wait state (before MSG_READY). */
|
/* Dispatch imsgs when in wait state (before MSG_READY). */
|
||||||
static void
|
static void
|
||||||
client_dispatch_wait(struct imsg *imsg)
|
client_dispatch_wait(struct imsg *imsg)
|
||||||
{
|
{
|
||||||
char *data;
|
char *data;
|
||||||
ssize_t datalen;
|
ssize_t datalen;
|
||||||
int retval;
|
|
||||||
static int pledge_applied;
|
static int pledge_applied;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -822,12 +851,7 @@ client_dispatch_wait(struct imsg *imsg)
|
|||||||
switch (imsg->hdr.type) {
|
switch (imsg->hdr.type) {
|
||||||
case MSG_EXIT:
|
case MSG_EXIT:
|
||||||
case MSG_SHUTDOWN:
|
case MSG_SHUTDOWN:
|
||||||
if (datalen != sizeof retval && datalen != 0)
|
client_dispatch_exit_message(data, datalen);
|
||||||
fatalx("bad MSG_EXIT size");
|
|
||||||
if (datalen == sizeof retval) {
|
|
||||||
memcpy(&retval, data, sizeof retval);
|
|
||||||
client_exitval = retval;
|
|
||||||
}
|
|
||||||
client_exitflag = 1;
|
client_exitflag = 1;
|
||||||
client_exit();
|
client_exit();
|
||||||
break;
|
break;
|
||||||
@ -918,11 +942,10 @@ client_dispatch_attached(struct imsg *imsg)
|
|||||||
proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
|
proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
|
||||||
break;
|
break;
|
||||||
case MSG_EXIT:
|
case MSG_EXIT:
|
||||||
if (datalen != 0 && datalen != sizeof (int))
|
client_dispatch_exit_message(data, datalen);
|
||||||
fatalx("bad MSG_EXIT size");
|
if (client_exitreason == CLIENT_EXIT_NONE)
|
||||||
|
client_exitreason = CLIENT_EXIT_EXITED;
|
||||||
proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
|
proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
|
||||||
client_exitreason = CLIENT_EXIT_EXITED;
|
|
||||||
break;
|
break;
|
||||||
case MSG_EXITED:
|
case MSG_EXITED:
|
||||||
if (datalen != 0)
|
if (datalen != 0)
|
||||||
|
57
control.c
57
control.c
@ -89,13 +89,16 @@ struct control_state {
|
|||||||
struct bufferevent *write_event;
|
struct bufferevent *write_event;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Low watermark. */
|
/* Low and high watermarks. */
|
||||||
#define CONTROL_BUFFER_LOW 512
|
#define CONTROL_BUFFER_LOW 512
|
||||||
#define CONTROL_BUFFER_HIGH 8192
|
#define CONTROL_BUFFER_HIGH 8192
|
||||||
|
|
||||||
/* Minimum to write to each client. */
|
/* Minimum to write to each client. */
|
||||||
#define CONTROL_WRITE_MINIMUM 32
|
#define CONTROL_WRITE_MINIMUM 32
|
||||||
|
|
||||||
|
/* Maximum age for clients that are not using pause mode. */
|
||||||
|
#define CONTROL_MAXIMUM_AGE 300000
|
||||||
|
|
||||||
/* Flags to ignore client. */
|
/* Flags to ignore client. */
|
||||||
#define CONTROL_IGNORE_FLAGS \
|
#define CONTROL_IGNORE_FLAGS \
|
||||||
(CLIENT_CONTROL_NOOUTPUT| \
|
(CLIENT_CONTROL_NOOUTPUT| \
|
||||||
@ -306,6 +309,41 @@ control_write(struct client *c, const char *fmt, ...)
|
|||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check age for this pane. */
|
||||||
|
static int
|
||||||
|
control_check_age(struct client *c, struct window_pane *wp,
|
||||||
|
struct control_pane *cp)
|
||||||
|
{
|
||||||
|
struct control_block *cb;
|
||||||
|
uint64_t t, age;
|
||||||
|
|
||||||
|
cb = TAILQ_FIRST(&cp->blocks);
|
||||||
|
if (cb == NULL)
|
||||||
|
return (0);
|
||||||
|
t = get_timer();
|
||||||
|
if (cb->t >= t)
|
||||||
|
return (0);
|
||||||
|
|
||||||
|
age = t - cb->t;
|
||||||
|
log_debug("%s: %s: %%%u is %llu behind", __func__, c->name, wp->id,
|
||||||
|
(unsigned long long)age);
|
||||||
|
|
||||||
|
if (c->flags & CLIENT_CONTROL_PAUSEAFTER) {
|
||||||
|
if (age < c->pause_age)
|
||||||
|
return (0);
|
||||||
|
cp->flags |= CONTROL_PANE_PAUSED;
|
||||||
|
control_discard_pane(c, cp);
|
||||||
|
control_write(c, "%%pause %%%u", wp->id);
|
||||||
|
} else {
|
||||||
|
if (age < CONTROL_MAXIMUM_AGE)
|
||||||
|
return (0);
|
||||||
|
c->exit_message = xstrdup("too far behind");
|
||||||
|
c->flags |= CLIENT_EXIT;
|
||||||
|
control_discard(c);
|
||||||
|
}
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
/* Write output from a pane. */
|
/* Write output from a pane. */
|
||||||
void
|
void
|
||||||
control_write_output(struct client *c, struct window_pane *wp)
|
control_write_output(struct client *c, struct window_pane *wp)
|
||||||
@ -314,7 +352,6 @@ control_write_output(struct client *c, struct window_pane *wp)
|
|||||||
struct control_pane *cp;
|
struct control_pane *cp;
|
||||||
struct control_block *cb;
|
struct control_block *cb;
|
||||||
size_t new_size;
|
size_t new_size;
|
||||||
uint64_t t;
|
|
||||||
|
|
||||||
if (winlink_find_by_window(&c->session->windows, wp->window) == NULL)
|
if (winlink_find_by_window(&c->session->windows, wp->window) == NULL)
|
||||||
return;
|
return;
|
||||||
@ -328,20 +365,8 @@ control_write_output(struct client *c, struct window_pane *wp)
|
|||||||
cp = control_add_pane(c, wp);
|
cp = control_add_pane(c, wp);
|
||||||
if (cp->flags & (CONTROL_PANE_OFF|CONTROL_PANE_PAUSED))
|
if (cp->flags & (CONTROL_PANE_OFF|CONTROL_PANE_PAUSED))
|
||||||
goto ignore;
|
goto ignore;
|
||||||
if (c->flags & CLIENT_CONTROL_PAUSEAFTER) {
|
if (control_check_age(c, wp, cp))
|
||||||
cb = TAILQ_FIRST(&cp->blocks);
|
return;
|
||||||
if (cb != NULL) {
|
|
||||||
t = get_timer();
|
|
||||||
log_debug("%s: %s: %%%u is %lld behind", __func__,
|
|
||||||
c->name, wp->id, (long long)t - cb->t);
|
|
||||||
if (cb->t < t - c->pause_age) {
|
|
||||||
cp->flags |= CONTROL_PANE_PAUSED;
|
|
||||||
control_discard_pane(c, cp);
|
|
||||||
control_write(c, "%%pause %%%u", wp->id);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
window_pane_get_new_data(wp, &cp->queued, &new_size);
|
window_pane_get_new_data(wp, &cp->queued, &new_size);
|
||||||
if (new_size == 0)
|
if (new_size == 0)
|
||||||
|
@ -55,9 +55,6 @@ static void server_client_dispatch_read_data(struct client *,
|
|||||||
static void server_client_dispatch_read_done(struct client *,
|
static void server_client_dispatch_read_done(struct client *,
|
||||||
struct imsg *);
|
struct imsg *);
|
||||||
|
|
||||||
/* Maximum data allowed to be held for a pane for a control client. */
|
|
||||||
#define SERVER_CLIENT_PANE_LIMIT 16777216
|
|
||||||
|
|
||||||
/* Compare client windows. */
|
/* Compare client windows. */
|
||||||
static int
|
static int
|
||||||
server_client_window_cmp(struct client_window *cw1,
|
server_client_window_cmp(struct client_window *cw1,
|
||||||
@ -1526,10 +1523,6 @@ server_client_check_pane_buffer(struct window_pane *wp)
|
|||||||
log_debug("%s: %s has %zu bytes used and %zu left for %%%u",
|
log_debug("%s: %s has %zu bytes used and %zu left for %%%u",
|
||||||
__func__, c->name, wpo->used - wp->base_offset, new_size,
|
__func__, c->name, wpo->used - wp->base_offset, new_size,
|
||||||
wp->id);
|
wp->id);
|
||||||
if (new_size > SERVER_CLIENT_PANE_LIMIT) {
|
|
||||||
control_discard(c);
|
|
||||||
c->flags |= CLIENT_EXIT;
|
|
||||||
}
|
|
||||||
if (wpo->used < minimum)
|
if (wpo->used < minimum)
|
||||||
minimum = wpo->used;
|
minimum = wpo->used;
|
||||||
}
|
}
|
||||||
@ -1764,6 +1757,8 @@ server_client_check_exit(struct client *c)
|
|||||||
{
|
{
|
||||||
struct client_file *cf;
|
struct client_file *cf;
|
||||||
const char *name = c->exit_session;
|
const char *name = c->exit_session;
|
||||||
|
char *data;
|
||||||
|
size_t size, msize;
|
||||||
|
|
||||||
if (c->flags & (CLIENT_DEAD|CLIENT_EXITED))
|
if (c->flags & (CLIENT_DEAD|CLIENT_EXITED))
|
||||||
return;
|
return;
|
||||||
@ -1786,7 +1781,17 @@ server_client_check_exit(struct client *c)
|
|||||||
|
|
||||||
switch (c->exit_type) {
|
switch (c->exit_type) {
|
||||||
case CLIENT_EXIT_RETURN:
|
case CLIENT_EXIT_RETURN:
|
||||||
proc_send(c->peer, MSG_EXIT, -1, &c->retval, sizeof c->retval);
|
if (c->exit_message != NULL) {
|
||||||
|
msize = strlen(c->exit_message) + 1;
|
||||||
|
size = (sizeof c->retval) + msize;
|
||||||
|
} else
|
||||||
|
size = (sizeof c->retval);
|
||||||
|
data = xmalloc(size);
|
||||||
|
memcpy(data, &c->retval, sizeof c->retval);
|
||||||
|
if (c->exit_message != NULL)
|
||||||
|
memcpy(data + sizeof c->retval, c->exit_message, msize);
|
||||||
|
proc_send(c->peer, MSG_EXIT, -1, data, size);
|
||||||
|
free(data);
|
||||||
break;
|
break;
|
||||||
case CLIENT_EXIT_SHUTDOWN:
|
case CLIENT_EXIT_SHUTDOWN:
|
||||||
proc_send(c->peer, MSG_SHUTDOWN, -1, NULL, 0);
|
proc_send(c->peer, MSG_SHUTDOWN, -1, NULL, 0);
|
||||||
@ -1796,6 +1801,7 @@ server_client_check_exit(struct client *c)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
free(c->exit_session);
|
free(c->exit_session);
|
||||||
|
free(c->exit_message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Redraw timer callback. */
|
/* Redraw timer callback. */
|
||||||
|
17
tmux.1
17
tmux.1
@ -5727,29 +5727,32 @@ When a
|
|||||||
client detaches, it prints a message.
|
client detaches, it prints a message.
|
||||||
This may be one of:
|
This may be one of:
|
||||||
.Bl -tag -width Ds
|
.Bl -tag -width Ds
|
||||||
.It [detached (from session ...)]
|
.It detached (from session ...)
|
||||||
The client was detached normally.
|
The client was detached normally.
|
||||||
.It [detached and SIGHUP]
|
.It detached and SIGHUP
|
||||||
The client was detached and its parent sent the
|
The client was detached and its parent sent the
|
||||||
.Dv SIGHUP
|
.Dv SIGHUP
|
||||||
signal (for example with
|
signal (for example with
|
||||||
.Ic detach-client
|
.Ic detach-client
|
||||||
.Fl P ) .
|
.Fl P ) .
|
||||||
.It [lost tty]
|
.It lost tty
|
||||||
The client's
|
The client's
|
||||||
.Xr tty 4
|
.Xr tty 4
|
||||||
or
|
or
|
||||||
.Xr pty 4
|
.Xr pty 4
|
||||||
was unexpectedly destroyed.
|
was unexpectedly destroyed.
|
||||||
.It [terminated]
|
.It terminated
|
||||||
The client was killed with
|
The client was killed with
|
||||||
.Dv SIGTERM .
|
.Dv SIGTERM .
|
||||||
.It [exited]
|
.It too far behind
|
||||||
|
The client is in control mode and became unable to keep up with the data from
|
||||||
|
.Nm .
|
||||||
|
.It exited
|
||||||
The server exited when it had no sessions.
|
The server exited when it had no sessions.
|
||||||
.It [server exited]
|
.It server exited
|
||||||
The server exited when it received
|
The server exited when it received
|
||||||
.Dv SIGTERM .
|
.Dv SIGTERM .
|
||||||
.It [server exited unexpectedly]
|
.It server exited unexpectedly
|
||||||
The server crashed or otherwise exited without telling the client the reason.
|
The server crashed or otherwise exited without telling the client the reason.
|
||||||
.El
|
.El
|
||||||
.Sh TERMINFO EXTENSIONS
|
.Sh TERMINFO EXTENSIONS
|
||||||
|
Loading…
Reference in New Issue
Block a user