From 07b0ea03c33893bd2b104db5ea4e1397f92e0477 Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 27 Oct 2015 13:23:24 +0000 Subject: [PATCH 1/3] 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. --- Makefile | 1 + client.c | 509 ++++++++++++++++++------------------------- cmd-attach-session.c | 18 +- cmd-detach-client.c | 13 +- cmd-find.c | 14 +- cmd-new-session.c | 7 +- proc.c | 249 +++++++++++++++++++++ server-client.c | 266 ++++++++++------------ server-fn.c | 64 +----- server.c | 72 ++---- signal.c | 14 +- tmux.c | 4 +- tmux.h | 31 ++- 13 files changed, 648 insertions(+), 614 deletions(-) create mode 100644 proc.c diff --git a/Makefile b/Makefile index 653c8d85..89c8c5c8 100644 --- a/Makefile +++ b/Makefile @@ -94,6 +94,7 @@ SRCS= alerts.c \ options-table.c \ options.c \ paste.c \ + proc.c \ procname.c \ resize.c \ screen-redraw.c \ diff --git a/client.c b/client.c index 73d871bc..606feefe 100644 --- a/client.c +++ b/client.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -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; } } diff --git a/cmd-attach-session.c b/cmd-attach-session.c index a7ef1cd9..4e390323 100644 --- a/cmd-attach-session.c +++ b/cmd-attach-session.c @@ -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(); diff --git a/cmd-detach-client.c b/cmd-detach-client.c index 4bae9997..813ac032 100644 --- a/cmd-detach-client.c +++ b/cmd-detach-client.c @@ -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); } diff --git a/cmd-find.c b/cmd-find.c index 4173e202..fbc06fb7 100644 --- a/cmd-find.c +++ b/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); } diff --git a/cmd-new-session.c b/cmd-new-session.c index b3bf3c74..f1a6167a 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.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); diff --git a/proc.c b/proc.c new file mode 100644 index 00000000..413b2125 --- /dev/null +++ b/proc.c @@ -0,0 +1,249 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2015 Nicholas Marriott + * + * 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 +#include +#include + +#include +#include +#include +#include +#include +#include + +#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; +} diff --git a/server-client.c b/server-client.c index 0e657ae8..13f905b2 100644 --- a/server-client.c +++ b/server-client.c @@ -18,10 +18,12 @@ #include #include +#include #include #include #include +#include #include #include #include @@ -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); } diff --git a/server-fn.c b/server-fn.c index a31a3772..095535ab 100644 --- a/server-fn.c +++ b/server-fn.c @@ -17,7 +17,10 @@ */ #include +#include +#include +#include #include #include #include @@ -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); } diff --git a/server.c b/server.c index 7ce1c99d..a36e9a73 100644 --- a/server.c +++ b/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; diff --git a/signal.c b/signal.c index 7e6268a7..9a4d58c2 100644 --- a/signal.c +++ b/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); } diff --git a/tmux.c b/tmux.c index 8b3d0bfe..01e73f5d 100644 --- a/tmux.c +++ b/tmux.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #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)); } diff --git a/tmux.h b/tmux.h index 97238865..c4b12402 100644 --- a/tmux.h +++ b/tmux.h @@ -24,11 +24,9 @@ #include #include #include -#include #include #include -#include #include #include #include @@ -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 */ From 67c3a014b960b8c1d7931d3c99f570610b1d4d3f Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 27 Oct 2015 14:51:35 +0000 Subject: [PATCH 2/3] No more TMPDIR. --- tmux.1 | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tmux.1 b/tmux.1 index a9f3cdc9..1fb99252 100644 --- a/tmux.1 +++ b/tmux.1 @@ -143,11 +143,10 @@ session created, and continues to process the rest of the configuration file. .It Fl L Ar socket-name .Nm stores the server socket in a directory under -.Ev TMUX_TMPDIR , -.Ev TMPDIR -if it is unset, or +.Ev TMUX_TMPDIR +or .Pa /tmp -if both are unset. +if it is unset. The default socket is named .Em default . This option allows a different socket name to be specified, allowing several From 44657bf932b068aff5ce1019a4e8a2e7b00b5321 Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 27 Oct 2015 15:58:42 +0000 Subject: [PATCH 3/3] Move struct options into options.c. --- alerts.c | 24 +++++++++---------- client.c | 6 ++--- cmd-attach-session.c | 4 ++-- cmd-break-pane.c | 2 +- cmd-choose-buffer.c | 2 +- cmd-move-window.c | 2 +- cmd-new-session.c | 10 ++++---- cmd-new-window.c | 4 ++-- cmd-rename-window.c | 2 +- cmd-send-keys.c | 4 ++-- cmd-set-option.c | 24 +++++++++---------- cmd-show-options.c | 14 ++++++----- cmd-split-window.c | 6 ++--- cmd-switch-client.c | 2 +- format.c | 12 +++++----- input-keys.c | 2 +- input.c | 6 ++--- layout-set.c | 8 +++---- names.c | 4 ++-- options.c | 28 ++++++++++++++++++++-- paste.c | 2 +- resize.c | 8 +++---- screen-redraw.c | 6 ++--- server-client.c | 20 ++++++++-------- server-fn.c | 16 ++++++------- server.c | 2 +- session.c | 19 ++++++++------- status.c | 56 ++++++++++++++++++++++---------------------- tmux.c | 31 ++++++++++++------------ tmux.h | 22 +++++++---------- tty-keys.c | 2 +- tty-term.c | 2 +- tty.c | 8 +++---- window-choose.c | 6 ++--- window-clock.c | 4 ++-- window-copy.c | 34 +++++++++++++-------------- window.c | 20 ++++++++-------- 37 files changed, 223 insertions(+), 201 deletions(-) diff --git a/alerts.c b/alerts.c index 806e565b..f1477030 100644 --- a/alerts.c +++ b/alerts.c @@ -80,11 +80,11 @@ alerts_enabled(struct window *w, int flags) struct session *s; if (flags & WINDOW_ACTIVITY) { - if (options_get_number(&w->options, "monitor-activity")) + if (options_get_number(w->options, "monitor-activity")) return (1); } if (flags & WINDOW_SILENCE) { - if (options_get_number(&w->options, "monitor-silence") != 0) + if (options_get_number(w->options, "monitor-silence") != 0) return (1); } if (~flags & WINDOW_BELL) @@ -92,7 +92,7 @@ alerts_enabled(struct window *w, int flags) RB_FOREACH(s, sessions, &sessions) { if (!session_has(s, w)) continue; - if (options_get_number(&s->options, "bell-action") != BELL_NONE) + if (options_get_number(s->options, "bell-action") != BELL_NONE) return (1); } return (0); @@ -116,7 +116,7 @@ alerts_reset(struct window *w) event_del(&w->alerts_timer); timerclear(&tv); - tv.tv_sec = options_get_number(&w->options, "monitor-silence"); + tv.tv_sec = options_get_number(w->options, "monitor-silence"); log_debug("@%u alerts timer reset %u", w->id, (u_int)tv.tv_sec); if (tv.tv_sec != 0) @@ -160,11 +160,11 @@ alerts_check_bell(struct session *s, struct winlink *wl) if (s->curw->window == w) w->flags &= ~WINDOW_BELL; - action = options_get_number(&s->options, "bell-action"); + action = options_get_number(s->options, "bell-action"); if (action == BELL_NONE) return (0); - visual = options_get_number(&s->options, "visual-bell"); + visual = options_get_number(s->options, "visual-bell"); TAILQ_FOREACH(c, &clients, entry) { if (c->session != s || c->flags & CLIENT_CONTROL) continue; @@ -201,14 +201,14 @@ alerts_check_activity(struct session *s, struct winlink *wl) if (s->curw == wl && !(s->flags & SESSION_UNATTACHED)) return (0); - if (!options_get_number(&w->options, "monitor-activity")) + if (!options_get_number(w->options, "monitor-activity")) return (0); - if (options_get_number(&s->options, "bell-on-alert")) + if (options_get_number(s->options, "bell-on-alert")) alerts_ring_bell(s); wl->flags |= WINLINK_ACTIVITY; - if (options_get_number(&s->options, "visual-activity")) { + if (options_get_number(s->options, "visual-activity")) { TAILQ_FOREACH(c, &clients, entry) { if (c->session != s) continue; @@ -233,14 +233,14 @@ alerts_check_silence(struct session *s, struct winlink *wl) if (s->curw == wl && !(s->flags & SESSION_UNATTACHED)) return (0); - if (options_get_number(&w->options, "monitor-silence") == 0) + if (options_get_number(w->options, "monitor-silence") == 0) return (0); - if (options_get_number(&s->options, "bell-on-alert")) + if (options_get_number(s->options, "bell-on-alert")) alerts_ring_bell(s); wl->flags |= WINLINK_SILENCE; - if (options_get_number(&s->options, "visual-silence")) { + if (options_get_number(s->options, "visual-silence")) { TAILQ_FOREACH(c, &clients, entry) { if (c->session != s) continue; diff --git a/client.c b/client.c index 606feefe..aa453538 100644 --- a/client.c +++ b/client.c @@ -291,9 +291,9 @@ client_main(struct event_base *base, int argc, char **argv, int flags) fatal("pledge failed"); /* Free stuff that is not used in the client. */ - options_free(&global_options); - options_free(&global_s_options); - options_free(&global_w_options); + options_free(global_options); + options_free(global_s_options); + options_free(global_w_options); environ_free(&global_environ); /* Create stdin handler. */ diff --git a/cmd-attach-session.c b/cmd-attach-session.c index 4e390323..a3623ec4 100644 --- a/cmd-attach-session.c +++ b/cmd-attach-session.c @@ -121,7 +121,7 @@ cmd_attach_session(struct cmd_q *cmdq, const char *tflag, int dflag, int rflag, } if (!Eflag) { - update = options_get_string(&s->options, + update = options_get_string(s->options, "update-environment"); environ_update(update, &c->environ, &s->environ); } @@ -152,7 +152,7 @@ cmd_attach_session(struct cmd_q *cmdq, const char *tflag, int dflag, int rflag, } if (!Eflag) { - update = options_get_string(&s->options, + update = options_get_string(s->options, "update-environment"); environ_update(update, &c->environ, &s->environ); } diff --git a/cmd-break-pane.c b/cmd-break-pane.c index 2aa5c5b7..39179cc7 100644 --- a/cmd-break-pane.c +++ b/cmd-break-pane.c @@ -84,7 +84,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmd_q *cmdq) layout_init(w, wp); if (idx == -1) - idx = -1 - options_get_number(&dst_s->options, "base-index"); + idx = -1 - options_get_number(dst_s->options, "base-index"); wl = session_attach(dst_s, w, idx, &cause); /* can't fail */ if (!args_has(self->args, 'd')) session_select(dst_s, wl->idx); diff --git a/cmd-choose-buffer.c b/cmd-choose-buffer.c index b4590306..e790de6b 100644 --- a/cmd-choose-buffer.c +++ b/cmd-choose-buffer.c @@ -63,7 +63,7 @@ cmd_choose_buffer_exec(struct cmd *self, struct cmd_q *cmdq) if ((wl = cmd_find_window(cmdq, args_get(args, 't'), NULL)) == NULL) return (CMD_RETURN_ERROR); - utf8flag = options_get_number(&wl->window->options, "utf8"); + utf8flag = options_get_number(wl->window->options, "utf8"); if (paste_get_top(NULL) == NULL) return (CMD_RETURN_NORMAL); diff --git a/cmd-move-window.c b/cmd-move-window.c index b15df4f6..1bd46ab2 100644 --- a/cmd-move-window.c +++ b/cmd-move-window.c @@ -95,7 +95,7 @@ cmd_move_window_exec(struct cmd *self, struct cmd_q *cmdq) * session already has the correct winlink id to us, either * automatically or specified by -s. */ - if (!sflag && options_get_number(&src->options, "renumber-windows")) + if (!sflag && options_get_number(src->options, "renumber-windows")) session_renumber_windows(src); recalculate_sizes(); diff --git a/cmd-new-session.c b/cmd-new-session.c index f1a6167a..48828e54 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -197,7 +197,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) goto error; } } - if (sy > 0 && options_get_number(&global_s_options, "status")) + if (sy > 0 && options_get_number(global_s_options, "status")) sy--; if (sx == 0) sx = 1; @@ -211,7 +211,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) argc = args->argc; argv = args->argv; } else if (target == NULL) { - cmd = options_get_string(&global_s_options, "default-command"); + cmd = options_get_string(global_s_options, "default-command"); if (cmd != NULL && *cmd != '\0') { argc = 1; argv = &cmd; @@ -232,13 +232,13 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) /* Construct the environment. */ environ_init(&env); if (c != NULL && !args_has(args, 'E')) { - update = options_get_string(&global_s_options, + update = options_get_string(global_s_options, "update-environment"); environ_update(update, &c->environ, &env); } /* Create the new session. */ - idx = -1 - options_get_number(&global_s_options, "base-index"); + idx = -1 - options_get_number(global_s_options, "base-index"); s = session_create(newname, argc, argv, path, cwd, &env, tiop, idx, sx, sy, &cause); if (s == NULL) { @@ -252,7 +252,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) if (argc >= 0 && args_has(args, 'n')) { w = s->curw->window; window_set_name(w, args_get(args, 'n')); - options_set_number(&w->options, "automatic-rename", 0); + options_set_number(w->options, "automatic-rename", 0); } /* diff --git a/cmd-new-window.c b/cmd-new-window.c index 893fe6e2..a3712d76 100644 --- a/cmd-new-window.c +++ b/cmd-new-window.c @@ -71,7 +71,7 @@ cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq) detached = args_has(args, 'd'); if (args->argc == 0) { - cmd = options_get_string(&s->options, "default-command"); + cmd = options_get_string(s->options, "default-command"); if (cmd != NULL && *cmd != '\0') { argc = 1; argv = (char **)&cmd; @@ -136,7 +136,7 @@ cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq) } if (idx == -1) - idx = -1 - options_get_number(&s->options, "base-index"); + idx = -1 - options_get_number(s->options, "base-index"); wl = session_new(s, args_get(args, 'n'), argc, argv, path, cwd, idx, &cause); if (wl == NULL) { diff --git a/cmd-rename-window.c b/cmd-rename-window.c index 2f677a48..bc85d96b 100644 --- a/cmd-rename-window.c +++ b/cmd-rename-window.c @@ -47,7 +47,7 @@ cmd_rename_window_exec(struct cmd *self, struct cmd_q *cmdq) return (CMD_RETURN_ERROR); window_set_name(wl->window, args->argv[0]); - options_set_number(&wl->window->options, "automatic-rename", 0); + options_set_number(wl->window->options, "automatic-rename", 0); server_status_window(wl->window); diff --git a/cmd-send-keys.c b/cmd-send-keys.c index b1f8d672..dd796d60 100644 --- a/cmd-send-keys.c +++ b/cmd-send-keys.c @@ -70,9 +70,9 @@ cmd_send_keys_exec(struct cmd *self, struct cmd_q *cmdq) if (self->entry == &cmd_send_prefix_entry) { if (args_has(args, '2')) - key = options_get_number(&s->options, "prefix2"); + key = options_get_number(s->options, "prefix2"); else - key = options_get_number(&s->options, "prefix"); + key = options_get_number(s->options, "prefix"); window_pane_key(wp, NULL, s, key, NULL); return (CMD_RETURN_NORMAL); } diff --git a/cmd-set-option.c b/cmd-set-option.c index e0b07edb..6762e6ad 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -126,10 +126,10 @@ cmd_set_option_exec(struct cmd *self, struct cmd_q *cmdq) /* Work out the tree from the table. */ if (table == server_options_table) - oo = &global_options; + oo = global_options; else if (table == window_options_table) { if (args_has(self->args, 'g')) - oo = &global_w_options; + oo = global_w_options; else { wl = cmd_find_window(cmdq, args_get(args, 't'), NULL); if (wl == NULL) { @@ -139,11 +139,11 @@ cmd_set_option_exec(struct cmd *self, struct cmd_q *cmdq) 'g')) ? " need target window or -g" : ""); return (CMD_RETURN_ERROR); } - oo = &wl->window->options; + oo = wl->window->options; } } else if (table == session_options_table) { if (args_has(self->args, 'g')) - oo = &global_s_options; + oo = global_s_options; else { s = cmd_find_session(cmdq, args_get(args, 't'), 0); if (s == NULL) { @@ -153,7 +153,7 @@ cmd_set_option_exec(struct cmd *self, struct cmd_q *cmdq) 'g')) ? " need target session or -g" : ""); return (CMD_RETURN_ERROR); } - oo = &s->options; + oo = s->options; } } else { cmdq_error(cmdq, "unknown table"); @@ -179,7 +179,7 @@ cmd_set_option_exec(struct cmd *self, struct cmd_q *cmdq) /* Start or stop timers if necessary. */ if (strcmp(oe->name, "automatic-rename") == 0) { RB_FOREACH(w, windows, &windows) { - if (options_get_number(&w->options, "automatic-rename")) + if (options_get_number(w->options, "automatic-rename")) w->active->flags |= PANE_CHANGED; } } @@ -210,25 +210,25 @@ cmd_set_option_user(struct cmd *self, struct cmd_q *cmdq, const char *optstr, struct options *oo; if (args_has(args, 's')) - oo = &global_options; + oo = global_options; else if (args_has(self->args, 'w') || self->entry == &cmd_set_window_option_entry) { if (args_has(self->args, 'g')) - oo = &global_w_options; + oo = global_w_options; else { wl = cmd_find_window(cmdq, args_get(args, 't'), NULL); if (wl == NULL) return (CMD_RETURN_ERROR); - oo = &wl->window->options; + oo = wl->window->options; } } else { if (args_has(self->args, 'g')) - oo = &global_s_options; + oo = global_s_options; else { s = cmd_find_session(cmdq, args_get(args, 't'), 0); if (s == NULL) return (CMD_RETURN_ERROR); - oo = &s->options; + oo = s->options; } } @@ -276,7 +276,7 @@ cmd_set_option_unset(struct cmd *self, struct cmd_q *cmdq, return (-1); } - if (args_has(args, 'g') || oo == &global_options) { + if (args_has(args, 'g') || oo == global_options) { switch (oe->type) { case OPTIONS_TABLE_STRING: options_set_string(oo, oe->name, "%s", oe->default_str); diff --git a/cmd-show-options.c b/cmd-show-options.c index a5011e72..e99d665f 100644 --- a/cmd-show-options.c +++ b/cmd-show-options.c @@ -61,28 +61,28 @@ cmd_show_options_exec(struct cmd *self, struct cmd_q *cmdq) int quiet; if (args_has(self->args, 's')) { - oo = &global_options; + oo = global_options; table = server_options_table; } else if (args_has(self->args, 'w') || self->entry == &cmd_show_window_options_entry) { table = window_options_table; if (args_has(self->args, 'g')) - oo = &global_w_options; + oo = global_w_options; else { wl = cmd_find_window(cmdq, args_get(args, 't'), NULL); if (wl == NULL) return (CMD_RETURN_ERROR); - oo = &wl->window->options; + oo = wl->window->options; } } else { table = session_options_table; if (args_has(self->args, 'g')) - oo = &global_s_options; + oo = global_s_options; else { s = cmd_find_session(cmdq, args_get(args, 't'), 0); if (s == NULL) return (CMD_RETURN_ERROR); - oo = &s->options; + oo = s->options; } } @@ -151,13 +151,15 @@ cmd_show_options_all(struct cmd *self, struct cmd_q *cmdq, struct options_entry *o; const char *optval; - RB_FOREACH(o, options_tree, &oo->tree) { + o = options_first(oo); + while (o != NULL) { if (*o->name == '@') { if (args_has(self->args, 'v')) cmdq_print(cmdq, "%s", o->str); else cmdq_print(cmdq, "%s \"%s\"", o->name, o->str); } + o = options_next(o); } for (oe = table; oe->name != NULL; oe++) { diff --git a/cmd-split-window.c b/cmd-split-window.c index f397113f..60b04d77 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -73,7 +73,7 @@ cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq) server_fill_environ(s, &env); if (args->argc == 0) { - cmd = options_get_string(&s->options, "default-command"); + cmd = options_get_string(s->options, "default-command"); if (cmd != NULL && *cmd != '\0') { argc = 1; argv = (char **)&cmd; @@ -135,9 +135,9 @@ cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq) else size = (wp->sx * percentage) / 100; } - hlimit = options_get_number(&s->options, "history-limit"); + hlimit = options_get_number(s->options, "history-limit"); - shell = options_get_string(&s->options, "default-shell"); + shell = options_get_string(s->options, "default-shell"); if (*shell == '\0' || areshell(shell)) shell = _PATH_BSHELL; diff --git a/cmd-switch-client.c b/cmd-switch-client.c index 3a72886a..5a8c8b08 100644 --- a/cmd-switch-client.c +++ b/cmd-switch-client.c @@ -120,7 +120,7 @@ cmd_switch_client_exec(struct cmd *self, struct cmd_q *cmdq) } if (c != NULL && !args_has(args, 'E')) { - update = options_get_string(&s->options, "update-environment"); + update = options_get_string(s->options, "update-environment"); environ_update(update, &c->environ, &s->environ); } diff --git a/format.c b/format.c index 285bfadb..0add71e5 100644 --- a/format.c +++ b/format.c @@ -581,15 +581,15 @@ format_find(struct format_tree *ft, const char *key, int modifiers) found = NULL; if (~modifiers & FORMAT_TIMESTRING) { - o = options_find(&global_options, key); + o = options_find(global_options, key); if (o == NULL && ft->w != NULL) - o = options_find(&ft->w->options, key); + o = options_find(ft->w->options, key); if (o == NULL) - o = options_find(&global_w_options, key); + o = options_find(global_w_options, key); if (o == NULL && ft->s != NULL) - o = options_find(&ft->s->options, key); + o = options_find(ft->s->options, key); if (o == NULL) - o = options_find(&global_s_options, key); + o = options_find(global_s_options, key); if (o != NULL) { switch (o->type) { case OPTIONS_STRING: @@ -1101,7 +1101,7 @@ format_defaults_pane(struct format_tree *ft, struct window_pane *wp) format_add(ft, "pane_in_mode", "%d", wp->screen != &wp->base); format_add(ft, "pane_synchronized", "%d", - !!options_get_number(&wp->window->options, "synchronize-panes")); + !!options_get_number(wp->window->options, "synchronize-panes")); format_add(ft, "pane_tty", "%s", wp->tty); format_add(ft, "pane_pid", "%ld", (long) wp->pid); diff --git a/input-keys.c b/input-keys.c index 6e49dd3b..579c0f39 100644 --- a/input-keys.c +++ b/input-keys.c @@ -171,7 +171,7 @@ input_key(struct window_pane *wp, int key, struct mouse_event *m) * Then try to look this up as an xterm key, if the flag to output them * is set. */ - if (options_get_number(&wp->window->options, "xterm-keys")) { + if (options_get_number(wp->window->options, "xterm-keys")) { if ((out = xterm_keys_lookup(key)) != NULL) { bufferevent_write(wp->event, out, strlen(out)); free(out); diff --git a/input.c b/input.c index ab56fc38..3a02b0ce 100644 --- a/input.c +++ b/input.c @@ -1907,12 +1907,12 @@ input_exit_rename(struct input_ctx *ictx) { if (ictx->flags & INPUT_DISCARD) return; - if (!options_get_number(&ictx->wp->window->options, "allow-rename")) + if (!options_get_number(ictx->wp->window->options, "allow-rename")) return; log_debug("%s: \"%s\"", __func__, ictx->input_buf); window_set_name(ictx->wp->window, ictx->input_buf); - options_set_number(&ictx->wp->window->options, "automatic-rename", 0); + options_set_number(ictx->wp->window->options, "automatic-rename", 0); server_status_window(ictx->wp->window); } @@ -1921,7 +1921,7 @@ input_exit_rename(struct input_ctx *ictx) int input_utf8_open(struct input_ctx *ictx) { - if (!options_get_number(&ictx->wp->window->options, "utf8")) { + if (!options_get_number(ictx->wp->window->options, "utf8")) { /* Print, and do not switch state. */ input_print(ictx); return (-1); diff --git a/layout-set.c b/layout-set.c index da94cff2..852ec0f6 100644 --- a/layout-set.c +++ b/layout-set.c @@ -245,10 +245,10 @@ layout_set_main_h(struct window *w) width = (w->sx - (n - 1)) / columns; /* Get the main pane height and add one for separator line. */ - mainheight = options_get_number(&w->options, "main-pane-height") + 1; + mainheight = options_get_number(w->options, "main-pane-height") + 1; /* Get the optional other pane height and add one for separator line. */ - otherheight = options_get_number(&w->options, "other-pane-height") + 1; + otherheight = options_get_number(w->options, "other-pane-height") + 1; /* * If an other pane height was specified, honour it so long as it @@ -366,10 +366,10 @@ layout_set_main_v(struct window *w) height = (w->sy - (n - 1)) / rows; /* Get the main pane width and add one for separator line. */ - mainwidth = options_get_number(&w->options, "main-pane-width") + 1; + mainwidth = options_get_number(w->options, "main-pane-width") + 1; /* Get the optional other pane width and add one for separator line. */ - otherwidth = options_get_number(&w->options, "other-pane-width") + 1; + otherwidth = options_get_number(w->options, "other-pane-width") + 1; /* * If an other pane width was specified, honour it so long as it diff --git a/names.c b/names.c index e880c577..0e806ca0 100644 --- a/names.c +++ b/names.c @@ -58,7 +58,7 @@ check_window_name(struct window *w) if (w->active == NULL) return; - if (!options_get_number(&w->options, "automatic-rename")) + if (!options_get_number(w->options, "automatic-rename")) return; if (~w->active->flags & PANE_CHANGED) { @@ -122,7 +122,7 @@ format_window_name(struct window *w) format_defaults_window(ft, w); format_defaults_pane(ft, w->active); - fmt = options_get_string(&w->options, "automatic-rename-format"); + fmt = options_get_string(w->options, "automatic-rename-format"); name = format_expand(ft, fmt); format_free(ft); diff --git a/options.c b/options.c index 030cfd51..487918fd 100644 --- a/options.c +++ b/options.c @@ -29,6 +29,13 @@ * a red-black tree. */ +struct options { + RB_HEAD(options_tree, options_entry) tree; + struct options *parent; +}; + +int options_cmp(struct options_entry *, struct options_entry *); +RB_PROTOTYPE(options_tree, options_entry, entry, options_cmp); RB_GENERATE(options_tree, options_entry, entry, options_cmp); int @@ -37,11 +44,15 @@ options_cmp(struct options_entry *o1, struct options_entry *o2) return (strcmp(o1->name, o2->name)); } -void -options_init(struct options *oo, struct options *parent) +struct options * +options_create(struct options *parent) { + struct options *oo; + + oo = xcalloc(1, sizeof *oo); RB_INIT(&oo->tree); oo->parent = parent; + return (oo); } void @@ -57,6 +68,19 @@ options_free(struct options *oo) free(o->str); free(o); } + free(oo); +} + +struct options_entry * +options_first(struct options *oo) +{ + return (RB_MIN(options_tree, &oo->tree)); +} + +struct options_entry * +options_next(struct options_entry *o) +{ + return (RB_NEXT(options_tree, &oo->tree, o)); } struct options_entry * diff --git a/paste.c b/paste.c index 44f88d0b..ad3b56b5 100644 --- a/paste.c +++ b/paste.c @@ -151,7 +151,7 @@ paste_add(char *data, size_t size) if (size == 0) return; - limit = options_get_number(&global_options, "buffer-limit"); + limit = options_get_number(global_options, "buffer-limit"); RB_FOREACH_REVERSE_SAFE(pb, paste_time_tree, &paste_by_time, pb1) { if (paste_num_automatic < limit) break; diff --git a/resize.c b/resize.c index 3606bfeb..c7805e05 100644 --- a/resize.c +++ b/resize.c @@ -53,7 +53,7 @@ recalculate_sizes(void) int flag, has_status, is_zoomed, forced; RB_FOREACH(s, sessions, &sessions) { - has_status = options_get_number(&s->options, "status"); + has_status = options_get_number(s->options, "status"); s->attached = 0; ssx = ssy = UINT_MAX; @@ -94,7 +94,7 @@ recalculate_sizes(void) RB_FOREACH(w, windows, &windows) { if (w->active == NULL) continue; - flag = options_get_number(&w->options, "aggressive-resize"); + flag = options_get_number(w->options, "aggressive-resize"); ssx = ssy = UINT_MAX; RB_FOREACH(s, sessions, &sessions) { @@ -115,12 +115,12 @@ recalculate_sizes(void) continue; forced = 0; - limit = options_get_number(&w->options, "force-width"); + limit = options_get_number(w->options, "force-width"); if (limit >= PANE_MINIMUM && ssx > limit) { ssx = limit; forced |= WINDOW_FORCEWIDTH; } - limit = options_get_number(&w->options, "force-height"); + limit = options_get_number(w->options, "force-height"); if (limit >= PANE_MINIMUM && ssy > limit) { ssy = limit; forced |= WINDOW_FORCEHEIGHT; diff --git a/screen-redraw.c b/screen-redraw.c index 799f5c55..fd4536d0 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -222,7 +222,7 @@ void screen_redraw_screen(struct client *c, int draw_panes, int draw_status, int draw_borders) { - struct options *oo = &c->session->options; + struct options *oo = c->session->options; struct tty *tty = &c->tty; u_int top; int status, spos; @@ -276,7 +276,7 @@ screen_redraw_draw_borders(struct client *c, int status, u_int top) { struct session *s = c->session; struct window *w = s->curw->window; - struct options *oo = &w->options; + struct options *oo = w->options; struct tty *tty = &c->tty; struct window_pane *wp; struct grid_cell m_active_gc, active_gc, m_other_gc, other_gc; @@ -392,7 +392,7 @@ screen_redraw_draw_number(struct client *c, struct window_pane *wp, u_int top) { struct tty *tty = &c->tty; struct session *s = c->session; - struct options *oo = &s->options; + struct options *oo = s->options; struct window *w = wp->window; struct grid_cell gc; u_int idx, px, py, i, j, xoff, yoff; diff --git a/server-client.c b/server-client.c index 13f905b2..8d6eefa0 100644 --- a/server-client.c +++ b/server-client.c @@ -490,7 +490,7 @@ server_client_assume_paste(struct session *s) struct timeval tv; int t; - if ((t = options_get_number(&s->options, "assume-paste-time")) == 0) + if ((t = options_get_number(s->options, "assume-paste-time")) == 0) return (0); timersub(&s->activity_time, &s->last_activity_time, &tv); @@ -556,7 +556,7 @@ server_client_handle_key(struct client *c, int key) m->valid = 1; m->key = key; - if (!options_get_number(&s->options, "mouse")) + if (!options_get_number(s->options, "mouse")) goto forward; } else m->valid = 0; @@ -593,7 +593,7 @@ retry: * If this is a repeating key, start the timer. Otherwise reset * the client back to the root table. */ - xtimeout = options_get_number(&s->options, "repeat-time"); + xtimeout = options_get_number(s->options, "repeat-time"); if (xtimeout != 0 && bd->can_repeat) { c->flags |= CLIENT_REPEAT; @@ -635,8 +635,8 @@ retry: * No match, but in the root table. Prefix switches to the prefix table * and everything else is passed through. */ - if (key == options_get_number(&s->options, "prefix") || - key == options_get_number(&s->options, "prefix2")) { + if (key == options_get_number(s->options, "prefix") || + key == options_get_number(s->options, "prefix2")) { server_client_key_table(c, "prefix"); server_status_client(c); return; @@ -713,7 +713,7 @@ server_client_check_focus(struct window_pane *wp) int push; /* Are focus events off? */ - if (!options_get_number(&global_options, "focus-events")) + if (!options_get_number(global_options, "focus-events")) return; /* Do we need to push the focus state? */ @@ -773,7 +773,7 @@ server_client_reset_state(struct client *c) struct window *w = c->session->curw->window; struct window_pane *wp = w->active; struct screen *s = wp->screen; - struct options *oo = &c->session->options; + struct options *oo = c->session->options; int status, mode, o; if (c->flags & CLIENT_SUSPENDED) @@ -862,7 +862,7 @@ server_client_check_redraw(struct client *c) return; if (c->flags & (CLIENT_REDRAW|CLIENT_STATUS)) { - if (options_get_number(&s->options, "set-titles")) + if (options_get_number(s->options, "set-titles")) server_client_set_title(c); if (c->message_string != NULL) @@ -922,7 +922,7 @@ server_client_set_title(struct client *c) char *title; struct format_tree *ft; - template = options_get_string(&s->options, "set-titles-string"); + template = options_get_string(s->options, "set-titles-string"); ft = format_create(); format_defaults(ft, c, NULL, NULL, NULL); @@ -1206,7 +1206,7 @@ server_client_dispatch_shell(struct client *c) { const char *shell; - shell = options_get_string(&global_s_options, "default-shell"); + shell = options_get_string(global_s_options, "default-shell"); if (*shell == '\0' || areshell(shell)) shell = _PATH_BSHELL; proc_send_s(c->peer, MSG_SHELL, shell); diff --git a/server-fn.c b/server-fn.c index 095535ab..e9a04cb5 100644 --- a/server-fn.c +++ b/server-fn.c @@ -39,7 +39,7 @@ server_fill_environ(struct session *s, struct environ *env) long pid; if (s != NULL) { - term = options_get_string(&global_options, "default-terminal"); + term = options_get_string(global_options, "default-terminal"); environ_set(env, "TERM", term); idx = s->id; @@ -183,7 +183,7 @@ server_lock_client(struct client *c) if (c->flags & CLIENT_SUSPENDED) return; - cmd = options_get_string(&c->session->options, "lock-command"); + cmd = options_get_string(c->session->options, "lock-command"); if (strlen(cmd) + 1 > MAX_IMSGSIZE - IMSG_HEADER_SIZE) return; @@ -219,7 +219,7 @@ server_kill_window(struct window *w) server_redraw_session_group(s); } - if (options_get_number(&s->options, "renumber-windows")) { + if (options_get_number(s->options, "renumber-windows")) { if ((sg = session_group_find(s)) != NULL) { TAILQ_FOREACH(target_s, &sg->sessions, gentry) session_renumber_windows(target_s); @@ -272,7 +272,7 @@ server_link_window(struct session *src, struct winlink *srcwl, } if (dstidx == -1) - dstidx = -1 - options_get_number(&dst->options, "base-index"); + dstidx = -1 - options_get_number(dst->options, "base-index"); dstwl = session_attach(dst, srcwl->window, dstidx, cause); if (dstwl == NULL) return (-1); @@ -308,7 +308,7 @@ server_destroy_pane(struct window_pane *wp) wp->fd = -1; } - if (options_get_number(&w->options, "remain-on-exit")) { + if (options_get_number(w->options, "remain-on-exit")) { if (old_fd == -1) return; screen_write_start(&ctx, wp, &wp->base); @@ -371,7 +371,7 @@ server_destroy_session(struct session *s) struct client *c; struct session *s_new; - if (!options_get_number(&s->options, "detach-on-destroy")) + if (!options_get_number(s->options, "detach-on-destroy")) s_new = server_next_session(s); else s_new = NULL; @@ -407,7 +407,7 @@ server_check_unattached(void) RB_FOREACH(s, sessions, &sessions) { if (!(s->flags & SESSION_UNATTACHED)) continue; - if (options_get_number (&s->options, "destroy-unattached")) + if (options_get_number (s->options, "destroy-unattached")) session_destroy(s); } } @@ -418,7 +418,7 @@ server_set_identify(struct client *c) struct timeval tv; int delay; - delay = options_get_number(&c->session->options, "display-panes-time"); + delay = options_get_number(c->session->options, "display-panes-time"); tv.tv_sec = delay / 1000; tv.tv_usec = (delay % 1000) * 1000L; diff --git a/server.c b/server.c index a36e9a73..2af2c442 100644 --- a/server.c +++ b/server.c @@ -217,7 +217,7 @@ server_loop(void) server_client_loop(); - if (!options_get_number(&global_options, "exit-unattached")) { + if (!options_get_number(global_options, "exit-unattached")) { if (!RB_EMPTY(&sessions)) return (0); } diff --git a/session.c b/session.c index a929cada..6b641d48 100644 --- a/session.c +++ b/session.c @@ -120,10 +120,10 @@ session_create(const char *name, int argc, char **argv, const char *path, TAILQ_INIT(&s->lastw); RB_INIT(&s->windows); - options_init(&s->options, &global_s_options); environ_init(&s->environ); if (env != NULL) environ_copy(env, &s->environ); + s->options = options_create(global_s_options); s->tio = NULL; if (tio != NULL) { @@ -190,6 +190,9 @@ session_free(unused int fd, unused short events, void *arg) log_debug("session %s freed (%d references)", s->name, s->references); if (s->references == 0) { + environ_free(&s->environ); + options_free(s->options); + free(s->name); free(s); } @@ -212,8 +215,6 @@ session_destroy(struct session *s) event_del(&s->lock_timer); session_group_remove(s); - environ_free(&s->environ); - options_free(&s->options); while (!TAILQ_EMPTY(&s->lastw)) winlink_stack_remove(&s->lastw, TAILQ_FIRST(&s->lastw)); @@ -271,7 +272,7 @@ session_update_activity(struct session *s, struct timeval *from) if (~s->flags & SESSION_UNATTACHED) { timerclear(&tv); - tv.tv_sec = options_get_number(&s->options, "lock-after-time"); + tv.tv_sec = options_get_number(s->options, "lock-after-time"); if (tv.tv_sec != 0) evtimer_add(&s->lock_timer, &tv); } @@ -332,11 +333,11 @@ session_new(struct session *s, const char *name, int argc, char **argv, environ_copy(&s->environ, &env); server_fill_environ(s, &env); - shell = options_get_string(&s->options, "default-shell"); + shell = options_get_string(s->options, "default-shell"); if (*shell == '\0' || areshell(shell)) shell = _PATH_BSHELL; - hlimit = options_get_number(&s->options, "history-limit"); + hlimit = options_get_number(s->options, "history-limit"); w = window_create(name, argc, argv, path, shell, cwd, &env, s->tio, s->sx, s->sy, hlimit, cause); if (w == NULL) { @@ -348,8 +349,8 @@ session_new(struct session *s, const char *name, int argc, char **argv, notify_window_linked(s, w); environ_free(&env); - if (options_get_number(&s->options, "set-remain-on-exit")) - options_set_number(&w->options, "remain-on-exit", 1); + if (options_get_number(s->options, "set-remain-on-exit")) + options_set_number(w->options, "remain-on-exit", 1); session_group_synchronize_from(s); return (wl); @@ -712,7 +713,7 @@ session_renumber_windows(struct session *s) RB_INIT(&s->windows); /* Start renumbering from the base-index if it's set. */ - new_idx = options_get_number(&s->options, "base-index"); + new_idx = options_get_number(s->options, "base-index"); new_curw_idx = 0; /* Go through the winlinks and assign new indexes. */ diff --git a/status.c b/status.c index e17c1f5d..a2f46b95 100644 --- a/status.c +++ b/status.c @@ -61,7 +61,7 @@ status_prompt_find_history_file(void) const char *home, *history_file; char *path; - history_file = options_get_string(&global_options, "history-file"); + history_file = options_get_string(global_options, "history-file"); if (*history_file == '\0') return (NULL); if (*history_file == '/') @@ -160,7 +160,7 @@ status_timer_callback(unused int fd, unused short events, void *arg) c->flags |= CLIENT_STATUS; timerclear(&tv); - tv.tv_sec = options_get_number(&s->options, "status-interval"); + tv.tv_sec = options_get_number(s->options, "status-interval"); if (tv.tv_sec != 0) evtimer_add(&c->status_timer, &tv); @@ -178,7 +178,7 @@ status_timer_start(struct client *c) else evtimer_set(&c->status_timer, status_timer_callback, c); - if (s != NULL && options_get_number(&s->options, "status")) + if (s != NULL && options_get_number(s->options, "status")) status_timer_callback(-1, 0, c); } @@ -198,10 +198,10 @@ status_at_line(struct client *c) { struct session *s = c->session; - if (!options_get_number(&s->options, "status")) + if (!options_get_number(s->options, "status")) return (-1); - if (options_get_number(&s->options, "status-position") == 0) + if (options_get_number(s->options, "status-position") == 0) return (0); return (c->tty.sy - 1); } @@ -216,12 +216,12 @@ status_redraw_get_left(struct client *c, time_t t, int utf8flag, char *left; size_t leftlen; - style_apply_update(gc, &s->options, "status-left-style"); + style_apply_update(gc, s->options, "status-left-style"); - template = options_get_string(&s->options, "status-left"); + template = options_get_string(s->options, "status-left"); left = status_replace(c, NULL, template, t); - *size = options_get_number(&s->options, "status-left-length"); + *size = options_get_number(s->options, "status-left-length"); leftlen = screen_write_cstrlen(utf8flag, "%s", left); if (leftlen < *size) *size = leftlen; @@ -238,12 +238,12 @@ status_redraw_get_right(struct client *c, time_t t, int utf8flag, char *right; size_t rightlen; - style_apply_update(gc, &s->options, "status-right-style"); + style_apply_update(gc, s->options, "status-right-style"); - template = options_get_string(&s->options, "status-right"); + template = options_get_string(s->options, "status-right"); right = status_replace(c, NULL, template, t); - *size = options_get_number(&s->options, "status-right-length"); + *size = options_get_number(s->options, "status-right-length"); rightlen = screen_write_cstrlen(utf8flag, "%s", right); if (rightlen < *size) *size = rightlen; @@ -261,7 +261,7 @@ status_get_window_at(struct client *c, u_int x) x += c->wlmouse; RB_FOREACH(wl, winlinks, &s->windows) { - oo = &wl->window->options; + oo = wl->window->options; len = strlen(options_get_string(oo, "window-status-separator")); if (x < wl->status_width) @@ -289,7 +289,7 @@ status_redraw(struct client *c) int larrow, rarrow, utf8flag; /* No status line? */ - if (c->tty.sy == 0 || !options_get_number(&s->options, "status")) + if (c->tty.sy == 0 || !options_get_number(s->options, "status")) return (1); left = right = NULL; larrow = rarrow = 0; @@ -298,7 +298,7 @@ status_redraw(struct client *c) t = time(NULL); /* Set up default colour. */ - style_apply(&stdgc, &s->options, "status-style"); + style_apply(&stdgc, s->options, "status-style"); /* Create the target screen. */ memcpy(&old_status, &c->status, sizeof old_status); @@ -313,7 +313,7 @@ status_redraw(struct client *c) goto out; /* Get UTF-8 flag. */ - utf8flag = options_get_number(&s->options, "status-utf8"); + utf8flag = options_get_number(s->options, "status-utf8"); /* Work out left and right strings. */ memcpy(&lgc, &stdgc, sizeof lgc); @@ -346,7 +346,7 @@ status_redraw(struct client *c) if (wl == s->curw) wloffset = wlwidth; - oo = &wl->window->options; + oo = wl->window->options; sep = options_get_string(oo, "window-status-separator"); seplen = screen_write_strlen(utf8flag, "%s", sep); wlwidth += wl->status_width + seplen; @@ -361,7 +361,7 @@ status_redraw(struct client *c) screen_write_cnputs(&ctx, -1, &wl->status_cell, utf8flag, "%s", wl->status_text); - oo = &wl->window->options; + oo = wl->window->options; sep = options_get_string(oo, "window-status-separator"); screen_write_nputs(&ctx, -1, &stdgc, utf8flag, "%s", sep); } @@ -461,7 +461,7 @@ draw: else wloffset = 0; if (wlwidth < wlavailable) { - switch (options_get_number(&s->options, "status-justify")) { + switch (options_get_number(s->options, "status-justify")) { case 1: /* centred */ wloffset += (wlavailable - wlwidth) / 2; break; @@ -520,7 +520,7 @@ char * status_print(struct client *c, struct winlink *wl, time_t t, struct grid_cell *gc) { - struct options *oo = &wl->window->options; + struct options *oo = wl->window->options; struct session *s = c->session; const char *fmt; char *text; @@ -553,7 +553,7 @@ status_message_set(struct client *c, const char *fmt, ...) int delay; u_int first, limit; - limit = options_get_number(&global_options, "message-limit"); + limit = options_get_number(global_options, "message-limit"); status_prompt_clear(c); status_message_clear(c); @@ -577,7 +577,7 @@ status_message_set(struct client *c, const char *fmt, ...) free(msg); } - delay = options_get_number(&c->session->options, "display-time"); + delay = options_get_number(c->session->options, "display-time"); tv.tv_sec = delay / 1000; tv.tv_usec = (delay % 1000) * 1000L; @@ -631,13 +631,13 @@ status_message_redraw(struct client *c) memcpy(&old_status, &c->status, sizeof old_status); screen_init(&c->status, c->tty.sx, 1, 0); - utf8flag = options_get_number(&s->options, "status-utf8"); + utf8flag = options_get_number(s->options, "status-utf8"); len = screen_write_strlen(utf8flag, "%s", c->message_string); if (len > c->tty.sx) len = c->tty.sx; - style_apply(&gc, &s->options, "message-style"); + style_apply(&gc, s->options, "message-style"); screen_write_start(&ctx, NULL, &c->status); @@ -686,7 +686,7 @@ status_prompt_set(struct client *c, const char *msg, const char *input, c->prompt_flags = flags; - keys = options_get_number(&c->session->options, "status-keys"); + keys = options_get_number(c->session->options, "status-keys"); if (keys == MODEKEY_EMACS) mode_key_init(&c->prompt_mdata, &mode_key_tree_emacs_edit); else @@ -761,7 +761,7 @@ status_prompt_redraw(struct client *c) memcpy(&old_status, &c->status, sizeof old_status); screen_init(&c->status, c->tty.sx, 1, 0); - utf8flag = options_get_number(&s->options, "status-utf8"); + utf8flag = options_get_number(s->options, "status-utf8"); len = screen_write_strlen(utf8flag, "%s", c->prompt_string); if (len > c->tty.sx) @@ -770,9 +770,9 @@ status_prompt_redraw(struct client *c) /* Change colours for command mode. */ if (c->prompt_mdata.mode == 1) - style_apply(&gc, &s->options, "message-command-style"); + style_apply(&gc, s->options, "message-command-style"); else - style_apply(&gc, &s->options, "message-style"); + style_apply(&gc, s->options, "message-style"); screen_write_start(&ctx, NULL, &c->status); @@ -815,7 +815,7 @@ void status_prompt_key(struct client *c, int key) { struct session *sess = c->session; - struct options *oo = &sess->options; + struct options *oo = sess->options; struct paste_buffer *pb; char *s, *first, *last, word[64], swapc; const char *histstr, *bufdata, *wsep = NULL; diff --git a/tmux.c b/tmux.c index 01e73f5d..bdc426f9 100644 --- a/tmux.c +++ b/tmux.c @@ -38,9 +38,9 @@ extern char *malloc_options; #endif -struct options global_options; /* server options */ -struct options global_s_options; /* session options */ -struct options global_w_options; /* window options */ +struct options *global_options; /* server options */ +struct options *global_s_options; /* session options */ +struct options *global_w_options; /* window options */ struct environ global_environ; char *shell_cmd; @@ -281,22 +281,21 @@ main(int argc, char **argv) if (getcwd(tmp, sizeof tmp) != NULL) environ_set(&global_environ, "PWD", tmp); - options_init(&global_options, NULL); - options_table_populate_tree(server_options_table, &global_options); + global_options = options_create(NULL); + options_table_populate_tree(server_options_table, global_options); - options_init(&global_s_options, NULL); - options_table_populate_tree(session_options_table, &global_s_options); - options_set_string(&global_s_options, "default-shell", "%s", - getshell()); + global_s_options = options_create(NULL); + options_table_populate_tree(session_options_table, global_s_options); + options_set_string(global_s_options, "default-shell", "%s", getshell()); - options_init(&global_w_options, NULL); - options_table_populate_tree(window_options_table, &global_w_options); + global_w_options = options_create(NULL); + options_table_populate_tree(window_options_table, global_w_options); /* Enable UTF-8 if the first client is on UTF-8 terminal. */ if (flags & CLIENT_UTF8) { - options_set_number(&global_s_options, "status-utf8", 1); - options_set_number(&global_s_options, "mouse-utf8", 1); - options_set_number(&global_w_options, "utf8", 1); + options_set_number(global_s_options, "status-utf8", 1); + options_set_number(global_s_options, "mouse-utf8", 1); + options_set_number(global_w_options, "utf8", 1); } /* Override keys to vi if VISUAL or EDITOR are set. */ @@ -307,8 +306,8 @@ main(int argc, char **argv) keys = MODEKEY_VI; else keys = MODEKEY_EMACS; - options_set_number(&global_s_options, "status-keys", keys); - options_set_number(&global_w_options, "mode-keys", keys); + options_set_number(global_s_options, "status-keys", keys); + options_set_number(global_w_options, "mode-keys", keys); } /* diff --git a/tmux.h b/tmux.h index c4b12402..3b2d2d10 100644 --- a/tmux.h +++ b/tmux.h @@ -680,11 +680,6 @@ struct options_entry { RB_ENTRY(options_entry) entry; }; -struct options { - RB_HEAD(options_tree, options_entry) tree; - struct options *parent; -}; - /* Scheduled job. */ struct job { enum { @@ -866,6 +861,7 @@ TAILQ_HEAD(window_panes, window_pane); RB_HEAD(window_pane_tree, window_pane); /* Window structure. */ +struct options; struct window { u_int id; @@ -899,7 +895,7 @@ struct window { #define WINDOW_FORCEHEIGHT 0x4000 #define WINDOW_ALERTFLAGS (WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_SILENCE) - struct options options; + struct options *options; u_int references; @@ -993,7 +989,7 @@ struct session { struct winlink_stack lastw; struct winlinks windows; - struct options options; + struct options *options; #define SESSION_UNATTACHED 0x1 /* not attached to any clients */ int flags; @@ -1405,9 +1401,9 @@ struct options_table_entry { #define CMD_BUFFER_USAGE "[-b buffer-name]" /* tmux.c */ -extern struct options global_options; -extern struct options global_s_options; -extern struct options global_w_options; +extern struct options *global_options; +extern struct options *global_s_options; +extern struct options *global_w_options; extern struct environ global_environ; extern char *shell_cmd; extern int debug_level; @@ -1509,10 +1505,10 @@ void notify_session_created(struct session *); void notify_session_closed(struct session *); /* options.c */ -int options_cmp(struct options_entry *, struct options_entry *); -RB_PROTOTYPE(options_tree, options_entry, entry, options_cmp); -void options_init(struct options *, struct options *); +struct options *options_create(struct options *); void options_free(struct options *); +struct options_entry *options_first(struct options *); +struct options_entry *options_next(struct options_entry *); struct options_entry *options_find1(struct options *, const char *); struct options_entry *options_find(struct options *, const char *); void options_remove(struct options *, const char *); diff --git a/tty-keys.c b/tty-keys.c index c1de2ab7..309e8c04 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -564,7 +564,7 @@ partial_key: } /* Get the time period. */ - delay = options_get_number(&global_options, "escape-time"); + delay = options_get_number(global_options, "escape-time"); tv.tv_sec = delay / 1000; tv.tv_usec = (delay % 1000) * 1000L; diff --git a/tty-term.c b/tty-term.c index 76626ddf..c6147559 100644 --- a/tty-term.c +++ b/tty-term.c @@ -457,7 +457,7 @@ tty_term_find(char *name, int fd, char **cause) } /* Apply terminal overrides. */ - s = options_get_string(&global_options, "terminal-overrides"); + s = options_get_string(global_options, "terminal-overrides"); tty_term_override(term, s); /* Delete curses data. */ diff --git a/tty.c b/tty.c index 3d6f29ca..6b6343c8 100644 --- a/tty.c +++ b/tty.c @@ -229,7 +229,7 @@ tty_start_tty(struct tty *tty) tty_puts(tty, "\033[?1000l\033[?1002l\033[?1006l\033[?1005l"); if (tty_term_flag(tty->term, TTYC_XT)) { - if (options_get_number(&global_options, "focus-events")) { + if (options_get_number(global_options, "focus-events")) { tty->flags |= TTY_FOCUS; tty_puts(tty, "\033[?1004h"); } @@ -457,7 +457,7 @@ tty_set_italics(struct tty *tty) const char *s; if (tty_term_has(tty->term, TTYC_SITM)) { - s = options_get_string(&global_options, "default-terminal"); + s = options_get_string(global_options, "default-terminal"); if (strcmp(s, "screen") != 0 && strncmp(s, "screen-", 7) != 0) { tty_putcode(tty, TTYC_SITM); return; @@ -1686,8 +1686,8 @@ tty_default_colours(struct grid_cell *gc, const struct window_pane *wp) return; pgc = &wp->colgc; - agc = options_get_style(&wp->window->options, "window-active-style"); - wgc = options_get_style(&wp->window->options, "window-style"); + agc = options_get_style(wp->window->options, "window-active-style"); + wgc = options_get_style(wp->window->options, "window-style"); if (gc->fg == 8 && !(gc->flags & GRID_FLAG_FG256)) { if (pgc->fg != 8 || (pgc->flags & GRID_FLAG_FG256)) { diff --git a/window-choose.c b/window-choose.c index 37baf0d7..f1c3f94a 100644 --- a/window-choose.c +++ b/window-choose.c @@ -169,7 +169,7 @@ window_choose_init(struct window_pane *wp) screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0); s->mode &= ~MODE_CURSOR; - keys = options_get_number(&wp->window->options, "mode-keys"); + keys = options_get_number(wp->window->options, "mode-keys"); if (keys == MODEKEY_EMACS) mode_key_init(&data->mdata, &mode_key_tree_emacs_choice); else @@ -748,7 +748,7 @@ window_choose_write_line( { struct window_choose_mode_data *data = wp->modedata; struct window_choose_mode_item *item; - struct options *oo = &wp->window->options; + struct options *oo = wp->window->options; struct screen *s = &data->screen; struct grid_cell gc; size_t last, xoff = 0; @@ -759,7 +759,7 @@ window_choose_write_line( fatalx("called before callback assigned"); last = screen_size_y(s) - 1; - utf8flag = options_get_number(&wp->window->options, "utf8"); + utf8flag = options_get_number(wp->window->options, "utf8"); memcpy(&gc, &grid_default_cell, sizeof gc); if (data->selected == data->top + py) style_apply(&gc, oo, "mode-style"); diff --git a/window-clock.c b/window-clock.c index 5bc546a9..e366714b 100644 --- a/window-clock.c +++ b/window-clock.c @@ -204,8 +204,8 @@ window_clock_draw_screen(struct window_pane *wp) struct tm *tm; u_int i, j, x, y, idx; - colour = options_get_number(&wp->window->options, "clock-mode-colour"); - style = options_get_number(&wp->window->options, "clock-mode-style"); + colour = options_get_number(wp->window->options, "clock-mode-colour"); + style = options_get_number(wp->window->options, "clock-mode-style"); screen_write_start(&ctx, NULL, s); diff --git a/window-copy.c b/window-copy.c index f81a2a16..3ba27c80 100644 --- a/window-copy.c +++ b/window-copy.c @@ -195,7 +195,7 @@ window_copy_init(struct window_pane *wp) s = &data->screen; screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0); - keys = options_get_number(&wp->window->options, "mode-keys"); + keys = options_get_number(wp->window->options, "mode-keys"); if (keys == MODEKEY_EMACS) mode_key_init(&data->mdata, &mode_key_tree_emacs_copy); else @@ -286,7 +286,7 @@ window_copy_vadd(struct window_pane *wp, const char *fmt, va_list ap) if (backing == &wp->base) return; - utf8flag = options_get_number(&wp->window->options, "utf8"); + utf8flag = options_get_number(wp->window->options, "utf8"); memcpy(&gc, &grid_default_cell, sizeof gc); old_hsize = screen_hsize(data->backing); @@ -629,13 +629,13 @@ window_copy_key(struct window_pane *wp, struct client *c, struct session *sess, break; case MODEKEYCOPY_NEXTWORD: word_separators = - options_get_string(&sess->options, "word-separators"); + options_get_string(sess->options, "word-separators"); for (; np != 0; np--) window_copy_cursor_next_word(wp, word_separators); break; case MODEKEYCOPY_NEXTWORDEND: word_separators = - options_get_string(&sess->options, "word-separators"); + options_get_string(sess->options, "word-separators"); for (; np != 0; np--) window_copy_cursor_next_word_end(wp, word_separators); break; @@ -645,7 +645,7 @@ window_copy_key(struct window_pane *wp, struct client *c, struct session *sess, break; case MODEKEYCOPY_PREVIOUSWORD: word_separators = - options_get_string(&sess->options, "word-separators"); + options_get_string(sess->options, "word-separators"); for (; np != 0; np--) window_copy_cursor_previous_word(wp, word_separators); break; @@ -777,7 +777,7 @@ window_copy_key(struct window_pane *wp, struct client *c, struct session *sess, return; input_on: - keys = options_get_number(&wp->window->options, "mode-keys"); + keys = options_get_number(wp->window->options, "mode-keys"); if (keys == MODEKEY_EMACS) mode_key_init(&data->mdata, &mode_key_tree_emacs_edit); else @@ -787,7 +787,7 @@ input_on: return; input_off: - keys = options_get_number(&wp->window->options, "mode-keys"); + keys = options_get_number(wp->window->options, "mode-keys"); if (keys == MODEKEY_EMACS) mode_key_init(&data->mdata, &mode_key_tree_emacs_copy); else @@ -1026,8 +1026,8 @@ window_copy_search_up(struct window_pane *wp, const char *searchstr) if (*searchstr == '\0') return; - utf8flag = options_get_number(&wp->window->options, "utf8"); - wrapflag = options_get_number(&wp->window->options, "wrap-search"); + utf8flag = options_get_number(wp->window->options, "utf8"); + wrapflag = options_get_number(wp->window->options, "wrap-search"); searchlen = screen_write_strlen(utf8flag, "%s", searchstr); screen_init(&ss, searchlen, 1, 0); @@ -1093,8 +1093,8 @@ window_copy_search_down(struct window_pane *wp, const char *searchstr) if (*searchstr == '\0') return; - utf8flag = options_get_number(&wp->window->options, "utf8"); - wrapflag = options_get_number(&wp->window->options, "wrap-search"); + utf8flag = options_get_number(wp->window->options, "utf8"); + wrapflag = options_get_number(wp->window->options, "wrap-search"); searchlen = screen_write_strlen(utf8flag, "%s", searchstr); screen_init(&ss, searchlen, 1, 0); @@ -1168,7 +1168,7 @@ window_copy_write_line(struct window_pane *wp, struct screen_write_ctx *ctx, { struct window_copy_mode_data *data = wp->modedata; struct screen *s = &data->screen; - struct options *oo = &wp->window->options; + struct options *oo = wp->window->options; struct grid_cell gc; char hdr[512]; size_t last, xoff = 0, size = 0, limit; @@ -1301,7 +1301,7 @@ window_copy_update_selection(struct window_pane *wp, int may_redraw) { struct window_copy_mode_data *data = wp->modedata; struct screen *s = &data->screen; - struct options *oo = &wp->window->options; + struct options *oo = wp->window->options; struct grid_cell gc; u_int sx, sy, ty, cy; @@ -1401,7 +1401,7 @@ window_copy_get_selection(struct window_pane *wp, size_t *len) * bottom-right-most, regardless of copy direction. If it is vi, also * keep bottom-right-most character. */ - keys = options_get_number(&wp->window->options, "mode-keys"); + keys = options_get_number(wp->window->options, "mode-keys"); if (data->rectflag) { /* * Need to ignore the column with the cursor in it, which for @@ -1460,7 +1460,7 @@ window_copy_copy_buffer(struct window_pane *wp, const char *bufname, void *buf, { struct screen_write_ctx ctx; - if (options_get_number(&global_options, "set-clipboard")) { + if (options_get_number(global_options, "set-clipboard")) { screen_write_start(&ctx, wp, NULL); screen_write_setselection(&ctx, buf, len); screen_write_stop(&ctx); @@ -1523,7 +1523,7 @@ window_copy_append_selection(struct window_pane *wp, const char *bufname) if (buf == NULL) return; - if (options_get_number(&global_options, "set-clipboard")) { + if (options_get_number(global_options, "set-clipboard")) { screen_write_start(&ctx, wp, NULL); screen_write_setselection(&ctx, buf, len); screen_write_stop(&ctx); @@ -2074,7 +2074,7 @@ window_copy_cursor_next_word_end(struct window_pane *wp, const char *separators) { struct window_copy_mode_data *data = wp->modedata; - struct options *oo = &wp->window->options; + struct options *oo = wp->window->options; struct screen *back_s = data->backing; u_int px, py, xx, yy; int keys, expected = 1; diff --git a/window.c b/window.c index 9e77adcd..baaaa0f8 100644 --- a/window.c +++ b/window.c @@ -302,7 +302,7 @@ window_create1(u_int sx, u_int sy) w->sx = sx; w->sy = sy; - options_init(&w->options, &global_w_options); + w->options = options_create(global_w_options); w->references = 0; @@ -335,7 +335,7 @@ window_create(const char *name, int argc, char **argv, const char *path, w->active = TAILQ_FIRST(&w->panes); if (name != NULL) { w->name = xstrdup(name); - options_set_number(&w->options, "automatic-rename", 0); + options_set_number(w->options, "automatic-rename", 0); } else w->name = default_window_name(w); @@ -359,7 +359,7 @@ window_destroy(struct window *w) if (event_initialized(&w->alerts_timer)) evtimer_del(&w->alerts_timer); - options_free(&w->options); + options_free(w->options); window_destroy_panes(w); @@ -437,8 +437,8 @@ window_redraw_active_switch(struct window *w, struct window_pane *wp) * active or inactive pane do not have a custom style, they will need * to be redrawn. */ - agc = options_get_style(&w->options, "window-active-style"); - wgc = options_get_style(&w->options, "window-style"); + agc = options_get_style(w->options, "window-active-style"); + wgc = options_get_style(w->options, "window-style"); if (style_equal(agc, wgc)) return; if (style_equal(&grid_default_cell, &w->active->colgc)) @@ -598,7 +598,7 @@ window_pane_at_index(struct window *w, u_int idx) struct window_pane *wp; u_int n; - n = options_get_number(&w->options, "pane-base-index"); + n = options_get_number(w->options, "pane-base-index"); TAILQ_FOREACH(wp, &w->panes, entry) { if (n == idx) return (wp); @@ -636,7 +636,7 @@ window_pane_index(struct window_pane *wp, u_int *i) struct window_pane *wq; struct window *w = wp->window; - *i = options_get_number(&w->options, "pane-base-index"); + *i = options_get_number(w->options, "pane-base-index"); TAILQ_FOREACH(wq, &w->panes, entry) { if (wp == wq) { return (0); @@ -1002,7 +1002,7 @@ window_pane_alternate_on(struct window_pane *wp, struct grid_cell *gc, if (wp->saved_grid != NULL) return; - if (!options_get_number(&wp->window->options, "alternate-screen")) + if (!options_get_number(wp->window->options, "alternate-screen")) return; sx = screen_size_x(s); sy = screen_size_y(s); @@ -1032,7 +1032,7 @@ window_pane_alternate_off(struct window_pane *wp, struct grid_cell *gc, if (wp->saved_grid == NULL) return; - if (!options_get_number(&wp->window->options, "alternate-screen")) + if (!options_get_number(wp->window->options, "alternate-screen")) return; sx = screen_size_x(s); sy = screen_size_y(s); @@ -1120,7 +1120,7 @@ window_pane_key(struct window_pane *wp, struct client *c, struct session *s, if (KEYC_IS_MOUSE(key)) return; - if (options_get_number(&wp->window->options, "synchronize-panes")) { + if (options_get_number(wp->window->options, "synchronize-panes")) { TAILQ_FOREACH(wp2, &wp->window->panes, entry) { if (wp2 == wp || wp2->mode != NULL) continue;