diff --git a/client.c b/client.c index b9e3b30a..e7fa4b71 100644 --- a/client.c +++ b/client.c @@ -48,13 +48,14 @@ enum { } client_exitreason = CLIENT_EXIT_NONE; int client_exitval; enum msgtype client_exittype; +const char *client_exitsession; int client_attached; int client_get_lock(char *); int client_connect(char *, int); void client_send_identify(int); -void client_send_environ(void); -void client_write_server(enum msgtype, void *, size_t); +int client_write_one(enum msgtype, int, const void *, size_t); +int client_write_server(enum msgtype, const void *, size_t); void client_update_event(void); void client_signal(int, short, void *); void client_stdin_callback(int, short, void *); @@ -138,12 +139,24 @@ failed: const char * client_exit_message(void) { + static char msg[256]; + switch (client_exitreason) { case CLIENT_EXIT_NONE: break; case CLIENT_EXIT_DETACHED: + if (client_exitsession != NULL) { + xsnprintf(msg, sizeof msg, "detached " + "(from session %s)", client_exitsession); + return (msg); + } return ("detached"); case CLIENT_EXIT_DETACHED_HUP: + if (client_exitsession != NULL) { + xsnprintf(msg, sizeof msg, "detached and SIGHUP " + "(from session %s)", client_exitsession); + return (msg); + } return ("detached and SIGHUP"); case CLIENT_EXIT_LOST_TTY: return ("lost tty"); @@ -165,12 +178,13 @@ client_main(int argc, char **argv, int flags) { struct cmd *cmd; struct cmd_list *cmdlist; - struct msg_command_data cmddata; - int cmdflags, fd; + struct msg_command_data *data; + int cmdflags, fd, i; pid_t ppid; enum msgtype msg; char *cause; struct termios tio, saved_tio; + size_t size; /* Set up the initial command. */ cmdflags = 0; @@ -179,7 +193,7 @@ client_main(int argc, char **argv, int flags) cmdflags = CMD_STARTSERVER; } else if (argc == 0) { msg = MSG_COMMAND; - cmdflags = CMD_STARTSERVER|CMD_SENDENVIRON|CMD_CANTNEST; + cmdflags = CMD_STARTSERVER|CMD_CANTNEST; } else { msg = MSG_COMMAND; @@ -197,8 +211,6 @@ client_main(int argc, char **argv, int flags) TAILQ_FOREACH(cmd, &cmdlist->list, qentry) { if (cmd->entry->flags & CMD_STARTSERVER) cmdflags |= CMD_STARTSERVER; - if (cmd->entry->flags & CMD_SENDENVIRON) - cmdflags |= CMD_SENDENVIRON; if (cmd->entry->flags & CMD_CANTNEST) cmdflags |= CMD_CANTNEST; } @@ -238,7 +250,7 @@ client_main(int argc, char **argv, int flags) setblocking(STDIN_FILENO, 0); event_set(&client_stdin, STDIN_FILENO, EV_READ|EV_PERSIST, client_stdin_callback, NULL); - if (flags & IDENTIFY_TERMIOS) { + if (flags & CLIENT_CONTROLCONTROL) { if (tcgetattr(STDIN_FILENO, &saved_tio) != 0) { fprintf(stderr, "tcgetattr failed: %s\n", strerror(errno)); @@ -261,26 +273,33 @@ client_main(int argc, char **argv, int flags) /* Establish signal handlers. */ set_signals(client_signal); - /* Send initial environment. */ - if (cmdflags & CMD_SENDENVIRON) - client_send_environ(); + /* Send identify messages. */ client_send_identify(flags); /* Send first command. */ if (msg == MSG_COMMAND) { - /* Fill in command line arguments. */ - cmddata.pid = environ_pid; - cmddata.session_id = environ_session_id; + /* How big is the command? */ + size = 0; + for (i = 0; i < argc; i++) + size += strlen(argv[i]) + 1; + data = xmalloc((sizeof *data) + size); /* Prepare command for server. */ - cmddata.argc = argc; - if (cmd_pack_argv( - argc, argv, cmddata.argv, sizeof cmddata.argv) != 0) { + data->argc = argc; + if (cmd_pack_argv(argc, argv, (char*)(data + 1), size) != 0) { fprintf(stderr, "command too long\n"); + free(data); return (1); } + size += sizeof *data; - client_write_server(msg, &cmddata, sizeof cmddata); + /* Send the command. */ + if (client_write_server(msg, data, size) != 0) { + fprintf(stderr, "failed to send command\n"); + free(data); + return (1); + } + free(data); } else if (msg == MSG_SHELL) client_write_server(msg, NULL, 0); @@ -296,37 +315,39 @@ client_main(int argc, char **argv, int flags) ppid = getppid(); if (client_exittype == MSG_DETACHKILL && ppid > 1) kill(ppid, SIGHUP); - } else if (flags & IDENTIFY_TERMIOS) { - if (flags & IDENTIFY_CONTROL) { - if (client_exitreason != CLIENT_EXIT_NONE) - printf("%%exit %s\n", client_exit_message()); - else - printf("%%exit\n"); - printf("\033\\"); - } + } else if (flags & CLIENT_CONTROLCONTROL) { + if (client_exitreason != CLIENT_EXIT_NONE) + printf("%%exit %s\n", client_exit_message()); + else + printf("%%exit\n"); + printf("\033\\"); tcsetattr(STDOUT_FILENO, TCSAFLUSH, &saved_tio); } setblocking(STDIN_FILENO, 1); return (client_exitval); } -/* Send identify message to server with the file descriptors. */ +/* Send identify messages to server. */ void client_send_identify(int flags) { - struct msg_identify_data data; - char *term; - int fd; + const char *s; + char **ss; + int fd; - data.flags = flags; + client_write_one(MSG_IDENTIFY_FLAGS, -1, &flags, sizeof flags); - if (getcwd(data.cwd, sizeof data.cwd) == NULL) - *data.cwd = '\0'; + if ((s = getenv("TERM")) == NULL) + s = ""; + client_write_one(MSG_IDENTIFY_TERM, -1, s, strlen(s) + 1); - term = getenv("TERM"); - if (term == NULL || - strlcpy(data.term, term, sizeof data.term) >= sizeof data.term) - *data.term = '\0'; + if ((s = ttyname(STDIN_FILENO)) == NULL) + s = ""; + client_write_one(MSG_IDENTIFY_TTYNAME, -1, s, strlen(s) + 1); + + if ((fd = open(".", O_RDONLY)) == -1) + fd = open("/", O_RDONLY); + client_write_one(MSG_IDENTIFY_CWD, fd, NULL, 0); #ifdef __CYGWIN__ snprintf(&data.ttyname, sizeof data.ttyname, "%s", @@ -334,32 +355,39 @@ client_send_identify(int flags) #else if ((fd = dup(STDIN_FILENO)) == -1) fatal("dup failed"); -#endif - imsg_compose(&client_ibuf, - MSG_IDENTIFY, PROTOCOL_VERSION, -1, fd, &data, sizeof data); + client_write_one(MSG_IDENTIFY_STDIN, fd, NULL, 0); + + for (ss = environ; *ss != NULL; ss++) + client_write_one(MSG_IDENTIFY_ENVIRON, -1, *ss, strlen(*ss) + 1); + + client_write_one(MSG_IDENTIFY_DONE, -1, NULL, 0); + client_update_event(); } -/* Forward entire environment to server. */ -void -client_send_environ(void) +/* Helper to send one message. */ +int +client_write_one(enum msgtype type, int fd, const void *buf, size_t len) { - struct msg_environ_data data; - char **var; + int retval; - for (var = environ; *var != NULL; var++) { - if (strlcpy(data.var, *var, sizeof data.var) >= sizeof data.var) - continue; - client_write_server(MSG_ENVIRON, &data, sizeof data); - } + retval = imsg_compose(&client_ibuf, type, PROTOCOL_VERSION, -1, fd, + (void*)buf, len); + if (retval != 1) + return (-1); + return (0); } /* Write a message to the server without a file descriptor. */ -void -client_write_server(enum msgtype type, void *buf, size_t len) +int +client_write_server(enum msgtype type, const void *buf, size_t len) { - imsg_compose(&client_ibuf, type, PROTOCOL_VERSION, -1, -1, buf, len); - client_update_event(); + int retval; + + retval = client_write_one(type, -1, buf, len); + if (retval == 0) + client_update_event(); + return (retval); } /* Update client event based on whether it needs to read or read and write. */ @@ -493,33 +521,33 @@ client_write(int fd, const char *data, size_t size) /* Dispatch imsgs when in wait state (before MSG_READY). */ int -client_dispatch_wait(void *data) +client_dispatch_wait(void *data0) { - struct imsg imsg; - ssize_t n, datalen; - struct msg_shell_data shelldata; - struct msg_exit_data exitdata; - struct msg_stdout_data stdoutdata; - struct msg_stderr_data stderrdata; - const char *shellcmd = data; + struct imsg imsg; + char *data; + ssize_t n, datalen; + struct msg_stdout_data stdoutdata; + struct msg_stderr_data stderrdata; + int retval; for (;;) { if ((n = imsg_get(&client_ibuf, &imsg)) == -1) fatalx("imsg_get failed"); if (n == 0) return (0); + + data = imsg.data; datalen = imsg.hdr.len - IMSG_HEADER_SIZE; log_debug("got %d from server", imsg.hdr.type); switch (imsg.hdr.type) { case MSG_EXIT: case MSG_SHUTDOWN: - if (datalen != sizeof exitdata) { - if (datalen != 0) - fatalx("bad MSG_EXIT size"); - } else { - memcpy(&exitdata, imsg.data, sizeof exitdata); - client_exitval = exitdata.retcode; + if (datalen != sizeof retval && datalen != 0) + fatalx("bad MSG_EXIT size"); + if (datalen == sizeof retval) { + memcpy(&retval, data, sizeof retval); + client_exitval = retval; } imsg_free(&imsg); return (-1); @@ -539,17 +567,19 @@ client_dispatch_wait(void *data) break; case MSG_STDOUT: if (datalen != sizeof stdoutdata) - fatalx("bad MSG_STDOUT"); - memcpy(&stdoutdata, imsg.data, sizeof stdoutdata); + fatalx("bad MSG_STDOUT size"); + memcpy(&stdoutdata, data, sizeof stdoutdata); - client_write(STDOUT_FILENO, stdoutdata.data, stdoutdata.size); + client_write(STDOUT_FILENO, stdoutdata.data, + stdoutdata.size); break; case MSG_STDERR: if (datalen != sizeof stderrdata) - fatalx("bad MSG_STDERR"); - memcpy(&stderrdata, imsg.data, sizeof stderrdata); + fatalx("bad MSG_STDERR size"); + memcpy(&stderrdata, data, sizeof stderrdata); - client_write(STDERR_FILENO, stderrdata.data, stderrdata.size); + client_write(STDERR_FILENO, stderrdata.data, + stderrdata.size); break; case MSG_VERSION: if (datalen != 0) @@ -563,23 +593,19 @@ client_dispatch_wait(void *data) imsg_free(&imsg); return (-1); case MSG_SHELL: - if (datalen != sizeof shelldata) - fatalx("bad MSG_SHELL size"); - memcpy(&shelldata, imsg.data, sizeof shelldata); - shelldata.shell[(sizeof shelldata.shell) - 1] = '\0'; + if (datalen == 0 || data[datalen - 1] != '\0') + fatalx("bad MSG_SHELL string"); clear_signals(0); - - shell_exec(shelldata.shell, shellcmd); + shell_exec(data, data0); /* NOTREACHED */ case MSG_DETACH: + case MSG_DETACHKILL: client_write_server(MSG_EXITING, NULL, 0); break; case MSG_EXITED: imsg_free(&imsg); return (-1); - default: - fatalx("unexpected message"); } imsg_free(&imsg); @@ -590,25 +616,28 @@ client_dispatch_wait(void *data) int client_dispatch_attached(void) { - struct imsg imsg; - struct msg_lock_data lockdata; - struct sigaction sigact; - ssize_t n, datalen; + struct imsg imsg; + struct sigaction sigact; + char *data; + ssize_t n, datalen; for (;;) { if ((n = imsg_get(&client_ibuf, &imsg)) == -1) fatalx("imsg_get failed"); if (n == 0) return (0); + + data = imsg.data; datalen = imsg.hdr.len - IMSG_HEADER_SIZE; log_debug("got %d from server", imsg.hdr.type); switch (imsg.hdr.type) { - case MSG_DETACHKILL: case MSG_DETACH: - if (datalen != 0) - fatalx("bad MSG_DETACH size"); + case MSG_DETACHKILL: + if (datalen == 0 || data[datalen - 1] != '\0') + fatalx("bad MSG_DETACH string"); + client_exitsession = xstrdup(data); client_exittype = imsg.hdr.type; if (imsg.hdr.type == MSG_DETACHKILL) client_exitreason = CLIENT_EXIT_DETACHED_HUP; @@ -617,8 +646,7 @@ client_dispatch_attached(void) client_write_server(MSG_EXITING, NULL, 0); break; case MSG_EXIT: - if (datalen != 0 && - datalen != sizeof (struct msg_exit_data)) + if (datalen != 0 && datalen != sizeof (int)) fatalx("bad MSG_EXIT size"); client_write_server(MSG_EXITING, NULL, 0); @@ -651,16 +679,12 @@ client_dispatch_attached(void) kill(getpid(), SIGTSTP); break; case MSG_LOCK: - if (datalen != sizeof lockdata) - fatalx("bad MSG_LOCK size"); - memcpy(&lockdata, imsg.data, sizeof lockdata); + if (datalen == 0 || data[datalen - 1] != '\0') + fatalx("bad MSG_LOCK string"); - lockdata.cmd[(sizeof lockdata.cmd) - 1] = '\0'; - system(lockdata.cmd); + system(data); client_write_server(MSG_UNLOCK, NULL, 0); break; - default: - fatalx("unexpected message"); } imsg_free(&imsg); diff --git a/cmd-attach-session.c b/cmd-attach-session.c index 07185737..e4c0b232 100644 --- a/cmd-attach-session.c +++ b/cmd-attach-session.c @@ -18,7 +18,11 @@ #include +#include +#include #include +#include +#include #include "tmux.h" @@ -30,22 +34,25 @@ enum cmd_retval cmd_attach_session_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_attach_session_entry = { "attach-session", "attach", - "drt:", 0, 0, - "[-dr] " CMD_TARGET_SESSION_USAGE, - CMD_CANTNEST|CMD_STARTSERVER|CMD_SENDENVIRON, - NULL, + "c:drt:", 0, 0, + "[-dr] [-c working-directory] " CMD_TARGET_SESSION_USAGE, + CMD_CANTNEST|CMD_STARTSERVER, NULL, cmd_attach_session_exec }; enum cmd_retval -cmd_attach_session(struct cmd_q *cmdq, const char* tflag, int dflag, int rflag) +cmd_attach_session(struct cmd_q *cmdq, const char *tflag, int dflag, int rflag, + const char *cflag) { - struct session *s; - struct client *c; - const char *update; - char *cause; - u_int i; + struct session *s; + struct client *c; + const char *update; + char *cause; + u_int i; + int fd; + struct format_tree *ft; + char *cp; if (RB_EMPTY(&sessions)) { cmdq_error(cmdq, "no sessions"); @@ -70,10 +77,33 @@ cmd_attach_session(struct cmd_q *cmdq, const char* tflag, int dflag, int rflag) continue; if (c == cmdq->client) continue; - server_write_client(c, MSG_DETACH, NULL, 0); + server_write_client(c, MSG_DETACH, + c->session->name, + strlen(c->session->name) + 1); } } + if (cflag != NULL) { + ft = format_create(); + if ((c = cmd_find_client(cmdq, NULL, 1)) != NULL) + format_client(ft, c); + format_session(ft, s); + format_winlink(ft, s, s->curw); + format_window_pane(ft, s->curw->window->active); + cp = format_expand(ft, cflag); + format_free(ft); + + fd = open(cp, O_RDONLY|O_DIRECTORY); + free(cp); + if (fd == -1) { + cmdq_error(cmdq, "bad working directory: %s", + strerror(errno)); + return (CMD_RETURN_ERROR); + } + close(s->cwd); + s->cwd = fd; + } + cmdq->client->session = s; notify_attached_session_changed(cmdq->client); session_update_activity(s); @@ -86,11 +116,34 @@ cmd_attach_session(struct cmd_q *cmdq, const char* tflag, int dflag, int rflag) return (CMD_RETURN_ERROR); } + if (cflag != NULL) { + ft = format_create(); + if ((c = cmd_find_client(cmdq, NULL, 1)) != NULL) + format_client(ft, c); + format_session(ft, s); + format_winlink(ft, s, s->curw); + format_window_pane(ft, s->curw->window->active); + cp = format_expand(ft, cflag); + format_free(ft); + + fd = open(cp, O_RDONLY|O_DIRECTORY); + free(cp); + if (fd == -1) { + cmdq_error(cmdq, "bad working directory: %s", + strerror(errno)); + return (CMD_RETURN_ERROR); + } + close(s->cwd); + s->cwd = fd; + } + if (rflag) cmdq->client->flags |= CLIENT_READONLY; - if (dflag) - server_write_session(s, MSG_DETACH, NULL, 0); + if (dflag) { + server_write_session(s, MSG_DETACH, s->name, + strlen(s->name) + 1); + } update = options_get_string(&s->options, "update-environment"); environ_update(update, &cmdq->client->environ, &s->environ); @@ -116,5 +169,5 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_q *cmdq) struct args *args = self->args; return (cmd_attach_session(cmdq, args_get(args, 't'), - args_has(args, 'd'), args_has(args, 'r'))); + args_has(args, 'd'), args_has(args, 'r'), args_get(args, 'c'))); } diff --git a/cmd-bind-key.c b/cmd-bind-key.c index 71e79ea0..4ff3ac84 100644 --- a/cmd-bind-key.c +++ b/cmd-bind-key.c @@ -27,7 +27,6 @@ * Bind a key to a command, this recurses through cmd_*. */ -enum cmd_retval cmd_bind_key_check(struct args *); enum cmd_retval cmd_bind_key_exec(struct cmd *, struct cmd_q *); enum cmd_retval cmd_bind_key_table(struct cmd *, struct cmd_q *, int); @@ -38,23 +37,9 @@ const struct cmd_entry cmd_bind_key_entry = { "[-cnr] [-t key-table] key command [arguments]", 0, NULL, - cmd_bind_key_check, cmd_bind_key_exec }; -enum cmd_retval -cmd_bind_key_check(struct args *args) -{ - if (args_has(args, 't')) { - if (args->argc != 2 && args->argc != 3) - return (CMD_RETURN_ERROR); - } else { - if (args->argc < 2) - return (CMD_RETURN_ERROR); - } - return (CMD_RETURN_NORMAL); -} - enum cmd_retval cmd_bind_key_exec(struct cmd *self, struct cmd_q *cmdq) { @@ -63,6 +48,18 @@ cmd_bind_key_exec(struct cmd *self, struct cmd_q *cmdq) struct cmd_list *cmdlist; int key; + if (args_has(args, 't')) { + if (args->argc != 2 && args->argc != 3) { + cmdq_error(cmdq, "not enough arguments"); + return (CMD_RETURN_ERROR); + } + } else { + if (args->argc < 2) { + cmdq_error(cmdq, "not enough arguments"); + return (CMD_RETURN_ERROR); + } + } + key = key_string_lookup_string(args->argv[0]); if (key == KEYC_NONE) { cmdq_error(cmdq, "unknown key: %s", args->argv[0]); diff --git a/cmd-break-pane.c b/cmd-break-pane.c index 8ed9a1a6..d0a5a450 100644 --- a/cmd-break-pane.c +++ b/cmd-break-pane.c @@ -34,7 +34,6 @@ const struct cmd_entry cmd_break_pane_entry = { "[-dP] [-F format] " CMD_TARGET_PANE_USAGE, 0, NULL, - NULL, cmd_break_pane_exec }; diff --git a/cmd-capture-pane.c b/cmd-capture-pane.c index f59dc2d6..e157e3cb 100644 --- a/cmd-capture-pane.c +++ b/cmd-capture-pane.c @@ -42,7 +42,6 @@ const struct cmd_entry cmd_capture_pane_entry = { CMD_TARGET_PANE_USAGE, 0, NULL, - NULL, cmd_capture_pane_exec }; diff --git a/cmd-choose-buffer.c b/cmd-choose-buffer.c index e6b79d91..d79f6fdc 100644 --- a/cmd-choose-buffer.c +++ b/cmd-choose-buffer.c @@ -35,7 +35,6 @@ const struct cmd_entry cmd_choose_buffer_entry = { CMD_TARGET_WINDOW_USAGE " [-F format] [template]", 0, NULL, - NULL, cmd_choose_buffer_exec }; diff --git a/cmd-choose-client.c b/cmd-choose-client.c index 40752a70..93671987 100644 --- a/cmd-choose-client.c +++ b/cmd-choose-client.c @@ -37,7 +37,6 @@ const struct cmd_entry cmd_choose_client_entry = { CMD_TARGET_WINDOW_USAGE " [-F format] [template]", 0, NULL, - NULL, cmd_choose_client_exec }; diff --git a/cmd-choose-list.c b/cmd-choose-list.c index 15f87294..c3caabba 100644 --- a/cmd-choose-list.c +++ b/cmd-choose-list.c @@ -39,7 +39,6 @@ const struct cmd_entry cmd_choose_list_entry = { "[-l items] " CMD_TARGET_WINDOW_USAGE "[template]", 0, NULL, - NULL, cmd_choose_list_exec }; diff --git a/cmd-choose-tree.c b/cmd-choose-tree.c index a9b6ffbc..be3bd69a 100644 --- a/cmd-choose-tree.c +++ b/cmd-choose-tree.c @@ -41,7 +41,6 @@ const struct cmd_entry cmd_choose_tree_entry = { "[-W format] " CMD_TARGET_WINDOW_USAGE, 0, NULL, - NULL, cmd_choose_tree_exec }; @@ -51,7 +50,6 @@ const struct cmd_entry cmd_choose_session_entry = { CMD_TARGET_WINDOW_USAGE " [-F format] [template]", 0, NULL, - NULL, cmd_choose_tree_exec }; @@ -61,7 +59,6 @@ const struct cmd_entry cmd_choose_window_entry = { CMD_TARGET_WINDOW_USAGE "[-F format] [template]", 0, NULL, - NULL, cmd_choose_tree_exec }; @@ -228,7 +225,6 @@ windows_only: free(final_win_template_last); window_choose_ready(wl->window->active, cur_win, NULL); - window_choose_collapse_all(wl->window->active); if (args_has(args, 'u')) { window_choose_expand_all(wl->window->active); diff --git a/cmd-clear-history.c b/cmd-clear-history.c index aebaa27d..cce3ea18 100644 --- a/cmd-clear-history.c +++ b/cmd-clear-history.c @@ -32,7 +32,6 @@ const struct cmd_entry cmd_clear_history_entry = { CMD_TARGET_PANE_USAGE, 0, NULL, - NULL, cmd_clear_history_exec }; diff --git a/cmd-clock-mode.c b/cmd-clock-mode.c index 872f3d53..50e4ab8b 100644 --- a/cmd-clock-mode.c +++ b/cmd-clock-mode.c @@ -32,7 +32,6 @@ const struct cmd_entry cmd_clock_mode_entry = { CMD_TARGET_PANE_USAGE, 0, NULL, - NULL, cmd_clock_mode_exec }; diff --git a/cmd-command-prompt.c b/cmd-command-prompt.c index 3bb79ed9..759d578b 100644 --- a/cmd-command-prompt.c +++ b/cmd-command-prompt.c @@ -30,7 +30,6 @@ */ void cmd_command_prompt_key_binding(struct cmd *, int); -int cmd_command_prompt_check(struct args *); enum cmd_retval cmd_command_prompt_exec(struct cmd *, struct cmd_q *); int cmd_command_prompt_callback(void *, const char *); @@ -42,7 +41,6 @@ const struct cmd_entry cmd_command_prompt_entry = { "[-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE " [template]", 0, cmd_command_prompt_key_binding, - NULL, cmd_command_prompt_exec }; diff --git a/cmd-confirm-before.c b/cmd-confirm-before.c index e670f69c..9266721f 100644 --- a/cmd-confirm-before.c +++ b/cmd-confirm-before.c @@ -38,7 +38,6 @@ const struct cmd_entry cmd_confirm_before_entry = { "[-p prompt] " CMD_TARGET_CLIENT_USAGE " command", 0, cmd_confirm_before_key_binding, - NULL, cmd_confirm_before_exec }; diff --git a/cmd-copy-mode.c b/cmd-copy-mode.c index 40584a28..f11c7aff 100644 --- a/cmd-copy-mode.c +++ b/cmd-copy-mode.c @@ -33,7 +33,6 @@ const struct cmd_entry cmd_copy_mode_entry = { "[-u] " CMD_TARGET_PANE_USAGE, 0, cmd_copy_mode_key_binding, - NULL, cmd_copy_mode_exec }; diff --git a/cmd-delete-buffer.c b/cmd-delete-buffer.c index bc3982ca..b8f55db4 100644 --- a/cmd-delete-buffer.c +++ b/cmd-delete-buffer.c @@ -34,7 +34,6 @@ const struct cmd_entry cmd_delete_buffer_entry = { CMD_BUFFER_USAGE, 0, NULL, - NULL, cmd_delete_buffer_exec }; diff --git a/cmd-detach-client.c b/cmd-detach-client.c index 6e00e079..f0867364 100644 --- a/cmd-detach-client.c +++ b/cmd-detach-client.c @@ -18,6 +18,8 @@ #include +#include + #include "tmux.h" /* @@ -32,7 +34,6 @@ const struct cmd_entry cmd_detach_client_entry = { "[-P] [-a] [-s target-session] " CMD_TARGET_CLIENT_USAGE, CMD_READONLY, NULL, - NULL, cmd_detach_client_exec }; @@ -41,8 +42,8 @@ cmd_detach_client_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct client *c, *c2; - struct session *s; - enum msgtype msgtype; + struct session *s; + enum msgtype msgtype; u_int i; if (args_has(args, 'P')) @@ -57,8 +58,10 @@ cmd_detach_client_exec(struct cmd *self, struct cmd_q *cmdq) for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); - if (c != NULL && c->session == s) - server_write_client(c, msgtype, NULL, 0); + if (c == NULL || c->session != s) + continue; + server_write_client(c, msgtype, c->session->name, + strlen(c->session->name) + 1); } } else { c = cmd_find_client(cmdq, args_get(args, 't'), 0); @@ -70,10 +73,14 @@ cmd_detach_client_exec(struct cmd *self, struct cmd_q *cmdq) c2 = ARRAY_ITEM(&clients, i); if (c2 == NULL || c == c2) continue; - server_write_client(c2, msgtype, NULL, 0); + server_write_client(c2, msgtype, + c2->session->name, + strlen(c2->session->name) + 1); } - } else - server_write_client(c, msgtype, NULL, 0); + } else { + server_write_client(c, msgtype, c->session->name, + strlen(c->session->name) + 1); + } } return (CMD_RETURN_STOP); diff --git a/cmd-display-message.c b/cmd-display-message.c index 485ccf08..78752f86 100644 --- a/cmd-display-message.c +++ b/cmd-display-message.c @@ -36,7 +36,6 @@ const struct cmd_entry cmd_display_message_entry = { " [message]", 0, NULL, - NULL, cmd_display_message_exec }; @@ -71,9 +70,9 @@ cmd_display_message_exec(struct cmd *self, struct cmd_q *cmdq) } if (args_has(args, 'c')) { - c = cmd_find_client(cmdq, args_get(args, 'c'), 0); - if (c == NULL) - return (CMD_RETURN_ERROR); + c = cmd_find_client(cmdq, args_get(args, 'c'), 0); + if (c == NULL) + return (CMD_RETURN_ERROR); } else { c = cmd_current_client(cmdq); if (c == NULL && !args_has(self->args, 'p')) { diff --git a/cmd-display-panes.c b/cmd-display-panes.c index 4a8731a4..c137feef 100644 --- a/cmd-display-panes.c +++ b/cmd-display-panes.c @@ -32,7 +32,6 @@ const struct cmd_entry cmd_display_panes_entry = { CMD_TARGET_CLIENT_USAGE, 0, NULL, - NULL, cmd_display_panes_exec }; diff --git a/cmd-find-window.c b/cmd-find-window.c index 02f19307..647cc8fb 100644 --- a/cmd-find-window.c +++ b/cmd-find-window.c @@ -48,7 +48,6 @@ const struct cmd_entry cmd_find_window_entry = { "[-CNT] [-F format] " CMD_TARGET_WINDOW_USAGE " match-string", 0, NULL, - NULL, cmd_find_window_exec }; diff --git a/cmd-has-session.c b/cmd-has-session.c index c4286b86..38a92f61 100644 --- a/cmd-has-session.c +++ b/cmd-has-session.c @@ -32,7 +32,6 @@ const struct cmd_entry cmd_has_session_entry = { CMD_TARGET_SESSION_USAGE, 0, NULL, - NULL, cmd_has_session_exec }; diff --git a/cmd-if-shell.c b/cmd-if-shell.c index d1cbd7f3..9b6dcf30 100644 --- a/cmd-if-shell.c +++ b/cmd-if-shell.c @@ -41,7 +41,6 @@ const struct cmd_entry cmd_if_shell_entry = { "[-b] " CMD_TARGET_PANE_USAGE " shell-command command [command]", 0, NULL, - NULL, cmd_if_shell_exec }; @@ -148,6 +147,9 @@ cmd_if_shell_done(struct cmd_q *cmdq1) struct cmd_if_shell_data *cdata = cmdq1->data; struct cmd_q *cmdq = cdata->cmdq; + if (cmdq1->client_exit >= 0) + cmdq->client_exit = cmdq1->client_exit; + if (!cmdq_free(cmdq) && !cdata->bflag) cmdq_continue(cmdq); diff --git a/cmd-join-pane.c b/cmd-join-pane.c index 2cf587e0..1a710cec 100644 --- a/cmd-join-pane.c +++ b/cmd-join-pane.c @@ -39,7 +39,6 @@ const struct cmd_entry cmd_join_pane_entry = { "[-bdhv] [-p percentage|-l size] [-s src-pane] [-t dst-pane]", 0, cmd_join_pane_key_binding, - NULL, cmd_join_pane_exec }; @@ -49,7 +48,6 @@ const struct cmd_entry cmd_move_pane_entry = { "[-bdhv] [-p percentage|-l size] [-s src-pane] [-t dst-pane]", 0, NULL, - NULL, cmd_join_pane_exec }; diff --git a/cmd-kill-pane.c b/cmd-kill-pane.c index 40761350..bf486eb3 100644 --- a/cmd-kill-pane.c +++ b/cmd-kill-pane.c @@ -34,7 +34,6 @@ const struct cmd_entry cmd_kill_pane_entry = { "[-a] " CMD_TARGET_PANE_USAGE, 0, NULL, - NULL, cmd_kill_pane_exec }; diff --git a/cmd-kill-server.c b/cmd-kill-server.c index a6065460..ba63faa3 100644 --- a/cmd-kill-server.c +++ b/cmd-kill-server.c @@ -35,7 +35,6 @@ const struct cmd_entry cmd_kill_server_entry = { "", 0, NULL, - NULL, cmd_kill_server_exec }; diff --git a/cmd-kill-session.c b/cmd-kill-session.c index a12cc8a4..54b0c31b 100644 --- a/cmd-kill-session.c +++ b/cmd-kill-session.c @@ -35,7 +35,6 @@ const struct cmd_entry cmd_kill_session_entry = { "[-a] " CMD_TARGET_SESSION_USAGE, 0, NULL, - NULL, cmd_kill_session_exec }; diff --git a/cmd-kill-window.c b/cmd-kill-window.c index 34b97499..ca8fe3d6 100644 --- a/cmd-kill-window.c +++ b/cmd-kill-window.c @@ -32,7 +32,6 @@ const struct cmd_entry cmd_kill_window_entry = { "[-a] " CMD_TARGET_WINDOW_USAGE, 0, NULL, - NULL, cmd_kill_window_exec }; diff --git a/cmd-link-window.c b/cmd-link-window.c index 2be8ace0..d94eb38a 100644 --- a/cmd-link-window.c +++ b/cmd-link-window.c @@ -34,7 +34,6 @@ const struct cmd_entry cmd_link_window_entry = { "[-dk] " CMD_SRCDST_WINDOW_USAGE, 0, NULL, - NULL, cmd_link_window_exec }; diff --git a/cmd-list-buffers.c b/cmd-list-buffers.c index 58af0020..02a4183e 100644 --- a/cmd-list-buffers.c +++ b/cmd-list-buffers.c @@ -35,7 +35,6 @@ const struct cmd_entry cmd_list_buffers_entry = { "[-F format]", 0, NULL, - NULL, cmd_list_buffers_exec }; diff --git a/cmd-list-clients.c b/cmd-list-clients.c index 59f63099..904ec005 100644 --- a/cmd-list-clients.c +++ b/cmd-list-clients.c @@ -36,7 +36,6 @@ const struct cmd_entry cmd_list_clients_entry = { "[-F format] " CMD_TARGET_SESSION_USAGE, CMD_READONLY, NULL, - NULL, cmd_list_clients_exec }; diff --git a/cmd-list-commands.c b/cmd-list-commands.c index 1bf6e703..06e48378 100644 --- a/cmd-list-commands.c +++ b/cmd-list-commands.c @@ -32,7 +32,6 @@ const struct cmd_entry cmd_list_commands_entry = { "", 0, NULL, - NULL, cmd_list_commands_exec }; diff --git a/cmd-list-keys.c b/cmd-list-keys.c index 78998b66..615c5ce1 100644 --- a/cmd-list-keys.c +++ b/cmd-list-keys.c @@ -35,7 +35,6 @@ const struct cmd_entry cmd_list_keys_entry = { "[-t key-table]", 0, NULL, - NULL, cmd_list_keys_exec }; diff --git a/cmd-list-panes.c b/cmd-list-panes.c index 0d498e28..c989eba1 100644 --- a/cmd-list-panes.c +++ b/cmd-list-panes.c @@ -41,7 +41,6 @@ const struct cmd_entry cmd_list_panes_entry = { "[-as] [-F format] " CMD_TARGET_WINDOW_USAGE, 0, NULL, - NULL, cmd_list_panes_exec }; diff --git a/cmd-list-sessions.c b/cmd-list-sessions.c index 61c12f4e..a3613c87 100644 --- a/cmd-list-sessions.c +++ b/cmd-list-sessions.c @@ -36,7 +36,6 @@ const struct cmd_entry cmd_list_sessions_entry = { "[-F format]", 0, NULL, - NULL, cmd_list_sessions_exec }; diff --git a/cmd-list-windows.c b/cmd-list-windows.c index 5c2a2b95..ce122f45 100644 --- a/cmd-list-windows.c +++ b/cmd-list-windows.c @@ -39,7 +39,6 @@ const struct cmd_entry cmd_list_windows_entry = { "[-a] [-F format] " CMD_TARGET_SESSION_USAGE, 0, NULL, - NULL, cmd_list_windows_exec }; diff --git a/cmd-load-buffer.c b/cmd-load-buffer.c index 3be14d6a..4acbab5e 100644 --- a/cmd-load-buffer.c +++ b/cmd-load-buffer.c @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -39,7 +40,6 @@ const struct cmd_entry cmd_load_buffer_entry = { CMD_BUFFER_USAGE " path", 0, NULL, - NULL, cmd_load_buffer_exec }; @@ -50,11 +50,11 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_q *cmdq) struct client *c = cmdq->client; struct session *s; FILE *f; - const char *path, *newpath, *wd; + const char *path; char *pdata, *new_pdata, *cause; size_t psize; u_int limit; - int ch, error, buffer, *buffer_ptr; + int ch, error, buffer, *buffer_ptr, cwd, fd; if (!args_has(args, 'b')) buffer = -1; @@ -82,20 +82,17 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_q *cmdq) return (CMD_RETURN_WAIT); } - if (c != NULL) - wd = c->cwd; - else if ((s = cmd_current_session(cmdq, 0)) != NULL) { - wd = options_get_string(&s->options, "default-path"); - if (*wd == '\0') - wd = s->cwd; - } else - wd = NULL; - if (wd != NULL && *wd != '\0') { - newpath = get_full_path(wd, path); - if (newpath != NULL) - path = newpath; - } - if ((f = fopen(path, "rb")) == NULL) { + if (c != NULL && c->session == NULL) + cwd = c->cwd; + else if ((s = cmd_current_session(cmdq, 0)) != NULL) + cwd = s->cwd; + else + cwd = AT_FDCWD; + + if ((fd = openat(cwd, path, O_RDONLY)) == -1 || + (f = fdopen(fd, "rb")) == NULL) { + if (fd != -1) + close(fd); cmdq_error(cmdq, "%s: %s", path, strerror(errno)); return (CMD_RETURN_ERROR); } diff --git a/cmd-lock-server.c b/cmd-lock-server.c index 0b6aafe8..2b591ecf 100644 --- a/cmd-lock-server.c +++ b/cmd-lock-server.c @@ -36,7 +36,6 @@ const struct cmd_entry cmd_lock_server_entry = { "", 0, NULL, - NULL, cmd_lock_server_exec }; @@ -46,7 +45,6 @@ const struct cmd_entry cmd_lock_session_entry = { CMD_TARGET_SESSION_USAGE, 0, NULL, - NULL, cmd_lock_server_exec }; @@ -56,7 +54,6 @@ const struct cmd_entry cmd_lock_client_entry = { CMD_TARGET_CLIENT_USAGE, 0, NULL, - NULL, cmd_lock_server_exec }; diff --git a/cmd-move-window.c b/cmd-move-window.c index 1a147c7e..21606755 100644 --- a/cmd-move-window.c +++ b/cmd-move-window.c @@ -34,7 +34,6 @@ const struct cmd_entry cmd_move_window_entry = { "[-dkr] " CMD_SRCDST_WINDOW_USAGE, 0, NULL, - NULL, cmd_move_window_exec }; diff --git a/cmd-new-session.c b/cmd-new-session.c index 4eebe632..ad083a44 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -18,6 +18,8 @@ #include +#include +#include #include #include #include @@ -30,46 +32,39 @@ * Create a new session and attach to the current terminal unless -d is given. */ -enum cmd_retval cmd_new_session_check(struct args *); enum cmd_retval cmd_new_session_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_new_session_entry = { "new-session", "new", - "AdDF:n:Ps:t:x:y:", 0, 1, - "[-AdDP] [-F format] [-n window-name] [-s session-name] " - CMD_TARGET_SESSION_USAGE " [-x width] [-y height] [command]", - CMD_STARTSERVER|CMD_CANTNEST|CMD_SENDENVIRON, + "Ac:dDF:n:Ps:t:x:y:", 0, 1, + "[-AdDP] [-c start-directory] [-F format] [-n window-name] " + "[-s session-name] " CMD_TARGET_SESSION_USAGE " [-x width] [-y height] " + "[command]", + CMD_STARTSERVER|CMD_CANTNEST, NULL, - cmd_new_session_check, cmd_new_session_exec }; -enum cmd_retval -cmd_new_session_check(struct args *args) -{ - if (args_has(args, 't') && (args->argc != 0 || args_has(args, 'n'))) - return (CMD_RETURN_ERROR); - return (CMD_RETURN_NORMAL); -} - enum cmd_retval cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; - struct client *c = cmdq->client; + struct client *c = cmdq->client, *c0; struct session *s, *groupwith; struct window *w; struct environ env; struct termios tio, *tiop; - struct passwd *pw; - const char *newname, *target, *update, *cwd, *errstr; - const char *template; + const char *newname, *target, *update, *errstr, *template; char *cmd, *cause, *cp; - int detached, idx; + int detached, already_attached, idx, cwd, fd = -1; u_int sx, sy; - int already_attached; struct format_tree *ft; + if (args_has(args, 't') && (args->argc != 0 || args_has(args, 'n'))) { + cmdq_error(cmdq, "command or window name given with target"); + return (CMD_RETURN_ERROR); + } + newname = args_get(args, 's'); if (newname != NULL) { if (!session_check_name(newname)) { @@ -79,7 +74,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) if (session_find(newname) != NULL) { if (args_has(args, 'A')) { return (cmd_attach_session(cmdq, newname, - args_has(args, 'D'), 0)); + args_has(args, 'D'), 0, NULL)); } cmdq_error(cmdq, "duplicate session: %s", newname); return (CMD_RETURN_ERROR); @@ -104,6 +99,31 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) if (c != NULL && c->session != NULL) already_attached = 1; + /* Get the new session working directory. */ + if (args_has(args, 'c')) { + ft = format_create(); + if ((c0 = cmd_find_client(cmdq, NULL, 1)) != NULL) + format_client(ft, c0); + cp = format_expand(ft, args_get(args, 'c')); + format_free(ft); + + fd = open(cp, O_RDONLY|O_DIRECTORY); + free(cp); + if (fd == -1) { + cmdq_error(cmdq, "bad working directory: %s", + strerror(errno)); + return (CMD_RETURN_ERROR); + } + cwd = fd; + } else if (c != NULL && c->session == NULL) + cwd = c->cwd; + else if ((c0 = cmd_current_client(cmdq)) != NULL) + cwd = c0->session->cwd; + else { + fd = open(".", O_RDONLY); + cwd = fd; + } + /* * Save the termios settings, part of which is used for new windows in * this session. @@ -125,21 +145,10 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) if (server_client_open(c, NULL, &cause) != 0) { cmdq_error(cmdq, "open terminal failed: %s", cause); free(cause); - return (CMD_RETURN_ERROR); + goto error; } } - /* Get the new session working directory. */ - if (c != NULL && c->cwd != NULL) - cwd = c->cwd; - else { - pw = getpwuid(getuid()); - if (pw->pw_dir != NULL && *pw->pw_dir != '\0') - cwd = pw->pw_dir; - else - cwd = "/"; - } - /* Find new session size. */ if (c != NULL) { sx = c->tty.sx; @@ -152,14 +161,14 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) sx = strtonum(args_get(args, 'x'), 1, USHRT_MAX, &errstr); if (errstr != NULL) { cmdq_error(cmdq, "width %s", errstr); - return (CMD_RETURN_ERROR); + goto error; } } if (detached && args_has(args, 'y')) { sy = strtonum(args_get(args, 'y'), 1, USHRT_MAX, &errstr); if (errstr != NULL) { cmdq_error(cmdq, "height %s", errstr); - return (CMD_RETURN_ERROR); + goto error; } } if (sy > 0 && options_get_number(&global_s_options, "status")) @@ -189,7 +198,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) if (s == NULL) { cmdq_error(cmdq, "create session failed: %s", cause); free(cause); - return (CMD_RETURN_ERROR); + goto error; } environ_free(&env); @@ -240,8 +249,8 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) template = NEW_SESSION_TEMPLATE; ft = format_create(); - if ((c = cmd_find_client(cmdq, NULL, 1)) != NULL) - format_client(ft, c); + if ((c0 = cmd_find_client(cmdq, NULL, 1)) != NULL) + format_client(ft, c0); format_session(ft, s); cp = format_expand(ft, template); @@ -253,5 +262,13 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) if (!detached) cmdq->client_exit = 0; + + if (fd != -1) + close(fd); return (CMD_RETURN_NORMAL); + +error: + if (fd != -1) + close(fd); + return (CMD_RETURN_ERROR); } diff --git a/cmd-new-window.c b/cmd-new-window.c index cfc0b8bd..5c2cbe40 100644 --- a/cmd-new-window.c +++ b/cmd-new-window.c @@ -18,7 +18,11 @@ #include +#include +#include #include +#include +#include #include "tmux.h" @@ -35,7 +39,6 @@ const struct cmd_entry cmd_new_window_entry = { CMD_TARGET_WINDOW_USAGE " [command]", 0, NULL, - NULL, cmd_new_window_exec }; @@ -46,9 +49,9 @@ cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq) struct session *s; struct winlink *wl; struct client *c; - const char *cmd, *cwd, *template; + const char *cmd, *template; char *cause, *cp; - int idx, last, detached; + int idx, last, detached, cwd, fd = -1; struct format_tree *ft; if (args_has(args, 'a')) { @@ -103,7 +106,29 @@ cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq) cmd = options_get_string(&s->options, "default-command"); else cmd = args->argv[0]; - cwd = cmd_get_default_path(cmdq, args_get(args, 'c')); + + if (args_has(args, 'c')) { + ft = format_create(); + if ((c = cmd_find_client(cmdq, NULL, 1)) != NULL) + format_client(ft, c); + format_session(ft, s); + format_winlink(ft, s, s->curw); + format_window_pane(ft, s->curw->window->active); + cp = format_expand(ft, args_get(args, 'c')); + format_free(ft); + + fd = open(cp, O_RDONLY|O_DIRECTORY); + free(cp); + if (fd == -1) { + cmdq_error(cmdq, "bad working directory: %s", + strerror(errno)); + return (CMD_RETURN_ERROR); + } + cwd = fd; + } else if (cmdq->client != NULL && cmdq->client->session == NULL) + cwd = cmdq->client->cwd; + else + cwd = s->cwd; if (idx == -1) idx = -1 - options_get_number(&s->options, "base-index"); @@ -111,7 +136,7 @@ cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq) if (wl == NULL) { cmdq_error(cmdq, "create window failed: %s", cause); free(cause); - return (CMD_RETURN_ERROR); + goto error; } if (!detached) { session_select(s, wl->idx); @@ -137,5 +162,12 @@ cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq) format_free(ft); } + if (fd != -1) + close(fd); return (CMD_RETURN_NORMAL); + +error: + if (fd != -1) + close(fd); + return (CMD_RETURN_ERROR); } diff --git a/cmd-paste-buffer.c b/cmd-paste-buffer.c index b07c9faf..5305b7e6 100644 --- a/cmd-paste-buffer.c +++ b/cmd-paste-buffer.c @@ -38,7 +38,6 @@ const struct cmd_entry cmd_paste_buffer_entry = { "[-dpr] [-s separator] [-b buffer-index] " CMD_TARGET_PANE_USAGE, 0, NULL, - NULL, cmd_paste_buffer_exec }; diff --git a/cmd-pipe-pane.c b/cmd-pipe-pane.c index aa72c699..611ad8cf 100644 --- a/cmd-pipe-pane.c +++ b/cmd-pipe-pane.c @@ -41,7 +41,6 @@ const struct cmd_entry cmd_pipe_pane_entry = { "[-o] " CMD_TARGET_PANE_USAGE " [command]", 0, NULL, - NULL, cmd_pipe_pane_exec }; diff --git a/cmd-queue.c b/cmd-queue.c index 243f73dd..c5905bdb 100644 --- a/cmd-queue.c +++ b/cmd-queue.c @@ -35,7 +35,7 @@ cmdq_new(struct client *c) cmdq->dead = 0; cmdq->client = c; - cmdq->client_exit = 0; + cmdq->client_exit = -1; TAILQ_INIT(&cmdq->queue); cmdq->item = NULL; @@ -143,7 +143,7 @@ cmdq_error(struct cmd_q *cmdq, const char *fmt, ...) evbuffer_add(c->stderr_data, "\n", 1); server_push_stderr(c); - c->retcode = 1; + c->retval = 1; } else { *msg = toupper((u_char) *msg); status_message_set(c, "%s", msg); @@ -154,18 +154,15 @@ cmdq_error(struct cmd_q *cmdq, const char *fmt, ...) /* Print a guard line. */ int -cmdq_guard(struct cmd_q *cmdq, const char *guard) +cmdq_guard(struct cmd_q *cmdq, const char *guard, int flags) { struct client *c = cmdq->client; - int flags; if (c == NULL) return 0; if (!(c->flags & CLIENT_CONTROL)) return 0; - flags = !!(cmdq->cmd->flags & CMD_CONTROL); - evbuffer_add_printf(c->stdout_data, "%%%s %ld %u %d\n", guard, (long) cmdq->time, cmdq->number, flags); server_push_stdout(c); @@ -202,7 +199,7 @@ cmdq_continue(struct cmd_q *cmdq) { struct cmd_q_item *next; enum cmd_retval retval; - int empty, guard; + int empty, guard, flags; char s[1024]; notify_disable(); @@ -228,13 +225,16 @@ cmdq_continue(struct cmd_q *cmdq) cmdq->time = time(NULL); cmdq->number++; - guard = cmdq_guard(cmdq, "begin"); + flags = !!(cmdq->cmd->flags & CMD_CONTROL); + guard = cmdq_guard(cmdq, "begin", flags); + retval = cmdq->cmd->entry->exec(cmdq->cmd, cmdq); + if (guard) { if (retval == CMD_RETURN_ERROR) - cmdq_guard(cmdq, "error"); + cmdq_guard(cmdq, "error", flags); else - cmdq_guard(cmdq, "end"); + cmdq_guard(cmdq, "end", flags); } if (retval == CMD_RETURN_ERROR) @@ -259,7 +259,7 @@ cmdq_continue(struct cmd_q *cmdq) } while (cmdq->item != NULL); empty: - if (cmdq->client_exit) + if (cmdq->client_exit > 0) cmdq->client->flags |= CLIENT_EXIT; if (cmdq->emptyfn != NULL) cmdq->emptyfn(cmdq); /* may free cmdq */ diff --git a/cmd-refresh-client.c b/cmd-refresh-client.c index 7d9d539f..45804fbe 100644 --- a/cmd-refresh-client.c +++ b/cmd-refresh-client.c @@ -29,10 +29,9 @@ enum cmd_retval cmd_refresh_client_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_refresh_client_entry = { "refresh-client", "refresh", "C:St:", 0, 0, - "[-S] [-C size]" CMD_TARGET_CLIENT_USAGE, + "[-S] [-C size] " CMD_TARGET_CLIENT_USAGE, 0, NULL, - NULL, cmd_refresh_client_exec }; diff --git a/cmd-rename-session.c b/cmd-rename-session.c index 3f8a9d8f..4c8ae122 100644 --- a/cmd-rename-session.c +++ b/cmd-rename-session.c @@ -34,7 +34,6 @@ const struct cmd_entry cmd_rename_session_entry = { CMD_TARGET_SESSION_USAGE " new-name", 0, NULL, - NULL, cmd_rename_session_exec }; diff --git a/cmd-rename-window.c b/cmd-rename-window.c index c756ba1f..f647abb3 100644 --- a/cmd-rename-window.c +++ b/cmd-rename-window.c @@ -34,7 +34,6 @@ const struct cmd_entry cmd_rename_window_entry = { CMD_TARGET_WINDOW_USAGE " new-name", 0, NULL, - NULL, cmd_rename_window_exec }; diff --git a/cmd-resize-pane.c b/cmd-resize-pane.c index ca2a6cd3..d31f8868 100644 --- a/cmd-resize-pane.c +++ b/cmd-resize-pane.c @@ -35,7 +35,6 @@ const struct cmd_entry cmd_resize_pane_entry = { "[-DLRUZ] [-x width] [-y height] " CMD_TARGET_PANE_USAGE " [adjustment]", 0, cmd_resize_pane_key_binding, - NULL, cmd_resize_pane_exec }; diff --git a/cmd-respawn-pane.c b/cmd-respawn-pane.c index 4486c91f..bcde2754 100644 --- a/cmd-respawn-pane.c +++ b/cmd-respawn-pane.c @@ -36,7 +36,6 @@ const struct cmd_entry cmd_respawn_pane_entry = { "[-k] " CMD_TARGET_PANE_USAGE " [command]", 0, NULL, - NULL, cmd_respawn_pane_exec }; @@ -78,7 +77,7 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmd_q *cmdq) cmd = args->argv[0]; else cmd = NULL; - if (window_pane_spawn(wp, cmd, NULL, NULL, &env, s->tio, &cause) != 0) { + if (window_pane_spawn(wp, cmd, NULL, -1, &env, s->tio, &cause) != 0) { cmdq_error(cmdq, "respawn pane failed: %s", cause); free(cause); environ_free(&env); diff --git a/cmd-respawn-window.c b/cmd-respawn-window.c index 35bd3471..e6d913cf 100644 --- a/cmd-respawn-window.c +++ b/cmd-respawn-window.c @@ -35,7 +35,6 @@ const struct cmd_entry cmd_respawn_window_entry = { "[-k] " CMD_TARGET_WINDOW_USAGE " [command]", 0, NULL, - NULL, cmd_respawn_window_exec }; @@ -80,7 +79,7 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_q *cmdq) cmd = args->argv[0]; else cmd = NULL; - if (window_pane_spawn(wp, cmd, NULL, NULL, &env, s->tio, &cause) != 0) { + if (window_pane_spawn(wp, cmd, NULL, -1, &env, s->tio, &cause) != 0) { cmdq_error(cmdq, "respawn window failed: %s", cause); free(cause); environ_free(&env); diff --git a/cmd-rotate-window.c b/cmd-rotate-window.c index 75ca7292..9f4cc751 100644 --- a/cmd-rotate-window.c +++ b/cmd-rotate-window.c @@ -33,7 +33,6 @@ const struct cmd_entry cmd_rotate_window_entry = { "[-DU] " CMD_TARGET_WINDOW_USAGE, 0, cmd_rotate_window_key_binding, - NULL, cmd_rotate_window_exec }; diff --git a/cmd-run-shell.c b/cmd-run-shell.c index 7c7d333c..f5231814 100644 --- a/cmd-run-shell.c +++ b/cmd-run-shell.c @@ -41,7 +41,6 @@ const struct cmd_entry cmd_run_shell_entry = { "[-b] " CMD_TARGET_PANE_USAGE " shell-command", 0, NULL, - NULL, cmd_run_shell_exec }; diff --git a/cmd-save-buffer.c b/cmd-save-buffer.c index 52914a94..fc56dd8f 100644 --- a/cmd-save-buffer.c +++ b/cmd-save-buffer.c @@ -20,8 +20,11 @@ #include #include +#include #include #include +#include +#include #include "tmux.h" @@ -37,7 +40,6 @@ const struct cmd_entry cmd_save_buffer_entry = { "[-a] " CMD_BUFFER_USAGE " path", 0, NULL, - NULL, cmd_save_buffer_exec }; @@ -47,7 +49,6 @@ const struct cmd_entry cmd_show_buffer_entry = { CMD_BUFFER_USAGE, 0, NULL, - NULL, cmd_save_buffer_exec }; @@ -55,17 +56,14 @@ enum cmd_retval cmd_save_buffer_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; - struct client *c; + struct client *c = cmdq->client; struct session *s; struct paste_buffer *pb; - const char *path, *newpath, *wd; - char *cause, *start, *end; - size_t size, used; - int buffer; - mode_t mask; + const char *path; + char *cause, *start, *end, *msg; + size_t size, used, msglen; + int cwd, fd, buffer; FILE *f; - char *msg; - size_t msglen; if (!args_has(args, 'b')) { if ((pb = paste_get_top(&global_buffers)) == NULL) { @@ -92,7 +90,6 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_q *cmdq) else path = args->argv[0]; if (strcmp(path, "-") == 0) { - c = cmdq->client; if (c == NULL) { cmdq_error(cmdq, "can't write to stdout"); return (CMD_RETURN_ERROR); @@ -102,28 +99,26 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_q *cmdq) goto do_print; } - c = cmdq->client; - if (c != NULL) - wd = c->cwd; - else if ((s = cmd_current_session(cmdq, 0)) != NULL) { - wd = options_get_string(&s->options, "default-path"); - if (*wd == '\0') - wd = s->cwd; - } else - wd = NULL; - if (wd != NULL && *wd != '\0') { - newpath = get_full_path(wd, path); - if (newpath != NULL) - path = newpath; - } - - mask = umask(S_IRWXG | S_IRWXO); - if (args_has(self->args, 'a')) - f = fopen(path, "ab"); + if (c != NULL && c->session == NULL) + cwd = c->cwd; + else if ((s = cmd_current_session(cmdq, 0)) != NULL) + cwd = s->cwd; else - f = fopen(path, "wb"); - umask(mask); + cwd = AT_FDCWD; + + f = NULL; + if (args_has(self->args, 'a')) { + fd = openat(cwd, path, O_CREAT|O_RDWR|O_APPEND, 0600); + if (fd != -1) + f = fdopen(fd, "ab"); + } else { + fd = openat(cwd, path, O_CREAT|O_RDWR, 0600); + if (fd != -1) + f = fdopen(fd, "wb"); + } if (f == NULL) { + if (fd != -1) + close(fd); cmdq_error(cmdq, "%s: %s", path, strerror(errno)); return (CMD_RETURN_ERROR); } diff --git a/cmd-select-layout.c b/cmd-select-layout.c index ae1be4c4..053f3e40 100644 --- a/cmd-select-layout.c +++ b/cmd-select-layout.c @@ -33,7 +33,6 @@ const struct cmd_entry cmd_select_layout_entry = { "[-np] " CMD_TARGET_WINDOW_USAGE " [layout-name]", 0, cmd_select_layout_key_binding, - NULL, cmd_select_layout_exec }; @@ -43,7 +42,6 @@ const struct cmd_entry cmd_next_layout_entry = { CMD_TARGET_WINDOW_USAGE, 0, NULL, - NULL, cmd_select_layout_exec }; @@ -53,7 +51,6 @@ const struct cmd_entry cmd_previous_layout_entry = { CMD_TARGET_WINDOW_USAGE, 0, NULL, - NULL, cmd_select_layout_exec }; diff --git a/cmd-select-pane.c b/cmd-select-pane.c index b8a12671..c342fef3 100644 --- a/cmd-select-pane.c +++ b/cmd-select-pane.c @@ -33,7 +33,6 @@ const struct cmd_entry cmd_select_pane_entry = { "[-lDLRU] " CMD_TARGET_PANE_USAGE, 0, cmd_select_pane_key_binding, - NULL, cmd_select_pane_exec }; @@ -43,7 +42,6 @@ const struct cmd_entry cmd_last_pane_entry = { CMD_TARGET_WINDOW_USAGE, 0, NULL, - NULL, cmd_select_pane_exec }; diff --git a/cmd-select-window.c b/cmd-select-window.c index c15d5858..73196200 100644 --- a/cmd-select-window.c +++ b/cmd-select-window.c @@ -35,7 +35,6 @@ const struct cmd_entry cmd_select_window_entry = { "[-lnpT] " CMD_TARGET_WINDOW_USAGE, 0, cmd_select_window_key_binding, - NULL, cmd_select_window_exec }; @@ -45,7 +44,6 @@ const struct cmd_entry cmd_next_window_entry = { "[-a] " CMD_TARGET_SESSION_USAGE, 0, cmd_select_window_key_binding, - NULL, cmd_select_window_exec }; @@ -55,7 +53,6 @@ const struct cmd_entry cmd_previous_window_entry = { "[-a] " CMD_TARGET_SESSION_USAGE, 0, cmd_select_window_key_binding, - NULL, cmd_select_window_exec }; @@ -65,7 +62,6 @@ const struct cmd_entry cmd_last_window_entry = { CMD_TARGET_SESSION_USAGE, 0, NULL, - NULL, cmd_select_window_exec }; diff --git a/cmd-send-keys.c b/cmd-send-keys.c index a2041656..50cb70e2 100644 --- a/cmd-send-keys.c +++ b/cmd-send-keys.c @@ -35,7 +35,6 @@ const struct cmd_entry cmd_send_keys_entry = { "[-lR] " CMD_TARGET_PANE_USAGE " key ...", 0, NULL, - NULL, cmd_send_keys_exec }; @@ -45,7 +44,6 @@ const struct cmd_entry cmd_send_prefix_entry = { "[-2] " CMD_TARGET_PANE_USAGE, 0, NULL, - NULL, cmd_send_keys_exec }; diff --git a/cmd-server-info.c b/cmd-server-info.c index 8eba172a..3aa5df8a 100644 --- a/cmd-server-info.c +++ b/cmd-server-info.c @@ -38,7 +38,6 @@ const struct cmd_entry cmd_server_info_entry = { "", 0, NULL, - NULL, cmd_server_info_exec }; diff --git a/cmd-set-buffer.c b/cmd-set-buffer.c index 46d28ff2..fade4fe3 100644 --- a/cmd-set-buffer.c +++ b/cmd-set-buffer.c @@ -35,7 +35,6 @@ const struct cmd_entry cmd_set_buffer_entry = { CMD_BUFFER_USAGE " data", 0, NULL, - NULL, cmd_set_buffer_exec }; diff --git a/cmd-set-environment.c b/cmd-set-environment.c index 0f0365aa..8d067c35 100644 --- a/cmd-set-environment.c +++ b/cmd-set-environment.c @@ -35,7 +35,6 @@ const struct cmd_entry cmd_set_environment_entry = { "[-gru] " CMD_TARGET_SESSION_USAGE " name [value]", 0, NULL, - NULL, cmd_set_environment_exec }; diff --git a/cmd-set-option.c b/cmd-set-option.c index c246743c..3acf125d 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -67,7 +67,6 @@ const struct cmd_entry cmd_set_option_entry = { "[-agosquw] [-t target-session|target-window] option [value]", 0, NULL, - NULL, cmd_set_option_exec }; @@ -77,7 +76,6 @@ const struct cmd_entry cmd_set_window_option_entry = { "[-agoqu] " CMD_TARGET_WINDOW_USAGE " option [value]", 0, NULL, - NULL, cmd_set_option_exec }; diff --git a/cmd-show-environment.c b/cmd-show-environment.c index ffe98bcc..2238929e 100644 --- a/cmd-show-environment.c +++ b/cmd-show-environment.c @@ -35,7 +35,6 @@ const struct cmd_entry cmd_show_environment_entry = { "[-g] " CMD_TARGET_SESSION_USAGE " [name]", 0, NULL, - NULL, cmd_show_environment_exec }; diff --git a/cmd-show-messages.c b/cmd-show-messages.c index bc2424ad..256570cd 100644 --- a/cmd-show-messages.c +++ b/cmd-show-messages.c @@ -35,7 +35,6 @@ const struct cmd_entry cmd_show_messages_entry = { CMD_TARGET_CLIENT_USAGE, 0, NULL, - NULL, cmd_show_messages_exec }; diff --git a/cmd-show-options.c b/cmd-show-options.c index e2f78e12..943353f6 100644 --- a/cmd-show-options.c +++ b/cmd-show-options.c @@ -40,7 +40,6 @@ const struct cmd_entry cmd_show_options_entry = { "[-gqsvw] [-t target-session|target-window] [option]", 0, NULL, - NULL, cmd_show_options_exec }; @@ -50,7 +49,6 @@ const struct cmd_entry cmd_show_window_options_entry = { "[-gv] " CMD_TARGET_WINDOW_USAGE " [option]", 0, NULL, - NULL, cmd_show_options_exec }; diff --git a/cmd-source-file.c b/cmd-source-file.c index 45a3a39b..eb7e1490 100644 --- a/cmd-source-file.c +++ b/cmd-source-file.c @@ -37,7 +37,6 @@ const struct cmd_entry cmd_source_file_entry = { "path", 0, NULL, - NULL, cmd_source_file_exec }; @@ -96,6 +95,9 @@ cmd_source_file_done(struct cmd_q *cmdq1) { struct cmd_q *cmdq = cmdq1->data; + if (cmdq1->client_exit >= 0) + cmdq->client_exit = cmdq1->client_exit; + cmdq_free(cmdq1); cfg_references--; diff --git a/cmd-split-window.c b/cmd-split-window.c index 601dcb17..506c8033 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -18,7 +18,11 @@ #include +#include +#include +#include #include +#include #include #include "tmux.h" @@ -37,7 +41,6 @@ const struct cmd_entry cmd_split_window_entry = { CMD_TARGET_PANE_USAGE " [command]", 0, cmd_split_window_key_binding, - NULL, cmd_split_window_exec }; @@ -58,16 +61,14 @@ cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq) struct window *w; struct window_pane *wp, *new_wp = NULL; struct environ env; - const char *cmd, *cwd, *shell; - char *cause, *new_cause; + const char *cmd, *shell, *template; + char *cause, *new_cause, *cp; u_int hlimit; - int size, percentage; + int size, percentage, cwd, fd = -1; enum layout_type type; struct layout_cell *lc; - const char *template; struct client *c; struct format_tree *ft; - char *cp; if ((wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp)) == NULL) return (CMD_RETURN_ERROR); @@ -83,7 +84,29 @@ cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq) cmd = options_get_string(&s->options, "default-command"); else cmd = args->argv[0]; - cwd = cmd_get_default_path(cmdq, args_get(args, 'c')); + + if (args_has(args, 'c')) { + ft = format_create(); + if ((c = cmd_find_client(cmdq, NULL, 1)) != NULL) + format_client(ft, c); + format_session(ft, s); + format_winlink(ft, s, s->curw); + format_window_pane(ft, s->curw->window->active); + cp = format_expand(ft, args_get(args, 'c')); + format_free(ft); + + fd = open(cp, O_RDONLY|O_DIRECTORY); + free(cp); + if (fd == -1) { + cmdq_error(cmdq, "bad working directory: %s", + strerror(errno)); + return (CMD_RETURN_ERROR); + } + cwd = fd; + } else if (cmdq->client != NULL && cmdq->client->session == NULL) + cwd = cmdq->client->cwd; + else + cwd = s->cwd; type = LAYOUT_TOPBOTTOM; if (args_has(args, 'h')) @@ -156,6 +179,9 @@ cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq) format_free(ft); } notify_window_layout_changed(w); + + if (fd != -1) + close(fd); return (CMD_RETURN_NORMAL); error: @@ -164,5 +190,7 @@ error: window_remove_pane(w, new_wp); cmdq_error(cmdq, "create pane failed: %s", cause); free(cause); + if (fd != -1) + close(fd); return (CMD_RETURN_ERROR); } diff --git a/cmd-start-server.c b/cmd-start-server.c index cba2403b..33b28b4a 100644 --- a/cmd-start-server.c +++ b/cmd-start-server.c @@ -32,7 +32,6 @@ const struct cmd_entry cmd_start_server_entry = { "", CMD_STARTSERVER, NULL, - NULL, cmd_start_server_exec }; diff --git a/cmd-string.c b/cmd-string.c index 7e84eda6..e793ea02 100644 --- a/cmd-string.c +++ b/cmd-string.c @@ -318,10 +318,13 @@ cmd_string_expand_tilde(const char *s, size_t *p) { struct passwd *pw; struct environ_entry *envent; - char *home, *path, *username; + char *home, *path, *user, *cp; + int last; home = NULL; - if (cmd_string_getc(s, p) == '/') { + + last = cmd_string_getc(s, p); + if (last == EOF || last == '/' || last == ' '|| last == '\t') { envent = environ_find(&global_environ, "HOME"); if (envent != NULL && *envent->value != '\0') home = envent->value; @@ -329,15 +332,27 @@ cmd_string_expand_tilde(const char *s, size_t *p) home = pw->pw_dir; } else { cmd_string_ungetc(p); - if ((username = cmd_string_string(s, p, '/', 0)) == NULL) - return (NULL); - if ((pw = getpwnam(username)) != NULL) + + cp = user = xmalloc(strlen(s)); + for (;;) { + last = cmd_string_getc(s, p); + if (last == EOF || last == '/' || last == ' '|| last == '\t') + break; + *cp++ = last; + } + *cp = '\0'; + + if ((pw = getpwnam(user)) != NULL) home = pw->pw_dir; - free(username); + free(user); } + if (home == NULL) return (NULL); - xasprintf(&path, "%s/", home); + if (last != EOF) + xasprintf(&path, "%s%c", home, last); + else + xasprintf(&path, "%s", home); return (path); } diff --git a/cmd-suspend-client.c b/cmd-suspend-client.c index 101658b1..e0e375fc 100644 --- a/cmd-suspend-client.c +++ b/cmd-suspend-client.c @@ -35,7 +35,6 @@ const struct cmd_entry cmd_suspend_client_entry = { CMD_TARGET_CLIENT_USAGE, 0, NULL, - NULL, cmd_suspend_client_exec }; diff --git a/cmd-swap-pane.c b/cmd-swap-pane.c index 05317260..b8ff7690 100644 --- a/cmd-swap-pane.c +++ b/cmd-swap-pane.c @@ -35,7 +35,6 @@ const struct cmd_entry cmd_swap_pane_entry = { "[-dDU] " CMD_SRCDST_PANE_USAGE, 0, cmd_swap_pane_key_binding, - NULL, cmd_swap_pane_exec }; diff --git a/cmd-swap-window.c b/cmd-swap-window.c index f9a2cb1b..1591d403 100644 --- a/cmd-swap-window.c +++ b/cmd-swap-window.c @@ -34,7 +34,6 @@ const struct cmd_entry cmd_swap_window_entry = { "[-d] " CMD_SRCDST_WINDOW_USAGE, 0, NULL, - NULL, cmd_swap_window_exec }; diff --git a/cmd-switch-client.c b/cmd-switch-client.c index 9adb2146..d101c52b 100644 --- a/cmd-switch-client.c +++ b/cmd-switch-client.c @@ -36,7 +36,6 @@ const struct cmd_entry cmd_switch_client_entry = { "[-lnpr] [-c target-client] [-t target-session]", CMD_READONLY, cmd_switch_client_key_binding, - NULL, cmd_switch_client_exec }; diff --git a/cmd-unbind-key.c b/cmd-unbind-key.c index dc037dde..cf6ad506 100644 --- a/cmd-unbind-key.c +++ b/cmd-unbind-key.c @@ -26,7 +26,6 @@ * Unbind key from command. */ -enum cmd_retval cmd_unbind_key_check(struct args *); enum cmd_retval cmd_unbind_key_exec(struct cmd *, struct cmd_q *); enum cmd_retval cmd_unbind_key_table(struct cmd *, struct cmd_q *, int); @@ -36,20 +35,9 @@ const struct cmd_entry cmd_unbind_key_entry = { "[-acn] [-t key-table] key", 0, NULL, - cmd_unbind_key_check, cmd_unbind_key_exec }; -enum cmd_retval -cmd_unbind_key_check(struct args *args) -{ - if (args_has(args, 'a') && args->argc != 0) - return (CMD_RETURN_ERROR); - if (!args_has(args, 'a') && args->argc != 1) - return (CMD_RETURN_ERROR); - return (CMD_RETURN_NORMAL); -} - enum cmd_retval cmd_unbind_key_exec(struct cmd *self, struct cmd_q *cmdq) { @@ -58,13 +46,22 @@ cmd_unbind_key_exec(struct cmd *self, struct cmd_q *cmdq) int key; if (!args_has(args, 'a')) { + if (args->argc != 1) { + cmdq_error(cmdq, "missing key"); + return (CMD_RETURN_ERROR); + } key = key_string_lookup_string(args->argv[0]); if (key == KEYC_NONE) { cmdq_error(cmdq, "unknown key: %s", args->argv[0]); return (CMD_RETURN_ERROR); } - } else + } else { + if (args->argc != 0) { + cmdq_error(cmdq, "key given with -a"); + return (CMD_RETURN_ERROR); + } key = KEYC_NONE; + } if (args_has(args, 't')) return (cmd_unbind_key_table(self, cmdq, key)); diff --git a/cmd-unlink-window.c b/cmd-unlink-window.c index 39cdd8ed..ec69b91f 100644 --- a/cmd-unlink-window.c +++ b/cmd-unlink-window.c @@ -32,7 +32,6 @@ const struct cmd_entry cmd_unlink_window_entry = { "[-k] " CMD_TARGET_WINDOW_USAGE, 0, NULL, - NULL, cmd_unlink_window_exec }; diff --git a/cmd-wait-for.c b/cmd-wait-for.c index d40ba49e..e251863d 100644 --- a/cmd-wait-for.c +++ b/cmd-wait-for.c @@ -33,10 +33,9 @@ enum cmd_retval cmd_wait_for_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_wait_for_entry = { "wait-for", "wait", "LSU", 1, 1, - "[-LSU] channel", + "[-L|-S|-U] channel", 0, NULL, - NULL, cmd_wait_for_exec }; diff --git a/cmd.c b/cmd.c index 282fb112..414c9067 100644 --- a/cmd.c +++ b/cmd.c @@ -254,8 +254,6 @@ cmd_parse(int argc, char **argv, const char *file, u_int line, char **cause) goto usage; if (entry->args_upper != -1 && args->argc > entry->args_upper) goto usage; - if (entry->check != NULL && entry->check(args) != 0) - goto usage; cmd = xcalloc(1, sizeof *cmd); cmd->entry = entry; @@ -315,7 +313,6 @@ cmd_print(struct cmd *cmd, char *buf, size_t len) struct session * cmd_current_session(struct cmd_q *cmdq, int prefer_unattached) { - struct msg_command_data *data = cmdq->msgdata; struct client *c = cmdq->client; struct session *s; struct sessionslist ss; @@ -357,13 +354,6 @@ cmd_current_session(struct cmd_q *cmdq, int prefer_unattached) return (s); } - /* Use the session from the TMUX environment variable. */ - if (data != NULL && data->pid == getpid() && data->session_id != -1) { - s = session_find_by_id(data->session_id); - if (s != NULL) - return (s); - } - return (cmd_choose_session(prefer_unattached)); } @@ -1278,87 +1268,3 @@ cmd_template_replace(const char *template, const char *s, int idx) return (buf); } - -/* - * Return the default path for a new pane, using the given path or the - * default-path option if it is NULL. Several special values are accepted: the - * empty string or relative path for the current pane's working directory, ~ - * for the user's home, - for the session working directory, . for the tmux - * server's working directory. The default on failure is the session's working - * directory. - */ -const char * -cmd_get_default_path(struct cmd_q *cmdq, const char *cwd) -{ - struct client *c = cmdq->client; - struct session *s; - struct environ_entry *envent; - const char *root; - char tmp[MAXPATHLEN]; - struct passwd *pw; - int n; - size_t skip; - static char path[MAXPATHLEN]; - - if ((s = cmd_current_session(cmdq, 0)) == NULL) - return (NULL); - - if (cwd == NULL) - cwd = options_get_string(&s->options, "default-path"); - - skip = 1; - if (strcmp(cwd, "$HOME") == 0 || strncmp(cwd, "$HOME/", 6) == 0) { - /* User's home directory - $HOME. */ - skip = 5; - goto find_home; - } else if (cwd[0] == '~' && (cwd[1] == '\0' || cwd[1] == '/')) { - /* User's home directory - ~. */ - goto find_home; - } else if (cwd[0] == '-' && (cwd[1] == '\0' || cwd[1] == '/')) { - /* Session working directory. */ - root = s->cwd; - goto complete_path; - } else if (cwd[0] == '.' && (cwd[1] == '\0' || cwd[1] == '/')) { - /* Server working directory. */ - if (getcwd(tmp, sizeof tmp) != NULL) { - root = tmp; - goto complete_path; - } - return (s->cwd); - } else if (*cwd == '/') { - /* Absolute path. */ - return (cwd); - } else { - /* Empty or relative path. */ - if (c != NULL && c->session == NULL && c->cwd != NULL) - root = c->cwd; - else if (s->curw != NULL) - root = osdep_get_cwd(s->curw->window->active->fd); - else - return (s->cwd); - skip = 0; - if (root != NULL) - goto complete_path; - } - - return (s->cwd); - -find_home: - envent = environ_find(&global_environ, "HOME"); - if (envent != NULL && *envent->value != '\0') - root = envent->value; - else if ((pw = getpwuid(getuid())) != NULL) - root = pw->pw_dir; - else - return (s->cwd); - -complete_path: - if (root[skip] == '\0') { - strlcpy(path, root, sizeof path); - return (path); - } - n = snprintf(path, sizeof path, "%s/%s", root, cwd + skip); - if (n > 0 && (size_t)n < sizeof path) - return (path); - return (s->cwd); -} diff --git a/control.c b/control.c index aa79085a..52fdb524 100644 --- a/control.c +++ b/control.c @@ -73,9 +73,9 @@ control_callback(struct client *c, int closed, unused void *data) c->cmdq->time = time(NULL); c->cmdq->number++; - cmdq_guard(c->cmdq, "begin"); + cmdq_guard(c->cmdq, "begin", 1); control_write(c, "parse error: %s", cause); - cmdq_guard(c->cmdq, "error"); + cmdq_guard(c->cmdq, "error", 1); free(cause); } else { diff --git a/format.c b/format.c index 8c4c7842..d8d34fe7 100644 --- a/format.c +++ b/format.c @@ -18,6 +18,8 @@ #include +#include +#include #include #include #include @@ -32,9 +34,10 @@ * string. */ -int format_replace(struct format_tree *, const char *, size_t, char **, - size_t *, size_t *); -void format_window_pane_tabs(struct format_tree *, struct window_pane *); +int format_replace(struct format_tree *, const char *, size_t, char **, + size_t *, size_t *); +char *format_get_command(struct window_pane *); +void format_window_pane_tabs(struct format_tree *, struct window_pane *); /* Format key-value replacement entry. */ RB_GENERATE(format_tree, format_entry, entry, format_cmp); @@ -118,7 +121,7 @@ format_create(void) if (gethostname(host, sizeof host) == 0) { format_add(ft, "host", "%s", host); - if ((ptr = strrchr(host, '.')) != NULL) + if ((ptr = strchr(host, '.')) != NULL) *ptr = '\0'; format_add(ft, "host_short", "%s", host); } @@ -151,6 +154,7 @@ void format_add(struct format_tree *ft, const char *key, const char *fmt, ...) { struct format_entry *fe; + struct format_entry *fe_now; va_list ap; fe = xmalloc(sizeof *fe); @@ -160,7 +164,13 @@ format_add(struct format_tree *ft, const char *key, const char *fmt, ...) xvasprintf(&fe->value, fmt, ap); va_end(ap); - RB_INSERT(format_tree, ft, fe); + fe_now = RB_INSERT(format_tree, ft, fe); + if (fe_now != NULL) { + free(fe_now->value); + fe_now->value = fe->value; + free(fe->key); + free(fe); + } } /* Find a format entry. */ @@ -181,18 +191,40 @@ format_find(struct format_tree *ft, const char *key) * #{?blah,a,b} is replace with a if blah exists and is nonzero else b. */ int -format_replace(struct format_tree *ft, - const char *key, size_t keylen, char **buf, size_t *len, size_t *off) +format_replace(struct format_tree *ft, const char *key, size_t keylen, + char **buf, size_t *len, size_t *off) { - char *copy, *ptr; + char *copy, *copy0, *endptr, *ptr, *saved; const char *value; size_t valuelen; + u_long limit = ULONG_MAX; /* Make a copy of the key. */ - copy = xmalloc(keylen + 1); + copy0 = copy = xmalloc(keylen + 1); memcpy(copy, key, keylen); copy[keylen] = '\0'; + /* Is there a length limit or whatnot? */ + if (!islower((u_char) *copy) && *copy != '?') { + while (*copy != ':' && *copy != '\0') { + switch (*copy) { + case '=': + errno = 0; + limit = strtoul(copy + 1, &endptr, 10); + if (errno == ERANGE && limit == ULONG_MAX) + goto fail; + copy = endptr; + break; + default: + copy++; + break; + } + } + if (*copy != ':') + goto fail; + copy++; + } + /* * Is this a conditional? If so, check it exists and extract either the * first or second element. If not, look up the key directly. @@ -216,13 +248,20 @@ format_replace(struct format_tree *ft, goto fail; value = ptr + 1; } + saved = format_expand(ft, value); + value = saved; } else { value = format_find(ft, copy); if (value == NULL) value = ""; + saved = NULL; } valuelen = strlen(value); + /* Truncate the value if needed. */ + if (valuelen > limit) + valuelen = limit; + /* Expand the buffer and copy in the value. */ while (*len - *off < valuelen + 1) { *buf = xrealloc(*buf, 2, *len); @@ -231,11 +270,12 @@ format_replace(struct format_tree *ft, memcpy(*buf + *off, value, valuelen); *off += valuelen; - free(copy); + free(saved); + free(copy0); return (0); fail: - free(copy); + free(copy0); return (-1); } @@ -243,10 +283,10 @@ fail: char * format_expand(struct format_tree *ft, const char *fmt) { - char *buf, *ptr; - const char *s; + char *buf; + const char *ptr, *s; size_t off, len, n; - int ch; + int ch, brackets; len = 64; buf = xmalloc(len); @@ -264,11 +304,16 @@ format_expand(struct format_tree *ft, const char *fmt) fmt++; ch = (u_char) *fmt++; - switch (ch) { case '{': - ptr = strchr(fmt, '}'); - if (ptr == NULL) + brackets = 1; + for (ptr = fmt; *ptr != '\0'; ptr++) { + if (*ptr == '{') + brackets++; + if (*ptr == '}' && --brackets == 0) + break; + } + if (*ptr != '}' || brackets != 0) break; n = ptr - fmt; @@ -304,6 +349,26 @@ format_expand(struct format_tree *ft, const char *fmt) return (buf); } +/* Get command name for format. */ +char * +format_get_command(struct window_pane *wp) +{ + char *cmd, *out; + + cmd = get_proc_name(wp->fd, wp->tty); + if (cmd == NULL || *cmd == '\0') { + free(cmd); + cmd = xstrdup(wp->cmd); + if (cmd == NULL || *cmd == '\0') { + free(cmd); + cmd = xstrdup(wp->shell); + } + } + out = parse_window_name(cmd); + free(cmd); + return (out); +} + /* Set default format keys for a session. */ void format_session(struct format_tree *ft, struct session *s) @@ -343,11 +408,12 @@ format_client(struct format_tree *ft, struct client *c) time_t t; struct session *s; - format_add(ft, "client_cwd", "%s", c->cwd); format_add(ft, "client_height", "%u", c->tty.sy); format_add(ft, "client_width", "%u", c->tty.sx); - format_add(ft, "client_tty", "%s", c->tty.path); - format_add(ft, "client_termname", "%s", c->tty.termname); + if (c->tty.path != NULL) + format_add(ft, "client_tty", "%s", c->tty.path); + if (c->tty.termname != NULL) + format_add(ft, "client_termname", "%s", c->tty.termname); t = c->creation_time.tv_sec; format_add(ft, "client_created", "%lld", (long long) t); @@ -381,28 +447,50 @@ format_client(struct format_tree *ft, struct client *c) format_add(ft, "client_last_session", "%s", s->name); } +/* Set default format keys for a window. */ +void +format_window(struct format_tree *ft, struct window *w) +{ + char *layout; + + layout = layout_dump(w); + + format_add(ft, "window_id", "@%u", w->id); + format_add(ft, "window_name", "%s", w->name); + format_add(ft, "window_width", "%u", w->sx); + format_add(ft, "window_height", "%u", w->sy); + format_add(ft, "window_layout", "%s", layout); + format_add(ft, "window_panes", "%u", window_count_panes(w)); + + free(layout); +} + /* Set default format keys for a winlink. */ void format_winlink(struct format_tree *ft, struct session *s, struct winlink *wl) { struct window *w = wl->window; - char *layout, *flags; + char *flags; - layout = layout_dump(w); flags = window_printable_flags(s, wl); - format_add(ft, "window_id", "@%u", w->id); + format_window(ft, w); + format_add(ft, "window_index", "%d", wl->idx); - format_add(ft, "window_name", "%s", w->name); - format_add(ft, "window_width", "%u", w->sx); - format_add(ft, "window_height", "%u", w->sy); format_add(ft, "window_flags", "%s", flags); - format_add(ft, "window_layout", "%s", layout); format_add(ft, "window_active", "%d", wl == s->curw); - format_add(ft, "window_panes", "%u", window_count_panes(w)); + + format_add(ft, "window_bell_flag", "%u", + !!(wl->flags & WINLINK_BELL)); + format_add(ft, "window_content_flag", "%u", + !!(wl->flags & WINLINK_CONTENT)); + format_add(ft, "window_activity_flag", "%u", + !!(wl->flags & WINLINK_ACTIVITY)); + format_add(ft, "window_silence_flag", "%u", + !!(wl->flags & WINLINK_SILENCE)); + free(flags); - free(layout); } /* Add window pane tabs. */ @@ -435,7 +523,6 @@ format_window_pane(struct format_tree *ft, struct window_pane *wp) struct grid_line *gl; unsigned long long size; u_int i, idx; - const char *cwd; char *cmd; size = 0; @@ -468,11 +555,7 @@ format_window_pane(struct format_tree *ft, struct window_pane *wp) format_add(ft, "pane_pid", "%ld", (long) wp->pid); if (wp->cmd != NULL) format_add(ft, "pane_start_command", "%s", wp->cmd); - if (wp->cwd != NULL) - format_add(ft, "pane_start_path", "%s", wp->cwd); - if ((cwd = osdep_get_cwd(wp->fd)) != NULL) - format_add(ft, "pane_current_path", "%s", cwd); - if ((cmd = osdep_get_name(wp->fd, wp->tty)) != NULL) { + if ((cmd = format_get_command(wp)) != NULL) { format_add(ft, "pane_current_command", "%s", cmd); free(cmd); } diff --git a/grid.c b/grid.c index 2955e8ba..9e800243 100644 --- a/grid.c +++ b/grid.c @@ -268,8 +268,7 @@ grid_get_cell(struct grid *gd, u_int px, u_int py) /* Set cell at relative position. */ void -grid_set_cell( - struct grid *gd, u_int px, u_int py, const struct grid_cell *gc) +grid_set_cell(struct grid *gd, u_int px, u_int py, const struct grid_cell *gc) { if (grid_check_y(gd, py) != 0) return; @@ -592,6 +591,7 @@ grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx, char *buf, code[128]; size_t len, off, size, codelen; u_int xx; + const struct grid_line *gl; GRID_DEBUG(gd, "px=%u, py=%u, nx=%u", px, py, nx); @@ -604,8 +604,11 @@ grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx, buf = xmalloc(len); off = 0; + gl = grid_peek_line(gd, py); for (xx = px; xx < px + nx; xx++) { - gc = grid_peek_cell(gd, xx, py); + if (gl == NULL || xx >= gl->cellsize) + break; + gc = &gl->celldata[xx]; if (gc->flags & GRID_FLAG_PADDING) continue; grid_cell_get(gc, &ud); @@ -653,8 +656,8 @@ grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx, * available. */ void -grid_duplicate_lines( - struct grid *dst, u_int dy, struct grid *src, u_int sy, u_int ny) +grid_duplicate_lines(struct grid *dst, u_int dy, struct grid *src, u_int sy, + u_int ny) { struct grid_line *dstl, *srcl; u_int yy; diff --git a/input.c b/input.c index 30d3bb98..259fad16 100644 --- a/input.c +++ b/input.c @@ -70,6 +70,10 @@ int input_input(struct input_ctx *); int input_c0_dispatch(struct input_ctx *); int input_esc_dispatch(struct input_ctx *); int input_csi_dispatch(struct input_ctx *); +void input_csi_dispatch_rm(struct input_ctx *); +void input_csi_dispatch_rm_private(struct input_ctx *); +void input_csi_dispatch_sm(struct input_ctx *); +void input_csi_dispatch_sm_private(struct input_ctx *); void input_csi_dispatch_sgr(struct input_ctx *); int input_dcs_dispatch(struct input_ctx *); int input_utf8_open(struct input_ctx *); @@ -1071,7 +1075,6 @@ int input_csi_dispatch(struct input_ctx *ictx) { struct screen_write_ctx *sctx = &ictx->ctx; - struct window_pane *wp = ictx->wp; struct screen *s = sctx->s; struct input_table_entry *entry; int n, m; @@ -1230,7 +1233,60 @@ input_csi_dispatch(struct input_ctx *ictx) screen_write_cursormove(sctx, ictx->old_cx, ictx->old_cy); break; case INPUT_CSI_RM: - switch (input_get(ictx, 0, 0, -1)) { + input_csi_dispatch_rm(ictx); + break; + case INPUT_CSI_RM_PRIVATE: + input_csi_dispatch_rm_private(ictx); + break; + case INPUT_CSI_SCP: + memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell); + ictx->old_cx = s->cx; + ictx->old_cy = s->cy; + break; + case INPUT_CSI_SGR: + input_csi_dispatch_sgr(ictx); + break; + case INPUT_CSI_SM: + input_csi_dispatch_sm(ictx); + break; + case INPUT_CSI_SM_PRIVATE: + input_csi_dispatch_sm_private(ictx); + break; + case INPUT_CSI_TBC: + switch (input_get(ictx, 0, 0, 0)) { + case 0: + if (s->cx < screen_size_x(s)) + bit_clear(s->tabs, s->cx); + break; + case 3: + bit_nclear(s->tabs, 0, screen_size_x(s) - 1); + break; + default: + log_debug("%s: unknown '%c'", __func__, ictx->ch); + break; + } + break; + case INPUT_CSI_VPA: + n = input_get(ictx, 0, 1, 1); + screen_write_cursormove(sctx, s->cx, n - 1); + break; + case INPUT_CSI_DECSCUSR: + n = input_get(ictx, 0, 0, 0); + screen_set_cursor_style(s, n); + break; + } + + return (0); +} + +/* Handle CSI RM. */ +void +input_csi_dispatch_rm(struct input_ctx *ictx) +{ + u_int i; + + for (i = 0; i < ictx->param_list_len; i++) { + switch (input_get(ictx, i, 0, -1)) { case 4: /* IRM */ screen_write_mode_clear(&ictx->ctx, MODE_INSERT); break; @@ -1238,10 +1294,18 @@ input_csi_dispatch(struct input_ctx *ictx) log_debug("%s: unknown '%c'", __func__, ictx->ch); break; } - break; - case INPUT_CSI_RM_PRIVATE: - switch (input_get(ictx, 0, 0, -1)) { - case 1: /* GATM */ + } +} + +/* Handle CSI private RM. */ +void +input_csi_dispatch_rm_private(struct input_ctx *ictx) +{ + u_int i; + + for (i = 0; i < ictx->param_list_len; i++) { + switch (input_get(ictx, i, 0, -1)) { + case 1: /* DECCKM */ screen_write_mode_clear(&ictx->ctx, MODE_KCURSOR); break; case 3: /* DECCOLM */ @@ -1271,10 +1335,10 @@ input_csi_dispatch(struct input_ctx *ictx) break; case 47: case 1047: - window_pane_alternate_off(wp, &ictx->cell, 0); + window_pane_alternate_off(ictx->wp, &ictx->cell, 0); break; case 1049: - window_pane_alternate_off(wp, &ictx->cell, 1); + window_pane_alternate_off(ictx->wp, &ictx->cell, 1); break; case 2004: screen_write_mode_clear(&ictx->ctx, MODE_BRACKETPASTE); @@ -1283,17 +1347,17 @@ input_csi_dispatch(struct input_ctx *ictx) log_debug("%s: unknown '%c'", __func__, ictx->ch); break; } - break; - case INPUT_CSI_SCP: - memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell); - ictx->old_cx = s->cx; - ictx->old_cy = s->cy; - break; - case INPUT_CSI_SGR: - input_csi_dispatch_sgr(ictx); - break; - case INPUT_CSI_SM: - switch (input_get(ictx, 0, 0, -1)) { + } +} + +/* Handle CSI SM. */ +void +input_csi_dispatch_sm(struct input_ctx *ictx) +{ + u_int i; + + for (i = 0; i < ictx->param_list_len; i++) { + switch (input_get(ictx, i, 0, -1)) { case 4: /* IRM */ screen_write_mode_set(&ictx->ctx, MODE_INSERT); break; @@ -1301,10 +1365,18 @@ input_csi_dispatch(struct input_ctx *ictx) log_debug("%s: unknown '%c'", __func__, ictx->ch); break; } - break; - case INPUT_CSI_SM_PRIVATE: - switch (input_get(ictx, 0, 0, -1)) { - case 1: /* GATM */ + } +} + +/* Handle CSI private SM. */ +void +input_csi_dispatch_sm_private(struct input_ctx *ictx) +{ + u_int i; + + for (i = 0; i < ictx->param_list_len; i++) { + switch (input_get(ictx, i, 0, -1)) { + case 1: /* DECCKM */ screen_write_mode_set(&ictx->ctx, MODE_KCURSOR); break; case 3: /* DECCOLM */ @@ -1330,10 +1402,10 @@ input_csi_dispatch(struct input_ctx *ictx) screen_write_mode_set(&ictx->ctx, MODE_MOUSE_ANY); break; case 1004: - if (s->mode & MODE_FOCUSON) + if (ictx->ctx.s->mode & MODE_FOCUSON) break; screen_write_mode_set(&ictx->ctx, MODE_FOCUSON); - wp->flags |= PANE_FOCUSPUSH; /* force update */ + ictx->wp->flags |= PANE_FOCUSPUSH; /* force update */ break; case 1005: screen_write_mode_set(&ictx->ctx, MODE_MOUSE_UTF8); @@ -1343,10 +1415,10 @@ input_csi_dispatch(struct input_ctx *ictx) break; case 47: case 1047: - window_pane_alternate_on(wp, &ictx->cell, 0); + window_pane_alternate_on(ictx->wp, &ictx->cell, 0); break; case 1049: - window_pane_alternate_on(wp, &ictx->cell, 1); + window_pane_alternate_on(ictx->wp, &ictx->cell, 1); break; case 2004: screen_write_mode_set(&ictx->ctx, MODE_BRACKETPASTE); @@ -1355,32 +1427,7 @@ input_csi_dispatch(struct input_ctx *ictx) log_debug("%s: unknown '%c'", __func__, ictx->ch); break; } - break; - case INPUT_CSI_TBC: - switch (input_get(ictx, 0, 0, 0)) { - case 0: - if (s->cx < screen_size_x(s)) - bit_clear(s->tabs, s->cx); - break; - case 3: - bit_nclear(s->tabs, 0, screen_size_x(s) - 1); - break; - default: - log_debug("%s: unknown '%c'", __func__, ictx->ch); - break; - } - break; - case INPUT_CSI_VPA: - n = input_get(ictx, 0, 1, 1); - screen_write_cursormove(sctx, s->cx, n - 1); - break; - case INPUT_CSI_DECSCUSR: - n = input_get(ictx, 0, 0, 0); - screen_set_cursor_style(s, n); - break; } - - return (0); } /* Handle CSI SGR. */ diff --git a/job.c b/job.c index b2c2251c..d7bd852b 100644 --- a/job.c +++ b/job.c @@ -144,7 +144,7 @@ job_write_callback(unused struct bufferevent *bufev, void *data) size_t len = EVBUFFER_LENGTH(EVBUFFER_OUTPUT(job->event)); log_debug("job write %p: %s, pid %ld, output left %zu", job, job->cmd, - (long) job->pid, len); + (long) job->pid, len); if (len == 0) { shutdown(job->fd, SHUT_WR); diff --git a/layout.c b/layout.c index b74bd789..646d1bd9 100644 --- a/layout.c +++ b/layout.c @@ -533,6 +533,9 @@ layout_resize_pane_mouse(struct client *c) pane_border = 0; if (m->event & MOUSE_EVENT_DRAG && m->flags & MOUSE_RESIZE_PANE) { TAILQ_FOREACH(wp, &w->panes, entry) { + if (!window_pane_visible(wp)) + continue; + if (wp->xoff + wp->sx == m->lx && wp->yoff <= 1 + m->ly && wp->yoff + wp->sy >= m->ly) { @@ -550,7 +553,7 @@ layout_resize_pane_mouse(struct client *c) } if (pane_border) server_redraw_window(w); - } else if (~m->event & MOUSE_EVENT_UP) { + } else if (m->event & MOUSE_EVENT_DOWN) { TAILQ_FOREACH(wp, &w->panes, entry) { if ((wp->xoff + wp->sx == m->x && wp->yoff <= 1 + m->y && diff --git a/names.c b/names.c index f536d2fc..7c02961c 100644 --- a/names.c +++ b/names.c @@ -22,12 +22,10 @@ #include #include #include -#include #include "tmux.h" void window_name_callback(unused int, unused short, void *); -char *parse_window_name(const char *); void queue_window_name(struct window *w) @@ -47,7 +45,7 @@ void window_name_callback(unused int fd, unused short events, void *data) { struct window *w = data; - char *name, *wname; + char *name; if (w->active == NULL) return; @@ -59,49 +57,39 @@ window_name_callback(unused int fd, unused short events, void *data) } queue_window_name(w); - if (w->active->screen != &w->active->base) - name = NULL; - else - name = osdep_get_name(w->active->fd, w->active->tty); - if (name == NULL) - wname = default_window_name(w); - else { - /* - * If tmux is using the default command, it will be a login - * shell and argv[0] may have a - prefix. Remove this if it is - * present. Ick. - */ - if (w->active->cmd != NULL && *w->active->cmd == '\0' && - name != NULL && name[0] == '-' && name[1] != '\0') - wname = parse_window_name(name + 1); - else - wname = parse_window_name(name); - free(name); - } - - if (w->active->fd == -1) { - xasprintf(&name, "%s[dead]", wname); - free(wname); - wname = name; - } - - if (strcmp(wname, w->name)) { - window_set_name(w, wname); + name = format_window_name(w); + if (strcmp(name, w->name) != 0) { + window_set_name(w, name); server_status_window(w); } - free(wname); + free(name); } char * default_window_name(struct window *w) { - if (w->active->screen != &w->active->base) - return (xstrdup("[tmux]")); if (w->active->cmd != NULL && *w->active->cmd != '\0') return (parse_window_name(w->active->cmd)); return (parse_window_name(w->active->shell)); } +char * +format_window_name(struct window *w) +{ + struct format_tree *ft; + char *fmt, *name; + + ft = format_create(); + format_window(ft, w); + format_window_pane(ft, w->active); + + fmt = options_get_string(&w->options, "automatic-rename-format"); + name = format_expand(ft, fmt); + + format_free(ft); + return (name); +} + char * parse_window_name(const char *in) { @@ -111,7 +99,7 @@ parse_window_name(const char *in) if (strncmp(name, "exec ", (sizeof "exec ") - 1) == 0) name = name + (sizeof "exec ") - 1; - while (*name == ' ') + while (*name == ' ' || *name == '-') name++; if ((ptr = strchr(name, ' ')) != NULL) *ptr = '\0'; diff --git a/options-table.c b/options-table.c index 2281d652..5da095b1 100644 --- a/options-table.c +++ b/options-table.c @@ -125,11 +125,6 @@ const struct options_table_entry session_options_table[] = { .default_str = "" }, - { .name = "default-path", - .type = OPTIONS_TABLE_STRING, - .default_str = "" - }, - { .name = "default-shell", .type = OPTIONS_TABLE_STRING, .default_str = _PATH_BSHELL @@ -386,7 +381,7 @@ const struct options_table_entry session_options_table[] = { { .name = "status-right", .type = OPTIONS_TABLE_STRING, - .default_str = "\"#22T\" %H:%M %d-%b-%y" + .default_str = "\"#{=22:pane_title}\" %H:%M %d-%b-%y" }, { .name = "status-right-attr", @@ -481,6 +476,11 @@ const struct options_table_entry window_options_table[] = { .default_num = 1 }, + { .name = "automatic-rename-format", + .type = OPTIONS_TABLE_STRING, + .default_str = "#{?pane_in_mode,[tmux],#{pane_current_command}}#{?pane_dead,[dead],}" + }, + { .name = "c0-change-trigger", .type = OPTIONS_TABLE_NUMBER, .default_num = 250, diff --git a/osdep-openbsd.c b/osdep-openbsd.c index 7be38a91..c61d90e7 100644 --- a/osdep-openbsd.c +++ b/osdep-openbsd.c @@ -37,9 +37,7 @@ ((p)->p_stat == SSTOP || (p)->p_stat == SZOMB || (p)->p_stat == SDEAD) struct kinfo_proc *cmp_procs(struct kinfo_proc *, struct kinfo_proc *); -char *osdep_get_name(int, char *); -char *osdep_get_cwd(int); -struct event_base *osdep_event_init(void); +char *get_proc_name(int, char *); struct kinfo_proc * cmp_procs(struct kinfo_proc *p1, struct kinfo_proc *p2) @@ -134,23 +132,3 @@ error: free(buf); return (NULL); } - -char* -osdep_get_cwd(int fd) -{ - int name[] = { CTL_KERN, KERN_PROC_CWD, 0 }; - static char path[MAXPATHLEN]; - size_t pathlen = sizeof path; - - if ((name[2] = tcgetpgrp(fd)) == -1) - return (NULL); - if (sysctl(name, 3, path, &pathlen, NULL, 0) != 0) - return (NULL); - return (path); -} - -struct event_base * -osdep_event_init(void) -{ - return (event_init()); -} diff --git a/resize.c b/resize.c index 5c365dfe..8d0bd275 100644 --- a/resize.c +++ b/resize.c @@ -92,7 +92,7 @@ recalculate_sizes(void) for (i = 0; i < ARRAY_LENGTH(&windows); i++) { w = ARRAY_ITEM(&windows, i); - if (w == NULL) + if (w == NULL || w->active == NULL) continue; flag = options_get_number(&w->options, "aggressive-resize"); diff --git a/server-client.c b/server-client.c index 5923eb0e..cc18a96f 100644 --- a/server-client.c +++ b/server-client.c @@ -40,9 +40,8 @@ void server_client_reset_state(struct client *); int server_client_assume_paste(struct session *); int server_client_msg_dispatch(struct client *); -void server_client_msg_command(struct client *, struct msg_command_data *); -void server_client_msg_identify( - struct client *, struct msg_identify_data *, int); +void server_client_msg_command(struct client *, struct imsg *); +void server_client_msg_identify(struct client *, struct imsg *); void server_client_msg_shell(struct client *); /* Create a new client. */ @@ -63,6 +62,8 @@ server_client_create(int fd) fatal("gettimeofday failed"); memcpy(&c->activity_time, &c->creation_time, sizeof c->activity_time); + environ_init(&c->environ); + c->cmdq = cmdq_new(c); c->cmdq->client_exit = 1; @@ -151,6 +152,8 @@ server_client_lost(struct client *c) */ if (c->flags & CLIENT_TERMINAL) tty_free(&c->tty); + free(c->ttyname); + free(c->term); evbuffer_free (c->stdin_data); evbuffer_free (c->stdout_data); @@ -162,6 +165,7 @@ server_client_lost(struct client *c) screen_free(&c->status); free(c->title); + close(c->cwd); evtimer_del(&c->repeat_timer); @@ -179,7 +183,6 @@ server_client_lost(struct client *c) free(c->prompt_string); free(c->prompt_buffer); - free(c->cwd); c->cmdq->dead = 1; cmdq_free(c->cmdq); @@ -695,8 +698,6 @@ server_client_repeat_timer(unused int fd, unused short events, void *data) void server_client_check_exit(struct client *c) { - struct msg_exit_data exitdata; - if (!(c->flags & CLIENT_EXIT)) return; @@ -707,9 +708,7 @@ server_client_check_exit(struct client *c) if (EVBUFFER_LENGTH(c->stderr_data) != 0) return; - exitdata.retcode = c->retcode; - server_write_client(c, MSG_EXIT, &exitdata, sizeof exitdata); - + server_write_client(c, MSG_EXIT, &c->retval, sizeof c->retval); c->flags &= ~CLIENT_EXIT; } @@ -790,10 +789,8 @@ int server_client_msg_dispatch(struct client *c) { struct imsg imsg; - struct msg_command_data commanddata; - struct msg_identify_data identifydata; - struct msg_environ_data environdata; struct msg_stdin_data stdindata; + const char *data; ssize_t n, datalen; if ((n = imsg_read(&c->ibuf)) == -1 || n == 0) @@ -804,40 +801,37 @@ server_client_msg_dispatch(struct client *c) return (-1); if (n == 0) return (0); + + data = imsg.data; datalen = imsg.hdr.len - IMSG_HEADER_SIZE; if (imsg.hdr.peerid != PROTOCOL_VERSION) { server_write_client(c, MSG_VERSION, NULL, 0); c->flags |= CLIENT_BAD; + if (imsg.fd != -1) + close(imsg.fd); imsg_free(&imsg); continue; } log_debug("got %d from client %d", imsg.hdr.type, c->ibuf.fd); switch (imsg.hdr.type) { - case MSG_COMMAND: - if (datalen != sizeof commanddata) - fatalx("bad MSG_COMMAND size"); - memcpy(&commanddata, imsg.data, sizeof commanddata); - - server_client_msg_command(c, &commanddata); + case MSG_IDENTIFY_FLAGS: + case MSG_IDENTIFY_TERM: + case MSG_IDENTIFY_TTYNAME: + case MSG_IDENTIFY_CWD: + case MSG_IDENTIFY_STDIN: + case MSG_IDENTIFY_ENVIRON: + case MSG_IDENTIFY_DONE: + server_client_msg_identify(c, &imsg); break; - case MSG_IDENTIFY: - if (datalen != sizeof identifydata) - fatalx("bad MSG_IDENTIFY size"); - memcpy(&identifydata, imsg.data, sizeof identifydata); -#ifdef __CYGWIN__ - imsg.fd = open(identifydata.ttyname, O_RDWR|O_NOCTTY); -#endif - if (imsg.fd == -1) - fatalx("MSG_IDENTIFY missing fd"); - - server_client_msg_identify(c, &identifydata, imsg.fd); + case MSG_COMMAND: + server_client_msg_command(c, &imsg); break; case MSG_STDIN: if (datalen != sizeof stdindata) fatalx("bad MSG_STDIN size"); - memcpy(&stdindata, imsg.data, sizeof stdindata); + memcpy(&stdindata, data, sizeof stdindata); if (c->stdin_callback == NULL) break; @@ -887,23 +881,12 @@ server_client_msg_dispatch(struct client *c) server_redraw_client(c); recalculate_sizes(); break; - case MSG_ENVIRON: - if (datalen != sizeof environdata) - fatalx("bad MSG_ENVIRON size"); - memcpy(&environdata, imsg.data, sizeof environdata); - - environdata.var[(sizeof environdata.var) - 1] = '\0'; - if (strchr(environdata.var, '=') != NULL) - environ_put(&c->environ, environdata.var); - break; case MSG_SHELL: if (datalen != 0) fatalx("bad MSG_SHELL size"); server_client_msg_shell(c); break; - default: - fatalx("unexpected message"); } imsg_free(&imsg); @@ -912,15 +895,26 @@ server_client_msg_dispatch(struct client *c) /* Handle command message. */ void -server_client_msg_command(struct client *c, struct msg_command_data *data) +server_client_msg_command(struct client *c, struct imsg *imsg) { - struct cmd_list *cmdlist = NULL; - int argc; - char **argv, *cause; + struct msg_command_data data; + char *buf; + size_t len; + struct cmd_list *cmdlist = NULL; + int argc; + char **argv, *cause; - argc = data->argc; - data->argv[(sizeof data->argv) - 1] = '\0'; - if (cmd_unpack_argv(data->argv, sizeof data->argv, argc, &argv) != 0) { + if (imsg->hdr.len - IMSG_HEADER_SIZE < sizeof data) + fatalx("bad MSG_COMMAND size"); + memcpy(&data, imsg->data, sizeof data); + + buf = (char*)imsg->data + sizeof data; + len = imsg->hdr.len - IMSG_HEADER_SIZE - sizeof data; + if (len > 0 && buf[len - 1] != '\0') + fatalx("bad MSG_COMMAND string"); + + argc = data.argc; + if (cmd_unpack_argv(buf, len, argc, &argv) != 0) { cmdq_error(c->cmdq, "command too long"); goto error; } @@ -951,44 +945,99 @@ error: /* Handle identify message. */ void -server_client_msg_identify( - struct client *c, struct msg_identify_data *data, int fd) +server_client_msg_identify(struct client *c, struct imsg *imsg) { - c->cwd = NULL; - data->cwd[(sizeof data->cwd) - 1] = '\0'; - if (*data->cwd != '\0') - c->cwd = xstrdup(data->cwd); + const char *data; + size_t datalen; + int flags; - if (data->flags & IDENTIFY_CONTROL) { + if (c->flags & CLIENT_IDENTIFIED) + fatalx("out-of-order identify message"); + + data = imsg->data; + datalen = imsg->hdr.len - IMSG_HEADER_SIZE; + + switch (imsg->hdr.type) { + case MSG_IDENTIFY_FLAGS: + if (datalen != sizeof flags) + fatalx("bad MSG_IDENTIFY_FLAGS size"); + memcpy(&flags, data, sizeof flags); + c->flags |= flags; + break; + case MSG_IDENTIFY_TERM: + if (datalen == 0 || data[datalen - 1] != '\0') + fatalx("bad MSG_IDENTIFY_TERM string"); + c->term = xstrdup(data); + break; + case MSG_IDENTIFY_TTYNAME: + if (datalen == 0 || data[datalen - 1] != '\0') + fatalx("bad MSG_IDENTIFY_TTYNAME string"); + c->ttyname = xstrdup(data); + break; + case MSG_IDENTIFY_CWD: + if (datalen != 0) + fatalx("bad MSG_IDENTIFY_CWD size"); + c->cwd = imsg->fd; + break; + case MSG_IDENTIFY_STDIN: + if (datalen != 0) + fatalx("bad MSG_IDENTIFY_STDIN size"); + c->fd = imsg->fd; + break; + case MSG_IDENTIFY_ENVIRON: + if (datalen == 0 || data[datalen - 1] != '\0') + fatalx("bad MSG_IDENTIFY_ENVIRON string"); + if (strchr(data, '=') != NULL) + environ_put(&c->environ, data); + break; + default: + break; + } + + if (imsg->hdr.type != MSG_IDENTIFY_DONE) + return; + c->flags |= CLIENT_IDENTIFIED; + +#ifdef __CYGWIN__ + c->fd = open(c->ttyname, O_RDWR|O_NOCTTY); + c->cwd = open(".", O_RDONLY); +#endif + + if (c->flags & CLIENT_CONTROL) { c->stdin_callback = control_callback; + evbuffer_free(c->stderr_data); c->stderr_data = c->stdout_data; - c->flags |= CLIENT_CONTROL; - if (data->flags & IDENTIFY_TERMIOS) + + if (c->flags & CLIENT_CONTROLCONTROL) evbuffer_add_printf(c->stdout_data, "\033P1000p"); server_write_client(c, MSG_STDIN, NULL, 0); c->tty.fd = -1; c->tty.log_fd = -1; - close(fd); + close(c->fd); + c->fd = -1; + return; } - if (!isatty(fd)) { - close(fd); + if (c->fd == -1) + return; + if (!isatty(c->fd)) { + close(c->fd); + c->fd = -1; return; } - data->term[(sizeof data->term) - 1] = '\0'; - tty_init(&c->tty, c, fd, data->term); - if (data->flags & IDENTIFY_UTF8) + tty_init(&c->tty, c, c->fd, c->term); + if (c->flags & CLIENT_UTF8) c->tty.flags |= TTY_UTF8; - if (data->flags & IDENTIFY_256COLOURS) + if (c->flags & CLIENT_256COLOURS) c->tty.term_flags |= TERM_256COLOURS; tty_resize(&c->tty); - if (!(data->flags & IDENTIFY_CONTROL)) + if (!(c->flags & CLIENT_CONTROL)) c->flags |= CLIENT_TERMINAL; } @@ -996,16 +1045,12 @@ server_client_msg_identify( void server_client_msg_shell(struct client *c) { - struct msg_shell_data data; - const char *shell; + const char *shell; shell = options_get_string(&global_s_options, "default-shell"); - if (*shell == '\0' || areshell(shell)) shell = _PATH_BSHELL; - if (strlcpy(data.shell, shell, sizeof data.shell) >= sizeof data.shell) - strlcpy(data.shell, _PATH_BSHELL, sizeof data.shell); + server_write_client(c, MSG_SHELL, shell, strlen(shell) + 1); - server_write_client(c, MSG_SHELL, &data, sizeof data); c->flags |= CLIENT_BAD; /* it will die after exec */ } diff --git a/server-fn.c b/server-fn.c index 86e2054e..4fc4eb5c 100644 --- a/server-fn.c +++ b/server-fn.c @@ -56,8 +56,8 @@ server_write_ready(struct client *c) } int -server_write_client( - struct client *c, enum msgtype type, const void *buf, size_t len) +server_write_client(struct client *c, enum msgtype type, const void *buf, + size_t len) { struct imsgbuf *ibuf = &c->ibuf; int error; @@ -73,8 +73,8 @@ server_write_client( } void -server_write_session( - struct session *s, enum msgtype type, const void *buf, size_t len) +server_write_session(struct session *s, enum msgtype type, const void *buf, + size_t len) { struct client *c; u_int i; @@ -235,9 +235,7 @@ server_lock_session(struct session *s) void server_lock_client(struct client *c) { - const char *cmd; - size_t cmdlen; - struct msg_lock_data lockdata; + const char *cmd; if (c->flags & CLIENT_CONTROL) return; @@ -246,8 +244,7 @@ server_lock_client(struct client *c) return; cmd = options_get_string(&c->session->options, "lock-command"); - cmdlen = strlcpy(lockdata.cmd, cmd, sizeof lockdata.cmd); - if (cmdlen >= sizeof lockdata.cmd) + if (strlen(cmd) + 1 > MAX_IMSGSIZE - IMSG_HEADER_SIZE) return; tty_stop_tty(&c->tty); @@ -256,7 +253,7 @@ server_lock_client(struct client *c) tty_raw(&c->tty, tty_term_string(c->tty.term, TTYC_E3)); c->flags |= CLIENT_SUSPENDED; - server_write_client(c, MSG_LOCK, &lockdata, sizeof lockdata); + server_write_client(c, MSG_LOCK, cmd, strlen(cmd) + 1); } void @@ -398,14 +395,15 @@ void server_destroy_session_group(struct session *s) { struct session_group *sg; + struct session *s1; if ((sg = session_group_find(s)) == NULL) server_destroy_session(s); else { - TAILQ_FOREACH(s, &sg->sessions, gentry) + TAILQ_FOREACH_SAFE(s, &sg->sessions, gentry, s1) { server_destroy_session(s); - TAILQ_REMOVE(&session_groups, sg, entry); - free(sg); + session_destroy(s); + } } } diff --git a/session.c b/session.c index 74eb06a5..66a52bc6 100644 --- a/session.c +++ b/session.c @@ -84,9 +84,8 @@ session_find_by_id(u_int id) /* Create a new session. */ struct session * -session_create(const char *name, const char *cmd, const char *cwd, - struct environ *env, struct termios *tio, int idx, u_int sx, u_int sy, - char **cause) +session_create(const char *name, const char *cmd, int cwd, struct environ *env, + struct termios *tio, int idx, u_int sx, u_int sy, char **cause) { struct session *s; @@ -98,7 +97,7 @@ session_create(const char *name, const char *cmd, const char *cwd, fatal("gettimeofday failed"); session_update_activity(s); - s->cwd = xstrdup(cwd); + s->cwd = dup(cwd); s->curw = NULL; TAILQ_INIT(&s->lastw); @@ -150,6 +149,7 @@ void session_destroy(struct session *s) { struct winlink *wl; + log_debug("session %s destroyed", s->name); RB_REMOVE(sessions, &sessions, s); @@ -169,7 +169,7 @@ session_destroy(struct session *s) winlink_remove(&s->windows, wl); } - free(s->cwd); + close(s->cwd); RB_INSERT(sessions, &dead_sessions, s); } @@ -225,8 +225,8 @@ session_previous_session(struct session *s) /* Create a new window on a session. */ struct winlink * -session_new(struct session *s, - const char *name, const char *cmd, const char *cwd, int idx, char **cause) +session_new(struct session *s, const char *name, const char *cmd, int cwd, + int idx, char **cause) { struct window *w; struct winlink *wl; @@ -249,8 +249,8 @@ session_new(struct session *s, shell = _PATH_BSHELL; hlimit = options_get_number(&s->options, "history-limit"); - w = window_create( - name, cmd, shell, cwd, &env, s->tio, s->sx, s->sy, hlimit, cause); + w = window_create(name, cmd, shell, cwd, &env, s->tio, s->sx, s->sy, + hlimit, cause); if (w == NULL) { winlink_remove(&s->windows, wl); environ_free(&env); @@ -614,7 +614,7 @@ session_renumber_windows(struct session *s) memcpy(&old_lastw, &s->lastw, sizeof old_lastw); TAILQ_INIT(&s->lastw); TAILQ_FOREACH(wl, &old_lastw, sentry) { - wl_new = winlink_find_by_index(&s->windows, wl->idx); + wl_new = winlink_find_by_window(&s->windows, wl->window); if (wl_new != NULL) TAILQ_INSERT_TAIL(&s->lastw, wl_new, sentry); } diff --git a/tmux.1 b/tmux.1 index 11251790..56cb3f8f 100644 --- a/tmux.1 +++ b/tmux.1 @@ -99,7 +99,9 @@ Force .Nm to assume the terminal supports 256 colours. .It Fl C -Start in control mode. +Start in control mode (see the +.Sx CONTROL MODE +section). Given twice .Xo ( Fl CC ) Xc disables echo. @@ -566,6 +568,7 @@ The following commands are available to manage clients and sessions: .Bl -tag -width Ds .It Xo Ic attach-session .Op Fl dr +.Op Fl c Ar working-directory .Op Fl t Ar target-session .Xc .D1 (alias: Ic attach ) @@ -599,6 +602,10 @@ needs to select the most recently used session, it will prefer the most recently used .Em unattached session. +.Pp +.Fl c +will set the session working directory (used for new windows) to +.Ar working-directory . .It Xo Ic detach-client .Op Fl P .Op Fl a @@ -626,9 +633,10 @@ If it does exist, exit with 0. Kill the .Nm server and clients and destroy all sessions. -.It Ic kill-session +.It Xo Ic kill-session .Op Fl a .Op Fl t Ar target-session +.Xc Destroy the given session, closing any windows linked to it and no other sessions, and detaching all clients attached to it. If @@ -673,6 +681,7 @@ Lock all clients attached to .Ar target-session . .It Xo Ic new-session .Op Fl AdDP +.Op Fl c Ar start-directory .Op Fl F Ar format .Op Fl n Ar window-name .Op Fl s Ar session-name @@ -1509,13 +1518,6 @@ is not specified, the value of the option is used. .Fl c specifies the working directory in which the new window is created. -It may have an absolute path or one of the following values (or a subdirectory): -.Bl -column "XXXXXXXXXXXX" "XXXXXXXXXXXXXXXXXXXXXXXX" -offset indent -.It Li "Empty string" Ta "Current pane's directory" -.It Li "~" Ta "User's home directory" -.It Li "-" Ta "Where session was started" -.It Li "." Ta "Where server was started" -.El .Pp When the shell command completes, the window closes. See the @@ -2175,15 +2177,6 @@ The default is an empty string, which instructs to create a login shell using the value of the .Ic default-shell option. -.It Ic default-path Ar path -Set the default working directory for new panes. -If empty (the default), the working directory is determined from the process -running in the active pane, from the command line environment or from the -working directory where the session was created. -Otherwise the same options are available as for the -.Fl c -flag to -.Ic new-window . .It Ic default-shell Ar path Specify the default shell. This is used as the login shell for new windows when the @@ -2710,8 +2703,8 @@ The default is on. Control automatic window renaming. When this setting is enabled, .Nm -will attempt - on supported platforms - to rename the window to reflect the -command currently running in it. +will rename the window automatically using the format specified by +.Ic automatic-rename-format . This flag is automatically disabled for an individual window when a name is specified at creation with .Ic new-window @@ -2725,6 +2718,13 @@ It may be switched off globally with: set-window-option -g automatic-rename off .Ed .Pp +.It Ic automatic-rename-format Ar format +The format (see +.Sx FORMATS ) +used when the +.Ic automatic-rename +option is enabled. +.Pp .It Ic c0-change-interval Ar interval .It Ic c0-change-trigger Ar trigger These two options configure a simple form of rate limiting for a pane. @@ -2738,8 +2738,8 @@ instead redraw it entirely every .Ar interval milliseconds. This helps to prevent fast output (such as -.Xr yes 1 -overwhelming the terminal). +.Xr yes 1 ) +overwhelming the terminal. The default is a trigger of 250 and an interval of 100. A trigger of zero disables the rate limiting. .Pp @@ -3026,6 +3026,12 @@ will include the string if the session is attached and the string .Ql not attached if it is unattached. +A limit may be placed on the length of the resultant string by prefixing it +by an +.Ql = , +a number and a colon, so +.Ql #{=10:pane_title} +will include at most the first 10 characters of the pane title. .Pp The following variables are available, where appropriate: .Bl -column "XXXXXXXXXXXXXXXXXXX" "XXXXX" @@ -3039,7 +3045,6 @@ The following variables are available, where appropriate: .It Li "client_activity_string" Ta "" Ta "String time client last had activity" .It Li "client_created" Ta "" Ta "Integer time client created" .It Li "client_created_string" Ta "" Ta "String time client created" -.It Li "client_cwd" Ta "" Ta "Working directory of client" .It Li "client_height" Ta "" Ta "Height of client" .It Li "client_last_session" Ta "" Ta "Name of the client's last session" .It Li "client_prefix" Ta "" Ta "1 if prefix key has been pressed" @@ -3067,7 +3072,6 @@ The following variables are available, where appropriate: .It Li "mouse_utf8_flag" Ta "" Ta "Pane mouse UTF-8 flag" .It Li "pane_active" Ta "" Ta "1 if active pane" .It Li "pane_current_command" Ta "" Ta "Current command if available" -.It Li "pane_current_path" Ta "" Ta "Current path if available" .It Li "pane_dead" Ta "" Ta "1 if pane is dead" .It Li "pane_height" Ta "" Ta "Height of pane" .It Li "pane_id" Ta "#D" Ta "Unique pane ID" @@ -3096,6 +3100,9 @@ The following variables are available, where appropriate: .It Li "session_width" Ta "" Ta "Width of session" .It Li "session_windows" Ta "" Ta "Number of windows in session" .It Li "window_active" Ta "" Ta "1 if window active" +.It Li "window_activity_flag" Ta "" Ta "1 if window has activity alert" +.It Li "window_bell_flag" Ta "" Ta "1 if window has bell" +.It Li "window_content_flag" Ta "" Ta "1 if window has content alert" .It Li "window_find_matches" Ta "" Ta "Matched data from the find-window" .It Li "window_flags" Ta "#F" Ta "Window flags" .It Li "window_height" Ta "" Ta "Height of window" @@ -3104,6 +3111,7 @@ The following variables are available, where appropriate: .It Li "window_layout" Ta "" Ta "Window layout description" .It Li "window_name" Ta "#W" Ta "Name of window" .It Li "window_panes" Ta "" Ta "Number of panes in window" +.It Li "window_silence_flag" Ta "" Ta "1 if window has silence alert" .It Li "window_width" Ta "" Ta "Width of window" .It Li "wrap_flag" Ta "" Ta "Pane wrap flag" .El @@ -3562,7 +3570,7 @@ If the command doesn't return success, the exit status is also displayed. .D1 (alias: Ic info ) Show server information and terminal details. .It Xo Ic wait-for -.Fl LSU +.Op Fl L | S | U .Ar channel .Xc .D1 (alias: Ic wait ) @@ -3803,4 +3811,4 @@ bind-key S command-prompt "new-window -n %1 'ssh %1'" .Sh SEE ALSO .Xr pty 4 .Sh AUTHORS -.An Nicholas Marriott Aq nicm@users.sourceforge.net +.An Nicholas Marriott Aq Mt nicm@users.sourceforge.net diff --git a/tmux.c b/tmux.c index 606c574f..1e6edd90 100644 --- a/tmux.c +++ b/tmux.c @@ -48,11 +48,8 @@ time_t start_time; char socket_path[MAXPATHLEN]; int login_shell; char *environ_path; -pid_t environ_pid = -1; -int environ_session_id = -1; __dead void usage(void); -void parseenvironment(void); char *makesocketpath(const char *); #ifndef HAVE___PROGNAME @@ -127,39 +124,6 @@ areshell(const char *shell) return (0); } -const char* -get_full_path(const char *wd, const char *path) -{ - static char newpath[MAXPATHLEN]; - char oldpath[MAXPATHLEN]; - - if (getcwd(oldpath, sizeof oldpath) == NULL) - return (NULL); - if (chdir(wd) != 0) - return (NULL); - if (realpath(path, newpath) != 0) - return (NULL); - chdir(oldpath); - return (newpath); -} - -void -parseenvironment(void) -{ - char *env, path[256]; - long pid; - int id; - - if ((env = getenv("TMUX")) == NULL) - return; - - if (sscanf(env, "%255[^,],%ld,%d", path, &pid, &id) != 3) - return; - environ_path = xstrdup(path); - environ_pid = pid; - environ_session_id = id; -} - char * makesocketpath(const char *label) { @@ -184,7 +148,8 @@ makesocketpath(const char *label) errno = ENOTDIR; return (NULL); } - if (sb.st_uid != uid || (sb.st_mode & (S_IRWXG|S_IRWXO)) != 0) { + if (sb.st_uid != uid || (!S_ISDIR(sb.st_mode) && + sb.st_mode & (S_IRWXG|S_IRWXO)) != 0) { errno = EACCES; return (NULL); } @@ -240,8 +205,10 @@ int main(int argc, char **argv) { struct passwd *pw; - char *s, *path, *label, *home, **var; - int opt, flags, quiet, keys; + char *s, *path, *label, *home, **var, tmp[MAXPATHLEN]; + char in[256]; + long long pid; + int opt, flags, quiet, keys, session; #if defined(DEBUG) && defined(__OpenBSD__) malloc_options = (char *) "AFGJPX"; @@ -255,17 +222,17 @@ main(int argc, char **argv) while ((opt = getopt(argc, argv, "2c:Cdf:lL:qS:uUVv")) != -1) { switch (opt) { case '2': - flags |= IDENTIFY_256COLOURS; + flags |= CLIENT_256COLOURS; break; case 'c': free(shell_cmd); shell_cmd = xstrdup(optarg); break; case 'C': - if (flags & IDENTIFY_CONTROL) - flags |= IDENTIFY_TERMIOS; + if (flags & CLIENT_CONTROL) + flags |= CLIENT_CONTROLCONTROL; else - flags |= IDENTIFY_CONTROL; + flags |= CLIENT_CONTROL; break; case 'V': printf("%s %s\n", __progname, VERSION); @@ -289,7 +256,7 @@ main(int argc, char **argv) path = xstrdup(optarg); break; case 'u': - flags |= IDENTIFY_UTF8; + flags |= CLIENT_UTF8; break; case 'v': debug_level++; @@ -304,7 +271,7 @@ main(int argc, char **argv) if (shell_cmd != NULL && argc != 0) usage(); - if (!(flags & IDENTIFY_UTF8)) { + if (!(flags & CLIENT_UTF8)) { /* * If the user has set whichever of LC_ALL, LC_CTYPE or LANG * exist (in that order) to contain UTF-8, it is a safe @@ -318,12 +285,14 @@ main(int argc, char **argv) } if (s != NULL && (strcasestr(s, "UTF-8") != NULL || strcasestr(s, "UTF8") != NULL)) - flags |= IDENTIFY_UTF8; + flags |= CLIENT_UTF8; } environ_init(&global_environ); for (var = environ; *var != NULL; var++) environ_put(&global_environ, *var); + if (getcwd(tmp, sizeof tmp) != NULL) + environ_set(&global_environ, "PWD", tmp); options_init(&global_options, NULL); options_table_populate_tree(server_options_table, &global_options); @@ -337,7 +306,7 @@ main(int argc, char **argv) options_table_populate_tree(window_options_table, &global_w_options); /* Enable UTF-8 if the first client is on UTF-8 terminal. */ - if (flags & IDENTIFY_UTF8) { + if (flags & CLIENT_UTF8) { options_set_number(&global_s_options, "status-utf8", 1); options_set_number(&global_s_options, "mouse-utf8", 1); options_set_number(&global_w_options, "utf8", 1); @@ -370,11 +339,15 @@ main(int argc, char **argv) } } + /* Get path from environment. */ + s = getenv("TMUX"); + if (s != NULL && sscanf(s, "%255[^,],%lld,%d", in, &pid, &session) == 3) + environ_path = xstrdup(in); + /* * Figure out the socket path. If specified on the command-line with -S * or -L, use it, otherwise try $TMUX or assume -L default. */ - parseenvironment(); if (path == NULL) { /* If no -L, use the environment. */ if (label == NULL) { @@ -387,7 +360,8 @@ main(int argc, char **argv) /* -L or default set. */ if (label != NULL) { if ((path = makesocketpath(label)) == NULL) { - fprintf(stderr, "can't create socket\n"); + fprintf(stderr, "can't create socket: %s\n", + strerror(errno)); exit(1); } } diff --git a/tmux.h b/tmux.h index cc1c79e8..3a298840 100644 --- a/tmux.h +++ b/tmux.h @@ -19,7 +19,7 @@ #ifndef TMUX_H #define TMUX_H -#define PROTOCOL_VERSION 7 +#define PROTOCOL_VERSION 8 #include #include @@ -51,14 +51,6 @@ extern char **environ; /* Automatic name refresh interval, in milliseconds. */ #define NAME_INTERVAL 500 -/* - * Maximum sizes of strings in message data. Don't forget to bump - * PROTOCOL_VERSION if any of these change! - */ -#define COMMAND_LENGTH 2048 /* packed argv size */ -#define TERMINAL_LENGTH 128 /* length of TERM environment variable */ -#define ENVIRON_LENGTH 1024 /* environment variable length */ - /* * UTF-8 data size. This must be big enough to hold combined characters as well * as single. @@ -144,7 +136,7 @@ extern char **environ; "[layout #{window_layout}] #{window_id}" \ "#{?window_active, (active),}"; #define LIST_WINDOWS_WITH_SESSION_TEMPLATE \ - "#{session_name}: " \ + "#{session_name}:" \ "#{window_index}: #{window_name}#{window_flags} " \ "(#{window_panes} panes) " \ "[#{window_width}x#{window_height}] " @@ -430,27 +422,33 @@ ARRAY_DECL(causelist, char *); /* Message codes. */ enum msgtype { - MSG_COMMAND, + MSG_VERSION = 12, + + MSG_IDENTIFY_FLAGS = 100, + MSG_IDENTIFY_TERM, + MSG_IDENTIFY_TTYNAME, + MSG_IDENTIFY_CWD, + MSG_IDENTIFY_STDIN, + MSG_IDENTIFY_ENVIRON, + MSG_IDENTIFY_DONE, + + MSG_COMMAND = 200, MSG_DETACH, - MSG_ERROR, + MSG_DETACHKILL, MSG_EXIT, MSG_EXITED, MSG_EXITING, - MSG_IDENTIFY, - MSG_STDIN, + MSG_LOCK, MSG_READY, MSG_RESIZE, - MSG_SHUTDOWN, - MSG_SUSPEND, - MSG_VERSION, - MSG_WAKEUP, - MSG_ENVIRON, - MSG_UNLOCK, - MSG_LOCK, MSG_SHELL, + MSG_SHUTDOWN, MSG_STDERR, + MSG_STDIN, MSG_STDOUT, - MSG_DETACHKILL + MSG_SUSPEND, + MSG_UNLOCK, + MSG_WAKEUP, }; /* @@ -459,45 +457,8 @@ enum msgtype { * Don't forget to bump PROTOCOL_VERSION if any of these change! */ struct msg_command_data { - pid_t pid; /* from $TMUX or -1 */ - int session_id; /* from $TMUX or -1 */ - - int argc; - char argv[COMMAND_LENGTH]; -}; - -struct msg_identify_data { - char cwd[MAXPATHLEN]; - - char term[TERMINAL_LENGTH]; - -#ifdef __CYGWIN__ - char ttyname[TTY_NAME_MAX]; -#endif - -#define IDENTIFY_UTF8 0x1 -#define IDENTIFY_256COLOURS 0x2 -/* 0x4 unused */ -#define IDENTIFY_CONTROL 0x8 -#define IDENTIFY_TERMIOS 0x10 - int flags; -}; - -struct msg_lock_data { - char cmd[COMMAND_LENGTH]; -}; - -struct msg_environ_data { - char var[ENVIRON_LENGTH]; -}; - -struct msg_shell_data { - char shell[MAXPATHLEN]; -}; - -struct msg_exit_data { - int retcode; -}; + int argc; +}; /* followed by packed argv */ struct msg_stdin_data { ssize_t size; @@ -945,7 +906,7 @@ struct window_pane { char *cmd; char *shell; - char *cwd; + int cwd; pid_t pid; char tty[TTY_NAME_MAX]; @@ -1005,6 +966,7 @@ struct window { #define WINDOW_REDRAW 0x4 #define WINDOW_SILENCE 0x8 #define WINDOW_ZOOMED 0x10 +#define WINDOW_ALERTFLAGS (WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_SILENCE) struct options options; @@ -1091,7 +1053,7 @@ struct session { u_int id; char *name; - char *cwd; + int cwd; struct timeval creation_time; struct timeval activity_time; @@ -1290,8 +1252,10 @@ RB_HEAD(status_out_tree, status_out); /* Client connection. */ struct client { struct imsgbuf ibuf; + + int fd; struct event event; - int retcode; + int retval; struct timeval creation_time; struct timeval activity_time; @@ -1299,8 +1263,10 @@ struct client { struct environ environ; char *title; - char *cwd; + int cwd; + char *term; + char *ttyname; struct tty tty; void (*stdin_callback)(struct client *, int, void *); @@ -1322,7 +1288,7 @@ struct client { #define CLIENT_EXIT 0x4 #define CLIENT_REDRAW 0x8 #define CLIENT_STATUS 0x10 -#define CLIENT_REPEAT 0x20 /* allow command to repeat within repeat time */ +#define CLIENT_REPEAT 0x20 #define CLIENT_SUSPENDED 0x40 #define CLIENT_BAD 0x80 #define CLIENT_IDENTIFY 0x100 @@ -1331,7 +1297,11 @@ struct client { #define CLIENT_READONLY 0x800 #define CLIENT_REDRAWWINDOW 0x1000 #define CLIENT_CONTROL 0x2000 -#define CLIENT_FOCUSED 0x4000 +#define CLIENT_CONTROLCONTROL 0x4000 +#define CLIENT_FOCUSED 0x8000 +#define CLIENT_UTF8 0x10000 +#define CLIENT_256COLOURS 0x20000 +#define CLIENT_IDENTIFIED 0x40000 int flags; struct event identify_timer; @@ -1428,8 +1398,6 @@ struct cmd_q { void (*emptyfn)(struct cmd_q *); void *data; - struct msg_command_data *msgdata; - TAILQ_ENTRY(cmd_q) waitentry; }; @@ -1446,12 +1414,10 @@ struct cmd_entry { #define CMD_STARTSERVER 0x1 #define CMD_CANTNEST 0x2 -#define CMD_SENDENVIRON 0x4 -#define CMD_READONLY 0x8 +#define CMD_READONLY 0x4 int flags; void (*key_binding)(struct cmd *, int); - int (*check)(struct args *); enum cmd_retval (*exec)(struct cmd *, struct cmd_q *); }; @@ -1525,13 +1491,10 @@ extern time_t start_time; extern char socket_path[MAXPATHLEN]; extern int login_shell; extern char *environ_path; -extern pid_t environ_pid; -extern int environ_session_id; void logfile(const char *); const char *getshell(void); int checkshell(const char *); int areshell(const char *); -const char* get_full_path(const char *, const char *); void setblocking(int, int); __dead void shell_exec(const char *, const char *); @@ -1549,16 +1512,19 @@ int format_cmp(struct format_entry *, struct format_entry *); RB_PROTOTYPE(format_tree, format_entry, entry, format_cmp); struct format_tree *format_create(void); void format_free(struct format_tree *); -void printflike3 format_add( - struct format_tree *, const char *, const char *, ...); +void printflike3 format_add(struct format_tree *, const char *, const char *, + ...); const char *format_find(struct format_tree *, const char *); char *format_expand(struct format_tree *, const char *); void format_session(struct format_tree *, struct session *); void format_client(struct format_tree *, struct client *); -void format_winlink( - struct format_tree *, struct session *, struct winlink *); -void format_window_pane(struct format_tree *, struct window_pane *); -void format_paste_buffer(struct format_tree *, struct paste_buffer *); +void format_window(struct format_tree *, struct window *); +void format_winlink(struct format_tree *, struct session *, + struct winlink *); +void format_window_pane(struct format_tree *, + struct window_pane *); +void format_paste_buffer(struct format_tree *, + struct paste_buffer *); /* mode-key.c */ extern const struct mode_key_table mode_key_tables[]; @@ -1764,7 +1730,6 @@ int cmd_find_index(struct cmd_q *, const char *, struct winlink *cmd_find_pane(struct cmd_q *, const char *, struct session **, struct window_pane **); char *cmd_template_replace(const char *, const char *, int); -const char *cmd_get_default_path(struct cmd_q *, const char *); extern const struct cmd_entry *cmd_table[]; extern const struct cmd_entry cmd_attach_session_entry; extern const struct cmd_entry cmd_bind_key_entry; @@ -1855,7 +1820,8 @@ extern const struct cmd_entry cmd_up_pane_entry; extern const struct cmd_entry cmd_wait_for_entry; /* cmd-attach-session.c */ -enum cmd_retval cmd_attach_session(struct cmd_q *, const char*, int, int); +enum cmd_retval cmd_attach_session(struct cmd_q *, const char *, int, int, + const char *); /* cmd-list.c */ struct cmd_list *cmd_list_parse(int, char **, const char *, u_int, char **); @@ -1868,7 +1834,7 @@ int cmdq_free(struct cmd_q *); void printflike2 cmdq_print(struct cmd_q *, const char *, ...); void printflike2 cmdq_info(struct cmd_q *, const char *, ...); void printflike2 cmdq_error(struct cmd_q *, const char *, ...); -int cmdq_guard(struct cmd_q *, const char *); +int cmdq_guard(struct cmd_q *, const char *, int); void cmdq_run(struct cmd_q *, struct cmd_list *); void cmdq_append(struct cmd_q *, struct cmd_list *); int cmdq_continue(struct cmd_q *); @@ -1919,10 +1885,10 @@ void server_window_loop(void); /* server-fn.c */ void server_fill_environ(struct session *, struct environ *); void server_write_ready(struct client *); -int server_write_client( - struct client *, enum msgtype, const void *, size_t); -void server_write_session( - struct session *, enum msgtype, const void *, size_t); +int server_write_client(struct client *, enum msgtype, const void *, + size_t); +void server_write_session(struct session *, enum msgtype, const void *, + size_t); void server_redraw_client(struct client *); void server_status_client(struct client *); void server_redraw_session(struct session *); @@ -2144,9 +2110,9 @@ void winlink_stack_remove(struct winlink_stack *, struct winlink *); int window_index(struct window *, u_int *); struct window *window_find_by_id(u_int); struct window *window_create1(u_int, u_int); -struct window *window_create(const char *, const char *, const char *, - const char *, struct environ *, struct termios *, - u_int, u_int, u_int, char **); +struct window *window_create(const char *, const char *, const char *, int, + struct environ *, struct termios *, u_int, u_int, u_int, + char **); void window_destroy(struct window *); struct window_pane *window_get_active_at(struct window *, u_int, u_int); void window_set_active_at(struct window *, u_int, u_int); @@ -2170,8 +2136,8 @@ struct window_pane *window_pane_create(struct window *, u_int, u_int, u_int); void window_pane_destroy(struct window_pane *); void window_pane_timer_start(struct window_pane *); int window_pane_spawn(struct window_pane *, const char *, - const char *, const char *, struct environ *, - struct termios *, char **); + const char *, int, struct environ *, struct termios *, + char **); void window_pane_resize(struct window_pane *, u_int, u_int); void window_pane_alternate_on(struct window_pane *, struct grid_cell *, int); @@ -2272,8 +2238,10 @@ void window_choose_collapse_all(struct window_pane *); void window_choose_set_current(struct window_pane *, u_int); /* names.c */ -void queue_window_name(struct window *); -char *default_window_name(struct window *); +void queue_window_name(struct window *); +char *default_window_name(struct window *); +char *format_window_name(struct window *); +char *parse_window_name(const char *); /* signal.c */ void set_signals(void(*)(int, short, void *)); @@ -2305,7 +2273,7 @@ RB_PROTOTYPE(sessions, session, entry, session_cmp); int session_alive(struct session *); struct session *session_find(const char *); struct session *session_find_by_id(u_int); -struct session *session_create(const char *, const char *, const char *, +struct session *session_create(const char *, const char *, int, struct environ *, struct termios *, int, u_int, u_int, char **); void session_destroy(struct session *); @@ -2313,8 +2281,8 @@ int session_check_name(const char *); void session_update_activity(struct session *); struct session *session_next_session(struct session *); struct session *session_previous_session(struct session *); -struct winlink *session_new(struct session *, - const char *, const char *, const char *, int, char **); +struct winlink *session_new(struct session *, const char *, const char *, int, + int, char **); struct winlink *session_attach( struct session *, struct window *, int, char **); int session_detach(struct session *, struct winlink *); @@ -2340,10 +2308,8 @@ int utf8_append(struct utf8_data *, u_char); u_int utf8_combine(const struct utf8_data *); u_int utf8_split2(u_int, u_char *); -/* osdep-*.c */ -char *osdep_get_name(int, char *); -char *osdep_get_cwd(int); -struct event_base *osdep_event_init(void); +/* procname.c */ +char *get_proc_name(int, char *); /* log.c */ void log_open(int, const char *); diff --git a/tty-keys.c b/tty-keys.c index 3055f399..595ad6e1 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -676,11 +676,17 @@ tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size) log_debug("mouse input: %.*s", (int) *size, buf); /* Check and return the mouse input. */ - if (b < 32 || x < 33 || y < 33) + if (b < 32) return (-1); b -= 32; - x -= 33; - y -= 33; + if (x >= 33) + x -= 33; + else + x = 256 - x; + if (y >= 33) + y -= 33; + else + y = 256 - y; } else if (buf[2] == '<') { /* Read the three inputs. */ *size = 3; @@ -740,6 +746,8 @@ tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size) m->sgr = sgr; m->sgr_xb = sgr_b; m->sgr_rel = sgr_rel; + m->x = x; + m->y = y; if (b & 64) { /* wheel button */ b &= 3; if (b == 0) @@ -767,8 +775,6 @@ tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size) } m->button = (b & 3); } - m->x = x; - m->y = y; return (0); } diff --git a/window-choose.c b/window-choose.c index 5ed85f0e..572581a5 100644 --- a/window-choose.c +++ b/window-choose.c @@ -81,6 +81,7 @@ int window_choose_key_index(struct window_choose_mode_data *, u_int); int window_choose_index_key(struct window_choose_mode_data *, int); void window_choose_prompt_input(enum window_choose_input_type, const char *, struct window_pane *, int); +void window_choose_reset_top(struct window_pane *, u_int); void window_choose_add(struct window_pane *wp, struct window_choose_data *wcd) @@ -107,8 +108,17 @@ window_choose_set_current(struct window_pane *wp, u_int cur) struct screen *s = &data->screen; data->selected = cur; - if (data->selected > screen_size_y(s) - 1) - data->top = ARRAY_LENGTH(&data->list) - screen_size_y(s); + window_choose_reset_top(wp, screen_size_y(s)); +} + +void +window_choose_reset_top(struct window_pane *wp, u_int sy) +{ + struct window_choose_mode_data *data = wp->modedata; + + data->top = 0; + if (data->selected > sy - 1) + data->top = data->selected - (sy - 1); window_choose_redraw_screen(wp); } @@ -277,10 +287,7 @@ window_choose_resize(struct window_pane *wp, u_int sx, u_int sy) struct window_choose_mode_data *data = wp->modedata; struct screen *s = &data->screen; - data->top = 0; - if (data->selected > sy - 1) - data->top = data->selected - (sy - 1); - + window_choose_reset_top(wp, sy); screen_resize(s, sx, sy, 0); window_choose_redraw_screen(wp); } @@ -373,6 +380,7 @@ window_choose_collapse_all(struct window_pane *wp) { struct window_choose_mode_data *data = wp->modedata; struct window_choose_mode_item *item; + struct screen *scr = &data->screen; struct session *s, *chosen; u_int i; @@ -391,7 +399,7 @@ window_choose_collapse_all(struct window_pane *wp) if (item->wcd->type & TREE_SESSION) data->selected = i; } - window_choose_redraw_screen(wp); + window_choose_reset_top(wp, screen_size_y(scr)); } void @@ -399,6 +407,7 @@ window_choose_expand_all(struct window_pane *wp) { struct window_choose_mode_data *data = wp->modedata; struct window_choose_mode_item *item; + struct screen *scr = &data->screen; struct session *s; u_int i; @@ -414,7 +423,7 @@ window_choose_expand_all(struct window_pane *wp) } } - window_choose_redraw_screen(wp); + window_choose_reset_top(wp, screen_size_y(scr)); } void diff --git a/window.c b/window.c index 7678adc6..9f47f444 100644 --- a/window.c +++ b/window.c @@ -306,7 +306,7 @@ window_create1(u_int sx, u_int sy) struct window * window_create(const char *name, const char *cmd, const char *shell, - const char *cwd, struct environ *env, struct termios *tio, + int cwd, struct environ *env, struct termios *tio, u_int sx, u_int sy, u_int hlimit, char **cause) { struct window *w; @@ -672,7 +672,7 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit) wp->cmd = NULL; wp->shell = NULL; - wp->cwd = NULL; + wp->cwd = -1; wp->fd = -1; wp->event = NULL; @@ -727,7 +727,7 @@ window_pane_destroy(struct window_pane *wp) RB_REMOVE(window_pane_tree, &all_window_panes, wp); - free(wp->cwd); + close(wp->cwd); free(wp->shell); free(wp->cmd); free(wp); @@ -735,7 +735,7 @@ window_pane_destroy(struct window_pane *wp) int window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell, - const char *cwd, struct environ *env, struct termios *tio, char **cause) + int cwd, struct environ *env, struct termios *tio, char **cause) { struct winsize ws; char *argv0, paneid[16]; @@ -754,9 +754,9 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell, free(wp->shell); wp->shell = xstrdup(shell); } - if (cwd != NULL) { - free(wp->cwd); - wp->cwd = xstrdup(cwd); + if (cwd != -1) { + close(wp->cwd); + wp->cwd = dup(cwd); } log_debug("spawn: %s -- %s", wp->shell, wp->cmd); @@ -771,7 +771,7 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell, xasprintf(cause, "%s: %s", cmd, strerror(errno)); return (-1); case 0: - if (chdir(wp->cwd) != 0) + if (fchdir(wp->cwd) != 0) chdir("/"); if (tcgetattr(STDIN_FILENO, &tio2) != 0) @@ -1243,6 +1243,7 @@ winlink_clear_flags(struct winlink *wl) continue; wm->flags &= ~WINLINK_ALERTFLAGS; + wm->window->flags &= ~WINDOW_ALERTFLAGS; server_status_session(s); } }