diff --git a/cmd-if-shell.c b/cmd-if-shell.c index e2a45972..a3ca6555 100644 --- a/cmd-if-shell.c +++ b/cmd-if-shell.c @@ -59,19 +59,21 @@ cmd_if_shell_exec(struct cmd *self, struct cmd_q *cmdq) struct args *args = self->args; struct cmd_if_shell_data *cdata; char *shellcmd; - struct session *s; - struct winlink *wl; - struct window_pane *wp; + struct session *s = NULL; + struct winlink *wl = NULL; + struct window_pane *wp = NULL; struct format_tree *ft; - wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp); - if (wl == NULL) - return (CMD_RETURN_ERROR); + if (args_has(args, 't')) + wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp); ft = format_create(); - format_session(ft, s); - format_winlink(ft, s, wl); - format_window_pane(ft, wp); + if (s != NULL) + format_session(ft, s); + 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]); format_free(ft); @@ -87,7 +89,7 @@ cmd_if_shell_exec(struct cmd *self, struct cmd_q *cmdq) cdata->cmdq = cmdq; 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); if (cdata->bflag) diff --git a/cmd-run-shell.c b/cmd-run-shell.c index 5452ceff..e78d0e40 100644 --- a/cmd-run-shell.c +++ b/cmd-run-shell.c @@ -49,16 +49,17 @@ struct cmd_run_shell_data { char *cmd; struct cmd_q *cmdq; int bflag; - u_int wp_id; + int wp_id; }; void cmd_run_shell_print(struct job *job, const char *msg) { 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) { cmdq_print(cdata->cmdq, "%s", msg); return; @@ -76,31 +77,33 @@ cmd_run_shell_exec(struct cmd *self, struct cmd_q *cmdq) struct args *args = self->args; struct cmd_run_shell_data *cdata; char *shellcmd; - struct session *s; - struct winlink *wl; - struct window_pane *wp; + struct session *s = NULL; + struct winlink *wl = NULL; + struct window_pane *wp = NULL; struct format_tree *ft; - wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp); - if (wl == NULL) - return (CMD_RETURN_ERROR); + if (args_has(args, 't')) + wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp); ft = format_create(); - format_session(ft, s); - format_winlink(ft, s, wl); - format_window_pane(ft, wp); + if (s != NULL) + format_session(ft, s); + 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]); format_free(ft); cdata = xmalloc(sizeof *cdata); cdata->cmd = shellcmd; cdata->bflag = args_has(args, 'b'); - cdata->wp_id = wp->id; + cdata->wp_id = wp != NULL ? (int) wp->id : -1; cdata->cmdq = cmdq; 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) return (CMD_RETURN_NORMAL); diff --git a/job.c b/job.c index 64deeeab..b76b3345 100644 --- a/job.c +++ b/job.c @@ -33,13 +33,14 @@ */ void job_callback(struct bufferevent *, short, void *); +void job_write_callback(struct bufferevent *, void *); /* All jobs list. */ struct joblist all_jobs = LIST_HEAD_INITIALIZER(all_jobs); /* Start a job running, if it isn't already. */ struct job * -job_run(const char *cmd, +job_run(const char *cmd, struct session *s, void (*callbackfn)(struct job *), void (*freefn)(void *), void *data) { struct job *job; @@ -52,7 +53,9 @@ job_run(const char *cmd, environ_init(&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()) { case -1: @@ -64,20 +67,20 @@ job_run(const char *cmd, environ_push(&env); environ_free(&env); + if (dup2(out[1], STDIN_FILENO) == -1) + fatal("dup2 failed"); if (dup2(out[1], STDOUT_FILENO) == -1) fatal("dup2 failed"); - if (out[1] != STDOUT_FILENO) + if (out[1] != STDIN_FILENO && out[1] != STDOUT_FILENO) close(out[1]); close(out[0]); nullfd = open(_PATH_DEVNULL, O_RDWR, 0); if (nullfd < 0) fatal("open failed"); - if (dup2(nullfd, STDIN_FILENO) == -1) - fatal("dup2 failed"); if (dup2(nullfd, STDERR_FILENO) == -1) fatal("dup2 failed"); - if (nullfd != STDIN_FILENO && nullfd != STDERR_FILENO) + if (nullfd != STDERR_FILENO) close(nullfd); closefrom(STDERR_FILENO + 1); @@ -104,7 +107,8 @@ job_run(const char *cmd, job->fd = out[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); 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); } +/* 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. */ void job_callback(unused struct bufferevent *bufev, unused short events, void *data) diff --git a/status.c b/status.c index fc773dca..6ce0b871 100644 --- a/status.c +++ b/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 (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++; so = xmalloc(sizeof *so);