Extend jobs to support writing and use that for copy-pipe instead of

popen, from Chris Johnsen.
pull/1/head
Nicholas Marriott 2013-03-25 11:43:01 +00:00
parent 270d90ce1e
commit d28a39d01d
4 changed files with 57 additions and 32 deletions

View File

@ -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)

View File

@ -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
View File

@ -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)

View File

@ -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);