mirror of
				https://github.com/tmux/tmux.git
				synced 2025-11-04 09:26:05 +00:00 
			
		
		
		
	Extend jobs to support writing and use that for copy-pipe instead of
popen, from Chris Johnsen.
This commit is contained in:
		@@ -59,19 +59,21 @@ cmd_if_shell_exec(struct cmd *self, struct cmd_q *cmdq)
 | 
				
			|||||||
	struct args			*args = self->args;
 | 
						struct args			*args = self->args;
 | 
				
			||||||
	struct cmd_if_shell_data	*cdata;
 | 
						struct cmd_if_shell_data	*cdata;
 | 
				
			||||||
	char				*shellcmd;
 | 
						char				*shellcmd;
 | 
				
			||||||
	struct session			*s;
 | 
						struct session			*s = NULL;
 | 
				
			||||||
	struct winlink			*wl;
 | 
						struct winlink			*wl = NULL;
 | 
				
			||||||
	struct window_pane		*wp;
 | 
						struct window_pane		*wp = NULL;
 | 
				
			||||||
	struct format_tree		*ft;
 | 
						struct format_tree		*ft;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp);
 | 
						if (args_has(args, 't'))
 | 
				
			||||||
	if (wl == NULL)
 | 
							wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp);
 | 
				
			||||||
		return (CMD_RETURN_ERROR);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ft = format_create();
 | 
						ft = format_create();
 | 
				
			||||||
	format_session(ft, s);
 | 
						if (s != NULL)
 | 
				
			||||||
	format_winlink(ft, s, wl);
 | 
							format_session(ft, s);
 | 
				
			||||||
	format_window_pane(ft, wp);
 | 
						if (s != NULL && wl != NULL)
 | 
				
			||||||
 | 
							format_winlink(ft, s, wl);
 | 
				
			||||||
 | 
						if (wp != NULL)
 | 
				
			||||||
 | 
							format_window_pane(ft, wp);
 | 
				
			||||||
	shellcmd = format_expand(ft, args->argv[0]);
 | 
						shellcmd = format_expand(ft, args->argv[0]);
 | 
				
			||||||
	format_free(ft);
 | 
						format_free(ft);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -87,7 +89,7 @@ cmd_if_shell_exec(struct cmd *self, struct cmd_q *cmdq)
 | 
				
			|||||||
	cdata->cmdq = cmdq;
 | 
						cdata->cmdq = cmdq;
 | 
				
			||||||
	cmdq->references++;
 | 
						cmdq->references++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	job_run(shellcmd, cmd_if_shell_callback, cmd_if_shell_free, cdata);
 | 
						job_run(shellcmd, s, cmd_if_shell_callback, cmd_if_shell_free, cdata);
 | 
				
			||||||
	free(shellcmd);
 | 
						free(shellcmd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (cdata->bflag)
 | 
						if (cdata->bflag)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -49,16 +49,17 @@ struct cmd_run_shell_data {
 | 
				
			|||||||
	char		*cmd;
 | 
						char		*cmd;
 | 
				
			||||||
	struct cmd_q	*cmdq;
 | 
						struct cmd_q	*cmdq;
 | 
				
			||||||
	int		 bflag;
 | 
						int		 bflag;
 | 
				
			||||||
	u_int		 wp_id;
 | 
						int		 wp_id;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
cmd_run_shell_print(struct job *job, const char *msg)
 | 
					cmd_run_shell_print(struct job *job, const char *msg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct cmd_run_shell_data	*cdata = job->data;
 | 
						struct cmd_run_shell_data	*cdata = job->data;
 | 
				
			||||||
	struct window_pane		*wp;
 | 
						struct window_pane		*wp = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wp = window_pane_find_by_id(cdata->wp_id);
 | 
						if (cdata->wp_id != -1)
 | 
				
			||||||
 | 
							wp = window_pane_find_by_id(cdata->wp_id);
 | 
				
			||||||
	if (wp == NULL) {
 | 
						if (wp == NULL) {
 | 
				
			||||||
		cmdq_print(cdata->cmdq, "%s", msg);
 | 
							cmdq_print(cdata->cmdq, "%s", msg);
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
@@ -76,31 +77,33 @@ cmd_run_shell_exec(struct cmd *self, struct cmd_q *cmdq)
 | 
				
			|||||||
	struct args			*args = self->args;
 | 
						struct args			*args = self->args;
 | 
				
			||||||
	struct cmd_run_shell_data	*cdata;
 | 
						struct cmd_run_shell_data	*cdata;
 | 
				
			||||||
	char				*shellcmd;
 | 
						char				*shellcmd;
 | 
				
			||||||
	struct session			*s;
 | 
						struct session			*s = NULL;
 | 
				
			||||||
	struct winlink			*wl;
 | 
						struct winlink			*wl = NULL;
 | 
				
			||||||
	struct window_pane		*wp;
 | 
						struct window_pane		*wp = NULL;
 | 
				
			||||||
	struct format_tree		*ft;
 | 
						struct format_tree		*ft;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp);
 | 
						if (args_has(args, 't'))
 | 
				
			||||||
	if (wl == NULL)
 | 
							wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp);
 | 
				
			||||||
		return (CMD_RETURN_ERROR);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ft = format_create();
 | 
						ft = format_create();
 | 
				
			||||||
	format_session(ft, s);
 | 
						if (s != NULL)
 | 
				
			||||||
	format_winlink(ft, s, wl);
 | 
							format_session(ft, s);
 | 
				
			||||||
	format_window_pane(ft, wp);
 | 
						if (s != NULL && wl != NULL)
 | 
				
			||||||
 | 
							format_winlink(ft, s, wl);
 | 
				
			||||||
 | 
						if (wp != NULL)
 | 
				
			||||||
 | 
							format_window_pane(ft, wp);
 | 
				
			||||||
	shellcmd = format_expand(ft, args->argv[0]);
 | 
						shellcmd = format_expand(ft, args->argv[0]);
 | 
				
			||||||
	format_free(ft);
 | 
						format_free(ft);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cdata = xmalloc(sizeof *cdata);
 | 
						cdata = xmalloc(sizeof *cdata);
 | 
				
			||||||
	cdata->cmd = shellcmd;
 | 
						cdata->cmd = shellcmd;
 | 
				
			||||||
	cdata->bflag = args_has(args, 'b');
 | 
						cdata->bflag = args_has(args, 'b');
 | 
				
			||||||
	cdata->wp_id = wp->id;
 | 
						cdata->wp_id = wp != NULL ? (int) wp->id : -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cdata->cmdq = cmdq;
 | 
						cdata->cmdq = cmdq;
 | 
				
			||||||
	cmdq->references++;
 | 
						cmdq->references++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	job_run(shellcmd, cmd_run_shell_callback, cmd_run_shell_free, cdata);
 | 
						job_run(shellcmd, s, cmd_run_shell_callback, cmd_run_shell_free, cdata);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (cdata->bflag)
 | 
						if (cdata->bflag)
 | 
				
			||||||
		return (CMD_RETURN_NORMAL);
 | 
							return (CMD_RETURN_NORMAL);
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										34
									
								
								job.c
									
									
									
									
									
								
							
							
						
						
									
										34
									
								
								job.c
									
									
									
									
									
								
							@@ -33,13 +33,14 @@
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void	job_callback(struct bufferevent *, short, void *);
 | 
					void	job_callback(struct bufferevent *, short, void *);
 | 
				
			||||||
 | 
					void	job_write_callback(struct bufferevent *, void *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* All jobs list. */
 | 
					/* All jobs list. */
 | 
				
			||||||
struct joblist	all_jobs = LIST_HEAD_INITIALIZER(all_jobs);
 | 
					struct joblist	all_jobs = LIST_HEAD_INITIALIZER(all_jobs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Start a job running, if it isn't already. */
 | 
					/* Start a job running, if it isn't already. */
 | 
				
			||||||
struct job *
 | 
					struct job *
 | 
				
			||||||
job_run(const char *cmd,
 | 
					job_run(const char *cmd, struct session *s,
 | 
				
			||||||
    void (*callbackfn)(struct job *), void (*freefn)(void *), void *data)
 | 
					    void (*callbackfn)(struct job *), void (*freefn)(void *), void *data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct job	*job;
 | 
						struct job	*job;
 | 
				
			||||||
@@ -52,7 +53,9 @@ job_run(const char *cmd,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	environ_init(&env);
 | 
						environ_init(&env);
 | 
				
			||||||
	environ_copy(&global_environ, &env);
 | 
						environ_copy(&global_environ, &env);
 | 
				
			||||||
	server_fill_environ(NULL, &env);
 | 
						if (s != NULL)
 | 
				
			||||||
 | 
							environ_copy(&s->environ, &env);
 | 
				
			||||||
 | 
						server_fill_environ(s, &env);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (pid = fork()) {
 | 
						switch (pid = fork()) {
 | 
				
			||||||
	case -1:
 | 
						case -1:
 | 
				
			||||||
@@ -64,20 +67,20 @@ job_run(const char *cmd,
 | 
				
			|||||||
		environ_push(&env);
 | 
							environ_push(&env);
 | 
				
			||||||
		environ_free(&env);
 | 
							environ_free(&env);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (dup2(out[1], STDIN_FILENO) == -1)
 | 
				
			||||||
 | 
								fatal("dup2 failed");
 | 
				
			||||||
		if (dup2(out[1], STDOUT_FILENO) == -1)
 | 
							if (dup2(out[1], STDOUT_FILENO) == -1)
 | 
				
			||||||
			fatal("dup2 failed");
 | 
								fatal("dup2 failed");
 | 
				
			||||||
		if (out[1] != STDOUT_FILENO)
 | 
							if (out[1] != STDIN_FILENO && out[1] != STDOUT_FILENO)
 | 
				
			||||||
			close(out[1]);
 | 
								close(out[1]);
 | 
				
			||||||
		close(out[0]);
 | 
							close(out[0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		nullfd = open(_PATH_DEVNULL, O_RDWR, 0);
 | 
							nullfd = open(_PATH_DEVNULL, O_RDWR, 0);
 | 
				
			||||||
		if (nullfd < 0)
 | 
							if (nullfd < 0)
 | 
				
			||||||
			fatal("open failed");
 | 
								fatal("open failed");
 | 
				
			||||||
		if (dup2(nullfd, STDIN_FILENO) == -1)
 | 
					 | 
				
			||||||
			fatal("dup2 failed");
 | 
					 | 
				
			||||||
		if (dup2(nullfd, STDERR_FILENO) == -1)
 | 
							if (dup2(nullfd, STDERR_FILENO) == -1)
 | 
				
			||||||
			fatal("dup2 failed");
 | 
								fatal("dup2 failed");
 | 
				
			||||||
		if (nullfd != STDIN_FILENO && nullfd != STDERR_FILENO)
 | 
							if (nullfd != STDERR_FILENO)
 | 
				
			||||||
			close(nullfd);
 | 
								close(nullfd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		closefrom(STDERR_FILENO + 1);
 | 
							closefrom(STDERR_FILENO + 1);
 | 
				
			||||||
@@ -104,7 +107,8 @@ job_run(const char *cmd,
 | 
				
			|||||||
	job->fd = out[0];
 | 
						job->fd = out[0];
 | 
				
			||||||
	setblocking(job->fd, 0);
 | 
						setblocking(job->fd, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	job->event = bufferevent_new(job->fd, NULL, NULL, job_callback, job);
 | 
						job->event = bufferevent_new(job->fd, NULL, job_write_callback,
 | 
				
			||||||
 | 
						    job_callback, job);
 | 
				
			||||||
	bufferevent_enable(job->event, EV_READ);
 | 
						bufferevent_enable(job->event, EV_READ);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	log_debug("run job %p: %s, pid %ld", job, job->cmd, (long) job->pid);
 | 
						log_debug("run job %p: %s, pid %ld", job, job->cmd, (long) job->pid);
 | 
				
			||||||
@@ -133,6 +137,22 @@ job_free(struct job *job)
 | 
				
			|||||||
	free(job);
 | 
						free(job);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Called when output buffer falls below low watermark (default is 0). */
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					job_write_callback(unused struct bufferevent *bufev, void *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct job	*job = data;
 | 
				
			||||||
 | 
						size_t		 len = EVBUFFER_LENGTH(EVBUFFER_OUTPUT(job->event));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						log_debug("job write %p: %s, pid %ld, output left %lu", job, job->cmd,
 | 
				
			||||||
 | 
							    (long) job->pid, (unsigned long) len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (len == 0) {
 | 
				
			||||||
 | 
							shutdown(job->fd, SHUT_WR);
 | 
				
			||||||
 | 
							bufferevent_disable(job->event, EV_WRITE);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Job buffer error callback. */
 | 
					/* Job buffer error callback. */
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
job_callback(unused struct bufferevent *bufev, unused short events, void *data)
 | 
					job_callback(unused struct bufferevent *bufev, unused short events, void *data)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								status.c
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								status.c
									
									
									
									
									
								
							@@ -594,7 +594,7 @@ status_find_job(struct client *c, char **iptr)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/* If not found at all, start the job and add to the tree. */
 | 
						/* If not found at all, start the job and add to the tree. */
 | 
				
			||||||
	if (so == NULL) {
 | 
						if (so == NULL) {
 | 
				
			||||||
		job_run(cmd, status_job_callback, status_job_free, c);
 | 
							job_run(cmd, NULL, status_job_callback, status_job_free, c);
 | 
				
			||||||
		c->references++;
 | 
							c->references++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		so = xmalloc(sizeof *so);
 | 
							so = xmalloc(sizeof *so);
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user