summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Marriott <nicm@cvs.openbsd.org>2017-01-13 10:12:13 +0000
committerNicholas Marriott <nicm@cvs.openbsd.org>2017-01-13 10:12:13 +0000
commitdf7669d613887e329e34f9e6ef5a3c076023990a (patch)
tree1f9ab953958408f6cbe69a65c51980c8b62a42b9
parent3b59fd0c092b6e6705f0ddd99438bc35d391ff4c (diff)
Add -E to detach-client to exec a command to replace the client instead
of exiting it, useful if tmux wasn't exec'd itself. From Jenna Magius.
-rw-r--r--usr.bin/tmux/client.c22
-rw-r--r--usr.bin/tmux/cmd-detach-client.c29
-rw-r--r--usr.bin/tmux/server-client.c28
-rw-r--r--usr.bin/tmux/tmux.110
-rw-r--r--usr.bin/tmux/tmux.h4
5 files changed, 80 insertions, 13 deletions
diff --git a/usr.bin/tmux/client.c b/usr.bin/tmux/client.c
index f205c8e43e1..1eb9c8e0570 100644
--- a/usr.bin/tmux/client.c
+++ b/usr.bin/tmux/client.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: client.c,v 1.114 2016/10/03 22:52:11 nicm Exp $ */
+/* $OpenBSD: client.c,v 1.115 2017/01/13 10:12:12 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -51,6 +51,8 @@ static enum {
static int client_exitval;
static enum msgtype client_exittype;
static const char *client_exitsession;
+static const char *client_execshell;
+static const char *client_execcmd;
static int client_attached;
static __dead void client_exec(const char *,const char *);
@@ -358,6 +360,14 @@ client_main(struct event_base *base, int argc, char **argv, int flags,
/* Start main loop. */
proc_loop(client_proc, NULL);
+ /* Run command if user requested exec, instead of exiting. */
+ if (client_exittype == MSG_EXEC) {
+ if (client_flags & CLIENT_CONTROLCONTROL)
+ tcsetattr(STDOUT_FILENO, TCSAFLUSH, &saved_tio);
+ clear_signals(0);
+ client_exec(client_execshell, client_execcmd);
+ }
+
/* Print the exit message, if any, and exit. */
if (client_attached) {
if (client_exitreason != CLIENT_EXIT_NONE)
@@ -655,6 +665,16 @@ client_dispatch_attached(struct imsg *imsg)
client_exitreason = CLIENT_EXIT_DETACHED;
proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
break;
+ case MSG_EXEC:
+ if (datalen == 0 || data[datalen - 1] != '\0' ||
+ strlen(data) + 1 == (size_t)datalen)
+ fatalx("bad MSG_EXEC string");
+ client_execcmd = xstrdup(data);
+ client_execshell = xstrdup(data + strlen(data) + 1);
+
+ client_exittype = imsg->hdr.type;
+ proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
+ break;
case MSG_EXIT:
if (datalen != 0 && datalen != sizeof (int))
fatalx("bad MSG_EXIT size");
diff --git a/usr.bin/tmux/cmd-detach-client.c b/usr.bin/tmux/cmd-detach-client.c
index b67dd3a7a8f..ade9447a79c 100644
--- a/usr.bin/tmux/cmd-detach-client.c
+++ b/usr.bin/tmux/cmd-detach-client.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-detach-client.c,v 1.29 2016/10/16 19:04:05 nicm Exp $ */
+/* $OpenBSD: cmd-detach-client.c,v 1.30 2017/01/13 10:12:12 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -33,8 +33,9 @@ const struct cmd_entry cmd_detach_client_entry = {
.name = "detach-client",
.alias = "detach",
- .args = { "as:t:P", 0, 0 },
- .usage = "[-P] [-a] [-s target-session] " CMD_TARGET_CLIENT_USAGE,
+ .args = { "aE:s:t:P", 0, 0 },
+ .usage = "[-aP] [-E shell-command] "
+ "[-s target-session] " CMD_TARGET_CLIENT_USAGE,
.sflag = CMD_SESSION,
.tflag = CMD_CLIENT,
@@ -63,6 +64,7 @@ cmd_detach_client_exec(struct cmd *self, struct cmdq_item *item)
struct client *c = item->state.c, *cloop;
struct session *s;
enum msgtype msgtype;
+ const char *cmd = args_get(args, 'E');
if (self->entry == &cmd_suspend_client_entry) {
tty_stop_tty(&c->tty);
@@ -79,20 +81,31 @@ cmd_detach_client_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(args, 's')) {
s = item->state.sflag.s;
TAILQ_FOREACH(cloop, &clients, entry) {
- if (cloop->session == s)
- server_client_detach(cloop, msgtype);
+ if (cloop->session == s) {
+ if (cmd != NULL)
+ server_client_exec(cloop, cmd);
+ else
+ server_client_detach(cloop, msgtype);
+ }
}
return (CMD_RETURN_STOP);
}
if (args_has(args, 'a')) {
TAILQ_FOREACH(cloop, &clients, entry) {
- if (cloop->session != NULL && cloop != c)
- server_client_detach(cloop, msgtype);
+ if (cloop->session != NULL && cloop != c) {
+ if (cmd != NULL)
+ server_client_exec(cloop, cmd);
+ else
+ server_client_detach(cloop, msgtype);
+ }
}
return (CMD_RETURN_NORMAL);
}
- server_client_detach(c, msgtype);
+ if (cmd != NULL)
+ server_client_exec(c, cmd);
+ else
+ server_client_detach(c, msgtype);
return (CMD_RETURN_STOP);
}
diff --git a/usr.bin/tmux/server-client.c b/usr.bin/tmux/server-client.c
index aa808a2d129..51a89a1b9b8 100644
--- a/usr.bin/tmux/server-client.c
+++ b/usr.bin/tmux/server-client.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: server-client.c,v 1.206 2017/01/11 22:36:07 nicm Exp $ */
+/* $OpenBSD: server-client.c,v 1.207 2017/01/13 10:12:12 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -296,6 +296,32 @@ server_client_detach(struct client *c, enum msgtype msgtype)
proc_send_s(c->peer, msgtype, s->name);
}
+/* Execute command to replace a client, */
+void
+server_client_exec(struct client *c, const char *cmd)
+{
+ struct session *s = c->session;
+ char *msg, *shell;
+ size_t cmdsize, shellsize;
+
+ if (*cmd == '\0')
+ return;
+ cmdsize = strlen(cmd) + 1;
+
+ if (s != NULL)
+ shell = options_get_string(s->options, "default-shell");
+ else
+ shell = options_get_string(global_s_options, "default-shell");
+ shellsize = strlen(shell) + 1;
+
+ msg = xmalloc(cmdsize + shellsize);
+ memcpy(msg, cmd, cmdsize);
+ memcpy(msg + cmdsize, shell, shellsize);
+
+ proc_send(c->peer, MSG_EXEC, -1, msg, cmdsize + shellsize);
+ free(msg);
+}
+
/* Check for mouse keys. */
static key_code
server_client_check_mouse(struct client *c)
diff --git a/usr.bin/tmux/tmux.1 b/usr.bin/tmux/tmux.1
index 6f951e11c3e..ab3d3d5fc84 100644
--- a/usr.bin/tmux/tmux.1
+++ b/usr.bin/tmux/tmux.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: tmux.1,v 1.524 2017/01/11 16:09:57 nicm Exp $
+.\" $OpenBSD: tmux.1,v 1.525 2017/01/13 10:12:12 nicm Exp $
.\"
.\" Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
.\"
@@ -14,7 +14,7 @@
.\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
.\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: January 11 2017 $
+.Dd $Mdocdate: January 13 2017 $
.Dt TMUX 1
.Os
.Sh NAME
@@ -724,6 +724,7 @@ is used, the
option will not be applied.
.It Xo Ic detach-client
.Op Fl aP
+.Op Fl E Ar shell-command
.Op Fl s Ar target-session
.Op Fl t Ar target-client
.Xc
@@ -740,6 +741,11 @@ If
.Fl P
is given, send SIGHUP to the parent process of the client, typically causing it
to exit.
+With
+.Fl E ,
+run
+.Ar shell-command
+to replace the client.
.It Ic has-session Op Fl t Ar target-session
.D1 (alias: Ic has )
Report an error and exit with 1 if the specified session does not exist.
diff --git a/usr.bin/tmux/tmux.h b/usr.bin/tmux/tmux.h
index df3ff0b550f..daee5b2e96c 100644
--- a/usr.bin/tmux/tmux.h
+++ b/usr.bin/tmux/tmux.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: tmux.h,v 1.693 2017/01/12 15:36:35 nicm Exp $ */
+/* $OpenBSD: tmux.h,v 1.694 2017/01/13 10:12:12 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -443,6 +443,7 @@ enum msgtype {
MSG_SUSPEND,
MSG_UNLOCK,
MSG_WAKEUP,
+ MSG_EXEC,
};
/*
@@ -1880,6 +1881,7 @@ int server_client_open(struct client *, char **);
void server_client_unref(struct client *);
void server_client_lost(struct client *);
void server_client_detach(struct client *, enum msgtype);
+void server_client_exec(struct client *, const char *);
void server_client_loop(void);
void server_client_push_stdout(struct client *);
void server_client_push_stderr(struct client *);