mirror of
https://github.com/tmux/tmux.git
synced 2025-03-25 23:38:48 +00:00
Add a flag to make a client wait for an empty line before exiting in
control mode to avoid stray commands ending up in the shell.
This commit is contained in:
parent
1bf9555e4f
commit
2372b0fdc6
38
client.c
38
client.c
@ -35,7 +35,7 @@
|
|||||||
|
|
||||||
static struct tmuxproc *client_proc;
|
static struct tmuxproc *client_proc;
|
||||||
static struct tmuxpeer *client_peer;
|
static struct tmuxpeer *client_peer;
|
||||||
static int client_flags;
|
static uint64_t client_flags;
|
||||||
static enum {
|
static enum {
|
||||||
CLIENT_EXIT_NONE,
|
CLIENT_EXIT_NONE,
|
||||||
CLIENT_EXIT_DETACHED,
|
CLIENT_EXIT_DETACHED,
|
||||||
@ -247,7 +247,9 @@ client_main(struct event_base *base, int argc, char **argv, int flags, int feat)
|
|||||||
pid_t ppid;
|
pid_t ppid;
|
||||||
enum msgtype msg;
|
enum msgtype msg;
|
||||||
struct termios tio, saved_tio;
|
struct termios tio, saved_tio;
|
||||||
size_t size;
|
size_t size, linesize = 0;
|
||||||
|
ssize_t linelen;
|
||||||
|
char *line = NULL;
|
||||||
|
|
||||||
/* Ignore SIGCHLD now or daemon() in the server will leave a zombie. */
|
/* Ignore SIGCHLD now or daemon() in the server will leave a zombie. */
|
||||||
signal(SIGCHLD, SIG_IGN);
|
signal(SIGCHLD, SIG_IGN);
|
||||||
@ -276,13 +278,14 @@ client_main(struct event_base *base, int argc, char **argv, int flags, int feat)
|
|||||||
free(pr->error);
|
free(pr->error);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Save the flags. */
|
|
||||||
client_flags = flags;
|
|
||||||
|
|
||||||
/* Create client process structure (starts logging). */
|
/* Create client process structure (starts logging). */
|
||||||
client_proc = proc_start("client");
|
client_proc = proc_start("client");
|
||||||
proc_set_signals(client_proc, client_signal);
|
proc_set_signals(client_proc, client_signal);
|
||||||
|
|
||||||
|
/* Save the flags. */
|
||||||
|
client_flags = flags;
|
||||||
|
log_debug("flags are %#llx", client_flags);
|
||||||
|
|
||||||
/* Initialize the client socket and start the server. */
|
/* Initialize the client socket and start the server. */
|
||||||
fd = client_connect(base, socket_path, client_flags);
|
fd = client_connect(base, socket_path, client_flags);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
@ -406,8 +409,19 @@ client_main(struct event_base *base, int argc, char **argv, int flags, int feat)
|
|||||||
printf("%%exit %s\n", client_exit_message());
|
printf("%%exit %s\n", client_exit_message());
|
||||||
else
|
else
|
||||||
printf("%%exit\n");
|
printf("%%exit\n");
|
||||||
|
fflush(stdout);
|
||||||
|
if (client_flags & CLIENT_CONTROL_WAITEXIT) {
|
||||||
|
setvbuf(stdin, NULL, _IOLBF, 0);
|
||||||
|
for (;;) {
|
||||||
|
linelen = getline(&line, &linesize, stdin);
|
||||||
|
if (linelen <= 1)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
free(line);
|
||||||
|
}
|
||||||
if (client_flags & CLIENT_CONTROLCONTROL) {
|
if (client_flags & CLIENT_CONTROLCONTROL) {
|
||||||
printf("\033\\");
|
printf("\033\\");
|
||||||
|
fflush(stdout);
|
||||||
tcsetattr(STDOUT_FILENO, TCSAFLUSH, &saved_tio);
|
tcsetattr(STDOUT_FILENO, TCSAFLUSH, &saved_tio);
|
||||||
}
|
}
|
||||||
} else if (client_exitreason != CLIENT_EXIT_NONE)
|
} else if (client_exitreason != CLIENT_EXIT_NONE)
|
||||||
@ -870,6 +884,13 @@ client_dispatch_wait(struct imsg *imsg)
|
|||||||
client_exitval = 1;
|
client_exitval = 1;
|
||||||
proc_exit(client_proc);
|
proc_exit(client_proc);
|
||||||
break;
|
break;
|
||||||
|
case MSG_FLAGS:
|
||||||
|
if (datalen != sizeof client_flags)
|
||||||
|
fatalx("bad MSG_FLAGS string");
|
||||||
|
|
||||||
|
memcpy(&client_flags, data, sizeof client_flags);
|
||||||
|
log_debug("new flags are %#llx", client_flags);
|
||||||
|
break;
|
||||||
case MSG_SHELL:
|
case MSG_SHELL:
|
||||||
if (datalen == 0 || data[datalen - 1] != '\0')
|
if (datalen == 0 || data[datalen - 1] != '\0')
|
||||||
fatalx("bad MSG_SHELL string");
|
fatalx("bad MSG_SHELL string");
|
||||||
@ -916,6 +937,13 @@ client_dispatch_attached(struct imsg *imsg)
|
|||||||
datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
|
datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
|
||||||
|
|
||||||
switch (imsg->hdr.type) {
|
switch (imsg->hdr.type) {
|
||||||
|
case MSG_FLAGS:
|
||||||
|
if (datalen != sizeof client_flags)
|
||||||
|
fatalx("bad MSG_FLAGS string");
|
||||||
|
|
||||||
|
memcpy(&client_flags, data, sizeof client_flags);
|
||||||
|
log_debug("new flags are %#llx", client_flags);
|
||||||
|
break;
|
||||||
case MSG_DETACH:
|
case MSG_DETACH:
|
||||||
case MSG_DETACHKILL:
|
case MSG_DETACHKILL:
|
||||||
if (datalen == 0 || data[datalen - 1] != '\0')
|
if (datalen == 0 || data[datalen - 1] != '\0')
|
||||||
|
@ -695,6 +695,7 @@ control_discard(struct client *c)
|
|||||||
|
|
||||||
RB_FOREACH(cp, control_panes, &cs->panes)
|
RB_FOREACH(cp, control_panes, &cs->panes)
|
||||||
control_discard_pane(c, cp);
|
control_discard_pane(c, cp);
|
||||||
|
bufferevent_disable(cs->read_event, EV_READ);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Stop control mode. */
|
/* Stop control mode. */
|
||||||
|
@ -2370,6 +2370,8 @@ server_client_control_flags(struct client *c, const char *next)
|
|||||||
}
|
}
|
||||||
if (strcmp(next, "no-output") == 0)
|
if (strcmp(next, "no-output") == 0)
|
||||||
return (CLIENT_CONTROL_NOOUTPUT);
|
return (CLIENT_CONTROL_NOOUTPUT);
|
||||||
|
if (strcmp(next, "wait-exit") == 0)
|
||||||
|
return (CLIENT_CONTROL_WAITEXIT);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2409,6 +2411,7 @@ server_client_set_flags(struct client *c, const char *flags)
|
|||||||
control_reset_offsets(c);
|
control_reset_offsets(c);
|
||||||
}
|
}
|
||||||
free(copy);
|
free(copy);
|
||||||
|
proc_send(c->peer, MSG_FLAGS, -1, &c->flags, sizeof c->flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get client flags. This is only flags useful to show to users. */
|
/* Get client flags. This is only flags useful to show to users. */
|
||||||
@ -2427,6 +2430,8 @@ server_client_get_flags(struct client *c)
|
|||||||
strlcat(s, "ignore-size,", sizeof s);
|
strlcat(s, "ignore-size,", sizeof s);
|
||||||
if (c->flags & CLIENT_CONTROL_NOOUTPUT)
|
if (c->flags & CLIENT_CONTROL_NOOUTPUT)
|
||||||
strlcat(s, "no-output,", sizeof s);
|
strlcat(s, "no-output,", sizeof s);
|
||||||
|
if (c->flags & CLIENT_CONTROL_WAITEXIT)
|
||||||
|
strlcat(s, "wait-exit,", sizeof s);
|
||||||
if (c->flags & CLIENT_CONTROL_PAUSEAFTER) {
|
if (c->flags & CLIENT_CONTROL_PAUSEAFTER) {
|
||||||
xsnprintf(tmp, sizeof tmp, "pause-after=%u,",
|
xsnprintf(tmp, sizeof tmp, "pause-after=%u,",
|
||||||
c->pause_age / 1000);
|
c->pause_age / 1000);
|
||||||
|
2
server.c
2
server.c
@ -45,7 +45,7 @@ struct clients clients;
|
|||||||
|
|
||||||
struct tmuxproc *server_proc;
|
struct tmuxproc *server_proc;
|
||||||
static int server_fd = -1;
|
static int server_fd = -1;
|
||||||
static int server_client_flags;
|
static uint64_t server_client_flags;
|
||||||
static int server_exit;
|
static int server_exit;
|
||||||
static struct event server_ev_accept;
|
static struct event server_ev_accept;
|
||||||
|
|
||||||
|
2
tmux.1
2
tmux.1
@ -989,6 +989,8 @@ output is paused once the pane is
|
|||||||
behind in control mode
|
behind in control mode
|
||||||
.It read-only
|
.It read-only
|
||||||
the client is read-only
|
the client is read-only
|
||||||
|
.It wait-exit
|
||||||
|
wait for an empty line input before exiting in control mode
|
||||||
.El
|
.El
|
||||||
.Pp
|
.Pp
|
||||||
A leading
|
A leading
|
||||||
|
2
tmux.h
2
tmux.h
@ -515,6 +515,7 @@ enum msgtype {
|
|||||||
MSG_UNLOCK,
|
MSG_UNLOCK,
|
||||||
MSG_WAKEUP,
|
MSG_WAKEUP,
|
||||||
MSG_EXEC,
|
MSG_EXEC,
|
||||||
|
MSG_FLAGS,
|
||||||
|
|
||||||
MSG_READ_OPEN = 300,
|
MSG_READ_OPEN = 300,
|
||||||
MSG_READ,
|
MSG_READ,
|
||||||
@ -1644,6 +1645,7 @@ struct client {
|
|||||||
#define CLIENT_NOFORK 0x40000000
|
#define CLIENT_NOFORK 0x40000000
|
||||||
#define CLIENT_ACTIVEPANE 0x80000000ULL
|
#define CLIENT_ACTIVEPANE 0x80000000ULL
|
||||||
#define CLIENT_CONTROL_PAUSEAFTER 0x100000000ULL
|
#define CLIENT_CONTROL_PAUSEAFTER 0x100000000ULL
|
||||||
|
#define CLIENT_CONTROL_WAITEXIT 0x200000000ULL
|
||||||
#define CLIENT_ALLREDRAWFLAGS \
|
#define CLIENT_ALLREDRAWFLAGS \
|
||||||
(CLIENT_REDRAWWINDOW| \
|
(CLIENT_REDRAWWINDOW| \
|
||||||
CLIENT_REDRAWSTATUS| \
|
CLIENT_REDRAWSTATUS| \
|
||||||
|
Loading…
Reference in New Issue
Block a user