mirror of
https://github.com/tmux/tmux.git
synced 2025-09-01 20:57:00 +00:00
Merge branch 'obsd-master'
This commit is contained in:
223
server-client.c
223
server-client.c
@ -48,6 +48,12 @@ static void server_client_dispatch(struct imsg *, void *);
|
||||
static void server_client_dispatch_command(struct client *, struct imsg *);
|
||||
static void server_client_dispatch_identify(struct client *, struct imsg *);
|
||||
static void server_client_dispatch_shell(struct client *);
|
||||
static void server_client_dispatch_write_ready(struct client *,
|
||||
struct imsg *);
|
||||
static void server_client_dispatch_read_data(struct client *,
|
||||
struct imsg *);
|
||||
static void server_client_dispatch_read_done(struct client *,
|
||||
struct imsg *);
|
||||
|
||||
/* Number of attached clients. */
|
||||
u_int
|
||||
@ -195,16 +201,6 @@ server_client_create(int fd)
|
||||
|
||||
TAILQ_INIT(&c->queue);
|
||||
|
||||
c->stdin_data = evbuffer_new();
|
||||
if (c->stdin_data == NULL)
|
||||
fatalx("out of memory");
|
||||
c->stdout_data = evbuffer_new();
|
||||
if (c->stdout_data == NULL)
|
||||
fatalx("out of memory");
|
||||
c->stderr_data = evbuffer_new();
|
||||
if (c->stderr_data == NULL)
|
||||
fatalx("out of memory");
|
||||
|
||||
c->tty.fd = -1;
|
||||
c->title = NULL;
|
||||
|
||||
@ -223,6 +219,8 @@ server_client_create(int fd)
|
||||
c->prompt_buffer = NULL;
|
||||
c->prompt_index = 0;
|
||||
|
||||
RB_INIT(&c->files);
|
||||
|
||||
c->flags |= CLIENT_FOCUSED;
|
||||
|
||||
c->keytable = key_bindings_get_table("root", 1);
|
||||
@ -264,6 +262,7 @@ void
|
||||
server_client_lost(struct client *c)
|
||||
{
|
||||
struct message_entry *msg, *msg1;
|
||||
struct client_file *cf;
|
||||
|
||||
c->flags |= CLIENT_DEAD;
|
||||
|
||||
@ -271,8 +270,10 @@ server_client_lost(struct client *c)
|
||||
status_prompt_clear(c);
|
||||
status_message_clear(c);
|
||||
|
||||
if (c->stdin_callback != NULL)
|
||||
c->stdin_callback(c, 1, c->stdin_callback_data);
|
||||
RB_FOREACH(cf, client_files, &c->files) {
|
||||
cf->error = EINTR;
|
||||
file_fire_done(cf);
|
||||
}
|
||||
|
||||
TAILQ_REMOVE(&clients, c, entry);
|
||||
log_debug("lost client %p", c);
|
||||
@ -286,11 +287,6 @@ server_client_lost(struct client *c)
|
||||
free(c->ttyname);
|
||||
free(c->term);
|
||||
|
||||
evbuffer_free(c->stdin_data);
|
||||
evbuffer_free(c->stdout_data);
|
||||
if (c->stderr_data != c->stdout_data)
|
||||
evbuffer_free(c->stderr_data);
|
||||
|
||||
status_free(c);
|
||||
|
||||
free(c->title);
|
||||
@ -1558,17 +1554,17 @@ server_client_click_timer(__unused int fd, __unused short events, void *data)
|
||||
static void
|
||||
server_client_check_exit(struct client *c)
|
||||
{
|
||||
struct client_file *cf;
|
||||
|
||||
if (~c->flags & CLIENT_EXIT)
|
||||
return;
|
||||
if (c->flags & CLIENT_EXITED)
|
||||
return;
|
||||
|
||||
if (EVBUFFER_LENGTH(c->stdin_data) != 0)
|
||||
return;
|
||||
if (EVBUFFER_LENGTH(c->stdout_data) != 0)
|
||||
return;
|
||||
if (EVBUFFER_LENGTH(c->stderr_data) != 0)
|
||||
return;
|
||||
RB_FOREACH(cf, client_files, &c->files) {
|
||||
if (EVBUFFER_LENGTH(cf->buffer) != 0)
|
||||
return;
|
||||
}
|
||||
|
||||
if (c->flags & CLIENT_ATTACHED)
|
||||
notify_client("client-detached", c);
|
||||
@ -1707,11 +1703,10 @@ server_client_set_title(struct client *c)
|
||||
static void
|
||||
server_client_dispatch(struct imsg *imsg, void *arg)
|
||||
{
|
||||
struct client *c = arg;
|
||||
struct msg_stdin_data stdindata;
|
||||
const char *data;
|
||||
ssize_t datalen;
|
||||
struct session *s;
|
||||
struct client *c = arg;
|
||||
const char *data;
|
||||
ssize_t datalen;
|
||||
struct session *s;
|
||||
|
||||
if (c->flags & CLIENT_DEAD)
|
||||
return;
|
||||
@ -1738,21 +1733,6 @@ server_client_dispatch(struct imsg *imsg, void *arg)
|
||||
case MSG_COMMAND:
|
||||
server_client_dispatch_command(c, imsg);
|
||||
break;
|
||||
case MSG_STDIN:
|
||||
if (datalen != sizeof stdindata)
|
||||
fatalx("bad MSG_STDIN size");
|
||||
memcpy(&stdindata, data, sizeof stdindata);
|
||||
|
||||
if (c->stdin_callback == NULL)
|
||||
break;
|
||||
if (stdindata.size <= 0)
|
||||
c->stdin_closed = 1;
|
||||
else {
|
||||
evbuffer_add(c->stdin_data, stdindata.data,
|
||||
stdindata.size);
|
||||
}
|
||||
c->stdin_callback(c, c->stdin_closed, c->stdin_callback_data);
|
||||
break;
|
||||
case MSG_RESIZE:
|
||||
if (datalen != 0)
|
||||
fatalx("bad MSG_RESIZE size");
|
||||
@ -1804,6 +1784,15 @@ server_client_dispatch(struct imsg *imsg, void *arg)
|
||||
|
||||
server_client_dispatch_shell(c);
|
||||
break;
|
||||
case MSG_WRITE_READY:
|
||||
server_client_dispatch_write_ready(c, imsg);
|
||||
break;
|
||||
case MSG_READ:
|
||||
server_client_dispatch_read_data(c, imsg);
|
||||
break;
|
||||
case MSG_READ_DONE:
|
||||
server_client_dispatch_read_done(c, imsg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1822,7 +1811,7 @@ server_client_command_done(struct cmdq_item *item, __unused void *data)
|
||||
static void
|
||||
server_client_dispatch_command(struct client *c, struct imsg *imsg)
|
||||
{
|
||||
struct msg_command_data data;
|
||||
struct msg_command data;
|
||||
char *buf;
|
||||
size_t len;
|
||||
int argc;
|
||||
@ -1966,19 +1955,11 @@ server_client_dispatch_identify(struct client *c, struct imsg *imsg)
|
||||
#endif
|
||||
|
||||
if (c->flags & CLIENT_CONTROL) {
|
||||
c->stdin_callback = control_callback;
|
||||
|
||||
evbuffer_free(c->stderr_data);
|
||||
c->stderr_data = c->stdout_data;
|
||||
|
||||
if (c->flags & CLIENT_CONTROLCONTROL)
|
||||
evbuffer_add_printf(c->stdout_data, "\033P1000p");
|
||||
proc_send(c->peer, MSG_STDIN, -1, NULL, 0);
|
||||
|
||||
c->tty.fd = -1;
|
||||
|
||||
close(c->fd);
|
||||
c->fd = -1;
|
||||
|
||||
control_start(c);
|
||||
c->tty.fd = -1;
|
||||
} else if (c->fd != -1) {
|
||||
if (tty_init(&c->tty, c, c->fd, c->term) != 0) {
|
||||
close(c->fd);
|
||||
@ -2018,93 +1999,71 @@ server_client_dispatch_shell(struct client *c)
|
||||
proc_kill_peer(c->peer);
|
||||
}
|
||||
|
||||
/* Event callback to push more stdout data if any left. */
|
||||
/* Handle write ready message. */
|
||||
static void
|
||||
server_client_stdout_cb(__unused int fd, __unused short events, void *arg)
|
||||
server_client_dispatch_write_ready(struct client *c, struct imsg *imsg)
|
||||
{
|
||||
struct client *c = arg;
|
||||
struct msg_write_ready *msg = imsg->data;
|
||||
size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE;
|
||||
struct client_file find, *cf;
|
||||
|
||||
if (~c->flags & CLIENT_DEAD)
|
||||
server_client_push_stdout(c);
|
||||
server_client_unref(c);
|
||||
}
|
||||
|
||||
/* Push stdout to client if possible. */
|
||||
void
|
||||
server_client_push_stdout(struct client *c)
|
||||
{
|
||||
struct msg_stdout_data data;
|
||||
size_t sent, left;
|
||||
|
||||
left = EVBUFFER_LENGTH(c->stdout_data);
|
||||
while (left != 0) {
|
||||
sent = left;
|
||||
if (sent > sizeof data.data)
|
||||
sent = sizeof data.data;
|
||||
memcpy(data.data, EVBUFFER_DATA(c->stdout_data), sent);
|
||||
data.size = sent;
|
||||
|
||||
if (proc_send(c->peer, MSG_STDOUT, -1, &data, sizeof data) != 0)
|
||||
break;
|
||||
evbuffer_drain(c->stdout_data, sent);
|
||||
|
||||
left = EVBUFFER_LENGTH(c->stdout_data);
|
||||
log_debug("%s: client %p, sent %zu, left %zu", __func__, c,
|
||||
sent, left);
|
||||
}
|
||||
if (left != 0) {
|
||||
c->references++;
|
||||
event_once(-1, EV_TIMEOUT, server_client_stdout_cb, c, NULL);
|
||||
log_debug("%s: client %p, queued", __func__, c);
|
||||
}
|
||||
}
|
||||
|
||||
/* Event callback to push more stderr data if any left. */
|
||||
static void
|
||||
server_client_stderr_cb(__unused int fd, __unused short events, void *arg)
|
||||
{
|
||||
struct client *c = arg;
|
||||
|
||||
if (~c->flags & CLIENT_DEAD)
|
||||
server_client_push_stderr(c);
|
||||
server_client_unref(c);
|
||||
}
|
||||
|
||||
/* Push stderr to client if possible. */
|
||||
void
|
||||
server_client_push_stderr(struct client *c)
|
||||
{
|
||||
struct msg_stderr_data data;
|
||||
size_t sent, left;
|
||||
|
||||
if (c->stderr_data == c->stdout_data) {
|
||||
server_client_push_stdout(c);
|
||||
if (msglen != sizeof *msg)
|
||||
fatalx("bad MSG_WRITE_READY size");
|
||||
find.stream = msg->stream;
|
||||
if ((cf = RB_FIND(client_files, &c->files, &find)) == NULL)
|
||||
return;
|
||||
}
|
||||
if (msg->error != 0) {
|
||||
cf->error = msg->error;
|
||||
file_fire_done(cf);
|
||||
} else
|
||||
file_push(cf);
|
||||
}
|
||||
|
||||
left = EVBUFFER_LENGTH(c->stderr_data);
|
||||
while (left != 0) {
|
||||
sent = left;
|
||||
if (sent > sizeof data.data)
|
||||
sent = sizeof data.data;
|
||||
memcpy(data.data, EVBUFFER_DATA(c->stderr_data), sent);
|
||||
data.size = sent;
|
||||
/* Handle read data message. */
|
||||
static void
|
||||
server_client_dispatch_read_data(struct client *c, struct imsg *imsg)
|
||||
{
|
||||
struct msg_read_data *msg = imsg->data;
|
||||
size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE;
|
||||
struct client_file find, *cf;
|
||||
void *bdata = msg->data;
|
||||
size_t bsize = msg->size;
|
||||
|
||||
if (proc_send(c->peer, MSG_STDERR, -1, &data, sizeof data) != 0)
|
||||
break;
|
||||
evbuffer_drain(c->stderr_data, sent);
|
||||
if (msglen != sizeof *msg)
|
||||
fatalx("bad MSG_READ_DATA size");
|
||||
find.stream = msg->stream;
|
||||
if ((cf = RB_FIND(client_files, &c->files, &find)) == NULL)
|
||||
return;
|
||||
|
||||
left = EVBUFFER_LENGTH(c->stderr_data);
|
||||
log_debug("%s: client %p, sent %zu, left %zu", __func__, c,
|
||||
sent, left);
|
||||
}
|
||||
if (left != 0) {
|
||||
c->references++;
|
||||
event_once(-1, EV_TIMEOUT, server_client_stderr_cb, c, NULL);
|
||||
log_debug("%s: client %p, queued", __func__, c);
|
||||
log_debug("%s: file %d read %zu bytes", c->name, cf->stream, bsize);
|
||||
if (cf->error == 0) {
|
||||
if (evbuffer_add(cf->buffer, bdata, bsize) != 0) {
|
||||
cf->error = ENOMEM;
|
||||
file_fire_done(cf);
|
||||
} else
|
||||
file_fire_read(cf);
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle read done message. */
|
||||
static void
|
||||
server_client_dispatch_read_done(struct client *c, struct imsg *imsg)
|
||||
{
|
||||
struct msg_read_done *msg = imsg->data;
|
||||
size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE;
|
||||
struct client_file find, *cf;
|
||||
|
||||
if (msglen != sizeof *msg)
|
||||
fatalx("bad MSG_READ_DONE size");
|
||||
find.stream = msg->stream;
|
||||
if ((cf = RB_FIND(client_files, &c->files, &find)) == NULL)
|
||||
return;
|
||||
|
||||
log_debug("%s: file %d read done", c->name, cf->stream);
|
||||
cf->error = msg->error;
|
||||
file_fire_done(cf);
|
||||
}
|
||||
|
||||
/* Add to client message log. */
|
||||
void
|
||||
server_client_add_message(struct client *c, const char *fmt, ...)
|
||||
|
Reference in New Issue
Block a user