Break the common process set up, event loop and imsg dispatch code
authornicm <nicm@openbsd.org>
Tue, 27 Oct 2015 13:23:24 +0000 (13:23 +0000)
committernicm <nicm@openbsd.org>
Tue, 27 Oct 2015 13:23:24 +0000 (13:23 +0000)
between server and client out into a separate internal API. This will
make it easier to add another process.

13 files changed:
usr.bin/tmux/Makefile
usr.bin/tmux/client.c
usr.bin/tmux/cmd-attach-session.c
usr.bin/tmux/cmd-detach-client.c
usr.bin/tmux/cmd-find.c
usr.bin/tmux/cmd-new-session.c
usr.bin/tmux/proc.c [new file with mode: 0644]
usr.bin/tmux/server-client.c
usr.bin/tmux/server-fn.c
usr.bin/tmux/server.c
usr.bin/tmux/signal.c
usr.bin/tmux/tmux.c
usr.bin/tmux/tmux.h

index 7cd4eac..5ab9642 100644 (file)
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.80 2015/09/11 14:41:50 nicm Exp $
+# $OpenBSD: Makefile,v 1.81 2015/10/27 13:23:24 nicm Exp $
 
 PROG=  tmux
 SRCS=  alerts.c \
@@ -94,6 +94,7 @@ SRCS= alerts.c \
        options-table.c \
        options.c \
        paste.c \
+       proc.c \
        procname.c \
        resize.c \
        screen-redraw.c \
index eef918d..b6e6042 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: client.c,v 1.98 2015/10/18 20:42:42 nicm Exp $ */
+/* $OpenBSD: client.c,v 1.99 2015/10/27 13:23:24 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -26,6 +26,7 @@
 #include <errno.h>
 #include <event.h>
 #include <fcntl.h>
+#include <imsg.h>
 #include <signal.h>
 #include <stdlib.h>
 #include <string.h>
 
 #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");
 }
 
+/* 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). */
-int
-client_dispatch_wait(void)
+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;
-
-               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);
+       data = imsg->data;
+       datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
+
+       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");
 
-                       client_write(STDERR_FILENO, stderrdata.data,
-                           stderrdata.size);
-                       break;
-               case MSG_VERSION:
-                       if (datalen != 0)
-                               fatalx("bad MSG_VERSION size");
+               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");
 
-                       fprintf(stderr, "protocol version mismatch "
-                           "(client %d, server %u)\n", PROTOCOL_VERSION,
-                           imsg.hdr.peerid);
-                       client_exitval = 1;
+               event_add(&client_stdin, NULL);
+               break;
+       case MSG_STDOUT:
+               if (datalen != sizeof stdoutdata)
+                       fatalx("bad MSG_STDOUT size");
+               memcpy(&stdoutdata, data, sizeof stdoutdata);
 
-                       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);
-               }
+               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);
 
-               imsg_free(&imsg);
+               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;
-
-       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;
-
-               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;
-                       client_write_server(MSG_EXITING, NULL, 0);
-                       break;
-               case MSG_EXIT:
-                       if (datalen != 0 && datalen != sizeof (int))
-                               fatalx("bad MSG_EXIT size");
+       ssize_t                  datalen;
 
-                       client_write_server(MSG_EXITING, NULL, 0);
-                       client_exitreason = CLIENT_EXIT_EXITED;
-                       break;
-               case MSG_EXITED:
-                       if (datalen != 0)
-                               fatalx("bad MSG_EXITED size");
+       data = imsg->data;
+       datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
 
-                       imsg_free(&imsg);
-                       return (-1);
-               case MSG_SHUTDOWN:
-                       if (datalen != 0)
-                               fatalx("bad MSG_SHUTDOWN size");
+       switch (imsg->hdr.type) {
+       case MSG_DETACH:
+       case MSG_DETACHKILL:
+               if (datalen == 0 || data[datalen - 1] != '\0')
+                       fatalx("bad MSG_DETACH string");
 
-                       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");
+               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");
 
-                       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");
+               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");
 
-                       system(data);
-                       client_write_server(MSG_UNLOCK, NULL, 0);
-                       break;
-               }
+               proc_exit(client_proc);
+               break;
+       case MSG_SHUTDOWN:
+               if (datalen != 0)
+                       fatalx("bad MSG_SHUTDOWN size");
 
-               imsg_free(&imsg);
+               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");
+
+               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);
+               proc_send(client_peer, MSG_UNLOCK, -1, NULL, 0);
+               break;
        }
 }
index 37ad2ce..27cb69a 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-attach-session.c,v 1.42 2015/09/16 22:29:30 nicm Exp $ */
+/* $OpenBSD: cmd-attach-session.c,v 1.43 2015/10/27 13:23:24 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -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();
index cce1c2d..743f8e2 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-detach-client.c,v 1.20 2015/04/24 23:17:11 nicm Exp $ */
+/* $OpenBSD: cmd-detach-client.c,v 1.21 2015/10/27 13:23:24 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -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);
 }
index 1a7be8a..4c0d79a 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-find.c,v 1.15 2015/10/23 16:29:07 nicm Exp $ */
+/* $OpenBSD: cmd-find.c,v 1.16 2015/10/27 13:23:24 nicm Exp $ */
 
 /*
  * Copyright (c) 2015 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -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(&current, 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);
 }
 
index 45a0510..9061449 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-new-session.c,v 1.72 2015/10/23 16:30:15 nicm Exp $ */
+/* $OpenBSD: cmd-new-session.c,v 1.73 2015/10/27 13:23:24 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -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/usr.bin/tmux/proc.c b/usr.bin/tmux/proc.c
new file mode 100644 (file)
index 0000000..226c58d
--- /dev/null
@@ -0,0 +1,249 @@
+/* $OpenBSD: proc.c,v 1.1 2015/10/27 13:23:24 nicm Exp $ */
+
+/*
+ * Copyright (c) 2015 Nicholas Marriott <nicm@users.sourceforge.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/uio.h>
+
+#include <errno.h>
+#include <event.h>
+#include <imsg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "tmux.h"
+
+struct tmuxproc {
+       const char       *name;
+       int               exit;
+
+       void            (*signalcb)(int);
+};
+
+struct tmuxpeer {
+       struct tmuxproc *parent;
+
+       struct imsgbuf   ibuf;
+       struct event     event;
+
+       int              flags;
+#define PEER_BAD 0x1
+
+       void            (*dispatchcb)(struct imsg *, void *);
+       void            *arg;
+};
+
+static void proc_update_event(struct tmuxpeer *);
+
+static void
+proc_event_cb(unused int fd, short events, void *arg)
+{
+       struct tmuxpeer *peer = arg;
+       ssize_t          n;
+       struct imsg      imsg;
+       int              v;
+
+       if (!(peer->flags & PEER_BAD) && (events & EV_READ)) {
+               if ((n = imsg_read(&peer->ibuf)) == -1 || n == 0) {
+                       peer->dispatchcb(NULL, peer->arg);
+                       return;
+               }
+               for (;;) {
+                       if ((n = imsg_get(&peer->ibuf, &imsg)) == -1) {
+                               peer->dispatchcb(NULL, peer->arg);
+                               return;
+                       }
+                       if (n == 0)
+                               break;
+                       log_debug("peer %p message %d", peer, imsg.hdr.type);
+
+                       v = imsg.hdr.peerid;
+                       if (imsg.hdr.type != MSG_VERSION &&
+                           v != PROTOCOL_VERSION) {
+                               log_debug("peer %p bad version %d", peer, v);
+
+                               proc_send(peer, MSG_VERSION, -1, NULL, 0);
+                               peer->flags |= PEER_BAD;
+
+                               if (imsg.fd != -1)
+                                       close(imsg.fd);
+                               imsg_free(&imsg);
+                               break;
+                       }
+
+                       peer->dispatchcb(&imsg, peer->arg);
+                       imsg_free(&imsg);
+               }
+       }
+
+       if (events & EV_WRITE) {
+               if (msgbuf_write(&peer->ibuf.w) <= 0 && errno != EAGAIN) {
+                       peer->dispatchcb(NULL, peer->arg);
+                       return;
+               }
+       }
+
+       if ((peer->flags & PEER_BAD) && peer->ibuf.w.queued == 0) {
+               peer->dispatchcb(NULL, peer->arg);
+               return;
+       }
+
+       proc_update_event(peer);
+}
+
+static void
+proc_signal_cb(int signo, unused short events, void *arg)
+{
+       struct tmuxproc *tp = arg;
+
+       tp->signalcb(signo);
+}
+
+static void
+proc_update_event(struct tmuxpeer *peer)
+{
+       short   events;
+
+       event_del(&peer->event);
+
+       events = EV_READ;
+       if (peer->ibuf.w.queued > 0)
+               events |= EV_WRITE;
+       event_set(&peer->event, peer->ibuf.fd, events, proc_event_cb, peer);
+
+       event_add(&peer->event, NULL);
+}
+
+int
+proc_send(struct tmuxpeer *peer, enum msgtype type, int fd, const void *buf,
+    size_t len)
+{
+       struct imsgbuf  *ibuf = &peer->ibuf;
+       void            *vp = (void *)buf;
+       int              retval;
+
+       if (peer->flags & PEER_BAD)
+               return (-1);
+       log_debug("sending message %d to peer %p (%zu bytes)", type, peer, len);
+
+       retval = imsg_compose(ibuf, type, PROTOCOL_VERSION, -1, fd, vp, len);
+       if (retval != 1)
+               return (-1);
+       proc_update_event(peer);
+       return (0);
+}
+
+int
+proc_send_s(struct tmuxpeer *peer, enum msgtype type, const char *s)
+{
+       return (proc_send(peer, type, -1, s, strlen(s) + 1));
+}
+
+struct tmuxproc *
+proc_start(const char *name, struct event_base *base, int forkflag,
+    void (*signalcb)(int))
+{
+       struct tmuxproc *tp;
+
+       if (forkflag) {
+               switch (fork()) {
+               case -1:
+                       fatal("fork failed");
+               case 0:
+                       break;
+               default:
+                       return (NULL);
+               }
+               if (daemon(1, 0) != 0)
+                       fatal("daemon failed");
+
+               clear_signals(0);
+               if (event_reinit(base) != 0)
+                       fatalx("event_reinit failed");
+       }
+
+       logfile(name);
+       setproctitle("%s (%s)", name, socket_path);
+
+       log_debug("%s started (%ld): socket %s, protocol %d", name,
+           (long)getpid(), socket_path, PROTOCOL_VERSION);
+
+       tp = xcalloc(1, sizeof *tp);
+       tp->name = xstrdup(name);
+
+       tp->signalcb = signalcb;
+       set_signals(proc_signal_cb, tp);
+
+       return (tp);
+}
+
+void
+proc_loop(struct tmuxproc *tp, int (*loopcb)(void))
+{
+       log_debug("%s loop enter", tp->name);
+       do
+               event_loop(EVLOOP_ONCE);
+       while (!tp->exit && (loopcb == NULL || !loopcb ()));
+       log_debug("%s loop exit", tp->name);
+}
+
+void
+proc_exit(struct tmuxproc *tp)
+{
+       tp->exit = 1;
+}
+
+struct tmuxpeer *
+proc_add_peer(struct tmuxproc *tp, int fd,
+    void (*dispatchcb)(struct imsg *, void *), void *arg)
+{
+       struct tmuxpeer *peer;
+
+       peer = xcalloc(1, sizeof *peer);
+       peer->parent = tp;
+
+       peer->dispatchcb = dispatchcb;
+       peer->arg = arg;
+
+       imsg_init(&peer->ibuf, fd);
+       event_set(&peer->event, fd, EV_READ, proc_event_cb, peer);
+
+       log_debug("add peer %p: %d (%p)", peer, fd, arg);
+
+       proc_update_event(peer);
+       return (peer);
+}
+
+void
+proc_remove_peer(struct tmuxpeer *peer)
+{
+       log_debug("remove peer %p", peer);
+
+       event_del(&peer->event);
+       imsg_clear(&peer->ibuf);
+
+       close(peer->ibuf.fd);
+       free(peer);
+}
+
+void
+proc_kill_peer(struct tmuxpeer *peer)
+{
+       peer->flags |= PEER_BAD;
+}
index a5c1fd6..b1bc87a 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: server-client.c,v 1.161 2015/10/26 23:16:18 nicm Exp $ */
+/* $OpenBSD: server-client.c,v 1.162 2015/10/27 13:23:24 nicm Exp $ */
 
 /*
  * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
 
 #include <sys/types.h>
 #include <sys/ioctl.h>
+#include <sys/uio.h>
 
 #include <errno.h>
 #include <event.h>
 #include <fcntl.h>
+#include <imsg.h>
 #include <paths.h>
 #include <stdlib.h>
 #include <string.h>
@@ -42,10 +44,10 @@ void        server_client_set_title(struct client *);
 void   server_client_reset_state(struct client *);
 int    server_client_assume_paste(struct session *);
 
-int    server_client_msg_dispatch(struct client *);
-void   server_client_msg_command(struct client *, struct imsg *);
-void   server_client_msg_identify(struct client *, struct imsg *);
-void   server_client_msg_shell(struct client *);
+void   server_client_dispatch(struct imsg *, void *);
+void   server_client_dispatch_command(struct client *, struct imsg *);
+void   server_client_dispatch_identify(struct client *, struct imsg *);
+void   server_client_dispatch_shell(struct client *);
 
 /* Check if this client is inside this server. */
 int
@@ -87,8 +89,7 @@ server_client_create(int fd)
 
        c = xcalloc(1, sizeof *c);
        c->references = 1;
-       imsg_init(&c->ibuf, fd);
-       server_update_event(c);
+       c->peer = proc_add_peer(server_proc, fd, server_client_dispatch, c);
 
        if (gettimeofday(&c->creation_time, NULL) != 0)
                fatal("gettimeofday failed");
@@ -220,10 +221,8 @@ server_client_lost(struct client *c)
 
        environ_free(&c->environ);
 
-       close(c->ibuf.fd);
-       imsg_clear(&c->ibuf);
-       if (event_initialized(&c->event))
-               event_del(&c->event);
+       proc_remove_peer(c->peer);
+       c->peer = NULL;
 
        server_client_unref(c);
 
@@ -257,40 +256,6 @@ server_client_free(unused int fd, unused short events, void *arg)
                free(c);
 }
 
-/* Process a single client event. */
-void
-server_client_callback(int fd, short events, void *data)
-{
-       struct client   *c = data;
-
-       if (c->flags & CLIENT_DEAD)
-               return;
-
-       if (fd == c->ibuf.fd) {
-               if (events & EV_WRITE && msgbuf_write(&c->ibuf.w) <= 0 &&
-                   errno != EAGAIN)
-                       goto client_lost;
-
-               if (c->flags & CLIENT_BAD) {
-                       if (c->ibuf.w.queued == 0)
-                               goto client_lost;
-                       return;
-               }
-
-               if (events & EV_READ && server_client_msg_dispatch(c) != 0)
-                       goto client_lost;
-       }
-
-       server_push_stdout(c);
-       server_push_stderr(c);
-
-       server_update_event(c);
-       return;
-
-client_lost:
-       server_client_lost(c);
-}
-
 /* Check for mouse keys. */
 int
 server_client_check_mouse(struct client *c)
@@ -880,7 +845,7 @@ server_client_check_exit(struct client *c)
        if (EVBUFFER_LENGTH(c->stderr_data) != 0)
                return;
 
-       server_write_client(c, MSG_EXIT, &c->retval, sizeof c->retval);
+       proc_send(c->peer, MSG_EXIT, -1, &c->retval, sizeof c->retval);
        c->flags &= ~CLIENT_EXIT;
 }
 
@@ -974,123 +939,112 @@ server_client_set_title(struct client *c)
 }
 
 /* Dispatch message from client. */
-int
-server_client_msg_dispatch(struct client *c)
+void
+server_client_dispatch(struct imsg *imsg, void *arg)
 {
-       struct imsg              imsg;
+       struct client           *c = arg;
        struct msg_stdin_data    stdindata;
        const char              *data;
-       ssize_t                  n, datalen;
+       ssize_t                  datalen;
        struct session          *s;
 
-       if ((n = imsg_read(&c->ibuf)) == -1 || n == 0)
-               return (-1);
+       if (c->flags & CLIENT_DEAD)
+               return;
 
-       for (;;) {
-               if ((n = imsg_get(&c->ibuf, &imsg)) == -1)
-                       return (-1);
-               if (n == 0)
-                       return (0);
-
-               data = imsg.data;
-               datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
-
-               if (imsg.hdr.peerid != PROTOCOL_VERSION) {
-                       server_write_client(c, MSG_VERSION, NULL, 0);
-                       c->flags |= CLIENT_BAD;
-                       if (imsg.fd != -1)
-                               close(imsg.fd);
-                       imsg_free(&imsg);
-                       continue;
-               }
+       if (imsg == NULL) {
+               server_client_lost(c);
+               return;
+       }
 
-               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);
+       data = imsg->data;
+       datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
 
-                       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");
+       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->flags & CLIENT_CONTROL)
-                               break;
-                       if (tty_resize(&c->tty)) {
-                               recalculate_sizes();
-                               server_redraw_client(c);
-                       }
+               if (c->stdin_callback == NULL)
                        break;
-               case MSG_EXITING:
-                       if (datalen != 0)
-                               fatalx("bad MSG_EXITING size");
+               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");
 
-                       c->session = NULL;
-                       tty_close(&c->tty);
-                       server_write_client(c, MSG_EXITED, NULL, 0);
+               if (c->flags & CLIENT_CONTROL)
                        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 (tty_resize(&c->tty)) {
+                       recalculate_sizes();
+                       server_redraw_client(c);
+               }
+               break;
+       case MSG_EXITING:
+               if (datalen != 0)
+                       fatalx("bad MSG_EXITING size");
 
-                       if (gettimeofday(&c->activity_time, NULL) != 0)
-                               fatal("gettimeofday failed");
-                       if (s != NULL)
-                               session_update_activity(s, &c->activity_time);
+               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");
 
-                       tty_start_tty(&c->tty);
-                       server_redraw_client(c);
-                       recalculate_sizes();
+               if (!(c->flags & CLIENT_SUSPENDED))
                        break;
-               case MSG_SHELL:
-                       if (datalen != 0)
-                               fatalx("bad MSG_SHELL size");
+               c->flags &= ~CLIENT_SUSPENDED;
 
-                       server_client_msg_shell(c);
+               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");
 
-               imsg_free(&imsg);
+               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);
 }
index 772999b..bbfaaa5 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: server-fn.c,v 1.89 2015/10/20 21:12:09 nicm Exp $ */
+/* $OpenBSD: server-fn.c,v 1.90 2015/10/27 13:23:24 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
  */
 
 #include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/uio.h>
 
+#include <imsg.h>
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
@@ -47,43 +50,6 @@ server_fill_environ(struct session *s, struct environ *env)
        environ_set(env, "TMUX", var);
 }
 
-void
-server_write_ready(struct client *c)
-{
-       if (c->flags & CLIENT_CONTROL)
-               return;
-       server_write_client(c, MSG_READY, NULL, 0);
-}
-
-int
-server_write_client(struct client *c, enum msgtype type, const void *buf,
-    size_t len)
-{
-       struct imsgbuf  *ibuf = &c->ibuf;
-       int              error;
-
-       if (c->flags & CLIENT_BAD)
-               return (-1);
-       log_debug("writing %d to client %p", type, c);
-       error = imsg_compose(ibuf, type, PROTOCOL_VERSION, -1, -1,
-           (void *) buf, len);
-       if (error == 1)
-               server_update_event(c);
-       return (error == 1 ? 0 : -1);
-}
-
-void
-server_write_session(struct session *s, enum msgtype type, const void *buf,
-    size_t len)
-{
-       struct client   *c;
-
-       TAILQ_FOREACH(c, &clients, entry) {
-               if (c->session == s)
-                       server_write_client(c, type, buf, len);
-       }
-}
-
 void
 server_redraw_client(struct client *c)
 {
@@ -227,7 +193,7 @@ server_lock_client(struct client *c)
        tty_raw(&c->tty, tty_term_string(c->tty.term, TTYC_E3));
 
        c->flags |= CLIENT_SUSPENDED;
-       server_write_client(c, MSG_LOCK, cmd, strlen(cmd) + 1);
+       proc_send_s(c->peer, MSG_LOCK, cmd);
 }
 
 void
@@ -484,22 +450,6 @@ server_callback_identify(unused int fd, unused short events, void *data)
        server_clear_identify(c);
 }
 
-void
-server_update_event(struct client *c)
-{
-       short   events;
-
-       events = 0;
-       if (!(c->flags & CLIENT_BAD))
-               events |= EV_READ;
-       if (c->ibuf.w.queued > 0)
-               events |= EV_WRITE;
-       if (event_initialized(&c->event))
-               event_del(&c->event);
-       event_set(&c->event, c->ibuf.fd, events, server_client_callback, c);
-       event_add(&c->event, NULL);
-}
-
 /* Push stdout to client if possible. */
 void
 server_push_stdout(struct client *c)
@@ -516,7 +466,7 @@ server_push_stdout(struct client *c)
        memcpy(data.data, EVBUFFER_DATA(c->stdout_data), size);
        data.size = size;
 
-       if (server_write_client(c, MSG_STDOUT, &data, sizeof data) == 0)
+       if (proc_send(c->peer, MSG_STDOUT, -1, &data, sizeof data) == 0)
                evbuffer_drain(c->stdout_data, size);
 }
 
@@ -540,7 +490,7 @@ server_push_stderr(struct client *c)
        memcpy(data.data, EVBUFFER_DATA(c->stderr_data), size);
        data.size = size;
 
-       if (server_write_client(c, MSG_STDERR, &data, sizeof data) == 0)
+       if (proc_send(c->peer, MSG_STDERR, -1, &data, sizeof data) == 0)
                evbuffer_drain(c->stderr_data, size);
 }
 
@@ -570,7 +520,7 @@ server_set_stdin_callback(struct client *c, void (*cb)(struct client *, int,
        if (c->stdin_closed)
                c->stdin_callback(c, 1, c->stdin_callback_data);
 
-       server_write_client(c, MSG_STDIN, NULL, 0);
+       proc_send(c->peer, MSG_STDIN, -1, NULL, 0);
 
        return (0);
 }
index 741b7ed..93b32f0 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: server.c,v 1.143 2015/10/23 16:07:29 nicm Exp $ */
+/* $OpenBSD: server.c,v 1.144 2015/10/27 13:23:24 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -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(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). */
+/* Server loop callback. */
 int
-server_should_exit(void)
+server_loop(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;
 
index 3613557..91187a0 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: signal.c,v 1.7 2014/10/20 23:27:14 nicm Exp $ */
+/* $OpenBSD: signal.c,v 1.8 2015/10/27 13:23:24 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -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);
 }
 
index 702052a..9812265 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: tmux.c,v 1.146 2015/10/25 07:48:16 deraadt Exp $ */
+/* $OpenBSD: tmux.c,v 1.147 2015/10/27 13:23:24 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -29,6 +29,7 @@
 #include <pwd.h>
 #include <stdlib.h>
 #include <string.h>
+#include <time.h>
 #include <unistd.h>
 
 #include "tmux.h"
@@ -347,9 +348,6 @@ main(int argc, char **argv)
        }
        free(path);
 
-       /* Set process title. */
-       setproctitle("%s (%s)", __progname, socket_path);
-
        /* Pass control to the client. */
        exit(client_main(event_init(), argc, argv, flags));
 }
index fd50033..eb3e293 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: tmux.h,v 1.565 2015/10/25 22:29:17 nicm Exp $ */
+/* $OpenBSD: tmux.h,v 1.566 2015/10/27 13:23:24 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
 #include <sys/time.h>
 #include <sys/queue.h>
 #include <sys/tree.h>
-#include <sys/uio.h>
 
 #include <bitstring.h>
 #include <event.h>
-#include <imsg.h>
 #include <limits.h>
 #include <stdarg.h>
 #include <stdint.h>
@@ -1170,8 +1168,10 @@ struct message_entry {
 };
 
 /* Client connection. */
+struct tmuxproc;
+struct tmuxpeer;
 struct client {
-       struct imsgbuf   ibuf;
+       struct tmuxpeer *peer;
 
        pid_t            pid;
        int              fd;
@@ -1209,7 +1209,7 @@ struct client {
 #define CLIENT_STATUS 0x10
 #define CLIENT_REPEAT 0x20
 #define CLIENT_SUSPENDED 0x40
-#define CLIENT_BAD 0x80
+/* 0x80 unused */
 #define CLIENT_IDENTIFY 0x100
 #define CLIENT_DEAD 0x200
 #define CLIENT_BORDERS 0x400
@@ -1420,6 +1420,19 @@ int               areshell(const char *);
 void            setblocking(int, int);
 const char     *find_home(void);
 
+/* proc.c */
+struct imsg;
+int    proc_send(struct tmuxpeer *, enum msgtype, int, const void *, size_t);
+int    proc_send_s(struct tmuxpeer *, enum msgtype, const char *);
+struct tmuxproc *proc_start(const char *, struct event_base *, int,
+           void (*)(int));
+void   proc_loop(struct tmuxproc *, int (*)(void));
+void   proc_exit(struct tmuxproc *);
+struct tmuxpeer *proc_add_peer(struct tmuxproc *, int,
+           void (*)(struct imsg *, void *), void *);
+void   proc_remove_peer(struct tmuxpeer *);
+void   proc_kill_peer(struct tmuxpeer *);
+
 /* cfg.c */
 extern int cfg_finished;
 extern int cfg_references;
@@ -1727,6 +1740,7 @@ void      alerts_reset_all(void);
 void   alerts_queue(struct window *, int);
 
 /* server.c */
+extern struct tmuxproc *server_proc;
 extern struct clients clients;
 extern struct session *marked_session;
 extern struct winlink *marked_winlink;
@@ -1748,16 +1762,10 @@ void     server_client_create(int);
 int     server_client_open(struct client *, char **);
 void    server_client_unref(struct client *);
 void    server_client_lost(struct client *);
-void    server_client_callback(int, short, void *);
 void    server_client_loop(void);
 
 /* server-fn.c */
 void    server_fill_environ(struct session *, struct environ *);
-void    server_write_ready(struct client *);
-int     server_write_client(struct client *, enum msgtype, const void *,
-            size_t);
-void    server_write_session(struct session *, enum msgtype, const void *,
-            size_t);
 void    server_redraw_client(struct client *);
 void    server_status_client(struct client *);
 void    server_redraw_session(struct session *);
@@ -1780,7 +1788,6 @@ void       server_destroy_session(struct session *);
 void    server_check_unattached(void);
 void    server_set_identify(struct client *);
 void    server_clear_identify(struct client *);
-void    server_update_event(struct client *);
 void    server_push_stdout(struct client *);
 void    server_push_stderr(struct client *);
 int     server_set_stdin_callback(struct client *, void (*)(struct client *,
@@ -2110,7 +2117,7 @@ char      *format_window_name(struct window *);
 char   *parse_window_name(const char *);
 
 /* signal.c */
-void   set_signals(void(*)(int, short, void *));
+void   set_signals(void(*)(int, short, void *), void *);
 void   clear_signals(int);
 
 /* control.c */