From e8273a993ec79a58ffff16eba17d0551c690c4db Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 19 Mar 2020 13:43:18 +0000 Subject: Add a flag to run a background process in a pty as well, not used for anything yet. --- job.c | 82 ++++++++++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 51 insertions(+), 31 deletions(-) (limited to 'job.c') diff --git a/job.c b/job.c index 0c316fd8..c31d51b2 100644 --- a/job.c +++ b/job.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "tmux.h" @@ -69,18 +70,15 @@ static LIST_HEAD(joblist, job) all_jobs = LIST_HEAD_INITIALIZER(all_jobs); struct job * job_run(const char *cmd, struct session *s, const char *cwd, job_update_cb updatecb, job_complete_cb completecb, job_free_cb freecb, - void *data, int flags) + void *data, int flags, int sx, int sy) { struct job *job; struct environ *env; pid_t pid; - int nullfd, out[2]; + int nullfd, out[2], master; const char *home; sigset_t set, oldset; - - if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, out) != 0) - return (NULL); - log_debug("%s: cmd=%s, cwd=%s", __func__, cmd, cwd == NULL ? "" : cwd); + struct winsize ws; /* * Do not set TERM during .tmux.conf, it is nice to be able to use @@ -90,13 +88,26 @@ job_run(const char *cmd, struct session *s, const char *cwd, sigfillset(&set); sigprocmask(SIG_BLOCK, &set, &oldset); - switch (pid = fork()) { + + if (flags & JOB_PTY) { + memset(&ws, 0, sizeof ws); + ws.ws_col = sx; + ws.ws_row = sy; + pid = fdforkpty(ptm_fd, &master, NULL, NULL, &ws); + } else { + if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, out) != 0) + goto fail; + pid = fork(); + } + log_debug("%s: cmd=%s, cwd=%s", __func__, cmd, cwd == NULL ? "" : cwd); + + switch (pid) { case -1: - sigprocmask(SIG_SETMASK, &oldset, NULL); - environ_free(env); - close(out[0]); - close(out[1]); - return (NULL); + if (~flags & JOB_PTY) { + close(out[0]); + close(out[1]); + } + goto fail; case 0: proc_clear_signals(server_proc, 1); sigprocmask(SIG_SETMASK, &oldset, NULL); @@ -109,22 +120,23 @@ job_run(const char *cmd, struct session *s, const char *cwd, 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] != STDIN_FILENO && out[1] != STDOUT_FILENO) - close(out[1]); - close(out[0]); - - nullfd = open(_PATH_DEVNULL, O_RDWR, 0); - if (nullfd == -1) - fatal("open failed"); - if (dup2(nullfd, STDERR_FILENO) == -1) - fatal("dup2 failed"); - if (nullfd != STDERR_FILENO) - close(nullfd); - + if (~flags & JOB_PTY) { + if (dup2(out[1], STDIN_FILENO) == -1) + fatal("dup2 failed"); + if (dup2(out[1], STDOUT_FILENO) == -1) + fatal("dup2 failed"); + if (out[1] != STDIN_FILENO && out[1] != STDOUT_FILENO) + close(out[1]); + close(out[0]); + + nullfd = open(_PATH_DEVNULL, O_RDWR, 0); + if (nullfd == -1) + fatal("open failed"); + if (dup2(nullfd, STDERR_FILENO) == -1) + fatal("dup2 failed"); + if (nullfd != STDERR_FILENO) + close(nullfd); + } closefrom(STDERR_FILENO + 1); execl(_PATH_BSHELL, "sh", "-c", cmd, (char *) NULL); @@ -133,7 +145,6 @@ job_run(const char *cmd, struct session *s, const char *cwd, sigprocmask(SIG_SETMASK, &oldset, NULL); environ_free(env); - close(out[1]); job = xmalloc(sizeof *job); job->state = JOB_RUNNING; @@ -150,7 +161,11 @@ job_run(const char *cmd, struct session *s, const char *cwd, job->freecb = freecb; job->data = data; - job->fd = out[0]; + if (~flags & JOB_PTY) { + close(out[1]); + job->fd = out[0]; + } else + job->fd = master; setblocking(job->fd, 0); job->event = bufferevent_new(job->fd, job_read_callback, @@ -161,6 +176,11 @@ job_run(const char *cmd, struct session *s, const char *cwd, log_debug("run job %p: %s, pid %ld", job, job->cmd, (long) job->pid); return (job); + +fail: + sigprocmask(SIG_SETMASK, &oldset, NULL); + environ_free(env); + return (NULL); } /* Kill and free an individual job. */ @@ -209,7 +229,7 @@ job_write_callback(__unused struct bufferevent *bufev, void *data) log_debug("job write %p: %s, pid %ld, output left %zu", job, job->cmd, (long) job->pid, len); - if (len == 0) { + if (len == 0 && (~job->flags & JOB_KEEPWRITE)) { shutdown(job->fd, SHUT_WR); bufferevent_disable(job->event, EV_WRITE); } -- cgit v1.2.3