aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile4
-rw-r--r--client-cmd.c108
-rw-r--r--client-msg.c99
-rw-r--r--client.c251
-rw-r--r--command.c113
-rw-r--r--op-list.c126
-rw-r--r--op.c64
-rw-r--r--server-msg.c190
-rw-r--r--server.c54
-rw-r--r--tmux.c578
-rw-r--r--tmux.h58
11 files changed, 913 insertions, 732 deletions
diff --git a/Makefile b/Makefile
index 80a3b003..a300e0c4 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.4 2007-09-26 10:35:24 nicm Exp $
+# $Id: Makefile,v 1.5 2007-09-26 13:43:14 nicm Exp $
.SUFFIXES: .c .o .y .h
.PHONY: clean
@@ -18,7 +18,7 @@ META?= \002 # C-b
SRCS= tmux.c server.c server-msg.c server-fn.c buffer.c buffer-poll.c \
xmalloc.c xmalloc-debug.c input.c screen.c window.c session.c local.c \
- log.c command.c
+ log.c client.c client-msg.c client-cmd.c op.c
YACC= yacc -d
diff --git a/client-cmd.c b/client-cmd.c
new file mode 100644
index 00000000..998fee2c
--- /dev/null
+++ b/client-cmd.c
@@ -0,0 +1,108 @@
+/* $Id: client-cmd.c,v 1.1 2007-09-26 13:43:14 nicm Exp $ */
+
+/*
+ * Copyright (c) 2007 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 "tmux.h"
+
+int client_cmd_prefix = META;
+
+int client_cmd_fn_select(int, struct client_ctx *, const char **);
+int client_cmd_fn_detach(int, struct client_ctx *, const char **);
+int client_cmd_fn_msg(int, struct client_ctx *, const char **);
+
+struct cmd {
+ int key;
+ int (*fn)(int, struct client_ctx *, const char **);
+ int arg;
+};
+
+struct cmd client_cmd_table[] = {
+ { '0', client_cmd_fn_select, 0 },
+ { '1', client_cmd_fn_select, 1 },
+ { '2', client_cmd_fn_select, 2 },
+ { '3', client_cmd_fn_select, 3 },
+ { '4', client_cmd_fn_select, 4 },
+ { '5', client_cmd_fn_select, 5 },
+ { '6', client_cmd_fn_select, 6 },
+ { '7', client_cmd_fn_select, 7 },
+ { '8', client_cmd_fn_select, 8 },
+ { '9', client_cmd_fn_select, 9 },
+ { 'C', client_cmd_fn_msg, MSG_CREATE },
+ { 'c', client_cmd_fn_msg, MSG_CREATE },
+ { 'D', client_cmd_fn_detach, 0 },
+ { 'd', client_cmd_fn_detach, 0 },
+ { 'N', client_cmd_fn_msg, MSG_NEXT },
+ { 'n', client_cmd_fn_msg, MSG_NEXT },
+ { 'P', client_cmd_fn_msg, MSG_PREVIOUS },
+ { 'p', client_cmd_fn_msg, MSG_PREVIOUS },
+ { 'R', client_cmd_fn_msg, MSG_REFRESH },
+ { 'r', client_cmd_fn_msg, MSG_REFRESH },
+ { 'T', client_cmd_fn_msg, MSG_RENAME },
+ { 't', client_cmd_fn_msg, MSG_RENAME },
+ { 'L', client_cmd_fn_msg, MSG_LAST },
+ { 'l', client_cmd_fn_msg, MSG_LAST },
+ { 'W', client_cmd_fn_msg, MSG_WINDOWLIST },
+ { 'w', client_cmd_fn_msg, MSG_WINDOWLIST }
+};
+#define NCLIENTCMD (sizeof client_cmd_table / sizeof client_cmd_table[0])
+
+/* Dispatch to a command. */
+int
+client_cmd_dispatch(int key, struct client_ctx *cctx, const char **error)
+{
+ struct cmd *cmd;
+ u_int i;
+
+ for (i = 0; i < NCLIENTCMD; i++) {
+ cmd = client_cmd_table + i;
+ if (cmd->key == key)
+ return (cmd->fn(cmd->arg, cctx, error));
+ }
+ return (0);
+}
+
+/* Handle generic command. */
+int
+client_cmd_fn_msg(int arg, struct client_ctx *cctx, unused const char **error)
+{
+ client_write_server(cctx, arg, NULL, 0);
+
+ return (0);
+}
+
+/* Handle select command. */
+int
+client_cmd_fn_select(
+ int arg, struct client_ctx *cctx, unused const char **error)
+{
+ struct select_data data;
+
+ data.idx = arg;
+ client_write_server(cctx, MSG_SELECT, &data, sizeof data);
+
+ return (0);
+}
+
+/* Handle detach command. */
+int
+client_cmd_fn_detach(
+ unused int arg, unused struct client_ctx *cctx, unused const char **error)
+{
+ return (-1);
+}
diff --git a/client-msg.c b/client-msg.c
new file mode 100644
index 00000000..6639d915
--- /dev/null
+++ b/client-msg.c
@@ -0,0 +1,99 @@
+/* $Id: client-msg.c,v 1.1 2007-09-26 13:43:14 nicm Exp $ */
+
+/*
+ * Copyright (c) 2007 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 <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "tmux.h"
+
+int client_msg_fn_output(struct hdr *, struct client_ctx *, const char **);
+int client_msg_fn_pause(struct hdr *, struct client_ctx *, const char **);
+int client_msg_fn_exit(struct hdr *, struct client_ctx *, const char **);
+
+struct client_msg {
+ enum hdrtype type;
+
+ int (*fn)(struct hdr *, struct client_ctx *, const char **);
+};
+struct client_msg client_msg_table[] = {
+ { MSG_OUTPUT, client_msg_fn_output },
+ { MSG_PAUSE, client_msg_fn_pause },
+ { MSG_EXIT, client_msg_fn_exit },
+};
+#define NCLIENTMSG (sizeof client_msg_table / sizeof client_msg_table[0])
+
+int
+client_msg_dispatch(struct client_ctx *cctx, const char **error)
+{
+ struct hdr hdr;
+ struct client_msg *msg;
+ u_int i;
+ int n;
+
+ for (;;) {
+ if (BUFFER_USED(cctx->srv_in) < sizeof hdr)
+ return (0);
+ memcpy(&hdr, BUFFER_OUT(cctx->srv_in), sizeof hdr);
+ if (BUFFER_USED(cctx->srv_in) < (sizeof hdr) + hdr.size)
+ return (0);
+ buffer_remove(cctx->srv_in, sizeof hdr);
+
+ for (i = 0; i < NCLIENTMSG; i++) {
+ msg = client_msg_table + i;
+ if (msg->type == hdr.type) {
+ if ((n = msg->fn(&hdr, cctx, error)) != 0)
+ return (n);
+ break;
+ }
+ }
+ if (i == NCLIENTMSG)
+ fatalx("unexpected message");
+ }
+}
+
+/* Output message from client. */
+int
+client_msg_fn_output(
+ struct hdr *hdr, struct client_ctx *cctx, unused const char **error)
+{
+ local_output(cctx->srv_in, hdr->size);
+ return (0);
+}
+
+/* Pause message from server. */
+int
+client_msg_fn_pause(
+ struct hdr *hdr, unused struct client_ctx *cctx, unused const char **error)
+{
+ if (hdr->size != 0)
+ fatalx("bad MSG_PAUSE size");
+ return (1);
+}
+
+/* Exit message from server. */
+int
+client_msg_fn_exit(
+ struct hdr *hdr, unused struct client_ctx *cctx, unused const char **error)
+{
+ if (hdr->size != 0)
+ fatalx("bad MSG_EXIT size");
+ return (-1);
+}
diff --git a/client.c b/client.c
new file mode 100644
index 00000000..8c120aa6
--- /dev/null
+++ b/client.c
@@ -0,0 +1,251 @@
+/* $Id: client.c,v 1.1 2007-09-26 13:43:15 nicm Exp $ */
+
+/*
+ * Copyright (c) 2007 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/ioctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "tmux.h"
+
+void client_handle_winch(struct client_ctx *);
+int client_process_local(struct client_ctx *, const char **);
+
+int
+client_init(char *path, struct client_ctx *cctx, int ws)
+{
+ struct sockaddr_un sa;
+ struct stat sb;
+ size_t sz;
+ int mode;
+
+ if (path == NULL) {
+ xasprintf(&path,
+ "%s/%s-%lu", _PATH_TMP, __progname, (u_long) getuid());
+ }
+
+retry:
+ if (stat(path, &sb) != 0) {
+ if (errno != ENOENT) {
+ log_warn("%s", path);
+ return (-1);
+ }
+ if (server_start(path) != 0)
+ return (-1);
+ sleep(1); /* XXX */
+ goto retry;
+ }
+ if (!S_ISSOCK(sb.st_mode)) {
+ log_warnx("%s: %s", path, strerror(ENOTSOCK));
+ return (-1);
+ }
+
+ if (ws) {
+ if (!isatty(STDIN_FILENO)) {
+ log_warnx("stdin is not a tty");
+ return (-1);
+ }
+ if (!isatty(STDOUT_FILENO)) {
+ log_warnx("stdout is not a tty");
+ return (-1);
+ }
+
+ if (ioctl(STDIN_FILENO, TIOCGWINSZ, &cctx->ws) == -1) {
+ log_warn("ioctl(TIOCGWINSZ)");
+ return (-1);
+ }
+ }
+
+ memset(&sa, 0, sizeof sa);
+ sa.sun_family = AF_UNIX;
+ sz = strlcpy(sa.sun_path, path, sizeof sa.sun_path);
+ if (sz >= sizeof sa.sun_path) {
+ log_warnx("%s: %s", path, strerror(ENAMETOOLONG));
+ return (-1);
+ }
+
+ if ((cctx->srv_fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
+ log_warn("%s: socket", path);
+ return (-1);
+ }
+ if (connect(
+ cctx->srv_fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) {
+ log_warn("%s: connect", path);
+ return (-1);
+ }
+
+ if ((mode = fcntl(cctx->srv_fd, F_GETFL)) == -1) {
+ log_warn("%s: fcntl", path);
+ return (-1);
+ }
+ if (fcntl(cctx->srv_fd, F_SETFL, mode|O_NONBLOCK) == -1) {
+ log_warn("%s: fcntl", path);
+ return (-1);
+ }
+ cctx->srv_in = buffer_create(BUFSIZ);
+ cctx->srv_out = buffer_create(BUFSIZ);
+
+ return (0);
+}
+
+int
+client_main(struct client_ctx *cctx)
+{
+ struct pollfd pfds[2];
+ const char *error;
+ int n;
+
+ logfile("client");
+ setproctitle("client");
+
+ siginit();
+ if ((cctx->loc_fd = local_init(&cctx->loc_in, &cctx->loc_out)) == -1)
+ return (1);
+
+ n = 0;
+ error = NULL;
+ while (!sigterm) {
+ if (sigwinch)
+ client_handle_winch(cctx);
+
+ pfds[0].fd = cctx->srv_fd;
+ pfds[0].events = POLLIN;
+ if (BUFFER_USED(cctx->srv_out) > 0)
+ pfds[0].events |= POLLOUT;
+ pfds[1].fd = cctx->loc_fd;
+ pfds[1].events = POLLIN;
+ if (BUFFER_USED(cctx->loc_out) > 0)
+ pfds[1].events |= POLLOUT;
+
+ if (poll(pfds, 2, INFTIM) == -1) {
+ if (errno == EAGAIN || errno == EINTR)
+ continue;
+ fatal("poll failed");
+ }
+
+ if (buffer_poll(&pfds[0], cctx->srv_in, cctx->srv_out) != 0)
+ goto server_dead;
+ if (buffer_poll(&pfds[1], cctx->loc_in, cctx->loc_out) != 0)
+ goto local_dead;
+
+ /* XXX Output flushed; pause if required. */
+ if (n)
+ usleep(750000);
+ /* XXX XXX special return code for pause */
+ if ((n = client_process_local(cctx, &error)) == -1)
+ break;
+ if ((n = client_msg_dispatch(cctx, &error)) == -1)
+ break;
+ }
+
+ local_done();
+
+ if (sigterm)
+ error = "received SIGTERM";
+ if (error != NULL) {
+ printf("[terminated: %s]\n", error);
+ return (0);
+ }
+ printf("[detached]\n");
+ return (0);
+
+server_dead:
+ local_done();
+
+ printf("[lost server]\n");
+ return (1);
+
+local_dead:
+ /* Can't do much here. Log and die. */
+ fatalx("local socket dead");
+}
+
+void
+client_write_server(
+ struct client_ctx *cctx, enum hdrtype type, void *buf, size_t len)
+{
+ struct hdr hdr;
+
+ hdr.type = type;
+ hdr.size = len;
+ buffer_write(cctx->srv_out, &hdr, sizeof hdr);
+ if (len > 0)
+ buffer_write(cctx->srv_out, buf, len);
+}
+
+void
+client_handle_winch(struct client_ctx *cctx)
+{
+ struct size_data data;
+
+ if (ioctl(STDIN_FILENO, TIOCGWINSZ, &cctx->ws) == -1)
+ fatal("ioctl failed");
+
+ data.sx = cctx->ws.ws_col;
+ data.sy = cctx->ws.ws_row;
+ client_write_server(cctx, MSG_SIZE, &data, sizeof data);
+
+ sigwinch = 0;
+}
+
+int
+client_process_local(struct client_ctx *cctx, const char **error)
+{
+ struct buffer *b;
+ size_t size;
+ int n, key;
+
+ n = 0;
+ b = buffer_create(BUFSIZ);
+
+ while ((key = local_key(&size)) != KEYC_NONE) {
+ log_debug("key code: %d", key);
+
+ if (key == client_cmd_prefix) {
+ if ((key = local_key(NULL)) == KEYC_NONE) {
+ /* XXX sux */
+ buffer_reverse_remove(cctx->loc_in, size);
+ break;
+ }
+ n = client_cmd_dispatch(key, cctx, error);
+ break;
+ }
+
+ input_store8(b, '\e');
+ input_store16(b, (uint16_t) key /*XXX*/);
+ }
+
+ log_debug("transmitting %zu bytes of input", BUFFER_USED(b));
+ if (BUFFER_USED(b) == 0) {
+ buffer_destroy(b);
+ return (n);
+ }
+ client_write_server(cctx, MSG_INPUT, BUFFER_OUT(b), BUFFER_USED(b));
+ buffer_destroy(b);
+ return (n);
+}
+
diff --git a/command.c b/command.c
deleted file mode 100644
index d07bd35f..00000000
--- a/command.c
+++ /dev/null
@@ -1,113 +0,0 @@
-/* $Id: command.c,v 1.7 2007-09-22 11:50:33 nicm Exp $ */
-
-/*
- * Copyright (c) 2007 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 "tmux.h"
-
-int cmd_prefix = META;
-
-int cmd_fn_select(struct buffer *, int);
-int cmd_fn_detach(struct buffer *, int);
-int cmd_fn_msg(struct buffer *, int);
-
-struct cmd {
- int key;
- int (*fn)(struct buffer *, int);
- int arg;
-};
-
-struct cmd cmd_table[] = {
- { '0', cmd_fn_select, 0 },
- { '1', cmd_fn_select, 1 },
- { '2', cmd_fn_select, 2 },
- { '3', cmd_fn_select, 3 },
- { '4', cmd_fn_select, 4 },
- { '5', cmd_fn_select, 5 },
- { '6', cmd_fn_select, 6 },
- { '7', cmd_fn_select, 7 },
- { '8', cmd_fn_select, 8 },
- { '9', cmd_fn_select, 9 },
- { 'C', cmd_fn_msg, MSG_CREATE },
- { 'c', cmd_fn_msg, MSG_CREATE },
- { 'D', cmd_fn_detach, 0 },
- { 'd', cmd_fn_detach, 0 },
- { 'N', cmd_fn_msg, MSG_NEXT },
- { 'n', cmd_fn_msg, MSG_NEXT },
- { 'P', cmd_fn_msg, MSG_PREVIOUS },
- { 'p', cmd_fn_msg, MSG_PREVIOUS },
- { 'R', cmd_fn_msg, MSG_REFRESH },
- { 'r', cmd_fn_msg, MSG_REFRESH },
- { 'T', cmd_fn_msg, MSG_RENAME },
- { 't', cmd_fn_msg, MSG_RENAME },
- { 'L', cmd_fn_msg, MSG_LAST },
- { 'l', cmd_fn_msg, MSG_LAST },
- { 'W', cmd_fn_msg, MSG_WINDOWLIST },
- { 'w', cmd_fn_msg, MSG_WINDOWLIST }
-};
-
-/* Dispatch to a command. */
-int
-cmd_execute(int key, struct buffer *srv_out)
-{
- struct cmd *cmd;
- u_int i;
-
- for (i = 0; i < (sizeof cmd_table / sizeof cmd_table[0]); i++) {
- cmd = cmd_table + i;
- if (cmd->key == key)
- return (cmd->fn(srv_out, cmd->arg));
- }
- return (0);
-}
-
-/* Handle generic command. */
-int
-cmd_fn_msg(struct buffer *srv_out, int type)
-{
- struct hdr hdr;
-
- hdr.type = type;
- hdr.size = 0;
- buffer_write(srv_out, &hdr, sizeof hdr);
-
- return (0);
-}
-
-/* Handle select command. */
-int
-cmd_fn_select(struct buffer *srv_out, int arg)
-{
- struct hdr hdr;
- struct select_data data;
-
- hdr.type = MSG_SELECT;
- hdr.size = sizeof data;
- buffer_write(srv_out, &hdr, sizeof hdr);
- data.idx = arg;
- buffer_write(srv_out, &data, sizeof data);
-
- return (0);
-}
-
-/* Handle detach command. */
-int
-cmd_fn_detach(unused struct buffer *srv_out, unused int arg)
-{
- return (-1);
-}
diff --git a/op-list.c b/op-list.c
new file mode 100644
index 00000000..e2f78efe
--- /dev/null
+++ b/op-list.c
@@ -0,0 +1,126 @@
+/* $Id: op-list.c,v 1.1 2007-09-26 13:43:15 nicm Exp $ */
+
+/*
+ * Copyright (c) 2007 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.
+ */
+
+/* List sessions or windows. */
+void
+op_list(char *name)
+{
+ struct sessions_data sd;
+ struct windows_data wd;
+ struct pollfd pfd;
+ struct hdr hdr;
+
+ /* Send query data. */
+ if (*name == '\0') {
+ hdr.type = MSG_SESSIONS;
+ hdr.size = sizeof sd;
+ buffer_write(server_out, &hdr, sizeof hdr);
+ buffer_write(server_out, &sd, hdr.size);
+ } else {
+ hdr.type = MSG_WINDOWS;
+ hdr.size = sizeof wd;
+ buffer_write(server_out, &hdr, sizeof hdr);
+ strlcpy(wd.name, name, sizeof wd.name);
+ buffer_write(server_out, &wd, hdr.size);
+ }
+
+ /* Main loop. */
+ for (;;) {
+ /* Set up pollfd. */
+ pfd.fd = server_fd;
+ pfd.events = POLLIN;
+ if (BUFFER_USED(server_out) > 0)
+ pfd.events |= POLLOUT;
+
+ /* Do the poll. */
+ if (poll(&pfd, 1, INFTIM) == -1) {
+ if (errno == EAGAIN || errno == EINTR)
+ continue;
+ err(1, "poll");
+ }
+
+ /* Read/write from sockets. */
+ if (buffer_poll(&pfd, server_in, server_out) != 0)
+ errx(1, "lost server");
+
+ /* Process data. */
+ process_list(name);
+ }
+}
+
+void
+op_list_process(const char *name)
+{
+ struct sessions_data sd;
+ struct sessions_entry se;
+ struct windows_data wd;
+ struct windows_entry we;
+ struct hdr hdr;
+ char *tim;
+
+ for (;;) {
+ if (BUFFER_USED(server_in) < sizeof hdr)
+ break;
+ memcpy(&hdr, BUFFER_OUT(server_in), sizeof hdr);
+ if (BUFFER_USED(server_in) < (sizeof hdr) + hdr.size)
+ break;
+ buffer_remove(server_in, sizeof hdr);
+
+ switch (hdr.type) {
+ case MSG_SESSIONS:
+ if (hdr.size < sizeof sd)
+ errx(1, "bad MSG_SESSIONS size");
+ buffer_read(server_in, &sd, sizeof sd);
+ hdr.size -= sizeof sd;
+ if (sd.sessions == 0 && hdr.size == 0)
+ exit(0);
+ if (hdr.size < sd.sessions * sizeof se)
+ errx(1, "bad MSG_SESSIONS size");
+ while (sd.sessions-- > 0) {
+ buffer_read(server_in, &se, sizeof se);
+ tim = ctime(&se.tim);
+ *strchr(tim, '\n') = '\0';
+ printf("%s: %u windows (created %s)\n",
+ se.name, se.windows, tim);
+ }
+ exit(0);
+ case MSG_WINDOWS:
+ if (hdr.size < sizeof wd)
+ errx(1, "bad MSG_WINDOWS size");
+ buffer_read(server_in, &wd, sizeof wd);
+ hdr.size -= sizeof wd;
+ if (wd.windows == 0 && hdr.size == 0)
+ errx(1, "session not found: %s", name);
+ if (hdr.size < wd.windows * sizeof we)
+ errx(1, "bad MSG_WINDOWS size");
+ while (wd.windows-- > 0) {
+ buffer_read(server_in, &we, sizeof we);
+ if (*we.title != '\0') {
+ printf("%u: %s \"%s\" (%s)\n",
+ we.idx, we.name, we.title, we.tty);
+ } else {
+ printf("%u: %s (%s)\n",
+ we.idx, we.name, we.tty);
+ }
+ }
+ exit(0);
+ default:
+ fatalx("unexpected message");
+ }
+ }
+}
diff --git a/op.c b/op.c
new file mode 100644
index 00000000..393ca69f
--- /dev/null
+++ b/op.c
@@ -0,0 +1,64 @@
+/* $Id: op.c,v 1.1 2007-09-26 13:43:15 nicm Exp $ */
+
+/*
+ * Copyright (c) 2007 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 <string.h>
+
+#include "tmux.h"
+
+int
+op_new(char *path, int argc, unused char **argv)
+{
+ struct new_data data;
+ struct client_ctx cctx;
+
+ if (argc != 0) /* XXX -n */
+ return (usage("new"));
+
+ if (client_init(path, &cctx, 1) != 0)
+ return (1);
+
+ strlcpy(data.name, "XXX"/*XXX*/, sizeof data.name);
+ data.sx = cctx.ws.ws_col;
+ data.sy = cctx.ws.ws_row;
+ client_write_server(&cctx, MSG_NEW, &data, sizeof data);
+
+ return (client_main(&cctx));
+}
+
+int
+op_attach(char *path, int argc, unused char **argv)
+{
+ struct attach_data data;
+ struct client_ctx cctx;
+
+ if (argc != 0) /* XXX -n */
+ return (usage("attach"));
+
+ if (client_init(path, &cctx, 1) != 0)
+ return (1);
+
+ strlcpy(data.name, "XXX"/*XXX*/, sizeof data.name);
+ data.sx = cctx.ws.ws_col;
+ data.sy = cctx.ws.ws_row;
+ client_write_server(&cctx, MSG_ATTACH, &data, sizeof data);
+
+ return (client_main(&cctx));
+}
+
diff --git a/server-msg.c b/server-msg.c
index 8bf5af2a..1c0de755 100644
--- a/server-msg.c
+++ b/server-msg.c
@@ -1,4 +1,4 @@
-/* $Id: server-msg.c,v 1.1 2007-09-26 10:35:24 nicm Exp $ */
+/* $Id: server-msg.c,v 1.2 2007-09-26 13:43:15 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -24,25 +24,25 @@
#include "tmux.h"
-void server_msg_fn_attach(struct client *, struct hdr *);
-void server_msg_fn_create(struct client *, struct hdr *);
-void server_msg_fn_input(struct client *, struct hdr *);
-void server_msg_fn_last(struct client *, struct hdr *);
-void server_msg_fn_new(struct client *, struct hdr *);
-void server_msg_fn_next(struct client *, struct hdr *);
-void server_msg_fn_previous(struct client *, struct hdr *);
-void server_msg_fn_refresh(struct client *, struct hdr *);
-void server_msg_fn_rename(struct client *, struct hdr *);
-void server_msg_fn_select(struct client *, struct hdr *);
-void server_msg_fn_sessions(struct client *, struct hdr *);
-void server_msg_fn_size(struct client *, struct hdr *);
-void server_msg_fn_windowlist(struct client *, struct hdr *);
-void server_msg_fn_windows(struct client *, struct hdr *);
+int server_msg_fn_attach(struct hdr *, struct client *);
+int server_msg_fn_create(struct hdr *, struct client *);
+int server_msg_fn_input(struct hdr *, struct client *);
+int server_msg_fn_last(struct hdr *, struct client *);
+int server_msg_fn_new(struct hdr *, struct client *);
+int server_msg_fn_next(struct hdr *, struct client *);
+int server_msg_fn_previous(struct hdr *, struct client *);
+int server_msg_fn_refresh(struct hdr *, struct client *);
+int server_msg_fn_rename(struct hdr *, struct client *);
+int server_msg_fn_select(struct hdr *, struct client *);
+int server_msg_fn_sessions(struct hdr *, struct client *);
+int server_msg_fn_size(struct hdr *, struct client *);
+int server_msg_fn_windowlist(struct hdr *, struct client *);
+int server_msg_fn_windows(struct hdr *, struct client *);
struct server_msg {
enum hdrtype type;
- void (*fn)(struct client *, struct hdr *);
+ int (*fn)(struct hdr *, struct client *);
};
struct server_msg server_msg_table[] = {
{ MSG_ATTACH, server_msg_fn_attach },
@@ -62,41 +62,45 @@ struct server_msg server_msg_table[] = {
};
#define NSERVERMSG (sizeof server_msg_table / sizeof server_msg_table[0])
-void
+int
server_msg_dispatch(struct client *c)
{
struct hdr hdr;
struct server_msg *msg;
u_int i;
-
- if (BUFFER_USED(c->in) < sizeof hdr)
- return;
- memcpy(&hdr, BUFFER_OUT(c->in), sizeof hdr);
- if (BUFFER_USED(c->in) < (sizeof hdr) + hdr.size)
- return;
- buffer_remove(c->in, sizeof hdr);
-
- for (i = 0; i < NSERVERMSG; i++) {
- msg = server_msg_table + i;
- if (msg->type == hdr.type) {
- msg->fn(c, &hdr);
- return;
- }
+ int n;
+
+ for (;;) {
+ if (BUFFER_USED(c->in) < sizeof hdr)
+ return (0);
+ memcpy(&hdr, BUFFER_OUT(c->in), sizeof hdr);
+ if (BUFFER_USED(c->in) < (sizeof hdr) + hdr.size)
+ return (0);
+ buffer_remove(c->in, sizeof hdr);
+
+ for (i = 0; i < NSERVERMSG; i++) {
+ msg = server_msg_table + i;
+ if (msg->type == hdr.type) {
+ if ((n = msg->fn(&hdr, c)) != 0)
+ return (n);
+ break;
+ }
+ }
+ if (i == NSERVERMSG)
+ fatalx("unexpected message");
}
-
- fatalx("unexpected message");
}
/* New message from client. */
-void
-server_msg_fn_new(struct client *c, struct hdr *hdr)
+int
+server_msg_fn_new(struct hdr *hdr, struct client *c)
{
struct new_data data;
const char *shell;
char *cmd, *msg;
if (c->session != NULL)
- return;
+ return (0);
if (hdr->size != sizeof data)
fatalx("bad MSG_NEW size");
buffer_read(c->in, &data, hdr->size);
@@ -110,9 +114,9 @@ server_msg_fn_new(struct client *c, struct hdr *hdr)
if (*data.name != '\0' && session_find(data.name) != NULL) {
xasprintf(&msg, "duplicate session: %s", data.name);
- write_client(c, MSG_READY, msg, strlen(msg));
+ write_client(c, MSG_ERROR, msg, strlen(msg));
xfree(msg);
- return;
+ return (0);
}
shell = getenv("SHELL");
@@ -124,19 +128,20 @@ server_msg_fn_new(struct client *c, struct hdr *hdr)
fatalx("session_create failed");
xfree(cmd);
- write_client(c, MSG_READY, NULL, 0);
draw_client(c, 0, c->sy - 1);
+
+ return (0);
}
/* Attach message from client. */
-void
-server_msg_fn_attach(struct client *c, struct hdr *hdr)
+int
+server_msg_fn_attach(struct hdr *hdr, struct client *c)
{
struct attach_data data;
char *msg;
if (c->session != NULL)
- return;
+ return (0);
if (hdr->size != sizeof data)
fatalx("bad MSG_ATTACH size");
buffer_read(c->in, &data, hdr->size);
@@ -152,24 +157,25 @@ server_msg_fn_attach(struct client *c, struct hdr *hdr)
c->session = session_find(data.name);
if (c->session == NULL) {
xasprintf(&msg, "session not found: %s", data.name);
- write_client(c, MSG_READY, msg, strlen(msg));
+ write_client(c, MSG_ERROR, msg, strlen(msg));
xfree(msg);
- return;
+ return (0);
}
- write_client(c, MSG_READY, NULL, 0);
draw_client(c, 0, c->sy - 1);
+
+ return (0);
}
/* Create message from client. */
-void
-server_msg_fn_create(struct client *c, struct hdr *hdr)
+int
+server_msg_fn_create(struct hdr *hdr, struct client *c)
{
const char *shell;
char *cmd;
if (c->session == NULL)
- return;
+ return (0);
if (hdr->size != 0)
fatalx("bad MSG_CREATE size");
@@ -182,14 +188,16 @@ server_msg_fn_create(struct client *c, struct hdr *hdr)
xfree(cmd);
draw_client(c, 0, c->sy - 1);
+
+ return (0);
}
/* Next message from client. */
-void
-server_msg_fn_next(struct client *c, struct hdr *hdr)
+int
+server_msg_fn_next(struct hdr *hdr, struct client *c)
{
if (c->session == NULL)
- return;
+ return (0);
if (hdr->size != 0)
fatalx("bad MSG_NEXT size");
@@ -197,14 +205,16 @@ server_msg_fn_next(struct client *c, struct hdr *hdr)
changed_window(c);
else
write_message(c, "No next window");
+
+ return (0);
}
/* Previous message from client. */
-void
-server_msg_fn_previous(struct client *c, struct hdr *hdr)
+int
+server_msg_fn_previous(struct hdr *hdr, struct client *c)
{
if (c->session == NULL)
- return;
+ return (0);
if (hdr->size != 0)
fatalx("bad MSG_PREVIOUS size");
@@ -212,16 +222,18 @@ server_msg_fn_previous(struct client *c, struct hdr *hdr)
changed_window(c);
else
write_message(c, "No previous window");
+
+ return (0);
}
/* Size message from client. */
-void
-server_msg_fn_size(struct client *c, struct hdr *hdr)
+int
+server_msg_fn_size(struct hdr *hdr, struct client *c)
{
struct size_data data;
if (c->session == NULL)
- return;
+ return (0);
if (hdr->size != sizeof data)
fatalx("bad MSG_SIZE size");
buffer_read(c->in, &data, hdr->size);
@@ -235,55 +247,63 @@ server_msg_fn_size(struct client *c, struct hdr *hdr)
if (window_resize(c->session->window, c->sx, c->sy) != 0)
draw_client(c, 0, c->sy - 1);
+
+ return (0);
}
/* Input message from client. */
-void
-server_msg_fn_input(struct client *c, struct hdr *hdr)
+int
+server_msg_fn_input(struct hdr *hdr, struct client *c)
{
if (c->session == NULL)
- return;
+ return (0);
window_input(c->session->window, c->in, hdr->size);
+
+ return (0);
}
/* Refresh message from client. */
-void
-server_msg_fn_refresh(struct client *c, struct hdr *hdr)
+int
+server_msg_fn_refresh(struct hdr *hdr, struct client *c)
{
struct refresh_data data;
if (c->session == NULL)
- return;
+ return (0);
if (hdr->size != 0 && hdr->size != sizeof data)
fatalx("bad MSG_REFRESH size");
draw_client(c, 0, c->sy - 1);
+
+ return (0);
}
/* Select message from client. */
-void
-server_msg_fn_select(struct client *c, struct hdr *hdr)
+int
+server_msg_fn_select(struct hdr *hdr, struct client *c)
{
struct select_data data;
if (c->session == NULL)
- return;
+ return (0);
if (hdr->size != sizeof data)
fatalx("bad MSG_SELECT size");
buffer_read(c->in, &data, hdr->size);
if (c->session == NULL)
- return;
+ return (0);
if (session_select(c->session, data.idx) == 0)
changed_window(c);
else
write_message(c, "Window %u not present", data.idx);
+
+ return (0);
}
/* Sessions message from client. */
-void
-server_msg_fn_sessions(struct client *c, struct hdr *hdr)
+int
+server_msg_fn_sessions(struct hdr *hdr, struct client *c)
{
struct sessions_data data;
struct sessions_entry entry;
@@ -315,11 +335,13 @@ server_msg_fn_sessions(struct client *c, struct hdr *hdr)
}
buffer_write(c->out, &entry, sizeof entry);
}
+
+ return (0);
}
/* Windows message from client. */
-void
-server_msg_fn_windows(struct client *c, struct hdr *hdr)
+int
+server_msg_fn_windows(struct hdr *hdr, struct client *c)
{
struct windows_data data;
struct windows_entry entry;
@@ -335,7 +357,7 @@ server_msg_fn_windows(struct client *c, struct hdr *hdr)
if (s == NULL) {
data.windows = 0;
write_client(c, MSG_WINDOWS, &data, sizeof data);
- return;
+ return (0);
}
data.windows = 0;
@@ -357,14 +379,16 @@ server_msg_fn_windows(struct client *c, struct hdr *hdr)
*entry.tty = '\0';
buffer_write(c->out, &entry, sizeof entry);
}
+
+ return (0);
}
/* Rename message from client. */
-void
-server_msg_fn_rename(struct client *c, struct hdr *hdr)
+int
+server_msg_fn_rename(struct hdr *hdr, struct client *c)
{
if (c->session == NULL)
- return;
+ return (0);
if (hdr->size != 0)
fatalx("bad MSG_RENAME size");
@@ -372,11 +396,11 @@ server_msg_fn_rename(struct client *c, struct hdr *hdr)
}
/* Last window message from client */
-void
-server_msg_fn_last(struct client *c, struct hdr *hdr)
+int
+server_msg_fn_last(struct hdr *hdr, struct client *c)
{
if (c->session == NULL)
- return;
+ return (0);
if (hdr->size != 0)
fatalx("bad MSG_LAST size");
@@ -384,11 +408,13 @@ server_msg_fn_last(struct client *c, struct hdr *hdr)
changed_window(c);
else
write_message(c, "No last window");
+
+ return (0);
}
/* Window list message from client */
-void
-server_msg_fn_windowlist(struct client *c, struct hdr *hdr)
+int
+server_msg_fn_windowlist(struct hdr *hdr, struct client *c)
{
struct window *w;
char *buf;
@@ -396,7 +422,7 @@ server_msg_fn_windowlist(struct client *c, struct hdr *hdr)
u_int i;
if (c->session == NULL)
- return;
+ return (0);
if (hdr->size != 0)
fatalx("bad MSG_WINDOWLIST size");
@@ -417,4 +443,6 @@ server_msg_fn_windowlist(struct client *c, struct hdr *hdr)
write_message(c, "%s", buf);
xfree(buf);
+
+ return (0);
}
diff --git a/server.c b/server.c
index 21a35f4f..3c12543d 100644
--- a/server.c
+++ b/server.c
@@ -1,4 +1,4 @@
-/* $Id: server.c,v 1.12 2007-09-26 10:35:24 nicm Exp $ */
+/* $Id: server.c,v 1.13 2007-09-26 13:43:15 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -24,6 +24,7 @@
#include <errno.h>
#include <fcntl.h>
+#include <paths.h>
#include <poll.h>
#include <signal.h>
#include <stdio.h>
@@ -43,7 +44,7 @@
/* Client list. */
struct clients clients;
-int server_main(int);
+int server_main(char *, int);
void fill_windows(struct pollfd **);
void handle_windows(struct pollfd **);
void fill_clients(struct pollfd **);
@@ -52,21 +53,18 @@ struct client *accept_client(int);
void lost_client(struct client *);
void lost_window(struct window *);
-/* Fork and start server process. */
int
-server_start(void)
+server_start(char *path)
{
- mode_t mode;
- int fd;
struct sockaddr_un sa;
size_t sz;
pid_t pid;
- FILE *f;
- char *path;
+ mode_t mode;
+ int fd;
- /* Fork the server process. */
switch (pid = fork()) {
case -1:
+ log_warn("fork");
return (-1);
case 0:
break;
@@ -74,20 +72,15 @@ server_start(void)
return (0);
}
- /* Start logging to file. */
- if (debug_level > 0) {
- xasprintf(&path,
- "%s-server-%ld.log", __progname, (long) getpid());
- f = fopen(path, "w");
- log_open(f, LOG_DAEMON, debug_level);
- xfree(path);
- }
+ logfile("server");
+ setproctitle("server (%s)", path);
+
log_debug("server started, pid %ld", (long) getpid());
/* Create the socket. */
memset(&sa, 0, sizeof sa);
sa.sun_family = AF_UNIX;
- sz = strlcpy(sa.sun_path, socket_path, sizeof sa.sun_path);
+ sz = strlcpy(sa.sun_path, path, sizeof sa.sun_path);
if (sz >= sizeof sa.sun_path) {
errno = ENAMETOOLONG;
fatal("socket failed");
@@ -113,32 +106,17 @@ server_start(void)
fatal("daemon failed");
log_debug("server daemonised, pid now %ld", (long) getpid());
- setproctitle("server (%s)", socket_path);
- exit(server_main(fd));
+ exit(server_main(path, fd));
}
/* Main server loop. */
int
-server_main(int srv_fd)
+server_main(char *srv_path, int srv_fd)
{
struct pollfd *pfds, *pfd;
int nfds, mode;
- struct sigaction act;
-
- sigemptyset(&act.sa_mask);
- act.sa_flags = SA_RESTART;
-
- act.sa_handler = SIG_IGN;
- if (sigaction(SIGPIPE, &act, NULL) != 0)
- fatal("sigaction failed");
- if (sigaction(SIGUSR1, &act, NULL) != 0)
- fatal("sigaction failed");
- if (sigaction(SIGUSR2, &act, NULL) != 0)
- fatal("sigaction failed");
- if (sigaction(SIGINT, &act, NULL) != 0)
- fatal("sigaction failed");
- if (sigaction(SIGQUIT, &act, NULL) != 0)
- fatal("sigaction failed");
+
+ siginit();
ARRAY_INIT(&windows);
ARRAY_INIT(&clients);
@@ -192,7 +170,7 @@ server_main(int srv_fd)
}
close(srv_fd);
- unlink(socket_path);
+ unlink(srv_path);
return (0);
}
diff --git a/tmux.c b/tmux.c
index 881e7900..6ae982eb 100644
--- a/tmux.c
+++ b/tmux.c
@@ -1,4 +1,4 @@
-/* $Id: tmux.c,v 1.8 2007-09-21 18:00:58 nicm Exp $ */
+/* $Id: tmux.c,v 1.9 2007-09-26 13:43:15 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -17,17 +17,9 @@
*/
#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/un.h>
#include <sys/wait.h>
-#include <err.h>
-#include <errno.h>
-#include <fcntl.h>
#include <paths.h>
-#include <getopt.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
@@ -40,44 +32,46 @@
const char *malloc_options = "AFGJPX";
#endif
-void op_new(char *, struct winsize *);
-void op_attach(char *, struct winsize *);
-int connect_server(void);
-int process_server(char **);
-int process_local(void);
-void sighandler(int);
-__dead void usage(void);
-__dead void main_list(char *);
-void process_list(const char *);
-
-/* SIGWINCH received flag. */
volatile sig_atomic_t sigwinch;
-
-/* SIGTERM received flag. */
volatile sig_atomic_t sigterm;
-
-/* Debug output level. */
int debug_level;
-/* Path to server socket. */
-char socket_path[MAXPATHLEN];
+void sighandler(int);
-/* Server socket and buffers. */
-int server_fd = -1;
-struct buffer *server_in;
-struct buffer *server_out;
+struct op {
+ const char *cmd;
+ int (*fn)(char *, int, char **);
+};
+struct op op_table[] = {
+// { "list", op_list },
+ { "new", op_new },
+ { "attach", op_attach }
+};
+#define NOP (sizeof op_table / sizeof op_table[0])
-/* Local socket and buffers. */
-int local_fd = -1;
-struct buffer *local_in;
-struct buffer *local_out;
+int
+usage(const char *s)
+{
+ if (s == NULL)
+ s = "command ...";
+ fprintf(stderr, "usage: %s [-v] [-s path] %s\n", __progname, s);
+ return (1);
+}
-__dead void
-usage(void)
+void
+logfile(const char *name)
{
- fprintf(stderr,
- "usage: %s [-v] [-n name] [-s path] command\n", __progname);
- exit(1);
+ FILE *f;
+ char *path;
+
+ log_close();
+ if (debug_level > 0) {
+ xasprintf(
+ &path, "%s-%s-%ld.log", __progname, name, (long) getpid());
+ f = fopen(path, "w");
+ log_open(f, LOG_DAEMON, debug_level);
+ xfree(path);
+ }
}
void
@@ -96,480 +90,104 @@ sighandler(int sig)
}
}
-int
-main(int argc, char **argv)
+void
+siginit(void)
{
- int opt, mode, n;
- char *path, *error, name[MAXNAMELEN];
- FILE *f;
- enum op op;
- struct pollfd pfds[2];
- struct hdr hdr;
- struct size_data sd;
- struct winsize ws;
struct sigaction act;
- struct stat sb;
-
- *name = '\0';
- path = NULL;
- while ((opt = getopt(argc, argv, "n:s:v?")) != EOF) {
- switch (opt) {
- case 'n':
- if (strlcpy(name, optarg, sizeof name) >= sizeof name)
- errx(1, "name too long");
- break;
- case 's':
- path = xstrdup(optarg);
- break;
- case 'v':
- debug_level++;
- break;
- case '?':
- default:
- usage();
- }
- }
- argc -= optind;
- argv += optind;
- if (argc != 1)
- usage();
-
- /* Determine command. */
- if (strncmp(argv[0], "list", strlen(argv[0])) == 0)
- op = OP_LIST;
- else if (strncmp(argv[0], "new", strlen(argv[0])) == 0)
- op = OP_NEW;
- else if (strncmp(argv[0], "attach", strlen(argv[0])) == 0)
- op = OP_ATTACH;
- else
- usage();
-
- /* Sort out socket path. */
- if (path == NULL) {
- xasprintf(&path,
- "%s/%s-%lu", _PATH_TMP, __progname, (u_long) getuid());
- }
- if (realpath(path, socket_path) == NULL)
- err(1, "realpath");
- xfree(path);
-
- /* Set up signal handlers. */
memset(&act, 0, sizeof act);
sigemptyset(&act.sa_mask);
act.sa_flags = SA_RESTART;
act.sa_handler = SIG_IGN;
if (sigaction(SIGPIPE, &act, NULL) != 0)
- err(1, "sigaction");
+ fatal("sigaction failed");
if (sigaction(SIGUSR1, &act, NULL) != 0)
- err(1, "sigaction");
+ fatal("sigaction failed");
if (sigaction(SIGUSR2, &act, NULL) != 0)
- err(1, "sigaction");
+ fatal("sigaction failed");
if (sigaction(SIGINT, &act, NULL) != 0)
- err(1, "sigaction");
+ fatal("sigaction failed");
if (sigaction(SIGTSTP, &act, NULL) != 0)
- err(1, "sigaction");
+ fatal("sigaction failed");
if (sigaction(SIGQUIT, &act, NULL) != 0)
- err(1, "sigaction");
+ fatal("sigaction failed");
act.sa_handler = sighandler;
if (sigaction(SIGWINCH, &act, NULL) != 0)
- err(1, "sigaction");
+ fatal("sigaction failed");
if (sigaction(SIGTERM, &act, NULL) != 0)
- err(1, "sigaction");
+ fatal("sigaction failed");
if (sigaction(SIGCHLD, &act, NULL) != 0)
- err(1, "sigaction");
-
- /* Start server if necessary. */
- n = 0;
-restart:
- if (stat(socket_path, &sb) != 0) {
- if (errno != ENOENT)
- err(1, "%s", socket_path);
- else if (op != OP_LIST) {
- if (server_start() != 0)
- errx(1, "couldn't start server");
- sleep(1); /* XXX this sucks */
- }
- } else {
- if (!S_ISSOCK(sb.st_mode))
- errx(1, "%s: not a socket", socket_path);
- }
-
- /* Connect to server. */
- if ((server_fd = connect_server()) == -1) {
- if (errno == ECONNREFUSED && n++ < 5) {
- unlink(socket_path);
- goto restart;
- }
- errx(1, "couldn't find server");
- }
- if ((mode = fcntl(server_fd, F_GETFL)) == -1)
- err(1, "fcntl");
- if (fcntl(server_fd, F_SETFL, mode|O_NONBLOCK) == -1)
- err(1, "fcntl");
- server_in = buffer_create(BUFSIZ);
- server_out = buffer_create(BUFSIZ);
-
- /* Skip to list function if listing. */
- if (op == OP_LIST)
- main_list(name);
-
- /* Check stdin/stdout. */
- if (!isatty(STDIN_FILENO))
- errx(1, "stdin is not a tty");
- if (!isatty(STDOUT_FILENO))
- errx(1, "stdout is not a tty");
-
- /* Find window size. */
- if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1)
- err(1, "ioctl(TIOCGWINSZ)");
-
- /* Send initial data. */
- switch (op) {
- case OP_NEW:
- op_new(name, &ws);
- break;
- case OP_ATTACH:
- op_attach(name, &ws);
- break;
- default:
- fatalx("unknown op");
- }
-
- /* Start logging to file. */
- if (debug_level > 0) {
- xasprintf(&path,
- "%s-client-%ld.log", __progname, (long) getpid());
- f = fopen(path, "w");
- log_open(f, LOG_USER, debug_level);
- xfree(path);
- }
- setproctitle("client (%s)", name);
-
- /* Main loop. */
- n = 0;
- while (!sigterm) {
- /* Handle SIGWINCH if necessary. */
- if (local_fd != -1 && sigwinch) {
- if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1)
- fatal("ioctl failed");
-
- hdr.type = MSG_SIZE;
- hdr.size = sizeof sd;
- buffer_write(server_out, &hdr, sizeof hdr);
- sd.sx = ws.ws_col;
- sd.sy = ws.ws_row;
- buffer_write(server_out, &sd, hdr.size);
-
- sigwinch = 0;
- }
-
- /* Set up pollfds. */
- pfds[0].fd = server_fd;
- pfds[0].events = POLLIN;
- if (BUFFER_USED(server_out) > 0)
- pfds[0].events |= POLLOUT;
- pfds[1].fd = local_fd;
- pfds[1].events = POLLIN;
- if (local_fd != -1 && BUFFER_USED(local_out) > 0)
- pfds[1].events |= POLLOUT;
-
- /* Do the poll. */
- if (poll(pfds, 2, INFTIM) == -1) {
- if (errno == EAGAIN || errno == EINTR)
- continue;
- fatal("poll failed");
- }
-
- /* Read/write from sockets. */
- if (buffer_poll(&pfds[0], server_in, server_out) != 0)
- goto server_dead;
- if (local_fd != -1 &&
- buffer_poll(&pfds[1], local_in, local_out) != 0)
- fatalx("lost local socket");
-
- /* Output flushed; pause if requested. */
- if (n)
- usleep(750000);
-
- /* Process any data. */
- if ((n = process_server(&error)) == -1)
- break;
- if (process_local() == -1)
- break;
- }
-
- if (local_fd != -1)
- local_done();
-
- if (error != NULL)
- errx(1, "%s", error);
-
- if (!sigterm)
- printf("[detached]\n");
- else
- printf("[terminated]\n");
- exit(0);
-
-server_dead:
- if (local_fd != -1)
- local_done();
-
- printf("[lost server]\n");
- exit(1);
+ fatal("sigaction failed");
}
-/* New command. */
void
-op_new(char *name, struct winsize *ws)
+sigreset(void)
{
- struct new_data data;
- struct hdr hdr;
-
- hdr.type = MSG_NEW;
- hdr.size = sizeof data;
- buffer_write(server_out, &hdr, sizeof hdr);
-
- strlcpy(data.name, name, sizeof data.name);
- data.sx = ws->ws_col;
- data.sy = ws->ws_row;
- buffer_write(server_out, &data, hdr.size);
-}
-
-/* Attach command. */
-void
-op_attach(char *name, struct winsize *ws)
-{
- struct attach_data data;
- struct hdr hdr;
-
- hdr.type = MSG_ATTACH;
- hdr.size = sizeof data;
- buffer_write(server_out, &hdr, sizeof hdr);
-
- strlcpy(data.name, name, sizeof data.name);
- data.sx = ws->ws_col;
- data.sy = ws->ws_row;
- buffer_write(server_out, &data, hdr.size);
-}
-
-/* Connect to server socket from PID. */
-int
-connect_server(void)
-{
- int fd;
- struct sockaddr_un sa;
- size_t sz;
-
- memset(&sa, 0, sizeof sa);
- sa.sun_family = AF_UNIX;
- sz = strlcpy(sa.sun_path, socket_path, sizeof sa.sun_path);
- if (sz >= sizeof sa.sun_path) {
- errno = ENAMETOOLONG;
- return (-1);
- }
-
- if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
- return (-1);
- if (connect(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1)
- return (-1);
- return (fd);
+ struct sigaction act;
+
+ memset(&act, 0, sizeof act);
+ sigemptyset(&act.sa_mask);
+
+ act.sa_handler = SIG_DFL;
+ if (sigaction(SIGPIPE, &act, NULL) != 0)
+ fatal("sigaction failed");
+ if (sigaction(SIGUSR1, &act, NULL) != 0)
+ fatal("sigaction failed");
+ if (sigaction(SIGUSR2, &act, NULL) != 0)
+ fatal("sigaction failed");
+ if (sigaction(SIGINT, &act, NULL) != 0)
+ fatal("sigaction failed");
+ if (sigaction(SIGTSTP, &act, NULL) != 0)
+ fatal("sigaction failed");
+ if (sigaction(SIGQUIT, &act, NULL) != 0)
+ fatal("sigaction failed");
+ if (sigaction(SIGWINCH, &act, NULL) != 0)
+ fatal("sigaction failed");
+ if (sigaction(SIGTERM, &act, NULL) != 0)
+ fatal("sigaction failed");
+ if (sigaction(SIGCHLD, &act, NULL) != 0)
+ fatal("sigaction failed");
}
-/* Handle data from server. */
int
-process_server(char **error)
+main(int argc, char **argv)
{
- struct hdr hdr;
-
- *error = NULL;
- for (;;) {
- if (BUFFER_USED(server_in) < sizeof hdr)
- break;
- memcpy(&hdr, BUFFER_OUT(server_in), sizeof hdr);
- if (BUFFER_USED(server_in) < (sizeof hdr) + hdr.size)
- break;
- buffer_remove(server_in, sizeof hdr);
+ struct op *op;
+ char *path;
+ int opt;
+ u_int i;
- switch (hdr.type) {
- case MSG_READY:
- if (hdr.size != 0) {
- xasprintf(error, "%.*s",
- (int) hdr.size, BUFFER_OUT(server_in));
- return (-1);
- }
- local_fd = local_init(&local_in, &local_out);
- break;
- case MSG_OUTPUT:
- local_output(server_in, hdr.size);
+ path = NULL;
+ while ((opt = getopt(argc, argv, "s:v?")) != EOF) {
+ switch (opt) {
+ case 's':
+ path = xstrdup(optarg);
break;
- case MSG_PAUSE:
- if (hdr.size != 0)
- fatalx("bad MSG_PAUSE size");
- return (1);
- case MSG_EXIT:
- return (-1);
- default:
- fatalx("unexpected message");
- }
- }
-
- return (0);
-}
-
-/* Handle data from local terminal. */
-int
-process_local(void)
-{
- struct buffer *b;
- struct hdr hdr;
- size_t size;
- int n, key;
-
- if (local_fd == -1)
- return (0);
-
- n = 0;
- b = buffer_create(BUFSIZ);
-
- while ((key = local_key(&size)) != KEYC_NONE) {
- log_debug("key code: %d", key);
-
- if (key == cmd_prefix) {
- if ((key = local_key(NULL)) == KEYC_NONE) {
- buffer_reverse_remove(local_in, size);
- break;
- }
- n = cmd_execute(key, server_out);
+ case 'v':
+ debug_level++;
break;
- }
-
- input_store8(b, '\e');
- input_store16(b, (uint16_t) key);
- }
-
- if (BUFFER_USED(b) == 0) {
- buffer_destroy(b);
- return (n);
- }
- log_debug("transmitting %zu bytes of input", BUFFER_USED(b));
-
- hdr.type = MSG_INPUT;
- hdr.size = BUFFER_USED(b);
- buffer_write(server_out, &hdr, sizeof hdr);
- buffer_write(server_out, BUFFER_OUT(b), BUFFER_USED(b));
-
- buffer_destroy(b);
- return (n);
-}
-
-/* List sessions or windows. */
-__dead void
-main_list(char *name)
-{
- struct sessions_data sd;
- struct windows_data wd;
- struct pollfd pfd;
- struct hdr hdr;
-
- /* Send query data. */
- if (*name == '\0') {
- hdr.type = MSG_SESSIONS;
- hdr.size = sizeof sd;
- buffer_write(server_out, &hdr, sizeof hdr);
- buffer_write(server_out, &sd, hdr.size);
- } else {
- hdr.type = MSG_WINDOWS;
- hdr.size = sizeof wd;
- buffer_write(server_out, &hdr, sizeof hdr);
- strlcpy(wd.name, name, sizeof wd.name);
- buffer_write(server_out, &wd, hdr.size);
- }
+ case '?':
+ default:
+ exit(usage(NULL));
+ }
+ }
+ argc -= optind;
+ argv += optind;
+ if (argc == 0)
+ exit(usage(NULL));
- /* Main loop. */
- for (;;) {
- /* Set up pollfd. */
- pfd.fd = server_fd;
- pfd.events = POLLIN;
- if (BUFFER_USED(server_out) > 0)
- pfd.events |= POLLOUT;
+ log_open(stderr, LOG_USER, debug_level);
- /* Do the poll. */
- if (poll(&pfd, 1, INFTIM) == -1) {
- if (errno == EAGAIN || errno == EINTR)
- continue;
- err(1, "poll");
+ for (i = 0; i < NOP; i++) {
+ op = op_table + i;
+ if (strncmp(argv[0], op->cmd, strlen(op->cmd)) == 0) {
+ argc--;
+ argv++;
+ exit(op->fn(path, argc, argv));
}
-
- /* Read/write from sockets. */
- if (buffer_poll(&pfd, server_in, server_out) != 0)
- errx(1, "lost server");
-
- /* Process data. */
- process_list(name);
}
-}
-void
-process_list(const char *name)
-{
- struct sessions_data sd;
- struct sessions_entry se;
- struct windows_data wd;
- struct windows_entry we;
- struct hdr hdr;
- char *tim;
-
- for (;;) {
- if (BUFFER_USED(server_in) < sizeof hdr)
- break;
- memcpy(&hdr, BUFFER_OUT(server_in), sizeof hdr);
- if (BUFFER_USED(server_in) < (sizeof hdr) + hdr.size)
- break;
- buffer_remove(server_in, sizeof hdr);
-
- switch (hdr.type) {
- case MSG_SESSIONS:
- if (hdr.size < sizeof sd)
- errx(1, "bad MSG_SESSIONS size");
- buffer_read(server_in, &sd, sizeof sd);
- hdr.size -= sizeof sd;
- if (sd.sessions == 0 && hdr.size == 0)
- exit(0);
- if (hdr.size < sd.sessions * sizeof se)
- errx(1, "bad MSG_SESSIONS size");
- while (sd.sessions-- > 0) {
- buffer_read(server_in, &se, sizeof se);
- tim = ctime(&se.tim);
- *strchr(tim, '\n') = '\0';
- printf("%s: %u windows (created %s)\n",
- se.name, se.windows, tim);
- }
- exit(0);
- case MSG_WINDOWS:
- if (hdr.size < sizeof wd)
- errx(1, "bad MSG_WINDOWS size");
- buffer_read(server_in, &wd, sizeof wd);
- hdr.size -= sizeof wd;
- if (wd.windows == 0 && hdr.size == 0)
- errx(1, "session not found: %s", name);
- if (hdr.size < wd.windows * sizeof we)
- errx(1, "bad MSG_WINDOWS size");
- while (wd.windows-- > 0) {
- buffer_read(server_in, &we, sizeof we);
- if (*we.title != '\0') {
- printf("%u: %s \"%s\" (%s)\n",
- we.idx, we.name, we.title, we.tty);
- } else {
- printf("%u: %s (%s)\n",
- we.idx, we.name, we.tty);
- }
- }
- exit(0);
- default:
- fatalx("unexpected message");
- }
- }
+ exit(usage(NULL));
}
diff --git a/tmux.h b/tmux.h
index cb10a3cf..c35a951f 100644
--- a/tmux.h
+++ b/tmux.h
@@ -1,4 +1,4 @@
-/* $Id: tmux.h,v 1.11 2007-09-26 10:35:24 nicm Exp $ */
+/* $Id: tmux.h,v 1.12 2007-09-26 13:43:15 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -257,18 +257,11 @@ struct buffer {
#define CODE_KKEYPADON 25
#define CODE_TITLE 26
-/* Command-line commands. */
-enum op {
- OP_LIST = 0,
- OP_NEW,
- OP_ATTACH
-};
-
/* Message codes. */
enum hdrtype {
MSG_NEW = 0,
MSG_ATTACH,
- MSG_READY,
+ MSG_ERROR,
MSG_CREATE,
MSG_EXIT,
MSG_SIZE,
@@ -423,17 +416,50 @@ struct client {
};
ARRAY_DECL(clients, struct client *);
+/* Client context. */
+struct client_ctx {
+ int srv_fd;
+ struct buffer *srv_in;
+ struct buffer *srv_out;
+
+ int loc_fd;
+ struct buffer *loc_in;
+ struct buffer *loc_out;
+
+ struct winsize ws;
+};
+
/* tmux.c */
-volatile sig_atomic_t sigterm;
-extern int debug_level;
-extern char socket_path[MAXPATHLEN];
+extern volatile sig_atomic_t sigwinch;
+extern volatile sig_atomic_t sigterm;
+extern int debug_level;
+int usage(const char *);
+void logfile(const char *);
+void siginit(void);
+void sigreset(void);
+
+/* op.c */
+int op_new(char *, int, char **);
+int op_attach(char *, int, char **);
+
+/* client.c */
+int client_init(char *, struct client_ctx *, int);
+int client_main(struct client_ctx *);
+void client_write_server(struct client_ctx *, enum hdrtype, void *, size_t);
+
+/* client-msg.c */
+int client_msg_dispatch(struct client_ctx *, const char **);
+
+/* command.c */
+extern int client_cmd_prefix;
+int client_cmd_dispatch(int, struct client_ctx *, const char **);
/* server.c */
extern struct clients clients;
-int server_start(void);
+int server_start(char *);
/* server-msg.c */
-void server_msg_dispatch(struct client *);
+int server_msg_dispatch(struct client *);
/* server-fn.c */
void write_message(struct client *, const char *, ...);
@@ -468,10 +494,6 @@ void local_done(void);
int local_key(size_t *);
void local_output(struct buffer *, size_t);
-/* command.c */
-extern int cmd_prefix;
-int cmd_execute(int, struct buffer *);
-
/* window.c */
extern struct windows windows;
struct window *window_create(const char *, u_int, u_int);