mirror of
https://github.com/tmux/tmux.git
synced 2025-09-03 06:17:04 +00:00
Add a flag to run a background process in a pty as well, not used for
anything yet.
This commit is contained in:
@ -144,7 +144,8 @@ cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
cmd_find_copy_state(&cdata->input.fs, fs);
|
cmd_find_copy_state(&cdata->input.fs, fs);
|
||||||
|
|
||||||
if (job_run(shellcmd, s, server_client_get_cwd(item->client, s), NULL,
|
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);
|
cmdq_error(item, "failed to run command: %s", shellcmd);
|
||||||
free(shellcmd);
|
free(shellcmd);
|
||||||
free(cdata);
|
free(cdata);
|
||||||
|
@ -145,8 +145,8 @@ cmd_run_shell_timer(__unused int fd, __unused short events, void* arg)
|
|||||||
|
|
||||||
if (cdata->cmd != NULL) {
|
if (cdata->cmd != NULL) {
|
||||||
if (job_run(cdata->cmd, cdata->s, cdata->cwd, NULL,
|
if (job_run(cdata->cmd, cdata->s, cdata->cwd, NULL,
|
||||||
cmd_run_shell_callback, cmd_run_shell_free, cdata,
|
cmd_run_shell_callback, cmd_run_shell_free, cdata, 0, -1,
|
||||||
0) == NULL)
|
-1) == NULL)
|
||||||
cmd_run_shell_free(cdata);
|
cmd_run_shell_free(cdata);
|
||||||
} else {
|
} else {
|
||||||
if (cdata->item != NULL)
|
if (cdata->item != NULL)
|
||||||
|
2
format.c
2
format.c
@ -354,7 +354,7 @@ format_job_get(struct format_tree *ft, const char *cmd)
|
|||||||
if (force || (fj->job == NULL && fj->last != t)) {
|
if (force || (fj->job == NULL && fj->last != t)) {
|
||||||
fj->job = job_run(expanded, NULL,
|
fj->job = job_run(expanded, NULL,
|
||||||
server_client_get_cwd(ft->client, NULL), format_job_update,
|
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) {
|
if (fj->job == NULL) {
|
||||||
free(fj->out);
|
free(fj->out);
|
||||||
xasprintf(&fj->out, "<'%s' didn't start>", fj->cmd);
|
xasprintf(&fj->out, "<'%s' didn't start>", fj->cmd);
|
||||||
|
80
job.c
80
job.c
@ -25,6 +25,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <util.h>
|
||||||
|
|
||||||
#include "tmux.h"
|
#include "tmux.h"
|
||||||
|
|
||||||
@ -69,18 +70,15 @@ static LIST_HEAD(joblist, job) all_jobs = LIST_HEAD_INITIALIZER(all_jobs);
|
|||||||
struct job *
|
struct job *
|
||||||
job_run(const char *cmd, struct session *s, const char *cwd,
|
job_run(const char *cmd, struct session *s, const char *cwd,
|
||||||
job_update_cb updatecb, job_complete_cb completecb, job_free_cb freecb,
|
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 job *job;
|
||||||
struct environ *env;
|
struct environ *env;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
int nullfd, out[2];
|
int nullfd, out[2], master;
|
||||||
const char *home;
|
const char *home;
|
||||||
sigset_t set, oldset;
|
sigset_t set, oldset;
|
||||||
|
struct winsize ws;
|
||||||
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
|
* 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);
|
sigfillset(&set);
|
||||||
sigprocmask(SIG_BLOCK, &set, &oldset);
|
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:
|
case -1:
|
||||||
sigprocmask(SIG_SETMASK, &oldset, NULL);
|
if (~flags & JOB_PTY) {
|
||||||
environ_free(env);
|
close(out[0]);
|
||||||
close(out[0]);
|
close(out[1]);
|
||||||
close(out[1]);
|
}
|
||||||
return (NULL);
|
goto fail;
|
||||||
case 0:
|
case 0:
|
||||||
proc_clear_signals(server_proc, 1);
|
proc_clear_signals(server_proc, 1);
|
||||||
sigprocmask(SIG_SETMASK, &oldset, NULL);
|
sigprocmask(SIG_SETMASK, &oldset, NULL);
|
||||||
@ -109,22 +120,23 @@ job_run(const char *cmd, struct session *s, const char *cwd,
|
|||||||
environ_push(env);
|
environ_push(env);
|
||||||
environ_free(env);
|
environ_free(env);
|
||||||
|
|
||||||
if (dup2(out[1], STDIN_FILENO) == -1)
|
if (~flags & JOB_PTY) {
|
||||||
fatal("dup2 failed");
|
if (dup2(out[1], STDIN_FILENO) == -1)
|
||||||
if (dup2(out[1], STDOUT_FILENO) == -1)
|
fatal("dup2 failed");
|
||||||
fatal("dup2 failed");
|
if (dup2(out[1], STDOUT_FILENO) == -1)
|
||||||
if (out[1] != STDIN_FILENO && out[1] != STDOUT_FILENO)
|
fatal("dup2 failed");
|
||||||
close(out[1]);
|
if (out[1] != STDIN_FILENO && out[1] != STDOUT_FILENO)
|
||||||
close(out[0]);
|
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);
|
|
||||||
|
|
||||||
|
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);
|
closefrom(STDERR_FILENO + 1);
|
||||||
|
|
||||||
execl(_PATH_BSHELL, "sh", "-c", cmd, (char *) NULL);
|
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);
|
sigprocmask(SIG_SETMASK, &oldset, NULL);
|
||||||
environ_free(env);
|
environ_free(env);
|
||||||
close(out[1]);
|
|
||||||
|
|
||||||
job = xmalloc(sizeof *job);
|
job = xmalloc(sizeof *job);
|
||||||
job->state = JOB_RUNNING;
|
job->state = JOB_RUNNING;
|
||||||
@ -150,7 +161,11 @@ job_run(const char *cmd, struct session *s, const char *cwd,
|
|||||||
job->freecb = freecb;
|
job->freecb = freecb;
|
||||||
job->data = data;
|
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);
|
setblocking(job->fd, 0);
|
||||||
|
|
||||||
job->event = bufferevent_new(job->fd, job_read_callback,
|
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);
|
log_debug("run job %p: %s, pid %ld", job, job->cmd, (long) job->pid);
|
||||||
return (job);
|
return (job);
|
||||||
|
|
||||||
|
fail:
|
||||||
|
sigprocmask(SIG_SETMASK, &oldset, NULL);
|
||||||
|
environ_free(env);
|
||||||
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Kill and free an individual job. */
|
/* 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,
|
log_debug("job write %p: %s, pid %ld, output left %zu", job, job->cmd,
|
||||||
(long) job->pid, len);
|
(long) job->pid, len);
|
||||||
|
|
||||||
if (len == 0) {
|
if (len == 0 && (~job->flags & JOB_KEEPWRITE)) {
|
||||||
shutdown(job->fd, SHUT_WR);
|
shutdown(job->fd, SHUT_WR);
|
||||||
bufferevent_disable(job->event, EV_WRITE);
|
bufferevent_disable(job->event, EV_WRITE);
|
||||||
}
|
}
|
||||||
|
5
tmux.h
5
tmux.h
@ -1929,8 +1929,11 @@ typedef void (*job_update_cb) (struct job *);
|
|||||||
typedef void (*job_complete_cb) (struct job *);
|
typedef void (*job_complete_cb) (struct job *);
|
||||||
typedef void (*job_free_cb) (void *);
|
typedef void (*job_free_cb) (void *);
|
||||||
#define JOB_NOWAIT 0x1
|
#define JOB_NOWAIT 0x1
|
||||||
|
#define JOB_KEEPWRITE 0x2
|
||||||
|
#define JOB_PTY 0x4
|
||||||
struct job *job_run(const char *, struct session *, const char *,
|
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_free(struct job *);
|
||||||
void job_check_died(pid_t, int);
|
void job_check_died(pid_t, int);
|
||||||
int job_get_status(struct job *);
|
int job_get_status(struct job *);
|
||||||
|
@ -3240,7 +3240,7 @@ window_copy_copy_buffer(struct window_mode_entry *wme, const char *prefix,
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
window_copy_copy_pipe(struct window_mode_entry *wme, struct session *s,
|
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;
|
void *buf;
|
||||||
size_t len;
|
size_t len;
|
||||||
@ -3250,7 +3250,7 @@ window_copy_copy_pipe(struct window_mode_entry *wme, struct session *s,
|
|||||||
if (buf == NULL)
|
if (buf == NULL)
|
||||||
return;
|
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);
|
bufferevent_write(job_get_event(job), buf, len);
|
||||||
window_copy_copy_buffer(wme, prefix, buf, len);
|
window_copy_copy_buffer(wme, prefix, buf, len);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user