diff options
author | Thomas Adam <thomas@xteddy.org> | 2020-03-19 14:01:31 +0000 |
---|---|---|
committer | Thomas Adam <thomas@xteddy.org> | 2020-03-19 14:01:31 +0000 |
commit | 17e4f2394a15602100ad72a052cf9b00e77f208a (patch) | |
tree | a8b6e59db7a20e49afc64cf46a59a27aeb93245b /job.c | |
parent | 7595b22e723e1a71ff84ba8d5fa9ad12454f501a (diff) | |
parent | ce61bf931b1af18064ab84542ee8f4a64e498fed (diff) |
Merge branch 'obsd-master'
Diffstat (limited to 'job.c')
-rw-r--r-- | job.c | 82 |
1 files changed, 51 insertions, 31 deletions
@@ -24,6 +24,7 @@ #include <stdlib.h> #include <string.h> #include <unistd.h> +#include <util.h> #include "tmux.h" @@ -68,18 +69,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 @@ -89,13 +87,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); @@ -108,22 +119,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); @@ -132,7 +144,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; @@ -149,7 +160,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, @@ -160,6 +175,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. */ @@ -208,7 +228,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); } |