summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr.bin/tmux/cmd-run-shell.c119
-rw-r--r--usr.bin/tmux/job.c4
-rw-r--r--usr.bin/tmux/server.c12
-rw-r--r--usr.bin/tmux/tmux.18
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.