mirror of
https://github.com/tmux/tmux.git
synced 2025-09-07 01:56:58 +00:00
Merge branch 'obsd-master' into master
This commit is contained in:
38
client.c
38
client.c
@ -61,7 +61,8 @@ static __dead void client_exec(const char *,const char *);
|
|||||||
static int client_get_lock(char *);
|
static int client_get_lock(char *);
|
||||||
static int client_connect(struct event_base *, const char *,
|
static int client_connect(struct event_base *, const char *,
|
||||||
uint64_t);
|
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_signal(int);
|
||||||
static void client_dispatch(struct imsg *, void *);
|
static void client_dispatch(struct imsg *, void *);
|
||||||
static void client_dispatch_attached(struct imsg *);
|
static void client_dispatch_attached(struct imsg *);
|
||||||
@ -234,13 +235,14 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
|
|||||||
struct cmd_parse_result *pr;
|
struct cmd_parse_result *pr;
|
||||||
struct msg_command *data;
|
struct msg_command *data;
|
||||||
int fd, i;
|
int fd, i;
|
||||||
const char *ttynam, *cwd;
|
const char *ttynam, *termname, *cwd;
|
||||||
pid_t ppid;
|
pid_t ppid;
|
||||||
enum msgtype msg;
|
enum msgtype msg;
|
||||||
struct termios tio, saved_tio;
|
struct termios tio, saved_tio;
|
||||||
size_t size, linesize = 0;
|
size_t size, linesize = 0;
|
||||||
ssize_t linelen;
|
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. */
|
/* Ignore SIGCHLD now or daemon() in the server will leave a zombie. */
|
||||||
signal(SIGCHLD, SIG_IGN);
|
signal(SIGCHLD, SIG_IGN);
|
||||||
@ -296,6 +298,8 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
|
|||||||
cwd = "/";
|
cwd = "/";
|
||||||
if ((ttynam = ttyname(STDIN_FILENO)) == NULL)
|
if ((ttynam = ttyname(STDIN_FILENO)) == NULL)
|
||||||
ttynam = "";
|
ttynam = "";
|
||||||
|
if ((termname = getenv("TERM")) == NULL)
|
||||||
|
termname = "";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Drop privileges for client. "proc exec" is needed for -c and for
|
* Drop privileges for client. "proc exec" is needed for -c and for
|
||||||
@ -311,6 +315,16 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
|
|||||||
NULL) != 0)
|
NULL) != 0)
|
||||||
fatal("pledge failed");
|
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. */
|
/* Free stuff that is not used in the client. */
|
||||||
if (ptm_fd != -1)
|
if (ptm_fd != -1)
|
||||||
close(ptm_fd);
|
close(ptm_fd);
|
||||||
@ -341,7 +355,8 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Send identify messages. */
|
/* 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. */
|
/* Send first command. */
|
||||||
if (msg == MSG_COMMAND) {
|
if (msg == MSG_COMMAND) {
|
||||||
@ -424,27 +439,32 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
|
|||||||
|
|
||||||
/* Send identify messages to server. */
|
/* Send identify messages to server. */
|
||||||
static void
|
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;
|
char **ss;
|
||||||
size_t sslen;
|
size_t sslen;
|
||||||
int fd, flags = client_flags;
|
int fd, flags = client_flags;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
u_int i;
|
||||||
|
|
||||||
proc_send(client_peer, MSG_IDENTIFY_FLAGS, -1, &flags, sizeof flags);
|
proc_send(client_peer, MSG_IDENTIFY_FLAGS, -1, &flags, sizeof flags);
|
||||||
proc_send(client_peer, MSG_IDENTIFY_LONGFLAGS, -1, &client_flags,
|
proc_send(client_peer, MSG_IDENTIFY_LONGFLAGS, -1, &client_flags,
|
||||||
sizeof client_flags);
|
sizeof client_flags);
|
||||||
|
|
||||||
if ((s = getenv("TERM")) == NULL)
|
proc_send(client_peer, MSG_IDENTIFY_TERM, -1, termname,
|
||||||
s = "";
|
strlen(termname) + 1);
|
||||||
proc_send(client_peer, MSG_IDENTIFY_TERM, -1, s, strlen(s) + 1);
|
|
||||||
proc_send(client_peer, MSG_IDENTIFY_FEATURES, -1, &feat, sizeof feat);
|
proc_send(client_peer, MSG_IDENTIFY_FEATURES, -1, &feat, sizeof feat);
|
||||||
|
|
||||||
proc_send(client_peer, MSG_IDENTIFY_TTYNAME, -1, ttynam,
|
proc_send(client_peer, MSG_IDENTIFY_TTYNAME, -1, ttynam,
|
||||||
strlen(ttynam) + 1);
|
strlen(ttynam) + 1);
|
||||||
proc_send(client_peer, MSG_IDENTIFY_CWD, -1, cwd, strlen(cwd) + 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)
|
if ((fd = dup(STDIN_FILENO)) == -1)
|
||||||
fatal("dup failed");
|
fatal("dup failed");
|
||||||
proc_send(client_peer, MSG_IDENTIFY_STDIN, fd, NULL, 0);
|
proc_send(client_peer, MSG_IDENTIFY_STDIN, fd, NULL, 0);
|
||||||
|
@ -304,6 +304,7 @@ server_client_lost(struct client *c)
|
|||||||
|
|
||||||
free(c->term_name);
|
free(c->term_name);
|
||||||
free(c->term_type);
|
free(c->term_type);
|
||||||
|
tty_term_free_list(c->term_caps, c->term_ncaps);
|
||||||
|
|
||||||
status_free(c);
|
status_free(c);
|
||||||
|
|
||||||
@ -1994,16 +1995,17 @@ server_client_dispatch(struct imsg *imsg, void *arg)
|
|||||||
datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
|
datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
|
||||||
|
|
||||||
switch (imsg->hdr.type) {
|
switch (imsg->hdr.type) {
|
||||||
|
case MSG_IDENTIFY_CLIENTPID:
|
||||||
|
case MSG_IDENTIFY_CWD:
|
||||||
|
case MSG_IDENTIFY_ENVIRON:
|
||||||
case MSG_IDENTIFY_FEATURES:
|
case MSG_IDENTIFY_FEATURES:
|
||||||
case MSG_IDENTIFY_FLAGS:
|
case MSG_IDENTIFY_FLAGS:
|
||||||
case MSG_IDENTIFY_LONGFLAGS:
|
case MSG_IDENTIFY_LONGFLAGS:
|
||||||
case MSG_IDENTIFY_TERM:
|
|
||||||
case MSG_IDENTIFY_TTYNAME:
|
|
||||||
case MSG_IDENTIFY_CWD:
|
|
||||||
case MSG_IDENTIFY_STDIN:
|
case MSG_IDENTIFY_STDIN:
|
||||||
case MSG_IDENTIFY_STDOUT:
|
case MSG_IDENTIFY_STDOUT:
|
||||||
case MSG_IDENTIFY_ENVIRON:
|
case MSG_IDENTIFY_TERM:
|
||||||
case MSG_IDENTIFY_CLIENTPID:
|
case MSG_IDENTIFY_TERMINFO:
|
||||||
|
case MSG_IDENTIFY_TTYNAME:
|
||||||
case MSG_IDENTIFY_DONE:
|
case MSG_IDENTIFY_DONE:
|
||||||
server_client_dispatch_identify(c, imsg);
|
server_client_dispatch_identify(c, imsg);
|
||||||
break;
|
break;
|
||||||
@ -2197,6 +2199,14 @@ server_client_dispatch_identify(struct client *c, struct imsg *imsg)
|
|||||||
c->term_name = xstrdup(data);
|
c->term_name = xstrdup(data);
|
||||||
log_debug("client %p IDENTIFY_TERM %s", c, data);
|
log_debug("client %p IDENTIFY_TERM %s", c, data);
|
||||||
break;
|
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:
|
case MSG_IDENTIFY_TTYNAME:
|
||||||
if (datalen == 0 || data[datalen - 1] != '\0')
|
if (datalen == 0 || data[datalen - 1] != '\0')
|
||||||
fatalx("bad MSG_IDENTIFY_TTYNAME string");
|
fatalx("bad MSG_IDENTIFY_TTYNAME string");
|
||||||
|
9
tmux.h
9
tmux.h
@ -501,6 +501,7 @@ enum msgtype {
|
|||||||
MSG_IDENTIFY_FEATURES,
|
MSG_IDENTIFY_FEATURES,
|
||||||
MSG_IDENTIFY_STDOUT,
|
MSG_IDENTIFY_STDOUT,
|
||||||
MSG_IDENTIFY_LONGFLAGS,
|
MSG_IDENTIFY_LONGFLAGS,
|
||||||
|
MSG_IDENTIFY_TERMINFO,
|
||||||
|
|
||||||
MSG_COMMAND = 200,
|
MSG_COMMAND = 200,
|
||||||
MSG_DETACH,
|
MSG_DETACH,
|
||||||
@ -1604,6 +1605,8 @@ struct client {
|
|||||||
char *term_name;
|
char *term_name;
|
||||||
int term_features;
|
int term_features;
|
||||||
char *term_type;
|
char *term_type;
|
||||||
|
char **term_caps;
|
||||||
|
u_int term_ncaps;
|
||||||
|
|
||||||
char *ttyname;
|
char *ttyname;
|
||||||
struct tty tty;
|
struct tty tty;
|
||||||
@ -2168,8 +2171,12 @@ extern struct tty_terms tty_terms;
|
|||||||
u_int tty_term_ncodes(void);
|
u_int tty_term_ncodes(void);
|
||||||
void tty_term_apply(struct tty_term *, const char *, int);
|
void tty_term_apply(struct tty_term *, const char *, int);
|
||||||
void tty_term_apply_overrides(struct tty_term *);
|
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 *);
|
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);
|
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_string(struct tty_term *, enum tty_code_code);
|
||||||
const char *tty_term_string1(struct tty_term *, enum tty_code_code, int);
|
const char *tty_term_string1(struct tty_term *, enum tty_code_code, int);
|
||||||
|
142
tty-term.c
142
tty-term.c
@ -453,7 +453,8 @@ tty_term_apply_overrides(struct tty_term *term)
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct tty_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;
|
struct tty_term *term;
|
||||||
const struct tty_term_code_entry *ent;
|
const struct tty_term_code_entry *ent;
|
||||||
@ -461,10 +462,9 @@ tty_term_create(struct tty *tty, char *name, int *feat, int fd, char **cause)
|
|||||||
struct options_entry *o;
|
struct options_entry *o;
|
||||||
struct options_array_item *a;
|
struct options_array_item *a;
|
||||||
union options_value *ov;
|
union options_value *ov;
|
||||||
u_int i;
|
u_int i, j;
|
||||||
int n, error;
|
const char *s, *acs, *value;
|
||||||
const char *s, *acs;
|
size_t offset, namelen;
|
||||||
size_t offset;
|
|
||||||
char *first;
|
char *first;
|
||||||
|
|
||||||
log_debug("adding term %s", name);
|
log_debug("adding term %s", name);
|
||||||
@ -475,59 +475,40 @@ tty_term_create(struct tty *tty, char *name, int *feat, int fd, char **cause)
|
|||||||
term->codes = xcalloc(tty_term_ncodes(), sizeof *term->codes);
|
term->codes = xcalloc(tty_term_ncodes(), sizeof *term->codes);
|
||||||
LIST_INSERT_HEAD(&tty_terms, term, entry);
|
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. */
|
/* Fill in codes. */
|
||||||
for (i = 0; i < tty_term_ncodes(); i++) {
|
for (i = 0; i < ncaps; i++) {
|
||||||
ent = &tty_term_codes[i];
|
namelen = strcspn(caps[i], "=");
|
||||||
|
if (namelen == 0)
|
||||||
|
continue;
|
||||||
|
value = caps[i] + namelen + 1;
|
||||||
|
|
||||||
code = &term->codes[i];
|
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;
|
code->type = TTYCODE_NONE;
|
||||||
switch (ent->type) {
|
switch (ent->type) {
|
||||||
case TTYCODE_NONE:
|
case TTYCODE_NONE:
|
||||||
break;
|
break;
|
||||||
case TTYCODE_STRING:
|
case TTYCODE_STRING:
|
||||||
s = tigetstr((char *) ent->name);
|
|
||||||
if (s == NULL || s == (char *) -1)
|
|
||||||
break;
|
|
||||||
code->type = TTYCODE_STRING;
|
code->type = TTYCODE_STRING;
|
||||||
code->value.string = tty_term_strip(s);
|
code->value.string = tty_term_strip(value);
|
||||||
break;
|
break;
|
||||||
case TTYCODE_NUMBER:
|
case TTYCODE_NUMBER:
|
||||||
n = tigetnum((char *) ent->name);
|
|
||||||
if (n == -1 || n == -2)
|
|
||||||
break;
|
|
||||||
code->type = TTYCODE_NUMBER;
|
code->type = TTYCODE_NUMBER;
|
||||||
code->value.number = n;
|
code->value.number = atoi(value);
|
||||||
break;
|
break;
|
||||||
case TTYCODE_FLAG:
|
case TTYCODE_FLAG:
|
||||||
n = tigetflag((char *) ent->name);
|
|
||||||
if (n == -1)
|
|
||||||
break;
|
|
||||||
code->type = TTYCODE_FLAG;
|
code->type = TTYCODE_FLAG;
|
||||||
code->value.flag = n;
|
code->value.flag = (*value == '1');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Apply terminal features. */
|
/* Apply terminal features. */
|
||||||
o = options_get_only(global_options, "terminal-features");
|
o = options_get_only(global_options, "terminal-features");
|
||||||
@ -649,6 +630,85 @@ tty_term_free(struct tty_term *term)
|
|||||||
free(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
|
int
|
||||||
tty_term_has(struct tty_term *term, enum tty_code_code code)
|
tty_term_has(struct tty_term *term, enum tty_code_code code)
|
||||||
{
|
{
|
||||||
|
4
tty.c
4
tty.c
@ -249,8 +249,8 @@ tty_open(struct tty *tty, char **cause)
|
|||||||
{
|
{
|
||||||
struct client *c = tty->client;
|
struct client *c = tty->client;
|
||||||
|
|
||||||
tty->term = tty_term_create(tty, c->term_name, &c->term_features,
|
tty->term = tty_term_create(tty, c->term_name, c->term_caps,
|
||||||
c->fd, cause);
|
c->term_ncaps, &c->term_features, cause);
|
||||||
if (tty->term == NULL) {
|
if (tty->term == NULL) {
|
||||||
tty_close(tty);
|
tty_close(tty);
|
||||||
return (-1);
|
return (-1);
|
||||||
|
Reference in New Issue
Block a user