mirror of
https://github.com/tmate-io/tmate-ssh-server.git
synced 2020-11-18 19:53:51 -08:00
Extend jobs to support writing and use that for copy-pipe instead of
popen, from Chris Johnsen.
This commit is contained in:
parent
270d90ce1e
commit
d28a39d01d
@ -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);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user