Pass the stdout file descriptor from the client as well as stdin and use

them for control clients directly instead of passing everything via the
client.
This commit is contained in:
nicm 2020-05-26 08:41:47 +00:00
parent 6f03e49e68
commit ea610a3119
5 changed files with 91 additions and 35 deletions

View File

@ -402,6 +402,8 @@ client_main(struct event_base *base, int argc, char **argv, int flags, int feat)
} else if (client_exitreason != CLIENT_EXIT_NONE)
fprintf(stderr, "%s\n", client_exit_message());
setblocking(STDIN_FILENO, 1);
setblocking(STDOUT_FILENO, 1);
setblocking(STDERR_FILENO, 1);
return (client_exitval);
}
@ -429,6 +431,9 @@ client_send_identify(const char *ttynam, const char *cwd, int feat)
if ((fd = dup(STDIN_FILENO)) == -1)
fatal("dup failed");
proc_send(client_peer, MSG_IDENTIFY_STDIN, fd, NULL, 0);
if ((fd = dup(STDOUT_FILENO)) == -1)
fatal("dup failed");
proc_send(client_peer, MSG_IDENTIFY_STDOUT, fd, NULL, 0);
pid = getpid();
proc_send(client_peer, MSG_IDENTIFY_CLIENTPID, -1, &pid, sizeof pid);

View File

@ -23,10 +23,11 @@
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "tmux.h"
/* Control offsets. */
/* Control client offset. */
struct control_offset {
u_int pane;
@ -34,13 +35,16 @@ struct control_offset {
int flags;
#define CONTROL_OFFSET_OFF 0x1
RB_ENTRY(control_offset) entry;
RB_ENTRY(control_offset) entry;
};
RB_HEAD(control_offsets, control_offset);
/* Control state. */
/* Control client state. */
struct control_state {
struct control_offsets offsets;
struct control_offsets offsets;
struct bufferevent *read_event;
struct bufferevent *write_event;
};
/* Compare client offsets. */
@ -146,18 +150,24 @@ control_set_pane_off(struct client *c, struct window_pane *wp)
void
control_write(struct client *c, const char *fmt, ...)
{
va_list ap;
struct control_state *cs = c->control_state;
va_list ap;
char *s;
va_start(ap, fmt);
file_vprint(c, fmt, ap);
file_print(c, "\n");
xvasprintf(&s, fmt, ap);
va_end(ap);
bufferevent_write(cs->write_event, s, strlen(s));
bufferevent_write(cs->write_event, "\n", 1);
free(s);
}
/* Write output from a pane. */
void
control_write_output(struct client *c, struct window_pane *wp)
{
struct control_state *cs = c->control_state;
struct control_offset *co;
struct evbuffer *message;
u_char *new_data;
@ -165,11 +175,6 @@ control_write_output(struct client *c, struct window_pane *wp)
if (c->flags & CLIENT_CONTROL_NOOUTPUT)
return;
/*
* Only write input if the window pane is linked to a window belonging
* to the client's session.
*/
if (winlink_find_by_window(&c->session->windows, wp->window) == NULL)
return;
@ -193,15 +198,15 @@ control_write_output(struct client *c, struct window_pane *wp)
else
evbuffer_add_printf(message, "%c", new_data[i]);
}
evbuffer_add(message, "", 1);
evbuffer_add(message, "\n", 1);
control_write(c, "%s", EVBUFFER_DATA(message));
bufferevent_write_buffer(cs->write_event, message);
evbuffer_free(message);
window_pane_update_used_data(wp, &co->offset, new_size, 1);
}
/* Control error callback. */
/* Control client error callback. */
static enum cmd_retval
control_error(struct cmdq_item *item, void *data)
{
@ -216,18 +221,27 @@ control_error(struct cmdq_item *item, void *data)
return (CMD_RETURN_NORMAL);
}
/* Control input callback. Read lines and fire commands. */
/* Control client error callback. */
static void
control_callback(__unused struct client *c, __unused const char *path,
int read_error, int closed, struct evbuffer *buffer, __unused void *data)
control_error_callback(__unused struct bufferevent *bufev,
__unused short what, void *data)
{
struct client *c = data;
c->flags |= CLIENT_EXIT;
}
/* Control client input callback. Read lines and fire commands. */
static void
control_read_callback(__unused struct bufferevent *bufev, void *data)
{
struct client *c = data;
struct control_state *cs = c->control_state;
struct evbuffer *buffer = cs->read_event->input;
char *line, *error;
struct cmdq_state *state;
enum cmd_parse_status status;
if (closed || read_error != 0)
c->flags |= CLIENT_EXIT;
for (;;) {
line = evbuffer_readln(buffer, NULL, EVBUFFER_EOL_LF);
if (line == NULL)
@ -255,13 +269,30 @@ control_start(struct client *c)
{
struct control_state *cs;
if (c->flags & CLIENT_CONTROLCONTROL) {
close(c->out_fd);
c->out_fd = -1;
} else
setblocking(c->out_fd, 0);
setblocking(c->fd, 0);
cs = c->control_state = xcalloc(1, sizeof *cs);
RB_INIT(&cs->offsets);
file_read(c, "-", control_callback, c);
cs->read_event = bufferevent_new(c->fd, control_read_callback, NULL,
control_error_callback, c);
bufferevent_enable(cs->read_event, EV_READ);
if (c->flags & CLIENT_CONTROLCONTROL)
file_print(c, "\033P1000p");
cs->write_event = cs->read_event;
else {
cs->write_event = bufferevent_new(c->out_fd, NULL, NULL,
control_error_callback, c);
}
bufferevent_enable(cs->write_event, EV_WRITE);
if (c->flags & CLIENT_CONTROLCONTROL)
control_write(c, "\033P1000p");
}
/* Stop control mode. */
@ -270,6 +301,10 @@ control_stop(struct client *c)
{
struct control_state *cs = c->control_state;
if (~c->flags & CLIENT_CONTROLCONTROL)
bufferevent_free(cs->write_event);
bufferevent_free(cs->read_event);
control_free_offsets(c);
free(cs);
}

8
file.c
View File

@ -242,7 +242,9 @@ file_write(struct client *c, const char *path, int flags, const void *bdata,
cf->path = xstrdup("-");
fd = STDOUT_FILENO;
if (c == NULL || c->flags & CLIENT_ATTACHED) {
if (c == NULL ||
(c->flags & CLIENT_ATTACHED) ||
(c->flags & CLIENT_CONTROL)) {
cf->error = EBADF;
goto done;
}
@ -311,7 +313,9 @@ file_read(struct client *c, const char *path, client_file_cb cb, void *cbdata)
cf->path = xstrdup("-");
fd = STDIN_FILENO;
if (c == NULL || c->flags & CLIENT_ATTACHED) {
if (c == NULL ||
(c->flags & CLIENT_ATTACHED) ||
(c->flags & CLIENT_CONTROL)) {
cf->error = EBADF;
goto done;
}

View File

@ -223,7 +223,7 @@ server_client_create(int fd)
c->environ = environ_create();
c->fd = -1;
c->cwd = NULL;
c->out_fd = -1;
c->queue = cmdq_new();
RB_INIT(&c->windows);
@ -338,6 +338,8 @@ server_client_lost(struct client *c)
proc_remove_peer(c->peer);
c->peer = NULL;
if (c->out_fd != -1)
close(c->out_fd);
if (c->fd != -1) {
close(c->fd);
c->fd = -1;
@ -1573,10 +1575,9 @@ server_client_check_pane_buffer(struct window_pane *wp)
out:
/*
* If there is data remaining, and there are no clients able to consume
* it, do not read any more. This is true when 1) there are attached
* clients 2) all the clients are control clients 3) all of them have
* either the OFF flag set, or are otherwise not able to accept any
* more data for this pane.
* it, do not read any more. This is true when there are attached
* clients, all of which are control clients which are not able to
* accept any more data.
*/
if (off)
bufferevent_disable(wp->event, EV_READ);
@ -1969,6 +1970,7 @@ server_client_dispatch(struct imsg *imsg, void *arg)
case MSG_IDENTIFY_TTYNAME:
case MSG_IDENTIFY_CWD:
case MSG_IDENTIFY_STDIN:
case MSG_IDENTIFY_STDOUT:
case MSG_IDENTIFY_ENVIRON:
case MSG_IDENTIFY_CLIENTPID:
case MSG_IDENTIFY_DONE:
@ -2179,6 +2181,12 @@ server_client_dispatch_identify(struct client *c, struct imsg *imsg)
c->fd = imsg->fd;
log_debug("client %p IDENTIFY_STDIN %d", c, imsg->fd);
break;
case MSG_IDENTIFY_STDOUT:
if (datalen != 0)
fatalx("bad MSG_IDENTIFY_STDOUT size");
c->out_fd = imsg->fd;
log_debug("client %p IDENTIFY_STDOUT %d", c, imsg->fd);
break;
case MSG_IDENTIFY_ENVIRON:
if (datalen == 0 || data[datalen - 1] != '\0')
fatalx("bad MSG_IDENTIFY_ENVIRON string");
@ -2207,11 +2215,9 @@ server_client_dispatch_identify(struct client *c, struct imsg *imsg)
c->name = name;
log_debug("client %p name is %s", c, c->name);
if (c->flags & CLIENT_CONTROL) {
close(c->fd);
c->fd = -1;
if (c->flags & CLIENT_CONTROL)
control_start(c);
} else if (c->fd != -1) {
else if (c->fd != -1) {
if (tty_init(&c->tty, c) != 0) {
close(c->fd);
c->fd = -1;
@ -2219,6 +2225,8 @@ server_client_dispatch_identify(struct client *c, struct imsg *imsg)
tty_resize(&c->tty);
c->flags |= CLIENT_TERMINAL;
}
close(c->out_fd);
c->out_fd = -1;
}
/*
@ -2335,7 +2343,8 @@ void
server_client_set_flags(struct client *c, const char *flags)
{
char *s, *copy, *next;
int flag, not;
uint64_t flag;
int not;
s = copy = xstrdup (flags);
while ((next = strsep(&s, ",")) != NULL) {

3
tmux.h
View File

@ -498,6 +498,7 @@ enum msgtype {
MSG_IDENTIFY_CLIENTPID,
MSG_IDENTIFY_CWD,
MSG_IDENTIFY_FEATURES,
MSG_IDENTIFY_STDOUT,
MSG_COMMAND = 200,
MSG_DETACH,
@ -967,6 +968,7 @@ struct window_pane {
int fd;
struct bufferevent *event;
struct window_pane_offset offset;
size_t base_offset;
@ -1581,6 +1583,7 @@ struct client {
pid_t pid;
int fd;
int out_fd;
struct event event;
int retval;