mirror of
https://github.com/tmux/tmux.git
synced 2025-01-14 12:48:56 +00:00
Break the common process set up, event loop and imsg dispatch code
between server and client out into a separate internal API. This will make it easier to add another process.
This commit is contained in:
parent
9952201ca7
commit
07b0ea03c3
1
Makefile
1
Makefile
@ -94,6 +94,7 @@ SRCS= alerts.c \
|
||||
options-table.c \
|
||||
options.c \
|
||||
paste.c \
|
||||
proc.c \
|
||||
procname.c \
|
||||
resize.c \
|
||||
screen-redraw.c \
|
||||
|
509
client.c
509
client.c
@ -26,6 +26,7 @@
|
||||
#include <errno.h>
|
||||
#include <event.h>
|
||||
#include <fcntl.h>
|
||||
#include <imsg.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -33,10 +34,10 @@
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
int client_flags;
|
||||
struct imsgbuf client_ibuf;
|
||||
struct event client_event;
|
||||
struct event client_stdin;
|
||||
struct tmuxproc *client_proc;
|
||||
struct tmuxpeer *client_peer;
|
||||
int client_flags;
|
||||
struct event client_stdin;
|
||||
enum {
|
||||
CLIENT_EXIT_NONE,
|
||||
CLIENT_EXIT_DETACHED,
|
||||
@ -47,24 +48,21 @@ enum {
|
||||
CLIENT_EXIT_EXITED,
|
||||
CLIENT_EXIT_SERVER_EXITED,
|
||||
} client_exitreason = CLIENT_EXIT_NONE;
|
||||
int client_exitval;
|
||||
enum msgtype client_exittype;
|
||||
const char *client_exitsession;
|
||||
int client_attached;
|
||||
int client_exitval;
|
||||
enum msgtype client_exittype;
|
||||
const char *client_exitsession;
|
||||
int client_attached;
|
||||
|
||||
__dead void client_exec(const char *);
|
||||
int client_get_lock(char *);
|
||||
int client_connect(struct event_base *, char *, int);
|
||||
void client_send_identify(const char *, const char *);
|
||||
int client_write_one(enum msgtype, int, const void *, size_t);
|
||||
int client_write_server(enum msgtype, const void *, size_t);
|
||||
void client_update_event(void);
|
||||
void client_signal(int, short, void *);
|
||||
void client_stdin_callback(int, short, void *);
|
||||
void client_write(int, const char *, size_t);
|
||||
void client_callback(int, short, void *);
|
||||
int client_dispatch_attached(void);
|
||||
int client_dispatch_wait(void);
|
||||
void client_signal(int);
|
||||
void client_dispatch(struct imsg *, void *);
|
||||
void client_dispatch_attached(struct imsg *);
|
||||
void client_dispatch_wait(struct imsg *);
|
||||
const char *client_exit_message(void);
|
||||
|
||||
/*
|
||||
@ -222,6 +220,9 @@ client_main(struct event_base *base, int argc, char **argv, int flags)
|
||||
struct termios tio, saved_tio;
|
||||
size_t size;
|
||||
|
||||
/* Ignore SIGCHLD now or daemon() in the server will leave a zombie. */
|
||||
signal(SIGCHLD, SIG_IGN);
|
||||
|
||||
/* Save the flags. */
|
||||
client_flags = flags;
|
||||
|
||||
@ -254,13 +255,6 @@ client_main(struct event_base *base, int argc, char **argv, int flags)
|
||||
cmd_list_free(cmdlist);
|
||||
}
|
||||
|
||||
/* Set process title, log and signals now this is the client. */
|
||||
setproctitle("client (%s)", socket_path);
|
||||
logfile("client");
|
||||
|
||||
/* Establish signal handlers. */
|
||||
set_signals(client_signal);
|
||||
|
||||
/* Initialize the client socket and start the server. */
|
||||
fd = client_connect(base, socket_path, cmdflags & CMD_STARTSERVER);
|
||||
if (fd == -1) {
|
||||
@ -274,6 +268,10 @@ client_main(struct event_base *base, int argc, char **argv, int flags)
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Build process state. */
|
||||
client_proc = proc_start("client", base, 0, client_signal);
|
||||
client_peer = proc_add_peer(client_proc, fd, client_dispatch, NULL);
|
||||
|
||||
/* Save these before pledge(). */
|
||||
if ((cwd = getcwd(path, sizeof path)) == NULL)
|
||||
cwd = "/";
|
||||
@ -298,10 +296,6 @@ client_main(struct event_base *base, int argc, char **argv, int flags)
|
||||
options_free(&global_w_options);
|
||||
environ_free(&global_environ);
|
||||
|
||||
/* Create imsg. */
|
||||
imsg_init(&client_ibuf, fd);
|
||||
event_set(&client_event, fd, EV_READ, client_callback, NULL);
|
||||
|
||||
/* Create stdin handler. */
|
||||
setblocking(STDIN_FILENO, 0);
|
||||
event_set(&client_stdin, STDIN_FILENO, EV_READ|EV_PERSIST,
|
||||
@ -345,18 +339,17 @@ client_main(struct event_base *base, int argc, char **argv, int flags)
|
||||
size += sizeof *data;
|
||||
|
||||
/* Send the command. */
|
||||
if (client_write_server(msg, data, size) != 0) {
|
||||
if (proc_send(client_peer, msg, -1, data, size) != 0) {
|
||||
fprintf(stderr, "failed to send command\n");
|
||||
free(data);
|
||||
return (1);
|
||||
}
|
||||
free(data);
|
||||
} else if (msg == MSG_SHELL)
|
||||
client_write_server(msg, NULL, 0);
|
||||
proc_send(client_peer, msg, -1, NULL, 0);
|
||||
|
||||
/* Set the event and dispatch. */
|
||||
client_update_event();
|
||||
event_dispatch();
|
||||
/* Start main loop. */
|
||||
proc_loop(client_proc, NULL);
|
||||
|
||||
/* Print the exit message, if any, and exit. */
|
||||
if (client_attached) {
|
||||
@ -388,144 +381,29 @@ client_send_identify(const char *ttynam, const char *cwd)
|
||||
int fd, flags = client_flags;
|
||||
pid_t pid;
|
||||
|
||||
client_write_one(MSG_IDENTIFY_FLAGS, -1, &flags, sizeof flags);
|
||||
proc_send(client_peer, MSG_IDENTIFY_FLAGS, -1, &flags, sizeof flags);
|
||||
|
||||
if ((s = getenv("TERM")) == NULL)
|
||||
s = "";
|
||||
client_write_one(MSG_IDENTIFY_TERM, -1, s, strlen(s) + 1);
|
||||
proc_send(client_peer, MSG_IDENTIFY_TERM, -1, s, strlen(s) + 1);
|
||||
|
||||
client_write_one(MSG_IDENTIFY_TTYNAME, -1, ttynam, strlen(ttynam) + 1);
|
||||
client_write_one(MSG_IDENTIFY_CWD, -1, cwd, strlen(cwd) + 1);
|
||||
proc_send(client_peer, MSG_IDENTIFY_TTYNAME, -1, ttynam, strlen(ttynam) + 1);
|
||||
proc_send(client_peer, MSG_IDENTIFY_CWD, -1, cwd, strlen(cwd) + 1);
|
||||
|
||||
if ((fd = dup(STDIN_FILENO)) == -1)
|
||||
fatal("dup failed");
|
||||
client_write_one(MSG_IDENTIFY_STDIN, fd, NULL, 0);
|
||||
proc_send(client_peer, MSG_IDENTIFY_STDIN, fd, NULL, 0);
|
||||
|
||||
pid = getpid();
|
||||
client_write_one(MSG_IDENTIFY_CLIENTPID, -1, &pid, sizeof pid);
|
||||
proc_send(client_peer, MSG_IDENTIFY_CLIENTPID, -1, &pid, sizeof pid);
|
||||
|
||||
for (ss = environ; *ss != NULL; ss++) {
|
||||
sslen = strlen(*ss) + 1;
|
||||
if (sslen <= MAX_IMSGSIZE - IMSG_HEADER_SIZE)
|
||||
client_write_one(MSG_IDENTIFY_ENVIRON, -1, *ss, sslen);
|
||||
proc_send(client_peer, MSG_IDENTIFY_ENVIRON, -1, *ss, sslen);
|
||||
}
|
||||
|
||||
client_write_one(MSG_IDENTIFY_DONE, -1, NULL, 0);
|
||||
}
|
||||
|
||||
/* Helper to send one message. */
|
||||
int
|
||||
client_write_one(enum msgtype type, int fd, const void *buf, size_t len)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = imsg_compose(&client_ibuf, type, PROTOCOL_VERSION, -1, fd,
|
||||
(void *)buf, len);
|
||||
if (retval != 1)
|
||||
return (-1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Write a message to the server without a file descriptor. */
|
||||
int
|
||||
client_write_server(enum msgtype type, const void *buf, size_t len)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = client_write_one(type, -1, buf, len);
|
||||
if (retval == 0)
|
||||
client_update_event();
|
||||
return (retval);
|
||||
}
|
||||
|
||||
/* Update client event based on whether it needs to read or read and write. */
|
||||
void
|
||||
client_update_event(void)
|
||||
{
|
||||
short events;
|
||||
|
||||
event_del(&client_event);
|
||||
events = EV_READ;
|
||||
if (client_ibuf.w.queued > 0)
|
||||
events |= EV_WRITE;
|
||||
event_set(&client_event, client_ibuf.fd, events, client_callback, NULL);
|
||||
event_add(&client_event, NULL);
|
||||
}
|
||||
|
||||
/* Callback to handle signals in the client. */
|
||||
void
|
||||
client_signal(int sig, unused short events, unused void *arg)
|
||||
{
|
||||
struct sigaction sigact;
|
||||
int status;
|
||||
|
||||
if (sig == SIGCHLD)
|
||||
waitpid(WAIT_ANY, &status, WNOHANG);
|
||||
else if (!client_attached) {
|
||||
if (sig == SIGTERM)
|
||||
event_loopexit(NULL);
|
||||
} else {
|
||||
switch (sig) {
|
||||
case SIGHUP:
|
||||
client_exitreason = CLIENT_EXIT_LOST_TTY;
|
||||
client_exitval = 1;
|
||||
client_write_server(MSG_EXITING, NULL, 0);
|
||||
break;
|
||||
case SIGTERM:
|
||||
client_exitreason = CLIENT_EXIT_TERMINATED;
|
||||
client_exitval = 1;
|
||||
client_write_server(MSG_EXITING, NULL, 0);
|
||||
break;
|
||||
case SIGWINCH:
|
||||
client_write_server(MSG_RESIZE, NULL, 0);
|
||||
break;
|
||||
case SIGCONT:
|
||||
memset(&sigact, 0, sizeof sigact);
|
||||
sigemptyset(&sigact.sa_mask);
|
||||
sigact.sa_flags = SA_RESTART;
|
||||
sigact.sa_handler = SIG_IGN;
|
||||
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
client_write_server(MSG_WAKEUP, NULL, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
client_update_event();
|
||||
}
|
||||
|
||||
/* Callback for client imsg read events. */
|
||||
void
|
||||
client_callback(unused int fd, short events, unused void *arg)
|
||||
{
|
||||
ssize_t n;
|
||||
int retval;
|
||||
|
||||
if (events & EV_READ) {
|
||||
if ((n = imsg_read(&client_ibuf)) == -1 || n == 0)
|
||||
goto lost_server;
|
||||
if (client_attached)
|
||||
retval = client_dispatch_attached();
|
||||
else
|
||||
retval = client_dispatch_wait();
|
||||
if (retval != 0) {
|
||||
event_loopexit(NULL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (events & EV_WRITE) {
|
||||
if (msgbuf_write(&client_ibuf.w) <= 0 && errno != EAGAIN)
|
||||
goto lost_server;
|
||||
}
|
||||
|
||||
client_update_event();
|
||||
return;
|
||||
|
||||
lost_server:
|
||||
client_exitreason = CLIENT_EXIT_LOST_SERVER;
|
||||
client_exitval = 1;
|
||||
event_loopexit(NULL);
|
||||
proc_send(client_peer, MSG_IDENTIFY_DONE, -1, NULL, 0);
|
||||
}
|
||||
|
||||
/* Callback for client stdin read events. */
|
||||
@ -538,10 +416,9 @@ client_stdin_callback(unused int fd, unused short events, unused void *arg)
|
||||
if (data.size < 0 && (errno == EINTR || errno == EAGAIN))
|
||||
return;
|
||||
|
||||
client_write_server(MSG_STDIN, &data, sizeof data);
|
||||
proc_send(client_peer, MSG_STDIN, -1, &data, sizeof data);
|
||||
if (data.size <= 0)
|
||||
event_del(&client_stdin);
|
||||
client_update_event();
|
||||
}
|
||||
|
||||
/* Force write to file descriptor. */
|
||||
@ -591,13 +468,65 @@ client_exec(const char *shell)
|
||||
fatal("execl failed");
|
||||
}
|
||||
|
||||
/* Dispatch imsgs when in wait state (before MSG_READY). */
|
||||
int
|
||||
client_dispatch_wait(void)
|
||||
/* Callback to handle signals in the client. */
|
||||
void
|
||||
client_signal(int sig)
|
||||
{
|
||||
struct sigaction sigact;
|
||||
int status;
|
||||
|
||||
if (sig == SIGCHLD)
|
||||
waitpid(WAIT_ANY, &status, WNOHANG);
|
||||
else if (!client_attached) {
|
||||
if (sig == SIGTERM)
|
||||
proc_exit(client_proc);
|
||||
} else {
|
||||
switch (sig) {
|
||||
case SIGHUP:
|
||||
client_exitreason = CLIENT_EXIT_LOST_TTY;
|
||||
client_exitval = 1;
|
||||
proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
|
||||
break;
|
||||
case SIGTERM:
|
||||
client_exitreason = CLIENT_EXIT_TERMINATED;
|
||||
client_exitval = 1;
|
||||
proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
|
||||
break;
|
||||
case SIGWINCH:
|
||||
proc_send(client_peer, MSG_RESIZE, -1, NULL, 0);
|
||||
break;
|
||||
case SIGCONT:
|
||||
memset(&sigact, 0, sizeof sigact);
|
||||
sigemptyset(&sigact.sa_mask);
|
||||
sigact.sa_flags = SA_RESTART;
|
||||
sigact.sa_handler = SIG_IGN;
|
||||
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
proc_send(client_peer, MSG_WAKEUP, -1, NULL, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Callback for client read events. */
|
||||
void
|
||||
client_dispatch(struct imsg *imsg, unused void *arg)
|
||||
{
|
||||
if (imsg == NULL) {
|
||||
client_exitreason = CLIENT_EXIT_LOST_SERVER;
|
||||
client_exitval = 1;
|
||||
} else if (client_attached)
|
||||
client_dispatch_attached(imsg);
|
||||
else
|
||||
client_dispatch_wait(imsg);
|
||||
}
|
||||
|
||||
/* Dispatch imsgs when in wait state (before MSG_READY). */
|
||||
void
|
||||
client_dispatch_wait(struct imsg *imsg)
|
||||
{
|
||||
struct imsg imsg;
|
||||
char *data;
|
||||
ssize_t n, datalen;
|
||||
ssize_t datalen;
|
||||
struct msg_stdout_data stdoutdata;
|
||||
struct msg_stderr_data stderrdata;
|
||||
int retval;
|
||||
@ -615,163 +544,141 @@ client_dispatch_wait(void)
|
||||
pledge_applied = 1;
|
||||
};
|
||||
|
||||
for (;;) {
|
||||
if ((n = imsg_get(&client_ibuf, &imsg)) == -1)
|
||||
fatalx("imsg_get failed");
|
||||
if (n == 0)
|
||||
return (0);
|
||||
data = imsg->data;
|
||||
datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
|
||||
|
||||
data = imsg.data;
|
||||
datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
|
||||
|
||||
log_debug("got %u from server", imsg.hdr.type);
|
||||
switch (imsg.hdr.type) {
|
||||
case MSG_EXIT:
|
||||
case MSG_SHUTDOWN:
|
||||
if (datalen != sizeof retval && datalen != 0)
|
||||
fatalx("bad MSG_EXIT size");
|
||||
if (datalen == sizeof retval) {
|
||||
memcpy(&retval, data, sizeof retval);
|
||||
client_exitval = retval;
|
||||
}
|
||||
imsg_free(&imsg);
|
||||
return (-1);
|
||||
case MSG_READY:
|
||||
if (datalen != 0)
|
||||
fatalx("bad MSG_READY size");
|
||||
|
||||
event_del(&client_stdin);
|
||||
client_attached = 1;
|
||||
client_write_server(MSG_RESIZE, NULL, 0);
|
||||
break;
|
||||
case MSG_STDIN:
|
||||
if (datalen != 0)
|
||||
fatalx("bad MSG_STDIN size");
|
||||
|
||||
event_add(&client_stdin, NULL);
|
||||
break;
|
||||
case MSG_STDOUT:
|
||||
if (datalen != sizeof stdoutdata)
|
||||
fatalx("bad MSG_STDOUT size");
|
||||
memcpy(&stdoutdata, data, sizeof stdoutdata);
|
||||
|
||||
client_write(STDOUT_FILENO, stdoutdata.data,
|
||||
stdoutdata.size);
|
||||
break;
|
||||
case MSG_STDERR:
|
||||
if (datalen != sizeof stderrdata)
|
||||
fatalx("bad MSG_STDERR size");
|
||||
memcpy(&stderrdata, data, sizeof stderrdata);
|
||||
|
||||
client_write(STDERR_FILENO, stderrdata.data,
|
||||
stderrdata.size);
|
||||
break;
|
||||
case MSG_VERSION:
|
||||
if (datalen != 0)
|
||||
fatalx("bad MSG_VERSION size");
|
||||
|
||||
fprintf(stderr, "protocol version mismatch "
|
||||
"(client %d, server %u)\n", PROTOCOL_VERSION,
|
||||
imsg.hdr.peerid);
|
||||
client_exitval = 1;
|
||||
|
||||
imsg_free(&imsg);
|
||||
return (-1);
|
||||
case MSG_SHELL:
|
||||
if (datalen == 0 || data[datalen - 1] != '\0')
|
||||
fatalx("bad MSG_SHELL string");
|
||||
|
||||
clear_signals(0);
|
||||
client_exec(data);
|
||||
/* NOTREACHED */
|
||||
case MSG_DETACH:
|
||||
case MSG_DETACHKILL:
|
||||
client_write_server(MSG_EXITING, NULL, 0);
|
||||
break;
|
||||
case MSG_EXITED:
|
||||
imsg_free(&imsg);
|
||||
return (-1);
|
||||
switch (imsg->hdr.type) {
|
||||
case MSG_EXIT:
|
||||
case MSG_SHUTDOWN:
|
||||
if (datalen != sizeof retval && datalen != 0)
|
||||
fatalx("bad MSG_EXIT size");
|
||||
if (datalen == sizeof retval) {
|
||||
memcpy(&retval, data, sizeof retval);
|
||||
client_exitval = retval;
|
||||
}
|
||||
proc_exit(client_proc);
|
||||
break;
|
||||
case MSG_READY:
|
||||
if (datalen != 0)
|
||||
fatalx("bad MSG_READY size");
|
||||
|
||||
imsg_free(&imsg);
|
||||
event_del(&client_stdin);
|
||||
client_attached = 1;
|
||||
proc_send(client_peer, MSG_RESIZE, -1, NULL, 0);
|
||||
break;
|
||||
case MSG_STDIN:
|
||||
if (datalen != 0)
|
||||
fatalx("bad MSG_STDIN size");
|
||||
|
||||
event_add(&client_stdin, NULL);
|
||||
break;
|
||||
case MSG_STDOUT:
|
||||
if (datalen != sizeof stdoutdata)
|
||||
fatalx("bad MSG_STDOUT size");
|
||||
memcpy(&stdoutdata, data, sizeof stdoutdata);
|
||||
|
||||
client_write(STDOUT_FILENO, stdoutdata.data,
|
||||
stdoutdata.size);
|
||||
break;
|
||||
case MSG_STDERR:
|
||||
if (datalen != sizeof stderrdata)
|
||||
fatalx("bad MSG_STDERR size");
|
||||
memcpy(&stderrdata, data, sizeof stderrdata);
|
||||
|
||||
client_write(STDERR_FILENO, stderrdata.data,
|
||||
stderrdata.size);
|
||||
break;
|
||||
case MSG_VERSION:
|
||||
if (datalen != 0)
|
||||
fatalx("bad MSG_VERSION size");
|
||||
|
||||
fprintf(stderr, "protocol version mismatch "
|
||||
"(client %d, server %u)\n", PROTOCOL_VERSION,
|
||||
imsg->hdr.peerid);
|
||||
client_exitval = 1;
|
||||
proc_exit(client_proc);
|
||||
break;
|
||||
case MSG_SHELL:
|
||||
if (datalen == 0 || data[datalen - 1] != '\0')
|
||||
fatalx("bad MSG_SHELL string");
|
||||
|
||||
clear_signals(0);
|
||||
client_exec(data);
|
||||
/* NOTREACHED */
|
||||
case MSG_DETACH:
|
||||
case MSG_DETACHKILL:
|
||||
proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
|
||||
break;
|
||||
case MSG_EXITED:
|
||||
proc_exit(client_proc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Dispatch imsgs in attached state (after MSG_READY). */
|
||||
int
|
||||
client_dispatch_attached(void)
|
||||
void
|
||||
client_dispatch_attached(struct imsg *imsg)
|
||||
{
|
||||
struct imsg imsg;
|
||||
struct sigaction sigact;
|
||||
char *data;
|
||||
ssize_t n, datalen;
|
||||
ssize_t datalen;
|
||||
|
||||
for (;;) {
|
||||
if ((n = imsg_get(&client_ibuf, &imsg)) == -1)
|
||||
fatalx("imsg_get failed");
|
||||
if (n == 0)
|
||||
return (0);
|
||||
data = imsg->data;
|
||||
datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
|
||||
|
||||
data = imsg.data;
|
||||
datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
|
||||
switch (imsg->hdr.type) {
|
||||
case MSG_DETACH:
|
||||
case MSG_DETACHKILL:
|
||||
if (datalen == 0 || data[datalen - 1] != '\0')
|
||||
fatalx("bad MSG_DETACH string");
|
||||
|
||||
log_debug("got %u from server", imsg.hdr.type);
|
||||
switch (imsg.hdr.type) {
|
||||
case MSG_DETACH:
|
||||
case MSG_DETACHKILL:
|
||||
if (datalen == 0 || data[datalen - 1] != '\0')
|
||||
fatalx("bad MSG_DETACH string");
|
||||
client_exitsession = xstrdup(data);
|
||||
client_exittype = imsg->hdr.type;
|
||||
if (imsg->hdr.type == MSG_DETACHKILL)
|
||||
client_exitreason = CLIENT_EXIT_DETACHED_HUP;
|
||||
else
|
||||
client_exitreason = CLIENT_EXIT_DETACHED;
|
||||
proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
|
||||
break;
|
||||
case MSG_EXIT:
|
||||
if (datalen != 0 && datalen != sizeof (int))
|
||||
fatalx("bad MSG_EXIT size");
|
||||
|
||||
client_exitsession = xstrdup(data);
|
||||
client_exittype = imsg.hdr.type;
|
||||
if (imsg.hdr.type == MSG_DETACHKILL)
|
||||
client_exitreason = CLIENT_EXIT_DETACHED_HUP;
|
||||
else
|
||||
client_exitreason = CLIENT_EXIT_DETACHED;
|
||||
client_write_server(MSG_EXITING, NULL, 0);
|
||||
break;
|
||||
case MSG_EXIT:
|
||||
if (datalen != 0 && datalen != sizeof (int))
|
||||
fatalx("bad MSG_EXIT size");
|
||||
proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
|
||||
client_exitreason = CLIENT_EXIT_EXITED;
|
||||
break;
|
||||
case MSG_EXITED:
|
||||
if (datalen != 0)
|
||||
fatalx("bad MSG_EXITED size");
|
||||
|
||||
client_write_server(MSG_EXITING, NULL, 0);
|
||||
client_exitreason = CLIENT_EXIT_EXITED;
|
||||
break;
|
||||
case MSG_EXITED:
|
||||
if (datalen != 0)
|
||||
fatalx("bad MSG_EXITED size");
|
||||
proc_exit(client_proc);
|
||||
break;
|
||||
case MSG_SHUTDOWN:
|
||||
if (datalen != 0)
|
||||
fatalx("bad MSG_SHUTDOWN size");
|
||||
|
||||
imsg_free(&imsg);
|
||||
return (-1);
|
||||
case MSG_SHUTDOWN:
|
||||
if (datalen != 0)
|
||||
fatalx("bad MSG_SHUTDOWN size");
|
||||
proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
|
||||
client_exitreason = CLIENT_EXIT_SERVER_EXITED;
|
||||
client_exitval = 1;
|
||||
break;
|
||||
case MSG_SUSPEND:
|
||||
if (datalen != 0)
|
||||
fatalx("bad MSG_SUSPEND size");
|
||||
|
||||
client_write_server(MSG_EXITING, NULL, 0);
|
||||
client_exitreason = CLIENT_EXIT_SERVER_EXITED;
|
||||
client_exitval = 1;
|
||||
break;
|
||||
case MSG_SUSPEND:
|
||||
if (datalen != 0)
|
||||
fatalx("bad MSG_SUSPEND size");
|
||||
memset(&sigact, 0, sizeof sigact);
|
||||
sigemptyset(&sigact.sa_mask);
|
||||
sigact.sa_flags = SA_RESTART;
|
||||
sigact.sa_handler = SIG_DFL;
|
||||
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
kill(getpid(), SIGTSTP);
|
||||
break;
|
||||
case MSG_LOCK:
|
||||
if (datalen == 0 || data[datalen - 1] != '\0')
|
||||
fatalx("bad MSG_LOCK string");
|
||||
|
||||
memset(&sigact, 0, sizeof sigact);
|
||||
sigemptyset(&sigact.sa_mask);
|
||||
sigact.sa_flags = SA_RESTART;
|
||||
sigact.sa_handler = SIG_DFL;
|
||||
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
kill(getpid(), SIGTSTP);
|
||||
break;
|
||||
case MSG_LOCK:
|
||||
if (datalen == 0 || data[datalen - 1] != '\0')
|
||||
fatalx("bad MSG_LOCK string");
|
||||
|
||||
system(data);
|
||||
client_write_server(MSG_UNLOCK, NULL, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
imsg_free(&imsg);
|
||||
system(data);
|
||||
proc_send(client_peer, MSG_UNLOCK, -1, NULL, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -113,16 +113,10 @@ cmd_attach_session(struct cmd_q *cmdq, const char *tflag, int dflag, int rflag,
|
||||
|
||||
if (c->session != NULL) {
|
||||
if (dflag) {
|
||||
/*
|
||||
* Can't use server_write_session in case attaching to
|
||||
* the same session as currently attached to.
|
||||
*/
|
||||
TAILQ_FOREACH(c_loop, &clients, entry) {
|
||||
if (c_loop->session != s || c == c_loop)
|
||||
continue;
|
||||
server_write_client(c, MSG_DETACH,
|
||||
c_loop->session->name,
|
||||
strlen(c_loop->session->name) + 1);
|
||||
proc_send_s(c->peer, MSG_DETACH, s->name);
|
||||
}
|
||||
}
|
||||
|
||||
@ -150,8 +144,11 @@ cmd_attach_session(struct cmd_q *cmdq, const char *tflag, int dflag, int rflag,
|
||||
c->flags |= CLIENT_READONLY;
|
||||
|
||||
if (dflag) {
|
||||
server_write_session(s, MSG_DETACH, s->name,
|
||||
strlen(s->name) + 1);
|
||||
TAILQ_FOREACH(c_loop, &clients, entry) {
|
||||
if (c_loop->session != s || c == c_loop)
|
||||
continue;
|
||||
proc_send_s(c->peer, MSG_DETACH, s->name);
|
||||
}
|
||||
}
|
||||
|
||||
if (!Eflag) {
|
||||
@ -168,7 +165,8 @@ cmd_attach_session(struct cmd_q *cmdq, const char *tflag, int dflag, int rflag,
|
||||
server_redraw_client(c);
|
||||
s->curw->flags &= ~WINLINK_ALERTFLAGS;
|
||||
|
||||
server_write_ready(c);
|
||||
if (~c->flags & CLIENT_CONTROL)
|
||||
proc_send(c->peer, MSG_READY, -1, NULL, 0);
|
||||
cmdq->client_exit = 0;
|
||||
}
|
||||
recalculate_sizes();
|
||||
|
@ -57,7 +57,7 @@ cmd_detach_client_exec(struct cmd *self, struct cmd_q *cmdq)
|
||||
return (CMD_RETURN_ERROR);
|
||||
tty_stop_tty(&c->tty);
|
||||
c->flags |= CLIENT_SUSPENDED;
|
||||
server_write_client(c, MSG_SUSPEND, NULL, 0);
|
||||
proc_send(c->peer, MSG_SUSPEND, -1, NULL, 0);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
@ -74,9 +74,7 @@ cmd_detach_client_exec(struct cmd *self, struct cmd_q *cmdq)
|
||||
TAILQ_FOREACH(cloop, &clients, entry) {
|
||||
if (cloop->session != s)
|
||||
continue;
|
||||
server_write_client(cloop, msgtype,
|
||||
cloop->session->name,
|
||||
strlen(cloop->session->name) + 1);
|
||||
proc_send_s(cloop->peer, msgtype, cloop->session->name);
|
||||
}
|
||||
return (CMD_RETURN_STOP);
|
||||
}
|
||||
@ -89,14 +87,11 @@ cmd_detach_client_exec(struct cmd *self, struct cmd_q *cmdq)
|
||||
TAILQ_FOREACH(cloop, &clients, entry) {
|
||||
if (cloop->session == NULL || cloop == c)
|
||||
continue;
|
||||
server_write_client(cloop, msgtype,
|
||||
cloop->session->name,
|
||||
strlen(cloop->session->name) + 1);
|
||||
proc_send_s(cloop->peer, msgtype, cloop->session->name);
|
||||
}
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
server_write_client(c, msgtype, c->session->name,
|
||||
strlen(c->session->name) + 1);
|
||||
proc_send_s(c->peer, msgtype, c->session->name);
|
||||
return (CMD_RETURN_STOP);
|
||||
}
|
||||
|
14
cmd-find.c
14
cmd-find.c
@ -129,8 +129,8 @@ cmd_find_try_TMUX(struct client *c, struct window *w)
|
||||
return (NULL);
|
||||
if (pid != getpid())
|
||||
return (NULL);
|
||||
log_debug("client %d TMUX is %s (session @%u)", c->ibuf.fd,
|
||||
envent->value, session);
|
||||
log_debug("client %p TMUX is %s (session @%u)", c, envent->value,
|
||||
session);
|
||||
|
||||
s = session_find_by_id(session);
|
||||
if (s == NULL || (w != NULL && !session_has(s, w)))
|
||||
@ -333,6 +333,8 @@ cmd_find_current_session(struct cmd_find_state *fs)
|
||||
{
|
||||
/* If we know the current client, use it. */
|
||||
if (fs->cmdq->client != NULL) {
|
||||
log_debug("%s: have client %p%s", __func__, fs->cmdq->client,
|
||||
fs->cmdq->client->session == NULL ? "" : " (with session)");
|
||||
if (fs->cmdq->client->session == NULL)
|
||||
return (cmd_find_current_session_with_client(fs));
|
||||
fs->s = fs->cmdq->client->session;
|
||||
@ -365,8 +367,11 @@ cmd_find_current_client(struct cmd_q *cmdq)
|
||||
u_int csize;
|
||||
|
||||
/* If the queue client has a session, use it. */
|
||||
if (cmdq->client != NULL && cmdq->client->session != NULL)
|
||||
if (cmdq->client != NULL && cmdq->client->session != NULL) {
|
||||
log_debug("%s: using cmdq %p client %p", __func__, cmdq,
|
||||
cmdq->client);
|
||||
return (cmdq->client);
|
||||
}
|
||||
|
||||
/* Otherwise find the current session. */
|
||||
cmd_find_clear_state(¤t, cmdq, 0);
|
||||
@ -375,6 +380,7 @@ cmd_find_current_client(struct cmd_q *cmdq)
|
||||
|
||||
/* If it is attached, find the best of it's clients. */
|
||||
s = current.s;
|
||||
log_debug("%s: current session $%u %s", __func__, s->id, s->name);
|
||||
if (~s->flags & SESSION_UNATTACHED) {
|
||||
csize = 0;
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
@ -1220,6 +1226,7 @@ cmd_find_client(struct cmd_q *cmdq, const char *target, int quiet)
|
||||
c = cmd_find_current_client(cmdq);
|
||||
if (c == NULL && !quiet)
|
||||
cmdq_error(cmdq, "no current client");
|
||||
log_debug("%s: no target, return %p", __func__, c);
|
||||
return (c);
|
||||
}
|
||||
copy = xstrdup(target);
|
||||
@ -1251,6 +1258,7 @@ cmd_find_client(struct cmd_q *cmdq, const char *target, int quiet)
|
||||
cmdq_error(cmdq, "can't find client %s", copy);
|
||||
|
||||
free(copy);
|
||||
log_debug("%s: target %s, return %p", __func__, target, c);
|
||||
return (c);
|
||||
}
|
||||
|
||||
|
@ -270,9 +270,10 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq)
|
||||
* taking this session and needs to get MSG_READY and stay around.
|
||||
*/
|
||||
if (!detached) {
|
||||
if (!already_attached)
|
||||
server_write_ready(c);
|
||||
else if (c->session != NULL)
|
||||
if (!already_attached) {
|
||||
if (~c->flags & CLIENT_CONTROL)
|
||||
proc_send(c->peer, MSG_READY, -1, NULL, 0);
|
||||
} else if (c->session != NULL)
|
||||
c->last_session = c->session;
|
||||
c->session = s;
|
||||
status_timer_start(c);
|
||||
|
249
proc.c
Normal file
249
proc.c
Normal file
@ -0,0 +1,249 @@
|
||||
/* $OpenBSD$ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2015 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <event.h>
|
||||
#include <imsg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
struct tmuxproc {
|
||||
const char *name;
|
||||
int exit;
|
||||
|
||||
void (*signalcb)(int);
|
||||
};
|
||||
|
||||
struct tmuxpeer {
|
||||
struct tmuxproc *parent;
|
||||
|
||||
struct imsgbuf ibuf;
|
||||
struct event event;
|
||||
|
||||
int flags;
|
||||
#define PEER_BAD 0x1
|
||||
|
||||
void (*dispatchcb)(struct imsg *, void *);
|
||||
void *arg;
|
||||
};
|
||||
|
||||
static void proc_update_event(struct tmuxpeer *);
|
||||
|
||||
static void
|
||||
proc_event_cb(unused int fd, short events, void *arg)
|
||||
{
|
||||
struct tmuxpeer *peer = arg;
|
||||
ssize_t n;
|
||||
struct imsg imsg;
|
||||
int v;
|
||||
|
||||
if (!(peer->flags & PEER_BAD) && (events & EV_READ)) {
|
||||
if ((n = imsg_read(&peer->ibuf)) == -1 || n == 0) {
|
||||
peer->dispatchcb(NULL, peer->arg);
|
||||
return;
|
||||
}
|
||||
for (;;) {
|
||||
if ((n = imsg_get(&peer->ibuf, &imsg)) == -1) {
|
||||
peer->dispatchcb(NULL, peer->arg);
|
||||
return;
|
||||
}
|
||||
if (n == 0)
|
||||
break;
|
||||
log_debug("peer %p message %d", peer, imsg.hdr.type);
|
||||
|
||||
v = imsg.hdr.peerid;
|
||||
if (imsg.hdr.type != MSG_VERSION &&
|
||||
v != PROTOCOL_VERSION) {
|
||||
log_debug("peer %p bad version %d", peer, v);
|
||||
|
||||
proc_send(peer, MSG_VERSION, -1, NULL, 0);
|
||||
peer->flags |= PEER_BAD;
|
||||
|
||||
if (imsg.fd != -1)
|
||||
close(imsg.fd);
|
||||
imsg_free(&imsg);
|
||||
break;
|
||||
}
|
||||
|
||||
peer->dispatchcb(&imsg, peer->arg);
|
||||
imsg_free(&imsg);
|
||||
}
|
||||
}
|
||||
|
||||
if (events & EV_WRITE) {
|
||||
if (msgbuf_write(&peer->ibuf.w) <= 0 && errno != EAGAIN) {
|
||||
peer->dispatchcb(NULL, peer->arg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ((peer->flags & PEER_BAD) && peer->ibuf.w.queued == 0) {
|
||||
peer->dispatchcb(NULL, peer->arg);
|
||||
return;
|
||||
}
|
||||
|
||||
proc_update_event(peer);
|
||||
}
|
||||
|
||||
static void
|
||||
proc_signal_cb(int signo, unused short events, void *arg)
|
||||
{
|
||||
struct tmuxproc *tp = arg;
|
||||
|
||||
tp->signalcb(signo);
|
||||
}
|
||||
|
||||
static void
|
||||
proc_update_event(struct tmuxpeer *peer)
|
||||
{
|
||||
short events;
|
||||
|
||||
event_del(&peer->event);
|
||||
|
||||
events = EV_READ;
|
||||
if (peer->ibuf.w.queued > 0)
|
||||
events |= EV_WRITE;
|
||||
event_set(&peer->event, peer->ibuf.fd, events, proc_event_cb, peer);
|
||||
|
||||
event_add(&peer->event, NULL);
|
||||
}
|
||||
|
||||
int
|
||||
proc_send(struct tmuxpeer *peer, enum msgtype type, int fd, const void *buf,
|
||||
size_t len)
|
||||
{
|
||||
struct imsgbuf *ibuf = &peer->ibuf;
|
||||
void *vp = (void *)buf;
|
||||
int retval;
|
||||
|
||||
if (peer->flags & PEER_BAD)
|
||||
return (-1);
|
||||
log_debug("sending message %d to peer %p (%zu bytes)", type, peer, len);
|
||||
|
||||
retval = imsg_compose(ibuf, type, PROTOCOL_VERSION, -1, fd, vp, len);
|
||||
if (retval != 1)
|
||||
return (-1);
|
||||
proc_update_event(peer);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
proc_send_s(struct tmuxpeer *peer, enum msgtype type, const char *s)
|
||||
{
|
||||
return (proc_send(peer, type, -1, s, strlen(s) + 1));
|
||||
}
|
||||
|
||||
struct tmuxproc *
|
||||
proc_start(const char *name, struct event_base *base, int forkflag,
|
||||
void (*signalcb)(int))
|
||||
{
|
||||
struct tmuxproc *tp;
|
||||
|
||||
if (forkflag) {
|
||||
switch (fork()) {
|
||||
case -1:
|
||||
fatal("fork failed");
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
return (NULL);
|
||||
}
|
||||
if (daemon(1, 0) != 0)
|
||||
fatal("daemon failed");
|
||||
|
||||
clear_signals(0);
|
||||
if (event_reinit(base) != 0)
|
||||
fatalx("event_reinit failed");
|
||||
}
|
||||
|
||||
logfile(name);
|
||||
setproctitle("%s (%s)", name, socket_path);
|
||||
|
||||
log_debug("%s started (%ld): socket %s, protocol %d", name,
|
||||
(long)getpid(), socket_path, PROTOCOL_VERSION);
|
||||
|
||||
tp = xcalloc(1, sizeof *tp);
|
||||
tp->name = xstrdup(name);
|
||||
|
||||
tp->signalcb = signalcb;
|
||||
set_signals(proc_signal_cb, tp);
|
||||
|
||||
return (tp);
|
||||
}
|
||||
|
||||
void
|
||||
proc_loop(struct tmuxproc *tp, int (*loopcb)(void))
|
||||
{
|
||||
log_debug("%s loop enter", tp->name);
|
||||
do
|
||||
event_loop(EVLOOP_ONCE);
|
||||
while (!tp->exit && (loopcb == NULL || !loopcb ()));
|
||||
log_debug("%s loop exit", tp->name);
|
||||
}
|
||||
|
||||
void
|
||||
proc_exit(struct tmuxproc *tp)
|
||||
{
|
||||
tp->exit = 1;
|
||||
}
|
||||
|
||||
struct tmuxpeer *
|
||||
proc_add_peer(struct tmuxproc *tp, int fd,
|
||||
void (*dispatchcb)(struct imsg *, void *), void *arg)
|
||||
{
|
||||
struct tmuxpeer *peer;
|
||||
|
||||
peer = xcalloc(1, sizeof *peer);
|
||||
peer->parent = tp;
|
||||
|
||||
peer->dispatchcb = dispatchcb;
|
||||
peer->arg = arg;
|
||||
|
||||
imsg_init(&peer->ibuf, fd);
|
||||
event_set(&peer->event, fd, EV_READ, proc_event_cb, peer);
|
||||
|
||||
log_debug("add peer %p: %d (%p)", peer, fd, arg);
|
||||
|
||||
proc_update_event(peer);
|
||||
return (peer);
|
||||
}
|
||||
|
||||
void
|
||||
proc_remove_peer(struct tmuxpeer *peer)
|
||||
{
|
||||
log_debug("remove peer %p", peer);
|
||||
|
||||
event_del(&peer->event);
|
||||
imsg_clear(&peer->ibuf);
|
||||
|
||||
close(peer->ibuf.fd);
|
||||
free(peer);
|
||||
}
|
||||
|
||||
void
|
||||
proc_kill_peer(struct tmuxpeer *peer)
|
||||
{
|
||||
peer->flags |= PEER_BAD;
|
||||
}
|
266
server-client.c
266
server-client.c
@ -18,10 +18,12 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <event.h>
|
||||
#include <fcntl.h>
|
||||
#include <imsg.h>
|
||||
#include <paths.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -42,10 +44,10 @@ void server_client_set_title(struct client *);
|
||||
void server_client_reset_state(struct client *);
|
||||
int server_client_assume_paste(struct session *);
|
||||
|
||||
int server_client_msg_dispatch(struct client *);
|
||||
void server_client_msg_command(struct client *, struct imsg *);
|
||||
void server_client_msg_identify(struct client *, struct imsg *);
|
||||
void server_client_msg_shell(struct client *);
|
||||
void server_client_dispatch(struct imsg *, void *);
|
||||
void server_client_dispatch_command(struct client *, struct imsg *);
|
||||
void server_client_dispatch_identify(struct client *, struct imsg *);
|
||||
void server_client_dispatch_shell(struct client *);
|
||||
|
||||
/* Check if this client is inside this server. */
|
||||
int
|
||||
@ -87,8 +89,7 @@ server_client_create(int fd)
|
||||
|
||||
c = xcalloc(1, sizeof *c);
|
||||
c->references = 1;
|
||||
imsg_init(&c->ibuf, fd);
|
||||
server_update_event(c);
|
||||
c->peer = proc_add_peer(server_proc, fd, server_client_dispatch, c);
|
||||
|
||||
if (gettimeofday(&c->creation_time, NULL) != 0)
|
||||
fatal("gettimeofday failed");
|
||||
@ -220,10 +221,8 @@ server_client_lost(struct client *c)
|
||||
|
||||
environ_free(&c->environ);
|
||||
|
||||
close(c->ibuf.fd);
|
||||
imsg_clear(&c->ibuf);
|
||||
if (event_initialized(&c->event))
|
||||
event_del(&c->event);
|
||||
proc_remove_peer(c->peer);
|
||||
c->peer = NULL;
|
||||
|
||||
server_client_unref(c);
|
||||
|
||||
@ -257,40 +256,6 @@ server_client_free(unused int fd, unused short events, void *arg)
|
||||
free(c);
|
||||
}
|
||||
|
||||
/* Process a single client event. */
|
||||
void
|
||||
server_client_callback(int fd, short events, void *data)
|
||||
{
|
||||
struct client *c = data;
|
||||
|
||||
if (c->flags & CLIENT_DEAD)
|
||||
return;
|
||||
|
||||
if (fd == c->ibuf.fd) {
|
||||
if (events & EV_WRITE && msgbuf_write(&c->ibuf.w) <= 0 &&
|
||||
errno != EAGAIN)
|
||||
goto client_lost;
|
||||
|
||||
if (c->flags & CLIENT_BAD) {
|
||||
if (c->ibuf.w.queued == 0)
|
||||
goto client_lost;
|
||||
return;
|
||||
}
|
||||
|
||||
if (events & EV_READ && server_client_msg_dispatch(c) != 0)
|
||||
goto client_lost;
|
||||
}
|
||||
|
||||
server_push_stdout(c);
|
||||
server_push_stderr(c);
|
||||
|
||||
server_update_event(c);
|
||||
return;
|
||||
|
||||
client_lost:
|
||||
server_client_lost(c);
|
||||
}
|
||||
|
||||
/* Check for mouse keys. */
|
||||
int
|
||||
server_client_check_mouse(struct client *c)
|
||||
@ -880,7 +845,7 @@ server_client_check_exit(struct client *c)
|
||||
if (EVBUFFER_LENGTH(c->stderr_data) != 0)
|
||||
return;
|
||||
|
||||
server_write_client(c, MSG_EXIT, &c->retval, sizeof c->retval);
|
||||
proc_send(c->peer, MSG_EXIT, -1, &c->retval, sizeof c->retval);
|
||||
c->flags &= ~CLIENT_EXIT;
|
||||
}
|
||||
|
||||
@ -974,123 +939,112 @@ server_client_set_title(struct client *c)
|
||||
}
|
||||
|
||||
/* Dispatch message from client. */
|
||||
int
|
||||
server_client_msg_dispatch(struct client *c)
|
||||
void
|
||||
server_client_dispatch(struct imsg *imsg, void *arg)
|
||||
{
|
||||
struct imsg imsg;
|
||||
struct client *c = arg;
|
||||
struct msg_stdin_data stdindata;
|
||||
const char *data;
|
||||
ssize_t n, datalen;
|
||||
ssize_t datalen;
|
||||
struct session *s;
|
||||
|
||||
if ((n = imsg_read(&c->ibuf)) == -1 || n == 0)
|
||||
return (-1);
|
||||
if (c->flags & CLIENT_DEAD)
|
||||
return;
|
||||
|
||||
for (;;) {
|
||||
if ((n = imsg_get(&c->ibuf, &imsg)) == -1)
|
||||
return (-1);
|
||||
if (n == 0)
|
||||
return (0);
|
||||
|
||||
data = imsg.data;
|
||||
datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
|
||||
|
||||
if (imsg.hdr.peerid != PROTOCOL_VERSION) {
|
||||
server_write_client(c, MSG_VERSION, NULL, 0);
|
||||
c->flags |= CLIENT_BAD;
|
||||
if (imsg.fd != -1)
|
||||
close(imsg.fd);
|
||||
imsg_free(&imsg);
|
||||
continue;
|
||||
}
|
||||
|
||||
log_debug("got %u from client %p", imsg.hdr.type, c);
|
||||
switch (imsg.hdr.type) {
|
||||
case MSG_IDENTIFY_FLAGS:
|
||||
case MSG_IDENTIFY_TERM:
|
||||
case MSG_IDENTIFY_TTYNAME:
|
||||
case MSG_IDENTIFY_CWD:
|
||||
case MSG_IDENTIFY_STDIN:
|
||||
case MSG_IDENTIFY_ENVIRON:
|
||||
case MSG_IDENTIFY_CLIENTPID:
|
||||
case MSG_IDENTIFY_DONE:
|
||||
server_client_msg_identify(c, &imsg);
|
||||
break;
|
||||
case MSG_COMMAND:
|
||||
server_client_msg_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");
|
||||
|
||||
if (c->flags & CLIENT_CONTROL)
|
||||
break;
|
||||
if (tty_resize(&c->tty)) {
|
||||
recalculate_sizes();
|
||||
server_redraw_client(c);
|
||||
}
|
||||
break;
|
||||
case MSG_EXITING:
|
||||
if (datalen != 0)
|
||||
fatalx("bad MSG_EXITING size");
|
||||
|
||||
c->session = NULL;
|
||||
tty_close(&c->tty);
|
||||
server_write_client(c, MSG_EXITED, NULL, 0);
|
||||
break;
|
||||
case MSG_WAKEUP:
|
||||
case MSG_UNLOCK:
|
||||
if (datalen != 0)
|
||||
fatalx("bad MSG_WAKEUP size");
|
||||
|
||||
if (!(c->flags & CLIENT_SUSPENDED))
|
||||
break;
|
||||
c->flags &= ~CLIENT_SUSPENDED;
|
||||
|
||||
if (c->tty.fd == -1) /* exited in the meantime */
|
||||
break;
|
||||
s = c->session;
|
||||
|
||||
if (gettimeofday(&c->activity_time, NULL) != 0)
|
||||
fatal("gettimeofday failed");
|
||||
if (s != NULL)
|
||||
session_update_activity(s, &c->activity_time);
|
||||
|
||||
tty_start_tty(&c->tty);
|
||||
server_redraw_client(c);
|
||||
recalculate_sizes();
|
||||
break;
|
||||
case MSG_SHELL:
|
||||
if (datalen != 0)
|
||||
fatalx("bad MSG_SHELL size");
|
||||
|
||||
server_client_msg_shell(c);
|
||||
break;
|
||||
}
|
||||
|
||||
imsg_free(&imsg);
|
||||
if (imsg == NULL) {
|
||||
server_client_lost(c);
|
||||
return;
|
||||
}
|
||||
|
||||
data = imsg->data;
|
||||
datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
|
||||
|
||||
switch (imsg->hdr.type) {
|
||||
case MSG_IDENTIFY_FLAGS:
|
||||
case MSG_IDENTIFY_TERM:
|
||||
case MSG_IDENTIFY_TTYNAME:
|
||||
case MSG_IDENTIFY_CWD:
|
||||
case MSG_IDENTIFY_STDIN:
|
||||
case MSG_IDENTIFY_ENVIRON:
|
||||
case MSG_IDENTIFY_CLIENTPID:
|
||||
case MSG_IDENTIFY_DONE:
|
||||
server_client_dispatch_identify(c, imsg);
|
||||
break;
|
||||
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");
|
||||
|
||||
if (c->flags & CLIENT_CONTROL)
|
||||
break;
|
||||
if (tty_resize(&c->tty)) {
|
||||
recalculate_sizes();
|
||||
server_redraw_client(c);
|
||||
}
|
||||
break;
|
||||
case MSG_EXITING:
|
||||
if (datalen != 0)
|
||||
fatalx("bad MSG_EXITING size");
|
||||
|
||||
c->session = NULL;
|
||||
tty_close(&c->tty);
|
||||
proc_send(c->peer, MSG_EXITED, -1, NULL, 0);
|
||||
break;
|
||||
case MSG_WAKEUP:
|
||||
case MSG_UNLOCK:
|
||||
if (datalen != 0)
|
||||
fatalx("bad MSG_WAKEUP size");
|
||||
|
||||
if (!(c->flags & CLIENT_SUSPENDED))
|
||||
break;
|
||||
c->flags &= ~CLIENT_SUSPENDED;
|
||||
|
||||
if (c->tty.fd == -1) /* exited in the meantime */
|
||||
break;
|
||||
s = c->session;
|
||||
|
||||
if (gettimeofday(&c->activity_time, NULL) != 0)
|
||||
fatal("gettimeofday failed");
|
||||
if (s != NULL)
|
||||
session_update_activity(s, &c->activity_time);
|
||||
|
||||
tty_start_tty(&c->tty);
|
||||
server_redraw_client(c);
|
||||
recalculate_sizes();
|
||||
break;
|
||||
case MSG_SHELL:
|
||||
if (datalen != 0)
|
||||
fatalx("bad MSG_SHELL size");
|
||||
|
||||
server_client_dispatch_shell(c);
|
||||
break;
|
||||
}
|
||||
|
||||
server_push_stdout(c);
|
||||
server_push_stderr(c);
|
||||
}
|
||||
|
||||
/* Handle command message. */
|
||||
void
|
||||
server_client_msg_command(struct client *c, struct imsg *imsg)
|
||||
server_client_dispatch_command(struct client *c, struct imsg *imsg)
|
||||
{
|
||||
struct msg_command_data data;
|
||||
char *buf;
|
||||
@ -1143,7 +1097,7 @@ error:
|
||||
|
||||
/* Handle identify message. */
|
||||
void
|
||||
server_client_msg_identify(struct client *c, struct imsg *imsg)
|
||||
server_client_dispatch_identify(struct client *c, struct imsg *imsg)
|
||||
{
|
||||
const char *data;
|
||||
size_t datalen;
|
||||
@ -1217,7 +1171,7 @@ server_client_msg_identify(struct client *c, struct imsg *imsg)
|
||||
|
||||
if (c->flags & CLIENT_CONTROLCONTROL)
|
||||
evbuffer_add_printf(c->stdout_data, "\033P1000p");
|
||||
server_write_client(c, MSG_STDIN, NULL, 0);
|
||||
proc_send(c->peer, MSG_STDIN, -1, NULL, 0);
|
||||
|
||||
c->tty.fd = -1;
|
||||
c->tty.log_fd = -1;
|
||||
@ -1248,14 +1202,14 @@ server_client_msg_identify(struct client *c, struct imsg *imsg)
|
||||
|
||||
/* Handle shell message. */
|
||||
void
|
||||
server_client_msg_shell(struct client *c)
|
||||
server_client_dispatch_shell(struct client *c)
|
||||
{
|
||||
const char *shell;
|
||||
|
||||
shell = options_get_string(&global_s_options, "default-shell");
|
||||
if (*shell == '\0' || areshell(shell))
|
||||
shell = _PATH_BSHELL;
|
||||
server_write_client(c, MSG_SHELL, shell, strlen(shell) + 1);
|
||||
proc_send_s(c->peer, MSG_SHELL, shell);
|
||||
|
||||
c->flags |= CLIENT_BAD; /* it will die after exec */
|
||||
proc_kill_peer(c->peer);
|
||||
}
|
||||
|
64
server-fn.c
64
server-fn.c
@ -17,7 +17,10 @@
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
#include <imsg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
@ -47,43 +50,6 @@ server_fill_environ(struct session *s, struct environ *env)
|
||||
environ_set(env, "TMUX", var);
|
||||
}
|
||||
|
||||
void
|
||||
server_write_ready(struct client *c)
|
||||
{
|
||||
if (c->flags & CLIENT_CONTROL)
|
||||
return;
|
||||
server_write_client(c, MSG_READY, NULL, 0);
|
||||
}
|
||||
|
||||
int
|
||||
server_write_client(struct client *c, enum msgtype type, const void *buf,
|
||||
size_t len)
|
||||
{
|
||||
struct imsgbuf *ibuf = &c->ibuf;
|
||||
int error;
|
||||
|
||||
if (c->flags & CLIENT_BAD)
|
||||
return (-1);
|
||||
log_debug("writing %d to client %p", type, c);
|
||||
error = imsg_compose(ibuf, type, PROTOCOL_VERSION, -1, -1,
|
||||
(void *) buf, len);
|
||||
if (error == 1)
|
||||
server_update_event(c);
|
||||
return (error == 1 ? 0 : -1);
|
||||
}
|
||||
|
||||
void
|
||||
server_write_session(struct session *s, enum msgtype type, const void *buf,
|
||||
size_t len)
|
||||
{
|
||||
struct client *c;
|
||||
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (c->session == s)
|
||||
server_write_client(c, type, buf, len);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
server_redraw_client(struct client *c)
|
||||
{
|
||||
@ -227,7 +193,7 @@ server_lock_client(struct client *c)
|
||||
tty_raw(&c->tty, tty_term_string(c->tty.term, TTYC_E3));
|
||||
|
||||
c->flags |= CLIENT_SUSPENDED;
|
||||
server_write_client(c, MSG_LOCK, cmd, strlen(cmd) + 1);
|
||||
proc_send_s(c->peer, MSG_LOCK, cmd);
|
||||
}
|
||||
|
||||
void
|
||||
@ -484,22 +450,6 @@ server_callback_identify(unused int fd, unused short events, void *data)
|
||||
server_clear_identify(c);
|
||||
}
|
||||
|
||||
void
|
||||
server_update_event(struct client *c)
|
||||
{
|
||||
short events;
|
||||
|
||||
events = 0;
|
||||
if (!(c->flags & CLIENT_BAD))
|
||||
events |= EV_READ;
|
||||
if (c->ibuf.w.queued > 0)
|
||||
events |= EV_WRITE;
|
||||
if (event_initialized(&c->event))
|
||||
event_del(&c->event);
|
||||
event_set(&c->event, c->ibuf.fd, events, server_client_callback, c);
|
||||
event_add(&c->event, NULL);
|
||||
}
|
||||
|
||||
/* Push stdout to client if possible. */
|
||||
void
|
||||
server_push_stdout(struct client *c)
|
||||
@ -516,7 +466,7 @@ server_push_stdout(struct client *c)
|
||||
memcpy(data.data, EVBUFFER_DATA(c->stdout_data), size);
|
||||
data.size = size;
|
||||
|
||||
if (server_write_client(c, MSG_STDOUT, &data, sizeof data) == 0)
|
||||
if (proc_send(c->peer, MSG_STDOUT, -1, &data, sizeof data) == 0)
|
||||
evbuffer_drain(c->stdout_data, size);
|
||||
}
|
||||
|
||||
@ -540,7 +490,7 @@ server_push_stderr(struct client *c)
|
||||
memcpy(data.data, EVBUFFER_DATA(c->stderr_data), size);
|
||||
data.size = size;
|
||||
|
||||
if (server_write_client(c, MSG_STDERR, &data, sizeof data) == 0)
|
||||
if (proc_send(c->peer, MSG_STDERR, -1, &data, sizeof data) == 0)
|
||||
evbuffer_drain(c->stderr_data, size);
|
||||
}
|
||||
|
||||
@ -570,7 +520,7 @@ server_set_stdin_callback(struct client *c, void (*cb)(struct client *, int,
|
||||
if (c->stdin_closed)
|
||||
c->stdin_callback(c, 1, c->stdin_callback_data);
|
||||
|
||||
server_write_client(c, MSG_STDIN, NULL, 0);
|
||||
proc_send(c->peer, MSG_STDIN, -1, NULL, 0);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
72
server.c
72
server.c
@ -43,6 +43,7 @@
|
||||
|
||||
struct clients clients;
|
||||
|
||||
struct tmuxproc *server_proc;
|
||||
int server_fd;
|
||||
int server_exit;
|
||||
struct event server_ev_accept;
|
||||
@ -54,11 +55,11 @@ struct window_pane *marked_window_pane;
|
||||
struct layout_cell *marked_layout_cell;
|
||||
|
||||
int server_create_socket(void);
|
||||
void server_loop(void);
|
||||
int server_loop(void);
|
||||
int server_should_exit(void);
|
||||
void server_send_exit(void);
|
||||
void server_accept_callback(int, short, void *);
|
||||
void server_signal_callback(int, short, void *);
|
||||
void server_accept(int, short, void *);
|
||||
void server_signal(int);
|
||||
void server_child_signal(void);
|
||||
void server_child_exited(pid_t, int);
|
||||
void server_child_stopped(pid_t, int);
|
||||
@ -162,17 +163,11 @@ server_start(struct event_base *base, int lockfd, char *lockfile)
|
||||
{
|
||||
int pair[2];
|
||||
|
||||
/* The first client is special and gets a socketpair; create it. */
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0)
|
||||
fatal("socketpair failed");
|
||||
log_debug("starting server");
|
||||
|
||||
switch (fork()) {
|
||||
case -1:
|
||||
fatal("fork failed");
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
server_proc = proc_start("server", base, 1, server_signal);
|
||||
if (server_proc == NULL) {
|
||||
close(pair[1]);
|
||||
return (pair[0]);
|
||||
}
|
||||
@ -182,21 +177,6 @@ server_start(struct event_base *base, int lockfd, char *lockfile)
|
||||
"ps", NULL) != 0)
|
||||
fatal("pledge failed");
|
||||
|
||||
/*
|
||||
* Must daemonise before loading configuration as the PID changes so
|
||||
* $TMUX would be wrong for sessions created in the config file.
|
||||
*/
|
||||
if (daemon(1, 0) != 0)
|
||||
fatal("daemon failed");
|
||||
|
||||
/* event_init() was called in our parent, need to reinit. */
|
||||
clear_signals(0);
|
||||
if (event_reinit(base) != 0)
|
||||
fatal("event_reinit failed");
|
||||
|
||||
logfile("server");
|
||||
log_debug("server started, pid %ld", (long) getpid());
|
||||
|
||||
RB_INIT(&windows);
|
||||
RB_INIT(&all_window_panes);
|
||||
TAILQ_INIT(&clients);
|
||||
@ -207,8 +187,6 @@ server_start(struct event_base *base, int lockfd, char *lockfile)
|
||||
utf8_build();
|
||||
|
||||
start_time = time(NULL);
|
||||
log_debug("socket path %s", socket_path);
|
||||
setproctitle("server (%s)", socket_path);
|
||||
|
||||
server_fd = server_create_socket();
|
||||
if (server_fd == -1)
|
||||
@ -226,31 +204,19 @@ server_start(struct event_base *base, int lockfd, char *lockfile)
|
||||
|
||||
server_add_accept(0);
|
||||
|
||||
set_signals(server_signal_callback);
|
||||
server_loop();
|
||||
proc_loop(server_proc, server_loop);
|
||||
status_prompt_save_history();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* Main server loop. */
|
||||
void
|
||||
/* Server loop callback. */
|
||||
int
|
||||
server_loop(void)
|
||||
{
|
||||
while (!server_should_exit()) {
|
||||
log_debug("event dispatch enter");
|
||||
event_loop(EVLOOP_ONCE);
|
||||
log_debug("event dispatch exit");
|
||||
|
||||
server_client_loop();
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if the server should exit (no more clients or sessions). */
|
||||
int
|
||||
server_should_exit(void)
|
||||
{
|
||||
struct client *c;
|
||||
|
||||
server_client_loop();
|
||||
|
||||
if (!options_get_number(&global_options, "exit-unattached")) {
|
||||
if (!RB_EMPTY(&sessions))
|
||||
return (0);
|
||||
@ -282,10 +248,10 @@ server_send_exit(void)
|
||||
cmd_wait_for_flush();
|
||||
|
||||
TAILQ_FOREACH_SAFE(c, &clients, entry, c1) {
|
||||
if (c->flags & (CLIENT_BAD|CLIENT_SUSPENDED))
|
||||
if (c->flags & CLIENT_SUSPENDED)
|
||||
server_client_lost(c);
|
||||
else
|
||||
server_write_client(c, MSG_SHUTDOWN, NULL, 0);
|
||||
proc_send(c->peer, MSG_SHUTDOWN, -1, NULL, 0);
|
||||
c->session = NULL;
|
||||
}
|
||||
|
||||
@ -331,7 +297,7 @@ server_update_socket(void)
|
||||
|
||||
/* Callback for server socket. */
|
||||
void
|
||||
server_accept_callback(int fd, short events, unused void *data)
|
||||
server_accept(int fd, short events, unused void *data)
|
||||
{
|
||||
struct sockaddr_storage sa;
|
||||
socklen_t slen = sizeof sa;
|
||||
@ -372,19 +338,19 @@ server_add_accept(int timeout)
|
||||
event_del(&server_ev_accept);
|
||||
|
||||
if (timeout == 0) {
|
||||
event_set(&server_ev_accept,
|
||||
server_fd, EV_READ, server_accept_callback, NULL);
|
||||
event_set(&server_ev_accept, server_fd, EV_READ, server_accept,
|
||||
NULL);
|
||||
event_add(&server_ev_accept, NULL);
|
||||
} else {
|
||||
event_set(&server_ev_accept,
|
||||
server_fd, EV_TIMEOUT, server_accept_callback, NULL);
|
||||
event_set(&server_ev_accept, server_fd, EV_TIMEOUT,
|
||||
server_accept, NULL);
|
||||
event_add(&server_ev_accept, &tv);
|
||||
}
|
||||
}
|
||||
|
||||
/* Signal handler. */
|
||||
void
|
||||
server_signal_callback(int sig, unused short events, unused void *data)
|
||||
server_signal(int sig)
|
||||
{
|
||||
int fd;
|
||||
|
||||
|
14
signal.c
14
signal.c
@ -32,7 +32,7 @@ struct event ev_sigusr1;
|
||||
struct event ev_sigwinch;
|
||||
|
||||
void
|
||||
set_signals(void(*handler)(int, short, unused void *))
|
||||
set_signals(void (*handler)(int, short, void *), void *arg)
|
||||
{
|
||||
struct sigaction sigact;
|
||||
|
||||
@ -49,17 +49,17 @@ set_signals(void(*handler)(int, short, unused void *))
|
||||
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
|
||||
signal_set(&ev_sighup, SIGHUP, handler, NULL);
|
||||
signal_set(&ev_sighup, SIGHUP, handler, arg);
|
||||
signal_add(&ev_sighup, NULL);
|
||||
signal_set(&ev_sigchld, SIGCHLD, handler, NULL);
|
||||
signal_set(&ev_sigchld, SIGCHLD, handler, arg);
|
||||
signal_add(&ev_sigchld, NULL);
|
||||
signal_set(&ev_sigcont, SIGCONT, handler, NULL);
|
||||
signal_set(&ev_sigcont, SIGCONT, handler, arg);
|
||||
signal_add(&ev_sigcont, NULL);
|
||||
signal_set(&ev_sigterm, SIGTERM, handler, NULL);
|
||||
signal_set(&ev_sigterm, SIGTERM, handler, arg);
|
||||
signal_add(&ev_sigterm, NULL);
|
||||
signal_set(&ev_sigusr1, SIGUSR1, handler, NULL);
|
||||
signal_set(&ev_sigusr1, SIGUSR1, handler, arg);
|
||||
signal_add(&ev_sigusr1, NULL);
|
||||
signal_set(&ev_sigwinch, SIGWINCH, handler, NULL);
|
||||
signal_set(&ev_sigwinch, SIGWINCH, handler, arg);
|
||||
signal_add(&ev_sigwinch, NULL);
|
||||
}
|
||||
|
||||
|
4
tmux.c
4
tmux.c
@ -29,6 +29,7 @@
|
||||
#include <pwd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "tmux.h"
|
||||
@ -347,9 +348,6 @@ main(int argc, char **argv)
|
||||
}
|
||||
free(path);
|
||||
|
||||
/* Set process title. */
|
||||
setproctitle("%s (%s)", __progname, socket_path);
|
||||
|
||||
/* Pass control to the client. */
|
||||
exit(client_main(event_init(), argc, argv, flags));
|
||||
}
|
||||
|
31
tmux.h
31
tmux.h
@ -24,11 +24,9 @@
|
||||
#include <sys/time.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/tree.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
#include <bitstring.h>
|
||||
#include <event.h>
|
||||
#include <imsg.h>
|
||||
#include <limits.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
@ -1170,8 +1168,10 @@ struct message_entry {
|
||||
};
|
||||
|
||||
/* Client connection. */
|
||||
struct tmuxproc;
|
||||
struct tmuxpeer;
|
||||
struct client {
|
||||
struct imsgbuf ibuf;
|
||||
struct tmuxpeer *peer;
|
||||
|
||||
pid_t pid;
|
||||
int fd;
|
||||
@ -1209,7 +1209,7 @@ struct client {
|
||||
#define CLIENT_STATUS 0x10
|
||||
#define CLIENT_REPEAT 0x20
|
||||
#define CLIENT_SUSPENDED 0x40
|
||||
#define CLIENT_BAD 0x80
|
||||
/* 0x80 unused */
|
||||
#define CLIENT_IDENTIFY 0x100
|
||||
#define CLIENT_DEAD 0x200
|
||||
#define CLIENT_BORDERS 0x400
|
||||
@ -1420,6 +1420,19 @@ int areshell(const char *);
|
||||
void setblocking(int, int);
|
||||
const char *find_home(void);
|
||||
|
||||
/* proc.c */
|
||||
struct imsg;
|
||||
int proc_send(struct tmuxpeer *, enum msgtype, int, const void *, size_t);
|
||||
int proc_send_s(struct tmuxpeer *, enum msgtype, const char *);
|
||||
struct tmuxproc *proc_start(const char *, struct event_base *, int,
|
||||
void (*)(int));
|
||||
void proc_loop(struct tmuxproc *, int (*)(void));
|
||||
void proc_exit(struct tmuxproc *);
|
||||
struct tmuxpeer *proc_add_peer(struct tmuxproc *, int,
|
||||
void (*)(struct imsg *, void *), void *);
|
||||
void proc_remove_peer(struct tmuxpeer *);
|
||||
void proc_kill_peer(struct tmuxpeer *);
|
||||
|
||||
/* cfg.c */
|
||||
extern int cfg_finished;
|
||||
extern int cfg_references;
|
||||
@ -1727,6 +1740,7 @@ void alerts_reset_all(void);
|
||||
void alerts_queue(struct window *, int);
|
||||
|
||||
/* server.c */
|
||||
extern struct tmuxproc *server_proc;
|
||||
extern struct clients clients;
|
||||
extern struct session *marked_session;
|
||||
extern struct winlink *marked_winlink;
|
||||
@ -1748,16 +1762,10 @@ void server_client_create(int);
|
||||
int server_client_open(struct client *, char **);
|
||||
void server_client_unref(struct client *);
|
||||
void server_client_lost(struct client *);
|
||||
void server_client_callback(int, short, void *);
|
||||
void server_client_loop(void);
|
||||
|
||||
/* server-fn.c */
|
||||
void server_fill_environ(struct session *, struct environ *);
|
||||
void server_write_ready(struct client *);
|
||||
int server_write_client(struct client *, enum msgtype, const void *,
|
||||
size_t);
|
||||
void server_write_session(struct session *, enum msgtype, const void *,
|
||||
size_t);
|
||||
void server_redraw_client(struct client *);
|
||||
void server_status_client(struct client *);
|
||||
void server_redraw_session(struct session *);
|
||||
@ -1780,7 +1788,6 @@ void server_destroy_session(struct session *);
|
||||
void server_check_unattached(void);
|
||||
void server_set_identify(struct client *);
|
||||
void server_clear_identify(struct client *);
|
||||
void server_update_event(struct client *);
|
||||
void server_push_stdout(struct client *);
|
||||
void server_push_stderr(struct client *);
|
||||
int server_set_stdin_callback(struct client *, void (*)(struct client *,
|
||||
@ -2110,7 +2117,7 @@ char *format_window_name(struct window *);
|
||||
char *parse_window_name(const char *);
|
||||
|
||||
/* signal.c */
|
||||
void set_signals(void(*)(int, short, void *));
|
||||
void set_signals(void(*)(int, short, void *), void *);
|
||||
void clear_signals(int);
|
||||
|
||||
/* control.c */
|
||||
|
Loading…
Reference in New Issue
Block a user