diff --git a/cmd-queue.c b/cmd-queue.c index fad9760b..f08a724e 100644 --- a/cmd-queue.c +++ b/cmd-queue.c @@ -201,12 +201,13 @@ cmdq_continue_one(struct cmd_q *cmdq) char *tmp; int flags = !!(cmd->flags & CMD_CONTROL); - tmp = cmd_print(cmd); - log_debug("cmdq %p: %s", cmdq, tmp); #ifdef TMATE if (tmate_should_replicate_cmd(cmd->entry)) - tmate_exec_cmd(tmp); + tmate_exec_cmd(cmd); #endif + + tmp = cmd_print(cmd); + log_debug("cmdq %p: %s", cmdq, tmp); free(tmp); cmdq->time = time(NULL); diff --git a/server.c b/server.c index 7313b711..81334f1e 100644 --- a/server.c +++ b/server.c @@ -135,13 +135,13 @@ server_create_socket(void) static void tmate_set_editor_mode(void) { switch (options_get_number(global_s_options, "status-keys")) { - case MODEKEY_EMACS: tmate_exec_cmd("set-option -g status-keys emacs"); break; - case MODEKEY_VI: tmate_exec_cmd("set-option -g status-keys vi"); break; + case MODEKEY_EMACS: tmate_exec_cmd_args(4, (const char *[]){"set-option", "-g", "status-keys", "emacs"}); break; + case MODEKEY_VI: tmate_exec_cmd_args(4, (const char *[]){"set-option", "-g", "status-keys", "vi"}); break; } switch (options_get_number(global_w_options, "mode-keys")) { - case MODEKEY_EMACS: tmate_exec_cmd("set-window-option -g mode-keys emacs"); break; - case MODEKEY_VI: tmate_exec_cmd("set-window-option -g mode-keys vi"); break; + case MODEKEY_EMACS: tmate_exec_cmd_args(4, (const char *[]){"set-window-option", "-g", "status-keys", "emacs"}); break; + case MODEKEY_VI: tmate_exec_cmd_args(4, (const char *[]){"set-window-option", "-g", "status-keys", "vi"}); break; } } #endif diff --git a/tmate-decoder.c b/tmate-decoder.c index 9669c4c0..3b1e31af 100644 --- a/tmate-decoder.c +++ b/tmate-decoder.c @@ -78,8 +78,8 @@ static void handle_resize(struct tmate_session *session, extern char **cfg_causes; extern u_int cfg_ncauses; -static void handle_exec_cmd(__unused struct tmate_session *session, - struct tmate_unpacker *uk) +static void handle_exec_cmd_str(__unused struct tmate_session *session, + struct tmate_unpacker *uk) { struct cmd_q *cmd_q; struct cmd_list *cmdlist; @@ -114,6 +114,55 @@ out: free(cmd_str); } +static void handle_exec_cmd(__unused struct tmate_session *session, + struct tmate_unpacker *uk) +{ + struct cmd_q *cmd_q; + struct cmd_list *cmdlist; + struct cmd *cmd; + char *cause; + u_int i; + unsigned int argc; + char **argv; + + int client_id = unpack_int(uk); + + argc = uk->argc; + argv = xmalloc(sizeof(char *) * argc); + for (i = 0; i < argc; i++) + argv[i] = unpack_string(uk); + + cmd = cmd_parse(argc, argv, NULL, 0, &cause); + if (!cmd) { + tmate_failed_cmd(client_id, cause); + free(cause); + goto out; + } + + cmdlist = xcalloc(1, sizeof *cmdlist); + cmdlist->references = 1; + TAILQ_INIT(&cmdlist->list); + TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry); + + cmd_q = cmdq_new(NULL); + cmdq_run(cmd_q, cmdlist, NULL); + cmd_list_free(cmdlist); + cmdq_free(cmd_q); + + /* error messages land in cfg_causes */ + for (i = 0; i < cfg_ncauses; i++) { + tmate_failed_cmd(client_id, cfg_causes[i]); + free(cfg_causes[i]); + } + + free(cfg_causes); + cfg_causes = NULL; + cfg_ncauses = 0; + +out: + cmd_free_argv(argc, argv); +} + static void maybe_save_reconnection_data(struct tmate_session *session, const char *name, const char *value) { @@ -152,10 +201,11 @@ void tmate_dispatch_slave_message(struct tmate_session *session, dispatch(TMATE_IN_NOTIFY, handle_notify); dispatch(TMATE_IN_LEGACY_PANE_KEY, handle_legacy_pane_key); dispatch(TMATE_IN_RESIZE, handle_resize); - dispatch(TMATE_IN_EXEC_CMD, handle_exec_cmd); + dispatch(TMATE_IN_EXEC_CMD_STR, handle_exec_cmd_str); dispatch(TMATE_IN_SET_ENV, handle_set_env); dispatch(TMATE_IN_READY, handle_ready); dispatch(TMATE_IN_PANE_KEY, handle_pane_key); + dispatch(TMATE_IN_EXEC_CMD, handle_exec_cmd); default: tmate_info("Bad message type: %d", cmd); } } diff --git a/tmate-encoder.c b/tmate-encoder.c index 1a6c7b19..d4be7c6e 100644 --- a/tmate-encoder.c +++ b/tmate-encoder.c @@ -152,44 +152,99 @@ int tmate_should_replicate_cmd(const struct cmd_entry *cmd) #define sc (&session->saved_tmux_cmds) #define SAVED_TMUX_CMD_INITIAL_SIZE 256 -static void __tmate_exec_cmd(const char *cmd); +static void __tmate_exec_cmd_args(int argc, const char **argv); static void append_saved_cmd(struct tmate_session *session, - const char *cmd) + int argc, const char **argv) { if (!sc->cmds) { sc->capacity = SAVED_TMUX_CMD_INITIAL_SIZE; - sc->cmds = xmalloc(sizeof(char *) * sc->capacity); + sc->cmds = xmalloc(sizeof(*sc->cmds) * sc->capacity); sc->tail = 0; } if (sc->tail == sc->capacity) { sc->capacity *= 2; - sc->cmds = xrealloc(sc->cmds, sizeof(char *) * sc->capacity); + sc->cmds = xrealloc(sc->cmds, sizeof(*sc->cmds) * sc->capacity); } - sc->cmds[sc->tail++] = xstrdup(cmd); + sc->cmds[sc->tail].argc = argc; + sc->cmds[sc->tail].argv = cmd_copy_argv(argc, (char **)argv); + + sc->tail++; } static void replay_saved_cmd(struct tmate_session *session) { unsigned int i; for (i = 0; i < sc->tail; i++) - __tmate_exec_cmd(sc->cmds[i]); + __tmate_exec_cmd_args(sc->cmds[i].argc, (const char **)sc->cmds[i].argv); } #undef sc -static void __tmate_exec_cmd(const char *cmd) +struct args_entry { + u_char flag; + char *value; + RB_ENTRY(args_entry) entry; +}; + +static void extract_cmd(struct cmd *cmd, int *_argc, char ***_argv) { - pack(array, 2); - pack(int, TMATE_OUT_EXEC_CMD); - pack(string, cmd); + struct args_entry *entry; + struct args* args = cmd->args; + int argc = 0; + char **argv; + int next = 0, i; + + argc++; /* cmd name */ + RB_FOREACH(entry, args_tree, &args->tree) { + argc++; + if (entry->value != NULL) + argc++; + } + argc += args->argc; + argv = xmalloc(sizeof(char *) * argc); + + argv[next++] = xstrdup(cmd->entry->name); + + RB_FOREACH(entry, args_tree, &args->tree) { + xasprintf(&argv[next++], "-%c", entry->flag); + if (entry->value != NULL) + argv[next++] = xstrdup(entry->value); + } + + for (i = 0; i < args->argc; i++) + argv[next++] = xstrdup(args->argv[i]); + + *_argc = argc; + *_argv = argv; } -void tmate_exec_cmd(const char *cmd) +static void __tmate_exec_cmd_args(int argc, const char **argv) { - __tmate_exec_cmd(cmd); - append_saved_cmd(&tmate_session, cmd); + int i; + + pack(array, argc + 1); + pack(int, TMATE_OUT_EXEC_CMD); + + for (i = 0; i < argc; i++) + pack(string, argv[i]); +} + +void tmate_exec_cmd_args(int argc, const char **argv) +{ + __tmate_exec_cmd_args(argc, argv); + append_saved_cmd(&tmate_session, argc, argv); +} + +void tmate_exec_cmd(struct cmd *cmd) +{ + int argc; + char **argv; + + extract_cmd(cmd, &argc, &argv); + tmate_exec_cmd_args(argc, (const char **)argv); + cmd_free_argv(argc, argv); } void tmate_failed_cmd(int client_id, const char *cause) diff --git a/tmate-protocol.h b/tmate-protocol.h index 93c65ba3..ebae07a9 100644 --- a/tmate-protocol.h +++ b/tmate-protocol.h @@ -45,7 +45,7 @@ enum tmate_daemon_out_msg_types { TMATE_OUT_HEADER, TMATE_OUT_SYNC_LAYOUT, TMATE_OUT_PTY_DATA, - TMATE_OUT_EXEC_CMD, + TMATE_OUT_EXEC_CMD_STR, TMATE_OUT_FAILED_CMD, TMATE_OUT_STATUS, TMATE_OUT_SYNC_COPY_MODE, @@ -54,6 +54,7 @@ enum tmate_daemon_out_msg_types { TMATE_OUT_READY, TMATE_OUT_RECONNECT, TMATE_OUT_SNAPSHOT, + TMATE_OUT_EXEC_CMD, }; /* @@ -62,7 +63,7 @@ enum tmate_daemon_out_msg_types { [[int: pane_id, int: sx, int: sy, int: xoff, int: yoff], ...], int: active_pane_id], ...], int: active_win_id] [TMATE_OUT_PTY_DATA, int: pane_id, binary: buffer] -[TMATE_OUT_EXEC_CMD, string: cmd] +[TMATE_OUT_EXEC_CMD_STR, string: cmd] [TMATE_OUT_FAILED_CMD, int: client_id, string: cause] [TMATE_OUT_STATUS, string: left, string: right] [TMATE_OUT_SYNC_COPY_MODE, int: pane_id, [int: backing, int: oy, int: cx, int: cy, @@ -72,26 +73,31 @@ enum tmate_daemon_out_msg_types { [TMATE_OUT_WRITE_COPY_MODE, int: pane_id, string: str] [TMATE_OUT_FIN] [TMATE_OUT_READY] +[TMATE_OUT_RECONNECT, string: reconnection_data] +[TMATE_OUT_SNAPSHOT, ...] +[TMATE_OUT_EXEC_CMD, string: cmd_name, ...string: args] */ enum tmate_daemon_in_msg_types { TMATE_IN_NOTIFY, TMATE_IN_LEGACY_PANE_KEY, TMATE_IN_RESIZE, - TMATE_IN_EXEC_CMD, + TMATE_IN_EXEC_CMD_STR, TMATE_IN_SET_ENV, TMATE_IN_READY, TMATE_IN_PANE_KEY, + TMATE_IN_EXEC_CMD, }; /* [TMATE_IN_NOTIFY, string: msg] [TMATE_IN_PANE_KEY, int: key] [TMATE_IN_RESIZE, int: sx, int: sy] // sx == -1: no clients -[TMATE_IN_EXEC_CMD, int: client_id, string: cmd] +[TMATE_IN_EXEC_CMD_STR, int: client_id, string: cmd] [TMATE_IN_SET_ENV, string: name, string: value] [TMATE_IN_READY] [TMATE_IN_PANE_KEY, int: pane_id, uint64 keycode] // pane_id == -1: active pane +[TMATE_IN_EXEC_CMD, int: client_id, ...string: args] */ #endif diff --git a/tmate.h b/tmate.h index e6d3ef09..fb764c54 100644 --- a/tmate.h +++ b/tmate.h @@ -84,7 +84,8 @@ extern void tmate_write_ready(void); extern void tmate_sync_layout(void); extern void tmate_pty_data(struct window_pane *wp, const char *buf, size_t len); extern int tmate_should_replicate_cmd(const struct cmd_entry *cmd); -extern void tmate_exec_cmd(const char *cmd); +extern void tmate_exec_cmd_args(int argc, const char **argv); +extern void tmate_exec_cmd(struct cmd *cmd); extern void tmate_failed_cmd(int client_id, const char *cause); extern void tmate_status(const char *left, const char *right); extern void tmate_sync_copy_mode(struct window_pane *wp); @@ -184,7 +185,10 @@ struct tmate_session { struct { unsigned int capacity; unsigned int tail; - char **cmds; + struct { + int argc; + char **argv; + } *cmds; } saved_tmux_cmds; };