Change command format.

This commit is contained in:
Nicholas Marriott 2007-08-27 13:45:26 +00:00
parent 6e210bb005
commit 04f4e4219b
6 changed files with 337 additions and 262 deletions

29
NOTES
View File

@ -11,10 +11,31 @@ Commands: d detach
There is one default server process per user which puts its socket in There is one default server process per user which puts its socket in
/tmp/tmux-UID. It is created the first time tmux is run and subsequent /tmp/tmux-UID. It is created the first time tmux is run and subsequent
invocations will connect to the same server. The server holds multiple invocations will connect to the same server. The server holds multiple
sessions, call tmux with "-n <session name>" to create a session or attach to sessions.
an existing session. All the sessions may be listed with -l, or the windows of
a single session with "-ln <session name>". Sessions are destroyed when no Syntax is: tmux [-v] [-n name] [-s path] command
windows remain attached to them.
The command is either list, new or attach. Create a new session with:
tmux new
Optionally giving it a name with:
tmux -n <session name> new
Attach to a previous session with:
tmux -n <session name> attach
List all sessions with:
tmux list
Or the windows of a single session with:
tmux -n <session name> list
Sessions are destroyed when no windows remain attached to them.
Another server process can be used by specifying an alternative socket path with Another server process can be used by specifying an alternative socket path with
"-s <path>" but it shouldn't normally be required. "-s <path>" but it shouldn't normally be required.

View File

@ -1,4 +1,4 @@
/* $Id: command.c,v 1.2 2007-08-27 10:30:28 nicm Exp $ */ /* $Id: command.c,v 1.3 2007-08-27 13:45:26 nicm Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -83,7 +83,7 @@ cmd_fn_select(struct buffer *srv_out, int arg)
struct hdr hdr; struct hdr hdr;
struct select_data data; struct select_data data;
hdr.code = MSG_SELECT; hdr.type = MSG_SELECT;
hdr.size = sizeof data; hdr.size = sizeof data;
buffer_write(srv_out, &hdr, sizeof hdr); buffer_write(srv_out, &hdr, sizeof hdr);
data.idx = arg; data.idx = arg;
@ -98,7 +98,7 @@ cmd_fn_create(struct buffer *srv_out, unused int arg)
{ {
struct hdr hdr; struct hdr hdr;
hdr.code = MSG_CREATE; hdr.type = MSG_CREATE;
hdr.size = 0; hdr.size = 0;
buffer_write(srv_out, &hdr, sizeof hdr); buffer_write(srv_out, &hdr, sizeof hdr);
@ -118,7 +118,7 @@ cmd_fn_next(struct buffer *srv_out, unused int arg)
{ {
struct hdr hdr; struct hdr hdr;
hdr.code = MSG_NEXT; hdr.type = MSG_NEXT;
hdr.size = 0; hdr.size = 0;
buffer_write(srv_out, &hdr, sizeof hdr); buffer_write(srv_out, &hdr, sizeof hdr);
@ -131,7 +131,7 @@ cmd_fn_previous(struct buffer *srv_out, unused int arg)
{ {
struct hdr hdr; struct hdr hdr;
hdr.code = MSG_PREVIOUS; hdr.type = MSG_PREVIOUS;
hdr.size = 0; hdr.size = 0;
buffer_write(srv_out, &hdr, sizeof hdr); buffer_write(srv_out, &hdr, sizeof hdr);
@ -144,7 +144,7 @@ cmd_fn_refresh(struct buffer *srv_out, unused int arg)
{ {
struct hdr hdr; struct hdr hdr;
hdr.code = MSG_REFRESH; hdr.type = MSG_REFRESH;
hdr.size = 0; hdr.size = 0;
buffer_write(srv_out, &hdr, sizeof hdr); buffer_write(srv_out, &hdr, sizeof hdr);
@ -157,7 +157,7 @@ cmd_fn_rename(struct buffer *srv_out, unused int arg)
{ {
struct hdr hdr; struct hdr hdr;
hdr.code = MSG_RENAME; hdr.type = MSG_RENAME;
hdr.size = 0; hdr.size = 0;
buffer_write(srv_out, &hdr, sizeof hdr); buffer_write(srv_out, &hdr, sizeof hdr);

122
server.c
View File

@ -1,4 +1,4 @@
/* $Id: server.c,v 1.5 2007-08-27 12:05:15 nicm Exp $ */ /* $Id: server.c,v 1.6 2007-08-27 13:45:26 nicm Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -63,7 +63,8 @@ void lost_window(struct window *);
void changed_window(struct client *); void changed_window(struct client *);
void draw_client(struct client *, u_int, u_int); void draw_client(struct client *, u_int, u_int);
void process_client(struct client *); void process_client(struct client *);
void process_identify_msg(struct client *, struct hdr *); void process_new_msg(struct client *, struct hdr *);
void process_attach_msg(struct client *, struct hdr *);
void process_create_msg(struct client *, struct hdr *); void process_create_msg(struct client *, struct hdr *);
void process_next_msg(struct client *, struct hdr *); void process_next_msg(struct client *, struct hdr *);
void process_previous_msg(struct client *, struct hdr *); void process_previous_msg(struct client *, struct hdr *);
@ -388,11 +389,11 @@ write_message(struct client *c, const char *fmt, ...)
input_store8(c->out, ' '); input_store8(c->out, ' ');
size = BUFFER_USED(c->out) - size; size = BUFFER_USED(c->out) - size;
hdr.code = MSG_OUTPUT; hdr.type = MSG_OUTPUT;
hdr.size = size; hdr.size = size;
memcpy(BUFFER_IN(c->out) - size - sizeof hdr, &hdr, sizeof hdr); memcpy(BUFFER_IN(c->out) - size - sizeof hdr, &hdr, sizeof hdr);
hdr.code = MSG_PAUSE; hdr.type = MSG_PAUSE;
hdr.size = 0; hdr.size = 0;
buffer_write(c->out, &hdr, sizeof hdr); buffer_write(c->out, &hdr, sizeof hdr);
@ -403,7 +404,7 @@ write_message(struct client *c, const char *fmt, ...)
screen_draw(&c->session->window->screen, c->out, c->sy - 1, c->sy - 1); screen_draw(&c->session->window->screen, c->out, c->sy - 1, c->sy - 1);
size = BUFFER_USED(c->out) - size; size = BUFFER_USED(c->out) - size;
hdr.code = MSG_OUTPUT; hdr.type = MSG_OUTPUT;
hdr.size = size; hdr.size = size;
memcpy(BUFFER_IN(c->out) - size - sizeof hdr, &hdr, sizeof hdr); memcpy(BUFFER_IN(c->out) - size - sizeof hdr, &hdr, sizeof hdr);
} }
@ -452,7 +453,7 @@ user_start(struct client *c, const char *prompt, const char *now,
input_store_zero(c->out, CODE_CURSORON); input_store_zero(c->out, CODE_CURSORON);
size = BUFFER_USED(c->out) - size; size = BUFFER_USED(c->out) - size;
hdr.code = MSG_OUTPUT; hdr.type = MSG_OUTPUT;
hdr.size = size; hdr.size = size;
memcpy(BUFFER_IN(c->out) - size - sizeof hdr, &hdr, sizeof hdr); memcpy(BUFFER_IN(c->out) - size - sizeof hdr, &hdr, sizeof hdr);
} }
@ -589,7 +590,7 @@ user_input(struct client *c, size_t in)
size = BUFFER_USED(c->out) - size; size = BUFFER_USED(c->out) - size;
if (size != 0) { if (size != 0) {
hdr.code = MSG_OUTPUT; hdr.type = MSG_OUTPUT;
hdr.size = size; hdr.size = size;
memcpy(BUFFER_IN(c->out) - size - sizeof hdr, &hdr, sizeof hdr); memcpy(BUFFER_IN(c->out) - size - sizeof hdr, &hdr, sizeof hdr);
} else } else
@ -602,7 +603,7 @@ write_client(struct client *c, u_int cmd, void *buf, size_t len)
{ {
struct hdr hdr; struct hdr hdr;
hdr.code = cmd; hdr.type = cmd;
hdr.size = len; hdr.size = len;
buffer_write(c->out, &hdr, sizeof hdr); buffer_write(c->out, &hdr, sizeof hdr);
@ -617,7 +618,7 @@ write_client2(struct client *c,
{ {
struct hdr hdr; struct hdr hdr;
hdr.code = cmd; hdr.type = cmd;
hdr.size = len1 + len2; hdr.size = len1 + len2;
buffer_write(c->out, &hdr, sizeof hdr); buffer_write(c->out, &hdr, sizeof hdr);
@ -635,7 +636,7 @@ write_clients(struct window *w, u_int cmd, void *buf, size_t len)
struct hdr hdr; struct hdr hdr;
u_int i; u_int i;
hdr.code = cmd; hdr.type = cmd;
hdr.size = len; hdr.size = len;
for (i = 0; i < ARRAY_LENGTH(&clients); i++) { for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
@ -714,7 +715,7 @@ draw_client(struct client *c, u_int py_upper, u_int py_lower)
size = BUFFER_USED(c->out) - size; size = BUFFER_USED(c->out) - size;
log_debug("redrawing screen, %zu bytes", size); log_debug("redrawing screen, %zu bytes", size);
if (size != 0) { if (size != 0) {
hdr.code = MSG_OUTPUT; hdr.type = MSG_OUTPUT;
hdr.size = size; hdr.size = size;
memcpy( memcpy(
BUFFER_IN(c->out) - size - sizeof hdr, &hdr, sizeof hdr); BUFFER_IN(c->out) - size - sizeof hdr, &hdr, sizeof hdr);
@ -735,9 +736,12 @@ process_client(struct client *c)
return; return;
buffer_remove(c->in, sizeof hdr); buffer_remove(c->in, sizeof hdr);
switch (hdr.code) { switch (hdr.type) {
case MSG_IDENTIFY: case MSG_NEW:
process_identify_msg(c, &hdr); process_new_msg(c, &hdr);
break;
case MSG_ATTACH:
process_attach_msg(c, &hdr);
break; break;
case MSG_CREATE: case MSG_CREATE:
process_create_msg(c, &hdr); process_create_msg(c, &hdr);
@ -769,19 +773,23 @@ process_client(struct client *c)
case MSG_RENAME: case MSG_RENAME:
process_rename_msg(c, &hdr); process_rename_msg(c, &hdr);
break; break;
default:
fatalx("unexpected message");
} }
} }
/* Identify message from client. */ /* New message from client. */
void void
process_identify_msg(struct client *c, struct hdr *hdr) process_new_msg(struct client *c, struct hdr *hdr)
{ {
struct identify_data data; struct new_data data;
const char *shell; const char *shell;
char *cmd; char *cmd, *msg;
if (c->session != NULL)
return;
if (hdr->size != sizeof data) if (hdr->size != sizeof data)
fatalx("bad MSG_IDENTIFY size"); fatalx("bad MSG_NEW size");
buffer_read(c->in, &data, hdr->size); buffer_read(c->in, &data, hdr->size);
c->sx = data.sx; c->sx = data.sx;
@ -790,21 +798,57 @@ process_identify_msg(struct client *c, struct hdr *hdr)
c->sy = data.sy; c->sy = data.sy;
if (c->sy == 0) if (c->sy == 0)
c->sy = 25; c->sy = 25;
/* Try and find session or create if not found. */ if (*data.name != '\0' && session_find(data.name) != NULL) {
c->session = session_find(data.name); xasprintf(&msg, "duplicate session: %s", data.name);
if (c->session == NULL) { write_client(c, MSG_READY, msg, strlen(msg));
shell = getenv("SHELL"); xfree(msg);
if (shell == NULL) return;
shell = "/bin/ksh";
xasprintf(&cmd, "%s -l", shell);
c->session =
session_create(data.name, cmd, c->sx, c->sy);
xfree(cmd);
} }
shell = getenv("SHELL");
if (shell == NULL)
shell = "/bin/ksh";
xasprintf(&cmd, "%s -l", shell);
c->session = session_create(data.name, cmd, c->sx, c->sy);
if (c->session == NULL) if (c->session == NULL)
fatalx("session_create failed"); fatalx("session_create failed");
xfree(cmd);
write_client(c, MSG_READY, NULL, 0);
draw_client(c, 0, c->sy - 1);
}
/* Attach message from client. */
void
process_attach_msg(struct client *c, struct hdr *hdr)
{
struct attach_data data;
char *msg;
if (c->session != NULL)
return;
if (hdr->size != sizeof data)
fatalx("bad MSG_ATTACH size");
buffer_read(c->in, &data, hdr->size);
c->sx = data.sx;
if (c->sx == 0)
c->sx = 80;
c->sy = data.sy;
if (c->sy == 0)
c->sy = 25;
if (*data.name != '\0')
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));
xfree(msg);
return;
}
write_client(c, MSG_READY, NULL, 0);
draw_client(c, 0, c->sy - 1); draw_client(c, 0, c->sy - 1);
} }
@ -816,7 +860,7 @@ process_create_msg(struct client *c, struct hdr *hdr)
char *cmd; char *cmd;
if (c->session == NULL) if (c->session == NULL)
fatalx("MSG_CREATE before identified"); return;
if (hdr->size != 0) if (hdr->size != 0)
fatalx("bad MSG_CREATE size"); fatalx("bad MSG_CREATE size");
@ -836,7 +880,7 @@ void
process_next_msg(struct client *c, struct hdr *hdr) process_next_msg(struct client *c, struct hdr *hdr)
{ {
if (c->session == NULL) if (c->session == NULL)
fatalx("MSG_NEXT before identified"); return;
if (hdr->size != 0) if (hdr->size != 0)
fatalx("bad MSG_NEXT size"); fatalx("bad MSG_NEXT size");
@ -851,7 +895,7 @@ void
process_previous_msg(struct client *c, struct hdr *hdr) process_previous_msg(struct client *c, struct hdr *hdr)
{ {
if (c->session == NULL) if (c->session == NULL)
fatalx("MSG_PREVIOUS before identified"); return;
if (hdr->size != 0) if (hdr->size != 0)
fatalx("bad MSG_PREVIOUS size"); fatalx("bad MSG_PREVIOUS size");
@ -868,7 +912,7 @@ process_size_msg(struct client *c, struct hdr *hdr)
struct size_data data; struct size_data data;
if (c->session == NULL) if (c->session == NULL)
fatalx("MSG_SIZE before identified"); return;
if (hdr->size != sizeof data) if (hdr->size != sizeof data)
fatalx("bad MSG_SIZE size"); fatalx("bad MSG_SIZE size");
buffer_read(c->in, &data, hdr->size); buffer_read(c->in, &data, hdr->size);
@ -889,7 +933,7 @@ void
process_input_msg(struct client *c, struct hdr *hdr) process_input_msg(struct client *c, struct hdr *hdr)
{ {
if (c->session == NULL) if (c->session == NULL)
fatalx("MSG_INPUT before identified"); return;
if (c->prompt == NULL) if (c->prompt == NULL)
window_input(c->session->window, c->in, hdr->size); window_input(c->session->window, c->in, hdr->size);
@ -904,7 +948,7 @@ process_refresh_msg(struct client *c, struct hdr *hdr)
struct refresh_data data; struct refresh_data data;
if (c->session == NULL) if (c->session == NULL)
fatalx("MSG_REFRESH before identified"); return;
if (hdr->size != 0 && hdr->size != sizeof data) if (hdr->size != 0 && hdr->size != sizeof data)
fatalx("bad MSG_REFRESH size"); fatalx("bad MSG_REFRESH size");
@ -918,7 +962,7 @@ process_select_msg(struct client *c, struct hdr *hdr)
struct select_data data; struct select_data data;
if (c->session == NULL) if (c->session == NULL)
fatalx("MSG_SELECT before identified"); return;
if (hdr->size != sizeof data) if (hdr->size != sizeof data)
fatalx("bad MSG_SELECT size"); fatalx("bad MSG_SELECT size");
buffer_read(c->in, &data, hdr->size); buffer_read(c->in, &data, hdr->size);
@ -1014,7 +1058,7 @@ void
process_rename_msg(struct client *c, struct hdr *hdr) process_rename_msg(struct client *c, struct hdr *hdr)
{ {
if (c->session == NULL) if (c->session == NULL)
fatalx("MSG_RENAME before identified"); return;
if (hdr->size != 0) if (hdr->size != 0)
fatalx("bad MSG_RENAME size"); fatalx("bad MSG_RENAME size");

View File

@ -1,4 +1,4 @@
/* $Id: session.c,v 1.4 2007-08-27 12:05:15 nicm Exp $ */ /* $Id: session.c,v 1.5 2007-08-27 13:45:26 nicm Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -50,8 +50,7 @@ session_create(const char *name, const char *cmd, u_int sx, u_int sy)
u_int i; u_int i;
s = xmalloc(sizeof *s); s = xmalloc(sizeof *s);
s->tim = time(NULL); s->tim = time(NULL);
strlcpy(s->name, name, sizeof s->name);
ARRAY_INIT(&s->windows); ARRAY_INIT(&s->windows);
if (session_new(s, cmd, sx, sy) != 0) { if (session_new(s, cmd, sx, sy) != 0) {
@ -60,13 +59,19 @@ session_create(const char *name, const char *cmd, u_int sx, u_int sy)
} }
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
s = ARRAY_ITEM(&sessions, i); if (ARRAY_ITEM(&sessions, i) == NULL) {
if (s == NULL) {
ARRAY_SET(&sessions, i, s); ARRAY_SET(&sessions, i, s);
return (s); break;
} }
} }
ARRAY_ADD(&sessions, s); if (i == ARRAY_LENGTH(&sessions))
ARRAY_ADD(&sessions, s);
if (*name != '\0')
strlcpy(s->name, name, sizeof s->name);
else
xsnprintf(s->name, sizeof s->name, "session-%u", i);
return (s); return (s);
} }
@ -128,7 +133,6 @@ session_detach(struct session *s, struct window *w)
} }
window_remove(&s->windows, w); window_remove(&s->windows, w);
return (0);
} }
/* Flush session if it is empty. */ /* Flush session if it is empty. */

292
tmux.c
View File

@ -1,4 +1,4 @@
/* $Id: tmux.c,v 1.2 2007-07-25 23:13:18 nicm Exp $ */ /* $Id: tmux.c,v 1.3 2007-08-27 13:45:26 nicm Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -40,13 +40,15 @@
const char *malloc_options = "AFGJPX"; const char *malloc_options = "AFGJPX";
#endif #endif
void op_new(char *, struct winsize *);
void op_attach(char *, struct winsize *);
int connect_server(void); int connect_server(void);
int process_server(struct buffer *); int process_server(char **);
int process_local(struct buffer *, struct buffer *); int process_local(void);
void sighandler(int); void sighandler(int);
__dead void usage(void); __dead void usage(void);
__dead void main_list(char *); __dead void main_list(char *);
void process_list(struct buffer *, const char *); void process_list(const char *);
/* SIGWINCH received flag. */ /* SIGWINCH received flag. */
volatile sig_atomic_t sigwinch; volatile sig_atomic_t sigwinch;
@ -60,11 +62,21 @@ int debug_level;
/* Path to server socket. */ /* Path to server socket. */
char socket_path[MAXPATHLEN]; char socket_path[MAXPATHLEN];
/* Server socket and buffers. */
int server_fd = -1;
struct buffer *server_in;
struct buffer *server_out;
/* Local socket and buffers. */
int local_fd = -1;
struct buffer *local_in;
struct buffer *local_out;
__dead void __dead void
usage(void) usage(void)
{ {
fprintf(stderr, fprintf(stderr,
"usage: %s [-v] [-n name] [-s path]\n", __progname); "usage: %s [-v] [-n name] [-s path] command\n", __progname);
exit(1); exit(1);
} }
@ -87,13 +99,12 @@ sighandler(int sig)
int int
main(int argc, char **argv) main(int argc, char **argv)
{ {
int opt, srv_fd, loc_fd, mode, listf, n; int opt, mode, n;
char *path, name[MAXNAMELEN]; char *path, *error, name[MAXNAMELEN];
FILE *f; FILE *f;
struct buffer *srv_in, *srv_out, *loc_in, *loc_out; enum op op;
struct pollfd pfds[2]; struct pollfd pfds[2];
struct hdr hdr; struct hdr hdr;
struct identify_data id;
struct size_data sd; struct size_data sd;
struct winsize ws; struct winsize ws;
struct sigaction act; struct sigaction act;
@ -101,13 +112,9 @@ main(int argc, char **argv)
*name = '\0'; *name = '\0';
path = NULL; path = NULL;
listf = 0;
while ((opt = getopt(argc, argv, "ln:s:v?")) != EOF) { while ((opt = getopt(argc, argv, "n:s:v?")) != EOF) {
switch (opt) { switch (opt) {
case 'l':
listf = 1;
break;
case 'n': case 'n':
if (strlcpy(name, optarg, sizeof name) >= sizeof name) if (strlcpy(name, optarg, sizeof name) >= sizeof name)
errx(1, "name too long"); errx(1, "name too long");
@ -125,7 +132,17 @@ main(int argc, char **argv)
} }
argc -= optind; argc -= optind;
argv += optind; argv += optind;
if (argc != 0) 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(); usage();
/* Sort out socket path. */ /* Sort out socket path. */
@ -137,18 +154,33 @@ main(int argc, char **argv)
err(1, "realpath"); err(1, "realpath");
xfree(path); xfree(path);
/* Skip to list function if listing. */ /* Start server if necessary. */
if (listf) { if (stat(socket_path, &sb) != 0) {
if (*name == '\0') if (errno != ENOENT)
main_list(NULL); err(1, "%s", socket_path);
else else if (op != OP_LIST) {
main_list(name); if (server_start() != 0)
errx(1, "couldn't start server");
sleep(1);
}
} else {
if (!S_ISSOCK(sb.st_mode))
errx(1, "%s: not a socket", socket_path);
} }
/* And fill name. */ /* Connect to server. */
if (*name == '\0') if ((server_fd = connect_server()) == -1)
xsnprintf(name, sizeof name, "s-%lu", (u_long) getpid()); 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);
if (op == OP_LIST)
main_list(name);
/* Check stdin/stdout. */ /* Check stdin/stdout. */
if (!isatty(STDIN_FILENO)) if (!isatty(STDIN_FILENO))
errx(1, "stdin is not a tty"); errx(1, "stdin is not a tty");
@ -181,42 +213,21 @@ main(int argc, char **argv)
if (sigaction(SIGCHLD, &act, NULL) != 0) if (sigaction(SIGCHLD, &act, NULL) != 0)
err(1, "sigaction"); err(1, "sigaction");
/* Start server if necessary. */
if (stat(socket_path, &sb) != 0) {
if (errno != ENOENT)
err(1, "%s", socket_path);
else {
if (server_start() != 0)
errx(1, "couldn't start server");
sleep(1);
}
} else {
if (!S_ISSOCK(sb.st_mode))
errx(1, "%s: not a socket", socket_path);
}
/* Connect to server. */
if ((srv_fd = connect_server()) == -1)
errx(1, "couldn't find server");
if ((mode = fcntl(srv_fd, F_GETFL)) == -1)
err(1, "fcntl");
if (fcntl(srv_fd, F_SETFL, mode|O_NONBLOCK) == -1)
err(1, "fcntl");
srv_in = buffer_create(BUFSIZ);
srv_out = buffer_create(BUFSIZ);
/* Find window size. */ /* Find window size. */
if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1) if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1)
err(1, "ioctl(TIOCGWINSZ)"); err(1, "ioctl(TIOCGWINSZ)");
/* Send initial data. */ /* Send initial data. */
hdr.code = MSG_IDENTIFY; switch (op) {
hdr.size = sizeof id; case OP_NEW:
buffer_write(srv_out, &hdr, sizeof hdr); op_new(name, &ws);
strlcpy(id.name, name, sizeof id.name); break;
id.sx = ws.ws_col; case OP_ATTACH:
id.sy = ws.ws_row; op_attach(name, &ws);
buffer_write(srv_out, &id, hdr.size); break;
default:
fatalx("unknown op");
}
/* Start logging to file. */ /* Start logging to file. */
if (debug_level > 0) { if (debug_level > 0) {
@ -226,39 +237,36 @@ main(int argc, char **argv)
log_open(f, LOG_USER, debug_level); log_open(f, LOG_USER, debug_level);
xfree(path); xfree(path);
} }
/* Initialise terminal. */
loc_fd = local_init(&loc_in, &loc_out);
setproctitle("client (%s)", name); setproctitle("client (%s)", name);
/* Main loop. */ /* Main loop. */
n = 0; n = 0;
while (!sigterm) { while (!sigterm) {
/* Handle SIGWINCH if necessary. */ /* Handle SIGWINCH if necessary. */
if (sigwinch) { if (local_fd != -1 && sigwinch) {
if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1) if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1)
fatal("ioctl failed"); fatal("ioctl failed");
hdr.code = MSG_SIZE; hdr.type = MSG_SIZE;
hdr.size = sizeof sd; hdr.size = sizeof sd;
buffer_write(srv_out, &hdr, sizeof hdr); buffer_write(server_out, &hdr, sizeof hdr);
sd.sx = ws.ws_col; sd.sx = ws.ws_col;
sd.sy = ws.ws_row; sd.sy = ws.ws_row;
buffer_write(srv_out, &sd, hdr.size); buffer_write(server_out, &sd, hdr.size);
sigwinch = 0; sigwinch = 0;
} }
/* Set up pollfds. */ /* Set up pollfds. */
pfds[0].fd = srv_fd; pfds[0].fd = server_fd;
pfds[0].events = POLLIN; pfds[0].events = POLLIN;
if (BUFFER_USED(srv_out) > 0) if (BUFFER_USED(server_out) > 0)
pfds[0].events |= POLLOUT; pfds[0].events |= POLLOUT;
pfds[1].fd = loc_fd; pfds[1].fd = local_fd;
pfds[1].events = POLLIN; pfds[1].events = POLLIN;
if (BUFFER_USED(loc_out) > 0) if (local_fd != -1 && BUFFER_USED(local_out) > 0)
pfds[1].events |= POLLOUT; pfds[1].events |= POLLOUT;
/* Do the poll. */ /* Do the poll. */
if (poll(pfds, 2, INFTIM) == -1) { if (poll(pfds, 2, INFTIM) == -1) {
if (errno == EAGAIN || errno == EINTR) if (errno == EAGAIN || errno == EINTR)
@ -267,9 +275,10 @@ main(int argc, char **argv)
} }
/* Read/write from sockets. */ /* Read/write from sockets. */
if (buffer_poll(&pfds[0], srv_in, srv_out) != 0) if (buffer_poll(&pfds[0], server_in, server_out) != 0)
goto server_dead; goto server_dead;
if (buffer_poll(&pfds[1], loc_in, loc_out) != 0) if (local_fd != -1 &&
buffer_poll(&pfds[1], local_in, local_out) != 0)
fatalx("lost local socket"); fatalx("lost local socket");
/* Output flushed; pause if requested. */ /* Output flushed; pause if requested. */
@ -277,13 +286,17 @@ main(int argc, char **argv)
usleep(750000); usleep(750000);
/* Process any data. */ /* Process any data. */
if ((n = process_server(srv_in)) == -1) if ((n = process_server(&error)) == -1)
break; break;
if (process_local(loc_in, srv_out) == -1) if (process_local() == -1)
break; break;
} }
local_done(); if (local_fd != -1)
local_done();
if (error != NULL)
errx(1, "%s", error);
if (!sigterm) if (!sigterm)
printf("[detached]\n"); printf("[detached]\n");
@ -292,12 +305,47 @@ main(int argc, char **argv)
exit(0); exit(0);
server_dead: server_dead:
local_done(); if (local_fd != -1)
local_done();
printf("[lost server]\n"); printf("[lost server]\n");
exit(1); exit(1);
} }
/* New command. */
void
op_new(char *name, struct winsize *ws)
{
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. */ /* Connect to server socket from PID. */
int int
connect_server(void) connect_server(void)
@ -323,21 +371,30 @@ connect_server(void)
/* Handle data from server. */ /* Handle data from server. */
int int
process_server(struct buffer *srv_in) process_server(char **error)
{ {
struct hdr hdr; struct hdr hdr;
*error = NULL;
for (;;) { for (;;) {
if (BUFFER_USED(srv_in) < sizeof hdr) if (BUFFER_USED(server_in) < sizeof hdr)
break; break;
memcpy(&hdr, BUFFER_OUT(srv_in), sizeof hdr); memcpy(&hdr, BUFFER_OUT(server_in), sizeof hdr);
if (BUFFER_USED(srv_in) < (sizeof hdr) + hdr.size) if (BUFFER_USED(server_in) < (sizeof hdr) + hdr.size)
break; break;
buffer_remove(srv_in, sizeof hdr); buffer_remove(server_in, sizeof hdr);
switch (hdr.code) { 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: case MSG_OUTPUT:
local_output(srv_in, hdr.size); local_output(server_in, hdr.size);
break; break;
case MSG_PAUSE: case MSG_PAUSE:
if (hdr.size != 0) if (hdr.size != 0)
@ -345,6 +402,8 @@ process_server(struct buffer *srv_in)
return (1); return (1);
case MSG_EXIT: case MSG_EXIT:
return (-1); return (-1);
default:
fatalx("unexpected message");
} }
} }
@ -353,13 +412,16 @@ process_server(struct buffer *srv_in)
/* Handle data from local terminal. */ /* Handle data from local terminal. */
int int
process_local(struct buffer *loc_in, struct buffer *srv_out) process_local(void)
{ {
struct buffer *b; struct buffer *b;
struct hdr hdr; struct hdr hdr;
size_t size; size_t size;
int n, key; int n, key;
if (local_fd == -1)
return (0);
n = 0; n = 0;
b = buffer_create(BUFSIZ); b = buffer_create(BUFSIZ);
@ -368,10 +430,10 @@ process_local(struct buffer *loc_in, struct buffer *srv_out)
if (key == cmd_prefix) { if (key == cmd_prefix) {
if ((key = local_key(NULL)) == KEYC_NONE) { if ((key = local_key(NULL)) == KEYC_NONE) {
buffer_reverse_remove(loc_in, size); buffer_reverse_remove(local_in, size);
break; break;
} }
n = cmd_execute(key, srv_out); n = cmd_execute(key, server_out);
break; break;
} }
@ -385,10 +447,10 @@ process_local(struct buffer *loc_in, struct buffer *srv_out)
} }
log_debug("transmitting %zu bytes of input", BUFFER_USED(b)); log_debug("transmitting %zu bytes of input", BUFFER_USED(b));
hdr.code = MSG_INPUT; hdr.type = MSG_INPUT;
hdr.size = BUFFER_USED(b); hdr.size = BUFFER_USED(b);
buffer_write(srv_out, &hdr, sizeof hdr); buffer_write(server_out, &hdr, sizeof hdr);
buffer_write(srv_out, BUFFER_OUT(b), BUFFER_USED(b)); buffer_write(server_out, BUFFER_OUT(b), BUFFER_USED(b));
buffer_destroy(b); buffer_destroy(b);
return (n); return (n);
@ -400,41 +462,29 @@ main_list(char *name)
{ {
struct sessions_data sd; struct sessions_data sd;
struct windows_data wd; struct windows_data wd;
int srv_fd, mode;
struct buffer *srv_in, *srv_out;
struct pollfd pfd; struct pollfd pfd;
struct hdr hdr; struct hdr hdr;
/* Connect to server. */
if ((srv_fd = connect_server()) == -1)
errx(1, "couldn't find server");
if ((mode = fcntl(srv_fd, F_GETFL)) == -1)
err(1, "fcntl");
if (fcntl(srv_fd, F_SETFL, mode|O_NONBLOCK) == -1)
err(1, "fcntl");
srv_in = buffer_create(BUFSIZ);
srv_out = buffer_create(BUFSIZ);
/* Send query data. */ /* Send query data. */
if (name == NULL) { if (*name == '\0') {
hdr.code = MSG_SESSIONS; hdr.type = MSG_SESSIONS;
hdr.size = sizeof sd; hdr.size = sizeof sd;
buffer_write(srv_out, &hdr, sizeof hdr); buffer_write(server_out, &hdr, sizeof hdr);
buffer_write(srv_out, &sd, hdr.size); buffer_write(server_out, &sd, hdr.size);
} else { } else {
hdr.code = MSG_WINDOWS; hdr.type = MSG_WINDOWS;
hdr.size = sizeof wd; hdr.size = sizeof wd;
buffer_write(srv_out, &hdr, sizeof hdr); buffer_write(server_out, &hdr, sizeof hdr);
strlcpy(wd.name, name, sizeof wd.name); strlcpy(wd.name, name, sizeof wd.name);
buffer_write(srv_out, &wd, hdr.size); buffer_write(server_out, &wd, hdr.size);
} }
/* Main loop. */ /* Main loop. */
for (;;) { for (;;) {
/* Set up pollfd. */ /* Set up pollfd. */
pfd.fd = srv_fd; pfd.fd = server_fd;
pfd.events = POLLIN; pfd.events = POLLIN;
if (BUFFER_USED(srv_out) > 0) if (BUFFER_USED(server_out) > 0)
pfd.events |= POLLOUT; pfd.events |= POLLOUT;
/* Do the poll. */ /* Do the poll. */
@ -445,16 +495,16 @@ main_list(char *name)
} }
/* Read/write from sockets. */ /* Read/write from sockets. */
if (buffer_poll(&pfd, srv_in, srv_out) != 0) if (buffer_poll(&pfd, server_in, server_out) != 0)
errx(1, "lost server"); errx(1, "lost server");
/* Process data. */ /* Process data. */
process_list(srv_in, name); process_list(name);
} }
} }
void void
process_list(struct buffer *srv_in, const char *name) process_list(const char *name)
{ {
struct sessions_data sd; struct sessions_data sd;
struct sessions_entry se; struct sessions_entry se;
@ -464,25 +514,25 @@ process_list(struct buffer *srv_in, const char *name)
char *tim; char *tim;
for (;;) { for (;;) {
if (BUFFER_USED(srv_in) < sizeof hdr) if (BUFFER_USED(server_in) < sizeof hdr)
break; break;
memcpy(&hdr, BUFFER_OUT(srv_in), sizeof hdr); memcpy(&hdr, BUFFER_OUT(server_in), sizeof hdr);
if (BUFFER_USED(srv_in) < (sizeof hdr) + hdr.size) if (BUFFER_USED(server_in) < (sizeof hdr) + hdr.size)
break; break;
buffer_remove(srv_in, sizeof hdr); buffer_remove(server_in, sizeof hdr);
switch (hdr.code) { switch (hdr.type) {
case MSG_SESSIONS: case MSG_SESSIONS:
if (hdr.size < sizeof sd) if (hdr.size < sizeof sd)
errx(1, "bad MSG_SESSIONS size"); errx(1, "bad MSG_SESSIONS size");
buffer_read(srv_in, &sd, sizeof sd); buffer_read(server_in, &sd, sizeof sd);
hdr.size -= sizeof sd; hdr.size -= sizeof sd;
if (sd.sessions == 0 && hdr.size == 0) if (sd.sessions == 0 && hdr.size == 0)
exit(0); exit(0);
if (hdr.size < sd.sessions * sizeof se) if (hdr.size < sd.sessions * sizeof se)
errx(1, "bad MSG_SESSIONS size"); errx(1, "bad MSG_SESSIONS size");
while (sd.sessions-- > 0) { while (sd.sessions-- > 0) {
buffer_read(srv_in, &se, sizeof se); buffer_read(server_in, &se, sizeof se);
tim = ctime(&se.tim); tim = ctime(&se.tim);
*strchr(tim, '\n') = '\0'; *strchr(tim, '\n') = '\0';
printf("%s: %u windows (created %s)\n", printf("%s: %u windows (created %s)\n",
@ -492,14 +542,14 @@ process_list(struct buffer *srv_in, const char *name)
case MSG_WINDOWS: case MSG_WINDOWS:
if (hdr.size < sizeof wd) if (hdr.size < sizeof wd)
errx(1, "bad MSG_WINDOWS size"); errx(1, "bad MSG_WINDOWS size");
buffer_read(srv_in, &wd, sizeof wd); buffer_read(server_in, &wd, sizeof wd);
hdr.size -= sizeof wd; hdr.size -= sizeof wd;
if (wd.windows == 0 && hdr.size == 0) if (wd.windows == 0 && hdr.size == 0)
errx(1, "session \"%s\" not found", name); errx(1, "session \"%s\" not found", name);
if (hdr.size < wd.windows * sizeof we) if (hdr.size < wd.windows * sizeof we)
errx(1, "bad MSG_WINDOWS size"); errx(1, "bad MSG_WINDOWS size");
while (wd.windows-- > 0) { while (wd.windows-- > 0) {
buffer_read(srv_in, &we, sizeof we); buffer_read(server_in, &we, sizeof we);
if (*we.title != '\0') { if (*we.title != '\0') {
printf("%u: %s \"%s\" (%s)\n", printf("%u: %s \"%s\" (%s)\n",
we.idx, we.name, we.title, we.tty); we.idx, we.name, we.title, we.tty);
@ -509,6 +559,8 @@ process_list(struct buffer *srv_in, const char *name)
} }
} }
exit(0); exit(0);
default:
fatalx("unexpected message");
} }
} }
} }

122
tmux.h
View File

@ -1,4 +1,4 @@
/* $Id: tmux.h,v 1.4 2007-08-27 12:05:15 nicm Exp $ */ /* $Id: tmux.h,v 1.5 2007-08-27 13:45:26 nicm Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -226,68 +226,6 @@ struct buffer {
#define KEYC_UP -149 #define KEYC_UP -149
#define KEYC_MOUSE -150 #define KEYC_MOUSE -150
/* Escape codes. */
/*
AL=\E[%dL parm_insert_line
DC=\E[%dP parm_dch
DL=\E[%dM parm_delete_line
DO=\E[%dB parm_down_cursor
IC=\E[%d@ parm_ich
Km=\E[M key_mouse
LE=\E[%dD parm_left_cursor
RI=\E[%dC parm_right_cursor
UP=\E[%dA parm_up_cursor
ac=++,,--..00``aaffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~
acs_chars
ae=^O exit_alt_charset_mode
al=\E[L insert_line
as=^N enter_alt_charset_mode
bl=^G bell
bt=\E[Z back_tab
cb=\E[1K clear_bol
cd=\E[J clear_eos
ce=\E[K clear_eol
cl=\E[H\E[J clear_screen
cm=\E[%i%d;%dH cursor_address
cr=^M carriage_return
cs=\E[%i%d;%dr change_scroll_region
ct=\E[3g clear_all_tabs
dc=\E[P delete_character
dl=\E[M delete_line
do=^J cursor_down
eA=\E(B\E)0 ena_acs
ei=\E[4l exit_insert_mode
ho=\E[H cursor_home
im=\E[4h enter_insert_mode
is=\E)0 init_2string
le=^H cursor_left
mb=\E[5m enter_blink_mode
md=\E[1m enter_bold_mode
me=\E[m exit_attrbute_mode
mr=\E[7m enter_reverse_mode
nd=\E[C cursor_right
nw=\EE newline
rc=\E8 restore_cursor
rs=\Ec reset_string
sc=\E7 save_cursor
se=\E[23m exit_standout_mode
sf=^J scroll_forward
so=\E[3m enter_standout_mode
sr=\EM scroll_reverse
st=\EH set_tab
ta=^I tab
ue=\E[24m exit_underline_mode
up=\EM cursor_up
s=\E[4m
vb=\Eg flash_screen
ve=\E[34h\E[?25h
cursor_normal
vi=\E[?25l cursor_invisible
vs=\E[34l cursor_visible
E0=\E(B
S0=\E(%p1%c
*/
/* Translated escape codes. */ /* Translated escape codes. */
#define CODE_CURSORUP 0 #define CODE_CURSORUP 0
#define CODE_CURSORDOWN 1 #define CODE_CURSORDOWN 1
@ -317,25 +255,47 @@ struct buffer {
#define CODE_KKEYPADON 25 #define CODE_KKEYPADON 25
#define CODE_TITLE 26 #define CODE_TITLE 26
/* Command-line commands. */
enum op {
OP_LIST = 0,
OP_NEW,
OP_ATTACH
};
/* Message codes. */ /* Message codes. */
#define MSG_IDENTIFY 0 enum hdrtype {
#define MSG_CREATE 1 MSG_NEW = 0,
#define MSG_EXIT 2 MSG_ATTACH,
#define MSG_SIZE 3 MSG_READY,
#define MSG_NEXT 4 MSG_CREATE,
#define MSG_PREVIOUS 5 MSG_EXIT,
#define MSG_INPUT 6 /* input from client to server */ MSG_SIZE,
#define MSG_OUTPUT 7 /* output from server to client */ MSG_NEXT,
#define MSG_REFRESH 8 MSG_PREVIOUS,
#define MSG_SELECT 9 MSG_INPUT,
#define MSG_SESSIONS 10 MSG_OUTPUT,
#define MSG_WINDOWS 11 MSG_REFRESH,
#define MSG_PAUSE 12 MSG_SELECT,
#define MSG_RENAME 13 MSG_SESSIONS,
MSG_WINDOWS,
MSG_PAUSE,
MSG_RENAME
};
struct identify_data { /* Message header structure. */
struct hdr {
enum hdrtype type;
size_t size;
};
struct new_data {
char name[MAXNAMELEN]; char name[MAXNAMELEN];
u_int sx;
u_int sy;
};
struct attach_data {
char name[MAXNAMELEN];
u_int sx; u_int sx;
u_int sy; u_int sy;
}; };
@ -377,12 +337,6 @@ struct refresh_data {
u_int py_lower; u_int py_lower;
}; };
/* Message header structure. */
struct hdr {
u_int code;
size_t size;
};
/* Attributes. */ /* Attributes. */
#define ATTR_BRIGHT 0x1 #define ATTR_BRIGHT 0x1
#define ATTR_DIM 0x2 #define ATTR_DIM 0x2