From 4ec61bef461aba6d5849bce971a241850b8d7ef6 Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 24 Nov 2015 20:40:51 +0000 Subject: [PATCH 01/15] Fix usage of detach-client. --- cmd-detach-client.c | 2 +- tmux.1 | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/cmd-detach-client.c b/cmd-detach-client.c index 813ac032..f7369df0 100644 --- a/cmd-detach-client.c +++ b/cmd-detach-client.c @@ -31,7 +31,7 @@ enum cmd_retval cmd_detach_client_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_detach_client_entry = { "detach-client", "detach", "as:t:P", 0, 0, - "[-P] [-a] [-s target-session] " CMD_TARGET_CLIENT_USAGE, + "[-aP] [-s target-session] " CMD_TARGET_CLIENT_USAGE, CMD_READONLY, cmd_detach_client_exec }; diff --git a/tmux.1 b/tmux.1 index 3fd383d6..455de33b 100644 --- a/tmux.1 +++ b/tmux.1 @@ -714,8 +714,7 @@ is used, .Ic update-environment option will not be applied. .It Xo Ic detach-client -.Op Fl P -.Op Fl a +.Op Fl aP .Op Fl s Ar target-session .Op Fl t Ar target-client .Xc From 9cccb8c1159b0a4747b5152e2df08e42207b574d Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 24 Nov 2015 21:19:46 +0000 Subject: [PATCH 02/15] Make the log stuff a bit tidier with some helper functions. --- cmd-show-messages.c | 1 - log.c | 35 +++++++++++++++++++++++++++++------ proc.c | 2 +- server.c | 2 +- tmux.c | 15 +-------------- tmux.h | 8 ++++---- 6 files changed, 36 insertions(+), 27 deletions(-) diff --git a/cmd-show-messages.c b/cmd-show-messages.c index 92ac5cc2..3d2edf9a 100644 --- a/cmd-show-messages.c +++ b/cmd-show-messages.c @@ -61,7 +61,6 @@ cmd_show_messages_server(struct cmd_q *cmdq) cmdq_print(cmdq, "started %s", tim); cmdq_print(cmdq, "socket path %s", socket_path); - cmdq_print(cmdq, "debug level %d", debug_level); cmdq_print(cmdq, "protocol version %d", PROTOCOL_VERSION); return (1); diff --git a/log.c b/log.c index 6c7be8b2..46f1673c 100644 --- a/log.c +++ b/log.c @@ -22,30 +22,53 @@ #include #include #include +#include #include #include "tmux.h" -FILE *log_file; +static FILE *log_file; +static int log_level; -void log_event_cb(int, const char *); -void log_vwrite(const char *, va_list); +static void log_event_cb(int, const char *); +static void log_vwrite(const char *, va_list); /* Log callback for libevent. */ -void +static void log_event_cb(__unused int severity, const char *msg) { log_debug("%s", msg); } +/* Increment log level. */ +void +log_add_level(void) +{ + log_level++; +} + +/* Get log level. */ +int +log_get_level(void) +{ + return (log_level); +} + /* Open logging to file. */ void -log_open(const char *path) +log_open(const char *name) { + char *path; + + if (log_level == 0) + return; + if (log_file != NULL) fclose(log_file); + xasprintf(&path, "tmux-%s-%ld.log", name, (long)getpid()); log_file = fopen(path, "w"); + free(path); if (log_file == NULL) return; @@ -65,7 +88,7 @@ log_close(void) } /* Write a log message. */ -void +static void log_vwrite(const char *msg, va_list ap) { char *fmt, *out; diff --git a/proc.c b/proc.c index 31fd136b..06340cd9 100644 --- a/proc.c +++ b/proc.c @@ -188,7 +188,7 @@ proc_start(const char *name, struct event_base *base, int forkflag, fatalx("event_reinit failed"); } - logfile(name); + log_open(name); setproctitle("%s (%s)", name, socket_path); log_debug("%s started (%ld): socket %s, protocol %d", name, diff --git a/server.c b/server.c index e17b9356..e9159422 100644 --- a/server.c +++ b/server.c @@ -173,7 +173,7 @@ server_start(struct event_base *base, int lockfd, char *lockfile) } close(pair[0]); - if (debug_level > 3) + if (log_get_level() > 3) tty_create_log(); if (pledge("stdio rpath wpath cpath fattr unix getpw recvfd proc exec " "tty ps", NULL) != 0) diff --git a/tmux.c b/tmux.c index aa827178..f5383fcf 100644 --- a/tmux.c +++ b/tmux.c @@ -44,7 +44,6 @@ struct options *global_w_options; /* window options */ struct environ *global_environ; char *shell_cmd; -int debug_level; time_t start_time; char socket_path[PATH_MAX]; @@ -61,18 +60,6 @@ usage(void) exit(1); } -void -logfile(const char *name) -{ - char *path; - - if (debug_level > 0) { - xasprintf(&path, "tmux-%s-%ld.log", name, (long) getpid()); - log_open(path); - free(path); - } -} - const char * getshell(void) { @@ -243,7 +230,7 @@ main(int argc, char **argv) flags |= CLIENT_UTF8; break; case 'v': - debug_level++; + log_add_level(); break; default: usage(); diff --git a/tmux.h b/tmux.h index 591fe54e..5f469f92 100644 --- a/tmux.h +++ b/tmux.h @@ -1432,10 +1432,8 @@ extern struct options *global_s_options; extern struct options *global_w_options; extern struct environ *global_environ; extern char *shell_cmd; -extern int debug_level; extern time_t start_time; extern char socket_path[PATH_MAX]; -void logfile(const char *); const char *getshell(void); int checkshell(const char *); int areshell(const char *); @@ -2210,8 +2208,10 @@ char *utf8_padcstr(const char *, u_int); char *get_proc_name(int, char *); /* log.c */ -void log_open(const char *); -void log_close(void); +void log_add_level(void); +int log_get_level(void); +void log_open(const char *); +void log_close(void); void printflike(1, 2) log_debug(const char *, ...); __dead void printflike(1, 2) fatal(const char *, ...); __dead void printflike(1, 2) fatalx(const char *, ...); From bdbbd9711c05507161bc70ccdde91bdb719d943b Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 24 Nov 2015 21:23:44 +0000 Subject: [PATCH 03/15] Show libevent version in showmsgs -I. --- cmd-show-messages.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmd-show-messages.c b/cmd-show-messages.c index 3d2edf9a..8cf71f41 100644 --- a/cmd-show-messages.c +++ b/cmd-show-messages.c @@ -62,6 +62,8 @@ cmd_show_messages_server(struct cmd_q *cmdq) cmdq_print(cmdq, "started %s", tim); cmdq_print(cmdq, "socket path %s", socket_path); cmdq_print(cmdq, "protocol version %d", PROTOCOL_VERSION); + cmdq_print(cmdq, "libevent %s (%s)", event_get_version(), + event_get_method()); return (1); } From 4e3015a8925f72b35393afec250cc46e4f480641 Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 24 Nov 2015 21:32:36 +0000 Subject: [PATCH 04/15] Log some system and libevent information at startup. --- proc.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/proc.c b/proc.c index 06340cd9..593c1b8b 100644 --- a/proc.c +++ b/proc.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -170,6 +171,7 @@ proc_start(const char *name, struct event_base *base, int forkflag, void (*signalcb)(int)) { struct tmuxproc *tp; + struct utsname u; if (forkflag) { switch (fork()) { @@ -191,8 +193,13 @@ proc_start(const char *name, struct event_base *base, int forkflag, log_open(name); setproctitle("%s (%s)", name, socket_path); + if (uname(&u) < 0) + memset(&u, 0, sizeof u); + log_debug("%s started (%ld): socket %s, protocol %d", name, (long)getpid(), socket_path, PROTOCOL_VERSION); + log_debug("on %s %s %s; libevent %s (%s)", u.sysname, u.release, + u.version, event_get_version(), event_get_method()); tp = xcalloc(1, sizeof *tp); tp->name = xstrdup(name); From 9fd3318dd818c45432581beff5b1a5f6cb55f2ff Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 24 Nov 2015 21:50:06 +0000 Subject: [PATCH 05/15] All kill-session -C to clear alerts in all windows, suggested by Aaron U'Ren. --- cmd-kill-session.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/cmd-kill-session.c b/cmd-kill-session.c index 74843eb6..3f39c241 100644 --- a/cmd-kill-session.c +++ b/cmd-kill-session.c @@ -31,8 +31,8 @@ enum cmd_retval cmd_kill_session_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_kill_session_entry = { "kill-session", NULL, - "at:", 0, 0, - "[-a] " CMD_TARGET_SESSION_USAGE, + "aCt:", 0, 0, + "[-aC] " CMD_TARGET_SESSION_USAGE, 0, cmd_kill_session_exec }; @@ -42,11 +42,18 @@ cmd_kill_session_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct session *s, *sloop, *stmp; + struct winlink *wl; if ((s = cmd_find_session(cmdq, args_get(args, 't'), 0)) == NULL) return (CMD_RETURN_ERROR); - if (args_has(args, 'a')) { + if (args_has(args, 'C')) { + RB_FOREACH(wl, winlinks, &s->windows) { + wl->window->flags &= ~WINDOW_ALERTFLAGS; + wl->flags &= ~WINLINK_ALERTFLAGS; + } + server_redraw_session(s); + } else if (args_has(args, 'a')) { RB_FOREACH_SAFE(sloop, sessions, &sessions, stmp) { if (sloop != s) { server_destroy_session(sloop); From 1e2df2d46496fc025330c25fa08e83d14e62d11b Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 24 Nov 2015 21:52:06 +0000 Subject: [PATCH 06/15] Remove the -I part of show-messages which isn't really that useful; the server start time can now be accessed with a new start_time format (use: tmux display -p '#{t:start_time}') --- cmd-show-messages.c | 26 ++------------------------ format.c | 2 ++ server.c | 2 +- tmux.1 | 12 ++++++++---- tmux.c | 2 +- tmux.h | 6 +++--- 6 files changed, 17 insertions(+), 33 deletions(-) diff --git a/cmd-show-messages.c b/cmd-show-messages.c index 8cf71f41..c98c2c91 100644 --- a/cmd-show-messages.c +++ b/cmd-show-messages.c @@ -33,8 +33,8 @@ enum cmd_retval cmd_show_messages_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_show_messages_entry = { "show-messages", "showmsgs", - "IJTt:", 0, 0, - "[-IJT] " CMD_TARGET_CLIENT_USAGE, + "JTt:", 0, 0, + "[-JT] " CMD_TARGET_CLIENT_USAGE, 0, cmd_show_messages_exec }; @@ -47,27 +47,9 @@ const struct cmd_entry cmd_server_info_entry = { cmd_show_messages_exec }; -int cmd_show_messages_server(struct cmd_q *); int cmd_show_messages_terminals(struct cmd_q *, int); int cmd_show_messages_jobs(struct cmd_q *, int); -int -cmd_show_messages_server(struct cmd_q *cmdq) -{ - char *tim; - - tim = ctime(&start_time); - *strchr(tim, '\n') = '\0'; - - cmdq_print(cmdq, "started %s", tim); - cmdq_print(cmdq, "socket path %s", socket_path); - cmdq_print(cmdq, "protocol version %d", PROTOCOL_VERSION); - cmdq_print(cmdq, "libevent %s (%s)", event_get_version(), - event_get_method()); - - return (1); -} - int cmd_show_messages_terminals(struct cmd_q *cmdq, int blank) { @@ -118,10 +100,6 @@ cmd_show_messages_exec(struct cmd *self, struct cmd_q *cmdq) int done, blank; done = blank = 0; - if (args_has(args, 'I') || self->entry == &cmd_server_info_entry) { - blank = cmd_show_messages_server(cmdq); - done = 1; - } if (args_has(args, 'T') || self->entry == &cmd_server_info_entry) { blank = cmd_show_messages_terminals(cmdq, blank); done = 1; diff --git a/format.c b/format.c index 50fa7dea..bafd8ce6 100644 --- a/format.c +++ b/format.c @@ -488,6 +488,8 @@ format_create_flags(int flags) format_add_cb(ft, "host", format_cb_host); format_add_cb(ft, "host_short", format_cb_host_short); format_add_cb(ft, "pid", format_cb_pid); + format_add(ft, "socket_path", "%s", socket_path); + format_add_tv(ft, "start_time", &start_time); return (ft); } diff --git a/server.c b/server.c index e9159422..d950ed77 100644 --- a/server.c +++ b/server.c @@ -187,7 +187,7 @@ server_start(struct event_base *base, int lockfd, char *lockfile) mode_key_init_trees(); key_bindings_init(); - start_time = time(NULL); + gettimeofday(&start_time, NULL); server_fd = server_create_socket(); if (server_fd == -1) diff --git a/tmux.1 b/tmux.1 index 455de33b..cba38264 100644 --- a/tmux.1 +++ b/tmux.1 @@ -740,7 +740,7 @@ Kill the .Nm server and clients and destroy all sessions. .It Xo Ic kill-session -.Op Fl a +.Op Fl aC .Op Fl t Ar target-session .Xc Destroy the given session, closing any windows linked to it and no other @@ -748,6 +748,10 @@ sessions, and detaching all clients attached to it. If .Fl a is given, all sessions but the specified one is killed. +The +.Fl C +clears alerts (bell, activity, or silence) in all windows linked to the +session. .It Xo Ic list-clients .Op Fl F Ar format .Op Fl t Ar target-session @@ -887,7 +891,7 @@ is specified, only update the client's status bar. Rename the session to .Ar new-name . .It Xo Ic show-messages -.Op Fl IJT +.Op Fl JT .Op Fl t Ar target-client .Xc .D1 (alias: Ic showmsgs ) @@ -900,11 +904,10 @@ With .Fl t , display the log for .Ar target-client . -.Fl I , .Fl J and .Fl T -show debugging information about the running server, jobs and terminals. +show debugging information about jobs and terminals. .It Ic source-file Ar path .D1 (alias: Ic source ) Execute commands from @@ -3410,6 +3413,7 @@ The following variables are available, where appropriate: .It Li "session_name" Ta "#S" Ta "Name of session" .It Li "session_width" Ta "" Ta "Width of session" .It Li "session_windows" Ta "" Ta "Number of windows in session" +.It Li "start_time" Ta "" Ta "Server start time" .It Li "window_activity" Ta "" Ta "Integer time of window last activity" .It Li "window_active" Ta "" Ta "1 if window active" .It Li "window_bell_flag" Ta "" Ta "1 if window has bell" diff --git a/tmux.c b/tmux.c index f5383fcf..7e89d526 100644 --- a/tmux.c +++ b/tmux.c @@ -44,7 +44,7 @@ struct options *global_w_options; /* window options */ struct environ *global_environ; char *shell_cmd; -time_t start_time; +struct timeval start_time; char socket_path[PATH_MAX]; __dead void usage(void); diff --git a/tmux.h b/tmux.h index 5f469f92..97908d98 100644 --- a/tmux.h +++ b/tmux.h @@ -1431,9 +1431,9 @@ extern struct options *global_options; extern struct options *global_s_options; extern struct options *global_w_options; extern struct environ *global_environ; -extern char *shell_cmd; -extern time_t start_time; -extern char socket_path[PATH_MAX]; +extern char *shell_cmd; +extern struct timeval start_time; +extern char socket_path[PATH_MAX]; const char *getshell(void); int checkshell(const char *); int areshell(const char *); From bef217b241ec50d6aed87dbb3604acd1bdb74121 Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 24 Nov 2015 22:04:36 +0000 Subject: [PATCH 07/15] Switch a fprintf to a fatal, and wrap some long lines. --- client.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/client.c b/client.c index 53a98a30..fcb704fb 100644 --- a/client.c +++ b/client.c @@ -303,11 +303,8 @@ client_main(struct event_base *base, int argc, char **argv, int flags) event_set(&client_stdin, STDIN_FILENO, EV_READ|EV_PERSIST, client_stdin_callback, NULL); if (client_flags & CLIENT_CONTROLCONTROL) { - if (tcgetattr(STDIN_FILENO, &saved_tio) != 0) { - fprintf(stderr, "tcgetattr failed: %s\n", - strerror(errno)); - return (1); - } + if (tcgetattr(STDIN_FILENO, &saved_tio) != 0) + fatal("tcgetattr failed"); cfmakeraw(&tio); tio.c_iflag = ICRNL|IXANY; tio.c_oflag = OPOST|ONLCR; @@ -389,7 +386,8 @@ client_send_identify(const char *ttynam, const char *cwd) s = ""; proc_send(client_peer, MSG_IDENTIFY_TERM, -1, s, strlen(s) + 1); - proc_send(client_peer, MSG_IDENTIFY_TTYNAME, -1, ttynam, strlen(ttynam) + 1); + proc_send(client_peer, MSG_IDENTIFY_TTYNAME, -1, ttynam, + strlen(ttynam) + 1); proc_send(client_peer, MSG_IDENTIFY_CWD, -1, cwd, strlen(cwd) + 1); if ((fd = dup(STDIN_FILENO)) == -1) @@ -401,8 +399,9 @@ client_send_identify(const char *ttynam, const char *cwd) for (ss = environ; *ss != NULL; ss++) { sslen = strlen(*ss) + 1; - if (sslen <= MAX_IMSGSIZE - IMSG_HEADER_SIZE) - proc_send(client_peer, MSG_IDENTIFY_ENVIRON, -1, *ss, sslen); + if (sslen > MAX_IMSGSIZE - IMSG_HEADER_SIZE) + continue; + proc_send(client_peer, MSG_IDENTIFY_ENVIRON, -1, *ss, sslen); } proc_send(client_peer, MSG_IDENTIFY_DONE, -1, NULL, 0); From 8976dac9e0c2e55b240ad55f4f7fa0a3b887c0e2 Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 24 Nov 2015 22:09:53 +0000 Subject: [PATCH 08/15] Remove malloc_options DEBUG bit. --- tmux.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/tmux.c b/tmux.c index 7e89d526..c515ebb2 100644 --- a/tmux.c +++ b/tmux.c @@ -34,10 +34,6 @@ #include "tmux.h" -#ifdef DEBUG -extern char *malloc_options; -#endif - struct options *global_options; /* server options */ struct options *global_s_options; /* session options */ struct options *global_w_options; /* window options */ @@ -182,10 +178,6 @@ main(int argc, char **argv) const char *s; int opt, flags, keys; -#ifdef DEBUG - malloc_options = (char *) "AFGJPX"; -#endif - setlocale(LC_TIME, ""); tzset(); From c913fb99b6f0f7d08b77d8d021df7d7fa27f82d0 Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 24 Nov 2015 22:27:22 +0000 Subject: [PATCH 09/15] Tidy the code that works out the socket path, and just use the full path in the global socket_path rather than copying it. --- client.c | 4 +-- tmux.c | 86 +++++++++++++++++++++++++------------------------------- tmux.h | 2 +- 3 files changed, 42 insertions(+), 50 deletions(-) diff --git a/client.c b/client.c index fcb704fb..595aff9b 100644 --- a/client.c +++ b/client.c @@ -55,7 +55,7 @@ int client_attached; __dead void client_exec(const char *); int client_get_lock(char *); -int client_connect(struct event_base *, char *, int); +int client_connect(struct event_base *, const char *, int); void client_send_identify(const char *, const char *); void client_stdin_callback(int, short, void *); void client_write(int, const char *, size_t); @@ -96,7 +96,7 @@ client_get_lock(char *lockfile) /* Connect client to server. */ int -client_connect(struct event_base *base, char *path, int start_server) +client_connect(struct event_base *base, const char *path, int start_server) { struct sockaddr_un sa; size_t size; diff --git a/tmux.c b/tmux.c index c515ebb2..f2143755 100644 --- a/tmux.c +++ b/tmux.c @@ -41,10 +41,10 @@ struct environ *global_environ; char *shell_cmd; struct timeval start_time; -char socket_path[PATH_MAX]; +const char *socket_path; __dead void usage(void); -char *makesocketpath(const char *); +static char *make_label(const char *); __dead void usage(void) @@ -102,38 +102,48 @@ areshell(const char *shell) return (0); } -char * -makesocketpath(const char *label) +static char * +make_label(const char *label) { - char base[PATH_MAX], realbase[PATH_MAX], *path, *s; - struct stat sb; - u_int uid; + char *base, resolved[PATH_MAX], *path, *s; + struct stat sb; + u_int uid; + int saved_errno; + + if (label == NULL) + label = "default"; uid = getuid(); + if ((s = getenv("TMUX_TMPDIR")) != NULL && *s != '\0') - xsnprintf(base, sizeof base, "%s/tmux-%u", s, uid); + xasprintf(&base, "%s/tmux-%u", s, uid); else - xsnprintf(base, sizeof base, "%s/tmux-%u", _PATH_TMP, uid); + xasprintf(&base, "%s/tmux-%u", _PATH_TMP, uid); if (mkdir(base, S_IRWXU) != 0 && errno != EEXIST) - return (NULL); + goto fail; if (lstat(base, &sb) != 0) - return (NULL); + goto fail; if (!S_ISDIR(sb.st_mode)) { errno = ENOTDIR; - return (NULL); + goto fail; } if (sb.st_uid != uid || (sb.st_mode & S_IRWXO) != 0) { errno = EACCES; - return (NULL); + goto fail; } - if (realpath(base, realbase) == NULL) - strlcpy(realbase, base, sizeof realbase); - - xasprintf(&path, "%s/%s", realbase, label); + if (realpath(base, resolved) == NULL) + strlcpy(resolved, base, sizeof resolved); + xasprintf(&path, "%s/%s", resolved, label); return (path); + +fail: + saved_errno = errno; + free(base); + errno = saved_errno; + return (NULL); } void @@ -289,41 +299,23 @@ main(int argc, char **argv) } /* - * Figure out the socket path. If specified on the command-line with -S - * or -L, use it, otherwise try $TMUX or assume -L default. + * If socket is specified on the command-line with -S or -L, it is + * used. Otherwise, $TMUX is checked and if that fails "default" is + * used. */ - if (path == NULL) { - /* If no -L, use the environment. */ - if (label == NULL) { - s = getenv("TMUX"); - if (s != NULL) { - path = xstrdup(s); - path[strcspn (path, ",")] = '\0'; - if (*path == '\0') { - free(path); - label = xstrdup("default"); - } - } else - label = xstrdup("default"); - } - - /* -L or default set. */ - if (label != NULL) { - if ((path = makesocketpath(label)) == NULL) { - fprintf(stderr, "can't create socket: %s\n", - strerror(errno)); - exit(1); - } + if (path == NULL && label == NULL) { + s = getenv("TMUX"); + if (s != NULL && *s != '\0' && *s != ',') { + path = xstrdup(s); + path[strcspn (path, ",")] = '\0'; } } - free(label); - - if (strlcpy(socket_path, path, sizeof socket_path) >= - sizeof socket_path) { - fprintf(stderr, "socket path too long: %s\n", path); + if (path == NULL && (path = make_label(label)) == NULL) { + fprintf(stderr, "can't create socket: %s\n", strerror(errno)); exit(1); } - free(path); + socket_path = path; + free(label); /* Pass control to the client. */ exit(client_main(event_init(), argc, argv, flags)); diff --git a/tmux.h b/tmux.h index 97908d98..50d7fb03 100644 --- a/tmux.h +++ b/tmux.h @@ -1433,7 +1433,7 @@ extern struct options *global_w_options; extern struct environ *global_environ; extern char *shell_cmd; extern struct timeval start_time; -extern char socket_path[PATH_MAX]; +extern const char *socket_path; const char *getshell(void); int checkshell(const char *); int areshell(const char *); From c18fbefe93dfbc7525b27e0129f8a0e8e9b70117 Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 24 Nov 2015 22:27:59 +0000 Subject: [PATCH 10/15] Document socket_path format. --- tmux.1 | 1 + 1 file changed, 1 insertion(+) diff --git a/tmux.1 b/tmux.1 index cba38264..8fa6ad55 100644 --- a/tmux.1 +++ b/tmux.1 @@ -3413,6 +3413,7 @@ The following variables are available, where appropriate: .It Li "session_name" Ta "#S" Ta "Name of session" .It Li "session_width" Ta "" Ta "Width of session" .It Li "session_windows" Ta "" Ta "Number of windows in session" +.It Li "socket_path" Ta "" "Server socket path" .It Li "start_time" Ta "" Ta "Server start time" .It Li "window_activity" Ta "" Ta "Integer time of window last activity" .It Li "window_active" Ta "" Ta "1 if window active" From 73e30cbda8ade3a1c7ba3b771a911545826f76b7 Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 24 Nov 2015 22:45:44 +0000 Subject: [PATCH 11/15] Actually show something (even if it not that helpful) if the server fails to start (for example if it can't create the socket), rather than hanging or showing nothing. --- client.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/client.c b/client.c index 595aff9b..5fdfd029 100644 --- a/client.c +++ b/client.c @@ -76,8 +76,12 @@ client_get_lock(char *lockfile) { int lockfd; - if ((lockfd = open(lockfile, O_WRONLY|O_CREAT, 0600)) == -1) - fatal("open failed"); + if ((lockfd = open(lockfile, O_WRONLY|O_CREAT, 0600)) == -1) { + lockfd = open("/dev/null", O_WRONLY); + if (lockfd == -1) + fatal("open failed"); + return (lockfd); + } log_debug("lock file is %s", lockfile); if (flock(lockfd, LOCK_EX|LOCK_NB) == -1) { @@ -114,10 +118,10 @@ client_connect(struct event_base *base, const char *path, int start_server) retry: if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) - fatal("socket failed"); + return (-1); log_debug("trying connect"); - if (connect(fd, (struct sockaddr *) &sa, sizeof(sa)) == -1) { + if (connect(fd, (struct sockaddr *)&sa, sizeof sa) == -1) { log_debug("connect failed: %s", strerror(errno)); if (errno != ECONNREFUSED && errno != ENOENT) goto failed; @@ -255,6 +259,9 @@ client_main(struct event_base *base, int argc, char **argv, int flags) cmd_list_free(cmdlist); } + /* Create client process structure (starts logging). */ + client_proc = proc_start("client", base, 0, client_signal); + /* Initialize the client socket and start the server. */ fd = client_connect(base, socket_path, cmdflags & CMD_STARTSERVER); if (fd == -1) { @@ -267,9 +274,6 @@ client_main(struct event_base *base, int argc, char **argv, int flags) } return (1); } - - /* Build process state. */ - client_proc = proc_start("client", base, 0, client_signal); client_peer = proc_add_peer(client_proc, fd, client_dispatch, NULL); /* Save these before pledge(). */ @@ -365,7 +369,8 @@ client_main(struct event_base *base, int argc, char **argv, int flags) printf("%%exit\n"); printf("\033\\"); tcsetattr(STDOUT_FILENO, TCSAFLUSH, &saved_tio); - } + } else + fprintf(stderr, "%s\n", client_exit_message()); setblocking(STDIN_FILENO, 1); return (client_exitval); } @@ -517,7 +522,11 @@ client_dispatch(struct imsg *imsg, __unused void *arg) if (imsg == NULL) { client_exitreason = CLIENT_EXIT_LOST_SERVER; client_exitval = 1; - } else if (client_attached) + proc_exit(client_proc); + return; + } + + if (client_attached) client_dispatch_attached(imsg); else client_dispatch_wait(imsg); From dca93c56e05ce631dd2f80da759f40c4d4b20ab5 Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 24 Nov 2015 23:01:51 +0000 Subject: [PATCH 12/15] Do lock failures slightly better, return a special value so we don't unlink the wrong thing. --- client.c | 34 ++++++++++++++++++---------------- server.c | 8 +++++--- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/client.c b/client.c index 5fdfd029..8144dd1c 100644 --- a/client.c +++ b/client.c @@ -67,23 +67,21 @@ const char *client_exit_message(void); /* * Get server create lock. If already held then server start is happening in - * another client, so block until the lock is released and return -1 to - * retry. Ignore other errors - just continue and start the server without the - * lock. + * another client, so block until the lock is released and return -2 to + * retry. Return -1 on failure to continue and start the server anyway. */ int client_get_lock(char *lockfile) { int lockfd; - if ((lockfd = open(lockfile, O_WRONLY|O_CREAT, 0600)) == -1) { - lockfd = open("/dev/null", O_WRONLY); - if (lockfd == -1) - fatal("open failed"); - return (lockfd); - } log_debug("lock file is %s", lockfile); + if ((lockfd = open(lockfile, O_WRONLY|O_CREAT, 0600)) == -1) { + log_debug("open failed: %s", strerror(errno)); + return (-1); + } + if (flock(lockfd, LOCK_EX|LOCK_NB) == -1) { log_debug("flock failed: %s", strerror(errno)); if (errno != EAGAIN) @@ -91,7 +89,7 @@ client_get_lock(char *lockfile) while (flock(lockfd, LOCK_EX) == -1 && errno == EINTR) /* nothing */; close(lockfd); - return (-1); + return (-2); } log_debug("flock succeeded"); @@ -131,12 +129,16 @@ retry: if (!locked) { xasprintf(&lockfile, "%s.lock", path); - if ((lockfd = client_get_lock(lockfile)) == -1) { - log_debug("didn't get lock"); + if ((lockfd = client_get_lock(lockfile)) < 0) { + log_debug("didn't get lock (%d)", lockfd); + free(lockfile); - goto retry; + lockfile = NULL; + + if (lockfd == -2) + goto retry; } - log_debug("got lock"); + log_debug("got lock (%d)", lockfd); /* * Always retry at least once, even if we got the lock, @@ -148,7 +150,7 @@ retry: goto retry; } - if (unlink(path) != 0 && errno != ENOENT) { + if (lockfd >= 0 && unlink(path) != 0 && errno != ENOENT) { free(lockfile); close(lockfd); return (-1); @@ -156,7 +158,7 @@ retry: fd = server_start(base, lockfd, lockfile); } - if (locked) { + if (locked && lockfd >= 0) { free(lockfile); close(lockfd); } diff --git a/server.c b/server.c index d950ed77..c45e8a2c 100644 --- a/server.c +++ b/server.c @@ -195,9 +195,11 @@ server_start(struct event_base *base, int lockfd, char *lockfile) server_update_socket(); server_client_create(pair[1]); - unlink(lockfile); - free(lockfile); - close(lockfd); + if (lockfd >= 0) { + unlink(lockfile); + free(lockfile); + close(lockfd); + } start_cfg(); From 3ff46b2e43d48376f74c0fd74b5616925d4063f0 Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 24 Nov 2015 23:22:51 +0000 Subject: [PATCH 13/15] Shell command from -c doesn't have to be global, pass it as an argument. --- client.c | 26 ++++++++++++++------------ tmux.c | 11 +++++------ tmux.h | 3 +-- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/client.c b/client.c index 8144dd1c..5987efa5 100644 --- a/client.c +++ b/client.c @@ -53,7 +53,7 @@ enum msgtype client_exittype; const char *client_exitsession; int client_attached; -__dead void client_exec(const char *); +__dead void client_exec(const char *,const char *); int client_get_lock(char *); int client_connect(struct event_base *, const char *, int); void client_send_identify(const char *, const char *); @@ -62,7 +62,7 @@ void client_write(int, const char *, size_t); void client_signal(int); void client_dispatch(struct imsg *, void *); void client_dispatch_attached(struct imsg *); -void client_dispatch_wait(struct imsg *); +void client_dispatch_wait(struct imsg *, const char *); const char *client_exit_message(void); /* @@ -213,7 +213,8 @@ client_exit_message(void) /* Client main loop. */ int -client_main(struct event_base *base, int argc, char **argv, int flags) +client_main(struct event_base *base, int argc, char **argv, int flags, + const char *shellcmd) { struct cmd *cmd; struct cmd_list *cmdlist; @@ -234,7 +235,7 @@ client_main(struct event_base *base, int argc, char **argv, int flags) /* Set up the initial command. */ cmdflags = 0; - if (shell_cmd != NULL) { + if (shellcmd != NULL) { msg = MSG_SHELL; cmdflags = CMD_STARTSERVER; } else if (argc == 0) { @@ -276,7 +277,8 @@ client_main(struct event_base *base, int argc, char **argv, int flags) } return (1); } - client_peer = proc_add_peer(client_proc, fd, client_dispatch, NULL); + client_peer = proc_add_peer(client_proc, fd, client_dispatch, + (void *)shellcmd); /* Save these before pledge(). */ if ((cwd = getcwd(path, sizeof path)) == NULL) { @@ -450,12 +452,12 @@ client_write(int fd, const char *data, size_t size) /* Run command in shell; used for -c. */ __dead void -client_exec(const char *shell) +client_exec(const char *shell, const char *shellcmd) { const char *name, *ptr; char *argv0; - log_debug("shell %s, command %s", shell, shell_cmd); + log_debug("shell %s, command %s", shell, shellcmd); ptr = strrchr(shell, '/'); if (ptr != NULL && *(ptr + 1) != '\0') @@ -473,7 +475,7 @@ client_exec(const char *shell) setblocking(STDERR_FILENO, 1); closefrom(STDERR_FILENO + 1); - execl(shell, argv0, "-c", shell_cmd, (char *) NULL); + execl(shell, argv0, "-c", shellcmd, (char *) NULL); fatal("execl failed"); } @@ -519,7 +521,7 @@ client_signal(int sig) /* Callback for client read events. */ void -client_dispatch(struct imsg *imsg, __unused void *arg) +client_dispatch(struct imsg *imsg, void *arg) { if (imsg == NULL) { client_exitreason = CLIENT_EXIT_LOST_SERVER; @@ -531,12 +533,12 @@ client_dispatch(struct imsg *imsg, __unused void *arg) if (client_attached) client_dispatch_attached(imsg); else - client_dispatch_wait(imsg); + client_dispatch_wait(imsg, arg); } /* Dispatch imsgs when in wait state (before MSG_READY). */ void -client_dispatch_wait(struct imsg *imsg) +client_dispatch_wait(struct imsg *imsg, const char *shellcmd) { char *data; ssize_t datalen; @@ -616,7 +618,7 @@ client_dispatch_wait(struct imsg *imsg) fatalx("bad MSG_SHELL string"); clear_signals(0); - client_exec(data); + client_exec(data, shellcmd); /* NOTREACHED */ case MSG_DETACH: case MSG_DETACHKILL: diff --git a/tmux.c b/tmux.c index f2143755..7d49dd30 100644 --- a/tmux.c +++ b/tmux.c @@ -39,7 +39,6 @@ struct options *global_s_options; /* session options */ struct options *global_w_options; /* window options */ struct environ *global_environ; -char *shell_cmd; struct timeval start_time; const char *socket_path; @@ -184,7 +183,7 @@ find_home(void) int main(int argc, char **argv) { - char *path, *label, **var, tmp[PATH_MAX]; + char *path, *label, **var, tmp[PATH_MAX], *shellcmd = NULL; const char *s; int opt, flags, keys; @@ -203,8 +202,8 @@ main(int argc, char **argv) flags |= CLIENT_256COLOURS; break; case 'c': - free(shell_cmd); - shell_cmd = xstrdup(optarg); + free(shellcmd); + shellcmd = xstrdup(optarg); break; case 'C': if (flags & CLIENT_CONTROL) @@ -241,7 +240,7 @@ main(int argc, char **argv) argc -= optind; argv += optind; - if (shell_cmd != NULL && argc != 0) + if (shellcmd != NULL && argc != 0) usage(); if (pledge("stdio rpath wpath cpath flock fattr unix getpw sendfd " @@ -318,5 +317,5 @@ main(int argc, char **argv) free(label); /* Pass control to the client. */ - exit(client_main(event_init(), argc, argv, flags)); + exit(client_main(event_init(), argc, argv, flags, shellcmd)); } diff --git a/tmux.h b/tmux.h index 50d7fb03..f4638bc8 100644 --- a/tmux.h +++ b/tmux.h @@ -1431,7 +1431,6 @@ extern struct options *global_options; extern struct options *global_s_options; extern struct options *global_w_options; extern struct environ *global_environ; -extern char *shell_cmd; extern struct timeval start_time; extern const char *socket_path; const char *getshell(void); @@ -1732,7 +1731,7 @@ int cmd_string_parse(const char *, struct cmd_list **, const char *, void cmd_wait_for_flush(void); /* client.c */ -int client_main(struct event_base *, int, char **, int); +int client_main(struct event_base *, int, char **, int, const char *); /* key-bindings.c */ RB_PROTOTYPE(key_bindings, key_binding, entry, key_bindings_cmp); From 62d3af17f9e6aec244ab1d91c1c46fdbbf6f8a86 Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 24 Nov 2015 23:46:15 +0000 Subject: [PATCH 14/15] Make environ_set va_args and use it to tidy up some calls. Also add a missing word in manpage (from jmc). --- cmd-set-environment.c | 4 ++-- environ.c | 46 ++++++++++++++++++++++++++++++------------- server-fn.c | 11 +++++------ tmux.1 | 2 +- tmux.c | 2 +- tmux.h | 6 ++++-- window.c | 7 +++---- 7 files changed, 48 insertions(+), 30 deletions(-) diff --git a/cmd-set-environment.c b/cmd-set-environment.c index 864e1d9b..2c0010af 100644 --- a/cmd-set-environment.c +++ b/cmd-set-environment.c @@ -79,13 +79,13 @@ cmd_set_environment_exec(struct cmd *self, struct cmd_q *cmdq) cmdq_error(cmdq, "can't specify a value with -r"); return (CMD_RETURN_ERROR); } - environ_set(env, name, NULL); + environ_clear(env, name); } else { if (value == NULL) { cmdq_error(cmdq, "no value specified"); return (CMD_RETURN_ERROR); } - environ_set(env, name, value); + environ_set(env, name, "%s", value); } return (CMD_RETURN_NORMAL); diff --git a/environ.c b/environ.c index 43a9ce01..de560896 100644 --- a/environ.c +++ b/environ.c @@ -83,8 +83,12 @@ environ_copy(struct environ *srcenv, struct environ *dstenv) { struct environ_entry *envent; - RB_FOREACH(envent, environ, srcenv) - environ_set(dstenv, envent->name, envent->value); + RB_FOREACH(envent, environ, srcenv) { + if (envent->value == NULL) + environ_clear(dstenv, envent->name); + else + environ_set(dstenv, envent->name, "%s", envent->value); + } } /* Find an environment variable. */ @@ -99,23 +103,37 @@ environ_find(struct environ *env, const char *name) /* Set an environment variable. */ void -environ_set(struct environ *env, const char *name, const char *value) +environ_set(struct environ *env, const char *name, const char *fmt, ...) +{ + struct environ_entry *envent; + va_list ap; + + va_start(ap, fmt); + if ((envent = environ_find(env, name)) != NULL) { + free(envent->value); + xvasprintf(&envent->value, fmt, ap); + } else { + envent = xmalloc(sizeof *envent); + envent->name = xstrdup(name); + xvasprintf(&envent->value, fmt, ap); + RB_INSERT(environ, env, envent); + } + va_end(ap); +} + +/* Clear an environment variable. */ +void +environ_clear(struct environ *env, const char *name) { struct environ_entry *envent; if ((envent = environ_find(env, name)) != NULL) { free(envent->value); - if (value != NULL) - envent->value = xstrdup(value); - else - envent->value = NULL; + envent->value = NULL; } else { envent = xmalloc(sizeof *envent); envent->name = xstrdup(name); - if (value != NULL) - envent->value = xstrdup(value); - else - envent->value = NULL; + envent->value = NULL; RB_INSERT(environ, env, envent); } } @@ -134,7 +152,7 @@ environ_put(struct environ *env, const char *var) name = xstrdup(var); name[strcspn(name, "=")] = '\0'; - environ_set(env, name, value); + environ_set(env, name, "%s", value); free(name); } @@ -166,9 +184,9 @@ environ_update(const char *vars, struct environ *srcenv, copyvars = next = xstrdup(vars); while ((var = strsep(&next, " ")) != NULL) { if ((envent = environ_find(srcenv, var)) == NULL) - environ_set(dstenv, var, NULL); + environ_clear(dstenv, var); else - environ_set(dstenv, envent->name, envent->value); + environ_set(dstenv, envent->name, "%s", envent->value); } free(copyvars); } diff --git a/server-fn.c b/server-fn.c index 3e4b6116..a22c964d 100644 --- a/server-fn.c +++ b/server-fn.c @@ -34,20 +34,19 @@ void server_callback_identify(int, short, void *); void server_fill_environ(struct session *s, struct environ *env) { - char var[PATH_MAX], *term; - u_int idx; - long pid; + char *term; + u_int idx; + long pid; if (s != NULL) { term = options_get_string(global_options, "default-terminal"); - environ_set(env, "TERM", term); + environ_set(env, "TERM", "%s", term); idx = s->id; } else idx = (u_int)-1; pid = getpid(); - xsnprintf(var, sizeof var, "%s,%ld,%u", socket_path, pid, idx); - environ_set(env, "TMUX", var); + environ_set(env, "TMUX", "%s,%ld,%u", socket_path, pid, idx); } void diff --git a/tmux.1 b/tmux.1 index 8fa6ad55..454af1d2 100644 --- a/tmux.1 +++ b/tmux.1 @@ -750,7 +750,7 @@ If is given, all sessions but the specified one is killed. The .Fl C -clears alerts (bell, activity, or silence) in all windows linked to the +flag clears alerts (bell, activity, or silence) in all windows linked to the session. .It Xo Ic list-clients .Op Fl F Ar format diff --git a/tmux.c b/tmux.c index 7d49dd30..68f0092d 100644 --- a/tmux.c +++ b/tmux.c @@ -273,7 +273,7 @@ main(int argc, char **argv) for (var = environ; *var != NULL; var++) environ_put(global_environ, *var); if (getcwd(tmp, sizeof tmp) != NULL) - environ_set(global_environ, "PWD", tmp); + environ_set(global_environ, "PWD", "%s", tmp); global_options = options_create(NULL); options_table_populate_tree(OPTIONS_TABLE_SERVER, global_options); diff --git a/tmux.h b/tmux.h index f4638bc8..2acfc75f 100644 --- a/tmux.h +++ b/tmux.h @@ -1567,7 +1567,9 @@ struct environ_entry *environ_first(struct environ *); struct environ_entry *environ_next(struct environ_entry *); void environ_copy(struct environ *, struct environ *); struct environ_entry *environ_find(struct environ *, const char *); -void environ_set(struct environ *, const char *, const char *); +void printflike(3, 4) environ_set(struct environ *, const char *, const char *, + ...); +void environ_clear(struct environ *, const char *); void environ_put(struct environ *, const char *); void environ_unset(struct environ *, const char *); void environ_update(const char *, struct environ *, struct environ *); @@ -1739,7 +1741,7 @@ RB_PROTOTYPE(key_tables, key_table, entry, key_table_cmp); extern struct key_tables key_tables; int key_table_cmp(struct key_table *, struct key_table *); int key_bindings_cmp(struct key_binding *, struct key_binding *); -struct key_table *key_bindings_get_table(const char *, int); +struct key_table *key_bindings_get_table(const char *, int); void key_bindings_unref_table(struct key_table *); void key_bindings_add(const char *, key_code, int, struct cmd_list *); void key_bindings_remove(const char *, key_code); diff --git a/window.c b/window.c index 8ee517a1..deda2895 100644 --- a/window.c +++ b/window.c @@ -808,7 +808,7 @@ window_pane_spawn(struct window_pane *wp, int argc, char **argv, struct termios *tio, char **cause) { struct winsize ws; - char *argv0, *cmd, **argvp, paneid[16]; + char *argv0, *cmd, **argvp; const char *ptr, *first, *home; struct termios tio2; int i; @@ -863,9 +863,8 @@ window_pane_spawn(struct window_pane *wp, int argc, char **argv, closefrom(STDERR_FILENO + 1); if (path != NULL) - environ_set(env, "PATH", path); - xsnprintf(paneid, sizeof paneid, "%%%u", wp->id); - environ_set(env, "TMUX_PANE", paneid); + environ_set(env, "PATH", "%s", path); + environ_set(env, "TMUX_PANE", "%%%u", wp->id); environ_push(env); clear_signals(1); From ac8678aefe157d7e40c5bcedd12333eaedf0df92 Mon Sep 17 00:00:00 2001 From: nicm Date: Wed, 25 Nov 2015 07:58:55 +0000 Subject: [PATCH 15/15] Don't print error if none to print. --- client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client.c b/client.c index 5987efa5..516ed3bf 100644 --- a/client.c +++ b/client.c @@ -373,7 +373,7 @@ client_main(struct event_base *base, int argc, char **argv, int flags, printf("%%exit\n"); printf("\033\\"); tcsetattr(STDOUT_FILENO, TCSAFLUSH, &saved_tio); - } else + } else if (client_exitreason != CLIENT_EXIT_NONE) fprintf(stderr, "%s\n", client_exit_message()); setblocking(STDIN_FILENO, 1); return (client_exitval);