mirror of
https://github.com/tmate-io/tmate.git
synced 2024-12-31 19:18:49 +01:00
Change command format.
This commit is contained in:
parent
6e210bb005
commit
04f4e4219b
29
NOTES
29
NOTES
@ -11,10 +11,31 @@ Commands: d detach
|
||||
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
|
||||
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
|
||||
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
|
||||
windows remain attached to them.
|
||||
sessions.
|
||||
|
||||
Syntax is: tmux [-v] [-n name] [-s path] command
|
||||
|
||||
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
|
||||
"-s <path>" but it shouldn't normally be required.
|
||||
|
14
command.c
14
command.c
@ -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>
|
||||
@ -83,7 +83,7 @@ cmd_fn_select(struct buffer *srv_out, int arg)
|
||||
struct hdr hdr;
|
||||
struct select_data data;
|
||||
|
||||
hdr.code = MSG_SELECT;
|
||||
hdr.type = MSG_SELECT;
|
||||
hdr.size = sizeof data;
|
||||
buffer_write(srv_out, &hdr, sizeof hdr);
|
||||
data.idx = arg;
|
||||
@ -98,7 +98,7 @@ cmd_fn_create(struct buffer *srv_out, unused int arg)
|
||||
{
|
||||
struct hdr hdr;
|
||||
|
||||
hdr.code = MSG_CREATE;
|
||||
hdr.type = MSG_CREATE;
|
||||
hdr.size = 0;
|
||||
buffer_write(srv_out, &hdr, sizeof hdr);
|
||||
|
||||
@ -118,7 +118,7 @@ cmd_fn_next(struct buffer *srv_out, unused int arg)
|
||||
{
|
||||
struct hdr hdr;
|
||||
|
||||
hdr.code = MSG_NEXT;
|
||||
hdr.type = MSG_NEXT;
|
||||
hdr.size = 0;
|
||||
buffer_write(srv_out, &hdr, sizeof hdr);
|
||||
|
||||
@ -131,7 +131,7 @@ cmd_fn_previous(struct buffer *srv_out, unused int arg)
|
||||
{
|
||||
struct hdr hdr;
|
||||
|
||||
hdr.code = MSG_PREVIOUS;
|
||||
hdr.type = MSG_PREVIOUS;
|
||||
hdr.size = 0;
|
||||
buffer_write(srv_out, &hdr, sizeof hdr);
|
||||
|
||||
@ -144,7 +144,7 @@ cmd_fn_refresh(struct buffer *srv_out, unused int arg)
|
||||
{
|
||||
struct hdr hdr;
|
||||
|
||||
hdr.code = MSG_REFRESH;
|
||||
hdr.type = MSG_REFRESH;
|
||||
hdr.size = 0;
|
||||
buffer_write(srv_out, &hdr, sizeof hdr);
|
||||
|
||||
@ -157,7 +157,7 @@ cmd_fn_rename(struct buffer *srv_out, unused int arg)
|
||||
{
|
||||
struct hdr hdr;
|
||||
|
||||
hdr.code = MSG_RENAME;
|
||||
hdr.type = MSG_RENAME;
|
||||
hdr.size = 0;
|
||||
buffer_write(srv_out, &hdr, sizeof hdr);
|
||||
|
||||
|
122
server.c
122
server.c
@ -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>
|
||||
@ -63,7 +63,8 @@ void lost_window(struct window *);
|
||||
void changed_window(struct client *);
|
||||
void draw_client(struct client *, u_int, u_int);
|
||||
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_next_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, ' ');
|
||||
|
||||
size = BUFFER_USED(c->out) - size;
|
||||
hdr.code = MSG_OUTPUT;
|
||||
hdr.type = MSG_OUTPUT;
|
||||
hdr.size = size;
|
||||
memcpy(BUFFER_IN(c->out) - size - sizeof hdr, &hdr, sizeof hdr);
|
||||
|
||||
hdr.code = MSG_PAUSE;
|
||||
hdr.type = MSG_PAUSE;
|
||||
hdr.size = 0;
|
||||
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);
|
||||
|
||||
size = BUFFER_USED(c->out) - size;
|
||||
hdr.code = MSG_OUTPUT;
|
||||
hdr.type = MSG_OUTPUT;
|
||||
hdr.size = size;
|
||||
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);
|
||||
|
||||
size = BUFFER_USED(c->out) - size;
|
||||
hdr.code = MSG_OUTPUT;
|
||||
hdr.type = MSG_OUTPUT;
|
||||
hdr.size = size;
|
||||
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;
|
||||
if (size != 0) {
|
||||
hdr.code = MSG_OUTPUT;
|
||||
hdr.type = MSG_OUTPUT;
|
||||
hdr.size = size;
|
||||
memcpy(BUFFER_IN(c->out) - size - sizeof hdr, &hdr, sizeof hdr);
|
||||
} else
|
||||
@ -602,7 +603,7 @@ write_client(struct client *c, u_int cmd, void *buf, size_t len)
|
||||
{
|
||||
struct hdr hdr;
|
||||
|
||||
hdr.code = cmd;
|
||||
hdr.type = cmd;
|
||||
hdr.size = len;
|
||||
|
||||
buffer_write(c->out, &hdr, sizeof hdr);
|
||||
@ -617,7 +618,7 @@ write_client2(struct client *c,
|
||||
{
|
||||
struct hdr hdr;
|
||||
|
||||
hdr.code = cmd;
|
||||
hdr.type = cmd;
|
||||
hdr.size = len1 + len2;
|
||||
|
||||
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;
|
||||
u_int i;
|
||||
|
||||
hdr.code = cmd;
|
||||
hdr.type = cmd;
|
||||
hdr.size = len;
|
||||
|
||||
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;
|
||||
log_debug("redrawing screen, %zu bytes", size);
|
||||
if (size != 0) {
|
||||
hdr.code = MSG_OUTPUT;
|
||||
hdr.type = MSG_OUTPUT;
|
||||
hdr.size = size;
|
||||
memcpy(
|
||||
BUFFER_IN(c->out) - size - sizeof hdr, &hdr, sizeof hdr);
|
||||
@ -735,9 +736,12 @@ process_client(struct client *c)
|
||||
return;
|
||||
buffer_remove(c->in, sizeof hdr);
|
||||
|
||||
switch (hdr.code) {
|
||||
case MSG_IDENTIFY:
|
||||
process_identify_msg(c, &hdr);
|
||||
switch (hdr.type) {
|
||||
case MSG_NEW:
|
||||
process_new_msg(c, &hdr);
|
||||
break;
|
||||
case MSG_ATTACH:
|
||||
process_attach_msg(c, &hdr);
|
||||
break;
|
||||
case MSG_CREATE:
|
||||
process_create_msg(c, &hdr);
|
||||
@ -769,19 +773,23 @@ process_client(struct client *c)
|
||||
case MSG_RENAME:
|
||||
process_rename_msg(c, &hdr);
|
||||
break;
|
||||
default:
|
||||
fatalx("unexpected message");
|
||||
}
|
||||
}
|
||||
|
||||
/* Identify message from client. */
|
||||
/* New message from client. */
|
||||
void
|
||||
process_identify_msg(struct client *c, struct hdr *hdr)
|
||||
process_new_msg(struct client *c, struct hdr *hdr)
|
||||
{
|
||||
struct identify_data data;
|
||||
const char *shell;
|
||||
char *cmd;
|
||||
struct new_data data;
|
||||
const char *shell;
|
||||
char *cmd, *msg;
|
||||
|
||||
if (c->session != NULL)
|
||||
return;
|
||||
if (hdr->size != sizeof data)
|
||||
fatalx("bad MSG_IDENTIFY size");
|
||||
fatalx("bad MSG_NEW size");
|
||||
buffer_read(c->in, &data, hdr->size);
|
||||
|
||||
c->sx = data.sx;
|
||||
@ -790,21 +798,57 @@ process_identify_msg(struct client *c, struct hdr *hdr)
|
||||
c->sy = data.sy;
|
||||
if (c->sy == 0)
|
||||
c->sy = 25;
|
||||
|
||||
/* Try and find session or create if not found. */
|
||||
c->session = session_find(data.name);
|
||||
if (c->session == NULL) {
|
||||
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);
|
||||
xfree(cmd);
|
||||
|
||||
if (*data.name != '\0' && session_find(data.name) != NULL) {
|
||||
xasprintf(&msg, "duplicate session: %s", data.name);
|
||||
write_client(c, MSG_READY, msg, strlen(msg));
|
||||
xfree(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
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)
|
||||
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);
|
||||
}
|
||||
|
||||
@ -816,7 +860,7 @@ process_create_msg(struct client *c, struct hdr *hdr)
|
||||
char *cmd;
|
||||
|
||||
if (c->session == NULL)
|
||||
fatalx("MSG_CREATE before identified");
|
||||
return;
|
||||
if (hdr->size != 0)
|
||||
fatalx("bad MSG_CREATE size");
|
||||
|
||||
@ -836,7 +880,7 @@ void
|
||||
process_next_msg(struct client *c, struct hdr *hdr)
|
||||
{
|
||||
if (c->session == NULL)
|
||||
fatalx("MSG_NEXT before identified");
|
||||
return;
|
||||
if (hdr->size != 0)
|
||||
fatalx("bad MSG_NEXT size");
|
||||
|
||||
@ -851,7 +895,7 @@ void
|
||||
process_previous_msg(struct client *c, struct hdr *hdr)
|
||||
{
|
||||
if (c->session == NULL)
|
||||
fatalx("MSG_PREVIOUS before identified");
|
||||
return;
|
||||
if (hdr->size != 0)
|
||||
fatalx("bad MSG_PREVIOUS size");
|
||||
|
||||
@ -868,7 +912,7 @@ process_size_msg(struct client *c, struct hdr *hdr)
|
||||
struct size_data data;
|
||||
|
||||
if (c->session == NULL)
|
||||
fatalx("MSG_SIZE before identified");
|
||||
return;
|
||||
if (hdr->size != sizeof data)
|
||||
fatalx("bad MSG_SIZE size");
|
||||
buffer_read(c->in, &data, hdr->size);
|
||||
@ -889,7 +933,7 @@ void
|
||||
process_input_msg(struct client *c, struct hdr *hdr)
|
||||
{
|
||||
if (c->session == NULL)
|
||||
fatalx("MSG_INPUT before identified");
|
||||
return;
|
||||
|
||||
if (c->prompt == NULL)
|
||||
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;
|
||||
|
||||
if (c->session == NULL)
|
||||
fatalx("MSG_REFRESH before identified");
|
||||
return;
|
||||
if (hdr->size != 0 && hdr->size != sizeof data)
|
||||
fatalx("bad MSG_REFRESH size");
|
||||
|
||||
@ -918,7 +962,7 @@ process_select_msg(struct client *c, struct hdr *hdr)
|
||||
struct select_data data;
|
||||
|
||||
if (c->session == NULL)
|
||||
fatalx("MSG_SELECT before identified");
|
||||
return;
|
||||
if (hdr->size != sizeof data)
|
||||
fatalx("bad MSG_SELECT size");
|
||||
buffer_read(c->in, &data, hdr->size);
|
||||
@ -1014,7 +1058,7 @@ void
|
||||
process_rename_msg(struct client *c, struct hdr *hdr)
|
||||
{
|
||||
if (c->session == NULL)
|
||||
fatalx("MSG_RENAME before identified");
|
||||
return;
|
||||
if (hdr->size != 0)
|
||||
fatalx("bad MSG_RENAME size");
|
||||
|
||||
|
20
session.c
20
session.c
@ -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>
|
||||
@ -50,8 +50,7 @@ session_create(const char *name, const char *cmd, u_int sx, u_int sy)
|
||||
u_int i;
|
||||
|
||||
s = xmalloc(sizeof *s);
|
||||
s->tim = time(NULL);
|
||||
strlcpy(s->name, name, sizeof s->name);
|
||||
s->tim = time(NULL);
|
||||
ARRAY_INIT(&s->windows);
|
||||
|
||||
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++) {
|
||||
s = ARRAY_ITEM(&sessions, i);
|
||||
if (s == NULL) {
|
||||
if (ARRAY_ITEM(&sessions, i) == NULL) {
|
||||
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);
|
||||
}
|
||||
|
||||
@ -128,7 +133,6 @@ session_detach(struct session *s, struct window *w)
|
||||
}
|
||||
|
||||
window_remove(&s->windows, w);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Flush session if it is empty. */
|
||||
|
292
tmux.c
292
tmux.c
@ -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>
|
||||
@ -40,13 +40,15 @@
|
||||
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(struct buffer *);
|
||||
int process_local(struct buffer *, struct buffer *);
|
||||
int process_server(char **);
|
||||
int process_local(void);
|
||||
void sighandler(int);
|
||||
__dead void usage(void);
|
||||
__dead void main_list(char *);
|
||||
void process_list(struct buffer *, const char *);
|
||||
void process_list(const char *);
|
||||
|
||||
/* SIGWINCH received flag. */
|
||||
volatile sig_atomic_t sigwinch;
|
||||
@ -60,11 +62,21 @@ int debug_level;
|
||||
/* Path to server socket. */
|
||||
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
|
||||
usage(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"usage: %s [-v] [-n name] [-s path]\n", __progname);
|
||||
"usage: %s [-v] [-n name] [-s path] command\n", __progname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@ -87,13 +99,12 @@ sighandler(int sig)
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int opt, srv_fd, loc_fd, mode, listf, n;
|
||||
char *path, name[MAXNAMELEN];
|
||||
int opt, mode, n;
|
||||
char *path, *error, name[MAXNAMELEN];
|
||||
FILE *f;
|
||||
struct buffer *srv_in, *srv_out, *loc_in, *loc_out;
|
||||
enum op op;
|
||||
struct pollfd pfds[2];
|
||||
struct hdr hdr;
|
||||
struct identify_data id;
|
||||
struct size_data sd;
|
||||
struct winsize ws;
|
||||
struct sigaction act;
|
||||
@ -101,13 +112,9 @@ main(int argc, char **argv)
|
||||
|
||||
*name = '\0';
|
||||
path = NULL;
|
||||
listf = 0;
|
||||
|
||||
while ((opt = getopt(argc, argv, "ln:s:v?")) != EOF) {
|
||||
while ((opt = getopt(argc, argv, "n:s:v?")) != EOF) {
|
||||
switch (opt) {
|
||||
case 'l':
|
||||
listf = 1;
|
||||
break;
|
||||
case 'n':
|
||||
if (strlcpy(name, optarg, sizeof name) >= sizeof name)
|
||||
errx(1, "name too long");
|
||||
@ -125,7 +132,17 @@ main(int argc, char **argv)
|
||||
}
|
||||
argc -= 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();
|
||||
|
||||
/* Sort out socket path. */
|
||||
@ -137,18 +154,33 @@ main(int argc, char **argv)
|
||||
err(1, "realpath");
|
||||
xfree(path);
|
||||
|
||||
/* Skip to list function if listing. */
|
||||
if (listf) {
|
||||
if (*name == '\0')
|
||||
main_list(NULL);
|
||||
else
|
||||
main_list(name);
|
||||
/* Start server if necessary. */
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
if (!S_ISSOCK(sb.st_mode))
|
||||
errx(1, "%s: not a socket", socket_path);
|
||||
}
|
||||
|
||||
/* And fill name. */
|
||||
if (*name == '\0')
|
||||
xsnprintf(name, sizeof name, "s-%lu", (u_long) getpid());
|
||||
|
||||
/* Connect to server. */
|
||||
if ((server_fd = connect_server()) == -1)
|
||||
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. */
|
||||
if (!isatty(STDIN_FILENO))
|
||||
errx(1, "stdin is not a tty");
|
||||
@ -181,42 +213,21 @@ main(int argc, char **argv)
|
||||
if (sigaction(SIGCHLD, &act, NULL) != 0)
|
||||
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. */
|
||||
if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1)
|
||||
err(1, "ioctl(TIOCGWINSZ)");
|
||||
|
||||
/* Send initial data. */
|
||||
hdr.code = MSG_IDENTIFY;
|
||||
hdr.size = sizeof id;
|
||||
buffer_write(srv_out, &hdr, sizeof hdr);
|
||||
strlcpy(id.name, name, sizeof id.name);
|
||||
id.sx = ws.ws_col;
|
||||
id.sy = ws.ws_row;
|
||||
buffer_write(srv_out, &id, hdr.size);
|
||||
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) {
|
||||
@ -226,39 +237,36 @@ main(int argc, char **argv)
|
||||
log_open(f, LOG_USER, debug_level);
|
||||
xfree(path);
|
||||
}
|
||||
|
||||
/* Initialise terminal. */
|
||||
loc_fd = local_init(&loc_in, &loc_out);
|
||||
setproctitle("client (%s)", name);
|
||||
|
||||
/* Main loop. */
|
||||
n = 0;
|
||||
while (!sigterm) {
|
||||
/* Handle SIGWINCH if necessary. */
|
||||
if (sigwinch) {
|
||||
if (local_fd != -1 && sigwinch) {
|
||||
if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1)
|
||||
fatal("ioctl failed");
|
||||
|
||||
hdr.code = MSG_SIZE;
|
||||
hdr.type = MSG_SIZE;
|
||||
hdr.size = sizeof sd;
|
||||
buffer_write(srv_out, &hdr, sizeof hdr);
|
||||
buffer_write(server_out, &hdr, sizeof hdr);
|
||||
sd.sx = ws.ws_col;
|
||||
sd.sy = ws.ws_row;
|
||||
buffer_write(srv_out, &sd, hdr.size);
|
||||
buffer_write(server_out, &sd, hdr.size);
|
||||
|
||||
sigwinch = 0;
|
||||
}
|
||||
|
||||
/* Set up pollfds. */
|
||||
pfds[0].fd = srv_fd;
|
||||
pfds[0].fd = server_fd;
|
||||
pfds[0].events = POLLIN;
|
||||
if (BUFFER_USED(srv_out) > 0)
|
||||
if (BUFFER_USED(server_out) > 0)
|
||||
pfds[0].events |= POLLOUT;
|
||||
pfds[1].fd = loc_fd;
|
||||
pfds[1].fd = local_fd;
|
||||
pfds[1].events = POLLIN;
|
||||
if (BUFFER_USED(loc_out) > 0)
|
||||
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)
|
||||
@ -267,9 +275,10 @@ main(int argc, char **argv)
|
||||
}
|
||||
|
||||
/* 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;
|
||||
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");
|
||||
|
||||
/* Output flushed; pause if requested. */
|
||||
@ -277,13 +286,17 @@ main(int argc, char **argv)
|
||||
usleep(750000);
|
||||
|
||||
/* Process any data. */
|
||||
if ((n = process_server(srv_in)) == -1)
|
||||
if ((n = process_server(&error)) == -1)
|
||||
break;
|
||||
if (process_local(loc_in, srv_out) == -1)
|
||||
if (process_local() == -1)
|
||||
break;
|
||||
}
|
||||
|
||||
local_done();
|
||||
if (local_fd != -1)
|
||||
local_done();
|
||||
|
||||
if (error != NULL)
|
||||
errx(1, "%s", error);
|
||||
|
||||
if (!sigterm)
|
||||
printf("[detached]\n");
|
||||
@ -292,12 +305,47 @@ main(int argc, char **argv)
|
||||
exit(0);
|
||||
|
||||
server_dead:
|
||||
local_done();
|
||||
if (local_fd != -1)
|
||||
local_done();
|
||||
|
||||
printf("[lost server]\n");
|
||||
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. */
|
||||
int
|
||||
connect_server(void)
|
||||
@ -323,21 +371,30 @@ connect_server(void)
|
||||
|
||||
/* Handle data from server. */
|
||||
int
|
||||
process_server(struct buffer *srv_in)
|
||||
process_server(char **error)
|
||||
{
|
||||
struct hdr hdr;
|
||||
|
||||
*error = NULL;
|
||||
for (;;) {
|
||||
if (BUFFER_USED(srv_in) < sizeof hdr)
|
||||
if (BUFFER_USED(server_in) < sizeof hdr)
|
||||
break;
|
||||
memcpy(&hdr, BUFFER_OUT(srv_in), sizeof hdr);
|
||||
if (BUFFER_USED(srv_in) < (sizeof hdr) + hdr.size)
|
||||
memcpy(&hdr, BUFFER_OUT(server_in), sizeof hdr);
|
||||
if (BUFFER_USED(server_in) < (sizeof hdr) + hdr.size)
|
||||
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:
|
||||
local_output(srv_in, hdr.size);
|
||||
local_output(server_in, hdr.size);
|
||||
break;
|
||||
case MSG_PAUSE:
|
||||
if (hdr.size != 0)
|
||||
@ -345,6 +402,8 @@ process_server(struct buffer *srv_in)
|
||||
return (1);
|
||||
case MSG_EXIT:
|
||||
return (-1);
|
||||
default:
|
||||
fatalx("unexpected message");
|
||||
}
|
||||
}
|
||||
|
||||
@ -353,13 +412,16 @@ process_server(struct buffer *srv_in)
|
||||
|
||||
/* Handle data from local terminal. */
|
||||
int
|
||||
process_local(struct buffer *loc_in, struct buffer *srv_out)
|
||||
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);
|
||||
|
||||
@ -368,10 +430,10 @@ process_local(struct buffer *loc_in, struct buffer *srv_out)
|
||||
|
||||
if (key == cmd_prefix) {
|
||||
if ((key = local_key(NULL)) == KEYC_NONE) {
|
||||
buffer_reverse_remove(loc_in, size);
|
||||
buffer_reverse_remove(local_in, size);
|
||||
break;
|
||||
}
|
||||
n = cmd_execute(key, srv_out);
|
||||
n = cmd_execute(key, server_out);
|
||||
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));
|
||||
|
||||
hdr.code = MSG_INPUT;
|
||||
hdr.type = MSG_INPUT;
|
||||
hdr.size = BUFFER_USED(b);
|
||||
buffer_write(srv_out, &hdr, sizeof hdr);
|
||||
buffer_write(srv_out, BUFFER_OUT(b), 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);
|
||||
@ -400,41 +462,29 @@ main_list(char *name)
|
||||
{
|
||||
struct sessions_data sd;
|
||||
struct windows_data wd;
|
||||
int srv_fd, mode;
|
||||
struct buffer *srv_in, *srv_out;
|
||||
struct pollfd pfd;
|
||||
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. */
|
||||
if (name == NULL) {
|
||||
hdr.code = MSG_SESSIONS;
|
||||
if (*name == '\0') {
|
||||
hdr.type = MSG_SESSIONS;
|
||||
hdr.size = sizeof sd;
|
||||
buffer_write(srv_out, &hdr, sizeof hdr);
|
||||
buffer_write(srv_out, &sd, hdr.size);
|
||||
buffer_write(server_out, &hdr, sizeof hdr);
|
||||
buffer_write(server_out, &sd, hdr.size);
|
||||
} else {
|
||||
hdr.code = MSG_WINDOWS;
|
||||
hdr.type = MSG_WINDOWS;
|
||||
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);
|
||||
buffer_write(srv_out, &wd, hdr.size);
|
||||
buffer_write(server_out, &wd, hdr.size);
|
||||
}
|
||||
|
||||
/* Main loop. */
|
||||
for (;;) {
|
||||
/* Set up pollfd. */
|
||||
pfd.fd = srv_fd;
|
||||
pfd.fd = server_fd;
|
||||
pfd.events = POLLIN;
|
||||
if (BUFFER_USED(srv_out) > 0)
|
||||
if (BUFFER_USED(server_out) > 0)
|
||||
pfd.events |= POLLOUT;
|
||||
|
||||
/* Do the poll. */
|
||||
@ -445,16 +495,16 @@ main_list(char *name)
|
||||
}
|
||||
|
||||
/* 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");
|
||||
|
||||
/* Process data. */
|
||||
process_list(srv_in, name);
|
||||
process_list(name);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
process_list(struct buffer *srv_in, const char *name)
|
||||
process_list(const char *name)
|
||||
{
|
||||
struct sessions_data sd;
|
||||
struct sessions_entry se;
|
||||
@ -464,25 +514,25 @@ process_list(struct buffer *srv_in, const char *name)
|
||||
char *tim;
|
||||
|
||||
for (;;) {
|
||||
if (BUFFER_USED(srv_in) < sizeof hdr)
|
||||
if (BUFFER_USED(server_in) < sizeof hdr)
|
||||
break;
|
||||
memcpy(&hdr, BUFFER_OUT(srv_in), sizeof hdr);
|
||||
if (BUFFER_USED(srv_in) < (sizeof hdr) + hdr.size)
|
||||
memcpy(&hdr, BUFFER_OUT(server_in), sizeof hdr);
|
||||
if (BUFFER_USED(server_in) < (sizeof hdr) + hdr.size)
|
||||
break;
|
||||
buffer_remove(srv_in, sizeof hdr);
|
||||
buffer_remove(server_in, sizeof hdr);
|
||||
|
||||
switch (hdr.code) {
|
||||
switch (hdr.type) {
|
||||
case MSG_SESSIONS:
|
||||
if (hdr.size < sizeof sd)
|
||||
errx(1, "bad MSG_SESSIONS size");
|
||||
buffer_read(srv_in, &sd, sizeof sd);
|
||||
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(srv_in, &se, sizeof se);
|
||||
buffer_read(server_in, &se, sizeof se);
|
||||
tim = ctime(&se.tim);
|
||||
*strchr(tim, '\n') = '\0';
|
||||
printf("%s: %u windows (created %s)\n",
|
||||
@ -492,14 +542,14 @@ process_list(struct buffer *srv_in, const char *name)
|
||||
case MSG_WINDOWS:
|
||||
if (hdr.size < sizeof wd)
|
||||
errx(1, "bad MSG_WINDOWS size");
|
||||
buffer_read(srv_in, &wd, sizeof wd);
|
||||
buffer_read(server_in, &wd, sizeof wd);
|
||||
hdr.size -= sizeof wd;
|
||||
if (wd.windows == 0 && hdr.size == 0)
|
||||
errx(1, "session \"%s\" not found", name);
|
||||
if (hdr.size < wd.windows * sizeof we)
|
||||
errx(1, "bad MSG_WINDOWS size");
|
||||
while (wd.windows-- > 0) {
|
||||
buffer_read(srv_in, &we, sizeof we);
|
||||
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);
|
||||
@ -509,6 +559,8 @@ process_list(struct buffer *srv_in, const char *name)
|
||||
}
|
||||
}
|
||||
exit(0);
|
||||
default:
|
||||
fatalx("unexpected message");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
122
tmux.h
122
tmux.h
@ -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>
|
||||
@ -226,68 +226,6 @@ struct buffer {
|
||||
#define KEYC_UP -149
|
||||
#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. */
|
||||
#define CODE_CURSORUP 0
|
||||
#define CODE_CURSORDOWN 1
|
||||
@ -317,25 +255,47 @@ struct buffer {
|
||||
#define CODE_KKEYPADON 25
|
||||
#define CODE_TITLE 26
|
||||
|
||||
/* Command-line commands. */
|
||||
enum op {
|
||||
OP_LIST = 0,
|
||||
OP_NEW,
|
||||
OP_ATTACH
|
||||
};
|
||||
|
||||
/* Message codes. */
|
||||
#define MSG_IDENTIFY 0
|
||||
#define MSG_CREATE 1
|
||||
#define MSG_EXIT 2
|
||||
#define MSG_SIZE 3
|
||||
#define MSG_NEXT 4
|
||||
#define MSG_PREVIOUS 5
|
||||
#define MSG_INPUT 6 /* input from client to server */
|
||||
#define MSG_OUTPUT 7 /* output from server to client */
|
||||
#define MSG_REFRESH 8
|
||||
#define MSG_SELECT 9
|
||||
#define MSG_SESSIONS 10
|
||||
#define MSG_WINDOWS 11
|
||||
#define MSG_PAUSE 12
|
||||
#define MSG_RENAME 13
|
||||
enum hdrtype {
|
||||
MSG_NEW = 0,
|
||||
MSG_ATTACH,
|
||||
MSG_READY,
|
||||
MSG_CREATE,
|
||||
MSG_EXIT,
|
||||
MSG_SIZE,
|
||||
MSG_NEXT,
|
||||
MSG_PREVIOUS,
|
||||
MSG_INPUT,
|
||||
MSG_OUTPUT,
|
||||
MSG_REFRESH,
|
||||
MSG_SELECT,
|
||||
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];
|
||||
u_int sx;
|
||||
u_int sy;
|
||||
};
|
||||
|
||||
struct attach_data {
|
||||
char name[MAXNAMELEN];
|
||||
u_int sx;
|
||||
u_int sy;
|
||||
};
|
||||
@ -377,12 +337,6 @@ struct refresh_data {
|
||||
u_int py_lower;
|
||||
};
|
||||
|
||||
/* Message header structure. */
|
||||
struct hdr {
|
||||
u_int code;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
/* Attributes. */
|
||||
#define ATTR_BRIGHT 0x1
|
||||
#define ATTR_DIM 0x2
|
||||
|
Loading…
Reference in New Issue
Block a user