diff options
-rw-r--r-- | usr.bin/tmux/cmd-run-shell.c | 119 | ||||
-rw-r--r-- | usr.bin/tmux/job.c | 4 | ||||
-rw-r--r-- | usr.bin/tmux/server.c | 12 | ||||
-rw-r--r-- | usr.bin/tmux/tmux.1 | 8 |
4 files changed, 95 insertions, 48 deletions
diff --git a/usr.bin/tmux/cmd-run-shell.c b/usr.bin/tmux/cmd-run-shell.c index 4dde3d8f75d..15e917c611b 100644 --- a/usr.bin/tmux/cmd-run-shell.c +++ b/usr.bin/tmux/cmd-run-shell.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cmd-run-shell.c,v 1.1 2009/09/20 19:15:01 nicm Exp $ */ +/* $OpenBSD: cmd-run-shell.c,v 1.2 2009/10/11 08:58:05 nicm Exp $ */ /* * Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org> @@ -29,6 +29,9 @@ int cmd_run_shell_exec(struct cmd *, struct cmd_ctx *); +void cmd_run_shell_callback(struct job *); +void cmd_run_shell_free(void *); + const struct cmd_entry cmd_run_shell_entry = { "run-shell", "run", "command", @@ -40,57 +43,97 @@ const struct cmd_entry cmd_run_shell_entry = { cmd_target_print }; +struct cmd_run_shell_data { + char *cmd; + struct cmd_ctx ctx; +}; + int cmd_run_shell_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct cmd_target_data *data = self->data; - FILE *fp; - char *buf, *lbuf, *msg; - size_t len; - int has_output, ret, status; - - if ((fp = popen(data->arg, "r")) == NULL) { - ctx->error(ctx, "popen error"); - return (-1); - } + struct cmd_target_data *data = self->data; + struct cmd_run_shell_data *cdata; + struct job *job; + + cdata = xmalloc(sizeof *cdata); + cdata->cmd = xstrdup(data->arg); + memcpy(&cdata->ctx, ctx, sizeof cdata->ctx); + + if (ctx->cmdclient != NULL) + ctx->cmdclient->references++; + if (ctx->curclient != NULL) + ctx->curclient->references++; + + job = job_add(NULL, NULL, + data->arg, cmd_run_shell_callback, cmd_run_shell_free, cdata); + job_run(job); + + return (1); /* don't let client exit */ +} + +void +cmd_run_shell_callback(struct job *job) +{ + struct cmd_run_shell_data *cdata = job->data; + struct cmd_ctx *ctx = &cdata->ctx; + char *cmd, *msg, *line, *buf; + size_t off, len, llen; + int retcode; + + buf = BUFFER_OUT(job->out); + len = BUFFER_USED(job->out); + + cmd = cdata->cmd; - has_output = 0; - lbuf = NULL; - while ((buf = fgetln(fp, &len)) != NULL) { - if (buf[len - 1] == '\n') - buf[len - 1] = '\0'; - else { - lbuf = xmalloc(len + 1); - memcpy(lbuf, buf, len); - lbuf[len] = '\0'; - buf = lbuf; + if (len != 0) { + line = buf; + for (off = 0; off < len; off++) { + if (buf[off] == '\n') { + llen = buf + off - line; + if (llen > INT_MAX) + break; + ctx->print(ctx, "%.*s", (int) llen, line); + line = buf + off + 1; + } } - ctx->print(ctx, "%s", buf); - has_output = 1; + llen = buf + len - line; + if (llen > 0 && llen < INT_MAX) + ctx->print(ctx, "%.*s", (int) llen, line); } - if (lbuf != NULL) - xfree(lbuf); msg = NULL; - status = pclose(fp); - - if (WIFEXITED(status)) { - if ((ret = WEXITSTATUS(status)) == 0) - return (0); - xasprintf(&msg, "'%s' returned %d", data->arg, ret); - } else if (WIFSIGNALED(status)) { - xasprintf( - &msg, "'%s' terminated by signal %d", data->arg, - WTERMSIG(status)); + if (WIFEXITED(job->status)) { + if ((retcode = WEXITSTATUS(job->status)) != 0) + xasprintf(&msg, "'%s' returned %d", cmd, retcode); + } else if (WIFSIGNALED(job->status)) { + retcode = WTERMSIG(job->status); + xasprintf(&msg, "'%s' terminated by signal %d", cmd, retcode); } - if (msg != NULL) { - if (has_output) + if (len != 0) ctx->print(ctx, "%s", msg); else ctx->info(ctx, "%s", msg); xfree(msg); } - return (0); + job_free(job); /* calls cmd_run_shell_free */ +} + +void +cmd_run_shell_free(void *data) +{ + struct cmd_run_shell_data *cdata = data; + struct cmd_ctx *ctx = &cdata->ctx; + + return; + if (ctx->cmdclient != NULL) { + ctx->cmdclient->references--; + server_write_client(ctx->cmdclient, MSG_EXIT, NULL, 0); + } + if (ctx->curclient != NULL) + ctx->curclient->references--; + + xfree(cdata->cmd); + xfree(cdata); } diff --git a/usr.bin/tmux/job.c b/usr.bin/tmux/job.c index 2e94e3b2961..130d6fa2b70 100644 --- a/usr.bin/tmux/job.c +++ b/usr.bin/tmux/job.c @@ -1,4 +1,4 @@ -/* $OpenBSD: job.c,v 1.4 2009/10/11 07:30:07 nicm Exp $ */ +/* $OpenBSD: job.c,v 1.5 2009/10/11 08:58:05 nicm Exp $ */ /* * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> @@ -70,7 +70,6 @@ job_tree_free(struct jobs *jobs) while (!RB_EMPTY(jobs)) { job = RB_ROOT(jobs); RB_REMOVE(jobs, jobs, job); - SLIST_REMOVE(&all_jobs, job, job, lentry); job_free(job); } } @@ -120,6 +119,7 @@ job_free(struct job *job) { job_kill(job); + SLIST_REMOVE(&all_jobs, job, job, lentry); xfree(job->cmd); if (job->freefn != NULL && job->data != NULL) diff --git a/usr.bin/tmux/server.c b/usr.bin/tmux/server.c index b3bb7b7222a..b57cf4afd7d 100644 --- a/usr.bin/tmux/server.c +++ b/usr.bin/tmux/server.c @@ -1,4 +1,4 @@ -/* $OpenBSD: server.c,v 1.53 2009/10/11 07:20:16 nicm Exp $ */ +/* $OpenBSD: server.c,v 1.54 2009/10/11 08:58:05 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> @@ -810,13 +810,17 @@ void server_check_jobs(void) { struct job *job; - + +restart: SLIST_FOREACH(job, &all_jobs, lentry) { if (job->flags & JOB_DONE || job->fd != -1 || job->pid != -1) continue; - if (job->callbackfn != NULL) - job->callbackfn(job); job->flags |= JOB_DONE; + + if (job->callbackfn != NULL) { + job->callbackfn(job); + goto restart; /* could be freed by callback */ + } } } diff --git a/usr.bin/tmux/tmux.1 b/usr.bin/tmux/tmux.1 index 7abd3f5782e..0dae7e24db4 100644 --- a/usr.bin/tmux/tmux.1 +++ b/usr.bin/tmux/tmux.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: tmux.1,v 1.105 2009/10/10 17:39:55 nicm Exp $ +.\" $OpenBSD: tmux.1,v 1.106 2009/10/11 08:58:05 nicm Exp $ .\" .\" Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> .\" @@ -14,7 +14,7 @@ .\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING .\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: October 10 2009 $ +.Dd $Mdocdate: October 11 2009 $ .Dt TMUX 1 .Os .Sh NAME @@ -2068,8 +2068,8 @@ option. .D1 (alias: Ic run ) Execute .Ar command -without creating a window. -Any output to stdout is displayed in output mode. +in the background without creating a window. +After the command finishes, any output to stdout is displayed in output mode. If .Ar command doesn't return success, the exit status is also displayed. |