mirror of
				https://github.com/tmux/tmux.git
				synced 2025-11-04 01:34:18 +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:
		
							
								
								
									
										38
									
								
								client.c
									
									
									
									
									
								
							
							
						
						
									
										38
									
								
								client.c
									
									
									
									
									
								
							@@ -35,7 +35,7 @@
 | 
			
		||||
 | 
			
		||||
static struct tmuxproc	*client_proc;
 | 
			
		||||
static struct tmuxpeer	*client_peer;
 | 
			
		||||
static int		 client_flags;
 | 
			
		||||
static uint64_t		 client_flags;
 | 
			
		||||
static enum {
 | 
			
		||||
	CLIENT_EXIT_NONE,
 | 
			
		||||
	CLIENT_EXIT_DETACHED,
 | 
			
		||||
@@ -247,7 +247,9 @@ client_main(struct event_base *base, int argc, char **argv, int flags, int feat)
 | 
			
		||||
	pid_t			 ppid;
 | 
			
		||||
	enum msgtype		 msg;
 | 
			
		||||
	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. */
 | 
			
		||||
	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);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Save the flags. */
 | 
			
		||||
	client_flags = flags;
 | 
			
		||||
 | 
			
		||||
	/* Create client process structure (starts logging). */
 | 
			
		||||
	client_proc = proc_start("client");
 | 
			
		||||
	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. */
 | 
			
		||||
	fd = client_connect(base, socket_path, client_flags);
 | 
			
		||||
	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());
 | 
			
		||||
		else
 | 
			
		||||
			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) {
 | 
			
		||||
			printf("\033\\");
 | 
			
		||||
			fflush(stdout);
 | 
			
		||||
			tcsetattr(STDOUT_FILENO, TCSAFLUSH, &saved_tio);
 | 
			
		||||
		}
 | 
			
		||||
	} else if (client_exitreason != CLIENT_EXIT_NONE)
 | 
			
		||||
@@ -870,6 +884,13 @@ client_dispatch_wait(struct imsg *imsg)
 | 
			
		||||
		client_exitval = 1;
 | 
			
		||||
		proc_exit(client_proc);
 | 
			
		||||
		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:
 | 
			
		||||
		if (datalen == 0 || data[datalen - 1] != '\0')
 | 
			
		||||
			fatalx("bad MSG_SHELL string");
 | 
			
		||||
@@ -916,6 +937,13 @@ client_dispatch_attached(struct imsg *imsg)
 | 
			
		||||
	datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
 | 
			
		||||
 | 
			
		||||
	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_DETACHKILL:
 | 
			
		||||
		if (datalen == 0 || data[datalen - 1] != '\0')
 | 
			
		||||
 
 | 
			
		||||
@@ -695,6 +695,7 @@ control_discard(struct client *c)
 | 
			
		||||
 | 
			
		||||
	RB_FOREACH(cp, control_panes, &cs->panes)
 | 
			
		||||
		control_discard_pane(c, cp);
 | 
			
		||||
	bufferevent_disable(cs->read_event, EV_READ);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Stop control mode. */
 | 
			
		||||
 
 | 
			
		||||
@@ -2370,6 +2370,8 @@ server_client_control_flags(struct client *c, const char *next)
 | 
			
		||||
	}
 | 
			
		||||
	if (strcmp(next, "no-output") == 0)
 | 
			
		||||
		return (CLIENT_CONTROL_NOOUTPUT);
 | 
			
		||||
	if (strcmp(next, "wait-exit") == 0)
 | 
			
		||||
		return (CLIENT_CONTROL_WAITEXIT);
 | 
			
		||||
	return (0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -2409,6 +2411,7 @@ server_client_set_flags(struct client *c, const char *flags)
 | 
			
		||||
			control_reset_offsets(c);
 | 
			
		||||
	}
 | 
			
		||||
	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. */
 | 
			
		||||
@@ -2427,6 +2430,8 @@ server_client_get_flags(struct client *c)
 | 
			
		||||
		strlcat(s, "ignore-size,", sizeof s);
 | 
			
		||||
	if (c->flags & CLIENT_CONTROL_NOOUTPUT)
 | 
			
		||||
		strlcat(s, "no-output,", sizeof s);
 | 
			
		||||
	if (c->flags & CLIENT_CONTROL_WAITEXIT)
 | 
			
		||||
		strlcat(s, "wait-exit,", sizeof s);
 | 
			
		||||
	if (c->flags & CLIENT_CONTROL_PAUSEAFTER) {
 | 
			
		||||
		xsnprintf(tmp, sizeof tmp, "pause-after=%u,",
 | 
			
		||||
		    c->pause_age / 1000);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								server.c
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								server.c
									
									
									
									
									
								
							@@ -45,7 +45,7 @@ struct clients		 clients;
 | 
			
		||||
 | 
			
		||||
struct tmuxproc		*server_proc;
 | 
			
		||||
static int		 server_fd = -1;
 | 
			
		||||
static int		 server_client_flags;
 | 
			
		||||
static uint64_t		 server_client_flags;
 | 
			
		||||
static int		 server_exit;
 | 
			
		||||
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
 | 
			
		||||
.It read-only
 | 
			
		||||
the client is read-only
 | 
			
		||||
.It wait-exit
 | 
			
		||||
wait for an empty line input before exiting in control mode
 | 
			
		||||
.El
 | 
			
		||||
.Pp
 | 
			
		||||
A leading
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								tmux.h
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								tmux.h
									
									
									
									
									
								
							@@ -515,6 +515,7 @@ enum msgtype {
 | 
			
		||||
	MSG_UNLOCK,
 | 
			
		||||
	MSG_WAKEUP,
 | 
			
		||||
	MSG_EXEC,
 | 
			
		||||
	MSG_FLAGS,
 | 
			
		||||
 | 
			
		||||
	MSG_READ_OPEN = 300,
 | 
			
		||||
	MSG_READ,
 | 
			
		||||
@@ -1644,6 +1645,7 @@ struct client {
 | 
			
		||||
#define CLIENT_NOFORK 0x40000000
 | 
			
		||||
#define CLIENT_ACTIVEPANE 0x80000000ULL
 | 
			
		||||
#define CLIENT_CONTROL_PAUSEAFTER 0x100000000ULL
 | 
			
		||||
#define CLIENT_CONTROL_WAITEXIT 0x200000000ULL
 | 
			
		||||
#define CLIENT_ALLREDRAWFLAGS		\
 | 
			
		||||
	(CLIENT_REDRAWWINDOW|		\
 | 
			
		||||
	 CLIENT_REDRAWSTATUS|		\
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user