=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/tmux/job.c,v retrieving revision 1.55 retrieving revision 1.56 diff -c -r1.55 -r1.56 *** src/usr.bin/tmux/job.c 2019/06/28 13:35:05 1.55 --- src/usr.bin/tmux/job.c 2020/03/19 13:43:18 1.56 *************** *** 1,4 **** ! /* $OpenBSD: job.c,v 1.55 2019/06/28 13:35:05 deraadt Exp $ */ /* * Copyright (c) 2009 Nicholas Marriott --- 1,4 ---- ! /* $OpenBSD: job.c,v 1.56 2020/03/19 13:43:18 nicm Exp $ */ /* * Copyright (c) 2009 Nicholas Marriott *************** *** 25,30 **** --- 25,31 ---- #include #include #include + #include #include "tmux.h" *************** *** 69,87 **** 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) { struct job *job; struct environ *env; pid_t pid; ! int nullfd, out[2]; 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); - /* * Do not set TERM during .tmux.conf, it is nice to be able to use * if-shell to decide on default-terminal based on outside TERM. --- 70,85 ---- 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, int sx, int sy) { struct job *job; struct environ *env; pid_t pid; ! int nullfd, out[2], master; const char *home; sigset_t set, oldset; + struct winsize ws; /* * Do not set TERM during .tmux.conf, it is nice to be able to use * if-shell to decide on default-terminal based on outside TERM. *************** *** 90,102 **** sigfillset(&set); sigprocmask(SIG_BLOCK, &set, &oldset); ! switch (pid = fork()) { case -1: ! sigprocmask(SIG_SETMASK, &oldset, NULL); ! environ_free(env); ! close(out[0]); ! close(out[1]); ! return (NULL); case 0: proc_clear_signals(server_proc, 1); sigprocmask(SIG_SETMASK, &oldset, NULL); --- 88,113 ---- sigfillset(&set); sigprocmask(SIG_BLOCK, &set, &oldset); ! ! 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: ! 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,130 **** 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); ! closefrom(STDERR_FILENO + 1); execl(_PATH_BSHELL, "sh", "-c", cmd, (char *) NULL); --- 120,142 ---- environ_push(env); environ_free(env); ! 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,139 **** sigprocmask(SIG_SETMASK, &oldset, NULL); environ_free(env); - close(out[1]); job = xmalloc(sizeof *job); job->state = JOB_RUNNING; --- 145,150 ---- *************** *** 150,156 **** job->freecb = freecb; job->data = data; ! job->fd = out[0]; setblocking(job->fd, 0); job->event = bufferevent_new(job->fd, job_read_callback, --- 161,171 ---- job->freecb = freecb; job->data = data; ! 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,166 **** --- 176,186 ---- 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,215 **** log_debug("job write %p: %s, pid %ld, output left %zu", job, job->cmd, (long) job->pid, len); ! if (len == 0) { shutdown(job->fd, SHUT_WR); bufferevent_disable(job->event, EV_WRITE); } --- 229,235 ---- log_debug("job write %p: %s, pid %ld, output left %zu", job, job->cmd, (long) job->pid, len); ! if (len == 0 && (~job->flags & JOB_KEEPWRITE)) { shutdown(job->fd, SHUT_WR); bufferevent_disable(job->event, EV_WRITE); }