Move the call to setupterm() into the client and have it pass the

results to the server over imsg, means the server does not need to enter
ncurses or read terminfo db. Old clients will not work with a new
server.
pull/2573/head
nicm 2021-02-17 07:18:36 +00:00
parent d768fc2553
commit af3ffa9c41
5 changed files with 169 additions and 72 deletions

View File

@ -62,7 +62,8 @@ static __dead void client_exec(const char *,const char *);
static int client_get_lock(char *);
static int client_connect(struct event_base *, const char *,
uint64_t);
static void client_send_identify(const char *, const char *, int);
static void client_send_identify(const char *, const char *,
char **, u_int, const char *, int);
static void client_signal(int);
static void client_dispatch(struct imsg *, void *);
static void client_dispatch_attached(struct imsg *);
@ -235,13 +236,14 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
struct cmd_parse_result *pr;
struct msg_command *data;
int fd, i;
const char *ttynam, *cwd;
const char *ttynam, *termname, *cwd;
pid_t ppid;
enum msgtype msg;
struct termios tio, saved_tio;
size_t size, linesize = 0;
ssize_t linelen;
char *line = NULL;
char *line = NULL, **caps = NULL, *cause;
u_int ncaps = 0;
/* Ignore SIGCHLD now or daemon() in the server will leave a zombie. */
signal(SIGCHLD, SIG_IGN);
@ -297,6 +299,8 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
cwd = "/";
if ((ttynam = ttyname(STDIN_FILENO)) == NULL)
ttynam = "";
if ((termname = getenv("TERM")) == NULL)
termname = "";
/*
* Drop privileges for client. "proc exec" is needed for -c and for
@ -312,6 +316,16 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
NULL) != 0)
fatal("pledge failed");
/* Load terminfo entry if any. */
if (isatty(STDIN_FILENO) &&
*termname != '\0' &&
tty_term_read_list(termname, STDIN_FILENO, &caps, &ncaps,
&cause) != 0) {
fprintf(stderr, "%s\n", cause);
free(cause);
return (1);
}
/* Free stuff that is not used in the client. */
if (ptm_fd != -1)
close(ptm_fd);
@ -340,7 +354,8 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
}
/* Send identify messages. */
client_send_identify(ttynam, cwd, feat);
client_send_identify(ttynam, termname, caps, ncaps, cwd, feat);
tty_term_free_list(caps, ncaps);
/* Send first command. */
if (msg == MSG_COMMAND) {
@ -423,27 +438,32 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
/* Send identify messages to server. */
static void
client_send_identify(const char *ttynam, const char *cwd, int feat)
client_send_identify(const char *ttynam, const char *termname, char **caps,
u_int ncaps, const char *cwd, int feat)
{
const char *s;
char **ss;
size_t sslen;
int fd, flags = client_flags;
pid_t pid;
char **ss;
size_t sslen;
int fd, flags = client_flags;
pid_t pid;
u_int i;
proc_send(client_peer, MSG_IDENTIFY_FLAGS, -1, &flags, sizeof flags);
proc_send(client_peer, MSG_IDENTIFY_LONGFLAGS, -1, &client_flags,
sizeof client_flags);
if ((s = getenv("TERM")) == NULL)
s = "";
proc_send(client_peer, MSG_IDENTIFY_TERM, -1, s, strlen(s) + 1);
proc_send(client_peer, MSG_IDENTIFY_TERM, -1, termname,
strlen(termname) + 1);
proc_send(client_peer, MSG_IDENTIFY_FEATURES, -1, &feat, sizeof feat);
proc_send(client_peer, MSG_IDENTIFY_TTYNAME, -1, ttynam,
strlen(ttynam) + 1);
proc_send(client_peer, MSG_IDENTIFY_CWD, -1, cwd, strlen(cwd) + 1);
for (i = 0; i < ncaps; i++) {
proc_send(client_peer, MSG_IDENTIFY_TERMINFO, -1,
caps[i], strlen(caps[i]) + 1);
}
if ((fd = dup(STDIN_FILENO)) == -1)
fatal("dup failed");
proc_send(client_peer, MSG_IDENTIFY_STDIN, fd, NULL, 0);

View File

@ -307,6 +307,7 @@ server_client_lost(struct client *c)
free(c->term_name);
free(c->term_type);
tty_term_free_list(c->term_caps, c->term_ncaps);
status_free(c);
@ -1997,16 +1998,17 @@ server_client_dispatch(struct imsg *imsg, void *arg)
datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
switch (imsg->hdr.type) {
case MSG_IDENTIFY_CLIENTPID:
case MSG_IDENTIFY_CWD:
case MSG_IDENTIFY_ENVIRON:
case MSG_IDENTIFY_FEATURES:
case MSG_IDENTIFY_FLAGS:
case MSG_IDENTIFY_LONGFLAGS:
case MSG_IDENTIFY_TERM:
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_TERM:
case MSG_IDENTIFY_TERMINFO:
case MSG_IDENTIFY_TTYNAME:
case MSG_IDENTIFY_DONE:
server_client_dispatch_identify(c, imsg);
break;
@ -2200,6 +2202,14 @@ server_client_dispatch_identify(struct client *c, struct imsg *imsg)
c->term_name = xstrdup(data);
log_debug("client %p IDENTIFY_TERM %s", c, data);
break;
case MSG_IDENTIFY_TERMINFO:
if (datalen == 0 || data[datalen - 1] != '\0')
fatalx("bad MSG_IDENTIFY_TERMINFO string");
c->term_caps = xreallocarray(c->term_caps, c->term_ncaps + 1,
sizeof *c->term_caps);
c->term_caps[c->term_ncaps++] = xstrdup(data);
log_debug("client %p IDENTIFY_TERMINFO %s", c, data);
break;
case MSG_IDENTIFY_TTYNAME:
if (datalen == 0 || data[datalen - 1] != '\0')
fatalx("bad MSG_IDENTIFY_TTYNAME string");

9
tmux.h
View File

@ -500,6 +500,7 @@ enum msgtype {
MSG_IDENTIFY_FEATURES,
MSG_IDENTIFY_STDOUT,
MSG_IDENTIFY_LONGFLAGS,
MSG_IDENTIFY_TERMINFO,
MSG_COMMAND = 200,
MSG_DETACH,
@ -1603,6 +1604,8 @@ struct client {
char *term_name;
int term_features;
char *term_type;
char **term_caps;
u_int term_ncaps;
char *ttyname;
struct tty tty;
@ -2167,8 +2170,12 @@ extern struct tty_terms tty_terms;
u_int tty_term_ncodes(void);
void tty_term_apply(struct tty_term *, const char *, int);
void tty_term_apply_overrides(struct tty_term *);
struct tty_term *tty_term_create(struct tty *, char *, int *, int, char **);
struct tty_term *tty_term_create(struct tty *, char *, char **, u_int, int *,
char **);
void tty_term_free(struct tty_term *);
int tty_term_read_list(const char *, int, char ***, u_int *,
char **);
void tty_term_free_list(char **, u_int);
int tty_term_has(struct tty_term *, enum tty_code_code);
const char *tty_term_string(struct tty_term *, enum tty_code_code);
const char *tty_term_string1(struct tty_term *, enum tty_code_code, int);

View File

@ -450,7 +450,8 @@ tty_term_apply_overrides(struct tty_term *term)
}
struct tty_term *
tty_term_create(struct tty *tty, char *name, int *feat, int fd, char **cause)
tty_term_create(struct tty *tty, char *name, char **caps, u_int ncaps,
int *feat, char **cause)
{
struct tty_term *term;
const struct tty_term_code_entry *ent;
@ -458,10 +459,9 @@ tty_term_create(struct tty *tty, char *name, int *feat, int fd, char **cause)
struct options_entry *o;
struct options_array_item *a;
union options_value *ov;
u_int i;
int n, error;
const char *s, *acs;
size_t offset;
u_int i, j;
const char *s, *acs, *value;
size_t offset, namelen;
char *first;
log_debug("adding term %s", name);
@ -472,57 +472,38 @@ tty_term_create(struct tty *tty, char *name, int *feat, int fd, char **cause)
term->codes = xcalloc(tty_term_ncodes(), sizeof *term->codes);
LIST_INSERT_HEAD(&tty_terms, term, entry);
/* Set up curses terminal. */
if (setupterm(name, fd, &error) != OK) {
switch (error) {
case 1:
xasprintf(cause, "can't use hardcopy terminal: %s",
name);
break;
case 0:
xasprintf(cause, "missing or unsuitable terminal: %s",
name);
break;
case -1:
xasprintf(cause, "can't find terminfo database");
break;
default:
xasprintf(cause, "unknown error");
break;
}
goto error;
}
/* Fill in codes. */
for (i = 0; i < tty_term_ncodes(); i++) {
ent = &tty_term_codes[i];
for (i = 0; i < ncaps; i++) {
namelen = strcspn(caps[i], "=");
if (namelen == 0)
continue;
value = caps[i] + namelen + 1;
code = &term->codes[i];
code->type = TTYCODE_NONE;
switch (ent->type) {
case TTYCODE_NONE:
break;
case TTYCODE_STRING:
s = tigetstr((char *) ent->name);
if (s == NULL || s == (char *) -1)
for (j = 0; j < tty_term_ncodes(); j++) {
ent = &tty_term_codes[j];
if (strncmp(ent->name, caps[i], namelen) != 0)
continue;
if (ent->name[namelen] != '\0')
continue;
code = &term->codes[j];
code->type = TTYCODE_NONE;
switch (ent->type) {
case TTYCODE_NONE:
break;
code->type = TTYCODE_STRING;
code->value.string = tty_term_strip(s);
break;
case TTYCODE_NUMBER:
n = tigetnum((char *) ent->name);
if (n == -1 || n == -2)
case TTYCODE_STRING:
code->type = TTYCODE_STRING;
code->value.string = tty_term_strip(value);
break;
code->type = TTYCODE_NUMBER;
code->value.number = n;
break;
case TTYCODE_FLAG:
n = tigetflag((char *) ent->name);
if (n == -1)
case TTYCODE_NUMBER:
code->type = TTYCODE_NUMBER;
code->value.number = atoi(value);
break;
code->type = TTYCODE_FLAG;
code->value.flag = n;
break;
case TTYCODE_FLAG:
code->type = TTYCODE_FLAG;
code->value.flag = (*value == '1');
break;
}
}
}
@ -643,6 +624,85 @@ tty_term_free(struct tty_term *term)
free(term);
}
int
tty_term_read_list(const char *name, int fd, char ***caps, u_int *ncaps,
char **cause)
{
const struct tty_term_code_entry *ent;
int error, n;
u_int i;
const char *s;
char tmp[11];
if (setupterm(name, fd, &error) != OK) {
switch (error) {
case 1:
xasprintf(cause, "can't use hardcopy terminal: %s",
name);
break;
case 0:
xasprintf(cause, "missing or unsuitable terminal: %s",
name);
break;
case -1:
xasprintf(cause, "can't find terminfo database");
break;
default:
xasprintf(cause, "unknown error");
break;
}
return (-1);
}
*ncaps = 0;
*caps = NULL;
for (i = 0; i < tty_term_ncodes(); i++) {
ent = &tty_term_codes[i];
switch (ent->type) {
case TTYCODE_NONE:
break;
case TTYCODE_STRING:
s = tigetstr((char *)ent->name);
if (s == NULL || s == (char *)-1)
continue;
break;
case TTYCODE_NUMBER:
n = tigetnum((char *)ent->name);
if (n == -1 || n == -2)
continue;
xsnprintf(tmp, sizeof tmp, "%d", n);
s = tmp;
break;
case TTYCODE_FLAG:
n = tigetflag((char *) ent->name);
if (n == -1)
continue;
if (n)
s = "1";
else
s = "0";
break;
}
*caps = xreallocarray(*caps, (*ncaps) + 1, sizeof **caps);
xasprintf(&(*caps)[*ncaps], "%s=%s", ent->name, s);
(*ncaps)++;
}
del_curterm(cur_term);
return (0);
}
void
tty_term_free_list(char **caps, u_int ncaps)
{
u_int i;
for (i = 0; i < ncaps; i++)
free(caps[i]);
free(caps);
}
int
tty_term_has(struct tty_term *term, enum tty_code_code code)
{

4
tty.c
View File

@ -249,8 +249,8 @@ tty_open(struct tty *tty, char **cause)
{
struct client *c = tty->client;
tty->term = tty_term_create(tty, c->term_name, &c->term_features,
c->fd, cause);
tty->term = tty_term_create(tty, c->term_name, c->term_caps,
c->term_ncaps, &c->term_features, cause);
if (tty->term == NULL) {
tty_close(tty);
return (-1);