aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornicm <nicm>2020-03-19 13:43:18 +0000
committernicm <nicm>2020-03-19 13:43:18 +0000
commite8273a993ec79a58ffff16eba17d0551c690c4db (patch)
tree42b0c159fc138b4a0e49fe39afe881cdd093d511
parent581ed718e737fd3875323e74b674bcf7f9d0bcb3 (diff)
downloadrtmux-e8273a993ec79a58ffff16eba17d0551c690c4db.tar.gz
rtmux-e8273a993ec79a58ffff16eba17d0551c690c4db.tar.bz2
rtmux-e8273a993ec79a58ffff16eba17d0551c690c4db.zip
Add a flag to run a background process in a pty as well, not used for
anything yet.
-rw-r--r--cmd-if-shell.c3
-rw-r--r--cmd-run-shell.c4
-rw-r--r--format.c2
-rw-r--r--job.c82
-rw-r--r--tmux.h5
-rw-r--r--window-copy.c4
6 files changed, 62 insertions, 38 deletions
diff --git a/cmd-if-shell.c b/cmd-if-shell.c
index 2befbc0c..b008241d 100644
--- a/cmd-if-shell.c
+++ b/cmd-if-shell.c
@@ -144,7 +144,8 @@ cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item)
cmd_find_copy_state(&cdata->input.fs, fs);
if (job_run(shellcmd, s, server_client_get_cwd(item->client, s), NULL,
- cmd_if_shell_callback, cmd_if_shell_free, cdata, 0) == NULL) {
+ cmd_if_shell_callback, cmd_if_shell_free, cdata, 0, -1,
+ -1) == NULL) {
cmdq_error(item, "failed to run command: %s", shellcmd);
free(shellcmd);
free(cdata);
diff --git a/cmd-run-shell.c b/cmd-run-shell.c
index bc21cc9c..1cf97d51 100644
--- a/cmd-run-shell.c
+++ b/cmd-run-shell.c
@@ -145,8 +145,8 @@ cmd_run_shell_timer(__unused int fd, __unused short events, void* arg)
if (cdata->cmd != NULL) {
if (job_run(cdata->cmd, cdata->s, cdata->cwd, NULL,
- cmd_run_shell_callback, cmd_run_shell_free, cdata,
- 0) == NULL)
+ cmd_run_shell_callback, cmd_run_shell_free, cdata, 0, -1,
+ -1) == NULL)
cmd_run_shell_free(cdata);
} else {
if (cdata->item != NULL)
diff --git a/format.c b/format.c
index 14d56126..fe8e9c68 100644
--- a/format.c
+++ b/format.c
@@ -354,7 +354,7 @@ format_job_get(struct format_tree *ft, const char *cmd)
if (force || (fj->job == NULL && fj->last != t)) {
fj->job = job_run(expanded, NULL,
server_client_get_cwd(ft->client, NULL), format_job_update,
- format_job_complete, NULL, fj, JOB_NOWAIT);
+ format_job_complete, NULL, fj, JOB_NOWAIT, -1, -1);
if (fj->job == NULL) {
free(fj->out);
xasprintf(&fj->out, "<'%s' didn't start>", fj->cmd);
diff --git a/job.c b/job.c
index 0c316fd8..c31d51b2 100644
--- a/job.c
+++ b/job.c
@@ -25,6 +25,7 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <util.h>
#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);
}
diff --git a/tmux.h b/tmux.h
index 72e0e9b9..043cb070 100644
--- a/tmux.h
+++ b/tmux.h
@@ -1929,8 +1929,11 @@ typedef void (*job_update_cb) (struct job *);
typedef void (*job_complete_cb) (struct job *);
typedef void (*job_free_cb) (void *);
#define JOB_NOWAIT 0x1
+#define JOB_KEEPWRITE 0x2
+#define JOB_PTY 0x4
struct job *job_run(const char *, struct session *, const char *,
- job_update_cb, job_complete_cb, job_free_cb, void *, int);
+ job_update_cb, job_complete_cb, job_free_cb, void *, int,
+ int, int);
void job_free(struct job *);
void job_check_died(pid_t, int);
int job_get_status(struct job *);
diff --git a/window-copy.c b/window-copy.c
index 056eac65..abde1c48 100644
--- a/window-copy.c
+++ b/window-copy.c
@@ -3240,7 +3240,7 @@ window_copy_copy_buffer(struct window_mode_entry *wme, const char *prefix,
static void
window_copy_copy_pipe(struct window_mode_entry *wme, struct session *s,
- const char *prefix, const char *command)
+ const char *prefix, const char *cmd)
{
void *buf;
size_t len;
@@ -3250,7 +3250,7 @@ window_copy_copy_pipe(struct window_mode_entry *wme, struct session *s,
if (buf == NULL)
return;
- job = job_run(command, s, NULL, NULL, NULL, NULL, NULL, JOB_NOWAIT);
+ job = job_run(cmd, s, NULL, NULL, NULL, NULL, NULL, JOB_NOWAIT, -1, -1);
bufferevent_write(job_get_event(job), buf, len);
window_copy_copy_buffer(wme, prefix, buf, len);
}