aboutsummaryrefslogtreecommitdiff
path: root/tmux.c
diff options
context:
space:
mode:
Diffstat (limited to 'tmux.c')
-rw-r--r--tmux.c578
1 files changed, 98 insertions, 480 deletions
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));
}